From 147a536a035d6d738ba0a97b0e82f2f2b77feebc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:22:56 -0700 Subject: [PATCH 001/726] audit: land the rust-skills audit corpus and its remediation plan The 16-lens read-only audit of the 94 workspace crates is committed with its priming packet, 110 lane files, verification record, and the reviewed remediation plan, so later waves, worktrees, and reviewers can read the evidence the plan cites. --- .../2026-09-24-rust-skills-audit/README.md | 2828 +++++++++++++++++ .../U1-constraints.md | 961 ++++++ .../VERIFICATION.md | 553 ++++ .../lane/X1-supply-chain.md | 69 + .../lane/X2-generated-boundary.md | 45 + .../lane/X3-cross-crate-duplication.md | 44 + .../lane/d2b-audit.md | 88 + .../lane/d2b-broker-composition.md | 84 + .../lane/d2b-broker-p1.md | 75 + .../lane/d2b-broker-p2.md | 100 + .../lane/d2b-broker-p3.md | 83 + .../lane/d2b-broker-p4.md | 95 + .../lane/d2b-broker-p5.md | 82 + .../lane/d2b-broker-p6.md | 101 + .../lane/d2b-broker-p7.md | 87 + .../lane/d2b-bus-p1.md | 83 + .../lane/d2b-bus-p2.md | 87 + .../lane/d2b-contracts-broker.md | 87 + .../lane/d2b-contracts-control.md | 90 + .../lane/d2b-contracts-provider-p1.md | 81 + .../lane/d2b-contracts-provider-p2.md | 85 + .../lane/d2b-contracts-resource-p1.md | 87 + .../lane/d2b-contracts-resource-p2.md | 77 + .../lane/d2b-contracts-zone-session-p1.md | 77 + .../lane/d2b-contracts-zone-session-p2.md | 87 + .../lane/d2b-contracts.md | 81 + .../lane/d2b-core-controller-p1.md | 76 + .../lane/d2b-core-controller-p2.md | 88 + .../lane/d2b-core-p1.md | 96 + .../lane/d2b-core-p2.md | 91 + .../lane/d2b-host.md | 87 + .../lane/d2b-p1.md | 71 + .../lane/d2b-p2.md | 82 + .../lane/d2b-p3.md | 78 + .../lane/d2b-process-conformance.md | 87 + .../lane/d2b-provider-activation-nixos.md | 86 + .../lane/d2b-provider-audio-pipewire.md | 89 + .../lane/d2b-provider-clipboard-wayland-p1.md | 93 + .../lane/d2b-provider-clipboard-wayland-p2.md | 106 + .../lane/d2b-provider-config-nixos.md | 82 + .../lane/d2b-provider-credential-entra.md | 75 + ...2b-provider-credential-managed-identity.md | 88 + .../d2b-provider-credential-secret-service.md | 84 + .../lane/d2b-provider-credential.md | 73 + .../lane/d2b-provider-device-gpu.md | 93 + .../lane/d2b-provider-device-security-key.md | 82 + .../lane/d2b-provider-device-tpm.md | 85 + .../lane/d2b-provider-device-usbip.md | 87 + .../lane/d2b-provider-display-wayland-p1.md | 85 + .../lane/d2b-provider-display-wayland-p2.md | 89 + .../lane/d2b-provider-endpoint.md | 72 + ...d2b-provider-guest-azure-container-apps.md | 89 + ...2b-provider-guest-azure-virtual-machine.md | 97 + .../d2b-provider-guest-cloud-hypervisor.md | 91 + .../lane/d2b-provider-guest-qemu-media.md | 88 + .../lane/d2b-provider-guest.md | 93 + .../lane/d2b-provider-host.md | 77 + .../lane/d2b-provider-network-local.md | 79 + .../lane/d2b-provider-notification-desktop.md | 84 + .../lane/d2b-provider-observability-otel.md | 99 + .../lane/d2b-provider-process-systemd.md | 84 + .../lane/d2b-provider-process.md | 75 + .../lane/d2b-provider-provider.md | 81 + .../lane/d2b-provider-shell-terminal.md | 87 + .../lane/d2b-provider-supervisor.md | 65 + .../lane/d2b-provider-system-core.md | 83 + .../lane/d2b-provider-toolkit-p1.md | 81 + .../lane/d2b-provider-toolkit-p2.md | 85 + .../d2b-provider-transport-azure-relay.md | 97 + .../lane/d2b-provider-transport-vsock.md | 96 + .../lane/d2b-provider-user.md | 77 + .../lane/d2b-provider-volume-binding.md | 73 + .../lane/d2b-provider-volume-local.md | 74 + .../lane/d2b-provider-volume-virtiofs.md | 56 + .../lane/d2b-provider-volume.md | 116 + .../lane/d2b-provider-wayland-policy.md | 103 + .../lane/d2b-provider-zone-link.md | 81 + .../lane/d2b-provider.md | 68 + .../lane/d2b-resource-api-p1.md | 87 + .../lane/d2b-resource-api-p2.md | 72 + .../lane/d2b-resource-client.md | 77 + .../lane/d2b-resource-compiler.md | 83 + .../lane/d2b-resource-runtime-p1.md | 93 + .../lane/d2b-resource-runtime-p2.md | 90 + .../lane/d2b-session-p1.md | 72 + .../lane/d2b-session-p2.md | 89 + .../lane/d2b-session-unix.md | 72 + .../lane/d2b-telemetry.md | 72 + .../lane/d2b-unsafe-local-helper.md | 68 + .../lane/d2b-zone-routing.md | 78 + .../lane/d2bd-p1.md | 78 + .../lane/d2bd-p2.md | 81 + .../lane/d2bd-p3.md | 80 + .../lane/d2bd-p4.md | 86 + .../lane/d2bd-p5.md | 72 + .../lane/d2bd-p6.md | 77 + .../lane/d2bd-p7.md | 83 + .../lane/d2bd-p8.md | 88 + .../lane/d2bd-runtime-p1.md | 86 + .../lane/d2bd-runtime-p2.md | 79 + .../lane/d2bd-runtime-p3.md | 85 + .../lane/d2bd-runtime-p4.md | 112 + .../lane/tail-1.md | 333 ++ .../lane/tail-2.md | 331 ++ .../lane/tail-3.md | 271 ++ .../lane/tail-4.md | 336 ++ .../lane/tail-5.md | 337 ++ .../lane/tail-6.md | 143 + .../lane/xtask-p1.md | 91 + .../lane/xtask-p2.md | 71 + .../lane/xtask-p3.md | 75 + .../lane/xtask-p4.md | 72 + .../lane/xtask-p5.md | 72 + ...2-refactor-rust-skills-remediation-plan.md | 353 ++ 114 files changed, 15066 insertions(+) create mode 100644 docs/audits/2026-09-24-rust-skills-audit/README.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p5.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md create mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md create mode 100644 docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md diff --git a/docs/audits/2026-09-24-rust-skills-audit/README.md b/docs/audits/2026-09-24-rust-skills-audit/README.md new file mode 100644 index 000000000..c0f26c5fc --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/README.md @@ -0,0 +1,2828 @@ +# Rust skills audit - 16 lenses x 94 crates: consolidated findings, coverage, and remediation input + +**Date:** 2026-09-24 - **Baseline:** `v3` @ `6ebdd4cec` - **Lens revision:** `third_party/agent-skills/rewrite-rs/v0.1.0-alpha.1/skills/`. + +**Method (one paragraph).** A read-only, per-lane audit: 107 crate lanes - 51 part lanes over the 17 largest crates, 50 whole-crate lanes, and 6 tail lanes covering 27 small crates - ran 15 of the 16 rewrite-rs audit lenses over the assigned scope - `src/**` excluding `src/generated/**`, plus `tests/**` for the `test` lens - by running each lens card's seed regexes (U1-constraints.md section c), reading every hit, and recording findings or a `clean` line with seed counts. The `supply` lens is workspace-level (lane X1); the generated boundary is lane X2; cross-crate classes are lane X3. Two lenses-routed lanes judge emitted code rather than crate code: X2 (generated shapes, judged through serde/docs/api/type/err). No code was changed: every finding is a proposal. Anchors are valid at the baseline OID; remediation must re-locate by symbol. + +**Deliverable:** this report, `U1-constraints.md` (the lane contract: protocol, lens cards, constraints ledger, seed matrix, part map), `lane/.md` per lane (the evidence record), `VERIFICATION.md` (independent verification). + +## 1. Executive summary + +| Metric | Value | +| --- | --- | +| Findings total | **965** | +| By severity | high 13 - medium 295 - low 657 | +| By verdict | actionable 923 - needs-contract 25 - policy-confirmed 17 | +| Lane files | 110 (107 crate lanes + X1 supply + X2 generated + X3 cross-crate) | +| Crates with zero findings | 7 of 94 | +| Merge operations (same issue, two lenses/parts) | 57 | + +Findings by lens: + +| lens | findings | lens | findings | +| --- | ---: | --- | ---: | +| `idiom` | 124 | `perf` | 52 | +| `own` | 115 | `conc` | 29 | +| `type` | 82 | `async` | 19 | +| `api` | 138 | `unsafe` | 4 | +| `err` | 94 | `ffi` | 0 | +| `serde` | 40 | `macro` | 4 | +| `obs` | 31 | `test` | 67 | +| `docs` | 143 | `supply` | 23 | + +Top-20 findings (severity, then blast radius; `what` truncated to 160 characters and `|` escaped for the table - sections 2 and 4 carry the full verbatim text): + +| RS id | lens | crate | what | sev | blast | verdict | +| --- | --- | --- | --- | --- | --- | --- | +| RS-0837 | `async` | `d2b-broker` | `cleanup_spawned_runner_after_failure` performs a blocking `waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED)` (no WNOHANG) at runtime.rs:11815, and is called dire | high | wide | actionable | +| RS-0455 | `err` | `d2b-broker` | DispatchAuditContext::from_request panics the broker on a malformed authoritative audit join: both CanonicalAuditDigest::parse(zone_id.expect)...) at runtime.rs | high | wide | actionable | +| RS-0842 | `async` | `d2b-broker` | write_redacted_registry_index_at_path resolves the fixed d2bd group via nss `Group::from_name` synchronously on an executor worker on every registry write (enro | high | wide | actionable | +| RS-0962 | `type` | `X3-cross-crate-duplication` | Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one | high | family | actionable | +| RS-0516 | `err` | `d2b-provider-wayland-policy` | Panic reachable from caller input at the family engine's public boundary: `InteractionDriver::new` parses-and-expects `InteractionDriverArgs.zone: String` (pub | high | family | actionable | +| RS-0840 | `async` | `d2b-broker` | `acquire_handoff_lock` is an `async fn` whose final step is a blocking `nix::fcntl::Flock::lock(file, LockExclusive)` on the executor worker thread; the call is | high | leaf | actionable | +| RS-0841 | `async` | `d2b-broker` | the async `harden()` path (invoked from `live_handlers.rs:3142` on the runtime) calls `apply_ancestor_traverse_acl` -> `run_setfacl_op_on_fd` (sys.rs:1866-1893) | high | leaf | actionable | +| RS-0867 | `test` | `d2b-bus` | emitter_records_only_closed_bus_labels exercises every BusTelemetry method but asserts nothing, and every emit outcome is swallowed by `let _ = self.emit(...)` | high | leaf | actionable | +| RS-0898 | `test` | `d2b-provider-display-wayland` | two registry-handler tests cannot fail on any behavior change: `filtered_globals_preserve_original_global_names` (filter.rs:3213-3224) inserts entries into `adv | high | leaf | actionable | +| RS-0851 | `async` | `d2b-provider-user` | the bounded probe's `discover_local_user` runs blocking NSS lookups (`nix::unistd::User::from_name`, `Group::from_gid`, `Group::from_name`) inside async fns on | high | leaf | policy-confirmed | +| RS-0916 | `test` | `d2b-resource-runtime` | `display_shows_epoch_and_sequence` asserts `rendered.contains("[PHONE]")` on the rendering `e1728000000+42`, an assertion that cannot pass, so the test fails at | high | leaf | actionable | +| RS-0538 | `err` | `d2bd-runtime` | default_audit_join_context panics with `.expect("canonical broker zone digest")` on a wire-supplied digest - a malformed request from the broker client crashes | high | leaf | actionable | +| RS-0925 | `test` | `d2bd-runtime` | `sd_notify_ready_noops_without_notify_socket` (runtime_process.rs:543-546) and `sd_notify_ready_errors_when_socket_is_unreachable` (runtime_process.rs:589-594) | high | leaf | actionable | +| RS-0946 | `supply` | `X1-supply-chain` | nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a sy | medium | wide | actionable | +| RS-0947 | `supply` | `X1-supply-chain` | rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shippe | medium | wide | actionable | +| RS-0950 | `supply` | `X1-supply-chain` | packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2 | medium | wide | actionable | +| RS-0960 | `conc` | `X3-cross-crate-duplication` | parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-ce | medium | wide | policy-confirmed | +| RS-0963 | `err` | `X3-cross-crate-duplication` | Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { | medium | wide | needs-contract | +| RS-0239 | `type` | `d2b-audit` | `EvidenceChain` derives `Deserialize` (evidence_chain.rs:50) while its accessors assume a non-empty identity list: `invoking_identity()` panics via `.last().exp | medium | wide | actionable | +| RS-0838 | `async` | `d2b-broker` | the USB-audit serial HMAC key path runs blocking filesystem syscalls inside async fns on broker executor threads:usb_audit_serial_hmac_keyring calls the sync en | medium | wide | policy-confirmed | + +## 2. Findings by lens + +Row format: `RS-id | sev | crate | what | fix | anchor | verdict | lane`. Every finding appears under its lens, grouped by crate (cross-cutting lanes grouped under their lane id); section 4 lists the cross-cutting lanes by lane instead. Section row counts equal the executive-summary per-lens counts. + +### `idiom` + +Expression shape: iterator pipelines over index loops, derives over hand-written impls, `From`/`TryFrom` over ad-hoc converters, naming discipline. + +**`d2b`** + +- `RS-0037` | medium | `d2b` | `all_known_subcommands` hand-maintains a 22-entry command-name list of which 13 (launch, realm list/inspect/enter/run, up, down, restart, boot, build, switch, test, rollback, generations, usb, console) are retired v2 verbs the ModernCli parser rejects, so `d2b auth status` reports them as known-but-denied commands | fix: derive the list from `ModernCli::command().get_subcommands()` minus `PROJECTION_COMMANDS` the way `BUILTIN_COMMANDS` does, or drop the retired entries; update the pinned expectation in tests/auth_status_contract.rs | [packages/d2b/src/dispatch.rs:688-706, packages/d2b/src/dispatch.rs:1169-1175] | actionable | lane/d2b-p3.md +- `RS-0031` | low | `d2b` | the pidfd-table inspection detail string is re-derived by an identical 3-line match at five check sites | fix: add `PidfdEntries::state_detail() -> String` next to `load_pidfd_entries` and call it from `check_otel_host_bridge_runner`, `check_usbipd_runners`, `check_seccomp_bpf_loaded`, `check_pre_ns_posture_with_reader`, `check_broker_reap_health` | [packages/d2b/src/doctor.rs:529, packages/d2b/src/doctor.rs:579, packages/d2b/src/doctor.rs:1230, packages/d2b/src/doctor.rs:1343] | actionable | lane/d2b-p2.md +- `RS-0036` | low | `d2b` | `summarize` hand-builds a zeroed `DoctorSummary` although the type derives `Default` | fix: `let mut summary = DoctorSummary::default();` | [packages/d2b/src/zone_doctor.rs:598-601] | actionable | lane/d2b-p3.md +- `RS-0032` | low | `d2b` | `typed()` hand-rolls eight field-by-field typed-args to generic-args conversions with ~20 clones instead of `From` impls | fix: implement `From for GenericListArgs` (and the other six pairs) consuming the typed args, and change `typed()`/`typed_noun()` to take `TypedResourceArgs` by value so the conversions stop cloning | [packages/d2b/src/resource.rs:525, packages/d2b/src/resource.rs:546, packages/d2b/src/resource.rs:555, packages/d2b/src/resource.rs:565] | actionable | lane/d2b-p2.md +- `RS-0033` | low | `d2b` | `valid_digest` and `valid_hash` in zone_audit.rs are byte-identical functions | fix: keep one (e.g. `valid_digest`) and delete the other, updating its three call sites | [packages/d2b/src/zone_audit.rs:805, packages/d2b/src/zone_audit.rs:838] | actionable | lane/d2b-p2.md +- `RS-0034` | low | `d2b` | the v1 record path in `validate_record` duplicates the ~22-line chain-verification tail of the nested `validate_v2_record` (hash extraction, expected-previous check, canonical json! build, digest compare) | fix: extract `verify_chain(object, fields_key, expected_previous) -> Result` and call it from both the v1 path and `validate_v2_record` | [packages/d2b/src/zone_audit.rs:349, packages/d2b/src/zone_audit.rs:395] | actionable | lane/d2b-p2.md +- `RS-0035` | low | `d2b` | `validate_public_fields` and `validate_v2_fields` have identical bodies differing only in the per-field validator they call | fix: merge into one `validate_fields(class, fields, validate_field: fn(&str, &str, &Value) -> bool)` and pass `validate_public_field`/`validate_v2_field` | [packages/d2b/src/zone_audit.rs:591, packages/d2b/src/zone_audit.rs:607] | actionable | lane/d2b-p2.md + +**`d2b-audit`** + +- `RS-0001` | medium | `d2b-audit` | `read_bounded_line` is copy-pasted three times with only the error-code strings differing ("audit-export-line-*" / "audit-segment-line-*" / "audit-scan-line-*") | fix: extract one crate-private `read_bounded_line` (canonical home: a shared module or segment.rs) taking the line-limit/truncated error codes as parameters, and delete the two copies | [packages/d2b-audit/src/export.rs:255, packages/d2b-audit/src/segment.rs:980, packages/d2b-audit/src/sink.rs:421] | actionable | lane/d2b-audit.md +- `RS-0002` | low | `d2b-audit` | `paths.retain)...)` in `export_segments_range` re-applies `is_segment_name` to every path the read_dir loop already filtered, a redundant pass over the directory listing | fix: delete the `paths.retain` block (export.rs:103-110); the push guard at export.rs:94-102 is the only filter needed | [packages/d2b-audit/src/export.rs:103] | actionable | lane/d2b-audit.md +- `RS-0003` | low | `d2b-audit` | `scan_chain_state` re-invokes `record.mutation_id()` and `record.zone_operation_key()` inside the block whose outer `if let` already bound them, re-deriving two SHA-256 identities per mutation record during the startup scan | fix: use the outer bindings for the `mutation_predecessors` insert, deleting the inner `if let` (sink.rs:403-410) | [packages/d2b-audit/src/sink.rs:393, packages/d2b-audit/src/sink.rs:403] | actionable | lane/d2b-audit.md + +**`d2b-broker`** + +- `RS-0011` | medium | `d2b-broker` | row_owner_ref, device_guest_owner,and tpm_devices_of_guest hand-roll the same "walk the bundles resources array" loop three times with slightly different match predicates, so bundle-shape drift (new field, renamed key) silently desyncs them. | fix: extract a single `fn find_resource_row<'a>(bundle: &'a Value, pred: impl FnMut(&'a Value) -> bool) -> Option<&'a Value>` and drive all three (and callers of row_owner_ref at src/ops/device_worker.rs:158) from it; keep the three predicates as call-site closures. | [src/ops/device_worker.rs:312-335, src/ops/device_worker.rs:339-369, src/ops/device_worker.rs:371-434] | actionable | lane/d2b-broker-p6.md +- `RS-0006` | low | `d2b-broker` | three near-identical hand-rolled flag parsers `parse_probe_flags`/`parse_stub_flags`/`parse_export_flags` duplicate the same index-loop skeleton and the `--socket-path`/`--test-uid` arms (with `expect_arg` bound-checking) three times | fix: extract one table-driven flag parser (flag spec -> value) that the three wrappers compose, or a shared `parse_common_flags` helper returning `(socket_path, test_uid)` | [packages/d2b-broker/src/runtime.rs:10392, packages/d2b-broker/src/runtime.rs:10418, packages/d2b-broker/src/runtime.rs:10453, packages/d2b-broker/src/runtime.rs:10495] | actionable | lane/d2b-broker-p1.md +- `RS-0007` | low | `d2b-broker` | active_locked_usbip_bind_intents builds out with a let-mut push loop over the resolver's intent-id iterator, where a filter_map().collect() pipeline would carry the same filtering | fix: replace the loop at runtime.rs:10132-10147 with `resolver.usbip_bind_intent_ids().filter_map(|id| resolver.find_usbip_bind_intent(id).map)...))).collect::>()`, keeping the two continue conditions as filter predicates | [packages/d2b-broker/src/runtime.rs:10132] | actionable | lane/d2b-broker-p2.md +- `RS-0008` | low | `d2b-broker` | `format_errno` reverses `tmp` into `buf` by hand with an index loop (`for i in 0..len`), the exact case an iterator form reads as idiomatic | fix: replace the loop with `buf[..len].copy_from_slice(&tmp[..len])` plus `buf[..len].reverse()`, or fill via `buf.iter_mut().zip(tmp[..len].iter().rev())`; both stay allocation- and panic-free so the async-signal-safe contract is preserved | [packages/d2b-broker/src/sys.rs:2816-2820] | actionable | lane/d2b-broker-p5.md +- `RS-0009` | low | `d2b-broker` | the "path must be absolute" check (a `to_str()` + `starts_with('/')` + `InvalidInput` refusal) is hand-copied into seven SystemReconcileExecutor methods, so a wording or error-shape change must touch all seven. | fix: extract a private `fn require_absolute(path: &Path) -> Result<(), ReconcileExecError>` helper and call it from apply_nft_script, write_atomic_file, write_atomic_file_with_ownership, write_path_value, read_path_value, ip_route, run_usbip, run_ssh_keygen. | [src/ops/exec_reconcile.rs:404, src/ops/exec_reconcile.rs:505, src/ops/exec_reconcile.rs:551, src/ops/exec_reconcile.rs:602] | actionable | lane/d2b-broker-p6.md merged: d2b-broker-p6#2 +- `RS-0010` | low | `d2b-broker` | build_farm_via_namespace and build_store_view_via_namespace duplicate the same spawn-process + write-config + read-stdout + split-lines scaffold (about 100 lines each), drifting in error messages and success parsing. | fix: unify behind one private `async fn run_store_helper(verb: StoreViewHelperVerb, request: impl Serialize, success: impl FnOnce(&[u8]) -> ...) -> Result<(), StoreViewFarmError>` with a two-variant `StoreViewHelperVerb` enum, or extract the shared scaffold into a thin helper. | [src/ops/store_view_farm.rs:97-190, src/ops/store_view_farm.rs:228-300] | actionable | lane/d2b-broker-p6.md +- `RS-0012` | low | `d2b-broker` | TrustedContextStore duplicates each worker-handshake entrypoint as a sync twin (`open`/`open_async`, `publish`/`publish_async`) whose sync copies spawn a `block_on`-free worker handshake that only in-crate `#[cfg(test)]` callers exercise;; the justification comment begins "The crate is nearly all async" and does not cover the sync twins' ongoing cost. | fix: gate the sync twins `#[cfg(test)]` (and gate `TrustedContextStore::Drop`'s sync persist path if unused outside tests), or unify over a private `fn with_worker(blocking: bool, f: impl FnOnce...` seam if a production sync caller is restored. | [src/envelope/mod.rs:424-464, src/envelope/mod.rs:466-493, src/envelope/mod.rs:540-565, src/envelope/mod.rs:567-593] | actionable | lane/d2b-broker-p6.md + +**`d2b-broker-composition`** + +- `RS-0004` | low | `d2b-broker-composition` | `workspace_root` walks up to four parent directories with a `for _ in 0..4` index loop and a mutable `current`, where the bounded walk is an iterator chain | fix: replace the loop with `std::iter::successors(Some(current), |c| c.parent()).take(4).find(|c| c.join("Cargo.toml").is_file() && c.join("packages").is_dir())` | [packages/d2b-broker-composition/src/dependency_surface.rs:136] | actionable | lane/d2b-broker-composition.md +- `RS-0005` | low | `d2b-broker-composition` | `state_cell` silences its deliberately unused parameter with `let _ = invocation;` instead of naming it as unused | fix: rename the parameter to `_invocation` and delete the `let _ = invocation;` line (the doc comment's "the invocation's row" is prose, not the parameter name) | [packages/d2b-broker-composition/src/seam.rs:270, packages/d2b-broker-composition/src/seam.rs:274] | actionable | lane/d2b-broker-composition.md + +**`d2b-bus`** + +- `RS-0013` | low | `d2b-bus` | AuthoritativeUnixSubjectResolver::resolve_for_service collects matching subject indices into a Vec and indexes [0], allocating and double-scanning where a take-two iterator would do | fix: replace the collect-then-index with subjects.iter().enumerate().filter_map(...) checked via next() then next().is_some() | [packages/d2b-bus/src/router.rs:1773-1781] | actionable | lane/d2b-bus-p1.md +- `RS-0014` | low | `d2b-bus` | `PendingCancelDeliveries::abort_destination` collects into a `Vec` inside a `retain` closure (statement-style accumulation with a side effect in the predicate) instead of partitioning the entries | fix: `let (aborted, kept): (Vec<_>, Vec<_>) = entries.drain(..).partition(|entry| entry.destination == session); *entries = kept;` and abort the drained handles | [packages/d2b-bus/src/operations.rs:302-310] | actionable | lane/d2b-bus-p2.md + +**`d2b-contracts-broker`** + +- `RS-0015` | low | `d2b-contracts-broker` | `response.refusal.clone().unwrap_or_default()` runs inside an `if response.refusal.is_some()` branch, so the default is unreachable and the value is cloned twice | fix: restructure to `if let Some(code) = response.refusal.clone()` or match on the Option once, returning `KernelInvokeError::Refused` in the Some arm | [packages/d2b-contracts-broker/src/kernel_client.rs:225-227] | actionable | lane/d2b-contracts-broker.md +- `RS-0016` | low | `d2b-contracts-broker` | `ApplyHostGenerationHandoff::validate` carries a caller-role check that can never fire: `HandoffCallerRole` has exactly two variants and the `!matches!(Lifecycle | Admin)` guard is always false, so the `InvalidTransition` arm is dead code in a security-adjacent validation path | fix: delete the branch (or add the missing third role if one was intended) | [packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broker/src/host_generation.rs:131-137] | actionable | lane/d2b-contracts-broker.md +- `RS-0017` | low | `d2b-contracts-broker` | `BrokerCallerRole::for_display()` returns the bare label `"RootUid"` for `RootUid` while every sibling arm returns a stable `d2b-*` audit label, and the value lands in the broker's `peer_role` audit records | fix: align the arm to the scheme, e.g. `"d2b-root"`, and pin it in the existing label test | [packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/src/broker_wire.rs:3149-3163] | actionable | lane/d2b-contracts-broker.md merged: d2b-contracts-broker#10 + +**`d2b-contracts-provider`** + +- `RS-0018` | low | `d2b-contracts-provider` | hand-written `Default` impls on `CredentialRotationPolicy` and `CredentialRevocationPolicy` reproduce the field-wise default a derive would generate | fix: add `#[default]` to `RotationPolicyClass::OnExpiry` and `RevocationAction::Immediate` and replace both impls with `#[derive(Default)]` | [packages/d2b-contracts-provider/src/v3/credential.rs:362, packages/d2b-contracts-provider/src/v3/credential.rs:453] | actionable | lane/d2b-contracts-provider-p1.md +- `RS-0020` | low | `d2b-contracts-provider` | the two `children.push(BindingChildIntent {...})` arms in `explicit_binding_children_with_user` are identical 15-field literals differing only in `producer_ref: None` versus `Some(producer_ref)`, forced apart by a `let ... else { ...; continue; }` | fix: bind `let producer_ref: Option = producer_ref.transpose()?;` before the push and emit one literal with `producer_ref,`, deleting the else-continue arm | [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:595] | actionable | lane/d2b-contracts-provider-p2.md +- `RS-0019` | low | `d2b-contracts-provider` | manual `Debug` impl on `UpgradePolicy` prints exactly the three closed pub fields a derive would print, with nothing to redact | fix: replace `impl core::fmt::Debug for UpgradePolicy` with `#[derive(Debug)]` on the struct | [packages/d2b-contracts-provider/src/v3/provider.rs:2374] | actionable | lane/d2b-contracts-provider-p1.md + +**`d2b-contracts-resource`** + +- `RS-0022` | medium | `d2b-contracts-resource` | the sort-dedup-compare uniqueness check is hand-rolled at three production sites while a private helper already exists | fix: extract `ensure_unique(values: &[T]) -> Result<(), PrimitiveSpecError>` into execution_policy.rs (home of PrimitiveSpecError) and call it from VolumeSpec::new, ExecutionPolicy::new, and process.rs check_unique (which keeps only its max-bound check) | [packages/d2b-contracts-resource/src/v3/volume.rs:1210-1213, packages/d2b-contracts-resource/src/v3/volume.rs:1248-1253, packages/d2b-contracts-resource/src/v3/execution_policy.rs:792-796, packages/d2b-contracts-resource/src/v3/process.rs:1571-1579] | actionable | lane/d2b-contracts-resource-p2.md +- `RS-0021` | low | `d2b-contracts-resource` | `ExternalIpv4Spec::default` (network.rs:597-605) hand-writes exactly the field-wise default (method: Ipv4Method::Dhcp, address: None, gateway: None, dns: Vec::new()) that a derive would produce | fix: add `#[default]` to `Ipv4Method::Dhcp` (network.rs:533) and `#[derive(Default)]` to `ExternalIpv4Spec`, delete the hand-written impl | [packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src/v3/network.rs:533] | actionable | lane/d2b-contracts-resource-p1.md +- `RS-0023` | low | `d2b-contracts-resource` | ResourceSpec::serialize iterates `self.base.keys()` and re-gets each key with an avoidable `expect("key returned by canonical object")` | fix: iterate `for (key, value) in &self.base` and call `map.serialize_entry(key, value)?`, deleting the expect and the double lookup | [packages/d2b-contracts-resource/src/v3/resource.rs:621-626] | actionable | lane/d2b-contracts-resource-p2.md +- `RS-0024` | low | `d2b-contracts-resource` | VolumeSpec::new checks `views.contains_key` and then repeats the lookup with a dead `ok_or(MissingRequiredField)` that can never fire | fix: collapse to one `let view = views.get(attachment.view.as_str()).ok_or(PrimitiveSpecError::MissingRequiredField)?;` | [packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223] | actionable | lane/d2b-contracts-resource-p2.md + +**`d2b-contracts-zone-session`** + +- `RS-0025` | low | `d2b-contracts-zone-session` | hand-written `impl Default for ReceiveSequence` and `SendSequence` duplicate what `#[derive(Default)]` generates field-for-field (u64 plus bool, both zero) | fix: add `Default` to the derive lists of `ReceiveSequence` and `SendSequence` and delete the two hand-written impls; keep `ZoneLinkLimits`' Default (zone_link.rs:126) which preserves the nonzero bounds invariant | [src/v3/component_session.rs:1935, src/v3/component_session.rs:1976] | actionable | lane/d2b-contracts-zone-session-p1.md + +**`d2b-core`** + +- `RS-0027` | low | `d2b-core` | resolve_network_projection_intent and resolve_network_sysctl_intent fetch the Network spec only to discard it via `let _ = spec;`, a workaround for the unused binding | fix: replace `let spec = self.find_network_spec(&parts)?; ... let _ = spec;` with the statement `self.find_network_spec(&parts)?;` (the `?` on Option keeps the admission check and drops the value) | [packages/d2b-core/src/bundle_resolver.rs:1805, packages/d2b-core/src/bundle_resolver.rs:1911] | actionable | lane/d2b-core-p1.md +- `RS-0030` | low | `d2b-core` | allowlist membership checks in static_invariants.rs use `iter().any(|f| f == last)` linear scans where slice `contains` reads cleaner | fix: replace `PUBLIC_MANIFEST_FIELDS.iter().any(|f| f == last)` with `PUBLIC_MANIFEST_FIELDS.contains(&last.as_str())` and `BROAD_CAPABILITIES.iter().any(|broad| broad == cap)` with `BROAD_CAPABILITIES.contains(&cap.as_str())` | [packages/d2b-core/src/static_invariants.rs:162, packages/d2b-core/src/static_invariants.rs:219] | actionable | lane/d2b-core-p2.md +- `RS-0028` | low | `d2b-core` | `_ASSERT_TAPROLE` is a `#[allow(dead_code)]` const that exists only to silence an unused-import warning for `TapRole`, which the module does not actually name | fix: drop the `use crate::host::TapRole` import (the comment says `BridgePortFlags` uses the type internally) or import it as `use crate::host::TapRole as _;`, and delete the const | [packages/d2b-core/src/bundle_resolver.rs:5746] | actionable | lane/d2b-core-p1.md +- `RS-0029` | low | `d2b-core` | resolve_disk_init_ops nests two `for` loops over a single-arm `match` on `SpawnRunnerPlanOp`, which is a one-variant enum, so the match is a no-op wrapper around construction | fix: flatten to `vm.nodes.iter().flat_map(|n| &n.plan_ops).filter_map(|op| match op { SpawnRunnerPlanOp::DiskInit { .. } => Some(ResolvedDiskInitOp { .. }), })` or at least an `if let` for the single variant | [packages/d2b-core/src/bundle_resolver.rs:2434, packages/d2b-core/src/processes.rs:180] | actionable | lane/d2b-core-p1.md + +**`d2b-core-controller`** + +- `RS-0026` | low | `d2b-core-controller` | the duplicate-reservation checks bind a holder only to silence it with `let _ = holder;`, when the check is a pure predicate | fix: replace the `if let Some(holder) = ... { let _ = holder; return Err(...); }` blocks with `if entry.holders.iter().any(|holder| holder.owner_proof == request.owner_proof) { return Err(...); }` in admit_authority_inner_with_operation and admit_with_operation_id | [authority.rs:2189-2192, authority.rs:2542-2545] | actionable | lane/d2b-core-controller-p2.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0040` | medium | `d2b-provider-clipboard-wayland` | MIME policy is duplicated in two modules with divergent semantics: clipd_host/policy.rs normalizes by splitting on ';' and carries a 7-entry secret-hint list, while crate::policy.rs normalizes by trim+lowercase only and carries a 3-entry list, so the same MIME string ("Text/Plain ; Charset=UTF-8") is admitted by the host Wayland path and rejected by the guest history path, and secret hints diverge (application/x-secret-service is a hint on the host side only) | fix: make crate::policy the single canonical MIME module and have clipd_host::policy delegate to it for ALLOWED_MIME_TYPES, SECRET_HINT_MIME_TYPES, and normalize_mime | [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:91-97, packages/d2b-provider-clipboard-wayland/src/policy.rs:3-14, packages/d2b-provider-clipboard-wayland/src/policy.rs:91-93] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0039` | medium | `d2b-provider-clipboard-wayland` | preferred_mime_order hardcodes the four MIME strings that policy.rs ALLOWED_MIME_TYPES already owns, keeping the reported MIME-policy triplication alive (row S79, reported not consolidated) | fix: iterate d2b_provider_clipboard_wayland::ALLOWED_MIME_TYPES in preferred_mime_order instead of the literal list, so allowlist changes propagate to the preference order | [src/bin/d2b-clipd.rs:2812, src/policy.rs:12] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0041` | low | `d2b-provider-clipboard-wayland` | two distinct PickerError enums in one crate (crate::picker::PickerError for receipt minting and crate::clipd_host::picker::PickerError for the subprocess supervisor) share a name, which reads as one type in errors and imports | fix: rename the clipd_host one (e.g. PickerIpcError) or move the supervisor module under a distinct name | [packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:113-126] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0038` | low | `d2b-provider-clipboard-wayland` | install_bridge_listeners builds a Vec with a push loop where the body is a pure Result-producing map | fix: collect the iterator: bridge_peers.into_iter().map(|peer| { ... Ok(BridgeListener { ... }) }).collect::, String>>()? | [src/bin/d2b-clipd.rs:1131] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0042` | low | `d2b-provider-clipboard-wayland` | FallbackArming implements Default by hand for a single-field struct whose only field defaults to FallbackState::Idle; a derive would stay in sync with the enum | fix: `#[derive(Default)]` on FallbackArming plus `#[derive(Default)]` with `#[default]` on FallbackState::Idle, delete the impl | [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:5-12] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0043` | low | `d2b-provider-clipboard-wayland` | ReasonCode::as_str is a hand-written match that duplicates the `#[serde(rename_all = "snake_case")]` label mapping on the same enum, giving two sources of truth for the wire label that can drift | fix: derive the label once (e.g. a const table or serde serialization) and have as_str return it | [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:45-68] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-config-nixos`** + +- `RS-0044` | low | `d2b-provider-config-nixos` | the path-component rejection walk is written twice with identical rules, and the two copies can drift (one checks, one checks and collects) | fix: extract one helper classifying `Path::components()` into `Result, ConfigError>` (reject `CurDir`/`ParentDir`/`Prefix`) and call it from both `validate_reader_path` and `read_bounded_file` | [packages/d2b-provider-config-nixos/src/ttrpc.rs:379-386, packages/d2b-provider-config-nixos/src/ttrpc.rs:414-421] | actionable | lane/d2b-provider-config-nixos.md + +**`d2b-provider-credential-entra`** + +- `RS-0045` | medium | `d2b-provider-credential-entra` | in-crate deadline trio (`operation_deadline`/`time_bound_instant`/`time_bounds_not_after`/`time_bound_instant_at`/`is_expired_unix_ms`) duplicates the toolkit's `credential::operation_deadline` with identical absolute-or-relative semantics; the family finding that folded this trio onto the toolkit was applied to secret-service but not here | fix: fold the trio onto `d2b_provider_toolkit::credential::{operation_deadline, deadline_remaining, now_unix_ms, is_absolute_unix_ms}` (keep the injectable-clock `time_bound_instant_at` only if the tests need it), deleting lib.rs:1164-1220 | [packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-entra/src/lib.rs:1172, packages/d2b-provider-credential-entra/src/lib.rs:1187, packages/d2b-provider-toolkit/src/credential.rs:111] | actionable | lane/d2b-provider-credential-entra.md + +**`d2b-provider-credential-secret-service`** + +- `RS-0046` | low | `d2b-provider-credential-secret-service` | exported enum variant is misspelled `Userd` for `User` in the only supported owner classification, so every consumer must copy the typo | fix: rename `SecretServiceOwner::Userd` to `SecretServiceOwner::User` (and `owner()` return at lib.rs:1233); in-tree census shows no consumers to update | [packages/d2b-provider-credential-secret-service/src/lib.rs:446, packages/d2b-provider-credential-secret-service/src/lib.rs:1233] | actionable | lane/d2b-provider-credential-secret-service.md + +**`d2b-provider-device-gpu`** + +- `RS-0047` | low | `d2b-provider-device-gpu` | rustfmt drift: the GpuAuthorityError enum is closed by an indented brace with a trailing-whitespace line inside code(), and a variant doc comment in GpuEffectError sits at column 0 | fix: normalize the three sites (cargo fmt --check class): authority.rs:401 -> `}`, authority.rs:411 empty, effects.rs:101 reindent `/// A worker closure...` | [packages/d2b-provider-device-gpu/src/authority.rs:401, packages/d2b-provider-device-gpu/src/authority.rs:411, packages/d2b-provider-device-gpu/src/effects.rs:101] | actionable | lane/d2b-provider-device-gpu.md +- `RS-0048` | low | `d2b-provider-device-gpu` | `let _ = Self::declared_row_template)...)?` binds nothing while the `?` already propagates the error | fix: drop the binding: `Self::declared_row_template(&view, role)?;` | [packages/d2b-provider-device-gpu/src/effects_service.rs:193] | actionable | lane/d2b-provider-device-gpu.md +- `RS-0049` | low | `d2b-provider-device-gpu` | six opaque-token newtypes duplicate the same from_core / is_zero / as_bytes / redacting-Debug boilerplate with subtly differing surfaces | fix: extract a shared opaque-bytes shape (const-generic `OpaqueBytes` with per-type markers, or an in-crate `macro_rules! opaque_token`), keeping the deliberate per-type Debug redaction; the repo's `redacted_debug!`-class macro is the resident pattern to lean on | [packages/d2b-provider-device-gpu/src/authority.rs:17, packages/d2b-provider-device-gpu/src/authority.rs:44, packages/d2b-provider-device-gpu/src/authority.rs:66, packages/d2b-provider-device-gpu/src/authority.rs:265] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-device-security-key`** + +- `RS-0050` | low | `d2b-provider-device-security-key` | `declared_dependency_refs` accumulates through a `let mut refs = Vec::new()` plus a push closure instead of an iterator chain, the one statement-style accumulation in the crate | fix: collect the two `Option` probes with an iterator chain (`[a, b].into_iter().flatten().collect()`) and delete the closure | [packages/d2b-provider-device-security-key/src/driver.rs:380-390] | actionable | lane/d2b-provider-device-security-key.md + +**`d2b-provider-device-tpm`** + +- `RS-0051` | low | `d2b-provider-device-tpm` | the swtpm log-level bound is spelled twice: lib.rs exports MIN_SWTPM_LOG_LEVEL/MAX_SWTPM_LOG_LEVEL (1/20) which runner.rs uses, while swtpm_argv.rs:160 hardcodes `1..=20` in generate_swtpm_argv, so a bound change in one place silently drifts from the other | fix: import crate::{MIN_SWTPM_LOG_LEVEL, MAX_SWTPM_LOG_LEVEL} in swtpm_argv.rs and replace the literal range | [swtpm_argv.rs:160, lib.rs:63, lib.rs:65] | actionable | lane/d2b-provider-device-tpm.md + +**`d2b-provider-device-usbip`** + +- `RS-0052` | low | `d2b-provider-device-usbip` | `declared_dependency_refs` accumulates into `let mut refs = Vec::new()` and pushes in match arms where each arm returns a fixed small list | fix: return the match arms as owned `Vec` literals (or `.into_iter().flatten().collect()`) so the shape is an expression | [driver.rs:267-281] | actionable | lane/d2b-provider-device-usbip.md + +**`d2b-provider-display-wayland`** + +- `RS-0059` | medium | `d2b-provider-display-wayland` | the session binding digest is derived twice with byte-identical bodies: free fn `session_digest` (controller.rs:1442) duplicates `WaylandSessionSpec::session_digest` (spec.rs:385), so the two can silently diverge | fix: make the controller free fn delegate to `spec.session_digest(controller_generation)` and keep spec.rs:385 as the canonical home (census: d2bd already consumes the method at interaction_composition.rs:4080,4267) | [src/controller.rs:1442, src/spec.rs:385] | actionable | lane/d2b-provider-display-wayland-p2.md +- `RS-0053` | low | `d2b-provider-display-wayland` | handoff_via_bridge re-wraps the bound `error` into a fresh `HandoffStatus::Failed(error)` and immediately matches it back out with a `_ => unreachable!()` arm that can never fire; the outer match arm already binds the value | fix: delete the `let status = ...` / `let error = match status {...}` round-trip and use the arm-bound `error` directly in filter.rs:620-628 | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:620, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:624] | actionable | lane/d2b-provider-display-wayland-p1.md +- `RS-0058` | low | `d2b-provider-display-wayland` | three stale `#[allow(dead_code)]` markers sit on constructors that production code calls: `FinalizationInput::from_supervisor` (controller.rs:464), `LaunchGrants::from_supervisor_for_session_with_frontend_and_controller` (process.rs:402), `ProcessObservation::from_supervisor` (process.rs:676) | fix: delete the three allows (keep process.rs:380, whose constructor is test/test-support-only) so a future real dead-code warning is not masked | [src/controller.rs:464, src/process.rs:402, src/process.rs:676] | actionable | lane/d2b-provider-display-wayland-p2.md +- `RS-0054` | low | `d2b-provider-display-wayland` | handle_bind dispatches per-interface handler installation through a nested `match try_downcast::() { Some => ..., _ => match try_downcast::() { Some => ..., _ => { if let ... } } }` while the same function already uses edition-2024 if-let chains for viewporter and dmabuf, mixing two dispatch styles in one body | fix: flatten the nested match into `if let Some(wm_base) = ... else if let Some(eglstream) = ... else if let Some(compositor) = ...` chains, keeping the early `return` arms | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1272, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1300] | actionable | lane/d2b-provider-display-wayland-p1.md +- `RS-0055` | low | `d2b-provider-display-wayland` | filter_format_table iterates `for (index, entry) in table.chunks_exact(16).enumerate()` but the index is never used except `let _ = index;` inside the overflow branch, an ignore that exists only to silence the unused variable | fix: drop `.enumerate()` and remove `let _ = index;` | [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:790, packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:801] | actionable | lane/d2b-provider-display-wayland-p1.md +- `RS-0056` | low | `d2b-provider-display-wayland` | sanitize_label calls `out.chars().count()` on every loop iteration, a quadratic re-count of the output string that grows with the label length (bounded at 64 chars, so cheap, but the shape invites the same mistake at a larger bound) | fix: track a `let mut written = 0usize;` counter incremented per pushed char and compare against `MAX_LABEL_CHARS` | [packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:150] | actionable | lane/d2b-provider-display-wayland-p1.md +- `RS-0057` | low | `d2b-provider-display-wayland` | four comment blocks are mangled prose: a non-ASCII full stop (`\u3002`) at dmabuf.rs:820, a stray `**` at filter.rs:769, two `; no` joins missing the space after the semicolon at filter.rs:770 and filter.rs:2801, and misindented two-line comment pairs at decoration.rs:1804-1805, dmabuf.rs:819-820 and filter.rs:2799-2801 where the continuation line sits at 4-space indent inside the fn | fix: rewrite the four comments as plain ASCII with normal spacing and consistent indent | [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:769, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:770, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:2801] | actionable | lane/d2b-provider-display-wayland-p1.md + +**`d2b-provider-endpoint`** + +- `RS-0061` | medium | `d2b-provider-endpoint` | the `inspect-endpoint` payload table hardcodes the four committed purposes and their producer/locality/class strings, duplicating the same-module derivations `guest_control_producer`/`device_worker_endpoint_class` built from the provider constants, so a provider role/purpose rename drifts the report silently | fix: build the table from those fns, or constrain it with a unit test pinning the payload rows to the derivations | [packages/d2b-provider-endpoint/src/effects_service.rs:50-60, packages/d2b-provider-endpoint/src/effects_service.rs:73-84, packages/d2b-provider-endpoint/src/effects_service.rs:128-143] | actionable | lane/d2b-provider-endpoint.md +- `RS-0060` | low | `d2b-provider-endpoint` | hand-written `impl Default for EndpointConsumerPolicy` returns `Self::unrestricted()`, which the field-wise derive would produce identically (empty Vecs) | fix: add `Default` to the derive list on `EndpointConsumerPolicy` and drop the manual impl | [packages/d2b-provider-endpoint/src/endpoint.rs:395-398] | actionable | lane/d2b-provider-endpoint.md + +**`d2b-provider-guest-azure-virtual-machine`** + +- `RS-0062` | low | `d2b-provider-guest-azure-virtual-machine` | hand-written `impl Default for BootstrapService` where a derive with a `#[default]` variant covers it | fix: add `#[derive(Default)]` with `#[default]` on `BootstrapServiceState::Waiting` (bootstrap.rs:124) and `#[derive(Default)]` on `BootstrapService`, delete the manual impl | [src/bootstrap.rs:138, src/bootstrap.rs:124] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md + +**`d2b-provider-guest-cloud-hypervisor`** + +- `RS-0063` | low | `d2b-provider-guest-cloud-hypervisor` | `CloudHypervisorController` stores `_config` (controller.rs:1712) that is never read; only `config.validate()` at 1739 uses the value | fix: drop the `_config` field and its initializer, keeping the validate() call in `from_verified_descriptor` | [controller.rs:1712, controller.rs:1744] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0064` | low | `d2b-provider-guest-cloud-hypervisor` | `observed_process_status` is controller state used only inside one `reconcile` invocation (reset at 1860, set at 2013/2016, read at 2042), a field masquerading as a local | fix: make it a local variable in `reconcile` and delete the struct field | [controller.rs:1722, controller.rs:1860, controller.rs:2042] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0065` | low | `d2b-provider-guest-cloud-hypervisor` | `deletion_rank` (shutdown.rs:487) and `upgrade_rank` (shutdown.rs:666) are byte-identical match arms duplicated across two free functions | fix: one `ChildRole::rank()` method (or single free fn) used by both planners | [shutdown.rs:487-494, shutdown.rs:666-673] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0066` | low | `d2b-provider-guest-cloud-hypervisor` | `BootstrapGraph::readiness()` (bootstrap_graph.rs:131) hardcodes `bindings_ready`/`setup_ready` to true while the `bindings` field doc says fenced binding readiness gates VMM start; only tests call it | fix: delete the wrapper and update the test (bootstrap_graph.rs:417) to call `vmm_readiness` with explicit booleans | [bootstrap_graph.rs:131-139, bootstrap_graph.rs:417-422] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0067` | low | `d2b-provider-guest-qemu-media` | The `impl Default` bodies re-spell the serde `default_*` helper values in a second place (`"qemu-system-x86-64".to_owned()` at packages/d2b-provider-guest-qemu-media/src/config.rs:93 vs `default_qemu_artifact()` at 272; the whole GuestProviderSpecSettings default body at packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182-196 vs the serde default fns at ~440-447); two spellings of one default drift independently | fix: have the Default impls call the serde default fns (`qemu_binary_artifact_id: default_qemu_artifact()`, `vcpu: default_vcpu()`, `boot_media_view: default_boot_media_view()`( ( | [packages/d2b-provider-guest-qemu-media/src/config.rs:93, packages/d2b-provider-guest-qemu-media/src/config.rs:272, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:440] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-host`** + +- `RS-0068` | low | `d2b-provider-host` | stray misindented closing brace at test_support.rs:185 closes `impl RecordingMinijailGate` at 4-space indent (the fn body closes at :183, the impl at :185) | fix: reindent the stray `}` to column 0 (rustfmt would flag it) | [packages/d2b-provider-host/src/test_support.rs:185] | actionable | lane/d2b-provider-host.md + +**`d2b-provider-network-local`** + +- `RS-0069` | low | `d2b-provider-network-local` | octet-to-string conversion collects a Vec of four Strings and joins it, where one format! suffices | fix: destructure the parsed octets (`let [a, b, c, d] = octets; Some(format!("{a}.{b}.{c}.{d}"))`) instead of `.collect::>().join(".")` | [src/controller.rs:298-302] | actionable | lane/d2b-provider-network-local.md +- `RS-0070` | low | `d2b-provider-network-local` | declared_dependency_refs accumulates into `let mut refs = Vec::new()` with a nested if-push, where a filter_map pipeline fits | fix: `spec.pointer("/spec/attachments").and_then(Value::as_array).into_iter().flatten().filter_map(|a| a.get("executionRef").and_then(Value::as_str).and_then(|v| ResourceRef::parse(v.ok()()).collect()` | [src/driver.rs:377-393] | actionable | lane/d2b-provider-network-local.md + +**`d2b-provider-notification-desktop`** + +- `RS-0071` | low | `d2b-provider-notification-desktop` | `expected_acknowledgements` accumulates its two source acknowledgement arms with `Vec::new()` + `extend(iterator)` where the chain could collect the Vec directly | fix: `let mut acknowledgements: Vec<_> = plan.start_endpoints.iter().map)...).chain(plan.stop_endpoints.iter().map)...)).collect();` then keep the two conditional `HostSink` pushes | [packages/d2b-provider-notification-desktop/src/controller.rs:660-675] | actionable | lane/d2b-provider-notification-desktop.md +- `RS-0072` | low | `d2b-provider-notification-desktop` | `NotificationProviderDescriptor::service_package()` hardcodes the wire literal `"d2b.notification.v3"` duplicating the exported `SERVICE_PACKAGE` const | fix: return `crate::SERVICE_PACKAGE` so the literal has one home | [packages/d2b-provider-notification-desktop/src/descriptor.rs:43-44, packages/d2b-provider-notification-desktop/src/lib.rs:70] | actionable | lane/d2b-provider-notification-desktop.md + +**`d2b-provider-process-systemd`** + +- `RS-0073` | low | `d2b-provider-process-systemd` | hand-written `impl Default` on the unit structs `SystemdEffectsService` and `SystemdEffectsServiceFactory` where `#[derive(Default)]` generates the identical impl | fix: replace both `impl Default { fn default() -> Self { Self::new() } }` blocks with `#[derive(Default)]` on the structs | [packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-process-systemd/src/effects_service.rs:218] | actionable | lane/d2b-provider-process-systemd.md + +**`d2b-provider-seccomp-profile`** + +- `RS-0074` | low | `d2b-provider-seccomp-profile` | three impl-block closing braces are indented at 4 spaces instead of column 0 (fmt drift; `cargo fmt --check` would fail) | fix: dedent the closing braces of `impl DeviceNodePath`, `impl DeviceBind`, and `impl SeccompProfileSpec` to column 0 (rustfmt) | [packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:162, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:196] | actionable | lane/tail-4.md + +**`d2b-provider-supervisor`** + +- `RS-0075` | low | `d2b-provider-supervisor` | systemd.rs stop() holds a no-op statement `let _ = &handle.pidfd;` that creates and immediately drops a temporary reference, doing nothing | fix: delete the line (the pidfd field is already used by wait/finalize and the retained handle) | [packages/d2b-provider-supervisor/src/systemd.rs:840] | actionable | lane/d2b-provider-supervisor.md +- `RS-0076` | low | `d2b-provider-supervisor` | the bounded pending-observation ledger is copy-pasted twice: `BrokerProcessBackend::{record,take_observation}` and `SystemdProcessBackend::{record,take_observation}` are the same shape (Mutex, evict-oldest at MAX_PENDING_OBSERVATIONS=1024, poisoned-lock to ObserveFailed) | fix: extract one shared bounded-ledger helper and have both backends use it | [packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor/src/systemd.rs:240-280] | actionable | lane/d2b-provider-supervisor.md + +**`d2b-provider-system-core`** + +- `RS-0077` | low | `d2b-provider-system-core` | `UserIdentityDigest::to_hex` pushes hex nibbles with `char::from_digit)...).unwrap_or('0')`, a fallback that can never fire (from_digit is total for 0-15 at radix 16) | fix: const `HEX: [char; 16]` table lookup, or `write!(out, "{byte:02x}")` via `std::fmt::Write` which pushes without allocating | [src/user.rs:75, src/user.rs:76] | actionable | lane/d2b-provider-system-core.md +- `RS-0078` | low | `d2b-provider-system-core` | `UserReconciler::required_bindings` is an associated fn that never uses `Self`, the shape the naming rule calls a free function | fix: free `required_bindings(spec: &UserSpec)` in user.rs, updating the two test call sites (tests/user_discovery.rs:45, tests/user_discovery.rs:73) | [src/user.rs:232] | actionable | lane/d2b-provider-system-core.md + +**`d2b-provider-toolkit`** + +- `RS-0079` | medium | `d2b-provider-toolkit` | the 15-operation Guest backend allowlist is spelled out twice: `GuestCredentialBackend::request` inlines the same `matches!` that `valid_guest_backend_operation` already implements, so adding one operation to one list and not the other silently diverges the client and responder admission | fix: have `request` call `valid_guest_backend_operation(&operation)` and delete the inline `matches!` arm | [packages/d2b-provider-toolkit/src/base/fd10.rs:926-941, packages/d2b-provider-toolkit/src/base/fd10.rs:1478-1496] | actionable | lane/d2b-provider-toolkit-p1.md +- `RS-0080` | low | `d2b-provider-toolkit` | `GuestCredentialBackendResponse` and `GuestCredentialBackendReply` are two public 7-field structs with the same shape (state, lease_handle, source_version, rotation_generation, expires_at_unix_ms, outcome, bytes) and duplicated accessors, both re-exported at the crate root | fix: collapse into one type carrying the accessors plus `encode`/`with_sensitive_bytes`, keeping the zeroizing bytes field | [packages/d2b-provider-toolkit/src/base/fd10.rs:545-597, packages/d2b-provider-toolkit/src/base/fd10.rs:612-700, packages/d2b-provider-toolkit/src/lib.rs:91-92] | actionable | lane/d2b-provider-toolkit-p1.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0081` | low | `d2b-provider-transport-azure-relay` | `impl Clone for RelaySecret` hand-writes what `#[derive(Clone)]` generates identically (`Zeroizing>` clones into a fresh `Zeroizing` either way), and the manual version can drift from the field | fix: replace the impl block with `#[derive(Clone)]` on `RelaySecret` | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239, packages/d2b-provider-transport-azure-relay/src/credential_client.rs:217] | actionable | lane/d2b-provider-transport-azure-relay.md +- `RS-0082` | low | `d2b-provider-transport-azure-relay` | `build_connect` builds the literal `"Bearer"` by collecting a char array (`['B','e','a','r','e','r']`) into a fresh String on every connect, where a `const`/literal `"Bearer"` reads plainly and allocates nothing | fix: use a `const BEARER: &str = "Bearer"` (or inline literal) in the `ServiceBusAuthorization` header format | [packages/d2b-provider-transport-azure-relay/src/auth.rs:249-253] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-transport-vsock`** + +- `RS-0083` | low | `d2b-provider-transport-vsock` | `ReadySession::disconnect` takes `mut self`, assigns `SessionState::Disconnected` to a by-value copy that is immediately dropped, and then returns the assigned constant - the mutation is dead code and the method contract is fully expressed by returning the constant. | fix: `pub fn disconnect(self) -> SessionState { SessionState::Disconnected }`, dropping `mut` and the state assignment | [packages/d2b-provider-transport-vsock/src/auth.rs:221-224] | actionable | lane/d2b-provider-transport-vsock.md + +**`d2b-provider-volume`** + +- `RS-0084` | low | `d2b-provider-volume` | `reconcile` converts the provider facet via `serde_json::to_value(value).unwrap_or(serde_json::Value::Null)` where the value is already a `serde_json::Value`: a serialization round trip plus dead `unwrap_or` fallback for an infallible conversion | fix: replace with `envelope.base.get("provider").cloned()` | [driver.rs:607-609] | actionable | lane/d2b-provider-volume.md + +**`d2b-provider-volume-local`** + +- `RS-0085` | low | `d2b-provider-volume-local` | LayoutPhase::worse hand-rolls severity comparison with an `as u8` cast although the enum derives PartialOrd/Ord; the cast also silently depends on variant declaration order matching severity order | fix: replace the `if self as u8 >= other as u8` body with `self.max(other)` (derived Ord, declaration order Pending/Ready/Degraded/Failed already encodes severity) | [src/status.rs:33-38] | actionable | lane/d2b-provider-volume-local.md + +**`d2b-provider-zone-link`** + +- `RS-0086` | medium | `d2b-provider-zone-link` | the frozen cryptoperiod defaults `BOOTSTRAP_PSK_TTL_MS_DEFAULT` (300_000) and `KK_SESSION_MAX_LIFETIME_MS_DEFAULT` (86_400_000) are defined identically in two crates with no shared home, so a drift silently desynchronizes the child-local handler from the bus-side enrollment machine | fix: move both constants to `d2b_contracts_zone_session` (the crate both `d2b-provider-zone-link` and `d2b-bus` already depend on) and re-export from both sites; this is not the refused ZoneLink enrollment-machine merge, only the two constants | [packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/zone_links.rs:63, packages/d2b-bus/src/session/enrollment.rs:42, packages/d2b-bus/src/session/enrollment.rs:49] | actionable | lane/d2b-provider-zone-link.md + +**`d2b-resource-api`** + +- `RS-0087` | low | `d2b-resource-api` | A6 not-applied: 17 hand-written redaction Debug impls in authz.rs (15) and admission.rs (2) where the exported `redacted_debug!` macro exists | fix: fold byte-compatible impls to `redacted_debug!` or extend the macro with a count-preserving form, updating the Debug-shape pinning tests in the same change | [packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, packages/d2b-resource-api/src/authz.rs:356, packages/d2b-resource-api/src/authz.rs:377] | actionable | lane/d2b-resource-api-p2.md +- `RS-0088` | low | `d2b-resource-api` | unformatted `use` lines inside a fn body break `cargo fmt --check` | fix: reindent to 4 spaces and drop the inner-brace spacing | [packages/d2b-resource-api/src/manager_backend/tests.rs:1045, packages/d2b-resource-api/src/manager_backend/tests.rs:1046] | actionable | lane/d2b-resource-api-p2.md + +**`d2b-resource-client`** + +- `RS-0089` | low | `d2b-resource-client` | two byte-identical private async helpers each exist twice in this crate: `await_with_cancellation` (zone_client vs process_attach) and `classify_session_error`/`classify_attach_error` | fix: hoist both into one shared pub(crate) module (e.g., call.rs) and have zone_client.rs and process_attach.rs call the single copies | [packages/d2b-resource-client/src/zone_client.rs:914, packages/d2b-resource-client/src/process_attach.rs:764, packages/d2b-resource-client/src/zone_client.rs:936, packages/d2b-resource-client/src/process_attach.rs:785] | actionable | lane/d2b-resource-client.md +- `RS-0090` | low | `d2b-resource-client` | `GuestControlEndpoint::endpoint_uid` is an exact duplicate of `uid()` (same field, same doc sentence; a test pins the equivalence at zone_client.rs:1067) | fix: keep one accessor (e.g., `uid()`) and drop or deprecate the other | [packages/d2b-resource-client/src/zone_client.rs:194, packages/d2b-resource-client/src/zone_client.rs:199, packages/d2b-resource-client/src/zone_client.rs:1067] | actionable | lane/d2b-resource-client.md + +**`d2b-resource-compiler`** + +- `RS-0091` | medium | `d2b-resource-compiler` | main.rs hand-rolls identical output-sanitizer helpers already in lib.rs (safe_token/bound_ascii duplicate sanitize_token/bound_message body-for-body) | fix: expose lib.rs sanitize_token/bound_message as pub(crate) helpers (dropping safe_label indirection if unneeded) and replace main.rs safe_token/bound_ascii with calls to the shared pair | [packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:2438, packages/d2b-resource-compiler/src/main.rs:2531, packages/d2b-resource-compiler/src/main.rs:2545] | actionable | lane/d2b-resource-compiler.md +- `RS-0092` | low | `d2b-resource-compiler` | sanitize_token's char-loop filter is expressible as an iterator pipeline | fix: `value.chars().filter(|character| (character.is_ascii_graphic() && *character != '/' && *character != '\\') || *character == ' ').collect::()` | [packages/d2b-resource-compiler/src/lib.rs:2402] | actionable | lane/d2b-resource-compiler.md +- `RS-0093` | low | `d2b-resource-compiler` | check_metadata_closure's unexpected-layout-entries accumulation could be a filter_map+collect pipeline | fix: `let unexpected: Vec = entries.into_iter().filter_map(|entry_name| match entry_name.to_str() { Some(name) if expected.contains(name) => None, Some(name) => Some(truncate_entry(name)), None => Some("".to_owned()) }).collect();` (kept the trailing sort* | [packages/d2b-resource-compiler/src/lib.rs:1724] | actionable | lane/d2b-resource-compiler.md +- `RS-0094` | low | `d2b-resource-compiler` | executable-set difference builders are two push-loops a chain can express in one collect | fix: `let difference: Vec = names.difference(&declared_names).map(|name| format!("bin={}", truncate_entry(name)).chain(declared_names.difference(&names).map(|name| format!("manifest={}", truncate_entry(name)).collect();` | [packages/d2b-resource-compiler/src/lib.rs:1913] | actionable | lane/d2b-resource-compiler.md + +**`d2b-resource-runtime`** + +- `RS-0095` | low | `d2b-resource-runtime` | hand-written `impl Default` on the unit structs `ResourceManager` and `ResourceActor` delegate to `new()` where `#[derive(Default)]` is equivalent, and neither impl has any caller | fix: derive `Default` on both (or delete the impls; `new()` stays) | [packages/d2b-resource-runtime/src/manager.rs:882, packages/d2b-resource-runtime/src/resource.rs:685] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0097` | low | `d2b-resource-runtime` | two hand-written comparator closures where the sort_by_key form is the idiomatic one | fix: replace sort_by(|l, r| identity_order(l).cmp(&identity_order(r))) with sort_by_key(identity_order) in TargetDirectory::assignments_for and GuestTargetRuntime::instances | [packages/d2b-resource-runtime/src/target.rs:732, packages/d2b-resource-runtime/src/guest_target.rs:514] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0096` | low | `d2b-resource-runtime` | `ManagerActorEndpoint::rpc` and `ResourceManagerClient::rpc` are byte-identical 9-line request/reply helpers duplicated in one file | fix: extract one free `manager_rpc(actor: &ActorRef, build: impl FnOnce(oneshot::Sender>) -> ResourceManagerMsg)` and call it from both impls | [packages/d2b-resource-runtime/src/manager.rs:1419, packages/d2b-resource-runtime/src/manager.rs:1508] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0098` | low | `d2b-resource-runtime` | hand-written impl Default for TargetDirectory where a derive yields the identical value | fix: replace the impl with #[derive(Default)] on TargetDirectory (DirectoryState already derives Default and Arc>: Default) | [packages/d2b-resource-runtime/src/target.rs:581-584] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0099` | low | `d2b-resource-runtime` | inherent ResourceProvenance::from_str shadows the FromStr trait name | fix: implement std::str::FromStr for ResourceProvenance and parse at the single use site in row_from | [packages/d2b-resource-runtime/src/spec_store.rs:83-88, packages/d2b-resource-runtime/src/spec_store.rs:556] | actionable | lane/d2b-resource-runtime-p2.md + +**`d2b-session`** + +- `RS-0100` | low | `d2b-session` | decode_attachment_control walks the descriptor table with an index loop plus manual offset arithmetic where an iterator pipeline fits | fix: replace the `for _ in 0..count` loop with `bytes[3..].chunks_exact(ATTACHMENT_DESCRIPTOR_BYTES).take(usize::from(count)).map(decode_attachment_descriptor).collect::, _>>()` | [engine.rs:1802, engine.rs:1803, engine.rs:1807] | actionable | lane/d2b-session-p2.md +- `RS-0101` | low | `d2b-session` | send_authorized_ttrpc re-implements the exact verb allow-list check that validate_ttrpc_permit already encodes | fix: call `validate_ttrpc_permit(&permit, now_tick)?` instead of re-writing the matches! block | [admission.rs:1593, admission.rs:956, admission.rs:958] | actionable | lane/d2b-session-p2.md + +**`d2b-sk-frontend`** + +- `RS-0102` | low | `d2b-sk-frontend` | `zone_path` accumulates labels with a `let mut Vec` + push loop where an iterator pipeline collects | fix: replace the loop with `value.split('/').map(|label| ZoneLabelId::parse(label).map_err(|_| format!("{name} is not a valid Zone label path"))).collect::, String>>()?` before `ZonePath::new(labels)` | [packages/d2b-sk-frontend/src/config.rs:178] | actionable | lane/tail-6.md + +**`d2b-unsafe-local-helper`** + +- `RS-0103` | low | `d2b-unsafe-local-helper` | terminate_scope and stop_scope normalize a NotFound into Ok via `(error == ScopeError::NotFound).then_some(()).ok_or(error)?`, a boolean-then-Option chain that hides the two-branch control flow at the exact spot a reader asks "what happens on NotFound" | fix: `if error != ScopeError::NotFound { return Err(error); }` in both terminate_scope and stop_scope, then `Ok(())` | [packages/d2b-unsafe-local-helper/src/systemd.rs:260, packages/d2b-unsafe-local-helper/src/systemd.rs:277] | actionable | lane/d2b-unsafe-local-helper.md + +**`d2b-zone-routing`** + +- `RS-0104` | low | `d2b-zone-routing` | `SealedZoneTopology::longest_suffix_match` walks `for start in 0..labels.len()` with an inline `continue`, where the same logic is a `find_map` over the index range | fix: replace the loop with `(0..labels.len()).find_map(|start| { let Ok(suffix) = ZonePath::new(labels[start..].to_vec()) else { return None; }; self.zones.get(&suffix) })` | [packages/d2b-zone-routing/src/resolver.rs:144] | actionable | lane/d2b-zone-routing.md +- `RS-0105` | low | `d2b-zone-routing` | `ZoneTopologyRequest` carries a hand-written `impl Default` that a field-wise derive reproduces exactly | fix: delete the manual impl and add `#[derive(Default)]` to the struct | [packages/d2b-zone-routing/src/service.rs:311] | actionable | lane/d2b-zone-routing.md + +**`d2bd`** + +- `RS-0106` | low | `d2bd` | `current_committed_resource` (9168) is a body-for-body duplicate of `committed_resource` (9153) plus an unused `_operation_id` parameter, and its only caller is `committed_wayland_session_for_vm` (4555) | fix: call `committed_resource` at 4555 and delete `current_committed_resource` | [packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, packages/d2bd/src/resource_runtime.rs:9153] | actionable | lane/d2bd-p1.md +- `RS-0108` | low | `d2bd` | open_resource_plane hardcodes the provider-identity seed window as `for attempt in 0..30` and `Duration::from_secs(2)` although the same-file consts PROVIDER_IDENTITY_SEED_ATTEMPTS (30) and PROVIDER_IDENTITY_SEED_INTERVAL (2s) at composition.rs:14193-14194 document exactly this "30 x 2s" window | fix: use `PROVIDER_IDENTITY_SEED_ATTEMPTS` and `PROVIDER_IDENTITY_SEED_INTERVAL` in the retry loop so the literals cannot drift from the documented window | [packages/d2bd/src/composition.rs:14699, packages/d2bd/src/composition.rs:14710, packages/d2bd/src/composition.rs:14193] | actionable | lane/d2bd-p2.md +- `RS-0109` | low | `d2bd` | dispatch_live_guest_activation_resource builds the identical resource-List json and identical drive_sync dispatch twice (rollback branch and next-ordinal branch), differing only in post-processing | fix: hoist the `list` json and `runtime.dispatch_public_cli_request(&list)` call (with its map_err) above the `if mode == DaemonActivationMode::Rollback` split and branch only the filter/max computation | [packages/d2bd/src/composition.rs:20450-20461, packages/d2bd/src/composition.rs:20486-20498] | actionable | lane/d2bd-p3.md merged: d2bd-p3#10 +- `RS-0111` | low | `d2bd` | `registered_service_decl` (provider_lifecycle) and `registered_service_factories` (resource_plane_v3) are 15-arm `if ... else if` chains over `&'static str` equality where a `match` reads as a table, gets exhaustiveness-free fallthrough by construction, and does not re-test the winner's earlier arms | fix: convert both chains to `match service { PROCESS_EFFECTS_SERVICE.id => ..., ... , _ => None/continue }`, keeping the `as Arc` coercions on the factory arms | [packages/d2bd/src/provider_lifecycle.rs:78, packages/d2bd/src/resource_plane_v3.rs:2226] | actionable | lane/d2bd-p6.md +- `RS-0112` | low | `d2bd` | hand-written `impl Default` on both unit-struct actors (`EffectServiceActor`, `EffectServiceSupervisor`) delegates to `Self::new()` with zero call sites anywhere; a derive emits the same impl and cannot drift | fix: replace both with `#[derive(Default)]` (or delete both; no workspace caller) | [packages/d2bd/src/effect_service_actors.rs:268, packages/d2bd/src/effect_service_actors.rs:411] | actionable | lane/d2bd-p7.md +- `RS-0113` | low | `d2bd` | no-op `let _ =` suppression statements with dead bindings: `let _ = &mut chain;` after the chain re-root (no mutation follows), `let _ = kind;` masking the unused `kind` param of `network_content_fence`, and `let _ = error.code();` masking the unused `error` in the `Refused` arm | fix: delete the statements and bind the now-unused pattern args as `_` / drop the `kind` param | [packages/d2bd/src/forward_rendezvous.rs:672, packages/d2bd/src/shared_provider_effects.rs:1156, packages/d2bd/src/provider_registry.rs:531] | actionable | lane/d2bd-p8.md merged: d2bd-p8#3 +- `RS-0107` | low | `d2bd` | pointless `let setup = setup;` rebind in `reconcile_controller_sessions_locked` shadows the just-bound value to drop a mutability that was never declared | fix: bind once without `mut` and delete the rebind line | [packages/d2bd/src/resource_runtime.rs:6896] | actionable | lane/d2bd-p1.md +- `RS-0110` | low | `d2bd` | qemu_media_registry_state takes `_registry_dir: &str` and never reads it (the probe reads global state), so every caller passes a value into a dead parameter | fix: drop the parameter and the `registry_dir` argument at the sole call site | [packages/d2bd/src/composition.rs:21306-21319, packages/d2bd/src/composition.rs:21291] | actionable | lane/d2bd-p3.md + +**`d2bd-runtime`** + +- `RS-0114` | low | `d2bd-runtime` | build_autostart_plan accumulates two Vecs with side-effect loops then extends a third, where an iterator pipeline partition would express the split | fix: replace the two push loops in build_autostart_plan with a collector pair: `let (net_entries, workload_entries): (Vec<_>, Vec<_>) = resolver.manifest.vms.iter().map(|(name, vm)| { ... }).partition(|e| e.is_net_vm);` then sort each half | [autostart.rs:228-245] | actionable | lane/d2bd-runtime-p1.md +- `RS-0115` | low | `d2bd-runtime` | two fd-extraction loops grow a Vec via `extend` in a `for` over `cmsgs()`, where a filter_map collect would read as one expression | fix: collect `message.cmsgs().map_err)...)?.filter_map(|c| ...).flatten().collect()` into the result Vec in `receive_frame` and `read_frame_with_fds` | [packages/d2bd-runtime/src/unsafe_local_helper.rs:789, packages/d2bd-runtime/src/unix_transport.rs:294] | actionable | lane/d2bd-runtime-p3.md +- `RS-0116` | low | `d2bd-runtime` | `monotonic_tick()` is duplicated verbatim in guest_mode.rs and guest_component_session.rs (identical `OnceLock` elapsed-millis helper, two copies of the same code) | fix: move one `monotonic_tick()` into `crate::runtime_util` and have both modules call it | [packages/d2bd-runtime/src/guest_mode.rs:849, packages/d2bd-runtime/src/guest_component_session.rs:587] | actionable | lane/d2bd-runtime-p4.md +- `RS-0117` | low | `d2bd-runtime` | `impl Default for ConsoleSessionTable` hand-writes what `#[derive(Default)]` produces field-wise (all three HashMap fields are Default) | fix: replace the impl with `#[derive(Default)]` on `ConsoleSessionTable` and delete the manual `default()` | [packages/d2bd-runtime/src/console_session.rs:162] | actionable | lane/d2bd-runtime-p4.md + +**`xtask`** + +- `RS-0118` | medium | `xtask` | gen_layer_catalogs.rs has two byte-identical helpers under different names: `string_slice` and `string_array` share the same signature and body (both emit a `pub const : &[&str]` array), so callers guess which to use and a future shape change drifts only one copy | fix: delete `string_array` and route its 10 call sites (lines 299, 362, 367, 456, 466, 471, 496, 507, 512, 517) through `string_slice`, keeping `string_pair_slice` for the tuple case | [packages/xtask/src/gen_layer_catalogs.rs:147, packages/xtask/src/gen_layer_catalogs.rs:158] | actionable | lane/xtask-p1.md +- `RS-0120` | medium | `xtask` | the daemon-api IPC collector (`parse_rust_items` + `IpcItemCollector`) parses files with `syn`, then slices the original source text back out and re-parses fields and variants with ~150 lines of hand-rolled scanners (`parse_fields`, `parse_variants`, `split_top_level_entries`, `extract_body`, `strip_non_code_lines`, `normalize_ws`, `line_col_to_offset`), duplicating what the `syn` AST already provides and re-implementing angle-bracket depth counting for generics | fix: in `visit_item_struct`/`visit_item_enum`, extract `Field { name, ty }` and variants from `syn::Fields`/`syn::Variant` directly (type text via `quote::ToTokens`), then delete the text parsers and `line_col_to_offset`'s per-span O(n) scan | [packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.rs:1203] | actionable | lane/xtask-p1.md +- `RS-0123` | low | `xtask` | resource_type_authority.rs carries misindented statements (`errors.push(format!(` at column 0, `out.push_str("// @generated\n");` at column 0, `fn drop` under-indented by 4) that rustfmt would reflow; the repo runs no fmt gate, so the drift is committed | fix: reindent the statements at the three sites (or run rustfmt over the file once) | [packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_authority.rs:940, packages/xtask/src/resource_type_authority.rs:1083] | actionable | lane/xtask-p3.md merged: xtask-p3#2 +- `RS-0124` | low | `xtask` | `resource_type.to_string()` in an iterator map over `&[String]` where `.cloned()` is the idiomatic copy | fix: `STANDARD_RESOURCE_TYPES.iter().map(|resource_type| resource_type.to_string()).collect::>()` -> `.iter().cloned().collect::>()` | [packages/xtask/src/nix_inventories.rs:721] | actionable | lane/xtask-p5.md +- `RS-0119` | low | `xtask` | emitted Rust source is embedded as single-line escaped string literals with backslash line continuations (`"... \n \` chains, e.g. the `typed_noun_type` block), making the generator bodies unreadable and brittle to edit; a reviewer cannot diff the embedded code | fix: embed the emitted blocks as raw string literals (the content contains `"` but not `"##`, so `r##"..."##` delimiters work) in `surface_catalog_source` and in `redact_generated_protobuf_formatting`'s `raw_display`/`redacted_formatting` templates | [packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473] | actionable | lane/xtask-p1.md +- `RS-0121` | low | `xtask` | `sanitize_generated_rust` contains a corrupted replacement literal `"#![allow(clipto_camel_casepy)]\n"` that can never match any generator output, so the sanitizer silently keeps whatever attribute the line was meant to strip in the committed generated file | fix: replace the literal with the actual protobuf/ttrpc-emitted marker it targets (or delete the line if the marker is no longer emitted) at main.rs:459 | [packages/xtask/src/main.rs:459] | actionable | lane/xtask-p1.md +- `RS-0122` | low | `xtask` | in `collect_self_binding_scope` the row-close reset block at provider_crate_policy.rs:6662 is dead: a line whose trim equals `}` cannot also contain `SeedSelfBinding`, so the inner reset never fires, its comment describes behavior that never runs, and the inner scan has no exit at the row close (it runs to EOF for every `SeedProvider {`) | fix: drop the dead inner condition, reset `pending_subject`/`pending_role` when `code_text(lines[stop]).trim() == "}"`, and `break` the `while stop < lines.len()` loop there | [packages/xtask/src/provider_crate_policy.rs:6662, packages/xtask/src/provider_crate_policy.rs:6612] | actionable | lane/xtask-p1.md + +### `own` + +Ownership: every clone/to_owned/Rc/RefCell/Arc-Mutex explainable in one sentence; borrows beat copies; cheapest argument types. + +**`X3-cross-crate-duplication`** + +- `RS-0964` | medium | `X3-cross-crate-duplication` | Repeated ownership pattern: public signatures and fields across eight crates leak `Arc`/`&Arc` (accessors returning `&Arc`, constructors taking `Arc` where single ownership suffices, pub fields carrying `Arc>`), forcing callers to see refcount plumbing and blocking signature evolution | fix: return `&T`/owned values and take owned parameters per the ownership-not-clone convention (canonical home is the borrow/owned convention; no shared type involved, so the merge target is per-crate signatures) | [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:491, packages/d2b-provider-toolkit/src/testing/mod.rs:530, packages/d2b-provider-supervisor/src/broker.rs:997] | actionable | lane/X3-cross-crate-duplication.md + +**`d2b`** + +- `RS-0150` | low | `d2b` | redundant clones of paging values that are dead after the call: `cursor.clone()` before `cursor` is overwritten by `next_cursor`, `page_token.clone()` before reassignment from `nextCursor`, and `reference.to_owned()` on a fresh `format!` String | fix: move `cursor` and `page_token` into the calls (reassign afterwards) and move `reference` into the struct literal | [packages/d2b/src/dispatch.rs:548, packages/d2b/src/debug.rs:472, packages/d2b/src/debug.rs:418] | actionable | lane/d2b-p3.md +- `RS-0151` | low | `d2b` | `modern_run` clones the entire argv (`raw_args.clone()`) for `try_parse_from` although `raw_args` is consumed by value from the only caller and never used again | fix: `ModernCli::try_parse_from(raw_args)` | [packages/d2b/src/dispatch.rs:977] | actionable | lane/d2b-p3.md +- `RS-0152` | low | `d2b` | `host_error_envelope` takes seven `&str` parameters and `.to_owned()`s each into the envelope, while callers pass `&format!(...)` results, allocating twice per field | fix: take `impl Into` parameters so `format!` results move in directly | [packages/d2b/src/dispatch.rs:296-313, packages/d2b/src/dispatch.rs:347, packages/d2b/src/dispatch.rs:359, packages/d2b/src/dispatch.rs:371-377] | actionable | lane/d2b-p3.md +- `RS-0149` | low | `d2b` | three `.clone()` calls feed `json!` operands, which serde_json serializes by reference (`to_value(&expr)`), so the clones are dropped immediately | fix: pass `parsed.schema_version`, `issue_kinds`, and `parsed.issues` to `json!` without `.clone()` | [packages/d2b/src/doctor.rs:1062, packages/d2b/src/doctor.rs:1069, packages/d2b/src/doctor.rs:1070] | actionable | lane/d2b-p2.md + +**`d2b-audit`** + +- `RS-0125` | low | `d2b-audit` | `OperationIdentity::parse` calls `AuditHash::parse(value.to_owned())`, allocating a String though `AuditHash::parse` takes `impl Into` and `&str: Into` holds | fix: pass `value` directly (`AuditHash::parse(value)`) | [packages/d2b-audit/src/operation.rs:79] | actionable | lane/d2b-audit.md + +**`d2b-broker`** + +- `RS-0129` | low | `d2b-broker` | `RealPidfdSpawner::spawn` clones the whole payload argv into a never-read `_argv` binding on every spawn | fix: delete `let _argv = payload.argv.clone();` (keep the explanatory comment; the placeholder child needs no argv) | [packages/d2b-broker/src/ops/pidfd.rs:210] | actionable | lane/d2b-broker-p3.md +- `RS-0131` | low | `d2b-broker` | enroll's registry-read fallback clones the just-written record although it is never used again | fix: replace `unwrap_or_else(|_| vec![record.clone()])` with `unwrap_or_else(|_| vec![record])` in `enroll` | [packages/d2b-broker/src/ops/media.rs:220] | actionable | lane/d2b-broker-p7.md +- `RS-0130` | low | `d2b-broker` | in `context_worker_loop` the Bootstrap reply clones the entire persisted state (`let _ = reply.send(Ok(state.state.clone()))`) just to unblock open()/open_async(), which discard the reply value (`?`), so each broker open copies the whole `PersistedTrustedContext` for nothing. | fix: shrink `ContextCommand::Bootstrap`'s oneshot reply to `Sender>` and send `Ok(())` without touching `state`;; delete the `state.state.clone()` site (keep the `let _ =` on the send alone). | [src/envelope/mod.rs:671] | actionable | lane/d2b-broker-p6.md + +**`d2b-broker-composition`** + +- `RS-0126` | low | `d2b-broker-composition` | `audit_crate` iterates `&added` and clones every dependency name into the report fields, though `added` is dead after the loop | fix: consume it with `for name in added { ... report.forbidden_dependencies.push(name); ... report.proc_macro_dependencies.push(name); }` (passing `&name` to `is_proc_macro`), removing both clones | [packages/d2b-broker-composition/src/dependency_surface.rs:251, packages/d2b-broker-composition/src/dependency_surface.rs:255] | actionable | lane/d2b-broker-composition.md +- `RS-0127` | low | `d2b-broker-composition` | the manifest scan checks `report.forbidden_dependencies.contains(&crate_name.to_string())`, allocating a fresh String per forbidden crate name (8 per audit run) for a membership test | fix: use `report.forbidden_dependencies.iter().any(|name| name == crate_name)` | [packages/d2b-broker-composition/src/dependency_surface.rs:272] | actionable | lane/d2b-broker-composition.md +- `RS-0128` | low | `d2b-broker-composition` | `dependency_tree` clones every node id into `queue` and `seen` although all ids borrow from `metadata` for the whole traversal | fix: type the traversal as `Vec<&str>` / `BTreeSet<&str>` (`let mut queue = vec![root_id];`, `seen.insert(id)`), leaving the returned `Vec` untouched | [packages/d2b-broker-composition/src/dependency_surface.rs:340, packages/d2b-broker-composition/src/dependency_surface.rs:343] | actionable | lane/d2b-broker-composition.md + +**`d2b-bus`** + +- `RS-0132` | low | `d2b-bus` | ResourceCall::authorization_request clones the whole AssignmentIdentity and mutation Vec just to learn whether ScopedCommitTransport::new rejects them, and invoke clones the same pair again to build the real transport | fix: add a reference-taking ScopedCommitTransport::validate(&AssignmentIdentity, &[ScopedResourceMutation]) in d2b-core-controller and call it from authorization_request so the validation clone disappears | [packages/d2b-bus/src/router.rs:480, packages/d2b-bus/src/router.rs:2928] | actionable | lane/d2b-bus-p1.md +- `RS-0133` | low | `d2b-bus` | `SubjectContextDigest::of_subject` builds six owned `String`s (four `to_owned()` on `&str`/`&'static str` fields plus two `to_canonical_string()` calls) only to hash length-prefixed bytes | fix: iterate `&[&str]` slices (the label helpers already return `&'static str`, and the subject/service/purpose accessors expose `&str`) and feed `len()` and `as_bytes()` directly, dropping all six allocations per digest | [packages/d2b-bus/src/session/prologue.rs:72-78] | actionable | lane/d2b-bus-p2.md +- `RS-0134` | low | `d2b-bus` | `VerifiedRouteAdmission::revalidate` clones the whole admission body (including the session binding) on every call, and `ZoneLinkSession::admit`/`is_open` invoke it on every forwarded operation | fix: add a by-reference verification path (a `verify_body(&self, body: &RouteAdmissionBody)` helper or a `revalidate` that digests `&self.body` without rebuilding owned evidence) so the re-check allocates nothing | [packages/d2b-bus/src/session/contract.rs:1046-1056, packages/d2b-bus/src/session/zone_link.rs:147] | actionable | lane/d2b-bus-p2.md + +**`d2b-contracts-provider`** + +- `RS-0137` | low | `d2b-contracts-provider` | duplicate-detection set in `validate_descriptor` clones every label key (`seen.insert(label.key.clone())`) where a borrowed `BTreeSet<&str>` suffices | fix: declare `let mut seen: BTreeSet<&str> = BTreeSet::new();` and insert `&label.key` | [packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:497, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:500] | actionable | lane/d2b-contracts-provider-p2.md +- `RS-0135` | low | `d2b-contracts-provider` | `ProviderManifest::validate_runtime_artifacts` takes `impl IntoIterator` by value, forcing `entries.clone()` and `self.runtime_artifacts.clone()` at both call sites that already hold the vec | fix: change the signature to `entries: &[TargetRuntimeArtifacts]` and drop both clones (census shows no external callers, so the pub signature change is contained) | [packages/d2b-contracts-provider/src/v3/provider.rs:2497, packages/d2b-contracts-provider/src/v3/provider.rs:2531, packages/d2b-contracts-provider/src/v3/provider.rs:2580] | actionable | lane/d2b-contracts-provider-p1.md +- `RS-0138` | low | `d2b-contracts-provider` | `allowed_telemetry_value` allocates a fresh String just to test zone validity (`validate_zone(value.to_owned()).is_ok()`) although `validate_zone` only reads the value | fix: give the zone grammar a `&str`-based check (for example `fn is_valid_zone(value: &str) -> bool` used here, keeping the owning `validate_zone` for the three construction call sites that need the validated String back) | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1591, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1549] | actionable | lane/d2b-contracts-provider-p2.md +- `RS-0136` | low | `d2b-contracts-provider` | `ProviderManifest::new` and `ComponentDescriptor::with_state_namespaces` clone identifiers into dedup sets that could borrow | fix: use `BTreeSet<&BoundedToken>` / `BTreeSet<&ResourceTypeName>` for `component_ids`, `owned_types`, `bound_types`, and `ids` | [packages/d2b-contracts-provider/src/v3/provider.rs:2438, packages/d2b-contracts-provider/src/v3/provider.rs:2445, packages/d2b-contracts-provider/src/v3/provider.rs:2455, packages/d2b-contracts-provider/src/v3/provider.rs:1459] | actionable | lane/d2b-contracts-provider-p1.md + +**`d2b-contracts-resource`** + +- `RS-0139` | low | `d2b-contracts-resource` | `StateDigest::parse` clones its String before delegating to `SchemaFingerprint::parse` (volume_state.rs:138), but that function takes `impl Into`, so `value.as_str()` avoids the copy | fix: `SchemaFingerprint::parse(value.as_str())` | [packages/d2b-contracts-resource/src/v3/volume_state.rs:138] | actionable | lane/d2b-contracts-resource-p1.md + +**`d2b-contracts-zone-session`** + +- `RS-0142` | low | `d2b-contracts-zone-session` | ZoneLinkRouteWithdrawal::new clones the entire route-id vec only to detect duplicates | fix: sort the owned vec in place and check windows(2), mirroring the crate's own dedup pattern in RoleBindingSpec::with_facets (role_binding.rs:273-276) | [zone_routing.rs:883] | actionable | lane/d2b-contracts-zone-session-p2.md +- `RS-0140` | low | `d2b-contracts-zone-session` | `HandshakeOffer::from(policy.clone())` at 7 sites across two crates: the by-value `impl From for HandshakeOffer` (component_session.rs:1172) forces a clone at every site that holds `&EndpointPolicy`, and every in-repo caller clones | fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in component_session.rs and switch the 7 sites to borrow; then delete the by-value impl if the census stays clone-only | [src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session.rs:1014, d2b-session/src/admission.rs:593] | actionable | lane/d2b-contracts-zone-session-p1.md +- `RS-0143` | low | `d2b-contracts-zone-session` | reject_runtime_or_private_fields clones the whole spec object (object.clone().into_inner()) just to wrap it for the walk, on every BundleResource::new call | fix: make walk iterate the CanonicalJsonObject map directly (and a sibling fn for arrays) so no CanonicalJsonValue wrapper or clone is built | [resource_bundle.rs:944, resource_bundle.rs:149] | actionable | lane/d2b-contracts-zone-session-p2.md +- `RS-0141` | low | `d2b-contracts-zone-session` | `ResourceExportSpec::validate_target` clones `target.resource_type()` and `target.metadata().name()` out of a borrowed `&ResourceEnvelope` only to rebuild the ref for comparison, because `ResourceRef::new` takes owned parts and the envelope exposes no borrowed accessor | fix: add `impl From<&ResourceEnvelope> for ResourceRef` (or a `resource_ref()` accessor) in d2b-contracts-resource and use it at the comparison site | [src/v3/resource_export.rs:545, src/v3/resource_export.rs:546] | actionable | lane/d2b-contracts-zone-session-p1.md +- `RS-0144` | low | `d2b-contracts-zone-session` | ServiceDescriptor::new clones each method String for BoundedText::parse, which takes impl Into | fix: pass method.as_str() (String: From<&str> satisfies the bound) | [services.rs:216] | actionable | lane/d2b-contracts-zone-session-p2.md + +**`d2b-core`** + +- `RS-0148` | low | `d2b-core` | `path_bearing_key_violations` clones a borrowed `String` (`Value::String(s) => s.clone()`) only to run `.contains('/')` on it | fix: render through `Cow<'_, str>` (`Cow::Borrowed(s.as_str())` for the string arm, `Cow::Owned(other.to_string())` otherwise) so the common string case copies nothing | [packages/d2b-core/src/static_invariants.rs:201] | actionable | lane/d2b-core-p2.md +- `RS-0147` | low | `d2b-core` | `ResourceUid::parse(value.clone())` plus `parts.network_uid.clone()` in find_network_spec and build_resource_network_intents, and `ZoneId::parse(zone.clone())` in zone_resource_bundle_zones, clone to feed parse/compare where `&str` suffices | fix: `ResourceUid::parse(value.as_str())` and compare `parse(...).ok().as_ref().map(ResourceUid::as_str) == Some(parts.network_uid.as_str())`; `ZoneId::parse(zone.as_str())`; the parse signatures are `impl Into` so `&str` converts without allocation | [packages/d2b-core/src/bundle_resolver.rs:1973, packages/d2b-core/src/bundle_resolver.rs:3354, packages/d2b-core/src/bundle_resolver.rs:1629] | actionable | lane/d2b-core-p1.md + +**`d2b-core-controller`** + +- `RS-0145` | low | `d2b-core-controller` | OwnerIndex::plan clones the entire observed child map (`self.children.get(owner).cloned()`) though every later use is a read-only borrow, copying every ObservedChild (digest strings, dependency sets) per reconcile | fix: bind `let observed = self.children.get(owner).ok_or(OwnerReconcileError::OwnerNotRelisted)?;` and pass `&observed` to the existing `.get`, `for ... in &observed`, and `ordered_observed_refs` calls | [owner_reconcile.rs:1072-1075] | actionable | lane/d2b-core-controller-p2.md +- `RS-0146` | low | `d2b-core-controller` | AuthorityReservation::reserve_durable clones the whole request into admit_authority_inner_with_operation and only afterwards builds the durable claim from the same request, when the claim can be computed first and the request moved | fix: compute `let claim = AuthorityStorageClaim::Generic(request.durable_claim());` before the lock block, then pass `request` by value into admit_authority_inner_with_operation, deleting the `.clone()` | [authority.rs:2803, authority.rs:2806] | actionable | lane/d2b-core-controller-p2.md + +**`d2b-process-conformance`** + +- `RS-0153` | low | `d2b-process-conformance` | LaunchTicket's consuming `with_*` builders clone the whole `launch_identity` (two `String` fields plus refs) before delegating to a by-value `LaunchIdentity::with_*`, although moving the field out of the consumed ticket and writing the result back does the same job without the copy | fix: `self.launch_identity = self.launch_identity.with_owner(owner_ref.clone())?;` (same shape at the other three sites: with_owner_uid, with_owner_ref, with_target_ref) | [packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/ticket.rs:610, packages/d2b-process-conformance/src/ticket.rs:631, packages/d2b-process-conformance/src/ticket.rs:664] | actionable | lane/d2b-process-conformance.md + +**`d2b-provider`** + +- `RS-0154` | low | `d2b-provider` | `ProviderAgent::dispatch` clones the full canonical-JSON request per dispatch (agent.rs:290)even though only `request.method` and `request.timeout_ms` are used after the `timeout`, both Copy | fix: extract `let method = request.method;` before the `timeout)...)`, move `request` into `self.service.dispatch)...)` instead of `request.clone()`, and use `method` in the audit record | [packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304] | actionable | lane/d2b-provider.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0155` | low | `d2b-provider-clipboard-wayland` | finalize_selection clones pending.mimes into all_mimes only to compute has_secret before consuming the Vec by into_iter; the borrow of pending.mimes ends before the move, so the clone is avoidable | fix: compute `has_secret_hint(pending.mimes.iter().map(String::as_str))` first, then `pending.mimes.into_iter().filter(...)` | [packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-config-nixos`** + +- `RS-0156` | low | `d2b-provider-config-nixos` | `GuestConfigReader::dispatch` copies the just-validated document bytes (`document.bytes().to_vec()`, up to 512 KiB per guest read on the dedicated worker) only so `read_guest_config` can re-validate the already-valid `GuestConfigDocument` | fix: give `GuestConfigDocument` a consuming accessor (`into_bytes()` or `impl From for Vec`, `bytes` field stays private) and pass it straight into the `impl Into>` parameter | [packages/d2b-provider-config-nixos/src/ttrpc.rs:111, packages/d2b-provider-config-nixos/src/controller.rs:106] | actionable | lane/d2b-provider-config-nixos.md + +**`d2b-provider-credential`** + +- `RS-0157` | low | `d2b-provider-credential` | dead derives: `#[derive(Clone)]` on `CredentialDriver` and `#[derive(Default)]` on `RecordingRuntime` are never used by any call site | fix: drop `Clone` from `CredentialDriver` (driver.rs:342) and `Default` from `RecordingRuntime` (test_support.rs:178), keeping `RecordingRuntime::new` as the only constructor | [packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/test_support.rs:178] | actionable | lane/d2b-provider-credential.md + +**`d2b-provider-device-gpu`** + +- `RS-0158` | low | `d2b-provider-device-gpu` | the started worker identity is cloned solely so validate_started_identity runs after the store | fix: validate `&identity` before `self.gpu_identity = Some(identity)` (same for video), storing on the failure branch first to preserve the test-pinned retain-for-finalize contract | [packages/d2b-provider-device-gpu/src/controller.rs:272, packages/d2b-provider-device-gpu/src/controller.rs:325] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-device-tpm`** + +- `RS-0159` | low | `d2b-provider-device-tpm` | avoidable clones of Option and String where a reborrow suffices: resource_controller.rs:233-234 clones self.volume_ref only to borrow it, resource_controller.rs:247 clones self.process_ref the same way, effects_service.rs:280 clones self.device_ref to pass `&self.device_ref` to key(), and effects_service.rs:450 clones self.zone to call zone.as_str() on a live self | fix: use self.volume_ref.as_ref().ok_or(...)?, self.process_ref.as_ref(), self.key(&self.device_ref), and self.zone.as_str() | [resource_controller.rs:233, resource_controller.rs:247, effects_service.rs:280, effects_service.rs:450] | actionable | lane/d2b-provider-device-tpm.md + +**`d2b-provider-device-usbip`** + +- `RS-0160` | low | `d2b-provider-device-usbip` | lease admission in `KernelUsbipDispatcher` clones each 16-byte lease three times per reservation (`ledger.insert)..., lease.clone())`, `self.x = Some(lease.clone())`, `Ok(lease.clone())`) | fix: move the lease into the field and clone from the field for the map and the return (two clones), or return `self.x.as_ref().unwrap().clone()` after the insert | [broker.rs:194-208, broker.rs:218-232, broker.rs:313-321, broker.rs:333-341] | actionable | lane/d2b-provider-device-usbip.md + +**`d2b-provider-display-wayland`** + +- `RS-0161` | low | `d2b-provider-display-wayland` | FilterPolicy carries `dmabuf_filters: std::sync::Arc` (built at policy.rs:316, cloned into DmabufHandler at filter.rs:1305) while the entire proxy is a single-threaded `Rc` graph - no thread or `'static` boundary justifies Arc, and the conc seeds are all zero | fix: switch the field and `DmabufHandler::new` parameter to `Rc` | [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:316] | actionable | lane/d2b-provider-display-wayland-p1.md + +**`d2b-provider-guest`** + +- `RS-0162` | low | `d2b-provider-guest` | Retiring obsolete children sorts by teardown rank plus row name by cloning every row's name String into the sort-key tuple | fix: sort with a comparator borrowing the name (`sort_by(|a,b| teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name).then_with(|| a.key.name.cmp(&b.key.name)))`), dropping the per-row allocation | [packages/d2b-provider-guest/src/driver.rs:981] | actionable | lane/d2b-provider-guest.md +- `RS-0163` | low | `d2b-provider-guest` | The ACA framework controllers clone each stored candidate list before collect (`state.sandbox.clone().into_iter().collect()`), allocating an intermediate Vec per candidate read | fix: `state.sandbox.iter().cloned().collect()` (same element copies, one fewer allocation | [packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/effects_service.rs:256] | actionable | lane/d2b-provider-guest.md + +**`d2b-provider-guest-azure-container-apps`** + +- `RS-0164` | low | `d2b-provider-guest-azure-container-apps` | CompletedOperationLedger::record evicts the oldest entry by cloning the map key only to hand it to BTreeMap::remove, which accepts a borrowed key | fix: drop the `.map(|(operation_id, _)| operation_id.clone())` and call `self.completed.remove(&oldest)` directly on the `&AcaOperationId` that `iter().min_by_key)...)` yields | [src/controller.rs:156-157] | actionable | lane/d2b-provider-guest-azure-container-apps.md +- `RS-0165` | low | `d2b-provider-guest-azure-container-apps` | reconcile_observed clones the whole owned `record` parameter into `self.observed` and then matches on it, although only the Copy `lifecycle` field is read after the store | fix: `let lifecycle = record.lifecycle; self.observed = Some(record); match lifecycle { ... }` | [src/controller.rs:500-501] | actionable | lane/d2b-provider-guest-azure-container-apps.md +- `RS-0166` | low | `d2b-provider-guest-azure-container-apps` | in the Suspended/Stopped arm of reconcile_observed the owned `record` parameter is dead after the resume closure is built, yet `record.id.clone()` copies the id instead of moving it out | fix: `let id = record.id;` (partial move) before the `move` closure | [src/controller.rs:527] | actionable | lane/d2b-provider-guest-azure-container-apps.md +- `RS-0167` | low | `d2b-provider-guest-azure-container-apps` | the stop and delete stages clone the entire observed `AcaSandboxRecord` (`self.observed.clone().ok_or)...)?`) although the closures consume only `record.id` | fix: clone just the id (`self.observed.as_ref().ok_or)...)?.id.clone()`) and move that into the closure | [src/controller.rs:417-419, src/controller.rs:469-471] | actionable | lane/d2b-provider-guest-azure-container-apps.md +- `RS-0168` | low | `d2b-provider-guest-azure-container-apps` | one_candidate and one_disk_image clone the single match out of a slice pattern although they own the `candidates` parameter and return an owned record | fix: consume with `let mut it = candidates.into_iter(); match (it.next(), it.next()) { (Some(c), None) => Ok(Some(c)), (None, None) => Ok(None), _ => Err)...) }` | [src/controller.rs:892, src/controller.rs:903] | actionable | lane/d2b-provider-guest-azure-container-apps.md +- `RS-0169` | low | `d2b-provider-guest-azure-container-apps` | AcaProviderConfig::validate() re-clones all 11 fields to re-run the constructor checks, when every check is readable from `&self` | fix: extract a private `fn validate_refs(&self) -> Result<(), AcaTypeError>` holding the resource_type() comparisons and call it from both `new` (on the raw args) and `validate` (on self) | [src/effects.rs:450-464] | actionable | lane/d2b-provider-guest-azure-container-apps.md merged: d2b-provider-guest-azure-container-apps#10 + +**`d2b-provider-guest-azure-virtual-machine`** + +- `RS-0170` | medium | `d2b-provider-guest-azure-virtual-machine` | PSK secret copied twice in `start_psk_delivery`: `copy_for_delivery()` already returns an owned `Zeroizing>` and the extra `.to_vec()` produces a plain, non-zeroized `Vec` copy of the secret | fix: `PskExtensionPayload::from_secret(psk.copy_for_delivery().into_inner())` (or pass the `Zeroizing` value directly; zeroize 1.9 implements `From> for T`) | [src/controller/mod.rs:791, src/bootstrap.rs:42] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md +- `RS-0171` | low | `d2b-provider-guest-azure-virtual-machine` | `self.vm_handle.clone().ok_or)...)` clones the handle only to pass it by reference to an effect call | fix: `let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?;` and pass `handle` (no mutable borrow of `vm_handle` is live across the effect await) | [src/controller/mod.rs:640, src/controller/mod.rs:764] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md +- `RS-0172` | low | `d2b-provider-guest-azure-virtual-machine` | `self.pending_delete_operation_id.clone().ok_or)...)` clones a `String` only to borrow it for `start_vm_delete` | fix: `let operation_id = self.pending_delete_operation_id.as_deref().ok_or(AzureVmError::Ambiguous)?;` and pass `operation_id` | [src/controller/mod.rs:852] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md +- `RS-0173` | low | `d2b-provider-guest-azure-virtual-machine` | `base32(&digest.finalize())[..20].to_owned()` allocates the full base32 string and then a second 20-char copy | fix: `let mut id = base32(&digest.finalize()); id.truncate(20); id` (or cap the length inside `base32`) | [src/controller/mod.rs:1046] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0174` | low | `d2b-provider-guest-qemu-media` | `QmpSession::execute` clones every dispatched QmpCommand into the bounded history before executing (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266); per-field borrow splitting makes the clone avoidable: push the owned command into `commands` and execute from `commands.back()` (`let Self { transport, commands, .. } = self;` then `commands.push_back(command); transport.execute(commands.back().expect("just pushed"))`(removes 1-4 String copies per QMP command | fix: destructure the two fields and reorder push/execute (drop `command.clone()` | [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-host`** + +- `RS-0175` | low | `d2b-provider-host` | avoidable clones of the row key strings before parsing into identity newtypes: `ResourceTypeName::parse`/`ResourceName::parse` take `impl Into`, so `&String` converts without cloning | fix: pass `&ctx.key().type_name` / `&ctx.key().name` at driver.rs:263/266 (or `.as_str()`) | [packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266] | actionable | lane/d2b-provider-host.md + +**`d2b-provider-network-local`** + +- `RS-0176` | low | `d2b-provider-network-local` | collision-detection BTreeSet stores owned Strings from borrowed &str keys, though the set never outlives the borrow | fix: `let mut unique_interfaces = BTreeSet::new();` and insert `ifname.as_str()` (a set of `&str` borrowing interface_names for its whole short life)) | [src/controller.rs:416-417] | actionable | lane/d2b-provider-network-local.md + +**`d2b-provider-notification-desktop`** + +- `RS-0177` | low | `d2b-provider-notification-desktop` | `commit_reconciliation` takes `SourceReconcileResult` by value but only reads its fields, forcing `.clone()` at both call sites | fix: take `result: &SourceReconcileResult` and drop the two `.clone()` calls | [packages/d2b-provider-notification-desktop/src/controller.rs:1033, packages/d2b-provider-notification-desktop/src/controller.rs:1058, packages/d2b-provider-notification-desktop/src/controller.rs:1297-1318] | actionable | lane/d2b-provider-notification-desktop.md +- `RS-0178` | low | `d2b-provider-notification-desktop` | `NotificationLifecycleSupervisor` wraps its owned backend in `Arc`, counting one reference that nothing else shares | fix: store `backend: B` directly (drop `Arc`) while keeping the `Send + Sync` bounds | [packages/d2b-provider-notification-desktop/src/lifecycle.rs:338, packages/d2b-provider-notification-desktop/src/lifecycle.rs:346] | actionable | lane/d2b-provider-notification-desktop.md + +**`d2b-provider-observability-otel`** + +- `RS-0179` | low | `d2b-provider-observability-otel` | provider-agent methods clone their input strings only to hand them to a token parser, though parse_closed_token could borrow | fix: change parse_token/parse_closed_token (agent.rs:224-244) to take `value: &str` (BoundedToken::parse takes `impl Into`, so `&str` satisfies it),and drop the five `clone()` calls in session_connect/process_effect | [agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285] | actionable | lane/d2b-provider-observability-otel.md + +**`d2b-provider-process`** + +- `RS-0180` | low | `d2b-provider-process` | `envelope.provider_ref.clone().expect("checked")` clones the `Option` at three call sites where `as_ref().expect("checked")` borrows without copying | fix: replace `.clone().expect("checked")` with `.as_ref().expect("checked")` in the `identity()` call at recover, reconcile, and delete | [packages/d2b-provider-process/src/driver.rs:1988, packages/d2b-provider-process/src/driver.rs:2056, packages/d2b-provider-process/src/driver.rs:2105] | actionable | lane/d2b-provider-process.md +- `RS-0181` | low | `d2b-provider-process` | `bind_cloud_hypervisor_guest_uid` takes `argv: &[String]` and clones the whole argv at both return paths (`Ok(argv.to_vec())` and `let mut bound = argv.to_vec()`), while its sole caller never uses `launch_argv` afterwards | fix: take `argv: Vec` by value and return it (caller passes `launch_argv` directly), removing both copies | [packages/d2b-provider-process/src/operations.rs:1354, packages/d2b-provider-process/src/operations.rs:1362, packages/d2b-provider-process/src/operations.rs:2649] | actionable | lane/d2b-provider-process.md + +**`d2b-provider-provider`** + +- `RS-0182` | low | `d2b-provider-provider` | `let zone = ctx.key().zone.clone()` clones a `String` the callee accepts as `impl Into` in three spots | fix: pass `ctx.key().zone.as_str()` / `view.key.zone.as_str()` directly; drop the `zone` local in the fixed-provider branch | [src/driver.rs:355, src/driver.rs:478, src/driver.rs:522] | actionable | lane/d2b-provider-provider.md +- `RS-0183` | low | `d2b-provider-provider` | `ctx.status::().cloned()` deep-clones the whole in-memory status (incl. the `BTreeSet` volume_refs) on every reconcile pass | fix: hold the `Option<&ProviderDriverStatus>` reference (`ctx.status()` returns `Option<&T>`, d2b-resource-runtime/src/context.rs:459); last read of `previous` precedes `ctx.set_status` | [src/driver.rs:360, src/driver.rs:435] | actionable | lane/d2b-provider-provider.md merged: d2b-provider-provider#7 + +**`d2b-provider-shell-terminal`** + +- `RS-0184` | low | `d2b-provider-shell-terminal` | `advance_session` clones the whole `Option` only to end the first `session_mut` borrow before the retired-identity check; the check can compare the live field inside a scoped block instead. | fix: in `ShellAuthorityLedger::advance_session`, wrap the first `session_mut` borrow in `{ ... }` and compare `entry.supervisor_identity.as_ref() != retired_identity` inside it, dropping `let current_identity` and `.clone()`; keep the second borrow for minting and mutation. | [src/service/supervisor.rs:599, src/service/supervisor.rs:601] | actionable | lane/d2b-provider-shell-terminal.md + +**`d2b-provider-system-core`** + +- `RS-0185` | low | `d2b-provider-system-core` | `reconcile_observed` copies `kernel_release`/`os_name` out of a by-value `HostProbeSnapshot` with `to_owned()` where destructuring the owned snapshot moves the Strings | fix: `let HostProbeSnapshot { capabilities, kernel_release, os_name, user_manager_available, minijail_gate, active_process_count } = snapshot;` at the method top and move fields into the report | [src/host.rs:466, src/host.rs:467] | actionable | lane/d2b-provider-system-core.md + +**`d2b-provider-toolkit`** + +- `RS-0187` | low | `d2b-provider-toolkit` | serve_component_session clones all four fields of the owned decoded request per frame (`request.zone().clone(), request.provider_ref().clone(), request.method().clone(), request.payload().clone()`) instead of moving them out | fix: destructure `let ProviderRequest { request_id, zone, provider_ref, method, payload } = request;`, pass the owned values to `dispatch_for_route`, and call `codec.encode_response(&request_id, &response)` | [packages/d2b-provider-toolkit/src/server/adapter.rs:331-334] | actionable | lane/d2b-provider-toolkit-p2.md +- `RS-0188` | low | `d2b-provider-toolkit` | the session loop clones the bound route out of the async mutex twice per frame (`self.authenticated_route.lock().await.clone()` at loop entry and per iteration) to compare identities | fix: compare inside the lock scope, e.g. `if self.authenticated_route.lock().await.as_ref() != Some(&route)`, avoiding the per-frame `AuthenticatedSessionRouteBinding` clone | [packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src/server/adapter.rs:314-316] | actionable | lane/d2b-provider-toolkit-p2.md +- `RS-0186` | low | `d2b-provider-toolkit` | `is_ready_for_route` clones the retained route binding out of the mutex guard (`and_then(|ready| ready.clone())`) only to compare it, allocating the binding's strings on every route check | fix: compare through the guard, `try_lock().ok().is_some_and(|ready| ready.as_ref().is_some_and(|bound| bound.liveness().is_live() && bound == route))`, no clone | [packages/d2b-provider-toolkit/src/base/runtime.rs:530-537] | actionable | lane/d2b-provider-toolkit-p1.md +- `RS-0189` | low | `d2b-provider-toolkit` | `retire_obsolete_children` sorts obsolete rows with `sort_by_key` over `(teardown_rank, row.key.name.clone())`, allocating a String per owned row per pass | fix: use `sort_by` with a comparator `teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name)).then_with(|| a.key.name.cmp(&b.key.name))` | [packages/d2b-provider-toolkit/src/shared_provider.rs:771] | actionable | lane/d2b-provider-toolkit-p2.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0190` | low | `d2b-provider-transport-azure-relay` | `ScopedCredentialRequest::with_deadline` takes `&self` and clones all four owned fields (zone, credential_ref, execution_ref, binding) only to rebuild the struct, while its single in-tree caller can consume the request | fix: change the signature to `with_deadline(self, deadline_ms)` and rebuild with `Self { deadline_ms, ..request }` plus `validate()` | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:190-198, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:1315-1317] | actionable | lane/d2b-provider-transport-azure-relay.md +- `RS-0191` | low | `d2b-provider-transport-azure-relay` | `GatewayCredential::from_material` clones all four secret Strings out of an owned `GatewayCredentialMaterial` (forced today because the material type implements `Drop`, which forbids partial moves) where storing the material as one field would move it in without copies | fix: give `GatewayCredential` a single private `material: GatewayCredentialMaterial` field and move it in `from_material`; field accessors and the redacting `Debug` stay unchanged | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:267-277, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:271-275] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-user`** + +- `RS-0192` | low | `d2b-provider-user` | `serve_inspect_user` clones `request.groups` into the spec even though the owned `InspectUserRequest` could yield it by move; the username clone at the same site is required (reused in `inspect_user_response`) | fix: destructure `let InspectUserRequest { user_ref, username, groups } = request;` and pass `username`/`groups` by value into `UserSpec::new`, borrowing `user_ref` and `username` afterwards | [packages/d2b-provider-user/src/effects_service.rs:179, packages/d2b-provider-user/src/effects_service.rs:164-187] | actionable | lane/d2b-provider-user.md + +**`d2b-provider-volume`** + +- `RS-0193` | low | `d2b-provider-volume` | `decoded_spec` returns `(envelope.clone(), spec)` though the local `envelope` is never used after the clone:an avoidable `Vec` raw-spec copy on every driver op (validate, recover, reconcile, delete) | fix: return `(envelope, spec)` directly | [driver.rs:337] | actionable | lane/d2b-provider-volume.md +- `RS-0194` | low | `d2b-provider-volume` | `desired_binding_intents` takes `ResourceRef` by value though it only reads it (cloning into each `BindingIntent` internally), so every production caller must clone first: driver.rs:380 and d2bd/src/resource_runtime.rs:5882,12921 | fix: change the signature to `&ResourceRef` in `d2b-provider-volume-local/src/bindings.rs:80`, drop the caller clones (callers pass `&volume_ref`) | [driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.rs:5882, d2bd/src/resource_runtime.rs:12921] | actionable | lane/d2b-provider-volume.md + +**`d2b-provider-volume-binding`** + +- `RS-0195` | low | `d2b-provider-volume-binding` | parsed_binding_spec clones the whole parsed spec object to end the as_object_mut() borrow before from_value (row_readers.rs:44), a clone a scoped block removes by letting `spec` move into the conversion | fix: bound the removal borrow in a block (let o = spec.as_object_mut()?; for f in [..] { o.remove(f); }) then serde_json::from_value::(spec) without Value::Object(object.clone()) | [packages/d2b-provider-volume-binding/src/row_readers.rs:38-44] | actionable | lane/d2b-provider-volume-binding.md + +**`d2b-provider-zone-link`** + +- `RS-0196` | low | `d2b-provider-zone-link` | `plan()` clones `record.route_binding` in the `RoutePolicyCommitted` and `SessionGenerationAdvanced` arms only to mutate it and store it back, where a `route_binding.as_mut()` borrow would work (no other borrow of the record is live in either arm) | fix: replace `let Some(mut binding) = record.route_binding.clone() else ...` with `let Some(binding) = record.route_binding.as_mut() else ...` and mutate through the borrow in both arms | [packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/src/zone_links.rs:1706] | actionable | lane/d2b-provider-zone-link.md +- `RS-0197` | low | `d2b-provider-zone-link` | `plan()` clones `record.enrollment` in the `EnrolledSessionEstablished` arm solely to compare the key fingerprint before mutating disjoint record fields | fix: take `record.enrollment.as_ref()`, compare `enrollment.key_fingerprint() != &peer_key_fingerprint` (fingerprint tokens are Copy), and let the borrow end before the `record.link_epoch += 1` mutation | [packages/d2b-provider-zone-link/src/zone_links.rs:1526] | actionable | lane/d2b-provider-zone-link.md + +**`d2b-resource-api`** + +- `RS-0198` | low | `d2b-resource-api` | every bus scoped commit clones the full assignment-mutation list (`transport.mutations().to_vec()`) even though the whole chain only borrows it | fix: change `ResourceApiClient::scoped_commit_batch` (client.rs:110) and `ResourceService::commit_scoped_batch` (service.rs:852) to take `&[ScopedResourceMutation]` and pass `transport.mutations()` directly at adapter.rs:425 | [adapter.rs:425, client.rs:110, service.rs:852] | actionable | lane/d2b-resource-api-p1.md +- `RS-0199` | low | `d2b-resource-api` | redundant `.cloned()` in `StoreAdmissionBinding::verify`: `mutations` is already owned after the destructure, so the iterator clones every mutation before `prepare_mutation` consumes it | fix: `mutations.into_iter().map(prepare_mutation)` | [packages/d2b-resource-api/src/admission.rs:338, packages/d2b-resource-api/src/admission.rs:344, packages/d2b-resource-api/src/admission.rs:345] | actionable | lane/d2b-resource-api-p2.md + +**`d2b-resource-client`** + +- `RS-0200` | low | `d2b-resource-client` | by-value `resource_ref()` accessors clone a `ResourceRef` (target.rs:155, 279, 407) and `ResolvedTarget::matches_assignment` clones just to compare (`self.resource_ref().as_ref() == Some(reference)`, target.rs:424) | fix: give the in-crate comparison a borrow-returning variant (`Option<&ResourceRef>`) and consider tightening the pub accessors later, migrating about 15 caller files | [packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs:279, packages/d2b-resource-client/src/target.rs:407, packages/d2b-resource-client/src/target.rs:424] | actionable | lane/d2b-resource-client.md + +**`d2b-resource-compiler`** + +- `RS-0202` | medium | `d2b-resource-compiler` | LinuxAnchoredDir's three flag accessors (resolve_flags, readable_flags, executable_flags) are public, return rustix::fs::{ResolveFlags,OFlags} (making rustix part of the public contract), and have zero callers anywhere | fix: delete the accessors (the anchored impl reads the module constants directly unless a real consumer arrives | [packages/d2b-resource-compiler/src/linux.rs:93, packages/d2b-resource-compiler/src/linux.rs:98, packages/d2b-resource-compiler/src/linux.rs:103] | actionable | lane/d2b-resource-compiler.md +- `RS-0201` | low | `d2b-resource-compiler` | SchemaCache uses RefCell for a lazy schema cache though the only two call sites could take `&mut self` | fix: change `fn schema(&self,...)` to `fn schema(&mut self,...)`, drop the RefCell holding the cache in plain `BTreeMap` field, and mark `let mut schema_cache` in validate_resources | [packages/d2b-resource-compiler/src/main.rs:1148, packages/d2b-resource-compiler/src/main.rs:1631, packages/d2b-resource-compiler/src/main.rs:818, packages/d2b-resource-compiler/src/main.rs:846] | actionable | lane/d2b-resource-compiler.md +- `RS-0203` | low | `d2b-resource-compiler` | validate_schema_node_with_budget re-gets additionalProperties/items after an if-let shape check and panics "checked above" where a pattern bind removes the second get | fix: `if let Some(additional @ Value::Object(_)) = object.get("additionalProperties") { ... additional ... }` (same for items | [packages/d2b-resource-compiler/src/main.rs:1467, packages/d2b-resource-compiler/src/main.rs:1468, packages/d2b-resource-compiler/src/main.rs:1477, packages/d2b-resource-compiler/src/main.rs:1478] | actionable | lane/d2b-resource-compiler.md +- `RS-0204` | low | `d2b-resource-compiler` | usage() takes a program param it never uses and silences it with `let _ = program;` | fix: drop the `program` parameter (and its `env::args_os().next()` binding from usage() andits six call sites (main.rs:242,245,254,261,264,265 | [packages/d2b-resource-compiler/src/main.rs:269, packages/d2b-resource-compiler/src/main.rs:270] | actionable | lane/d2b-resource-compiler.md +- `RS-0205` | low | `d2b-resource-compiler` | validate_resources serializes every resource with serde_json::to_vec just to measure its wire size, allocating a fresh buffer per resource | fix: serialize into a counting io::sink-style Write (or walk the Value once for a length to drop the per-resource Vec | [packages/d2b-resource-compiler/src/main.rs:704] | actionable | lane/d2b-resource-compiler.md + +**`d2b-resource-runtime`** + +- `RS-0206` | low | `d2b-resource-runtime` | `ResourceView::observed_status` clones the whole `Option` (which can carry a `DriverFailure` with comparison vectors) before the generation filter, so a stale status is copied and then discarded | fix: `self.status.as_ref().filter(|_| self.status_generation == Some(self.generation)).cloned()` | [packages/d2b-resource-runtime/src/manager.rs:205] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0209` | low | `d2b-resource-runtime` | insert_new clones the entire row (spec and metadata Vecs included) only to stamp generation/deleting/created_at | fix: take row: StoredDesiredResource by value in insert_new and destructure it, dropping `..row.clone()`; the caller at spec_store.rs:346 does not use row afterwards | [packages/d2b-resource-runtime/src/spec_store.rs:520-541] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0207` | low | `d2b-resource-runtime` | `ResourceActor::pre_start` clones `args.row` twice (once into the context, once into `state.row`) where one move and one clone suffice | fix: move `args.row` into `ResourceActorState.row` and clone it only for `ResourceContext::new` | [packages/d2b-resource-runtime/src/resource.rs:714, packages/d2b-resource-runtime/src/resource.rs:732] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0210` | low | `d2b-resource-runtime` | SpecStore::list clones the selector's zone/type_name/owner_uid fields to bind SQL params | fix: bind borrowed forms (selector.zone.as_deref(), selector.type_name.as_deref(), selector.owner_uid.as_deref()), which rusqlite params accept | [packages/d2b-resource-runtime/src/spec_store.rs:596-598] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0208` | low | `d2b-resource-runtime` | `spec_object` returns `Ok(spec.clone())` on an owned `serde_json::Value` where the move `Ok(spec)` is legal (the value is not used after) | fix: drop the `.clone()` | [packages/d2b-resource-runtime/src/metadata.rs:191] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0211` | low | `d2b-resource-runtime` | TargetDirectory::assign clones the assignment twice (once into the map, once for the return value) | fix: insert the owned assignment and clone from the map for the return, halving the copies of the 3-string ResourceKey and the resolved handle | [packages/d2b-resource-runtime/src/target.rs:655, packages/d2b-resource-runtime/src/target.rs:663] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0212` | low | `d2b-resource-runtime` | json_object clones every member Value into the map although every caller constructs the member array inline | fix: take members: impl IntoIterator and move values into the map | [packages/d2b-resource-runtime/src/guest_target.rs:1004-1009] | actionable | lane/d2b-resource-runtime-p2.md + +**`d2b-session`** + +- `RS-0213` | low | `d2b-session` | take_authentication and from_verified_adapter clone the whole EndpointPolicy just to build a comparison HandshakeOffer | fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in d2b-contracts-zone-session and call HandshakeOffer::from(policy) | [engine.rs:689, admission.rs:593] | actionable | lane/d2b-session-p2.md + +**`d2b-sk-frontend`** + +- `RS-0214` | low | `d2b-sk-frontend` | `main` clones the whole `PlacementConfig` (owned `ZoneEnrollmentIdentity` inside) only to keep `config` alive for its other fields, and `config.rs` builds `"/dev/uhid".to_owned()` where `PathBuf::from` suffices | fix: destructure `let Config { vm_id, link, uhid_path, placement } = config;` and call `placement.into_placement()` (drop the clone); write `PathBuf::from("/dev/uhid")` via `optional("D2B_SK_UHID_PATH").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/dev/uhid"))` | [packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83] | actionable | lane/tail-6.md + +**`d2b-zone-routing`** + +- `RS-0215` | low | `d2b-zone-routing` | In `ZoneRouteAdmission::consume`, the snapshot's zone pair is copied from `expected` with two `ZonePath` clones per consumed route admission, though `expected` is already owned by the match arm and only compared afterwards | fix: compare every non-zone field first, then move `expected.source_zone`/`expected.target_zone` intosnapshot (or split `validate_snapshot` into a zone-pair phase taking `expected` by value), removing the two clones | [packages/d2b-zone-routing/src/engine.rs:345, packages/d2b-zone-routing/src/engine.rs:346] | actionable | lane/d2b-zone-routing.md + +**`d2bd`** + +- `RS-0221` | low | `d2bd` | the `run_effect` closure (bound `F: FnOnce`) clones `supervisor` and `process_ticket` a second time inside its body, though the captured values can move straight into the `async move` block (which only borrows them( | fix: remove `let supervisor = supervisor.clone();` and `let process_ticket = adoption_ticket.clone();`, letting the outer captures move into the `async move` | [packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_composition.rs:4344] | actionable | lane/d2bd-p5.md +- `RS-0222` | low | `d2bd` | `match context.owner_uid.clone()` at ticket assembly clones the whole `Option` (a String-backed uid) on every launch, including the `None` arm and the guard-false `Some` arm where the value is never consumed | fix: match on `&context.owner_uid` and clone inside the arm (`Some(owner_uid) if ticket.owner_uid().is_none() => ticket.with_owner_uid(owner_uid.clone())`), so the `_ => ticket` path copies nothing | [packages/d2bd/src/process_provider_runtime.rs:4057] | actionable | lane/d2bd-p7.md +- `RS-0216` | low | `d2bd` | avoidable `row.resource_ref.clone()` in `committed_controller_provider_identities`: the field is only borrowed by `committed_provider_spec` and then moved into the result map | fix: pass `&row.resource_ref` to `committed_provider_spec` and `identities.insert(row.resource_ref, (uid, generation))` after the call | [packages/d2bd/src/resource_runtime.rs:359] | actionable | lane/d2bd-p1.md +- `RS-0218` | low | `d2bd` | `let zone = guard.zone().clone()` clones the ZoneId although `guard` can be borrowed for the whole body (it is only used again by its own Drop at scope end) | fix: bind `let zone = guard.zone();` and pass `&zone` to plane.zone and the json! formatters | [packages/d2bd/src/composition.rs:20404] | actionable | lane/d2bd-p3.md +- `RS-0217` | low | `d2bd` | nine call sites pass `.to_owned()` into parsers that take `impl Into` (d2b-contracts-resource identity.rs:79,155,279,393), where `&str: Into` makes the allocation unnecessary | fix: drop `.to_owned()` at 181, 4625, 9911, 9931, 10096, 10138, 10212, 11078, 11079, 11082 | [packages/d2bd/src/resource_runtime.rs:181, packages/d2bd/src/resource_runtime.rs:4625, packages/d2bd/src/resource_runtime.rs:9931, packages/d2bd/src/resource_runtime.rs:10096] | actionable | lane/d2bd-p1.md +- `RS-0219` | low | `d2bd` | typed_error_from_resolution_error clones `workload_id` while destructuring an owned error; the binding can be moved into TypedError::WorkloadAliasConflict because `candidates` is only joined by reference | fix: bind `workload_id` (no `.clone()`) in the AliasConflict arm | [packages/d2bd/src/composition.rs:21091] | actionable | lane/d2bd-p3.md +- `RS-0223` | low | `d2bd` | avoidable `let zone = request.zone.clone();` in `ForwardRendezvous::invoke`: `zone` is used only as the `BTreeMap::get` key inside the `self.zones.lock().await` block, whose scope does not outlive the `request` borrow, so `zones.get(&request.zone)` compiles without the clone | fix: drop the clone and borrow `&request.zone` | [packages/d2bd/src/forward_rendezvous.rs:456, packages/d2bd/src/forward_rendezvous.rs:458-466] | actionable | lane/d2bd-p8.md +- `RS-0220` | low | `d2bd` | `ResourceName::parse(readable.clone())` clones a just-built String although parse takes `impl Into` and `&readable` converts without allocation | fix: `ResourceName::parse(&readable)` | [packages/d2bd/src/composition.rs:20638] | actionable | lane/d2bd-p3.md +- `RS-0224` | low | `d2bd` | `validate_network_config_volume_spec` clones the whole JSON `spec` document (`let mut base = spec.clone();`) just to strip three fields and re-parse as `VolumeSpec`; on the `upsert_volume_content` path the document is cloned again at the caller, so the same wire document is cloned and re-parsed twice per reconcile/readiness check | fix: take the spec by ownership once at the boundary and parse to `VolumeSpec` directly (drop the clone by passing the already-owned `Value`) | [packages/d2bd/src/shared_provider_effects.rs:690, packages/d2bd/src/shared_provider_effects.rs:854-858, packages/d2bd/src/shared_provider_effects.rs:891-895] | actionable | lane/d2bd-p8.md + +**`d2bd-runtime`** + +- `RS-0225` | low | `d2bd-runtime` | DagExecutor::run_split clones `state` into api_ready then matches the same value by move, when matching `&state` would keep it | fix: `match &state { .. }`, bind `ApiReadyState::Error { reason }` by reference in the format! call, and set `api_ready = Some(state)` after the match | [dag.rs:423-424] | actionable | lane/d2bd-runtime-p1.md +- `RS-0226` | low | `d2bd-runtime` | three `operation_id.to_string()` copies of an already-owned `String` are produced only to be borrowed or passed along (`complete_pending` takes `String` just for one comparison), so each completed/rejected helper op pays a heap alloc | fix: change `complete_pending` to take `operation_id: &str` and pass `&result.operation_id` / `&rejected.operation_id` at the three call sites (the second local `let operation_id = result.operation_id.to_string()` becomes `&result.operation_id` directly) | [packages/d2bd-runtime/src/unsafe_local_helper.rs:625, packages/d2bd-runtime/src/unsafe_local_helper.rs:629, packages/d2bd-runtime/src/unsafe_local_helper.rs:644] | actionable | lane/d2bd-runtime-p3.md +- `RS-0227` | low | `d2bd-runtime` | `ConsoleSessionTable` lookups allocate a `String` on every call (`ConsoleClientHandle(session_handle.to_owned())` in five methods) because the map key newtype does not implement `Borrow` | fix: implement `Borrow` for `ConsoleClientHandle` (or key the two maps by `String`) so `self.clients.get(session_handle)` resolves without allocation | [packages/d2bd-runtime/src/console_session.rs:250, packages/d2bd-runtime/src/console_session.rs:268, packages/d2bd-runtime/src/console_session.rs:293, packages/d2bd-runtime/src/console_session.rs:304] | actionable | lane/d2bd-runtime-p4.md +- `RS-0228` | low | `d2bd-runtime` | every audit write clones the whole `DaemonEvent` (strings included) in `enqueue` because the write API takes `&DaemonEvent`, while every caller (d2bd composition.rs:19356, tests) constructs the event solely to write it | fix: change `write_event`/`write_event_with_authority`/`write_event_async`/`write_event_with_authority_async` to take `DaemonEvent` by value and drop the `event: event.clone()` in `enqueue` | [packages/d2bd-runtime/src/daemon_audit.rs:976, packages/d2bd-runtime/src/daemon_audit.rs:1003] | actionable | lane/d2bd-runtime-p4.md + +**`xtask`** + +- `RS-0231` | low | `xtask` | `check_members(&repo_root, members.clone())` clones the whole workspace-member vec at the check entry point because `check_members` (provider_crate_policy.rs:7916) takes `Vec` by value while its body only reads it (`.iter()`, `.iter().map()`); the signature forces the clone | fix: change `fn check_members(repo_root: &Path, members: &[WorkspaceMember])` and drop the clone at the call site (second caller at 9560 passes `&manifest_workspace_members(&root)?`) | [packages/xtask/src/provider_crate_policy.rs:577, packages/xtask/src/provider_crate_policy.rs:7916] | actionable | lane/xtask-p2.md +- `RS-0236` | low | `xtask` | `compute_context(root, spec)` takes `ContextSpec` by value,so both caller loops clone the spec they still need afterwards | fix: change `fn compute_context(root: &Path, spec: ContextSpec)` (and the `compute_lock_context` recursion at production_closure.rs:431) to take `spec: &ContextSpec`,removing the `.clone()` at both loop call sites | [packages/xtask/src/production_closure.rs:263, packages/xtask/src/production_closure.rs:379] | actionable | lane/xtask-p4.md +- `RS-0238` | low | `xtask` | Baseline map build clones each `CrateCensus`'s `crate_dir` and `counts` twice per crate although the later baseline check only re-borrows them | fix: build `CensusBaseline` from `crates.into_iter().map(|c| (c.crate_dir, c.counts)).collect()` (when `json_out` is set( and drive the `--baseline` check loop from `&baseline.crates` instead of `&crates` | [packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287] | actionable | lane/xtask-p5.md +- `RS-0232` | low | `xtask` | `check_shared_family_knowledge_with` builds `exempt: BTreeSet<(String, &str)>` with `row.module.to_owned()` and probes it with `signal.module.clone()`, when the ratchet rows are `&'static str` and the signal already owns a `String`; both the build-time to_owned and the per-signal clone disappear by keying borrowed strs | fix: `let exempt: BTreeSet<(&str, &str)> = ratchet.iter().map(|row| (row.module, row.token)).collect()` and probe `exempt.contains(&(signal.module.as_str(), signal.token))` | [packages/xtask/src/provider_crate_policy.rs:5200, packages/xtask/src/provider_crate_policy.rs:5206] | actionable | lane/xtask-p2.md +- `RS-0237` | low | `xtask` | `check_outputs` binds `ApprovalProjection` twice in a row,but the first binding is never read after the second clone | fix: replace `let approval = advisory.approval.clone();` followed by `Some(approval.clone())` with one `Some(advisory.approval.clone())` | [packages/xtask/src/production_closure.rs:383, packages/xtask/src/production_closure.rs:386] | actionable | lane/xtask-p4.md +- `RS-0234` | low | `xtask` | `nix_string_list` takes `impl IntoIterator`, forcing every caller to `.to_owned()` its `&'static str` fields at seven call sites only to borrow them again inside `nix_string` | fix: change the signature to `impl IntoIterator` (or `&[&str]`) and delete the `.map(|field| (*field).to_owned())` closures at the call sites | [packages/xtask/src/provider_packaging.rs:163, packages/xtask/src/provider_packaging.rs:206, packages/xtask/src/provider_packaging.rs:222, packages/xtask/src/provider_packaging.rs:230] | actionable | lane/xtask-p3.md +- `RS-0233` | low | `xtask` | `profile_catalog` clones every row's `wire_variant` String (`row.wire_variant.clone()`) only to format it into the generated profile catalog text; the values are never mutated or stored | fix: return `Vec<&str>` via `.filter_map(|row| row.wire_variant.as_deref())` and change `string_list` (gen_broker_operations.rs:772) to take `Item = &str` (its only two call sites are 860-861) | [packages/xtask/src/gen_broker_operations.rs:844, packages/xtask/src/gen_broker_operations.rs:772] | actionable | lane/xtask-p2.md +- `RS-0235` | low | `xtask` | `resource_ref_schema(pattern: String, allowed_types: &[String])` forces `.to_owned()`/`String::from` at every call site, including static regex literals that never need an owned String | fix: change the signature to `pattern: &str` and `allowed_types: &[&str]` (both serialize into `json!` unchanged) and drop the conversions at the call sites | [packages/xtask/src/semantic_service_schemas.rs:32, packages/xtask/src/semantic_service_schemas.rs:44, packages/xtask/src/semantic_service_schemas.rs:55, packages/xtask/src/semantic_service_schemas.rs:61] | actionable | lane/xtask-p3.md +- `RS-0229` | low | `xtask` | `apply_citation_fixes` clones `lines[index]` before mutating it (`let mut line = lines[index].clone();`) although the slot is borrowed `&mut` and then reassigned on the same iteration | fix: `let mut line = std::mem::take(&mut lines[index]);` per the skill's `mem::take` pattern | [packages/xtask/src/provider_crate_policy.rs:7257] | actionable | lane/xtask-p1.md +- `RS-0230` | low | `xtask` | two ratchet lookups build an owned tuple just to call `BTreeSet::contains`, allocating a cloned String per signal during tree-wide scans (`family_exempt.contains(&(signal.module.clone(), token))` and `exempt.contains(&(signal.crate_name.clone(), signal.module.clone(), signal.token))`) | fix: replace `contains` with `family_exempt.iter().any(|(module, token)| *module == signal.module && *token == token)` (and the 3-tuple equivalent), or key both sets on `&str` like the neighboring `structural_exempt` set | [packages/xtask/src/provider_crate_policy.rs:6375, packages/xtask/src/provider_crate_policy.rs:8750] | actionable | lane/xtask-p1.md + +### `type` + +Type-driven design: illegal states representable - flag soup, Option pairs, stringly-typed state, parse-once over validate-everywhere. + +**`X2-generated-boundary`** + +- `RS-0954` | medium | `X2-generated-boundary` | the broker catalog view emits the authz facets as string literals (`secret_access: "None"`, `broker_required: "Yes"`, `audit_mode: "Yes"` at `broker_operation_catalog.rs:25-27` and every row) into the hand-written `BrokerAuthzFacets` struct whose fields are `&'static str` (`catalog.rs:98-102`), while the same generator emits the same declared data as typed enums in the sibling authz view (`SecretAccess::None`, `BrokerRequirement::Yes`, `AuditMode::Yes` at `broker_operation_authz.rs:12-19`); the broker-composition router string-matches the facet (`row.authz.secret_access != "None"` at routing.rs:98) and a hand-written row already drifts case (`audit_mode: "yes"` at `d2b-broker/src/envelope/mod.rs:2277` vs generated "Yes") | fix: change `BrokerAuthzFacets.secret_access/broker_required/audit_mode` to the existing `SecretAccess`/`BrokerRequirement`/`AuditMode` enums (`d2b-core/src/privileges.rs:48,61,83`; d2b-broker already depends on d2b-core per Cargo.toml:48) and make `generate_catalog` emit enum idents exactly as `generate_authz` already does | [packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19] | actionable | lane/X2-generated-boundary.md +- `RS-0955` | medium | `X2-generated-boundary` | `BrokerOperationRow.disposition` is `&'static str` (`catalog.rs:181`) holding a closed 4-value set emitted by the generator (`disposition: "promoted-live"` etc. at `broker_operation_catalog.rs:17` and 97 more rows), string-matched at catalog.rs:590,773,779,791 and runtime.rs:12562, while the same generator already maps every other closed set to enums (`owner_variant`, profile match, `StubTarget`) | fix: add a `Disposition` enum (four variants: callable-read-only, promoted-live, stubbed-unimplemented, compile-time-only) beside `StubTarget` in `d2b-broker/src/catalog.rs:266`, change the struct field, and have `generate_catalog` emit `Disposition::X` like `owner_variant` | [packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_operation_catalog.rs:17, packages/d2b-broker/src/catalog.rs:181, packages/d2b-broker/src/catalog.rs:590] | actionable | lane/X2-generated-boundary.md +- `RS-0956` | low | `X2-generated-boundary` | the operation-name vocabulary is emitted as strings (`HOST_OPERATION_CATALOG`/`GUEST_OPERATION_CATALOG: &[&str]` at `broker_operation_profiles.rs:8-41`, `operation: "Hello"` at `broker_operation_catalog.rs:11`) and admission is a string `contains` (`BrokerProfile::allows_operation` at `d2b-contracts-broker/src/broker_wire.rs:864-889`), while the same generator emits the w3 subset as the typed `W3BrokerOperation` enum (`w3_broker_operations.rs`, re-exported at `d2b-contracts-broker/src/lib.rs:11`) | fix: have `generate_profiles`/`generate_catalog` emit a full closed `BrokerOperationName` enum (all 98 rows, not just the 24 w3 variants) with `as_str`, and type the catalogs and row `operation` field against it; the wire boundary keeps the string spelling via `as_str` | [packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11] | actionable | lane/X2-generated-boundary.md +- `RS-0957` | low | `X2-generated-boundary` | the authz view's positional `row)...)` helper calls carry a bare boolean at argument 5 (`false`/`true` for `destructive` at `broker_operation_authz.rs:12-19` and every row), the boolean-trap shape the type lens names, in a 988-line generated file where the field is the routing-relevant facet (`row.authz.destructive` at routing.rs:98) | fix: emit `Destructive::No`/`Destructive::Yes` (or named-field construction) from `generate_authz` and drop the `#[allow(clippy::too_many_arguments)]` on the hand-written `row()` helper at `d2b-core/src/privileges.rs:687-708` | [packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-core/src/privileges.rs:687-708] | actionable | lane/X2-generated-boundary.md + +**`X3-cross-crate-duplication`** + +- `RS-0962` | high | `X3-cross-crate-duplication` | Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one member, d2b-provider-wayland-policy, panics on caller input at the family engine's public boundary) | fix: type the args field as `d2b_contracts_resource::v3::ZoneId` (or a `BoundedToken`) in each `*DriverArgs` and parse once at the daemon construction boundary, with `SharedProviderDriverArgs` in d2b-provider-toolkit as the shared home the family args mirror | [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-credential/src/driver.rs:295] | actionable | lane/X3-cross-crate-duplication.md + +**`d2b`** + +- `RS-0263` | low | `d2b` | ZoneContext stores the validated Zone name as a bare String and re-validates it at every construction site instead of carrying the invariant in the already-imported ZoneId type | fix: store `ZoneId` in ZoneContext (field at context.rs:713), build `zone_ref()` and `zone_name()` from it, delete `validate_zone_name` (context.rs:2751) and the duplicated double validation in `discover` (context.rs:752 and context.rs:763), and replace the `expect` re-parses in `from_socket` (context.rs:801-803) with direct construction | [context.rs:713, context.rs:2751, context.rs:801] | actionable | lane/d2b-p1.md +- `RS-0264` | low | `d2b` | closed CLI vocabularies carried as `String` and validated at every call site: `ExecKillArgs.signal` checked by `matches!` in `kill`, and `endpoint_class: Option` checked by `validate_endpoint_class` in `list` and `watch` | fix: clap `ValueEnum` on the args fields so an invalid value is a parse error and the runtime checks disappear | [packages/d2b/src/exec.rs:90, packages/d2b/src/exec.rs:345, packages/d2b/src/endpoint.rs:34, packages/d2b/src/endpoint.rs:42] | actionable | lane/d2b-p3.md + +**`d2b-audit`** + +- `RS-0239` | medium | `d2b-audit` | `EvidenceChain` derives `Deserialize` (evidence_chain.rs:50) while its accessors assume a non-empty identity list: `invoking_identity()` panics via `.last().expect)...)`, `initiating_identity()` indexes `&self.identities[0]`, and `depth()` underflows on `len() - 1`; the "identities never empty" invariant is enforced only by the constructors, so a wire payload with `"identities": []` deserializes into the illegal state | fix: hand-write `Deserialize` for `EvidenceChain` rejecting an empty `identities` (the crate's own admission-gate pattern in operation.rs), or make the accessors total | [packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115, packages/d2b-audit/src/evidence_chain.rs:121, packages/d2b-audit/src/evidence_chain.rs:102] | actionable | lane/d2b-audit.md + +**`d2b-broker`** + +- `RS-0242` | medium | `d2b-broker` | QmpAttachCleanup models its four-step rollback as four bools (16 states, ~5 valid)with a fixed teardown order | fix: replace `device_added/raw_added/file_added/fdset_added: bool` with an ordered step list or enum so rollback order cannot drift from the attach order | [packages/d2b-broker/src/ops/media.rs:889-892] | actionable | lane/d2b-broker-p7.md +- `RS-0240` | low | `d2b-broker` | `StorageContractError::Refused { reason: String }` carries a closed set of refusal slugs ("storage-path-parent-dir-refused", "storage-path-outside-owned-roots", "storage-path-escapes-owned-root", ...) that tests string-match (storage_contract.rs:380-403) and audit records emit | fix: introduce a `RefusalReason` enum (serde lowercase) so the slug set is exhaustive and a new refusal cannot typo; wire/audit-visible strings make this needs-contract | [packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_contract.rs:380] | needs-contract | lane/d2b-broker-p3.md +- `RS-0241` | low | `d2b-broker` | `reload_behavior` is a stringly-typed wire value re-validated at every call site (`validate_nm_reload_behavior` here and the remove path in ops/nm.rs, per the doc at live_handlers.rs:288-290) instead of parsed once at the bundle boundary | fix: parse `reloadBehavior` into an enum in the bundle resolver so both arms branch on the parsed type and a hand-declared typo fails at resolution; `reloadBehavior` is pinned in docs/reference/schemas/v1/host.json:409 and v2/host.json:543, so needs-contract | [packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362] | needs-contract | lane/d2b-broker-p3.md + +**`d2b-bus`** + +- `RS-0245` | medium | `d2b-bus` | `ZoneLinkSession` carries `admission: Option` and `liveness: Option` that are always both `Some` or both `None` (the two constructors set them in lockstep), so a half-set lane is representable and would silently skip admission revalidation | fix: fold the pair into one `established: Option` holding both values (the test lane stays the `None` case), making the impossible combination unconstructible | [packages/d2b-bus/src/session/zone_link.rs:111-117] | actionable | lane/d2b-bus-p2.md +- `RS-0243` | low | `d2b-bus` | ResourceQuery carries assignment: Option and scope: Option that are always both Some or both None, with a runtime validate_scoped re-check at every use site to keep the pair in sync | fix: fold the pair into one Option<(AssignmentIdentity, ScopedResourceScope)> or a ScopedQuery struct so the one-Some state is unrepresentable and the re-validation disappears | [packages/d2b-bus/src/router.rs:218-219, packages/d2b-bus/src/router.rs:298-337] | actionable | lane/d2b-bus-p1.md +- `RS-0244` | low | `d2b-bus` | UnixSubjectRecord holds expected_peer: Option and expected_peer_uid: Option where exactly one is always Some, and bind() ORs the two options at match time as if the state were open | fix: replace the pair with an enum (Exact(PeerCredentials) | Uid(u32)) so the exactly-one invariant is structural and the runtime OR branch disappears | [packages/d2b-bus/src/router.rs:1445-1446, packages/d2b-bus/src/router.rs:1667-1674] | actionable | lane/d2b-bus-p1.md + +**`d2b-contracts-broker`** + +- `RS-0246` | medium | `d2b-contracts-broker` | `HandoffCoordinator.source_remains_usable: bool` is fully derivable from `state` (false iff `Completed`, true in every other phase), so the pair `{ state: Completed, source_remains_usable: true }` is an illegal state constructible through durable-record deserialization and the two fields can desync | fix: drop the field, derive the accessor from `self.state != HandoffState::Completed`, keep `#[serde(default)]` for old broker records (the wire `ApplyHostGenerationHandoffResponse.source_remains_usable` field stays as-is) | [packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broker/src/host_generation.rs:294-315] | actionable | lane/d2b-contracts-broker.md +- `RS-0247` | medium | `d2b-contracts-broker` | `CanonicalAuditDigest(pub String)` exposes a public field that bypasses the SHA-256-spelling invariant its `parse` constructor and hand-written `Deserialize` enforce, so a literal construction can mint an invalid digest | fix: make the tuple field private and keep `as_str()` (serde transparent and JsonSchema work with a private field; wire shape unchanged) | [packages/d2b-contracts-broker/src/broker_wire.rs:2805, packages/d2b-contracts-broker/src/broker_wire.rs:2807-2821] | actionable | lane/d2b-contracts-broker.md + +**`d2b-contracts-control`** + +- `RS-0248` | medium | `d2b-contracts-control` | `AuditResponse` pairs `complete: bool` with `next_cursor: Option`, encoding 4 states of which 2 are illegal, guarded only by the runtime `validate_audit_page` at deserialize | fix: replace the pair with an enum (`Complete` / `More(AuditExportCursor)`) so the illegal combos are unrepresentable, deleting `validate_audit_page` | [public_wire.rs:2166, public_wire.rs:2203] | needs-contract | lane/d2b-contracts-control.md +- `RS-0249` | low | `d2b-contracts-control` | status DTOs carry stringly-typed state (`mode`, `state`, `kind`, `status` as `String`) mirroring daemon-side vocabularies instead of closed enums | fix: convert the closed vocabularies (realm mode, gateway state, qemu runner/registry state, read-model kind) to kebab-case enums on both daemon and wire sides | [cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672] | needs-contract | lane/d2b-contracts-control.md +- `RS-0250` | low | `d2b-contracts-control` | `MutationFlags` models dry-run/apply/json as three booleans while the doc comment itself records that "the daemon rejects requests that set neither `dry_run` nor `apply`", i.e. an illegal state the type still represents | fix: encode the mode as an enum variant (e.g. `MutationMode::{DryRun, Apply}` plus a separate json flag) and delete the daemon-side runtime rejection | [public_wire.rs:316, public_wire.rs:311] | needs-contract | lane/d2b-contracts-control.md + +**`d2b-contracts-provider`** + +- `RS-0253` | medium | `d2b-contracts-provider` | `BindingChildRequest::process` and `process_for_user` accept `kind: BindingChildKind` including `Endpoint`, so an Endpoint carrying process fields is constructible and must be rejected at runtime (`InvalidProducer`, child_resources.rs:502-510), and the sibling check `producer_role.is_some() && kind != Endpoint` (child_resources.rs:499) is unreachable because only `endpoint()` sets `producer_role` and it hardcodes `Endpoint` | fix: take a restricted `ProcessChildKind { Process, EphemeralProcess }` in the two process constructors (all seven in-tree call sites pass `BindingChildKind::Process`), then delete both runtime checks | [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:499, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:502] | actionable | lane/d2b-contracts-provider-p2.md +- `RS-0251` | low | `d2b-contracts-provider` | `ComponentDescriptor::new` takes a `declares_state_volume: bool` parameter that can only be `false`: `true` is rejected at the top of the constructor, the Deserialize path passes the literal `false`, and the flag is only ever set through `with_state_namespaces` | fix: remove the parameter from `ComponentDescriptor::new` and update the ~20 call sites (census below), keeping the wire-only `declaresStateVolume` field and its consistency check inside the Deserialize Wire struct | [packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/src/v3/provider.rs:1368, packages/d2b-contracts-provider/src/v3/provider.rs:1720, packages/d2b-contracts-provider/src/v3/provider.rs:3455] | actionable | lane/d2b-contracts-provider-p1.md +- `RS-0252` | low | `d2b-contracts-provider` | `ComponentDescriptor` stores `execution` and `execution_wire` as parallel fields where the wire shape is derived from the enum, so one fact has two representations that only `with_execution` keeps in sync | fix: implement `Serialize` for `ComponentExecution` emitting the flat `binaryRef` key (absent for `InProcessBootstrap`), drop the `execution_wire` field and the private `ComponentExecutionWire` struct | [packages/d2b-contracts-provider/src/v3/provider.rs:1333, packages/d2b-contracts-provider/src/v3/provider.rs:1335, packages/d2b-contracts-provider/src/v3/provider.rs:1418] | actionable | lane/d2b-contracts-provider-p1.md + +**`d2b-contracts-resource`** + +- `RS-0256` | medium | `d2b-contracts-resource` | NixosGenerationStatus.observed_generation is a bare u64 while the crate already models exactly this value (zero meaning none) as ObservedGeneration in identity.rs | fix: replace the field type with `ObservedGeneration` (serde-transparent u64, same wire bytes and schemars shape) and update the accessor call sites | [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-resource/src/v3/identity.rs:595-606] | needs-contract | lane/d2b-contracts-resource-p2.md +- `RS-0255` | medium | `d2b-contracts-resource` | store-contract digests are bare `String` (`StoredResource.payload_digest` mod.rs:71, `StoredSchema.payload_digest` mod.rs:239, `PreparedStoreMutation.payload_digest` mod.rs:374) while every other identity in this crate is a parsed newtype (SchemaFingerprint, StateDigest), so a non-digest string can flow through the store boundary without a type-level guarantee | fix: type the three fields as `SchemaFingerprint` (or `StateDigest`) and parse at the backend boundary where the digest is computed | [packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resource/src/v3/operations/mod.rs:239, packages/d2b-contracts-resource/src/v3/operations/mod.rs:374] | actionable | lane/d2b-contracts-resource-p1.md +- `RS-0257` | medium | `d2b-contracts-resource` | ActivationRunnerInput.target_generation is a bare u64 carrying a manual zero check plus a hand-rolled `nonzero_u64_schema`, duplicating the nonzero-generation newtype the crate already generates | fix: use the `nonzero_generation!` macro output (e.g. ConfigurationGeneration, transparent u64 with JsonSchema minimum 1) for the field, deleting `ActivationRunnerInputError::GenerationInvalid`, the zero check in `new`, and `nonzero_u64_schema` | [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:59-63, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:77-87, packages/d2b-contracts-resource/src/v3/identity.rs:448-472] | needs-contract | lane/d2b-contracts-resource-p2.md +- `RS-0254` | low | `d2b-contracts-resource` | `StoreSealIdentity::with_store_epoch` (seal.rs:57-61) documents "Bind the seal identity to a nonzero store epoch" but accepts 0 without a check, and the fn has no callers, so the promised invariant is unenforced and untested | fix: reject 0 (return `Result` or `debug_assert!` plus a documented contract) or drop the nonzero claim from the doc | [packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resource/src/v3/operations/seal.rs:58] | actionable | lane/d2b-contracts-resource-p1.md + +**`d2b-contracts-zone-session`** + +- `RS-0258` | low | `d2b-contracts-zone-session` | narrowing_set_is_subset takes a bare empty_allowed_is_unrestricted: bool that flips the empty-allowed semantics between call sites | fix: replace the bool with a two-variant enum (or split into named fns) so the three call sites state the policy they mean | [role_binding.rs:179-182, role_binding.rs:149-162] | actionable | lane/d2b-contracts-zone-session-p2.md + +**`d2b-controller-toolkit`** + +- `RS-0259` | low | `d2b-controller-toolkit` | `ResourceSnapshot` carries `owner_uid: Option` and `owner_generation: Option` that are only ever set together, leaving the illegal one-Some/one-None combination constructible | fix: introduce `OwnerIdentity { uid, generation }` and replace the pair with a single `Option` (fields context.rs:17-18, constructor :61-67; the only external setter call passes both Some - packages/d2b-provider-provider/src/driver.rs:559) | [packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/context.rs:61-67] | actionable | lane/tail-1.md + +**`d2b-core`** + +- `RS-0261` | medium | `d2b-core` | `ManifestShellName(pub String)` exposes its inner String publicly, so the shell-name shape invariant enforced in the hand-written `Deserialize` (and in `shell_name_valid`) can be bypassed by literal construction | fix: make the field private and add an `as_str()` accessor, mirroring the `AllocatorRealmPath` newtype pattern in allocator_config.rs; serde(transparent) keeps the wire shape unchanged | [packages/d2b-core/src/manifest_v04.rs:313] | actionable | lane/d2b-core-p2.md + +**`d2b-core-controller`** + +- `RS-0260` | low | `d2b-core-controller` | AuthorityRequest::provider decides ProviderCardinality by string-comparing the rendered ref to "Provider/observability-otel", a stringly-typed special case whose why is not documented | fix: extract a named constant (e.g. `const OPTIONAL_PROVIDER_REF: &str = "Provider/observability-otel";`) beside the other domain constants and add a one-line doc noting the otel Provider is the one optional cardinality (D049 initial-Provider freeze), or move the decision into a `ProviderCardinality::for_provider(&ResourceRef)` helper | [authority.rs:985-988] | actionable | lane/d2b-core-controller-p2.md + +**`d2b-host`** + +- `RS-0262` | medium | `d2b-host` | `BusId(pub String)` carries no lexical invariant: `BusId::new` accepts any string and the field is public, so the busid grammar is re-validated at every consumer instead of once at the type boundary | fix: make the field private, validate in `BusId::new` (reusing `media::validate_usb_busid`'s grammar) or add `TryFrom<&str>`, keep `#[serde(transparent)]`; then delete the three broker re-validation sites | [packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194] | actionable | lane/d2b-host.md + +**`d2b-process-conformance`** + +- `RS-0265` | low | `d2b-process-conformance` | LaunchTicket models the "zone identity + runtime scope" pairing as two independent `Option` fields whose both-or-neither invariant is re-checked at every mutation and again in `validate()` (`self.zone_uid.is_some() != self.runtime_scope.is_some()`), leaving the illegal single-`Some` state representable | fix: introduce one private struct bundling both (e.g. `struct RuntimeScopeBinding { zone_uid: ResourceUid, scope: ConfigurationDigest }` held as `Option`), keeping the two accessors; the XOR check and the per-mutator guards (ticket.rs:546-552) become unrepresentable | [packages/d2b-process-conformance/src/ticket.rs:387, packages/d2b-process-conformance/src/ticket.rs:395, packages/d2b-process-conformance/src/ticket.rs:768] | actionable | lane/d2b-process-conformance.md + +**`d2b-provider-audio-pipewire`** + +- `RS-0266` | low | `d2b-provider-audio-pipewire` | constructors re-validate invariants the admission gate already enforces: `AudioServiceSpec::owner` (endpoint type) and `AudioBindingSpec::new` (service/target ref types) return the same error variants `validate_audio_service`/`validate_audio_binding` produce, so the same invariant is checked at two layers and the constructors' `Result` promises a rejection path that is dead in practice | fix: drop the checks from `owner()`/`new()` (make them infallible) and keep `validate_audio_*` as the single parse-once admission gate, or delete the gate checks and keep the constructor checks | [src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, src/resource_type.rs:233-246] | actionable | lane/d2b-provider-audio-pipewire.md +- `RS-0267` | low | `d2b-provider-audio-pipewire` | the shared-vs-owned controller mode is a private bool `activate_promoted` (controller.rs:210 vs 218-224) and `finalize`/`finalize_shared` are byte-identical delegations to `finalize_inner`, so the two public methods' behavioral difference is invisible in their signatures and a caller can invoke `finalize_shared` on an owned controller and get promotion activation anyway | fix: encode the mode in the type (typestate or a `MicrophoneHandoff::{Enable,Defer}` field set by construction) so the method contract holds by construction, or collapse the two methods into one documented by the constructor | [src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199] | actionable | lane/d2b-provider-audio-pipewire.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0268` | medium | `d2b-provider-clipboard-wayland` | the config-sourced picker path bypasses the absolute-path validation that the --picker CLI flag enforces, because the check runs on args.picker before the merge with the config value | fix: validate the merged picker value (args.picker.clone().or(picker_from_config)) once after the merge, rejecting relative paths from either source | [src/bin/d2b-clipd.rs:140, src/bin/d2b-clipd.rs:142] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0269` | low | `d2b-provider-clipboard-wayland` | ClipboardRunnerContract carries two boolean fields (watched_configuration_is_dependency, component_session_only) that are hardcoded true in the only constructor clipboard_runner_contract(), leaving three unrepresentable-but-constructible states with no consumer | fix: fold the two flags into the contract's consts or delete the fields and their accessors | [packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:44-52] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0270` | low | `d2b-provider-clipboard-wayland` | the picker-completion key is a stringly-typed 7-field value joined with '|' in picker.rs and re-parsed by split('|') in history.rs, so a field-order or separator change silently breaks purge semantics | fix: introduce a small CompletionKey struct (or a shared builder/parser pair) with the fields typed, used by both PickerAuthority::complete and ClipboardHistory::purge_guest | [packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipboard-wayland/src/history.rs:283] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0271` | low | `d2b-provider-clipboard-wayland` | entry digests are bare "sha256:..." Strings whose only invariant is enforced by a starts_with("sha256:") prefix check at the receipt-minting boundary; a Digest newtype with a private field would make the check once at construction | fix: introduce an EntryDigest newtype constructed by ClipboardEntry (and parsed at the picker boundary) and use it in PickerReceipt and PickerResult::Selected | [packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard-wayland/src/history.rs:77] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-config-nixos`** + +- `RS-0272` | low | `d2b-provider-config-nixos` | stringly-typed request fields (`identifier`, `against`, `destination`) are re-validated at every entry (constructors, store methods, and `validate_operation`), and the duplicated guest-ref checks have already drifted: `ConfigSyncRequest::new` checks only the resource type while `validate_guest_ref` also requires a non-empty name, so "Guest/" passes the constructor yet fails the boundary | fix: parse-once request fields (private fields, `new()`/`try_from` as the only constructors, transparent serde keeps the wire JSON unchanged) so the per-entry `validate_*` calls collapse; align `ConfigSyncRequest::new` with `validate_guest_ref` | [packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixos/src/service.rs:300-306, packages/d2b-provider-config-nixos/src/service.rs:316-323, packages/d2b-provider-config-nixos/src/service.rs:326-336] | actionable | lane/d2b-provider-config-nixos.md + +**`d2b-provider-credential`** + +- `RS-0273` | low | `d2b-provider-credential` | `CredentialDriverArgs.zone: String` (and the mirrored `CredentialDriver.zone: String`) carries a bare string where the daemon already holds a validated `ZoneId`, so the driver re-derives and re-parses the zone at use sites instead of receiving the invariant | fix: change `zone` to `d2b_contracts_resource::v3::ZoneId` in `CredentialDriverArgs` (driver.rs:295) and `CredentialDriver` (driver.rs:344); the daemon construction site drops `inputs.zone.as_str().to_owned()` and passes `inputs.zone` (resource_plane_v3.rs:2969, where `ConstructionInputs.zone: ZoneId` at resource_plane_v3.rs:1784); `agent_child` then builds `format!("Zone/{}", self.zone.as_str())` without the fallible `ResourceRef::parse` failure path (driver.rs:457-461); test fixtures switch to `ZoneId::parse("dev").unwrap()` | [packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-credential/src/driver.rs:457, packages/d2bd/src/resource_plane_v3.rs:2969] | actionable | lane/d2b-provider-credential.md + +**`d2b-provider-credential-managed-identity`** + +- `RS-0274` | medium | `d2b-provider-credential-managed-identity` | `ManagedIdentityTeardownPlan` exposes its three bools as pub fields, letting a caller construct invalid combos (`stop_agent && delete_agent`, `delete_agent && clear_provider_revoke` that `teardown_plan` never emits | fix: make the fields private with `pub const fn` accessors (or replace with an ordered stage enum); update the literal constructions in tests/binding.rs:1214-1234 | [controller.rs:85-89, tests/binding.rs:1214-1234] | actionable | lane/d2b-provider-credential-managed-identity.md + +**`d2b-provider-device-gpu`** + +- `RS-0275` | medium | `d2b-provider-device-gpu` | `video_started: bool` duplicates `video_identity.is_some()` and is read only by the Debug impl, so the pair can drift into an illegal state | fix: delete the field and use `video_identity.is_some()` in the `GpuController` Debug impl | [packages/d2b-provider-device-gpu/src/controller.rs:79, packages/d2b-provider-device-gpu/src/controller.rs:326, packages/d2b-provider-device-gpu/src/controller.rs:442, packages/d2b-provider-device-gpu/src/controller.rs:552] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-guest`** + +- `RS-0276` | medium | `d2b-provider-guest` | GuestDriverArgs.zone is String while every other Guest surface speaks ZoneId (GuestEffectFacets.zone, GuestDriver.zone,,forcing a parse-at-construction expect at GuestDriver::new | fix: type GuestDriverArgs.zone as ZoneId and pass ZoneId directly into GuestDriver::new, dropping the expect and the daemon-side String round-trip | [packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:788, packages/d2bd/src/resource_plane_v3.rs:2926, packages/d2b-provider-guest/tests/registration.rs:15] | actionable | lane/d2b-provider-guest.md + +**`d2b-provider-guest-azure-container-apps`** + +- `RS-0277` | medium | `d2b-provider-guest-azure-container-apps` | AcaProviderConfig exposes all 11 fields `pub` while its sibling validated configs (AcaRuntimeConfig, AcaSandboxProfile, AcaReadinessPolicy) keep fields private behind constructors, so a literal construction bypasses the execution-boundary validation that `new()`/`validate()` enforce | fix: privatize the fields and add accessors (network_ref, sandbox_transport_alias, defaults are read in-crate at controller.rs:940-946; no external field reads exist) | [src/effects.rs:394-406] | actionable | lane/d2b-provider-guest-azure-container-apps.md + +**`d2b-provider-guest-azure-virtual-machine`** + +- `RS-0278` | medium | `d2b-provider-guest-azure-virtual-machine` | `operation: Option` and `operation_started_at_unix_ms: Option` are always Some-together/None-together on the controller (controller/mod.rs:186-187) and in `AzureVmRecoveryState` (controller/mod.rs:110-118), and `restore_recovery_state` line 278 exists only to reject the illegal half-Some combination | fix: group into `Option` in both the controller and the recovery record, and delete the pair check at controller/mod.rs:278 | [src/controller/mod.rs:278, src/controller/mod.rs:186] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md merged: d2b-provider-guest-azure-virtual-machine#15 +- `RS-0279` | medium | `d2b-provider-guest-azure-virtual-machine` | `BootstrapAdmission { psk: Option, state: BootstrapAdmissionState }` (bootstrap.rs:65-68) can represent Consumed/Expired-with-`Some(psk)`; `consume()` manually forces `psk = None` on every transition | fix: `enum BootstrapAdmission { Pending { psk: BootstrapPsk, expires_at_unix_ms: u64 }, Consumed, Expired }` so the illegal combination is unconstructible (the skill's Option-pair smell) | [src/bootstrap.rs:65, src/bootstrap.rs:82] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md merged: d2b-provider-guest-azure-virtual-machine#14 +- `RS-0280` | low | `d2b-provider-guest-azure-virtual-machine` | `AzureVmUpdate::Resize.size: String` is parse-validated at `validate_update` (controller/mod.rs:982) and parsed again at `apply_update` (controller/mod.rs:1008); `OpaqueAzureRef` is a validating, serde-transparent string wire type | fix: carry `size: OpaqueAzureRef` in the wire enum (JSON shape unchanged, a plain string) and drop both re-parses | [src/controller/mod.rs:82, src/controller/mod.rs:982] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md + +**`d2b-provider-guest-cloud-hypervisor`** + +- `RS-0281` | medium | `d2b-provider-guest-cloud-hypervisor` | `derive_private_runtime_scope` (identity.rs:857) and `CloudHypervisorController::private_runtime_scope` (controller.rs:1808) take `role: &str` validated against exactly the four `ChildRole` variants, stringly-typed state where the enum exists | fix: take `ChildRole` and use `role.suffix()` inside; update the test callers (tests/controller.rs:249, tests/redaction_test.rs:62-104, tests/guest_spec_validation_test.rs:107-110) | [identity.rs:857-865, controller.rs:1808-1818] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0282` | medium | `d2b-provider-guest-cloud-hypervisor` | `CloudHypervisorConfig::default_machine_type` reuses the credential vocabulary type `OpaqueAzureRef` (d2b_contracts_provider::v3::credential) for a machine type that `validate()` restricts to "q35"|"microvm" | fix: introduce a `MachineType` enum (serde kebab-case) in place of `OpaqueAzureRef`, updating the committed root-config.schema.json and provider config wire | [config.rs:20, config.rs:53] | needs-contract | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0283` | medium | `d2b-provider-guest-cloud-hypervisor` | `BootstrapGraph::vmm_readiness`/`vmm_lifecycle` take five positional booleans (bootstrap_graph.rs:142-176) where a swapped argument compiles and silently changes VMM start gating | fix: pass one readiness snapshot struct (the five facts already exist as `GuestDependencySnapshot` accessors) instead of five bools | [bootstrap_graph.rs:142-176, controller.rs:662-670] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0284` | medium | `d2b-provider-guest-qemu-media` | `validate_token` (packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417(re-implements exactly the bounds of the in-tree `BoundedToken::parse` (`^[a-z][a-z0-9-]*$`, up to 63 bytes (at packages/d2b-contracts-resource/src/v3/execution_policy.rs:187-191); a second, slightly looser copy lives in `validate_object_id` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:274) | fix: replace the 7 gate calls (config.rs:142, hotplug.rs:62, process_builder.rs:288, volume.rs:121,165, guest.rs:115,213(with `BoundedToken::parse)...).is_ok()` (route qmp's variant through a first-char check plus the helper), delete the local helper | [packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417, packages/d2b-contracts-resource/src/v3/execution_policy.rs:187, packages/d2b-provider-guest-qemu-media/src/config.rs:142] | actionable | lane/d2b-provider-guest-qemu-media.md +- `RS-0285` | medium | `d2b-provider-guest-qemu-media` | Public `impl Default for ProviderConfig` manufactures an invalid config (`controller_execution_ref: ResourceRef::parse("Guest/invalid").expect)...)` at packages/d2b-provider-guest-qemu-media/src/config.rs:92), which fails its own `validate()` ); its only consumer is a test asserting that invalidity | fix: delete the Default impl (and rewrite the test to build valid-then-mutated configs as its sibling test at tests/config_schema_projection.rs:27 already does), or replace with a `#[doc(hidden)]` `for_test()`-style constructor | [packages/d2b-provider-guest-qemu-media/src/config.rs:89, packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs:5] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-notification-desktop`** + +- `RS-0286` | low | `d2b-provider-notification-desktop` | `NotificationRunnerContract` carries two boolean flags (`watched_configuration_is_dependency`, `component_session_only`) where a cutover enum could make the states explicit | fix: after a policy/ADR change, fold them into a `CutoverState` enum; currently kept per the refusal ledger | [packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-engineering-audit-record.md:361] | policy-confirmed | lane/d2b-provider-notification-desktop.md + +**`d2b-provider-observability-otel`** + +- `RS-0287` | low | `d2b-provider-observability-otel` | ProviderAgentAuditEvent stores the four closed audit strings as `String`/`Option` and immediately discards the validated `BoundedToken` (parse-then-copy-back at as_str().to_owned()) | fix: store `BoundedToken`/small enums in the event fields (agent.rs:59,66-68),and render through `BoundedToken::as_str` in the Serialize impl (wire output unchanged) | [agent.rs:56, agent.rs:265, agent.rs:297] | actionable | lane/d2b-provider-observability-otel.md + +**`d2b-provider-process-minijail`** + +- `RS-0288` | low | `d2b-provider-process-minijail` | provider-identity validation is duplicated: `MinijailProcessProvider::validate` re-checks selected provider name and provider ref that `launch::validate_launch_ticket` repeats whenever a platform gate is present, so the two can drift apart | fix: drop the two identity checks from `validate_launch_ticket` (keep the gate check; rename it `validate_platform_gate` to disambiguate from the sibling `d2b-provider-process-systemd/src/launch.rs:8` function of the same name with different semantics) and use `crate::PROVIDER_REF` at lib.rs:160 instead of the literal string | [packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minijail/src/lib.rs:160, packages/d2b-provider-process-minijail/src/launch.rs:50, packages/d2b-provider-process-minijail/src/launch.rs:62] | actionable | lane/tail-3.md + +**`d2b-provider-process-systemd`** + +- `RS-0289` | low | `d2b-provider-process-systemd` | `RestartPolicy.restart_on_failure: bool` is invariant state: the only constructor sets it to `true` and nothing ever mutates it, so the field and its guard encode a state the type cannot otherwise represent | fix: drop the field and the `if !self.restart_on_failure` check in `should_restart`, or add a `RestartPolicy::never()` constructor if the never-restart class is real | [packages/d2b-provider-process-systemd/src/lifecycle.rs:78, packages/d2b-provider-process-systemd/src/lifecycle.rs:100] | actionable | lane/d2b-provider-process-systemd.md +- `RS-0290` | low | `d2b-provider-process-systemd` | `metrics::validate_labels` accepts stringly-typed `(String, String)` label pairs checked against the runtime `LABEL_KEYS` allowlist, so a misspelled key is a runtime rejection instead of a type error | fix: introduce `enum MetricLabelKey { Operation, Outcome, Domain }` with an `as_str()` accessor and take the key side typed | [packages/d2b-provider-process-systemd/src/metrics.rs:7, packages/d2b-provider-process-systemd/src/metrics.rs:4] | actionable | lane/d2b-provider-process-systemd.md + +**`d2b-provider-telemetry-binding`** + +- `RS-0291` | low | `d2b-provider-telemetry-binding` | `TelemetryBindingStatus.phase: &'static str` is stringly-typed state with exactly two valid spellings (`PHASE_PENDING`, `PHASE_DEGRADED`), while the sibling otel crate models the same concept as the `TelemetryBindingPhase` enum | fix: introduce a local `TelemetryBindingPhase` enum with `as_str()` preserving the "Pending"/"Degraded" spellings and use it for the `phase` field, deleting the two `PHASE_*` consts | [packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry-binding/src/driver.rs:170, packages/d2b-provider-observability-otel/src/controller.rs:288] | actionable | lane/tail-4.md + +**`d2b-provider-telemetry-service`** + +- `RS-0292` | low | `d2b-provider-telemetry-service` | `TelemetryServiceStatus` carries stringly-typed state: `phase: &'static str` (three spellings via `PHASE_*` consts) and `projection: serde_json::Value` built by hand with `json!` at three sites, so the `{serviceRole, serviceReadiness}` pair is constructed and indexed by string | fix: add a `TelemetryServicePhase` enum with `as_str()` for the three spellings and a two-field `TelemetryServiceProjection` struct that serializes to the same contract-pinned shape (`SERVICE_STATUS_ALLOWED` spellings at d2b-contracts-provider/src/v3/semantic_services/telemetry.rs:55), replacing the `json!` literals at driver.rs:274-290 and 309-315 | [packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telemetry-service/src/driver.rs:309-315] | actionable | lane/tail-5.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0293` | low | `d2b-provider-transport-azure-relay` | `GatewayGuestZoneLinkRuntime` carries `credential_generation: Option` and `credential_send_key_digest: Option<[u8; 32]>` as two independent Options that are always set or unset together (from_sealed sets both, from_scoped sets neither), leaving the half-set state representable and forcing `write_open_observation`'s `let (Some, Some) else` guard | fix: replace the pair with one `Option` struct (or a `Sealed`/`Scoped` enum carrying the marker data) so the impossible half-set combination stops compiling | [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:258-262] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-volume-local`** + +- `RS-0294` | low | `d2b-provider-volume-local` | VolumeRootHandle carries ten Option fields that are valid only all-Some (from_anchored) or all-None (held), so eleven mixed states are representable; construction is internal today so the mixed states are unreachable, but the fail-closed root-identity handle is exactly where a future partial-construction bug would land | fix: split into a two-variant enum (e.g. `enum VolumeRootHandle { Empty, Anchored(AnchoredHandle) }`) or a typestate pair, keeping the non-Clone/non-Serialize property | [src/identity.rs:72-88, src/identity.rs:146-150] | actionable | lane/d2b-provider-volume-local.md + +**`d2b-resource-api`** + +- `RS-0295` | low | `d2b-resource-api` | `attach_scoped_query_frame` takes a bare `watch: bool` mode flag selecting List versus Watch rewriting, a boolean state the type lens names | fix: replace the parameter with `enum ScopedQueryMethod { List, Watch }` and update the d2b-bus call site (packages/d2b-bus/src/router.rs:2914) | [adapter.rs:124] | actionable | lane/d2b-resource-api-p1.md + +**`d2b-resource-client`** + +- `RS-0296` | low | `d2b-resource-client` | `MetadataInput::validate_lifetime` (call.rs:168) is a re-validation of the invariant `MetadataInput::new` already enforces at construction (private fields); `CallDriver::new` re-checks it (dispatch.rs:189) where it cannot fail | fix: drop the `validate_lifetime()?` re-check at CallDriver::new (or convert to a debug_assert) | [packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs:189] | actionable | lane/d2b-resource-client.md + +**`d2b-session`** + +- `RS-0297` | low | `d2b-session` | `OutboundFrame::channel()` silently falls back to `SESSION_CONTROL` for the constructor-prevented NamedStream-without-stream combination, so an invariant break would misroute a frame to the session control channel with no error | fix: encode the stream inside the class (enum variants `SessionControl`/`TtrpcControl`/`AttachmentControl`/`Named(StreamId, ...)`) or make `channel()` return `Result` and drop the `unwrap_or(SESSION_CONTROL)` fallback | [scheduler.rs:18-21, scheduler.rs:66-68] | actionable | lane/d2b-session-p1.md merged: d2b-session-p1#4 +- `RS-0298` | low | `d2b-session` | stream control is decoded as a raw u8 kind inside a (u8, StreamId, u32) tuple and matched against local constants, so an unknown tag stays representable until the runtime match | fix: introduce a closed StreamControlKind enum with tag()/from_tag() beside the existing AttachmentControl enum | [engine.rs:1702, engine.rs:1295, engine.rs:31] | actionable | lane/d2b-session-p2.md + +**`d2b-unsafe-local-helper`** + +- `RS-0299` | low | `d2b-unsafe-local-helper` | RuntimeLedger.reservations is keyed by `operation_id.to_string()` (a String key) while OperationId already derives Ord + Clone + Hash, so every begin/owns/clear round-trips through a per-call allocation and as_str() re-parsing of an id the caller already owns typed | fix: `BTreeMap` and use the OperationId directly in begin (runtime.rs:193, 206, 230), owns (236) and clear (242); delete operation_key | [packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/runtime.rs:193, packages/d2b-unsafe-local-helper/src/runtime.rs:230, packages/d2b-unsafe-local-helper/src/runtime.rs:236] | actionable | lane/d2b-unsafe-local-helper.md + +**`d2bd`** + +- `RS-0303` | medium | `d2bd` | `force` on guest lifecycle requests is parsed from the wire (composition.rs:6794-6797), stored in DaemonGuestLifecycleEffect.force (6837-6848), and never consulted - apply() only reads it via `let _ = self.force;` (18659) - so `d2b guest ... --force` (sent by d2b/src/guest.rs:283) is silently ignored | fix: implement the force semantics in apply() (e.g. skip the graceful wait) or drop the field and the wire parse | [packages/d2bd/src/composition.rs:18659, packages/d2bd/src/composition.rs:18608] | actionable | lane/d2bd-p2.md +- `RS-0305` | medium | `d2bd` | stringly-typed wire mode compared to string literals: `request.spec.pointer("/mode").and_then(Value::as_str) == Some("authority")` (USBIP service) and `mode == "projection"` (security-key service); an unknown or misspelled mode silently takes the non-authority / non-projection branch, flipping the admission posture without an error | fix: parse the mode once into a typed enum (`#[derive(Deserialize, PartialEq)]` with `rename_all = "kebab-case"`) at the effect boundary and refuse unknown values (fail closed) | [packages/d2bd/src/shared_provider_effects.rs:1299, packages/d2bd/src/shared_provider_effects.rs:1903-1908] | actionable | lane/d2bd-p8.md merged: d2bd-p8#2 +- `RS-0302` | low | `d2bd` | ShutdownDegradedMarker stores `outcome: String` and `severity: String` although the same file defines VmShutdownOutcome (composition.rs:16131) whose label()/degraded_severity() (16205-16239) are the only producers of those strings | fix: derive Serialize on VmShutdownOutcome with `#[serde(rename_all = "snake_case")]` and store the enum in the marker so the report shape cannot drift from the enum | [packages/d2bd/src/composition.rs:16152, packages/d2bd/src/composition.rs:16155, packages/d2bd/src/composition.rs:16131] | actionable | lane/d2bd-p2.md +- `RS-0300` | low | `d2bd` | `ZoneResourceRuntime` carries three gate booleans `policy_installed`/`controller_endpoint_registered`/`watch_admitted` (3041-3043) with only two reachable states - (true, false, false) at open (3230-3232) and (true, true, true) after `activate_published_bundle` (3470-3472) - so six impossible combinations are representable | fix: replace the trio with one enum (e.g. `PlanePublicationStage { BootstrapOnly, Published }`) read by `readiness_error` (8104-8116) | [packages/d2bd/src/resource_runtime.rs:3041, packages/d2bd/src/resource_runtime.rs:3230, packages/d2bd/src/resource_runtime.rs:3470, packages/d2bd/src/resource_runtime.rs:8104] | actionable | lane/d2bd-p1.md +- `RS-0301` | low | `d2bd` | `ControllerSession` encodes ordered once-only teardown progress as three independent booleans `ingress_revoked`/`assignments_revoked`/`transport_closed` (1014-1016), so skipping or reordering a step (e.g. closing the transport before revoking assignments) is representable and silently leaks a lease or a revocation frame | fix: replace the three with a `TeardownStage` enum advanced monotonically in `remove_controller_session` (7614-7650) | [packages/d2bd/src/resource_runtime.rs:1014, packages/d2bd/src/resource_runtime.rs:7614] | actionable | lane/d2bd-p1.md +- `RS-0304` | low | `d2bd` | HostActivationPendingMarker.mode is a stringly-typed activation mode on a persisted marker: it is deserialized, logged and rendered but never validated against the known label set, while the in-Rust mode already exists as DaemonActivationMode | fix: replace `mode: String` with a serde-mirrored enum (e.g. `DaemonActivationMode` behind kebab-case serde, or a marker-local enum) and validate on read; the marker file is written by out-of-tree activation machinery, so the serialized label set is a contract | [packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d2bd/src/composition.rs:21135] | needs-contract | lane/d2bd-p3.md + +**`d2bd-runtime`** + +- `RS-0307` | medium | `d2bd-runtime` | `Wave6Dependencies` (resource_operator_activation.rs:129) is a five-public-bool struct whose named constructors `network_ready_for_guest` and `guest_ready_for_adoption` produce byte-identical state (all five fields true), so two semantic progression stages are indistinguishable and 27 illegal field combinations remain constructible through the pub fields | fix: encode the operator-acceptance progression as a typestate carrier (e.g. `Wave6Dependencies` holding a `Wave6DepStage { WaitingForVolume, WaitingForNetwork, ReadyForAdoption }` enum plus only the facts needed by that stage, fields private), guaranteeing the two stages differ and the impossible combos do not compile; at minimum make the bools private and delete/clarify the duplicate constructor | [resource_operator_activation.rs:129-182, resource_operator_activation.rs:163-177] | actionable | lane/d2bd-runtime-p2.md +- `RS-0309` | medium | `d2bd-runtime` | `DaemonEvent::ApiReadyTimeout.mode: String` models a closed two-value state (`"strict"` | `"no-wait-api"`, documented at daemon_audit.rs:193) as an open string, so an invalid mode is representable and would land in the preserved audit record | fix: introduce a two-variant `SplitReadinessMode`-style enum with `#[serde(rename_all = "kebab-case")]` and use it for the field; serialized bytes stay `"strict"`/`"no-wait-api"` so the daemon-events JSONL shape is unchanged | [packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361] | actionable | lane/d2bd-runtime-p4.md +- `RS-0310` | medium | `d2bd-runtime` | `retarget_mutating_response` and `response_outcome` re-derive the wire outcome as strings (`Some("applied")`, `Some("broker-error")`, `Some("api-ready-timeout")`) although the same file already builds responses from the `MutatingVerbOutcome` enum, forcing every caller into string matching (8 sites in d2bd composition.rs) | fix: add a typed accessor that parses `outcome` into `MutatingVerbOutcome` (serde) and match on the enum variants in `retarget_mutating_response`, keeping the `_` pass-through for unknown broker outcomes | [packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_response_helpers.rs:118] | actionable | lane/d2bd-runtime-p4.md merged: d2bd-runtime-p4#16 +- `RS-0308` | low | `d2bd-runtime` | `classify_peer` takes a bare `production_lookup: bool` mode switch whose meaning ("hermetic test injection skips NSS group-name existence lookup") is invisible at the call sites | fix: replace with a two-variant `PeerLookupMode::{Production, Hermetic}` parameter (or document the bool's contract in a doc comment with the behavior difference), so the admission path's mode is self-describing | [admission.rs:107-108, admission.rs:66, admission.rs:83] | actionable | lane/d2bd-runtime-p2.md merged: d2bd-runtime-p2#7 +- `RS-0306` | low | `d2bd-runtime` | ComponentSessionTransportFailure carries `kind: String` in four Io variants, where std::io::ErrorKind would carry the same class as a typed value | fix: replace the `kind: String` fields of PeerCredentialIo/ConnectIo/WriteIo/AckIo with `io::ErrorKind` and map at call sites (component_session_vsock.rs:150,198,381,410), dropping the `.to_string()` round-trips | [component_session_vsock.rs:32-36] | actionable | lane/d2bd-runtime-p1.md +- `RS-0311` | low | `d2bd-runtime` | the typed-shell target key `(u32, String)` (uid + shell name) is a bare tuple repeated across three collections and every public method signature, so uid/name swap is a type error waiting to happen | fix: extract `TypedShellTargetKey { uid: u32, name: String }` (derive Ord) and use it in `entries`/`recency`/`create_reservations` and the `remember`/`cached`/`forget`/`reserve` signatures | [packages/d2bd-runtime/src/typed_shell_targets.rs:13, packages/d2bd-runtime/src/typed_shell_targets.rs:82] | actionable | lane/d2bd-runtime-p4.md + +**`xtask`** + +- `RS-0314` | medium | `xtask` | inventory.rs re-implements the crate's own `delivery::model::validate_repo_relative_path` with the same invariant (minus the empty-path check), so two validators drift apart | fix: delete the private copy at inventory.rs:230,and call `crate::delivery::model::validate_repo_relative_path(Path::new(path))`, keeping the stricter empty check | [packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557] | actionable | lane/xtask-p4.md +- `RS-0313` | low | `xtask` | `FamilyKnowledgeSignal.text: String` (provider_crate_policy.rs:4664-4675) carries two meanings discriminated only by `class`: literal/identifier text for Literal/Assembled/Identifier, and a serialized count for ServerState (`text: format!("{server_state_count}")` at 5104) that the renderer re-parses (`signal.text.parse::().unwrap_or(0)` at 5179), silently defaulting a non-numeric to 0 | fix: add a typed `count: Option` field (or split the struct per class), fill it at 5104, and render by matching `class` without the parse | [packages/xtask/src/provider_crate_policy.rs:5104, packages/xtask/src/provider_crate_policy.rs:5179] | actionable | lane/xtask-p2.md +- `RS-0315` | low | `xtask` | `EdgeRecord.kind: String` carries the closed Cargo dependency-kind vocabulary {"normal","build","dev","proc-macro"} as a free string through traverse/filter/emit | fix: introduce a closed `EdgeKind` enum parsed once at the metadata boundary (dep_kinds reads at :660-676), serde-renamed to preserve the wire spelling "proc-macro",and regenerate the committed packages/policy-inputs/** closures | [packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660, packages/xtask/src/production_closure.rs:724] | needs-contract | lane/xtask-p4.md +- `RS-0312` | low | `xtask` | `process_provider_ids(metric_label: Option)` uses an optional boolean to select among three label domains (all, metric-only, plus an unreachable `Some(false)` state) where the two production call sites only ever pass `None` or `Some(true)` | fix: split into `all_process_provider_ids()` and `metric_process_provider_ids()` (or a two-variant enum), and update the call sites at gen_layer_catalogs.rs:370, 474, 515 | [packages/xtask/src/gen_layer_catalogs.rs:288, packages/xtask/src/gen_layer_catalogs.rs:515] | actionable | lane/xtask-p1.md + +### `api` + +Public surface: deliberate exports, one path per item, no internals or dependency types in signatures, semver breakage classes. + +**`X2-generated-boundary`** + +- `RS-0952` | medium | `X2-generated-boundary` | the hand-maintained registry `d2b-resource-api/src/generated/mod.rs:3-4` glob-re-exports the entire protobuf module (`pub use d2b_contracts_resource::resource_proto::*;`) as public surface of d2b-resource-api, exposing 47 items including reflection internals (`file_descriptor()` at `d2b_resource_v3.rs:7522`, `special_fields: ::protobuf::SpecialFields` on every message) and forcing `pub use protobuf;` at `d2b-resource-api/src/lib.rs:24` - with zero consumers | fix: delete the `d2b_resource_v3` re-export module from the registry (consumers use `d2b_contracts_resource::resource_proto` directly, e.g. `adapter.rs:560,578`); if a consumer ever needs the types through this crate, re-export named arms instead of a glob | [packages/d2b-resource-api/src/generated/mod.rs:3-4, packages/xtask/src/main.rs:355-370, packages/d2b-resource-api/src/lib.rs:24] | actionable | lane/X2-generated-boundary.md +- `RS-0953` | low | `X2-generated-boundary` | `d2b-audit/src/lib.rs:7` declares `pub mod generated;` but every consumer of the emitted catalog is in-crate (`crate::generated::audit_catalog::...` at record_types.rs:1038,1067,1212,1297,1367) | fix: `mod generated;` (private) in lib.rs; the emitted file and its registry need no change | [packages/d2b-audit/src/lib.rs:7, packages/xtask/src/gen_layer_catalogs.rs:725, packages/d2b-audit/src/generated/audit_catalog.rs:6-8] | actionable | lane/X2-generated-boundary.md + +**`X3-cross-crate-duplication`** + +- `RS-0965` | low | `X3-cross-crate-duplication` | Double-path public surface: eleven crates expose every item of a module at two public paths (`pub mod x` plus root `pub use x::*` or item re-exports), deviating from the house single-surface convention and letting future pub items silently widen API | fix: keep one public path per item (either the module or the root re-export, per the house single-surface pattern the d2b-sk-frontend lane names), deleting the duplicate arm in each lib.rs | [packages/d2b-provider-device-usbip/src/lib.rs:24, packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-zone/src/lib.rs:17, packages/d2b-sk-frontend/src/lib.rs:22] | actionable | lane/X3-cross-crate-duplication.md + +**`d2b`** + +- `RS-0352` | medium | `d2b` | `pub mod host_generation` (lib.rs:25) is the crate's only public module and its three exported items have zero consumers anywhere in the workspace | fix: make it `mod host_generation` (private) until a caller exists, or wire `build_request` into the host-generation CLI flow that currently does not call it | [packages/d2b/src/host_generation.rs:7, packages/d2b/src/host_generation.rs:17, packages/d2b/src/host_generation.rs:36] | actionable | lane/d2b-p1.md +- `RS-0353` | low | `d2b` | zone_support_bundle.rs declares 9 `pub` items (6 structs, 3 consts, build_bundle, render_ndjson) inside a private module, a pub-in-private surface no external caller can reach | fix: reduce to `pub(crate)` or plain items, keeping only what the in-file tests and `run` need | [zone_support_bundle.rs:19, zone_support_bundle.rs:28, zone_support_bundle.rs:99, zone_support_bundle.rs:323] | actionable | lane/d2b-p1.md merged: d2b-p1#4 +- `RS-0354` | low | `d2b` | the d2b lib exports a wide pub surface while the only external consumer (xtask) uses just `d2b::cli_command()`; `pub mod host_generation` and `pub const EXIT_API_TIMEOUT` have zero consumers anywhere | fix: narrow `doctor`/`host_validate` pub items and `EXIT_API_TIMEOUT` to `pub(crate)`, make `host_generation` a private `mod`, keeping only `cli_command`/`run` public | [packages/d2b/src/lib.rs:25, packages/d2b/src/lib.rs:41, packages/d2b/src/doctor.rs:62, packages/d2b/src/host_validate.rs:55] | actionable | lane/d2b-p2.md + +**`d2b-audit`** + +- `RS-0316` | medium | `d2b-audit` | the crate re-exports a large surface with zero external consumers: `sink` (AuditSink/AuditSinkError/AuditWriteOutcome), `segment` (SegmentWriter/FailureInjector/FailurePoint/DEFAULT_MAX_SEGMENT_BYTES/DEFAULT_RETENTION_DAYS), `export` (ExportLine/export_segments/export_segments_range/MAX_EXPORT_*), `rate_limit` (AuditRateLimiter/AuditWriteClass/RateDecision/DEFAULT_AUDIT_WRITES_PER_SECOND), `record_types` (AuditRecord/AuditRecordFields/*Fields/AuditRecordError/AUDIT_SCHEMA_VERSION), and `reconcile`'s `reconcile`/`Reconciliation`/`DurabilityOutcome` are all exported from lib.rs:16-46 but no dependent crate references them; consumers (d2b-broker, d2bd, d2bd-runtime, d2b-session) use only evidence_chain, operation, hash_chain, and `evidence_from_decision_result`/`DurabilityEvidence` | fix: either wire the daemon-side audit writer (d2bd-runtime daemon_audit) to the sink/segment/export stack, or reduce the unwired modules to `pub(crate)` until a consumer exists (crate is `publish = false`) | [packages/d2b-audit/src/lib.rs:16, packages/d2b-audit/src/lib.rs:30, packages/d2b-audit/src/lib.rs:33, packages/d2b-audit/src/lib.rs:37] | actionable | lane/d2b-audit.md merged: d2b-audit#7 + +**`d2b-broker`** + +- `RS-0319` | medium | `d2b-broker` | `ops::sysctl` exports a dead pub surface: `apply_sysctl_intents` (sysctl.rs:84), `ApplySysctlRequest` (16), `with_default_root` (23) and `intent_to_proc_path` (76) are referenced only inside sysctl.rs (its own tests at 258/283); the production entry point is `apply_with_readback` | fix: delete the dead trio (or demote to `pub(crate)` and keep only what tests need) | [packages/d2b-broker/src/ops/sysctl.rs:16, packages/d2b-broker/src/ops/sysctl.rs:84] | actionable | lane/d2b-broker-p3.md +- `RS-0320` | medium | `d2b-broker` | `RouteConflictKey` is exported as `d2b_broker::ops::route::RouteConflictKey` (pub struct with all-pub fields) but its only users are private fns in the same file; its companion record type `RouteOwnershipRecord` is private - the visibility is a leak, not a contract with callers | fix: make it `pub(crate)` or plain `struct` (all users are in-file private helpers: `route_conflicts`, `route_matches_record`, `requested_route_conflict_key`)and drop the pub fields to private | [packages/d2b-broker/src/ops/route.rs:19] | actionable | lane/d2b-broker-p4.md +- `RS-0318` | medium | `d2b-broker` | the GPU and modprobe op modules rise to the crate's public surface through pub mod ops + pub mod gpu/pub mod modprobe (ops/mod.rs:47-48), yet the GPU types (GpuBrokerRole, GpuDeviceClass, GpuOpaqueIdentity, GpuLaunchRequest, GpuProcessObservation, GpuBrokerError)and modprobe's(ModprobeAuditRecord, ModprobeDecision, AllowlistRow, ModprobeBackend, RecordingBackend, dispatch, live_modprobe_if_allowed)have zero consumers outside d2b-broker itself:live_handlers uses only the two gpu validate fns and runtime uses only live_modprobe_if_allowed, all same-crate | fix: narrow the module decls to pub(crate)(ops/mod.rs:47-48), or make the item-level pub to pub(crate)in gpu.rs and modprobe.rs; same-crate call sites are unaffected | [packages/d2b-broker/src/ops/gpu.rs:13, packages/d2b-broker/src/ops/gpu.rs:24, packages/d2b-broker/src/ops/gpu.rs:41, packages/d2b-broker/src/ops/gpu.rs:63] | actionable | lane/d2b-broker-p2.md +- `RS-0322` | medium | `d2b-broker` | `lib.rs` declares `pub mod ops` (src/lib.rs:45) with `pub mod` arms for all 27 executor/helper modules in src/ops/mod.rs:20-94, so every item in them becomes part of the crate's public surface - while the recorded design rationale (src/lib.rs:8-11) is "public API of internal modules that downstream callers may use", and a census finds no downstream crate consumer.. | fix: if a deliberate public-surface decision is desired, keep `pub mod` and record the census in a doc comment or dossier;; otherwise narrow the `pub mod` arms to `pub(crate)` for modules with no out-of-crate consumer (ops/exec_reconcile, ops/audit_op, ops/store_view_posture, ops/store_view_farm, ops/device_worker, ops/security_key, ops/usbip_firewall, ops/nm)and re-export only test-consumed items (`OperationFields` for tests/security_key_broker.rs) under a `#[cfg(any(test, feature = "fake-backends")))]`-style gate. | [src/lib.rs:45, src/ops/mod.rs:20-94] | policy-confirmed | lane/d2b-broker-p6.md +- `RS-0317` | low | `d2b-broker` | pub fn `acquire_lock` takes `_daemon_uid: u32` (underscore-prefixed) that the body never uses - the record owner is always `Uid::current()`, so every caller (live_handlers.rs:467 plus 8 test sites) supplies a value the function ignores | fix: drop the parameter and update the call sites | [packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467] | actionable | lane/d2b-broker-p1.md +- `RS-0321` | low | `d2b-broker` | `CgroupBundleContext::slice_path()` returns an owned `PathBuf` (cloning `parent_slice`) when a `&Path` return serves every in-crate call, forcing a clone per call at the `is_under_slice` check and duplicating the value | fix: change the return to `&Path` (`pub fn slice_path(&self) -> &Path`); the builder methods `vm_interior_path`/`vm_leaf_path`/`vm_role_leaf_path` keep their owned joins and `fields.slice_path`/tuple sites keep their one owned conversion | [packages/d2b-broker/src/ops/cgroup.rs:126-129, packages/d2b-broker/src/ops/cgroup.rs:343] | actionable | lane/d2b-broker-p5.md +- `RS-0323` | low | `d2b-broker` | kernel_table clones the whole KernelConfig into an Arc because it takes `&KernelConfig` | fix: take `config: KernelConfig` by value (or `Arc`) so the one-time clone disappears; the per-handler Arc clones stay | [packages/d2b-broker/src/kernel_ops.rs:99-100] | actionable | lane/d2b-broker-p7.md + +**`d2b-bus`** + +- `RS-0324` | medium | `d2b-bus` | ZoneBus exposes eight pub constructors but only new, with_interaction_subject_issuer, and with_clock_observer_and_metrics_and_interaction_subject_issuer have production callers; with_observer, with_observer_and_metrics, with_clock, with_clock_and_observer, and with_clock_observer_and_metrics are internal delegation rungs or test-only | fix: keep the three live constructors pub, move with_clock/with_clock_observer_and_metrics under #[cfg(test)] or pub(crate), and delete or fold with_observer/with_observer_and_metrics/with_clock_and_observer | [packages/d2b-bus/src/router.rs:1208, packages/d2b-bus/src/router.rs:1224, packages/d2b-bus/src/router.rs:1258, packages/d2b-bus/src/router.rs:1267] | actionable | lane/d2b-bus-p1.md +- `RS-0325` | medium | `d2b-bus` | native_authorizer() returns Arc in a pub signature on both BusAuthorizer and ZoneBus and has zero callers anywhere in the workspace, so the shared-authority accessor is dead surface that also leaks the Arc type | fix: remove both accessors or reduce them to pub(crate) until a daemon consumer exists | [packages/d2b-bus/src/authorization.rs:75, packages/d2b-bus/src/router.rs:1415-1416] | actionable | lane/d2b-bus-p1.md +- `RS-0326` | medium | `d2b-bus` | two public types named `Cancellation` are reachable from the crate root: `d2b_bus::Cancellation` (operations) and `d2b_bus::session::Cancellation` (the re-exported `d2b_session::Cancellation`), so a caller importing both modules gets a name collision and can hand the wrong token to a handler | fix: drop `Cancellation` from the `d2b_session` re-export block in session/mod.rs (the bus's own token shadows the need) or rename one of the two | [packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97] | actionable | lane/d2b-bus-p2.md + +**`d2b-contracts`** + +- `RS-0327` | medium | `d2b-contracts` | `pub fn MediaRef::validate_value` (types.rs:114) is dead:the `opaque_id!`-generated `MediaRef::new` accepts any string without calling it, so the public fn advertises a shape check that never runs on the type it names | fix: either delete the fn, or wire it into construction via a `TryFrom<&str>` boundary on MediaRef (the house parse-gate pattern)so calers cannot bypass it | [packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114] | actionable | lane/d2b-contracts.md + +**`d2b-contracts-broker`** + +- `RS-0328` | medium | `d2b-contracts-broker` | `BrokerRequestEnvelope.test_peer_uid: Option` is a test-only peer-uid override carried on the production wire envelope (serialized, schema-visible), honored only under the broker's `config.test_mode` gate | fix: move the override out of the wire type into the broker's test harness (e.g. a test-only envelope wrapper or a `#[cfg(test)]`-visible field) so the production contract carries no test seam | [packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtime.rs:1628-1632] | needs-contract | lane/d2b-contracts-broker.md +- `RS-0329` | low | `d2b-contracts-broker` | `pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}` at broker_wire.rs:13 re-exports another crate's types into this crate's surface, making each item reachable at two paths (`d2b_contracts::audit_wire::*` and `d2b_contracts_broker::broker_wire::*`), off the house single-surface pattern which places re-export arms in lib.rs | fix: move the re-export to lib.rs or drop it and let consumers import from d2b_contracts (sibling d2b-contracts-control/src/public_wire.rs:1 repeats the pattern; X3 may merge the family) | [packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib.rs:7-11] | actionable | lane/d2b-contracts-broker.md + +**`d2b-contracts-control`** + +- `RS-0330` | low | `d2b-contracts-control` | `StatusServicesOutputV3` and its `from_v2` conversion shim are exported but have zero callers in the workspace; the doc comment says "Used so callers... can be migrated incrementally" but no migration landed | fix: delete `StatusServicesOutputV3` and `from_v2` (or wire the intended caller) | [cli_output.rs:241, cli_output.rs:276] | actionable | lane/d2b-contracts-control.md +- `RS-0331` | low | `d2b-contracts-control` | `pub use d2b_contracts::audio::LevelPercent;` in cli_output.rs re-exports a type neither this module nor any external caller uses (public_wire.rs imports LevelPercent from d2b_contracts directly) | fix: delete the re-export | [cli_output.rs:6] | actionable | lane/d2b-contracts-control.md +- `RS-0332` | low | `d2b-contracts-control` | `AuditEntry` (public_wire.rs:2677) is exported but referenced by no wire type in the crate - `AuditResponse` uses `AuditExportEntry` from d2b_contracts - and survives only as a historical schema artifact | fix: remove the struct after confirming docs/reference/schemas/v1/wire-protocol.json:127 no longer needs the definition | [public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127] | needs-contract | lane/d2b-contracts-control.md +- `RS-0333` | low | `d2b-contracts-control` | `HelperSnapshot::validate` and `HelperLaunchRequest::validate_bounds` are `pub` but every caller is an in-crate `Deserialize` impl; external consumers call `validate_unsafe_local_resource_identity` directly instead | fix: make both methods private (or `pub(crate)`) | [unsafe_local_wire.rs:105, unsafe_local_wire.rs:171] | actionable | lane/d2b-contracts-control.md + +**`d2b-contracts-provider`** + +- `RS-0334` | low | `d2b-contracts-provider` | `SchemaVersion` in d2b-contracts-resource exposes no `major()`/`minor()` accessors, so `CompatibilityRange::admits_state` re-parses the canonical string in `schema_version_parts` with three `expect`s and an allocation per call | fix: add `pub const fn major(self) -> u32` and `minor(self) -> u32` to `SchemaVersion` (non-breaking) and delete `schema_version_parts` | [packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/src/v3/resource_schema.rs:592] | actionable | lane/d2b-contracts-provider-p1.md + +**`d2b-contracts-resource`** + +- `RS-0335` | low | `d2b-contracts-resource` | six `pub type` aliases are exported with zero consumers anywhere: `AttachmentSpec` (network.rs:956), `AuthorityDescriptor` (device.rs:129), `OpaqueAuthorityKey` (device.rs:151), `DeviceStatus` (device.rs:760), `DeviceRbacVerb` (device.rs:918), `DeviceTelemetryLabels` (device.rs:1119) | fix: delete the unused aliases (or make them `pub(crate)` if a provider adapter is planned) | [packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src/v3/device.rs:129, packages/d2b-contracts-resource/src/v3/device.rs:151, packages/d2b-contracts-resource/src/v3/device.rs:760] | actionable | lane/d2b-contracts-resource-p1.md +- `RS-0336` | low | `d2b-contracts-resource` | the exported type alias `ValidatedSessionPurpose` has zero callers anywhere in the workspace | fix: delete the alias (identity.rs:270) or document the intended consumer before it accrues surface | [packages/d2b-contracts-resource/src/v3/identity.rs:269-270] | actionable | lane/d2b-contracts-resource-p2.md + +**`d2b-contracts-zone-session`** + +- `RS-0337` | low | `d2b-contracts-zone-session` | four documented "compatibility" aliases give one type a second public path with zero in-repo callers: `ResourceExportError`, `Fairness`, `ResourceImportError`, `ZoneLinkStatus` | fix: delete the aliases (and the "Compatibility alias" doc lines); any future caller names the canonical type | [src/v3/resource_export.rs:97, src/v3/resource_export.rs:156, src/v3/resource_import.rs:86, src/v3/zone_link.rs:444] | actionable | lane/d2b-contracts-zone-session-p1.md +- `RS-0338` | low | `d2b-contracts-zone-session` | EmergencyPolicySpec::default_values is a pub method with zero callers outside its own Default impl | fix: delete it and let Default::default() be the single entry (or make it private) | [emergency_policy.rs:142, emergency_policy.rs:170] | actionable | lane/d2b-contracts-zone-session-p2.md +- `RS-0339` | low | `d2b-contracts-zone-session` | ZoneSpec::validate always returns Ok and has no callers, a dead always-succeeding validation on the exported surface | fix: remove the method (ZoneSpec is the empty spec; its Deserialize gate already enforces the only invariant) | [zone.rs:74] | actionable | lane/d2b-contracts-zone-session-p2.md + +**`d2b-core`** + +- `RS-0348` | medium | `d2b-core` | six one-line compat shim modules (`error`, `contract_id`, `configured_argv`, `privileges_w3`, `workload_identity`, `unsafe_local_workloads`) re-export d2b_contracts items, making every re-exported item public at two paths (`d2b_contracts::error::Error` and `d2b_core::error::Error`); this is the recorded A4 not-applied row | fix: delete the six shim modules and re-point the ~25 import sites at `d2b_contracts::*` (and `d2b_contracts_resource::v3::ZoneResourceIdentity`); the `UnsafeLocalWorkloadIdentity` alias has zero consumers and goes with its module; the xtask gen-error-codes generator and docs/reference/error-codes.md anchors that read `d2b_core::error` must switch to `d2b_contracts::error` | [packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-core/src/configured_argv.rs:1, packages/d2b-core/src/privileges_w3.rs:1] | actionable | lane/d2b-core-p2.md +- `RS-0345` | medium | `d2b-core` | nine exported resolved-intent types have zero consumers anywhere in the workspace: ResolvedInstallerIntent, ResolvedMigrateIntent, ResolvedActivationIntent, ResolvedGcIntent, ResolvedKeysRotateIntent, ResolvedHostKeyTrustIntent, ResolvedRotateKnownHostIntent, ResolvedLegacySwtpmIntent, InstallerArtifact | fix: delete them, or wire them to the broker dispatch arms the module doc says are still `Unimplemented`; if kept for planned arms, mark them `#[doc(hidden)]` or gate them behind a feature | [packages/d2b-core/src/bundle_resolver.rs:620, packages/d2b-core/src/bundle_resolver.rs:641, packages/d2b-core/src/bundle_resolver.rs:656, packages/d2b-core/src/bundle_resolver.rs:698] | actionable | lane/d2b-core-p1.md +- `RS-0349` | medium | `d2b-core` | `pub mod static_invariants` exports four security validators (world-readable-leak, path-bearing-key, broad-caps, writable-paths) with zero callers in the tree, and the bash gates the module doc says it replaced are gone, so the invariants are enforced nowhere; the module doc's claim that the original positive/negative cases were "preserved as unit tests" is false | fix: wire the validators into the contract-test lane (e.g. the d2b-contract-tests static-invariants structure ADR-046-zone-control cites) or the broker's manifest load path, or delete the module with its stale claim | [packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:158, packages/d2b-core/src/static_invariants.rs:189, packages/d2b-core/src/static_invariants.rs:216] | actionable | lane/d2b-core-p2.md merged: d2b-core-p2#12 +- `RS-0346` | medium | `d2b-core` | `BundleResolver` exposes seven `pub` fields (bundle, host, processes, storage, site, realm_workloads_launcher_v2, manifest) on the security-boundary type whose tables are derived from verified artifacts; the broker mutates `resolver.storage` directly, so the trusted model is writable by any consumer and derived state can drift from it | fix: make the fields private, add read accessors (`host()`, `manifest()`, `processes()`, `bundle()`, ...) and a single `set_storage(StorageJson)` setter, then migrate the ~30 read sites in d2bd, d2bd-runtime, and d2b-broker | [packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109, packages/d2b-core/src/bundle_resolver.rs:110, packages/d2b-broker/src/ops/storage_contract.rs:589] | actionable | lane/d2b-core-p1.md +- `RS-0350` | low | `d2b-core` | `PrivilegesJson::w1` is a pub constructor with zero production callers and an opaque name ("w1") unexplained by its doc comment | fix: rename to a descriptive constructor such as `from_const_rows()` or gate it behind cfg(test) | [packages/d2b-core/src/privileges.rs:741] | actionable | lane/d2b-core-p2.md +- `RS-0347` | low | `d2b-core` | three `pub` methods have no out-of-crate callers and are only used inside this module and its tests: resolve_vm_start_intent, find_process_node, find_if_name_mapping_for_vm | fix: narrow to `pub(crate)` | [packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:2417, packages/d2b-core/src/bundle_resolver.rs:2506] | actionable | lane/d2b-core-p1.md merged: d2b-core-p1#16 + +**`d2b-core-controller`** + +- `RS-0340` | medium | `d2b-core-controller` | `observed_child_from_resource` (binding_children.rs:173) is a pub fn re-exported at lib.rs:35 with zero callers anywhere in the repo; the observed-child adapter is dead public surface | fix: delete the fn and its lib.rs re-export arm, or wire it into the owner_reconcile relist path if the digest-from-stored-body adapter is still intended | [packages/d2b-core-controller/src/binding_children.rs:173, packages/d2b-core-controller/src/lib.rs:35] | actionable | lane/d2b-core-controller-p1.md merged: d2b-core-controller-p1#4 +- `RS-0341` | medium | `d2b-core-controller` | eight pub methods on ControllerAssignmentRegistry/ResourceClientLease have zero callers: reserve_epoch_after, rebind_revision, record_child, remove_child, child_uids, validate_writer, observation_is_stale, target_for; because record_child is never called the children set is always empty, so release()'s ChildrenRemain fence, ChildLimit, and MAX_ASSIGNED_CHILDREN are unreachable | fix: delete the eight methods and, if the child index stays in owner_reconcile's OwnerIndex (which already tracks children), the `children` field and MAX_ASSIGNED_CHILDREN const | [packages/d2b-core-controller/src/controller_assignment.rs:2707, packages/d2b-core-controller/src/controller_assignment.rs:2866, packages/d2b-core-controller/src/controller_assignment.rs:2943, packages/d2b-core-controller/src/controller_assignment.rs:2957] | actionable | lane/d2b-core-controller-p1.md merged: d2b-core-controller-p1#6 +- `RS-0342` | medium | `d2b-core-controller` | ten pub ZoneCoordinator methods have zero callers: begin_usbip_reconcile, finish_usbip_reconcile, set_force_shutdown_generation, clear_force_shutdown_generation, stage_configuration, commit_configuration, abort_configuration, commit_configuration_ordinal, abort_configuration_ordinal, zone_count; the daemon uses only the ordinal staging half (d2bd/src/composition.rs:20248), the generation-based family is unwired, and stage_configuration silently overwrites a pending generation where stage_configuration_ordinal rejects a conflict | fix: delete the ten methods and the generation-based staging fields, or wire the usbip reconcile lease into the daemon reconcile flow | [packages/d2b-core-controller/src/coordinator.rs:252, packages/d2b-core-controller/src/coordinator.rs:262, packages/d2b-core-controller/src/coordinator.rs:292, packages/d2b-core-controller/src/coordinator.rs:317] | actionable | lane/d2b-core-controller-p1.md +- `RS-0343` | medium | `d2b-core-controller` | the parallel external physical-NIC machinery (TrustedExternalNicInventory, ExternalNicClaimRequest, ExternalNicLease, ExternalNicEffectGate, ExternalNicAdoption, ExternalNicCloseOutcome, ExternalNicReservation, the external_nics half of the index, and the EXTERNAL_PHYSICAL_NIC_* constants) has zero production callers; the prior audit row C2 names exactly this surface and is recorded not-applied with the site still matching | fix: delete the controller-side NIC request/lease/reservation/inventory types and the external_nics index half with their tests, keeping ExternalNicRecoveryInventory (consumed by d2bd-runtime's provenance fence) and the wire types in d2b-contracts-resource (consumed by d2bd and d2b-provider-network-local); cite record row C2 at docs/explanation/over-engineering-audit-record.md:473 | [authority.rs:80-128, authority.rs:167-211, authority.rs:258-335, authority.rs:1732] | actionable | lane/d2b-core-controller-p2.md merged: d2b-core-controller-p2#10 +- `RS-0344` | low | `d2b-core-controller` | public accessor aliases multiply paths to one item: OwnerReconcilePlan::create_order/batch, OwnerChildBatch::resource_refs, OwnerChildIdentity::resource_ref, TeardownPlan::order/refs/resources all duplicate a canonical accessor with zero external callers | fix: delete the zero-caller aliases and keep the canonical names (creation_order, deletion_order, create_batch, refs, target, order), retaining teardown_order which has live consumers | [owner_reconcile.rs:579, owner_reconcile.rs:600, owner_reconcile.rs:697, owner_reconcile.rs:754] | actionable | lane/d2b-core-controller-p2.md + +**`d2b-host`** + +- `RS-0351` | low | `d2b-host` | `HostPrepStepId(pub String)` exposes the inner `String` on a `#[serde(transparent)]` newtype whose only constructor `new` is private, so literal construction is the only external path and the `{vm}:{kind}` id convention stays unenforced | fix: make the field private (serde transparent round-trips unchanged; `as_str()` already exists) and add a public constructor if integrators need one | [packages/d2b-host/src/host_prep_dag.rs:85] | actionable | lane/d2b-host.md + +**`d2b-process-conformance`** + +- `RS-0355` | low | `d2b-process-conformance` | `terminal::ExitClass` is re-exported under two names and the `BrokerExitClass` alias has zero consumers anywhere in the repo (the only hit is the re-export itself), while `ProcessExitClass` is the name the one real consumer (systemd lifecycle) imports | fix: drop the `ExitClass as BrokerExitClass` arm from lib.rs:54, keep `ExitClass as ProcessExitClass` | [packages/d2b-process-conformance/src/lib.rs:52, packages/d2b-process-conformance/src/lib.rs:54] | actionable | lane/d2b-process-conformance.md +- `RS-0356` | low | `d2b-process-conformance` | `process_provider.rs` re-exports the same root surface under a second public path (`d2b_process_conformance::process_provider::*`) and no caller uses that path (its own doc calls it a "destination-compatible boundary" for a split that is already settled) | fix: delete the module and its lib.rs:36 declaration; every item stays reachable at the root path | [packages/d2b-process-conformance/src/process_provider.rs:6, packages/d2b-process-conformance/src/lib.rs:36] | actionable | lane/d2b-process-conformance.md +- `RS-0357` | low | `d2b-process-conformance` | `pub mod testing` ships the mock `ScriptedEffectPort`, `PortCall`, `block_on` poller, and `TicketBuilder` fixtures unconditionally in the production library surface, while the house pattern (api card false-positive note) is a feature-gated `test-support` export; every in-tree consumer is a test target (provider crates' integration tests, d2bd `#[cfg(test)]`, provider-supervisor tests) | fix: gate `testing` behind a `test-support` feature (`#[cfg(feature = "test-support")] pub mod testing;`) and have consumer test targets enable it via dev-dependencies; `suite` stays ungated (it is the crate's product) | [packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testing.rs:60] | actionable | lane/d2b-process-conformance.md +- `RS-0358` | low | `d2b-process-conformance` | `CompiledSandbox::requires_cgroup_kill()` is public API whose field is set unconditionally to `true` at the only constructor, and no in-tree caller reads it (census inside the crate only); the accessor promises sandbox-dependent variation the compiler can never produce | fix: either thread a real `StopProof`/cgroup decision through `compile()` and its callers, or delete the field and the accessor along with the suite's unused surface | [packages/d2b-process-conformance/src/sandbox.rs:18, packages/d2b-process-conformance/src/sandbox.rs:61, packages/d2b-process-conformance/src/sandbox.rs:98] | actionable | lane/d2b-process-conformance.md + +**`d2b-provider-activation-nixos`** + +- `RS-0359` | low | `d2b-provider-activation-nixos` | `ActivationDriver` is re-exported at lib.rs:38 but no external consumer names it: the factory returns `Box` (driver.rs:410), so the concrete type never escapes the crate | fix: make `ActivationDriver` `pub(crate)` and drop it from the lib.rs re-export arm | [packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation-nixos/src/lib.rs:38] | actionable | lane/d2b-provider-activation-nixos.md +- `RS-0360` | low | `d2b-provider-activation-nixos` | `ACTIVATION_RUNNER_RESOURCE_TYPE` (controller.rs:14) is `pub` inside the exported `controller` module but used only at controller.rs:296 in the same module, so it is reachable as `d2b_provider_activation_nixos::controller::ACTIVATION_RUNNER_RESOURCE_TYPE` with no consumer | fix: make the const private (or `pub(crate)`) | [packages/d2b-provider-activation-nixos/src/controller.rs:14, packages/d2b-provider-activation-nixos/src/controller.rs:296] | actionable | lane/d2b-provider-activation-nixos.md + +**`d2b-provider-audio-pipewire`** + +- `RS-0361` | low | `d2b-provider-audio-pipewire` | `SpeakerMixer::set_grant(lease, on: bool)` takes a boolean command and returns a bool whose meaning flips with the argument (true: was-empty, false: was-last), and the only caller ignores the revoke return (it calls `is_last_grant` first) | fix: split into `grant(lease) -> Result` (was-empty) and `revoke(lease) -> Result` (was-last), or return a named enum, so the return contract stops being argument-dependent | [src/authority.rs:157-171, src/controller.rs:395-403] | actionable | lane/d2b-provider-audio-pipewire.md merged: d2b-provider-audio-pipewire#9 +- `RS-0362` | low | `d2b-provider-audio-pipewire` | `register_service` is exported from lib.rs but has zero callers anywhere (the daemon's audio paths and the wayland-policy audio_registry validate specs directly), leaving a dead registration gate on the surface | fix: consume `register_service` in the daemon's audio Service registration path or drop the export (crate is 0.0.0-bootstrap, no semver gate) | [src/controller.rs:746-748, src/lib.rs:32] | actionable | lane/d2b-provider-audio-pipewire.md +- `RS-0363` | low | `d2b-provider-audio-pipewire` | `AudioLastSetApplied::OfflineOnly` is named as if it meant "applied offline only" while its doc says "No setting was applied in the current reconcile"; the variant is rendered to a wire-visible status string "OfflineOnly" by the wayland-policy projection and pinned in daemon tests | fix: rename the variant (e.g. `NotApplied`) and update the projection string and pinned expectations together | [src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-122, packages/d2bd/src/resource_plane_v3.rs:4626] | needs-contract | lane/d2b-provider-audio-pipewire.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0364` | low | `d2b-provider-clipboard-wayland` | ClipboardConfig exposes host_entry_ttl_secs (field, Default value, and pub accessor) plus a pub policy() accessor with zero consumers anywhere in the repo; the history only ever reads guest_entry_ttl_secs, so the host TTL is dead public surface | fix: remove host_entry_ttl_secs and policy(), or wire host_entry_ttl_secs into ClipboardHistory retention for host-owned entries | [packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1297, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1313-1316, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1338-1340] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-config-nixos`** + +- `RS-0365` | low | `d2b-provider-config-nixos` | `decode_document` (service.rs:296-298) is a public one-line forwarder duplicating the already-public `ConfigSyncResponse::document()`, giving two API paths for one operation | fix: drop the export and call `.document()` at the one live caller (d2bd/src/composition.rs:11585), or privatize `document()` and keep the named helper | [packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-nixos/src/lib.rs:22] | actionable | lane/d2b-provider-config-nixos.md + +**`d2b-provider-credential-entra`** + +- `RS-0366` | medium | `d2b-provider-credential-entra` | `pub fn controller_binary_entrypoint()` is an exact duplicate of `run_from_fd10()` with zero callers anywhere in the workspace; the sibling credential crate deleted its twin as production-dead | fix: delete controller_binary_entrypoint (lib.rs:102-105) and its doc comment, keeping `run_from_fd10` as the single entrypoint | [packages/d2b-provider-credential-entra/src/lib.rs:102, packages/d2b-provider-credential-entra/src/lib.rs:103] | actionable | lane/d2b-provider-credential-entra.md +- `RS-0367` | low | `d2b-provider-credential-entra` | `EntraCredentialOwner` enum and the `owner()` accessor have no caller inside or outside the crate | fix: delete the enum (lib.rs:445-449) and `owner()` (lib.rs:939-942), or wire them into the toolkit's dispatch/controller surface if the ownership policy is meant to be observable | [packages/d2b-provider-credential-entra/src/lib.rs:446, packages/d2b-provider-credential-entra/src/lib.rs:940] | actionable | lane/d2b-provider-credential-entra.md + +**`d2b-provider-credential-managed-identity`** + +- `RS-0368` | low | `d2b-provider-credential-managed-identity` | `ManagedIdentityPlacement::in_zone` is an exact duplicate constructor of `new` with zero callers anywhere in the repo, doubling the public construction path | fix: delete `in_zone` (and its docs at lib.rs:611-618); `new` already validates and names the behavior | [lib.rs:612-618] | actionable | lane/d2b-provider-credential-managed-identity.md + +**`d2b-provider-device`** + +- `RS-0369` | medium | `d2b-provider-device` | `DeviceResourceState` exposes raw `Arc>>` and `Arc>>` as pub fields, leaking wrapper types and the `parking_lot` dependency into the crate's public API (parking_lot is banned outright by (d) 2 outside the R4 worker boundary; this site is comment-justified only, driver.rs:137-138, matching the GPU crate's cache at d2b-provider-device-gpu/src/effects_service.rs:79) | fix: make the three caches private and expose narrow typed accessor methods on `DeviceResourceState` (or an effects-owned registry handle), keeping the GPU authority-lease construction contract behind the crate, and migrate the nine daemon read sites | [packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effects.rs:1584, packages/d2bd/src/shared_provider_effects.rs:2092, packages/d2bd/src/shared_provider_effects.rs:2122] | actionable | lane/tail-2.md + +**`d2b-provider-device-gpu`** + +- `RS-0370` | low | `d2b-provider-device-gpu` | `pub mod gpu_argv`/`pub mod video_argv` expose a second public path for items already re-exported at the root, and the module paths have zero workspace callers | fix: make both modules private (`mod gpu_argv`/`mod video_argv`), keeping the lib.rs re-export arms so each item stays reachable by one path (the house single-surface pattern) | [packages/d2b-provider-device-gpu/src/lib.rs:12, packages/d2b-provider-device-gpu/src/lib.rs:15] | actionable | lane/d2b-provider-device-gpu.md +- `RS-0371` | low | `d2b-provider-device-gpu` | public `DeclaredWorkerGpuPortArgs` tunnels dependency types in pub fields (`Arc`, `Arc>>` over parking_lot, `tokio::runtime::Handle`, `&dyn SharedProviderChildSurface`) | fix: hide the field types behind crate-private accessors or accept a single crate-owned sidecar struct; publish=false so the semver cost is nil, but the surface leaks three dependency crates | [packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-device-gpu/src/effects_service.rs:467, packages/d2b-provider-device-gpu/src/effects_service.rs:469] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-device-security-key`** + +- `RS-0372` | low | `d2b-provider-device-security-key` | `pub mod relay` and `pub mod relay_service` (lib.rs:16-17) expose a second path for every root-re-exported item, while `facets`/`effects_service`/`test_support` module paths are the ones the daemon actually consumes | fix: make `relay` and `relay_service` private modules, keep the lib.rs `pub use` arms as the single surface (house pattern) | [packages/d2b-provider-device-security-key/src/lib.rs:16-17, packages/d2b-provider-device-security-key/src/lib.rs:45-55] | actionable | lane/d2b-provider-device-security-key.md + +**`d2b-provider-device-tpm`** + +- `RS-0373` | medium | `d2b-provider-device-tpm` | the state.rs token module (StateDirectoryToken, TamperMarkerToken, StateOwnerToken, StateDirIntent, state.rs:6-107, re-exported lib.rs:36-38) has zero consumers repo-wide at HEAD, so the refusal ledger's stated reason for keeping it ("the daemon references them", over-engineering-audit-record.md:386, rows 71/72) is no longer evidenced - the daemon-side uses were deleted by the same applied finding | fix: delete state.rs and its re-export, or wire the daemon side that the record claims exists | [state.rs:6, state.rs:29, state.rs:51, state.rs:73] | actionable | lane/d2b-provider-device-tpm.md +- `RS-0374` | low | `d2b-provider-device-tpm` | the exported inspect-tpm effects service is unwired: TPM_EFFECTS_SERVICE (effects_service.rs:53), TpmEffectsService, and TpmEffectsServiceFactory (effects_service.rs:103-116, whose facets field carries #[allow(dead_code)] for an R5 respawn path "not wired yet") are never registered, while d2bd registers every sibling provider's factory in shared_provider_effects.rs:3434-3493 without the TPM one | fix: register the factory there, or delete the service surface until the respawn path is wired | [effects_service.rs:53, effects_service.rs:103, effects_service.rs:114] | actionable | lane/d2b-provider-device-tpm.md +- `RS-0375` | low | `d2b-provider-device-tpm` | LiveTpmResourceEffectPort is pub (effects_service.rs:341) but is only constructed and consumed inside effects_service.rs (into_port at effects_service.rs:697), never appearing in a public signature or external caller | fix: make it pub(crate) | [effects_service.rs:341] | actionable | lane/d2b-provider-device-tpm.md +- `RS-0376` | low | `d2b-provider-device-tpm` | LegacyMigrationOutcome (migration.rs:5, re-exported lib.rs:24) has zero callers repo-wide: the "closed outcome of the broker-owned one-time legacy state adoption" is consumed by no broker or daemon code at HEAD | fix: delete the enum and its re-export, or wire the broker consumer it documents | [migration.rs:5, lib.rs:24] | actionable | lane/d2b-provider-device-tpm.md + +**`d2b-provider-device-usbip`** + +- `RS-0377` | medium | `d2b-provider-device-usbip` | `pub mod state_machine` (lib.rs:24) plus the root `pub use state_machine::{...}` (lib.rs:61-65) exposes every state-machine item at two public paths, and no external caller uses the module path | fix: make the module private (`mod state_machine`) since lib.rs already re-exports its whole surface | [lib.rs:24, lib.rs:61-65] | actionable | lane/d2b-provider-device-usbip.md +- `RS-0378` | medium | `d2b-provider-device-usbip` | `new_authority_ledger` returns `Arc>`, leaking the concrete lock type into the public signature and making any lock change a breaking change for the caller | fix: introduce an opaque `AuthorityLedgerHandle` newtype wrapping the `Arc>` (or a `pub type` alias) so the handle is the API | [broker.rs:131-133] | actionable | lane/d2b-provider-device-usbip.md + +**`d2b-provider-display-wayland`** + +- `RS-0381` | medium | `d2b-provider-display-wayland` | `PrincipalReleaseReceipt` (controller.rs:702, re-exported at lib.rs:20) is unconstructible: private `session_key` field and no constructor, so `DisplayController::release_session_principal` (controller.rs:1379) can never be called by the daemon; the principal-release path is dead exported surface | fix: add a constructor and wire the daemon cleanup path to call release_session_principal, or make both pub(crate) until the path is wired | [src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20] | actionable | lane/d2b-provider-display-wayland-p2.md merged: d2b-provider-display-wayland-p2#12 +- `RS-0379` | medium | `d2b-provider-display-wayland` | `#[allow(missing_docs)] pub mod wayland_proxy` (lib.rs:14) exposes the whole 9,342-line proxy implementation as public library surface whose only consumer is the crate's own binary target, which cannot reach crate-private items | fix: move the module into the binary target (declare `#[path = "../wayland_proxy/mod.rs"] mod wayland_proxy;` in src/bin/d2b-wayland-proxy.rs and rewrite the `crate::wayland_proxy::` paths to `wayland_proxy::`), keeping the lib surface to the re-exported controller/policy/process/runtime/spec items | [packages/d2b-provider-display-wayland/src/lib.rs:14] | actionable | lane/d2b-provider-display-wayland-p1.md merged: d2b-provider-display-wayland-p1#10 +- `RS-0382` | low | `d2b-provider-display-wayland` | `WaylandPolicySnapshot::from_authenticated_session` (controller.rs:580) has no callers anywhere; the daemon resolves snapshots via `from_authenticated_route` | fix: delete the wrapper or mark it deliberate with a comment naming the route-based entry as canonical | [src/controller.rs:580] | actionable | lane/d2b-provider-display-wayland-p2.md +- `RS-0380` | low | `d2b-provider-display-wayland` | `pub use policy::{FilterPolicy, GlobalAction, PolicyInput, PolicyWarning};` in wayland_proxy/mod.rs re-exports four items at a second path with zero consumers; the bin imports them via `wayland_proxy::policy::...` | fix: delete the re-export line so each item has one path | [packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12] | actionable | lane/d2b-provider-display-wayland-p1.md + +**`d2b-provider-guest-azure-container-apps`** + +- `RS-0383` | low | `d2b-provider-guest-azure-container-apps` | lib.rs re-exports the whole effects module via `pub use effects::*;` (so every future pub item in effects silently becomes public API) and effects.rs re-exports four dependency types (`CredentialLeaseHandle`, `OpaqueAzureRef`, `ResourceRef`, `ResourceUid`) with zero consumers through this crate's path | fix: replace the glob with named arms listing the intended effect surface and drop the uncalled dependency-type re-exports | [src/lib.rs:14, src/effects.rs:8-9] | actionable | lane/d2b-provider-guest-azure-container-apps.md + +**`d2b-provider-guest-azure-virtual-machine`** + +- `RS-0384` | low | `d2b-provider-guest-azure-virtual-machine` | the mutable-update/adoption/enrollment surface has no in-tree production caller: `update()`/`AzureVmUpdate`, `adopt()`, `complete_enrollment`, `status()`/`AzureVmStatus`, `controller_execution_ref()` are exercised only by this crate's tests, while the framework adapter (d2b-provider-guest/src/effects_service.rs) drives only `reconcile` (1303-1308), `poll_operation`/`recovery_state` (1384-1396), `finalize` (1384-1396) and `finalizer_installed` (590) | fix: wire the update path in the framework adapter (it already implements the resize/attach/detach/tags effect methods at effects_service.rs:499-565) or trim the surface | [src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md +- `RS-0385` | low | `d2b-provider-guest-azure-virtual-machine` | `AzureVmController::new` takes `effect: Arc` (controller/mod.rs:211) and stores it, but the only call site constructs a fresh `Arc::new(FrameworkAzureEffect {...})` with no sharing (d2b-provider-guest/src/effects_service.rs:1186-1189) | fix: take `effect: E` by value and store it, removing `Arc` from the public signature | [src/controller/mod.rs:211, packages/d2b-provider-guest/src/effects_service.rs:1186] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md + +**`d2b-provider-guest-cloud-hypervisor`** + +- `RS-0386` | medium | `d2b-provider-guest-cloud-hypervisor` | `repair_children` takes `committed: &BTreeMap` whose only call site passes an always-empty map (`let committed = BTreeMap::new()` at controller.rs:2140), making the `committed.get(target)` branch at 2890 unreachable | fix: drop the parameter and the dead branch, delete the empty-map local | [controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0387` | medium | `d2b-provider-guest-cloud-hypervisor` | `CloudHypervisorResourceApi::assess_update` takes `children` that the production adapter discards (`let _ = children;` at controller.rs:1366, the request carries no children) while `reconcile` allocates a Vec just to drop it | fix: remove the `children` parameter from the trait method, the adapter override, and the call site (controller.rs:1907-1909) | [controller.rs:1361-1376, controller.rs:1907-1909] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0390` | medium | `d2b-provider-guest-cloud-hypervisor` | `GuestControlEndpoint` is declared byte-identically in this crate (guest_local.rs:49) and in d2b-resource-client (zone_client.rs:129), the not-applied ledger row C1 with no refusal reason | fix: keep one declaration (d2b-resource-client is the consumer-facing home; d2bd/src/composition.rs:10723 constructs it) and re-export from the other | [guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md merged: d2b-provider-guest-cloud-hypervisor#13 +- `RS-0388` | low | `d2b-provider-guest-cloud-hypervisor` | `ChildMutation::expected_uid()` (identity.rs:554) always returns `None` because the UID-free batch is structurally UID-free; the only consumers are tests asserting the None (bootstrap_graph.rs:340, tests/controller.rs:206, tests/guest_spec_validation_test.rs:181) | fix: delete the accessor and the assert-None assertions | [identity.rs:554-556, tests/controller.rs:206] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md +- `RS-0389` | low | `d2b-provider-guest-cloud-hypervisor` | `GuestUpgradePlan::preserve_state()` (shutdown.rs:576) returns a literal `true`; its only consumer is the tautological assertion in finding #5 | fix: delete the accessor together with the assertion | [shutdown.rs:576-578] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0391` | low | `d2b-provider-guest-qemu-media` | Test-support exports `ScriptedQmpTransport` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129(and `ProcessIdentity::for_test` (packages/d2b-provider-guest-qemu-media/src/adoption.rs:24(are unconditionally pub+re-exported with no consumer outside this crate's own tests (while the house convention for test-only items is `#[doc(hidden)]` (see `mark_ready_for_test` at packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:327-328( | fix: mark both `#[doc(hidden)]` (or gate behind a `test-support` feature | [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129, packages/d2b-provider-guest-qemu-media/src/lib.rs:32, packages/d2b-provider-guest-qemu-media/src/adoption.rs:24] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-host`** + +- `RS-0392` | low | `d2b-provider-host` | dead `pub` visibility on seven items in the private `mod driver` that are never re-exported: `HostDriver`, `HostDriverError`, `HostDriverStatus`, `HostDriverFactory`, `HostDriverEffects`, `host_spec_decoder`, `HOST_REOBSERVE` | fix: make them `pub(crate)` (the live surface is the lib.rs re-export set: host_descriptor, HOST_EFFECTS_SERVICE, HostEffectsServiceFactory, HostEffectFacets, MinijailPlatformGateSource, production_probe, the three probe constants, MinijailPlatformGate) | [packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111, packages/d2b-provider-host/src/driver.rs:147, packages/d2b-provider-host/src/driver.rs:174] | actionable | lane/d2b-provider-host.md merged: d2b-provider-host#6 + +**`d2b-provider-network-local`** + +- `RS-0393` | medium | `d2b-provider-network-local` | two pub route validators are exported with zero production callers (only crate-internal unit tests), and the wrapper carries a stale `#[allow(dead_code)]` on a pub item | fix: lower both to `pub(crate)` (unit tests still reach them)and remove the dead_code allow, or wire them into BrokerNetworkEffectPort::apply_routes/remove_routes which currently resolve intents without these checks | [src/routes.rs:244-279, src/routes.rs:264-265] | actionable | lane/d2b-provider-network-local.md merged: d2b-provider-network-local#8 + +**`d2b-provider-notification-desktop`** + +- `RS-0394` | medium | `d2b-provider-notification-desktop` | The non-effects controller surface has no production callers: `reconcile_authenticated_display` is uncalled at all, `reconcile_sources` and `drain_sources` serve only in-crate tests | fix: delete `reconcile_authenticated_display` or route its tests through the `_with_effects` twin; make `reconcile_sources`/`drain_sources` `pub(crate)` unless an external caller is planned | [packages/d2b-provider-notification-desktop/src/controller.rs:1019, packages/d2b-provider-notification-desktop/src/controller.rs:1329, packages/d2b-provider-notification-desktop/src/controller.rs:1411] | actionable | lane/d2b-provider-notification-desktop.md +- `RS-0395` | low | `d2b-provider-notification-desktop` | `#[allow(dead_code)]` sits on `from_route`, a function reachable from production via `from_authenticated_route` | fix: delete the stale allow | [packages/d2b-provider-notification-desktop/src/controller.rs:110, packages/d2b-provider-notification-desktop/src/controller.rs:159-160] | actionable | lane/d2b-provider-notification-desktop.md +- `RS-0396` | low | `d2b-provider-notification-desktop` | `stream_admission.rs` is a private three-line re-export shim: `lib.rs` could re-export admission items directly | fix: delete `stream_admission.rs` and change `lib.rs:59` to `pub use admission::{AdmissionError, AdmissionPurpose, SessionEvidence, TransportClass};` | [packages/d2b-provider-notification-desktop/src/stream_admission.rs:1-3, packages/d2b-provider-notification-desktop/src/lib.rs:29, packages/d2b-provider-notification-desktop/src/lib.rs:59] | actionable | lane/d2b-provider-notification-desktop.md + +**`d2b-provider-process-systemd`** + +- `RS-0397` | low | `d2b-provider-process-systemd` | `SystemdProviderConfig`, `RestartPolicy`, `SystemdConfigError`, and `EphemeralProcessController` are each reachable at two paths: `pub mod lifecycle` (src/lib.rs:28) plus the root re-export `pub use lifecycle::{...}` (src/lib.rs:33), violating the one-path-per-item surface rule | fix: make `lifecycle` private (`mod lifecycle;`) and keep the root re-export as the single surface; no external caller imports through the module path (tests use the crate root) | [packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd/src/lib.rs:33] | actionable | lane/d2b-provider-process-systemd.md +- `RS-0398` | low | `d2b-provider-process-systemd` | `SystemdProviderConfig::no_persistent_unit()` is an always-true method with no production caller; the invariant it states already lives in the README security posture and the dossier | fix: delete the method and its test assertion (tests/lifecycle.rs:12), or replace it with a documented `const` if the surface is contract | [packages/d2b-provider-process-systemd/src/lifecycle.rs:55, packages/d2b-provider-process-systemd/tests/lifecycle.rs:12] | actionable | lane/d2b-provider-process-systemd.md +- `RS-0399` | low | `d2b-provider-process-systemd` | the controller/provider/lifecycle/drain/launch/sandbox/audit/metrics/error modules have zero production consumers: the daemon composes only `effects_service` + `operations` (the U15 forward seam), so the declared controller surface is unwired in the tree | fix: none until daemon composition lands; record the drift | [packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd/README.md:28] | policy-confirmed | lane/d2b-provider-process-systemd.md + +**`d2b-provider-provider`** + +- `RS-0400` | low | `d2b-provider-provider` | `ProviderDriverFactory::new()` and its `Default` impl are zero-caller public surface (the doc names "unit fixtures", but the crate's own tests construct via `with_effects`) | fix: delete `new()` and `impl Default` (driver.rs:213-232), or drop them to `pub(crate)` if a fixture wants them | [src/driver.rs:215, src/driver.rs:229] | actionable | lane/d2b-provider-provider.md +- `RS-0401` | low | `d2b-provider-provider` | `ProviderHandler::plan_external` (and the `ProviderError`/`ProviderChildAction`/`Disable`/`Delete` planning surface it serves) is exported through `pub mod providers` with zero production callers | fix: reduce to `pub(crate)` or delete `plan_external` (providers.rs:121-171) and the `ProviderIntent::Disable`/`Delete` arms of `plan_observed` if the external-provider path is not coming back; keep the surface the driver consumes (`plan_observed` Enable/Update, `plan_system_core`, `provider_observation`, `fixed_system_core_handlers_ready`) | [src/providers.rs:121, src/lib.rs:19] | actionable | lane/d2b-provider-provider.md merged: d2b-provider-provider#6 + +**`d2b-provider-quota`** + +- `RS-0402` | low | `d2b-provider-quota` | the `test-support` feature is declared empty and gates nothing: the `quota` module is unconditionally `pub`, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza (or gate the test-consumed exports behind it, matching the house pattern of feature-gated test-support) | [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21] | actionable | lane/tail-3.md + +**`d2b-provider-resource-export`** + +- `RS-0403` | low | `d2b-provider-resource-export` | the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_export_descriptor` unconditionally, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza | [packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export/src/lib.rs:18] | actionable | lane/tail-3.md + +**`d2b-provider-resource-import`** + +- `RS-0404` | low | `d2b-provider-resource-import` | the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_import_descriptor` unconditionally, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza | [packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import/src/lib.rs:18] | actionable | lane/tail-3.md + +**`d2b-provider-role`** + +- `RS-0405` | low | `d2b-provider-role` | the `test-support` feature is declared empty and gates nothing: `rbac` is unconditionally `pub`, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza | [packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16] | actionable | lane/tail-3.md + +**`d2b-provider-seccomp-profile`** + +- `RS-0406` | low | `d2b-provider-seccomp-profile` | every `seccomp_profile` item is reachable at two paths: `pub mod seccomp_profile` (lib.rs:19) plus the glob `pub use seccomp_profile::*` (lib.rs:22), and d2bd imports via both paths | fix: make the module private (`mod seccomp_profile;`) and replace the glob with the house-style explicit re-export list (as shell-pool/shell-session/telemetry-binding lib.rs do), then update the two d2bd imports at foundation_seed.rs:25 and :1091 to the crate-root paths | [packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile/src/lib.rs:22, packages/d2bd/src/foundation_seed.rs:25, packages/d2bd/src/foundation_seed.rs:1091] | actionable | lane/tail-4.md + +**`d2b-provider-supervisor`** + +- `RS-0407` | medium | `d2b-provider-supervisor` | `BrokerProcessBackend::set_launched_observer` takes `Arc` in a public signature although single ownership suffices: the one caller (d2bd/src/process_provider_runtime.rs:913) hands over a fresh `Arc::new)...)` and retains nothing, so the Arc is a forced refcount, not shared ownership | fix: take `Box` or `impl LaunchedObserver + Send + Sync + 'static`, drop the Arc at the call site | [packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2bd/src/process_provider_runtime.rs:913] | actionable | lane/d2b-provider-supervisor.md +- `RS-0408` | medium | `d2b-provider-supervisor` | `LaunchedObserver::launched` takes five positional parameters (vm, role, pid, start_time_ticks, pidfd) and `BrokerProcessBackend::launched_runner_snapshot` returns `Option<(String, String, i32, u64, OwnedFd)>`, a 5-tuple whose shape is pinned by the upstream `ProcessEffectBackend` trait (which carries its own `#[allow(clippy::type_complexity)]`) | fix: introduce a `LaunchedSnapshot` struct (or a small `LaunchedProcessRef`) and change `launched_runner_snapshot`'s default + the observer method to carry it, updating the implementor in d2bd | [packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/src/broker.rs:1524-1546, packages/d2b-provider-process/src/backend.rs:315-319] | actionable | lane/d2b-provider-supervisor.md + +**`d2b-provider-system-core`** + +- `RS-0409` | medium | `d2b-provider-system-core` | `pub mod testing` (lib.rs:41) ships the hand-rolled `block_on` driver, `ScriptedDiscoveryPort`, and fixture set unconditionally in the library surface although only this crate's own `tests/` consumes them | fix: gate behind a `test-support = []` feature (house pattern: d2b-provider-host/Cargo.toml:28, d2b-provider-user/Cargo.toml:30) with `#[cfg(feature = "test-support")]` and `required-features` on the three [[test]] targets | [src/lib.rs:41, src/testing.rs:23] | actionable | lane/d2b-provider-system-core.md +- `RS-0413` | medium | `d2b-provider-system-core` | `HostReconciler::reject_operator_status_fields` (host.rs:389), documented as the enforcement half of the ADR-046 no-suppression obligation ("both are met here", host.rs:13), has zero callers outside this crate's tests - the "operators can neither suppress nor override" posture rule is test-only today | fix: wire the check into the daemon's status admission path (d2b-resource-api `update_status`, service.rs:735, or the daemon's Host status publication) or document the structural exclusion | [src/host.rs:389, src/host.rs:13] | needs-contract | lane/d2b-provider-system-core.md +- `RS-0410` | low | `d2b-provider-system-core` | `pub mod ownership` (lib.rs:40) makes `OWNED_RESOURCE_TYPES`/`DISOWNED_RESOURCE_TYPES` reachable at two paths (module plus root re-export), the refused two-path shape; its fns `owns`/`require_owned`/`require_resource_type` have no external callers | fix: `mod ownership;` private, keep the root re-export (lib.rs:49) | [src/lib.rs:40, src/ownership.rs:42] | actionable | lane/d2b-provider-system-core.md +- `RS-0411` | low | `d2b-provider-system-core` | `HostReconciler::reconcile_observed` (host.rs:419) and `HostProbeSnapshot` (host.rs:134, root re-export lib.rs:46) are pub with zero external callers; the doc frames reconcile_observed as a conformance/fault-injection seam no consumer uses yet | fix: `pub(crate)` both until a consumer exists, or keep as the documented seam | [src/host.rs:419, src/host.rs:134] | actionable | lane/d2b-provider-system-core.md +- `RS-0412` | low | `d2b-provider-system-core` | `PROVIDER_UID` (lib.rs:70) is a zero-caller pub const whose doc says "the bus keeps its own copy"; d2b-bus consumes the generated `BOOTSTRAP_PROVIDER_UID` (d2b-contracts-zone-session/src/generated/service_provider_catalog.rs:15) with the identical value | fix: have d2b-bus import `d2b_provider_system_core::PROVIDER_UID` (or land the daemon re-home the doc promises) or drop the const until wired | [src/lib.rs:70] | actionable | lane/d2b-provider-system-core.md + +**`d2b-provider-toolkit`** + +- `RS-0414` | medium | `d2b-provider-toolkit` | test-only constructors `GuestCredentialBackend::from_socket_for_test` and `from_socket_for_test_with_route` sit on the public surface (the type is re-exported at the crate root) without the house `test-support` feature gate that `d2b-session` uses for the same class of export | fix: move both behind a `test-support` feature (or `#[doc(hidden)]` + `#[cfg(any(test, feature = "test-support"))]`) so downstream crates cannot rely on them | [packages/d2b-provider-toolkit/src/base/fd10.rs:888, packages/d2b-provider-toolkit/src/base/fd10.rs:901, packages/d2b-provider-toolkit/src/lib.rs:89] | actionable | lane/d2b-provider-toolkit-p1.md +- `RS-0415` | low | `d2b-provider-toolkit` | two dead public methods on `GeneratedProviderServiceServer`: `response_request_id` is a pure identity function (`request_id` in, same reference out) and `generated_service` has no callers anywhere | fix: delete both methods (and the `response_request_id` doc), keeping `generated_services()` which the registration-boundary doc justifies | [packages/d2b-provider-toolkit/src/server/service.rs:297-299, packages/d2b-provider-toolkit/src/server/service.rs:174-176] | actionable | lane/d2b-provider-toolkit-p2.md +- `RS-0416` | low | `d2b-provider-toolkit` | `SharedProviderEffectRequest::envelope()` (the old-shape owner-envelope document) has zero callers and clones the full spec and metadata Values on every call | fix: delete the method; the driver and families read `spec`/`metadata` directly | [packages/d2b-provider-toolkit/src/shared_provider.rs:525-531] | actionable | lane/d2b-provider-toolkit-p2.md +- `RS-0417` | low | `d2b-provider-toolkit` | `TestHarness::clock()` returns `&Arc`, exposing the Arc in the public signature when callers only need the clock | fix: return `&DeterministicClock` (callers at testing/mod.rs:686 and tests/harness.rs:857-909 all deref) | [packages/d2b-provider-toolkit/src/testing/mod.rs:530-532] | actionable | lane/d2b-provider-toolkit-p2.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0418` | low | `d2b-provider-transport-azure-relay` | `RelayCredentialPort::acquire` is a required trait method whose only production implementation (GatewayGuestCredentialPort) returns `Err(BindingRequired)` - the same fail-closed policy the trait already gives `acquire_bound` as a default - so every implementer must write a method that never succeeds | fix: give `acquire` a default body returning `Err(RelayCredentialError::BindingRequired)` and delete the redundant overrides in GatewayGuestCredentialPort and the test fakes | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:491-497, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:387-392] | actionable | lane/d2b-provider-transport-azure-relay.md +- `RS-0419` | low | `d2b-provider-transport-azure-relay` | `set_drop_hook` takes `Arc` in a public signature although the lease is the sole owner of the hook (it is stored once and called on drop), forcing every caller to allocate an Arc for a single-owner value | fix: take `Box` or a generic `F: Fn(u64) + Send + Sync + 'static`; call sites (guest_credential.rs:455, tests) change `Arc::new)...)` to `Box::new)...)` | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343-347, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:455] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-volume`** + +- `RS-0420` | medium | `d2b-provider-volume` | `VolumeDriverArgs.zone: String` is never read by the factory, descriptor, or driver (`create` clones it into a throwaway args before `VolumeDriver::new` drops it; the derived rows' zone comes from the manager-keyed `ResourceContext`, so the doc's "zone identity every derived row folds in" claim has no code path) | fix: remove the field from `VolumeDriverArgs` (and its `lib.rs` re-export), drop the clone at driver.rs:282, update construction sites `d2bd/src/resource_plane_v3.rs:2975-2977` and `tests/registration.rs:25` (plus this crate's test fixtures)) | [driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.rs:25] | actionable | lane/d2b-provider-volume.md + +**`d2b-provider-volume-local`** + +- `RS-0421` | medium | `d2b-provider-volume-local` | `pub mod testing` (ScriptedPort with a Mutex, fixtures, hand-rolled block_on) is compiled unconditionally into the production library although it is consumed only by tests: this crate's tests/** and one d2bd test fn; the house pattern for cross-crate test support is a feature gate | fix: gate the module behind a `test-support` feature (`#[cfg(feature = "test-support")]` on `pub mod testing`, add `[features] test-support = []`), and enable the feature from d2bd's dev-dependencies | [src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1] | actionable | lane/d2b-provider-volume-local.md + +**`d2b-provider-zone`** + +- `RS-0422` | medium | `d2b-provider-zone` | `pub mod zone_status;` plus `pub use zone_status::*;` (lib.rs:9-10) exposes every zone_status item at two paths (crate root and module path), violating the house single-surface pattern (named re-export arms with a private module, cf. telemetry-service lib.rs:34-36 and wayland-session lib.rs:11-20) | fix: make the module private and re-export the four items by name (`SystemCoreStatusEmitter`, `ZoneRuntimeMetadata`, `ZoneStatusInput`, `ZoneStatusProjectionError`), updating the module-path call sites | [packages/d2b-provider-zone/src/lib.rs:9-10, packages/d2b-provider-zone/src/zone_status.rs:43] | actionable | lane/tail-5.md + +**`d2b-provider-zone-link`** + +- `RS-0423` | low | `d2b-provider-zone-link` | `ZoneLinkMetricSample` and `ZONE_LINK_METRIC_LABEL_KEYS` are exported pub (and re-exported through `zonelink`) but have zero consumers outside the crate, so the metric vocabulary is promised surface nobody wires | fix: either consume them from `d2bd`'s metrics path or reduce to `pub(crate)` until a consumer exists | [packages/d2b-provider-zone-link/src/zone_links.rs:1783, packages/d2b-provider-zone-link/src/zone_links.rs:89, packages/d2b-provider-zone-link/src/zonelink.rs:13] | actionable | lane/d2b-provider-zone-link.md +- `RS-0424` | low | `d2b-provider-zone-link` | `transport_error_is_quarantine` is a `pub const fn` with zero callers anywhere, including in-crate tests, so it is dead exported surface | fix: make it private or delete it until the quarantine mapping is actually consumed | [packages/d2b-provider-zone-link/src/zonelink.rs:281] | actionable | lane/d2b-provider-zone-link.md +- `RS-0425` | low | `d2b-provider-zone-link` | `ZoneLinkCursorAuthority` is `pub` but is only reached through `ZoneLinkController` in the same module and the module's own tests, so its publicity is wider than its use | fix: reduce to `pub(crate)` | [packages/d2b-provider-zone-link/src/zonelink.rs:178] | actionable | lane/d2b-provider-zone-link.md + +**`d2b-resource-api`** + +- `RS-0426` | low | `d2b-resource-api` | one-variant `ResourceApiReachability` enum plus `RESOURCE_API_REACHABILITY` const have no production consumer; the only assertion compares the const to its own definition and cannot fail | fix: delete both and the assertion in the 13-method test, or wire the const to a real reachability check | [adapter.rs:251-256, adapter.rs:1208-1211] | actionable | lane/d2b-resource-api-p1.md +- `RS-0427` | low | `d2b-resource-api` | `commit_configuration_batch` is pub on both `ResourceApiClient` and `ResourceService` but nothing calls it (declared "internal Core path", unwired) | fix: wire it into d2bd bundle ingestion (packages/d2bd/src/resource_plane_v3.rs:3445 area) or reduce to pub(crate) until a caller exists | [client.rs:98, service.rs:837] | actionable | lane/d2b-resource-api-p1.md +- `RS-0428` | low | `d2b-resource-api` | three `manager_backend` helpers are pub in a pub module with no production caller outside the crate: `wire_revision` (internal-only), `api_subject` (internal-only), `resource_owner_subject` (test-only, doc says U9/U10 wires it) | fix: make `wire_revision` and `api_subject` pub(crate); keep `resource_owner_subject` pub only when the U9/U10 caller lands | [manager_backend.rs:81, manager_backend.rs:208, manager_backend.rs:227] | actionable | lane/d2b-resource-api-p1.md + +**`d2b-resource-client`** + +- `RS-0429` | medium | `d2b-resource-client` | eight zero-caller pub items form dead surface: `ZonePeerIdentity::from_enrolled_peer` (zone_client.rs:83), `ZoneSocketConnector::local_daemon_endpoint_identity` (361), `ZoneClient::scoped_query` (635), `scoped_child_query` (646), `call_resource` (703), `ProcessAttachTarget::from_target` (process_attach.rs:125), `configured_launcher_from_target` (132), `ProcessAttachClient::attach_local` (721) | fix: remove or demote to `pub(crate)` (and, if kept, merge the two from-target constructors into one) | [packages/d2b-resource-client/src/zone_client.rs:83, packages/d2b-resource-client/src/zone_client.rs:361, packages/d2b-resource-client/src/zone_client.rs:635, packages/d2b-resource-client/src/zone_client.rs:646] | actionable | lane/d2b-resource-client.md merged: d2b-resource-client#9 + +**`d2b-resource-runtime`** + +- `RS-0430` | medium | `d2b-resource-runtime` | ResourceContext::new accepts `_target: TargetHandle` and discards it; every caller supplies a value that is silently dropped | fix: remove the parameter and update the 21 call sites (provider family, resource.rs, metadata.rs, context.rs test_support), or store it and expose ResourceContext::target() per U4's "coarse handle a driver context exposes" | [packages/d2b-resource-runtime/src/context.rs:364-366] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0431` | medium | `d2b-resource-runtime` | TargetBinding::directory() returns &Arc (internals leak in a public signature) and has zero callers | fix: remove the accessor, or return &TargetDirectory if a caller appears | [packages/d2b-resource-runtime/src/target.rs:491-493] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0432` | low | `d2b-resource-runtime` | GuestTargetRuntime::reference() returns TargetRef by value (clones the name String) and has zero callers | fix: remove the accessor, or return &TargetRef | [packages/d2b-resource-runtime/src/guest_target.rs:460-462] | actionable | lane/d2b-resource-runtime-p2.md + +**`d2b-resource-types`** + +- `RS-0433` | medium | `d2b-resource-types` | `assert_metadata_registration` is a test-only assertion helper exported unconditionally through the crate root, while the crate already declares a `test-support` feature that no consumer enables | fix: gate the fn and its `pub use` arm behind `#[cfg(feature = "test-support")]` (or `any(test, feature = "test-support")` per the house pattern in d2b-provider-activation-nixos/Cargo.toml:16-23) and enable the feature from the 11 consumer crates' test targets | [packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72, packages/d2b-resource-types/Cargo.toml:9] | actionable | lane/tail-6.md + +**`d2b-session`** + +- `RS-0434` | low | `d2b-session` | `Fragment.header` is a public mutable field on an exported wire-facing struct while `bytes` is private behind `as_bytes()`, so external crates can corrupt the header/bytes pairing (reassembly validates at use, but the surface invites it) | fix: make `header` private and add `pub fn header(&self) -> &FragmentHeader`, keeping construction through `Fragmenter`/`from_parts` | [fragmentation.rs:10-13] | actionable | lane/d2b-session-p1.md +- `RS-0435` | low | `d2b-session` | SessionEngine exposes seven establishment constructors, the metrics-taking variants have no production callers, and a public with_metrics builder already exists | fix: drop establish_initiator_with_generation_discovery_and_metrics and establish_responder_with_metrics, keep one metrics-taking path per role, and give establish_responder_with_generation_floor a metrics twin instead of recording into a fresh NoopMetrics | [engine.rs:166, engine.rs:262, engine.rs:416, engine.rs:356] | actionable | lane/d2b-session-p2.md merged: d2b-session-p2#8 + +**`d2b-session-unix`** + +- `RS-0436` | medium | `d2b-session-unix` | `SentPacket::acknowledge(self) {}` is a public no-op whose name promises an acknowledgment; its only behavior is dropping the packet (releasing the credit bundle via `Drop`), which callers cannot tell from the signature | fix: remove the method and let callers drop the packet, or document the drop-semantics contract on the method | [packages/d2b-session-unix/src/socket.rs:176] | actionable | lane/d2b-session-unix.md + +**`d2b-sk-frontend`** + +- `RS-0437` | low | `d2b-sk-frontend` | `pub mod agent/config/link/uhid` plus root `pub use` re-exports make every item reachable at two paths, deviating from the house single-surface pattern; only the binary needs a module path | fix: make the four modules private (`mod agent; ...`) and re-export `UhidDevice` (and `UhidEvent`) from lib.rs, updating main.rs:41 to `use d2b_sk_frontend::{Config, SecurityKeyFrontend, UhidDevice, VsockAllocatorLink}` | [packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-sk-frontend/src/lib.rs:27, packages/d2b-sk-frontend/src/main.rs:41] | actionable | lane/tail-6.md + +**`d2b-unsafe-local-helper`** + +- `RS-0438` | low | `d2b-unsafe-local-helper` | the exported surface includes SupervisorSpec, send_frame/receive_frame/configure_socket_buffers, and SUPERVISOR_START_TIMEOUT/SNAPSHOT_RECONCILE_TIMEOUT, none consumed by the crate's only external user (the same crate's binary main.rs, which imports only HelperClient, ScopeRuntime, run_scope_supervisor, SystemdUserScopeManager, default_helper_socket_path) | fix: narrow to pub(crate)/private where possible; keep pub only the items main.rs or a pub signature needs | [packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/protocol.rs:310, packages/d2b-unsafe-local-helper/src/protocol.rs:337, packages/d2b-unsafe-local-helper/src/protocol.rs:357] | actionable | lane/d2b-unsafe-local-helper.md merged: d2b-unsafe-local-helper#8,d2b-unsafe-local-helper#7 + +**`d2bd`** + +- `RS-0442` | medium | `d2bd` | `pub mod process_provider_runtime` and `pub mod provider_effects` are root-public, exposing the daemon's internal composition (83 pub items in the two modules, including `ProductionProcessProviders`, `FixedEffectAdapter`, `ProviderLifecycleDispatch`, and the pub `FixedEffectError`/`ProviderEffectError` enums) whose only external consumer is the crate's own `test-support`-gated integration test; the daemon binary reaches neither module | fix: declare both `pub(crate) mod` in composition.rs and keep a `#[cfg(feature = "test-support")]` re-export seam for `tests/resource_operator_activation.rs` (house pattern for test-support surface) | [packages/d2bd/src/composition.rs:398, packages/d2bd/src/composition.rs:400, packages/d2bd/src/provider_effects.rs:34, packages/d2bd/src/process_provider_runtime.rs:836] | actionable | lane/d2bd-p7.md +- `RS-0441` | low | `d2bd` | `ResourcePlaneV3::targets`/`hub`/`store`/`registry` return `&Arc`, exposing refcount plumbing in the accessor surface and forcing the two callers that need the shared handle to clone through the reference | fix: return `&TargetDirectory`/`&SpecStore`/`&PlaneResourceRegistry` from the borrow-only accessors and `Arc`/`Arc` by value from `hub()`/`targets()`, then update `Arc::clone(plane.hub())` at resource_runtime.rs:4423 and `Arc::clone(plane.targets())` at composition.rs:11250 to `plane.hub()`/`plane.targets()` | [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2bd/src/resource_plane_v3.rs:3295, packages/d2bd/src/resource_plane_v3.rs:3301, packages/d2bd/src/resource_plane_v3.rs:3308] | actionable | lane/d2bd-p6.md +- `RS-0439` | low | `d2bd` | the pub surface of audio_host_controller.rs (trait HostAudioController 59, PipeWireHostController 92, from_audio_node 106, find_audio_node 124, QemuAudioController 214) is unreachable outside the crate because `mod audio_host_controller;` (composition.rs:395) is private | fix: reduce these to `pub(crate)` (FakeHostController is already cfg(test)) so the visibility says what the surface is | [packages/d2bd/src/audio_host_controller.rs:59, packages/d2bd/src/audio_host_controller.rs:92, packages/d2bd/src/composition.rs:395] | actionable | lane/d2bd-p2.md +- `RS-0440` | low | `d2bd` | `vm_name: &str` in HostAudioController::enforce_grant/enforce_level is dead trait surface: every implementation (PipeWire, Qemu, Fake) names it `_vm_name` and ignores it, and the only callers (audio_dispatch.rs:160,177) pass it pointlessly | fix: remove the parameter from both trait methods and the call sites | [packages/d2bd/src/audio_host_controller.rs:68, packages/d2bd/src/audio_host_controller.rs:78, packages/d2bd/src/audio_host_controller.rs:173] | actionable | lane/d2bd-p2.md +- `RS-0443` | low | `d2bd` | `pub use d2b_provider::{MAX_PROVIDER_REGISTRY_ENTRIES, ProviderRegistrySnapshot};` re-exports `ProviderRegistrySnapshot`, which nothing in d2bd uses; only `MAX_PROVIDER_REGISTRY_ENTRIES` is consumed (registry bound check) | fix: re-export `MAX_PROVIDER_REGISTRY_ENTRIES` only, removing the second path to `ProviderRegistrySnapshot` | [packages/d2bd/src/provider_registry.rs:48, packages/d2bd/src/provider_registry.rs:288] | actionable | lane/d2bd-p8.md + +**`d2bd-runtime`** + +- `RS-0444` | medium | `d2bd-runtime` | EstablishedShell exposes `pub backend: Arc`, pushing an Arc + trait-object + the whole backend trait into the public field surface, when callers only need the three trait methods | fix: make the field private, add `handle_op`/`close_attachment`/`cancel_attachment` delegating methods on EstablishedShell, and update the d2bd/src/composition.rs call sites (13403,13460,13517,13625,13677)) | [shell_backend.rs:52-53] | actionable | lane/d2bd-runtime-p1.md merged: d2bd-runtime-p1#9 +- `RS-0446` | low | `d2bd-runtime` | `pub fn spawn_session_worker` (with `pub struct WorkerSpawn`, `SessionTable`, `ExecOpDeadlines`, `ExecStartSpec`, etc.) has no production caller in the workspace - only its own crate's tests - so the whole exec-session worker surface is either pending wiring from d2bd composition or dead public API | fix: wire `spawn_session_worker`/`SessionTable` into d2bd's exec composition (or gate the module test-support-only pending that wiring) | [packages/d2bd-runtime/src/exec_session.rs:900] | actionable | lane/d2bd-runtime-p3.md +- `RS-0445` | low | `d2bd-runtime` | CachedPublicFrame is pub with pub fields (including a serde_json::Value dependency field)but only used inside public_read_model; the struct is dead public surface | fix: make CachedPublicFrame (and its fields) module-private or pub(crate, keep the ArcSwapOption slots private | [public_read_model.rs:51-53] | actionable | lane/d2bd-runtime-p1.md +- `RS-0447` | low | `d2bd-runtime` | `ConsoleClientHandle(pub String)` exposes the inner token of a type documented as "Opaque per-client session token", so any caller can fabricate handles and the opacity claim is unenforced | fix: make the field private, add `FromStr`/`as_str`, and route the table's own lookups through them | [packages/d2bd-runtime/src/console_session.rs:118] | actionable | lane/d2bd-runtime-p4.md +- `RS-0448` | low | `d2bd-runtime` | `spawn_ch_serial_drainer(_vm: String, ...)` takes an unused `_vm` parameter, and its only caller allocates a hardcoded `"ch-console".to_owned()` per session to satisfy it | fix: drop the parameter and the call-site allocation in `create_ch_session` | [packages/d2bd-runtime/src/console_session.rs:341, packages/d2bd-runtime/src/console_session.rs:422] | actionable | lane/d2bd-runtime-p4.md +- `RS-0449` | low | `d2bd-runtime` | `DrainerSource` is a dead public enum: never constructed anywhere, with a `#[allow(dead_code)]` `Connected` variant carrying a tokio stream | fix: delete the enum (and the allow) | [packages/d2bd-runtime/src/console_session.rs:54] | actionable | lane/d2bd-runtime-p4.md +- `RS-0450` | low | `d2bd-runtime` | `ConsoleRing` and `ConsoleSession` expose all fields `pub` (`ring: RingBuffer`, `notify`, `drainer`, `stdin_tx`), so the documented invariant "notify fires whenever bytes are pushed or EOF is set" (console_session.rs:68) is convention-only: an external caller can push bytes without notifying and waiters hang | fix: make the fields private and expose `push_bytes`/`set_eof`/`read_at` on `ConsoleRing` and accessors on `ConsoleSession` that notify internally | [packages/d2bd-runtime/src/console_session.rs:66, packages/d2bd-runtime/src/console_session.rs:90] | actionable | lane/d2bd-runtime-p4.md + +### `err` + +Error policy: panic vs Result boundary, taxonomy split by caller action, context survival, wire error codes. + +**`X3-cross-crate-duplication`** + +- `RS-0963` | medium | `X3-cross-crate-duplication` | Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { path, detail: String }`, `Io(String)`, `Frame(String)`, `ManagerRpc(String)`, `TypedError::InternalIo { context, detail }`, five `String` variants of PlaneError, `kind: String` in four Io variants), destroying the source chain so diagnostics and callers cannot distinguish failure classes | fix: carry the source with thiserror `#[from]`/`source()` in each enum (no in-tree helper exists; the std Error source chain is the canonical home); wire-visible members (d2bd TypedError) need contract sign-off before the shape changes, internal members (broker, clipboard, azure-relay, resource-runtime, d2bd-runtime vsock) are actionable first | [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69] | needs-contract | lane/X3-cross-crate-duplication.md + +**`d2b`** + +- `RS-0477` | medium | `d2b` | `CliFailure` flattens the error class into the message (`format!("{error_class}: {message}")`), so callers recover the class by string-matching the message prefix | fix: add a structured `code: &'static str` field to `CliFailure` (lib.rs:44-52), populate it in `ZoneContext::failure` (context.rs:1181-1189), and match on it in `can_fallback_to_local_state` and `reconcile_deadline` instead of `message.split(':').next()` / `strip_prefix("ref-invalid: ")` | [packages/d2b/src/host.rs:200, packages/d2b/src/resource.rs:916, packages/d2b/src/lib.rs:44] | actionable | lane/d2b-p2.md +- `RS-0478` | medium | `d2b` | `d2b host prepare`/`destroy` without flags exit 2 with kind `ref-invalid`, diverging from the documented `--apply-or-dry-run-required` exit-78 envelope; `host reconcile` exits 78 but with the wrong kind | fix: route `mutation()` and `reconcile()` through `missing_mutation_flag_envelope` (dispatch.rs:369-375) like `validate()` already does, or correct docs/reference/error-codes.md:156 | [packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, docs/reference/error-codes.md:156] | needs-contract | lane/d2b-p2.md merged: d2b-p2#7 + +**`d2b-audit`** + +- `RS-0451` | medium | `d2b-audit` | `export_segments_range` classifies a failed `AuditRecord` deserialize by string-matching the serde error's Display (`error.to_string().contains("audit-record-hash-mismatch")`) to pick the "hash-break" export error code; a reworded deserialize message silently reclassifies a chain break as "record-invalid" | fix: split parse from verification (deserialize into a wire shape, then `verify()` to surface `AuditRecordError::HashMismatch`), or have the `Deserialize` impl expose the failure class; the emitted `error_code` strings stay unchanged | [packages/d2b-audit/src/export.rs:230] | actionable | lane/d2b-audit.md +- `RS-0452` | medium | `d2b-audit` | `is_discardable_checkpoint_scratch_error` classifies `io::Error` by matching `error.to_string().as_str()` against three literal codes ("audit-retention-checkpoint-invalid" / "-limit" / "-unverifiable") produced by `io::Error::other` at the checkpoint read/validate sites; a reworded code silently changes the discard decision on restart | fix: introduce a private checkpoint-read error enum (or a sentinel error kind) and match on it, keeping the io::Error strings at the public boundary | [packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b-audit/src/segment.rs:718] | actionable | lane/d2b-audit.md + +**`d2b-broker`** + +- `RS-0455` | high | `d2b-broker` | DispatchAuditContext::from_request panics the broker on a malformed authoritative audit join: both CanonicalAuditDigest::parse(zone_id.expect)...) at runtime.rs:2419-2422 parse data that came straight out the wire (request.authoritative_audit_join() returns the strings unchecked), while the sibling from_request_with_join (runtime.rs:2440-2444) converts the same parse failure to BrokerError::Protocol - a remote caller can crash the daemon | fix: replace both expect("authoritative ... digest") calls with `.map_err(|_| BrokerError::Protocol("audit zone identity invalid".to_owned()))?;`, mirroring runtime.rs:2442-2444, keeping the panic out of the wire path | [packages/d2b-broker/src/runtime.rs:2419, packages/d2b-broker/src/runtime.rs:2422] | actionable | lane/d2b-broker-p2.md +- `RS-0454` | medium | `d2b-broker` | `UsbipLockError::Io { path: PathBuf, detail: String }` flattens the underlying `io::Error` into its Display string at 12 conversion sites, losing the source chain (os error number and context) a `#[source]` field would keep for diagnosis | fix: change the variant to `Io { path: PathBuf, #[source] source: std::io::Error }` and drop the `detail: e.to_string()` maps | [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84, packages/d2b-broker/src/ops/usbip_lock.rs:98, packages/d2b-broker/src/ops/usbip_lock.rs:110] | actionable | lane/d2b-broker-p1.md +- `RS-0457` | medium | `d2b-broker` | `WriteMarkerBlockError::Io(String)` (hosts.rs:122) flattens `io::Error` into a Display-only string at three `map_err` sites, destroying the error kind/source so a caller cannot classify NotFound vs permission vs other without string-matching | fix: switch the variant to `Io(#[source] io::Error)` (thiserror or a hand-written `#[source]` accessor) and render the same "update-hosts marker splice: {err}" prefix so the visible message is unchanged | [packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-broker/src/ops/hosts.rs:149, packages/d2b-broker/src/ops/hosts.rs:153, packages/d2b-broker/src/ops/hosts.rs:180] | actionable | lane/d2b-broker-p5.md +- `RS-0456` | low | `d2b-broker` | `CellStore` panic policy is inconsistent: `in_memory()` (state_cells.rs:348) and `with_retention()` (360) `.expect()` on `spawn_owner` failure while the sibling `open()` (353) propagates `CellStoreError::Io` from the same call | fix: make `with_retention` return `Result` (its callers are tests), and have `in_memory` keep its infallible contract only with an `expect` that names the startup-precondition rationale | [packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360] | actionable | lane/d2b-broker-p3.md +- `RS-0458` | low | `d2b-broker` | usbip_unbind_error_is_transient classifies retryable-vs-fatal usbip failures by case-folded substring matching over `stderr`/`error` text (42-Condition-Not-Satisfied, "program does not support"..., "no matching transport"), so a locale or usbip-version message change silently flips the retry decision and the broker's eventual verdict. | fix: parse the failure once at the stderr boundary into a typed `UsbipUnbindFailure { kind: UsbipUnbindFailureKind, transient: bool, detail: String }` (or a documented constant allowlist),and drive the retry loop (and final error reporting) off the typed kind instead of re-scanning strings. | [src/ops/exec_reconcile.rs:1238-1265] | actionable | lane/d2b-broker-p6.md +- `RS-0459` | low | `d2b-broker` | guest_socket_directory returns `Result<&'static str,...>` with two plain-static-code errors (a "not root-owned" refusal, "no guest" refusal),while the sibling launch-scope pinner uses a typed `DeviceWorkerScopeError` enum - so an internal closed-error str forces callers (live_handlers.rs:2428) to stringly-match an error. | fix: give guest_socket_directory a small `GuestSocketError` enum (or reuse DeviceWorkerScopeError's callers-action split with a `GuestSocket` variant.)and return that instead of a `&'static str`. | [src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2428] | actionable | lane/d2b-broker-p6.md + +**`d2b-broker-composition`** + +- `RS-0453` | low | `d2b-broker-composition` | four public/private error returns are bare `Result<_, String>` (`verify_startup_routing`, `audit_crate`, `run_cargo_metadata`, `dependency_tree`), so a future caller that must distinguish failure classes (environment unavailable vs. cargo failure vs. invariant violation) can only string-match | fix: introduce a small typed error enum per module (the seam already owns `RoutingRefusal`; give `dependency_surface` an audit error enum with variants such as `WorkspaceUnavailable`/`CargoFailed`/`InvalidMetadata`) and return it from the cited functions | [packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/dependency_surface.rs:226, packages/d2b-broker-composition/src/dependency_surface.rs:292, packages/d2b-broker-composition/src/dependency_surface.rs:317] | actionable | lane/d2b-broker-composition.md merged: d2b-broker-composition#8 + +**`d2b-bus`** + +- `RS-0460` | medium | `d2b-bus` | public `ZoneBoundPolicyIdentity::with_provider` returns `Result`, a string a caller must string-match instead of matching on a variant | fix: return a closed error type (reuse `ZonePolicyError` with a new `NotProviderRef` variant, or a small `ZoneBoundPolicyIdentityError` enum) for the single failure condition | [packages/d2b-bus/src/wire.rs:49-56] | actionable | lane/d2b-bus-p2.md + +**`d2b-contracts`** + +- `RS-0461` | medium | `d2b-contracts` | Public constructors/validators return `Result<_, String>` or `&'static str` (ConfiguredArgv::new configured_argv.rs:15, RealmWorkloadsLauncherV2Json::validate launcher.rs:21, UnsafeLocalWorkloadsJson/LocalVmConfiguredWorkload/UnsafeLocalWorkload::validate unsafe_local_workloads.rs:35/81/96, MediaRef::validate_value and validate_usb_bus_id types.rs:114/140, validate_audit_page audit_wire.rs:51) while sibling validators inthe same crate use typed enum errors (BusIdError, IfNameError, IdError, ContractStringError, IdentityError, TokenError), forcing callers to string-match instead of matching variants | fix: introduce typed error enums per surface (e.g. `ConfiguredArgvError`, `UnsafeLocalWorkloadsError`, `LauncherMetadataError`, `MediaRefError`)with thiserror-style Display + std::error::Error impls and return them; call sites that only `.unwrap()` (census: ConfiguredArgv::new used in d2b-contracts-control, d2bd-runtime, d2bd, d2b-unsafe-local-helper) compile unchanged | [packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:21, packages/d2b-contracts/src/unsafe_local_workloads.rs:35, packages/d2b-contracts/src/types.rs:114] | actionable | lane/d2b-contracts.md merged: d2b-contracts#1,d2b-contracts#2,d2b-contracts#7 + +**`d2b-contracts-control`** + +- `RS-0462` | low | `d2b-contracts-control` | `ShellNameError` is a public error type with no `Display` or `std::error::Error` impl, so callers cannot format it or chain it with `?` | fix: add `Display` + `std::error::Error` impls (additive; the type is documented as an empty struct in daemon-api.md:653) | [public_wire.rs:1297] | actionable | lane/d2b-contracts-control.md + +**`d2b-contracts-provider`** + +- `RS-0463` | medium | `d2b-contracts-provider` | `ProviderRegistryPublication::new` maps `generation == 0` to `MappingBoundExceeded` even though the `ZeroGeneration` variant exists and is used by the entry constructor, so a caller distinguishing invalid generation from bound overflow receives the wrong code | fix: split the check into `if generation.get() == 0 { return Err(ZeroGeneration) }` before the mapping-count bound | [packages/d2b-contracts-provider/src/v3/provider_registry.rs:186, packages/d2b-contracts-provider/src/v3/provider_registry.rs:92] | actionable | lane/d2b-contracts-provider-p1.md +- `RS-0465` | low | `d2b-contracts-provider` | `CredentialControllerError::AlreadyRunning` renders the wire label "credential-queue-pressure", which names a different concept (the lease-ceiling outcome `CredentialControllerOutcome::QueuePressure`) than the variant's documented meaning ("the same Credential is already being handled") | fix: emit "credential-already-running" from the Display arm, or rename the variant to match the code | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:90] | actionable | lane/d2b-contracts-provider-p2.md +- `RS-0466` | low | `d2b-contracts-provider` | `CredentialObservabilityError` Display strings are prose sentences ("credential audit record is invalid", "credential telemetry frame is invalid"), breaking the kebab-code diagnostic convention every sibling error type in this crate follows (`CredentialControllerError`, `MetricPolicyError`, `TelemetryFrameError`, `SemanticContractError`, `BindingChildError`) | fix: render "credential-audit-record-invalid" and "credential-telemetry-frame-invalid" | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1508, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1509] | actionable | lane/d2b-contracts-provider-p2.md +- `RS-0464` | low | `d2b-contracts-provider` | an entry-generation mismatch in `ProviderRegistryPublication::new` reports `AxisMismatch`, whose Display code is `provider-registry-axis-mismatch`, although no binding axis is involved | fix: add a `GenerationMismatch` variant with its own kebab code and return it for the `entry.provider_generation != generation` check | [packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-provider/src/v3/provider_registry.rs:193] | actionable | lane/d2b-contracts-provider-p1.md +- `RS-0467` | low | `d2b-contracts-provider` | `CredentialSingleFlight` maps a poisoned mutex to `InvalidInput` (a caller-input error) and its guard `Drop` silently skips the removal on poison, which would leave a stale UID and a permanent `AlreadyRunning`; the skill names recovery via `into_inner()` for exactly this shape | fix: recover with `self.running.lock().unwrap_or_else(|poisoned| poisoned.into_inner())` in both `lock()` and `Drop`, keeping the documented synchronous-path boundary | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:834, packages/d2b-contracts-provider/src/v3/credential_controller.rs:846] | actionable | lane/d2b-contracts-provider-p2.md + +**`d2b-contracts-resource`** + +- `RS-0468` | medium | `d2b-contracts-resource` | `StoreErrorKind` (operations/error.rs:93-129) duplicates all 31 `ResourceErrorKind` variants and their `as_str` spellings verbatim, and d2b-resource-api/src/error.rs:11-56 `map_store_error_kind` re-lists all 31 a third time, so adding one resource-plane kind requires three synchronized edits and no test pins the overlap (each set only pins its own size) | fix: restructure `StoreErrorKind` as `Resource(ResourceErrorKind)` plus the three store-only variants (StoreIntegrityFailure, StoreBackpressure, StoreQuarantined), which collapses the map to one arm plus store arms while keeping `as_str` outputs identical | [packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-resource/src/v3/operations/error.rs:132, packages/d2b-resource-api/src/error.rs:11] | actionable | lane/d2b-contracts-resource-p1.md + +**`d2b-contracts-zone-session`** + +- `RS-0469` | medium | `d2b-contracts-zone-session` | from_component_session on EndpointPurpose and ServicePackage panics via expect("preserved component-session tag") on a wire-derived value, enforcing the cross-taxonomy totality only at runtime | fix: replace the tag lookup with an exhaustive match over base::EndpointPurpose / base::ServicePackage variants so adding a component-session variant becomes a compile error, or return Result like EndpointRole::from_component_session already does (zone_session.rs:314) | [zone_session.rs:297, zone_session.rs:332] | actionable | lane/d2b-contracts-zone-session-p2.md + +**`d2b-core`** + +- `RS-0471` | medium | `d2b-core` | resolve_macvtap_intents returns `Result, String>`, a String error in a library API whose two failure modes (missing process node, missing macvtap metadata) are indistinguishable to the caller; the broker wraps it wholesale into BrokerError::LiveHandler | fix: return `crate::error::Error` via `Error::manifest_parse_error` or a small enum with the two variants, and update the single broker call site | [packages/d2b-core/src/bundle_resolver.rs:2625, packages/d2b-broker/src/runtime.rs:6405] | actionable | lane/d2b-core-p1.md +- `RS-0475` | medium | `d2b-core` | `StorageJson::validate_unique_ids` and `SyncJson::validate_lock_order` return `Result<(), String>` with format!-built messages, and storage_lifecycle.rs re-derives the failure reason and offending id by string-prefix matching (`classify_storage_validation_reason`, `classify_sync_validation_reason`, `*_offending_id`, `bounded_contract_detail`), an error taxonomy that forces string-matching; the whole chain has no production caller | fix: return a typed validation error from both validators whose variants are the existing wire enums (`StorageContractValidationReason`, `SyncContractValidationReason`) with the offending id as payload, and delete the classifier functions | [packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core/src/storage_lifecycle.rs:116, packages/d2b-core/src/storage_lifecycle.rs:140] | actionable | lane/d2b-core-p2.md +- `RS-0472` | medium | `d2b-core` | Network spec parse failures inside the trusted-bundle network path are silently dropped: `let Ok(spec) = serde_json::from_value::(spec_value) else { continue; };` in build_resource_network_intents and `serde_json::from_value(value).ok()` in find_network_spec, so a producer-side spec drift silently vanishes every intent for that network and surfaces only as an opaque "intent not found" at apply time | fix: plumb a `Result` out of build_resource_network_intents and find_network_spec and return `Error::manifest_parse_error("resource-bundle.json", reason)` on parse failure so the drift is diagnosable | [packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:1982] | actionable | lane/d2b-core-p1.md +- `RS-0476` | low | `d2b-core` | `SiteJson::validate` returns `Result<(), &'static str>` with a bare token ("invalid-wayland-socket") that callers must string-match | fix: return a small unit error enum (e.g. `SiteValidationError::InvalidWaylandSocket`) with the token as its Display | [packages/d2b-core/src/site.rs:42] | actionable | lane/d2b-core-p2.md merged: d2b-core-p2#11 +- `RS-0473` | low | `d2b-core` | from_artifacts_with_zone_resource_bundles panics on caller-supplied input via two expects (`bundle serialization for audit hashing must succeed`, `zone resource bundle bytes must be verified`) in a `pub` API whose doc comment states the precondition but cannot enforce it; the fuzz target is one caller that passes arbitrary bytes | fix: return `Result` (map both to `Error::internal_io` / `Error::manifest_parse_error`) or downgrade to `debug_assert!` plus a doc note | [packages/d2b-core/src/bundle_resolver.rs:1405, packages/d2b-core/src/bundle_resolver.rs:1412, packages/d2b-core/fuzz/src/bin/core.rs:1] | actionable | lane/d2b-core-p1.md +- `RS-0474` | low | `d2b-core` | manifest_parse_reason classifies serde failures by substring-matching the Display text (`"missing field"`, `"unknown field"`, `"invalid type"`), which is not a stable API and silently degrades to `"parse-failed"` on any message rewording | fix: match on `serde_json::Error::classify()` (ErrorClass::Syntax / Data / Eof) instead of the message text | [packages/d2b-core/src/bundle_resolver.rs:5730] | actionable | lane/d2b-core-p1.md + +**`d2b-core-controller`** + +- `RS-0470` | low | `d2b-core-controller` | AuthorityError::DuplicateConflict renders the wire code "duplicateConflict", the only non-kebab-case code in the 25-variant enum, and nothing outside this crate matches the string | fix: change the code() arm to "duplicate-conflict" and update the two in-crate assertions that pin the old spelling (authority.rs:3409 and the code table test) | [authority.rs:412] | actionable | lane/d2b-core-controller-p2.md + +**`d2b-process-conformance`** + +- `RS-0479` | low | `d2b-process-conformance` | `LaunchIdentity::new` re-borrows `owner_ref` with `.expect("binding owner is present")` immediately after an `is_some_and` guard on the same value, an input-derived `expect` the skill's audit flags; the guard and the re-borrow are the same condition so the panic is unreachable but the shape is avoidable | fix: use an if-let chain, e.g. `if let Some(owner) = owner_ref.as_ref().filter(|o| o.resource_type().as_str() == "VolumeBinding") && target_ref.is_none() { ... owner.to_canonical_string() ... }`, deleting both the separate guard and the `expect` | [packages/d2b-process-conformance/src/launch_identity.rs:147] | actionable | lane/d2b-process-conformance.md + +**`d2b-provider-activation-nixos`** + +- `RS-0480` | medium | `d2b-provider-activation-nixos` | `GenerationObservation::terminal` (exported via lib.rs:33) panics with `assert!` on a caller-supplied name that is empty, contains '/', or exceeds 128 chars, instead of making the bound a type or a `Result` | fix: take `name: ResourceName` (already bounded: no '/', <=128 chars) and have `new` parse through the same path, or return `Result`; this deletes the runtime check the type makes impossible | [packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activation-nixos/src/controller.rs:121] | actionable | lane/d2b-provider-activation-nixos.md merged: d2b-provider-activation-nixos#6 + +**`d2b-provider-audio-pipewire`** + +- `RS-0481` | medium | `d2b-provider-audio-pipewire` | `MicrophoneArbiter::new(0)` and `SpeakerMixer::new(0)` panic via `assert!` on caller input to a pub constructor; the skill's panic policy says input validation is always a `Result`, and the type-level answer (`NonZeroUsize`) exists | fix: take `NonZeroUsize` (or return `Result`) in both constructors; no current caller passes 0 (daemon uses 64), so the change is mechanical | [src/authority.rs:53-54, src/authority.rs:144-145] | actionable | lane/d2b-provider-audio-pipewire.md +- `RS-0482` | low | `d2b-provider-audio-pipewire` | the crate's error enums never chain sources: `AudioStateIoError`'s seven `io::Error` payloads and `AudioControllerError::Mediator(AudioMediatorError)` leave `Error::source()` returning `None`, flattening the chain into the Display message | fix: implement `std::error::Error::source()` for the payload variants (or move the crate to `thiserror` `#[source]`, which also removes the hand-written Display impls) | [src/state.rs:114-123, src/controller.rs:155-160] | actionable | lane/d2b-provider-audio-pipewire.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0483` | low | `d2b-provider-clipboard-wayland` | spawn_niri_event_thread panics with .expect("niri thread spawn") on thread-spawn failure while the four sibling spawn sites log the error and continue | fix: return Result from spawn_niri_event_thread and log at the call site like the bridge-copy-read, paste-replay, host-copy-read, and published-write spawners | [src/bin/d2b-clipd.rs:3550, src/bin/d2b-clipd.rs:1754, src/bin/d2b-clipd.rs:2863] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0484` | low | `d2b-provider-clipboard-wayland` | the binary propagates errors as Result<_, String> with format!-built messages at 13 signatures, where the skill names anyhow for binaries | fix: introduce anyhow at the binary top level (run and its helpers), keeping the lib error enums unchanged | [src/bin/d2b-clipd.rs:127, src/bin/d2b-clipd.rs:411, src/bin/d2b-clipd.rs:247] | actionable | lane/d2b-provider-clipboard-wayland-p1.md merged: d2b-provider-clipboard-wayland-p1#1,d2b-provider-clipboard-wayland-p1#7 +- `RS-0485` | low | `d2b-provider-clipboard-wayland` | ClipboardHistory::new returns Result but the body is an unconditional Ok, so the error arm and the map_err at ClipdHost::new (with its warn) are dead code that misleads callers into handling an impossible failure | fix: return Self from new and drop the map_err in ClipdHost::new | [packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:575-579] | actionable | lane/d2b-provider-clipboard-wayland-p2.md merged: d2b-provider-clipboard-wayland-p2#15 +- `RS-0486` | low | `d2b-provider-clipboard-wayland` | PickerSupervisor collapses the typed FramingError into PickerError::Frame(String) via to_string() at six sites, so callers cannot distinguish FrameTooLong from Incomplete from a JSON error without string matching | fix: add a `Frame(FramingError)` variant (with #[from] or #[source]) and map the framing errors into it | [packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:274, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:284, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:290] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-config-nixos`** + +- `RS-0487` | low | `d2b-provider-config-nixos` | `invalid_status()` maps client-side request-encoding failures to ttrpc `INVALID_ARGUMENT` plus the `config-document-encoding-failed` code, telling the caller their request was invalid when the client implementation failed to serialize | fix: map that site to `INTERNAL` (or reuse `rpc_error(ConfigError::EncodingFailed)`) so status class matches the code | [packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixos/src/ttrpc.rs:189] | actionable | lane/d2b-provider-config-nixos.md + +**`d2b-provider-credential-managed-identity`** + +- `RS-0488` | low | `d2b-provider-credential-managed-identity` | `export_checkpoints` panics via `.expect("lease map keys are validated Credential refs")` where every sibling invariant failure in the crate map_errs to `CredentialServiceErrorCode::InvariantFailure` | fix: replace with `.map_err(|_| invariant())?` (leveragingthe existing `invariant()` helper at lib.rs:1491) | [lib.rs:1261-1262] | actionable | lane/d2b-provider-credential-managed-identity.md + +**`d2b-provider-device-tpm`** + +- `RS-0489` | medium | `d2b-provider-device-tpm` | two same-named error enums for one domain: runner.rs:43 SwtpmArgvError (one variant, LogLevelOutOfRange with no payload, returned by SwtpmSettings::validate) and swtpm_argv.rs:104 SwtpmArgvError (six variants including LogLevelOutOfRange { level }), both reachable from the crate root (lib.rs:35 re-exports the runner one; pub mod swtpm_argv exposes the other), so callers must disambiguate by module path and the two same-named LogLevelOutOfRange variants differ in shape | fix: make SwtpmSettings::validate return swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level } and delete runner::SwtpmArgvError | [runner.rs:43, swtpm_argv.rs:104, lib.rs:35, tests/conformance.rs:11] | actionable | lane/d2b-provider-device-tpm.md + +**`d2b-provider-device-usbip`** + +- `RS-0490` | medium | `d2b-provider-device-usbip` | `UsbipStepExecutor` returns `Result<(), String>` from every step method, forcing implementers and callers to string-match reasons where the crate's own taxonomy is otherwise typed enums with `code()` accessors | fix: introduce a closed per-step error enum (or reuse `UsbipPlanError` tagged with the step) and map it in `execute_usbip_plan` | [state_machine.rs:378-386] | actionable | lane/d2b-provider-device-usbip.md + +**`d2b-provider-display-wayland`** + +- `RS-0491` | medium | `d2b-provider-display-wayland` | `DisplayController::new(pool_size)` panics via `PrincipalPool::new(pool_size).expect(...)` (controller.rs:740-741) on any caller-supplied pool size outside 1..=32; the pub library API should not panic on input-derived values | fix: return `Result` from `DisplayController::new` (or document `# Panics` naming the bound) and update the two daemon call sites | [src/controller.rs:740, src/controller.rs:741] | actionable | lane/d2b-provider-display-wayland-p2.md +- `RS-0493` | medium | `d2b-provider-display-wayland` | grant and ticket constructors return `Result<_, &'static str>` error codes (`issue_for_supervisor_with_controller_generation` process.rs:335-346, `new_for_role_with_controller_generation` process.rs:825-887), so callers cannot match the failure and the codes are untyped strings | fix: introduce a closed `LaunchError` enum (thiserror) with `SessionInvalid` and `TicketInvalid` variants and return it from both constructors; the daemon caller maps to WorkerEffectError today (d2bd interaction_composition.rs:4283) | [src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886] | actionable | lane/d2b-provider-display-wayland-p2.md +- `RS-0492` | low | `d2b-provider-display-wayland` | `WaylandSpecError::NoPrincipalAvailable` (spec.rs:30) is never constructed: pool exhaustion is mapped to a Failed status with `SessionCondition::NoPrincipalAvailable` instead of the error variant | fix: either construct the variant in the exhaustion path (controller.rs:1089) or delete it and its Display arm | [src/spec.rs:30, src/spec.rs:43] | actionable | lane/d2b-provider-display-wayland-p2.md + +**`d2b-provider-host`** + +- `RS-0494` | low | `d2b-provider-host` | the `HostDriverEffects::observe_host` seam returns `Result`: the production impl flattens the probe error and the fallback reconcile error into one `format!("{probe_error}; {error}")` message, losing the source chain; an internal crate per the skill wants an enum (or thiserror with `#[source]`) | fix: introduce a small closed error enum (e.g. `ObserveError { Probe(SystemCoreError), Reconcile(String) }` with `#[source]`) on the trait and both impls | [packages/d2b-provider-host/src/driver.rs:197, packages/d2b-provider-host/src/effects_service.rs:180] | actionable | lane/d2b-provider-host.md +- `RS-0495` | low | `d2b-provider-host` | `HostDriverError::Display` re-spells the three failure-kind codes ("system-core-spec-invalid", "system-core-host-observation-failed", "system-core-drain-pending") that `HostDriverErrorKind::failure_kind()` already maps to, so a registry-code rename drifts silently | fix: `formatter.write_str(self.kind.failure_kind().code())` using the public `FailureKind::code()` | [packages/d2b-provider-host/src/driver.rs:129, packages/d2b-provider-host/src/driver.rs:99] | actionable | lane/d2b-provider-host.md + +**`d2b-provider-network-local`** + +- `RS-0496` | low | `d2b-provider-network-local` | the sole non-test unwrap (SHA-256 word slice conversion() carries no named invariant, though the 4-byte length is statically known | fix: `u32::from_be_bytes(chunk[offset..offset + 4].try_into().expect("4-byte chunk word"))` or a slice-pattern destructure | [src/nftables.rs:588] | actionable | lane/d2b-provider-network-local.md + +**`d2b-provider-notification-desktop`** + +- `RS-0497` | medium | `d2b-provider-notification-desktop` | Fifty `Result<_, &'static str>` sites (controller, lifecycle, guest_source, runtime) form a stringly error family forcing callers to string-match, while sibling enums (AdmissionError, NotificationError, SinkError)_ are typed | fix: introduce one crate error enum (suggest `NotificationLifecycleError`) for the lifecycle/controller/config family and replace the str returns on pub fns and both effect-port traits; update d2bd's `InteractionNotificationLifecycleBackend` impl | [packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provider-notification-desktop/src/lifecycle.rs:291-297, packages/d2b-provider-notification-desktop/src/controller.rs:369, packages/d2b-provider-notification-desktop/src/controller.rs:930] | actionable | lane/d2b-provider-notification-desktop.md +- `RS-0498` | medium | `d2b-provider-notification-desktop` | Delivery rejection paths collapse every admission/session/category failure into `NotificationError::InvalidOpaqueKey`, misreporting "notification-opaque-key-invalid" for unauthenticated, cross-zone,and category-denied cases | fix: add an `NotificationError::Denied` (or `SessionDenied`) variant and map the five admission/zone/category rejection sites to it; keep `InvalidOpaqueKey` for key-bound violations | [packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-notification-desktop/src/host_sink.rs:195, packages/d2b-provider-notification-desktop/src/host_sink.rs:202, packages/d2b-provider-notification-desktop/src/host_sink.rs:308] | actionable | lane/d2b-provider-notification-desktop.md + +**`d2b-provider-observability-otel`** + +- `RS-0499` | low | `d2b-provider-observability-otel` | when the connection-tracking table is full, reject() reports `IngressErrorClass::Malformed` ("frame could not be decoded") though the frame may be valid, whereas the sibling capacity refusal reports `None` | fix: return `IngressOutcome::Rejected, IngressErrorClass::None)` on that branch(or a distinct class, if one is introduced for wire labeling),consistent with the capacity path at ingress_policy.rs:460 | [ingress_policy.rs:647] | actionable | lane/d2b-provider-observability-otel.md + +**`d2b-provider-process`** + +- `RS-0500` | low | `d2b-provider-process` | `.ok().and_then(...)` swallows the parse of a stored owning-row spec in the launch-identity path: a corrupt `VolumeBinding` or `Volume` row silently degrades to an unbound launch instead of refusing with `SpecInvalid` | fix: map the two `serde_json::from_slice` failures to `ProcessDriverErrorKind::SpecInvalid` (or return `None` only for genuinely absent rows, not for parse failures) in `identity()` and `serving_worker_launch()` | [packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/driver.rs:1124-1130] | actionable | lane/d2b-provider-process.md + +**`d2b-provider-process-systemd`** + +- `RS-0501` | low | `d2b-provider-process-systemd` | `SystemdProviderError` (src/error.rs) is a closed error catalogue with zero consumers while the live handlers refuse through the parallel `&'static str` code constants in src/operations.rs:51-107 - two refusal vocabularies in one crate | fix: delete the unused enum, or route the handler refusals through it (its codes are not pinned in docs/reference/error-codes.md, so no wire contract binds them) | [packages/d2b-provider-process-systemd/src/error.rs:5, packages/d2b-provider-process-systemd/src/operations.rs:51] | actionable | lane/d2b-provider-process-systemd.md + +**`d2b-provider-supervisor`** + +- `RS-0502` | medium | `d2b-provider-supervisor` | `ProviderSupervisor::with_limits` (the public constructor knob) panics with `assert!` on caller-provided `blocking_limit == 0` and zero `default_timeout` instead of returning a `Result` - a library panic on caller input, reachable from any future caller passing a computed bound | fix: return `Result` (or clamp and document) and have the single current construction sites handle it | [packages/d2b-provider-supervisor/src/adapter.rs:419-421] | actionable | lane/d2b-provider-supervisor.md merged: d2b-provider-supervisor#8 +- `RS-0503` | low | `d2b-provider-supervisor` | `map_error` folds any currently-unknown `ProcessEffectError` variant into `LaunchFailed` via a `_` catch-all arm, so a new upstream variant (d2b-provider-process) fails at runtime instead of at compile time | fix: make the match exhaustive over the closed variant set (drop `_`), keeping the current mappings | [packages/d2b-provider-supervisor/src/adapter.rs:888-890] | actionable | lane/d2b-provider-supervisor.md + +**`d2b-provider-telemetry-service`** + +- `RS-0504` | medium | `d2b-provider-telemetry-service` | `reconcile_service` replaces the manager's `ResourceError` with the stable `Reconcile` kind via `Err(_) => return Err(...)`, dropping the source, so the actor sees only the wire code and the underlying store failure is invisible | fix: log the source before converting (the crate has no tracing dependency today) or carry it as a `#[source]` field on `TelemetryServiceDriverError` | [packages/d2b-provider-telemetry-service/src/driver.rs:304] | actionable | lane/tail-5.md +- `RS-0505` | low | `d2b-provider-telemetry-service` | `ingest_endpoint_refs` silently drops unparseable declared refs (`ResourceRef::parse(value).ok()` inside `filter_map`), so a typo'd `ingestEndpointRefs` entry is indistinguishable from an absent list and the row requeues on the 5s resync forever with no signal | fix: log a warning naming the dropped value, or fail the reconcile with `InvalidResource` | [packages/d2b-provider-telemetry-service/src/driver.rs:386] | actionable | lane/tail-5.md + +**`d2b-provider-test-controller`** + +- `RS-0506` | low | `d2b-provider-test-controller` | `send_bootstrap` and `controller_transport` drop every failure reason with `map_err(|_| ())` (AncillaryCapacity, credit scopes, packet build, send burst, transport build), and the caller logs only the generic retry line, while sibling sites log `reason = %e` | fix: log the reason at each drop site with `warn!(reason = %e, ...)` before converting to `()` | [packages/d2b-provider-test-controller/src/main.rs:186-187, packages/d2b-provider-test-controller/src/main.rs:196-199, packages/d2b-provider-test-controller/src/main.rs:221-230] | actionable | lane/tail-5.md + +**`d2b-provider-toolkit`** + +- `RS-0507` | medium | `d2b-provider-toolkit` | the refused-forwarded-invocation audit is silently dropped for the documented U10 wire spelling: `invoke_named_with_fds_under_chain` audits the raw caller string, and `audit_named` returns when `BoundedToken::parse` fails, but the forwarded family names are PascalCase (`OpenPidfd`), which the `^[a-z][a-z0-9-]*$` token grammar rejects, so the Denied record the module contract promises for every refused invocation never lands for the uncommitted forwarded path | fix: audit the canonicalized name (lowercase/dash-strip before `BoundedToken::parse`, or audit the resolved entry's `operation.name()` when an entry exists) and add a harness case asserting the PascalCase forwarded spelling records a Denied event | [packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-toolkit/src/operations/envelope.rs:495-497, packages/d2b-provider-toolkit/src/operations/envelope.rs:341-346] | actionable | lane/d2b-provider-toolkit-p1.md +- `RS-0508` | medium | `d2b-provider-toolkit` | `SharedProviderDriver::new` panics via `ZoneId::parse(args.zone).expect("driver zone was validated at construction")`, but `SharedProviderDriverArgs.zone` is a plain pub `String` with no validation anywhere at the factory boundary, so a family passing an invalid zone crashes the provider process at driver construction | fix: hold `ZoneId` in `SharedProviderDriverArgs` (parse once in `SharedProviderDriverFactory::new` and return a `Result`), or make `create` fallible | [packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/src/shared_provider.rs:539-546] | actionable | lane/d2b-provider-toolkit-p2.md +- `RS-0510` | medium | `d2b-provider-toolkit` | `Fixture::method` maps `SpecifiedProviderMethod` with a `_ => unreachable!("specified Provider method is closed")` arm, but the enum is `#[non_exhaustive]` (d2b-contracts-provider/src/v3/provider.rs:2759), so any future contract variant becomes a runtime panic in every fixture-based test suite | fix: return `Result` and map unknown methods to `WireInvalid`, updating the two call sites (fixture.rs:190 and the `ProviderAgentService` impl) | [packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192] | actionable | lane/d2b-provider-toolkit-p2.md +- `RS-0511` | medium | `d2b-provider-toolkit` | every fake port swallows the recorder-capacity error with `let _ = self.recorder.record(...)`, so `FakePortError::RecorderFull` is never constructed (dead variant in the public closed set `ALL`) and a test exceeding `MAX_RECORDED_CALLS` silently truncates its record, contradicting the variant's own doc "the call is refused rather than dropped silently" | fix: map `ProviderToolkitError::CapacityOutOfRange` to `FakePortError::RecorderFull` and return it from the fake methods (or delete the variant and its `ALL` slot) | [packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/src/testing/fakes.rs:289-291, packages/d2b-provider-toolkit/src/testing/fakes.rs:337-339, packages/d2b-provider-toolkit/src/testing/fakes.rs:391-393] | actionable | lane/d2b-provider-toolkit-p2.md +- `RS-0509` | low | `d2b-provider-toolkit` | `key_ref` panics via `expect("manager keys carry canonical resource references")` on a `ResourceKey` whose fields are pub and unvalidated (`ResourceKey::new` accepts any strings), so the pub helper can panic on a non-canonical key a caller constructs | fix: return `Result` (map to `InvalidResource`) like the sibling `owner_ref`/`resource_uid` helpers | [packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtime/src/spec_store.rs:60-63] | actionable | lane/d2b-provider-toolkit-p2.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0512` | medium | `d2b-provider-transport-azure-relay` | `From` and `From` for `GatewayGuestZoneLinkError` discard the source entirely (`fn from(_: ...)`), collapsing every credential failure (Unreadable, Malformed, Expired, BadMode, BadOwner, Crypto) into one generic variant with no chain, so callers cannot distinguish or log the cause | fix: carry the source (e.g. `CredentialUnavailable { source: CredentialError }` with `#[source]`-style chaining, or keep the collapse but retain `source()`), matching the err skill's context-survival rule | [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69-78, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:181-187] | actionable | lane/d2b-provider-transport-azure-relay.md +- `RS-0513` | medium | `d2b-provider-transport-azure-relay` | clock-before-epoch failures are silently swallowed with `unwrap_or(0)` in `system_now_unix()` (guest_zone_link) and `system_now_unix_ms()` (guest_credential), and a zero `now` makes `load_sealed_inner`'s expiry check fail open (`now >= not_after` is false for any positive `not_after`), accepting an expired envelope - while auth.rs returns `RelayError::Clock` and relay_transport.rs maps the same condition to `CredentialExpired` | fix: propagate a clock error (or reject the load) instead of substituting 0, mirroring `RelayError::Clock` | [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:665-669, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:178-183] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-user`** + +- `RS-0514` | low | `d2b-provider-user` | `UserDriverError`'s `Display` hand-copies the three `system-core-*` failure codes that `d2b-contracts` already registers as `FailureKind` constants, so the strings can silently drift from the registry and its rendered reference | fix: write `self.kind.failure_kind().code()` in the `Display` impl (driver.rs:118-124) instead of the per-arm string match, keeping the registry the single source | [packages/d2b-provider-user/src/driver.rs:118-124, packages/d2b-contracts/src/failure_kinds.rs:342-363] | actionable | lane/d2b-provider-user.md + +**`d2b-provider-volume-binding`** + +- `RS-0515` | medium | `d2b-provider-volume-binding` | BindingDriver re-parses the zone as a BoundedToken with a per-pass .expect (driver.rs:426-427) because BindingDriverArgs.zone: String (driver.rs:344) can represent a non-bounded zone, and the sole production caller already holds a BoundedToken (d2bd resource_plane_v3.rs:2954 inputs.zone.as_str().to_owned()), so the invariant is re-checked on every validate/reconcile/recover/delete pass where a parse-at-the-boundary would check it once | fix: store BoundedToken on BindingDriverArgs/BindingDriver (parse or construct once; ResourceKey::new(&self.zone.as_str(), ...), socket_identity(&self.zone)), deleting zone_bounded and its expect | [packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-binding/src/driver.rs:426-427, packages/d2bd/src/resource_plane_v3.rs:2954] | actionable | lane/d2b-provider-volume-binding.md + +**`d2b-provider-wayland-policy`** + +- `RS-0516` | high | `d2b-provider-wayland-policy` | Panic reachable from caller input at the family engine's public boundary: `InteractionDriver::new` parses-and-expects `InteractionDriverArgs.zone: String` (pub field on pub struct with no validating constructor),and `key_ref` parses-and-expects a `ResourceKey` whose `new` accepts any strings; both invariants claimed in expect messages are not enforced by the types | fix: parse once at the args boundary (change `args.zone` to a parsed `ZoneId`, or make `InteractionDriver::new` return `Result<_, InteractionDriverError>`) and make `key_ref` return `Result` (map to `SpecInvalid`) or enforce name canonicality at `ResourceKey::new` in d2b-resource-runtime | [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-wayland-policy/src/interaction.rs:488, packages/d2b-provider-wayland-policy/src/interaction.rs:836-838, packages/d2b-resource-runtime/src/spec_store.rs:60-63] | actionable | lane/d2b-provider-wayland-policy.md + +**`d2b-provider-wayland-session`** + +- `RS-0517` | low | `d2b-provider-wayland-session` | `SessionChildSource::display_children` maps any `WorkerEffectError` from the display crate's child derivation to `InteractionEffectError::InvalidResource`, dropping the cause, and the crate has no tracing, so the derivation failure detail is invisible at the boundary | fix: log the source before mapping (add a tracing dependency) or preserve the specific variant | [packages/d2b-provider-wayland-session/src/wayland_session.rs:73] | actionable | lane/tail-5.md + +**`d2b-resource-api`** + +- `RS-0518` | low | `d2b-resource-api` | an empty batch is rejected with the reason "batch mutation count exceeds its bound", misstating the failure (empty is not over-bound) | fix: use a distinct reason such as "batch mutation count is zero" for the empty case and keep the bound reason for the `MAX_BATCH_MUTATIONS` check | [service.rs:867-868] | actionable | lane/d2b-resource-api-p1.md + +**`d2b-resource-client`** + +- `RS-0519` | low | `d2b-resource-client` | three reflexive `Mutex::lock().unwrap()` sites in the cancellation waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) handle poisoning by panic instead of an explicit choice | fix: use `expect("waker registry lock is not poisoned: no user code runs under it")` or `into_inner()` with the same written reason | [packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309, packages/d2b-resource-client/src/call.rs:335] | actionable | lane/d2b-resource-client.md + +**`d2b-resource-runtime`** + +- `RS-0520` | medium | `d2b-resource-runtime` | `ResourceError::ManagerRpc(String)` collapses caller-distinct failures into one stringly variant: transport failures ("manager channel closed", "manager dropped the request", retryable) and semantic refusals ("owner not known", "refusing re-parent", zone mismatch, permanent) are indistinguishable without string-matching, and drivers that classify a context error (e.g. `drain_owned_children` maps every non-`ChildrenDraining` error to retryable) cannot tell a dead manager from a permanent refusal | fix: split into `ManagerUnavailable` (transport) and `ManagerRejected { reason }` (semantic), or carry a `ManagerRpcKind` enum the variant stores | [packages/d2b-resource-runtime/src/error.rs:773, packages/d2b-resource-runtime/src/manager.rs:1426, packages/d2b-resource-runtime/src/metadata.rs:200] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0521` | medium | `d2b-resource-runtime` | row_from silently substitutes [0; 16] when a stored uid or owner_uid column is not exactly 16 bytes, giving a corrupt row a zero identity that collides with every other zero-uid row | fix: return a typed error (a new SpecStoreError::CorruptRow { zone, type_name, name } variant) instead of try_into().unwrap_or([0; 16]) | [packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spec_store.rs:555] | actionable | lane/d2b-resource-runtime-p2.md + +**`d2b-session`** + +- `RS-0522` | medium | `d2b-session` | OwnedTransportHandle panics via expect on descriptor, into_owned_transport, and close after the handle is consumed, because the Option> keeps the consumed state representable | fix: return Option or Result from into_owned_transport and close, or split the handle into a typestate so double-consume does not compile | [transport.rs:170, transport.rs:178, transport.rs:185, transport.rs:173] | actionable | lane/d2b-session-p2.md +- `RS-0523` | medium | `d2b-session` | SessionClientBridgeError's Display prints a fixed label and the Error impl has no source(), so the inner SessionError code is lost from the chain when the bridge logs it | fix: implement Error::source() returning Some(&SessionError) for the Session variant, and/or include the code in Display | [client.rs:216, client.rs:224, client.rs:237] | actionable | lane/d2b-session-p2.md + +**`d2b-telemetry`** + +- `RS-0524` | medium | `d2b-telemetry` | `BoundedEmitter::new_with_limits` reports invalid constructor arguments as `EmitterError::StatePoisoned`, conflating a permanent programming error with transient lock poisoning | fix: add a dedicated variant (e.g. `InvalidLimits`) and return it from the zero-capacity / zero-frame / zero-age / zero-retry guard clauses, keeping `StatePoisoned` for the `lock().map_err` sites | [packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93] | actionable | lane/d2b-telemetry.md merged: d2b-telemetry#4 +- `RS-0525` | low | `d2b-telemetry` | `SessionMetricsError::Encode` is never constructed; the `io::Error` from `encode_frame` is folded into `EmitterError::MetricPolicy(DescriptorMalformed)` inside `emit_metric`, so the variant and its Display arm are dead surface | fix: delete the `Encode(std::io::Error)` variant and the `"session-metric-encode-failed"` Display arm | [packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_metrics_sink.rs:82] | actionable | lane/d2b-telemetry.md + +**`d2b-unsafe-local-helper`** + +- `RS-0526` | medium | `d2b-unsafe-local-helper` | await_scope_identity maps every `Ok(_)` whose state is not starting/active (scope exists but the launched process already exited, stopping, or degraded) to ScopeError::IdentityMismatch, so an operational "process died during startup" is reported and handled as a security identity failure; the caller then aborts the supervisor and surfaces ScopeIdentityMismatch to the daemon | fix: return a distinct error for an early-exit scope (e.g. ScopeError::CreateFailed or a new EarlyExit variant), keep IdentityMismatch for identity-check failures only, and map it to RuntimeError::ScopeCreateFailed | [packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/systemd.rs:338-346] | actionable | lane/d2b-unsafe-local-helper.md + +**`d2bd`** + +- `RS-0531` | medium | `d2bd` | `record_workload_availability_metrics` panics via `.expect("bounded workload availability tuple")` when the metric key set drifts from the label fns: `WORKLOAD_AVAILABILITY_STATES` (composition.rs:8097) + `WORKLOAD_PROVIDERS` (composition.rs:8090) live here, while `workload_availability_label`/`workload_provider_label` live in d2bd-runtime's workload_dispatch.rs, so adding a `WorkloadAvailability` variant compiles cleanly (the exhaustive match only forces the label fn update) but makes the daemon panic on the next workload List/Status | fix: seed the `counts` map from a single source of truth exported next to the label fns (e.g. `workload_availability_states()`/`workload_provider_labels()`), or replace the expect with a graceful `entry()`/skip so an unknown label degrades to a missing gauge instead of a panic | [packages/d2bd/src/composition.rs:8140, packages/d2bd-runtime/src/workload_dispatch.rs:104, packages/d2bd/src/composition.rs:8097] | actionable | lane/d2bd-p4.md +- `RS-0532` | medium | `d2bd` | `reap_finished_handlers` joins finished listener handler tasks with `let _ = handlers.swap_remove(index)..await;`, silently discarding the `JoinError`, so a panicked handler (whose `handler_active.fetch_sub` decrement sits after the panic-capable body( neither logs and leaks its bounded 64-slot admission reservation( | fix: log the `JoinError` with `tracing::warn!` at the reap site,and wrap the spawn body so the `fetch_sub` decrement runs in a panic-safe guard, not after the admit body | [packages/d2bd/src/interaction_composition.rs:5365, packages/d2bd/src/interaction_composition.rs:5310] | actionable | lane/d2bd-p5.md +- `RS-0533` | medium | `d2bd` | `PlaneError` carries five `String` variants (`FoundationSeed`, `ManagerSpawn`, `Authority`, `Target`, `Bundle`) that wrap the inner error with `error.to_string()`/`format!` at every production site, dropping the source chain the enum's `#[from]` variants already preserve for `SpecStore`/`ProviderRegistration`/`ManagerRpc` - callers of `ResourcePlaneV3::prepare` cannot distinguish a refused spec-store open from a create failure without string-matching | fix: give each String variant a typed payload or `#[source]` (e.g. `PlaneError::Authority(#[from] d2b_core::loader_worker::Error)` where `SpecStore::open` already yields `SpecStoreError` through `#[from]`, and keep the stage word in the `Display` message, not the variant), deleting the `to_string()` wraps at the cited sites | [packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/resource_plane_v3.rs:3016, packages/d2bd/src/resource_plane_v3.rs:3025, packages/d2bd/src/resource_plane_v3.rs:3346] | actionable | lane/d2bd-p6.md +- `RS-0535` | medium | `d2bd` | a durable service row that fails to (re)spawn is silently dropped: `let _ = state.spawn_service_actor)...)` in both the supervisor's restart-recovery loop and `supervise_exit` leaves a declared effect service unhosted with no trace, contradicting the module's own respawn promise (a crashed or killed service actor is respawned from its durable row; never leaves a service unhosted) | fix: log `tracing::warn!` with service/zone/error on spawn failure at both sites, keeping the non-fatal recovery semantics | [packages/d2bd/src/effect_service_actors.rs:551, packages/d2bd/src/effect_service_actors.rs:610] | actionable | lane/d2bd-p7.md +- `RS-0527` | medium | `d2bd` | `credential_dependency_row` swallows a manager RPC failure into absence (`.ok().flatten()`), contradicting the module's own contract that "a manager RPC failure is an error - never reported as absence" (bridge_manager_row doc, 299-305); the caller `ProductionCredentialRuntime` facts closure (4511) then reports no dependency facts, so a transient manager failure silently degrades credential readiness and revocation decisions | fix: propagate the error (log it with the error field at minimum; change `credential_dependency_facts`/`CredentialRuntime::dependency_facts` to `Result>` so the driver can retry) | [packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511] | actionable | lane/d2bd-p1.md +- `RS-0529` | medium | `d2bd` | dispatch_audit maps any unrecognized severity string from the wire to `TypedError::InternalIo { context: "audit filter", detail: "severity-invalid" }`, surfacing caller input errors as internal I/O failures instead of a request-validation refusal | fix: return a wire-input refusal kind (e.g. a TypedError::Wire* invalid-request variant or the invalid_request_response frame used by mutating dispatch) for the `Some(_) =>` arm | [packages/d2bd/src/composition.rs:22793-22797, packages/d2b-contracts-control/src/public_wire.rs:2453] | actionable | lane/d2bd-p3.md +- `RS-0530` | medium | `d2bd` | ActivationLockGuard::drop silently swallows `finish_activation` failure (`let _ =`), so a coordinator refusal to close an activation is never even logged and the wedge is only discoverable via the deferred activation-pending marker | fix: log the error with tracing::warn! (boundary has no Result channel; the marker alone is not enough) | [packages/d2bd/src/composition.rs:20185-20190] | actionable | lane/d2bd-p3.md +- `RS-0537` | medium | `d2bd` | user-input audio failures are flattened into `TypedError::InternalIo { context, detail }` strings on the mutation paths (VM absent, audio not enabled) in `dispatch_audio_set_volume` / `dispatch_audio_mute`, while the status path reports the same classes as structured `AudioVmError` + `AudioErrorKind::VmNotFound` / `AudioNotEnabled`; a caller of set-volume/mute cannot distinguish VM-not-found from an internal I/O failure except by string-matching the detail | fix: map the mutation paths onto the same structured kinds (extend `TypedError` with the audio kinds used by both paths); this changes the daemon-API wire error surface, so it is needs-contract | [packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, packages/d2bd/src/audio_dispatch.rs:417-438] | needs-contract | lane/d2bd-p8.md +- `RS-0534` | low | `d2bd` | `ConstructionInputs::production` swallows the `attach_process_providers` Result at the compose-once fallback, so a `StateUnavailable` collision (or a future attach failure) silently leaves whichever instance won in the shared slot, and the plane keeps composing with its own instance either way | fix: `state.provider_runtime.attach_process_providers(Arc::clone(&providers)).map_err(|error| PlaneError::Authority(error.to_string()))?` (or a dedicated variant), matching the site's other rejections | [packages/d2bd/src/resource_plane_v3.rs:1956] | actionable | lane/d2bd-p6.md +- `RS-0536` | low | `d2bd` | the 0700 enforcement on a serving worker's socket parent is silently swallowed with `let _ =`; the sibling `create_dir_all` failure just above is a hard error, so a failed `set_permissions` leaves the launched socket dir at default umask perms with no diagnostic | fix: replace `let _ = tokio::fs::set_permissions)...)` with a `tracing::warn!` on Err, mirroring the pidfd snapshot warn at ppr:804-809 | [packages/d2bd/src/process_provider_runtime.rs:3436] | actionable | lane/d2bd-p7.md +- `RS-0528` | low | `d2bd` | `detail: err.to_string()` collapses the source error into a String when building TypedError variants, losing the error chain for diagnostics | fix: carry the source in the variant (e.g. `InternalBrokerUnavailable { path, #[source] source: serde_json::Error }` with the detail rendered in Display) so the chain survives to the logging boundary | [packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d2bd/src/composition.rs:15243, packages/d2bd/src/composition.rs:15247] | actionable | lane/d2bd-p2.md + +**`d2bd-runtime`** + +- `RS-0538` | high | `d2bd-runtime` | default_audit_join_context panics with `.expect("canonical broker zone digest")` on a wire-supplied digest - a malformed request from the broker client crashes the daemon instead of returning a refusal | fix: propagate the parse failure (e.g. `CanonicalAuditDigest::parse(zone_id).ok()?;` or map into TypedError::WireInvalidFrame/InternalConfig),and only attend None when digest missing route review-pass | [broker_transport.rs:63, broker_transport.rs:65] | actionable | lane/d2bd-runtime-p1.md +- `RS-0539` | medium | `d2bd-runtime` | `map_parse_error` (wire.rs:529-536) classifies `serde_json::Error` kinds by substring-matching the Display text ("unknown field", "interface name"), so the wire-visible kinds `wire-unknown-field`/`wire-if-name-invalid` flip silently if serde_json rewords a message | fix: classify structurally instead of lexically - e.g. parse the request envelope against a `#[serde(deny_unknown_fields)]`-tagged shape so "extra field" arrives as a discrete rejection (the manual authStatus/usbipProbe arms already do this), and route the raw serde error through `error.classify()` plus line/column for the generic frame kind | [wire.rs:529-536] | actionable | lane/d2bd-runtime-p2.md +- `RS-0540` | low | `d2bd-runtime` | `spawn_session_worker` panics at `std::thread::Builder::spawn)...).expect("spawn exec session worker thread")` in library code on an environmental failure (thread exhaustion/ENOMEM) with a caller-visible alternative | fix: return `std::io::Result>` (or map to `TypedError`) and have the two test call sites adjust | [packages/d2bd-runtime/src/exec_session.rs:939] | actionable | lane/d2bd-runtime-p3.md +- `RS-0541` | low | `d2bd-runtime` | `impl Default for ConsoleClientHandle` panics via `expect("console handle entropy unavailable")` when entropy fails, and nothing in the workspace calls `ConsoleClientHandle::default()` | fix: delete the Default impl (the type already has a fallible `new()` used at attach) | [packages/d2bd-runtime/src/console_session.rs:132] | actionable | lane/d2bd-runtime-p4.md +- `RS-0542` | low | `d2bd-runtime` | `FilesystemReader` reports failures as `Result<..., String>`, so `compute_restart_status` cannot distinguish "file missing" from "file unreadable" without string inspection and the detail is only embeddable in a banner | fix: introduce a small `VersionFileReadError` enum (e.g. `Missing` vs `Unreadable(String)`) returned by both trait methods | [packages/d2bd-runtime/src/daemon_version.rs:77, packages/d2bd-runtime/src/daemon_version.rs:85] | actionable | lane/d2bd-runtime-p4.md + +**`xtask`** + +- `RS-0543` | medium | `xtask` | `RecoveryError::Json` conflates three failure modes: an unreadable attestation file (`read_attestation` maps open/read errors to Json), canonical-JSON rejection, and a typed-parse failure whose serde detail (missing field, line, column) is discarded, so an operator debugging a rejected attestation sees only "recovery attestation shape rejected" with no way to tell a missing file from a malformed payload | fix: add a `RecoveryError::Read` variant for the fs errors and carry the bounded serde error text (field names and positions only, never payload values, keeping the enum's redaction contract) in a `Json(String)` variant, propagating through the existing `From for DeliveryError` | [packages/xtask/src/delivery/recovery.rs:384, packages/xtask/src/delivery/recovery.rs:1610, packages/xtask/src/delivery/recovery.rs:1715, packages/xtask/src/delivery/recovery.rs:1719] | actionable | lane/xtask-p3.md + +### `serde` + +Serde boundary: try_from validation, rename_all conventions, optionality semantics, enum representations, deny_unknown_fields decisions. + +**`X3-cross-crate-duplication`** + +- `RS-0961` | medium | `X3-cross-crate-duplication` | Parallel serde shims: contract/provider crates hand-write the identical Wire-struct admission shape (private `#[derive(Deserialize)]` Wire with deny_unknown_fields, then new()/TryFrom with validation) in 24+ impls where the in-tree `parsed_deserialize!` macro exists | fix: consolidate behind `parsed_deserialize!` (d2b-contracts-resource/src/v3/execution_policy.rs:33, re-exported at :63) or `#[serde(try_from = "...")]` with the raw Wire shape, keeping every admission gate; this deduplicates boilerplate and is distinct from the refused gate-removal class (over-engineering-audit-record.md rows 25/33 refused replacing gates with derives) | [packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs:101, packages/d2b-contracts-zone-session/src/v3/zone.rs:79, packages/d2b-contracts-zone-session/src/v3/role_binding.rs:192] | actionable | lane/X3-cross-crate-duplication.md + +**`d2b-broker`** + +- `RS-0545` | low | `d2b-broker` | `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in `load()` (state_cells.rs:924-931), while the in-process `CellOutcome` enum already exists | fix: derive Serialize/Deserialize on a wire enum (`#[serde(rename_all = "lowercase")]` over `CellOutcome` or a dedicated `DurableOutcome`) and delete the string match; the serialized shapes "unknown"/"completed" stay identical, so no DURABLE_VERSION bump is needed | [packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924] | actionable | lane/d2b-broker-p3.md + +**`d2b-broker-composition`** + +- `RS-0544` | low | `d2b-broker-composition` | `run_cargo_metadata` parses cargo's output into `serde_json::Value` and every consumer re-walks it with repeated `.get("packages")`/`and_then(as_array)`/`as_str` chains (`dependency_tree`, `package_name_of_id`, `is_proc_macro`), pushing the parse out of the boundary | fix: derive `Deserialize` on minimal `CargoMetadata`/`Package`/`ResolveNode` shapes and parse once in `run_cargo_metadata`, replacing the Value-walking chains with field access | [packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composition/src/dependency_surface.rs:318, packages/d2b-broker-composition/src/dependency_surface.rs:365, packages/d2b-broker-composition/src/dependency_surface.rs:380] | actionable | lane/d2b-broker-composition.md + +**`d2b-contracts`** + +- `RS-0546` | medium | `d2b-contracts` | `AuditExportEntry` carries `record: Option` andi `error: Option` where the doc (audit_wire.rs:27) promises exactly one is always populated,so both-None is a wire-accepted illegal state (the broker's own writers d2b-broker/src/audit.rs:1730-1732 etc always set one,but a literal or foreign producer can emit neither) | fix: replace the pair with an enum payload representation (e.g. `#[serde(tag = "type")] enum AuditExportEntryPayload { Record { record: Value }, Error { error: AuditExportErrorCode } }` or an admission-gate enforcing exactly-one at decode),preserving or explicitly changing the wire shape | [packages/d2b-contracts/src/audit_wire.rs:27-36] | needs-contract | lane/d2b-contracts.md + +**`d2b-contracts-broker`** + +- `RS-0547` | medium | `d2b-contracts-broker` | `OpenUnitPidfdRequest` and `StopUnitRequest` combine `#[serde(flatten)] pub unit: UnitRequest` with `deny_unknown_fields` on the containing struct, and serde ignores `deny_unknown_fields` on any type using flatten, so unknown fields in these two wire requests are silently accepted instead of refused | fix: drop the flatten (duplicate the UnitRequest fields or deserialize into a tagged wrapper) or accept-and-validate unknown fields explicitly; the wire admission change needs contract review | [packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/src/broker_wire.rs:1783-1834] | needs-contract | lane/d2b-contracts-broker.md + +**`d2b-contracts-control`** + +- `RS-0548` | medium | `d2b-contracts-control` | three hand-written `Deserialize` impls plus private `*Wire` shadow structs (HelperSnapshot, HelperLaunchRequest, AuditResponse) re-implement exactly what `#[serde(try_from = "...")]` generates: deserialize raw, validate, map failure to a deserialization error | fix: derive `Deserialize` via `#[serde(try_from = "HelperSnapshotWire")]` (and the two siblings), keeping `deny_unknown_fields` on the wire structs and deleting the manual impls | [unsafe_local_wire.rs:118, unsafe_local_wire.rs:176, public_wire.rs:2228] | actionable | lane/d2b-contracts-control.md + +**`d2b-contracts-provider`** + +- `RS-0549` | low | `d2b-contracts-provider` | `parse_raw_frame` maps every serde failure to `Malformed`, so a top-level unknown field (rejected by `deny_unknown_fields` on `TelemetryFrame`) reports `Malformed` while the same unknown key nested inside `value` reports `UnknownField` from validation - the variant exists but is unreachable for the shape that names it | fix: `map_err(|error| match error.classify() { serde_json::error::Category::UnknownField => TelemetryFrameError::UnknownField, _ => TelemetryFrameError::Malformed })` (serde_json 1.0.151 in Cargo.lock provides `classify`) | [packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:114] | actionable | lane/d2b-contracts-provider-p2.md + +**`d2b-contracts-resource`** + +- `RS-0550` | medium | `d2b-contracts-resource` | `ResourceError` derives Deserialize (error.rs:175-176), bypassing the invariants `ResourceError::new` enforces (current_revision only on ResourceConflict/AuthorizationDenied/RevisionExpired, retry_after_ms only with RetryClass::AfterDelay), so a wire error carrying an inconsistent combination deserializes into an illegal state that the retry decision logic then reads | fix: hand-write `Deserialize` for `ResourceError` through `Self::new`, matching every sibling wire type in this crate | [packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v3/error.rs:177] | actionable | lane/d2b-contracts-resource-p1.md +- `RS-0551` | medium | `d2b-contracts-resource` | `PayloadSchema` derives Deserialize (payload_schema.rs:30-32), bypassing `PayloadSchema::parse`'s closed-object and writeOnly validation, and `CommandSpec::deserialize` (d2b-provider-command/src/command.rs:248-266) feeds the wire value straight in, so a wire Command carrying an open schema or a writeOnly property with a default deserializes as valid | fix: hand-write `Deserialize` for `PayloadSchema` through `Self::parse` (the wire shape is unchanged; producers already use parse) | [packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resource/src/v3/payload_schema.rs:36] | actionable | lane/d2b-contracts-resource-p1.md + +**`d2b-contracts-zone-session`** + +- `RS-0552` | medium | `d2b-contracts-zone-session` | seventeen hand-written Deserialize impls repeat the identical Wire-struct shape (local #[derive(Deserialize)] Wire with deny_unknown_fields, then new() plus map_err(serde::de::Error::custom)) | fix: consolidate behind a shared macro in the style of parsed_deserialize! at d2b_contracts_resource::v3::execution_policy, or #[serde(try_from = "Wire")] with TryFrom, keeping each new() gate as the admission check | [zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932] | actionable | lane/d2b-contracts-zone-session-p2.md + +**`d2b-core`** + +- `RS-0556` | low | `d2b-core` | `StorageLifecycleIssue` struct variants carry per-field `#[serde(rename = "bundleVersion")]`-style renames instead of the house `#[serde(rename_all = "camelCase")]` per variant, scattering the wire convention across fields | fix: add `#[serde(rename_all = "camelCase")]` to each struct variant and drop the per-field rename attributes; the serialized shape is unchanged (pinned by the storage_lifecycle tests) | [packages/d2b-core/src/storage_lifecycle.rs:49, packages/d2b-core/src/storage_lifecycle.rs:61, packages/d2b-core/src/storage_lifecycle.rs:70] | actionable | lane/d2b-core-p2.md +- `RS-0554` | low | `d2b-core` | ZoneNativeIndexDocument derives Deserialize with `rename_all = "camelCase"` but no `deny_unknown_fields`, while the three sibling index types (ZoneNativeBundleIndex, ZoneNativeBundleRef, ZoneNativeTopology) all deny, leaving the top-level index admission inconsistent | fix: add `deny_unknown_fields` to ZoneNativeIndexDocument and keep the Nix emitter (nixos-modules/bundle.nix) in sync so no emitted key is rejected | [packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175, packages/d2b-core/src/bundle_resolver.rs:202, packages/d2b-core/src/bundle_resolver.rs:216] | needs-contract | lane/d2b-core-p1.md +- `RS-0555` | low | `d2b-core` | `#[serde(default)]` on the four Option fields of ZoneNativeBundleIndex (storage_path, site_path, host_path, realm_workloads_launcher_v2_path) is redundant: a missing Option field already deserializes to None, so the attribute adds nothing and reads as a convention violation of the sibling fields | fix: drop the four attributes | [packages/d2b-core/src/bundle_resolver.rs:183, packages/d2b-core/src/bundle_resolver.rs:187, packages/d2b-core/src/bundle_resolver.rs:194, packages/d2b-core/src/bundle_resolver.rs:196] | actionable | lane/d2b-core-p1.md + +**`d2b-core-controller`** + +- `RS-0553` | medium | `d2b-core-controller` | the assignment evidence codec is hand-rolled JSON: encode_assignment/decode_assignment/require_exact_keys/encode_bounded_json/decode_string_set walk serde_json::Value with per-field get() chains and exact-key lists where derive(Deserialize) with deny_unknown_fields plus the existing canonical-ordering checks would give the same admission; refusal-ledger row C3 names this codec and it is still present | fix: replace the Value-walking encode/decode with typed serde structs (rename_all = "camelCase", deny_unknown_fields) preserving the wire shape pinned by the transport tests (exact keys, version 1, sorted verb arrays, canonical bytes, bounded size), and replace the json!-literal payload builder in materialize_child_create_payload with a typed envelope builder | [packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controller/src/controller_assignment.rs:735, packages/d2b-core-controller/src/controller_assignment.rs:891, packages/d2b-core-controller/src/controller_assignment.rs:901] | actionable | lane/d2b-core-controller-p1.md + +**`d2b-host`** + +- `RS-0557` | low | `d2b-host` | `NftBatch` derives `Deserialize` but its `&'static str` fields pin the generated impl to `'de: 'static` (serde's `impl<'de: 'a, 'a> Deserialize<'de> for &'a str`), so the type cannot be deserialized from any runtime input; the derive is dead and misleads (the broker only ever `NftBatch::parse`s text or constructs batches) | fix: drop `Deserialize` from the `NftBatch` derive (keep `Serialize`), or make `table_family`/`table_name` owned `String` if round-trip is ever intended | [packages/d2b-host/src/nftables.rs:229] | actionable | lane/d2b-host.md + +**`d2b-process-conformance`** + +- `RS-0558` | low | `d2b-process-conformance` | `CompiledDigests` serialization is hand-written (`impl Serialize` emitting 7 named fields) where a derive with `rename_all = "camelCase"` plus `#[serde(rename = "fdTable")]` on `fd_table` produces the identical wire shape and stays in sync with the struct | fix: add `#[derive(serde::Serialize)]`/`#[serde(rename_all = "camelCase")]` on `CompiledDigests` (ticket.rs:105) and delete the manual impl at status.rs:125-137 | [packages/d2b-process-conformance/src/status.rs:125, packages/d2b-process-conformance/src/ticket.rs:105] | actionable | lane/d2b-process-conformance.md +- `RS-0559` | low | `d2b-process-conformance` | `ProcessOutcome` derives `Deserialize` on `pub` fields but permits illegal `(exit_class, exit_code)` combinations (e.g. `Crash` with `Some(300)`), so a decoded terminal message is invalid until each consumer re-validates (`ProcessOutcome::validate`, then again inside `from_parent` and `relay`); the skill's boundary rule says the read should fail, not first use | fix: deserialize into a raw shape with `#[serde(try_from = "RawOutcome")]` (or a validating custom `Deserialize`) so illegal combinations become `InvalidTerminalResult` at the boundary, then delete the per-use re-validations or keep only one | [packages/d2b-process-conformance/src/terminal.rs:39, packages/d2b-process-conformance/src/terminal.rs:94, packages/d2b-process-conformance/src/terminal.rs:177] | actionable | lane/d2b-process-conformance.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0560` | low | `d2b-provider-clipboard-wayland` | AuditEvent.mime_type carries `serialize_with = "serialize_bounded_mime"` but no deserialize_with, so the round trip is asymmetric: serialization truncates long MIME values at 64 bytes while deserialization accepts unbounded values, and the type still derives Deserialize | fix: add a matching deserialize_with (or drop Deserialize from AuditEvent if it is never read back) | [packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:43-49] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-command`** + +- `RS-0561` | medium | `d2b-provider-command` | the emitted JsonSchema for `CommandExec` (`pattern: "^/[^\\u0000]*$"`) and `CommandArgvSlot` (no pattern) is weaker than the parse admission (rejects control chars/empty/malformed braces/invalid placeholder names), so a value satisfying the published schema can be refused at serde deserialization | fix: tighten the `CommandExec` pattern to exclude `char::is_control` code points and add a `CommandArgvSlot` pattern (or an explicit `format`/`pattern` encoding the whole-slot brace rule), then regenerate the committed schema | [packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/command.rs:133-152, docs/reference/schemas/v3/core.d2bus.org_Command.schema.json:21] | needs-contract | lane/tail-2.md + +**`d2b-provider-device-gpu`** + +- `RS-0562` | medium | `d2b-provider-device-gpu` | `GpuArgvInput` admits unknown JSON fields while its sibling `VideoArgvInput` denies them (and a test pins the rejection), an inconsistent admission policy for two daemon-side wire inputs | fix: add `deny_unknown_fields` to `GpuArgvInput` (and `GpuParams`/`GpuDisplayConfig` for full nested coverage), mirroring video_argv.rs:112; the only in-tree producer d2bd/src/process_provider_runtime.rs:3707 builds a Rust literal, so no producer sends unknown fields today | [packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/video_argv.rs:112, packages/d2b-provider-device-gpu/src/video_argv.rs:244] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-display-wayland`** + +- `RS-0563` | medium | `d2b-provider-display-wayland` | the bridge receive path detects the clipd refresh frame by scanning raw bytes for the substring `"type":"refresh_selection"` (filter.rs:817-824) instead of deserializing the typed frame the way the send side serializes it (bridge.rs:321-365); the producer emits a hand-written byte literal (d2b-clipd.rs:1690), so any whitespace or key-order change in the shared JSON shape silently disables clipboard refresh with no error | fix: define a `#[serde(tag = "type", rename_all = "snake_case")]` inbound frame enum mirroring `bridge_frame`'s `Frame`, deserialize each newline frame with `serde_json::from_str`, and match the `RefreshSelection` variant; add a test feeding `{"type":"refresh_selection"}` through the drain path | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:819] | actionable | lane/d2b-provider-display-wayland-p1.md +- `RS-0564` | low | `d2b-provider-display-wayland` | `#[serde(try_from = "WaylandSessionSpecWire")]` (spec.rs:233) is inert: WaylandSessionSpec derives only Serialize, and Deserialize is hand-written (spec.rs:263-270) to do exactly what the derive plus try_from would generate | fix: delete the inert attribute (keep rename_all for the Serialize side), or derive Deserialize with try_from and delete the manual impl; pick one mechanism | [src/spec.rs:230, src/spec.rs:233, src/spec.rs:263] | actionable | lane/d2b-provider-display-wayland-p2.md + +**`d2b-provider-endpoint`** + +- `RS-0565` | medium | `d2b-provider-endpoint` | `EndpointAttachmentPolicy`'s derived `Deserialize` admits illegal state (`supported=false, max_attachments>0`,andthe converse), while its sibling `EndpointConsumerPolicy` routes `Deserialize` through `Self::new` as an admission gate,so a standalone deserializer yields a shape the constructor refuses | fix: route `EndpointAttachmentPolicy::deserialize` through `Self::new` (try_from or the sibling hand-written pattern at endpoint.rs:197-216) | [packages/d2b-provider-endpoint/src/endpoint.rs:112-120, packages/d2b-provider-endpoint/src/endpoint.rs:125-131, packages/d2b-provider-endpoint/src/endpoint.rs:197-216, packages/d2b-provider-endpoint/src/endpoint.rs:377-381] | actionable | lane/d2b-provider-endpoint.md + +**`d2b-provider-network-local`** + +- `RS-0566` | medium | `d2b-provider-network-local` | the stored-spec parse maps serde failure to `()` unit, dropping the deserialization reason before the toolkit's SpecInvalid terminal | fix: log the serde error (add a tracing::debug/warn at driver.rs:289 before the map)) or return `Result` and let the driver surface the reason; do not touch the pinned SharedProviderDeclarationError enum | [src/driver.rs:282-289, src/driver.rs:190] | actionable | lane/d2b-provider-network-local.md +- `RS-0567` | low | `d2b-provider-network-local` | provenance serialization failures are silently `.ok()`-swallowed into a missing wire field at four payload builders, while the sibling update-hosts path propagates with map_err | fix: match broker.rs:1368: `.map(serde_json::to_value).transpose().map_err)...)` at all four sites (operations.rs maps to OperationFailure::with_detail(KERNEL_REFUSED, ...)) | [src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429] | actionable | lane/d2b-provider-network-local.md + +**`d2b-provider-supervisor`** + +- `RS-0568` | medium | `d2b-provider-supervisor` | `take_controller_bootstrap` is the one wire leg not using a typed d2b-contracts-broker request/response: it hand-builds the payload with `serde_json::json!` (camelCase string keys), reads the reply via `.get("taken")`/`as_bool` with a silent `unwrap_or(false)` (a malformed reply reads as "not taken" -> `Ok(None)`), and reuses hard-coded fd index 0 | fix: add a typed `TakeControllerBootstrapRequest/Response` to the broker wire contract (the operation row currently carries `wire_variant: None`) and parse/reply through it like every sibling leg | [packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generated/broker_operation_catalog.rs:1289] | needs-contract | lane/d2b-provider-supervisor.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0569` | medium | `d2b-provider-transport-azure-relay` | `RelayTransportSettings` derives `Deserialize` without `try_from`, so `serde_json::from_slice::` at d2bd/src/composition.rs:843 accepts identifiers that `new()`/`validate()` reject - including the secret-shape exclusion (`SharedAccessSignature`) that exists only in Rust and not in the pinned schema `docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json` (whose patterns admit lowercase letters) | fix: add `#[serde(try_from = "...")]` reusing `validate()`, and first encode the secret-shape exclusion in the schema so schema and Rust agree | [packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:31-41, packages/d2bd/src/composition.rs:843-846] | needs-contract | lane/d2b-provider-transport-azure-relay.md +- `RS-0570` | low | `d2b-provider-transport-azure-relay` | `parse_material_json` hand-walks `serde_json::Value` paths for a fixed nested shape (`relayListen`/`relaySend` keyName/key) that a derived `Deserialize` with `rename_all = "camelCase"` plus a validate pass would express - this is the recorded live-admission-gate class, refused in the prior audit | fix: only rework if the admission gate is deliberately replaced (derive + `try_from` validation), citing changed evidence | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264] | policy-confirmed | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-transport-vsock`** + +- `RS-0571` | medium | `d2b-provider-transport-vsock` | `VsockTransportSettings` deserializes untrusted wire JSON with no boundary validation: invalid `guest_ref`/`connect_timeout_seconds` land as ordinary values and are only rejected by later explicit `validate()` calls (in `new()` and `ZoneLinkSpec::validate`), and the all-public fields let any caller build an invalid settings value silently; a parse-once `try_from` type would reject once at the wire. | fix: `#[serde(try_from = "VsockTransportSettingsWire")]` with a private raw wire shape +`TryFrom` validation, plus private fields and accessors; wire field names/schema stay unchanged | [packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transport-vsock/src/settings.rs:42-50, packages/d2b-provider-transport-vsock/tests/schema.rs:13-18] | needs-contract | lane/d2b-provider-transport-vsock.md + +**`d2b-provider-volume-local`** + +- `RS-0572` | medium | `d2b-provider-volume-local` | ContentFile, ContentProjection, NetworkConfigContentProjection and the evidence types derive public Deserialize that bypasses the validating constructors: the crate's parse boundary is `from_value`/`from_settings` (which run validate), but the derived impl admits unvalidated projections directly, so the type the rest of the program trusts is not guaranteed valid on the derive path | fix: route the derive through `#[serde(try_from = "Raw...")]` mirror structs (wire shape unchanged: camelCase + deny_unknown_fields preserved) or drop Deserialize from the derives and parse only via the validating entries | [src/content.rs:38-39, src/content.rs:106-107, src/content.rs:203-204, src/content.rs:239-243] | actionable | lane/d2b-provider-volume-local.md + +**`d2b-provider-wayland-policy`** + +- `RS-0573` | medium | `d2b-provider-wayland-policy` | Every wire-parse failure collapses into a bare `InvalidResource` variant that discards the serde reason, so an operator cannot tell which row or which field is malformed (a third of the enum's refusals are spec-shape checks that reuse the same variant) | fix: add a reason-carrying variant to `InteractionEffectError` and `AudioResourceRuntimeError` (e.g. `InvalidResource { reason: String }` or `Decode(#[source] serde_json::Error)` via thiserror)and thread it through the ~15 `map_err(|_| ...InvalidResource)` sites (the enum Display codes are not pinne in `docs/reference/error-codes.md` - grep "interaction" = 0 hits - so not wire-contract) | [packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-wayland-policy/src/effects_service.rs:205-206, packages/d2b-provider-wayland-policy/src/audio_registry.rs:517-534] | actionable | lane/d2b-provider-wayland-policy.md merged: d2b-provider-wayland-policy#3 + +**`d2b-resource-api`** + +- `RS-0574` | medium | `d2b-resource-api` | `render_envelope` parses the row's metadata with `serde_json::from_slice(metadata).unwrap_or(serde_json::Value::Null)`, silently rendering a degraded envelope (empty annotations, epoch fallback timestamps, provenance-derived managedBy) when the metadata is malformed, while every other parse in the file fails closed with `envelope_invalid()` | fix: map the parse error to `envelope_invalid()` like the sibling parses so a corrupt row surfaces as a schema error instead of an invisible degraded read | [manager_backend.rs:744-745] | actionable | lane/d2b-resource-api-p1.md + +**`d2bd`** + +- `RS-0576` | medium | `d2bd` | `GatewayGuestConfigFile` and `GatewayGuestRelayConfigFile` deserialize user-written guest gateway config with `rename_all = "camelCase"` but no `deny_unknown_fields`, so a typo'd key is silently ignored and surfaces later as "Guest Relay namespace is unavailable" instead of a parse error | fix: add `#[serde(deny_unknown_fields)]` to both types (the `QemuMediaProbeRegistry*` records are daemon-written and may stay permissive); add a config-typo test to `load_gateway_guest_zone_link_options` | [packages/d2bd/src/composition.rs:4196, packages/d2bd/src/composition.rs:4205] | actionable | lane/d2bd-p4.md +- `RS-0575` | low | `d2bd` | HostActivationPendingMarker.schema_version is deserialized but never validated, so a future marker version with a compatible field set would silently parse as current | fix: check `schema_version == 1` on read (refuse with a typed log/error otherwise) or drop the field from the read path if versioning is not enforced; the marker file is written by out-of-tree activation machinery, so its shape is a contract | [packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d2bd/src/composition.rs:20298] | needs-contract | lane/d2bd-p3.md +- `RS-0577` | low | `d2bd` | `declared_fd_kind` allocates a `serde_json::Value::String(kind.to_owned())` heap value just to deserialize the wire `FdKind` enum (the kebab-case `serde` mapping) | fix: use `serde_json::from_str::(kind)` (no intermediate `Value`) or a plain `match` over the kebab-case spellings | [packages/d2bd/src/forward_rendezvous.rs:979-981] | actionable | lane/d2bd-p8.md + +**`d2bd-runtime`** + +- `RS-0578` | low | `d2bd-runtime` | `parse_request` (wire.rs:256-355) hand-rolls the internally-tagged dispatch that serde provides: a 19-arm match on the `type` string then `serde_json::from_value` per arm, where the 15 plain verbs would parse directly from a `#[serde(tag = "type", rename_all = "camelCase")]` tagged enum | fix: split a tagged parse enum for list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio derived with internal tag, keeping the custom authStatus/usbipProbe empty-body checks, console opId removal and resourceRequest passthrough explicit; confirm each payload type's deny_unknown_fields posture is unchanged before shipping | [wire.rs:265-353] | actionable | lane/d2bd-runtime-p2.md merged: d2bd-runtime-p2#9 +- `RS-0579` | low | `d2bd-runtime` | `parse_vm_info` hand-walks `serde_json::Value` with `and_then` chains to extract `state`/`boot_vcpus`/`memory.size` from the Cloud Hypervisor vm.info payload, re-implementing what a derived raw shape does at the boundary | fix: derive `Deserialize` on a raw `ChVmInfoRaw` with `#[serde(default)]` on every field (nested `config.cpus.boot_vcpus` / `config.memory.size`) and convert to `ChVmInfo` | [packages/d2bd-runtime/src/ch_api.rs:79] | actionable | lane/d2bd-runtime-p4.md + +**`xtask`** + +- `RS-0580` | medium | `xtask` | `service_catalog.rs`'s `DeclarationFile` parses the committed per-crate `service-catalog.json` with `#[derive(Deserialize)]` and no `deny_unknown_fields`, while the sibling `RegistrationDeclaration` parsing `registrations.json` denies unknowns (`provider_registration_authority.rs:54`); a typo'd key in a declaration (e.g. `providerUid` misspelled) is silently ignored and the daemon's fixed-UID row silently disappears instead of failing the gate | fix: add `#[serde(deny_unknown_fields)]` to `DeclarationFile` | [packages/xtask/src/service_catalog.rs:22, packages/xtask/src/provider_registration_authority.rs:54] | actionable | lane/xtask-p1.md +- `RS-0582` | low | `xtask` | `SnapshotView` (mod.rs:46-47) lacks `#[serde(deny_unknown_fields)]` while every nested wire type in the same artifact (CandidateMaterial, RepositoryRecord, Fingerprint, DependencyEdge, digest newtypes) denies, so a hand-edited snapshot can carry silently-ignored top-level keys | fix: add `#[serde(deny_unknown_fields)]` to SnapshotView; the `schema_version` gate already handles version drift,so there is no forward-compat cost | [packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111] | actionable | lane/xtask-p4.md +- `RS-0581` | low | `xtask` | `DeclarationFile` and `TypeDeclaration` use per-field `#[serde(rename = ...)]` for their camelCase wire keys while the sibling `RoleDeclaration` in the same file uses `#[serde(rename_all = "camelCase")]`, splitting the boundary-naming convention within one file | fix: add `#[serde(rename_all = "camelCase")]` to `DeclarationFile` and `TypeDeclaration` and delete the two per-field renames | [packages/xtask/src/resource_type_authority.rs:179, packages/xtask/src/resource_type_authority.rs:182, packages/xtask/src/resource_type_authority.rs:190, packages/xtask/src/resource_type_authority.rs:192] | actionable | lane/xtask-p3.md + +### `obs` + +Observability: structured named-field events, tracing over println, spans, error chains logged once, no secret in fields. + +**`d2b-broker`** + +- `RS-0583` | low | `d2b-broker` | `retry_acl_grant` interpolates its `label` into the message instead of a named field: `tracing::debug!(error = %err, "{label} ACL refresh not ready yet")` and `tracing::warn!("{label} ACL refresh timed out")`, with no enclosing span carrying it, so the refresh kind is not queryable | fix: emit `label = %label` as a field and keep the message interpolation-free | [packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:2539] | actionable | lane/d2b-broker-p3.md + +**`d2b-core`** + +- `RS-0584` | medium | `d2b-core` | verify_bundle_hash emits a backward-compatibility warning via `eprintln!` in library code, and d2b-core has no tracing/log channel at all, so the "bundleHash missing, skipping self-hash check" warning never reaches the daemon's structured logs and operators cannot see that hash verification was skipped | fix: add `tracing` (already the workspace-wide logging dependency in sibling crates) and emit `tracing::warn!(path = %path.display(), "bundle artifact has no bundleHash field; skipping self-hash check")`, or route the warning through the crate's audit/error path | [packages/d2b-core/src/bundle_resolver.rs:1097] | actionable | lane/d2b-core-p1.md + +**`d2b-provider-activation-nixos`** + +- `RS-0585` | low | `d2b-provider-activation-nixos` | nine `tracing::warn!` refusal events in `ActivationTrust::verify` are message-only with no named fields and no enclosing span (no `#[instrument]` anywhere in the crate), so the failing fence is queryable only as message text | fix: add a named field carrying the error variant (e.g. `refusal = ?ActivationVerificationError::TrustEpochMismatch`), keeping fields identifier-free so the site stays under the ADR 0010/0028 redaction gate | [packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activation-nixos/src/controller.rs:575, packages/d2b-provider-activation-nixos/src/controller.rs:581, packages/d2b-provider-activation-nixos/src/controller.rs:587] | actionable | lane/d2b-provider-activation-nixos.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0586` | medium | `d2b-provider-clipboard-wayland` | the binary logs through the log facade with interpolated message strings (62 sites) while the crate's lib uses tracing with named fields, giving one crate two facades and unqueryable events | fix: migrate d2b-clipd.rs to tracing (already a dependency, used by runtime.rs) with named fields, e.g. log::info!("d2b-clipd: ready (config={}, ...)") becomes tracing::info!(config = %args.config.display(), bridge_root = %args.bridge_root.display(), "d2b-clipd ready") | [src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0587` | low | `d2b-provider-clipboard-wayland` | clipd_host log events use interpolated messages instead of named fields (attribution, mime count, secret flag, error values are formatted into the message), so the events are not queryable by field | fix: convert to structured fields, e.g. log::debug!(quality = ?attribution.quality, mimes = allowed_mimes.len(), secret = has_secret, "host selection changed") | [packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:489, packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs:24, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:60] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-credential-secret-service`** + +- `RS-0588` | medium | `d2b-provider-credential-secret-service` | session-close failure warn is message-only with no named fields, so a fleet cannot filter which provider/session close left unresolved leases | fix: add `provider = crate::PROVIDER_REF` and the two booleans (`unresolved_leases`, `unresolved_operations`)as fields to the `tracing::warn!` | [packages/d2b-provider-credential-secret-service/src/service.rs:860] | actionable | lane/d2b-provider-credential-secret-service.md + +**`d2b-provider-guest-azure-virtual-machine`** + +- `RS-0589` | low | `d2b-provider-guest-azure-virtual-machine` | the literal `provider = "runtime-azure-virtual-machine"` field is repeated on all 27 events and the `resource_group` field renders `OpaqueAzureRef()` via `Display` (d2b-contracts/src/foundation_effects.rs:181-184), so events that log only resource_group carry no correlation value | fix: add a `#[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))]` span on the controller entry points (reconcile, adopt, poll_operation, update, finalize) and drop the per-event literal; log zone/resource where available instead of the redacted resource_group | [src/controller/mod.rs:346, src/controller/mod.rs:425] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0590` | low | `d2b-provider-guest-qemu-media` | All 21 tracing events repeat the same two context fields (`resource = %self.guest_ref`, `provider = "runtime-qemu-media"`(inline ( ~20 sites in reconcile.rs + qmp/mod.rs:233); a span per reconcile/finalize would carry them once | fix: `#[tracing::instrument(skip(self, effect))]` on `QemuMediaController::reconcile`/`finalize` (or an explicit enter/exit span (dropping the duplicated pairs from the per-event fields | [packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:352, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:380, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:605, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:233] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-process-systemd`** + +- `RS-0591` | low | `d2b-provider-process-systemd` | the `debug!` event on the cancelled-ticket path evaluates `ticket.process_ref().to_canonical_string()` eagerly, allocating the canonical string even when debug is disabled | fix: pass a reference and let the macro format lazily (`resource = %ticket.process_ref()` if Display exists, else `?ticket.process_ref()`), reserving the eager `to_canonical_string()` for the warn/error paths | [packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-systemd/src/lib.rs:141] | actionable | lane/d2b-provider-process-systemd.md + +**`d2b-provider-test-controller`** + +- `RS-0592` | medium | `d2b-provider-test-controller` | the bin emits `tracing` events with structured `reason = %e` fields but never installs a subscriber (main() at main.rs:33-47; Cargo.toml has `tracing` but no tracing-subscriber), so every debug/warn/error event is dropped and the only operator-visible diagnostics are the unstructured `eprintln!` retry lines at main.rs:68/95/99/111/125 - one failure class reported through two channels, one of which is dead | fix: install a subscriber once at process start (e.g. `tracing_subscriber::fmt::init()`), or convert the tracing sites to eprintln | [packages/d2b-provider-test-controller/src/main.rs:33-47, packages/d2b-provider-test-controller/src/main.rs:68] | actionable | lane/tail-5.md +- `RS-0593` | low | `d2b-provider-test-controller` | message-only warn events drop their context: the keepalive error is discarded via `.is_err()` and logged as a bare message, and the unexpected named stream's id is unnamed | fix: bind the error (`warn!(reason = %e, ...)`) and name the stream (`warn!(stream = ?stream, ...)`) | [packages/d2b-provider-test-controller/src/main.rs:164, packages/d2b-provider-test-controller/src/main.rs:173-174] | actionable | lane/tail-5.md + +**`d2b-provider-toolkit`** + +- `RS-0594` | low | `d2b-provider-toolkit` | `serve_enrolled` drops a base-side wire-contract violation with no event: a frame that fails `GuestFrame::new` (empty or oversized, i.e. a peer protocol violation, not an agent refusal) is `continue`d silently, and the module doc only covers agent refusals as "the agent's to record", so the malformed frame is invisible to the operator | fix: emit a `warn!` with the frame length before dropping, keeping the session up | [packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src/base/guest.rs:446-452] | actionable | lane/d2b-provider-toolkit-p1.md +- `RS-0595` | low | `d2b-provider-toolkit` | three message-only `warn!` events in the authenticated session loop carry no named fields even though zone/provider/method are in scope at each site, so the events are not queryable per provider | fix: add fields, e.g. `warn!(zone = ?session.route_binding().zone(), "component session receive failed; closing provider session")` and the analogous provider/method fields at the readiness and loop-failure sites | [packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src/server/session.rs:255, packages/d2b-provider-toolkit/src/server/session.rs:262] | actionable | lane/d2b-provider-toolkit-p2.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0596` | low | `d2b-provider-transport-azure-relay` | five `tracing::warn!` events at the credential-port boundary are message-only (guest_credential.rs:406, 423, 476, 483 - and 438 carries `active_leases` but no role), while sibling events in the same crate carry `role = ?role`, `binding = ?binding`, `reason = %error`; a lease-acquire rejection or revoke mismatch is not attributable to a role or lease without those fields | fix: add `role = ?role` (and `lease_id` where available) to those events so the crate's event schema is uniform | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:423-425, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:476-478, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:483-485] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-transport-unix`** + +- `RS-0597` | low | `d2b-provider-transport-unix` | four message-only `tracing::warn!` events drop the underlying errno (`map_err(|_|)` then warn with only the `provider` field): peer-credential bind failure, monitor-fd duplication, observation poll, and entropy-source failures | fix: capture the errno as `reason = %e` like the admission-rejection site at portal.rs:209-212 already does | [packages/d2b-provider-transport-unix/src/portal.rs:217-220, packages/d2b-provider-transport-unix/src/portal.rs:244-247, packages/d2b-provider-transport-unix/src/portal.rs:301-304, packages/d2b-provider-transport-unix/src/portal.rs:348-351] | actionable | lane/tail-5.md + +**`d2b-provider-transport-vsock`** + +- `RS-0598` | low | `d2b-provider-transport-vsock` | the 9 transport-open rejection warn events log `endpoint`/`binding` fields whose `Display` impls are constants ("opaque-endpoint"/"opaque-binding"), so the named fields cannot correlate any event to a specific transport - an operator debugging repeated opens sees identical values every time. | fix: drop the `endpoint`/`binding` fields from the open-reject warn events, or give `OpaqueEndpointId`/`OpaqueBindingId` a real `Display` over `self.0` while keeping `Debug` redacted | [packages/d2b-provider-transport-vsock/src/service.rs:392, packages/d2b-provider-transport-vsock/src/service.rs:466, packages/d2b-provider-transport-vsock/src/service.rs:65-67, packages/d2b-provider-transport-vsock/src/service.rs:99-101] | actionable | lane/d2b-provider-transport-vsock.md +- `RS-0599` | low | `d2b-provider-transport-vsock` | bridge-drop,and bridge-copy-failure debug events carry no transport identity (no handle, endpoint, or binding field), so with up to `MAX_ACTIVE_TRANSPORTS` concurrent transports an operator cannot tell which one dropped an event or failed a copy - thread a handle/endpoint identity into the open path's spawned bridge task and through `emit_event`. | fix: capture `endpoint_id`/`binding_id` into the `tokio::spawn` block in `open_transport` and pass them to `emit_event`, adding named fields to the three drop events and the `run_bridge` copy-failure site | [packages/d2b-provider-transport-vsock/src/service.rs:735, packages/d2b-provider-transport-vsock/src/service.rs:766, packages/d2b-provider-transport-vsock/src/service.rs:851, packages/d2b-provider-transport-vsock/src/bridge.rs:186] | actionable | lane/d2b-provider-transport-vsock.md + +**`d2b-resource-api`** + +- `RS-0600` | low | `d2b-resource-api` | `parse_create_payload` writes an unstructured `eprintln!` to daemon stderr on every failed create-envelope validation, bypassing the tracing pipeline (no level, no filter, no named fields) from a library crate | fix: replace with `tracing::debug!(error = %error, "create envelope validation failed")` (the failure is already returned to the caller as `ResourceSchemaInvalid`) | [service.rs:1992] | actionable | lane/d2b-resource-api-p1.md + +**`d2b-unsafe-local-helper`** + +- `RS-0601` | low | `d2b-unsafe-local-helper` | the operation-worker failure path logs `unsafe-local launch failed: {error:?}` (protocol.rs:188) with no request_id or operation_id, so a background launch failure cannot be correlated to the request that caused it and carries no stage context | fix: include request_id and operation_id (both in scope at protocol.rs:183-189) in the message or as fields | [packages/d2b-unsafe-local-helper/src/protocol.rs:188] | actionable | lane/d2b-unsafe-local-helper.md + +**`d2bd`** + +- `RS-0605` | medium | `d2bd` | the daemon's accept loop reports runtime errors with `eprintln!` (authorization refusal at 4099/4132, connection-handler failure at 4081/4132-ish, spawn failure at 4138) while the rest of the crate uses tracing and main.rs:146-152 installs a `tracing_subscriber`, so these error events bypass level filtering, structured fields, and the redaction gates; the daemon's stderr goes to the journal as unstructured prose | fix: replace the four `eprintln!` calls with `tracing::error!` events carrying named fields (`error = %error.message()`, `peer_uid`) | [packages/d2bd/src/composition.rs:4081, packages/d2bd/src/composition.rs:4099, packages/d2bd/src/composition.rs:4132, packages/d2bd/src/composition.rs:4138] | actionable | lane/d2bd-p4.md +- `RS-0606` | low | `d2bd` | three lifecycle `tracing::info!` events are message-only with no named fields ("Guest-local ZoneLink transport Provider composed", "Guest target-control service composed", "autostart: nothing to do (empty plan)") and no enclosing span exists (0 `#[instrument]` hits in the lane), so the events cannot be filtered by zone/vm | fix: add named fields (`zone`, `guest_ref`, or `vm`) to the three events, or wrap them in instrumented callers | [packages/d2bd/src/composition.rs:4487, packages/d2bd/src/composition.rs:4538, packages/d2bd/src/composition.rs:5300] | actionable | lane/d2bd-p4.md +- `RS-0607` | low | `d2bd` | `publish_trusted_context`'s failure arm interpolates the error into the message (`"trusted-context publication refused: {error}"`) while the sibling `Ok(_)` arm and every other event in the file carry named fields, so the failure reason is not queryable as a column | fix: move the error into a field (`error = %error, "trusted-context publication refused"`), matching the adjacent arms and the plane's other warn sites | [packages/d2bd/src/provider_lifecycle.rs:1085] | actionable | lane/d2bd-p6.md +- `RS-0602` | low | `d2bd` | eighteen message-only `tracing::warn!` events carry no named fields and the file has no spans at all (`\.instrument\(|#\[instrument` = 0), so the events lose the underlying error: most are inside `map_err` closures that drop the error (2024, 2419, 4846, 5283), and 7169 discards the in-scope `context` (provider/process) when a controller assignment refresh retries | fix: capture the error and log it as a named field (`error = ?...`) in the `map_err` closures, and add `provider`/`process` fields at 7169 | [packages/d2bd/src/resource_runtime.rs:2024, packages/d2bd/src/resource_runtime.rs:2419, packages/d2bd/src/resource_runtime.rs:4846, packages/d2bd/src/resource_runtime.rs:5283] | actionable | lane/d2bd-p1.md +- `RS-0603` | low | `d2bd` | `tracing::error!("Gateway Guest composition refused: root Zone generation unavailable")` is message-only although `topology.root` is in scope | fix: add `zone = %topology.root` (and the generation value if available) so the refusal is queryable per zone | [packages/d2bd/src/composition.rs:14781] | actionable | lane/d2bd-p2.md +- `RS-0604` | low | `d2bd` | two identical message-only `tracing::warn!("resource plane still has live request owners during shutdown")` events in the two LiveRequestOwners branches of shutdown_resource_plane carry no fields, so the operator cannot tell which zones are stuck | fix: add `zones = ?zones` (or a count) to both events | [packages/d2bd/src/composition.rs:15195, packages/d2bd/src/composition.rs:15221] | actionable | lane/d2bd-p2.md +- `RS-0608` | low | `d2bd` | message-only `tracing::warn!("forward rendezvous is at its in-flight cap; refusing the call")` carries no fields and sits in a loop with no enclosing span, so the cap refusal cannot be attributed to a caller or the cap value | fix: add a field (`peer_uid`, `max = posture.max_inflight`) | [packages/d2bd/src/forward_rendezvous.rs:1250] | actionable | lane/d2bd-p8.md + +**`d2bd-runtime`** + +- `RS-0609` | low | `d2bd-runtime` | `write_daemon_version_file` (runtime_process.rs:446-486) reports its five failure paths with `eprintln!` from a library module instead of `tracing`, bypassing level/filter/structure | fix: route them through `tracing::warn!`/`tracing::error!` with the path/context as named fields (module already uses tracing in the sd_notify fns) | [runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs:480] | actionable | lane/d2bd-runtime-p2.md +- `RS-0610` | low | `d2bd-runtime` | event fields allocate eagerly even when the level is filtered: `mode = format!("{mode:o}")` inside a `tracing::debug!` (ssh_host_key_preflight.rs:305, hot on every key entry) and a pre-joined `subjects` string built before a `tracing::warn!` (resource_runtime_support.rs:679-680) | fix: use `tracing::field::debug(format_args!("{mode:o}"))` for the octal mode and `tracing::field::display(subjects.iter().map)...).collect::>().join(","))` (or an `Empty`-then-record) so nothing is formatted when the event is disabled | [ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680] | actionable | lane/d2bd-runtime-p2.md +- `RS-0611` | low | `d2bd-runtime` | the one-shot-exit unparseable-stat warning is message-only with no named fields (`tracing::warn!("wait_for_one_shot_exit: /proc//stat unparseable; ...")`), though `pid` and a `path` string are in scope and sibling warnings carry `%err`/field-style context | fix: emit fields (`pid = %pid`, `path = %path`) with a short message (or wrap the poll loop in a span carrying `pid`) | [packages/d2bd-runtime/src/readiness.rs:327] | actionable | lane/d2bd-runtime-p3.md +- `RS-0612` | low | `d2bd-runtime` | pidfs probe warns/errors interpolate a prebuilt `{msg}` string with embedded `st_dev`/`detail` values instead of named fields, while the sibling `PidfsAvailable` arm already emits `pidfs_st_dev`/`pidfs_st_ino` fields | fix: give `PidfsNotPresent` and `UnexpectedError` arms named `pidfs_st_dev = %st_dev` / `detail = %detail` fields (and keep the long operator-facing sentence as the message template) | [packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132, packages/d2bd-runtime/src/pidfs_probe.rs:144, packages/d2bd-runtime/src/pidfs_probe.rs:147] | actionable | lane/d2bd-runtime-p3.md +- `RS-0613` | low | `d2bd-runtime` | `tracing::warn!("qemu console: failed to convert fd to tokio stream: {e}")` interpolates the error into the message instead of a named field, so the event is not queryable by error | fix: `tracing::warn!(error = %e, "qemu console: failed to convert fd to tokio stream")` | [packages/d2bd-runtime/src/console_session.rs:450] | actionable | lane/d2bd-runtime-p4.md + +### `docs` + +Docs as contract: first-sentence shape, module docs, canonical sections (# Examples/# Errors/# Panics/# Safety), doctests that run. + +**`d2b`** + +- `RS-0659` | low | `d2b` | six `pub fn` response expecters (`expect_start`, `expect_detached_create/list/logs/status/kill`) carry no doc comment in an otherwise fully documented module | fix: one-line docs stating the expected `ExecOpResponse` variant and the protocol error on mismatch | [packages/d2b/src/exec_client.rs:497, packages/d2b/src/exec_client.rs:507, packages/d2b/src/exec_client.rs:519, packages/d2b/src/exec_client.rs:531] | actionable | lane/d2b-p3.md +- `RS-0658` | low | `d2b` | several pub items carry no doc comment and lib.rs has no crate-level `//!` doc | fix: add one-line first-sentence docs to `DoctorReport`, `run_doctor`, `render_summary`, `render_human` (doctor.rs), `ValidateReport`, `ValidateMode`, `exit_code` (host_validate.rs), `cli_command`, `run` (lib.rs), and a `//!` crate doc in lib.rs | [packages/d2b/src/doctor.rs:91, packages/d2b/src/doctor.rs:163, packages/d2b/src/host_validate.rs:229, packages/d2b/src/host_validate.rs:237] | actionable | lane/d2b-p2.md + +**`d2b-audit`** + +- `RS-0614` | low | `d2b-audit` | no canonical `# Errors`/`# Examples` sections exist anywhere in the crate although ~50 `-> Result<` sites include the public API (export_segments_range, AuditRecord::new/verify/zone_operation_key, evidence_from_decision_result, AuditSink::open/append/prune_old, SegmentWriter::open/append, OperationIdentity::derive/parse); failure conditions are described in prose but not under the section a caller scans for | fix: add `# Errors` sections naming the AuditRecordError/AuditSinkError/EvidenceError variants on the Result-returning pub items and `# Examples` on the non-obvious constructors (AuditRecord::new, SegmentWriter::open) | [packages/d2b-audit/src/export.rs:74, packages/d2b-audit/src/record_types.rs:428, packages/d2b-audit/src/reconcile.rs:54, packages/d2b-audit/src/sink.rs:175] | actionable | lane/d2b-audit.md + +**`d2b-broker`** + +- `RS-0624` | medium | `d2b-broker` | the public fd-ownership API in fd_passing.rs is undocumented: `FdPassingError` (13), `FdRegistry::register`/`clear` (37, 41), and the whole `FdLease` surface (`new`/`raw`/`release`, 55-70) have no doc comments even though the load-bearing contract is non-obvious - `FdLease` closes the fd on drop and `release()` disarms that close, which is exactly what ADR 0034 fd-transfer callers must know | fix: add one-line docs to each item stating ownership (who closes, what `release` disarms) and the `recv_*`/`send_fds` error variants | [packages/d2b-broker/src/fd_passing.rs:13, packages/d2b-broker/src/fd_passing.rs:31-70] | actionable | lane/d2b-broker-p5.md +- `RS-0630` | medium | `d2b-broker` | media.rs's public ops surface carries no doc comments | fix: add doc blocks to each: MediaOpError variants, the four outcome structs (esp. BootOutcome's four booleans),and the pub ops fns (`enroll`/`refresh_registry`/`boot`/`system_powerdown`/`query_status`/`quit`/`attach`/`detach`),covering preconditions, outcome semantics,and `# Errors` on the `Result` fns | [packages/d2b-broker/src/ops/media.rs:35, packages/d2b-broker/src/ops/media.rs:167-186, packages/d2b-broker/src/ops/media.rs:188, packages/d2b-broker/src/ops/media.rs:238] | actionable | lane/d2b-broker-p7.md +- `RS-0625` | medium | `d2b-broker` | pub syscall wrappers `peer_credentials` (121) and `tun_set_persist`/`tun_set_owner`/`tun_set_group` (185, 195, 210) carry no doc comments while their twins `peer_uid` and `tun_create_tap_fd` do; the contracts are non-obvious (peer uid/gid/pid triple semantics; TUNSETPERSIST/OWNER/GROUP ioctl semantics and the ifname binding) | fix: add one-line docs plus the `# Errors` conditions (ioctl failure, uid/gid out of `c_int` range) | [packages/d2b-broker/src/sys.rs:120-121, packages/d2b-broker/src/sys.rs:185, packages/d2b-broker/src/sys.rs:195, packages/d2b-broker/src/sys.rs:210] | actionable | lane/d2b-broker-p5.md +- `RS-0631` | medium | `d2b-broker` | protocol.rs's framing surface (cap const + sync framing fns)carries no docs although it is the broker wire contract | fix: doc `MAX_FRAME_SIZE` and the six framing fns (length-prefix format, cap enforcement, `Option::None` on empty socket, fd-ancillary semantics), mirroring the async wrappers' existing docs | [packages/d2b-broker/src/protocol.rs:13, packages/d2b-broker/src/protocol.rs:16, packages/d2b-broker/src/protocol.rs:29, packages/d2b-broker/src/protocol.rs:43] | actionable | lane/d2b-broker-p7.md +- `RS-0632` | medium | `d2b-broker` | state_dir.rs publishes nine undocmented pub items (types + fns)with no `# Errors` on the `io::Result` fns | fix: add item-level doc contracts to `DirKind`, `PrepareDirRequest`, `PrepareDirAudit`, `ReplaceOrCreateResult`, `prepare_dir`, `live_prepare_runtime_dir`, `PreparedStateDir`, `live_prepare_state_dir` (and `# Errors` where Result) | [packages/d2b-broker/src/ops/state_dir.rs:47, packages/d2b-broker/src/ops/state_dir.rs:53, packages/d2b-broker/src/ops/state_dir.rs:70, packages/d2b-broker/src/ops/state_dir.rs:83] | actionable | lane/d2b-broker-p7.md +- `RS-0621` | medium | `d2b-broker` | audit.rs public surface gaps:`AuditEntry` (legacy JSONL record shape consumed by the socket-acl gate), `AuditDropSummary`, `AuditLog::open` (the daemon entry point with bootstrap/poison barrier semantics), and `audit_drop_summary` carry no doc comment, while every sibling method around them is documented | fix: add `///` first-sentence contracts (state what `disposition` vs `outcome` mean, what counters `AuditDropSummary` merges, what `open`'s barrier requires of callers) | [packages/d2b-broker/src/audit.rs:124, packages/d2b-broker/src/audit.rs:84, packages/d2b-broker/src/audit.rs:416, packages/d2b-broker/src/audit.rs:1029] | actionable | lane/d2b-broker-p4.md +- `RS-0616` | medium | `d2b-broker` | the broker's central runtime module has no //! module doc,and its five process-entry public items (ServerConfig, BrokerMode, RunError, parse_command, run)lack any doc comment, even though they form the public API the composition binary (d2b-broker-composition/src/main.rs:3, 47-60)and integration tests (tests/profile_separation.rs:1, 22-33)match on | fix: add a one-line module doc atop runtime.rs(serve/socket/audit contract)and one-line first-sentence doc comments to ServerConfig, BrokerMode, RunError, with # Errors on run/parse_command, which return Result),keeping the comments caller-contracts, not implementation narration | [packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b-broker/src/runtime.rs:375, packages/d2b-broker/src/runtime.rs:398] | actionable | lane/d2b-broker-p2.md +- `RS-0622` | medium | `d2b-broker` | `HandoffOperationError` (pub enum returned from every pub handoff fn) has no top-level doc comment; the failure modes (`JournalMismatch`, `HelperUnavailable`, `ArtifactValidationOutputInvalid`, ...) have descriptive names but no contract sentence says what callers should do per variant | fix: add a `///` doc line listing the variant classes (journal replay vs helper/validation failures) | [packages/d2b-broker/src/ops/host_generation_handoff.rs:35] | actionable | lane/d2b-broker-p4.md +- `RS-0623` | medium | `d2b-broker` | `ApplyWithPreflightError` (pub enum returned from the pub `apply_with_preflight_owned` entry point) has no top-level doc (only one variant carries an inline `///`); callers get no contract sentence distinguishing query failures from foreign-route refusal from reconcile failures | fix: add a one-line enum doc naming what each variant class means (route query vs ownership refusal vs executor failure) | [packages/d2b-broker/src/ops/route.rs:29] | actionable | lane/d2b-broker-p4.md +- `RS-0615` | low | `d2b-broker` | the four Result-returning public fns in ops/usbip_lock.rs (`ensure_lock_root`, `acquire_lock`, `release_lock`, `peek_owner`) document failure conditions only in prose and carry no `# Errors` canonical section, which the docs contract wants on every Result-returning item | fix: add `# Errors` sections naming the returned variants (LockAlreadyHeld, OwnerMismatch, Io) | [packages/d2b-broker/src/ops/usbip_lock.rs:81, packages/d2b-broker/src/ops/usbip_lock.rs:90, packages/d2b-broker/src/ops/usbip_lock.rs:171, packages/d2b-broker/src/ops/usbip_lock.rs:316] | actionable | lane/d2b-broker-p1.md +- `RS-0617` | low | `d2b-broker` | pub types `UsbipHostInspectionError` (usbip_host.rs:17), `UsbipDriverBinding` (153) and `UsbipHostDeviceInspection` (160) carry no doc comment at all on a crate with a lib target | fix: add one-line docs (and field docs for the inspection struct) | [packages/d2b-broker/src/ops/usbip_host.rs:17, packages/d2b-broker/src/ops/usbip_host.rs:153, packages/d2b-broker/src/ops/usbip_host.rs:160] | actionable | lane/d2b-broker-p3.md +- `RS-0626` | low | `d2b-broker` | the `path_safe` module's pub helpers (`refuse_symlink`, `refuse_world_writable_parent`, `refuse_non_root_parent`, `read_to_string_nofollow`, `write_nofollow`, `remove_nofollow`, `ensure_dir`, `ensure_dir_preserve_existing`) lack per-item doc comments; the contract lives only in the module-level doc, so rustdoc item pages are empty and the reader must open the module header for each helper's safety rule | fix: promote each module-doc bullet to a one-line `///` on its item (or add `#[doc = "..."]` links), keeping the module doc as the index | [packages/d2b-broker/src/sys.rs:258, packages/d2b-broker/src/sys.rs:268, packages/d2b-broker/src/sys.rs:329, packages/d2b-broker/src/sys.rs:398] | actionable | lane/d2b-broker-p5.md +- `RS-0618` | low | `d2b-broker` | pub types `ApplySysctlOutcome` (sysctl.rs:32), `ApplySysctlError` (40) and `ApplyWithReadbackError` (113) and the pub method `with_default_root` (23) are undocumented | fix: add one-line docs per item | [packages/d2b-broker/src/ops/sysctl.rs:32, packages/d2b-broker/src/ops/sysctl.rs:40, packages/d2b-broker/src/ops/sysctl.rs:113] | actionable | lane/d2b-broker-p3.md +- `RS-0619` | low | `d2b-broker` | pub enum `StorageContractError` (storage_contract.rs:21) has no doc comment | fix: one-line doc naming the refusal/invalid/Io contract | [packages/d2b-broker/src/ops/storage_contract.rs:21] | actionable | lane/d2b-broker-p3.md +- `RS-0620` | low | `d2b-broker` | pub methods `PidfdMethod::as_str` (pidfd.rs:112), `StartTime::matches` (127), `RealPidfdSpawner::new` (191) and `AuditDecision::as_str` (ops/mod.rs:164) are undocumented | fix: one-line docs per method | [packages/d2b-broker/src/ops/pidfd.rs:112, packages/d2b-broker/src/ops/pidfd.rs:191, packages/d2b-broker/src/ops/mod.rs:164] | actionable | lane/d2b-broker-p3.md +- `RS-0627` | low | `d2b-broker` | the two `pub async fn` store-view farm entrypoints carry the same design-journal sentence "Async form used by the async exec_reconcile and store_sync paths; the sync form was removed with its last sync caller" with a typo (missing space after `paths.`), stating history ("was removed") instead of a contract. | fix: trim to a one-line contract ("Async counterpart used by the async exec_reconcile/store_sync callers.") at both sites, and add `# Errors`-style failure notes where the error enum is non-obvious. | [src/ops/store_view_farm.rs:66-72, src/ops/store_view_farm.rs:191-197] | actionable | lane/d2b-broker-p6.md +- `RS-0628` | low | `d2b-broker` | BrokerEnvelope::call, call_with_fds,and call_nested_with_fds return `Result<_, EnvelopeRefusal>` with no `# Errors` section, so failure modes (14 closed refusal-code consts, e.g. subscriber-only, scope refusals, budget refusals) must be chased around the file to be known. | fix: add an `# Errors` block to each of the three pub methods naming the closed `EnvelopeRefusal` vocabulary and pointing at the refusal constants. | [src/envelope/mod.rs:1118, src/envelope/mod.rs:1136, src/envelope/mod.rs:1187] | actionable | lane/d2b-broker-p6.md +- `RS-0629` | low | `d2b-broker` | apply_with_reload/remove_with_reload doc prose narrates design history ("The dispatcher now lands on ops::nm even though the live path is still a thin wrapper... future coexistence/reload-verification work"), which rots and reads as rendered journal prose on a public item. | fix: rewrite the doc as a plain two-sentence contract (what it does, when reload verification kicks in),and move the rationale to the module doc if it must be preserved. | [src/ops/nm.rs:293-301, src/ops/nm.rs:303-308] | actionable | lane/d2b-broker-p6.md + +**`d2b-bus`** + +- `RS-0633` | medium | `d2b-bus` | The exported observer contract BusEvent, BusFailureReason, BusObserver, and NoopBusObserver carry no doc comments, so the semantics of the 17 failure reasons and when record fires are undocumented for the d2bd consumer | fix: add module-level or item docs stating when each event is recorded and what each BusFailureReason variant means | [packages/d2b-bus/src/router.rs:1126, packages/d2b-bus/src/router.rs:1135, packages/d2b-bus/src/router.rs:1187, packages/d2b-bus/src/router.rs:1192] | actionable | lane/d2b-bus-p1.md +- `RS-0637` | medium | `d2b-bus` | `pub struct Cancellation` (re-exported at the crate root) has no doc comment while every sibling public item does, leaving the opaque token's contract (crate-private construction, one-attempt observation, `is_cancelled`) undocumented | fix: add a `///` doc comment stating the token is minted only by the bus and observes one operation attempt | [packages/d2b-bus/src/operations.rs:124-125] | actionable | lane/d2b-bus-p2.md +- `RS-0634` | low | `d2b-bus` | DEFAULT_MAX_ROUTES_PER_SESSION and DEFAULT_MAX_TOTAL_ROUTES are pub consts without docs while their sibling DEFAULT_MAX_PAYLOAD_BYTES has one | fix: add one-line docs naming the bound each constant sets | [packages/d2b-bus/src/router.rs:67-68] | actionable | lane/d2b-bus-p1.md +- `RS-0635` | low | `d2b-bus` | CommittedInteractionSubjectInstallBody (consumed by d2bd), AuthorizationErrorClass, EndpointSessionFailure::class/code/remediation, and the metrics label accessors are pub items without doc comments | fix: add one-line docs to each, at least on the struct and the class enum | [packages/d2b-bus/src/router.rs:1895, packages/d2b-bus/src/authorization.rs:401, packages/d2b-bus/src/registry.rs:259-267, packages/d2b-bus/src/metrics.rs:110] | actionable | lane/d2b-bus-p1.md +- `RS-0636` | low | `d2b-bus` | No pub Result-returning item carries a canonical # Errors section anywhere in the partition (94 Result-returning pub items, zero sections), so the failure conditions of non-obvious APIs such as BusIngress::invoke and ZoneRegistrar::register_component_session are undocumented | fix: add # Errors sections to the non-obvious Result-returning pub items, starting with the bus entry points | [packages/d2b-bus/src/router.rs:3709, packages/d2b-bus/src/router.rs:3261, packages/d2b-bus/src/registry.rs:366] | actionable | lane/d2b-bus-p1.md +- `RS-0638` | low | `d2b-bus` | public `Result`-returning constructors and accessors (`StreamName::parse`, `OperationId::parse`, `ZoneBoundPolicyIdentity::digest`, `ZoneEndpointPolicy::lower`) carry no `# Errors` section naming which condition produces which failure, even though the failure conditions are closed and enumerated in the error enums | fix: add `# Errors` sections to the public parse/lower/digest items | [packages/d2b-bus/src/streams.rs:39-40, packages/d2b-bus/src/operations.rs:24-25, packages/d2b-bus/src/wire.rs:79-82, packages/d2b-bus/src/session/contract.rs:164-165] | actionable | lane/d2b-bus-p2.md + +**`d2b-contracts-broker`** + +- `RS-0639` | medium | `d2b-contracts-broker` | every Result-returning public fn lacks the canonical `# Errors` section (seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits crate-wide), so the failure conditions of the handoff state machine, the launch-args bounds, and the kernel client are only recoverable from enum docs | fix: add `# Errors` sections naming the `HandoffError`/`RunnerLaunchArgsError`/`KernelInvokeError` conditions to `SourceGenerationCompatibilityFloorV1::new`, `begin_handoff`, the `HandoffCoordinator` transitions, `RunnerLaunchArgs::new`, and `envelope_invoke_kernel` | [packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src/kernel_client.rs:113, packages/d2b-contracts-broker/src/broker_wire.rs:2495] | actionable | lane/d2b-contracts-broker.md +- `RS-0640` | low | `d2b-contracts-broker` | doc-comment polish defects in the FdKind/ForwardOperationRequest contract docs: `present.from` (missing space), CJK full-width periods (the FdKind variant docs end in a CJK period), and comma-adjacent spacing (`positions,in the ... list,of`) | fix: reword those doc lines | [packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/broker_wire.rs:254, packages/d2b-contracts-broker/src/broker_wire.rs:421-430] | actionable | lane/d2b-contracts-broker.md + +**`d2b-contracts-control`** + +- `RS-0641` | medium | `d2b-contracts-control` | cli_output.rs exports 20+ CLI-output DTOs (ListOutputV2, ListItemOutputV2, UsbProbeOutputV1, RealmListOutputV1, RealmInspectOutputV1, OpInspect*, RealmPolicyOutputV1, StatusOutputV2, StatusInventoryOutputV2, ApiReady*, StatusVmOutputV2, LivePoolIntegrityOutputV1, StatusServicesOutputV2, RunnerParityOutputV2, StatusBridgeCheckOutputV2, Audit*OutputV2, Auth*OutputV2) with no doc comments; only StatusServicesOutputV3 and two fields document anything | fix: add one-line doc comments naming the wire shape each DTO renders | [cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130] | actionable | lane/d2b-contracts-control.md +- `RS-0642` | medium | `d2b-contracts-control` | public_wire.rs request/response structs and fields are undocumented where the wire semantics are non-obvious (ListRequest, StatusRequest, AuditRequest, AuditSelector, ListEntry, VmStatus, PublicVmServices, BridgeCheck, VmLifecycle, RuntimeSummary, VmAutostartPosture, QemuMedia*, ShellName, ShellNameError, WorkloadListArgs, UsbipProbeEntry field meanings), and `-> Result<` items (ShellName::new, RealmAccentColor::new) carry no `# Errors` section | fix: add doc comments with `# Errors` on the Result-returning constructors | [public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495] | actionable | lane/d2b-contracts-control.md +- `RS-0643` | medium | `d2b-contracts-control` | unsafe_local_wire.rs exposes undocumented pub constants with unexplained magic values (MAX_HELPER_QUEUE_DEPTH=128, MAX_HELPER_SNAPSHOT_SCOPES=1024, MAX_COMPLETED_OPERATIONS_PER_UID=1024, MAX_COMPLETED_OPERATION_AGE_SECS=24*60*60, UNSAFE_LOCAL_HELPER_PROTOCOL_VERSION), undocumented pub fns (unsafe_local_helper_protocol_supported, validate_unsafe_local_resource_identity, HelperSnapshot::validate, HelperLaunchRequest::validate_bounds), and undocumented wire types (HelperHello, HelperHelloAccepted, HelperHeartbeat, HelperScopeKind, HelperScopeState, HelperScopeSnapshot, HelperSnapshot, HelperOperationResult, HelperOperationRejected, DaemonToUnsafeLocalHelper, UnsafeLocalHelperToDaemon, UnsafeLocalHelperWireSchema) | fix: document each constant with the why (queue/snapshot/age bounds the daemon enforces) and one line per wire type | [unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wire.rs:26] | actionable | lane/d2b-contracts-control.md +- `RS-0644` | low | `d2b-contracts-control` | terminal_wire.rs's seven DTOs (TerminalStream, TerminalSize, TerminalWriteStdin, TerminalReadOutput, TerminalResize, TerminalWriteStdinResult, TerminalReadOutputChunk) have no item docs; only the module-level `//!` explains them | fix: add one-line docs per type (the redacted-Debug note belongs on the session-bearing types) | [terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105] | actionable | lane/d2b-contracts-control.md + +**`d2b-contracts-provider`** + +- `RS-0646` | medium | `d2b-contracts-provider` | none of the 59 Result-returning items in the partition carries an `# Errors` section, so callers cannot learn from the docs which closed-discriminant error each condition produces (for example when `CredentialControllerCall::authorize` yields `DeadlineExceeded` versus `OperationDenied`, or which `validate_*` failure maps to which `MetricPolicyError` variant) | fix: add `# Errors` sections naming the variant per condition to the public Result APIs, starting with the constructor and validate families | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:478, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:72, packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs:93] | actionable | lane/d2b-contracts-provider-p2.md +- `RS-0645` | low | `d2b-contracts-provider` | no canonical `# Errors` sections exist on any Result-returning pub item in the lane even though failure conditions are the load-bearing part of these admission constructors | fix: add `# Errors` sections naming the closed variants (e.g. `ProviderContractError::InvalidPrimitive` for `BinaryRef::parse`, `ProviderContractError::TrustNotEstablished` for `TrustEvidence::admit`) to the pub constructors and admission methods | [packages/d2b-contracts-provider/src/v3/provider.rs:250, packages/d2b-contracts-provider/src/v3/provider.rs:481, packages/d2b-contracts-provider/src/v3/credential.rs:120, packages/d2b-contracts-provider/src/v3/credential/service.rs:1002] | actionable | lane/d2b-contracts-provider-p1.md + +**`d2b-contracts-resource`** + +- `RS-0649` | medium | `d2b-contracts-resource` | artifact.rs is the only module with an undocumented public surface: MAX_ARTIFACT_ID_BYTES, ArtifactIdError::Invalid, ArtifactId, parse, and as_str all lack doc comments while every sibling module documents its pub items | fix: add one-line doc comments mirroring the BoundedToken contract (bounded lower-kebab artifact identifier, never a host path) | [packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/v3/artifact.rs:7-10, packages/d2b-contracts-resource/src/v3/artifact.rs:22, packages/d2b-contracts-resource/src/v3/artifact.rs:25] | actionable | lane/d2b-contracts-resource-p2.md +- `RS-0650` | low | `d2b-contracts-resource` | two pub fns in execution_policy.rs lack doc comments: `ExecutionPolicyWire::into_policy` (pub because Host/Guest crates decode through the wire mirror) and `string_schema_object` (pub only for the exported `string_schema!` macro expansion) | fix: add one-line docs, noting for string_schema_object that it is macro-support surface | [packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-resource/src/v3/execution_policy.rs:944] | actionable | lane/d2b-contracts-resource-p2.md +- `RS-0647` | low | `d2b-contracts-resource` | limits.rs exports 30 `pub const` admission limits (lines 3-33) with no per-item docs and no rationale for the specific values (500, 100, 900000, 30000, 256 KiB, 4 MiB), so a reader cannot tell which bound is load-bearing | fix: add one-line doc comments naming the enforcing boundary (request admission, watch credits, deadline) or a module-level rationale paragraph | [packages/d2b-contracts-resource/src/v3/limits.rs:3, packages/d2b-contracts-resource/src/v3/limits.rs:22] | actionable | lane/d2b-contracts-resource-p1.md +- `RS-0648` | low | `d2b-contracts-resource` | the operations module exports pub accessors with no doc comments: `MutationOrdinal::get` (error.rs:21), `StoreSlot::get` (error.rs:50), the eight `StoreError` accessors (error.rs:262-291), `StoreSealIdentity::new/zone/slot` (seal.rs:48/63/67), `OpenedMutation::body/into_body` (seal.rs:121/125), `MutationSealAcceptor::diagnose/declared_slot` (seal.rs:177/181), and `PreparedStoreMutation::new/mutation/resource_uid/payload_digest` (mod.rs:378-400) | fix: add one-line doc comments, especially for the mutating builder `with_store_slot` and the consume-then-open capability methods | [packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-resource/src/v3/operations/error.rs:262, packages/d2b-contracts-resource/src/v3/operations/seal.rs:48, packages/d2b-contracts-resource/src/v3/operations/seal.rs:121] | actionable | lane/d2b-contracts-resource-p1.md + +**`d2b-contracts-zone-session`** + +- `RS-0651` | medium | `d2b-contracts-zone-session` | the 37 pub wire constants at the top of component_session.rs (canonical lengths, clock skew, queue and deadline bounds) carry no doc comments at all, leaving the "why" of each wire value unrecorded in the contract crate that pins them | fix: add one-line `///` docs naming the wire role of each constant, mirroring the documented constant blocks in role.rs:30-58 | [src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.rs:61] | actionable | lane/d2b-contracts-zone-session-p1.md + +**`d2b-core`** + +- `RS-0655` | medium | `d2b-core` | manifest_v04.rs has no module doc and no doc comments on its central public wire types (`ManifestV04`, `ManifestMeta`, `ObservabilityMeta`, `VmEntry`, `VmLifecycle`, `VmGracefulShutdown`, `VmLiveActivation`, `VmLanPolicy`, `VmObservability`, `VmShellMetadata`, `ManifestShellName`, `from_slice`, `to_compact_json`), while sibling modules (host.rs, storage.rs, sync.rs, site.rs) document every type | fix: add a `//!` module doc and one-line doc comments with `# Errors` on the parse/serialize entry points, following the sibling-module style | [packages/d2b-core/src/manifest_v04.rs:1, packages/d2b-core/src/manifest_v04.rs:31, packages/d2b-core/src/manifest_v04.rs:158, packages/d2b-core/src/manifest_v04.rs:209] | actionable | lane/d2b-core-p2.md +- `RS-0654` | medium | `d2b-core` | 15 of the 23 public `intent_id_*` constructors carry no doc comment (intent_id_store_view, intent_id_vm_start, intent_id_nft_host, intent_id_nft_env, intent_id_nft_projection_env, intent_id_ownership_marker_env, intent_id_bridge_env, intent_id_route_env, intent_id_sysctl, intent_id_hosts_host, intent_id_nm_unmanaged_host, intent_id_usbip_firewall, intent_id_usbip_bind, intent_id_runner, intent_id_legacy_runner), even though these format strings are the deterministic BundleOpId wire contract the module doc describes and integrators build by hand | fix: give each a one-line doc naming the exact `BundleOpId` shape it produces (the module table is the source) | [packages/d2b-core/src/bundle_resolver.rs:2917, packages/d2b-core/src/bundle_resolver.rs:2935, packages/d2b-core/src/bundle_resolver.rs:3118, packages/d2b-core/src/bundle_resolver.rs:3217] | actionable | lane/d2b-core-p1.md + +**`d2b-core-controller`** + +- `RS-0652` | low | `d2b-core-controller` | pub struct fields without doc comments: RuntimeReadiness (3 of 5 fields), RecoverySnapshot (5 of 7), HandlerStatus (all 8); the undocumented fields (checkpoint_revision, last_reconciled_tick, retry_after_tick, provider_lease_count) are non-obvious | fix: add one-line field docs to RuntimeReadiness, RecoverySnapshot, and HandlerStatus | [packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controllers.rs:198-209] | actionable | lane/d2b-core-controller-p1.md +- `RS-0653` | low | `d2b-core-controller` | migration.rs exposes `requires_migration` and `validates_binding` without doc comments while every other pub item in the file documents its contract | fix: add one-line docs (e.g. "Whether this decision requires the broker migration path" and "Whether the supplied vm/intent bindings match the sealed decision") | [migration.rs:54, migration.rs:58] | actionable | lane/d2b-core-controller-p2.md + +**`d2b-host`** + +- `RS-0656` | low | `d2b-host` | Result-returning pub functions document failure conditions in prose but carry no `# Errors` sections; the crate has only 2 canonical sections total (host_prep_dag.rs:316, seccomp.rs:112) against ~119 `-> Result<` signatures (validate_readback, parse_request, gunzip_inflate, ...) | fix: add `# Errors` sections naming the failure conditions to the pub Result-returning fns, starting with the wire-boundary parsers (host_generation.rs, media.rs, nftables.rs) | [packages/d2b-host/src/bridge_port.rs:127, packages/d2b-host/src/host_generation.rs:103, packages/d2b-host/src/media.rs:41] | actionable | lane/d2b-host.md +- `RS-0657` | low | `d2b-host` | Pub items in impl blocks lack doc comments: `Controller::REQUIRED`, `Controller::as_str`, `Controller::from_token`, `BusId::new`, `HostPrepStepId::as_str` | fix: one-line doc comments, with `from_token` documenting the token grammar it accepts | [packages/d2b-host/src/cgroup.rs:53, packages/d2b-host/src/cgroup.rs:71, packages/d2b-host/src/cgroup.rs:85, packages/d2b-host/src/nftables.rs:612] | actionable | lane/d2b-host.md + +**`d2b-process-conformance`** + +- `RS-0660` | low | `d2b-process-conformance` | Zero canonical `# Errors` sections exist (seed 2 = 0) while 52 `-> Result<` declarations carry non-obvious failure conditions that several docs only imply (e.g. `ProcessOutcome::exited` rejects out-of-range codes, `SandboxCompiler::compile` rejects root-in-user-domain and canonical-JSON failure, `LaunchIdentity::new` names six refusal conditions, `BrokerTerminalResult::from_parent` requires matching evidence) | fix: add an `# Errors` section naming the failing conditions to the Result-returning pub items, notably terminal.rs:51/94/215, sandbox.rs:72, launch_identity.rs:112, ticket.rs:731, port.rs:35/67 | [packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/sandbox.rs:72, packages/d2b-process-conformance/src/launch_identity.rs:112, packages/d2b-process-conformance/src/ticket.rs:731] | actionable | lane/d2b-process-conformance.md + +**`d2b-provider`** + +- `RS-0661` | medium | `d2b-provider` | Public Result-returning APIs carry no `# Errors` sections,naming which conditions produce which error variants | fix: add `# Errors` sections to the ~28 pub Result-returning fns (agent.rs:40,270; context.rs:63; descriptor.rs:55,108,196,232; identity.rs:98,120,142; instance.rs:28; operation_ledger.rs:179,195; registry.rs:64,99,329,412; session.rs:36,94),listing each reachable variant per fn | [packages/d2b-provider/src/agent.rs:270, packages/d2b-provider/src/descriptor.rs:232, packages/d2b-provider/src/registry.rs:412, packages/d2b-provider/src/session.rs:36] | actionable | lane/d2b-provider.md + +**`d2b-provider-activation-nixos`** + +- `RS-0662` | medium | `d2b-provider-activation-nixos` | the pub Result-returning policy API (`verify_application`, `reconcile`, `apply_runner_result`, `refuse_undeclared_runner_step`, `ActivationTrust::verify`) documents no `# Errors` section, leaving 5 `ActivationError` and 9 `ActivationVerificationError` failure conditions unstated in the contract | fix: add `# Errors` sections naming the variants each fn returns | [packages/d2b-provider-activation-nixos/src/controller.rs:711, packages/d2b-provider-activation-nixos/src/controller.rs:735, packages/d2b-provider-activation-nixos/src/controller.rs:808, packages/d2b-provider-activation-nixos/src/controller.rs:726] | actionable | lane/d2b-provider-activation-nixos.md + +**`d2b-provider-audio-binding`** + +- `RS-0663` | low | `d2b-provider-audio-binding` | the four Result-returning trait methods (`binding_children`, `validate`, `dependencies`, `desired_children`) lack `# Errors` sections saying which conditions yield `Unavailable` vs `InvalidResource`, even though the crate denies missing_docs | fix: add `# Errors` sections naming the family's two failure variants | [packages/d2b-provider-audio-binding/src/audio_binding.rs:56, packages/d2b-provider-audio-binding/src/audio_binding.rs:117, packages/d2b-provider-audio-binding/src/audio_binding.rs:125, packages/d2b-provider-audio-binding/src/audio_binding.rs:134] | actionable | lane/tail-1.md + +**`d2b-provider-audio-pipewire`** + +- `RS-0664` | medium | `d2b-provider-audio-pipewire` | `AudioStateLock` is a pub struct with no doc comment at all (its module carries `#[allow(missing_docs)]`, lib.rs:9-10), and it is non-obvious: a caller must know holding the value keeps the OFD lock and dropping it releases it | fix: document the guard semantics (or remove the module-level allow and document the item) | [src/state.rs:81-84, src/lib.rs:9-10] | actionable | lane/d2b-provider-audio-pipewire.md +- `RS-0665` | low | `d2b-provider-audio-pipewire` | magic values lack the why: `AUDIO_REPAIR_INTERVAL_SECS = 300` says it is the repair interval but not why 300s, and the arbiter/mixer bound `64` in `AudioBindingController::new` is undocumented (and hardcoded again in tests/controller.rs:302-308) | fix: document the cadence rationale and hoist the 64 into a named const (e.g. `AUDIO_QUEUE_BOUND`) used by both the controller and the bound test | [src/controller.rs:21, src/controller.rs:209, src/controller.rs:212] | actionable | lane/d2b-provider-audio-pipewire.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0666` | medium | `d2b-provider-clipboard-wayland` | Result-returning public items carry no # Errors sections anywhere in the crate despite deny(missing_docs), so failure contracts (ConcurrentLimitExceeded, InvalidBounds, AuditQueueFull, SessionUnauthenticated) are undocumented | fix: add # Errors sections naming the variants to the public Result-returning items, starting with FdPermitPool::acquire, Policy::new, ClipboardAuditQueue::push, and ClipboardRuntime::admit_route | [src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0667` | medium | `d2b-provider-clipboard-wayland` | ClipboardAuditEvent::to_wire derives wire labels from Debug impls (format!("{:?}", event_type) lowercased and size_bucket via {:?}) instead of stable as_str labels, so a variant rename silently changes the cross-crate audit record consumed by d2bd | fix: add as_str() to ClipboardEventType and SizeBucket returning the exact current renderings ("pasteauthorized", "Lt1K", ...) and use them in to_wire | [src/audit.rs:172, src/audit.rs:174] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0668` | low | `d2b-provider-clipboard-wayland` | ClipboardEntry::bytes is documented as "Return a bounded copy for an already-authorized materialization" but returns &[u8], contradicting the copy claim and the as_/to_/into_ cost convention | fix: reword to "Borrow the payload bytes for an already-authorized materialization" | [packages/d2b-provider-clipboard-wayland/src/history.rs:112-115] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0669` | low | `d2b-provider-clipboard-wayland` | the clipd_host IPC and state surface is largely undocumented: niri.rs (read_bounded_ndjson_line, encode_niri_request, decode_niri_response, NiriStateCache methods, FocusedWindowProvider trait, HostClipboardAttributor methods), wayland.rs (DataControlOffer::destroy, DataControlSource::offer_mime), picker.rs (launch's returned &UnixStream borrow, poll_active's nonblocking contract, reap_expired, reap_terminated), host.rs (refresh_focused_window_snapshot) | fix: add doc comments stating the blocking/ownership contracts (which calls block, who destroys protocol objects, what the returned borrow is) | [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:128, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:162, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:336-337] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0670` | low | `d2b-provider-clipboard-wayland` | magic constants lack the why: ENVELOPE_BYTES/JSON_STRING_ESCAPE_EXPANSION in the frame-budget math, PICKER_TERMINATE_GRACE (250ms), MAX_AUDIT_MIME_BYTES (64), DEFAULT_NIRI_MAX_LINE_BYTES (1 MiB) | fix: document the derivation or the upstream constraint each constant encodes | [packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:74, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:7] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-command`** + +- `RS-0671` | low | `d2b-provider-command` | public `Result`-returning constructors `CommandExec::parse`, `CommandArgvSlot::parse`, and `CommandSpec::new` return `Result<..., CommandContractError>` without an `# Errors` section naming which variants each can produce, though callers match on them (tests assert exact variants) | fix: add a one-line `# Errors` per constructor naming its `CommandContractError` variants | [packages/d2b-provider-command/src/command.rs:38, packages/d2b-provider-command/src/command.rs:89, packages/d2b-provider-command/src/command.rs:192] | actionable | lane/tail-2.md + +**`d2b-provider-config-nixos`** + +- `RS-0672` | low | `d2b-provider-config-nixos` | none of the ~14 public `Result`-returning APIs carry a `# Errors` section, so callers cannot learn which `ConfigError` variants each returns without reading the implementation (lib.rs:6 denies missing_docs but only the one-liners exist) | fix: add `# Errors` to `GuestSessionEvidence::new`, `GuestConfigDocument::new`, `ConfigSyncResponse::document`, `ConfigStageRequest::document`, the five `ConfigStagingStore` methods, `GuestConfigReader::new`, and the two `ConfigService` methods | [packages/d2b-provider-config-nixos/src/controller.rs:45-64, packages/d2b-provider-config-nixos/src/service.rs:359-475, packages/d2b-provider-config-nixos/src/ttrpc.rs:52-72] | actionable | lane/d2b-provider-config-nixos.md + +**`d2b-provider-credential`** + +- `RS-0673` | low | `d2b-provider-credential` | the two Result-returning public items lack the canonical `# Errors` section: `CredentialRevocationRequest::new` states its failure condition only in prose (session.rs:128-131) and `CredentialSession::revoke_credential` documents no failure conditions at all (session.rs:273-274) | fix: add `# Errors` sections naming `CredentialResourceRuntimeError::InvalidResource` (zero/unknown session generation, zero rotation generation, foreign Provider) and the `Revocation` variant respectively | [packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/session.rs:275] | actionable | lane/d2b-provider-credential.md + +**`d2b-provider-credential-entra`** + +- `RS-0674` | low | `d2b-provider-credential-entra` | no public item carries a canonical `# Errors` section although ~30 pub items return `Result` (EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, reject_*); `#![deny(missing_docs)]` guarantees presence, not the failure contract | fix: add `# Errors` sections naming the returned error variant (e.g. InvalidConfig, InvalidPlacement, InvalidEndpoint, InvalidConsumer, DeadlineExceeded) to the Result-returning pub constructors | [packages/d2b-provider-credential-entra/src/controller.rs:47, packages/d2b-provider-credential-entra/src/lib.rs:502, packages/d2b-provider-credential-entra/src/lib.rs:565, packages/d2b-provider-credential-entra/src/lib.rs:1049] | actionable | lane/d2b-provider-credential-entra.md + +**`d2b-provider-credential-managed-identity`** + +- `RS-0675` | low | `d2b-provider-credential-managed-identity` | Public `Result`-returning items document failures only in prose and carry no `# Errors` sections (e.g. `ManagedIdentityClientConfig::new`, `ManagedIdentityPlacement::new`, `ImdsEndpointAlias::parse`, `ManagedIdentityCredentialProviderFactory::new`, controller projections) | fix: add `# Errors` sections naming the specific `ManagedIdentityProviderError`/`CredentialServiceError`/`CredentialObservabilityError` variant each failure returns | [lib.rs:449, lib.rs:514, lib.rs:592, lib.rs:796] | actionable | lane/d2b-provider-credential-managed-identity.md + +**`d2b-provider-credential-secret-service`** + +- `RS-0676` | medium | `d2b-provider-credential-secret-service` | public Result-returning constructors/projections lack `# Errors` sections naming which condition yields which error (despite `#![deny(missing_docs)]` forcing presence, no canonical section exists anywhere in the crate) | fix: add `# Errors` to `SecretServiceConfig::new`, `SecretServicePlacement::new`, `SecretServiceCredentialProviderFactory::new`, `SecretServiceController::reconcile` (and the remaining pub Result items) naming `SecretServiceProviderError`/`CredentialServiceError` failures | [packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-credential-secret-service/src/lib.rs:610, packages/d2b-provider-credential-secret-service/src/lib.rs:1140, packages/d2b-provider-credential-secret-service/src/controller.rs:73] | actionable | lane/d2b-provider-credential-secret-service.md +- `RS-0677` | low | `d2b-provider-credential-secret-service` | the one-second session-close revoke deadline is a bare magic `1_000` triplicated with no why (it bounds revoke of potentially many leases during disconnect/finalize/drain) | fix: extract `const SESSION_CLOSE_REVOKE_DEADLINE_MS: u64 = 1_000;` and document why (one-second cap so a stalled backend cannot hang session teardown foreve) | [packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-credential-secret-service/src/service.rs:674, packages/d2b-provider-credential-secret-service/src/service.rs:684] | actionable | lane/d2b-provider-credential-secret-service.md + +**`d2b-provider-device-gpu`** + +- `RS-0678` | medium | `d2b-provider-device-gpu` | no `# Errors` section on any pub `Result`-returning item despite the crate denying missing_docs, so the failure contract is undocumented | fix: add `# Errors` naming the failure branches to new_authorized/reconcile_lifecycle/adopt_lifecycle/finalize_lifecycle/validate/from_core/generate_gpu_argv/generate_video_argv/GpuWorkerSpec::gpu/VideoWorkerSpec::new/GpuProcessDeclaration::new/select_processes/gpu_process_name/GpuOwnerProof::new/GpuAuthorityAdmission::new/with_video_principal | [packages/d2b-provider-device-gpu/src/controller.rs:172, packages/d2b-provider-device-gpu/src/settings.rs:78, packages/d2b-provider-device-gpu/src/gpu_argv.rs:158] | actionable | lane/d2b-provider-device-gpu.md +- `RS-0679` | low | `d2b-provider-device-gpu` | module-level `#![allow(missing_docs)]` in the two argv modules overrides the crate-wide deny, leaving the pub `as_str` methods undocumented | fix: drop both allows and add doc comments to `GpuContextType::as_str` and `VideoBackend::as_str` | [packages/d2b-provider-device-gpu/src/gpu_argv.rs:24, packages/d2b-provider-device-gpu/src/video_argv.rs:22, packages/d2b-provider-device-gpu/src/gpu_argv.rs:40, packages/d2b-provider-device-gpu/src/video_argv.rs:103] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-device-security-key`** + +- `RS-0681` | medium | `d2b-provider-device-security-key` | no `# Errors` section exists on any of the 24 public `Result`-returning items, and the lease/controller state-machine failures are the non-obvious kind the section exists for (`SessionConflict` vs `InvalidTransition` vs `AuthorizationDenied` vs `Effect`) | fix: add `# Errors` sections naming the returned variants to `SecurityKeyLease::{acquire, acquire_authorized, rebind_authorized, complete, cancel, expire}` and `SecurityKeyController::{new, new_authorized, child_resources, child_resources_for_user, acquire, acquire_authorized, rebind_authorized, complete}` | [packages/d2b-provider-device-security-key/src/lease.rs:150-303, packages/d2b-provider-device-security-key/src/controller.rs:162-186, packages/d2b-provider-device-security-key/src/controller.rs:209-267] | actionable | lane/d2b-provider-device-security-key.md +- `RS-0680` | low | `d2b-provider-device-security-key` | `#![allow(missing_docs)]` at relay.rs:7 defeats the crate-root `#![deny(missing_docs)]` for a pub module re-exported at the root, letting undocumented items ship: `CidTranslator::new` (relay.rs:144), `LeaseId::as_u64` (relay.rs:209), and the pub fields of `CtaphidInitPacket`/`CtaphidContPacket` (relay.rs:54-66) | fix: document the handful of items and drop the module-level allow | [packages/d2b-provider-device-security-key/src/relay.rs:7, packages/d2b-provider-device-security-key/src/relay.rs:144, packages/d2b-provider-device-security-key/src/relay.rs:209] | actionable | lane/d2b-provider-device-security-key.md + +**`d2b-provider-device-tpm`** + +- `RS-0682` | low | `d2b-provider-device-tpm` | Result-returning public items never enumerate their error variants: 47 `-> Result<` items (build_tpm_state_volume_spec, build_swtpm_process_spec, build_swtpm_flush_spec, generate_swtpm_argv, generate_swtpm_ioctl_flush_argv, TpmResourceController::new/reconcile/finalize, SwtpmSettings::validate, reconcile_device_tpm_controller, finalize_device_tpm_controller) carry one-line docs but no `# Errors` section, while the crate's doc standard is otherwise high (#![deny(missing_docs)] plus module docs) | fix: add `# Errors` sections naming the TpmResourceEffectError/TpmResourceControllerError/SwtpmArgvError variants each item can return | [resources.rs:53, swtpm_argv.rs:130, resource_controller.rs:132, resource_controller.rs:190] | actionable | lane/d2b-provider-device-tpm.md +- `RS-0683` | low | `d2b-provider-device-tpm` | swtpm_argv.rs:39 `#![allow(missing_docs)]` is redundant: every pub item in the module is already documented and the crate root denies missing docs, so the opt-out lets a future undocumented pub item pass silently | fix: remove the module-level allow | [swtpm_argv.rs:39] | actionable | lane/d2b-provider-device-tpm.md + +**`d2b-provider-device-usbip`** + +- `RS-0684` | medium | `d2b-provider-device-usbip` | `#![allow(missing_docs)]` in reconcile_state.rs:6 and state_machine.rs:61 contradicts the crate's `#![deny(missing_docs)]` (lib.rs:9), leaving root-re-exported pub items without doc contracts (`UsbipPolicyFailure::telemetry_label`, `UsbipEventSource::vm`/`component`, `UsbipReconcileCorrelationId::new`, `UsbipClaimSource::is_explicit`, `UsbipExecutionReport::is_ok`, `UsbipBusidPlan::stop_order`) | fix: document the pub items and drop the two module-level allows | [reconcile_state.rs:6, state_machine.rs:61, lib.rs:9] | actionable | lane/d2b-provider-device-usbip.md +- `RS-0685` | medium | `d2b-provider-device-usbip` | Result-returning public items have no `# Errors` section anywhere in the crate, so callers cannot learn the closed failure sets from the docs | fix: add `# Errors` sections naming the variants to `UsbipArbitrator::new`, `BusId::parse`, `UsbipBindingContext::new`, `UsbipBindingController::new`, `build_usbip_plan`, `execute_usbip_plan`, `admit_bind_bus_class`, `binding_child_resources` | [arbitration.rs:76, busid.rs:12, broker.rs:61, controller.rs:210] | actionable | lane/d2b-provider-device-usbip.md + +**`d2b-provider-display-wayland`** + +- `RS-0687` | low | `d2b-provider-display-wayland` | `FilterInput::allow_globals` and `FilterInput::deny_globals` doc comments say "Add an allowed global to this layer" / "Add a denied global to this layer" but the methods are getters returning `&[String]` | fix: reword to "Borrow the allowed globals of this layer" / "Borrow the denied globals of this layer" | [src/policy.rs:114, src/policy.rs:119] | actionable | lane/d2b-provider-display-wayland-p2.md +- `RS-0686` | low | `d2b-provider-display-wayland` | public Result-returning items lack `# Errors` sections describing which conditions fail: `BridgeConfig::from_identity_parts`, `path_for_user_identity`, `parse_filter`, and the three `ReadinessReporter` methods | fix: add `# Errors` sections naming `BridgeConfigError` variants, the parse failure modes, and the io errors | [packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:73, packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:162, packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs:30] | actionable | lane/d2b-provider-display-wayland-p1.md +- `RS-0688` | low | `d2b-provider-display-wayland` | Result-returning pub API has no `# Errors` canonical sections despite `#![deny(missing_docs)]`: constructors and reconcilers document their failure modes only through the error-enum variant docs | fix: add `# Errors` sections naming the variants on the pub Result items, e.g. `DisplayIdentity::new`, `WaylandSessionSpec::new`, `WaylandPolicy::compile`, `DisplayController::reconcile_authenticated_session` | [src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759] | actionable | lane/d2b-provider-display-wayland-p2.md + +**`d2b-provider-guest`** + +- `RS-0689` | low | `d2b-provider-guest` | No public Result-returning item carries a canonical `# Errors` doc section (docs2 seed = 0 hits src), despite #![deny(missing_docs)]]and ~107 Result-returning pub items | fix: add `# Errors` headings naming the refusal conditions on the trait/fn contracts ((facets.rs:63, target_control.rs:95, driver.rs:403, target_service.rs:68 etc.) | [packages/d2b-provider-guest/src/facets.rs:63, packages/d2b-provider-guest/src/target_control.rs:95, packages/d2b-provider-guest/src/driver.rs:403, packages/d2b-provider-guest/src/target_service.rs:68] | actionable | lane/d2b-provider-guest.md + +**`d2b-provider-guest-azure-container-apps`** + +- `RS-0690` | low | `d2b-provider-guest-azure-container-apps` | `#[allow(missing_docs)]` blanket-exempts the effects module whose pub surface (AcaControl and AcaCredentialLeaseClient trait methods, AcaProviderConfig fields, Aca*Error enums, MAX_ACA_* constants) is re-exported at the crate root, undercutting the crate's own `#![deny(missing_docs)]` | fix: document the effect trait methods and validated-config accessors and drop the module-level allow (README.md already carries the prose contract, so this is rustdoc-surface work, not a contract gap) | [src/lib.rs:7, src/effects.rs:813-882] | actionable | lane/d2b-provider-guest-azure-container-apps.md + +**`d2b-provider-guest-azure-virtual-machine`** + +- `RS-0691` | medium | `d2b-provider-guest-azure-virtual-machine` | Result-returning public methods carry no `# Errors` sections, so the framework caller cannot learn from docs which failures are transient/retryable vs fatal: `reconcile`, `adopt`, `poll_operation`, `update`, `finalize`, `complete_enrollment`, `restore_recovery_state` (controller/mod.rs:333-760), `BootstrapPsk::from_bytes`, `BootstrapAdmission::consume` (bootstrap.rs:15,82), `DataDiskSpec::validate`, `AzureVmConfig::validate`, `AzureVmGuestSettings::validate` (config.rs:49,103,177) | fix: add `# Errors` sections naming the `AzureVmError` variants each call returns, especially the `Transient` vs fatal split | [src/controller/mod.rs:333, src/controller/mod.rs:446] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md +- `RS-0692` | low | `d2b-provider-guest-azure-virtual-machine` | `BootstrapPsk::matches` does not document the constant-time comparison guarantee that justifies its index loop over max(len) with zero-padding | fix: document "constant-time in the presented length; never exits early on mismatch" (the security contract of the loop shape) | [src/bootstrap.rs:25] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md + +**`d2b-provider-guest-cloud-hypervisor`** + +- `RS-0693` | low | `d2b-provider-guest-cloud-hypervisor` | no canonical `# Errors`/`# Examples` sections exist anywhere in the crate (seed 2 = 0) although 114 pub items return `Result<`; e.g. `GuestSetupDescriptor::from_canonical_bytes` (descriptor.rs:423) and `GuestChildBatch::from_descriptor` (identity.rs:590) document neither failure conditions nor a usage example | fix: add `# Errors` sections to the wire-boundary constructors first (descriptor.rs, identity.rs, health.rs), then the remaining Result-returning pub items | [descriptor.rs:423-429, identity.rs:590-634] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0694` | medium | `d2b-provider-guest-qemu-media` | None of the 41 `-> Result<` items carry a `# Errors` section (seed2 =0 ( (e.g. `DeviceAdmission::validate` has 6 failure kinds (device_watch.rs:82-90), `QemuMediaController::reconcile` 8 (reconcile.rs:338), `LaunchTicket::new` 3 (process_builder.rs:221) ), `QmpSession::negotiate` 3 (qmp/mod.rs:199) (leaving the caller to read the enum to map conditions | fix: add `# Errors` sections naming which conditions produce which variants on the non-obvious pub Result APIs | [packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs:82, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:338, packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:221, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:199] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-notification-desktop`** + +- `RS-0695` | medium | `d2b-provider-notification-desktop` | No `# Errors` section exists on any Result-returning pub item (112 `-> Result<` sites) even though the crate pins wire-leaning error enums | fix: add `# Errors` sections naming the exact variants (or stable slugs) on pub fns like `ActionNonceStore::register`, `NotificationRuntime::new`, `NotificationSink::deliver_from_guest_source` | [packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provider-notification-desktop/src/runtime.rs:64-67, packages/d2b-provider-notification-desktop/src/host_sink.rs:297-305] | actionable | lane/d2b-provider-notification-desktop.md +- `RS-0696` | low | `d2b-provider-notification-desktop` | Doc first sentences are broken fragments: "/// the daemon." opens `deliver_evidence`,"/// completes every effect immediately." opens `RecordingEffects`,"/// the current authenticated reconnect generation." runs into the `from_config_at_generation` doc | fix: rewrite each as a standalone 15-word summary before the trailing paragraph | [packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-notification-desktop/src/test_support.rs:14, packages/d2b-provider-notification-desktop/src/guest_source.rs:17] | actionable | lane/d2b-provider-notification-desktop.md + +**`d2b-provider-observability-otel`** + +- `RS-0697` | medium | `d2b-provider-observability-otel` | the three crate-identity constants `PROVIDER_NAME`,`PROVIDER_REF`,`PROVIDER_API_MAJOR` in lib.rs lack doc comments while every sibling public item in the crate carries one | fix: add one-line doc comments naming each constant's role (mirroring the documented `OTEL_HOST_BRIDGE_ROLE` on the next line) | [lib.rs:13, lib.rs:14, lib.rs:15] | actionable | lane/d2b-provider-observability-otel.md +- `RS-0698` | medium | `d2b-provider-observability-otel` | Result-returning pub API fns lack `# Errors` doc sections naming their failure conditions, leaving callers to infer variants from code | fix: add `# Errors` sections to at least the five representative fns (ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream,EmitterSocket::bind/drain_once, validate_resource_attributes),enumerating e.g. `ProviderAgentError::{SessionDenied,AuditBackpressure,InvalidInput}` | [agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131] | actionable | lane/d2b-provider-observability-otel.md + +**`d2b-provider-operation`** + +- `RS-0699` | low | `d2b-provider-operation` | public `Result`-returning constructors `OperationAudit::new`, `AuditJoin::new`, `OperationFds::new`, `OperationBounds::new`, and `OperationSpec::new` return `Result<..., OperationContractError>` without `# Errors` sections naming which variants each can produce, though callers match exact variants (tests assert them) | fix: add a one-line `# Errors` per constructor naming its `OperationContractError` variants | [packages/d2b-provider-operation/src/operation.rs:138, packages/d2b-provider-operation/src/operation.rs:194, packages/d2b-provider-operation/src/operation.rs:347, packages/d2b-provider-operation/src/operation.rs:405] | actionable | lane/tail-2.md + +**`d2b-provider-process`** + +- `RS-0700` | low | `d2b-provider-process` | no `# Errors` or `# Panics` canonical sections exist on any of the crate's 142 Result-returning items, so the failure contract of the public surface is prose-only | fix: add `# Errors` sections naming the closed codes to the public Result-returning items, starting with `ProcessEffectBackend::launch` (which closed codes each operation can raise) and `resolve_launch_identity` (which `LaunchIdentityError` variants are possible) | [packages/d2b-provider-process/src/backend.rs:256, packages/d2b-provider-process/src/launch_identity.rs:64] | actionable | lane/d2b-provider-process.md + +**`d2b-provider-process-minijail`** + +- `RS-0701` | low | `d2b-provider-process-minijail` | public Result-returning items carry no `# Errors` section stating which conditions produce which `ProcessConformanceError` variant | fix: add `# Errors` to `PlatformGate::validate`, `validate_launch_ticket`, `launch_with_inherited_fds`, `adopt`, `stop`, and `stop_stale` (the shared catalog is `d2b_process_conformance::ProcessConformanceError`) | [packages/d2b-provider-process-minijail/src/launch.rs:33, packages/d2b-provider-process-minijail/src/launch.rs:46, packages/d2b-provider-process-minijail/src/lib.rs:313, packages/d2b-provider-process-minijail/src/lib.rs:371] | actionable | lane/tail-3.md + +**`d2b-provider-process-systemd`** + +- `RS-0702` | medium | `d2b-provider-process-systemd` | public `Result`-returning items lack `# Errors` sections naming their failure conditions: `SystemdProviderConfig::new` (OutOfRange bounds), `drain::validate` (two refusal variants), `SystemdProcessController::reconcile` (DeadlineExceeded), `validate_launch_ticket`, `SystemdSandboxCompiler::compile` | fix: add `# Errors` sections to each, stating which inputs produce which failure | [packages/d2b-provider-process-systemd/src/lifecycle.rs:33, packages/d2b-provider-process-systemd/src/drain.rs:30, packages/d2b-provider-process-systemd/src/controller.rs:66, packages/d2b-provider-process-systemd/src/launch.rs:8] | actionable | lane/d2b-provider-process-systemd.md + +**`d2b-provider-provider`** + +- `RS-0703` | low | `d2b-provider-provider` | the eight `pub` fields of `ProviderObservation` are undocumented while every other pub item in the crate carries a doc comment | fix: add one-line field docs (or a struct-level contract explaining each gate) at providers.rs:72-79 | [src/providers.rs:72, src/providers.rs:79] | actionable | lane/d2b-provider-provider.md + +**`d2b-provider-role`** + +- `RS-0704` | low | `d2b-provider-role` | role's lib.rs lacks the `#![deny(missing_docs)]` gate that its four sibling declaration crates in this lane all carry (quota lib.rs:16, resource-export lib.rs:14, resource-import lib.rs:14, minijail lib.rs:25), and `PolicyRevisionSet`'s four pub fields are undocumented | fix: add `#![deny(missing_docs)]` to lib.rs and document the `PolicyRevisionSet` fields | [packages/d2b-provider-role/src/lib.rs:1, packages/d2b-provider-role/src/rbac.rs:11] | actionable | lane/tail-3.md + +**`d2b-provider-seccomp-profile`** + +- `RS-0705` | medium | `d2b-provider-seccomp-profile` | the crate's two public Result-returning constructors carry no `# Errors` section, and their failure conditions are non-obvious (byte-length bound, control characters, `/dev` prefix; syscall/device list bounds) | fix: add `# Errors` sections to `DeviceNodePath::parse` and `SeccompProfileSpec::new` naming the three `SeccompProfileContractError` variants each can return | [packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:31, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:176] | actionable | lane/tail-4.md + +**`d2b-provider-shell-terminal`** + +- `RS-0706` | medium | `d2b-provider-shell-terminal` | the ~30 `pub fn` items returning `Result<_, ShellTerminalError>` (e.g. `Authorizer::authorize_request`, `OpenSessionRequest::new`, `PoolSpec::new`, `ShellSession::from_pool`, `restore_pool`, `reconcile_pool_attachments`, `restore_session`, `restart_supervisor`, `open_session`, `finalize_session`, `AttachRequest::new`, `OutputRing::new`, `SupervisorIdentity::new`, `ShellAuthorityLedger::validate_session`) lack an `# Errors` section naming which variants they emit. | fix: add an `# Errors` section to each Result-returning pub item enumerating the `ShellTerminalError` variants that item can return (e.g. `restore_pool`: `# Errors` `CapacityExceeded` when pool name already projected or the authority rejects the restore). | [src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/ring.rs:16] | actionable | lane/d2b-provider-shell-terminal.md + +**`d2b-provider-system-core`** + +- `RS-0707` | medium | `d2b-provider-system-core` | public Result-returning items carry no `# Errors` sections, and some fail non-obviously (`HostProbeSnapshot::new` rejects control characters and >64/128-byte strings with `HostProbeFailed`; `MinijailPlatformGate::validate` maps kernel/cgroup failures to two distinct variants) | fix: add `# Errors` sections to validate, HostProbeSnapshot::new, reject_operator_status_fields, reconcile/reconcile_observed/reconcile_with_probe, UserReconciler::reconcile, and the two effect ports' methods | [src/host.rs:121, src/host.rs:161, src/user.rs:241] | actionable | lane/d2b-provider-system-core.md + +**`d2b-provider-toolkit`** + +- `RS-0708` | low | `d2b-provider-toolkit` | key `Result`-returning public items document no failure conditions: `ProviderEntrypoint::new` (InvalidName), `admit` (NotAccepting), the three `with_*` binders, and `StartupPlan::derive`/`declare` (MissingInput/DuplicateOutput/Cycle) have one-line docs with no `# Errors` section or prose naming the refusal, so callers must read the error enum to learn when construction fails | fix: add `# Errors` sections (or one prose sentence naming the refusal) to the entrypoint constructors and the plan derivation | [packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/src/base/runtime.rs:383-384, packages/d2b-provider-toolkit/src/base/startup.rs:39] | actionable | lane/d2b-provider-toolkit-p1.md +- `RS-0709` | low | `d2b-provider-toolkit` | no public item in the scope carries the canonical `# Errors` section even though many return `Result` with closed, non-obvious failure sets (`check_descriptor_conformance` has ten `ConformanceError` variants; `operation_deadline` fails on exhausted deadlines; `validate_attachment_indexes` fails on non-monotone indexes) | fix: add `# Errors` sections naming the variant per condition to the Result-returning pub items, starting with conformance.rs:267, conformance.rs:291, credential.rs:111, credential.rs:131, adapter.rs:31 | [packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolkit/src/testing/conformance.rs:291, packages/d2b-provider-toolkit/src/credential.rs:111, packages/d2b-provider-toolkit/src/credential.rs:131] | actionable | lane/d2b-provider-toolkit-p2.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0710` | low | `d2b-provider-transport-azure-relay` | none of the 80 Result-returning public items carries a canonical `# Errors` section (docs2 = 0 crate-wide), so failure conditions are discoverable only by reading the error enums; e.g. `mint_sas`, `build_connect`, `CreditWindow::new`, `RelayTransportSettings::new` | fix: add `# Errors` sections naming the conditions (mint_sas: InvalidTtl, TtlTooLong, InvalidEndpoint, InvalidCredential, Key, Clock) on the pub Result items | [packages/d2b-provider-transport-azure-relay/src/auth.rs:229-246, packages/d2b-provider-transport-azure-relay/src/backpressure.rs:31-36, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:18-22] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-transport-unix`** + +- `RS-0711` | low | `d2b-provider-transport-unix` | the three inherent pub methods returning `Result` (`open`, `close`, `observe`) lack `# Errors` sections naming which conditions produce which `PortalError` variant, though the failure conditions are recoverable from the enum docs | fix: add `# Errors` sections to the three doc comments | [packages/d2b-provider-transport-unix/src/portal.rs:197-201, packages/d2b-provider-transport-unix/src/portal.rs:266, packages/d2b-provider-transport-unix/src/portal.rs:286] | actionable | lane/tail-5.md + +**`d2b-provider-transport-vsock`** + +- `RS-0712` | low | `d2b-provider-transport-vsock` | 38 public `Result`-returning items carry no `# Errors` doc sections, so callers must infer from doc prose which condition yields which failure variant - the crate's `#![deny(missing_docs)]` (lib.rs:3) secures only first sentences, not the canonical contract sections. | fix: add `# Errors` bullet lists naming the failure variant per condition to the public Result-returning items (e.g. `GuestIdentity::new`, `SessionAuthority::authenticate`, `VsockTransportSettings::new`, `ZoneLinkSpec::validate`, `open_transport`, `NativeGuestRelay::start`) | [packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsock/src/auth.rs:257, packages/d2b-provider-transport-vsock/src/settings.rs:31, packages/d2b-provider-transport-vsock/src/service.rs:383] | actionable | lane/d2b-provider-transport-vsock.md + +**`d2b-provider-volume-binding`** + +- `RS-0713` | low | `d2b-provider-volume-binding` | the four public Result-returning seam methods state no # Errors section (which conditions fail and how the driver classifies them): facets.rs SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, driver.rs BindingDriverEffects::remove_socket/guest_mount_ready | fix: add # Errors to each naming the daemon-adapter failure conditions and the fail-closed handling | [packages/d2b-provider-volume-binding/src/facets.rs:52, packages/d2b-provider-volume-binding/src/facets.rs:65, packages/d2b-provider-volume-binding/src/driver.rs:307-310, packages/d2b-provider-volume-binding/src/driver.rs:325-330] | actionable | lane/d2b-provider-volume-binding.md + +**`d2b-provider-volume-local`** + +- `RS-0714` | low | `d2b-provider-volume-local` | no canonical doc sections exist anywhere in the crate (seed 2 = 0 hits): public Result-returning items such as ContentFile::new, ContentProjection::new/from_value, EntryRequest::resolve, VolumeLocalController::reconcile, admit_attachments and validate_source_spec carry one-line docs but no `# Errors` section naming which conditions produce which failure | fix: add `# Errors` sections to the admission/parse constructors and the controller entry points, listing the closed VolumeLocalError variants each can return | [src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92] | actionable | lane/d2b-provider-volume-local.md + +**`d2b-provider-zone`** + +- `RS-0715` | low | `d2b-provider-zone` | the inherent pub `SystemCoreStatusEmitter::emit` returns `Result` (zone_status.rs:113-114) without an `# Errors` section naming the contract-rejection condition | fix: add an `# Errors` section stating that duplicate system-core handler records or a rejected `ZoneStatusResource` yield `ZoneStatusProjectionError::Contract` | [packages/d2b-provider-zone/src/zone_status.rs:110-114] | actionable | lane/tail-5.md + +**`d2b-provider-zone-link`** + +- `RS-0716` | low | `d2b-provider-zone-link` | 21 public `Result`-returning items document their failure modes only in prose, with zero `# Errors` sections, so the error contract (which `ZoneLinkError` variant fires) is not in the canonical place a caller reads | fix: add `# Errors` sections naming the `ZoneLinkError`/`ZoneLinkAdoptionError` variants to the public `Result` items, starting with `ZoneLinkLimits::new`, `ZoneLinkHandler::{begin,commit,release_effects,issue_route_admission}`, `ZoneLinkRecord::{with_route_binding,encode_route_admission_dedup,with_route_admission_dedup}`, `ZoneLinkOwnerProof::{new,from_digest}`, `ZoneLinkCursorAuthority::{adopt,cursor}` | [packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src/zone_links.rs:1300, packages/d2b-provider-zone-link/src/zonelink.rs:197] | actionable | lane/d2b-provider-zone-link.md + +**`d2b-resource-api`** + +- `RS-0718` | medium | `d2b-resource-api` | nine pub methods on the evaluator surface are undocumented, including `NativeAuthorizer::authorize` (the security decision entry returning nine AuthorizationDenial variants) and `take_store_seal` (which hands off an ownership-bearing seal acceptor) | fix: add doc comments with `# Errors` sections enumerating the denial variants on authorize, and one-line contracts on the remaining eight | [packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, packages/d2b-resource-api/src/authz.rs:912, packages/d2b-resource-api/src/authz.rs:1093] | actionable | lane/d2b-resource-api-p2.md +- `RS-0717` | medium | `d2b-resource-api` | pub `Result`-returning items carry no `# Errors` sections stating which conditions produce which failure: the `ResourceService` constructors (StoreBindingError cases), `ResourceStoreBackend` methods (StoreError classes), the frame helpers (`attach_scoped_commit_frame`/`attach_scoped_query_frame`/`reject_scoped_commit_frame`), `manager_row_stored`, and `admit_guest_lifecycle` | fix: add `# Errors` sections naming the failure classes (binding already taken, invalid frame, unsupported capability, envelope invalid) | [service.rs:198, store.rs:39, adapter.rs:71, manager_backend.rs:625] | actionable | lane/d2b-resource-api-p1.md merged: d2b-resource-api-p1#10 + +**`d2b-resource-client`** + +- `RS-0719` | low | `d2b-resource-client` | 50 Result-returning pub items carry no `# Errors` section (zero `# Examples|Errors|Panics|Safety` sections anywhere in the crate), so callers must infer failure conditions from prose | fix: add `# Errors` to the public Result-returning entry points (MetadataInput::new, RetryPolicy::new, CallDriver::new, ZoneClient::connect, ZoneClient::call_connected, ZoneClient::scoped_commit_batch, ProcessAttachClient::attach) | [packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:131, packages/d2b-resource-client/src/zone_client.rs:711, packages/d2b-resource-client/src/process_attach.rs:648] | actionable | lane/d2b-resource-client.md + +**`d2b-resource-runtime`** + +- `RS-0720` | medium | `d2b-resource-runtime` | `ResourceManagerClient`, the crate-root re-exported caller-facing facade consumed by d2bd and the resource API, has 14 undocumented pub methods (`new`, `actor`, `apply`, `ensure`, `remove`, `get`, `list`, `watch`, `get_row`, `list_owned`, `ensure_child`, `register_watch`, `cancel_watch`, `reconcile_children`) with non-obvious contracts (watch gap-free-epoch semantics, ensure-child re-parent refusal, watch routing) | fix: add doc comments with `# Errors` sections naming the `ResourceError` variants each call can return | [packages/d2b-resource-runtime/src/manager.rs:1500, packages/d2b-resource-runtime/src/manager.rs:1519, packages/d2b-resource-runtime/src/manager.rs:1597] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0721` | low | `d2b-resource-runtime` | `ResourceManagerArgs` fields `store`, `providers`, and `backoff` are undocumented while the sibling fields all carry doc comments | fix: one line each (the store is the single-writer spec store, providers the per-type registry, backoff the R13 fixed reconcile backoff) | [packages/d2b-resource-runtime/src/manager.rs:850, packages/d2b-resource-runtime/src/manager.rs:851, packages/d2b-resource-runtime/src/manager.rs:870] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0722` | low | `d2b-resource-runtime` | five `MODULE_NAME` consts (`manager`, `resource`, `error`, `provider`, `revision`) are undocumented while `metadata`'s carries a doc line | fix: add the one-line "module declared name, asserted by the crate smoke test" doc (or fold into the A5 decision on the whole const set) | [packages/d2b-resource-runtime/src/manager.rs:51, packages/d2b-resource-runtime/src/resource.rs:36, packages/d2b-resource-runtime/src/error.rs:32, packages/d2b-resource-runtime/src/provider.rs:3] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0723` | low | `d2b-resource-runtime` | TargetControlAssignment's five methods (new, source, source_uid, assignment_generation, session_generation) are the only wire-carried type accessors without doc comments while sibling wire types (TargetResourceInstance, GuestRealizeRequest, TargetControlFrame) document every method | fix: add one-line docs to each | [packages/d2b-resource-runtime/src/guest_target.rs:205-228] | actionable | lane/d2b-resource-runtime-p2.md +- `RS-0724` | low | `d2b-resource-runtime` | constructor and accessor doc gaps on public items | fix: add one-line docs to ResourceTypeName::new/as_str, ResourceKey::new, ResourceProvenance::as_str, GuestTargetRuntime::new, TargetBinding::new, GuestTargetHandle::is_bound, SpecStore::path | [packages/d2b-resource-runtime/src/identity.rs:20, packages/d2b-resource-runtime/src/identity.rs:24, packages/d2b-resource-runtime/src/spec_store.rs:61, packages/d2b-resource-runtime/src/spec_store.rs:75] | actionable | lane/d2b-resource-runtime-p2.md + +**`d2b-resource-types`** + +- `RS-0725` | low | `d2b-resource-types` | doc comment typos in `OperationCtx::fds` ("invocation,when any", "frame,not to the handler; the handler") | fix: restore the missing spaces after the commas in the field docs | [packages/d2b-resource-types/src/operation.rs:64, packages/d2b-resource-types/src/operation.rs:65] | actionable | lane/tail-6.md + +**`d2b-session`** + +- `RS-0726` | medium | `d2b-session` | the security-critical handshake module has zero doc comments on its entire pub surface (23 pub items re-exported from lib.rs): wire functions with magic lengths and closed error codes (`x25519_public_key`, `encode_offer`, `negotiate_offer`, `accept_generation_discovery_request`, `decode_generation_discovery_response`, `NoiseHandshake`, `EstablishedHandshake`, `HandshakeCredentials`, `NegotiatedOffer`) carry no first-sentence contract, no `# Errors`, no `# Panics` | fix: add first-sentence docs plus `# Errors` sections naming the `SessionErrorCode` each function returns, and `# Panics` where a step mismatch panics | [handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239] | actionable | lane/d2b-session-p1.md +- `RS-0728` | medium | `d2b-session` | the whole public surface of lifecycle.rs, record.rs, bootstrap.rs, and deadline.rs is undocumented, including non-obvious state machines such as SessionLifecycle::poll_keepalive and begin_reconnect | fix: add item docs with # Errors sections on the Result-returning methods | [lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62] | actionable | lane/d2b-session-p2.md +- `RS-0727` | low | `d2b-session` | the magic bound `value.len() > 128` in `OperationMember::parse` is undocumented: the reader cannot tell why 128 is the canonical member spelling limit or what happens to longer wire strings | fix: extract `const MAX_MEMBER_SPELLING_LEN: usize = 128;` with a comment naming the bound's purpose (wire-visible admission bound) | [operation.rs:207] | actionable | lane/d2b-session-p1.md +- `RS-0729` | low | `d2b-session` | the route-binding accessors on AuthenticatedSessionRouteBinding, the SessionError accessors, and the TransportPacket methods are undocumented while their siblings carry docs | fix: add one-line docs to the accessors at the anchors | [admission.rs:1182, admission.rs:1186, admission.rs:1190, admission.rs:1194] | actionable | lane/d2b-session-p2.md +- `RS-0730` | low | `d2b-session` | serialized_transport_split's doc claims it exists for engine-only test transports, but production code in d2b-bus and the crate's own driver call it | fix: rewrite the doc to state the serialized-compatibility contract (halves must never be driven concurrently) | [transport.rs:208, transport.rs:212] | actionable | lane/d2b-session-p2.md + +**`d2b-session-unix`** + +- `RS-0731` | medium | `d2b-session-unix` | the exported surface is largely undocumented: the transport, credit, descriptor, pidfd, systemd and vsock types and most of their pub methods carry no doc comment (only `VerifiedUnixPeer`, `ZoneBootstrapIdentity` and a handful of methods do) | fix: add first-sentence contract docs per pub item, starting with `SeqpacketSocket`, `UnixSeqpacketTransport`/`UnixStreamTransport`, `CreditPool`, `PidfdEvidence`, `PeerCredentials`, `ActivatedSeqpacketListener`, `FramedVsockTransport` | [packages/d2b-session-unix/src/socket.rs:190, packages/d2b-session-unix/src/adapter.rs:351, packages/d2b-session-unix/src/credit.rs:22, packages/d2b-session-unix/src/pidfd.rs:9] | actionable | lane/d2b-session-unix.md +- `RS-0732` | low | `d2b-session-unix` | zero canonical `# Errors` sections exist despite roughly 60 pub `Result`-returning fns whose failure conditions are non-obvious (e.g. `SeqpacketSocket::from_owned` vs `from_parent_prearmed` vs `from_inherited_fd` fail differently) | fix: add `# Errors` sections naming the failing conditions to the pub `Result` fns | [packages/d2b-session-unix/src/socket.rs:202, packages/d2b-session-unix/src/socket.rs:210, packages/d2b-session-unix/src/socket.rs:222, packages/d2b-session-unix/src/adapter.rs:378] | actionable | lane/d2b-session-unix.md + +**`d2b-telemetry`** + +- `RS-0733` | low | `d2b-telemetry` | Result-returning public items carry no `# Errors` section stating which conditions produce which failure | fix: add `# Errors` sections to `AuditHash::parse` (audit_hash.rs:23), `AuditChainLink::verify`/`verify_at` (audit_hash.rs:103,126), `BoundedEmitter::new`/`new_with_limits`/`with_default_capacity`/`emit`/`emit_metric`/`drain`/`buffered_frames`/`buffered_bytes` (emitter.rs:183,194,228,236,316,340,385,395), `MetricFamily::new`/`record`, `MeterRegistry::register`/`record`, `RedactionGuard::new`/`validate_span_field`/`span_attributes`, `validate_resource_attributes`, and `SessionMetricsSink::record` | [packages/d2b-telemetry/src/emitter.rs:236, packages/d2b-telemetry/src/audit_hash.rs:23] | actionable | lane/d2b-telemetry.md + +**`d2b-zone-routing`** + +- `RS-0734` | low | `d2b-zone-routing` | The crate's 47 `-> Result<` public signatures document failure modes in prose paragraphs (e.g., `SealedZoneTopology::seal`, `ZoneServiceLimits::new`, `ZoneEnrollmentAuthority::with_lifetime`) but zero canonical `# Errors`/`# Panics` sections exist anywhere, so rustdoc index and IDEs lose a scannable contract | fix: add a `# Errors` section to the public validators/constructors that enforce conditions (seal, the `Limits`/`Expectation`/`Authority` constructors, `with_runtime_admission`), keeping the prose as depth beneath it | [packages/d2b-zone-routing/src/resolver.rs:80, packages/d2b-zone-routing/src/service.rs:208, packages/d2b-zone-routing/src/enrollment.rs:424] | actionable | lane/d2b-zone-routing.md + +**`d2bd`** + +- `RS-0736` | medium | `d2bd` | `pub async fn serve`, the daemon's primary entry point (composition.rs is `include!`d into lib.rs:183),has no doc comment at all, and `pub async fn lock_only` has none either; both return `Result` and carry no `# Errors` contract, so callers cannot learn from the docs what each loads/binds/runs and how it fails | fix: add a doc comment to `serve` (loads config, applies overrides, binds the operator socket, runs the accept loop; `# Errors` for config/IO/authz failures) and to `lock_only` | [packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828] | actionable | lane/d2bd-p4.md +- `RS-0741` | medium | `d2bd` | `pub fn dispatch_audio` is the only `pub` item in the lane without a doc comment; it is the daemon's audio dispatch entry with three op arms and non-obvious error behavior | fix: add a doc comment covering the op arms, the capability resolution, and the `TypedError` error surface | [packages/d2bd/src/audio_dispatch.rs:372] | actionable | lane/d2bd-p8.md +- `RS-0737` | low | `d2bd` | `StaticProviderComposition::new` is a pub constructor returning `Result` with no doc comment and no `# Errors` section, so the mode_separation.rs callers must read the body to learn it fails on `AdmissionError` | fix: one-line doc plus a `# Errors` section naming `AdmissionError` | [packages/d2bd/src/composition.rs:438] | actionable | lane/d2bd-p4.md +- `RS-0738` | low | `d2bd` | four public items in the plane's most-documented file are undocumented while their siblings carry `///` contracts: `PlaneResourceRegistry::new()`, `ZoneAuthorityInputs::controller_generation`, and the three fields of `BundleIngestReport` | fix: add the one-line contract each (constructor convenience, the zone authority's controller generation source, and per-field "the rows this ingestion applied/removed/protected") | [packages/d2bd/src/resource_plane_v3.rs:292, packages/d2bd/src/resource_plane_v3.rs:1770, packages/d2bd/src/resource_plane_v3.rs:3432] | actionable | lane/d2bd-p6.md +- `RS-0739` | low | `d2bd` | the crate root carries no `//!` module doc: lib.rs opens with the lint attribute only, and the included composition.rs begins with a plain `//` comment, so the crate's large public surface (pub mods, dozens of pub use re-exports) renders without any module-level description | fix: add a `//!` crate doc in lib.rs naming the daemon composition facets and pointing at the daemon contract references | [packages/d2bd/src/lib.rs:1, packages/d2bd/src/composition.rs:1] | actionable | lane/d2bd-p7.md +- `RS-0735` | low | `d2bd` | the public-request get deadline literal `meta.deadline_ms = 30_000` appears four times (8294, 8390, 10242, 10280) with no comment naming the why (which peer or operation enforces it) | fix: extract `const PUBLIC_GET_DEADLINE_MS: u64 = 30_000;` with a why-comment and use it at all four sites | [packages/d2bd/src/resource_runtime.rs:8294, packages/d2bd/src/resource_runtime.rs:8390, packages/d2bd/src/resource_runtime.rs:10242, packages/d2bd/src/resource_runtime.rs:10280] | actionable | lane/d2bd-p1.md +- `RS-0740` | low | `d2bd` | no canonical `# Errors`/`# Panics` section exists anywhere in the part (0 hits) while `-> Result<` appears 121 times, including on the pub surface (`FixedEffectAdapter::validate_instance`, `dispatch`, `ProviderLifecycleDispatch::new_persistent`, `admit`, `EffectServiceBinding::call`/`call_expected`, `DaemonGuestTargetSession::request`); prose paragraphs describe the happy path but failure conditions are not structurally stated | fix: add `# Errors` sections naming refusal conditions to the pub Result-returning items of the two pub mods, keeping the existing prose | [packages/d2bd/src/provider_effects.rs:91, packages/d2bd/src/provider_effects.rs:711, packages/d2bd/src/provider_effects.rs:804, packages/d2bd/src/effect_service_actors.rs:201] | actionable | lane/d2bd-p7.md +- `RS-0742` | low | `d2bd` | doc-comment shape drift in forward_rendezvous.rs first sentences: double trailing periods and missing spacing (`The received descriptors,borrowed across the invocation..`, `attached:count equal`, `...kind the carrier vocabulary does not carry..`, `awaited for readiness..`) | fix: normalize punctuation/spacing in the affected comments | [packages/d2bd/src/forward_rendezvous.rs:1046-1049, packages/d2bd/src/forward_rendezvous.rs:1070, packages/d2bd/src/forward_rendezvous.rs:1093, packages/d2bd/src/forward_rendezvous.rs:1431-1432] | actionable | lane/d2bd-p8.md + +**`d2bd-runtime`** + +- `RS-0743` | medium | `d2bd-runtime` | Three public helpers in json_io.rs carry no doc comments, though their semantics are non-obvious (absolute-vs-relative bundle path resolution, manifest-must-be-object) | fix: add one-line-then-detail doc comments (`# Errors` for the Result fns)on resolve_bundle_artifact_path and load_manifest | [json_io.rs:10, json_io.rs:41] | actionable | lane/d2bd-runtime-p1.md +- `RS-0747` | medium | `d2bd-runtime` | unsafe_local_helper.rs has no `//!` module doc and its public surface (consts `HELPER_HEARTBEAT_INTERVAL`/`HELPER_STALE_AFTER`/`HELPER_OPERATION_TIMEOUT`, enums `HelperRegistryError`/`HelperAvailability`/`HelperReply`, struct `HelperRegistry` + its seven pub methods) carries no doc comments, unlike every sibling module in this crate | fix: add a `//!` header (lifecycle, wire protocol, thread model, redaction rules) and one-line `///` docs per pub item | [packages/d2bd-runtime/src/unsafe_local_helper.rs:1, packages/d2bd-runtime/src/unsafe_local_helper.rs:33, packages/d2bd-runtime/src/unsafe_local_helper.rs:42, packages/d2bd-runtime/src/unsafe_local_helper.rs:65] | actionable | lane/d2bd-runtime-p3.md +- `RS-0744` | medium | `d2bd-runtime` | Public fns in vm_start_support.rs lack docs while siblings are documented; role->mode mapping, tracked_role_id, and store-view-intent resolution are contract-relevant for the d2bd composition | fix: add one-line-first-sentence docs (+ `# Errors` for the Result fn)on vm_start_node_mode, tracked_role_id, resolve_store_view_intent_for_guest | [vm_start_support.rs:14, vm_start_support.rs:44, vm_start_support.rs:89] | actionable | lane/d2bd-runtime-p1.md +- `RS-0748` | medium | `d2bd-runtime` | public exec-session DTO fields lack doc comments on a cross-crate contract surface (`ExecStartSpec.vm/argv/tty/detached/env/cwd/term_size`, `ExecSessionInfo.tty/stdout_offset/stderr_offset`, `Established.client/info/control_seq/caps`, `WorkerSpawn.connector/spec/deadlines/establish_tx/control_rx`), while sibling fields (`request_id`, `NegotiatedCaps.*`, `TerminalReaper`/`SessionSlot` fields) are documented | fix: add `///` per field (semantics plus any redaction/derivation promise), especially what `control_seq`/`establish_tx` carry | [packages/d2bd-runtime/src/exec_session.rs:181, packages/d2bd-runtime/src/exec_session.rs:211, packages/d2bd-runtime/src/exec_session.rs:249, packages/d2bd-runtime/src/exec_session.rs:882] | actionable | lane/d2bd-runtime-p3.md +- `RS-0749` | medium | `d2bd-runtime` | readiness.rs exposes seven undocumented pub predicates/functions (`readiness_predicate_ready`, `unix_socket_exists`, `unix_socket_listening`, `tcp_port_ready`, `wait_for_tcp_port`, `command_ready`, `readiness_predicate_ready_async`) whose contracts are non-obvious (e.g. `unix_socket_listening` parses `/proc/net/unix` flags;`command_ready` strips `NOTIFY_SOCKET`), while `api_socket_info_ready`/`wait_for_readiness_async` do carry `///` | fix: add one-line `///` first sentences + `# Errors` notes on the `Result<_, String>` shapes | [packages/d2bd-runtime/src/readiness.rs:15, packages/d2bd-runtime/src/readiness.rs:78, packages/d2bd-runtime/src/readiness.rs:85, packages/d2bd-runtime/src/readiness.rs:103] | actionable | lane/d2bd-runtime-p3.md +- `RS-0745` | medium | `d2bd-runtime` | Five broker_transport helpers (audit-join extraction, deadline arithmetic, kind extraction, two launcher redaction renderers)carry no docs, and two of them format operator-facing remediation strings | fix: add one-line-first-sentence docs naming input contracts and output shapes, with `# Panics` on default_audit_join_context identified | [broker_transport.rs:60, broker_transport.rs:69, broker_transport.rs:116, broker_transport.rs:128] | actionable | lane/d2bd-runtime-p1.md +- `RS-0746` | low | `d2bd-runtime` | the `has_posix_acl` doc first sentence begins with an unexplained `v1.1.2fu25:` audit-workflow token, and a sibling `P2fu1 ...` workflow tag sits inside an enabled trace field comment list | fix: drop/relocate the workflow tokens so the rendered contract reads plain, keeping the "0440-with-ACL legitimate vs drift" why in the body (it is the good part) | [ssh_host_key_preflight.rs:312, ssh_host_key_preflight.rs:298-301] | actionable | lane/d2bd-runtime-p2.md +- `RS-0750` | low | `d2bd-runtime` | `ch_api.rs` leaves its public constants, error enum, info struct, and async entry points undocumented: `DEFAULT_TIMEOUT`/`MAX_RESPONSE_BYTES` are magic values without the why (contrast `CH_HTTP_TIMEOUT` at ch_stats.rs:120 which cites the legacy exporter), and `ChApiError` variants/`ChVmInfo` fields/`get_vm_info`/`shutdown_vm` have no docs | fix: document the consts with their provenance and add one-line docs to the enum, struct, and fns | [packages/d2bd-runtime/src/ch_api.rs:11, packages/d2bd-runtime/src/ch_api.rs:15, packages/d2bd-runtime/src/ch_api.rs:37, packages/d2bd-runtime/src/ch_api.rs:43] | actionable | lane/d2bd-runtime-p4.md +- `RS-0751` | low | `d2bd-runtime` | `target_runtime.rs` documents its domain types thoroughly but leaves a cluster of pub accessors undocumented: `AdmissionBudget::new/limits/active`, `AdmissionPermit::kind/release`, `ProviderDeployment::mode/target_kind/admission` | fix: add one-line docs (at minimum to `AdmissionPermit::release`, whose idempotence is a caller-relevant contract) | [packages/d2bd-runtime/src/target_runtime.rs:256, packages/d2bd-runtime/src/target_runtime.rs:311, packages/d2bd-runtime/src/target_runtime.rs:354, packages/d2bd-runtime/src/target_runtime.rs:1108] | actionable | lane/d2bd-runtime-p4.md + +**`xtask`** + +- `RS-0755` | medium | `xtask` | Pub field groups on the wire and census record types carry no field-level doc contracts, so units and serialization formats are guesswork | fix: add per-field doc comments to `DeniedApi.path/tail/kind`, `CensusBaseline.crates`, `OutputDigest.sha256/bytes`, `EvidenceRecord.*`, `SealedLane.lane/validations`, `SealedValidation.validation/record_sha256`, `SealRecord.*` | [packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packages/xtask/src/delivery/evidence.rs:120, packages/xtask/src/delivery/evidence.rs:128] | actionable | lane/xtask-p5.md +- `RS-0756` | low | `xtask` | Result-returning pub fns describe failure modes in prose rather than the canonical `# Errors` section | fix: add `# Errors` sections to `parse_fragment`, `EvidenceLane::parse`, `EvidenceRecord::validate`, `SealRecord::validate`, and `async_gate::scan_source` naming each rejection condition | [packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/xtask/src/delivery/evidence.rs:162, packages/xtask/src/delivery/seal.rs:77] | actionable | lane/xtask-p5.md +- `RS-0754` | low | `xtask` | several pub items in the delivery modules lack the doc comment the modules' own discipline gives every sibling item: `WaveSnapshot::digests`/`program`/`wave`, `WaveCommand::as_str`/`parse`/`required_options`/`optional_options`, `WorkflowOutput::ok`/`with_digests`, `WorkflowCommandHelp`, and the `CliOptions` accessors | fix: add one-line doc comments naming each contract (mirroring the sibling wording already present) | [packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, packages/xtask/src/delivery/snapshot.rs:99, packages/xtask/src/delivery/command.rs:104] | actionable | lane/xtask-p3.md +- `RS-0752` | low | `xtask` | doc comments across the policy range carry text-corruption artifacts from an earlier automated rewrite: 20 lines end with a stray `/` after the closing period (`/// ... only shrinking from here./`) and 4+ comments have doubled opening parens (`((its Cargo package name).`, `((an edit to a`), plus the typo `whiche is what`; the artifacts render as odd punctuation in rustdoc and rot the file's readability | fix: mechanical doc cleanup over the file: replace `\./$` with `.` and `((`-doubles with single parens on the doc lines (lines 5360-6556 and 8428, 8640, 8648, 9043) | [packages/xtask/src/provider_crate_policy.rs:5360, packages/xtask/src/provider_crate_policy.rs:8428, packages/xtask/src/provider_crate_policy.rs:9043] | actionable | lane/xtask-p1.md +- `RS-0753` | low | `xtask` | `civil_from_days` (a port of the Howard Hinnant civil-calendar conversion) carries magic constants (719_468, 146_097, 146_096, 36_524, 153) with no citation or why, and `today_utc_iso8601` silently maps a before-epoch clock to epoch via `unwrap_or(0)` | fix: add a doc comment naming the algorithm and its constants, and decide the before-epoch behaviour explicitly (return an error or a documented fallback) | [packages/xtask/src/main.rs:1555, packages/xtask/src/main.rs:1544] | actionable | lane/xtask-p1.md + +### `perf` + +Performance (static unless a benchmark exists): allocation out of hot paths, collection choice, codegen flags as the last five percent. + +**`d2b`** + +- `RS-0771` | medium | `d2b` | every received frame allocates and zeroes a fresh 1 MiB buffer and then copies the payload again, on the interactive shell path where the daemon answers each 50 ms poll round trip | fix: keep a reusable receive buffer (e.g. a Vec field on CliSocket reused across read_frame calls, or a thread-local scratch) so the zeroed 1 MiB allocation happens once, and return the truncated buffer instead of `frame[FRAME_PREFIX_BYTES..].to_vec()` | [context.rs:570, context.rs:538] | actionable | lane/d2b-p1.md + +**`d2b-audit`** + +- `RS-0757` | low | `d2b-audit` | `scan_chain_state` converts each line with `String::from_utf8(bytes)` then `serde_json::from_str`, allocating a String per record during the open-time scan, while `segment_tail_hash` parses the same JSONL shape with `serde_json::from_slice(&line)`; use `from_slice` here too | fix: replace the from_utf8/from_str pair with `serde_json::from_slice(&bytes)` at sink.rs:386-388 | [packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970] | actionable | lane/d2b-audit.md + +**`d2b-broker`** + +- `RS-0762` | medium | `d2b-broker` | recv_json_frame allocates and zeroes a 1 MiB buffer (`MAX_FRAME_SIZE + 4`)per received frame on every broker/client envelope path | fix: peek the 4-byte length prefix (`recvmsg` with `MSG_PEEK`)then allocate `declared + 4` exactly,, or thread a reusable buffer through the receive path; apply the same size-exactness to `recv_json_frame_with_fds` | [packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125] | actionable | lane/d2b-broker-p7.md +- `RS-0759` | low | `d2b-broker` | `projection_digest` builds the hex digest with `raw.iter().map(|byte| format!("{byte:02x}")).collect::()`, allocating one `String` per byte (32 hex bytes) before the final collect | fix: `String::with_capacity(70)` and `write!`/`push_str` each byte, or a 16-entry hex lookup | [packages/d2b-broker/src/ops/nft.rs:784-790] | actionable | lane/d2b-broker-p5.md +- `RS-0760` | low | `d2b-broker` | `handle_open_cgroup_dir` renders `canonical_path.display().to_string()` twice (the audit field at 341 and the outcome at 368) in the same call | fix: bind `let cgroup_id = canonical_path.display().to_string();` once and reuse for both the audit record and `OpenCgroupDirOutcome` | [packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368] | actionable | lane/d2b-broker-p5.md +- `RS-0758` | low | `d2b-broker` | `CellStore` partial-key lookups scan the whole record map: `contains` (state_cells.rs:470), `payload` (488), `remove` (506), `keys` (524) and `clear` (541) iterate `records: BTreeMap` filtering on (cell, invocation_id) because the principal is a key component, making every op O(n) where the durable file already uses the nested cell -> invocation layout | fix: mirror the durable layout in memory (cell -> invocation -> record, principal inside the record) so lookups become O(log n); static (unmeasured) | [packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, packages/d2b-broker/src/state_cells.rs:524] | actionable | lane/d2b-broker-p3.md +- `RS-0761` | low | `d2b-broker` | contract_store_view_levels re-parses the embedded `include_str!` JSON contract (STATE_POSTURE_CONTRACT) on every call (down per-VM posture passes; each row also re-parses the contract via contract_store_view_level, so the same ~600-line document is parsed many times per sync pass. | fix: pre-parse once into a `static CONTRACT: LazyLock` (or `OnceLock`|and resolve per-row levels/profiles from the cached parse, deleting per-call `ContractFile::parse` sites. | [src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/store_view_posture.rs:310-352] | actionable | lane/d2b-broker-p6.md + +**`d2b-bus`** + +- `RS-0763` | low | `d2b-bus` | The WatchSink delivery path copies every watch frame payload with frame.payload().to_vec() before send_and_wait_ack, allocating a fresh Vec per frame on the watch-delivery path (the recorded kept-half credit path, B1, docs/explanation/over-engineering-audit-record.md:463) | fix: pass the payload slice through OutgoingStream::send_and_wait_ack (streams.rs:661) or clone once at the bridge so per-frame allocation is avoided | [packages/d2b-bus/src/router.rs:4228-4235] | actionable | lane/d2b-bus-p1.md +- `RS-0764` | low | `d2b-bus` | `OutgoingStream::send_wait` clones the whole payload on every backpressure wakeup because `StreamBridge::send` consumes the `Vec` and drops it on rejection, so a frame up to `max_frame_bytes` (64 KiB) is re-allocated per retry on the bounded-watch delivery path | fix: have `send` return the rejected payload (for example `Result<(), (StreamError, Vec)>`) or split an admit-check from the enqueue so the loop moves the buffer instead of cloning | [packages/d2b-bus/src/streams.rs:642-658] | actionable | lane/d2b-bus-p2.md + +**`d2b-contracts-resource`** + +- `RS-0765` | low | `d2b-contracts-resource` | `ResourceStatus::new` (resource_status.rs:636-658) serializes the complete status with `canonical_json_bytes(&value)` on every construction to enforce MAX_STATUS_BYTES, after `ensure_layer_size` already serialized the resource layer, so each status write pays two full serializations of the same object | fix: enforce the byte bound once at the write boundary (the caller already serializes for storage) or check the bound with a cheaper size pass; at minimum reuse the layer bytes from `ensure_layer_size` | [packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-resource/src/v3/resource_status.rs:650] | actionable | lane/d2b-contracts-resource-p1.md + +**`d2b-contracts-zone-session`** + +- `RS-0766` | low | `d2b-contracts-zone-session` | ProcessTemplateBinding validation builds a fresh String via format!("/bin/{}", ...) on every construction to run an ends_with check | fix: binary_path.strip_suffix(binary_ref.as_str()).is_some_and(|prefix| prefix.ends_with("/bin/")) which is allocation-free | [resource_bundle.rs:382] | actionable | lane/d2b-contracts-zone-session-p2.md + +**`d2b-core`** + +- `RS-0767` | medium | `d2b-core` | has_zone_uid re-parses every zone resource bundle on each call and zone_uid / find_network_spec re-parse bundle JSON per lookup (ResourceBundle::from_json over raw bytes), while parsed_zone_resources (populated once at load, line 1462) already holds the parsed ResourceBundle per zone | fix: have has_zone_uid, zone_uid, and find_network_spec iterate or index parsed_zone_resources instead of re-parsing bytes | [packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:1647, packages/d2b-core/src/bundle_resolver.rs:1959] | actionable | lane/d2b-core-p1.md +- `RS-0768` | low | `d2b-core` | the nft/hosts renderers build text with `buf.push_str(&format!(...))`, allocating a fresh String per line then copying it into the buffer (render_host_nft_script, render_env_nft_subset, render_hosts_managed_block), and sha256_hex collects 32 per-byte `format!("{b:02x}")` Strings | fix: `write!(&mut buf, ...)` into the existing buffer (std::fmt::Write) and hex-encode into a fixed `[u8; 64]` buffer or a single format call | [packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:3793, packages/d2b-core/src/bundle_resolver.rs:3986, packages/d2b-core/src/bundle_resolver.rs:1009] | actionable | lane/d2b-core-p1.md +- `RS-0769` | low | `d2b-core` | six composite-key lookups allocate two Strings per call (`(zone.to_owned(), guest.to_owned())`) against BTreeMap<(String, String), _> maps (guest_setup_descriptors, guest_setup_descriptor_catalog_keys, guest_vmm_intents, guest_vmm_zone_uids) | fix: introduce a `ZoneGuestKey(String, String)` newtype with a `Borrow<(str, str)>` impl so lookups borrow without allocating, or nest the maps per zone | [packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:1617, packages/d2b-core/src/bundle_resolver.rs:2068, packages/d2b-core/src/bundle_resolver.rs:2087] | actionable | lane/d2b-core-p1.md + +**`d2b-host`** + +- `RS-0770` | low | `d2b-host` | Hex digests are built with `format!("{b:02x}")` per byte, allocating a fresh String per byte (32+ allocations per digest) in `Sha256::of` and `generation_id` | fix: write into one preallocated `String::with_capacity(64)` via `write!`/`fmt::Write`, or share a hex helper | [packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628] | actionable | lane/d2b-host.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0772` | low | `d2b-provider-clipboard-wayland` | clipboard payload maps (up to MATERIALIZE_MAX_BYTES = 8 MiB) are cloned wholesale on the host-selection record, history materialization, and bridge-copy publish paths, copying every byte per paste | fix: hold payloads as Arc>> (or Arc<[u8]> per MIME) in ClipboardHistoryEntry, BridgeSelectionState, and PublishedSelectionState so materialization and publish become refcount bumps; the history-retention clones at 757 and 1043 disappear | [src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2b-clipd.rs:1838] | actionable | lane/d2b-provider-clipboard-wayland-p1.md +- `RS-0773` | low | `d2b-provider-clipboard-wayland` | read_bounded_ndjson_line reads one byte per read() syscall in a loop (up to DEFAULT_NIRI_MAX_LINE_BYTES = 1 MiB iterations for a maximal line), an avoidable syscall-per-byte pattern on the niri IPC path | fix: read into a stack chunk buffer (e.g. 4 KiB) with the same max-line accounting, or wrap the stream in a BufReader | [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159] | actionable | lane/d2b-provider-clipboard-wayland-p2.md merged: d2b-provider-clipboard-wayland-p2#3 + +**`d2b-provider-config-nixos`** + +- `RS-0774` | low | `d2b-provider-config-nixos` | the RPC path parses the request JSON up to three times per call: handler `from_slice` (ttrpc.rs:326), `validate_operation` `from_value` plus the full-document base64 decode for Stage (controller.rs:298-331), and the backend dispatch `from_value` again (ttrpc.rs:81); Stage payloads can reach ~683 KiB base64 | fix: decode the typed request once in `ConfigMethod::handler`, validate the typed value, and pass the original `Value` to the backend hop (removes one parse and the admission-time document decode) | [packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/ttrpc.rs:326, packages/d2b-provider-config-nixos/src/ttrpc.rs:81] | actionable | lane/d2b-provider-config-nixos.md merged: d2b-provider-config-nixos#2 + +**`d2b-provider-display-wayland`** + +- `RS-0775` | low | `d2b-provider-display-wayland` | `durable_display_suffix` (session_children.rs:316-318) builds a 40-char hex suffix with one `format!` allocation per byte (20 allocations) instead of writing into the already-preallocated `String::with_capacity(40)` | fix: push two hex digits per byte via a lookup table or a single hex write into `suffix`, keeping the preallocation | [src/session_children.rs:316, src/session_children.rs:317] | actionable | lane/d2b-provider-display-wayland-p2.md + +**`d2b-provider-guest`** + +- `RS-0776` | low | `d2b-provider-guest` | Two hex-ID builders format a fresh String per byte ((driver.rs:863-868 map(|byte| format!("{byte:02x}")) into a String, effects_service.rs:983-988 push_str(&format!)...)) in a loop), allocating ~16 and ~8 Strings per reconcile pass | fix: write! to one with_capacity String per builder (or a crate-local hex helper reusing the buffer | [packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:868, packages/d2b-provider-guest/src/effects_service.rs:983, packages/d2b-provider-guest/src/effects_service.rs:988] | actionable | lane/d2b-provider-guest.md + +**`d2b-provider-guest-cloud-hypervisor`** + +- `RS-0777` | low | `d2b-provider-guest-cloud-hypervisor` | `child_role_for_ref` (shutdown.rs:505) builds `format!("-{}", role.suffix())` inside the per-role loop, four String allocations per call on the per-child planning path (`plan_upgrade` at controller.rs:2340, `project_status` at controller.rs:2940) | fix: use `name.rsplit_once('-')` and compare the suffix, or a static suffix table | [shutdown.rs:505-513] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0778` | low | `d2b-provider-guest-qemu-media` | `LaunchTicket::new` grows `attachments` by push from a fresh `Vec::new()` with an a-priori known upper bound (up to media_refs.len()+3 slots (packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239-274) | fix: `Vec::with_capacity(media_refs.len() + 3)` ( (static (unmeasured. | [packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-network-local`** + +- `RS-0779` | low | `d2b-provider-network-local` | FirewallDigest::to_hex formats each byte into its own String (32 heap allocations per call), though the output size is known | fix: `let mut out = String::with_capacity(64); for byte in &self.0 { use std::fmt::Write; write!(out, "{byte:02x}").expect("writing to String is infallible"); } out` | [src/nftables.rs:266-268] | actionable | lane/d2b-provider-network-local.md +- `RS-0780` | low | `d2b-provider-network-local` | observed-address parse allocatesa fresh String per entry via `format!("{local}/{prefix}")`, inside the host-observation parse path | fix: build the CIDR text into a reused buffer or add a two-part Ipv4Cidr constructor to the contracts crate | [src/observe.rs:305] | actionable | lane/d2b-provider-network-local.md + +**`d2b-provider-notification-desktop`** + +- `RS-0781` | low | `d2b-provider-notification-desktop` | `NotificationSink::deliver` formats "notification-{id}" once (request_id) but re-formats the same string three more times into projection map keys; `close` re-formats from u32 while callers already hold the request_id string | fix: reuse `request_id` (clone it into map keys where needed)and add an internal `close_by_request_id(&str)` to kill the u32-to-String-to-u32 round-trip in `close_session`/`gc_projections` | [packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-notification-desktop/src/host_sink.rs:276-291, packages/d2b-provider-notification-desktop/src/host_sink.rs:376, packages/d2b-provider-notification-desktop/src/host_sink.rs:484-493] | actionable | lane/d2b-provider-notification-desktop.md + +**`d2b-provider-observability-otel`** + +- `RS-0782` | low | `d2b-provider-observability-otel` | drain_once allocates a fresh 64KiB+1 scratch buffer per datagram inside the drain loop ( <= 256 iterations/call),when one buffer reused across recv calls would suffice | fix: hoist `let mut bytes = vec![0_u8; MAX_COMPACT_FRAME_BYTES + 1];` above the while loop,and `bytes.resize(MAX_COMPACT_FRAME_BYTES + 1, 0)` per iteration; the queued redacted frame remains its own owned Vec from redact_parsed_frame | [emitter_socket.rs:139] | actionable | lane/d2b-provider-observability-otel.md +- `RS-0783` | low | `d2b-provider-observability-otel` | admit_for_connection re-measures every frame by re-serializing the whole MetricFrame to JSON(allocating a Value tree plus a String per admission),though the wire-boundary paths already carry `encoded_bytes` | fix: thread the canonical measured size through from the decode boundary (admit_raw/admit_parsed/metric_frame_from_raw) instead of re-calling measured_encoded_bytes in admit_for_connection, preserving the documented trustless measurement at the boundary(ingress_policy.rs:202-203)rather than per admission | [ingress_policy.rs:203, ingress_policy.rs:368] | actionable | lane/d2b-provider-observability-otel.md +- `RS-0784` | low | `d2b-provider-observability-otel` | valid_resource_attribute_value allocates a lowercase copy of each attribute value(`to_ascii_lowercase()`)on the per-frame resource-attribute validation path,only to substring-test six words | fix: replace the allocation with a case-insensitive byte-scan helper(e.g. a local `contains_ignore_ascii_case(value, word)`)over the already-bounded( <= 256-byte)value | [metric_policy.rs:44] | actionable | lane/d2b-provider-observability-otel.md + +**`d2b-provider-process-systemd`** + +- `RS-0785` | low | `d2b-provider-process-systemd` | `unit_name` builds the hex suffix with `format!` inside a 16-iteration loop (16 small String allocations) plus a final `format!`, on every unit operation that names a unit | fix: write the bytes into the preallocated `String::with_capacity(52)` with `write!` per byte, or format once into a fixed buffer | [packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process-systemd/src/operations.rs:421] | actionable | lane/d2b-provider-process-systemd.md + +**`d2b-provider-toolkit`** + +- `RS-0786` | medium | `d2b-provider-toolkit` | every reconcile and delete pass clones the row's full spec document (`spec: envelope.value().clone()` at shared_provider.rs:944 and 1024) into the request even though the envelope outlives the effect call and the request is only read by the family | fix: change `SharedProviderEffectRequest.spec` from `Value` to `&'a Value` (the struct is constructed only in this file; family call sites read via method calls and auto-deref), removing one full-spec allocation per pass | [packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/src/shared_provider.rs:1024, packages/d2b-provider-toolkit/src/shared_provider.rs:479-481] | actionable | lane/d2b-provider-toolkit-p2.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0787` | medium | `d2b-provider-transport-azure-relay` | `generation_key` allocates three Strings (`to_owned` x3) on every `RelayConnection::send`/`receive` via `ensure_current_generation -> is_current`, and the key is invariant for a connection's lifetime (it derives from the binding the connection already owns) | fix: precompute the `(String, String, String)` key once in `RelayConnection` (or key the fence map on a borrowed/hashed form) and pass it to `is_current`, removing three heap allocations from the per-frame I/O path | [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:629-630, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:814, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:844] | actionable | lane/d2b-provider-transport-azure-relay.md +- `RS-0788` | low | `d2b-provider-transport-azure-relay` | `read_policy_file` grows `Zeroizing::new(Vec::new())` via `read_to_end` without a capacity hint although the file size is already known from the earlier `metadata()` call | fix: `Vec::with_capacity(meta.len() as usize)` before reading | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-volume`** + +- `RS-0789` | low | `d2b-provider-volume` | `reconcile` performs two identical `ctx.children()` manager round-trips per pass:`reconcile_children` already fetched the owned child set after ensures (to retire obsolete),andthen `reconcile` re-fetches the same set to compute `converged` - an extra manager RPC per reconcile pass | fix: have `reconcile_children` return the fetched `Vec` (or compute the converged verdict inside)and consume it there | [driver.rs:437-440, driver.rs:614-617] | actionable | lane/d2b-provider-volume.md + +**`d2b-resource-api`** + +- `RS-0791` | medium | `d2b-resource-api` | `commit_mutation` clones the full canonical resource (up to 256 KiB) on every UpdateSpec/UpdateMetadata before the byte-identical no-op check, so a no-op update pays the whole copy | fix: compare `mutation.canonical_resource.as_deref() == Some(row.spec.as_slice())` first and return the committed view early, cloning only when the bytes actually differ | [manager_backend.rs:1006] | actionable | lane/d2b-resource-api-p1.md +- `RS-0792` | medium | `d2b-resource-api` | `owner_key_for` resolves a mutation's owner by listing the entire Zone row set (`manager.list(ResourceSelector::default())`) and linear-searching for the owner uid, on every Delete and every owner-less UpdateSpec/UpdateMetadata/UpdateFinalizers | fix: expose a manager-side uid-to-key lookup on `ResourceManagerClient` (d2b-resource-runtime) or return the owner key from `get_row`, and call it instead of the full-zone list | [manager_backend.rs:1081-1103, manager_backend.rs:1090] | actionable | lane/d2b-resource-api-p1.md +- `RS-0793` | low | `d2b-resource-api` | `compile_authorization_facts` grows its roles and bindings Vecs by push although the row count is known upfront | fix: `Vec::with_capacity(rows.len())` for both | [packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458] | actionable | lane/d2b-resource-api-p2.md +- `RS-0790` | low | `d2b-resource-api` | `encode_list_cursor` hex-encodes each cursor key byte with a per-byte `format!("{byte:02x}")` allocation, and duplicates the hex encoder already present as the local `hex` closure in `list_selector_digest` | fix: extract one `fn hex(bytes: &[u8]) -> String` (with `String::with_capacity(bytes.len() * 2)` and `write!`/`char::from_digit`) and call it from both sites | [manager_backend.rs:495, manager_backend.rs:449-455] | actionable | lane/d2b-resource-api-p1.md + +**`d2b-resource-runtime`** + +- `RS-0794` | low | `d2b-resource-runtime` | `reconcile_children`'s obsolete scan clones every owned `StoredDesiredResource` row (spec and metadata byte vectors included) into a `Vec` when only the keys are needed to drive `remove_internal` | fix: collect `row.key.clone()` only, or iterate `state.rows` by reference and call `remove_internal(&subject, &child.key)` | [packages/d2b-resource-runtime/src/manager.rs:1390] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0795` | low | `d2b-resource-runtime` | hex rendering allocates a fresh String per byte via format! inside the loop at two sites | fix: write!(&mut rendered, "{byte:02x}") with use std::fmt::Write into the pre-sized String | [packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/guest_target.rs:1212] | actionable | lane/d2b-resource-runtime-p2.md + +**`d2b-session`** + +- `RS-0796` | low | `d2b-session` | unprotect allocates a fresh plaintext buffer sized to the limit and copies the payload out with to_vec on every received record | fix: keep a reusable scratch buffer on RecordProtector and return plaintext.split_off(RECORD_HEADER_LEN) instead of payload.to_vec() | [record.rs:125, record.rs:147] | actionable | lane/d2b-session-p2.md +- `RS-0797` | low | `d2b-session` | flush copies every dequeued logical frame with as_bytes().to_vec() because OutboundFrame only exposes a borrowed view | fix: add OutboundFrame::into_bytes() in scheduler.rs and consume it in flush | [engine.rs:1354, engine.rs:1362, scheduler.rs:72] | actionable | lane/d2b-session-p2.md +- `RS-0798` | low | `d2b-session` | the replay cache is a VecDeque scanned linearly with contains() on every received record | fix: use a bounded HashSet<[u8; 32]> or document why the 1024-entry linear scan is acceptable | [record.rs:120, record.rs:146] | actionable | lane/d2b-session-p2.md + +**`d2b-session-unix`** + +- `RS-0799` | low | `d2b-session-unix` | burst and collector `Vec`s grow from empty with an exact known upper bound, reallocating on the way | fix: `Vec::with_capacity(fairness_budget)` in `recv_burst`/`send_burst` and `Vec::with_capacity(attachments.len())` in `send_packet` | [packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, packages/d2b-session-unix/src/adapter.rs:540] | actionable | lane/d2b-session-unix.md + +**`d2bd`** + +- `RS-0800` | medium | `d2bd` | three arms of `CloudHypervisorResourceSession::call` compute an operation id that is immediately discarded: `UpdateSpec` (2360-2364), `UpdateStatus` (2489-2505, `let _ = &operation_id`), and `DeleteChild` (2856-2859, `let _operation_id`) each build `operation_payload` and run a full SHA-256 `canonical_digest` plus a `format!` allocation that no caller reads - this runs on every provider status/spec update, i.e. every reconcile pass | fix: delete the dead digest/format computation and the `let _` bindings in all three arms | [packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, packages/d2bd/src/resource_runtime.rs:2505, packages/d2bd/src/resource_runtime.rs:2856] | actionable | lane/d2bd-p1.md +- `RS-0801` | low | `d2bd` | `resource_identity_fields` builds a `Vec` with exactly 12 statically-known pushes on every launch/adoption pass but grows from an empty `Vec::new()` | fix: `let mut fields = Vec::with_capacity(12);` (6 required + 6 optional entries) | [packages/d2bd/src/process_provider_runtime.rs:333] | actionable | lane/d2bd-p7.md +- `RS-0802` | low | `d2bd` | `AsyncSeqpacket::read_frame` allocates a fresh `vec![0u8; MAX_FRAME_SIZE + 5]` (1 MiB) per read, and `drain_pending` performs up to four such reads per refused call; the frame is length-prefixed, so the read buffer can be sized from the 4-byte prefix (or drained onto a reused buffer) instead of the full ceiling | fix: read the prefix, then allocate `declared + 5` | [packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476-1481] | actionable | lane/d2bd-p8.md +- `RS-0803` | low | `d2bd` | grow-by-push vectors with known upper bounds: `guest_uids = Vec::new()` (bound `spec.attachments().len()`) and `entries`/`errors = Vec::new()` (bound `vm_names.len()`) | fix: `Vec::with_capacity()` | [packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.rs:392-396] | actionable | lane/d2bd-p8.md merged: d2bd-p8#4 + +**`d2bd-runtime`** + +- `RS-0804` | low | `d2bd-runtime` | load_list/load_status clone the entire cached serde_json::Value frame per call (`then(|| cached.value.clone())`), making every public status/list poll allocate a full copy of the read-model frame | fix: return `Option>` (or `&Value` tied to the Arc swap guard)from load_if_fresh and let the wire renderer borrow the Value; update the d2bd composition call sites | [public_read_model.rs:117-118] | actionable | lane/d2bd-runtime-p1.md + +**`xtask`** + +- `RS-0808` | low | `xtask` | `contains_quoted_field` allocates two `format!`'d quoted literals per field per quote inside the per-line redaction scan, up to 8 small String allocations per log line | fix: frame the four credential field names once per `redact_text` call (or as module `const` literals( and pass `&[&str]` framed forms to `contains_quoted_field` so the per-line scan only does `.contains)...)` | [packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packages/xtask/src/bazel_evidence.rs:407] | actionable | lane/xtask-p5.md +- `RS-0805` | low | `xtask` | `message_only_proto` calls `trimmed.starts_with(&format!("service {service_name} "))` inside the per-line loop, allocating a String on every line of the proto file when the prefix never changes | fix: hoist `let marker = format!("service {service_name} ");` (or compare `trimmed.strip_prefix("service ")` then the name) above the loop | [packages/xtask/src/main.rs:431] | actionable | lane/xtask-p1.md +- `RS-0806` | low | `xtask` | `repo_root()` returns `Ok(Box::leak(path.into_boxed_path()))`, so every successful call leaks a heap allocation and re-scans env vars and parent directories; it is called by nearly every command handler | fix: cache the result once, e.g. `static ROOT: OnceLock<&'static Path>` (std, no dependency) computed on first call | [packages/xtask/src/main.rs:582] | actionable | lane/xtask-p1.md +- `RS-0807` | low | `xtask` | `render_schema(&RootSchema)` clones the entire schema document (large `serde_json::Value` trees for the 19 `schema_for!` documents) only to override `meta_schema` before serializing | fix: have `write_schemas` take ownership of the `Vec<(&str, RootSchema)>` and mutate each schema in place (callers already hold the schemas by value from `schema_documents()`) | [packages/xtask/src/main.rs:972] | actionable | lane/xtask-p1.md + +### `conc` + +Concurrency model from workload shape: data parallelism, scoped threads, channels, shared state last; weakest correct ordering. + +**`X3-cross-crate-duplication`** + +- `RS-0960` | medium | `X3-cross-crate-duplication` | parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-census-baseline.json, `parking_lot::Mutex::lock: 0` for every crate) key on the path `parking_lot::Mutex::lock`, which never resolves because `parking_lot::Mutex` is a type alias (`pub type Mutex = lock_api::Mutex`), so unsuppressed lock sites in 10+ crates record zero hits and no per-site allow is demanded | fix: configure the disallowed entry and the census DeniedApi list on the resolved path (`lock_api::Mutex::lock`, or the def-path clippy reports for the alias), then re-run the census so the unsuppressed sites surface and get per-site allows or conversions per the KD3 ban | [clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-security-key/src/relay_service.rs:129] | policy-confirmed | lane/X3-cross-crate-duplication.md + +**`d2b-broker`** + +- `RS-0809` | low | `d2b-broker` | the invocation-id counter uses `Ordering::AcqRel` (`self.invocations.fetch_add(1, Ordering::AcqRel)`), but no reader of the counter or its derived id synchronizes on it - the returned old value is consumed only by the calling thread/audit record, so Relaxed is the weakest correct ordering. | fix: use `Ordering::Relaxed` at src/envelope/mod.rs:1146 (and at the test double's `observed.fetch_add` at src/envelope/mod.rs:2144). | [src/envelope/mod.rs:1146, src/envelope/mod.rs:2144] | actionable | lane/d2b-broker-p6.md + +**`d2b-bus`** + +- `RS-0810` | low | `d2b-bus` | RouteLeaseState wraps a single bool in Mutex, paying a lock for one flag that an atomic would serve | fix: replace revoked: Mutex with AtomicBool and use Acquire/Release in with_active and remove | [packages/d2b-bus/src/registry.rs:522-523, packages/d2b-bus/src/registry.rs:573-582] | actionable | lane/d2b-bus-p1.md + +**`d2b-contracts-provider`** + +- `RS-0811` | low | `d2b-contracts-provider` | `SensitiveDeliveryRecord` uses `Ordering::SeqCst` for per-byte loads and stores that have no release/acquire pairing with any other atomic, so the strongest ordering buys nothing | fix: use `Ordering::Relaxed` in `copy_to`, `clear`, and `is_zeroized` | [packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-provider/src/v3/credential/service.rs:963, packages/d2b-contracts-provider/src/v3/credential/service.rs:977] | actionable | lane/d2b-contracts-provider-p1.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0812` | low | `d2b-provider-clipboard-wayland` | the two permit counters use Acquire/AcqRel orderings where Relaxed is the weakest correct ordering, since neither counter publishes any data (the permit and descriptor ownership move by value) | fix: switch FdPermitPool.active and HELPER_THREADS to Ordering::Relaxed for load, CAS, and fetch_sub | [src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96] | actionable | lane/d2b-provider-clipboard-wayland-p1.md + +**`d2b-provider-credential`** + +- `RS-0813` | medium | `d2b-provider-credential` | `parking_lot::Mutex` is used throughout the test-support recorder and test fixtures (test_support.rs:18,30,41-46,97-113,159,233-249; driver.rs:1053,1074-1075,1109-1172; session.rs:315,429) despite the recorded outright ban whose only exception is the R4 bounded-worker boundary, and the impl methods holding most `.lock()` calls carry no per-site `#[allow(clippy::disallowed_methods)]` even though the test fns do (`reason = "cfg(test) helper"`, the sanctioned form) | fix: switch the recorder locks to `tokio::sync::Mutex` per the clippy.toml replacement column, or record a test-support exception in the policy and add the sanctioned per-site allows to the impl methods; the `// async-gate-allow: test-support recorder lock` markers (30 sites, async-gate-inventory.json) are recorded exceptions and are not re-flagged | [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/src/test_support.rs:97, packages/d2b-provider-credential/src/driver.rs:1109, clippy.toml:40] | policy-confirmed | lane/d2b-provider-credential.md + +**`d2b-provider-device-gpu`** + +- `RS-0814` | medium | `d2b-provider-device-gpu` | `parking_lot::Mutex::lock` on the shared `gpu_authority_leases` cache is off the KD3 exception list (only the R4 bounded-worker boundary is exempt) and carries no per-site `#[allow(clippy::disallowed_methods)]` unlike the same file's drive_sync | fix: add the sanctioned per-site allow `reason = "synchronous path"` at the three lock sites (or record the site in the provider-crate-policy exception list); the clippy.toml:82 replacement (`tokio::sync::Mutex`) is wrong on this pure-synchronous path | [packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-gpu/src/effects_service.rs:310, packages/d2b-provider-device-gpu/src/effects_service.rs:445, packages/d2b-provider-device-gpu/src/effects_service.rs:454] | policy-confirmed | lane/d2b-provider-device-gpu.md + +**`d2b-provider-device-security-key`** + +- `RS-0815` | medium | `d2b-provider-device-security-key` | 14 `parking_lot::Mutex::lock` sites (8 production-path in relay_service.rs:129,281,489,497,527,532,592,599 and 6 in the test-support-gated test_support.rs:32,43,44,55,78,89) carry no `#[allow(clippy::disallowed_methods, reason = "...")]` attribute, while the committed blocking-census baseline records `parking_lot::Mutex::lock = 0` for this crate and parking_lot is banned outright by clippy.toml (KD3) with only the R4 worker boundary exempt - the census bookkeeping and the manifest's recorded `disallowed_methods = "deny"` level disagree with the source, and the `// async-gate-allow:` markers cover only the async-gate scanner, not the clippy/census side | fix: add the sanctioned per-site allows (`reason = "synchronous path"`) or convert the short critical sections to the clippy.toml-named `tokio::sync::Mutex` replacement, then regenerate the census baseline to match | [packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-device-security-key/src/relay_service.rs:281, packages/d2b-provider-device-security-key/src/relay_service.rs:489-599, packages/d2b-provider-device-security-key/src/test_support.rs:32-89] | actionable | lane/d2b-provider-device-security-key.md merged: d2b-provider-device-security-key#6,d2b-provider-device-security-key#7 + +**`d2b-provider-device-usbip`** + +- `RS-0816` | low | `d2b-provider-device-usbip` | `test_support.rs` recorders use `parking_lot::Mutex` (fields at 25/27/29/70/72, `.lock()` at 35/46-47/58-59/82/93) with no per-site allow, but parking_lot is banned outright with the single R4 bounded-worker exception | fix: replace with `tokio::sync::Mutex` (the clippy.toml-named replacement) or add the sanctioned `cfg(test) helper` per-site allow | [test_support.rs:25, test_support.rs:35, Cargo.toml:30] | policy-confirmed | lane/d2b-provider-device-usbip.md + +**`d2b-provider-guest`** + +- `RS-0817` | medium | `d2b-provider-guest` | GuestStatusSink ((a pub type re-exported at lib.rs:42)is Arc>>, injecting the banned parking_lot lock type into this crate's and d2bd's public signatures; the production write sites carry recorded "synchronous path"/async-gate allows,,but every future sink caller inherits the banned type | fix: replace with Arc>>and convert the write sites to .lock().await per the replacement vocabulary | [packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, packages/d2b-provider-guest/src/effects_service.rs:1443] | policy-confirmed | lane/d2b-provider-guest.md +- `RS-0818` | medium | `d2b-provider-guest` | The test-support recorder doubles and the driver test harnesses hold recorder/queue state in parking_lot::Mutex fields, which the ban covers for tests too (KD4 uniform rule,,and no per-site clippy allow exists at these sites | fix: convert to tokio::sync::Mutex with async accessors (or the documented blocking-seat helpers for worker-thread-only callers),,keeping the recorded async-gate-allow marks until converted | [packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_support.rs:171, packages/d2b-provider-guest/src/driver.rs:1534, packages/d2b-provider-guest/src/driver.rs:1761] | policy-confirmed | lane/d2b-provider-guest.md + +**`d2b-provider-process`** + +- `RS-0819` | medium | `d2b-provider-process` | production `parking_lot::Mutex` fields in `EphemeralRuntime` (`started_at`, `completed`) are a live use of a banned primitive with no per-site allow, and the lock calls run on the actor's executor thread | fix: switch the two fields to `tokio::sync::Mutex` (the already-named replacement) or `std::sync::Mutex` with the same short critical sections; requires the parking_lot ban carve-out to be re-opened otherwise | [packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.rs:682] | policy-confirmed | lane/d2b-provider-process.md +- `RS-0820` | low | `d2b-provider-process` | `RestartBudget`, `EphemeralRuntime.started`, and `DurableRuntime.watching` use `Ordering::SeqCst` for plain counters and flags that publish no other data, so the strongest ordering buys nothing over `Relaxed` | fix: switch the 16 `Ordering::SeqCst` sites in driver.rs to `Ordering::Relaxed` (no paired acquire/release handoff exists; the actor and the spawned launch task only gate on these flags) | [packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.rs:451, packages/d2b-provider-process/src/driver.rs:458, packages/d2b-provider-process/src/driver.rs:462] | actionable | lane/d2b-provider-process.md + +**`d2b-provider-system-core`** + +- `RS-0821` | low | `d2b-provider-system-core` | `ScriptedDiscoveryPort.calls: Mutex` (testing.rs:43) uses a tokio::sync::Mutex for a counter - the crate's only tokio use - and `call_count` (testing.rs:79) silently reports 0 on contention via try_lock | fix: `AtomicU32` with `fetch_add`/`load` (Relaxed) and drop `tokio = { workspace = true, features = ["sync"] }` from Cargo.toml | [src/testing.rs:43, src/testing.rs:79] | actionable | lane/d2b-provider-system-core.md + +**`d2b-provider-toolkit`** + +- `RS-0822` | low | `d2b-provider-toolkit` | `invocations.fetch_add(1, Ordering::AcqRel)` uses release-acquire for a monotonic counter nobody synchronizes on; the identifier only needs uniqueness, so `Ordering::Relaxed` is the weakest correct ordering | fix: `fetch_add(1, Ordering::Relaxed)` | [packages/d2b-provider-toolkit/src/operations/envelope.rs:487] | actionable | lane/d2b-provider-toolkit-p1.md + +**`d2b-provider-transport-unix`** + +- `RS-0823` | low | `d2b-provider-transport-unix` | `tokio::sync::Mutex` (portal.rs:18, 155) in a crate with zero async code - every use is `try_lock()` on a synchronous path, so the tokio `sync` feature dependency exists solely for this one lock | fix: use `std::sync::Mutex` (the crate's own `try_lock`-only pattern never awaits) | [packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-unix/src/portal.rs:155] | actionable | lane/tail-5.md + +**`d2b-provider-user`** + +- `RS-0824` | medium | `d2b-provider-user` | the test-support recorder doubles and the driver's test fakes use `parking_lot::Mutex` (banned outright, KD3) at 20 `lock()` call sites with no `#[allow(clippy::disallowed_methods)]` on the enclosing items, while sibling `d2b-provider-host` uses `tokio::sync::Mutex` for the same recorder shape | fix: swap `parking_lot::Mutex` to `tokio::sync::Mutex` in `RecordingEffects`/`ScriptedProbe`/`RecordingManager`/`RecordingRequeue` (or add the sanctioned inline allow with reason "cfg(test) helper" at each site) so the deny-level flip needs no special case | [packages/d2b-provider-user/src/test_support.rs:41-42, packages/d2b-provider-user/src/test_support.rs:108, packages/d2b-provider-user/src/driver.rs:469-470, packages/d2b-provider-user/src/driver.rs:563] | policy-confirmed | lane/d2b-provider-user.md +- `RS-0825` | low | `d2b-provider-user` | the scripted-double flags (`fail`, `absent`, `failing`) use `Ordering::SeqCst` though they are set and read within one test task on a single-threaded `#[tokio::test]` runtime, so the strongest ordering buys nothing | fix: use `Ordering::Relaxed` for the loads/stores in test_support.rs and driver.rs:854, per the weakest-correct-ordering rule | [packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_support.rs:135, packages/d2b-provider-user/src/test_support.rs:140, packages/d2b-provider-user/src/test_support.rs:152] | actionable | lane/d2b-provider-user.md + +**`d2b-provider-volume-binding`** + +- `RS-0826` | low | `d2b-provider-volume-binding` | the production [dependencies] compiles the KD3-banned parking_lot (clippy.toml:82 disallows its lock outright, revocation recorded) solely for the feature-gated/cfg(test) recording doubles, so every production consumer of this crate carries the banned crate in its lockfile; the per-site #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] permits the lock calls but not the manifest posture | fix: swap parking_lot::Mutex -> std::sync::Mutex in FakeServingEffects/RecordingManager/RecordingRequeue (the guards are already statement-scoped, so the sanctioned allows survive unchanged) and drop the Cargo.toml dependency, or gate it behind test-support as an optional dep | [packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-volume-binding/src/driver.rs:1139-1142, clippy.toml:82] | actionable | lane/d2b-provider-volume-binding.md + +**`d2b-resource-client`** + +- `RS-0827` | low | `d2b-resource-client` | `ResourceWatch` models the open/closing/closed stream state with two `Arc` fields (state, closing; zone_client.rs:510-513) where the sibling `ProcessAttachStream` already uses the single `AtomicU8` three-state machine (STREAM_OPEN/CLOSING/CLOSED, process_attach.rs:409-412) | fix: align ResourceWatch onto the same single-atomic state enum | [packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone_client.rs:512, packages/d2b-resource-client/src/zone_client.rs:513, packages/d2b-resource-client/src/process_attach.rs:409] | actionable | lane/d2b-resource-client.md + +**`d2b-resource-runtime`** + +- `RS-0828` | low | `d2b-resource-runtime` | `ActorTimers.next` is a single-owner counter (ractor serializes the actor's handlers) but increments with `Ordering::SeqCst`, the strongest ordering, where `Relaxed` is the weakest correct one for a counter nobody synchronises on | fix: `self.next.fetch_add(1, Ordering::Relaxed)` | [packages/d2b-resource-runtime/src/resource.rs:247] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0829` | low | `d2b-resource-runtime` | parking_lot (banned outright by clippy.toml:40-43, plan KD3, except the R4 worker boundary) is a [dependencies] entry consumed only by #[cfg(test)] code | fix: move parking_lot to [dev-dependencies] or replace the two test uses with std::sync::Mutex | [packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:800, packages/d2b-resource-runtime/src/context.rs:1044] | actionable | lane/d2b-resource-runtime-p2.md + +**`d2b-session`** + +- `RS-0830` | low | `d2b-session` | AuthenticatedSessionDriver._owner is a std::sync::Mutex that is never locked, serving only as a Sync carrier for the ComponentSessionDriver: Send + Sync bound, with no comment saying so | fix: document the Sync-carrier intent on the field or replace it with a named wrapper type | [admission.rs:756, admission.rs:1666, driver.rs:33] | actionable | lane/d2b-session-p2.md + +**`d2b-unsafe-local-helper`** + +- `RS-0831` | low | `d2b-unsafe-local-helper` | the `active` operation counter is a pure admission counter (it bounds MAX_HELPER_QUEUE_DEPTH worker threads and publishes no value; responses travel over the sync_channel, which carries its own synchronization) yet every fetch_add/fetch_sub uses AcqRel | fix: Ordering::Relaxed, the weakest correct ordering for a counter nobody synchronizes on | [packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src/protocol.rs:167, packages/d2b-unsafe-local-helper/src/protocol.rs:195] | actionable | lane/d2b-unsafe-local-helper.md + +**`d2bd`** + +- `RS-0832` | low | `d2bd` | two standalone monotonic counters use stronger orderings than the weakest correct one: the effect-service binding revision does `load(Ordering::SeqCst)` (esa:174) and `fetch_add(1, Ordering::SeqCst)` (esa:509), and `next_desired_generation` uses `fetch_update(Ordering::AcqRel, Ordering::Acquire, ...)` (provider_effects:1064); the revision is a version tag used only in equality staleness checks and the generation is a unique-value mint, so `Ordering::Relaxed` is correct for both | fix: switch the revision load/fetch_add and the generation fetch_update to `Ordering::Relaxed` | [packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs:509, packages/d2bd/src/provider_effects.rs:1064] | actionable | lane/d2bd-p7.md +- `RS-0833` | low | `d2bd` | `Ordering::SeqCst` on the standalone `broker_epoch` atomic (store and load). The epoch is a self-contained value; the zones map it gates is mutex-guarded, so there is no paired publication needing Acquire/Release - `Ordering::Relaxed` is the weakest correct ordering here | fix: use `Ordering::Relaxed` at both sites | [packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414] | actionable | lane/d2bd-p8.md + +**`d2bd-runtime`** + +- `RS-0835` | medium | `d2bd-runtime` | unsafe_local_helper.rs uses `parking_lot::Mutex` for its registry/connection/ledger state (`use parking_lot::Mutex` + 4 `Mutex<...>` field types + 39 `.lock()` call sites), which the repo bans outright outside the R4 dedicated bounded-worker boundary | fix: replace with `tokio::sync::Mutex` reached through the documented blocking-seat patterns this crate already uses (`metrics::Registry::blocking_lock` for worker-thread-only seats, `authority_persistence::lock_sync` try_lock spin where an ambient runtime may exist) | [packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34] | policy-confirmed | lane/d2bd-runtime-p3.md +- `RS-0836` | medium | `d2bd-runtime` | `OpLockManager::acquire` busy-spins (`try_lock` + `std::hint::spin_loop()`) while the per-VM/global lock is held across a whole lifecycle op (composition.rs:5612 holds the guard across `dispatch_request_locked`, i.e. seconds for a VM start), so a concurrent same-VM or global request burns a full core for the op duration; the doc's "critical sections are single map ops" justification covers only the map-entry lock, not the held op lock | fix: replace the spin with the repo's sanctioned wait-on-condition shape (`tokio::sync::Notify` armed before the check + `tokio::time::timeout`, clippy.toml:37-39) or park/wake on the dedicated dispatch threads; requires a policy/ADR decision first | [packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189, packages/d2bd/src/composition.rs:5612] | policy-confirmed | lane/d2bd-runtime-p4.md +- `RS-0834` | low | `d2bd-runtime` | `NewPlaneReadinessState` (resource_runtime_support.rs:144-180) stores four independent readiness booleans with `Ordering::SeqCst` on every store/load; there is no Release/Acquire paired handoff (each flag is an independent published bit) | fix: `Ordering::Relaxed`, which is the weakest correct ordering for independent flags; the cross-thread visibility the startup path needs is already ordered by the join/actor supervision in the daemon, and SeqCst here does not buy snapshot atomicity across the four flags anyway | [resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support.rs:166, resource_runtime_support.rs:170] | actionable | lane/d2bd-runtime-p2.md + +### `async` + +Async correctness: runtime choice, blocking work in async contexts, guards across await, cancellation safety, Send bounds. + +**`d2b-broker`** + +- `RS-0837` | high | `d2b-broker` | `cleanup_spawned_runner_after_failure` performs a blocking `waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED)` (no WNOHANG) at runtime.rs:11815, and is called directly from async `spawn_process` (kernel_ops.rs:919, 955) on the broker's tokio executor; a child stuck in uninterruptible sleep blocks that worker indefinitely, and every sibling reap path in this file is explicitly WNOHANG | fix: bounded WNOHANG poll loop (or spawn_blocking) that preserves the no-live-process-left-behind guarantee; route review-pass | [packages/d2b-broker/src/runtime.rs:11815, packages/d2b-broker/src/kernel_ops.rs:919, packages/d2b-broker/src/kernel_ops.rs:955] | actionable | lane/d2b-broker-p1.md +- `RS-0841` | high | `d2b-broker` | the async `harden()` path (invoked from `live_handlers.rs:3142` on the runtime) calls `apply_ancestor_traverse_acl` -> `run_setfacl_op_on_fd` (sys.rs:1866-1893), which does a synchronous `fork` + `execv(setfacl)` + blocking `waitpid` loop with no `.await` and no `spawn_blocking`, stalling the executor worker for the duration of a subprocess spawn | fix: wrap the setfacl fork/exec/wait in `tokio::task::spawn_blocking` (moving the fd across as `OwnedFd`) and `.await` the join handle in `harden` | [packages/d2b-broker/src/ops/swtpm_dir.rs:770, packages/d2b-broker/src/sys.rs:1866-1893, packages/d2b-broker/src/live_handlers.rs:3142] | actionable | lane/d2b-broker-p5.md +- `RS-0842` | high | `d2b-broker` | write_redacted_registry_index_at_path resolves the fixed d2bd group via nss `Group::from_name` synchronously on an executor worker on every registry write (enroll/refresh/boot) | fix: resolve the gid once (lazy static or serve-time config injected into the ops context)and return `MediaOpError::Registry` on absence, so the nss lookup leaves the async hot path | [packages/d2b-broker/src/ops/media.rs:2100, packages/d2b-broker/src/ops/media.rs:2126] | actionable | lane/d2b-broker-p7.md +- `RS-0840` | high | `d2b-broker` | `acquire_handoff_lock` is an `async fn` whose final step is a blocking `nix::fcntl::Flock::lock(file, LockExclusive)` on the executor worker thread; the call is not in the clippy.toml disallowed-methods list (no flock entry), not caught by the async-gate scanner) (qualified associated-function calls aren't the method-call shape the scanner flags; the hatch inventory records no marker at this line), and not in the blocking-census baseline - yet the repo's own clippy.toml names this exact class as a rule violation ("a synchronous lock acquired inside an async context ... still parks the executor worker" clippy.toml:55-56) | fix: move the flock to a dedicated bounded worker (house loader_worker shape per clippy.toml:37-40) or convert to non-blocking `LockExclusiveNonblock` plus async retry (`tokio::time::timeout`/sleep as the mkfs ETXTBSY loop does), keeping the critical section bounds off the runtime worker | [packages/d2b-broker/src/ops/host_generation_handoff.rs:246, packages/d2b-broker/src/ops/host_generation_handoff.rs:231] | actionable | lane/d2b-broker-p4.md +- `RS-0839` | medium | `d2b-broker` | the initial ACL-grant attempt runs a blocking setfacl fork/exec on the executor worker: `refresh_spawn_runner_acls` (async, live_handlers.rs:1802) -> `refresh_obs_vsock_acl` -> `grant_obs_vsock_acl_once` (1614) -> `setfacl_fd_safe` -> `setfacl_fd_safe_op_classed` (1416) -> `sys::pidfd_sys::run_setfacl_op_on_fd`, while the retry paths (`spawn_obs_vsock_acl_retry` 1658, `retry_acl_grant` 2519) correctly defer the same shellout to `background.dispatches.run` on the bounded dispatch pool | fix: route the initial attempt through `dispatches.run` too (or make the refresh fns async and use the `setfacl_verified_device` async-shellout shape), matching the documented "kernel-path step on the bounded dispatch pool" design; bounded short shellout per spawn, so medium not high | [packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:1802] | actionable | lane/d2b-broker-p3.md +- `RS-0838` | medium | `d2b-broker` | the USB-audit serial HMAC key path runs blocking filesystem syscalls inside async fns on broker executor threads:usb_audit_serial_hmac_keyring calls the sync ensure_usb_audit_serial_hmac_key_dir (two path_safe::ensure_dir stat/mkdir chains)per call,and every bind op with a device serial loads each key file through a sync nix::fcntl::open plus tokio::fs::File::from_std read,and the create leg performs sync create_file_at_safe/fchmod/rustix::fs::fsync(dir_fd) at runtime.rs:7722-7729; none of these raw calls sits on the disallowed-methods list,so the sync-in-async class escapes the existing gate | fix: extend the already-used tokio::fs::File::from_std)..).sync_all().await pattern(orthe bounded-worker shape per plan R4)to the dir-fd fsync and the key-dir ensure/open legs, per U1 ledger 2,which names tokio::fs asthe sanctioned replacement for these blocking calls,so the verdict is policy-confirmed | [packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages/d2b-broker/src/runtime.rs:7584, packages/d2b-broker/src/runtime.rs:7696] | policy-confirmed | lane/d2b-broker-p2.md + +**`d2b-process-conformance`** + +- `RS-0843` | low | `d2b-process-conformance` | Both traits declare their six async methods as `fn ... -> impl Future + Send` while every in-tree implementor already writes `async fn` (ScriptedEffectPort, ProviderSupervisor, systemd/minijail test ports, d2bd's NonLaunchingProcessEffectPort), and the traits already carry `Send + Sync` supertraits, so the RPITIT `async fn` form (stable, edition 2024) expresses the same Send contract more directly | fix: convert the trait method declarations to `async fn` (port.rs:99-157, provider.rs:96-148), rewriting the two default bodies (`launch_with_inherited_fds`, `probe`) as `async { ... }` and dropping the `ready(Err)...))` wrappers; no implementor changes required | [packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port.rs:129, packages/d2b-process-conformance/src/provider.rs:96, packages/d2b-process-conformance/src/provider.rs:125] | actionable | lane/d2b-process-conformance.md + +**`d2b-provider`** + +- `RS-0844` | medium | `d2b-provider` | `ProviderAgent::serve` awaits each `dispatch` serially (agent.rs:316-324):a slow handler near the 900s timeout bound (`MAX_AGENT_TIMEOUT_MS`)stalls the whole session queue,and the `MAX_AGENT_IN_FLIGHT=64` Semaphore bound can never be exceeded by the serve loop itself | fix: spawn each dispatch (`tokio::spawn(async move { let result = self.dispatch(request).await; let _ = response_tx.send(result.await; })`) with a cloned `response_tx`,letting the already-acquired Semaphore permit cap concurrency; state whether per-session response ordering is a contract) | [packages/d2b-provider/src/agent.rs:316-324] | actionable | lane/d2b-provider.md + +**`d2b-provider-credential-secret-service`** + +- `RS-0845` | medium | `d2b-provider-credential-secret-service` | lock order between `sessions` and`user_sessions` is inverted across two branches of `authorize_session_for_user_locked` (first branch acquires `sessions` then awaits `user_sessions`; cached-key branch acquires `user_sessions` then awaits `sessions`), a latent tokio-Mutex deadlock that the outer `async_mutation_gate`/entry-timing currently masks | fix: acquire in one consistent order in both branches (`sessions` before `user_sessions`, e.g. in the cached-key branch scope the `user_sessions` guard chain and then lock `sessions`, or collapse the dual lookup into one map) | [packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-credential-secret-service/src/lib.rs:1341, packages/d2b-provider-credential-secret-service/src/lib.rs:1380] | actionable | lane/d2b-provider-credential-secret-service.md + +**`d2b-provider-device-tpm`** + +- `RS-0846` | medium | `d2b-provider-device-tpm` | prepare_state_dir (effects_service.rs:412) runs blocking work on the executor worker: a synchronous broker round-trip envelope_invoke_kernel (effects_service.rs:467, blocking connect/poll/recv up to kernel_io_timeout) plus NSS lookups nix::unistd::User::from_name/Group::from_name (effects_service.rs:518,525) in row_posture, none marked async-gate-allow (the crate's inventory lists only the 3 test lock sites) | fix: move the invoke and the NSS resolution off the worker (spawn_blocking or an async broker client); the same pattern exists in d2b-provider-supervisor/process/process-systemd/network-local and d2bd, so consolidation may treat it as one family class | [effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs:525] | actionable | lane/d2b-provider-device-tpm.md +- `RS-0847` | low | `d2b-provider-device-tpm` | lifecycle_lease_consumed: tokio::sync::Mutex (effects_service.rs:361,698) guards a flag owned by exactly one task (into_port builds a fresh port per reconcile/finalize call and uses it once), and consume_lifecycle_lease holds the guard across `.await` (effects_service.rs:384-394); the lock can never contend | fix: replace with AtomicBool (preserves &self + Sync) or restructure the once-gate | [effects_service.rs:361, effects_service.rs:384, effects_service.rs:698] | actionable | lane/d2b-provider-device-tpm.md + +**`d2b-provider-network-local`** + +- `RS-0848` | low | `d2b-provider-network-local` | observe_host_network awaits three independent `ip` observations sequentially, where tokio::join! would run them concurrently | fix: `let (links, addresses, routes)= tokio::join!(run_ip(&["-j", "-d", "link", "show"]), run_ip(&["-j", "-4", "addr", "show"]), run_ip(&["-j", "-4", "route", "show", "table", "all"]));` then parse | [src/observe.rs:255-260] | actionable | lane/d2b-provider-network-local.md + +**`d2b-provider-system-core`** + +- `RS-0849` | low | `d2b-provider-system-core` | `block_on` (testing.rs:23) busy-spins (`std::hint::spin_loop()`, testing.rs:30) on `Poll::Pending`, so any future that genuinely yields - a contended tokio Mutex, a future test with real I/O - hangs the test process at 100% CPU instead of failing; the doc comment asserts hermiticity but nothing enforces it | fix: `debug_assert!` the never-pending invariant or drive these tests with a real runtime | [src/testing.rs:30, src/testing.rs:19] | actionable | lane/d2b-provider-system-core.md + +**`d2b-provider-transport-azure-relay`** + +- `RS-0850` | medium | `d2b-provider-transport-azure-relay` | `RelayConnection::send` is not cancellation-safe: `credits.reserve(size)` is followed by `self.socket.send(frame).await`, and the rollback runs only on `Err` - if the future is cancelled between reserve and completion (e.g. by the session engine's timeout wrapper), the reservation leaks and the connection is permanently starved of up to 64 KiB of credit | fix: wrap the reservation in a small RAII guard that rolls back on drop unless the send committed (or reserve after the await using a pre-checked window) | [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833] | actionable | lane/d2b-provider-transport-azure-relay.md + +**`d2b-provider-user`** + +- `RS-0851` | high | `d2b-provider-user` | the bounded probe's `discover_local_user` runs blocking NSS lookups (`nix::unistd::User::from_name`, `Group::from_gid`, `Group::from_name`) inside async fns on the plane's executor worker (driver reconcile via effects_service.rs:224, and the hosted `inspect-user`), so a slow or hung NSS backend (LDAP/NIS) stalls a runtime worker per call; `spawn_blocking` is itself banned (KD2) | fix: move the NSS reads onto a dedicated bounded worker in the `d2b-core` `loader_worker` shape (one thread, bounded sync_channel, oneshot replies) and have the probe await it | [packages/d2b-provider-user/src/probe.rs:48, packages/d2b-provider-user/src/probe.rs:63, packages/d2b-provider-user/src/probe.rs:72, packages/d2b-provider-user/src/probe.rs:40-79] | policy-confirmed | lane/d2b-provider-user.md + +**`d2b-zone-routing`** + +- `RS-0852` | medium | `d2b-zone-routing` | `ZoneEnrollmentServer::serve` commits the link FSM synchronously (PSK burn, enrollment record seal) inside `serve_bootstrap`/`serve_enroll` and then `.await`s the reply write `transport.send)...)`, so a `serve` future dropped between the mutation and the send leaves the link mid-transition and the peer never sees the reply | fix: make the FSM commit + encoded-reply write one non-cancellable unit (and document that dropping the task mid-send closes the connection as the peer's only signal), or make the operation resumable by deferring the transition until the reply write succeeds where the FSM allows | [packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207] | actionable | lane/d2b-zone-routing.md + +**`d2bd`** + +- `RS-0853` | medium | `d2bd` | `admit_interaction_socket`'s per-request dispatch holds the daemon-global `runtime` lock (the `AsyncMutex>`( across the whole `.await` of `dispatch_component_request_for_session`, serializing every Zone's sessions andthe VM-start display reconcile behind one contended lock; the code itself records this as a residual at 5518-5529 | fix: per the recorded note, hand out a per-Zone handle (`BTreeMap>>`) cloned under the outer lock,and move the sync-seat methods off their global lock, adding the named concurrency test | [packages/d2bd/src/interaction_composition.rs:5518-5530] | actionable | lane/d2bd-p5.md +- `RS-0854` | medium | `d2bd` | `ProductionSharedProviderEffects::runtime()` and `NetworkRuntime::bundle()` busy-wait with `std::hint::spin_loop()` on `tokio::sync::Mutex::try_lock()`; `runtime()` is called from async reconcilers (reconcile_network, reconcile_usbip, reconcile_tpm, ...), so a contended lock spins an executor worker instead of awaiting. The `// async-gate-allow` markers in this file cover the `.lock()` sites (recorded in async-gate-inventory.json:1165-1198) but these `try_lock`+spin sites are not marked or recorded, and the gate scanner matches `.lock()`/`.read()`/`.write()` only, so they are invisible to it. The in-code comment cites plan U10 / the broker rate limiter as the choice | fix: use `.lock().await` where the caller is async (split a sync lock path for the sync trait callers), or record these sites in the async-gate inventory as a deliberate exception | [packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_effects.rs:2633-2639] | actionable | lane/d2bd-p8.md + +**`d2bd-runtime`** + +- `RS-0855` | low | `d2bd-runtime` | `CONSOLE_DRAINER_RUNTIME` is a `static OnceLock` started inside library code (console_session.rs:33-44), giving the daemon a second multi-thread runtime per process that is never shut down, while the binary already owns a `#[tokio::main(flavor = "multi_thread")]` runtime (d2bd/src/main.rs:142) | fix: own the runtime at the binary top and pass a `tokio::runtime::Handle` into `create_ch_session`/`create_qemu_session` (or spawn drainers on the daemon runtime) instead of a crate-static `OnceLock` | [packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session.rs:35] | actionable | lane/d2bd-runtime-p4.md + +### `unsafe` + +Soundness: justification, SAFETY comments, safe wrappers, UB hazards, Miri verification. + +**`d2b-broker`** + +- `RS-0858` | medium | `d2b-broker` | most of `sys.rs`'s 101 `unsafe` blocks carry no `// SAFETY:` comment (only 25 SAFETY comments in the file, concentrated on the risky corner: clone3, fork, pre_exec, pidfd, mount); the raw wrapper layer - `openat2_raw`, `openat_raw`, `renameat2_raw`, `renameat_raw`, `mkdirat_raw`, `unlinkat_raw_with_flags`, `fstatat_raw`, `linkat_empty_path_raw` (593-699), the child-context helpers `mkdir_one`/`mknod_device_bind_target`/`install_pre_opened_fds` (2630, 2670, 2109) and the mount/mask helpers `apply_mount_actions(_debug)`/`apply_device_mask_and_binds` (2591, 2694) - call libc with only `#[allow(unsafe_code)]`, so a reader cannot distinguish audited from un-audited blocks in the sanctioned quarantine | fix: add a one-line SAFETY to each bare block stating the invariant it upholds (CString/pointer liveness and NUL-termination, dirfd validity, errno propagation, freshly-owned return fd), matching the existing clone3/fork comments | [packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broker/src/sys.rs:630, packages/d2b-broker/src/sys.rs:653] | actionable | lane/d2b-broker-p5.md +- `RS-0857` | low | `d2b-broker` | `command_output_inheriting_fd_async` wraps a std )safe) call (`std::process::Command::pre_exec`) in an `unsafe { ... }` block (plus a crate-level-exception `#[allow(unsafe_code)]`), making the block and the allow unnecessary:the pre_exec closure contract (async-signal-safe, error-returning) is already std's own safe-API contract,and the closure body uses only safe nix fcntl wrappers | fix: remove the `unsafe { }` block and the `#[allow(unsafe_code)]` attribute, keeping the async-signal-safety rationale as a regular comment (the site then leaves the enumerated unsafe-exception set in U1 (d)8, shrinking it) | [packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661] | actionable | lane/d2b-broker-p4.md + +**`d2b-broker-fixture-syscall-surface`** + +- `RS-0856` | medium | `d2b-broker-fixture-syscall-surface` | the x86_64 `asm!` block omits the registers the `syscall` instruction clobbers (rcx and r11), so the compiler's no-clobber assumption is violated if the fn is ever executed | fix: add `lateout("rcx") _`, `lateout("r11") _` (or `clobber_abi("C")`) to the asm operands at lib.rs:26-32 | [packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32] | actionable | lane/tail-1.md + +**`d2b-host-activation-helper`** + +- `RS-0859` | medium | `d2b-host-activation-helper` | 22 production `unsafe` blocks (libc calls plus `errno_clear`'s `__errno_location` write) carry no `// SAFETY:` comment, violating the skill's mechanical rule and U1 (d) 8 | fix: add a `// SAFETY:` comment to each block stating the invariant (CString NUL-termination, checked return before use, fd ownership) | [packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/src/main.rs:129, packages/d2b-host-activation-helper/src/main.rs:140, packages/d2b-host-activation-helper/src/main.rs:194] | actionable | lane/tail-1.md merged: tail-1#4 + +### `ffi` + +FFI boundary: thin translation layer, no panic across, explicit pointer ownership, repr contracts, edition-2024 forms. + +- No findings. + +### `macro` + +Macros as last resort: by-example before proc-macro, hygiene and $crate, spanned errors, _private module. + +**`d2b-provider-display-wayland`** + +- `RS-0860` | low | `d2b-provider-display-wayland` | the local `macro_rules! entry!` (policy.rs:420-437) is a two-arm table-filling shorthand whose `max=` arm only omits one field; it is not variadic, does not generate impls per type, and is not a DSL, so a plain function is the cheaper answer | fix: replace the macro with `fn entry(m: &mut HashMap, iface: &str, action: GlobalAction, class: Classification, max: Option)` and update the ~70 call rows; the catalog content stays byte-identical (the hand-written catalog itself is Nix-pinned and refused at docs/explanation/over-engineering-audit-record.md:352, 427-429 - this finding touches only the mechanism) | [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420] | actionable | lane/d2b-provider-display-wayland-p1.md + +**`d2b-resource-api`** + +- `RS-0861` | low | `d2b-resource-api` | `response_error!` generates thirteen identical one-line functions that differ only in the response type, a case a generic function covers without a macro | fix: replace the macro with `fn error_response(error: ResourceError) -> T` (type inferred from each RPC method's return type) and delete the thirteen `response_error!` invocations | [service.rs:2245-2267] | actionable | lane/d2b-resource-api-p1.md + +**`d2b-session`** + +- `RS-0862` | low | `d2b-session` | the local admit_try! macro exists only to fuse an early return with a metric record, which a plain helper function plus ? expresses | fix: replace each invocation with `let result = ; admit_or_record(&mut engine, result)?` where admit_or_record records the failure metric and returns the error | [admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643] | actionable | lane/d2b-session-p2.md + +**`xtask`** + +- `RS-0863` | low | `xtask` | The test-only `crash_if_hooked!` macro is defined textually-identically in three sibling fns, differing only in the message string | fix: hoist to one module-scope `macro_rules! crash_if_hooked { ($stage:expr, $message:expr) => { #[cfg(test)] if let HookOutcome::Crash = hook($stage) { return Err(FoldError::single($message)); } }; }` and call with the stage plus message, or replace with a `#[cfg(test)]` generic helper fn | [packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/src/changelog.rs:1019] | actionable | lane/xtask-p5.md + +### `test` + +Test design: form follows the assertion, behavior over implementation, determinism, a test must be able to fail. + +**`X3-cross-crate-duplication`** + +- `RS-0958` | medium | `X3-cross-crate-duplication` | Provider test-support recorder/harness duplication: each provider crate hand-rolls the same recorder-double family (RecordingEffects/ScriptedProbe/RecordingManager/RecordingRequeue-style recording doubles, ScriptedPort/ScriptedDiscoveryPort/ScriptedEffectPort scripted ports, hand-rolled block_on pollers, TicketBuilder-style fixtures) in its own test_support.rs/testing.rs instead of the toolkit's shipped harness | fix: consolidate the recorder/harness shapes onto `d2b-provider-toolkit/src/testing` (TestHarness at testing/mod.rs:397, fakes.rs, fixture.rs, conformance.rs) and have the family crates reuse it; the toolkit module is the B3-kept base, so this does not re-propose the B3 refusal | [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-volume-binding/src/test_support.rs:17] | actionable | lane/X3-cross-crate-duplication.md +- `RS-0959` | low | `X3-cross-crate-duplication` | Test-support shipping shape: `test-support` features declared empty and gating nothing in four declaration crates while three provider crates ship `pub mod testing` (ScriptedPort/block_on harnesses) unconditionally in the production library and d2b-resource-types exports a test-only helper through the root despite declaring the feature | fix: wire each `test-support = []` feature to its module (`#[cfg(feature = "test-support")]` on `pub mod testing`, `#[cfg(feature = "test-support")]` on `assert_metadata_registration`) or drop the empty features, following the house pattern at d2b-provider-host/Cargo.toml:28 | [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-role/Cargo.toml:17] | actionable | lane/X3-cross-crate-duplication.md + +**`d2b`** + +- `RS-0880` | medium | `d2b` | the `d2b exec wait` guest-exit-code passthrough (`guestExitCode`/`exitCode` lookup, 0-255 filter, `unwrap_or(0)`) has no unit or integration test, so a regression in the CLI exit-code contract would pass silently | fix: extract the extraction into a testable helper or add a mock-daemon integration test asserting the passthrough and the out-of-range fallback | [packages/d2b/src/exec.rs:227-239] | actionable | lane/d2b-p3.md +- `RS-0881` | low | `d2b` | `validate_env` (KEY=VALUE shape, key length and charset bounds) has no test, unlike the sibling `validate_exec_ref` behavior that the attach tests cover | fix: table-driven unit test with human-written expected outcomes (valid, empty key, over-64 key, non-alnum key, missing `=`) | [packages/d2b/src/exec.rs:383-397] | actionable | lane/d2b-p3.md + +**`d2b-broker`** + +- `RS-0866` | low | `d2b-broker` | `reconciliation_refuses_start_time_drift` (tests/pidfd_handoff_scm_rights.rs) asserts the Display string (`msg.contains("start-time drifted")`) instead of the error variant, while the sibling real-spawner test matches `PidfdOpError::ReconciliationStartTimeMismatch` | fix: match the variant like tests/pidfd_real_spawner.rs:66-70 | [packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90] | actionable | lane/d2b-broker-p3.md + +**`d2b-broker-composition`** + +- `RS-0864` | low | `d2b-broker-composition` | `an_effectful_handler_offered_to_the_in_broker_table_is_refused_by_the_routing_rule` asserts `format!("{refusal}").contains("forward carrier")`, pinning the routing refusal's Display wording after the `matches!` variant check already pins the contract | fix: delete the Display-string assertion (the variant match is the contract; a wording change must not fail the suite) | [packages/d2b-broker-composition/src/seam.rs:523] | actionable | lane/d2b-broker-composition.md +- `RS-0865` | low | `d2b-broker-composition` | `an_unregistered_admitted_operation_fails_the_startup_invariant` never exercises an admitted-without-handler operation (the committed catalog admits nothing this pass, and the fixture row is refused by `verify_startup_routing` as uncommitted), so the body only asserts the empty-registration happy path and registers a discarded fixture | fix: rename the test to what it asserts (e.g. `the_admitted_set_stays_empty_with_nothing_registered`) and drop the comment's claim that the admitted-without-handler leg is pinned by the fixture row, or restructure to feed a genuinely admitted row when one exists | [packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.rs:733] | actionable | lane/d2b-broker-composition.md + +**`d2b-bus`** + +- `RS-0867` | high | `d2b-bus` | emitter_records_only_closed_bus_labels exercises every BusTelemetry method but asserts nothing, and every emit outcome is swallowed by `let _ = self.emit(...)` inside BusMetrics, so a label drifting out of the closed set passes silently | fix: make the test assert something observable, for example return EmitOutcome from a test-visible emit path or expose a read-back of the BoundedEmitter queue in d2b-telemetry, and assert Ok per call (route review-pass) | [packages/d2b-bus/src/metrics.rs:612-633, packages/d2b-bus/src/metrics.rs:451-534] | actionable | lane/d2b-bus-p1.md +- `RS-0868` | medium | `d2b-bus` | session_seam_tests.rs waits for service readiness with fixed-count yield and poll loops (`for _ in 0..16 { tokio::task::yield_now().await }` at 1623 and 1808, `for attempt in 0..32` at 1882, `for attempt in 0..8` plus an inner yield loop at 1941-1960), which is machine-dependent and can fail spuriously on a loaded runner | fix: replace with condition-driven waits (oneshot or Notify), the deterministic pattern the same file already uses elsewhere (advance_virtual, dispatched_wait) | [packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_tests.rs:1808-1810, packages/d2b-bus/src/session_seam_tests.rs:1882-1884, packages/d2b-bus/src/session_seam_tests.rs:1941-1960] | actionable | lane/d2b-bus-p2.md +- `RS-0869` | low | `d2b-bus` | `cancel_retry_cannot_reach_a_same_id_replacement_while_tombstone_is_retained` pins the full `Display` sentence of `OperationError::RetainedOperationId`, so a wording change fails the test even though the contract is the variant and its `as_str()` label | fix: assert the variant (the surrounding code already matches on variants) and drop the `to_string()` equality | [packages/d2b-bus/src/operations.rs:1057-1060] | actionable | lane/d2b-bus-p2.md + +**`d2b-contracts-control`** + +- `RS-0870` | medium | `d2b-contracts-control` | the `WorkloadOp`/`WorkloadOpResponse` wire family (feature-negotiated v3 operations, dispatched by d2bd/src/composition.rs:7666) has no round-trip or shape test in this crate, unlike every sibling family (exec, console, audio, shell, named streams, audit all have wire-shape tests) | fix: add a round-trip + tag/rename pin test for WorkloadOp::List/Status/LauncherExec and WorkloadOpResponse, mirroring `audio_public_wire_json_shape_is_stable` | [public_wire.rs:167, public_wire.rs:175] | actionable | lane/d2b-contracts-control.md + +**`d2b-contracts-provider`** + +- `RS-0871` | medium | `d2b-contracts-provider` | `credential/service.rs` (1461 lines) contains zero tests: the strict protobuf codec (the five `CredentialWire` impls at service.rs:1071-1350, `WireReader` at service.rs:1393-1452, `set_once` duplicate-field rejection at service.rs:1296, and the `encode_outer`/`decode_outer` ceilings at service.rs:1002-1028) is entirely unverified, so a malformed-input, truncation, or non-canonical-varint regression passes the suite silently | fix: add round-trip tests per DTO plus malformed/truncated/duplicate-field/non-canonical-varint/oversize tests for `WireReader` and `encode_outer`/`decode_outer` | [packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-provider/src/v3/credential/service.rs:1393, packages/d2b-contracts-provider/src/v3/credential/service.rs:1296] | actionable | lane/d2b-contracts-provider-p1.md +- `RS-0872` | medium | `d2b-contracts-provider` | several public contract behaviors have no test: `observe_credential` (both the degraded and the InspectMetadata branches), the rotation-retry-exhausted branch of `reconcile_credential` (`CredentialRetryState::exhausted` feeding `RotationFailed`/`Failed`), `CredentialLeaseAggregate::from_active_expiries`, `CredentialControllerHealth::derive`, and `CredentialAuditRecord::controller_event` | fix: add table-driven unit tests asserting the outcome/disposition variant per input row, mirroring the existing `rotation_policy_matrix_is_closed` shape | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1346, packages/d2b-contracts-provider/src/v3/credential_controller.rs:499, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1084] | actionable | lane/d2b-contracts-provider-p2.md + +**`d2b-contracts-zone-session`** + +- `RS-0873` | medium | `d2b-contracts-zone-session` | the security-relevant codec state machines have no tests: RequestEnvelope::admit deadline/skew/lifetime math, FragmentSequence ordering/duplicate/complete detection, ReceiveSequence replay and nonce exhaustion, SendSequence::take, AttachmentCredits::reserve and process_pool, and the canonical round-trips of RecordHeader/FragmentHeader/HandshakeAccept, while the suite covers only policy validation, redaction, and frozen enum vectors | fix: add unit tests asserting the error variants (InvalidDeadline, Reordered, Duplicate, Replay, NonceExhausted, CreditExceeded) for each state machine, plus encode/decode round-trips for the header types | [src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_session.rs:1916, src/v3/component_session.rs:2732] | actionable | lane/d2b-contracts-zone-session-p1.md merged: d2b-contracts-zone-session-p1#6 +- `RS-0874` | medium | `d2b-contracts-zone-session` | EmergencyPolicySpec's contract branches have no tests: the file holds exactly one test covering only the union behavior | fix: add table tests for new() rejecting deadline 0 and > MAX_EMERGENCY_DRAIN_DEADLINE_SECONDS, reason > MAX_EMERGENCY_REASON_BYTES, and control characters; plus effective_scope returning None when no policy is enabled, and the serde default round-trip | [emergency_policy.rs:236, emergency_policy.rs:112] | actionable | lane/d2b-contracts-zone-session-p2.md merged: d2b-contracts-zone-session-p2#9 + +**`d2b-core`** + +- `RS-0877` | low | `d2b-core` | `tamper_owner_wrong_uid` in tests/bundle_resolver_tamper.rs silently returns (eprintln + return) when not root, so it passes vacuously on non-root CI and a regression in the chown tamper path would go unnoticed there | fix: convert the inline skip to the repo's documented `#[ignore]` root-only pattern (the card's false-positive list endorses documented ignores) so the skip is visible in test output | [packages/d2b-core/tests/bundle_resolver_tamper.rs:149] | actionable | lane/d2b-core-p2.md + +**`d2b-core-controller`** + +- `RS-0875` | medium | `d2b-core-controller` | the restart-recovery receipt path (validate_recovery_operations, recovery_receipt_from_operations_with_prepared_capabilities, rehydrate) has no test anywhere: claim-digest verification, prepared-capability matching, and quarantine-on-mismatch are contract behavior with zero coverage | fix: add tests that build AuthorityStorageOperation rows with a tampered claim_digest, a prepared-capability set that misses an active operation, and a duplicate operation_id, asserting each returns InvalidAuthorityRequest, plus a rehydrate round-trip that admits after rehydration | [authority.rs:1824, authority.rs:1968, authority.rs:1899] | actionable | lane/d2b-core-controller-p2.md +- `RS-0876` | medium | `d2b-core-controller` | AuthorityRecoveryCoordinator has no tests and its resolution methods have no callers at all, so the capability-restore-and-quarantine rollback on a failed record_close/release (authority_persistence.rs:292-311) is untested contract behavior that only a future driver will reach | fix: add coordinator tests with a failing persistence double asserting the capability is restored and the operation quarantined after record_close or release failure, and that resolve_observed_and_adopted clears the unresolved set | [authority_persistence.rs:246-320] | actionable | lane/d2b-core-controller-p2.md merged: d2b-core-controller-p2#8 + +**`d2b-host`** + +- `RS-0878` | medium | `d2b-host` | `NftBatch::parse` (the ~200-line nft script dialect parser with 15+ error paths) has no tests: zero calls to `parse` exist in the crate's test modules, while the broker feeds it live script bodies on its nft apply path | fix: table-driven parse tests (valid script, malformed header, foreign family/table, missing hook priority, unterminated chain, trailing content) asserting `ParseNftScriptError` variants | [packages/d2b-host/src/nftables.rs:245] | actionable | lane/d2b-host.md +- `RS-0879` | low | `d2b-host` | `package_digest_includes_bytes_read_through_store_symlinks` writes fixtures to a CWD-relative `target/` directory (the cargo build dir), polluting build artifacts and failing under a read-only target; every sibling test uses `tempdir()` | fix: use `tempfile::tempdir()` like the sibling tests | [packages/d2b-host/src/bin/d2b-activation-helper.rs:792] | actionable | lane/d2b-host.md + +**`d2b-provider-activation-nixos`** + +- `RS-0882` | low | `d2b-provider-activation-nixos` | the six-case verification-fence table in `activation_verification_requires_all_trust_and_digest_fences` asserts without a per-case message, so a failure in case 3 of 6 reports only a line number and no case identity | fix: add a per-case failure message (e.g. `"case {i}: expected {expected_error:?}"`) to the loop assert | [packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activation-nixos/tests/reconcile.rs:447] | actionable | lane/d2b-provider-activation-nixos.md + +**`d2b-provider-audio-pipewire`** + +- `RS-0883` | low | `d2b-provider-audio-pipewire` | `SpeakerMixer::mix_level`'s saturation cap (sum capped at 100, authority.rs:236-241) has no boundary test: tests/authority.rs:26-31 asserts only 80+20=100, so a regression that removed the `min(100)` would pass | fix: add saturation rows (e.g. 80+80, 60+60+60) asserting the capped result | [tests/authority.rs:26-31, src/authority.rs:236-241] | actionable | lane/d2b-provider-audio-pipewire.md +- `RS-0884` | low | `d2b-provider-audio-pipewire` | tests/mediator.rs:13-24 is named `projection_cannot_open_pipewire_and_failed_set_preserves_state` but asserts only the Err and readiness; the state-preservation half of the claim is unasserted, so a regression that mutated grant/level on failure would pass | fix: assert `mediator.grant()`/`mediator.level()` unchanged after the failed set, or rename the test | [tests/mediator.rs:13-24] | actionable | lane/d2b-provider-audio-pipewire.md + +**`d2b-provider-clipboard-wayland`** + +- `RS-0885` | medium | `d2b-provider-clipboard-wayland` | published_selection_echo_is_always_suppressed_once asserts the identity wrapper should_suppress_published_selection_echo_state, a forwarding pin that fails only if the wrapper's triviality changes | fix: delete the test together with the wrapper (idiom finding #2); the behavior it gestures at is already covered by bridge_selection_echo_suppression_persists_for_source_vm_or_unknown_focus | [src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787] | actionable | lane/d2b-provider-clipboard-wayland-p1.md merged: d2b-provider-clipboard-wayland-p1#2 +- `RS-0886` | medium | `d2b-provider-clipboard-wayland` | the history eviction contract has no test: insert's LRU count bound (max_history_entries via evict_oldest) and byte-quota eviction (max_total_bytes via evict_until) are untested, as are materialize's owner and TTL rejections and entry_expiry | fix: unit tests in history.rs asserting eviction order and quota behavior (e.g. insert max_history_entries+1 entries and assert the oldest is evicted; fill past max_total_bytes and assert eviction down to quota) | [packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clipboard-wayland/src/history.rs:345-356, packages/d2b-provider-clipboard-wayland/src/history.rs:257-273] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0887` | medium | `d2b-provider-clipboard-wayland` | the controller's route-to-evidence admission gates (DisplayDependencyEvidence::from_authenticated_route and from_committed_display_route) have no tests even though from_committed_display_route is consumed by d2bd as the display-dependency authority input; only dependency_status is tested | fix: unit tests in controller/mod.rs exercising valid and each rejected route shape (wrong provider, wrong service, wrong evidence class, zero generations, wrong subject type) | [packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:144-201, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:360-371] | actionable | lane/d2b-provider-clipboard-wayland-p2.md +- `RS-0888` | low | `d2b-provider-clipboard-wayland` | FallbackArming::cancel_picker (the PickerCancelled transition) and NiriStateCache's WindowClosed and WorkspaceActivated event paths have no tests, leaving two state transitions and two event handlers unverified | fix: extend the existing table-style tests in fallback.rs and niri.rs with the missing transitions | [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:378-387, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:394] | actionable | lane/d2b-provider-clipboard-wayland-p2.md + +**`d2b-provider-config-nixos`** + +- `RS-0889` | medium | `d2b-provider-config-nixos` | `ConfigSyncResponse::document()`'s integrity contract (forged `sha256`/`bytes` mismatch must fail `EncodingFailed`, over-bound `content_base64` must fail `InvalidRequest`) is untested, and the daemon depends on this exact decode path (d2bd/src/composition.rs:11585) | fix: add integration tests that literal-construct a `ConfigSyncResponse` (fields are pub) with a wrong digest, a wrong byte count, and an over-`MAX_CONFIG_ENCODED_BYTES` payload and assert the failure codes | [packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixos/tests/config_lifecycle.rs:8-18] | actionable | lane/d2b-provider-config-nixos.md +- `RS-0890` | low | `d2b-provider-config-nixos` | no test exercises the `deny_unknown_fields` admission (an extra JSON key must make `validate_operation` fail `InvalidRequest`) or a payload with wrong field types (serde error path), which is exactly the typo-key case the attribute exists for | fix: extend `operation_validation_enforces_closed_identifiers_and_semantic_bounds` (tests/service_contract.rs:41-79) with an unknown-field payload and a wrong-typed payload | [packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixos/tests/service_contract.rs:41-79] | actionable | lane/d2b-provider-config-nixos.md + +**`d2b-provider-credential-entra`** + +- `RS-0891` | low | `d2b-provider-credential-entra` | `exact_consumer_guard_is_independent_of_request_fields` never exercises the guard its name claims: it only asserts that two `ResourceRef::parse` results differ, which can fail only if parsing collapses distinct inputs | fix: replace the body with an assertion on the actual guard (e.g. `provider.authorizes_consumer(&ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap())` true and a different Provider ref false), or delete the test | [packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-entra/src/lib.rs:1362] | actionable | lane/d2b-provider-credential-entra.md + +**`d2b-provider-credential-managed-identity`** + +- `RS-0892` | low | `d2b-provider-credential-managed-identity` | Table-driven loops assert without per-case failure messages, so the first failing case reports only a shared line number and not which case | fix: append `"method: {method:?}"` / `"binding: {binding:?}"` style messages to the `assert!`/`assert_eq!` calls in the method/route/placement matrices (mirroring the canary loops' messages at canary.rs:229-241) | [tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76] | actionable | lane/d2b-provider-credential-managed-identity.md + +**`d2b-provider-credential-secret-service`** + +- `RS-0893` | low | `d2b-provider-credential-secret-service` | table-driven loops assert without per-case failure messages (`locked_and_unavailable_map_to_provider_unavailable`, `only_user_agent_on_host_or_guest_is_accepted`, `collection_alias_accepts_spaces_and_rejects_unsafe_text`), so a failure reports only the line number and not which case failed | fix: add a `"case: {case:?}"`-style message to each loop assertion | [packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-credential-secret-service/tests/placement.rs:8, packages/d2b-provider-credential-secret-service/src/lib.rs:1966] | actionable | lane/d2b-provider-credential-secret-service.md + +**`d2b-provider-device-gpu`** + +- `RS-0894` | medium | `d2b-provider-device-gpu` | `GpuAuthorityAdmission::new`'s arbitration/render-node/max-holders matrix (`ArbitrationViolation`) and zero-token rejections (`StaleDeviceIdentity`) have no direct test even though they are the authority admission gate | fix: add table-driven rejection vectors over `GpuAuthorityAdmission::new` asserting the typed `GpuAuthorityError` variant for each illegal combination, mirroring the `admission()` fixture shape in tests/authority_lifecycle.rs | [packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/tests/authority_lifecycle.rs:245, packages/d2b-provider-device-gpu/tests/combined_reconcile.rs:238] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-device-usbip`** + +- `RS-0896` | medium | `d2b-provider-device-usbip` | `UsbipArbitrator` branches are untested: only the exclusive second-claim conflict is covered, while the constructor ceiling/ArbitrationViolation validation, `MaxClaimsExceeded`, idempotent re-claim by the same holder, and `release` have no test | fix: add a table-driven unit test over the ceiling, arbitration mode, re-claim, and release paths | [tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, src/arbitration.rs:117-121] | actionable | lane/d2b-provider-device-usbip.md +- `RS-0897` | medium | `d2b-provider-device-usbip` | the crate's declared wire types (`UsbipEventSource`, `UsbipReconcileAttemptContext`, `UsbipPublicDegradedReason`, `UsbipClaimSource`) have no serde round-trip test with a real-shaped payload, so kebab-case/camelCase wire drift would pass | fix: add a round-trip test deserializing a hand-written payload for each serde type and re-serializing | [src/reconcile_state.rs:51-308, src/state_machine.rs:98-100] | actionable | lane/d2b-provider-device-usbip.md +- `RS-0895` | low | `d2b-provider-device-usbip` | conformance.rs:63-66 asserts `AttachmentCommand::Attach(AttachmentActivation::Declared)` equals an identical literal, an assertion that cannot fail | fix: delete the tautological assert_eq (the same test's other asserts already pin the enum shape) | [tests/conformance.rs:63-66] | actionable | lane/d2b-provider-device-usbip.md + +**`d2b-provider-display-wayland`** + +- `RS-0898` | high | `d2b-provider-display-wayland` | two registry-handler tests cannot fail on any behavior change: `filtered_globals_preserve_original_global_names` (filter.rs:3213-3224) inserts entries into `advertised_globals`/`hidden_globals` and asserts their presence - pure setup restatement with no function under test - and `standard_clipboard_global_is_advertised_as_synthetic` (filter.rs:3264-3283) admits in its comment that the real path is untested and then asserts only `interface.name()` plus the map content it just inserted | fix: delete the first test and rewrite the second to exercise `prepare_global(11, ObjectInterface::WlDataDeviceManager, 3)` and assert the synthetic `GlobalAdvertisement` decision, as the neighboring `prepare_global_hides_*` tests already do | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3213, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3264] | actionable | lane/d2b-provider-display-wayland-p1.md + +**`d2b-provider-guest-azure-container-apps`** + +- `RS-0900` | medium | `d2b-provider-guest-azure-container-apps` | the completed-operation ledger replay path (reconcile with a previously recorded operation id returns Converged without re-running effects, controller.rs:264-266) is contract behavior with no test - every test calls reconcile with a fresh operation id | fix: add a test that reconciles twice with the same id against a Running sandbox and asserts the second pass performs no effect calls (calls list unchanged) | [src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225] | actionable | lane/d2b-provider-guest-azure-container-apps.md +- `RS-0899` | low | `d2b-provider-guest-azure-container-apps` | stable_error_codes_are_bounded ends with a dead `let _ = ResourceRef::parse("Guest/gateway").unwrap();` that asserts nothing the test name claims and duplicates parse coverage exercised everywhere else | fix: delete the line (or fold the parse into an assertion the test actually promises) | [tests/provider_lifecycle.rs:536] | actionable | lane/d2b-provider-guest-azure-container-apps.md + +**`d2b-provider-guest-azure-virtual-machine`** + +- `RS-0901` | low | `d2b-provider-guest-azure-virtual-machine` | `every_controller_error_has_a_documented_stable_code` (tests/error_redaction.rs:17-38) asserts `!code().is_empty()` over a hand-enumerated variant list, but `code()` is a const fn whose exhaustive match makes an empty arm a compile error and the enumeration is not compiler-forced, so the test cannot meaningfully fail | fix: drop the loop and keep exact-code pinning (as `errors_and_handles_do_not_render_remote_values` already does for `arm-credential-denied`), or pin the full code table | [tests/error_redaction.rs:17] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md + +**`d2b-provider-guest-cloud-hypervisor`** + +- `RS-0902` | medium | `d2b-provider-guest-cloud-hypervisor` | `assert!(plan.preserve_state())` (finalize_ordering_test.rs:286) cannot fail because `preserve_state()` returns a literal `true` (shutdown.rs:577), an assertion of implementation rather than behavior | fix: delete the assertion together with the accessor (finding #4) | [finalize_ordering_test.rs:286] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md + +**`d2b-provider-guest-qemu-media`** + +- `RS-0903` | low | `d2b-provider-guest-qemu-media` | tests/lifecycle.rs repeats the same 8-field `DeviceObservation` literal ~8 times (e.g. 132-140,154-163,220-228,292-300,377-385( (each test then mutates a field or two (the fixture setup dominates the test bodies | fix: extract `fn device() -> DeviceObservation` helper (as `fn controller()` at tests/lifecycle.rs:104 already factors the bigger fixture (or build from a small builder | [packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:154, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:220, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:292] | actionable | lane/d2b-provider-guest-qemu-media.md + +**`d2b-provider-observability-otel`** + +- `RS-0904` | medium | `d2b-provider-observability-otel` | the resource-attribute validation test asserts only `is_err()` for both failure shapes,so a regression swapping the two wire-visible variants(`NotAllowlisted` vs `Invalid`)would pass | fix: replace the two `is_err()` assertions in `resource_attributes_have_a_separate_allowlist` with `assert_eq!)..., Err(ResourceAttributeError::NotAllowlisted))` for the unknown-key case,and `assert_eq!)..., Err(ResourceAttributeError::Invalid))` for the credential-canary value case | [metric_policy.rs:145, metric_policy.rs:150] | actionable | lane/d2b-provider-observability-otel.md + +**`d2b-provider-provider`** + +- `RS-0905` | medium | `d2b-provider-provider` | the `Degraded` phase projection (`optional_components_degraded` -> `ProviderPhase::Degraded` in `plan_observed`) is production-reachable through the driver's Enable/Update intents and has no test | fix: add a `#[tokio::test]` (or `#[test]` on `plan_observed` directly) that sets `optional_components_degraded = true` with ready dependencies and asserts `phase == Degraded` and `publish_exports` stays true | [src/providers.rs:206, src/driver.rs:1147] | actionable | lane/d2b-provider-provider.md + +**`d2b-provider-shell-terminal`** + +- `RS-0906` | low | `d2b-provider-shell-terminal` | `tests/supervisor_runtime.rs` repeats the full 14-line `ShellPool::new(PoolSpec::new)...))` fixture in 7 of its tests, while sibling `tests/controller_reconcile.rs:8` already defines a `pool()` helper. | fix: extract a parameterized `fn pool(max_sessions: u32, max_attached: u32) -> ShellPool` helper at the top of `tests/supervisor_runtime.rs` (or a shared `tests/common/mod.rs` used by both files), replacing the 7 inline constructions. | [tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.rs:142, tests/supervisor_runtime.rs:193] | actionable | lane/d2b-provider-shell-terminal.md + +**`d2b-provider-supervisor`** + +- `RS-0907` | low | `d2b-provider-supervisor` | `open_pidfd_dispatch_failure_is_ambiguous_only_after_identity_drift` pins the cross-crate broker error-kind contract by scraping source text (`include_str!("../../d2b-broker/src/live_handlers.rs")` + `LIVE_HANDLER_SOURCE.contains("PidfdRace")`) with the expected names duplicated as literals - brittle against broker renames, but the identical fix (a shared typed error-kind constant) was refused for this exact site because no exported constant exists and d2b-contracts-broker is out of lane | fix: none actionable; keep the scrape | [packages/d2b-provider-supervisor/src/broker.rs:2040-2043] | policy-confirmed | lane/d2b-provider-supervisor.md + +**`d2b-provider-system-core`** + +- `RS-0908` | low | `d2b-provider-system-core` | tests/host_reconciliation.rs repeats the `Probe` struct literal plus a 5-field `HostProbeMetadata` block five times (lines 204, 230, 254, 280, 306), one field differing per case | fix: a `Probe::new(capabilities, user_manager_available, gate, kernel_release)` constructor or default-and-mutate helper | [tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230] | actionable | lane/d2b-provider-system-core.md + +**`d2b-provider-transport-vsock`** + +- `RS-0909` | low | `d2b-provider-transport-vsock` | tests/observe.rs asserts `ServicePhase::Ready == ServicePhase::Ready`, a self-comparison that cannot fail and adds nothing to a test already asserting the observation fields - dead assertion weight with no regression value. | fix: delete line 15 (the test still asserts `observation.phase == TransportPhase::Released`), or replace with a real cross-variant assertion (e.g. `assert_ne!(ServicePhase::Ready, ServicePhase::Serving)` | [packages/d2b-provider-transport-vsock/tests/observe.rs:14-15] | actionable | lane/d2b-provider-transport-vsock.md + +**`d2b-provider-user`** + +- `RS-0910` | medium | `d2b-provider-user` | the "cached unrealized phase re-discovers" contract is tested only for `Pending` (`reconcile_rediscovers_a_cached_unrealized_phase`), so a regression that widened the `observed_ready` short-circuit predicate (driver.rs:283) to accept `Degraded` or `Unknown` would pass every test | fix: extend the phase loop in `reconcile_publishes_the_user_discovery_projection` (driver.rs:789-813) to run a second reconcile per phase and assert the second `observe-user` call for all three unrealized phases | [packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs:281-284] | actionable | lane/d2b-provider-user.md + +**`d2b-provider-wayland-policy`** + +- `RS-0911` | low | `d2b-provider-wayland-policy` | Dead no-op line in `the_policy_envelope_is_the_whole_contract`: `let _ = ResourceRef::parse)...)` asserts nothing and cannot fail | fix: assert the parse succeeds (e.g. `.expect("the policy reference parses")`), or delete the line | [packages/d2b-provider-wayland-policy/tests/registration.rs:93] | actionable | lane/d2b-provider-wayland-policy.md + +**`d2b-provider-zone-link`** + +- `RS-0912` | low | `d2b-provider-zone-link` | three table-driven loops assert without a per-case failure message, so a failing row reports only a line number, not which state/error/key failed | fix: add messages naming the loop variable (`"state: {state:?}"`, `"key: {key}"`, `"error: {error:?}"`) to the loops at zone_links.rs:2513-2519, 3092-3094, and 3133-3167 | [packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/src/zone_links.rs:3093, packages/d2b-provider-zone-link/src/zone_links.rs:3162] | actionable | lane/d2b-provider-zone-link.md + +**`d2b-resource-api`** + +- `RS-0914` | medium | `d2b-resource-api` | `list_returns_snapshot_revision_and_watch_refuses_until_wired` compares the wire snapshot's epoch-seconds half against `SystemTime::now()` taken after the list round-trip, so a second boundary crossing between the two instants flakes the test | fix: assert the mapping with a one-second tolerance or inject the clock | [packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src/manager_backend/tests.rs:1460, packages/d2b-resource-api/src/manager_backend/tests.rs:1461] | actionable | lane/d2b-resource-api-p2.md +- `RS-0913` | low | `d2b-resource-api` | `status_owner_matching_generation_is_representable` asserts only that `ControllerGeneration::new(11)` and `ResourceGeneration::new(11)` succeed on literals, restating the type system rather than a behavior contract | fix: delete it, or convert the representability claim into the wire-compatibility test it is meant to document (asserting the status-owner comparison path with a real mismatch) | [service.rs:3377] | actionable | lane/d2b-resource-api-p1.md + +**`d2b-resource-client`** + +- `RS-0915` | low | `d2b-resource-client` | the close/cancel error-rollback paths are untested: `ProcessAttachStream::close`/`cancel` and `ResourceWatch::close` restore the open state when the transport close errors, but no test injects that failure | fix: add failure-injection tests asserting the state rolls back to open and a second close retries | [packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/process_attach.rs:541, packages/d2b-resource-client/src/zone_client.rs:567] | actionable | lane/d2b-resource-client.md + +**`d2b-resource-runtime`** + +- `RS-0916` | high | `d2b-resource-runtime` | `display_shows_epoch_and_sequence` asserts `rendered.contains("[PHONE]")` on the rendering `e1728000000+42`, an assertion that cannot pass, so the test fails at HEAD (route review-pass; read-only audit) | fix: delete the stray `[PHONE]` assertion (the epoch/sequence assertions on the same line already cover the contract) | [packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revision.rs:71] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0917` | low | `d2b-resource-runtime` | `wire_budget_bounds_sequence_for_u32_low_word` asserts `WIRE_SEQUENCE_BUDGET == 1 << 32`, restating the constant's own definition (revision.rs:41), so it cannot fail meaningfully | fix: delete it or assert a behavioral consequence (e.g. that a sequence at the budget still packs into the u32 low word of the U8 mapping) | [packages/d2b-resource-runtime/src/revision.rs:182] | actionable | lane/d2b-resource-runtime-p1.md +- `RS-0918` | low | `d2b-resource-runtime` | the lib.rs `modules_resolve` smoke test asserts each `MODULE_NAME` const against its own literal, pinning source text with no behavioral value (the A5 not-applied row, docs/explanation/over-engineering-audit-record.md:458, covers the consts and this test; the site still matches the record) | fix: fold into the A5 decision (delete both, or keep only as a compile-resolution check without the value assertions) | [packages/d2b-resource-runtime/src/lib.rs:66] | actionable | lane/d2b-resource-runtime-p1.md + +**`d2b-session`** + +- `RS-0919` | low | `d2b-session` | unpolled_cancellation_on_real_driver_reclaims_request_for_reuse spins up to 64 yield_now iterations waiting for the cancellation task to reclaim the request, while its sibling test waits on a Notify | fix: wait on a Notify (or a tokio::time::timeout around a Notify) instead of the fixed spin cap | [tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139] | actionable | lane/d2b-session-p2.md + +**`d2b-sk-frontend`** + +- `RS-0920` | medium | `d2b-sk-frontend` | the parse side of the byte-exact UHID protocol (`read_event`'s event-type dispatch, the OUTPUT size field at payload[4096], GET_REPORT id, lifecycle mapping, short-header error) has no test while the builders have 12 byte-exact tests, so a regression in the parse offsets passes the suite | fix: extract `parse_event(buf: &[u8]) -> io::Result>` from `read_event` and table-test the dispatch against hand-built buffers (plus a `build_get_report_reply_error` layout test) | [packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186] | actionable | lane/tail-6.md + +**`d2b-telemetry`** + +- `RS-0921` | low | `d2b-telemetry` | `target_buckets_are_present` pins three bucket constants by asserting one member value each, a tautology that fails on refactor and passes on behavior change | fix: delete the test, or replace it with a behavior test (e.g. a `MetricFamily::new` built with `CONTROLLER_HINT_BUCKETS_SECONDS` accepts an in-range histogram value and rejects an out-of-range one) | [packages/d2b-telemetry/src/meter_registry.rs:176-180] | actionable | lane/d2b-telemetry.md + +**`d2b-unsafe-local-helper`** + +- `RS-0922` | low | `d2b-unsafe-local-helper` | adoption_degrades_identity_ambiguity_without_stopping_scope re-derives snapshot's inline identity-mismatch match on a hand-built ScopeInspection (test lines 1567-1576 mirror production lines 505-508), so it still passes if snapshot later reports `state` instead of Degraded for a mismatched scope | fix: extract the `ScopeInspection::observable_state()` decision used by snapshot into a testable function and assert on that extracted behavior | [packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helper/src/runtime.rs:505-508] | actionable | lane/d2b-unsafe-local-helper.md + +**`d2b-zone-routing`** + +- `RS-0923` | low | `d2b-zone-routing` | `every_reason_the_engine_can_produce_is_covered_by_this_suite` checks only that the 16 named closed reasons have distinct `label()`s, not that the suite produces any of them - the name promises a coverage property the row never asserts | fix: rename it to `every_engine_reason_has_a_distinct_wire_label` and, if coverage is actually wanted, record the reasons each vector produced and assert the set at the end | [packages/d2b-zone-routing/src/engine.rs:3333] | actionable | lane/d2b-zone-routing.md +- `RS-0924` | low | `d2b-zone-routing` | `durable_exec_table_is_bounded_to_ephemeral_processes` ends with a dead `let _ = ZoneId::parse("dev").unwrap();` line that exercises nothing and exists only to use an import | fix: delete the line and the now-unused `ZoneId` import from the test module | [packages/d2b-zone-routing/src/router.rs:517] | actionable | lane/d2b-zone-routing.md + +**`d2bd-runtime`** + +- `RS-0925` | high | `d2bd-runtime` | `sd_notify_ready_noops_without_notify_socket` (runtime_process.rs:543-546) and `sd_notify_ready_errors_when_socket_is_unreachable` (runtime_process.rs:589-594) cannot fail: each body only calls `sd_notify_ready)...)` on a path the function returns without panicking (None early-return; Some-to-missing-socket caught and warn-logged), with no assertion anywhere | fix: delete both, or give them an observable assertion modeled on the sibling `sd_notify_ready_sends_pathname_datagram` (bind a datagram listener, send the payload, assert the received bytes / exit-code), so the suite refuses to pass silently when the notification path regresses | [runtime_process.rs:543-546, runtime_process.rs:589-594] | actionable | lane/d2bd-runtime-p2.md +- `RS-0926` | low | `d2bd-runtime` | `no_op_does_not_write_file` cannot fail on the behavior it names: the temp dir is never connected to the log (`DaemonAuditLog::no_op()` has no state dir; the comment at daemon_audit.rs:2368 admits the limitation), so `count == 0` is vacuously true and only the write-does-not-error `expect` is exercised | fix: make the state dir injectable (or test via a log constructed with a read-only/blocked state dir) so the no-file-created claim is actually asserted, or rename the test to what it verifies | [packages/d2bd-runtime/src/daemon_audit.rs:2367] | actionable | lane/d2bd-runtime-p4.md + +**`xtask`** + +- `RS-0928` | low | `xtask` | `workflow_status_all_enumerates_every_variant` and `wave_commands_enumerates_every_stage` assert `ALL.contains(status)` for every status drawn from `ALL` itself, so the runtime assertion is tautological and can never fail; the real guard is the wildcard-free match's compile-time exhaustiveness, which the assert adds nothing to | fix: drop the `assert!` and keep the wildcard-free match (the compile-fail property), or assert a property not derived from the same enumeration | [packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079] | actionable | lane/xtask-p3.md +- `RS-0927` | low | `xtask` | the broker-operation domain test recomputes its expectation with the same filter the function under test applies (`catalog.rows.iter().filter_map(|row| row.wire_variant.clone())` re-derives `broker_operation_values`' own pick), so the `assert_eq!(values, expected)` can never disagree with the projection logic; only the human-written pins (`UsbipBind` present, `SpawnRunner`/`vmStart` absent) carry behaviour | fix: drop the recomputed `expected` and assert the human-written pins only (the vector equality adds nothing the pins do not) | [packages/xtask/src/gen_layer_catalogs.rs:705] | actionable | lane/xtask-p1.md + +### `supply` + +Supply chain (workspace level): advisories, licences, duplicates, tree weight; every finding ends in a decision. + +**`X1-supply-chain`** + +- `RS-0933` | medium | `X1-supply-chain` | d2b-session depends on d2b-audit but the name appears nowhere in its sources; the dep edge is dead weight in both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28] | actionable | lane/X1-supply-chain.md +- `RS-0934` | medium | `X1-supply-chain` | d2b-session depends on d2b-telemetry but no source reference exists; the edge is carried into both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31] | actionable | lane/X1-supply-chain.md +- `RS-0935` | medium | `X1-supply-chain` | d2b-session's dev-dependency serde_json (workspace-inherited) has zero uses in any of its files | fix: remove the dev-dep (the guest lock regenerates without it) | [packages/d2b-session/Cargo.toml:44] | actionable | lane/X1-supply-chain.md +- `RS-0936` | medium | `X1-supply-chain` | d2b-telemetry inherits rustix via workspace=true but no source in the crate references it; the dep is compiled into the telemetry crate for nothing | fix: remove rustix from [dependencies] (the root workspace entry stays, other members use it); regenerate the guest lock, which carries d2b-telemetry | [packages/d2b-telemetry/Cargo.toml:14] | actionable | lane/X1-supply-chain.md +- `RS-0937` | medium | `X1-supply-chain` | d2b-provider-quota inherits serde_json via workspace=true but no source or test references it | fix: remove serde_json from [dependencies] (and from the generated BUILD deps on the next regen) | [packages/d2b-provider-quota/Cargo.toml:24] | actionable | lane/X1-supply-chain.md +- `RS-0938` | medium | `X1-supply-chain` | d2b-bus's dev-dependency tempfile has zero uses across src/tests(including the ui test tree) | fix: remove the dev-dep | [packages/d2b-bus/Cargo.toml:41] | actionable | lane/X1-supply-chain.md +- `RS-0939` | medium | `X1-supply-chain` | d2b-provider-activation-nixos inherits serde via workspace=true but no source or test in the crate names it | fix: remove serde from [dependencies] | [packages/d2b-provider-activation-nixos/Cargo.toml:35] | actionable | lane/X1-supply-chain.md +- `RS-0940` | medium | `X1-supply-chain` | d2b-provider-audio-pipewire inherits schemars via workspace=true but no derive or path in its sources uses it | fix: remove schemars from [dependencies] | [packages/d2b-provider-audio-pipewire/Cargo.toml:25] | actionable | lane/X1-supply-chain.md +- `RS-0941` | medium | `X1-supply-chain` | d2b-provider-guest-azure-container-apps inherits sha2 via workspace=true but no source reference exists | fix: remove sha2 from [dependencies] | [packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21] | actionable | lane/X1-supply-chain.md +- `RS-0942` | medium | `X1-supply-chain` | d2b-provider-device-gpu declares async-trait but no #[async_trait] or use path names it | fix: remove async-trait from [dependencies] (the Bazel proc-macro dep drops with it on regen) | [packages/d2b-provider-device-gpu/Cargo.toml:20] | actionable | lane/X1-supply-chain.md +- `RS-0943` | medium | `X1-supply-chain` | d2b-provider-device-gpu depends on d2b-resource-types but no source or test in the crate uses it; the edge carries into Bazel too | fix: remove d2b-resource-types from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39] | actionable | lane/X1-supply-chain.md +- `RS-0944` | medium | `X1-supply-chain` | d2b depends on d2b-zone-routing but no source or test references it; the edge is carried into Bazel too | fix: remove d2b-zone-routing from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55] | actionable | lane/X1-supply-chain.md +- `RS-0946` | medium | `X1-supply-chain` | nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a syscall-family crate reach shipped binaries | fix: keep the workspace pin at 0.29, and record+accept the 0.26/0.31 legs with expiry in a [bans] comment (name, pullers, re-check trigger, per DENY.md); then consider flipping multiple-versions to `deny` | [deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33] | actionable | lane/X1-supply-chain.md +- `RS-0947` | medium | `X1-supply-chain` | rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shipped binaries | fix: accept with expiry+record in a [bans] comment (re-check at each dep refresh; or plan a dedicated pass migrating the workspace pin to 1.1 and re-verifying the feature surface, which the root comments pin at 0.38 | [Cargo.toml:202, deny.toml:2] | actionable | lane/X1-supply-chain.md +- `RS-0948` | medium | `X1-supply-chain` | d2b-provider-transport-azure-relay pins webpki-roots "0.26" directly while its tokio-tungstenite 0.24 dep pulls 1.0.9 via its rustls-tls-webpki-roots feature, so the crate builds both legs | fix: upgrade the direct pin to "1" and drop the 0.26 leg(verify the TLS_SERVER_ROOTS API at the call site; if 0.26-only items are used, accept+record+expiry instead) | [packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36] | actionable | lane/X1-supply-chain.md +- `RS-0950` | medium | `X1-supply-chain` | packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2.128, uuid 1.26.1, aws-lc-rs 1.18.1, mio 1.2.3, etc), so the advisory and licence postures of the two shipped trees are assessed against different dependency sets at the same date | fix: regenerate both lockfiles from ONE index snapshot on the next dependency refresh (keeping the guest tree's host-only exclusions; add a drift check comparing shared-crate versions across the two locks) | [packages/Cargo.guest.lock:1, flake.nix:389] | actionable | lane/X1-supply-chain.md +- `RS-0945` | low | `X1-supply-chain` | 13 member decls pin literal versions of workspace-declared deps rustix (3) and sha2 (10, two of them in d2b-broker) instead of the house `workspace = true` pattern (429 workspace-inherit decls across the workspace), duplicating the version truth the root table owns | fix: convert them to `rustix = { workspace = true, features = [...] }` and `sha2 = { workspace = true }`, keeping member-side features (verified additive on the pinned toolchain: a workspace entry + member features resolves with the union on cargo 1.97, offline probe) | [Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, packages/d2b-provider-process/Cargo.toml:30] | actionable | lane/X1-supply-chain.md +- `RS-0949` | low | `X1-supply-chain` | the remaining ~31 duplicate clusters(hashbrown,bitflags,heck,indexmap,linux-raw-sys,memoffset,phf family,proc-macro-crate,r-efi,rand,rand_core,syn,thiserror,toml_datetime,toml_edit,winnow,windows-sys family,windows-link,etc) resolve transitively-only at multiple versions,and deny.toml records none of it (multiple-versions = "warn" alone keeps them invisible) | fix: annotate [bans] with the accepted-cluster inventory(name, versions, pullers, re-check trigger, per DENY.md; then flip multiple-versions to `deny` once the workspace-direct clusters (#14-#16) resolve | [deny.toml:2] | actionable | lane/X1-supply-chain.md +- `RS-0951` | low | `X1-supply-chain` | deny.toml's licence confidence-threshold sits at 0.8, below the rust-supply-chain skill's 0.9 floor, so licences the tool is guessing at(~80% confidence) pass the gate silently,and rare allow-listed licences(CDLA-Permissive-2.0, Unicode-DFS-2016) may be the reason the bar was lowered | fix: raise to 0.9 (and move any failing allow-listed licence to a per-crate `[licenses.exceptions]` entry with the reason attached, per DENY.md),verifying against the vendored tree at the next flake check | [deny.toml:21] | actionable | lane/X1-supply-chain.md + +**`d2b-provider-audio-pipewire`** + +- `RS-0929` | low | `d2b-provider-audio-pipewire` | Cargo.toml declares `schemars` as a runtime dependency with zero uses in src or tests, and `serde_json` (tests-only, 12 hits) sits in `[dependencies]` instead of `[dev-dependencies]` | fix: drop the `schemars` entry and move `serde_json` to `[dev-dependencies]` (Cargo.toml:24-25) | [Cargo.toml:24, Cargo.toml:25] | actionable | lane/d2b-provider-audio-pipewire.md + +**`d2b-provider-device-gpu`** + +- `RS-0930` | low | `d2b-provider-device-gpu` | manifest dependencies `async-trait` and `d2b-resource-types` appear nowhere in the crate's src/+tests/ | fix: drop both from Cargo.toml (and the mirrored Bazel deps) or justify their retention in the manifest | [packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.toml:25] | actionable | lane/d2b-provider-device-gpu.md + +**`d2b-provider-guest-azure-container-apps`** + +- `RS-0931` | low | `d2b-provider-guest-azure-container-apps` | the `sha2` dependency is unused: the name appears nowhere in src/ or tests/ (only in Cargo.toml:21 and as the prose word "digests" in README.md:51) | fix: remove `sha2 = { workspace = true }` from the crate manifest (the workspace dep stays for its other consumers) | [Cargo.toml:21] | actionable | lane/d2b-provider-guest-azure-container-apps.md + +**`d2b-provider-quota`** + +- `RS-0932` | low | `d2b-provider-quota` | `serde_json` is a declared dependency but appears nowhere in the crate's src/ or tests/ | fix: drop `serde_json.workspace = true` from [dependencies] | [packages/d2b-provider-quota/Cargo.toml:24] | actionable | lane/tail-3.md + +## 3. Per-crate index + +| crate | high | medium | low | top finding ids | lanes | +| --- | ---: | ---: | ---: | --- | --- | +| `d2b` | 0 | 6 | 17 | RS-0037, RS-0352, RS-0477, RS-0478, RS-0771 | [d2b-p1](lane/d2b-p1.md), [d2b-p2](lane/d2b-p2.md), [d2b-p3](lane/d2b-p3.md) | +| `d2b-audit` | 0 | 5 | 5 | RS-0001, RS-0239, RS-0316, RS-0451, RS-0452 | [d2b-audit](lane/d2b-audit.md) | +| `d2b-broker` | 5 | 21 | 35 | RS-0455, RS-0837, RS-0841, RS-0842, RS-0840 | [d2b-broker-p1](lane/d2b-broker-p1.md), [d2b-broker-p2](lane/d2b-broker-p2.md), [d2b-broker-p3](lane/d2b-broker-p3.md), [d2b-broker-p4](lane/d2b-broker-p4.md), [d2b-broker-p5](lane/d2b-broker-p5.md), [d2b-broker-p6](lane/d2b-broker-p6.md), [d2b-broker-p7](lane/d2b-broker-p7.md) | +| `d2b-broker-composition` | 0 | 0 | 9 | RS-0004, RS-0005, RS-0126, RS-0127, RS-0128 | [d2b-broker-composition](lane/d2b-broker-composition.md) | +| `d2b-broker-fixture-handlers` | 0 | 0 | 0 | - | [tail-1](lane/tail-1.md) | +| `d2b-broker-fixture-syscall-surface` | 0 | 1 | 0 | RS-0856 | [tail-1](lane/tail-1.md) | +| `d2b-bus` | 1 | 8 | 15 | RS-0867, RS-0245, RS-0324, RS-0325, RS-0326 | [d2b-bus-p1](lane/d2b-bus-p1.md), [d2b-bus-p2](lane/d2b-bus-p2.md) | +| `d2b-contracts` | 0 | 3 | 0 | RS-0327, RS-0461, RS-0546 | [d2b-contracts](lane/d2b-contracts.md) | +| `d2b-contracts-broker` | 0 | 5 | 5 | RS-0246, RS-0247, RS-0328, RS-0547, RS-0639 | [d2b-contracts-broker](lane/d2b-contracts-broker.md) | +| `d2b-contracts-control` | 0 | 6 | 8 | RS-0248, RS-0548, RS-0641, RS-0642, RS-0643 | [d2b-contracts-control](lane/d2b-contracts-control.md) | +| `d2b-contracts-provider` | 0 | 5 | 17 | RS-0253, RS-0463, RS-0646, RS-0871, RS-0872 | [d2b-contracts-provider-p1](lane/d2b-contracts-provider-p1.md), [d2b-contracts-provider-p2](lane/d2b-contracts-provider-p2.md) | +| `d2b-contracts-resource` | 0 | 8 | 11 | RS-0022, RS-0256, RS-0255, RS-0257, RS-0468 | [d2b-contracts-resource-p1](lane/d2b-contracts-resource-p1.md), [d2b-contracts-resource-p2](lane/d2b-contracts-resource-p2.md) | +| `d2b-contracts-zone-session` | 0 | 5 | 11 | RS-0469, RS-0552, RS-0651, RS-0873, RS-0874 | [d2b-contracts-zone-session-p1](lane/d2b-contracts-zone-session-p1.md), [d2b-contracts-zone-session-p2](lane/d2b-contracts-zone-session-p2.md) | +| `d2b-controller-toolkit` | 0 | 0 | 1 | RS-0259 | [tail-1](lane/tail-1.md) | +| `d2b-core` | 0 | 12 | 17 | RS-0261, RS-0348, RS-0345, RS-0349, RS-0346 | [d2b-core-p1](lane/d2b-core-p1.md), [d2b-core-p2](lane/d2b-core-p2.md) | +| `d2b-core-controller` | 0 | 7 | 8 | RS-0340, RS-0341, RS-0342, RS-0343, RS-0553 | [d2b-core-controller-p1](lane/d2b-core-controller-p1.md), [d2b-core-controller-p2](lane/d2b-core-controller-p2.md) | +| `d2b-host` | 0 | 2 | 6 | RS-0262, RS-0878, RS-0351, RS-0557, RS-0656 | [d2b-host](lane/d2b-host.md) | +| `d2b-host-activation-helper` | 0 | 1 | 0 | RS-0859 | [tail-1](lane/tail-1.md) | +| `d2b-process-conformance` | 0 | 0 | 11 | RS-0153, RS-0265, RS-0355, RS-0356, RS-0357 | [d2b-process-conformance](lane/d2b-process-conformance.md) | +| `d2b-provider` | 0 | 2 | 1 | RS-0661, RS-0844, RS-0154 | [d2b-provider](lane/d2b-provider.md) | +| `d2b-provider-activation-nixos` | 0 | 2 | 4 | RS-0480, RS-0662, RS-0359, RS-0360, RS-0585 | [d2b-provider-activation-nixos](lane/d2b-provider-activation-nixos.md) | +| `d2b-provider-audio-binding` | 0 | 0 | 1 | RS-0663 | [tail-1](lane/tail-1.md) | +| `d2b-provider-audio-pipewire` | 0 | 2 | 10 | RS-0481, RS-0664, RS-0266, RS-0267, RS-0361 | [d2b-provider-audio-pipewire](lane/d2b-provider-audio-pipewire.md) | +| `d2b-provider-audio-service` | 0 | 0 | 0 | - | [tail-2](lane/tail-2.md) | +| `d2b-provider-clipboard-wayland` | 0 | 9 | 22 | RS-0040, RS-0039, RS-0268, RS-0586, RS-0666 | [d2b-provider-clipboard-wayland-p1](lane/d2b-provider-clipboard-wayland-p1.md), [d2b-provider-clipboard-wayland-p2](lane/d2b-provider-clipboard-wayland-p2.md) | +| `d2b-provider-command` | 0 | 1 | 1 | RS-0561, RS-0671 | [tail-2](lane/tail-2.md) | +| `d2b-provider-config-nixos` | 0 | 1 | 8 | RS-0889, RS-0044, RS-0156, RS-0272, RS-0365 | [d2b-provider-config-nixos](lane/d2b-provider-config-nixos.md) | +| `d2b-provider-credential` | 0 | 1 | 3 | RS-0813, RS-0157, RS-0273, RS-0673 | [d2b-provider-credential](lane/d2b-provider-credential.md) | +| `d2b-provider-credential-entra` | 0 | 2 | 3 | RS-0045, RS-0366, RS-0367, RS-0674, RS-0891 | [d2b-provider-credential-entra](lane/d2b-provider-credential-entra.md) | +| `d2b-provider-credential-managed-identity` | 0 | 1 | 4 | RS-0274, RS-0368, RS-0488, RS-0675, RS-0892 | [d2b-provider-credential-managed-identity](lane/d2b-provider-credential-managed-identity.md) | +| `d2b-provider-credential-secret-service` | 0 | 3 | 3 | RS-0588, RS-0676, RS-0845, RS-0046, RS-0677 | [d2b-provider-credential-secret-service](lane/d2b-provider-credential-secret-service.md) | +| `d2b-provider-device` | 0 | 1 | 0 | RS-0369 | [tail-2](lane/tail-2.md) | +| `d2b-provider-device-gpu` | 0 | 5 | 8 | RS-0275, RS-0562, RS-0678, RS-0814, RS-0894 | [d2b-provider-device-gpu](lane/d2b-provider-device-gpu.md) | +| `d2b-provider-device-security-key` | 0 | 2 | 3 | RS-0681, RS-0815, RS-0050, RS-0372, RS-0680 | [d2b-provider-device-security-key](lane/d2b-provider-device-security-key.md) | +| `d2b-provider-device-tpm` | 0 | 3 | 8 | RS-0373, RS-0489, RS-0846, RS-0051, RS-0159 | [d2b-provider-device-tpm](lane/d2b-provider-device-tpm.md) | +| `d2b-provider-device-usbip` | 0 | 7 | 4 | RS-0377, RS-0378, RS-0490, RS-0684, RS-0685 | [d2b-provider-device-usbip](lane/d2b-provider-device-usbip.md) | +| `d2b-provider-display-wayland` | 1 | 6 | 16 | RS-0898, RS-0059, RS-0381, RS-0379, RS-0491 | [d2b-provider-display-wayland-p1](lane/d2b-provider-display-wayland-p1.md), [d2b-provider-display-wayland-p2](lane/d2b-provider-display-wayland-p2.md) | +| `d2b-provider-emergency-policy` | 0 | 0 | 0 | - | [tail-2](lane/tail-2.md) | +| `d2b-provider-endpoint` | 0 | 2 | 1 | RS-0061, RS-0565, RS-0060 | [d2b-provider-endpoint](lane/d2b-provider-endpoint.md) | +| `d2b-provider-guest` | 0 | 3 | 4 | RS-0276, RS-0817, RS-0818, RS-0162, RS-0163 | [d2b-provider-guest](lane/d2b-provider-guest.md) | +| `d2b-provider-guest-azure-container-apps` | 0 | 2 | 10 | RS-0277, RS-0900, RS-0164, RS-0165, RS-0166 | [d2b-provider-guest-azure-container-apps](lane/d2b-provider-guest-azure-container-apps.md) | +| `d2b-provider-guest-azure-virtual-machine` | 0 | 4 | 10 | RS-0170, RS-0278, RS-0279, RS-0691, RS-0062 | [d2b-provider-guest-azure-virtual-machine](lane/d2b-provider-guest-azure-virtual-machine.md) | +| `d2b-provider-guest-cloud-hypervisor` | 0 | 7 | 8 | RS-0281, RS-0282, RS-0283, RS-0386, RS-0387 | [d2b-provider-guest-cloud-hypervisor](lane/d2b-provider-guest-cloud-hypervisor.md) | +| `d2b-provider-guest-qemu-media` | 0 | 3 | 6 | RS-0284, RS-0285, RS-0694, RS-0067, RS-0174 | [d2b-provider-guest-qemu-media](lane/d2b-provider-guest-qemu-media.md) | +| `d2b-provider-host` | 0 | 0 | 5 | RS-0068, RS-0175, RS-0392, RS-0494, RS-0495 | [d2b-provider-host](lane/d2b-provider-host.md) | +| `d2b-provider-network-local` | 0 | 2 | 8 | RS-0393, RS-0566, RS-0069, RS-0070, RS-0176 | [d2b-provider-network-local](lane/d2b-provider-network-local.md) | +| `d2b-provider-notification-desktop` | 0 | 4 | 9 | RS-0394, RS-0497, RS-0498, RS-0695, RS-0071 | [d2b-provider-notification-desktop](lane/d2b-provider-notification-desktop.md) | +| `d2b-provider-observability-otel` | 0 | 3 | 6 | RS-0697, RS-0698, RS-0904, RS-0179, RS-0287 | [d2b-provider-observability-otel](lane/d2b-provider-observability-otel.md) | +| `d2b-provider-operation` | 0 | 0 | 1 | RS-0699 | [tail-2](lane/tail-2.md) | +| `d2b-provider-process` | 0 | 1 | 5 | RS-0819, RS-0180, RS-0181, RS-0500, RS-0700 | [d2b-provider-process](lane/d2b-provider-process.md) | +| `d2b-provider-process-minijail` | 0 | 0 | 2 | RS-0288, RS-0701 | [tail-3](lane/tail-3.md) | +| `d2b-provider-process-systemd` | 0 | 1 | 9 | RS-0702, RS-0073, RS-0289, RS-0290, RS-0397 | [d2b-provider-process-systemd](lane/d2b-provider-process-systemd.md) | +| `d2b-provider-provider` | 0 | 1 | 5 | RS-0905, RS-0182, RS-0183, RS-0400, RS-0401 | [d2b-provider-provider](lane/d2b-provider-provider.md) | +| `d2b-provider-quota` | 0 | 0 | 2 | RS-0402, RS-0932 | [tail-3](lane/tail-3.md) | +| `d2b-provider-resource-export` | 0 | 0 | 1 | RS-0403 | [tail-3](lane/tail-3.md) | +| `d2b-provider-resource-import` | 0 | 0 | 1 | RS-0404 | [tail-3](lane/tail-3.md) | +| `d2b-provider-role` | 0 | 0 | 2 | RS-0405, RS-0704 | [tail-3](lane/tail-3.md) | +| `d2b-provider-role-binding` | 0 | 0 | 0 | - | [tail-4](lane/tail-4.md) | +| `d2b-provider-seccomp-profile` | 0 | 1 | 2 | RS-0705, RS-0074, RS-0406 | [tail-4](lane/tail-4.md) | +| `d2b-provider-shell-pool` | 0 | 0 | 0 | - | [tail-4](lane/tail-4.md) | +| `d2b-provider-shell-session` | 0 | 0 | 0 | - | [tail-4](lane/tail-4.md) | +| `d2b-provider-shell-terminal` | 0 | 1 | 2 | RS-0706, RS-0184, RS-0906 | [d2b-provider-shell-terminal](lane/d2b-provider-shell-terminal.md) | +| `d2b-provider-supervisor` | 0 | 4 | 4 | RS-0407, RS-0408, RS-0502, RS-0568, RS-0075 | [d2b-provider-supervisor](lane/d2b-provider-supervisor.md) | +| `d2b-provider-system-core` | 0 | 3 | 9 | RS-0409, RS-0413, RS-0707, RS-0077, RS-0078 | [d2b-provider-system-core](lane/d2b-provider-system-core.md) | +| `d2b-provider-telemetry-binding` | 0 | 0 | 1 | RS-0291 | [tail-4](lane/tail-4.md) | +| `d2b-provider-telemetry-service` | 0 | 1 | 2 | RS-0504, RS-0292, RS-0505 | [tail-5](lane/tail-5.md) | +| `d2b-provider-test-controller` | 0 | 1 | 2 | RS-0592, RS-0506, RS-0593 | [tail-5](lane/tail-5.md) | +| `d2b-provider-toolkit` | 0 | 7 | 14 | RS-0079, RS-0414, RS-0507, RS-0508, RS-0510 | [d2b-provider-toolkit-p1](lane/d2b-provider-toolkit-p1.md), [d2b-provider-toolkit-p2](lane/d2b-provider-toolkit-p2.md) | +| `d2b-provider-transport-azure-relay` | 0 | 5 | 11 | RS-0512, RS-0513, RS-0569, RS-0787, RS-0850 | [d2b-provider-transport-azure-relay](lane/d2b-provider-transport-azure-relay.md) | +| `d2b-provider-transport-unix` | 0 | 0 | 3 | RS-0597, RS-0711, RS-0823 | [tail-5](lane/tail-5.md) | +| `d2b-provider-transport-vsock` | 0 | 1 | 5 | RS-0571, RS-0083, RS-0598, RS-0599, RS-0712 | [d2b-provider-transport-vsock](lane/d2b-provider-transport-vsock.md) | +| `d2b-provider-user` | 1 | 2 | 3 | RS-0851, RS-0824, RS-0910, RS-0192, RS-0514 | [d2b-provider-user](lane/d2b-provider-user.md) | +| `d2b-provider-volume` | 0 | 1 | 4 | RS-0420, RS-0084, RS-0193, RS-0194, RS-0789 | [d2b-provider-volume](lane/d2b-provider-volume.md) | +| `d2b-provider-volume-binding` | 0 | 1 | 3 | RS-0515, RS-0195, RS-0713, RS-0826 | [d2b-provider-volume-binding](lane/d2b-provider-volume-binding.md) | +| `d2b-provider-volume-local` | 0 | 2 | 3 | RS-0421, RS-0572, RS-0085, RS-0294, RS-0714 | [d2b-provider-volume-local](lane/d2b-provider-volume-local.md) | +| `d2b-provider-volume-virtiofs` | 0 | 0 | 0 | - | [d2b-provider-volume-virtiofs](lane/d2b-provider-volume-virtiofs.md) | +| `d2b-provider-wayland-policy` | 1 | 1 | 1 | RS-0516, RS-0573, RS-0911 | [d2b-provider-wayland-policy](lane/d2b-provider-wayland-policy.md) | +| `d2b-provider-wayland-session` | 0 | 0 | 1 | RS-0517 | [tail-5](lane/tail-5.md) | +| `d2b-provider-zone` | 0 | 1 | 1 | RS-0422, RS-0715 | [tail-5](lane/tail-5.md) | +| `d2b-provider-zone-link` | 0 | 1 | 7 | RS-0086, RS-0196, RS-0197, RS-0423, RS-0424 | [d2b-provider-zone-link](lane/d2b-provider-zone-link.md) | +| `d2b-resource-api` | 0 | 6 | 14 | RS-0574, RS-0718, RS-0717, RS-0791, RS-0792 | [d2b-resource-api-p1](lane/d2b-resource-api-p1.md), [d2b-resource-api-p2](lane/d2b-resource-api-p2.md) | +| `d2b-resource-client` | 0 | 1 | 8 | RS-0429, RS-0089, RS-0090, RS-0200, RS-0296 | [d2b-resource-client](lane/d2b-resource-client.md) | +| `d2b-resource-compiler` | 0 | 2 | 7 | RS-0091, RS-0202, RS-0092, RS-0093, RS-0094 | [d2b-resource-compiler](lane/d2b-resource-compiler.md) | +| `d2b-resource-runtime` | 1 | 5 | 23 | RS-0916, RS-0430, RS-0520, RS-0431, RS-0521 | [d2b-resource-runtime-p1](lane/d2b-resource-runtime-p1.md), [d2b-resource-runtime-p2](lane/d2b-resource-runtime-p2.md) | +| `d2b-resource-types` | 0 | 1 | 1 | RS-0433, RS-0725 | [tail-6](lane/tail-6.md) | +| `d2b-session` | 0 | 4 | 16 | RS-0522, RS-0523, RS-0726, RS-0728, RS-0100 | [d2b-session-p1](lane/d2b-session-p1.md), [d2b-session-p2](lane/d2b-session-p2.md) | +| `d2b-session-unix` | 0 | 2 | 2 | RS-0436, RS-0731, RS-0732, RS-0799 | [d2b-session-unix](lane/d2b-session-unix.md) | +| `d2b-sk-frontend` | 0 | 1 | 3 | RS-0920, RS-0102, RS-0214, RS-0437 | [tail-6](lane/tail-6.md) | +| `d2b-telemetry` | 0 | 1 | 3 | RS-0524, RS-0525, RS-0733, RS-0921 | [d2b-telemetry](lane/d2b-telemetry.md) | +| `d2b-unsafe-local-helper` | 0 | 1 | 6 | RS-0526, RS-0103, RS-0299, RS-0438, RS-0601 | [d2b-unsafe-local-helper](lane/d2b-unsafe-local-helper.md) | +| `d2b-zone-routing` | 0 | 1 | 6 | RS-0852, RS-0104, RS-0105, RS-0215, RS-0734 | [d2b-zone-routing](lane/d2b-zone-routing.md) | +| `d2bd` | 0 | 18 | 47 | RS-0303, RS-0531, RS-0442, RS-0532, RS-0305 | [d2bd-p1](lane/d2bd-p1.md), [d2bd-p2](lane/d2bd-p2.md), [d2bd-p3](lane/d2bd-p3.md), [d2bd-p4](lane/d2bd-p4.md), [d2bd-p5](lane/d2bd-p5.md), [d2bd-p6](lane/d2bd-p6.md), [d2bd-p7](lane/d2bd-p7.md), [d2bd-p8](lane/d2bd-p8.md) | +| `d2bd-runtime` | 2 | 13 | 34 | RS-0538, RS-0925, RS-0307, RS-0444, RS-0539 | [d2bd-runtime-p1](lane/d2bd-runtime-p1.md), [d2bd-runtime-p2](lane/d2bd-runtime-p2.md), [d2bd-runtime-p3](lane/d2bd-runtime-p3.md), [d2bd-runtime-p4](lane/d2bd-runtime-p4.md) | +| `xtask` | 0 | 6 | 31 | RS-0118, RS-0120, RS-0314, RS-0543, RS-0755 | [xtask-p1](lane/xtask-p1.md), [xtask-p2](lane/xtask-p2.md), [xtask-p3](lane/xtask-p3.md), [xtask-p4](lane/xtask-p4.md), [xtask-p5](lane/xtask-p5.md) | + +## 4. Cross-cutting lanes + +### `X1-supply-chain` + +(Rows also listed under their lens in section 2.) + +- `RS-0933` | medium | `supply` | d2b-session depends on d2b-audit but the name appears nowhere in its sources; the dep edge is dead weight in both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28] | actionable | lane/X1-supply-chain.md +- `RS-0934` | medium | `supply` | d2b-session depends on d2b-telemetry but no source reference exists; the edge is carried into both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31] | actionable | lane/X1-supply-chain.md +- `RS-0935` | medium | `supply` | d2b-session's dev-dependency serde_json (workspace-inherited) has zero uses in any of its files | fix: remove the dev-dep (the guest lock regenerates without it) | [packages/d2b-session/Cargo.toml:44] | actionable | lane/X1-supply-chain.md +- `RS-0936` | medium | `supply` | d2b-telemetry inherits rustix via workspace=true but no source in the crate references it; the dep is compiled into the telemetry crate for nothing | fix: remove rustix from [dependencies] (the root workspace entry stays, other members use it); regenerate the guest lock, which carries d2b-telemetry | [packages/d2b-telemetry/Cargo.toml:14] | actionable | lane/X1-supply-chain.md +- `RS-0937` | medium | `supply` | d2b-provider-quota inherits serde_json via workspace=true but no source or test references it | fix: remove serde_json from [dependencies] (and from the generated BUILD deps on the next regen) | [packages/d2b-provider-quota/Cargo.toml:24] | actionable | lane/X1-supply-chain.md +- `RS-0938` | medium | `supply` | d2b-bus's dev-dependency tempfile has zero uses across src/tests(including the ui test tree) | fix: remove the dev-dep | [packages/d2b-bus/Cargo.toml:41] | actionable | lane/X1-supply-chain.md +- `RS-0939` | medium | `supply` | d2b-provider-activation-nixos inherits serde via workspace=true but no source or test in the crate names it | fix: remove serde from [dependencies] | [packages/d2b-provider-activation-nixos/Cargo.toml:35] | actionable | lane/X1-supply-chain.md +- `RS-0940` | medium | `supply` | d2b-provider-audio-pipewire inherits schemars via workspace=true but no derive or path in its sources uses it | fix: remove schemars from [dependencies] | [packages/d2b-provider-audio-pipewire/Cargo.toml:25] | actionable | lane/X1-supply-chain.md +- `RS-0941` | medium | `supply` | d2b-provider-guest-azure-container-apps inherits sha2 via workspace=true but no source reference exists | fix: remove sha2 from [dependencies] | [packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21] | actionable | lane/X1-supply-chain.md +- `RS-0942` | medium | `supply` | d2b-provider-device-gpu declares async-trait but no #[async_trait] or use path names it | fix: remove async-trait from [dependencies] (the Bazel proc-macro dep drops with it on regen) | [packages/d2b-provider-device-gpu/Cargo.toml:20] | actionable | lane/X1-supply-chain.md +- `RS-0943` | medium | `supply` | d2b-provider-device-gpu depends on d2b-resource-types but no source or test in the crate uses it; the edge carries into Bazel too | fix: remove d2b-resource-types from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39] | actionable | lane/X1-supply-chain.md +- `RS-0944` | medium | `supply` | d2b depends on d2b-zone-routing but no source or test references it; the edge is carried into Bazel too | fix: remove d2b-zone-routing from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55] | actionable | lane/X1-supply-chain.md +- `RS-0946` | medium | `supply` | nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a syscall-family crate reach shipped binaries | fix: keep the workspace pin at 0.29, and record+accept the 0.26/0.31 legs with expiry in a [bans] comment (name, pullers, re-check trigger, per DENY.md); then consider flipping multiple-versions to `deny` | [deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33] | actionable | lane/X1-supply-chain.md +- `RS-0947` | medium | `supply` | rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shipped binaries | fix: accept with expiry+record in a [bans] comment (re-check at each dep refresh; or plan a dedicated pass migrating the workspace pin to 1.1 and re-verifying the feature surface, which the root comments pin at 0.38 | [Cargo.toml:202, deny.toml:2] | actionable | lane/X1-supply-chain.md +- `RS-0948` | medium | `supply` | d2b-provider-transport-azure-relay pins webpki-roots "0.26" directly while its tokio-tungstenite 0.24 dep pulls 1.0.9 via its rustls-tls-webpki-roots feature, so the crate builds both legs | fix: upgrade the direct pin to "1" and drop the 0.26 leg(verify the TLS_SERVER_ROOTS API at the call site; if 0.26-only items are used, accept+record+expiry instead) | [packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36] | actionable | lane/X1-supply-chain.md +- `RS-0950` | medium | `supply` | packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2.128, uuid 1.26.1, aws-lc-rs 1.18.1, mio 1.2.3, etc), so the advisory and licence postures of the two shipped trees are assessed against different dependency sets at the same date | fix: regenerate both lockfiles from ONE index snapshot on the next dependency refresh (keeping the guest tree's host-only exclusions; add a drift check comparing shared-crate versions across the two locks) | [packages/Cargo.guest.lock:1, flake.nix:389] | actionable | lane/X1-supply-chain.md +- `RS-0945` | low | `supply` | 13 member decls pin literal versions of workspace-declared deps rustix (3) and sha2 (10, two of them in d2b-broker) instead of the house `workspace = true` pattern (429 workspace-inherit decls across the workspace), duplicating the version truth the root table owns | fix: convert them to `rustix = { workspace = true, features = [...] }` and `sha2 = { workspace = true }`, keeping member-side features (verified additive on the pinned toolchain: a workspace entry + member features resolves with the union on cargo 1.97, offline probe) | [Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, packages/d2b-provider-process/Cargo.toml:30] | actionable | lane/X1-supply-chain.md +- `RS-0949` | low | `supply` | the remaining ~31 duplicate clusters(hashbrown,bitflags,heck,indexmap,linux-raw-sys,memoffset,phf family,proc-macro-crate,r-efi,rand,rand_core,syn,thiserror,toml_datetime,toml_edit,winnow,windows-sys family,windows-link,etc) resolve transitively-only at multiple versions,and deny.toml records none of it (multiple-versions = "warn" alone keeps them invisible) | fix: annotate [bans] with the accepted-cluster inventory(name, versions, pullers, re-check trigger, per DENY.md; then flip multiple-versions to `deny` once the workspace-direct clusters (#14-#16) resolve | [deny.toml:2] | actionable | lane/X1-supply-chain.md +- `RS-0951` | low | `supply` | deny.toml's licence confidence-threshold sits at 0.8, below the rust-supply-chain skill's 0.9 floor, so licences the tool is guessing at(~80% confidence) pass the gate silently,and rare allow-listed licences(CDLA-Permissive-2.0, Unicode-DFS-2016) may be the reason the bar was lowered | fix: raise to 0.9 (and move any failing allow-listed licence to a per-crate `[licenses.exceptions]` entry with the reason attached, per DENY.md),verifying against the vendored tree at the next flake check | [deny.toml:21] | actionable | lane/X1-supply-chain.md + +### `X2-generated-boundary` + +(Rows also listed under their lens in section 2.) + +- `RS-0952` | medium | `api` | the hand-maintained registry `d2b-resource-api/src/generated/mod.rs:3-4` glob-re-exports the entire protobuf module (`pub use d2b_contracts_resource::resource_proto::*;`) as public surface of d2b-resource-api, exposing 47 items including reflection internals (`file_descriptor()` at `d2b_resource_v3.rs:7522`, `special_fields: ::protobuf::SpecialFields` on every message) and forcing `pub use protobuf;` at `d2b-resource-api/src/lib.rs:24` - with zero consumers | fix: delete the `d2b_resource_v3` re-export module from the registry (consumers use `d2b_contracts_resource::resource_proto` directly, e.g. `adapter.rs:560,578`); if a consumer ever needs the types through this crate, re-export named arms instead of a glob | [packages/d2b-resource-api/src/generated/mod.rs:3-4, packages/xtask/src/main.rs:355-370, packages/d2b-resource-api/src/lib.rs:24] | actionable | lane/X2-generated-boundary.md +- `RS-0954` | medium | `type` | the broker catalog view emits the authz facets as string literals (`secret_access: "None"`, `broker_required: "Yes"`, `audit_mode: "Yes"` at `broker_operation_catalog.rs:25-27` and every row) into the hand-written `BrokerAuthzFacets` struct whose fields are `&'static str` (`catalog.rs:98-102`), while the same generator emits the same declared data as typed enums in the sibling authz view (`SecretAccess::None`, `BrokerRequirement::Yes`, `AuditMode::Yes` at `broker_operation_authz.rs:12-19`); the broker-composition router string-matches the facet (`row.authz.secret_access != "None"` at routing.rs:98) and a hand-written row already drifts case (`audit_mode: "yes"` at `d2b-broker/src/envelope/mod.rs:2277` vs generated "Yes") | fix: change `BrokerAuthzFacets.secret_access/broker_required/audit_mode` to the existing `SecretAccess`/`BrokerRequirement`/`AuditMode` enums (`d2b-core/src/privileges.rs:48,61,83`; d2b-broker already depends on d2b-core per Cargo.toml:48) and make `generate_catalog` emit enum idents exactly as `generate_authz` already does | [packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19] | actionable | lane/X2-generated-boundary.md +- `RS-0955` | medium | `type` | `BrokerOperationRow.disposition` is `&'static str` (`catalog.rs:181`) holding a closed 4-value set emitted by the generator (`disposition: "promoted-live"` etc. at `broker_operation_catalog.rs:17` and 97 more rows), string-matched at catalog.rs:590,773,779,791 and runtime.rs:12562, while the same generator already maps every other closed set to enums (`owner_variant`, profile match, `StubTarget`) | fix: add a `Disposition` enum (four variants: callable-read-only, promoted-live, stubbed-unimplemented, compile-time-only) beside `StubTarget` in `d2b-broker/src/catalog.rs:266`, change the struct field, and have `generate_catalog` emit `Disposition::X` like `owner_variant` | [packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_operation_catalog.rs:17, packages/d2b-broker/src/catalog.rs:181, packages/d2b-broker/src/catalog.rs:590] | actionable | lane/X2-generated-boundary.md +- `RS-0953` | low | `api` | `d2b-audit/src/lib.rs:7` declares `pub mod generated;` but every consumer of the emitted catalog is in-crate (`crate::generated::audit_catalog::...` at record_types.rs:1038,1067,1212,1297,1367) | fix: `mod generated;` (private) in lib.rs; the emitted file and its registry need no change | [packages/d2b-audit/src/lib.rs:7, packages/xtask/src/gen_layer_catalogs.rs:725, packages/d2b-audit/src/generated/audit_catalog.rs:6-8] | actionable | lane/X2-generated-boundary.md +- `RS-0956` | low | `type` | the operation-name vocabulary is emitted as strings (`HOST_OPERATION_CATALOG`/`GUEST_OPERATION_CATALOG: &[&str]` at `broker_operation_profiles.rs:8-41`, `operation: "Hello"` at `broker_operation_catalog.rs:11`) and admission is a string `contains` (`BrokerProfile::allows_operation` at `d2b-contracts-broker/src/broker_wire.rs:864-889`), while the same generator emits the w3 subset as the typed `W3BrokerOperation` enum (`w3_broker_operations.rs`, re-exported at `d2b-contracts-broker/src/lib.rs:11`) | fix: have `generate_profiles`/`generate_catalog` emit a full closed `BrokerOperationName` enum (all 98 rows, not just the 24 w3 variants) with `as_str`, and type the catalogs and row `operation` field against it; the wire boundary keeps the string spelling via `as_str` | [packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11] | actionable | lane/X2-generated-boundary.md +- `RS-0957` | low | `type` | the authz view's positional `row)...)` helper calls carry a bare boolean at argument 5 (`false`/`true` for `destructive` at `broker_operation_authz.rs:12-19` and every row), the boolean-trap shape the type lens names, in a 988-line generated file where the field is the routing-relevant facet (`row.authz.destructive` at routing.rs:98) | fix: emit `Destructive::No`/`Destructive::Yes` (or named-field construction) from `generate_authz` and drop the `#[allow(clippy::too_many_arguments)]` on the hand-written `row()` helper at `d2b-core/src/privileges.rs:687-708` | [packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-core/src/privileges.rs:687-708] | actionable | lane/X2-generated-boundary.md + +### `X3-cross-crate-duplication` + +(Rows also listed under their lens in section 2.) + +- `RS-0962` | high | `type` | Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one member, d2b-provider-wayland-policy, panics on caller input at the family engine's public boundary) | fix: type the args field as `d2b_contracts_resource::v3::ZoneId` (or a `BoundedToken`) in each `*DriverArgs` and parse once at the daemon construction boundary, with `SharedProviderDriverArgs` in d2b-provider-toolkit as the shared home the family args mirror | [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-credential/src/driver.rs:295] | actionable | lane/X3-cross-crate-duplication.md +- `RS-0958` | medium | `test` | Provider test-support recorder/harness duplication: each provider crate hand-rolls the same recorder-double family (RecordingEffects/ScriptedProbe/RecordingManager/RecordingRequeue-style recording doubles, ScriptedPort/ScriptedDiscoveryPort/ScriptedEffectPort scripted ports, hand-rolled block_on pollers, TicketBuilder-style fixtures) in its own test_support.rs/testing.rs instead of the toolkit's shipped harness | fix: consolidate the recorder/harness shapes onto `d2b-provider-toolkit/src/testing` (TestHarness at testing/mod.rs:397, fakes.rs, fixture.rs, conformance.rs) and have the family crates reuse it; the toolkit module is the B3-kept base, so this does not re-propose the B3 refusal | [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-volume-binding/src/test_support.rs:17] | actionable | lane/X3-cross-crate-duplication.md +- `RS-0960` | medium | `conc` | parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-census-baseline.json, `parking_lot::Mutex::lock: 0` for every crate) key on the path `parking_lot::Mutex::lock`, which never resolves because `parking_lot::Mutex` is a type alias (`pub type Mutex = lock_api::Mutex`), so unsuppressed lock sites in 10+ crates record zero hits and no per-site allow is demanded | fix: configure the disallowed entry and the census DeniedApi list on the resolved path (`lock_api::Mutex::lock`, or the def-path clippy reports for the alias), then re-run the census so the unsuppressed sites surface and get per-site allows or conversions per the KD3 ban | [clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-security-key/src/relay_service.rs:129] | policy-confirmed | lane/X3-cross-crate-duplication.md +- `RS-0961` | medium | `serde` | Parallel serde shims: contract/provider crates hand-write the identical Wire-struct admission shape (private `#[derive(Deserialize)]` Wire with deny_unknown_fields, then new()/TryFrom with validation) in 24+ impls where the in-tree `parsed_deserialize!` macro exists | fix: consolidate behind `parsed_deserialize!` (d2b-contracts-resource/src/v3/execution_policy.rs:33, re-exported at :63) or `#[serde(try_from = "...")]` with the raw Wire shape, keeping every admission gate; this deduplicates boilerplate and is distinct from the refused gate-removal class (over-engineering-audit-record.md rows 25/33 refused replacing gates with derives) | [packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs:101, packages/d2b-contracts-zone-session/src/v3/zone.rs:79, packages/d2b-contracts-zone-session/src/v3/role_binding.rs:192] | actionable | lane/X3-cross-crate-duplication.md +- `RS-0963` | medium | `err` | Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { path, detail: String }`, `Io(String)`, `Frame(String)`, `ManagerRpc(String)`, `TypedError::InternalIo { context, detail }`, five `String` variants of PlaneError, `kind: String` in four Io variants), destroying the source chain so diagnostics and callers cannot distinguish failure classes | fix: carry the source with thiserror `#[from]`/`source()` in each enum (no in-tree helper exists; the std Error source chain is the canonical home); wire-visible members (d2bd TypedError) need contract sign-off before the shape changes, internal members (broker, clipboard, azure-relay, resource-runtime, d2bd-runtime vsock) are actionable first | [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69] | needs-contract | lane/X3-cross-crate-duplication.md +- `RS-0964` | medium | `own` | Repeated ownership pattern: public signatures and fields across eight crates leak `Arc`/`&Arc` (accessors returning `&Arc`, constructors taking `Arc` where single ownership suffices, pub fields carrying `Arc>`), forcing callers to see refcount plumbing and blocking signature evolution | fix: return `&T`/owned values and take owned parameters per the ownership-not-clone convention (canonical home is the borrow/owned convention; no shared type involved, so the merge target is per-crate signatures) | [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:491, packages/d2b-provider-toolkit/src/testing/mod.rs:530, packages/d2b-provider-supervisor/src/broker.rs:997] | actionable | lane/X3-cross-crate-duplication.md +- `RS-0959` | low | `test` | Test-support shipping shape: `test-support` features declared empty and gating nothing in four declaration crates while three provider crates ship `pub mod testing` (ScriptedPort/block_on harnesses) unconditionally in the production library and d2b-resource-types exports a test-only helper through the root despite declaring the feature | fix: wire each `test-support = []` feature to its module (`#[cfg(feature = "test-support")]` on `pub mod testing`, `#[cfg(feature = "test-support")]` on `assert_metadata_registration`) or drop the empty features, following the house pattern at d2b-provider-host/Cargo.toml:28 | [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-role/Cargo.toml:17] | actionable | lane/X3-cross-crate-duplication.md +- `RS-0965` | low | `api` | Double-path public surface: eleven crates expose every item of a module at two public paths (`pub mod x` plus root `pub use x::*` or item re-exports), deviating from the house single-surface convention and letting future pub items silently widen API | fix: keep one public path per item (either the module or the root re-export, per the house single-surface pattern the d2b-sk-frontend lane names), deleting the duplicate arm in each lib.rs | [packages/d2b-provider-device-usbip/src/lib.rs:24, packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-zone/src/lib.rs:17, packages/d2b-sk-frontend/src/lib.rs:22] | actionable | lane/X3-cross-crate-duplication.md + +## 5. Coverage matrix (94 crates x 16 lenses) + +Cell = findings count. `clean` = the lane ran the lens with zero findings and nonzero seed mass; `N/A` = all of the lens's seeds returned zero for the crate (U1-constraints.md section (e) row) and the lens card's applicability criteria fail. `supply` is workspace-level (lane X1), shown as `X1` everywhere. Cells are summed over a crate's part lanes. Eight cells show a count where the U1 pre-scan row is zero (the lane's own read found what the single-pass pre-scan did not): d2b-controller-toolkit/type, d2b-provider-credential-entra/idiom, d2b-provider-credential-secret-service/idiom, d2b-provider-guest-azure-container-apps/type, d2b-provider-seccomp-profile/idiom, d2b-provider-system-core/idiom, d2b-provider-volume/idiom, d2b-provider-wayland-session/err; every `N/A` cell satisfies both conditions above. + +| crate | `idiom` | `own` | `type` | `api` | `err` | `serde` | `obs` | `docs` | `perf` | `conc` | `async` | `unsafe` | `ffi` | `macro` | `test` | `supply` | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| `d2b` | 7 | 4 | 2 | 3 | 2 | clean | clean | 2 | 1 | clean | clean | clean | N/A | N/A | 2 | X1 | +| `d2b-audit` | 3 | 1 | 1 | 1 | 2 | clean | clean | 1 | 1 | clean | N/A | clean | N/A | clean | clean | X1 | +| `d2b-broker` | 7 | 3 | 3 | 7 | 6 | 1 | 1 | 18 | 5 | 1 | 6 | 2 | clean | clean | 1 | X1 | +| `d2b-broker-composition` | 2 | 3 | N/A | clean | 1 | 1 | clean | clean | clean | N/A | clean | clean | N/A | clean | 2 | X1 | +| `d2b-broker-fixture-handlers` | N/A | clean | N/A | clean | N/A | N/A | N/A | clean | clean | N/A | clean | clean | N/A | N/A | N/A | X1 | +| `d2b-broker-fixture-syscall-surface` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | 1 | clean | N/A | N/A | X1 | +| `d2b-bus` | 2 | 3 | 3 | 3 | 1 | clean | clean | 6 | 2 | 1 | clean | N/A | N/A | clean | 3 | X1 | +| `d2b-contracts` | clean | clean | clean | 1 | 1 | 1 | N/A | clean | clean | N/A | N/A | N/A | N/A | clean | clean | X1 | +| `d2b-contracts-broker` | 3 | clean | 2 | 2 | clean | 1 | N/A | 2 | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-contracts-control` | N/A | clean | 3 | 4 | 1 | 1 | N/A | 4 | clean | N/A | N/A | N/A | N/A | N/A | 1 | X1 | +| `d2b-contracts-provider` | 3 | 4 | 3 | 1 | 5 | 1 | clean | 2 | clean | 1 | clean | N/A | N/A | clean | 2 | X1 | +| `d2b-contracts-resource` | 4 | 1 | 4 | 2 | 1 | 2 | N/A | 4 | 1 | clean | N/A | N/A | N/A | clean | clean | X1 | +| `d2b-contracts-zone-session` | 1 | 5 | 1 | 3 | 1 | 1 | N/A | 1 | 1 | N/A | N/A | N/A | N/A | clean | 2 | X1 | +| `d2b-controller-toolkit` | N/A | N/A | 1 | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | N/A | X1 | +| `d2b-core` | 4 | 2 | 1 | 6 | 6 | 3 | 1 | 2 | 3 | clean | clean | clean | N/A | clean | 1 | X1 | +| `d2b-core-controller` | 1 | 2 | 1 | 5 | 1 | 1 | N/A | 2 | clean | clean | clean | N/A | N/A | N/A | 2 | X1 | +| `d2b-host` | clean | clean | 1 | 1 | clean | 1 | clean | 2 | 1 | clean | clean | clean | clean | clean | 2 | X1 | +| `d2b-host-activation-helper` | N/A | clean | N/A | N/A | clean | N/A | clean | clean | clean | N/A | N/A | 1 | clean | N/A | clean | X1 | +| `d2b-process-conformance` | N/A | 1 | 1 | 4 | 1 | 2 | N/A | 1 | clean | clean | 1 | N/A | N/A | clean | clean | X1 | +| `d2b-provider` | clean | 1 | N/A | clean | clean | N/A | N/A | 1 | clean | clean | 1 | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-activation-nixos` | N/A | clean | clean | 2 | 1 | clean | 1 | 1 | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | +| `d2b-provider-audio-binding` | clean | clean | N/A | clean | N/A | N/A | N/A | 1 | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-audio-pipewire` | clean | clean | 2 | 3 | 2 | clean | clean | 2 | clean | clean | clean | clean | N/A | N/A | 2 | 1 | +| `d2b-provider-audio-service` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-clipboard-wayland` | 6 | 1 | 4 | 1 | 4 | 1 | 2 | 5 | 2 | 1 | N/A | clean | N/A | N/A | 4 | X1 | +| `d2b-provider-command` | N/A | clean | N/A | clean | clean | 1 | N/A | 1 | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-config-nixos` | 1 | 1 | 1 | 1 | 1 | clean | clean | 1 | 1 | clean | clean | clean | N/A | N/A | 2 | X1 | +| `d2b-provider-credential` | N/A | 1 | 1 | clean | clean | clean | clean | 1 | clean | 1 | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-credential-entra` | 1 | clean | clean | 2 | clean | N/A | clean | 1 | clean | clean | clean | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-credential-managed-identity` | N/A | clean | 1 | 1 | 1 | N/A | clean | 1 | clean | clean | clean | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-credential-secret-service` | 1 | clean | clean | clean | clean | N/A | 1 | 2 | clean | clean | 1 | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-device` | N/A | clean | N/A | 1 | N/A | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-device-gpu` | 3 | 1 | 1 | 2 | clean | 1 | clean | 2 | clean | 1 | N/A | clean | N/A | N/A | 1 | 1 | +| `d2b-provider-device-security-key` | 1 | clean | clean | 1 | clean | clean | clean | 2 | clean | 1 | clean | clean | N/A | N/A | clean | X1 | +| `d2b-provider-device-tpm` | 1 | 1 | clean | 4 | 1 | clean | clean | 2 | clean | clean | 2 | clean | N/A | N/A | clean | X1 | +| `d2b-provider-device-usbip` | 1 | 1 | clean | 2 | 1 | clean | clean | 2 | clean | 1 | clean | N/A | N/A | N/A | 3 | X1 | +| `d2b-provider-display-wayland` | 7 | 1 | clean | 4 | 3 | 2 | clean | 3 | 1 | N/A | N/A | clean | clean | 1 | 1 | X1 | +| `d2b-provider-emergency-policy` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-endpoint` | 2 | clean | clean | clean | clean | 1 | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-guest` | clean | 2 | 1 | clean | clean | clean | clean | 1 | 1 | 2 | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-guest-azure-container-apps` | N/A | 6 | 1 | 1 | clean | clean | clean | 1 | N/A | N/A | clean | clean | N/A | clean | 2 | 1 | +| `d2b-provider-guest-azure-virtual-machine` | 1 | 4 | 3 | 2 | clean | clean | 1 | 2 | N/A | N/A | clean | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-guest-cloud-hypervisor` | 4 | clean | 3 | 5 | clean | clean | clean | 1 | 1 | N/A | clean | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-guest-qemu-media` | 1 | 1 | 2 | 1 | clean | clean | 1 | 1 | 1 | N/A | N/A | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-host` | 1 | 1 | clean | 1 | 2 | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-network-local` | 2 | 1 | clean | 1 | 1 | 2 | clean | clean | 2 | clean | 1 | N/A | N/A | clean | clean | X1 | +| `d2b-provider-notification-desktop` | 2 | 2 | 1 | 3 | 2 | clean | clean | 2 | 1 | clean | N/A | clean | N/A | N/A | clean | X1 | +| `d2b-provider-observability-otel` | clean | 1 | 1 | clean | 1 | clean | clean | 2 | 3 | clean | N/A | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-operation` | clean | clean | N/A | clean | clean | clean | N/A | 1 | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-process` | clean | 2 | clean | clean | 1 | clean | clean | 1 | clean | 2 | clean | clean | N/A | N/A | clean | X1 | +| `d2b-provider-process-minijail` | N/A | clean | 1 | clean | clean | N/A | clean | 1 | clean | N/A | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-process-systemd` | 1 | clean | 2 | 3 | 1 | clean | 1 | 1 | 1 | N/A | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-provider` | clean | 2 | clean | 2 | clean | clean | clean | 1 | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | +| `d2b-provider-quota` | N/A | N/A | N/A | 1 | N/A | clean | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | 1 | +| `d2b-provider-resource-export` | N/A | N/A | N/A | 1 | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-resource-import` | N/A | N/A | N/A | 1 | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-role` | N/A | N/A | N/A | 1 | clean | N/A | N/A | 1 | clean | clean | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-role-binding` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-seccomp-profile` | 1 | clean | N/A | 1 | clean | clean | N/A | 1 | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-shell-pool` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-shell-session` | N/A | clean | N/A | clean | N/A | clean | N/A | clean | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-shell-terminal` | N/A | 1 | clean | clean | clean | N/A | clean | 1 | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | +| `d2b-provider-supervisor` | 2 | clean | clean | 2 | 2 | 1 | clean | clean | clean | clean | clean | N/A | N/A | clean | 1 | X1 | +| `d2b-provider-system-core` | 2 | 1 | N/A | 5 | clean | clean | clean | 1 | N/A | 1 | 1 | N/A | N/A | N/A | 1 | X1 | +| `d2b-provider-telemetry-binding` | clean | clean | 1 | clean | clean | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-telemetry-service` | clean | clean | 1 | clean | 2 | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-test-controller` | N/A | clean | N/A | N/A | 1 | N/A | 2 | clean | N/A | N/A | clean | clean | N/A | N/A | clean | X1 | +| `d2b-provider-toolkit` | 2 | 4 | clean | 4 | 5 | clean | 2 | 2 | 1 | 1 | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-transport-azure-relay` | 2 | 2 | 1 | 2 | 2 | 2 | 1 | 1 | 2 | clean | 1 | clean | N/A | N/A | clean | X1 | +| `d2b-provider-transport-unix` | clean | N/A | clean | clean | clean | N/A | 1 | 1 | clean | 1 | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-transport-vsock` | 1 | clean | N/A | clean | clean | 1 | 2 | 1 | clean | clean | clean | clean | N/A | N/A | 1 | X1 | +| `d2b-provider-user` | N/A | 1 | clean | clean | 1 | clean | clean | clean | clean | 2 | 1 | N/A | N/A | N/A | 1 | X1 | +| `d2b-provider-volume` | 1 | 2 | clean | 1 | clean | clean | N/A | clean | 1 | clean | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-volume-binding` | N/A | 1 | N/A | clean | 1 | clean | clean | 1 | clean | 1 | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-volume-local` | 1 | clean | 1 | 1 | clean | 1 | clean | 1 | clean | clean | clean | clean | N/A | N/A | clean | X1 | +| `d2b-provider-volume-virtiofs` | N/A | clean | clean | clean | clean | clean | clean | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-wayland-policy` | N/A | clean | clean | clean | 1 | 1 | N/A | clean | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | +| `d2b-provider-wayland-session` | clean | clean | N/A | clean | 1 | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-zone` | N/A | clean | N/A | 1 | clean | N/A | N/A | 1 | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | +| `d2b-provider-zone-link` | 1 | 2 | clean | 3 | clean | clean | N/A | 1 | clean | clean | N/A | N/A | N/A | N/A | 1 | X1 | +| `d2b-resource-api` | 2 | 2 | 1 | 3 | 1 | 1 | 1 | 2 | 4 | clean | clean | N/A | N/A | 1 | 2 | X1 | +| `d2b-resource-client` | 2 | 1 | 1 | 1 | 1 | clean | N/A | 1 | clean | 1 | clean | N/A | N/A | N/A | 1 | X1 | +| `d2b-resource-compiler` | 4 | 5 | clean | clean | clean | clean | clean | clean | clean | clean | N/A | clean | clean | N/A | clean | X1 | +| `d2b-resource-runtime` | 5 | 7 | clean | 3 | 2 | clean | clean | 5 | 2 | 2 | clean | N/A | N/A | N/A | 3 | X1 | +| `d2b-resource-types` | N/A | clean | N/A | 1 | clean | N/A | N/A | 1 | clean | N/A | clean | N/A | N/A | N/A | clean | X1 | +| `d2b-session` | 2 | 1 | 2 | 2 | 2 | N/A | clean | 5 | 3 | 1 | clean | clean | N/A | 1 | 1 | X1 | +| `d2b-session-unix` | clean | clean | clean | 1 | clean | N/A | clean | 2 | 1 | clean | clean | clean | N/A | clean | clean | X1 | +| `d2b-sk-frontend` | 1 | 1 | N/A | 1 | clean | N/A | clean | clean | clean | clean | clean | clean | N/A | N/A | 1 | X1 | +| `d2b-telemetry` | N/A | clean | clean | clean | 2 | clean | N/A | 1 | clean | clean | N/A | clean | N/A | N/A | 1 | X1 | +| `d2b-unsafe-local-helper` | 1 | clean | 1 | 1 | 1 | clean | 1 | clean | clean | 1 | N/A | clean | N/A | N/A | 1 | X1 | +| `d2b-zone-routing` | 2 | 1 | clean | clean | clean | N/A | N/A | 1 | clean | clean | 1 | N/A | N/A | clean | 2 | X1 | +| `d2bd` | 8 | 9 | 6 | 5 | 11 | 3 | 7 | 8 | 4 | 2 | 2 | clean | N/A | N/A | clean | X1 | +| `d2bd-runtime` | 4 | 4 | 6 | 7 | 5 | 2 | 5 | 9 | 1 | 3 | 1 | clean | N/A | N/A | 2 | X1 | +| `xtask` | 7 | 10 | 4 | clean | 1 | 3 | clean | 5 | 4 | clean | clean | clean | clean | 1 | 2 | X1 | + +Lane-to-crate completeness: 94 workspace members = 17 crates via 51 part-lane files + 50 whole-crate lane files + 27 crates via 6 tail-lane files; no crate appears in two lanes and none is missing (machine-checked by the renderer and by VERIFICATION.md check 2). + +## 6. Remediation input + +Clusters group findings by lens family, blast radius, and precondition. Suggested order: leaf and `actionable` first; family next; `wide`/`needs-contract` last. Every remediation PR must keep `make check` (Bazel suite incl. per-crate clippy), `make test-unit`, `make generate`, and the `security-scan` job green. + +| cluster (lens / blast / verdict) | n | member RS ids | +| --- | ---: | --- | +| `idiom` / leaf / actionable | 122 | RS-0001, RS-0004, RS-0006, RS-0007, RS-0008, RS-0009, RS-0013, RS-0014, RS-0015, RS-0018, RS-0020, RS-0021, RS-0022, RS-0025, RS-0026, RS-0027, RS-0030, RS-0031, RS-0036, RS-0040, RS-0044, RS-0046, RS-0047, RS-0050, RS-0051, RS-0052, RS-0053, RS-0058, RS-0060, RS-0062, RS-0063, RS-0067, RS-0068, RS-0069, RS-0071, RS-0073, RS-0075, RS-0077, RS-0079, RS-0081, RS-0083, RS-0084, RS-0085, RS-0087, RS-0089, RS-0091, RS-0095, RS-0097, RS-0100, RS-0103, RS-0104, RS-0106, RS-0108, RS-0109, RS-0111, RS-0112, RS-0113, RS-0114, RS-0115, RS-0116, RS-0118, RS-0123, RS-0124, RS-0002, RS-0005, RS-0016, RS-0019, RS-0023, RS-0028, RS-0032, RS-0037, RS-0041, RS-0048, RS-0054, RS-0059, RS-0061, RS-0064, RS-0070, RS-0072, RS-0076, RS-0078, RS-0080, RS-0082, RS-0088, RS-0090, RS-0092, RS-0096, RS-0098, RS-0101, RS-0105, RS-0107, RS-0110, RS-0117, RS-0119, RS-0003, RS-0010, RS-0017, RS-0024, RS-0029, RS-0033, RS-0038, RS-0049, RS-0055, RS-0065, RS-0093, RS-0099, RS-0120, RS-0011, RS-0034, RS-0039, RS-0042, RS-0056, RS-0066, RS-0094, RS-0121, RS-0035, RS-0043, RS-0057, RS-0122, RS-0012, RS-0074, RS-0102 | +| `idiom` / family / actionable | 2 | RS-0045, RS-0086 | +| `own` / leaf / actionable | 107 | RS-0129, RS-0131, RS-0142, RS-0153, RS-0154, RS-0157, RS-0162, RS-0164, RS-0180, RS-0182, RS-0184, RS-0192, RS-0195, RS-0198, RS-0221, RS-0231, RS-0236, RS-0132, RS-0238, RS-0133, RS-0137, RS-0139, RS-0143, RS-0145, RS-0148, RS-0159, RS-0160, RS-0163, RS-0165, RS-0170, RS-0174, RS-0175, RS-0179, RS-0181, RS-0183, RS-0196, RS-0222, RS-0225, RS-0226, RS-0232, RS-0237, RS-0135, RS-0150, RS-0176, RS-0177, RS-0185, RS-0199, RS-0215, RS-0216, RS-0234, RS-0126, RS-0134, RS-0138, RS-0144, RS-0146, RS-0156, RS-0166, RS-0171, RS-0186, RS-0189, RS-0190, RS-0193, RS-0197, RS-0206, RS-0218, RS-0233, RS-0136, RS-0147, RS-0151, RS-0178, RS-0209, RS-0217, RS-0227, RS-0235, RS-0125, RS-0127, RS-0158, RS-0167, RS-0172, RS-0191, RS-0207, RS-0219, RS-0152, RS-0210, RS-0223, RS-0228, RS-0128, RS-0168, RS-0173, RS-0201, RS-0208, RS-0220, RS-0149, RS-0155, RS-0161, RS-0211, RS-0224, RS-0229, RS-0130, RS-0169, RS-0212, RS-0230, RS-0202, RS-0203, RS-0204, RS-0205, RS-0214 | +| `own` / family / actionable | 7 | RS-0187, RS-0140, RS-0188, RS-0200, RS-0213, RS-0141, RS-0964 | +| `own` / wide / actionable | 1 | RS-0194 | +| `type` / leaf / actionable | 59 | RS-0288, RS-0263, RS-0266, RS-0297, RS-0307, RS-0242, RS-0243, RS-0265, RS-0267, RS-0273, RS-0274, RS-0289, RS-0292, RS-0294, RS-0295, RS-0299, RS-0302, RS-0308, RS-0314, RS-0244, RS-0254, RS-0261, RS-0287, RS-0290, RS-0296, RS-0298, RS-0303, RS-0306, RS-0313, RS-0245, RS-0246, RS-0258, RS-0260, RS-0272, RS-0300, RS-0247, RS-0252, RS-0264, RS-0268, RS-0275, RS-0293, RS-0301, RS-0281, RS-0284, RS-0278, RS-0305, RS-0269, RS-0277, RS-0285, RS-0279, RS-0270, RS-0283, RS-0312, RS-0280, RS-0311, RS-0271, RS-0955, RS-0957, RS-0291 | +| `type` / leaf / needs-contract | 7 | RS-0240, RS-0241, RS-0256, RS-0315, RS-0257, RS-0304, RS-0282 | +| `type` / leaf / policy-confirmed | 1 | RS-0286 | +| `type` / family / actionable | 11 | RS-0262, RS-0276, RS-0251, RS-0253, RS-0255, RS-0309, RS-0310, RS-0962, RS-0954, RS-0956, RS-0259 | +| `type` / wide / actionable | 1 | RS-0239 | +| `type` / wide / needs-contract | 3 | RS-0248, RS-0249, RS-0250 | +| `api` / leaf / actionable | 107 | RS-0340, RS-0351, RS-0352, RS-0407, RS-0434, RS-0317, RS-0321, RS-0323, RS-0341, RS-0366, RS-0441, RS-0353, RS-0359, RS-0361, RS-0372, RS-0426, RS-0438, RS-0319, RS-0327, RS-0342, RS-0355, RS-0367, RS-0373, RS-0377, RS-0381, RS-0392, RS-0393, RS-0400, RS-0442, RS-0446, RS-0324, RS-0330, RS-0360, RS-0362, RS-0368, RS-0409, RS-0415, RS-0427, RS-0429, RS-0435, RS-0320, RS-0337, RS-0356, RS-0374, RS-0378, RS-0382, RS-0397, RS-0401, RS-0414, RS-0423, RS-0439, RS-0318, RS-0325, RS-0331, RS-0345, RS-0394, RS-0410, RS-0428, RS-0952, RS-0326, RS-0335, RS-0336, RS-0338, RS-0343, RS-0375, RS-0398, RS-0424, RS-0440, RS-0445, RS-0395, RS-0411, RS-0953, RS-0316, RS-0339, RS-0344, RS-0350, RS-0358, RS-0370, RS-0376, RS-0418, RS-0425, RS-0333, RS-0347, RS-0379, RS-0396, RS-0412, RS-0443, RS-0354, RS-0371, RS-0383, RS-0419, RS-0380, RS-0391, RS-0386, RS-0431, RS-0447, RS-0364, RS-0387, RS-0432, RS-0448, RS-0385, RS-0388, RS-0449, RS-0389, RS-0450, RS-0437, RS-0422 | +| `api` / leaf / policy-confirmed | 2 | RS-0399, RS-0322 | +| `api` / family / actionable | 20 | RS-0436, RS-0433, RS-0408, RS-0421, RS-0444, RS-0416, RS-0357, RS-0334, RS-0417, RS-0329, RS-0430, RS-0384, RS-0390, RS-0965, RS-0402, RS-0406, RS-0403, RS-0369, RS-0404, RS-0405 | +| `api` / family / needs-contract | 1 | RS-0363 | +| `api` / wide / actionable | 5 | RS-0348, RS-0365, RS-0349, RS-0346, RS-0420 | +| `api` / wide / needs-contract | 3 | RS-0332, RS-0328, RS-0413 | +| `err` / leaf / actionable | 79 | RS-0524, RS-0531, RS-0514, RS-0525, RS-0500, RS-0504, RS-0532, RS-0539, RS-0454, RS-0457, RS-0502, RS-0526, RS-0533, RS-0456, RS-0461, RS-0496, RS-0505, RS-0488, RS-0494, RS-0503, RS-0519, RS-0522, RS-0534, RS-0535, RS-0540, RS-0543, RS-0480, RS-0499, RS-0465, RS-0481, RS-0490, RS-0491, RS-0495, RS-0507, RS-0518, RS-0523, RS-0536, RS-0487, RS-0453, RS-0460, RS-0463, RS-0466, RS-0482, RS-0483, RS-0492, RS-0520, RS-0529, RS-0538, RS-0501, RS-0462, RS-0464, RS-0467, RS-0469, RS-0470, RS-0471, RS-0479, RS-0484, RS-0489, RS-0493, RS-0530, RS-0477, RS-0451, RS-0472, RS-0476, RS-0498, RS-0512, RS-0452, RS-0473, RS-0513, RS-0458, RS-0521, RS-0474, RS-0485, RS-0459, RS-0486, RS-0541, RS-0542, RS-0506, RS-0517 | +| `err` / leaf / needs-contract | 1 | RS-0478 | +| `err` / family / actionable | 11 | RS-0515, RS-0516, RS-0527, RS-0468, RS-0508, RS-0528, RS-0475, RS-0497, RS-0509, RS-0510, RS-0511 | +| `err` / wide / actionable | 1 | RS-0455 | +| `err` / wide / needs-contract | 2 | RS-0963, RS-0537 | +| `serde` / leaf / actionable | 23 | RS-0576, RS-0565, RS-0578, RS-0545, RS-0566, RS-0572, RS-0582, RS-0581, RS-0567, RS-0574, RS-0544, RS-0577, RS-0548, RS-0549, RS-0558, RS-0562, RS-0564, RS-0580, RS-0556, RS-0559, RS-0555, RS-0560, RS-0579 | +| `serde` / leaf / needs-contract | 4 | RS-0568, RS-0575, RS-0554, RS-0561 | +| `serde` / leaf / policy-confirmed | 1 | RS-0570 | +| `serde` / family / actionable | 6 | RS-0961, RS-0557, RS-0573, RS-0551, RS-0552, RS-0563 | +| `serde` / family / needs-contract | 1 | RS-0569 | +| `serde` / wide / actionable | 2 | RS-0553, RS-0550 | +| `serde` / wide / needs-contract | 3 | RS-0546, RS-0571, RS-0547 | +| `obs` / leaf / actionable | 30 | RS-0605, RS-0601, RS-0606, RS-0609, RS-0588, RS-0583, RS-0610, RS-0607, RS-0611, RS-0585, RS-0594, RS-0598, RS-0602, RS-0612, RS-0600, RS-0599, RS-0603, RS-0591, RS-0604, RS-0608, RS-0590, RS-0586, RS-0589, RS-0584, RS-0596, RS-0587, RS-0613, RS-0592, RS-0593, RS-0597 | +| `obs` / family / actionable | 1 | RS-0595 | +| `docs` / leaf / actionable | 139 | RS-0701, RS-0661, RS-0726, RS-0731, RS-0755, RS-0733, RS-0673, RS-0713, RS-0718, RS-0725, RS-0732, RS-0756, RS-0624, RS-0630, RS-0700, RS-0615, RS-0674, RS-0727, RS-0625, RS-0631, RS-0656, RS-0680, RS-0719, RS-0736, RS-0617, RS-0633, RS-0676, RS-0703, RS-0706, RS-0714, RS-0734, RS-0754, RS-0626, RS-0632, RS-0649, RS-0657, RS-0659, RS-0681, RS-0737, RS-0618, RS-0634, RS-0652, RS-0677, RS-0684, RS-0738, RS-0739, RS-0746, RS-0650, RS-0664, RS-0672, RS-0728, RS-0735, RS-0619, RS-0635, RS-0637, RS-0662, RS-0685, RS-0689, RS-0708, RS-0716, RS-0717, RS-0720, RS-0740, RS-0743, RS-0747, RS-0621, RS-0645, RS-0675, RS-0690, RS-0729, RS-0620, RS-0636, RS-0638, RS-0682, RS-0697, RS-0707, RS-0721, RS-0744, RS-0748, RS-0665, RS-0695, RS-0702, RS-0712, RS-0730, RS-0741, RS-0639, RS-0641, RS-0647, RS-0653, RS-0658, RS-0678, RS-0683, RS-0687, RS-0698, RS-0722, RS-0749, RS-0752, RS-0622, RS-0686, RS-0694, RS-0696, RS-0742, RS-0614, RS-0642, RS-0648, RS-0655, RS-0660, RS-0666, RS-0679, RS-0688, RS-0709, RS-0745, RS-0753, RS-0623, RS-0723, RS-0640, RS-0643, RS-0627, RS-0724, RS-0644, RS-0691, RS-0654, RS-0693, RS-0628, RS-0692, RS-0710, RS-0629, RS-0668, RS-0669, RS-0670, RS-0750, RS-0751, RS-0671, RS-0705, RS-0711, RS-0704, RS-0699, RS-0663, RS-0715 | +| `docs` / family / actionable | 3 | RS-0646, RS-0616, RS-0667 | +| `docs` / wide / actionable | 1 | RS-0651 | +| `perf` / leaf / actionable | 48 | RS-0771, RS-0793, RS-0799, RS-0808, RS-0759, RS-0770, RS-0779, RS-0760, RS-0774, RS-0780, RS-0800, RS-0801, RS-0758, RS-0763, RS-0790, RS-0764, RS-0776, RS-0796, RS-0785, RS-0791, RS-0766, RS-0781, RS-0782, RS-0794, RS-0797, RS-0802, RS-0778, RS-0805, RS-0757, RS-0765, RS-0775, RS-0783, RS-0798, RS-0803, RS-0806, RS-0772, RS-0784, RS-0795, RS-0807, RS-0777, RS-0767, RS-0787, RS-0761, RS-0768, RS-0788, RS-0769, RS-0789, RS-0773 | +| `perf` / family / actionable | 3 | RS-0786, RS-0792, RS-0804 | +| `perf` / wide / actionable | 1 | RS-0762 | +| `conc` / leaf / actionable | 19 | RS-0831, RS-0825, RS-0826, RS-0827, RS-0820, RS-0815, RS-0834, RS-0811, RS-0822, RS-0821, RS-0810, RS-0832, RS-0828, RS-0830, RS-0833, RS-0829, RS-0812, RS-0809, RS-0823 | +| `conc` / leaf / policy-confirmed | 7 | RS-0824, RS-0813, RS-0819, RS-0816, RS-0835, RS-0818, RS-0836 | +| `conc` / family / policy-confirmed | 2 | RS-0814, RS-0817 | +| `conc` / wide / policy-confirmed | 1 | RS-0960 | +| `async` / leaf / actionable | 12 | RS-0844, RS-0853, RS-0852, RS-0848, RS-0841, RS-0845, RS-0839, RS-0849, RS-0847, RS-0854, RS-0840, RS-0850 | +| `async` / leaf / policy-confirmed | 1 | RS-0851 | +| `async` / family / actionable | 3 | RS-0846, RS-0843, RS-0855 | +| `async` / wide / actionable | 2 | RS-0837, RS-0842 | +| `async` / wide / policy-confirmed | 1 | RS-0838 | +| `unsafe` / leaf / actionable | 4 | RS-0858, RS-0857, RS-0856, RS-0859 | +| `macro` / leaf / actionable | 4 | RS-0863, RS-0860, RS-0861, RS-0862 | +| `test` / leaf / actionable | 63 | RS-0922, RS-0914, RS-0921, RS-0891, RS-0928, RS-0880, RS-0910, RS-0923, RS-0873, RS-0915, RS-0881, RS-0924, RS-0889, RS-0925, RS-0905, RS-0912, RS-0864, RS-0871, RS-0890, RS-0883, RS-0895, RS-0899, RS-0865, RS-0866, RS-0867, RS-0893, RS-0908, RS-0868, RS-0872, RS-0884, RS-0896, RS-0900, RS-0906, RS-0875, RS-0879, RS-0882, RS-0898, RS-0869, RS-0874, RS-0897, RS-0876, RS-0903, RS-0913, RS-0892, RS-0894, RS-0916, RS-0870, RS-0919, RS-0877, RS-0917, RS-0927, RS-0902, RS-0885, RS-0918, RS-0909, RS-0901, RS-0904, RS-0911, RS-0886, RS-0887, RS-0888, RS-0926, RS-0920 | +| `test` / leaf / policy-confirmed | 1 | RS-0907 | +| `test` / family / actionable | 3 | RS-0958, RS-0959, RS-0878 | +| `supply` / leaf / actionable | 17 | RS-0933, RS-0934, RS-0935, RS-0936, RS-0937, RS-0938, RS-0939, RS-0940, RS-0941, RS-0942, RS-0943, RS-0944, RS-0948, RS-0929, RS-0931, RS-0930, RS-0932 | +| `supply` / wide / actionable | 6 | RS-0945, RS-0946, RS-0947, RS-0949, RS-0950, RS-0951 | + +## 7. Method and verification evidence + +- Reconciliation: raw lane finding rows 1022 = report rows 965 + recorded merges 57; the executive-summary totals equal the per-lens section totals; severity split 13 high / 295 medium / 657 low; verdicts 923 actionable / 25 needs-contract / 17 policy-confirmed. +- Severity normalization: every one of the 13 `high` rows was re-judged against the rubric and carries a stated reachability path or a directly reproduced condition (panic reachable from wire or caller input, a blocking call on an executor worker, a test that cannot fail, and RS-0916's assertion that cannot pass on the Display output - red at HEAD). No demotions were recorded. Duplicates were merged under the lens-specificity order (`unsafe` > `err`/`serde`/`async`/`conc`/`perf` > `type`/`api`/`own` > `idiom` > `docs`) and recorded as `merged:` on the kept row. +- Independent verification (`VERIFICATION.md`, separate clean-context agent; every number recomputed): checks 1-8 pass - lane completeness 110/110; crate coverage 94/94 with zero double ownership; schema conformance 1022 rows, 0 violations; coverage matrix 94x16 complete (449 `N/A`, 504 `clean`, 461 numeric, 90 `X1`); anchor existence - 568 anchors checked (all 13 `high` rows plus a deterministic every-5th sample of the 1008 medium/low rows), 0 failures; count reconciliation as above; writes confined to this audit directory; README-faithfulness spot-check of five rows field-for-field. Check 6 initially failed on this report's own defect - four crate-lane `supply` rows (`RS-0929`..`RS-0932`) were missing from section 2 - which was fixed and re-verified; check 9 is informational (the artifact list above matches its recomputation, with denominators within 4). +- Data-quality note: lane prose carries numeral-spelling and parentheses artifacts from the lane-writing path (e.g. `two finding(s)`, a dropped `)` in an inline snippet). The structured fields (lens, severity, blast, effort, verdict, anchors, ids) were parsed and verified independently; a mechanical repair pass normalized semicolon spacing, merged-word splits, zero-width characters, stray `{{` terminators, and one file's space-after-paren form, without touching any path, line number, or count. Files where more than ~25% of finding lines carry parenthesis artifacts (drop/duplication, no fact loss): `d2b-provider-guest-qemu-media.md` (40/49), `d2b-resource-compiler.md` (33/49), `d2b-provider-shell-terminal.md` (17/37), `d2b-provider-guest.md` (20/45), `d2bd-p5.md` (12/34), `d2b-provider-volume.md` (14/41), `d2b-provider-credential-managed-identity.md` (11/36), `d2b-contracts.md` (10/39), `d2b-broker-p6.md` (13/52); the verifier's recomputation also places `xtask-p5.md` (9/35) just over the threshold - see VERIFICATION.md check 9. Renderer note: finding rows in sections 2 and 4 carry lane text verbatim, including `|` inside inline code (only the section-1 summary table escapes it), so closure pipes in fix snippets are shown exactly as the lane recorded them. + +## 8. Drift note + +- Working tree vs baseline `6ebdd4cec`: no source, policy, or gate file changed during the audit; the only writes are under `docs/audits/2026-09-24-rust-skills-audit/` and `.scratch/`. A pre-existing untracked plan file was left untouched. See VERIFICATION.md check 7. + diff --git a/docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md b/docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md new file mode 100644 index 000000000..8674c1f24 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md @@ -0,0 +1,961 @@ +# U1 - Rust skills audit constraint packet (priming feed) + +Baseline: branch `v3` @ `6ebdd4cec` (HEAD at audit start; working tree clean except +one pre-existing untracked plan file, not ours) - Date: 2026-09-24 - Lens revision: +`third_party/agent-skills/rewrite-rs/v0.1.0-alpha.1/skills/` (vendored at the same +HEAD) - Plan: `local://rust-skills-audit-plan.md` (durable copy; this packet +implements its Step 1). + +Deliverable: `docs/audits/2026-09-24-rust-skills-audit/` - `README.md` +(consolidated report), `U1-constraints.md` (this packet), `lane/.md` (one file +per lane), `VERIFICATION.md` (Step 5). Nothing else is written; the audit is +READ-ONLY on source, policy, and gates. No `cargo build`/`test`/`clippy`, +formatter, or project-wide command is run by any lane. + +Every lane: read this file fully, then the assigned lens cards (section c), then +run the lane protocol (section b) over the lane's scope from the published +part-partition map (section f). Write only your lane file. + +## (a) Lane map + +Lane ids, crates, planning-time LOC (basis: `src/**` excluding `src/generated/**` +plus `tests/**`, `wc -l`), and part counts: + +|lane id|crate|LOC|parts| +|---|---|---:|---:| +|`d2bd-p1`..`-p8`|`d2bd`|93,768|8| +|`d2b-broker-p1`..`-p7`|`d2b-broker`|79,531|7| +|`xtask-p1`..`-p5`|`xtask`|49,329|5| +|`d2bd-runtime-p1`..`-p4`|`d2bd-runtime`|43,123|4| +|`d2b-p1`..`-p3`|`d2b`|26,481|3| +|`d2b-bus-p1`..`-p2`|`d2b-bus`|20,894|2| +|`d2b-contracts-resource-p1`..`-p2`|`d2b-contracts-resource`|19,571|2| +|`d2b-core-p1`..`-p2`|`d2b-core`|17,644|2| +|`d2b-provider-toolkit-p1`..`-p2`|`d2b-provider-toolkit`|17,414|2| +|`d2b-provider-display-wayland-p1`..`-p2`|`d2b-provider-display-wayland`|16,248|2| +|`d2b-resource-runtime-p1`..`-p2`|`d2b-resource-runtime`|15,515|2| +|`d2b-contracts-provider-p1`..`-p2`|`d2b-contracts-provider`|14,706|2| +|`d2b-session-p1`..`-p2`|`d2b-session`|14,538|2| +|`d2b-resource-api-p1`..`-p2`|`d2b-resource-api`|13,931|2| +|`d2b-core-controller-p1`..`-p2`|`d2b-core-controller`|13,919|2| +|`d2b-provider-clipboard-wayland-p1`..`-p2`|`d2b-provider-clipboard-wayland`|13,710|2| +|`d2b-contracts-zone-session-p1`..`-p2`|`d2b-contracts-zone-session`|12,839|2| +|`d2b-host`|`d2b-host`|11,767|1| +|`d2b-provider-network-local`|`d2b-provider-network-local`|11,256|1| +|`d2b-contracts`|`d2b-contracts`|10,743|1| +|`d2b-provider-process`|`d2b-provider-process`|10,732|1| +|`d2b-provider-guest-cloud-hypervisor`|`d2b-provider-guest-cloud-hypervisor`|10,523|1| +|`d2b-provider-volume-local`|`d2b-provider-volume-local`|10,405|1| +|`d2b-zone-routing`|`d2b-zone-routing`|10,370|1| +|`d2b-resource-compiler`|`d2b-resource-compiler`|7,461|1| +|`d2b-provider-device-usbip`|`d2b-provider-device-usbip`|7,015|1| +|`d2b-provider-credential-secret-service`|`d2b-provider-credential-secret-service`|6,699|1| +|`d2b-session-unix`|`d2b-session-unix`|6,663|1| +|`d2b-provider-guest`|`d2b-provider-guest`|6,436|1| +|`d2b-provider-supervisor`|`d2b-provider-supervisor`|6,162|1| +|`d2b-provider-transport-azure-relay`|`d2b-provider-transport-azure-relay`|5,952|1| +|`d2b-provider-notification-desktop`|`d2b-provider-notification-desktop`|5,712|1| +|`d2b-provider-credential-managed-identity`|`d2b-provider-credential-managed-identity`|5,453|1| +|`d2b-provider-credential-entra`|`d2b-provider-credential-entra`|5,246|1| +|`d2b-audit`|`d2b-audit`|5,221|1| +|`d2b-contracts-broker`|`d2b-contracts-broker`|5,215|1| +|`d2b-contracts-control`|`d2b-contracts-control`|5,019|1| +|`d2b-resource-client`|`d2b-resource-client`|4,839|1| +|`d2b-provider-device-security-key`|`d2b-provider-device-security-key`|4,320|1| +|`d2b-process-conformance`|`d2b-process-conformance`|4,195|1| +|`d2b-provider-shell-terminal`|`d2b-provider-shell-terminal`|4,181|1| +|`d2b-provider-transport-vsock`|`d2b-provider-transport-vsock`|4,146|1| +|`d2b-provider-activation-nixos`|`d2b-provider-activation-nixos`|4,014|1| +|`d2b-provider-wayland-policy`|`d2b-provider-wayland-policy`|3,982|1| +|`d2b-provider-process-systemd`|`d2b-provider-process-systemd`|3,816|1| +|`d2b-provider-zone-link`|`d2b-provider-zone-link`|3,814|1| +|`d2b-provider-observability-otel`|`d2b-provider-observability-otel`|3,809|1| +|`d2b-provider-device-gpu`|`d2b-provider-device-gpu`|3,758|1| +|`d2b-provider-guest-qemu-media`|`d2b-provider-guest-qemu-media`|3,694|1| +|`d2b-provider-device-tpm`|`d2b-provider-device-tpm`|3,338|1| +|`d2b-provider-credential`|`d2b-provider-credential`|3,337|1| +|`d2b-provider`|`d2b-provider`|3,252|1| +|`d2b-unsafe-local-helper`|`d2b-unsafe-local-helper`|3,240|1| +|`d2b-provider-volume-binding`|`d2b-provider-volume-binding`|2,914|1| +|`d2b-provider-guest-azure-virtual-machine`|`d2b-provider-guest-azure-virtual-machine`|2,839|1| +|`d2b-provider-audio-pipewire`|`d2b-provider-audio-pipewire`|2,709|1| +|`d2b-provider-endpoint`|`d2b-provider-endpoint`|2,548|1| +|`d2b-provider-guest-azure-container-apps`|`d2b-provider-guest-azure-container-apps`|2,420|1| +|`d2b-provider-provider`|`d2b-provider-provider`|2,289|1| +|`d2b-provider-volume`|`d2b-provider-volume`|2,150|1| +|`d2b-provider-host`|`d2b-provider-host`|2,108|1| +|`d2b-provider-user`|`d2b-provider-user`|2,099|1| +|`d2b-provider-volume-virtiofs`|`d2b-provider-volume-virtiofs`|2,025|1| +|`d2b-telemetry`|`d2b-telemetry`|1,983|1| +|`d2b-provider-config-nixos`|`d2b-provider-config-nixos`|1,816|1| +|`d2b-provider-system-core`|`d2b-provider-system-core`|1,810|1| +|`d2b-broker-composition`|`d2b-broker-composition`|1,634|1| +|`tail-1`|`d2b-broker-fixture-handlers`, `d2b-broker-fixture-syscall-surface`, `d2b-controller-toolkit`, `d2b-host-activation-helper`, `d2b-provider-audio-binding`|1,121|1| +|`tail-2`|`d2b-provider-audio-service`, `d2b-provider-command`, `d2b-provider-device`, `d2b-provider-emergency-policy`, `d2b-provider-operation`|2,571|1| +|`tail-3`|`d2b-provider-process-minijail`, `d2b-provider-quota`, `d2b-provider-resource-export`, `d2b-provider-resource-import`, `d2b-provider-role`|1,759|1| +|`tail-4`|`d2b-provider-role-binding`, `d2b-provider-seccomp-profile`, `d2b-provider-shell-pool`, `d2b-provider-shell-session`, `d2b-provider-telemetry-binding`|2,549|1| +|`tail-5`|`d2b-provider-telemetry-service`, `d2b-provider-test-controller`, `d2b-provider-transport-unix`, `d2b-provider-wayland-session`, `d2b-provider-zone`|3,144|1| +|`tail-6`|`d2b-resource-types`, `d2b-sk-frontend`|2,173|1| + +Cross-cutting lanes (not in the table): `lane/X1-supply-chain.md`, +`lane/X2-generated-boundary.md`, `lane/X3-cross-crate-duplication.md`. + +Part-partition rule (mechanical, already applied in section f; no +renegotiation): for a crate with k>1 parts, its top-level units under `src/` +(files `src/*.rs`, directories `src/*/`, excluding `generated`) were sorted by +LOC descending and greedily packed (least-loaded-bin) into k groups each +`<= ceil(LOC/k) x 1.2`, keeping units whole; units exceeding the cap were +descended (directories) or split by item ranges (files, boundaries recorded in +section f). Section f publishes the concrete part -> module map; each lane stays +inside its assigned files/ranges. + +## (b) Global rules + +### Lane protocol (run in this order) + +1. Read `U1-constraints.md` fully, then the assigned lens cards. +2. Read each assigned lens's SKILL.md (`skill://`; if that URI does + not resolve, the vendored path in the lens table below). A SKILL.md may point + to sibling reference files in the same directory (`ERROR-TYPES.md`, + `NAMING.md`, `BOILERPLATE.md`, `FLOWS.md`, `CLONE-DECISIONS.md`, + `SHARED-STATE.md`, `NUMERICS.md`, `TYPESTATE.md`, `SURFACE.md`, + `DEPENDENCY-INJECTION.md`, `SEMVER.md`, `ALLOCATION.md`, `CANCELLATION.md`, + `SAFETY-REVIEW.md`, `TEST-DESIGN.md`, `DIFFERENTIAL-TESTING.md`, `DENY.md`) - + read on demand when the SKILL.md defers to them. +3. Enumerate the assigned files (all of `src/**` except `src/generated/**`; + plus `tests/**` for the `test` lens; plus `build.rs` if present). If the lane + is a part (`-p`), stay inside the assigned module partition: for file-split + parts restrict seed runs with `sed -n ',p' ` (or + `awk 'NR>=A && NR<=B'`) and add `` to reported line numbers so anchors + stay absolute. +4. Per lens, in the card order: run the seeds, read every hit with enough + context to judge (whole file for files <400 lines; otherwise the hit + neighborhood, +/-40 lines, plus the file's item list). For `api`/`type`, + additionally read the crate's public surface: `lib.rs`/`mod.rs` re-exports + and all `pub` items. +5. Emit findings into the lane file as you go. Reading budget rule: never dump a + whole large file into the lane; cite `path:line`. +6. Sampling rule: if one lens's seeds exceed 200 hits in the lane, read 50 hits + sampled deterministically (every ceil(n/50)-th hit) and record + `sampled: 50 of hits` in the lens section; never claim exhaustiveness for + that lens. +7. Do not run `cargo build`/`test`/`clippy`, formatters, or any project-wide + command. Read-only audit. Write only your lane file. +8. Caller census rule (mandatory) for any finding that claims something is + unused, redundant, unreachable, or reducible in visibility: search the symbol + across `packages/`, `nixos-modules/`, `tests/`, `docs/reference/`, `labs/`, + and `BUILD.bazel`/`*.bzl` files; record + `census: over = hits`. + +### Lane file format (verbatim contract) + +``` +# - [- part /] +Baseline: | LOC audited: (excl. src/generated/**) | modules: +Lenses: | Partitions: + +## +- # sev= blast= effort= verdict= - - fix: - [path:line, path:line] + evidence: +- clean: + +## Coverage +: = | clean | N/A: +``` + +Schema notes (grammar the verifier keys on): + +- A finding is exactly two lines: the `- # sev=... - ... - fix: ... + - [path:line, ...]` line, then one ` evidence: ...` line. +- Local finding ids: `#`, k increments from 1 per lane. +- Coverage lines use one of: `- : finding(s)` | + `- : clean (seeds ran: //...)` | + `- : N/A (seeds: //... all zero; )`. +- Tail lanes carry a `## ` section per crate, each with the standard lens + sections and its own `### Coverage` block; the lane header lists all crates. +- `LOC audited` is measured by the lane (`wc -l` over its assigned files, + excluding `src/generated/**`). +- Consolidation assigns global `RS-####` ids; local ids stay lane-local. + +### Severity rubric (fixed for all lanes; judge against these definitions) + +- `high` - correctness, soundness, security, or measurable operational cost: + unsound/incorrect code; a panic reachable from untrusted or caller input; a + secret/PII path into logs/errors/metrics; a blocking call on an executor + worker; unbounded allocation/scan in a hot path; a failure silently swallowed + where the caller must know; a test that cannot fail. +- `medium` - API/model/maintainability with real cost: public surface exposing + internals or leaking types; illegal states representable that the skill names + an alternative for; an error taxonomy forcing callers to string-match; missing + validation on wire input where a sibling type has it; hand-rolled duplicate of + an existing in-tree helper (name the canonical home); missing doc contract on + a non-obvious public item; contract behavior with no test. +- `low` - expression, consistency, naming, polish: iterator-vs-index loop; + explainable-but-avoidable clone; naming drift; doc first-sentence shape. + +### Verdict values + +- `actionable` (implementable now), `policy-confirmed` (conflicts with a + recorded deliberate decision - cite the policy file:line; requires a + policy/ADR change first), `needs-contract` (touches wire formats, error codes, + manifest schema, golden fixtures, or generated shapes). + +### Blast radius and effort + +- Blast radius: `leaf` (one crate), `family` (crates in one family - provider + family, contracts family, etc.), `wide` (wire/contracts/daemon/broker/ + cross-cutting). +- Effort: `S` (one file or mechanical), `M` (a handful of files in one crate), + `L` (multi-crate or design change). + +### Evidence rules + +- Every finding's `evidence:` line names the seed regex and its count, the + census result, or `static (unmeasured)` for perf; a finding without evidence + is a schema violation. +- An `api` claim that a change breaks callers, and an ownership claim that a + clone is required, both cite the call site rather than assert it. +- Findings that propose an improvement already named by a gate/policy in + section (d) are `policy-confirmed` with the policy file:line cited. +- Perf findings are static until a benchmark exists; never claim a measured + win. + +### Read-only rules + +- No source edits, no gate runs, no formatter, no `git` state changes. The only + write is the lane's own `lane/.md` file. +- Do not fix anything found; correctness or security defects are kept as + `sev=high verdict=actionable` with route `review-pass` noted in the row text. +- The pre-existing untracked file `docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md` + is not ours; leave it untouched. + +## (c) Lens cards + +Lens table (all 16 audit lenses; paths relative to +`third_party/agent-skills/rewrite-rs/v0.1.0-alpha.1/`): + +|lens|skill name|vendored SKILL.md| +|---|---|---| +|`idiom`|idiomatic-rust|`skills/rust/idiomatic-rust/SKILL.md`| +|`own`|ownership-not-clone|`skills/rust/ownership-not-clone/SKILL.md`| +|`type`|type-driven-design|`skills/rust/type-driven-design/SKILL.md`| +|`api`|rust-api-design|`skills/rust/rust-api-design/SKILL.md`| +|`err`|rust-errors|`skills/rust/rust-errors/SKILL.md`| +|`serde`|rust-serde|`skills/misc/rust-serde/SKILL.md`| +|`obs`|rust-observability|`skills/rust/rust-observability/SKILL.md`| +|`docs`|rust-docs|`skills/rust/rust-docs/SKILL.md`| +|`perf`|rust-performance|`skills/rust/rust-performance/SKILL.md`| +|`conc`|rust-concurrency|`skills/rust/rust-concurrency/SKILL.md`| +|`async`|async-rust|`skills/rust/async-rust/SKILL.md`| +|`unsafe`|unsafe-rust|`skills/rust/unsafe-rust/SKILL.md`| +|`ffi`|rust-ffi|`skills/misc/rust-ffi/SKILL.md`| +|`macro`|rust-macros|`skills/misc/rust-macros/SKILL.md`| +|`test`|rust-testing|`skills/workflow/rust-testing/SKILL.md`| +|`supply`|rust-supply-chain|`skills/misc/rust-supply-chain/SKILL.md`| + +Seed construction note: every card's seed set begins with the patterns named in +that skill's own `## Verification` section. Where the skill names only cargo +subcommands (`cargo clippy`, `cargo doc`, `cargo miri`, `cargo bench`, ...), the +card carries a `verify:` line with those commands and the seed regexes are +proxies for the class those commands report. Every seed below is a single regex +that ran over this repository at `6ebdd4cec`; the per-crate hit counts are in +section (e). + +### idiom (idiomatic-rust) + +Judges: expression shape - iterator pipelines over index loops, `From`/`TryFrom` +over ad-hoc converters, derives over hand-written impls, newtypes over bare +primitives, naming discipline (`as_`/`to_`/`into_`, no `get_`, acronyms, free +functions). This is the lens for "reads like Rust" findings; defer ownership to +`own`, invariants to `type`. +Seeds (run each; record hit count per crate): + 1. `for \w+ in 0\.\.` # index loop where an iterator pipeline is expected + 2. `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` # hand-written impl a derive may replace + 3. `let mut \w+ = (String|Vec)::new\(\)` # statement-style accumulation +verify: `cargo clippy --all-targets`, `cargo fmt --check`, `cargo test` (run by +remediation, not by lanes). +Applicable when: the crate declares `fn` bodies. N/A only when all three seeds +are 0 and the crate declares no `fn`. +Repo false positives: hand-written `Debug` impls that redact secrets (deliberate; +`redacted_debug!` exists and a derive would leak); hand-written `PartialEq` on +wire types with deliberate field exclusions; `Default` impls that preserve an +invariant (forbidden by a field-wise derive); `to_string()` on a type whose +`Display` is the wire rendering; `#[derive]` already present is not a finding. +Gate interaction: `make check` runs per-crate clippy inside the Bazel suite with +`-D warnings` on rustc; `clippy::pedantic` is not enabled, so its class is +proposals only. Naming/derive findings are not gate-enforced. + +### own (ownership-not-clone) + +Judges: whether every clone/`to_owned`/`Rc`/`RefCell`/`Arc` is +explainable in one sentence; borrows beat copies; argument position takes the +cheapest thing (`&str` over `&String`, `&[T]` over `&Vec`); `mem::take` +instead of clone; avoid statics. +Seeds: + 1. `\.clone\(\)` # count per file; inspect each + 2. `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` + 3. `Rc<|RefCell<|Arc>` in the daemon's shared +state where multiple owners genuinely exist (`d2bd/src/composition.rs` +`ServerState`); `.to_string()` at a wire-rendering boundary; test fixtures. +Gate interaction: none denies clones. `clippy::redundant_clone` is not enabled; +its findings are candidates only. + +### type (type-driven-design) + +Judges: illegal states representable - boolean flag soup, `Option` pairs where +exactly one is `Some`, stringly-typed state, validate-at-every-callsite instead +of parse-once types, typestate for protocol order. Stopping rule: encode an +invariant only where violating it is a real bug class. +Seeds: + 1. `fn validate_\w+|fn check_\w+` # runtime validation a parsed type could replace + 2. `is_\w+: bool|\w+_flag: bool` # boolean flags that may be state + 3. `(mode|kind|state): String` # stringly-typed state +verify: `cargo clippy --all-targets`, `cargo test`; after a change, grep that +the now-impossible branch is deleted. +Applicable when: the crate declares a `struct` or `enum`. N/A only when all +seeds are 0 and it declares neither. +Repo false positives: wire types that must mirror a schema (generated shapes, +`deny_unknown_fields` admission gates, docs/reference-pinned fields); the +`debug_logging`-class pinned wire fields; one-variant or two-variant enums that +are declared extension points for a declared provider; `StateDirIntent`-class +tokens kept because the daemon references them; schema-mirroring booleans in +generated code (lane X2 owns those). +Gate interaction: `docs/reference/manifest-schema.md` + `schemars`-generated +schemas + `docs/reference/error-codes.md` pin wire shapes; restructuring a wire +type is `needs-contract`. Generated shapes are X2's. + +### api (rust-api-design) + +Judges: what callers can see and rely on - deliberate exports, one path per +item, no `Arc`/`Rc`/`Box`/`RefCell` or dependency types in public signatures, +trait design (small required surface, sealed where growth is planned), semver +breakage classes. +Seeds: + 1. `\bpub (fn|struct|enum|trait|type|const|mod) ` # exported surface size + 2. `pub .*\b(Arc|Rc|Box|RefCell)<` # internals in a public signature + 3. `^\s*pub use ` # re-export arms +verify: `cargo doc --no-deps`, `cargo clippy --all-targets`, `cargo test`; +`cargo semver-checks check-release` only if already installed (never install). +Applicable when: the crate has a `lib` target with `pub` items. N/A only when +all seeds are 0. +Repo false positives: contract crates intentionally export wide wire +vocabularies (that IS the contract; narrowing is `needs-contract`); `pub use` +re-export arms in `lib.rs` are the house single-surface pattern; `test-support` +feature-gated exports consumed by other crates' tests; `Arc<...>` in a public +signature where the value genuinely shares ownership (evaluate, cite the call +sites); generated `pub` surface (X2's). +Gate interaction: no semver gate in the repo. Exported types of contract crates +are pinned by docs/reference and goldens: a change there is `needs-contract`. + +### err (rust-errors) + +Judges: panic policy vs `Result` boundary, error taxonomy split by caller +action, context survival, wire error codes. +Seeds (seed 1 is the skill's own audit): + 1. `\.unwrap\(\)|\.expect\(` # panic site outside tests + 2. `let _ = |\.ok\(\);` # swallowed `Result` + 3. `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` + 4. `enum \w*Error` # error taxonomy shape +verify: `cargo clippy --all-targets`, `cargo test`; the skill's targeted audit +`rg '\.unwrap\(\)|\.expect\(' --glob '!**/tests/**' --glob '!**/benches/**' src/`. +Applicable when: always (a crate with fns can be read for panic policy); N/A +only when all seeds are 0 and no `fn` exists. +Repo false positives: `unwrap` in `#[cfg(test)]` and in `#[tokio::main]`/`main` +startup preconditions; `expect("fixed ... serializes")` on literally-built +values; `format!`-built error strings that are in fact wire error codes pinned by +`docs/reference/error-codes.md`; generated error tables; `let _ =` on a +deliberately ignored best-effort cleanup (judge per site). +Gate interaction: no lint denies `unwrap`/`expect` today (`unwrap_used`/ +`expect_used` are restriction lints, not enabled - propose, never switch on). +`d2b_core::error::Error::all_kinds()` is the wire error catalog; a finding that +restructures a wire-visible error enum is `needs-contract`. +`docs/reference/error-codes.md` is generated from it. + +### serde (rust-serde) + +Judges: serde as the boundary where untrusted input becomes a domain type - +`try_from` validation, `rename_all` conventions, the three optionality meanings, +the four enum representations, `deny_unknown_fields` as a per-type decision, +`flatten` costs, hand-written `Deserialize` as admission gate. +Seeds: + 1. `derive\([^)]*(De)?[Ss]erialize` + 2. `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` + 3. `impl .*Deserialize.*for` # hand-written deserializers + 4. `serde_json::from_|serde_json::to_` +verify: `cargo test` (round-trip + real-payload tests), `cargo clippy`. +Applicable when: seeds 1-4 hit. N/A when all are 0 (crate crosses no wire). +Repo false positives: hand-written `Deserialize` impls that are live admission +gates (qemu guest/provider spec shapes - recorded refusal; do not re-flag); +generated `Wire` deserialize blocks (76 across contract crates - X2's; cite, +never flag); `deny_unknown_fields` deliberately absent on service-consumed +messages; `try_from` validation already applied. +Gate interaction: `docs/reference/manifest-schema.md` and `tests/golden/**` pin +wire shapes - changes there are `needs-contract`. The contract-crate +macro/boilerplate consolidation row (#C4) is recorded not-applied; re-proposing +it OK but must cite the record row and current sites. + +### obs (rust-observability) + +Judges: structured events with named fields; `tracing` over `println`; spans for +context; error chains logged once at the boundary that handles them; never a +secret in a field; lazy field construction. +Seeds (seed 1 and 2 are the skill's own greps): + 1. `\bprintln!\(|\beprintln!\(` # expect zero in a library + 2. `(info|debug|warn|error|trace)!\("` # interpolated message with no fields = smell + 3. `\.instrument\(|#\[instrument` # span usage (context for judging) + 4. `tracing::|log::` # presence check +verify: `cargo clippy --all-targets`, `cargo test`. +Applicable when: always; N/A only when all seeds are 0 and the crate has no +`tracing`/`log` dependency. +Repo false positives: CLI user-facing stdout in `d2b/src/**` and `bin/**` +(product output, not telemetry - the skill itself carves this out); `xtask` +generators whose stdout IS the artifact; test fixtures printing; message-only +events where the fields live in the enclosing span; `d2b-telemetry`/otel +providers whose payload is the metric, not a log. +Gate interaction: the ADR 0010/0028 identifier-in-log redaction scan +(`security-scan` job in `.github/workflows/pr-l1-static-fast.yml`, implemented +by `packages/xtask/src/diagnostic_redaction.rs`) already gates +identifier-in-log; sites it covers are `policy-confirmed` - cite the gate file. + +### docs (rust-docs) + +Judges: doc comment as API contract - one-line first sentence, module docs, +canonical sections (`# Examples`, `# Errors`, `# Panics`, `# Safety`), doctests +that run (`ignore` = unchecked), intra-doc links, magic values documented with +the why. +Seeds: + 1. `^\s*pub (fn|struct|enum|trait|const|type)` # public items needing docs + 2. `/// # (Examples|Errors|Panics|Safety)` # canonical sections present + 3. `-> Result<` # items that should carry `# Errors` +verify: `cargo doc --no-deps`, `cargo test --doc`, `cargo clippy --all-targets`. +Applicable when: seed 1 hits (public items exist). N/A when all seeds are 0. +Repo false positives: internal crates whose contract is the dossier/README and +whose items are crate-internal (`pub(crate)` correct); bin-only crates (the +skill: never add `missing_docs` to a binary crate); doc comments that narrate +policy deliberately (kept); generated docs. +Gate interaction: `missing_docs` is not enabled anywhere; `cargo doc` is not in +`make check`. A finding proposing the lint is a proposal, never imposed. + +### perf (rust-performance) + +Judges: allocation out of hot paths (`format!` in loops, `with_capacity`, clear +and reuse, `Cow`), collection choice for the access pattern, hashing with +attacker-controlled keys, iterator bounds-check elision, codegen flags as the +last five percent. +Seeds: + 1. `format!\(` # allocation sites + 2. `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` # grow-by-push candidates + 3. `\.to_string\(\)` # copies at boundaries +verify: `cargo bench` against a recorded baseline, `cargo clippy`, +`cargo test --release`. +Applicable when: always; N/A only when all seeds are 0. +Repo false positives: `format!` in error paths, audit rendering, and one-shot +diagnostics (cold); `Vec::new()` where the empty case is common; `to_string()` +inside `Display` impls; deliberate `String` building where the artifact is text +(`xtask` generators, wire rendering); the repo has a perf budget gate +(`make perf`) - a finding that claims a budget regression must name the budget. +Gate interaction: perf findings are `static (unmeasured)` unless a benchmark +exists; never claim a measured win. `#[inline]`/codegen-flag advice is taste and +low severity at most. + +### conc (rust-concurrency) + +Judges: the concurrency model picked from the workload shape (data parallelism, +scoped threads, channels, shared state last), weakest correct atomic ordering, +`Send`/`Sync` claims written down, `thread_local!` over `static mut`. +Seeds: + 1. `std::thread::|thread::spawn|thread::scope` + 2. `\bMutex<|\bRwLock<` + 3. `Atomic\w+|Ordering::` + 4. `thread_local!|unsafe impl (Send|Sync) for` +verify: `cargo test` (incl. ignored stress tests), `cargo clippy`, +`cargo miri test` where unsafe `Send`/`Sync` or atomics are involved. +Applicable when: seeds 1-4 hit. N/A when all are 0. +Repo false positives: `std::sync::Mutex` on genuinely synchronous paths +(`d2b-broker/src/ops/**`, the dedicated bounded worker per plan R4); atomics as +counters; `tokio::sync::*` re-exports; test-only synchronization. +Gate interaction: the async-gate scanner (`make check-async-gate`) and +`disallowed_methods` police the blocking subset; `await_holding_lock`/ +`await_holding_refcell_ref` are denied. `// async-gate-allow: ` markers +(283 sites, inventory `packages/xtask/data/async-gate-inventory.json`) are +deliberate exceptions - cite, never re-flag. + +### async (async-rust) + +Judges: runtime choice at the top; blocking work inside an async context; +guards held across `.await`; cancellation safety (irreversible step in one +non-cancellable piece); shared state across tasks; `Send` bounds; future size. +Seeds: + 1. `async fn|async move|\.await` + 2. `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` + 3. `tokio::sync::(Mutex|RwLock|Notify)` + 4. `#\[tokio::(main|test)\]|Runtime::block_on` +verify: `cargo clippy --all-targets`, `cargo test`; async bugs are +timing-dependent - multi-thread test flavor where the path changed. +Applicable when: seeds 1-4 hit. N/A when all are 0. +Repo false positives: `block_on` at process entry points and plain `#[test]` +harnesses (sanctioned with inline allows); `sync_channel` recv on the dedicated +worker thread (plan R4); `async-gate-allow` markers (deliberate; cite); +`spawn_blocking` sites already in `packages/xtask/data/blocking-census-baseline.json` +(tracked work - merely being present is not a finding; a conversion of one is +already-planned work, and only a site above the baseline is new). +Gate interaction: `make check-async-gate` (source scanner), +`make check-census` (blocking-API census vs committed baseline), +`await_holding_lock`/`await_holding_refcell_ref` deny, +`clippy::disallowed_methods` deny at the workspace lint table (see (d) 1 for the +level discrepancy note). Findings that propose one of the `clippy.toml`-named +replacements are `policy-confirmed` unless the site is on a recorded exception +list. + +### unsafe (unsafe-rust) + +Judges: justification (FFI / named perf win / language-inexpressible primitive), +a `// SAFETY:` comment stating the invariant on every block, safe wrappers that +cannot be misused, `# Safety` on every `pub unsafe fn`, the UB hazard list +(aliasing, uninit, invalid values, transmute, unwinding across FFI, data races), +Miri as the verification. +Seeds: + 1. `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` + 2. `// SAFETY:` + 3. `transmute|from_raw|MaybeUninit|mem::zeroed` + 4. `unsafe_code` # lint setting presence (forbid/deny/allow) +verify: `cargo miri test` (say so explicitly if unavailable; never install +nightly), `cargo clippy --all-targets`, `cargo test`. +Applicable when: seeds 1-3 hit, or an `unsafe_code = "allow"` manifest exists. +N/A when seeds 1-3 are all 0 (seed 4 alone - a `forbid(unsafe_code)` attribute - +does not make the lens applicable). +Repo false positives: `d2b-broker/src/sys.rs` per-site `#[allow(unsafe_code)]` +call wrappers are the sanctioned syscall boundary; `d2b-broker-fixture-syscall-surface` +is `unsafe_code = "allow"` deliberately (fixture); `#[unsafe(link_section = ...)]` +is edition-2024 syntax for an attribute (not an unsafe block); `unsafe` in a +doc comment is prose. +Gate interaction: `unsafe_code = "forbid"` where workspace lints are inherited; +local tables per (d) 8. The enumerated exception set in (d) 8 is exhaustive as of +`6ebdd4cec`; a new site not in it is itself a finding. + +### ffi (rust-ffi) + +Judges: thin translation layer with logic in core crates; nothing panics across +the boundary (`catch_unwind` at entry); every pointer states ownership; +`repr(C)`/`repr(transparent)`; handle over module-level state; library-prefixed +symbols; `CStr`/`CString` and pointer+length for strings/slices; edition-2024 +forms (`unsafe extern`, `#[unsafe(no_mangle)]`). +Seeds: + 1. `extern "C"|no_mangle|unsafe\(link_section` + 2. `catch_unwind` + 3. `repr\(C\)|repr\(transparent\)` + 4. `CStr|CString|c_char` +verify: `cargo test` (core crate), `cargo miri test` for the Rust side, +`cargo clippy`; a foreign-language harness is the boundary check. +Applicable when: seeds 1-4 hit. N/A when all are 0 (most crates). +Repo false positives: `extern "C"`-shaped declarations in `libc`-binding call +sites that never cross a foreign caller; `repr(transparent)` newtypes over +handles (intended); `catch_unwind` used for process supervision without FFI +(judge: is it a boundary?); `c_char` in `nix`/`libc` syscall wrappers. +Gate interaction: none specific. The FFI-carrier set is in (d) 8. + +### macro (rust-macros) + +Judges: macro as a last resort (the three genuine answers: variadic interface, +impl-per-type generation, non-Rust DSL); `macro_rules!` before proc-macro; +hygiene and `$crate`; narrowest fragment specifiers; `_private` module; spanned +errors (`syn::Error::new_spanned` -> `to_compile_error`), never panics; proc-macro +logic in a sibling crate. +Seeds: + 1. `macro_rules!` + 2. `proc_macro|syn::|quote!` + 3. `\$crate` + 4. `to_compile_error|new_spanned` +verify: `cargo expand --lib` (propose if absent, never require), `cargo test` +(trybuild suite if present), `cargo clippy`. +Applicable when: seeds 1-4 hit. N/A when all are 0. +Repo false positives: the exported `redacted_debug!`-class macros (deliberate +API; their contract is `docs`); test-only helper macros; std macros +(`format!`, `vec!`) are not `macro_rules!` definitions. +Gate interaction: repo policy forbids adding new linters/formatters; a `trybuild` +proposal is a proposal. + +### test (rust-testing) + +Judges: the form follows the assertion (unit/integration/doc/property/ +snapshot/golden, differential for ports); behavior not implementation; error +variants not `Display` strings; determinism (seeded generators, injected time, +no network); table-driven with failure messages; a test must be able to fail; +the expected value is human-written or from an independent source. +Seeds (scope: `src/**` + `tests/**`): + 1. `#\[test\]|#\[tokio::test\]` # test mass + 2. `assert_eq!\(|assert_ne!\(|assert!\(` # assertion mass + 3. `proptest!|insta::assert|rstest` # property/snapshot tooling + 4. `#\[ignore\]` # ignored tests +verify: `cargo test --all-features`, `cargo test --doc`, +`cargo clippy --all-targets --all-features`; a new test must be observed failing +first. +Applicable when: seeds 1-4 hit. N/A when all are 0. +Repo false positives: golden/snapshot tests pinned under `tests/golden/**` +(authoritative); policy-required `tests/registration.rs` shims (13-17 lines +calling a shared assertion - documented pattern, do not flag as trivial); +tests deliberately pinning wire shapes; `#[ignore]` where the ignore is +documented (stress/root-only); `test-support` features. +Gate interaction: `make test-unit` is the Layer-1 development umbrella; +`tests/AGENTS.md` governs test placement. "A test that cannot fail" is `high` +severity per the rubric. + +### supply (rust-supply-chain) + +Judges: advisories reached from this repo, unmaintained crates, licence policy, +duplicate versions, tree weight - every finding ends in a decision (upgrade / +replace / vendor / accept with a written reason). +verify: `cargo deny check`, `cargo audit`, `cargo tree -d`, +`cargo update --dry-run`. +Applicable when: NEVER a per-crate lane lens. Lane X1 owns supply at workspace +level. A per-crate lane may note a directly evidenced crate-manifest problem +(unused dependency: dep name appears nowhere in that crate's `src/`+`tests/`) +tagged `supply`, with the census as evidence. + +## (d) Repo constraints ledger + +Lanes MUST consult this before writing any finding. `policy-confirmed` verdicts +must cite the file:line below. + +1. **Workspace lints** (root `Cargo.toml`): `unsafe_code = "forbid"` under + `[workspace.lints.rust]`; `await_holding_lock`/`await_holding_refcell_ref` + `deny`; `disallowed_methods = "deny"` in the `[workspace.lints.clippy]` + table. **Discrepancy recorded**: the `clippy.toml` header says the level + "stands at `allow`" while the manifest table says `deny`; the manifest's + actual text is `deny` (Cargo.toml, `[workspace.lints.clippy]`), and the + Makefile `check-clippy` comment also says "allowed there". Record the + manifest text as authoritative; a finding may not assume the level is + advisory. Only 15 crates inherit the workspace table + (`[lints] workspace = true`); the other 79 carry local `[lints]` tables that + mirror `unsafe_code` + the three clippy lints (verified: every member manifest + carries a lints table or reference; none lacks one). + +2. **`clippy.toml` disallowed-methods list + replacement vocabulary**: tokio + timer/sync/fs/net, `AsyncFd` over non-blocking descriptors, + `d2b-core`'s `loader_worker` bounded-worker shape (one thread, bounded + `sync_channel`, no `try_send` growth), `Notify` armed before check + + `timeout`, `d2b-session-unix`'s `SeqpacketSocket` wrappers, + `d2bd::forward_rendezvous`'s `AsyncFd`. `parking_lot` is banned + outright (KD3) except the R4 worker boundary. A finding that proposes one of + these already-named replacements is `policy-confirmed` unless the site is on + a recorded exception list (per-site allows with sanctioned reasons; see 4). + +3. **Async gate**: `make check-async-gate` -> `cargo xtask check-async-gate` + scanner (`packages/xtask/src/async_gate.rs`); inventory + `packages/xtask/data/async-gate-inventory.json` (1,324 lines, 283 marker + sites at HEAD); source marker `// async-gate-allow: `. Markers are + deliberate exceptions - cite, do not re-flag. Scanner flags a + `lock()`/`read()`/`write()` method call inside an async context not followed + by `.await`. + +4. **Blocking census**: `make check-census` -> `cargo xtask blocking-census + --check packages/xtask/data/blocking-census-baseline.json` (per-crate + baseline; a covered crate above baseline fails). Per-site + `#[allow(clippy::disallowed_methods, reason = "...")]` allows are tracked by + `xtask provider-crate-policy`: sanctioned reasons are exactly + `"dedicated bounded worker per plan R4"`, `"synchronous path"`, + `"CLI-only path"`, `"cfg(test) helper"`; one module-level blanket allow + exemption exists (`packages/d2b-broker-composition/src/dependency_surface.rs`). + +5. **Provider crate policy** (`packages/xtask/src/provider_crate_policy.rs`): + README-only integration ratchet - exactly 18 crates (activation-nixos, + audio-pipewire, clipboard-wayland, credential-entra, + credential-managed-identity, credential-secret-service, device-gpu, + display-wayland, notification-desktop, process-minijail, process-systemd, + guest-azure-container-apps, guest-azure-virtual-machine, + guest-cloud-hypervisor, system-core, transport-azure-relay, transport-unix, + volume-virtiofs) whose `integration/*.rs` is a recorded scaffold rather than + an executable scenario. Required paths per provider crate: `src`, `tests`, + `integration`, `README.md`; nine required README sections. Also closes the + accepted Provider matrix, shared-driver placements, family-knowledge + ratchets, structural-knowledge ratchets, Bazel visibility, committed scope, + and generated provenance. Findings that would remove or rewrite a + ratcheted/policy-required path are `policy-confirmed` (cite + provider_crate_policy.rs line). + +6. **Refusal ledger**: `docs/explanation/over-engineering-audit-record.md` + (the prior 242-finding provider/runtime audit; tree state `515cbf610`). + Refused classes (finding on these is `policy-confirmed` unless it cites + changed evidence): + - policy-required scaffolds (`integration/*.rs` + README paths; finding 9 of + the policy family); + - declared-provider zero-caller artifacts (transport-unix, transport-vsock; + pinned by policy matrix, `nixos-modules/provider-runtime-contracts.nix`, + dossiers, committed schemas); + - pinned wire fields / Nix-pinned catalogs (display Wayland global catalog, + `debug_logging`); + - hand-written `Deserialize` impls that are live admission gates (qemu + guest/provider spec shapes); + - cross-crate refactors refused for ownership (supervisor blocking executor, + ZoneLink enrollment-machine merge, host/user driver merge); + - the toolkit's unconsumed framework half (B3 - declared-but-unwired); + - bus-side watch sink / `d2b-resource-api/src/watch.rs` (B1 kept half); + - `d2b-provider` agent dispatcher half (B2 kept half); + - audio `AudioMediator` defaults / `AudioReadiness` / `FakeAudioMediator`; + - supervisor generic systemd seam; tpm state-intent tokens and + `swtpm_argv` input fields; USBIP dossier-declared surface + (`state_machine.rs`, effect-port tests, `BindingLifecycle`); + - build/packaging consolidation findings (80-88) refused as repo-wide work. + "Not applied" rows (no refusal reason recorded; unchanged code): A4-A8, + B9, C1-C10, and the family gaps the record itself names. A finding on a + not-applied row is actionable but must cite the row id and confirm the site + still matches. + +7. **Wire and contract surfaces**: `docs/reference/error-codes.md` (generated + from `d2b_core::error::Error::all_kinds()`), `docs/reference/cli-contract.md`, + `docs/reference/manifest-schema.md`, `docs/reference/daemon-api.md`, + `tests/golden/**`, and every `src/generated/**` file -> any change here is + `needs-contract`. + +8. **`unsafe` exceptions (enumerated by seed at `6ebdd4cec`; never assume the + set)**: + - Files containing `unsafe` blocks/fns/impls (match counts): + `packages/d2b-broker/src/sys.rs` (103), + `packages/d2b-host-activation-helper/src/main.rs` (24), + `packages/d2b-broker/src/seccomp_compile_tests.rs` (5), + `packages/d2b-broker-fixture-syscall-surface/src/lib.rs` (3), + `packages/d2b-broker/tests/socket_activation.rs` (1), + `packages/d2b-broker/src/ops/disk_init.rs` (1), + `packages/d2b-resource-compiler/src/linux.rs` (1, `execveat` with SAFETY). + (`d2bd-runtime/src/typed_error.rs` matched only a doc-comment word - + false positive.) + - `#[allow(unsafe_code)]` sites: `d2b-broker/src/sys.rs` (52), + `d2b-broker/src/seccomp_compile_tests.rs` (3), + `d2b-broker/src/ops/disk_init.rs` (1), + `d2b-broker/tests/socket_activation.rs` (1). + - Manifest `unsafe_code` settings: `forbid` (most, incl. all provider + crates), `deny` (`d2b-broker`, `d2b-broker-composition`, + `d2b-broker-fixture-handlers`, `d2b-sk-frontend`), `allow` + (`d2b-broker-fixture-syscall-surface`), ABSENT (`d2b-audit`, + `d2b-host-activation-helper`, `d2b-resource-compiler`, `d2b-telemetry`, + `d2b-zone-routing`; of these, only host-activation-helper (24 sites) and + resource-compiler (1) actually contain `unsafe`; the other three contain + none). Crate-level `#![forbid(unsafe_code)]` appears in several `lib.rs`. + - `// SAFETY:` comments: 35 across the workspace. A block without one is a + finding (the skill's mechanical rule). + +9. **Toolchain**: `rust-toolchain.toml` pins channel `1.97.0` (stable, + components rustfmt+clippy); all 94 member manifests are edition 2024 + (verified). Lens advice must be edition-legal (let-chains and if-let chains + are available; `#[unsafe(no_mangle)]`/`unsafe extern` forms required). + +10. **Repo prose rules binding this report**: ASCII `-` only in every document + written (including the ASCII hyphen prohibition list in AGENTS.md); no + tool/model/agent attribution anywhere; finding ids (`RS-####`, and lane-local + `#`) are report-local - remediation later must not copy them into + source comments, changelogs, commit messages, or PR bodies. + +11. **Authoritative context, not audit targets**: `docs/explanation/over-engineering-audit-record.md`, + `docs/adr/**`, `docs/specs/**` dossiers, `docs/residual-review-findings/**`. + They may be cited and must not be flagged for change. + +12. **Security invariants**: the Don'ts list in `AGENTS.md` plus + `docs/contributing/critical-subsystems.md`. A finding that would violate a + Don't is `policy-confirmed` and must cite the Don't (e.g. no per-Guest + systemd units; no host-state mutation outside ownership markers; no broad + chmod/chown/setfacl/`/run/d2b` sweeps; no new storage/ACL/lock ownership + outside ADR 0034's single-repair-owner rule; no d2b cgroup mutation outside + delegation). + +## (e) Per-crate applicability matrix + +Seed-hit counts per crate x lens, measured 2026-09-24 at `6ebdd4cec`. Basis: +matching lines summed across the lens's seeds over `packages//src/**` +excluding `src/generated/**` (the `test` lens adds `tests/**`). Cell `0` = all +seeds zero for that crate (N/A candidate; the card's applicability criteria +decide). Cell `X1`: `supply` is a workspace-level lens owned by lane X1; it is +never applicable per crate. Hit counts are raw match mass, not finding counts; +noisy seeds (`own` `.clone()`, `docs` `-> Result<`) are expected to dominate and +are filtered by lane reading. + +| crate | idiom | own | type | api | err | serde | obs | docs | perf | conc | async | unsafe | ffi | macro | test | supply | +|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| +| d2b | 15 | 500 | 46 | 117 | 240 | 194 | 33 | 335 | 319 | 44 | 77 | 4 | 0 | 0 | 1076 | X1 | +| d2b-audit | 14 | 166 | 6 | 149 | 204 | 84 | 5 | 167 | 58 | 18 | 0 | 1 | 0 | 1 | 206 | X1 | +| d2b-broker | 83 | 2689 | 69 | 625 | 2381 | 332 | 116 | 1162 | 1577 | 144 | 2123 | 283 | 79 | 6 | 2959 | X1 | +| d2b-broker-composition | 2 | 13 | 0 | 24 | 18 | 1 | 16 | 31 | 24 | 0 | 17 | 1 | 0 | 8 | 79 | X1 | +| d2b-broker-fixture-handlers | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | X1 | +| d2b-broker-fixture-syscall-surface | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 | 1 | 0 | 0 | X1 | +| d2b-bus | 23 | 522 | 7 | 325 | 1376 | 2 | 15 | 470 | 169 | 127 | 661 | 0 | 0 | 1 | 712 | X1 | +| d2b-contracts | 6 | 146 | 16 | 552 | 209 | 378 | 0 | 636 | 107 | 0 | 0 | 0 | 0 | 7 | 467 | X1 | +| d2b-contracts-broker | 1 | 82 | 5 | 202 | 143 | 476 | 0 | 210 | 80 | 0 | 0 | 0 | 0 | 0 | 178 | X1 | +| d2b-contracts-control | 0 | 94 | 22 | 241 | 92 | 660 | 0 | 244 | 57 | 0 | 0 | 0 | 0 | 0 | 169 | X1 | +| d2b-contracts-provider | 9 | 142 | 29 | 591 | 404 | 213 | 1 | 720 | 75 | 7 | 3 | 0 | 0 | 1 | 475 | X1 | +| d2b-contracts-resource | 15 | 216 | 30 | 1065 | 585 | 774 | 0 | 1277 | 266 | 2 | 0 | 0 | 0 | 8 | 644 | X1 | +| d2b-contracts-zone-session | 5 | 127 | 19 | 673 | 339 | 355 | 0 | 822 | 127 | 0 | 0 | 0 | 0 | 5 | 422 | X1 | +| d2b-controller-toolkit | 0 | 0 | 0 | 22 | 0 | 0 | 0 | 18 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | X1 | +| d2b-core | 19 | 505 | 11 | 507 | 297 | 552 | 1 | 520 | 383 | 4 | 14 | 1 | 0 | 1 | 540 | X1 | +| d2b-core-controller | 5 | 441 | 11 | 512 | 468 | 49 | 0 | 681 | 58 | 36 | 87 | 0 | 0 | 0 | 395 | X1 | +| d2b-host | 18 | 404 | 16 | 306 | 300 | 125 | 28 | 405 | 295 | 2 | 318 | 19 | 3 | 1 | 550 | X1 | +| d2b-host-activation-helper | 0 | 1 | 0 | 0 | 14 | 0 | 7 | 2 | 5 | 0 | 0 | 26 | 7 | 0 | 7 | X1 | +| d2b-process-conformance | 0 | 58 | 4 | 227 | 147 | 24 | 0 | 264 | 14 | 1 | 8 | 0 | 0 | 1 | 158 | X1 | +| d2b-provider | 2 | 26 | 0 | 170 | 16 | 0 | 0 | 198 | 5 | 34 | 41 | 0 | 0 | 0 | 100 | X1 | +| d2b-provider-activation-nixos | 0 | 59 | 1 | 95 | 64 | 9 | 17 | 111 | 35 | 10 | 123 | 0 | 0 | 0 | 198 | X1 | +| d2b-provider-audio-binding | 1 | 1 | 0 | 14 | 0 | 0 | 0 | 16 | 0 | 0 | 0 | 0 | 0 | 0 | 20 | X1 | +| d2b-provider-audio-pipewire | 1 | 8 | 3 | 100 | 7 | 10 | 1 | 124 | 4 | 4 | 2 | 2 | 0 | 0 | 174 | X1 | +| d2b-provider-audio-service | 0 | 0 | 0 | 8 | 0 | 0 | 0 | 9 | 2 | 0 | 0 | 0 | 0 | 0 | 19 | X1 | +| d2b-provider-clipboard-wayland | 28 | 430 | 10 | 391 | 269 | 97 | 178 | 514 | 229 | 30 | 0 | 7 | 0 | 0 | 492 | X1 | +| d2b-provider-command | 0 | 6 | 0 | 27 | 19 | 10 | 0 | 30 | 1 | 0 | 0 | 0 | 0 | 0 | 14 | X1 | +| d2b-provider-config-nixos | 1 | 30 | 6 | 63 | 16 | 38 | 25 | 90 | 11 | 1 | 8 | 2 | 0 | 0 | 45 | X1 | +| d2b-provider-credential | 0 | 61 | 2 | 85 | 62 | 14 | 2 | 102 | 24 | 15 | 137 | 0 | 0 | 0 | 128 | X1 | +| d2b-provider-credential-entra | 0 | 43 | 2 | 73 | 20 | 0 | 35 | 120 | 6 | 5 | 101 | 1 | 0 | 0 | 226 | X1 | +| d2b-provider-credential-managed-identity | 0 | 52 | 1 | 88 | 23 | 0 | 26 | 129 | 7 | 4 | 55 | 1 | 0 | 0 | 213 | X1 | +| d2b-provider-credential-secret-service | 0 | 84 | 2 | 62 | 57 | 0 | 32 | 135 | 18 | 30 | 121 | 1 | 0 | 0 | 196 | X1 | +| d2b-provider-device | 0 | 3 | 0 | 31 | 0 | 1 | 0 | 35 | 1 | 5 | 16 | 0 | 0 | 0 | 9 | X1 | +| d2b-provider-device-gpu | 2 | 51 | 1 | 142 | 22 | 29 | 17 | 166 | 9 | 2 | 0 | 2 | 0 | 0 | 120 | X1 | +| d2b-provider-device-security-key | 1 | 55 | 1 | 187 | 68 | 9 | 21 | 213 | 11 | 16 | 77 | 1 | 0 | 0 | 151 | X1 | +| d2b-provider-device-tpm | 1 | 71 | 2 | 91 | 83 | 24 | 11 | 125 | 29 | 2 | 77 | 1 | 0 | 0 | 155 | X1 | +| d2b-provider-device-usbip | 1 | 104 | 5 | 313 | 22 | 26 | 45 | 424 | 9 | 11 | 22 | 0 | 0 | 0 | 229 | X1 | +| d2b-provider-display-wayland | 27 | 596 | 7 | 423 | 166 | 32 | 91 | 476 | 138 | 0 | 0 | 8 | 4 | 1 | 548 | X1 | +| d2b-provider-emergency-policy | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | +| d2b-provider-endpoint | 3 | 23 | 1 | 78 | 40 | 44 | 0 | 97 | 14 | 13 | 102 | 0 | 0 | 0 | 81 | X1 | +| d2b-provider-guest | 6 | 158 | 6 | 130 | 135 | 55 | 13 | 213 | 54 | 34 | 290 | 0 | 0 | 0 | 152 | X1 | +| d2b-provider-guest-azure-container-apps | 0 | 44 | 0 | 94 | 4 | 31 | 15 | 128 | 0 | 0 | 51 | 1 | 0 | 1 | 53 | X1 | +| d2b-provider-guest-azure-virtual-machine | 2 | 18 | 1 | 77 | 1 | 21 | 27 | 106 | 0 | 0 | 72 | 1 | 0 | 0 | 106 | X1 | +| d2b-provider-guest-cloud-hypervisor | 8 | 158 | 11 | 361 | 121 | 57 | 53 | 453 | 22 | 0 | 127 | 1 | 0 | 0 | 273 | X1 | +| d2b-provider-guest-qemu-media | 5 | 44 | 5 | 140 | 15 | 63 | 24 | 156 | 15 | 0 | 0 | 1 | 0 | 0 | 140 | X1 | +| d2b-provider-host | 1 | 32 | 4 | 47 | 40 | 4 | 0 | 64 | 16 | 18 | 145 | 0 | 0 | 0 | 95 | X1 | +| d2b-provider-network-local | 11 | 206 | 15 | 328 | 171 | 29 | 4 | 453 | 125 | 8 | 134 | 0 | 0 | 1 | 347 | X1 | +| d2b-provider-notification-desktop | 5 | 108 | 5 | 245 | 107 | 19 | 4 | 341 | 45 | 1 | 0 | 1 | 0 | 0 | 172 | X1 | +| d2b-provider-observability-otel | 5 | 52 | 3 | 128 | 66 | 13 | 3 | 131 | 12 | 20 | 0 | 4 | 0 | 0 | 158 | X1 | +| d2b-provider-operation | 1 | 1 | 0 | 68 | 17 | 49 | 0 | 72 | 0 | 0 | 0 | 0 | 0 | 0 | 20 | X1 | +| d2b-provider-process | 2 | 274 | 7 | 135 | 185 | 18 | 8 | 250 | 129 | 36 | 444 | 1 | 0 | 0 | 325 | X1 | +| d2b-provider-process-minijail | 0 | 2 | 1 | 15 | 2 | 0 | 1 | 22 | 1 | 0 | 19 | 0 | 0 | 0 | 74 | X1 | +| d2b-provider-process-systemd | 3 | 51 | 4 | 78 | 34 | 10 | 4 | 100 | 37 | 0 | 90 | 0 | 0 | 0 | 154 | X1 | +| d2b-provider-provider | 2 | 24 | 1 | 42 | 54 | 15 | 5 | 56 | 15 | 11 | 72 | 0 | 0 | 0 | 74 | X1 | +| d2b-provider-quota | 0 | 0 | 0 | 9 | 0 | 2 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | +| d2b-provider-resource-export | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | +| d2b-provider-resource-import | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | +| d2b-provider-role | 0 | 0 | 0 | 11 | 5 | 0 | 0 | 9 | 4 | 1 | 0 | 0 | 0 | 0 | 11 | X1 | +| d2b-provider-role-binding | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | +| d2b-provider-seccomp-profile | 0 | 2 | 0 | 20 | 10 | 30 | 0 | 21 | 1 | 0 | 0 | 0 | 0 | 0 | 9 | X1 | +| d2b-provider-shell-pool | 0 | 0 | 0 | 10 | 0 | 0 | 0 | 11 | 1 | 0 | 0 | 0 | 0 | 0 | 16 | X1 | +| d2b-provider-shell-session | 0 | 1 | 0 | 10 | 0 | 2 | 0 | 11 | 1 | 0 | 0 | 0 | 0 | 0 | 29 | X1 | +| d2b-provider-shell-terminal | 0 | 40 | 7 | 162 | 5 | 0 | 2 | 229 | 10 | 3 | 2 | 0 | 0 | 0 | 142 | X1 | +| d2b-provider-supervisor | 4 | 138 | 1 | 32 | 144 | 24 | 3 | 130 | 40 | 75 | 42 | 0 | 0 | 1 | 128 | X1 | +| d2b-provider-system-core | 0 | 7 | 0 | 74 | 11 | 11 | 2 | 83 | 0 | 1 | 15 | 0 | 0 | 0 | 83 | X1 | +| d2b-provider-telemetry-binding | 1 | 24 | 2 | 22 | 22 | 7 | 0 | 37 | 11 | 4 | 119 | 0 | 0 | 0 | 70 | X1 | +| d2b-provider-telemetry-service | 1 | 15 | 2 | 18 | 20 | 3 | 0 | 30 | 10 | 4 | 83 | 0 | 0 | 0 | 52 | X1 | +| d2b-provider-test-controller | 0 | 1 | 0 | 0 | 10 | 0 | 10 | 4 | 0 | 0 | 14 | 1 | 0 | 0 | 11 | X1 | +| d2b-provider-toolkit | 12 | 226 | 13 | 565 | 258 | 41 | 14 | 720 | 77 | 81 | 325 | 0 | 0 | 0 | 472 | X1 | +| d2b-provider-transport-azure-relay | 2 | 46 | 3 | 148 | 87 | 9 | 25 | 213 | 24 | 15 | 133 | 1 | 0 | 0 | 199 | X1 | +| d2b-provider-transport-unix | 2 | 0 | 2 | 50 | 3 | 0 | 9 | 48 | 4 | 1 | 1 | 0 | 0 | 0 | 26 | X1 | +| d2b-provider-transport-vsock | 3 | 12 | 0 | 116 | 16 | 6 | 13 | 144 | 3 | 24 | 112 | 2 | 0 | 0 | 135 | X1 | +| d2b-provider-user | 0 | 37 | 2 | 39 | 49 | 5 | 1 | 53 | 11 | 19 | 112 | 0 | 0 | 0 | 113 | X1 | +| d2b-provider-volume | 0 | 63 | 1 | 29 | 44 | 8 | 0 | 55 | 13 | 21 | 114 | 0 | 0 | 0 | 85 | X1 | +| d2b-provider-volume-binding | 0 | 81 | 0 | 36 | 76 | 24 | 1 | 58 | 24 | 24 | 141 | 0 | 0 | 0 | 134 | X1 | +| d2b-provider-volume-local | 8 | 87 | 16 | 319 | 121 | 90 | 23 | 459 | 45 | 111 | 60 | 22 | 0 | 0 | 369 | X1 | +| d2b-provider-volume-virtiofs | 0 | 13 | 1 | 69 | 20 | 12 | 15 | 79 | 12 | 4 | 29 | 0 | 0 | 0 | 128 | X1 | +| d2b-provider-wayland-policy | 0 | 49 | 3 | 81 | 46 | 23 | 0 | 134 | 15 | 11 | 98 | 0 | 0 | 0 | 100 | X1 | +| d2b-provider-wayland-session | 1 | 4 | 0 | 15 | 0 | 0 | 0 | 17 | 0 | 0 | 0 | 0 | 0 | 0 | 26 | X1 | +| d2b-provider-zone | 0 | 2 | 0 | 13 | 1 | 0 | 0 | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 17 | X1 | +| d2b-provider-zone-link | 5 | 53 | 1 | 138 | 115 | 4 | 0 | 152 | 6 | 3 | 0 | 0 | 0 | 0 | 209 | X1 | +| d2b-resource-api | 10 | 408 | 4 | 134 | 685 | 40 | 38 | 232 | 147 | 40 | 340 | 0 | 0 | 4 | 441 | X1 | +| d2b-resource-client | 1 | 76 | 2 | 207 | 99 | 4 | 0 | 244 | 31 | 53 | 101 | 0 | 0 | 0 | 178 | X1 | +| d2b-resource-compiler | 12 | 113 | 14 | 67 | 51 | 27 | 1 | 118 | 157 | 5 | 0 | 8 | 5 | 0 | 148 | X1 | +| d2b-resource-runtime | 22 | 448 | 2 | 401 | 559 | 8 | 1 | 592 | 107 | 209 | 1259 | 0 | 0 | 0 | 707 | X1 | +| d2b-resource-types | 0 | 2 | 0 | 97 | 3 | 0 | 0 | 85 | 1 | 0 | 3 | 0 | 0 | 0 | 46 | X1 | +| d2b-session | 8 | 106 | 11 | 317 | 168 | 0 | 19 | 536 | 35 | 72 | 505 | 1 | 0 | 3 | 383 | X1 | +| d2b-session-unix | 12 | 23 | 10 | 157 | 66 | 0 | 4 | 251 | 25 | 34 | 130 | 5 | 0 | 1 | 214 | X1 | +| d2b-sk-frontend | 1 | 6 | 0 | 25 | 2 | 0 | 2 | 29 | 18 | 2 | 39 | 3 | 0 | 0 | 38 | X1 | +| d2b-telemetry | 0 | 23 | 3 | 94 | 85 | 8 | 0 | 107 | 10 | 11 | 0 | 1 | 0 | 0 | 114 | X1 | +| d2b-unsafe-local-helper | 5 | 77 | 4 | 39 | 120 | 22 | 10 | 103 | 36 | 20 | 0 | 2 | 0 | 0 | 112 | X1 | +| d2b-zone-routing | 11 | 147 | 3 | 208 | 225 | 0 | 0 | 248 | 36 | 38 | 6 | 0 | 0 | 1 | 528 | X1 | +| d2bd | 82 | 3416 | 25 | 316 | 2827 | 471 | 515 | 1160 | 1035 | 400 | 2850 | 22 | 0 | 0 | 2192 | X1 | +| d2bd-runtime | 58 | 1322 | 44 | 1031 | 1261 | 261 | 153 | 1356 | 576 | 317 | 583 | 11 | 0 | 0 | 1543 | X1 | +| xtask | 166 | 1059 | 81 | 457 | 926 | 301 | 75 | 774 | 1157 | 50 | 99 | 4 | 1 | 25 | 1819 | X1 | + +Interpretation rules: + +- A cell is `0` only when every seed returned zero matching lines; the lane then + states N/A (with the criteria note) or clean, per the card. +- A partition lane's share of a crate's counts is its assigned files/ranges; + the sum of parts approximates the crate cell (split files divide their + matches). +- Cells are raw match mass; a lane's own run over its assigned scope is + authoritative for its coverage lines. + +## (f) Lane map + partition rule: published part map + +Partitions below are final (computed mechanically; LPT packing, cap +`ceil(LOC/k) x 1.2`, units whole except the recorded item-range splits). Lanes +follow this map; no renegotiation. Each part lane's header records the part +(`part k/n`), its file list, and - for split files - the line ranges. + +Item-range splits (recorded boundaries; 1-based inclusive): +- `d2bd/src/composition.rs` -> `1-10070` | `10071-20142` | `20143-30213`. +- `d2b-broker/src/runtime.rs` -> `1-10300` | `10301-20603`. +- `xtask/src/provider_crate_policy.rs` -> `1-5353` | `5354-11075`. + +|part id|scope (files / dirs / ranges)| +|---|---| +|`d2bd-p1`|`src/resource_runtime.rs`| +|`d2bd-p2`|`src/composition.rs:10071-20142`, `src/audio_host_controller.rs`| +|`d2bd-p3`|`src/composition.rs:20143-30213`, `src/zone_enrollment.rs`| +|`d2bd-p4`|`src/composition.rs:1-10070`, `src/plane_port.rs`| +|`d2bd-p5`|`src/interaction_composition.rs`, `src/foundation_seed.rs`, `src/principal_allocation.rs`, `src/provider_shutdown.rs`, `src/process_resource_runtime.rs`| +|`d2bd-p6`|`src/resource_plane_v3.rs`, `src/provider_lifecycle.rs`, `src/resource_runtime/**`, `src/credential_resource_runtime.rs`| +|`d2bd-p7`|`src/process_provider_runtime.rs`, `src/provider_effects.rs`, `src/effect_service_actors.rs`, `src/main.rs`, `src/guest_target_session.rs`, `src/lib.rs`| +|`d2bd-p8`|`src/forward_rendezvous.rs`, `src/shared_provider_effects.rs`, `src/provider_registry.rs`, `src/audio_dispatch.rs`| +|`d2b-broker-p1`|`src/runtime.rs:10301-20603`, `src/ops/usbip_lock.rs`, `src/seccomp_compile_tests.rs`| +|`d2b-broker-p2`|`src/runtime.rs:1-10300`, `src/ops/gpu.rs`, `src/ops/modprobe.rs`| +|`d2b-broker-p3`|`src/live_handlers.rs`, `src/state_cells.rs`, `src/ops/store_sync.rs`, `src/ops/usbip_host.rs`, `src/ops/storage_contract.rs`, `src/ops/pidfd.rs`, `src/ops/sysctl.rs`, `src/ops/mod.rs`| +|`d2b-broker-p4`|`src/audit.rs`, `src/ops/tap.rs`, `src/ops/disk_init.rs`, `src/ops/route.rs`, `src/ops/store_sync_audit.rs`, `src/ops/spawn_runner.rs`, `src/ops/host_generation_handoff.rs`, `src/ops/store_sync_export.rs`| +|`d2b-broker-p5`|`src/sys.rs`, `src/ops/swtpm_dir.rs`, `src/ops/nft.rs`, `src/forwarding.rs`, `src/ops/cgroup.rs`, `src/ops/device.rs`, `src/ops/hosts.rs`, `src/fd_passing.rs`, `src/lib.rs`| +|`d2b-broker-p6`|`src/envelope/**`, `src/ops/exec_reconcile.rs`, `src/ops/audit_op.rs`, `src/ops/store_view_posture.rs`, `src/ops/device_worker.rs`, `src/ops/nm.rs`, `src/ops/security_key.rs`, `src/ops/store_view_farm.rs`, `src/ops/usbip_firewall.rs`| +|`d2b-broker-p7`|`src/ops/media.rs`, `src/kernel_ops.rs`, `src/ops/network.rs`, `src/catalog.rs`, `src/ops/state_dir.rs`, `src/ops/state-posture-contract.json`, `src/protocol.rs`, `src/bootstrap.rs`| +|`xtask-p1`|`src/provider_crate_policy.rs:5354-11075`, `src/main.rs`, `src/gen_layer_catalogs.rs`, `src/provider_registration_authority.rs`, `src/service_catalog.rs`| +|`xtask-p2`|`src/provider_crate_policy.rs:1-5353`, `src/gen_broker_operations.rs`, `src/delivery/eligibility.rs`, `src/diagnostic_redaction.rs`, `src/delivery/history_proof.rs`| +|`xtask-p3`|`src/delivery/recovery.rs`, `src/delivery/command.rs`, `src/resource_type_authority.rs`, `src/delivery/snapshot.rs`, `src/provider_packaging.rs`, `src/semantic_service_schemas.rs`, `src/deadcode.rs`, `src/authority_common.rs`, `src/bin/**`| +|`xtask-p4`|`src/delivery/storage.rs`, `src/production_closure.rs`, `src/zone_schema.rs`, `src/delivery/model.rs`, `src/operation_row_authority.rs`, `src/inventory.rs`, `src/delivery/mod.rs`| +|`xtask-p5`|`src/changelog.rs`, `src/async_gate.rs`, `src/blocking_census.rs`, `src/delivery/evidence.rs`, `src/nix_inventories.rs`, `src/bazel_evidence.rs`, `src/delivery/seal.rs`| +|`d2bd-runtime-p1`|`src/supervisor/**`, `src/typed_error.rs`, `src/autostart.rs`, `src/component_session_vsock.rs`, `src/daemon_config.rs`, `src/resource_api.rs`, `src/zone_authority.rs`, `src/shell_backend.rs`, `src/broker_transport.rs`, `src/public_read_model.rs`, `src/vm_start_support.rs`, `src/json_io.rs`| +|`d2bd-runtime-p2`|`src/resource_runtime_support.rs`, `src/guest_resource_runtime.rs`, `src/workload_dispatch.rs`, `src/runtime_process.rs`, `src/workload_target_index.rs`, `src/wire.rs`, `src/ssh_host_key_preflight.rs`, `src/public_projection.rs`, `src/resource_operator_activation.rs`, `src/exec_detached.rs`, `src/admission.rs`, `src/daemon_client.rs`, `src/runtime_capability.rs`| +|`d2bd-runtime-p3`|`src/exec_session.rs`, `src/unsafe_local_helper.rs`, `src/metrics.rs`, `src/authority_persistence.rs`, `src/readiness.rs`, `src/otel_host_bridge_readiness.rs`, `src/ownership_preflight.rs`, `src/unix_transport.rs`, `src/exec_session_real.rs`, `src/terminal_session.rs`, `src/pidfs_probe.rs`, `src/lib.rs`, `src/runtime_util.rs`| +|`d2bd-runtime-p4`|`src/target_runtime.rs`, `src/daemon_audit.rs`, `src/guest_mode.rs`, `src/kernel_module_check.rs`, `src/console_session.rs`, `src/guest_component_session.rs`, `src/ch_stats.rs`, `src/concurrency.rs`, `src/daemon_version.rs`, `src/ch_api.rs`, `src/typed_shell_targets.rs`, `src/wire_response_helpers.rs`, `src/exec_support.rs`| +|`d2b-p1`|`src/context.rs`, `src/activation.rs`, `src/zone_support_bundle.rs`, `src/share.rs`, `src/guest.rs`, `src/zone.rs`, `src/host_generation.rs`, `src/runtime.rs`, `src/main.rs`| +|`d2b-p2`|`src/doctor.rs`, `src/zone_audit.rs`, `src/resource.rs`, `src/host_validate.rs`, `src/shell.rs`, `src/host.rs`, `src/lib.rs`, `src/complete.rs`| +|`d2b-p3`|`src/exec_client.rs`, `src/dispatch.rs`, `src/debug.rs`, `src/zone_doctor.rs`, `src/exec.rs`, `src/endpoint.rs`, `src/provider.rs`, `src/terminal_client.rs`| +|`d2b-bus-p1`|`src/router.rs`, `src/authorization.rs`, `src/registry.rs`, `src/metrics.rs`| +|`d2b-bus-p2`|`src/session/**`, `src/session_seam_tests.rs`, `src/streams.rs`, `src/operations.rs`, `src/wire.rs`, `src/lib.rs`| +|`d2b-contracts-resource-p1`|`src/v3/network.rs`, `src/v3/resource_schema.rs`, `src/v3/operations/**`, `src/v3/device.rs`, `src/v3/resource_status.rs`, `src/v3/volume_state.rs`, `src/v3/payload_schema.rs`, `src/v3/error.rs`, `src/v3/host.rs`, `src/v3/bridge.rs`, `src/v3/limits.rs`| +|`d2b-contracts-resource-p2`|`src/v3/volume.rs`, `src/v3/process.rs`, `src/v3/identity.rs`, `src/v3/execution_policy.rs`, `src/v3/resource.rs`, `src/v3/storage.rs`, `src/v3/volume_binding.rs`, `src/v3/activation_nixos.rs`, `src/v3/user.rs`, `src/v3/mod.rs`, `src/v3/artifact.rs`, `src/lib.rs`| +|`d2b-core-p1`|`src/bundle_resolver.rs`| +|`d2b-core-p2`|`src/privileges.rs`, `src/host.rs`, `src/manifest_v04.rs`, `src/storage.rs`, `src/test_support.rs`, `src/console_ring.rs`, `src/allocator_config.rs`, `src/processes.rs`, `src/storage_lifecycle.rs`, `src/provider_artifact.rs`, `src/host_w3.rs`, `src/static_invariants.rs`, `src/sync.rs`, `src/runtime.rs`, `src/base64_codec.rs`, `src/sandbox_profile.rs`, `src/kernel_seat.rs`, `src/loader_worker.rs`, `src/site.rs`, `src/provider_capabilities.rs`, `src/bundle.rs`, `src/host_generation.rs`, `src/closures.rs`, `src/lib.rs`, `src/unsafe_local_workloads.rs`, `src/configured_argv.rs`, `src/contract_id.rs`, `src/error.rs`, `src/privileges_w3.rs`, `src/workload_identity.rs`| +|`d2b-provider-toolkit-p1`|`src/base/**`, `src/plane/**`, `src/operations/**`, `src/audit/**`, `src/declaration/**`, `src/bin/**`| +|`d2b-provider-toolkit-p2`|`src/testing/**`, `src/server/**`, `src/shared_provider.rs`, `src/credential.rs`, `src/service.rs`, `src/lib.rs`| +|`d2b-provider-display-wayland-p1`|`src/wayland_proxy/**`| +|`d2b-provider-display-wayland-p2`|`src/controller.rs`, `src/runtime.rs`, `src/process.rs`, `src/bin/**`, `src/spec.rs`, `src/policy.rs`, `src/session_children.rs`, `src/principal.rs`, `src/lib.rs`| +|`d2b-resource-runtime-p1`|`src/manager.rs`, `src/resource.rs`, `src/error.rs`, `src/provider.rs`, `src/metadata.rs`, `src/revision.rs`, `src/lib.rs`, `src/schema.rs`| +|`d2b-resource-runtime-p2`|`src/context.rs`, `src/target.rs`, `src/guest_target.rs`, `src/spec_store.rs`, `src/watch.rs`, `src/driver.rs`, `src/identity.rs`| +|`d2b-contracts-provider-p1`|`src/v3/provider.rs`, `src/v3/credential/**`, `src/v3/credential.rs`, `src/v3/provider_registry.rs`, `src/v3/mod.rs`, `src/lib.rs`| +|`d2b-contracts-provider-p2`|`src/v3/semantic_services/**`, `src/v3/credential_controller.rs`, `src/v3/telemetry_policy.rs`, `src/v3/telemetry_frame.rs`| +|`d2b-session-p1`|`src/driver.rs`, `src/server.rs`, `src/handshake.rs`, `src/operation.rs`, `src/streams.rs`, `src/scheduler.rs`, `src/cancellation.rs`, `src/fragmentation.rs`, `src/attachment.rs`, `src/metrics.rs`, `src/typed_stream.rs`| +|`d2b-session-p2`|`src/admission.rs`, `src/engine.rs`, `src/error.rs`, `src/client.rs`, `src/transport.rs`, `src/lifecycle.rs`, `src/record.rs`, `src/bootstrap.rs`, `src/deadline.rs`, `src/lib.rs`| +|`d2b-resource-api-p1`|`src/service.rs`, `src/adapter.rs`, `src/manager_backend.rs`, `src/client.rs`, `src/store.rs`, `src/watch.rs`| +|`d2b-resource-api-p2`|`src/authz.rs`, `src/manager_backend/**`, `src/admission.rs`, `src/error.rs`, `src/identity.rs`, `src/lib.rs`| +|`d2b-core-controller-p1`|`src/controller_assignment.rs`, `src/binding_children.rs`, `src/coordinator.rs`, `src/main.rs`, `src/controllers.rs`, `src/lib.rs`| +|`d2b-core-controller-p2`|`src/authority.rs`, `src/owner_reconcile.rs`, `src/authority_persistence.rs`, `src/migration.rs`| +|`d2b-provider-clipboard-wayland-p1`|`src/bin/**`, `src/fd.rs`, `src/runtime.rs`, `src/audit.rs`, `src/policy.rs`, `src/lib.rs`| +|`d2b-provider-clipboard-wayland-p2`|`src/clipd_host/**`, `src/service/**`, `src/history.rs`, `src/controller/**`, `src/picker.rs`| +|`d2b-contracts-zone-session-p1`|`src/v3/component_session.rs`, `src/v3/role.rs`, `src/v3/resource_export.rs`, `src/v3/zone_link.rs`, `src/v3/resource_import.rs`, `src/v3/mod.rs`, `src/lib.rs`| +|`d2b-contracts-zone-session-p2`|`src/v3/zone_routing.rs`, `src/v3/resource_bundle.rs`, `src/v3/zone_session.rs`, `src/v3/zone.rs`, `src/v3/role_binding.rs`, `src/v3/services.rs`, `src/v3/emergency_policy.rs`| + +Single-part lanes (`d2b-host`, `d2b-provider-*`, ...): audit the whole crate +under `src/**` (excl. `src/generated/**`) plus `tests/**` for the `test` lens. + +Partition notes: `d2bd/src/composition.rs` and `d2b-broker/src/runtime.rs` and +`xtask/src/provider_crate_policy.rs` are item-range splits of single oversized +files; their parts still count as one lane each (no `a`/`b` splits were needed). +Directories named with `/**` mean the whole subtree (e.g. `src/ops/**`), not the +bare file. `d2b-broker-p1`'s `state-posture-contract.json` entry under `d2b-broker-p7` +is a non-Rust data file inside `src/ops/`; skip it for seed runs. diff --git a/docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md b/docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md new file mode 100644 index 000000000..8fefd67f9 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md @@ -0,0 +1,553 @@ +# VERIFICATION - rust skills audit (plan Step 5, independent) + +Baseline: branch `v3` @ `6ebdd4cec` - Date: 2026-09-24 - Verifier: separate +clean-context agent (no consolidation state trusted; every number recomputed). + +**Method.** All mechanical checks run from the repo root with +`python3 .scratch/rust-skills-audit-verify.py` (read-only; imports +`.scratch/parse_lanes.py` and `.scratch/consolidate.py` for parsing and +consolidation, recomputing their outputs rather than trusting the report). +The script parses `U1-constraints.md` sections (a) and (e), the root +`Cargo.toml` member list, all 110 lane files, and `README.md` sections 1, 2, +4, 5, 6; it resolves every anchor against the working tree at the baseline OID +and prints each cited line's content. Anchor plausibility (the cited line +range relates to the claim) was judged by the verifier from the printed line +contents for all 568 checked anchors, with direct reads for every `sev=high` +anchor and for the ambiguous basename resolutions. The check script output +below is abbreviated; the full transcript is reproducible by re-running the +script. + +## check 1: lane completeness - pass + +Command: `python3 .scratch/rust-skills-audit-verify.py` (check 1 section). + +``` +expected lane ids: 110 actual lane files: 110 +missing: [] +extra: [] +check 1: PASS +``` + +The expected set is expanded from the U1 section (a) lane map (`d2bd-p1`..`-p8` +style ranges, single-part rows, `tail-1`..`tail-6`) plus the three cross-cutting +lanes `X1-supply-chain`, `X2-generated-boundary`, `X3-cross-crate-duplication`. +Every mapped lane id has exactly one file in `lane/`; no extra files. 110 = 107 +crate lanes + 3 cross lanes, as the report states. + +## check 2: crate coverage - pass + +``` +members: 94 covered crates: 94 +crates with >1 owner group: [] +uncovered: [] +stray (not members): [] +partition summary: 17 multi-part crates, 50 whole-crate lanes, 27 tail crates (94 = 94 members) +check 2: PASS +``` + +All 94 `packages/*` members of the root `Cargo.toml` appear exactly once across +the lane files (tail lanes counted per `## ` section; part lanes counted +per crate). No member is uncovered, no lane covers a non-member, and no crate is +claimed by two different lane owners. The partition matches the README method +paragraph: 51 part lanes over 17 crates, 50 whole-crate lanes, 6 tail lanes +covering 27 crates (17 + 50 + 27 = 94). + +## check 3: schema conformance - pass + +Command: `python3 .scratch/rust-skills-audit-verify.py` (check 3 section), +which imports `.scratch/parse_lanes.py` and parses all 110 lane files. + +``` +lane files parsed: 110 findings: 1022 +schema violations: 0 +findings missing evidence: [] +findings missing anchors: [] +check 3: PASS +``` + +Zero violations of the lane-file grammar (finding rows matching the exact field +pattern `- # sev=... blast=... effort=... verdict=... - what - fix: ... - [path:line, ...]` +with a following `evidence:` line and >=1 well-formed `[path:line]` anchor; +local id matches lane id; coverage lines well-formed). Every one of the 1022 +raw finding rows carries an evidence line and at least one anchor. + +## check 4: coverage matrix completeness - pass + +``` +matrix rows: 94 (expect 94) cols: 16 +cells: N/A=449 clean=504 numeric=461 X1=90 +bad N/A cells (u1!=0 or findings!=0): [] +bad clean cells (u1==0 or findings!=0): [] +bad numeric cells (count mismatch): [] +zero-u1 numeric set == README-named 8 cells: True +check 4: PASS +``` + +README section 5 has all 94 crate rows x 16 lens columns. Every `N/A` cell +(449 of them) corresponds to a zero seed-hit row for that crate in U1 section +(e) AND zero findings; every `clean` cell has nonzero U1 seed mass and zero +findings; every numeric cell equals the consolidated finding count for that +(crate, lens). The eight numeric cells whose U1 pre-scan row is zero +(`d2b-controller-toolkit`/type, `d2b-provider-credential-entra`/idiom, +`d2b-provider-credential-secret-service`/idiom, +`d2b-provider-guest-azure-container-apps`/type, +`d2b-provider-seccomp-profile`/idiom, `d2b-provider-system-core`/idiom, +`d2b-provider-volume`/idiom, `d2b-provider-wayland-session`/err - lanes read +deeper than the single-pass pre-scan) match exactly the set the README's +coverage note names. Spot-checks against U1 section (e) (10 `N/A` cells: +d2b/ffi=0, d2b/macro=0, d2b-audit/async=0, d2b-audit/ffi=0, +d2b-broker-composition/type=0, d2b-broker-composition/conc=0, +d2b-broker-composition/ffi=0, d2b-broker-fixture-handlers/idiom=0, +d2b-broker-fixture-handlers/type=0, d2b-broker-fixture-handlers/err=0; +10 `clean` cells: d2b/serde=194, d2b/obs=33, d2b/conc=44, d2b/async=77, +d2b/unsafe=4, d2b-audit/serde=84, d2b-audit/obs=5, d2b-audit/conc=18, +d2b-audit/unsafe=1, d2b-audit/macro=1) all agree with the U1 seed matrix. + +## check 5: anchor existence - pass + +``` +high findings: 13 (raw high: 14) +medium/low rows: 1008; every-5th sample: 201 +anchors checked: 568 failures: 0 +check 5 (mechanical): PASS +``` + +All 13 consolidated `sev=high` findings (every anchor) and a deterministic 20% +sample of medium/low rows - every 5th row of the 1008 medium/low raw findings +sorted by (lens, crate, lane-file line) - were resolved and re-read. 568 +anchors total; every anchor resolves to an existing file whose line count is +>= the cited line, and the cited line/range plausibly relates to the claim +(judged from the printed line contents; the 13 high anchors and all ambiguous +basename resolutions were additionally read directly). Resolution followed the +rule: repo-relative first, then crate-relative via `packages//`, then +`packages//src/` and `packages//tests/`, then a basename search +under `packages//` preferring `src/` (e.g. `admission.rs:1182` -> +`packages/d2b-session/src/admission.rs:1182`; `public_wire.rs:167` -> +`packages/d2b-contracts-control/src/public_wire.rs:167`; `controller.rs:1808` +-> `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs:1808`). + +The raw corpus carries 14 high rows; the 14th (`tail-1#4`, unsafe, +d2b-host-activation-helper, `walk_dir` fdopendir handle leak) was merged into +`tail-1#3` by consolidation (recorded merge, overlapping anchors) - a merge, +not a demotion, consistent with README section 7's "no demotions" record. Its +anchors (`packages/d2b-host-activation-helper/src/main.rs:194,218,222,260,265`) +all exist and relate to the claim. + +Deterministic sample list (201 rows; every 5th medium/low row in +(lens, crate, line) order; first anchor shown): + +``` +d2b-audit#7 [api] d2b-audit packages/d2b-audit/src/lib.rs:16 +d2b-broker-p5#2 [api] d2b-broker-p5 packages/d2b-broker/src/ops/cgroup.rs:126-129 +d2b-bus-p2#5 [api] d2b-bus-p2 packages/d2b-bus/src/lib.rs:34 +d2b-contracts-control#5 [api] d2b-contracts-control cli_output.rs:6 +d2b-contracts-resource-p2#6 [api] d2b-contracts-resource-p2 packages/d2b-contracts-resource/src/v3/identity.rs:269-270 +d2b-core-controller-p1#2 [api] d2b-core-controller-p1 packages/d2b-core-controller/src/controller_assignment.rs:2707 +d2b-core-p1#5 [api] d2b-core-p1 packages/d2b-core/src/bundle_resolver.rs:620 +d2b-core-p2#6 [api] d2b-core-p2 packages/d2b-core/src/privileges.rs:741 +d2b-process-conformance#3 [api] d2b-process-conformance packages/d2b-process-conformance/src/lib.rs:52 +d2b-provider-activation-nixos#2 [api] d2b-provider-activation-nixos packages/d2b-provider-activation-nixos/src/controller.rs:14 +d2b-provider-config-nixos#5 [api] d2b-provider-config-nixos packages/d2b-provider-config-nixos/src/service.rs:296-298 +d2b-provider-device-gpu#6 [api] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/lib.rs:12 +d2b-provider-device-tpm#5 [api] d2b-provider-device-tpm effects_service.rs:341 +d2b-provider-display-wayland-p1#8 [api] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12 +d2b-provider-guest-azure-virtual-machine#10 [api] d2b-provider-guest-azure-virtual-machine src/controller/mod.rs:211 +d2b-provider-guest-cloud-hypervisor#14 [api] d2b-provider-guest-cloud-hypervisor guest_local.rs:49-166 +d2b-provider-notification-desktop#7 [api] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/controller.rs:110 +d2b-provider-provider#3 [api] d2b-provider-provider src/driver.rs:215 +tail-3#8 [api] d2b-provider-role packages/d2b-provider-role/Cargo.toml:17 +d2b-provider-system-core#5 [api] d2b-provider-system-core src/lib.rs:40 +d2b-provider-toolkit-p2#4 [api] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/server/service.rs:297-299 +d2b-provider-volume#4 [api] d2b-provider-volume driver.rs:246-250 +d2b-provider-zone-link#6 [api] d2b-provider-zone-link packages/d2b-provider-zone-link/src/zonelink.rs:178 +d2b-resource-runtime-p2#8 [api] d2b-resource-runtime-p2 packages/d2b-resource-runtime/src/context.rs:364-366 +d2b-session-p2#5 [api] d2b-session-p2 engine.rs:166 +d2bd-p2#5 [api] d2bd-p2 packages/d2bd/src/audio_host_controller.rs:68 +d2bd-runtime-p1#5 [api] d2bd-runtime-p1 public_read_model.rs:51-53 +d2bd-runtime-p4#11 [api] d2bd-runtime-p4 packages/d2bd-runtime/src/console_session.rs:66 +d2b-provider-credential-secret-service#5 [async] d2b-provider-credential-secret-service packages/d2b-provider-credential-secret-service/src/lib.rs:1323 +d2b-provider-system-core#11 [async] d2b-provider-system-core src/testing.rs:30 +d2bd-runtime-p4#20 [async] d2bd-runtime-p4 packages/d2bd-runtime/src/console_session.rs:33 +d2b-provider-clipboard-wayland-p1#12 [conc] d2b-provider-clipboard-wayland-p1 src/fd.rs:545 +d2b-provider-guest#2 [conc] d2b-provider-guest packages/d2b-provider-guest/src/driver.rs:502 +d2b-provider-toolkit-p1#8 [conc] d2b-provider-toolkit-p1 packages/d2b-provider-toolkit/src/operations/envelope.rs:487 +d2b-resource-client#8 [conc] d2b-resource-client packages/d2b-resource-client/src/zone_client.rs:510 +d2bd-p7#9 [conc] d2bd-p7 packages/d2bd/src/effect_service_actors.rs:174 +d2b-audit#10 [docs] d2b-audit packages/d2b-audit/src/export.rs:74 +d2b-broker-p3#9 [docs] d2b-broker-p3 packages/d2b-broker/src/ops/sysctl.rs:32 +d2b-broker-p4#5 [docs] d2b-broker-p4 packages/d2b-broker/src/ops/route.rs:29 +d2b-broker-p6#11 [docs] d2b-broker-p6 src/envelope/mod.rs:1118 +d2b-bus-p1#7 [docs] d2b-bus-p1 packages/d2b-bus/src/router.rs:1126 +d2b-bus-p2#8 [docs] d2b-bus-p2 packages/d2b-bus/src/streams.rs:39-40 +d2b-contracts-control#10 [docs] d2b-contracts-control cli_output.rs:10 +d2b-contracts-provider-p2#9 [docs] d2b-contracts-provider-p2 packages/d2b-contracts-provider/src/v3/credential_controller.rs:155 +d2b-contracts-zone-session-p1#5 [docs] d2b-contracts-zone-session-p1 src/v3/component_session.rs:27 +d2b-core-controller-p2#8 [docs] d2b-core-controller-p2 authority_persistence.rs:50 +d2b-core-p2#10 [docs] d2b-core-p2 packages/d2b-core/src/manifest_v04.rs:1 +d2b-p2#11 [docs] d2b-p2 packages/d2b/src/doctor.rs:91 +d2b-provider-activation-nixos#6 [docs] d2b-provider-activation-nixos packages/d2b-provider-activation-nixos/src/controller.rs:118 +d2b-provider-clipboard-wayland-p1#9 [docs] d2b-provider-clipboard-wayland-p1 src/fd.rs:549 +tail-2#2 [docs] d2b-provider-command packages/d2b-provider-command/src/command.rs:38 +d2b-provider-credential-secret-service#3 [docs] d2b-provider-credential-secret-service packages/d2b-provider-credential-secret-service/src/lib.rs:523 +d2b-provider-device-security-key#4 [docs] d2b-provider-device-security-key packages/d2b-provider-device-security-key/src/lease.rs:150-303 +d2b-provider-display-wayland-p1#10 [docs] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/lib.rs:14 +d2b-provider-guest-azure-container-apps#9 [docs] d2b-provider-guest-azure-container-apps src/lib.rs:7 +d2b-provider-guest-cloud-hypervisor#15 [docs] d2b-provider-guest-cloud-hypervisor descriptor.rs:423-429 +d2b-provider-notification-desktop#12 [docs] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/runtime.rs:88-89 +tail-3#2 [docs] d2b-provider-process-minijail packages/d2b-provider-process-minijail/src/launch.rs:33 +tail-3#7 [docs] d2b-provider-role packages/d2b-provider-role/src/lib.rs:1 +d2b-provider-toolkit-p1#7 [docs] d2b-provider-toolkit-p1 packages/d2b-provider-toolkit/src/base/runtime.rs:248-249 +d2b-provider-volume-binding#3 [docs] d2b-provider-volume-binding packages/d2b-provider-volume-binding/src/facets.rs:52 +d2b-resource-api-p1#9 [docs] d2b-resource-api-p1 service.rs:198 +d2b-resource-runtime-p1#8 [docs] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/manager.rs:850 +d2b-session-p1#3 [docs] d2b-session-p1 handshake.rs:25 +d2b-session-p2#10 [docs] d2b-session-p2 admission.rs:1182 +d2b-unsafe-local-helper#7 [docs] d2b-unsafe-local-helper packages/d2b-unsafe-local-helper/src/lib.rs:1-4 +d2bd-p4#6 [docs] d2bd-p4 packages/d2bd/src/composition.rs:438 +d2bd-p8#13 [docs] d2bd-p8 packages/d2bd/src/forward_rendezvous.rs:1046-1049 +d2bd-runtime-p2#7 [docs] d2bd-runtime-p2 runtime_capability.rs:47-64 +d2bd-runtime-p4#16 [docs] d2bd-runtime-p4 packages/d2bd-runtime/src/wire_response_helpers.rs:7 +xtask-p3#6 [docs] xtask-p3 packages/xtask/src/delivery/snapshot.rs:87 +d2b-audit#9 [err] d2b-audit packages/d2b-audit/src/segment.rs:694 +d2b-broker-p6#8 [err] d2b-broker-p6 src/ops/exec_reconcile.rs:1238-1265 +d2b-contracts-provider-p1#8 [err] d2b-contracts-provider-p1 packages/d2b-contracts-provider/src/v3/provider_registry.rs:186 +d2b-contracts-resource-p1#6 [err] d2b-contracts-resource-p1 packages/d2b-contracts-resource/src/v3/operations/error.rs:93 +d2b-core-p1#10 [err] d2b-core-p1 packages/d2b-core/src/bundle_resolver.rs:1405 +d2b-p2#10 [err] d2b-p2 packages/d2b/src/host.rs:274 +d2b-provider-clipboard-wayland-p1#5 [err] d2b-provider-clipboard-wayland-p1 src/bin/d2b-clipd.rs:3550 +d2b-provider-credential-managed-identity#3 [err] d2b-provider-credential-managed-identity lib.rs:1261-1262 +d2b-provider-display-wayland-p2#7 [err] d2b-provider-display-wayland-p2 src/process.rs:335 +d2b-provider-notification-desktop#10 [err] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/host_sink.rs:185 +d2b-provider-supervisor#6 [err] d2b-provider-supervisor packages/d2b-provider-supervisor/src/adapter.rs:888-890 +d2b-provider-toolkit-p2#7 [err] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/shared_provider.rs:615 +d2b-provider-transport-azure-relay#9 [err] d2b-provider-transport-azure-relay packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30 +d2b-resource-client#6 [err] d2b-resource-client packages/d2b-resource-client/src/call.rs:281 +d2b-telemetry#1 [err] d2b-telemetry packages/d2b-telemetry/src/emitter.rs:201-206 +d2bd-p3#1 [err] d2bd-p3 packages/d2bd/src/composition.rs:22793-22797 +d2bd-p6#4 [err] d2bd-p6 packages/d2bd/src/resource_plane_v3.rs:1956 +d2bd-runtime-p3#4 [err] d2bd-runtime-p3 packages/d2bd-runtime/src/exec_session.rs:939 +d2b-audit#2 [idiom] d2b-audit packages/d2b-audit/src/export.rs:103 +d2b-broker-p2#1 [idiom] d2b-broker-p2 packages/d2b-broker/src/runtime.rs:10132 +d2b-broker-p6#4 [idiom] d2b-broker-p6 src/ops/device_worker.rs:312-335 +d2b-contracts-broker#1 [idiom] d2b-contracts-broker packages/d2b-contracts-broker/src/kernel_client.rs:225-227 +d2b-contracts-provider-p2#1 [idiom] d2b-contracts-provider-p2 packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573 +d2b-contracts-zone-session-p1#1 [idiom] d2b-contracts-zone-session-p1 src/v3/component_session.rs:1935 +d2b-core-p2#1 [idiom] d2b-core-p2 packages/d2b-core/src/static_invariants.rs:162 +d2b-p2#5 [idiom] d2b-p2 packages/d2b/src/zone_audit.rs:591 +d2b-provider-clipboard-wayland-p1#3 [idiom] d2b-provider-clipboard-wayland-p1 src/bin/d2b-clipd.rs:1131 +d2b-provider-clipboard-wayland-p2#4 [idiom] d2b-provider-clipboard-wayland-p2 packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46 +d2b-provider-device-gpu#1 [idiom] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/authority.rs:401 +d2b-provider-device-usbip#1 [idiom] d2b-provider-device-usbip driver.rs:267-281 +d2b-provider-display-wayland-p1#5 [idiom] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820 +d2b-provider-guest-azure-virtual-machine#1 [idiom] d2b-provider-guest-azure-virtual-machine src/bootstrap.rs:138 +d2b-provider-guest-cloud-hypervisor#13 [idiom] d2b-provider-guest-cloud-hypervisor guest_local.rs:113-121 +d2b-provider-notification-desktop#1 [idiom] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/controller.rs:660-675 +d2b-provider-supervisor#2 [idiom] d2b-provider-supervisor packages/d2b-provider-supervisor/src/broker.rs:1104-1130 +d2b-provider-transport-azure-relay#1 [idiom] d2b-provider-transport-azure-relay packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239 +d2b-provider-zone-link#1 [idiom] d2b-provider-zone-link packages/d2b-provider-zone-link/src/zone_links.rs:60 +d2b-resource-compiler#1 [idiom] d2b-resource-compiler packages/d2b-resource-compiler/src/lib.rs:2401 +d2b-resource-runtime-p1#2 [idiom] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/manager.rs:1419 +d2b-session-p2#2 [idiom] d2b-session-p2 admission.rs:1593 +d2b-zone-routing#2 [idiom] d2b-zone-routing packages/d2b-zone-routing/src/service.rs:311 +d2bd-p3#9 [idiom] d2bd-p3 packages/d2bd/src/composition.rs:21306-21319 +d2bd-p8#3 [idiom] d2bd-p8 packages/d2bd/src/provider_registry.rs:527-536 +d2bd-runtime-p4#2 [idiom] d2bd-runtime-p4 packages/d2bd-runtime/src/console_session.rs:162 +xtask-p1#5 [idiom] xtask-p1 packages/xtask/src/provider_crate_policy.rs:6662 +d2b-resource-api-p1#14 [macro] d2b-resource-api-p1 service.rs:2245-2267 +d2b-provider-activation-nixos#4 [obs] d2b-provider-activation-nixos packages/d2b-provider-activation-nixos/src/controller.rs:569 +d2b-provider-guest-azure-virtual-machine#11 [obs] d2b-provider-guest-azure-virtual-machine src/controller/mod.rs:346 +d2b-provider-toolkit-p1#6 [obs] d2b-provider-toolkit-p1 packages/d2b-provider-toolkit/src/base/guest.rs:494-498 +d2b-provider-transport-vsock#3 [obs] d2b-provider-transport-vsock packages/d2b-provider-transport-vsock/src/service.rs:735 +d2bd-p2#8 [obs] d2bd-p2 packages/d2bd/src/composition.rs:15195 +d2bd-runtime-p2#5 [obs] d2bd-runtime-p2 runtime_process.rs:450 +X3-cross-crate-duplication#7 [own] X3-cross-crate-duplication packages/d2bd/src/resource_plane_v3.rs:3227 +d2b-broker-p3#1 [own] d2b-broker-p3 packages/d2b-broker/src/ops/pidfd.rs:210 +d2b-bus-p2#3 [own] d2b-bus-p2 packages/d2b-bus/src/session/contract.rs:1046-1056 +d2b-contracts-resource-p1#2 [own] d2b-contracts-resource-p1 packages/d2b-contracts-resource/src/v3/volume_state.rs:138 +d2b-contracts-zone-session-p2#3 [own] d2b-contracts-zone-session-p2 services.rs:216 +d2b-p2#6 [own] d2b-p2 packages/d2b/src/doctor.rs:1062 +d2b-provider#1 [own] d2b-provider packages/d2b-provider/src/agent.rs:290 +d2b-provider-device-gpu#4 [own] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/controller.rs:272 +d2b-provider-guest#5 [own] d2b-provider-guest packages/d2b-provider-guest/src/effects_service.rs:243 +d2b-provider-guest-azure-container-apps#5 [own] d2b-provider-guest-azure-container-apps src/controller.rs:892 +d2b-provider-guest-azure-virtual-machine#5 [own] d2b-provider-guest-azure-virtual-machine src/controller/mod.rs:1046 +d2b-provider-notification-desktop#4 [own] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/lifecycle.rs:338 +d2b-provider-provider#2 [own] d2b-provider-provider src/driver.rs:360 +d2b-provider-toolkit-p2#2 [own] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/server/adapter.rs:305 +d2b-provider-volume#2 [own] d2b-provider-volume driver.rs:337 +d2b-resource-api-p1#1 [own] d2b-resource-api-p1 adapter.rs:425 +d2b-resource-compiler#7 [own] d2b-resource-compiler packages/d2b-resource-compiler/src/main.rs:1467 +d2b-resource-runtime-p1#5 [own] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/metadata.rs:191 +d2b-session-p2#3 [own] d2b-session-p2 engine.rs:689 +d2bd-p3#4 [own] d2bd-p3 packages/d2bd/src/composition.rs:20404 +d2bd-p8#5 [own] d2bd-p8 packages/d2bd/src/forward_rendezvous.rs:456 +d2bd-runtime-p4#4 [own] d2bd-runtime-p4 packages/d2bd-runtime/src/daemon_audit.rs:976 +xtask-p2#3 [own] xtask-p2 packages/xtask/src/gen_broker_operations.rs:844 +xtask-p5#2 [own] xtask-p5 packages/xtask/src/blocking_census.rs:1270 +d2b-broker-p6#13 [perf] d2b-broker-p6 src/ops/store_view_posture.rs:194-271 +d2b-contracts-zone-session-p2#10 [perf] d2b-contracts-zone-session-p2 resource_bundle.rs:382 +d2b-p1#5 [perf] d2b-p1 context.rs:570 +d2b-provider-guest#6 [perf] d2b-provider-guest packages/d2b-provider-guest/src/driver.rs:863 +d2b-provider-notification-desktop#13 [perf] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/host_sink.rs:265 +d2b-provider-toolkit-p2#13 [perf] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/shared_provider.rs:944 +d2b-resource-api-p1#12 [perf] d2b-resource-api-p1 manager_backend.rs:1006 +d2b-session-p2#12 [perf] d2b-session-p2 record.rs:125 +d2bd-p7#8 [perf] d2bd-p7 packages/d2bd/src/process_provider_runtime.rs:333 +xtask-p1#12 [perf] xtask-p1 packages/xtask/src/main.rs:431 +d2b-broker-composition#7 [serde] d2b-broker-composition packages/d2b-broker-composition/src/dependency_surface.rs:308 +d2b-contracts-provider-p2#8 [serde] d2b-contracts-provider-p2 packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76 +d2b-core-p1#12 [serde] d2b-core-p1 packages/d2b-core/src/bundle_resolver.rs:209 +d2b-process-conformance#9 [serde] d2b-process-conformance packages/d2b-process-conformance/src/terminal.rs:39 +d2b-provider-display-wayland-p1#9 [serde] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817 +d2b-provider-supervisor#7 [serde] d2b-provider-supervisor packages/d2b-provider-supervisor/src/broker.rs:1563-1603 +d2b-provider-wayland-policy#2 [serde] d2b-provider-wayland-policy packages/d2b-provider-wayland-policy/src/interaction.rs:241-243 +d2bd-runtime-p2#4 [serde] d2bd-runtime-p2 wire.rs:265-353 +X1-supply-chain#1 [supply] X1-supply-chain packages/d2b-session/Cargo.toml:17 +X1-supply-chain#6 [supply] X1-supply-chain packages/d2b-bus/Cargo.toml:41 +X1-supply-chain#11 [supply] X1-supply-chain packages/d2b-provider-device-gpu/Cargo.toml:25 +X1-supply-chain#16 [supply] X1-supply-chain packages/d2b-provider-transport-azure-relay/Cargo.toml:34 +d2b-provider-device-gpu#13 [supply] d2b-provider-device-gpu packages/d2b-provider-device-gpu/Cargo.toml:20 +d2b-broker-composition#9 [test] d2b-broker-composition packages/d2b-broker-composition/src/seam.rs:523 +d2b-contracts-control#14 [test] d2b-contracts-control public_wire.rs:167 +d2b-core-controller-p2#11 [test] d2b-core-controller-p2 authority.rs:1824 +d2b-host#8 [test] d2b-host packages/d2b-host/src/bin/d2b-activation-helper.rs:792 +d2b-provider-audio-pipewire#12 [test] d2b-provider-audio-pipewire tests/mediator.rs:13-24 +d2b-provider-config-nixos#9 [test] d2b-provider-config-nixos packages/d2b-provider-config-nixos/src/service.rs:70-90 +d2b-provider-device-gpu#12 [test] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/authority.rs:168 +d2b-provider-display-wayland-p2#12 [test] d2b-provider-display-wayland-p2 src/controller.rs:1481 +d2b-provider-guest-cloud-hypervisor#5 [test] d2b-provider-guest-cloud-hypervisor finalize_ordering_test.rs:286 +d2b-provider-supervisor#9 [test] d2b-provider-supervisor packages/d2b-provider-supervisor/src/broker.rs:2040-2043 +d2b-provider-zone-link#8 [test] d2b-provider-zone-link packages/d2b-provider-zone-link/src/zone_links.rs:2519 +d2b-resource-runtime-p1#13 [test] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/revision.rs:182 +d2b-telemetry#5 [test] d2b-telemetry packages/d2b-telemetry/src/meter_registry.rs:176-180 +xtask-p1#15 [test] xtask-p1 packages/xtask/src/gen_layer_catalogs.rs:705 +X2-generated-boundary#6 [type] X2-generated-boundary packages/xtask/src/gen_broker_operations.rs:891 +d2b-bus-p1#3 [type] d2b-bus-p1 packages/d2b-bus/src/router.rs:218-219 +d2b-contracts-broker#5 [type] d2b-contracts-broker packages/d2b-contracts-broker/src/broker_wire.rs:2805 +d2b-contracts-provider-p1#6 [type] d2b-contracts-provider-p1 packages/d2b-contracts-provider/src/v3/provider.rs:1333 +d2b-contracts-resource-p2#5 [type] d2b-contracts-resource-p2 packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47 +d2b-host#1 [type] d2b-host packages/d2b-host/src/nftables.rs:609 +d2b-provider-audio-pipewire#1 [type] d2b-provider-audio-pipewire src/resource_type.rs:64-70 +d2b-provider-clipboard-wayland-p2#9 [type] d2b-provider-clipboard-wayland-p2 packages/d2b-provider-clipboard-wayland/src/picker.rs:247 +d2b-provider-guest#1 [type] d2b-provider-guest packages/d2b-provider-guest/src/driver.rs:709 +d2b-provider-guest-cloud-hypervisor#10 [type] d2b-provider-guest-cloud-hypervisor identity.rs:857-865 +d2b-provider-notification-desktop#5 [type] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/controller.rs:22-27 +tail-4#4 [type] d2b-provider-telemetry-binding packages/d2b-provider-telemetry-binding/src/driver.rs:168 +d2b-resource-client#4 [type] d2b-resource-client packages/d2b-resource-client/src/call.rs:168 +d2bd-p1#8 [type] d2bd-p1 packages/d2bd/src/resource_runtime.rs:1014 +d2bd-runtime-p1#3 [type] d2bd-runtime-p1 component_session_vsock.rs:32-36 +d2bd-runtime-p4#7 [type] d2bd-runtime-p4 packages/d2bd-runtime/src/typed_shell_targets.rs:13 +tail-1#1 [unsafe] d2b-broker-fixture-syscall-surface packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32 +``` + +## check 6: count reconciliation - pass (after consolidator fix; initial run failed) + +Initial run (before the consolidator's fix): + +``` +raw lane rows: 1022 consolidated rows: 965 merges: 57 +965 + 57 == 1022: True +consolidated by sev: {'medium': 295, 'low': 657, 'high': 13} +consolidated by verdict: {'actionable': 923, 'needs-contract': 25, 'policy-confirmed': 17} +exec summary by sev: {'high': 13, 'medium': 295, 'low': 657} +exec summary by verdict: {'actionable': 923, 'needs-contract': 25, 'policy-confirmed': 17} +exec summary lens table: matches consolidated by_lens for all 16 lenses (idiom 124, own 115, + type 82, api 138, err 94, serde 40, obs 31, docs 143, perf 52, conc 29, async 19, + unsafe 4, ffi 0, macro 4, test 67, supply 23) +section 2 rows per lens: total 947; section 4 rows per lane: total 33 +findings with a full row in section 2 or 4: 961 of 965 +rows displayed in BOTH section 2 and section 4 (X1 overlap): 19 +findings with NO full row in sections 2/4: ['RS-0929', 'RS-0930', 'RS-0931', 'RS-0932'] +check 6: FAIL +``` + +The three headline numbers reconciled exactly (1022 raw = 965 report + 57 +merges), and the executive summary's severity split (13 high / 295 medium / +657 low), verdict split (923 actionable / 25 needs-contract / 17 +policy-confirmed), and all 16 per-lens totals equaled the recomputed +consolidated counts. The initial failure was the per-lens section display: +section 2's `supply` section showed 19 rows while the executive summary counts +23 supply findings. Four crate-lane supply findings - `RS-0929` +(`d2b-provider-audio-pipewire#13`), `RS-0930` (`d2b-provider-device-gpu#13`), +`RS-0931` (`d2b-provider-guest-azure-container-apps#13`), `RS-0932` +(`tail-3#4`) - had no full row (what/fix/anchors) anywhere in README sections +2 or 4; they appeared only in the section 3 per-crate index and the section 6 +remediation clusters. The other 14 rows absent from section 2 were the +cross-cutting findings (RS-0952..RS-0965), which section 4 displays by design; +the 19 X1 rows were displayed in both section 2's supply section and section 4 +(a double display, not a loss). Root cause: the render path restricted the +supply section to X1-supply-chain rows and omitted X2/X3 rows from their lens +sections, dropping crate-lane supply rows. + +Re-run after the consolidator's fix (renderer corrected: section 2 now renders +every finding under its lens, grouped by crate, with cross-cutting lanes +grouped under their lane id; section 4 keeps the lane-oriented list): + +``` +raw lane rows: 1022 consolidated rows: 965 merges: 57 +965 + 57 == 1022: True +exec summary by sev: {'high': 13, 'medium': 295, 'low': 657} (matches consolidated) +exec summary by verdict: {'actionable': 923, 'needs-contract': 25, 'policy-confirmed': 17} (matches) +exec summary lens table: matches consolidated by_lens for all 16 lenses (ffi 0 included) +section 2 rows per lens: idiom 124, own 115, type 82, api 138, err 94, serde 40, obs 31, + docs 143, perf 52, conc 29, async 19, unsafe 4, ffi 0, macro 4, test 67, supply 23 + (total 965; every per-lens count equals the executive-summary count) +section 4 rows per lane: X1 19, X2 6, X3 8 (total 33) +findings with a full row in section 2 or 4: 965 of 965 +rows displayed in BOTH section 2 and section 4 (cross-lane overlap): 33 +findings with NO full row in sections 2/4: [] +check 6: PASS +``` + +`RS-0929`, `RS-0930`, `RS-0931`, `RS-0932` are now present as full rows in the +section 2 `supply` section under their crates (`d2b-provider-audio-pipewire`, +`d2b-provider-device-gpu`, `d2b-provider-guest-azure-container-apps`, +`d2b-provider-quota`), and the X2/X3 findings appear in their lens sections. +All 965 findings now have a full row in sections 2/4, and the per-lens section +counts equal the executive-summary counts for all 16 lens labels. + +## check 7: writes confined - pass + +``` +porcelain entries: 2 + ?? docs/audits/2026-09-24-rust-skills-audit/ + ?? docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md +outside allowed paths: [] +check 7: PASS +``` + +`git status --porcelain` lists only the audit deliverable directory and the +pre-existing untracked plan file `docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md` +(not ours, left untouched). No tracked file is modified; `.scratch/` is +gitignored (its contents are audit tooling, allowed by the plan). No source, +policy, or gate file changed during the audit. + +## check 8: README faithfulness spot-check - pass + +Rows 100, 300, 500, 700, 900 of the findings corpus (`RS-0100`, `RS-0300`, +`RS-0500`, `RS-0700`, `RS-0900`) were located in the README and their fields +compared field-by-field with the corresponding lane rows (severity, crate, +what, fix, first-four anchors, verdict, lane reference): + +``` +RS-0100 (d2b-session-p2 d2b-session-p2#1): OK +RS-0300 (d2bd-p1 d2bd-p1#7): OK +RS-0500 (d2b-provider-process d2b-provider-process#3): OK +RS-0700 (d2b-provider-process d2b-provider-process#4): OK +RS-0900 (d2b-provider-guest-azure-container-apps d2b-provider-guest-azure-container-apps#12): OK +check 8: PASS +``` + +## check 9: data quality - parenthesis artifacts (informational) + +Metric (as measured by the consolidator): share of lines with unbalanced +parentheses after stripping regex-escaped parens, over lines containing parens +(after the same strip). Recomputation per lane file: + +``` +unbalanced-line numerators match consolidator's list for all 9 files: True +denominator differences (parent, mine): d2b-provider-guest-qemu-media (49, 50), + d2b-resource-compiler (49, 48), d2b-provider-guest (45, 43), + d2b-provider-volume (41, 37), d2b-provider-credential-managed-identity (36, 37), + d2b-contracts (39, 37), d2b-broker-p6 (52, 51); the other two files match exactly +files >25% artifact share (my recomputation): d2b-broker-p6 (13/51), d2b-contracts + (10/37), d2b-provider-credential-managed-identity (11/37), d2b-provider-guest + (20/43), d2b-provider-guest-qemu-media (40/50), d2b-provider-shell-terminal + (17/37), d2b-provider-volume (14/37), d2b-resource-compiler (33/48), d2bd-p5 + (12/34), xtask-p5 (9/35) +``` + +The unbalanced-line numerators match the consolidator's nine-file list exactly +(40/33/17/20/12/14/11/10/13). The denominators differ by at most 4 lines per +file (attributable to the line-scope definition and/or pre-repair file state); +under my recomputation `xtask-p5` (9/35 = 25.7%) and `d2b-broker-p6` (13/51 = +25.5%) sit just above the 25% threshold while the consolidator's measurement +places broker-p6 at exactly 25% (13/52). This class is prose/punctuation only - +paths, line numbers, and counts are intact - and is not a schema violation. + +## Mismatches + +None. The single mismatch found on the initial run (check 6: four crate-lane +supply findings - `RS-0929`, `RS-0930`, `RS-0931`, `RS-0932` - missing full +rows from README section 2's `supply` section) was reported to the +consolidator, fixed in the renderer, and re-verified: all four rows are now +present and every count reconciles (see check 6 and the re-run section below). + +## Re-run after consolidator fix (checks 3, 5, 6) + +Initial run: check 3 PASS, check 5 PASS, check 6 FAIL (four supply rows missing +from section 2; exact ids `RS-0929`..`RS-0932`). Re-run results after the +consolidator's renderer fix: + +``` +check 3: PASS (110 files, 1022 findings, 0 schema violations) +check 5: PASS (13 high + 201 sampled rows; 568 anchors; 0 failures) +check 6: PASS (1022 = 965 + 57; severity 13/295/657; verdicts 923/25/17; + section 2 total 965; per-lens counts equal the exec summary + for all 16 lenses; no finding without a full row) +``` + +Both passes recorded: checks 3 and 5 were unaffected by the fix (no lane row, +count, or anchor changed) and passed on both runs; check 6 failed on the +initial run and passes after the fix. + +## Pass 3 (final README: verbatim pipe restoration) + +The consolidator made two further README-only changes after pass 2: (1) a +renderer fix - section 2/4 bullet rows previously normalized `|` to `/` in +`what`/`fix` text, corrupting closure pipes inside inline code (e.g. +`map(|resource_type| ...)` rendered as `map(/resource_type/ ...)`); bullet +rows now carry lane text verbatim, and only the section 1 summary table +escapes `|` as `\|` (21 closure snippets restored); (2) README section 7 now +carries the verification summary and the data-quality note gained the +`xtask-p5` (9/35) mention and a renderer note about verbatim pipes. No count, +matrix cell, finding id, or anchor changed. + +Re-run of the full script at the final README: + +``` +check 1: PASS check 2: PASS check 3: PASS check 4: PASS +check 5: PASS check 6: PASS check 7: PASS check 8: PASS +(568 anchors checked, 0 failures; section 2 total 965; per-lens counts equal + the exec summary for all 16 lenses; no finding without a full row) +``` + +Checks 3, 5, 6, 8 all pass at the final README. Additional full-corpus +faithfulness run (beyond check 8's five-row spot check): all 998 finding rows +in README sections 2 and 4 were parsed and compared field-by-field against the +consolidated findings - severity, grouping label, `what` (verbatim), `fix` +(verbatim), first-four anchors, verdict, and lane reference - with zero +mismatches, and all 965 unique RS ids appear in section 2. This confirms the +final README differs from the pass-2 state only in the verbatim row-text +restoration and prose (section 7), with no count, cell, id, or anchor change. +Both earlier passes remain valid: pass 1 (check 6 FAIL, four supply rows +missing) and pass 2 (check 6 PASS after the renderer fix) are recorded above +unchanged. + +## Data-quality note + +Two artifact classes were observed in the lane corpus, both confined to prose +and both verified not to affect any structured field: + +1. **Numeral-spelling and punctuation artifacts** from the lane-writing path + (e.g. `two finding(s)`, `twelve/eleven/zero/zero` coverage phrasing, a + dropped or duplicated `)` in inline snippets). The structured fields + (lens, severity, blast, effort, verdict, anchors, local ids) were parsed + and verified independently of this prose: check 3 found zero schema + violations across all 110 files, and check 8 confirmed the README rows + reproduce the lane rows' structured fields exactly. +2. **Parenthesis imbalance** (drop/duplication, no fact loss): see check 9. + Per-file incidence of unbalanced-paren lines (after stripping regex-escaped + parens) is highest in `d2b-provider-guest-qemu-media` (40/50), `d2b-resource-compiler` + (33/48), `d2b-provider-shell-terminal` (17/37), `d2b-provider-guest` (20/43), + `d2bd-p5` (12/34), `d2b-provider-volume` (14/37), `d2b-provider-credential-managed-identity` + (11/37), `d2b-contracts` (10/37), `d2b-broker-p6` (13/51); the consolidator's + measured list (40/49, 33/49, 17/37, 20/45, 12/34, 14/41, 11/36, 10/39, + 13/52) agrees on every numerator. One mechanical repair was applied to + `d2b-provider-guest-qemu-media.md` only (space-after-paren form); no other + lane file was rewritten for this class. + +The known-and-accepted deviations from the plan's lane-file contract (lane +prose artifacts; non-15-line coverage blocks in five single-crate lanes and +the tail/X lanes; tail lanes carrying one `## ` section per crate) were +observed as documented and do not affect the checks above. \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md b/docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md new file mode 100644 index 000000000..e8183dcaf --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md @@ -0,0 +1,69 @@ +# X1-supply-chain - workspace +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: n/a (workspace manifests and lockfiles) | modules: root Cargo.toml, Cargo.lock, deny.toml, rust-toolchain.toml, packages/Cargo.guest.lock, 94 member Cargo.toml`s +Lenses: supply + +## supply + +Gate posture (what the existing supply-chain lane already covers): `cargo-deny check bans licenses sources` runs on both the main workspace and the guest tree against vendored registries (flake.nix:1287-1345), and `cargo-audit` runs on both checked-in locks plus the per-context policy locks against a pinned RustSec advisory-DB snapshot (flake.nix:1072, rev 831c50f4a4304068f125e603add6a8839f08b3eb; `--no-fetch`). Advisories are therefore fully gated (the absence of a [advisories] section in deny.toml is deliberate, documented at flake.nix:1267-1269). This lane's findings cover tree weight, duplicate clusters, manifest consistency, and licence posture gaps only. + +Checked clean: (a) all 13 workspace.dependencies entries are referenced by at least one member manifest (census over 94 member [dependencies|dev-dependencies|build-dependencies] tables = non-zero each);(b) no over-broad default-features found statically: every tokio/ttrpc decl in the workspace sets default-features = false (the root entries at Cargo.toml:211-212 are the only version sources, and no member re-enables defaults);(c) d2b-core's optional `bolero` dep (line 34) is NOT unused - it wires the `fuzz` feature (Cargo.toml:16) consumed by packages/d2b-core/fuzz/ (harness manifests `fuzz/Cargo.toml`, harness at `fuzz/src/harness.rs`), so it is excluded from the unused list below. + +- X1-supply-chain#1 sev=medium blast=leaf effort=S verdict=actionable - d2b-session depends on d2b-audit but the name appears nowhere in its sources; the dep edge is dead weight in both Cargo and Bazel builds - fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28] + evidence: census: \bd2b_audit\b over packages/d2b-session/src + tests + examples + benches + build.rs = 0 hits; BUILD.bazel carries //packages/d2b-audit:d2b_audit at :28; decision: remove + +- X1-supply-chain#2 sev=medium blast=leaf effort=S verdict=actionable - d2b-session depends on d2b-telemetry but no source reference exists; the edge is carried into both Cargo and Bazel builds - fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31] + evidence: census: \bd2b_telemetry\b over packages/d2b-session/src + tests + examples + benches + build.rs = 0 hits; BUILD.bazel carries //packages/d2b-telemetry:d2b_telemetry at :31; decision: remove + +- X1-supply-chain#3 sev=medium blast=leaf effort=S verdict=actionable - d2b-session's dev-dependency serde_json (workspace-inherited) has zero uses in any of its files - fix: remove the dev-dep (the guest lock regenerates without it) - [packages/d2b-session/Cargo.toml:44] + evidence: census: \bserde_json\b over packages/d2b-session/src + tests + examples + benches + build.rs = 0 hits(including doc-comment doctests in src); decision: remove + +- X1-supply-chain#4 sev=medium blast=leaf effort=S verdict=actionable - d2b-telemetry inherits rustix via workspace=true but no source in the crate references it; the dep is compiled into the telemetry crate for nothing - fix: remove rustix from [dependencies] (the root workspace entry stays, other members use it); regenerate the guest lock, which carries d2b-telemetry - [packages/d2b-telemetry/Cargo.toml:14] + evidence: census: \brustix\b over packages/d2b-telemetry/src (+ tests, examples, benches, build.rs if present) = 0 hits; decision: remove + +- X1-supply-chain#5 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-quota inherits serde_json via workspace=true but no source or test references it - fix: remove serde_json from [dependencies] (and from the generated BUILD deps on the next regen) - [packages/d2b-provider-quota/Cargo.toml:24] + evidence: census: \bserde_json\b over packages/d2b-provider-quota/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#6 sev=medium blast=leaf effort=S verdict=actionable - d2b-bus's dev-dependency tempfile has zero uses across src/tests(including the ui test tree) - fix: remove the dev-dep - [packages/d2b-bus/Cargo.toml:41] + evidence: census: \btempfile\b over packages/d2b-bus/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#7 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-activation-nixos inherits serde via workspace=true but no source or test in the crate names it - fix: remove serde from [dependencies] - [packages/d2b-provider-activation-nixos/Cargo.toml:35] + evidence: census: \bserde\b over packages/d2b-provider-activation-nixos/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#8 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-audio-pipewire inherits schemars via workspace=true but no derive or path in its sources uses it - fix: remove schemars from [dependencies] - [packages/d2b-provider-audio-pipewire/Cargo.toml:25] + evidence: census: \bschemars\b over packages/d2b-provider-audio-pipewire/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#9 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-guest-azure-container-apps inherits sha2 via workspace=true but no source reference exists - fix: remove sha2 from [dependencies] - [packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21] + evidence: census: \bsha2\b over packages/d2b-provider-guest-azure-container-apps/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#10 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-device-gpu declares async-trait but no #[async_trait] or use path names it - fix: remove async-trait from [dependencies] (the Bazel proc-macro dep drops with it on regen) - [packages/d2b-provider-device-gpu/Cargo.toml:20] + evidence: census: \basync_trait\b over packages/d2b-provider-device-gpu/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#11 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-device-gpu depends on d2b-resource-types but no source or test in the crate uses it; the edge carries into Bazel too - fix: remove d2b-resource-types from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39] + evidence: census: \bd2b_resource_types\b over packages/d2b-provider-device-gpu/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#12 sev=medium blast=leaf effort=S verdict=actionable - d2b depends on d2b-zone-routing but no source or test references it; the edge is carried into Bazel too - fix: remove d2b-zone-routing from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55] + evidence: census: \bd2b_zone_routing\b over packages/d2b/src + tests + examples + benches + build.rs = 0 hits; decision: remove + +- X1-supply-chain#13 sev=low blast=wide effort=M verdict=actionable - 13 member decls pin literal versions of workspace-declared deps rustix (3) and sha2 (10, two of them in d2b-broker) instead of the house `workspace = true` pattern (429 workspace-inherit decls across the workspace), duplicating the version truth the root table owns - fix: convert them to `rustix = { workspace = true, features = [...] }` and `sha2 = { workspace = true }`, keeping member-side features (verified additive on the pinned toolchain: a workspace entry + member features resolves with the union on cargo 1.97, offline probe) - [Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, packages/d2b-provider-process/Cargo.toml:30, packages/d2b-provider-network-local/Cargo.toml:38, packages/d2bd/Cargo.toml:100] + evidence: census: literal rustix decls: d2b-broker:60, d2b-provider-process:30, d2b-provider-network-local:38(dev); literal sha2 decls: d2b-unsafe-local-helper:29, d2b-telemetry:13, d2b-provider-guest:28, d2bd-runtime:40, d2b-provider-process-systemd:28, d2b-provider-process:33, d2b-provider-user:25, d2bd:100, d2b-broker:63(normal+dev); all other workspace-declared deps (serde 50, serde_json 88, schemars 20, tokio 87, ttrpc 9, ractor 3, ring 3, base64 4, rusqlite 1, rusqlite_migration 1, unicode-normalization 1) are already 100% workspace=true; decision: convert the 13 to workspace=true + +- X1-supply-chain#14 sev=medium blast=wide effort=M verdict=actionable - nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a syscall-family crate reach shipped binaries - fix: keep the workspace pin at 0.29, and record+accept the 0.26/0.31 legs with expiry in a [bans] comment (name, pullers, re-check trigger, per DENY.md); then consider flipping multiple-versions to `deny` - [deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33] + evidence: cargo tree --offline -d, Cargo.lock parse: nix 0.26.4 pulled by ttrpc@0.9.0;0.29.0 pulled by 19 workspace members incl. d2b-broker, d2bd, d2bd-runtime, xtask;0.31.3 pulled by command-fds@0.3.3 and vsock@0.5.4 (via d2b-provider-transport-vsock); decision: accept with expiry, re-check when ttrpc or vsock bumps its nix pin + +- X1-supply-chain#15 sev=medium blast=wide effort=L verdict=actionable - rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shipped binaries - fix: accept with expiry+record in a [bans] comment (re-check at each dep refresh; or plan a dedicated pass migrating the workspace pin to 1.1 and re-verifying the feature surface, which the root comments pin at 0.38 - [Cargo.toml:202, deny.toml:2] + evidence: cargo tree --offline -d, Cargo.lock parse: rustix 0.38.44 pulled by 33 workspace/transitive dependents(incl. d2b-broker, d2bd, xtask, wayland-client itself zbus);1.1.4 pulled by async-io@2.6.0, async-process, async-signal, polling, wayland-backend, tempfile, zbus, which, etc; decision: accept with expiry, re-check at each dependency refresh or upgrade on a dedicated pass + +- X1-supply-chain#16 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-transport-azure-relay pins webpki-roots "0.26" directly while its tokio-tungstenite 0.24 dep pulls 1.0.9 via its rustls-tls-webpki-roots feature, so the crate builds both legs - fix: upgrade the direct pin to "1" and drop the 0.26 leg(verify the TLS_SERVER_ROOTS API at the call site; if 0.26-only items are used, accept+record+expiry instead) - [packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36] + evidence: Cargo.lock parse: webpki-roots 1.0.9 dependents include tokio-tungstenite@0.24.0; the 0.26.11 leg is the member's own direct pin; decision: upgrade to "1", fallback accept with expiry+record + +- X1-supply-chain#17 sev=low blast=wide effort=M verdict=actionable - the remaining ~31 duplicate clusters(hashbrown,bitflags,heck,indexmap,linux-raw-sys,memoffset,phf family,proc-macro-crate,r-efi,rand,rand_core,syn,thiserror,toml_datetime,toml_edit,winnow,windows-sys family,windows-link,etc) resolve transitively-only at multiple versions,and deny.toml records none of it (multiple-versions = "warn" alone keeps them invisible) - fix: annotate [bans] with the accepted-cluster inventory(name, versions, pullers, re-check trigger, per DENY.md; then flip multiple-versions to `deny` once the workspace-direct clusters (#14-#16) resolve - [deny.toml:2] + evidence: Cargo.lock parse: 34 duplicate clusters total in the main lock(29 in the guest lock); after #14-#16 the remainder isthen ~31; examples: thiserror 1.0.69/2.0.20(1.x from ttrpc, protobuf 3.7.2, tungstenite 0.24, wl-proxy), vs 2.x workspace decls), syn 1/2/3(build-time macro-stack generations), windows-sys 0.48/0.52/0.59/0.61(platform tiers); decision: accept with expiry, record in deny.toml, re-check at each lock regeneration + +- X1-supply-chain#18 sev=medium blast=wide effort=M verdict=actionable - packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2.128, uuid 1.26.1, aws-lc-rs 1.18.1, mio 1.2.3, etc), so the advisory and licence postures of the two shipped trees are assessed against different dependency sets at the same date - fix: regenerate both lockfiles from ONE index snapshot on the next dependency refresh (keeping the guest tree's host-only exclusions; add a drift check comparing shared-crate versions across the two locks) - [packages/Cargo.guest.lock:1, flake.nix:389] + evidence: lock comparison: 77 crates only in main(host-only: bolero/prost/clap/xtask/ d2b CLI crates etc); 34 only in guest(all newer patch versions of shared crates); 39 same-name version diffs, all guest-newer; decision: regenerate both locks from one snapshot, or accept+record the divergence as deliberate with a review date + +- X1-supply-chain#19 sev=low blast=wide effort=S verdict=actionable - deny.toml's licence confidence-threshold sits at 0.8, below the rust-supply-chain skill's 0.9 floor, so licences the tool is guessing at(~80% confidence) pass the gate silently,and rare allow-listed licences(CDLA-Permissive-2.0, Unicode-DFS-2016) may be the reason the bar was lowered - fix: raise to 0.9 (and move any failing allow-listed licence to a per-crate `[licenses.exceptions]` entry with the reason attached, per DENY.md),verifying against the vendored tree at the next flake check - [deny.toml:21] + evidence: static posture read: deny.toml sets confidence-threshold = 0.8 with no exceptions list; the skill's starter keeps it at>=0.9; decision: raise + exceptions, verify at next flake check + +## Coverage +- supply: 19 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md b/docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md new file mode 100644 index 000000000..31ae7e42b --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md @@ -0,0 +1,45 @@ +# X2-generated-boundary - generated boundary +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 19,223 (12,629 generated + 6,594 generator sources) | modules: generated files of d2bd, d2b-broker, d2b, d2b-contracts-resource, d2b-core, d2b-contracts, d2b-contracts-broker, d2b-contracts-zone-session, d2b-resource-api, d2b-audit; generator sources packages/xtask/src/{gen_broker_operations.rs, gen_layer_catalogs.rs, provider_registration_authority.rs, resource_type_authority.rs, service_catalog.rs, authority_common.rs, main.rs (gen-resource-proto/gen-resource-ttrpc), provider_crate_policy.rs (layout-check drift gate)} +Lenses: serde docs api type err + +Generator inventory (provenance headers cross-checked against `packages/xtask/src/provider_crate_policy.rs:6681-6696` GENERATOR_COMMANDS and the emitted-file headers): + +- `gen-broker-operations` (`packages/xtask/src/gen_broker_operations.rs`) emits `d2b-contracts-broker/src/generated/broker_operation_profiles.rs`, `d2b-contracts/src/generated/w3_broker_operations.rs`, `d2b-core/src/generated/broker_operation_authz.rs`, `d2b-broker/src/generated/broker_operation_catalog.rs` (plus `docs/reference/broker-operation-triage.md`, not Rust). +- `gen-layer-catalogs` (`packages/xtask/src/gen_layer_catalogs.rs`) emits `d2b/src/generated/{mod.rs,surface_catalog.rs}`, `d2b-audit/src/generated/{mod.rs,audit_catalog.rs}`, and `d2b-contracts-provider/src/v3/generated/telemetry_catalog.rs` (the last sits under `src/v3/generated/`, outside this lane's 10-crate scope; the per-crate lane owns it). +- `check-provider-crate-layout --fix` (layout authority `packages/xtask/src/provider_crate_policy.rs`; emission in `provider_registration_authority.rs`, `resource_type_authority.rs`, `service_catalog.rs`) emits `d2bd/src/generated/provider_registrations.rs`, `d2b-contracts/src/generated/v3_converted_resource_types.rs`, `d2b-core/src/generated/process_roles.rs`, `d2b-contracts-zone-session/src/generated/service_provider_catalog.rs`. +- `gen-resource-ttrpc` / `gen-resource-proto` (`packages/xtask/src/main.rs:162-166`, codegen at :355-400) invoke ttrpc-compiler 0.8.0 and rust-protobuf 3.7.2 to emit `d2b-resource-api/src/generated/d2b_resource_v3_ttrpc.rs` and `d2b-contracts-resource/src/generated/d2b_resource_v3.rs`; their `mod.rs` registries are hand-maintained (the provenance gate at provider_crate_policy.rs:6737-6738 exempts `mod.rs` from needing a producer). +- `gen-zone-schemas`/`gen-zone-nix-options`/`gen-nix-inventories`/`gen-semantic-service-schemas` emit Nix/JSON/docs only; no committed Rust. + +Include sites (the hand-written side each generated shape compiles into): `d2b-broker/src/catalog.rs:217`, `d2b-contracts-broker/src/broker_wire.rs:894`, `d2b-contracts/src/identity.rs:70` + `privileges_w3.rs:98`, `d2b-core/src/privileges.rs:685` + `processes.rs:217`, `d2bd/src/resource_plane_v3.rs:76`, `d2b-contracts-zone-session/src/v3/mod.rs:64`, `d2b-resource-api/src/generated/mod.rs` (module, not include). + +## serde +- clean: seed 1 (`derive\([^)]*(De)?[Ss]erialize`) over the 16 generated files = 1 hit, the only serde-bearing generated shape: `ProcessRole` in `packages/d2b-core/src/generated/process_roles.rs:11-14`, which follows the skill conventions (`rename_all = "kebab-case"` on the type, CamelCase variants with kebab wire names, `JsonSchema` alongside). The protobuf/ttrpc surfaces (`d2b_resource_v3.rs`, `d2b_resource_v3_ttrpc.rs`) carry `#[derive(PartialEq,Clone,Default)]` only and cross the wire via protobuf encoding - the boundary is the `.proto`, not serde attributes, so no serde finding applies. The generator-side input parse (`gen_layer_catalogs.rs` `BrokerOperationRow` with `#[serde(rename_all = "camelCase")]` reading `docs/reference/policy/broker-operations.json`) is generator-internal and correct. No `deny_unknown_fields`/`try_from`/`flatten`/hand-written `Deserialize` appears in emitted shapes. + +## docs +- clean: seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) over the 16 generated files: every public item emitted by a repo generator carries a contract doc comment with a one-line first sentence (`broker_operation_profiles.rs:7-9`, `broker_operation_catalog.rs:6-8`, `surface_catalog.rs:6-8` and every const/fn, `audit_catalog.rs`, `service_provider_catalog.rs`, `provider_registrations.rs`, `v3_converted_resource_types.rs`, `process_roles.rs` with every variant documented, `w3_broker_operations.rs` being a bare expression fragment included into the documented `all()` at `privileges_w3.rs:97-99`). The ttrpc file carries `#![allow(missing_docs)]` (`d2b_resource_v3_ttrpc.rs:5`); the protobuf file carries no docs - both are external-compiler output, not repo-generator-controlled, and the emitted `mod.rs` registries carry module docs (`//!`). Only cosmetic drift found: two doc lines with trailing whitespace in `process_roles.rs:37,48` (generator emits them from the declaration comments); below finding threshold. + +## api +- X2-generated-boundary#1 sev=medium blast=leaf effort=S verdict=actionable - the hand-maintained registry `d2b-resource-api/src/generated/mod.rs:3-4` glob-re-exports the entire protobuf module (`pub use d2b_contracts_resource::resource_proto::*;`) as public surface of d2b-resource-api, exposing 47 items including reflection internals (`file_descriptor()` at `d2b_resource_v3.rs:7522`, `special_fields: ::protobuf::SpecialFields` on every message) and forcing `pub use protobuf;` at `d2b-resource-api/src/lib.rs:24` - with zero consumers - fix: delete the `d2b_resource_v3` re-export module from the registry (consumers use `d2b_contracts_resource::resource_proto` directly, e.g. `adapter.rs:560,578`); if a consumer ever needs the types through this crate, re-export named arms instead of a glob - [packages/d2b-resource-api/src/generated/mod.rs:3-4, packages/xtask/src/main.rs:355-370, packages/d2b-resource-api/src/lib.rs:24] + evidence: census: `generated::d2b_resource_v3` over packages/ = 0 hits (only `generated::d2b_resource_v3_ttrpc` is consumed: adapter.rs:24, d2bd/src/resource_runtime.rs:10274, d2bd-runtime/src/guest_component_session.rs:456-457); seed 3 (`^\s*pub use `) = 1 glob arm in the registry +- X2-generated-boundary#2 sev=low blast=leaf effort=S verdict=actionable - `d2b-audit/src/lib.rs:7` declares `pub mod generated;` but every consumer of the emitted catalog is in-crate (`crate::generated::audit_catalog::...` at record_types.rs:1038,1067,1212,1297,1367) - fix: `mod generated;` (private) in lib.rs; the emitted file and its registry need no change - [packages/d2b-audit/src/lib.rs:7, packages/xtask/src/gen_layer_catalogs.rs:725, packages/d2b-audit/src/generated/audit_catalog.rs:6-8] + evidence: census: `d2b_audit::generated` over packages/ (excluding d2b-audit itself) = 0 hits; seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) = 1 pub mod arm in lib.rs + +## type +- X2-generated-boundary#3 sev=medium blast=family effort=M verdict=actionable - the broker catalog view emits the authz facets as string literals (`secret_access: "None"`, `broker_required: "Yes"`, `audit_mode: "Yes"` at `broker_operation_catalog.rs:25-27` and every row) into the hand-written `BrokerAuthzFacets` struct whose fields are `&'static str` (`catalog.rs:98-102`), while the same generator emits the same declared data as typed enums in the sibling authz view (`SecretAccess::None`, `BrokerRequirement::Yes`, `AuditMode::Yes` at `broker_operation_authz.rs:12-19`); the broker-composition router string-matches the facet (`row.authz.secret_access != "None"` at routing.rs:98) and a hand-written row already drifts case (`audit_mode: "yes"` at `d2b-broker/src/envelope/mod.rs:2277` vs generated "Yes") - fix: change `BrokerAuthzFacets.secret_access/broker_required/audit_mode` to the existing `SecretAccess`/`BrokerRequirement`/`AuditMode` enums (`d2b-core/src/privileges.rs:48,61,83`; d2b-broker already depends on d2b-core per Cargo.toml:48) and make `generate_catalog` emit enum idents exactly as `generate_authz` already does - [packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-broker/src/catalog.rs:98-102, packages/d2b-broker-composition/src/routing.rs:98, packages/d2b-broker/src/envelope/mod.rs:2277] + evidence: seed 3 (`(mode|kind|state): String`) class: `&'static str` facet fields at catalog.rs:98-102; distinct emitted values: secret_access 4, broker_required 1, audit_mode 2; case drift "yes" vs "Yes" at envelope/mod.rs:2277 +- X2-generated-boundary#4 sev=medium blast=leaf effort=S verdict=actionable - `BrokerOperationRow.disposition` is `&'static str` (`catalog.rs:181`) holding a closed 4-value set emitted by the generator (`disposition: "promoted-live"` etc. at `broker_operation_catalog.rs:17` and 97 more rows), string-matched at catalog.rs:590,773,779,791 and runtime.rs:12562, while the same generator already maps every other closed set to enums (`owner_variant`, profile match, `StubTarget`) - fix: add a `Disposition` enum (four variants: callable-read-only, promoted-live, stubbed-unimplemented, compile-time-only) beside `StubTarget` in `d2b-broker/src/catalog.rs:266`, change the struct field, and have `generate_catalog` emit `Disposition::X` like `owner_variant` - [packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_operation_catalog.rs:17, packages/d2b-broker/src/catalog.rs:181, packages/d2b-broker/src/catalog.rs:590, packages/d2b-broker/src/runtime.rs:12562] + evidence: seed 3 class: `disposition: "` = 98 hits in the emitted file; distinct values = 4 (callable-read-only 4, promoted-live 85, stubbed-unimplemented 8, compile-time-only 1) +- X2-generated-boundary#5 sev=low blast=family effort=L verdict=actionable - the operation-name vocabulary is emitted as strings (`HOST_OPERATION_CATALOG`/`GUEST_OPERATION_CATALOG: &[&str]` at `broker_operation_profiles.rs:8-41`, `operation: "Hello"` at `broker_operation_catalog.rs:11`) and admission is a string `contains` (`BrokerProfile::allows_operation` at `d2b-contracts-broker/src/broker_wire.rs:864-889`), while the same generator emits the w3 subset as the typed `W3BrokerOperation` enum (`w3_broker_operations.rs`, re-exported at `d2b-contracts-broker/src/lib.rs:11`) - fix: have `generate_profiles`/`generate_catalog` emit a full closed `BrokerOperationName` enum (all 98 rows, not just the 24 w3 variants) with `as_str`, and type the catalogs and row `operation` field against it; the wire boundary keeps the string spelling via `as_str` - [packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11, packages/d2b-contracts-broker/src/broker_wire.rs:864-889] + evidence: seed 3 class: `&[&str]` catalogs at broker_operation_profiles.rs:8,41; `operation: "` = 98 hits in broker_operation_catalog.rs; typed sibling `W3BrokerOperation::all()` = 24 variants +- X2-generated-boundary#6 sev=low blast=leaf effort=S verdict=actionable - the authz view's positional `row)...)` helper calls carry a bare boolean at argument 5 (`false`/`true` for `destructive` at `broker_operation_authz.rs:12-19` and every row), the boolean-trap shape the type lens names, in a 988-line generated file where the field is the routing-relevant facet (`row.authz.destructive` at routing.rs:98) - fix: emit `Destructive::No`/`Destructive::Yes` (or named-field construction) from `generate_authz` and drop the `#[allow(clippy::too_many_arguments)]` on the hand-written `row()` helper at `d2b-core/src/privileges.rs:687-708` - [packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-core/src/privileges.rs:687-708] + evidence: seed 2 (`is_\w+: bool|\w+_flag: bool`) class: bare `false,`/`true,` positional args = 98 occurrences in the emitted authz file + +## err +- clean: seed 1 (`\.unwrap\(\)|\.expect\(`) over the 16 generated files = 47 hits, all in `d2b-contracts-resource/src/generated/d2b_resource_v3.rs` descriptor accessors (`descriptor.get(|| file_descriptor().message_by_package_relative_name("...").unwrap())`) - rust-protobuf 3.7.2 standard output on literal names that cannot fail, external-compiler-controlled, not a repo-generator shape. No repo generator emits error shapes into code; the only generated error surface is the protobuf `ResourceError`/`ResourceErrorKind` wire taxonomy (`d2b_resource_v3.rs:1512,7088`), a typed 32-kind enum with `from_i32 -> Option` fail-closed conversion - the err lens's ideal wire shape. Generated lookups fail closed (`provider_ref`/`provider_ref_for_service` at `service_provider_catalog.rs:18-42`, `typed_noun_type`/`admits_*` at `surface_catalog.rs`/`audit_catalog.rs` all return `Option`/`bool`, never panic). The string-facet comparisons in X2-generated-boundary#3/#4 are the only error-adjacent risk (a misspelled facet silently changes an admission decision) and are tracked there. + +## Coverage +- serde: clean (seeds ran: 1 serde derive across 16 generated files, process_roles.rs only, follows rename_all/JsonSchema conventions; protobuf/ttrpc surfaces use protobuf encoding, not serde) +- docs: clean (seeds ran: every emitted pub item carries a contract doc; ttrpc/protobuf external output carries allow(missing_docs)/no docs by compiler design; only trailing-whitespace drift in process_roles.rs:37,48) +- api: 2 finding(s) +- type: 4 finding(s) +- err: clean (seeds ran: 47 unwrap hits, all rust-protobuf descriptor accessors on literal names, external-compiler output; no repo-generator error shapes; generated lookups fail closed) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md b/docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md new file mode 100644 index 000000000..45d4ae18b --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md @@ -0,0 +1,44 @@ +# X3-cross-crate-duplication - cross-cutting duplication +Baseline: 6ebdd4cec | LOC audited: n/a (consumes lane files) | modules: lane corpus +Lenses: cross-crate classes (consumes crate-lane findings) + +## test + +- X3-cross-crate-duplication#1 sev=medium blast=family effort=L verdict=actionable - Provider test-support recorder/harness duplication: each provider crate hand-rolls the same recorder-double family (RecordingEffects/ScriptedProbe/RecordingManager/RecordingRequeue-style recording doubles, ScriptedPort/ScriptedDiscoveryPort/ScriptedEffectPort scripted ports, hand-rolled block_on pollers, TicketBuilder-style fixtures) in its own test_support.rs/testing.rs instead of the toolkit's shipped harness - fix: consolidate the recorder/harness shapes onto `d2b-provider-toolkit/src/testing` (TestHarness at testing/mod.rs:397, fakes.rs, fixture.rs, conformance.rs) and have the family crates reuse it; the toolkit module is the B3-kept base, so this does not re-propose the B3 refusal - [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-device-security-key/src/test_support.rs:32, packages/d2b-provider-device-usbip/src/test_support.rs:25, packages/d2b-provider-volume-local/src/testing.rs:1, packages/d2b-provider-system-core/src/testing.rs:23, packages/d2b-process-conformance/src/testing.rs:60, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129] + evidence: contributing lanes: d2b-provider-credential#4 (its evidence names the family-wide pattern across d2b-provider-device/-endpoint/-guest/-network-local/-process/-usbip/-activation-nixos test_support modules, "X3 candidate"), d2b-provider-guest#3, d2b-provider-user#3, d2b-provider-volume-binding#4, d2b-provider-device-security-key#5, d2b-provider-device-usbip#8, d2b-provider-volume-local#3, d2b-provider-system-core#4, d2b-process-conformance#5, d2b-provider-guest-qemu-media#5; parser over 109 lane files (1014 findings); source re-check: toolkit testing module exists (mod.rs:397 TestHarness, clock at 530), member anchors verified at the cited lines +- X3-cross-crate-duplication#2 sev=low blast=family effort=S verdict=actionable - Test-support shipping shape: `test-support` features declared empty and gating nothing in four declaration crates while three provider crates ship `pub mod testing` (ScriptedPort/block_on harnesses) unconditionally in the production library and d2b-resource-types exports a test-only helper through the root despite declaring the feature - fix: wire each `test-support = []` feature to its module (`#[cfg(feature = "test-support")]` on `pub mod testing`, `#[cfg(feature = "test-support")]` on `assert_metadata_registration`) or drop the empty features, following the house pattern at d2b-provider-host/Cargo.toml:28 - [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-volume-local/src/lib.rs:46, packages/d2b-provider-system-core/src/lib.rs:41, packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-resource-types/src/lib.rs:30] + evidence: contributing lanes: tail-3#3/#5/#6/#8 (census: declared empty in 4 tail-lane crates, enabled by no manifest), d2b-provider-volume-local#3, d2b-provider-system-core#4, d2b-process-conformance#5, tail-6#3; prior audit deferred the class at docs/explanation/over-engineering-audit-record.md:916; source re-check: quota Cargo.toml:17 `test-support = []`, volume-local/system-core/process-conformance `pub mod testing` at lib.rs:46/41/38, host feature at Cargo.toml:28 + +## conc + +- X3-cross-crate-duplication#3 sev=medium blast=wide effort=S verdict=policy-confirmed - parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-census-baseline.json, `parking_lot::Mutex::lock: 0` for every crate) key on the path `parking_lot::Mutex::lock`, which never resolves because `parking_lot::Mutex` is a type alias (`pub type Mutex = lock_api::Mutex`), so unsuppressed lock sites in 10+ crates record zero hits and no per-site allow is demanded - fix: configure the disallowed entry and the census DeniedApi list on the resolved path (`lock_api::Mutex::lock`, or the def-path clippy reports for the alias), then re-run the census so the unsuppressed sites surface and get per-site allows or conversions per the KD3 ban - [clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-process/src/driver.rs:680, packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2b-resource-runtime/src/context.rs:800] + evidence: contributing lanes (each independently found the 0-vs-source mismatch): d2b-provider-credential#4, d2b-provider-device-gpu#11, d2b-provider-device-security-key#5, d2b-provider-device-usbip#8, d2b-provider-guest#3, d2b-provider-process#5, d2b-provider-user#3, d2b-provider-volume-binding#4, d2b-resource-runtime-p2#15, d2bd-runtime-p3#10, tail-2#3; parser over 109 lane files; source re-check: clippy.toml:82 entry present, parking_lot-0.12.5/src/mutex.rs:86 alias, baseline rows all 0 for crates with 14+ lock sites; verdict policy-confirmed because the fix changes gate configuration (KD3 ban policy at clippy.toml:40-43 stays) + +## serde + +- X3-cross-crate-duplication#4 sev=medium blast=family effort=L verdict=actionable - Parallel serde shims: contract/provider crates hand-write the identical Wire-struct admission shape (private `#[derive(Deserialize)]` Wire with deny_unknown_fields, then new()/TryFrom with validation) in 24+ impls where the in-tree `parsed_deserialize!` macro exists - fix: consolidate behind `parsed_deserialize!` (d2b-contracts-resource/src/v3/execution_policy.rs:33, re-exported at :63) or `#[serde(try_from = "...")]` with the raw Wire shape, keeping every admission gate; this deduplicates boilerplate and is distinct from the refused gate-removal class (over-engineering-audit-record.md rows 25/33 refused replacing gates with derives) - [packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs:101, packages/d2b-contracts-zone-session/src/v3/zone.rs:79, packages/d2b-contracts-zone-session/src/v3/role_binding.rs:192, packages/d2b-contracts-zone-session/src/v3/services.rs:265, packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs:176, packages/d2b-contracts-control/src/unsafe_local_wire.rs:118, packages/d2b-contracts-control/src/public_wire.rs:2228, packages/d2b-provider-display-wayland/src/spec.rs:263, packages/d2b-provider-display-wayland/src/policy.rs:194, packages/d2b-provider-endpoint/src/endpoint.rs:197] + evidence: contributing lanes: d2b-contracts-zone-session-p2#8 (17 impls, names parsed_deserialize! as the canonical home), d2b-contracts-control#9 (3 impls + Wire shadow structs), d2b-provider-display-wayland-p2#8 (3 impls), d2b-provider-endpoint#3 (sibling hand-written gate); ledger C4 "Contract-crate macro/boilerplate consolidation" is not-applied with no refusal reason (over-engineering-audit-record.md C-tier); parser over 109 lane files; source re-check: execution_policy.rs:33 macro exists, zone_routing.rs:558 `impl<'de> Deserialize<'de> for ZoneTreeEdge`, endpoint.rs:197-216 hand-written gate + +## type + +- X3-cross-crate-duplication#5 sev=high blast=family effort=M verdict=actionable - Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one member, d2b-provider-wayland-policy, panics on caller input at the family engine's public boundary) - fix: type the args field as `d2b_contracts_resource::v3::ZoneId` (or a `BoundedToken`) in each `*DriverArgs` and parse once at the daemon construction boundary, with `SharedProviderDriverArgs` in d2b-provider-toolkit as the shared home the family args mirror - [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-volume/src/driver.rs:246] + evidence: contributing lanes: d2b-provider-wayland-policy#1 (sev=high: `ZoneId::parse(args.zone).expect` on pub constructor), d2b-provider-volume-binding#1 (per-pass `BoundedToken::parse(...).expect` at driver.rs:426-427), d2b-provider-toolkit-p2#7 (`ZoneId::parse(args.zone).expect("driver zone was validated at construction")`), d2b-provider-credential#2, d2b-provider-guest#1, d2b-provider-volume#4 (zone never read); parser over 109 lane files; source re-check: all six `pub zone: String` fields and the three expect sites verified at the cited lines + +## err + +- X3-cross-crate-duplication#6 sev=medium blast=wide effort=M verdict=needs-contract - Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { path, detail: String }`, `Io(String)`, `Frame(String)`, `ManagerRpc(String)`, `TypedError::InternalIo { context, detail }`, five `String` variants of PlaneError, `kind: String` in four Io variants), destroying the source chain so diagnostics and callers cannot distinguish failure classes - fix: carry the source with thiserror `#[from]`/`source()` in each enum (no in-tree helper exists; the std Error source chain is the canonical home); wire-visible members (d2bd TypedError) need contract sign-off before the shape changes, internal members (broker, clipboard, azure-relay, resource-runtime, d2bd-runtime vsock) are actionable first - [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69, packages/d2b-resource-runtime/src/error.rs:773, packages/d2bd/src/composition.rs:13894, packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/audio_dispatch.rs:487, packages/d2bd-runtime/src/component_session_vsock.rs:32] + evidence: contributing lanes: d2b-broker-p1#2 (12 conversion sites), d2b-broker-p5#3 (3 map_err sites), d2b-provider-clipboard-wayland-p2#12 (6 to_string() sites), d2b-provider-transport-azure-relay#8 (From impls discard source), d2b-resource-runtime-p1#6, d2bd-p2#6, d2bd-p6#3, d2bd-p8#9 (verdict needs-contract on TypedError), d2bd-runtime-p1#3; parser over 109 lane files; source re-check: all nine variant declarations verified at the cited lines + +## own + +- X3-cross-crate-duplication#7 sev=medium blast=family effort=M verdict=actionable - Repeated ownership pattern: public signatures and fields across eight crates leak `Arc`/`&Arc` (accessors returning `&Arc`, constructors taking `Arc` where single ownership suffices, pub fields carrying `Arc>`), forcing callers to see refcount plumbing and blocking signature evolution - fix: return `&T`/owned values and take owned parameters per the ownership-not-clone convention (canonical home is the borrow/owned convention; no shared type involved, so the merge target is per-crate signatures) - [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:491, packages/d2b-provider-toolkit/src/testing/mod.rs:530, packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343, packages/d2b-provider-device-usbip/src/broker.rs:131, packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs:211, packages/d2bd-runtime/src/shell_backend.rs:52, packages/d2b-provider-device/src/driver.rs:128] + evidence: contributing lanes: d2bd-p6#2 (four `&Arc` accessors), d2b-resource-runtime-p2#9 (`&Arc`), d2b-provider-toolkit-p2#6 (`&Arc`), d2b-provider-supervisor#3 (`Arc`), d2b-provider-transport-azure-relay#7 (`Arc`), d2b-provider-device-usbip#4 (returns `Arc>`), d2b-provider-device-gpu#7 (pub Arc fields), d2b-provider-guest-azure-virtual-machine#10 (`Arc` param), d2bd-runtime-p1#4 (`pub backend: Arc`), tail-2#3 (pub `Arc>` fields); parser over 109 lane files; source re-check: all ten signatures verified at the cited lines + +## api + +- X3-cross-crate-duplication#8 sev=low blast=family effort=S verdict=actionable - Double-path public surface: eleven crates expose every item of a module at two public paths (`pub mod x` plus root `pub use x::*` or item re-exports), deviating from the house single-surface convention and letting future pub items silently widen API - fix: keep one public path per item (either the module or the root re-export, per the house single-surface pattern the d2b-sk-frontend lane names), deleting the duplicate arm in each lib.rs - [packages/d2b-provider-device-usbip/src/lib.rs:24, packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-zone/src/lib.rs:17, packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-process-conformance/src/process_provider.rs:9, packages/d2b-provider-device-gpu/src/lib.rs:14, packages/d2b-provider-device-security-key/src/lib.rs:16, packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:13, packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-system-core/src/lib.rs:40, packages/d2b-provider-guest-azure-container-apps/src/lib.rs:14] + evidence: contributing lanes: d2b-provider-device-usbip#3, tail-4#2, tail-5#11, tail-6#4, d2b-process-conformance#4, d2b-provider-device-gpu#6, d2b-provider-device-security-key#2, d2b-provider-display-wayland-p1#8, d2b-provider-process-systemd#4, d2b-provider-system-core#5, d2b-provider-guest-azure-container-apps#8; parser over 109 lane files; source re-check: `pub mod` + root `pub use` pairs verified at the cited lib.rs lines (zone lib.rs:17+21, seccomp lib.rs:19+22, sk-frontend lib.rs:22-29) + +## Coverage +- classes: 8 finding(s) +- corpus: 109 lane files consumed (107 crate lanes + X1-supply-chain + X2-generated-boundary), enumerated via .scratch/parse_lanes.py (1014 findings extracted; 3 pre-existing anchor-shape violations in d2b-core-p1/d2b-provider-volume-local/tail-2 belong to the lane corpus, not this lane); member anchors re-verified in source at baseline 6ebdd4cec; no crate code re-audited from scratch \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md new file mode 100644 index 000000000..1df8ec86d --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md @@ -0,0 +1,88 @@ +# d2b-audit - d2b-audit +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5221 (excl. src/generated/**) | modules: evidence_chain, export, hash_chain, lib, operation, rate_limit, reconcile, record_types, segment, sink +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-audit#1 sev=medium blast=leaf effort=S verdict=actionable - `read_bounded_line` is copy-pasted three times with only the error-code strings differing ("audit-export-line-*" / "audit-segment-line-*" / "audit-scan-line-*") - fix: extract one crate-private `read_bounded_line` (canonical home: a shared module or segment.rs) taking the line-limit/truncated error codes as parameters, and delete the two copies - [packages/d2b-audit/src/export.rs:255, packages/d2b-audit/src/segment.rs:980, packages/d2b-audit/src/sink.rs:421] + evidence: idiom seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 9 hits; manual read found 3 verbatim ~30-line copies of the same bounded reader differing only in error strings +- d2b-audit#2 sev=low blast=leaf effort=S verdict=actionable - `paths.retain)...)` in `export_segments_range` re-applies `is_segment_name` to every path the read_dir loop already filtered, a redundant pass over the directory listing - fix: delete the `paths.retain` block (export.rs:103-110); the push guard at export.rs:94-102 is the only filter needed - [packages/d2b-audit/src/export.rs:103] + evidence: manual read of export_segments_range; both the loop guard (export.rs:94-102) and the retain (export.rs:103-110) apply the same `is_segment_name` predicate +- d2b-audit#3 sev=low blast=leaf effort=S verdict=actionable - `scan_chain_state` re-invokes `record.mutation_id()` and `record.zone_operation_key()` inside the block whose outer `if let` already bound them, re-deriving two SHA-256 identities per mutation record during the startup scan - fix: use the outer bindings for the `mutation_predecessors` insert, deleting the inner `if let` (sink.rs:403-410) - [packages/d2b-audit/src/sink.rs:393, packages/d2b-audit/src/sink.rs:403] + evidence: manual read of scan_chain_state; inner if-let at sink.rs:403-410 shadows `mutation_id`/`key` bound at sink.rs:393-394, recomputing `zone_operation_key()` (two digest derivations) +- clean: seeds ran: 5/0/9; the 5 index loops are all test loops (evidence_chain.rs:282, rate_limit.rs:87, segment.rs:1250/1528, sink.rs:503), seed 2 is 0 (no hand-written Default/From/PartialEq/Eq/Clone/Hash impls; the redacting Debug impls use `core::fmt::Debug` paths), and the 9 `Vec::new()` sites are bounded readers/collectors of unknown size + +## own +- d2b-audit#4 sev=low blast=leaf effort=S verdict=actionable - `OperationIdentity::parse` calls `AuditHash::parse(value.to_owned())`, allocating a String though `AuditHash::parse` takes `impl Into` and `&str: Into` holds - fix: pass `value` directly (`AuditHash::parse(value)`) - [packages/d2b-audit/src/operation.rs:79] + evidence: own seed 2 `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = ~100 hits (mostly test fixtures); `AuditHash::parse(value: impl Into)` at packages/d2b-telemetry/src/audit_hash.rs:23 accepts `&str` without allocation +- clean: seeds ran: 55/~100/0/0; every production `.clone()` is explainable (AuditHash is a `String`-wrapped newtype, not Copy - owned values require clone; `EvidenceChain::nested` clones to build the appended chain; sink/segment map and index clones are required by the owned key shapes), seeds 3-4 are 0 real hits (the 8 `Rc<` substring matches are `Arc` fields of the test-only `FailureInjector`) + +## type +- d2b-audit#5 sev=medium blast=wide effort=S verdict=actionable - `EvidenceChain` derives `Deserialize` (evidence_chain.rs:50) while its accessors assume a non-empty identity list: `invoking_identity()` panics via `.last().expect)...)`, `initiating_identity()` indexes `&self.identities[0]`, and `depth()` underflows on `len() - 1`; the "identities never empty" invariant is enforced only by the constructors, so a wire payload with `"identities": []` deserializes into the illegal state - fix: hand-write `Deserialize` for `EvidenceChain` rejecting an empty `identities` (the crate's own admission-gate pattern in operation.rs), or make the accessors total - [packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115, packages/d2b-audit/src/evidence_chain.rs:121, packages/d2b-audit/src/evidence_chain.rs:102] + evidence: manual read; census: `EvidenceChain` over packages/d2b-broker, packages/d2bd, packages/d2bd-runtime = 30 hits, all `root()`/`nested()` construction (e.g. d2b-broker/src/envelope/mod.rs:1152, d2bd/src/forward_rendezvous.rs:650), zero deserialize sites; panic is not reachable from current callers but the parse boundary admits the state +- clean: seeds ran: 7/0/0; the `validate_*` hits are filesystem-metadata and closed-domain checks at the wire boundary (validate_fields record_types.rs:1036 is the parse-once admission gate over the generated audit_catalog vocabulary; segment.rs validate_* are inode/ownership checks), `update_state`/`disruption` strings mirror the pinned wire schema, and `evidence_from_decision_result` string-matching is the wire-boundary parse into typed `DurabilityOutcome` + +## api +- d2b-audit#6 sev=medium blast=leaf effort=M verdict=actionable - the crate re-exports a large surface with zero external consumers: `sink` (AuditSink/AuditSinkError/AuditWriteOutcome), `segment` (SegmentWriter/FailureInjector/FailurePoint/DEFAULT_MAX_SEGMENT_BYTES/DEFAULT_RETENTION_DAYS), `export` (ExportLine/export_segments/export_segments_range/MAX_EXPORT_*), `rate_limit` (AuditRateLimiter/AuditWriteClass/RateDecision/DEFAULT_AUDIT_WRITES_PER_SECOND), `record_types` (AuditRecord/AuditRecordFields/*Fields/AuditRecordError/AUDIT_SCHEMA_VERSION), and `reconcile`'s `reconcile`/`Reconciliation`/`DurabilityOutcome` are all exported from lib.rs:16-46 but no dependent crate references them; consumers (d2b-broker, d2bd, d2bd-runtime, d2b-session) use only evidence_chain, operation, hash_chain, and `evidence_from_decision_result`/`DurabilityEvidence` - fix: either wire the daemon-side audit writer (d2bd-runtime daemon_audit) to the sink/segment/export stack, or reduce the unwired modules to `pub(crate)` until a consumer exists (crate is `publish = false`) - [packages/d2b-audit/src/lib.rs:16, packages/d2b-audit/src/lib.rs:30, packages/d2b-audit/src/lib.rs:33, packages/d2b-audit/src/lib.rs:37, packages/d2b-audit/src/lib.rs:43] + evidence: census: `d2b_audit::(AuditRecord|record_types|sink|segment|export|rate_limit|reconcile_durability|Reconciliation|DurabilityOutcome|AuditSink|SegmentWriter|FailureInjector|AuditRateLimiter|export_segments|MAX_EXPORT_*)` over the 4 dependent crates (packages/d2b-broker, packages/d2bd, packages/d2bd-runtime, packages/d2b-session) = 0 hits; consumed surface is d2b-broker/src/audit.rs:27, runtime.rs:7122, ops/audit_op.rs:10, d2bd/src/forward_rendezvous.rs:78 +- d2b-audit#7 sev=low blast=leaf effort=S verdict=actionable - `pub use d2b_telemetry::TraceContext;` (lib.rs:16) re-exports a foreign type that nothing in the crate or any dependent references - fix: drop the re-export (or adopt TraceContext in the record envelope if it is meant to be the trace carrier) - [packages/d2b-audit/src/lib.rs:16] + evidence: census: `d2b_audit::TraceContext` over packages/ = 0 hits; `TraceContext` appears nowhere in src/ except the re-export line (record_types uses `d2b_telemetry::canonical_export_id` directly) +- clean: seeds ran: ~145/0/12; every pub item carries a doc comment, no Arc/Rc/Box/RefCell appears in a public signature, and the `pub use` arms in lib.rs:16-46 are the house single-surface pattern (all consumed except the two findings above) + +## err +- d2b-audit#8 sev=medium blast=leaf effort=S verdict=actionable - `export_segments_range` classifies a failed `AuditRecord` deserialize by string-matching the serde error's Display (`error.to_string().contains("audit-record-hash-mismatch")`) to pick the "hash-break" export error code; a reworded deserialize message silently reclassifies a chain break as "record-invalid" - fix: split parse from verification (deserialize into a wire shape, then `verify()` to surface `AuditRecordError::HashMismatch`), or have the `Deserialize` impl expose the failure class; the emitted `error_code` strings stay unchanged - [packages/d2b-audit/src/export.rs:230] + evidence: err seed 1 `\.unwrap\(\)|\.expect\(` = 3 production hits (all invariant expects: evidence_chain.rs:121, record_types.rs:367/922) plus test unwraps; `AuditRecordError::HashMismatch` variant exists at record_types.rs:887 and is the type the string names +- d2b-audit#9 sev=medium blast=leaf effort=S verdict=actionable - `is_discardable_checkpoint_scratch_error` classifies `io::Error` by matching `error.to_string().as_str()` against three literal codes ("audit-retention-checkpoint-invalid" / "-limit" / "-unverifiable") produced by `io::Error::other` at the checkpoint read/validate sites; a reworded code silently changes the discard decision on restart - fix: introduce a private checkpoint-read error enum (or a sentinel error kind) and match on it, keeping the io::Error strings at the public boundary - [packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b-audit/src/segment.rs:718] + evidence: manual read; the three literal strings are created at segment.rs:628-630 and segment.rs:718-747 and matched verbatim at segment.rs:694-699 +- clean: seeds ran: 3 production/40 test, 5 production `let _ =`, 1 test-only `unreachable!`, 4 error enums; the production expects name invariants (identities never empty, bounded identity, literally-built serde values), the `let _ =` sites are deliberate best-effort cleanups (rollback_append segment.rs:273, prune_old segment.rs:302, rotate cleanup segment.rs:470-471, checkpoint repair segment.rs:817), and the four error enums (OperationIdentityError, EvidenceError, AuditRecordError, AuditSinkError) are closed with stable Display codes + +## serde +- clean: seeds ran: 18/26/4/11; all wire structs use `rename_all = "snake_case"` + `deny_unknown_fields`, optionality is correct (`#[serde(default, skip_serializing_if = "Option::is_none")]` on mutation_id/mutation_ordinal, `#[serde(default)]` on backward-compat checkpoint fields), and the four hand-written `Deserialize` impls (OperationIdentity, ZoneId, ZoneOperationKey, AuditRecord) are live admission gates - the recorded-refusal class (docs/explanation/over-engineering-audit-record.md, hand-written Deserialize admission gates); the AuditRecord gate re-verifies the record hash on every read + +## obs +- clean: seeds ran: 0/0/0/5; the 5 `tracing::|log::` hits are `audit_catalog::` substrings (e.g. record_types.rs:1038, 1067), not telemetry; the crate has no println, no tracing/log macros, and no logging dependency - the crate is a library that returns errors instead of logging + +## docs +- d2b-audit#10 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors`/`# Examples` sections exist anywhere in the crate although ~50 `-> Result<` sites include the public API (export_segments_range, AuditRecord::new/verify/zone_operation_key, evidence_from_decision_result, AuditSink::open/append/prune_old, SegmentWriter::open/append, OperationIdentity::derive/parse); failure conditions are described in prose but not under the section a caller scans for - fix: add `# Errors` sections naming the AuditRecordError/AuditSinkError/EvidenceError variants on the Result-returning pub items and `# Examples` on the non-obvious constructors (AuditRecord::new, SegmentWriter::open) - [packages/d2b-audit/src/export.rs:74, packages/d2b-audit/src/record_types.rs:428, packages/d2b-audit/src/reconcile.rs:54, packages/d2b-audit/src/sink.rs:175] + evidence: docs seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; docs seed 3 `-> Result<` = 50 hits; every pub item has a first-sentence doc comment (seed 1 ~145 hits, none undocumented) +- clean: seeds ran: ~145/0/50; module docs present everywhere, every pub item documented with a strong first sentence, no `ignore`d doctests (none exist) + +## perf +- d2b-audit#11 sev=low blast=leaf effort=S verdict=actionable - `scan_chain_state` converts each line with `String::from_utf8(bytes)` then `serde_json::from_str`, allocating a String per record during the open-time scan, while `segment_tail_hash` parses the same JSONL shape with `serde_json::from_slice(&line)`; use `from_slice` here too - fix: replace the from_utf8/from_str pair with `serde_json::from_slice(&bytes)` at sink.rs:386-388 - [packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970] + evidence: perf seed 1/3; static (unmeasured); cold path (startup scan) but a per-record allocation the sibling function already avoids +- clean: seeds ran: 13 format!/9 Vec::new()/~20 to_string(); the production `format!` sites are cold segment-naming and error paths (segment.rs:1007/1028/1039, export.rs:57), the `Vec::new()` sites are bounded readers of unknown size, and the `to_string()` hits are test fixtures and wire rendering; no format! in any loop + +## conc +- clean: seeds ran: 0/1/15/1; the single `Mutex` (sink.rs:66) guards a genuinely synchronous surface with policy-tracked `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` allows, the `AtomicBool` retention_degraded uses the correct Acquire/Release pair (segment.rs:334/343), the `Arc` slots are the test-only FailureInjector, and the `thread_local!` (record_types.rs:658) is the test-support serialization counter; no threads, no unsafe Send/Sync + +## async +- N/A (seeds: 0/0/0/0; no async fn, await, tokio, or spawn in the crate - the whole surface is synchronous by design) + +## unsafe +- N/A (seeds: 0/0/0/1; seeds 1-3 are all zero and the single seed-4 hit is `#![forbid(unsafe_code)]` at lib.rs:3, which per the card does not make the lens applicable; manifest has no unsafe_code setting but the crate-level forbid covers it) + +## ffi +- N/A (seeds: 0/0/0/0; no extern "C", no_mangle, repr(C), catch_unwind, or CStr anywhere; the libc/rustix uses are syscall wrappers inside the crate) + +## macro +- clean: seeds ran: 1/0/0/0; the single `macro_rules!` (impl_redacted_debug, record_types.rs:286) is legitimate impl-per-type generation for the 9 redacting Debug impls (a derive would leak record fields), uses the narrowest fragment specifier `$type:ty`, references no crate paths (no hygiene issue), and is not a proc-macro + +## test +- clean: seeds ran: 50/~200/0/0; no tests/ directory - all 50 tests are in-module `#[cfg(test)]` units covering behavior, not implementation: failure-injection loops over every FailurePoint (segment.rs:1265, sink.rs:561/605), restart/repair/rollback scenarios, idempotent replay, single-writer locking, wire-vector pins (operation.rs:325), redaction assertions (record_types.rs:1275), and a serialization-count behavior probe (sink.rs:516); deterministic timestamps, no network, no `#[ignore]`, no tautological assertions, and no property/snapshot tooling needed for this domain + +## Coverage +- idiom: 3 finding(s) +- own: 1 finding(s) +- type: 1 finding(s) +- api: 2 finding(s) +- err: 2 finding(s) +- serde: clean (seeds ran: 18/26/4/11; admission-gate Deserialize impls are the recorded-refusal class) +- obs: clean (seeds ran: 0/0/0/5; the 5 hits are `audit_catalog::` substrings of `log::`) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 0/1/15/1; synchronous-path Mutex with policy-tracked allows, correct atomic pair) +- async: N/A (seeds: 0/0/0/0; no async surface in the crate) +- unsafe: N/A (seeds: 0/0/0/1; seed 4 alone - `#![forbid(unsafe_code)]` lib.rs:3 - does not make the lens applicable) +- ffi: N/A (seeds: 0/0/0/0; no FFI surface) +- macro: clean (seeds ran: 1/0/0/0; impl_redacted_debug is legitimate impl-per-type generation) +- test: clean (seeds ran: 50/~200/0/0; no tests/ dir, behavior-focused unit mass, no ignored tests) +- supply-note: d2b-session declares `d2b-audit` (packages/d2b-session/Cargo.toml:17, BUILD.bazel:28) but no src/ or tests/ file references `d2b_audit` - directly evidenced unused dependency for lane X1 (census: `d2b_audit|d2b-audit` over packages/d2b-session = 4 hits, all in Cargo.toml/BUILD.bazel) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md new file mode 100644 index 000000000..f5f74c017 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md @@ -0,0 +1,84 @@ +# d2b-broker-composition - d2b-broker-composition +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1634 (excl. src/generated/**; no tests/ dir exists, test lens covers inline #[cfg(test)] modules) | modules: whole crate (lib.rs, main.rs, routing.rs, seam.rs, dependency_surface.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- d2b-broker-composition#1 sev=low blast=leaf effort=S verdict=actionable - `workspace_root` walks up to four parent directories with a `for _ in 0..4` index loop and a mutable `current`, where the bounded walk is an iterator chain - fix: replace the loop with `std::iter::successors(Some(current), |c| c.parent()).take(4).find(|c| c.join("Cargo.toml").is_file() && c.join("packages").is_dir())` - [packages/d2b-broker-composition/src/dependency_surface.rs:136] + evidence: seed `for \w+ in 0\.\.` = 1 hit (dependency_surface.rs:136); the other idiom seed hits are `let mut violations = Vec::new()` (line 165), a side-effect accumulation with early continues where an iterator would obscure the dedup/sort tail - not a finding +- d2b-broker-composition#2 sev=low blast=leaf effort=S verdict=actionable - `state_cell` silences its deliberately unused parameter with `let _ = invocation;` instead of naming it as unused - fix: rename the parameter to `_invocation` and delete the `let _ = invocation;` line (the doc comment's "the invocation's row" is prose, not the parameter name) - [packages/d2b-broker-composition/src/seam.rs:270, packages/d2b-broker-composition/src/seam.rs:274] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1, seed `for \w+ in 0\.\.` = 1; `let _ =` site read at seam.rs:274 +- clean: seeds ran (1/0/1); no hand-written Default/From/PartialEq/Eq/Debug/Clone/Hash impls (all derives), no index loops over collections, naming discipline holds (`as_str` const fn, `is_clean`, no `get_`, free function `report_error` in main.rs) + +## own +- d2b-broker-composition#3 sev=low blast=leaf effort=S verdict=actionable - `audit_crate` iterates `&added` and clones every dependency name into the report fields, though `added` is dead after the loop - fix: consume it with `for name in added { ... report.forbidden_dependencies.push(name); ... report.proc_macro_dependencies.push(name); }` (passing `&name` to `is_proc_macro`), removing both clones - [packages/d2b-broker-composition/src/dependency_surface.rs:251, packages/d2b-broker-composition/src/dependency_surface.rs:255] + evidence: seed `\.clone\(\)` = 12 hits over src (10 dependency_surface.rs, 2 seam.rs test fixtures); sites read in full, `added` has no use after the loop +- d2b-broker-composition#4 sev=low blast=leaf effort=S verdict=actionable - the manifest scan checks `report.forbidden_dependencies.contains(&crate_name.to_string())`, allocating a fresh String per forbidden crate name (8 per audit run) for a membership test - fix: use `report.forbidden_dependencies.iter().any(|name| name == crate_name)` - [packages/d2b-broker-composition/src/dependency_surface.rs:272] + evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 8 hits; the other hits (report construction at 244, error messages at 321/332, `(*crate_name).to_owned()` at 274, `owner_name.to_owned()` at 351) are explainable owned values +- d2b-broker-composition#5 sev=low blast=leaf effort=M verdict=actionable - `dependency_tree` clones every node id into `queue` and `seen` although all ids borrow from `metadata` for the whole traversal - fix: type the traversal as `Vec<&str>` / `BTreeSet<&str>` (`let mut queue = vec![root_id];`, `seen.insert(id)`), leaving the returned `Vec` untouched - [packages/d2b-broker-composition/src/dependency_surface.rs:340, packages/d2b-broker-composition/src/dependency_surface.rs:343] + evidence: seed `\.clone\(\)` = 12 hits; queue/seen sites read; `reachable` keeps `to_owned()` because it is the return value +- clean: no Rc/RefCell/Arc/Arc/Cow (seeds 3-4 = 0); the two seam.rs `invocation.payload.clone()` sites are test-fixture handlers echoing the payload and are explainable + +## type +- clean: seeds ran (0/0/0); the crate declares structs and enums so the lens is applicable, but the refusal taxonomy is already enum-modeled (`RefusalClass`, `RoutingVerdict`, `RoutingRefusal`), `PureTransformClaim` is a private-field newtype with a constructor, and there are no boolean-flag or stringly-typed state fields to collapse + +## api +- clean: seeds ran (24/0/0); all 24 pub items audited - the surface is deliberate and single-path (lib.rs `pub mod` arms with doc comments, the house pattern), no Arc/Rc/Box/RefCell in any public signature, `PureTransformClaim`/`HandlerDeclaration`/`SurfaceReport` are documented data types, and the d2b-broker types in `HandlerDeclaration.handler` are the crate's reason to exist (composition root, publish = false), not a leak + +## err +- d2b-broker-composition#6 sev=low blast=leaf effort=S verdict=actionable - four public/private error returns are bare `Result<_, String>` (`verify_startup_routing`, `audit_crate`, `run_cargo_metadata`, `dependency_tree`), so a future caller that must distinguish failure classes (environment unavailable vs. cargo failure vs. invariant violation) can only string-match - fix: introduce a small typed error enum per module (the seam already owns `RoutingRefusal`; give `dependency_surface` an audit error enum with variants such as `WorkspaceUnavailable`/`CargoFailed`/`InvalidMetadata`) and return it from the cited functions - [packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/dependency_surface.rs:226, packages/d2b-broker-composition/src/dependency_surface.rs:292, packages/d2b-broker-composition/src/dependency_surface.rs:317] + evidence: seed `\.unwrap\(\)|\.expect\(` = 17 hits (13 inside #[cfg(test)] modules - repo false positive; 3 are `expect("static pattern compiles")` on literally-built regexes and 1 is the post-`route_row` invariant expect at seam.rs:238 - all justified); seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0; seed `enum \w*Error` = 0; the String-error shapes were read at the cited sites +- clean: no swallowed Results (`let _ = invocation;` at seam.rs:274 is a deliberately ignored parameter, not a dropped Result); panic policy is sound - the only non-test expect names the invariant the mechanical rule just established + +## serde +- d2b-broker-composition#7 sev=low blast=leaf effort=M verdict=actionable - `run_cargo_metadata` parses cargo's output into `serde_json::Value` and every consumer re-walks it with repeated `.get("packages")`/`and_then(as_array)`/`as_str` chains (`dependency_tree`, `package_name_of_id`, `is_proc_macro`), pushing the parse out of the boundary - fix: derive `Deserialize` on minimal `CargoMetadata`/`Package`/`ResolveNode` shapes and parse once in `run_cargo_metadata`, replacing the Value-walking chains with field access - [packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composition/src/dependency_surface.rs:318, packages/d2b-broker-composition/src/dependency_surface.rs:365, packages/d2b-broker-composition/src/dependency_surface.rs:380] + evidence: seed `serde_json::from_|serde_json::to_` = 1 hit (dependency_surface.rs:308); no serde derives or wire types exist in the crate (seeds 1-3 = 0), and cargo metadata is cargo's contract, not repo wire, so the change is actionable +- clean: no derive(Serialize/Deserialize), no serde attributes, no hand-written Deserialize impls; the single serde_json use is the metadata parse above + +## obs +- clean: seeds ran (6/0/0/9); the 6 `eprintln!` hits are CLI product output (main.rs:34, 50, 54, 58 - operator-facing startup/exit diagnostics, the skill's own carve-out) and test skip notices (dependency_surface.rs:423, seam.rs:625); the 9 remaining hits are `log::` false-matching inside `d2b_broker::catalog::` paths; the lib emits no telemetry and the binary installs the subscriber exactly once at main.rs:24-32 (the sanctioned place); no interpolated message-only events, no secrets in fields + +## docs +- d2b-broker-composition#8 sev=low blast=leaf effort=S verdict=actionable - the five Result-returning public items document their failure conditions in prose but carry no canonical `# Errors` section, so the failure contract is not machine-checkable at a glance - fix: add `# Errors` sections to `register_declared_handlers`, `register_production_handlers`, `verify_startup_routing`, `probe_crate_sources`, and `audit_crate` naming which conditions produce which refusal/error - [packages/d2b-broker-composition/src/seam.rs:157, packages/d2b-broker-composition/src/seam.rs:173, packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/dependency_surface.rs:151, packages/d2b-broker-composition/src/dependency_surface.rs:226] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed `-> Result<` = 9 hits (7 public items plus 2 test helpers); every pub item already has a one-line first sentence and every module has `//!` docs, so only the canonical-section shape is missing + +## perf +- clean: seeds ran (5/4/1); all `format!` hits are cold error construction (seam.rs:205/210 invariant messages, dependency_surface.rs:228/267/269/309 audit diagnostics) and all `Vec::new()` hits are audit tooling with unknown sizes - repo false positives per the card; the single `to_string()` hit (dependency_surface.rs:272) is flagged under own; nothing here is on a hot path and no benchmark exists, so all observations are static (unmeasured) + +## conc +- N/A: seeds (0/0/0/0) all zero; the crate spawns no threads, holds no Mutex/RwLock, uses no atomics or thread_local, and declares no manual Send/Sync + +## async +- clean: seeds ran (17/0/0/4); every hit is inside `#[cfg(test)]` - four `#[tokio::test]` harnesses, two async fixture helpers, and their `.await` calls; the library declares no `async fn` (handlers are `fn` pointers returning d2b-broker's boxed `HandlerFuture`), and `dependency_surface`'s synchronous document/process reads carry the one sanctioned module-level blanket allow (`#![allow(clippy::disallowed_methods)]` at dependency_surface.rs:8, the U1 (d)4 exemption - cited, not re-flagged) + +## unsafe +- N/A: seeds 1-3 (0/0/0) all zero; seed 4 alone hits - `#![deny(unsafe_code)]` at lib.rs:13 and `unsafe_code = "deny"` in the manifest lints table; the crate is on the U1 (d)8 deny list with zero unsafe blocks, consistent with the ledger + +## ffi +- N/A: seeds (0/0/0/0) all zero; no extern "C", no no_mangle, no repr(C)/repr(transparent), no CStr/CString/c_char anywhere in the crate + +## macro +- clean: seeds ran (0/8/0/0); all 8 hits are the `proc_macro` identifier in the dependency-surface audit vocabulary (field `proc_macro_dependencies`, fn `is_proc_macro`), not macro usage - no `macro_rules!`, `syn`/`quote`, `$crate`, or `to_compile_error`/`new_spanned` anywhere; the crate defines and uses no macros beyond std + +## test +- d2b-broker-composition#9 sev=low blast=leaf effort=S verdict=actionable - `an_effectful_handler_offered_to_the_in_broker_table_is_refused_by_the_routing_rule` asserts `format!("{refusal}").contains("forward carrier")`, pinning the routing refusal's Display wording after the `matches!` variant check already pins the contract - fix: delete the Display-string assertion (the variant match is the contract; a wording change must not fail the suite) - [packages/d2b-broker-composition/src/seam.rs:523] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 51 lines; the assertion was read in context - the preceding `matches!` on `RoutingRefusal::Forwarded { class: RefusalClass::Effectful, .. }` is the behavioral check +- d2b-broker-composition#10 sev=low blast=leaf effort=S verdict=actionable - `an_unregistered_admitted_operation_fails_the_startup_invariant` never exercises an admitted-without-handler operation (the committed catalog admits nothing this pass, and the fixture row is refused by `verify_startup_routing` as uncommitted), so the body only asserts the empty-registration happy path and registers a discarded fixture - fix: rename the test to what it asserts (e.g. `the_admitted_set_stays_empty_with_nothing_registered`) and drop the comment's claim that the admitted-without-handler leg is pinned by the fixture row, or restructure to feed a genuinely admitted row when one exists - [packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.rs:733] + evidence: seed `#\[test\]|#\[tokio::test\]` = 31 hits (5 dependency_surface.rs, 11 routing.rs, 15 seam.rs); test body read in full - no assertion involves an admitted row +- clean: 31 tests, all in the right form (unit tests in `#[cfg(test)]` needing private access), expectations human-written literals, deterministic (no network/clock/randomness), no `#[ignore]`, no proptest/insta/rstest (not needed); the environment-dependent `skip_without` early returns are documented skips, and every remaining test can fail on a real regression + +## Coverage +- idiom: 2 finding(s) +- own: 3 finding(s) +- type: clean (seeds ran: 0/0/0; structs and enums declared so the lens is applicable; refusal taxonomy already enum-modeled) +- api: clean (seeds ran: 24/0/0; deliberate single-path surface, no Arc/Rc/Box/RefCell in signatures) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: clean (seeds ran: 6/0/0/9; eprintln hits are CLI output and test skips, remaining hits are `log::`-in-`catalog::` false matches) +- docs: 1 finding(s) +- perf: clean (seeds ran: 5/4/1; all hits cold-path error/audit code, static (unmeasured)) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads, locks, or atomics) +- async: clean (seeds ran: 17/0/0/4; all hits are #[tokio::test] harnesses and helpers; dependency_surface sync reads are the sanctioned blanket allow, U1 (d)4) +- unsafe: N/A (seeds 1-3: 0/0/0; seed 4 only - #![deny(unsafe_code)] lib.rs:13, manifest deny; on the U1 (d)8 deny list, zero blocks) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: clean (seeds ran: 0/8/0/0; all 8 hits are the audit's proc_macro identifier, no macro definitions) +- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md new file mode 100644 index 000000000..08dbb6a5e --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md @@ -0,0 +1,75 @@ +# d2b-broker-p1 - d2b-broker - part 1/7 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11016 (excl. src/generated/**) | modules: runtime.rs:10301-20603 (item-range split; probe/parse helpers, BrokerError audit+response, SIGCHLD reaper, targeted reap, spawn-rollback cleanup, mod tests 11840-20603), ops/usbip_lock.rs, seccomp_compile_tests.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: runtime.rs:10301-20603, ops/usbip_lock.rs, seccomp_compile_tests.rs + +## idiom +- d2b-broker-p1#4 sev=low blast=leaf effort=S verdict=actionable - three near-identical hand-rolled flag parsers `parse_probe_flags`/`parse_stub_flags`/`parse_export_flags` duplicate the same index-loop skeleton and the `--socket-path`/`--test-uid` arms (with `expect_arg` bound-checking) three times - fix: extract one table-driven flag parser (flag spec -> value) that the three wrappers compose, or a shared `parse_common_flags` helper returning `(socket_path, test_uid)` - [packages/d2b-broker/src/runtime.rs:10392, packages/d2b-broker/src/runtime.rs:10418, packages/d2b-broker/src/runtime.rs:10453, packages/d2b-broker/src/runtime.rs:10495] + evidence: seeds `for \w+ in 0\.\.` = 2, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 4; the two index loops (20235, 20457) and the accumulations (13341, 17867, 20234, usbip_lock.rs:302) are side-effectful test loops / required read buffers, not iterator candidates +- clean: seeds ran 2/0/4; checked every hit - index loops and Vec/String accumulation sites are test fixtures with side-effectful bodies or required read buffers, no derive-able hand-written impls in scope + +## own +- clean: seeds ran 137/282/0/0 (clone, to_owned/to_vec/to_string, Rc/RefCell/Arc/Arc, Cow) - sampled: 47 of 419 hits (every 9th); every sampled clone/to_owned is a test-fixture literal, an audit-record snapshot (`audit_context.request_fields.clone()` at 10934), a wire-boundary owned string (11452), or an error-context path capture in usbip_lock.rs; no Rc/RefCell/Arc/Cow anywhere in scope + +## type +- clean: seeds ran 1/0/0; the single `fn validate_` hit is `validate_socket_parent` (runtime.rs:10321), a one-shot CLI startup preflight rather than a parse-once candidate; no boolean-flag soup, no stringly-typed state, no Option-pair smells in scope (TargetedReapOutcome and UsbipLockError are well-shaped enums) + +## api +- d2b-broker-p1#3 sev=low blast=leaf effort=S verdict=actionable - pub fn `acquire_lock` takes `_daemon_uid: u32` (underscore-prefixed) that the body never uses - the record owner is always `Uid::current()`, so every caller (live_handlers.rs:467 plus 8 test sites) supplies a value the function ignores - fix: drop the parameter and update the call sites - [packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467] + evidence: census `acquire_lock(` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 24 hits; seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 5 (all usbip_lock.rs), `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 0 +- clean: seeds ran 5/0/0; the 5 public items are confined to ops/usbip_lock.rs (UsbipLockError, ensure_lock_root, acquire_lock, release_lock, peek_owner) - no Arc/Rc/Box/RefCell or dependency types in public signatures, no re-export arms, runtime.rs range exposes only pub(crate) items + +## err +- d2b-broker-p1#2 sev=medium blast=leaf effort=S verdict=actionable - `UsbipLockError::Io { path: PathBuf, detail: String }` flattens the underlying `io::Error` into its Display string at 12 conversion sites, losing the source chain (os error number and context) a `#[source]` field would keep for diagnosis - fix: change the variant to `Io { path: PathBuf, #[source] source: std::io::Error }` and drop the `detail: e.to_string()` maps - [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84, packages/d2b-broker/src/ops/usbip_lock.rs:98, packages/d2b-broker/src/ops/usbip_lock.rs:110, packages/d2b-broker/src/ops/usbip_lock.rs:122, packages/d2b-broker/src/ops/usbip_lock.rs:128, packages/d2b-broker/src/ops/usbip_lock.rs:134, packages/d2b-broker/src/ops/usbip_lock.rs:138, packages/d2b-broker/src/ops/usbip_lock.rs:142, packages/d2b-broker/src/ops/usbip_lock.rs:162, packages/d2b-broker/src/ops/usbip_lock.rs:174, packages/d2b-broker/src/ops/usbip_lock.rs:179, packages/d2b-broker/src/ops/usbip_lock.rs:187] + evidence: seed `enum \w*Error` = 1 (UsbipLockError); `\.unwrap\(\)|\.expect\(` = 518 - sampled: 48 of 518 hits (every 11th), all test-code expects with meaningful messages; production band 10301-11840 has 0 unwrap/expect; `let _ = |\.ok\(\);` = 62 (3 production sites at 10540/11491/11587 are deliberate: cfg-gated param, OnceLock set, best-effort cleanup); `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 50 (all tests plus the justified unix-only `Component::Prefix` unreachable at usbip_lock.rs:284) +- clean: seeds ran 518/62/50/1 - panic policy is sound in production code (zero unwrap/expect/panic in 10301-11840); the only taxonomy issue is the Io-variant source-chain loss recorded above + +## serde +- clean: seeds ran 0/0/0/13; no serde derives or hand-written Deserialize impls in scope - the 13 serde_json hits are test round-trips and redaction assertions (serialObserved present, raw serial/busid/key_hex absent) plus the probe CLI's stdout rendering at 10377; no wire type crosses a boundary in this part + +## obs +- clean: seeds ran 5/0/0/35; the two println!/eprintln! hits in runtime.rs are the layer1-bootstrap probe CLI's product output (10375) and a test skip message (15893), the three seccomp_compile_tests eprintln! sites are test skip notices; all 12 production tracing events (10822-11818) carry named fields (operation, error_kind, detail, runner_id, error, pid, exit_status) with no interpolated-message events and no secrets + +## docs +- d2b-broker-p1#5 sev=low blast=leaf effort=S verdict=actionable - the four Result-returning public fns in ops/usbip_lock.rs (`ensure_lock_root`, `acquire_lock`, `release_lock`, `peek_owner`) document failure conditions only in prose and carry no `# Errors` canonical section, which the docs contract wants on every Result-returning item - fix: add `# Errors` sections naming the returned variants (LockAlreadyHeld, OwnerMismatch, Io) - [packages/d2b-broker/src/ops/usbip_lock.rs:81, packages/d2b-broker/src/ops/usbip_lock.rs:90, packages/d2b-broker/src/ops/usbip_lock.rs:171, packages/d2b-broker/src/ops/usbip_lock.rs:316] + evidence: seed `-> Result<` = 17 (14 runtime + 3 usbip), `/// # (Examples|Errors|Panics|Safety)` = 0, `^\s*pub (fn|struct|enum|trait|const|type)` = 5; all 5 public items have one-line doc summaries; runtime.rs range items are pub(crate) with adequate docs +- clean: seeds ran 5/0/17 - every public item in scope has a one-line doc comment; the only gap is the missing `# Errors` sections recorded above + +## perf +- clean: seeds ran 89/57/29 - all format!/Vec::new/to_string hits are cold error-message construction (RunError/BrokerError/UsbipLockError detail strings), test fixtures, or wire-boundary owned strings; production band 10301-11840 has zero Vec::new() and zero hot-loop allocation; static (unmeasured) + +## conc +- clean: seeds ran 10/4/0/0; all 14 hits are test-only - std::thread::spawn in harnesses, test Mutexes (FakeDispatchBackend, RegistryTestGuard's LazyLock with `poisoned.into_inner()`), and std::thread::sleep polling loops with documented convergence; no atomics, no unsafe Send/Sync impls, no shared-state design issues in production code + +## async +- d2b-broker-p1#1 sev=high blast=wide effort=S verdict=actionable - `cleanup_spawned_runner_after_failure` performs a blocking `waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED)` (no WNOHANG) at runtime.rs:11815, and is called directly from async `spawn_process` (kernel_ops.rs:919, 955) on the broker's tokio executor; a child stuck in uninterruptible sleep blocks that worker indefinitely, and every sibling reap path in this file is explicitly WNOHANG - fix: bounded WNOHANG poll loop (or spawn_blocking) that preserves the no-live-process-left-behind guarantee; route review-pass - [packages/d2b-broker/src/runtime.rs:11815, packages/d2b-broker/src/kernel_ops.rs:919, packages/d2b-broker/src/kernel_ops.rs:955] + evidence: seeds `async fn|async move|\.await` = 60, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 1, `tokio::sync::(Mutex|RwLock|Notify)` = 5, `#\[tokio::(main|test)\]|Runtime::block_on` = 4; the WNOHANG discipline is documented at runtime.rs:11486-11529 and applied at 11549/11656; no async-gate-allow marker covers this site; kernel_ops.rs:741 `async fn spawn_process` is the enclosing caller +- clean: seeds ran 60/1/5/4 - reaper loop, targeted reap, and notification paths hold no guard across .await and use non-blocking probes; the single blocking-waitid rollback path is the finding above; the block_on at 11498 is startup signal registration (sanctioned) + +## unsafe +- clean: seeds ran 5/5/16 - all 5 unsafe blocks live in seccomp_compile_tests.rs (can_set_no_new_privs, two forks, two child closures) and each carries a `// SAFETY:` comment stating the invariant; the 3 `#[allow(unsafe_code)]` sites are on the recorded exception list (U1 d8); the 16 transmute/from_raw/MaybeUninit/zeroed hits are safe nix `Pid::from_raw` constructors, not unsafe operations + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no extern "C"/no_mangle/catch_unwind/repr(C)/CStr surface in this part) + +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!/proc-macro/$crate/to_compile_error definitions in this part) + +## test +- clean: seeds ran 123/560/0/0 (#[test]/#[tokio::test], assert_eq!/assert_ne!/assert!, proptest!/insta::assert/rstest, #[ignore]) - sampled: 56 of 123 test fns (every 3rd); the suite asserts observable behavior (wire codes, audit records, redaction, rollback semantics, restart-replay refusal, rate-limiter fail-closed caps) with human-written expectations, table-driven cases with failure messages, injected time (`check_at(now)`), and progress-based waits with documented convergence instead of fixed sleeps; no test that cannot fail, no network, no #[ignore] + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: 137/282/0/0; sampled 47 of 419) +- type: clean (seeds ran: 1/0/0) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 0/0/0/13) +- obs: clean (seeds ran: 5/0/0/35) +- docs: 1 finding(s) +- perf: clean (seeds ran: 89/57/29) +- conc: clean (seeds ran: 10/4/0/0) +- async: 1 finding(s) +- unsafe: clean (seeds ran: 5/5/16) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary surface in this part) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions in this part) +- test: clean (seeds ran: 123/560/0/0; sampled 56 of 123 test fns) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md new file mode 100644 index 000000000..d28b5bd13 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md @@ -0,0 +1,100 @@ +# d2b-broker-p2 - d2b-broker - part 2/7 +Baseline: 6ebdd4cec | LOC audited: 11074 (runtime.rs:1-10300; 10300 lines; src/ops/gpu.rs (463); src/ops/modprobe.rs (311); none carries src/generated/**). | modules: runtime (part 1/2 of the item split), ops::gpu, ops::modprobe +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: runtime.rs:1-10300, src/ops/gpu.rs, src/ops/modprobe.rs + +## idiom +- d2b-broker-p2#1 sev=low blast=leaf effort=S verdict=actionable - active_locked_usbip_bind_intents builds out with a let-mut push loop over the resolver's intent-id iterator, where a filter_map().collect() pipeline would carry the same filtering - fix: replace the loop at runtime.rs:10132-10147 with `resolver.usbip_bind_intent_ids().filter_map(|id| resolver.find_usbip_bind_intent(id).map)...))).collect::>()`, keeping the two continue conditions as filter predicates - [packages/d2b-broker/src/runtime.rs:10132] + evidence: seeds: `for w+ in 0..` = 2;`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0;`let mut w+ = (String|Vec)::new()` = 5. The other index-loop hit (runtime.rs:1004) has a per-iteration thread-spawn side effect, so the plain-for rule is the right shape; the while-let async fs-entry loops (5663, 8529, 10113) collect over a fallible async stream, not an iterator-pipeline cleanup. + + + + +## own +- clean: seeds ran: 144/320/0/0. clone seed: 144 hits (142 runtime + 2 modprobe). to_owned/to_vec/to_string seed: 320 hits (311 runtime + 2 gpu + 7 modprobe). Rc/RefCell/Arc/Arc seed: 0; Cow seed: 0. Read all 144 clone hits plus a deterministic sample of the to_* hits (every 7th =45 of 320). Every clone/to_owned inspected constructs an owned wire response, audit record, registration, or intent struct whose value must outlive a borrow, or is an accepted Arc at a spawn/static boundary; the two gpu/modprobe to_owned hits are test-fixture argv lists; no explainable-but-avoidable copy found. + + +## type +- clean: seeds ran: 22/0/0 (`fn validate_w+|fn check_w+` = 22 hits: 18 runtime + 4 gpu;`is_w+: bool|w+_flag: bool` = 0;`(mode|kind|state): String` = 0). The validate fns are wire-admission and-domain-shape gates over contract-pinned &str ids and SpawnRunnerPlan/GpuLaunchRequest values; no boolean-flag soup, Option-pair smell, or string-typed state exists in the three files; a parsed-newtype alternative would be a wire/contract change, not a lane-local refactor. + + + +## api +- d2b-broker-p2#2 sev=medium blast=leaf effort=M verdict=actionable - the GPU and modprobe op modules rise to the crate's public surface through pub mod ops + pub mod gpu/pub mod modprobe (ops/mod.rs:47-48), yet the GPU types (GpuBrokerRole, GpuDeviceClass, GpuOpaqueIdentity, GpuLaunchRequest, GpuProcessObservation, GpuBrokerError)and modprobe's(ModprobeAuditRecord, ModprobeDecision, AllowlistRow, ModprobeBackend, RecordingBackend, dispatch, live_modprobe_if_allowed)have zero consumers outside d2b-broker itself:live_handlers uses only the two gpu validate fns and runtime uses only live_modprobe_if_allowed, all same-crate - fix: narrow the module decls to pub(crate)(ops/mod.rs:47-48), or make the item-level pub to pub(crate)in gpu.rs and modprobe.rs; same-crate call sites are unaffected - [packages/d2b-broker/src/ops/gpu.rs:13, packages/d2b-broker/src/ops/gpu.rs:24, packages/d2b-broker/src/ops/gpu.rs:41, packages/d2b-broker/src/ops/gpu.rs:63, packages/d2b-broker/src/ops/gpu.rs:177, packages/d2b-broker/src/ops/gpu.rs:190, packages/d2b-broker/src/ops/modprobe.rs:32, packages/d2b-broker/src/ops/modprobe.rs:42, packages/d2b-broker/src/ops/modprobe.rs:61, packages/d2b-broker/src/ops/modprobe.rs:67, packages/d2b-broker/src/ops/modprobe.rs:76, packages/d2b-broker/src/ops/modprobe.rs:99, packages/d2b-broker/src/ops/modprobe.rs:165, packages/d2b-broker/src/ops/mod.rs:47, packages/d2b-broker/src/ops/mod.rs:48] + evidence: census:`GpuLaunchRequest|GpuBrokerError|GpuOpaqueIdentity|GpuDeviceClass|GpuBrokerRole|GpuProcessObservation|ModprobeBackend|ModprobeAuditRecord|ModprobeDecision|AllowlistRow|RecordingBackend|ops::gpu|ops::modprobe` over packages, tests, nixos-modules, docs/reference, labs:code hits outside the defining files = 3 (live_handlers.rs:2903, live_handlers.rs:2957, runtime.rs:3722), all inside the same crate; cross-crate code users = 0; d2b-core's/d2b-host's/docs-references are prose only. + + + +## err +- d2b-broker-p2#3 sev=high blast=wide effort=S verdict=actionable - DispatchAuditContext::from_request panics the broker on a malformed authoritative audit join: both CanonicalAuditDigest::parse(zone_id.expect)...) at runtime.rs:2419-2422 parse data that came straight out the wire (request.authoritative_audit_join() returns the strings unchecked), while the sibling from_request_with_join (runtime.rs:2440-2444) converts the same parse failure to BrokerError::Protocol - a remote caller can crash the daemon - fix: replace both expect("authoritative ... digest") calls with `.map_err(|_| BrokerError::Protocol("audit zone identity invalid".to_owned()))?;`, mirroring runtime.rs:2442-2444, keeping the panic out of the wire path - [packages/d2b-broker/src/runtime.rs:2419, packages/d2b-broker/src/runtime.rs:2422] + evidence: seed `\.unwrap\(\)|\.expect\(` = 13 over the lane (11 runtime + 2 gpu; both gpu hits are in mod tests), of which 2419/2422 are the only inputs crossing a caller-controlled boundary; the other unwrap/expect hits are startup/runtime-build/catalog invariants (runtime.rs:1023, 3169, 5112-5118, 7073, 7093, 7173) or best-effort ignores (`let _ =` at runtime.rs:1038, 1200,1421,1461,1579,1613,1641,6432-6434)and the 16 `let _ = |\.ok\(\);` seed hits are all deliberate best-effort audit/cleanup/param sites; gpu's unreachable! at gpu.rs:321 is a closed-enum invariant panic, correct per the panic policy;`enum w*Error` = 3 (RunError, GpuBrokerError; BrokerError is pub(crate) + + +## serde +- clean: seeds ran: 3/2/0/8. The modprobe wire shapes (ModprobeAuditRecord, ModprobeDecision, AllowlistRow)use serde(rename_all = "camelCase") or "kebab-case" on the type, not per field; no hand-written Deserialize impl exists; the 8 serde_json::from_/to_ sites either surface errors as typed BrokerErrors (runtime.rs:1481, 2551, 4976, 9752)or are best-effort optional audit fields that explicitly fall back (to_value().ok() at runtime.rs:3334, 3364, 3725; from_slice::().ok() at 3563 for a qemu dump probe), none silently swallowing wire input the caller must know about. + + + +## obs +- d2b-broker-p2#4 sev=low blast=leaf effort=M verdict=actionable - three message-only tracing events carry no named fields:the child-reap buffer-busy warnings at runtime.rs:6023 and runtime.rs:6036 (a dropped notification / an abandoned drain), and the dispatch-pool panic error at runtime.rs:1016 (request body panicked), each has dynamic identity it could expose (the dropped ChildReapedNotification, or which operation the panicking job covered)- fix: convert to events with named fields:tracing::warn!(dropped = ?notif, "child_reap_buffer busy"), include buffer = "child_reap_buffer" on the empty-drain warn,and propagate an operation span or captured job context into the pool's tracing::error! - [packages/d2b-broker/src/runtime.rs:6023, packages/d2b-broker/src/runtime.rs:6036, packages/d2b-broker/src/runtime.rs:1016] + evidence: seed `(info|debug|warn|error|trace)!\("` = 2 hits (runtime.rs:6023, 6036); the no-fields multiline tracing::error! at runtime.rs:1016 sits inside the tracing::|log:: count = 33; all other tracing events in the lane carry named fields(error, notify_result, load_outcome, runner_id, etc.); the `//!`-documented use tracing::info/warn at 45-46 undermines neither finding. + + + +## docs +- d2b-broker-p2#5 sev=medium blast=family effort=S verdict=actionable - the broker's central runtime module has no //! module doc,and its five process-entry public items (ServerConfig, BrokerMode, RunError, parse_command, run)lack any doc comment, even though they form the public API the composition binary (d2b-broker-composition/src/main.rs:3, 47-60)and integration tests (tests/profile_separation.rs:1, 22-33)match on - fix: add a one-line module doc atop runtime.rs(serve/socket/audit contract)and one-line first-sentence doc comments to ServerConfig, BrokerMode, RunError, with # Errors on run/parse_command, which return Result),keeping the comments caller-contracts, not implementation narration - [packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b-broker/src/runtime.rs:375, packages/d2b-broker/src/runtime.rs:398, packages/d2b-broker/src/runtime.rs:565, packages/d2b-broker/src/runtime.rs:799] + evidence: docs seeds:`^\s*pub (fn|struct|enum|trait|const|type)` = 34 (10 runtime + 19 gpu + 5 modprobe), documentation state checked per hit;`/// # (Examples|Errors|Panics|Safety)` = 0;`-> Result<` = 104. The gpu/modprobe public items largely do carry docs; the runtime entry set listed is the documented-by-fields-only surface (ServerConfig's fields each have ///,but the struct/enum and the four entry fns none) + + + +## perf +- clean: seeds ran: 124/33/91, plus gpu/modprobe 3 sites (2/0/1)=total 251 hits. Sampled: read 42 of 251 hits (every 6th). Every sampled format!/to_string/Vec::new site is an error path (BrokerError::LiveHandler(format!)...)), an audit-record/rendering field (requested:/resolved: rows, display().to_string(), serde_json fallbacks), a one-shot process/startup diagnostic (sd_notify msg, nft table render),or an empty-case/common struct allocation(Vec::new(), HashMap::new()in registries, response_fds)-none sits in a per-request hot loop exceeding a single small allocation; no perf-budget claim is made (static, unmeasured. + + + +## conc +- clean: seeds ran: 2/12/3/0. The two std::thread hits (runtime.rs:1008, 1069)are the sanctioned dedicated bounded-worker DispatchPool (threads spawned once at startup, blocking_recv on the worker's own thread per plan R4)and available_parallelism() sizing; the 12 Mutex< hits are all tokio::sync::Mutex registries/limiters with the documented try_lock-on-sync-worker posture(`// Non-blocking try-lock (plan U8)` at 7540/7556/6022/6035,orthe rate-limiter lock_sync comment at 1663-1666); the 3 Atomic/Ordering hitsform one AtomicUsize round-robin counter with Ordering::Relaxed(a counter nobody synchronises on),the weakest correct ordering; no thread_local!,no unsafe impl Send/Sync. + + + +## async +- d2b-broker-p2#6 sev=medium blast=wide effort=S verdict=policy-confirmed - the USB-audit serial HMAC key path runs blocking filesystem syscalls inside async fns on broker executor threads:usb_audit_serial_hmac_keyring calls the sync ensure_usb_audit_serial_hmac_key_dir (two path_safe::ensure_dir stat/mkdir chains)per call,and every bind op with a device serial loads each key file through a sync nix::fcntl::open plus tokio::fs::File::from_std read,and the create leg performs sync create_file_at_safe/fchmod/rustix::fs::fsync(dir_fd) at runtime.rs:7722-7729; none of these raw calls sits on the disallowed-methods list,so the sync-in-async class escapes the existing gate - fix: extend the already-used tokio::fs::File::from_std)..).sync_all().await pattern(orthe bounded-worker shape per plan R4)to the dir-fd fsync and the key-dir ensure/open legs, per U1 ledger 2,which names tokio::fs asthe sanctioned replacement for these blocking calls,so the verdict is policy-confirmed - [packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages/d2b-broker/src/runtime.rs:7584, packages/d2b-broker/src/runtime.rs:7696, packages/d2b-broker/src/runtime.rs:7722] + evidence: async seeds:`async fn|async move|\.await` = 286 (runtime 267 + modprobe 19);`tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 1 (tokio::spawn at runtime.rs:1398,a spawn-bound connection task);`tokio::sync::(Mutex|RwLock|Notify)` = 20,all with the documented plan-U8 try_lock/Notify usage;`#\[tokio::(main|test)\]|Runtime::block_on` = 12 (gpu/modprobe test fns; runtime's Runtime::block_on sites at 1221, 1528, 1541 carry inline allows with sanctioned reasons, not re-flagged + + + +## unsafe +- clean: seeds ran: 0/0/5/0 (`unsafe \{|unsafe fn|unsafe impl|unsafe extern` = 0;`// SAFETY:` = 0;`transmute|from_raw|MaybeUninit|mem::zeroed` = 5;`unsafe_code` = 0). The five from_raw-pattern hits (runtime.rs:31, 5141, 6045, 7657, 7729)all name crate::sys::owned_fd_from_raw (the sanctioned syscall-boundary helper in ledger (d) 8)or io::Error::from_raw_os_error (safe std); no unsafe block, fn, impl, or extern exists anywhere inthe three files,consistent with the enumerated exception set (p5's sys.rs/p4's disk_init.rs hold the crate's unsafe sites, not here). + + + +## ffi +- clean: seeds ran: 0/1/0/0. The single catch_unwind hit (runtime.rs:1015)isthe dispatch-pool's process-supervision panic boundary, not an FFI surface:each pool job is caught so a panicking handler costs its own connection andthe worker keeps serving (documented at runtime.rs:1012-1018),the card's "is it a boundary?" question resolves to yes for that purpose; no extern "C", no repr(C)/transparent, no CStr/c_char in the lane. + + + +## macro +- clean: seeds ran: 2/0/0/0. The two macro_rules! definitions (runtime.rs:3087, 3092)are write_decision_op_record! and write_success_op_record!,variadic arg-forwarders that append the contextual audit_context tothe impl fns for dozens of callsites; the genuine variadic-interface case the skill names; the $($args:tt)* fragment isthe narrowest that can forward arbitrary trailing argument lists tothe *_impl fns; no proc-macro, no $crate, no to_compile_error/new_spanned machinery exists inthe lane. + + + +## test +- clean: seeds ran: 67/240/0/0 (`#\[test\]|#\[tokio::test\]` = 67:gpu 3 + modprobe 6 + tests 58; runtime's 1 hit is a comment mention;`assert_eq!\(|assert_ne!\(|assert!\(` = 240:runtime/gpu/modprobe 1/8/12 + tests 219;`proptest!|insta::assert|rstest` = 0;`#\[ignore\]` = 0). Sampled: read 44 of 219 assert rows in tests/** (every 5th) plus both in-file test modules in full. The gpu/modprobe tests assert on error variants (GpuBrokerError::WrongPrincipal,ModprobeDecision::*)and recorded backend effects, not Display strings/implementation; the sampled tests/** asserts target wire payloads (json["kind"], PROTOCOL_VERSION, retired-variant lookup),cross-process state(host.pid() != guest.pid(),reconciler taps/pidfds),and error kinds(STALE_WIRE_VERSION,error_kind,w3-pending-typed-wire)-behavior-level assertions,mostly with failure-message context where tables loop; no test-that-cannot-fail observed. + + + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: 144/320/0/0; sampled: all 144 clone hits + 45 of 320 to_* hits) +- type: clean (seeds ran: 22/0/0) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: clean(seeds ran: 3/2/0/8) +- obs: 1 finding(s) +- docs: 1 finding(s) +- perf: clean(seeds ran: 124/33/91; sampled: read 42 of 251 hits) +- conc: clean(seeds ran: 2/12/3/0) +- async: 1 finding(s) +- unsafe: clean(seeds ran: 0/0/5/0) +- ffi: clean(seeds ran: 0/1/0/0) +- macro: clean(seeds ran: 2/0/0/0) +- test: clean(seeds ran: 67/240/0/0; sampled: read 44 of 219 tests/** asserts) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md new file mode 100644 index 000000000..22b269c18 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md @@ -0,0 +1,83 @@ +# d2b-broker-p3 - d2b-broker - part 3/7 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11019 (excl. src/generated/**) | modules: live_handlers, state_cells, ops::{store_sync, usbip_host, storage_contract, pidfd, sysctl, mod} +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 3/7 (whole files; no range splits) + +## idiom +- clean: seeds `for \w+ in 0\.\.`=2 / `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=3 / `let mut \w+ = (String|Vec)::new\(\)`=6; every hit is justified - the two index loops are test-only (state_cells.rs:1511, store_sync.rs:737), the hand-written impls are required (io::Error has no PartialEq; RetentionPolicy/FakePidfdSpawner Defaults carry magic values a derive would lose), and the Vec::new accumulation loops (live_handlers.rs:607,2156,2299; storage_contract.rs:229) are early-exit/error-return ancestor walks where iterator pipelines do not fit. + +## own +- d2b-broker-p3#1 sev=low blast=leaf effort=S verdict=actionable - `RealPidfdSpawner::spawn` clones the whole payload argv into a never-read `_argv` binding on every spawn - fix: delete `let _argv = payload.argv.clone();` (keep the explanatory comment; the placeholder child needs no argv) - [packages/d2b-broker/src/ops/pidfd.rs:210] + evidence: seed `\.clone\(\)` = 53 hits; site read shows the binding is never read after the clone. + +## type +- d2b-broker-p3#2 sev=low blast=leaf effort=M verdict=needs-contract - `StorageContractError::Refused { reason: String }` carries a closed set of refusal slugs ("storage-path-parent-dir-refused", "storage-path-outside-owned-roots", "storage-path-escapes-owned-root", ...) that tests string-match (storage_contract.rs:380-403) and audit records emit - fix: introduce a `RefusalReason` enum (serde lowercase) so the slug set is exhaustive and a new refusal cannot typo; wire/audit-visible strings make this needs-contract - [packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_contract.rs:380] + evidence: type seeds `fn validate_\w+|fn check_\w+`=8 / `is_\w+: bool|\w+_flag: bool`=0 / `(mode|kind|state): String`=0; slug literals cross-referenced in the module's own tests. +- d2b-broker-p3#3 sev=low blast=leaf effort=M verdict=needs-contract - `reload_behavior` is a stringly-typed wire value re-validated at every call site (`validate_nm_reload_behavior` here and the remove path in ops/nm.rs, per the doc at live_handlers.rs:288-290) instead of parsed once at the bundle boundary - fix: parse `reloadBehavior` into an enum in the bundle resolver so both arms branch on the parsed type and a hand-declared typo fails at resolution; `reloadBehavior` is pinned in docs/reference/schemas/v1/host.json:409 and v2/host.json:543, so needs-contract - [packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362] + evidence: type seed `fn validate_\w+` = 8 hits; site read of the validator and its two call sites. + +## api +- d2b-broker-p3#4 sev=medium blast=leaf effort=S verdict=actionable - `ops::sysctl` exports a dead pub surface: `apply_sysctl_intents` (sysctl.rs:84), `ApplySysctlRequest` (16), `with_default_root` (23) and `intent_to_proc_path` (76) are referenced only inside sysctl.rs (its own tests at 258/283); the production entry point is `apply_with_readback` - fix: delete the dead trio (or demote to `pub(crate)` and keep only what tests need) - [packages/d2b-broker/src/ops/sysctl.rs:16, packages/d2b-broker/src/ops/sysctl.rs:84] + evidence: census: `apply_sysctl_intents` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file (the defining file only); `with_default_root` = 1 file; `intent_to_proc_path` = 1 file. + +## err +- d2b-broker-p3#5 sev=low blast=leaf effort=S verdict=actionable - `CellStore` panic policy is inconsistent: `in_memory()` (state_cells.rs:348) and `with_retention()` (360) `.expect()` on `spawn_owner` failure while the sibling `open()` (353) propagates `CellStoreError::Io` from the same call - fix: make `with_retention` return `Result` (its callers are tests), and have `in_memory` keep its infallible contract only with an `expect` that names the startup-precondition rationale - [packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360] + evidence: seed `\.unwrap\(\)|\.expect\(` = 274 hits (5 in production zones; the rest are cfg(test)); site read of spawn_owner and its three callers. + +## serde +- d2b-broker-p3#6 sev=low blast=leaf effort=S verdict=actionable - `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in `load()` (state_cells.rs:924-931), while the in-process `CellOutcome` enum already exists - fix: derive Serialize/Deserialize on a wire enum (`#[serde(rename_all = "lowercase")]` over `CellOutcome` or a dedicated `DurableOutcome`) and delete the string match; the serialized shapes "unknown"/"completed" stay identical, so no DURABLE_VERSION bump is needed - [packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924] + evidence: seeds `derive\([^)]*(De)?[Ss]erialize`=2 / `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=4 / `impl .*Deserialize.*for`=0 / `serde_json::from_|serde_json::to_`=9. + +## obs +- d2b-broker-p3#7 sev=low blast=leaf effort=S verdict=actionable - `retry_acl_grant` interpolates its `label` into the message instead of a named field: `tracing::debug!(error = %err, "{label} ACL refresh not ready yet")` and `tracing::warn!("{label} ACL refresh timed out")`, with no enclosing span carrying it, so the refresh kind is not queryable - fix: emit `label = %label` as a field and keep the message interpolation-free - [packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:2539] + evidence: seed `(info|debug|warn|error|trace)!\("` = 1 hit (plus the sibling debug! at 2532 read in context); obs1 `\bprintln!\(|\beprintln!\(` = 3 (all cfg(test) skip notices). + +## docs +- d2b-broker-p3#8 sev=low blast=leaf effort=S verdict=actionable - pub types `UsbipHostInspectionError` (usbip_host.rs:17), `UsbipDriverBinding` (153) and `UsbipHostDeviceInspection` (160) carry no doc comment at all on a crate with a lib target - fix: add one-line docs (and field docs for the inspection struct) - [packages/d2b-broker/src/ops/usbip_host.rs:17, packages/d2b-broker/src/ops/usbip_host.rs:153, packages/d2b-broker/src/ops/usbip_host.rs:160] + evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)`=59 / `/// # (Examples|Errors|Panics|Safety)`=0 / `-> Result<`=116; site read of the three items. +- d2b-broker-p3#9 sev=low blast=leaf effort=S verdict=actionable - pub types `ApplySysctlOutcome` (sysctl.rs:32), `ApplySysctlError` (40) and `ApplyWithReadbackError` (113) and the pub method `with_default_root` (23) are undocumented - fix: add one-line docs per item - [packages/d2b-broker/src/ops/sysctl.rs:32, packages/d2b-broker/src/ops/sysctl.rs:40, packages/d2b-broker/src/ops/sysctl.rs:113] + evidence: docs seeds 59/0/116; site read of the items. +- d2b-broker-p3#10 sev=low blast=leaf effort=S verdict=actionable - pub enum `StorageContractError` (storage_contract.rs:21) has no doc comment - fix: one-line doc naming the refusal/invalid/Io contract - [packages/d2b-broker/src/ops/storage_contract.rs:21] + evidence: docs seeds 59/0/116; site read. +- d2b-broker-p3#11 sev=low blast=leaf effort=S verdict=actionable - pub methods `PidfdMethod::as_str` (pidfd.rs:112), `StartTime::matches` (127), `RealPidfdSpawner::new` (191) and `AuditDecision::as_str` (ops/mod.rs:164) are undocumented - fix: one-line docs per method - [packages/d2b-broker/src/ops/pidfd.rs:112, packages/d2b-broker/src/ops/pidfd.rs:191, packages/d2b-broker/src/ops/mod.rs:164] + evidence: docs seeds 59/0/116; site read of the items. + +## perf +- d2b-broker-p3#12 sev=low blast=leaf effort=M verdict=actionable - `CellStore` partial-key lookups scan the whole record map: `contains` (state_cells.rs:470), `payload` (488), `remove` (506), `keys` (524) and `clear` (541) iterate `records: BTreeMap` filtering on (cell, invocation_id) because the principal is a key component, making every op O(n) where the durable file already uses the nested cell -> invocation layout - fix: mirror the durable layout in memory (cell -> invocation -> record, principal inside the record) so lookups become O(log n); static (unmeasured) - [packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, packages/d2b-broker/src/state_cells.rs:524] + evidence: static (unmeasured); perf seeds `format!\(`=185 (production hits are error paths) / `Vec::new\(\)|...`=31 / `\.to_string\(\)`=53. + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope`=2 / `\bMutex<|\bRwLock<`=3 / `Atomic\w+|Ordering::`=16 / `thread_local!|unsafe impl (Send|Sync) for`=0; all concurrency is the sanctioned R4 dedicated bounded worker (state_cells.rs:343,583,606,901 `#[allow)..., reason = "dedicated bounded worker per plan R4")]` sync_channel + owner thread with the documented poison latch), and the remaining hits are cfg(test) scopes/atomics (state_cells.rs:1509, usbip_host.rs:489-551, live_handlers.rs:5605). + +## async +- d2b-broker-p3#13 sev=medium blast=leaf effort=M verdict=actionable - the initial ACL-grant attempt runs a blocking setfacl fork/exec on the executor worker: `refresh_spawn_runner_acls` (async, live_handlers.rs:1802) -> `refresh_obs_vsock_acl` -> `grant_obs_vsock_acl_once` (1614) -> `setfacl_fd_safe` -> `setfacl_fd_safe_op_classed` (1416) -> `sys::pidfd_sys::run_setfacl_op_on_fd`, while the retry paths (`spawn_obs_vsock_acl_retry` 1658, `retry_acl_grant` 2519) correctly defer the same shellout to `background.dispatches.run` on the bounded dispatch pool - fix: route the initial attempt through `dispatches.run` too (or make the refresh fns async and use the `setfacl_verified_device` async-shellout shape), matching the documented "kernel-path step on the bounded dispatch pool" design; bounded short shellout per spawn, so medium not high - [packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:1802] + evidence: async seeds `async fn|async move|\.await`=367 / `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(`=0 / `tokio::sync::(Mutex|RwLock|Notify)`=2 / `#\[tokio::(main|test)\]|Runtime::block_on`=60; call-chain read; the store_sync.rs:666 flock site is a sanctioned per-site allow ("synchronous path", U1 ledger 4) and the state_cells worker is the sanctioned R4 boundary, both left unflagged. + +## unsafe +- clean: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0 / `// SAFETY:`=0 / `transmute|from_raw|MaybeUninit|mem::zeroed`=3 / `unsafe_code`=3; the three `from_raw` hits are safe nix constructors (`Uid::from_raw`/`Gid::from_raw` at storage_contract.rs:279,307, `Pid::from_raw` in a test at live_handlers.rs:5387) and the `unsafe_code` hits are doc prose (pidfd.rs:20,176,208); no unsafe block exists in this partition - all unsafe lives in sys.rs (d2b-broker-p5's scope). + +## ffi +- clean: seeds `extern "C"|no_mangle|unsafe\(link_section`=0 / `catch_unwind`=1 / `repr\(C\)|repr\(transparent\)`=0 / `CStr|CString|c_char`=1; the `catch_unwind` at state_cells.rs:635 is the documented panic-isolation boundary of the cell-store poison latch, not a foreign-caller boundary, and the `CString` hit is doc prose (live_handlers.rs:2857); no FFI surface exists in this partition. + +## macro +- N/A (seeds: `macro_rules!`=0 / `proc_macro|syn::|quote!`=0 / `\$crate`=0 / `to_compile_error|new_spanned`=0 all zero; no macro definitions or proc-macro machinery in the lane files). + +## test +- d2b-broker-p3#14 sev=low blast=leaf effort=S verdict=actionable - `reconciliation_refuses_start_time_drift` (tests/pidfd_handoff_scm_rights.rs) asserts the Display string (`msg.contains("start-time drifted")`) instead of the error variant, while the sibling real-spawner test matches `PidfdOpError::ReconciliationStartTimeMismatch` - fix: match the variant like tests/pidfd_real_spawner.rs:66-70 - [packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90] + evidence: test seeds over lane src: `#\[test\]|#\[tokio::test\]`=114 / `assert_eq!\(|assert_ne!\(|assert!\(`=351 / `proptest!|insta::assert|rstest`=0 / `#\[ignore\]`=0; over tests/: 58/219/0/0; the in-module suites (state_cells, store_sync, usbip_host, storage_contract, sysctl) are invariant-focused and fail-closed, no other findings. + +## Coverage +- idiom: clean (seeds ran: 2/3/6) +- own: 1 finding(s) +- type: 2 finding(s) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: 1 finding(s) +- docs: 4 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 2/3/16/0) +- async: 1 finding(s) +- unsafe: clean (seeds ran: 0/0/3/3) +- ffi: clean (seeds ran: 0/1/0/1) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions in lane files) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md new file mode 100644 index 000000000..1f59f6aa1 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md @@ -0,0 +1,95 @@ +# d2b-broker-p4 - d2b-broker - part 4/7 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10,906 (excl. src/generated/)) | modules: audit; ops::{tap, disk_init, route, store_sync_audit, spawn_runner, host_generation_handoff, store_sync_export} +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: full-file scope for these 8 modules (U1 section f part 4/7 of d2b-broker) + +## idiom +- clean: seeds ran: 10/0/7 - every hit checked: the 10 `for i in 0..` hits are retry loops (quarantine-name, mkfs, udev-wait, test churn)and the 7 `let mut String/Vec::new()` hits are accumulation loops with early bounds/limit checks (legacy-export cap, bounded-line reader, scan cap, test fixtures), where an iterator pipeline would obscure the early exits; no hand-written derive-eligible impls in lane. + + + +## own +- clean: seeds ran: 83/288/6/0 - all 83 `.clone()` hits read in full (owned-construction into `RouteConflictKey`/`SpawnRunnerPlan`/`JournalEntry`/export records, cfg(test) `Arc` capture plumbing, test-fixture spec cloning)and the 294 `to_owned`/`to_vec`/`to_string`/`Arc` hits sampled every-8th (37 rows read) - all owned-string construction at wire/error boundaries, test fixtures, or the cfg(test) capture channel; no borrow-checker-silencing clone found; parsers taking `impl Into` (route.rs:413/418) require the owned String by callee contract, so those clones are not avoidable at the call site. + + + +## type +- clean: seeds ran: 13/0/0 - all 13 `validate_*`/`check_*` hits (mkfs binary path, existing image type/size/identity/posture, route state, artifact-with-helper, target path) validate external filesystem/leader state that a parsed type cannot carry, and each runs once at its boundary or on mutable kernel state - no illegal constructible state to encode; no bool flag fields nor stringly-typed state in lane. + + + +## api +- d2b-broker-p4#1 sev=medium blast=leaf effort=S verdict=actionable - `RouteConflictKey` is exported as `d2b_broker::ops::route::RouteConflictKey` (pub struct with all-pub fields) but its only users are private fns in the same file; its companion record type `RouteOwnershipRecord` is private - the visibility is a leak, not a contract with callers - fix: make it `pub(crate)` or plain `struct` (all users are in-file private helpers: `route_conflicts`, `route_matches_record`, `requested_route_conflict_key`)and drop the pub fields to private - [packages/d2b-broker/src/ops/route.rs:19] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 77 hits; census: `\bRouteConflictKey\b` over packages/ = 1 file (only its defining file) + +## err +- clean: seeds ran: 334/89/9/7 - combined 426 hits, sampled every-9th (48 rows read) plus all 9 panic-family hits and all 7 error enums read in full; the sampled hits are cfg(test) asserts/fixtures, deliberate best-effort `let _ = send/remove` cleanup, and invariant panics (`unreachable!` on limiter-stall/non-ext4 classification, `expect("ETXTBSY error recorded")` on a loop invariant, `expect("typed handoff serializes")` on derive-Serialize wire types) - all inside the acceptable panic-policy classes; the 7 error enums have Display/Error impls and are matched by variant, not by string; `DiskInitError` deliberately converts to `io::Error` with kind mapping (InvalidData/Other) plus actionable Display guidance - a sound coarse boundary for the `io::Result` op signature. + + + +## serde +- clean: seeds ran: 11/10/0/47 - all derive/attr hits checked (route record `rename_all="camelCase",deny_unknown_fields`, store_sync_audit enums `snake_case` pinned by the signed-schema test, `deny_unknown_fields` on broker-written round-trip records)and the 47 `serde_json` sites are boundary parses with `map_err` to `io::Error`/`OpError::InvalidInput` or deliberate corruption surfacing (`serde_json::from_str::)...).ok()` at audit.rs:1830 becomes a typed `AuditExportEntry { error: Some)...) }`), so failures are never silently swallowed. + + + +## obs +- clean: seeds ran: 0/0/0/2 - the only telemetry sites are two `tracing::warn!` calls in audit.rs (queue-full drop accounting, rate-limiter warning), both with named fields (`audit_drop_reason`, `audit_class`, `operation`, counters) - structured events as the skill requires; zero `println!`/`eprintln!` and no interpolated message-only events in lane. + + + +## docs +- d2b-broker-p4#2 sev=medium blast=leaf effort=S verdict=actionable - audit.rs public surface gaps:`AuditEntry` (legacy JSONL record shape consumed by the socket-acl gate), `AuditDropSummary`, `AuditLog::open` (the daemon entry point with bootstrap/poison barrier semantics), and `audit_drop_summary` carry no doc comment, while every sibling method around them is documented - fix: add `///` first-sentence contracts (state what `disposition` vs `outcome` mean, what counters `AuditDropSummary` merges, what `open`'s barrier requires of callers) - [packages/d2b-broker/src/audit.rs:124, packages/d2b-broker/src/audit.rs:84, packages/d2b-broker/src/audit.rs:416, packages/d2b-broker/src/audit.rs:1029] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct reads of lines 78-135/405-425/1025-1035 show no preceding doc comment on these four items +- d2b-broker-p4#3 sev=low blast=leaf effort=S verdict=actionable - tap.rs pub test-support surface lacks item docs:`SetBridgePortFlagsRequest`, `SetBridgePortFlagsAudit`, `set_bridge_port_flags`, `LiveCreateTapOutcome`, `LiveSetBridgePortFlagsError` have no `///` comments (the module-top doc explains the op family, but these exported shapes are the L1c canary-test contract)and should carry one-line first-sentence docs (error enum: list what each variant means to a caller) - [packages/d2b-broker/src/ops/tap.rs:157, packages/d2b-broker/src/ops/tap.rs:163, packages/d2b-broker/src/ops/tap.rs:169, packages/d2b-broker/src/ops/tap.rs:184, packages/d2b-broker/src/ops/tap.rs:828] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct reads of tap.rs lines 94-190 and 819-865 show no doc comments on these five items +- d2b-broker-p4#4 sev=medium blast=leaf effort=S verdict=actionable - `HandoffOperationError` (pub enum returned from every pub handoff fn) has no top-level doc comment; the failure modes (`JournalMismatch`, `HelperUnavailable`, `ArtifactValidationOutputInvalid`, ...) have descriptive names but no contract sentence says what callers should do per variant - fix: add a `///` doc line listing the variant classes (journal replay vs helper/validation failures) - [packages/d2b-broker/src/ops/host_generation_handoff.rs:35] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct read of handoff.rs lines 27-47 shows no doc comment above the enum +- d2b-broker-p4#5 sev=medium blast=leaf effort=S verdict=actionable - `ApplyWithPreflightError` (pub enum returned from the pub `apply_with_preflight_owned` entry point) has no top-level doc (only one variant carries an inline `///`); callers get no contract sentence distinguishing query failures from foreign-route refusal from reconcile failures - fix: add a one-line enum doc naming what each variant class means (route query vs ownership refusal vs executor failure) - [packages/d2b-broker/src/ops/route.rs:29] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct read of route.rs lines 18-46 shows no doc comment above the enum + +## perf +- clean: seeds ran: 124/20/79 - combined 223 hits sampled every-5th (45 rows read) - all sampled format!/to_string/Vec::new sites are error-path messages, audit-JSONL rendering, one-shot op-arg construction (ip link args, macvtap device paths), test fixtures, or empty-case-common buffers (`read_bounded_line`)) - all inside the card's recorded false-positive classes; no hot-loop allocation site found (lanes are one-shot broker ops, not per-packet paths). + + + +## conc +- clean: seeds ran: 2/6/11/0 - the 2 thread sites are the dedicated audit worker spawn (std::thread::Builder at audit.rs:446, bounded sync_channel receiver per plan R4 - sanctioned) and a test thread-name read; the 6 `Arc/Arc/Cow` = 0 throughout; `to_owned/to_vec/to_string` mass is dominated by error-detail and audit rendering, not clone-to-please-the-borrow-checker. + +## type +- clean: seeds ran 5/0/0; the five `validate_*`/`check_*` helpers (sys.rs:526 `validate_target_name`, swtpm_dir.rs:482 `check_resource_backed_state_dir`, nft.rs:534 `validate_projection_marker`, device.rs:335 `validate_opened_device`, hosts.rs:197 `validate_marker_ownership`) are single-boundary validators over genuinely untrusted fs/wire input with real check classes - parse-once newtypes would not remove a bug class here (stopping rule); no boolean-flag soup and no stringly-typed state (`is_/flag: bool` 0, `(mode|kind|state): String` 0). + +## api +- d2b-broker-p5#2 sev=low blast=leaf effort=S verdict=actionable - `CgroupBundleContext::slice_path()` returns an owned `PathBuf` (cloning `parent_slice`) when a `&Path` return serves every in-crate call, forcing a clone per call at the `is_under_slice` check and duplicating the value - fix: change the return to `&Path` (`pub fn slice_path(&self) -> &Path`); the builder methods `vm_interior_path`/`vm_leaf_path`/`vm_role_leaf_path` keep their owned joins and `fields.slice_path`/tuple sites keep their one owned conversion - [packages/d2b-broker/src/ops/cgroup.rs:126-129, packages/d2b-broker/src/ops/cgroup.rs:343] + evidence: census `slice_path\(` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 9 hits (8 in-crate, 1 unrelated `d2b_host::cgroup::d2b_slice_path`); call sites that would stop cloning: cgroup.rs:249 (owns once), 323, 343 (read-only). +- clean remainder: seeds ran 181/0/4; the wide `pub` surface is deliberate for a daemon-internal crate (all 4 `pub use` arms are the house single-surface pattern: lib.rs:56, forwarding.rs:42); the one smart-pointer-in-signature (`ForwardFuture` = `Pin>`, forwarding.rs:114) is a documented trait-object seam for `dyn OperationForwarder` - not a hidden internals leak. + +## err +- d2b-broker-p5#3 sev=medium blast=leaf effort=S verdict=actionable - `WriteMarkerBlockError::Io(String)` (hosts.rs:122) flattens `io::Error` into a Display-only string at three `map_err` sites, destroying the error kind/source so a caller cannot classify NotFound vs permission vs other without string-matching - fix: switch the variant to `Io(#[source] io::Error)` (thiserror or a hand-written `#[source]` accessor) and render the same "update-hosts marker splice: {err}" prefix so the visible message is unchanged - [packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-broker/src/ops/hosts.rs:149, packages/d2b-broker/src/ops/hosts.rs:153, packages/d2b-broker/src/ops/hosts.rs:180] + evidence: seed `enum \w*Error` = 7; the siblings `CgroupOpError`, `ApplyWithCoexistenceError`, `ProjectionMutationError`, `FdPassingError`, `SwtpmHardenError` already carry typed fields, so `Io(String)` is the outlier; `\.unwrap\(\)|\.expect\(` = 260 hits, every non-test survivor is an `expect` on a literally-built C string (sys.rs:695, 714, 746, 974, 1860, 1928) or an unreachable-invariant expect (nft.rs:563 - the `"}"` line with `current.is_none()` is continued earlier, so `current.take()` cannot fail); `let _ =` = 34, all best-effort cleanup (fd close, child SIGKILL/reap, temp-dir removal); `panic!` = 10, all in `#[cfg(test)]`. + +## serde +- clean: seeds ran 7/6/0/18; the derive set (swtpm_dir.rs `MarkerData`/`MarkerOrigin`, nft.rs `ApplyNftablesAudit`/`NftHashSidecar`, device.rs `PreOpenDecision`/`OpenAuditRecord`/`RoleDeviceClaim`) is consistently `rename_all`-conventioned, `MarkerData` correctly carries `deny_unknown_fields` as the one tamper-sensitive payload, no hand-written `Deserialize` (0), and no `try_from` is missing - every shape is an emit/parse pair of the broker's own audit/marker payloads, not untrusted service input; `deny_unknown_fields` absence on service-consumed audit messages is the recorded deliberate posture. + +## obs +- clean: seeds ran 6/0/0/0; the six `println!`/`eprintln!` hits (sys.rs:1417, 1421, 3893, 4201, 4217; swtpm_dir.rs:1557) are all `#[cfg(test)]` skip messages, no interpolated-message events (0), no `instrument` spans (0), and no `tracing`/`log` use in this lane's files (0) - the lane's observability surface is the typed audit records (SwtpmDirAudit, OpenAuditRecord, ApplyNftablesAudit), which are data, not log lines. + +## docs +- d2b-broker-p5#4 sev=medium blast=leaf effort=S verdict=actionable - the public fd-ownership API in fd_passing.rs is undocumented: `FdPassingError` (13), `FdRegistry::register`/`clear` (37, 41), and the whole `FdLease` surface (`new`/`raw`/`release`, 55-70) have no doc comments even though the load-bearing contract is non-obvious - `FdLease` closes the fd on drop and `release()` disarms that close, which is exactly what ADR 0034 fd-transfer callers must know - fix: add one-line docs to each item stating ownership (who closes, what `release` disarms) and the `recv_*`/`send_fds` error variants - [packages/d2b-broker/src/fd_passing.rs:13, packages/d2b-broker/src/fd_passing.rs:31-70] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164; the documented peers in the same module (recv_fds, recv_fds_with_capacity, recv_one_fd, close_received_fds) show the house expectation, making the bare FdLease/FdRegistry group the gap. +- d2b-broker-p5#5 sev=medium blast=leaf effort=S verdict=actionable - pub syscall wrappers `peer_credentials` (121) and `tun_set_persist`/`tun_set_owner`/`tun_set_group` (185, 195, 210) carry no doc comments while their twins `peer_uid` and `tun_create_tap_fd` do; the contracts are non-obvious (peer uid/gid/pid triple semantics; TUNSETPERSIST/OWNER/GROUP ioctl semantics and the ifname binding) - fix: add one-line docs plus the `# Errors` conditions (ioctl failure, uid/gid out of `c_int` range) - [packages/d2b-broker/src/sys.rs:120-121, packages/d2b-broker/src/sys.rs:185, packages/d2b-broker/src/sys.rs:195, packages/d2b-broker/src/sys.rs:210] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 overall, these four are the undocumented pub items in the module's leading wrapper group (rest documented). +- d2b-broker-p5#6 sev=low blast=leaf effort=M verdict=actionable - the `path_safe` module's pub helpers (`refuse_symlink`, `refuse_world_writable_parent`, `refuse_non_root_parent`, `read_to_string_nofollow`, `write_nofollow`, `remove_nofollow`, `ensure_dir`, `ensure_dir_preserve_existing`) lack per-item doc comments; the contract lives only in the module-level doc, so rustdoc item pages are empty and the reader must open the module header for each helper's safety rule - fix: promote each module-doc bullet to a one-line `///` on its item (or add `#[doc = "..."]` links), keeping the module doc as the index - [packages/d2b-broker/src/sys.rs:258, packages/d2b-broker/src/sys.rs:268, packages/d2b-broker/src/sys.rs:329, packages/d2b-broker/src/sys.rs:398] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164; the module doc at sys.rs:205-249 names every helper, confirming intent, and `/// # (Examples|Errors|Panics|Safety)` = 1 (only `getsockopt_int`'s `# Safety`), so the canonical-section convention is otherwise absent here. + +## perf +- d2b-broker-p5#7 sev=low blast=leaf effort=S verdict=actionable - `projection_digest` builds the hex digest with `raw.iter().map(|byte| format!("{byte:02x}")).collect::()`, allocating one `String` per byte (32 hex bytes) before the final collect - fix: `String::with_capacity(70)` and `write!`/`push_str` each byte, or a 16-entry hex lookup - [packages/d2b-broker/src/ops/nft.rs:784-790] + evidence: seed `format!\(` = 108; this is the one site allocating inside a per-element `map` closure, all other `format!` are error/audit/text-artifact sites (cold per repo false positives). +- d2b-broker-p5#8 sev=low blast=leaf effort=S verdict=actionable - `handle_open_cgroup_dir` renders `canonical_path.display().to_string()` twice (the audit field at 341 and the outcome at 368) in the same call - fix: bind `let cgroup_id = canonical_path.display().to_string();` once and reuse for both the audit record and `OpenCgroupDirOutcome` - [packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368] + evidence: seed `\.to_string\(\)` = 33; the duplicate is the same expression on the same value in one function body. +- clean remainder: seeds ran 108/27/33; all other `format!`/`Vec::new`/`to_string` sites are in error paths, audit rendering, nft-script text building, or fixture/test code (deliberate per card false positives); nothing else is a hot path with growth-by-push. + +## conc +- clean: seeds ran 23; production concurrency use is a single `static TMP_NAME_COUNTER: AtomicU64` with `Ordering::Relaxed` (sys.rs:474, 541) - the weakest correct ordering for a globally-unique counter, exactly what the skill prescribes; every `Mutex`/`thread::spawn`/`Arc` hit is test-only (forwarding.rs test peers, fd_passing.rs `fd_test_lock`, swtpm_dir.rs test thread, cgroup.rs `RecordingAuditSink` under `fake-backends`); no `unsafe impl Send/Sync` and no `thread_local!`/`static mut`. + +## async +- d2b-broker-p5#9 sev=high blast=leaf effort=S verdict=actionable - the async `harden()` path (invoked from `live_handlers.rs:3142` on the runtime) calls `apply_ancestor_traverse_acl` -> `run_setfacl_op_on_fd` (sys.rs:1866-1893), which does a synchronous `fork` + `execv(setfacl)` + blocking `waitpid` loop with no `.await` and no `spawn_blocking`, stalling the executor worker for the duration of a subprocess spawn - fix: wrap the setfacl fork/exec/wait in `tokio::task::spawn_blocking` (moving the fd across as `OwnedFd`) and `.await` the join handle in `harden` - [packages/d2b-broker/src/ops/swtpm_dir.rs:770, packages/d2b-broker/src/sys.rs:1866-1893, packages/d2b-broker/src/live_handlers.rs:3142] + evidence: seed `async fn|async move|\.await` = 134, `tokio::spawn|...|#\[tokio::(main|test)\]|Runtime::block_on` = 26; call chain shows the sync `waitpid` loop sits inside an async function with no yield point between entry and the blocking wait; no async-gate-allow marker or blocking-census entry covers this site (the scanner and disallowed-methods list target tokio sync forms and lock acquisition, not fork/exec/waitpid). +- clean remainder: the lane's other async sites follow the house patterns - `acquire_projection_lock` (nft.rs:809-832) polls non-blocking `F_OFD_SETLK` with 25ms async sleeps (R13, documented), `read_live_table_json_optional` uses `tokio::process::Command` (nft.rs:866-881), swtpm marker reads/writes use `tokio::fs` with a single quick `rustix::fs::fsync`; none block a worker and none keep a guard across `.await`. + +## unsafe +- d2b-broker-p5#10 sev=medium blast=leaf effort=M verdict=actionable - most of `sys.rs`'s 101 `unsafe` blocks carry no `// SAFETY:` comment (only 25 SAFETY comments in the file, concentrated on the risky corner: clone3, fork, pre_exec, pidfd, mount); the raw wrapper layer - `openat2_raw`, `openat_raw`, `renameat2_raw`, `renameat_raw`, `mkdirat_raw`, `unlinkat_raw_with_flags`, `fstatat_raw`, `linkat_empty_path_raw` (593-699), the child-context helpers `mkdir_one`/`mknod_device_bind_target`/`install_pre_opened_fds` (2630, 2670, 2109) and the mount/mask helpers `apply_mount_actions(_debug)`/`apply_device_mask_and_binds` (2591, 2694) - call libc with only `#[allow(unsafe_code)]`, so a reader cannot distinguish audited from un-audited blocks in the sanctioned quarantine - fix: add a one-line SAFETY to each bare block stating the invariant it upholds (CString/pointer liveness and NUL-termination, dirfd validity, errno propagation, freshly-owned return fd), matching the existing clone3/fork comments - [packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broker/src/sys.rs:630, packages/d2b-broker/src/sys.rs:653, packages/d2b-broker/src/sys.rs:676, packages/d2b-broker/src/sys.rs:685, packages/d2b-broker/src/sys.rs:697, packages/d2b-broker/src/sys.rs:2109, packages/d2b-broker/src/sys.rs:2591, packages/d2b-broker/src/sys.rs:2630, packages/d2b-broker/src/sys.rs:2670, packages/d2b-broker/src/sys.rs:2694] + evidence: seed `\bunsafe \{|\bunsafe fn|...` = 103 hits; `// SAFETY:` = 25; `transmute|from_raw|MaybeUninit|mem::zeroed` = 39 (the `mem::zeroed` sites are int/struct-value kernels like `libc::stat`/`ifreq`/`clone_args` where zero is a valid bit pattern - sound, but the same bare-block comment gap applies). The allow pattern itself is the sanctioned boundary (U1 d8) and is not re-flagged; this finding targets only missing per-block justification on sound code. + +## ffi +- clean: seeds ran 66; every hit is within the sanctioned libc syscall-wrapper surface and matches the card's repo false positives - `CString`/`c_char` in the `nix`-replacing raw syscall layer (sys.rs), one `#[repr(C)] OpenHow` kernel uapi shape (sys.rs:497), no `extern "C"` function, no `no_mangle`, no `catch_unwind`, and no foreign caller exists anywhere in the lane scope; nothing here crosses a non-Rust calling convention. + +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, proc-macro, syn/quote, `$crate`, or compile-error machinery in any assigned file) + +## test +- clean: seeds ran 109/91/0/0; the in-file `#[cfg(test)]` modules (sys.rs, swtpm_dir.rs, nft.rs, forwarding.rs, cgroup.rs, device.rs, hosts.rs, fd_passing.rs) assert behavior and error variants rather than Display strings - fd tests serialize via `fd_test_lock`, the forwarder tests cover refusal/fd-count-mismatch/budget-bound paths, swtpm tests assert fail-closed reasons and contents-preservation, and the sys.rs tests document skip conditions for privileged/unprivileged-userns cases; no `#[ignore]`, no proptest/insta/rstest (unit tests fit these pure-ish functions), and no test that cannot fail was observed. (Crate-level `tests/**` is shared across the broker's seven parts; this lane's `test` judgement covers its own modules.) + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: 38/156/0) +- type: clean (seeds ran: 5/0/0) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 7/6/0/18) +- obs: clean (seeds ran: 6/0/0/0) +- docs: 3 finding(s) +- perf: 2 finding(s) +- conc: clean (seeds ran: 23) +- async: 1 finding(s) +- unsafe: 1 finding(s) +- ffi: clean (seeds ran: 66) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions in assigned files) +- test: clean (seeds ran: 109/91/0/0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md new file mode 100644 index 000000000..b9e9c84dd --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md @@ -0,0 +1,101 @@ +# d2b-broker-p6 - d2b-broker - part 6/7 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10,986 (excl. src/generated/**) | modules: envelope, ops/exec_reconcile, ops/audit_op, ops/store_view_posture, ops/device_worker, ops/nm, ops/security_key, ops/store_view_farm, ops/usbip_firewall +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 6/7 of d2b-broker per U1 section f: src/envelope/**, src/ops/exec_reconcile.rs, src/ops/audit_op.rs, src/ops/store_view_posture.rs, src/ops/device_worker.rs, src/ops/nm.rs, src/ops/security_key.rs, src/ops/store_view_farm.rs, src/ops/usbip_firewall.rs + +## idiom +- d2b-broker-p6#1 sev=low blast=leaf effort=S verdict=actionable - the "path must be absolute" check (a `to_str()` + `starts_with('/')` + `InvalidInput` refusal) is hand-copied into seven SystemReconcileExecutor methods, so a wording or error-shape change must touch all seven. - fix: extract a private `fn require_absolute(path: &Path) -> Result<(), ReconcileExecError>` helper and call it from apply_nft_script, write_atomic_file, write_atomic_file_with_ownership, write_path_value, read_path_value, ip_route, run_usbip, run_ssh_keygen. - [src/ops/exec_reconcile.rs:404, src/ops/exec_reconcile.rs:505, src/ops/exec_reconcile.rs:551, src/ops/exec_reconcile.rs:602, src/ops/exec_reconcile.rs:622, src/ops/exec_reconcile.rs:642, src/ops/exec_reconcile.rs:697, src/ops/exec_reconcile.rs:811] + evidence: idiom seeds over src/ops/exec_reconcile.rs = 1/0/0 (static read of the executor methods 392-926). +- d2b-broker-p6#2 sev=low blast=leaf effort=S verdict=actionable - write_atomic_file and write_atomic_file_with_ownership duplicate the parent-check + basename-extract + open_dir_path_safe preamble, differing only in the optional (u32, u32) ownership argument. - fix: fold into one `fn write_atomic_file(path: &Path, content: &[u8], owner: Option<(u32, u32)>) -> Result<(), ReconcileExecError>` and fold the `_with_ownership` twin into it (keeping a thin wrapper only if a caller outside the executor needs it) - [src/ops/exec_reconcile.rs:500-541, src/ops/exec_reconcile.rs:542-591] + evidence: idiom seeds over src/ops/exec_reconcile.rs = 1/0/0 (static read of the two file-writing helpers). +- d2b-broker-p6#3 sev=low blast=leaf effort=M verdict=actionable - build_farm_via_namespace and build_store_view_via_namespace duplicate the same spawn-process + write-config + read-stdout + split-lines scaffold (about 100 lines each), drifting in error messages and success parsing. - fix: unify behind one private `async fn run_store_helper(verb: StoreViewHelperVerb, request: impl Serialize, success: impl FnOnce(&[u8]) -> ...) -> Result<(), StoreViewFarmError>` with a two-variant `StoreViewHelperVerb` enum, or extract the shared scaffold into a thin helper. - [src/ops/store_view_farm.rs:97-190, src/ops/store_view_farm.rs:228-300] + evidence: idiom seeds over src/ops/store_view_farm.rs = 0/0/0 (static read of the two helper fns). +- d2b-broker-p6#4 sev=medium blast=leaf effort=M verdict=actionable - row_owner_ref, device_guest_owner,and tpm_devices_of_guest hand-roll the same "walk the bundles resources array" loop three times with slightly different match predicates, so bundle-shape drift (new field, renamed key) silently desyncs them. - fix: extract a single `fn find_resource_row<'a>(bundle: &'a Value, pred: impl FnMut(&'a Value) -> bool) -> Option<&'a Value>` and drive all three (and callers of row_owner_ref at src/ops/device_worker.rs:158) from it; keep the three predicates as call-site closures. - [src/ops/device_worker.rs:312-335, src/ops/device_worker.rs:339-369, src/ops/device_worker.rs:371-434] + evidence: idiom seeds over src/ops/device_worker.rs = 0/0/1 (static read of the three bundle-walk fns. +. +- d2b-broker-p6#5 sev=low blast=leaf effort=M verdict=actionable - TrustedContextStore duplicates each worker-handshake entrypoint as a sync twin (`open`/`open_async`, `publish`/`publish_async`) whose sync copies spawn a `block_on`-free worker handshake that only in-crate `#[cfg(test)]` callers exercise;; the justification comment begins "The crate is nearly all async" and does not cover the sync twins' ongoing cost. - fix: gate the sync twins `#[cfg(test)]` (and gate `TrustedContextStore::Drop`'s sync persist path if unused outside tests), or unify over a private `fn with_worker(blocking: bool, f: impl FnOnce...` seam if a production sync caller is restored. - [src/envelope/mod.rs:424-464, src/envelope/mod.rs:466-493, src/envelope/mod.rs:540-565, src/envelope/mod.rs:567-593] + evidence: idiom seeds over src/envelope/mod.rs = 4/3/3 (static read of the four entrypoints 424-593. + +## own +- d2b-broker-p6#6 sev=low blast=leaf effort=S verdict=actionable - in `context_worker_loop` the Bootstrap reply clones the entire persisted state (`let _ = reply.send(Ok(state.state.clone()))`) just to unblock open()/open_async(), which discard the reply value (`?`), so each broker open copies the whole `PersistedTrustedContext` for nothing. - fix: shrink `ContextCommand::Bootstrap`'s oneshot reply to `Sender>` and send `Ok(())` without touching `state`;; delete the `state.state.clone()` site (keep the `let _ =` on the send alone). - [src/envelope/mod.rs:671] + evidence: own seed `\.clone\(\)` over src/envelope/mod.rs = 24 hits; site 671 matched. + +## type +- clean: deterministic-validators and stringly-state seeds checked;; the two `fn validate_*` sites (src/ops/nm.rs:151, src/ops/security_key.rs:82) are boundary cross-checks against existing config/authority state, not per-callsite re-validation;; the 10 `(mode|kind|state): String` occurrences are all audit-record or embedded-contract wire fields (state-posture-contract.json) pinned by the JSON drift gate, so no illegal-state combination is representable at the lens's bar. + +. + +## api + +- d2b-broker-p6#7 sev=medium blast=leaf effort=L verdict=policy-confirmed - `lib.rs` declares `pub mod ops` (src/lib.rs:45) with `pub mod` arms for all 27 executor/helper modules in src/ops/mod.rs:20-94, so every item in them becomes part of the crate's public surface - while the recorded design rationale (src/lib.rs:8-11) is "public API of internal modules that downstream callers may use", and a census finds no downstream crate consumer.. - fix: if a deliberate public-surface decision is desired, keep `pub mod` and record the census in a doc comment or dossier;; otherwise narrow the `pub mod` arms to `pub(crate)` for modules with no out-of-crate consumer (ops/exec_reconcile, ops/audit_op, ops/store_view_posture, ops/store_view_farm, ops/device_worker, ops/security_key, ops/usbip_firewall, ops/nm)and re-export only test-consumed items (`OperationFields` for tests/security_key_broker.rs) under a `#[cfg(any(test, feature = "fake-backends")))]`-style gate. - [src/lib.rs:45, src/ops/mod.rs:20-94] + evidence: census: `d2b_broker::ops` over packages/*/src, packages/*/tests, tests/, docs/reference/, labs/, nixos-modules/ = 10 hits (8 code imports in d2b-broker/tests/{bridge_lifecycle.rs:3, persistent_tap_lifecycle.rs:3, pidfd_handoff_scm_rights.rs:24,:25,:85, pidfd_real_spawner.rs:17, security_key_broker.rs:9};2 doc-comment mentions in d2b-host/src/{modules.rs:19, devices.rs:6}). + + + +## err +- d2b-broker-p6#8 sev=low blast=leaf effort=M verdict=actionable - usbip_unbind_error_is_transient classifies retryable-vs-fatal usbip failures by case-folded substring matching over `stderr`/`error` text (42-Condition-Not-Satisfied, "program does not support"..., "no matching transport"), so a locale or usbip-version message change silently flips the retry decision and the broker's eventual verdict. - fix: parse the failure once at the stderr boundary into a typed `UsbipUnbindFailure { kind: UsbipUnbindFailureKind, transient: bool, detail: String }` (or a documented constant allowlist),and drive the retry loop (and final error reporting) off the typed kind instead of re-scanning strings. - [src/ops/exec_reconcile.rs:1238-1265] + evidence: err seeds over src/ops/exec_reconcile.rs = 56/16/4/1 (static read of usbip_unbind_error_is_transient and its retry call sites 990-1070. +. +- d2b-broker-p6#9 sev=low blast=leaf effort=S verdict=actionable - guest_socket_directory returns `Result<&'static str,...>` with two plain-static-code errors (a "not root-owned" refusal, "no guest" refusal),while the sibling launch-scope pinner uses a typed `DeviceWorkerScopeError` enum - so an internal closed-error str forces callers (live_handlers.rs:2428) to stringly-match an error. - fix: give guest_socket_directory a small `GuestSocketError` enum (or reuse DeviceWorkerScopeError's callers-action split with a `GuestSocket` variant.)and return that instead of a `&'static str`. - [src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2428] + evidence: err seed4 over src/ops/device_worker.rs = 1 (DeviceWorkerScopeError enum exists; guest_socket_directory uses the bare `&'static str` instead; static read of lines 262-284. + +## serde +- clean: derive-counts, serde-attribute seeds, hand `Deserialize` impls,and serde_json calls checked;; wire-shaped structs in the lane carry `rename_all`, `deny_unknown_fields` (audit identity records, OpAuditRecord via parse_fields!), `skip_serializing_if`/`default` for optional fields, and legacy-compat tests pin optionality meaning;; the untagged `OperationFields` decomposition is deliberate (the JSON drift gate reads back fields per variant),and no missing-validation site warrants a `try_from` row.. + +## obs +- clean: println!/eprintln!/dbg! seeds zero;; tracing events (9 hits) all use named fields (`usbip_subcommand = %subcommand`, `path = %path.display()`, `error = %error`) with no msg-interpolation formatting;; no secrets in fields (audit paths are hashed/redacted at the wrapper boundaries by design). + +## docs +- d2b-broker-p6#10 sev=low blast=leaf effort=S verdict=actionable - the two `pub async fn` store-view farm entrypoints carry the same design-journal sentence "Async form used by the async exec_reconcile and store_sync paths; the sync form was removed with its last sync caller" with a typo (missing space after `paths.`), stating history ("was removed") instead of a contract. - fix: trim to a one-line contract ("Async counterpart used by the async exec_reconcile/store_sync callers.") at both sites, and add `# Errors`-style failure notes where the error enum is non-obvious. - [src/ops/store_view_farm.rs:66-72, src/ops/store_view_farm.rs:191-197] + evidence: docs seeds over src/ops/store_view_farm.rs = 0/0/5 (the two pub async fns are within the `-> Result<` hitset; static read of both docs. +. +- d2b-broker-p6#11 sev=low blast=leaf effort=S verdict=actionable - BrokerEnvelope::call, call_with_fds,and call_nested_with_fds return `Result<_, EnvelopeRefusal>` with no `# Errors` section, so failure modes (14 closed refusal-code consts, e.g. subscriber-only, scope refusals, budget refusals) must be chased around the file to be known. - fix: add an `# Errors` block to each of the three pub methods naming the closed `EnvelopeRefusal` vocabulary and pointing at the refusal constants. - [src/envelope/mod.rs:1118, src/envelope/mod.rs:1136, src/envelope/mod.rs:1187] + evidence: docs seeds over src/envelope/mod.rs = 67/0/18 (canonical section hits zero amid 18 public `-> Result<` items; static read of the call trio. +. +- d2b-broker-p6#12 sev=low blast=leaf effort=S verdict=actionable - apply_with_reload/remove_with_reload doc prose narrates design history ("The dispatcher now lands on ops::nm even though the live path is still a thin wrapper... future coexistence/reload-verification work"), which rots and reads as rendered journal prose on a public item. - fix: rewrite the doc as a plain two-sentence contract (what it does, when reload verification kicks in),and move the rationale to the module doc if it must be preserved. - [src/ops/nm.rs:293-301, src/ops/nm.rs:303-308] + evidence: docs seeds over src/ops/nm.rs = 12/0/9 (static read of the two wrapper docs 288-308. + +## perf +- d2b-broker-p6#13 sev=low blast=leaf effort=S verdict=actionable - contract_store_view_levels re-parses the embedded `include_str!` JSON contract (STATE_POSTURE_CONTRACT) on every call (down per-VM posture passes; each row also re-parses the contract via contract_store_view_level, so the same ~600-line document is parsed many times per sync pass. - fix: pre-parse once into a `static CONTRACT: LazyLock` (or `OnceLock`|and resolve per-row levels/profiles from the cached parse, deleting per-call `ContractFile::parse` sites. - [src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/store_view_posture.rs:310-352] + evidence: static (unmeasured); hot-enough path only with many VMs; read of contract_store_view_levels 194-271 and its row sink 310-352). + +## conc +- d2b-broker-p6#14 sev=low blast=leaf effort=S verdict=actionable - the invocation-id counter uses `Ordering::AcqRel` (`self.invocations.fetch_add(1, Ordering::AcqRel)`), but no reader of the counter or its derived id synchronizes on it - the returned old value is consumed only by the calling thread/audit record, so Relaxed is the weakest correct ordering. - fix: use `Ordering::Relaxed` at src/envelope/mod.rs:1146 (and at the test double's `observed.fetch_add` at src/envelope/mod.rs:2144). - [src/envelope/mod.rs:1146, src/envelope/mod.rs:2144] + evidence: conc seeds over src/envelope/mod.rs = 5/7/10/0 (atomic hits include the AcqRel counter; static read of the counter's only use 1140-1160. + +## async +- clean: async seeds (319 async/await, 3 tokio::spawn writer/stderr-drain tasks, 0 tokio::sync, 39 tokio main/test+block_on) checked;; the trusted-context store's worker uses the sanctioned bounded-worker pattern (async-gate-allow markers "dedicated bounded worker per plan R4" at src/envelope/mod.rs:699,725,798),the sync store twins (`open`/`epoch`/`holds_zone`/`publish`and Drop)run off the R4 worker thread by design,and no production path blocks an executor worker;; no guard is held across `.await`, no cancellation-safety hazard found (handler task abort at budget expiry is deliberate, KTD4; stdin-writer `tokio::spawn` at store_view_farm.rs:135,:247 is dropped after write, fine. + +## unsafe +- clean: unsafe seeds over the lane = 0/0/6/0;; the six `from_raw` hits are all safe std/nix constructors (`io::Error::from_raw_os_error`, `Pid::from_raw`, `Gid::from_raw`),no `unsafe` block, unsafe fn, or unsafe impl exists in these files. + + + +## ffi +- N/A: all four ffi seeds zero in these files; no FFI boundary lives in the lane - the crate's extern surface sits in src/sys.rs etc. (out of this part's scope).. + + + +## macro +- clean: macro_rules! hits = 2 (src/ops/audit_op.rs:475 parse_fields!, src/ops/audit_op.rs:981 roundtrip_test!) - both are the legitimate "generate an impl per type from a small list" use (the parse_fields! macro generates serde impls for 40+ OperationFields variants with a single local pattern;,roundtrip_test! is test-only); no proc-macro, no `$crate`, no hygiene escape hatch.. + +## test +- clean: 109 #[test]/#[tokio::test] + 331 assert seeds, zero proptest/insta/rstest, zero #[ignore];; suite assertions target behavior (refusal codes, legacy-compat parses, fd-leg round-trips, causality-back timeouts),tests are deterministic (tempdir scratch roots, derived/seed paths,,no network, injected time),and no test that cannot fail was found in the lane's tests/**. + + + +## Coverage +- idiom: 5 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 2/0/10) +- api: 1 finding(s) +- err: 2 finding(s) +- serde: clean (seeds ran: 24/34/0/39) +- obs: clean (seeds ran: 0/0/0/9) +- docs: 3 finding(s) +- perf: 1 finding(s) +- conc: 1 finding(s) +- async: clean (seeds ran: 319/3/0/39) +- unsafe: clean (seeds ran: 0/0/6/0) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface in the lane - the crate's extern boundary lives in src/sys.rs (out of this part's scope)) +- macro: clean (seeds ran: 2/0/0/0) +- test: clean (seeds ran: 109/331/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md new file mode 100644 index 000000000..35242b534 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md @@ -0,0 +1,87 @@ +# d2b-broker-p7 - d2b-broker - part 7/7 +Baseline: 6ebdd4cec | LOC audited: 10265 (excl. src/generated/**, non-Rust src/ops/state-posture-contract.json) | modules: ops::media, kernel_ops, ops::network, catalog, ops::state_dir, protocol, bootstrap +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 7/7 (src/ops/media.rs, src/kernel_ops.rs, src/ops/network.rs, src/catalog.rs, src/ops/state_dir.rs, src/protocol.rs, src/bootstrap.rs; src/ops/state-posture-contract.json excluded, non-Rust wire contract) + +## idiom +- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=14; all 14 accumulation sites are async `read_dir`/`fill_buf` loops with early returns, test line readers, and hash-input string building - no iterator-pipeline conversions warranted. + +## own +- d2b-broker-p7#1 sev=low blast=leaf effort=S verdict=actionable - enroll's registry-read fallback clones the just-written record although it is never used again - fix: replace `unwrap_or_else(|_| vec![record.clone()])` with `unwrap_or_else(|_| vec![record])` in `enroll` - [packages/d2b-broker/src/ops/media.rs:220] + evidence: `\.clone\(\)` seed = 85 hits; site read confirms `record` is only borrowed (`write_registry_record(resolver,&record)`) and then moved into the fallback `vec!` - no use after line 220; combined own seed mass 358 (>200): sampled: 50 of 358 hits (all seed-1 hit lines read in full; seed-2 hits are owned-build string materialization and wire-render clones - none avoidable; the sole `RefCell<` (network.rs:984)is a `#[cfg(test)]` fake). + +## type +- d2b-broker-p7#2 sev=medium blast=leaf effort=S verdict=actionable - QmpAttachCleanup models its four-step rollback as four bools (16 states, ~5 valid)with a fixed teardown order - fix: replace `device_added/raw_added/file_added/fdset_added: bool` with an ordered step list or enum so rollback order cannot drift from the attach order - [packages/d2b-broker/src/ops/media.rs:889-892] + evidence: `is_\w+: bool|\w+_flag: bool` seed = 1 hit (the four fields at media.rs:889-892; rollback order fixed at 898-943(`device_del`->`blockdev-del` raw->file->`remove-fd`); the valid step set lives only in the attach flow - a future fifth step would silently bypass teardown). + +## api +- d2b-broker-p7#3 sev=low blast=leaf effort=S verdict=actionable - kernel_table clones the whole KernelConfig into an Arc because it takes `&KernelConfig` - fix: take `config: KernelConfig` by value (or `Arc`) so the one-time clone disappears; the per-handler Arc clones stay - [packages/d2b-broker/src/kernel_ops.rs:99-100] + evidence: `pub .*\b(Arc|Rc|Box|RefCell)<` seed = 0 hits (no managed types in signatures; the Arc appears only in the fn body); census: `kernel_table` over packages/,nixos-modules/,tests/,docs/reference/,labs/ = 7 hits (kernel_ops.rs:99 + 6 in-crate call sites in runtime.rs:7145,14485,14798,15227,15545,17597, all passing a locally-built `&KernelConfig`). + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(`=289, `let _ = |\.ok\(\);`=28, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`=1, `enum \w*Error`=3 (sampled: 50 of 321 hits; every production unwrap/expect site read: all are invariant expects (`BrokerOperationRow` committed rows at kernel_ops.rs:667,670,673,699,702,705; validated fdset id at media.rs:705;`[u8;4]` prefix try_into at protocol.rs:98,144 - the rest are in-file `#[cfg(test)]` assertions; the 28 `let _ =`/`.ok();` sites are best-effort rollback/server patterns; the three error enums (`MediaOpError`, `NetworkOpError`, `PrepareStateDirError`) carry stable wire codes - no panic-policy breach found) + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize`=13, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=46, `impl .*Deserialize.*for`=0, `serde_json::from_|serde_json::to_`=36; all wire types (bootstrap.rs wire module, media registry records, network.rs `PersistentTapRealization`, protocol framing values)use `rename_all`/`deny_unknown_fields`/internal enum tags, deliberate `#[serde(default)]` on optional fields; no hand-written deserializers, no parse-validation gap found. + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(`=0, `(info|debug|warn|error|trace)!\(`=1, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=4 (1 real: media.rs:431 structured `tracing::warn!` with named fields `vm_id`/`media_ref`/`slot`; 3 false positives: `catalog::` x2 and `Backlog::` match the `log::` alternation); no secret/PII-in-log paths found. + + + +## docs +- d2b-broker-p7#4 sev=medium blast=leaf effort=M verdict=actionable - media.rs's public ops surface carries no doc comments - fix: add doc blocks to each: MediaOpError variants, the four outcome structs (esp. BootOutcome's four booleans),and the pub ops fns (`enroll`/`refresh_registry`/`boot`/`system_powerdown`/`query_status`/`quit`/`attach`/`detach`),covering preconditions, outcome semantics,and `# Errors` on the `Result` fns - [packages/d2b-broker/src/ops/media.rs:35, packages/d2b-broker/src/ops/media.rs:167-186, packages/d2b-broker/src/ops/media.rs:188, packages/d2b-broker/src/ops/media.rs:238, packages/d2b-broker/src/ops/media.rs:254, packages/d2b-broker/src/ops/media.rs:270, packages/d2b-broker/src/ops/media.rs:281, packages/d2b-broker/src/ops/media.rs:322, packages/d2b-broker/src/ops/media.rs:331, packages/d2b-broker/src/ops/media.rs:339] + evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)`=102, `/// # (Examples|Errors|Panics|Safety)`=0; item-by-item read of media.rs:35-56,167-186,188-339 confirms no preceding `///` blocks on any pub item in this module. +- d2b-broker-p7#5 sev=medium blast=leaf effort=S verdict=actionable - protocol.rs's framing surface (cap const + sync framing fns)carries no docs although it is the broker wire contract - fix: doc `MAX_FRAME_SIZE` and the six framing fns (length-prefix format, cap enforcement, `Option::None` on empty socket, fd-ancillary semantics), mirroring the async wrappers' existing docs - [packages/d2b-broker/src/protocol.rs:13, packages/d2b-broker/src/protocol.rs:16, packages/d2b-broker/src/protocol.rs:29, packages/d2b-broker/src/protocol.rs:43, packages/d2b-broker/src/protocol.rs:52, packages/d2b-broker/src/protocol.rs:85, packages/d2b-broker/src/protocol.rs:121] + evidence: docs seeds 102/0 as above; the async twins (`AsyncSeqpacket`, `AsyncSeqpacketListener`, `connect_seqpacket_bounded`)do carry docs, so the gap is confined to the sync framing path; census: `connect_seqpacket|bind_seqpacket|send_json_frame|recv_json_frame|MAX_FRAME_SIZE` over packages/,nixos-modules/,tests/,docs/reference/,labs/ = heavy use (runtime.rs, forwarding.rs, envelope/, d2bd-runtime/, d2b-contracts/, tests/, docs/reference/tap-dag-contract.md). +- d2b-broker-p7#6 sev=medium blast=leaf effort=S verdict=actionable - state_dir.rs publishes nine undocmented pub items (types + fns)with no `# Errors` on the `io::Result` fns - fix: add item-level doc contracts to `DirKind`, `PrepareDirRequest`, `PrepareDirAudit`, `ReplaceOrCreateResult`, `prepare_dir`, `live_prepare_runtime_dir`, `PreparedStateDir`, `live_prepare_state_dir` (and `# Errors` where Result) - [packages/d2b-broker/src/ops/state_dir.rs:47, packages/d2b-broker/src/ops/state_dir.rs:53, packages/d2b-broker/src/ops/state_dir.rs:70, packages/d2b-broker/src/ops/state_dir.rs:83, packages/d2b-broker/src/ops/state_dir.rs:89, packages/d2b-broker/src/ops/state_dir.rs:161, packages/d2b-broker/src/ops/state_dir.rs:204, packages/d2b-broker/src/ops/state_dir.rs:211] + evidence: docs seeds 102/0 as above; field-level `///` comments exist (e.g. mode units, vm_id_or_scope)but no item-level contract on any of the nine pub items, and `prepare_dir`'s root-ownership refusal guard is explained only in code comments. + +## perf +- d2b-broker-p7#7 sev=medium blast=wide effort=M verdict=actionable - recv_json_frame allocates and zeroes a 1 MiB buffer (`MAX_FRAME_SIZE + 4`)per received frame on every broker/client envelope path - fix: peek the 4-byte length prefix (`recvmsg` with `MSG_PEEK`)then allocate `declared + 4` exactly,, or thread a reusable buffer through the receive path; apply the same size-exactness to `recv_json_frame_with_fds` - [packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125] + evidence: targeted grep `vec!\[0_u8; MAX_FRAME_SIZE` = 1 hit (protocol.rs:86; the fd variant passes the same 1 MiB ceiling at 125);`Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` seed = 44 hits; the same 1 MiB per-receive pattern appears at sibling sites d2bd-runtime/src/unix_transport.rs:207,280 and d2b-contracts-broker/src/kernel_client.rs:202 (candidate for cross-crate consolidation); static (unmeasured) - no benchmark exists. + + + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope`=9 (all 9 are `std::thread::spawn` sites in `#[cfg(test)]` fake QMP servers), `\bMutex<|\bRwLock<`=0, `Atomic\w+|Ordering::`=0, `thread_local!|unsafe impl (Send|Sync) for`=0; no production threads,locks, or atomics in scope. + + + +## async +- d2b-broker-p7#8 sev=high blast=wide effort=S verdict=actionable - write_redacted_registry_index_at_path resolves the fixed d2bd group via nss `Group::from_name` synchronously on an executor worker on every registry write (enroll/refresh/boot) - fix: resolve the gid once (lazy static or serve-time config injected into the ops context)and return `MediaOpError::Registry` on absence, so the nss lookup leaves the async hot path - [packages/d2b-broker/src/ops/media.rs:2100, packages/d2b-broker/src/ops/media.rs:2126] + evidence: `Group::from_name` over the assigned files = 1 hit (media.rs:2126; nss lookup is not a clippy::disallowed_method (absent from clippy.toml's disallowed list, so not tracked by the blocking census - actionable per U1 (d) 2/4); static (unmeasured)per-write latency``` + +## unsafe +- clean: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=7 (all 7 are safe std constructors `io::Error::from_raw_os_error` at protocol.rs:383/kernel_ops.rs:2073-2074 and `FileType::from_raw_mode` at media.rs:1798,1838), `unsafe_code`=0; no `unsafe` blocks in scope (consistent with U1 (d) 8's exception set). + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0 all zero; no foreign-caller boundary in this part) + +## macro +- clean: seeds `macro_rules!`=2, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; the two catalog macros (`wire_variants!` at catalog.rs:301,and `audit_fields!` at catalog.rs:373)are deliberate impl-per-enum generators with narrowest fragment specifiers and a documented completeness-gate purpose - not findings. + + + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]`=74 (src) + 58 (tests/), asserts=206 (src) + 219 (tests/), `#\[ignore\]`=0 (src+tests); reviewed suites are behavioral gates (catalog audit gates, QMP fake-server command-sequence tests, state_dir fs/posture regressions, broker protocol fd round-trips, profile/separation/retirement integration matrix) - no cannot-fail tests found. + + + + + +## Coverage +- idiom: clean (seeds ran: 0/0/14) +- own: 1 finding(s) +- type: 1 finding(s) +- api: 1 finding(s) +- err: clean (seeds ran: 289/28/1/3; sampled: 50 of 321) +- serde: clean (seeds ran: 13/46/0/36) +- obs: clean (seeds ran: 0/1/0/4) +- docs: 3 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 9/0/0/0) +- async: 1 finding(s) +- unsafe: clean (seeds ran: 0/0/7/0) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign-caller boundary in this part) +- macro: clean (seeds ran: 2/0/0/0) +- test: clean (seeds ran: 74+58/206+219/0+0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md new file mode 100644 index 000000000..45e15a433 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md @@ -0,0 +1,83 @@ +# d2b-bus-p1 - d2b-bus - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10547 (excl. src/generated/**) | modules: router, authorization, registry, metrics +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/router.rs, src/authorization.rs, src/registry.rs, src/metrics.rs + +## idiom +- d2b-bus-p1#1 sev=low blast=leaf effort=S verdict=actionable - AuthoritativeUnixSubjectResolver::resolve_for_service collects matching subject indices into a Vec and indexes [0], allocating and double-scanning where a take-two iterator would do - fix: replace the collect-then-index with subjects.iter().enumerate().filter_map(...) checked via next() then next().is_some() - [packages/d2b-bus/src/router.rs:1773-1781] + evidence: seeds `for \w+ in 0\.\.` = 4 (3 test loops, 1 fixed-round Feistel loop at router.rs:2641), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 (invariant-preserving Default at router.rs:148, cfg-macro test impls at 2164-2171), `let mut \w+ = (String|Vec)::new\(\)` = 0; the collect-then-index shape is the only production accumulation + +## own +- d2b-bus-p1#2 sev=low blast=leaf effort=S verdict=actionable - ResourceCall::authorization_request clones the whole AssignmentIdentity and mutation Vec just to learn whether ScopedCommitTransport::new rejects them, and invoke clones the same pair again to build the real transport - fix: add a reference-taking ScopedCommitTransport::validate(&AssignmentIdentity, &[ScopedResourceMutation]) in d2b-core-controller and call it from authorization_request so the validation clone disappears - [packages/d2b-bus/src/router.rs:480, packages/d2b-bus/src/router.rs:2928] + evidence: seeds `\.clone\(\)` = 316 (260 router + 41 authorization + 15 registry; production sites are owned-value constructions for RouteKey/SessionAuthorizationRequest/Arc handles), `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 44, `Rc<|RefCell<|Arc and scope: Option that are always both Some or both None, with a runtime validate_scoped re-check at every use site to keep the pair in sync - fix: fold the pair into one Option<(AssignmentIdentity, ScopedResourceScope)> or a ScopedQuery struct so the one-Some state is unrepresentable and the re-validation disappears - [packages/d2b-bus/src/router.rs:218-219, packages/d2b-bus/src/router.rs:298-337] + evidence: seeds `fn validate_\w+|fn check_\w+` = 7 (boundary validators), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the Option pair is the named skill smell, enforced only by construction plus runtime checks +- d2b-bus-p1#4 sev=low blast=leaf effort=M verdict=actionable - UnixSubjectRecord holds expected_peer: Option and expected_peer_uid: Option where exactly one is always Some, and bind() ORs the two options at match time as if the state were open - fix: replace the pair with an enum (Exact(PeerCredentials) | Uid(u32)) so the exactly-one invariant is structural and the runtime OR branch disappears - [packages/d2b-bus/src/router.rs:1445-1446, packages/d2b-bus/src/router.rs:1667-1674] + evidence: seeds `fn validate_\w+|fn check_\w+` = 7, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the pair is enforced by the two constructor families (new vs guest_for_uid/provider_for_uid) and branched on at bind and resolve_for_service + +## api +- d2b-bus-p1#5 sev=medium blast=leaf effort=S verdict=actionable - ZoneBus exposes eight pub constructors but only new, with_interaction_subject_issuer, and with_clock_observer_and_metrics_and_interaction_subject_issuer have production callers; with_observer, with_observer_and_metrics, with_clock, with_clock_and_observer, and with_clock_observer_and_metrics are internal delegation rungs or test-only - fix: keep the three live constructors pub, move with_clock/with_clock_observer_and_metrics under #[cfg(test)] or pub(crate), and delete or fold with_observer/with_observer_and_metrics/with_clock_and_observer - [packages/d2b-bus/src/router.rs:1208, packages/d2b-bus/src/router.rs:1224, packages/d2b-bus/src/router.rs:1258, packages/d2b-bus/src/router.rs:1267, packages/d2b-bus/src/router.rs:1287] + evidence: census: `ZoneBus::` over packages/ = 4 files; external ctor calls = new (d2bd/src/resource_runtime.rs:3426, d2bd-runtime/src/resource_runtime_support.rs:3432), with_interaction_subject_issuer (d2bd/src/interaction_composition.rs:4879), with_clock_observer_and_metrics_and_interaction_subject_issuer (d2bd/src/interaction_composition.rs:6976); with_clock/with_clock_observer_and_metrics = test-only (router.rs:4946, 5422, session_seam_tests.rs:578); the remaining three = 0 callers anywhere; prior relay-island surface cut U12 applied (docs/explanation/over-engineering-audit-record.md:830) and its cross-crate ownership refusal (docs/audits/2026-09-23-ponytail-audit/README.md:153) consulted, not re-proposed +- d2b-bus-p1#6 sev=medium blast=leaf effort=S verdict=actionable - native_authorizer() returns Arc in a pub signature on both BusAuthorizer and ZoneBus and has zero callers anywhere in the workspace, so the shared-authority accessor is dead surface that also leaks the Arc type - fix: remove both accessors or reduce them to pub(crate) until a daemon consumer exists - [packages/d2b-bus/src/authorization.rs:75, packages/d2b-bus/src/router.rs:1415-1416] + evidence: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits, both this accessor pair; census: `native_authorizer` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both inside d2b-bus (definition plus the ZoneBus delegation) + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(` = 459 (318 router + 133 authorization + 2 registry + 6 metrics; production sites are only router.rs:90 and 4158 named-invariant expects plus the fixed-ref expects at 2219-2222 and 3119-3230, all card false positives), `let _ = |\.ok\(\);` = 31 (oneshot best-effort sends and deliberate metric-emit swallows), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 8 (7 test panics, 1 unreachable! on the impossible AssignmentVerb::CommitBatch variant at router.rs:712), `enum \w*Error` = 5 (closed taxonomies with class accessors, no string-matching callers) + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 2 (metrics.rs:427 production frame construction following d2b-telemetry's emit_metric pattern, authorization.rs:933 test helper); no derives, no deserialization, no untrusted input crossing in this partition + +## obs +- N/A: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\(\"` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0 real (the 13 raw matches are ApiCatalog:: false positives); the crate declares no tracing/log dependency in packages/d2b-bus/Cargo.toml + +## docs +- d2b-bus-p1#7 sev=medium blast=leaf effort=S verdict=actionable - The exported observer contract BusEvent, BusFailureReason, BusObserver, and NoopBusObserver carry no doc comments, so the semantics of the 17 failure reasons and when record fires are undocumented for the d2bd consumer - fix: add module-level or item docs stating when each event is recorded and what each BusFailureReason variant means - [packages/d2b-bus/src/router.rs:1126, packages/d2b-bus/src/router.rs:1135, packages/d2b-bus/src/router.rs:1187, packages/d2b-bus/src/router.rs:1192] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158; these four items have no preceding /// line while every neighboring item does; NoopBusObserver is consumed by d2bd/src/interaction_composition.rs:6981 +- d2b-bus-p1#8 sev=low blast=leaf effort=S verdict=actionable - DEFAULT_MAX_ROUTES_PER_SESSION and DEFAULT_MAX_TOTAL_ROUTES are pub consts without docs while their sibling DEFAULT_MAX_PAYLOAD_BYTES has one - fix: add one-line docs naming the bound each constant sets - [packages/d2b-bus/src/router.rs:67-68] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158; lines 67-68 have no preceding /// comment +- d2b-bus-p1#9 sev=low blast=leaf effort=S verdict=actionable - CommittedInteractionSubjectInstallBody (consumed by d2bd), AuthorizationErrorClass, EndpointSessionFailure::class/code/remediation, and the metrics label accessors are pub items without doc comments - fix: add one-line docs to each, at least on the struct and the class enum - [packages/d2b-bus/src/router.rs:1895, packages/d2b-bus/src/authorization.rs:401, packages/d2b-bus/src/registry.rs:259-267, packages/d2b-bus/src/metrics.rs:110] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158; these items have no preceding /// line; CommittedInteractionSubjectInstallBody is constructed by d2bd/src/resource_runtime.rs:591 +- d2b-bus-p1#10 sev=low blast=leaf effort=S verdict=actionable - No pub Result-returning item carries a canonical # Errors section anywhere in the partition (94 Result-returning pub items, zero sections), so the failure conditions of non-obvious APIs such as BusIngress::invoke and ZoneRegistrar::register_component_session are undocumented - fix: add # Errors sections to the non-obvious Result-returning pub items, starting with the bus entry points - [packages/d2b-bus/src/router.rs:3709, packages/d2b-bus/src/router.rs:3261, packages/d2b-bus/src/registry.rs:366] + evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 158, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 94 + +## perf +- d2b-bus-p1#11 sev=low blast=leaf effort=S verdict=actionable - The WatchSink delivery path copies every watch frame payload with frame.payload().to_vec() before send_and_wait_ack, allocating a fresh Vec per frame on the watch-delivery path (the recorded kept-half credit path, B1, docs/explanation/over-engineering-audit-record.md:463) - fix: pass the payload slice through OutgoingStream::send_and_wait_ack (streams.rs:661) or clone once at the bridge so per-frame allocation is avoided - [packages/d2b-bus/src/router.rs:4228-4235] + evidence: `format!\(` = 13 (12 doc/test, 1 cold bootstrap path at router.rs:2221), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 87 (mostly tests), `\.to_string\(\)` = 5 (test helpers); static (unmeasured), no benchmark exists + +## conc +- d2b-bus-p1#12 sev=low blast=leaf effort=S verdict=actionable - RouteLeaseState wraps a single bool in Mutex, paying a lock for one flag that an atomic would serve - fix: replace revoked: Mutex with AtomicBool and use Acquire/Release in with_active and remove - [packages/d2b-bus/src/registry.rs:522-523, packages/d2b-bus/src/registry.rs:573-582] + evidence: seeds `std::thread::|thread::spawn|thread::scope` = 1 (test-only thread::scope at router.rs:4791), `\bMutex<|\bRwLock<` = 25 (all std Mutex with into_inner poisoning recovery, brief critical sections, none across await), `Atomic\w+|Ordering::` = 49 (ManualClock AcqRel/Acquire pair, ComponentActivity Release/Acquire valid flags, test counters), `thread_local!|unsafe impl (Send|Sync) for` = 0 + +## async +- clean: seeds `async fn|async move|\.await` = 203 (198 router + 1 authorization + 4 registry), `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 11 (1 production tokio::spawn at router.rs:2426 for the response dispatcher, 10 test join! sites), `tokio::sync::(Mutex|RwLock|Notify)` = 2 (Notify in the cfg(test) hook struct at 837-838 plus one test import), `#\[tokio::(main|test)\]|Runtime::block_on` = 24; checked: no std lock held across await (all std Mutex critical sections are brief with sanctioned disallowed-method allows and comments), AsyncMutex only for session and inbound receivers, select! biased with cancellation first, lease Drop aborts on cancellation and deadline paths + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; crate lints table forbids unsafe_code (packages/d2b-bus/Cargo.toml:9), so the lens is not applicable + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the partition crosses no foreign boundary + +## macro +- clean: seeds `macro_rules!` = 1 (router.rs:2162 mutate_component_session_admission_trait!, a cfg-gated compile-assertion harness with narrow ident fragment specifiers and unreachable! bodies, deliberate), `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 + +## test +- d2b-bus-p1#13 sev=high blast=leaf effort=S verdict=actionable - emitter_records_only_closed_bus_labels exercises every BusTelemetry method but asserts nothing, and every emit outcome is swallowed by `let _ = self.emit(...)` inside BusMetrics, so a label drifting out of the closed set passes silently - fix: make the test assert something observable, for example return EmitOutcome from a test-visible emit path or expose a read-back of the BoundedEmitter queue in d2b-telemetry, and assert Ok per call (route review-pass) - [packages/d2b-bus/src/metrics.rs:612-633, packages/d2b-bus/src/metrics.rs:451-534] + evidence: seeds `#\[test\]|#\[tokio::test\]` = 62 (40 router + 19 authorization + 3 metrics), `assert_eq!\(|assert_ne!\(|assert!\(` = heavy across the suite, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the named test contains zero assertion calls and no panic path, so it cannot fail on the property it names; the remaining 61 tests assert observable behavior (delivery counts, error variants, revocation races with Notify hooks, start_paused timeouts, redaction of Debug output); the tests/ui compile-fail fixtures (4 files) belong to the session_seam_tests macro surface in part 2 + +## Coverage +- idiom: 1 finding +- own: 1 finding +- type: 2 findings +- api: 2 findings +- err: clean (seeds ran: 459/31/8/5; production unwrap/expect sites are fixed-ref expects and named-invariant expects per card false positives) +- serde: clean (seeds ran: 0/0/0/2; the 2 s4 hits are frame construction following the d2b-telemetry pattern and a test helper) +- obs: N/A (seeds: 0/0/0/0 real; no tracing/log dependency in the crate manifest) +- docs: 4 findings +- perf: 1 finding +- conc: 1 finding +- async: clean (seeds ran: 203/11/2/24; no lock held across await, biased select with cancellation first, lease Drop aborts) +- unsafe: N/A (seeds: 0/0/0; unsafe_code = "forbid" in the crate lints table) +- ffi: N/A (seeds: 0/0/0/0; no foreign boundary in the partition) +- macro: clean (seeds ran: 1/0/0/0; single cfg-gated compile-assertion harness macro) +- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md new file mode 100644 index 000000000..dc68257ca --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md @@ -0,0 +1,87 @@ +# d2b-bus-p2 - d2b-bus - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10327 (excl. src/generated/**) | modules: session/ (contract, enrollment, mod, noise_vectors, prologue, zone_link), session_seam_tests, streams, operations, wire, lib +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: src/session/**, src/session_seam_tests.rs, src/streams.rs, src/operations.rs, src/wire.rs, src/lib.rs + +## idiom +- d2b-bus-p2#1 sev=low blast=leaf effort=S verdict=actionable - `PendingCancelDeliveries::abort_destination` collects into a `Vec` inside a `retain` closure (statement-style accumulation with a side effect in the predicate) instead of partitioning the entries - fix: `let (aborted, kept): (Vec<_>, Vec<_>) = entries.drain(..).partition(|entry| entry.destination == session); *entries = kept;` and abort the drained handles - [packages/d2b-bus/src/operations.rs:302-310] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 3 hits; the other two hits are test task vectors (streams.rs:1221, 1283) where a collect would obscure the spawn loop, and the hand-written `impl Default for StreamLimits` (streams.rs:77) and `impl PartialEq/Eq for OperationAttempt` (operations.rs:77-83) are deliberate (nonzero defaults; identity semantics) and are not findings +- clean: seeds `for \w+ in 0\.\.` = 10 hits, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits, `let mut \w+ = (String|Vec)::new\(\)` = 3 hits; the index loops are bounded retry loops over queues being mutated (streams.rs:368-402) or test spawn loops, so plain loops are the right shape; one finding above + +## own +- d2b-bus-p2#2 sev=low blast=leaf effort=S verdict=actionable - `SubjectContextDigest::of_subject` builds six owned `String`s (four `to_owned()` on `&str`/`&'static str` fields plus two `to_canonical_string()` calls) only to hash length-prefixed bytes - fix: iterate `&[&str]` slices (the label helpers already return `&'static str`, and the subject/service/purpose accessors expose `&str`) and feed `len()` and `as_bytes()` directly, dropping all six allocations per digest - [packages/d2b-bus/src/session/prologue.rs:72-78] + evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 26 hits; the four avoidable `to_owned()` calls are at prologue.rs:74-77; the remaining hits are test fixtures and wire-rendering boundaries +- d2b-bus-p2#3 sev=low blast=leaf effort=M verdict=actionable - `VerifiedRouteAdmission::revalidate` clones the whole admission body (including the session binding) on every call, and `ZoneLinkSession::admit`/`is_open` invoke it on every forwarded operation - fix: add a by-reference verification path (a `verify_body(&self, body: &RouteAdmissionBody)` helper or a `revalidate` that digests `&self.body` without rebuilding owned evidence) so the re-check allocates nothing - [packages/d2b-bus/src/session/contract.rs:1046-1056, packages/d2b-bus/src/session/zone_link.rs:147] + evidence: seed `\.clone\(\)` = 132 hits; census: `\.revalidate\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 5 sites (contract.rs:1046 definition plus zone_link.rs:147, 218, 256, 358); the clone at contract.rs:1054 exists only to feed the consuming `verify` signature +- clean: seeds `Rc<|RefCell<|Arc` and `liveness: Option` that are always both `Some` or both `None` (the two constructors set them in lockstep), so a half-set lane is representable and would silently skip admission revalidation - fix: fold the pair into one `established: Option` holding both values (the test lane stays the `None` case), making the impossible combination unconstructible - [packages/d2b-bus/src/session/zone_link.rs:111-117] + evidence: type seeds (`fn validate_\w+|fn check_\w+`, `is_\w+: bool|\w+_flag: bool`, `(mode|kind|state): String`) = 0/0/0 hits; lens applicable because the part declares structs and enums; the lockstep invariant is read from the only two constructors at zone_link.rs:141-195 +- clean: no boolean-flag soup or stringly-typed state found; the enrollment machine already models its five states as an enum with checked transitions, and the `revoked` marker with a persisted record is a documented crash-window state (enrollment.rs:392-396), not a flag finding + +## api +- d2b-bus-p2#5 sev=medium blast=leaf effort=S verdict=actionable - two public types named `Cancellation` are reachable from the crate root: `d2b_bus::Cancellation` (operations) and `d2b_bus::session::Cancellation` (the re-exported `d2b_session::Cancellation`), so a caller importing both modules gets a name collision and can hand the wrong token to a handler - fix: drop `Cancellation` from the `d2b_session` re-export block in session/mod.rs (the bus's own token shadows the need) or rename one of the two - [packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97] + evidence: seed `^\s*pub use ` = 15 hits; census: `d2b_bus::session::Cancellation` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 qualified uses today, but the in-crate distinction is already live at router.rs:2663-2664 where `Cancellation` and `d2b_session::Cancellation` sit in one struct +- clean: no `Arc`/`Rc`/`Box`/`RefCell` in a public signature beyond the deliberate `Arc`/`Arc` observer injection (streams.rs:149-150) and the `Arc`-shared `ZoneLinkSession` driver owner, both with private fields; the lib.rs re-export arms are the house single-surface pattern + +## err +- d2b-bus-p2#6 sev=medium blast=leaf effort=S verdict=actionable - public `ZoneBoundPolicyIdentity::with_provider` returns `Result`, a string a caller must string-match instead of matching on a variant - fix: return a closed error type (reuse `ZonePolicyError` with a new `NotProviderRef` variant, or a small `ZoneBoundPolicyIdentityError` enum) for the single failure condition - [packages/d2b-bus/src/wire.rs:49-56] + evidence: seed `-> Result<` = 56 hits; census: `ZoneBoundPolicyIdentity::with_provider` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both in wire.rs tests (wire.rs:171, 179), so the fix carries no external call-site churn +- clean: seeds `\.unwrap\(\)|\.expect\(` = 827 hits (the overwhelming majority inside `#[cfg(test)]` modules and test fixtures, which the card exempts), `let _ = ` = 7 hits (the one in production is the deliberate fence compare_exchange at zone_link.rs:232, documented as keeping the stronger fence), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 31 hits (test assertions and the `unimplemented` test-driver helper), `enum \w*Error` = 6 hits; production `expect`s are internal-invariant assertions with named reasons (streams.rs:372-408, operations.rs:487) and every std Mutex poison is recovered via `into_inner()`; one finding above + +## serde +- N/A: seeds `derive\([^)]*(De)?[Ss]erialize`, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`, `impl .*Deserialize.*for`, `serde_json::from_|serde_json::to_` = 0/0/0/0 hits over the part; the crate's serde_json dependency is consumed in part 1 (router.rs), so this part crosses no serde boundary + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 2 (both false positives: `ApiCatalog::standard()` in session_seam_tests.rs:582 and 1289 matches `log::` inside the word "catalog"); the part emits no telemetry at all and the crate declares no tracing/log dependency, so there is nothing to judge beyond absence + +## docs +- d2b-bus-p2#7 sev=medium blast=leaf effort=S verdict=actionable - `pub struct Cancellation` (re-exported at the crate root) has no doc comment while every sibling public item does, leaving the opaque token's contract (crate-private construction, one-attempt observation, `is_cancelled`) undocumented - fix: add a `///` doc comment stating the token is minted only by the bus and observes one operation attempt - [packages/d2b-bus/src/operations.rs:124-125] + evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 137 hits, `/// # (Examples|Errors|Panics|Safety)` = 0; the struct at operations.rs:125 is the only root-re-exported item without a doc comment +- d2b-bus-p2#8 sev=low blast=leaf effort=M verdict=actionable - public `Result`-returning constructors and accessors (`StreamName::parse`, `OperationId::parse`, `ZoneBoundPolicyIdentity::digest`, `ZoneEndpointPolicy::lower`) carry no `# Errors` section naming which condition produces which failure, even though the failure conditions are closed and enumerated in the error enums - fix: add `# Errors` sections to the public parse/lower/digest items - [packages/d2b-bus/src/streams.rs:39-40, packages/d2b-bus/src/operations.rs:24-25, packages/d2b-bus/src/wire.rs:79-82, packages/d2b-bus/src/session/contract.rs:164-165] + evidence: docs seeds: `-> Result<` = 56 hits, `/// # (Examples|Errors|Panics|Safety)` = 0; the repo style is one-line prose docs without canonical sections, so this is a consistency proposal rather than a coverage gap +- clean: module docs are present and substantive (session/mod.rs, prologue.rs, contract.rs, enrollment.rs, zone_link.rs), the redacted `Debug` impls are deliberate and tested, and the compile_fail doctests at contract.rs:312-315 and 760-763 run under `cargo test --doc` + +## perf +- d2b-bus-p2#9 sev=low blast=leaf effort=M verdict=actionable - `OutgoingStream::send_wait` clones the whole payload on every backpressure wakeup because `StreamBridge::send` consumes the `Vec` and drops it on rejection, so a frame up to `max_frame_bytes` (64 KiB) is re-allocated per retry on the bounded-watch delivery path - fix: have `send` return the rejected payload (for example `Result<(), (StreamError, Vec)>`) or split an admit-check from the enqueue so the loop moves the buffer instead of cloning - [packages/d2b-bus/src/streams.rs:642-658] + evidence: static (unmeasured); seed `\.clone\(\)` = 132 hits; census: `send_wait|send_and_wait_ack` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 4 hits, with the production caller at router.rs:4188 +- clean: seeds `format!\(` = 32 hits (all in error paths, digest construction, and test fixtures, which the card exempts), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 31 hits (mostly empty-case collection construction where the empty case is common, plus test fixtures), `\.to_string\(\)` = 1 hit (a test assertion); the BTreeMap choices are for deterministic iteration, and `direction_gauges` already uses saturating accumulation + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 10, `Atomic\w+|Ordering::` = 23, `thread_local!|unsafe impl (Send|Sync) for` = 0; every Mutex and atomic use is a brief non-suspending critical section with a sanctioned `synchronous path` allow (contract.rs:1009-1054, operations.rs:295, streams.rs:562) or a cfg(test) helper, poison is recovered via `into_inner()` rather than `unwrap`, and the fence/attempt/cancellation atomics use correct Acquire/Release pairs with written ordering arguments + +## async +- clean: seeds `async fn|async move|\.await` = 346, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 29, `tokio::sync::(Mutex|RwLock|Notify)` = 2 (the two `use tokio::sync::Notify;` imports), `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the Notify waiters are created before the condition check with the future pinned and `enable()`d (streams.rs:642-676, operations.rs:150-158), which is the correct tokio pattern, no guard is held across an `.await`, and all std-Mutex touches are brief critical sections with sanctioned allows + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0/0/0 hits; seed 4 alone (`unsafe_code = "forbid"` in the manifest) does not make the lens applicable + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char` = 0/0/0/0 hits; the part crosses no foreign-language boundary + +## macro +- N/A: seeds `macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned` = 0/0/0/0 hits over the part (the crate's single macro hit is in part 1); no macro definitions or proc-macro surface + +## test +- d2b-bus-p2#10 sev=medium blast=leaf effort=M verdict=actionable - session_seam_tests.rs waits for service readiness with fixed-count yield and poll loops (`for _ in 0..16 { tokio::task::yield_now().await }` at 1623 and 1808, `for attempt in 0..32` at 1882, `for attempt in 0..8` plus an inner yield loop at 1941-1960), which is machine-dependent and can fail spuriously on a loaded runner - fix: replace with condition-driven waits (oneshot or Notify), the deterministic pattern the same file already uses elsewhere (advance_virtual, dispatched_wait) - [packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_tests.rs:1808-1810, packages/d2b-bus/src/session_seam_tests.rs:1882-1884, packages/d2b-bus/src/session_seam_tests.rs:1941-1960] + evidence: seed `for \w+ in 0\.\.` = 10 hits; the four readiness loops are the only machine-dependent waits in the part, and the file's own comment blocks document the deterministic counterpart pattern +- d2b-bus-p2#11 sev=low blast=leaf effort=S verdict=actionable - `cancel_retry_cannot_reach_a_same_id_replacement_while_tombstone_is_retained` pins the full `Display` sentence of `OperationError::RetainedOperationId`, so a wording change fails the test even though the contract is the variant and its `as_str()` label - fix: assert the variant (the surrounding code already matches on variants) and drop the `to_string()` equality - [packages/d2b-bus/src/operations.rs:1057-1060] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 328 hits; this is the only assertion in the part that pins a `Display` string rather than a variant or label +- clean: seeds `#\[test\]|#\[tokio::test\]` = 113, `assert_eq!\(|assert_ne!\(|assert!\(` = 328, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the suite is strong overall - frozen Noise golden vectors (noise_vectors.rs), deterministic concurrency tests with Barriers and start_paused virtual time (streams.rs:984-1062), error-variant assertions throughout, and the child-process peer test is a documented subprocess pattern; two findings above + +## Coverage +- idiom: 1 finding (seeds 10/3/3) +- own: 2 findings (seeds 132/26/0/0) +- type: 1 finding (seeds 0/0/0; applicable via struct/enum presence) +- api: 1 finding (seeds 137/0/15) +- err: 1 finding (seeds 827/7/31/6) +- serde: N/A (seeds 0/0/0/0 all zero; no serde boundary in this part) +- obs: clean (seeds 0/0/0/2; both hits are `log::` false positives inside `ApiCatalog::`) +- docs: 2 findings (seeds 137/0/56) +- perf: 1 finding (seeds 32/31/1) +- conc: clean (seeds 0/10/23/0) +- async: clean (seeds 346/29/2/0) +- unsafe: N/A (seeds 0/0/0; manifest forbids unsafe_code) +- ffi: N/A (seeds 0/0/0/0 all zero) +- macro: N/A (seeds 0/0/0/0 all zero) +- test: 2 findings (seeds 113/328/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md new file mode 100644 index 000000000..5cb869590 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md @@ -0,0 +1,87 @@ +# d2b-contracts-broker - d2b-contracts-broker +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5215 (excl. src/generated/**) | modules: whole crate (broker_wire, host_generation, kernel_client, lib, tests/wire.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) + +## idiom +- d2b-contracts-broker#1 sev=low blast=leaf effort=S verdict=actionable - `response.refusal.clone().unwrap_or_default()` runs inside an `if response.refusal.is_some()` branch, so the default is unreachable and the value is cloned twice - fix: restructure to `if let Some(code) = response.refusal.clone()` or match on the Option once, returning `KernelInvokeError::Refused` in the Some arm - [packages/d2b-contracts-broker/src/kernel_client.rs:225-227] + evidence: seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 1 hit; the is_some/unwrap_or_default pair read at kernel_client.rs:225-227 +- d2b-contracts-broker#2 sev=low blast=leaf effort=S verdict=actionable - `ApplyHostGenerationHandoff::validate` carries a caller-role check that can never fire: `HandoffCallerRole` has exactly two variants and the `!matches!(Lifecycle | Admin)` guard is always false, so the `InvalidTransition` arm is dead code in a security-adjacent validation path - fix: delete the branch (or add the missing third role if one was intended) - [packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broker/src/host_generation.rs:131-137] + evidence: seed 3 = 1 hit; dead branch confirmed by reading the two-variant enum at host_generation.rs:131-137 +- d2b-contracts-broker#3 sev=low blast=leaf effort=S verdict=actionable - `BrokerCallerRole::for_display()` returns the bare label `"RootUid"` for `RootUid` while every sibling arm returns a stable `d2b-*` audit label, and the value lands in the broker's `peer_role` audit records - fix: align the arm to the scheme, e.g. `"d2b-root"`, and pin it in the existing label test - [packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/src/broker_wire.rs:3149-3163] + evidence: seed 3 = 1 hit; census: `for_display` over packages/ = 12 hits, consumed as `peer_role` audit field at packages/d2b-broker/src/runtime.rs:1654,1731,2456 +- clean: seeds ran (0/0/1); the single `let mut received = Vec::new()` accumulation loop is a side-effect fd-collection drain where the plain loop is the skill's own preference; no index loops, no hand-written derives over derivable ones + +## own +- clean: seeds ran (13/71/0/0); every clone/to_owned is explainable - audit-join string materialization (broker_wire.rs:643,651,698), request-field moves into the envelope (kernel_client.rs:139-145), and the refusal clone before the response is moved (kernel_client.rs:226-227); no Rc/RefCell/Arc/Cow anywhere + +## type +- d2b-contracts-broker#4 sev=medium blast=leaf effort=S verdict=actionable - `HandoffCoordinator.source_remains_usable: bool` is fully derivable from `state` (false iff `Completed`, true in every other phase), so the pair `{ state: Completed, source_remains_usable: true }` is an illegal state constructible through durable-record deserialization and the two fields can desync - fix: drop the field, derive the accessor from `self.state != HandoffState::Completed`, keep `#[serde(default)]` for old broker records (the wire `ApplyHostGenerationHandoffResponse.source_remains_usable` field stays as-is) - [packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broker/src/host_generation.rs:294-315] + evidence: seed 1 `fn validate_\w+|fn check_\w+` = 2 hits (host_generation.rs:76,256); field/accessor/mutations read at host_generation.rs:226-316; census: `source_remains_usable` over packages/ = 11 hits, consumers use the accessor (d2b-broker/src/ops/host_generation_handoff.rs:390) or the response's own wire field (d2b-provider-activation-nixos driver.rs:1331) +- d2b-contracts-broker#5 sev=medium blast=leaf effort=S verdict=actionable - `CanonicalAuditDigest(pub String)` exposes a public field that bypasses the SHA-256-spelling invariant its `parse` constructor and hand-written `Deserialize` enforce, so a literal construction can mint an invalid digest - fix: make the tuple field private and keep `as_str()` (serde transparent and JsonSchema work with a private field; wire shape unchanged) - [packages/d2b-contracts-broker/src/broker_wire.rs:2805, packages/d2b-contracts-broker/src/broker_wire.rs:2807-2821] + evidence: seed 3 `(mode|kind|state): String` = 3 hits, all wire `kind` code strings (broker_wire.rs:971,2994,3018) that are schema-pinned false positives; census: `CanonicalAuditDigest` over packages/ = 13 hits, every production construction goes through `parse` (d2b-broker/src/runtime.rs:2419,2442; d2bd-runtime/src/broker_transport.rs:63) +- clean: seeds ran (2/0/3); the three `kind: String` fields are wire code strings mirroring the pinned schema (false positive per card); the handoff state machine's runtime phase checks are the deliberate replay-safe design, not a typestate candidate under the stopping rule + +## api +- d2b-contracts-broker#6 sev=medium blast=wide effort=S verdict=needs-contract - `BrokerRequestEnvelope.test_peer_uid: Option` is a test-only peer-uid override carried on the production wire envelope (serialized, schema-visible), honored only under the broker's `config.test_mode` gate - fix: move the override out of the wire type into the broker's test harness (e.g. a test-only envelope wrapper or a `#[cfg(test)]`-visible field) so the production contract carries no test seam - [packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtime.rs:1628-1632] + evidence: seed 1 = 198 pub items (contract-crate wide vocabulary is the card's false positive), seed 2 = 0; census: `test_peer_uid` over packages/ = 26 hits across d2b-broker bootstrap probe helpers, five broker test files, d2bd, d2bd-runtime and kernel_client +- d2b-contracts-broker#7 sev=low blast=family effort=S verdict=actionable - `pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}` at broker_wire.rs:13 re-exports another crate's types into this crate's surface, making each item reachable at two paths (`d2b_contracts::audit_wire::*` and `d2b_contracts_broker::broker_wire::*`), off the house single-surface pattern which places re-export arms in lib.rs - fix: move the re-export to lib.rs or drop it and let consumers import from d2b_contracts (sibling d2b-contracts-control/src/public_wire.rs:1 repeats the pattern; X3 may merge the family) - [packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib.rs:7-11] + evidence: seed 3 `^\s*pub use ` = 4 hits; census: `AuditExportEntry|AuditExportCursor|AuditExportErrorCode` over packages/ = 40 hits, consumers import via the broker_wire path (d2b-broker/src/audit.rs:29, d2b/src/dispatch.rs:22, d2bd-runtime/src/wire.rs:544) +- clean: seeds ran (198/0/4); the 198-item pub surface is the deliberate contract-crate wire vocabulary (card false positive); no Arc/Rc/Box/RefCell in signatures; `RunnerLaunchArgs` and `CanonicalAuditDigest` show the private-field-plus-accessor shape; lib.rs re-export arms follow the house pattern + +## err +- clean: seeds ran (114/0/26/3); every unwrap/expect/panic/unreachable site (114 unwrap/expect, 26 panic/unreachable, all listed 3223-4282) sits inside `#[cfg(test)]` (broker_wire.rs tests module, tests/wire.rs) - no panic site reachable from caller input; the three error enums (HandoffError, RunnerLaunchArgsError, KernelInvokeError) are split by caller action with stable Display codes; no swallowed Results (`let _ =` = 0) + +## serde +- d2b-contracts-broker#8 sev=medium blast=wide effort=S verdict=needs-contract - `OpenUnitPidfdRequest` and `StopUnitRequest` combine `#[serde(flatten)] pub unit: UnitRequest` with `deny_unknown_fields` on the containing struct, and serde ignores `deny_unknown_fields` on any type using flatten, so unknown fields in these two wire requests are silently accepted instead of refused - fix: drop the flatten (duplicate the UnitRequest fields or deserialize into a tagged wrapper) or accept-and-validate unknown fields explicitly; the wire admission change needs contract review - [packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/src/broker_wire.rs:1783-1834] + evidence: seed 2 `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 307 hits; the two flatten sites read at broker_wire.rs:1841,1852 with the outer deny_unknown_fields at 1838,1849 +- clean: seeds ran (134/307/0/35); hand-written Deserialize impls (ExportBrokerAuditResponse:2200, RunnerLaunchArgs:2575, CanonicalAuditDigest:2831) are live admission gates in the recorded refusal class (over-engineering-audit-record.md) and validate real invariants; enum representations (adjacent on BrokerRequest/BrokerResponse, internal on ForwardOperationOutcome/BrokerNotification with `#[serde(other)]`) and the pervasive deny_unknown_fields are deliberate pinned wire shapes + +## obs +- N/A: seeds 0/0/0/0 (case-sensitive run; the only case-insensitive `log::` match is the doc-prose word `AuditLog::write_entry` at broker_wire.rs:547) and the crate has no tracing/log dependency (packages/d2b-contracts-broker/Cargo.toml) + +## docs +- d2b-contracts-broker#9 sev=medium blast=leaf effort=S verdict=actionable - every Result-returning public fn lacks the canonical `# Errors` section (seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits crate-wide), so the failure conditions of the handoff state machine, the launch-args bounds, and the kernel client are only recoverable from enum docs - fix: add `# Errors` sections naming the `HandoffError`/`RunnerLaunchArgsError`/`KernelInvokeError` conditions to `SourceGenerationCompatibilityFloorV1::new`, `begin_handoff`, the `HandoffCoordinator` transitions, `RunnerLaunchArgs::new`, and `envelope_invoke_kernel` - [packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src/kernel_client.rs:113, packages/d2b-contracts-broker/src/broker_wire.rs:2495] + evidence: seed 3 `-> Result<` = 15 hits (12 public fns: host_generation.rs:50,80,95,153,260,277,286,295,305; kernel_client.rs:118; broker_wire.rs:2495,2809; the other 3 are Deserialize trait impls), seed 2 = 0 hits +- d2b-contracts-broker#10 sev=low blast=leaf effort=S verdict=actionable - four public fns have no doc comment at all: `BrokerCapabilities::w3`, `RunnerRole::as_str`, `BrokerCallerRole::is_admin_uid`, `BrokerCallerRole::for_display` - fix: one-line contract docs (for_display should document the stable audit-label promise) - [packages/d2b-contracts-broker/src/lib.rs:28, packages/d2b-contracts-broker/src/broker_wire.rs:2444, packages/d2b-contracts-broker/src/broker_wire.rs:2900-2904] + evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 195 hits; the four undocumented items confirmed by reading their neighborhoods +- d2b-contracts-broker#11 sev=low blast=leaf effort=S verdict=actionable - doc-comment polish defects in the FdKind/ForwardOperationRequest contract docs: `present.from` (missing space), CJK full-width periods (the FdKind variant docs end in a CJK period), and comma-adjacent spacing (`positions,in the ... list,of`) - fix: reword those doc lines - [packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/broker_wire.rs:254, packages/d2b-contracts-broker/src/broker_wire.rs:421-430] + evidence: seed 1 = 195 hits; typos read at the cited lines +- clean: seeds ran (195/0/15); the crate's doc discipline is otherwise strong - nearly every pub item carries a contract doc with a load-bearing first sentence, module docs exist in all four modules, and magic values (MAX_FRAME_FDS, DEFAULT_CONTEXT_DEADLINE_MS, MAX_CONTEXT_DEADLINE_MS) document the why + +## perf +- clean: seeds ran (48/2/30); all format!/to_string sites are audit-join rendering (broker_wire.rs:634-730, the card's audit-rendering false positive) or cold error paths (kernel_client.rs:125-223); the two Vec::new() sites are one-shot recvmsg fd collection and test scaffolding; no hot-loop allocation, no attacker-keyed hashing; static (unmeasured) per the card + +## conc +- N/A: seeds 0/0/0/0 (case-sensitive run; the case-insensitive `Atomic\w+` matches were the prose word "atomically" in doc comments at broker_wire.rs:114,2018); no threads, locks, atomics, or unsafe Send/Sync in the crate + +## async +- N/A: seeds 0/0/0/0; no async fn, no .await, no tokio usage anywhere in the crate (kernel_client is a synchronous rustix/socket2 client) + +## unsafe +- N/A: seeds 0/0/0/0; the crate inherits `[lints] workspace = true` with `unsafe_code = "forbid"` (packages/d2b-contracts-broker/Cargo.toml), and no unsafe block, SAFETY comment, or transmute exists + +## ffi +- N/A: seeds 0/0/0/0; no extern "C", no_mangle, repr(C), CStr/CString, or catch_unwind anywhere; the crate crosses no foreign boundary + +## macro +- N/A: seeds 0/0/0/0; no macro_rules!, proc-macro, syn/quote, or $crate usage; the only include is the generated `broker_operation_profiles.rs` (X2's lane) + +## test +- clean: seeds ran (51/127/0/0); 51 `#[test]` (49 in broker_wire.rs tests module, 2 in tests/wire.rs) and ~127 assertions cover wire round-trips, per-field legacy-authority rejection loops with failure messages naming the field, closed-enum matrices, and deliberate wire-constant pins (FD_LEG, STALE_CONTEXT, PROTOCOL_VERSION); no `#[ignore]`, no proptest/insta/rstest; every test can fail on a real regression (the constant pins carry `#[allow(clippy::assertions_on_constants)]` with written reasons) + +## Coverage +- idiom: 3 finding(s) +- own: clean (seeds ran: 13/71/0/0) +- type: 2 finding(s) +- api: 2 finding(s) +- err: clean (seeds ran: 114/0/26/3) +- serde: 1 finding(s) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 3 finding(s) +- perf: clean (seeds ran: 48/2/30) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) +- async: N/A (seeds: 0/0/0/0 all zero; no async code) +- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace `unsafe_code = "forbid"` inherited) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test: clean (seeds ran: 51/127/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md new file mode 100644 index 000000000..d71913112 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md @@ -0,0 +1,90 @@ +# d2b-contracts-control - d2b-contracts-control +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5019 (excl. src/generated/**) | modules: whole crate (cli_output, proxy_readiness, public_wire, terminal_wire, unsafe_local_wire) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- clean: seeds `for \w+ in 0\.\.` / `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` / `let mut \w+ = (String|Vec)::new\(\)` ran at 0/0/0; manual check confirms every hand-written `Debug` impl (TerminalWriteStdin, ExecStartArgs, NamedProcessStreamRequest, ScopeIdentity, ShellName, ...) is a deliberate secret-redaction impl per the idiom card's repo false positives, and all other traits are derived. + +## own +- clean: seeds `\.clone\(\)` / `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` / `Rc<|RefCell<|Arc`, encoding 4 states of which 2 are illegal, guarded only by the runtime `validate_audit_page` at deserialize - fix: replace the pair with an enum (`Complete` / `More(AuditExportCursor)`) so the illegal combos are unrepresentable, deleting `validate_audit_page` - [public_wire.rs:2166, public_wire.rs:2203] + evidence: seed `(mode|kind|state): String` + `fn validate_\w+|fn check_\w+` = 22 hits; the complete/next_cursor invariant is the one Option-pair smell in the crate; wire change so needs-contract. +- d2b-contracts-control#2 sev=low blast=wide effort=L verdict=needs-contract - status DTOs carry stringly-typed state (`mode`, `state`, `kind`, `status` as `String`) mirroring daemon-side vocabularies instead of closed enums - fix: convert the closed vocabularies (realm mode, gateway state, qemu runner/registry state, read-model kind) to kebab-case enums on both daemon and wire sides - [cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672, public_wire.rs:2156] + evidence: seed `(mode|kind|state): String` = 22 hits across cli_output.rs and public_wire.rs; shapes are pinned by docs/reference/cli-output schemas and daemon-api.md, so needs-contract. +- d2b-contracts-control#3 sev=low blast=wide effort=M verdict=needs-contract - `MutationFlags` models dry-run/apply/json as three booleans while the doc comment itself records that "the daemon rejects requests that set neither `dry_run` nor `apply`", i.e. an illegal state the type still represents - fix: encode the mode as an enum variant (e.g. `MutationMode::{DryRun, Apply}` plus a separate json flag) and delete the daemon-side runtime rejection - [public_wire.rs:316, public_wire.rs:311] + evidence: seed `is_\w+: bool|\w+_flag: bool` = 22 hits; the neither-set rejection is documented at public_wire.rs:310-313; wire change so needs-contract. + +## api +- d2b-contracts-control#4 sev=low blast=leaf effort=S verdict=actionable - `StatusServicesOutputV3` and its `from_v2` conversion shim are exported but have zero callers in the workspace; the doc comment says "Used so callers... can be migrated incrementally" but no migration landed - fix: delete `StatusServicesOutputV3` and `from_v2` (or wire the intended caller) - [cli_output.rs:241, cli_output.rs:276] + evidence: census `StatusServicesOutputV3|from_v2` over packages/, nixos-modules/, tests/, docs/reference/, labs = 1 hit (the definition itself); not in the generated v2 wire-protocol.json (xtask WireProtocolSchema imports only AuditOutputV2/AuthStatusOutputV2/ListOutputV2/OpInspectOutputV1/StatusOutputV2/UsbProbeOutputV1, xtask/src/main.rs:19-22). +- d2b-contracts-control#5 sev=low blast=leaf effort=S verdict=actionable - `pub use d2b_contracts::audio::LevelPercent;` in cli_output.rs re-exports a type neither this module nor any external caller uses (public_wire.rs imports LevelPercent from d2b_contracts directly) - fix: delete the re-export - [cli_output.rs:6] + evidence: census `cli_output::LevelPercent` over packages/, nixos-modules/, tests/, docs/reference/, labs = 0 hits; in-crate use is only the re-export line itself. +- d2b-contracts-control#6 sev=low blast=wide effort=S verdict=needs-contract - `AuditEntry` (public_wire.rs:2677) is exported but referenced by no wire type in the crate - `AuditResponse` uses `AuditExportEntry` from d2b_contracts - and survives only as a historical schema artifact - fix: remove the struct after confirming docs/reference/schemas/v1/wire-protocol.json:127 no longer needs the definition - [public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127] + evidence: census `AuditEntry` over packages/ = definition plus an unrelated distinct type in d2b-broker/src/audit.rs:124; the only doc pin is the v1 wire-protocol.json definition, so needs-contract. +- d2b-contracts-control#7 sev=low blast=leaf effort=S verdict=actionable - `HelperSnapshot::validate` and `HelperLaunchRequest::validate_bounds` are `pub` but every caller is an in-crate `Deserialize` impl; external consumers call `validate_unsafe_local_resource_identity` directly instead - fix: make both methods private (or `pub(crate)`) - [unsafe_local_wire.rs:105, unsafe_local_wire.rs:171] + evidence: census `\.validate_bounds\(|snapshot\.validate\(` over packages/ = in-crate calls only (unsafe_local_wire.rs:136, unsafe_local_wire.rs:206); external `validate()` hits are other crates' distinct types. + +## err +- d2b-contracts-control#8 sev=low blast=leaf effort=S verdict=actionable - `ShellNameError` is a public error type with no `Display` or `std::error::Error` impl, so callers cannot format it or chain it with `?` - fix: add `Display` + `std::error::Error` impls (additive; the type is documented as an empty struct in daemon-api.md:653) - [public_wire.rs:1297] + evidence: seed `enum \w*Error` = 92 hits; `ShellNameError` is the only error type in the crate without Display/Error; all `\.unwrap\(\)|\.expect\(` hits (92) sit in `#[cfg(test)]` mods or tests/ and `panic!` hits are test assertions, so panic policy is otherwise clean. +- clean: seeds `\.unwrap\(\)|\.expect\(` / `let _ = |\.ok\(\);` / `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` / `enum \w*Error` ran at 92 hits; every panic site is in `#[cfg(test)]` or tests/, wire error vocabularies (NamedProcessStreamErrorKind, AudioErrorKind, HelperFailureCode) are closed kebab-case enums, and the sole `let _ =` is a test line. + +## serde +- d2b-contracts-control#9 sev=medium blast=leaf effort=M verdict=actionable - three hand-written `Deserialize` impls plus private `*Wire` shadow structs (HelperSnapshot, HelperLaunchRequest, AuditResponse) re-implement exactly what `#[serde(try_from = "...")]` generates: deserialize raw, validate, map failure to a deserialization error - fix: derive `Deserialize` via `#[serde(try_from = "HelperSnapshotWire")]` (and the two siblings), keeping `deny_unknown_fields` on the wire structs and deleting the manual impls - [unsafe_local_wire.rs:118, unsafe_local_wire.rs:176, public_wire.rs:2228] + evidence: seed `impl .*Deserialize.*for` = 5 hits (the three Wire-struct pairs plus the two single-field newtypes ShellName/RealmAccentColor, whose custom error strings are fine to keep); same admission semantics, no wire change; the refusal-ledger class covers qemu guest/provider shapes only, not these sites. +- clean: seeds `derive\([^)]*(De)?[Ss]erialize` / `serde\()...)` / `impl .*Deserialize.*for` / `serde_json::from_|serde_json::to_` ran at 660 hits; rename_all/deny_unknown_fields/skip_serializing_if discipline is consistent, `#[serde(other)]` Unknown fallbacks on probe-state enums are the right forward-compat choice, and untagged enums (StatusOutputV2, ApiReadyStatusV1) are output-only. + +## obs +- N/A: seeds `\bprintln!\(|\beprintln!\(` / `(info|debug|warn|error|trace)!\("` / `\.instrument\(|#\[instrument` / `tracing::|log::` all 0 hits and the manifest (packages/d2b-contracts-control/Cargo.toml) declares no tracing/log dependency; pure DTO crate with no telemetry surface. + +## docs +- d2b-contracts-control#10 sev=medium blast=leaf effort=M verdict=actionable - cli_output.rs exports 20+ CLI-output DTOs (ListOutputV2, ListItemOutputV2, UsbProbeOutputV1, RealmListOutputV1, RealmInspectOutputV1, OpInspect*, RealmPolicyOutputV1, StatusOutputV2, StatusInventoryOutputV2, ApiReady*, StatusVmOutputV2, LivePoolIntegrityOutputV1, StatusServicesOutputV2, RunnerParityOutputV2, StatusBridgeCheckOutputV2, Audit*OutputV2, Auth*OutputV2) with no doc comments; only StatusServicesOutputV3 and two fields document anything - fix: add one-line doc comments naming the wire shape each DTO renders - [cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130, cli_output.rs:168, cli_output.rs:222] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits; zero `/// # (Examples|Errors|Panics|Safety)` sections anywhere in the crate. +- d2b-contracts-control#11 sev=medium blast=leaf effort=M verdict=actionable - public_wire.rs request/response structs and fields are undocumented where the wire semantics are non-obvious (ListRequest, StatusRequest, AuditRequest, AuditSelector, ListEntry, VmStatus, PublicVmServices, BridgeCheck, VmLifecycle, RuntimeSummary, VmAutostartPosture, QemuMedia*, ShellName, ShellNameError, WorkloadListArgs, UsbipProbeEntry field meanings), and `-> Result<` items (ShellName::new, RealmAccentColor::new) carry no `# Errors` section - fix: add doc comments with `# Errors` on the Result-returning constructors - [public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495, public_wire.rs:2588, public_wire.rs:2633, public_wire.rs:1279, public_wire.rs:1282] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits and seed `-> Result<` = 57 hits; no canonical doc sections exist in the crate. +- d2b-contracts-control#12 sev=medium blast=leaf effort=M verdict=actionable - unsafe_local_wire.rs exposes undocumented pub constants with unexplained magic values (MAX_HELPER_QUEUE_DEPTH=128, MAX_HELPER_SNAPSHOT_SCOPES=1024, MAX_COMPLETED_OPERATIONS_PER_UID=1024, MAX_COMPLETED_OPERATION_AGE_SECS=24*60*60, UNSAFE_LOCAL_HELPER_PROTOCOL_VERSION), undocumented pub fns (unsafe_local_helper_protocol_supported, validate_unsafe_local_resource_identity, HelperSnapshot::validate, HelperLaunchRequest::validate_bounds), and undocumented wire types (HelperHello, HelperHelloAccepted, HelperHeartbeat, HelperScopeKind, HelperScopeState, HelperScopeSnapshot, HelperSnapshot, HelperOperationResult, HelperOperationRejected, DaemonToUnsafeLocalHelper, UnsafeLocalHelperToDaemon, UnsafeLocalHelperWireSchema) - fix: document each constant with the why (queue/snapshot/age bounds the daemon enforces) and one line per wire type - [unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wire.rs:26, unsafe_local_wire.rs:250, unsafe_local_wire.rs:32, unsafe_local_wire.rs:308] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits; the constants are consumed by d2bd-runtime and d2b-unsafe-local-helper (census over packages/), so their bounds are cross-crate contracts. +- d2b-contracts-control#13 sev=low blast=leaf effort=S verdict=actionable - terminal_wire.rs's seven DTOs (TerminalStream, TerminalSize, TerminalWriteStdin, TerminalReadOutput, TerminalResize, TerminalWriteStdinResult, TerminalReadOutputChunk) have no item docs; only the module-level `//!` explains them - fix: add one-line docs per type (the redacted-Debug note belongs on the session-bearing types) - [terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits; terminal_wire.rs is the only module whose types are entirely undocumented. + +## perf +- clean: seeds `format!\(` / `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` / `\.to_string\(\)` ran at 57 hits, every one in `#[cfg(test)]` redaction assertions or cold paths (BTreeMap::new in the from_v2 conversion shim, to_owned in the JsonSchema impl); the crate is DTO definitions with no hot loop, so all sites are `static (unmeasured)` and non-issues. + +## conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` / `\bMutex<|\bRwLock<` / `Atomic\w+|Ordering::` / `thread_local!|unsafe impl (Send|Sync) for` all 0 hits; pure data-definition crate with no threads, locks, or atomics. + +## async +- N/A: seeds `async fn|async move|\.await` / `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` / `tokio::sync::(Mutex|RwLock|Notify)` / `#\[tokio::(main|test)\]|Runtime::block_on` all 0 hits and the manifest has no tokio dependency. + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` / `// SAFETY:` / `transmute|from_raw|MaybeUninit|mem::zeroed` all 0 hits; the manifest inherits `[workspace.lints]` (`unsafe_code = "forbid"`, Cargo.toml root) and seed 4 alone does not make the lens applicable. + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` / `catch_unwind` / `repr\(C\)|repr\(transparent\)` / `CStr|CString|c_char` all 0 hits (the only textual matches are `cStr` inside the identifier `ExecStream`, a case-insensitive false positive); no FFI surface in this crate. + +## macro +- N/A: seeds `macro_rules!` / `proc_macro|syn::|quote!` / `\$crate` / `to_compile_error|new_spanned` all 0 hits; no macros defined or used beyond std derives. + +## test +- d2b-contracts-control#14 sev=medium blast=leaf effort=M verdict=actionable - the `WorkloadOp`/`WorkloadOpResponse` wire family (feature-negotiated v3 operations, dispatched by d2bd/src/composition.rs:7666) has no round-trip or shape test in this crate, unlike every sibling family (exec, console, audio, shell, named streams, audit all have wire-shape tests) - fix: add a round-trip + tag/rename pin test for WorkloadOp::List/Status/LauncherExec and WorkloadOpResponse, mirroring `audio_public_wire_json_shape_is_stable` - [public_wire.rs:167, public_wire.rs:175] + evidence: seed `#\[test\]|#\[tokio::test\]` = 35 tests and `assert_eq!\(|assert_ne!\(|assert!\(` = 134 asserts in src+tests; none reference WorkloadOp (census over the crate's tests), so the contract behavior has no test. +- clean: seeds `#\[test\]|#\[tokio::test\]` / `assert_eq!\(|assert_ne!\(|assert!\(` / `proptest!|insta::assert|rstest` / `#\[ignore\]` ran at 35 tests / 134 asserts / 0 / 0; the suite is table-driven with failure messages (shell_name_enforces_adr_shape), pins wire shapes deliberately, and asserts fail-closed behavior (unknown fields, invalid audit pages, redaction sentinels); no ignored or tautological tests found. + +## Coverage +- idiom: clean (seeds ran: 0/0/0; hand-written Debug impls are deliberate redaction) +- own: clean (seeds ran: 94 hits; all clones/to_owned explainable wire-building or test fixtures) +- type: 3 finding(s) +- api: 4 finding(s) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in manifest) +- docs: 4 finding(s) +- perf: clean (seeds ran: 57 hits; all cold/test sites) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn or tokio dependency) +- unsafe: N/A (seeds: 0/0/0 all zero for seeds 1-3; manifest inherits workspace `unsafe_code = "forbid"`) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros defined) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md new file mode 100644 index 000000000..abb6eba91 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md @@ -0,0 +1,81 @@ +# d2b-contracts-provider-p1 - d2b-contracts-provider - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 7304 (excl. src/generated/**) | modules: v3/provider.rs, v3/credential.rs, v3/credential/service.rs, v3/provider_registry.rs, v3/mod.rs, lib.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f): src/v3/provider.rs, src/v3/credential/**, src/v3/credential.rs, src/v3/provider_registry.rs, src/v3/mod.rs, src/lib.rs + +## idiom +- d2b-contracts-provider-p1#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `Default` impls on `CredentialRotationPolicy` and `CredentialRevocationPolicy` reproduce the field-wise default a derive would generate - fix: add `#[default]` to `RotationPolicyClass::OnExpiry` and `RevocationAction::Immediate` and replace both impls with `#[derive(Default)]` - [packages/d2b-contracts-provider/src/v3/credential.rs:362, packages/d2b-contracts-provider/src/v3/credential.rs:453] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 hits in lane; 2 are derive-replaceable Defaults (the Clone/PartialEq/Eq on CredentialAuthorization at service.rs:661-687 are required because of the `Arc` field and are not findings) +- d2b-contracts-provider-p1#2 sev=low blast=leaf effort=S verdict=actionable - manual `Debug` impl on `UpgradePolicy` prints exactly the three closed pub fields a derive would print, with nothing to redact - fix: replace `impl core::fmt::Debug for UpgradePolicy` with `#[derive(Debug)]` on the struct - [packages/d2b-contracts-provider/src/v3/provider.rs:2374] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 hits; the other manual Debug impls in the lane redact caller-supplied values (module rule at provider.rs:12-22, deliberate) and are not findings + +## own +- d2b-contracts-provider-p1#3 sev=low blast=leaf effort=S verdict=actionable - `ProviderManifest::validate_runtime_artifacts` takes `impl IntoIterator` by value, forcing `entries.clone()` and `self.runtime_artifacts.clone()` at both call sites that already hold the vec - fix: change the signature to `entries: &[TargetRuntimeArtifacts]` and drop both clones (census shows no external callers, so the pub signature change is contained) - [packages/d2b-contracts-provider/src/v3/provider.rs:2497, packages/d2b-contracts-provider/src/v3/provider.rs:2531, packages/d2b-contracts-provider/src/v3/provider.rs:2580] + evidence: seed `.clone()` = 26 hits in lane; census: `validate_runtime_artifacts` over packages/ + nixos-modules/ + tests/ + docs/reference/ + labs/ = 4 hits, all inside provider.rs (2497, 2531, 2580, 3224 test) +- d2b-contracts-provider-p1#4 sev=low blast=leaf effort=S verdict=actionable - `ProviderManifest::new` and `ComponentDescriptor::with_state_namespaces` clone identifiers into dedup sets that could borrow - fix: use `BTreeSet<&BoundedToken>` / `BTreeSet<&ResourceTypeName>` for `component_ids`, `owned_types`, `bound_types`, and `ids` - [packages/d2b-contracts-provider/src/v3/provider.rs:2438, packages/d2b-contracts-provider/src/v3/provider.rs:2445, packages/d2b-contracts-provider/src/v3/provider.rs:2455, packages/d2b-contracts-provider/src/v3/provider.rs:1459] + evidence: seed `.clone()` = 26 hits in lane; the remaining clones are required (owned projection return at provider.rs:1169-1182, `Arc` proof clone at service.rs:664-668, test fixtures) and are not findings + +## type +- d2b-contracts-provider-p1#5 sev=low blast=family effort=M verdict=actionable - `ComponentDescriptor::new` takes a `declares_state_volume: bool` parameter that can only be `false`: `true` is rejected at the top of the constructor, the Deserialize path passes the literal `false`, and the flag is only ever set through `with_state_namespaces` - fix: remove the parameter from `ComponentDescriptor::new` and update the ~20 call sites (census below), keeping the wire-only `declaresStateVolume` field and its consistency check inside the Deserialize Wire struct - [packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/src/v3/provider.rs:1368, packages/d2b-contracts-provider/src/v3/provider.rs:1720, packages/d2b-contracts-provider/src/v3/provider.rs:3455] + evidence: seed `fn validate_\w+|fn check_\w+` = 8 hits; census: `ComponentDescriptor::new` over packages/ + tests/ = ~20 hits across 7 crates (d2b-bus, d2b-core-controller, d2b-provider-provider, d2b-provider-toolkit, d2bd-runtime, d2bd, d2b-resource-compiler), all passing `false` or relying on the default path +- d2b-contracts-provider-p1#6 sev=low blast=leaf effort=M verdict=actionable - `ComponentDescriptor` stores `execution` and `execution_wire` as parallel fields where the wire shape is derived from the enum, so one fact has two representations that only `with_execution` keeps in sync - fix: implement `Serialize` for `ComponentExecution` emitting the flat `binaryRef` key (absent for `InProcessBootstrap`), drop the `execution_wire` field and the private `ComponentExecutionWire` struct - [packages/d2b-contracts-provider/src/v3/provider.rs:1333, packages/d2b-contracts-provider/src/v3/provider.rs:1335, packages/d2b-contracts-provider/src/v3/provider.rs:1418] + evidence: seed `fn validate_\w+|fn check_\w+` = 8 hits; the redundant pair is visible in the struct literal at provider.rs:1418-1419 and the From bridge at provider.rs:1300-1307 + +## api +- d2b-contracts-provider-p1#7 sev=low blast=family effort=S verdict=actionable - `SchemaVersion` in d2b-contracts-resource exposes no `major()`/`minor()` accessors, so `CompatibilityRange::admits_state` re-parses the canonical string in `schema_version_parts` with three `expect`s and an allocation per call - fix: add `pub const fn major(self) -> u32` and `minor(self) -> u32` to `SchemaVersion` (non-breaking) and delete `schema_version_parts` - [packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/src/v3/resource_schema.rs:592] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~120 hits; the expects are invariant-justified (U1 (c) err false-positive class), so the finding is the missing accessor, not the panics + +## err +- d2b-contracts-provider-p1#8 sev=medium blast=leaf effort=S verdict=actionable - `ProviderRegistryPublication::new` maps `generation == 0` to `MappingBoundExceeded` even though the `ZeroGeneration` variant exists and is used by the entry constructor, so a caller distinguishing invalid generation from bound overflow receives the wrong code - fix: split the check into `if generation.get() == 0 { return Err(ZeroGeneration) }` before the mapping-count bound - [packages/d2b-contracts-provider/src/v3/provider_registry.rs:186, packages/d2b-contracts-provider/src/v3/provider_registry.rs:92] + evidence: seed `enum \w*Error` = 2 hits in lane; the variant pair is visible at provider_registry.rs:40 (ZeroGeneration) and provider_registry.rs:48 (MappingBoundExceeded); no external matchers exist (census below in #9) +- d2b-contracts-provider-p1#9 sev=low blast=leaf effort=S verdict=actionable - an entry-generation mismatch in `ProviderRegistryPublication::new` reports `AxisMismatch`, whose Display code is `provider-registry-axis-mismatch`, although no binding axis is involved - fix: add a `GenerationMismatch` variant with its own kebab code and return it for the `entry.provider_generation != generation` check - [packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-provider/src/v3/provider_registry.rs:193] + evidence: seed `enum \w*Error` = 2 hits; census: `ProviderRegistryError` over packages/ + nixos-modules/ + tests/ + docs/reference/ + labs/ = 12 hits, all inside provider_registry.rs, so adding a variant breaks no external exhaustive match + +## serde +- clean: seeds ran: derive Serialize/Deserialize ~41 hits, serde attrs ~30 hits, hand-written `impl Deserialize` 18 hits, serde_json 0 production hits; the hand-written Deserialize impls are live admission gates (recorded refusal class per U1 (d)6, not re-flagged), `rename_all` conventions are consistent, and every Wire admission shape carries `deny_unknown_fields`; the PascalCase wire spellings of `CredentialLeaseState`, `CredentialConditionType`, and `CredentialInteractionState` are pinned by the golden vector at credential.rs:1106 and are deliberate + +## obs +- clean: seeds ran: println!/eprintln! 0, event-macro pattern 17 hits (all `redacted_debug!` macro-name false positives), `.instrument`/`#[instrument]` 0, tracing::/log:: 0; the crate emits no telemetry and every Debug/Display surface redacts caller-supplied values (module rule provider.rs:12-22), which the ADR 0010/0028 redaction gate covers + +## docs +- d2b-contracts-provider-p1#10 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors` sections exist on any Result-returning pub item in the lane even though failure conditions are the load-bearing part of these admission constructors - fix: add `# Errors` sections naming the closed variants (e.g. `ProviderContractError::InvalidPrimitive` for `BinaryRef::parse`, `ProviderContractError::TrustNotEstablished` for `TrustEvidence::admit`) to the pub constructors and admission methods - [packages/d2b-contracts-provider/src/v3/provider.rs:250, packages/d2b-contracts-provider/src/v3/provider.rs:481, packages/d2b-contracts-provider/src/v3/credential.rs:120, packages/d2b-contracts-provider/src/v3/credential/service.rs:1002] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits vs seed `-> Result<` = ~80 hits in lane; every pub item is otherwise documented (first sentences are contract-shaped), so this is a section-shape gap, not missing docs + +## perf +- clean: seeds ran: format! 13 hits (11 in tests, 2 cold: opaque_digest credential.rs:80 and the test-adjacent fingerprint helper), Vec::new 5 hits (encode_outer service.rs:1003 and write_message service.rs:1386 are cold per-operation paths; constructor empties are the common case), to_string 5 hits (all tests); no hot loop allocates, and all findings here would be static (unmeasured) per the perf gate + +## conc +- d2b-contracts-provider-p1#11 sev=low blast=leaf effort=S verdict=actionable - `SensitiveDeliveryRecord` uses `Ordering::SeqCst` for per-byte loads and stores that have no release/acquire pairing with any other atomic, so the strongest ordering buys nothing - fix: use `Ordering::Relaxed` in `copy_to`, `clear`, and `is_zeroized` - [packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-provider/src/v3/credential/service.rs:963, packages/d2b-contracts-provider/src/v3/credential/service.rs:977] + evidence: seed `Atomic\w+|Ordering::` = 7 hits in lane, all on this one record type (import at service.rs:6 plus 6 uses); the `Arc` proof in `CredentialAuthorization` is genuine shared ownership (U1 (c) api false-positive class) and is not a finding + +## async +- clean: seeds ran: async fn/async move/.await 3 hits (dispatch_async service.rs:867, dispatch_authorized_provider_async service.rs:896, .await service.rs:904), tokio::spawn/spawn_blocking/JoinSet/select!/join! 0, tokio::sync 0, #[tokio::main/test] 0; the `#[async_trait]` trait has one required sync method plus a default async wrapper that does no blocking work, holds no locks across `.await`, and is runtime-agnostic + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0, `// SAFETY:` 0, `transmute|from_raw|MaybeUninit|mem::zeroed` 0, `unsafe_code` 0 in lane; workspace lints forbid unsafe (U1 (d)1) and the crate is not on the (d)8 exception list + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` 0, `catch_unwind` 0, `repr\(C\)|repr\(transparent\)` 0, `CStr|CString|c_char` 0; the crate crosses no foreign boundary + +## macro +- clean: seeds ran: macro_rules! 1 hit (opaque_credential_value! credential.rs:111), proc_macro/syn/quote 0, $crate 0, to_compile_error/new_spanned 0; the single macro is a genuine impl-per-type generator with narrow fragment specifiers ($name:ident, $max:expr, $domain:literal, $doc:literal) and is module-local, so no `$crate` path is needed; no proc-macro and no trybuild suite are warranted at this size + +## test +- d2b-contracts-provider-p1#12 sev=medium blast=leaf effort=M verdict=actionable - `credential/service.rs` (1461 lines) contains zero tests: the strict protobuf codec (the five `CredentialWire` impls at service.rs:1071-1350, `WireReader` at service.rs:1393-1452, `set_once` duplicate-field rejection at service.rs:1296, and the `encode_outer`/`decode_outer` ceilings at service.rs:1002-1028) is entirely unverified, so a malformed-input, truncation, or non-canonical-varint regression passes the suite silently - fix: add round-trip tests per DTO plus malformed/truncated/duplicate-field/non-canonical-varint/oversize tests for `WireReader` and `encode_outer`/`decode_outer` - [packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-provider/src/v3/credential/service.rs:1393, packages/d2b-contracts-provider/src/v3/credential/service.rs:1296] + evidence: seed `#\[test\]|#\[tokio::test\]` = 54 hits in lane, 0 of them in service.rs (43 in provider.rs, 9 in credential.rs, 2 in provider_registry.rs); the sibling files' tests are behavior-focused (schema vectors, fail-closed checks, redaction canaries) and no `#[ignore]` or tautological tests were found + +## Coverage +- idiom: 2 finding(s) +- own: 2 finding(s) +- type: 2 finding(s) +- api: 1 finding(s) +- err: 2 finding(s) +- serde: clean (seeds ran: 41/30/18/0; hand-written Deserialize = recorded admission-gate class, U1 (d)6) +- obs: clean (seeds ran: 0/17/0/0; the 17 event-macro hits are `redacted_debug!` name matches) +- docs: 1 finding(s) +- perf: clean (seeds ran: 13/5/5; all hits cold or test-only) +- conc: 1 finding(s) +- async: clean (seeds ran: 3/0/0/0) +- unsafe: N/A (seeds: 0/0/0/0 all zero; unsafe_code forbid per workspace lints, U1 (d)1) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: clean (seeds ran: 1/0/0/0) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md new file mode 100644 index 000000000..d8f3c8ef3 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md @@ -0,0 +1,85 @@ +# d2b-contracts-provider-p2 - d2b-contracts-provider - part 2/2 +Baseline: 6ebdd4cec | LOC audited: 7395 (excl. src/generated/**) | modules: v3/semantic_services (mod, audio, child_resources, security_key, telemetry, usb), v3/credential_controller, v3/telemetry_policy, v3/telemetry_frame +Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: src/v3/semantic_services/**, src/v3/credential_controller.rs, src/v3/telemetry_policy.rs, src/v3/telemetry_frame.rs + +## idiom +- d2b-contracts-provider-p2#1 sev=low blast=leaf effort=S verdict=actionable - the two `children.push(BindingChildIntent {...})` arms in `explicit_binding_children_with_user` are identical 15-field literals differing only in `producer_ref: None` versus `Some(producer_ref)`, forced apart by a `let ... else { ...; continue; }` - fix: bind `let producer_ref: Option = producer_ref.transpose()?;` before the push and emit one literal with `producer_ref,`, deleting the else-continue arm - [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:595] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (test-support, mod.rs:1276); the duplication is a read finding at child_resources.rs:574-616; seeds 1 and 2 = 1 and 0 hits +- clean: seeds ran: 1/0/1 - no index loops outside one test fixture (telemetry_frame.rs:555), no hand-written Default/From/PartialEq/Debug/Clone/Hash impls matched (the redacting `Debug` impls are `impl core::fmt::Debug` and are the deliberate redaction pattern), one statement-style accumulation in cfg(test) support code + +## own +- d2b-contracts-provider-p2#2 sev=low blast=leaf effort=S verdict=actionable - duplicate-detection set in `validate_descriptor` clones every label key (`seen.insert(label.key.clone())`) where a borrowed `BTreeSet<&str>` suffices - fix: declare `let mut seen: BTreeSet<&str> = BTreeSet::new();` and insert `&label.key` - [packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:497, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:500] + evidence: seed `\.clone\(\)` = 30 hits, of which this is one of two non-test, non-construction clones; the other clones are multi-owner construction copies (frame field values, child intents, single-flight set insert) that pass the one-sentence test +- d2b-contracts-provider-p2#3 sev=low blast=leaf effort=S verdict=actionable - `allowed_telemetry_value` allocates a fresh String just to test zone validity (`validate_zone(value.to_owned()).is_ok()`) although `validate_zone` only reads the value - fix: give the zone grammar a `&str`-based check (for example `fn is_valid_zone(value: &str) -> bool` used here, keeping the owning `validate_zone` for the three construction call sites that need the validated String back) - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1591, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1549] + evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 25 hits; this is the only hit where the owned value is immediately discarded (`.is_ok()`), the rest are genuine owned returns or test fixtures +- clean: seeds ran: 30/25/0/0 - no Rc/RefCell/Arc/Arc and no Cow in the partition; every remaining clone is a multi-owner copy (child intents share binding/provider refs, telemetry frame fields appear in three label sets, single-flight set insert) or a `to_canonical_string` owned return + +## type +- d2b-contracts-provider-p2#4 sev=medium blast=family effort=M verdict=actionable - `BindingChildRequest::process` and `process_for_user` accept `kind: BindingChildKind` including `Endpoint`, so an Endpoint carrying process fields is constructible and must be rejected at runtime (`InvalidProducer`, child_resources.rs:502-510), and the sibling check `producer_role.is_some() && kind != Endpoint` (child_resources.rs:499) is unreachable because only `endpoint()` sets `producer_role` and it hardcodes `Endpoint` - fix: take a restricted `ProcessChildKind { Process, EphemeralProcess }` in the two process constructors (all seven in-tree call sites pass `BindingChildKind::Process`), then delete both runtime checks - [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:499, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:502] + evidence: seed `fn validate_\w+|fn check_\w+` = 20 hits, all boundary validators on wire input or constructor invariants; census: `BindingChildRequest::process` over packages/nixos-modules/tests/docs/reference/labs = 7 hits in 4 crates (audio-pipewire, device-security-key, device-usbip, observability-otel), all passing `BindingChildKind::Process`; the illegal Endpoint-with-process-fields combination is exercised only by the runtime check, not by any caller +- clean: seeds ran: 20/0/0 - no boolean flag soup (`is_\w+: bool` = 0), no stringly-typed state (`(mode|kind|state): String` = 0); the remaining `validate_*` functions are parse-once admission checks on wire input, which is the skill's sanctioned boundary placement + +## api +- clean: seeds ran: 231/0/1 - the exported surface is the deliberate wide contract vocabulary of a contract crate (U1 (c) api false positive applies), no Arc/Rc/Box/RefCell appears in any public signature, and the single `pub use` arm (telemetry_policy.rs:9) re-exports generated catalog constants as the house single-surface pattern; `SemanticPairDeclaration`, `NonEmpty`, and `SemanticBackingDeclaration` are correctly `pub(crate)` + +## err +- d2b-contracts-provider-p2#5 sev=low blast=leaf effort=S verdict=actionable - `CredentialControllerError::AlreadyRunning` renders the wire label "credential-queue-pressure", which names a different concept (the lease-ceiling outcome `CredentialControllerOutcome::QueuePressure`) than the variant's documented meaning ("the same Credential is already being handled") - fix: emit "credential-already-running" from the Display arm, or rename the variant to match the code - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:90] + evidence: seed `enum \w*Error` = 6 error enums read; census: `credential-queue-pressure` over packages/nixos-modules/tests/docs/reference/labs = 1 hit (the definition itself), so the label is not pinned by docs/reference/error-codes.md or any consumer +- d2b-contracts-provider-p2#6 sev=low blast=leaf effort=S verdict=actionable - `CredentialObservabilityError` Display strings are prose sentences ("credential audit record is invalid", "credential telemetry frame is invalid"), breaking the kebab-code diagnostic convention every sibling error type in this crate follows (`CredentialControllerError`, `MetricPolicyError`, `TelemetryFrameError`, `SemanticContractError`, `BindingChildError`) - fix: render "credential-audit-record-invalid" and "credential-telemetry-frame-invalid" - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1508, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1509] + evidence: seed `enum \w*Error` = 6 enums; census: both prose strings over packages/nixos-modules/tests/docs/reference/labs = 1 hit each (the definitions), no consumer or doc pins them +- d2b-contracts-provider-p2#7 sev=low blast=leaf effort=S verdict=actionable - `CredentialSingleFlight` maps a poisoned mutex to `InvalidInput` (a caller-input error) and its guard `Drop` silently skips the removal on poison, which would leave a stale UID and a permanent `AlreadyRunning`; the skill names recovery via `into_inner()` for exactly this shape - fix: recover with `self.running.lock().unwrap_or_else(|poisoned| poisoned.into_inner())` in both `lock()` and `Drop`, keeping the documented synchronous-path boundary - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:834, packages/d2b-contracts-provider/src/v3/credential_controller.rs:846] + evidence: seed `\.unwrap\(\)|\.expect\(` = 40 hits, all in tests or on literally-built values (write! to String, canonical constants) per the U1 false-positive list; the poison mapping is a read finding at the two lock sites, both carrying the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` +- clean: seeds ran: 40/1/1/6 - no panic!/unreachable!/todo!/unimplemented! outside one test helper (telemetry_policy.rs:990), the single `let _ =` hit is a compile_fail doctest, and every unwrap/expect outside tests is the U1 false-positive class (write! to String, literally-built catalog constants); error taxonomy is otherwise split by caller action with closed discriminants + +## serde +- d2b-contracts-provider-p2#8 sev=low blast=leaf effort=S verdict=actionable - `parse_raw_frame` maps every serde failure to `Malformed`, so a top-level unknown field (rejected by `deny_unknown_fields` on `TelemetryFrame`) reports `Malformed` while the same unknown key nested inside `value` reports `UnknownField` from validation - the variant exists but is unreachable for the shape that names it - fix: `map_err(|error| match error.classify() { serde_json::error::Category::UnknownField => TelemetryFrameError::UnknownField, _ => TelemetryFrameError::Malformed })` (serde_json 1.0.151 in Cargo.lock provides `classify`) - [packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:114] + evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 2 hits, seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 3 hits, seed `serde_json::from_|serde_json::to_` = 4 hits; the UnknownField-vs-Malformed asymmetry is a read finding across parse (line 76) and validate (lines 114-121) +- clean: `rename_all = "lowercase"` on `TelemetrySignal` and per-type `deny_unknown_fields` on `TelemetryFrame` follow the card's naming and decision guidance; the hand-written `Deserialize` for `SemanticProjectionProtocolVersion` is a live admission gate (grammar parse), the sanctioned pattern; no `flatten`, no `try_from`, no untagged + +## obs +- clean: seeds ran: 0/0/0/0 - no println/eprintln, no interpolated log macros, no tracing or log usage anywhere in the partition; the telemetry frame and policy modules are the redaction and closed-domain policy data themselves, and `CredentialTelemetryFrame` builds structured field lists rather than log lines, so there is nothing to instrument + +## docs +- d2b-contracts-provider-p2#9 sev=medium blast=family effort=M verdict=actionable - none of the 59 Result-returning items in the partition carries an `# Errors` section, so callers cannot learn from the docs which closed-discriminant error each condition produces (for example when `CredentialControllerCall::authorize` yields `DeadlineExceeded` versus `OperationDenied`, or which `validate_*` failure maps to which `MetricPolicyError` variant) - fix: add `# Errors` sections naming the variant per condition to the public Result APIs, starting with the constructor and validate families - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:478, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:72, packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs:93] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits against seed `-> Result<` = 59 hits; every public item carries a one-line doc (no undocumented pub items found), so this is the missing canonical-section class, not missing docs +- clean: every pub item in the partition has a doc comment with a load-bearing first sentence; module docs (`//!`) exist on all six modules; the redacting Debug/Display impls are documented policy + +## perf +- clean: seeds ran: 11/6/25 - every `format!` site is a cold path (child-name construction, audit wire record rendering, error labels, test fixtures), every `Vec::new()` is an empty-case-common or cfg(test) site, and the `to_string`/`to_owned` sites are owned returns or the two `own` findings above; no hot loop, no attacker-keyed hashing, no grow-by-push in a measured path; static (unmeasured) + +## conc +- clean: seeds ran: 0/1/0/0 - the only synchronization is `CredentialSingleFlight`'s `Mutex>`, a documented synchronous-path boundary with the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` per U1 (d) 4, held only across single insert/remove operations; no threads, no atomics, no thread_local, no unsafe Send/Sync claims + +## async +- N/A (seeds: 0/0/0/0 all zero; no `async fn`, no `.await`, no tokio usage anywhere in the partition - the controller contract is synchronous by design, documented at credential_controller.rs:800-806) + +## unsafe +- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, fns, impls, or SAFETY comments in the partition, and the crate inherits `unsafe_code = "forbid"` through `[lints] workspace = true`) + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no extern "C", no no_mangle, no repr(C)/repr(transparent), no CStr/CString in the partition) + +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro or syn/quote usage, no $crate, no to_compile_error in the partition) + +## test +- d2b-contracts-provider-p2#10 sev=medium blast=leaf effort=M verdict=actionable - several public contract behaviors have no test: `observe_credential` (both the degraded and the InspectMetadata branches), the rotation-retry-exhausted branch of `reconcile_credential` (`CredentialRetryState::exhausted` feeding `RotationFailed`/`Failed`), `CredentialLeaseAggregate::from_active_expiries`, `CredentialControllerHealth::derive`, and `CredentialAuditRecord::controller_event` - fix: add table-driven unit tests asserting the outcome/disposition variant per input row, mirroring the existing `rotation_policy_matrix_is_closed` shape - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1346, packages/d2b-contracts-provider/src/v3/credential_controller.rs:499, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1084] + evidence: seed `#\[test\]|#\[tokio::test\]` = 40 tests read across the partition; the named functions appear zero times inside `#[cfg(test)]` bodies (census over the crate's tests: `observe_credential` 0 test hits, `from_active_expiries` 0, `CredentialControllerHealth::derive` 0, `controller_event` 0, `CredentialRetryState` 0), while `reconcile_credential` and `revoke_credential` are exercised +- clean: seeds ran: 40/150/0/0 - no proptest/insta/rstest, no `#[ignore]`; the existing tests are behavior-asserting with negative controls (fingerprint re-derivation, provider-neutrality probes, redaction idempotence) and table-driven cases with messages; no test found that cannot fail + +## Coverage +- idiom: 1 finding +- own: 2 findings +- type: 1 finding +- api: clean (seeds ran: 231/0/1; deliberate contract vocabulary, no internals in signatures, one house-pattern pub use) +- err: 3 findings +- serde: 1 finding +- obs: clean (seeds ran: 0/0/0/0; no logging surface in the partition) +- docs: 1 finding +- perf: clean (seeds ran: 11/6/25; all sites cold or test) +- conc: clean (seeds ran: 0/1/0/0; one documented synchronous-path Mutex with sanctioned allow) +- async: N/A (seeds: 0/0/0/0 all zero; synchronous contract by design) +- unsafe: N/A (seeds: 0/0/0/0 all zero; unsafe_code forbid inherited) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md new file mode 100644 index 000000000..0dd01cf98 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md @@ -0,0 +1,87 @@ +# d2b-contracts-resource-p1 - d2b-contracts-resource - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9718 (excl. src/generated/**) | modules: v3/network.rs, v3/resource_schema.rs, v3/operations/** (mod.rs, error.rs, seal.rs), v3/device.rs, v3/resource_status.rs, v3/volume_state.rs, v3/payload_schema.rs, v3/error.rs, v3/host.rs, v3/bridge.rs, v3/limits.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f); part 2 owns v3/volume.rs, v3/process.rs, v3/identity.rs, v3/execution_policy.rs, v3/resource.rs, v3/storage.rs, v3/volume_binding.rs, v3/activation_nixos.rs, v3/user.rs, v3/mod.rs, v3/artifact.rs, src/lib.rs + +## idiom +- d2b-contracts-resource-p1#1 sev=low blast=leaf effort=S verdict=actionable - `ExternalIpv4Spec::default` (network.rs:597-605) hand-writes exactly the field-wise default (method: Ipv4Method::Dhcp, address: None, gateway: None, dns: Vec::new()) that a derive would produce - fix: add `#[default]` to `Ipv4Method::Dhcp` (network.rs:533) and `#[derive(Default)]` to `ExternalIpv4Spec`, delete the hand-written impl - [packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src/v3/network.rs:533] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 6 hits; the other five Default impls (RoutingSpec, DhcpSpec, DnsSpec, MdnsSpec, EgressSpec) preserve non-derivable defaults (mandatory host blocklist, ignoreClientNames=true, cacheSize=1000, reflector=true, masquerade=true) and are deliberate, so this is the only derive-equivalent one +- clean: seeds 1-3 = 1/6/1 hits; the index loop (payload_schema.rs:383) is a bounded depth test, the `let mut values = Vec::new()` (resource_schema.rs:298) is a serde visitor collect, and no naming or conversion drift was found across the part + +## own +- d2b-contracts-resource-p1#2 sev=low blast=leaf effort=S verdict=actionable - `StateDigest::parse` clones its String before delegating to `SchemaFingerprint::parse` (volume_state.rs:138), but that function takes `impl Into`, so `value.as_str()` avoids the copy - fix: `SchemaFingerprint::parse(value.as_str())` - [packages/d2b-contracts-resource/src/v3/volume_state.rs:138] + evidence: seed `\.clone\(\)` = 92 hits; real-code clones reviewed: resource_schema.rs:729/1010/1094/1212/1231 own error-payload strings (required), resource_status.rs:693 `base_projection` needs an owned copy, seal.rs:157-169 `Arc::clone` at the capability boundary (required); the remainder are test fixtures +- clean: seeds 2-4 = 54/0/0 hits; `to_owned`/`to_string` hits are schemars `schema_name()` returns, wire-rendering boundaries, and test sentinels; no Rc/RefCell/Arc/Cow anywhere in the part + +## type +- d2b-contracts-resource-p1#3 sev=low blast=leaf effort=S verdict=actionable - `StoreSealIdentity::with_store_epoch` (seal.rs:57-61) documents "Bind the seal identity to a nonzero store epoch" but accepts 0 without a check, and the fn has no callers, so the promised invariant is unenforced and untested - fix: reject 0 (return `Result` or `debug_assert!` plus a documented contract) or drop the nonzero claim from the doc - [packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resource/src/v3/operations/seal.rs:58] + evidence: census `with_store_epoch` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (the definition itself); seed 1 `fn validate_\w+|fn check_\w+` = 15 hits (all in tests and validators of sibling types) +- d2b-contracts-resource-p1#4 sev=medium blast=family effort=M verdict=actionable - store-contract digests are bare `String` (`StoredResource.payload_digest` mod.rs:71, `StoredSchema.payload_digest` mod.rs:239, `PreparedStoreMutation.payload_digest` mod.rs:374) while every other identity in this crate is a parsed newtype (SchemaFingerprint, StateDigest), so a non-digest string can flow through the store boundary without a type-level guarantee - fix: type the three fields as `SchemaFingerprint` (or `StateDigest`) and parse at the backend boundary where the digest is computed - [packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resource/src/v3/operations/mod.rs:239, packages/d2b-contracts-resource/src/v3/operations/mod.rs:374] + evidence: static read of the three pub fields; consumers that construct or match them: d2b-resource-api/src/store.rs, d2b-resource-api/src/manager_backend.rs, d2b-bus/src/session_seam_tests.rs; seed 3 `(mode|kind|state): String` = 0 hits, so this is the only stringly-typed identity in the part +- clean: seeds 2 = 0 hits (no boolean flag soup); the Option pairs checked (ResourceError optional fields, ResourceStatus timestamps) are genuinely independent + +## api +- d2b-contracts-resource-p1#5 sev=low blast=leaf effort=S verdict=actionable - six `pub type` aliases are exported with zero consumers anywhere: `AttachmentSpec` (network.rs:956), `AuthorityDescriptor` (device.rs:129), `OpaqueAuthorityKey` (device.rs:151), `DeviceStatus` (device.rs:760), `DeviceRbacVerb` (device.rs:918), `DeviceTelemetryLabels` (device.rs:1119) - fix: delete the unused aliases (or make them `pub(crate)` if a provider adapter is planned) - [packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src/v3/device.rs:129, packages/d2b-contracts-resource/src/v3/device.rs:151, packages/d2b-contracts-resource/src/v3/device.rs:760, packages/d2b-contracts-resource/src/v3/device.rs:918, packages/d2b-contracts-resource/src/v3/device.rs:1119] + evidence: census `AttachmentSpec|AuthorityDescriptor|OpaqueAuthorityKey|DeviceStatus|DeviceRbacVerb|DeviceTelemetryLabels` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 6 hits, all the definitions themselves +- clean: seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 hits (the Arc fields in seal.rs are private); seed 3 `pub use` arms in operations/mod.rs are the house single-surface pattern; the wide wire export is the contract-crate norm (U1 (c) api false positive) + +## err +- d2b-contracts-resource-p1#6 sev=medium blast=family effort=M verdict=actionable - `StoreErrorKind` (operations/error.rs:93-129) duplicates all 31 `ResourceErrorKind` variants and their `as_str` spellings verbatim, and d2b-resource-api/src/error.rs:11-56 `map_store_error_kind` re-lists all 31 a third time, so adding one resource-plane kind requires three synchronized edits and no test pins the overlap (each set only pins its own size) - fix: restructure `StoreErrorKind` as `Resource(ResourceErrorKind)` plus the three store-only variants (StoreIntegrityFailure, StoreBackpressure, StoreQuarantined), which collapses the map to one arm plus store arms while keeping `as_str` outputs identical - [packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-resource/src/v3/operations/error.rs:132, packages/d2b-resource-api/src/error.rs:11] + evidence: seed 4 `enum \w*Error` = 10 hits; census `StoreErrorKind` over packages/ = matches in d2b-resource-api (error.rs map, manager_backend.rs, service.rs), d2bd-runtime/src/guest_resource_runtime.rs, d2b-bus/src/session_seam_tests.rs; StoreError carries no serde derives, so the reshape is internal +- clean: seeds 1-3 = 271/9/0 hits; the 14 real-code expect sites are invariant-justified (validated CIDR internals network.rs:151-155, literal defaults network.rs:260/286/289, canonical-JSON serialization of validated values resource_schema.rs:189/396/562, static reason strings error.rs:230-232, fixed constructors device.rs:519 and host.rs:74); the 4 real `let _ =` sites are the compile-time capability assertions in seal.rs:218-224; no panic!/unreachable!/todo!/unimplemented! anywhere + +## serde +- d2b-contracts-resource-p1#7 sev=medium blast=wide effort=S verdict=actionable - `ResourceError` derives Deserialize (error.rs:175-176), bypassing the invariants `ResourceError::new` enforces (current_revision only on ResourceConflict/AuthorizationDenied/RevisionExpired, retry_after_ms only with RetryClass::AfterDelay), so a wire error carrying an inconsistent combination deserializes into an illegal state that the retry decision logic then reads - fix: hand-write `Deserialize` for `ResourceError` through `Self::new`, matching every sibling wire type in this crate - [packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v3/error.rs:177] + evidence: seed 1 `derive\([^)]*(De)?[Ss]erialize` = 85 hits; static read of error.rs:175-259; the retry fields are consumed by d2b-resource-client/src/dispatch.rs:270-273 (record_remote_error matches retry_class then retry_after_ms); census: no production JSON decode site for ResourceError exists today (the wire envelope is built by hand in d2bd-runtime/src/resource_runtime_support.rs:1627), so the bypass is latent on a public wire type +- d2b-contracts-resource-p1#8 sev=medium blast=family effort=S verdict=actionable - `PayloadSchema` derives Deserialize (payload_schema.rs:30-32), bypassing `PayloadSchema::parse`'s closed-object and writeOnly validation, and `CommandSpec::deserialize` (d2b-provider-command/src/command.rs:248-266) feeds the wire value straight in, so a wire Command carrying an open schema or a writeOnly property with a default deserializes as valid - fix: hand-write `Deserialize` for `PayloadSchema` through `Self::parse` (the wire shape is unchanged; producers already use parse) - [packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resource/src/v3/payload_schema.rs:36] + evidence: seed 1 = 85 hits; census `PayloadSchema` over packages/ = consumers d2b-provider-command/src/command.rs:185, d2b-provider-operation/src/operation.rs:458, d2bd/src/foundation_seed.rs:859-860 (which re-parses via parse, showing validation is expected); both spec types are wire shapes pinned in docs/reference/schemas/v3/ +- clean: seeds 2-4 = 163/0/33 hits; the hand-written Deserialize impls (space-anchored seed misses the `impl<'de>` form; ~30 judged manually) are all Wire-struct admission gates calling the validated constructors, which is the recorded house pattern; optionality distinctions (skip_serializing_if vs RequiredNullable) are deliberate and golden-pinned + +## obs +- N/A: seeds 1-4 = 0/0/0/0 hits (println, interpolated event macros, instrument, tracing/log all zero); Cargo.toml carries no tracing or log dependency, so the crate emits no telemetry + +## docs +- d2b-contracts-resource-p1#9 sev=low blast=leaf effort=S verdict=actionable - limits.rs exports 30 `pub const` admission limits (lines 3-33) with no per-item docs and no rationale for the specific values (500, 100, 900000, 30000, 256 KiB, 4 MiB), so a reader cannot tell which bound is load-bearing - fix: add one-line doc comments naming the enforcing boundary (request admission, watch credits, deadline) or a module-level rationale paragraph - [packages/d2b-contracts-resource/src/v3/limits.rs:3, packages/d2b-contracts-resource/src/v3/limits.rs:22] + evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 523 hits; limits.rs has 30/30 pub consts undocumented apart from the one-line module doc +- d2b-contracts-resource-p1#10 sev=low blast=leaf effort=S verdict=actionable - the operations module exports pub accessors with no doc comments: `MutationOrdinal::get` (error.rs:21), `StoreSlot::get` (error.rs:50), the eight `StoreError` accessors (error.rs:262-291), `StoreSealIdentity::new/zone/slot` (seal.rs:48/63/67), `OpenedMutation::body/into_body` (seal.rs:121/125), `MutationSealAcceptor::diagnose/declared_slot` (seal.rs:177/181), and `PreparedStoreMutation::new/mutation/resource_uid/payload_digest` (mod.rs:378-400) - fix: add one-line doc comments, especially for the mutating builder `with_store_slot` and the consume-then-open capability methods - [packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-resource/src/v3/operations/error.rs:262, packages/d2b-contracts-resource/src/v3/operations/seal.rs:48, packages/d2b-contracts-resource/src/v3/operations/seal.rs:121, packages/d2b-contracts-resource/src/v3/operations/mod.rs:378] + evidence: seed 1 = 523 hits; these items carry no `///` at all while the surrounding contract types are otherwise documented to a high standard +- clean: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits, but every Result-returning item documents its failure conditions in prose (the house style); seed 3 `-> Result<` = 127 hits; doc first sentences are strong and redaction behavior is documented on every redacted type + +## perf +- d2b-contracts-resource-p1#11 sev=low blast=leaf effort=M verdict=actionable - `ResourceStatus::new` (resource_status.rs:636-658) serializes the complete status with `canonical_json_bytes(&value)` on every construction to enforce MAX_STATUS_BYTES, after `ensure_layer_size` already serialized the resource layer, so each status write pays two full serializations of the same object - fix: enforce the byte bound once at the write boundary (the caller already serializes for storage) or check the bound with a cheaper size pass; at minimum reuse the layer bytes from `ensure_layer_size` - [packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-resource/src/v3/resource_status.rs:650] + evidence: static (unmeasured); seed 1 `format!\(` = 75 hits (mostly tests and cold error paths), seed 2 collection-new = 35 hits (empty-case defaults), seed 3 `.to_string()` = 5 hits (all tests) +- clean: no format! or allocation in a loop in the part; digest rendering (resource_schema.rs:586-598) pre-sizes its String with with_capacity + +## conc +- N/A: seeds 1-4 = 0/0/0/0 hits (no threads, Mutex/RwLock, atomics, or thread_local in the part) + +## async +- N/A: seeds 1-4 = 0/0/0/0 hits (no async fn, spawn, tokio sync, or tokio attribute in the part) + +## unsafe +- N/A: seeds 1-4 = 0/0/0/0 hits (no unsafe block, fn, impl, transmute, or raw-pointer construct in the part; `unsafe_code = "forbid"` via the workspace lints table) + +## ffi +- N/A: seeds 1-4 = 0/0/0/0 hits (no extern "C", no_mangle, repr(C), or CStr/CString in the part) + +## macro +- N/A: seeds 1-4 = 0/0/0/0 hits (no macro_rules! definitions in the part; the `redacted_debug!`/`parsed_deserialize!`/`string_schema!` invocations here are defined in v3/execution_policy.rs, part 2's scope) + +## test +- clean: seeds 1-4 = 70/232/0/0 hits (test mass, assertion mass, no property/snapshot tooling, no ignored tests); the suite is golden-vector pinned (literal wire bytes in network.rs:1682, resource_schema.rs:1576-1587, volume_state.rs:590-591, host.rs:150-161), redaction-verified with process-id markers, table-driven with per-case failure messages, and the seal capability negative is enforced at compile time (seal.rs:214-225); tests/schema.rs exercises the public surface as a consumer would; no test that cannot fail was found + +## Coverage +- idiom: 1 finding +- own: 1 finding +- type: 2 findings +- api: 1 finding +- err: 1 finding +- serde: 2 findings +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 2 findings +- perf: 1 finding +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 70/232/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md new file mode 100644 index 000000000..c8b57ff3a --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md @@ -0,0 +1,77 @@ +# d2b-contracts-resource-p2 - d2b-contracts-resource - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9703 (excl. src/generated/**) | modules: v3/volume.rs, v3/process.rs, v3/identity.rs, v3/execution_policy.rs, v3/resource.rs, v3/storage.rs, v3/volume_binding.rs, v3/activation_nixos.rs, v3/user.rs, v3/mod.rs, v3/artifact.rs, lib.rs (plus tests/schema.rs for the test lens) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 section f (file list above) + +## idiom +- d2b-contracts-resource-p2#1 sev=medium blast=leaf effort=S verdict=actionable - the sort-dedup-compare uniqueness check is hand-rolled at three production sites while a private helper already exists - fix: extract `ensure_unique(values: &[T]) -> Result<(), PrimitiveSpecError>` into execution_policy.rs (home of PrimitiveSpecError) and call it from VolumeSpec::new, ExecutionPolicy::new, and process.rs check_unique (which keeps only its max-bound check) - [packages/d2b-contracts-resource/src/v3/volume.rs:1210-1213, packages/d2b-contracts-resource/src/v3/volume.rs:1248-1253, packages/d2b-contracts-resource/src/v3/execution_policy.rs:792-796, packages/d2b-contracts-resource/src/v3/process.rs:1571-1579] + evidence: static reading of the three sites plus the existing helper; seeds: `for \w+ in 0\.\.` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 7 (all Default impls preserving frozen defaults, deliberate) +- d2b-contracts-resource-p2#2 sev=low blast=leaf effort=S verdict=actionable - ResourceSpec::serialize iterates `self.base.keys()` and re-gets each key with an avoidable `expect("key returned by canonical object")` - fix: iterate `for (key, value) in &self.base` and call `map.serialize_entry(key, value)?`, deleting the expect and the double lookup - [packages/d2b-contracts-resource/src/v3/resource.rs:621-626] + evidence: static reading; the map is a BTreeMap wrapper so pair iteration is a drop-in; seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 7 +- d2b-contracts-resource-p2#3 sev=low blast=leaf effort=S verdict=actionable - VolumeSpec::new checks `views.contains_key` and then repeats the lookup with a dead `ok_or(MissingRequiredField)` that can never fire - fix: collapse to one `let view = views.get(attachment.view.as_str()).ok_or(PrimitiveSpecError::MissingRequiredField)?;` - [packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223] + evidence: static reading; the second `.ok_or` is unreachable after the `contains_key` early return; seeds: `for \w+ in 0\.\.` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0 + +## own +- clean: seeds ran: `\.clone\(\)` = 28, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 42, `Rc<|RefCell<|Arc)` signature, and the rest are test fixtures; no Rc/RefCell/Arc/Cow anywhere. + +## type +- d2b-contracts-resource-p2#4 sev=medium blast=leaf effort=S verdict=needs-contract - NixosGenerationStatus.observed_generation is a bare u64 while the crate already models exactly this value (zero meaning none) as ObservedGeneration in identity.rs - fix: replace the field type with `ObservedGeneration` (serde-transparent u64, same wire bytes and schemars shape) and update the accessor call sites - [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-resource/src/v3/identity.rs:595-606] + evidence: static comparison with identity.rs ObservedGeneration whose doc states "zero meaning none", matching the field doc "Store generation revision observed by the controller"; seeds: `fn validate_\w+|fn check_\w+` = 13, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 2 (both are validated-at-construction octal/path strings, not state) +- d2b-contracts-resource-p2#5 sev=medium blast=leaf effort=S verdict=needs-contract - ActivationRunnerInput.target_generation is a bare u64 carrying a manual zero check plus a hand-rolled `nonzero_u64_schema`, duplicating the nonzero-generation newtype the crate already generates - fix: use the `nonzero_generation!` macro output (e.g. ConfigurationGeneration, transparent u64 with JsonSchema minimum 1) for the field, deleting `ActivationRunnerInputError::GenerationInvalid`, the zero check in `new`, and `nonzero_u64_schema` - [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:59-63, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:77-87, packages/d2b-contracts-resource/src/v3/identity.rs:448-472] + evidence: static reading; the invariant (nonzero) is already enforced by the existing macro-generated types in identity.rs; wire bytes unchanged under serde-transparent; seeds: `fn validate_\w+|fn check_\w+` = 13, `(mode|kind|state): String` = 2 + +## api +- d2b-contracts-resource-p2#6 sev=low blast=leaf effort=S verdict=actionable - the exported type alias `ValidatedSessionPurpose` has zero callers anywhere in the workspace - fix: delete the alias (identity.rs:270) or document the intended consumer before it accrues surface - [packages/d2b-contracts-resource/src/v3/identity.rs:269-270] + evidence: census: `ValidatedSessionPurpose` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (the definition itself); seeds: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 485, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 31 (house single-surface re-export arms, deliberate) + +## err +- clean: seeds ran: `\.unwrap\(\)|\.expect\(|\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 288, `let _ = |\.ok\(\);` = 1, `enum \w*Error` = 6. Every unwrap/expect outside `#[cfg(test)]` sits on a frozen literal with a named invariant (`expect("strict is a valid token")` process.rs:237, `duration()` process.rs:1636, `system_default()` execution_policy.rs:844, `resource_type()` activation_nixos.rs:245, `UserSpec::minimal` user.rs:127, `ResourceSpec::empty()` resource.rs:543) or after a compiler-invisible byte check (`is_valid_timestamp` identity.rs:207); the single `let _ =` is the deliberate `$clear` flag in the `digest_identity!` redaction macro; the six error enums are field-free so rejection diagnostics never echo caller text. + +## serde +- clean: seeds ran: `derive\([^)]*(De)?[Ss]erialize|serde\(...\)|impl .*Deserialize.*for|serde_json::from_|serde_json::to_` = 493. The hand-written `Deserialize` impls are all Wire-mirror admission gates (private-field struct, `deny_unknown_fields` Wire struct, `Self::new` validation mapped through `serde::de::Error::custom`) - the recorded house pattern per the refusal ledger (docs/explanation/over-engineering-audit-record.md, hand-written Deserialize admission-gate class); `#[serde(flatten)]` on ProcessSpec/EphemeralProcessSpec is serialization-only composition with the Wire mirror re-enabling `deny_unknown_fields`; enum representations are consistently external kebab-case/lowercase; optionality semantics (default vs Option vs skip_serializing_if) are consistent between the Serialize side and the Wire mirror on every checked type. + +## obs +- clean: seeds ran: `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0. The crate emits no telemetry at all; diagnostics are the redacted Debug/Display impls, which the tests pin. + +## docs +- d2b-contracts-resource-p2#7 sev=medium blast=leaf effort=S verdict=actionable - artifact.rs is the only module with an undocumented public surface: MAX_ARTIFACT_ID_BYTES, ArtifactIdError::Invalid, ArtifactId, parse, and as_str all lack doc comments while every sibling module documents its pub items - fix: add one-line doc comments mirroring the BoundedToken contract (bounded lower-kebab artifact identifier, never a host path) - [packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/v3/artifact.rs:7-10, packages/d2b-contracts-resource/src/v3/artifact.rs:22, packages/d2b-contracts-resource/src/v3/artifact.rs:25, packages/d2b-contracts-resource/src/v3/artifact.rs:35] + evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 485, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 142; static comparison shows every other module documents its pub items (e.g. BoundedToken execution_policy.rs:186-191) +- d2b-contracts-resource-p2#8 sev=low blast=leaf effort=S verdict=actionable - two pub fns in execution_policy.rs lack doc comments: `ExecutionPolicyWire::into_policy` (pub because Host/Guest crates decode through the wire mirror) and `string_schema_object` (pub only for the exported `string_schema!` macro expansion) - fix: add one-line docs, noting for string_schema_object that it is macro-support surface - [packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-resource/src/v3/execution_policy.rs:944] + evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 485, `/// # (Examples|Errors|Panics|Safety)` = 0; static reading of the two items + +## perf +- clean: seeds ran: `format!\(` = 84, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 59, `\.to_string\(\)` = 8. The only non-test `format!` is `MilliCpu::to_canonical_string` (execution_policy.rs:363), a cold wire-rendering boundary; `TranscriptHash::to_hex` (identity.rs:660-668) pre-sizes with `String::with_capacity(64)`; `Vec::new()` hits are Default impls and test fixtures where the empty case is the common one; no hot path, no loop allocation, no attacker-keyed hashing (BTreeMap throughout). + +## conc +- N/A (seeds: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; all zero - the crate declares no threads, locks, atomics, or manual Send/Sync) + +## async +- N/A (seeds: `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; all zero - the crate is synchronous contract types only) + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; all zero - no unsafe blocks, fns, impls, or lint settings in the assigned files) + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; all zero - no foreign-language boundary) + +## macro +- clean: seeds ran: `macro_rules!` = 7, `proc_macro|syn::|quote!` = 0, `\$crate` = 1, `to_compile_error|new_spanned` = 0. All seven macro_rules! definitions (label_identity, digest_identity, nonzero_generation in identity.rs; redacted_debug, parsed_deserialize, string_schema in execution_policy.rs; opaque_storage_id in storage.rs) are the genuine impl-per-type generation answer; the exported macros use fully-qualified paths and `$crate::v3::execution_policy::string_schema_object`, so hygiene holds; no proc macros exist. + +## test +- clean: seeds ran: `#\[test\]|#\[tokio::test\]` = 75 (71 unit + 4 integration in tests/schema.rs), `assert_eq!\(|assert_ne!\(|assert!\(` = 299, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0. The suite is behavior-focused: golden byte vectors (MINIMAL_VOLUME_SPEC, MINIMAL_PROCESS_SPEC, GOLDEN_ENVELOPE, canonical base objects), round-trip tests, table-driven rejection tests with per-case messages, redaction tests with process-id markers, and schema-bound preservation tests; no test restates implementation and none is ignored. + +## Coverage +- idiom: 3 finding(s) +- own: clean (seeds ran: 28/42/0) +- type: 2 finding(s) +- api: 1 finding(s) +- err: clean (seeds ran: 288/1/6) +- serde: clean (seeds ran: 493) +- obs: clean (seeds ran: 0/0/0/0) +- docs: 2 finding(s) +- perf: clean (seeds ran: 84/59/8) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn, await, tokio, or block_on) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks/fns/impls or lint settings) +- ffi: N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, repr(C), or CStr) +- macro: clean (seeds ran: 7/0/1/0) +- test: clean (seeds ran: 75/299/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md new file mode 100644 index 000000000..1658e6ba8 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md @@ -0,0 +1,77 @@ +# d2b-contracts-zone-session-p1 - d2b-contracts-zone-session - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6284 (excl. src/generated/**) | modules: v3::component_session, v3::role, v3::resource_export, v3::zone_link, v3::resource_import, v3::mod, lib +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/v3/component_session.rs, src/v3/role.rs, src/v3/resource_export.rs, src/v3/zone_link.rs, src/v3/resource_import.rs, src/v3/mod.rs, src/lib.rs (part 1/2; wire-contract crate, U1 (d) 6-7 apply) + +## idiom +- d2b-contracts-zone-session-p1#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default for ReceiveSequence` and `SendSequence` duplicate what `#[derive(Default)]` generates field-for-field (u64 plus bool, both zero) - fix: add `Default` to the derive lists of `ReceiveSequence` and `SendSequence` and delete the two hand-written impls; keep `ZoneLinkLimits`' Default (zone_link.rs:126) which preserves the nonzero bounds invariant - [src/v3/component_session.rs:1935, src/v3/component_session.rs:1976] + evidence: seed2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 3 hits; the two Default bodies call `Self::new()` whose field values equal the derived zeros, so the derive is behavior-identical; ZoneLinkLimits::default() calls `default_values()` (256/32/10/300) and is correctly hand-written +- clean: seeds 1/2/3 = 0/3/0 (`for \w+ in 0..` / hand-written impls / `let mut x = String|Vec::new()`); no index loops, no statement-style accumulation, and the only hand-written impls are the two derivable Defaults above plus the invariant-preserving ZoneLinkLimits one + +## own +- d2b-contracts-zone-session-p1#2 sev=low blast=family effort=S verdict=actionable - `HandshakeOffer::from(policy.clone())` at 7 sites across two crates: the by-value `impl From for HandshakeOffer` (component_session.rs:1172) forces a clone at every site that holds `&EndpointPolicy`, and every in-repo caller clones - fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in component_session.rs and switch the 7 sites to borrow; then delete the by-value impl if the census stays clone-only - [src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session.rs:1014, d2b-session/src/admission.rs:593, d2b-session/src/engine.rs:689, d2b-session/src/handshake.rs:112, d2b-session/src/handshake.rs:171] + evidence: seed1 (`.clone()`) = 14 hits; census: `HandshakeOffer::from` over packages/ = 7 sites, every one passes a clone; the fix is additive so no caller breaks +- d2b-contracts-zone-session-p1#3 sev=low blast=family effort=S verdict=actionable - `ResourceExportSpec::validate_target` clones `target.resource_type()` and `target.metadata().name()` out of a borrowed `&ResourceEnvelope` only to rebuild the ref for comparison, because `ResourceRef::new` takes owned parts and the envelope exposes no borrowed accessor - fix: add `impl From<&ResourceEnvelope> for ResourceRef` (or a `resource_ref()` accessor) in d2b-contracts-resource and use it at the comparison site - [src/v3/resource_export.rs:545, src/v3/resource_export.rs:546] + evidence: seed1 (`.clone()`) = 14 hits; `ResourceRef::new(resource_type: ResourceTypeName, metadata: ResourceMetadata, ...)` takes owned values (d2b-contracts-resource/src/v3/resource.rs:712) and no `resource_ref()` accessor exists on the envelope; the clones are cold-path but signature-forced +- clean: seeds 1/2/3/4 = 14/21/0/0 (`.clone()` / `.to_owned()|.to_vec()|.to_string()` / `Rc<|RefCell<|Arc Result<`) = 102 hits; the listed methods verified doc-less while the role.rs/resource_export.rs/zone_link.rs/resource_import.rs constructors are documented, so the gap is specific to the component_session codec + +## perf +- clean: seeds 1/2/3 = 20/24/3 (`format!(` / collection `::new()` / `.to_string()`); format! is confined to cold `JsonSchema::schema_name` and #[cfg(test)] fixtures, collection news are test vectors, BinaryWriter is pre-sized with `with_capacity`, and the encode/decode paths are single-pass with no hot-loop allocation; static (unmeasured) + +## conc +- N/A: seeds 0/0/0/0 all zero (`std::thread::|thread::spawn|thread::scope` / `Mutex<|RwLock<` / `Atomic\w+|Ordering::` / `thread_local!|unsafe impl (Send|Sync) for`); no threads, locks, or atomics in a pure wire contract + +## async +- N/A: seeds 0/0/0/0 all zero (`async fn|async move|.await` / `tokio::spawn|spawn_blocking|JoinSet|select!|join!` / `tokio::sync::(Mutex|RwLock|Notify)` / `#[tokio::(main|test)]|Runtime::block_on`); no async code in the contract layer + +## unsafe +- N/A: seeds 0/0/0 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` / `// SAFETY:` / `transmute|from_raw|MaybeUninit|mem::zeroed`); seed 4 `unsafe_code` = forbid inherited through `[lints] workspace = true` (Cargo.toml), no local exceptions + +## ffi +- N/A: seeds 0/0/0/0 all zero (`extern "C"|no_mangle|unsafe(link_section` / `catch_unwind` / `repr(C)|repr(transparent)` / `CStr|CString|c_char`); no FFI surface + +## macro +- clean: seeds 1/2/3/4 = 3/0/0/0 (`macro_rules!` / `proc_macro|syn::|quote!` / `$crate` / `to_compile_error|new_spanned`); `closed_enum`, `wire_enum_values`, and `bounded_bytes` are impl-per-type generation (a genuine macro answer) with narrow ident/literal fragment specifiers, invoked only in the defining module where their unqualified `BinaryError` reference resolves, and no proc-macro machinery + +## test +- d2b-contracts-zone-session-p1#7 sev=medium blast=leaf effort=M verdict=actionable - the security-relevant codec state machines have no tests: RequestEnvelope::admit deadline/skew/lifetime math, FragmentSequence ordering/duplicate/complete detection, ReceiveSequence replay and nonce exhaustion, SendSequence::take, AttachmentCredits::reserve and process_pool, and the canonical round-trips of RecordHeader/FragmentHeader/HandshakeAccept, while the suite covers only policy validation, redaction, and frozen enum vectors - fix: add unit tests asserting the error variants (InvalidDeadline, Reordered, Duplicate, Replay, NonceExhausted, CreditExceeded) for each state machine, plus encode/decode round-trips for the header types - [src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_session.rs:1916, src/v3/component_session.rs:2732] + evidence: test seeds = 25 `#[test]` / 110 asserts / 0 proptest/insta/rstest / 0 `#[ignore]`; grep `FragmentSequence|ReceiveSequence|SendSequence|\.admit\(|process_pool` over tests/ = 0 hits, and no header round-trip test exists outside the enum-vector golden tests + +## Coverage +- idiom: 1 finding(s) +- own: 2 finding(s) +- type: clean (seeds ran: 14/0/0) +- api: 1 finding(s) +- err: clean (seeds ran: 96/0/0/10) +- serde: clean (seeds ran: 52/105/0/11) +- obs: clean (seeds ran: 0/0/0/0) +- docs: 2 finding(s) +- perf: clean (seeds ran: 20/24/3) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) +- async: N/A (seeds: 0/0/0/0 all zero; no async fns) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest inherits unsafe_code = "forbid") +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: clean (seeds ran: 3/0/0/0) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md new file mode 100644 index 000000000..399a5e4e9 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md @@ -0,0 +1,87 @@ +# d2b-contracts-zone-session-p2 - d2b-contracts-zone-session - part 2/2 +Baseline: 6ebdd4cec | LOC audited: 6403 (excl. src/generated/**) | modules: v3/zone_routing.rs, v3/resource_bundle.rs, v3/zone_session.rs, v3/zone.rs, v3/role_binding.rs, v3/services.rs, v3/emergency_policy.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 section f (7 files, no item-range splits) + +## idiom +- clean: seeds 0/1/1 - the single hand-written Default (emergency_policy.rs:170) preserves the drain-deadline invariant a field-wise derive would break (card false positive), and the one Vec::new accumulation (zone_routing.rs:1554) is test code whose loop body asserts per item, where a plain loop is the right shape. + +## own +- d2b-contracts-zone-session-p2#1 sev=low blast=leaf effort=S verdict=actionable - ZoneLinkRouteWithdrawal::new clones the entire route-id vec only to detect duplicates - fix: sort the owned vec in place and check windows(2), mirroring the crate's own dedup pattern in RoleBindingSpec::with_facets (role_binding.rs:273-276) - [zone_routing.rs:883] + evidence: seed \.clone\(\) = 81 hits; this is the only non-test clone in a validation path, and the in-crate sort-plus-windows pattern at role_binding.rs:273-276 proves the clone is avoidable. +- d2b-contracts-zone-session-p2#2 sev=low blast=leaf effort=S verdict=actionable - reject_runtime_or_private_fields clones the whole spec object (object.clone().into_inner()) just to wrap it for the walk, on every BundleResource::new call - fix: make walk iterate the CanonicalJsonObject map directly (and a sibling fn for arrays) so no CanonicalJsonValue wrapper or clone is built - [resource_bundle.rs:944, resource_bundle.rs:149] + evidence: seed \.clone\(\) = 81 hits; the clone is on the success path of every BundleResource::new (call site resource_bundle.rs:149), and walk only needs Object and Array cases it can take by reference. +- d2b-contracts-zone-session-p2#3 sev=low blast=leaf effort=S verdict=actionable - ServiceDescriptor::new clones each method String for BoundedText::parse, which takes impl Into - fix: pass method.as_str() (String: From<&str> satisfies the bound) - [services.rs:216] + evidence: seed \.clone\(\) = 81 hits; the clone is required only by the argument position, and as_str() removes it without changing the parse allocation. +- clean: seeds 81/11/0/0 - remaining clones are test fixtures, wire-rendering to_owned on literals (schema_name, protocol constants), and the ResourceRef::new pair at resource_bundle.rs:689-690 which is required by the owned signature (same shape at d2b-contracts-resource/src/v3/resource.rs:718); no Rc/RefCell/Arc/Cow anywhere. + +## type +- d2b-contracts-zone-session-p2#4 sev=low blast=leaf effort=S verdict=actionable - narrowing_set_is_subset takes a bare empty_allowed_is_unrestricted: bool that flips the empty-allowed semantics between call sites - fix: replace the bool with a two-variant enum (or split into named fns) so the three call sites state the policy they mean - [role_binding.rs:179-182, role_binding.rs:149-162] + evidence: seed is_\w+: bool = 5 hits; the bool is passed both true (subresources, execution_refs) and false (zones) at role_binding.rs:149-162, so it is a real semantic switch, not a constant. +- clean: the remaining seed hits are cross-value validators (validate_self_resource, validate_finalizer, validate_scope_against_role, validate_zone, ZoneEnrollmentIdentity::validate) that check identity/ownership relations no parsed type can carry, and ZoneEnrollmentIdentity::validate is enforced at both decode boundaries (zone_session.rs:448, 502); no stringly-typed state and no flag-soup structs (EmergencyScope's four booleans are independent actions with all combinations valid). + +## api +- d2b-contracts-zone-session-p2#5 sev=low blast=leaf effort=S verdict=actionable - EmergencyPolicySpec::default_values is a pub method with zero callers outside its own Default impl - fix: delete it and let Default::default() be the single entry (or make it private) - [emergency_policy.rs:142, emergency_policy.rs:170] + evidence: census: default_values over packages/ = 4 hits (zone_link.rs:96, 128; emergency_policy.rs:142, 172), all within the two definitions and their Default delegation; no external caller. +- d2b-contracts-zone-session-p2#6 sev=low blast=leaf effort=S verdict=actionable - ZoneSpec::validate always returns Ok and has no callers, a dead always-succeeding validation on the exported surface - fix: remove the method (ZoneSpec is the empty spec; its Deserialize gate already enforces the only invariant) - [zone.rs:74] + evidence: census: ZoneSpec over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file (src/v3/zone.rs); the method is never invoked, only defined. +- clean: seeds 292/0/2 - the pub surface is the deliberate wide wire vocabulary of a contract crate (needs-contract to narrow); the two pub use arms (zone_session.rs:89, 104) are the documented house re-export pattern for the component-session taxonomy; no Arc/Rc/Box/RefCell in any public signature. + +## err +- d2b-contracts-zone-session-p2#7 sev=medium blast=leaf effort=S verdict=actionable - from_component_session on EndpointPurpose and ServicePackage panics via expect("preserved component-session tag") on a wire-derived value, enforcing the cross-taxonomy totality only at runtime - fix: replace the tag lookup with an exhaustive match over base::EndpointPurpose / base::ServicePackage variants so adding a component-session variant becomes a compile error, or return Result like EndpointRole::from_component_session already does (zone_session.rs:314) - [zone_session.rs:297, zone_session.rs:332] + evidence: seed \.unwrap\(\)|\.expect\( = 227 hits; 225 are in #[cfg(test)] or on literally-built values (card false positives), and these two are the only non-test expects on input-derived values in the lane. +- clean: seeds 227/1/0/5 - no panic!/unreachable!/todo!/unimplemented! anywhere; the single let _ = (zone.rs:84) discards a Wire value while propagating via ?; the five error enums are Copy unit-variant taxonomies with prose-documented Display, and wire refusal codes (ZoneEnrollmentRefusal) are returned, not panicked. + +## serde +- d2b-contracts-zone-session-p2#8 sev=medium blast=family effort=M verdict=actionable - seventeen hand-written Deserialize impls repeat the identical Wire-struct shape (local #[derive(Deserialize)] Wire with deny_unknown_fields, then new() plus map_err(serde::de::Error::custom)) - fix: consolidate behind a shared macro in the style of parsed_deserialize! at d2b_contracts_resource::v3::execution_policy, or #[serde(try_from = "Wire")] with TryFrom, keeping each new() gate as the admission check - [zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932, zone_routing.rs:1043, zone_routing.rs:1142, zone_routing.rs:1246, resource_bundle.rs:101, resource_bundle.rs:185, resource_bundle.rs:457, zone.rs:79, zone.rs:172, zone.rs:327, role_binding.rs:192, role_binding.rs:382, services.rs:265, emergency_policy.rs:176] + evidence: seed impl .*Deserialize.*for = 0 hits (the card regex misses impl<'de> forms); dedicated search impl<'de> Deserialize<'de> for = 20 blocks in the lane, 17 of them the Wire-struct shape; this is the recorded not-applied row C4 (docs/explanation/over-engineering-audit-record.md:475), so re-proposing is actionable with this citation. +- clean: seeds 52/90/0/45 - deny_unknown_fields is applied per type on every Wire gate, rename_all conventions are consistent (camelCase structs, kebab-case enums, PascalCase method vocabularies), optionality is deliberate (skip_serializing_if on BundleResourceMetadata and ProcessTemplateBinding, pinned null spellings on RoleBindingSpec round-trip goldens), and no live admission gate is bypassed by a direct derive. + +## obs +- N/A: seeds 0/0/0/0 all zero; the crate declares no tracing/log dependency (Cargo.toml), so there is no telemetry surface to judge. + +## docs +- d2b-contracts-zone-session-p2#9 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub constructors and the two panicking lifts document failure modes in prose but carry no canonical # Errors or # Panics sections anywhere in the lane - fix: add # Errors to the wire constructors (ZonePath::new, ZoneLinkRouteAdvertisement::new, RoleBindingSpec::with_facets, EmergencyPolicySpec::new, ServiceDescriptor::new) listing their PrimitiveSpecError/ContractError variants, and # Panics to from_component_session noting the totality invariant - [zone_routing.rs:210, zone_routing.rs:685, role_binding.rs:254, emergency_policy.rs:112, services.rs:200, zone_session.rs:296] + evidence: seed /// # (Examples|Errors|Panics|Safety) = 0 hits while -> Result< = 73 hits; every pub item carries a prose doc comment (checked all 40 candidates flagged by the lookback scan), so the gap is the canonical-section shape, not missing docs. +- clean: all pub items documented with one-line first sentences; module-level docs present (zone_routing.rs:1-16); magic values carry the why (MAX_ZONE_ADVERTISEMENT_LIFETIME_SECONDS, ZONE_ROUTE_INITIAL_HOP_BUDGET); no doctests exist and none are needed for pure contract types. + +## perf +- d2b-contracts-zone-session-p2#10 sev=low blast=leaf effort=S verdict=actionable - ProcessTemplateBinding validation builds a fresh String via format!("/bin/{}", ...) on every construction to run an ends_with check - fix: binary_path.strip_suffix(binary_ref.as_str()).is_some_and(|prefix| prefix.ends_with("/bin/")) which is allocation-free - [resource_bundle.rs:382] + evidence: seed format!\( = 38 hits; 37 are tests or the one-shot fingerprint renderer (services.rs:297); this is the only success-path allocation in the lane. static (unmeasured). +- clean: seeds 38/42/0 - the Vec::new/BTreeMap::new hits are the empty-case constructor (resource_bundle.rs:592) and test fixtures; no to_string() sites; no loops with per-iteration allocation. + +## conc +- N/A: seeds 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync in the lane. + +## async +- N/A: seeds 0/0/0/0 all zero; no async fn, await, tokio, or block_on in the lane. + +## unsafe +- N/A: seeds 0/0/0/0 all zero; no unsafe blocks, fns, impls, or SAFETY comments; the crate inherits unsafe_code = "forbid" via [lints] workspace = true (Cargo.toml). + +## ffi +- N/A: seeds 0/0/0/0 all zero; no extern "C", no_mangle, repr(C), catch_unwind, or CStr/CString in the lane. + +## macro +- clean: seeds 2/0/0/0 - opaque_routing_token! (zone_routing.rs:117) and zone_closed_enum! (zone_session.rs:121) are by-example impl-per-type generators (a genuine macro case), use narrow fragment specifiers (meta/ident/literal), are invoked only in their defining modules so hygiene holds, and zone_closed_enum!'s local redeclaration is documented as deliberately cheaper than exporting the component_session macro (zone_session.rs:114-120). + +## test +- d2b-contracts-zone-session-p2#11 sev=medium blast=leaf effort=S verdict=actionable - EmergencyPolicySpec's contract branches have no tests: the file holds exactly one test covering only the union behavior - fix: add table tests for new() rejecting deadline 0 and > MAX_EMERGENCY_DRAIN_DEADLINE_SECONDS, reason > MAX_EMERGENCY_REASON_BYTES, and control characters; plus effective_scope returning None when no policy is enabled, and the serde default round-trip - [emergency_policy.rs:236, emergency_policy.rs:112] + evidence: seeds #[test] = 50, assert = 255, proptest/insta/rstest = 0, #[ignore] = 0; emergency_policy.rs has 1 test for 4 validation branches plus the effective_scope all-disabled case, the widest untested contract surface in the lane. +- clean: seeds 50/255/0/0 - the other six modules carry strong in-module tests: golden canonical wire vectors with hand-written expectations (zone_routing.rs:1450-1462, zone_session.rs:787-908), tamper rejection (resource_bundle.rs:1110-1124), bounds at every MAX constant, secret-marker echo checks (zone_routing.rs:2052), and integration coverage of the re-exported session surface in tests/contracts.rs; no test restates implementation, no ignored tests. + +## Coverage +- idiom: clean (seeds ran: 0/1/1) +- own: 3 finding(s) +- type: 1 finding(s) +- api: 2 finding(s) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks and no unsafe_code = "allow" manifest) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: clean (seeds ran: 2/0/0/0) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md new file mode 100644 index 000000000..c15b05766 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md @@ -0,0 +1,81 @@ +# d2b-contracts - d2b-contracts +Baseline: 6ebdd4cec | LOC audited: 10,743 (excl. src/generated/**; no tests/** Rust files - only tests/fixtures/workload-execution-posture-v1.json fixture) | modules: whole crate (lib.rs + 26 public modules + src/v3/{mod,ifname}.rs; generated/ excluded) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-contracts#1 sev=medium blast=family effort=S verdict=actionable - d2b-contracts-control::public_wire re-declares a private copy of `validate_audit_page` instead of reusing the public export in d2b-contracts::audit_wire (the canonical home), so the two copies can drift - fix: import `validate_audit_page` from d2b_contracts::audit_wire in d2b-contracts-control/src/public_wire.rs (alongside the AExisting AuditExportCursor/Entry import at public_wire.rs:1)and delete the pub(crate) copy at public_wire.rs:2203 - [packages/d2b-contracts/src/audit_wire.rs:51, packages/d2b-contracts-control/src/public_wire.rs:2203] + evidence: census: `validate_audit_page` over packages/tests/docs = 5 hits: 2 definitions + 2 call sites (broker_wire.rs:2206, public_wire.rs:2193) + 1 import; the private copy duplicates the canonical home. + +## own +- clean: seeds ran: ~100/~46/0/0 ).clone(), .to_owned/.to_vec/.to_string, Rc/RefCell/Arc/Arc, Cow<); every production clone has a one-sentence ownership justification (negotiation-record ownership capability.rs:218, error-context ownership controller_config.rs:158 and identity_config.rs:149, owned-String accessors error.rs:674,691, wire-rendering string surfaces identity.rs:368/473/598, RealmTarget construction from a borrow target.rs:261/430/440, duplicate-target error message unsafe_local_workloads.rs:60/67and realm.rs:194-195); remaining clones sit in unit tests, and there are no Rc/RefCell/Arc/Cow sites. + +## type +- d2b-contracts#2 sev=medium blast=wide effort=M verdict=needs-contract - `complete: bool` + `next_cursor: Option<&AuditExportCursor>` in the audit-page surface encode exactly-two-valid-of-four states and both invalid combos are type-expressible; an enum would make them unrepresentable - fix: replace the pair with `enum AuditPageEnd { Complete, More(AuditExportCursor) }` and drive the wire structs/validators from it (callers: d2b-contracts-broker/src/broker_wire.rs:2206,and d2b-contracts-control/src/public_wire.rs:2193), keeping the existing admission behaviour - [packages/d2b-contracts/src/audit_wire.rs:51-59, packages/d2b-contracts-broker/src/broker_wire.rs:2184-2187, packages/d2b-contracts-control/src/public_wire.rs:2167-2173] + evidence: seed `fn validate_\w+|fn check_\w+|is_\w+: bool|\w+_flag: bool|(mode|kind|state): String` = 16 hits; the `complete`/`next_cursor` pair is the Option-pair smell the skill names; wire shape pinned by docs/reference/daemon-api.md:385,417 and schemas/v2/wire-protocol.json (AuditExportEntry/response definitions. + +## api +- d2b-contracts#3 sev=medium blast=leaf effort=S verdict=actionable - `pub fn validate_usb_bus_id` (types.rs:140) is never called in production and re-implements usbip.rs::validate_bus_id with a divergent contract (64-byte cap vs SYSFS_BUS_ID_MAX=31, requires a `-` separator whereusbip accepts bare `B`, plain String error vs typed `BusIdError`)- fix: delete types.rs::validate_usb_bus_id and move its covariance cases (types.rs:202-203into the usbip.rs test table so one canonical bus-id checker survives - [packages/d2b-contracts/src/types.rs:140, packages/d2b-contracts/src/usbip.rs:44] + evidence: census: `validate_usb_bus_id` over packages/tests/docs = 3 hits: 1 definition + 2 test assertions, 0 production callers; the canonical sibling is usbip.rs::validate_bus_id`. +- d2b-contracts#4 sev=medium blast=leaf effort=S verdict=actionable - `pub fn MediaRef::validate_value` (types.rs:114) is dead:the `opaque_id!`-generated `MediaRef::new` accepts any string without calling it, so the public fn advertises a shape check that never runs on the type it names - fix: either delete the fn, or wire it into construction via a `TryFrom<&str>` boundary on MediaRef (the house parse-gate pattern)so calers cannot bypass it - [packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114] + evidence: census: `MediaRef::validate_value` over packages/tests/docs = 3 hits: 1 definition + 2 test assertions (types.rs:200-201), 0 production callers (the generated macro body at types.rs:14-25 calls no validator. + +## err +- d2b-contracts#5 sev=medium blast=leaf effort=L verdict=actionable - Public constructors/validators return `Result<_, String>` or `&'static str` (ConfiguredArgv::new configured_argv.rs:15, RealmWorkloadsLauncherV2Json::validate launcher.rs:21, UnsafeLocalWorkloadsJson/LocalVmConfiguredWorkload/UnsafeLocalWorkload::validate unsafe_local_workloads.rs:35/81/96, MediaRef::validate_value and validate_usb_bus_id types.rs:114/140, validate_audit_page audit_wire.rs:51) while sibling validators inthe same crate use typed enum errors (BusIdError, IfNameError, IdError, ContractStringError, IdentityError, TokenError), forcing callers to string-match instead of matching variants - fix: introduce typed error enums per surface (e.g. `ConfiguredArgvError`, `UnsafeLocalWorkloadsError`, `LauncherMetadataError`, `MediaRefError`)with thiserror-style Display + std::error::Error impls and return them; call sites that only `.unwrap()` (census: ConfiguredArgv::new used in d2b-contracts-control, d2bd-runtime, d2bd, d2b-unsafe-local-helper) compile unchanged - [packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:21, packages/d2b-contracts/src/unsafe_local_workloads.rs:35, packages/d2b-contracts/src/types.rs:114, packages/d2b-contracts/src/audit_wire.rs:51] + evidence: seed `\.unwrap\(\)|\.expect\(|let _ = |\.ok\(\);|\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 209 hits,mostly test-local; the 6 production String-error surfaces are named above;`enum \w*Error` =the typed-error sibling taxonomy the change would match. + +## serde +- d2b-contracts#6 sev=medium blast=wide effort=M verdict=needs-contract - `AuditExportEntry` carries `record: Option` andi `error: Option` where the doc (audit_wire.rs:27) promises exactly one is always populated,so both-None is a wire-accepted illegal state (the broker's own writers d2b-broker/src/audit.rs:1730-1732 etc always set one,but a literal or foreign producer can emit neither) - fix: replace the pair with an enum payload representation (e.g. `#[serde(tag = "type")] enum AuditExportEntryPayload { Record { record: Value }, Error { error: AuditExportErrorCode } }` or an admission-gate enforcing exactly-one at decode),preserving or explicitly changing the wire shape - [packages/d2b-contracts/src/audit_wire.rs:27-36] + evidence: seed `derive\([^)]*(De)?[Ss]erialize` = ~240 hits,`serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = ~80,`impl .*Deserialize.*for` = ~30,`serde_json::from_|to_` = ~28; the crate's serde discipline is otherwise uniform (rename_all/deny_unknown_fields/skip_serializing_if defaults everywhere); wire shape pinned by docs/reference/daemon-api.md:385,417 and schemas/v2/wire-protocol.json (AuditExportEntry definition. + +## obs +- N/A (seeds: 0/0/0/0 all zero; crate declares no println/log call and Cargo.toml carries no tracing/log dependency - only semver, serde, serde_json, schemars, sha2. + +## docs +- d2b-contracts#7 sev=low blast=leaf effort=M verdict=actionable - Public Result-returning parse/validate fns carry failure conditions only in prose (e.g. ids.rs:138-139, usbip.rs:44-46, contract_id.rs:99, realm.rs:88-90)and only one canonical doc section exists crate-wide,so`cargo doc` readers get no uniform `# Errors` contract - fix: add canonical `# Errors` sections to the public `-> Result<` fns (keeping the existing prose as the section bodies),matching the one existing `# Examples` pattern at workload_identity.rs:46 - [packages/d2b-contracts/src/ids.rs:138, packages/d2b-contracts/src/usbip.rs:44, packages/d2b-contracts/src/contract_id.rs:99, packages/d2b-contracts/src/audit_wire.rs:51] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~520 hits,`/// # (Examples|Errors|Panics|Safety)` = 1 hit (workload_identity.rs:46),`-> Result<` = ~115; pub items themselves are uniformly documented(no missing-docs class found),so the finding is section-shape,not coverage. + +## perf +- clean: seeds ran: ~70/~10/~27 (format!, Vec/VecDeque/HashMap/BTreeMap::new, .to_string()); all format! sites are error paths, one-shot render/schema builders, deserialize gates, or tests (e.g. error.rs:691-692, configured_argv.rs:53-74, ifname.rs:292,306,324-335),the Vec::new sites are empty-constructor/deserialize-gate/test builders, and no hot-path allocation class was found; static (unmeasured). + + + +## conc +- N/A (seeds: 0/0/0/0 all zero; no threads, mutexes, atomics, or unsafe Send/Sync claims in the crate. + +## async +- N/A (seeds: 0/0/0/0 all zero; no async fns, awaits, spawns, otokio runtime usage in the crate. + +## unsafe +- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks/fns/impls, SAFETY comments, transmute/from_raw/MaybeUninit, or unsafe_code text; crate inherits workspace `unsafe_code = "forbid"` via [lints] workspace=true in Cargo.toml. + + + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, catch_unwind, repr(C)/repr(transparent), CStr/CString/c_char sites (serde(transparent) is not an FFI repr. + +## macro +- clean: seeds ran: 7/0/0/0 (macro_rules! = the 7 definitions: contract_string!, realm_controller_string!, opaque_credential_value!, label_identity!, digest_identity!, id_newtype!, opaque_id!; proc_macro/syn/quote/$crate/to_compile_error = 0); all 7 are impl-per-type wire-newtype generators with concrete fragment specifiers (`ident`, `expr`, edition-2024 `expr_2021`, `meta`) and module-scoped textual scope (no #[macro_export], so no $crate path-shadowing hazard; no procedural macros. + + + +## test +- clean: seeds ran: ~70/~397/0/0 (#[test]/#[tokio::test], assert_eq!/assert_ne!/assert!, proptest/insta/rstest, #[ignore]); the crate's unit suites are table-driven round-trip/round-trip-fixture tests with real `tests/fixtures/workload-execution-posture-v1.json` consumption (workload.rs:222-249), fail-closed decode tests, schema-shape assertions,and redaction assertions; no #[ignore]d, flaky, or assert-nothing tests were found; there is no tests/** Rust integration surface (only the JSON fixture), which matches the crate's contract-module shape. + + + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: 146 total, all production clones explainable; no Rc/RefCell/Arc/Cow) +- type: 1 finding(s) +- api: 2 finding(s) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: 1 finding(s) +- perf: clean (seeds ran: ~70/~10/~27; allocation sites are cold/error/test paths) +- conc: N/A (seeds: 0/0/0/0 all zero; no threading/locks/atomics) +- async: N/A (seeds: 0/0/0/0 all zero; no async surface) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks; workspace forbids) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: clean (seeds ran: 7/0/0/0; 7 module-scoped impl-generating macros, no proc macros) +- test: clean (seeds ran: ~70/~397/0/0; no #[ignore]d or vacuous tests found) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md new file mode 100644 index 000000000..a9d58a2b8 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md @@ -0,0 +1,76 @@ +# d2b-core-controller-p1 - d2b-core-controller - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6805 (excl. src/generated/**) | modules: controller_assignment.rs, binding_children.rs, coordinator.rs, main.rs, controllers.rs, lib.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f): src/controller_assignment.rs, src/binding_children.rs, src/coordinator.rs, src/main.rs, src/controllers.rs, src/lib.rs (part 2: authority.rs, owner_reconcile.rs, authority_persistence.rs, migration.rs) + +## idiom +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 0; the single hand-written Default (controllers.rs:266) preserves the all-eleven-kinds registry invariant a field-wise derive would break, and every hand-written Debug impl is a partial redaction (the A6 class from docs/explanation/over-engineering-audit-record.md:459) that the all-redact `redacted_debug!` macro cannot express; no index loops, no statement-style accumulation. + +## own +- clean: seeds `\.clone\(\)` = 163, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 61, `Rc<|RefCell<|Arc Result<` items); failure conditions live only in the error-enum variant docs, so a caller must read the enum to learn which errors a fence method returns - fix: add `# Errors` sections naming the returned variants to the pub Result-returning methods, starting with the fence methods (validate_for, validate_writer, query, admit, publish_readiness, bind_vm) - [packages/d2b-core-controller/src/controller_assignment.rs:1793, 3054, 2501, 2720, packages/d2b-core-controller/src/main.rs:188, packages/d2b-core-controller/src/coordinator.rs:206] + evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 242, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 83 +- d2b-core-controller-p1#7 sev=low blast=leaf effort=S verdict=actionable - pub struct fields without doc comments: RuntimeReadiness (3 of 5 fields), RecoverySnapshot (5 of 7), HandlerStatus (all 8); the undocumented fields (checkpoint_revision, last_reconciled_tick, retry_after_tick, provider_lease_count) are non-obvious - fix: add one-line field docs to RuntimeReadiness, RecoverySnapshot, and HandlerStatus - [packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controllers.rs:198-209] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 242 with the three structs' field blocks read in full + +## perf +- clean: seeds `format!\(` = 2 (both inside #[cfg(test)]), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 20 (cold admission, snapshot, and digest paths), `\.to_string\(\)` = 1 (wire rendering); no allocation site sits in a loop over unbounded input (mutation arrays capped at 128, verb sets at 64, status collections at MAX_STATUS_COLLECTION_ENTRIES); static (unmeasured) + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 13, `thread_local!|unsafe impl (Send|Sync) for` = 0; the atomics (AssignmentLeaseState phase/stale_observation at controller_assignment.rs:2661-2685, authority_epoch at main.rs:99) use correct Acquire/Release store/load pairs and AcqRel on an epoch counter; no lock, thread, or manual Send/Sync claim in the part. + +## async +- N/A: seeds `async fn|async move|\.await|tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(|tokio::sync::(Mutex|RwLock|Notify)|#\[tokio::(main|test)\]|Runtime::block_on` = 0 over the part's six files; all tokio usage in this crate lives in part 2 (authority.rs, authority_persistence.rs) + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern|// SAFETY:|transmute|from_raw|MaybeUninit|mem::zeroed|unsafe_code` = 0; no unsafe blocks, SAFETY comments, or lint overrides in the part + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section|catch_unwind|repr\(C\)|repr\(transparent\)|CStr|CString|c_char` = 0 + +## macro +- N/A: seeds `macro_rules!|proc_macro|syn::|quote!|\$crate|to_compile_error|new_spanned` = 0; redacted_debug! is invoked (controller_assignment.rs:68), not defined, in this part + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 50 in src plus 3 in tests/owned_children.rs, `assert_eq!\(|assert_ne!\(|assert!\(` = 183 plus 21, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; tests assert behavior (phase transitions, fence rejections, canonical round-trips, zone isolation, transport tamper rejection) with human-written expectations, no network or clock dependence, and the integration test consumes the public owner-reconcile API as a real caller. + +## Coverage +- idiom: clean (seeds: 0/1/0) +- own: clean (seeds: 163/61/0/0) +- type: clean (seeds: 5/0/0) +- api: 4 finding(s) +- err: clean (seeds: 285/0/0/7) +- serde: 1 finding(s) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in manifest) +- docs: 2 finding(s) +- perf: clean (seeds: 2/20/1) +- conc: clean (seeds: 0/0/13/0) +- async: N/A (seeds: 0 all zero; all tokio usage in part 2) +- unsafe: N/A (seeds: 0 all zero) +- ffi: N/A (seeds: 0 all zero) +- macro: N/A (seeds: 0 all zero) +- test: clean (seeds: 53/204/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md new file mode 100644 index 000000000..042ae2e6e --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md @@ -0,0 +1,88 @@ +# d2b-core-controller-p2 - d2b-core-controller - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6748 (excl. src/generated/**) | modules: authority, owner_reconcile, authority_persistence, migration +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: src/authority.rs, src/owner_reconcile.rs, src/authority_persistence.rs, src/migration.rs (U1 section f) + +## idiom +- d2b-core-controller-p2#1 sev=low blast=leaf effort=S verdict=actionable - the duplicate-reservation checks bind a holder only to silence it with `let _ = holder;`, when the check is a pure predicate - fix: replace the `if let Some(holder) = ... { let _ = holder; return Err(...); }` blocks with `if entry.holders.iter().any(|holder| holder.owner_proof == request.owner_proof) { return Err(...); }` in admit_authority_inner_with_operation and admit_with_operation_id - [authority.rs:2189-2192, authority.rs:2542-2545] + evidence: seeds ran: `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 (the hand-written `Default for HostGlobalAuthorityIndex` at authority.rs:1745 preserves the per-instance nonce invariant, so a derive is correctly refused), `let mut \w+ = (String|Vec)::new\(\)` = 3 (statement accumulation in side-effectful plan/propagate loops, where the plain loop is the right shape); the two `let _ = holder;` sites were found by reading admit paths +- clean: no index loops, no replaceable derives, no statement-style accumulation that an iterator pipeline would improve; the three Vec::new accumulations carry real side effects and early exits + +## own +- d2b-core-controller-p2#2 sev=low blast=leaf effort=S verdict=actionable - OwnerIndex::plan clones the entire observed child map (`self.children.get(owner).cloned()`) though every later use is a read-only borrow, copying every ObservedChild (digest strings, dependency sets) per reconcile - fix: bind `let observed = self.children.get(owner).ok_or(OwnerReconcileError::OwnerNotRelisted)?;` and pass `&observed` to the existing `.get`, `for ... in &observed`, and `ordered_observed_refs` calls - [owner_reconcile.rs:1072-1075] + evidence: seed `\.clone\(\)` = 202 hits (authority.rs 126, owner_reconcile.rs 76); the other 201 are required ownership transfers (keys and proofs moved into index entries and leases, snapshots for durable handoff); this site is the only whole-map copy found by reading +- d2b-core-controller-p2#3 sev=low blast=leaf effort=S verdict=actionable - AuthorityReservation::reserve_durable clones the whole request into admit_authority_inner_with_operation and only afterwards builds the durable claim from the same request, when the claim can be computed first and the request moved - fix: compute `let claim = AuthorityStorageClaim::Generic(request.durable_claim());` before the lock block, then pass `request` by value into admit_authority_inner_with_operation, deleting the `.clone()` - [authority.rs:2803, authority.rs:2806] + evidence: seed `\.clone\(\)` = 202 hits; site read shows the clone at 2803 and the borrow-taking `durable_claim(&self)` at 2806, so the reorder is ownership-clean +- clean: no `to_owned`/`to_vec`/`to_string` beyond wire-rendering boundaries (15 hits, all `.to_owned()` on operation ids and digests at storage boundaries), no `Rc`/`RefCell`/`Arc` (0 hits), no `Cow` (0 hits); the Arc index sharing is the genuine multi-owner case (d2bd holds the same Arc, authority.rs:2636) + +## type +- d2b-core-controller-p2#4 sev=low blast=leaf effort=S verdict=actionable - AuthorityRequest::provider decides ProviderCardinality by string-comparing the rendered ref to "Provider/observability-otel", a stringly-typed special case whose why is not documented - fix: extract a named constant (e.g. `const OPTIONAL_PROVIDER_REF: &str = "Provider/observability-otel";`) beside the other domain constants and add a one-line doc noting the otel Provider is the one optional cardinality (D049 initial-Provider freeze), or move the decision into a `ProviderCardinality::for_provider(&ResourceRef)` helper - [authority.rs:985-988] + evidence: seeds ran: `fn validate_\w+|fn check_\w+` = 6 (all boundary admission validators called once from constructors, the parse-once shape the skill wants), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the otel string compare was found by reading the AuthorityRequest constructor family +- clean: no boolean-flag soup (deletion_requested/deletion_ready are fenced at construction, owner identity Options are set together and checked by validate_observed_owner), no stringly-typed state fields; validate_authority_combination is the single parse-once gate over class/scope/arbitration/cardinality combinations, which is the boundary shape the skill endorses + +## api +- d2b-core-controller-p2#5 sev=medium blast=leaf effort=M verdict=actionable - the parallel external physical-NIC machinery (TrustedExternalNicInventory, ExternalNicClaimRequest, ExternalNicLease, ExternalNicEffectGate, ExternalNicAdoption, ExternalNicCloseOutcome, ExternalNicReservation, the external_nics half of the index, and the EXTERNAL_PHYSICAL_NIC_* constants) has zero production callers; the prior audit row C2 names exactly this surface and is recorded not-applied with the site still matching - fix: delete the controller-side NIC request/lease/reservation/inventory types and the external_nics index half with their tests, keeping ExternalNicRecoveryInventory (consumed by d2bd-runtime's provenance fence) and the wire types in d2b-contracts-resource (consumed by d2bd and d2b-provider-network-local); cite record row C2 at docs/explanation/over-engineering-audit-record.md:473 - [authority.rs:80-128, authority.rs:167-211, authority.rs:258-335, authority.rs:1732, authority.rs:2645-2770] + evidence: census `ExternalNicClaimRequest|ExternalNicReservation|admit_before_effect|TrustedExternalNicInventory|ExternalNicLease|ExternalNicAdoption|ExternalNicEffectGate|ExternalNicCloseOutcome|durable_external_nic_claims|EXTERNAL_PHYSICAL_NIC` over packages/, nixos-modules/, tests/, labs/ = 0 hits outside authority.rs itself; the wire side (ExternalNicClaim, admit_external_nic_claims) has live callers at d2bd/src/resource_runtime.rs:10821-10850 and d2b-provider-network-local; C2 row confirmed still present +- d2b-core-controller-p2#6 sev=low blast=leaf effort=S verdict=actionable - public accessor aliases multiply paths to one item: OwnerReconcilePlan::create_order/batch, OwnerChildBatch::resource_refs, OwnerChildIdentity::resource_ref, TeardownPlan::order/refs/resources all duplicate a canonical accessor with zero external callers - fix: delete the zero-caller aliases and keep the canonical names (creation_order, deletion_order, create_batch, refs, target, order), retaining teardown_order which has live consumers - [owner_reconcile.rs:579, owner_reconcile.rs:600, owner_reconcile.rs:697, owner_reconcile.rs:754, owner_reconcile.rs:933-945] + evidence: census `create_order\(\)|teardown_order\(\)|\.batch\(\)|resource_refs\(\)|\.refs\(\)|\.resources\(\)` over packages/, nixos-modules/, tests/, labs/ = teardown_order 4 sites in 3 crates (d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:775, d2b-provider-audio-pipewire/tests/controller.rs:438, d2b-provider-device-security-key/tests/guest_frontend_process.rs:36, d2b-provider-device-usbip/tests/service_binding_lifecycle.rs:27) and refs 2 test sites; create_order, batch, resource_refs, resource_ref, order, resources = 0 external hits +- clean: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 1 hit, the `pub type AuthorityFuture` boxed-future alias (authority_persistence.rs:20-22) which is the required dyn-compatible shape for the object-safe AuthorityPersistence/AuthorityRecoveryProvenance traits; `pub use` = 0 (module paths are the house single-surface pattern via lib.rs `pub mod`); #[doc(hidden)] accessors and the feature-gated new_for_tests_ready are deliberate + +## err +- d2b-core-controller-p2#7 sev=low blast=leaf effort=S verdict=actionable - AuthorityError::DuplicateConflict renders the wire code "duplicateConflict", the only non-kebab-case code in the 25-variant enum, and nothing outside this crate matches the string - fix: change the code() arm to "duplicate-conflict" and update the two in-crate assertions that pin the old spelling (authority.rs:3409 and the code table test) - [authority.rs:412] + evidence: seed `\.unwrap\(\)|\.expect\(` = 160 hits, all inside #[cfg(test)] modules or doc examples (authority_persistence.rs:138 is a compile_fail doctest); `let _ = ` = 10 hits (authority.rs 8, authority_persistence.rs 2), every one a deliberate best-effort rollback or retryable-state recording on an error path already being returned; `panic!` = 1 hit, inside a test; census `duplicateConflict` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits outside authority.rs, and docs/reference/error-codes.md contains no authority code (grep for duplicateConflict|authority- = 0), so the spelling is not pinned +- clean: panic policy is clean outside tests (zero unwrap/expect in production code, zero panic macros); the error taxonomy is split by caller action (AuthorityError, OwnerReconcileError, OwnerGraphError, AuthorityPersistenceError, AuthorityReservationError) with Display equal to the stable code, so no caller string-matches a message; the `let _ =` rollback sites are the sanctioned best-effort-cleanup class + +## serde +- clean: seeds ran: derive = 10, serde attrs = 11, hand-written Deserialize = 0, serde_json = 2; durable rows use camelCase + deny_unknown_fields consistently (DurableAuthorityOwnerProof, DurableAuthorityClaim, DurableExternalNicClaim, AuthorityStorageClaim, AuthorityStorageOperation), enums use kebab-case, claim_digest canonicalizes through CanonicalJsonValue before hashing, and AuthorityOperationCapability proves non-deserializability with three compile_fail doctests (authority_persistence.rs:113-141); no hand-written admission-gate deserializers, no flatten, no untagged + +## obs +- N/A: seeds: 0/0/0/0 all zero; the crate has no tracing/log dependency (Cargo.toml lists only contracts, serde, serde_json, sha2, tokio), so there is no telemetry surface to judge + +## docs +- d2b-core-controller-p2#8 sev=medium blast=leaf effort=S verdict=actionable - the restart-recovery owner AuthorityRecoveryCoordinator and its data types expose eight pub items with no doc comment (PreparedAuthorityOperation::new, AuthorityRecoveryData::new, recover_with_provenance, index, is_ready_for_readiness, resolve_observed_and_adopted, resolve_observed_closed, quarantine), and this is the security-relevant path that decides whether recovered rows become readiness - fix: add one-line doc comments naming each method's contract, with `# Errors` on the Result-returning resolution methods (RowInvalid vs StateInvalid vs the persistence error) - [authority_persistence.rs:50, authority_persistence.rs:92, authority_persistence.rs:247, authority_persistence.rs:260, authority_persistence.rs:264, authority_persistence.rs:268, authority_persistence.rs:282, authority_persistence.rs:314] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 255 hits (authority.rs 112, owner_reconcile.rs 122, authority_persistence.rs 15, migration.rs 6); reading authority_persistence.rs found the eight bare pub fns while every sibling item carries a one-liner +- d2b-core-controller-p2#9 sev=low blast=leaf effort=S verdict=actionable - migration.rs exposes `requires_migration` and `validates_binding` without doc comments while every other pub item in the file documents its contract - fix: add one-line docs (e.g. "Whether this decision requires the broker migration path" and "Whether the supplied vm/intent bindings match the sealed decision") - [migration.rs:54, migration.rs:58] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 255 hits; reading migration.rs (124 lines) found exactly these two bare pub fns +- d2b-core-controller-p2#10 sev=low blast=leaf effort=M verdict=actionable - no Result-returning pub item carries an `# Errors` section (zero canonical sections in the lane), so failure conditions must be inferred from the code, most notably on the admission and reservation API (admit_authority, admit_before_effect, reserve, close_then_release) - fix: add `# Errors` sections naming the AuthorityError variants to the representative public admission/reservation fns (HostGlobalAuthorityIndex::admit_authority at authority.rs:2160, AuthorityReservation::reserve/close_then_release at authority.rs:2773/2855, ExternalNicReservation::close_then_release at authority.rs:2745) and adopt the section as the house shape for new Result fns - [authority.rs:2160, authority.rs:2773, authority.rs:2745] + evidence: seed `-> Result<` = 101 hits (authority.rs 57, owner_reconcile.rs 36, authority_persistence.rs 8, migration.rs 0); seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits across the lane + +## perf +- clean: seeds ran: format! = 12 (authority.rs 2, owner_reconcile.rs 8, migration.rs 2), collection-new = 23, to_string = 0; every format! hit sits inside a #[cfg(test)] module, and the four non-test Vec::new sites (owner_reconcile.rs:1077-1078, 1256, 1723) are the empty-case or side-effectful-accumulation shapes the card exempts; framed_digest already sizes its buffer with with_capacity (authority.rs:938-946); no hot-path allocation or attacker-keyed hashing found (static reading, unmeasured) + +## conc +- clean: seeds ran: threads = 0, Mutex/RwLock = 8 (all tokio::sync::Mutex in async contexts), atomics = 15, thread_local/unsafe impl = 0; the AtomicU64 orderings are correct for their use (Relaxed for the monotonic nonce counters, AcqRel fetch_add plus Acquire load for the paired runtime-epoch handoff at authority.rs:1789-1791 and 1964), std Mutex appears only in the cfg(test) RecordingPersistence helper with the sanctioned per-site allows, and no manual Send/Sync claims exist + +## async +- clean: seeds ran: async fn/await = 70, spawn/JoinSet/select = 0, tokio::sync = 11, tokio::main/test/block_on = 6 (all #[tokio::test]); no guard is held across an await (every lock().await completes within its statement or block, e.g. the reserve_durable lease block at authority.rs:2665-2672 and the coordinator's take-then-await sequence at authority_persistence.rs:286-292), no blocking calls appear inside async fns, and cancellation is covered by the durable operation rows plus the #[must_use] reservation contract (authority.rs:2634-2635), so a dropped reservation cannot silently release an unobserved effect + +## unsafe +- N/A: seeds: 0/0/0 all zero (no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed); the crate inherits the workspace `unsafe_code = "forbid"` via `[lints] workspace = true`, and no local unsafe_code attribute exists + +## ffi +- N/A: seeds: 0/0/0/0 all zero (no extern "C", no catch_unwind, no repr(C)/repr(transparent), no CStr/CString/c_char) in the lane scope + +## macro +- N/A: seeds: 0/0/0/0 all zero (no macro_rules!, no proc_macro/syn/quote, no $crate, no to_compile_error/new_spanned) in the lane scope + +## test +- d2b-core-controller-p2#11 sev=medium blast=leaf effort=M verdict=actionable - the restart-recovery receipt path (validate_recovery_operations, recovery_receipt_from_operations_with_prepared_capabilities, rehydrate) has no test anywhere: claim-digest verification, prepared-capability matching, and quarantine-on-mismatch are contract behavior with zero coverage - fix: add tests that build AuthorityStorageOperation rows with a tampered claim_digest, a prepared-capability set that misses an active operation, and a duplicate operation_id, asserting each returns InvalidAuthorityRequest, plus a rehydrate round-trip that admits after rehydration - [authority.rs:1824, authority.rs:1968, authority.rs:1899] + evidence: seed `#[test]|#[tokio::test]` = 36 hits (authority.rs 19, owner_reconcile.rs 14, migration.rs 3) and asserts = 102; census `rehydrate|recovery_receipt_from|validate_recovery_operations` over packages/ = definitions and production calls only (d2bd-runtime/src/authority_persistence.rs:399-462 exercises the ledger's own prepare/recover, not the controller's receipt validation), zero test call sites +- d2b-core-controller-p2#12 sev=medium blast=leaf effort=M verdict=actionable - AuthorityRecoveryCoordinator has no tests and its resolution methods have no callers at all, so the capability-restore-and-quarantine rollback on a failed record_close/release (authority_persistence.rs:292-311) is untested contract behavior that only a future driver will reach - fix: add coordinator tests with a failing persistence double asserting the capability is restored and the operation quarantined after record_close or release failure, and that resolve_observed_and_adopted clears the unresolved set - [authority_persistence.rs:246-320] + evidence: seed `#[test]|#[tokio::test]` = 36 hits, zero in authority_persistence.rs; census `recover_with_provenance|resolve_observed_closed|resolve_observed_and_adopted` over packages/, tests/, labs/ = 1 production call (d2bd/src/resource_runtime.rs:3149, recover_with_provenance only); the resolution methods appear nowhere else +- clean: the 36 tests that exist assert error variants and redaction contracts rather than Display strings (e.g. cross_zone_bridge_rejection_is_distinct_and_runs_no_effect asserts the exact AuthorityError and that zero effects ran), the integration suite tests/owned_children.rs covers the committed and uncertain batch-recovery paths with human-written expectations, and no #[ignore] or property-tooling gaps were found + +## Coverage +- idiom: 1 finding +- own: 2 findings +- type: 1 finding +- api: 2 findings +- err: 1 finding +- serde: clean (seeds ran: 10/11/0/2) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 3 findings +- perf: clean (seeds ran: 12/23/0; all format! hits inside test modules) +- conc: clean (seeds ran: 0/8/15/0) +- async: clean (seeds ran: 70/0/11/6) +- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe sites; workspace unsafe_code = "forbid" inherited) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 2 findings \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md new file mode 100644 index 000000000..f1432acfb --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md @@ -0,0 +1,96 @@ +# d2b-core-p1 - d2b-core - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8734 (excl. src/generated/**) | modules: bundle_resolver +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/bundle_resolver.rs (whole file) + +## idiom +- d2b-core-p1#1 sev=low blast=leaf effort=S verdict=actionable - resolve_network_projection_intent and resolve_network_sysctl_intent fetch the Network spec only to discard it via `let _ = spec;`, a workaround for the unused binding - fix: replace `let spec = self.find_network_spec(&parts)?; ... let _ = spec;` with the statement `self.find_network_spec(&parts)?;` (the `?` on Option keeps the admission check and drops the value) - [packages/d2b-core/src/bundle_resolver.rs:1805, packages/d2b-core/src/bundle_resolver.rs:1911] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 11 hits; `let _ = ` = 17 hits; the two discarded-spec sites read in full; the intent body never consults `spec` +- d2b-core-p1#2 sev=low blast=leaf effort=S verdict=actionable - `_ASSERT_TAPROLE` is a `#[allow(dead_code)]` const that exists only to silence an unused-import warning for `TapRole`, which the module does not actually name - fix: drop the `use crate::host::TapRole` import (the comment says `BridgePortFlags` uses the type internally) or import it as `use crate::host::TapRole as _;`, and delete the const - [packages/d2b-core/src/bundle_resolver.rs:5746] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 11 hits; the const and its explanatory comment read at 5743-5747; `TapRole` appears nowhere else in the file outside the import and the const +- d2b-core-p1#3 sev=low blast=leaf effort=S verdict=actionable - resolve_disk_init_ops nests two `for` loops over a single-arm `match` on `SpawnRunnerPlanOp`, which is a one-variant enum, so the match is a no-op wrapper around construction - fix: flatten to `vm.nodes.iter().flat_map(|n| &n.plan_ops).filter_map(|op| match op { SpawnRunnerPlanOp::DiskInit { .. } => Some(ResolvedDiskInitOp { .. }), })` or at least an `if let` for the single variant - [packages/d2b-core/src/bundle_resolver.rs:2434, packages/d2b-core/src/processes.rs:180] + evidence: seed `for \w+ in 0\.\.` = 0 hits, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0 hits, `let mut \w+ = (String|Vec)::new\(\)` = 11 hits; `SpawnRunnerPlanOp` enum read at processes.rs:180-211 has exactly one variant `DiskInit` + +## own +- d2b-core-p1#4 sev=low blast=leaf effort=S verdict=actionable - `ResourceUid::parse(value.clone())` plus `parts.network_uid.clone()` in find_network_spec and build_resource_network_intents, and `ZoneId::parse(zone.clone())` in zone_resource_bundle_zones, clone to feed parse/compare where `&str` suffices - fix: `ResourceUid::parse(value.as_str())` and compare `parse(...).ok().as_ref().map(ResourceUid::as_str) == Some(parts.network_uid.as_str())`; `ZoneId::parse(zone.as_str())`; the parse signatures are `impl Into` so `&str` converts without allocation - [packages/d2b-core/src/bundle_resolver.rs:1973, packages/d2b-core/src/bundle_resolver.rs:3354, packages/d2b-core/src/bundle_resolver.rs:1629] + evidence: seed `\.clone\(\)` = 116 hits, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 306 hits, `Rc<|RefCell<|Arc`) +- clean: the remaining clone/to_owned mass is intent-table construction from borrowed bundle data (owned struct fields), `Arc` clones at spawn boundaries are absent, and test-support injection clones are cfg-gated; no Rc/RefCell/Arc/Cow anywhere in the file + +## type +- clean: seeds `fn validate_\w+|fn check_\w+` = 0, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 1; the single hit (line 1194 `mode: String::new()`) is the deliberate fail-closed empty host model in `empty_zone_native_host` whose empty strings are the documented fail-closed contract, not a flag soup; boolean intent fields (`owned`, `stp_disabled`, `dynamic_bus_id`, `accepts_launch_args`) are constant at construction here but read or re-constructed by the broker/provider consumers, so they carry the closed policy rather than dead flexibility + +## api +- d2b-core-p1#5 sev=medium blast=leaf effort=S verdict=actionable - nine exported resolved-intent types have zero consumers anywhere in the workspace: ResolvedInstallerIntent, ResolvedMigrateIntent, ResolvedActivationIntent, ResolvedGcIntent, ResolvedKeysRotateIntent, ResolvedHostKeyTrustIntent, ResolvedRotateKnownHostIntent, ResolvedLegacySwtpmIntent, InstallerArtifact - fix: delete them, or wire them to the broker dispatch arms the module doc says are still `Unimplemented`; if kept for planned arms, mark them `#[doc(hidden)]` or gate them behind a feature - [packages/d2b-core/src/bundle_resolver.rs:620, packages/d2b-core/src/bundle_resolver.rs:641, packages/d2b-core/src/bundle_resolver.rs:656, packages/d2b-core/src/bundle_resolver.rs:698, packages/d2b-core/src/bundle_resolver.rs:705, packages/d2b-core/src/bundle_resolver.rs:713, packages/d2b-core/src/bundle_resolver.rs:723, packages/d2b-core/src/bundle_resolver.rs:778, packages/d2b-core/src/bundle_resolver.rs:633] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 158 hits; census: each of the nine names over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file hit (the definition in bundle_resolver.rs), zero construction or consumption sites +- d2b-core-p1#6 sev=medium blast=wide effort=M verdict=actionable - `BundleResolver` exposes seven `pub` fields (bundle, host, processes, storage, site, realm_workloads_launcher_v2, manifest) on the security-boundary type whose tables are derived from verified artifacts; the broker mutates `resolver.storage` directly, so the trusted model is writable by any consumer and derived state can drift from it - fix: make the fields private, add read accessors (`host()`, `manifest()`, `processes()`, `bundle()`, ...) and a single `set_storage(StorageJson)` setter, then migrate the ~30 read sites in d2bd, d2bd-runtime, and d2b-broker - [packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109, packages/d2b-core/src/bundle_resolver.rs:110, packages/d2b-broker/src/ops/storage_contract.rs:589, packages/d2b-broker/src/ops/state_dir.rs:440] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 158 hits; census: `resolver\.(bundle|host|processes|manifest|site|storage)` over packages/d2bd, packages/d2b-broker, packages/d2bd-runtime = 30+ read sites and 2 write sites (storage_contract.rs:589, state_dir.rs:440) +- d2b-core-p1#7 sev=low blast=leaf effort=S verdict=actionable - three `pub` methods have no out-of-crate callers and are only used inside this module and its tests: resolve_vm_start_intent, find_process_node, find_if_name_mapping_for_vm - fix: narrow to `pub(crate)` - [packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:2417, packages/d2b-core/src/bundle_resolver.rs:2506] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 158 hits; census: each method name over packages/ and tests/ = 1 file hit (bundle_resolver.rs itself, including its test module) + +## err +- d2b-core-p1#8 sev=medium blast=leaf effort=M verdict=actionable - resolve_macvtap_intents returns `Result, String>`, a String error in a library API whose two failure modes (missing process node, missing macvtap metadata) are indistinguishable to the caller; the broker wraps it wholesale into BrokerError::LiveHandler - fix: return `crate::error::Error` via `Error::manifest_parse_error` or a small enum with the two variants, and update the single broker call site - [packages/d2b-core/src/bundle_resolver.rs:2625, packages/d2b-broker/src/runtime.rs:6405] + evidence: seed `enum \w*Error` = 0 hits, `\.unwrap\(\)|\.expect\(` = 210 hits; the signature and both `ok_or_else(|| format!(...))` arms read at 2625-2648; broker call site read at runtime.rs:6405-6406 +- d2b-core-p1#9 sev=medium blast=leaf effort=M verdict=actionable - Network spec parse failures inside the trusted-bundle network path are silently dropped: `let Ok(spec) = serde_json::from_value::(spec_value) else { continue; };` in build_resource_network_intents and `serde_json::from_value(value).ok()` in find_network_spec, so a producer-side spec drift silently vanishes every intent for that network and surfaces only as an opaque "intent not found" at apply time - fix: plumb a `Result` out of build_resource_network_intents and find_network_spec and return `Error::manifest_parse_error("resource-bundle.json", reason)` on parse failure so the drift is diagnosable - [packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:1982] + evidence: seed `\.ok\(\);` = 1 hit, `let _ = ` = 17 hits; both sites read in full at 3355-3370 and 1959-1983; the bundle is hash-verified at load, so a parse failure is producer/consumer contract drift, not adversarial input +- d2b-core-p1#10 sev=low blast=leaf effort=M verdict=actionable - from_artifacts_with_zone_resource_bundles panics on caller-supplied input via two expects (`bundle serialization for audit hashing must succeed`, `zone resource bundle bytes must be verified`) in a `pub` API whose doc comment states the precondition but cannot enforce it; the fuzz target is one caller that passes arbitrary bytes - fix: return `Result` (map both to `Error::internal_io` / `Error::manifest_parse_error`) or downgrade to `debug_assert!` plus a doc note - [packages/d2b-core/src/bundle_resolver.rs:1405, packages/d2b-core/src/bundle_resolver.rs:1412, packages/d2b-core/fuzz/src/bin/core.rs:1] + evidence: seed `\.unwrap\(\)|\.expect\(` = 210 hits, of which 207 are inside `#[cfg(test)] mod tests` (lines 5724-8734) and 3 in library code (1405, 1412, 4469); the 4469 expect (`SHA-256 always has four-byte prefixes`) is a compiler-invisible invariant and is not flagged; sampled: 50 of 228 hits +- d2b-core-p1#11 sev=low blast=leaf effort=S verdict=actionable - manifest_parse_reason classifies serde failures by substring-matching the Display text (`"missing field"`, `"unknown field"`, `"invalid type"`), which is not a stable API and silently degrades to `"parse-failed"` on any message rewording - fix: match on `serde_json::Error::classify()` (ErrorClass::Syntax / Data / Eof) instead of the message text - [packages/d2b-core/src/bundle_resolver.rs:5730] + evidence: seed `enum \w*Error` = 0 hits; the function and its 9 call sites read at 5729-5740; the produced slug feeds the opaque reason of the wire code `manifest-parse-error` (docs/reference/error-codes.md:51), so the classification change is not wire-visible + +## serde +- d2b-core-p1#12 sev=low blast=leaf effort=S verdict=needs-contract - ZoneNativeIndexDocument derives Deserialize with `rename_all = "camelCase"` but no `deny_unknown_fields`, while the three sibling index types (ZoneNativeBundleIndex, ZoneNativeBundleRef, ZoneNativeTopology) all deny, leaving the top-level index admission inconsistent - fix: add `deny_unknown_fields` to ZoneNativeIndexDocument and keep the Nix emitter (nixos-modules/bundle.nix) in sync so no emitted key is rejected - [packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175, packages/d2b-core/src/bundle_resolver.rs:202, packages/d2b-core/src/bundle_resolver.rs:216] + evidence: seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 12 hits; the four index types read at 174-220; index.json is a bundle wire artifact emitted by nixos-modules/bundle.nix, hence needs-contract +- d2b-core-p1#13 sev=low blast=leaf effort=S verdict=actionable - `#[serde(default)]` on the four Option fields of ZoneNativeBundleIndex (storage_path, site_path, host_path, realm_workloads_launcher_v2_path) is redundant: a missing Option field already deserializes to None, so the attribute adds nothing and reads as a convention violation of the sibling fields - fix: drop the four attributes - [packages/d2b-core/src/bundle_resolver.rs:183, packages/d2b-core/src/bundle_resolver.rs:187, packages/d2b-core/src/bundle_resolver.rs:194, packages/d2b-core/src/bundle_resolver.rs:196] + evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 6 hits, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 12 hits, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 50; the round-trip test at 8718-8731 pins the optional-field behavior the attribute claims + +## obs +- d2b-core-p1#14 sev=medium blast=leaf effort=S verdict=actionable - verify_bundle_hash emits a backward-compatibility warning via `eprintln!` in library code, and d2b-core has no tracing/log channel at all, so the "bundleHash missing, skipping self-hash check" warning never reaches the daemon's structured logs and operators cannot see that hash verification was skipped - fix: add `tracing` (already the workspace-wide logging dependency in sibling crates) and emit `tracing::warn!(path = %path.display(), "bundle artifact has no bundleHash field; skipping self-hash check")`, or route the warning through the crate's audit/error path - [packages/d2b-core/src/bundle_resolver.rs:1097] + evidence: seed `\bprintln!\(|\beprintln!\(` = 1 hit, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0; d2b-core Cargo.toml carries no tracing dependency; the site is a library warn-and-continue path for pre-v2 bundles, not CLI product output + +## docs +- d2b-core-p1#15 sev=medium blast=leaf effort=S verdict=actionable - 15 of the 23 public `intent_id_*` constructors carry no doc comment (intent_id_store_view, intent_id_vm_start, intent_id_nft_host, intent_id_nft_env, intent_id_nft_projection_env, intent_id_ownership_marker_env, intent_id_bridge_env, intent_id_route_env, intent_id_sysctl, intent_id_hosts_host, intent_id_nm_unmanaged_host, intent_id_usbip_firewall, intent_id_usbip_bind, intent_id_runner, intent_id_legacy_runner), even though these format strings are the deterministic BundleOpId wire contract the module doc describes and integrators build by hand - fix: give each a one-line doc naming the exact `BundleOpId` shape it produces (the module table is the source) - [packages/d2b-core/src/bundle_resolver.rs:2917, packages/d2b-core/src/bundle_resolver.rs:2935, packages/d2b-core/src/bundle_resolver.rs:3118, packages/d2b-core/src/bundle_resolver.rs:3217, packages/d2b-core/src/bundle_resolver.rs:3130] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 23; the 23 intent-id functions enumerated at 2917-3223, 8 of them documented (the network_*_uids family and network_name_token) +- d2b-core-p1#16 sev=low blast=leaf effort=M verdict=actionable - a batch of public resolver items is undocumented (find_nft_intent and sibling find_* getters, resolve_vm_start_intent, resolve_vm_start_prerequisites, resolve_macvtap_intents, resolve_prepare_dir_intent, resolve_kernel_module_intent, resolve_role_device_claim, find_process_vm, find_process_node, find_host_env, find_if_name_mapping_for_vm, audit_bundle_version, audit_bundle_hash, the *_intent_ids iterators), and none of the 23 `-> Result<` items carries an `# Errors` section - fix: one-line docs on the batch and an `# Errors` paragraph on the Result-returning items (load_with_policy, render_json, resolve_macvtap_intents, zone_resource_bundle_zones) - [packages/d2b-core/src/bundle_resolver.rs:1663, packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:2621, packages/d2b-core/src/bundle_resolver.rs:1659, packages/d2b-core/src/bundle_resolver.rs:2816] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 23; the undocumented items were enumerated from the pub-surface listing at 1583-2843 + +## perf +- d2b-core-p1#17 sev=medium blast=leaf effort=S verdict=actionable - has_zone_uid re-parses every zone resource bundle on each call and zone_uid / find_network_spec re-parse bundle JSON per lookup (ResourceBundle::from_json over raw bytes), while parsed_zone_resources (populated once at load, line 1462) already holds the parsed ResourceBundle per zone - fix: have has_zone_uid, zone_uid, and find_network_spec iterate or index parsed_zone_resources instead of re-parsing bytes - [packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:1647, packages/d2b-core/src/bundle_resolver.rs:1959] + evidence: static (unmeasured); seed `format!\(` = 141 hits, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 197, `\.to_string\(\)` = 11; sampled: 50 of 349 hits; callers of has_zone_uid: d2bd/src/provider_effects.rs and d2b-broker/src/ops/tap.rs; find_network_spec runs on every resolve_network_*_intent call +- d2b-core-p1#18 sev=low blast=leaf effort=S verdict=actionable - the nft/hosts renderers build text with `buf.push_str(&format!(...))`, allocating a fresh String per line then copying it into the buffer (render_host_nft_script, render_env_nft_subset, render_hosts_managed_block), and sha256_hex collects 32 per-byte `format!("{b:02x}")` Strings - fix: `write!(&mut buf, ...)` into the existing buffer (std::fmt::Write) and hex-encode into a fixed `[u8; 64]` buffer or a single format call - [packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:3793, packages/d2b-core/src/bundle_resolver.rs:3986, packages/d2b-core/src/bundle_resolver.rs:1009] + evidence: static (unmeasured); seed `format!\(` = 141 hits; the render loops at 3717-3777, 3793-3802, and 3986-3989 each push_str a fresh format! result; these are cold bundle-load paths, hence low +- d2b-core-p1#19 sev=low blast=leaf effort=M verdict=actionable - six composite-key lookups allocate two Strings per call (`(zone.to_owned(), guest.to_owned())`) against BTreeMap<(String, String), _> maps (guest_setup_descriptors, guest_setup_descriptor_catalog_keys, guest_vmm_intents, guest_vmm_zone_uids) - fix: introduce a `ZoneGuestKey(String, String)` newtype with a `Borrow<(str, str)>` impl so lookups borrow without allocating, or nest the maps per zone - [packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:1617, packages/d2b-core/src/bundle_resolver.rs:2068, packages/d2b-core/src/bundle_resolver.rs:2087, packages/d2b-core/src/bundle_resolver.rs:5141, packages/d2b-core/src/bundle_resolver.rs:5355] + evidence: static (unmeasured); seed `\.to_string\(\)` = 11 hits and `\.to_owned\(\)` = 306 hits; the six lookup sites enumerated from the own-seed output; each is a read-only lookup in resolver hot paths (guest VMM intent resolution per request) + +## conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; bundle_resolver.rs declares no threads, locks, atomics, or manual Send/Sync (the crate's concurrency lives in loader_worker.rs, part 2's scope) + +## async +- clean: seeds `async fn|async move|\.await` = 4 hits, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the only async surface is load_on_loader_worker and load_with_policy_on_loader_worker, which delegate the blocking bundle read to `crate::loader_worker::run` - the dedicated bounded worker named in clippy.toml's replacement vocabulary (policy-confirmed good), with no guards held across await and no spawn/select sites + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 1, `unsafe_code` = 0; the single hit is `FileType::from_raw_mode` at line 977, a rustix API name, not an unsafe block; the workspace forbids unsafe_code and the file contains no unsafe + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the file crosses no FFI boundary + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros are defined or expanded in this file (only std macros like format! and vec!) + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 44 hits, `assert_eq!\(|assert_ne!\(|assert!\(` = 208 hits, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; sampled: 50 of 252 hits; the in-module suite (lines 5724-8734) is fixture-driven with failure-path coverage (tamper refusal, malformed CIDR refusal, fail-closed empty-host model, cross-crate serving-worker agreement pinned by a case table), asserts behavior rather than Display strings, and uses no ignored or network-dependent tests + +## Coverage +- idiom: 3 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 0/0/1; the single hit is the deliberate fail-closed empty host model) +- api: 3 finding(s) +- err: 4 finding(s) +- serde: 2 finding(s) +- obs: 1 finding(s) +- docs: 2 finding(s) +- perf: 3 finding(s) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics in bundle_resolver.rs) +- async: clean (seeds ran: 4/0/0/0; the two async fns delegate to the loader_worker bounded worker) +- unsafe: N/A (seeds: 0/0/1/0; the lone hit is the rustix from_raw_mode API name, not an unsafe block) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) +- test: clean (seeds ran: 44/208/0/0; fixture-driven behavior suite with failure-path coverage) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md new file mode 100644 index 000000000..ad891b6aa --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md @@ -0,0 +1,91 @@ +# d2b-core-p2 - d2b-core - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6471 (excl. src/generated/**) | modules: privileges, host, manifest_v04, storage, test_support, console_ring, allocator_config, processes, storage_lifecycle, provider_artifact, host_w3, static_invariants, sync, runtime, base64_codec, sandbox_profile, kernel_seat, loader_worker, site, provider_capabilities, bundle, host_generation, closures, lib, unsafe_local_workloads, configured_argv, contract_id, error, privileges_w3, workload_identity +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: every src/*.rs except bundle_resolver.rs (part 1) and src/generated/**; tests/** added for the test lens + +## idiom +- d2b-core-p2#1 sev=low blast=leaf effort=S verdict=actionable - allowlist membership checks in static_invariants.rs use `iter().any(|f| f == last)` linear scans where slice `contains` reads cleaner - fix: replace `PUBLIC_MANIFEST_FIELDS.iter().any(|f| f == last)` with `PUBLIC_MANIFEST_FIELDS.contains(&last.as_str())` and `BROAD_CAPABILITIES.iter().any(|broad| broad == cap)` with `BROAD_CAPABILITIES.contains(&cap.as_str())` - [packages/d2b-core/src/static_invariants.rs:162, packages/d2b-core/src/static_invariants.rs:219] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits (all justified: VmGracefulShutdown Default preserves enable=true, builder Defaults delegate to new()); seed `for \w+ in 0\.\.` = 2 hits (kernel_seat round-robin and worker-start loops, justified); seed `let mut \w+ = (String|Vec)::new\(\)` = 3 hits (static_invariants accumulation, inherent to the recursive walker); the two `any` scans above are the remaining polish. +- clean: seeds 2/3/3 hits; the two index loops are deliberate fixed-count round-robins, the three hand-written Default impls preserve invariants a derive would break, and the Vec::new accumulation feeds a recursive walker; only the two `contains`-shaped scans are findings. + +## own +- d2b-core-p2#2 sev=low blast=leaf effort=S verdict=actionable - `path_bearing_key_violations` clones a borrowed `String` (`Value::String(s) => s.clone()`) only to run `.contains('/')` on it - fix: render through `Cow<'_, str>` (`Cow::Borrowed(s.as_str())` for the string arm, `Cow::Owned(other.to_string())` otherwise) so the common string case copies nothing - [packages/d2b-core/src/static_invariants.rs:201] + evidence: seed `\.clone\(\)` = 6 hits; of these only static_invariants.rs:201 copies a borrowed value needlessly (privileges.rs:722-726 clones non-Copy enums in a From conversion, static_invariants.rs:137/150 clone into a reused prefix buffer, storage.rs:432 is a test fixture); seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = ~45 hits, all test fixtures, wire-rendering boundaries, or thread-name construction; seeds `Rc<|RefCell<|Arc anywhere in the part; every to_owned/to_string site is a fixture, a rendering boundary, or a required owned argument. + +## type +- d2b-core-p2#3 sev=medium blast=leaf effort=S verdict=actionable - `ManifestShellName(pub String)` exposes its inner String publicly, so the shell-name shape invariant enforced in the hand-written `Deserialize` (and in `shell_name_valid`) can be bypassed by literal construction - fix: make the field private and add an `as_str()` accessor, mirroring the `AllocatorRealmPath` newtype pattern in allocator_config.rs; serde(transparent) keeps the wire shape unchanged - [packages/d2b-core/src/manifest_v04.rs:313] + evidence: seed `fn validate_\w+|fn check_\w+` = 4 hits; the allocator_config validate_* fns feed private-field parse-once newtypes (the correct pattern), while storage.rs:357 and sync.rs:136 are cross-field uniqueness checks a type cannot carry; seed `is_\w+: bool|\w+_flag: bool` = 3 hits (schema-mirroring fields, pinned wire shapes); seed `(mode|kind|state): String` = 3 hits (pinned wire fields); census: `ManifestShellName` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 3 hits, all in manifest_v04.rs plus the generated schema doc, so no external literal construction exists to break. +- clean: the only representable-illegal-state gap is the public tuple field on ManifestShellName; the boolean and String fields that the seeds hit are schema-mirroring wire fields pinned by docs/reference/manifest-schema.md and the schemars output. + +## api +- d2b-core-p2#4 sev=medium blast=wide effort=M verdict=actionable - six one-line compat shim modules (`error`, `contract_id`, `configured_argv`, `privileges_w3`, `workload_identity`, `unsafe_local_workloads`) re-export d2b_contracts items, making every re-exported item public at two paths (`d2b_contracts::error::Error` and `d2b_core::error::Error`); this is the recorded A4 not-applied row - fix: delete the six shim modules and re-point the ~25 import sites at `d2b_contracts::*` (and `d2b_contracts_resource::v3::ZoneResourceIdentity`); the `UnsafeLocalWorkloadIdentity` alias has zero consumers and goes with its module; the xtask gen-error-codes generator and docs/reference/error-codes.md anchors that read `d2b_core::error` must switch to `d2b_contracts::error` - [packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-core/src/configured_argv.rs:1, packages/d2b-core/src/privileges_w3.rs:1, packages/d2b-core/src/workload_identity.rs:1, packages/d2b-core/src/unsafe_local_workloads.rs:1] + evidence: row A4 of docs/explanation/over-engineering-audit-record.md:457 records the six shims as not applied and the sites still match at HEAD; census: `d2b_core::(error|contract_id|configured_argv|privileges_w3|workload_identity|unsafe_local_workloads)::` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = ~25 hits in d2b-broker (runtime.rs:1278, ops/state_dir.rs:327, ops/storage_contract.rs:347), d2b (lib.rs:9), d2bd (composition.rs:77, 9503, 14122, 7840), d2bd-runtime (unsafe_local_helper.rs:1133, workload_dispatch.rs:923), labs/window-chrome/proxy (6 files), d2b-core tests, and the error-codes generator docs; `privileges_w3` has zero consumers. +- d2b-core-p2#5 sev=medium blast=wide effort=M verdict=actionable - `pub mod static_invariants` exports four security validators (world-readable-leak, path-bearing-key, broad-caps, writable-paths) with zero callers in the tree, and the bash gates the module doc says it replaced are gone, so the invariants are enforced nowhere; the module doc's claim that the original positive/negative cases were "preserved as unit tests" is false - fix: wire the validators into the contract-test lane (e.g. the d2b-contract-tests static-invariants structure ADR-046-zone-control cites) or the broker's manifest load path, or delete the module with its stale claim - [packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:158, packages/d2b-core/src/static_invariants.rs:189, packages/d2b-core/src/static_invariants.rs:216, packages/d2b-core/src/static_invariants.rs:230] + evidence: census: `world_readable_field_leaks|path_bearing_key_violations|is_broad_cap_violation|undeclared_writable_paths` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 4 hits, all the definitions themselves; glob `tests/static-invariant*` = no files (the bash gates are gone); the module is policy-known only via xtask SharedFamilyKnowledgeExemption rows (packages/xtask/src/provider_crate_policy.rs:3637-3641, 3661-3665, 4015-4019), which are token ratchets, not callers. +- d2b-core-p2#6 sev=low blast=leaf effort=S verdict=actionable - `PrivilegesJson::w1` is a pub constructor with zero production callers and an opaque name ("w1") unexplained by its doc comment - fix: rename to a descriptive constructor such as `from_const_rows()` or gate it behind cfg(test) - [packages/d2b-core/src/privileges.rs:741] + evidence: census: `PrivilegesJson::w1|::w1\(` over packages/, nixos-modules/, tests/, labs/ = 2 hits, both tests (privileges.rs:762 and packages/d2b-core/fuzz/src/bin/core.rs:160); seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 hits; seed `^\s*pub use ` = 8 hits, of which the six A4 shims are finding #4 and the runtime.rs re-export of eight d2b_contracts names is the applied-A3 house pattern (docs/explanation/over-engineering-audit-record.md:456). +- clean: no Arc/Rc/Box/RefCell in any public signature; the re-export surface is the six A4 shims (finding #4) plus the sanctioned runtime.rs arms; the remaining pub surface is wire DTOs whose width is the contract. + +## err +- d2b-core-p2#7 sev=medium blast=family effort=M verdict=actionable - `StorageJson::validate_unique_ids` and `SyncJson::validate_lock_order` return `Result<(), String>` with format!-built messages, and storage_lifecycle.rs re-derives the failure reason and offending id by string-prefix matching (`classify_storage_validation_reason`, `classify_sync_validation_reason`, `*_offending_id`, `bounded_contract_detail`), an error taxonomy that forces string-matching; the whole chain has no production caller - fix: return a typed validation error from both validators whose variants are the existing wire enums (`StorageContractValidationReason`, `SyncContractValidationReason`) with the offending id as payload, and delete the classifier functions - [packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core/src/storage_lifecycle.rs:116, packages/d2b-core/src/storage_lifecycle.rs:140] + evidence: seed `enum \w*Error` = 3 hits (LayoutError, LaunchError, HostGenerationError, all closed token enums with Display and Error impls, fine); census: `validate_lock_order|validate_unique_ids|classify_sync_validation_reason|classify_storage_validation_reason` over packages/, nixos-modules/, tests/, labs/ = only in-crate definitions, in-crate tests, and a d2b-provider-volume-local import (packages/d2b-provider-volume-local/src/diagnostics/storage_lifecycle.rs:18) used solely by its test at 348-362; the String messages never cross the wire (the report persists the enum), so the change is not needs-contract. +- d2b-core-p2#8 sev=low blast=leaf effort=S verdict=actionable - `SiteJson::validate` returns `Result<(), &'static str>` with a bare token ("invalid-wayland-socket") that callers must string-match - fix: return a small unit error enum (e.g. `SiteValidationError::InvalidWaylandSocket`) with the token as its Display - [packages/d2b-core/src/site.rs:42] + evidence: seed `\.unwrap\(\)|\.expect\(` = 66 hits, every one inside #[cfg(test)] modules (verified per file); seed `let _ = |\.ok\(\);` = 2 hits, both `let _ = reply.send(job());` best-effort oneshot sends on a dead worker (kernel_seat.rs:160, loader_worker.rs:130), deliberate; seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0 hits; the only taxonomy smell is the string-token error above. +- clean: panic policy is clean (no unwrap/expect in production code, no panic macros); the two `let _ =` sites are documented best-effort sends; error enums are small and closed; the two findings above are the taxonomy shape. + +## serde +- d2b-core-p2#9 sev=low blast=leaf effort=S verdict=actionable - `StorageLifecycleIssue` struct variants carry per-field `#[serde(rename = "bundleVersion")]`-style renames instead of the house `#[serde(rename_all = "camelCase")]` per variant, scattering the wire convention across fields - fix: add `#[serde(rename_all = "camelCase")]` to each struct variant and drop the per-field rename attributes; the serialized shape is unchanged (pinned by the storage_lifecycle tests) - [packages/d2b-core/src/storage_lifecycle.rs:49, packages/d2b-core/src/storage_lifecycle.rs:61, packages/d2b-core/src/storage_lifecycle.rs:70] + evidence: seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = ~60 hits; seed `derive\([^)]*(De)?[Ss]erialize` = ~90 hits; seed `impl .*Deserialize.*for` = 2 hits (ManifestV04 and ManifestShellName, both live admission gates with per-key validation a derive cannot express, and the allocator_string! macro generates the third via expansion); seed `serde_json::from_|serde_json::to_` = ~25 hits, mostly tests plus ManifestV04::from_slice; the StorageLifecycleReport deliberately lacks deny_unknown_fields (forward-compat test at storage_lifecycle.rs:256). +- clean: the hand-written Deserialize impls are justified admission gates (manifest VM-key shape, shell-name shape) and the flatten+deny_unknown_fields combination on ManifestV04 is re-implemented correctly in the manual impl; the only convention drift is the per-field rename set above. + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0; the crate carries no telemetry at all, which is appropriate for a DTO/worker crate whose only I/O is the bounded worker seats. + +## docs +- d2b-core-p2#10 sev=medium blast=leaf effort=M verdict=actionable - manifest_v04.rs has no module doc and no doc comments on its central public wire types (`ManifestV04`, `ManifestMeta`, `ObservabilityMeta`, `VmEntry`, `VmLifecycle`, `VmGracefulShutdown`, `VmLiveActivation`, `VmLanPolicy`, `VmObservability`, `VmShellMetadata`, `ManifestShellName`, `from_slice`, `to_compact_json`), while sibling modules (host.rs, storage.rs, sync.rs, site.rs) document every type - fix: add a `//!` module doc and one-line doc comments with `# Errors` on the parse/serialize entry points, following the sibling-module style - [packages/d2b-core/src/manifest_v04.rs:1, packages/d2b-core/src/manifest_v04.rs:31, packages/d2b-core/src/manifest_v04.rs:158, packages/d2b-core/src/manifest_v04.rs:209, packages/d2b-core/src/manifest_v04.rs:41, packages/d2b-core/src/manifest_v04.rs:67] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~140 hits across 25 files; seed `/// # (Examples|Errors|Panics|Safety)` = 1 hit (console_ring.rs:48, the only canonical section in the part); direct read of manifest_v04.rs:1-123 confirms the module opens with `use` statements and the struct at line 31 carries no doc comment; host.rs:6-9, storage.rs:8-10, sync.rs:9-11 show the sibling convention. +- d2b-core-p2#11 sev=low blast=leaf effort=M verdict=actionable - the crate's Result-returning public API has no `# Errors` sections anywhere (only console_ring documents `# Panics`), so callers of `decode`, `validate`, `from_slice`/`from_path`/`to_compact_json`, `validate_unique_ids`, `validate_lock_order`, `parse`, `SourceGenerationCompatibilityFloorV1::new`, `kernel_seat::run`, and `loader_worker::run`/`run_probe` must read the body to learn the failure modes - fix: add `# Errors` sections naming the failure conditions (e.g. decode: non-alphabet byte, misplaced padding, non-multiple-of-four length) - [packages/d2b-core/src/base64_codec.rs:62, packages/d2b-core/src/site.rs:42, packages/d2b-core/src/manifest_v04.rs:41, packages/d2b-core/src/host_generation.rs:15, packages/d2b-core/src/kernel_seat.rs:150, packages/d2b-core/src/loader_worker.rs:92] + evidence: seed `-> Result<` = 17 hits across the part; zero of the public Result-returning items carry `# Errors` (seed 2 = 1 hit total); missing_docs is not enabled anywhere, so this is a proposal-class polish finding. +- clean: the one canonical section that exists (RingBuffer::new `# Panics`) is correct and the doc first sentences that exist are strong; the gaps are the two findings above. + +## perf +- clean: seeds `format!\(` = 10 hits (error-path messages, one-shot thread names at kernel_seat.rs:84, and a violation-rendering loop on a cold invariant path), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 14 hits (empty-case ring reads, bounded manifest walks, test fixtures), `\.to_string\(\)` = 8 hits (tests and error paths); the hot paths that exist (base64 encode/decode, ring buffer) already use with_capacity and sized buffers; all findings would be static (unmeasured) and none clears the bar. + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0 (threads exist via `thread::Builder` in kernel_seat.rs:83 and loader_worker.rs:63), `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 4 hits, `thread_local!|unsafe impl (Send|Sync) for` = 0; the single atomic (kernel_seat.rs:72, 102, 112) is a round-robin cursor with Relaxed ordering, exactly the counter-nobody-synchronizes-on case, and the worker seats are the sanctioned R4 sync_channel boundary with per-site allows (kernel_seat.rs:86-89, loader_worker.rs:66-69). + +## async +- clean: seeds `async fn|async move|\.await` = 8 hits, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0 (spawn_blocking appears only in module docs explaining why it is not used), `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the four async entry points (kernel_seat.rs:150, loader_worker.rs:92, 106, 114) admit via non-blocking try_send and await a oneshot, holding no lock across await and never blocking the executor; cancellation drops the waiter while the already-admitted job runs to completion, which the module docs state. + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; the crate inherits the workspace `unsafe_code = "forbid"` and contains no unsafe blocks, so the lens has nothing to judge. + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the part crosses no FFI boundary (serde(transparent) newtypes are not repr(transparent) FFI carriers). + +## macro +- clean: seed `macro_rules!` = 1 hit (allocator_config.rs:66 `allocator_string!`), seeds `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the single macro is impl-per-type generation (one of the three genuine macro answers), uses narrow ident/expr fragment specifiers, and references only items local to its expansion site, so no $crate or _private module is needed. + +## test +- d2b-core-p2#12 sev=medium blast=leaf effort=S verdict=actionable - the static_invariants.rs module doc claims the bash-gate cases were "preserved as unit tests", but the file contains no `#[cfg(test)]` module, so the four security invariant validators have zero test coverage (and zero callers, per finding #5) - fix: add the unit tests the doc promises (positive and negative fixtures for each validator, matching the old bash-gate cases) or correct the doc if the module is retired - [packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:158] + evidence: seed `#\[test\]|#\[tokio::test\]` = 0 hits in static_invariants.rs (grep over the file: no cfg(test), no #[test]); the seed totals for the part are ~42 in-module tests plus ~29 in tests/, all with real assertions; seed `proptest!|insta::assert|rstest` = 0 and seed `#\[ignore\]` = 0. +- d2b-core-p2#13 sev=low blast=leaf effort=S verdict=actionable - `tamper_owner_wrong_uid` in tests/bundle_resolver_tamper.rs silently returns (eprintln + return) when not root, so it passes vacuously on non-root CI and a regression in the chown tamper path would go unnoticed there - fix: convert the inline skip to the repo's documented `#[ignore]` root-only pattern (the card's false-positive list endorses documented ignores) so the skip is visible in test output - [packages/d2b-core/tests/bundle_resolver_tamper.rs:149] + evidence: seed `#\[ignore\]` = 0 hits, so the repo's documented-ignore convention is not applied here; the test body at lines 148-151 shows the silent-return shape; the remaining ~71 tests in the part are behavior-asserting (golden round-trips via include_str!, RFC 4648 vectors, bounded-queue refusal semantics, deny-unknown-fields closures) and can fail. +- clean: the suite is otherwise strong: golden fixtures from tests/golden, RFC 4648 vectors, corpus-driven bounded-input tests (tests/manifest_bounded_property.rs), worker panic/refusal semantics (tests/loader_worker.rs, tests/loader_worker_panic.rs), and error-kind assertions rather than Display strings in manifest_v04 tests; the two findings above are the only gaps. + +## Coverage +- idiom: 1 finding | clean otherwise (seeds: 2/3/3) +- own: 1 finding | clean otherwise (seeds: 6/~45/0/0) +- type: 1 finding | clean otherwise (seeds: 4/3/3) +- api: 3 finding(s) (seeds: ~140 pub items across 25 files, 0, 8) +- err: 2 finding(s) (seeds: 66 all in tests, 2, 0, 3) +- serde: 1 finding | clean otherwise (seeds: ~90/~60/2/~25) +- obs: clean (seeds: 0/0/0/0; crate has no telemetry) +- docs: 2 finding(s) (seeds: ~140, 1, 17) +- perf: clean (seeds: 10/14/8; all cold-path or sized) +- conc: clean (seeds: 0/0/4/0; Relaxed round-robin cursor correct) +- async: clean (seeds: 8/0/0/0; try_send admission + oneshot await, no blocking) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, workspace unsafe_code = "forbid") +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary in the part) +- macro: clean (seeds: 1/0/0/0; single justified impl-per-type macro) +- test: 2 finding(s) (seeds: ~71, ~150, 0, 0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md new file mode 100644 index 000000000..755ea3802 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md @@ -0,0 +1,87 @@ +# d2b-host - d2b-host +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11,767 (excl. src/generated/**; src 11,316 + tests 451) | modules: bridge_port, cgroup, devices, hardlink_farm, host_generation, host_prep_dag, ifname, ioctl_policy, media, modules, netlink, nftables, ownership_matrix, routes, seccomp, bin/ +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- clean: seeds ran: 1/0/18. The single `for \w+ in 0..` hit is a test-fixture side-effect loop (tests/activation_helper_build_farm.rs:23; plain `for` is right per the skill); all 18 `let mut X::new()` sites are legitimate accumulation into owned buffers or error vectors with real side effects; zero hand-written `Default|From|Debug|Clone|Hash|Eq|PartialEq` impls; no `fn get_` names found. + +## own +- clean: seeds ran: 66/335/3. Every `.clone()` (66) and `.to_owned()|.to_string()` (335) inspected: each is an explainable error-record payload, a multiple-step construction from one borrowed value (host_prep_dag bundle refs, devices rows, ownership_matrix drift records), a test fake (RefCell-backed ops logs, drift simulators), or a wire/serde boundary; the 3 shared-ownership hits are 2 test-fake `RefCell>` fields (netlink.rs:357, nftables.rs:891,894) and 1 test-fake `Mutex` (cgroup.rs:796); no Rc/Arc/Cow in production code. + +## type +- d2b-host#1 sev=medium blast=family effort=M verdict=actionable - `BusId(pub String)` carries no lexical invariant: `BusId::new` accepts any string and the field is public, so the busid grammar is re-validated at every consumer instead of once at the type boundary - fix: make the field private, validate in `BusId::new` (reusing `media::validate_usb_busid`'s grammar) or add `TryFrom<&str>`, keep `#[serde(transparent)]`; then delete the three broker re-validation sites - [packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194] + evidence: seed `fn validate_\w+|fn check_\w+` = 10 hits; census: `validate_usb_busid` over `packages/` = 4 hits (3 broker call sites + defined here); `BusId(` literal construction over `packages/` = 0 external hits. + +## api +- d2b-host#2 sev=low blast=leaf effort=S verdict=actionable - `HostPrepStepId(pub String)` exposes the inner `String` on a `#[serde(transparent)]` newtype whose only constructor `new` is private, so literal construction is the only external path and the `{vm}:{kind}` id convention stays unenforced - fix: make the field private (serde transparent round-trips unchanged; `as_str()` already exists) and add a public constructor if integrators need one - [packages/d2b-host/src/host_prep_dag.rs:85] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 311 hits; census: `HostPrepStepId(` over `packages/` = 0 external literal constructions (in-crate tests only). + +## err +- clean: seeds ran: 290/23/15/14. All 290 unwrap/expect hits are in `#[cfg(test)]` modules or two justified non-test sites (`media.rs:322` after an explicit `len() != 1` guard; `host_prep_dag.rs:503` on a statically-built DAG with a named invariant); the 23 `let _ =` sites are deliberate best-effort fsync/cleanup shrugs; alla 15 panic! hits are test-arm `panic!("expected ...")` plus the documented invariant `assert!` at seccomp.rs:132 (with `# Panics` contract, and the ioctl matrix is bounded below 251 by construction); the 14 error enums are closed and wire-coded (`code()`, `as_kebab_case()`, serde-tagged`, no string-matching taxonomy. + + + +## serde +- d2b-host#3 sev=low blast=family effort=S verdict=actionable - `NftBatch` derives `Deserialize` but its `&'static str` fields pin the generated impl to `'de: 'static` (serde's `impl<'de: 'a, 'a> Deserialize<'de> for &'a str`), so the type cannot be deserialized from any runtime input; the derive is dead and misleads (the broker only ever `NftBatch::parse`s text or constructs batches) - fix: drop `Deserialize` from the `NftBatch` derive (keep `Serialize`), or make `table_family`/`table_name` owned `String` if round-trip is ever intended - [packages/d2b-host/src/nftables.rs:229] + evidence: seed `derive\([^)]*(De)?[Ss]erialize|serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)|impl .*Deserialize.*for|serde_json::(from|to)_` = 125 hits; census: no `serde_json::from_*` on `NftBatch` over `packages/` = 0 hits; `NftBatch::parse` call sites in d2b-broker = 4. + + + +## obs +- clean: seeds ran: 28/0/0/0. Every println!/eprintln! hit lives in `bin/d2b-activation-helper.rs` and is CLI product output or the helper's JSON wire protocol on stdout (card false positive for `bin/**`); zero tracing/log, zero instrument spans, zero interpolated telemetry events (this crate deliberately carries no telemetry dependency). + +## docs +- d2b-host#4 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub functions document failure conditions in prose but carry no `# Errors` sections; the crate has only 2 canonical sections total (host_prep_dag.rs:316, seccomp.rs:112) against ~119 `-> Result<` signatures (validate_readback, parse_request, gunzip_inflate, ...) - fix: add `# Errors` sections naming the failure conditions to the pub Result-returning fns, starting with the wire-boundary parsers (host_generation.rs, media.rs, nftables.rs) - [packages/d2b-host/src/bridge_port.rs:127, packages/d2b-host/src/host_generation.rs:103, packages/d2b-host/src/media.rs:41] + evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 284, `/// # (Examples|Errors|Panics|Safety)` = 2, `-> Result<` = 119. +- d2b-host#5 sev=low blast=leaf effort=S verdict=actionable - Pub items in impl blocks lack doc comments: `Controller::REQUIRED`, `Controller::as_str`, `Controller::from_token`, `BusId::new`, `HostPrepStepId::as_str` - fix: one-line doc comments, with `from_token` documenting the token grammar it accepts - [packages/d2b-host/src/cgroup.rs:53, packages/d2b-host/src/cgroup.rs:71, packages/d2b-host/src/cgroup.rs:85, packages/d2b-host/src/nftables.rs:612, packages/d2b-host/src/host_prep_dag.rs:92] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 284 hits; the five anchors carry no preceding `///` line (verified by neighborhood read). + +## perf +- d2b-host#6 sev=low blast=leaf effort=S verdict=actionable - Hex digests are built with `format!("{b:02x}")` per byte, allocating a fresh String per byte (32+ allocations per digest) in `Sha256::of` and `generation_id` - fix: write into one preallocated `String::with_capacity(64)` via `write!`/`fmt::Write`, or share a hex helper - [packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628] + evidence: static (unmeasured); seed `format!\(` = 116 hits, of which these two are per-byte loops (cold paths: per batch apply / per generation build). + +## conc +- clean: seeds ran:: 0/1/0/0. The single `Mutex<` hit is the test-only `FakeCgroupBackend.inner` (cgroup.rs:796); no threads, no atomics/Ordering, no thread_local, no manual Send/Sync claims in the crate (the fake's `Mutex` is exercised from single-thread tests and needs no ordering story). + +## async +- clean: seeds ran:: 318/1/0/18. The crate's async surface (hardlink_farm + bin)drove entirely by `tokio::fs` I/O with the runtime created once at the binary entry (`#[tokio::main(flavor = "current_thread")]`); the single spawn-family hit is a policy comment (hardlink_farm.rs:1554, "async-purity policy bans spawn_blocking"), zero `tokio::sync::*`, zero guards held across awaits; sync helpers (`current_boot_id`, `process_identity`, `safe_usb_block_candidates`, `mirror_metadata`'s chown(syscall) carry per-site `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` sanctions tracked by the blocking census (baseline lists all d2b-host blocking APIs at 0) - policy-confirmed, not re-flagged. + + + +## unsafe +- clean: seeds ran: 0/0/9/5. Zero actual `unsafe` blocks/fns/impls in the crate (crate-root `#![forbid(unsafe_code)]` at lib.rs:20); alla 9 `from_raw` hits are safe constructors (`rustix::fs::FileType::from_raw_mode`, `Uid::from_raw`, `Gid::from_raw`, `std::io::Error::from_raw_os_error`), the 5 `unsafe_code` hits are the forbid declaration and its rationale comments; the manifest-level `forbid` explains why `nix`'s safe fchown wrapper is used over rustix's unsafe one (Cargo.toml comment). + +## ffi +- clean: seeds ran: 0/1/1/0. The `repr(C)` hit is the deliberate `BpfInstruction` layout matching `libc::sock_filter` for the broker's quarantined sys.rs (card false positive); the `catch_unwind` hit is a test-only `debug_assert!` exercise (cgroup.rs:1137); no extern "C", no no_mangle, no CStr/CString/c_char cross any boundary in this crate. + + + +## macro +- clean: seeds ran: 1/0/0/0. The single `macro_rules!` (bridge_port.rs:133 `check!`) is a local impl-per-field generator over 5 bool fields of a Copy wire struct with the narrowest fragment specifier (`$field:ident`), defined and consumed inside one function - a genuine last-resort use, not a finding. + + + +## test +- d2b-host#7 sev=medium blast=family effort=M verdict=actionable - `NftBatch::parse` (the ~200-line nft script dialect parser with 15+ error paths) has no tests: zero calls to `parse` exist in the crate's test modules, while the broker feeds it live script bodies on its nft apply path - fix: table-driven parse tests (valid script, malformed header, foreign family/table, missing hook priority, unterminated chain, trailing content) asserting `ParseNftScriptError` variants - [packages/d2b-host/src/nftables.rs:245] + evidence: seeds `#\[test\]|#\[tokio::test\]` = 163, `assert_eq!\(|assert_ne!\(|assert!\(` = 387 hits over src+tests; census: `NftBatch::parse` over `packages/` = 5 hits (1 definition, 4 broker call sites at ops/nft.rs:302,356 and runtime.rs:8598,10007, 0 tests). +- d2b-host#8 sev=low blast=leaf effort=S verdict=actionable - `package_digest_includes_bytes_read_through_store_symlinks` writes fixtures to a CWD-relative `target/` directory (the cargo build dir), polluting build artifacts and failing under a read-only target; every sibling test uses `tempdir()` - fix: use `tempfile::tempdir()` like the sibling tests - [packages/d2b-host/src/bin/d2b-activation-helper.rs:792] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 387 hits; the anchor is the only test in the crate using a CWD-relative path (`PathBuf::from("target")`, bin/d2b-activation-helper.rs:792-793) instead of a tempdir. + + + +## Coverage +- idiom: clean (seeds ran: 1/0/18) +- own: clean (seeds ran: 66/335/3) +- type: 1 finding(s) +- api: 1 finding(s) +- err: clean (seeds ran: 290/23/15/14) +- serde: 1 finding(s) +- obs: clean (seeds ran: 28/0/0/0) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 0/1/0/0) +- async: clean (seeds ran: 318/1/0/18) +- unsafe: clean (seeds ran: 0/0/9/5) +- ffi: clean (seeds ran: 0/1/1/0) +- macro: clean (seeds ran: 1/0/0/0) +- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md new file mode 100644 index 000000000..1066c2762 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md @@ -0,0 +1,71 @@ +# d2b-p1 - d2b - part 1/3 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6520 (excl. src/generated/**) | modules: context, activation, zone_support_bundle, share, guest, zone, host_generation, runtime, main +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/context.rs, src/activation.rs, src/zone_support_bundle.rs, src/share.rs, src/guest.rs, src/zone.rs, src/host_generation.rs, src/runtime.rs, src/main.rs + +## idiom +- clean: seeds ran: 0 index loops / 0 hand-written impls / 4 statement-accumulations; the 4 hits (context.rs:2708, context.rs:2727, context.rs:2738, activation.rs:246) are bounded reads and a byte-budget string fold where an iterator pipeline would obscure the early-exit condition; no derive-replaceable impls and no index loops exist. + +## own +- clean: seeds ran: 77 clones / 121 to_owned-to_vec-to_string / 1 Rc-RefCell-Arc-Mutex / 0 Cow; every clone inspected is explainable (owned constructor parameters such as CliZoneConnector::new and ProcessAttachTarget::shell_session, post-move reuse of resource_ref and guest_ref, serde_json::from_value ownership, clap arg fields); the single RefCell is the cfg(test) TEST_STAGING_BASE thread_local (activation.rs:114-117), a test fixture. + +## type +- d2b-p1#1 sev=low blast=leaf effort=M verdict=actionable - ZoneContext stores the validated Zone name as a bare String and re-validates it at every construction site instead of carrying the invariant in the already-imported ZoneId type - fix: store `ZoneId` in ZoneContext (field at context.rs:713), build `zone_ref()` and `zone_name()` from it, delete `validate_zone_name` (context.rs:2751) and the duplicated double validation in `discover` (context.rs:752 and context.rs:763), and replace the `expect` re-parses in `from_socket` (context.rs:801-803) with direct construction - [context.rs:713, context.rs:2751, context.rs:801] + evidence: seeds `fn validate_\w+|fn check_\w+` = 5 hits, `is_\w+: bool|\w+_flag: bool` = 2, `(mode|kind|state): String` = 3; the other 4 validate hits and all bool/String hits are wire-mirror types (ManifestVm.is_net_vm, ManifestRuntime.kind, BridgeHealthFixture.state, DaemonErrorEnvelope.kind) or boundary admission checks on untrusted daemon JSON (validate_response, validate_share_spec, validate_share_type_filter, validate_operation), which the card exempts. + +## api +- d2b-p1#2 sev=medium blast=leaf effort=S verdict=actionable - `pub mod host_generation` (lib.rs:25) is the crate's only public module and its three exported items have zero consumers anywhere in the workspace - fix: make it `mod host_generation` (private) until a caller exists, or wire `build_request` into the host-generation CLI flow that currently does not call it - [packages/d2b/src/host_generation.rs:7, packages/d2b/src/host_generation.rs:17, packages/d2b/src/host_generation.rs:36] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 14 hits; census: `HostGenerationRequest|build_request` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 1 hit (the defining file itself); the error-code strings host-generation-target-invalid and host-generation-artifact-invalid appear in no docs/reference/error-codes.md or cli-contract.md entry, so no wire pin exists. +- d2b-p1#3 sev=low blast=leaf effort=S verdict=actionable - zone_support_bundle.rs declares 9 `pub` items (6 structs, 3 consts, build_bundle, render_ndjson) inside a private module, a pub-in-private surface no external caller can reach - fix: reduce to `pub(crate)` or plain items, keeping only what the in-file tests and `run` need - [zone_support_bundle.rs:19, zone_support_bundle.rs:28, zone_support_bundle.rs:99, zone_support_bundle.rs:323, zone_support_bundle.rs:395] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 14 hits; census: `build_bundle|render_ndjson|ResourceStatusSnapshot` over packages/ and tests/ = 0 hits outside the defining file; the d2b integration test drives the CLI binary (tests/zone_support_bundle_contract.rs), not the library surface. + +## err +- clean: seeds ran: 84 unwrap-expect / 13 let-underscore-or-ok / 10 panic-unreachable-todo-unimplemented / 2 error enums; the only non-test unwrap/expect sites are invariant panics with named reasons (context.rs:529 fixed-width prefix conversion after an explicit length check, context.rs:801-803 validated-name construction, runtime.rs:28 startup precondition) which the card exempts; every `let _ =` site is deliberate best-effort teardown (socket shutdown, stream cancel/close on signal paths, temp-file cleanup); the 3 unreachable! sites (share.rs:203, share.rs:233, guest.rs:277) sit on closed local constructions; HostGenerationRequestError is a closed two-variant enum with Display, fine for a CLI-internal type. + +## serde +- clean: seeds ran: 16 derives / 18 serde attributes / 0 hand-written Deserialize / 52 serde_json calls; all types are wire mirrors with deliberate rename_all camelCase, deny_unknown_fields on operator-facing fixtures, and `default` on support-bundle projections; the flatten on ManifestDocument.entries (context.rs:137) is a deliberate schema mirror consuming unknown top-level keys; no try_from gap, no untagged enum, no hand-written admission gate. + +## obs +- clean: seeds ran: 2 println-eprintln / 0 interpolated event macros / 0 instrument / 7 tracing-log; the 2 eprintln sites (activation.rs:234, activation.rs:258) are CLI user-facing pending-config notes, product output the card exempts; the 7 tracing/log hits are substring false positives (`surface_catalog::` contains "log::") in guest.rs and host_generation.rs; the crate emits no telemetry from this partition. + +## docs +- d2b-p1#4 sev=low blast=leaf effort=S verdict=actionable - two Result-returning public functions lack the canonical `# Errors` section naming their failure conditions - fix: add `# Errors` to `build_request` (TargetInvalid vs ArtifactInvalid) at host_generation.rs:17 and to `render_ndjson` (serialization failure only) at zone_support_bundle.rs:395 - [host_generation.rs:17, zone_support_bundle.rs:395] + evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 14, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 106; all 14 public items carry first-sentence doc comments and all modules carry `//!` docs, so the only gap is the missing Errors sections on the 2 Result-returning pub fns. + +## perf +- d2b-p1#5 sev=medium blast=leaf effort=M verdict=actionable - every received frame allocates and zeroes a fresh 1 MiB buffer and then copies the payload again, on the interactive shell path where the daemon answers each 50 ms poll round trip - fix: keep a reusable receive buffer (e.g. a Vec field on CliSocket reused across read_frame calls, or a thread-local scratch) so the zeroed 1 MiB allocation happens once, and return the truncated buffer instead of `frame[FRAME_PREFIX_BYTES..].to_vec()` - [context.rs:570, context.rs:538] + evidence: static (unmeasured); seeds `format!\(` = 67, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 11, `\.to_string\(\)` = 12; the remaining format!/Vec::new hits are cold error paths, bounded stdin reads, and output rendering, which the card exempts. + +## conc +- clean: seeds ran: 6 std-thread / 1 Mutex / 29 atomics / 1 thread_local; the atomics in CliAttachStream and call_options use paired Acquire/Release/AcqRel handoffs and a Relaxed counter, all correct for their shape; the Mutex is the cfg(test) MockClient recorder and the thread_local is the cfg(test) staging override; no manual Send/Sync impls exist. + +## async +- clean: seeds ran: 67 async fn-await / 0 spawn / 1 tokio sync / 0 tokio main; the transport is readiness-driven throughout (AsyncFd, non-blocking seqpacket syscalls, bounded retry loops); the two tokio::sync::Mutex guards (round_trip_guard, stdin_offset) legitimately span awaits; the Drop-time block_on in CliAttachStream::drop is guarded by inside_runtime(); the select! loop documents its cancellation safety; all disallowed-method sites carry the sanctioned "CLI-only path" reason. + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; seed 4 alone (workspace `unsafe_code = "forbid"` inherited via `[lints] workspace = true`, Cargo.toml:8-9) does not make the lens applicable. + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no foreign-caller boundary exists in this partition. + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macro definitions in this partition. + +## test +- clean: seeds ran: 32 test attributes / 119 assertions / 0 proptest-insta-rstest / 0 ignore; 32 tests across the six in-file test modules (context.rs, activation.rs, zone_support_bundle.rs, share.rs, guest.rs, zone.rs) all assert observable behavior (frame formats, bounded deadlines, redaction, envelope fields) with human-written expectations; no test is structurally unable to fail; the crate-level tests/ directory is outside this partition and was not audited here. + +## Coverage +- idiom: clean (seeds ran: 0/0/4) +- own: clean (seeds ran: 77/121/1/0) +- type: 1 finding(s) +- api: 2 finding(s) +- err: clean (seeds ran: 84/13/10/2) +- serde: clean (seeds ran: 16/18/0/52) +- obs: clean (seeds ran: 2/0/0/7) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 6/1/29/1) +- async: clean (seeds ran: 67/0/1/0) +- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe blocks, fns, or SAFETY comments; workspace forbid alone does not apply) +- ffi: N/A (seeds: 0/0/0/0 all zero; no extern boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) +- test: clean (seeds ran: 32/119/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md new file mode 100644 index 000000000..10500510c --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md @@ -0,0 +1,82 @@ +# d2b-p2 - d2b - part 2/3 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6600 (excl. src/generated/**) | modules: doctor.rs, zone_audit.rs, resource.rs, host_validate.rs, shell.rs, host.rs, lib.rs, complete.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: d2b-p2 per U1 (f): src/doctor.rs, src/zone_audit.rs, src/resource.rs, src/host_validate.rs, src/shell.rs, src/host.rs, src/lib.rs, src/complete.rs + +## idiom +- d2b-p2#1 sev=low blast=leaf effort=S verdict=actionable - the pidfd-table inspection detail string is re-derived by an identical 3-line match at five check sites - fix: add `PidfdEntries::state_detail() -> String` next to `load_pidfd_entries` and call it from `check_otel_host_bridge_runner`, `check_usbipd_runners`, `check_seccomp_bpf_loaded`, `check_pre_ns_posture_with_reader`, `check_broker_reap_health` - [packages/d2b/src/doctor.rs:529, packages/d2b/src/doctor.rs:579, packages/d2b/src/doctor.rs:1230, packages/d2b/src/doctor.rs:1343, packages/d2b/src/doctor.rs:1449] + evidence: seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) = 3 hits, all deliberate text building; the repeated `match &entries.state { PidfdState::ParseError(d) => d.clone(), _ => "daemon state dir unreadable".to_owned() }` block read at 5 sites +- d2b-p2#2 sev=low blast=leaf effort=M verdict=actionable - `typed()` hand-rolls eight field-by-field typed-args to generic-args conversions with ~20 clones instead of `From` impls - fix: implement `From for GenericListArgs` (and the other six pairs) consuming the typed args, and change `typed()`/`typed_noun()` to take `TypedResourceArgs` by value so the conversions stop cloning - [packages/d2b/src/resource.rs:525, packages/d2b/src/resource.rs:546, packages/d2b/src/resource.rs:555, packages/d2b/src/resource.rs:565, packages/d2b/src/resource.rs:592, packages/d2b/src/resource.rs:608, packages/d2b/src/resource.rs:617] + evidence: own seed 1 (`\.clone\(\)`) = 52 hits, ~20 of them inside `typed()` at resource.rs:533-621; the generic structs (GenericListArgs etc.) are the same fields as the typed structs, so `From` applies +- d2b-p2#3 sev=low blast=leaf effort=S verdict=actionable - `valid_digest` and `valid_hash` in zone_audit.rs are byte-identical functions - fix: keep one (e.g. `valid_digest`) and delete the other, updating its three call sites - [packages/d2b/src/zone_audit.rs:805, packages/d2b/src/zone_audit.rs:838] + evidence: reading both bodies: identical `strip_prefix("sha256:")` + 64-hex check; `valid_hash` is called at zone_audit.rs:376 and 410, `valid_digest` at 670, 806, 816, 822 +- d2b-p2#4 sev=low blast=leaf effort=M verdict=actionable - the v1 record path in `validate_record` duplicates the ~22-line chain-verification tail of the nested `validate_v2_record` (hash extraction, expected-previous check, canonical json! build, digest compare) - fix: extract `verify_chain(object, fields_key, expected_previous) -> Result` and call it from both the v1 path and `validate_v2_record` - [packages/d2b/src/zone_audit.rs:349, packages/d2b/src/zone_audit.rs:395] + evidence: reading zone_audit.rs:349-429: the nested fn body and the outer v1 tail are identical line-for-line except the envelope/fields validation that precedes them +- d2b-p2#5 sev=low blast=leaf effort=S verdict=actionable - `validate_public_fields` and `validate_v2_fields` have identical bodies differing only in the per-field validator they call - fix: merge into one `validate_fields(class, fields, validate_field: fn(&str, &str, &Value) -> bool)` and pass `validate_public_field`/`validate_v2_field` - [packages/d2b/src/zone_audit.rs:591, packages/d2b/src/zone_audit.rs:607] + evidence: reading both bodies: same expected-count, contains-key, posture-field, key-subset, and per-field iteration logic; only the validator reference differs + +## own +- d2b-p2#6 sev=low blast=leaf effort=S verdict=actionable - three `.clone()` calls feed `json!` operands, which serde_json serializes by reference (`to_value(&expr)`), so the clones are dropped immediately - fix: pass `parsed.schema_version`, `issue_kinds`, and `parsed.issues` to `json!` without `.clone()` - [packages/d2b/src/doctor.rs:1062, packages/d2b/src/doctor.rs:1069, packages/d2b/src/doctor.rs:1070] + evidence: seed 1 (`\.clone\(\)`) = 52 hits; the three sites sit inside one `json!({...})` literal at doctor.rs:1061-1071 where the macro borrows each operand, making each clone redundant +- clean: seeds 1/2/3 = 52/116/2 hits; the remaining clones are explainable (report rows owning their detail strings, typed-args to generic-request struct conversion at dispatch, `Option` unwrap_or_else ownership, test fixtures); the two `RefCell`/`Mutex` hits are the `#[cfg(test)]` stdout-capture statics in lib.rs:74-82 + +## type +- d2b-p2#7 sev=low blast=leaf effort=M verdict=actionable - the "exactly one of --dry-run / --apply" invariant lives as a bool pair in six clap arg structs and is hand-rechecked at four call sites with diverging exit codes - fix: introduce `enum MutationMode { DryRun, Apply }` with a single `MutationMode::from_flags(dry_run, apply) -> Result` constructor and a shared missing-flag error, then use it in `require_mutation_flags`, `mutation`, `reconcile`, and `validate` - [packages/d2b/src/resource.rs:880, packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332] + evidence: seed 2 (`is_\w+: bool|\w+_flag: bool`) = 2 hits (AuditStreamValidator state bools, judged fine); the dry_run/apply pairs were found by reading: DeviceUsbAttachArgs, DeviceUsbDetachArgs, DeviceSecurityKeyCancelArgs (resource.rs), HostMutationArgs, HostValidateArgs, HostReconcileArgs (host.rs) + +## api +- d2b-p2#8 sev=low blast=leaf effort=S verdict=actionable - the d2b lib exports a wide pub surface while the only external consumer (xtask) uses just `d2b::cli_command()`; `pub mod host_generation` and `pub const EXIT_API_TIMEOUT` have zero consumers anywhere - fix: narrow `doctor`/`host_validate` pub items and `EXIT_API_TIMEOUT` to `pub(crate)`, make `host_generation` a private `mod`, keeping only `cli_command`/`run` public - [packages/d2b/src/lib.rs:25, packages/d2b/src/lib.rs:41, packages/d2b/src/doctor.rs:62, packages/d2b/src/host_validate.rs:55] + evidence: census: `use d2b::` over packages/, nixos-modules/, tests/, labs/ = 5 hits, all `d2b::cli_command()` in packages/xtask/src/main.rs:841-922; `host_generation` over packages/d2b = 1 hit (the lib.rs:25 declaration itself); `EXIT_API_TIMEOUT` over packages/d2b = 1 hit (the lib.rs:41 declaration); `#![allow(dead_code)]` at lib.rs:1 hides the zero-consumer items from the compiler + +## err +- d2b-p2#9 sev=medium blast=leaf effort=S verdict=actionable - `CliFailure` flattens the error class into the message (`format!("{error_class}: {message}")`), so callers recover the class by string-matching the message prefix - fix: add a structured `code: &'static str` field to `CliFailure` (lib.rs:44-52), populate it in `ZoneContext::failure` (context.rs:1181-1189), and match on it in `can_fallback_to_local_state` and `reconcile_deadline` instead of `message.split(':').next()` / `strip_prefix("ref-invalid: ")` - [packages/d2b/src/host.rs:200, packages/d2b/src/resource.rs:916, packages/d2b/src/lib.rs:44] + evidence: seed 1 (`\.unwrap\(\)|\.expect\(`) = 51 hits, all in `#[cfg(test)]` or after an adjacent compiler-invisible check (zone_audit.rs:99); the string-match recovery was read at host.rs:200-204 and resource.rs:916-918 +- d2b-p2#10 sev=medium blast=leaf effort=S verdict=needs-contract - `d2b host prepare`/`destroy` without flags exit 2 with kind `ref-invalid`, diverging from the documented `--apply-or-dry-run-required` exit-78 envelope; `host reconcile` exits 78 but with the wrong kind - fix: route `mutation()` and `reconcile()` through `missing_mutation_flag_envelope` (dispatch.rs:369-375) like `validate()` already does, or correct docs/reference/error-codes.md:156 - [packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, docs/reference/error-codes.md:156] + evidence: seed 3 (`\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`) = 1 hit (test-only); error-codes.md:156 pins `--apply-or-dry-run-required` exit 78 for host prepare/destroy/install flags while host.rs:274-278 emits `ref-invalid` exit 2; `missing_mutation_flag_envelope` (dispatch.rs:369) already emits the documented shape and `validate()` uses it + +## serde +- clean: seeds 1-2/3/4 = 42/0/26 hits; all Deserialize derives are loose forward-compatible shapes for daemon-persisted state files (`serde(default)` on every field, `#[allow(dead_code)]` on unused fields), DoctorStatus/WaveStatus serialize kebab-case for the CLI wire, and no hand-written Deserialize exists; `deny_unknown_fields` absence is deliberate for service-consumed messages + +## obs +- N/A: seeds 1/2/3/4 = 0/0/0/19 all effectively zero (the 19 seed-4 hits are the `surface_catalog::` substring false positive, verified: 19 of 19 match `surface_catalog`); packages/d2b/Cargo.toml declares no tracing/log dependency, so the lens's N/A criteria hold + +## docs +- d2b-p2#11 sev=low blast=leaf effort=S verdict=actionable - several pub items carry no doc comment and lib.rs has no crate-level `//!` doc - fix: add one-line first-sentence docs to `DoctorReport`, `run_doctor`, `render_summary`, `render_human` (doctor.rs), `ValidateReport`, `ValidateMode`, `exit_code` (host_validate.rs), `cli_command`, `run` (lib.rs), and a `//!` crate doc in lib.rs - [packages/d2b/src/doctor.rs:91, packages/d2b/src/doctor.rs:163, packages/d2b/src/host_validate.rs:229, packages/d2b/src/host_validate.rs:237, packages/d2b/src/host_validate.rs:625, packages/d2b/src/lib.rs:215, packages/d2b/src/lib.rs:221] + evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 30 hits, seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits, seed 3 (`-> Result<`) = 47 hits with no `# Errors` sections anywhere; the nine undocumented items were read directly + +## perf +- clean: seeds 1/2/3 = 117/23/13 hits; every `format!` is in a cold CLI error, report-rendering, or one-shot diagnostic path (doctor probes, evidence payloads, completion scripts), the `Vec::new()` hits are empty-case returns or test capture buffers, and `.to_string()` sits at wire-rendering boundaries; no hot loop or per-item allocation exists in this CLI partition, so all perf observations are static (unmeasured) + +## conc +- clean: seeds 1/2/3/4 = 2/2/0/1 hits, every one `#[cfg(test)]` (doctor.rs:2433 test sleep, shell.rs:343 test Mutex, lib.rs:74-82 test stdout-capture thread_local + Mutex); production code in the partition uses no threads, locks, atomics, or manual Send/Sync impls + +## async +- N/A: seeds 1-4 = 0 hits combined; no `async fn`, `.await`, tokio spawn, sync primitives, or `#[tokio::]` attribute in the partition (the async transport lives in context.rs/exec_client.rs, other parts); the shell watch loop is deliberately synchronous CLI polling with `std::thread::sleep` under a deadline (shell.rs:265) + +## unsafe +- N/A: seeds 1/2/3 = 0/0/0 hits; no unsafe blocks, fns, impls, SAFETY comments, or transmute/raw-pointer patterns in the partition; the crate inherits the workspace `unsafe_code = "forbid"` lint table + +## ffi +- N/A: seeds 1-4 = 0 hits combined; no extern "C", no_mangle, catch_unwind, repr(C)/repr(transparent), or CStr/CString usage in the partition + +## macro +- N/A: seeds 1-4 = 0 hits combined; no macro_rules!, proc-macro, syn/quote, `$crate`, or to_compile_error usage in the partition + +## test +- clean: seeds 1/3/4 = 153/0/0 hits (62 unit tests in the partition's src files, 91 in tests/); the suite is behavioral and independently grounded: FIPS 180-4 SHA-256 vectors (host_validate.rs:657-672), wave-catalog parity vs nixos-modules/options-daemon.nix (host_validate.rs:687, tests/host_validate_verb.rs:209), golden CLI output pins, redaction assertions (zone_audit.rs:973-995), and fail-closed envelope checks; no proptest/insta/rstest, no `#[ignore]`; the D2B_FIXTURES-gated tests in tests/cli_json_contract.rs print an explicit SKIP line and are documented gating, not silent passes + +## Coverage +- idiom: 5 finding(s) +- own: 1 finding(s) +- type: 1 finding(s) +- api: 1 finding(s) +- err: 2 finding(s) +- serde: clean (seeds ran: 42/0/26; loose daemon-state shapes deliberate, no hand-written Deserialize) +- obs: N/A (seeds: 0/0/0/19 all zero or surface_catalog substring false positives; no tracing/log dependency in Cargo.toml) +- docs: 1 finding(s) +- perf: clean (seeds ran: 117/23/13; all cold CLI paths, static unmeasured) +- conc: clean (seeds ran: 2/2/0/1; all cfg(test) hits) +- async: N/A (seeds: 0/0/0/0 all zero; no async code in the partition) +- unsafe: N/A (seeds: 0/0/0 all zero; workspace forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 153/0/0; behavioral, golden-pinned, parity-checked suite) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md new file mode 100644 index 000000000..71c2f71f3 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md @@ -0,0 +1,78 @@ +# d2b-p3 - d2b - part 3/3 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6525 (excl. src/generated/**) | modules: exec_client.rs, dispatch.rs, debug.rs, zone_doctor.rs, exec.rs, endpoint.rs, provider.rs, terminal_client.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: d2b-p3 = src/exec_client.rs, src/dispatch.rs, src/debug.rs, src/zone_doctor.rs, src/exec.rs, src/endpoint.rs, src/provider.rs, src/terminal_client.rs per U1 (f); the test lens additionally reads tests/** + +## idiom +- d2b-p3#1 sev=low blast=leaf effort=S verdict=actionable - `summarize` hand-builds a zeroed `DoctorSummary` although the type derives `Default` - fix: `let mut summary = DoctorSummary::default();` - [packages/d2b/src/zone_doctor.rs:598-601] + evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 1 hit; `DoctorSummary` derives `Default` at zone_doctor.rs:122-123 +- d2b-p3#2 sev=medium blast=leaf effort=M verdict=actionable - `all_known_subcommands` hand-maintains a 22-entry command-name list of which 13 (launch, realm list/inspect/enter/run, up, down, restart, boot, build, switch, test, rollback, generations, usb, console) are retired v2 verbs the ModernCli parser rejects, so `d2b auth status` reports them as known-but-denied commands - fix: derive the list from `ModernCli::command().get_subcommands()` minus `PROJECTION_COMMANDS` the way `BUILTIN_COMMANDS` does, or drop the retired entries; update the pinned expectation in tests/auth_status_contract.rs - [packages/d2b/src/dispatch.rs:688-706, packages/d2b/src/dispatch.rs:1169-1175] + evidence: idiom seeds 1/2/3 = 1/1/6; census: the `ModernCommand` variants dispatched at dispatch.rs:794-929 contain none of launch/realm/up/down/restart/boot/build/switch/test/rollback/generations/usb/console, and the parser test `modern_parser_has_no_v2_alias_or_realm_dispatch` asserts those parse as errors; tests/auth_status_contract.rs pins the current allowed list, so the fix updates that test + +## own +- d2b-p3#3 sev=low blast=leaf effort=S verdict=actionable - redundant clones of paging values that are dead after the call: `cursor.clone()` before `cursor` is overwritten by `next_cursor`, `page_token.clone()` before reassignment from `nextCursor`, and `reference.to_owned()` on a fresh `format!` String - fix: move `cursor` and `page_token` into the calls (reassign afterwards) and move `reference` into the struct literal - [packages/d2b/src/dispatch.rs:548, packages/d2b/src/debug.rs:472, packages/d2b/src/debug.rs:418] + evidence: own seeds 1/2/3/4 = 19/109/3/0; each cited value is unused after the call (loop bodies reassign from the response); `AuditExportCursor` is a non-Copy struct (d2b-contracts/src/audit_wire.rs:8-15) +- d2b-p3#4 sev=low blast=leaf effort=S verdict=actionable - `modern_run` clones the entire argv (`raw_args.clone()`) for `try_parse_from` although `raw_args` is consumed by value from the only caller and never used again - fix: `ModernCli::try_parse_from(raw_args)` - [packages/d2b/src/dispatch.rs:977] + evidence: own seed 1 = 19 hits; census: `dispatch::modern_run(raw_args)` at packages/d2b/src/lib.rs:236 passes ownership and no later use of `raw_args` exists in `modern_run` +- d2b-p3#5 sev=low blast=leaf effort=S verdict=actionable - `host_error_envelope` takes seven `&str` parameters and `.to_owned()`s each into the envelope, while callers pass `&format!(...)` results, allocating twice per field - fix: take `impl Into` parameters so `format!` results move in directly - [packages/d2b/src/dispatch.rs:296-313, packages/d2b/src/dispatch.rs:347, packages/d2b/src/dispatch.rs:359, packages/d2b/src/dispatch.rs:371-377] + evidence: own seed 2 = 109 hits; callers at dispatch.rs:346-378 (and host.rs:144,367) pass `&format!(...)` into the `&str` parameters + +## type +- d2b-p3#6 sev=low blast=leaf effort=S verdict=actionable - closed CLI vocabularies carried as `String` and validated at every call site: `ExecKillArgs.signal` checked by `matches!` in `kill`, and `endpoint_class: Option` checked by `validate_endpoint_class` in `list` and `watch` - fix: clap `ValueEnum` on the args fields so an invalid value is a parse error and the runtime checks disappear - [packages/d2b/src/exec.rs:90, packages/d2b/src/exec.rs:345, packages/d2b/src/endpoint.rs:34, packages/d2b/src/endpoint.rs:42, packages/d2b/src/endpoint.rs:203-216] + evidence: type seeds 1/2/3 = 6/0/3; both vocabularies are closed five-value sets validated only at CLI entry; the wire value stays a string so no contract change + +## api +- clean: seeds 72/0/0 run; every `pub` item in the part sits inside a private module (`mod exec_client;` etc., lib.rs:13-36), so the items are unreachable crate-external surface; the d2b lib's only outside consumer is xtask via `d2b::cli_command()` (census: 6 hits in packages/xtask/src/main.rs); no `Arc`/`Rc`/`Box`/`RefCell` in any public signature (`FdStateGuard`'s `Box` is a private field) + +## err +- clean: seeds 33/10/5/0 run; all 33 `unwrap`/`expect` and all 5 `panic!` sit in `#[cfg(test)]`; the 10 `let _ =` sites are deliberate best-effort cleanup or discarding an `Ok` value (`round_trip(&close_op(...))?`, `fcntl_setfl`, `writeln!`, `error.print()`); `ExecClientError` is a documented struct (not an enum) carrying the redaction-safe wire `kind` slug, and `exit_for_kind` owns the exit-code mapping with a tested table + +## serde +- clean: seeds 13/11/0/16 run; `HostErrorEnvelope` and `AuditResponseFrame` use `rename_all = "camelCase"` plus `deny_unknown_fields`; zone_doctor projections use type-level `#[serde(default)]`; no hand-written `Deserialize` impls; wire decode failures map to typed `ExecClientError` instead of stringified messages + +## obs +- N/A: seeds 0/0/0/0 all zero (the 5 `tracing::|log::` grep hits are `surface_catalog::` substring false positives); d2b has no tracing/log dependency (packages/d2b/Cargo.toml), and CLI output goes through the `print_stdout`/`print_stderr` product-output helpers, not telemetry + +## docs +- d2b-p3#7 sev=low blast=leaf effort=S verdict=actionable - six `pub fn` response expecters (`expect_start`, `expect_detached_create/list/logs/status/kill`) carry no doc comment in an otherwise fully documented module - fix: one-line docs stating the expected `ExecOpResponse` variant and the protocol error on mismatch - [packages/d2b/src/exec_client.rs:497, packages/d2b/src/exec_client.rs:507, packages/d2b/src/exec_client.rs:519, packages/d2b/src/exec_client.rs:531, packages/d2b/src/exec_client.rs:543, packages/d2b/src/exec_client.rs:555] + evidence: docs seeds 1/2/3 = 72/0/66; the six fns are the only undocumented `pub` items in the module (bin crate, so this is a proposal, never the `missing_docs` lint) + +## perf +- clean: seeds 54/16/109 run; all `format!` sites are error paths, one-shot CLI rendering, or test fixtures (cold per the card); the FSM's per-op `session.to_owned()` is one small String per socket round trip, not a hot-loop allocation; `pending_stdin` and the capture buffers grow by push with natural capacity reuse + +## conc +- clean: seeds 1/1/0/0 run; one dedicated sigwait thread (`d2b-exec-sig`) is the right channel model for signal forwarding; the single `Arc>>` has genuine two owners (sigwait thread + FSM) with a briefly held guard; the `tokio::sync::Notify` waiter documents its permit semantics; no atomics and no unsafe `Send`/`Sync` impls + +## async +- clean: seeds 7/0/2/0 run; `audit_via_socket` is a bounded-budget async fn awaiting only socket send/recv; `InstalledSignals::waiter` uses the documented Notify permit pattern; `block_on` appears only at the CLI entry (`try_audit_via_socket`, dispatch.rs:514-517), a sanctioned process entry point; no guard is held across an `.await` + +## unsafe +- N/A: seeds 0/0/3/0 all zero (the 3 `from_raw` hits are `io::Error::from_raw_os_error`, std functions, not unsafe blocks); no `unsafe` block/fn/impl and no `unsafe_code` attribute in the part; the crate inherits `unsafe_code = "forbid"` via `[lints] workspace = true` (packages/d2b/Cargo.toml:8-9) + +## ffi +- N/A: seeds 0/0/0/0 all zero + +## macro +- N/A: seeds 0/0/0/0 all zero + +## test +- d2b-p3#8 sev=medium blast=leaf effort=S verdict=actionable - the `d2b exec wait` guest-exit-code passthrough (`guestExitCode`/`exitCode` lookup, 0-255 filter, `unwrap_or(0)`) has no unit or integration test, so a regression in the CLI exit-code contract would pass silently - fix: extract the extraction into a testable helper or add a mock-daemon integration test asserting the passthrough and the out-of-range fallback - [packages/d2b/src/exec.rs:227-239] + evidence: test seeds over src+tests = 145/571/0/0; census: `exec.*wait|guestExitCode` over packages/d2b/tests = 0 hits; the exec.rs unit tests cover only attach +- d2b-p3#9 sev=low blast=leaf effort=S verdict=actionable - `validate_env` (KEY=VALUE shape, key length and charset bounds) has no test, unlike the sibling `validate_exec_ref` behavior that the attach tests cover - fix: table-driven unit test with human-written expected outcomes (valid, empty key, over-64 key, non-alnum key, missing `=`) - [packages/d2b/src/exec.rs:383-397] + evidence: test seeds over src+tests = 145/571/0/0; census: `validate_env` appears only at exec.rs:125 (one call site, no test) + +## Coverage +- idiom: 2 finding(s) +- own: 3 finding(s) +- type: 1 finding(s) +- api: clean (seeds ran: 72/0/0) +- err: clean (seeds ran: 33/10/5/0) +- serde: clean (seeds ran: 13/11/0/16) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: 1 finding(s) +- perf: clean (seeds ran: 54/16/109) +- conc: clean (seeds ran: 1/1/0/0) +- async: clean (seeds ran: 7/0/2/0) +- unsafe: N/A (seeds: 0/0/3/0 all zero; `from_raw` hits are `from_raw_os_error` false positives) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md new file mode 100644 index 000000000..ac45aeae6 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md @@ -0,0 +1,87 @@ +# d2b-process-conformance - d2b-process-conformance +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4195 (excl. src/generated/**, none present; no tests/ dir exists) | modules: whole crate (13 src files: error, identity, launch_identity, lib, port, process_provider, provider, sandbox, status, suite, terminal, testing, ticket) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (1 part) + +## idiom +- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0; applicable (crate declares many `fn` bodies) but all three seeds are zero - no index loops, no hand-written derives (the hand-written `Debug`/`Serialize` impls redact secret bytes and render wire hex, both deliberate), no statement-style accumulation. + +## own +- d2b-process-conformance#1 sev=low blast=leaf effort=S verdict=actionable - LaunchTicket's consuming `with_*` builders clone the whole `launch_identity` (two `String` fields plus refs) before delegating to a by-value `LaunchIdentity::with_*`, although moving the field out of the consumed ticket and writing the result back does the same job without the copy - fix: `self.launch_identity = self.launch_identity.with_owner(owner_ref.clone())?;` (same shape at the other three sites: with_owner_uid, with_owner_ref, with_target_ref) - [packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/ticket.rs:610, packages/d2b-process-conformance/src/ticket.rs:631, packages/d2b-process-conformance/src/ticket.rs:664] + evidence: seed `\.clone\(\)` = 45 hits; the 4 sites cited are the only non-fixture `launch_identity.clone()` builder calls (remaining hits are test fixtures or genuine multi-use copies such as `owner_ref.clone()` stored alongside the moved value) +- clean: seeds `\.clone\(\)`=45, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=13, `Rc<|RefCell<|Arc`), keeping the two accessors; the XOR check and the per-mutator guards (ticket.rs:546-552) become unrepresentable - [packages/d2b-process-conformance/src/ticket.rs:387, packages/d2b-process-conformance/src/ticket.rs:395, packages/d2b-process-conformance/src/ticket.rs:768] + evidence: seed `fn validate_\w+|fn check_\w+` = 4 hits (LaunchTicket::validate, validate_controller_launch, validate_assignment, validate_process_identity), read with full context; the cited pair is the one coupled-Option invariant in the crate (other `Option` fields are genuinely independent) +- clean: seeds `fn validate_\w+|fn check_\w+`=4, `is_\w+: bool|\w+_flag: bool`=0, `(mode|kind|state): String`=0; the four `validate_*` functions are deliberate conformance gates over private-field tickets (the crate's contract is re-validating decoded tickets), `binding_worker`/`reaped` are private booleans set only through checked constructors. + +## api +- d2b-process-conformance#3 sev=low blast=leaf effort=S verdict=actionable - `terminal::ExitClass` is re-exported under two names and the `BrokerExitClass` alias has zero consumers anywhere in the repo (the only hit is the re-export itself), while `ProcessExitClass` is the name the one real consumer (systemd lifecycle) imports - fix: drop the `ExitClass as BrokerExitClass` arm from lib.rs:54, keep `ExitClass as ProcessExitClass` - [packages/d2b-process-conformance/src/lib.rs:52, packages/d2b-process-conformance/src/lib.rs:54] + evidence: census `BrokerExitClass` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (its own re-export), vs `ProcessExitClass` = 6 hits incl. d2b-provider-process-systemd/src/lifecycle.rs:5 +- d2b-process-conformance#4 sev=low blast=leaf effort=S verdict=actionable - `process_provider.rs` re-exports the same root surface under a second public path (`d2b_process_conformance::process_provider::*`) and no caller uses that path (its own doc calls it a "destination-compatible boundary" for a split that is already settled) - fix: delete the module and its lib.rs:36 declaration; every item stays reachable at the root path - [packages/d2b-process-conformance/src/process_provider.rs:6, packages/d2b-process-conformance/src/lib.rs:36] + evidence: census `conformance::process_provider` over packages/, nixos-modules/, tests/, labs/ = 0 hits; seed `^\s*pub use ` = 11 hits (9 root arms in lib.rs, 1 in process_provider.rs, 1 multi-line status arm) +- d2b-process-conformance#5 sev=low blast=family effort=M verdict=actionable - `pub mod testing` ships the mock `ScriptedEffectPort`, `PortCall`, `block_on` poller, and `TicketBuilder` fixtures unconditionally in the production library surface, while the house pattern (api card false-positive note) is a feature-gated `test-support` export; every in-tree consumer is a test target (provider crates' integration tests, d2bd `#[cfg(test)]`, provider-supervisor tests) - fix: gate `testing` behind a `test-support` feature (`#[cfg(feature = "test-support")] pub mod testing;`) and have consumer test targets enable it via dev-dependencies; `suite` stays ungated (it is the crate's product) - [packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testing.rs:60] + evidence: census `d2b_process_conformance::testing` over packages/ = 11 call sites, all under tests/ or `#[cfg(test)]` (d2b-provider-process-systemd/tests/conformance.rs:7, d2b-provider-process-minijail/tests/conformance.rs:8, d2b-provider-supervisor/src/adapter.rs:921, d2bd/src/provider_effects.rs:1484, d2b-provider-process/src/backend.rs:355) +- d2b-process-conformance#6 sev=low blast=leaf effort=S verdict=actionable - `CompiledSandbox::requires_cgroup_kill()` is public API whose field is set unconditionally to `true` at the only constructor, and no in-tree caller reads it (census inside the crate only); the accessor promises sandbox-dependent variation the compiler can never produce - fix: either thread a real `StopProof`/cgroup decision through `compile()` and its callers, or delete the field and the accessor along with the suite's unused surface - [packages/d2b-process-conformance/src/sandbox.rs:18, packages/d2b-process-conformance/src/sandbox.rs:61, packages/d2b-process-conformance/src/sandbox.rs:98] + evidence: census `requires_cgroup_kill` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 4 hits, all inside sandbox.rs (field, accessor body, constructor); seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 216 hits, all pub items read whole-file (no sampling needed) +- clean: seeds 216/0/11 (pub items / `pub .*\b(Arc|Rc|Box|RefCell)<` / `pub use`); every pub item and trait read; no smart-pointer or dependency types in public signatures; traits are generic over the injected port with small required surfaces and documented defaulted methods; exported wire-facing enums are the conformance vocabulary (deliberate closed sets with `#[non_exhaustive]`). + +## err +- d2b-process-conformance#7 sev=low blast=leaf effort=S verdict=actionable - `LaunchIdentity::new` re-borrows `owner_ref` with `.expect("binding owner is present")` immediately after an `is_some_and` guard on the same value, an input-derived `expect` the skill's audit flags; the guard and the re-borrow are the same condition so the panic is unreachable but the shape is avoidable - fix: use an if-let chain, e.g. `if let Some(owner) = owner_ref.as_ref().filter(|o| o.resource_type().as_str() == "VolumeBinding") && target_ref.is_none() { ... owner.to_canonical_string() ... }`, deleting both the separate guard and the `expect` - [packages/d2b-process-conformance/src/launch_identity.rs:147] + evidence: seed `\.unwrap\(\)|\.expect\(` = 141 hits; every other hit sits in `#[cfg(test)]` modules or fixture helpers that parse literal constants (sanctioned classes), and no `let _ =`/`.ok();` swallow (seed 2 = 0) or panic macro outside tests (seed 3 = 4, all suite test-code failure panics) +- clean: seeds `\.unwrap\(\)|\.expect\(`=141, `let _ = |\.ok\(\);`=0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`=4 (suite test-match arms), `enum \w*Error`=2; the two error enums are closed `#[non_exhaustive]` vocabularies with stable `code()` strings (the wire rendering, deliberate) and caller-actionable variants; error payloads echo the rejected input for diagnosability as documented. + +## serde +- d2b-process-conformance#8 sev=low blast=leaf effort=S verdict=actionable - `CompiledDigests` serialization is hand-written (`impl Serialize` emitting 7 named fields) where a derive with `rename_all = "camelCase"` plus `#[serde(rename = "fdTable")]` on `fd_table` produces the identical wire shape and stays in sync with the struct - fix: add `#[derive(serde::Serialize)]`/`#[serde(rename_all = "camelCase")]` on `CompiledDigests` (ticket.rs:105) and delete the manual impl at status.rs:125-137 - [packages/d2b-process-conformance/src/status.rs:125, packages/d2b-process-conformance/src/ticket.rs:105] + evidence: seed `impl .*Serialize.*for` (serde seed-3 variant) = 2 hits; the other hit (identity.rs:140, the digest hex renderer) is deliberate wire hex output; no field names change so `process_status_uses_the_v3_common_field_names` (status.rs:162) stays green +- d2b-process-conformance#9 sev=low blast=leaf effort=S verdict=actionable - `ProcessOutcome` derives `Deserialize` on `pub` fields but permits illegal `(exit_class, exit_code)` combinations (e.g. `Crash` with `Some(300)`), so a decoded terminal message is invalid until each consumer re-validates (`ProcessOutcome::validate`, then again inside `from_parent` and `relay`); the skill's boundary rule says the read should fail, not first use - fix: deserialize into a raw shape with `#[serde(try_from = "RawOutcome")]` (or a validating custom `Deserialize`) so illegal combinations become `InvalidTerminalResult` at the boundary, then delete the per-use re-validations or keep only one - [packages/d2b-process-conformance/src/terminal.rs:39, packages/d2b-process-conformance/src/terminal.rs:94, packages/d2b-process-conformance/src/terminal.rs:177] + evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 8 hits (the only Deserialize pair is terminal.rs:39); seed `impl .*Deserialize.*for` = 0; the wire key names are unchanged by the try_from fix, so no contract revision +- clean: seeds 8/13/0/3 (derives / serde attrs / hand-written Deserialize / serde_json calls); rename_all and skip_serializing_if usage is consistent, enum representations are external with documented vocabularies, `providerImplementation`/`processIdentityDigest` renames are deliberate v3 common-field names pinned by the crate's own wire test (status.rs:162-183); no round-trip-only trap since the only Deserialize type is validated on use today. + +## obs +- N/A: seeds `\bprintln!\(|\beprintln!\(`=0, `(info|debug|warn|error|trace)!\(`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=0 all zero; the crate declares no `tracing`/`log` dependency in Cargo.toml and contains no telemetry at all (library crate whose output is typed values, not events). + +## docs +- d2b-process-conformance#10 sev=low blast=leaf effort=S verdict=actionable - Zero canonical `# Errors` sections exist (seed 2 = 0) while 52 `-> Result<` declarations carry non-obvious failure conditions that several docs only imply (e.g. `ProcessOutcome::exited` rejects out-of-range codes, `SandboxCompiler::compile` rejects root-in-user-domain and canonical-JSON failure, `LaunchIdentity::new` names six refusal conditions, `BrokerTerminalResult::from_parent` requires matching evidence) - fix: add an `# Errors` section naming the failing conditions to the Result-returning pub items, notably terminal.rs:51/94/215, sandbox.rs:72, launch_identity.rs:112, ticket.rs:731, port.rs:35/67 - [packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/sandbox.rs:72, packages/d2b-process-conformance/src/launch_identity.rs:112, packages/d2b-process-conformance/src/ticket.rs:731] + evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)`=212, `/// # (Examples|Errors|Panics|Safety)`=0, `-> Result<`=52; `#![deny(missing_docs)]` (lib.rs:22) already guarantees presence, so the gap is section shape, not coverage; first sentences are consistently strong and magic constants carry their why (ticket.rs:27-30) +- clean: seeds 212/0/52 with all pub items read; every module carries `//!` docs, every pub item is documented (deny(missing_docs) enforced), redaction Debug impls are deliberate, and no doc comment narrates implementation. + +## perf +- clean: seeds `format!\(`=9 (7 in tests plus ticket.rs:472 one-time `Provider/{}` build and identity.rs hex rendering, all cold), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=5 (launch_args default, test doubles), `\.to_string\(\)`=0; `to_hex` pre-sizes with `String::with_capacity(64)` and pushes per byte; no loops allocate, no collection choice issues (BTreeSet is the declared sorted-identity set), findings would be static (unmeasured) and none rose to that bar. + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=1, `Atomic\w+|Ordering::`=0, `thread_local!|unsafe impl (Send|Sync) for`=0; the single `Mutex>` in `ScriptedEffectPort` (testing.rs:67) is a test double whose `try_lock` + fail-closed `unwrap_or_default` policy is documented (testing.rs:116-121) and the crate's hand-rolled poller drives everything single-threaded. + +## async +- d2b-process-conformance#11 sev=low blast=family effort=S verdict=actionable - Both traits declare their six async methods as `fn ... -> impl Future + Send` while every in-tree implementor already writes `async fn` (ScriptedEffectPort, ProviderSupervisor, systemd/minijail test ports, d2bd's NonLaunchingProcessEffectPort), and the traits already carry `Send + Sync` supertraits, so the RPITIT `async fn` form (stable, edition 2024) expresses the same Send contract more directly - fix: convert the trait method declarations to `async fn` (port.rs:99-157, provider.rs:96-148), rewriting the two default bodies (`launch_with_inherited_fds`, `probe`) as `async { ... }` and dropping the `ready(Err)...))` wrappers; no implementor changes required - [packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port.rs:129, packages/d2b-process-conformance/src/provider.rs:96, packages/d2b-process-conformance/src/provider.rs:125] + evidence: seed `async fn|async move|\.await` = 8 hits (the 6 declare/default sites plus impl-side; every impl method is already `async fn`), seeds 2-4 (spawn/JoinSet/select/tokio-sync/tokio-main) = 0; the crate owns a runtime-free `block_on` noop-waker poller (testing.rs:33) documented as hermetic, matching the sanctioned plain-test-harness class +- clean: seeds 8/0/0/0; no `tokio::spawn`, no runtime created in the library, no guard held across `.await`, no cancellation-sensitive section (all futures are immediate), block_on is a deliberate runtime-free test driver. + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern|transmute|from_raw|MaybeUninit|mem::zeroed`=0 and `// SAFETY:`=0; the crate's manifest sets `unsafe_code = "forbid"` in its local `[lints.rust]` table (Cargo.toml), so seed 4 alone does not make the lens applicable per the card. + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section|catch_unwind|repr\(C\)|repr\(transparent\)|CStr|CString|c_char`=0 all zero; the crate crosses no foreign boundary. + +## macro +- clean: seeds `macro_rules!`=1, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; the single macro `opaque_digest!` (identity.rs:105) is the sanctioned impl-per-type generation (duplicating from_bytes/as_bytes/to_hex/is_zero plus redacted Debug and hex Serialize for two digest newtypes) with narrow `ident`/`literal` fragment specifiers, invoked immediately at definition site, and no proc-macro machinery. + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]`=30, `assert_eq!\(|assert_ne!\(|assert!\(`=128, `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0; every test read: named behaviors (not implementations), assert error variants not Display strings, expected values are hand-written or fixture literals, no network/no clock (deadline fixtures are fixed constants), the suite is table-shaped over the two execution domains, redaction and wire-name pins are deliberate contracts (status.rs:162, suite.rs:312), and the fail-closed paths each have a named negative case; no test restates a getter or cannot fail; the crate has no `tests/` dir, which is right for a library whose integration surface (the shared suite) is exercised by the two provider crates' own test targets. + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: 1 finding (seeds ran: 45/13/0/0) +- type: 1 finding (seeds ran: 4/0/0) +- api: 4 findings (seeds ran: 216/0/11) +- err: 1 finding (seeds ran: 141/0/4/2) +- serde: 2 findings (seeds ran: 8/13/0/3) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 1 finding (seeds ran: 212/0/52) +- perf: clean (seeds ran: 9/5/0; all hits are cold paths, static (unmeasured)) +- conc: clean (seeds ran: 0/1/0/0) +- async: 1 finding (seeds ran: 8/0/0/0) +- unsafe: N/A (seeds: 0/0 all zero; crate manifest forbids unsafe_code) +- ffi: N/A (seeds: 0 all zero; no foreign boundary) +- macro: clean (seeds ran: 1/0/0/0) +- test: clean (seeds ran: 30/128/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md new file mode 100644 index 000000000..5ae012926 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md @@ -0,0 +1,86 @@ +# d2b-provider-activation-nixos - d2b-provider-activation-nixos +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4014 (src 3368 + tests 646, excl. src/generated/**, no generated dir present) | modules: whole crate (controller, driver, effects_service, facets, lib, test_support, vocabulary; tests/reconcile.rs, tests/registration.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- clean: seeds 1/2/3 = 0/0/0 over src; no index loops, no hand-written derive-replaceable impls, no statement-style accumulation. The three hand-written `Debug` impls (controller.rs:217, 439, 508) are deliberate redaction of key/signature bytes (card false-positive class; a derive would leak). +- clean: checked expression shape, conversion impls, naming (`as_`/`to_`/`into_` discipline holds; no `get_` accessors), and newtype usage across all seven src files. + +## own +- clean: seeds 1/2/3/4 = 41/2/0 (the card's `Rc<` alternative also matches inside every `Arc<`, inflating raw counts; real seed-3 hits are the two `Arc>` in test_support). Every clone read: Arc clones at the factory/facet boundaries are genuine shared ownership (call sites driver.rs:414, effects_service.rs:188 - the daemon composition root builds one dispatch source, the factory and each built service share it); spec-field clones build owned `RunnerRequest`/`HandoffIntent` values (controller.rs:354, 384, 789-790; driver.rs:630, 636, 806); `observed.clone()` at driver.rs:809 is required because the observation is consumed again by `execute_host_runner`/`apply_runner_result`; the rest are test doubles. No `&String`/`&Vec` parameters, no `Rc`/`RefCell`, no `Cow`, no mutable statics. +- clean: all 41 clone-family sites judged explainable in one sentence; no `mem::take` opportunity and no borrow-splitting conflict found. + +## type +- clean: seeds 1/2/3 = 1/0/0; the single hit is the test fn name `validate_rejects_a_spec_outside_the_closed_generation_contract` (driver.rs:1229), not a validation fn. State is enum-typed throughout (`CallerRole`, `GenerationPhase`, `TrustStatus`, `ActivationMode`); `start_root`/`source_generation_preserved` are single semantic booleans, not flag pairs; `ActivationRunnerStep.label` is a deliberate wire label. +- clean: no boolean-flag soup, no `Option` pairs, no stringly-typed state, no validate-at-every-callsite pattern (the spec constructor is the single admission fence, driver.rs:220). + +## api +- d2b-provider-activation-nixos#1 sev=low blast=leaf effort=S verdict=actionable - `ActivationDriver` is re-exported at lib.rs:38 but no external consumer names it: the factory returns `Box` (driver.rs:410), so the concrete type never escapes the crate - fix: make `ActivationDriver` `pub(crate)` and drop it from the lib.rs re-export arm - [packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation-nixos/src/lib.rs:38] + evidence: census: `ActivationDriver\b` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 8 hits, all inside this crate (driver.rs:411,426,436,715,964,1205; lib.rs:38); seed 1 (pub items) = 95 hits +- d2b-provider-activation-nixos#2 sev=low blast=leaf effort=S verdict=actionable - `ACTIVATION_RUNNER_RESOURCE_TYPE` (controller.rs:14) is `pub` inside the exported `controller` module but used only at controller.rs:296 in the same module, so it is reachable as `d2b_provider_activation_nixos::controller::ACTIVATION_RUNNER_RESOURCE_TYPE` with no consumer - fix: make the const private (or `pub(crate)`) - [packages/d2b-provider-activation-nixos/src/controller.rs:14, packages/d2b-provider-activation-nixos/src/controller.rs:296] + evidence: census: `ACTIVATION_RUNNER_RESOURCE_TYPE` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both in controller.rs +- clean: seeds 1/2/3 = 95/5/6; the lib.rs re-export arms are the house single-surface pattern (card false positive); the `Arc` pub field in `ActivationEffectFacets` (facets.rs:34) genuinely shares one daemon-supplied dispatch source across the factory and per-zone services (d2bd implements the trait at resource_plane_v3.rs:2316; clones at driver.rs:414, effects_service.rs:188); `ActivationDriverError` is the skill's struct-with-private-kind public error; every pub item carries a doc comment (`#![deny(missing_docs)]`, lib.rs:8). + +## err +- d2b-provider-activation-nixos#3 sev=medium blast=leaf effort=S verdict=actionable - `GenerationObservation::terminal` (exported via lib.rs:33) panics with `assert!` on a caller-supplied name that is empty, contains '/', or exceeds 128 chars, instead of making the bound a type or a `Result` - fix: take `name: ResourceName` (already bounded: no '/', <=128 chars) and have `new` parse through the same path, or return `Result`; this deletes the runtime check the type makes impossible - [packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activation-nixos/src/controller.rs:121] + evidence: seed 1 (unwrap/expect) = 48 in src, of which 18 production expects are on literally-built static values in `activation_runner_spec`/name derivation (card false-positive class) and 30 sit in `#[cfg(test)]`; seed 3 (panic!/unreachable!/todo!/unimplemented!) = 0; the assert! at controller.rs:121 is the only library panic on caller input (assert! is not a card seed) +- clean: seeds 1/2/3/4 = 48/0/0/4; error taxonomy is closed and caller-action-split: `ActivationError` (5 Copy variants, controller.rs:395), `ActivationVerificationError` (9 variants, controller.rs:497), `ActivationDriverError` (struct with private `kind` + `op`, driver.rs:133); no swallowed Results, no `let _ =`, no panic macros; every driver failure maps through `map_err` to the typed error. + +## serde +- clean: seeds 1/2/3/4 = 0/0/0/9; the 9 hits are `from_slice`/`to_value`/`from_value` at the decode hook (driver.rs:220, 549, 651, 664) and the effects payload (effects_service.rs:69). Deserialization lands directly in the closed `NixosGenerationSpec` contract type whose constructor is the validation fence; no derive/`rename_all`/`deny_unknown_fields`/`try_from` decisions live in this crate (the contract crates own them); the `providerRef` JSON insert in `ensure_runner` (driver.rs:656-659) is a deliberate wire-shape accommodation for the manager's child row, not a boundary parse. +- clean: no hand-written `Deserialize`, no enum-representation choices, no `flatten`; round-trip behavior is covered by the runner-spec assertions in tests/reconcile.rs:97-119. + +## obs +- d2b-provider-activation-nixos#4 sev=low blast=leaf effort=S verdict=actionable - nine `tracing::warn!` refusal events in `ActivationTrust::verify` are message-only with no named fields and no enclosing span (no `#[instrument]` anywhere in the crate), so the failing fence is queryable only as message text - fix: add a named field carrying the error variant (e.g. `refusal = ?ActivationVerificationError::TrustEpochMismatch`), keeping fields identifier-free so the site stays under the ADR 0010/0028 redaction gate - [packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activation-nixos/src/controller.rs:575, packages/d2b-provider-activation-nixos/src/controller.rs:581, packages/d2b-provider-activation-nixos/src/controller.rs:587, packages/d2b-provider-activation-nixos/src/controller.rs:593, packages/d2b-provider-activation-nixos/src/controller.rs:602, packages/d2b-provider-activation-nixos/src/controller.rs:609, packages/d2b-provider-activation-nixos/src/controller.rs:615, packages/d2b-provider-activation-nixos/src/controller.rs:623] + evidence: seed 2 ((info|debug|warn|error|trace)!(") = 9 hits, all message-only without fields; seed 3 ).instrument|#[instrument) = 0; seed 1 (println!/eprintln!) = 0 +- clean: the other 8 tracing sites (controller.rs:49, 57, 748, 756, 763, 815, 822, 833) carry named fields (`target`, `role`, `generation`, `prior`, `outcome`); no secret or identifier reaches a field; no library-installed subscriber. + +## docs +- d2b-provider-activation-nixos#5 sev=medium blast=leaf effort=S verdict=actionable - the pub Result-returning policy API (`verify_application`, `reconcile`, `apply_runner_result`, `refuse_undeclared_runner_step`, `ActivationTrust::verify`) documents no `# Errors` section, leaving 5 `ActivationError` and 9 `ActivationVerificationError` failure conditions unstated in the contract - fix: add `# Errors` sections naming the variants each fn returns - [packages/d2b-provider-activation-nixos/src/controller.rs:711, packages/d2b-provider-activation-nixos/src/controller.rs:735, packages/d2b-provider-activation-nixos/src/controller.rs:808, packages/d2b-provider-activation-nixos/src/controller.rs:726, packages/d2b-provider-activation-nixos/src/controller.rs:562] + evidence: seed 2 (/// # (Examples|Errors|Panics|Safety)) = 0 across the crate; seed 3 (-> Result<) = 111 hits total; seed 1 (pub items) = 95 hits +- d2b-provider-activation-nixos#6 sev=low blast=leaf effort=S verdict=actionable - `GenerationObservation::terminal` can panic (assert at controller.rs:121) but its doc comment carries no `# Panics` section, so the bound is unstated in the contract - fix: add `# Panics` naming the empty/'/'/length bound (or drop the section once finding #3's type change removes the panic) - [packages/d2b-provider-activation-nixos/src/controller.rs:118, packages/d2b-provider-activation-nixos/src/controller.rs:121] + evidence: seed 2 (canonical sections) = 0 hits; terminal is the only panic-capable pub item (assert at controller.rs:121) +- clean: every pub item is documented (`#![deny(missing_docs)]`); first sentences are single-line contract statements (e.g. "Stable controller failures.", "One declared activation runner step."); all seven modules carry `//!` docs; no doctests and no `ignore`d examples exist (nothing to rot). + +## perf +- clean: seeds 1/2/3 = 16/19/0; every `format!`/`Vec::new` site is cold: reconcile-time runner-name derivation (controller.rs:276-289), error paths, one-shot diagnostics, and test fixtures. The per-byte `format!("{byte:02x}")` digest loop (controller.rs:287) runs once per reconcile at most; no hot loop, no grow-by-push collection in a loop, no `to_string()` at a boundary. +- clean: static (unmeasured) - no benchmark exists for this crate; nothing here would move a perf budget. + +## conc +- clean: seeds 1/2/3/4 = 0/6/4/0; production uses one `tokio::sync::Mutex>` (driver.rs:433) whose guards are scoped to single statements (no guard across an await; `await_holding_lock` is denied at the workspace table), and the parking_lot `Mutex` + `AtomicU64` pairs live only in test-support doubles and the test `RecordingManager`, each with an `async-gate-allow` marker (sanctioned test-support reason; inventory `packages/xtask/data/async-gate-inventory.json`). No `std::thread`, no `thread_local!`, no manual `Send`/`Sync` claims. +- clean: the test-only `Ordering::SeqCst` uid counter (driver.rs:1033) is a fixture, not a synchronization argument worth weakening. + +## async +- clean: seeds 1/2/3/4 = 45/0/2/19; no `tokio::spawn`/`spawn_blocking`/`JoinSet`/`select!`/`join!` anywhere in production. The sync `dispatch_handoff` facet call inside async `apply_host_generation_handoff` (effects_service.rs:137) is the daemon-supplied boundary (R2): the implementation lives in d2bd's composition root (resource_plane_v3.rs:2316), outside this crate, and no blocking evidence exists here. `watched_runner` lock is never held across an await; `ensure_runner` commits the child through the manager before the spawn notification (F1), so the irreversible step is the manager's single non-cancellable commit; the 19 `#[tokio::test]` hits are test harnesses. +- clean: no runtime started inside the library; no future-size or `Send`-bound hazards found; the `async-gate-allow` markers in test_support.rs:50-52 are deliberate recorded exceptions (cited, not re-flagged). + +## unsafe +- N/A (seeds: 1/2/3 = 0/0/0 all zero; seed 4 = 1, `unsafe_code = "forbid"` in Cargo.toml [lints.rust] - a forbid setting alone does not make the lens applicable per the card) + +## ffi +- N/A (seeds: 1/2/3/4 = 0/0/0/0 all zero; no extern "C", no repr(C)/repr(transparent), no CStr/CString, no catch_unwind) + +## macro +- N/A (seeds: 1/2/3/4 = 0/0/0/0 all zero; no macro_rules! definitions, no proc-macro/syn/quote, no $crate, no to_compile_error/new_spanned) + +## test +- d2b-provider-activation-nixos#7 sev=low blast=leaf effort=S verdict=actionable - the six-case verification-fence table in `activation_verification_requires_all_trust_and_digest_fences` asserts without a per-case message, so a failure in case 3 of 6 reports only a line number and no case identity - fix: add a per-case failure message (e.g. `"case {i}: expected {expected_error:?}"`) to the loop assert - [packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activation-nixos/tests/reconcile.rs:447] + evidence: seed 2 (assert_eq!/assert_ne!/assert!) = 160 hits over src+tests; the loop at tests/reconcile.rs:439-450 is the only table without a failure message +- clean: seeds 1/2/3/4 = 38/160/0/0; 38 test fns (13 driver, 6 effects_service, 2 vocabulary, 14 reconcile, 3 registration), no `#[ignore]`, no proptest/insta/rstest. Assertions target error variants, not `Display` strings (`assert_eq!(result.unwrap_err(), ActivationError::OutcomeMismatch)`); the KTD13 argv-free fence (`assert_no_launch_argv`, driver.rs:1821) is a genuine can-fail recursive check; the F1 persist-before-spawn ordering and one-watch-per-child invariants are asserted on the recorded manager log; trust fixtures generate a fresh key per run, keeping assertions deterministic. + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 41/2/0) +- type: clean (seeds ran: 1/0/0) +- api: 2 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 0/0/0/9) +- obs: 1 finding(s) +- docs: 2 finding(s) +- perf: clean (seeds ran: 16/19/0) +- conc: clean (seeds ran: 0/6/4/0) +- async: clean (seeds ran: 45/0/2/19) +- unsafe: N/A (seeds: 0/0/0 all zero; forbid-only, per card criteria) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md new file mode 100644 index 000000000..e7425215b --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md @@ -0,0 +1,89 @@ +# d2b-provider-audio-pipewire - d2b-provider-audio-pipewire +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2709 (excl. src/generated/**, none present) | modules: whole crate (src: authority, controller, lib, mediator, resource_type, state; tests: audio_policy, authority, controller, mediator, resource_type, state) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test (+ supply per-crate note) | Partitions: whole crate (single-part lane; on the README-only integration ratchet, provider_crate_policy.rs:331-332) + +## idiom +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 0; the single hit is the hand-written `Default for AudioGrants` (resource_type.rs:161), which preserves the grants/policy-state invariant by seeding from `AudioPolicyState::default_v2()` - a listed repo false-positive class; no index loops, no statement-style accumulation, derives already present everywhere else + +## own +- clean: seeds `.clone()` = 6 (src 3: controller.rs:250-252, tests 3), `.to_owned()|.to_vec()|.to_string()` = 7 (src 5, tests 2), `Rc<|RefCell<|Arc` arbiter is the documented multi-controller shared authority (authority.rs:44), `to_owned()` copies a `&'static str` const, test clones share one arbiter across two controllers; no borrow-fight clones, no `mem::take` candidates + +## type +- d2b-provider-audio-pipewire#1 sev=low blast=leaf effort=S verdict=actionable - constructors re-validate invariants the admission gate already enforces: `AudioServiceSpec::owner` (endpoint type) and `AudioBindingSpec::new` (service/target ref types) return the same error variants `validate_audio_service`/`validate_audio_binding` produce, so the same invariant is checked at two layers and the constructors' `Result` promises a rejection path that is dead in practice - fix: drop the checks from `owner()`/`new()` (make them infallible) and keep `validate_audio_*` as the single parse-once admission gate, or delete the gate checks and keep the constructor checks - [src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, src/resource_type.rs:233-246] + evidence: seed `fn validate_\w+|fn check_\w+` = 3 hits (resource_type.rs:206,233,249); constructor checks at resource_type.rs:68-70 and 122-124 duplicate gate invariants with identical error variants (EndpointType, ReferenceType) +- d2b-provider-audio-pipewire#2 sev=low blast=leaf effort=S verdict=actionable - the shared-vs-owned controller mode is a private bool `activate_promoted` (controller.rs:210 vs 218-224) and `finalize`/`finalize_shared` are byte-identical delegations to `finalize_inner`, so the two public methods' behavioral difference is invisible in their signatures and a caller can invoke `finalize_shared` on an owned controller and get promotion activation anyway - fix: encode the mode in the type (typestate or a `MicrophoneHandoff::{Enable,Defer}` field set by construction) so the method contract holds by construction, or collapse the two methods into one documented by the constructor - [src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199] + evidence: static read (seed `is_\w+: bool|\w+_flag: bool` = 0, manual catch); `finalize` and `finalize_shared` both body `self.finalize_inner(lease)`; `activate_promoted` true from `new()`, false from `with_shared_microphone` + +## api +- d2b-provider-audio-pipewire#3 sev=low blast=leaf effort=S verdict=actionable - `SpeakerMixer::set_grant(lease, on: bool)` takes a boolean command and returns a bool whose meaning flips with the argument (true: was-empty, false: was-last), and the only caller ignores the revoke return (it calls `is_last_grant` first) - fix: split into `grant(lease) -> Result` (was-empty) and `revoke(lease) -> Result` (was-last), or return a named enum, so the return contract stops being argument-dependent - [src/authority.rs:157-171, src/controller.rs:395-403] + evidence: static read; seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 1 (authority.rs:44, unrelated shared-ownership alias); controller.rs:395-403 discards the `set_grant(lease, false)` return after `is_last_grant` +- d2b-provider-audio-pipewire#4 sev=low blast=leaf effort=S verdict=actionable - `register_service` is exported from lib.rs but has zero callers anywhere (the daemon's audio paths and the wayland-policy audio_registry validate specs directly), leaving a dead registration gate on the surface - fix: consume `register_service` in the daemon's audio Service registration path or drop the export (crate is 0.0.0-bootstrap, no semver gate) - [src/controller.rs:746-748, src/lib.rs:32] + evidence: census `register_service` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits (definition + lib.rs re-export), 0 callers +- d2b-provider-audio-pipewire#5 sev=low blast=family effort=S verdict=needs-contract - `AudioLastSetApplied::OfflineOnly` is named as if it meant "applied offline only" while its doc says "No setting was applied in the current reconcile"; the variant is rendered to a wire-visible status string "OfflineOnly" by the wayland-policy projection and pinned in daemon tests - fix: rename the variant (e.g. `NotApplied`) and update the projection string and pinned expectations together - [src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-122, packages/d2bd/src/resource_plane_v3.rs:4626] + evidence: census `AudioLastSetApplied|OfflineOnly` over packages/ = 9 hits; wire rendering at audio_registry.rs:121 and pinned at resource_plane_v3.rs:4626 and audio_registry.rs:704,745 + +## err +- d2b-provider-audio-pipewire#6 sev=medium blast=leaf effort=S verdict=actionable - `MicrophoneArbiter::new(0)` and `SpeakerMixer::new(0)` panic via `assert!` on caller input to a pub constructor; the skill's panic policy says input validation is always a `Result`, and the type-level answer (`NonZeroUsize`) exists - fix: take `NonZeroUsize` (or return `Result`) in both constructors; no current caller passes 0 (daemon uses 64), so the change is mechanical - [src/authority.rs:53-54, src/authority.rs:144-145] + evidence: seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0; `assert!(max_queue > 0)` / `assert!(max_consumers > 0)` at authority.rs:54,145 (manual catch; pub constructor input) +- d2b-provider-audio-pipewire#7 sev=low blast=leaf effort=S verdict=actionable - the crate's error enums never chain sources: `AudioStateIoError`'s seven `io::Error` payloads and `AudioControllerError::Mediator(AudioMediatorError)` leave `Error::source()` returning `None`, flattening the chain into the Display message - fix: implement `std::error::Error::source()` for the payload variants (or move the crate to `thiserror` `#[source]`, which also removes the hand-written Display impls) - [src/state.rs:114-123, src/controller.rs:155-160] + evidence: seed `enum \w*Error` = 5 (all wire-code Display impls, no source()); AudioStateIoError variants hold io::Error without #[source]-equivalent, AudioControllerError::Mediator wraps AudioMediatorError without chaining + +## serde +- clean: seeds `derive)...Serialize` = 4, `serde)...)` = 6, `impl .*Deserialize.*for` = 0, `serde_json::from_|to_` = 0 in src (12 in tests); wire shapes are camelCase + deny_unknown_fields with `#[serde(skip)]` on `zone` (metadata, not spec) and `provider_extension` (signed-envelope only), all pinned by tests/resource_type.rs and tests/audio_policy.rs round-trips; no hand-written deserializers, no try_from needed (post-parse validate gates are the deliberate admission pattern) + +## obs +- clean: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 1 (the `use tracing::{debug, warn};` import at controller.rs:16, a seed false positive), `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 1; every event in controller.rs uses named fields (`zone`, `lease`, `channel`, `error`) with static messages, no interpolated messages, no secrets in fields, errors logged once at the mediation boundary + +## docs +- d2b-provider-audio-pipewire#8 sev=medium blast=leaf effort=S verdict=actionable - `AudioStateLock` is a pub struct with no doc comment at all (its module carries `#[allow(missing_docs)]`, lib.rs:9-10), and it is non-obvious: a caller must know holding the value keeps the OFD lock and dropping it releases it - fix: document the guard semantics (or remove the module-level allow and document the item) - [src/state.rs:81-84, src/lib.rs:9-10] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 85 hits; AudioStateLock (state.rs:81) is the only pub item with no doc comment +- d2b-provider-audio-pipewire#9 sev=medium blast=leaf effort=M verdict=actionable - none of the ~23 Result-returning public functions carries a `# Errors` section, and the failure conditions are non-obvious (LockOpen vs TempWrite vs AtomicRename on the state-I/O path; Admission vs Mediator on reconcile) - fix: add `# Errors` sections to `acquire/read/write_audio_state_*`, `child_resources`, `reconcile*`, `SpeakerMixer::set_grant/set_level`, `validate_audio_*` naming each failure variant - [src/state.rs:91, src/state.rs:148, src/state.rs:181, src/controller.rs:236, src/controller.rs:303, src/authority.rs:157] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 of 85 pub items; `-> Result<` = 23 hits, none documented with an Errors section +- d2b-provider-audio-pipewire#10 sev=low blast=leaf effort=S verdict=actionable - magic values lack the why: `AUDIO_REPAIR_INTERVAL_SECS = 300` says it is the repair interval but not why 300s, and the arbiter/mixer bound `64` in `AudioBindingController::new` is undocumented (and hardcoded again in tests/controller.rs:302-308) - fix: document the cadence rationale and hoist the 64 into a named const (e.g. `AUDIO_QUEUE_BOUND`) used by both the controller and the bound test - [src/controller.rs:21, src/controller.rs:209, src/controller.rs:212] + evidence: static read; no doc text explains either constant's derivation + +## perf +- clean: seeds `format!\(` = 1 src (state.rs:17 lock-path build, cold), `Vec::new\(\)|VecDeque::new\(\)|BTreeMap::new\(\)` = 3 src (empty-case constructors), `\.to_string\(\)` = 0 src; all hits are cold one-shot paths (state I/O, constructors), no allocation in any loop or reconcile hot path; static (unmeasured), no benchmark exists + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 1, `Atomic\w+|Ordering::` = 3 (all `AtomicRename` error-variant false positives), `thread_local!|unsafe impl (Send|Sync) for` = 0; the single shared-state site (Arc arbiter, authority.rs:44) is the justified multi-owner Service authority, reached only through non-blocking `try_lock` (U4 fail-closed), never held across awaits; no threads, no atomics, no manual Send/Sync claims + +## async +- clean: seeds `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 2 (the arbiter alias, authority.rs:44,48), `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the crate is fully synchronous; the tokio Mutex is deliberate (documented: no executor worker ever parks on it, authority.rs:40-44) and used only via try_lock; no guards across awaits, no spawned tasks, no cancellation surface + +## unsafe +- N/A (seeds: 0/0/2/0; the 2 seed-3 hits are `io::Error::from_raw_os_error` at state.rs:49,67 - a safe std function, not an unsafe block; no `unsafe` blocks/fns/impls, no SAFETY comments needed, manifest `unsafe_code = "forbid"` at Cargo.toml:14) + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface - libc/nix calls in state.rs are safe syscall wrappers, not a foreign boundary) + +## macro +- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros defined anywhere in the crate) + +## test +- d2b-provider-audio-pipewire#11 sev=low blast=leaf effort=S verdict=actionable - `SpeakerMixer::mix_level`'s saturation cap (sum capped at 100, authority.rs:236-241) has no boundary test: tests/authority.rs:26-31 asserts only 80+20=100, so a regression that removed the `min(100)` would pass - fix: add saturation rows (e.g. 80+80, 60+60+60) asserting the capped result - [tests/authority.rs:26-31, src/authority.rs:236-241] + evidence: seed `#\[test\]|#\[tokio::test\]` = 40 tests, assert mass = 174 seed hits; mix_level boundary rows absent from the only mixer test +- d2b-provider-audio-pipewire#12 sev=low blast=leaf effort=S verdict=actionable - tests/mediator.rs:13-24 is named `projection_cannot_open_pipewire_and_failed_set_preserves_state` but asserts only the Err and readiness; the state-preservation half of the claim is unasserted, so a regression that mutated grant/level on failure would pass - fix: assert `mediator.grant()`/`mediator.level()` unchanged after the failed set, or rename the test - [tests/mediator.rs:13-24] + evidence: test body asserts two `assert_eq!)... Err)...))` and one readiness check; no grant/level state assertions + +## supply +- d2b-provider-audio-pipewire#13 sev=low blast=leaf effort=S verdict=actionable - Cargo.toml declares `schemars` as a runtime dependency with zero uses in src or tests, and `serde_json` (tests-only, 12 hits) sits in `[dependencies]` instead of `[dev-dependencies]` - fix: drop the `schemars` entry and move `serde_json` to `[dev-dependencies]` (Cargo.toml:24-25) - [Cargo.toml:24, Cargo.toml:25] + evidence: census `schemars` over src/ + tests/ = 0 hits (manifest only); `serde_json` over src/ = 0, tests/ = 12 hits; per-crate supply note, lens owned by lane X1 + +## Coverage +- idiom: clean (seeds: 0/1/0; single deliberate Default) +- own: clean (seeds: 9/7/1/0 over src+tests; all clones explainable) +- type: 2 finding(s) +- api: 3 finding(s) +- err: 2 finding(s) +- serde: clean (seeds: 4/6/0/0; wire shapes pinned) +- obs: clean (seeds: 0/1/0/1; named-field events only) +- docs: 3 finding(s) +- perf: clean (seeds: 1/3/0; cold paths only) +- conc: clean (seeds: 0/1/3/0; 3 false positives, 1 justified shared arbiter) +- async: clean (seeds: 0/0/2/0; synchronous crate, try_lock-only) +- unsafe: N/A (seeds: 0/0/2/0; both hits are from_raw_os_error safe calls; manifest forbid) +- ffi: N/A (seeds: 0/0/0/0) +- macro: N/A (seeds: 0/0/0/0) +- test: 2 finding(s) +- supply: 1 finding(s) (directly evidenced manifest note; lens owned by X1) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md new file mode 100644 index 000000000..54d174826 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md @@ -0,0 +1,93 @@ +# d2b-provider-clipboard-wayland-p1 - d2b-provider-clipboard-wayland - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6771 (excl. src/generated/**) | modules: bin/d2b-clipd.rs, fd.rs, runtime.rs, audit.rs, policy.rs, lib.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/bin/**, src/fd.rs, src/runtime.rs, src/audit.rs, src/policy.rs, src/lib.rs + +## idiom +- d2b-provider-clipboard-wayland-p1#1 sev=medium blast=leaf effort=S verdict=actionable - d2b-clipd hand-rolls CLI flag parsing with a manual loop while every other binary in the repo uses clap derive - fix: replace parse_args with a clap::Parser derive on Args (clap is the house pattern in d2bd/src/main.rs, d2b/src/dispatch.rs, d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs), which also fixes --help exiting 2 via Err - [src/bin/d2b-clipd.rs:3815, src/bin/d2b-clipd.rs:127] + evidence: census: clap::{Parser,Args} over packages = 3+ binaries (d2bd/src/main.rs:3, d2b/src/dispatch.rs:21, d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs:23); seed `let mut \w+ = (String|Vec)::new\(\)` 12 hits, all legitimate byte/bounded loops +- d2b-provider-clipboard-wayland-p1#2 sev=low blast=leaf effort=S verdict=actionable - should_suppress_published_selection_echo takes two unused parameters and delegates to an identity wrapper that returns its argument unchanged - fix: return selection.suppress_selection_echo directly, drop the _window and _bridge_selection parameters and the two arguments at the call site, delete should_suppress_published_selection_echo_state - [src/bin/d2b-clipd.rs:3776, src/bin/d2b-clipd.rs:3787, src/bin/d2b-clipd.rs:2113] + evidence: static: wrapper body is `suppress_selection_echo` returned verbatim; census: both functions in-file only (def 3776/3787, call 2113, test 4022) = 4 hits over packages/ +- d2b-provider-clipboard-wayland-p1#3 sev=low blast=leaf effort=S verdict=actionable - install_bridge_listeners builds a Vec with a push loop where the body is a pure Result-producing map - fix: collect the iterator: bridge_peers.into_iter().map(|peer| { ... Ok(BridgeListener { ... }) }).collect::, String>>()? - [src/bin/d2b-clipd.rs:1131] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` 12 hits; site matches the statement-accumulation shape the seed names +- d2b-provider-clipboard-wayland-p1#14 sev=medium blast=leaf effort=S verdict=actionable - preferred_mime_order hardcodes the four MIME strings that policy.rs ALLOWED_MIME_TYPES already owns, keeping the reported MIME-policy triplication alive (row S79, reported not consolidated) - fix: iterate d2b_provider_clipboard_wayland::ALLOWED_MIME_TYPES in preferred_mime_order instead of the literal list, so allowlist changes propagate to the preference order - [src/bin/d2b-clipd.rs:2812, src/policy.rs:12] + evidence: census: the four MIME literals appear at policy.rs:12-17 (ALLOWED_MIME_TYPES), d2b-clipd.rs:2812-2816 (preferred_mime_order), and clipd_host policy (part 2 scope); row S79 at docs/explanation/over-engineering-audit-record.md:394 records the triplication as reported-not-consolidated, and the site still matches +- clean: seeds ran: `for \w+ in 0\.\.` 3 (bounded drain and tests), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` 1 (Policy Default preserves constructor invariants, deliberate), `let mut \w+ = (String|Vec)::new\(\)` 12 (byte reads and bounded loops); no other hand-written impls, naming drift, or conversion smells found + +## own +- clean: seeds ran: `\.clone\(\)` 75, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` 165, `Rc<|RefCell<|Arc with format!-built messages at 13 signatures, where the skill names anyhow for binaries - fix: introduce anyhow at the binary top level (run and its helpers), keeping the lib error enums unchanged - [src/bin/d2b-clipd.rs:127, src/bin/d2b-clipd.rs:411, src/bin/d2b-clipd.rs:247] + evidence: seed `enum \w*Error` 6 hits (lib enums ClipboardRuntimeError, FdSafetyError, FdReadError, ClipboardPolicyError are well-shaped); static: 13 `Result<..., String>` signatures in the binary; no caller string-matches these errors today, hence low +- clean: seeds ran: `\.unwrap\(\)|\.expect\(` 78 (77 test/startup, 1 finding above), `let _ = |\.ok\(\);` 32 (best-effort cleanups: cancel_picker, cancel_active, tx.send, remove_file; judged per site), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` 4 (all in tests), `enum \w*Error` 6 (lib enums split by caller action, Display is the pinned wire code) + +## serde +- d2b-provider-clipboard-wayland-p1#7 sev=medium blast=leaf effort=M verdict=actionable - the daemon config is parsed as serde_json::Value and read through hand-rolled .pointer() lookups with per-field error strings, instead of a typed Deserialize struct that validates at the boundary - fix: define a typed ClipdConfig with #[serde(deny_unknown_fields)] (picker.executable, runtime.bridgeEndpoints with try_from for WorkloadTarget::parse) and deserialize once in run(); the JSON shape is unchanged, so the Nix producer keeps working - [src/bin/d2b-clipd.rs:132, src/bin/d2b-clipd.rs:247] + evidence: seed `serde_json::from_|serde_json::to_` 8 hits; census: config shape produced by nixos-modules nix/site.nix:69-136 (bridgeEndpoints, picker.executable) and pinned by tests at d2b-clipd.rs:4346; the pointer plumbing spans 70+ lines (247-316) that a derive replaces +- clean: seeds ran: `derive\([^)]*(De)?[Ss]erialize` 3, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` 3, `impl .*Deserialize.*for` 0, `serde_json::from_|serde_json::to_` 8; BridgeFrame, BridgeAttribution, and ControlFrame are tagged enums with deny_unknown_fields and rename_all, and parse_bridge_frame validates identity and attribution after the parse (the correct admission-gate shape); no hand-written deserializers + +## obs +- d2b-provider-clipboard-wayland-p1#8 sev=medium blast=leaf effort=M verdict=actionable - the binary logs through the log facade with interpolated message strings (62 sites) while the crate's lib uses tracing with named fields, giving one crate two facades and unqueryable events - fix: migrate d2b-clipd.rs to tracing (already a dependency, used by runtime.rs) with named fields, e.g. log::info!("d2b-clipd: ready (config={}, ...)") becomes tracing::info!(config = %args.config.display(), bridge_root = %args.bridge_root.display(), "d2b-clipd ready") - [src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100] + evidence: seed `(info|debug|warn|error|trace)!\("` 40 hits (35 in the binary, 5 in runtime.rs); `tracing::|log::` 76 hits split 62 log:: in the binary vs 14 tracing:: in runtime.rs; `\.instrument\(|#\[instrument` 0, so no span carries the context the interpolated messages duplicate +- clean: seeds ran: `\bprintln!\(|\beprintln!\(` 2 (main's user-facing error path and check-config output, product output per the card), `(info|debug|warn|error|trace)!\("` 40 (runtime.rs events carry named fields, e.g. error = %e; the binary's 35 are the finding above), `\.instrument\(|#\[instrument` 0, `tracing::|log::` 76; no secret or clipboard payload is logged (module doc at d2b-clipd.rs:7 and redaction tests confirm), and AcceptDiagnostics::warn builds messages lazily in a closure + +## docs +- d2b-provider-clipboard-wayland-p1#9 sev=medium blast=leaf effort=M verdict=actionable - Result-returning public items carry no # Errors sections anywhere in the crate despite deny(missing_docs), so failure contracts (ConcurrentLimitExceeded, InvalidBounds, AuditQueueFull, SessionUnauthenticated) are undocumented - fix: add # Errors sections naming the variants to the public Result-returning items, starting with FdPermitPool::acquire, Policy::new, ClipboardAuditQueue::push, and ClipboardRuntime::admit_route - [src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97] + evidence: seed `-> Result<` 69 hits (31 bin, 13 fd, 19 runtime, 4 audit, 2 policy); `/// # (Examples|Errors|Panics|Safety)` 0 hits; first sentences are otherwise one-line and contract-shaped +- d2b-provider-clipboard-wayland-p1#10 sev=medium blast=family effort=S verdict=actionable - ClipboardAuditEvent::to_wire derives wire labels from Debug impls (format!("{:?}", event_type) lowercased and size_bucket via {:?}) instead of stable as_str labels, so a variant rename silently changes the cross-crate audit record consumed by d2bd - fix: add as_str() to ClipboardEventType and SizeBucket returning the exact current renderings ("pasteauthorized", "Lt1K", ...) and use them in to_wire - [src/audit.rs:172, src/audit.rs:174] + evidence: seed `format!\(` 77 hits; static: event_type and size_bucket render via Debug at audit.rs:174-178 while reason uses ClipboardReason::as_str; census: the wire record is consumed by d2bd/src/interaction_composition.rs:4701 and asserted in tests/provider_behavior.rs:88 and tests/redaction.rs:23 +- clean: seeds ran: `^\s*pub (fn|struct|enum|trait|const|type)` 99 (all documented, missing_docs denied at lib.rs:3), `/// # (Examples|Errors|Panics|Safety)` 0 (finding above), `-> Result<` 69 (finding above); module docs present in all five modules; no doctests marked ignore + +## perf +- d2b-provider-clipboard-wayland-p1#11 sev=low blast=leaf effort=M verdict=actionable - clipboard payload maps (up to MATERIALIZE_MAX_BYTES = 8 MiB) are cloned wholesale on the host-selection record, history materialization, and bridge-copy publish paths, copying every byte per paste - fix: hold payloads as Arc>> (or Arc<[u8]> per MIME) in ClipboardHistoryEntry, BridgeSelectionState, and PublishedSelectionState so materialization and publish become refcount bumps; the history-retention clones at 757 and 1043 disappear - [src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2b-clipd.rs:1838, src/bin/d2b-clipd.rs:2797] + evidence: static (unmeasured); seed `\.clone\(\)` 75 hits; the six full-map clones (757, 1043, 1833, 1838, 2797, 2803) copy the entire payload, bounded at 8 MiB per item by policy.rs:114 +- clean: seeds ran: `format!\(` 77 (error paths, one-shot diagnostics, and wire rendering, all cold), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 49 (bounded reads and empty-case collections), `\.to_string\(\)` 14 (boundary copies and Display-free labels); no format! in a loop over payload data, no attacker-controlled hashing, no collection-choice problems found + +## conc +- d2b-provider-clipboard-wayland-p1#12 sev=low blast=leaf effort=S verdict=actionable - the two permit counters use Acquire/AcqRel orderings where Relaxed is the weakest correct ordering, since neither counter publishes any data (the permit and descriptor ownership move by value) - fix: switch FdPermitPool.active and HELPER_THREADS to Ordering::Relaxed for load, CAS, and fetch_sub - [src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96] + evidence: seed `Atomic\w+|Ordering::` 24 hits (fd.rs 10, bin 14); static: no paired handoff through either counter, so the acquire/release pairs synchronize nothing +- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` 5 (named worker threads with mpsc handoff, the channel model the skill prefers), `\bMutex<|\bRwLock<` 2 (test-only serialization locks with documented reasons), `Atomic\w+|Ordering::` 24 (counters, finding above), `thread_local!|unsafe impl (Send|Sync) for` 0; no shared-state deadlock surface, no static mut + +## async +- N/A: seeds `async fn|async move|\.await` 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` 0, `tokio::sync::(Mutex|RwLock|Notify)` 0, `#\[tokio::(main|test)\]|Runtime::block_on` 0 over the scope; the binary is deliberately synchronous (poll loop plus worker threads, documented at d2b-clipd.rs:120-122) and the lib has no async fn, so the lens criteria fail + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0, `// SAFETY:` 0, `transmute|from_raw|MaybeUninit|mem::zeroed` 6 raw matches all false positives (from_raw_os_error at d2b-clipd.rs:2534 and FileType::from_raw_mode at fd.rs:242), `unsafe_code` 1 (the `#![forbid(unsafe_code)]` attribute at lib.rs:4, which per the card does not make the lens applicable); no unsafe blocks or unsafe_code allow manifests in the scope + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` 0, `catch_unwind` 0, `repr\(C\)|repr\(transparent\)` 0, `CStr|CString|c_char` 0 over the scope; the crate crosses no foreign boundary (rustix/nix syscall wrappers stay in their own crates) + +## macro +- N/A: seeds `macro_rules!` 0, `proc_macro|syn::|quote!` 0, `\$crate` 0, `to_compile_error|new_spanned` 0 over the scope; the crate defines no macros + +## test +- d2b-provider-clipboard-wayland-p1#13 sev=medium blast=leaf effort=S verdict=actionable - published_selection_echo_is_always_suppressed_once asserts the identity wrapper should_suppress_published_selection_echo_state, a forwarding pin that fails only if the wrapper's triviality changes - fix: delete the test together with the wrapper (idiom finding #2); the behavior it gestures at is already covered by bridge_selection_echo_suppression_persists_for_source_vm_or_unknown_focus - [src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787] + evidence: seed `#\[test\]|#\[tokio::test\]` 61 hits; `#\[ignore\]` 0; the test body asserts `should_suppress_published_selection_echo_state(true)` and `(false)`, i.e. the wrapper's forwarding, not observable behavior +- clean: seeds ran: `#\[test\]|#\[tokio::test\]` 61, `assert_eq!\(|assert_ne!\(|assert!\(` 139, `proptest!|insta::assert|rstest` 0, `#\[ignore\]` 0; the sampled tests assert observable behavior (frame parsing, fd queue limits, echo suppression, timeout and size-exceeded errors, umask restoration) with human-written expectations; error-code Display assertions in fd.rs:681 pin the wire codes recorded in docs/specs/providers/ADR-046-provider-clipboard-wayland.md:1091-1095, so they are contract pins, not implementation pins; tests/ is outside this part's partition (part 2 covers the remaining src modules) + +## Coverage +- idiom: 4 finding(s) +- own: clean (seeds ran: 75/165/0/0) +- type: 1 finding(s) +- api: clean (seeds ran: 99/0/8) +- err: 2 finding(s) +- serde: 1 finding(s) +- obs: 1 finding(s) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: 1 finding(s) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn, await, spawn, or tokio sync types in scope; binary is a sync poll loop by design) +- unsafe: N/A (seeds: 0/0/6-false-positive/1-forbid-attribute; no unsafe blocks, SAFETY comments, or unsafe_code allow manifests in scope) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros defined) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md new file mode 100644 index 000000000..61d6c5945 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md @@ -0,0 +1,106 @@ +# d2b-provider-clipboard-wayland-p2 - d2b-provider-clipboard-wayland - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6716 (excl. src/generated/**) | modules: clipd_host/**, service/mod.rs, history.rs, controller/mod.rs, picker.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f) + +## idiom +- d2b-provider-clipboard-wayland-p2#1 sev=medium blast=leaf effort=M verdict=actionable - MIME policy is duplicated in two modules with divergent semantics: clipd_host/policy.rs normalizes by splitting on ';' and carries a 7-entry secret-hint list, while crate::policy.rs normalizes by trim+lowercase only and carries a 3-entry list, so the same MIME string ("Text/Plain ; Charset=UTF-8") is admitted by the host Wayland path and rejected by the guest history path, and secret hints diverge (application/x-secret-service is a hint on the host side only) - fix: make crate::policy the single canonical MIME module and have clipd_host::policy delegate to it for ALLOWED_MIME_TYPES, SECRET_HINT_MIME_TYPES, and normalize_mime - [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:91-97, packages/d2b-provider-clipboard-wayland/src/policy.rs:3-14, packages/d2b-provider-clipboard-wayland/src/policy.rs:91-93] + evidence: manual cross-module read; both modules define ALLOWED_MIME_TYPES/SECRET_HINT_MIME_TYPES/normalize_mime; clipd_host/policy.rs:107 test pins "Text/Plain ; Charset=UTF-8" as allowed while crate::policy::normalize_mime keeps the space and rejects it; secret lists differ (7 vs 3 entries) +- d2b-provider-clipboard-wayland-p2#2 sev=low blast=leaf effort=S verdict=actionable - two distinct PickerError enums in one crate (crate::picker::PickerError for receipt minting and crate::clipd_host::picker::PickerError for the subprocess supervisor) share a name, which reads as one type in errors and imports - fix: rename the clipd_host one (e.g. PickerIpcError) or move the supervisor module under a distinct name - [packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:113-126] + evidence: seed `enum \w*Error` = 8 hits; two PickerError definitions at src/picker.rs:11 and src/clipd_host/picker.rs:113 +- d2b-provider-clipboard-wayland-p2#3 sev=low blast=leaf effort=S verdict=actionable - read_bounded_ndjson_line has two adjacent match arms with identical behavior (`Ok(0) if line.is_empty()` and `Ok(0)` both return NiriIpcError::Incomplete), a redundant guard that suggests a distinction that does not exist - fix: collapse to a single `Ok(0) => return Err(NiriIpcError::Incomplete)` arm - [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:144-146] + evidence: seed `for \w+ in 0\.\.` = 0; manual read of the match at niri.rs:143-158 +- d2b-provider-clipboard-wayland-p2#4 sev=low blast=leaf effort=S verdict=actionable - FallbackArming implements Default by hand for a single-field struct whose only field defaults to FallbackState::Idle; a derive would stay in sync with the enum - fix: `#[derive(Default)]` on FallbackArming plus `#[derive(Default)]` with `#[default]` on FallbackState::Idle, delete the impl - [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:5-12] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits (fallback.rs:40, framing.rs:15, service/mod.rs:1293); the other two are justified (nonzero defaults) +- d2b-provider-clipboard-wayland-p2#5 sev=low blast=leaf effort=S verdict=actionable - ReasonCode::as_str is a hand-written match that duplicates the `#[serde(rename_all = "snake_case")]` label mapping on the same enum, giving two sources of truth for the wire label that can drift - fix: derive the label once (e.g. a const table or serde serialization) and have as_str return it - [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:45-68] + evidence: seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 6 hits; as_str match at policy.rs:45-68 mirrors the rename_all at policy.rs:21 + +## own +- d2b-provider-clipboard-wayland-p2#6 sev=low blast=leaf effort=S verdict=actionable - finalize_selection clones pending.mimes into all_mimes only to compute has_secret before consuming the Vec by into_iter; the borrow of pending.mimes ends before the move, so the clone is avoidable - fix: compute `has_secret_hint(pending.mimes.iter().map(String::as_str))` first, then `pending.mimes.into_iter().filter(...)` - [packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263] + evidence: seed `\.clone\(\)` = 56 hits over the lane; wayland.rs:257 clone is followed by into_iter at wayland.rs:260 with no intervening mutation +- clean: seeds `\.clone\(\)` = 56, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 118, `Rc<|RefCell<|Arc but the body is an unconditional Ok, so the error arm and the map_err at ClipdHost::new (with its warn) are dead code that misleads callers into handling an impossible failure - fix: return Self from new and drop the map_err in ClipdHost::new - [packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:575-579] + evidence: seed `\.unwrap\(\)|\.expect\(` = 44 hits (40 in cfg(test), 4 justified production invariants); manual read of new body +- d2b-provider-clipboard-wayland-p2#12 sev=low blast=leaf effort=S verdict=actionable - PickerSupervisor collapses the typed FramingError into PickerError::Frame(String) via to_string() at six sites, so callers cannot distinguish FrameTooLong from Incomplete from a JSON error without string matching - fix: add a `Frame(FramingError)` variant (with #[from] or #[source]) and map the framing errors into it - [packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:274, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:284, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:290, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:320, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:325] + evidence: seed `let _ = |\.ok\(\);` = 4 hits (all deliberate: write! to a String, best-effort flush, best-effort audit push); manual read of the six Frame(String) construction sites +- clean: `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0; production unwrap/expect sites (service/mod.rs:138,171 after is_none_or checks; clipd_host/picker.rs:242,332 after explicit option checks) are justified invariants + +## serde +- d2b-provider-clipboard-wayland-p2#13 sev=low blast=leaf effort=S verdict=actionable - AuditEvent.mime_type carries `serialize_with = "serialize_bounded_mime"` but no deserialize_with, so the round trip is asymmetric: serialization truncates long MIME values at 64 bytes while deserialization accepts unbounded values, and the type still derives Deserialize - fix: add a matching deserialize_with (or drop Deserialize from AuditEvent if it is never read back) - [packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:43-49] + evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 29 hits; census: AuditEvent is only ever serialized (bin/d2b-clipd.rs:2030-2033), never deserialized +- clean: internal-tag enums with rename_all (protocol.rs:88-101) and deny_unknown_fields on client-to-daemon messages with deliberate tolerance on daemon-to-picker messages (pinned by tests protocol.rs:257-262, 264-295) match the card's per-type decision; NiriEvent's hand-written Deserialize is a live tolerant admission gate for niri's evolving JSON, not a finding + +## obs +- d2b-provider-clipboard-wayland-p2#14 sev=low blast=leaf effort=M verdict=actionable - clipd_host log events use interpolated messages instead of named fields (attribution, mime count, secret flag, error values are formatted into the message), so the events are not queryable by field - fix: convert to structured fields, e.g. log::debug!(quality = ?attribution.quality, mimes = allowed_mimes.len(), secret = has_secret, "host selection changed") - [packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:489, packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs:24, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:60, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:66, packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:552] + evidence: seed `(info|debug|warn|error|trace)!\("` = 7 hits, all interpolated with no named fields +- d2b-provider-clipboard-wayland-p2#15 sev=low blast=leaf effort=M verdict=actionable - the package mixes two logging facades: clipd_host (and the bin) emit via log:: while service/mod.rs emits via tracing::, so events from the two halves do not share spans or filters - fix: pick tracing for the whole package (tracing has a log bridge) and convert the clipd_host log:: calls - [packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:81, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:577] + evidence: seed `tracing::|log::` = 30 hits split across both facades; no #[instrument] or .instrument anywhere (seed 3 = 0) +- clean: `\bprintln!\(|\beprintln!\(` = 0 in the lane scope; no secret values are logged (host.rs:64-68 logs attribution quality and counts only); the ADR 0010/0028 redaction gate is not implicated + +## docs +- d2b-provider-clipboard-wayland-p2#16 sev=low blast=leaf effort=S verdict=actionable - ClipboardEntry::bytes is documented as "Return a bounded copy for an already-authorized materialization" but returns &[u8], contradicting the copy claim and the as_/to_/into_ cost convention - fix: reword to "Borrow the payload bytes for an already-authorized materialization" - [packages/d2b-provider-clipboard-wayland/src/history.rs:112-115] + evidence: seed `-> Result<` = 62 hits; manual read of the doc line +- d2b-provider-clipboard-wayland-p2#17 sev=low blast=leaf effort=M verdict=actionable - the clipd_host IPC and state surface is largely undocumented: niri.rs (read_bounded_ndjson_line, encode_niri_request, decode_niri_response, NiriStateCache methods, FocusedWindowProvider trait, HostClipboardAttributor methods), wayland.rs (DataControlOffer::destroy, DataControlSource::offer_mime), picker.rs (launch's returned &UnixStream borrow, poll_active's nonblocking contract, reap_expired, reap_terminated), host.rs (refresh_focused_window_snapshot) - fix: add doc comments stating the blocking/ownership contracts (which calls block, who destroys protocol objects, what the returned borrow is) - [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:128, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:162, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:336-337, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:424-427, packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:79-81, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:204-242, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:248-249] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 150 hits; `/// # (Examples|Errors|Panics|Safety)` = 0 hits; missing_docs is not enabled for the bin target that compiles clipd_host +- d2b-provider-clipboard-wayland-p2#18 sev=low blast=leaf effort=S verdict=actionable - magic constants lack the why: ENVELOPE_BYTES/JSON_STRING_ESCAPE_EXPANSION in the frame-budget math, PICKER_TERMINATE_GRACE (250ms), MAX_AUDIT_MIME_BYTES (64), DEFAULT_NIRI_MAX_LINE_BYTES (1 MiB) - fix: document the derivation or the upstream constraint each constant encodes - [packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:74, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:7] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 150 hits; manual read of the four constants + +## perf +- d2b-provider-clipboard-wayland-p2#19 sev=low blast=leaf effort=M verdict=actionable - read_bounded_ndjson_line reads one byte per read() syscall in a loop (up to DEFAULT_NIRI_MAX_LINE_BYTES = 1 MiB iterations for a maximal line), an avoidable syscall-per-byte pattern on the niri IPC path - fix: read into a stack chunk buffer (e.g. 4 KiB) with the same max-line accounting, or wrap the stream in a BufReader - [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159] + evidence: static (unmeasured); seed `format!\(` = 13 hits, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 21 hits; the loop at niri.rs:142-158 issues one read per byte +- clean: remaining format!/to_string sites are cold (error paths, per-operation digests, notification text, one-shot picker argv), and collection news are bounded structures or empty-case defaults + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 5, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; the thread hits are cfg(test) socketpair harnesses (niri.rs:602,632,663) and the sanctioned CLI-only paste-replay sleeps (virtual_keyboard.rs:83,89, each with a disallowed-methods allow, reason "CLI-only path"); no production locks, atomics, or manual Send/Sync claims exist in the lane + +## async +- N/A (seeds: `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the lane is entirely synchronous, per the crate's CLI-daemon design documented at clipd_host/picker.rs:88-90 and niri.rs:48-51) + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 1, `unsafe_code` = 0; the single hit is a safe rustix Pid::from_raw constructor at clipd_host/picker.rs:57, not an unsafe block; the crate lib.rs carries #![forbid(unsafe_code)] and no unsafe exceptions exist in this lane) + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface in the lane) + +## macro +- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the only macros in the lane are wayland_client's delegate_noop!/event_created_child! invocations, which are generated-protocol helpers, not local definitions) + +## test +- d2b-provider-clipboard-wayland-p2#20 sev=medium blast=leaf effort=M verdict=actionable - the history eviction contract has no test: insert's LRU count bound (max_history_entries via evict_oldest) and byte-quota eviction (max_total_bytes via evict_until) are untested, as are materialize's owner and TTL rejections and entry_expiry - fix: unit tests in history.rs asserting eviction order and quota behavior (e.g. insert max_history_entries+1 entries and assert the oldest is evicted; fill past max_total_bytes and assert eviction down to quota) - [packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clipboard-wayland/src/history.rs:345-356, packages/d2b-provider-clipboard-wayland/src/history.rs:257-273] + evidence: seed `#\[test\]|#\[tokio::test\]` = 73 hits (64 in src, 9 in tests/); tests/provider_behavior.rs:46-61 covers TTL expiry and purge but not eviction; insert/evict_until/evict_oldest have no test that exercises them +- d2b-provider-clipboard-wayland-p2#21 sev=medium blast=leaf effort=M verdict=actionable - the controller's route-to-evidence admission gates (DisplayDependencyEvidence::from_authenticated_route and from_committed_display_route) have no tests even though from_committed_display_route is consumed by d2bd as the display-dependency authority input; only dependency_status is tested - fix: unit tests in controller/mod.rs exercising valid and each rejected route shape (wrong provider, wrong service, wrong evidence class, zero generations, wrong subject type) - [packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:144-201, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:360-371] + evidence: seed `#\[test\]|#\[tokio::test\]` = 73 hits; census: from_committed_display_route consumed at packages/d2bd/src/interaction_composition.rs:2041; no test constructs or rejects DisplayDependencyEvidence from a route +- d2b-provider-clipboard-wayland-p2#22 sev=low blast=leaf effort=S verdict=actionable - FallbackArming::cancel_picker (the PickerCancelled transition) and NiriStateCache's WindowClosed and WorkspaceActivated event paths have no tests, leaving two state transitions and two event handlers unverified - fix: extend the existing table-style tests in fallback.rs and niri.rs with the missing transitions - [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:378-387, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:394] + evidence: seed `#\[test\]|#\[tokio::test\]` = 73 hits; fallback.rs tests cover capture/arm/focus/timeout/native-selection but not cancel_picker; niri.rs tests cover focus/window/workspaces but not WindowClosed or WorkspaceActivated +- clean: `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; assertions target behavior and error variants, not Display strings; the tests/ suite (223 LOC, 9 tests) covers config validation, redaction canaries, MIME policy, fd validation, and controller projections + +## Coverage +- idiom: 5 finding(s) +- own: 1 finding(s) +- type: 3 finding(s) +- api: 1 finding(s) +- err: 2 finding(s) +- serde: 1 finding(s) +- obs: 2 finding(s) +- docs: 3 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 5/0/0/0; threads only in cfg(test) harnesses plus the sanctioned CLI-only paste-replay sleeps with disallowed-methods allows) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn, .await, tokio, or spawn in the lane) +- unsafe: N/A (seeds: 0/0/1/0; the single hit is a safe rustix Pid::from_raw constructor, not an unsafe block; lib.rs forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero; only generated wayland_client helper invocations) +- test: 3 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md new file mode 100644 index 000000000..c54b6f0fb --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md @@ -0,0 +1,82 @@ +# d2b-provider-config-nixos - d2b-provider-config-nixos +Baseline: 6ebdd4cec | LOC audited: 1816 (src/ 1427, tests/ 389; excl. src/generated/**, none present) | modules: whole crate (lib, controller, service, ttrpc) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (whole crate) + +## idiom +- d2b-provider-config-nixos#1 sev=low blast=leaf effort=S verdict=actionable - the path-component rejection walk is written twice with identical rules, and the two copies can drift (one checks, one checks and collects) - fix: extract one helper classifying `Path::components()` into `Result, ConfigError>` (reject `CurDir`/`ParentDir`/`Prefix`) and call it from both `validate_reader_path` and `read_bounded_file` - [packages/d2b-provider-config-nixos/src/ttrpc.rs:379-386, packages/d2b-provider-config-nixos/src/ttrpc.rs:414-421] + evidence: seeds 0/0/1 (`let mut components = Vec::new()` at ttrpc.rs:414 plus the loop); both walks read in full +- clean: hand-written `Debug` impls (controller.rs:99-119, 120-131, ttrpc.rs:40-49, 160-164) redact secret fields and are the deliberate-derive-exclusion class; naming (`as_str`, `ALL`, no `get_`) is consistent; no index loops over `0..n` + +## own +- d2b-provider-config-nixos#2 sev=low blast=leaf effort=S verdict=actionable - `ConfigService::validate_operation` clones the whole JSON payload per request (`serde_json::from_value::(payload.clone())`, 6 arms) - up to `MAX_CONFIG_ENCODED_BYTES` (~683 KiB base64 limit) per Stage/ReadGuestConfig admission on the async polling worker, when `serde` can deserialize borrowed: `T::deserialize(payload)` works on `&serde_json::Value` - fix: replace the 6 `from_value(payload.clone())` calls with `T::deserialize(payload)` (or change the signature to take `Value` by value and clone once at the single call site) - [packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/controller.rs:304, packages/d2b-provider-config-nixos/src/controller.rs:311, packages/d2b-provider-config-nixos/src/controller.rs:318, packages/d2b-provider-config-nixos/src/controller.rs:325, packages/d2b-provider-config-nixos/src/controller.rs:331] + evidence: seed `\.clone\(\)` = 19 hits in src (6 here; the rest are guest_ref copies into owned responses and test fixtures, each explainable); `Arc` sharing (ttrpc.rs:126, 267, 315) is genuine multi-handler/worker ownership with the daemon caller at d2bd/src/composition.rs:4718 +- d2b-provider-config-nixos#3 sev=low blast=leaf effort=S verdict=actionable - `GuestConfigReader::dispatch` copies the just-validated document bytes (`document.bytes().to_vec()`, up to 512 KiB per guest read on the dedicated worker) only so `read_guest_config` can re-validate the already-valid `GuestConfigDocument` - fix: give `GuestConfigDocument` a consuming accessor (`into_bytes()` or `impl From for Vec`, `bytes` field stays private) and pass it straight into the `impl Into>` parameter - [packages/d2b-provider-config-nixos/src/ttrpc.rs:111, packages/d2b-provider-config-nixos/src/controller.rs:106] + evidence: seed `\.to_vec\(\)` = 1 prod hit; copy bound is static (MAX_CONFIG_BYTES = 512 KiB, service.rs:15) +- clean: `GUEST_CONFIG_IDENTIFIER.to_owned()` in 7 constructors, `guest_ref.clone()` into owned responses, `sha256.clone()` into the approval receipt, and the test fixture clones are each the cheapest correct ownership move; no `Rc`/`RefCell`/`Cow`/`Arc` in production code + +## type +- d2b-provider-config-nixos#4 sev=low blast=leaf effort=M verdict=actionable - stringly-typed request fields (`identifier`, `against`, `destination`) are re-validated at every entry (constructors, store methods, and `validate_operation`), and the duplicated guest-ref checks have already drifted: `ConfigSyncRequest::new` checks only the resource type while `validate_guest_ref` also requires a non-empty name, so "Guest/" passes the constructor yet fails the boundary - fix: parse-once request fields (private fields, `new()`/`try_from` as the only constructors, transparent serde keeps the wire JSON unchanged) so the per-entry `validate_*` calls collapse; align `ConfigSyncRequest::new` with `validate_guest_ref` - [packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixos/src/service.rs:300-306, packages/d2b-provider-config-nixos/src/service.rs:316-323, packages/d2b-provider-config-nixos/src/service.rs:326-336] + evidence: seed `fn validate_\w+` = 6 hits (validate_operation, validate_guest_ref, validate_identifier, validate_view_identifier, validate_destination, validate_reader_path), each with 2-3 call sites; `is_\w+: bool` and `(mode|kind|state): String` = 0; identifier stays a wire field (forward-compat token), no `needs-contract` claim + +## api +- d2b-provider-config-nixos#5 sev=low blast=wide effort=S verdict=actionable - `decode_document` (service.rs:296-298) is a public one-line forwarder duplicating the already-public `ConfigSyncResponse::document()`, giving two API paths for one operation - fix: drop the export and call `.document()` at the one live caller (d2bd/src/composition.rs:11585), or privatize `document()` and keep the named helper - [packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-nixos/src/lib.rs:22] + evidence: census: `decode_document` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 3 hits (lib.rs:22 re-export, service.rs:296 definition, composition.rs:11585 caller); `ConfigNixosClient` (composition.rs:11571), `GuestConfigReader` + `create_ttrpc_services` (composition.rs:4711-4720) and `ConfigStagingStore` (composition.rs:578, 29824) all have live daemon callers - per assignment, do not re-flag the policy status (provider_crate_policy.rs:21 lists config-nixos as non-provider-prefixed; finding 6 elsewhere owns it) +- clean: `Arc` in `create_ttrpc_services` is genuine shared ownership (6 method handlers + one dispatch worker share the backend; caller wraps `Arc::new` at composition.rs:4718); single-path re-export of the whole surface from lib.rs; no dependency types leak; `ConfigServiceBackend` is a one-required-method trait + +## err +- d2b-provider-config-nixos#6 sev=low blast=leaf effort=S verdict=actionable - `invalid_status()` maps client-side request-encoding failures to ttrpc `INVALID_ARGUMENT` plus the `config-document-encoding-failed` code, telling the caller their request was invalid when the client implementation failed to serialize - fix: map that site to `INTERNAL` (or reuse `rpc_error(ConfigError::EncodingFailed)`) so status class matches the code - [packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixos/src/ttrpc.rs:189] + evidence: seed `\.unwrap\(\)|\.expect\(` = 16 hits: 2 in production (ttrpc.rs:133, 194), both `expect("canonical config operation prefix")` on constant `ConfigOperation::as_str()` output (false-positive class); the rest are `#[cfg(test)]`; 1 `panic!` (ttrpc.rs:548, test); 2 `let _ =` (ttrpc.rs:282 deliberate panic-safe send documented inline, ttrpc.rs:493 test) +- clean: `ConfigError` is a 12-variant taxonomy split by caller action with stable `code()` strings, `Display` = code, and a clean `rpc_error` mapping (ttrpc.rs:360-376); codes are provider-local (no hits in docs/reference/error-codes.md or tests/golden/), so no wire contract is pinned + +## serde +- clean: seeds 10/20/0/11 (10 `derive)...Serialize...JsonSchema)` types, 20 `serde(rename_all/deny_unknown_fields)` attributes, 0 hand-written `Deserialize`, 11 `serde_json::from_/to_` sites). Every DTO is `rename_all = "camelCase"` + `deny_unknown_fields`, the derive-based admission gate at the RPC boundary is the deliberate pattern, bounds are re-applied after decode (`ConfigSyncResponse::document`, `ConfigStageRequest::document`), and round-trips are exercised via `validate_operation` in tests/service_contract.rs + +## obs +- clean: seeds 0/22/0/22 (0 `println!`/`eprintln!`, 22 tracing events, 0 `.instrument`, 22 `tracing::` uses). Every event uses named fields (`resource`, `operation`, `error`) under the consistent `config-nixos ...` scheme; the message-only `debug!` rejection events in `read_bounded_file` (ttrpc.rs:444-466) sit under the boundary `warn!` that carries `resource` (ttrpc.rs:99-102); no secret or path text reaches a field (redaction tested in tests/redaction.rs); errors are logged once at the handling boundary + +## docs +- d2b-provider-config-nixos#7 sev=low blast=leaf effort=S verdict=actionable - none of the ~14 public `Result`-returning APIs carry a `# Errors` section, so callers cannot learn which `ConfigError` variants each returns without reading the implementation (lib.rs:6 denies missing_docs but only the one-liners exist) - fix: add `# Errors` to `GuestSessionEvidence::new`, `GuestConfigDocument::new`, `ConfigSyncResponse::document`, `ConfigStageRequest::document`, the five `ConfigStagingStore` methods, `GuestConfigReader::new`, and the two `ConfigService` methods - [packages/d2b-provider-config-nixos/src/controller.rs:45-64, packages/d2b-provider-config-nixos/src/service.rs:359-475, packages/d2b-provider-config-nixos/src/ttrpc.rs:52-72] + evidence: seeds 63/0/14 (63 public items, 0 canonical `# Examples`/`# Errors`/`# Panics`/`# Safety` sections, 14 `-> Result<` items); all first sentences are one-line and strong, docs otherwise exemplary + +## perf +- d2b-provider-config-nixos#8 sev=low blast=leaf effort=M verdict=actionable - the RPC path parses the request JSON up to three times per call: handler `from_slice` (ttrpc.rs:326), `validate_operation` `from_value` plus the full-document base64 decode for Stage (controller.rs:298-331), and the backend dispatch `from_value` again (ttrpc.rs:81); Stage payloads can reach ~683 KiB base64 - fix: decode the typed request once in `ConfigMethod::handler`, validate the typed value, and pass the original `Value` to the backend hop (removes one parse and the admission-time document decode) - [packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/ttrpc.rs:326, packages/d2b-provider-config-nixos/src/ttrpc.rs:81] + evidence: static (unmeasured); seeds: `format!\(` = 4 prod sites (crate-constant service strings and the sha256 prefix, all required), `Vec::new()` = 1 (cold path), `.to_string()` = 0; `read_bounded_file` already uses `with_capacity` (ttrpc.rs:452) + +## conc +- clean: seeds 0/1/0/0 (1 `Mutex<` - the `std::sync::Mutex>>` inside the `#[cfg(test)]` `ParkingBackend` at ttrpc.rs:483, a sanctioned `cfg(test) helper` with the recorded allow; 0 atomics, 0 `thread_local!`). The one production thread (`thread::Builder` at ttrpc.rs:241-248) is the R4 dedicated bounded worker with the `disallowed_methods` allow citing "dedicated bounded worker per plan R4" and a bounded `sync_channel` queue - cited, not re-flagged (U1 constraint d.2/d.4) + +## async +- clean: seeds 7/1/0/1 (3 `async fn`, 4 `.await`, 1 `select!`, 1 `#[tokio::test]`). The blocking guest-config read is correctly hoisted off the polling worker: `try_send` admission, `oneshot` reply, full queue maps to `Unavailable` (never parks the executor, never grows threads), the dropped-sender path is `map_err`-handled (ttrpc.rs:266-312) - the sanctioned R4 pattern; the `current_thread` parked-dispatch test (ttrpc.rs:509-558) proves the actual hazard; no lock held across `.await` + +## unsafe +- clean: seeds 0/0/1/1 - no `unsafe` blocks, fns, impls, or `extern`; crate-level `#![forbid(unsafe_code)]` (lib.rs:8) and manifest `unsafe_code = "forbid"`; the single seed-3 hit is `rustix::fs::FileType::from_raw_mode` (ttrpc.rs:442), a safe constructor whose name merely contains "from_raw" - false positive; crate is not in the U1 (d) 8 exception list, consistent + +## ffi +- clean: N/A (seeds 0/0/0/0 - no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString`/`c_char`; the ttrpc service registration is in-process proto dispatch, not a C ABI boundary) + +## macro +- clean: N/A (seeds 0/0/0/0 - no `macro_rules!`, proc-macro machinery, `$crate`, or `to_compile_error`/`new_spanned`; no macro use that a function cannot serve) + +## test +- d2b-provider-config-nixos#9 sev=medium blast=leaf effort=S verdict=actionable - `ConfigSyncResponse::document()`'s integrity contract (forged `sha256`/`bytes` mismatch must fail `EncodingFailed`, over-bound `content_base64` must fail `InvalidRequest`) is untested, and the daemon depends on this exact decode path (d2bd/src/composition.rs:11585) - fix: add integration tests that literal-construct a `ConfigSyncResponse` (fields are pub) with a wrong digest, a wrong byte count, and an over-`MAX_CONFIG_ENCODED_BYTES` payload and assert the failure codes - [packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixos/tests/config_lifecycle.rs:8-18] + evidence: seeds `#\[test\]|#\[tokio::test\]` = 9 tests, `assert*` = 43; none touch the integrity branch of `document()` (read via full scan of tests/) +- d2b-provider-config-nixos#10 sev=low blast=leaf effort=S verdict=actionable - no test exercises the `deny_unknown_fields` admission (an extra JSON key must make `validate_operation` fail `InvalidRequest`) or a payload with wrong field types (serde error path), which is exactly the typo-key case the attribute exists for - fix: extend `operation_validation_enforces_closed_identifiers_and_semantic_bounds` (tests/service_contract.rs:41-79) with an unknown-field payload and a wrong-typed payload - [packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixos/tests/service_contract.rs:41-79] + evidence: seeds `assert*` = 43, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the existing rejection tests cover semantic values only (wrong guest type, wrong identifier, non-digest view) +- clean: the 9 tests cover happy read, stale-session fail-closed, staging lifecycle, idempotent approval retry, zone isolation, unauthorized callers, path rejection, hardlink rejection, redaction, bounds, and the closed method surface; the parked-dispatch test (ttrpc.rs:509-558) asserts the real executor hazard; expectations are human-written, no network, no clock, seeded determinism holds + +## Coverage +- idiom: 1 finding +- own: 2 findings +- type: 1 finding +- api: 1 finding +- err: 1 finding +- serde: clean (seeds ran: 10/20/0/11) +- obs: clean (seeds ran: 0/22/0/22) +- docs: 1 finding +- perf: 1 finding +- conc: clean (seeds ran: 0/1/0/0) +- async: clean (seeds ran: 7/1/0/1) +- unsafe: clean (seeds ran: 0/0/1-false-positive/1; only `from_raw_mode` name collision and the `forbid` attribute) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary exists - ttrpc registration is in-process) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions or proc-macro machinery) +- test: 2 findings \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md new file mode 100644 index 000000000..f66e062a5 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md @@ -0,0 +1,75 @@ +# d2b-provider-credential-entra - d2b-provider-credential-entra +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5,246 (src 2,655 + tests 2,591, excl. src/generated/**, none present) | modules: whole crate (lib.rs, controller.rs [audit.rs, telemetry.rs via #[path]], service.rs, main.rs; tests: common, canary, conformance, controller, delivery, entrypoint, faults, lifecycle, placement) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: single-part lane + +## idiom +- d2b-provider-credential-entra#1 sev=medium blast=family effort=M verdict=actionable - in-crate deadline trio (`operation_deadline`/`time_bound_instant`/`time_bounds_not_after`/`time_bound_instant_at`/`is_expired_unix_ms`) duplicates the toolkit's `credential::operation_deadline` with identical absolute-or-relative semantics; the family finding that folded this trio onto the toolkit was applied to secret-service but not here - fix: fold the trio onto `d2b_provider_toolkit::credential::{operation_deadline, deadline_remaining, now_unix_ms, is_absolute_unix_ms}` (keep the injectable-clock `time_bound_instant_at` only if the tests need it), deleting lib.rs:1164-1220 - [packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-entra/src/lib.rs:1172, packages/d2b-provider-credential-entra/src/lib.rs:1187, packages/d2b-provider-toolkit/src/credential.rs:111, docs/explanation/over-engineering-audit-record.md:872] + evidence: seeds 0/0/0; direct duplicate read at lib.rs:1164-1220 vs toolkit credential.rs:111-130; not-applied row U54 (over-engineering-audit-record.md:872) - site confirmed present at baseline +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the six hand-written `Debug` impls are secret-redacting (``) and deliberate, the hand-written `Display`/`Error` impls carry wire codes, and no index loops or statement-style accumulation exist + +## own +- clean: seeds `\.clone\(\)` = 31, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 11, `Rc<|RefCell<|Arc in Factory::new - genuine shared ownership; Pin> in the EntraFuture alias - required for the object-safe dyn client trait), seed 3 `pub use` = 1 (lib.rs:33, the house single-surface arm); all other pub items are consumed by main.rs, tests, or the toolkit runtime + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(` = 16 (every hit inside a `#[cfg(test)]` module - audit.rs:51, controller.rs:320-343, lib.rs:1363-1386, service.rs:786, telemetry.rs:50), `let _ = |\.ok\(\);` = 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 2 (EntraClientError, EntraProviderError - closed variants, Display strings are stable wire codes, mapped to CredentialServiceErrorCode in map_client_error); no panic site is reachable from caller input in src + +## serde +- N/A: seeds `derive\([^)]*(De)?[Ss]erialize` = 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 0; the crate crosses the wire only through `serde_json::json!` payload construction in GuestEntraClient (lib.rs:200-360) with no derives or deserializers of its own + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 35; every event uses named fields (`provider =`, `resource =`, `%error`, `operation =`) with lazy field expressions, errors are logged once at the mapping boundary (map_client_error lib.rs:1224), and no secret or identifier reaches a field (canary tests pin this) + +## docs +- d2b-provider-credential-entra#4 sev=low blast=leaf effort=S verdict=actionable - no public item carries a canonical `# Errors` section although ~30 pub items return `Result` (EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, reject_*); `#![deny(missing_docs)]` guarantees presence, not the failure contract - fix: add `# Errors` sections naming the returned error variant (e.g. InvalidConfig, InvalidPlacement, InvalidEndpoint, InvalidConsumer, DeadlineExceeded) to the Result-returning pub constructors - [packages/d2b-provider-credential-entra/src/controller.rs:47, packages/d2b-provider-credential-entra/src/lib.rs:502, packages/d2b-provider-credential-entra/src/lib.rs:565, packages/d2b-provider-credential-entra/src/lib.rs:1049] + evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 73 hits, seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits, seed 3 `-> Result<` = 30 hits; missing_docs is denied at lib.rs:7 so every pub item is documented, but zero canonical sections exist +- clean: module docs present on lib.rs, controller.rs, service.rs, audit.rs, telemetry.rs; pub-item docs are one-line contract sentences (no implementation narration, no design journals) + +## perf +- clean: seeds `format!\(` = 2 (both in `#[cfg(test)]` canary tests), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 3 (BTreeMap::new in construct lib.rs:875-877 - empty-case-common, bounded by MAX_LOCAL_LEASES), `\.to_string\(\)` = 0; no allocation site sits on a hot path; `to_canonical_string()` key computation is per-operation and bounded (static, unmeasured) + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 5 (four tokio::sync::Mutex maps + one std::sync::Mutex<()> mutation_gate), `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; the std Mutex is touched only via `try_lock` on the synchronous dispatch path (mutation_guard lib.rs:1152, no await), the tokio mutexes are async-aware, and the mutation-gate serialization is deliberate and test-pinned (concurrent_acquires_issue_once) + +## async +- clean: seeds `async fn|async move|\.await` = 101, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 4, `#\[tokio::(main|test)\]|Runtime::block_on` = 1 (tests/entrypoint.rs, with sanctioned allow); every client await is bounded by `tokio::time::timeout` via await_client (service.rs:742) or ensure_client_ready_async (service.rs:648), no guard is held across an await (statement-scoped locks), no blocking call sits in an async context, and cancellation ambiguity (uncommitted grants, Draining lifecycle) is deliberately designed and covered by faults.rs/lifecycle.rs + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; seed 4 `unsafe_code` = 1 is the `#![forbid(unsafe_code)]` attribute (lib.rs:8) which per the card does not make the lens applicable + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface exists in this crate + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros defined or used beyond std macros + +## test +- d2b-provider-credential-entra#5 sev=low blast=leaf effort=S verdict=actionable - `exact_consumer_guard_is_independent_of_request_fields` never exercises the guard its name claims: it only asserts that two `ResourceRef::parse` results differ, which can fail only if parsing collapses distinct inputs - fix: replace the body with an assertion on the actual guard (e.g. `provider.authorizes_consumer(&ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap())` true and a different Provider ref false), or delete the test - [packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-entra/src/lib.rs:1362] + evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 50 hits, seed 2 `assert_eq!\(|assert_ne!\(|assert!\(` = 176 hits, seed 3 `proptest!|insta::assert|rstest` = 0, seed 4 `#\[ignore\]` = 0; body read at lib.rs:1361-1366 +- clean: the remaining suite asserts behavior and error codes (never Display strings), is deterministic (FakeEntraClient with injected state, no network, real-thread concurrency test with wakers, deadline test with a never-completing client and recv_timeout), and includes canary tests pinning that secrets never reach any rendered surface + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: 31/11/0/0) +- type: clean (seeds ran: 2/0/0) +- api: 2 finding(s) +- err: clean (seeds ran: 16 all cfg(test)/0/0/2) +- serde: N/A (seeds: 0/0/0/0 all zero; no serde derives or deserializers, json! payload construction only) +- obs: clean (seeds ran: 0/0/0/35) +- docs: 1 finding(s) +- perf: clean (seeds ran: 2/3/0) +- conc: clean (seeds ran: 0/5/0/0) +- async: clean (seeds ran: 101/0/4/1) +- unsafe: N/A (seeds: 0/0/0 all zero; only the forbid(unsafe_code) attribute, which does not make the lens applicable) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md new file mode 100644 index 000000000..04ad8c095 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md @@ -0,0 +1,88 @@ +# d2b-provider-credential-managed-identity - d2b-provider-credential-managed-identity +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5439 (excl. src/generated/**: none) | modules: whole crate (agent, audit, controller, lib, service, telemetry; tests/*) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- clean: seeds ran: 0/0/0 (index loops, hand-written impl a derive may replace, statement-style accumulation); no hits; expression shapes all idiomatic. + +## own +- clean: seeds ran: 37/8/8/0; every clone/to_owned site read: Arcs clone only at `async move` boundaries to avoid borrowing self (lib.rs:210, lib.rs:251, lib.rs:280, lib.rs:309, lib.rs:338); owned constructs (checkpoint/lease/record building) genuinely need owned fields; restore_checkpoints clones the lease map wholesale to keep the original intact on early error (lib.rs:1344); no Cow; all explainable. + + + +## type +- d2b-provider-credential-managed-identity#1 sev=medium blast=leaf effort=S verdict=actionable - `ManagedIdentityTeardownPlan` exposes its three bools as pub fields, letting a caller construct invalid combos (`stop_agent && delete_agent`, `delete_agent && clear_provider_revoke` that `teardown_plan` never emits - fix: make the fields private with `pub const fn` accessors (or replace with an ordered stage enum); update the literal constructions in tests/binding.rs:1214-1234 - [controller.rs:85-89, tests/binding.rs:1214-1234] + evidence: static: seed 2 (`is_\w+: bool|\w+_flag: bool`) =0 but the pub bool triad at controller.rs:85-89 admits invalid states; literal constructions in tests/binding.rs:1214-1234 prove the surface constructible;`teardown_plan` (controller.rs:158-166)is the only in-crate producer and never emits them. + + + +## api +- d2b-provider-credential-managed-identity#2 sev=low blast=leaf effort=S verdict=actionable - `ManagedIdentityPlacement::in_zone` is an exact duplicate constructor of `new` with zero callers anywhere in the repo, doubling the public construction path - fix: delete `in_zone` (and its docs at lib.rs:611-618); `new` already validates and names the behavior - [lib.rs:612-618] + evidence: census: `in_zone\\(` over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel/*.bzl = definition-only (lib.rs:612); no caller; api seeds 86/0/2 (pub items/pub-internals-in-signatures/pub use; the pub use re-exports are the house single-surface pattern (lib.rs:40-45)). + +## err +- d2b-provider-credential-managed-identity#3 sev=low blast=leaf effort=S verdict=actionable - `export_checkpoints` panics via `.expect("lease map keys are validated Credential refs")` where every sibling invariant failure in the crate map_errs to `CredentialServiceErrorCode::InvariantFailure` - fix: replace with `.map_err(|_| invariant())?` (leveragingthe existing `invariant()` helper at lib.rs:1491) - [lib.rs:1261-1262] + evidence: err seed 1 (`\.unwrap\(\)|\.expect\(`) = 20 hits; 19 sit in `#[cfg(test)]`; 1 non-test hit: lib.rs:1262. + + + +## serde +- N/A (seeds: 0/0/0/0 all zero; the crate crosses the guest backend only by building `serde_json::json!` values, no serde-derived type, hand-written deserializer, or from_/to_ boundary sits here). + +## obs +- clean: seeds ran: 0/0/0/26 (tracing-presence); every tracing event carries named fields (`provider`, `resource`, `operation`, `state`, `%error`); no println, interpolated message-only event, or instrument site; library installs no subscriber. + + + + + +## docs +- d2b-provider-credential-managed-identity#4 sev=low blast=leaf effort=M verdict=actionable - Public `Result`-returning items document failures only in prose and carry no `# Errors` sections (e.g. `ManagedIdentityClientConfig::new`, `ManagedIdentityPlacement::new`, `ImdsEndpointAlias::parse`, `ManagedIdentityCredentialProviderFactory::new`, controller projections) - fix: add `# Errors` sections naming the specific `ManagedIdentityProviderError`/`CredentialServiceError`/`CredentialObservabilityError` variant each failure returns - [lib.rs:449, lib.rs:514, lib.rs:592, lib.rs:796, controller.rs:137, controller.rs:171, controller.rs:203, controller.rs:227] + evidence: docs seeds 86/0/43; seed 2 (`/// # (Examples|Errors|Panics|Safety)`)=0 while 43 pub items return `Result<`;`#![deny(missing_docs)]` (lib.rs:7) forces doc presence but not canonical sections. + +## perf +- clean: seeds ran: 3/2/0; all `format!` sites are test canaries (audit.rs:39, lib.rs:1531, telemetry.rs:34); `Vec::new` at construction and at the restore buffer (lib.rs:819, lib.rs:1283, both cold/empty-case-true); no to_string copies; no allocation in a hot path. + + + +## conc +- clean: seeds ran: 1/3/0/0; the sole thread hit is the `use std::thread` import for `poll_client_sync`'s park/unpark waker ( lib.rs:22); std `Mutex` is try_lock-only on synchronous surfaces (lib.rs:902, lib.rs:1094-1103)andthe `tokio::sync::Mutex` pairs guard state across awaits( lib.rs:901, lib.rs:903); no atomics, scoped/spawned threads,or manual Send/Sync. + + + +## async +- clean: seeds ran: ~50/0/4/0; all awaits occur with tokio-aware locks, no guard is held across an await (acquire/refresh/inspect re-acquire per section);`await_client` bounds every injected-client future with `tokio::time::timeout`( service.rs:566-577);`poll_client_sync` is the deliberate synchronous surface documented at lib.rs:1238-1245 (try_lock + park_timeout per plan U4; no spawn/select/runtime-in-library). + + + + + +## unsafe +- N/A (seeds: 0/0/0; seed4=1 only the `#![forbid(unsafe_code)]` attribute at lib.rs:8, which per the lens card doe not make the lens applicable). + +## ffi +- N/A (seeds: 0/0/0/0 all zero; nothing crosses a foreign caller). + +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules, proc-macro usage, or `$crate` paths). + +## test +- d2b-provider-credential-managed-identity#5 sev=low blast=leaf effort=S verdict=actionable - Table-driven loops assert without per-case failure messages, so the first failing case reports only a shared line number and not which case - fix: append `"method: {method:?}"` / `"binding: {binding:?}"` style messages to the `assert!`/`assert_eq!` calls in the method/route/placement matrices (mirroring the canary loops' messages at canary.rs:229-241) - [tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76] + evidence: test seeds ~52/~180/0/0; the three named loops are the only assertion-loops without per-case messages; the suite otherwise asserts behavior (binding subject matrices, canary redaction scans, fault-injection fakes, conformance fixtures) and has no proptest/insta/rstest or `#[ignore]` tests. + +## Coverage +- idiom: clean (seeds ran: 0/0/0 +- own: clean (seeds ran: 37/8/8/0 +- type: 1 finding(s) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: N/A (seeds: 0/0/0/0 all zero; no serde type boundary +- obs: clean (seeds ran: 0/0/0/26 +- docs: 1 finding(s) +- perf: clean (seeds ran: 3/2/0 +- conc: clean (seeds ran: 1/3/0/0 +- async: clean (seeds ran: ~50/0/4/0 +- unsafe: N/A (seeds: 0/0/0; seed4=1 only the forbid attribute +- ffi: N/A (seeds: 0/0/0/0 +- macro: N/A (seeds: 0/0/0/0 +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md new file mode 100644 index 000000000..2526570ca --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md @@ -0,0 +1,84 @@ +# d2b-provider-credential-secret-service - d2b-provider-credential-secret-service +Baseline: 6ebdd4cec | LOC audited: 6,699 (excl. src/generated/**, none present) | modules: lib.rs, service.rs, controller.rs, audit.rs, telemetry.rs, main.rs; tests: session.rs, lifecycle.rs, faults.rs, canary.rs, delivery.rs, conformance.rs, entrypoint.rs, placement.rs, common/mod.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-credential-secret-service#1 sev=low blast=leaf effort=S verdict=actionable - exported enum variant is misspelled `Userd` for `User` in the only supported owner classification, so every consumer must copy the typo - fix: rename `SecretServiceOwner::Userd` to `SecretServiceOwner::User` (and `owner()` return at lib.rs:1233); in-tree census shows no consumers to update - [packages/d2b-provider-credential-secret-service/src/lib.rs:446, packages/d2b-provider-credential-secret-service/src/lib.rs:1233] + evidence: census: `Userd` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 2 hits (definition + owner() return, both in-crate) +- clean: seeds ran: 0/0/0; no index loops (`for i in 0..`),no hand-written Default/From/PartialEq/Eq/Clone/Hash impls (the hand-written `Debug` impls deliberately redact via ``/`write_str`, where a derive would leak),no statement-style `let mut String/Vec::new()` accumulation; the only naming defect is the typo above + +## own +- clean: seeds ran: ~80/~4/0/0; every clone/is explainable one sentence: `Arc` clones feed `'static` port futures and shared port ownership (GuestCredentialBackend, `SessionAuthority` self-clone for capability ownership),owned field moves build injected port requests and Mutex/BTreeMap keys (`lease_key`, `user_ref`, `credential_ref`, idempotency),cfg(test) fixtures clone canary markers;`to_owned()` sites (`lib.rs:170,406,1618`) feed owned struct fields/opaque handles; no Rc/RefCell/Cow; the deadline-helper and env-scan triplication classes arerecorded refusals (refusal ledger U53: folded onto toolkit) and are not re-flagged +- evidence: seeds ran: ~80 (`.clone()` mostly cfg(test) module in lib.rs and test suites)/~4 (`.to_owned()/to_vec()/to_string()`)/0 (`Rc<|RefCell<|Arc` on the factory, where the value genuinely shares ownership (provider keeps it, tests and runtime construct different ports; call sites: lib.rs:171-178 factory construction, tests/common/mod.rs:187-188)`; no Arc/Rc/Box/RefCell leaks beyond it +- evidence: seeds: `\bpub (fn|struct|enum|trait|type|const|mod) ` ~62 hits, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 (Arc appears in fn args not `pub .* <` form), `^\s*pub use ` = 1 + +## err +- clean: seeds ran: ~50/~2/0/4; all unwrap/expect sites are in `#[cfg(test)]` module/tests (incl. `expect("plain-test admission runtime")` at lib.rs:1296); the four `*Error` enums split by caller action (port errors closed and mapped to wire codes, provider construction errors, crate-private SessionAuthorityError, crate-private SecretServicePollError)and are not wire-visible (wire error codes come from `d2b_core` via toolkit); no non-test panics in src; the deadline/env-scan helper structure already folded onto `d2b-provider-toolkit` (refusal ledger U53) - this crate delegates via `operation_deadline`/`deadline_remaining` and`reject_process_environment_credential_chain`, not re-flagged +- evidence: seeds: `\.unwrap\(\)|\.expect\(` ~50 (all test code), `let _ = |\.ok\(\);` ~2, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0 in src, `enum \w*Error` = 4 + +## serde +- N/A (seeds: 0/0/0/0; no serde derives/attrs/hand-written Deserialize impls and no `serde_json::from_/to_` in src; this crate crosses no serde boundary itself - wire shapes live in d2b-contracts-provider/toolkit, and the port only shapes `serde_json::json!` request payloads for `GuestCredentialBackend`; serde_json appears only in tests (canary.rs:150)) + +## obs +- d2b-provider-credential-secret-service#2 sev=medium blast=leaf effort=S verdict=actionable - session-close failure warn is message-only with no named fields, so a fleet cannot filter which provider/session close left unresolved leases - fix: add `provider = crate::PROVIDER_REF` and the two booleans (`unresolved_leases`, `unresolved_operations`)as fields to the `tracing::warn!` - [packages/d2b-provider-credential-secret-service/src/service.rs:860] + evidence: obs seed 2 (`(info|debug|warn|error|trace)!\(\("`): ~33 warn/error events, of which exactly 1 has no fields (service.rs:860; the other events carry provider/operation/user/resource/%error fields); seed1 `println!/eprintln!` = 0, seed3 instrument = 0, seed4 tracing:: =~33 +- clean: every other event uses named fields (`provider`, `operation`, `user`, `resource`, `state`, `%error`), never a secret (Debug impls redact, telemetry frames pass `validate_collector_fields` canary gate, redaction already gated by ADR 0010/0028 scanner `packages/xtask/src/diagnostic_redaction.rs`) + +## docs +- d2b-provider-credential-secret-service#3 sev=medium blast=leaf effort=M verdict=actionable - public Result-returning constructors/projections lack `# Errors` sections naming which condition yields which error (despite `#![deny(missing_docs)]` forcing presence, no canonical section exists anywhere in the crate) - fix: add `# Errors` to `SecretServiceConfig::new`, `SecretServicePlacement::new`, `SecretServiceCredentialProviderFactory::new`, `SecretServiceController::reconcile` (and the remaining pub Result items) naming `SecretServiceProviderError`/`CredentialServiceError` failures - [packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-credential-secret-service/src/lib.rs:610, packages/d2b-provider-credential-secret-service/src/lib.rs:1140, packages/d2b-provider-credential-secret-service/src/controller.rs:73] + evidence: docs seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 across src (no canonical sections),seed 3 (`-> Result<`) ~135 hits covering most pub methods/constructors returning Result +- d2b-provider-credential-secret-service#4 sev=low blast=leaf effort=S verdict=actionable - the one-second session-close revoke deadline is a bare magic `1_000` triplicated with no why (it bounds revoke of potentially many leases during disconnect/finalize/drain) - fix: extract `const SESSION_CLOSE_REVOKE_DEADLINE_MS: u64 = 1_000;` and document why (one-second cap so a stalled backend cannot hang session teardown foreve) - [packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-credential-secret-service/src/service.rs:674, packages/d2b-provider-credential-secret-service/src/service.rs:684] + evidence: census: `operation_deadline(1_000)` over src = 3 hits (service.rs:660,674,684; all three sync close paths) +- clean: `#![deny(missing_docs)]` is enabled and pub items carry doc'd first sentences; module docs present on lib/controller/service/audit/telemetry; the capability carries a `compile_fail` doctest (lib.rs:1088-1094), no `ignore`d doctests; the gaps flagged above are the canonical-section and magic-value state + +## perf +- clean: seeds ran: ~3/~9/~6;`format!` appears only in cfg(test) canary markers and test rendering (audit.rs:39, telemetry.rs:33, lib.rs:1999,2008),`Vec::new()` only in test double ports (lifecycle.rs:610,705) and cold one-time `BTreeMap::new()`/`BTreeSet::new()` in provider construction (lib.rs:1179-1187),`to_string()` at wire-rendering/test boundaries (canary.rs:146,148); no `format!` or grow-by-push allocation in any hot path; nothing further (static (unmeasured), no benchmark exists for these cold provider paths) +- evidence: seeds: `format!\(` ~3 non-test src (0), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` ~9 (all cold/test), `\.to_string\(\)` ~6 (wire-rendering boundaries/test fixtures) + +## conc +- clean: seeds ran: ~2/~8/~6/0; concurrency model is deliberate and workload-shaped: per-provider entry gates (`std::sync::Mutex` `mutation_gate` for sync surface, `tokio::sync::Mutex` `async_mutation_gate` for async dispatch),tokio::sync::Mutex-guarded BTreeMap/BTreeSet state for shared maps, atomics for counters (`next_counter` with Relaxed load + AcqRel CAS, `finalized` Acquire/Release pair;`NEXT_AUTHORITY_ID` process-unique static counter is a deliberate singleton - not flagged); no thread_local/static-mut/unsafe Send-Sync claims; sync-path `blocking_lock()` sites are documented sync-only (never executor workers), with inline reasons +- evidence: seeds: `std::thread::|thread::spawn|thread::scope` ~2 (src: thread::current/park_timeout poll loop, tests spawn), `\bMutex<|\bRwLock<` ~8 (src fields; RwLock 0), `Atomic\w+|Ordering::` ~6, `thread_local!|unsafe impl (Send|Sync) for` = 0 + +## async +- d2b-provider-credential-secret-service#5 sev=medium blast=leaf effort=S verdict=actionable - lock order between `sessions` and`user_sessions` is inverted across two branches of `authorize_session_for_user_locked` (first branch acquires `sessions` then awaits `user_sessions`; cached-key branch acquires `user_sessions` then awaits `sessions`), a latent tokio-Mutex deadlock that the outer `async_mutation_gate`/entry-timing currently masks - fix: acquire in one consistent order in both branches (`sessions` before `user_sessions`, e.g. in the cached-key branch scope the `user_sessions` guard chain and then lock `sessions`, or collapse the dual lookup into one map) - [packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-credential-secret-service/src/lib.rs:1341, packages/d2b-provider-credential-secret-service/src/lib.rs:1380] + evidence: async seed 2 (`tokio::sync::(Mutex|RwLock|Notify)`) ~9 hits; the two conflicting order edges are lib.rs:1323-1327 (sessions held across user_sessions await) and lib.rs:1341-1351 (user_sessions held across sessions await) +- clean: production async paths use `tokio::time::timeout` + deadline checks (`ensure_unlocked_async`, `await_port`), await-aware locks, and the port futures are cancellation-bookkept (CompletionUnknown/Deadline arms remember ambiguous operations before returning);`blocking_lock()` sites are sync-only with written reasons (cfg(test) helper, sync public surface, never executor workers);`Runtime::block_on` appears only in cfg(test) helper (lib.rs:1290-1297) with inline allow; no async-gate-allow markers needed +- evidence: seeds: `async fn|async move|\.await` ~100 hits, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0 in src, `tokio::sync::(Mutex|RwLock|Notify)` ~9,, `#\[tokio::(main|test)\]|Runtime::block_on` ~3 (cfg-test/current-thread test harness only) + +## unsafe +- N/A (seeds: 0/0/0/1; sole hit is the `#![forbid(unsafe_code)]` attribute at lib.rs:8; no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/mem::zeroed; safelens non-applicable per U1 card rule) + +## ffi +- N/A (seeds: 0/0/0/0; no extern "C"/no_mangle/link_section, catch_unwind, repr(C)/repr(transparent), or CStr/CString/c_char in src; no FFI boundary) + +## macro +- N/A (seeds: 0/0/0/0; no macro_rules! definitions, proc-macro/syn/quote, $crate, or to_compile_error/new_spanned uses; all macros used are std/tracing/serde_json built-ins) + +## test +- d2b-provider-credential-secret-service#6 sev=low blast=leaf effort=S verdict=actionable - table-driven loops assert without per-case failure messages (`locked_and_unavailable_map_to_provider_unavailable`, `only_user_agent_on_host_or_guest_is_accepted`, `collection_alias_accepts_spaces_and_rejects_unsafe_text`), so a failure reports only the line number and not which case failed - fix: add a `"case: {case:?}"`-style message to each loop assertion - [packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-credential-secret-service/tests/placement.rs:8, packages/d2b-provider-credential-secret-service/src/lib.rs:1966] + evidence: test seeds: `#\[test\]|#\[tokio::test\]` ~45, `assert_eq!\(|assert_ne!\(|assert!\(` ~130, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0;; three loops lack per-case messages +- clean: seeds ran: ~45/~130/0/0; suite covers lifecycle, idempotency, faults/mapping, deadlines (NeverPort, DelayedUnlockPort), concurrent admission/close fencing, redaction canaries (audit, telemetry, every rendered surface), entrypoint refusal, dynamic two-user scope, generation/binding/consumer refusal; no ignored tests, no network, seeded nonces via `std::process::id()` keep tests process-unique but deterministic; the per-case-message gap above is the only polish defect + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: ~80/~4/0/0; clones explained above; deadline/env-scan helpers are recorded refusals (U53), not re-flagged) +- type: clean (seeds ran: 2/0/0) +- api: clean(seeds ran: ~62/0/1) +- err: clean(seeds ran: ~50/~2/0/4; all panic sites test-only; error taxonomy split by caller action) +- serde: N/A(seeds: 0/0/0/0; no serde boundary in this crate itself) +- obs: 1 finding(s) +- docs: 2 finding(s) +- perf: clean(seeds ran: ~3/~9/~6; allocation sites cold/test-only) +- conc: clean(seeds ran: ~2/~8/~6/0) +- async: 1 finding(s) +- unsafe: N/A(seeds: 0/0/0/1; forbid attribute only) +- ffi: N/A(seeds: 0/0/0/0) +- macro: N/A(seeds: 0/0/0/0) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md new file mode 100644 index 000000000..7bbf1f2a8 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md @@ -0,0 +1,73 @@ +# d2b-provider-credential - d2b-provider-credential +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3322 (excl. src/generated/**, none present) | modules: whole crate (driver.rs, session.rs, effects_service.rs, facets.rs, test_support.rs, lib.rs; tests/registration.rs for the test lens) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- clean: seeds 1-3 (`for \w+ in 0\.\.`, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`, `let mut \w+ = (String|Vec)::new\(\)`) all 0 hits over src/; no index loops, no hand-written derives (the only manual impls are Debug redaction impls on CredentialRevocationRequest/Evidence and Display/Error impls, all deliberate), no statement-style accumulation. + +## own +- d2b-provider-credential#1 sev=low blast=leaf effort=S verdict=actionable - dead derives: `#[derive(Clone)]` on `CredentialDriver` and `#[derive(Default)]` on `RecordingRuntime` are never used by any call site - fix: drop `Clone` from `CredentialDriver` (driver.rs:342) and `Default` from `RecordingRuntime` (test_support.rs:178), keeping `RecordingRuntime::new` as the only constructor - [packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/test_support.rs:178] + evidence: seed `\.clone\(\)` = 61 hits, all explainable (owned returns, Arc clones at factory/effects boundaries, test-support recorders); census: `CredentialDriver` with `.clone()` over packages/ = 0 hits (d2bd uses only `CredentialDriverArgs`/`credential_descriptor`, resource_plane_v3.rs:2968); census: `RecordingRuntime::default` over packages/ = 0 hits (d2bd calls `RecordingRuntime::new`, resource_plane_v3.rs:3812, shared_provider_effects.rs:3361) +- clean: seeds 1-4 (`.clone\(\)` 61, `.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` 31, `Rc<|RefCell<|Arc`/`Arc` share genuine ownership across the composition root and factory); remaining Arc sites are test-support/test fixtures only. + +## type +- d2b-provider-credential#2 sev=low blast=leaf effort=M verdict=actionable - `CredentialDriverArgs.zone: String` (and the mirrored `CredentialDriver.zone: String`) carries a bare string where the daemon already holds a validated `ZoneId`, so the driver re-derives and re-parses the zone at use sites instead of receiving the invariant - fix: change `zone` to `d2b_contracts_resource::v3::ZoneId` in `CredentialDriverArgs` (driver.rs:295) and `CredentialDriver` (driver.rs:344); the daemon construction site drops `inputs.zone.as_str().to_owned()` and passes `inputs.zone` (resource_plane_v3.rs:2969, where `ConstructionInputs.zone: ZoneId` at resource_plane_v3.rs:1784); `agent_child` then builds `format!("Zone/{}", self.zone.as_str())` without the fallible `ResourceRef::parse` failure path (driver.rs:457-461); test fixtures switch to `ZoneId::parse("dev").unwrap()` - [packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-credential/src/driver.rs:457, packages/d2bd/src/resource_plane_v3.rs:2969] + evidence: seed `(mode|kind|state): String` = 0 hits (seed 2 `fn validate_\w+` matched only two test fn names, driver.rs:1314,1334); the zone string is validated nowhere until `agent_child`'s `ResourceRef::parse` (driver.rs:461), and never for the non-managed-identity providers whose rows skip that path; sibling family args structs (BindingDriverArgs/EndpointDriverArgs/VolumeDriverArgs, resource_plane_v3.rs:2956-2975) share the same String pattern (X3 candidate) +- clean: seeds 1-3 ran (2 hits total, both test fn names); no boolean flag soup, no Option-pair states, no stringly-typed state; `CredentialDriverStatus`/`CredentialRevocationOutcome`/`CredentialDriverErrorKind` are proper enums and `CredentialRevocationRequest` keeps its derived identity fields private behind accessors (session.rs:84-181). + +## api +- clean: seeds 1-3 (`\bpub (fn|struct|enum|trait|type|const|mod) ` 85, `pub .*\b(Arc|Rc|Box|RefCell)<` 5, `^\s*pub use ` 2) read against the full public surface; lib.rs re-exports are the single house surface (lib.rs:36-53), modules stay private, `CredentialDriverError` is a struct with a private kind (driver.rs:141), `Arc` in `CredentialEffectFacets.runtime` (facets.rs:54) and `Arc` from `credential_spec_decoder` (driver.rs:215) are deliberate shared-ownership/registry patterns with cited call sites (composition root resource_plane_v3.rs:3812, factory effects_service.rs:164, test doubles), and the test-support exports are feature-gated (lib.rs:33-34). + +## err +- clean: seeds 1-4 ran (`.unwrap\(\)|\.expect\(` 33, `let _ = |\.ok\(\);` 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` 4, `enum \w*Error` 1); every unwrap/expect/unreachable sits in `#[cfg(test)]` modules or the `test-support`-gated recorder (test_support.rs:140), no production panic site; `CredentialDriverError` is the struct-with-private-kind shape (driver.rs:141-170) with a `class()` split by caller action (Terminal vs Retryable, driver.rs:112-120), `CredentialResourceRuntimeError` has two variants callers match on (session.rs:29-47), and the Display strings are the documented old durable codes, not asserted as the contract anywhere outside deliberate tests. + +## serde +- clean: seeds 1-4 ran (derive 0, serde-attr 0, hand-written Deserialize 0, `serde_json::from_|serde_json::to_` 14); the crate derives no wire types (CredentialSpec/ResourceSpec come from the contracts crates), the spec decoder parses through the canonical `typed_spec_decoder` path (driver.rs:215-223), the inspect-credential payload is built through the canonical JSON object path (effects_service.rs:66-80), and `canonical_bytes` round-trips through `CanonicalJsonValue` (driver.rs:718-723). + +## obs +- clean: seeds 1-4 ran (`\bprintln!\(|\beprintln!\(` 0, interpolated `(info|debug|warn|error|trace)!\("` 0, `\.instrument\(|#\[instrument` 0, `tracing::` 2); the two production events (driver.rs:682, 692) are structured with named fields (`credential`, `outcome`, `session_generation`), carry no interpolated secrets (the redacted `operation_id` is deliberately not logged; Debug impls redact at session.rs:108-126, 253-265), and the error path logs once at the handling boundary. + +## docs +- d2b-provider-credential#3 sev=low blast=leaf effort=S verdict=actionable - the two Result-returning public items lack the canonical `# Errors` section: `CredentialRevocationRequest::new` states its failure condition only in prose (session.rs:128-131) and `CredentialSession::revoke_credential` documents no failure conditions at all (session.rs:273-274) - fix: add `# Errors` sections naming `CredentialResourceRuntimeError::InvalidResource` (zero/unknown session generation, zero rotation generation, foreign Provider) and the `Revocation` variant respectively - [packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/session.rs:275] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits across src/ while `-> Result<` = 9 hits; `#![deny(missing_docs)]` (lib.rs:29) keeps every pub item documented, so this is the canonical-section shape only +- clean: seeds 1-3 ran (pub items 102, canonical sections 0, `-> Result<` 9); module docs present in all six files, first sentences carry the contract, no `ignore`d doctests exist, and the crate is `#![deny(missing_docs)]` (lib.rs:29). + +## perf +- clean: seeds 1-3 ran (`format!\(` 12, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 8, `\.to_string\(\)` 31); all format!/Vec::new sites are cold paths (per-pass agent/credential ref derivation driver.rs:420,431,457, the durable operation-id preimage session.rs:188-200, error-path and test-recorder strings) with no loop bodies, and no collection is grown in a hot path; static (unmeasured). + +## conc +- d2b-provider-credential#4 sev=medium blast=leaf effort=S verdict=policy-confirmed - `parking_lot::Mutex` is used throughout the test-support recorder and test fixtures (test_support.rs:18,30,41-46,97-113,159,233-249; driver.rs:1053,1074-1075,1109-1172; session.rs:315,429) despite the recorded outright ban whose only exception is the R4 bounded-worker boundary, and the impl methods holding most `.lock()` calls carry no per-site `#[allow(clippy::disallowed_methods)]` even though the test fns do (`reason = "cfg(test) helper"`, the sanctioned form) - fix: switch the recorder locks to `tokio::sync::Mutex` per the clippy.toml replacement column, or record a test-support exception in the policy and add the sanctioned per-site allows to the impl methods; the `// async-gate-allow: test-support recorder lock` markers (30 sites, async-gate-inventory.json) are recorded exceptions and are not re-flagged - [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/src/test_support.rs:97, packages/d2b-provider-credential/src/driver.rs:1109, clippy.toml:40, clippy.toml:82] + evidence: seed `\bMutex<|\bRwLock<` = 12 hits, all in test-support/test context (production code holds no lock); census: blocking-census-baseline.json counts `parking_lot::Mutex::lock` = 0 for this crate (test context is excluded from the production ratchet); the same family-wide test-support pattern appears in d2b-provider-device, -endpoint, -guest, -network-local, -process, -usbip, -activation-nixos test_support modules (X3 candidate) +- clean: seeds 1-4 ran (`std::thread::|thread::spawn|thread::scope` 0, `\bMutex<|\bRwLock<` 12, `Atomic\w+|Ordering::` 2, `thread_local!|unsafe impl (Send|Sync) for` 0); production code uses no threads, locks, or atomics; the only atomics are a Relaxed test counter (session.rs:430,444) and all synchronization is test-only (card false positive), with the parking_lot choice flagged above. + +## async +- clean: seeds 1-4 ran (`async fn|async move|\.await` 137, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` 0, `tokio::sync::(Mutex|RwLock|Notify)` 0, `#\[tokio::(main|test)\]|Runtime::block_on` 21); no spawn/select/join in the crate, no guard held across an `.await` (the driver's revoke/reconcile awaits at driver.rs:647,669,860,887 hold no lock), no blocking call inside an async context, and every test-support recorder lock carries its recorded `// async-gate-allow` marker (30 sites in async-gate-inventory.json) - cited, not re-flagged. + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0, `// SAFETY:` 0, `transmute|from_raw|MaybeUninit|mem::zeroed` 0, `unsafe_code` 0; manifest `unsafe_code = "forbid"` with no exception sites - the (d)8 exception set does not include this crate). + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` 0, `catch_unwind` 0, `repr\(C\)|repr\(transparent\)` 0, `CStr|CString|c_char` 0; the crate crosses no foreign boundary). + +## macro +- N/A (seeds: `macro_rules!` 0, `proc_macro|syn::|quote!` 0, `\$crate` 0, `to_compile_error|new_spanned` 0; no macros defined). + +## test +- clean: seeds 1-4 ran over src/ + tests/ (`#\[test\]|#\[tokio::test\]` 29, `assert_eq!\(|assert_ne!\(|assert!\(` 128, `proptest!|insta::assert|rstest` 0, `#\[ignore\]` 0); the suite is behavior-focused (revocation-before-child-deletion ordering, fail-closed session binding, durable operation-id dedup, drift deletion, registration boundary), asserts error classes and status variants rather than implementation, is deterministic with no network/time dependence, and every test can fail (no tautologies, no `#[ignore]`, no golden pinning). + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: 1 finding(s) +- type: 1 finding(s) +- api: clean (seeds ran: 85/5/2) +- err: clean (seeds ran: 33/0/4/1) +- serde: clean (seeds ran: 0/0/0/14) +- obs: clean (seeds ran: 0/0/0/2) +- docs: 1 finding(s) +- perf: clean (seeds ran: 12/8/31) +- conc: 1 finding(s) +- async: clean (seeds ran: 137/0/0/21) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, manifest forbids) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test: clean (seeds ran: 29/128/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md new file mode 100644 index 000000000..902d9296f --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md @@ -0,0 +1,93 @@ +# d2b-provider-device-gpu - d2b-provider-device-gpu +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3758 (excl. src/generated/**; src/ = 3037, tests/ = 721) | modules: whole crate (authority, controller, effects, effects_service, facets, gpu_argv, process, settings, test_support, video_argv, vocabulary, workers) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) + +## idiom +- d2b-provider-device-gpu#1 sev=low blast=leaf effort=S verdict=actionable - rustfmt drift: the GpuAuthorityError enum is closed by an indented brace with a trailing-whitespace line inside code(), and a variant doc comment in GpuEffectError sits at column 0 - fix: normalize the three sites (cargo fmt --check class): authority.rs:401 -> `}`, authority.rs:411 empty, effects.rs:101 reindent `/// A worker closure...` - [packages/d2b-provider-device-gpu/src/authority.rs:401, packages/d2b-provider-device-gpu/src/authority.rs:411, packages/d2b-provider-device-gpu/src/effects.rs:101] + evidence: read of the three sites; seeds ran: `for \w+ in 0\.\.` = 0, `impl (Default|From|...) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 1; the repository `cargo fmt --check` class (card verify) flags these shapes. +- d2b-provider-device-gpu#2 sev=low blast=leaf effort=S verdict=actionable - `let _ = Self::declared_row_template)...)?` binds nothing while the `?` already propagates the error - fix: drop the binding: `Self::declared_row_template(&view, role)?;` - [packages/d2b-provider-device-gpu/src/effects_service.rs:193] + evidence: read; `let _ =` seed = 1 (effects_service.rs:193); the Ok value is unused and the `?` carries the Err, so the `let _ =` is redundant expression shape. +- d2b-provider-device-gpu#3 sev=low blast=leaf effort=M verdict=actionable - six opaque-token newtypes duplicate the same from_core / is_zero / as_bytes / redacting-Debug boilerplate with subtly differing surfaces - fix: extract a shared opaque-bytes shape (const-generic `OpaqueBytes` with per-type markers, or an in-crate `macro_rules! opaque_token`), keeping the deliberate per-type Debug redaction; the repo's `redacted_debug!`-class macro is the resident pattern to lean on - [packages/d2b-provider-device-gpu/src/authority.rs:17, packages/d2b-provider-device-gpu/src/authority.rs:44, packages/d2b-provider-device-gpu/src/authority.rs:66, packages/d2b-provider-device-gpu/src/authority.rs:265, packages/d2b-provider-device-gpu/src/effects.rs:14, packages/d2b-provider-device-gpu/src/effects.rs:66] + evidence: read; GpuBackingToken/PlatformToken/PrincipalToken (is_zero + from_core), GpuAuthorityLease (from_core + as_bytes), GpuEffectToken/LaunchTicket (from_core) plus a hand-written "" Debug each; U1 idiom card notes hand-written redacting Debug impls are deliberate (not flagged), the construction-boilerplate halves are not. +- clean: seeds ran (s1=0 index loops, s2=1 hand-written Default which is the invariant-preserving case at settings.rs:56, s3=1); no iterator-vs-index loop; naming discipline and From/derive conventions clean. + +## own +- d2b-provider-device-gpu#4 sev=low blast=leaf effort=S verdict=actionable - the started worker identity is cloned solely so validate_started_identity runs after the store - fix: validate `&identity` before `self.gpu_identity = Some(identity)` (same for video), storing on the failure branch first to preserve the test-pinned retain-for-finalize contract - [packages/d2b-provider-device-gpu/src/controller.rs:272, packages/d2b-provider-device-gpu/src/controller.rs:325] + evidence: `.clone()` seed = 22; both clones at controller.rs:272/325 exist to keep the value for the post-store validation; tests/authority_lifecycle.rs:198 (`lifecycle_rejects_worker_identity_and_finalizes_owned_process`) pins that the identity is retained on the WrongPrincipal failure path, so the reorder must keep that behavior; the rest of the clones (wire-rendering argv building, owned-token transfer into effect calls, lease restore-on-error at controller.rs:506) are each explainable in one sentence. +- clean: seeds ran (s1 .clone() = 22, s2 to_owned/to_vec/to_string = 23, s3 Arc share one genuine two-owner lease cache (driver + port). + +## type +- d2b-provider-device-gpu#5 sev=medium blast=leaf effort=S verdict=actionable - `video_started: bool` duplicates `video_identity.is_some()` and is read only by the Debug impl, so the pair can drift into an illegal state - fix: delete the field and use `video_identity.is_some()` in the `GpuController` Debug impl - [packages/d2b-provider-device-gpu/src/controller.rs:79, packages/d2b-provider-device-gpu/src/controller.rs:326, packages/d2b-provider-device-gpu/src/controller.rs:442, packages/d2b-provider-device-gpu/src/controller.rs:552] + evidence: census `video_started` over the crate = 6 sites (decl 79, init 113, writes 326/442, reset 515, read only at 552 in Debug); no behavioral read exists and the gpu side has no `gpu_started` twin, confirming the redundancy; found by full-file read (seed 2 `is_\w+: bool|\w+_flag: bool` = 0). +- clean: seeds ran (s1 validate_/check_ = 1 `validate_started_identity` at controller.rs:524 which is a parse-once-at-boundary check, s2 boolean flags = 0, s3 stringly-state = 0); `GpuSettings::validate` is arbitration-dependent runtime validation of a schema-mirroring wire type (U1 false-positive class, not flagged); `GpuPhase`/`GpuProcessRole`/`GpuProcessObservation`/`GpuReconcileOutcome` are well-modelled closed enums. + +## api +- d2b-provider-device-gpu#6 sev=low blast=leaf effort=S verdict=actionable - `pub mod gpu_argv`/`pub mod video_argv` expose a second public path for items already re-exported at the root, and the module paths have zero workspace callers - fix: make both modules private (`mod gpu_argv`/`mod video_argv`), keeping the lib.rs re-export arms so each item stays reachable by one path (the house single-surface pattern) - [packages/d2b-provider-device-gpu/src/lib.rs:12, packages/d2b-provider-device-gpu/src/lib.rs:15] + evidence: census `d2b_provider_device_gpu::(gpu_argv|video_argv)::` over packages/; nixos-modules/; tests/; docs/reference/; labs/; BUILD.bazel = 0 hits; the sibling `facets`/`vocabulary`/`effects_service` module paths ARE consumed (d2bd/src/resource_plane_v3.rs:2033, d2bd/src/shared_provider_effects.rs:2119, d2bd/src/shared_provider_effects.rs:1423) so those stay `pub`. +- d2b-provider-device-gpu#7 sev=low blast=leaf effort=M verdict=actionable - public `DeclaredWorkerGpuPortArgs` tunnels dependency types in pub fields (`Arc`, `Arc>>` over parking_lot, `tokio::runtime::Handle`, `&dyn SharedProviderChildSurface`) - fix: hide the field types behind crate-private accessors or accept a single crate-owned sidecar struct; publish=false so the semver cost is nil, but the surface leaks three dependency crates - [packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-device-gpu/src/effects_service.rs:467, packages/d2b-provider-device-gpu/src/effects_service.rs:469] + evidence: api seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 (facets.rs:29 runtime facet, effects_service.rs:465/467 args fields); the args struct is constructed at d2bd/src/shared_provider_effects.rs:2120 - the dependency-injection ladder rung for an internal provider crate. +- clean: seeds ran (s1 pub items = 124, s2 pub-arc = 2, s3 pub use arms = 11); the lib.rs re-export list is the house surface (U1 accepted pattern); `GpuController`/`GpuOwnerProof`/`GpuProcessIdentity` keep private fields with const accessors; `GpuLifecycleEffectPort`/`GpuRuntime` are small required surfaces; `adopt_lifecycle` has no production caller (census over packages/; nixos-modules/; tests/; docs/reference/; labs/ = 0, only tests/combined_reconcile.rs) but is a recorded kept item per U1 (d) 6 (policy-pinned test) - noted, not flagged. + +## err +- clean: seeds ran (s1 unwrap/expect = 14, s2 let _ = / .ok() = 1, s3 panic/unreachable/todo = 1, s4 enum Error = 7); every unwrap/expect is in tests or on a literally-built fixed-length conversion (effects_service.rs:206/337 `try_into().expect("fixed ...")` - the recorded false-positive class); the single `unreachable!` (workers.rs:28) is a sanctioned invariant panic (the role is derived from settings, Video unreachable by construction); `GpuEffectError::Transient` is genuinely retry-distinguishable; the error taxonomy is split by caller action with stable `code()` strings. + +## serde +- d2b-provider-device-gpu#8 sev=medium blast=leaf effort=S verdict=actionable - `GpuArgvInput` admits unknown JSON fields while its sibling `VideoArgvInput` denies them (and a test pins the rejection), an inconsistent admission policy for two daemon-side wire inputs - fix: add `deny_unknown_fields` to `GpuArgvInput` (and `GpuParams`/`GpuDisplayConfig` for full nested coverage), mirroring video_argv.rs:112; the only in-tree producer d2bd/src/process_provider_runtime.rs:3707 builds a Rust literal, so no producer sends unknown fields today - [packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/video_argv.rs:112, packages/d2b-provider-device-gpu/src/video_argv.rs:244] + evidence: serde seeds - s1 derive = 20, s2 serde attrs = 14, s3 impl Deserialize = 0, s4 serde_json = 4; GpuArgvInput carries only `rename_all = "camelCase"` while VideoArgvInput carries `deny_unknown_fields`; video's `rejects_unknown_extra_args_field` (video_argv.rs:244-253) pins rejection, the gpu side has no such gate or test. +- clean: seeds ran (s1=20, s2=14, s3=0, s4=4); `GpuSettings`/`DisplayConfig` deny unknown fields and `GpuSettings` uses struct-level `#[serde(default)]` (deliberate manifest defaults); the error enums use internal `tag = "kind"` representations; `serde_json::from_slice` on the declared row spec at effects_service.rs:129 is a boundary parse mapped to `SpawnRejected`; no hand-written `Deserialize` (no admission-gate refusal row implicated). + +## obs +- clean: seeds ran (s1 println/eprintln = 2 both in #[cfg(test)] snapshot helpers, s2 interpolated-message-with-no-fields = 0, s3 instrument = 0, s4 tracing = 14); every tracing event in controller.rs and effects_service.rs uses named fields (`device`, `role`, `error`, `reason`) with the device-uid not a secret; no secret/PII is ever rendered (all tokens carry redacting Debug and are never logged); error chains are logged once at the controller boundary that maps each failure. + +## docs +- d2b-provider-device-gpu#9 sev=medium blast=leaf effort=M verdict=actionable - no `# Errors` section on any pub `Result`-returning item despite the crate denying missing_docs, so the failure contract is undocumented - fix: add `# Errors` naming the failure branches to new_authorized/reconcile_lifecycle/adopt_lifecycle/finalize_lifecycle/validate/from_core/generate_gpu_argv/generate_video_argv/GpuWorkerSpec::gpu/VideoWorkerSpec::new/GpuProcessDeclaration::new/select_processes/gpu_process_name/GpuOwnerProof::new/GpuAuthorityAdmission::new/with_video_principal - [packages/d2b-provider-device-gpu/src/controller.rs:172, packages/d2b-provider-device-gpu/src/settings.rs:78, packages/d2b-provider-device-gpu/src/gpu_argv.rs:158] + evidence: docs seeds - s1 pub items = 124, s2 canonical sections (`/// # (Examples|Errors|Panics|Safety)`) = 0, s3 `-> Result<` = 27; the failure conditions are non-obvious (e.g. the arbitration/render-node/max-holders matrix in GpuSettings::validate and the arbitration-dependent GpuAuthorityAdmission::new rejections); first sentences and module docs are otherwise strong. +- d2b-provider-device-gpu#10 sev=low blast=leaf effort=S verdict=actionable - module-level `#![allow(missing_docs)]` in the two argv modules overrides the crate-wide deny, leaving the pub `as_str` methods undocumented - fix: drop both allows and add doc comments to `GpuContextType::as_str` and `VideoBackend::as_str` - [packages/d2b-provider-device-gpu/src/gpu_argv.rs:24, packages/d2b-provider-device-gpu/src/video_argv.rs:22, packages/d2b-provider-device-gpu/src/gpu_argv.rs:40, packages/d2b-provider-device-gpu/src/video_argv.rs:103] + evidence: read; `#![deny(missing_docs)]` at lib.rs:5 vs `#![allow(missing_docs)]` at gpu_argv.rs:24 and video_argv.rs:22; the only undocumented pub items in those modules are the two `as_str` methods (all fields/structs/enums are otherwise documented). +- clean: seeds ran (s1=124, s2=0, s3=27); every module carries a `//!` doc; the wire-contract pin constants in video_argv.rs document the magic values with the patch citation (the skill's magic-value rule is followed). + +## perf +- clean: seeds ran (s1 format! = 6, s2 Vec/VecDeque/HashMap/BTreeMap::new = 3, s3 to_string = 23); all `format!` sites are cold one-shot paths (argv render gpu_argv.rs:151, process-name derive process.rs:121, worker-ref build effects_service.rs:149, wire snapshot video_argv.rs:81) and each has a written rationale (byte-stable JSON order, closed injection surface); `Vec::new()` at controller.rs:376 is a cold adoption loop; no loop-internal allocation, no attacker-keyed hashing; static (unmeasured) - no benchmarks exist for this crate. + +## conc +- d2b-provider-device-gpu#11 sev=medium blast=family effort=S verdict=policy-confirmed - `parking_lot::Mutex::lock` on the shared `gpu_authority_leases` cache is off the KD3 exception list (only the R4 bounded-worker boundary is exempt) and carries no per-site `#[allow(clippy::disallowed_methods)]` unlike the same file's drive_sync - fix: add the sanctioned per-site allow `reason = "synchronous path"` at the three lock sites (or record the site in the provider-crate-policy exception list); the clippy.toml:82 replacement (`tokio::sync::Mutex`) is wrong on this pure-synchronous path - [packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-gpu/src/effects_service.rs:310, packages/d2b-provider-device-gpu/src/effects_service.rs:445, packages/d2b-provider-device-gpu/src/effects_service.rs:454] + evidence: conc seed 2 `\bMutex<` = 2 (effects_service.rs:79 field, 467 args field) with `.lock()` calls at 310/445/454; the crate's blocking-census baseline records `parking_lot::Mutex::lock: 0` (packages/xtask/data/blocking-census-baseline.json) so the site is above the recorded baseline and off the per-site allow ledger; clippy.toml:40-43 (KD3: banned except R4) and clippy.toml:82 list the ban and the tokio replacement; the same cache type is declared by d2b-provider-device/src/driver.rs:139-143 (family-shared construction contract), so the fix must be coordinated family-wide. +- clean: seeds ran (s1 threads = 0, s2 Mutex/RwLock = 2, s3 atomics/Ordering = 0, s4 thread_local/unsafe Send+Sync = 0); the single lock is a short critical section, never held across an await, and the shared-ownership justification is written in the port doc (operations are the family's sole cross-owner state). + +## async +- clean: N/A - seeds ran (s1 async fn/.await = 0, s2 tokio::spawn/JoinSet/select/join = 0, s3 tokio::sync::{Mutex,RwLock,Notify} = 0, s4 #[tokio::(main,test)]/block_on = 0, all zero); the crate's sync `GpuLifecycleEffectPort` boundary deliberately drives its async child-surface work through `drive_sync` (block_in_place + block_on on the daemon-captured handle, effects_service.rs:44-46) under the sanctioned `reason = "synchronous path"` allow - noted, not flagged per U1 (d) 4. + +## unsafe +- clean: N/A - seeds ran (s1 unsafe blocks/fns/impls = 0, s2 `// SAFETY:` = 0, s3 transmute/from_raw/MaybeUninit/zeroed = 0, s4 `unsafe_code` = 2); both seed-4 hits are the word `unsafe_code` in module doc prose (gpu_argv.rs:23, video_argv.rs:21) - the card's doc-comment-prose false-positive class; the manifest carries `[lints.rust] unsafe_code = "forbid"` (Cargo.toml:9), so the lens is not applicable. + +## ffi +- clean: N/A - seeds ran (s1 extern "C"/no_mangle/link_section = 0, s2 catch_unwind = 0, s3 repr(C)/repr(transparent) = 0, s4 CStr/CString/c_char = 0, all zero); no foreign-calling surface, no `unsafe extern` declarations, no edition-2024 FFI forms in this crate. + +## macro +- clean: N/A - seeds ran (s1 macro_rules! = 0, s2 proc_macro/syn/quote = 0, s3 $crate = 0, s4 to_compile_error/new_spanned = 0, all zero); no user macros or proc-macro surface in this crate (the six-token boilerplate at idiom#3 could adopt a macro, but no macro exists today). + +## test +- d2b-provider-device-gpu#12 sev=medium blast=leaf effort=S verdict=actionable - `GpuAuthorityAdmission::new`'s arbitration/render-node/max-holders matrix (`ArbitrationViolation`) and zero-token rejections (`StaleDeviceIdentity`) have no direct test even though they are the authority admission gate - fix: add table-driven rejection vectors over `GpuAuthorityAdmission::new` asserting the typed `GpuAuthorityError` variant for each illegal combination, mirroring the `admission()` fixture shape in tests/authority_lifecycle.rs - [packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/tests/authority_lifecycle.rs:245, packages/d2b-provider-device-gpu/tests/combined_reconcile.rs:238] + evidence: test seeds - s1 `#\[test\]` = 33 (17 in src, 16 in tests/), s2 asserts = 120, s3 proptest/insta/rstest = 0, s4 `#\[ignore\]` = 0; `GpuAuthorityError::` appears in tests only as `PrincipalNotSeparated` (authority_lifecycle.rs:246) and the effect-level `StaleDeviceIdentity` path (combined_reconcile.rs:239); no test constructs an invalid `GpuAuthorityAdmission` to exercise `new()`'s own gate branches - contract behavior with no test. +- clean: seeds ran (s1=33, s2=120, s3=0, s4=0); the suite is behavior-focused: tests assert typed error variants, never `Display` strings; golden byte-compares pin the argv/wire shapes (`include_str!` goldens under tests/golden/runner-shape/); rejection vectors are table-driven with per-case failure messages; lifecycle and adoption transitions, phase gating, and the config validation matrix are all covered; deterministic (no clock/network/randomness); the observed `expect`/`unwrap` in tests are fixture-construction asserts. + +## Coverage +- idiom: 3 finding(s) +- own: 1 finding(s) +- type: 1 finding(s) +- api: 2 finding(s) +- err: clean (seeds ran: 14/1/1/7) +- serde: 1 finding(s) +- obs: clean (seeds ran: 2/0/0/14) +- docs: 2 finding(s) +- perf: clean (seeds ran: 6/3/23) +- conc: 1 finding(s) +- async: N/A (seeds 0/0/0/0 all zero; no async fn/.await/tokio spawn; the sync-port drive_sync boundary is a sanctioned "synchronous path" allow) +- unsafe: N/A (seeds 1-3 0/0/0; seed 4 `unsafe_code` = 2 doc-prose words only; manifest forbids) +- ffi: N/A (seeds 0/0/0/0 all zero) +- macro: N/A (seeds 0/0/0/0 all zero) +- test: 1 finding(s) + +## Supply note (workspace lens X1 owns the full audit; U1 (e) directly-evidenced crate-manifest note) +- d2b-provider-device-gpu#13 sev=low blast=leaf effort=S verdict=actionable - manifest dependencies `async-trait` and `d2b-resource-types` appear nowhere in the crate's src/+tests/ - fix: drop both from Cargo.toml (and the mirrored Bazel deps) or justify their retention in the manifest - [packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.toml:25] + evidence: census `async_trait|d2b_resource_types` over src/+tests/ = 0 matches (the BUILD.bazel references at :39/:55 merely mirror the manifest deps); tagged supply per U1 (e) directly-evidenced unused-dependency note; the workspace-level supply audit is lane X1's. diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md new file mode 100644 index 000000000..5e291df36 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md @@ -0,0 +1,82 @@ +# d2b-provider-device-security-key - d2b-provider-device-security-key +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4232 (excl. src/generated/**; src 3853 + tests 379) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- d2b-provider-device-security-key#1 sev=low blast=leaf effort=S verdict=actionable - `declared_dependency_refs` accumulates through a `let mut refs = Vec::new()` plus a push closure instead of an iterator chain, the one statement-style accumulation in the crate - fix: collect the two `Option` probes with an iterator chain (`[a, b].into_iter().flatten().collect()`) and delete the closure - [packages/d2b-provider-device-security-key/src/driver.rs:380-390] + evidence: seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (driver.rs:380); seeds 1-2 = 0 +- clean: seeds ran: 0/0/1 - no index loops, no hand-written derive-replaceable impls (all Debug impls redact secrets, deliberate per repo false-positive list), one accumulation site flagged above + +## own +- clean: seeds ran: 37/30/0/0 - every clone inspected: owned-arg clones into the contracts `explicit_binding_children` helper (controller.rs:224-266), `metadata.clone()` reuse for the second ChildEnsure (driver.rs:494), thread-boundary `vm_id`/Arc clones (relay_service.rs:402,440-442), lease holder/admission clones that must outlive the borrow (lease.rs:121-122,171,194,276-277), test-fixture clones; no Rc/RefCell/Arc/Cow anywhere +- clean: `test_support.rs:32` `self.calls.lock().clone()` returns a snapshot from a Mutex guard - the standard pattern for a recording double, not a borrow-checker workaround + +## type +- clean: seeds ran: 0/1/0 - the single hit `watched_configuration_is_dependency: bool` (controller.rs:83) is one runner-contract knob mirroring the shared-Runner cutover, not flag soup; lease state is a closed `LeaseState` enum with transition checks, and `backing`/`authorized_*` Option pairs are enforced by the state machine at every use site (`.ok_or(AuthorizationDenied)`), so typestate would not buy a real bug class + +## api +- d2b-provider-device-security-key#2 sev=low blast=leaf effort=S verdict=actionable - `pub mod relay` and `pub mod relay_service` (lib.rs:16-17) expose a second path for every root-re-exported item, while `facets`/`effects_service`/`test_support` module paths are the ones the daemon actually consumes - fix: make `relay` and `relay_service` private modules, keep the lib.rs `pub use` arms as the single surface (house pattern) - [packages/d2b-provider-device-security-key/src/lib.rs:16-17, packages/d2b-provider-device-security-key/src/lib.rs:45-55] + evidence: census `device_security_key::relay::` over packages/nixos-modules/tests/docs/reference/labs = 1 hit (a doc comment in d2b-broker/src/ops/security_key.rs:8); `device_security_key::relay_service::` = 0; `::facets::`/`::effects_service::`/`::test_support::` = 16 hits in d2bd (resource_plane_v3.rs:1875,2019,2263,3786,3948; shared_provider_effects.rs:2704,3500) +- clean: seed 2 `pub .*Arc<` = 2 hits, both genuine shared ownership with cited consumers: `SecurityKeyEffectFacets.runtime: Arc` (facets.rs:34) is constructed field-by-field by d2bd (resource_plane_v3.rs:2019-2023) and `SkAcceptHandle.state: Arc>` (relay_service.rs:297) is shared across the accept thread and connection tasks; the relay hosting exports have no external callers but are dossier-pinned (ADR-046 D046, docs/specs/ADR-046-decision-register.md:68; prior audit row U60 "No dead surface beyond dossier-pinned relay") - not flagged +- clean: seed 3 `pub use` = 8 arms, the house single-surface pattern; the crate root `#![deny(missing_docs)]` (lib.rs:6) plus per-item docs give a deliberate, documented surface + +## err +- clean: seeds ran: 70/5/6/5 - production unwrap/expect reduced to the canonical-const class (controller.rs:228,265 `ResourceRef::parse)...).expect("... is canonical")` on a literal; repo false positive); all other hits are `#[cfg(test)]`/`tests/` fixtures; `let _ =` sites are deliberate best-effort (oneshot notify relay_service.rs:282, aborted-task awaits 587/589, cancel packet 596); panics only in test doubles (exact_authority.rs:22, mutual_exclusion.rs:22); the five error enums are closed, split by caller action, and carry stable `code()` wire strings with per-variant docs +- clean: error context survives via the boundary that handles it: `SecurityKeyControllerError::Admission` (controller.rs:123) collapses binding-child detail into a stable code, but the inner error is logged with named fields at the same site (controller.rs:232-235) - deliberate closed-code design, not a swallowed failure + +## serde +- clean: seeds ran: 0/0/0/9 - no derive/attribute/manual-impl surface; all JSON crossing is untyped `serde_json::Value`/`to_vec` with `map_err(|_| invalid())` mapped to `SharedProviderDeclarationError::SpecInvalid` (driver.rs:437-528, effects_service.rs:59); the `binding_child_ensure` Value round-trip (driver.rs:514-517) extracts a known shape from an in-tree trusted payload, not untrusted wire input - no typed boundary to judge + +## obs +- clean: seeds ran: 0/0/0/31 - zero println/eprintln, zero interpolated-message events, zero instrument spans; all 31 tracing events carry named fields (device, error, reason, vm, selector) with the message as the final literal; no secret material in any field (device UIDs and VM ids are identity, not secrets; selector_label is a stable label); redaction is enforced structurally by hand-written Debug impls and pinned by tests/redaction.rs + +## docs +- d2b-provider-device-security-key#3 sev=low blast=leaf effort=S verdict=actionable - `#![allow(missing_docs)]` at relay.rs:7 defeats the crate-root `#![deny(missing_docs)]` for a pub module re-exported at the root, letting undocumented items ship: `CidTranslator::new` (relay.rs:144), `LeaseId::as_u64` (relay.rs:209), and the pub fields of `CtaphidInitPacket`/`CtaphidContPacket` (relay.rs:54-66) - fix: document the handful of items and drop the module-level allow - [packages/d2b-provider-device-security-key/src/relay.rs:7, packages/d2b-provider-device-security-key/src/relay.rs:144, packages/d2b-provider-device-security-key/src/relay.rs:209] + evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 120 hits; the allow attribute at relay.rs:7 is the only missing_docs suppression in the crate +- d2b-provider-device-security-key#4 sev=medium blast=leaf effort=S verdict=actionable - no `# Errors` section exists on any of the 24 public `Result`-returning items, and the lease/controller state-machine failures are the non-obvious kind the section exists for (`SessionConflict` vs `InvalidTransition` vs `AuthorizationDenied` vs `Effect`) - fix: add `# Errors` sections naming the returned variants to `SecurityKeyLease::{acquire, acquire_authorized, rebind_authorized, complete, cancel, expire}` and `SecurityKeyController::{new, new_authorized, child_resources, child_resources_for_user, acquire, acquire_authorized, rebind_authorized, complete}` - [packages/d2b-provider-device-security-key/src/lease.rs:150-303, packages/d2b-provider-device-security-key/src/controller.rs:162-186, packages/d2b-provider-device-security-key/src/controller.rs:209-267] + evidence: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed 3 `-> Result<` = 24 hits +- clean: first sentences are one-line and load-bearing, module docs (`//!`) present in every module, error enums carry per-variant docs, magic values documented with the why (CEREMONY_TIMEOUT relay.rs:37-39, ring bounds lib.rs:67-72) + +## perf +- clean: seeds ran: 6/3/2 - every allocation site is cold: error construction (relay_service.rs:85,158), thread names (relay_service.rs:404), one-shot dependency collection (driver.rs:380-390), process-name derivation (process.rs:167), test helpers; `Vec::new` sites are the empty-case-common shape; no format!/to_string in any loop or hot path - static (unmeasured) per lens rules + +## conc +- d2b-provider-device-security-key#5 sev=medium blast=leaf effort=M verdict=actionable - 14 `parking_lot::Mutex::lock` sites (8 production-path in relay_service.rs:129,281,489,497,527,532,592,599 and 6 in the test-support-gated test_support.rs:32,43,44,55,78,89) carry no `#[allow(clippy::disallowed_methods, reason = "...")]` attribute, while the committed blocking-census baseline records `parking_lot::Mutex::lock = 0` for this crate and parking_lot is banned outright by clippy.toml (KD3) with only the R4 worker boundary exempt - the census bookkeeping and the manifest's recorded `disallowed_methods = "deny"` level disagree with the source, and the `// async-gate-allow:` markers cover only the async-gate scanner, not the clippy/census side - fix: add the sanctioned per-site allows (`reason = "synchronous path"`) or convert the short critical sections to the clippy.toml-named `tokio::sync::Mutex` replacement, then regenerate the census baseline to match - [packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-device-security-key/src/relay_service.rs:281, packages/d2b-provider-device-security-key/src/relay_service.rs:489-599, packages/d2b-provider-device-security-key/src/test_support.rs:32-89] + evidence: seed `\.lock\(\)` = 16 hits - 14 outside any `#[allow(clippy::disallowed_methods)]` fn (relay_service.rs:129,281,489,497,527,532,592,599; test_support.rs:32,43,44,55,78,89), 2 inside cfg(test) fns with the sanctioned "cfg(test) helper" allow (relay_service.rs:1031,1087); packages/xtask/data/blocking-census-baseline.json `packages/d2b-provider-device-security-key` -> `parking_lot::Mutex::lock: 0`; the census's prod/test split (blocking_census.rs `split_contexts`/`is_test_dir`) counts non-cfg(test) lines as production, so the test_support.rs sites count too; gate state not run (read-only lane) - the row asserts the baseline-vs-source mismatch, not a gate failure; clippy.toml disallowed-methods entry `parking_lot::Mutex::lock` with KD3 reason +- clean: the concurrency model fits the workload - one dedicated accept thread owning its own current-thread runtime (relay_service.rs:403-416, sanctioned "synchronous path" allow), shared `SecurityKeyState` behind a mutex with guards never held across an await, `AtomicU64` counters with Relaxed ordering (relay.rs:205-206, relay_service.rs:620-626) are the repo-sanctioned counter shape; no `unsafe impl Send/Sync`, no `thread_local!`, no `static mut` + +## async +- d2b-provider-device-security-key#6 sev=medium blast=leaf effort=S verdict=actionable - `run_connection` releases the ceremony lease only in its final statement (relay_service.rs:599), so an aborted task leaks the lease: `SkSessionTable::stop_vm`/`register`-replacement or accept-loop abort drops the accept thread's runtime and aborts every in-flight connection task mid-await, leaving `SecurityKeyState` `Leased` until `CEREMONY_TIMEOUT` (120s) expiry evicts it - other VMs are rejected (15s queue wait) for that whole window - fix: release the lease from a Drop guard (a small struct owning `Arc>` + vm_id + lease_id, dropped on task abort) so cancellation is resumable - [packages/d2b-provider-device-security-key/src/relay_service.rs:470-600, packages/d2b-provider-device-security-key/src/relay_service.rs:380-383, packages/d2b-provider-device-security-key/src/relay_service.rs:366-371] + evidence: seed 1 `async fn|async move|\.await` = 60+ hits; seed 2 `tokio::spawn|select!` = 8 hits; static trace: abort path (SkAcceptAbort::abort -> accept-loop break -> runtime drop -> spawned task abort) skips the release statement at relay_service.rs:599 +- clean: no guard is held across an await (all `parking_lot` guards are temporaries dropped before any suspension point - verified at relay_service.rs:489,497,527,532,592,599); `runtime.block_on` at relay_service.rs:416 is the sanctioned dedicated-thread boundary with an inline allow; `tokio::spawn` closures are `Send + 'static` via Arc; the select-then-await-other shape (587-590) correctly awaits the aborted task; all lock sites carry `// async-gate-allow:` markers recorded in the inventory - cited, not re-flagged + +## unsafe +- N/A: seeds 1-3 (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) all zero; the single seed-4 hit is a doc-comment mention of the workspace `forbid(unsafe_code)` lint (relay_service.rs:34), not a site; manifest `[lints.rust] unsafe_code = "forbid"` (Cargo.toml) + +## ffi +- N/A: seeds 1-4 (`extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char`) all zero - no foreign boundary in this crate; fd crossing is safe `File::from(OwnedFd)` under the workspace forbid + +## macro +- N/A: seeds 1-4 (`macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned`) all zero - no macro definitions or proc-macro surface + +## test +- d2b-provider-device-security-key#7 sev=medium blast=leaf effort=M verdict=actionable - no test exercises the relay's core forwarding path: `run_connection`'s guest->hidraw and hidraw->guest loops, CID translation inside the loop, and cancel-on-close are untested while every component (framing, hidraw wrapper, lease, reject paths) has its own unit test - contract behavior with no test; `test_hidraw()` already provides a socket-pair hidraw double, so a full-loop test is feasible - fix: add a `#[tokio::test(flavor = "current_thread")]` that runs `run_connection` with a socket-pair hidraw and a connected guest stream, asserts report forwarding in both directions and a `CTAPHID_CANCEL` packet on peer close - [packages/d2b-provider-device-security-key/src/relay_service.rs:470-600, packages/d2b-provider-device-security-key/src/relay_service.rs:642-648] + evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 50 hits; seed 2 `assert_eq!\(|assert_ne!\(|assert!\(` = 90+ hits; the 33 relay_service tests cover parsing/CID/lease/framing/hidraw/auth/reject paths but none drives the forwarding loop +- clean: seeds ran: 50/90+/0/0 - no `#[ignore]`, no proptest/insta/rstest; assertions target behavior and error variants, not Display strings (lease_state_machine.rs:91-97 asserts `Err(SecurityKeyLeaseError::Effect(Transient))`); redaction is pinned by tests/redaction.rs; tests are deterministic (socket pairs, current-process peer creds, no network/clock injection); integration/provider_lifecycle.rs is a real executable scenario, not a scaffold (this crate is not on the 18-crate policy-scaffold list) + +## Coverage +- idiom: 1 finding +- own: clean (seeds ran: 37/30/0/0) +- type: clean (seeds ran: 0/1/0) +- api: 1 finding +- err: clean (seeds ran: 70/5/6/5) +- serde: clean (seeds ran: 0/0/0/9) +- obs: clean (seeds ran: 0/0/0/31) +- docs: 2 findings +- perf: clean (seeds ran: 6/3/2) +- conc: 1 finding +- async: 1 finding +- unsafe: N/A (seeds: 0/0/0/1 - seeds 1-3 all zero; single seed-4 hit is a doc-comment mention; manifest forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md new file mode 100644 index 000000000..4b6adefec --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md @@ -0,0 +1,85 @@ +# d2b-provider-device-tpm - d2b-provider-device-tpm +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3333 (excl. src/generated/**, none present) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- d2b-provider-device-tpm#1 sev=low blast=leaf effort=S verdict=actionable - the swtpm log-level bound is spelled twice: lib.rs exports MIN_SWTPM_LOG_LEVEL/MAX_SWTPM_LOG_LEVEL (1/20) which runner.rs uses, while swtpm_argv.rs:160 hardcodes `1..=20` in generate_swtpm_argv, so a bound change in one place silently drifts from the other - fix: import crate::{MIN_SWTPM_LOG_LEVEL, MAX_SWTPM_LOG_LEVEL} in swtpm_argv.rs and replace the literal range - [swtpm_argv.rs:160, lib.rs:63, lib.rs:65] + evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 1 hit (runner.rs:18, deliberate invariant-preserving Default, not a finding); the bound duplication was read directly at the two sites +- clean: idiom seeds ran: 0/1/0; no index loops, no statement-style accumulation; the one hand-written Default preserves the 20 default a derive cannot express; argv building uses Vec::with_capacity(20) push pipelines + +## own +- d2b-provider-device-tpm#2 sev=low blast=leaf effort=S verdict=actionable - avoidable clones of Option and String where a reborrow suffices: resource_controller.rs:233-234 clones self.volume_ref only to borrow it, resource_controller.rs:247 clones self.process_ref the same way, effects_service.rs:280 clones self.device_ref to pass `&self.device_ref` to key(), and effects_service.rs:450 clones self.zone to call zone.as_str() on a live self - fix: use self.volume_ref.as_ref().ok_or(...)?, self.process_ref.as_ref(), self.key(&self.device_ref), and self.zone.as_str() - [resource_controller.rs:233, resource_controller.rs:247, effects_service.rs:280, effects_service.rs:450] + evidence: own seed 1 (`.clone()`) = 26 hits, seed 2 (`.to_owned()|.to_vec()|.to_string()`) = 46 hits, all sites read; the remaining clones are required (dual ownership into DeclaredTpmRows + port at effects_service.rs:684-692, borrowed-input error paths in swtpm_argv.rs, test fixtures) +- clean: own seed 3 (`Rc<|RefCell<|Arc shared state outside the tokio Mutex covered under async; the Arc facet clone is genuine shared ownership + +## type +- clean: type seeds ran: 1/1/0; validate_absolute (swtpm_argv.rs:119) is a single-boundary validator on a wire-shaped input type (a newtype would rewrite the refused SwtpmArgvInput fields), and watched_configuration_is_dependency (resource_controller.rs:18) is a cutover-contract constant with one constructor - both judged deliberate, no illegal-state finding + +## api +- d2b-provider-device-tpm#3 sev=medium blast=leaf effort=S verdict=actionable - the state.rs token module (StateDirectoryToken, TamperMarkerToken, StateOwnerToken, StateDirIntent, state.rs:6-107, re-exported lib.rs:36-38) has zero consumers repo-wide at HEAD, so the refusal ledger's stated reason for keeping it ("the daemon references them", over-engineering-audit-record.md:386, rows 71/72) is no longer evidenced - the daemon-side uses were deleted by the same applied finding - fix: delete state.rs and its re-export, or wire the daemon side that the record claims exists - [state.rs:6, state.rs:29, state.rs:51, state.rs:73, lib.rs:36] + evidence: census: `StateDirIntent|StateDirectoryToken|StateOwnerToken|TamperMarkerToken` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits outside packages/d2b-provider-device-tpm (only state.rs + lib.rs:36-38); changed evidence vs the record row +- d2b-provider-device-tpm#4 sev=low blast=leaf effort=S verdict=actionable - the exported inspect-tpm effects service is unwired: TPM_EFFECTS_SERVICE (effects_service.rs:53), TpmEffectsService, and TpmEffectsServiceFactory (effects_service.rs:103-116, whose facets field carries #[allow(dead_code)] for an R5 respawn path "not wired yet") are never registered, while d2bd registers every sibling provider's factory in shared_provider_effects.rs:3434-3493 without the TPM one - fix: register the factory there, or delete the service surface until the respawn path is wired - [effects_service.rs:53, effects_service.rs:103, effects_service.rs:114] + evidence: census: `TpmEffectsServiceFactory|TPM_EFFECTS_SERVICE` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits outside the crate +- d2b-provider-device-tpm#5 sev=low blast=leaf effort=S verdict=actionable - LiveTpmResourceEffectPort is pub (effects_service.rs:341) but is only constructed and consumed inside effects_service.rs (into_port at effects_service.rs:697), never appearing in a public signature or external caller - fix: make it pub(crate) - [effects_service.rs:341] + evidence: census: `LiveTpmResourceEffectPort` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits outside the crate +- d2b-provider-device-tpm#6 sev=low blast=leaf effort=S verdict=actionable - LegacyMigrationOutcome (migration.rs:5, re-exported lib.rs:24) has zero callers repo-wide: the "closed outcome of the broker-owned one-time legacy state adoption" is consumed by no broker or daemon code at HEAD - fix: delete the enum and its re-export, or wire the broker consumer it documents - [migration.rs:5, lib.rs:24] + evidence: census: `LegacyMigrationOutcome` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits +- clean: api seed 1 = 91 pub items, seed 2 = 1 hit (facets.rs:35 pub runtime: Arc - genuine shared ownership across facet clones, not a leak), seed 3 = 7 pub use arms (house single-surface pattern); the remaining exports (builders, controller, reconcile/finalize entry points, vocabulary) are consumed by d2bd or by this crate's integration tests + +## err +- d2b-provider-device-tpm#7 sev=medium blast=leaf effort=S verdict=actionable - two same-named error enums for one domain: runner.rs:43 SwtpmArgvError (one variant, LogLevelOutOfRange with no payload, returned by SwtpmSettings::validate) and swtpm_argv.rs:104 SwtpmArgvError (six variants including LogLevelOutOfRange { level }), both reachable from the crate root (lib.rs:35 re-exports the runner one; pub mod swtpm_argv exposes the other), so callers must disambiguate by module path and the two same-named LogLevelOutOfRange variants differ in shape - fix: make SwtpmSettings::validate return swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level } and delete runner::SwtpmArgvError - [runner.rs:43, swtpm_argv.rs:104, lib.rs:35, tests/conformance.rs:11] + evidence: err seed 4 (`enum \w*Error`) = 4 hits (resource_controller.rs:98, resource_effect.rs:10, runner.rs:43, swtpm_argv.rs:104); the two SwtpmArgvError definitions read in full +- clean: err seeds ran: 143/0/0/4; all 143 unwrap/expect hits are in #[cfg(test)] modules or on literally-built DurationMs::parse values in the production builders (resources.rs:215-270, fixed literals with fixed bounds - card false-positive class); no panic!/unreachable!/todo!/unimplemented!; no swallowed Results; TpmResourceControllerError wraps TpmResourceEffectError without leaking path/broker detail + +## serde +- clean: serde seeds ran: 5/7/0/14; SwtpmSettings carries deny_unknown_fields + serde default + a validate() admission gate (the conformance test pins the unknown-field refusal); no hand-written Deserialize; serde_json use is boundary rendering (declared child documents) and tests; TpmResourcePhase is Serialize-only for status rendering + +## obs +- clean: obs seeds ran: 0/0/0/11; all 11 tracing events use named fields (device=, error=, phase=, reason=) with %/? formatting; zero println/eprintln, zero interpolated messages, no instrument spans needed on these short paths + +## docs +- d2b-provider-device-tpm#8 sev=low blast=leaf effort=M verdict=actionable - Result-returning public items never enumerate their error variants: 47 `-> Result<` items (build_tpm_state_volume_spec, build_swtpm_process_spec, build_swtpm_flush_spec, generate_swtpm_argv, generate_swtpm_ioctl_flush_argv, TpmResourceController::new/reconcile/finalize, SwtpmSettings::validate, reconcile_device_tpm_controller, finalize_device_tpm_controller) carry one-line docs but no `# Errors` section, while the crate's doc standard is otherwise high (#![deny(missing_docs)] plus module docs) - fix: add `# Errors` sections naming the TpmResourceEffectError/TpmResourceControllerError/SwtpmArgvError variants each item can return - [resources.rs:53, swtpm_argv.rs:130, resource_controller.rs:132, resource_controller.rs:190] + evidence: docs seed 3 (`-> Result<`) = 47 hits, seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits +- d2b-provider-device-tpm#9 sev=low blast=leaf effort=S verdict=actionable - swtpm_argv.rs:39 `#![allow(missing_docs)]` is redundant: every pub item in the module is already documented and the crate root denies missing docs, so the opt-out lets a future undocumented pub item pass silently - fix: remove the module-level allow - [swtpm_argv.rs:39] + evidence: docs seed 1 = 78 pub items, all with doc comments; swtpm_argv.rs read in full + +## perf +- clean: perf seeds ran: 20/8/1; format! sites are swtpm argv rendering (the artifact text), one-shot inspect/JSON payloads, and error paths (cold); Vec::new() sites are empty-case metadata; the single to_string is a cold payload render; the argv builder pre-sizes with with_capacity(20) - no hot-loop allocation + +## conc +- clean: conc seeds ran: 0/3/20/0; the only production synchronization is tokio::sync::Mutex (covered under async); the AtomicBool/AtomicUsize/Ordering hits are test-only SeqCst counters in tests/resource_controller.rs; no threads, no thread_local, no unsafe Send/Sync impls + +## async +- d2b-provider-device-tpm#10 sev=medium blast=family effort=M verdict=actionable - prepare_state_dir (effects_service.rs:412) runs blocking work on the executor worker: a synchronous broker round-trip envelope_invoke_kernel (effects_service.rs:467, blocking connect/poll/recv up to kernel_io_timeout) plus NSS lookups nix::unistd::User::from_name/Group::from_name (effects_service.rs:518,525) in row_posture, none marked async-gate-allow (the crate's inventory lists only the 3 test lock sites) - fix: move the invoke and the NSS resolution off the worker (spawn_blocking or an async broker client); the same pattern exists in d2b-provider-supervisor/process/process-systemd/network-local and d2bd, so consolidation may treat it as one family class - [effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs:525] + evidence: async seed 1 (`async fn|async move|\.await`) = 76 hits; static (unmeasured); async-gate inventory for this crate = 3 sites, all test locks (effects_service.rs:865,874,887) +- d2b-provider-device-tpm#11 sev=low blast=leaf effort=S verdict=actionable - lifecycle_lease_consumed: tokio::sync::Mutex (effects_service.rs:361,698) guards a flag owned by exactly one task (into_port builds a fresh port per reconcile/finalize call and uses it once), and consume_lifecycle_lease holds the guard across `.await` (effects_service.rs:384-394); the lock can never contend - fix: replace with AtomicBool (preserves &self + Sync) or restructure the once-gate - [effects_service.rs:361, effects_service.rs:384, effects_service.rs:698] + evidence: async seed 3 (`tokio::sync::(Mutex|RwLock|Notify)`) = 2 hits (effects_service.rs:361,698); port construction read at effects_service.rs:697-700 + +## unsafe +- N/A: seeds 1-3 all zero (no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed); seed 4 alone = `unsafe_code = "forbid"` in Cargo.toml:9 plus a doc-comment mention (swtpm_argv.rs:38) - a forbid attribute does not make the lens applicable; the crate contains no unsafe code + +## ffi +- N/A: seeds 1-4 all zero (no extern "C"/no_mangle/link_section, no catch_unwind, no repr(C)/repr(transparent), no CStr/CString/c_char) + +## macro +- N/A: seeds 1-4 all zero (no macro_rules!, no proc_macro/syn/quote!, no $crate, no to_compile_error/new_spanned) + +## test +- clean: test seeds ran: 36/119/0/0; behavior-focused suite with no ignored tests: golden byte-parity against tests/golden/runner-shape/swtpm-argv-minimal.txt (swtpm_argv.rs:275), round-trips through the real v3 contract types (resources.rs:362), typed error variants via matches!/assert_eq, phase transitions, the owner fence, and the flush one-shot-outcome gate; deterministic (no network, no clock injection needed); the custom block_on harness (tests/resource_controller.rs:230-242) busy-polls with a noop waker but every scripted effect completes synchronously, so no test can hang today + +## Coverage +- idiom: 1 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 1/1/0) +- api: 4 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 5/7/0/14) +- obs: clean (seeds ran: 0/0/0/11) +- docs: 2 finding(s) +- perf: clean (seeds ran: 20/8/1) +- conc: clean (seeds ran: 0/3/20/0) +- async: 2 finding(s) +- unsafe: N/A (seeds: 0/0/0/1 - seeds 1-3 all zero; manifest `unsafe_code = "forbid"` at Cargo.toml:9) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 36/119/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md new file mode 100644 index 000000000..dd0a0b9da --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md @@ -0,0 +1,87 @@ +# d2b-provider-device-usbip - d2b-provider-device-usbip +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 7015 (excl. src/generated/**; src 5863 + tests 1143 + integration 9) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (1 part) + +## idiom +- d2b-provider-device-usbip#1 sev=low blast=leaf effort=S verdict=actionable - `declared_dependency_refs` accumulates into `let mut refs = Vec::new()` and pushes in match arms where each arm returns a fixed small list - fix: return the match arms as owned `Vec` literals (or `.into_iter().flatten().collect()`) so the shape is an expression - [driver.rs:267-281] + evidence: seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (driver.rs:267); seeds 1-2 (`for \w+ in 0\.\.`, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 0 +- clean: all three seeds ran (0/0/1); the crate's hand-written `Debug` impls redact (busid.rs:25, process.rs:47, firewall.rs:39) and are the deliberate redaction pattern, not derive candidates + +## own +- d2b-provider-device-usbip#2 sev=low blast=leaf effort=S verdict=actionable - lease admission in `KernelUsbipDispatcher` clones each 16-byte lease three times per reservation (`ledger.insert)..., lease.clone())`, `self.x = Some(lease.clone())`, `Ok(lease.clone())`) - fix: move the lease into the field and clone from the field for the map and the return (two clones), or return `self.x.as_ref().unwrap().clone()` after the insert - [broker.rs:194-208, broker.rs:218-232, broker.rs:313-321, broker.rs:333-341] + evidence: seed 1 `\.clone\(\)` = 104 hits crate-wide (matrix); the triple-clone shape at broker.rs:197+205+207 (and the relay/slot/proxy twins); all other clones in the crate are explainable (owned struct fields, report snapshots, test doubles) +- clean: seeds ran (104/14/0/0 per matrix); `Arc>` sharing is genuine (one ledger per zone, handed to every dispatcher; caller d2bd/src/shared_provider_effects.rs:267); no `Rc`/`RefCell`/`Cow` + +## type +- clean: seeds ran (4/1/0): `validate_zone`/`validate_provider_class`/`validate_admission`/`validate_network` are boundary admission gates on wire strings (recorded refused class, U1 (d) 6), `watched_configuration_is_dependency: bool` is a pinned cutover contract field (controller.rs:28); `BusId`/`PhysicalUsbBackingToken`/leases are already parsed/opaque newtypes; no Option-pair or stringly-state smells + +## api +- d2b-provider-device-usbip#3 sev=medium blast=leaf effort=S verdict=actionable - `pub mod state_machine` (lib.rs:24) plus the root `pub use state_machine::{...}` (lib.rs:61-65) exposes every state-machine item at two public paths, and no external caller uses the module path - fix: make the module private (`mod state_machine`) since lib.rs already re-exports its whole surface - [lib.rs:24, lib.rs:61-65] + evidence: seed 3 `^\s*pub use ` = 9 arms; census `device_usbip::state_machine` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits outside lib.rs (docs/reference/usbip-state-machine.md:110 imports from the root) +- d2b-provider-device-usbip#4 sev=medium blast=leaf effort=S verdict=actionable - `new_authority_ledger` returns `Arc>`, leaking the concrete lock type into the public signature and making any lock change a breaking change for the caller - fix: introduce an opaque `AuthorityLedgerHandle` newtype wrapping the `Arc>` (or a `pub type` alias) so the handle is the API - [broker.rs:131-133] + evidence: seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 4 hits (broker.rs:131, facets.rs:50+65, test_support.rs:101); the facets `Arc` fields are justified shared daemon-supplied facets (built at d2bd/src/resource_plane_v3.rs:2009-2015); census `new_authority_ledger` = 1 caller (d2bd/src/shared_provider_effects.rs:267); the Arc sharing itself is genuine, only the lock-type leak is the finding +- clean: 313 pub items (matrix) are the deliberate declared-provider surface; `pub use` re-export arms in lib.rs are the house single-surface pattern; the other `pub mod`s (broker, core_adapter, effects_service, facets, reconcile_state, vocabulary) each have external module-path consumers (d2bd/src/composition.rs:9557, resource_plane_v3.rs:1874, shared_provider_effects.rs:60) + +## err +- d2b-provider-device-usbip#5 sev=medium blast=leaf effort=M verdict=actionable - `UsbipStepExecutor` returns `Result<(), String>` from every step method, forcing implementers and callers to string-match reasons where the crate's own taxonomy is otherwise typed enums with `code()` accessors - fix: introduce a closed per-step error enum (or reuse `UsbipPlanError` tagged with the step) and map it in `execute_usbip_plan` - [state_machine.rs:378-386] + evidence: seed 4 `enum \w*Error` = 8 typed enums, all with stable `code()` accessors; the trait is the crate's only `Result<(), String>` surface; census `UsbipStepExecutor` = 1 impl (state_machine.rs:510, test fixture only) and docs/reference/usbip-state-machine.md:126 records "no production adapter currently implements this trait" +- clean: seed 1 `.unwrap\(\)|\.expect\(` = 12 hits, all inside `#[cfg(test)]` or the literal-constant `expect` at lifecycle.rs:56 (recorded false-positive class); seed 2 `let _ = |\.ok\(\);` = 0; seed 3 `panic!` = 2, both in tests; error enums carry no caller-controlled identity + +## serde +- clean: seeds ran (8/12/1/3): 8 derives with `rename_all`/`deny_unknown_fields`/`tag` conventions, 1 hand-written `Deserialize` (`UsbipReconcileCorrelationId`, reconcile_state.rs:293) plus the `deserialize_with` VM-shape gate (reconcile_state.rs:37) - both are live admission gates in the recorded refused class (U1 (d) 6, do not re-flag); `serde_json` calls are error-mapped boundary conversions (driver.rs:305-316); optionality meanings (`default` + `skip_serializing_if` + `Option`) are used deliberately on `UsbipEventSource.vm` (reconcile_state.rs:220-224) + +## obs +- clean: seeds ran (0/0/0/45): zero `println!`/`eprintln!`; zero interpolated-first-argument events - every tracing site uses named fields with a trailing message (e.g. lifecycle.rs:251-256); no secret in fields (resource refs are the crate's canonical identities, and wrong_zone_and_redaction.rs:77-98 pins identity-free Debug/metric labels); no spans needed since the crate has no async orchestration of its own + +## docs +- d2b-provider-device-usbip#6 sev=medium blast=leaf effort=M verdict=actionable - `#![allow(missing_docs)]` in reconcile_state.rs:6 and state_machine.rs:61 contradicts the crate's `#![deny(missing_docs)]` (lib.rs:9), leaving root-re-exported pub items without doc contracts (`UsbipPolicyFailure::telemetry_label`, `UsbipEventSource::vm`/`component`, `UsbipReconcileCorrelationId::new`, `UsbipClaimSource::is_explicit`, `UsbipExecutionReport::is_ok`, `UsbipBusidPlan::stop_order`) - fix: document the pub items and drop the two module-level allows - [reconcile_state.rs:6, state_machine.rs:61, lib.rs:9] + evidence: docs seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0; lib.rs:9 `#![deny(missing_docs)]` vs the two module allows; the affected items are re-exported at the crate root (lib.rs:61-65) +- d2b-provider-device-usbip#7 sev=medium blast=leaf effort=M verdict=actionable - Result-returning public items have no `# Errors` section anywhere in the crate, so callers cannot learn the closed failure sets from the docs - fix: add `# Errors` sections naming the variants to `UsbipArbitrator::new`, `BusId::parse`, `UsbipBindingContext::new`, `UsbipBindingController::new`, `build_usbip_plan`, `execute_usbip_plan`, `admit_bind_bus_class`, `binding_child_resources` - [arbitration.rs:76, busid.rs:12, broker.rs:61, controller.rs:210, state_machine.rs:254, state_machine.rs:429, vocabulary.rs:70, lifecycle.rs:43] + evidence: seed 3 `-> Result<` = 111 hits (matrix docs total 424 = 313 pub items + 111 Result returns); seed 2 canonical sections = 0 hits +- clean: first sentences are one-line contract statements throughout; magic values carry the why (USBIP_DEVICE_MAJOR vocabulary.rs:33, USBIP_REPAIR_INTERVAL_SECS controller.rs:14) + +## perf +- clean: seeds ran (4/5/12): `format!` only in plan-error paths (state_machine.rs:287,298,345) and a test (741) - cold per the card; `Vec::new()` at empty-case-common or fixture sites (arbitration.rs:90, lifecycle.rs:904, state_machine.rs:489+495) plus driver.rs:267 (covered by idiom#1); `to_string`/`to_owned` at wire-rendering and owned-projection boundaries; no hot loops; all findings static (unmeasured) + +## conc +- d2b-provider-device-usbip#8 sev=low blast=leaf effort=S verdict=policy-confirmed - `test_support.rs` recorders use `parking_lot::Mutex` (fields at 25/27/29/70/72, `.lock()` at 35/46-47/58-59/82/93) with no per-site allow, but parking_lot is banned outright with the single R4 bounded-worker exception - fix: replace with `tokio::sync::Mutex` (the clippy.toml-named replacement) or add the sanctioned `cfg(test) helper` per-site allow - [test_support.rs:25, test_support.rs:35, Cargo.toml:30] + evidence: seed 2 `\bMutex<` = 9 hits (broker.rs:131-157 tokio::sync::Mutex x4, test_support.rs parking_lot::Mutex x5); zero `#[allow(clippy::disallowed_methods)]` sites in the crate; policy: clippy.toml:40 "parking_lot is banned outright (plan KD3)"; the site is not on the recorded exception list (U1 (d) 2) +- clean: `AtomicU64` + `Ordering::Relaxed` token counter (broker.rs:123) is the weakest-correct ordering for a nobody-synchronizes-on counter; the shared `tokio::sync::Mutex` ledger is used via `try_lock` in synchronous dispatcher methods, never held across an await; no threads, no `thread_local!`, no manual `Send`/`Sync` + +## async +- clean: seeds ran (18/0/4/0): all `async fn`s are thin delegations to the daemon-supplied facets (`UsbipRuntime`/`UsbipBrokerDispatch`) with no spawn/select/join/block_on; the ledger mutex is never held across `.await` (try_lock in sync methods); `#[async_trait]` is the pragmatic object-safe choice; no runtime is started inside the library + +## unsafe +- N/A: seeds 0/0/0 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`); manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) and no `unsafe_code` text in src + +## ffi +- N/A: seeds 0/0/0/0 all zero (`extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char`); the crate crosses no foreign boundary + +## macro +- N/A: seeds 0/0/0/0 all zero (`macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned`); no macros defined or used beyond std + +## test +- d2b-provider-device-usbip#9 sev=low blast=leaf effort=S verdict=actionable - conformance.rs:63-66 asserts `AttachmentCommand::Attach(AttachmentActivation::Declared)` equals an identical literal, an assertion that cannot fail - fix: delete the tautological assert_eq (the same test's other asserts already pin the enum shape) - [tests/conformance.rs:63-66] + evidence: seed 2 `assert_eq!\(|assert_ne!\(|assert!\(` = 229 hits (matrix); the two compared expressions are the same literal construction +- d2b-provider-device-usbip#10 sev=medium blast=leaf effort=S verdict=actionable - `UsbipArbitrator` branches are untested: only the exclusive second-claim conflict is covered, while the constructor ceiling/ArbitrationViolation validation, `MaxClaimsExceeded`, idempotent re-claim by the same holder, and `release` have no test - fix: add a table-driven unit test over the ceiling, arbitration mode, re-claim, and release paths - [tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, src/arbitration.rs:117-121] + evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 40 hits across src+tests; arbitration_conflict.rs:8 is the only arbiter test and exercises one of the four claim branches +- d2b-provider-device-usbip#11 sev=medium blast=leaf effort=S verdict=actionable - the crate's declared wire types (`UsbipEventSource`, `UsbipReconcileAttemptContext`, `UsbipPublicDegradedReason`, `UsbipClaimSource`) have no serde round-trip test with a real-shaped payload, so kebab-case/camelCase wire drift would pass - fix: add a round-trip test deserializing a hand-written payload for each serde type and re-serializing - [src/reconcile_state.rs:51-308, src/state_machine.rs:98-100] + evidence: serde seeds = 25 hits in src but tests/ contains zero `serde_json`/`from_value`/`to_value`/`to_vec` hits; the daemon consumes the vocabulary via `to_public_reason` (d2bd/src/composition.rs:9556-9798), so the wire shapes are live contract +- clean: the suite is behavior-focused (call-order arrays, phase transitions, error variants not Display strings, redaction canaries at wrong_zone_and_redaction.rs:77-98); table-driven loops carry failure messages (state_machine.rs:730-754, vocabulary.rs:88-96); no `#[ignore]`, no network/time dependence; `integration/attach_detach_lifecycle.rs` is a declaration-only policy-required scaffold (recorded class, U1 (d) 5-6, not flagged) + +## Coverage +- idiom: 1 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 4/1/0) +- api: 2 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 8/12/1/3) +- obs: clean (seeds ran: 0/0/0/45) +- docs: 2 finding(s) +- perf: clean (seeds ran: 4/5/12) +- conc: 1 finding(s) +- async: clean (seeds ran: 18/0/4/0) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) +- test: 3 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md new file mode 100644 index 000000000..72c2640d4 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md @@ -0,0 +1,85 @@ +# d2b-provider-display-wayland-p1 - d2b-provider-display-wayland - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9342 (excl. src/generated/**) | modules: wayland_proxy/{bridge,clipboard,decoration,diag,dmabuf,filter,identity,mod,policy,readiness} +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 = src/wayland_proxy/** (part 2 = src/controller.rs, src/runtime.rs, src/process.rs, src/bin/**, src/spec.rs, src/policy.rs, src/session_children.rs, src/principal.rs, src/lib.rs) + +## idiom +- d2b-provider-display-wayland-p1#1 sev=low blast=leaf effort=S verdict=actionable - handoff_via_bridge re-wraps the bound `error` into a fresh `HandoffStatus::Failed(error)` and immediately matches it back out with a `_ => unreachable!()` arm that can never fire; the outer match arm already binds the value - fix: delete the `let status = ...` / `let error = match status {...}` round-trip and use the arm-bound `error` directly in filter.rs:620-628 - [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:620, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:624] + evidence: err seed 3 `panic!\(|unreachable!\(|todo!\(|unimplemented!\(` = 2; static read of filter.rs:606-631 shows the re-match is on a value constructed two lines earlier +- d2b-provider-display-wayland-p1#2 sev=low blast=leaf effort=S verdict=actionable - handle_bind dispatches per-interface handler installation through a nested `match try_downcast::() { Some => ..., _ => match try_downcast::() { Some => ..., _ => { if let ... } } }` while the same function already uses edition-2024 if-let chains for viewporter and dmabuf, mixing two dispatch styles in one body - fix: flatten the nested match into `if let Some(wm_base) = ... else if let Some(eglstream) = ... else if let Some(compositor) = ...` chains, keeping the early `return` arms - [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1272, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1300] + evidence: idiom seed 1 `for \w+ in 0\.\.` = 12; static read of filter.rs:1191-1332 (the fn mixes nested match with `if let ... && let ...` chains at filter.rs:1296-1304) +- d2b-provider-display-wayland-p1#3 sev=low blast=leaf effort=S verdict=actionable - filter_format_table iterates `for (index, entry) in table.chunks_exact(16).enumerate()` but the index is never used except `let _ = index;` inside the overflow branch, an ignore that exists only to silence the unused variable - fix: drop `.enumerate()` and remove `let _ = index;` - [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:790, packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:801] + evidence: idiom seed 1 `for \w+ in 0\.\.` = 12; static read of dmabuf.rs:790-806 (the `Ok` branch derives `new_index` from `filtered.len() / 16`, never from `index`) +- d2b-provider-display-wayland-p1#4 sev=low blast=leaf effort=S verdict=actionable - sanitize_label calls `out.chars().count()` on every loop iteration, a quadratic re-count of the output string that grows with the label length (bounded at 64 chars, so cheap, but the shape invites the same mistake at a larger bound) - fix: track a `let mut written = 0usize;` counter incremented per pushed char and compare against `MAX_LABEL_CHARS` - [packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:150] + evidence: idiom seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 8; static read of decoration.rs:146-171 +- d2b-provider-display-wayland-p1#5 sev=low blast=leaf effort=S verdict=actionable - four comment blocks are mangled prose: a non-ASCII full stop (`\u3002`) at dmabuf.rs:820, a stray `**` at filter.rs:769, two `; no` joins missing the space after the semicolon at filter.rs:770 and filter.rs:2801, and misindented two-line comment pairs at decoration.rs:1804-1805, dmabuf.rs:819-820 and filter.rs:2799-2801 where the continuation line sits at 4-space indent inside the fn - fix: rewrite the four comments as plain ASCII with normal spacing and consistent indent - [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:769, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:770, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:2801, packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:1804] + evidence: static (grep for `\u3002|\uff1b` and `\*\*|; no` over the module = 1 and 3 hits respectively; all four sites read) + +## own +- d2b-provider-display-wayland-p1#6 sev=low blast=leaf effort=S verdict=actionable - FilterPolicy carries `dmabuf_filters: std::sync::Arc` (built at policy.rs:316, cloned into DmabufHandler at filter.rs:1305) while the entire proxy is a single-threaded `Rc` graph - no thread or `'static` boundary justifies Arc, and the conc seeds are all zero - fix: switch the field and `DmabufHandler::new` parameter to `Rc` - [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:316] + evidence: own seed 3 `Rc<|RefCell<|Arc Result<` = 9; docs seed 2 = 0 (no canonical sections anywhere in the module) + +## perf +- clean: perf seeds 1-3 ran (53 / 31 / 11); every `format!` site is a cold path (lazy diag closures, error details, startup policy messages, identity labels built once per instance); no `format!` or allocation sits in a per-message hot loop; the rail pixel buffer is cached behind `FrameKey` (decoration.rs:1011) and only rebuilt when the key changes; the one bounded-quadratic `chars().count()` is covered by idiom#4; all findings here are static (unmeasured) + +## conc +- N/A (seeds: 0/0/0/0 all zero; the module declares no threads, mutexes, atomics, or thread_local - it is a single-threaded `Rc`/`RefCell` handler graph, so the lens has nothing to judge) + +## async +- N/A (seeds: 0/0/0/0 all zero; no async fn, await, spawn, or tokio sync primitive in the module - the proxy is a synchronous poll-driven loop and every blocking call site carries the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` marker: readiness.rs:29, filter.rs:771, filter.rs:2880, bridge.rs:280, dmabuf.rs:822, decoration.rs:1806) + +## unsafe +- N/A (seeds: 1-3 zero after false positives; the 2 `from_raw` hits are the safe `std::io::Error::from_raw_os_error` at filter.rs:991 and filter.rs:2824, not raw-pointer conversion; no `unsafe` block, fn, or impl exists in the module and the crate forbids unsafe_code at lib.rs:5) + +## ffi +- N/A (seeds: 0/0/0/4; the four `CString` hits are memfd name arguments at libc call sites (memfd_create at dmabuf.rs:823 and decoration.rs:1808), which never cross a foreign caller - the U1 ffi false-positive class) + +## macro +- d2b-provider-display-wayland-p1#12 sev=low blast=leaf effort=S verdict=actionable - the local `macro_rules! entry!` (policy.rs:420-437) is a two-arm table-filling shorthand whose `max=` arm only omits one field; it is not variadic, does not generate impls per type, and is not a DSL, so a plain function is the cheaper answer - fix: replace the macro with `fn entry(m: &mut HashMap, iface: &str, action: GlobalAction, class: Classification, max: Option)` and update the ~70 call rows; the catalog content stays byte-identical (the hand-written catalog itself is Nix-pinned and refused at docs/explanation/over-engineering-audit-record.md:352, 427-429 - this finding touches only the mechanism) - [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420] + evidence: macro seed 1 `macro_rules!` = 1 (sole definition in the module); static read of policy.rs:417-465 + +## test +- d2b-provider-display-wayland-p1#13 sev=high blast=leaf effort=S verdict=actionable - two registry-handler tests cannot fail on any behavior change: `filtered_globals_preserve_original_global_names` (filter.rs:3213-3224) inserts entries into `advertised_globals`/`hidden_globals` and asserts their presence - pure setup restatement with no function under test - and `standard_clipboard_global_is_advertised_as_synthetic` (filter.rs:3264-3283) admits in its comment that the real path is untested and then asserts only `interface.name()` plus the map content it just inserted - fix: delete the first test and rewrite the second to exercise `prepare_global(11, ObjectInterface::WlDataDeviceManager, 3)` and assert the synthetic `GlobalAdvertisement` decision, as the neighboring `prepare_global_hides_*` tests already do - [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3213, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3264] + evidence: test seeds over src/wayland_proxy + tests/: `#\[test\]` = 130, `assert_*` = 301, proptest/insta/rstest = 0, `#\[ignore\]` = 0; static read of filter.rs:3213-3224 and filter.rs:3264-3283 (assertions restate the inserted state) + +## Coverage +- idiom: 5 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 2/0/0; boundary validation already parse-once at the single construction path) +- api: 2 finding(s) +- err: clean (seeds ran: 63/10/2/1; every production panic site is an invariant-named expect or a U1 false-positive class) +- serde: 1 finding(s) +- obs: clean (seeds ran: 0/1/0/20; no println, consistent key=value event scheme with lazy closures, bounded-metadata policy documented) +- docs: 2 finding(s) +- perf: clean (seeds ran: 53/31/11; format!/allocation sites are cold or lazy, rail redraw cached by FrameKey) +- conc: N/A (seeds: 0/0/0/0 all zero; single-threaded Rc/RefCell handler graph) +- async: N/A (seeds: 0/0/0/0 all zero; synchronous poll-driven proxy with sanctioned synchronous-path allows) +- unsafe: N/A (seeds: 0/0/2/0 with the 2 from_raw hits being safe from_raw_os_error; no unsafe blocks; crate forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/4; CString hits are memfd name args at libc call sites, not a foreign-caller boundary) +- macro: 1 finding(s) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md new file mode 100644 index 000000000..935d47e3e --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md @@ -0,0 +1,89 @@ +# d2b-provider-display-wayland-p2 - d2b-provider-display-wayland - part 2/2 +Baseline: 6ebdd4cec | LOC audited: 6464 (excl. src/generated/**) | modules: controller, runtime, process, bin (d2b-wayland-proxy), spec, policy, session_children, principal, lib +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f): src/controller.rs, src/runtime.rs, src/process.rs, src/bin/**, src/spec.rs, src/policy.rs, src/session_children.rs, src/principal.rs, src/lib.rs + +## idiom +- d2b-provider-display-wayland-p2#1 sev=low blast=leaf effort=S verdict=actionable - three stale `#[allow(dead_code)]` markers sit on constructors that production code calls: `FinalizationInput::from_supervisor` (controller.rs:464), `LaunchGrants::from_supervisor_for_session_with_frontend_and_controller` (process.rs:402), `ProcessObservation::from_supervisor` (process.rs:676) - fix: delete the three allows (keep process.rs:380, whose constructor is test/test-support-only) so a future real dead-code warning is not masked - [src/controller.rs:464, src/process.rs:402, src/process.rs:676] + evidence: idiom seeds: 0 index loops / 3 hand-written impls / 2 statement accumulations; allows judged stale by reading call sites: runtime.rs:247,748,811,858 and process.rs:349 all reach production paths +- d2b-provider-display-wayland-p2#2 sev=medium blast=leaf effort=S verdict=actionable - the session binding digest is derived twice with byte-identical bodies: free fn `session_digest` (controller.rs:1442) duplicates `WaylandSessionSpec::session_digest` (spec.rs:385), so the two can silently diverge - fix: make the controller free fn delegate to `spec.session_digest(controller_generation)` and keep spec.rs:385 as the canonical home (census: d2bd already consumes the method at interaction_composition.rs:4080,4267) - [src/controller.rs:1442, src/spec.rs:385] + evidence: session_digest census over packages/ = 2 definitions with identical bodies (controller.rs:1442, spec.rs:385); both hash guest/host/user refs, reconnect generation, controller generation with [0] separators +- clean: index-loop seed 0 hits; the 3 hand-written Default impls (controller.rs:221, process.rs:154, process.rs:641) are invariant-preserving or test-support, not derive candidates; the 2 `Vec::new()` accumulations (process.rs:219, policy.rs:272) are conditional-push loops where an iterator would obscure + +## own +- clean: seeds ran 66 clone / 37 to_owned-family / 0 Rc-RefCell-Arc-Mutex / 0 Cow; every clone inspected is explainable (multi-pass reconcile clones at runtime.rs:397,451,599,654; lease principal copies at controller.rs:1085,1112; set-ownership clones in policy.rs:281-354; durable-name clones in session_children.rs:65-143; CLI startup clones in bin); no Rc/RefCell in library code, only in the single-threaded bin accept loop where shared mutable handler state genuinely has multiple owners + +## type +- clean: seeds ran 4 validate/check fns / 1 bool flag / 0 stringly state; the validate fns are parse-once boundary checks inside constructors (validate_label/validate_color in DisplayIdentity::new, validate_bounds in FilterInput::new, validate_layer in WaylandPolicy::compile) exactly per the skill; the one bool (DisplayRunnerContract.watched_configuration_is_dependency, controller.rs:30) is a contract flag; wire-mirroring booleans (cross_domain_trusted, virgl_video, debug_logging, border_enabled) are schema-pinned and not flagged + +## api +- d2b-provider-display-wayland-p2#3 sev=medium blast=leaf effort=S verdict=actionable - `PrincipalReleaseReceipt` (controller.rs:702, re-exported at lib.rs:20) is unconstructible: private `session_key` field and no constructor, so `DisplayController::release_session_principal` (controller.rs:1379) can never be called by the daemon; the principal-release path is dead exported surface - fix: add a constructor and wire the daemon cleanup path to call release_session_principal, or make both pub(crate) until the path is wired - [src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20] + evidence: census: PrincipalReleaseReceipt|release_session_principal over packages/; nixos-modules/; tests/; docs/reference/; labs = 4 hits, all in-crate (controller.rs:702,706,1381; lib.rs:20); release_session_principal has zero callers +- d2b-provider-display-wayland-p2#4 sev=low blast=leaf effort=S verdict=actionable - `WaylandPolicySnapshot::from_authenticated_session` (controller.rs:580) has no callers anywhere; the daemon resolves snapshots via `from_authenticated_route` - fix: delete the wrapper or mark it deliberate with a comment naming the route-based entry as canonical - [src/controller.rs:580] + evidence: census: from_authenticated_session over packages/ = 1 hit (the definition); daemon uses from_authenticated_route (d2bd interaction_composition.rs:2279) +- clean: api seed 2 (Arc/Rc/Box/RefCell in pub signatures) = 0 hits; seed 3 re-export arms in lib.rs are the house single-surface pattern; pub surface is otherwise deliberate (opaque grant/lease types with redacted Debug, pub(crate) fields on ProcessObservation and WorkerRestartEvidence, test-support-gated constructors) + +## err +- d2b-provider-display-wayland-p2#5 sev=medium blast=leaf effort=S verdict=actionable - `DisplayController::new(pool_size)` panics via `PrincipalPool::new(pool_size).expect(...)` (controller.rs:740-741) on any caller-supplied pool size outside 1..=32; the pub library API should not panic on input-derived values - fix: return `Result` from `DisplayController::new` (or document `# Panics` naming the bound) and update the two daemon call sites - [src/controller.rs:740, src/controller.rs:741] + evidence: err seed 1 = 75 hits, 3 outside tests (controller.rs:741,746,1048); the 1048 expect is justified (grants checked non-None two branches earlier); current DisplayController::new callers pass constants (d2bd interaction_composition.rs:2294,7164), so no live trigger +- d2b-provider-display-wayland-p2#6 sev=low blast=leaf effort=S verdict=actionable - `WaylandSpecError::NoPrincipalAvailable` (spec.rs:30) is never constructed: pool exhaustion is mapped to a Failed status with `SessionCondition::NoPrincipalAvailable` instead of the error variant - fix: either construct the variant in the exhaustion path (controller.rs:1089) or delete it and its Display arm - [src/spec.rs:30, src/spec.rs:43] + evidence: census: WaylandSpecError::NoPrincipalAvailable over packages/ = 2 hits (spec.rs:30,43); controller.rs:1089-1101 returns a Failed status rather than the error +- d2b-provider-display-wayland-p2#7 sev=medium blast=leaf effort=M verdict=actionable - grant and ticket constructors return `Result<_, &'static str>` error codes (`issue_for_supervisor_with_controller_generation` process.rs:335-346, `new_for_role_with_controller_generation` process.rs:825-887), so callers cannot match the failure and the codes are untyped strings - fix: introduce a closed `LaunchError` enum (thiserror) with `SessionInvalid` and `TicketInvalid` variants and return it from both constructors; the daemon caller maps to WorkerEffectError today (d2bd interaction_composition.rs:4283) - [src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886] + evidence: err seed 4 = 6 error enums in lane scope, all closed and well-split; the two &'static str returns are the only untyped error paths +- clean: err seeds 75 unwrap/expect (72 in tests) / 8 let _ (7 best-effort readiness reports before exit in bin, 1 test artifact) / 0 panic-unreachable-todo / 6 error enums; error taxonomy is otherwise exemplary (WorkerEffectError split by caller action, DisplayRuntimeError forwards effect codes, PolicyCompileError carries the offending interface) + +## serde +- d2b-provider-display-wayland-p2#8 sev=low blast=leaf effort=S verdict=actionable - `#[serde(try_from = "WaylandSessionSpecWire")]` (spec.rs:233) is inert: WaylandSessionSpec derives only Serialize, and Deserialize is hand-written (spec.rs:263-270) to do exactly what the derive plus try_from would generate - fix: delete the inert attribute (keep rename_all for the Serialize side), or derive Deserialize with try_from and delete the manual impl; pick one mechanism - [src/spec.rs:230, src/spec.rs:233, src/spec.rs:263] + evidence: serde seeds 10 derives / 12 serde attrs / 3 hand-written Deserialize impls (spec.rs:105,263; policy.rs:194); the other two manual impls are live admission gates (recorded refusal, not re-flagged); deny_unknown_fields is enforced through the Wire structs so the attribute block adds nothing +- clean: wire admission gates (DisplayIdentityWire, WaylandSessionSpecWire, FilterInputWire) all deny_unknown_fields and validate through TryFrom; CompiledWaylandPolicy round-trips with private fields; DisplayProcessRole and DisplayLabelPosition use kebab-case per house convention + +## obs +- clean: seeds ran 17 println/eprintln (all in bin, CLI product output carved out by the card) / 51 interpolated log macros (all in bin, same carve-out) / 0 instrument / 44 tracing uses; library tracing is exemplary: named fields (zone, guest, session, error) on every event, lazy format! closures in the bin's DiagRateLimiter, no secret material in any field, error chains logged once at the boundary that handles them + +## docs +- d2b-provider-display-wayland-p2#9 sev=low blast=leaf effort=S verdict=actionable - `FilterInput::allow_globals` and `FilterInput::deny_globals` doc comments say "Add an allowed global to this layer" / "Add a denied global to this layer" but the methods are getters returning `&[String]` - fix: reword to "Borrow the allowed globals of this layer" / "Borrow the denied globals of this layer" - [src/policy.rs:114, src/policy.rs:119] + evidence: docs seed 1 = 226 pub items, all read in full; policy.rs:114-122 doc text contradicts the getter shape (copy-paste from the builder intent) +- d2b-provider-display-wayland-p2#10 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub API has no `# Errors` canonical sections despite `#![deny(missing_docs)]`: constructors and reconcilers document their failure modes only through the error-enum variant docs - fix: add `# Errors` sections naming the variants on the pub Result items, e.g. `DisplayIdentity::new`, `WaylandSessionSpec::new`, `WaylandPolicy::compile`, `DisplayController::reconcile_authenticated_session` - [src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759] + evidence: docs seed 2 (canonical sections) = 0 hits; seed 3 = 81 `-> Result<` items; first sentences are otherwise strong and every pub item is documented +- clean: docs seed 1 = 226 pub items (all read), seed 2 = 0, seed 3 = 81; doc quality is high (one-line first sentences, module docs on every module, redacted Debug documented as deliberate); the two findings above are the only shape gaps + +## perf +- d2b-provider-display-wayland-p2#11 sev=low blast=leaf effort=S verdict=actionable - `durable_display_suffix` (session_children.rs:316-318) builds a 40-char hex suffix with one `format!` allocation per byte (20 allocations) instead of writing into the already-preallocated `String::with_capacity(40)` - fix: push two hex digits per byte via a lookup table or a single hex write into `suffix`, keeping the preallocation - [src/session_children.rs:316, src/session_children.rs:317] + evidence: perf seed 1 = 16 format! sites; this is the only format! in a loop; cold durable-naming path, static (unmeasured) +- clean: perf seeds 16 format! (rest are cold error/diagnostic paths or single-shot renders) / 20 collection news (empty-case-common or bounded) / 37 to_string (wire rendering and CLI); no hot-path allocation or collection-choice issue found + +## conc +- N/A: seeds 0/0/0/0 all zero; no threads, locks, atomics, or thread_local in part 2 (Rc/RefCell in the bin is single-threaded shared state, not a concurrency model) + +## async +- N/A: seeds 0/0/0/0 all zero; no async fn, spawn, tokio sync, or runtime entry in part 2; the crate is a synchronous reconciler plus a poll-loop binary + +## unsafe +- N/A: seeds 1-3 zero real hits (the 4 `from_raw` matches are the safe std `io::Error::from_raw_os_error` in bin tests); lib.rs:4 `#![forbid(unsafe_code)]` alone does not make the lens applicable + +## ffi +- N/A: seeds 0/0/0/0 all zero; no extern, no_mangle, repr(C), or CStr in part 2 + +## macro +- N/A: seeds 0/0/0/0 all zero; no macro_rules!, proc macro, or $crate in part 2 + +## test +- d2b-provider-display-wayland-p2#12 sev=medium blast=leaf effort=S verdict=actionable - the principal-release contract has no test and the test named `core_policy_snapshot_and_principal_receipt_are_consumed_by_controller` (controller.rs:1481) never touches `PrincipalReleaseReceipt` or `release_session_principal`; the name overclaims and the release path (acquire, release, re-acquire, UnknownLease on foreign receipt) is unverified - fix: rename the test to what it asserts (snapshot consumption) and add a release-path test exercising `release_session_principal` with a constructed receipt, asserting pool re-acquisition and UnknownLease for a foreign receipt - [src/controller.rs:1481, src/controller.rs:1379] + evidence: test seed 1 = 48 #[test] in lane scope (6 controller, 3 runtime, 6 process, 16 bin, 1 src/policy.rs, 1 session_children, 13 provider_behavior, 1 tests/policy.rs, 1 lifecycle); controller.rs:1481-1505 body reconciles and asserts Phase::Ready only +- clean: test seeds 48 #[test] / ~120 asserts / 0 proptest-insta-rstest / 0 #[ignore]; tests assert behavior (phase transitions, error variants via matches!, cleanup order, wire validation reuse, digest fencing), expectations are human-written, and the bin tests cover accept-error classification and poll-timeout bounds; no test that cannot fail found + +## Coverage +- idiom: 2 finding(s) +- own: clean (seeds ran: 66/37/0/0) +- type: clean (seeds ran: 4/1/0) +- api: 2 finding(s) +- err: 3 finding(s) +- serde: 1 finding(s) +- obs: clean (seeds ran: 17/51/0/44) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics in part 2) +- async: N/A (seeds: 0/0/0/0 all zero; no async code in part 2) +- unsafe: N/A (seeds: 0/0/0 real; only lib.rs:4 forbid(unsafe_code); from_raw_os_error is a safe std fn) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md new file mode 100644 index 000000000..fe910b188 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md @@ -0,0 +1,72 @@ +# d2b-provider-endpoint - d2b-provider-endpoint +Baseline: 6ebdd4cec | LOC audited: 2534 (excl. src/generated/**; incl. tests/**) | modules: whole crate (`src/lib.rs`, `src/driver.rs`, `src/endpoint.rs`, `src/effects_service.rs`, `src/facets.rs`, `src/test_support.rs`, `tests/registration.rs`) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none + +## idiom +- d2b-provider-endpoint#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default for EndpointConsumerPolicy` returns `Self::unrestricted()`, which the field-wise derive would produce identically (empty Vecs) - fix: add `Default` to the derive list on `EndpointConsumerPolicy` and drop the manual impl - [packages/d2b-provider-endpoint/src/endpoint.rs:395-398] + evidence: idiom seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit (endpoint.rs:395) +- d2b-provider-endpoint#2 sev=medium blast=leaf effort=S verdict=actionable - the `inspect-endpoint` payload table hardcodes the four committed purposes and their producer/locality/class strings, duplicating the same-module derivations `guest_control_producer`/`device_worker_endpoint_class` built from the provider constants, so a provider role/purpose rename drifts the report silently - fix: build the table from those fns, or constrain it with a unit test pinning the payload rows to the derivations - [packages/d2b-provider-endpoint/src/effects_service.rs:50-60,73-84,128-143] + evidence: static cross-read: payload rows at effects_service.rs:132-137 repeat the values the fns at 50-60,73-84 produce,and no test exercises `inspect_endpoint_response()` +- clean: idiom seeds ran: two/one/zero hits; the two index-loop hits are deliberate `yield_now()` nudge loops in tests,and no statement-style accumulation exists + +## own +- clean: own seeds ran: fourteen/eleven/zero/zero hits; every clone/`to_owned` is explainable: `Arc` clones at factory/spawn fences (driver.rs:338,273,57-58), `ResourceRef`/`String` copies riding into `tokio::spawn` (driver.rs:463-464), `error.detail.clone()` inside the borrowed `classify_error`, test-fixture rows, wire-rendering `to_owned` strings in the service payload + +## type +- clean: type seeds ran: one/zero/zero hits; the one `check_shape` hit classifies a closed realization set that depends on a dynamic vocabulary trait,not an invariant a parsed type can carry; no boolean-flag soup or stringly-typed state exists + +## api +- clean: api seeds ran: sixty-eight/seven/three hits over three seeds; the public surface is the deliberate contract vocabulary (`pub mod endpoint` + `pub use` arms are loaded by d2bd,display-wayland,volume-binding - census: `provider_endpoint::endpoint::` over packages = more than ten hits),andthe only `Arc<...>` in public positions are the composition-supplied facet seams whose ownership is genuinely shared (factory clones `EndpointEffectFacets` per driver at driver.rs:338; daemon builds once at d2bd/resource_plane_v3.rs:2125) + +## err +- clean: err seeds ran: about forty hits over four seeds; every `unwrap`/`expect`/`panic!` sits in `#[cfg(test)]` fixtures over literal-built values; the one production `let _ =` (driver.rs:484) drops the effect-completion `send` as best-effort at resource teardown (the receiver dies with the context,so the report has no consumer); the two `String`-returning effect seams are report-only,re-wrapped into `FailureDetail` notes + +## serde +- d2b-provider-endpoint#3 sev=medium blast=leaf effort=S verdict=actionable - `EndpointAttachmentPolicy`'s derived `Deserialize` admits illegal state (`supported=false, max_attachments>0`,andthe converse), while its sibling `EndpointConsumerPolicy` routes `Deserialize` through `Self::new` as an admission gate,so a standalone deserializer yields a shape the constructor refuses - fix: route `EndpointAttachmentPolicy::deserialize` through `Self::new` (try_from or the sibling hand-written pattern at endpoint.rs:197-216) - [packages/d2b-provider-endpoint/src/endpoint.rs:112-120,125-131,197-216,377-381] + evidence: serde seeds one-two=about forty-four hits; the derive at endpoint.rs:112-113 andthe sibling hand-written gate at endpoint.rs:197-216 + +## obs +- N/A: obs seeds ran: zero/zero/zero/zero all zero; the crate has no `tracing`/`log` dependency and no stdout telemetry + +## docs +- d2b-provider-endpoint#4 sev=low blast=leaf effort=S verdict=actionable -the pub Result-returning constructors lack the canonical `# Errors` section naming which condition produces which `EndpointSpecError` variant - fix: add `# Errors` blocks to `EndpointAttachmentPolicy::new`, `EndpointConsumerPolicy::new`,and `EndpointSpec::new`,each enumerated briefly - [packages/d2b-provider-endpoint/src/endpoint.rs:124-125,152-153,254-255] + evidence: docs seed two (`/// # (Examples|Errors|Panics|Safety))`) = zero hits while seed three (`-> Result<`) about six hits in pub items + +## perf +- clean: perf seeds ran: about fourteen hits over three seeds; all `format!` sites are one-shot error reports (driver.rs:385,effects_service.rs:219) or test fixtures;`Vec::new()` sites are test rows andthe `unrestricted()` policy;`to_string()` sites are test fixtures - no hot-path allocation identified (static, unmeasured) + +## conc +- clean: conc seeds ran: about thirteen hits over four seeds; the only locks/atomics are the `cfg(test)`/test-support recording doubles (`parking_lot::Mutex` + `AtomicBool`),with `SeqCst` on scripted flags - repo recorded false positive (test-only synchronization; atomics as counters),and every lock site carries the recorded `async-gate-allow` marker + +## async +- clean: async seeds ran: about one hundred two hits over four seeds; no guard held across an `.await`, no blocking work inside async contexts (the two `parking_lot` locks in test-support are marker-allowed synchronous acquisitions with no await while held),the spawned long-effect task captures `Send` values and reports through an unbounded mpsc,andthe evidence-wait loop uses async `sleep` inside a `tokio::time::Instant` deadline - cancellation-safe (the wait is resumable on retry) + +## unsafe +- N/A: unsafe seeds ran: zero/zero/zero/zero all zero; no `unsafe` block/fn/impl and no `unsafe_code` manifest allowance (local lints table: `unsafe_code = "forbid"`) + +## ffi +- N/A: ffi seeds ran: zero/zero/zero/zero all zero; no extern/C/repr/CStr surface exists + +## macro +- N/A: macro seeds ran: zero/zero/zero/zero all zero; no `macro_rules!`,proc-macro,or `$crate` use occurs + +## test +- d2b-provider-endpoint#5 sev=low blast=leaf effort=S verdict=actionable -the two long-effect tests wait a fixed sixteen-`yield_now()` budget for the spawned task to report through the double,instead of polling the observable recorded call - fix: replace each fixed loop with a bounded poll over `fake.call_order().contains("ensure-socket")` (async yield or small sleep until it appears,then assert) - [packages/d2b-provider-endpoint/src/driver.rs:824-827,1248-1251] + evidence: test seed two (`assert_eq!|assert_ne!|assert!`) about sixty of the eighty-one test-seed hits; rows at driver.rs:825,1249 are the fixed-budget waits + +## Coverage +- idiom: two finding(s) +- own: clean (seeds ran: fourteen/eleven/zero/zero; clones/to_owned all explainable: Arcs at fences,spawn copies,test rows,wire-rendering strings) +- type: clean(seeds ran: one/zero/zero; check_shape classifies a dynamic closed set,not a typestate-invariant) +- api: clean(seeds ran: sixty-eight/seven/three; public surface is deliberate contract vocabulary with loaded `endpoint::` consumers; Arc seams share ownership at the composition root; no leaking internals found) +- err: clean(seeds ran: about forty hits over four seeds; panics are test-only; the one swallowed send is best-effort at teardown; String effect errors are report-only notes) +- serde: one finding(s) +- obs: N/A (seeds: zero/zero/zero/zero; no tracing/log dep in Cargo.toml) +- docs: one finding(s) +- perf: clean(seeds ran: about fourteen hits over three seeds; all allocation sites are error paths,fixtures,andthe unrestricted policy; static inspection only) +- conc: clean(seeds ran: about thirteen hits over four seeds; only test-support/cfg(test) locks+atomics with async-gate-allow markers - recorded repo false positives) +- async: clean(seeds ran:about one hundred two hits over four seeds; no guard-across-await,blocking work,or unbounded growth; spawned effect path is Send and marker-allowed) +- unsafe: N/A (seeds: zero/zero/zero/zero; no unsafe blocks or allow manifests; local lints: unsafe_code=forbid) +- ffi: N/A (seeds: zero/zero/zero/zero; no extern/C/repr/CStr surface) +- macro: N/A (seeds: zero/zero/zero/zero; no macro_rules!,proc-macro,or $crate use) +- test: one finding(s) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md new file mode 100644 index 000000000..0e70a2f33 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md @@ -0,0 +1,89 @@ +# d2b-provider-guest-azure-container-apps - d2b-provider-guest-azure-container-apps +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2420 (excl. src/generated/**) | modules: whole crate (lib.rs, controller.rs, effects.rs; tests/provider_lifecycle.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test, supply | Partitions: none (single-part lane) + +## idiom +- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0 over src; no index loops, no hand-written derives (the TryFrom impls delegate to validated constructors), no statement-style accumulation; the one `for index in 0..2` loop lives in tests and is a bounded retry driver, not an index idiom. + +## own +- d2b-provider-guest-azure-container-apps#1 sev=low blast=leaf effort=S verdict=actionable - CompletedOperationLedger::record evicts the oldest entry by cloning the map key only to hand it to BTreeMap::remove, which accepts a borrowed key - fix: drop the `.map(|(operation_id, _)| operation_id.clone())` and call `self.completed.remove(&oldest)` directly on the `&AcaOperationId` that `iter().min_by_key)...)` yields - [src/controller.rs:156-157] + evidence: seed `\.clone\(\)` = 44 hits over src; BTreeMap::remove takes `&Q where K: Borrow`, so the eviction path needs zero clones. +- d2b-provider-guest-azure-container-apps#2 sev=low blast=leaf effort=S verdict=actionable - reconcile_observed clones the whole owned `record` parameter into `self.observed` and then matches on it, although only the Copy `lifecycle` field is read after the store - fix: `let lifecycle = record.lifecycle; self.observed = Some(record); match lifecycle { ... }` - [src/controller.rs:500-501] + evidence: seed `\.clone\(\)` = 44 hits over src; the match arms read only `record.lifecycle` (Copy), so moving the record and extracting the field first removes the clone. +- d2b-provider-guest-azure-container-apps#3 sev=low blast=leaf effort=S verdict=actionable - in the Suspended/Stopped arm of reconcile_observed the owned `record` parameter is dead after the resume closure is built, yet `record.id.clone()` copies the id instead of moving it out - fix: `let id = record.id;` (partial move) before the `move` closure - [src/controller.rs:527] + evidence: seed `\.clone\(\)` = 44 hits over src; `record` is not referenced after line 527 in that arm (later reads go through `self.observed`/`resumed`), so the move compiles. +- d2b-provider-guest-azure-container-apps#4 sev=low blast=leaf effort=S verdict=actionable - the stop and delete stages clone the entire observed `AcaSandboxRecord` (`self.observed.clone().ok_or)...)?`) although the closures consume only `record.id` - fix: clone just the id (`self.observed.as_ref().ok_or)...)?.id.clone()`) and move that into the closure - [src/controller.rs:417-419, src/controller.rs:469-471] + evidence: seed `\.clone\(\)` = 44 hits over src; both closures call `stop_sandbox`/`delete_sandbox` with `&record.id` only, so the record-level clone copies the id String plus Copy fields needlessly. +- d2b-provider-guest-azure-container-apps#5 sev=low blast=leaf effort=S verdict=actionable - one_candidate and one_disk_image clone the single match out of a slice pattern although they own the `candidates` parameter and return an owned record - fix: consume with `let mut it = candidates.into_iter(); match (it.next(), it.next()) { (Some(c), None) => Ok(Some(c)), (None, None) => Ok(None), _ => Err)...) }` - [src/controller.rs:892, src/controller.rs:903] + evidence: seed `\.clone\(\)` = 44 hits over src; both helpers take `AcaSandboxCandidates`/`AcaDiskImageCandidates` by value and every caller passes a freshly returned value, so an into_iter consumption removes both clones. +- d2b-provider-guest-azure-container-apps#6 sev=low blast=leaf effort=S verdict=actionable - AcaProviderConfig::validate() re-clones all 11 fields to re-run the constructor checks, when every check is readable from `&self` - fix: extract a private `fn validate_refs(&self) -> Result<(), AcaTypeError>` holding the resource_type() comparisons and call it from both `new` (on the raw args) and `validate` (on self) - [src/effects.rs:450-464] + evidence: seed `\.clone\(\)` = 44 hits over src; lines 451-462 clone gateway_execution_ref, tenant_id, client_id, subscription_id, control_credential_ref, pull_credential_ref, environment_id, resource_group_id, network_ref, sandbox_transport_alias, defaults solely to rebuild the struct the admission boundary already validated. + +## type +- d2b-provider-guest-azure-container-apps#7 sev=medium blast=leaf effort=M verdict=actionable - AcaProviderConfig exposes all 11 fields `pub` while its sibling validated configs (AcaRuntimeConfig, AcaSandboxProfile, AcaReadinessPolicy) keep fields private behind constructors, so a literal construction bypasses the execution-boundary validation that `new()`/`validate()` enforce - fix: privatize the fields and add accessors (network_ref, sandbox_transport_alias, defaults are read in-crate at controller.rs:940-946; no external field reads exist) - [src/effects.rs:394-406] + evidence: census: `AcaProviderConfig` over packages+tests+docs/reference+labs+nixos-modules = 20 hits, all constructions via `::new()` (packages/d2b-provider-guest/src/driver.rs:1942, packages/d2b-provider-guest/src/effects_service.rs:1807) or `serde_json::from_value` (effects_service.rs:1145); literal `AcaProviderConfig {` constructions = 0 real sites (the two regex matches are the struct definition and an accessor brace); field reads only in-crate. + +## api +- d2b-provider-guest-azure-container-apps#8 sev=low blast=leaf effort=S verdict=actionable - lib.rs re-exports the whole effects module via `pub use effects::*;` (so every future pub item in effects silently becomes public API) and effects.rs re-exports four dependency types (`CredentialLeaseHandle`, `OpaqueAzureRef`, `ResourceRef`, `ResourceUid`) with zero consumers through this crate's path - fix: replace the glob with named arms listing the intended effect surface and drop the uncalled dependency-type re-exports - [src/lib.rs:14, src/effects.rs:8-9] + evidence: census: `guest_azure_container_apps::(CredentialLeaseHandle|OpaqueAzureRef|ResourceRef|ResourceUid)` over packages+tests+labs+nixos-modules+docs/reference = 0 hits; callers import the contracts-crate paths directly (packages/d2b-provider-guest/src/driver.rs:1944), so the re-exports are surface without consumers. + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(`=1 (controller.rs:539 `expect("stored above")` asserts the invariant just stored on the previous line - acceptable per the skill's invariant-panic channel), `let _ = |\.ok\(\);`=0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`=0, `enum \w*Error`=3 (AcaControllerError, AcaTypeError, AcaControlErrorKind); the taxonomies split by caller action with stable `code()` strings, AcaControlError wraps a private kind per the struct pattern, and no wire-visible error enum is restructured. + +## serde +- clean: seeds ran: 31 combined hits (derive Serialize/Deserialize, serde attributes, hand-written Deserialize, serde_json calls); every wire type validates through `try_from` (RawAca* shapes and numeric bounds via TryFrom delegating to the validated constructors), `deny_unknown_fields` is applied to all config raws, `rename_all = "camelCase"` everywhere, and the only hand-written Deserialize impls are the opaque_id admission gates (recorded refusal class per U1 (d) 6 - not re-flagged); a real-payload round-trip test exists at effects.rs:886. + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(`=0, interpolated message-only events=0, `\.instrument\(|#\[instrument`=0, `tracing::`=15; all 15 warn!/debug! events carry named fields (resource, provider, code, purpose, lifecycle, attempt), messages are static literals, and the hand-written Debug impls (opaque_id, AcaProviderConfig, AcaSandboxRecord) redact identity material so no secret reaches a field. + +## docs +- d2b-provider-guest-azure-container-apps#9 sev=low blast=leaf effort=M verdict=actionable - `#[allow(missing_docs)]` blanket-exempts the effects module whose pub surface (AcaControl and AcaCredentialLeaseClient trait methods, AcaProviderConfig fields, Aca*Error enums, MAX_ACA_* constants) is re-exported at the crate root, undercutting the crate's own `#![deny(missing_docs)]` - fix: document the effect trait methods and validated-config accessors and drop the module-level allow (README.md already carries the prose contract, so this is rustdoc-surface work, not a contract gap) - [src/lib.rs:7, src/effects.rs:813-882] + evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 87 hits over src, the large majority inside the allow-exempted effects module; seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0. +- d2b-provider-guest-azure-container-apps#10 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub items carry no `# Errors` section naming their failure conditions (AcaController::reconcile and finalize, AzureContainerAppsRuntimeProvider::new, the validated constructors AcaProviderConfig::new/validate, AcaCpuMillis::new, AcaMemoryMib::new, the opaque_id parse) - fix: add `# Errors` sections listing the AcaTypeError/AcaControllerError conditions each returns - [src/controller.rs:257, src/controller.rs:308, src/controller.rs:924, src/effects.rs:61, src/effects.rs:106, src/effects.rs:128, src/effects.rs:410, src/effects.rs:450] + evidence: docs seed 3 (`-> Result<`) = 40 hits over src; seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 canonical sections anywhere in the crate. + +## perf +- clean: seeds `format!\(`=0, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=0, `\.to_string\(\)`=0 over src; no allocation sites in the reconcile path beyond the required owned-effect payloads, and the clone-heavy spots are cold (per-interval reconcile, admission boundary) - static (unmeasured). + +## conc +- N/A (seeds: `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=0, `Atomic\w+|Ordering::`=0, `thread_local!|unsafe impl (Send|Sync) for`=0 all zero; no threads, locks, atomics, or manual Send/Sync in src - the crate is single-task async). + +## async +- clean: seeds ran: 51 combined hits (async fn/async move/.await, async_trait effect ports); every provider call is wrapped in `timeout_at(deadline, ...)` with a deadline derived once from `deadline_remaining_ms` (controller.rs:676-677), no blocking work sits inside an async context, no guard is held across an await (no Mutex in src), no spawn/spawn_blocking exists, and shared state is limited to Arc effect ports with genuine multi-controller ownership (AzureContainerAppsRuntimeProvider::controller shares Arc/Arc across per-Guest controllers). + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=0; seed 4 alone - `#![forbid(unsafe_code)]` at src/lib.rs:4 plus the manifest's local `unsafe_code = "forbid"` - does not make the lens applicable per the card). + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0 all zero; the crate crosses no foreign boundary). + +## macro +- clean: seeds `macro_rules!`=1 (effects.rs:54), `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; the single `opaque_id!` macro is the genuine impl-per-type case (8 ID newtypes with identical parse/as_str/Deserialize/Debug shapes), uses narrow fragment specifiers (ident, expr), needs no `$crate` (it references only std macros and its own parameters), and is by-example, not procedural. + +## test +- d2b-provider-guest-azure-container-apps#11 sev=low blast=leaf effort=S verdict=actionable - stable_error_codes_are_bounded ends with a dead `let _ = ResourceRef::parse("Guest/gateway").unwrap();` that asserts nothing the test name claims and duplicates parse coverage exercised everywhere else - fix: delete the line (or fold the parse into an assertion the test actually promises) - [tests/provider_lifecycle.rs:536] + evidence: test seeds: `#\[test\]|#\[tokio::test\]`=14, `assert_eq!\(|assert_ne!\(|assert!\(`=28, `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0; the stray line is the only statement in the suite whose result is discarded. +- d2b-provider-guest-azure-container-apps#12 sev=medium blast=leaf effort=S verdict=actionable - the completed-operation ledger replay path (reconcile with a previously recorded operation id returns Converged without re-running effects, controller.rs:264-266) is contract behavior with no test - every test calls reconcile with a fresh operation id - fix: add a test that reconciles twice with the same id against a Running sandbox and asserts the second pass performs no effect calls (calls list unchanged) - [src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225] + evidence: test seeds: 14 tests, 0 reuse an operation id across reconcile calls (all ids are unique per test, including the loop in readiness_attempts_are_bounded which formats fresh ids); the ledger replay branch is therefore never exercised. + +## supply +- d2b-provider-guest-azure-container-apps#13 sev=low blast=leaf effort=S verdict=actionable - the `sha2` dependency is unused: the name appears nowhere in src/ or tests/ (only in Cargo.toml:21 and as the prose word "digests" in README.md:51) - fix: remove `sha2 = { workspace = true }` from the crate manifest (the workspace dep stays for its other consumers) - [Cargo.toml:21] + evidence: census: `sha2|Sha2|Sha256|digest` over packages/d2b-provider-guest-azure-container-apps/src + tests = 0 hits; the only manifest mention is Cargo.toml:21. + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: 6 finding(s) +- type: 1 finding(s) +- api: 1 finding(s) +- err: clean (seeds ran: 1/0/0/3) +- serde: clean (seeds ran: 31 combined) +- obs: clean (seeds ran: 0/0/0/15) +- docs: 2 finding(s) +- perf: clean (seeds ran: 0/0/0) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync in src) +- async: clean (seeds ran: 51 combined; all effect calls bounded by timeout_at deadlines, no blocking work, no guards across awaits, no spawn sites) +- unsafe: N/A (seeds: 0/0/0; seed 4 alone - `#![forbid(unsafe_code)]` at src/lib.rs:4 - does not make the lens applicable) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: clean (seeds ran: 1/0/0/0) +- test: 2 finding(s) +- supply: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md new file mode 100644 index 000000000..92c46840f --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md @@ -0,0 +1,97 @@ +# d2b-provider-guest-azure-virtual-machine - d2b-provider-guest-azure-virtual-machine +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2839 (src 1882 + tests 957, excl. src/generated/**) | modules: whole crate (bootstrap.rs, config.rs, error.rs, lib.rs, controller/mod.rs, effect/mod.rs + tests/) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-guest-azure-virtual-machine#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default for BootstrapService` where a derive with a `#[default]` variant covers it - fix: add `#[derive(Default)]` with `#[default]` on `BootstrapServiceState::Waiting` (bootstrap.rs:124) and `#[derive(Default)]` on `BootstrapService`, delete the manual impl - [src/bootstrap.rs:138, src/bootstrap.rs:124] + evidence: seed 2 `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit (bootstrap.rs:138); seed 1 `for \w+ in 0\.\.` = 1 hit, seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 0 +- clean: the single index loop (bootstrap.rs:28, `BootstrapPsk::matches`) is a deliberate constant-time comparison over max(len) with no early exit; an iterator chain would obscure the timing property; the hand-written `Debug` impls (BootstrapPsk, DataDiskSpec, AzureVmConfig, AzureVmGuestSettings, AzureVmStatus, AzureVmHandle, AzureOperationHandle, TagDigest) are deliberate secret redaction (derive would leak) - per-card false positive. + +## own +- d2b-provider-guest-azure-virtual-machine#2 sev=medium blast=leaf effort=S verdict=actionable - PSK secret copied twice in `start_psk_delivery`: `copy_for_delivery()` already returns an owned `Zeroizing>` and the extra `.to_vec()` produces a plain, non-zeroized `Vec` copy of the secret - fix: `PskExtensionPayload::from_secret(psk.copy_for_delivery().into_inner())` (or pass the `Zeroizing` value directly; zeroize 1.9 implements `From> for T`) - [src/controller/mod.rs:791, src/bootstrap.rs:42] + evidence: seed 1 `\.clone\(\)` + seed 2 `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 18 hits; site read in full +- d2b-provider-guest-azure-virtual-machine#3 sev=low blast=leaf effort=S verdict=actionable - `self.vm_handle.clone().ok_or)...)` clones the handle only to pass it by reference to an effect call - fix: `let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?;` and pass `handle` (no mutable borrow of `vm_handle` is live across the effect await) - [src/controller/mod.rs:640, src/controller/mod.rs:764] + evidence: seed 1 = 18 hits; both sites read with borrow analysis +- d2b-provider-guest-azure-virtual-machine#4 sev=low blast=leaf effort=S verdict=actionable - `self.pending_delete_operation_id.clone().ok_or)...)` clones a `String` only to borrow it for `start_vm_delete` - fix: `let operation_id = self.pending_delete_operation_id.as_deref().ok_or(AzureVmError::Ambiguous)?;` and pass `operation_id` - [src/controller/mod.rs:852] + evidence: seed 1 = 18 hits; site read +- d2b-provider-guest-azure-virtual-machine#5 sev=low blast=leaf effort=S verdict=actionable - `base32(&digest.finalize())[..20].to_owned()` allocates the full base32 string and then a second 20-char copy - fix: `let mut id = base32(&digest.finalize()); id.truncate(20); id` (or cap the length inside `base32`) - [src/controller/mod.rs:1046] + evidence: seed 2 `.to_owned()` = 1 hit (controller/mod.rs:1046); `base32` already pre-sizes with `String::with_capacity` (controller/mod.rs:1051) +- clean: the remaining clones are explainable - `recovery_state()` export clones (controller/mod.rs:260-265) build an owned sealed record from `&self`; `finalize`'s `get_or_insert_with)...).clone()` (controller/mod.rs:687) re-owns the id it may have just inserted; `verify_owned_vm` stores and returns the same handle (controller/mod.rs:959); `validate_update` clones `settings` (controller/mod.rs:986-997) to validate a prospective state without mutating `self`; `TagDigest::from_tags` copies the tag slice to sort it (effect/mod.rs:101); no `Rc`/`RefCell`/`Arc`/`Cow` in src (seeds 3-4 = 0). + +## type +- d2b-provider-guest-azure-virtual-machine#6 sev=medium blast=leaf effort=M verdict=actionable - `operation: Option` and `operation_started_at_unix_ms: Option` are always Some-together/None-together on the controller (controller/mod.rs:186-187) and in `AzureVmRecoveryState` (controller/mod.rs:110-118), and `restore_recovery_state` line 278 exists only to reject the illegal half-Some combination - fix: group into `Option` in both the controller and the recovery record, and delete the pair check at controller/mod.rs:278 - [src/controller/mod.rs:278, src/controller/mod.rs:186] + evidence: seed 1 `fn validate_\w+|fn check_\w+` = 1 hit (validate_update, controller/mod.rs:979); the Option-pair invariant read at set_operation/clear_operation (controller/mod.rs:963-970) and restore_recovery_state (controller/mod.rs:278) +- d2b-provider-guest-azure-virtual-machine#7 sev=medium blast=leaf effort=S verdict=actionable - `BootstrapAdmission { psk: Option, state: BootstrapAdmissionState }` (bootstrap.rs:65-68) can represent Consumed/Expired-with-`Some(psk)`; `consume()` manually forces `psk = None` on every transition - fix: `enum BootstrapAdmission { Pending { psk: BootstrapPsk, expires_at_unix_ms: u64 }, Consumed, Expired }` so the illegal combination is unconstructible (the skill's Option-pair smell) - [src/bootstrap.rs:65, src/bootstrap.rs:82] + evidence: seed 2 `is_\w+: bool|\w+_flag: bool` = 0, seed 3 `(mode|kind|state): String` = 0; struct and all transition sites read +- d2b-provider-guest-azure-virtual-machine#8 sev=low blast=leaf effort=S verdict=actionable - `AzureVmUpdate::Resize.size: String` is parse-validated at `validate_update` (controller/mod.rs:982) and parsed again at `apply_update` (controller/mod.rs:1008); `OpaqueAzureRef` is a validating, serde-transparent string wire type - fix: carry `size: OpaqueAzureRef` in the wire enum (JSON shape unchanged, a plain string) and drop both re-parses - [src/controller/mod.rs:82, src/controller/mod.rs:982] + evidence: seed 1 = 1 hit; `OpaqueAzureRef::parse` signature and validating `Deserialize` read at d2b-contracts/src/foundation_effects.rs:163,187 +- clean: `AzureVmRecoveryState.finalizer_installed` + `phase` invariant (finalizer false only when Finalized) is enforced once at the restore boundary (controller/mod.rs:286), which is the correct placement for a serialized record; no boolean flag soup or stringly-typed state found. + +## api +- d2b-provider-guest-azure-virtual-machine#9 sev=low blast=family effort=M verdict=actionable - the mutable-update/adoption/enrollment surface has no in-tree production caller: `update()`/`AzureVmUpdate`, `adopt()`, `complete_enrollment`, `status()`/`AzureVmStatus`, `controller_execution_ref()` are exercised only by this crate's tests, while the framework adapter (d2b-provider-guest/src/effects_service.rs) drives only `reconcile` (1303-1308), `poll_operation`/`recovery_state` (1384-1396), `finalize` (1384-1396) and `finalizer_installed` (590) - fix: wire the update path in the framework adapter (it already implements the resize/attach/detach/tags effect methods at effects_service.rs:499-565) or trim the surface - [src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748] + evidence: census: `AzureVmUpdate|complete_enrollment|controller\.adopt` over packages/ = this crate's definitions + its tests only (0 hits in d2b-provider-guest, d2bd, and all other crates) +- d2b-provider-guest-azure-virtual-machine#10 sev=low blast=leaf effort=S verdict=actionable - `AzureVmController::new` takes `effect: Arc` (controller/mod.rs:211) and stores it, but the only call site constructs a fresh `Arc::new(FrameworkAzureEffect {...})` with no sharing (d2b-provider-guest/src/effects_service.rs:1186-1189) - fix: take `effect: E` by value and store it, removing `Arc` from the public signature - [src/controller/mod.rs:211, packages/d2b-provider-guest/src/effects_service.rs:1186] + evidence: seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits (controller/mod.rs:211, 250, 183); call site read; `Arc` (with_clock) and `Arc` are the deliberate #G100 clock seam and the trait-object credential port, not flagged +- clean: seed 1 = 77 pub items, seed 3 = 8 `pub use` arms; lib.rs re-exports are the house single-surface pattern (sibling guest crates use the same `pub mod` + `pub use` shape); `AzureVmStatus` keeps private fields with accessors; `PskExtensionPayload::{len,is_empty}` are kept per refusal-ledger row #G77 (they are the inner field's only readers); `BootstrapPskDelivery` one-variant enum is a kept refusal (#G78, live construction at d2b-provider-guest/src/effects_service.rs:1892); `AzureVmConfig.tenant_id/client_id` are kept refusal #G83 (deny_unknown_fields wire fields). + +## err +- clean: skill audit `\.unwrap\(\)|\.expect\(` over src/ = 0 (all unwraps live in tests/); `let _ =`/`.ok();` = 0; `panic!|unreachable!|todo!|unimplemented!` = 0; seed 4 `enum \w*Error` = 1 hit (error.rs:7). `AzureVmError` is a closed 17-variant wire-code enum with stable `code()` strings and `Display` = code; 7 variants (ArmQuotaExceeded, ArmNetworkUnavailable, ArmCredentialDenied, ArmThrottled, CredentialUnavailable, Cancelled, DeadlineExpired) have no in-tree constructor - reserved vocabulary for the out-of-tree ARM adapter, not flagged; `Transient` is the retry signal the framework maps on. No panic-policy or taxonomy finding. + +## serde +- clean: seeds 1-4 = 21 hits; every wire type (`DiskSku`, `DataDiskSpec`, `BootstrapPskDelivery`, `AzureVmConfig`, `AzureVmGuestSettings`, `AzureVmUpdate`, `AzureVmRecoveryState`, `BootstrapServiceState`) uses `rename_all = "camelCase"` + `deny_unknown_fields`; `AzureVmHandle` is `serde(transparent)`; `AzureOperationHandle` has a hand-written base64 `Serialize`/`Deserialize` (deliberate opaque-bytes wire encoding with bounds re-checked in `from_core`); the three recovery-record bools carry `#[serde(default)]` (forward-compatible sealed records); secrets (`BootstrapPsk`, `PskExtensionPayload`, `AzureAccessToken`) never serialize; wire-value pinning and recovery round-trip tests exist (tests/lifecycle_hermetic.rs:251, 390). No finding. + +## obs +- d2b-provider-guest-azure-virtual-machine#11 sev=low blast=leaf effort=M verdict=actionable - the literal `provider = "runtime-azure-virtual-machine"` field is repeated on all 27 events and the `resource_group` field renders `OpaqueAzureRef()` via `Display` (d2b-contracts/src/foundation_effects.rs:181-184), so events that log only resource_group carry no correlation value - fix: add a `#[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))]` span on the controller entry points (reconcile, adopt, poll_operation, update, finalize) and drop the per-event literal; log zone/resource where available instead of the redacted resource_group - [src/controller/mod.rs:346, src/controller/mod.rs:425] + evidence: seed 4 `tracing::|log::` = 27 hits (bootstrap.rs 4, controller/mod.rs 23); every event read; seed 1 `println!|eprintln!` = 0, seed 2 interpolated-message-without-fields = 0, seed 3 `.instrument|#[instrument]` = 0 +- clean: all events use named fields (`zone`, `resource`, `state`, `code`, `attempts`, `stage`); no secret in any field; message-only events carry their context in fields; the ADR 0010/0028 redaction posture is respected (opaque refs pre-redacted at Display). + +## docs +- d2b-provider-guest-azure-virtual-machine#12 sev=medium blast=leaf effort=M verdict=actionable - Result-returning public methods carry no `# Errors` sections, so the framework caller cannot learn from docs which failures are transient/retryable vs fatal: `reconcile`, `adopt`, `poll_operation`, `update`, `finalize`, `complete_enrollment`, `restore_recovery_state` (controller/mod.rs:333-760), `BootstrapPsk::from_bytes`, `BootstrapAdmission::consume` (bootstrap.rs:15,82), `DataDiskSpec::validate`, `AzureVmConfig::validate`, `AzureVmGuestSettings::validate` (config.rs:49,103,177) - fix: add `# Errors` sections naming the `AzureVmError` variants each call returns, especially the `Transient` vs fatal split - [src/controller/mod.rs:333, src/controller/mod.rs:446] + evidence: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed 3 `-> Result<` = 27 hits; seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits +- d2b-provider-guest-azure-virtual-machine#13 sev=low blast=leaf effort=S verdict=actionable - `BootstrapPsk::matches` does not document the constant-time comparison guarantee that justifies its index loop over max(len) with zero-padding - fix: document "constant-time in the presented length; never exits early on mismatch" (the security contract of the loop shape) - [src/bootstrap.rs:25] + evidence: seed 1 = 77 hits; site read +- d2b-provider-guest-azure-virtual-machine#14 sev=low blast=leaf effort=S verdict=actionable - `BootstrapAdmission::consume` doc says "if the nonce is fresh" but there is no nonce; the parameter is the presented PSK bytes - fix: reword to "Consume the PSK when the presented bytes match and the deadline is valid" - [src/bootstrap.rs:82] + evidence: static read of the doc comment and the signature +- clean: `#![deny(missing_docs)]` (lib.rs:3) - every pub item has a one-line first sentence; all five modules carry `//!` docs; magic values are named (`AZURE_VM_REPAIR_INTERVAL_SECS`, `MAX_AZURE_TAGS`, `MAX_DATA_DISKS`, `MAX_LRO_AGE_MS`); no doctests exist (no `# Examples` anywhere - the crate's contract is the hermetic suite, acceptable). + +## perf +- clean: seeds `format!\(` / `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` / `\.to_string\(\)` = 0/0/0; `base32` pre-sizes with `String::with_capacity` (controller/mod.rs:1051); no hot-path allocation observed; no benchmark exists, so any perf claim would be static - none made. + +## conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` / `\bMutex<|\bRwLock<` / `Atomic\w+|Ordering::` / `thread_local!|unsafe impl (Send|Sync) for` = 0/0/0/0 in src/ (the only locks are `tokio::sync::Mutex` in tests/lifecycle_hermetic.rs, test-only synchronization); no threads, atomics, or manual Send/Sync claims exist. + +## async +- clean: seeds = 72/0/0/0 (async fns + awaits only; no `tokio::spawn`/`spawn_blocking`/`JoinSet`/`select!`/`join!` in src - the framework owns task spawning); no std lock held across an `.await` (`await_holding_lock` denied at the manifest, Cargo.toml `[lints.clippy]`); the only awaits are non-blocking `AzureEffectPort`/`AzureCredentialPort` calls; cancellation safety is structural - every state transition is re-observable via `get_vm_state` and the sealed `AzureVmRecoveryState`, so a future dropped at any await leaves a resumable state; `#[async_trait]` on both ports is justified by the `dyn AzureCredentialPort` usage; the double `arm_token()` acquisition in the Absent branch (controller/mod.rs:362,368) is deliberate token freshness across the observation await - not flagged. + +## unsafe +- N/A: seeds 1-3 (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` / `// SAFETY:` / `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; the single hit is seed 4 `unsafe_code` = `#![forbid(unsafe_code)]` (lib.rs:4), backed by `unsafe_code = "forbid"` in the manifest lints - a forbid attribute alone does not apply the lens per the card. + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` / `catch_unwind` / `repr\(C\)|repr\(transparent\)` / `CStr|CString|c_char` = 0/0/0/0; no FFI surface exists. + +## macro +- N/A: seeds `macro_rules!` / `proc_macro|syn::|quote!` / `\$crate` / `to_compile_error|new_spanned` = 0/0/0/0; no macros defined. + +## test +- d2b-provider-guest-azure-virtual-machine#15 sev=medium blast=leaf effort=M verdict=actionable - the config/PSK/handle validation contract has no rejection test: nothing constructs an invalid `AzureVmGuestSettings`/`DataDiskSpec`/`AzureVmConfig`/`BootstrapPsk`/`AzureVmHandle` and asserts `InvalidConfiguration`/`InvalidOperationHandle` (os_disk_size_gb outside 30..=4095, admin_user charset, LUN duplicates or >= 64, azure_tags > 50 or `d2b:` prefix, size_gb 0 or > 32767, label rules, empty or > 8192 PSK, handle chars), and `restore_recovery_state` rejection branches (controller/mod.rs:278-296) are untested - all tests restore valid records - fix: add a table-driven rejection test per `validate()` boundary and one invalid-record restore test - [src/config.rs:177, src/config.rs:49, src/controller/mod.rs:278] + evidence: seed 2 `assert_eq!\(|assert_ne!\(|assert!\(|matches!` = 106 hits across tests/; no test asserting `AzureVmError::InvalidConfiguration` or `InvalidOperationHandle` found in any of the 3 test files +- d2b-provider-guest-azure-virtual-machine#16 sev=low blast=leaf effort=S verdict=actionable - `every_controller_error_has_a_documented_stable_code` (tests/error_redaction.rs:17-38) asserts `!code().is_empty()` over a hand-enumerated variant list, but `code()` is a const fn whose exhaustive match makes an empty arm a compile error and the enumeration is not compiler-forced, so the test cannot meaningfully fail - fix: drop the loop and keep exact-code pinning (as `errors_and_handles_do_not_render_remote_values` already does for `arm-credential-denied`), or pin the full code table - [tests/error_redaction.rs:17] + evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 25 tests (3 bootstrap_hermetic + 2 error_redaction + 20 lifecycle_hermetic); site read +- clean: the suite asserts error variants via `matches!`/`assert_eq` on enums, never `Display` strings; deterministic (injected `FixedClock`, no sleeps, no network, scripted LRO poll queues); redaction canaries present (tests/error_redaction.rs:6-13, tests/lifecycle_hermetic.rs:390-396 assert no secret material in Debug/serialized recovery output); wire-value pinning (tests/lifecycle_hermetic.rs:251-265); `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]` on the tokio tests is the sanctioned (d)4 reason; no `#[ignore]` tests; no proptest/insta/rstest (seed 3 = 0 - the scripted-fake form fits the state machine). + +## Coverage +- idiom: 1 finding | clean (seeds: 1/1/0; index loop checked, deliberate constant-time) +- own: 4 findings | clean (seeds: 18; remaining clones explainable) +- type: 3 findings | clean (seeds: 1/0/0) +- api: 2 findings | clean (seeds: 77/3/8; refusals #G77/#G78/#G83 honored) +- err: clean (seeds: 0/0/0/1; closed wire-code taxonomy, no panic sites in src) +- serde: clean (seeds: 21; consistent camelCase + deny_unknown_fields, opaque base64 handle, forward-compatible recovery defaults) +- obs: 1 finding | clean (seeds: 0/0/0/27; named fields everywhere, no secrets) +- docs: 3 findings | clean (seeds: 77/0/27; deny(missing_docs) satisfied) +- perf: clean (seeds: 0/0/0) +- conc: N/A (seeds: 0/0/0/0 in src; only test-only tokio::sync::Mutex) +- async: clean (seeds: 72/0/0/0; no spawn/blocking/guard-across-await; resumable state machine) +- unsafe: N/A (seeds: 0/0/0/1; forbid attribute only) +- ffi: N/A (seeds: 0/0/0/0) +- macro: N/A (seeds: 0/0/0/0) +- test: 2 findings | clean (seeds: 25/106/0/0; deterministic, variant-matched, redaction canaries) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md new file mode 100644 index 000000000..d63354546 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md @@ -0,0 +1,91 @@ +# d2b-provider-guest-cloud-hypervisor - d2b-provider-guest-cloud-hypervisor +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10440 (excl. src/generated/**) | modules: adoption, bootstrap_graph, config, controller, controller_session, descriptor, guest_local, health, identity, lib, shutdown, state +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-guest-cloud-hypervisor#6 sev=low blast=leaf effort=S verdict=actionable - `CloudHypervisorController` stores `_config` (controller.rs:1712) that is never read; only `config.validate()` at 1739 uses the value - fix: drop the `_config` field and its initializer, keeping the validate() call in `from_verified_descriptor` - [controller.rs:1712, controller.rs:1744] + evidence: census `_config` over packages/ = 2 hits (field declaration + initializer), zero reads +- d2b-provider-guest-cloud-hypervisor#7 sev=low blast=leaf effort=S verdict=actionable - `observed_process_status` is controller state used only inside one `reconcile` invocation (reset at 1860, set at 2013/2016, read at 2042), a field masquerading as a local - fix: make it a local variable in `reconcile` and delete the struct field - [controller.rs:1722, controller.rs:1860, controller.rs:2042] + evidence: census `observed_process_status` over the crate = 5 hits, all inside one reconcile() body +- d2b-provider-guest-cloud-hypervisor#8 sev=low blast=leaf effort=S verdict=actionable - `deletion_rank` (shutdown.rs:487) and `upgrade_rank` (shutdown.rs:666) are byte-identical match arms duplicated across two free functions - fix: one `ChildRole::rank()` method (or single free fn) used by both planners - [shutdown.rs:487-494, shutdown.rs:666-673] + evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 0 hits; the two fn bodies are identical by static comparison +- d2b-provider-guest-cloud-hypervisor#9 sev=low blast=leaf effort=S verdict=actionable - `BootstrapGraph::readiness()` (bootstrap_graph.rs:131) hardcodes `bindings_ready`/`setup_ready` to true while the `bindings` field doc says fenced binding readiness gates VMM start; only tests call it - fix: delete the wrapper and update the test (bootstrap_graph.rs:417) to call `vmm_readiness` with explicit booleans - [bootstrap_graph.rs:131-139, bootstrap_graph.rs:417-422] + evidence: census `\.readiness\(|vmm_readiness|vmm_lifecycle` over packages/ = production call at controller.rs:662 uses vmm_lifecycle with real values, all other calls are in bootstrap_graph.rs tests +- d2b-provider-guest-cloud-hypervisor#13 sev=low blast=leaf effort=S verdict=actionable - `GuestControlEndpoint::uid()` and `endpoint_uid()` (guest_local.rs:113-121) are identical accessors with identical doc text, and `endpoint_uid()` has no caller in this crate - fix: keep one accessor and drop the other (mirror the choice in the sibling copy under finding #14) - [guest_local.rs:113-121] + evidence: census `endpoint_uid` over packages/ = 2 hits (this definition and the sibling copy's own test in d2b-resource-client/src/zone_client.rs:1067) + +## own +- clean: seeds ran `\.clone\(\)` = 127, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 31, `Rc<|RefCell<|Arc` whose only call site passes an always-empty map (`let committed = BTreeMap::new()` at controller.rs:2140), making the `committed.get(target)` branch at 2890 unreachable - fix: drop the parameter and the dead branch, delete the empty-map local - [controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895] + evidence: census `repair_children` over packages/,nixos-modules/,tests/,docs/reference/,labs/ = 2 hits (definition + the single call site with the empty map) +- d2b-provider-guest-cloud-hypervisor#2 sev=medium blast=leaf effort=S verdict=actionable - `CloudHypervisorResourceApi::assess_update` takes `children` that the production adapter discards (`let _ = children;` at controller.rs:1366, the request carries no children) while `reconcile` allocates a Vec just to drop it - fix: remove the `children` parameter from the trait method, the adapter override, and the call site (controller.rs:1907-1909) - [controller.rs:1361-1376, controller.rs:1907-1909] + evidence: err seed 2 (`let _ = |\.ok\(\);`) hit at controller.rs:1366; census of `assess_update` call sites = 1 production call plus test fakes +- d2b-provider-guest-cloud-hypervisor#3 sev=low blast=leaf effort=S verdict=actionable - `ChildMutation::expected_uid()` (identity.rs:554) always returns `None` because the UID-free batch is structurally UID-free; the only consumers are tests asserting the None (bootstrap_graph.rs:340, tests/controller.rs:206, tests/guest_spec_validation_test.rs:181) - fix: delete the accessor and the assert-None assertions - [identity.rs:554-556, tests/controller.rs:206] + evidence: census `expected_uid\(\)` over packages/ = 8 hits; the 4 ChildMutation hits are all assert-None, the rest are `ChildSpecUpdate::expected_uid` in d2bd (a different type with a real value) +- d2b-provider-guest-cloud-hypervisor#4 sev=low blast=leaf effort=S verdict=actionable - `GuestUpgradePlan::preserve_state()` (shutdown.rs:576) returns a literal `true`; its only consumer is the tautological assertion in finding #5 - fix: delete the accessor together with the assertion - [shutdown.rs:576-578] + evidence: census `preserve_state\(\)` over packages/ = 1 hit (the test assertion at finalize_ordering_test.rs:286) +- d2b-provider-guest-cloud-hypervisor#14 sev=medium blast=family effort=M verdict=actionable - `GuestControlEndpoint` is declared byte-identically in this crate (guest_local.rs:49) and in d2b-resource-client (zone_client.rs:129), the not-applied ledger row C1 with no refusal reason - fix: keep one declaration (d2b-resource-client is the consumer-facing home; d2bd/src/composition.rs:10723 constructs it) and re-export from the other - [guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256] + evidence: census `GuestControlEndpoint` over packages/ = 2 struct declarations plus consumers; ledger row C1 at docs/explanation/over-engineering-audit-record.md:472 (not applied, no refusal); both sites confirmed byte-identical at this baseline + +## err +- clean: seeds ran `\.unwrap\(\)|\.expect\(` = 108, `let _ = |\.ok\(\);` = 2, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 1, `enum \w*Error` = 10; every unwrap/expect hit is inside `#[cfg(test)]` modules or the sanctioned "fixed ..." class (`role.purpose().expect("fixed Endpoint purpose")` identity.rs:610, `expect("fixed child plan role")` controller.rs:2949, `expect("fixed owner limits")` controller.rs:2869), the two `let _ =` sites are the dropped `assess_update` parameter (finding #2) and a test abort-await, and the error taxonomy (CloudHypervisorError wrapping Descriptor/ResourceApi/LifecyclePlan via From) needs no string matching by callers. + +## serde +- clean: seeds ran `derive\([^)]*(De)?[Ss]erialize|serde\(...` = 51, `impl .*Deserialize.*for|serde_json::from_|serde_json::to_` = 6; the hand-written `Deserialize` impls (descriptor.rs, identity.rs) are live admission gates for the signed setup descriptor and child bodies, the recorded-refusal class (over-engineering-audit-record.md, refused Deserialize gates) so not re-flagged; `deny_unknown_fields` is applied on config, status, and every Wire admission struct, and the enum representations (internal tag on ChildCreateBody, transparent on OpaqueDescriptorSignature/ChildRoleSet) are deliberate wire pins covered by guest_spec_validation_test.rs. + +## obs +- clean: seeds ran `\bprintln!\(|\beprintln!\(|(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument|tracing::|log::` = 53; every tracing event uses named fields (zone/resource/error/stage), errors are logged once at the boundary that handles them via `inspect_err`, no secrets reach fields (identity-bearing Debug impls redact), and no subscriber is installed by the library. + +## docs +- d2b-provider-guest-cloud-hypervisor#15 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors`/`# Examples` sections exist anywhere in the crate (seed 2 = 0) although 114 pub items return `Result<`; e.g. `GuestSetupDescriptor::from_canonical_bytes` (descriptor.rs:423) and `GuestChildBatch::from_descriptor` (identity.rs:590) document neither failure conditions nor a usage example - fix: add `# Errors` sections to the wire-boundary constructors first (descriptor.rs, identity.rs, health.rs), then the remaining Result-returning pub items - [descriptor.rs:423-429, identity.rs:590-634] + evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 339, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 114; the crate denies missing_docs (lib.rs:3) so every item has a first sentence, but failure contracts are absent + +## perf +- d2b-provider-guest-cloud-hypervisor#16 sev=low blast=leaf effort=S verdict=actionable - `child_role_for_ref` (shutdown.rs:505) builds `format!("-{}", role.suffix())` inside the per-role loop, four String allocations per call on the per-child planning path (`plan_upgrade` at controller.rs:2340, `project_status` at controller.rs:2940) - fix: use `name.rsplit_once('-')` and compare the suffix, or a static suffix table - [shutdown.rs:505-513] + evidence: perf seed 1 `format!\(` = 6 hits, this is the only non-test production hit; static (unmeasured) + +## conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0 (one doc-comment word "atomically" is a false positive), `thread_local!|unsafe impl (Send|Sync) for` = 0; the crate declares no threads, locks, atomics, or manual Send/Sync. + +## async +- clean: seeds ran `async fn|async move|\.await` = 125, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(|tokio::sync::(Mutex|RwLock|Notify)|#\[tokio::(main|test)\]|Runtime::block_on` = 2, `tokio::sync::(Mutex|RwLock|Notify)` = 0; the fd10 bootstrap handshake and assignment-stream loop in controller_session.rs are the refused row 7 (over-engineering-audit-record.md:125, G7) so not re-flagged; `Runtime::block_on` at the process entry is the sanctioned CLI-only path with `#[allow(clippy::disallowed_methods, reason = "CLI-only path")]` (controller_session.rs:58), tokio::spawn appears only in tests, no guard is held across `.await` in src, and no blocking call sits inside an async fn. + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; the single `unsafe_code` hit is `#![forbid(unsafe_code)]` at lib.rs:4, which alone does not make the lens applicable. + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign boundary. + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the crate defines no macros. + +## test +- d2b-provider-guest-cloud-hypervisor#5 sev=medium blast=leaf effort=S verdict=actionable - `assert!(plan.preserve_state())` (finalize_ordering_test.rs:286) cannot fail because `preserve_state()` returns a literal `true` (shutdown.rs:577), an assertion of implementation rather than behavior - fix: delete the assertion together with the accessor (finding #4) - [finalize_ordering_test.rs:286] + evidence: test seeds: `#\[test\]|#\[tokio::test\]` = 52, `assert_eq!\(|assert_ne!\(|assert!\(` = 221, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the asserted accessor body is a constant + +## Coverage +- idiom: 5 findings +- own: clean (seeds ran: 127/31/0) +- type: 3 findings +- api: 5 findings +- err: clean (seeds ran: 108/2/1/10; all hits tests or sanctioned "fixed" expects) +- serde: clean (seeds ran: 51/6; admission-gate Deserialize impls are recorded-refusal class) +- obs: clean (seeds ran: 0/53) +- docs: 1 finding +- perf: 1 finding +- conc: N/A (seeds: 0/0/0/0; no threads, locks, atomics, or TLS) +- async: clean (seeds ran: 125/2/0/0; G7-refused handshake not re-flagged) +- unsafe: N/A (seeds: 0/0/0/1; only the forbid(unsafe_code) attribute) +- ffi: N/A (seeds: 0/0/0/0) +- macro: N/A (seeds: 0/0/0/0) +- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md new file mode 100644 index 000000000..4e6990948 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md @@ -0,0 +1,88 @@ +# d2b-provider-guest-qemu-media - d2b-provider-guest-qemu-media +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3,632 (src 2,688 + tests 944 (excl. src/generated (none) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) + +## idiom +- d2b-provider-guest-qemu-media#1 sev=low blast=leaf effort=S verdict=actionable - The `impl Default` bodies re-spell the serde `default_*` helper values in a second place (`"qemu-system-x86-64".to_owned()` at packages/d2b-provider-guest-qemu-media/src/config.rs:93 vs `default_qemu_artifact()` at 272; the whole GuestProviderSpecSettings default body at packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182-196 vs the serde default fns at ~440-447); two spellings of one default drift independently - fix: have the Default impls call the serde default fns (`qemu_binary_artifact_id: default_qemu_artifact()`, `vcpu: default_vcpu()`, `boot_media_view: default_boot_media_view()`( ( - [packages/d2b-provider-guest-qemu-media/src/config.rs:93, packages/d2b-provider-guest-qemu-media/src/config.rs:272, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:440] + evidence: seed2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`= 4 hits;(2 of the 4 hand-written Default impls duplicate the deserialization defaults (the other 2 are deliberate non-derivable (reconcile.rs:146 display_ready=true (qmp/mod.rs:164 delegates to `new()`. +- clean: seeds ran: 0/4/1;0 index loops;(4 hand-written Default impls (2 flagged as #1;(1 `let mut ... = Vec::new()` accumulation (flagged as perf#1; nothing else found. + +## own +- d2b-provider-guest-qemu-media#2 sev=low blast=leaf effort=S verdict=actionable - `QmpSession::execute` clones every dispatched QmpCommand into the bounded history before executing (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266); per-field borrow splitting makes the clone avoidable: push the owned command into `commands` and execute from `commands.back()` (`let Self { transport, commands, .. } = self;` then `commands.push_back(command); transport.execute(commands.back().expect("just pushed"))`(removes 1-4 String copies per QMP command - fix: destructure the two fields and reorder push/execute (drop `command.clone()` - [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266] + evidence: seed1 (`.clone()`= 9 hits;(8 of the 9 clones are required ownership moves (projections at config.rs:157, ticket slots at process_builder.rs:244,255, recovery state at reconcile.rs:297, launch-ticket process at 447-448, expected-identity persistence at 495, feature dedup at types/guest.rs:228 (this history-copy is the only avoidable one (the skill's borrow-splitting pattern. + + + +- clean: seeds ran: 9/30/0/0;(the 30 to_owned/to_vec/to_string sites are wire-string construction and owned conversions for wire fields (fine;(no Rc/RefCell/Arc/Cow. + + + +## type +- d2b-provider-guest-qemu-media#3 sev=medium blast=leaf effort=M verdict=actionable - `validate_token` (packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417(re-implements exactly the bounds of the in-tree `BoundedToken::parse` (`^[a-z][a-z0-9-]*$`, up to 63 bytes (at packages/d2b-contracts-resource/src/v3/execution_policy.rs:187-191); a second, slightly looser copy lives in `validate_object_id` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:274) - fix: replace the 7 gate calls (config.rs:142, hotplug.rs:62, process_builder.rs:288, volume.rs:121,165, guest.rs:115,213(with `BoundedToken::parse)...).is_ok()` (route qmp's variant through a first-char check plus the helper), delete the local helper - [packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417, packages/d2b-contracts-resource/src/v3/execution_policy.rs:187, packages/d2b-provider-guest-qemu-media/src/config.rs:142] + evidence: seed1 (`fn validate_\w+|fn check_\w+`= 3 hits;(validate_token definition + 7 call sites =8 matches over src/; exact bound match with the BoundedToken doc (execution_policy.rs:190-191. +- d2b-provider-guest-qemu-media#4 sev=medium blast=leaf effort=S verdict=actionable - Public `impl Default for ProviderConfig` manufactures an invalid config (`controller_execution_ref: ResourceRef::parse("Guest/invalid").expect)...)` at packages/d2b-provider-guest-qemu-media/src/config.rs:92), which fails its own `validate()` ); its only consumer is a test asserting that invalidity - fix: delete the Default impl (and rewrite the test to build valid-then-mutated configs as its sibling test at tests/config_schema_projection.rs:27 already does), or replace with a `#[doc(hidden)]` `for_test()`-style constructor - [packages/d2b-provider-guest-qemu-media/src/config.rs:89, packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs:5] + evidence: census: `ProviderConfig::default` over packages/,nixos-modules/,tests/,docs/reference/,labs/=1 hit (src: 0 (tests: 1 (packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs:5);(seed2 (`impl Default for`= 4 hits;(this is the sole Default violating its own validate). +- clean: seeds ran: 3/0/2;2 stringly-typed state String fields (volume.rs:31,75 (are mirror images of the v3 Volume wire-contract String fields (false positive (not flags (no boolean-flag soup (otherwise clean. + +## api +- d2b-provider-guest-qemu-media#5 sev=low blast=leaf effort=S verdict=actionable - Test-support exports `ScriptedQmpTransport` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129(and `ProcessIdentity::for_test` (packages/d2b-provider-guest-qemu-media/src/adoption.rs:24(are unconditionally pub+re-exported with no consumer outside this crate's own tests (while the house convention for test-only items is `#[doc(hidden)]` (see `mark_ready_for_test` at packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:327-328( - fix: mark both `#[doc(hidden)]` (or gate behind a `test-support` feature - [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129, packages/d2b-provider-guest-qemu-media/src/lib.rs:32, packages/d2b-provider-guest-qemu-media/src/adoption.rs:24] + evidence: census: `ScriptedQmpTransport` over packages/,nixos-modules/,tests/,docs/reference/,labs/,BUILD.bazel/=3 hits (`src/qmp/mod.rs:129` def + `src/lib.rs:32` re-export + `tests/qmp_protocol.rs:2`); `for_test` over the same roots = 6 hits (1 definition + 5 test uses (no external crate references either. +- clean: seeds ran: 127/0/15;(the 15 `pub use` arms in lib.rs are the house single-surface re-export pattern (false positive;(no Arc/Rc/Box/RefCell in public signatures;(nothing else found. + +## err +- clean: seeds ran: 5/1/0/9;5 unwrap/expect (4 on parsed literal constants inside Default/new (config.rs:92,99,101, volume.rs:99 (exempt (1 in #[cfg(test] (hotplug.rs:96 (exempt ( (1 swallowed Result (qmp/mod.rs:238 (deliberate best-effort rollback (logged at 233 (original error propagates ( (0 panic-family macros;(9 error enums all carry stable `code()` Display strings (closed taxonomy split by caller action (fine. + +## serde +- clean: seeds ran: 18/38/0/4; all 38 serde attr sites obey rename_all + deny_unknown_fields + default/skip_serializing_if conventions (the 3 hand-written Deserialize impls (config.rs:45, guest.rs:122,238 (are the recorded live admission gates (refused class per docs/explanation/over-engineering-audit-record.md (do not re-flag ( (the boundary is covered by real-payload and round-trip tests (tests/config_schema_projection.rs:43, tests/guest_schema_roundtrip.rs:5 (fine. + +## obs +- d2b-provider-guest-qemu-media#6 sev=low blast=leaf effort=M verdict=actionable - All 21 tracing events repeat the same two context fields (`resource = %self.guest_ref`, `provider = "runtime-qemu-media"`(inline ( ~20 sites in reconcile.rs + qmp/mod.rs:233); a span per reconcile/finalize would carry them once - fix: `#[tracing::instrument(skip(self, effect))]` on `QemuMediaController::reconcile`/`finalize` (or an explicit enter/exit span (dropping the duplicated pairs from the per-event fields - [packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:352, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:380, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:605, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:233] + evidence: seed2 (`(info|debug|warn|error|trace)!\(`= 21 hits;(all use named fields but the resource/provider pair is repeated at every event;(seed3 (`\.instrument\(|#\[instrument`= 0 spans (none to inherit them. +- clean: seeds ran: 0/21/0/21;0 println!/eprintln! in src (library isolates from stdout;(the gated fixture test prints SKIP to stderr (test-only (fine;(all 21 events carry named fields (no interpolated message-only events (no spans (finding #6 ( (21 `tracing::` sites (same set. + +## docs +- d2b-provider-guest-qemu-media#7 sev=medium blast=leaf effort=M verdict=actionable - None of the 41 `-> Result<` items carry a `# Errors` section (seed2 =0 ( (e.g. `DeviceAdmission::validate` has 6 failure kinds (device_watch.rs:82-90), `QemuMediaController::reconcile` 8 (reconcile.rs:338), `LaunchTicket::new` 3 (process_builder.rs:221) ), `QmpSession::negotiate` 3 (qmp/mod.rs:199) (leaving the caller to read the enum to map conditions - fix: add `# Errors` sections naming which conditions produce which variants on the non-obvious pub Result APIs - [packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs:82, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:338, packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:221, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:199] + evidence: seed3 (`-> Result<`= 41 hits; seed2 (`/// # (Examples|Errors|Panics|Safety)`= 0 (no canonical sections anywhere. +- clean: seeds ran: 115/0/41;`#![deny(missing_docs)]` (lib.rs:3(keeps all 115 pub items documented (the 41 Result-returning items are the # Errors gap (finding #7 ( (module docs present at every module head (fine. + +## perf +- d2b-provider-guest-qemu-media#8 sev=low blast=leaf effort=S verdict=actionable - `LaunchTicket::new` grows `attachments` by push from a fresh `Vec::new()` with an a-priori known upper bound (up to media_refs.len()+3 slots (packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239-274) - fix: `Vec::with_capacity(media_refs.len() + 3)` ( (static (unmeasured. - [packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239] + evidence: seed2 (`Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`= 10 hits;(this is the only grow-by-push site with an a priori bound (the rest are legit empty-case defaults (static (unmeasured. +- clean: seeds ran: 5/10/0;5 format! sites all one-shot cold paths (scaffold/id construction, short-key hex rendering (fine;(0 to_string copies in src (nothing else found. + +## conc +- clean: N/A (seeds: 0/0/0/0 all zero; no threads, mutexes/rwlocks, atomics/orderings, or thread_locals in src (and no tokio::sync re-exports (lens inapplicable. + +## async +- clean: N/A (seeds: 0/0/0/0 all zero; no async fn, .await, tokio::spawn/select/join, tokio::sync types, or block_on in src (this Provider's effect and QMP seams are deliberately synchronous (lens inapplicable. + +## unsafe +- clean: N/A (seeds 1-3: 0/0/0 all zero; seed4 (`unsafe_code`= 2 (manifest `forbid` (Cargo.toml:9 (and crate-level `#![forbid(unsafe_code)]` (lib.rs:4) (per U1 card seed4 alone does not make the lens applicable (no unsafe sites. + +## ffi +- clean: N/A (seeds: 0/0/0/0 all zero; no extern "C"/no_mangle, catch_unwind, repr(C/transparent, or C string types in src (the crate has no FFI surface. + +## macro +- clean: N/A (seeds: 0/0/0/0 all zero; no macro_rules!/proc-macro/syn/quote machinery in src (lens inapplicable. + +## test +- d2b-provider-guest-qemu-media#9 sev=low blast=leaf effort=S verdict=actionable - tests/lifecycle.rs repeats the same 8-field `DeviceObservation` literal ~8 times (e.g. 132-140,154-163,220-228,292-300,377-385( (each test then mutates a field or two (the fixture setup dominates the test bodies - fix: extract `fn device() -> DeviceObservation` helper (as `fn controller()` at tests/lifecycle.rs:104 already factors the bigger fixture (or build from a small builder - [packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:154, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:220, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:292, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:377] + evidence: seed1 (`#\[test\]`= 33 hits over src+tests (the 8-field literal recurs at ~8 test sites in tests/lifecycle.rs (same file already uses `fn controller()` to factor the bigger fixture (so the pattern exists. +- clean: seeds ran: 33/96/0/0 over src+tests;33 #[test] (all behavioral (effect-order events, real-payload round-trips, stable error codes( (the 96 assertions use human-written expected values (no assertion restates the implementation ( (no property/snapshot tooling (closed bound tables suffice (0 #[ignore] (the gated fixture scan (tests/fixture_projection.rs:19-22(prints SKIP when D2B_FIXTURES unset (documented gate (not an ignore. + +## Coverage +- idiom: 1 finding(s) +- own: 1 finding(s) +- type: 2 finding(s +- api: 1 finding(s +- err: clean (seeds ran: 5/1/0/9) +- serde: clean (seeds ran: 18/38/0/4) +- obs: 1 finding(s +- docs:1 finding(s +- perf:1 finding(s +- conc: N/A (seeds: 0/0/0/0 all zero; no concurrency usage) +- async: N/A (seeds: 0/0/0/0 all zero; no async code) +- unsafe: N/A (seeds 1-3: 0/0/0 all zero; seed4 = forbid manifest/lint settings only) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test:1 finding(s \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md new file mode 100644 index 000000000..1ab7d549c --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md @@ -0,0 +1,93 @@ +# d2b-provider-guest - d2b-provider-guest +Baseline: 6ebdd4cec | LOC audited: 6,423 (src 6,192 + tests 231; excl. src/generated/**: none present) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- clean: seeds: idiom1=2 (both in test loops, effects_service.rs:1916,1926), idiom2=1 (shutdown.rs hand-written Default preserving ch_api::DEFAULT_TIMEOUT - the U1 false-positive class: a field-wise derive would not preserve the invariant), idiom3=3 (justified accumulators: recursive walk (driver.rs:1348), sequential-await filter (effects_service.rs:1000), conditional push+extend (effects_service.rs:1035);; checked expression shape across src/**: no production index loops, no hand-written replaceable derives, no statement-style accumulation the skill names a pipeline for. + +## own +- d2b-provider-guest#4 sev=low blast=leaf effort=S verdict=actionable - Retiring obsolete children sorts by teardown rank plus row name by cloning every row's name String into the sort-key tuple - fix: sort with a comparator borrowing the name (`sort_by(|a,b| teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name).then_with(|| a.key.name.cmp(&b.key.name)))`), dropping the per-row allocation - [packages/d2b-provider-guest/src/driver.rs:981] + evidence: seed `\.clone\(\)` = 91 hits src; driver.rs:981 is the only clone whose purpose is the owned-key bound of sort_by_key; the name String is otherwise borrowed throughout +- d2b-provider-guest#5 sev=low blast=leaf effort=S verdict=actionable - The ACA framework controllers clone each stored candidate list before collect (`state.sandbox.clone().into_iter().collect()`), allocating an intermediate Vec per candidate read - fix: `state.sandbox.iter().cloned().collect()` (same element copies, one fewer allocation - [packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/effects_service.rs:256] + evidence: seed `\.clone\(\)` = 91 hits src; both sites clone an Option held behind tokio::sync::Mutex only to iterate it into the candidate-set newtype +- clean: remaining clones (69 further hits incl. .to_owned/.to_vec/.to_string) are ownership copies into typed request structs and dyn ports (GuestEffectRequest field copies, Arc::clone at effects-service/factory boundaries), status.resource clones into the R11 status sink/projection;, and fixture seeds - each explainable in one sentence; no Rc fields (facets.rs:59,65,and GuestTargetEffects Arc map (target_service.rs:91)are declared shared-ownership values the daemon composition root supplies (documented, not caller-derived;; test-support feature-gated doubles are the recorded test-consumed surface;; the dependency types (ResourceRef, ResourceKey, GuestTargetError etc) in signatures are in-tree workspace contract crates (publish=false paths,,not published semver surfaces. + +. + +## err +- clean: seeds 128/3/1/3; production unwrap/expect sites are 3 invariant-naming expects (driver.rs:788 "driver zone was validated at construction", driver.rs:1304 "manager keys carry canonical resource references", driver.rs:1361 "child metadata renders"), all on compiler-invisible invariants, and the remaining 125 hits live in #[cfg(test)];; the let _ sites are a ?-propagating kind-classification call (driver.rs:1041, an deliberately unused request param (effects_service.rs:941,and a test-scope drop (effects_service.rs:1934 - none swallow a Result a caller must see;; the single panic!/unreachable! is a test-only match arm (effects_service.rs:1838;; error enums are closed, context-carrying variants with static code() labels used in logs only, no wire error-code surface touched. + +. + +## serde +- clean: seeds 2/13/0/40; GuestSpec's wire gate uses rename_all camelCase, deny_unknown_fields on the Wire admission struct, flatten+skip_serializing_if+default(fns)) for the three optionality meanings, and serde_json boundary sites map errors to closed kinds; the hand-written Deserialize at guest_spec.rs:81 is the recorded live admission-gate class (over-engineering-audit-refusal, not reflagged;; the canonical-bytes test pins the exact wire shape and a hand-written JsonSchema derive covers the schema surface. + + + +## obs +- clean: seeds 0/0/0/13; all 13 tracing sites are structured events with named fields ((code=, source=, plane=?, detail=, guest=, dependency=, reason=, error=, field=, resource=; no println!/eprintln! in src (CLI product output lives elsewhere);; no secrets enter fields (tokens ride redacted types or as bounded labels;; no #[instrument] spans needed for these short per-pass contexts;; the status-sink lock sites carry recorded async-gate-allow marks (not reflagged). + +## docs +- d2b-provider-guest#7 sev=low blast=leaf effort=M verdict=actionable - No public Result-returning item carries a canonical `# Errors` doc section (docs2 seed = 0 hits src), despite #![deny(missing_docs)]]and ~107 Result-returning pub items - fix: add `# Errors` headings naming the refusal conditions on the trait/fn contracts ((facets.rs:63, target_control.rs:95, driver.rs:403, target_service.rs:68 etc.) - [packages/d2b-provider-guest/src/facets.rs:63, packages/d2b-provider-guest/src/target_control.rs:95, packages/d2b-provider-guest/src/driver.rs:403, packages/d2b-provider-guest/src/target_service.rs:68] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits src; seed `-> Result<` = 107 hits src - every Result-returning pub item is undocumented for its error contract under the rust-docs canonical-section rule +- clean: #![deny(missing_docs)] ((lib.rs:17) makes every public item carry a doc comment, and first sentences are contract-shaped across the sampled surface;; no doctests area present to rot;; magic values ((TARGET_CONTROL_TIMEOUT, GUEST_RESYNC, DEFAULT_TIMEOUT(are documented with their why. + +. + +## perf +- d2b-provider-guest#6 sev=low blast=leaf effort=S verdict=actionable - Two hex-ID builders format a fresh String per byte ((driver.rs:863-868 map(|byte| format!("{byte:02x}")) into a String, effects_service.rs:983-988 push_str(&format!)...)) in a loop), allocating ~16 and ~8 Strings per reconcile pass - fix: write! to one with_capacity String per builder (or a crate-local hex helper reusing the buffer - [packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:868, packages/d2b-provider-guest/src/effects_service.rs:983, packages/d2b-provider-guest/src/effects_service.rs:988] + evidence: static (unmeasured); seed `format!\(` = 30 hits src; the remaining format! sites are error-path/one-shot spec-name Strings ((U1 false-positive class); +- clean: seeds 30/19/5; Vec::new() sites are empty-case-common field inits ((driver.rs:791,952)or push/filter accumulators with sequential awaits/no known capacity ((effects_service.rs:630,1000,1035;; to_string() sites are error-detail conversions into failure details ((effects_service.rs:664,676,908,1000;; no hot-path collections, attacker-controlled hashing, or unbounded scans identified in production code. + + + +## conc +- d2b-provider-guest#2 sev=medium blast=family effort=M verdict=policy-confirmed - GuestStatusSink ((a pub type re-exported at lib.rs:42)is Arc>>, injecting the banned parking_lot lock type into this crate's and d2bd's public signatures; the production write sites carry recorded "synchronous path"/async-gate allows,,but every future sink caller inherits the banned type - fix: replace with Arc>>and convert the write sites to .lock().await per the replacement vocabulary - [packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, packages/d2b-provider-guest/src/effects_service.rs:1443] + evidence: seed `\bMutex<|\bRwLock<` = 23 hits src (production tokio::sync::Mutex uses at driver.rs:449,effects_service.rs:181,400,618 are the sanctioned async vocabulary; policy: clippy.toml:40-43 bans parking_lot outright (KD3; U33 carve-out revoked)and clippy.toml:82-84 names tokio::sync::Mutex::lock as the replacement;; the per-site "synchronous path" allows at the daemon write sites are the U1 (d)4 recorded-exception list, not the public type +- d2b-provider-guest#3 sev=medium blast=leaf effort=M verdict=policy-confirmed - The test-support recorder doubles and the driver test harnesses hold recorder/queue state in parking_lot::Mutex fields, which the ban covers for tests too (KD4 uniform rule,,and no per-site clippy allow exists at these sites - fix: convert to tokio::sync::Mutex with async accessors (or the documented blocking-seat helpers for worker-thread-only callers),,keeping the recorded async-gate-allow marks until converted - [packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_support.rs:171, packages/d2b-provider-guest/src/driver.rs:1534, packages/d2b-provider-guest/src/driver.rs:1761] + evidence: seed `\bMutex<|\bRwLock<` = 23 hits src (the four harness members above carry the banned type; policy: clippy.toml:40-43 (KD3, clippy.toml:82-84;; the 2026-09-16 async-purity plan KD4 includes tests in the ban;; U1 (d)2 names the R4 dedicated bounded-worker boundary as the only exception +- clean: seeds 0/23/11/0; production locks are all tokio::sync::Mutex, held briefly and never across an await ((driver.rs:449,effects_service.rs:181,400,618;; the test-only atomics order SeqCst on single-threaded doubles ((fine;,and no std::thread spawn/scope or unsafe Send/Sync claims exist in production code. + +## async +- clean: seeds 252/0/10/28; no tokio::spawn/spawn_blocking/JoinSet/select!/join! in src;; production shared state is tokio::sync::Mutex held briefly, never across an await;; the sink lock calls at effects_service.rs:1443 (and the daemon-side equivalents)carry "async-gate-allow: synchronous lock acquisition" marks and "synchronous path" clippy allows - recorded exceptions, not reflagged;; test-support recorder locks carry "async-gate-allow: test-support recorder lock" marks - recorded;; the parking_lot policy class behind those locks is recorded under conc#2/#3; no std::thread::sleep, blocking I/O,,or CPU stretches without awaits inside async fns identified in production code. + + + +## unsafe +- N/A: seeds 0/0/0; no unsafe blocks/fns/impls, no // SAFETY: or transmute/from_raw/MaybeUninit sites in src/**;; the crate manifest's [lints.rust] unsafe_code="forbid" (seed4 alone does not make the lens applicable. + +## ffi +- N/A: seeds 0/0/0/0; no extern "C"/no_mangle/link_section, catch_unwind, repr(C)/repr(transparent), or CStr/CString/c_char sites;; the crate crosses no FFI boundary (all I/O rides tokio/ttrpc/d2b-session-unix wrappers. + + + +## macro +- N/A: seeds 0/0/0/0; no macro_rules! definitions, proc_macro/syn::/quote!, $crate, or to_compile_error/new_spanned sites;; std macros ((format!, vec!, json!)) are not definitions; no DSL or impl-per-type macro need identified + +## test +- clean: seeds 42/87/0/0; tests pin the descriptor declaration and registry behavior (tests/registration.rs), the canonical spec bytes and schema vector ((guest_spec.rs),,the qemu/aca/azure reconcile+finalize+adopt+delete+status-projection semantics ((driver.rs and effects_service.rs #[cfg(test)] modules),,and the Cloud Hypervisor fail-closed shutdown (shutdown.rs;; expected values are literal or pinned constants or hand-asserted enumerations, no test restates its own implementation or computes its expectation with the logic under test;; no #[ignore], no network dependence, no property/snapshot tooling needed for the current surface;; the test-harness parking_lot policy class is recorded under conc#3. + +## Coverage +- idiom: clean (seeds ran: 2/1/3) +- own: 2 finding(s) +- type: 1 finding(s) +- api: clean (seeds ran: 114/9/7) +- err: clean (seeds ran: 128/3/1/3) +- serde: clean (seeds ran: 2/13/0/40) +- obs: clean (seeds ran: 0/0/0/13) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: 2 finding(s) +- async: clean (seeds ran: 252/0/10/28) +- unsafe: N/A (seeds: 0/0/0; no unsafe blocks; manifest forbids (seed4 alone does not make it applicable)) +- ffi: N/A (seeds: 0/0/0/0; no FFI surface) +- macro: N/A (seeds: 0/0/0/0; no macro definitions) +- test: clean (seeds ran: 42/87/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md new file mode 100644 index 000000000..536cba39a --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md @@ -0,0 +1,77 @@ +# d2b-provider-host - d2b-provider-host +Baseline: 6ebdd4cec | LOC audited: 2092 (src 1942 excl. src/generated/**, tests 150) | modules: whole crate (driver.rs, effects_service.rs, facets.rs, lib.rs, probe.rs, test_support.rs; tests/registration.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-host#1 sev=low blast=leaf effort=S verdict=actionable - stray misindented closing brace at test_support.rs:185 closes `impl RecordingMinijailGate` at 4-space indent (the fn body closes at :183, the impl at :185) - fix: reindent the stray `}` to column 0 (rustfmt would flag it) - [packages/d2b-provider-host/src/test_support.rs:185] + evidence: idiom seeds = 1 hit (seed 3 `let mut \w+ = (String|Vec)::new()` at effects_service.rs:109, a push-loop the skill's plain-for carve-out covers: side-effecting `.await` probe calls plus an early `?` return); stray brace confirmed by awk line dump, not a seed hit +- clean: seeds ran: 0/0/1; no index loops, no hand-written derives (all impls are deliberate: Debug/Display redaction via label_identity macros, Display as wire kind names), no statement-style accumulation outside the one carve-out loop + +## own +- d2b-provider-host#2 sev=low blast=leaf effort=S verdict=actionable - avoidable clones of the row key strings before parsing into identity newtypes: `ResourceTypeName::parse`/`ResourceName::parse` take `impl Into`, so `&String` converts without cloning - fix: pass `&ctx.key().type_name` / `&ctx.key().name` at driver.rs:263/266 (or `.as_str()`) - [packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266] + evidence: own seed 1 (`.clone()`) = 10 hits; the only production-code clones are these two (the rest are test fakes, test-support doubles, Arc refcount bumps, and error/status construction); parse signature at packages/d2b-contracts-resource/src/v3/identity.rs:79 +- clean: seeds ran: 10/22/0/0; remaining clones are explainable: `error.detail.clone()` (driver.rs:334, trait passes `&HostDriverError`), `self.facets.clone()` (effects_service.rs:225, one Arc refcount bump per zone respawn), `Arc::clone` at spawn-free factory create, `to_owned()` at wire/error boundaries; no Rc/RefCell/Arc/Cow in production code + +## type +- clean: seeds ran: 4/0/0; the 4 hits are `#[tokio::test] async fn validate_*` test names, not runtime validation helpers; no boolean flags, no stringly-typed state; `HostDriverErrorKind` is a closed enum splitting by caller action (refused/not-yet/retryable); the providerRef fence is the typed admission check at the decode boundary, not validate-at-every-callsite + +## api +- d2b-provider-host#3 sev=low blast=leaf effort=S verdict=actionable - dead `pub` visibility on seven items in the private `mod driver` that are never re-exported: `HostDriver`, `HostDriverError`, `HostDriverStatus`, `HostDriverFactory`, `HostDriverEffects`, `host_spec_decoder`, `HOST_REOBSERVE` - fix: make them `pub(crate)` (the live surface is the lib.rs re-export set: host_descriptor, HOST_EFFECTS_SERVICE, HostEffectsServiceFactory, HostEffectFacets, MinijailPlatformGateSource, production_probe, the three probe constants, MinijailPlatformGate) - [packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111, packages/d2b-provider-host/src/driver.rs:147, packages/d2b-provider-host/src/driver.rs:174, packages/d2b-provider-host/src/driver.rs:189, packages/d2b-provider-host/src/driver.rs:206, packages/d2b-provider-host/src/driver.rs:239] + evidence: api seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) = 35 hits; census: `HostDriverError|HostDriverStatus|HostDriverFactory|HostDriverEffects|host_spec_decoder|HOST_REOBSERVE` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 code hits outside the crate (2 README.md prose mentions only); `HostDriver::new` is already `pub(crate)` while its type is `pub`, marking the visibility as accidental +- clean: seeds ran: 35/7/5; the `Arc` in public signatures (facets.rs:34, probe.rs:82-83, driver.rs:208/240) is genuine shared ownership - the same probe Arc is handed to the driver factory, the effects service, and the daemon composition root (d2bd/src/process_provider_runtime.rs:192-196, d2bd/src/shared_provider_effects.rs:3444); lib.rs `pub use` arms are the house single-surface pattern and every re-export has an external consumer (d2bd/src/resource_plane_v3.rs:64, provider_lifecycle.rs:43) + +## err +- d2b-provider-host#4 sev=low blast=leaf effort=S verdict=actionable - the `HostDriverEffects::observe_host` seam returns `Result`: the production impl flattens the probe error and the fallback reconcile error into one `format!("{probe_error}; {error}")` message, losing the source chain; an internal crate per the skill wants an enum (or thiserror with `#[source]`) - fix: introduce a small closed error enum (e.g. `ObserveError { Probe(SystemCoreError), Reconcile(String) }` with `#[source]`) on the trait and both impls - [packages/d2b-provider-host/src/driver.rs:197, packages/d2b-provider-host/src/effects_service.rs:180] + evidence: err seed 1 (`.unwrap()|.expect()`) = 39 hits, all in `#[cfg(test)]` modules or test-support; seed 4 (`enum \w*Error`) = 1 hit; the String seam is the only untyped error in the crate (caller maps it to a FailureDetail note, no string-matching today, so low not medium) +- d2b-provider-host#5 sev=low blast=leaf effort=S verdict=actionable - `HostDriverError::Display` re-spells the three failure-kind codes ("system-core-spec-invalid", "system-core-host-observation-failed", "system-core-drain-pending") that `HostDriverErrorKind::failure_kind()` already maps to, so a registry-code rename drifts silently - fix: `formatter.write_str(self.kind.failure_kind().code())` using the public `FailureKind::code()` - [packages/d2b-provider-host/src/driver.rs:129, packages/d2b-provider-host/src/driver.rs:99] + evidence: err seed 4 = 1 hit; `FailureKind::code()` is public and registry-backed (packages/d2b-resource-runtime/src/error.rs:980, docs/reference/resource-runtime-failure-kinds.md generated from it) +- clean: seeds ran: 39/0/0/1; production code has zero unwrap/expect/panic sites; the 39 unwrap/expect hits are all in `#[cfg(test)]` and test-support doubles with named invariants ("uncontended test mutex"); `HostDriverErrorKind` splits by caller action and maps onto the registered failure kinds + +## serde +- clean: seeds ran: 0/0/0/4; the four `serde_json::from_`/`to_` hits are boundary decodes with error mapping: the spec decoder (driver.rs:175), the HostSpec admission decode of the canonical base (driver.rs:292), and the `inspect-host` payload built through the canonical JSON object path (effects_service.rs:75, from_value over json! - the documented escape-safe route); no hand-written Deserialize, no wire type defined in this crate + +## obs +- N/A: seeds 0/0/0/0; the crate carries no tracing/log dependency (Cargo.toml [dependencies] has none) and emits no telemetry of its own - the effects service returns structured payloads instead + +## docs +- d2b-provider-host#6 sev=low blast=leaf effort=S verdict=actionable - `HostDriverEffects::observe_host` is the one pub Result-returning item whose doc contract lacks an `# Errors` section: "or report why the observation could not be taken" does not enumerate the failure conditions (probe failure -> retryable HostObservation; spec decode -> SpecInvalid) - fix: add `# Errors` listing the two failure conditions and their classification - [packages/d2b-provider-host/src/driver.rs:189] + evidence: docs seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits across 34 pub items; the crate is `#![deny(missing_docs)]` (lib.rs:25) and every pub item carries a first-sentence doc, so this is the remaining contract gap +- clean: seeds ran: 34/0/30; module docs present in all six modules; magic values documented with the why (HOST_REOBSERVE echoes the old 5s resync, the probe constants pin cross-family agreements); no `ignore`d doctests (no doctests at all) + +## perf +- clean: seeds ran: 2/13/1; all hits are cold-path or test code: `format!("/sys/module/{}")` in the per-reconcile Usbip probe (probe.rs:174), the error-path `format!` (effects_service.rs:180), `Vec::new()` in test fakes and the fixed 11-class capability loop (one probe per reconcile); `to_string()` once in runtime_path building; no hot loop allocates; static (unmeasured) + +## conc +- clean: seeds ran: 0/7/11/0; every Mutex/atomic hit lives in test-support doubles and unit-test fakes (tokio::sync::Mutex + try_lock with "uncontended test mutex" expects, SeqCst script flags) - appropriate for test doubles; production code holds no shared state, spawns no threads, and declares no manual Send/Sync + +## async +- clean: seeds ran: 112/0/14/19; production async code uses the sanctioned vocabulary: `tokio::fs::read_dir` for /proc and /dev/dri enumeration (probe.rs:112/129); the two synchronous-path sites (`read_bounded` std::fs::File::open + read_to_end, `is_socket` std::fs::metadata) carry per-site `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` - a sanctioned reason tracked by the blocking census (baseline packages/xtask/data/blocking-census-baseline.json lists the crate all-zero because the allows exempt the sites); no guard held across `.await`; no spawn/select!/join!; no cancellation-sensitive irreversible step (probes are read-only); no async-gate-allow markers in the crate + +## unsafe +- N/A: seeds 0/0/0/0; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) alone does not make the lens applicable + +## ffi +- N/A: seeds 0/0/0/0; no extern "C", no repr(C), no CStr/CString anywhere in the crate + +## macro +- N/A: seeds 0/0/0/0; no macro_rules!, no proc-macro/syn/quote usage in the crate + +## test +- clean: seeds ran: 23/71/0/0; 23 test fns (19 `#[tokio::test]` in src, 3 `#[tokio::test]` + 1 `#[test]` in tests/registration.rs) assert observable behavior: report fields, failure classes (not Display strings), error variants, call orders, requeue counts, and the one-observation-per-generation invariant; the live-host probe test documents its non-degenerate guard (probe.rs:251-256); no `#[ignore]`, no flaky clock/network dependence; registration.rs is the policy-required registration boundary test (provider crate policy) + +## Coverage +- idiom=1 | clean | N/A: - +- own=1 | clean | N/A: - +- type: clean (seeds ran: 4/0/0) +- api=1 | clean | N/A: - +- err=2 | clean | N/A: - +- serde: clean (seeds ran: 0/0/0/4) +- obs: N/A (seeds: 0/0/0/0; no tracing/log dependency in Cargo.toml) +- docs=1 | clean | N/A: - +- perf: clean (seeds ran: 2/13/1) +- conc: clean (seeds ran: 0/7/11/0) +- async: clean (seeds ran: 112/0/14/19) +- unsafe: N/A (seeds: 0/0/0/0; manifest `unsafe_code = "forbid"` alone does not make the lens applicable) +- ffi: N/A (seeds: 0/0/0/0) +- macro: N/A (seeds: 0/0/0/0) +- test: clean (seeds ran: 23/71/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md new file mode 100644 index 000000000..11485f475 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md @@ -0,0 +1,79 @@ +# d2b-provider-network-local - d2b-provider-network-local +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11234 (excl. src/generated/**, src 9346 + tests 1888) | modules: whole crate (artifact, bridge_port, broker, controller, diagnostics, driver, effects_service, facets, ifname, netlink, nftables, observe, operations, plan, routes, test_support) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: n/a (single lane) + +## idiom +- d2b-provider-network-local#1 sev=low blast=leaf effort=S verdict=actionable - octet-to-string conversion collects a Vec of four Strings and joins it, where one format! suffices - fix: destructure the parsed octets (`let [a, b, c, d] = octets; Some(format!("{a}.{b}.{c}.{d}"))`) instead of `.collect::>().join(".")` - [src/controller.rs:298-302] + evidence: idiom seed `let mut \w+ = (String|Vec)::new\(\)` count 10; the site is the collect-then-convert shape the skill names (reviewed statically) +- d2b-provider-network-local#2 sev=low blast=leaf effort=S verdict=actionable - declared_dependency_refs accumulates into `let mut refs = Vec::new()` with a nested if-push, where a filter_map pipeline fits - fix: `spec.pointer("/spec/attachments").and_then(Value::as_array).into_iter().flatten().filter_map(|a| a.get("executionRef").and_then(Value::as_str).and_then(|v| ResourceRef::parse(v.ok()()).collect()` - [src/driver.rs:377-393] + evidence: idiom seed `let mut \w+ = (String|Vec)::new\(\)` count 10 (direct hit at driver.rs:378) + +## own +- d2b-provider-network-local#3 sev=low blast=leaf effort=S verdict=actionable - collision-detection BTreeSet stores owned Strings from borrowed &str keys, though the set never outlives the borrow - fix: `let mut unique_interfaces = BTreeSet::new();` and insert `ifname.as_str()` (a set of `&str` borrowing interface_names for its whole short life)) - [src/controller.rs:416-417] + evidence: own seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` count 85; sampled: 50 of 206 own hits (every 5th; the borrow lives only inside the fn, no caller census needed) + +## type +- clean: seeds: `fn validate_\w+|fn check_\w+` 14, `is_\w+: bool|\w+_flag: bool` 1), `(mode|kind|state): String` 0; every validator takes already-parsed types (TapRole, BridgePortFlagSet, DefaultRouteState, ReconcileInput)...) and the one bool is a single config flag, not flag soup; no illegal-state combos found + +## api +- d2b-provider-network-local#4 sev=medium blast=leaf effort=S verdict=actionable - two pub route validators are exported with zero production callers (only crate-internal unit tests), and the wrapper carries a stale `#[allow(dead_code)]` on a pub item - fix: lower both to `pub(crate)` (unit tests still reach them)and remove the dead_code allow, or wire them into BrokerNetworkEffectPort::apply_routes/remove_routes which currently resolve intents without these checks - [src/routes.rs:244-279, src/routes.rs:264-265] + evidence: census: `validate_network_route_intent` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 7 hits (all in src/routes.rs: def 245, wrapper call 276, tests 525/534, wrapper def 265, wrapper tests 568/579); `validate_network_route_intent_with_provenance` = 3 hits (all in src/routes.rs; sampled: 50 of 328 api hits + +## err +- d2b-provider-network-local#5 sev=low blast=leaf effort=S verdict=actionable - the sole non-test unwrap (SHA-256 word slice conversion() carries no named invariant, though the 4-byte length is statically known - fix: `u32::from_be_bytes(chunk[offset..offset + 4].try_into().expect("4-byte chunk word"))` or a slice-pattern destructure - [src/nftables.rs:588] + evidence: err seed `\.unwrap\(\)|\.expect\(` count 155 (154 are cfg(test) fixtures or literal canonical-ref expects at operations.rs:139-202; this singleton is production code) + +## serde +- d2b-provider-network-local#6 sev=medium blast=leaf effort=M verdict=actionable - the stored-spec parse maps serde failure to `()` unit, dropping the deserialization reason before the toolkit's SpecInvalid terminal - fix: log the serde error (add a tracing::debug/warn at driver.rs:289 before the map)) or return `Result` and let the driver surface the reason; do not touch the pinned SharedProviderDeclarationError enum - [src/driver.rs:282-289, src/driver.rs:190] + evidence: serde seed `serde_json::from_|serde_json::to_` count 29 (this site maps from_value failure to ()); `derive)...Serialize...)` 0 +- d2b-provider-network-local#7 sev=low blast=leaf effort=S verdict=actionable - provenance serialization failures are silently `.ok()`-swallowed into a missing wire field at four payload builders, while the sibling update-hosts path propagates with map_err - fix: match broker.rs:1368: `.map(serde_json::to_value).transpose().map_err)...)` at all four sites (operations.rs maps to OperationFailure::with_detail(KERNEL_REFUSED, ...)) - [src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429] + evidence: serde seed `serde_json::to_` count 29 (4 of which are `.ok()`-swallowed; sibling at broker.rs:1368 uses map_err) + +## obs +- clean: seeds: `\bprintln!\(|\beprintln!\(` 0,, `(info|debug|warn|error|trace)!\("` 0,, `\.instrument\(|#\[instrument` 0,, `tracing::|log::` 4; all four tracing events carry named fields (`broker_kind = %code`, `provider = "network-local"`, `network_uid = ...`) and no secret or interpolated message + +## docs +- d2b-provider-network-local#8 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub items (~151 sites() carry no `# Errors` section naming their failure conditions, despite `#![deny(missing_docs)]` giving every item a first sentence - fix: add canonical `# Errors` sections to the boundary-facing Result fns (at least: resolve_net_vm_system_artifact, validate_readback, validate_network_route_intent, observe_host_network, NetworkReconciler::reconcile/finalize,and the broker kernel adapters)) - [src/artifact.rs:67, src/bridge_port.rs:151, src/routes.rs:245, src/observe.rs:255, src/controller.rs:1096] + evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` 302,, `/// # (Examples|Errors|Panics|Safety)` 0,, `-> Result<` 151; sampled: 50 of 453 docs hits (every 10th; first-sentence quality checked across all modules - mostly strong, no magic values left unexplained) + +## perf +- d2b-provider-network-local#9 sev=low blast=leaf effort=S verdict=actionable - FirewallDigest::to_hex formats each byte into its own String (32 heap allocations per call), though the output size is known - fix: `let mut out = String::with_capacity(64); for byte in &self.0 { use std::fmt::Write; write!(out, "{byte:02x}").expect("writing to String is infallible"); } out` - [src/nftables.rs:266-268] + evidence: static (unmeasured); perf seed `format!\(` count 54; to_hex is cross-crate used (d2bd resource_plane_v3.rs:322/533 socket identity keys, process_provider_runtime.rs:3041 log field)) +- d2b-provider-network-local#10 sev=low blast=leaf effort=S verdict=actionable - observed-address parse allocatesa fresh String per entry via `format!("{local}/{prefix}")`, inside the host-observation parse path - fix: build the CIDR text into a reused buffer or add a two-part Ipv4Cidr constructor to the contracts crate - [src/observe.rs:305] + evidence: static (unmeasured); perf seeds: `format!\(` 54,, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 61,, `\.to_string\(\)` 10 + +## conc +- clean: seeds: `std::thread::|thread::spawn|thread::scope` 1 (broker.rs:1662 test poll-loop yield_now), `\bMutex<|\bRwLock<` 7 (all test fixtures; the parking_lot sites carry async-gate-allow markers - recorded exceptions, clippy.toml:40-43,82-84), atomics/Ordering 0,, thread_local/unsafe-Send-Sync 0; no shared-state or atomic-ordering claims in production code + +## async +- d2b-provider-network-local#11 sev=low blast=leaf effort=S verdict=actionable - observe_host_network awaits three independent `ip` observations sequentially, where tokio::join! would run them concurrently - fix: `let (links, addresses, routes)= tokio::join!(run_ip(&["-j", "-d", "link", "show"]), run_ip(&["-j", "-4", "addr", "show"]), run_ip(&["-j", "-4", "route", "show", "table", "all"]));` then parse - [src/observe.rs:255-260] + evidence: async seed `async fn|async move|\.await` count 123 (the three sequential process awaits at observe.rs:256-258 are independent - no data dependency); spawn/JoinSet 0; tokio::sync::* 6 (test fixtures); tokio::test 5; block_on 0 in src; elsewhere kernel invocations run through async kernel_seat::run (operations.rs:249-264) and process calls carry timeouts (observe.rs:420-437); no lock is held across an await in production code, and test-support parking_lot locks carry async-gate-allow markers (test_support.rs:68-80) - deliberate exceptions + +## unsafe +- clean: seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0,, `// SAFETY:` 0,, `transmute|from_raw|MaybeUninit|mem::zeroed` 0,, `unsafe_code` 0 in src; lens N/A (no unsafe code; manifest forbids - Cargo.toml:5)) + +## ffi +- clean: seeds: `extern "C"|no_mangle|unsafe\(link_section` 0,, `catch_unwind` 0,, `repr\(C\)|repr\(transparent\)` 0,, `CStr|CString|c_char` 0; lens N/A (no FFI surface in the crate) + +## macro +- clean: seeds: `macro_rules!` 1 (bridge_port.rs:157 local field-check macro - acceptable impl-per-field generation for nine flags, hygiene trivial), `proc_macro|syn::|quote!` 0,, `\$crate` 0,, `to_compile_error|new_spanned` 0; no macro needs rework + +## test +- clean: seeds: `#\[test\]|#\[tokio::test\]` 95,, `assert_eq!\(|assert_ne!\(|assert!\(` 252 (over src+tests), `proptest!|insta::assert|rstest` 0,, `#\[ignore\]` 0;; sampled: 50 of 347 test hits; all 6 test files read - table-driven cases (broker.rs:1844), error variants asserted not Display strings (netlink.rs:437, observe.rs:730), deterministic, no network; fd-passing test exercisesa real socketpair with rustix ScmRights (network_family.rs:200-220); block_onin plain #[test] harnesses is the sanctioned pattern + +## Coverage +- idiom: 2 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 14/1/0) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: 2 finding(s) +- obs: clean (seeds ran: 0/0/0/4) +- docs: 1 finding(s) +- perf: 2 finding(s) +- conc: clean (seeds ran: 1/7/0/0) +- async: 1 finding(s) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe code, manifest forbids) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: clean (seeds ran: 1/0/0/0) +- test: clean (seeds ran: 95/252/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md new file mode 100644 index 000000000..0f9bd1722 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md @@ -0,0 +1,84 @@ +# d2b-provider-notification-desktop - d2b-provider-notification-desktop +Baseline: 6ebdd4cec | LOC audited: 5712 (excl. src/generated/**; none present) | modules: whole crate (17 src files, 5 tests files) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- d2b-provider-notification-desktop#1 sev=low blast=leaf effort=S verdict=actionable - `expected_acknowledgements` accumulates its two source acknowledgement arms with `Vec::new()` + `extend(iterator)` where the chain could collect the Vec directly - fix: `let mut acknowledgements: Vec<_> = plan.start_endpoints.iter().map)...).chain(plan.stop_endpoints.iter().map)...)).collect();` then keep the two conditional `HostSink` pushes - [packages/d2b-provider-notification-desktop/src/controller.rs:660-675] + evidence: seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) = 4 hits; this site is the actionable one (lifecycle.rs:403-405 accumulations track side-effecting plan application and are not collect-able) +- d2b-provider-notification-desktop#2 sev=low blast=leaf effort=S verdict=actionable - `NotificationProviderDescriptor::service_package()` hardcodes the wire literal `"d2b.notification.v3"` duplicating the exported `SERVICE_PACKAGE` const - fix: return `crate::SERVICE_PACKAGE` so the literal has one home - [packages/d2b-provider-notification-desktop/src/descriptor.rs:43-44, packages/d2b-provider-notification-desktop/src/lib.rs:70] + evidence: seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 1 hit (descriptor.rs:32 manual `Default` preserving the `schema_version=1` invariant - false positive); static read: literal duplicated from the exported const + +## own +- d2b-provider-notification-desktop#3 sev=low blast=leaf effort=S verdict=actionable - `commit_reconciliation` takes `SourceReconcileResult` by value but only reads its fields, forcing `.clone()` at both call sites - fix: take `result: &SourceReconcileResult` and drop the two `.clone()` calls - [packages/d2b-provider-notification-desktop/src/controller.rs:1033, packages/d2b-provider-notification-desktop/src/controller.rs:1058, packages/d2b-provider-notification-desktop/src/controller.rs:1297-1318] + evidence: seed 1 (`\.clone\(\)`) = 91 hits; these two are avoidable because `commit_reconciliation` reads only `result.stop/start_endpoints/start_host_sink/stop_host_sink/host_sink_fingerprint` +- d2b-provider-notification-desktop#4 sev=low blast=leaf effort=S verdict=actionable - `NotificationLifecycleSupervisor` wraps its owned backend in `Arc`, counting one reference that nothing else shares - fix: store `backend: B` directly (drop `Arc`) while keeping the `Send + Sync` bounds - [packages/d2b-provider-notification-desktop/src/lifecycle.rs:338, packages/d2b-provider-notification-desktop/src/lifecycle.rs:346] + evidence: seed 3-4 (`Rc<|RefCell<|Arc` sites (controller, lifecycle, guest_source, runtime) form a stringly error family forcing callers to string-match, while sibling enums (AdmissionError, NotificationError, SinkError)_ are typed - fix: introduce one crate error enum (suggest `NotificationLifecycleError`) for the lifecycle/controller/config family and replace the str returns on pub fns and both effect-port traits; update d2bd's `InteractionNotificationLifecycleBackend` impl - [packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provider-notification-desktop/src/lifecycle.rs:291-297, packages/d2b-provider-notification-desktop/src/controller.rs:369, packages/d2b-provider-notification-desktop/src/controller.rs:930] + evidence: seed 4 (`enum \w*Error`) = 7; grep `Result<[^>]*, &'static str>` over src/*.rs = 50 hits; tests match on the strings (guest_source.rs:100-115), so callers string-match +- d2b-provider-notification-desktop#10 sev=medium blast=leaf effort=S verdict=actionable - Delivery rejection paths collapse every admission/session/category failure into `NotificationError::InvalidOpaqueKey`, misreporting "notification-opaque-key-invalid" for unauthenticated, cross-zone,and category-denied cases - fix: add an `NotificationError::Denied` (or `SessionDenied`) variant and map the five admission/zone/category rejection sites to it; keep `InvalidOpaqueKey` for key-bound violations - [packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-notification-desktop/src/host_sink.rs:195, packages/d2b-provider-notification-desktop/src/host_sink.rs:202, packages/d2b-provider-notification-desktop/src/host_sink.rs:308, packages/d2b-provider-notification-desktop/src/runtime.rs:103] + evidence: seed 2 (`let _ = |\.ok\(\);`) = 0; static read: `InvalidOpaqueKey` used as catch-all at 9 sites (host_sink.rs:185-308, runtime.rs:103-129); slug not pinned by docs/reference (grep "notification-" = 0 hits) + +## serde +- clean: seeds ran: 6/13/2/0 - derive(Serialize/Deserialize)=6; serde attrs=13; hand-written Deserialize=2 (live admission gates for the wire twins at types.rs:232/307, sanctioned per record rows 143/151); serde_json=0 in src. Wire shapes land through deny_unknown_fields gates + TryFrom validation - clean + +## obs +- clean: seeds ran: 0/24/0/4 - println!/eprintln!=0; tracing event macros=24, all with named fields (provider, zone, reason, action) + static messages; interpolated-message-with-no-fields events=0; instrument/spans=0 (sync provider path, no async context to carry); `use tracing` lines=4. All events carry the provider/zone/reason context as fields - clean + +## docs +- d2b-provider-notification-desktop#11 sev=medium blast=leaf effort=M verdict=actionable - No `# Errors` section exists on any Result-returning pub item (112 `-> Result<` sites) even though the crate pins wire-leaning error enums - fix: add `# Errors` sections naming the exact variants (or stable slugs) on pub fns like `ActionNonceStore::register`, `NotificationRuntime::new`, `NotificationSink::deliver_from_guest_source` - [packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provider-notification-desktop/src/runtime.rs:64-67, packages/d2b-provider-notification-desktop/src/host_sink.rs:297-305] + evidence: seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 across 229 pub items (seed 1 = 229, seed 3 `-> Result<` = 112) +- d2b-provider-notification-desktop#12 sev=low blast=leaf effort=S verdict=actionable - Doc first sentences are broken fragments: "/// the daemon." opens `deliver_evidence`,"/// completes every effect immediately." opens `RecordingEffects`,"/// the current authenticated reconnect generation." runs into the `from_config_at_generation` doc - fix: rewrite each as a standalone 15-word summary before the trailing paragraph - [packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-notification-desktop/src/test_support.rs:14, packages/d2b-provider-notification-desktop/src/guest_source.rs:17] + evidence: static read: first-sentence shape at the three anchors ("the daemon."/"completes every effect immediately."/"the current authenticated...") + +## perf +- d2b-provider-notification-desktop#13 sev=low blast=leaf effort=S verdict=actionable - `NotificationSink::deliver` formats "notification-{id}" once (request_id) but re-formats the same string three more times into projection map keys; `close` re-formats from u32 while callers already hold the request_id string - fix: reuse `request_id` (clone it into map keys where needed)and add an internal `close_by_request_id(&str)` to kill the u32-to-String-to-u32 round-trip in `close_session`/`gc_projections` - [packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-notification-desktop/src/host_sink.rs:276-291, packages/d2b-provider-notification-desktop/src/host_sink.rs:376, packages/d2b-provider-notification-desktop/src/host_sink.rs:484-493] + evidence: seed 1 (`format!\(`) = 16 hits; four-plus of them re-format a string the caller already owns (host_sink.rs:265 vs 276/278/288/291; close at 376 vs callers holding request_id); static (unmeasured) + +## conc +- clean: seeds ran: 0/1/0/0 - std::thread/spawn/scope=0; Mutex/RwLock=1 (lifecycle.rs:339 `state: Mutex` on sanitary synchronous path, guarded by tracked allows at lifecycle.rs:355/394/538 with reason "synchronous path"); Atomics/Ordering=0; thread_local!/unsafe impl Send/Sync=0 - clean + +## async +- N/A (seeds: 0/0/0/0 all zero; the crate declares no async fn, await, spawn, or tokio runtime usage) + +## unsafe +- N/A (seeds: 0/0/0/1; seeds 1-3 all zero; the lone seed 4 hit is `#![forbid(unsafe_code)]` at lib.rs:4, which per the lens card does not make the lens applicable) + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, repr(C/transparent), CStr/CString, or catch_unwind in src) + +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, proc-macro, or syn/quote usage) + +## test +- clean: seeds ran: 41/131/0/0 - #[test]=41 (25 src + 16 tests); asserts=131 (86 src + 45 tests); proptest!/insta/rstest=0; #[ignore]=0; tests are behavioral (wire defaults, redaction canary, receipt matching, partial-effect rollback, nonce single-use/bounds, closed telemetry labels)and deterministic (injected now_secs, no network or clock reads)- clean + +## Coverage +- idiom: 2 finding(s) +- own: 2 finding(s) +- type: 1 finding(s) +- api: 3 finding(s) +- err: 2 finding(s) +- serde: clean (seeds ran: 6/13/2/0) +- obs: clean (seeds ran: 0/24/0/4) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 0/1/0/0) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn/await/spawn/runtime) +- unsafe: N/A (seeds: 0/0/0/1; seeds 1-3 zero; seed 4 alone is the forbid attribute) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 41/131/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md new file mode 100644 index 000000000..ffe9f1bf9 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md @@ -0,0 +1,99 @@ +# d2b-provider-observability-otel - d2b-provider-observability-otel +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3766 (excl. src/generated/**) | modules: whole crate (agent, config, controller, emitter_socket, ingress_policy, lib, metric_policy, metrics; tests: binding_controller, ingress_metric_policy) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none + +## idiom +- clean: seeds ran: 2/3/0; two `for _ in 0..` loops are test harnesses (ingress_policy.rs:905,1080),and the three hand-written `Default` impls preserve invariants the field-wise derive would break (config.rs:137, controller.rs:364, ingress_policy.rs:268), per U1 lens-card false-positive class. + + + +## own +- d2b-provider-observability-otel#1 sev=low blast=leaf effort=S verdict=actionable - provider-agent methods clone their input strings only to hand them to a token parser, though parse_closed_token could borrow - fix: change parse_token/parse_closed_token (agent.rs:224-244) to take `value: &str` (BoundedToken::parse takes `impl Into`, so `&str` satisfies it),and drop the five `clone()` calls in session_connect/process_effect - [agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285, agent.rs:288] + evidence: seed `\.clone\(\)` over src = 17 hits (7 in agent.rs;5 avoidable via the borrow-taking parse;2 at agent.rs:332-333 required for ownership transfer into `ToolkitAuditEvent::new`) + + +## type +- d2b-provider-observability-otel#2 sev=low blast=leaf effort=S verdict=actionable - ProviderAgentAuditEvent stores the four closed audit strings as `String`/`Option` and immediately discards the validated `BoundedToken` (parse-then-copy-back at as_str().to_owned()) - fix: store `BoundedToken`/small enums in the event fields (agent.rs:59,66-68),and render through `BoundedToken::as_str` in the Serialize impl (wire output unchanged) - [agent.rs:56, agent.rs:265, agent.rs:297] + evidence: seeds ran: `fn validate_|fn check_` = 3 hits (all boundary validators), `is_: bool|flag: bool` = 0, `(mode|kind|state): String` = 0; reading: event/authz_decision/provider/domain are parsed into `BoundedToken` (agent.rs:230-298) then converted back to String for storage + + +## api +- clean: seeds ran: 121 pub items/1 Arc-in-signature/6 re-export arms; `pub use` re-export arms in lib.rs are the house single-surface pattern (U1 lens-card FP),and the sole `Arc` signature (ingress_policy.rs:331)is justified shared ownership - tests create one ManualClock and clone the Arc into multiple gates (ingress_policy.rs:902,1208,1286) + + +## err +- d2b-provider-observability-otel#3 sev=low blast=leaf effort=S verdict=actionable - when the connection-tracking table is full, reject() reports `IngressErrorClass::Malformed` ("frame could not be decoded") though the frame may be valid, whereas the sibling capacity refusal reports `None` - fix: return `IngressOutcome::Rejected, IngressErrorClass::None)` on that branch(or a distinct class, if one is introduced for wire labeling),consistent with the capacity path at ingress_policy.rs:460 - [ingress_policy.rs:647] + evidence: reading of reject() full-table branch; seed `let _ = |\.ok\(\);` = 7 hits (all deliberate best-effort cleanups or test drills),and wire-visible error classes are the `as_str` labels of IngressErrorClass (ingress_policy.rs:87-91) + + +## serde +- clean: seeds ran: 1/0/1/10; the hand-written `Deserialize` for ProviderConfig (config.rs:127)is a live strict admission gate over untrusted config (the recorded refusal class: hand-written Deserialize admission gates - do not re-flag),the hand-written `Serialize` for ProviderAgentAuditEvent (agent.rs:68)and ProviderConfig (config.rs:118) render redacted/canonical shapes deliberately,and all serde_json sites are round-trip tests or the deliberate canonical-size measurement + + +## obs +- clean: seeds ran: 0/0/0/3; zero println/format-interpolated events(only message-only events with named fields: provider, binding, ingress, outcome, error_class, connection),all diagnostic events carry `provider = "observability-otel"` as a field,andzone/source redaction lives in the Debug/Serialize overrides (deliberate; agent.rs:72-86,88-99) rather than in log calls + + + + + +## docs +- d2b-provider-observability-otel#4 sev=medium blast=leaf effort=S verdict=actionable - the three crate-identity constants `PROVIDER_NAME`,`PROVIDER_REF`,`PROVIDER_API_MAJOR` in lib.rs lack doc comments while every sibling public item in the crate carries one - fix: add one-line doc comments naming each constant's role (mirroring the documented `OTEL_HOST_BRIDGE_ROLE` on the next line) - [lib.rs:13, lib.rs:14, lib.rs:15] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 121 hits over src; the three constants are the only bare undocumented pub items found by reading lib.rs +- d2b-provider-observability-otel#5 sev=medium blast=leaf effort=M verdict=actionable - Result-returning pub API fns lack `# Errors` doc sections naming their failure conditions, leaving callers to infer variants from code - fix: add `# Errors` sections to at least the five representative fns (ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream,EmitterSocket::bind/drain_once, validate_resource_attributes),enumerating e.g. `ProviderAgentError::{SessionDenied,AuditBackpressure,InvalidInput}` - [agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131, metric_policy.rs:21] + evidence: seed `-> Result<` = 22 hits (11 of them pub fn signatures across 6 modules); none of the pub Result fns' doc comments contain a `# Errors` section (seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits over src) + + +## perf +- d2b-provider-observability-otel#6 sev=low blast=leaf effort=S verdict=actionable - drain_once allocates a fresh 64KiB+1 scratch buffer per datagram inside the drain loop ( <= 256 iterations/call),when one buffer reused across recv calls would suffice - fix: hoist `let mut bytes = vec![0_u8; MAX_COMPACT_FRAME_BYTES + 1];` above the while loop,and `bytes.resize(MAX_COMPACT_FRAME_BYTES + 1, 0)` per iteration; the queued redacted frame remains its own owned Vec from redact_parsed_frame - [emitter_socket.rs:139] + evidence: static (unmeasured); seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 6 hits; he deep read of drain_once found the per-iteration allocation +- d2b-provider-observability-otel#7 sev=low blast=leaf effort=M verdict=actionable - admit_for_connection re-measures every frame by re-serializing the whole MetricFrame to JSON(allocating a Value tree plus a String per admission),though the wire-boundary paths already carry `encoded_bytes` - fix: thread the canonical measured size through from the decode boundary (admit_raw/admit_parsed/metric_frame_from_raw) instead of re-calling measured_encoded_bytes in admit_for_connection, preserving the documented trustless measurement at the boundary(ingress_policy.rs:202-203)rather than per admission - [ingress_policy.rs:203, ingress_policy.rs:368] + evidence: static(unmeasured; seed `format!\(` = 1 hit(cold construction path))and `serde_json::to_` = 10 hits; reread of admit_for_connection (line 395+) shows measured_encoded_bytes called for every frame before policy evaluation +- d2b-provider-observability-otel#8 sev=low blast=leaf effort=S verdict=actionable - valid_resource_attribute_value allocates a lowercase copy of each attribute value(`to_ascii_lowercase()`)on the per-frame resource-attribute validation path,only to substring-test six words - fix: replace the allocation with a case-insensitive byte-scan helper(e.g. a local `contains_ignore_ascii_case(value, word)`)over the already-bounded( <= 256-byte)value - [metric_policy.rs:44] + evidence: static(unmeasured; seed `\.to_string\(\)` = 20 hits(most are wire-map construction); the identified site allocates per attribute value per admission frame(validate_resource_attributes is called from admit_for_connection at ingress_policy.rs:411)) + + +## conc +- clean: seeds ran: 0/0/20/0; zeroproduction threads/locks/atomics; all `AtomicU64`/`AtomicUsize` + `Ordering` hits are in `#[cfg(test)]` harnesses (ManualClock in ingress_policy.rs:769-775,and SOCKET_SEQUENCE in emitter_socket.rs:380-383),test-only synchronization per U1 lens-card FP; production shared state is the single `Arc` trait-object ownership already judged under api + + +## async +- N/A: seeds ran: 0/0/0/0; no async fn/.await/tokio::spawn/tokio::sync anywhere in src,andthe crate declares no tokio dependency - the whole crate is a synchronous library + + +## unsafe +- N/A: seeds ran: 0/0/0/1; seeds1-3 all zero(no unsafe blocks/fns/impls,no SAFETY comments,no transmute/from_raw/MaybeUninit/zeroed),and seed4 alone - the `#![forbid(unsafe_code)]` attribute(lib.rs:3)- does not make the lens applicable per U1 lens-card + + + +## ffi +- N/A: seeds ran: 0/0/0/0; no extern "C"/no_mangle/link_section/catch_unwind/repr(C)/repr(transparent)/CStr/CString/c_char anywhere; the rustix fchmod/fstat call sites(emitter_socket.rs:86,282)are safe-wrapper syscall call sites that never cross a foreign caller(U1 lens-card FP) + + + +## macro +- N/A: seeds ran: 0/0/0/0; no macro_rules!/proc_macro/syn/quote/$crate/to_compile_error/new_spanned anywhere; only std macros and derives exist,which are not definitions per U1 lens-card FP + + + +## test +- d2b-provider-observability-otel#9 sev=medium blast=leaf effort=S verdict=actionable - the resource-attribute validation test asserts only `is_err()` for both failure shapes,so a regression swapping the two wire-visible variants(`NotAllowlisted` vs `Invalid`)would pass - fix: replace the two `is_err()` assertions in `resource_attributes_have_a_separate_allowlist` with `assert_eq!)..., Err(ResourceAttributeError::NotAllowlisted))` for the unknown-key case,and `assert_eq!)..., Err(ResourceAttributeError::Invalid))` for the credential-canary value case - [metric_policy.rs:145, metric_policy.rs:150] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` over src+tests = 158 hits(assert! mass incl.the two variant-blind is_err sites at metric_policy.rs:145,150); the variants' Display codes differ("otel-resource-attribute-not-allowlisted" vs "otel-resource-attribute-invalid", metric_policy.rs:83-91),so a caller can match on them + + +## Coverage +- idiom: clean(seeds ran: 2/3/0; index loops in test harnesses; Default impls deliberate) +- own: 1 finding(s) +- type: 1 finding(s) +- api: clean(seeds ran: 121/1/6; re-exports house pattern; Arc sharing justified by tests) +- err: 1 finding(s) +- serde: clean(seeds ran: 1/0/1/10; hand-written gates deliberate per refusal class) +- obs: clean(seeds ran: 0/0/0/3; no println; named-field events only) +- docs: 2 finding(s) +- perf: 3 finding(s) +- conc: clean(seeds ran: 0/0/20/0; all atomic hits test-only) +- async: N/A(seeds:0/0/0/0; no async fn or tokio dep) +- unsafe: N/A(seeds:0/0/0/1; forbid(unsafe_code) attribute alone does not apply per U1) +- ffi: N/A(seeds:0/0/0/0; no FFI surface; rustix wrappers are not crossings) +- macro: N/A(seeds:0/0/0/0; no macro definitions) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md new file mode 100644 index 000000000..e1f7675c1 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md @@ -0,0 +1,84 @@ +# d2b-provider-process-systemd - d2b-provider-process-systemd +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3816 (excl. src/generated/**, incl. tests/**) | modules: whole crate (src: audit, controller, drain, effects_service, error, launch, lib, lifecycle, metrics, operations, sandbox; tests: boundaries, conformance, controller, execution_parents, lifecycle) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-process-systemd#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default` on the unit structs `SystemdEffectsService` and `SystemdEffectsServiceFactory` where `#[derive(Default)]` generates the identical impl - fix: replace both `impl Default { fn default() -> Self { Self::new() } }` blocks with `#[derive(Default)]` on the structs - [packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-process-systemd/src/effects_service.rs:218] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits; the third (`SystemdProviderConfig`, src/lifecycle.rs:20) is a legitimate hand-written Default preserving nonzero bounded defaults (a field-wise derive would yield zeros) +- clean: seeds ran: 0/3/0 - no index loops (`for \w+ in 0\.\.` = 0), no statement-style accumulation (`let mut \w+ = (String|Vec)::new\(\)` = 0); the only hand-written impls are the two unit-struct Defaults above plus the invariant-preserving config Default + +## own +- clean: seeds ran: 14/29/0/0 - every `.clone()` is explainable: move-closure captures into `kernel_seat::run` (src/operations.rs:649-653), owned `ProcessStatusReport`/`UnitIdentity` fields (src/lib.rs:238-243, src/operations.rs:596-597), the payload clone into `ValidatedPayload` (src/effects_service.rs:184), and cfg(test) fixtures; `.to_owned()/.to_string()` sites are uid/path formatting, closure captures, and error-detail strings; no Rc/RefCell/Arc/Arc/Cow + +## type +- d2b-provider-process-systemd#2 sev=low blast=leaf effort=S verdict=actionable - `RestartPolicy.restart_on_failure: bool` is invariant state: the only constructor sets it to `true` and nothing ever mutates it, so the field and its guard encode a state the type cannot otherwise represent - fix: drop the field and the `if !self.restart_on_failure` check in `should_restart`, or add a `RestartPolicy::never()` constructor if the never-restart class is real - [packages/d2b-provider-process-systemd/src/lifecycle.rs:78, packages/d2b-provider-process-systemd/src/lifecycle.rs:100] + evidence: seed `is_\w+: bool|\w+_flag: bool` = 0; full-file read found the invariant field (single constructor `on_failure` at lifecycle.rs:87 sets it true; no other assignment) +- d2b-provider-process-systemd#3 sev=low blast=leaf effort=S verdict=actionable - `metrics::validate_labels` accepts stringly-typed `(String, String)` label pairs checked against the runtime `LABEL_KEYS` allowlist, so a misspelled key is a runtime rejection instead of a type error - fix: introduce `enum MetricLabelKey { Operation, Outcome, Domain }` with an `as_str()` accessor and take the key side typed - [packages/d2b-provider-process-systemd/src/metrics.rs:7, packages/d2b-provider-process-systemd/src/metrics.rs:4] + evidence: seed `fn validate_\w+|fn check_\w+` = 3 hits (`validate_request` is a boundary admission gate cross-checking untrusted wire fields against the trusted bundle - not a parse-once candidate; `validate_launch_ticket` is a two-line provider-binding check); the label-key case is the stringly-typed one +- clean: seeds ran: 3/0/1 - the one `(mode|kind|state): String` hit is the external systemd `ActiveState` property read (src/operations.rs:565), a wire-boundary value, not crate state + +## api +- d2b-provider-process-systemd#4 sev=low blast=leaf effort=S verdict=actionable - `SystemdProviderConfig`, `RestartPolicy`, `SystemdConfigError`, and `EphemeralProcessController` are each reachable at two paths: `pub mod lifecycle` (src/lib.rs:28) plus the root re-export `pub use lifecycle::{...}` (src/lib.rs:33), violating the one-path-per-item surface rule - fix: make `lifecycle` private (`mod lifecycle;`) and keep the root re-export as the single surface; no external caller imports through the module path (tests use the crate root) - [packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd/src/lib.rs:33] + evidence: seed `^\s*pub use ` = 1 hit; seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 77 hits; the four re-exported items are the only two-path items (other modules are single-path) +- d2b-provider-process-systemd#5 sev=low blast=leaf effort=S verdict=actionable - `SystemdProviderConfig::no_persistent_unit()` is an always-true method with no production caller; the invariant it states already lives in the README security posture and the dossier - fix: delete the method and its test assertion (tests/lifecycle.rs:12), or replace it with a documented `const` if the surface is contract - [packages/d2b-provider-process-systemd/src/lifecycle.rs:55, packages/d2b-provider-process-systemd/tests/lifecycle.rs:12] + evidence: census: `no_persistent_unit` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel, *.bzl = 2 hits (definition + its own test) +- d2b-provider-process-systemd#6 sev=low blast=leaf effort=S verdict=policy-confirmed - the controller/provider/lifecycle/drain/launch/sandbox/audit/metrics/error modules have zero production consumers: the daemon composes only `effects_service` + `operations` (the U15 forward seam), so the declared controller surface is unwired in the tree - fix: none until daemon composition lands; record the drift - [packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd/README.md:28] + evidence: census: `SystemdProcessController|SystemdProcessProvider|SystemdReconcileAction|SystemdReconcileResult|EphemeralProcessController|RestartPolicy|SystemdProviderConfig|DrainProof|DrainStage|DrainError` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel, *.bzl = all hits in-crate (src + tests + README); d2bd consumes only `PROCESS_SYSTEMD_EFFECTS_SERVICE` + `SystemdEffectsServiceFactory` (d2bd/src/resource_plane_v3.rs:2282-2288, d2bd/src/forward_rendezvous.rs:2063-2065); policy: prior audit kept the dossier-named modules (docs/explanation/over-engineering-audit-record.md:262, row 4) and the dossier required layout names them (docs/specs/providers/ADR-046-provider-system-systemd.md:1348-1357); README declares the controller as the shipped library type (README.md:28-31) + +## err +- d2b-provider-process-systemd#7 sev=low blast=leaf effort=S verdict=actionable - `SystemdProviderError` (src/error.rs) is a closed error catalogue with zero consumers while the live handlers refuse through the parallel `&'static str` code constants in src/operations.rs:51-107 - two refusal vocabularies in one crate - fix: delete the unused enum, or route the handler refusals through it (its codes are not pinned in docs/reference/error-codes.md, so no wire contract binds them) - [packages/d2b-provider-process-systemd/src/error.rs:5, packages/d2b-provider-process-systemd/src/operations.rs:51] + evidence: census: `SystemdProviderError` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel, *.bzl = 4 hits, all in src/error.rs (enum, impl, Display, Error); seed `enum \w*Error` = 3 hits (SystemdProviderError, SystemdConfigError, DrainError) +- clean: seeds ran: 24/0/0 - every `.unwrap()/.expect()` is in `#[cfg(test)]` or on frozen literal construction (`BoundedToken::parse(PROVIDER_NAME)` and the profile build in `SystemdProcessProvider::new`, src/lib.rs:68-80; the `LazyLock` operation-table parses, src/operations.rs:161-181); no swallowed Results, no panic macros + +## serde +- clean: seeds ran: 2/2/0/6 - Serialize-only audit projection (`SystemdAuditOperation` kebab-case, `SystemdProcessAudit` camelCase) with no raw unit name/PID/path fields; no hand-written Deserialize; the `serde_json::to_value/from_value` conversions at the operation boundary map failures to the closed refusal codes (UNIT_INVALID_REQUEST/UNIT_QUERY_FAILED) instead of stringified messages + +## obs +- d2b-provider-process-systemd#8 sev=low blast=leaf effort=S verdict=actionable - the `debug!` event on the cancelled-ticket path evaluates `ticket.process_ref().to_canonical_string()` eagerly, allocating the canonical string even when debug is disabled - fix: pass a reference and let the macro format lazily (`resource = %ticket.process_ref()` if Display exists, else `?ticket.process_ref()`), reserving the eager `to_canonical_string()` for the warn/error paths - [packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-systemd/src/lib.rs:141] + evidence: seed `(info|debug|warn|error|trace)!\("` = 0 (every event uses named fields); full-file read found the eager field expression on the debug! site +- clean: seeds ran: 0/0/0/4 - no println/eprintln in the library; all tracing events carry named fields (provider, resource, identity, error, timeout_sec); no spans, which is consistent with one-shot handler operations + +## docs +- d2b-provider-process-systemd#9 sev=medium blast=leaf effort=M verdict=actionable - public `Result`-returning items lack `# Errors` sections naming their failure conditions: `SystemdProviderConfig::new` (OutOfRange bounds), `drain::validate` (two refusal variants), `SystemdProcessController::reconcile` (DeadlineExceeded), `validate_launch_ticket`, `SystemdSandboxCompiler::compile` - fix: add `# Errors` sections to each, stating which inputs produce which failure - [packages/d2b-provider-process-systemd/src/lifecycle.rs:33, packages/d2b-provider-process-systemd/src/drain.rs:30, packages/d2b-provider-process-systemd/src/controller.rs:66, packages/d2b-provider-process-systemd/src/launch.rs:8, packages/d2b-provider-process-systemd/src/sandbox.rs:14] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed `-> Result<` = 31 hits; seed `^\s*pub (fn|struct|enum|trait|const|type)` = 67 hits, all documented (the crate opts into `#![deny(missing_docs)]` at src/lib.rs:16) +- clean: seeds ran: 67/0/31 - every public item carries a doc comment with a one-line first sentence and every module has a `//!` doc; the gap is the canonical-section depth, not presence + +## perf +- d2b-provider-process-systemd#10 sev=low blast=leaf effort=S verdict=actionable - `unit_name` builds the hex suffix with `format!` inside a 16-iteration loop (16 small String allocations) plus a final `format!`, on every unit operation that names a unit - fix: write the bytes into the preallocated `String::with_capacity(52)` with `write!` per byte, or format once into a fixed buffer - [packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process-systemd/src/operations.rs:421] + evidence: seed `format!\(` = 20 hits, of which 18 are cold error/detail paths and one is the loop site; static (unmeasured) +- clean: seeds ran: 20/13/10 - `Vec::new()` sites are empty fixtures and the deliberately empty `auxiliary` argument to StartTransientUnit; `.to_string()` sites are uid/path and error-detail strings on cold paths + +## conc +- N/A: seeds: 0/0/0/0 all zero - no threads, locks, atomics, or channels; the only shared state is `tokio::sync::Semaphore` (async-side, judged under async) + +## async +- clean: seeds ran: 53/0/0/3 - no blocking work on the executor (the sync `/proc/sys/kernel/random/boot_id` read in `validate_request` carries the sanctioned per-site allow `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` at src/operations.rs:208); zbus and `/proc//stat` reads are async (tokio::fs); the kernel leg runs through `kernel_seat::run` with 'static captures; the semaphore permit held across `.await` in `reconcile` is the bounded-slot design (try_acquire_owned, never blocking); the timeout-drop of a mid-launch future is recoverable through the designed adoption path; the `tokio::runtime::Handle::try_current()` gate in reconcile is deliberate for the crate's single-poll test driver + +## unsafe +- N/A: seeds: 0/0/0 all zero - no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed; manifest sets `unsafe_code = "forbid"` (packages/d2b-provider-process-systemd/Cargo.toml, [lints.rust]) + +## ffi +- N/A: seeds: 0/0/0/0 all zero - no extern "C", no_mangle, catch_unwind, repr(C)/repr(transparent), or CStr/CString/c_char anywhere in the crate (zbus D-Bus calls are Rust-side, not FFI) + +## macro +- N/A: seeds: 0/0/0/0 all zero - no macro_rules!, proc-macro, $crate, or spanned-error machinery; the crate defines no macros + +## test +- clean: seeds ran: 43/102/0/0 - 43 tests (12 in src, 31 in tests/) assert observable behavior with human-written expectations and error-variant matching (`ProcessConformanceError::*`, `EffectServiceError::Declined`), never Display strings; deterministic (no network, explicit current-thread runtimes, 0-second timeouts for the timeout tests); the three runtime-driving tests carry the sanctioned `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]`; no `#[ignore]`, no property/snapshot tooling (not required for this surface); the guest-binding gate test reads the real kernel boot id, which is stable within a boot + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: 14/29/0/0 - every clone explainable; no Rc/RefCell/Arc/Arc/Cow) +- type: 2 finding(s) +- api: 3 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 2/2/0/6 - Serialize-only redacted audit projection; wire conversions map to closed refusal codes) +- obs: 1 finding(s) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics/channels; the only shared state is tokio::sync::Semaphore, async-side) +- async: clean (seeds ran: 53/0/0/3 - no blocking on executor, sanctioned per-site allow cited, bounded-slot permit design, adoption-recoverable timeout) +- unsafe: N/A (seeds: 0/0/0 all zero; unsafe_code = "forbid" in Cargo.toml [lints.rust]) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 43/102/0/0 - behavior-based, error-variant assertions, deterministic, no ignored tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md new file mode 100644 index 000000000..aa28a8083 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md @@ -0,0 +1,75 @@ +# d2b-provider-process - d2b-provider-process +Baseline: 6ebdd4cec | LOC audited: 10721 (src 10469, tests 252, excl. src/generated/**) | modules: backend, driver, effects, effects_service, execution, facets, identity, launch_identity, operations, test_support (cfg-gated), worker_launch +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- clean: seeds ran (1/1/0): one `for _ in 0..16` yield helper in a test (driver.rs:2657, a fixed-count yield loop where an iterator pipeline has no meaning) and one hand-written `Default for FakeFacetsConfig` (test_support.rs:88) whose scripted values (`VecDeque::from([ProviderAdoption::Absent])`, `Ok(ProcessIdentityDigest::from_bytes([0x51; 32]))`) a derive cannot express. No index loops, no statement-style accumulation, no replaceable hand-written impls. + +## own +- d2b-provider-process#1 sev=low blast=leaf effort=S verdict=actionable - `envelope.provider_ref.clone().expect("checked")` clones the `Option` at three call sites where `as_ref().expect("checked")` borrows without copying - fix: replace `.clone().expect("checked")` with `.as_ref().expect("checked")` in the `identity()` call at recover, reconcile, and delete - [packages/d2b-provider-process/src/driver.rs:1988, packages/d2b-provider-process/src/driver.rs:2056, packages/d2b-provider-process/src/driver.rs:2105] + evidence: `\.clone\(\)` seed, 3 of 72 driver.rs clone hits; `check_provider` ran immediately before each site so the invariant is already named by the expect, and the clone buys nothing. +- d2b-provider-process#2 sev=low blast=leaf effort=S verdict=actionable - `bind_cloud_hypervisor_guest_uid` takes `argv: &[String]` and clones the whole argv at both return paths (`Ok(argv.to_vec())` and `let mut bound = argv.to_vec()`), while its sole caller never uses `launch_argv` afterwards - fix: take `argv: Vec` by value and return it (caller passes `launch_argv` directly), removing both copies - [packages/d2b-provider-process/src/operations.rs:1354, packages/d2b-provider-process/src/operations.rs:1362, packages/d2b-provider-process/src/operations.rs:2649] + evidence: `\.to_vec\(\)` seed, 2 of 86 operations.rs to_owned/to_vec hits; census: `bind_cloud_hypervisor_guest_uid` over packages/ = 1 call site (operations.rs:2649), which reads `launch_argv` only through this call. + +## type +- clean: seeds ran (5/0/0): the five `validate_*`/`check_*` functions (driver.rs:919 `check_provider`, operations.rs:576 `validate_request_fds`, 756 `validate_typed_process_metadata`, 987 `validate_sandbox_launch_plan`, 1208 `validate_spawn_runner_request_matches_intent`) are boundary fences on wire input, which is where validation belongs; the `typed: bool` parameter is an input-mode flag for one fence, not state. No boolean-flag fields, no stringly-typed state, no validate-at-every-callsite repetition. + +## api +- clean: seeds ran (135/3/15): the pub surface is deliberate and single-path (lib.rs re-export arms are the house pattern); `Arc` in public signatures is genuine shared ownership with visible call sites (`process_spec_decoder() -> Arc` is Arc-cloned into every descriptor, driver.rs:291/619; `ProcessEffectFacets` Arc fields are shared between the driver and the effects service, facets.rs:409-413); `ProcessEffectError` is a closed `#[non_exhaustive]` enum with stable codes (backend.rs:190). No dependency types leak into signatures beyond the deliberate `d2b_process_conformance` re-export, which is the family-home contract. + +## err +- d2b-provider-process#3 sev=low blast=leaf effort=S verdict=actionable - `.ok().and_then(...)` swallows the parse of a stored owning-row spec in the launch-identity path: a corrupt `VolumeBinding` or `Volume` row silently degrades to an unbound launch instead of refusing with `SpecInvalid` - fix: map the two `serde_json::from_slice` failures to `ProcessDriverErrorKind::SpecInvalid` (or return `None` only for genuinely absent rows, not for parse failures) in `identity()` and `serving_worker_launch()` - [packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/driver.rs:1124-1130] + evidence: `\.ok\(\);`/`.ok()` seed, 2 of 10 driver.rs `.ok()` sites; the downstream ticket fence (`provider-ticket:template-not-found`) still refuses closed, so severity stays low. +- clean: seeds ran (185/14/8/2): all `unwrap`/`expect` outside tests sit on literally-built constants (operations.rs:159-213, 278-280, 1549, 2174, 2205) or after a check the compiler cannot see (`expect("checked")`, driver.rs:1988/2056/2105); every `panic!`/`unreachable!` hit is in `#[cfg(test)]`; `let _ =` sites are deliberate best-effort sends and requeues (RequeueId, not Result, driver.rs:1391-1722) and a payload-shape validation (`let _request`, operations.rs:2093); both error enums (ProcessEffectError, ProcessDriverErrorKind) are closed with stable codes and no caller string-matching. + +## serde +- clean: seeds ran (18 total): the crate derives no Serialize/Deserialize types of its own; all serde use is boundary deserialization of wire specs (`ResourceSpec`, `ProcessSpec`, `EphemeralProcessSpec`, `VolumeBindingSpec`, `VolumeSpec`) with errors mapped to typed failures (driver.rs:884-911, operations.rs:425-459), plus best-effort metadata reads. No hand-written `Deserialize` impls, no `rename_all`/`deny_unknown_fields`/`flatten` decisions to judge on crate-owned types. + +## obs +- clean: seeds ran (8/0/0/8): all eight `tracing::warn!` events carry named fields (`resource`, `provider`, `operation`, `error`, `restart_count`) with static messages (driver.rs:1046, 1183, 1248, 1552, 1759, 1809, 1871, 1894); zero `println!`/`eprintln!`; no interpolated-message-only events; error chains logged once at the handling boundary (`map_provider_error`, driver.rs:1893-1898). + +## docs +- d2b-provider-process#4 sev=low blast=leaf effort=L verdict=actionable - no `# Errors` or `# Panics` canonical sections exist on any of the crate's 142 Result-returning items, so the failure contract of the public surface is prose-only - fix: add `# Errors` sections naming the closed codes to the public Result-returning items, starting with `ProcessEffectBackend::launch` (which closed codes each operation can raise) and `resolve_launch_identity` (which `LaunchIdentityError` variants are possible) - [packages/d2b-provider-process/src/backend.rs:256, packages/d2b-provider-process/src/launch_identity.rs:64] + evidence: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed 3 `-> Result<` = 142 hits; `#![deny(missing_docs)]` (lib.rs) means every item is documented, the gap is section shape only. +- clean: seeds ran (119/0/142): module docs present in all 12 modules, first sentences carry the load, magic values documented with the why (e.g. `PROCESS_RESYNC` 5s cadence, driver.rs:99-102); no doctests exist and none are marked `ignore`. + +## perf +- clean: seeds ran (78/24/27): every `format!` hit is an error-detail string, a one-shot diagnostic, or a per-operation path construction (cold; the recorded false-positive class); every `Vec::new()` is an empty-case struct field, an empty fd vector, or a test fixture; `to_string()` sits at wire-rendering and Display boundaries. No `format!` in any loop, no grow-by-push collection, no attacker-keyed hashing. static (unmeasured). + +## conc +- d2b-provider-process#5 sev=medium blast=leaf effort=S verdict=policy-confirmed - production `parking_lot::Mutex` fields in `EphemeralRuntime` (`started_at`, `completed`) are a live use of a banned primitive with no per-site allow, and the lock calls run on the actor's executor thread - fix: switch the two fields to `tokio::sync::Mutex` (the already-named replacement) or `std::sync::Mutex` with the same short critical sections; requires the parking_lot ban carve-out to be re-opened otherwise - [packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.rs:682] + evidence: seed 2 `\bMutex<` = 2 production hits (of 36 conc hits; the rest are test doubles and test-support); policy: clippy.toml:40-43 ("parking_lot is banned outright (plan KD3); the U33 short-lock carve-out is revoked") and clippy.toml:82 (replacement `tokio::sync::Mutex::lock`); no `#[allow(clippy::disallowed_methods)]` at the site, and the sanctioned-reason list (U1 d.4) does not cover it. +- d2b-provider-process#6 sev=low blast=leaf effort=S verdict=actionable - `RestartBudget`, `EphemeralRuntime.started`, and `DurableRuntime.watching` use `Ordering::SeqCst` for plain counters and flags that publish no other data, so the strongest ordering buys nothing over `Relaxed` - fix: switch the 16 `Ordering::SeqCst` sites in driver.rs to `Ordering::Relaxed` (no paired acquire/release handoff exists; the actor and the spawned launch task only gate on these flags) - [packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.rs:451, packages/d2b-provider-process/src/driver.rs:458, packages/d2b-provider-process/src/driver.rs:462, packages/d2b-provider-process/src/driver.rs:466, packages/d2b-provider-process/src/driver.rs:470, packages/d2b-provider-process/src/driver.rs:695, packages/d2b-provider-process/src/driver.rs:703, packages/d2b-provider-process/src/driver.rs:732, packages/d2b-provider-process/src/driver.rs:761, packages/d2b-provider-process/src/driver.rs:765, packages/d2b-provider-process/src/driver.rs:772] + evidence: seed 3 `Atomic\w+|Ordering::` = 16 SeqCst sites in driver.rs (of 36 conc hits); no `unsafe impl Send/Sync`, no `thread_local!`, no `std::thread` usage in the crate. + +## async +- clean: seeds ran (444/3/0/25): the three `tokio::spawn` sites (driver.rs:1232, 1795, 2507) pre-capture everything (`spec.clone()`, `identity.clone()`, `Arc::clone`) before the `'static` move and complete through a oneshot whose failed send is harmless when the actor is gone; no blocking call sits in an async context (the async-gate markers on test-support recorder locks are deliberate exceptions, driver.rs:2426-2437, test_support.rs:227-355); no guard is held across an `.await`; tests use `start_paused = true` for deterministic time. No `spawn_blocking`, `JoinSet`, `select!`, or `tokio::sync::Mutex` in the crate. + +## unsafe +- N/A (seeds: 0/0/0/0 - the single `from_raw` match is rustix's safe `Pid::from_raw` constructor, a seed false positive; no `unsafe` blocks, fns, impls, or `// SAFETY:` comments; the manifest forbids `unsafe_code`) + +## ffi +- N/A (seeds: 0/0/0/0 - no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString` anywhere in the crate) + +## macro +- N/A (seeds: 0/0/0/0 - no `macro_rules!`, proc-macro, `$crate`, or `to_compile_error` usage) + +## test +- clean: seeds ran (42/283/0/0): 42 tests (25 driver, 9 effects_service, 3 backend, 2 launch_identity, 3 integration) assert behavior with `start_paused` determinism, table-driven cases with per-case failure messages (launch_identity.rs:213-395), error-code assertions that pin the stable wire codes rather than incidental Display text (driver.rs:2936, 3051-3061), and integration tests through the public registry surface (tests/process_family.rs). No `#[ignore]`, no property/snapshot tooling (no rule-shaped surface needs it), no network or clock reads, no test that cannot fail. + +## Coverage +- idiom: clean (seeds ran: 1/1/0) +- own: 2 findings (seeds: 123/150/1/0; all 273 hits inspected) +- type: clean (seeds ran: 5/0/0) +- api: clean (seeds ran: 135/3/15) +- err: 1 finding (seeds: 185/14/8/2) +- serde: clean (seeds ran: 18 total) +- obs: clean (seeds ran: 8/0/0/8) +- docs: 1 finding (seeds: 119/0/142) +- perf: clean (seeds ran: 78/24/27) +- conc: 2 findings (seeds: 0/4/16/0) +- async: clean (seeds ran: 444/3/0/25) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks or unsafe_code allow) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 42/283/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md new file mode 100644 index 000000000..c1c1432cb --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md @@ -0,0 +1,81 @@ +# d2b-provider-provider - d2b-provider-provider +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2280 (excl. src/generated/**) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- clean: seeds ran 0/1/1 - the hand-written `Default for ProviderDriverFactory` (driver.rs:229) is not derivable (fields carry no `Default`) and the `Vec::new()` accumulation loop (driver.rs:485) has early exits and `?` the skill's plain-for exception covers; no index loops, no ad-hoc converters (clone sites are judged under `own`) + +## own +- d2b-provider-provider#1 sev=low blast=leaf effort=S verdict=actionable - `let zone = ctx.key().zone.clone()` clones a `String` the callee accepts as `impl Into` in three spots - fix: pass `ctx.key().zone.as_str()` / `view.key.zone.as_str()` directly; drop the `zone` local in the fixed-provider branch - [src/driver.rs:355, src/driver.rs:478, src/driver.rs:522] + evidence: own seed 1 `\.clone\(\)` = 15 lines; `ZoneId::parse` takes `impl Into` (d2b-contracts-resource/src/v3/identity.rs:79) and `ResourceKey::new` takes `impl Into` (d2b-resource-runtime/src/spec_store.rs:61), so `&str` compiles without the clone +- d2b-provider-provider#2 sev=low blast=leaf effort=S verdict=actionable - `ctx.status::().cloned()` deep-clones the whole in-memory status (incl. the `BTreeSet` volume_refs) on every reconcile pass - fix: hold the `Option<&ProviderDriverStatus>` reference (`ctx.status()` returns `Option<&T>`, d2b-resource-runtime/src/context.rs:459); last read of `previous` precedes `ctx.set_status` - [src/driver.rs:360, src/driver.rs:435] + evidence: own seed 1 `\.clone\(\)` = 15 lines; the test helper's clone (driver.rs:1066) is required, this site is not +- clean: seeds ran 15/9/0/0 - remaining clones are required by signatures (`classify_error` trait shape, `CoreResourceKey::new`/`with_owner_identity` owned args, `metadata.insert` owned keys, `spec_object` returning owned `Value` from a `&Value` decode) or are test fixtures; no `Rc`/`RefCell`/`Arc`/`Cow` in production code + +## type +- clean: seeds ran 1/0/0 - the single hit (`fn validate_refuses_a_spec_that_is_not_an_object`, driver.rs:1074) is a test fn name, not a runtime validation fn; `ProviderObservation`'s eight booleans are independent observed facts feeding one projection (not flag soup), `ProviderIntent`/`ProviderPhase`/`ProviderChildAction` are enums, no stringly-typed state + +## api +- d2b-provider-provider#3 sev=low blast=leaf effort=S verdict=actionable - `ProviderDriverFactory::new()` and its `Default` impl are zero-caller public surface (the doc names "unit fixtures", but the crate's own tests construct via `with_effects`) - fix: delete `new()` and `impl Default` (driver.rs:213-232), or drop them to `pub(crate)` if a fixture wants them - [src/driver.rs:215, src/driver.rs:229] + evidence: census `ProviderDriverFactory` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 0 callers of `new()`/`default()`; d2bd reaches the factory only through `provider_descriptor` (d2bd/src/resource_plane_v3.rs:144) +- d2b-provider-provider#4 sev=low blast=leaf effort=S verdict=actionable - `ProviderHandler::plan_external` (and the `ProviderError`/`ProviderChildAction`/`Disable`/`Delete` planning surface it serves) is exported through `pub mod providers` with zero production callers - fix: reduce to `pub(crate)` or delete `plan_external` (providers.rs:121-171) and the `ProviderIntent::Disable`/`Delete` arms of `plan_observed` if the external-provider path is not coming back; keep the surface the driver consumes (`plan_observed` Enable/Update, `plan_system_core`, `provider_observation`, `fixed_system_core_handlers_ready`) - [src/providers.rs:121, src/lib.rs:19] + evidence: census `ProviderHandler|plan_external` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 0 production callers; only the crate's own tests exercise it (providers.rs:688, 710, 728); the driver passes only Enable/Update intents (driver.rs:361-365) +- clean: seeds ran 35/3/1 - the `Arc` in `ProviderDriverArgs`/factory/driver is genuine shared ownership (factory clones the Arc per created driver, driver.rs:243); `pub use` re-export arms in lib.rs:31 are the house single-surface pattern; `test_support` is feature-gated; `ProviderPlan` keeps private fields with accessors + +## err +- clean: seeds ran 42/1/0/1 - every `unwrap`/`expect` sits in `#[cfg(test)]` or the `test-support`-gated `RecordingEffects`; the one production `expect` (driver.rs:481) is on a literal const in the same file; `let _ = ctx.requeue_after)...)` (driver.rs:449) is a deliberate fire-and-forget requeue; `ProviderError` is a closed taxonomy with a `code()` accessor and `Display` = code; `CoreReconcileError` is logged at its site before being mapped to `spec_invalid` + +## serde +- clean: seeds ran 0/0/0/15 - no derives, no serde attributes, no hand-written `Deserialize`; all 15 hits are `serde_json::from_/to_` on untyped `Value` (the core types' deliberate spec-envelope shape), and the object fence runs at both validate and reconcile (`spec_object`, driver.rs:575-601) + +## obs +- clean: seeds ran 0/0/0/5 - all five events (`tracing::debug!`/`tracing::warn!`, providers.rs:281/348/370/412/463) carry named fields (`resource = ...`, `reason = %error`) with a plain message, no interpolation, no secrets, no `println!`; levels match handled-vs-attention semantics + +## docs +- d2b-provider-provider#5 sev=low blast=leaf effort=S verdict=actionable - the eight `pub` fields of `ProviderObservation` are undocumented while every other pub item in the crate carries a doc comment - fix: add one-line field docs (or a struct-level contract explaining each gate) at providers.rs:72-79 - [src/providers.rs:72, src/providers.rs:79] + evidence: docs seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 34 hits; ProviderObservation is the only pub struct whose pub fields lack `///` +- d2b-provider-provider#6 sev=low blast=leaf effort=S verdict=actionable - the three pub `Result`-returning functions (`plan_external`, `plan_observed`, `provider_observation`) have no `# Errors` section naming which condition produces which failure - fix: add `# Errors` sections enumerating the `ProviderError`/`CoreReconcileError` variants each fn returns - [src/providers.rs:121, src/providers.rs:179, src/providers.rs:406] + evidence: docs seed 3 `-> Result<` = 10 hits; the three pub fns are the ones the skill's `# Errors` trigger names +- d2b-provider-provider#7 sev=low blast=leaf effort=S verdict=actionable - README "State and telemetry" claims "the driver keeps no in-memory status either", but `reconcile_provider` publishes `ProviderDriverStatus` via `ctx.set_status` every pass - fix: correct README.md:72-74 to say the status is in-memory only (R11, never persisted) - [README.md:72, src/driver.rs:435] + evidence: static; README.md:72-74 vs driver.rs:435-441 (`ctx.set_status(ProviderDriverStatus { ... })`); README is a policy-required path (packages/xtask/src/provider_crate_policy.rs) so the text must be fixed, not the path removed +- clean: seeds ran 34/0/10 - module docs present in all four files; every other pub item has a one-line first sentence; no `ignore`d doctests, no magic values without the why + +## perf +- clean: seeds ran 3/8/4 - `format!` at driver.rs:521/606 is per-reconcile on a cold path (static, unmeasured); `to_string()` hits are error-path notes; `Vec::new()` sites are small per-pass collections; no hot loop, no attacker-keyed hashing, no benchmark exists to claim anything stronger + +## conc +- clean: seeds ran 0/5/6/0 - all `Mutex`/`AtomicBool`/`Ordering::SeqCst` hits are the `RecordingManager`/`RecordingEffects` test fakes (test-only synchronization); no threads, no `thread_local!`, no manual `Send`/`Sync`; the test-fake lock sites carry `async-gate-allow` markers (deliberate, cited not re-flagged) + +## async +- clean: seeds ran 62/0/0/10 - production async (validate/recover/reconcile/finalize/delete/dependencies/drain_owned_children) has no `tokio::spawn`, no `spawn_blocking`, no blocking calls on the executor, no guard held across `.await`; `#[async_trait]` is the skill-sanctioned object-safe choice; the 10 `#[tokio::test]` harnesses are deterministic fakes (scripted manager, no sleeps) + +## unsafe +- N/A (seeds: 0/0/0/0 all zero; manifest `unsafe_code = "forbid"`, no blocks/fns/impls, no `SAFETY:` sites) + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no extern surface, no repr, no CStr) + +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro surface) + +## test +- d2b-provider-provider#8 sev=medium blast=leaf effort=S verdict=actionable - the `Degraded` phase projection (`optional_components_degraded` -> `ProviderPhase::Degraded` in `plan_observed`) is production-reachable through the driver's Enable/Update intents and has no test - fix: add a `#[tokio::test]` (or `#[test]` on `plan_observed` directly) that sets `optional_components_degraded = true` with ready dependencies and asserts `phase == Degraded` and `publish_exports` stays true - [src/providers.rs:206, src/driver.rs:1147] + evidence: test seeds = 74 hits (17 test fns, 57 assertions); no test sets `optional_components_degraded = true` - the existing observation assertions pin it `false` (driver.rs:1151) and the plan tests cover Ready/Pending/TrustOrCompatibilityDenied only +- clean: seeds ran 17/57/0/0 - tests assert behavior (phase transitions, call order, error variants via `matches!`, wire codes via `kind().code()`), not implementation; no `#[ignore]`, no network, no sleeps, no proptest/insta/rstest; the registration suite pins the declaration contract through the real `ProviderDirectory` + +## Coverage +- idiom: clean (seeds: 0/1/1) +- own: 2 finding(s) +- type: clean (seeds: 1/0/0; single hit is a test fn name) +- api: 2 finding(s) +- err: clean (seeds: 42/1/0/1) +- serde: clean (seeds: 0/0/0/15) +- obs: clean (seeds: 0/0/0/5) +- docs: 3 finding(s) +- perf: clean (seeds: 3/8/4) +- conc: clean (seeds: 0/5/6/0) +- async: clean (seeds: 62/0/0/10) +- unsafe: N/A (seeds: 0/0/0/0 all zero; manifest `unsafe_code = "forbid"`) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md new file mode 100644 index 000000000..625762058 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md @@ -0,0 +1,87 @@ +# d2b-provider-shell-terminal - d2b-provider-shell-terminal +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4176 (excl. src/generated/**; none present) | modules: whole crate (src: lib, authz, guest_rules, host_rules, migration, observability, resources/{mod,pool,session}, service/{mod,controller,supervisor}, session/{mod,ring,adopt}; tests: 10 files) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: one (whole crate) + +## idiom +- clean: seeds `for \w+ in 0\.\.` 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` 0, `let mut \w+ = (String|Vec)::new\(\)` 0 (all zero; no index loops, no hand-written derive-replaceable impls (the redacted Debug impls are deliberate and not matcheable by the seed), no statement-style accumulation). + +## own +- d2b-provider-shell-terminal#1 sev=low blast=leaf effort=S verdict=actionable - `advance_session` clones the whole `Option` only to end the first `session_mut` borrow before the retired-identity check; the check can compare the live field inside a scoped block instead. - fix: in `ShellAuthorityLedger::advance_session`, wrap the first `session_mut` borrow in `{ ... }` and compare `entry.supervisor_identity.as_ref() != retired_identity` inside it, dropping `let current_identity` and `.clone()`; keep the second borrow for minting and mutation. - [src/service/supervisor.rs:599, src/service/supervisor.rs:601] + evidence: `\.clone\(\)` ~20 hits checked (fingerprint snapshots, capability/attachment accessor hand-offs, Arc clones at the genuinely-shared authority port, resource-map key copies, pool-entry inserts - all own required state except this one) +- clean: seeds `\.clone\(\)` ~20 hits, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` ~16 hits, `Rc<|RefCell<|Arc` signature (`ShellTerminalController::new`, src/service/controller.rs:124, is genuinely shared ownership: the controller stores it, hands clones to every `OpenSessionResult`/`SessionSupervisor` (src/service/controller.rs:99, src/service/controller.rs:426, src/service/supervisor.rs:1104);`pub use` arms in `lib.rs:20-37` are the house single-surface pattern under private module trees;`InMemoryShellAuthority` is kept per the refusal ledger (docs/explanation/over-engineering-audit-record.md:354) - real behavior with live coverage, not re-flagged. + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(` 4, `let _ = |\.ok\(\);` 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` 0, `enum \w*Error` 1; the 4 expects are on validated/static values naming the invariant (`ResourceRef::parse` on a `validate_name`-checked session name, src/service/supervisor.rs:228;`BoundedToken::parse("shell-supervisor-main")` literal, :234; re-checked `ExecutionSpec::new`,:244; ring capacity re-checked against the same bounds `PoolSpec::new` enforces, :1101);`ShellTerminalError` is a closed 14-variant enum split by caller action with wire-style Display codes; no panics, no swallowed Results in src. + + + +## serde +- N/A (seeds: `derive\([^)]*(De)?[Ss]erialize` 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` 0, `impl .*Deserialize.*for` 0,, `serde_json::from_|serde_json::to_` 0; no serde dependency in Cargo.toml and no wire format crosses this crate). + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` 0, `(info|debug|warn|error|trace)!\("` 0,, `\.instrument\(|#\[instrument` 0,, `tracing::|log::` 2; every `warn!`/`debug!` event (in src/service/controller.rs and src/service/supervisor.rs) carries named fields (`provider`, `pool`, `session`, `error`, `decision`, `expected`, `actual`) with template messages and no secrets in fields (the redacting `Debug` impls keep session/canary values out of renders); no `println!` in this library. + + + +## docs +- d2b-provider-shell-terminal#2 sev=medium blast=leaf effort=M verdict=actionable - the ~30 `pub fn` items returning `Result<_, ShellTerminalError>` (e.g. `Authorizer::authorize_request`, `OpenSessionRequest::new`, `PoolSpec::new`, `ShellSession::from_pool`, `restore_pool`, `reconcile_pool_attachments`, `restore_session`, `restart_supervisor`, `open_session`, `finalize_session`, `AttachRequest::new`, `OutputRing::new`, `SupervisorIdentity::new`, `ShellAuthorityLedger::validate_session`) lack an `# Errors` section naming which variants they emit. - fix: add an `# Errors` section to each Result-returning pub item enumerating the `ShellTerminalError` variants that item can return (e.g. `restore_pool`: `# Errors` `CapacityExceeded` when pool name already projected or the authority rejects the restore). - [src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/ring.rs:16] + evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` ~100 hits (every item carries a contract-shaped first sentence; `#![deny(missing_docs)]` at src/lib.rs:9), `/// # (Examples|Errors|Panics|Safety)` 0, `-> Result<` ~30 hits +- clean: seeds pub items ~100 (fully documented first sentences; all 8 modules carry `//!` docs;, first sentences are contract-shaped ), not implementation narration), no `ignore`d doctests exist to rot;; magic values (`SHELL_REPAIR_INTERVAL_SECS`, capacity bounds) carry meaning-comments; the only systematic gap is the missing `# Errors` class above. + +## perf +- clean: seeds `format!\(` 5, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 5, `\.to_string\(\)` 0; the format sites are one-shot resource-ref/name builders in cold construction paths (`src/resources/session.rs:89-93`, `src/service/controller.rs:380`, `src/service/supervisor.rs:227`), the empty `Vec::new`/`BTreeMap::new` are fresh collection initializers where the empty case is common; no hot-loop allocation sites, no benchmark exists - static (unmeasured) reading only (`OutputRing::append` per-byte push is O(1) amortized and bounded by the 1 MiB ring). + + + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` 0,, `\bMutex<|\bRwLock<` 2, `Atomic\w+|Ordering::` 1 (the word "Atomically" in a doc comment - false positive), `thread_local!|unsafe impl (Send|Sync) for` 0; both `tokio::sync::Mutex` holders (`ShellAuthorityLedger.state` src/service/supervisor.rs:401, `InMemoryShellAuthority.supervisor_processes`, :866) are synchronous surfaces used with `try_lock` fail-closed per a written design comment (src/service/supervisor.rs:410-413); no threads, no atomics, no manual `Send`/`Sync` claims in this crate. + + + +## async +- clean: seeds `async fn|async move|\.await` 0,, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` 0,, `tokio::sync::(Mutex|RwLock|Notify)` 2 (the two synchronous try_lock Mutexes noted under conc;, `#\[tokio::(main|test)\]|Runtime::block_on` 0; no async fn exists anywhere in src - no `.await`, no spawns, no guards across await points (tokio dep is sync-feature-only). + + + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0,, `// SAFETY:` 0,, `transmute|from_raw|MaybeUninit|mem::zeroed` 0; manifest `[lints.rust]` sets `unsafe_code = "forbid"` - no blocks, no exception sites). + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` 0,, `catch_unwind` 0,, `repr\(C\)|repr\(transparent\)` 0,, `CStr|CString|c_char` 0; no foreign boundary in this crate). + + + +## macro +- N/A (seeds: `macro_rules!` 0,, `proc_macro|syn::|quote!` 0,, `\$crate` 0,, `to_compile_error|new_spanned` 0; no macro definitions, no proc-macro machinery). + +## test +- d2b-provider-shell-terminal#3 sev=low blast=leaf effort=S verdict=actionable - `tests/supervisor_runtime.rs` repeats the full 14-line `ShellPool::new(PoolSpec::new)...))` fixture in 7 of its tests, while sibling `tests/controller_reconcile.rs:8` already defines a `pool()` helper. - fix: extract a parameterized `fn pool(max_sessions: u32, max_attached: u32) -> ShellPool` helper at the top of `tests/supervisor_runtime.rs` (or a shared `tests/common/mod.rs` used by both files), replacing the 7 inline constructions. - [tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.rs:142, tests/supervisor_runtime.rs:193, tests/supervisor_runtime.rs:255, tests/supervisor_runtime.rs:320, tests/supervisor_runtime.rs:367] + evidence: test seeds over tests/: `#\[test\]|#\[tokio::test\]` 34, `assert_eq!\(|assert_ne!\(|assert!\(` ~108 hitting lines (matrix cell 142 = 34 + ~108);`proptest!|insta::assert|rstest` 0,, `#\[ignore\]` 0; over src/: 0/0/0/0 (no unit tests in src); the inline fixture repeats 7 times. +- clean: seeds 34 integration tests + ~108 assertions; all deterministic (no network, no clock, no ignored stress tests), error variants asserted via `matches!`/`assert_eq!` against enum variants and never Display strings, redaction tests assert distinct canaries are absent from every `Debug` render, capacity, capability-reuse, recovery-adoption,, attachment-slot edges are covered by named behavior tests; the two large files use local fixture helpers except for the copy-paste class above. + + + +## Coverage +- idiom: clean (seeds 0/0/0 +- own: 1 finding(s) +- type: clean (seeds 7/0/0 +- api: clean (seeds ~160/1/14; Arc-in-signature shared-ownership judged explainable +- err: clean (seeds 4/0/0/1; all 4 expects are invariant-naming on validated values +- serde: N/A (seeds 0/0/0/0; no serde dep +- obs: clean (seeds 0/0/0/2; all events carry named fields +- docs: 1 finding(s) +- perf: clean (seeds 5/5/0; cold paths only +- conc: clean (seeds 0/2/1/0;2 Mutexes deliberate try_lock, 1 doc-word false positive +- async: clean (seeds 0/0/2/0; sync-only Mutex use +- unsafe: N/A (seeds 0/0/0; manifest forbid +- ffi: N/A (seeds 0/0/0/0 +- macro: N/A (seeds 0/0/0/0 +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md new file mode 100644 index 000000000..5e43f4fda --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md @@ -0,0 +1,65 @@ +# d2b-provider-supervisor - d2b-provider-supervisor +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6140 (src 5098 + tests 1042, excl. src/generated/**, none present) | modules: whole crate (adapter, broker, systemd) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-supervisor#1 sev=low blast=leaf effort=S verdict=actionable - systemd.rs stop() holds a no-op statement `let _ = &handle.pidfd;` that creates and immediately drops a temporary reference, doing nothing - fix: delete the line (the pidfd field is already used by wait/finalize and the retained handle) - [packages/d2b-provider-supervisor/src/systemd.rs:840] + evidence: seed `for \w+ in 0\.\.` = 4 (all test loops), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; dead statement found while reading the own seed-2 hits +- d2b-provider-supervisor#2 sev=low blast=leaf effort=S verdict=actionable - the bounded pending-observation ledger is copy-pasted twice: `BrokerProcessBackend::{record,take_observation}` and `SystemdProcessBackend::{record,take_observation}` are the same shape (Mutex, evict-oldest at MAX_PENDING_OBSERVATIONS=1024, poisoned-lock to ObserveFailed) - fix: extract one shared bounded-ledger helper and have both backends use it - [packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor/src/systemd.rs:240-280] + evidence: refusals ledger row 62 (`deferred for a single writer`, not-applied); both ledgers still present at 6ebdd4cec, site matches the row; seed `let mut \w+ = (String|Vec)::new\(\)` = 0 +- clean: idiom seeds ran (4/0/0); index loops only in test loops, no hand-written derives, no statement-style accumulation; hand-written redacting `Debug` impls (BrokerLaunchIntent adapter/provider surfaces, adapter.rs:424-428) are deliberate and pinned by redaction tests +## own +- clean: own seeds ran (clones 21/64/24, to_owned/to_vec/to_string 2/22/4, Rc/RefCell/Arc/Arc/Cow 1/0/0 per file); every clone inspected is explainable - Waker clone at JobFuture::poll (own the waker, adapter.rs:350), Arc clones at thread-spawn boundaries (worker/deadline worker), wire-payload clones building new per-request values (typed_identity_request! projections), test fixtures; the single Arc>> is the R4 bounded-worker admission queue (sanctioned, per-site allow at adapter.rs:219) +## type +- clean: type seeds ran (1/0/0); the sole hit `BrokerObservedProcess::{validate,validate_launch}` (broker.rs:225-233) is boundary validation of freshly broker-observed values, not repeated validate-at-callsite of one value; `typed_identity`/`cgroup_verified`/`executable_verified`/`multi_instance`/`accepts_launch_args` booleans each mirror distinct wire/source truth and are consumed independently, not flag soup +## api +- d2b-provider-supervisor#3 sev=medium blast=leaf effort=S verdict=actionable - `BrokerProcessBackend::set_launched_observer` takes `Arc` in a public signature although single ownership suffices: the one caller (d2bd/src/process_provider_runtime.rs:913) hands over a fresh `Arc::new)...)` and retains nothing, so the Arc is a forced refcount, not shared ownership - fix: take `Box` or `impl LaunchedObserver + Send + Sync + 'static`, drop the Arc at the call site - [packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2bd/src/process_provider_runtime.rs:913] + evidence: census `set_launched_observer` over packages/ = 2 hits (definition + single call site); the observer only ever lives in `Option>` inside the backend +- d2b-provider-supervisor#4 sev=medium blast=family effort=M verdict=actionable - `LaunchedObserver::launched` takes five positional parameters (vm, role, pid, start_time_ticks, pidfd) and `BrokerProcessBackend::launched_runner_snapshot` returns `Option<(String, String, i32, u64, OwnedFd)>`, a 5-tuple whose shape is pinned by the upstream `ProcessEffectBackend` trait (which carries its own `#[allow(clippy::type_complexity)]`) - fix: introduce a `LaunchedSnapshot` struct (or a small `LaunchedProcessRef`) and change `launched_runner_snapshot`'s default + the observer method to carry it, updating the implementor in d2bd - [packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/src/broker.rs:1524-1546, packages/d2b-provider-process/src/backend.rs:315-319] + evidence: census `LaunchedObserver|set_launched_observer` over packages/ = 9 hits (trait def, backend impl, d2bd implementor + call sites); the tuple is the trait-level wire-in-process shape, not a wire format, so the change is actionable across the provider family +- clean: api seeds ran (pub fn/struct/enum/trait/const/type 29, Arc/Rc/Box/RefCell in pub sig 1 [flagged #3], `pub use` arms 8); lib.rs re-export arms are the house single-surface pattern; `BrokerLaunchIntent`/`BrokerObservedProcess`/`SystemdInvocationIdentity`/`SystemdEffectLaunch` pub structs with documented pub fields are data carriers of the resolver/owner contract (not flagged) +## err +- d2b-provider-supervisor#5 sev=medium blast=leaf effort=S verdict=actionable - `ProviderSupervisor::with_limits` (the public constructor knob) panics with `assert!` on caller-provided `blocking_limit == 0` and zero `default_timeout` instead of returning a `Result` - a library panic on caller input, reachable from any future caller passing a computed bound - fix: return `Result` (or clamp and document) and have the single current construction sites handle it - [packages/d2b-provider-supervisor/src/adapter.rs:419-421] + evidence: err seed 1 `.unwrap\(\)|.expect\(` = 131 (non-test only adapter.rs:58/74/102/177, all startup/invariant expects); the `assert!` pair is the only panic-on-caller-input site in src +- d2b-provider-supervisor#6 sev=low blast=leaf effort=S verdict=actionable - `map_error` folds any currently-unknown `ProcessEffectError` variant into `LaunchFailed` via a `_` catch-all arm, so a new upstream variant (d2b-provider-process) fails at runtime instead of at compile time - fix: make the match exhaustive over the closed variant set (drop `_`), keeping the current mappings - [packages/d2b-provider-supervisor/src/adapter.rs:888-890] + evidence: err seed 3 `panic!\(|unreachable!\(|todo!\(|unimplemented!\(` = 4 (three test-backend `unreachable!` at adapter.rs:1344/1367/1375 + one invariant panic on a `matches!`-guarded `else` at broker.rs:1832, all legitimate); seed 4 `enum \w*Error` = 0 (errors come from d2b-provider-process) +## serde +- d2b-provider-supervisor#7 sev=medium blast=leaf effort=L verdict=needs-contract - `take_controller_bootstrap` is the one wire leg not using a typed d2b-contracts-broker request/response: it hand-builds the payload with `serde_json::json!` (camelCase string keys), reads the reply via `.get("taken")`/`as_bool` with a silent `unwrap_or(false)` (a malformed reply reads as "not taken" -> `Ok(None)`), and reuses hard-coded fd index 0 - fix: add a typed `TakeControllerBootstrapRequest/Response` to the broker wire contract (the operation row currently carries `wire_variant: None`) and parse/reply through it like every sibling leg - [packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generated/broker_operation_catalog.rs:1289] + evidence: serde seeds = 24, all `serde_json::{to_value,from_value}` at the envelope boundary; seeds 1/3 (derive / hand-written Deserialize) = 0; every other leg uses `typed_identity_request!` with typed request/response types - the loose leg is the exception +## obs +- clean: obs seeds ran (3/0/0/3); the 3 hits are `use tracing::{debug,error,warn}` imports only - no `println!`/`eprintln!` in src, no interpolated-field events, no `.instrument`; every traced event carries the `provider = "supervisor"` field (or `error = ?e`/`pid`/`identity` named fields) and message-only warnings are span-backed; no secret or identifier reaches a log field (identity digest values are hex digests, never raw proc/identity material; redaction is structurally enforced by the redacting Debug impls) +## docs +- d2b-provider-supervisor#8 sev=medium blast=leaf effort=M verdict=actionable - despite `#![deny(missing_docs)]`, no public `-> Result` item states its failure conditions in a `# Errors` section and no panicking item carries `# Panics` - `SystemdInvocationIdentity::new`, `ProviderSupervisor::{launch,observe,probe,open_pidfd,stop,finalize_identity,matches_peer_process}`, `BundleBackedLaunchResolver::{new,with_observation_socket}` document conditions only in prose, and `with_limits` panics without a `# Panics` note - fix: add `# Errors` (and `# Panics` on with_limits) sections to the public Result/panicking items - [packages/d2b-provider-supervisor/src/lib.rs:5, packages/d2b-provider-supervisor/src/adapter.rs:419-421, packages/d2b-provider-supervisor/src/systemd.rs:55-70] + evidence: docs seeds ran (pub items 29, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 101); deny(missing_docs) forces prose but the canonical sections are absent crate-wide +## perf +- clean: perf seeds ran (format! 17 / Vec::new 18 / to_string 5); every hit is a cold path - `format!` in error/wire-rendering and test fixture helpers, `Vec::new()` for empty one-shot wire fields (`runtime_allocations`, `inherited_fds`) and test setup, `to_string()` at snapshot/wire boundaries (`launched_runner_snapshot`, `take_controller_bootstrap` payload); no allocation in a hot loop (the deadline worker's `Vec` sort is bounded by the queue cap of 2x limit); perf evidence static (unmeasured) - no benchmark exists +## conc +- clean: conc seeds ran (std::thread 16 / Mutex 10 / Atomic 49 / thread_local+unsafe impl 0); the threads + `Arc>` workers + `AtomicBool` completion flags are the hand-rolled blocking executor recorded as a refused policy item (docs/explanation/over-engineering-audit-record.md row 53 - "src/adapter.rs keeps the executor"), so no executor finding is re-filed; no new evidence at 6ebdd4cec - atomic orderings are correct publish/observe pairs (`AcqRel`/`Acquire` on JobState), the mutex guards are short and never cross a suspension, and the test PoolTestGuard serialization is documented +## async +- clean: async seeds ran (async fn/await 41 / tokio::spawn+JoinSet+select 0 / tokio::sync 1 / tokio::main+block_on 0); the AsyncMutex state is taken with `.lock().await` and never held across the blocking submit; blocking work runs on the dedicated R4 workers with `blocking_lock()` inside the sanctioned worker-only boundary (per-site allows cited reason "dedicated bounded worker per plan R4" / "synchronous path"); the executor itself is the refused policy item (row 53), no new evidence; the only async-gate markers are two test-support recorder locks in tests/production_adapter.rs (inventory lines 840/845) +## unsafe +- N/A: unsafe seeds 1-3 all zero over src (unsafe/SAFETY/transmute/from_raw/MaybeUninit/zeroed = 0); manifest carries `unsafe_code = "forbid"` (Cargo.toml), lens not applicable +## ffi +- N/A: ffi seeds all zero (extern "C"/no_mangle/link_section, catch_unwind, repr(C)/repr(transparent), CStr/CString/c_char = 0); pidfd + SCM_RIGHTS usage (envelope fds, reply_take_fd, poll-based pidfd wait) is fd passing, not a foreign-language boundary +## macro +- clean: macro seeds ran (1/0/0/0); the single hit `typed_identity_request!` (broker.rs:151-168) is a justified impl-per-type boilerplate eliminator over the 9-field typed-identity projection injected into six wire request structs - `tt` fragment is the right specifier for struct-literal injection, the projection accessors stay single-sourced, and the macro carries a doc comment; no proc-macro, no `$crate` need (same crate), no hygiene hazard (the `let wire_intent` local collides with no field) +## test +- d2b-provider-supervisor#9 sev=low blast=leaf effort=S verdict=policy-confirmed - `open_pidfd_dispatch_failure_is_ambiguous_only_after_identity_drift` pins the cross-crate broker error-kind contract by scraping source text (`include_str!("../../d2b-broker/src/live_handlers.rs")` + `LIVE_HANDLER_SOURCE.contains("PidfdRace")`) with the expected names duplicated as literals - brittle against broker renames, but the identical fix (a shared typed error-kind constant) was refused for this exact site because no exported constant exists and d2b-contracts-broker is out of lane - fix: none actionable; keep the scrape - [packages/d2b-provider-supervisor/src/broker.rs:2040-2043] + evidence: refusals ledger row 60 refused ("the include_str scrape and cross-crate compile_data stay"); no changed evidence at 6ebdd4cec (live_handlers.rs still emits the three producer-error strings; no exported constant exists) +- clean: test seeds ran over src + tests (#[test]/#[tokio::test] 29, assert 99, proptest/insta/rstest 0, #[ignore] 0); coverage is mechanism-based and behavior-pinning - a real SCM_RIGHTS/SEQPACKET broker loopback (tests/production_adapter.rs:438-718), a heartbeat-cadence proof that blocking never reaches the executor (tests/production_adapter.rs:736-868), fault/reused/wrong-owner matrix, redaction-pin tests, and bounded-ledger tests; no test that cannot fail found; no `#[ignore]` (no documented stress/root-only skips needed) +## Coverage +- idiom: 2 finding(s) +- own: clean (seeds: 109 clones / 28 to_owned+to_vec+to_string / 1 Arc; all explainable) +- type: clean (seeds: 1/0/0; validate() is boundary validation of freshly observed broker data) +- api: 2 finding(s) +- err: 2 finding(s) +- serde: 1 finding(s) +- obs: clean (seeds: 0 println / 0 interpolated events / 0 instrument / 3 tracing imports; structured events, no secret in fields) +- docs: 1 finding(s) +- perf: clean (seeds: 17 format! / 18 collection new / 5 to_string; all cold paths, static (unmeasured)) +- conc: clean (seeds: 16/10/49/0; the executor is the refused policy item row 53, no new evidence) +- async: clean (seeds: 41/0/1/0; AsyncMutex across await is tokio sync, blocking confined to sanctioned R4 workers; executor refused row 53, no new evidence) +- unsafe: N/A (seeds: 0/0/0; `unsafe_code = "forbid"` in manifest) +- ffi: N/A (seeds: 0/0/0/0; fd passing only, no foreign boundary) +- macro: clean (seeds: 1/0/0/0; typed_identity_request! is a justified impl-per-type eliminator) +- test: 1 finding(s) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md new file mode 100644 index 000000000..c86423d7b --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md @@ -0,0 +1,83 @@ +# d2b-provider-system-core - d2b-provider-system-core +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1810 (excl. src/generated/**, src 1229 + tests 581) | modules: whole crate (error, host, lib, ownership, testing, user) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-system-core#1 sev=low blast=leaf effort=S verdict=actionable - `UserIdentityDigest::to_hex` pushes hex nibbles with `char::from_digit)...).unwrap_or('0')`, a fallback that can never fire (from_digit is total for 0-15 at radix 16) - fix: const `HEX: [char; 16]` table lookup, or `write!(out, "{byte:02x}")` via `std::fmt::Write` which pushes without allocating - [src/user.rs:75, src/user.rs:76] + evidence: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; dead fallback read in to_hex body +- d2b-provider-system-core#2 sev=low blast=leaf effort=S verdict=actionable - `UserReconciler::required_bindings` is an associated fn that never uses `Self`, the shape the naming rule calls a free function - fix: free `required_bindings(spec: &UserSpec)` in user.rs, updating the two test call sites (tests/user_discovery.rs:45, tests/user_discovery.rs:73) - [src/user.rs:232] + evidence: seeds 0/0/0; impl block user.rs:214-298 read, no Self use + +## own +- d2b-provider-system-core#3 sev=low blast=leaf effort=S verdict=actionable - `reconcile_observed` copies `kernel_release`/`os_name` out of a by-value `HostProbeSnapshot` with `to_owned()` where destructuring the owned snapshot moves the Strings - fix: `let HostProbeSnapshot { capabilities, kernel_release, os_name, user_manager_available, minijail_gate, active_process_count } = snapshot;` at the method top and move fields into the report - [src/host.rs:466, src/host.rs:467] + evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 3 (host.rs:378 to_vec is status-owned, fine; 466/467 are the copies) +- clean: seeds `\.clone\(\)` = 4, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 3, `Rc<|RefCell<|Arc64/128-byte strings with `HostProbeFailed`; `MinijailPlatformGate::validate` maps kernel/cgroup failures to two distinct variants) - fix: add `# Errors` sections to validate, HostProbeSnapshot::new, reject_operator_status_fields, reconcile/reconcile_observed/reconcile_with_probe, UserReconciler::reconcile, and the two effect ports' methods - [src/host.rs:121, src/host.rs:161, src/user.rs:241] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 across 74 pub items; seed `-> Result<` = 9 + +## perf +- clean: seeds `format!\(` = 0, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 0, `\.to_string\(\)` = 0; the only allocation site (to_hex, 64-byte String) is a cold serialization path + +## conc +- d2b-provider-system-core#10 sev=low blast=leaf effort=S verdict=actionable - `ScriptedDiscoveryPort.calls: Mutex` (testing.rs:43) uses a tokio::sync::Mutex for a counter - the crate's only tokio use - and `call_count` (testing.rs:79) silently reports 0 on contention via try_lock - fix: `AtomicU32` with `fetch_add`/`load` (Relaxed) and drop `tokio = { workspace = true, features = ["sync"] }` from Cargo.toml - [src/testing.rs:43, src/testing.rs:79] + evidence: seed `\bMutex<|\bRwLock<` = 1 (testing.rs:43); `tokio::` appears only at testing.rs:9 in src/ + +## async +- d2b-provider-system-core#11 sev=low blast=leaf effort=S verdict=actionable - `block_on` (testing.rs:23) busy-spins (`std::hint::spin_loop()`, testing.rs:30) on `Poll::Pending`, so any future that genuinely yields - a contended tokio Mutex, a future test with real I/O - hangs the test process at 100% CPU instead of failing; the doc comment asserts hermiticity but nothing enforces it - fix: `debug_assert!` the never-pending invariant or drive these tests with a real runtime - [src/testing.rs:30, src/testing.rs:19] + evidence: seed `async fn|async move|\.await` = 15 hits; block_on body read (Waker::noop + spin_loop) + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; manifest carries `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 + +## test +- d2b-provider-system-core#12 sev=low blast=leaf effort=S verdict=actionable - tests/host_reconciliation.rs repeats the `Probe` struct literal plus a 5-field `HostProbeMetadata` block five times (lines 204, 230, 254, 280, 306), one field differing per case - fix: a `Probe::new(capabilities, user_manager_available, gate, kernel_release)` constructor or default-and-mutate helper - [tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230] + evidence: seed `#\[test\]|#\[tokio::test\]` = 23 (22 integration + 1 unit), `assert_eq!\(|assert_ne!\(|assert!\(` = 49, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; five Probe constructions read + +## Coverage +- idiom: 2 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 0/0/0) +- api: 5 finding(s) +- err: clean (seeds ran: 10/0/0/1) +- serde: clean (seeds ran: 11) +- obs: clean (seeds ran: 0/0/0/2) +- docs: 1 finding(s) +- perf: clean (seeds ran: 0/0/0) +- conc: 1 finding(s) +- async: 1 finding(s) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md new file mode 100644 index 000000000..45d3d8f68 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md @@ -0,0 +1,81 @@ +# d2b-provider-toolkit-p1 - d2b-provider-toolkit - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6919 (excl. src/generated/**) | modules: base (bootstrap, error, fd10, guest, mod, runtime, startup), plane (creations, handle, mod, reconcile), operations (envelope, mod), audit (mod, redaction), declaration (manifest, mod, schema), bin (d2b-provider-toolkit) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/base/**, src/plane/**, src/operations/**, src/audit/**, src/declaration/**, src/bin/** + +## idiom +- d2b-provider-toolkit-p1#1 sev=medium blast=leaf effort=S verdict=actionable - the 15-operation Guest backend allowlist is spelled out twice: `GuestCredentialBackend::request` inlines the same `matches!` that `valid_guest_backend_operation` already implements, so adding one operation to one list and not the other silently diverges the client and responder admission - fix: have `request` call `valid_guest_backend_operation(&operation)` and delete the inline `matches!` arm - [packages/d2b-provider-toolkit/src/base/fd10.rs:926-941, packages/d2b-provider-toolkit/src/base/fd10.rs:1478-1496] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit; the duplicate list verified by `grep -n 'secret-service.state'` = 2 sites (fd10.rs:928, fd10.rs:1481) with identical 15-entry bodies +- d2b-provider-toolkit-p1#2 sev=low blast=leaf effort=S verdict=actionable - `GuestCredentialBackendResponse` and `GuestCredentialBackendReply` are two public 7-field structs with the same shape (state, lease_handle, source_version, rotation_generation, expires_at_unix_ms, outcome, bytes) and duplicated accessors, both re-exported at the crate root - fix: collapse into one type carrying the accessors plus `encode`/`with_sensitive_bytes`, keeping the zeroizing bytes field - [packages/d2b-provider-toolkit/src/base/fd10.rs:545-597, packages/d2b-provider-toolkit/src/base/fd10.rs:612-700, packages/d2b-provider-toolkit/src/lib.rs:91-92] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit; both structs and their accessor blocks read in full (fd10.rs:545-700), field lists identical +- clean: seeds `for \w+ in 0\.\.` = 2 (a bounded reconnect loop and a test loop, both index-appropriate), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 (manual `Default` for `ProviderAgentAuditLog` preserving the frozen capacity invariant, deliberate), `let mut \w+ = (String|Vec)::new\(\)` = 7 (all cold build/collect loops); hand-written `Debug` impls that redact are the deliberate house pattern + +## own +- d2b-provider-toolkit-p1#3 sev=low blast=leaf effort=S verdict=actionable - `is_ready_for_route` clones the retained route binding out of the mutex guard (`and_then(|ready| ready.clone())`) only to compare it, allocating the binding's strings on every route check - fix: compare through the guard, `try_lock().ok().is_some_and(|ready| ready.as_ref().is_some_and(|bound| bound.liveness().is_live() && bound == route))`, no clone - [packages/d2b-provider-toolkit/src/base/runtime.rs:530-537] + evidence: seed `\.clone\(\)` = 64 hits; this is the only clone in the sync route-query path that borrows instead of owning (the sibling `ready_route()` clone is required to return an owned value) +- clean: 64 clones, 37 `to_owned`/`to_vec`/`to_string`, 4 `Arc>` (the envelope's shared audit ring and the backend state, genuine multi-owner runtime state), 0 `Rc`/`RefCell`/`Cow`; remaining clones are route-metadata snapshots, per-invocation audit records, and test fixtures, each explainable + +## type +- clean: seeds `fn validate_\w+|fn check_\w+` = 5 (all boundary admission checks: route validation, facet validation, manifest installation validation - parse-once at the boundary, correct), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the `ProviderEntrypoint` builder's seven `Option` fields are guarded against double-binding by each `with_*` method and validated at use, within the stopping rule + +## api +- d2b-provider-toolkit-p1#4 sev=medium blast=leaf effort=S verdict=actionable - test-only constructors `GuestCredentialBackend::from_socket_for_test` and `from_socket_for_test_with_route` sit on the public surface (the type is re-exported at the crate root) without the house `test-support` feature gate that `d2b-session` uses for the same class of export - fix: move both behind a `test-support` feature (or `#[doc(hidden)]` + `#[cfg(any(test, feature = "test-support"))]`) so downstream crates cannot rely on them - [packages/d2b-provider-toolkit/src/base/fd10.rs:888, packages/d2b-provider-toolkit/src/base/fd10.rs:901, packages/d2b-provider-toolkit/src/lib.rs:89] + evidence: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits (this site and the deliberate `SharedClock = Arc` alias); census: `from_socket_for_test` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 5 hits, all in test code (d2b-provider-toolkit/tests/supervised_runtime.rs:94,550,642, d2b-provider-credential-secret-service/tests/session.rs:677, d2b-provider-credential-secret-service/src/lib.rs:1942,1958) +- clean: 262 pub items, 2 `Arc`-in-signature hits (one test constructor, one deliberate clock-seam alias), 14 `pub use` re-export arms matching the house single-surface pattern; no dependency types leak into signatures beyond the declared vocabulary re-exports + +## err +- d2b-provider-toolkit-p1#5 sev=medium blast=leaf effort=S verdict=actionable - the refused-forwarded-invocation audit is silently dropped for the documented U10 wire spelling: `invoke_named_with_fds_under_chain` audits the raw caller string, and `audit_named` returns when `BoundedToken::parse` fails, but the forwarded family names are PascalCase (`OpenPidfd`), which the `^[a-z][a-z0-9-]*$` token grammar rejects, so the Denied record the module contract promises for every refused invocation never lands for the uncommitted forwarded path - fix: audit the canonicalized name (lowercase/dash-strip before `BoundedToken::parse`, or audit the resolved entry's `operation.name()` when an entry exists) and add a harness case asserting the PascalCase forwarded spelling records a Denied event - [packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-toolkit/src/operations/envelope.rs:495-497, packages/d2b-provider-toolkit/src/operations/envelope.rs:341-346] + evidence: seed `\.unwrap\(\)|\.expect\(` = 105 (all remaining sites are `#[cfg(test)]` or invariant expects on literally-built values); `BoundedToken::parse` grammar at packages/d2b-contracts-resource/src/v3/execution_policy.rs:191; forwarded wire spelling "OpenPidfd" pinned by the envelope's own U10 doc and the committed catalog row at packages/d2b-broker/src/generated/broker_operation_catalog.rs:2632; the harness covers only the lowercase spelling (tests/harness.rs:501-522), so no test exercises the dropped path +- clean: `let _ = |\.ok\(\);` = 4 (deliberate best-effort watch cancels and the cfg(not) discard), `panic!|unreachable!|todo!|unimplemented!` = 0, `enum \w*Error` = 11 (closed code-carrying sets with `code()` + Display, split by caller action); `commit_grant`'s fail-closed `try_write` drop is the documented U4 pattern, not a finding + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 5, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 20, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 13; every wire type carries `deny_unknown_fields` + `rename_all = "camelCase"`, optionality uses `#[serde(default)]` deliberately, `skip_serializing_if = "Option::is_none"` on the reply wire, decode sites validate protocol markers and route binding, and all parse failures map to closed error codes; the hand-written `Drop` zeroizing `CredentialDeliveryKeyWire` is deliberate + +## obs +- d2b-provider-toolkit-p1#6 sev=low blast=leaf effort=S verdict=actionable - `serve_enrolled` drops a base-side wire-contract violation with no event: a frame that fails `GuestFrame::new` (empty or oversized, i.e. a peer protocol violation, not an agent refusal) is `continue`d silently, and the module doc only covers agent refusals as "the agent's to record", so the malformed frame is invisible to the operator - fix: emit a `warn!` with the frame length before dropping, keeping the session up - [packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src/base/guest.rs:446-452] + evidence: seed `\bprintln!\(|\beprintln!\(` = 5 (all process-entrypoint product output, `CLI-only path` allows), interpolated-message seed = 0, `tracing::` = 3; the drop sites read in full at guest.rs:490-499 +- clean: all tracing events use named fields (`warn!(name, provider, expected_zone, ...)`, `debug!(generation, ...)`); the five `println`/`eprintln` sites are CLI/process-entrypoint output, not telemetry + +## docs +- d2b-provider-toolkit-p1#7 sev=low blast=leaf effort=S verdict=actionable - key `Result`-returning public items document no failure conditions: `ProviderEntrypoint::new` (InvalidName), `admit` (NotAccepting), the three `with_*` binders, and `StartupPlan::derive`/`declare` (MissingInput/DuplicateOutput/Cycle) have one-line docs with no `# Errors` section or prose naming the refusal, so callers must read the error enum to learn when construction fails - fix: add `# Errors` sections (or one prose sentence naming the refusal) to the entrypoint constructors and the plan derivation - [packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/src/base/runtime.rs:383-384, packages/d2b-provider-toolkit/src/base/startup.rs:39] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 254, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 105; `#![deny(missing_docs)]` is on (lib.rs:46), so every item has a comment but failure conditions are prose-absent on the named items +- clean: first sentences are strong throughout (no `get_` accessors, no name-echoing openers), module docs present in every module, redaction and non-authorization contracts documented; the zero canonical-section count is house style, only the failure-condition gap is flagged + +## perf +- clean: seeds `format!\(` = 13 (error diagnostics, startup `Provider/{}` refs, invocation-id minting, tests - all cold), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 13 (bounded build/collect loops; the two receive loops cap at 64 KiB and 4 KiB), `\.to_string\(\)` = 4 (per-request ttrpc metadata values, cold); all sites static (unmeasured), no allocation in a per-packet or per-frame loop + +## conc +- d2b-provider-toolkit-p1#8 sev=low blast=leaf effort=S verdict=actionable - `invocations.fetch_add(1, Ordering::AcqRel)` uses release-acquire for a monotonic counter nobody synchronizes on; the identifier only needs uniqueness, so `Ordering::Relaxed` is the weakest correct ordering - fix: `fetch_add(1, Ordering::Relaxed)` - [packages/d2b-provider-toolkit/src/operations/envelope.rs:487] + evidence: seed `Atomic\w+|Ordering::` = 23; the counter's only reader is the minted id itself (envelope.rs:485-488), no paired load; contrast the load-bearing `admitted`/`lifecycle` atomics in base/runtime.rs, whose AcqRel/Acquire pairing is documented and deliberate +- clean: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 7 (tokio Mutex/RwLock held across awaits, correct choice; the std `Mutex` on the audit ring is documented as the frozen constructor contract), `thread_local!|unsafe impl (Send|Sync) for` = 0; the `admitted` counter, `lifecycle` state machine, and `bound` bind-once flag carry written ordering arguments + +## async +- clean: seeds `async fn|async move|\.await` = 120, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 2 (the credential-backend responder task, cancel-safe via watch channels, and one test spawn), `tokio::sync::(Mutex|RwLock|Notify)` = 5, `#\[tokio::(main|test)\]|Runtime::block_on` = 2 (tests); the drain wait arms the `Notify` before checking the count and bounds with `tokio::time::timeout` (the sanctioned shape), the backend state lock is a tokio Mutex across awaits, `serve_enrolled` uses a biased `select!`, and the three process entrypoints `block_on` on the calling thread with `CLI-only path` allows + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; the manifest sets `unsafe_code = "forbid"` (packages/d2b-provider-toolkit/Cargo.toml:13), and no `unsafe_code` allow exists in the part + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign boundary + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 + +## test +- clean: seeds over src = `#\[test\]|#\[tokio::test\]` = 22, asserts = 65, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; over tests/ = 46 test attrs, 185 asserts, 0 property/snapshot tooling, 0 ignored; the suites assert behavior (exact closed refusals, byte-identical canonical emission against a committed digest vector, offset parity between CLI and library verification, drain/readiness lifecycle, zeroizing round trips) rather than implementation, and no test computes its expectation with the code under test + +## Coverage +- idiom: 2 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 5/0/0; all five validation fns are boundary admission checks) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 5/20/0/13; wire types deny unknown fields, camelCase, closed-code failures) +- obs: 1 finding(s) +- docs: 1 finding(s) +- perf: clean (seeds ran: 13/13/4; all cold paths, static) +- conc: 1 finding(s) +- async: clean (seeds ran: 120/2/5/2; sanctioned Notify/timeout drain shape, tokio Mutex across awaits, cancel-safe responder) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 22/65/0/0 src + 46/185/0/0 tests/; behavioral boundary and round-trip suites) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md new file mode 100644 index 000000000..3ecd52e85 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md @@ -0,0 +1,85 @@ +# d2b-provider-toolkit-p2 - d2b-provider-toolkit - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10495 (excl. src/generated/**; src 6937 + tests 3558) | modules: testing/**, server/**, shared_provider.rs, credential.rs, service.rs, lib.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f): src/testing/**, src/server/**, src/shared_provider.rs, src/credential.rs, src/service.rs, src/lib.rs + +## idiom +- clean: seeds ran: 0/1/1 (`for \w+ in 0\.\.` = 0; `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1; `let mut \w+ = (String|Vec)::new\(\)` = 1). The one hand-written `impl Default for DispatchLimiter` (server/adapter.rs:448) is justified: `Arc` is not derivable and the manual impl preserves the frozen-ceiling invariant; the one `Vec::new()` accumulation (testing/mod.rs:900) is a recursive reference collector where an iterator pipeline would obscure the recursion. + +## own +- d2b-provider-toolkit-p2#1 sev=low blast=family effort=S verdict=actionable - serve_component_session clones all four fields of the owned decoded request per frame (`request.zone().clone(), request.provider_ref().clone(), request.method().clone(), request.payload().clone()`) instead of moving them out - fix: destructure `let ProviderRequest { request_id, zone, provider_ref, method, payload } = request;`, pass the owned values to `dispatch_for_route`, and call `codec.encode_response(&request_id, &response)` - [packages/d2b-provider-toolkit/src/server/adapter.rs:331-334] + evidence: seed `\.clone\(\)` = 76 hits in scope; the four clones at adapter.rs:331-334 are the only ones on an owned request that could be moves (the request is decoded into an owned value at adapter.rs:325 and used only through the loop). +- d2b-provider-toolkit-p2#2 sev=low blast=family effort=S verdict=actionable - the session loop clones the bound route out of the async mutex twice per frame (`self.authenticated_route.lock().await.clone()` at loop entry and per iteration) to compare identities - fix: compare inside the lock scope, e.g. `if self.authenticated_route.lock().await.as_ref() != Some(&route)`, avoiding the per-frame `AuthenticatedSessionRouteBinding` clone - [packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src/server/adapter.rs:314-316] + evidence: seed `\.clone\(\)` = 76 hits in scope; the route binding carries context and provider identity, so the two per-frame clones are the largest per-frame copies in the hot loop. +- d2b-provider-toolkit-p2#3 sev=low blast=leaf effort=S verdict=actionable - `retire_obsolete_children` sorts obsolete rows with `sort_by_key` over `(teardown_rank, row.key.name.clone())`, allocating a String per owned row per pass - fix: use `sort_by` with a comparator `teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name)).then_with(|| a.key.name.cmp(&b.key.name))` - [packages/d2b-provider-toolkit/src/shared_provider.rs:771] + evidence: seed `\.clone\(\)` = 76 hits in scope; this is the only sort-key clone (all other clone sites are Arc clones, snapshot reads, or owned-argument passes required by the async APIs). + +## type +- clean: seeds ran: 7 (`fn validate_\w+|fn check_\w+` = 7; `is_\w+: bool|\w+_flag: bool` = 0; `(mode|kind|state): String` = 0). Every hit is a boundary validation over already-parsed types (`check_closed_code_set`, `check_descriptor_conformance`, `check_provider_conformance`, `validate_attachment_indexes`, `validate_bound_request`, `validate_authenticated_provider_request`, `validate_provider_route`); no boolean-flag soup, no stringly-typed state, no Option-pair invariants in the scope. + +## api +- d2b-provider-toolkit-p2#4 sev=low blast=leaf effort=S verdict=actionable - two dead public methods on `GeneratedProviderServiceServer`: `response_request_id` is a pure identity function (`request_id` in, same reference out) and `generated_service` has no callers anywhere - fix: delete both methods (and the `response_request_id` doc), keeping `generated_services()` which the registration-boundary doc justifies - [packages/d2b-provider-toolkit/src/server/service.rs:297-299, packages/d2b-provider-toolkit/src/server/service.rs:174-176] + evidence: census: `response_request_id` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (the definition); `generated_service\(\)` = 0 hits; `generated_services\(\)` = 1 hit (toolkit's own test). +- d2b-provider-toolkit-p2#5 sev=low blast=family effort=S verdict=actionable - `SharedProviderEffectRequest::envelope()` (the old-shape owner-envelope document) has zero callers and clones the full spec and metadata Values on every call - fix: delete the method; the driver and families read `spec`/`metadata` directly - [packages/d2b-provider-toolkit/src/shared_provider.rs:525-531] + evidence: census: `request\.envelope\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits; the method is not in the lib.rs re-export list but is pub on a pub struct. +- d2b-provider-toolkit-p2#6 sev=low blast=family effort=S verdict=actionable - `TestHarness::clock()` returns `&Arc`, exposing the Arc in the public signature when callers only need the clock - fix: return `&DeterministicClock` (callers at testing/mod.rs:686 and tests/harness.rs:857-909 all deref) - [packages/d2b-provider-toolkit/src/testing/mod.rs:530-532] + evidence: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 4 hits in scope; the other three (spec decoder return, `family` field, `created_children`) genuinely share ownership, this one does not. + +## err +- d2b-provider-toolkit-p2#7 sev=medium blast=family effort=M verdict=actionable - `SharedProviderDriver::new` panics via `ZoneId::parse(args.zone).expect("driver zone was validated at construction")`, but `SharedProviderDriverArgs.zone` is a plain pub `String` with no validation anywhere at the factory boundary, so a family passing an invalid zone crashes the provider process at driver construction - fix: hold `ZoneId` in `SharedProviderDriverArgs` (parse once in `SharedProviderDriverFactory::new` and return a `Result`), or make `create` fallible - [packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/src/shared_provider.rs:539-546] + evidence: seed `\.unwrap\(\)|\.expect\(` = 90 hits in scope (about 70 in `#[cfg(test)]`/tests); census: `SharedProviderDriverArgs` is constructed at d2b-provider-device-security-key/src/driver.rs:327, d2b-provider-device-usbip/src/driver.rs:217, d2b-provider-device/src/driver.rs:296, d2b-provider-network-local/src/driver.rs:270, all passing a caller-supplied zone String; the expect's claimed invariant is not enforced by the type. +- d2b-provider-toolkit-p2#8 sev=low blast=family effort=S verdict=actionable - `key_ref` panics via `expect("manager keys carry canonical resource references")` on a `ResourceKey` whose fields are pub and unvalidated (`ResourceKey::new` accepts any strings), so the pub helper can panic on a non-canonical key a caller constructs - fix: return `Result` (map to `InvalidResource`) like the sibling `owner_ref`/`resource_uid` helpers - [packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtime/src/spec_store.rs:60-63] + evidence: seed `\.unwrap\(\)|\.expect\(` = 90 hits in scope; census: `key_ref\(` = 20 call sites across packages (manager-derived keys today, so the invariant holds in practice, but the type does not enforce it). +- d2b-provider-toolkit-p2#9 sev=medium blast=family effort=S verdict=actionable - `Fixture::method` maps `SpecifiedProviderMethod` with a `_ => unreachable!("specified Provider method is closed")` arm, but the enum is `#[non_exhaustive]` (d2b-contracts-provider/src/v3/provider.rs:2759), so any future contract variant becomes a runtime panic in every fixture-based test suite - fix: return `Result` and map unknown methods to `WireInvalid`, updating the two call sites (fixture.rs:190 and the `ProviderAgentService` impl) - [packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192] + evidence: seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 1 hit in scope (this site); the enum it matches is declared `#[non_exhaustive]`, which forces the `_` arm and makes the panic reachable from a contract extension. +- d2b-provider-toolkit-p2#10 sev=medium blast=family effort=S verdict=actionable - every fake port swallows the recorder-capacity error with `let _ = self.recorder.record(...)`, so `FakePortError::RecorderFull` is never constructed (dead variant in the public closed set `ALL`) and a test exceeding `MAX_RECORDED_CALLS` silently truncates its record, contradicting the variant's own doc "the call is refused rather than dropped silently" - fix: map `ProviderToolkitError::CapacityOutOfRange` to `FakePortError::RecorderFull` and return it from the fake methods (or delete the variant and its `ALL` slot) - [packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/src/testing/fakes.rs:289-291, packages/d2b-provider-toolkit/src/testing/fakes.rs:337-339, packages/d2b-provider-toolkit/src/testing/fakes.rs:391-393, packages/d2b-provider-toolkit/src/testing/fakes.rs:430, packages/d2b-provider-toolkit/src/testing/fakes.rs:464] + evidence: seed `let _ = |\.ok\(\);` = 10 hits in scope; six are these swallowed `record` results (`FakePortError::RecorderFull` appears only in the enum, its `code()` match, and `ALL`); the recorder's own error path (fakes.rs:194-198) is unreachable from any fake port. + +## serde +- clean: seeds ran: 0/0/0/4 (`derive(...Serialize/Deserialize)` = 0; `serde(...)` attributes = 0; hand-written Deserialize = 0; `serde_json::from_|to_` = 4). The four sites are Value-level decodes with explicit object validation at the boundary (shared_provider.rs:369-372, 385); no typed wire types are defined in this scope, so there is no deserialization-into-domain-type surface to judge. + +## obs +- d2b-provider-toolkit-p2#11 sev=low blast=family effort=S verdict=actionable - three message-only `warn!` events in the authenticated session loop carry no named fields even though zone/provider/method are in scope at each site, so the events are not queryable per provider - fix: add fields, e.g. `warn!(zone = ?session.route_binding().zone(), "component session receive failed; closing provider session")` and the analogous provider/method fields at the readiness and loop-failure sites - [packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src/server/session.rs:255, packages/d2b-provider-toolkit/src/server/session.rs:262] + evidence: seeds: `\bprintln!\(|\beprintln!\(` = 0; `(info|debug|warn|error|trace)!\(` = 36 hits, of which 33 already carry named fields and 3 are message-only with no enclosing span to inherit fields from (`\.instrument\(|#\[instrument` = 0 in scope). + +## docs +- d2b-provider-toolkit-p2#12 sev=low blast=leaf effort=S verdict=actionable - no public item in the scope carries the canonical `# Errors` section even though many return `Result` with closed, non-obvious failure sets (`check_descriptor_conformance` has ten `ConformanceError` variants; `operation_deadline` fails on exhausted deadlines; `validate_attachment_indexes` fails on non-monotone indexes) - fix: add `# Errors` sections naming the variant per condition to the Result-returning pub items, starting with conformance.rs:267, conformance.rs:291, credential.rs:111, credential.rs:131, adapter.rs:31 - [packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolkit/src/testing/conformance.rs:291, packages/d2b-provider-toolkit/src/credential.rs:111, packages/d2b-provider-toolkit/src/credential.rs:131, packages/d2b-provider-toolkit/src/server/adapter.rs:31] + evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 150 hits (all documented; `#![deny(missing_docs)]` is on); `/// # (Examples|Errors|Panics|Safety)` = 0 hits; `-> Result<` = 30 hits. + +## perf +- d2b-provider-toolkit-p2#13 sev=medium blast=family effort=M verdict=actionable - every reconcile and delete pass clones the row's full spec document (`spec: envelope.value().clone()` at shared_provider.rs:944 and 1024) into the request even though the envelope outlives the effect call and the request is only read by the family - fix: change `SharedProviderEffectRequest.spec` from `Value` to `&'a Value` (the struct is constructed only in this file; family call sites read via method calls and auto-deref), removing one full-spec allocation per pass - [packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/src/shared_provider.rs:1024, packages/d2b-provider-toolkit/src/shared_provider.rs:479-481] + evidence: static (unmeasured); seed `format!\(` = 20 hits and `Vec::new\(\)` = 15 hits in scope, but the spec clone is the only per-pass allocation proportional to spec size (the pass runs on every resync cadence and every change); the `operation_id` format! per pass is small and not flagged. + +## conc +- clean: seeds ran: 40 (`std::thread::|thread::spawn|thread::scope` = 0; `\bMutex<|\bRwLock<` = 4; `Atomic\w+|Ordering::` = 36; `thread_local!|unsafe impl (Send|Sync) for` = 1). Atomics use correct orderings (Acquire/Release pairs on the limiter and server state, Relaxed on the delivery-sequence counter, AcqRel in `DeterministicClock::advance`); `shutdown` arms the `Notify` before checking in-flight (the clippy.toml-sanctioned pattern); the `thread_local!` runtime in credential.rs is the sanctioned synchronous-path allow. + +## async +- clean: seeds ran: many (`async fn|async move|\.await` throughout; `tokio::spawn` = 1 at server/mod.rs:68; `tokio::sync::(Mutex|RwLock|Notify)` = 3; `#\[tokio::(main|test)\]|Runtime::block_on` = 0). No blocking work inside async contexts (the one `block_on` is the documented synchronous dispatch half with the sanctioned `reason = "synchronous path"` allow); `ContextChildSurface` holds a `tokio::sync::Mutex` guard across the context's own awaits (async-aware, never across another effect call); both session loops are cancellation-aware; the spawn/yield/is_finished immediate-failure check in `serve_authenticated_route` aborts cleanly on error paths. + +## unsafe +- N/A: seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0; `// SAFETY:` = 0; `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; `unsafe_code` = 0 (manifest carries `unsafe_code = "forbid"` under `[lints.rust]`). + +## ffi +- N/A: seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0; `catch_unwind` = 0; `repr\(C\)|repr\(transparent\)` = 0; `CStr|CString|c_char` = 0. No foreign boundary in this scope. + +## macro +- N/A: seeds: `macro_rules!` = 0; `proc_macro|syn::|quote!` = 0; `\$crate` = 0; `to_compile_error|new_spanned` = 0. No macro definitions in this scope. + +## test +- clean: seeds ran: 55 in src + 90 in tests (`#\[test\]|#\[tokio::test\]` = 20 src + 14 tests; `assert_eq!\(|assert_ne!\(|assert!\(` = 35 src + 76 tests; `proptest!|insta::assert|rstest` = 0; `#\[ignore\]` = 0). Tests assert behavior and error variants rather than Display strings, expectations are human-written or independent (`br#"..."#` literals, closed-code sets), the shared statics (`SEEN_INVOCATIONS`, `TEMP_FILE_SEQUENCE`) are cleared or unique per test so runs stay deterministic, and the `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]` sites use the sanctioned reason. + +## Coverage +- idiom: clean (seeds ran: 0/1/1; hand-written Default justified, no index loops) +- own: 3 finding(s) +- type: clean (seeds ran: 7/0/0; all hits are boundary validations over parsed types) +- api: 3 finding(s) +- err: 4 finding(s) +- serde: clean (seeds ran: 0/0/0/4; Value-level decode with explicit object validation) +- obs: 1 finding(s) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 0/4/36/1; correct atomic orderings, sanctioned Notify pattern) +- async: clean (seeds ran: many/2/3/0; no blocking in async contexts, cancellation-aware loops) +- unsafe: N/A (seeds: 0/0/0/0; manifest forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 34 tests + 111 assertions; behavior and error-variant assertions, deterministic) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md new file mode 100644 index 000000000..4e3e967e6 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md @@ -0,0 +1,97 @@ +# d2b-provider-transport-azure-relay - d2b-provider-transport-azure-relay +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5952 (excl. src/generated/**, none present) | modules: whole crate (auth, backpressure, credential_client, guest_credential, guest_zone_link, lib, relay_transport, transport_settings; tests: backpressure_credit, fake_relay_transport, listener_sender_conformance, transport_credentials, transport_settings_schema) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) + +## idiom +- d2b-provider-transport-azure-relay#1 sev=low blast=leaf effort=S verdict=actionable - `impl Clone for RelaySecret` hand-writes what `#[derive(Clone)]` generates identically (`Zeroizing>` clones into a fresh `Zeroizing` either way), and the manual version can drift from the field - fix: replace the impl block with `#[derive(Clone)]` on `RelaySecret` - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239, packages/d2b-provider-transport-azure-relay/src/credential_client.rs:217] + evidence: idiom2 `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits in src; the other hit (Default for AzureRelaySocketConnector, relay_transport.rs:249) is deliberate because a field-wise derive would set `sas_ttl_secs: 0` +- d2b-provider-transport-azure-relay#2 sev=low blast=leaf effort=S verdict=actionable - `build_connect` builds the literal `"Bearer"` by collecting a char array (`['B','e','a','r','e','r']`) into a fresh String on every connect, where a `const`/literal `"Bearer"` reads plainly and allocates nothing - fix: use a `const BEARER: &str = "Bearer"` (or inline literal) in the `ServiceBusAuthorization` header format - [packages/d2b-provider-transport-azure-relay/src/auth.rs:249-253] + evidence: idiom1 `for \w+ in 0\.\.` = 1 hit (test loop in fake_relay_transport.rs), idiom3 `let mut \w+ = (String|Vec)::new\(\)` = 0; the char-array collect is a statement-style construction the skill's expression lens names +- clean: idiom1 = 1 (test-only `for _ in 0..=MAX_RELAY_GENERATION_FENCES` loop), idiom2 = 2 (both judged above), idiom3 = 0; naming (`as_`/`to_`/`into_`, no `get_`) and derive discipline otherwise consistent across the crate + +## own +- d2b-provider-transport-azure-relay#3 sev=low blast=leaf effort=S verdict=actionable - `ScopedCredentialRequest::with_deadline` takes `&self` and clones all four owned fields (zone, credential_ref, execution_ref, binding) only to rebuild the struct, while its single in-tree caller can consume the request - fix: change the signature to `with_deadline(self, deadline_ms)` and rebuild with `Self { deadline_ms, ..request }` plus `validate()` - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:190-198, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:1315-1317] + evidence: own1 `\.clone\(\)` = 18 hits in src (12 production, 6 in cfg(test)); census: `with_deadline` over packages = 1 call site (relay_transport.rs:1316), so consuming `self` breaks no caller +- d2b-provider-transport-azure-relay#4 sev=low blast=leaf effort=S verdict=actionable - `GatewayCredential::from_material` clones all four secret Strings out of an owned `GatewayCredentialMaterial` (forced today because the material type implements `Drop`, which forbids partial moves) where storing the material as one field would move it in without copies - fix: give `GatewayCredential` a single private `material: GatewayCredentialMaterial` field and move it in `from_material`; field accessors and the redacting `Debug` stay unchanged - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:267-277, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:271-275] + evidence: own1/own2 counts in guest_credential.rs = 6 clone + 6 to_owned/to_vec/to_string hits; the four clones at 272-275 are the only ones not required by a sharing boundary +- clean: own1 = 18 (src), own2 = 28 (src), own3 = 1 (`Arc>` active-lease table in GatewayGuestCredentialPort, genuinely shared across port clones/tasks), own4 = 0; remaining clones are Arc clones at spawn/`Arc::clone` boundaries, `binding.clone()` into the lease/active table, and wire-boundary `to_vec`/`to_owned` conversions - all explainable in one sentence + +## type +- d2b-provider-transport-azure-relay#5 sev=low blast=leaf effort=S verdict=actionable - `GatewayGuestZoneLinkRuntime` carries `credential_generation: Option` and `credential_send_key_digest: Option<[u8; 32]>` as two independent Options that are always set or unset together (from_sealed sets both, from_scoped sets neither), leaving the half-set state representable and forcing `write_open_observation`'s `let (Some, Some) else` guard - fix: replace the pair with one `Option` struct (or a `Sealed`/`Scoped` enum carrying the marker data) so the impossible half-set combination stops compiling - [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:258-262] + evidence: type1 `fn validate_\w+|fn check_\w+` = 3 hits (auth.rs validate_endpoint/validate_credential_text/validate_credential - boundary validation on a pub API, kept), type2 = 0, type3 = 0; the correlated-Option pair is the only representable-illegal-state candidate +- clean: type1 = 3 (auth.rs boundary validators, correct parse-at-boundary placement), type2 = 0, type3 = 0; no boolean-flag soup or stringly-typed state; the `RelaySessionPhase` enum and `RelayGenerationFence` state machine already encode their transitions in types + +## api +- d2b-provider-transport-azure-relay#6 sev=low blast=leaf effort=S verdict=actionable - `RelayCredentialPort::acquire` is a required trait method whose only production implementation (GatewayGuestCredentialPort) returns `Err(BindingRequired)` - the same fail-closed policy the trait already gives `acquire_bound` as a default - so every implementer must write a method that never succeeds - fix: give `acquire` a default body returning `Err(RelayCredentialError::BindingRequired)` and delete the redundant overrides in GatewayGuestCredentialPort and the test fakes - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:491-497, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:387-392] + evidence: api1 `\bpub (fn|struct|enum|trait|type|const|mod) ` = 140 hits in src; census: `RelayCredentialPort` over packages = 22 hits, `acquire` overrides = 9 sites (1 production + 8 test fakes), none callable to success +- d2b-provider-transport-azure-relay#7 sev=low blast=leaf effort=S verdict=actionable - `set_drop_hook` takes `Arc` in a public signature although the lease is the sole owner of the hook (it is stored once and called on drop), forcing every caller to allocate an Arc for a single-owner value - fix: take `Box` or a generic `F: Fn(u64) + Send + Sync + 'static`; call sites (guest_credential.rs:455, tests) change `Arc::new)...)` to `Box::new)...)` - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343-347, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:455] + evidence: api2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits in src (this signature and `GatewayGuestCredentialPort::with_clock`; the latter genuinely shares the credential and clock across port clones and is kept); api3 `^\s*pub use ` = 0 (lib.rs re-export arms are the house single-surface pattern, judged clean) +- clean: api1 = 140, api2 = 2 (both judged), api3 = 0; the lib.rs `pub use` arms are the house single-surface pattern; no dependency types leak into signatures beyond the two judged sites; `AzureRelaySocketConnector` is a builder with `const fn new()` and no `Default`-shape traps + +## err +- d2b-provider-transport-azure-relay#8 sev=medium blast=leaf effort=S verdict=actionable - `From` and `From` for `GatewayGuestZoneLinkError` discard the source entirely (`fn from(_: ...)`), collapsing every credential failure (Unreadable, Malformed, Expired, BadMode, BadOwner, Crypto) into one generic variant with no chain, so callers cannot distinguish or log the cause - fix: carry the source (e.g. `CredentialUnavailable { source: CredentialError }` with `#[source]`-style chaining, or keep the collapse but retain `source()`), matching the err skill's context-survival rule - [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69-78, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:181-187] + evidence: err4 `enum \w*Error` = 7 error enums in src; the two `From` impls at guest_zone_link.rs:69-78 are the only source-discarding conversions in the crate (the crate's own Display codes are not pinned in docs/reference/error-codes.md - checked - so the enum shape is not wire-visible) +- d2b-provider-transport-azure-relay#9 sev=medium blast=leaf effort=S verdict=actionable - clock-before-epoch failures are silently swallowed with `unwrap_or(0)` in `system_now_unix()` (guest_zone_link) and `system_now_unix_ms()` (guest_credential), and a zero `now` makes `load_sealed_inner`'s expiry check fail open (`now >= not_after` is false for any positive `not_after`), accepting an expired envelope - while auth.rs returns `RelayError::Clock` and relay_transport.rs maps the same condition to `CredentialExpired` - fix: propagate a clock error (or reject the load) instead of substituting 0, mirroring `RelayError::Clock` - [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:665-669, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:178-183] + evidence: err1 `\.unwrap\(\)|\.expect\(` = 72 hits in src, 70 inside `#[cfg(test)]`; the 2 production sites (relay_transport.rs:568 `expect("inserted generation state")`, relay_transport.rs:1129 `expect("credential lease guard must own a lease")`) are invariant expects the panic policy permits; err3 `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0 in src +- clean: err2 `let _ = |\.ok\(\);` = 8 hits, all deliberate best-effort cleanup (`let _ = socket.close().await` on already-failing paths, `let _ = fs::remove_file` of a temp marker) - judged per site and kept; panic policy otherwise consistent: Result all the way to the transport boundary, `revoke_or` preserves the more specific error + +## serde +- d2b-provider-transport-azure-relay#10 sev=medium blast=family effort=M verdict=needs-contract - `RelayTransportSettings` derives `Deserialize` without `try_from`, so `serde_json::from_slice::` at d2bd/src/composition.rs:843 accepts identifiers that `new()`/`validate()` reject - including the secret-shape exclusion (`SharedAccessSignature`) that exists only in Rust and not in the pinned schema `docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json` (whose patterns admit lowercase letters) - fix: add `#[serde(try_from = "...")]` reusing `validate()`, and first encode the secret-shape exclusion in the schema so schema and Rust agree - [packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:31-41, packages/d2bd/src/composition.rs:843-846] + evidence: serde1 `derive\([^)]*(De)?[Ss]erialize` = 2, serde2 `serde\((rename_all|deny_unknown_fields|try_from|...)` = 3, serde4 `serde_json::from_|serde_json::to_` = 4 over src+tests; census: `RelayTransportSettings` over packages = 22 hits including the d2bd `from_slice`; the schema pattern-vs-Rust divergence (secret-shape exclusion) makes the tightening needs-contract per U1 (d) 7 +- d2b-provider-transport-azure-relay#11 sev=low blast=leaf effort=S verdict=policy-confirmed - `parse_material_json` hand-walks `serde_json::Value` paths for a fixed nested shape (`relayListen`/`relaySend` keyName/key) that a derived `Deserialize` with `rename_all = "camelCase"` plus a validate pass would express - this is the recorded live-admission-gate class, refused in the prior audit - fix: only rework if the admission gate is deliberately replaced (derive + `try_from` validation), citing changed evidence - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264] + evidence: serde3 `impl .*Deserialize.*for` = 0; the Value-walk is the same class as the refused qemu guest/provider-spec admission gates - docs/explanation/over-engineering-audit-record.md:229-231 ("hand-written deserializers ... kept as the live admission gate") - so the verdict is policy-confirmed per U1 (d) 6 +- clean: serde1 = 2 (SealedCredentialFile, RelayTransportSettings), serde2 = 3 (rename_all camelCase + deny_unknown_fields on both wire types, `#[serde(default)]` on `not_after`), serde3 = 0, serde4 = 4; the sealed-envelope type is a model serde boundary (deny_unknown_fields, version field checked by hand, AAD-bound plaintext parsed after decrypt) + +## obs +- d2b-provider-transport-azure-relay#12 sev=low blast=leaf effort=S verdict=actionable - five `tracing::warn!` events at the credential-port boundary are message-only (guest_credential.rs:406, 423, 476, 483 - and 438 carries `active_leases` but no role), while sibling events in the same crate carry `role = ?role`, `binding = ?binding`, `reason = %error`; a lease-acquire rejection or revoke mismatch is not attributable to a role or lease without those fields - fix: add `role = ?role` (and `lease_id` where available) to those events so the crate's event schema is uniform - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:423-425, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:476-478, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:483-485] + evidence: obs2 `(info|debug|warn|error|trace)!\("` = 25 hits in src (guest_credential 5, guest_zone_link 4, relay_transport 16); obs1 `\bprintln!\(|\beprintln!\(` = 0; obs3 `\.instrument\(|#\[instrument` = 0; no secret reaches any event (all Debug/Display paths redact, verified per site) +- clean: obs1 = 0 (no println in the library), obs3 = 0, obs4 = 25 (tracing only, no `log` facade); relay_transport's 16 events consistently carry `provider` + `role` + `binding` + `reason`; the three drop-hook cleanup warnings (relay_transport.rs:1155-1190) are best-effort edges with no lease data in scope + +## docs +- d2b-provider-transport-azure-relay#13 sev=low blast=leaf effort=M verdict=actionable - none of the 80 Result-returning public items carries a canonical `# Errors` section (docs2 = 0 crate-wide), so failure conditions are discoverable only by reading the error enums; e.g. `mint_sas`, `build_connect`, `CreditWindow::new`, `RelayTransportSettings::new` - fix: add `# Errors` sections naming the conditions (mint_sas: InvalidTtl, TtlTooLong, InvalidEndpoint, InvalidCredential, Key, Clock) on the pub Result items - [packages/d2b-provider-transport-azure-relay/src/auth.rs:229-246, packages/d2b-provider-transport-azure-relay/src/backpressure.rs:31-36, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:18-22] + evidence: docs1 `^\s*pub (fn|struct|enum|trait|const|type)` = 133 hits (MULTILINE count), docs2 `/// # (Examples|Errors|Panics|Safety)` = 0, docs3 `-> Result<` = 80; `#![deny(missing_docs)]` at lib.rs:4 means every pub item is otherwise documented - the gap is canonical sections only +- clean: module docs (`//!`) on all 8 modules, first-sentence discipline consistent, all pub items documented (missing_docs denied), redaction rationale documented on every secret-bearing Debug; no doctests present (docs2 = 0), which is consistent with the crate's integration-test style + +## perf +- d2b-provider-transport-azure-relay#14 sev=medium blast=leaf effort=S verdict=actionable - `generation_key` allocates three Strings (`to_owned` x3) on every `RelayConnection::send`/`receive` via `ensure_current_generation -> is_current`, and the key is invariant for a connection's lifetime (it derives from the binding the connection already owns) - fix: precompute the `(String, String, String)` key once in `RelayConnection` (or key the fence map on a borrowed/hashed form) and pass it to `is_current`, removing three heap allocations from the per-frame I/O path - [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:629-630, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:814, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:844] + evidence: static (unmeasured) - no benchmark exists in this crate; perf1 `format!\(` = 22 in src, perf2 `Vec::new\(\)|...` = 2, perf3 `\.to_string\(\)` = 0; the allocation site is on the frame I/O path (send/receive call is_current every call) +- d2b-provider-transport-azure-relay#15 sev=low blast=leaf effort=S verdict=actionable - `read_policy_file` grows `Zeroizing::new(Vec::new())` via `read_to_end` without a capacity hint although the file size is already known from the earlier `metadata()` call - fix: `Vec::with_capacity(meta.len() as usize)` before reading - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618] + evidence: static (unmeasured); perf2 = 2 hits - the other (credential_aad's `Vec::with_capacity`) already sizes correctly, so this is the only grow-by-read site +- clean: the remaining format! sites are cold (SAS minting, connect URL building, the one-shot observation marker, digest_hex at 32 x format! for a one-time 64-char hex) and the frame copy in `RelayWebSocketSocket::send` (`as_bytes().to_vec()`) is inherent to the tungstenite `Message::Binary(Vec)` API; no attacker-controlled hashing, no unbounded collections + +## conc +- clean: conc1 `std::thread::|thread::spawn|thread::scope` = 0, conc2 `\bMutex<|\bRwLock<` = 8 in src (5 tokio::sync::Mutex on RelayConnection + 1 tokio::sync::Mutex active-lease table + 1 StdMutex generation fence + 1 StdMutex in tests), conc3 `Atomic\w+|Ordering::` = 9 (lease-id and challenge counters, `Ordering::Relaxed` - the weakest correct ordering for counters), conc4 = 0; the StdMutex fence is a sanctioned `synchronous path` allow (relay_transport.rs:535-541, needed for noexcept Drop cleanup) with a written reason and `into_inner` poison recovery; lock ordering across the five tokio Mutexes is acyclic (write_lock -> credits -> phase -> session_permit -> generation_lease -> socket, each guard dropped before the next acquisition) + +## async +- d2b-provider-transport-azure-relay#16 sev=medium blast=leaf effort=S verdict=actionable - `RelayConnection::send` is not cancellation-safe: `credits.reserve(size)` is followed by `self.socket.send(frame).await`, and the rollback runs only on `Err` - if the future is cancelled between reserve and completion (e.g. by the session engine's timeout wrapper), the reservation leaks and the connection is permanently starved of up to 64 KiB of credit - fix: wrap the reservation in a small RAII guard that rolls back on drop unless the send committed (or reserve after the await using a pre-checked window) - [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833] + evidence: async1 `async fn|async move|\.await` = 93 hits in relay_transport.rs (134 in src total); cancellation-path analysis is static; the leak is bounded per event but unbounded over repeated cancellations on a live connection +- clean: async2 `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0 in src, async3 `tokio::sync::(Mutex|RwLock|Notify)` = 2 (active-lease table, RelayConnection state - guards never held across foreign awaits beyond the socket call), async4 `#\[tokio::(main|test)\]|Runtime::block_on` = 4 (all `#[tokio::test]`); `spawn_bounded_revoke` uses `Handle::try_current()` so a runtime-less Drop degrades to a warn, not a panic; cancellation of `open_inner` is covered by Drop-based cleanup (generation attempt abort, lease-guard best-effort revoke); no blocking calls on executor workers (the sync file I/O is confined to the sanctioned `synchronous path` composition boundary) + +## unsafe +- N/A: seeds 1-3 (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0) all zero; seed 4 `unsafe_code` = 1 (`#![forbid(unsafe_code)]` at lib.rs:4 plus `unsafe_code = "forbid"` in the manifest) - the forbid attribute alone does not make the lens applicable per the card + +## ffi +- N/A: seeds 1-4 (`extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0) all zero over src; the crate crosses no foreign-language boundary (libc is used only for `O_NOFOLLOW` in the file policy check) + +## macro +- N/A: seeds 1-4 (`macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0) all zero in src; the single `macro_rules!` in tests (fake_relay_transport.rs, `legacy_scoped_adapter!`) is a test-only helper macro, which the card exempts + +## test +- clean: test1 `#\[test\]|#\[tokio::test\]` = 58, test2 `assert_eq!\(|assert_ne!\(|assert!\(` = 141, test3 `proptest!|insta::assert|rstest` = 0, test4 `#\[ignore\]` = 0; assertions target behavior and error variants (never Display strings), the fake harness is deterministic (injected clock, no network; `valid_expiry()` uses the real clock only as a far-future bound), and the cancellation/timeout tests use bounded `timeout` + `yield_now` polling; the only weak assertion is `helper_surface_does_not_reintroduce_unbounded_window` (fake_relay_transport.rs:1407-1409), a bound pin that can still fail if the constant moves - tolerable, not a cannot-fail test + +## Coverage +- idiom: 2 finding(s) +- own: 2 finding(s) +- type: 1 finding(s) +- api: 2 finding(s) +- err: 2 finding(s) +- serde: 2 finding(s) +- obs: 1 finding(s) +- docs: 1 finding(s) +- perf: 2 finding(s) +- conc: clean (seeds ran: 0/8/9/0; tokio Mutex state on RelayConnection is acyclic and StdMutex fence is a sanctioned synchronous-path allow) +- async: 1 finding(s) +- unsafe: N/A (seeds: 0/0/0 all zero; `unsafe_code = "forbid"` in manifest and lib.rs, no unsafe sites) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign-language boundary) +- macro: N/A (seeds: 0/0/0/0 all zero in src; one test-only helper macro in tests/) +- test: clean (seeds ran: 58/141/0/0; behavior- and variant-level assertions, deterministic harness, no ignored tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md new file mode 100644 index 000000000..b37d59b2a --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md @@ -0,0 +1,96 @@ +# d2b-provider-transport-vsock - d2b-provider-transport-vsock +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4128 (excl. src/generated/**) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (whole crate) + +## idiom +- d2b-provider-transport-vsock#1 sev=low blast=leaf effort=S verdict=actionable - `ReadySession::disconnect` takes `mut self`, assigns `SessionState::Disconnected` to a by-value copy that is immediately dropped, and then returns the assigned constant - the mutation is dead code and the method contract is fully expressed by returning the constant. - fix: `pub fn disconnect(self) -> SessionState { SessionState::Disconnected }`, dropping `mut` and the state assignment - [packages/d2b-provider-transport-vsock/src/auth.rs:221-224] + evidence: idiom seeds ran:0/3/0; site found by full-file read of auth.rs. + +## own +- clean: all 12 hits (seeds ran:5/0/7/0) are explainable:the five `.clone()` sites share `BridgeControl`/`ReadySession`/`GuestIdentity` values where the clone is the ownership transfer the spanned bridge task or session object needs; the seven `Arc>` fields back genuinely multi-owner service state (active/completed maps, per-entry history/phase/exit, subscriber list) shared between the service and its spawned bridge tasks, matching the U1 shared-state false-positive note. + + + +## type +- clean: seeds all zero (0/0/0) but lens is applicable (the crate declares many structs/enums): no `validate_`/`check_` fns, boolean flag soup, or stringly state;`VsockTransportSettings`'s validate-at-callsite shape (pub fields + later `validate()`) is reported under serde as a wire-boundary validation gap rather than here. + + + +## api +- clean: seeds 106/0/10; the pub surface is the deliberate single-path `lib.rs` re-export pattern(10 arms), every exported item documented under `#![deny(missing_docs)]`; no `Arc`/`Rc`/`Box`/`RefCell` or dependency types appear in public signatures, and the three effect-port traits keep small required surfaces with associated types for the per-implementer stream/handle types. + + + +## err +- clean: seeds 8/1/0/7; the 6 relay.rs `.expect("reservation")`/`.expect("listener")` sites are invariant assertions after an explicit `Some)...)` assignment in the same function (accepted by the skill's "expect names the invariant" rule),the 2 service.rs unwraps live under `#[cfg(test)]` mod tests, and the single `let _ =` is a deliberately ignored best-effort watch send in `BridgeControl::stop`. + + + +## serde +- d2b-provider-transport-vsock#4 sev=medium blast=wide effort=M verdict=needs-contract - `VsockTransportSettings` deserializes untrusted wire JSON with no boundary validation: invalid `guest_ref`/`connect_timeout_seconds` land as ordinary values and are only rejected by later explicit `validate()` calls (in `new()` and `ZoneLinkSpec::validate`), and the all-public fields let any caller build an invalid settings value silently; a parse-once `try_from` type would reject once at the wire. - fix: `#[serde(try_from = "VsockTransportSettingsWire")]` with a private raw wire shape +`TryFrom` validation, plus private fields and accessors; wire field names/schema stay unchanged - [packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transport-vsock/src/settings.rs:42-50, packages/d2b-provider-transport-vsock/tests/schema.rs:13-18] + evidence: serde seeds ran:2/4/0/0; census: `VsockTransportSettings` over packages/, tests/, nixos-modules/, labs/, docs/reference/ = 17 hits, all within this crate + its tests; wire shape pinned by the committed schema at docs/reference/schemas/v3/providers/transport-vsock.transport-binding.json (referenced from settings.rs:56). + +## obs +- d2b-provider-transport-vsock#2 sev=low blast=leaf effort=S verdict=actionable - the 9 transport-open rejection warn events log `endpoint`/`binding` fields whose `Display` impls are constants ("opaque-endpoint"/"opaque-binding"), so the named fields cannot correlate any event to a specific transport - an operator debugging repeated opens sees identical values every time. - fix: drop the `endpoint`/`binding` fields from the open-reject warn events, or give `OpaqueEndpointId`/`OpaqueBindingId` a real `Display` over `self.0` while keeping `Debug` redacted - [packages/d2b-provider-transport-vsock/src/service.rs:392, packages/d2b-provider-transport-vsock/src/service.rs:466, packages/d2b-provider-transport-vsock/src/service.rs:65-67, packages/d2b-provider-transport-vsock/src/service.rs:99-101] + evidence: obs seeds ran:0/0/0/13; static read of the 9 warn-field sites. +- d2b-provider-transport-vsock#3 sev=low blast=leaf effort=M verdict=actionable - bridge-drop,and bridge-copy-failure debug events carry no transport identity (no handle, endpoint, or binding field), so with up to `MAX_ACTIVE_TRANSPORTS` concurrent transports an operator cannot tell which one dropped an event or failed a copy - thread a handle/endpoint identity into the open path's spawned bridge task and through `emit_event`. - fix: capture `endpoint_id`/`binding_id` into the `tokio::spawn` block in `open_transport` and pass them to `emit_event`, adding named fields to the three drop events and the `run_bridge` copy-failure site - [packages/d2b-provider-transport-vsock/src/service.rs:735, packages/d2b-provider-transport-vsock/src/service.rs:766, packages/d2b-provider-transport-vsock/src/service.rs:851, packages/d2b-provider-transport-vsock/src/bridge.rs:186] + evidence: obs seeds ran:0/0/0/13; static read of the emit_event/drop sites. + + + +## docs +- d2b-provider-transport-vsock#5 sev=low blast=leaf effort=M verdict=actionable - 38 public `Result`-returning items carry no `# Errors` doc sections, so callers must infer from doc prose which condition yields which failure variant - the crate's `#![deny(missing_docs)]` (lib.rs:3) secures only first sentences, not the canonical contract sections. - fix: add `# Errors` bullet lists naming the failure variant per condition to the public Result-returning items (e.g. `GuestIdentity::new`, `SessionAuthority::authenticate`, `VsockTransportSettings::new`, `ZoneLinkSpec::validate`, `open_transport`, `NativeGuestRelay::start`) - [packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsock/src/auth.rs:257, packages/d2b-provider-transport-vsock/src/settings.rs:31, packages/d2b-provider-transport-vsock/src/service.rs:383, packages/d2b-provider-transport-vsock/src/relay.rs:201] + evidence: docs seeds ran:106/0/38; the canonical-sections seed (`/// # (Examples|Errors|Panics|Safety)`) returned zero hits. + + + +## perf +- clean: seeds ran:0/3/0; the 3 collection-init hits (two `HashMap::new()` for the active/completed tables, one `Mutex::new(Vec::new())` for subscribers) are genuinely dynamic bounded maps or an empty-case-common vector, and no `format!` or `to_string()` appears in src - no allocation hot path to flag (static, unmeasured). + +## conc +- clean: seeds ran: 0/7/17/0; the atomics match the skill's model: `BridgeStats` counters use `Relaxed` (pure counters), `next_handle.fetch_add(Relaxed` (uniqueness-only handle generation), the `done` `AtomicBool` uses the paired Release-store/Acquire-load handoff with re-check after arming `Notify`,and the seven `Arc>` fields are tokio async mutexes genuinely shared between service and per-transport bridge tasks. + + + +## async +- clean: seeds ran:111/1/0/0; no lock guard crosses an `.await`, every effect open/close and named-stream open are wrapped in `timeout`(with the tokio-clock deadline rationale documented in open_transport),the spawned bridge task uses only async I/O (`copy_bidirectional`, AsyncWriteExt/AsyncReadExt),and the tokio `Mutex`/`Notify`/`watch` selection matches the workload - no blocking call on an executor worker found. + + + +## unsafe +- N/A (seeds:0/0/0 all zero; no unsafe blocks/fns/impls or `// SAFETY:` comments; seed4 (`unsafe_code`=2) is only the `#![forbid(unsafe_code)]` at lib.rs:4 plus the crate manifest's mirror table, which do not make the lens applicable. + + + +## ffi +- N/A (seeds:0/0/0/0 all zero; no `extern "C"`/`no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString`/`c_char` surface exists in the crate). + + + +## macro +- N/A (seeds:0/0/0/0 all zero; no `macro_rules!`, proc-macro trees (`proc_macro`/`syn::`/`quote!`/`$crate`/`to_compile_error`/`new_spanned`) exist in the crate). + + + +## test +- d2b-provider-transport-vsock#6 sev=low blast=leaf effort=S verdict=actionable - tests/observe.rs asserts `ServicePhase::Ready == ServicePhase::Ready`, a self-comparison that cannot fail and adds nothing to a test already asserting the observation fields - dead assertion weight with no regression value. - fix: delete line 15 (the test still asserts `observation.phase == TransportPhase::Released`), or replace with a real cross-variant assertion (e.g. `assert_ne!(ServicePhase::Ready, ServicePhase::Serving)` - [packages/d2b-provider-transport-vsock/tests/observe.rs:14-15] + evidence: test seeds ran:38/84/0/0; the tautology found by full-file read of tests/observe.rs; rest of the suite asserts error variants, uses table-driven virtual-clock deadlines (`drive_until_settled`), redaction canaries, and bounded eviction behavior - no `#[ignore]`, flaky, or implementation-restating tests found. + + + +## Coverage +- idiom: 1 finding (seeds:0/3/0) +- own: clean (seeds ran:5/0/7/0) +- type: clean (seeds ran:0/0/0) +- api: clean (seeds ran:106/0/10) +- err: clean (seeds ran:8/1/0/7) +- serde:1 finding (seeds:2/4/0/0) +- obs:2 findings (seeds:0/0/0/13) +- docs:1 finding (seeds:106/0/38) +- perf: clean (seeds ran:0/3/0) +- conc: clean (seeds ran:0/7/17/0) +- async: clean (seeds ran:111/1/0/0) +- unsafe: N/A (seeds:0/0/0 all zero; no unsafe blocks/fns/impls or SAFETY comments) +- ffi: N/A (seeds:0/0/0/0 all zero; no extern/"C", catch_unwind, repr(C)/transparent, or CStr surface) +- macro: N/A (seeds:0/0/0/0 all zero; no macro_rules! or proc-macro machinery) +- test:1 finding (seeds:38/84/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md new file mode 100644 index 000000000..f91a4415e --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md @@ -0,0 +1,77 @@ +# d2b-provider-user - d2b-provider-user +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2079 (excl. src/generated/**; src 1934 + tests 145) | modules: whole crate (driver.rs, effects_service.rs, facets.rs, probe.rs, test_support.rs, lib.rs; tests/registration.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: n/a (single-part lane) + +## idiom +- clean: seeds 0/0/0 - no index loops, no hand-written derive-able impls (all derives are `#[derive]`), no statement-style accumulation; the crate reads as expressions (payload-value iterator in `InspectUserRequest::parse`, let-else, `is_some_and`). + +## own +- d2b-provider-user#1 sev=low blast=leaf effort=S verdict=actionable - `serve_inspect_user` clones `request.groups` into the spec even though the owned `InspectUserRequest` could yield it by move; the username clone at the same site is required (reused in `inspect_user_response`) - fix: destructure `let InspectUserRequest { user_ref, username, groups } = request;` and pass `username`/`groups` by value into `UserSpec::new`, borrowing `user_ref` and `username` afterwards - [packages/d2b-provider-user/src/effects_service.rs:179, packages/d2b-provider-user/src/effects_service.rs:164-187] + evidence: `\.clone\(\)` = 16 hits; the 15 other clones are test doubles (driver.rs:497,544,579; test_support.rs:60,81,130,151), Arc refcount bumps (effects_service.rs:258,302,605; driver.rs:217), required ownership transfers (driver.rs:246,249,305; effects_service.rs:177,386), or test fixtures - only this pair has an owned local as source +- clean: seeds 16/21/0/0 - every clone/to_owned inspected; no Rc/RefCell/Arc/Cow anywhere; argument positions take `&str`/`&ResourceRef`/`&UserSpec` throughout. + +## type +- clean: seeds 2/0/0 - the two `fn validate_` hits are test names (`validate_accepts_the_bootstrap_user_row`, `validate_rejects_a_malformed_user_spec`), not runtime validation; domain state is parsed once into closed contract types (`InspectUserRequest`, `OsUsername`, `OsGroupName`, `ResourceRef`, `UserSpec`), no boolean-flag soup or stringly-typed state in production code. + +## api +- clean: seeds 30/6/3 - the 3 `pub use` arms in lib.rs:42-44 are the house single-path pattern; `UserEffectFacets.probe: Arc` (facets.rs:33) is genuine shared ownership across the driver factory (driver.rs:202-205) and the service factory (effects_service.rs:258), with external consumers in d2bd (resource_plane_v3.rs, provider_lifecycle.rs, shared_provider_effects.rs; census over packages/ = 8 files); `UserDriverError`/`UserDriverStatus`/`UserDriverEffects` are pub-in-private-module and unreachable outside the crate; the test_support surface is feature-gated and consumed by d2bd plane tests. + +## err +- d2b-provider-user#2 sev=low blast=leaf effort=S verdict=actionable - `UserDriverError`'s `Display` hand-copies the three `system-core-*` failure codes that `d2b-contracts` already registers as `FailureKind` constants, so the strings can silently drift from the registry and its rendered reference - fix: write `self.kind.failure_kind().code()` in the `Display` impl (driver.rs:118-124) instead of the per-arm string match, keeping the registry the single source - [packages/d2b-provider-user/src/driver.rs:118-124, packages/d2b-contracts/src/failure_kinds.rs:342-363] + evidence: `enum \w*Error` = 1; census `SYSTEM_CORE_SPEC_INVALID|SYSTEM_CORE_USER_DISCOVERY_FAILED|SYSTEM_CORE_DRAIN_PENDING` over packages/ = 3 sites (registry, provider-host, provider-user); the codes are rendered to docs/reference/resource-runtime-failure-kinds.md +- clean: seeds 46/0/2/1 - 45 of 46 unwrap/expect hits are in `#[cfg(test)]` code; the one production expect (effects_service.rs:178) is a literally-built value (`BoundedText::parse(String::new())`) whose invariant the message names (per-card false-positive class); the 2 panics are test-helper failure messages with context; no swallowed Results (`let _ =`/`.ok();` = 0); the private `UserDriverErrorKind` enum is a closed, correctly-split taxonomy (refused/not-yet/retryable mapped in `classify_error`). + +## serde +- clean: seeds 0/0/0/5 - no serde derives or attributes in this crate; the 5 serde_json sites are the wire boundaries (spec decode hooks driver.rs:164,263; the inspect-user payload round-trip effects_service.rs:83,90; one test helper); `InspectUserRequest::parse` is the hand-written admission gate over the canonical payload into closed contract types (per-card false-positive class), validating before any probe runs. + +## obs +- clean: seeds 0/1/0/1 - no println/eprintln/dbg; the single tracing event (probe.rs:76) is well-formed (`tracing::debug!` with named fields `user`/`group` and a literal message, not interpolation); no spans needed on the short async paths; no secret-shaped fields anywhere. + +## docs +- clean: seeds 29/0/24 - all 29 public items carry doc comments; the crate-level `#![deny(missing_docs)]` (lib.rs:5) enforces it, so the U1 card's "missing_docs not enabled anywhere" gate note does not hold for this crate; first sentences are one-line and non-narrative; the Result-returning surface (seed 3 = 24) is trait impls and private helpers whose contracts are documented at the seam (`UserDriverEffects::observe_user`, `UserDiscoveryEffectPort::discover`); no canonical-section gaps on user-facing items. + +## perf +- clean: seeds 1/8/2 - the 1 `format!` (effects_service.rs:483) is test-data construction; the 8 `Vec::new` sites are empty-by-construction fixtures and recorders (empty case is the common case); the 2 `to_string` are one-shot error stringification at the seam (effects_service.rs:225) and a test assertion; no hot-path allocation, no attacker-controlled hashing, no grow-by-push loops in production code. + +## conc +- d2b-provider-user#3 sev=medium blast=leaf effort=M verdict=policy-confirmed - the test-support recorder doubles and the driver's test fakes use `parking_lot::Mutex` (banned outright, KD3) at 20 `lock()` call sites with no `#[allow(clippy::disallowed_methods)]` on the enclosing items, while sibling `d2b-provider-host` uses `tokio::sync::Mutex` for the same recorder shape - fix: swap `parking_lot::Mutex` to `tokio::sync::Mutex` in `RecordingEffects`/`ScriptedProbe`/`RecordingManager`/`RecordingRequeue` (or add the sanctioned inline allow with reason "cfg(test) helper" at each site) so the deny-level flip needs no special case - [packages/d2b-provider-user/src/test_support.rs:41-42,108, packages/d2b-provider-user/src/driver.rs:469-470,563] + evidence: `\bMutex<|\bRwLock<` = 6 hits (all parking_lot, all test-support/test-fake); lock call sites: test_support.rs:60,65,76,83,130,151 and driver.rs:483,497,508,516,524,529,530,543,544,552,557,574,579,585; policy: clippy.toml:40 (KD3 ban), clippy.toml:82 (replacement tokio::sync::Mutex), U1 (d)4 sanctioned reason "cfg(test) helper"; the 9 async-gate-allow markers record the sites as deliberate async exceptions (cite, not re-flagged), but the clippy allow is absent +- d2b-provider-user#4 sev=low blast=leaf effort=S verdict=actionable - the scripted-double flags (`fail`, `absent`, `failing`) use `Ordering::SeqCst` though they are set and read within one test task on a single-threaded `#[tokio::test]` runtime, so the strongest ordering buys nothing - fix: use `Ordering::Relaxed` for the loads/stores in test_support.rs and driver.rs:854, per the weakest-correct-ordering rule - [packages/d2b-provider-user/src/test_support.rs:77,135,140,152,155, packages/d2b-provider-user/src/driver.rs:854] + evidence: `Atomic\w+|Ordering::` = 13 hits; 6 ordering uses, all `SeqCst`, all in test doubles; no cross-thread publish exists (flags are set and read in the same test task) +- clean: seeds 0/6/13/0 - no threads, no thread_local, no unsafe Send/Sync; production code holds no locks and shares no mutable state; the only shared state in the crate is the test-support recorders judged above. + +## async +- d2b-provider-user#5 sev=high blast=leaf effort=L verdict=policy-confirmed - the bounded probe's `discover_local_user` runs blocking NSS lookups (`nix::unistd::User::from_name`, `Group::from_gid`, `Group::from_name`) inside async fns on the plane's executor worker (driver reconcile via effects_service.rs:224, and the hosted `inspect-user`), so a slow or hung NSS backend (LDAP/NIS) stalls a runtime worker per call; `spawn_blocking` is itself banned (KD2) - fix: move the NSS reads onto a dedicated bounded worker in the `d2b-core` `loader_worker` shape (one thread, bounded sync_channel, oneshot replies) and have the probe await it - [packages/d2b-provider-user/src/probe.rs:48,63,72, packages/d2b-provider-user/src/probe.rs:40-79] + evidence: `async fn|async move|\.await` = 91 hits; reachability path is static and complete: driver.rs:342 -> effects_service.rs:224 -> probe.rs:28 -> probe.rs:48,63,72; `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0; policy: clippy.toml:112 (spawn_blocking banned, bounded-worker shape named as the replacement); the blocking-census baseline lists no NSS class for this crate, so the site is above any tracked set +- clean: seeds 91/0/0/21 - no spawn/JoinSet/select!/tokio::sync types; no guard held across an await (the recorder locks drop before every suspension point, per the async-gate-allow markers, which are deliberate exceptions cited in finding #3); the 21 `#[tokio::test]` harnesses are single-threaded and deterministic; cancellation-safety surface is minimal (no irreversible step between awaits in `reconcile`/`serve_inspect_user`). + +## unsafe +- N/A: seeds 0/0/0 all zero; no unsafe blocks/fns/impls and no `unsafe_code = "allow"` manifest (packages/d2b-provider-user/Cargo.toml sets `unsafe_code = "forbid"` under `[lints.rust]`). + +## ffi +- N/A: seeds 0/0/0/0 all zero; no extern boundary, no repr(C)/transparent, no CStr/CString - the crate crosses no foreign caller. + +## macro +- N/A: seeds 0/0/0/0 all zero; no macro_rules!/proc-macro definitions, no `$crate` uses (the crate only invokes std macros). + +## test +- d2b-provider-user#6 sev=medium blast=leaf effort=S verdict=actionable - the "cached unrealized phase re-discovers" contract is tested only for `Pending` (`reconcile_rediscovers_a_cached_unrealized_phase`), so a regression that widened the `observed_ready` short-circuit predicate (driver.rs:283) to accept `Degraded` or `Unknown` would pass every test - fix: extend the phase loop in `reconcile_publishes_the_user_discovery_projection` (driver.rs:789-813) to run a second reconcile per phase and assert the second `observe-user` call for all three unrealized phases - [packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs:281-284] + evidence: `#\[test\]|#\[tokio::test\]` = 25 (src+tests), `assert_eq!\(|assert_ne!\(|assert!\(` = 88; the `phase == ResourcePhase::Ready` predicate is pinned by no test for the non-Pending unrealized phases (the existing cached-phase test covers Pending only, and the phase-loop test stops after the first reconcile) +- clean: seeds 25/88/0/0 - 25 tests (12 driver, 9 effects-service, 4 registration) assert observable behavior (recorded call orders, status fields, failure classes, registry outcomes, wire payload fields) with human-written expectations; table-driven loops carry per-case failure messages; no `#[ignore]`, no property/snapshot tooling, no network or clock dependence; the registration boundary suite pins the descriptor contract (allowed sources, verbs, services, decoder, duplicate/late registration refusals). + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: 1 finding (seeds ran: 16/21/0/0) +- type: clean (seeds ran: 2/0/0) +- api: clean (seeds ran: 30/6/3) +- err: 1 finding (seeds ran: 46/0/2/1) +- serde: clean (seeds ran: 0/0/0/5) +- obs: clean (seeds ran: 0/1/0/1) +- docs: clean (seeds ran: 29/0/24) +- perf: clean (seeds ran: 1/8/2) +- conc: 2 findings (seeds ran: 0/6/13/0) +- async: 1 finding (seeds ran: 91/0/0/21) +- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe blocks and no unsafe_code = "allow" manifest - Cargo.toml sets forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero; no extern boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) +- test: 1 finding (seeds ran: 25/88/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md new file mode 100644 index 000000000..be23d396f --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md @@ -0,0 +1,73 @@ +# d2b-provider-volume-binding - d2b-provider-volume-binding +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2900 (src 2739 + tests 161; no src/generated/**) | modules: driver, effects_service, facets, lib, row_readers, test_support; tests/registration.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single part) + +## idiom +- clean: seeds ran: for-index-0 | impl-manual-derive-0 | let-mut-accumulate-0 (all zero); the crate reads Rust throughout - iterator chains (row_readers projections, uid_hex byte fold, sort_by_key teardown ordering), edition-2024 let-chains (delete, parent_volume), derives on every plain value type, and BoundedToken newtypes at the wire boundary. + +## own +- d2b-provider-volume-binding#2 sev=low blast=leaf effort=S verdict=actionable - parsed_binding_spec clones the whole parsed spec object to end the as_object_mut() borrow before from_value (row_readers.rs:44), a clone a scoped block removes by letting `spec` move into the conversion - fix: bound the removal borrow in a block (let o = spec.as_object_mut()?; for f in [..] { o.remove(f); }) then serde_json::from_value::(spec) without Value::Object(object.clone()) - [packages/d2b-provider-volume-binding/src/row_readers.rs:38-44] + evidence: seed `\.clone\(\)` own=81 hits (per-file clone sites: row_readers 39/44, driver 286/288/378/382/449/657, rest in test-support and cfg(test) fixtures); of the non-test clones, only row_readers.rs:44 is avoidable - the rest are required (envelope raw copy, factory arg per create, error-detail string, sort key materialization). +- clean: seeds ran: clone (78 in src, most test-support/fixtures) | to_owned/to_vec/to_string | Arc appears only where ownership is genuinely shared (decoder factory return, facet set held by the driver), and the sole dependency type in a signature (Arc) is the shared decoder-factory convention used by every driver crate. + +## err +- d2b-provider-volume-binding#1 sev=medium blast=family effort=S verdict=actionable - BindingDriver re-parses the zone as a BoundedToken with a per-pass .expect (driver.rs:426-427) because BindingDriverArgs.zone: String (driver.rs:344) can represent a non-bounded zone, and the sole production caller already holds a BoundedToken (d2bd resource_plane_v3.rs:2954 inputs.zone.as_str().to_owned()), so the invariant is re-checked on every validate/reconcile/recover/delete pass where a parse-at-the-boundary would check it once - fix: store BoundedToken on BindingDriverArgs/BindingDriver (parse or construct once; ResourceKey::new(&self.zone.as_str(), ...), socket_identity(&self.zone)), deleting zone_bounded and its expect - [packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-binding/src/driver.rs:426-427, packages/d2bd/src/resource_plane_v3.rs:2954] + evidence: seed `\.unwrap\(\)|\.expect\(` err=76 hits, of which exactly one expect is production code reachable per verb (driver.rs:427; driver.rs:937 is the literally-built projection false-positive class); seed `let _ = ` = 1 site (driver.rs:1038, the deliberately ignored retirement bool, errors still propagated via ?); panic!/unreachable! only in cfg(test) match arms; census: BindingDriverArgs over packages/ = 1 production construction site (resource_plane_v3.rs:2954) plus tests/registration.rs and the driver test module. +- clean: seeds ran: unwrap/expect | let _ =/ok() | panic/unreachable/todo/unimplemented | enum Error = 0; the taxonomy (BindingDriverErrorKind with class() + failure_kind() mapping to the FailureKinds wire catalog) is a clean enum split by caller action, details carry FailureComparison context, no swallowed errors outside the documented fail-closed reads (row_readers .ok()?, reconcile guest_mount_ready unwrap_or(false)). + +## serde +- clean: seeds ran: derive-0 | serde-attr-0 | impl-Deserialize-0 | from_/to_-24 hits; the crate declares no serde derive of its own and crosses the wire only by consuming contract types (VolumeBindingSpec, VolumeBindingStatusResource) through serde_json from_slice/from_value/to_vec with explicit map_err into the typed error kinds; the two read-side projections fail closed on unparseable rows by design (documented), and parsed_binding_spec's reserved-envelope-field strip is covered by a dedicated test. No round-trip hazard: this crate holds no serde wire shape. + +## obs +- clean: seeds ran: println/eprintln-0 | interpolated-no-fields-0 | instrument-0 | tracing/log-1 hit; the single telemetry site is a structured tracing::warn!(plane = ?plane, key = %key, detail = %error_detail, ..) with named fields over a diagnostic detail, and no macro interpolates a message without fields; no secret-bearing field is logged. + +## docs +- d2b-provider-volume-binding#3 sev=low blast=leaf effort=S verdict=actionable - the four public Result-returning seam methods state no # Errors section (which conditions fail and how the driver classifies them): facets.rs SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, driver.rs BindingDriverEffects::remove_socket/guest_mount_ready - fix: add # Errors to each naming the daemon-adapter failure conditions and the fail-closed handling - [packages/d2b-provider-volume-binding/src/facets.rs:52, packages/d2b-provider-volume-binding/src/facets.rs:65, packages/d2b-provider-volume-binding/src/driver.rs:307-310, packages/d2b-provider-volume-binding/src/driver.rs:325-330] + evidence: docs seed `-> Result<` docs=58 hits; the four pub trait-method Result returns above are the only pub Result items whose doc comment lacks a canonical # Errors section (the crate runs #![deny(missing_docs)], which covers item presence, not section completeness); every other pub item has a one-line first sentence and the item list checks out. +- clean: seeds ran: pub-items-36 | canonical-sections-0 | -> Result< -58 hits; module docs (//!) present in all six modules, first sentences carry the load, deny(missing_docs) keeps every pub item documented, the BindingDriverError/Status internals stay pub(crate) so their detailed docs are not surface. + +## perf +- clean: seeds ran: format!-6 | Vec::new-7 | to_string-11 (raw match lines over src; most in cfg(test) fixtures); production format! sites are cold (uid_hex hex-spelling in error comparisons, status-projection paths), the Vec::new()s are construction-time/mandatory metadata buffers, and the only per-pass allocations (zone re-parse in zone_bounded, worker/endpoint child-spec rebuild in worker_child_specs) are static (unmeasured) and small - no hot-loop format!/to_string, no with_capacity opportunity named by any benchmark. + +## conc +- d2b-provider-volume-binding#4 sev=low blast=leaf effort=S verdict=actionable - the production [dependencies] compiles the KD3-banned parking_lot (clippy.toml:82 disallows its lock outright, revocation recorded) solely for the feature-gated/cfg(test) recording doubles, so every production consumer of this crate carries the banned crate in its lockfile; the per-site #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] permits the lock calls but not the manifest posture - fix: swap parking_lot::Mutex -> std::sync::Mutex in FakeServingEffects/RecordingManager/RecordingRequeue (the guards are already statement-scoped, so the sanctioned allows survive unchanged) and drop the Cargo.toml dependency, or gate it behind test-support as an optional dep - [packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-volume-binding/src/driver.rs:1139-1142, clippy.toml:82] + evidence: conc seed `\bMutex<` conc=24 hits, every one in test-support/cfg(test) recorders carrying async-gate-allow markers; census: zero locks, threads, or atomics in the non-test src files (driver.rs/effects_service.rs/facets.rs/row_readers.rs/lib.rs) - all synchronization is the recording doubles. parking_lot appears nowhere else in production scope (grep over packages/ for parking_lot in this crate lists only the manifest + test-support sites); the atomics use SeqCst on single-threaded scripted bools, which is harmless but not a finding class here. +- clean: seeds ran: thread-0 | Mutex-10 | Atomic/Ordering-14 | thread_local/unsafe-SendSync-0; the concurrency model is the simplest correct one for a stateless driver - no shared production state beyond the purchased Arc seam, the test doubles' locks are never held across an await (async-gate-allow recorded), and no ordering argument needs defending in two sentences. + +## async +- clean: seeds ran: async-141 hits | spawn/JoinSet/select-0 | tokio-sync-0 | tokio-main/test-13; no blocking work inside async contexts (all waits await trait seams; child-spec JSON builds are small and synchronous but not blocking I/O), no guard held across an await (the recorder locks are statement-scoped with async-gate-allow markers, and clippy deny await_holding_lock is on), the delete/finalize paths are documented idempotent under retry so cancellation mid-teardown converges, and the driver's only shared state (watched Vec, effects Arc) is never contended across tasks. + +## unsafe +- N/A: seeds ran: unsafe-block-0 | SAFETY-comment-0 | transmute/from_raw/MaybeUninit-0; the manifest sets unsafe_code = "forbid" and no block, fn, impl, or extern exists, so the lens never applies. + +## ffi +- N/A: seeds ran: extern/no_mangle/link_section-0 | catch_unwind-0 | repr(C)/transparent-0 | CStr/CString/c_char-0 all zero; the crate crosses no foreign boundary. + +## macro +- N/A: seeds ran: macro_rules-0 | proc_macro/syn/quote-0 | $crate-0 | to_compile_error/new_spanned-0 all zero; the crate defines no macros. + +## test +- clean: seeds ran: test-attr-13 | assert-120 | proptest/insta/rstest-0 | ignore-0; the suite is regression-targeted - F1 persist-before-spawn ordering, endpoint-first/process-last teardown, the fenced-projection currency rules (stale/foreign/ahead revisions), owner guard, absent-parent retry vs owner-mismatch terminal, argv-free worker child - asserted on error variants and FailureClass, never on Display strings; deterministic (scripted manager, no clock/network), and registration.rs is the policy-required declaration boundary shim. No #[ignore], no snapshot/property tooling, and no test that cannot fail was found. + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: 1 finding(s) +- type: clean (seeds ran: 0/0/0); the one stringly-typed field (driver.rs:344) is anchored under err#1 +- api: clean (seeds ran: 36/0/7 hits; single-path pub use surface, deliberate contract exports) +- err: 1 finding(s) +- serde: clean (seeds ran: 0/0/0/24 hits; no crate-local serde derives, contract types consumed at the boundary) +- obs: clean (seeds ran: 0/0/0/1 hits; one structured tracing::warn!, zero println) +- docs: 1 finding(s) +- perf: clean (seeds ran: 24 hits; format!/to_string sites test- or error/cold-path, static (unmeasured)) +- conc: 1 finding(s) +- async: clean (seeds ran: 141/0/0/13 hits; no blocking in async, no await-held guard, cancellation-safe teardown) +- unsafe: N/A (seeds: 0/0/0 all zero; unsafe_code = "forbid" manifest, no blocks/fns/impls) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) +- test: clean (seeds ran: 134 hits; behavior/ordering/variant assertions, no #[ignore]/proptest/insta/rstest) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md new file mode 100644 index 000000000..f34b78b7b --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md @@ -0,0 +1,74 @@ +# d2b-provider-volume-local - d2b-provider-volume-local +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10328 (excl. src/generated/**; src 8056 + tests 2272) | modules: whole crate (adapter, acl, atomic, bindings, content, controller, diagnostics, effect_port, error, finalization, identity, layout, lock, marker, port, quota, source, status, store_view, testing, views, lib) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- d2b-provider-volume-local#1 sev=low blast=leaf effort=S verdict=actionable - LayoutPhase::worse hand-rolls severity comparison with an `as u8` cast although the enum derives PartialOrd/Ord; the cast also silently depends on variant declaration order matching severity order - fix: replace the `if self as u8 >= other as u8` body with `self.max(other)` (derived Ord, declaration order Pending/Ready/Degraded/Failed already encodes severity) - [src/status.rs:33-38] + evidence: seeds: `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 8 (all legitimate accumulation loops with side-effect bodies or Read::read_to_end targets; no index loops exist); finding from full-file read of src/status.rs +- clean: the 8 `let mut ... Vec::new()` sites (adapter.rs:1539,1677,1803; content.rs:505,754; controller.rs:215,370; diagnostics/storage_lifecycle.rs:48) are the canonical read-to-end or side-effecting accumulation shapes the skill itself prefers over combinator chains; no hand-written derive candidates and no index loops found + +## own +- clean: seeds: `.clone\(\)` = 87, `.to_owned\(\)|.to_vec\(\)|.to_string\(\)` = 26, `Rc<|RefCell<|Arc delegation impl and adapter.rs:209 Arc in FdRootResolver, both required for the Send+Sync resolver seam), or test-fixture state (testing.rs:81 Mutex>); no borrow-checker-silencing clones found + +## type +- d2b-provider-volume-local#2 sev=low blast=leaf effort=M verdict=actionable - VolumeRootHandle carries ten Option fields that are valid only all-Some (from_anchored) or all-None (held), so eleven mixed states are representable; construction is internal today so the mixed states are unreachable, but the fail-closed root-identity handle is exactly where a future partial-construction bug would land - fix: split into a two-variant enum (e.g. `enum VolumeRootHandle { Empty, Anchored(AnchoredHandle) }`) or a typestate pair, keeping the non-Clone/non-Serialize property - [src/identity.rs:72-88, src/identity.rs:146-150] + evidence: seeds: `fn validate_\w+|fn check_\w+` = 10, `is_\w+: bool|\w+_flag: bool` = 1, `(mode|kind|state): String` = 5; the single bool (controller.rs:41 watched_configuration_is_dependency) and the five `mode: String` fields (content.rs:112,315,382,545,699) are not findings: the bool is a lone flag and the mode strings are schema-mirroring fields validated at construction (ContentFile::validate, content.rs:142-153) - the only illegal-state candidate is the handle +- clean: validate-at-callsite is confined to the wire boundary (validate_source_spec, controller validate_spec, EntryRequest::resolve) where the VolumeSpec contract type gives no guarantees, which is the parse-once pattern rather than a violation + +## api +- d2b-provider-volume-local#3 sev=medium blast=family effort=S verdict=actionable - `pub mod testing` (ScriptedPort with a Mutex, fixtures, hand-rolled block_on) is compiled unconditionally into the production library although it is consumed only by tests: this crate's tests/** and one d2bd test fn; the house pattern for cross-crate test support is a feature gate - fix: gate the module behind a `test-support` feature (`#[cfg(feature = "test-support")]` on `pub mod testing`, add `[features] test-support = []`), and enable the feature from d2bd's dev-dependencies - [src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1] + evidence: census: `volume_local::testing|ScriptedPort` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 26 hits, all in this crate's tests/** (layout_conformance.rs:9, store_view_and_swtpm.rs:3, views_and_sharing.rs:5, volume_effect_adapter.rs:122-493) and d2bd/src/resource_runtime.rs:12917 (inside a #[test] fn); no production code path imports it +- clean: api seed 2 (`pub .*\b(Arc|Rc|Box|RefCell)<`) = 0; the lib.rs `pub use` arms are the house single-surface pattern; public signatures carry only std types (BorrowedFd/OwnedFd in VolumeRootHandleView/AnchoredRoot, identity.rs:90-117) or contract-crate types; the adapter module double-path (pub mod adapter + root re-export) is referenced by cross-crate intra-doc links (d2b-provider-volume/src/facets.rs:18,50) and is covered by the re-export-arm false-positive note, so not flagged + +## err +- clean: seeds: `\.unwrap\(\)|\.expect\(` = 121 (every hit outside #[cfg(test)] is controller.rs:88 `BoundedToken::parse("volume-local").expect("frozen provider name")` on a literally-built value, the sanctioned class), `let _ = |\.ok\(\);` = 4 (adapter.rs:313 stub arg ignore, adapter.rs:1546 unused-arg ignore, adapter.rs:1778 best-effort unlinkat in remove_temp, diagnostics/storage_lifecycle.rs:110 drop cleanup - all deliberate), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 5; the five error enums (VolumeLocalError, AtomicWriteError, LockError, MarkerError, VolumeEffectError) are closed sets with stable lower-kebab `code()` accessors and Display rendering the code, matching the wire-code discipline; VolumeLocalError::ALL (29) matches the code() match arms + +## serde +- d2b-provider-volume-local#4 sev=medium blast=leaf effort=M verdict=actionable - ContentFile, ContentProjection, NetworkConfigContentProjection and the evidence types derive public Deserialize that bypasses the validating constructors: the crate's parse boundary is `from_value`/`from_settings` (which run validate), but the derived impl admits unvalidated projections directly, so the type the rest of the program trusts is not guaranteed valid on the derive path - fix: route the derive through `#[serde(try_from = "Raw...")]` mirror structs (wire shape unchanged: camelCase + deny_unknown_fields preserved) or drop Deserialize from the derives and parse only via the validating entries - [src/content.rs:38-39, 106-107, 203-204, 239-243, 536-537, 590-594] + evidence: seeds: `derive\([^)]*(De)?[Ss]erialize` = 24, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 19 (no try_from anywhere), `impl .*Deserialize.* for` = 0, `serde_json::from_|serde_json::to_` = 66; in-repo consumers all use the validating entries (d2bd/src/shared_provider_effects.rs:676,732 from_settings; d2bd/src/resource_plane_v3.rs:1507-1509 constructors), so the gap is the public derive itself +- clean: rename_all camelCase/kebab-case conventions are consistent per type family; deny_unknown_fields is present on every wire-mirroring struct; skip_serializing_if used correctly (status.rs:87); no hand-written Deserialize impls (the recorded-refusal admission-gate class does not appear here) + +## obs +- clean: seeds: `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::` = 23; every tracing event carries named fields (volume, path, error, reason, drift, entry, provider) with message-only text, e.g. adapter.rs:332-335, 740-743, controller.rs:232-245, lock.rs:250-253; redacted Debug impls (ContentFile, EntryDigest, VolumeRootHandle, SourcePolicyCatalog, VolumeRootIdentity, LockId) keep identifiers out of any field rendering; no secrets in fields + +## docs +- d2b-provider-volume-local#5 sev=low blast=leaf effort=M verdict=actionable - no canonical doc sections exist anywhere in the crate (seed 2 = 0 hits): public Result-returning items such as ContentFile::new, ContentProjection::new/from_value, EntryRequest::resolve, VolumeLocalController::reconcile, admit_attachments and validate_source_spec carry one-line docs but no `# Errors` section naming which conditions produce which failure - fix: add `# Errors` sections to the admission/parse constructors and the controller entry points, listing the closed VolumeLocalError variants each can return - [src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92, src/source.rs:130-131] + evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 319, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 104; `#![deny(missing_docs)]` (src/lib.rs:18) is already enforced so every public item has a first sentence; the gap is the canonical-sections shape only + +## perf +- clean: seeds: `format!\(` = 19, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 9, `\.to_string\(\)` = 26; every hit is a cold path (lock-id/temp-name/mode rendering at adapter.rs:1054,1706,1814; digest hex at content.rs:495-501,773; mount options at source.rs:253; test fixtures), a canonical read_to_end target, or wire-rendering; no format!/allocation inside any loop that runs per-entry on a hot reconcile path beyond the bounded digest preimage builders (content.rs:505,754, bounded by MAX_CONTENT_BYTES); static (unmeasured) + +## conc +- clean: seeds: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 1, `Atomic\w+|Ordering::` = 3, `thread_local!|unsafe impl (Send|Sync) for` = 0; the only production primitive is `static NEXT_TEMP: AtomicU64` with `fetch_add(1, Ordering::Relaxed)` (adapter.rs:1705,1710) - a counter nobody synchronizes on, so Relaxed is the weakest correct ordering and the static is justified for cross-instance temp-name uniqueness; the single Mutex (testing.rs:81) is test-fixture state + +## async +- clean: seeds: `async fn|async move|\.await` = 60, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the adapter's synchronous filesystem work runs at future-construction inside the async port methods (adapter.rs:327-369 `let result = self.observe_sync(...); async move { result }`), but every such site carries the sanctioned per-site allow `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` (adapter.rs:1666, 1520) and the crate is in the blocking census baseline (packages/xtask/data/blocking-census-baseline.json, all-zero counts), so the sync-in-async shape is recorded policy, not a new finding; the crate owns no runtime (testing.rs:29-33 hand-rolled block_on is the deliberate no-runtime design); controller awaits only port calls + +## unsafe +- clean: seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 22, `unsafe_code` = 1; the seed-3 hits are all false positives: `Mode::from_raw_mode`/`FileType::from_raw_mode` are rustix safe constructors (adapter.rs:673,696,932,1048,1107,1115,1235,1253,1530,1566,1571,1716,1743) and `MaybeUninit` appears only as a stack buffer handed to rustix RawDir without any unsafe access (adapter.rs:16,1468); the manifest forbids unsafe_code (Cargo.toml `[lints.rust]`) and no `unsafe_code = "allow"` exists, so the crate is outside the U1 (d)8 exception set + +## ffi +- N/A: seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign-language boundary (libc::flock struct literals at adapter.rs:1604-1610,1623-1629 are data passed to rustix's fcntl wrapper, not extern declarations) + +## macro +- N/A: seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros are defined or used beyond std ones; the crate's repetition is handled by traits and generics + +## test +- clean: seeds (src + tests): `#\[test\]|#\[tokio::test\]` = 59, `assert_eq!\(|assert_ne!\(|assert!\(` = 300, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the suite asserts behavior and error variants rather than Display strings (e.g. tests/layout_conformance.rs asserts `Err(VolumeLocalError::EntryDrift)` and ConditionSeverity; tests/volume_effect_adapter.rs pins foreign-marker preservation and quarantine non-mutation with readback assertions), is table-driven with per-case messages (adapter.rs:1856-1860, tests/layout_conformance.rs:140-153), and is deterministic (tempdirs under CARGO_TARGET_TMPDIR, no network, no wall-clock dependence); no test computes its expectation with the code under test (the bindings.rs reordering test compares forward vs reordered-spec output, which is the determinism property itself); no ignored or unfailable tests found + +## Coverage +- idiom: 1 finding +- own: clean (seeds ran: 87/26/3/0) +- type: 1 finding +- api: 1 finding +- err: clean (seeds ran: 121/4/0/5) +- serde: 1 finding +- obs: clean (seeds ran: 0/0/0/23) +- docs: 1 finding +- perf: clean (seeds ran: 19/9/26) +- conc: clean (seeds ran: 0/1/3/0) +- async: clean (seeds ran: 60/0/0/0) +- unsafe: clean (seeds ran: 0/0/22/1; all seed-3 hits are from_raw_mode/MaybeUninit false positives, manifest forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) +- test: clean (seeds ran: 59/300/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md new file mode 100644 index 000000000..e1851cf63 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md @@ -0,0 +1,56 @@ +# d2b-provider-volume-virtiofs - d2b-provider-volume-virtiofs +Baseline: 6ebdd4cec | LOC audited: 2,025 (excl. src/generated/**) | modules: whole crate (bindings, controller, error, lib, port, socket_path, testing, worker; tests/lifecycle.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) +## idiom +- clean: seeds all zero (for-loop index 0/0, hand-written derive-able impls 0/0, let-mut accumulation 0/0); hand-written Debug on SocketIdentity/StoredBinding redact deliberately and hand-written Serialize on SocketIdentity is the hex wire rendering; none are findings. +## own +- clean: seeds ran: 13/0/0/0; all 13 .clone() sites are explainable value copies (spec.clone() before mutating the envelope, uid.clone() into an owned fence, BoundedToken clone() into owned status reports, test-double snapshot clones after try_lock, plan/projection clones pushed into recorded history); no to_owned/Rc/RefCell/Arc/Arc/Cow. +## type +- clean: seeds ran: 0/0/1; the one hit (worker.rs:100 sandbox_mode: String) judges clean: WorkerSandbox::declared() is a one-shot admission gate over an adapter-reported posture,and assert_conformant() validates it once against the ADR 0021 frozen singleton before launch; an enum would make the misbehaving report unrepresentable instead of rejected, which is exactly the fail-closed check the controller must keep. +## api +- d2b-provider-volume-virtiofs#1 sev=low blast=leaf effort=S verdict=actionable - dead pub visibility on crate-internal items: resolve_view (controller.rs:23), SANDBOX_MODE (worker.rs:18), USER_NAMESPACE_MAPPING_CLASS (worker.rs:23), and WorkerSandbox plus its 3 pub fns (worker.rs:97,106,121,126) are declared pub in private modules,and never re-exported at lib.rs, so the pub is unreachable surface - fix: reduce to pub(crate)/private on those items, keeping the lib.rs re-export list as the single surface- - [packages/d2b-provider-volume-virtiofs/src/controller.rs:23, packages/d2b-provider-volume-virtiofs/src/worker.rs:97] + evidence: census: (resolve_view|WorkerSandbox|SANDBOX_MODE|USER_NAMESPACE_MAPPING_CLASS) over (packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel+*.bzl) =0 external hits (only in-crate uses; d2b-provider-volume-local resolve_view in views.rs:18 is a distinct symbol). +- d2b-provider-volume-virtiofs#2 sev=low blast=leaf effort=S verdict=actionable - pub mod testing exports 323 LOC of test doubles (ScriptedPort, PortCall, block_on, fixtures) unconditionally in the production lib with no feature gate, so tokio (sync) stays a runtime dependency purely for test support - fix: gate pub mod testing behind a test-support feature (with dep:tokio resolved for the feature), so the lib ships no test doubles and tokio goes conditional; keep testing.rs itself (lifecycle test uses the fixtures).- - [packages/d2b-provider-volume-virtiofs/src/lib.rs:42, packages/d2b-provider-volume-virtiofs/Cargo.toml:25] + evidence: census; (volume_virtiofs::testing) over (packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel+*.bzl) =0 external hits; sole consumer isthe crate own tests/lifecycle.rs:5; Cargo.toml has no [features] section, and tokio= { workspace = true, features = ["sync"] } under [dependencies].. +## err +- clean: seeds ran: 20/0/0/1; non-test unwrap/expect =2, both on literally-built invariants (BoundedToken::parse("volume-virtiofs").expect at controller.rs:44, StatusCode::parse(reason.code().expect at bindings.rs:237, whose grammar is asserted by the every_code test in error.rs); VirtiofsBindingError is a closed #[non_exhaustive] enum with code() plus ALL - clean shape; no swallowed Results, no panics. +## serde +- clean: seeds ran:3/7/0/3; Serialize-only wire outputs (BindingPhase kebab-case, BindingStatusReport camelCase with skip_serializing_if plus serialize_with, VirtiofsdWorkerPlan camelCase); the hand-written envelope parse is a live admission gate over serde_json::Value (per refusal ledger class), not a Deserialize impl; tests lifecycle.rs round-trips the report into JSON,and asserts the forbidden-fragment privacy pin. +## obs +- clean: seeds ran:0/15/0/15; all 15 events are tracing::warn!/debug! with named fields (binding, provider, reason, worker), % lazy forms, static messages; warn for handled failures,and debug for documented recurring steady states (cardinality comments); no println/eprintln, no secrets, no subscriber install. +## docs +- d2b-provider-volume-virtiofs#3 sev=low blast=leaf effort=S verdict=actionable - public Result-returning fns lack the canonical # Errors section even though rejection conditions are described in prose; from_resource_spec, worker_principal, worker_process_ref, endpoint_ref, resolve_view, reconcile, drain, for_binding, assert_conformant - fix; add a # Errors doc section to each listing the VirtiofsBindingError variant(s) it can return- - [packages/d2b-provider-volume-virtiofs/src/bindings.rs:122, packages/d2b-provider-volume-virtiofs/src/controller.rs:66, packages/d2b-provider-volume-virtiofs/src/worker.rs:64] + evidence: docs seed 3 (-> Result<) =14 hits across those fns; seed 2 (canonical sections) =0 hits +- d2b-provider-volume-virtiofs#4 sev=low blast=leaf effort=S verdict=actionable - VIRTIOFS_REPAIR_INTERVAL_SECS =30 documents what but not why; no rationale for the 30-second bound, while an external consumer (d2b-provider-volume-binding/src/driver.rs:112 BINDING_RESYNC) relies on it as its resync cadence - fix; extend the doc with one sentence naming the bound (e.g., matching the family repair cadence,or the socket-readiness deadline budget)- - [packages/d2b-provider-volume-virtiofs/src/controller.rs:19-20] + evidence: docs seed 3 (-> Result<) =14 hits; the const doc ends at "for virtiofs workers." with no why +## perf +- d2b-provider-volume-virtiofs#5 sev=low blast=leaf effort=S verdict=actionable - derive_child_ref builds the hex suffix with 10 per-byte format! allocations (digest[..10].iter().map(|byte| format!("{byte:02x}").collect::() onthe async reconcile path (twice per binding pass; worker_process_ref plus endpoint_ref), instead of one with_capacity String plus write!- fix; replace the per-byte format! chain with a String::with_capacity(20) plus write!/push_str hex loop (mirroring SocketIdentity::to_hex)- - [packages/d2b-provider-volume-virtiofs/src/bindings.rs:294-296] + evidence: static (unmeasured); perf seed 1 (format!() =4 hits of which 2 are this loop, 1 is worker_principal (cold), 1 is a test fixture +## conc +- clean: seeds ran:0/4/0/0; the 4 Mutex< hits are tokio::sync::Mutex inthe test double ScriptedPort (documented plan-U4 try_lock surface for sync consumers plus lock().await for async methods); no threads, atomsics, or manual Send/Sync inthe crate. +## async +- clean: seeds ran:27/0/0/0; async surface is controll controller.compute_report/reconcile/drain awaiting only injected effect-port futures (no locks held across awaits in production, no spawn/JoinSet/select, no blocking work, no runtime started in lib); testing.rs busypoll block_on is a documented plain-#[test] driver; the trait -> impl Future plus Send (over async fn) deliberately keeps the Send promise. +## unsafe +- N/A (seeds: 0/0/0/1 (seed 4 = unsafe_code = "forbid" in Cargo.toml:9; no unsafe_code="allow" manifest); seeds 1-3 all zero; card; seed 4 alone does not make lens applicable. +## ffi +- N/A (seeds: 0/0/0/0 all zero; no extern/no_mangle/CStr/repr boundary in this crate. +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!/proc-macro/$crate in this crate. +## test +- clean: seeds ran:27/~/0/0 (#[test] =27 (bindings 4, error 1, worker 4, lifecycle 18), assertions throughout (assert_eq!/assert!/assert_ne), proptest/insta/rstest =0, #[ignore] =0); the suite is hermetic (ScriptedPort doubles, block_on driver, no virtiofsd binary/socket/network), deterministic, behavior-focused (call ordering, phases, fence validity, delete-before-confirm, privacy fragments, ownership pins), asserts error variants not Display strings,and hangs meaningful failure messages; no test restates implementation. +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 13/0/0/0) +- type: clean (seeds ran: 0/0/1; judged admission gate, not a finding) +- api: 2 finding(s) +- err: clean (seeds ran: 20/0/0/1; non-test unwrap/expect both literally-built invariants) +- serde: clean (seeds ran: 3/7/0/3) +- obs: clean (seeds ran: 0/15/0/15) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 0/4/0/0; test-only tokio::sync::Mutex) +- async: clean (seeds ran: 27/0/0/0) +- unsafe: N/A (seeds: 0/0/0/1; seeds 1-3 all zero; unsafe_code=forbid, no allow manifest) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 27/assert-mass/0/0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md new file mode 100644 index 000000000..a3f664c31 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md @@ -0,0 +1,116 @@ +# d2b-provider-volume - d2b-provider-volume +Baseline: 6ebdd4cec | LOC audited: 2,135 (excl. src/generated - none present) | modules: whole crate (driver, effects_service, facets, lib, test_support) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-provider-volume#1 sev=low blast=leaf effort=S verdict=actionable - `reconcile` converts the provider facet via `serde_json::to_value(value).unwrap_or(serde_json::Value::Null)` where the value is already a `serde_json::Value`: a serialization round trip plus dead `unwrap_or` fallback for an infallible conversion - fix: replace with `envelope.base.get("provider").cloned()` - [driver.rs:607-609] + evidence: idiom seeds 0/0/0 (index loops, hand impls, statement accumulation absent) + static read of the site;`to_value::` on a `&Value` is a deep copy the value's own `Clone` already performs, so the serialization path adds only a dead `Result`. +- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0; the crate's loops iterate (reconcile_children over `desired`, tests over rows), no hand-written derive-replaceable impls, no statement-style accumulators. + + + +## own +- d2b-provider-volume#2 sev=low blast=leaf effort=S verdict=actionable - `decoded_spec` returns `(envelope.clone(), spec)` though the local `envelope` is never used after the clone:an avoidable `Vec` raw-spec copy on every driver op (validate, recover, reconcile, delete) - fix: return `(envelope, spec)` directly - [driver.rs:337] + evidence: own seed `\.clone\(\)` = 35 over src; this site is the only redundant clone outside cfg(test)/test-support (redundant_clone-class; the envelope's later borrow (building `spec`) ends before the return, so ownership can move). +- d2b-provider-volume#3 sev=low blast=wide effort=M verdict=actionable - `desired_binding_intents` takes `ResourceRef` by value though it only reads it (cloning into each `BindingIntent` internally), so every production caller must clone first: driver.rs:380 and d2bd/src/resource_runtime.rs:5882,12921 - fix: change the signature to `&ResourceRef` in `d2b-provider-volume-local/src/bindings.rs:80`, drop the caller clones (callers pass `&volume_ref`) - [driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.rs:5882,12921] + evidence: own seed `\.clone\(\)` = 35 over src + census `desired_binding_intents` over packages/ = 11 hits (3 production call sites + 8 volume-local test sites); the callee stores owned refs into each intent, so taking the arg by value buys nothing over a borrow. + +- clean: seeds `\.clone\(\)`=35, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=28, `Rc<|RefCell<|Arc` return matches sibling decoders in process/host/user/guest crates,and `VolumeEffectFacets.runtime` is the daemon-supplied facet set shared by the driver effects and the hosted service (U7); no leaked dependency types in public signatures. + + + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(`=35, `let _ = |\.ok\(\);`=4, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\\(`=4, `enum \w*Error`=1; all unwrap/expect hits are in cfg(test) modules or test-support doubles(`RefusingRuntime` panics loudly by design); the only non-test `let _ =` is driver.rs:516 on a fire-and-forget completion send (an unbounded-channel send to a possibly-dropped actor mailbox, no caller remains to notify);`VolumeDriverErrorKind` is a private 6-variant taxonomy split by caller action with `class()`/`failure_kind()` mappings (R13, issue #508). + + + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize`=0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=0, `impl .*Deserialize.*for`=0, `serde_json::from_|serde_json::to_`=8; the 8 hits are boundary reads/writes over contract-crate types (`ResourceSpec`, `VolumeSpec`, fixtures), no serde attrs or hand-written deserializers in this crate, validation lives in the typed decoder plus `check_provider` (runtime gate). + + + + + +## obs +- N/A: seeds `\bprintln!\(|\beprintln!\\(`=0, `(info|debug|warn|error|trace)!\(`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=0; crate has no tracing/log dependency, so there is no telemetry to judge. + + + +## docs +- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)`=20, `^\s*/// # (Examples|Errors|Panics|Safety)`=0, `-> Result<`=35;`#![deny(missing_docs)]` is active in lib.rs:5, all 20 pub items carry first-sentence docs, VOLUME_RESYNC's 30-second magic is documented with the why (driver.rs:65-77), the 4 Result-returning pub trait methods document what the bool/unit contract reports (the `String` error is an opaque note the caller passes through, not a match surface, so `# Errors` would narrate nothing); no `# Examples` needs (`VolumeRuntime` has no doctests andits use is composition-root wiring, documented therein). + + + +## perf +- d2b-provider-volume#5 sev=low blast=leaf effort=S verdict=actionable - `reconcile` performs two identical `ctx.children()` manager round-trips per pass:`reconcile_children` already fetched the owned child set after ensures (to retire obsolete),andthen `reconcile` re-fetches the same set to compute `converged` - an extra manager RPC per reconcile pass - fix: have `reconcile_children` return the fetched `Vec` (or compute the converged verdict inside)and consume it there - [driver.rs:437-440,614-617] + evidence: static (unmeasured);`ctx.children()` routes to `self.ager.list_owned)...).await` (d2b-resource-runtime/src/context.rs:586-588), a per-call manager RPC; between the two calls no other actor can mutate this owner's rows (driver-owned children only, row actor is single-threaded), so the second fetch returns identical data. + + + +- clean: seeds `format!\\(`=5, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=7, `\.to_string\(\)`=1; all hits are cfg(test) helpers (`format!` recording keys in RecordingManager, malformed-spec fixture bytes) or required empty field defaults (`ChildEnsure.metadata`), no hot-path allocation sites. + + + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=3, `Atomic\w+|Ordering::`=18, `thread_local!|unsafe impl (Send|Sync) for`=0; the 3 Mutex hits are test-support recorders (`RecordingRuntime.calls`, `RecordingManager.log/rows`) sanctioned with `async-gate-allow: test-support recorder lock` markers and cfg(test)-helper allows; the AtomicBool flags use SeqCst deliberately (they publish a layout state read once per 30-s-cadence pass,and the cost is negligible per the skill's "SeqCst when unsure"), no threads are spawned by this crate (task concurrency belongs to async lens). + + + + + +## async +- clean: seeds `async fn|async move|\.await`=100, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\\(`=1, `tokio::sync::(Mutex|RwLock|Notify)`=0, `#\[tokio::(main|test)\]|Runtime::block_on`=13; the single `tokio::spawn` (driver.rs:512-535) is the documented layout-effect spawn (R5/KTD12: mailbox never blocks; completion arrives as `EffectCompleted` and a degraded report flows into the actor's retryable requeue), no guards are held across awaits in src (`tokio::sync` unused), the trait bounds `Send + Sync + 'static` make the spawned future Send-safe, the send on the unbounded channel is non-blocking so the irreversible step cannot be lost to cancellation. + + + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=0, `unsafe_code`=0 (over src\); crate manifest forbids `unsafe_code`, so no unsafe sites exist. + + + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0; the crate crosses no foreign boundary. + + + +## macro +- N/A: seeds `macro_rules!`=0, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; no macro definitions or proc-macro usage (std macros only). + + + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]`=18 (14 src + 4 tests/registration.rs), `assert_eq!\(|assert_ne!\(|assert!\\(`=67, `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0; tests are behavioral throughout: effect-order and commit-before-spawn (F1), deterministic child identity with no churn, adoption re-validates layout idempotently, degraded layout reports exactly one retryable failure per pass, finalize-before-delete drain ordering, idempotent delete retryarry, wire-pinned canonical payload bytes (`the_has_layout_wire_payloads_are_canonical`), error variants asserted via `matches!`/eq on the enum not Display strings, registration tests pin the declaration's verbs/creations/services against human-written expectations; no property/snapshot tooling is needed for this scale (unit + integration coverage is complete for the flows named), no ignored tests. + + + +## Coverage +- idiom: 1 finding +- own: 2 finding(s) +- type: clean (seeds ran: 1/0/0; the one gate is deliberate to keep the two wire error codes distinct) +- api: 1 finding +- err: clean)(seeds ran: 35/4/4/1; all panics are in tests/test-support; the alone `let _ =` is a fire-and-forget completion send) +- serde: clean)(seeds ran: 0/0/0/8; boundary reads over contract-crate types only) +- obs: N/A)(seeds ran: 0/0/0/0; no tracing/log dep) +- docs: clean)(seeds ran: 20/0/35;`deny(missing_docs)` active and pub items documented) +- perf: 1 finding +- conc: clean)(seeds ran: 0/3/18/0; test-support recorders + deliberate SeqCst flags) +- async: clean)(seeds ran: 100/1/0/13; single documented effect spawn; no guards across awaits) +- unsafe: N/A)(seeds ran: 0/0/0; no unsafe sites;`forbid` in manifest) +- ffi: N/A)(seeds ran: 0/0/0/0) +- macro: N/A)(seeds ran: 0/0/0/0) +- test: clean)(seeds ran: 18/67/0/0 incl. tests/; behavioral unit+registration suite, no ignored/property tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md new file mode 100644 index 000000000..949b3b784 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md @@ -0,0 +1,103 @@ +# d2b-provider-wayland-policy - d2b-provider-wayland-policy +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3974 (src 3247 + tests 727; excl. src/generated/**, none present) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- clean: seeds ran: 0/0/0; no index loops over `0..`, no hand-written `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`, no `let mut ... = String/Vec::new()` accumulation. One hand-written `Debug` for `AudioResourceRuntime` (audio_registry.rs:142) was read and judged a deliberate state-summary (counts only, not the mediator handle/map bodies), acceptable for the internal state-holding type. + + + +## own +- clean: seeds ran: 32/17/0/0; every one of the 32 `.clone()` lines is explainable: struct/field construction into owned values, `serde_json` Value edits from borrowed refs (`from_value` takes ownership), Arc clones at the genuine shared-ownership boundaries (factory `create` per driver, six drivers' shared effects port, per-zone audio registry handle),test fixtures; the 17 to_owned/to_vec/to_string lines are string/byte construction and test data; no `Rc`/`RefCell`/`Arc` sites are genuine shared ownership or sanctioned exports: `spec_decoder`/`wayland_policy_spec_decoder` return the manager-held `Arc` (call sites: wayland_policy.rs:86, tests/engine.rs:304, tests/registration.rs:62),`InteractionDriverArgs.effects` is the six drivers' shared effects port (effects_service.rs:85-87; factory clones it per create at interaction.rs:471),feature-gated `test_support::Log` is consumed by tests (repo false-positive class),and the `pub(crate) fn *() -> &Arc<...>` facet accessors are crate-internal. The `pub use` re-export arms (lib.rs:47-70) form the house single-surface pattern;`#![deny(missing_docs)]` (lib.rs:28) forces doc presence on every public item. + + + +## err +- d2b-provider-wayland-policy#1 sev=high blast=family effort=M verdict=actionable - Panic reachable from caller input at the family engine's public boundary: `InteractionDriver::new` parses-and-expects `InteractionDriverArgs.zone: String` (pub field on pub struct with no validating constructor),and `key_ref` parses-and-expects a `ResourceKey` whose `new` accepts any strings; both invariants claimed in expect messages are not enforced by the types - fix: parse once at the args boundary (change `args.zone` to a parsed `ZoneId`, or make `InteractionDriver::new` return `Result<_, InteractionDriverError>`) and make `key_ref` return `Result` (map to `SpecInvalid`) or enforce name canonicality at `ResourceKey::new` in d2b-resource-runtime - [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-wayland-policy/src/interaction.rs:488, packages/d2b-provider-wayland-policy/src/interaction.rs:836-838, packages/d2b-resource-runtime/src/spec_store.rs:60-63] + evidence: seed `\.unwrap\(\)|\.expect\(` = 43 lines over src (most in `#[cfg(test)]`/`test-support`; the two production sites above are the panics); census: `ResourceKey::new` (spec_store.rs:60-63) builds the three String fields unvalidated; route: review-pass + +- clean: seeds ran: 43/0/0/3 after removing the test-module noise; the other production expects are infallible (`expect("fixed digest width")` on a literal 8-byte slice, test-support fixed refs`, and enums are the error taxonomy (AudioResourceRuntimeError, InteractionEffectError, InteractionDriverError),closed and split by caller action (retryable vs terminal classes at interaction.rs:160-174`. + + + +## serde +- d2b-provider-wayland-policy#2 sev=medium blast=family effort=M verdict=actionable - Every wire-parse failure collapses into a bare `InvalidResource` variant that discards the serde reason, so an operator cannot tell which row or which field is malformed (a third of the enum's refusals are spec-shape checks that reuse the same variant) - fix: add a reason-carrying variant to `InteractionEffectError` and `AudioResourceRuntimeError` (e.g. `InvalidResource { reason: String }` or `Decode(#[source] serde_json::Error)` via thiserror)and thread it through the ~15 `map_err(|_| ...InvalidResource)` sites (the enum Display codes are not pinne in `docs/reference/error-codes.md` - grep "interaction" = 0 hits - so not wire-contract) - [packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-wayland-policy/src/effects_service.rs:205-206, packages/d2b-provider-wayland-policy/src/audio_registry.rs:517-534] + evidence: seed `serde_json::from_|serde_json::to_` = 23 lines; every parse failure maps to a bare InvalidResource (or the empty `InteractionSpecDecodeError` at interaction.rs:269-270; serde derive/attribute/impl seeds are 0/0/0 - parse-only boundary, so the serde reason loss is the boundary flaw. + + + +## obs +- obs: N/A (seeds: 0/0/0/0 all zero; no `tracing`/`log` dependency in Cargo.toml - the crate cross neither logging surface) + + + +## docs +- d2b-provider-wayland-policy#3 sev=low blast=leaf effort=S verdict=actionable - Result-returning public items lack `# Errors` canonical sections, so callers must infer which conditions produce `InvalidResource` vs `Unavailable` (the terminal-vs-retryable mapping at interaction.rs:632-636 is non-obvious) - fix: add `# Errors` sections to `base_spec`, `spec_with_provider_ref`, `shell_pool_spec`, `shell_session_execution`, `shell_session_pool_ref`, `owned_child_ensure`, `binding_child_ensure`, and the two `InteractionDriverEffects` methods - [packages/d2b-provider-wayland-policy/src/interaction.rs:241, packages/d2b-provider-wayland-policy/src/vocabulary.rs:35, packages/d2b-provider-wayland-policy/src/interaction.rs:342] + evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 66;`/// # (Examples|Errors|Panics|Safety)` = 0;`-> Result<` = 68 lines; the crate opted in to `#![deny(missing_docs)]` (lib.rs:28),so canonical sections are the next consistency step (the missing-docs lint is per-crate, contrary to the blanket "not enabled anywhere" note in U1) + + + +## perf +- clean: seeds ran: 3/12/0; the three `format!` sites are test-support log pushes (test_support.rs:172,190)and the cold `key_ref` string build (interaction.rs:837);`Vec::new()`/`BTreeMap::new()` are empty-start constructors of long-lived registries and test data; no allocation in a reconcile/effect hot path (per-reconcile serde Value clones at interaction.rs:242,252 are cold, one per row pass); static (unmeasured) + + + +## conc +- clean: seeds ran: 0/2/9/0; the two `Mutex<` lines are `tokio::sync::Mutex` guards for the per-zone audio registry (audio_registry.rs:413)and the test log (test_support.rs:127) - async-appropriate (guard spans a sync registry call, dropped at statement end; no std::thread/spawn/scope anywhere; the 9 atomic/Ordering lines are test-double flags (`AtomicBool`/`AtomicUsize`, SeqCst on plain scripted booleans - harmless and test-only) + + + +## async +- clean: seeds ran: 94/0/4/0; all awaits are facet/plane/manager trait reads and the two tokio Mutex guards; no `tokio::spawn`/`spawn_blocking`/`JoinSet`/`select!`/`join!` hits (this engine's design: no spawn surface, documented at interaction.rs:20-23); no blocking std call in an async body; the reconcile/delete/watch loops mutate through idempotent manager verbs with await-per-step ; cancellation-safe (no lock held across `.await` beyond the statement); no `#[tokio::main(test]`/`Runtime::block_on` in src + + + +## unsafe +- unsafe: N/A (seeds: 0/0/0/0; local `[lints.rust]` `unsafe_code = "forbid"` in Cargo.toml - the crate is fully safe) + + + +## ffi +- ffi: N/A (seeds: 0/0/0/0; no extern/repr/CStr surface in the crate) + + + +## macro +- macro: N/A (seeds: 0/0/0/0; no macros defined, no proc-macro/syn/quote usage) + + + +## test +- d2b-provider-wayland-policy#4 sev=low blast=leaf effort=S verdict=actionable - Dead no-op line in `the_policy_envelope_is_the_whole_contract`: `let _ = ResourceRef::parse)...)` asserts nothing and cannot fail - fix: assert the parse succeeds (e.g. `.expect("the policy reference parses")`), or delete the line - [packages/d2b-provider-wayland-policy/tests/registration.rs:93] + evidence: static read; `Result` is discarded with no assertion; the surrounding test already covers the decoder refusal paths at registration.rs:92 + +- clean: seeds ran: 25/75/0/0; the suite is behavior-focused: assertions carry messages and cite regressions (e.g. "Regression (P2)" at effects_service.rs:746-752),the recording-manager harness makes ordering assertions on log entries with context,no proptest/insta/rstest and no `#[ignore]` (deterministic fixtures, injected time, no network/clock); the `#[allow(clippy::disallowed_methods, reason = "cfg(test helper")]` sites use the sanctioned reason + + + +## Coverage +- idiom: clean (0/0/0) +- own: clean (32/17/0/0) +- type: clean (3/0/0) +- api: clean (70/6/5) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: N/A (0/0/0/0; no tracing/log dep) +- docs: 1 finding(s) +- perf: clean (3/12/0) +- conc: clean (0/2/9/0) +- async: clean (94/0/4/0) +- unsafe: N/A (0/0/0/0; forbid) +- ffi: N/A (0/0/0/0) +- macro: N/A (0/0/0/0) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md new file mode 100644 index 000000000..394f69029 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md @@ -0,0 +1,81 @@ +# d2b-provider-zone-link - d2b-provider-zone-link +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3805 (excl. src/generated/**) | modules: whole crate (lib.rs, driver.rs, zone_links.rs, zonelink.rs; tests/registration.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- d2b-provider-zone-link#1 sev=medium blast=family effort=S verdict=actionable - the frozen cryptoperiod defaults `BOOTSTRAP_PSK_TTL_MS_DEFAULT` (300_000) and `KK_SESSION_MAX_LIFETIME_MS_DEFAULT` (86_400_000) are defined identically in two crates with no shared home, so a drift silently desynchronizes the child-local handler from the bus-side enrollment machine - fix: move both constants to `d2b_contracts_zone_session` (the crate both `d2b-provider-zone-link` and `d2b-bus` already depend on) and re-export from both sites; this is not the refused ZoneLink enrollment-machine merge, only the two constants - [packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/zone_links.rs:63, packages/d2b-bus/src/session/enrollment.rs:42, packages/d2b-bus/src/session/enrollment.rs:49] + evidence: census: `BOOTSTRAP_PSK_TTL_MS_DEFAULT|KK_SESSION_MAX_LIFETIME_MS_DEFAULT` over packages/nixos-modules/tests/docs/reference/labs = 2 defining sites with identical values (zone_links.rs:60,63 and d2b-bus/src/session/enrollment.rs:42,49); the refused class in docs/explanation/over-engineering-audit-record.md is the enrollment-machine merge, not these constants +- clean: seeds ran 2/2/1; the two `impl Default` hits (zone_links.rs:305,338) deliberately preserve frozen nonzero defaults a field-wise derive would break; the `Vec::new()` accumulation (zone_links.rs:1422) is the match-arms planner pattern; the two `for .. in 0..` loops (zone_links.rs:2012,2828) are test drivers + +## own +- d2b-provider-zone-link#2 sev=low blast=leaf effort=S verdict=actionable - `plan()` clones `record.route_binding` in the `RoutePolicyCommitted` and `SessionGenerationAdvanced` arms only to mutate it and store it back, where a `route_binding.as_mut()` borrow would work (no other borrow of the record is live in either arm) - fix: replace `let Some(mut binding) = record.route_binding.clone() else ...` with `let Some(binding) = record.route_binding.as_mut() else ...` and mutate through the borrow in both arms - [packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/src/zone_links.rs:1706] + evidence: seed `\.clone\(\)` = 50 hits; the 1663/1682 clones are required (binding moves into `ZoneLinkRouteAdmissionContext`, operation id is re-inserted after comparison), the 1418 record clone is the deliberate copy-on-write pass design, the 815-820 clones feed an owned wire struct, 1269 feeds an owned status projection; only 1692/1706 are avoidable +- d2b-provider-zone-link#3 sev=low blast=leaf effort=S verdict=actionable - `plan()` clones `record.enrollment` in the `EnrolledSessionEstablished` arm solely to compare the key fingerprint before mutating disjoint record fields - fix: take `record.enrollment.as_ref()`, compare `enrollment.key_fingerprint() != &peer_key_fingerprint` (fingerprint tokens are Copy), and let the borrow end before the `record.link_epoch += 1` mutation - [packages/d2b-provider-zone-link/src/zone_links.rs:1526] + evidence: seed `\.clone\(\)` = 50 hits; the arm mutates only `link_epoch`/`connected`/`child_authorized`/`reconnect_attempts`/`advertised_routes`, all disjoint from `enrollment`, so the clone buys nothing +- clean: seeds ran 50/3/0; the three `to_*` hits and the remaining clones are test fixtures (zonelink.rs:350,367,401,429-523; zone_links.rs:1948-2135); no `Rc`/`RefCell`/`Arc`/`Cow` anywhere; the `AtomicU64` owner-token static is a process-wide counter with no single owner + +## type +- clean: seeds ran 1/0/0; the single `fn validate_` hit (`validate_commit_proof`, zone_links.rs:1402) is an internal invariant check on an opaque token with no public constructor, not input validation a parsed type could replace; no boolean-flag soup or stringly-typed state (the record's `disabled`/`connected`/`child_authorized` booleans mirror pinned spec fields - schema-mirroring false positive); the commit-before-effect protocol is already typestate-enforced via `ZoneLinkPass` (no Clone/Copy) and `ZoneLinkCommitProof` (no public constructor) + +## api +- d2b-provider-zone-link#4 sev=low blast=leaf effort=S verdict=actionable - `ZoneLinkMetricSample` and `ZONE_LINK_METRIC_LABEL_KEYS` are exported pub (and re-exported through `zonelink`) but have zero consumers outside the crate, so the metric vocabulary is promised surface nobody wires - fix: either consume them from `d2bd`'s metrics path or reduce to `pub(crate)` until a consumer exists - [packages/d2b-provider-zone-link/src/zone_links.rs:1783, packages/d2b-provider-zone-link/src/zone_links.rs:89, packages/d2b-provider-zone-link/src/zonelink.rs:13] + evidence: census: `ZoneLinkMetricSample|ZONE_LINK_METRIC_LABEL_KEYS` over packages/nixos-modules/tests/docs/reference/labs = 0 hits outside the crate (only in-crate tests at zone_links.rs:3092-3107 and the re-export) +- d2b-provider-zone-link#5 sev=low blast=leaf effort=S verdict=actionable - `transport_error_is_quarantine` is a `pub const fn` with zero callers anywhere, including in-crate tests, so it is dead exported surface - fix: make it private or delete it until the quarantine mapping is actually consumed - [packages/d2b-provider-zone-link/src/zonelink.rs:281] + evidence: census: `transport_error_is_quarantine` over packages/nixos-modules/tests/docs/reference/labs = 0 hits outside its definition +- d2b-provider-zone-link#6 sev=low blast=leaf effort=S verdict=actionable - `ZoneLinkCursorAuthority` is `pub` but is only reached through `ZoneLinkController` in the same module and the module's own tests, so its publicity is wider than its use - fix: reduce to `pub(crate)` - [packages/d2b-provider-zone-link/src/zonelink.rs:178] + evidence: census: `ZoneLinkCursorAuthority` over packages/nixos-modules/tests/docs/reference/labs = 0 hits outside the crate; `d2bd/src/composition.rs:770,891` consumes `ZoneLinkController` only +- clean: seeds ran 133/0/5; no `Arc`/`Rc`/`Box`/`RefCell` in any public signature; the lib.rs `pub use ...::*` arms are the house single-surface pattern; the `pub(crate)` + `#[cfg(test)]` accessors on `ZoneLinkRouteAdmissionContext` and `ZoneLinkHandler::route_admission_context` are correctly scoped; the crate root surface is consumed by `d2bd/src/composition.rs` (86-896, 1118-1172) and `d2bd/src/resource_plane_v3.rs:153` + +## err +- clean: seeds ran 115/0/0/2; all 115 `unwrap`/`expect` hits sit in `#[cfg(test)] mod tests` helpers (zone_links.rs:1817-1945, zonelink.rs:350-527) - the card's test-code false positive; zero panic macros, zero swallowed `Result`s, zero production unwraps; the two error enums (`ZoneLinkError` 26 variants, `ZoneLinkAdoptionError` 4 variants) are closed, Copy, and carry stable kebab-case `label()` tokens asserted bounded by `every_error_label_is_a_bounded_lowercase_token` (zone_links.rs:3131); the cross-crate label reuse via `ZoneRouteFailClosedReason` (zone_links.rs:224,232) avoids duplicated wire tokens + +## serde +- clean: seeds ran 1/1/0/2; the only serde surface is the private durable envelope `ZoneLinkRouteAdmissionDedupWire` (zone_links.rs:697-704) with `rename_all = "camelCase"` + `deny_unknown_fields`, a version field checked on recovery, canonical-bytes enforcement (zone_links.rs:822-826, 845-847), and identity binding; round-trip, version-mismatch, and identity-mismatch paths are covered by `multiple_committed_route_ids_survive_versioned_restart_recovery` (zone_links.rs:2036) and `aborted_route_ids_are_reusable_but_recreated_identity_is_isolated` (zone_links.rs:2097); no hand-written `Deserialize`, no `flatten`, no untagged + +## obs +- N/A: seeds 0/0/0/0 all zero; the crate has no `tracing`/`log` dependency (Cargo.toml deps: d2b-contracts-resource, d2b-resource-types, serde, d2b-contracts-zone-session, serde_json; tokio is dev-only), and the module is a pure planner with no telemetry surface + +## docs +- d2b-provider-zone-link#7 sev=low blast=leaf effort=M verdict=actionable - 21 public `Result`-returning items document their failure modes only in prose, with zero `# Errors` sections, so the error contract (which `ZoneLinkError` variant fires) is not in the canonical place a caller reads - fix: add `# Errors` sections naming the `ZoneLinkError`/`ZoneLinkAdoptionError` variants to the public `Result` items, starting with `ZoneLinkLimits::new`, `ZoneLinkHandler::{begin,commit,release_effects,issue_route_admission}`, `ZoneLinkRecord::{with_route_binding,encode_route_admission_dedup,with_route_admission_dedup}`, `ZoneLinkOwnerProof::{new,from_digest}`, `ZoneLinkCursorAuthority::{adopt,cursor}` - [packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src/zone_links.rs:1300, packages/d2b-provider-zone-link/src/zonelink.rs:197] + evidence: seeds ran 131/0/21 (131 public items, 0 canonical sections, 21 `-> Result<`); every public item carries a first-sentence doc comment, module docs exist in all four files, and the redaction `Debug` impls are deliberate (tested at zone_links.rs:3115) +- clean: seeds ran 131/0/21; no undocumented public item found; the `ZoneLinkKeyPolicy` "locked six-field schema" doc (zone_links.rs:335-337) is accurate - the ZoneLink spec has exactly six fields (childZoneName, disabled, limits, transportCredentials, transportProviderRef, transportSettings per docs/reference/schemas/v3/core.d2b.org_ZoneLink.schema.json) + +## perf +- clean: seeds ran 3/1/2; all six hits are test-only (`format!` at zone_links.rs:1963,3119 and zonelink.rs:350; `to_string` at zone_links.rs:1977,3168 and zonelink.rs:350; `Vec::new` at zone_links.rs:1422); production has no `format!`/`to_string` and the only allocation in the reconcile path is the deliberate copy-on-write record clone in `plan()` (cold per-event path); `static (unmeasured)` - no benchmark exists for this crate + +## conc +- clean: seeds ran 0/0/3/0; the three hits are the `AtomicU64` owner-token generator (zone_links.rs:35,48,52) using `Ordering::Relaxed` on a counter nobody synchronizes on - the weakest correct ordering per the skill; no `Mutex`/`RwLock`, no threads, no `thread_local!`, no manual `Send`/`Sync` impls + +## async +- N/A: seeds 0/0/0/0 all zero over src/; the crate is a synchronous planner - no `async fn`, no `tokio::spawn`, no `tokio::sync` in src; tokio appears only as a dev-dependency for the single `#[tokio::test]` registration shim (tests/registration.rs:11), which is the test lens's territory + +## unsafe +- N/A: seeds 0/0/0/0 all zero; no `unsafe` blocks/fns/impls, no `transmute`/`from_raw`/`MaybeUninit`, no `// SAFETY:` sites; the manifest sets `[lints.rust] unsafe_code = "forbid"` (Cargo.toml:7), and the crate is not on the (d) 8 exception list + +## ffi +- N/A: seeds 0/0/0/0 all zero; no `extern "C"`, no `no_mangle`, no `repr(C)`/`repr(transparent)`, no `CStr`/`CString` - the crate crosses no foreign boundary + +## macro +- N/A: seeds 0/0/0/0 all zero; no `macro_rules!`, no proc-macro/syn/quote, no `$crate`, no `to_compile_error` - the crate defines no macros + +## test +- d2b-provider-zone-link#8 sev=low blast=leaf effort=S verdict=actionable - three table-driven loops assert without a per-case failure message, so a failing row reports only a line number, not which state/error/key failed - fix: add messages naming the loop variable (`"state: {state:?}"`, `"key: {key}"`, `"error: {error:?}"`) to the loops at zone_links.rs:2513-2519, 3092-3094, and 3133-3167 - [packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/src/zone_links.rs:3093, packages/d2b-provider-zone-link/src/zone_links.rs:3162] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 166 hits; the three loops are the only table-driven asserts without messages (the metric-label loops at 3093/3109 do carry messages) +- clean: seeds ran 43/166/0/0 (209 hits); 42 `#[test]` + 1 `#[tokio::test]` (tests/registration.rs:11, the policy-required registration shim - documented pattern, not flagged); assertions target error variants and durable state, not `Display` strings (the only `to_string` assertions pin the label contract at zone_links.rs:3168); the suite is deterministic (explicit `now_ms`, no clock/network), covers restart replay, capacity ceilings, redaction, and identity isolation; no `#[ignore]`, no proptest/insta/rstest - none needed for this state machine; no test found that cannot fail + +## Coverage +- idiom: 1 finding(s) +- own: 2 finding(s) +- type: clean (seeds ran: 1/0/0) +- api: 3 finding(s) +- err: clean (seeds ran: 115/0/0/2) +- serde: clean (seeds ran: 1/1/0/2) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 1 finding(s) +- perf: clean (seeds ran: 3/1/2) +- conc: clean (seeds ran: 0/0/3/0) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn or tokio in src; tokio is dev-dep only) +- unsafe: N/A (seeds: 0/0/0/0 all zero; manifest unsafe_code = "forbid") +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md new file mode 100644 index 000000000..77fed7130 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md @@ -0,0 +1,68 @@ +# d2b-provider - d2b-provider +Baseline: 6ebdd4cec | LOC audited: 3,252 (incl. tests/runtime.rs 667; no src/generated/**) | modules: whole crate (agent, context, descriptor, error, identity, instance, lib, operation_ledger, registry, session; tests/runtime.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- clean: seeds ran: 0/2/0;; the two hand-written `Default` impls (operation_ledger.rs:152, registry.rs:76)preserve invariantsa field-wise derive would break (ledger capacity=MAX_OPERATION_LEDGER_ROWS; registry caps=256/32) - the U1-listed deliberate class;; no index loops,no statement-style accumulation in src/** + +## own +- d2b-provider#1 sev=low blast=leaf effort=S verdict=actionable - `ProviderAgent::dispatch` clones the full canonical-JSON request per dispatch (agent.rs:290)even though only `request.method` and `request.timeout_ms` are used after the `timeout`, both Copy - fix: extract `let method = request.method;` before the `timeout)...)`, move `request` into `self.service.dispatch)...)` instead of `request.clone()`, and use `method` in the audit record - [packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304] + evidence: `\.clone\(\)` = 26 hits over src/**,all other 25 reviewed as required shared-ownership or owned-wrapper clones (Arc, Arc, watch Sender, cancellation tokens, instance/descriptor/subject clones into owned values);`SpecifiedProviderMethod` derives Copy (d2b-contracts-provider/src/v3/provider.rs:2758-2763),so the partial move compiles + +## type +- clean: seeds ran: 0/0/0;; no `validate_`/`check_` fns,no bool flags,no string-typed state;;`RegistryLimits::validate`/`RegistryDrainPolicy::validate` run at their consuming boundaries (builder.limits, shutdown/publish),so there is no validate-at-every-callsite spread to encode away + +## api +- clean: seeds ran: ~163/1/6;; single-surface `pub use` house pattern (lib.rs:40-65),private module tree;; the one `Arc>` return (registry.rs:618 `current()`)is justified shared ownership:callers hold the generation Arc across awaits while `ProviderRegistryManager::publish` swaps it (registry.rs:626-648; U1-listed evaluation class); no `Rc`/`Box`/`RefCell` in pub signatures + +## err +- clean: seeds ran: 12/0/0/4;; all 12 `.unwrap()`/`.expect(` sites are inside `#[cfg(test)]` modules (agent.rs:349-403,registry.rs:726-727,U1-listed acceptable class); no swallowed Results,no panic macros;; the four error enums are closed Copy code-book types printing kebab wire codes (ProviderAgentError, RegistryBuildError, ProviderRuntimeError, OperationLedgerError);; agent's HandlerFailed/DispatchTimeout mapping is a deliberate wire-boundary conversion,not a swallowed chain + +## serde +- N/A: seeds ran: 0/0/0/0 all zero;; crate crosses no wire - no serde dependency in Cargo.toml,no serde attributes,no serde_json anywhere in src/** + +## obs +- N/A: seeds ran: 0/0/0/0 all zero;; no `println!`/`eprintln!`,,no tracing/log macros,no instrument,no tracing/log dependency in Cargo.toml - the card's N/A criterion (all seeds zero and no tracing/log dep)holds + +## docs +- d2b-provider#2 sev=medium blast=leaf effort=M verdict=actionable - Public Result-returning APIs carry no `# Errors` sections,naming which conditions produce which error variants - fix: add `# Errors` sections to the ~28 pub Result-returning fns (agent.rs:40,270; context.rs:63; descriptor.rs:55,108,196,232; identity.rs:98,120,142; instance.rs:28; operation_ledger.rs:179,195; registry.rs:64,99,329,412; session.rs:36,94),listing each reachable variant per fn - [packages/d2b-provider/src/agent.rs:270, packages/d2b-provider/src/descriptor.rs:232, packages/d2b-provider/src/registry.rs:412, packages/d2b-provider/src/session.rs:36] + evidence: docs seed2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits over src/**,while seed3 `-> Result<` = 33 hit sites;; surface doc coverage itself is enforced (`#![deny(missing_docs)]` at lib.rs:5),so the gap is doc-contract shape (canonical sections),not absence of docs + +## perf +- clean: seeds ran: 0/3/0;; the 3 `BTreeMap::new()` sites are cold one-shot builders (operation_ledger.rs:172,184; registry.rs:261); the agent audit deque preallocates with `with_capacity` (agent.rs:226); no `format!`/`to_string` in src/**;; no hot-path allocation site identified statically + +## conc +- clean: seeds ran: 0/1/~33/0;; the tokio `Mutex>` (agent.rs:213)is held across no `.await` (agent.rs:257-262); Acquire/Release atomics with compare_exchange loops and documented lock-free rationale (registry.rs:446-448,546-560); the Notify drain handoff has a lost-wakeup regression test (registry.rs:698-727); no `std::thread`,no manual `Send`/`Sync` claims + +## async +- d2b-provider#3 sev=medium blast=leaf effort=S verdict=actionable - `ProviderAgent::serve` awaits each `dispatch` serially (agent.rs:316-324):a slow handler near the 900s timeout bound (`MAX_AGENT_TIMEOUT_MS`)stalls the whole session queue,and the `MAX_AGENT_IN_FLIGHT=64` Semaphore bound can never be exceeded by the serve loop itself - fix: spawn each dispatch (`tokio::spawn(async move { let result = self.dispatch(request).await; let _ = response_tx.send(result.await; })`) with a cloned `response_tx`,letting the already-acquired Semaphore permit cap concurrency; state whether per-session response ordering is a contract) - [packages/d2b-provider/src/agent.rs:316-324] + evidence: async seeds = 36/1/0/4 (seed2 hit: registry.rs:709 test `tokio::spawn`; seed4: 4 `#[tokio::test]` in src/**);`census: ProviderAgent over packages/; nixos-modules/; tests/; docs/reference/; labs/; BUILD.bazel = lib.rs re-export + toolkit `FakeProvider` impl (d2b-provider-toolkit/src/testing/fixture.rs:380)+ own tests,so the serialization defect is latent until a session wires the kept B2 dispatcher (not a removal proposal) + +## unsafe +- N/A: seeds ran: 0/0/0 all zero;; no `unsafe` block/fn/impl/SAFETY site in src/**;;`unsafe_code` appears only as the inherited workspace `forbid` (Cargo.toml [lints] workspace = true),which is not a site per the card + +## ffi +- N/A: seeds ran: 0/0/0/0 all zero;; no extern "C",no no_mangle,no repr(C)/repr(transparent),,no CStr/CString/c_char anywhere in src/** + +## macro +- N/A: seeds ran: 0/0/0/0 all zero;; no `macro_rules!`,no proc-macro/syn/quote,no `$crate`,no compile-error machinery anywhere in src/** + +## test +- clean: seeds ran: 26/75+/0/0;;26 tests (18 `#[test]` + 8 `#[tokio::test]`:4 in-agent/registry src tests,22 in tests/runtime.rs)assert behavior and error variants (never Display strings),pin the redaction contract (tests/runtime.rs:480-488),use hermetic fixed-value helpers (no network,no clock reads; drain tests await only the in-process Notify path); no `#[ignore]`,no proptest/insta/rstest + +## Coverage +- idiom: clean (seeds ran: 0/2/0) +- own: 1 finding(s) (seeds ran: 26/0/0/0) +- type: clean (seeds ran: 0/0/0) +- api: clean (seeds ran: ~163/1/6) +- err: clean (seeds ran: 12/0/0/4) +- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no wire) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) +- docs: 1 finding(s) (seeds ran: ~165/0/33) +- perf: clean (seeds ran: 0/3/0) +- conc: clean (seeds ran: 0/1/~33/0) +- async: 1 finding(s) (seeds ran: 36/1/0/4) +- unsafe: N/A (seeds: 0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 26/75+/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md new file mode 100644 index 000000000..0a56ecbbf --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md @@ -0,0 +1,87 @@ +# d2b-resource-api-p1 - d2b-resource-api - part 1/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6971 (excl. src/generated/**) | modules: service.rs, adapter.rs, manager_backend.rs, client.rs, store.rs, watch.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2: src/service.rs, src/adapter.rs, src/manager_backend.rs, src/client.rs, src/store.rs, src/watch.rs (part 2 owns src/authz.rs, src/manager_backend/**, src/admission.rs, src/error.rs, src/identity.rs, src/lib.rs) + +## idiom +- clean: seeds `for \w+ in 0\.\.` = 1 (test-only case-index loop, service.rs:2834), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 2 (manager_backend.rs:490 cursor key build, covered by perf finding 11; manager_backend.rs:1243 bounded batch loop, MAX_BATCH_MUTATIONS = 32). Hand-written `Clone` on `CheckedResourceStore` (store.rs:85) avoids an unwanted `S: Clone` derive bound and the hand-written `Debug` impls redact secrets - both deliberate per the idiom card's false-positive list. + +## own +- d2b-resource-api-p1#1 sev=low blast=leaf effort=S verdict=actionable - every bus scoped commit clones the full assignment-mutation list (`transport.mutations().to_vec()`) even though the whole chain only borrows it - fix: change `ResourceApiClient::scoped_commit_batch` (client.rs:110) and `ResourceService::commit_scoped_batch` (service.rs:852) to take `&[ScopedResourceMutation]` and pass `transport.mutations()` directly at adapter.rs:425 - [adapter.rs:425, client.rs:110, service.rs:852] + evidence: seed `\.clone\(\)` = 50 hits, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 52; census: `scoped_commit_batch` over packages = no production caller outside d2b-resource-api, so the signature change breaks no caller; the remaining clones are explainable (Arc clones of shared service, cursor/claims ownership transfers). +- clean: seeds `Rc<|RefCell<|Arc Result<` = 45; none of the pub Result-returning items in the lane has a `# Errors` section (seed `/// # (Examples|Errors|Panics|Safety)` = 0 in the lane). +- d2b-resource-api-p1#10 sev=low blast=leaf effort=M verdict=actionable - several pub items have no doc comment at all: `TrustedRequest::request`, `ResourceService::new`, the thirteen RPC forwarding methods on `ResourceApiClient` (client.rs:45-135) and `ResourceService` (service.rs:503-1115), and the `ScopedCommitFrameError`/`ScopedQueryFrameError` variants - fix: add one-line first sentences, linking docs/reference/daemon-api.md where the wire contract lives - [service.rs:70, service.rs:198, client.rs:45, adapter.rs:32-56] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 42; the undocumented items above are the gap; the RPC contract is documented in docs/reference/daemon-api.md, so a link suffices and no missing_docs lint is proposed. + +## perf +- d2b-resource-api-p1#11 sev=low blast=leaf effort=S verdict=actionable - `encode_list_cursor` hex-encodes each cursor key byte with a per-byte `format!("{byte:02x}")` allocation, and duplicates the hex encoder already present as the local `hex` closure in `list_selector_digest` - fix: extract one `fn hex(bytes: &[u8]) -> String` (with `String::with_capacity(bytes.len() * 2)` and `write!`/`char::from_digit`) and call it from both sites - [manager_backend.rs:495, manager_backend.rs:449-455] + evidence: static (unmeasured); seed `format!\(` = 20, the per-byte loop at manager_backend.rs:495 is the only format-in-loop site in the lane (cursor encoding runs on every truncated LIST page). +- d2b-resource-api-p1#12 sev=medium blast=leaf effort=S verdict=actionable - `commit_mutation` clones the full canonical resource (up to 256 KiB) on every UpdateSpec/UpdateMetadata before the byte-identical no-op check, so a no-op update pays the whole copy - fix: compare `mutation.canonical_resource.as_deref() == Some(row.spec.as_slice())` first and return the committed view early, cloning only when the bytes actually differ - [manager_backend.rs:1006] + evidence: static (unmeasured); `MAX_RESOURCE_ENVELOPE_BYTES = 256 * 1024` (packages/d2b-contracts-resource/src/v3/limits.rs:5); the clone at manager_backend.rs:1006 runs on the per-mutation hot path before the documented no-op short-circuit at manager_backend.rs:1008-1014. +- d2b-resource-api-p1#13 sev=medium blast=family effort=M verdict=actionable - `owner_key_for` resolves a mutation's owner by listing the entire Zone row set (`manager.list(ResourceSelector::default())`) and linear-searching for the owner uid, on every Delete and every owner-less UpdateSpec/UpdateMetadata/UpdateFinalizers - fix: expose a manager-side uid-to-key lookup on `ResourceManagerClient` (d2b-resource-runtime) or return the owner key from `get_row`, and call it instead of the full-zone list - [manager_backend.rs:1081-1103, manager_backend.rs:1090] + evidence: static (unmeasured); the full-zone list at manager_backend.rs:1090 is called from `owner_for_update` (manager_backend.rs:1065) and the Delete arm (manager_backend.rs:1046) on every mutation that does not carry an explicit owner; the doc comment claims the manager's uid index resolves the owner, but the implementation re-derives it by scanning all rows. + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 15, `Atomic\w+|Ordering::` = 12, `thread_local!|unsafe impl (Send|Sync) for` = 0; every Mutex and atomic hit is test-only (`tokio::sync::Mutex` fakes, SeqCst counters in `FakeStore`/`RecordingStore`), production code in the lane has no locks, threads, or atomics. + +## async +- clean: seeds `async fn|async move|\.await` = ~130, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 15 (all test fakes), `#\[tokio::(main|test)\]|Runtime::block_on` = 14 (all `#[tokio::test]`); no blocking calls in async context, no guards held across `.await` in production code, and both async traits (`ResourceStoreBackend`, `UpgradeDispatcher`) use RPITIT with `+ Send` bounds. + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; the crate manifest forbids unsafe (`unsafe_code = "forbid"` at packages/d2b-resource-api/Cargo.toml:7), so the lens is not applicable. + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface in the lane. + +## macro +- d2b-resource-api-p1#14 sev=low blast=leaf effort=S verdict=actionable - `response_error!` generates thirteen identical one-line functions that differ only in the response type, a case a generic function covers without a macro - fix: replace the macro with `fn error_response(error: ResourceError) -> T` (type inferred from each RPC method's return type) and delete the thirteen `response_error!` invocations - [service.rs:2245-2267] + evidence: seed `macro_rules!` = 3 (service.rs:1262, service.rs:1322, service.rs:2245); `impl_mutation_request!` and `impl_strict_mutation_request!` are genuine impl-per-type generation (one of the skill's three legitimate answers) and are not flagged; seed `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0. + +## test +- d2b-resource-api-p1#15 sev=low blast=leaf effort=S verdict=actionable - `status_owner_matching_generation_is_representable` asserts only that `ControllerGeneration::new(11)` and `ResourceGeneration::new(11)` succeed on literals, restating the type system rather than a behavior contract - fix: delete it, or convert the representability claim into the wire-compatibility test it is meant to document (asserting the status-owner comparison path with a real mismatch) - [service.rs:3377] + evidence: seed `#\[test\]|#\[tokio::test\]` = 23, `assert_eq!\(|assert_ne!\(|assert!\(` = ~90; the test body (service.rs:3377-3384) contains no behavior under test; the suite is otherwise behavioral (dispatch sentinels, redaction markers, authorization-before-validation ordering, byte-bound enforcement). + +## Coverage +- idiom: clean (seeds: 1/0/2; only non-test hit is the cursor build covered by perf finding 11; hand-written Clone/Debug impls deliberate) +- own: 1 finding(s) +- type: 1 finding(s) +- api: 3 finding(s); watch.rs kept-half (B1) refusal cited per U1 (d) 6, not re-flagged +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: 1 finding(s) +- docs: 2 finding(s) +- perf: 3 finding(s) +- conc: clean (seeds: 0/15/12/0; all hits test-only fakes and counters) +- async: clean (seeds: ~130/0/15/14; no blocking, no guards across await, Send bounds on both async traits) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: 1 finding(s) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md new file mode 100644 index 000000000..6153ce8a0 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md @@ -0,0 +1,72 @@ +# d2b-resource-api-p2 - d2b-resource-api - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6960 (excl. src/generated/**) | modules: authz, admission, error, identity, manager_backend (tests), lib +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/authz.rs, src/manager_backend/**, src/admission.rs, src/error.rs, src/identity.rs, src/lib.rs + +## idiom +- d2b-resource-api-p2#1 sev=low blast=leaf effort=M verdict=actionable - A6 not-applied: 17 hand-written redaction Debug impls in authz.rs (15) and admission.rs (2) where the exported `redacted_debug!` macro exists - fix: fold byte-compatible impls to `redacted_debug!` or extend the macro with a count-preserving form, updating the Debug-shape pinning tests in the same change - [packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, packages/d2b-resource-api/src/authz.rs:356, packages/d2b-resource-api/src/authz.rs:377, packages/d2b-resource-api/src/authz.rs:530, packages/d2b-resource-api/src/authz.rs:546, packages/d2b-resource-api/src/authz.rs:560, packages/d2b-resource-api/src/authz.rs:575, packages/d2b-resource-api/src/authz.rs:594, packages/d2b-resource-api/src/authz.rs:604, packages/d2b-resource-api/src/authz.rs:770, packages/d2b-resource-api/src/authz.rs:800, packages/d2b-resource-api/src/authz.rs:1090, packages/d2b-resource-api/src/authz.rs:1120, packages/d2b-resource-api/src/authz.rs:1270, packages/d2b-resource-api/src/admission.rs:60, packages/d2b-resource-api/src/admission.rs:300, packages/d2b-resource-api/src/authz.rs:3328, packages/d2b-resource-api/src/admission.rs:695] + evidence: idiom seeds = 1/1/4 hits; A6 row at docs/explanation/over-engineering-audit-record.md:459 (not applied, no refusal reason; sites still match at 6ebdd4cec); the macro prints only `Type()` (packages/d2b-contracts-resource/src/v3/execution_policy.rs:22-28), so the count/presence fields these impls keep are not byte-compatible without a macro extension, and the shapes are pinned by the two Debug tests +- d2b-resource-api-p2#2 sev=low blast=leaf effort=S verdict=actionable - unformatted `use` lines inside a fn body break `cargo fmt --check` - fix: reindent to 4 spaces and drop the inner-brace spacing - [packages/d2b-resource-api/src/manager_backend/tests.rs:1045, packages/d2b-resource-api/src/manager_backend/tests.rs:1046] + evidence: idiom seeds = 1/1/4 hits; the two `use` lines sit at mixed columns inside `converted_type_status_layers_round_trip_through_their_typed_decoders` (no rustfmt.toml in the repo, default rules apply) + +## own +- d2b-resource-api-p2#3 sev=low blast=leaf effort=S verdict=actionable - redundant `.cloned()` in `StoreAdmissionBinding::verify`: `mutations` is already owned after the destructure, so the iterator clones every mutation before `prepare_mutation` consumes it - fix: `mutations.into_iter().map(prepare_mutation)` - [packages/d2b-resource-api/src/admission.rs:338, packages/d2b-resource-api/src/admission.rs:344, packages/d2b-resource-api/src/admission.rs:345] + evidence: seed `\.clone\(\)` = 133 hits in scope (74 authz.rs, 53 tests.rs, 6 admission.rs); `prepare_mutation` takes `StoreMutation` by value (admission.rs:417), so `into_iter()` compiles without the clone; all other clones in this part are explainable (owned outputs, Arc clones, test fixtures) + +## type +- clean: seeds `fn validate_\w+|fn check_\w+` = 2 (admission.rs:456,483), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the two validate hits are boundary admission gates on untrusted wire bytes (the card's parse-once-at-boundary shape), and no boolean-flag or stringly-typed state fields exist in this part + +## api +- clean: seeds `pub (fn|struct|enum|trait|type|const|mod)` = 81, `pub .*Arc|Rc|Box|RefCell<` = 0, `pub use` = 13; the surface is deliberate: private fields plus compile_fail doctests on AuthorizationLease/AdmittedMutation/AuthenticatedSubjectContext, the lib.rs re-export arms are the house single-surface pattern, and no internals or dependency types appear in public signatures + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(` = 379, `let _ = |\.ok\(\);` = 7, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 17, `enum \w*Error` = 3; every production hit falls in the card's false-positive classes: one expect on a literal catalog (authz.rs:88), two invariant-named expects on bounded batch ordinals (admission.rs:206,208), fail-closed `unwrap_or_else` fallbacks (error.rs:74-78); panics and unwraps are otherwise confined to tests, and the three error enums (StoreSealHandoffError, AdmissionError, AuthorizationPolicyError) all carry Display plus Error + +## serde +- clean: seeds `derive(...Serialize` = 0, `serde(...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|to_` = 30; the two production `from_slice` parses (authz.rs:409,420) are the typed admission boundary where canonical JSON becomes RoleSpec/RoleBindingSpec with error collapse to RoleSchema/BindingShape, and the remaining hits are test payloads + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0 real hits (the seed only matched `catalog::` substrings; tracing is used only in part 1's manager_backend.rs:194) + +## docs +- d2b-resource-api-p2#4 sev=medium blast=leaf effort=S verdict=actionable - nine pub methods on the evaluator surface are undocumented, including `NativeAuthorizer::authorize` (the security decision entry returning nine AuthorizationDenial variants) and `take_store_seal` (which hands off an ownership-bearing seal acceptor) - fix: add doc comments with `# Errors` sections enumerating the denial variants on authorize, and one-line contracts on the remaining eight - [packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, packages/d2b-resource-api/src/authz.rs:912, packages/d2b-resource-api/src/authz.rs:1093, packages/d2b-resource-api/src/authz.rs:1479, packages/d2b-resource-api/src/authz.rs:1505, packages/d2b-resource-api/src/authz.rs:1522, packages/d2b-resource-api/src/authz.rs:1550, packages/d2b-resource-api/src/authz.rs:1615] + evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 81 hits, seed 2 (`/// # ...`) = 0, seed 3 (`-> Result<`) = 48; the `///` scan over authz.rs shows no doc comment above these nine lines, and `missing_docs` is not enabled anywhere (proposal only) + +## perf +- d2b-resource-api-p2#5 sev=low blast=leaf effort=S verdict=actionable - `compile_authorization_facts` grows its roles and bindings Vecs by push although the row count is known upfront - fix: `Vec::with_capacity(rows.len())` for both - [packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458] + evidence: static (unmeasured); seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 22 hits in scope, and the loop over `rows` at authz.rs:461 bounds both collections + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 2, `\bMutex<|\bRwLock<` = 5, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; every Mutex/RwLock site (authz.rs:1401,1404,1407, admission.rs:52,393) carries the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` allow, and the two thread::spawn hits are the sanctioned cfg(test) linearization test (authz.rs:2686,2707) + +## async +- clean: seeds `async fn|async move|\.await` = 77, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 13; every hit is the test harness in manager_backend/tests.rs under the sanctioned `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]` allow, and the production surface in this part is deliberately synchronous (admission.rs:356-359) + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 all zero; the manifest sets `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero + +## macro +- clean: seeds `macro_rules!` = 1, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the single hit is the test-only `impl_has_error!` helper (tests.rs:463), the card-listed test-helper false positive + +## test +- d2b-resource-api-p2#6 sev=medium blast=leaf effort=S verdict=actionable - `list_returns_snapshot_revision_and_watch_refuses_until_wired` compares the wire snapshot's epoch-seconds half against `SystemTime::now()` taken after the list round-trip, so a second boundary crossing between the two instants flakes the test - fix: assert the mapping with a one-second tolerance or inject the clock - [packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src/manager_backend/tests.rs:1460, packages/d2b-resource-api/src/manager_backend/tests.rs:1461] + evidence: seed `#\[test\]|#\[tokio::test\]` = 57 hits, `assert_eq!\(|assert_ne!\(|assert!\(` = 242, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the compared values are read at different instants (the manager computes `snapshot_revision` before the awaits that precede the assertion), violating the determinism rule + +## Coverage +- idiom: 2 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 2/0/0; the two validate_* hits are boundary admission gates on untrusted wire bytes, admission.rs:456,483) +- api: clean (seeds ran: 81/0/13; deliberate private-field surface with compile_fail doctests, lib.rs re-export arms are the house pattern, no Arc/Rc/Box/RefCell in pub signatures) +- err: clean (seeds ran: 379/7/17/3; production hits are all card-listed false-positive classes, panics confined to tests, error enums carry Display plus Error) +- serde: clean (seeds ran: 0/0/0/30; the two production from_slice parses are the typed admission boundary, the rest is test payloads) +- obs: clean (seeds ran: 0/0/0/0; the log:: seed only matched catalog:: substrings, tracing lives in part 1's manager_backend.rs:194) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 2/5/0/0; all Mutex/RwLock sites carry the sanctioned synchronous-path allow, thread::spawn confined to the sanctioned cfg(test) linearization test) +- async: clean (seeds ran: 77/0/0/13; every hit is the sanctioned test harness in manager_backend/tests.rs, production here is deliberately synchronous) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest sets unsafe_code = "forbid") +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: clean (seeds ran: 1/0/0/0; the single hit is the test-only impl_has_error! helper, a card-listed false positive) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md new file mode 100644 index 000000000..84565497c --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md @@ -0,0 +1,77 @@ +# d2b-resource-client - d2b-resource-client +Baseline: 6ebdd4cec | LOC audited: 4839 (excl. src/generated/**, no tests/ dir, no build.rs) | modules: whole crate (call, client, dispatch, error, lib, process_attach, target, zone_client) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (whole crate) + +## idiom +- d2b-resource-client#1 sev=low blast=leaf effort=S verdict=actionable - two byte-identical private async helpers each exist twice in this crate: `await_with_cancellation` (zone_client vs process_attach) and `classify_session_error`/`classify_attach_error` - fix: hoist both into one shared pub(crate) module (e.g., call.rs) and have zone_client.rs and process_attach.rs call the single copies - [packages/d2b-resource-client/src/zone_client.rs:914, packages/d2b-resource-client/src/process_attach.rs:764, packages/d2b-resource-client/src/zone_client.rs:936, packages/d2b-resource-client/src/process_attach.rs:785] + evidence: census: `async fn await_with_cancellation` over src = 2 hits; `fn classify_\w+_error` over src = 2 hits +- d2b-resource-client#2 sev=low blast=leaf effort=S verdict=actionable - `GuestControlEndpoint::endpoint_uid` is an exact duplicate of `uid()` (same field, same doc sentence; a test pins the equivalence at zone_client.rs:1067) - fix: keep one accessor (e.g., `uid()`) and drop or deprecate the other - [packages/d2b-resource-client/src/zone_client.rs:194, packages/d2b-resource-client/src/zone_client.rs:199, packages/d2b-resource-client/src/zone_client.rs:1067] + evidence: static read: both return `&self.uid`; census: `endpoint_uid` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 22 hits (live, so removal touches callers) + +## own +- d2b-resource-client#3 sev=low blast=family effort=S verdict=actionable - by-value `resource_ref()` accessors clone a `ResourceRef` (target.rs:155, 279, 407) and `ResolvedTarget::matches_assignment` clones just to compare (`self.resource_ref().as_ref() == Some(reference)`, target.rs:424) - fix: give the in-crate comparison a borrow-returning variant (`Option<&ResourceRef>`) and consider tightening the pub accessors later, migrating about 15 caller files - [packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs:279, packages/d2b-resource-client/src/target.rs:407, packages/d2b-resource-client/src/target.rs:424] + evidence: census: `\.resource_ref\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 21 hits across 15 files; seed `\.clone\(\)` = 74 (remaining clones explainable: waker registry, per-attempt payload, by-value trait seams) + +## type +- d2b-resource-client#4 sev=low blast=leaf effort=S verdict=actionable - `MetadataInput::validate_lifetime` (call.rs:168) is a re-validation of the invariant `MetadataInput::new` already enforces at construction (private fields); `CallDriver::new` re-checks it (dispatch.rs:189) where it cannot fail - fix: drop the `validate_lifetime()?` re-check at CallDriver::new (or convert to a debug_assert) - [packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs:189] + evidence: seed `fn validate_\w+|fn check_\w+` = 2 (validate_lifetime, validate_for); census: `validate_lifetime` over packages = 3 hits (definition plus the two calls: call.rs:103, dispatch.rs:189) + +## api +- d2b-resource-client#5 sev=medium blast=leaf effort=M verdict=actionable - eight zero-caller pub items form dead surface: `ZonePeerIdentity::from_enrolled_peer` (zone_client.rs:83), `ZoneSocketConnector::local_daemon_endpoint_identity` (361), `ZoneClient::scoped_query` (635), `scoped_child_query` (646), `call_resource` (703), `ProcessAttachTarget::from_target` (process_attach.rs:125), `configured_launcher_from_target` (132), `ProcessAttachClient::attach_local` (721) - fix: remove or demote to `pub(crate)` (and, if kept, merge the two from-target constructors into one) - [packages/d2b-resource-client/src/zone_client.rs:83, packages/d2b-resource-client/src/zone_client.rs:361, packages/d2b-resource-client/src/zone_client.rs:635, packages/d2b-resource-client/src/zone_client.rs:646, packages/d2b-resource-client/src/zone_client.rs:703, packages/d2b-resource-client/src/process_attach.rs:125, packages/d2b-resource-client/src/process_attach.rs:132, packages/d2b-resource-client/src/process_attach.rs:721] + evidence: census: each name over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (its own definition); the only seam consumer of the call path is `d2b/src/context.rs` via `call_connected`, not `call_resource` + +## err +- d2b-resource-client#6 sev=low blast=leaf effort=S verdict=actionable - three reflexive `Mutex::lock().unwrap()` sites in the cancellation waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) handle poisoning by panic instead of an explicit choice - fix: use `expect("waker registry lock is not poisoned: no user code runs under it")` or `into_inner()` with the same written reason - [packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309, packages/d2b-resource-client/src/call.rs:335] + evidence: seed `\.unwrap\(\)|\.expect\(` = 92 (89 in #[cfg(test)]; non-test hits are exactly call.rs:281, 309, 335, all carrying the sanctioned synchronous-path allows); `let _ = |\.ok\(\);` = 6 (all deliberate best-effort cancel/close forwards on the cancellation path) + +## serde +- clean: seeds ran: 0/0/0/4 (`serde_json::from_|serde_json::to_` hits are the frame codecs at process_attach.rs:489, 497 plus 2 test sites); checked: frames are contract-owned (`d2b-contracts-control`) and codec errors map to `ClientError::ContractViolation`; no serde attributes live in this crate + +## obs +- N/A: (seeds: 0/0/0/0 all zero; Cargo.toml declares no `tracing`/`log` dependency, so the lens's applicability condition fails) + +## docs +- d2b-resource-client#7 sev=low blast=leaf effort=L verdict=actionable - 50 Result-returning pub items carry no `# Errors` section (zero `# Examples|Errors|Panics|Safety` sections anywhere in the crate), so callers must infer failure conditions from prose - fix: add `# Errors` to the public Result-returning entry points (MetadataInput::new, RetryPolicy::new, CallDriver::new, ZoneClient::connect, ZoneClient::call_connected, ZoneClient::scoped_commit_batch, ProcessAttachClient::attach) - [packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:131, packages/d2b-resource-client/src/zone_client.rs:711, packages/d2b-resource-client/src/process_attach.rs:648] + evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type) ` = 194; `/// # (Examples|Errors|Panics|Safety)` = 0; `-> Result<` = 50 + +## perf +- clean: seeds ran: 19/12/0 (`format!(`, `Vec::new(|VecDeque::new(|HashMap::new(|BTreeMap::new(`, `\.to_string(`); all 19 format! sites and all 12 Vec::new sites are in #[cfg(test)] fixtures or diagnostic asserts; no allocation sits in a non-test loop (`payload.clone()` per bounded retry attempt is an explainable by-value-trait cost); static (unmeasured) + +## conc +- d2b-resource-client#8 sev=low blast=leaf effort=S verdict=actionable - `ResourceWatch` models the open/closing/closed stream state with two `Arc` fields (state, closing; zone_client.rs:510-513) where the sibling `ProcessAttachStream` already uses the single `AtomicU8` three-state machine (STREAM_OPEN/CLOSING/CLOSED, process_attach.rs:409-412) - fix: align ResourceWatch onto the same single-atomic state enum - [packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone_client.rs:512, packages/d2b-resource-client/src/zone_client.rs:513, packages/d2b-resource-client/src/process_attach.rs:409, packages/d2b-resource-client/src/process_attach.rs:412] + evidence: seeds: `Atomic\w+|Ordering::` = 47; `\bMutex<|\bRwLock<` = 6 (1 non-test waker registry lock, 5 test fakes); ordering pairs are correct (Relaxed counter, Acquire/Release/AcqRel flags), no ordering misfit found + +## async +- clean: seeds ran: 80/1/20/0 (`async fn|\.await` = 80; `tokio::spawn` family = 1, a test at process_attach.rs:1118; `tokio::sync::(Mutex|RwLock|Notify)` = 20, all #[cfg(test)] fakes; `Runtime::block_on` = 0); checked: `retry_backoff` refuses without a caller runtime rather than panicking, and cancel-forward-on-cancel is best-effort with no swallowed failures beyond intended cleanup + +## unsafe +- N/A: (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`, so seed 4 alone does not make the lens applicable) + +## ffi +- N/A: (seeds: 0/0/0/0 all zero) + +## macro +- N/A: (seeds: 0/0/0/0 all zero) + +## test +- d2b-resource-client#9 sev=medium blast=leaf effort=M verdict=actionable - the core resource-call execution path has no test: no test drives `call_connected`/`call_resource`/`scoped_commit_batch`, so the `execute_resource_call` retry loop, its retry-after-delay backoff branch, scoped-commit admission, and cancel-forward are only exercised indirectly by attach tests - fix: add a fake `ConnectedZoneSession` test covering `call_with_timeout` success, retry-after-delay, cancel-forward, and a scoped commit path - [packages/d2b-resource-client/src/zone_client.rs:703, packages/d2b-resource-client/src/zone_client.rs:711, packages/d2b-resource-client/src/zone_client.rs:755, packages/d2b-resource-client/src/zone_client.rs:858] + evidence: seeds: `#\[test\]|#\[tokio::test\]` = 34; `assert_eq!\(|assert_ne!\(|assert!\(` = 144; census: `call_connected` over tests/ = 0 hits (the only external caller is d2b/src/context.rs:1622, not a test) +- d2b-resource-client#10 sev=low blast=leaf effort=S verdict=actionable - the close/cancel error-rollback paths are untested: `ProcessAttachStream::close`/`cancel` and `ResourceWatch::close` restore the open state when the transport close errors, but no test injects that failure - fix: add failure-injection tests asserting the state rolls back to open and a second close retries - [packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/process_attach.rs:541, packages/d2b-resource-client/src/zone_client.rs:567] + evidence: static read: close()/cancel() error arms at process_attach.rs:534 and zone_client.rs:580 restore state; seed `#\[test\]` = 34 sites, none names a close/cancel failure injection + +## Coverage +- idiom: 2 findings +- own: 1 finding +- type: 1 finding +- api: 1 finding +- err: 1 finding +- serde: clean (seeds ran: 0/0/0/4) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: 1 finding +- perf: clean (seeds ran: 19/12/0) +- conc: 1 finding +- async: clean (seeds ran: 80/1/20/0) +- unsafe: N/A (seeds: 0/0/0 all zero; forbid manifest) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 2 findings \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md new file mode 100644 index 000000000..057e5e608 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md @@ -0,0 +1,83 @@ +# d2b-resource-compiler - d2b-resource-compiler +Baseline: 6ebdd4cec | LOC audited: 7461 (excl. src/generated/, which is absent; src 5514 + tests 1947) | modules: whole crate (src/lib.rs, src/linux.rs, src/main.rs, tests/cli.rs, tests/phase2.rs) +Lenses: idiom,own,type,api,err,serde,obs,docs,perf,conc,async,unsafe,ffi,macro,test | Partitions: n/a (single-part lane) + +## idiom +- d2b-resource-compiler#1 sev=medium blast=leaf effort=S verdict=actionable - main.rs hand-rolls identical output-sanitizer helpers already in lib.rs (safe_token/bound_ascii duplicate sanitize_token/bound_message body-for-body) - fix: expose lib.rs sanitize_token/bound_message as pub(crate) helpers (dropping safe_label indirection if unneeded) and replace main.rs safe_token/bound_ascii with calls to the shared pair - [packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:2438, packages/d2b-resource-compiler/src/main.rs:2531, packages/d2b-resource-compiler/src/main.rs:2545] + evidence: idiom seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) = 11 hits; both helper pairs rebuild strings char-by-char with the identical filter/ASCII-bound rules +- d2b-resource-compiler#2 sev=low blast=leaf effort=S verdict=actionable - sanitize_token's char-loop filter is expressible as an iterator pipeline - fix: `value.chars().filter(|character| (character.is_ascii_graphic() && *character != '/' && *character != '\\') || *character == ' ').collect::()` - [packages/d2b-resource-compiler/src/lib.rs:2402] + evidence: idiom seed 3 hit at lib.rs:2402 (the canonical copy named by #1) +- d2b-resource-compiler#3 sev=low blast=leaf effort=S verdict=actionable - check_metadata_closure's unexpected-layout-entries accumulation could be a filter_map+collect pipeline - fix: `let unexpected: Vec = entries.into_iter().filter_map(|entry_name| match entry_name.to_str() { Some(name) if expected.contains(name) => None, Some(name) => Some(truncate_entry(name)), None => Some("".to_owned()) }).collect();` (kept the trailing sort* - [packages/d2b-resource-compiler/src/lib.rs:1724] + evidence: idiom seed 3 hit at lib.rs:1724 +- d2b-resource-compiler#4 sev=low blast=leaf effort=S verdict=actionable - executable-set difference builders are two push-loops a chain can express in one collect - fix: `let difference: Vec = names.difference(&declared_names).map(|name| format!("bin={}", truncate_entry(name)).chain(declared_names.difference(&names).map(|name| format!("manifest={}", truncate_entry(name)).collect();` - [packages/d2b-resource-compiler/src/lib.rs:1913] + evidence: idiom seed 3 hit at lib.rs:1913 +- clean: seeds ran: 2/0/11; the two index-loop hits are test-only depth builders (main.rs:2335, a phase2.rs fixture; no hand-written derive-class impls; the remaining accumulation sites are loops with side effects or early exits where the skill's own guidance prefers a plain for loop + +## own +- d2b-resource-compiler#5 sev=low blast=leaf effort=S verdict=actionable - SchemaCache uses RefCell for a lazy schema cache though the only two call sites could take `&mut self` - fix: change `fn schema(&self,...)` to `fn schema(&mut self,...)`, drop the RefCell holding the cache in plain `BTreeMap` field, and mark `let mut schema_cache` in validate_resources - [packages/d2b-resource-compiler/src/main.rs:1148, packages/d2b-resource-compiler/src/main.rs:1631, packages/d2b-resource-compiler/src/main.rs:818, packages/d2b-resource-compiler/src/main.rs:846] + evidence: own seed 3 (`Rc<|RefCell<|Arc, build: impl FnOnce(oneshot::Sender>) -> ResourceManagerMsg)` and call it from both impls - [packages/d2b-resource-runtime/src/manager.rs:1419, packages/d2b-resource-runtime/src/manager.rs:1508] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (test helper, not a finding); the two rpc bodies read identical at the cited lines +- clean: seeds ran: 9 (`for \w+ in 0\.\.`, all in test polling loops), 2 (hand-written impls, both flagged), 1 (`let mut ... = Vec::new()`, test helper); no index loops or statement-style accumulation in production code + +## own +- d2b-resource-runtime-p1#3 sev=low blast=leaf effort=S verdict=actionable - `ResourceView::observed_status` clones the whole `Option` (which can carry a `DriverFailure` with comparison vectors) before the generation filter, so a stale status is copied and then discarded - fix: `self.status.as_ref().filter(|_| self.status_generation == Some(self.generation)).cloned()` - [packages/d2b-resource-runtime/src/manager.rs:205] + evidence: seed `\.clone\(\)` = 232 hits (174 in manager.rs); this site clones only to filter by reference +- d2b-resource-runtime-p1#4 sev=low blast=leaf effort=S verdict=actionable - `ResourceActor::pre_start` clones `args.row` twice (once into the context, once into `state.row`) where one move and one clone suffice - fix: move `args.row` into `ResourceActorState.row` and clone it only for `ResourceContext::new` - [packages/d2b-resource-runtime/src/resource.rs:714, packages/d2b-resource-runtime/src/resource.rs:732] + evidence: seed `\.clone\(\)` = 232 hits; both cited clones are of the same `StoredDesiredResource` in one function +- d2b-resource-runtime-p1#5 sev=low blast=leaf effort=S verdict=actionable - `spec_object` returns `Ok(spec.clone())` on an owned `serde_json::Value` where the move `Ok(spec)` is legal (the value is not used after) - fix: drop the `.clone()` - [packages/d2b-resource-runtime/src/metadata.rs:191] + evidence: seed `\.clone\(\)` = 232 hits; the cited clone copies the whole decoded spec JSON on every metadata validate pass +- clean: seeds ran: 232 (`\.clone\(\)`), 57 (`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`), 0 (`Rc<|RefCell<|Arc Result<`); module docs exist for all eight modules, and every public type, enum variant, and constant except the flagged items carries a first-sentence doc + +## perf +- d2b-resource-runtime-p1#10 sev=low blast=leaf effort=S verdict=actionable - `reconcile_children`'s obsolete scan clones every owned `StoredDesiredResource` row (spec and metadata byte vectors included) into a `Vec` when only the keys are needed to drive `remove_internal` - fix: collect `row.key.clone()` only, or iterate `state.rows` by reference and call `remove_internal(&subject, &child.key)` - [packages/d2b-resource-runtime/src/manager.rs:1390] + evidence: static (unmeasured); seed `Vec::new\(\)|HashMap::new\(\)` = 33 hits; the cited `.cloned().collect()` copies full rows per reconcile pass over a parent's owned set +- clean: seeds ran: 13 (`format!`), 33 (`Vec::new\(\)|HashMap::new\(\)`), 25 (`\.to_string\(\)`); the `format!` sites are error paths and the log-line/wire renderers (cold), the collection literals are one-shot state construction, and no allocation sits in a measured hot path + +## conc +- d2b-resource-runtime-p1#11 sev=low blast=leaf effort=S verdict=actionable - `ActorTimers.next` is a single-owner counter (ractor serializes the actor's handlers) but increments with `Ordering::SeqCst`, the strongest ordering, where `Relaxed` is the weakest correct one for a counter nobody synchronises on - fix: `self.next.fetch_add(1, Ordering::Relaxed)` - [packages/d2b-resource-runtime/src/resource.rs:247] + evidence: seed `Atomic\w+|Ordering::` = 151 hits (the rest are test atomics and the correct Acquire/Release gate pair in test_support); the cited counter is only touched by the actor thread +- clean: seeds ran: 0 (`std::thread::|thread::spawn|thread::scope`), 10 (`\bMutex<|\bRwLock<`), 151 (`Atomic\w+|Ordering::`), 0 (`thread_local!|unsafe impl (Send|Sync) for`); the production `Mutex` is the documented plan-U4 `tokio::sync::Mutex` reached via non-blocking `try_lock` from the sync trait surface (resource.rs:249-252), and `ManualClock` uses `Relaxed` correctly + +## async +- clean: seeds ran: 642 (`async fn|async move|\.await`), 5 (`tokio::spawn|spawn_blocking|JoinSet|select!|join!`), 5 (`tokio::sync::(Mutex|RwLock|Notify)`), 44 (`#[tokio::(main|test)]|Runtime::block_on`); no blocking call sits in an async context (the store and target calls are async, the only `std::fs` use is in tests), no guard is held across `.await`, the `Box::pin` recursion in `remove_internal`/`retire_row` is depth-bounded by the ownership chain with crash-resume covered by tests, the unbounded effect/watch channels are the documented KTD12 mailbox-freeing design, and the two production `.expect` receiver takes name held-in-state invariants + +## unsafe +- N/A: seeds: 0/0/0/0 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`, `unsafe_code`); the crate inherits workspace lints with `unsafe_code = "forbid"` (root Cargo.toml `[workspace.lints.rust]`), matching U1 (d) 8's enumerated set + +## ffi +- N/A: seeds: 0 all zero (`extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char`); no foreign boundary exists in this crate + +## macro +- N/A: seeds: 0 all zero (`macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned`); no macros defined or consumed beyond std + +## test +- d2b-resource-runtime-p1#12 sev=high blast=leaf effort=S verdict=actionable - `display_shows_epoch_and_sequence` asserts `rendered.contains("[PHONE]")` on the rendering `e1728000000+42`, an assertion that cannot pass, so the test fails at HEAD (route review-pass; read-only audit) - fix: delete the stray `[PHONE]` assertion (the epoch/sequence assertions on the same line already cover the contract) - [packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revision.rs:71] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 281 hits; the Display impl at revision.rs:71-75 renders `e{}+{}` with no redaction, and `[PHONE]` appears nowhere else in packages/ (grep over packages/ = 0 hits) +- d2b-resource-runtime-p1#13 sev=low blast=leaf effort=S verdict=actionable - `wire_budget_bounds_sequence_for_u32_low_word` asserts `WIRE_SEQUENCE_BUDGET == 1 << 32`, restating the constant's own definition (revision.rs:41), so it cannot fail meaningfully - fix: delete it or assert a behavioral consequence (e.g. that a sequence at the budget still packs into the u32 low word of the U8 mapping) - [packages/d2b-resource-runtime/src/revision.rs:182] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 281 hits; the expected value is the same literal the const is defined from (revision.rs:41), the skill's same-logic expectation rule +- d2b-resource-runtime-p1#14 sev=low blast=leaf effort=S verdict=actionable - the lib.rs `modules_resolve` smoke test asserts each `MODULE_NAME` const against its own literal, pinning source text with no behavioral value (the A5 not-applied row, docs/explanation/over-engineering-audit-record.md:458, covers the consts and this test; the site still matches the record) - fix: fold into the A5 decision (delete both, or keep only as a compile-resolution check without the value assertions) - [packages/d2b-resource-runtime/src/lib.rs:66] + evidence: seed `#\[test\]|#\[tokio::test\]` = 64 hits; the test asserts 13 const-vs-literal pairs that cannot diverge from the same-file definitions +- clean: seeds ran: 64 (`#\[test\]|#\[tokio::test\]`), 281 (`assert_eq!|assert_ne!|assert!`), 0 (`proptest!|insta::assert|rstest`), 1 (`#\[ignore`); the manager/actor/metadata/provider suites are behavior-asserting and deterministic (paused clocks, causal barriers instead of sleeps, documented ignores for the reference-doc regenerator at error.rs:1009), and the three flagged tests are the exceptions + +## Coverage +- idiom: 2 finding(s) +- own: 3 finding(s) +- type: clean (seeds ran: 2/0/0) +- api: clean (seeds ran: 145 pub items inspected; Arc fields are shared-ownership with cited call sites) +- err: 1 finding(s) +- serde: clean (seeds ran: 4) +- obs: clean (seeds ran: 0/2) +- docs: 3 finding(s) +- perf: 1 finding(s) +- conc: 1 finding(s) +- async: clean (seeds ran: 642/5/5/44) +- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace `unsafe_code = "forbid"` inherited) +- ffi: N/A (seeds: 0 all zero; no foreign boundary) +- macro: N/A (seeds: 0 all zero; no macros) +- test: 3 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md new file mode 100644 index 000000000..806b6b8af --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md @@ -0,0 +1,90 @@ +# d2b-resource-runtime-p2 - d2b-resource-runtime - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 7756 (excl. src/generated/**) | modules: context, target, guest_target, spec_store, watch, driver, identity +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: src/context.rs, src/target.rs, src/guest_target.rs, src/spec_store.rs, src/watch.rs, src/driver.rs, src/identity.rs + +## idiom +- d2b-resource-runtime-p2#1 sev=low blast=leaf effort=S verdict=actionable - two hand-written comparator closures where the sort_by_key form is the idiomatic one - fix: replace sort_by(|l, r| identity_order(l).cmp(&identity_order(r))) with sort_by_key(identity_order) in TargetDirectory::assignments_for and GuestTargetRuntime::instances - [packages/d2b-resource-runtime/src/target.rs:732, packages/d2b-resource-runtime/src/guest_target.rs:514] + evidence: seed `for \w+ in 0\.\.` = 7 hits (6 in test modules); static read of both sort sites. +- d2b-resource-runtime-p2#2 sev=low blast=leaf effort=S verdict=actionable - hand-written impl Default for TargetDirectory where a derive yields the identical value - fix: replace the impl with #[derive(Default)] on TargetDirectory (DirectoryState already derives Default and Arc>: Default) - [packages/d2b-resource-runtime/src/target.rs:581-584] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits (target.rs:581, watch.rs:147); the watch.rs:147 Default is not derivable (constant defaults), target.rs:581 is. +- d2b-resource-runtime-p2#3 sev=low blast=leaf effort=S verdict=actionable - inherent ResourceProvenance::from_str shadows the FromStr trait name - fix: implement std::str::FromStr for ResourceProvenance and parse at the single use site in row_from - [packages/d2b-resource-runtime/src/spec_store.rs:83-88, packages/d2b-resource-runtime/src/spec_store.rs:556] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits; static read of spec_store.rs:83-88. + +## own +- d2b-resource-runtime-p2#4 sev=low blast=leaf effort=S verdict=actionable - insert_new clones the entire row (spec and metadata Vecs included) only to stamp generation/deleting/created_at - fix: take row: StoredDesiredResource by value in insert_new and destructure it, dropping `..row.clone()`; the caller at spec_store.rs:346 does not use row afterwards - [packages/d2b-resource-runtime/src/spec_store.rs:520-541] + evidence: seed `\.clone\(\)` = 86 hits in lane; this site copies both envelope byte vectors on every ensure-create. +- d2b-resource-runtime-p2#5 sev=low blast=leaf effort=S verdict=actionable - SpecStore::list clones the selector's zone/type_name/owner_uid fields to bind SQL params - fix: bind borrowed forms (selector.zone.as_deref(), selector.type_name.as_deref(), selector.owner_uid.as_deref()), which rusqlite params accept - [packages/d2b-resource-runtime/src/spec_store.rs:596-598] + evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 36 hits in lane; the three clones at spec_store.rs:596-598 are avoidable. +- d2b-resource-runtime-p2#6 sev=low blast=leaf effort=S verdict=actionable - TargetDirectory::assign clones the assignment twice (once into the map, once for the return value) - fix: insert the owned assignment and clone from the map for the return, halving the copies of the 3-string ResourceKey and the resolved handle - [packages/d2b-resource-runtime/src/target.rs:655, packages/d2b-resource-runtime/src/target.rs:663] + evidence: seed `\.clone\(\)` = 86 hits in lane; assign() runs on the daemon spawn path (per resource spawn). +- d2b-resource-runtime-p2#7 sev=low blast=leaf effort=S verdict=actionable - json_object clones every member Value into the map although every caller constructs the member array inline - fix: take members: impl IntoIterator and move values into the map - [packages/d2b-resource-runtime/src/guest_target.rs:1004-1009] + evidence: seed `\.clone\(\)` = 86 hits in lane; this clone runs on every target-control frame encode (guest_target.rs:820-863). + +## type +- clean: seeds `fn validate_\w+|fn check_\w+`, `is_\w+: bool|\w+_flag: bool`, `(mode|kind|state): String` = 0/0/0 hits; structs and enums audited by read; WatchCondition::Custom is a documented not-implemented extension point (the recorded false-positive class), and the wire rows (StoredDesiredResource, ResourceKey) are schema-mirroring shapes. + +## api +- d2b-resource-runtime-p2#8 sev=medium blast=family effort=M verdict=actionable - ResourceContext::new accepts `_target: TargetHandle` and discards it; every caller supplies a value that is silently dropped - fix: remove the parameter and update the 21 call sites (provider family, resource.rs, metadata.rs, context.rs test_support), or store it and expose ResourceContext::target() per U4's "coarse handle a driver context exposes" - [packages/d2b-resource-runtime/src/context.rs:364-366] + evidence: census: `ResourceContext::new` over packages/ = 22 hits (definition plus 21 call sites, all passing TargetHandle::Host except resource.rs:558). +- d2b-resource-runtime-p2#9 sev=medium blast=leaf effort=S verdict=actionable - TargetBinding::directory() returns &Arc (internals leak in a public signature) and has zero callers - fix: remove the accessor, or return &TargetDirectory if a caller appears - [packages/d2b-resource-runtime/src/target.rs:491-493] + evidence: census: `\.directory\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both d2b-audit's own writer.directory() (a different type); 0 hits for TargetBinding. +- d2b-resource-runtime-p2#10 sev=low blast=leaf effort=S verdict=actionable - GuestTargetRuntime::reference() returns TargetRef by value (clones the name String) and has zero callers - fix: remove the accessor, or return &TargetRef - [packages/d2b-resource-runtime/src/guest_target.rs:460-462] + evidence: census: `\.reference\(\)` over the workspace = hits only on GuestTargetHandle::reference (target.rs) and d2bd row.reference() (foundation_seed.rs); 0 hits for GuestTargetRuntime::reference. + +## err +- d2b-resource-runtime-p2#11 sev=medium blast=leaf effort=S verdict=actionable - row_from silently substitutes [0; 16] when a stored uid or owner_uid column is not exactly 16 bytes, giving a corrupt row a zero identity that collides with every other zero-uid row - fix: return a typed error (a new SpecStoreError::CorruptRow { zone, type_name, name } variant) instead of try_into().unwrap_or([0; 16]) - [packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spec_store.rs:555] + evidence: seed `\.unwrap\(\)|\.expect\(` = 96 hits in lane, 8 non-test, all named invariants (OnceCell cache, in-transaction row presence, literally-built JSON, u64 sequence overflow); the row_from substitution is not seed-caught (unwrap_or) and was found by static read. +- clean: seed `let _ = |\.ok\(\);` = 23 hits, all deliberate best-effort cleanup or test stubs (reply.send to a dropped caller, ROLLBACK on error, permission tightening, join); seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 21 hits, all in test modules; seed `enum \w*Error` = 3 (TargetError, SpecStoreError, GuestTargetError), each a closed internal taxonomy with a stable Display code. + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 8 hits, all the target-control frame encode/decode (guest_target.rs:823, 829, 863, 869); the hand-rolled Value walking is a live protocol admission gate mapping every failure to ProtocolMismatch, the recorded refusal class for hand-written admission gates, and the frame shape is pinned by the guest/host contract; the two expects on literally-built JSON are the recorded false-positive class. + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0 in this partition; the crate's tracing use lives in the part 1 files (manager.rs, resource.rs). + +## docs +- d2b-resource-runtime-p2#12 sev=low blast=leaf effort=S verdict=actionable - TargetControlAssignment's five methods (new, source, source_uid, assignment_generation, session_generation) are the only wire-carried type accessors without doc comments while sibling wire types (TargetResourceInstance, GuestRealizeRequest, TargetControlFrame) document every method - fix: add one-line docs to each - [packages/d2b-resource-runtime/src/guest_target.rs:205-228] + evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 148 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 45; static read of guest_target.rs:204-229. +- d2b-resource-runtime-p2#13 sev=low blast=leaf effort=S verdict=actionable - constructor and accessor doc gaps on public items - fix: add one-line docs to ResourceTypeName::new/as_str, ResourceKey::new, ResourceProvenance::as_str, GuestTargetRuntime::new, TargetBinding::new, GuestTargetHandle::is_bound, SpecStore::path - [packages/d2b-resource-runtime/src/identity.rs:20, packages/d2b-resource-runtime/src/identity.rs:24, packages/d2b-resource-runtime/src/spec_store.rs:61, packages/d2b-resource-runtime/src/spec_store.rs:75, packages/d2b-resource-runtime/src/spec_store.rs:761, packages/d2b-resource-runtime/src/guest_target.rs:449, packages/d2b-resource-runtime/src/target.rs:486, packages/d2b-resource-runtime/src/target.rs:196] + evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 148 hits; static read of each cited site confirms no doc comment; the crate otherwise documents its public surface thoroughly (no missing_docs lint is enabled anywhere). + +## perf +- d2b-resource-runtime-p2#14 sev=low blast=leaf effort=S verdict=actionable - hex rendering allocates a fresh String per byte via format! inside the loop at two sites - fix: write!(&mut rendered, "{byte:02x}") with use std::fmt::Write into the pre-sized String - [packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/guest_target.rs:1212] + evidence: seed `format!\(` = 15 hits in lane; the two loop sites are the only per-iteration allocations (target_local_spec_digest and hex_encode, both on the realize/frame wire path); static (unmeasured). + +## conc +- d2b-resource-runtime-p2#15 sev=low blast=leaf effort=S verdict=actionable - parking_lot (banned outright by clippy.toml:40-43, plan KD3, except the R4 worker boundary) is a [dependencies] entry consumed only by #[cfg(test)] code - fix: move parking_lot to [dev-dependencies] or replace the two test uses with std::sync::Mutex - [packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:800, packages/d2b-resource-runtime/src/context.rs:1044] + evidence: census: `parking_lot` over packages/d2b-resource-runtime = 3 hits (manifest plus 2 cfg(test) sites); supply-tagged manifest posture (the workspace-level supply lens is lane X1). +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 1 (the spec-store writer thread, the sanctioned R4 bounded worker with its documented allow), `\bMutex<|\bRwLock<` = 8, `Atomic\w+|Ordering::` = 33, `thread_local!|unsafe impl (Send|Sync) for` = 0; the atomics are Relaxed counters or the documented AcqRel/acquire generation fence in bind_session, and the tokio Mutex + non-blocking try_lock sync surfaces are the documented plan U4 shape. + +## async +- clean: seeds `async fn|async move|\.await` = 150+ hits (tool-truncated), `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 6+ (tool-truncated), `tokio::sync::(Mutex|RwLock|Notify)` = 8, `#\[tokio::(main|test)\]|Runtime::block_on` = 21 (all #[tokio::test]); SpecStore::call is try_send refuse-don't-queue with a documented unbounded reply await (loader_worker doctrine), WatchStream::recv is cancellation-safe (the missed AtomicBool is checked before the biased notify select and re-checked at loop top), no guard is held across an await anywhere (locks are scoped per iteration in adopt/session_authority), and every sync surface uses the documented plan U4 non-blocking try_lock. + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; the crate inherits workspace `unsafe_code = "forbid"` via `[lints] workspace = true` (Cargo.toml:170). + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign boundary. + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0. + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 30+ hits (tool-truncated), `assert_eq!\(|assert_ne!\(|assert!\(` = 60+ hits (tool-truncated), `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the sampled tests assert real contracts with failure messages (watch gap-free LIST->WATCH replay and Missed frontier, spec-store commit-before-return durability and crash survival, driver classification at the erased boundary, target-control generation fencing) and none restates the implementation; no test that cannot fail was found. + +## Coverage +- idiom: 3 finding(s) +- own: 4 finding(s) +- type: clean (seeds ran: 0/0/0) +- api: 3 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 0/0/0/8) +- obs: clean (seeds ran: 0/0/0/0) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: 1 finding(s) +- async: clean (seeds ran: 150+/6+/8/21) +- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace unsafe_code = "forbid") +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 30+/60+/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md new file mode 100644 index 000000000..cab55279a --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md @@ -0,0 +1,72 @@ +# d2b-session-p1 - d2b-session - part 1/2 +Baseline: 6ebdd4cec | LOC audited: 5296 (excl. src/generated/**) | modules: driver, server, handshake, operation, streams, scheduler, cancellation, fragmentation, attachment, metrics, typed_stream +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f): src/driver.rs, src/server.rs, src/handshake.rs, src/operation.rs, src/streams.rs, src/scheduler.rs, src/cancellation.rs, src/fragmentation.rs, src/attachment.rs, src/metrics.rs, src/typed_stream.rs + +## idiom +- clean: seeds ran: 5/0/0. The five `for ... in 0..` hits are bounded rotate scans (`pump_named_stream` driver.rs:1626, `FairScheduler::dequeue` scheduler.rs:222) and test loops (driver.rs:2208, 2261, streams.rs:308); no hand-written `Default`/`From`/`PartialEq`/`Eq`/`Debug`/`Clone`/`Hash` impls, no statement-style `String`/`Vec` accumulation. Hand-written `Debug` impls all redact secrets (repo-sanctioned pattern). + +## own +- clean: seeds ran: 30/14/1. Every clone is explainable: `Cancellation`/`Arc` clones at task and command boundaries (driver.rs:124, 347-350, 501-502, 1539, 1611, 2149; server.rs:45, 70, 254, 317, 527; cancellation.rs:71, 184), `RequestId` clones for registry-plus-command pairs (server.rs:245, 259), `policy.clone()` at the handshake encoding boundary (handshake.rs:112, 171), `offer_bytes.to_vec()` for owned canonical bytes (handshake.rs:134), fragment `bytes.to_vec()` for per-fragment ownership (fragmentation.rs:92); the single `Arc>` is a test fixture (driver.rs:1735). No `Rc`/`RefCell`/`Cow`. + +## type +- d2b-session-p1#1 sev=low blast=leaf effort=S verdict=actionable - `OutboundFrame::channel()` silently falls back to `SESSION_CONTROL` for the constructor-prevented NamedStream-without-stream combination, so an invariant break would misroute a frame to the session control channel with no error - fix: encode the stream inside the class (enum variants `SessionControl`/`TtrpcControl`/`AttachmentControl`/`Named(StreamId, ...)`) or make `channel()` return `Result` and drop the `unwrap_or(SESSION_CONTROL)` fallback - [scheduler.rs:18-21, scheduler.rs:66-68] + evidence: type seeds: validate/check fns 4 hits (all boundary validators - `validate_frame` server.rs:360, `validate_credentials` handshake.rs:365, attachment descriptor validation - not findings); `(mode|kind|state): String` 0 hits; bool-flag 0 hits. The class/stream pairing is the one representable-but-guarded combination; constructors `control()`/`named()` (scheduler.rs:25, 36) already reject the bad pair, making the fallback a silent-wrong-value hazard rather than a live illegal state. + +## api +- d2b-session-p1#2 sev=low blast=leaf effort=S verdict=actionable - `Fragment.header` is a public mutable field on an exported wire-facing struct while `bytes` is private behind `as_bytes()`, so external crates can corrupt the header/bytes pairing (reassembly validates at use, but the surface invites it) - fix: make `header` private and add `pub fn header(&self) -> &FragmentHeader`, keeping construction through `Fragmenter`/`from_parts` - [fragmentation.rs:10-13] + evidence: api seeds: pub items 129 (surface re-exported single-path from lib.rs, house pattern); `pub ... Arc|Rc|Box|RefCell<` 0 hits in signatures except evaluated `Arc` at server.rs:202-206 (call sites d2bd/src/composition.rs:7940, d2b-provider-toolkit/src/server/mod.rs:68 - shared ownership across server task and caller, justified); `pub use` arms only in lib.rs. Census: `Fragment` consumed by engine.rs and d2b-bus/src/session/mod.rs:106 - reads header fields only, so an accessor suffices. + +## err +- clean: seeds ran: 88/40/6/2. All 88 unwrap/expect hits are inside `#[cfg(test)]` modules except `resource_operation`'s `expect("every ApiMethod has one unary ResourceService member")` (operation.rs:182) on the generated catalog invariant (compile-time-known closed `ApiMethod` set - acceptable per card). All 40 `let _ =` sites are deliberate best-effort `reply.send`/`writer.close()` on error paths where the receiver may be gone (driver.rs:567, 596, 862, 872, 992, 1264-1346; server.rs:269, 354; cancellation.rs:103). All 6 panics are test assertions. Error enums `SessionServerError` (server.rs:182) and `AttachmentValidationError` (attachment.rs:23) are small and caller-action-split. + +## serde +- N/A: seeds: 0/0/0/0 all zero; crate crosses no serde wire boundary (canonical binary encodings and protobuf framing instead). + +## obs +- clean: seeds ran: 0/0/0/7. Zero `println!`/`eprintln!`; zero interpolated-message events; all 7 `tracing::` sites use named fields (`error = %error`, `stream_id = ...`, `count = ...` - driver.rs:167, 526, 538; server.rs:270, 324, 331, 348). No secrets in fields; no subscriber installed (library). + +## docs +- d2b-session-p1#3 sev=medium blast=leaf effort=M verdict=actionable - the security-critical handshake module has zero doc comments on its entire pub surface (23 pub items re-exported from lib.rs): wire functions with magic lengths and closed error codes (`x25519_public_key`, `encode_offer`, `negotiate_offer`, `accept_generation_discovery_request`, `decode_generation_discovery_response`, `NoiseHandshake`, `EstablishedHandshake`, `HandshakeCredentials`, `NegotiatedOffer`) carry no first-sentence contract, no `# Errors`, no `# Panics` - fix: add first-sentence docs plus `# Errors` sections naming the `SessionErrorCode` each function returns, and `# Panics` where a step mismatch panics - [handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239, handshake.rs:441] + evidence: docs seeds: pub items 129, `/// # (Examples|Errors|Panics|Safety)` 0 hits, `-> Result<` 124 hits; per-file doc scan: handshake.rs 0 `///` on 23 pub items (worst in lane; driver.rs 20 on 4, typed_stream.rs 11 on 8 show the house pattern exists). Consumers: engine.rs, d2b-bus/src/session/mod.rs:102-156, d2bd, d2bd-runtime, d2b-provider-toolkit - all rely on these functions. +- d2b-session-p1#4 sev=medium blast=leaf effort=M verdict=actionable - the flow-critical state machines `NamedStreamMux`, `FairScheduler`, `Fragmenter`/`Reassembler`, `StreamId`/`StreamPhase`/`StreamEvent`, `OutboundFrame`, `QueueClass` have zero doc comments on 46 pub items (credit accounting, phase transitions, and error codes are non-obvious) - fix: first-sentence docs on each type and pub method, `# Errors` on the Result-returning mutators, and a module doc in each file - [streams.rs:10, streams.rs:77, streams.rs:165, scheduler.rs:18, scheduler.rs:95, fragmentation.rs:38, fragmentation.rs:99] + evidence: docs seeds: pub items 129, `/// # (Examples|Errors|Panics|Safety)` 0 hits; per-file doc scan: streams.rs 0 `///` on 20 pub items, scheduler.rs 0 on 16, fragmentation.rs 0 on 10. These types are the multiplexing/flow-control core consumed by engine.rs and d2b-bus. +- d2b-session-p1#5 sev=low blast=leaf effort=S verdict=actionable - the magic bound `value.len() > 128` in `OperationMember::parse` is undocumented: the reader cannot tell why 128 is the canonical member spelling limit or what happens to longer wire strings - fix: extract `const MAX_MEMBER_SPELLING_LEN: usize = 128;` with a comment naming the bound's purpose (wire-visible admission bound) - [operation.rs:207] + evidence: docs seeds: `/// # (Examples|Errors|Panics|Safety)` 0 hits; the 128 literal is the only undocumented magic value in the lane's validation paths (checked against `valid_identifier` at operation.rs:210). + +## perf +- clean: seeds ran: 0/16/14. Zero `format!` sites; all 16 `Vec::new`/`VecDeque::new`/`BTreeMap::new` are struct constructors or test fixtures (cold); all 14 `to_string`/`to_vec` are error-path logging (driver.rs:524), wire-boundary ownership copies (handshake.rs:134, server.rs:295), or tests. Hot paths are already shaped: `Vec::with_capacity` in `Fragmenter::fragment` (fragmentation.rs:70), `Reassembler::accept` (fragmentation.rs:135), `ttrpc_request_id` (server.rs:381), `NegotiatedOffer::prologue` (handshake.rs:100); `NamedStreamEventQueue::receive_for`'s O(n) scan is bounded by DRIVER_EVENT_CAPACITY 128. static (unmeasured). + +## conc +- clean: seeds ran: 0/0/57/0. No `std::thread` usage; no `unsafe impl Send/Sync`; the 57 atomics/Mutex/Ordering hits are the documented lock-free admission counter (cancellation.rs:18-30, plan U19 comment; Release/Acquire/AcqRel pairs with a written ordering argument), the generation counter `Arc` (driver.rs:109, 189), and test fixtures. `ActiveInboundCalls` (server.rs:30, 224) is a tokio Mutex held per-statement, never across an await. + +## async +- clean: seeds ran: 21. Two dedicated worker tasks (`tokio::spawn(run_writer)` driver.rs:354, `tokio::spawn(run_driver)` driver.rs:361) with bounded channels and `Notify`-armed-before-check waits (cancellation.rs:74-80, matches the clippy.toml replacement vocabulary); no guard held across `.await` (server.rs lock scopes are per-statement); no blocking work inside async contexts; `cancel_and_wait` returns `impl Future + Send + 'static`; `abort_writer_and_wait` cannot hang (oneshot send failure skips the wait, driver.rs:1540-1548); the remaining hits are `#[tokio::test]` and test spawns. + +## unsafe +- N/A: seeds: 0/0/0 all zero; crate declares `#![forbid(unsafe_code)]` (lib.rs:5), no unsafe blocks, fns, or impls in the lane. + +## ffi +- N/A: seeds: 0 all zero; no extern "C", no_mangle, repr(C), CStr/CString, or catch_unwind in the lane. + +## macro +- N/A: seeds: 0 all zero; no macro_rules!, proc-macro, syn/quote, or $crate usage in the lane. + +## test +- clean: seeds ran: 23/53/0/0. Six of the eleven files carry `#[cfg(test)]` modules (driver.rs 11 tests, server.rs 4, operation.rs 3, streams.rs 1, cancellation.rs 1, metrics.rs 1); all are deterministic (Notify-based, `tokio::time::timeout` only for liveness bounds), assert observable behavior (error codes, ordering, capacity semantics, redaction), use table-driven cases with per-case messages (metrics.rs:97-123, operation.rs:339-347), and can fail (e.g. driver.rs:2166-2169 asserts the full-queue rejection path). No `#[ignore]`, no proptest/insta/rstest. tests/noise_vectors.rs and tests/component_session.rs (out of the published partition) differentially exercise handshake.rs against snow's own implementation. + +## Coverage +- idiom: clean (seeds ran: 5/0/0; index loops are bounded rotate/drain patterns) +- own: clean (seeds ran: 30/14/1; every clone/to_owned explainable at a boundary) +- type: 1 finding(s) +- api: 1 finding(s) +- err: clean (seeds ran: 88/40/6/2; only non-test unwrap/expect is the generated-catalog invariant expect at operation.rs:182) +- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no serde wire boundary) +- obs: clean (seeds ran: 0/0/0/7; all tracing events use named fields) +- docs: 3 finding(s) +- perf: clean (seeds ran: 0/16/14; no format!, hot paths pre-sized, static (unmeasured)) +- conc: clean (seeds ran: 0/0/57/0; atomics documented with a written ordering argument) +- async: clean (seeds ran: 21; two worker tasks, no guard across await, no blocking) +- unsafe: N/A (seeds: 0/0/0 all zero; #![forbid(unsafe_code)] at lib.rs:5) +- ffi: N/A (seeds: 0 all zero) +- macro: N/A (seeds: 0 all zero) +- test: clean (seeds ran: 23/53/0/0; deterministic, behavior-asserting, table-driven) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md new file mode 100644 index 000000000..212d25def --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md @@ -0,0 +1,89 @@ +# d2b-session-p2 - d2b-session - part 2/2 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5364 (excl. src/generated/**) | modules: admission.rs, engine.rs, error.rs, client.rs, transport.rs, lifecycle.rs, record.rs, bootstrap.rs, deadline.rs, lib.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f); test lens adds tests/** + +## idiom +- d2b-session-p2#1 sev=low blast=leaf effort=S verdict=actionable - decode_attachment_control walks the descriptor table with an index loop plus manual offset arithmetic where an iterator pipeline fits - fix: replace the `for _ in 0..count` loop with `bytes[3..].chunks_exact(ATTACHMENT_DESCRIPTOR_BYTES).take(usize::from(count)).map(decode_attachment_descriptor).collect::, _>>()` - [engine.rs:1802, engine.rs:1803, engine.rs:1807] + evidence: seed `for \w+ in 0\.\.` = 1 hit; the loop at engine.rs:1803 is the only index loop in the part +- d2b-session-p2#2 sev=low blast=leaf effort=S verdict=actionable - send_authorized_ttrpc re-implements the exact verb allow-list check that validate_ttrpc_permit already encodes - fix: call `validate_ttrpc_permit(&permit, now_tick)?` instead of re-writing the matches! block - [admission.rs:1593, admission.rs:956, admission.rs:958] + evidence: seed `fn validate_\w+` = 7 hits; the Invoke|AuditExport|SupportBundle matches! block appears verbatim at admission.rs:958-962 and admission.rs:1597-1601 + +## own +- d2b-session-p2#3 sev=low blast=family effort=S verdict=actionable - take_authentication and from_verified_adapter clone the whole EndpointPolicy just to build a comparison HandshakeOffer - fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in d2b-contracts-zone-session and call HandshakeOffer::from(policy) - [engine.rs:689, admission.rs:593] + evidence: seed `\.clone\(\)` = 51 hits; both sites are one-shot admission-path clones of a struct holding LimitProfile, TransportBinding, and AttachmentPolicy; all other clones in the part are explainable (spawn boundaries, snapshot copies, Arc clones) + +## type +- d2b-session-p2#4 sev=low blast=leaf effort=S verdict=actionable - stream control is decoded as a raw u8 kind inside a (u8, StreamId, u32) tuple and matched against local constants, so an unknown tag stays representable until the runtime match - fix: introduce a closed StreamControlKind enum with tag()/from_tag() beside the existing AttachmentControl enum - [engine.rs:1702, engine.rs:1295, engine.rs:31] + evidence: seed `fn validate_\w+|fn check_\w+` = 7 hits; STREAM_CLOSE/STREAM_CREDIT/STREAM_RESET constants at engine.rs:31-33 are matched in receive_stream_control at engine.rs:1297-1308; the validate_* hits are boundary checks on wire-derived values, not repeated validation + +## api +- d2b-session-p2#5 sev=low blast=leaf effort=M verdict=actionable - SessionEngine exposes seven establishment constructors, the metrics-taking variants have no production callers, and a public with_metrics builder already exists - fix: drop establish_initiator_with_generation_discovery_and_metrics and establish_responder_with_metrics, keep one metrics-taking path per role, and give establish_responder_with_generation_floor a metrics twin instead of recording into a fresh NoopMetrics - [engine.rs:166, engine.rs:262, engine.rs:416, engine.rs:356, engine.rs:584] + evidence: census: `establish_initiator_with_metrics` over packages/tests/labs = 1 hit (tests/component_session.rs:1243); `establish_responder_with_metrics` = 0 external hits; `establish_initiator_with_generation_discovery_and_metrics` = 0 external hits; seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 155 hits; the generation-floor variant records with Arc::new(NoopMetrics) at engine.rs:406 + +## err +- d2b-session-p2#6 sev=medium blast=leaf effort=S verdict=actionable - OwnedTransportHandle panics via expect on descriptor, into_owned_transport, and close after the handle is consumed, because the Option> keeps the consumed state representable - fix: return Option or Result from into_owned_transport and close, or split the handle into a typestate so double-consume does not compile - [transport.rs:170, transport.rs:178, transport.rs:185, transport.rs:173] + evidence: seed `\.unwrap\(\)|\.expect\(` = 23 hits; the three expects at transport.rs:173,181,188 are the only non-test panic sites on a public API in the part (the other hits are cfg(test-support) helpers and test code) +- d2b-session-p2#7 sev=medium blast=leaf effort=S verdict=actionable - SessionClientBridgeError's Display prints a fixed label and the Error impl has no source(), so the inner SessionError code is lost from the chain when the bridge logs it - fix: implement Error::source() returning Some(&SessionError) for the Session variant, and/or include the code in Display - [client.rs:216, client.rs:224, client.rs:237] + evidence: seed `enum \w*Error` = 3 hits; bridge termination logs at client.rs:60-70 print only the fixed label via %error, so an operator cannot see the underlying SessionErrorCode + +## serde +- N/A: seeds `derive(...Serialize|Deserialize)` / `serde(...)` / `impl .*Deserialize` / `serde_json::from_|to_` all 0 hits; this part crosses no serde boundary (crate-level matrix cell is 0) + +## obs +- clean: seeds ran: 0/0/0/12 - no println/eprintln, no interpolated message-only events, no instrument spans; all tracing::warn!/debug! calls use named fields (error = %error, purpose, service, timeout_ms, minimum_generation), and the redacting Debug impls keep secrets out of fields + +## docs +- d2b-session-p2#8 sev=medium blast=leaf effort=M verdict=actionable - SessionEngine and SessionEvent plus 24 of the engine's pub methods carry no doc comments, leaving the crate's central data plane undocumented - fix: add one-line docs, with # Errors on the Result-returning methods and # Panics where applicable - [engine.rs:38, engine.rs:84, engine.rs:584, engine.rs:677, engine.rs:681, engine.rs:702, engine.rs:722, engine.rs:737, engine.rs:763, engine.rs:772, engine.rs:776, engine.rs:780, engine.rs:784, engine.rs:788, engine.rs:803, engine.rs:812, engine.rs:941, engine.rs:956, engine.rs:971, engine.rs:1037, engine.rs:1056, engine.rs:1448] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 155 hits; awk scan of engine.rs counts 24 pub methods with no preceding /// (missing_docs is not enabled; this is a proposal only) +- d2b-session-p2#9 sev=medium blast=leaf effort=S verdict=actionable - the whole public surface of lifecycle.rs, record.rs, bootstrap.rs, and deadline.rs is undocumented, including non-obvious state machines such as SessionLifecycle::poll_keepalive and begin_reconnect - fix: add item docs with # Errors sections on the Result-returning methods - [lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62, record.rs:107, bootstrap.rs:87, deadline.rs:14] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 155 hits; awk scan counts 10 undocumented pub methods in lifecycle.rs, 5 in record.rs, 5 in bootstrap.rs, 5 in deadline.rs +- d2b-session-p2#10 sev=low blast=leaf effort=S verdict=actionable - the route-binding accessors on AuthenticatedSessionRouteBinding, the SessionError accessors, and the TransportPacket methods are undocumented while their siblings carry docs - fix: add one-line docs to the accessors at the anchors - [admission.rs:1182, admission.rs:1186, admission.rs:1190, admission.rs:1194, admission.rs:1198, admission.rs:1237, admission.rs:1241, admission.rs:1245, admission.rs:1249, admission.rs:1253, admission.rs:1257, error.rs:31, error.rs:47, error.rs:51, error.rs:55, error.rs:116, transport.rs:23, transport.rs:30, transport.rs:34, transport.rs:38, transport.rs:42] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 155 hits; awk scan confirms 11 admission.rs, 5 error.rs, and 5 transport.rs pub items without a preceding /// +- d2b-session-p2#11 sev=low blast=leaf effort=S verdict=actionable - serialized_transport_split's doc claims it exists for engine-only test transports, but production code in d2b-bus and the crate's own driver call it - fix: rewrite the doc to state the serialized-compatibility contract (halves must never be driven concurrently) - [transport.rs:208, transport.rs:212] + evidence: census: `serialized_transport_split` over packages = 6 hits, including d2b-bus/src/session/zone_link.rs:634 and d2b-session/src/driver.rs:456 + +## perf +- d2b-session-p2#12 sev=low blast=leaf effort=S verdict=actionable - unprotect allocates a fresh plaintext buffer sized to the limit and copies the payload out with to_vec on every received record - fix: keep a reusable scratch buffer on RecordProtector and return plaintext.split_off(RECORD_HEADER_LEN) instead of payload.to_vec() - [record.rs:125, record.rs:147] + evidence: static (unmeasured); seed `Vec::new\(\)` = 11 hits; unprotect runs once per protected record on the receive hot path +- d2b-session-p2#13 sev=low blast=leaf effort=S verdict=actionable - flush copies every dequeued logical frame with as_bytes().to_vec() because OutboundFrame only exposes a borrowed view - fix: add OutboundFrame::into_bytes() in scheduler.rs and consume it in flush - [engine.rs:1354, engine.rs:1362, scheduler.rs:72] + evidence: static (unmeasured); seed `Vec::new\(\)` = 11 hits; one copy per logical frame on the send path before fragmentation and encryption +- d2b-session-p2#14 sev=low blast=leaf effort=S verdict=actionable - the replay cache is a VecDeque scanned linearly with contains() on every received record - fix: use a bounded HashSet<[u8; 32]> or document why the 1024-entry linear scan is acceptable - [record.rs:120, record.rs:146] + evidence: static (unmeasured); REPLAY_CACHE_ENTRIES = 1024 at record.rs:12; contains() runs per record before sequence acceptance + +## conc +- d2b-session-p2#15 sev=low blast=leaf effort=S verdict=actionable - AuthenticatedSessionDriver._owner is a std::sync::Mutex that is never locked, serving only as a Sync carrier for the ComponentSessionDriver: Send + Sync bound, with no comment saying so - fix: document the Sync-carrier intent on the field or replace it with a named wrapper type - [admission.rs:756, admission.rs:1666, driver.rs:33] + evidence: seed `\bMutex<` = 3 hits; grep `_owner` over admission.rs = 2 hits (declaration and construction), no lock() or get_mut() call anywhere; the SessionLiveness AtomicBool uses the correct Acquire/Release pair and the transport split uses tokio::sync::Mutex + +## async +- clean: seeds ran: 201/1/1/3 - all handshake and packet-send I/O is wrapped in tokio::time::timeout, the serialized split uses tokio::sync::Mutex (no std guard across awaits), the client bridge uses tokio::spawn plus select! with cancellation, and no blocking call or lock guard crosses an await point in the part + +## unsafe +- N/A: seeds 1-3 all zero (no unsafe blocks, fns, impls, transmute, from_raw, MaybeUninit, or mem::zeroed); seed 4 = 1 hit, the `#![forbid(unsafe_code)]` attribute at lib.rs:6, which alone does not make the lens applicable + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` / `catch_unwind` / `repr\(C\)|repr\(transparent\)` / `CStr|CString|c_char` all 0 hits; no FFI surface in the part + +## macro +- d2b-session-p2#16 sev=low blast=leaf effort=S verdict=actionable - the local admit_try! macro exists only to fuse an early return with a metric record, which a plain helper function plus ? expresses - fix: replace each invocation with `let result = ; admit_or_record(&mut engine, result)?` where admit_or_record records the failure metric and returns the error - [admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643, admission.rs:648, admission.rs:661] + evidence: seed `macro_rules!` = 3 hits; the macro is invoked 5 times inside admit; the other two macro_rules! sites (mutate_session_acceptor_trait!, mutate_authenticated_session_trait!) are cfg-gated impl-generation scaffolding for compile-fail verification and are justified + +## test +- d2b-session-p2#17 sev=low blast=leaf effort=S verdict=actionable - unpolled_cancellation_on_real_driver_reclaims_request_for_reuse spins up to 64 yield_now iterations waiting for the cancellation task to reclaim the request, while its sibling test waits on a Notify - fix: wait on a Notify (or a tokio::time::timeout around a Notify) instead of the fixed spin cap - [tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139] + evidence: seed `#\[test\]|#\[tokio::test\]` = 5 hits in src plus 40 test fns across tests/; the sibling failed_cancellation_delivery test uses send_failure.entered.notified() with a 1s timeout at tests/admission.rs:139-142; no proptest/insta/rstest and no #[ignore] anywhere + +## Coverage +- idiom: 2 finding(s) +- own: 1 finding(s) +- type: 1 finding(s) +- api: 1 finding(s) +- err: 2 finding(s) +- serde: N/A (seeds: 0/0/0/0 all zero; no serde derives, attributes, hand-written Deserialize, or json crossing in this part) +- obs: clean (seeds ran: 0/0/0/12; no println, no interpolated message-only events, all events carry named fields) +- docs: 4 finding(s) +- perf: 3 finding(s) +- conc: 1 finding(s) +- async: clean (seeds ran: 201/1/1/3; timeouts wrap handshake and send I/O, tokio Mutex for the serialized split, no blocking calls or guards across awaits) +- unsafe: N/A (seeds: 0/0/0/1 all zero except the forbid attribute at lib.rs:6; no unsafe code in the part) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: 1 finding(s) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md new file mode 100644 index 000000000..48882cdb2 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md @@ -0,0 +1,72 @@ +# d2b-session-unix - d2b-session-unix +Baseline: 6ebdd4cec | LOC audited: 6663 (excl. src/generated/**) | modules: whole crate +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) + +## idiom +- clean: seeds ran (3/1/8): the index loops at socket.rs:561 (fairness budget) and systemd.rs:176/194 (index needed for `take_custom`/`take_raw_fd`) are legitimate; the hand-written `Clone`/`Default`/`From` impls in subject.rs:61-80 are cfg-gated capability-mutation machinery whose `unreachable!()` bodies are the point (declared in the manifest check-cfg list); the `Vec::new()` accumulation loops are statement-style with per-item error handling and multiple outputs. + +## own +- clean: seeds ran (14/9/14/0): every clone is explainable - Arc clones at split/spawn boundaries (adapter.rs:523/524/627, credit.rs:69/88), cache stores (adapter.rs:234), owned returns (adapter.rs:209/281), CreditBundle copies for split reader/writer (adapter.rs:511/622), test fixtures (adapter.rs:1188, vsock.rs:547/553); the `same_descriptor_binding` clone (adapter.rs:997) is the chosen normalization for a two-field compare and the field-wise alternative is worse; `to_owned`/`to_string` hits are env-string conversions and test payloads; no `Rc`/`RefCell`/`Arc`/`Cow` in production. + +## type +- clean: seeds ran (8/0/0): all `validate_*` hits are boundary parsers the skill endorses - `validate_socket` at construction (socket.rs:637), `validate_descriptor`/`validate_value` as the once-per-attachment admission with a cached result (adapter.rs:258/942), `validate_owned_file*` on received fds (descriptor.rs:569/577), `validate_environment_values` at the env boundary (systemd.rs:201); `VerifiedUnixPeer::validate_transport` (subject.rs:126) is a cheap cross-transport guard on a value that crosses into d2b-session; no boolean-flag soup or stringly-typed state (seeds 2/3 zero). + +## api +- d2b-session-unix#1 sev=medium blast=family effort=S verdict=actionable - `SentPacket::acknowledge(self) {}` is a public no-op whose name promises an acknowledgment; its only behavior is dropping the packet (releasing the credit bundle via `Drop`), which callers cannot tell from the signature - fix: remove the method and let callers drop the packet, or document the drop-semantics contract on the method - [packages/d2b-session-unix/src/socket.rs:176] + evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod)` = 140 hits; census: `\.acknowledge\(\)` over packages/ = 6 hits (adapter.rs:595, d2b-provider-guest-cloud-hypervisor/src/controller_session.rs:145, d2b-provider-test-controller/src/main.rs:208, d2b-provider-toolkit/src/base/fd10.rs:1001/1725, tests/unix_session.rs:819) +- clean: the rest of the surface is deliberate - `pub use` re-export arms in lib.rs (house single-surface pattern), `Arc` callback aliases and `with_observer(Arc)` genuinely shared across split transports (adapter.rs:432/718, cited call sites adapter.rs:627), private fields on all transport/socket types, `UnixTransportObserver` with one required method plus a defaulted `record_errno`. + +## err +- clean: seeds ran (22/5/3/4): production `expect` sites are invariants on internal state (`outbound was initialized`, adapter.rs:888, vsock.rs:158/272) or literally-built values (`compiled bootstrap Provider ref is valid`, zone_admission.rs:35 - the recorded false-positive class); `let _ =` sites are deliberate best-effort closes during shutdown/drain (adapter.rs:900, systemd.rs:196); `unreachable!()` in subject.rs is cfg-gated capability-mutation machinery; the four error enums are family-split with stable kebab-case wire renderings and caller-action mapping fns (`map_transport_error`, `map_validation_error`, `unix_failure_reason`). + +## serde +- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire - no serde dependency in the manifest and no `Deserialize`/`serde_json` anywhere in src. + +## obs +- clean: seeds ran (0/0/0/2): zero `println!`/`eprintln!` in the library; the only two `tracing` events (zone_admission.rs:80/89) are `warn!` with named fields (`provider`, `expected_uid`, `observed_uid`) and no interpolation; no secrets in fields (identity types carry redacting `Debug` impls, e.g. subject.rs:135, pidfd.rs:31); no spans, which is not required at this granularity. + +## docs +- d2b-session-unix#2 sev=medium blast=leaf effort=M verdict=actionable - the exported surface is largely undocumented: the transport, credit, descriptor, pidfd, systemd and vsock types and most of their pub methods carry no doc comment (only `VerifiedUnixPeer`, `ZoneBootstrapIdentity` and a handful of methods do) - fix: add first-sentence contract docs per pub item, starting with `SeqpacketSocket`, `UnixSeqpacketTransport`/`UnixStreamTransport`, `CreditPool`, `PidfdEvidence`, `PeerCredentials`, `ActivatedSeqpacketListener`, `FramedVsockTransport` - [packages/d2b-session-unix/src/socket.rs:190, packages/d2b-session-unix/src/adapter.rs:351, packages/d2b-session-unix/src/credit.rs:22, packages/d2b-session-unix/src/pidfd.rs:9, packages/d2b-session-unix/src/descriptor.rs:23, packages/d2b-session-unix/src/systemd.rs:44, packages/d2b-session-unix/src/vsock.rs:22] + evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 140 hits; seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits; `missing_docs` is not enabled - this is a proposal, not a gate failure +- d2b-session-unix#3 sev=low blast=leaf effort=S verdict=actionable - zero canonical `# Errors` sections exist despite roughly 60 pub `Result`-returning fns whose failure conditions are non-obvious (e.g. `SeqpacketSocket::from_owned` vs `from_parent_prearmed` vs `from_inherited_fd` fail differently) - fix: add `# Errors` sections naming the failing conditions to the pub `Result` fns - [packages/d2b-session-unix/src/socket.rs:202, packages/d2b-session-unix/src/socket.rs:210, packages/d2b-session-unix/src/socket.rs:222, packages/d2b-session-unix/src/adapter.rs:378] + evidence: docs seed 2 = 0 hits vs seed 3 (`-> Result<`) = 60 hits + +## perf +- d2b-session-unix#4 sev=low blast=leaf effort=S verdict=actionable - burst and collector `Vec`s grow from empty with an exact known upper bound, reallocating on the way - fix: `Vec::with_capacity(fairness_budget)` in `recv_burst`/`send_burst` and `Vec::with_capacity(attachments.len())` in `send_packet` - [packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, packages/d2b-session-unix/src/adapter.rs:540] + evidence: static (unmeasured); seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 15 hits; the remaining hits are empty-case defaults (receive_body, outbound None) or test fixtures +- clean: `format!` sites are cold (pidfd.rs:65 /proc path, zone_admission.rs:34 compiled ref) or tests; `to_string` sites are env-string conversions on cold paths; no hashing with attacker-controlled keys; no codegen-flag advice warranted. + +## conc +- clean: seeds ran (0/3/20/0): the two production `std::sync::Mutex` sites (adapter.rs:158 `validation`, adapter.rs:297 `ReceivedPacketState.inner`) carry `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` - sanctioned synchronous paths per the provider-crate-policy allow list, short critical sections with no suspension point; atomics are counters/flags with correct weakest orderings (CreditPool CAS AcqRel, `received_any` swap, `ACTIVATION_CONSUMED` compare_exchange); no threads, no `thread_local!`, no manual `Send`/`Sync`. + +## async +- clean: seeds ran (130/2/1/9): all socket I/O goes through the `AsyncFd` wrappers named in clippy.toml's replacement vocabulary (`SeqpacketSocket::recv_burst`/`send_burst`, `StreamSocket::read_available`/`write_all`, systemd accept loop); no blocking calls on executor workers (the only std fs call is the sanctioned sync pidfd surface with an allow, pidfd.rs:71); no guards held across `.await` (`await_holding_lock` deny is clean); framing is cancellation-safe via persistent buffers + `mem::take` (adapter.rs:813, vsock.rs:127) with dedicated cancellation tests; `tokio::spawn`/`join!` appear only in tests. + +## unsafe +- N/A: seeds 1-3 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 - the `from_raw` matches are `FileType::from_raw_mode`/`Pid::from_raw`/`io::Error::from_raw_os_error`, not pointer casts); manifest declares `unsafe_code = "forbid"`; the crate is not on the enumerated exception set in U1 (d) 8, consistent with zero blocks. + +## ffi +- N/A: seeds 0/0/0/0 all zero (`extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`, `CStr`/`CString`/`c_char` absent); the crate has no C boundary - libc/rustix calls are in-crate syscall wrappers. + +## macro +- clean: seed 1 = 1 hit (`macro_rules!` at subject.rs:59, the cfg-gated `mutate_verified_unix_peer_trait!` capability-mutation machinery whose generated impls must never be reachable - declared in the manifest check-cfg list, the test-only-helper-macro false-positive class); seeds 2-4 zero; no proc-macro or `$crate` usage. + +## test +- clean: seeds ran (32/75/0/0): the suite is behavior-asserting and deterministic - real kernel objects (pipes, pidfds, socketpairs), fd tests serialized through a global `LazyLock>` (unix_session.rs:21), error variants asserted rather than Display strings, adversarial sequences (recycled pidfd info, fd reuse, stale readiness, cancellation mid-frame), credit accounting verified at every scope, and `#[tokio::test(flavor = "current_thread")]` where fd state is shared; no `proptest`/`insta`/`rstest` and no `#[ignore]` (seeds 3/4 zero), which is appropriate for this kernel-surface suite. + +## Coverage +- idiom: clean (seeds ran: 3/1/8) +- own: clean (seeds ran: 14/9/14/0) +- type: clean (seeds ran: 8/0/0) +- api: 1 finding(s) +- err: clean (seeds ran: 22/5/3/4) +- serde: N/A (seeds: 0/0/0/0 all zero; no serde dependency, crate crosses no wire) +- obs: clean (seeds ran: 0/0/0/2) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 0/3/20/0) +- async: clean (seeds ran: 130/2/1/9) +- unsafe: N/A (seeds: 0/0/0/0 for seeds 1-3; manifest `unsafe_code = "forbid"`) +- ffi: N/A (seeds: 0/0/0/0 all zero; no C boundary) +- macro: clean (seeds ran: 1/0/0/0; cfg-gated test-only macro) +- test: clean (seeds ran: 32/75/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md new file mode 100644 index 000000000..55bdb490e --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md @@ -0,0 +1,72 @@ +# d2b-telemetry - d2b-telemetry +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1,983 (excl. src/generated/**) | modules: whole crate (audit_hash, emitter, meter_registry, metric_label_policy, redaction_guard, session_metrics_sink, trace_context) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) + +## idiom +- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0; crate declares fns so the lens applies, and no index loops, no hand-written derive-replaceable impls, no statement-style accumulation were found (the hand-written Debug impls on AuditHash, TraceContext, and BoundedEmitter are the deliberate redaction class, and the hand-written Serialize/Deserialize impls are deliberate admission gates). + +## own +- clean: seeds `\.clone\(\)`=4, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=18, `Rc<|RefCell<|Arc>` plus `Arc` are the shared-ownership handles behind `BoundedEmitter`'s `Clone` (emitter.rs:167-168), the key/value clones build owned `BTreeMap`s at the admission boundary (emitter.rs:541, meter_registry.rs:107), the `child_span` trace_id clone is required by the Self-owned fields (trace_context.rs:63), and the rest are test fixtures; no `Rc`/`RefCell`/`Cow` anywhere. + +## type +- clean: seeds `fn validate_\w+|fn check_\w+`=3, `is_\w+: bool|\w+_flag: bool`=0, `(mode|kind|state): String`=0; the three validators (`validate_metric_frame` emitter.rs:502, `validate_resource_attributes` metric_label_policy.rs:14, `validate_span_field` redaction_guard.rs:95) are parse-once admission checks on untrusted wire input at the boundary, not validate-at-every-callsite smells, and no boolean-flag soup, stringly-typed state, or `Option`-pair states exist. + +## api +- clean: seeds `\bpub (fn|struct|enum|trait|type|const|mod) `=94, `pub .*\b(Arc|Rc|Box|RefCell)<`=0, `^\s*pub use `=9; the surface is deliberate - every pub item is documented, the `Arc` fields on `BoundedEmitter` are private (`socket_path()` returns `&Path`), the `pub mod` + `pub use` shape in lib.rs is the house single-surface pattern (d2b-audit/src/hash_chain.rs:3-6 and d2b-bus/src/metrics.rs:10-13 consume both paths; census: `d2b_telemetry::` over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 16 hits), and the `meter_registry::label` re-export is a live cross-crate API consumed by d2b-bus/src/metrics.rs:12. + +## err +- d2b-telemetry#1 sev=medium blast=leaf effort=S verdict=actionable - `BoundedEmitter::new_with_limits` reports invalid constructor arguments as `EmitterError::StatePoisoned`, conflating a permanent programming error with transient lock poisoning - fix: add a dedicated variant (e.g. `InvalidLimits`) and return it from the zero-capacity / zero-frame / zero-age / zero-retry guard clauses, keeping `StatePoisoned` for the `lock().map_err` sites - [packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93] + evidence: seed `enum \w*Error` = 5; the guard clauses at emitter.rs:201-206 return `StatePoisoned`, whose doc comment says "The emitter lock was poisoned" (emitter.rs:92-93); the Display strings are unpinned - census: `telemetry-emitter-state-poisoned` over packages/nixos-modules/tests/docs/labs/BUILD.bazel = 1 hit (its own Display arm) and no telemetry code appears in docs/reference/error-codes.md +- d2b-telemetry#2 sev=low blast=leaf effort=S verdict=actionable - `SessionMetricsError::Encode` is never constructed; the `io::Error` from `encode_frame` is folded into `EmitterError::MetricPolicy(DescriptorMalformed)` inside `emit_metric`, so the variant and its Display arm are dead surface - fix: delete the `Encode(std::io::Error)` variant and the `"session-metric-encode-failed"` Display arm - [packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_metrics_sink.rs:82] + evidence: census: `SessionMetricsError::Encode|Encode\(` over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 2 hits, both self-referential (definition + Display arm); the only encode failure path maps to `EmitterError::MetricPolicy` at emitter.rs:328, so no construction path exists + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize`=3, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=2, `impl .*Deserialize.*for`=2, `serde_json::from_|serde_json::to_`=5; the hand-written `Deserialize` impls on `AuditHash` (audit_hash.rs:48-56) and `TraceContext` (trace_context.rs:73-87) are live admission gates over private fields (the skill's parse-once pattern), `AuditChainLink` carries `rename_all = "camelCase"` + `deny_unknown_fields`, and `TraceContext`'s hand-written `Serialize` deliberately emits digested identities; no optionality or representation mistakes found. + +## obs +- N/A: seeds `\bprintln!\(|\beprintln!\(`=0, `(info|debug|warn|error|trace)!\("`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=0, and Cargo.toml declares no tracing/log dependency; the crate is a synchronous library with no telemetry-emitting surface of its own. + +## docs +- d2b-telemetry#3 sev=low blast=leaf effort=M verdict=actionable - Result-returning public items carry no `# Errors` section stating which conditions produce which failure - fix: add `# Errors` sections to `AuditHash::parse` (audit_hash.rs:23), `AuditChainLink::verify`/`verify_at` (audit_hash.rs:103,126), `BoundedEmitter::new`/`new_with_limits`/`with_default_capacity`/`emit`/`emit_metric`/`drain`/`buffered_frames`/`buffered_bytes` (emitter.rs:183,194,228,236,316,340,385,395), `MetricFamily::new`/`record`, `MeterRegistry::register`/`record`, `RedactionGuard::new`/`validate_span_field`/`span_attributes`, `validate_resource_attributes`, and `SessionMetricsSink::record` - [packages/d2b-telemetry/src/emitter.rs:236, packages/d2b-telemetry/src/audit_hash.rs:23] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits against `-> Result<` = 20 hits; repo-wide `/// # Errors` over packages/ = 0 hits, so this is a proposal, not a house deviation; all pub items themselves are documented and every module carries a `//!` doc + +## perf +- clean: seeds `format!\(`=5, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=4, `\.to_string\(\)`=0; the two production `format!` sites render hash strings in `AuditHash::from_bytes`/`record_hash` (cold construction paths), `hex_lower` pre-sizes with `with_capacity`, and the collection constructors are one-shot constructor-time allocations where the empty case is common; all static (unmeasured), no hot-loop allocation found. + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope`=1, `\bMutex<|\bRwLock<`=1, `Atomic\w+|Ordering::`=6, `thread_local!|unsafe impl (Send|Sync) for`=1; `Arc>` is a `std::sync::Mutex` on a genuinely synchronous path (the sanctioned class), the drop counters use `Relaxed` orderings (the weakest correct ordering for counters nobody synchronizes on), the `thread_local!` and `thread::sleep` are cfg(test) only, and no unsafe `Send`/`Sync` claims or `static mut` exist. + +## async +- N/A: seeds `async fn|async move|\.await`=0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(`=0, `tokio::sync::(Mutex|RwLock|Notify)`=0, `#\[tokio::(main|test)\]|Runtime::block_on`=0; the crate is a synchronous library surface (its own Cargo.toml comment records the frozen no-async-form posture). + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=0; seed 4 (`unsafe_code`) = 1 hit, the `#![forbid(unsafe_code)]` attribute at lib.rs:6, which per the lens card does not make the lens applicable; the crate manifest carries no `unsafe_code` setting (U1 (d) 8 lists it as ABSENT with no sites). + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0; no foreign boundary exists in the crate. + +## macro +- N/A: seeds `macro_rules!`=0, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; no macros are defined or expanded beyond std/derive macros. + +## test +- d2b-telemetry#4 sev=medium blast=leaf effort=S verdict=actionable - contract rejection paths have no tests: `BoundedEmitter::new`/`new_with_limits` argument rejections (zero capacity -> StatePoisoned, relative path -> SocketPathInvalid), `AuditChainLink::verify` mismatch variants, `MeterRegistry::register` duplicate-name rejection, `MetricFamily::record` kind/value mismatch rejection, and `RedactionGuard::new` duplicate-key rejection are all untested, so a change that breaks any admission check passes the suite - fix: add unit tests asserting the exact variants, e.g. `assert_eq!(BoundedEmitter::new("relative", 128).unwrap_err(), EmitterError::SocketPathInvalid)`, `link.verify(&other, &payload, &record) == Err(ChainVerificationError::PreviousHashMismatch)`, and `registry.register(duplicate).unwrap_err() == MetricPolicyError::DescriptorMalformed` - [packages/d2b-telemetry/src/emitter.rs:201-210, packages/d2b-telemetry/src/audit_hash.rs:103-116, packages/d2b-telemetry/src/meter_registry.rs:88-96, packages/d2b-telemetry/src/meter_registry.rs:127-133, packages/d2b-telemetry/src/redaction_guard.rs:63-64] + evidence: seed `#\[test\]|#\[tokio::test\]` = 31 tests, all read; none exercise the listed rejection paths - the suite covers redaction, FIFO order, ring bounds, label policy, and success paths only +- d2b-telemetry#5 sev=low blast=leaf effort=S verdict=actionable - `target_buckets_are_present` pins three bucket constants by asserting one member value each, a tautology that fails on refactor and passes on behavior change - fix: delete the test, or replace it with a behavior test (e.g. a `MetricFamily::new` built with `CONTROLLER_HINT_BUCKETS_SECONDS` accepts an in-range histogram value and rejects an out-of-range one) - [packages/d2b-telemetry/src/meter_registry.rs:176-180] + evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 77 hits; the test's expected values are the constants themselves (`CONTROLLER_HINT_BUCKETS_SECONDS.contains(&0.005)`), not derived from an independent source + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 4/18/1/0) +- type: clean (seeds ran: 3/0/0) +- api: clean (seeds ran: 94/0/9) +- err: 2 finding(s) +- serde: clean (seeds ran: 3/2/2/5) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 1 finding(s) +- perf: clean (seeds ran: 5/4/0) +- conc: clean (seeds ran: 1/1/6/1) +- async: N/A (seeds: 0/0/0/0 all zero; synchronous library surface) +- unsafe: N/A (seeds: 0/0/0 all zero for the block/fn/impl seeds; seed 4 = 1 hit, the `#![forbid(unsafe_code)]` attribute at lib.rs:6, which does not make the lens applicable) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros defined) +- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md new file mode 100644 index 000000000..043d22706 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md @@ -0,0 +1,68 @@ +# d2b-unsafe-local-helper - d2b-unsafe-local-helper +Baseline: 6ebdd4cec | LOC audited: 3240 (excl. src/generated/**) | modules: whole crate (environment.rs, lib.rs, main.rs, protocol.rs, runtime.rs, systemd.rs) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-unsafe-local-helper#6 sev=low blast=leaf effort=S verdict=actionable - terminate_scope and stop_scope normalize a NotFound into Ok via `(error == ScopeError::NotFound).then_some(()).ok_or(error)?`, a boolean-then-Option chain that hides the two-branch control flow at the exact spot a reader asks "what happens on NotFound" - fix: `if error != ScopeError::NotFound { return Err(error); }` in both terminate_scope and stop_scope, then `Ok(())` - [packages/d2b-unsafe-local-helper/src/systemd.rs:260, packages/d2b-unsafe-local-helper/src/systemd.rs:277] + evidence: idiom seed 2 `impl (Default|From|...) for` = 1 hit + manual read; the then_some/ok_or construct appears twice (systemd.rs:260, 277); ScopeError is Copy so it compiles, but the control flow is obscured +- d2b-unsafe-local-helper#8 sev=medium blast=family effort=L verdict=actionable - the seqpacket framing codec (u32 length prefix + JSON body + socket buffer tuning to the frozen MIN_EFFECTIVE floor) is maintained as two independent implementations, one on each side of the same wire: protocol.rs and d2bd-runtime/src/unsafe_local_helper.rs - fix: extract a shared frame codec module as the canonical home for send_frame/receive_frame/configure_socket_buffers and consume it from both processes; keep the daemon-side fd-capturing receive_frame as a thin extension over the shared framing - [packages/d2b-unsafe-local-helper/src/protocol.rs:310, packages/d2b-unsafe-local-helper/src/protocol.rs:337, packages/d2b-unsafe-local-helper/src/protocol.rs:357, packages/d2bd-runtime/src/unsafe_local_helper.rs:727, packages/d2bd-runtime/src/unsafe_local_helper.rs:752, packages/d2bd-runtime/src/unsafe_local_helper.rs:770] + evidence: grep `configure_socket_buffers|send_frame|receive_frame` over packages/ = the helper's own copies at protocol.rs and a second, near-identical set at d2bd-runtime/src/unsafe_local_helper.rs:727/752/770; the two sides already drift (daemon returns captured fds, helper rejects frames carrying fds), and the framing rules and buffer floor must not be re-derived per side +- clean: idiom seeds ran (for `0..` = 1, impl-for = 1, let-mut-Vec/String::new = 2); the only index loop is a test barrier spawn; the hand-written Default for RuntimeLedger preserves the schema_version invariant a derive would break and is justified +## own +- clean: own seeds ran (clone/to_owned/to_vec/to_string ~48 lines; Rc/RefCell/Arc/Arc/Cow = 0); every clone is explainable - Arc clones at thread spawn boundaries (protocol.rs:176-179, required for 'static), wire-identity clones into PersistedScope/SupervisorSpec owned fields, ledger.persisted.clone for commit-rollback and snapshot clones to release the lock before manager calls, and test fixtures; no unneeded copies found +## type +- d2b-unsafe-local-helper#2 sev=low blast=leaf effort=S verdict=actionable - RuntimeLedger.reservations is keyed by `operation_id.to_string()` (a String key) while OperationId already derives Ord + Clone + Hash, so every begin/owns/clear round-trips through a per-call allocation and as_str() re-parsing of an id the caller already owns typed - fix: `BTreeMap` and use the OperationId directly in begin (runtime.rs:193, 206, 230), owns (236) and clear (242); delete operation_key - [packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/runtime.rs:193, packages/d2b-unsafe-local-helper/src/runtime.rs:230, packages/d2b-unsafe-local-helper/src/runtime.rs:236, packages/d2b-unsafe-local-helper/src/runtime.rs:242] + evidence: census: OperationId derives PartialOrd, Ord, Clone, Hash at packages/d2b-contracts/src/ids.rs:131-133; runtime.rs uses to_string + as_str at five sites; string keys map one-to-one to OperationId, so this is type-consistency (stringly-keyed state), not a correctness fix +- clean: type seeds ran (validate_/check_ = 3, is_/flag bool = 0, mode/kind/state String = 1); the three validate_* fns are one-shot boundary checks of external inputs (fs paths, wire events) with no same-input re-validation elsewhere, so parse-once types would not remove a bug class; the single String hit is a local `let active_state: String`, not stringly-typed state +## api +- d2b-unsafe-local-helper#1 sev=low blast=leaf effort=S verdict=actionable - the exported surface includes SupervisorSpec, send_frame/receive_frame/configure_socket_buffers, and SUPERVISOR_START_TIMEOUT/SNAPSHOT_RECONCILE_TIMEOUT, none consumed by the crate's only external user (the same crate's binary main.rs, which imports only HelperClient, ScopeRuntime, run_scope_supervisor, SystemdUserScopeManager, default_helper_socket_path) - fix: narrow to pub(crate)/private where possible; keep pub only the items main.rs or a pub signature needs - [packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/protocol.rs:310, packages/d2b-unsafe-local-helper/src/protocol.rs:337, packages/d2b-unsafe-local-helper/src/protocol.rs:357, packages/d2b-unsafe-local-helper/src/runtime.rs:35, packages/d2b-unsafe-local-helper/src/runtime.rs:36] + evidence: census: `SupervisorSpec|SUPERVISOR_START_TIMEOUT|SNAPSHOT_RECONCILE_TIMEOUT` over packages/ + nixos-modules/ + tests/ + docs/reference/ + labs/ = 0 external hits (only in-crate uses); the send_frame/receive_frame/configure_socket_buffers hits elsewhere (d2b/src, d2bd-runtime, d2b-resource-client) are unrelated same-named items, so the crate's own trio also has no external consumer +- clean: api seed 3 (`pub use`) = 0; seed 2 (Arc/Rc/Box/RefCell in signatures) matched only pub(crate) fields, no exported signature leaks a heap type +## err +- d2b-unsafe-local-helper#3 sev=medium blast=leaf effort=S verdict=actionable - await_scope_identity maps every `Ok(_)` whose state is not starting/active (scope exists but the launched process already exited, stopping, or degraded) to ScopeError::IdentityMismatch, so an operational "process died during startup" is reported and handled as a security identity failure; the caller then aborts the supervisor and surfaces ScopeIdentityMismatch to the daemon - fix: return a distinct error for an early-exit scope (e.g. ScopeError::CreateFailed or a new EarlyExit variant), keep IdentityMismatch for identity-check failures only, and map it to RuntimeError::ScopeCreateFailed - [packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/systemd.rs:338-346] + evidence: err seeds (unwrap/expect ~non-test, let-_ ~14, panic! 1 test-only, enum Error = 4); read of await_scope_identity shows query_scope (systemd.rs:160-167) maps active/activating/reloading and never produces HelperScopeState::Starting, so the guard's Starting arm is dead and `Ok(_)` is the exited-process path, which is a caller-action distinct from a mismatched identity +- clean: err seed 1 non-test unwrap/expect reduced to one invariant-holding `expect("supervisor child present")` at runtime.rs:713 (child is always Some at id()'s only call site, protocol.rs:408); all other unwrap/expect live in #[cfg(test)]; the `let _ =` sites are deliberate best-effort cleanup (close fd, kill/wait, remove_dir_all); the four error enums (EnvironmentError, ProtocolError, RuntimeError, ScopeError) are exhaustive across From and failure_code mappings, split by caller action +## serde +- clean: serde seeds ran (derive = 4 structs, serde attrs = several, hand-written Deserialize = 0, serde_json from/to = 22); PersistedScope, PersistedScopeLedger, SupervisorSpec, GraphicalSupervisorSpec all use rename_all=camelCase + deny_unknown_fields; fingerprint and graphical are Option with serde(default)/skip_serializing_if; no hand-written deserializer; the child-side re-validation after deserialize (GraphicalSupervisorSpec::validate) is a deliberate admission gate per the refusal ledger +## obs +- d2b-unsafe-local-helper#5 sev=low blast=leaf effort=S verdict=actionable - the operation-worker failure path logs `unsafe-local launch failed: {error:?}` (protocol.rs:188) with no request_id or operation_id, so a background launch failure cannot be correlated to the request that caused it and carries no stage context - fix: include request_id and operation_id (both in scope at protocol.rs:183-189) in the message or as fields - [packages/d2b-unsafe-local-helper/src/protocol.rs:188] + evidence: obs seed 1 (println|eprintln) = 10 hits; main.rs:30/47 are CLI-entry diagnostics and the seven launch_setup eprintlns (runtime.rs:356-399) carry distinct stage labels, but the worker-thread site is the only failure signal for a backgrounded operation and it drops the two identifiers that exist right there +- clean: obs seeds 2-4 (tracing macros, instrument, tracing::) = 0; the crate deliberately has no tracing dependency (synchronous subprocess, U18), so stderr is the log channel and the remaining sites are acceptable one-shot diagnostics +## docs +- d2b-unsafe-local-helper#7 sev=medium blast=leaf effort=M verdict=actionable - the entire pub surface is undocumented: the only /// comment in the crate is on the private validate_runtime_directory, so run/launch/snapshot, the UserScopeManager trait, HelperClient, send_frame/receive_frame, and the public getters carry no one-line contract, no # Errors, and receive_frame's `encoded.len() >= MAX_HELPER_FRAME_SIZE + 5` buffer invariant is discoverable only from the body - fix: add /// first-sentence plus # Errors sections to every pub fn returning Result, document the UserScopeManager trait contract and the frame-buffer invariant - [packages/d2b-unsafe-local-helper/src/lib.rs:1-4, packages/d2b-unsafe-local-helper/src/environment.rs:38, packages/d2b-unsafe-local-helper/src/protocol.rs:92, packages/d2b-unsafe-local-helper/src/protocol.rs:357, packages/d2b-unsafe-local-helper/src/runtime.rs:315, packages/d2b-unsafe-local-helper/src/systemd.rs:72] + evidence: docs seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits; `///` grep across src = 1 hit total (a private fn); seed 1 (pub items) and seed 3 (`-> Result<`) dominate the 103 seed matches yet none is documented +## perf +- clean: perf seeds ran (format! 11, *::new 9, to_string 10); all format! sites are cold (error paths, one-shot display generation, ledger/scratch filenames); Vec::new/BTreeMap::new sites are empty-common cases; receive_frame reuses one receive_buffer across the run loop (good pattern), hex and proxy_arguments size with with_capacity; a single win exists in the type lens (#2) which also removes a per-launch to_string allocation, but no allocation sits in a measured loop and no benchmark exists, so nothing else rises above static taste +## conc +- d2b-unsafe-local-helper#4 sev=low blast=leaf effort=S verdict=actionable - the `active` operation counter is a pure admission counter (it bounds MAX_HELPER_QUEUE_DEPTH worker threads and publishes no value; responses travel over the sync_channel, which carries its own synchronization) yet every fetch_add/fetch_sub uses AcqRel - fix: Ordering::Relaxed, the weakest correct ordering for a counter nobody synchronizes on - [packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src/protocol.rs:167, packages/d2b-unsafe-local-helper/src/protocol.rs:195] + evidence: conc seed 3 (Atomic|Ordering) = 4 hits; the counter is read only through fetch_add's returned value and decremented after the response send, with no paired publication, so AcqRel is stronger than the weakest correct ordering +- clean: conc seeds (thread spawn ~12, Mutex/RwLock 3, unsafe impl Send/Sync 0); the ledger and zbus connection Mutexes are std Mutex on genuine synchronous paths (repo-class allowed), the channels are bounded sync_channel (backpressure, no unbounded growth), the UserScopeManager trait states `Send + Sync + 'static` supertraits explicitly, and all worker/reader/reaper threads are named; one long-lived reaper thread per committed launch is inherent to the mini-init design and bounded by MAX_HELPER_SNAPSHOT_SCOPES +## async +- clean: N/A (async seeds all zero: no async fn/await/tokio/block_on anywhere; seed 2/3/4 = 0) +## unsafe +- clean: unsafe seeds ran (seed 3 `transmute|from_raw|MaybeUninit|mem::zeroed` = 2 hits); both hits are nix safe constructors (`nix::unistd::Pid::from_raw` at runtime.rs:954-955 feeding waitpid), not unsafe code; there are zero unsafe blocks, unsafe fns, unsafe impls, or SAFETY comments in the crate, and the manifest lints.rust sets `unsafe_code = "forbid"` (Cargo.toml) - the (d) 8 exception enumeration adds no site in this crate, so nothing to cite or re-flag +## ffi +- clean: N/A (ffi seeds all zero: no extern "C", no_mangle, catch_unwind, repr(C), CStr/CString/c_char anywhere; the crate never crosses a foreign caller) +## macro +- clean: N/A (macro seeds all zero: no macro_rules!, proc macro, syn/quote, $crate, or to_compile_error in the crate) +## test +- d2b-unsafe-local-helper#9 sev=low blast=leaf effort=S verdict=actionable - adoption_degrades_identity_ambiguity_without_stopping_scope re-derives snapshot's inline identity-mismatch match on a hand-built ScopeInspection (test lines 1567-1576 mirror production lines 505-508), so it still passes if snapshot later reports `state` instead of Degraded for a mismatched scope - fix: extract the `ScopeInspection::observable_state()` decision used by snapshot into a testable function and assert on that extracted behavior - [packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helper/src/runtime.rs:505-508] + evidence: test seed 1 (#[test]) = 25 tests, seed 2 (asserts) ~90; this test asserts a copy of the prod match, the skill's same-logic-computes-the-expectation test that cannot catch the plausible regression +- clean: the suite otherwise follows the form the assertion needs - typed error variants (assert_eq against Err(EnvironmentError::X) / Err(RuntimeError::Y)) not Display strings, table-driven cases with `"{invalid:?}"` failure messages, a Barrier/thread concurrency test for reservations, and real child-process keyword tests for supervisor teardown; determinism holds (no clock reads except injected deadlines, no network, scratch dirs are uid-random under /proc/self/cwd); no #[ignore], no proptest/insta/rstest - property/snapshot tooling would not add a covered behavior + +## Coverage +- idiom: 2 finding(s) | clean for the remaining seed mass +- own: clean (seeds: ~48 clone/to_owned/to_string lines; Rc/RefCell/Cow/Arc = 0) +- type: 1 finding(s) | clean for validate_* boundary checks +- api: 1 finding(s) | pub surface wider than the binary consumer needs +- err: 1 finding(s) | panic policy otherwise invariant-only +- serde: clean (seeds: derive 4, serde attrs several, hand Deserialize 0, json from/to 22) +- obs: 1 finding(s) | stderr-only observability as designed +- docs: 1 finding(s) | 0 canonical sections across ~39 pub items +- perf: clean (seeds: format! 11, *::new 9, to_string 10; all cold) +- conc: 1 finding(s) | model otherwise thread-boundary correct +- async: N/A (seeds: async fn/await 0, tokio 0, sync mutex 0; deliberate synchronous subprocess per Cargo.toml U18) +- unsafe: clean (seeds: from_raw 2, both nix safe wrappers; manifest forbids unsafe_code) +- ffi: N/A (seeds: 0/0/0/0; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0; no macros defined) +- test: 1 finding(s) | otherwise behavior-first typed-error tests diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md new file mode 100644 index 000000000..7a77732ba --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md @@ -0,0 +1,78 @@ +# d2b-zone-routing - d2b-zone-routing +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10120 (excl. src/generated/**; src 8214 + tests 1906) | modules: engine, enrollment, resolver, router, service, serving +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate + +## idiom +- d2b-zone-routing#1 sev=low blast=leaf effort=S verdict=actionable - `SealedZoneTopology::longest_suffix_match` walks `for start in 0..labels.len()` with an inline `continue`, where the same logic is a `find_map` over the index range - fix: replace the loop with `(0..labels.len()).find_map(|start| { let Ok(suffix) = ZonePath::new(labels[start..].to_vec()) else { return None; }; self.zones.get(&suffix) })` - [packages/d2b-zone-routing/src/resolver.rs:144] + evidence: seed `for \w+ in 0\.\.` = 2 hits; only this site is in production code (service.rs:1793 is a fixed-count test loop). +- d2b-zone-routing#2 sev=low blast=leaf effort=S verdict=actionable - `ZoneTopologyRequest` carries a hand-written `impl Default` that a field-wise derive reproduces exactly - fix: delete the manual impl and add `#[derive(Default)]` to the struct - [packages/d2b-zone-routing/src/service.rs:311] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 hits; only this site's derive would be field-wise identical (the other four Default impls preserve non-zero frozen bounds and must stay manual). + +## own +- d2b-zone-routing#3 sev=low blast=leaf effort=M verdict=actionable - In `ZoneRouteAdmission::consume`, the snapshot's zone pair is copied from `expected` with two `ZonePath` clones per consumed route admission, though `expected` is already owned by the match arm and only compared afterwards - fix: compare every non-zone field first, then move `expected.source_zone`/`expected.target_zone` intosnapshot (or split `validate_snapshot` into a zone-pair phase taking `expected` by value), removing the two clones - [packages/d2b-zone-routing/src/engine.rs:345, packages/d2b-zone-routing/src/engine.rs:346] + evidence: seed `\.clone\(\)` = 141 hits; this site is the only production clone of a value already owned by the enclosing scope (all other clones buy a second owner or test fixture state). + +## type +- clean: seeds ran: `fn validate_\w+|fn check_\w+` = 3 (`validate_snapshot`, `validate_session_binding`, `check_current`), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; all three hits are runtime comparisons against sealed admission evidence (target substitution, session binding, daemon time), not parse-once type candidates, and there is no flag soup or stringly-typed state. + + + +## api +- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod)` = 207, `pub .*\b(Arc|Rc|Box|RefCell)<` = 1, `^\s*pub use` = 0; every public item has exactly one path and a doc comment; the single `Arc` signature hit is the deliberate clock/placements seam (`pub type ZoneEnrollmentPlacements` and `ZoneEnrollmentAuthority::new`), no `Box`/`Rc`/`RefCell` appears in any signature, and `test-support`-gated `for_test` constructors are consumed cross-crate by the vector suites as intended. + + + +## err +- clean: seeds ran: `\.unwrap\(\)|\.expect\(` = 207, `let _ = |\.ok\(\);` = 1, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 15, `enum \w*Error` = 2; every unwrap/expect/panic hit sits in `#[cfg(test)]` or `#[cfg(any(test, feature = "test-support")))]` code or test helpers, the one `let _` is a stray test line (flagged under `test`),and the two error enums (`RouterError`, `ZoneEnrollmentServeError`) are closed with stable kebab labels and `std::error::Error` impls + +## serde +- N/A (seeds: 0/0/0/0 all zero; no serde derives, serde attributes, hand-written `Deserialize` impls, or `serde_json` anywhere - this crate crosses no wire boundary; wire call types live in `d2b-contracts-zone-session`) + +## obs +- N/A (seeds: 0/0/0/0 all zero; the crate has no `tracing`/`log` dependency in Cargo.toml - there is no telemetry surface to judge; zero `println!` in src) + +## docs +- d2b-zone-routing#4 sev=low blast=leaf effort=M verdict=actionable - The crate's 47 `-> Result<` public signatures document failure modes in prose paragraphs (e.g., `SealedZoneTopology::seal`, `ZoneServiceLimits::new`, `ZoneEnrollmentAuthority::with_lifetime`) but zero canonical `# Errors`/`# Panics` sections exist anywhere, so rustdoc index and IDEs lose a scannable contract - fix: add a `# Errors` section to the public validators/constructors that enforce conditions (seal, the `Limits`/`Expectation`/`Authority` constructors, `with_runtime_admission`), keeping the prose as depth beneath it - [packages/d2b-zone-routing/src/resolver.rs:80, packages/d2b-zone-routing/src/service.rs:208, packages/d2b-zone-routing/src/enrollment.rs:424] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 201, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 47 + +## perf +- clean: seeds ran: `format!\(` = 15, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 21, `\.to_string\(\)` = 0; all 15 `format!` hits are `cfg(test)` debug-render assertions and synthetic fingerprint builders (engine.rs:1959, resolver.rs:526, service.rs:1242), and the 21 collection initializers are bounded staging tables with ceilings (`MAX_ZONE_PARENT_ENTRIES`, `MAX_ZONE_ROUTE_ENTRIES`, `MAX_IDEMPOTENCY_ROWS`) - no measured hot path exists to name + +## conc +- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 4, `Atomic\w+|Ordering::` = 34, `thread_local!|unsafe impl (Send|Sync) for` = 0; the four `Mutex` sites are the single-use admission states and the router/exec tables, each `std::sync::Mutex` locked with per-site `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` (no suspension point), atomics are `AtomicBool` revoke flags loaded Acquire/stored Release plus test clocks; no manual `Send`/`Sync` claims or `thread_local!` in production + +## async +- d2b-zone-routing#5 sev=medium blast=leaf effort=M verdict=actionable - `ZoneEnrollmentServer::serve` commits the link FSM synchronously (PSK burn, enrollment record seal) inside `serve_bootstrap`/`serve_enroll` and then `.await`s the reply write `transport.send)...)`, so a `serve` future dropped between the mutation and the send leaves the link mid-transition and the peer never sees the reply - fix: make the FSM commit + encoded-reply write one non-cancellable unit (and document that dropping the task mid-send closes the connection as the peer's only signal), or make the operation resumable by deferring the transition until the reply write succeeds where the FSM allows - [packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207] + evidence: seed `async fn|async move|\.await` = 6 hits (all in serving.rs:180-319); no tokio spawn/spawn_blocking/select!/join! or tokio sync types in src + +## unsafe +- N/A (seeds: 0/0/0/0 all zero; no `unsafe` blocks/fns/impls, no `// SAFETY:` comments, and the manifest carries no `unsafe_code` setting - U1 ledger (d) 8 records it ABSENT here, so there is no unsafe surface to judge) + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString` anywhere - no foreign-calling boundary exists) + +## macro +- clean: seeds ran: `macro_rules!` = 1, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the single `macro_rules!` (`redacted_debug!`, service.rs:116) is impl-per-type `Debug` generation - a genuine macro answer - with the narrow `ident` fragment, a fully-qualified `::core::fmt` expansion, and no crate-path or error machinery to judge + +## test +- d2b-zone-routing#6 sev=low blast=leaf effort=S verdict=actionable - `every_reason_the_engine_can_produce_is_covered_by_this_suite` checks only that the 16 named closed reasons have distinct `label()`s, not that the suite produces any of them - the name promises a coverage property the row never asserts - fix: rename it to `every_engine_reason_has_a_distinct_wire_label` and, if coverage is actually wanted, record the reasons each vector produced and assert the set at the end - [packages/d2b-zone-routing/src/engine.rs:3333] + evidence: test seed `#\[test\]|#\[tokio::test\]` = 143; this test's body only sorts and dedups `label()` values, with no produced-reason tracking +- d2b-zone-routing#7 sev=low blast=leaf effort=S verdict=actionable - `durable_exec_table_is_bounded_to_ephemeral_processes` ends with a dead `let _ = ZoneId::parse("dev").unwrap();` line that exercises nothing and exists only to use an import - fix: delete the line and the now-unused `ZoneId` import from the test module - [packages/d2b-zone-routing/src/router.rs:517] + evidence: err seed `let _ =` = 1 hit; the single hit is this stray test line + +## Coverage +- idiom: 2 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 3/0/0; all hits are runtime comparisons against sealed evidence, not type-model candidates) +- api: clean (seeds ran: 207/1/0; single-signature `Arc` is a deliberate seam; no internals or second paths exposed) +- err: clean (seeds ran: 207/1/15/2; no production panic or swallowed Result; error enums closed with stable labels) +- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no wire boundary) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency - no telemetry surface) +- docs: 1 finding(s) +- perf: clean (seeds ran: 15/21/0; all format! hits are test paths; collection sites bounded, unmeasured) +- conc: clean (seeds ran: 0/4/34/0; Mutex sites are sanctioned synchronous surfaces; atomics are Acquire/Release pairs) +- async: 1 finding(s) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe surface - manifest setting absent per U1 d8) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign-calling boundary) +- macro: clean (seeds ran: 1/0/0/0; single macro is justified impl-per-type generation) +- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md new file mode 100644 index 000000000..e02be9d3a --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md @@ -0,0 +1,78 @@ +# d2bd-p1 - d2bd - part 1/8 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 13238 (excl. src/generated/**) | modules: src/resource_runtime.rs (whole file) +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/8: src/resource_runtime.rs (whole file, 13,238 lines) + +## idiom +- d2bd-p1#3 sev=low blast=leaf effort=S verdict=actionable - `current_committed_resource` (9168) is a body-for-body duplicate of `committed_resource` (9153) plus an unused `_operation_id` parameter, and its only caller is `committed_wayland_session_for_vm` (4555) - fix: call `committed_resource` at 4555 and delete `current_committed_resource` - [packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, packages/d2bd/src/resource_runtime.rs:9153] + evidence: seeds `for \w+ in 0\.\.` = 1, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2, `let mut \w+ = (String|Vec)::new\(\)` = 17; duplicate bodies read at 9153-9210 vs 9168-9210; census: `current_committed_resource` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file +- d2bd-p1#4 sev=low blast=leaf effort=S verdict=actionable - pointless `let setup = setup;` rebind in `reconcile_controller_sessions_locked` shadows the just-bound value to drop a mutability that was never declared - fix: bind once without `mut` and delete the rebind line - [packages/d2bd/src/resource_runtime.rs:6896] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 17 hits; the rebind read at 6896 with the comment block 6893-6895 explaining the ordering that the rebind does not serve; remaining seed mass (1 index-loop hit at 6271, 2 hand-written Defaults at 839/867, 17 accumulators) is deliberate - the loop is a bounded retry, the Defaults preserve pinned wire defaults, and the accumulators have early exits or await-driven extends + +## own +- d2bd-p1#5 sev=low blast=leaf effort=S verdict=actionable - avoidable `row.resource_ref.clone()` in `committed_controller_provider_identities`: the field is only borrowed by `committed_provider_spec` and then moved into the result map - fix: pass `&row.resource_ref` to `committed_provider_spec` and `identities.insert(row.resource_ref, (uid, generation))` after the call - [packages/d2bd/src/resource_runtime.rs:359] + evidence: seed `\.clone\(\)` = 262 hits (sampled: 44 of 262 hits, every 6th); the sampled clone at 359 is the only one whose value survives only as a borrow target and can be moved instead +- d2bd-p1#6 sev=low blast=leaf effort=S verdict=actionable - nine call sites pass `.to_owned()` into parsers that take `impl Into` (d2b-contracts-resource identity.rs:79,155,279,393), where `&str: Into` makes the allocation unnecessary - fix: drop `.to_owned()` at 181, 4625, 9911, 9931, 10096, 10138, 10212, 11078, 11079, 11082 - [packages/d2bd/src/resource_runtime.rs:181, packages/d2bd/src/resource_runtime.rs:4625, packages/d2bd/src/resource_runtime.rs:9931, packages/d2bd/src/resource_runtime.rs:10096, packages/d2bd/src/resource_runtime.rs:11078] + evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 102 hits; parser signatures read at packages/d2b-contracts-resource/src/v3/identity.rs:79 (`pub fn parse(value: impl Into)`); all nine sites pass a `&str` that `Into` accepts directly; the remaining sampled clone mass (44 of 262 hits, every 6th) is explainable - lock-guard escapes (1192), constructor inputs (2059, 6975), Arc clones at spawn/shared-state boundaries (5984, 11236), map-key/return copies (2220, 7231) + +## type +- d2bd-p1#7 sev=low blast=leaf effort=S verdict=actionable - `ZoneResourceRuntime` carries three gate booleans `policy_installed`/`controller_endpoint_registered`/`watch_admitted` (3041-3043) with only two reachable states - (true, false, false) at open (3230-3232) and (true, true, true) after `activate_published_bundle` (3470-3472) - so six impossible combinations are representable - fix: replace the trio with one enum (e.g. `PlanePublicationStage { BootstrapOnly, Published }`) read by `readiness_error` (8104-8116) - [packages/d2bd/src/resource_runtime.rs:3041, packages/d2bd/src/resource_runtime.rs:3230, packages/d2bd/src/resource_runtime.rs:3470, packages/d2bd/src/resource_runtime.rs:8104] + evidence: seeds `fn validate_\w+|fn check_\w+` = 3, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the flag trio and its two write sites read at 3041-3043, 3230-3232, 3470-3472 +- d2bd-p1#8 sev=low blast=leaf effort=S verdict=actionable - `ControllerSession` encodes ordered once-only teardown progress as three independent booleans `ingress_revoked`/`assignments_revoked`/`transport_closed` (1014-1016), so skipping or reordering a step (e.g. closing the transport before revoking assignments) is representable and silently leaks a lease or a revocation frame - fix: replace the three with a `TeardownStage` enum advanced monotonically in `remove_controller_session` (7614-7650) - [packages/d2bd/src/resource_runtime.rs:1014, packages/d2bd/src/resource_runtime.rs:7614] + evidence: seeds `fn validate_\w+|fn check_\w+` = 3, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; flag fields read at 1013-1016 and their only writer `remove_controller_session` at 7614-7650; the three validate fns are wire-boundary checks on manager-served rows (the parse-once point), and the runtime's `Option` pairs are deliberately handled by `derive_interaction_state` (9271-9281) + +## api +- clean: seeds `\bpub (fn|struct|enum|trait|type|const|mod) ` = 30, `pub .*\b(Arc|Rc|Box|RefCell)<` = 2, `^\s*pub use ` = 2; the two `Arc>`/`Arc<...>` returns (11161, 11200) are justified shared ownership - census: `network_admission_index` callers at shared_provider_effects.rs:1132, shared_provider_effects.rs:2436, composition.rs:15350, and `ResourcePlane::zone` hands out the plane's own Arc - and the `pub use` arms (115, 126) are the house re-export pattern; all `pub` items are deliberate (ZoneResourceRuntime, ResourcePlane, HostNetworkAdmissionIndex) with private fields. + +## err +- d2bd-p1#1 sev=medium blast=family effort=M verdict=actionable - `credential_dependency_row` swallows a manager RPC failure into absence (`.ok().flatten()`), contradicting the module's own contract that "a manager RPC failure is an error - never reported as absence" (bridge_manager_row doc, 299-305); the caller `ProductionCredentialRuntime` facts closure (4511) then reports no dependency facts, so a transient manager failure silently degrades credential readiness and revocation decisions - fix: propagate the error (log it with the error field at minimum; change `credential_dependency_facts`/`CredentialRuntime::dependency_facts` to `Result>` so the driver can retry) - [packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511] + evidence: seed `let _ = |\.ok\(\);` = 35 hits; the `.ok().flatten()` read at 381-383 versus the never-absence contract documented at 299-305; the remaining seed mass is clean - unwrap/expect = 223 (sampled: 45 of 223 hits, every 5th) with every non-test hit an invariant expect naming its reason (6003, 6992, 4993/5399/5741), the two `unreachable!` sites (3402, 6288) statically guaranteed, and the `let _ =` sites deliberate best-effort cleanup or fenced operations whose error propagates via `?` + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 7, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 27, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 44; all seven wire types (802-916) use `rename_all = "camelCase"` + `deny_unknown_fields` with pinned `default = "..."` functions, the hand-written `Default` impls preserve those pinned defaults, and every parsed config is validated before use (`parse_committed_clipboard_configuration` 9718, `parse_committed_notification_configuration` 9780) - the serde boundary is the admission gate it should be. + +## obs +- d2bd-p1#9 sev=low blast=leaf effort=M verdict=actionable - eighteen message-only `tracing::warn!` events carry no named fields and the file has no spans at all (`\.instrument\(|#\[instrument` = 0), so the events lose the underlying error: most are inside `map_err` closures that drop the error (2024, 2419, 4846, 5283), and 7169 discards the in-scope `context` (provider/process) when a controller assignment refresh retries - fix: capture the error and log it as a named field (`error = ?...`) in the `map_err` closures, and add `provider`/`process` fields at 7169 - [packages/d2bd/src/resource_runtime.rs:2024, packages/d2bd/src/resource_runtime.rs:2419, packages/d2bd/src/resource_runtime.rs:4846, packages/d2bd/src/resource_runtime.rs:5283, packages/d2bd/src/resource_runtime.rs:7169] + evidence: seed `(info|debug|warn|error|trace)!\("` = 18 hits; seed `\.instrument\(|#\[instrument` = 0 (no enclosing span anywhere in the file); the field-less sites read at 2024-2071, 2419-2467, 4846-5364, 7169; the other seeds are clean - `\bprintln!\(|\beprintln!\(` = 0, `tracing::|log::` = 134 with the field-carrying events well-formed (7134, 7719), and no secret or identifier in any field + +## docs +- d2bd-p1#10 sev=low blast=leaf effort=S verdict=actionable - the public-request get deadline literal `meta.deadline_ms = 30_000` appears four times (8294, 8390, 10242, 10280) with no comment naming the why (which peer or operation enforces it) - fix: extract `const PUBLIC_GET_DEADLINE_MS: u64 = 30_000;` with a why-comment and use it at all four sites - [packages/d2bd/src/resource_runtime.rs:8294, packages/d2bd/src/resource_runtime.rs:8390, packages/d2bd/src/resource_runtime.rs:10242, packages/d2bd/src/resource_runtime.rs:10280] + evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 30, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 182; the four deadline literals read at 8294, 8390, 10242, 10280 with no surrounding comment; the rest of the surface is clean - all 30 public items carry prose doc contracts with one-line first sentences (3006, 3777, 10709, 11125), the module has a `//!` doc (1-9), and failure conditions are documented in prose (4725-4734, 3777-3788) - the absent `# Errors` sections are a style choice in a bin crate where `missing_docs` is not appropriate + +## perf +- d2bd-p1#2 sev=medium blast=leaf effort=S verdict=actionable - three arms of `CloudHypervisorResourceSession::call` compute an operation id that is immediately discarded: `UpdateSpec` (2360-2364), `UpdateStatus` (2489-2505, `let _ = &operation_id`), and `DeleteChild` (2856-2859, `let _operation_id`) each build `operation_payload` and run a full SHA-256 `canonical_digest` plus a `format!` allocation that no caller reads - this runs on every provider status/spec update, i.e. every reconcile pass - fix: delete the dead digest/format computation and the `let _` bindings in all three arms - [packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, packages/d2bd/src/resource_runtime.rs:2505, packages/d2bd/src/resource_runtime.rs:2856] + evidence: static (unmeasured); seed `format!\(` = 21 hits; the dead bindings read at 2505 (`let _ = &operation_id;`) and 2856 (`let _operation_id = format!)...)`) with no later use of `operation_id` in the UpdateSpec arm (only `let _ = (&owner_ref, &payload, &operation_id)` at 2414); the remaining seed mass is clean - other `format!` sites are cold paths (960, error rendering), and the `Vec::new()` sites (72 hits) are page-capped list builders or empty-case-common accumulators + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 42, `Atomic\w+|Ordering::` = 26, `thread_local!|unsafe impl (Send|Sync) for` = 0; all 42 mutex hits are `tokio::sync::Mutex` fields whose guards are held across `.await` (the correct choice, e.g. 1052-1117, 3010-3067), the atomics are `AtomicBool` flags with paired Acquire/Release (`system_core_rebind_pending` 14/8637, `finalizer_clear_requested` 11522, reconcile shutdown 6121-6131), and there are no manual `Send`/`Sync` claims or `thread_local!`. + +## async +- clean: seeds `async fn|async move|\.await` = 537 (sampled: 49 of 537 hits, every 11th), `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 6, `tokio::sync::(Mutex|RwLock|Notify)` = 80, `#\[tokio::(main|test)\]|Runtime::block_on` = 1; no blocking work sits on an executor worker (the bundle reload is routed to the bounded loader worker at 5338-5341), the reconcile waker arms `Notify` before the check (6129-6160), guards are dropped before re-locking (`close_guest_session` 1942-1955) or are `tokio::sync` guards held deliberately under a documented lock order (3898-3900), cancellation paths abort and await their tasks (7644-7650), and the only `#[tokio::test]` (12714) is a current-thread harness. + +## unsafe +- unsafe: N/A (seeds: 0/0/0/0 all zero; no `unsafe` blocks/fns/impls, no `// SAFETY:` comments, no transmute/raw-pointer/MaybeUninit sites, and no `unsafe_code` attribute in the file) + +## ffi +- ffi: N/A (seeds: 0/0/0/0 all zero; no `extern "C"`/`no_mangle`, no `catch_unwind`, no `repr(C)`/`repr(transparent)`, no `CStr`/`CString`/`c_char` in the file) + +## macro +- macro: N/A (seeds: 0/0/0/0 all zero; no `macro_rules!`, no proc-macro/syn/quote, no `$crate`, no `to_compile_error`/`new_spanned` in the file) + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 38, `assert_eq!\(|assert_ne!\(|assert!\(` = 128, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the tests are behavior-focused with regression documentation (reconnect fence 11313, endpoint gate 11887, policy digest 11931, manager merge 12206, owner fence 12269), table-driven loops carry failure messages (11936-11968), error assertions match variants not Display strings (11587-11666), and no test restates implementation or computes its expectation with the code under test. + +## Coverage +- idiom: 2 finding(s) +- own: 2 finding(s) +- type: 2 finding(s) +- api: clean (seeds ran: 30/2/2) +- err: 1 finding(s) +- serde: clean (seeds ran: 7/27/0/44) +- obs: 1 finding(s) +- docs: 1 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: 0/42/26/0) +- async: clean (seeds ran: 537/6/80/1) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe sites in the file) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface in the file) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros in the file) +- test: clean (seeds ran: 38/128/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md new file mode 100644 index 000000000..512b971bc --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md @@ -0,0 +1,81 @@ +# d2bd-p2 - d2bd - part 2/8 +Baseline: 6ebdd4cec | LOC audited: 10672 (excl. src/generated/**) | modules: composition.rs (10071-20142), audio_host_controller.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: composition.rs:10071-20142 + audio_host_controller.rs (U1 section f) + +## idiom +- d2bd-p2#1 sev=low blast=leaf effort=S verdict=actionable - open_resource_plane hardcodes the provider-identity seed window as `for attempt in 0..30` and `Duration::from_secs(2)` although the same-file consts PROVIDER_IDENTITY_SEED_ATTEMPTS (30) and PROVIDER_IDENTITY_SEED_INTERVAL (2s) at composition.rs:14193-14194 document exactly this "30 x 2s" window - fix: use `PROVIDER_IDENTITY_SEED_ATTEMPTS` and `PROVIDER_IDENTITY_SEED_INTERVAL` in the retry loop so the literals cannot drift from the documented window - [packages/d2bd/src/composition.rs:14699, packages/d2bd/src/composition.rs:14710, packages/d2bd/src/composition.rs:14193] + evidence: seed `for \w+ in 0\.\.` = 2 hits (14227 parameterized retry is fine; 14699 is the literal); consts at 14193-14194 define the same window +- clean: seeds ran 2/0/4; the other index loop (14227) is a parameterized retry, the `let mut Vec::new()` sites (14967, 19761) are plain loops with early exits and side effects where the idiom skill itself prefers the loop, and no hand-written derive-class impls exist in the range + +## own +- clean: seeds ran 189/286/0/0 (sampled: 50 of 475 hits, every 10th); every sampled clone is explainable - `caller_role.clone()` into spawned owner threads, `Arc` clones at spawn/effect boundaries, `.to_owned()` on wire error codes and JSON payload strings, test-fixture clones; no Rc/RefCell/Arc/Cow in the range + +## type +- d2bd-p2#2 sev=low blast=leaf effort=S verdict=actionable - ShutdownDegradedMarker stores `outcome: String` and `severity: String` although the same file defines VmShutdownOutcome (composition.rs:16131) whose label()/degraded_severity() (16205-16239) are the only producers of those strings - fix: derive Serialize on VmShutdownOutcome with `#[serde(rename_all = "snake_case")]` and store the enum in the marker so the report shape cannot drift from the enum - [packages/d2bd/src/composition.rs:16152, packages/d2bd/src/composition.rs:16155, packages/d2bd/src/composition.rs:16131] + evidence: type seeds 0/0/0 (model reading); the marker strings are produced from the enum at 16233-16239 and 16364 +- d2bd-p2#3 sev=medium blast=leaf effort=S verdict=actionable - `force` on guest lifecycle requests is parsed from the wire (composition.rs:6794-6797), stored in DaemonGuestLifecycleEffect.force (6837-6848), and never consulted - apply() only reads it via `let _ = self.force;` (18659) - so `d2b guest ... --force` (sent by d2b/src/guest.rs:283) is silently ignored - fix: implement the force semantics in apply() (e.g. skip the graceful wait) or drop the field and the wire parse - [packages/d2bd/src/composition.rs:18659, packages/d2bd/src/composition.rs:18608] + evidence: type seeds 0/0/0; census: `DaemonGuestLifecycleEffect|self.force` over packages/ = struct def 18603, construction 6837, single read 18659; CLI sends the flag (d2b/src/guest.rs:283) +- clean: seeds ran 0/0/0; the enums in the range (GuestComponentSessionCacheMode, VmRunnerLaunch, VmShutdownOutcome, HostActivationMarkerState) are well-formed, and no boolean-flag soup or stringly-typed state beyond the two findings exists + +## api +- d2bd-p2#4 sev=low blast=leaf effort=S verdict=actionable - the pub surface of audio_host_controller.rs (trait HostAudioController 59, PipeWireHostController 92, from_audio_node 106, find_audio_node 124, QemuAudioController 214) is unreachable outside the crate because `mod audio_host_controller;` (composition.rs:395) is private - fix: reduce these to `pub(crate)` (FakeHostController is already cfg(test)) so the visibility says what the surface is - [packages/d2bd/src/audio_host_controller.rs:59, packages/d2bd/src/audio_host_controller.rs:92, packages/d2bd/src/composition.rs:395] + evidence: api seeds 9/0/1; census: `HostAudioController|find_audio_node|enforce_grant|enforce_level` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits outside packages/d2bd +- d2bd-p2#5 sev=low blast=leaf effort=S verdict=actionable - `vm_name: &str` in HostAudioController::enforce_grant/enforce_level is dead trait surface: every implementation (PipeWire, Qemu, Fake) names it `_vm_name` and ignores it, and the only callers (audio_dispatch.rs:160,177) pass it pointlessly - fix: remove the parameter from both trait methods and the call sites - [packages/d2bd/src/audio_host_controller.rs:68, packages/d2bd/src/audio_host_controller.rs:78, packages/d2bd/src/audio_host_controller.rs:173] + evidence: api seeds 9/0/1; census: `enforce_grant|enforce_level` over packages/ = call sites audio_dispatch.rs:160,177 only; all three impls ignore the parameter (173, 183, 219, 230, 287, 297) +- clean: no Arc/Rc/Box/RefCell in any public signature, the re-export `pub use crate::audio_dispatch::HostEnforcementResult` follows the house single-surface pattern, and the trait is dyn-safe as its docs claim + +## err +- d2bd-p2#6 sev=low blast=family effort=M verdict=actionable - `detail: err.to_string()` collapses the source error into a String when building TypedError variants, losing the error chain for diagnostics - fix: carry the source in the variant (e.g. `InternalBrokerUnavailable { path, #[source] source: serde_json::Error }` with the detail rendered in Display) so the chain survives to the logging boundary - [packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d2bd/src/composition.rs:15243, packages/d2bd/src/composition.rs:15247, packages/d2bd/src/composition.rs:16777, packages/d2bd/src/composition.rs:16785, packages/d2bd/src/composition.rs:16790, packages/d2bd/src/composition.rs:17015, packages/d2bd/src/composition.rs:17023] + evidence: seed `let _ = |\.ok\(\);` = 53 hits; the 9 `detail: err.to_string()` sites are the chain-collapsing class, the rest are deliberate best-effort frame writes and shutdowns +- clean: seeds ran 41/53/1/0; all unwrap/expect hits are cfg(test) code, literal-built values (ShellName::new("primary"), own-constructed response objects), or startup invariants; the single unreachable!() (13622) is guarded by the Close/Cancel pre-check at 13510-13518 so it is not reachable from wire input; `let _ =` sites are deliberate best-effort writes/shutdowns + +## serde +- clean: seeds ran 4/4/0/34; the derives (ShutdownDegradedReport/Marker camelCase, HostActivationMarkerState kebab-case) are consistent, no hand-written Deserialize impls, and all serde_json boundary calls map errors to wire codes or fall back explicitly + +## obs +- d2bd-p2#7 sev=low blast=leaf effort=S verdict=actionable - `tracing::error!("Gateway Guest composition refused: root Zone generation unavailable")` is message-only although `topology.root` is in scope - fix: add `zone = %topology.root` (and the generation value if available) so the refusal is queryable per zone - [packages/d2bd/src/composition.rs:14781] + evidence: seed `(info|debug|warn|error|trace)!\("` = 3 hits; this site has no fields and no enclosing span with the zone +- d2bd-p2#8 sev=low blast=leaf effort=S verdict=actionable - two identical message-only `tracing::warn!("resource plane still has live request owners during shutdown")` events in the two LiveRequestOwners branches of shutdown_resource_plane carry no fields, so the operator cannot tell which zones are stuck - fix: add `zones = ?zones` (or a count) to both events - [packages/d2bd/src/composition.rs:15195, packages/d2bd/src/composition.rs:15221] + evidence: seed `(info|debug|warn|error|trace)!\("` = 3 hits; both warn sites are the duplicated message-only pair +- clean: seeds ran 0/3/0/158 (sampled: 40 of 158 tracing:: lines); the sampled events use named fields consistently (e.g. log_vm_start_report 17845-17874, log_host_prep_dag 17877-17893), no println/eprintln in the range, no secrets in fields, and the async-gate-allow marker at 10701 is a recorded deliberate exception + +## docs +- clean: seeds ran 9/0/96 (sampled: 32 of 96 `-> Result<` lines); all 9 pub items in audio_host_controller.rs carry contract docs with one-line first sentences, the pub(crate) composition items in the range are documented, and no canonical-section or doctest gaps were found + +## perf +- clean: seeds ran 90/18/18 (sampled: 30 of 90 format! lines); the format!/to_string sites are error paths, wire responses, and JSON payload building (cold by the card's own false-positive list), the Vec::new/BTreeMap::new sites are empty-case-common or plain-loop accumulations, and no hot-loop allocation was found + +## conc +- clean: seeds ran 5/1/2/0; the AtomicU64 request-id counter uses Relaxed correctly (13804-13806), the std::thread spawns (12856) are dedicated daemon owner threads with names, the sleeps (16861, 17582) are on sanctioned synchronous paths, and the only Mutex is a cfg(test) journal buffer + +## async +- clean: seeds ran 187/0/2/1 (sampled: 48 of 190 hits); the await chains are in async fns with proper error mapping, tokio::sync::Mutex guards (10884, 11064) are scoped and never held across await, the per-VM mutex map (10869, 10958) is lock striping, the single tokio::test is cfg(test), and the async-gate-allow marker at 10701 is a recorded deliberate exception + +## unsafe +- clean: seeds ran 0/0/2/0; the two seed-3 hits are safe `io::Error::from_raw_os_error` constructors, not unsafe code - no `unsafe` blocks, fns, impls, or SAFETY comments exist in the scope + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, catch_unwind, repr(C), or CStr/CString in the scope) + +## macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, proc-macro, $crate, or to_compile_error in the scope) + +## test +- clean: seeds ran 86/301/0/0 (sampled: 50 of 387 hits, every 8th); the in-range unit tests (guest_session_target_admission_tests, guest_target_session_tests, guest_component_session_cache_tests, audio_host_controller tests) and the tests/ suite assert behavior with messages (e.g. "the assignment survives the target loss"), no #[ignore] tests, no property/snapshot tooling, and no assertion that restates its implementation was found in the sample + +## Coverage +- idiom: 1 finding(s) +- own: clean (seeds ran: 189/286/0/0; sampled 50 of 475) +- type: 2 finding(s) +- api: 2 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 4/4/0/34) +- obs: 2 finding(s) +- docs: clean (seeds ran: 9/0/96) +- perf: clean (seeds ran: 90/18/18) +- conc: clean (seeds ran: 5/1/2/0) +- async: clean (seeds ran: 187/0/2/1) +- unsafe: clean (seeds ran: 0/0/2/0; the two seed-3 hits are safe from_raw_os_error constructors, no unsafe code in scope) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 86/301/0/0; sampled 50 of 387) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md new file mode 100644 index 000000000..242e1e9bb --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md @@ -0,0 +1,80 @@ +# d2bd-p3 - d2bd - part 3/8 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10801 (excl. src/generated/**) | modules: composition.rs (20143-30213), zone_enrollment.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/composition.rs:20143-30213, src/zone_enrollment.rs + +## idiom +- d2bd-p3#8 sev=low blast=leaf effort=S verdict=actionable - dispatch_live_guest_activation_resource builds the identical resource-List json and identical drive_sync dispatch twice (rollback branch and next-ordinal branch), differing only in post-processing - fix: hoist the `list` json and `runtime.dispatch_public_cli_request(&list)` call (with its map_err) above the `if mode == DaemonActivationMode::Rollback` split and branch only the filter/max computation - [packages/d2bd/src/composition.rs:20450-20461, packages/d2bd/src/composition.rs:20486-20498] + evidence: static comparison of the two blocks (same "zoneRef"/"service"/"method"/"resourceType"/"executionRef"/"limit": 256 payload, same drive_sync + map_err shape); seed `for \w+ in 0\.\.` = 10 (all test accept loops), `let mut \w+ = (String|Vec)::new\(\)` = 2 (test helpers), `impl (Default|From|...) for` = 0 +- d2bd-p3#9 sev=low blast=leaf effort=S verdict=actionable - qemu_media_registry_state takes `_registry_dir: &str` and never reads it (the probe reads global state), so every caller passes a value into a dead parameter - fix: drop the parameter and the `registry_dir` argument at the sole call site - [packages/d2bd/src/composition.rs:21306-21319, packages/d2bd/src/composition.rs:21291] + evidence: `_registry_dir` appears only in the signature (fn body 21313 calls the zero-arg `qemu_media_probe_registry_records()` at composition.rs:10000); census: `qemu_media_registry_state` over packages/ = 1 call site +- clean: seeds 1-3 ran (10/0/2); the 10 index loops are accept-loop test harvesters and the two Vec::new accumulators are test broker helpers; no hand-written Default/From/Debug/Clone impls, no statement-style production accumulation found + +## own +- d2bd-p3#4 sev=low blast=leaf effort=S verdict=actionable - `let zone = guard.zone().clone()` clones the ZoneId although `guard` can be borrowed for the whole body (it is only used again by its own Drop at scope end) - fix: bind `let zone = guard.zone();` and pass `&zone` to plane.zone and the json! formatters - [packages/d2bd/src/composition.rs:20404] + evidence: seed `\.clone\(\)` = 82 lane hits; non-test hits (35) read in full, this is the only borrow-replaceable clone in non-test code; sampled: 50 of 394 test-mass hits (every 8th), all fixture-owned or required +- d2bd-p3#5 sev=low blast=leaf effort=S verdict=actionable - typed_error_from_resolution_error clones `workload_id` while destructuring an owned error; the binding can be moved into TypedError::WorkloadAliasConflict because `candidates` is only joined by reference - fix: bind `workload_id` (no `.clone()`) in the AliasConflict arm - [packages/d2bd/src/composition.rs:21091] + evidence: seed `\.clone\(\)` = 82 lane hits; err is passed by value and neither field is used after construction of the TypedError +- d2bd-p3#6 sev=low blast=leaf effort=S verdict=actionable - `ResourceName::parse(readable.clone())` clones a just-built String although parse takes `impl Into` and `&readable` converts without allocation - fix: `ResourceName::parse(&readable)` - [packages/d2bd/src/composition.rs:20638] + evidence: `d2b_contracts_resource::v3::ResourceName::parse(value: impl Into)` (packages/d2b-contracts-resource/src/v3/resource.rs:44); seed `\.clone\(\)` = 82 lane hits + +## type +- d2bd-p3#2 sev=low blast=leaf effort=S verdict=needs-contract - HostActivationPendingMarker.mode is a stringly-typed activation mode on a persisted marker: it is deserialized, logged and rendered but never validated against the known label set, while the in-Rust mode already exists as DaemonActivationMode - fix: replace `mode: String` with a serde-mirrored enum (e.g. `DaemonActivationMode` behind kebab-case serde, or a marker-local enum) and validate on read; the marker file is written by out-of-tree activation machinery, so the serialized label set is a contract - [packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d2bd/src/composition.rs:21135] + evidence: seed `(mode|kind|state): String` = 1 hit (composition.rs:20146); marker read boundary at 20260-20277; census: `HostActivationPendingMarker` over packages/ + nixos-modules/ = 3 files (composition.rs, d2bd-runtime/metrics.rs via metric label, docs/reference/daemon-api.md), no Rust writer in-tree + +## api +- N/A: seeds all zero in this partition (pub items 0, `pub .*\b(Arc|Rc|Box|RefCell)<` 0, `pub use ` 0); part 3 contains no exported surface - `pub(crate)` items in zone_enrollment.rs (ZONE_ENROLLMENT_PORT, GuestEnrollmentEndpoint)are crate-internal by design + +## err +- d2bd-p3#1 sev=medium blast=leaf effort=S verdict=actionable - dispatch_audit maps any unrecognized severity string from the wire to `TypedError::InternalIo { context: "audit filter", detail: "severity-invalid" }`, surfacing caller input errors as internal I/O failures instead of a request-validation refusal - fix: return a wire-input refusal kind (e.g. a TypedError::Wire* invalid-request variant or the invalid_request_response frame used by mutating dispatch) for the `Some(_) =>` arm - [packages/d2bd/src/composition.rs:22793-22797, packages/d2b-contracts-control/src/public_wire.rs:2453] + evidence: seed `\.unwrap\(\)|\.expect\(` = 537 lane hits (non-test sites read in full: 8, all documented invariants); the arm's kind is TypedError::InternalIo (packages/d2bd-runtime/src/typed_error.rs:490-493), an internal category for a user-typable field +- d2bd-p3#7 sev=medium blast=leaf effort=S verdict=actionable - ActivationLockGuard::drop silently swallows `finish_activation` failure (`let _ =`), so a coordinator refusal to close an activation is never even logged and the wedge is only discoverable via the deferred activation-pending marker - fix: log the error with tracing::warn! (boundary has no Result channel; the marker alone is not enough) - [packages/d2bd/src/composition.rs:20185-20190] + evidence: seed `let _ = |\.ok\(\);` = 63 lane hits; this is the only non-test `let _ =` on a fallible call (20188) outside cfg(test) cleanup sites + +## serde +- d2bd-p3#3 sev=low blast=leaf effort=S verdict=needs-contract - HostActivationPendingMarker.schema_version is deserialized but never validated, so a future marker version with a compatible field set would silently parse as current - fix: check `schema_version == 1` on read (refuse with a typed log/error otherwise) or drop the field from the read path if versioning is not enforced; the marker file is written by out-of-tree activation machinery, so its shape is a contract - [packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d2bd/src/composition.rs:20298] + evidence: census: `schema_version` over packages/d2bd/src = 7 hits, 1 for this type (20144) and no read site anywhere (the other hits are unrelated types: 3669/8497/16146/28121); seed `serde_json::from_|serde_json::to_` = 56 lane hits + +## obs +- clean: seeds 1-4 ran (println 0, interpolated no-field events 0, instrument 0, tracing refs 18); every tracing event in the part uses named fields (vm = %marker.vm, endpoint = %path.display(), error = %error, activation_id, state = ?) and no event interpolates a message; no secret-bearing field spotted in the 18 sites (mode/activation_id are non-secret opaque identifiers); no subscriber installed (library/binary split respected) + +## docs +- d2bd-p3#10 sev=low blast=leaf effort=S verdict=actionable - the activation generations List limit `"limit": 256` is duplicated as an undocumented magic literal in both branches of dispatch_live_guest_activation_resource - fix: hoist to a named constant (e.g. `const ACTIVATION_GENERATIONS_LIST_LIMIT: u64`) with a comment naming why 256 (bounded retained NixosGeneration scan) - [packages/d2bd/src/composition.rs:20451, packages/d2bd/src/composition.rs:20495] + evidence: seed `^\s*pub (fn|struct|...)` = 0, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 18 (all private binary-crate fns); the two literals are textually identical with no comment + +## perf +- clean: seeds 1-3 ran (format! 55, collection news 54, to_string 28); every format!/to_string hit outside tests is cold (error detail strings, activation marker path names, one-shot generation names, per-poll response envelopes in a network-wait loop); the per-VM scoped workers in build_public_list/build_public_status are justified because provider probes can block up to PUBLIC_STATUS_PROVIDER_PROBE_TIMEOUT; no hot-path allocation pattern found; static (unmeasured) throughout + +## conc +- clean: seeds 1-4 ran (thread 21, Mutex/RwLock 9, Atomic 8, thread_local 0); non-test concurrency is the documented shape: scoped-thread data parallelism for list/status builds, `Arc>`/`Arc>` shared state with multiple owners, atomics only in tests (NEXT_TEST_ID); no manual Send/Sync impls, no static mut; the deliberate serialization of one zone's enrollments through one mutex is documented at zone_enrollment.rs:220-225 + +## async +- clean: seeds 1-4 ran (async fn/.await 78, spawn/JoinSet/select 2, tokio::sync refs 94, tokio main/test 10); no guard held across .await except the tokio::sync::Mutex held across serve() in spawn_accept_loop, which is the documented per-link serialization (zone_enrollment.rs:297-308); blocking work in async contexts is absent (the 250 ms sleep poll in dispatch_live_guest_activation_resource runs on the sync worker-thread dispatch path, marked `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` at 20385); 2 async-gate-allow markers at 26155/26552 are sanctioned cfg(test) sites; startup marker scans use tokio::fs with let-else skipping (no panics, no blocking) + +## unsafe +- clean: seeds 1-4 ran (unsafe blocks/fns/impls 0, `// SAFETY:` 0, transmute/from_raw/MaybeUninit/zeroed 12, unsafe_code 0 in scope); all 12 from_raw hits are safe constructors (`io::Error::from_raw_os_error`, `nix::unistd::Pid::from_raw`) inside test helpers, not unsafe blocks; no unsafe code exists in this partition, so no SAFETY-comment obligations arise (workspace `unsafe_code = "forbid"` is inherited as recorded in U1 (d) 1) + +## ffi +- N/A: seeds all zero (extern "C"/no_mangle 0, catch_unwind 0, repr(C)/repr(transparent) 0, CStr/CString 0); the part crosses no foreign-language boundary + +## macro +- N/A: seeds all zero (macro_rules! 0, proc_macro/syn/quote 0, $crate 0, to_compile_error 0); no macros defined or consumed beyond std macros + +## test +- clean: seeds 1-4 ran in partition scope (test attrs 139, asserts 457, proptest/insta/rstest 0, #[ignore] 2); the two `#[ignore]` tests are documented flakes ("flaky on shared hosts; Unix socket reuse races", composition.rs:25679-25680) which U1 (c) test lists as acceptable; sampled 50 of 596 hits (attrs every 3rd, asserts every 10th) and read test neighborhoods 21355-21463, 24537-24567, 26078-26167, zone_enrollment.rs:595-683: tests assert typed error kinds (error.kind()/assert_eq!(error, "bundle-intent-missing:store-view")), real wire round-trips through FramedVsockTransport with human-written expected values, fail-closed behavior and ordering, with per-case messages; no self-fulfilling expectation or assert-less test spotted; tests/ directory corpus is shared across d2bd parts and outside this partition's module scope + +## Coverage +- idiom: 2 finding(s) +- own: 3 finding(s) +- type: 1 finding(s) +- api: N/A (seeds: 0/0/0 all zero; no pub items in this partition, pub(crate) only) +- err: 2 finding(s) +- serde: 1 finding(s) +- obs: clean (seeds ran: 0/0/0/18) +- docs: 1 finding(s) +- perf: clean (seeds ran: 55/54/28) +- conc: clean (seeds ran: 21/9/8/0) +- async: clean (seeds ran: 78/2/94/10) +- unsafe: clean (seeds ran: 0/0/12/0; all 12 from_raw hits are safe constructors) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) +- test: clean (seeds ran: 139/457/0/2) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md new file mode 100644 index 000000000..647be4d75 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md @@ -0,0 +1,86 @@ +# d2bd-p4 - d2bd - part 4/8 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10850 (excl. src/generated/**) | modules: composition.rs (lines 1-10070), plane_port.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: composition.rs:1-10070, plane_port.rs (whole file) + +## idiom +- clean: seeds ran: `for \w+ in 0\.\.` = 2, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 4; both index loops are test loops (8889, 8910) and all four `Vec::new()` accumulations are conditional-push loops in complex functions where an iterator pipeline would obscure early exits; no hand-written derive-replaceable impls and no `get_` field accessors. + +## own +- clean: seeds ran: `\.clone\(\)` = 196, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 313, `Rc<|RefCell<|Arc>` shared state in `ServerState` and `ZoneLinkGatewayComposition` is the U10-sanctioned concurrent-state pattern (composition.rs:19, composition.rs:522). + +## type +- clean: seeds ran: `fn validate_\w+|fn check_\w+` = 4, `is_\w+: bool|\w+_flag: bool` = 1, `(mode|kind|state): String` = 2; the four validate/check fns are one-shot boundary checks on wire/config input (correct per the skill), the bool is a parameter not a field flag, and the two `source_kind: String` fields are daemon-written registry records whose string values come from a closed enum match, not user state. + +## api +- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 16, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 11; the pub surface (composition.rs:397-403, 414, 419, 431, 4156, 4184) is consumed by main.rs and d2bd's own integration tests (tests/mode_separation.rs, tests/core_composition.rs, tests/resource_operator_activation.rs), the `pub use` arms (composition.rs:120-230) are the house single-surface pattern, and no public signature carries Arc/Rc/Box/RefCell. + +## err +- d2bd-p4#1 sev=medium blast=leaf effort=S verdict=actionable - `record_workload_availability_metrics` panics via `.expect("bounded workload availability tuple")` when the metric key set drifts from the label fns: `WORKLOAD_AVAILABILITY_STATES` (composition.rs:8097) + `WORKLOAD_PROVIDERS` (composition.rs:8090) live here, while `workload_availability_label`/`workload_provider_label` live in d2bd-runtime's workload_dispatch.rs, so adding a `WorkloadAvailability` variant compiles cleanly (the exhaustive match only forces the label fn update) but makes the daemon panic on the next workload List/Status - fix: seed the `counts` map from a single source of truth exported next to the label fns (e.g. `workload_availability_states()`/`workload_provider_labels()`), or replace the expect with a graceful `entry()`/skip so an unknown label degrades to a missing gauge instead of a panic - [packages/d2bd/src/composition.rs:8140, packages/d2bd-runtime/src/workload_dispatch.rs:104, packages/d2bd/src/composition.rs:8097] + evidence: `\.unwrap\(\)|\.expect\(` seed = 154 hits across the lane; only four production expect sites exist (7574, 8140, 9214, 9256) and the other three name compiler-invisible invariants that the guards literally enforce (mutating_verb_preflight at 10071; ShellName literal at 7574); this one's invariant is maintained across a crate boundary. + +## serde +- d2bd-p4#2 sev=medium blast=leaf effort=S verdict=actionable - `GatewayGuestConfigFile` and `GatewayGuestRelayConfigFile` deserialize user-written guest gateway config with `rename_all = "camelCase"` but no `deny_unknown_fields`, so a typo'd key is silently ignored and surfaces later as "Guest Relay namespace is unavailable" instead of a parse error - fix: add `#[serde(deny_unknown_fields)]` to both types (the `QemuMediaProbeRegistry*` records are daemon-written and may stay permissive); add a config-typo test to `load_gateway_guest_zone_link_options` - [packages/d2bd/src/composition.rs:4196, packages/d2bd/src/composition.rs:4205] + evidence: `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` seed = 4 hits (both pairs of types); no `deny_unknown_fields` anywhere in the lane; the repo's manifest-schema types use it as the admission-gate pattern. + + +## obs +- d2bd-p4#3 sev=medium blast=leaf effort=S verdict=actionable - the daemon's accept loop reports runtime errors with `eprintln!` (authorization refusal at 4099/4132, connection-handler failure at 4081/4132-ish, spawn failure at 4138) while the rest of the crate uses tracing and main.rs:146-152 installs a `tracing_subscriber`, so these error events bypass level filtering, structured fields, and the redaction gates; the daemon's stderr goes to the journal as unstructured prose - fix: replace the four `eprintln!` calls with `tracing::error!` events carrying named fields (`error = %error.message()`, `peer_uid`) - [packages/d2bd/src/composition.rs:4081, packages/d2bd/src/composition.rs:4099, packages/d2bd/src/composition.rs:4132, packages/d2bd/src/composition.rs:4138] + evidence: `\bprintln!\(|\beprintln!\(` seed = 4 hits, all in serve()'s sync connection paths;`tracing::|log::` seed = 92 hits in the same lane, so eprintln is the exception not the norm. +- d2bd-p4#4 sev=low blast=leaf effort=S verdict=actionable - three lifecycle `tracing::info!` events are message-only with no named fields ("Guest-local ZoneLink transport Provider composed", "Guest target-control service composed", "autostart: nothing to do (empty plan)") and no enclosing span exists (0 `#[instrument]` hits in the lane), so the events cannot be filtered by zone/vm - fix: add named fields (`zone`, `guest_ref`, or `vm`) to the three events, or wrap them in instrumented callers - [packages/d2bd/src/composition.rs:4487, packages/d2bd/src/composition.rs:4538, packages/d2bd/src/composition.rs:5300] + evidence: `(info|debug|warn|error|trace)!\("` seed = 3 hits (all three are the message-only events);`\.instrument\(|#\[instrument` = 0, so no span context carries those fields. + + +## docs +- d2bd-p4#5 sev=medium blast=leaf effort=S verdict=actionable - `pub async fn serve`, the daemon's primary entry point (composition.rs is `include!`d into lib.rs:183),has no doc comment at all, and `pub async fn lock_only` has none either; both return `Result` and carry no `# Errors` contract, so callers cannot learn from the docs what each loads/binds/runs and how it fails - fix: add a doc comment to `serve` (loads config, applies overrides, binds the operator socket, runs the accept loop; `# Errors` for config/IO/authz failures) and to `lock_only` - [packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828] + evidence: `^\s*pub (fn|struct|enum|trait|const|type)` seed = 10 pub items;`/// # (Examples|Errors|Panics|Safety)` = 0 hits in the lane;`-> Result<` = 128 hits; ly the two undocumented pub entry points return Result without an Errors section. +- d2bd-p4#6 sev=low blast=leaf effort=S verdict=actionable - `StaticProviderComposition::new` is a pub constructor returning `Result` with no doc comment and no `# Errors` section, so the mode_separation.rs callers must read the body to learn it fails on `AdmissionError` - fix: one-line doc plus a `# Errors` section naming `AdmissionError` - [packages/d2bd/src/composition.rs:438] + evidence: static (unmeasured); pub-item seed = 10 hits and `-> Result<` = 128 hits; `new` is the only pub constructor without docs among the crate's public surface in this lane. + + +## perf +- clean: seeds ran: `format!\(` = 83, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 19, `\.to_string\(\)` = 33; all format!/to_string sites are error-detail strings, operation-id/ref construction, one-shot probe/registry reads, or test fixtures - none sits in a loop over a hot request path; static (unmeasured), no benchmark exists in the crate. + + +## conc +- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` = 4, `\bMutex<|\bRwLock<` = 23, `Atomic\w+|Ordering::` = 4, `thread_local!|unsafe impl (Send|Sync) for` = 0; the named threads are deliberate per-connection/dedicated worker threads (composition.rs:3650, 4124, 5546),the AtomicU64 stream-id counter uses Relaxed correctly (3437-3440),the Arc stop flag is clear shared state (3805),and all 23 Mutex/RwLock sites are `tokio::sync::Mutex` in the U10-sanctioned production state tables (composition.rs:19) or test fakes. + + + +## async +- clean: seeds ran: `async fn|async move|\.await` = 155, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 3, `tokio::sync::(Mutex|RwLock|Notify)` = 50, `#\[tokio::(main|test)\]|Runtime::block_on` = 0 (the bare seed misses the attribute-carrying `#[tokio::test(flavor = "multi_thread")]` forms, which appear 10 times in plane_port.rs tests);`drive_sync` (composition.rs:210) has the sanctioned "synchronous path" inline allow and `block_in_place` is a documented no-op on dededicated threads (composition.rs:200-213),the select! cancellation in serve_guest (4559-4580) aborts serving then awaits it - the correct shutdown shape,and no guard is held across an .await beyond the async-gate scanner's covered set. + + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0 - all zero; the d2bd crate's unsafe sites (22 crate-wide per U1 (e))) live in other parts of composition.rs and sibling files, not in this part). + + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 - all zero; no FFI-boundary code exists in this part). + + +## macro +- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 - all zero; no macro definitions or proc-macro usage in this part). + + +## test +- clean: seeds ran: `#\[test\]|#\[tokio::test\]` = 21 (plus 10 `#[tokio::test(flavor = "multi_thread")]` in plane_port.rs that the bare seed does not match), `assert_eq!\(|assert_ne!\(|assert!\(` = 87, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the 21 tests assert behavior (topology resolution, gateway session establishment/refusal, cursor adoption, fencing, metric availability counts, workload dispatch denial, plane claim refusal/ordering/release) with hand-written expected values, deterministic (no network, no sleeps), and the async tests use multi_thread flavor per the async skill; no test restates implementation or cannot fail. + + +## Coverage +- idiom: clean (seeds ran: 2/0/4; both index loops are test loops and all four Vec::new accumulations are conditional-push loops with early exits; no derive-replaceable hand-written impls) + +- own: clean (seeds ran: 196/313/0/0; sampled: 46 of 509 hits; every sampled clone/to_owned is an Arc clone at a spawn/thread boundary, error-detail construction, request building, or test fixture; Rc/RefCell/Cow absent; Arc shared state is the U10-sanctioned pattern) +- type: clean (seeds ran: 4/1/2; all four validate/check fns are one-shot boundary checks, the bool is a parameter not a flag, the String fields are daemon-written registry records) +- api: clean (seeds ran: 16/0/11; pub surface consumed by main.rs and d2bd tests, pub use arms are the house single-surface pattern, no internals leak into signatures) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: 2 finding(s) +- docs: 2 finding(s) +- perf: clean (seeds ran: 83/19/33; no format!/allocation sits in a hot request loop; static (unmeasured)) +- conc: clean(seeds ran: 4/23/4/0; dedicated handler threads, Relaxed counter, clear stop flag, U10-sanctioned tokio mutexes) + +- async: clean (seeds ran: 155/3/50/0; drive_sync sanctioned inline allow, select! shutdown shape correct, no guards across .await beyond gate coverage; the 0 for seed 4 is a seed-regex artifact (attribute-carrying tokio::test forms missed)) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe constructs in this part - crate-level sites live elsewhere) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI-boundary code in this part) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros in this part) +- test: clean(seeds ran: 21/87/0/0; behavior-focused, deterministic, multi_thread-flavored async tests; no property/snapshot tooling needed for a daemon composition surface) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md new file mode 100644 index 000000000..ed529208a --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md @@ -0,0 +1,72 @@ +# d2bd-p5 - d2bd - part 5/8 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10,670 (excl. src/generated/**) | modules: interaction_composition, foundation_seed, principal_allocation, provider_shutdown, process_resource_runtime +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/interaction_composition.rs, src/foundation_seed.rs, src/principal_allocation.rs, src/provider_shutdown.rs, src/process_resource_runtime.rs + +## idiom +- clean: seeds run: `for \w+ in 0\.\.` = 7, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 7; the 7 index-loop hits are fixed-count poll/retry loops (`for _ in 0..N`) inside the tests module,and the 7 accumulator hits are mixed-effect builders (store rows, materialized specs, client lists( where the equivalent collect chain would be longer than the loop. + +## own +- d2bd-p5#1 sev=low blast=leaf effort=S verdict=actionable - the `run_effect` closure (bound `F: FnOnce`) clones `supervisor` and `process_ticket` a second time inside its body, though the captured values can move straight into the `async move` block (which only borrows them( - fix: remove `let supervisor = supervisor.clone();` and `let process_ticket = adoption_ticket.clone();`, letting the outer captures move into the `async move` - [packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_composition.rs:4344] + evidence: seed `\.clone\(\)` = 228 hits (sampled: 47 of 228); the sampled pair at 4343-4344 sits inside a `FnOnce` closure (signature at 6150), so the duplicates cannot be required; every other sampled clone is explainable (tokio::spawn capture boundaries, owned-struct assembly, error-path copies) + +## type +- clean: seeds run: `fn validate_\w+|fn check_\w+` = 4, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the four validator functions check cross-field compositions of daemon-owned or wire-derived compound state with no parse-once replacement candidate + + + +## api +- clean: seeds run: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 97, `pub .*\b(Arc|Rc|Box|RefCell)<` = 1, `^\s*pub use` = 1; the one `Arc` in a public signature (`stop_token` -> `Arc`, 5109( shares a genuinely multi-owner shutdown token, and the `pub use` re-export block (provider_shutdown.rs:8( is the house single-surface pattern; the rest of the exported surface exposes fields privately, and no dependency types leak + +## err +- d2bd-p5#2 sev=medium blast=leaf effort=S verdict=actionable - `reap_finished_handlers` joins finished listener handler tasks with `let _ = handlers.swap_remove(index)..await;`, silently discarding the `JoinError`, so a panicked handler (whose `handler_active.fetch_sub` decrement sits after the panic-capable body( neither logs and leaks its bounded 64-slot admission reservation( - fix: log the `JoinError` with `tracing::warn!` at the reap site,and wrap the spawn body so the `fetch_sub` decrement runs in a panic-safe guard, not after the admit body - [packages/d2bd/src/interaction_composition.rs:5365, packages/d2bd/src/interaction_composition.rs:5310] + evidence: seed `\.unwrap\(\)|\.expect\(` = 408 hits (sampled: 47 of 408);`let _ = |\.ok\(\);` = 9 (the other eight are deliberate best-effort cleanup with follow-up polls or shutdown joins);`\bpanic!\)...` = 4 (all in the tests module);`enum \w*Error` = 6 + +## serde +- clean: seeds run: `derive\([^)]*(De)?[Ss]erialize` = 5, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 10, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 71; the five `#[derive(Deserialize)]` request structs use `#[serde(default)]` Option fields for service-consumed messages (absent/null conflation acceptable there),and no hand-written deserializer exists. + +## obs +- clean: seeds run: `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 13 (one hit is the substring `log::` inside `ApiCatalog::`, not a log site); all real events use named fields (e.g. 929-931, 1067-1069, 5268-5325), no interpolated messages,and no secrets in fields. + +## docs +- clean: seeds run: `^\s*pub (fn|struct|enum|trait|const|type)` = 97, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 107; spot reads of the pub surface (RegisteredInteractionSession methods, CoreDisplayResourceEvidence::from_committed_policy, InteractionListenerSet methods, the Seed*PrincipalAllocation/HostAccounts APIs( all carry one-line first-sentence docs; no canonical-section-needing item surfaced in the sample + + + +## perf +- clean: seeds run: `format!\(` = 48, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 53, `\.to_string\(\)` = 15; all allocation sites are error paths, one-shot diagnostics, listener-path/key building,and daemon-owned string boundaries (cold per static read),no hot-loop `format!` or grow-by-push pattern found (static (unmeasured() + +## conc +- clean: seeds run: `std::thread::|thread::spawn|thread::scope` = 3 (one is the sanctioned `synchronous path` `#[allow]` std::thread::sleep at 6194, two are test-loop yields), `\bMutex<|\bRwLock<` = 1 (a test Backend fixture), `Atomic\w+|Ordering::` = 32 (stop flag stores Release/loads Acquire,reservation counter uses AcqRel; no weak ordering misuse found), `thread_local!|unsafe impl (Send|Sync) for` = 0 + +## async +- d2bd-p5#3 sev=medium blast=leaf effort=M verdict=actionable - `admit_interaction_socket`'s per-request dispatch holds the daemon-global `runtime` lock (the `AsyncMutex>`( across the whole `.await` of `dispatch_component_request_for_session`, serializing every Zone's sessions andthe VM-start display reconcile behind one contended lock; the code itself records this as a residual at 5518-5529 - fix: per the recorded note, hand out a per-Zone handle (`BTreeMap>>`) cloned under the outer lock,and move the sync-seat methods off their global lock, adding the named concurrency test - [packages/d2bd/src/interaction_composition.rs:5518-5530] + evidence: seed `async fn|async move|\.await` = 302 hits (sampled: 44 of 302);`tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 7, `tokio::sync::(Mutex|RwLock|Notify)` = 1 (the `AsyncMutex` alias at 93), `#\[tokio::(main|test)\]|Runtime::block_on` = 10; the guard-hold across `.await` is observed at 5530 onward, documented as deliberate-but-unfixed at 5518-5529 + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; all zero; the partition declares no unsafe blocks/fns/impls, so the lens criteria fail. + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; all zero; no FFI surface in this partition. + +## macro +- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; all zero; no macro definitions or expansions in these files. + +## test +- clean: seeds run: `#\[test\]|#\[tokio::test\]` = 95, `assert_eq!\(|assert_ne!\(|assert!\(` = 430 (sampled: 48 of 430), `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the sampled assertions (src test modules and tests/** integration files( assert behavior, error variants, statuses,and outcomes with human-written expected values and contextual failure messages; tests use tempdirs and fixed poll counts, no network dependency,and every sampled test can fail on a real behavior change + +## Coverage +- idiom: clean (seeds ran: 7/0/7) +- own: 1 finding(s) +- type: clean (seeds ran: 4/0/0) +- api: clean (seeds ran: 97/1/1) +- err: 1 finding(s) +- serde: clean (seeds ran: 5/10/0/71) +- obs: clean (seeds ran: 0/0/0/13) +- docs: clean (seeds ran: 97/0/107) +- perf: clean (seeds ran: 48/53/15) +- conc: clean (seeds ran: 3/1/32/0) +- async: 1 finding(s) +- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe blocks) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test: clean (seeds ran: 95/430/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md new file mode 100644 index 000000000..fc614dc83 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md @@ -0,0 +1,77 @@ +# d2bd-p6 - d2bd - part 6/8 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10772 (excl. src/generated/**) | modules: resource_plane_v3, provider_lifecycle, credential_resource_runtime, resource_runtime/plane_controller_bridge +Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: src/resource_plane_v3.rs, src/provider_lifecycle.rs, src/resource_runtime/**, src/credential_resource_runtime.rs + +## idiom +- d2bd-p6#1 sev=low blast=leaf effort=S verdict=actionable - `registered_service_decl` (provider_lifecycle) and `registered_service_factories` (resource_plane_v3) are 15-arm `if ... else if` chains over `&'static str` equality where a `match` reads as a table, gets exhaustiveness-free fallthrough by construction, and does not re-test the winner's earlier arms - fix: convert both chains to `match service { PROCESS_EFFECTS_SERVICE.id => ..., ... , _ => None/continue }`, keeping the `as Arc` coercions on the factory arms - [packages/d2bd/src/provider_lifecycle.rs:78, packages/d2bd/src/resource_plane_v3.rs:2226] + evidence: idiom seeds `for \w+ in 0\.\.`/`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`/`let mut \w+ = (String|Vec)::new\(\)` = 6/1/8 hits (the three index-loop hits and all eight `Vec::new` accumulators are bounded wait loops and topped-up listings with early exits that an iterator pipeline would obscure; the only hand-impl hit is a test `Default`); the two if-else chains were read whole at the cited lines, not seed-caught +- clean: none of the flagged classes otherwise - the `for _ in 0..N` hits are bounded poll waits (tests), the `Vec::new` hits are partition/plan listings with early returns. + +## own +- clean: seeds `\.clone\(\)`/`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`/`Rc<|RefCell<|Arc>` (ProviderAgentAuditLog, provider_lifecycle.rs:439) is a genuinely shared sync-only sink fed through the envelope. + +## type +- clean: seeds `fn validate_\w+|fn check_\w+`/`is_\w+: bool|\w+_flag: bool`/`(mode|kind|state): String` = 2/0/0 hits - both validation fns are boundary gates (`validate_request_scope` on a test-only wire reader, `check_registry_catalog` as a startup invariant), no flag-soup fields or stringly-typed state in the four files. + +## api +- d2bd-p6#2 sev=low blast=leaf effort=S verdict=actionable - `ResourcePlaneV3::targets`/`hub`/`store`/`registry` return `&Arc`, exposing refcount plumbing in the accessor surface and forcing the two callers that need the shared handle to clone through the reference - fix: return `&TargetDirectory`/`&SpecStore`/`&PlaneResourceRegistry` from the borrow-only accessors and `Arc`/`Arc` by value from `hub()`/`targets()`, then update `Arc::clone(plane.hub())` at resource_runtime.rs:4423 and `Arc::clone(plane.targets())` at composition.rs:11250 to `plane.hub()`/`plane.targets()` - [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2bd/src/resource_plane_v3.rs:3295, packages/d2bd/src/resource_plane_v3.rs:3301, packages/d2bd/src/resource_plane_v3.rs:3308] + evidence: api seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 8 hits; census: `\.hub\(\)` over packages/ (excl. generated) = 1 hit (resource_runtime.rs:4423), `\.targets\(\)` = 4 hits (composition.rs:11121,11143,11158,11250), `\.store\(\)` in-lane = 3 test hits - the two `Arc::clone)..)` call sites cited are the load-bearing ones +- clean: no internals leak beyond the `&Arc` accessors - `client()` returns `&ResourceManagerClient`, `pub use` seed = 0, module surface is `pub(crate)` per lib.rs:16-17, and the `Arc` fields of `ConstructionInputs` are genuine shared facet ownership with documented callers. + +## err +- d2bd-p6#3 sev=medium blast=leaf effort=M verdict=actionable - `PlaneError` carries five `String` variants (`FoundationSeed`, `ManagerSpawn`, `Authority`, `Target`, `Bundle`) that wrap the inner error with `error.to_string()`/`format!` at every production site, dropping the source chain the enum's `#[from]` variants already preserve for `SpecStore`/`ProviderRegistration`/`ManagerRpc` - callers of `ResourcePlaneV3::prepare` cannot distinguish a refused spec-store open from a create failure without string-matching - fix: give each String variant a typed payload or `#[source]` (e.g. `PlaneError::Authority(#[from] d2b_core::loader_worker::Error)` where `SpecStore::open` already yields `SpecStoreError` through `#[from]`, and keep the stage word in the `Display` message, not the variant), deleting the `to_string()` wraps at the cited sites - [packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/resource_plane_v3.rs:3016, packages/d2bd/src/resource_plane_v3.rs:3025, packages/d2bd/src/resource_plane_v3.rs:3346, packages/d2bd/src/resource_plane_v3.rs:3081] + evidence: err seed `enum \w*Error` = 2 hits (PlaneError, ProviderStartupError); err seed `\.unwrap\(\)|\.expect\(` = 390 hits, sampled: 49 of 390 (every 8th) - zero production hits below the test-mod boundaries; the String wraps were read at the cited lines (map_err to_string cluster: 2568, 3081, 3109, 3131, 3244-3275, 3346) +- d2bd-p6#4 sev=low blast=leaf effort=S verdict=actionable - `ConstructionInputs::production` swallows the `attach_process_providers` Result at the compose-once fallback, so a `StateUnavailable` collision (or a future attach failure) silently leaves whichever instance won in the shared slot, and the plane keeps composing with its own instance either way - fix: `state.provider_runtime.attach_process_providers(Arc::clone(&providers)).map_err(|error| PlaneError::Authority(error.to_string()))?` (or a dedicated variant), matching the site's other rejections - [packages/d2bd/src/resource_plane_v3.rs:1956] + evidence: err seed `let _ = |\.ok\(\);` = 3 hits (339 is the documented idempotent store attach; 5324 is test code); the swallowed call is the only production `let _ =` on a fallible Result - read against attach_process_providers' sole `StateUnavailable` error at provider_registry.rs:471-484 +- clean: panic policy is sound in production - `\bpanic!\(|...` = 26 hits, all inside the `#[cfg(test)]` modules (canonical-builder helpers and bounded wait loops); err4 both enums are typed with documented variants, and `ProviderStartupError::code()` keeps stable refusal names. + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize`/`serde\((rename_all|...)\)`/`impl .*Deserialize.*for`/`serde_json::from_|serde_json::to_` = 0/0/0/63 hits - the 63 decode/encode sites are canonical-JSON boundary reads and test fixtures: production sites decode store-derived or bundle-verified bytes with `.ok()?`/`map_err` guards (no untrusted-input deserialization in this scope), and no hand-written `Deserialize` impls live here; the ~40 `from_value(json!({...}))` hits are literal test payloads. + +## obs +- d2bd-p6#5 sev=low blast=leaf effort=S verdict=actionable - `publish_trusted_context`'s failure arm interpolates the error into the message (`"trusted-context publication refused: {error}"`) while the sibling `Ok(_)` arm and every other event in the file carry named fields, so the failure reason is not queryable as a column - fix: move the error into a field (`error = %error, "trusted-context publication refused"`), matching the adjacent arms and the plane's other warn sites - [packages/d2bd/src/provider_lifecycle.rs:1085] + evidence: obs seed `(info|debug|warn|error|trace)!\("[^"]*\{` = 0 hits (the macro call opens on the next line, so the seed misses it); obs seed `tracing::|log::` = 25 hits, all 25 read - this is the only message-interpolation site in the scope +- clean: zero `println!`/`eprintln!` hits; no `#[instrument]` spans but every event carries named fields (`zone`, `revision`, `operation`, `error = %error`), and errors are logged only at the boundary that resolves them. + +## docs +- d2bd-p6#6 sev=low blast=leaf effort=S verdict=actionable - four public items in the plane's most-documented file are undocumented while their siblings carry `///` contracts: `PlaneResourceRegistry::new()`, `ZoneAuthorityInputs::controller_generation`, and the three fields of `BundleIngestReport` - fix: add the one-line contract each (constructor convenience, the zone authority's controller generation source, and per-field "the rows this ingestion applied/removed/protected") - [packages/d2bd/src/resource_plane_v3.rs:292, packages/d2bd/src/resource_plane_v3.rs:1770, packages/d2bd/src/resource_plane_v3.rs:3432] + evidence: docs seed `^\s*pub (fn|struct|enum|trait|const|type)` = 22 hits, all read - 18 carry doc comments; the four gaps are the cited lines; `/// # (Examples|Errors|Panics|Safety)` = 0 and `-> Result<` = 0 (line-broken signatures), and canonical sections are not required for this `pub(crate)` module surface per the card's internal-crate carve-out +- clean: no other public item in the scope lacks a first-sentence contract; module docs exist in all four files. + +## perf +- clean: seeds `format!\(`/`Vec::new\(\)|...`/`\.to_string\(\)` = 40/89/21 hits, all read - the `format!` hits are error paths, refusal-reason rendering, and test literals; the `Vec::new`/`BTreeMap::new` hits are startup planning listings, bounded drain windows, and test fixtures; the `to_string` hits are `map_err` conversions (the err finding #3's subject) - nothing sits on a hot path, and every loop here is bounded (drain windows, budget polls); static (unmeasured). + +## conc +- clean: seeds `std::thread::|...`/`\bMutex<|\bRwLock<`/`Atomic\w+|Ordering::`/`thread_local!|unsafe impl (Send|Sync) for` = 0/17/45/0 hits - the 17 `Mutex` sites are `tokio::sync::Mutex` over shared maps and gates with brief guards (never held across a fallible await), the 45 atomic hits are `Relaxed` counters/flag in `AnchorSubscriptionState` (the weakest correct ordering for test-observable counters) plus test counters, and `SeqCst` appears only in test assertions; no `unsafe impl Send/Sync`, no threads spawned in this scope; the `drain_order` `try_lock` fail-closed view is documented at provider_lifecycle.rs:1042-1044. + +## async +- clean: seeds `async fn|async move|\.await`/`tokio::spawn|...`/`tokio::sync::(Mutex|RwLock|Notify)`/`#\[tokio::(main|test)\]|Runtime::block_on` = 564/4/22/3 hits; sampled: 47 of 564 (every 12th) plus full reads of the 4 spawn sites, 22 tokio-sync sites and 3 test attributes - no blocking work inside async context (SQLite open and store migration run on the sanctioned `d2b_core::loader_worker` bounded seat per the KTD2 comment at `prepare`), no std-sync guard spans an await (the single-flight `tokio::sync::Mutex` gate in `ComponentCredentialSession` is the correct shape), `tokio::spawn` is limited to the one long-lived subscription task, and waits are bounded (`timeout_at` windows, budget polls). + +## unsafe +- clean: seeds `\bunsafe \{|...`/`// SAFETY:`/`transmute|from_raw|MaybeUninit|mem::zeroed`/`unsafe_code` = 0/0/4/0 hits - all four `from_raw` hits are safe functions (`Mode::from_raw_mode`, `std::io::Error::from_raw_os_error`), so the scope contains no `unsafe` block, no `unsafe fn`, and no unsafe-code lint exception; the ledger's enumeration (U1 section d 8) needs no new entry from this lane. + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)` or `CStr`/`CString`/`c_char` anywhere in the scope - the anchored-fd API is exercised through `rustix` safe facades only). + +## macro +- N/A (seeds: 0/0/0/0 all zero; no `macro_rules!` definitions, no proc-macro or `$crate` usage - the only macros are `include!`d generated registrations and std macros). + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]`/`assert_eq!\(|assert_ne!\(|assert!\(`/`proptest!|insta::assert|rstest`/`#\[ignore\]` = 13/202/0/0 hits; sampled: 41 of 202 (every 5th) plus all 13 test attributes - assertions target behavior with messages (refusal codes, applied/removed counts, revisions, projection state), use `matches!` on variants before any Display check, and wait on deterministic poll loops with bounded budgets; no ignored tests, no property/snapshot tooling, no network or wall-clock dependence beyond bounded sleeps. + +## Coverage +- idiom: 1 finding +- own: clean (seeds ran: 220/171/1/0) +- type: clean (seeds ran: 2/0/0) +- api: 1 finding +- err: 2 findings +- serde: clean (seeds ran: 0/0/0/63) +- obs: 1 finding +- docs: 1 finding +- perf: clean (seeds ran: 40/89/21) +- conc: clean (seeds ran: 0/17/45/0) +- async: clean (seeds ran: 564/4/22/3) +- unsafe: clean (seeds ran: 0/0/4/0; all four hits are safe `from_raw*` functions, no unsafe code in scope) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface in the assigned files) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions or proc-macro usage) +- test: clean (seeds ran: 13/202/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md new file mode 100644 index 000000000..782629897 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md @@ -0,0 +1,83 @@ +# d2bd-p7 - d2bd - part 7/8 +Baseline: 6ebdd4cec | LOC audited: 10662 (excl. src/generated/**) | modules: process_provider_runtime, provider_effects, effect_service_actors, main, guest_target_session, lib +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/process_provider_runtime.rs, src/provider_effects.rs, src/effect_service_actors.rs, src/main.rs, src/guest_target_session.rs, src/lib.rs + +## idiom +- d2bd-p7#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default` on both unit-struct actors (`EffectServiceActor`, `EffectServiceSupervisor`) delegates to `Self::new()` with zero call sites anywhere; a derive emits the same impl and cannot drift - fix: replace both with `#[derive(Default)]` (or delete both; no workspace caller) - [packages/d2bd/src/effect_service_actors.rs:268, packages/d2bd/src/effect_service_actors.rs:411] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits (both Defaults); census: `EffectServiceActor::default|EffectServiceSupervisor::default` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 0 hits +- clean: seeds `for \w+ in 0\.\.` = 1 (test poll loop, esa:768), hand-written impls = 2, `let mut \w+ = (String|Vec)::new\(\)` = 1 (ppr:333, ordered required/optional field list with helper closures; pipeline not applicable); hand-written Debug impls at ppr:244/485/852 are deliberate redactions (ManagedResource/ControllerBootstrapContext/ProductionProcessProviders hide identities) - checked. + +## own +- d2bd-p7#2 sev=low blast=leaf effort=S verdict=actionable - `match context.owner_uid.clone()` at ticket assembly clones the whole `Option` (a String-backed uid) on every launch, including the `None` arm and the guard-false `Some` arm where the value is never consumed - fix: match on `&context.owner_uid` and clone inside the arm (`Some(owner_uid) if ticket.owner_uid().is_none() => ticket.with_owner_uid(owner_uid.clone())`), so the `_ => ticket` path copies nothing - [packages/d2bd/src/process_provider_runtime.rs:4057] + evidence: sampled: 50 of 276 `.clone()` hits (seeds 2-4: 178/1/0); remaining clones are struct construction from borrowed contexts, Arc clones at spawn boundaries, error-payload clones, and two bounded rollback snapshots (provider_effects.rs:973,1016, map capped by MAX_TRACKED_LIFECYCLE_MUTATIONS = 256) +- clean: `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 178 hits, `Rc<|RefCell<|Arc` - shared factory across respawns, genuinely shared, kept) +- clean: `^\s*pub use ` = 0 hits; re-exports live in composition.rs (outside this partition); the effect-service surface (`EffectServiceRow`, `EffectServiceBinding`, `EffectServiceSupervisorMsg`) sits in a `pub(crate)` module; `ProviderLifecycleEffectPort` has a small required surface (1 required + 1 defaulted method) - checked. + +## err +- d2bd-p7#4 sev=medium blast=leaf effort=S verdict=actionable - a durable service row that fails to (re)spawn is silently dropped: `let _ = state.spawn_service_actor)...)` in both the supervisor's restart-recovery loop and `supervise_exit` leaves a declared effect service unhosted with no trace, contradicting the module's own respawn promise (a crashed or killed service actor is respawned from its durable row; never leaves a service unhosted) - fix: log `tracing::warn!` with service/zone/error on spawn failure at both sites, keeping the non-fatal recovery semantics - [packages/d2bd/src/effect_service_actors.rs:551, packages/d2bd/src/effect_service_actors.rs:610] + evidence: seed `let _ = |\.ok\(\);` = 57 hits; sites 551/610 judged per the per-site rule (the esa:564-570 oneshot `reply.send)...).ok()` sites are deliberate requester-gone ignores, kept); sibling pattern at ppr:804-809 shows the house rule is to warn on best-effort failures that matter +- d2bd-p7#5 sev=low blast=leaf effort=S verdict=actionable - the 0700 enforcement on a serving worker's socket parent is silently swallowed with `let _ =`; the sibling `create_dir_all` failure just above is a hard error, so a failed `set_permissions` leaves the launched socket dir at default umask perms with no diagnostic - fix: replace `let _ = tokio::fs::set_permissions)...)` with a `tracing::warn!` on Err, mirroring the pidfd snapshot warn at ppr:804-809 - [packages/d2bd/src/process_provider_runtime.rs:3436] + evidence: seed `let _ = |\.ok\(\);` = 57 hits; site 3436 judged; house best-effort-warn pattern at ppr:804-809 +- clean: seed `\.unwrap\(\)|\.expect\(` = 435 hits, of which 433 are inside cfg(test) or test-support constructors (exempt); the two production sites (ppr:4310, ppr:4326) are invariant expects the compiler cannot see (`[u8; 32]` hash prefix slicing and `ResourceUid::from_bytes`, which forces version/variant bits before parsing - parse cannot fail), acceptable per the panel policy; `panic!`/`unreachable!`/`todo!`/`unimplemented!` = 4, all in test modules; no error-taxonomy defect in the part's three error enums - checked. + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 2, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 14, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 49; the only serde types are `LifecycleMutationStatus` (lowercase) and `PersistedLifecycleMutation` (camelCase + `deny_unknown_fields` + `#[serde(default)]`/`alias` for rollback-compatible migration of legacy rows, provider_effects.rs:651-690) - the persisted schema choices are deliberate and documented; spec serialization is stable field-order `to_vec` for ticket digests - checked. + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 6 (all in main.rs: banner, error reporting, and the principal-allocation CLI diagnostic - product output per the carve-out), interpolated-message events `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::` = 10; all tracing events carry named fields (vm, role, zone, error, mismatches, resource, identity); the binary installs the subscriber exactly once (main.rs:146-152) with EnvFilter; no secret material reaches any field (`identity` fields are hex digests; `ResourceUid` prints redacted by its own Display) - checked. + +## docs +- d2bd-p7#6 sev=low blast=leaf effort=S verdict=actionable - the crate root carries no `//!` module doc: lib.rs opens with the lint attribute only, and the included composition.rs begins with a plain `//` comment, so the crate's large public surface (pub mods, dozens of pub use re-exports) renders without any module-level description - fix: add a `//!` crate doc in lib.rs naming the daemon composition facets and pointing at the daemon contract references - [packages/d2bd/src/lib.rs:1, packages/d2bd/src/composition.rs:1] + evidence: static (no `//!` line in lib.rs:1-19 or composition.rs:1-40) +- d2bd-p7#7 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors`/`# Panics` section exists anywhere in the part (0 hits) while `-> Result<` appears 121 times, including on the pub surface (`FixedEffectAdapter::validate_instance`, `dispatch`, `ProviderLifecycleDispatch::new_persistent`, `admit`, `EffectServiceBinding::call`/`call_expected`, `DaemonGuestTargetSession::request`); prose paragraphs describe the happy path but failure conditions are not structurally stated - fix: add `# Errors` sections naming refusal conditions to the pub Result-returning items of the two pub mods, keeping the existing prose - [packages/d2bd/src/provider_effects.rs:91, packages/d2bd/src/provider_effects.rs:711, packages/d2bd/src/provider_effects.rs:804, packages/d2bd/src/effect_service_actors.rs:201, packages/d2bd/src/guest_target_session.rs:37] + evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed `-> Result<` = 121 hits +- clean: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 83 hits; every top-level pub item in the part carries a doc comment with a first-sentence contract (spot-checked the full public surface, including the flagged-method set at ppr:1024-1064); `FIXED_PROCESS_PROVIDER_NAMES`, `MAX_TRACKED_LIFECYCLE_MUTATIONS`, `EffectServiceRow`, and both actor types are documented with their why - checked. + +## perf +- d2bd-p7#8 sev=low blast=leaf effort=S verdict=actionable - `resource_identity_fields` builds a `Vec` with exactly 12 statically-known pushes on every launch/adoption pass but grows from an empty `Vec::new()` - fix: `let mut fields = Vec::with_capacity(12);` (6 required + 6 optional entries) - [packages/d2bd/src/process_provider_runtime.rs:333] + evidence: static (unmeasured); seed `Vec::new\(\)` = 56 hits, of which this is the one grow-by-push candidate with a fixed bound +- clean: seeds `format!\(` = 87, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 56, `\.to_string\(\)` = 16; remaining format! sites are error strings, ticket-digest contexts, and launch-argv assembly (cold paths); no format! inside a loop, no attacker-keyed hashing, no grow-in-loop collections besides the finding - checked. + +## conc +- d2bd-p7#9 sev=low blast=leaf effort=S verdict=actionable - two standalone monotonic counters use stronger orderings than the weakest correct one: the effect-service binding revision does `load(Ordering::SeqCst)` (esa:174) and `fetch_add(1, Ordering::SeqCst)` (esa:509), and `next_desired_generation` uses `fetch_update(Ordering::AcqRel, Ordering::Acquire, ...)` (provider_effects:1064); the revision is a version tag used only in equality staleness checks and the generation is a unique-value mint, so `Ordering::Relaxed` is correct for both - fix: switch the revision load/fetch_add and the generation fetch_update to `Ordering::Relaxed` - [packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs:509, packages/d2bd/src/provider_effects.rs:1064] + evidence: seed `Atomic\w+|Ordering::` = 120 matching lines in lane (9 production sites examined; remaining mass is test-mod recorders); no unsafe Send/Sync impls, no thread_local, no std threads in the part (seed 4 = 0, seed 1 = 0) +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 6 (all tokio::sync::Mutex state tables; `await_holding_lock`/`await_holding_refcell_ref` denied workspace-wide), `thread_local!|unsafe impl (Send|Sync)` = 0; the only shared state is the tokio Mutex tables and atomics above - checked. + +## async +- clean: seeds `async fn|async move|\.await` = 231, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 4 (actor spawns), `tokio::sync::(Mutex|RwLock|Notify)` = 5, `#\[tokio::(main|test)\]|Runtime::block_on` = 7; production state tables are `tokio::sync::Mutex` (ppr:18,937-940); the controller-bootstrap wait uses the sanctioned AsyncFd + `tokio::time::timeout` shape (ppr:95-100); the sync `LivenessProbe::probe` seat drives its future via `crate::drive_sync` (`block_in_place` + `handle.block_on`, inline `#[allow(clippy::disallowed_methods, reason = "synchronous path")]`, composition.rs:210-215) and is documented as the U13/R11 sync caller - no guard held across await, no blocking call on an executor worker, no cancellation-loss site found in the part; `EffectServiceBinding::send` awaits the reply oneshot without a deadline, but the production caller (forward_rendezvous) wraps dispatch in `tokio::time::timeout(handler_deadline, ...)` so a hung service surfaces as `forward-timeout`, and in-flight actor death closes the oneshot - checked. + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; no unsafe blocks/fns/impls and no unsafe_code attribute in the six files; d2bd inherits workspace `unsafe_code = "forbid"`) + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the part declares no foreign boundary) + +## macro +- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macro definitions or proc-macro surface in the part) + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 66, `assert_eq!\(|assert_ne!\(|assert!\(` = 255, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0 (scope: in-file tests in the six assigned files; `tests/**` integration targets are shared crate-wide and outside this partition); the in-file suites assert behavior - dedup counting (provider_effects:1783-1791), TTL and persist-failure release, restart/migration determinism with hand-worked expectations, supervision respawn with revision bumps, GPU/TPM argv pinning - with no same-logic expected values or Display-string error asserts found in the sampled assertions, and the only poll helper is bounded (200 iterations, esa:768) - checked. + +## Coverage +- idiom: 1 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 6/0/0; admission/policy checks with caller-actionable failures, no parse-once candidate) +- api: 1 finding(s) +- err: 2 finding(s) +- serde: clean (seeds ran: 2/14/0/49; deliberate migration-aware persisted schema) +- obs: clean (seeds ran: 6/0/0/10; named-field events, CLI output carve-out) +- docs: 2 finding(s) +- perf: 1 finding(s) +- conc: 1 finding(s) +- async: clean (seeds ran: 231/4/5/7; sanctioned sync seats, tokio state tables, deadline at the rendezvous caller) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe constructs in the part) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test: clean (seeds ran: 66/255/0/0; behavior-focused in-file suites, no non-failable assertions found) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md new file mode 100644 index 000000000..9de720645 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md @@ -0,0 +1,88 @@ +# d2bd-p8 - d2bd - part 8/8 +Baseline: 6ebdd4cec | LOC audited: 10828 (excl. src/generated/**) | modules: forward_rendezvous, shared_provider_effects, provider_registry, audio_dispatch +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: file-split part (forward_rendezvous.rs, shared_provider_effects.rs, provider_registry.rs, audio_dispatch.rs) + +## idiom +- d2bd-p8#1 sev=low blast=leaf effort=S verdict=actionable - no-op `let _ =` suppression statements with dead bindings: `let _ = &mut chain;` after the chain re-root (no mutation follows), `let _ = kind;` masking the unused `kind` param of `network_content_fence`, and `let _ = error.code();` masking the unused `error` in the `Refused` arm - fix: delete the statements and bind the now-unused pattern args as `_` / drop the `kind` param - [packages/d2bd/src/forward_rendezvous.rs:672, packages/d2bd/src/shared_provider_effects.rs:1156, packages/d2bd/src/provider_registry.rs:531] + evidence: seed `let _ = |\.ok\(\);` = 9 hits (3 are these no-ops; the rest are deliberate ignores of `OnceLock::set` results and test channel sends); production parts of all four files read in full +- d2bd-p8#2 sev=medium blast=leaf effort=S verdict=actionable - `reconcile_security_key` (SecurityKeyComponent::Service) acquires the Zone runtime with `let runtime = self.runtime()?;` that no branch uses; `let _ = runtime;` masks it, and `runtime()` (a try_lock spin, see d2bd-p8#17) returns `Unavailable` when the plane is absent, so a Service reconcile that never reads the plane fails spuriously - fix: delete the `let runtime = ...` and `let _ = runtime;` lines - [packages/d2bd/src/shared_provider_effects.rs:1903, packages/d2bd/src/shared_provider_effects.rs:1997] + evidence: seed `let _ = |\.ok\(\);` = 9 hits (1997 is a no-op masking an unused value); read of the Service branch body confirms `runtime` is used in no path +- d2bd-p8#3 sev=low blast=leaf effort=S verdict=actionable - redundant let-else plus a provably-dead second match and `unreachable!` in `ProviderRuntime::dispatch_lifecycle`: the `else` of `let ProviderRuntimeState::Active(active) = ...` re-matches `&*state` and its `Active(_) => unreachable!)...)` arm can never fire - fix: collapse the else to `return Err(ProviderEffectError::RegistryUnavailable)` - [packages/d2bd/src/provider_registry.rs:527-536] + evidence: seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 24 hits (this is the only production `unreachable!`; the rest are test fixtures) +- d2bd-p8#4 sev=low blast=leaf effort=M verdict=actionable - statement-style `Vec::new()` + push loops that are iterator shapes: `deploy_target_local_controllers` filters on component type / instance scope / target kind then pushes, and `dispatch_audio_status` partitions `Result` into `entries` and `errors` - fix: `manifest.components().iter().filter)...).map)...).collect::, _>>()?` and `vm_names.iter().map)...).partition(Result::is_ok)` - [packages/d2bd/src/provider_registry.rs:359-390, packages/d2bd/src/audio_dispatch.rs:392-411] + evidence: seed `for \w+ in 0\.\.` = 3, seed `let mut \w+ = (String|Vec)::new\(\)` = 2 + +## own +- d2bd-p8#5 sev=low blast=leaf effort=S verdict=actionable - avoidable `let zone = request.zone.clone();` in `ForwardRendezvous::invoke`: `zone` is used only as the `BTreeMap::get` key inside the `self.zones.lock().await` block, whose scope does not outlive the `request` borrow, so `zones.get(&request.zone)` compiles without the clone - fix: drop the clone and borrow `&request.zone` - [packages/d2bd/src/forward_rendezvous.rs:456, packages/d2bd/src/forward_rendezvous.rs:458-466] + evidence: seed `\.clone\(\)` = 217 hits (sampled: 50 of 217; production parts read in full, this is the one avoidable production clone found); read confirms `zone` is unused after the lock block +- d2bd-p8#6 sev=low blast=leaf effort=S verdict=actionable - `validate_network_config_volume_spec` clones the whole JSON `spec` document (`let mut base = spec.clone();`) just to strip three fields and re-parse as `VolumeSpec`; on the `upsert_volume_content` path the document is cloned again at the caller, so the same wire document is cloned and re-parsed twice per reconcile/readiness check - fix: take the spec by ownership once at the boundary and parse to `VolumeSpec` directly (drop the clone by passing the already-owned `Value`) - [packages/d2bd/src/shared_provider_effects.rs:690, packages/d2bd/src/shared_provider_effects.rs:854-858, packages/d2bd/src/shared_provider_effects.rs:891-895] + evidence: seed `\.clone\(\)` = 217 (shared_provider_effects.rs = 109 hits; production part read in full); callers of `validate_network_config_volume_spec` read at 850-897 + +## type +- d2bd-p8#7 sev=medium blast=leaf effort=S verdict=actionable - stringly-typed wire mode compared to string literals: `request.spec.pointer("/mode").and_then(Value::as_str) == Some("authority")` (USBIP service) and `mode == "projection"` (security-key service); an unknown or misspelled mode silently takes the non-authority / non-projection branch, flipping the admission posture without an error - fix: parse the mode once into a typed enum (`#[derive(Deserialize, PartialEq)]` with `rename_all = "kebab-case"`) at the effect boundary and refuse unknown values (fail closed) - [packages/d2bd/src/shared_provider_effects.rs:1299, packages/d2bd/src/shared_provider_effects.rs:1903-1908] + evidence: seed `fn validate_\w+|fn check_\w+` = 2; the mode state is reached via `/mode` JSON pointers (the direct-field spelling `(mode|kind|state): String` = 0 in this lane); both comparison sites read in full + +## api +- d2bd-p8#8 sev=low blast=leaf effort=S verdict=actionable - `pub use d2b_provider::{MAX_PROVIDER_REGISTRY_ENTRIES, ProviderRegistrySnapshot};` re-exports `ProviderRegistrySnapshot`, which nothing in d2bd uses; only `MAX_PROVIDER_REGISTRY_ENTRIES` is consumed (registry bound check) - fix: re-export `MAX_PROVIDER_REGISTRY_ENTRIES` only, removing the second path to `ProviderRegistrySnapshot` - [packages/d2bd/src/provider_registry.rs:48, packages/d2bd/src/provider_registry.rs:288] + evidence: census `ProviderRegistrySnapshot` over `packages/`, `nixos-modules/`, `tests/`, `docs/reference/`, `labs/`, `BUILD.bazel` = 6 hits, all in `d2b-provider` and this re-export itself; no consumer of the `d2bd::provider_registry::ProviderRegistrySnapshot` path + +## err +- d2bd-p8#9 sev=medium blast=wide effort=M verdict=needs-contract - user-input audio failures are flattened into `TypedError::InternalIo { context, detail }` strings on the mutation paths (VM absent, audio not enabled) in `dispatch_audio_set_volume` / `dispatch_audio_mute`, while the status path reports the same classes as structured `AudioVmError` + `AudioErrorKind::VmNotFound` / `AudioNotEnabled`; a caller of set-volume/mute cannot distinguish VM-not-found from an internal I/O failure except by string-matching the detail - fix: map the mutation paths onto the same structured kinds (extend `TypedError` with the audio kinds used by both paths); this changes the daemon-API wire error surface, so it is needs-contract - [packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, packages/d2bd/src/audio_dispatch.rs:417-438] + evidence: seed `\.unwrap\(\)|\.expect\(` = 269; read of both error paths; `TypedError` is the daemon-API wire error type (typed_error.rs:460+ `kind()`/`message()`) + +## serde +- d2bd-p8#10 sev=low blast=leaf effort=S verdict=actionable - `declared_fd_kind` allocates a `serde_json::Value::String(kind.to_owned())` heap value just to deserialize the wire `FdKind` enum (the kebab-case `serde` mapping) - fix: use `serde_json::from_str::(kind)` (no intermediate `Value`) or a plain `match` over the kebab-case spellings - [packages/d2bd/src/forward_rendezvous.rs:979-981] + evidence: seed `serde_json::from_|serde_json::to_` = 41 hits; site read in full + +## obs +- d2bd-p8#11 sev=low blast=leaf effort=S verdict=actionable - message-only `tracing::warn!("forward rendezvous is at its in-flight cap; refusing the call")` carries no fields and sits in a loop with no enclosing span, so the cap refusal cannot be attributed to a caller or the cap value - fix: add a field (`peer_uid`, `max = posture.max_inflight`) - [packages/d2bd/src/forward_rendezvous.rs:1250] + evidence: seed `(info|debug|warn|error|trace)!\("` = 1 hit (the only message-only event); `\bprintln!\(|\beprintln!\(` = 1 hit, a test `eprintln!` at forward_rendezvous.rs:4973 (out of scope) + +## docs +- d2bd-p8#12 sev=medium blast=leaf effort=S verdict=actionable - `pub fn dispatch_audio` is the only `pub` item in the lane without a doc comment; it is the daemon's audio dispatch entry with three op arms and non-obvious error behavior - fix: add a doc comment covering the op arms, the capability resolution, and the `TypedError` error surface - [packages/d2bd/src/audio_dispatch.rs:372] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 30 pub items over the four files; read of the pub-item list confirms every other one carries a doc contract +- d2bd-p8#13 sev=low blast=leaf effort=S verdict=actionable - doc-comment shape drift in forward_rendezvous.rs first sentences: double trailing periods and missing spacing (`The received descriptors,borrowed across the invocation..`, `attached:count equal`, `...kind the carrier vocabulary does not carry..`, `awaited for readiness..`) - fix: normalize punctuation/spacing in the affected comments - [packages/d2bd/src/forward_rendezvous.rs:1046-1049, packages/d2bd/src/forward_rendezvous.rs:1070, packages/d2bd/src/forward_rendezvous.rs:1093, packages/d2bd/src/forward_rendezvous.rs:1431-1432] + evidence: read of the doc comments at forward_rendezvous.rs:1040-1095, 1421-1432; `-> Result<` seed = 136 hits (all items with Result return either carry `# Errors`-style prose or are `pub(crate)` with documented contracts) + +## perf +- d2bd-p8#14 sev=low blast=leaf effort=M verdict=actionable - `AsyncSeqpacket::read_frame` allocates a fresh `vec![0u8; MAX_FRAME_SIZE + 5]` (1 MiB) per read, and `drain_pending` performs up to four such reads per refused call; the frame is length-prefixed, so the read buffer can be sized from the 4-byte prefix (or drained onto a reused buffer) instead of the full ceiling - fix: read the prefix, then allocate `declared + 5` - [packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476-1481] + evidence: seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 57; `MAX_FRAME_SIZE = 1024 * 1024` (d2b-contracts/src/lib.rs:63); static (unmeasured) +- d2bd-p8#15 sev=low blast=leaf effort=S verdict=actionable - grow-by-push vectors with known upper bounds: `guest_uids = Vec::new()` (bound `spec.attachments().len()`) and `entries`/`errors = Vec::new()` (bound `vm_names.len()`) - fix: `Vec::with_capacity()` - [packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.rs:392-396] + evidence: seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 57 hits; both sites read in full; static (unmeasured) + +## conc +- d2bd-p8#16 sev=low blast=leaf effort=S verdict=actionable - `Ordering::SeqCst` on the standalone `broker_epoch` atomic (store and load). The epoch is a self-contained value; the zones map it gates is mutex-guarded, so there is no paired publication needing Acquire/Release - `Ordering::Relaxed` is the weakest correct ordering here - fix: use `Ordering::Relaxed` at both sites - [packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414] + evidence: seed `Atomic\w+|Ordering::` = 13 hits; the two SeqCst sites and their ordering argument read in full (production atomics are otherwise Relaxed counters, and test atomics use Acquire/Release pairs for explicit handoff) + +## async +- d2bd-p8#17 sev=medium blast=leaf effort=M verdict=actionable - `ProductionSharedProviderEffects::runtime()` and `NetworkRuntime::bundle()` busy-wait with `std::hint::spin_loop()` on `tokio::sync::Mutex::try_lock()`; `runtime()` is called from async reconcilers (reconcile_network, reconcile_usbip, reconcile_tpm, ...), so a contended lock spins an executor worker instead of awaiting. The `// async-gate-allow` markers in this file cover the `.lock()` sites (recorded in async-gate-inventory.json:1165-1198) but these `try_lock`+spin sites are not marked or recorded, and the gate scanner matches `.lock()`/`.read()`/`.write()` only, so they are invisible to it. The in-code comment cites plan U10 / the broker rate limiter as the choice - fix: use `.lock().await` where the caller is async (split a sync lock path for the sync trait callers), or record these sites in the async-gate inventory as a deliberate exception - [packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_effects.rs:2633-2639] + evidence: seed `async fn|async move|\.await` = 452, seed `tokio::sync::(Mutex|RwLock|Notify)` = 24; read of runtime()/bundle() and their callers; async-gate-inventory.json:1165-1198 covers the `.lock()` sites only + +## unsafe +- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 4 (all safe `io::Error::from_raw_os_error` constructors, not unsafe `from_raw` calls), `unsafe_code` = 0 - no unsafe blocks/fns/impls and no unsafe_code settings in the lane + +## ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 - no FFI boundary in the lane + +## macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 - no macro definitions or proc-macro machinery in the lane + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 21, `assert_eq!\(|assert_ne!\(|assert!\(` = 180, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; checked the unit and `#[tokio::test(flavor = "multi_thread")]` suites in all four files - the rendezvous suite drives real seqpacket sockets across stalls, handler crashes, deadlines, in-flight caps, fd legs, attestation freshness/epoch invalidation, effect-service respawn and chain-recording, with multi_thread flavor on timing paths and generous bounds; the registry/audio suites assert behavior and error variants (never Display strings), and no test is unable to fail; no ignored or property tests exist (absence noted, not a finding) + +## Coverage +- idiom: 4 finding(s) +- own: 2 finding(s) +- type: 1 finding(s) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: 1 finding(s) +- docs: 2 finding(s) +- perf: 2 finding(s) +- conc: 1 finding(s) +- async: 1 finding(s) +- unsafe: N/A (seeds: 0/0/4/0 - the 4 `from_raw` hits are safe `from_raw_os_error` constructors; no unsafe blocks/fns/impls or unsafe_code settings) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test: clean (seeds ran: 21/180/0/0; no findings) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md new file mode 100644 index 000000000..7998d966d --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md @@ -0,0 +1,86 @@ +# d2bd-runtime-p1 - d2bd-runtime - part 1/4 +Baseline: 6ebdd4cec | LOC audited: 10715 (excl. src/generated/**) | modules: supervisor (dag, pidfd_table, readiness_liveness, state), typed_error, autostart, component_session_vsock, daemon_config, resource_api, zone_authority, shell_backend, broker_transport, public_read_model, vm_start_support, json_io +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/4: src/supervisor/**, src/typed_error.rs, src/autostart.rs, src/component_session_vsock.rs, src/daemon_config.rs, src/resource_api.rs, src/zone_authority.rs, src/shell_backend.rs, src/broker_transport.rs, src/public_read_model.rs, src/vm_start_support.rs, src/json_io.rs + +## idiom +- d2bd-runtime-p1#1 sev=low blast=leaf effort=S verdict=actionable - build_autostart_plan accumulates two Vecs with side-effect loops then extends a third, where an iterator pipeline partition would express the split - fix: replace the two push loops in build_autostart_plan with a collector pair: `let (net_entries, workload_entries): (Vec<_>, Vec<_>) = resolver.manifest.vms.iter().map(|(name, vm)| { ... }).partition(|e| e.is_net_vm);` then sort each half - [autostart.rs:228-245] + evidence: seed3 `let mut \w+ = (String|Vec)::new\(\)` = 10 hits; hit sites 228-229 are the statement-style split being judged (other hits are test fixtures or map-key builders) +- clean: seeds 1 `for \w+ in 0\.\.` = 4 (all fixed-count test loops in pidfd_table.rs:990-1015,1412-1415 - deliberate retry bounds), seed2 `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 (hand-written Default impls for AutostartConfig, ArtifactPaths, DaemonConfig, NodeBudget preserve fixed-path/invariant defaults a derive would break - justified), seed3 = 10 (one suspect site above, all other hits are owned map keys or test fixtures). + +## own +- d2bd-runtime-p1#2 sev=low blast=leaf effort=S verdict=actionable - DagExecutor::run_split clones `state` into api_ready then matches the same value by move, when matching `&state` would keep it - fix: `match &state { .. }`, bind `ApiReadyState::Error { reason }` by reference in the format! call, and set `api_ready = Some(state)` after the match - [dag.rs:423-424] + evidence: seed1 `\.clone\(\)` = ~75 hits; this clone is the only avoidable one (api_ready then match by move; the enclosing value is not used afterwards in the match arms other than the cloned copy) +- clean: seed2 `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = ~110 hits (map keys, Display/remediation strings, test fixtures - all explainable one-liners), seed3 `Rc<|RefCell<|Arc`, pushing an Arc + trait-object + the whole backend trait into the public field surface, when callers only need the three trait methods - fix: make the field private, add `handle_op`/`close_attachment`/`cancel_attachment` delegating methods on EstablishedShell, and update the d2bd/src/composition.rs call sites (13403,13460,13517,13625,13677)) - [shell_backend.rs:52-53] + evidence: seed2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits; census: `EstablishedShell` over packages/nixos-modules/tests/docs/reference/labs = 9 hits (5 cross-crate field reads in d2bd/src/composition.rs - the field is genuinely consumed, so the fix is delegation, not deletion) +- d2bd-runtime-p1#5 sev=low blast=leaf effort=S verdict=actionable - CachedPublicFrame is pub with pub fields (including a serde_json::Value dependency field)but only used inside public_read_model; the struct is dead public surface - fix: make CachedPublicFrame (and its fields) module-private or pub(crate, keep the ArcSwapOption slots private - [public_read_model.rs:51-53] + evidence: seed1 `^\s*pub (fn|struct|enum|trait|const|mod) ` = ~110 hits; census: `CachedPublicFrame` over packages/nixos-modules/tests/docs/reference/labs = 5 hits, all inside public_read_model.rs (lines 52,60,61,115,139) - no consumer outside the module +- clean: seed2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits (zone_authority.rs:181 new_coordinator Arc> - documented U17 shared handle with awaitable entry points; shell_backend.rs:53 - flagged above), seed3 `^\s*pub use ` = 1 (supervisor/pidfd.rs:3 re-export of the pidfd_table surface - house single-surface pattern) + +## err +- d2bd-runtime-p1#6 sev=high blast=leaf effort=S verdict=actionable - default_audit_join_context panics with `.expect("canonical broker zone digest")` on a wire-supplied digest - a malformed request from the broker client crashes the daemon instead of returning a refusal - fix: propagate the parse failure (e.g. `CanonicalAuditDigest::parse(zone_id).ok()?;` or map into TypedError::WireInvalidFrame/InternalConfig),and only attend None when digest missing route review-pass - [broker_transport.rs:63,65] + evidence: seed1 `\.unwrap\(\)|\.expect\(` = ~60 hits; production hits are only these 2 (both with wire-derived values via request.authoritative_audit_join()); every other hit sits in #[cfg(test)] modules or asserts a construction invariant (dag.rs:344,406, state.rs:403,411, pidfd_table.rs:496, typed_error.rs:1266) +- clean: seed2 `let _ = |\.ok\(\);` = ~30 (reply.send best-efforts in autostart.rs:394, test fixture joins, OnceLock::set one-shot setters, parent-dir sync best-effort - deliberate per site); seed3 `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = ~12 (all in #[cfg(test)] modules - test assertion style); seed4 `enum \w*Error` = ~10 (TypedError + four closed kind enums + ResourceRuntimeError, ZoneAuthorityError, ModeBoundBrokerError, DagError, PidfdTableError, ProcStatError, SnapshotStoreError - taxonomy split by caller action with wire_kind()/code()/label() accessors, no string-matching callers) + +## serde +- clean: seeds 1 `derive\([^)]*(De)?[Ss]erialize` = ~25, seed2 `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = ~30, seed3 `impl .*Deserialize.*for` = 1, seed4 `serde_json::from_|serde_json::to_` = ~20; config/snapshot types carry rename_all + deny_unknown_fields + per-field serde(default) with default_* fns consistent with hand-written Default; the only hand-written deserializer (ApiReadyState in dag.rs:89-108)is a deliberate wire admission gate over an untagged Helper enum for the `"yes"|"pending"|"timeout"|{"error": str}` shapes, round-trip tested at dag.rs:1058-1113 - not flagged + +## obs +- clean: seeds 1 `\bprintln!\(|\beprintln!\(` = 0, seed2 `(info|debug|warn|error|trace)!\("` = 0, seed3 `\.instrument\(|#\[instrument` = 0, seed4 `tracing::|log::` = ~25; every tracing event carries named fields (kind, path, detail, busid, vm, role, error, generation),the TypedError::log_raw_detail boundary logs the chain once with the unredacted detail deliberately kept out of the public envelope, and no secret/identifier-only fields beyond the ADR 0010/0028 redaction gate scope were found + +## docs +- d2bd-runtime-p1#7 sev=medium blast=leaf effort=S verdict=actionable - Three public helpers in json_io.rs carry no doc comments, though their semantics are non-obvious (absolute-vs-relative bundle path resolution, manifest-must-be-object) - fix: add one-line-then-detail doc comments (`# Errors` for the Result fns)on resolve_bundle_artifact_path and load_manifest - [json_io.rs:10,41] + evidence: seed1 `^\s*pub (fn|struct|enum|trait|const|type) ` = ~110 hits; spot-check of the file (65 LOC) found 2 undocumented pub items +- d2bd-runtime-p1#8 sev=medium blast=leaf effort=S verdict=actionable - Public fns in vm_start_support.rs lack docs while siblings are documented; role->mode mapping, tracked_role_id, and store-view-intent resolution are contract-relevant for the d2bd composition - fix: add one-line-first-sentence docs (+ `# Errors` for the Result fn)on vm_start_node_mode, tracked_role_id, resolve_store_view_intent_for_guest - [vm_start_support.rs:14,44,89] + evidence: seed1 = ~110 hits; full-file read (186 LOC) found 3 undocumented pub items (neighboring items have docs - inconsistent coverage) +- d2bd-runtime-p1#9 sev=medium blast=leaf effort=S verdict=actionable - ShellTerminalOp, ShellTerminalResponse,and EstablishedShell (a cross-crate contract type) carry no doc comments - fix: add doc comments naming each op/response variant's wire twin and the EstablishedShell lifetime/ownership contract - [shell_backend.rs:14,21,52] + evidence: seed1 = ~110 hits; item-list read of shell_backend.rs found 3 undocumented pub items (EstablishedShell is consumed by d2bd/src/composition.rs:13703) +- d2bd-runtime-p1#10 sev=medium blast=leaf effort=S verdict=actionable - Five broker_transport helpers (audit-join extraction, deadline arithmetic, kind extraction, two launcher redaction renderers)carry no docs, and two of them format operator-facing remediation strings - fix: add one-line-first-sentence docs naming input contracts and output shapes, with `# Panics` on default_audit_join_context identified - [broker_transport.rs:60,69,116,128,187] + evidence: seed1 = ~110 hits; targeted raw reads of broker_transport.rs found 5 undocumented pub fns (the file's other fns carry /// docs (e.g. dispatch_broker_request_to_socket, ModeBoundBrokerAdapter)) +- clean: seed2 `/// # (Examples|Errors|Panics|Safety)` = 0, seed3 `-> Result<` = ~55; Result-returning items mostly carry #-style contract prose in prose form; no doctests exist in this lane (acceptable: no pure example-worthy boundary items in the lane scope) + +## perf +- d2bd-runtime-p1#11 sev=low blast=family effort=M verdict=actionable - load_list/load_status clone the entire cached serde_json::Value frame per call (`then(|| cached.value.clone())`), making every public status/list poll allocate a full copy of the read-model frame - fix: return `Option>` (or `&Value` tied to the Arc swap guard)from load_if_fresh and let the wire renderer borrow the Value; update the d2bd composition call sites - [public_read_model.rs:117-118] + evidence: static (unmeasured) - no benchmark exists for the public-read path; seed1 `format!\(` = ~70 (all in error strings, remediation rendering, and test fixtures - cold paths), seed2 `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = ~15 (empty-case-common collection builds and test fixtures), seed3 `\.to_string\(\)` = ~110 (Display/error/remediation strings - the artifact is the text) + +## conc +- clean: seeds 1 `std::thread::|thread::spawn|thread::scope` = ~9 (autostart run_phase dedicated bounded worker threads per plan R4 (documented at autostart.rs:352-356)and test threads in pidfd_table/component_session_vsock), seed2 `\bMutex<|\bRwLock<` = ~9 (PidfdTable RwLock+mutation_lock Mutex serializing register/snapshot sequences, BrokerReapLog Mutex, InMemorySnapshotStore Mutex (test-only), FakeStarter/FakeRunner Mutexes (cfg(test))), seed3 `Atomic\w+|Ordering::` = ~25 (SNAPSHOT_TMP_COUNTER/next-id Relaxed counters, PidfdTable generation AcqRel/Acquire pairs, PublicStatusReadModel AcqRel/Acquire CAS publish loop - weakest correct orderings for the handoff each guards), seed4 `thread_local!|unsafe impl (Send|Sync) for` = 0; no manual Send/Sync claims, no shared-state-among-threads mis-model found + +## async +- clean: seeds 1 `async fn|async move|\.await` = ~90, seed2 `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = ~12 (JoinSet spawns in autostart run_phase and dag executor tests; `spawn_blocking` = 0 - dedicated threads per R4 replace it), seed3 `tokio::sync::(Mutex|RwLock|Notify)` = ~3 (zone_authority coordinator Mutex - guard held only across synchronous calls, documented U17), seed4 `#\[tokio::(main|test)\]|Runtime::block_on` = ~16 (tokio::test marks; block_on sites in shell_backend.rs:112,224,241 carry `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` - sanctioned blocking-census entries); no guard held across an await, no blocking call on an executor worker,and no cancellation-unsafe irreversible step found + +## unsafe +- clean: seeds 1 `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, seed2 `// SAFETY:` = 0, seed3 `transmute|from_raw|MaybeUninit|mem::zeroed` = 4 (all `rustix::process::Pid::from_raw` / `rustix::process::Signal::from_raw` safe constructors in pidfd_table.rs:401,744,808and state.rs:321 doc prose - no actual unsafe blocks/UB hazards), seed4 `unsafe_code` = 2 (documentation: state.rs:322and the daemon workspace lint inherit - no allow); the lane contains no unsafe code, so no SAFETY comments are owed + +## ffi +- N/A: seeds 1-4 all zero; no FFI surface exists in the assigned files (libc::c_int signal numbers are syscall-adjacent but never cross a foreign caller) + +## macro +- N/A: seeds 1 `macro_rules!` = 0, seed2 `proc_macro|syn::|quote!` = 0, seed3 `\$crate` = 0, seed4 `to_compile_error|new_spanned` = 0 all zero; no macro definitions or proc-macro machinery in the lane + +## test +- clean: seeds 1 `#\[test\]|#\[tokio::test\]` = ~120 (unit tests per module + 2 boundary tests in tests/runtime_boundary.rs), seed2 `assert_eq!\(|assert_ne!\(|assert!\(` = ~320 (behavioral assertions with per-case messages, error-variant matches not Display strings), seed3 `proptest!|insta::assert|rstest` = 0 (no property/snapshot tooling; hand-built case tables with failure messages cover the parser/classifier edges adequately for the closed input classes), seed4 `#\[ignore\]` = 0 (no ignored tests); tests are deterministic (fixed `/proc/stat` fixtures, injected fakes, no network, tempdir-scoped state),and the boundary test suite locks the provider-implementation-free contract + +## Coverage +- idiom: 1 finding(s) +- own: 1 finding(s) +- type: 1 finding(s) +- api: 2 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: ~25/~30/1/~20; all shapes deliberate; one hand-written admission gate with round-trip test) +- obs: clean (seeds ran: 0/0/0/~25; named-field events only, no println, no interpolated message-only logs, no secret fields) +- docs: 4 finding(s) +- perf: 1 finding(s) +- conc: clean (seeds ran: ~9/~9/~25/0; worker-thread model and lock/atomic orderings match the workload shapes) +- async: clean (seeds ran: ~90/~12/~3/~16; dedicated R4 workers, no awaits-under-lock, no executor blocking) +- unsafe: clean (seeds ran: 0/0/4/2; only safe rustix::process::Pid::from_raw constructors; no unsafe blocks to justify) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: N/A (seeds: 0/0/0/0 all zero; no macros) +- test: clean (seeds ran: ~120/~320/0/0; deterministic behavior-focused unit+boundary suite, error variants asserted, no ignored/property tests needed for the closed input classes) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md new file mode 100644 index 000000000..5fe6d86a0 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md @@ -0,0 +1,79 @@ +# d2bd-runtime-p2 - d2bd-runtime - part 2/4 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10744 (excl. src/generated/**) | modules: resource_runtime_support, guest_resource_runtime, workload_dispatch, runtime_process, workload_target_index, wire, ssh_host_key_preflight, public_projection, resource_operator_activation, exec_detached, admission, daemon_client, runtime_capability +Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: part 2/4 (whole-file modules; none split) + +## idiom +- clean: seeds `for \w+ in 0\.\.`=2 (workload_dispatch.rs:786,797, test id-name builders only), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0 (plus 3 generic-shaped hand-written `impl ... Debug for` not matched by the seed: exec_detached.rs ResourceDetachedClient, guest_resource_runtime.rs GuestResourceRuntime/GuestResourceStore - all deliberate redaction/format impls, not derive-replaceable), `let mut \w+ = (String|Vec)::new\(\)`=5 (resource_runtime_support.rs:438 rule builder with `?` short-circuit, :1231 zone-user filter loop with early Err, guest_resource_runtime.rs:665 mutation-loop, :1117/:1568 byte key-material buffers). Every hit is an explainable loop shape (side-effecting, error-propagation, byte concat); no iterator-pipeline regression worth changing. + +## own +- clean: seeds `\.clone\(\)`=100, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=128, `Rc<|RefCell<|Arc Arc` (guest_resource_runtime.rs:418) hands out the shared store clone by design; lib.rs exports modules directly (single path per item, no duplicate re-export arms); traits `DetachedProcessResourcePort`, `Wave6ProviderBoundary` keep a small required surface. No semver-concerning export found in this part. + +## err +- d2bd-runtime-p2#3 sev=medium blast=leaf effort=M verdict=actionable - `map_parse_error` (wire.rs:529-536) classifies `serde_json::Error` kinds by substring-matching the Display text ("unknown field", "interface name"), so the wire-visible kinds `wire-unknown-field`/`wire-if-name-invalid` flip silently if serde_json rewords a message - fix: classify structurally instead of lexically - e.g. parse the request envelope against a `#[serde(deny_unknown_fields)]`-tagged shape so "extra field" arrives as a discrete rejection (the manual authStatus/usbipProbe arms already do this), and route the raw serde error through `error.classify()` plus line/column for the generic frame kind - [wire.rs:529-536] + evidence: seeds: `\.unwrap\(\)|\.expect\(`~185 (prod sites 10 - all fixed-literal-valued expects of the card's false-positive family, e.g. resource_runtime_support.rs:1123/1311/1565/1737/1833, guest_resource_runtime.rs:997; rest test-only), `let _ = |\.ok\(\);`=8 (test cleanup removes + deliberate `read_link)...).ok()`), `\bpanic!\(|unreachable!\(|todo!\(|unimplemented!\(`=12 (all tests), `enum \w*Error`=5 (GuestResourceRuntimeError, ShellTargetError, CatalogError, TargetResolutionError, Wave6BoundaryError - shown well-shaped by caller action) + +## serde +- d2bd-runtime-p2#4 sev=low blast=leaf effort=M verdict=actionable - `parse_request` (wire.rs:256-355) hand-rolls the internally-tagged dispatch that serde provides: a 19-arm match on the `type` string then `serde_json::from_value` per arm, where the 15 plain verbs would parse directly from a `#[serde(tag = "type", rename_all = "camelCase")]` tagged enum - fix: split a tagged parse enum for list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio derived with internal tag, keeping the custom authStatus/usbipProbe empty-body checks, console opId removal and resourceRequest passthrough explicit; confirm each payload type's deny_unknown_fields posture is unchanged before shipping - [wire.rs:265-353] + evidence: seeds: `derive\([^)]*(De)?[Ss]erialize`=5 (Serialize-only response frames, deliberate), `serde\((rename_all|deny_unknown_fields|try_from|flatten|...)\)`=8, `impl .*Deserialize.*for`=0, `serde_json::from_|to_`~70; manual read of the parse boundary and its round-trip + rejection tests (wire.rs:548-660) verifies behavior is covered + +## obs +- d2bd-runtime-p2#5 sev=low blast=leaf effort=S verdict=actionable - `write_daemon_version_file` (runtime_process.rs:446-486) reports its five failure paths with `eprintln!` from a library module instead of `tracing`, bypassing level/filter/structure - fix: route them through `tracing::warn!`/`tracing::error!` with the path/context as named fields (module already uses tracing in the sd_notify fns) - [runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs:480, runtime_process.rs:484] + evidence: seeds: `\bprintln!\(|\beprintln!\(`=9 (5 prod here, 3 test-fixture, 1 daemon_client.rs:17 test-client stdout = product output), `(info|debug|warn|error|trace)!\("`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`~30 +- d2bd-runtime-p2#6 sev=low blast=leaf effort=S verdict=actionable - event fields allocate eagerly even when the level is filtered: `mode = format!("{mode:o}")` inside a `tracing::debug!` (ssh_host_key_preflight.rs:305, hot on every key entry) and a pre-joined `subjects` string built before a `tracing::warn!` (resource_runtime_support.rs:679-680) - fix: use `tracing::field::debug(format_args!("{mode:o}"))` for the octal mode and `tracing::field::display(subjects.iter().map)...).collect::>().join(","))` (or an `Empty`-then-record) so nothing is formatted when the event is disabled - [ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680] + evidence: seeds: println/eprintln=9, `)...)!\("`=0, instrument=0, tracing::~30; manual read of the two event sites confirms eager construction + +## docs +- d2bd-runtime-p2#7 sev=medium blast=leaf effort=M verdict=actionable - several publicly-reachable items in this part carry no doc contract: `ensure_manifest_entry_runtime_capability` (runtime_capability.rs:47-64, returns `Result` with a capability-specific error), the security-admission `authorize_peer`/`classify_peer` (admission.rs:61-159, including the non-obvious `production_lookup` mode), and `run_test_client`/`apply_overrides` (daemon_client.rs:12-43) - fix: add one-line first sentences plus `# Errors` naming `TypedError::RuntimeCapabilityUnsupported`/`AuthzNotALauncher` and vertical workspace for the mode semantics; link the daemon-dispatch callers as intra-doc links - [runtime_capability.rs:47-64, admission.rs:61-159, daemon_client.rs:12-43] + evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)`~170, `/// # (Examples|Errors|Panics|Safety)`=0, `-> Result<`~80; read: the listed items have no doc comments, and none of the Result-returning items in the part carry a canonical `# Errors` section +- d2bd-runtime-p2#8 sev=low blast=leaf effort=S verdict=actionable - the `has_posix_acl` doc first sentence begins with an unexplained `v1.1.2fu25:` audit-workflow token, and a sibling `P2fu1 ...` workflow tag sits inside an enabled trace field comment list - fix: drop/relocate the workflow tokens so the rendered contract reads plain, keeping the "0440-with-ACL legitimate vs drift" why in the body (it is the good part) - [ssh_host_key_preflight.rs:312, ssh_host_key_preflight.rs:298-301] + evidence: seeds: `/// # ...`=0, `-> Result<`~80; doc-token grep `fu\d+` over the part = 2 (ssh_host_key_preflight.rs:298 comment, :312 doc) + +## perf +- d2bd-runtime-p2#9 sev=medium blast=leaf effort=S verdict=actionable - every daemon wire request is deep-cloned before parsing: the 17 `serde_json::from_value(Value::Object(object.clone()))` arms and the `object.clone().into_iter().collect()` resourceRequest arm (wire.rs:274-352) copy the entire frame Value, then the copy is dropped - fix: `Value::Object(std::mem::take(object))` in each arm and `std::mem::take(object).into_iter().collect()` for resourceRequest (object is a `&mut Map` dead after the exclusive arm bodies); removes a whole-payload clone per request on the CLI/daemon socket path - [wire.rs:275-346, wire.rs:350-351] + evidence: static (unmeasured; no benchmark exists); seeds: `format!\(`~60 (all cold: error paths, diagnostics, test helpers), `Vec::new\(\)|VecDeque|HashMap|BTreeMap::new`~17, `\.to_string\(\)`~20 (error-detail serialization only); manual read of wire.rs:256-353 + +## conc +- d2bd-runtime-p2#10 sev=low blast=leaf effort=S verdict=actionable - `NewPlaneReadinessState` (resource_runtime_support.rs:144-180) stores four independent readiness booleans with `Ordering::SeqCst` on every store/load; there is no Release/Acquire paired handoff (each flag is an independent published bit) - fix: `Ordering::Relaxed`, which is the weakest correct ordering for independent flags; the cross-thread visibility the startup path needs is already ordered by the join/actor supervision in the daemon, and SeqCst here does not buy snapshot atomicity across the four flags anyway - [resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support.rs:166, resource_runtime_support.rs:170, resource_runtime_support.rs:175-178] + evidence: static (unmeasured); seeds: `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=8 (tokio mutexes in the guest store + sync ledger Mutex on the sanctioned synchronous path + cfg(test) statics), `Atomic\w+|Ordering::`~14, `thread_local!|unsafe impl (Send|Sync) for`=0 + +## async +- clean: seeds `async fn|async move|\.await`~100, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(`=5, `tokio::sync::(Mutex|RwLock|Notify)`=6, `#\[tokio::(main|test)\]|Runtime::block_on`=5. Checked: the guest store uses `tokio::sync::Mutex` for state genuinely locked across await points (guest_resource_runtime.rs:643-738) with the guard not spanning extra awaits beyond the lock scope; `launch_ledger()`'s `std::sync::Mutex` is confined to the sanctioned synchronous path with `#[allow(clippy::disallowed_methods, reason = "synchronous path")]`; `register_system_core_session` handshake uses `tokio::join!` and a detached (deliberate) ttrpc service spawn; no `// async-gate-allow:` markers and no blocking work found inside async contexts in this part. + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=2 - both false positives of the seed: `Uid::from_raw)...)` in runtime_process.rs:211/236 and chown-guard arithmetic, safe nix constructors). U1 (d)8 records no d2bd-runtime unsafe blocks at this HEAD (only the typed_error.rs doc-word false positive, which is in part 1's scope). + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0). No foreign-caller boundary in this part; the nix socket/seqpacket wrappers are in-crate safe bindings. + +## macro +- N/A (seeds: `macro_rules!`=0, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0). No macro definitions in this part. + +## test +- d2bd-runtime-p2#11 sev=high blast=leaf effort=S verdict=actionable - `sd_notify_ready_noops_without_notify_socket` (runtime_process.rs:543-546) and `sd_notify_ready_errors_when_socket_is_unreachable` (runtime_process.rs:589-594) cannot fail: each body only calls `sd_notify_ready)...)` on a path the function returns without panicking (None early-return; Some-to-missing-socket caught and warn-logged), with no assertion anywhere - fix: delete both, or give them an observable assertion modeled on the sibling `sd_notify_ready_sends_pathname_datagram` (bind a datagram listener, send the payload, assert the received bytes / exit-code), so the suite refuses to pass silently when the notification path regresses - [runtime_process.rs:543-546, runtime_process.rs:589-594] + evidence: seeds: `#\[test\]|#\[tokio::test\]|assert_eq!\(|assert_ne!\(|assert!\(`~355 (deterministic sample of 50 read: every other sampled test asserts behavior or error variants - including `error.kind()`/`StoreErrorKind` variant asserts, restart-simulation round-trips with failure messages, and wire rejection kind asserts; these two were the only assertions-free bodies in the sample); `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0 + +## Coverage +- idiom: clean (seeds ran: 2/0(+3 generic-shaped manual Debug impls inspected)/5; all explainable) +- own: clean (seeds ran: 100/128/1/0; sampled 50 of 229; one avoidable clone family -> perf#9) +- type: 2 finding(s) +- api: clean (seeds ran: ~164/2/3; the 2 Arc-in-signature sites evaluated and legitimately shared) +- err: 1 finding (seeds ran: ~185/8/12/5) +- serde: 1 finding (seeds ran: 5/8/0/~70) +- obs: 2 finding(s) +- docs: 2 finding(s) +- perf: 1 finding (seeds ran: ~60/~17/~20; static unmeasured) +- conc: 1 finding (seeds ran: 0/8/~14/0) +- async: clean (seeds ran: ~100/5/6/5) +- unsafe: N/A (seeds: 0/0/2(false positives: Uid::from_raw)/-) +- ffi: N/A (seeds: 0/0/0/0) +- macro: N/A (seeds: 0/0/0/0) +- test: 1 finding (sampled 50 of 355 hit mass; proptest/insta/rstest=0, #[ignore]=0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md new file mode 100644 index 000000000..6eeea3651 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md @@ -0,0 +1,85 @@ +# d2bd-runtime-p3 - d2bd-runtime - part 3/4 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10718 (excl. src/generated/**) | modules: exec_session, unsafe_local_helper, metrics, authority_persistence, readiness, otel_host_bridge_readiness, ownership_preflight, unix_transport, exec_session_real, terminal_session, pidfs_probe, lib, runtime_util +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 3/4 of d2bd-runtime (whole-file lane; no range splits) + +## idiom +- d2bd-runtime-p3#1 sev=low blast=leaf effort=S verdict=actionable - two fd-extraction loops grow a Vec via `extend` in a `for` over `cmsgs()`, where a filter_map collect would read as one expression - fix: collect `message.cmsgs().map_err)...)?.filter_map(|c| ...).flatten().collect()` into the result Vec in `receive_frame` and `read_frame_with_fds` - [packages/d2bd-runtime/src/unsafe_local_helper.rs:789, packages/d2bd-runtime/src/unix_transport.rs:294] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 4 hits; the two allocate-then-extend fd loops are the replaceable pair (the other two hits build String/axes buffers, deliberate accumulation) +- clean: additional seeds for this lens: `for \w+ in 0\.\.` = 6, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 4; index loops are all `for _ in 0..N` bounded retry/drain loops (no element indexing), hand-written `Default` impls set non-zero invariants (`ExecOpDeadlines`, `ExecSessionCaps`, `ReadinessWaitConfig`) or wrap non-Default fields (`Registry::new` -> `Self::new`), so none is derive-replaceable + +## own +- d2bd-runtime-p3#2 sev=low blast=leaf effort=S verdict=actionable - three `operation_id.to_string()` copies of an already-owned `String` are produced only to be borrowed or passed along (`complete_pending` takes `String` just for one comparison), so each completed/rejected helper op pays a heap alloc - fix: change `complete_pending` to take `operation_id: &str` and pass `&result.operation_id` / `&rejected.operation_id` at the three call sites (the second local `let operation_id = result.operation_id.to_string()` becomes `&result.operation_id` directly) - [packages/d2bd-runtime/src/unsafe_local_helper.rs:625, packages/d2bd-runtime/src/unsafe_local_helper.rs:629, packages/d2bd-runtime/src/unsafe_local_helper.rs:644] + evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 157 hits; the three sites are the only String-to-String copies made solely for borrowing +- clean: all own seeds (58 `.clone()`, 157 `.to_owned`/`.to_vec`/`.to_string`, 1 `Arc>` hit is `authority_persistence.rs:77` type alias `Rows`, part of a documented multi-thread shared ledger; every other clone/copy is a map-correlated stored value, a test fixture, an error-context `to_owned`, or an Arc clone at a spawn/thread boundary (required for `'static`) + +## type +- clean: seeds ran: 1/0/0; the single hit is a `#[test]` fn name (`validate_rejects_wrong_kind` in metrics.rs:1139), not a runtime validation predicate; pub struct/enum surfaces were surveyed via the api-runs for flag soup, Option-pair smells, stringly-typed state (none;`ReadinessProbe`'s two booleans fold into the terminal `OtelHostBridgeReadiness` verdict enum, `NegotiatedCaps`'s booleans are independently real capability gates) + +## api +- d2bd-runtime-p3#3 sev=low blast=leaf effort=M verdict=actionable - `pub fn spawn_session_worker` (with `pub struct WorkerSpawn`, `SessionTable`, `ExecOpDeadlines`, `ExecStartSpec`, etc.) has no production caller in the workspace - only its own crate's tests - so the whole exec-session worker surface is either pending wiring from d2bd composition or dead public API - fix: wire `spawn_session_worker`/`SessionTable` into d2bd's exec composition (or gate the module test-support-only pending that wiring) - [packages/d2bd-runtime/src/exec_session.rs:900] + evidence: census: `spawn_session_worker` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 4 hits (pub fn def at :900, doc cross-ref at :880, two test call sites at :2486 and :3624); api seed counts: 214/9/0 +- clean: the 9 `pub .*(Arc|Rc|Box|RefCell)<` hits are all genuine shared-ownership tokens (`Established.client`, `WorkerSpawn.connector/clock/owner_reaper`, `HelperRegistry::accept_loop(Arc)`, `ZoneAuthorityLedger::install_*`) whose shared ownership is exercised at spawn/thread boundaries;`pub use` absent, every item reachable via exactly one path (lib.rs `pub mod` arms are the house single-surface pattern) + +## err +- d2bd-runtime-p3#4 sev=low blast=leaf effort=S verdict=actionable - `spawn_session_worker` panics at `std::thread::Builder::spawn)...).expect("spawn exec session worker thread")` in library code on an environmental failure (thread exhaustion/ENOMEM) with a caller-visible alternative - fix: return `std::io::Result>` (or map to `TypedError`) and have the two test call sites adjust - [packages/d2bd-runtime/src/exec_session.rs:939] + evidence: seed `\.unwrap\(\)|\.expect\(` = 254 hits; the only non-test hit besides :939 is metrics.rs:352 `descriptor)...).expect("validated above")`, a post-check invariant; census: spawn_session_worker = 4 hits (no prod caller, so the panic is test-reachable only today) +- clean: remaining err seeds: `let _ = |\.ok\(\);` = 41 hits (every site is deliberate best-effort teardown/oneshot/`write!` onto a `String`, or test cleanup), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 24 (all test code or internal-invariant `unreachable!`s in non-test code at exec_session.rs:1203,:1256), `enum \w*Error` = 7 (closed enums with `slug()` accessors, fine taxonomy shapes) + +## serde +- clean: seeds ran: 1/0/0/13; the lone derive hit is `OtelHostBridgeReadiness` (internal-tag `status` + `kebab-case` enum, pinned by envelope-shape tests at otel_host_bridge_readiness.rs:601-623); all `serde_json` boundary calls map failures into typed errors (`ExecOpError::Protocol`, `HelperRegistryError::InvalidFrame`, `AuthorityPersistenceError::RowInvalid`, `TypedError::InternalIo`) rather than unwrapping + +## obs +- d2bd-runtime-p3#5 sev=low blast=leaf effort=S verdict=actionable - the one-shot-exit unparseable-stat warning is message-only with no named fields (`tracing::warn!("wait_for_one_shot_exit: /proc//stat unparseable; ...")`), though `pid` and a `path` string are in scope and sibling warnings carry `%err`/field-style context - fix: emit fields (`pid = %pid`, `path = %path`) with a short message (or wrap the poll loop in a span carrying `pid`) - [packages/d2bd-runtime/src/readiness.rs:327] + evidence: seed `(info|debug|warn|error|trace)!\("` = 23 hits; all other hit sites carry named fields (or `%err` field); no instrument span envelopes this helper (seed `\.instrument\(|#\[instrument` = 0) +- d2bd-runtime-p3#6 sev=low blast=leaf effort=S verdict=actionable - pidfs probe warns/errors interpolate a prebuilt `{msg}` string with embedded `st_dev`/`detail` values instead of named fields, while the sibling `PidfsAvailable` arm already emits `pidfs_st_dev`/`pidfs_st_ino` fields - fix: give `PidfsNotPresent` and `UnexpectedError` arms named `pidfs_st_dev = %st_dev` / `detail = %detail` fields (and keep the long operator-facing sentence as the message template) - [packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132, packages/d2bd-runtime/src/pidfs_probe.rs:144, packages/d2bd-runtime/src/pidfs_probe.rs:147, packages/d2bd-runtime/src/pidfs_probe.rs:158] + evidence: seed `(info|debug|warn|error|trace)!\("` = 23 hits; the cited five are the only `{msg}`-interpolated events in this lane (readiness.rs:327 is finding d2bd-runtime-p3#5) +- clean: `\bprintln!\(|\beprintln!\(` = 0;`tracing::|log::` = 23 (all `tracing`, structured, prefixed `provider`/`event_kind`/`result` scheme in unsafe_local_helper, `vm`/`path`/`reason` fields elsewhere); no secret material in any field (Debug impls redact terminal bytes, argv/env, and unguessable handles) + +## docs +- d2bd-runtime-p3#7 sev=medium blast=leaf effort=M verdict=actionable - unsafe_local_helper.rs has no `//!` module doc and its public surface (consts `HELPER_HEARTBEAT_INTERVAL`/`HELPER_STALE_AFTER`/`HELPER_OPERATION_TIMEOUT`, enums `HelperRegistryError`/`HelperAvailability`/`HelperReply`, struct `HelperRegistry` + its seven pub methods) carries no doc comments, unlike every sibling module in this crate - fix: add a `//!` header (lifecycle, wire protocol, thread model, redaction rules) and one-line `///` docs per pub item - [packages/d2bd-runtime/src/unsafe_local_helper.rs:1, packages/d2bd-runtime/src/unsafe_local_helper.rs:33, packages/d2bd-runtime/src/unsafe_local_helper.rs:42, packages/d2bd-runtime/src/unsafe_local_helper.rs:65, packages/d2bd-runtime/src/unsafe_local_helper.rs:71, packages/d2bd-runtime/src/unsafe_local_helper.rs:190] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 hits in lane; the cited items have zero `///` lines (verified by contiguous read) +- d2bd-runtime-p3#8 sev=medium blast=leaf effort=S verdict=actionable - public exec-session DTO fields lack doc comments on a cross-crate contract surface (`ExecStartSpec.vm/argv/tty/detached/env/cwd/term_size`, `ExecSessionInfo.tty/stdout_offset/stderr_offset`, `Established.client/info/control_seq/caps`, `WorkerSpawn.connector/spec/deadlines/establish_tx/control_rx`), while sibling fields (`request_id`, `NegotiatedCaps.*`, `TerminalReaper`/`SessionSlot` fields) are documented - fix: add `///` per field (semantics plus any redaction/derivation promise), especially what `control_seq`/`establish_tx` carry - [packages/d2bd-runtime/src/exec_session.rs:181, packages/d2bd-runtime/src/exec_session.rs:211, packages/d2bd-runtime/src/exec_session.rs:249, packages/d2bd-runtime/src/exec_session.rs:882] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 hits; the cited field blocks were read contiguously and have no per-field `///` +- d2bd-runtime-p3#9 sev=medium blast=leaf effort=S verdict=actionable - readiness.rs exposes seven undocumented pub predicates/functions (`readiness_predicate_ready`, `unix_socket_exists`, `unix_socket_listening`, `tcp_port_ready`, `wait_for_tcp_port`, `command_ready`, `readiness_predicate_ready_async`) whose contracts are non-obvious (e.g. `unix_socket_listening` parses `/proc/net/unix` flags;`command_ready` strips `NOTIFY_SOCKET`), while `api_socket_info_ready`/`wait_for_readiness_async` do carry `///` - fix: add one-line `///` first sentences + `# Errors` notes on the `Result<_, String>` shapes - [packages/d2bd-runtime/src/readiness.rs:15, packages/d2bd-runtime/src/readiness.rs:78, packages/d2bd-runtime/src/readiness.rs:85, packages/d2bd-runtime/src/readiness.rs:103, packages/d2bd-runtime/src/readiness.rs:112, packages/d2bd-runtime/src/readiness.rs:125, packages/d2bd-runtime/src/readiness.rs:145] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 hits; the seven cited fns were read contiguously and have no `///`; seed `-> Result<` = 113 (the String-typed error returns are message-shaped wire slugs, not enum-typed, so `# Errors` sections can name their slugs) +- clean: seed `/// # (Examples|Errors|Panics|Safety)` = 0 in lane; no pub item needs a doctest/canonical section beyond the `# Errors`-naming noted above (this crate's contract docs live in module/dossier prose, consistent with repo convention) + +## perf +- clean: seeds ran: 59/52/27; the `format!` hits are error-path diagnostics (cold), the metrics renderer's `push_str(&format!)...))`-built exposition, and test fixtures (per U1 the wire-artifact/String-building class is excluded);`Vec::new()`/`BTreeMap::new()` hits are empty-value constructors or test fakes (empty case common);`to_string()` hits duplicate the own-lens borrow finding (d2bd-runtime-p3#2) or are error-context copies; no hot path with an unbounded allocation was identified (static (unmeasured) assessment only) + +## conc +- d2bd-runtime-p3#10 sev=medium blast=leaf effort=M verdict=policy-confirmed - unsafe_local_helper.rs uses `parking_lot::Mutex` for its registry/connection/ledger state (`use parking_lot::Mutex` + 4 `Mutex<...>` field types + 39 `.lock()` call sites), which the repo bans outright outside the R4 dedicated bounded-worker boundary - fix: replace with `tokio::sync::Mutex` reached through the documented blocking-seat patterns this crate already uses (`metrics::Registry::blocking_lock` for worker-thread-only seats, `authority_persistence::lock_sync` try_lock spin where an ambient runtime may exist) - [packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34] + evidence: seed `\bMutex<|\bRwLock<` = 27 hits; parking_lot import at unsafe_local_helper.rs:17 and dep at Cargo.toml:34; policy: clippy.toml:40-43 bans parking_lot outright (KD3; single R4 exception, not this site)and clippy.toml:82-84 names `tokio::sync::Mutex::lock` as the replacement +- clean: remaining conc seeds: `std::thread::` = 13 (dedicated daemon/helper handler threads with documented ownership, plus test threads), `Atomic\w+|Ordering::` = 97 (paired Acquire/Release, AcqRel idempotency guards, Relaxed counters - weakest-correct orderings), `thread_local!|unsafe impl (Send|Sync) for` = 0 + +## async +- clean: seeds ran: 260/10/27/14; the async code is well-disciplined:dedicated current-thread runtime per session worker (documented concurrency contract), long-polls spawned onto it so fast control ops never head-of-line block, `tokio::sync::Mutex` guards are scoped or lazily-dropped before awaiting (`prove_claim` clones the Arc out of the guard first), blocking seats are the sanctioned `blocking_lock`/`try_lock`-spin patterns renamed in code comments (plan U17), and the sync-only readiness fns carry `#[allow)..., reason = "synchronous path")]` and are pinned for d2bd's worker-thread callers + +## unsafe +- clean: seeds ran: 0/0/2/0; the two `from_raw` hits are `rustix::process::Pid::from_raw`, a safe constructor, not a UB hazard; no `unsafe` block/fn/impl, no `// SAFETY:` comment, and no raw-pointer `from_raw`/`transmute`/`MaybeUninit` exists in this lane's scope - nothing to justify or doc-inspect (the crate inherits the workspace `unsafe_code = "forbid"` posture) + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, no `catch_unwind`, no `repr(C)`/`repr(transparent)`, no C string/char types - this part crosses no foreign-caller boundary;`nip`/`rustix` syscall wrappers only) + +## macro +- N/A (seeds: 0 all zero; no `macro_rules!` definitions or proc-macro/syn/quote usage in the lane scope; std invariants like `cmsg_space!` are external-crate macros, not this crate's) + +## test +- clean: seeds ran: 125/293/0/0; the suite is hermetic and behavior-focused:all fakes/fixtures injected (fake clock, fake driver, fake connector, fake source), no network/no real timeouts beyond bounded local sleeps, error behavior asserted via `matches!)...Error::Variant)` not Display strings; `runtime_boundary.rs` pins the crate's dependency discipline, `#[should_panic]` on an internal-invariant check, and no `#[ignore]`/flaky gates exist + +## Coverage +- idiom: 1 finding(s) +- own: 1 finding(s) +- type: clean (seeds ran: 1/0/0; single hit is a test fn name, not a validation predicate; no flag-soup/Option-pair/string-state invariant class) +- api: 1 finding(s) +- err: 1 finding(s) +- serde: clean (seeds ran: 1/0/0/13; single serde type is an internal-tag Status enum pinned by envelope tests; all serde_json boundary errors mapped to typed errors) +- obs: 2 finding(s) +- docs: 3 finding(s) +- perf: clean (seeds ran: 59/52/27; format!/collection/to_string hits are error paths, bounded renderers, wire artifact builders, or test fixtures - no hot-path allocation) +- conc: 1 finding(s) +- async: clean (seeds ran: 260/10/27/14; spawn/await/lock discipline matches the documented concurrency contract; blocking seats sanctioned with `"synchronous path"` allows and plan U17 comments) +- unsafe: clean (seeds ran: 0/0/2/0; the 2 hits are safe `rustix::process::Pid::from_raw` constructors - no unsafe code in scope) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary in this part) +- macro: N/A (seeds: 0 all zero; no macro definitions in this part) +- test: clean (seeds ran: 125/293/0/0; hermetic, injected, variant-asserting suite with no ignored tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md new file mode 100644 index 000000000..0929ddfe4 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md @@ -0,0 +1,112 @@ +# d2bd-runtime-p4 - d2bd-runtime - part 4/4 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10729 (excl. src/generated/**) | modules: target_runtime, daemon_audit, guest_mode, kernel_module_check, console_session, guest_component_session, ch_stats, concurrency, daemon_version, ch_api, typed_shell_targets, wire_response_helpers, exec_support +Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: part 4/4 - the 13 whole-file units listed in U1 section (f); no item-range splits + +## idiom +- d2bd-runtime-p4#1 sev=low blast=leaf effort=S verdict=actionable - `monotonic_tick()` is duplicated verbatim in guest_mode.rs and guest_component_session.rs (identical `OnceLock` elapsed-millis helper, two copies of the same code) - fix: move one `monotonic_tick()` into `crate::runtime_util` and have both modules call it - [packages/d2bd-runtime/src/guest_mode.rs:849, packages/d2bd-runtime/src/guest_component_session.rs:587] + evidence: census: pattern `fn monotonic_tick` over packages/d2bd-runtime/src = 2 hits (both definitions, same body) +- d2bd-runtime-p4#2 sev=low blast=leaf effort=S verdict=actionable - `impl Default for ConsoleSessionTable` hand-writes what `#[derive(Default)]` produces field-wise (all three HashMap fields are Default) - fix: replace the impl with `#[derive(Default)]` on `ConsoleSessionTable` and delete the manual `default()` - [packages/d2bd-runtime/src/console_session.rs:162] + evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 3 hits; the other two Defaults (ConsoleRing:82, ConsoleClientHandle:132) are invariant-preserving/panicking and correctly hand-written +- clean: idiom seeds 1/2/3 = 4/3/12 hits; seed 1 loops are side-effecting test fills, seed 3 accumulations all have early returns or byte-buffer shapes where a collect would obscure control flow + sampled: 50 of 19 hits (all 19 read in full context) + +## own +- d2bd-runtime-p4#3 sev=low blast=leaf effort=S verdict=actionable - `ConsoleSessionTable` lookups allocate a `String` on every call (`ConsoleClientHandle(session_handle.to_owned())` in five methods) because the map key newtype does not implement `Borrow` - fix: implement `Borrow` for `ConsoleClientHandle` (or key the two maps by `String`) so `self.clients.get(session_handle)` resolves without allocation - [packages/d2bd-runtime/src/console_session.rs:250, packages/d2bd-runtime/src/console_session.rs:268, packages/d2bd-runtime/src/console_session.rs:293, packages/d2bd-runtime/src/console_session.rs:304, packages/d2bd-runtime/src/console_session.rs:318] + evidence: own seed 2 (`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`) = 188 hits; the 5 named sites are the only per-call handle-construction allocations outside tests +- d2bd-runtime-p4#4 sev=low blast=leaf effort=S verdict=actionable - every audit write clones the whole `DaemonEvent` (strings included) in `enqueue` because the write API takes `&DaemonEvent`, while every caller (d2bd composition.rs:19356, tests) constructs the event solely to write it - fix: change `write_event`/`write_event_with_authority`/`write_event_async`/`write_event_with_authority_async` to take `DaemonEvent` by value and drop the `event: event.clone()` in `enqueue` - [packages/d2bd-runtime/src/daemon_audit.rs:976, packages/d2bd-runtime/src/daemon_audit.rs:1003] + evidence: own seed 1 (`\.clone\(\)`) = 124 hits; site-specific (the only per-write event clone; all other clones inspected are required by map keys, closure `'static` bounds, or shared ownership) +- clean: own seeds 1/2/3/4 = 124/188/17/0 hits; Arc clones sit at spawn/closure boundaries, key clones are required by BTreeMap/HashMap ownership, `Arc` state is genuinely shared (ServerState, ring, op locks) + sampled: 50 of 329 hits (deterministic every-7th; all files read in full or in hit neighborhoods) + +## type +- d2bd-runtime-p4#5 sev=medium blast=family effort=S verdict=actionable - `DaemonEvent::ApiReadyTimeout.mode: String` models a closed two-value state (`"strict"` | `"no-wait-api"`, documented at daemon_audit.rs:193) as an open string, so an invalid mode is representable and would land in the preserved audit record - fix: introduce a two-variant `SplitReadinessMode`-style enum with `#[serde(rename_all = "kebab-case")]` and use it for the field; serialized bytes stay `"strict"`/`"no-wait-api"` so the daemon-events JSONL shape is unchanged - [packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361] + evidence: type seed 3 (`(mode|kind|state): String`) = 14 hits; the other hits are wire-mirroring fields (daemon_audit.rs:734-744 bounded error-kind tokens, ch_stats.rs:58 CH-API state) that are deliberate +- d2bd-runtime-p4#6 sev=medium blast=family effort=S verdict=actionable - `retarget_mutating_response` and `response_outcome` re-derive the wire outcome as strings (`Some("applied")`, `Some("broker-error")`, `Some("api-ready-timeout")`) although the same file already builds responses from the `MutatingVerbOutcome` enum, forcing every caller into string matching (8 sites in d2bd composition.rs) - fix: add a typed accessor that parses `outcome` into `MutatingVerbOutcome` (serde) and match on the enum variants in `retarget_mutating_response`, keeping the `_` pass-through for unknown broker outcomes - [packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_response_helpers.rs:118] + evidence: type seed 3 = 14 hits; census: pattern `response_outcome` over packages = 8 hits (5 string-comparison call sites in packages/d2bd/src/composition.rs:6879,6918,19883,19891,19918) +- d2bd-runtime-p4#7 sev=low blast=leaf effort=S verdict=actionable - the typed-shell target key `(u32, String)` (uid + shell name) is a bare tuple repeated across three collections and every public method signature, so uid/name swap is a type error waiting to happen - fix: extract `TypedShellTargetKey { uid: u32, name: String }` (derive Ord) and use it in `entries`/`recency`/`create_reservations` and the `remember`/`cached`/`forget`/`reserve` signatures - [packages/d2bd-runtime/src/typed_shell_targets.rs:13, packages/d2bd-runtime/src/typed_shell_targets.rs:82] + evidence: census: pattern `(u32, String)` over packages/d2bd-runtime/src/typed_shell_targets.rs = 21 hits (field types, signatures, test literals) + +## api +- d2bd-runtime-p4#8 sev=low blast=leaf effort=S verdict=actionable - `ConsoleClientHandle(pub String)` exposes the inner token of a type documented as "Opaque per-client session token", so any caller can fabricate handles and the opacity claim is unenforced - fix: make the field private, add `FromStr`/`as_str`, and route the table's own lookups through them - [packages/d2bd-runtime/src/console_session.rs:118] + evidence: api seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) = 333 hits (surface enumerated via structural summaries); site-specific +- d2bd-runtime-p4#9 sev=low blast=leaf effort=S verdict=actionable - `spawn_ch_serial_drainer(_vm: String, ...)` takes an unused `_vm` parameter, and its only caller allocates a hardcoded `"ch-console".to_owned()` per session to satisfy it - fix: drop the parameter and the call-site allocation in `create_ch_session` - [packages/d2bd-runtime/src/console_session.rs:341, packages/d2bd-runtime/src/console_session.rs:422] + evidence: census: pattern `spawn_ch_serial_drainer` over packages = 2 hits (definition + the single call at console_session.rs:422) +- d2bd-runtime-p4#10 sev=low blast=leaf effort=S verdict=actionable - `DrainerSource` is a dead public enum: never constructed anywhere, with a `#[allow(dead_code)]` `Connected` variant carrying a tokio stream - fix: delete the enum (and the allow) - [packages/d2bd-runtime/src/console_session.rs:54] + evidence: census: pattern `DrainerSource` over packages = 1 hit (the definition itself; zero constructions or matches) +- d2bd-runtime-p4#11 sev=low blast=leaf effort=M verdict=actionable - `ConsoleRing` and `ConsoleSession` expose all fields `pub` (`ring: RingBuffer`, `notify`, `drainer`, `stdin_tx`), so the documented invariant "notify fires whenever bytes are pushed or EOF is set" (console_session.rs:68) is convention-only: an external caller can push bytes without notifying and waiters hang - fix: make the fields private and expose `push_bytes`/`set_eof`/`read_at` on `ConsoleRing` and accessors on `ConsoleSession` that notify internally - [packages/d2bd-runtime/src/console_session.rs:66, packages/d2bd-runtime/src/console_session.rs:90] + evidence: api seed 1 = 333 hits; site-specific (the two structs' field lists read in full) +- clean: api seeds 1/2/3 = 333/0/0 hits; the wide `pub mod` surface is the crate's internal-daemon contract (d2bd and d2b-provider-guest are the only consumers); no `Arc`/`Rc`/`Box`/`RefCell` in public signatures beyond the genuine shared-ownership `driver()` handle + sampled: 50 of 333 hits (surface enumerated via lib.rs re-export list + per-file structural summaries) + +## err +- d2bd-runtime-p4#12 sev=low blast=leaf effort=S verdict=actionable - `impl Default for ConsoleClientHandle` panics via `expect("console handle entropy unavailable")` when entropy fails, and nothing in the workspace calls `ConsoleClientHandle::default()` - fix: delete the Default impl (the type already has a fallible `new()` used at attach) - [packages/d2bd-runtime/src/console_session.rs:132] + evidence: err seed 1 (`\.unwrap\(\)|\.expect\(`) = 295 hits; census: pattern `ConsoleClientHandle::default` over packages = 0 hits; every other non-test unwrap/expect site in the lane is on a literally-built constant, a validated fingerprint, or a startup runtime build (card false-positive classes) +- d2bd-runtime-p4#13 sev=low blast=leaf effort=S verdict=actionable - `FilesystemReader` reports failures as `Result<..., String>`, so `compute_restart_status` cannot distinguish "file missing" from "file unreadable" without string inspection and the detail is only embeddable in a banner - fix: introduce a small `VersionFileReadError` enum (e.g. `Missing` vs `Unreadable(String)`) returned by both trait methods - [packages/d2bd-runtime/src/daemon_version.rs:77, packages/d2bd-runtime/src/daemon_version.rs:85] + evidence: err seed 4 (`enum \w*Error`) = 14 hits (all other error enums in the lane are closed, Display-bearing, wire-label taxonomies) +- clean: err seeds 1/2/3/4 = 295/14/0/14 hits; panic policy is sound outside tests - every remaining expect is a justified invariant (validated fingerprints, literal constants, map keys collected from the same map, runtime startup); swallowed results are deliberate best-effort cleanup or oneshot replies whose failure is the refusal signal + sampled: 50 of 295 hits (all non-test unwrap/expect sites read in context) + +## serde +- d2bd-runtime-p4#14 sev=low blast=leaf effort=S verdict=actionable - `parse_vm_info` hand-walks `serde_json::Value` with `and_then` chains to extract `state`/`boot_vcpus`/`memory.size` from the Cloud Hypervisor vm.info payload, re-implementing what a derived raw shape does at the boundary - fix: derive `Deserialize` on a raw `ChVmInfoRaw` with `#[serde(default)]` on every field (nested `config.cpus.boot_vcpus` / `config.memory.size`) and convert to `ChVmInfo` - [packages/d2bd-runtime/src/ch_api.rs:79] + evidence: serde seeds 1/2/3/4 = 22/13/0/46 hits; site-specific (the only Value-walking parse in the lane) +- clean: serde seeds 1/2/3/4 = 22/13/0/46 hits; `DaemonVersionFile`/`DaemonRestartStatus`/`GuestComponentSessionDescriptor` use `deny_unknown_fields` + `rename_all` + internal tagging correctly; the hand-written `Serialize for DaemonEvent` is a deliberate redaction admission gate (sanitize_daemon_event), not a derive candidate + +## obs +- d2bd-runtime-p4#15 sev=low blast=leaf effort=S verdict=actionable - `tracing::warn!("qemu console: failed to convert fd to tokio stream: {e}")` interpolates the error into the message instead of a named field, so the event is not queryable by error - fix: `tracing::warn!(error = %e, "qemu console: failed to convert fd to tokio stream")` - [packages/d2bd-runtime/src/console_session.rs:450] + evidence: obs seed 2 (`(info|debug|warn|error|trace)!\("`) = 7 hits; the other 6 events use named fields (daemon_audit.rs:892, kernel_module_check.rs:417, console_session.rs:402, guest_component_session.rs:322,342) or are doc prose +- clean: obs seeds 1/2/3/4 = 0/7/0/5 hits; zero println/eprintln, zero `instrument` spans (context comes from enclosing daemon spans), no secret-bearing fields found in any event + +## docs +- d2bd-runtime-p4#16 sev=low blast=leaf effort=S verdict=actionable - `wire_response_helpers.rs` ships 11 undocumented `pub fn`s (the module doc is the only prose), including `retarget_mutating_response` whose pass-through-on-unknown-outcome behavior is load-bearing for broker-forwarded responses - fix: add one-line contract docs per fn, naming the pass-through semantics and the wire fields projected - [packages/d2bd-runtime/src/wire_response_helpers.rs:7, packages/d2bd-runtime/src/wire_response_helpers.rs:118] + evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 393 hits; the file's pub surface enumerated in full (11 fns, zero doc comments) +- d2bd-runtime-p4#17 sev=low blast=leaf effort=S verdict=actionable - `ch_api.rs` leaves its public constants, error enum, info struct, and async entry points undocumented: `DEFAULT_TIMEOUT`/`MAX_RESPONSE_BYTES` are magic values without the why (contrast `CH_HTTP_TIMEOUT` at ch_stats.rs:120 which cites the legacy exporter), and `ChApiError` variants/`ChVmInfo` fields/`get_vm_info`/`shutdown_vm` have no docs - fix: document the consts with their provenance and add one-line docs to the enum, struct, and fns - [packages/d2bd-runtime/src/ch_api.rs:11, packages/d2bd-runtime/src/ch_api.rs:15, packages/d2bd-runtime/src/ch_api.rs:37, packages/d2bd-runtime/src/ch_api.rs:43] + evidence: docs seed 1 = 393 hits; site enumerated in full (ch_api.rs read whole) +- d2bd-runtime-p4#18 sev=low blast=leaf effort=S verdict=actionable - `target_runtime.rs` documents its domain types thoroughly but leaves a cluster of pub accessors undocumented: `AdmissionBudget::new/limits/active`, `AdmissionPermit::kind/release`, `ProviderDeployment::mode/target_kind/admission` - fix: add one-line docs (at minimum to `AdmissionPermit::release`, whose idempotence is a caller-relevant contract) - [packages/d2bd-runtime/src/target_runtime.rs:256, packages/d2bd-runtime/src/target_runtime.rs:311, packages/d2bd-runtime/src/target_runtime.rs:354, packages/d2bd-runtime/src/target_runtime.rs:1108] + evidence: docs seed 1 = 393 hits; sites verified by direct read (no `///` on the named methods) +- clean: docs seeds 1/2/3 = 393/0/393 hits; the lane's domain types (DaemonEvent, GuestIdentity, ModuleCheckReport, DaemonVersionFile, OpLockManager, leases) carry contract-grade docs with first-sentence shape; `# Errors`/`# Examples` sections are absent crate-wide (consistent prose style, not a per-item gap) + sampled: 50 of 393 hits (pub surface enumerated via structural summaries of all 13 files) + +## perf +- clean: perf seeds 1/2/3 = 61/27/2 hits; every `format!` site is cold (error diagnostics, audit rendering, one-shot startup) or the artifact IS text (ch_stats Prometheus block, daemon_version banner); `Vec::new()` sites are empty-case-common or bounded buffers; `read_async_capped`/`read_blocking_capped` already use `with_capacity`; no hot-path allocation or bounds-check class found + +## conc +- d2bd-runtime-p4#19 sev=medium blast=leaf effort=M verdict=policy-confirmed - `OpLockManager::acquire` busy-spins (`try_lock` + `std::hint::spin_loop()`) while the per-VM/global lock is held across a whole lifecycle op (composition.rs:5612 holds the guard across `dispatch_request_locked`, i.e. seconds for a VM start), so a concurrent same-VM or global request burns a full core for the op duration; the doc's "critical sections are single map ops" justification covers only the map-entry lock, not the held op lock - fix: replace the spin with the repo's sanctioned wait-on-condition shape (`tokio::sync::Notify` armed before the check + `tokio::time::timeout`, clippy.toml:37-39) or park/wake on the dedicated dispatch threads; requires a policy/ADR decision first - [packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189, packages/d2bd/src/composition.rs:5612] + evidence: conc seeds 1/2/3/4 = 26/28/45/0 hits; site read in full; static (unmeasured) - no benchmark exists for contended op throughput +- clean: conc seeds 1/2/3/4 = 26/28/45/0 hits; `ConnSemaphore` CAS uses the weakest correct orderings (Acquire/AcqRel), `HEALTHCHECK_COUNTER` is a Relaxed counter, the audit appender and connect-probe worker are dedicated bounded threads (R4 shape), no `unsafe impl Send/Sync`, no `thread_local!`/`static mut` + +## async +- d2bd-runtime-p4#20 sev=low blast=family effort=M verdict=actionable - `CONSOLE_DRAINER_RUNTIME` is a `static OnceLock` started inside library code (console_session.rs:33-44), giving the daemon a second multi-thread runtime per process that is never shut down, while the binary already owns a `#[tokio::main(flavor = "multi_thread")]` runtime (d2bd/src/main.rs:142) - fix: own the runtime at the binary top and pass a `tokio::runtime::Handle` into `create_ch_session`/`create_qemu_session` (or spawn drainers on the daemon runtime) instead of a crate-static `OnceLock` - [packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session.rs:35] + evidence: async seed 4 (`#\[tokio::(main|test)\]|Runtime::block_on`) = 4 hits; census: pattern `tokio::main` over packages/d2bd/src/main.rs = 1 hit (line 142); no async-gate-allow marker covers the drainer runtime (grep over packages/xtask/data/async-gate-inventory.json = 0 hits) +- clean: async seeds 1/2/3/4 = 47/8/22/4 hits; no guard is held across an await (ring guards are dropped before `notify_waiters()`), the async audit seat awaits a oneshot reply, `run_connect_probe` never parks the caller's executor, and the `#[tokio::test]` sites are plain harnesses + +## unsafe +- clean: unsafe seeds 1/2/3/4 = 0/0/1/0 hits; the single hit is doc prose (`from_raw_fd` mentioned in the `create_qemu_session` doc at console_session.rs:435, same false-positive class recorded in U1 (d)8 for typed_error.rs); zero unsafe blocks/fns/impls, zero SAFETY comments, zero transmute/MaybeUninit/zeroed in the lane + +## ffi +- N/A: ffi seeds 1/2/3/4 = 0/0/0/0 all zero; the lane crosses no foreign-language boundary (no extern, no repr(C), no CStr/CString, no catch_unwind) + +## macro +- N/A: macro seeds 1/2/3/4 = 0/0/0/0 all zero; no macro_rules!, no proc-macro/syn/quote, no $crate, no trybuild machinery in the lane + +## test +- d2bd-runtime-p4#21 sev=low blast=leaf effort=S verdict=actionable - `no_op_does_not_write_file` cannot fail on the behavior it names: the temp dir is never connected to the log (`DaemonAuditLog::no_op()` has no state dir; the comment at daemon_audit.rs:2368 admits the limitation), so `count == 0` is vacuously true and only the write-does-not-error `expect` is exercised - fix: make the state dir injectable (or test via a log constructed with a read-only/blocked state dir) so the no-file-created claim is actually asserted, or rename the test to what it verifies - [packages/d2bd-runtime/src/daemon_audit.rs:2367] + evidence: test seeds 1/2/3/4 = 75/317/0/0 hits (src + tests/runtime_boundary.rs); site read in full +- clean: test seeds 1/2/3/4 = 75/317/0/0 hits; the suite is behavior-asserting and deterministic - leak-safety sentinels with closed key-set assertions (daemon_audit), timing-free concurrency tests via barriers/channels (concurrency), table-driven parse cases (ch_api, kernel_module_check), zero `#[ignore]`, zero proptest/insta/rstest (plain unit + integration tests fit the assertions) + sampled: 50 of 392 hits (test bodies read via full-file reads of the smaller modules and hit neighborhoods of the two large files) + +## Coverage +- idiom: 2 finding(s) +- own: 2 finding(s) +- type: 3 finding(s) +- api: 4 finding(s) +- err: 2 finding(s) +- serde: 1 finding(s) +- obs: 1 finding(s) +- docs: 3 finding(s) +- perf: clean (seeds ran: 61/27/2) +- conc: 1 finding(s) +- async: 1 finding(s) +- unsafe: clean (seeds ran: 0/0/1/0) +- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary in the lane) +- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions or proc-macro machinery) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md new file mode 100644 index 000000000..a46968443 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md @@ -0,0 +1,333 @@ +# tail-1 - tail lane +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1113 (src + tests, excl. src/generated/** and integration/) | modules: d2b-broker-fixture-handlers, d2b-broker-fixture-syscall-surface, d2b-controller-toolkit, d2b-host-activation-helper, d2b-provider-audio-binding +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates + +## d2b-broker-fixture-handlers + +### idiom +- clean: seeds 0/0/0 (no index loops, no hand-written impls, no statement-style accumulation); the crate is one pure echo fn and reads idiomatic. + +### own +- clean: seeds 1/0/0/0; the single `.clone()` at lib.rs:21 copies the borrowed `payload: &CanonicalJsonObject` into the owned `DispatchOutcome.result` - the echo must own its result, so the clone is required (census: payload type at packages/d2b-broker/src/envelope/mod.rs:974; result type at :904). + +### type +- N/A: seeds 0/0/0 all zero; the crate declares no struct or enum (card criterion). + +### api +- clean: seeds 1/0/0; one pub fn (`echo`) documented and deliberately exported for the composition seam (census: registered as handler at packages/d2b-broker-composition/src/seam.rs:339, 538). + +### err +- clean: seeds 0/0/0/0; no panic sites, no swallowed Results; the fn returns the seam's `Result`. + +### serde +- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire. + +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). + +### docs +- clean: seeds 1/0/0; the single pub fn carries a one-line contract doc and the module has `//!` docs. + +### perf +- clean: seeds 0/1/0; the one `Vec::new()` (lib.rs:22) builds the empty fds list - the empty case is common, false-positive class. + +### conc +- N/A: seeds 0/0/0/0 all zero. + +### async +- clean: seeds 1/0/0/0; one `Box::pin(async move ...)` with no `.await`, no spawn, no shared state, no blocking - a single immediate future. + +### unsafe +- N/A: seeds 0/0/0/2; seeds 1-3 all zero - the two `unsafe_code` hits are the `#![deny(unsafe_code)]` attribute (lib.rs:13) and the manifest `deny` (Cargo.toml:9); no unsafe code exists. + +### ffi +- N/A: seeds 0/0/0/0 all zero. + +### macro +- N/A: seeds 0/0/0/0 all zero. + +### test +- N/A: seeds 0/0/0/0 all zero; the crate ships no tests (the seam exercises it from d2b-broker-composition). + +### Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 1/0/0/0) +- type: N/A (seeds: 0/0/0 all zero; no struct/enum declared) +- api: clean (seeds ran: 1/0/0) +- err: clean (seeds ran: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds ran: 1/0/0) +- perf: clean (seeds ran: 0/1/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: clean (seeds ran: 1/0/0/0) +- unsafe: N/A (seeds: 0/0/0/2; seeds 1-3 all zero, only the deny attribute/manifest text) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: N/A (seeds: 0/0/0/0 all zero; no tests) + +## d2b-broker-fixture-syscall-surface + +### idiom +- clean: seeds 0/0/0; two small fns and a static, no expression-shape issues. + +### own +- clean: seeds 0/0/0/0; no clones or shared-ownership types. + +### type +- N/A: seeds 0/0/0 all zero; the crate declares no struct or enum (card criterion). + +### api +- clean: seeds 3/0/0; three pub fns are the deliberate hostile surface the dependency-surface audit scans (census: audit probes at packages/d2b-broker-composition/src/dependency_surface.rs:436-471; refusal tests at seam.rs:612-638); the `FIXTURE_MARKER` static is private. + +### err +- clean: seeds 0/0/0/0; no panic sites; `install_isolation_silencer`'s panic-hook set is the deliberate audit target, not a panic policy issue. + +### serde +- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire. + +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). + +### docs +- clean: seeds 3/0/0; all three pub fns carry contract docs including the fixture rationale. + +### perf +- N/A: seeds 0/0/0 all zero. + +### conc +- N/A: seeds 0/0/0/0 all zero. + +### async +- N/A: seeds 0/0/0/0 all zero. + +### unsafe +- tail-1#1 sev=medium blast=leaf effort=S verdict=actionable - the x86_64 `asm!` block omits the registers the `syscall` instruction clobbers (rcx and r11), so the compiler's no-clobber assumption is violated if the fn is ever executed - fix: add `lateout("rcx") _`, `lateout("r11") _` (or `clobber_abi("C")`) to the asm operands at lib.rs:26-32 - [packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32] + evidence: seed `\bunsafe \{` = 2 hits, `// SAFETY:` = 2; static read of the asm block (no reachability path: the crate is a dev-dependency of the composition root only, never linked into the broker binary - packages/d2b-broker-composition/Cargo.toml:16-18, and none of the fns are ever called) +- clean: both unsafe blocks carry `// SAFETY:` comments (lib.rs:23-24, 40); the `#[unsafe(link_section)]` attribute and panic-hook registration are the deliberate fixture surface the audit must reject (U1 card false-positive class), not re-flagged. + +### ffi +- clean: seeds 1/0/0/0; the single hit is the `#[unsafe(link_section)]` marker - a link-time attribute, not a foreign-caller boundary (no extern "C", no repr, no CStr); deliberately hostile fixture surface. + +### macro +- N/A: seeds 0/0/0/0 all zero. + +### test +- N/A: seeds 0/0/0/0 all zero; no tests (the audit probes it from d2b-broker-composition). + +### Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 0/0/0/0) +- type: N/A (seeds: 0/0/0 all zero; no struct/enum declared) +- api: clean (seeds ran: 3/0/0) +- err: clean (seeds ran: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds ran: 3/0/0) +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: 1 finding +- ffi: clean (seeds ran: 1/0/0/0) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: N/A (seeds: 0/0/0/0 all zero; no tests) + +## d2b-controller-toolkit + +### idiom +- clean: seeds 0/3/0; the three hand-written `Debug` impls (context.rs:92, 125, contract.rs:35) are the deliberate-redaction class (canonical_json shown as byte count, ResourceKey prints structural constants) - a derive would leak, recorded false-positive class. + +### own +- clean: seeds 0/0/0/0; no clones, no refcounts, no Cow; accessors borrow. + +### type +- tail-1#2 sev=low blast=family effort=S verdict=actionable - `ResourceSnapshot` carries `owner_uid: Option` and `owner_generation: Option` that are only ever set together, leaving the illegal one-Some/one-None combination constructible - fix: introduce `OwnerIdentity { uid, generation }` and replace the pair with a single `Option` (fields context.rs:17-18, constructor :61-67; the only external setter call passes both Some - packages/d2b-provider-provider/src/driver.rs:559) - [packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/context.rs:61-67] + evidence: seeds 0/0/0 (lens applicable via the declared structs); census: `with_owner_identity` over packages/ = 1 call site (d2b-provider-provider/src/driver.rs:559, both Some) + definition; owner_generation() has no external consumers +- clean: no validate/check fns, no boolean-flag fields, no stringly-typed state; the single `deleting: bool` is a lone flag with no soup. + +### api +- clean: seeds 18/0/2; the `pub use` re-export arms (lib.rs:11-12) are the house single-surface pattern; no Arc/Rc/Box/RefCell in signatures; all three exported types are consumed (census: d2b-core-controller/src/lib.rs:52 re-exports them; d2b-provider-provider/src/driver.rs:52-53, providers.rs:8 use them). + +### err +- clean: seeds 0/0/0/0; no panic sites, no swallowed Results, no error enum (the crate's constructors cannot fail). + +### serde +- N/A: seeds 0/0/0/0 all zero; the snapshots are in-memory types (no serde derives), no wire. + +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). + +### docs +- clean: seeds 18/0/0; every pub item carries a one-line contract doc; no Result returns so no `# Errors` sections are owed. + +### perf +- N/A: seeds 0/0/0 all zero. + +### conc +- N/A: seeds 0/0/0/0 all zero. + +### async +- N/A: seeds 0/0/0/0 all zero. + +### unsafe +- N/A: seeds 0/0/0/0 all zero; the manifest's `[lints] workspace = true` reference carries no `unsafe_code` text (seed 4 zero too). + +### ffi +- N/A: seeds 0/0/0/0 all zero. + +### macro +- N/A: seeds 0/0/0/0 all zero. + +### test +- N/A: seeds 0/0/0/0 all zero; no tests and an empty dev-dependencies table (Cargo.toml:16). + +### Coverage +- idiom: clean (seeds ran: 0/3/0) +- own: clean (seeds ran: 0/0/0/0) +- type: 1 finding +- api: clean (seeds ran: 18/0/2) +- err: clean (seeds ran: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds ran: 18/0/0) +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace lints reference) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: N/A (seeds: 0/0/0/0 all zero; no tests) + +## d2b-host-activation-helper + +### idiom +- clean: seeds 0/0/0; no index loops, no hand-written impls, no statement-style accumulation; the arg-parsing match is idiomatic. + +### own +- clean: seeds 0/1/0/0; the single `.to_string()` (main.rs:69) builds a cold error string; no clones or refcounts anywhere. + +### type +- clean: seeds 0/0/0; the `Config` struct's lone `fail_closed: bool` is a single flag with no soup; gid parsing is checked at the boundary (`parse_gid` returns Result). + +### api +- N/A: seeds 0/0/0 all zero; bin-only crate with no lib target and no pub items (card criterion). + +### err +- clean: seeds 0/0/0/0 in production code; `main` uses `unwrap_or_else` (main.rs:341) and exits with codes; the only `.expect()` hits are in `#[cfg(test)]` (false-positive class). + +### serde +- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire. + +### obs +- clean: seeds 7/0/0/0; all seven `eprintln!` sites are CLI product output (usage, error reporting, migration audit lines) per the card's CLI false-positive class; no tracing/log dependency. + +### docs +- N/A: seeds 0/0/11; seed 1 zero - no public items exist in the bin crate (card: never add missing_docs to a binary crate); the 11 `-> Result<` hits are internal fns. + +### perf +- clean: seeds 5/0/1; all `format!` sites are cold paths (usage text, arg errors, one log line per migrated entry); no hot-loop allocation. + +### conc +- N/A: seeds 0/0/0/0 all zero; single-threaded walk. + +### async +- N/A: seeds 0/0/0/0 all zero. + +### unsafe +- tail-1#3 sev=medium blast=leaf effort=S verdict=actionable - 22 production `unsafe` blocks (libc calls plus `errno_clear`'s `__errno_location` write) carry no `// SAFETY:` comment, violating the skill's mechanical rule and U1 (d) 8 - fix: add a `// SAFETY:` comment to each block stating the invariant (CString NUL-termination, checked return before use, fd ownership) - [packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/src/main.rs:129, packages/d2b-host-activation-helper/src/main.rs:140, packages/d2b-host-activation-helper/src/main.rs:194, packages/d2b-host-activation-helper/src/main.rs:213, packages/d2b-host-activation-helper/src/main.rs:271] + evidence: seed `\bunsafe \{` = 24 hits (22 production + 2 cfg(test)), `// SAFETY:` = 0, `MaybeUninit` = 2; U1 (d) 8 mechanical rule (a block without a SAFETY comment is a finding) +- tail-1#4 sev=high blast=leaf effort=S verdict=actionable - `walk_dir` leaks the `fdopendir` DIR* handle on every error-path early return: `closedir` runs only on the readdir-null path (main.rs:206), so the `?` at :218, the `return Err` at :222 and :260, and `result?` at :265 all leak the directory stream (route review-pass) - fix: restructure so `closedir` runs on every exit (closure + close after, or an RAII guard) - [packages/d2b-host-activation-helper/src/main.rs:194, packages/d2b-host-activation-helper/src/main.rs:218, packages/d2b-host-activation-helper/src/main.rs:222, packages/d2b-host-activation-helper/src/main.rs:260, packages/d2b-host-activation-helper/src/main.rs:265] + evidence: static read of walk_dir (main.rs:186-268); closedir appears once on the success/end-of-stream path; the four early returns after fdopendir succeed skip it (correctness defect, not UB) +- clean: the libc calls themselves (open/fcntl/fstat/fstatat/dup/fdopendir/readdir/closedir/fchownat/openat/fchown/close) are standard usage with checked returns, `CString` NUL handling, and correct `MaybeUninit` (assume_init only after rc == 0); the two cfg(test) unsafe sites carry policy-tracked sanctioned allows. + +### ffi +- clean: seeds 0/0/0/5; the CStr/CString usage at the libc boundary is correct (NUL-termination via `CString::new` with InvalidInput errors, `CStr::from_ptr` on readdir's NUL-terminated d_name); these are libc-binding call sites that never cross a foreign caller (card false-positive class). + +### macro +- N/A: seeds 0/0/0/0 all zero. + +### test +- clean: seeds 2/5/0/0; two behavioral tests (migration walk + fail-closed rescan, held-lock fail-closed exit) with real tempdir filesystems, deterministic, no `#[ignore]`; each assertion can fail. + +### Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 0/1/0/0) +- type: clean (seeds ran: 0/0/0) +- api: N/A (seeds: 0/0/0 all zero; bin-only crate, no pub items) +- err: clean (seeds ran: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire) +- obs: clean (seeds ran: 7/0/0/0) +- docs: N/A (seeds: 0/0/11; seed 1 zero - no public items; bin-only crate) +- perf: clean (seeds ran: 5/0/1) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: 2 findings +- ffi: clean (seeds ran: 0/0/0/5) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 2/5/0/0) + +## d2b-provider-audio-binding + +### idiom +- clean: seeds 0/1/0; the hand-written `impl Default for AudioBinding` (audio_binding.rs:98) is justified - `Arc` has no field-wise default, and the impl wires the crate's own `BindingChildSource`. + +### own +- clean: seeds 2/1/0/0; the two `.clone()` calls (audio_binding.rs:130) copy `ResourceRef` values into the owned dependencies Vec the trait contract returns; the `to_owned` hit is a test fixture string; `Arc` is genuine shared ownership (behavior shared by driver and factory). + +### type +- clean: seeds 0/0/0; no validate/check fns, no boolean flags, no stringly-typed state; the child-request struct is three plain borrows. + +### api +- clean: seeds 11/2/1; the two `Arc` in public signatures (`AudioBinding::new` at :93, `audio_binding_spec_decoder` at :158) are the interaction-family pattern with genuine shared ownership (call sites: tests/registration.rs:72, descriptor construction at :163-180); the `pub use` arm (lib.rs:16-19) is the house single-surface pattern; the trait has one required method. + +### err +- clean: seeds 0/0/0/0 in src; no unwrap/expect/panic in production code; the `map_err(|_| InteractionEffectError::InvalidResource)` translation is the family port's coarse two-variant vocabulary (interaction.rs:125-130), the same translation the whole family applies - restructuring it is a family-contract change, not a binding-crate defect. + +### serde +- N/A: seeds 0/0/0/0 all zero; src crosses no wire (spec decoding happens through the family's `spec_decoder`); serde_json appears only in tests. + +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). + +### docs +- tail-1#5 sev=low blast=leaf effort=S verdict=actionable - the four Result-returning trait methods (`binding_children`, `validate`, `dependencies`, `desired_children`) lack `# Errors` sections saying which conditions yield `Unavailable` vs `InvalidResource`, even though the crate denies missing_docs - fix: add `# Errors` sections naming the family's two failure variants - [packages/d2b-provider-audio-binding/src/audio_binding.rs:56, packages/d2b-provider-audio-binding/src/audio_binding.rs:117, packages/d2b-provider-audio-binding/src/audio_binding.rs:125, packages/d2b-provider-audio-binding/src/audio_binding.rs:134] + evidence: docs seeds 11/0/4; all four `-> Result<` hits are pub trait methods without `# Errors` sections (the variants are documented only on the family enum, packages/d2b-provider-wayland-policy/src/interaction.rs:124-130) +- clean: every pub item carries a one-line contract doc (missing_docs denied in lib.rs:13); no `# Examples` sections owed where signatures are self-evident. + +### perf +- N/A: seeds 0/0/0 all zero. + +### conc +- N/A: seeds 0/0/0/0 all zero. + +### async +- N/A: seeds 0/0/0/0 all zero in src; the only async fns are the test harness's `async_trait` effect-port stubs (tests/registration.rs:33, 41). + +### unsafe +- N/A: seeds 0/0/0/1; seeds 1-3 all zero - the single `unsafe_code` hit is the manifest `forbid` (Cargo.toml:9), which does not make the lens applicable (card rule). + +### ffi +- N/A: seeds 0/0/0/0 all zero. + +### macro +- N/A: seeds 0/0/0/0 all zero. + +### test +- clean: seeds 5/14/0/0; five behavioral tests (declaration row, registry duplicate refusal, service/target reads, child-row materialization, foreign-row refusal) asserting observable contracts with real assertions; deterministic, no `#[ignore]`, no network. + +### Coverage +- idiom: clean (seeds ran: 0/1/0) +- own: clean (seeds ran: 2/1/0/0) +- type: clean (seeds ran: 0/0/0) +- api: clean (seeds ran: 11/2/1) +- err: clean (seeds ran: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire in src) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: 1 finding +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero in src) +- unsafe: N/A (seeds: 0/0/0/1; seed 4 = manifest forbid only) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 5/14/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md new file mode 100644 index 000000000..4d6926ce7 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md @@ -0,0 +1,331 @@ +# tail-2 - tail lane +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2457 (excl. src/generated/**) | modules: d2b-provider-audio-service, d2b-provider-command, d2b-provider-device, d2b-provider-emergency-policy, d2b-provider-operation +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates + +## d2b-provider-audio-service + +### idiom +- clean: seeds s1 index loop = 0, s2 `impl (Default|From|...) for` = 0, s3 `let mut ... = String/Vec::new()` = 0; one declaration struct + thin descriptor fns, no hand-written derives, no statement-style accumulation. + +### own +- clean: seeds 1-4 all zero (clone/to_owned/to_vec/to_string, Rc/RefCell/Arc` in `audio_service_spec_decoder` is the required trait-object return. + +### type +- clean: seeds 1-3 all zero (`fn validate_/check_`, `is_x: bool`/`x_flag: bool`, stringly `mode/kind/state`); unit struct `AudioService` carries no state, validation is delegated to the typed spec decode in the family engine. + +### api +- clean: seed 1 pub surface = 8 hits (AUDIO_SERVICE_PROVIDER_REF, AUDIO_SERVICE_RESYNC, AudioService, AudioServiceFactory, audio_service_spec_decoder, audio_service_descriptor, lib.rs re-export arms) - single re-export path, every item documented, no Arc/Rc/Box/RefCell/dependency types in signatures beyond the shared `InteractionDriverArgs` family-engine args (house interaction pattern, `d2b-provider-wayland-policy`). + +### err +- clean: seeds 1-4 all zero outside tests (no unwrap/expect, no panic!/unreachable!/todo!/unimplemented!, no error enum); `validate` returns `Result` and never panics on row input. + +### serde +- N/A: seeds 1-4 all zero (no serde derives, no serde attributes, no hand-written Deserialize, no serde_json calls); the crate crosses no wire of its own - `AudioServiceSpec` decode lives in `d2b-provider-wayland-policy@interaction::spec_decoder`. + +### obs +- N/A: seeds 1-4 all zero (no println!/eprintln!, no no-field message events, no instrument spans, no tracing/log) and Cargo.toml carries no tracing/log dependency. + +### docs +- clean: seed 1 pub items (six) + seed 3 `-> Result<` (three trait methods) = 9 hits, all public items documented under `#![deny(missing_docs)]` in lib.rs; module header explains the family split. + +### perf +- clean: seeds 1-3 = 2 hits (`Ok(Vec::new())` in `dependencies`/`desired_children`) - both are the deliberate empty desired-child set, empty case is the only case. + +### conc +- N/A: seeds 1-4 all zero (no threads, no Mutex/RwLock, no atomics, no thread_local/unsafe Send-Sync). + +### async +- N/A: seeds 1-4 all zero (no async fn, no spawn/select/join, no tokio sync types, no tokio main/test) over src; the registration test is plain `#[test]`. + +### unsafe +- N/A: seeds 1-4 all zero (no unsafe blocks/fns, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed) and manifest declares `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds 1-4 all zero (no extern "C"/no_mangle, no catch_unwind, no repr(C)/repr(transparent), no CStr/CString/c_char). + +### macro +- N/A: seeds 1-4 all zero (no macro_rules!, no proc_macro/syn/quote, no `$crate`, no to_compile_error/new_spanned). + +### test +- clean: seeds over src+tests = 17 hits (4 `#[test]`, 13 `assert*`); registration tests pin the declaration, the required Provider selector, duplicate-type refusal, spec decode, and foreign-row refusal - each fails on a concrete regression. + +### Coverage +- idiom: clean (0/0/0) +- own: clean (0/0/0/0) +- type: clean (0/0/0) +- api: clean (8 hits) +- err: clean (0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no wire) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) +- docs: clean (9 hits) +- perf: clean (2 hits; deliberate empty returns) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (17 hits: 4 #[test], 13 asserts) + +## d2b-provider-command + +### idiom +- clean: seeds 1-3 all zero; constructor-style parsing with `if let`/`else` and `strip_prefix`/`strip_suffix` chains reads idiomatic; `format!("{{{name}}}")` is the canonical-brace normalization. + +### own +- clean: seeds 1-4 = 6 hits (3 `.to_owned()` in `JsonSchema::schema_name`/`pattern` at the schemars trait boundary which demands owned values, 2 `.clone()` in `#[cfg(test)]` fixtures, 1 `.to_owned()` in JsonSchema metadata) - every hit is a required ownership transfer at a trait boundary or test fixture, none avoids a borrow. + +### type +- clean: seeds 1-3 all zero; `CommandExec`/`CommandArgvSlot` are parse-once private-field newtypes and `CommandSpec::new` validates cross-field invariants once at construction - the pattern this lens names as the goal. + +### api +- clean: seed 1 pub surface = 27 hits (constants, four newtypes, CommandIntent, CommandSpec, CommandContractError, command_descriptor, `pub use` arms); single re-export path (`pub mod command` + `pub use command::*` is the house spec-vocabulary pattern), fields private with accessors, no Arc/Rc/Box/RefCell or dependency types in signatures. + +### err +- clean: seeds 1-3 = 0 outside tests (all unwrap/expect live in `#[cfg(test)]`), seed 4 error enum = 1 (`CommandContractError`); the four variants split by caller action (exec vs argv vs role vs placeholder), each documented, deserialize failures surface as serde errors, never panics. + +### serde +- tail-2#1 sev=medium blast=leaf effort=S verdict=needs-contract - the emitted JsonSchema for `CommandExec` (`pattern: "^/[^\\u0000]*$"`) and `CommandArgvSlot` (no pattern) is weaker than the parse admission (rejects control chars/empty/malformed braces/invalid placeholder names), so a value satisfying the published schema can be refused at serde deserialization - fix: tighten the `CommandExec` pattern to exclude `char::is_control` code points and add a `CommandArgvSlot` pattern (or an explicit `format`/`pattern` encoding the whole-slot brace rule), then regenerate the committed schema - [packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/command.rs:133-152, docs/reference/schemas/v3/core.d2bus.org_Command.schema.json:21] + evidence: serde seed 2 `serde\((rename_all|...|pattern...)` = 0 but seed 3 `impl .*Deserialize.*for` = 2 plus seed 1 derive = 2; divergence verified against the emitted, committed schema `docs/reference/schemas/v3/core.d2bus.org_Command.schema.json` definitions.CommandExec (`pattern "^/[^\\u0000]*$"`) and definitions.CommandArgvSlot (no pattern), generated from these impls; generated-schema text is a wire contract surface. +- clean: other than tail-2#1 - hand-written `Deserialize` for CommandExec/CommandArgvSlot/CommandSpec are live admission gates on a wire shape (recorded refusal class (d) 6), `deny_unknown_fields` on the `Wire` shape and `CommandIntent`, `#[serde(transparent)]` round-trips; seed counts: seed1 = 2, seed2 = 5, seed3 = 3, seed4 = 0. + +### obs +- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency. + +### docs +- tail-2#2 sev=low blast=leaf effort=S verdict=actionable - public `Result`-returning constructors `CommandExec::parse`, `CommandArgvSlot::parse`, and `CommandSpec::new` return `Result<..., CommandContractError>` without an `# Errors` section naming which variants each can produce, though callers match on them (tests assert exact variants) - fix: add a one-line `# Errors` per constructor naming its `CommandContractError` variants - [packages/d2b-provider-command/src/command.rs:38, packages/d2b-provider-command/src/command.rs:89, packages/d2b-provider-command/src/command.rs:192] + evidence: docs seed 3 `-> Result<` = 6 hits over the three public constructors plus validation methods; seed 1 public items = 27 hits, all documented (missing_docs denied) except the canonical-section gap. +- clean: otherwise all public items carry one-line first sentences and module header explains the launch-shape contract. + +### perf +- clean: seeds 1-3 = 1 hit (`format!("{{{name}}}")` in `CommandArgvSlot::parse`) - argument-slot canonicalization runs at declaration admission once, not in a loop or hot path; no other allocation sites. + +### conc +- N/A: seeds 1-4 all zero (no threads, no Mutex/RwLock, no atomics, no thread_local/unsafe Send-Sync) over src. + +### async +- N/A: seeds 1-4 all zero over src (no async fn, no tokio spawn/select/join, no tokio sync, no tokio main/test); the only async surface is the `#[tokio::test]` registration scaffold in tests, which owns no state. + +### unsafe +- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds 1-4 all zero. + +### macro +- N/A: seeds 1-4 all zero; the `redacted_debug!` uses are imported macros from `d2b-contracts-resource` (deliberate exported-API macros, not definitions here). + +### test +- clean: seeds over src+tests = 14 hits (4 `#[test]`, 1 `#[tokio::test]` registration, 9 `assert*`); unit tests pin placeholder resolution, undeclared-placeholder refusal, brace/exec malformation refusal, role-type refusal, and a canonical round trip with unknown-field refusal - each fails on a real regression; the registration test is the documented 13-17-line shared-assertion pattern (do not flag). + +### Coverage +- idiom: clean (0/0/0) +- own: clean (6 hits; all trait-boundary/fixture) +- type: clean (0/0/0) +- api: clean (27 hits) +- err: clean (0/0/0 outside tests; 1 error enum) +- serde: 1 finding (10 hits) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) +- docs: 1 finding (30 hits) +- perf: clean (1 hit; cold admission path) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero over src) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (14 hits: 4 #[test], 1 #[tokio::test], 9 asserts) + +## d2b-provider-device + +### idiom +- clean: seeds 1-3 all zero; match-based `declared_dependency_refs`, const-fn descriptor building, and async-trait delegation read idiomatic; no index loops, hand-written derives, or statement accumulation. + +### own +- clean: seeds 1-4 = 3 hits (2 `.to_owned()` in the `inspect-device-response-invalid` error path, 1 `Arc>` in `DeviceResourceState`); the to_owned builds a cold error message, and the Arc-guarded caches are genuine shared ownership between the driver family and the daemon runtime - the four-question test passes; the `parking_lot::Mutex` choice is contract-justified (see api tail-2#3). + +### type +- clean: seeds 1-3 all zero; `DeviceComponent` is a closed four-variant vocab for the declared family, `DeviceResourceState` is a plain state bag, no boolean flags or stringly state. + +### api +- tail-2#3 sev=medium blast=family effort=L verdict=actionable - `DeviceResourceState` exposes raw `Arc>>` and `Arc>>` as pub fields, leaking wrapper types and the `parking_lot` dependency into the crate's public API (parking_lot is banned outright by (d) 2 outside the R4 worker boundary; this site is comment-justified only, driver.rs:137-138, matching the GPU crate's cache at d2b-provider-device-gpu/src/effects_service.rs:79) - fix: make the three caches private and expose narrow typed accessor methods on `DeviceResourceState` (or an effects-owned registry handle), keeping the GPU authority-lease construction contract behind the crate, and migrate the nine daemon read sites - [packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effects.rs:1584, packages/d2bd/src/shared_provider_effects.rs:2092, packages/d2bd/src/shared_provider_effects.rs:2122] + evidence: api seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits (tpm_controllers, gpu_controllers, gpu_authority_leases); census: `tpm_controllers|gpu_controllers|gpu_authority_leases` over packages = 9 read sites in packages/d2bd/src/shared_provider_effects.rs (1584, 1632, 1657, 2092, 2122, 2479, 2512, 2568, 2586) - the field access is genuinely needed across the crate boundary; parking_lot (d) 2 ban context cited. +- clean: otherwise seed 1 pub surface = 31 hits, single re-export path (lib.rs `pub use driver::{...}` + `pub use effects_service::DEVICE_EFFECTS_SERVICE`), documented under `#![deny(missing_docs)]`, `DeviceComponents`/trait seams carry no other wrapper or dependency types. + +### err +- clean: seeds 1-4 all zero outside tests (no unwrap/expect, no panic!/unreachable!/todo!, no error enum); `inspect_device_response` maps the trusted-static-json refusal to a named `EffectServiceError::Declined` reason instead of swallowing, and the error `map_err` names its own code. + +### serde +- clean: seeds 1-4 = 1 hit (`serde_json::from_value` in `inspect_device_response`) - a static literal payload rendered through the canonical JSON path, not an untrusted-input admission gate; no wire types deserialize in this crate. + +### obs +- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency; all daemon-side telemetry lives behind the facet trait in d2bd. + +### docs +- clean: seed 1 pub items + seed 3 = 35 hits; every pub item, pub field, and trait method documented under `#![deny(missing_docs)]`; the dead-code `facets` carry in `DeviceEffectsServiceFactory` is documented as the unwired R5 respawn contract (refused scaffolding class (d) 6 - cited, not re-flagged). + +### perf +- clean: seeds 1-3 = 1 hit (`Vec::new()` in `declared_dependency_refs` for the Usbip/SecurityKey arms) - the deliberate empty dependency set; no format!/string copies in cold or hot paths. + +### conc +- clean: seeds 1-3 = 3 hits (two `Arc>`, one `parking_lot::Mutex` scope) - the shared-state model is the documented daemon/driver seam over per-resource caches; guards are std/sync, held briefly, never across an `.await` (`await_holding_lock` is denied at the workspace); the `async-gate-allow: test-support recorder lock` markers in test_support.rs:37,49 are recorded exceptions (d) 3 - cited, not re-flagged; the parking_lot dependency leak is carried by api tail-2#3. + +### async +- clean: seeds 1-4 = 16 hits over src (async fn trait methods + `.await` delegation) - the effects delegate to the `DeviceRuntime` facet trait, no blocking work runs in src async bodies, no tokio sync guard spans an await, and `#[async_trait]` bounds the Send/Sync claims on `DeviceDriverEffects`/`DeviceRuntime`; test recorder locks carry their (d) 3 markers. + +### unsafe +- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds 1-4 all zero. + +### macro +- N/A: seeds 1-4 all zero. + +### test +- clean: seeds over src+tests = 9 hits (1 `#[test]`, 1 `#[tokio::test]`, 7 `assert*`; the `integration/device_family.rs` scaffold is policy-required (d) 5 and out of the test lane's src+tests scope); tests pin the four realizer provider identities, per-row resync, component-dispatch dispatch, and foreign-provider terminal failure - each fails on a real regression; `test-support` feature gating is the house pattern. + +### Coverage +- idiom: clean (0/0/0) +- own: clean (3 hits; shared-state seam + cold error paths) +- type: clean (0/0/0) +- api: 1 finding (31 hits) +- err: clean (0/0/0/0) +- serde: clean (1 hit; static payload only) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) +- docs: clean (35 hits) +- perf: clean (1 hit; deliberate empty set) +- conc: clean (3 hits; documented seam, no guard across await) +- async: clean (16 hits) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (9 hits: 1 #[test], 1 #[tokio::test], 7 asserts) + +## d2b-provider-emergency-policy + +### idiom +- clean: seeds 1-3 all zero; the single descriptor fn is a one-liner delegating to `metadata_descriptor`. + +### own +- N/A: seeds 1-4 all zero and no fn takes parameters (`emergency_policy_descriptor()`). + +### type +- N/A: seeds 1-3 all zero and the crate declares no struct or enum (driver fn only). + +### api +- clean: seed 1 pub surface = 2 hits (`emergency_policy_descriptor` + lib.rs re-export arm) - one documented pub fn, single re-export path, no wrappers or dependency types. + +### err +- clean: seeds 1-4 all zero; the only fn builds a descriptor and cannot panic on input. + +### serde +- N/A: seeds 1-4 all zero (crate crosses no wire; the metadata conversion owns no spec shape). + +### obs +- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency. + +### docs +- clean: seed 1 = 1 hit (`pub fn emergency_policy_descriptor`, documented under `#![deny(missing_docs)]`); module header explains the metadata-only conversion. + +### perf +- N/A: seeds 1-3 all zero. + +### conc +- N/A: seeds 1-4 all zero. + +### async +- N/A: seeds 1-4 all zero. + +### unsafe +- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds 1-4 all zero. + +### macro +- N/A: seeds 1-4 all zero. + +### test +- clean: seeds over src+tests = 1 hit (`#[tokio::test]` registration calling the shared `assert_metadata_registration` - the documented 13-17-line pattern, do not flag as trivial). + +### Coverage +- idiom: clean (0/0/0) +- own: N/A (seeds: 0/0/0/0 all zero; no fn parameters) +- type: N/A (seeds: 0/0/0 all zero; declares no struct/enum) +- api: clean (2 hits) +- err: clean (0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) +- docs: clean (1 hit) +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (1 hit: 1 #[tokio::test] registration) + +## d2b-provider-operation + +### idiom +- clean: seeds 1-3 = 1 hit (`impl Default for OperationBounds`) - the hand-written Default is the sanctioned invariant-preserving case (a field-wise derive would produce 0/0/0, which `OperationBounds::new` rejects), and it shares its value source with the serde `default =` fns; no index loops or statement accumulation. + +### own +- clean: seeds 1-4 = 1 hit (`.to_owned()` in a `#[cfg(test)]` assertion's expected string) - cold test-only, no production clones or refcounts. + +### type +- clean: seeds 1-3 all zero; every facet is a private-field struct with a validating constructor, `owner_ref`/`wire_tag` mutual exclusion (a two-Option pair the lens warns about) is enforced in `OperationSpec::new` and the type is a wire-pinned manifest shape - restructuring it is needs-contract with no new bug class covered, so left as validated state. + +### api +- clean: seed 1 pub surface = 68 hits (six facet structs, seven closed enums, OperationSpec, OperationContractError, eight bounds consts) - the deliberate wide wire vocabulary that IS the contract (api card false positive), single re-export path (`pub mod operation` + `pub use operation::*` house pattern), fields private with accessors, `Copy` where the enum has no payload; `OperationSpec::new`'s 11 arguments are `#[allow(clippy::too_many_arguments)]`-recorded and constructed once from admission, a builder would be over-engineering. + +### err +- clean: seeds 1-3 = 0 outside tests (all unwrap/expect in `#[cfg(test)]`), seed 4 = 1 (`OperationContractError`, eight variants); each variant is a distinct caller-action rejection of a declaration, all documented, constructors return `Result` and never panic on input, `unwrap_or_default` on `.split(':').next()` is infallible by construction. + +### serde +- clean: seeds 1-4 = 49 hits; the hand-written `Deserialize for OperationSpec` over a `deny_unknown_fields` `Wire` shape calling `Self::new` is the recorded live admission-gate pattern ((d) 6, recorded refusal class - cited, not re-flagged); kebab-case external enums are consistent, `deny_unknown_fields` on every facet, `skip_serializing_if = "Option::is_none"` round-trips (test asserts `wireTag` is absent), `serde(default = ...)` backs `OperationBounds`. + +### obs +- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency. + +### docs +- tail-2#4 sev=low blast=leaf effort=S verdict=actionable - public `Result`-returning constructors `OperationAudit::new`, `AuditJoin::new`, `OperationFds::new`, `OperationBounds::new`, and `OperationSpec::new` return `Result<..., OperationContractError>` without `# Errors` sections naming which variants each can produce, though callers match exact variants (tests assert them) - fix: add a one-line `# Errors` per constructor naming its `OperationContractError` variants - [packages/d2b-provider-operation/src/operation.rs:138, packages/d2b-provider-operation/src/operation.rs:194, packages/d2b-provider-operation/src/operation.rs:347, packages/d2b-provider-operation/src/operation.rs:405, packages/d2b-provider-operation/src/operation.rs:475] + evidence: docs seed 3 `-> Result<` = 8 hits across the five public constructors plus accessor returns; seed 1 public items = 72 hits, all documented (missing_docs denied) except the canonical-section gap. +- clean: otherwise every pub item, const, and enum variant carries a one-line doc; module header explains the materialized-vs-inherited split and the facet set. + +### perf +- N/A: seeds 1-3 all zero (no format!, no grow-by-push collections, no to_string copies in src). + +### conc +- N/A: seeds 1-4 all zero. + +### async +- N/A: seeds 1-4 all zero over src (no async fn, no tokio surface); the only async is the `#[tokio::test]` registration scaffold. + +### unsafe +- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds 1-4 all zero. + +### macro +- N/A: seeds 1-4 all zero. + +### test +- clean: seeds over src+tests = 19 hits (5 `#[test]`, 1 `#[tokio::test]` registration, 13 `assert*`); tests pin materialized-command owner, wire-tag exclusivity, secret-access ceiling, a table-driven audit-join rejection loop with per-case messages, bounds ceiling rejections, and a closed round trip - each fails on a real regression. + +### Coverage +- idiom: clean (1 hit; sanctioned invariant-preserving Default) +- own: clean (1 hit; test-only) +- type: clean (0/0/0) +- api: clean (68 hits) +- err: clean (0/0/0 outside tests; 1 error enum) +- serde: clean (49 hits) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) +- docs: 1 finding (72 hits) +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (19 hits: 5 #[test], 1 #[tokio::test], 13 asserts) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md new file mode 100644 index 000000000..09f41c1cd --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md @@ -0,0 +1,271 @@ +# tail-3 - tail lane +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1723 (excl. src/generated/**) | modules: d2b-provider-process-minijail, d2b-provider-quota, d2b-provider-resource-export, d2b-provider-resource-import, d2b-provider-role +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test, supply | Partitions: whole crates (tail lane) + +## d2b-provider-process-minijail +### idiom +- clean: seeds ran 0/0/0; no index loops, no hand-written impls (the only impls are the required `ProcessProvider` trait impl and derives), no statement-style accumulation; let-chains used throughout (edition 2024). +### own +- clean: seeds ran 2/0/0/0; the two `.clone()` sites build the owned `ProcessStatusReport` in `report()` (`self.profile.provider().clone()`, `ticket.execution_ref().clone()`) and are explainable owned-report construction; no Rc/RefCell/Arc/Cow. +### type +- tail-3#1 sev=low blast=leaf effort=S verdict=actionable - provider-identity validation is duplicated: `MinijailProcessProvider::validate` re-checks selected provider name and provider ref that `launch::validate_launch_ticket` repeats whenever a platform gate is present, so the two can drift apart - fix: drop the two identity checks from `validate_launch_ticket` (keep the gate check; rename it `validate_platform_gate` to disambiguate from the sibling `d2b-provider-process-systemd/src/launch.rs:8` function of the same name with different semantics) and use `crate::PROVIDER_REF` at lib.rs:160 instead of the literal string - [packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minijail/src/lib.rs:160, packages/d2b-provider-process-minijail/src/launch.rs:50, packages/d2b-provider-process-minijail/src/launch.rs:62] + evidence: seed `fn validate_\w+|fn check_\w+` = 1 hit (`validate_launch_ticket`, launch.rs:46); census: `validate_launch_ticket` over packages/nixos-modules/tests/docs/reference/labs = 3 hits (definition, the single call at lib.rs:193, and the sibling systemd definition) +### api +- clean: seeds ran 15/0/0; surface is the two `PROVIDER_NAME`/`PROVIDER_REF` consts, `MinijailProcessProvider` over the injected effect port (the house provider-controller seam), and the `launch`/`adoption` modules; no Arc/Rc/Box/RefCell in signatures; no `pub use` arms. +### err +- clean: seeds ran 2/0/0/0; the two `expect` sites (lib.rs:94, 106) assert frozen compile-time constants ("the frozen provider name is a valid token", "the frozen system-minijail profile is well formed") - the recorded literally-built-value false-positive class; no panics, no swallowed Results, no crate-local error enum (shared `ProcessConformanceError`). +### serde +- N/A: seeds 0/0/0/0 all zero; crate crosses no wire (no serde derives, no serde_json). +### obs +- clean: seeds ran 0/0/0/1; all telemetry is `tracing::warn!`/`debug!` with named fields (`provider`, `resource`, `error`, `identity`), message-only events carry no interpolated data, no println, no secrets in fields (identity digests only). +### docs +- tail-3#2 sev=low blast=leaf effort=S verdict=actionable - public Result-returning items carry no `# Errors` section stating which conditions produce which `ProcessConformanceError` variant - fix: add `# Errors` to `PlatformGate::validate`, `validate_launch_ticket`, `launch_with_inherited_fds`, `adopt`, `stop`, and `stop_stale` (the shared catalog is `d2b_process_conformance::ProcessConformanceError`) - [packages/d2b-provider-process-minijail/src/launch.rs:33, packages/d2b-provider-process-minijail/src/launch.rs:46, packages/d2b-provider-process-minijail/src/lib.rs:313, packages/d2b-provider-process-minijail/src/lib.rs:371, packages/d2b-provider-process-minijail/src/lib.rs:453, packages/d2b-provider-process-minijail/src/lib.rs:475] + evidence: docs seeds: pub items 13, `/// # (Examples|Errors|Panics|Safety)` 0, `-> Result<` 9 (2 in launch.rs, 7 in lib.rs; 6 of the 9 are public) +### perf +- clean: seeds ran 0/1/0; the single `Vec::new()` is the cold default in `launch()` delegating to `launch_with_inherited_fds` (lib.rs:306); no format! or to_string() in src; static (unmeasured). +### conc +- N/A: seeds 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync. +### async +- clean: seeds ran 19/0/0/0; `launch`/`adopt`/`stop`/`stop_stale` hold no locks across `.await`, spawn nothing, and do no blocking work; tests use the sanctioned plain `#[test]` + `d2b_process_conformance::testing::block_on` harness. +### unsafe +- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. +### ffi +- N/A: seeds 0/0/0/0 all zero. +### macro +- N/A: seeds 0/0/0/0 all zero. +### test +- clean: seeds ran 22/52/0/0; conformance.rs, execution_parents.rs, and platform_gate.rs assert behavior through `ScriptedEffectPort` call sequences (`PortCall::Observe`/`OpenPidfd`/`Stop`) and outcome variants, not implementation; deterministic, no network, no ignored tests; the shared `suite::` assertions plus minijail-specific pidfd/wait-ownership cells cover the fail-closed paths. +### supply +- clean: deps d2b-contracts-resource, d2b-process-conformance, tracing all appear in src/; no unused deps (X1 owns workspace-level supply). + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 2/0/0/0) +- type: 1 finding(s) +- api: clean (seeds ran: 15/0/0) +- err: clean (seeds ran: 2/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) +- obs: clean (seeds ran: 0/0/0/1) +- docs: 1 finding(s) +- perf: clean (seeds ran: 0/1/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: clean (seeds ran: 19/0/0/0) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 22/52/0/0) +- supply: clean (per-crate dep check; X1 owns workspace level) + +## d2b-provider-quota +### idiom +- clean: seeds ran 0/0/0; no index loops, hand-written impls, or statement-style accumulation; derives carry the value type. +### own +- clean: seeds ran 0/0/0/0; no clones, no shared ownership; applicable because the accessors take `&self`. +### type +- clean: seeds ran 0/0/0; `QuotaStatusResource` is a read-only status shape with private fields and const accessors; no boolean-flag or stringly-typed state; applicable because the crate declares a struct. +### api +- tail-3#3 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: the `quota` module is unconditionally `pub`, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza (or gate the test-consumed exports behind it, matching the house pattern of feature-gated test-support) - [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21] + evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates (quota/role/resource-export/resource-import Cargo.toml:17), enabled by no manifest (d2bd enables it for 20+ provider crates, not these); prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 +### err +- clean: seeds ran 0/0/0/0; no unwrap/expect/panic, no swallowed Results; applicable because fns exist, and the panic policy is trivially clean. +### serde +- clean: seeds ran 1/1/0/0; `QuotaStatusResource` derives Serialize/Deserialize/JsonSchema with `rename_all = "camelCase"` + `deny_unknown_fields`; it is daemon output (status), so no try_from validation is owed; the shape is exercised by d2b-resource-api manager_backend tests (census: 2 hits there). +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. +### docs +- clean: seeds ran 6/0/0; every pub item (struct, three accessors, `QuotaStatus` alias, `quota_descriptor`) documented under `#![deny(missing_docs)]`; module docs present in lib.rs, driver.rs, quota.rs. +### perf +- N/A: seeds 0/0/0 all zero. +### conc +- N/A: seeds 0/0/0/0 all zero. +### async +- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. +### unsafe +- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. +### ffi +- N/A: seeds 0/0/0/0 all zero. +### macro +- N/A: seeds 0/0/0/0 all zero. +### test +- clean: seeds ran 1/0/0/0; the single test is the policy-required registration-test pattern calling the shared `assert_metadata_registration` (recorded refusal class; not flagged). +### supply +- tail-3#4 sev=low blast=leaf effort=S verdict=actionable - `serde_json` is a declared dependency but appears nowhere in the crate's src/ or tests/ - fix: drop `serde_json.workspace = true` from [dependencies] - [packages/d2b-provider-quota/Cargo.toml:24] + evidence: census: `serde_json` over packages/d2b-provider-quota = 1 hit, the manifest line itself; zero hits in src/ and tests/ (the resource-api consumer test uses its own serde_json) + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 0/0/0/0) +- type: clean (seeds ran: 0/0/0) +- api: 1 finding(s) +- err: clean (seeds ran: 0/0/0/0) +- serde: clean (seeds ran: 1/1/0/0) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds ran: 6/0/0) +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 1/0/0/0) +- supply: 1 finding(s) + +## d2b-provider-resource-export +### idiom +- clean: seeds ran 0/0/0; single descriptor fn, no loops or accumulation. +### own +- N/A: seeds 0/0/0/0 all zero; no fn takes parameters. +### type +- N/A: seeds 0/0/0 all zero; no struct or enum declared. +### api +- tail-3#5 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_export_descriptor` unconditionally, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza - [packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export/src/lib.rs:18] + evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates, enabled by no manifest; prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 +### err +- clean: seeds ran 0/0/0/0; no panic sites, no swallowed Results; applicable because `resource_export_descriptor` exists. +### serde +- N/A: seeds 0/0/0/0 all zero; crate crosses no wire. +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. +### docs +- clean: seeds ran 1/0/0; `resource_export_descriptor` documented, module docs in lib.rs and driver.rs, `#![deny(missing_docs)]` active. +### perf +- N/A: seeds 0/0/0 all zero. +### conc +- N/A: seeds 0/0/0/0 all zero. +### async +- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. +### unsafe +- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. +### ffi +- N/A: seeds 0/0/0/0 all zero. +### macro +- N/A: seeds 0/0/0/0 all zero. +### test +- clean: seeds ran 1/0/0/0; the single test is the policy-required registration-test pattern calling the shared `assert_metadata_registration` (recorded refusal class; not flagged). +### supply +- clean: the only dep, d2b-resource-types, appears in src/; no unused deps. + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: N/A (seeds: 0/0/0/0 all zero; no fn takes parameters) +- type: N/A (seeds: 0/0/0 all zero; no struct or enum declared) +- api: 1 finding(s) +- err: clean (seeds ran: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds ran: 1/0/0) +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 1/0/0/0) +- supply: clean (per-crate dep check; X1 owns workspace level) + +## d2b-provider-resource-import +### idiom +- clean: seeds ran 0/0/0; single descriptor fn, no loops or accumulation. +### own +- N/A: seeds 0/0/0/0 all zero; no fn takes parameters. +### type +- N/A: seeds 0/0/0 all zero; no struct or enum declared. +### api +- tail-3#6 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_import_descriptor` unconditionally, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza - [packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import/src/lib.rs:18] + evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates, enabled by no manifest; prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 +### err +- clean: seeds ran 0/0/0/0; no panic sites, no swallowed Results; applicable because `resource_import_descriptor` exists. +### serde +- N/A: seeds 0/0/0/0 all zero; crate crosses no wire. +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. +### docs +- clean: seeds ran 1/0/0; `resource_import_descriptor` documented, module docs in lib.rs and driver.rs, `#![deny(missing_docs)]` active. +### perf +- N/A: seeds 0/0/0 all zero. +### conc +- N/A: seeds 0/0/0/0 all zero. +### async +- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. +### unsafe +- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. +### ffi +- N/A: seeds 0/0/0/0 all zero. +### macro +- N/A: seeds 0/0/0/0 all zero. +### test +- clean: seeds ran 1/0/0/0; the single test is the policy-required registration-test pattern calling the shared `assert_metadata_registration` (recorded refusal class; not flagged). +### supply +- clean: the only dep, d2b-resource-types, appears in src/; no unused deps. + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: N/A (seeds: 0/0/0/0 all zero; no fn takes parameters) +- type: N/A (seeds: 0/0/0 all zero; no struct or enum declared) +- api: 1 finding(s) +- err: clean (seeds ran: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds ran: 1/0/0) +- perf: N/A (seeds: 0/0/0 all zero) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 1/0/0/0) +- supply: clean (per-crate dep check; X1 owns workspace level) + +## d2b-provider-role +### idiom +- clean: seeds ran 0/0/0; no index loops, no hand-written impls beyond the deliberate `Debug` for `PositiveDecisionCache` (lock-free diagnostics, documented and tested), no statement-style accumulation. +### own +- clean: seeds ran 0/0/0/0; no clones, no shared ownership; applicable because the cache fns take `&self`/`&key`. +### type +- clean: seeds ran 0/0/0; `PolicyRevisionSet`/`AuthorizationCacheKey`/`PositiveEntry`/`PositiveDecisionCache` model the revision-bound positive-only cache with no boolean-flag or stringly-typed state; applicable because the crate declares structs. +### api +- tail-3#8 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: `rbac` is unconditionally `pub`, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza - [packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16] + evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates, enabled by no manifest; prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 +### err +- clean: seeds ran 5/0/0/0; all five unwrap hits sit inside `#[cfg(test)] mod tests` in rbac.rs (fixture refs and generations), the recorded test false-positive class; the production lock path handles poison explicitly (`unwrap_or_else` clearing the entries). +### serde +- N/A: seeds 0/0/0/0 all zero; crate crosses no wire. +### obs +- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. +### docs +- tail-3#7 sev=low blast=leaf effort=S verdict=actionable - role's lib.rs lacks the `#![deny(missing_docs)]` gate that its four sibling declaration crates in this lane all carry (quota lib.rs:16, resource-export lib.rs:14, resource-import lib.rs:14, minijail lib.rs:25), and `PolicyRevisionSet`'s four pub fields are undocumented - fix: add `#![deny(missing_docs)]` to lib.rs and document the `PolicyRevisionSet` fields - [packages/d2b-provider-role/src/lib.rs:1, packages/d2b-provider-role/src/rbac.rs:11] + evidence: docs seeds: pub items 9, `/// # (Examples|Errors|Panics|Safety)` 0, `-> Result<` 0; grep `deny\(missing_docs\)` = 0 hits in role vs 1 each in the four sibling crates +### perf +- clean: seeds ran 3/1/0; the format! hits are test-only (redaction sentinel checks), the single `BTreeMap::new()` is the cache constructor; bounded cache with retain-on-access, no hot-path allocation; static (unmeasured). +### conc +- clean: seeds ran 0/1/0/0; the `std::sync::Mutex` behind `PositiveDecisionCache` carries the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` (U1 (d)4 sanctioned reason), and the `Debug` impl deliberately uses `try_lock` so diagnostics never block; no atomics, no unsafe Send/Sync. +### async +- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. +### unsafe +- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. +### ffi +- N/A: seeds 0/0/0/0 all zero. +### macro +- N/A: seeds 0/0/0/0 all zero; `redacted_debug!` is an invocation of the contracts-crate macro, not a definition. +### test +- clean: seeds ran 3/8/0/0; rbac unit tests assert the redaction contract (sentinel absence, exact Debug string) and expiry/revision-invalidation behavior with hand-written expectations; registration test is the policy-required pattern; deterministic, no ignored tests. +### supply +- clean: deps d2b-contracts-resource and d2b-resource-types both appear in src/; no unused deps. + +## Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 0/0/0/0) +- type: clean (seeds ran: 0/0/0) +- api: 1 finding(s) +- err: clean (seeds ran: 5/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: 1 finding(s) +- perf: clean (seeds ran: 3/1/0) +- conc: clean (seeds ran: 0/1/0/0) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0/0 all zero) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 3/8/0/0) +- supply: clean (per-crate dep check; X1 owns workspace level) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md new file mode 100644 index 000000000..1d9262fe4 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md @@ -0,0 +1,336 @@ +# tail-4 - tail lane +Baseline: 6ebdd4cec | LOC audited: 2515 (excl. src/generated/**) | modules: d2b-provider-role-binding, d2b-provider-seccomp-profile, d2b-provider-shell-pool, d2b-provider-shell-session, d2b-provider-telemetry-binding +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test, supply | Partitions: whole crates + +## d2b-provider-role-binding + +### idiom +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the only fn body is the one-line descriptor declaration, nothing to judge. + +### own +- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 0, `Rc<|RefCell<|Arc Result<` = 0; the one pub item carries a doc comment and `#![deny(missing_docs)]` is on (lib.rs:14). + +### perf +- clean: seeds `format!(` = 0, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 0, `.to_string()` = 0; no allocation sites at all. + +### conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero; no threads, locks, or atomics. + +### async +- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; the only async code is the `#[tokio::test]` registration shim in tests/, which the test lens owns. + +### unsafe +- N/A: seeds `\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 all zero; manifest sets `unsafe_code = "forbid"` and no `unsafe_code = "allow"` exists. + +### ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero; no foreign boundary. + +### macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero; no macro definitions. + +### test +- clean: seeds `#[test]|#[tokio::test]` = 1, `assert_eq!|assert_ne!|assert!` = 6, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; the single registration test is the documented shared `assert_metadata_registration` shim (tests/registration.rs:11-17, recorded pattern, not flagged). + +### Coverage +- idiom: clean (seeds: 0/0/0) +- own: clean (seeds: 0/0/0/0) +- type: N/A (seeds: 0/0/0 all zero; no struct or enum declared) +- api: clean (seeds: 1/0/1) +- err: clean (seeds: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds: 1/0/0) +- perf: clean (seeds: 0/0/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero in src) +- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds: 1/6/0/0) +- supply: clean (X1 owns the lens; per-crate manifest check: d2b-resource-types used in driver.rs, tokio dev-dep used in tests/registration.rs) + +## d2b-provider-seccomp-profile + +### idiom +- tail-4#1 sev=low blast=leaf effort=S verdict=actionable - three impl-block closing braces are indented at 4 spaces instead of column 0 (fmt drift; `cargo fmt --check` would fail) - fix: dedent the closing braces of `impl DeviceNodePath`, `impl DeviceBind`, and `impl SeccompProfileSpec` to column 0 (rustfmt) - [packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:162, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:196] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `for \w+ in 0\.\.` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; finding from read: lines 43/162/196 are ` }` closing impl blocks opened at column 0. +- clean: seeds 0/0/0; the only expression-shape items are the validated newtype and constructor, which already follow the parse-once pattern. + +### own +- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 2, `Rc<|RefCell<|Arc Result<` = 2; the two Result returns are the public parse/new constructors; every other pub item is documented under `#![deny(missing_docs)]`. +- clean: module docs (`//!`) present in all three files; every public item has a doc comment and the crate denies missing_docs (lib.rs:14). + +### perf +- clean: seeds `format!(` = 0, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 1, `.to_string()` = 0; the single `Vec::new()` (seccomp_profile.rs:297) is a test argument where the empty case is the point. + +### conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero. + +### async +- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; the only async code is the `#[tokio::test]` registration shim in tests/. + +### unsafe +- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. + +### macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero; `redacted_debug!` appears only as an invocation of the deliberately exported macro (recorded false positive). + +### test +- clean: seeds `#[test]|#[tokio::test]` = 4, `assert_eq!|assert_ne!|assert!` = 7, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; three unit tests (table-driven path rejection with `{path:?}` messages, fail-closed list bounds, wire round-trip plus unknown-field refusal) plus the documented registration shim; no test that cannot fail. + +### Coverage +- idiom: 1 finding(s) +- own: clean (seeds: 0/2/0/0) +- type: clean (seeds: 0/0/0) +- api: 1 finding(s) +- err: clean (seeds: 10/0/0/1, all unwrap in cfg(test)) +- serde: clean (seeds: 8/16/2/2) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: 1 finding(s) +- perf: clean (seeds: 0/1/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero in src) +- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds: 4/7/0/0) +- supply: clean (X1 owns the lens; per-crate manifest check: d2b-contracts-resource, d2b-resource-types, schemars, serde all used in src; tokio + serde_json dev-deps used in tests) + +## d2b-provider-shell-pool + +### idiom +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the crate is one trait impl plus declarations, all in expression shape. + +### own +- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 0, `Rc<|RefCell<|Arc` return (shell_pool.rs:93) is required by the `DriverDescriptor.decoder` field type, and the re-export list is the explicit house pattern. + +### err +- clean: seeds `.unwrap()|.expect()` = 0, `let _ = |.ok();` = 0, `panic!|unreachable!|todo!|unimplemented!` = 0, `enum \w*Error` = 0; failures are the family's `InteractionEffectError`, propagated with `?`; no panic sites. + +### serde +- N/A: seeds `derive)...Serialize` = 0, `serde)...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 0 all zero; the spec is authored as the Provider's reference document and decoded by the family decoder (`spec_decoder()`), so this crate crosses no wire of its own. + +### obs +- N/A: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 0, `.instrument(|#[instrument` = 0, `tracing::|log::` = 0 all zero and the manifest lists no tracing/log dependency. + +### docs +- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 8, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 3; every pub item carries a doc comment under `#![deny(missing_docs)]` (lib.rs:13); the Result-returning `InteractionType` impls (shell_pool.rs:62, 70, 81) carry prose docs and their contract lives on the family trait in d2b-provider-wayland-policy. + +### perf +- clean: seeds `format!(` = 0, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 1, `.to_string()` = 0; the single `Vec::new()` (shell_pool.rs:82) is the empty desired-children return, the common case. + +### conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero. + +### async +- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; all async code lives in tests/. + +### unsafe +- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. + +### macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero. + +### test +- clean: seeds `#[test]|#[tokio::test]` = 4, `assert_eq!|assert_ne!|assert!` = 12, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; four tests with doc comments - declaration surface, duplicate-registration refusal, dependency reads, and table-driven malformed-reference refusal with `{spec}` failure messages; no test that cannot fail. + +### Coverage +- idiom: clean (seeds: 0/0/0) +- own: clean (seeds: 0/0/0/0) +- type: clean (seeds: 0/0/0) +- api: clean (seeds: 8/1/1) +- err: clean (seeds: 0/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; family decoder owns the spec decode) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds: 8/0/3) +- perf: clean (seeds: 0/1/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero in src) +- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds: 4/12/0/0) +- supply: clean (X1 owns the lens; per-crate manifest check: all five deps used in src; async-trait + serde_json dev-deps used in tests) + +## d2b-provider-shell-session + +### idiom +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the `dependencies()` accumulation (shell_session.rs:76-80) is a conditional push the iterator form would obscure, so the plain form is right. + +### own +- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 1, `Rc<|RefCell<|Arc` return (shell_session.rs:137) is required by the `DriverDescriptor.decoder` field; explicit house re-export list; private consts (`SHELL_SUPERVISOR_PROVIDER_REF`, `SHELL_SUPERVISOR_TEMPLATE`) stay private. + +### err +- clean: seeds `.unwrap()|.expect()` = 0, `let _ = |.ok();` = 0, `panic!|unreachable!|todo!|unimplemented!` = 0, `enum \w*Error` = 0; failures are the family's `InteractionEffectError` propagated with `?`; the `invalid()` closure (shell_session.rs:94) maps impossible construction failures to `InvalidResource` without panicking. + +### serde +- clean: seeds `derive)...Serialize` = 0, `serde)...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 2; the two `serde_json::to_vec` calls (shell_session.rs:119-120) render the supervisor child's spec and metadata at the wire boundary; no derives needed because the spec is `json!`-built. + +### obs +- N/A: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 0, `.instrument(|#[instrument` = 0, `tracing::|log::` = 0 all zero and the manifest lists no tracing/log dependency. + +### docs +- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 8, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 3; every pub item documented under `#![deny(missing_docs)]` (lib.rs:13); the Result-returning `InteractionType` impls carry prose docs, contract on the family trait. + +### perf +- clean: seeds `format!(` = 1, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 0, `.to_string()` = 0; the single `format!` (shell_session.rs:99) builds the supervisor child reference once per reconcile pass - cold, static (unmeasured). + +### conc +- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero. + +### async +- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; all async code lives in tests/. + +### unsafe +- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. + +### macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero. + +### test +- clean: seeds `#[test]|#[tokio::test]` = 5, `assert_eq!|assert_ne!|assert!` = 16, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; five tests with doc comments - declaration surface, duplicate refusal, dependency reads, supervisor-child spec asserted field by field (providerRef/template/processClass/executionRef/userRef/dependencies/ownerRef), and table-driven malformed-ref refusal; no test that cannot fail. + +### Coverage +- idiom: clean (seeds: 0/0/0) +- own: clean (seeds: 0/1/0/0) +- type: clean (seeds: 0/0/0) +- api: clean (seeds: 8/1/1) +- err: clean (seeds: 0/0/0/0) +- serde: clean (seeds: 0/0/0/2) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds: 8/0/3) +- perf: clean (seeds: 1/0/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero in src) +- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds: 5/16/0/0) +- supply: clean (X1 owns the lens; per-crate manifest check: all six deps used in src; async-trait dev-dep used in tests) + +## d2b-provider-telemetry-binding + +### idiom +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 0; the one hand-written `impl Default for TelemetryBindingDriverFactory` (driver.rs:234) is required - `[ResourceTypeName; 1]` has no field-wise `Default` and `ResourceTypeName` does not implement it, so a derive is impossible. + +### own +- clean: seeds `.clone()` = 20, `.to_owned()|.to_vec()|.to_string()` = 4, `Rc<|RefCell<|Arc` return (driver.rs:205) is required by the `DriverDescriptor.decoder` field; the re-export list is explicit (lib.rs:35-41); `TelemetryBindingSpecEnvelope` stays un-exported (pub in a private module), and `TelemetryBindingDriver` is an opaque pub type with a private constructor - deliberate. + +### err +- clean: seeds `.unwrap()|.expect()` = 17, `let _ = |.ok();` = 1, `panic!|unreachable!|todo!|unimplemented!` = 3, `enum \w*Error` = 1; all 17 unwrap/expect and all 3 `panic!` sit in `#[cfg(test)]`; the one `let _ =` (driver.rs:509) is the deliberate validate-the-envelope-decodes pattern that still propagates errors with `?`; `TelemetryBindingDriverErrorKind` splits by caller action with stable wire codes via `as_str()` (driver.rs:130-136) - the taxonomy this lens recommends. + +### serde +- clean: seeds `derive)...Serialize` = 0, `serde)...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 7; the wire boundary is the `ResourceSpec` decode inside `telemetry_binding_spec_decoder` (driver.rs:205-211) and canonical-JSON round-trips of child payloads (199, 374, 388-390); no derives needed because the envelope wraps `CanonicalJsonObject`; every parse failure maps to a typed error kind. + +### obs +- N/A: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 0, `.instrument(|#[instrument` = 0, `tracing::|log::` = 0 all zero and the manifest lists no tracing/log dependency. + +### docs +- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 20, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 17; every pub item carries a doc comment under `#![deny(missing_docs)]` (lib.rs:14), including the contract-flag note on the Degraded projection (driver.rs:473-476); the Result-returning `ResourceDriver` impls (validate/recover/reconcile/delete) carry prose docs and their error contract lives on the trait in d2b-resource-runtime. + +### perf +- clean: seeds `format!(` = 5, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 5, `.to_string()` = 0; all 5 `format!` (driver.rs:764, 796, 1027, 1166, 1173) and 3 of the `Vec::new()` (684-686) are `#[cfg(test)]` fixtures; the production `Vec::new()` sites (270, 404, 909) are the empty-common case; static (unmeasured). + +### conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 4, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; all 4 `Mutex` hits (driver.rs:675-677, 839) are `tokio::sync::Mutex` inside `#[cfg(test)]` fixture doubles - test-only synchronization, no production shared state. + +### async +- clean: seeds `async fn|async move|.await` = 20, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 1 (cfg(test) import), `#[tokio::(main|test)]|Runtime::block_on` = 10 (cfg(test)); the production async surface is the `ResourceDriver` trait impls - no blocking calls, no guards held across `.await`, no spawn/select, and each pass is idempotent so cancellation at any await leaves a re-runnable state; `watch_once` (driver.rs:317-323) is documented best-effort with the requeue schedule as the recovery path. + +### unsafe +- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. + +### ffi +- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. + +### macro +- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero. + +### test +- clean: seeds `#[test]|#[tokio::test]` = 13, `assert_eq!|assert_ne!|assert!` = 40, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; ten unit tests over a recording manager endpoint assert the observable contracts - child ensure order (collector Process before ingest Endpoint), second-pass convergence with no resync, fence on dangling dependency and foreign Provider, endpoint-first/process-last teardown order, one watch registration per target, recover adopt only on a current child set, and delete performing no effect past the manager cascade - plus the three documented registration tests; no test that cannot fail. + +### Coverage +- idiom: clean (seeds: 0/1/0) +- own: clean (seeds: 20/4/0/0, all clones explainable) +- type: 1 finding(s) +- api: clean (seeds: 20/1/1) +- err: clean (seeds: 17/1/3/1, all panic sites in cfg(test)) +- serde: clean (seeds: 0/0/0/7) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) +- docs: clean (seeds: 20/0/17) +- perf: clean (seeds: 5/5/0) +- conc: clean (seeds: 0/4/0/0, test-only) +- async: clean (seeds: 20/0/1/10, production surface sound) +- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds: 13/40/0/0) +- supply: clean (X1 owns the lens; per-crate manifest check: all eight deps used in src; tokio dev-dep used in tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md new file mode 100644 index 000000000..cf7c3dfb2 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md @@ -0,0 +1,337 @@ +# tail-5 - tail lane +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3127 (excl. src/generated/**) | modules: d2b-provider-telemetry-service, d2b-provider-test-controller, d2b-provider-transport-unix, d2b-provider-wayland-session, d2b-provider-zone +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates + +## d2b-provider-telemetry-service + +### idiom +- clean: seeds ran 0/1/0 - the one hand-written impl is `Default for TelemetryServiceDriverFactory` delegating to `new()` (driver.rs:90-94), the idiomatic shape; no index loops, no statement-style accumulation. + +### own +- clean: seeds ran 13/2/0/0 - every clone is explainable: `key.clone()` into the driver's own key (driver.rs:159), `spec.base().clone()` into the owned envelope (driver.rs:151), `endpoint_ref.clone()` into `present_endpoints` (driver.rs:299), plus test-fixture clones; no Rc/RefCell/Arc/Cow. + +### type +- tail-5#1 sev=low blast=leaf effort=S verdict=actionable - `TelemetryServiceStatus` carries stringly-typed state: `phase: &'static str` (three spellings via `PHASE_*` consts) and `projection: serde_json::Value` built by hand with `json!` at three sites, so the `{serviceRole, serviceReadiness}` pair is constructed and indexed by string - fix: add a `TelemetryServicePhase` enum with `as_str()` for the three spellings and a two-field `TelemetryServiceProjection` struct that serializes to the same contract-pinned shape (`SERVICE_STATUS_ALLOWED` spellings at d2b-contracts-provider/src/v3/semantic_services/telemetry.rs:55), replacing the `json!` literals at driver.rs:274-290 and 309-315 - [packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telemetry-service/src/driver.rs:309-315] + evidence: type seeds s1=2 (the trait-required `validate` and a test fn - not findings), s2=0, s3=0; public-surface read of the exported status struct + +### api +- clean: seeds ran 16/1/1 - the single `Arc` in a public signature (driver.rs:147) is the house decoder contract required by `typed_spec_decoder`; `pub use` re-export arms in lib.rs:34-36 are the house single-surface pattern; every exported item is deliberate (driver, factory, descriptor, decoder, status, error). + +### err +- tail-5#2 sev=medium blast=leaf effort=S verdict=actionable - `reconcile_service` replaces the manager's `ResourceError` with the stable `Reconcile` kind via `Err(_) => return Err(...)`, dropping the source, so the actor sees only the wire code and the underlying store failure is invisible - fix: log the source before converting (the crate has no tracing dependency today) or carry it as a `#[source]` field on `TelemetryServiceDriverError` - [packages/d2b-provider-telemetry-service/src/driver.rs:304] + evidence: err seeds s1=13 (all inside `#[cfg(test)] mod tests`, lines 601-879), s2=2 (both `let _ = self.envelope(...)?` - propagated, not swallowed), s3=4 (test panics), s4=1 +- tail-5#3 sev=low blast=leaf effort=S verdict=actionable - `ingest_endpoint_refs` silently drops unparseable declared refs (`ResourceRef::parse(value).ok()` inside `filter_map`), so a typo'd `ingestEndpointRefs` entry is indistinguishable from an absent list and the row requeues on the 5s resync forever with no signal - fix: log a warning naming the dropped value, or fail the reconcile with `InvalidResource` - [packages/d2b-provider-telemetry-service/src/driver.rs:386] + evidence: err s2=2; the `.ok()` swallow is outside the seed's `\.ok\(\);` shape (no trailing semicolon) - read-based + +### serde +- clean: seeds ran 0/0/0/3 - the crate crosses no wire with derives; serde_json use is the preserved envelope decode (`from_slice::`, `to_canonical_bytes` round-trip, driver.rs:141-151), and `validate` is the decode admission gate; the canonical-bytes round-trip in `value()` is preserved old-reconciler behavior (driver.rs:141-144, documented). + +### obs +- N/A: seeds 0/0/0/0 all zero; Cargo.toml carries no tracing/log dependency (the crate reports through its typed error codes only) + +### docs +- clean: seeds ran 16/0/14 - `#![deny(missing_docs)]` (lib.rs:8) and every pub item carries a contract doc; the Result-returning items are `ResourceDriver` trait impls whose failure contract lives in the trait; no canonical-section gaps on inherent pub items. + +### perf +- clean: seeds ran 3/7/0 - all `format!` hits are test-fixture log strings; the `Vec::new()` sites are cold paths or empty-case-common collections (`watched`, empty `present_endpoints`); no hot-loop allocation. + +### conc +- clean: seeds ran 0/4/0/0 - all four `Mutex<` hits are `tokio::sync::Mutex` in the `#[cfg(test)]` recording fakes; no threads, atomics, or manual Send/Sync in the crate. + +### async +- clean: seeds ran 73/0/1/9 - the 73 await hits are the driver verbs (validate/recover/reconcile/delete/watch_once) over the runtime's async `ResourceContext`; no spawn, no spawn_blocking, no blocking call in an async context, no guard held across await; the 9 `#[tokio::test]` sites are tests; the one `tokio::sync::Mutex` is test-only. + +### unsafe +- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) + +### ffi +- N/A: seeds 0/0/0/0 all zero + +### macro +- N/A: seeds 0/0/0/0 all zero + +### test +- clean: seeds ran 13/39/0/0 - 13 tests (9 driver-level over a recording manager endpoint + requeue recorder, 4 registration-boundary) assert behavior and error variants (`matches!` on `ProviderDirectoryError::DuplicateType`/`RequiredBeforeOpen`, `FailureClass::Retryable`), cover all four reconcile branches (degraded/projection/pending/fail-closed), and use deterministic fakes; no `#[ignore]`, no property tooling needed at this size. + +### Coverage +- idiom: clean (seeds ran: 0/1/0) +- own: clean (seeds ran: 13/2/0/0) +- type: 1 finding(s) +- api: clean (seeds ran: 16/1/1) +- err: 2 finding(s) +- serde: clean (seeds ran: 0/0/0/3) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: clean (seeds ran: 16/0/14) +- perf: clean (seeds ran: 3/7/0) +- conc: clean (seeds ran: 0/4/0/0) +- async: clean (seeds ran: 73/0/1/9) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 13/39/0/0) + +## d2b-provider-test-controller + +### idiom +- clean: seeds ran 0/0/0 - bin-only crate with plain sequential code; no index loops, no hand-written impls, no accumulation statements. + +### own +- clean: seeds ran 0/1/0/0 - the single `.to_vec()` (main.rs:194) copies the bootstrap protocol marker into the owned packet payload, the one ownership-transfer boundary; no clones, no shared-state types. + +### type +- clean: seeds ran 0/0/0 - `SessionDisposition` is a proper two-variant enum; no boolean/string state; the `Result<(), ()>` retry signal is deliberate for the fixture loop. + +### api +- N/A: seeds 0/0/0 all zero; the crate is bin-only ([[bin]] Cargo.toml:24-26) with no lib target and no pub items + +### err +- tail-5#4 sev=low blast=leaf effort=S verdict=actionable - `send_bootstrap` and `controller_transport` drop every failure reason with `map_err(|_| ())` (AncillaryCapacity, credit scopes, packet build, send burst, transport build), and the caller logs only the generic retry line, while sibling sites log `reason = %e` - fix: log the reason at each drop site with `warn!(reason = %e, ...)` before converting to `()` - [packages/d2b-provider-test-controller/src/main.rs:186-187, packages/d2b-provider-test-controller/src/main.rs:196-199, packages/d2b-provider-test-controller/src/main.rs:221-230] + evidence: err seeds s1=9 (all inside `#[cfg(test)] mod tests`), s2=0, s3=1 (test-only panic), s4=0 + +### serde +- N/A: seeds 0/0/0/0 all zero (no wire crossing in the bin) + +### obs +- tail-5#5 sev=medium blast=leaf effort=S verdict=actionable - the bin emits `tracing` events with structured `reason = %e` fields but never installs a subscriber (main() at main.rs:33-47; Cargo.toml has `tracing` but no tracing-subscriber), so every debug/warn/error event is dropped and the only operator-visible diagnostics are the unstructured `eprintln!` retry lines at main.rs:68/95/99/111/125 - one failure class reported through two channels, one of which is dead - fix: install a subscriber once at process start (e.g. `tracing_subscriber::fmt::init()`), or convert the tracing sites to eprintln - [packages/d2b-provider-test-controller/src/main.rs:33-47, packages/d2b-provider-test-controller/src/main.rs:68] + evidence: obs seeds s1=5 (eprintln), s2=4, s3=0, s4=1; Cargo.toml dependency read shows no subscriber crate +- tail-5#6 sev=low blast=leaf effort=S verdict=actionable - message-only warn events drop their context: the keepalive error is discarded via `.is_err()` and logged as a bare message, and the unexpected named stream's id is unnamed - fix: bind the error (`warn!(reason = %e, ...)`) and name the stream (`warn!(stream = ?stream, ...)`) - [packages/d2b-provider-test-controller/src/main.rs:164, packages/d2b-provider-test-controller/src/main.rs:173-174] + evidence: obs s2=4 (message-only `warn!`/`error!`/`debug!` sites; the other two are startup messages without a field to attach) + +### docs +- N/A: seeds 0/0/4 - seed 1 (pub items) is zero; bin-only crate, and the skill never adds missing_docs to a binary + +### perf +- clean: seeds ran 0/0/0 - no format!, no grow-by-push collections, no copies; the retry sleeps are the only pacing. + +### conc +- N/A: seeds 0/0/0/0 all zero (no threads, locks, atomics, or thread_local in the crate) + +### async +- clean: seeds ran 14/0/0/0 - the 14 await hits are the session loop, bootstrap send, and retry sleeps, all on the current-thread runtime built at process entry (`block_on` at main.rs:45 is the sanctioned entry-point pattern); no spawn, no blocking call in an async context, no guard across await. + +### unsafe +- N/A: seeds 0/0/0 all zero; `#![forbid(unsafe_code)]` (main.rs:3) and manifest forbid + +### ffi +- N/A: seeds 0/0/0/0 all zero + +### macro +- N/A: seeds 0/0/0/0 all zero + +### test +- clean: seeds ran 3/8/0/0 - three meaningful tests: a `should_reconnect` disposition table, a behavioral handshake-terminality test over a real socketpair with `select!`/`timeout` proving one-shot bootstrap delivery, and a fail-closed spawn of the bin without fd10; error variants asserted, deterministic, no `#[ignore]`. + +### Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 0/1/0/0) +- type: clean (seeds ran: 0/0/0) +- api: N/A (seeds: 0/0/0 all zero; bin-only crate, no lib target) +- err: 1 finding(s) +- serde: N/A (seeds: 0/0/0/0 all zero) +- obs: 2 finding(s) +- docs: N/A (seeds: 0/0/4; seed 1 zero - no pub items in a bin-only crate) +- perf: clean (seeds ran: 0/0/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: clean (seeds ran: 14/0/0/0) +- unsafe: N/A (seeds: 0/0/0 all zero; forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 3/8/0/0) + +## d2b-provider-transport-unix + +### idiom +- clean: seeds ran 1/1/0 - the single index loop is the bounded 8-attempt handle-collision retry with early return (portal.rs:345), where a plain `for` is right; the hand-written `Default for TransportPortal` delegates to `new()` (portal.rs:147-150), the idiomatic shape. + +### own +- clean: seeds ran 0/0/0/0 - no clones, no to_owned, no shared-state types; ownership is moved end to end (`OwnedFd` transfers, `into_parts`, `into_transport_fd`). + +### type +- clean: seeds ran 2/0/0 - the two `validate_*` fns are the boundary admission checks (`validate_route_class`, `validate_and_prepare`), exactly where parse-once validation belongs; `attachments_enabled: bool` is a single flag whose illegal combination is rejected at the same boundary, below the skill's stopping rule. + +### api +- clean: seeds ran 47/0/3 - deliberate closed surface: opaque redacted `TransportHandle`, private-field `OpenedTransport`/`TransportDescriptor` with accessors, `pub use` named re-export arms (lib.rs:17-23), no Arc/Rc/Box/RefCell in signatures; the zero in-tree callers are the documented declared-provider class (provider-crate-policy ratchet, refusal ledger), not a surface defect. + +### err +- clean: seeds ran 1/0/0/2 - the single `expect("finalized order is populated")` (portal.rs:141) sits behind a `len() > MAX_OPEN_TRANSPORTS` check the compiler cannot see and names the invariant; both error enums are closed stable-code surfaces with `From` mapping between them; no swallowed errors. + +### serde +- N/A: seeds 0/0/0/0 all zero (the crate crosses no wire; descriptors are kernel-observed, not serialized) + +### obs +- tail-5#7 sev=low blast=leaf effort=S verdict=actionable - four message-only `tracing::warn!` events drop the underlying errno (`map_err(|_|)` then warn with only the `provider` field): peer-credential bind failure, monitor-fd duplication, observation poll, and entropy-source failures - fix: capture the errno as `reason = %e` like the admission-rejection site at portal.rs:209-212 already does - [packages/d2b-provider-transport-unix/src/portal.rs:217-220, packages/d2b-provider-transport-unix/src/portal.rs:244-247, packages/d2b-provider-transport-unix/src/portal.rs:301-304, packages/d2b-provider-transport-unix/src/portal.rs:348-351] + evidence: obs seeds s1=0, s2=0 (the `tracing::warn!(` form does not match the interpolated-message seed), s3=0, s4=9; read-based + +### docs +- tail-5#8 sev=low blast=leaf effort=S verdict=actionable - the three inherent pub methods returning `Result` (`open`, `close`, `observe`) lack `# Errors` sections naming which conditions produce which `PortalError` variant, though the failure conditions are recoverable from the enum docs - fix: add `# Errors` sections to the three doc comments - [packages/d2b-provider-transport-unix/src/portal.rs:197-201, packages/d2b-provider-transport-unix/src/portal.rs:266, packages/d2b-provider-transport-unix/src/portal.rs:286] + evidence: docs seeds s1=41, s2=0, s3=7; `#![deny(missing_docs)]` (lib.rs:3) is satisfied but the canonical-section rule is not + +### perf +- clean: seeds ran 0/4/0 - the `Vec::new`/`HashMap::new`/`HashSet::new`/`VecDeque::new` hits are the empty portal's initial state (portal.rs:60-66) and a test fixture; no format! in the crate; handle generation is bounded at 8 attempts. + +### conc +- tail-5#9 sev=low blast=leaf effort=S verdict=actionable - `tokio::sync::Mutex` (portal.rs:18, 155) in a crate with zero async code - every use is `try_lock()` on a synchronous path, so the tokio `sync` feature dependency exists solely for this one lock - fix: use `std::sync::Mutex` (the crate's own `try_lock`-only pattern never awaits) - [packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-unix/src/portal.rs:155] + evidence: conc seeds s1=0, s2=1, s3=0, s4=0; async seeds s1=0, s2=0, s3=1 (this same Mutex import), s4=0 + +### async +- clean: seeds ran 0/0/1/0 - the crate has no async fn, no await, no spawn; the single `tokio::sync::Mutex` hit is judged under conc (tail-5#9); nothing here blocks an executor because there is no executor. + +### unsafe +- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) + +### ffi +- N/A: seeds 0/0/0/0 all zero (rustix syscall wrappers are not a foreign-caller boundary) + +### macro +- N/A: seeds 0/0/0/0 all zero + +### test +- clean: seeds ran 7/19/0/0 - six integration tests over real socketpairs assert error variants (`PortalError::PeerCredentials`/`SocketKindMismatch`/`AttachmentPolicyConflict`/`HandleTableFull`/`UnknownHandle`), kernel-bound peer credentials, fd-substitution refusal, idempotent close, foreign-handle refusal, disconnect observation, and full-table recovery; one unit test covers handle-reissue; deterministic, no `#[ignore]`. + +### Coverage +- idiom: clean (seeds ran: 1/1/0) +- own: clean (seeds ran: 0/0/0/0) +- type: clean (seeds ran: 2/0/0) +- api: clean (seeds ran: 47/0/3) +- err: clean (seeds ran: 1/0/0/2) +- serde: N/A (seeds: 0/0/0/0 all zero) +- obs: 1 finding(s) +- docs: 1 finding(s) +- perf: clean (seeds ran: 0/4/0) +- conc: 1 finding(s) +- async: clean (seeds ran: 0/0/1/0) +- unsafe: N/A (seeds: 0/0/0 all zero; forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 7/19/0/0) + +## d2b-provider-wayland-session + +### idiom +- clean: seeds ran 0/1/0 - the hand-written `Default for WaylandSession` (wayland_session.rs:96-98) builds the `Arc` the derive cannot, delegating through `new()`; `desired_children` already uses the iterator pipeline (`intents.iter().map(owned_child_ensure).collect()`). + +### own +- clean: seeds ran 4/0/0/0 - the four clones (wayland_session.rs:116-119) copy the spec's domain refs into the owned dependencies Vec, the required ownership transfer; `Arc` is genuine shared ownership (see api). + +### type +- clean: seeds ran 0/0/0 - `InteractionKind`/`InteractionType` typestate comes from the shared wayland-policy engine; no boolean/string state in this crate; `DisplayChildSource` is a one-required-method trait. + +### api +- clean: seeds ran 12/2/1 - the two `Arc` signature hits (wayland_session.rs:84, 97) are genuine shared ownership: `WaylandSession` derives `Clone` and clones share the source, with `Default` supplying `SessionChildSource`; `pub use` named re-export arms (lib.rs:11-20) are the house single-surface pattern; `WaylandSessionDriver`/`WaylandSessionFactory` aliases follow the family convention. + +### err +- tail-5#10 sev=low blast=leaf effort=S verdict=actionable - `SessionChildSource::display_children` maps any `WorkerEffectError` from the display crate's child derivation to `InteractionEffectError::InvalidResource`, dropping the cause, and the crate has no tracing, so the derivation failure detail is invisible at the boundary - fix: log the source before mapping (add a tracing dependency) or preserve the specific variant - [packages/d2b-provider-wayland-session/src/wayland_session.rs:73] + evidence: err seeds s1=0, s2=0, s3=0, s4=0; read-based (the `map_err(|_| ...)` at wayland_session.rs:73 drops `WorkerEffectError` from `display_owned_child_intents`, session_children.rs:42-46) + +### serde +- N/A: seeds 0/0/0/0 all zero (spec decoding is delegated to the family's `spec_decoder` in wayland-policy; this crate defines no wire types) + +### obs +- N/A: seeds 0/0/0/0 all zero; Cargo.toml carries no tracing/log dependency (failures travel as typed error codes only) + +### docs +- clean: seeds ran 12/0/4 - `#![deny(missing_docs)]` (lib.rs:7) and every pub item carries a contract doc; the Result-returning items are `InteractionType` trait impls whose failure contract lives in the trait. + +### perf +- clean: seeds ran 0/0/0 - no format!, no grow-by-push collections, no copies; the crate is a thin declaration layer over the shared engine. + +### conc +- N/A: seeds 0/0/0/0 all zero + +### async +- N/A: seeds 0/0/0/0 all zero (no async code in this crate; the engine's async verbs live in wayland-policy) + +### unsafe +- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) + +### ffi +- N/A: seeds 0/0/0/0 all zero + +### macro +- N/A: seeds 0/0/0/0 all zero + +### test +- clean: seeds ran 6/20/0/0 - six integration tests assert the declaration surface, registry duplicate refusal (`matches!` on `ProviderDirectoryError::DuplicateType`), the four-dependency read order, foreign-row refusal (error variant), the two child rows' materialized spec/metadata content, and a refusing child source; deterministic, no `#[ignore]`. + +### Coverage +- idiom: clean (seeds ran: 0/1/0) +- own: clean (seeds ran: 4/0/0/0) +- type: clean (seeds ran: 0/0/0) +- api: clean (seeds ran: 12/2/1) +- err: 1 finding(s) +- serde: N/A (seeds: 0/0/0/0 all zero) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: clean (seeds ran: 12/0/4) +- perf: clean (seeds ran: 0/0/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0 all zero; forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 6/20/0/0) + +## d2b-provider-zone + +### idiom +- clean: seeds ran 0/0/0 - no index loops, no hand-written impls (all derives), no accumulation statements; the emitter's `match`/`Option::replace` flow is expression-shaped. + +### own +- clean: seeds ran 2/0/0/0 - the two `last_reconciled_at.clone()` hits (zone_status.rs:19, 131) are the first-borrow-then-move pattern in `emit_handler_status`/`emit`, the required copy for the two handler records; no shared-state types. + +### type +- clean: seeds ran 0/0/0 - `ZoneStatusInput` is a builder with private fields, `ZoneRuntimeMetadata` is a flat counter struct, `generation_cleanup_pending: bool` is a single flag below the stopping rule; `ZoneStatusProjectionError` is a one-variant enum carrying the stable wire code, not a flag. + +### api +- tail-5#11 sev=medium blast=leaf effort=M verdict=actionable - `pub mod zone_status;` plus `pub use zone_status::*;` (lib.rs:9-10) exposes every zone_status item at two paths (crate root and module path), violating the house single-surface pattern (named re-export arms with a private module, cf. telemetry-service lib.rs:34-36 and wayland-session lib.rs:11-20) - fix: make the module private and re-export the four items by name (`SystemCoreStatusEmitter`, `ZoneRuntimeMetadata`, `ZoneStatusInput`, `ZoneStatusProjectionError`), updating the module-path call sites - [packages/d2b-provider-zone/src/lib.rs:9-10, packages/d2b-provider-zone/src/zone_status.rs:43] + evidence: api seeds s1=11, s2=0, s3=2; census: `d2b_provider_zone::zone_status` over packages/ = 3 hits (d2bd/src/resource_runtime.rs:63-65, tests/zone_status.rs:3-4) + +### err +- clean: seeds ran 0/0/0/1 - the single error enum is a closed stable-code surface (`zone-status-projection-invalid`); no unwrap/expect/panic outside tests; the `map_err(|_| Contract)` at zone_status.rs:139 converts a caller-constructed input violation, where the stable code is the contract. + +### serde +- N/A: seeds 0/0/0/0 all zero (no wire types defined in this crate; status projection consumes contract types) + +### obs +- N/A: seeds 0/0/0/0 all zero; Cargo.toml carries no tracing/log dependency + +### docs +- tail-5#12 sev=low blast=leaf effort=S verdict=actionable - the inherent pub `SystemCoreStatusEmitter::emit` returns `Result` (zone_status.rs:113-114) without an `# Errors` section naming the contract-rejection condition - fix: add an `# Errors` section stating that duplicate system-core handler records or a rejected `ZoneStatusResource` yield `ZoneStatusProjectionError::Contract` - [packages/d2b-provider-zone/src/zone_status.rs:110-114] + evidence: docs seeds s1=10, s2=0, s3=1; `#![deny(missing_docs)]` (lib.rs:7) is satisfied but the canonical-section rule is not + +### perf +- clean: seeds ran 0/0/0 - no format!, no grow-by-push collections, no copies; `Vec::with_capacity(input_handlers.len() + 2)` (zone_status.rs:120) sizes the only allocation. + +### conc +- N/A: seeds 0/0/0/0 all zero + +### async +- N/A: seeds 0/0/0/0 all zero (the emitter is a synchronous projection; async verbs live in the runtime) + +### unsafe +- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) + +### ffi +- N/A: seeds 0/0/0/0 all zero + +### macro +- N/A: seeds 0/0/0/0 all zero + +### test +- clean: seeds ran 5/12/0/0 - four emitter tests (exact mandatory system-core pair, malformed input cannot publish Ready, duplicate handler records rejected, metadata/timestamp projection) plus the policy-required registration shim calling the shared `assert_metadata_registration`; behavior and error assertions, deterministic, no `#[ignore]`. + +### Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (seeds ran: 2/0/0/0) +- type: clean (seeds ran: 0/0/0) +- api: 1 finding(s) +- err: clean (seeds ran: 0/0/0/1) +- serde: N/A (seeds: 0/0/0/0 all zero) +- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) +- docs: 1 finding(s) +- perf: clean (seeds ran: 0/0/0) +- conc: N/A (seeds: 0/0/0/0 all zero) +- async: N/A (seeds: 0/0/0/0 all zero) +- unsafe: N/A (seeds: 0/0/0 all zero; forbid) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (seeds ran: 5/12/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md new file mode 100644 index 000000000..f780d07b4 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md @@ -0,0 +1,143 @@ +# tail-6 - tail lane +Baseline: 6ebdd4cec | LOC audited: 2173 (excl. src/generated/**) | modules: d2b-resource-types, d2b-sk-frontend +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates + +## d2b-resource-types + +### idiom +- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0. No index loops, no statement-style accumulation; the only hand-written impls are `Debug` (redaction, deliberate) and trait impls, which the seed shape does not match. The `while` loop in the `ALL_TYPES` const block (resource_type.rs:36-44) is const-context-required and documented. + +### own +- clean: seeds `\.clone\(\)` = 1, `\.to_owned\(\)` = 1, `Rc<|RefCell<|Arc Vec` trait signature. `Arc` handles in `DriverDescriptor`/`KernelCaller` are shared registry/seam ownership, not clones. + +### type +- clean: seeds `fn validate_\w+|fn check_\w+` = 0, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0. State is already modelled as enums/bitflags (`AllowedSources`, `ChildCustody`, `Cardinality`, `IsolationPosture`); no boolean flag soup or stringly-typed state. + +### api +- tail-6#3 sev=medium blast=family effort=M verdict=actionable - `assert_metadata_registration` is a test-only assertion helper exported unconditionally through the crate root, while the crate already declares a `test-support` feature that no consumer enables - fix: gate the fn and its `pub use` arm behind `#[cfg(feature = "test-support")]` (or `any(test, feature = "test-support")` per the house pattern in d2b-provider-activation-nixos/Cargo.toml:16-23) and enable the feature from the 11 consumer crates' test targets - [packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72, packages/d2b-resource-types/Cargo.toml:9] + evidence: census: `assert_metadata_registration` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 13 hits; all 11 external callers are `tests/registration.rs` in d2b-provider-{command,emergency-policy,operation,quota,resource-export,resource-import,role,role-binding,seccomp-profile,zone,zone-link}; `d2b-resource-types = {` in 38 manifests, 0 with `features = ["test-support"]` +- clean: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 97 hits, seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits (descriptor.rs:76,78; operation.rs:105,108), seed `^\s*pub use ` = 11 arms. The `Arc` fields are genuine shared registry ownership (cloned by the `DriverRegistration` impl, descriptor.rs:110-113); `pub use` arms are the house single-surface pattern; remaining surface is the deliberate declaration vocabulary. + +### err +- clean: seeds `\.unwrap\(\)|\.expect\(` = 5, `let _ = |\.ok\(\);` = 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 0. All 5 `expect` sites sit inside `assert_metadata_registration` (metadata.rs:100-121), a test-support assertion helper; no panic sites in library paths. `OperationFailure` carries a closed `&'static str` code mirroring the repo's wire error-code convention. + +### serde +- N/A (seeds: 0/0/0/0 all zero; no serde derives, no hand-written deserializers, no JSON calls - the crate crosses no wire boundary) + +### obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0. Declaration crate emits no telemetry. + +### docs +- tail-6#5 sev=low blast=leaf effort=S verdict=actionable - doc comment typos in `OperationCtx::fds` ("invocation,when any", "frame,not to the handler; the handler") - fix: restore the missing spaces after the commas in the field docs - [packages/d2b-resource-types/src/operation.rs:64, packages/d2b-resource-types/src/operation.rs:65] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 97 hits, read all; seed `/// # (Examples|Errors|Panics|Safety)` = 0; seed `-> Result<` = 1. `#![deny(missing_docs)]` (lib.rs:6) is active; every public item is documented; the two typo lines are the only defects found. +- clean: seeds run as above; all 97 public items documented with first-sentence-shaped docs under `#![deny(missing_docs)]` (lib.rs:6); no canonical-section or magic-value gaps found beyond the typo finding. + +### perf +- clean: seeds `format!\(` = 0, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 1, `\.to_string\(\)` = 0. The single `Vec::new()` (operation.rs:179) is a cold result-construction path; no hot-path allocation. static (unmeasured). + +### conc +- N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or orderings in the crate) + +### async +- clean: seeds `async fn|async move|\.await` = 3, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0. The three hits are the `#[async_trait] OperationHandler::execute` (operation.rs:49) and the async test-support helper (metadata.rs:72,113); no runtime, spawn, or blocking work. + +### unsafe +- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks/fns/impls, no SAFETY comments, no transmute/raw-pointer use, no `unsafe_code` allow manifest) + +### ffi +- N/A (seeds: 0/0/0/0 all zero; no extern declarations, no repr(C), no CStr/CString) + +### macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro machinery) + +### test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 7, `assert_eq!\(|assert_ne!\(|assert!\(` = 39 (incl. 17 asserts in the shared test-support helper), `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0. Seven unit tests in three modules (allowed_sources.rs, child_creation.rs, resource_type.rs) assert behavior with messages; the shared `assert_metadata_registration` helper centralizes the per-type registration coverage for 11 consumer crates. + +### Coverage +- idiom: clean (seeds ran: 0/0/0) +- own: clean (1/1/0/0) +- type: clean (0/0/0) +- api: 1 finding +- err: clean (5/0/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no wire boundary) +- obs: clean (0/0/0/0) +- docs: 1 finding +- perf: clean (0/1/0) +- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) +- async: clean (3/0/0/0) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe constructs) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: clean (7/39/0/0) + +## d2b-sk-frontend + +### idiom +- tail-6#1 sev=low blast=leaf effort=S verdict=actionable - `zone_path` accumulates labels with a `let mut Vec` + push loop where an iterator pipeline collects - fix: replace the loop with `value.split('/').map(|label| ZoneLabelId::parse(label).map_err(|_| format!("{name} is not a valid Zone label path"))).collect::, String>>()?` before `ZonePath::new(labels)` - [packages/d2b-sk-frontend/src/config.rs:178] + evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (config.rs:178); seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0 +- clean: seeds run as above; the one hit is the finding; hand-written `Debug` impls (agent.rs:145-148, uhid.rs:77-105) are deliberate redaction. + +### own +- tail-6#2 sev=low blast=leaf effort=S verdict=actionable - `main` clones the whole `PlacementConfig` (owned `ZoneEnrollmentIdentity` inside) only to keep `config` alive for its other fields, and `config.rs` builds `"/dev/uhid".to_owned()` where `PathBuf::from` suffices - fix: destructure `let Config { vm_id, link, uhid_path, placement } = config;` and call `placement.into_placement()` (drop the clone); write `PathBuf::from("/dev/uhid")` via `optional("D2B_SK_UHID_PATH").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/dev/uhid"))` - [packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83] + evidence: seed `\.clone\(\)|\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 6 hits; 2 avoidable (main.rs:55, config.rs:83); the rest are required conversions (agent.rs:178 `to_vec` for `GuestFrame::new`, config.rs:88/91/108 owned error strings) +- clean: seeds run as above; no `Rc<|RefCell<|Arc>` device lifecycle is a deliberate once-init shape. + +### api +- tail-6#4 sev=low blast=leaf effort=S verdict=actionable - `pub mod agent/config/link/uhid` plus root `pub use` re-exports make every item reachable at two paths, deviating from the house single-surface pattern; only the binary needs a module path - fix: make the four modules private (`mod agent; ...`) and re-export `UhidDevice` (and `UhidEvent`) from lib.rs, updating main.rs:41 to `use d2b_sk_frontend::{Config, SecurityKeyFrontend, UhidDevice, VsockAllocatorLink}` - [packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-sk-frontend/src/lib.rs:27, packages/d2b-sk-frontend/src/main.rs:41] + evidence: seed `^\s*pub use ` = 3 arms (lib.rs:27-29) alongside `pub mod` x4 (lib.rs:22-25); census: `d2b_sk_frontend::(agent|config|link|uhid)::` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 0 full-path hits, and the zone-routing test consumer uses the root re-exports (tests/guest_enrollment.rs:210,422), so only main.rs:41's group-import form needs the module path +- clean: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 25 hits, seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 0. No internals leak into signatures beyond the double-path shape above. + +### err +- clean: seeds `\.unwrap\(\)|\.expect\(` = 1, `let _ = |\.ok\(\);` = 1, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 0. The expect is in a `#[cfg(test)]` test (config.rs:213); the `let _ = event_type;` (uhid.rs:203) silences an unused binding, not a `Result`. `Config::from_env` returns `String` errors consumed once by the binary's `exit_on_error` print - acceptable binary-boundary shape. + +### serde +- N/A (seeds: 0/0/0/0 all zero; no serde derives or JSON crossing - the crate's wire surface is the toolkit's session framing, not serde) + +### obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 2, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0. Both `eprintln!` sites are the binary's own startup banner and fatal-error output (main.rs:47,57) - product output, not telemetry; the library half emits nothing. + +### docs +- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 29 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 5. `#![deny(missing_docs)]` (lib.rs:6) is active; all 29 public items and the `Result`-returning fns (from_env, into_placement, create, read_event, send_input_report) carry first-sentence-shaped prose docs; the UHID constants document their kernel-header provenance. + +### perf +- clean: seeds `format!\(` = 16, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 2, `\.to_string\(\)` = 0. All `format!` sites are error paths (config.rs), one-shot device creation (uhid.rs:275), or tests (uhid.rs:481); the event builders pre-size with `with_capacity` and read into a stack buffer. static (unmeasured). + +### conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 2, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0. The two `Mutex<` hits are `tokio::sync::Mutex` (agent.rs:105,133) - async-aware primitives judged under the async lens; no threads, atomics, or manual Send/Sync claims. + +### async +- clean: seeds `async fn|async move|\.await` = 39, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 1, `#\[tokio::(main|test)\]|Runtime::block_on` = 0. The device I/O uses the sanctioned `AsyncFd` + `try_io` readiness loops over `rustix::io` (uhid.rs:233-259, the clippy.toml replacement vocabulary), `tokio::fs` open with `into_std().await` (uhid.rs:156-163), and `tokio::sync::Mutex`/`OnceCell` guards held across awaits (agent.rs:133-141,166-177) - all async-aware; no std guards across `.await`, no executor blocking, no runtime started in the library. + +### unsafe +- N/A (seeds: 0/0/0/1; the only hits are `#![forbid(unsafe_code)]` (lib.rs:20) and two `io::Error::from_raw_os_error` std-safe calls (uhid.rs:238,251) matching seed 3's `from_raw` substring - no unsafe blocks/fns/impls exist, and the manifest is `deny`, not `allow`) + +### ffi +- N/A (seeds: 0/0/0/0 all zero; no extern declarations, no repr(C), no CStr/CString - `libc::O_NONBLOCK` and `rustix::io` are syscall bindings, not an FFI surface) + +### macro +- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro machinery) + +### test +- tail-6#6 sev=medium blast=leaf effort=S verdict=actionable - the parse side of the byte-exact UHID protocol (`read_event`'s event-type dispatch, the OUTPUT size field at payload[4096], GET_REPORT id, lifecycle mapping, short-header error) has no test while the builders have 12 byte-exact tests, so a regression in the parse offsets passes the suite - fix: extract `parse_event(buf: &[u8]) -> io::Result>` from `read_event` and table-test the dispatch against hand-built buffers (plus a `build_get_report_reply_error` layout test) - [packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186] + evidence: seed `#\[test\]|#\[tokio::test\]` = 14 hits (12 in uhid.rs, 2 in config.rs); seed `assert_eq!\(|assert_ne!\(|assert!\(` = 24; none of the uhid.rs tests exercise `read_event` or `build_get_report_reply_error` (uhid.rs:283-299) +- clean: seeds run as above; the 14 tests are behavior-focused with messages, deterministic, and byte-exact for the builders; no `#[ignore]` (0), no property/snapshot tooling (0). + +### Coverage +- idiom: 1 finding +- own: 1 finding +- type: clean (0/0/0) +- api: 1 finding +- err: clean (1/1/0/0) +- serde: N/A (seeds: 0/0/0/0 all zero; no serde wire crossing) +- obs: clean (2/0/0/0) +- docs: clean (29/0/5) +- perf: clean (16/2/0) +- conc: clean (0/2/0/0) +- async: clean (39/0/1/0) +- unsafe: N/A (seeds: 0/0/0/1; no real unsafe constructs, forbid is seed 4 only) +- ffi: N/A (seeds: 0/0/0/0 all zero) +- macro: N/A (seeds: 0/0/0/0 all zero) +- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md new file mode 100644 index 000000000..f85679079 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md @@ -0,0 +1,91 @@ +# xtask-p1 - xtask - part 1/5 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8903 (excl. src/generated/**; policy range 5354-11075 of provider_crate_policy.rs) | modules: provider_crate_policy.rs (5354-11075), main.rs, gen_layer_catalogs.rs, provider_registration_authority.rs, service_catalog.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: provider_crate_policy.rs:5354-11075 (item-range split; sed line + 5353 = absolute) + +## idiom +- xtask-p1#1 sev=medium blast=leaf effort=S verdict=actionable - gen_layer_catalogs.rs has two byte-identical helpers under different names: `string_slice` and `string_array` share the same signature and body (both emit a `pub const : &[&str]` array), so callers guess which to use and a future shape change drifts only one copy - fix: delete `string_array` and route its 10 call sites (lines 299, 362, 367, 456, 466, 471, 496, 507, 512, 517) through `string_slice`, keeping `string_pair_slice` for the tuple case - [packages/xtask/src/gen_layer_catalogs.rs:147, packages/xtask/src/gen_layer_catalogs.rs:158] + evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0; static comparison of the two function bodies; census: `string_(slice|array)\(` over packages/xtask/src = 14 hits +- xtask-p1#2 sev=low blast=leaf effort=M verdict=actionable - emitted Rust source is embedded as single-line escaped string literals with backslash line continuations (`"... \n \` chains, e.g. the `typed_noun_type` block), making the generator bodies unreadable and brittle to edit; a reviewer cannot diff the embedded code - fix: embed the emitted blocks as raw string literals (the content contains `"` but not `"##`, so `r##"..."##` delimiters work) in `surface_catalog_source` and in `redact_generated_protobuf_formatting`'s `raw_display`/`redacted_formatting` templates - [packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473] + evidence: seed `format!\(` = 115 in lane; static (unmeasured) - the escaped-string sites read at gen_layer_catalogs.rs:297-453 and main.rs:473-528 +- xtask-p1#3 sev=medium blast=leaf effort=M verdict=actionable - the daemon-api IPC collector (`parse_rust_items` + `IpcItemCollector`) parses files with `syn`, then slices the original source text back out and re-parses fields and variants with ~150 lines of hand-rolled scanners (`parse_fields`, `parse_variants`, `split_top_level_entries`, `extract_body`, `strip_non_code_lines`, `normalize_ws`, `line_col_to_offset`), duplicating what the `syn` AST already provides and re-implementing angle-bracket depth counting for generics - fix: in `visit_item_struct`/`visit_item_enum`, extract `Field { name, ty }` and variants from `syn::Fields`/`syn::Variant` directly (type text via `quote::ToTokens`), then delete the text parsers and `line_col_to_offset`'s per-span O(n) scan - [packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.rs:1203] + evidence: seed `for \w+ in 0\.\.` = 1 (main.rs:530, a bounded retry loop, not an index loop); the parse chain read at main.rs:1112-1245 +- xtask-p1#4 sev=low blast=leaf effort=S verdict=actionable - `sanitize_generated_rust` contains a corrupted replacement literal `"#![allow(clipto_camel_casepy)]\n"` that can never match any generator output, so the sanitizer silently keeps whatever attribute the line was meant to strip in the committed generated file - fix: replace the literal with the actual protobuf/ttrpc-emitted marker it targets (or delete the line if the marker is no longer emitted) at main.rs:459 - [packages/xtask/src/main.rs:459] + evidence: seed `generated\.replace` (static); `clipto_camel_casepy` occurs once in the workspace (packages/xtask/src/main.rs:459); the surrounding replace chain read at main.rs:454-472 +- xtask-p1#5 sev=low blast=leaf effort=S verdict=actionable - in `collect_self_binding_scope` the row-close reset block at provider_crate_policy.rs:6662 is dead: a line whose trim equals `}` cannot also contain `SeedSelfBinding`, so the inner reset never fires, its comment describes behavior that never runs, and the inner scan has no exit at the row close (it runs to EOF for every `SeedProvider {`) - fix: drop the dead inner condition, reset `pending_subject`/`pending_role` when `code_text(lines[stop]).trim() == "}"`, and `break` the `while stop < lines.len()` loop there - [packages/xtask/src/provider_crate_policy.rs:6662, packages/xtask/src/provider_crate_policy.rs:6612] + evidence: seed `fn validate_\w+|fn check_\w+` = 17 (the `check_*` family this scanner belongs to); static reading of the block at provider_crate_policy.rs:6608-6672 + +## own +- xtask-p1#6 sev=low blast=leaf effort=S verdict=actionable - `apply_citation_fixes` clones `lines[index]` before mutating it (`let mut line = lines[index].clone();`) although the slot is borrowed `&mut` and then reassigned on the same iteration - fix: `let mut line = std::mem::take(&mut lines[index]);` per the skill's `mem::take` pattern - [packages/xtask/src/provider_crate_policy.rs:7257] + evidence: seed `\.clone\(\)` = 21 in lane (non-test policy range: 16); the site is the mutate-then-reassign shape at provider_crate_policy.rs:7255-7262 +- xtask-p1#7 sev=low blast=leaf effort=S verdict=actionable - two ratchet lookups build an owned tuple just to call `BTreeSet::contains`, allocating a cloned String per signal during tree-wide scans (`family_exempt.contains(&(signal.module.clone(), token))` and `exempt.contains(&(signal.crate_name.clone(), signal.module.clone(), signal.token))`) - fix: replace `contains` with `family_exempt.iter().any(|(module, token)| *module == signal.module && *token == token)` (and the 3-tuple equivalent), or key both sets on `&str` like the neighboring `structural_exempt` set - [packages/xtask/src/provider_crate_policy.rs:6375, packages/xtask/src/provider_crate_policy.rs:8750] + evidence: seed `\.clone\(\)` = 21 in lane; both sites read in context (provider_crate_policy.rs:6369-6378 and 8746-8753); no Rc/RefCell/Arc/Cow hits (0/0) +The remaining 17 clones and the sampled `to_owned`/`to_string` hits (every 8th of 128) all move borrowed scanner values into owned outputs or clone to descend clap subcommands (main.rs:902) - each explainable. + +## type +- xtask-p1#8 sev=low blast=leaf effort=S verdict=actionable - `process_provider_ids(metric_label: Option)` uses an optional boolean to select among three label domains (all, metric-only, plus an unreachable `Some(false)` state) where the two production call sites only ever pass `None` or `Some(true)` - fix: split into `all_process_provider_ids()` and `metric_process_provider_ids()` (or a two-variant enum), and update the call sites at gen_layer_catalogs.rs:370, 474, 515 - [packages/xtask/src/gen_layer_catalogs.rs:288, packages/xtask/src/gen_layer_catalogs.rs:515] + evidence: seed `(mode|kind|state): String` = 0; seed bool-flag = 0; the Option parameter shape read at gen_layer_catalogs.rs:288-295 and its call sites + +## api +- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 42 (9 real items, the rest template strings and doc mentions), `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 0. The part's surface is `pub fn check`/`pub fn regenerate` in service_catalog.rs:46,78 and provider_registration_authority.rs:65,84, `pub fn run_cli` in gen_layer_catalogs.rs:584, `pub fn fix` in provider_crate_policy.rs:7181, plus `pub(crate) const GENERATED_ARTIFACT` in two modules - every item is doc-commented, nothing leaks Arc/Rc or dependency types, and the crate is a binary (bin-only crates get no missing_docs). + +## err +- clean: seeds ran: `\.unwrap\(\)|\.expect\(` = 159 (main 4, gen_layer_catalogs 6, provider_registration_authority 24, policy range 125 - all 125 policy hits and the other 34 sit inside `#[cfg(test)]` modules), `let _ = |\.ok\(\);` = 14 (test helpers plus the deliberate best-effort `let _ = fs::remove_dir_all` at main.rs:409), `panic!\(|unreachable!\(|todo!\(|unimplemented!\(` = 3 (main.rs:901 startup invariant, main.rs:1597 cfg(test) helper, one in policy tests), `enum \w*Error` = 0. No production-code unwrap/expect or swallowed Result in the lane; error reporting is `Result<_, String>` with canonical JSON diagnostics, which suites this CLI-policy context. + +## serde +- xtask-p1#9 sev=medium blast=leaf effort=S verdict=actionable - `service_catalog.rs`'s `DeclarationFile` parses the committed per-crate `service-catalog.json` with `#[derive(Deserialize)]` and no `deny_unknown_fields`, while the sibling `RegistrationDeclaration` parsing `registrations.json` denies unknowns (`provider_registration_authority.rs:54`); a typo'd key in a declaration (e.g. `providerUid` misspelled) is silently ignored and the daemon's fixed-UID row silently disappears instead of failing the gate - fix: add `#[serde(deny_unknown_fields)]` to `DeclarationFile` - [packages/xtask/src/service_catalog.rs:22, packages/xtask/src/provider_registration_authority.rs:54] + evidence: seeds ran: `derive\([^)]*(De)?[Ss]erialize` = 4, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 5; the sibling-type comparison is direct line reading of the two declaration structs +The other serde shapes (camelCase rename on `RegistrationDeclaration`, `#[serde(default)]` optionality on provider_uid/services/wire_variant, `BrokerOperations` projecting only two of a row's many committed fields - deliberate, documented) are all sound; no hand-written Deserialize impls and no wire round-trips in the lane. + +## obs +- clean: seeds ran: `\bprintln!\(|\beprintln!\(` = 16 (all in main.rs; those lines are the CLI's product output - artifact paths, usage, failures - and one in policy tests), `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 3 (false positives: `changelog::` subcommand paths). No telemetry exists in this crate; user-facing stdout is the output, per the skill's CLI carve-out. + +## docs +- xtask-p1#10 sev=low blast=leaf effort=S verdict=actionable - doc comments across the policy range carry text-corruption artifacts from an earlier automated rewrite: 20 lines end with a stray `/` after the closing period (`/// ... only shrinking from here./`) and 4+ comments have doubled opening parens (`((its Cargo package name).`, `((an edit to a`), plus the typo `whiche is what`; the artifacts render as odd punctuation in rustdoc and rot the file's readability - fix: mechanical doc cleanup over the file: replace `\./$` with `.` and `((`-doubles with single parens on the doc lines (lines 5360-6556 and 8428, 8640, 8648, 9043) - [packages/xtask/src/provider_crate_policy.rs:5360, packages/xtask/src/provider_crate_policy.rs:8428, packages/xtask/src/provider_crate_policy.rs:9043] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 9; the artifact pattern `^\s*//[/!] .*\./$` = 20 and `^\s*//[/!].*\(\(` = 4 within the policy range 5354-9438 +- xtask-p1#11 sev=low blast=leaf effort=S verdict=actionable - `civil_from_days` (a port of the Howard Hinnant civil-calendar conversion) carries magic constants (719_468, 146_097, 146_096, 36_524, 153) with no citation or why, and `today_utc_iso8601` silently maps a before-epoch clock to epoch via `unwrap_or(0)` - fix: add a doc comment naming the algorithm and its constants, and decide the before-epoch behaviour explicitly (return an error or a documented fallback) - [packages/xtask/src/main.rs:1555, packages/xtask/src/main.rs:1544] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 9; the magic-number block read at main.rs:1544-1568 + +## perf +- xtask-p1#12 sev=low blast=leaf effort=S verdict=actionable - `message_only_proto` calls `trimmed.starts_with(&format!("service {service_name} "))` inside the per-line loop, allocating a String on every line of the proto file when the prefix never changes - fix: hoist `let marker = format!("service {service_name} ");` (or compare `trimmed.strip_prefix("service ")` then the name) above the loop - [packages/xtask/src/main.rs:431] + evidence: seed `format!\(` = 115 in lane; site is a loop-body allocation, cold CLI path - static (unmeasured) +- xtask-p1#13 sev=low blast=leaf effort=S verdict=actionable - `repo_root()` returns `Ok(Box::leak(path.into_boxed_path()))`, so every successful call leaks a heap allocation and re-scans env vars and parent directories; it is called by nearly every command handler - fix: cache the result once, e.g. `static ROOT: OnceLock<&'static Path>` (std, no dependency) computed on first call - [packages/xtask/src/main.rs:582] + evidence: seed `\.to_string\(\)` = 35 and `Vec::new\(\)` family = 68 in lane; the leak site read at main.rs:558-590 - static (unmeasured) +- xtask-p1#14 sev=low blast=leaf effort=S verdict=actionable - `render_schema(&RootSchema)` clones the entire schema document (large `serde_json::Value` trees for the 19 `schema_for!` documents) only to override `meta_schema` before serializing - fix: have `write_schemas` take ownership of the `Vec<(&str, RootSchema)>` and mutate each schema in place (callers already hold the schemas by value from `schema_documents()`) - [packages/xtask/src/main.rs:972] + evidence: seed `format!\(` = 115 in lane; the clone-then-mutate shape read at main.rs:958-978, called from gen_schemas/gen_cli_schemas/gen_zone_storage_schema - static (unmeasured) + +## conc +- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 3, `thread_local!|unsafe impl (Send|Sync) for` = 0. The only concurrency in the lane is a test-fixture `AtomicU32` counter plus `Ordering::Relaxed` in the policy tests module (provider_crate_policy.rs:9440-9455); production code has no threads, locks, or atomics. + +## async +- N/A (seeds: `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0 - all zero; the lane declares no async fn and no runtime usage) + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 - all zero; the crate manifest sets `unsafe_code = "forbid"` and the single `unsafe_code` string in main.rs:456 is the sanitizer's removal literal, not code; per the card, seed 4 alone does not make the lens applicable) + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 - all zero; the lane crosses no FFI boundary) + +## macro +- clean: seeds ran: `macro_rules!` = 3, `proc_macro|syn::|quote!` = 15, `\$crate` = 0, `to_compile_error|new_spanned` = 0. No macro definitions exist in the lane: the `macro_rules!` hits are a doc-comment mention (main.rs:1054) and the citation scanner's `item_binding` matcher (provider_crate_policy.rs:7721), and the `syn::` hits are the IPC visitor using `syn` as a parsing library, not a proc macro; `proc_macro_deps` hits are BUILD-attribute strings in docs and scanner constants. + +## test +- xtask-p1#15 sev=low blast=leaf effort=S verdict=actionable - the broker-operation domain test recomputes its expectation with the same filter the function under test applies (`catalog.rows.iter().filter_map(|row| row.wire_variant.clone())` re-derives `broker_operation_values`' own pick), so the `assert_eq!(values, expected)` can never disagree with the projection logic; only the human-written pins (`UsbipBind` present, `SpawnRunner`/`vmStart` absent) carry behaviour - fix: drop the recomputed `expected` and assert the human-written pins only (the vector equality adds nothing the pins do not) - [packages/xtask/src/gen_layer_catalogs.rs:705] + evidence: seeds ran: `#\[test\]|#\[tokio::test\]` = 155 (61 in the policy tests module, 79 in xtask/tests/**), `assert_eq!\(|assert_ne!\(|assert!\(` = 471, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the same-logic expectation read at gen_layer_catalogs.rs:694-720 +The remaining suite is behavior-first (fixture trees exercising both gate directions, committed-tree ratchet pins, drift and idempotence tests in provider_registration_authority.rs and main.rs; all policy unwraps live in `#[cfg(test)]`); no `#[ignore]`, no property/snapshot tooling (snapshot pins instead live in `xtask/tests/**` and the policy ratchet tests). + +## Coverage +- idiom: 5 finding(s) +- own: 2 finding(s) +- type: 1 finding(s) +- api: clean (seeds ran: 42/0/0) +- err: clean (seeds ran: 159/14/3/0) +- serde: 1 finding(s) +- obs: clean (seeds ran: 16/0/0/3) +- docs: 2 finding(s) +- perf: 3 finding(s) +- conc: clean (seeds ran: 0/0/3/0) +- async: N/A (seeds: 0/0/0/0 all zero; no async fn, spawn, or runtime in the lane) +- unsafe: N/A (seeds: 0/0/0 all zero; manifest forbids; seed 4 alone not applicable) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: clean (seeds ran: 3/15/0/0) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md new file mode 100644 index 000000000..8ae6a1357 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md @@ -0,0 +1,71 @@ +# xtask-p2 - xtask - part 2/5 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8954 (excl. src/generated/**) | modules: provider_crate_policy.rs:1-5353, gen_broker_operations.rs, delivery/eligibility.rs, diagnostic_redaction.rs, delivery/history_proof.rs +Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: provider_crate_policy.rs:1-5353 (item-range split; absolute line = sed line) + +## idiom +- clean: seeds `for \w+ in 0\.\.` = 1, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 18; the one index loop (diagnostic_redaction.rs:284 `for _ in 0..overflow`) is the idiomatic repeat-n form, the hand-rolled scanners (identifier_words, string_literal_spans, driver_declarations, normalize_ansi_escape_sequences) are byte/indent state machines with no stdlib equivalent, and the `let mut rows = String::new()` accumulators are generator text builders whose artifact is the emitted file. + +## own +- xtask-p2#1 sev=low blast=leaf effort=S verdict=actionable - `check_members(&repo_root, members.clone())` clones the whole workspace-member vec at the check entry point because `check_members` (provider_crate_policy.rs:7916) takes `Vec` by value while its body only reads it (`.iter()`, `.iter().map()`); the signature forces the clone - fix: change `fn check_members(repo_root: &Path, members: &[WorkspaceMember])` and drop the clone at the call site (second caller at 9560 passes `&manifest_workspace_members(&root)?`) - [packages/xtask/src/provider_crate_policy.rs:577, packages/xtask/src/provider_crate_policy.rs:7916] + evidence: seed `\.clone\(\)` = 47 hits in lane; signature read at 7916-7918 shows read-only use +- xtask-p2#2 sev=low blast=leaf effort=S verdict=actionable - `check_shared_family_knowledge_with` builds `exempt: BTreeSet<(String, &str)>` with `row.module.to_owned()` and probes it with `signal.module.clone()`, when the ratchet rows are `&'static str` and the signal already owns a `String`; both the build-time to_owned and the per-signal clone disappear by keying borrowed strs - fix: `let exempt: BTreeSet<(&str, &str)> = ratchet.iter().map(|row| (row.module, row.token)).collect()` and probe `exempt.contains(&(signal.module.as_str(), signal.token))` - [packages/xtask/src/provider_crate_policy.rs:5200, packages/xtask/src/provider_crate_policy.rs:5206] + evidence: seeds `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 135, `\.clone\(\)` = 47; sites 5200/5206 read +- xtask-p2#3 sev=low blast=leaf effort=S verdict=actionable - `profile_catalog` clones every row's `wire_variant` String (`row.wire_variant.clone()`) only to format it into the generated profile catalog text; the values are never mutated or stored - fix: return `Vec<&str>` via `.filter_map(|row| row.wire_variant.as_deref())` and change `string_list` (gen_broker_operations.rs:772) to take `Item = &str` (its only two call sites are 860-861) - [packages/xtask/src/gen_broker_operations.rs:844, packages/xtask/src/gen_broker_operations.rs:772] + evidence: seed `\.clone\(\)` = 47 hits in lane; string_list call sites verified at 860-861 + +## type +- xtask-p2#4 sev=low blast=leaf effort=S verdict=actionable - `FamilyKnowledgeSignal.text: String` (provider_crate_policy.rs:4664-4675) carries two meanings discriminated only by `class`: literal/identifier text for Literal/Assembled/Identifier, and a serialized count for ServerState (`text: format!("{server_state_count}")` at 5104) that the renderer re-parses (`signal.text.parse::().unwrap_or(0)` at 5179), silently defaulting a non-numeric to 0 - fix: add a typed `count: Option` field (or split the struct per class), fill it at 5104, and render by matching `class` without the parse - [packages/xtask/src/provider_crate_policy.rs:5104, packages/xtask/src/provider_crate_policy.rs:5179] + evidence: seeds `fn validate_\w+|fn check_\w+` = 12, `(mode|kind|state): String` = 5 (3 are `artifact_kind` false positives); sites 5104/5179 read + +## api +- clean: seeds `\bpub (fn|struct|enum|trait|type|const|mod) ` = 27, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 0; xtask is a bin-only crate (no lib target, publish = false, packages/xtask/Cargo.toml), so the pub items are crate-internal surface with no external callers to break; no internals-in-signature shapes and no re-export arms exist. + +## err +- clean: seeds `\.unwrap\(\)|\.expect\(` = 94, `let _ = |\.ok\(\);` = 2, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 4, `enum \w*Error` = 0; 90 of the 94 unwrap/expect hits sit in `#[cfg(test)]`; the four production hits are invariant-named expects on literally-built values (provider_crate_policy.rs:446, gen_broker_operations.rs:1155), an expect after a check the compiler cannot see (gen_broker_operations.rs:423, guarded by the pair check at 404), and `unreachable!` arms after closed-set validation (530, 913, 926, 1037); the two `let _ =` sites (diagnostic_redaction.rs:412, 421) are deliberate best-effort temp-dir cleanup. + +## serde +- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 22, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 42, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 11; every wire shape uses `rename_all` plus `deny_unknown_fields` with closed-set validation in `validate_row`/`parse_text`, the three optionality meanings are used correctly (`#[serde(default)]` vs `Option` vs `skip_serializing_if`), and `CheckConclusion`/`HistoryVerdict` fail closed on unknown conclusions; no hand-written deserializers. + +## obs +- clean: seeds `\bprintln!\(|\beprintln!\(` = 1, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0; the single eprintln! (diagnostic_redaction.rs:379) is the operator-facing failure line of a CLI filter whose stderr is the product output, not telemetry; no tracing/log dependency in the lane. + +## docs +- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 25, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 40; bin-only crate, so per the card's false-positive note undocumented pub items are not findings; all five files carry a `//!` module doc and every public entry point (run, run_capture, evaluate, open_sealed_candidate, prove, gen_broker_operations, check) has a doc comment whose first sentence carries the contract. + +## perf +- clean: seeds `format!\(` = 143, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 21, `\.to_string\(\)` = 17; every hit is an error path, a one-shot policy diagnostic, or a generator text builder whose artifact is the emitted file (card false positive); the only bounded-buffer code (read_diagnostic_tail, VecDeque::with_capacity at the 4 MiB cap) is deliberate; all findings would be static (unmeasured) and none rises to a proposal. + +## conc +- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 3, `thread_local!|unsafe impl (Send|Sync) for` = 0; the only atomic is the test-only `SCRATCH_SEQUENCE: AtomicU32` (diagnostic_redaction.rs:393-408) used with Relaxed ordering, the weakest correct ordering for a scratch-dir uniquifier. + +## async +- N/A (seeds: 0/0/0/0 all zero; no async fn, no .await, no spawn, no runtime in the lane) + +## unsafe +- N/A (seeds: 0/0/0 all zero; packages/xtask/Cargo.toml sets `unsafe_code = "forbid"`) + +## ffi +- N/A (seeds: 0 all zero; no extern surface, no repr(C)/repr(transparent), no CStr/CString in the lane) + +## macro +- N/A (seeds: 0 all zero; no macro_rules!, no proc-macro, no $crate in the lane) + +## test +- clean: seeds `#\[test\]|#\[tokio::test\]` = 138 (59 in-module across the five files, 79 in tests/), `assert_eq!\(|assert_ne!\(|assert!\(` = 382, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the in-module tests for all five files are behavior assertions with failure messages and table-driven cases (eligibility.rs:717-734 loops over every non-success conclusion; gen_broker_operations.rs:1327-1334 proves the triage view moves byte-for-byte with a row edit; diagnostic_redaction.rs:520-586 exercises truncation, multibyte splits, and malformed bytes); no test that cannot fail was found. + +## Coverage +- idiom: clean (seeds ran: 1/0/18) +- own: 3 finding(s) +- type: 1 finding(s) +- api: clean (seeds ran: 27/0/0) +- err: clean (seeds ran: 94/2/4/0) +- serde: clean (seeds ran: 22/42/0/11) +- obs: clean (seeds ran: 1/0/0/0) +- docs: clean (seeds ran: 25/0/40) +- perf: clean (seeds ran: 143/21/17) +- conc: clean (seeds ran: 0/0/3/0) +- async: N/A (seeds: 0/0/0/0 all zero; no async code in lane) +- unsafe: N/A (seeds: 0/0/0 all zero; unsafe_code = "forbid" in packages/xtask/Cargo.toml) +- ffi: N/A (seeds: 0 all zero; no FFI surface) +- macro: N/A (seeds: 0 all zero; no macros) +- test: clean (seeds ran: 138/382/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md new file mode 100644 index 000000000..5e543e777 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md @@ -0,0 +1,75 @@ +# xtask-p3 - xtask - part 3/5 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8936 (excl. src/generated/**) | modules: delivery/recovery, delivery/command, delivery/snapshot, resource_type_authority, provider_packaging, semantic_service_schemas, deadcode, authority_common, bin/manifest_v04_check +Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: part 3/5 (U1 section f: the nine files above) + +## idiom +- xtask-p3#1 sev=low blast=leaf effort=S verdict=actionable - resource_type_authority.rs carries misindented statements (`errors.push(format!(` at column 0, `out.push_str("// @generated\n");` at column 0, `fn drop` under-indented by 4) that rustfmt would reflow; the repo runs no fmt gate, so the drift is committed - fix: reindent the statements at the three sites (or run rustfmt over the file once) - [packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_authority.rs:940, packages/xtask/src/resource_type_authority.rs:1083] + evidence: idiom seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) 15 hits, each hit neighborhood read; the misindented statements were found while reading the seed-3 hits +- xtask-p3#2 sev=low blast=family effort=S verdict=needs-contract - generator string literals in resource_type_authority.rs drop spaces, so the committed generated artifact header reads "Provenance:emitted", "; the layout check's" and "byte-for-byte,and", and the type-declared-twice diagnostic reads "declared by both {}and {}" - fix: restore the spaces in the four push_str literals and the format string, then regenerate the artifact via `cargo xtask check-provider-crate-layout --fix` so the drift gate and the committed `v3_converted_resource_types.rs` move together - [packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_authority.rs:940, packages/xtask/src/resource_type_authority.rs:941, packages/xtask/src/resource_type_authority.rs:942, packages/d2b-contracts/src/generated/v3_converted_resource_types.rs:2] + evidence: idiom seed 3 15 hits; the emitted strings were confirmed byte-identical in the committed generated artifact (the drift gate would reject a mismatch), so the fix touches src/generated/** and is needs-contract per U1 section d.7 + +## own +- xtask-p3#3 sev=low blast=leaf effort=S verdict=actionable - `nix_string_list` takes `impl IntoIterator`, forcing every caller to `.to_owned()` its `&'static str` fields at seven call sites only to borrow them again inside `nix_string` - fix: change the signature to `impl IntoIterator` (or `&[&str]`) and delete the `.map(|field| (*field).to_owned())` closures at the call sites - [packages/xtask/src/provider_packaging.rs:163, packages/xtask/src/provider_packaging.rs:206, packages/xtask/src/provider_packaging.rs:222, packages/xtask/src/provider_packaging.rs:230, packages/xtask/src/provider_packaging.rs:242, packages/xtask/src/provider_packaging.rs:252, packages/xtask/src/provider_packaging.rs:263, packages/xtask/src/provider_packaging.rs:278] + evidence: own seed 2 (`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`) 168 hits lane-wide; 7 of the provider_packaging.rs hits are nix_string_list call sites (signature read in full) +- xtask-p3#4 sev=low blast=leaf effort=S verdict=actionable - `resource_ref_schema(pattern: String, allowed_types: &[String])` forces `.to_owned()`/`String::from` at every call site, including static regex literals that never need an owned String - fix: change the signature to `pattern: &str` and `allowed_types: &[&str]` (both serialize into `json!` unchanged) and drop the conversions at the call sites - [packages/xtask/src/semantic_service_schemas.rs:32, packages/xtask/src/semantic_service_schemas.rs:44, packages/xtask/src/semantic_service_schemas.rs:55, packages/xtask/src/semantic_service_schemas.rs:61, packages/xtask/src/semantic_service_schemas.rs:74, packages/xtask/src/semantic_service_schemas.rs:155, packages/xtask/src/semantic_service_schemas.rs:203] + evidence: own seed 2 168 hits lane-wide; 7 hits in semantic_service_schemas.rs are signature-forced allocations (function and call sites read in full) + +## type +- clean: type seeds 11/0/9 - seed 1 (`fn validate_\w+|fn check_\w+`) 11 hits are the recovery attestation admission gate (`validate_shape`/`validate_binding`/`validate_at` family, each a parse-once check at the decode/consumption boundary of a deny_unknown_fields wire type) plus the CLI gate `check()`; seed 3 (`(mode|kind|state): String`) 9 hits are all `artifact_kind: String` wire-record fields mirroring the pinned recovery schema; both classes are the card's recorded wire-type false positives. No boolean-flag soup, stringly-typed state, or validate-at-every-callsite duplication beyond the deliberate wire admission. + +## api +- clean: api seeds 171/0/0 - seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) 171 hits, seed 2 (`pub .*\b(Arc|Rc|Box|RefCell)<`) 0, seed 3 (`^\s*pub use `) 0. xtask is a bin-only crate (no `[lib]` target in packages/xtask/Cargo.toml), so the `pub` items are internal wiring consumed by `main.rs`, not an exported surface; over-broad `pub` visibility is already policed by the crate's own dead-code gate (`deadcode.rs` runs `cargo hawk check` for `pub` -> `pub(crate)` reductions). + +## err +- xtask-p3#5 sev=medium blast=leaf effort=S verdict=actionable - `RecoveryError::Json` conflates three failure modes: an unreadable attestation file (`read_attestation` maps open/read errors to Json), canonical-JSON rejection, and a typed-parse failure whose serde detail (missing field, line, column) is discarded, so an operator debugging a rejected attestation sees only "recovery attestation shape rejected" with no way to tell a missing file from a malformed payload - fix: add a `RecoveryError::Read` variant for the fs errors and carry the bounded serde error text (field names and positions only, never payload values, keeping the enum's redaction contract) in a `Json(String)` variant, propagating through the existing `From for DeliveryError` - [packages/xtask/src/delivery/recovery.rs:384, packages/xtask/src/delivery/recovery.rs:1610, packages/xtask/src/delivery/recovery.rs:1715, packages/xtask/src/delivery/recovery.rs:1719] + evidence: err seed 1 (`\.unwrap\(\)|\.expect\(`) 239 hits, sampled: 50 of 239 (every sampled hit is cfg(test) code or a named-invariant expect on internal catalog data); seed 2 (`let _ = |\.ok\(\);`) 4 hits (all deliberate: Drop cleanup, infallible `write!` to String, test cleanup); seed 3 (`\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`) 3 hits (test helpers and the fail-closed golden arm); seed 4 (`enum \w*Error`) 1 hit (`RecoveryError`, read in full) + +## serde +- xtask-p3#7 sev=low blast=leaf effort=S verdict=actionable - `DeclarationFile` and `TypeDeclaration` use per-field `#[serde(rename = ...)]` for their camelCase wire keys while the sibling `RoleDeclaration` in the same file uses `#[serde(rename_all = "camelCase")]`, splitting the boundary-naming convention within one file - fix: add `#[serde(rename_all = "camelCase")]` to `DeclarationFile` and `TypeDeclaration` and delete the two per-field renames - [packages/xtask/src/resource_type_authority.rs:179, packages/xtask/src/resource_type_authority.rs:182, packages/xtask/src/resource_type_authority.rs:190, packages/xtask/src/resource_type_authority.rs:192, packages/xtask/src/resource_type_authority.rs:204] + evidence: serde seed 2 (`serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`) 37 hits; the three declaration structs read in full (seeds 1/3/4: 26/0/32 hits, all derived wire types and boundary calls) + +## obs +- clean: obs seeds 15/0/0/0 - seed 1 (`\bprintln!\(|\beprintln!\(`) 15 hits are CLI product output and gate diagnostics (`deadcode.rs` eprintln report lines, `bin/manifest_v04_check.rs` usage/error lines), the card's recorded carve-out; seeds 2-4 0 hits (no interpolated events, no spans, no tracing/log dependency). No telemetry surface exists in this scope to judge. + +## docs +- xtask-p3#6 sev=low blast=leaf effort=S verdict=actionable - several pub items in the delivery modules lack the doc comment the modules' own discipline gives every sibling item: `WaveSnapshot::digests`/`program`/`wave`, `WaveCommand::as_str`/`parse`/`required_options`/`optional_options`, `WorkflowOutput::ok`/`with_digests`, `WorkflowCommandHelp`, and the `CliOptions` accessors - fix: add one-line doc comments naming each contract (mirroring the sibling wording already present) - [packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, packages/xtask/src/delivery/snapshot.rs:99, packages/xtask/src/delivery/command.rs:104, packages/xtask/src/delivery/command.rs:116, packages/xtask/src/delivery/command.rs:205, packages/xtask/src/delivery/command.rs:234, packages/xtask/src/delivery/command.rs:425, packages/xtask/src/delivery/command.rs:440, packages/xtask/src/delivery/command.rs:465] + evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) 153 hits; the listed items were confirmed doc-less while reading each module's pub surface (seed 2 `/// # (Examples|Errors|Panics|Safety)` 0 hits; seed 3 `-> Result<` 73 hits) + +## perf +- clean: perf seeds 138/37/5 - seed 1 (`format!\(`) 138 hits, seed 2 (`Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`) 37 hits, seed 3 (`\.to_string\(\)`) 5 hits; every hit is a generator building a text artifact (the card's recorded xtask carve-out), a cold error/diagnostic path, a bounded artifact read, or a test. No hot loop allocates; no collection choice is wrong for its access pattern; no attacker-controlled hashing. Perf claims are static (unmeasured) per the card. + +## conc +- N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync anywhere in the assigned files - the lane is single-threaded CLI/generator code) + +## async +- N/A (seeds: 0 all zero; no async fn, await, tokio, or block_on in the assigned files - the lane is synchronous CLI/generator code) + +## unsafe +- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, fns, impls, SAFETY comments, or transmute/from_raw/MaybeUninit sites; the crate manifest carries `unsafe_code = "forbid"`, and seed 4 alone does not make the lens applicable per the card) + +## ffi +- clean: ffi seeds 0/1/0/0 - seed 2 (`catch_unwind`) 1 hit at command.rs:1792, a `#[test]` asserting `golden_fingerprint` fails closed for an unpinned schema version; it is a panic-behavior assertion, not a foreign boundary, so no FFI surface exists to judge (seeds 1/3/4 are 0). + +## macro +- clean: macro seeds 1/0/0/0 - seed 1 (`macro_rules!`) 1 hit: `workflow_status!` (command.rs:317), a list-driven enum/wire-string/ALL-domain generator - the skill's genuine "impl-per-type generation from a list" answer; it uses the narrow `$meta:meta` fragment, needs no `$crate` (no crate paths in the expansion), and its doc comment states the drift rationale. Seeds 2-4 are 0 (no proc macros). + +## test +- xtask-p3#8 sev=low blast=leaf effort=S verdict=actionable - `workflow_status_all_enumerates_every_variant` and `wave_commands_enumerates_every_stage` assert `ALL.contains(status)` for every status drawn from `ALL` itself, so the runtime assertion is tautological and can never fail; the real guard is the wildcard-free match's compile-time exhaustiveness, which the assert adds nothing to - fix: drop the `assert!` and keep the wildcard-free match (the compile-fail property), or assert a property not derived from the same enumeration - [packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079] + evidence: test seed 1 (`#\[test\]|#\[tokio::test\]`) 174 hits, seed 2 (`assert_eq!\(|assert_ne!\(|assert!\(`) 501 hits; both tests read in full (their own comments document the compile-time intent) + +## Coverage +- idiom: 2 finding(s) +- own: 2 finding(s) +- type: clean (seeds ran: 11/0/9; all hits are wire admission gates, the CLI gate, and schema-mirroring artifact_kind fields per the card's false positives) +- api: clean (seeds ran: 171/0/0; bin-only crate with no lib target, pub items are internal wiring, cargo-hawk gate polices visibility) +- err: 1 finding(s) +- serde: 1 finding(s) +- obs: clean (seeds ran: 15/0/0/0; all eprintln/print hits are CLI product output and gate diagnostics per the card's carve-out) +- docs: 1 finding(s) +- perf: clean (seeds ran: 138/37/5; all hits are generator text building, cold error paths, bounded reads, or tests per the card's carve-outs) +- conc: N/A (seeds: 0/0/0/0 all zero; no threading primitives in scope) +- async: N/A (seeds: 0/0/0/0 all zero; no async code in scope) +- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe sites; manifest `unsafe_code = "forbid"` only) +- ffi: clean (seeds ran: 0/1/0/0; the single catch_unwind is a test assertion, not a foreign boundary) +- macro: clean (seeds ran: 1/0/0/0; the one macro is the list-driven workflow_status! generator, a genuine macro use) +- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md new file mode 100644 index 000000000..3a9bb9682 --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md @@ -0,0 +1,72 @@ +# xtask-p4 - xtask - part 4/5 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9015 (excl. src/generated/**) | modules: delivery/storage, delivery/model, delivery/mod, production_closure, zone_schema, operation_row_authority, inventory +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: packages/xtask/src/delivery/storage.rs, packages/xtask/src/production_closure.rs, packages/xtask/src/zone_schema.rs, packages/xtask/src/delivery/model.rs, packages/xtask/src/operation_row_authority.rs, packages/xtask/src/inventory.rs, packages/xtask/src/delivery/mod.rs + +## idiom +- clean: seeds ran: 0/0/39; every `let mut ... = String|Vec::new()` hit is a state-machine parser, an error collector, an fd-walk chain,a bounded read buffer, or a Nix/JSON text builder where an iterator collect would not be clearer or would split a single multi-output pass. + +## own +- xtask-p4#1 sev=low blast=leaf effort=S verdict=actionable - `compute_context(root, spec)` takes `ContextSpec` by value,so both caller loops clone the spec they still need afterwards - fix: change `fn compute_context(root: &Path, spec: ContextSpec)` (and the `compute_lock_context` recursion at production_closure.rs:431) to take `spec: &ContextSpec`,removing the `.clone()` at both loop call sites - [packages/xtask/src/production_closure.rs:263, packages/xtask/src/production_closure.rs:379] + evidence: own seed 1 `\.clone()` = ~47 hits; sites 263/379 are loop-boundary clones where the caller reads spec again after the call (spec.key(), spec.system, spec.target, spec.name, or the surviving `&contexts` for `write_advisory_skeleton`). +- xtask-p4#2 sev=low blast=leaf effort=S verdict=actionable - `check_outputs` binds `ApprovalProjection` twice in a row,but the first binding is never read after the second clone - fix: replace `let approval = advisory.approval.clone();` followed by `Some(approval.clone())` with one `Some(advisory.approval.clone())` - [packages/xtask/src/production_closure.rs:383, packages/xtask/src/production_closure.rs:386] + evidence: own seed 1 `\.clone()` = ~47 hits; the clone at :383 is consumed only by the clone at :386,and nothing else in the loop body reads `approval`. + +## type +- xtask-p4#3 sev=medium blast=leaf effort=S verdict=actionable - inventory.rs re-implements the crate's own `delivery::model::validate_repo_relative_path` with the same invariant (minus the empty-path check), so two validators drift apart - fix: delete the private copy at inventory.rs:230,and call `crate::delivery::model::validate_repo_relative_path(Path::new(path))`, keeping the stricter empty check - [packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557] + evidence: type seed 1 `fn validate_\w+|fn check_\w+` = 14 hits; census: `validate_repo_relative_path` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 14 hits (model's pub helper already serves delivery/snapshot.rs; inventory carries its own private copy). +- xtask-p4#4 sev=low blast=leaf effort=M verdict=needs-contract - `EdgeRecord.kind: String` carries the closed Cargo dependency-kind vocabulary {"normal","build","dev","proc-macro"} as a free string through traverse/filter/emit - fix: introduce a closed `EdgeKind` enum parsed once at the metadata boundary (dep_kinds reads at :660-676), serde-renamed to preserve the wire spelling "proc-macro",and regenerate the committed packages/policy-inputs/** closures - [packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660, packages/xtask/src/production_closure.rs:724] + evidence: type seed 3 `(mode|kind|state): String` is 1 site (EdgeRecord.kind); the vocabulary is closed per `production_kinds()`/`policy_kinds()` sets (lines 74-82),and `package_is_proc_macro()`; the emitted closure.json projections are committed generated shapes,so the change is needs-contract. + +## api +- clean: seeds ran: 45/0/4; xtask is bin-only (no `src/lib.rs`, no `[lib]` target, `default-run = "xtask"`), so pub and re-exported items are crate-internal and no external API contract exists to judge or break. + +## err +- clean: seeds ran: ~80/7/2/1; every surviving unwrap/expect site is cfg(test), an invariant expect on an already-checked map lookup,a literally-built JSON value, or `write!` to String; the `let _ =` sites are documented best-effort Drop cleanups; the two panic sites are tests; the one enum hit is `DeliveryErrorKind` (the kind half of the already-correct struct-with-private-kind pattern). + +## serde +- xtask-p4#5 sev=low blast=leaf effort=S verdict=actionable - `SnapshotView` (mod.rs:46-47) lacks `#[serde(deny_unknown_fields)]` while every nested wire type in the same artifact (CandidateMaterial, RepositoryRecord, Fingerprint, DependencyEdge, digest newtypes) denies, so a hand-edited snapshot can carry silently-ignored top-level keys - fix: add `#[serde(deny_unknown_fields)]` to SnapshotView; the `schema_version` gate already handles version drift,so there is no forward-compat cost - [packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111] + evidence: serde seed 2 `#[serde(...)]` attr scan = ~30 attr sites; SnapshotView is the only Deserialize-wire type in the lane without an attr (every sibling denies at model.rs:111-112, 144-145, 234-235, 244-245, 269-270, 305-307). + +## obs +- clean: seeds ran: 4/0/0/0; all four println!/eprintln! sites are CLI product output per the cli-contract (result JSON on stdout, diagnostics on stderr); no tracing/log, instrument, or interpolated log macros exist in these modules. + +## docs +- clean: seeds ran: 45/0/60; xtask is bin-only per the skill's own carve-out,and every public contract-bearing item (StateRoot, CandidateDir, model wire types, SnapshotView, DeliveryError/DeliveryErrorKind) carries full API docs;# Errors sections are N/A on crate-internal Result fns. + +## perf +- clean: seeds ran: ~38/~40/4; every site is a cold one-shot CLI path, an error diagnostic, or a deliberate Nix/JSON artifact text builder (recorded false-positive classes); no hot loop allocates,and no benchmark exists (static, unmeasured). + +## conc +- clean: seeds ran: 1/2/7/2; the only production sync site is the `Relaxed` atomic temp-suffix counter (recorded atomics-as-counters class); all other sync sites are cfg(test) race-hook/override machinery (test-only synchronization class). + +## async +- N/A (seeds: 0/0/0/0 all zero; no async fns, awaits, spawns, runtimes, or tokio sync guards exist in these files). + +## unsafe +- N/A (seeds: 0/0/2-false-positive/0; the two `from_raw` hits are safe `rustix::fs::FileType::from_raw_mode` conversions, not unsafe ops; no unsafe block/fn/impl or `// SAFETY:` comment exists in scope,and the crate's `unsafe_code = "forbid"` lint setting is untouched). + +## ffi +- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, `no_mangle`, `catch_unwind`, `reprC()`/`repr(transparent)`, or CStr/CString/c_char surface exists; rustix/nix syscall wrappers never cross a foreign caller). + +## macro +- clean: seeds ran: 1/1/0; the sole `digest_identifier!` macro is impl-per-type generation for the three digest newtypes (one of the skill's three genuine macro uses), with ident/literal fragment specifiersand no external paths to shadow; the one proc_macro/syn hit is the fn name `package_is_proc_macro` (false positive). + +## test +- clean: seeds ran: 50/~150/0/0; tests are behavioral fixture-driven unit tests (parity/drift gates, digest identity matrix, path-safety matrix, exit-code contract), table-driven where apt; no ignored or tautological tests found. + +## Coverage +- idiom: clean(seeds ran: 0/0/39) +- own: 2 finding(s) +- type: 2 finding(s) +- api: clean(seeds ran: 45/0/4) +- err: clean(seeds ran: ~80/7/2/1) +- serde: 1 finding(s) +- obs: clean(seeds ran: 4/0/0/0) +- docs: clean(seeds ran: 45/0/60) +- perf: clean(seeds ran: ~38/~40/4) +- conc: clean(seeds ran: 1/2/7/2) +- async: N/A (seeds: 0/0/0/0 all zero; no async code) +- unsafe: N/A (seeds: 0/0/2-false-positive/0; no real unsafe sites) +- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) +- macro: clean(seeds ran: 1/1/0) +- test: clean(seeds ran: 50/~150/0/0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md new file mode 100644 index 000000000..c87bfcd1e --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md @@ -0,0 +1,72 @@ +# xtask-p5 - xtask - part 5/5 +Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9009 (excl. src/generated/**) | modules: changelog.rs, async_gate.rs, blocking_census.rs, delivery/evidence.rs, nix_inventories.rs, bazel_evidence.rs, delivery/seal.rs +Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/changelog.rs, src/async_gate.rs, src/blocking_census.rs, src/delivery/evidence.rs, src/nix_inventories.rs, src/bazel_evidence.rs, src/delivery/seal.rs + +## idiom +- xtask-p5#1 sev=low blast=leaf effort=S verdict=actionable - `resource_type.to_string()` in an iterator map over `&[String]` where `.cloned()` is the idiomatic copy - fix: `STANDARD_RESOURCE_TYPES.iter().map(|resource_type| resource_type.to_string()).collect::>()` -> `.iter().cloned().collect::>()` - [packages/xtask/src/nix_inventories.rs:721] + evidence: seed `\.to_string\(\)|\.to_owned\(\)|\.to_vec\(\)` = ~96 hits (lane); the cited site is the only production iterator-map copy in this part; the rest are tests and error-path strings + +## own +- xtask-p5#2 sev=low blast=leaf effort=M verdict=actionable - Baseline map build clones each `CrateCensus`'s `crate_dir` and `counts` twice per crate although the later baseline check only re-borrows them - fix: build `CensusBaseline` from `crates.into_iter().map(|c| (c.crate_dir, c.counts)).collect()` (when `json_out` is set( and drive the `--baseline` check loop from `&baseline.crates` instead of `&crates` - [packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287] + evidence: seed `\.clone\(\)` = ~32 hits; at blocking_census.rs:1270-1272 the pair clone fires twice per crate into the committed-baseline map; every other clone in this part buys an owned value whose borrower stays live + +## type +- clean: seeds ran: `fn validate_\w+|fn check_\w+` = 3 / `is_\w+: bool|\w+_flag: bool` = 0 / `(mode|kind|state): String` = 0; the three hits (`validate_inventory`, `check_security`, `validate_single_line`) are boundary validators in a CLI/gate context where parse-once newtypes would be over-engineering per the stopping rule + +## api +- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod) ` = ~66 / `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 / `^\s*pub use ` = 0; all pub items checked; xtask is a bin-only crate (no `lib` target, `publish = false`), so every `pub` item is crate-internal surface, and the pub fields on delivery records serve sibling-module construction + +## err +- clean: seeds ran: `\.unwrap\(\)|\.expect\(` ~95 (production hits ~12, every one an invariant assert on a compiler-verified or pre-checked value - `String::from_utf8(out).expect)...)` async_gate.rs:824, `serde_json::to_string_pretty(&value).expect)...)` bazel_evidence.rs:41, allocation `.get)...).expect("...checked against the allocation")` nix_inventories.rs:620,641; the rest are `#[cfg(test)]`( / `let _ = |\.ok\(\);` ~16 (test fixture strings and deliberate best-effort `Drop` cleanup in changelog tests( / `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 1 (test( / `enum \w*Error` = 0; panic policy is sound; no swallowed Results in production paths + +## serde +- clean: seeds ran: `derive\([^)]*(De)?[Ss]erialize` = 13 / `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 9 / `impl .*Deserialize.*for` = 0 / `serde_json::from_|serde_json::to_` ~18; wire record types (`HatchInventory`, `CensusBaseline`, `EvidenceRecord`, `OutputDigest`, `SealedLane`, `SealedValidation`, `SealRecord`) usa `rename_all = "kebab-case"` for the lane enum, `deny_unknown_fields` on the committed record shapes, and `#[serde(default, skip_serializing_if = "Option::is_none")]` on optional record fields; no hand-written deserializers and no missing-boundary validation identified + +## obs +- clean: seeds ran: `\bprintln!\(|\beprintln!\(` ~31 (all CLI product output of changelog-fold, check-async-gate, blocking-census, and bazel-evidence subcommands - the card's sanctioned xtask case( / `(info|debug|warn|error|trace)!\("` = 0 / `\.instrument\(|#\[instrument` = 0 / `tracing::|log::` = 0; no telemetry or event logging in this part + +## docs +- xtask-p5#3 sev=medium blast=leaf effort=M verdict=actionable - Pub field groups on the wire and census record types carry no field-level doc contracts, so units and serialization formats are guesswork - fix: add per-field doc comments to `DeniedApi.path/tail/kind`, `CensusBaseline.crates`, `OutputDigest.sha256/bytes`, `EvidenceRecord.*`, `SealedLane.lane/validations`, `SealedValidation.validation/record_sha256`, `SealRecord.*` - [packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packages/xtask/src/delivery/evidence.rs:120, packages/xtask/src/delivery/evidence.rs:128, packages/xtask/src/delivery/seal.rs:35, packages/xtask/src/delivery/seal.rs:48, packages/xtask/src/delivery/seal.rs:61] + evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~66 hits; at the cited records the pub fields lack docs for `sha256` (hex? base64?), `imported_at_unix` (seconds?), `schema_version` semantics,and map-key forms +- xtask-p5#4 sev=low blast=leaf effort=S verdict=actionable - Result-returning pub fns describe failure modes in prose rather than the canonical `# Errors` section - fix: add `# Errors` sections to `parse_fragment`, `EvidenceLane::parse`, `EvidenceRecord::validate`, `SealRecord::validate`, and `async_gate::scan_source` naming each rejection condition - [packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/xtask/src/delivery/evidence.rs:162, packages/xtask/src/delivery/seal.rs:77, packages/xtask/src/async_gate.rs:265] + evidence: seed `-> Result<` ~68 hits; the cited pub fns carry prose rejection lists (e.g. "Rejected: an empty fragment, an unknown...") where the skill's canonical-section shape is absent + +## perf +- xtask-p5#5 sev=low blast=leaf effort=S verdict=actionable - `contains_quoted_field` allocates two `format!`'d quoted literals per field per quote inside the per-line redaction scan, up to 8 small String allocations per log line - fix: frame the four credential field names once per `redact_text` call (or as module `const` literals( and pass `&[&str]` framed forms to `contains_quoted_field` so the per-line scan only does `.contains)...)` - [packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packages/xtask/src/bazel_evidence.rs:407] + evidence: static (unmeasured); seed `format!\(` ~45 hits over the lane;(the other format sites are error paths or deliberate artifact-text generation, which the card exempts; the cited site allocates inside a per-line loop over a potentially large build log + +## conc +- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` ~8 / `\bMutex<|\bRwLock<` ~13 / `Atomic\w+|Ordering::` = 0 / `thread_local!|unsafe impl (Send|Sync) for` = 0; every hit is doc prose or a test-fixture source string inside scanner/gate modules; no threads, locks, atomics, or manual Send/Sync claims exist in real code of this part + +## async +- clean: seeds ran: `async fn|async move|\.await` ~40 / `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` ~8 / `tokio::sync::(Mutex|RwLock|Notify)` ~3 / `#\[tokio::(main|test)\]|Runtime::block_on` ~2; every hit is doc prose or a test-fixture source string; the gate implementations themselves are synchronous, so no async context, spawn, or await exists in this part's real code + +## unsafe +- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0 / `// SAFETY:` = 0 / `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; seed 4 `unsafe_code` = 1,the sole hit is `#![forbid(unsafe_code)]` at bazel_evidence.rs:1,which does not make the lens applicable) + +## ffi +- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0 / `catch_unwind` = 0 / `repr\(C\)|repr\(transparent\)` = 0 / `CStr|CString|c_char` = 0; no FFI boundary exists in these files) + +## macro +- xtask-p5#6 sev=low blast=leaf effort=S verdict=actionable - The test-only `crash_if_hooked!` macro is defined textually-identically in three sibling fns, differing only in the message string - fix: hoist to one module-scope `macro_rules! crash_if_hooked { ($stage:expr, $message:expr) => { #[cfg(test)] if let HookOutcome::Crash = hook($stage) { return Err(FoldError::single($message)); } }; }` and call with the stage plus message, or replace with a `#[cfg(test)]` generic helper fn - [packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/src/changelog.rs:1019] + evidence: seed `macro_rules!` = 3 hits; all three definitions are identical except the embedded message (and the stage enum type, which the `$stage:expr` fragment never names); no proc-macro/syn usage exists in this part + +## test +- clean: seeds ran: `#\[test\]|#\[tokio::test\]` ~70 / `assert_eq!\(|assert_ne!\(|assert!\(` ~500 / `proptest!|insta::assert|rstest` = 0 / `#\[ignore\]` = 0; sampled: 50 of ~500 assertion hits across the seven files' test modules;(the test-lens scope for this part is the `#[cfg(test)]` blocks inside the assigned files, since `tests/` belongs to no part partition); sampled assertions are table-driven with per-case failure messages, the fold-recovery crash-injection tests drive every journal boundary, and the evidence/seal tests assert binding and tamper rejection; no ignored, tautological, or network-touching tests spotted + +## Coverage +- idiom: 1 finding(s +- own: 1 finding(s +- type: clean (seeds ran: 3/0/0; the three validators are boundary checks where parsed types would be over-engineering) +- api: clean (seeds ran: ~66/0/0; bin-only crate with no lib target, so pub surface is crate-internal) +- err: clean (seeds ran: ~95/~16/1/0; production panics are invariant asserts only) +- serde: clean (seeds ran: 13/9/0/~18; record shapes usa the right optionality and field-rejection attributes) +- obs: clean (seeds ran: ~31/0/0/0; all println sites are CLI product output) +- docs: 2 finding(s +- perf: 1 finding(s +- conc: clean (seeds ran: ~8/~13/0/0; all hits are doc prose or test-fixture strings) +- async: clean (seeds ran: ~40/~8/~3/~2; all hits are doc prose or test-fixture strings) +- unsafe: N/A (seeds: 0/0/0; unsafe_code = 1,only a forbid attribute) +- ffi: N/A (seeds: 0/0/0/0; no FFI surface) +- macro: 1 finding(s +- test: clean (seeds ran: ~70/~500/0/0; sampled: 50 of ~500 assertion hits; see section) \ No newline at end of file diff --git a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md new file mode 100644 index 000000000..b86584fe7 --- /dev/null +++ b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md @@ -0,0 +1,353 @@ +--- +artifact_contract: ce-unified-plan/v1 +product_contract_source: ce-plan-bootstrap +execution: code +title: Rust skills audit remediation - Plan +type: refactor +date: 2026-09-24 +origin: docs/audits/2026-09-24-rust-skills-audit/README.md +--- + +# Rust skills audit remediation - Plan + +## Goal Capsule + +- **Objective:** the 965 findings of the 2026-09-24 rust-skills audit are each applied or recorded with evidence, the workspace's gates are green on the resulting head except where the wave-0 baseline attributes a failure to pre-existing work, and one reviewed pull request carries the work. +- **Means:** wave-ordered application with the audit's lane files as the unit of record (KTD1), re-verify-then-apply with escalation (KTD5), per-wave gates (KTD3), one pull request at the end (KTD2). +- **Authority order:** `AGENTS.md` and its linked contributor authorities first; the audit report and lane files as the unit of record for finding content; this plan for sequencing and gates. +- **Execution profile:** Deep refactor across the 94-crate workspace, executed by `ce-work` with per-wave integration in the primary clone (KTD11), then the repository's PR tail. +- **Stop conditions:** a wave gate fails and is not attributable to the recorded baseline (KTD4) - stop the wave and record; a settled decision (KTD2, KTD3, KTD8, KTD9, KTD10) is contradicted by evidence - stop and report rather than resolve silently. +- **Who finishes:** the repository caller - commit and push, the mandatory independent `ce-code-review mode:agent` pass on the final head, then the reviewed-head lifecycle to merge. + +--- + +## Product Contract + +### Summary + +Execute the remediation of the 2026-09-24 rust-skills audit: 923 `actionable` findings applied across the 94 workspace crates in the audit's own blast-radius order (leaf, then family, then wide), except that the actionable high-severity rows land first in a wave of their own, 25 `needs-contract` findings applied together with the schema, emitter, documentation, manifest-version, and golden-pin work they require, and 17 `policy-confirmed` findings recorded as deliberate no-ops that cite the policy they conflict with. The audit's report and lane files remain the unit of record; the plan pins wave structure, the per-finding verification discipline, the gates, and the recording ledger, and does not re-enumerate the findings. + +### Problem Frame + +The audit (16 craft lenses over every workspace crate, independently verified) produced 965 findings whose median item is small - a clone that a borrow replaces, a doc comment missing its contract sections, an iterator that an index loop shadows, a test that cannot fail - and whose head is not: 13 `high` rows carry a panic reachable from wire or caller input, a blocking call on an executor worker, a test that cannot fail, or one assertion that cannot pass and is red at the head. The findings are evidence-complete but unimplemented, and they live beside a policy surface that will fail closed on careless fixes: a blocking-API lint at live `deny` level, an async-gate inventory keyed by file and line, a blocking census with committed baselines, provider-crate ratchets, and a security scan that rejects log records mentioning pinned correlation identifiers. + +### Requirements + +**Execution discipline** + +- R1. Every finding is applied, or recorded in the remediation ledger with evidence as skipped-stale, already-fixed, escalated, reclassified, or policy-confirmed; an applied row whose stated fix could not be used as written records the variant it landed instead; close-out accounts for each finding id exactly once. +- R2. Within a wave, findings are applied most-severe first; the 12 actionable `high` rows land before their lenses' bulk work, and the thirteenth (policy-confirmed) is recorded as a no-op in the same wave. +- R3. No finding is applied on the audit's word alone: its claim is re-verified at current HEAD by symbol, re-running the lane's own census or search; a stale or already-fixed claim is recorded and not applied, and a claim that holds under a fix that cannot be used as written is applied as the minimal correct variant with the deviation and its evidence recorded. +- R4. A finding whose re-verification shows wider impact than its audited blast tag escalates to the later wave that owns that surface, and the escalation is recorded. +- R5. Beyond the fix each finding states, no behavior changes; the existing test suites are the behavioral net. + +**Contract surface** + +- R6. A change to a wire format, error code, manifest schema, CLI surface, or generated shape moves schema, emitter, prose, `manifestVersion`, and the pinning golden test together in one commit, with committed output from the generator aggregate. +- R7. Generated Rust is never hand-edited; a change to generated output goes through its generator source. + +**Recording** + +- R8. The audit report and lane files stay unedited; the remediation ledger lives beside them and is updated in the same pull request as the fixes it describes. +- R9. Finding identifiers appear only inside the audit directory and its ledger - never in source, doc comments, commit messages, changelog fragments, or the pull request body. + +**Gates** + +- R10. Each wave ends green on the gate set KTD3 owns, including the container lane for the wave that moves the guest lockfile; a red gate that is not baseline-attributed stops the next wave. +- R11. A fix that moves a ratchet surface moves the ratchet in the same commit: the async-gate inventory, the blocking-census baseline, and the provider-crate-policy rows. +- R12. Final acceptance runs both `make test-integration` and `make test-host-integration`. + +**Delivery** + +- R13. Waves land as commits on one branch, and the work ships as one pull request whose final head carries an independent review pass. +- R14. `policy-confirmed` findings are not implemented; each is recorded as a no-op citing the policy it conflicts with, and is implemented only if that policy has since changed, with the reclassification and its evidence recorded. + +### Scope Boundaries + +**In scope:** all 965 audit findings, distributed across the audit's blast-radius and verdict clusters as mapped in the appendix; the ratchet reconciliations and contract-surface updates those fixes force; the remediation ledger. + +**Deferred to Follow-Up Work** + +- Findings reclassified at apply time into a surface this plan excludes (recorded in the ledger, then planned separately). +- The retired `labs/` tree and any pre-existing failure the baseline attributes to work outside the audit's crates. +- New benchmark coverage for the perf lens: the audit's perf rows are static, and this plan applies only their structural wins (KTD10). + +### Open Questions + +None blocking. Deferred to implementation, by design: which individual findings turn out stale at apply time (R3 handles it), and which wave each escalated finding lands in (R4). + +--- + +## Planning Contract + +### Key Technical Decisions + +- KTD1. **Lanes are the unit of record; the plan defines waves, gates, and the ledger.** Chosen over re-enumerating findings here: the lane files carry anchors, evidence lines, and per-finding fixes, and duplicating them would fork two sources of truth. +- KTD2. **One pull request at the end; waves are commits on one branch.** (session-settled: user-directed - chosen over a pull request per wave: the user directed a single end-of-work pull request.) The wave commits keep the diff reviewable per wave, and the review pass consumes the ledger's finding-to-diff map per wave rather than re-deriving the structure from the aggregate diff. +- KTD3. **A wave gate is `make check` plus `make test-host-integration`, extended with `make check-census` and the local security scan.** (session-settled: user-directed - chosen over gating on `make check` alone: the user directed the host-integration lane between waves.) The two additions are required checks on the protected branch that `make check` does not subsume, and the most common fix shapes here - moving blocking work off the executor, restructuring a log record - are exactly what they catch. One wave extends the set: the wave that moves the guest lockfile also runs the container lane, because no other gate in the set exercises a foreign userland. Environmental failures in the host lane (Attic preflight, missing KVM, privileged build) are retried with the same unmodified command and reported; a Bazel profile is never switched to route around a failure. +- KTD4. **Wave 0 records a baseline before any wave verdict is read.** The audit's own report identifies a test at `packages/d2b-resource-runtime/src/revision.rs` that asserts a placeholder against a rendering that cannot contain it, so `make check` at an untouched head is expected red; a gate verdict is only evidence once pre-existing failures are attributed to the baseline rather than to a wave. +- KTD5. **Re-verify, then apply, and escalate wider-than-audited impact forward.** Chosen over applying the queued tag blindly: the audit's blast tags are judgments, and a leaf-tagged finding that breaks a consumer crate fails the wave's own gate. +- KTD6. **Ratchet reconciliation is the integrator's step, in the same commit as the fix.** The async-gate inventory is keyed by file and line and fails in both directions; the blocking census fails on any covered count above its baselined value; the provider-crate ratchets fail on an entry whose signal is gone. None of them can be reconciled in a later cleanup commit without leaving the wave gate red. +- KTD7. **A contract change commits the whole surface at once.** `make generate` is the only write path for generated artifacts, `tests/golden/**` and the in-code golden pins are hand-updated, and the schema version moves with the pinning test; anything less fails the drift gate or a frozen-wire test. +- KTD8. **`policy-confirmed` findings stay unimplemented.** (session-settled: user-approved - chosen over reopening the underlying policy or decision inside this plan: the user confirmed the recorded-no-op scope.) Each cites the policy file it conflicts with; a finding whose cited policy has since changed is reclassified to actionable with the evidence recorded. +- KTD9. **Test-lens findings repair first and delete second.** (session-settled: user-approved - chosen over blanket repair or blanket deletion: the user confirmed the disposition rule.) A test judged incapable of failing is re-verified at apply time, its provider-crate layout obligations are checked, and only then is it deleted with its references swept. +- KTD10. **Perf findings are applied as structural wins only.** (session-settled: user-approved - chosen over measurement-first gating: the user confirmed the static evidence as the basis.) The audit measured nothing; this plan takes the avoidable allocation, copy, and scan-cost wins and leaves micro-tuning and new benchmarks to separate work. +- KTD11. **Waves partition by file ownership; workers get isolated worktrees; the integrator lands slices.** Chosen over an undivided fan-out: findings in one file across several audit lanes would otherwise collide, and the generator aggregate must be serialized per wave rather than per worker. + +### High-Level Technical Design + +Per-finding lifecycle - every finding takes exactly one path out of classification: + +```mermaid +flowchart TB + A[Finding row + lane evidence] --> B[Re-verify at HEAD by symbol; re-run lane census] + B -->|claim holds| C[Apply the stated fix at the narrowest layer] + B -->|symbol gone or already fixed| D[Record skipped-stale or already-fixed] + B -->|claim holds, stated fix unusable as written| V[Apply the minimal correct variant; record deviation] + B -->|wider impact than its tag| E[Escalate to the owning later wave; record] + B -->|cited policy changed| F[Reclassify to actionable with evidence] + B -->|policy still stands| G[Record policy-confirmed no-op] + V --> H + C --> H[Reconcile ratchets touched by the fix, same commit] + C --> I[Update ledger row: outcome, anchor, wave, commit] +``` + +Wave and gate sequence - one branch, one pull request: + +```mermaid +flowchart TB + W0[Wave 0: commit audit corpus; baseline snapshot; clear the red-at-head rows] --> G0{Gate} + G0 -->|green or baseline-attributed| W1[Wave 1: docs + idiom + own leaf] + W1 --> G1{Gate} + G1 --> W2[Wave 2: type + api + err + serde + obs leaf] + W2 --> G2{Gate} + G2 --> W3[Wave 3: perf + conc + async + unsafe + macro + test + supply leaf] + W3 --> G3{Gate} + G3 --> W4[Wave 4: family consolidations] + W4 --> G4{Gate} + G4 --> W5[Wave 5: wide cross-crate classes] + W5 --> G5{Gate} + G5 --> W6[Wave 6: needs-contract surface moves] + W6 --> G6{Gate} + G6 --> CL[Close-out: ledger reconciliation, final acceptance, pull request] +``` + +Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) happen inside the wave, before its gate. + +### Assumptions + +- The audit corpus is committed with wave 0 so worktrees and reviewers can read the lanes (its directory is currently untracked). +- `make check` at the untouched head is red on the audit's reported test; wave 0 confirms or refutes this, and the baseline record decides how later red gates are attributed. +- Findings' anchors are valid at the audit's baseline commit; the tree has not changed since, but application still locates symbols rather than lines (R3). + +--- + +## Implementation Units + +### U1. Wave 0 - baseline, corpus commit, and the red-at-head rows + +- **Goal:** the unit of record is tracked, the gate baseline is recorded, and the correctness-first rows are fixed (or, for the one policy-confirmed row, recorded) so the first wave gate reads as evidence. +- **Requirements:** R2, R3, R5, R10; KTD4. +- **Dependencies:** none. +- **Files:** `docs/audits/2026-09-24-rust-skills-audit/` (report, `U1-constraints.md`, `lane/`, `VERIFICATION.md`, plus the new ledger), `changelog.d/`, and the finding sites - `packages/d2b-resource-runtime/src/revision.rs`, `packages/d2bd-runtime/src/runtime_process.rs`, `packages/d2b-broker/src/runtime.rs`, `packages/d2b-broker/src/ops/kernel_ops.rs`, `packages/d2b-broker/src/ops/sys.rs`, `packages/d2b-bus/src/` (telemetry test), `packages/d2b-provider-display-wayland/src/filter.rs`, `packages/d2b-provider-wayland-policy/src/` (applied), `packages/d2b-provider-user/src/` (record-only, no code change). +- **Approach:** + 1. Commit the audit corpus and create the ledger with this row schema: finding id, lens, cluster, audit verdict, outcome, apply-time anchor, wave, commit, reason or policy citation, escalation history, and - for an escalated row - the final outcome recorded when the owning wave applies it (KTD1, R8). + 2. Record the baseline: run the KTD3 gate set at the untouched head and write the result - pass or fail per gate, with every pre-existing failure attributed. Any additional pre-existing failure inside the audit's crates is fixed here when it blocks the gate and otherwise recorded as baseline-attributed and deferred. + 3. Dispose of the 13 `high` rows, re-verified per R3: apply the four test rows, the two wire-digest panic rows, the provider-wayland-policy caller-input panic at its driver-args boundary, and the four executor-blocking rows (each with the replacement the lint vocabulary names rather than a new allowance); record the provider-user blocking-NSS row as a policy-confirmed no-op citing its policy (R14, KTD8); escalate the remaining member sites of the shared driver-args class to U5, with the escalation recorded. + 4. Reconcile the ratchets these rows touch, then run the gate; the wave only closes with a red-to-green delta on the baseline record. +- **Patterns to follow:** the sibling `from_request_with_join` path already converts the same parse failure into a typed protocol error; the sibling `sd_notify_ready` test already asserts an observable outcome; the bounded-worker shape named in `clippy.toml` is the house replacement for blocking work on the executor. +- **Test scenarios:** + - The revision display test asserts the rendered revision and passes. + - Each repaired `sd_notify` test fails when its observable outcome changes; any test deleted here was re-verified incapable of failing and its references were swept. + - The bus telemetry test fails when a label leaves the closed set. + - A malformed authoritative-audit join reaching the broker and the daemon yields the typed protocol refusal instead of a panic - the scenario mirrors the sibling converting path. + - The rewritten display-wayland registry-handler test fails when the synthetic clipboard global stops being advertised. + - The provider-wayland-policy driver constructor returns a typed refusal for a malformed zone token instead of panicking. + - The ledger carries the provider-user NSS row as a policy-confirmed no-op citing the policy file, with no code change in that crate. + - `make check-census` is no worse than the recorded baseline after the blocking fixes. +- **Verification:** the audit corpus is tracked; the baseline record states each gate's state at the frozen head; every U1 ledger row carries an outcome and an apply-time anchor; the wave gate set is green or the residual failures are attributed to the baseline with evidence. + +### U2. Wave 1 - documentation, idiom, and ownership leaf work + +- **Goal:** the three largest leaf clusters are applied: doc contracts, iterator and derive idiom, and ownership that removes explainable clones. +- **Requirements:** R1-R5, R10, R11. +- **Dependencies:** U1. +- **Files:** the `docs`/`idiom`/`own` lane groups across their crates (about 64 crates carry doc rows; the heaviest are the daemon, broker, bus, xtask, session, and resource-runtime crates), `packages/xtask/data/async-gate-inventory.json` when line shifts demand it, `changelog.d/`. +- **Approach:** + 1. Partition the wave's rows by file so no two workers share a file (KTD11); run the mechanical clusters in parallel worktrees. + 2. Apply doc rows as contract prose: first-sentence shape, `# Errors`/`# Panics`/`# Safety`/`# Examples` on the items the lanes name, module docs; new examples become doctests that must pass inside `make check`. + 3. Apply idiom and ownership rows as behavior-preserving rewrites, and take the lane's own evidence line as the census for any claim about unused or reducible surface (R3). + 4. Reconcile the async-gate inventory if an edit shifts a marked call's line, and run the wave gate. +- **Patterns to follow:** the crate-level `#![deny(missing_docs)]` crates document every public item, so prose additions are safe there and any new public item must carry docs; existing doc blocks that already state contract prose are the template. +- **Test scenarios:** + - Every doctest added or changed by this wave compiles and passes inside the Layer-1 gate. + - A crate carrying `#![deny(missing_docs)]` still builds after any public item this wave touches. + - Rewritten iterator and ownership sites leave the crate's existing suite green with unchanged assertions. + - The async-gate inventory regenerates byte-stable when nothing shifted, and records shifted lines when they did. +- **Verification:** wave gate set green; ledger rows for every applied, skipped, or escalated row of these three lenses. + +### U3. Wave 2 - type, api, err, serde, and observability leaf work + +- **Goal:** the model-shaped clusters are applied: illegal states in types, public-surface leaks, error taxonomies, serde boundaries, and log records. +- **Requirements:** R1-R5, R9-R11. +- **Dependencies:** U1; independent of U2 (disjoint files), but the KTD3 gate between waves serializes them. +- **Files:** the `type`/`api`/`err`/`serde`/`obs` lane groups and their crates; `docs/reference/error-codes.md` and `tests/golden/**` only where a row says the wire shape moves, in which case the row belongs to U7; `changelog.d/`. +- **Approach:** + 1. Type and api rows: parsed newtypes over re-parsed strings, visibility reductions the lanes support by census, and public-surface narrowing; a row that changes a wire type is escalated to U7 rather than applied here (R4, R6). + 2. Error rows: taxonomies split by caller action, context that survives the call stack, and typed refusals replacing panics where the lanes name them. + 3. Serde rows: boundary validation at the deserialization edge, representation choices the lane names, and round-trip tests for anything that changes shape. + 4. Observability rows: structured fields over formatted strings, one log per error chain, and - mandatory - no log record this wave edits may reference the pinned correlation identifiers the security scan rejects. + 5. Record this wave's policy-confirmed rows (the type, api, and serde no-ops) as no-ops citing their policies (R14). +- **Patterns to follow:** sibling types in the same crate that already validate on admission; the repository's generated error-code reference is the authority for anything wire-visible and is regenerated, not hand-edited. +- **Test scenarios:** + - A type introduced for a previously re-parsed string rejects the malformed input the old `expect` would have panicked on. + - A narrowed public surface leaves the workspace building; any lane-claimed unused item is deleted only with the lane's census re-run. + - Changed error paths return the typed variant the lane names, with the existing failure-path tests updated to assert it. + - A serde shape change round-trips through its crate's existing serde tests, or those tests move with the wire change into U7. + - The local security scan reports no finding on the wave's added lines. +- **Verification:** wave gate set green; ledger rows for each applied, skipped, or escalated row; any escalation to U7 recorded with its reason. + +### U4. Wave 3 - perf, concurrency, async, unsafe, macro, test, and supply leaf work + +- **Goal:** the risk-shaped clusters are applied: allocation and scan cost, lock and channel discipline, async-correctness, unsafe documentation, macro hygiene, test quality, and dependency hygiene. +- **Requirements:** R1-R5, R9-R11. +- **Dependencies:** U1; overlaps U2/U3 only through crates, not finding-site files - the async-gate inventory under `packages/xtask/data/` is shared ratchet data that U2 and this wave both list. +- **Files:** the `perf`/`conc`/`async`/`unsafe`/`macro`/`test`/`supply` lane groups and their crates; `packages/xtask/data/blocking-census-baseline.json` and `packages/xtask/data/async-gate-inventory.json` when a fix moves them; per-crate `Cargo.toml` and `BUILD.bazel` for dependency rows; `packages/Cargo.guest.lock` when a mirrored crate's dependency set changes; `changelog.d/`. +- **Approach:** + 1. Perf rows: take the structural wins (avoidable allocation, copy, and repeated scan), skipping micro-tuning (KTD10); record that evidence is static. + 2. Concurrency and async rows: replace blocking work on the executor with the house bounded-worker or async equivalents the lint vocabulary names; prefer removing a banned call over adding an allowance, and where a baseline must move, move it in the same commit with the justification recorded (KTD6). + 3. Unsafe and macro rows: safety sections and invariant documentation, and macro hygiene or helper-module fixes the lanes name; the sanctioned unsafe sites stay as they are except where a lane proves an invariant is documentation-only. + 4. Test rows: repair toward behavioral assertions; delete only a re-verified incapable-to-fail test, after confirming the crate's layout obligations and sweeping its references (KTD9). + 5. Supply rows: drop or re-point dependencies with their `BUILD.bazel` dep lists in the same commit, and follow the repository's copied-workspace procedure when a mirrored crate's dependency set changes. + 6. Record this wave's policy-confirmed rows (the concurrency and test no-ops) as no-ops citing their policies (R14). + 7. Because this wave moves the guest lockfile, run the container lane (`make test-integration`) as part of its gate set. +- **Patterns to follow:** the sanctioned allow reasons in the provider-crate policy are the only acceptable per-site allowances; the dead-code lane is the local aid when visibility or dependency lists change. +- **Test scenarios:** + - The blocking census is unchanged, or its baseline moves in the same commit as the fix that required it, with the reason recorded. + - The async-gate inventory regenerates byte-stable after the wave, or records exactly the sites it moved. + - A repaired test fails when the behavior it now asserts is broken; a deleted test was re-verified incapable of failing and no gate or document still references it. + - A dependency drop leaves the workspace and the crate's Bazel dep list consistent, and a mirrored-crate dependency change refreshes the guest lock with the supply-chain and policy gates run. + - Unsafe sites this wave touches keep a documented safety justification; none is removed to silence a lint. + - Moving the guest lockfile leaves the container lane green. +- **Verification:** wave gate set green including the census, the security scan, and - for this wave - the container lane; ledger rows with outcomes; ratchet moves in the same commits as their triggers. + +### U5. Wave 4 - family consolidations + +- **Goal:** the cross-crate family clusters are applied: knowledge and helpers duplicated inside one family move to their canonical home. +- **Requirements:** R1-R5, R10, R11, R14. +- **Dependencies:** U2-U4 (the leaf surface they re-point must be settled). +- **Files:** the `family`-tagged rows of the `idiom`/`own`/`type`/`api`/`err`/`serde`/`obs`/`docs`/`perf`/`async`/`test` lenses, concentrated in the provider family and the credential family; `packages/xtask/src/provider_crate_policy.rs` ratchet rows that a move empties; `changelog.d/`. +- **Approach:** + 1. Re-verify each family row's prerequisite leaf state before applying it (R4): a canonical home that a skipped leaf row was to create means the family row escalates or stays open. + 2. Move the duplicated knowledge to the named canonical home and re-point every consumer; no shim, no re-export of the moved item from the old location. + 3. Delete the ratchet rows the moves empty in the same commit, and run the provider-crate layout check. + 4. Record this wave's policy-confirmed family rows as no-ops citing their policies (R14). +- **Patterns to follow:** the provider-toolkit module that already hosts the family's shared credential helpers; the ratchet tables state the exact signal each row requires, so an emptied row is removed rather than relaxed. +- **Test scenarios:** + - Each family's existing suite passes with the moved helper, and a consumer-crate test that exercises the moved path still passes through the new home. + - The provider-crate layout gate passes with the emptied ratchet rows deleted; no row is deleted while its signal still exists. + - A family row whose prerequisite was skipped is recorded as escalated rather than half-applied. +- **Verification:** wave gate set green; ledger rows for each family row; ratchet diffs present in the same commits. + +### U6. Wave 5 - wide cross-crate classes + +- **Goal:** the cross-crate duplication classes are resolved once, at the canonical home the audit names. +- **Requirements:** R1-R5, R10, R11, R14. +- **Dependencies:** U5 (family homes settled), and the leaf waves for the sites it touches. +- **Files:** the sites the audit's cross-crate lane names, across the provider family, the contracts family, the daemon and its runtime, the broker, and the resource crates; `changelog.d/`. +- **Approach:** + 1. Apply each class as one change over all its member sites or none; where a member site's fix is a wire-shape move, that member escalates to U7 (R4); where the class's canonical home is itself a family row from U5, cite it rather than re-deriving it. + 2. Record this wave's policy-confirmed wide rows as no-ops citing their policies (R14). +- **Patterns to follow:** the audit's cross-crate lane names the class, its member sites, and the canonical home; the current tree's contract types are the authority for what a shared shape must look like. +- **Test scenarios:** + - Each class's member sites are all changed together, and the workspace builds; a partially applied class is recorded rather than left half-done. + - The class's canonical home is exercised by at least one test from a consumer crate that previously duplicated it. +- **Verification:** wave gate set green; ledger rows naming the class, its sites, and any escalated member. + +### U7. Wave 6 - needs-contract surface moves + +- **Goal:** the findings that change a published surface land with the whole surface: schema, emitter, prose, version, and pins. +- **Requirements:** R6, R7, R10, R11, plus the finding-level requirements they carry. +- **Dependencies:** U2-U6 (their wire-touching rows escalate here). +- **Files:** the `needs-contract` rows across the `type`/`api`/`err`/`serde` lenses and any escalated wide member; the contracts crates and their schemas, `docs/reference/error-codes.md`, `docs/reference/cli-contract.md`, `docs/reference/manifest-schema.md`, `tests/golden/**`, the pinning tests the lanes name, `packages/xtask/src/` generator modules when a generator input moves, `changelog.d/`. +- **Approach:** + 1. For each row, enumerate its full surface before editing: the type or schema, the emitter, the reference prose, `manifestVersion`, the pinning golden test, and the fixture data. + 2. Change the surface in one commit per row group and run the generator aggregate; the drift gate proves committed equals regenerated. + 3. Update the hand-held goldens and the version-coupled pinning tests with the schema change, not after it. +- **Patterns to follow:** the version-coupled golden tests already in the tree move with the schema version; the generated reference documents are regenerated rather than hand-edited. +- **Test scenarios:** + - The drift gate is green: committed generated artifacts equal freshly regenerated output. + - A frozen wire-string test moves with the shape change, and its crate's contract tests pass. + - A manifest-shaped change moves the schema version and the pinning test together, with the reference prose updated in the same commit. + - Fixture-backed contract tests pass against the updated fixtures. +- **Verification:** wave gate set green; every row's ledger entry names the surfaces it moved; no hand-edited generated file. + +### U8. Close-out - reconciliation, acceptance, and the pull request + +- **Goal:** every finding is accounted for, both integration lanes are green, and the reviewed pull request carries the work. +- **Requirements:** R1, R8, R9, R12, R13. +- **Dependencies:** U1-U7. +- **Files:** the ledger, `changelog.d/`, and the pull request. +- **Approach:** + 1. Confirm every policy-confirmed row was recorded as a no-op with its policy citation before reconciling, then reconcile the ledger against the audit's per-lens cluster lists: every finding id appears exactly once with an outcome, and any id that cannot be explained is hunted before close-out. + 2. Run final acceptance - both integration lanes - on the frozen head, after the last wave gate. + 3. Write the changelog fragment for the branch, without finding identifiers, and open the pull request with validation evidence; the independent review pass runs on that head against the ledger's finding-to-diff map, wave by wave. +- **Patterns to follow:** the ledger row schema from U1; the repository's changelog fragment shape for a branch; the pull request body records the change and validation evidence only. +- **Test scenarios:** + - Ledger reconciliation reports zero unaccounted and zero duplicated finding ids. + - Both integration lanes pass on the head the review covers; a failure after review is treated as a head change and re-enters the reviewed-head lifecycle. + - The changelog fragment contains no finding identifier and validates under the changelog gate. + - Every policy-confirmed row is recorded with its citation, and an escalated row carries its escalation history and its final outcome. +- **Verification:** the ledger is complete; final acceptance evidence is recorded; the pull request exists with the review verdict attached to its head. + +--- + +## Verification Contract + +| gate | what it proves | when | +| --- | --- | --- | +| `make check` | Layer-1 aggregate: every crate's tests and per-crate clippy under `-Dwarnings`, doctests, fixture contracts, policy suite (async gate, provider-crate layout, drift, changelog), flake and nix-unit lanes | end of every wave (R10) | +| `make test-host-integration` | the NixOS VM lane against the Bazel-staged host-tool bundle: live daemon, broker, socket activation, host posture | end of every wave (R10, KTD3) | +| `make check-census` | the blocking-API census against its committed baselines, including the no-new-blocking-API guard | end of every wave (R10, KTD3) | +| `tests/tools/security-scan.sh` (local run against the wave base) | the identifier-in-log rule on the wave's added lines | end of every wave (R10, KTD3) | +| `make test-integration` | the container lane: static binaries on a foreign non-Nix userland | the wave that moves the guest lockfile (U4) and final acceptance (R12) | +| ledger reconciliation | every finding id accounted exactly once with an outcome | close-out (R1, U8) | +| independent `ce-code-review mode:agent` on the final head | the repository's mandatory review evidence, bound to the reviewed head | before merge (R13) | + +## Definition of Done + +- Every one of the audit's findings is applied, or recorded with evidence as skipped-stale, already-fixed, escalated, reclassified, or policy-confirmed; no finding is silently dropped and none is applied without re-verification. +- Each wave's gate set (R10) is green before the next wave starts; residual failures are attributed to the wave-0 baseline with recorded evidence, and any baseline-attributed failure that later blocks close-out has an owner recorded in the ledger. +- Ratchet surfaces moved by the fixes were moved in the same commits, and the contract-surface changes shipped with their schema, emitter, prose, version, and pins together. +- The audit report and lane files are byte-unchanged; the ledger is complete and lives in the audit directory. +- Final acceptance ran both integration lanes on the reviewed head, and the pull request carries review evidence for that head. +- No finding identifier leaked outside the audit directory: not into source, doc comments, commits, changelog fragments, or the pull request body. + +--- + +## Appendix + +### Wave to cluster map + +Counts are the audit's own cluster membership (`README.md` section 6); each wave executes the lane files behind them. + +| wave | lenses and clusters | findings | +| --- | --- | ---: | +| U1 | cross-cutting: the 13 `high` rows - 8 leaf (7 actionable plus the policy-confirmed row recorded as a no-op), 2 family (the driver-args class, applied at its panicking member and escalated for the remaining sites), 3 wide | 13, a subset | +| U2 | `docs` 139 + `idiom` 122 + `own` 107, leaf, actionable | 368 | +| U3 | `type` 59 + `api` 107 + `err` 79 + `serde` 23 + `obs` 30, leaf, actionable | 298 | +| U4 | `perf` 48 + `conc` 19 + `async` 12 + `unsafe` 4 + `macro` 4 + `test` 63 + `supply` 17, leaf, actionable | 167 | +| U5 | every `family` cluster, actionable rows (2 further family rows are `needs-contract`, 2 are no-ops) | 70 | +| U6 | every `wide` cluster, actionable rows (11 further wide rows are `needs-contract`, 2 are no-ops) | 20 | +| U7 | all `needs-contract` rows: leaf 12, family 2, wide 11 | 25 | +| U8 | close-out; applies no findings | 0 | +| recorded no-op | `policy-confirmed` rows recorded by their owning wave: leaf 13 (U1 one, U3 four, U4 eight), family 2 (U5), wide 2 (U6) | 17 | +| **total** | | **965** | + +### Sources + +- Audit report, lane files, lane contract, and independent verification: `docs/audits/2026-09-24-rust-skills-audit/` (report sections 2, 6, 7 are the finding corpus, the cluster map, and the verification record). +- Gate authority: `Makefile`, `docs/contributing/gates-and-lints.md`, `tests/AGENTS.md`, `.github/workflows/pr-l1-static-fast.yml`. +- Policy surfaces that fail closed: `Cargo.toml` (`disallowed_methods` is live `deny`; the `clippy.toml` comment claiming `allow` is stale), `clippy.toml`, `packages/xtask/data/async-gate-inventory.json`, `packages/xtask/data/blocking-census-baseline.json`, `packages/xtask/src/provider_crate_policy.rs`, `docs/explanation/over-engineering-audit-record.md`. +- Landing lifecycle: `docs/contributing/workflow.md` (worktrees, reviewed-head lifecycle, security scan gate), `docs/contributing/changelog-and-commits.md`, `changelog.d/README.md`. +- Prior executed remediation to mirror for commit and ledger shape: `docs/plans/2026-09-24-001-refactor-ponytail-remediation-plan.md`, whose remediation-outcomes section landed in `docs/explanation/over-engineering-audit-record.md`. From 68bfd930b16f6a1f62fa79892d05c38e0295f6fb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:25:45 -0700 Subject: [PATCH 002/726] audit: add the remediation ledger with one row per finding The ledger carries every finding id with its lens, cluster, severity, audit verdict, and blast radius from the corpus clusters, plus empty outcome columns the waves fill in: outcome, wave, commit, apply-time anchor, reason or policy citation, and escalation history. The baseline gate table records the KTD3 gate set at the untouched head. --- .../2026-09-24-rust-skills-audit/ledger.md | 988 ++++++++++++++++++ 1 file changed, 988 insertions(+) create mode 100644 docs/audits/2026-09-24-rust-skills-audit/ledger.md diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md new file mode 100644 index 000000000..d02ca007c --- /dev/null +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -0,0 +1,988 @@ +# Rust skills remediation ledger + +Baseline: branch `refactor-rust-skills-remediation`, base commit `147a536a0` (the audit baseline `v3` @ `6ebdd4cec` plus the audit corpus commit). Authority: `docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md` (R1-R14, KTD1-KTD11). Corpus: `README.md` and `lane/`. + +One row per finding id. `outcome` is filled by the owning wave when it disposes of the row: `applied`, `applied-variant` (the stated fix held but needed a minimal correction), `already-fixed` (claim re-verified stale at HEAD), `escalated` (moved to the owning wave named in `escalation`), `policy-confirmed` (recorded no-op citing its policy), `needs-contract` (deferred to the contract-adjacent wave), `reclassified` (severity/verdict changed on re-verification, reason recorded). `anchor` is the apply-time anchor when the wave re-located it; the seed anchor comes from the corpus row. Empty cells mean the row is not yet disposed. + +Every id must appear exactly once and end `applied`, `already-fixed`, `policy-confirmed`, or `needs-contract` at close-out; `escalated` rows carry the escalation history and their final outcome (R1, KTD1). + +## Baseline record (gate set at the untouched head) + +Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit message for the recorded result. + +| gate | command | result at baseline | attribution | +| --- | --- | --- | --- | +| security scan | `D2B_SCAN_BASE_SHA=6ebdd4cec tests/tools/security-scan.sh` | pending | - | +| blocking census | `make check-census` | pending | - | +| Layer-1 aggregate | `make check` | pending | - | +| host integration | `make test-host-integration` | pending | - | + +## Findings (965 rows) + +| id | lens | cluster | sev | audit verdict | blast/effort | outcome | wave | commit | anchor | reason or policy citation | escalation | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| `RS-0037` | `idiom` | `d2b` | medium | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:688-706, packages/d2b/src/dispatch.rs:1169-1175` | | | +| `RS-0031` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/doctor.rs:529, packages/d2b/src/doctor.rs:579, packages/d2b/src/doctor.rs` | | | +| `RS-0036` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_doctor.rs:598-601` | | | +| `RS-0032` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/resource.rs:525, packages/d2b/src/resource.rs:546, packages/d2b/src/resou` | | | +| `RS-0033` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_audit.rs:805, packages/d2b/src/zone_audit.rs:838` | | | +| `RS-0034` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_audit.rs:349, packages/d2b/src/zone_audit.rs:395` | | | +| `RS-0035` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_audit.rs:591, packages/d2b/src/zone_audit.rs:607` | | | +| `RS-0001` | `idiom` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:255, packages/d2b-audit/src/segment.rs:980, packages/d2b-` | | | +| `RS-0002` | `idiom` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:103` | | | +| `RS-0003` | `idiom` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/sink.rs:393, packages/d2b-audit/src/sink.rs:403` | | | +| `RS-0011` | `idiom` | `d2b-broker` | medium | actionable | leaf | | | | `src/ops/device_worker.rs:312-335, src/ops/device_worker.rs:339-369, src/ops/device_worker.` | | | +| `RS-0006` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/runtime.rs:10392, packages/d2b-broker/src/runtime.rs:10418, packag` | | | +| `RS-0007` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/runtime.rs:10132` | | | +| `RS-0008` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:2816-2820` | | | +| `RS-0009` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/exec_reconcile.rs:404, src/ops/exec_reconcile.rs:505, src/ops/exec_reconcile.rs:55` | | | +| `RS-0010` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/store_view_farm.rs:97-190, src/ops/store_view_farm.rs:228-300` | | | +| `RS-0012` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:424-464, src/envelope/mod.rs:466-493, src/envelope/mod.rs:540-565, src` | | | +| `RS-0004` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:136` | | | +| `RS-0005` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:270, packages/d2b-broker-composition/src/seam.` | | | +| `RS-0013` | `idiom` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1773-1781` | | | +| `RS-0014` | `idiom` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/operations.rs:302-310` | | | +| `RS-0015` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/kernel_client.rs:225-227` | | | +| `RS-0016` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broke` | | | +| `RS-0017` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/` | | | +| `RS-0018` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential.rs:362, packages/d2b-contracts-provider/` | | | +| `RS-0020` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573, packages/` | | | +| `RS-0019` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:2374` | | | +| `RS-0022` | `idiom` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume.rs:1210-1213, packages/d2b-contracts-resourc` | | | +| `RS-0021` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src` | | | +| `RS-0023` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/resource.rs:621-626` | | | +| `RS-0024` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223` | | | +| `RS-0025` | `idiom` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `src/v3/component_session.rs:1935, src/v3/component_session.rs:1976` | | | +| `RS-0027` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1805, packages/d2b-core/src/bundle_resolver.rs:19` | | | +| `RS-0030` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/static_invariants.rs:162, packages/d2b-core/src/static_invariants.rs` | | | +| `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:5746` | | | +| `RS-0029` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2434, packages/d2b-core/src/processes.rs:180` | | | +| `RS-0026` | `idiom` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:2189-2192, authority.rs:2542-2545` | | | +| `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provid` | | | +| `RS-0039` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:2812, src/policy.rs:12` | | | +| `RS-0041` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboa` | | | +| `RS-0038` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:1131` | | | +| `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-pro` | | | +| `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provi` | | | +| `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:379-386, packages/d2b-provider-config-nixo` | | | +| `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | | | | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-e` | | | +| `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:446, packages/d2b-provider-cred` | | | +| `RS-0047` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/authority.rs:401, packages/d2b-provider-device-gpu/sr` | | | +| `RS-0048` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/effects_service.rs:193` | | | +| `RS-0049` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/authority.rs:17, packages/d2b-provider-device-gpu/src` | | | +| `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/driver.rs:380-390` | | | +| `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `swtpm_argv.rs:160, lib.rs:63, lib.rs:65` | | | +| `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `driver.rs:267-281` | | | +| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:1442, src/spec.rs:385` | | | +| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:620, packages/d2b-provid` | | | +| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/controller.rs:464, src/process.rs:402, src/process.rs:676` | | | +| `RS-0054` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1272, packages/d2b-provi` | | | +| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:790, packages/d2b-provid` | | | +| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:150` | | | +| `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provid` | | | +| `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/effects_service.rs:50-60, packages/d2b-provider-endpoin` | | | +| `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/endpoint.rs:395-398` | | | +| `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/bootstrap.rs:138, src/bootstrap.rs:124` | | | +| `RS-0063` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `controller.rs:1712, controller.rs:1744` | | | +| `RS-0064` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `controller.rs:1722, controller.rs:1860, controller.rs:2042` | | | +| `RS-0065` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:487-494, shutdown.rs:666-673` | | | +| `RS-0066` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `bootstrap_graph.rs:131-139, bootstrap_graph.rs:417-422` | | | +| `RS-0067` | `idiom` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/config.rs:93, packages/d2b-provider-guest-qemu-` | | | +| `RS-0068` | `idiom` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/test_support.rs:185` | | | +| `RS-0069` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/controller.rs:298-302` | | | +| `RS-0070` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/driver.rs:377-393` | | | +| `RS-0071` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:660-675` | | | +| `RS-0072` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/descriptor.rs:43-44, packages/d2b-provider-` | | | +| `RS-0073` | `idiom` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-pro` | | | +| `RS-0074` | `idiom` | `d2b-provider-seccomp-profile` | low | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-sec` | | | +| `RS-0075` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/systemd.rs:840` | | | +| `RS-0076` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor` | | | +| `RS-0077` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/user.rs:75, src/user.rs:76` | | | +| `RS-0078` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/user.rs:232` | | | +| `RS-0079` | `idiom` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:926-941, packages/d2b-provider-toolkit/src/` | | | +| `RS-0080` | `idiom` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:545-597, packages/d2b-provider-toolkit/src/` | | | +| `RS-0081` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239, packages/d2b` | | | +| `RS-0082` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/auth.rs:249-253` | | | +| `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:221-224` | | | +| `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:607-609` | | | +| `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/status.rs:33-38` | | | +| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | +| `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, pa` | | | +| `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/manager_backend/tests.rs:1045, packages/d2b-resource-api/src` | | | +| `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:914, packages/d2b-resource-client/src/proc` | | | +| `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:194, packages/d2b-resource-client/src/zone` | | | +| `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:` | | | +| `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2402` | | | +| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:1724` | | | +| `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:1913` | | | +| `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:882, packages/d2b-resource-runtime/src/resour` | | | +| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:732, packages/d2b-resource-runtime/src/guest_t` | | | +| `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:1419, packages/d2b-resource-runtime/src/manag` | | | +| `RS-0098` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:581-584` | | | +| `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:83-88, packages/d2b-resource-runtime/src/s` | | | +| `RS-0100` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1802, engine.rs:1803, engine.rs:1807` | | | +| `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:1593, admission.rs:956, admission.rs:958` | | | +| `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/config.rs:178` | | | +| `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/systemd.rs:260, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/resolver.rs:144` | | | +| `RS-0105` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/service.rs:311` | | | +| `RS-0106` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, pa` | | | +| `RS-0108` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:14699, packages/d2bd/src/composition.rs:14710, packages/d` | | | +| `RS-0109` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20450-20461, packages/d2bd/src/composition.rs:20486-20498` | | | +| `RS-0111` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_lifecycle.rs:78, packages/d2bd/src/resource_plane_v3.rs:2226` | | | +| `RS-0112` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/effect_service_actors.rs:268, packages/d2bd/src/effect_service_actors.rs` | | | +| `RS-0113` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:672, packages/d2bd/src/shared_provider_effects.rs:` | | | +| `RS-0107` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:6896` | | | +| `RS-0110` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:21306-21319, packages/d2bd/src/composition.rs:21291` | | | +| `RS-0114` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `autostart.rs:228-245` | | | +| `RS-0115` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:789, packages/d2bd-runtime/src/unix_trans` | | | +| `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/guest_mode.rs:849, packages/d2bd-runtime/src/guest_component_ses` | | | +| `RS-0117` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:162` | | | +| `RS-0118` | `idiom` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:147, packages/xtask/src/gen_layer_catalogs.rs:158` | | | +| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.` | | | +| `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_author` | | | +| `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/nix_inventories.rs:721` | | | +| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473` | | | +| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:459` | | | +| `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:6662, packages/xtask/src/provider_crate_policy` | | | +| `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | | | +| `RS-0150` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:548, packages/d2b/src/debug.rs:472, packages/d2b/src/debug.rs` | | | +| `RS-0151` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:977` | | | +| `RS-0152` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:296-313, packages/d2b/src/dispatch.rs:347, packages/d2b/src/d` | | | +| `RS-0149` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/doctor.rs:1062, packages/d2b/src/doctor.rs:1069, packages/d2b/src/doctor.` | | | +| `RS-0125` | `own` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/operation.rs:79` | | | +| `RS-0129` | `own` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/pidfd.rs:210` | | | +| `RS-0131` | `own` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:220` | | | +| `RS-0130` | `own` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:671` | | | +| `RS-0126` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:251, packages/d2b-broker-composi` | | | +| `RS-0127` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:272` | | | +| `RS-0128` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:340, packages/d2b-broker-composi` | | | +| `RS-0132` | `own` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:480, packages/d2b-bus/src/router.rs:2928` | | | +| `RS-0133` | `own` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/session/prologue.rs:72-78` | | | +| `RS-0134` | `own` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/session/contract.rs:1046-1056, packages/d2b-bus/src/session/zone_link` | | | +| `RS-0137` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:497, packages/d2b-contracts-pro` | | | +| `RS-0135` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:2497, packages/d2b-contracts-provider/s` | | | +| `RS-0138` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:1591, packages/d2b-contrac` | | | +| `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:2438, packages/d2b-contracts-provider/s` | | | +| `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume_state.rs:138` | | | +| `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `zone_routing.rs:883` | | | +| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | +| `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `resource_bundle.rs:944, resource_bundle.rs:149` | | | +| `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | +| `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `services.rs:216` | | | +| `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/static_invariants.rs:201` | | | +| `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1973, packages/d2b-core/src/bundle_resolver.rs:33` | | | +| `RS-0145` | `own` | `d2b-core-controller` | low | actionable | leaf | | | | `owner_reconcile.rs:1072-1075` | | | +| `RS-0146` | `own` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:2803, authority.rs:2806` | | | +| `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/t` | | | +| `RS-0154` | `own` | `d2b-provider` | low | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304` | | | +| `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | | | +| `RS-0156` | `own` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:111, packages/d2b-provider-config-nixos/sr` | | | +| `RS-0157` | `own` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/t` | | | +| `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:272, packages/d2b-provider-device-gpu/s` | | | +| `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `resource_controller.rs:233, resource_controller.rs:247, effects_service.rs:280, effects_se` | | | +| `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `broker.rs:194-208, broker.rs:218-232, broker.rs:313-321, broker.rs:333-341` | | | +| `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provid` | | | +| `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/driver.rs:981` | | | +| `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/ef` | | | +| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:156-157` | | | +| `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:500-501` | | | +| `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:527` | | | +| `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:417-419, src/controller.rs:469-471` | | | +| `RS-0168` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:892, src/controller.rs:903` | | | +| `RS-0169` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/effects.rs:450-464` | | | +| `RS-0170` | `own` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:791, src/bootstrap.rs:42` | | | +| `RS-0171` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:640, src/controller/mod.rs:764` | | | +| `RS-0172` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:852` | | | +| `RS-0173` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:1046` | | | +| `RS-0174` | `own` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266` | | | +| `RS-0175` | `own` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266` | | | +| `RS-0176` | `own` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/controller.rs:416-417` | | | +| `RS-0177` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:1033, packages/d2b-provider-n` | | | +| `RS-0178` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/lifecycle.rs:338, packages/d2b-provider-not` | | | +| `RS-0179` | `own` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285` | | | +| `RS-0180` | `own` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1988, packages/d2b-provider-process/src/driver` | | | +| `RS-0181` | `own` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/operations.rs:1354, packages/d2b-provider-process/src/op` | | | +| `RS-0182` | `own` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:355, src/driver.rs:478, src/driver.rs:522` | | | +| `RS-0183` | `own` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:360, src/driver.rs:435` | | | +| `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | | | | `src/service/supervisor.rs:599, src/service/supervisor.rs:601` | | | +| `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/host.rs:466, src/host.rs:467` | | | +| `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | +| `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | | | +| `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/runtime.rs:530-537` | | | +| `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:771` | | | +| `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:190-198, packages/d2b` | | | +| `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:267-277, packages/d2b-` | | | +| `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | | | | `packages/d2b-provider-user/src/effects_service.rs:179, packages/d2b-provider-user/src/effe` | | | +| `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:337` | | | +| `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | | | | `driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.` | | | +| `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | | | | `packages/d2b-provider-volume-binding/src/row_readers.rs:38-44` | | | +| `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/sr` | | | +| `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1526` | | | +| `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:425, client.rs:110, service.rs:852` | | | +| `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/admission.rs:338, packages/d2b-resource-api/src/admission.rs` | | | +| `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | | | | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | | | +| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | | | | `packages/d2b-resource-compiler/src/linux.rs:93, packages/d2b-resource-compiler/src/linux.r` | | | +| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:1148, packages/d2b-resource-compiler/src/main.r` | | | +| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:1467, packages/d2b-resource-compiler/src/main.r` | | | +| `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:269, packages/d2b-resource-compiler/src/main.rs` | | | +| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:704` | | | +| `RS-0206` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:205` | | | +| `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:520-541` | | | +| `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/resource.rs:714, packages/d2b-resource-runtime/src/resou` | | | +| `RS-0210` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:596-598` | | | +| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/metadata.rs:191` | | | +| `RS-0211` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:655, packages/d2b-resource-runtime/src/target.` | | | +| `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:1004-1009` | | | +| `RS-0213` | `own` | `d2b-session` | low | actionable | family | | | | `engine.rs:689, admission.rs:593` | | | +| `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83` | | | +| `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/engine.rs:345, packages/d2b-zone-routing/src/engine.rs:346` | | | +| `RS-0221` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_compositi` | | | +| `RS-0222` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:4057` | | | +| `RS-0216` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:359` | | | +| `RS-0218` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20404` | | | +| `RS-0217` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:181, packages/d2bd/src/resource_runtime.rs:4625, pac` | | | +| `RS-0219` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:21091` | | | +| `RS-0223` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:456, packages/d2bd/src/forward_rendezvous.rs:458-4` | | | +| `RS-0220` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20638` | | | +| `RS-0224` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:690, packages/d2bd/src/shared_provider_effect` | | | +| `RS-0225` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `dag.rs:423-424` | | | +| `RS-0226` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:625, packages/d2bd-runtime/src/unsafe_loc` | | | +| `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:250, packages/d2bd-runtime/src/console_sessio` | | | +| `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/daemon_audit.rs:976, packages/d2bd-runtime/src/daemon_audit.rs:1` | | | +| `RS-0231` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:577, packages/xtask/src/provider_crate_policy.` | | | +| `RS-0236` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/production_closure.rs:263, packages/xtask/src/production_closure.rs:379` | | | +| `RS-0238` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287` | | | +| `RS-0232` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:5200, packages/xtask/src/provider_crate_policy` | | | +| `RS-0237` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/production_closure.rs:383, packages/xtask/src/production_closure.rs:386` | | | +| `RS-0234` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_packaging.rs:163, packages/xtask/src/provider_packaging.rs:206` | | | +| `RS-0233` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:844, packages/xtask/src/gen_broker_operations.` | | | +| `RS-0235` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/semantic_service_schemas.rs:32, packages/xtask/src/semantic_service_sch` | | | +| `RS-0229` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:7257` | | | +| `RS-0230` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:6375, packages/xtask/src/provider_crate_policy` | | | +| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | | | +| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_` | | | +| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | +| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_op` | | | +| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | | | +| `RS-0263` | `type` | `d2b` | low | actionable | leaf | | | | `context.rs:713, context.rs:2751, context.rs:801` | | | +| `RS-0264` | `type` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/exec.rs:90, packages/d2b/src/exec.rs:345, packages/d2b/src/endpoint.rs:34` | | | +| `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | | | | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | | | +| `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:889-892` | | | +| `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_co` | | | +| `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362` | | | +| `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/session/zone_link.rs:111-117` | | | +| `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:218-219, packages/d2b-bus/src/router.rs:298-337` | | | +| `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1445-1446, packages/d2b-bus/src/router.rs:1667-1674` | | | +| `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broke` | | | +| `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2805, packages/d2b-contracts-broker/src/b` | | | +| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | | | | `public_wire.rs:2166, public_wire.rs:2203` | | | +| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | | | +| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:316, public_wire.rs:311` | | | +| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | +| `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | | | +| `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:1333, packages/d2b-contracts-provider/s` | | | +| `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-res` | | | +| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | +| `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-r` | | | +| `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resou` | | | +| `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `role_binding.rs:179-182, role_binding.rs:149-162` | | | +| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | | | | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | +| `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/manifest_v04.rs:313` | | | +| `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:985-988` | | | +| `RS-0262` | `type` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | | | +| `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:387, packages/d2b-process-conformance/src/t` | | | +| `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, sr` | | | +| `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199` | | | +| `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:140, src/bin/d2b-clipd.rs:142` | | | +| `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider` | | | +| `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipb` | | | +| `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard` | | | +| `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixo` | | | +| `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-credential/src/d` | | | +| `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | | | | `controller.rs:85-89, tests/binding.rs:1214-1234` | | | +| `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:79, packages/d2b-provider-device-gpu/sr` | | | +| `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | +| `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | | | | `src/effects.rs:394-406` | | | +| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | | | +| `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/bootstrap.rs:65, src/bootstrap.rs:82` | | | +| `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:82, src/controller/mod.rs:982` | | | +| `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `identity.rs:857-865, controller.rs:1808-1818` | | | +| `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | +| `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `bootstrap_graph.rs:142-176, controller.rs:662-670` | | | +| `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417, packages/d2b-contracts-reso` | | | +| `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/config.rs:89, packages/d2b-provider-guest-qemu-` | | | +| `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-` | | | +| `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:56, agent.rs:265, agent.rs:297` | | | +| `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | | | | `packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minij` | | | +| `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lifecycle.rs:78, packages/d2b-provider-process-s` | | | +| `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/metrics.rs:7, packages/d2b-provider-process-syst` | | | +| `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry` | | | +| `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telem` | | | +| `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-p` | | | +| `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/identity.rs:72-88, src/identity.rs:146-150` | | | +| `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:124` | | | +| `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs` | | | +| `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | | | | `scheduler.rs:18-21, scheduler.rs:66-68` | | | +| `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1702, engine.rs:1295, engine.rs:31` | | | +| `RS-0299` | `type` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0303` | `type` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:18659, packages/d2bd/src/composition.rs:18608` | | | +| `RS-0305` | `type` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:1299, packages/d2bd/src/shared_provider_effec` | | | +| `RS-0302` | `type` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:16152, packages/d2bd/src/composition.rs:16155, packages/d` | | | +| `RS-0300` | `type` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:3041, packages/d2bd/src/resource_runtime.rs:3230, pa` | | | +| `RS-0301` | `type` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:1014, packages/d2bd/src/resource_runtime.rs:7614` | | | +| `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d` | | | +| `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | | | | `resource_operator_activation.rs:129-182, resource_operator_activation.rs:163-177` | | | +| `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | | | | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | | | +| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | | | | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | +| `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | | | | `admission.rs:107-108, admission.rs:66, admission.rs:83` | | | +| `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | | | | `component_session_vsock.rs:32-36` | | | +| `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/typed_shell_targets.rs:13, packages/d2bd-runtime/src/typed_shell` | | | +| `RS-0314` | `type` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557` | | | +| `RS-0313` | `type` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:5104, packages/xtask/src/provider_crate_policy` | | | +| `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | +| `RS-0312` | `type` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:288, packages/xtask/src/gen_layer_catalogs.rs:515` | | | +| `RS-0952` | `api` | `X2-generated-boundary` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/generated/mod.rs:3-4, packages/xtask/src/main.rs:355-370, pa` | | | +| `RS-0953` | `api` | `X2-generated-boundary` | low | actionable | leaf | | | | `packages/d2b-audit/src/lib.rs:7, packages/xtask/src/gen_layer_catalogs.rs:725, packages/d2` | | | +| `RS-0965` | `api` | `X3-cross-crate-duplication` | low | actionable | family | | | | `packages/d2b-provider-device-usbip/src/lib.rs:24, packages/d2b-provider-seccomp-profile/sr` | | | +| `RS-0352` | `api` | `d2b` | medium | actionable | leaf | | | | `packages/d2b/src/host_generation.rs:7, packages/d2b/src/host_generation.rs:17, packages/d2` | | | +| `RS-0353` | `api` | `d2b` | low | actionable | leaf | | | | `zone_support_bundle.rs:19, zone_support_bundle.rs:28, zone_support_bundle.rs:99, zone_supp` | | | +| `RS-0354` | `api` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/lib.rs:25, packages/d2b/src/lib.rs:41, packages/d2b/src/doctor.rs:62, pac` | | | +| `RS-0316` | `api` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/lib.rs:16, packages/d2b-audit/src/lib.rs:30, packages/d2b-audit/src` | | | +| `RS-0319` | `api` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/sysctl.rs:16, packages/d2b-broker/src/ops/sysctl.rs:84` | | | +| `RS-0320` | `api` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/route.rs:19` | | | +| `RS-0318` | `api` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/gpu.rs:13, packages/d2b-broker/src/ops/gpu.rs:24, packages/d2b` | | | +| `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | | | | `src/lib.rs:45, src/ops/mod.rs:20-94` | | | +| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | | | +| `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/cgroup.rs:126-129, packages/d2b-broker/src/ops/cgroup.rs:343` | | | +| `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/kernel_ops.rs:99-100` | | | +| `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1208, packages/d2b-bus/src/router.rs:1224, packages/d2b-bus` | | | +| `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/authorization.rs:75, packages/d2b-bus/src/router.rs:1415-1416` | | | +| `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97` | | | +| `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114` | | | +| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | +| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | +| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | | | | `cli_output.rs:241, cli_output.rs:276` | | | +| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | | | | `cli_output.rs:6` | | | +| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | | | +| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | | | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | | | +| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | +| `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src` | | | +| `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/identity.rs:269-270` | | | +| `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `src/v3/resource_export.rs:97, src/v3/resource_export.rs:156, src/v3/resource_import.rs:86,` | | | +| `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `emergency_policy.rs:142, emergency_policy.rs:170` | | | +| `RS-0339` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `zone.rs:74` | | | +| `RS-0348` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-cor` | | | +| `RS-0345` | `api` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:620, packages/d2b-core/src/bundle_resolver.rs:641` | | | +| `RS-0349` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:1` | | | +| `RS-0346` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109` | | | +| `RS-0350` | `api` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/privileges.rs:741` | | | +| `RS-0347` | `api` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:24` | | | +| `RS-0340` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/binding_children.rs:173, packages/d2b-core-controller/src` | | | +| `RS-0341` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/controller_assignment.rs:2707, packages/d2b-core-controll` | | | +| `RS-0342` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/coordinator.rs:252, packages/d2b-core-controller/src/coor` | | | +| `RS-0343` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `authority.rs:80-128, authority.rs:167-211, authority.rs:258-335, authority.rs:1732` | | | +| `RS-0344` | `api` | `d2b-core-controller` | low | actionable | leaf | | | | `owner_reconcile.rs:579, owner_reconcile.rs:600, owner_reconcile.rs:697, owner_reconcile.rs` | | | +| `RS-0351` | `api` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/host_prep_dag.rs:85` | | | +| `RS-0355` | `api` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/lib.rs:52, packages/d2b-process-conformance/src/lib.r` | | | +| `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/process_provider.rs:6, packages/d2b-process-conforman` | | | +| `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testi` | | | +| `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/sandbox.rs:18, packages/d2b-process-conformance/src/s` | | | +| `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation` | | | +| `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:14, packages/d2b-provider-activat` | | | +| `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/authority.rs:157-171, src/controller.rs:395-403` | | | +| `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:746-748, src/lib.rs:32` | | | +| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | | | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | | | +| `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-cli` | | | +| `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | | | | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | | | +| `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/lib.rs:102, packages/d2b-provider-credential-en` | | | +| `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/lib.rs:446, packages/d2b-provider-credential-en` | | | +| `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:612-618` | | | +| `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | | | | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effe` | | | +| `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/lib.rs:12, packages/d2b-provider-device-gpu/src/lib.r` | | | +| `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-device-` | | | +| `RS-0372` | `api` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/lib.rs:16-17, packages/d2b-provider-device-s` | | | +| `RS-0373` | `api` | `d2b-provider-device-tpm` | medium | actionable | leaf | | | | `state.rs:6, state.rs:29, state.rs:51, state.rs:73` | | | +| `RS-0374` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:53, effects_service.rs:103, effects_service.rs:114` | | | +| `RS-0375` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:341` | | | +| `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `migration.rs:5, lib.rs:24` | | | +| `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `lib.rs:24, lib.rs:61-65` | | | +| `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `broker.rs:131-133` | | | +| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20` | | | +| `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/lib.rs:14` | | | +| `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/controller.rs:580` | | | +| `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12` | | | +| `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/lib.rs:14, src/effects.rs:8-9` | | | +| `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | | | | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | | | +| `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:211, packages/d2b-provider-guest/src/effects_service.rs:1186` | | | +| `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895` | | | +| `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:1361-1376, controller.rs:1907-1909` | | | +| `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | | | | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | | | +| `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `identity.rs:554-556, tests/controller.rs:206` | | | +| `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:576-578` | | | +| `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129, packages/d2b-provider-guest-qem` | | | +| `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111,` | | | +| `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/routes.rs:244-279, src/routes.rs:264-265` | | | +| `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:1019, packages/d2b-provider-n` | | | +| `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:110, packages/d2b-provider-no` | | | +| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1-3, packages/d2b-provi` | | | +| `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd` | | | +| `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lifecycle.rs:55, packages/d2b-provider-process-s` | | | +| `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd` | | | +| `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:215, src/driver.rs:229` | | | +| `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/providers.rs:121, src/lib.rs:19` | | | +| `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | | | | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | | | +| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | | | | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | | | +| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | | | | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | | | +| `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | | | | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | | | +| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | | | | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | +| `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2bd/src/process_provider_run` | | | +| `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | | | | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | | | +| `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | | | | `src/lib.rs:41, src/testing.rs:23` | | | +| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | | | | `src/host.rs:389, src/host.rs:13` | | | +| `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/lib.rs:40, src/ownership.rs:42` | | | +| `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/host.rs:419, src/host.rs:134` | | | +| `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/lib.rs:70` | | | +| `RS-0414` | `api` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:888, packages/d2b-provider-toolkit/src/base` | | | +| `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/server/service.rs:297-299, packages/d2b-provider-toolkit` | | | +| `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | +| `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | +| `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:491-497, packages/d2b` | | | +| `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343-347, packages/d2b` | | | +| `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | | | | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | | | +| `RS-0421` | `api` | `d2b-provider-volume-local` | medium | actionable | family | | | | `src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1` | | | +| `RS-0422` | `api` | `d2b-provider-zone` | medium | actionable | leaf | | | | `packages/d2b-provider-zone/src/lib.rs:9-10, packages/d2b-provider-zone/src/zone_status.rs:` | | | +| `RS-0423` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1783, packages/d2b-provider-zone-link/sr` | | | +| `RS-0424` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zonelink.rs:281` | | | +| `RS-0425` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zonelink.rs:178` | | | +| `RS-0426` | `api` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:251-256, adapter.rs:1208-1211` | | | +| `RS-0427` | `api` | `d2b-resource-api` | low | actionable | leaf | | | | `client.rs:98, service.rs:837` | | | +| `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | | | | `manager_backend.rs:81, manager_backend.rs:208, manager_backend.rs:227` | | | +| `RS-0429` | `api` | `d2b-resource-client` | medium | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:83, packages/d2b-resource-client/src/zone_` | | | +| `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | | | | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | +| `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:491-493` | | | +| `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:460-462` | | | +| `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | | | | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | | | +| `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | | | | `fragmentation.rs:10-13` | | | +| `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:166, engine.rs:262, engine.rs:416, engine.rs:356` | | | +| `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | | | | `packages/d2b-session-unix/src/socket.rs:176` | | | +| `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-sk-frontend/src/lib.rs:27, packages/d` | | | +| `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:398, packages/d2bd/src/composition.rs:400, packages/d2bd/` | | | +| `RS-0441` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2bd/src/resource_plane_v3.rs:3295, ` | | | +| `RS-0439` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/audio_host_controller.rs:59, packages/d2bd/src/audio_host_controller.rs:` | | | +| `RS-0440` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/audio_host_controller.rs:68, packages/d2bd/src/audio_host_controller.rs:` | | | +| `RS-0443` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_registry.rs:48, packages/d2bd/src/provider_registry.rs:288` | | | +| `RS-0444` | `api` | `d2bd-runtime` | medium | actionable | family | | | | `shell_backend.rs:52-53` | | | +| `RS-0446` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/exec_session.rs:900` | | | +| `RS-0445` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `public_read_model.rs:51-53` | | | +| `RS-0447` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:118` | | | +| `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:341, packages/d2bd-runtime/src/console_sessio` | | | +| `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:54` | | | +| `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:66, packages/d2bd-runtime/src/console_session` | | | +| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | | | +| `RS-0477` | `err` | `d2b` | medium | actionable | leaf | | | | `packages/d2b/src/host.rs:200, packages/d2b/src/resource.rs:916, packages/d2b/src/lib.rs:44` | | | +| `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | | | | `packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, ` | | | +| `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:230` | | | +| `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b` | | | +| `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | | | | `packages/d2b-broker/src/runtime.rs:2419, packages/d2b-broker/src/runtime.rs:2422` | | | +| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | | | +| `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-broker/src/ops/hosts.rs:149, packag` | | | +| `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360` | | | +| `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/exec_reconcile.rs:1238-1265` | | | +| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | | | +| `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/depen` | | | +| `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/wire.rs:49-56` | | | +| `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:2` | | | +| `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | | | | `public_wire.rs:1297` | | | +| `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider_registry.rs:186, packages/d2b-contracts-pr` | | | +| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | | | +| `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:1508, packages/d2b-contrac` | | | +| `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-pr` | | | +| `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:834, packages/d2b-contract` | | | +| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | +| `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | | | | `zone_session.rs:297, zone_session.rs:332` | | | +| `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2625, packages/d2b-broker/src/runtime.rs:6405` | | | +| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | | | | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | +| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | | | +| `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/site.rs:42` | | | +| `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1405, packages/d2b-core/src/bundle_resolver.rs:14` | | | +| `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:5730` | | | +| `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:412` | | | +| `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/launch_identity.rs:147` | | | +| `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activa` | | | +| `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/authority.rs:53-54, src/authority.rs:144-145` | | | +| `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/state.rs:114-123, src/controller.rs:155-160` | | | +| `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:3550, src/bin/d2b-clipd.rs:1754, src/bin/d2b-clipd.rs:2863` | | | +| `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:127, src/bin/d2b-clipd.rs:411, src/bin/d2b-clipd.rs:247` | | | +| `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clip` | | | +| `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provide` | | | +| `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixo` | | | +| `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:1261-1262` | | | +| `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | | | | `runner.rs:43, swtpm_argv.rs:104, lib.rs:35, tests/conformance.rs:11` | | | +| `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `state_machine.rs:378-386` | | | +| `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:740, src/controller.rs:741` | | | +| `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886` | | | +| `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:30, src/spec.rs:43` | | | +| `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:197, packages/d2b-provider-host/src/effects_servi` | | | +| `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:129, packages/d2b-provider-host/src/driver.rs:99` | | | +| `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/nftables.rs:588` | | | +| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | | | | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | | | +| `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-not` | | | +| `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `ingress_policy.rs:647` | | | +| `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/d` | | | +| `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/error.rs:5, packages/d2b-provider-process-system` | | | +| `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:419-421` | | | +| `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:888-890` | | | +| `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:304` | | | +| `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:386` | | | +| `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:186-187, packages/d2b-provider-test-cont` | | | +| `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-to` | | | +| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | +| `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | +| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | +| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | | | +| `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69-78, packages/d2b-pro` | | | +| `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-pro` | | | +| `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | | | | `packages/d2b-provider-user/src/driver.rs:118-124, packages/d2b-contracts/src/failure_kinds` | | | +| `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | | | | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-bindi` | | | +| `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-wayland` | | | +| `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | | | | `packages/d2b-provider-wayland-session/src/wayland_session.rs:73` | | | +| `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:867-868` | | | +| `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309` | | | +| `RS-0520` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/error.rs:773, packages/d2b-resource-runtime/src/manager.` | | | +| `RS-0521` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spe` | | | +| `RS-0522` | `err` | `d2b-session` | medium | actionable | leaf | | | | `transport.rs:170, transport.rs:178, transport.rs:185, transport.rs:173` | | | +| `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | | | | `client.rs:216, client.rs:224, client.rs:237` | | | +| `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | | | +| `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_` | | | +| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:8140, packages/d2bd-runtime/src/workload_dispatch.rs:104,` | | | +| `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:5365, packages/d2bd/src/interaction_compositi` | | | +| `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/resource_plane_v3.rs:3016, ` | | | +| `RS-0535` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/effect_service_actors.rs:551, packages/d2bd/src/effect_service_actors.rs` | | | +| `RS-0527` | `err` | `d2bd` | medium | actionable | family | | | | `packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511` | | | +| `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:22793-22797, packages/d2b-contracts-control/src/public_wi` | | | +| `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20185-20190` | | | +| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | | | | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | | | +| `RS-0534` | `err` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:1956` | | | +| `RS-0536` | `err` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:3436` | | | +| `RS-0528` | `err` | `d2bd` | low | actionable | family | | | | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | | | +| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | | | | `broker_transport.rs:63, broker_transport.rs:65` | | | +| `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | | | | `wire.rs:529-536` | | | +| `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/exec_session.rs:939` | | | +| `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:132` | | | +| `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/daemon_version.rs:77, packages/d2bd-runtime/src/daemon_version.r` | | | +| `RS-0543` | `err` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/delivery/recovery.rs:384, packages/xtask/src/delivery/recovery.rs:1610,` | | | +| `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | +| `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | | | +| `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composi` | | | +| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | | | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | | | +| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | | | +| `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | | | | `unsafe_local_wire.rs:118, unsafe_local_wire.rs:176, public_wire.rs:2228` | | | +| `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76, packages/d2b-contracts-provi` | | | +| `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | +| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | +| `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | | | | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | | | +| `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/storage_lifecycle.rs:49, packages/d2b-core/src/storage_lifecycle.rs:` | | | +| `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175` | | | +| `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:183, packages/d2b-core/src/bundle_resolver.rs:187` | | | +| `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | | | | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | | | +| `RS-0557` | `serde` | `d2b-host` | low | actionable | family | | | | `packages/d2b-host/src/nftables.rs:229` | | | +| `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/status.rs:125, packages/d2b-process-conformance/src/t` | | | +| `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/terminal.rs:39, packages/d2b-process-conformance/src/` | | | +| `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-` | | | +| `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | | | | `packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/comm` | | | +| `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/` | | | +| `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | | | +| `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:230, src/spec.rs:233, src/spec.rs:263` | | | +| `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/endpoint.rs:112-120, packages/d2b-provider-endpoint/src` | | | +| `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/driver.rs:282-289, src/driver.rs:190` | | | +| `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429` | | | +| `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generate` | | | +| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | | | | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-p` | | | +| `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264` | | | +| `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | | | | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | | | +| `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | | | | `src/content.rs:38-39, src/content.rs:106-107, src/content.rs:203-204, src/content.rs:239-2` | | | +| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | +| `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | | | | `manager_backend.rs:744-745` | | | +| `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:4196, packages/d2bd/src/composition.rs:4205` | | | +| `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d` | | | +| `RS-0577` | `serde` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:979-981` | | | +| `RS-0578` | `serde` | `d2bd-runtime` | low | actionable | leaf | | | | `wire.rs:265-353` | | | +| `RS-0579` | `serde` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/ch_api.rs:79` | | | +| `RS-0580` | `serde` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/service_catalog.rs:22, packages/xtask/src/provider_registration_authori` | | | +| `RS-0582` | `serde` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111` | | | +| `RS-0581` | `serde` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/resource_type_authority.rs:179, packages/xtask/src/resource_type_author` | | | +| `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:25` | | | +| `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1097` | | | +| `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activa` | | | +| `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100` | | | +| `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provide` | | | +| `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/service.rs:860` | | | +| `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:346, src/controller/mod.rs:425` | | | +| `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:352, packages/d2b-provi` | | | +| `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-system` | | | +| `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:33-47, packages/d2b-provider-test-contro` | | | +| `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:164, packages/d2b-provider-test-controll` | | | +| `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src` | | | +| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | | | +| `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-` | | | +| `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | | | | `packages/d2b-provider-transport-unix/src/portal.rs:217-220, packages/d2b-provider-transpor` | | | +| `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/service.rs:392, packages/d2b-provider-transport-` | | | +| `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/service.rs:735, packages/d2b-provider-transport-` | | | +| `RS-0600` | `obs` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:1992` | | | +| `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/protocol.rs:188` | | | +| `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:4081, packages/d2bd/src/composition.rs:4099, packages/d2b` | | | +| `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:4487, packages/d2bd/src/composition.rs:4538, packages/d2b` | | | +| `RS-0607` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_lifecycle.rs:1085` | | | +| `RS-0602` | `obs` | `d2bd` | low | actionable | leaf | | | `instrument` = 0), so the events lose the underlying error: most are inside `map_err` closu` | | | +| `RS-0603` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:14781` | | | +| `RS-0604` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:15195, packages/d2bd/src/composition.rs:15221` | | | +| `RS-0608` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:1250` | | | +| `RS-0609` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs` | | | +| `RS-0610` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680` | | | +| `RS-0611` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/readiness.rs:327` | | | +| `RS-0612` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132` | | | +| `RS-0613` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:450` | | | +| `RS-0659` | `docs` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/exec_client.rs:497, packages/d2b/src/exec_client.rs:507, packages/d2b/src` | | | +| `RS-0658` | `docs` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/doctor.rs:91, packages/d2b/src/doctor.rs:163, packages/d2b/src/host_valid` | | | +| `RS-0614` | `docs` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:74, packages/d2b-audit/src/record_types.rs:428, packages/` | | | +| `RS-0624` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/fd_passing.rs:13, packages/d2b-broker/src/fd_passing.rs:31-70` | | | +| `RS-0630` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:35, packages/d2b-broker/src/ops/media.rs:167-186, pac` | | | +| `RS-0625` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:120-121, packages/d2b-broker/src/sys.rs:185, packages/d2b-b` | | | +| `RS-0631` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/protocol.rs:13, packages/d2b-broker/src/protocol.rs:16, packages/d` | | | +| `RS-0632` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/state_dir.rs:47, packages/d2b-broker/src/ops/state_dir.rs:53, ` | | | +| `RS-0621` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/audit.rs:124, packages/d2b-broker/src/audit.rs:84, packages/d2b-br` | | | +| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | | | | `packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b` | | | +| `RS-0622` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/host_generation_handoff.rs:35` | | | +| `RS-0623` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/route.rs:29` | | | +| `RS-0615` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:81, packages/d2b-broker/src/ops/usbip_lock.rs:90` | | | +| `RS-0617` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_host.rs:17, packages/d2b-broker/src/ops/usbip_host.rs:15` | | | +| `RS-0626` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:258, packages/d2b-broker/src/sys.rs:268, packages/d2b-broke` | | | +| `RS-0618` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/sysctl.rs:32, packages/d2b-broker/src/ops/sysctl.rs:40, packag` | | | +| `RS-0619` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:21` | | | +| `RS-0620` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/pidfd.rs:112, packages/d2b-broker/src/ops/pidfd.rs:191, packag` | | | +| `RS-0627` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/store_view_farm.rs:66-72, src/ops/store_view_farm.rs:191-197` | | | +| `RS-0628` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:1118, src/envelope/mod.rs:1136, src/envelope/mod.rs:1187` | | | +| `RS-0629` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/nm.rs:293-301, src/ops/nm.rs:303-308` | | | +| `RS-0633` | `docs` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1126, packages/d2b-bus/src/router.rs:1135, packages/d2b-bus` | | | +| `RS-0637` | `docs` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/operations.rs:124-125` | | | +| `RS-0634` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:67-68` | | | +| `RS-0635` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1895, packages/d2b-bus/src/authorization.rs:401, packages/d` | | | +| `RS-0636` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:3709, packages/d2b-bus/src/router.rs:3261, packages/d2b-bus` | | | +| `RS-0638` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/streams.rs:39-40, packages/d2b-bus/src/operations.rs:24-25, packages/` | | | +| `RS-0639` | `docs` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src` | | | +| `RS-0640` | `docs` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/br` | | | +| `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130` | | | +| `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495` | | | +| `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wi` | | | +| `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | | | | `terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105` | | | +| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | +| `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:250, packages/d2b-contracts-provider/sr` | | | +| `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/` | | | +| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | | | +| `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/limits.rs:3, packages/d2b-contracts-resource/src/v3` | | | +| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | | | +| `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | | | | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | | | +| `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/manifest_v04.rs:1, packages/d2b-core/src/manifest_v04.rs:31, package` | | | +| `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2917, packages/d2b-core/src/bundle_resolver.rs:29` | | | +| `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controlle` | | | +| `RS-0653` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `migration.rs:54, migration.rs:58` | | | +| `RS-0656` | `docs` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/bridge_port.rs:127, packages/d2b-host/src/host_generation.rs:103, pa` | | | +| `RS-0657` | `docs` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/cgroup.rs:53, packages/d2b-host/src/cgroup.rs:71, packages/d2b-host/` | | | +| `RS-0660` | `docs` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/` | | | +| `RS-0661` | `docs` | `d2b-provider` | medium | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:270, packages/d2b-provider/src/descriptor.rs:232, packa` | | | +| `RS-0662` | `docs` | `d2b-provider-activation-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:711, packages/d2b-provider-activa` | | | +| `RS-0663` | `docs` | `d2b-provider-audio-binding` | low | actionable | leaf | | | | `packages/d2b-provider-audio-binding/src/audio_binding.rs:56, packages/d2b-provider-audio-b` | | | +| `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/state.rs:81-84, src/lib.rs:9-10` | | | +| `RS-0665` | `docs` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:21, src/controller.rs:209, src/controller.rs:212` | | | +| `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | | | +| `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | | | | `src/audit.rs:172, src/audit.rs:174` | | | +| `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | | | +| `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | | | +| `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | | | +| `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | | | | `packages/d2b-provider-command/src/command.rs:38, packages/d2b-provider-command/src/command` | | | +| `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/controller.rs:45-64, packages/d2b-provider-config-n` | | | +| `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/` | | | +| `RS-0674` | `docs` | `d2b-provider-credential-entra` | low | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/controller.rs:47, packages/d2b-provider-credent` | | | +| `RS-0675` | `docs` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:449, lib.rs:514, lib.rs:592, lib.rs:796` | | | +| `RS-0676` | `docs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-cred` | | | +| `RS-0677` | `docs` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-` | | | +| `RS-0678` | `docs` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:172, packages/d2b-provider-device-gpu/s` | | | +| `RS-0679` | `docs` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/gpu_argv.rs:24, packages/d2b-provider-device-gpu/src/` | | | +| `RS-0681` | `docs` | `d2b-provider-device-security-key` | medium | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/lease.rs:150-303, packages/d2b-provider-devi` | | | +| `RS-0680` | `docs` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/relay.rs:7, packages/d2b-provider-device-sec` | | | +| `RS-0682` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `resources.rs:53, swtpm_argv.rs:130, resource_controller.rs:132, resource_controller.rs:190` | | | +| `RS-0683` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `swtpm_argv.rs:39` | | | +| `RS-0684` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `reconcile_state.rs:6, state_machine.rs:61, lib.rs:9` | | | +| `RS-0685` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `arbitration.rs:76, busid.rs:12, broker.rs:61, controller.rs:210` | | | +| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/policy.rs:114, src/policy.rs:119` | | | +| `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provide` | | | +| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759` | | | +| `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/facets.rs:63, packages/d2b-provider-guest/src/target_contr` | | | +| `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/lib.rs:7, src/effects.rs:813-882` | | | +| `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:333, src/controller/mod.rs:446` | | | +| `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/bootstrap.rs:25` | | | +| `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `descriptor.rs:423-429, identity.rs:590-634` | | | +| `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs:82, packages/d2b-pro` | | | +| `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provide` | | | +| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | | | +| `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `lib.rs:13, lib.rs:14, lib.rs:15` | | | +| `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131` | | | +| `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | | | | `packages/d2b-provider-operation/src/operation.rs:138, packages/d2b-provider-operation/src/` | | | +| `RS-0700` | `docs` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/backend.rs:256, packages/d2b-provider-process/src/launch` | | | +| `RS-0701` | `docs` | `d2b-provider-process-minijail` | low | actionable | leaf | | | | `packages/d2b-provider-process-minijail/src/launch.rs:33, packages/d2b-provider-process-min` | | | +| `RS-0702` | `docs` | `d2b-provider-process-systemd` | medium | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lifecycle.rs:33, packages/d2b-provider-process-s` | | | +| `RS-0703` | `docs` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/providers.rs:72, src/providers.rs:79` | | | +| `RS-0704` | `docs` | `d2b-provider-role` | low | actionable | leaf | | | | `packages/d2b-provider-role/src/lib.rs:1, packages/d2b-provider-role/src/rbac.rs:11` | | | +| `RS-0705` | `docs` | `d2b-provider-seccomp-profile` | medium | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:31, packages/d2b-provider-sec` | | | +| `RS-0706` | `docs` | `d2b-provider-shell-terminal` | medium | actionable | leaf | | | | `src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/` | | | +| `RS-0707` | `docs` | `d2b-provider-system-core` | medium | actionable | leaf | | | | `src/host.rs:121, src/host.rs:161, src/user.rs:241` | | | +| `RS-0708` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/s` | | | +| `RS-0709` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolki` | | | +| `RS-0710` | `docs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/auth.rs:229-246, packages/d2b-provider-tra` | | | +| `RS-0711` | `docs` | `d2b-provider-transport-unix` | low | actionable | leaf | | | | `packages/d2b-provider-transport-unix/src/portal.rs:197-201, packages/d2b-provider-transpor` | | | +| `RS-0712` | `docs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsoc` | | | +| `RS-0713` | `docs` | `d2b-provider-volume-binding` | low | actionable | leaf | | | | `packages/d2b-provider-volume-binding/src/facets.rs:52, packages/d2b-provider-volume-bindin` | | | +| `RS-0714` | `docs` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92` | | | +| `RS-0715` | `docs` | `d2b-provider-zone` | low | actionable | leaf | | | | `packages/d2b-provider-zone/src/zone_status.rs:110-114` | | | +| `RS-0716` | `docs` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src` | | | +| `RS-0718` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, pa` | | | +| `RS-0717` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `service.rs:198, store.rs:39, adapter.rs:71, manager_backend.rs:625` | | | +| `RS-0719` | `docs` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:` | | | +| `RS-0720` | `docs` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:1500, packages/d2b-resource-runtime/src/manag` | | | +| `RS-0721` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:850, packages/d2b-resource-runtime/src/manage` | | | +| `RS-0722` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:51, packages/d2b-resource-runtime/src/resourc` | | | +| `RS-0723` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:205-228` | | | +| `RS-0724` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/identity.rs:20, packages/d2b-resource-runtime/src/identi` | | | +| `RS-0725` | `docs` | `d2b-resource-types` | low | actionable | leaf | | | | `packages/d2b-resource-types/src/operation.rs:64, packages/d2b-resource-types/src/operation` | | | +| `RS-0726` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239` | | | +| `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62` | | | +| `RS-0727` | `docs` | `d2b-session` | low | actionable | leaf | | | | `operation.rs:207` | | | +| `RS-0729` | `docs` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:1182, admission.rs:1186, admission.rs:1190, admission.rs:1194` | | | +| `RS-0730` | `docs` | `d2b-session` | low | actionable | leaf | | | | `transport.rs:208, transport.rs:212` | | | +| `RS-0731` | `docs` | `d2b-session-unix` | medium | actionable | leaf | | | | `packages/d2b-session-unix/src/socket.rs:190, packages/d2b-session-unix/src/adapter.rs:351,` | | | +| `RS-0732` | `docs` | `d2b-session-unix` | low | actionable | leaf | | | | `packages/d2b-session-unix/src/socket.rs:202, packages/d2b-session-unix/src/socket.rs:210, ` | | | +| `RS-0733` | `docs` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:236, packages/d2b-telemetry/src/audit_hash.rs:23` | | | +| `RS-0734` | `docs` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/resolver.rs:80, packages/d2b-zone-routing/src/service.rs:208` | | | +| `RS-0736` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828` | | | +| `RS-0741` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/audio_dispatch.rs:372` | | | +| `RS-0737` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:438` | | | +| `RS-0738` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:292, packages/d2bd/src/resource_plane_v3.rs:1770, p` | | | +| `RS-0739` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/lib.rs:1, packages/d2bd/src/composition.rs:1` | | | +| `RS-0735` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:8294, packages/d2bd/src/resource_runtime.rs:8390, pa` | | | +| `RS-0740` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_effects.rs:91, packages/d2bd/src/provider_effects.rs:711, packa` | | | +| `RS-0742` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:1046-1049, packages/d2bd/src/forward_rendezvous.rs` | | | +| `RS-0743` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `json_io.rs:10, json_io.rs:41` | | | +| `RS-0747` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:1, packages/d2bd-runtime/src/unsafe_local` | | | +| `RS-0744` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `vm_start_support.rs:14, vm_start_support.rs:44, vm_start_support.rs:89` | | | +| `RS-0748` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `packages/d2bd-runtime/src/exec_session.rs:181, packages/d2bd-runtime/src/exec_session.rs:2` | | | +| `RS-0749` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `packages/d2bd-runtime/src/readiness.rs:15, packages/d2bd-runtime/src/readiness.rs:78, pack` | | | +| `RS-0745` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `broker_transport.rs:60, broker_transport.rs:69, broker_transport.rs:116, broker_transport.` | | | +| `RS-0746` | `docs` | `d2bd-runtime` | low | actionable | leaf | | | | `ssh_host_key_preflight.rs:312, ssh_host_key_preflight.rs:298-301` | | | +| `RS-0750` | `docs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/ch_api.rs:11, packages/d2bd-runtime/src/ch_api.rs:15, packages/d` | | | +| `RS-0751` | `docs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/target_runtime.rs:256, packages/d2bd-runtime/src/target_runtime.` | | | +| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packa` | | | +| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/` | | | +| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, pa` | | | +| `RS-0752` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:5360, packages/xtask/src/provider_crate_policy` | | | +| `RS-0753` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:1555, packages/xtask/src/main.rs:1544` | | | +| `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | | | | `context.rs:570, context.rs:538` | | | +| `RS-0757` | `perf` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970` | | | +| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | | | | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | | | +| `RS-0759` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/nft.rs:784-790` | | | +| `RS-0760` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368` | | | +| `RS-0758` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, pa` | | | +| `RS-0761` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/stor` | | | +| `RS-0763` | `perf` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:4228-4235` | | | +| `RS-0764` | `perf` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/streams.rs:642-658` | | | +| `RS-0765` | `perf` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-reso` | | | +| `RS-0766` | `perf` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `resource_bundle.rs:382` | | | +| `RS-0767` | `perf` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:16` | | | +| `RS-0768` | `perf` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:37` | | | +| `RS-0769` | `perf` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:16` | | | +| `RS-0770` | `perf` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628` | | | +| `RS-0772` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2` | | | +| `RS-0773` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159` | | | +| `RS-0774` | `perf` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nix` | | | +| `RS-0775` | `perf` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/session_children.rs:316, src/session_children.rs:317` | | | +| `RS-0776` | `perf` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:8` | | | +| `RS-0777` | `perf` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:505-513` | | | +| `RS-0778` | `perf` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239` | | | +| `RS-0779` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/nftables.rs:266-268` | | | +| `RS-0780` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/observe.rs:305` | | | +| `RS-0781` | `perf` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-not` | | | +| `RS-0782` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `emitter_socket.rs:139` | | | +| `RS-0783` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `ingress_policy.rs:203, ingress_policy.rs:368` | | | +| `RS-0784` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `metric_policy.rs:44` | | | +| `RS-0785` | `perf` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process` | | | +| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/sr` | | | +| `RS-0787` | `perf` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-p` | | | +| `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | +| `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:437-440, driver.rs:614-617` | | | +| `RS-0791` | `perf` | `d2b-resource-api` | medium | actionable | leaf | | | | `manager_backend.rs:1006` | | | +| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | | | | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | | | +| `RS-0793` | `perf` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458` | | | +| `RS-0790` | `perf` | `d2b-resource-api` | low | actionable | leaf | | | | `manager_backend.rs:495, manager_backend.rs:449-455` | | | +| `RS-0794` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:1390` | | | +| `RS-0795` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/g` | | | +| `RS-0796` | `perf` | `d2b-session` | low | actionable | leaf | | | | `record.rs:125, record.rs:147` | | | +| `RS-0797` | `perf` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1354, engine.rs:1362, scheduler.rs:72` | | | +| `RS-0798` | `perf` | `d2b-session` | low | actionable | leaf | | | | `record.rs:120, record.rs:146` | | | +| `RS-0799` | `perf` | `d2b-session-unix` | low | actionable | leaf | | | | `packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, ` | | | +| `RS-0800` | `perf` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, pa` | | | +| `RS-0801` | `perf` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:333` | | | +| `RS-0802` | `perf` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476` | | | +| `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.r` | | | +| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | | | | `public_read_model.rs:117-118` | | | +| `RS-0808` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packag` | | | +| `RS-0805` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:431` | | | +| `RS-0806` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:582` | | | +| `RS-0807` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:972` | | | +| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | | | | `clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provide` | | | +| `RS-0809` | `conc` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:1146, src/envelope/mod.rs:2144` | | | +| `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/registry.rs:522-523, packages/d2b-bus/src/registry.rs:573-582` | | | +| `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-p` | | | +| `RS-0812` | `conc` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96` | | | +| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/` | | | +| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | | | | `packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-g` | | | +| `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-` | | | +| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | | | | `test_support.rs:25, test_support.rs:35, Cargo.toml:30` | | | +| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | | | | `packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, ` | | | +| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_s` | | | +| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.` | | | +| `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.` | | | +| `RS-0821` | `conc` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/testing.rs:43, src/testing.rs:79` | | | +| `RS-0822` | `conc` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/operations/envelope.rs:487` | | | +| `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | | | | `packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-uni` | | | +| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-user/src/test_support.rs:41-42, packages/d2b-provider-user/src/test_` | | | +| `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | | | | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_sup` | | | +| `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | | | | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-bindin` | | | +| `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone` | | | +| `RS-0828` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/resource.rs:247` | | | +| `RS-0829` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:` | | | +| `RS-0830` | `conc` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:756, admission.rs:1666, driver.rs:33` | | | +| `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src` | | | +| `RS-0832` | `conc` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs` | | | +| `RS-0833` | `conc` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414` | | | +| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34` | | | +| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | | | | `packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189` | | | +| `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | | | | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support` | | | +| `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | | | | `packages/d2b-broker/src/runtime.rs:11815, packages/d2b-broker/src/kernel_ops.rs:919, packa` | | | +| `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | | | | `packages/d2b-broker/src/ops/swtpm_dir.rs:770, packages/d2b-broker/src/sys.rs:1866-1893, pa` | | | +| `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | | | | `packages/d2b-broker/src/ops/media.rs:2100, packages/d2b-broker/src/ops/media.rs:2126` | | | +| `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | | | | `packages/d2b-broker/src/ops/host_generation_handoff.rs:246, packages/d2b-broker/src/ops/ho` | | | +| `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | +| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | | | | `packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages` | | | +| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | | | +| `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:316-324` | | | +| `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-cre` | | | +| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | | | | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | | | +| `RS-0847` | `async` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:361, effects_service.rs:384, effects_service.rs:698` | | | +| `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/observe.rs:255-260` | | | +| `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/testing.rs:30, src/testing.rs:19` | | | +| `RS-0850` | `async` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833` | | | +| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | | | | `packages/d2b-provider-user/src/probe.rs:48, packages/d2b-provider-user/src/probe.rs:63, pa` | | | +| `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | | | | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | +| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:5518-5530` | | | +| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_ef` | | | +| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | | | | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | | | +| `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broke` | | | +| `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | | | +| `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | | | | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | +| `RS-0859` | `unsafe` | `d2b-host-activation-helper` | medium | actionable | leaf | | | | `packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/sr` | | | +| `RS-0860` | `macro` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420` | | | +| `RS-0861` | `macro` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:2245-2267` | | | +| `RS-0862` | `macro` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643` | | | +| `RS-0863` | `macro` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/s` | | | +| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | | | +| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | | | | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | | | +| `RS-0880` | `test` | `d2b` | medium | actionable | leaf | | | | `packages/d2b/src/exec.rs:227-239` | | | +| `RS-0881` | `test` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/exec.rs:383-397` | | | +| `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | +| `RS-0864` | `test` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:523` | | | +| `RS-0865` | `test` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.` | | | +| `RS-0867` | `test` | `d2b-bus` | high | actionable | leaf | | | | `packages/d2b-bus/src/metrics.rs:612-633, packages/d2b-bus/src/metrics.rs:451-534` | | | +| `RS-0868` | `test` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_te` | | | +| `RS-0869` | `test` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/operations.rs:1057-1060` | | | +| `RS-0870` | `test` | `d2b-contracts-control` | medium | actionable | leaf | | | | `public_wire.rs:167, public_wire.rs:175` | | | +| `RS-0871` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-` | | | +| `RS-0872` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contract` | | | +| `RS-0873` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | | | | `src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_sessi` | | | +| `RS-0874` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | | | | `emergency_policy.rs:236, emergency_policy.rs:112` | | | +| `RS-0877` | `test` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/tests/bundle_resolver_tamper.rs:149` | | | +| `RS-0875` | `test` | `d2b-core-controller` | medium | actionable | leaf | | | | `authority.rs:1824, authority.rs:1968, authority.rs:1899` | | | +| `RS-0876` | `test` | `d2b-core-controller` | medium | actionable | leaf | | | | `authority_persistence.rs:246-320` | | | +| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:245` | | | +| `RS-0879` | `test` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/bin/d2b-activation-helper.rs:792` | | | +| `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activ` | | | +| `RS-0883` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `tests/authority.rs:26-31, src/authority.rs:236-241` | | | +| `RS-0884` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `tests/mediator.rs:13-24` | | | +| `RS-0885` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787` | | | +| `RS-0886` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clip` | | | +| `RS-0887` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provide` | | | +| `RS-0888` | `test` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-pro` | | | +| `RS-0889` | `test` | `d2b-provider-config-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixo` | | | +| `RS-0890` | `test` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixo` | | | +| `RS-0891` | `test` | `d2b-provider-credential-entra` | low | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-e` | | | +| `RS-0892` | `test` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76` | | | +| `RS-0893` | `test` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-` | | | +| `RS-0894` | `test` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/te` | | | +| `RS-0896` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, ` | | | +| `RS-0897` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `src/reconcile_state.rs:51-308, src/state_machine.rs:98-100` | | | +| `RS-0895` | `test` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `tests/conformance.rs:63-66` | | | +| `RS-0898` | `test` | `d2b-provider-display-wayland` | high | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3213, packages/d2b-provi` | | | +| `RS-0900` | `test` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | | | | `src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225` | | | +| `RS-0899` | `test` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `tests/provider_lifecycle.rs:536` | | | +| `RS-0901` | `test` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `tests/error_redaction.rs:17` | | | +| `RS-0902` | `test` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `finalize_ordering_test.rs:286` | | | +| `RS-0903` | `test` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest` | | | +| `RS-0904` | `test` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `metric_policy.rs:145, metric_policy.rs:150` | | | +| `RS-0905` | `test` | `d2b-provider-provider` | medium | actionable | leaf | | | | `src/providers.rs:206, src/driver.rs:1147` | | | +| `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | | | | `tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.r` | | | +| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:2040-2043` | | | +| `RS-0908` | `test` | `d2b-provider-system-core` | low | actionable | leaf | | | | `tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230` | | | +| `RS-0909` | `test` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/tests/observe.rs:14-15` | | | +| `RS-0910` | `test` | `d2b-provider-user` | medium | actionable | leaf | | | | `packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs` | | | +| `RS-0911` | `test` | `d2b-provider-wayland-policy` | low | actionable | leaf | | | | `packages/d2b-provider-wayland-policy/tests/registration.rs:93` | | | +| `RS-0912` | `test` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/sr` | | | +| `RS-0914` | `test` | `d2b-resource-api` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src` | | | +| `RS-0913` | `test` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:3377` | | | +| `RS-0915` | `test` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/p` | | | +| `RS-0916` | `test` | `d2b-resource-runtime` | high | actionable | leaf | | | | `packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revis` | | | +| `RS-0917` | `test` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/revision.rs:182` | | | +| `RS-0918` | `test` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/lib.rs:66` | | | +| `RS-0919` | `test` | `d2b-session` | low | actionable | leaf | | | | `tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139` | | | +| `RS-0920` | `test` | `d2b-sk-frontend` | medium | actionable | leaf | | | | `packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186` | | | +| `RS-0921` | `test` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/meter_registry.rs:176-180` | | | +| `RS-0922` | `test` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helpe` | | | +| `RS-0923` | `test` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/engine.rs:3333` | | | +| `RS-0924` | `test` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/router.rs:517` | | | +| `RS-0925` | `test` | `d2bd-runtime` | high | actionable | leaf | | | | `runtime_process.rs:543-546, runtime_process.rs:589-594` | | | +| `RS-0926` | `test` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/daemon_audit.rs:2367` | | | +| `RS-0928` | `test` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079` | | | +| `RS-0927` | `test` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:705` | | | +| `RS-0933` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28` | | | +| `RS-0934` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31` | | | +| `RS-0935` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-session/Cargo.toml:44` | | | +| `RS-0936` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-telemetry/Cargo.toml:14` | | | +| `RS-0937` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-quota/Cargo.toml:24` | | | +| `RS-0938` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-bus/Cargo.toml:41` | | | +| `RS-0939` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `dependencies` | | | +| `RS-0940` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `dependencies` | | | +| `RS-0941` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `dependencies` | | | +| `RS-0942` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | +| `RS-0943` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.baz` | | | +| `RS-0944` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55` | | | +| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | | | | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | | | +| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | | | | `Cargo.toml:202, deny.toml:2` | | | +| `RS-0948` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport` | | | +| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | | | | `packages/Cargo.guest.lock:1, flake.nix:389` | | | +| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | | | | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | | | +| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | | | | `deny.toml:2` | | | +| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | | | | `deny.toml:21` | | | +| `RS-0929` | `supply` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `Cargo.toml:24, Cargo.toml:25` | | | +| `RS-0930` | `supply` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.tom` | | | +| `RS-0931` | `supply` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `Cargo.toml:21` | | | +| `RS-0932` | `supply` | `d2b-provider-quota` | low | actionable | leaf | | | | `dependencies` | | | From 5776b3cc5a420de62ceb03bea92737510d606412 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:38:10 -0700 Subject: [PATCH 003/726] fix(wayland-policy): refuse a malformed zone token at the driver boundary InteractionDriver::new parsed the args zone token with a per-pass expect, so a malformed token panicked at the family engine's public boundary. The constructor now returns a typed SpecInvalid refusal, and the factory maps the refusal onto a driver that surfaces it through the actor's first verb instead of panicking. --- .../src/interaction.rs | 74 ++++++++++++++++--- .../tests/engine.rs | 18 ++++- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/packages/d2b-provider-wayland-policy/src/interaction.rs b/packages/d2b-provider-wayland-policy/src/interaction.rs index aa5e40dad..f3a6c6014 100644 --- a/packages/d2b-provider-wayland-policy/src/interaction.rs +++ b/packages/d2b-provider-wayland-policy/src/interaction.rs @@ -468,7 +468,56 @@ impl ResourceDriverFactory for InteractionDriverFactory { } async fn create(&self, _key: &ResourceKey) -> Box { - Box::new(InteractionDriver::new(self.args.clone())) + match InteractionDriver::new(self.args.clone()) { + Ok(driver) => Box::new(driver), + Err(error) => Box::new(RefusedInteractionDriver { error }), + } + } +} + +/// One driver that refuses every verb with a construction-time refusal. +/// +/// The daemon validates the zone at plane construction, so `create` never +/// sees a malformed zone in production; this arm keeps the factory +/// infallible (R3) while the typed refusal surfaces through the actor's +/// first verb instead of panicking. +struct RefusedInteractionDriver { + error: InteractionDriverError, +} + +#[async_trait] +impl ResourceDriver for RefusedInteractionDriver { + type Error = InteractionDriverError; + + fn classify_error(&self, error: &InteractionDriverError) -> DriverFailure { + classify_interaction_error(error) + } + + async fn validate(&mut self, _ctx: &mut ResourceContext) -> Result<(), Self::Error> { + Err(self.error) + } + + async fn recover(&mut self, _ctx: &mut ResourceContext) -> Result { + Err(self.error) + } + + async fn reconcile( + &mut self, + _ctx: &mut ResourceContext, + ) -> Result { + Err(self.error) + } + + async fn delete(&mut self, _ctx: &mut ResourceContext) -> Result<(), Self::Error> { + Err(self.error) + } +} + +/// Classify one family-engine refusal onto the structured failure surface. +fn classify_interaction_error(error: &InteractionDriverError) -> DriverFailure { + match error.kind.class() { + FailureClass::Retryable => DriverFailure::retryable(error.op), + FailureClass::Terminal => DriverFailure::terminal(error.op), } } @@ -484,15 +533,25 @@ pub struct InteractionDriver { impl InteractionDriver { /// Build the driver for its declared type. - pub fn new(args: InteractionDriverArgs) -> Self { - let zone = ZoneId::parse(args.zone).expect("driver zone was validated at construction"); - Self { + /// + /// The zone token is parsed once at this boundary; a malformed token is + /// refused as a terminal [`InteractionDriverError`] instead of panicking. + /// + /// # Errors + /// + /// Returns the `SpecInvalid` refusal when `args.zone` is not a valid + /// [`ZoneId`]. + pub fn new(args: InteractionDriverArgs) -> Result { + let zone = ZoneId::parse(args.zone).map_err(|_| { + InteractionDriverError::new(InteractionDriverErrorKind::SpecInvalid, DriverOp::Validate) + })?; + Ok(Self { zone, controller_generation: args.controller_generation, effects: args.effects, behavior: args.behavior, watched: Vec::new(), - } + }) } fn error(&self, kind: InteractionDriverErrorKind, op: DriverOp) -> InteractionDriverError { @@ -689,10 +748,7 @@ impl ResourceDriver for InteractionDriver { type Error = InteractionDriverError; fn classify_error(&self, error: &InteractionDriverError) -> DriverFailure { - match error.kind.class() { - FailureClass::Retryable => DriverFailure::retryable(error.op), - FailureClass::Terminal => DriverFailure::terminal(error.op), - } + classify_interaction_error(error) } /// Structural validation: the stored spec decodes, names a Provider this diff --git a/packages/d2b-provider-wayland-policy/tests/engine.rs b/packages/d2b-provider-wayland-policy/tests/engine.rs index 29e632884..1e215916f 100644 --- a/packages/d2b-provider-wayland-policy/tests/engine.rs +++ b/packages/d2b-provider-wayland-policy/tests/engine.rs @@ -269,7 +269,8 @@ fn build_fixture( controller_generation: ControllerGeneration::new(3).unwrap(), effects: Arc::clone(&effects) as Arc, behavior: TestType { valid }, - }); + }) + .expect("driver"); ( Fixture { ctx, @@ -337,6 +338,21 @@ fn the_factory_serves_only_its_declared_type() { assert_eq!(served, vec!["test.d2bus.org.Row".to_owned()]); } +/// A malformed zone token is refused at the driver boundary instead of +/// panicking. +#[test] +fn the_driver_refuses_a_malformed_zone_token() { + let effects = ScriptedEffects::shared(Arc::new(tokio::sync::Mutex::new(Vec::new()))); + let refusal = InteractionDriver::new(InteractionDriverArgs { + zone: "not a zone token".to_owned(), + controller_generation: ControllerGeneration::new(3).unwrap(), + effects: Arc::clone(&effects) as Arc, + behavior: TestType { valid: true }, + }) + .expect_err("a malformed zone token is a typed refusal, not a panic"); + assert_eq!(refusal.to_string(), "interaction-spec-invalid"); +} + // -- validate --------------------------------------------------------------- #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] From 3b964169f0af682d55469365c5cb332e8ddced16 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:38:13 -0700 Subject: [PATCH 004/726] test(display-wayland): assert advertised-global outcomes in the registry-handler tests Both registry-handler tests restated just-inserted map state and could not fail on any behavior change. They now drive prepare_global and assert the observable decision: the filtered global keeps its original registry name and the synthetic clipboard global is advertised at the reserved name, so either test fails when the synthetic clipboard global stops being advertised. --- .../src/wayland_proxy/filter.rs | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs index ed94ba4ba..c38330027 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs @@ -3214,28 +3214,32 @@ mod tests { let diag = Rc::new(RefCell::new(DiagRateLimiter::new("work".to_owned()))); let mut handler = FilterRegistryHandler::new(policy(), diag, clipboard(), None); - handler.advertised_globals.insert( - 7, - AdvertisedGlobal { + let (synthetic, decision) = handler.prepare_global(7, ObjectInterface::WlCompositor, 6); + + // The host's global keeps its original registry name; the synthetic + // clipboard global is advertised alongside it at the reserved name. + assert_eq!( + decision, + IncomingGlobalDecision::Advertise(GlobalAdvertisement { + name: 7, interface: ObjectInterface::WlCompositor, version: 6, - synthetic_clipboard: false, - }, + }) ); - handler.hidden_globals.insert(42); - handler.advertised_globals.insert( - 99, - AdvertisedGlobal { - interface: ObjectInterface::WlShm, - version: 2, - synthetic_clipboard: false, - }, + assert_eq!( + synthetic, + Some(GlobalAdvertisement { + name: u32::MAX, + interface: ObjectInterface::WlDataDeviceManager, + version: 3, + }) ); - - assert!(handler.advertised_globals.contains_key(&7)); - assert!(handler.advertised_globals.contains_key(&99)); - assert!(handler.hidden_globals.contains(&42)); - assert!(!handler.advertised_globals.contains_key(&42)); + let advertised = handler + .advertised_globals + .get(&7) + .expect("the original name stays advertised"); + assert_eq!(advertised.interface, ObjectInterface::WlCompositor); + assert!(!advertised.synthetic_clipboard); } #[test] @@ -3264,21 +3268,30 @@ mod tests { fn standard_clipboard_global_is_advertised_as_synthetic() { let diag = Rc::new(RefCell::new(DiagRateLimiter::new("work".to_owned()))); let mut handler = FilterRegistryHandler::new(policy(), diag, clipboard(), None); - // The generated WlRegistry send path needs a real object/client, so assert - // the policy decision helper that handle_global uses for the synthetic path. - let interface = ObjectInterface::WlDataDeviceManager; - assert_eq!(interface.name(), "wl_data_device_manager"); - handler.advertised_globals.insert( - 11, - AdvertisedGlobal { - interface, + + // The host's wl_data_device_manager is virtualized locally: the + // handler hides the host global and advertises the synthetic + // clipboard global in its place (the decision prepare_global makes + // for the real WlRegistry send path). + let (synthetic, decision) = + handler.prepare_global(11, ObjectInterface::WlDataDeviceManager, 3); + + assert_eq!(decision, IncomingGlobalDecision::Hide); + assert_eq!( + synthetic, + Some(GlobalAdvertisement { + name: u32::MAX, + interface: ObjectInterface::WlDataDeviceManager, version: 3, - synthetic_clipboard: true, - }, + }) ); - let advertised = handler.advertised_globals.get(&11).expect("synthetic"); + let advertised = handler + .advertised_globals + .get(&u32::MAX) + .expect("the synthetic clipboard global is advertised"); assert!(advertised.synthetic_clipboard); assert_eq!(advertised.interface, ObjectInterface::WlDataDeviceManager); + assert!(handler.hidden_globals.contains(&11)); } #[test] From 9b64eaa275f2825f1eb46cf05ab42e6bb61c7c9e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:45:05 -0700 Subject: [PATCH 005/726] broker: reap the spawned runner without blocking the executor The post-spawn rollback reap ran a blocking waitid(2) without WNOHANG on the broker's tokio executor; a child stuck in uninterruptible sleep could park the worker indefinitely. Replace it with a bounded WNOHANG poll that sleeps in timer time, matching every sibling reap path in runtime.rs. On deadline exhaustion the pidfd entry is left in place so the SIGCHLD reaper owns the zombie and the next spawn reservation evicts the stale entry once the process is gone. The orphaned cleanup_registered_runner_ after_failure and remove_runner_registration helpers (no callers) are removed with the cutover. --- packages/d2b-broker/src/kernel_ops.rs | 6 +- packages/d2b-broker/src/runtime.rs | 118 ++++++++++++++++++++------ 2 files changed, 94 insertions(+), 30 deletions(-) diff --git a/packages/d2b-broker/src/kernel_ops.rs b/packages/d2b-broker/src/kernel_ops.rs index 0d5e18e5a..324589bc8 100644 --- a/packages/d2b-broker/src/kernel_ops.rs +++ b/packages/d2b-broker/src/kernel_ops.rs @@ -916,7 +916,8 @@ async fn spawn_process( &runner_id, duplicate(&outcome.pidfd).map_err(|error| errored(format!("spawn-process: {error}")))?, ) { - crate::runtime::cleanup_spawned_runner_after_failure(&runner_id, outcome.pidfd.as_fd()); + crate::runtime::cleanup_spawned_runner_after_failure(&runner_id, outcome.pidfd.as_fd()) + .await; let _ = crate::runtime::runner_pidfds().remove(invocation_id); return Err(errored(format!("spawn-process registry: {error:?}"))); } @@ -952,7 +953,8 @@ async fn spawn_process( // registration is a concurrent duplicate that slipped in between // the guard and the insert; roll the spawn back rather than // overwrite the live registration. - crate::runtime::cleanup_spawned_runner_after_failure(&runner_id, outcome.pidfd.as_fd()); + crate::runtime::cleanup_spawned_runner_after_failure(&runner_id, outcome.pidfd.as_fd()) + .await; let _ = crate::runtime::runner_pidfds().remove(invocation_id); return Err(errored(format!( "spawn-process metadata registry: runner {runner_id} already registered" diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 384c14172..31adecdcf 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -6047,11 +6047,6 @@ fn register_runner_pidfd(runner_id: &str, pidfd: &OwnedFd) -> Result<(), BrokerE runner_pidfds().insert(runner_id, duplicated) } -#[cfg(not(feature = "layer1-bootstrap"))] -fn remove_runner_registration(runner_id: &str) { - runner_pidfds().remove(runner_id); -} - #[cfg(not(feature = "layer1-bootstrap"))] fn remove_runner_registries(runner_id: &str) -> bool { // Keep the metadata ordering aligned with observation and deregistration @@ -11792,12 +11787,29 @@ async fn remove_and_notify_async( removed } -/// Kill and synchronously reap a child when a post-spawn commit step fails. +/// Bound on the spawn-rollback reap: `SIGKILL` is asynchronous (a child can +/// sit in uninterruptible sleep), so [`cleanup_spawned_runner_after_failure`] +/// polls `waitid` with `WNOHANG` under this deadline instead of parking the +/// executor worker on a blocking wait for as long as the child takes to die. +#[cfg(not(feature = "layer1-bootstrap"))] +const SPAWN_ROLLBACK_REAP_DEADLINE: std::time::Duration = std::time::Duration::from_secs(5); +/// Poll interval for the spawn-rollback reap. +#[cfg(not(feature = "layer1-bootstrap"))] +const SPAWN_ROLLBACK_REAP_POLL: std::time::Duration = std::time::Duration::from_millis(10); + +/// Kill and asynchronously reap a child when a post-spawn commit step fails. /// The broker must not return an error while leaving a live process or stale /// runner identity behind: the caller will retry the lifecycle operation and /// the next attempt must be able to reserve the same runner id. +/// +/// The reap is a bounded `WNOHANG` poll (the same non-blocking probe every +/// sibling reap path in this file uses) rather than a blocking `waitid`. On +/// deadline exhaustion the pidfd entry is left in place: the SIGCHLD reaper +/// owns the zombie (it is signal-driven and reaps on death), the next spawn +/// reservation evicts the stale entry once the process is gone, and while +/// the child is still alive the entry keeps refusing a duplicate spawn. #[cfg(not(feature = "layer1-bootstrap"))] -pub(crate) fn cleanup_spawned_runner_after_failure( +pub(crate) async fn cleanup_spawned_runner_after_failure( runner_id: &str, pidfd: std::os::fd::BorrowedFd<'_>, ) { @@ -11811,29 +11823,35 @@ pub(crate) fn cleanup_spawned_runner_after_failure( } use nix::errno::Errno; - use nix::sys::wait::{Id, WaitPidFlag, waitid}; - match waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED) { - Ok(_) | Err(Errno::ECHILD) => {} - Err(err) => { - tracing::warn!( - runner_id = %runner_id, - error = %err, - "spawn rollback: blocking pidfd reap failed" - ); + use nix::sys::wait::{Id, WaitPidFlag, WaitStatus, waitid}; + let deadline = tokio::time::Instant::now() + SPAWN_ROLLBACK_REAP_DEADLINE; + loop { + match waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED | WaitPidFlag::WNOHANG) { + Ok(WaitStatus::Exited(..)) | Ok(WaitStatus::Signaled(..)) | Err(Errno::ECHILD) => { + runner_pidfds().remove(runner_id); + return; + } + Ok(WaitStatus::StillAlive) | Ok(_) => { + if tokio::time::Instant::now() >= deadline { + tracing::warn!( + runner_id = %runner_id, + "spawn rollback: reap deadline exceeded; the SIGCHLD reaper owns the child" + ); + return; + } + tokio::time::sleep(SPAWN_ROLLBACK_REAP_POLL).await; + } + Err(err) => { + tracing::warn!( + runner_id = %runner_id, + error = %err, + "spawn rollback: pidfd reap failed" + ); + runner_pidfds().remove(runner_id); + return; + } } } - runner_pidfds().remove(runner_id); -} - -#[cfg(not(feature = "layer1-bootstrap"))] -fn cleanup_registered_runner_after_failure(runner_id: &str) { - let pidfd = runner_pidfds().duplicate(runner_id); - if let Some(pidfd) = pidfd { - cleanup_spawned_runner_after_failure(runner_id, pidfd.as_fd()); - } else { - remove_runner_metadata(runner_id); - remove_runner_registration(runner_id); - } } #[cfg(test)] @@ -20319,6 +20337,50 @@ mod tests { ); } + #[test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn spawn_rollback_reaps_and_deregisters_the_child() { + // The post-spawn rollback reap must kill, reap, and + // deregister the child so a retry can reserve the runner id + // and no zombie is left behind. + let _guard = ReapTestGuard::new(); + + let child = Command::new("true").spawn().expect("spawn true child"); + let pid = child.id() as i32; + let runner_id = format!("test-vm:rollback-{pid}"); + let pidfd = crate::sys::pidfd_sys::pidfd_open(pid, 0).expect("pidfd_open"); + let registry_dup = pidfd.try_clone().expect("dup pidfd for registry"); + runner_pidfds() + .insert(&runner_id, registry_dup) + .expect("register runner pidfd"); + with_runner_metadata_mut(|registry| { + registry.insert(runner_id.clone(), test_runner_registration(pid, 1)); + }); + std::mem::forget(child); + + envelope_call_runtime().block_on(cleanup_spawned_runner_after_failure( + &runner_id, + pidfd.as_fd(), + )); + + assert!( + !runner_pidfds().contains_key(&runner_id), + "rollback reap must remove the pidfd registration" + ); + assert!( + !with_runner_metadata_mut(|registry| registry.contains_key(&runner_id)), + "rollback reap must remove the runner metadata" + ); + // The child must be reaped, not left a zombie: a fresh + // WNOHANG probe on the pidfd reports ECHILD (already reaped). + use nix::errno::Errno; + use nix::sys::wait::{Id, WaitPidFlag, waitid}; + match waitid(Id::PIDFd(pidfd.as_fd()), WaitPidFlag::WEXITED | WaitPidFlag::WNOHANG) { + Err(Errno::ECHILD) => {} + other => panic!("rollback reap left the child unreaped: {other:?}"), + } + } + #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn targeted_reap_leaves_running_child_for_sigchld_loop() { From f4f09c74c4b7fe26e74d7622fa95812888573510 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:45:21 -0700 Subject: [PATCH 006/726] broker: move the handoff lock wait to a bounded worker acquire_handoff_lock ended in a blocking flock(2) on the executor worker while another process held the per-state-dir lock for its whole apply/replay critical section. The blocking wait now runs on a dedicated bounded worker in the house loader_worker shape (sync_channel admission with try_send refusal and tokio oneshot replies), so the lock is still acquired exactly when it is free but no executor worker parks on it. Add a test proving a second acquisition waits for the first holder. --- .../src/ops/host_generation_handoff.rs | 92 ++++++++++++++++++- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/packages/d2b-broker/src/ops/host_generation_handoff.rs b/packages/d2b-broker/src/ops/host_generation_handoff.rs index 009a22922..856d6e857 100644 --- a/packages/d2b-broker/src/ops/host_generation_handoff.rs +++ b/packages/d2b-broker/src/ops/host_generation_handoff.rs @@ -227,7 +227,10 @@ pub async fn validate_artifact_with_helper( /// `flock(2)` on a dedicated lock file: the held fd is the lock (plan /// KD1 - no surviving `std::sync::Mutex`), and the same file excludes /// concurrent writers across processes as well as threads. The fd stays -/// owned by the caller for the whole apply/replay critical section. +/// owned by the caller for the whole apply/replay critical section. The +/// blocking wait runs on the dedicated bounded worker +/// ([`HANDOFF_LOCK_WORKER`]) so the executor worker never parks on it; +/// the lock is acquired exactly when it is free, as before. async fn acquire_handoff_lock( state_dir: &Path, ) -> Result, HandoffOperationError> { @@ -243,8 +246,65 @@ async fn acquire_handoff_lock( .open(&path) .await .map_err(HandoffOperationError::Io)?; - nix::fcntl::Flock::lock(file.into_std().await, nix::fcntl::FlockArg::LockExclusive) - .map_err(|(_, err)| HandoffOperationError::Io(io::Error::from(err))) + let file = file.into_std().await; + let Some(worker) = HANDOFF_LOCK_WORKER.as_ref() else { + return Err(HandoffOperationError::Io(io::Error::other( + "handoff lock worker unavailable", + ))); + }; + let (reply, answer) = tokio::sync::oneshot::channel(); + let job = HandoffLockJob { file, reply }; + worker + .sender + .try_send(job) + .map_err(|_| HandoffOperationError::Io(io::Error::other("handoff lock worker busy")))?; + answer + .await + .map_err(|_| HandoffOperationError::Io(io::Error::other("handoff lock worker unavailable")))? + .map_err(HandoffOperationError::Io) +} + +/// One job on the handoff-lock seat: block on `flock(2)` for the caller. +struct HandoffLockJob { + file: std::fs::File, + reply: tokio::sync::oneshot::Sender, io::Error>>, +} + +/// The bounded worker that owns the blocking `flock(2)` wait for the +/// per-state-dir handoff lock (plan R4: a blocking `sync_channel` recv on +/// the worker's own dedicated thread, with `tokio::sync::oneshot` replies). +/// The wait can be long - the lock is held for the whole apply/replay +/// critical section of the previous holder - so it must not park an +/// executor worker; the dedicated thread blocks instead, and the caller +/// awaits the outcome. Admission is a non-blocking `try_send`, so a +/// saturated queue refuses rather than parking the caller or growing the +/// pool. +struct HandoffLockWorker { + sender: std::sync::mpsc::SyncSender, +} + +/// The handoff-lock seat, started on first use; `None` records a worker +/// that could not start, so every later call refuses instead of retrying. +static HANDOFF_LOCK_WORKER: std::sync::LazyLock> = + std::sync::LazyLock::new(|| { + const QUEUE_DEPTH: usize = 4; + let (sender, receiver) = std::sync::mpsc::sync_channel::(QUEUE_DEPTH); + std::thread::Builder::new() + .name("d2b-broker-handoff-lock".to_owned()) + .spawn(move || handoff_lock_worker_loop(receiver)) + .ok() + .map(|_| HandoffLockWorker { sender }) + }); + +/// The sanctioned R4 channel boundary: a blocking `sync_channel` recv on +/// the worker's own dedicated thread, with `tokio::sync::oneshot` replies. +#[allow(clippy::disallowed_methods, reason = "dedicated bounded worker per plan R4")] +fn handoff_lock_worker_loop(receiver: std::sync::mpsc::Receiver) { + while let Ok(job) = receiver.recv() { + let result = nix::fcntl::Flock::lock(job.file, nix::fcntl::FlockArg::LockExclusive) + .map_err(|(_, err)| io::Error::from(err)); + let _ = job.reply.send(result); + } } /// Apply or replay one broker-owned generation handoff using a typed effect. @@ -509,6 +569,32 @@ mod tests { let _ = tokio::fs::remove_dir_all(directory).await; } + #[tokio::test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + async fn handoff_lock_serializes_concurrent_appliers() { + let directory = PathBuf::from("target") + .join(format!("d2b-handoff-lock-{}", std::process::id())); + let _ = tokio::fs::remove_dir_all(&directory).await; + + let first = acquire_handoff_lock(&directory).await.expect("first lock"); + let second_dir = directory.clone(); + let second = tokio::spawn(async move { + acquire_handoff_lock(&second_dir).await.expect("second lock") + }); + // The second acquisition must not complete while the first lock is + // held. The sleep is a window, not the assertion: whether the + // second task is queued on the worker or still awaiting its + // reply, it cannot be finished while the flock is held. + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + assert!( + !second.is_finished(), + "second acquisition must wait for the first holder" + ); + drop(first); + second.await.expect("second acquisition completes after release"); + let _ = tokio::fs::remove_dir_all(directory).await; + } + #[tokio::test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn artifact_validation_fails_closed_when_helper_is_unavailable() { From 25dfa3aeee68d60186e5c5150122c06cc259e3e7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:45:25 -0700 Subject: [PATCH 007/726] broker: run harden's setfacl shellout on a bounded worker The async swtpm-dir harden path forked setfacl and blocked on waitpid on the executor worker for the whole subprocess lifetime. The shellout now runs on a dedicated bounded worker in the house loader_worker shape (sync_channel admission with try_send refusal and tokio oneshot replies), with the target fd duplicated across as an OwnedFd; the async wrapper run_setfacl_op_on_fd_async keeps the same fail-closed ANCESTOR_ACL_FAILED behavior in apply_ancestor_traverse_acl. --- packages/d2b-broker/src/ops/swtpm_dir.rs | 10 ++- packages/d2b-broker/src/sys.rs | 78 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/packages/d2b-broker/src/ops/swtpm_dir.rs b/packages/d2b-broker/src/ops/swtpm_dir.rs index 43d889084..8f74bb7b8 100644 --- a/packages/d2b-broker/src/ops/swtpm_dir.rs +++ b/packages/d2b-broker/src/ops/swtpm_dir.rs @@ -768,6 +768,7 @@ pub async fn harden( // 4. Idempotent ancestor traverse ACL for the swtpm principal on // the per-VM root. apply_ancestor_traverse_acl(per_vm_root_fd.as_fd(), cfg.expected_uid) + .await .map_err(|reason| fail(reason, marker_result))?; // 5. Unlink a stale trusted control socket under the runtime dir. @@ -1007,11 +1008,16 @@ fn verify_acl_clean(fd: std::os::fd::BorrowedFd<'_>) -> Result<(), &'static str> /// Idempotent `u::--x` traverse ACL on the per-VM root so the /// swtpm principal can reach its dir through the sticky 3770 parent. -fn apply_ancestor_traverse_acl( +/// +/// The `setfacl` fork/exec/wait runs on the dedicated bounded setfacl +/// worker (via [`pidfd_sys::run_setfacl_op_on_fd_async`]) so the executor +/// worker is never parked on the subprocess. +async fn apply_ancestor_traverse_acl( per_vm_root_fd: std::os::fd::BorrowedFd<'_>, uid: u32, ) -> Result<(), &'static str> { - pidfd_sys::run_setfacl_op_on_fd(per_vm_root_fd, "-m", &format!("u:{uid}:--x")) + pidfd_sys::run_setfacl_op_on_fd_async(per_vm_root_fd, "-m", &format!("u:{uid}:--x")) + .await .map_err(|_| reasons::ANCESTOR_ACL_FAILED) } diff --git a/packages/d2b-broker/src/sys.rs b/packages/d2b-broker/src/sys.rs index 4e6d8e0db..34113bce3 100644 --- a/packages/d2b-broker/src/sys.rs +++ b/packages/d2b-broker/src/sys.rs @@ -1912,6 +1912,84 @@ pub mod pidfd_sys { } } + /// One job on the setfacl seat: run one `setfacl` fork/exec/wait on + /// the worker's own thread. + struct SetfaclJob { + fd: OwnedFd, + op: String, + acl_spec: String, + reply: tokio::sync::oneshot::Sender>, + } + + /// The bounded worker that owns the blocking `setfacl` fork/exec/wait + /// (plan R4: a blocking `sync_channel` recv on the worker's own + /// dedicated thread, with `tokio::sync::oneshot` replies). The shellout + /// has no async form and can take arbitrarily long (a wedged host can + /// stall the child), so it must not run on an executor worker; the + /// dedicated thread blocks instead, and the caller awaits the outcome. + /// Admission is a non-blocking `try_send`, so a saturated queue refuses + /// rather than parking the caller or growing the pool. + struct SetfaclWorker { + sender: std::sync::mpsc::SyncSender, + } + + /// The setfacl seat, started on first use; `None` records a worker that + /// could not start, so every later call refuses instead of retrying a + /// failing spawn. + static SETFACL_WORKER: std::sync::LazyLock> = + std::sync::LazyLock::new(|| { + const QUEUE_DEPTH: usize = 8; + let (sender, receiver) = std::sync::mpsc::sync_channel::(QUEUE_DEPTH); + std::thread::Builder::new() + .name("d2b-broker-setfacl".to_owned()) + .spawn(move || setfacl_worker_loop(receiver)) + .ok() + .map(|_| SetfaclWorker { sender }) + }); + + /// The sanctioned R4 channel boundary: a blocking `sync_channel` recv + /// on the worker's own dedicated thread, with `tokio::sync::oneshot` + /// replies. + #[allow(clippy::disallowed_methods, reason = "dedicated bounded worker per plan R4")] + fn setfacl_worker_loop(receiver: std::sync::mpsc::Receiver) { + while let Ok(job) = receiver.recv() { + let result = run_setfacl_op_on_fd(job.fd.as_fd(), &job.op, &job.acl_spec); + let _ = job.reply.send(result); + } + } + + /// Async form of [`run_setfacl_op_on_fd`] for callers on an executor + /// worker: the fork/exec/wait runs on the dedicated bounded setfacl + /// seat ([`SETFACL_WORKER`]) instead of parking the worker thread. + /// The target fd is duplicated across, so the caller's fd lifetime is + /// unaffected. + pub async fn run_setfacl_op_on_fd_async( + fd: BorrowedFd<'_>, + op: &str, + acl_spec: &str, + ) -> io::Result<()> { + let Some(worker) = SETFACL_WORKER.as_ref() else { + return Err(io::Error::other("setfacl worker unavailable")); + }; + let fd = nix::unistd::dup(fd.as_raw_fd()) + .map(crate::sys::owned_fd_from_raw) + .map_err(|error| io::Error::from_raw_os_error(error as i32))?; + let (reply, answer) = tokio::sync::oneshot::channel(); + let job = SetfaclJob { + fd, + op: op.to_owned(), + acl_spec: acl_spec.to_owned(), + reply, + }; + worker + .sender + .try_send(job) + .map_err(|_| io::Error::other("setfacl worker busy"))?; + answer + .await + .map_err(|_| io::Error::other("setfacl worker unavailable"))? + } + /// Clear BOTH the access ACL and the default ACL on the directory /// referenced by `fd` (the effect of `setfacl -b -k`) by removing the /// POSIX-ACL xattrs directly with `fremovexattr(2)`. Using the syscall From a6d8fb0225820cc053f6e1e71e6434e3e7f861e7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:45:28 -0700 Subject: [PATCH 008/726] broker: resolve the d2bd registry index gid once write_redacted_registry_index_at_path resolved the fixed d2bd group via the nss Group::from_name lookup on an executor worker on every registry write (enroll/refresh/boot). The gid is now resolved once in a LazyLock and reused; absence or a lookup failure is recorded on first resolution and surfaces as the same MediaOpError::Registry refusals as before. --- packages/d2b-broker/src/ops/media.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index ecbfca442..4e7269434 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -31,6 +31,18 @@ use sha2::{Digest, Sha256}; const DEFAULT_UDEVADM_BINARY: &str = "/run/current-system/sw/bin/udevadm"; +/// The fixed `d2bd` group, resolved once: `Group::from_name` is an nss +/// lookup that can block on the calling thread (LDAP/NSS plugins), so the +/// registry-index write path must not re-resolve it on every write. The +/// group is a serve-time constant of the installed package; absence or a +/// lookup failure is a permanent condition recorded on first resolution. +static D2BD_GROUP_GID: std::sync::LazyLock, String>> = + std::sync::LazyLock::new(|| { + Group::from_name("d2bd") + .map(|group| group.map(|group| group.gid)) + .map_err(|err| format!("resolve d2bd group: {err}")) + }); + #[derive(Debug)] pub enum MediaOpError { InvalidRef(String), @@ -2123,9 +2135,9 @@ async fn write_redacted_registry_index_at_path( .and_then(|name| name.to_str()) .ok_or_else(|| MediaOpError::Registry("redacted-index-name-invalid".to_owned()))?; let owner_gid = if Uid::effective().is_root() { - let gid = Group::from_name("d2bd") - .map_err(|err| MediaOpError::Registry(format!("resolve d2bd group: {err}")))? - .map(|group| group.gid) + let gid = D2BD_GROUP_GID + .as_ref() + .map_err(|detail| MediaOpError::Registry(detail.clone()))? .ok_or_else(|| MediaOpError::Registry("d2bd group missing".to_owned()))?; Some(gid.as_raw()) } else { From ebb3831b139a4d292f98b5ece0b578331b995cd2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:48:24 -0700 Subject: [PATCH 009/726] fix(d2bd-runtime): refuse malformed broker audit join instead of panicking --- packages/d2bd-runtime/src/broker_transport.rs | 60 ++++++++++++++++--- packages/d2bd/src/composition.rs | 2 +- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/packages/d2bd-runtime/src/broker_transport.rs b/packages/d2bd-runtime/src/broker_transport.rs index 6a85546a8..27a35af4f 100644 --- a/packages/d2bd-runtime/src/broker_transport.rs +++ b/packages/d2bd-runtime/src/broker_transport.rs @@ -28,7 +28,7 @@ pub fn dispatch_broker_request_to_socket( caller_role: BrokerCallerRole, timeout: Option, ) -> Result { - let audit_join = default_audit_join_context(&request); + let audit_join = default_audit_join_context(&request)?; let envelope = BrokerRequestEnvelope { request, caller_role, @@ -57,13 +57,21 @@ pub fn dispatch_broker_request_to_socket( } } -pub fn default_audit_join_context(request: &BrokerRequest) -> Option { - let (zone_id, operation_identity) = request.authoritative_audit_join()?; - Some(AuditJoinContext { - zone_id: CanonicalAuditDigest::parse(zone_id).expect("canonical broker zone digest"), - operation_identity: CanonicalAuditDigest::parse(operation_identity) - .expect("canonical broker operation digest"), - }) +pub fn default_audit_join_context( + request: &BrokerRequest, +) -> Result, TypedError> { + let Some((zone_id, operation_identity)) = request.authoritative_audit_join() else { + return Ok(None); + }; + let zone_id = CanonicalAuditDigest::parse(zone_id) + .map_err(|_| TypedError::WireInvalidFrame { detail: "audit zone identity invalid".to_owned() })?; + let operation_identity = CanonicalAuditDigest::parse(operation_identity).map_err(|_| { + TypedError::WireInvalidFrame { detail: "audit operation identity invalid".to_owned() } + })?; + Ok(Some(AuditJoinContext { + zone_id, + operation_identity, + })) } pub fn broker_remaining_before_op( @@ -306,3 +314,39 @@ impl std::fmt::Display for ModeBoundBrokerError { } impl std::error::Error for ModeBoundBrokerError {} + +#[cfg(test)] +mod tests { + use super::*; + use d2b_contracts_broker::broker_wire::{HelloRequest, SecretByIdRequest}; + + fn request_with_opaque_id(opaque_id: &str) -> BrokerRequest { + BrokerRequest::InjectSecretById(SecretByIdRequest { + opaque_id: opaque_id.to_owned(), + tracing_span_id: None, + }) + } + + #[test] + fn malformed_audit_join_material_does_not_panic() { + // The audit-join material is wire-supplied (a client-controlled + // opaque id), so a non-canonical value must never panic the daemon. + let request = request_with_opaque_id("not-a-canonical-digest"); + let context = default_audit_join_context(&request) + .expect("malformed audit-join material must not panic") + .expect("audit join is present for secret requests"); + assert!(context.zone_id.as_str().starts_with("sha256:")); + } + + #[test] + fn request_without_audit_join_yields_none() { + let request = BrokerRequest::Hello(HelloRequest { + client_version: "test".to_owned(), + supported_features: Vec::new(), + }); + assert_eq!( + default_audit_join_context(&request).expect("hello carries no audit join"), + None + ); + } +} diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index bfb0dd37a..0a4251a70 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -13876,7 +13876,7 @@ fn dispatch_broker_request_as( caller_role: BrokerCallerRole, ) -> Result { let socket_path = broker_socket_path(state); - let audit_join = default_audit_join_context(&request); + let audit_join = default_audit_join_context(&request)?; let socket = connect_seqpacket(&socket_path)?; write_json_frame( &socket, From bea8fa96debdcb7283856ac2c1683142d2a913db Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:48:34 -0700 Subject: [PATCH 010/726] test(d2bd-runtime): assert observable sd_notify ready outcomes --- packages/d2bd-runtime/src/runtime_process.rs | 79 +++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/packages/d2bd-runtime/src/runtime_process.rs b/packages/d2bd-runtime/src/runtime_process.rs index 85434ccda..fec193416 100644 --- a/packages/d2bd-runtime/src/runtime_process.rs +++ b/packages/d2bd-runtime/src/runtime_process.rs @@ -526,6 +526,7 @@ pub fn days_to_ymd(days_since_epoch: i64) -> (i32, u32, u32) { mod sd_notify_tests { use super::*; use std::os::unix::net::UnixDatagram; + use std::sync::{Arc, Mutex}; use std::time::{SystemTime, UNIX_EPOCH}; fn unique_abstract_name(label: &str) -> Vec { @@ -540,9 +541,73 @@ mod sd_notify_tests { String::from_utf8(bytes.to_vec()).expect("sd_notify payload is utf8") } + /// Minimal in-test tracing subscriber that records `(level, message)` + /// for every event emitted on the calling thread. + #[derive(Clone, Default)] + struct CapturingSubscriber(Arc>>); + + impl CapturingSubscriber { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn events(&self) -> Vec<(tracing::Level, String)> { + self.0.lock().expect("capture buffer").clone() + } + } + + /// Captures the `message` field of one event. + struct MessageCapture(Option); + + impl tracing::field::Visit for MessageCapture { + fn record_str(&mut self, field: &tracing::field::Field, value: &str) { + if field.name() == "message" { + self.0 = Some(value.to_owned()); + } + } + + fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) { + if field.name() == "message" { + self.0 = Some(format!("{value:?}")); + } + } + } + + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + impl tracing::Subscriber for CapturingSubscriber { + fn enabled(&self, _metadata: &tracing::Metadata<'_>) -> bool { + true + } + + fn new_span(&self, _span: &tracing::span::Attributes<'_>) -> tracing::span::Id { + tracing::span::Id::from_u64(1) + } + + fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {} + + fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {} + + fn event(&self, event: &tracing::Event<'_>) { + let mut capture = MessageCapture(None); + event.record(&mut capture); + let message = capture.0.unwrap_or_default(); + self.0 + .lock() + .expect("capture buffer") + .push((*event.metadata().level(), message)); + } + + fn enter(&self, _span: &tracing::span::Id) {} + + fn exit(&self, _span: &tracing::span::Id) {} + } + #[test] fn sd_notify_ready_noops_without_notify_socket() { - sd_notify_ready(None); + let subscriber = CapturingSubscriber::default(); + tracing::subscriber::with_default(subscriber.clone(), || sd_notify_ready(None)); + let events = subscriber.events(); + assert!( + events.is_empty(), + "no notify socket must be a silent no-op, got events: {events:?}" + ); } #[test] @@ -590,7 +655,17 @@ mod sd_notify_tests { fn sd_notify_ready_errors_when_socket_is_unreachable() { let dir = tempfile::tempdir().expect("tempdir"); let path = dir.path().join("missing").join("notify.sock"); - sd_notify_ready(Some(path.as_os_str())); + let subscriber = CapturingSubscriber::default(); + tracing::subscriber::with_default(subscriber.clone(), || { + sd_notify_ready(Some(path.as_os_str())); + }); + let events = subscriber.events(); + assert!( + events.iter().any(|(level, message)| { + *level == tracing::Level::WARN && message.contains("sendto failed") + }), + "unreachable notify socket must be reported, got events: {events:?}" + ); } } From 01e8edab3432822c4aaa8444019cae810251f2f5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:48:37 -0700 Subject: [PATCH 011/726] test(d2b-bus): assert every bus metric emit stays in the closed label set --- packages/d2b-bus/src/metrics.rs | 177 ++++++++++++++++++++++++++++---- 1 file changed, 159 insertions(+), 18 deletions(-) diff --git a/packages/d2b-bus/src/metrics.rs b/packages/d2b-bus/src/metrics.rs index 24fe35787..e01a33f32 100644 --- a/packages/d2b-bus/src/metrics.rs +++ b/packages/d2b-bus/src/metrics.rs @@ -612,24 +612,165 @@ mod tests { fn emitter_records_only_closed_bus_labels() { let emitter = BoundedEmitter::new("/nonexistent", 16 * 1024).unwrap(); let metrics = BusMetrics::new(emitter); - metrics.route( - &ServiceName::parse("d2b.resource.v3").unwrap(), - BusDirection::Host, - BusRouteOutcome::Ok, - 0.005, - ); - metrics.session_active(BusTransport::Unix, 1); - metrics.registration(BusDirection::Local, BusRegistrationOutcome::Accepted); - metrics.stream_active(BusDirection::Guest, 1); - metrics.stream_result(BusDirection::Guest, BusStreamOutcome::Accepted); - metrics.credits(BusDirection::Guest, 64); - metrics.backpressure( - BusDirection::Guest, - BusStreamKind::Stream, - BusBackpressureReason::Credit, - ); - metrics.rejection(BusDirection::Local, BusRejectionOutcome::Denied); - metrics.disconnect(BusDirection::ZoneLink, BusDisconnectOutcome::Abandoned); + + // Every label value the closed bus enums can produce must be + // admitted by the metric descriptors. A label that escapes the + // closed set (a new variant, a typo in `as_str`) fails the emit + // here instead of passing silently. + let service = "d2b.resource.v3"; + for direction in BusDirection::ALL { + let direction = direction.as_str(); + for outcome in [ + BusRouteOutcome::Ok, + BusRouteOutcome::Denied, + BusRouteOutcome::NotFound, + BusRouteOutcome::Error, + ] { + metrics + .emit( + BusMetric::RouteTotal, + BTreeMap::from([ + ("service".to_owned(), service.to_owned()), + ("direction".to_owned(), direction.to_owned()), + ("outcome".to_owned(), outcome.as_str().to_owned()), + ]), + 1.0, + ) + .expect("route labels stay in the closed set"); + } + metrics + .emit( + BusMetric::RouteDuration, + BTreeMap::from([ + ("service".to_owned(), service.to_owned()), + ("direction".to_owned(), direction.to_owned()), + ]), + 0.005, + ) + .expect("route duration labels stay in the closed set"); + for outcome in [ + BusRegistrationOutcome::Accepted, + BusRegistrationOutcome::Rejected, + ] { + metrics + .emit( + BusMetric::RegistrationTotal, + BTreeMap::from([ + ("direction".to_owned(), direction.to_owned()), + ("outcome".to_owned(), outcome.as_str().to_owned()), + ]), + 1.0, + ) + .expect("registration labels stay in the closed set"); + } + metrics + .emit( + BusMetric::StreamActive, + BTreeMap::from([("direction".to_owned(), direction.to_owned())]), + 1.0, + ) + .expect("stream active labels stay in the closed set"); + for outcome in [ + BusStreamOutcome::Accepted, + BusStreamOutcome::Rejected, + BusStreamOutcome::Closed, + ] { + metrics + .emit( + BusMetric::StreamTotal, + BTreeMap::from([ + ("direction".to_owned(), direction.to_owned()), + ("outcome".to_owned(), outcome.as_str().to_owned()), + ]), + 1.0, + ) + .expect("stream result labels stay in the closed set"); + } + metrics + .emit( + BusMetric::CreditBytes, + BTreeMap::from([("direction".to_owned(), direction.to_owned())]), + 64.0, + ) + .expect("credit labels stay in the closed set"); + for kind in [BusStreamKind::Control, BusStreamKind::Stream] { + for reason in [ + BusBackpressureReason::Credit, + BusBackpressureReason::BufferFull, + BusBackpressureReason::Capacity, + ] { + metrics + .emit( + BusMetric::BackpressureTotal, + BTreeMap::from([ + ("direction".to_owned(), direction.to_owned()), + ("kind".to_owned(), kind.as_str().to_owned()), + ("reason".to_owned(), reason.as_str().to_owned()), + ]), + 1.0, + ) + .expect("backpressure labels stay in the closed set"); + } + } + for outcome in [ + BusRejectionOutcome::Denied, + BusRejectionOutcome::NotFound, + BusRejectionOutcome::Error, + BusRejectionOutcome::Quota, + ] { + metrics + .emit( + BusMetric::RejectionTotal, + BTreeMap::from([ + ("direction".to_owned(), direction.to_owned()), + ("outcome".to_owned(), outcome.as_str().to_owned()), + ]), + 1.0, + ) + .expect("rejection labels stay in the closed set"); + } + for outcome in [ + BusDisconnectOutcome::Abandoned, + BusDisconnectOutcome::Cancel, + BusDisconnectOutcome::Revoked, + BusDisconnectOutcome::Error, + ] { + metrics + .emit( + BusMetric::DisconnectTotal, + BTreeMap::from([ + ("direction".to_owned(), direction.to_owned()), + ("outcome".to_owned(), outcome.as_str().to_owned()), + ]), + 1.0, + ) + .expect("disconnect labels stay in the closed set"); + } + } + + // The active-session transport label is a separate closed domain. + for transport in BusTransport::ALL { + metrics + .emit( + BusMetric::SessionActive, + BTreeMap::from([("transport".to_owned(), transport.as_str().to_owned())]), + 1.0, + ) + .expect("session transport labels stay in the closed set"); + } + + // Unknown services collapse to the catalog bucket, which is closed. + metrics + .emit( + BusMetric::RouteTotal, + BTreeMap::from([ + ("service".to_owned(), "bus".to_owned()), + ("direction".to_owned(), "local".to_owned()), + ("outcome".to_owned(), "ok".to_owned()), + ]), + 1.0, + ) + .expect("the collapsed service bucket stays in the closed set"); } #[test] From 8b191fe399a65f3876e44f658685545f8063e141 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:52:45 -0700 Subject: [PATCH 012/726] test(resource-runtime): drop the redundant revision-display assertion --- packages/d2b-resource-runtime/src/revision.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/d2b-resource-runtime/src/revision.rs b/packages/d2b-resource-runtime/src/revision.rs index 86d522971..1404e2970 100644 --- a/packages/d2b-resource-runtime/src/revision.rs +++ b/packages/d2b-resource-runtime/src/revision.rs @@ -154,7 +154,6 @@ mod tests { fn display_shows_epoch_and_sequence() { let revision = RuntimeRevision::new(1_728_000_000, 42); let rendered = revision.to_string(); - assert!(rendered.contains("1728000000"), "got: {rendered}"); assert!(rendered.contains('4'), "got: {rendered}"); assert!(rendered.contains("e1728000000+42"), "got: {rendered}"); } From 092b0f3d365803ec699144992a0c24580de8a304 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:58:07 -0700 Subject: [PATCH 013/726] fix(broker): refuse a malformed audit join instead of expecting it DispatchAuditContext::from_request parsed the authoritative audit join with CanonicalAuditDigest::parse and expected on failure, leaving a latent panic in the wire path. Convert both parses to the typed BrokerError::Protocol refusals the sibling from_request_with_join path already uses, with the same wording. The parse input is a computed canonical digest at HEAD, so the refusal leg is unreachable without a join-shape change; the new test pins the typed-refusal surface (valid join builds the context; a mismatched supplied join is refused with the typed Protocol error) and the refusal was observed under a mutation that made the join return raw non-canonical strings. --- packages/d2b-broker/src/runtime.rs | 59 +++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 31adecdcf..e438c0ae5 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -2413,14 +2413,17 @@ impl DispatchAuditContext { } #[cfg(not(feature = "layer1-bootstrap"))] { - let join = request - .authoritative_audit_join() - .map(|(zone_id, operation_identity)| AuditJoinContext { + let join = match request.authoritative_audit_join() { + Some((zone_id, operation_identity)) => Some(AuditJoinContext { zone_id: CanonicalAuditDigest::parse(zone_id) - .expect("authoritative zone digest"), + .map_err(|_| BrokerError::Protocol("audit zone identity invalid".to_owned()))?, operation_identity: CanonicalAuditDigest::parse(operation_identity) - .expect("authoritative operation digest"), - }); + .map_err(|_| { + BrokerError::Protocol("audit operation identity invalid".to_owned()) + })?, + }), + None => None, + }; Self::from_request_with_join(request, peer_pid, caller_role, join.as_ref()) } } @@ -17270,6 +17273,50 @@ mod tests { let _ = fs::remove_dir_all(&root); } + /// A malformed authoritative audit join must yield the typed protocol + /// refusal, never a panic. The parse-failure leg cannot be driven at + /// HEAD: `authoritative_audit_join` computes canonical digests, so + /// `CanonicalAuditDigest::parse` always succeeds on its output (the + /// refusal was observed under a mutation that made the join return raw + /// strings - see the wave-0 report). This test pins the typed-refusal + /// surface of the converted call: a valid join builds the context + /// without panicking, and a supplied join that mismatches the request's + /// canonical join is refused with the typed Protocol error. + #[cfg(not(feature = "layer1-bootstrap"))] + #[test] + fn from_request_refuses_a_malformed_audit_join_with_a_typed_protocol_error() { + let request = store_sync_request(7); + let caller_role = CallerRole::AdminUid { uid: 1000 }; + + let context = DispatchAuditContext::from_request(&request, 4242, &caller_role) + .expect("valid audit join builds the dispatch context"); + let (zone_id, operation_identity) = request + .authoritative_audit_join() + .expect("store sync carries an authoritative join"); + let join = context.audit_join.as_ref().expect("join recorded"); + assert_eq!(join.zone_id.as_str(), zone_id.as_str()); + assert_eq!(join.operation_identity.as_str(), operation_identity.as_str()); + + let foreign_join = AuditJoinContext { + zone_id: CanonicalAuditDigest::parse( + "sha256:0000000000000000000000000000000000000000000000000000000000000000", + ) + .expect("fixed canonical digest"), + operation_identity: CanonicalAuditDigest::parse( + "sha256:1111111111111111111111111111111111111111111111111111111111111111", + ) + .expect("fixed canonical digest"), + }; + let error = DispatchAuditContext::from_request_with_join( + &request, + 4242, + &caller_role, + Some(&foreign_join), + ) + .expect_err("a mismatched supplied join must be refused"); + assert!(matches!(error, BrokerError::Protocol(_))); + } + /// A second sync of the same closure must take the fast path and still /// emit EXACTLY ONE allowed record carrying `skipped_fast_path` + /// `fast_path`. From 628e27af15a66d4fdfa59d816c8498c697a699cf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 00:58:45 -0700 Subject: [PATCH 014/726] audit: record the wave-0 dispositions and the branch changelog fragment Every wave-0 row carries an outcome, the commit that carries its change, and its deviation where the re-verification changed the row's premise. The fragment states the consumer-visible effect for the branch's first wave. --- .../refactor-rust-skills-remediation.md | 5 ++++ .../2026-09-24-rust-skills-audit/ledger.md | 30 ++++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 changelog.d/refactor-rust-skills-remediation.md diff --git a/changelog.d/refactor-rust-skills-remediation.md b/changelog.d/refactor-rust-skills-remediation.md new file mode 100644 index 000000000..0a65a2bc2 --- /dev/null +++ b/changelog.d/refactor-rust-skills-remediation.md @@ -0,0 +1,5 @@ +### Fixed + +- Repaired three tests that could not fail - the daemon readiness pair, the bus telemetry closed-label check, and the Wayland display registry handlers - so each one now fails when the behaviour it names breaks, and dropped a redundant revision-display assertion that could never fail either way. +- Malformed wire input no longer panics the broker, the daemon runtime, or the Wayland policy engine: a malformed authoritative audit join, a malformed broker zone digest, and a malformed driver zone token now return typed refusals at those boundaries. +- Moved blocking reaping, file locking, ACL application, and NSS group lookup off the broker's async executor workers, so a busy executor no longer stalls on host syscalls. diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index d02ca007c..10e73197e 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -2,7 +2,9 @@ Baseline: branch `refactor-rust-skills-remediation`, base commit `147a536a0` (the audit baseline `v3` @ `6ebdd4cec` plus the audit corpus commit). Authority: `docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md` (R1-R14, KTD1-KTD11). Corpus: `README.md` and `lane/`. -One row per finding id. `outcome` is filled by the owning wave when it disposes of the row: `applied`, `applied-variant` (the stated fix held but needed a minimal correction), `already-fixed` (claim re-verified stale at HEAD), `escalated` (moved to the owning wave named in `escalation`), `policy-confirmed` (recorded no-op citing its policy), `needs-contract` (deferred to the contract-adjacent wave), `reclassified` (severity/verdict changed on re-verification, reason recorded). `anchor` is the apply-time anchor when the wave re-located it; the seed anchor comes from the corpus row. Empty cells mean the row is not yet disposed. +One row per finding id. `outcome` is filled by the owning wave when it disposes of the row: `applied`, `applied-variant` (the claim or the stated fix needed a minimal correction or a recorded deviation), `skipped-stale` (the claim does not hold at HEAD; no change made), `already-fixed` (the stated fix is already present in the tree), `escalated` (moved to the owning wave named in `escalation`), `policy-confirmed` (recorded no-op citing its policy), `needs-contract` (deferred to the contract-adjacent wave), `reclassified` (severity or verdict changed on re-verification, reason recorded). + +Corpus caveat: the audit read its sources through a tool path that rewrites long digit runs, so at least one row (RS-0916) quotes a literal that exists nowhere in the tree or in git history. Every row's true state is re-verified at apply time (R3) and the ledger records the corrected finding; the corpus row text is left as the audit wrote it. `anchor` is the apply-time anchor when the wave re-located it; the seed anchor comes from the corpus row. Empty cells mean the row is not yet disposed. Every id must appear exactly once and end `applied`, `already-fixed`, `policy-confirmed`, or `needs-contract` at close-out; `escalated` rows carry the escalation history and their final outcome (R1, KTD1). @@ -264,7 +266,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_` | | | | `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | | `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_op` | | | -| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | | | +| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | escalated | U1 | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | wave 0 applied the panicking constructor member (RS-0516); the five remaining provider-crate zone/key_ref member sites are the family wave's | U5 | | `RS-0263` | `type` | `d2b` | low | actionable | leaf | | | | `context.rs:713, context.rs:2751, context.rs:801` | | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/exec.rs:90, packages/d2b/src/exec.rs:345, packages/d2b/src/endpoint.rs:34` | | | | `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | | | | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | | | @@ -485,7 +487,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | | | | `packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, ` | | | | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:230` | | | | `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b` | | | -| `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | | | | `packages/d2b-broker/src/runtime.rs:2419, packages/d2b-broker/src/runtime.rs:2422` | | | +| `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | | `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | | | | `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-broker/src/ops/hosts.rs:149, packag` | | | | `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360` | | | @@ -546,7 +548,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-pro` | | | | `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | | | | `packages/d2b-provider-user/src/driver.rs:118-124, packages/d2b-contracts/src/failure_kinds` | | | | `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | | | | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-bindi` | | | -| `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-wayland` | | | +| `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 (driver-args class member key_ref; RS-0962) | | `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | | | | `packages/d2b-provider-wayland-session/src/wayland_session.rs:73` | | | | `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:867-868` | | | | `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309` | | | @@ -568,7 +570,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0534` | `err` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:1956` | | | | `RS-0536` | `err` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:3436` | | | | `RS-0528` | `err` | `d2bd` | low | actionable | family | | | | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | | | -| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | | | | `broker_transport.rs:63, broker_transport.rs:65` | | | +| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | applied-variant | U1 | ebb3831b1 | packages/d2bd-runtime/src/broker_transport.rs, packages/d2bd/src/composition.rs | claim re-verified unreachable at HEAD (digests canonicalized before parse); applied anyway to remove the latent expect and mirror the sibling typed refusal - callers updated | | | `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | | | | `wire.rs:529-536` | | | | `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/exec_session.rs:939` | | | | `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:132` | | | @@ -869,10 +871,10 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34` | | | | `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | | | | `packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189` | | | | `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | | | | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support` | | | -| `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | | | | `packages/d2b-broker/src/runtime.rs:11815, packages/d2b-broker/src/kernel_ops.rs:919, packa` | | | -| `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | | | | `packages/d2b-broker/src/ops/swtpm_dir.rs:770, packages/d2b-broker/src/sys.rs:1866-1893, pa` | | | -| `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | | | | `packages/d2b-broker/src/ops/media.rs:2100, packages/d2b-broker/src/ops/media.rs:2126` | | | -| `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | | | | `packages/d2b-broker/src/ops/host_generation_handoff.rs:246, packages/d2b-broker/src/ops/ho` | | | +| `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | 9b64eaa27 | packages/d2b-broker/src/runtime.rs (reap fn; kernel_ops.rs callers) | bounded WNOHANG reap poll replaces the blocking waitid; orphaned helpers deleted | | +| `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | 25dfa3aee | packages/d2b-broker/src/sys.rs, packages/d2b-broker/src/ops/swtpm_dir.rs | setfacl shellout moved behind an async wrapper on a bounded worker | | +| `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | a6d8fb022 | packages/d2b-broker/src/ops/media.rs | nss group lookup hoisted to a LazyLock, off the per-write path | | +| `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | f4f09c74c | packages/d2b-broker/src/ops/host_generation_handoff.rs | flock wait moved to a bounded worker (sanctioned allow reason) | | | `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | | `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | | | | `packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages` | | | | `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | | | @@ -883,7 +885,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/observe.rs:255-260` | | | | `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/testing.rs:30, src/testing.rs:19` | | | | `RS-0850` | `async` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833` | | | -| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | | | | `packages/d2b-provider-user/src/probe.rs:48, packages/d2b-provider-user/src/probe.rs:63, pa` | | | +| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | policy-confirmed | U1 | | `packages/d2b-provider-user/src/probe.rs:48, packages/d2b-provider-user/src/probe.rs:63, pa` | recorded no-op (KTD8/R14): the deliberate bounded NSS probe is the crate's documented contract - packages/d2b-provider-user/README.md:50-55, src/probe.rs:1-5; audit cluster README.md:2806 | | | `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | | | | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | | `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:5518-5530` | | | | `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_ef` | | | @@ -903,7 +905,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | | `RS-0864` | `test` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:523` | | | | `RS-0865` | `test` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.` | | | -| `RS-0867` | `test` | `d2b-bus` | high | actionable | leaf | | | | `packages/d2b-bus/src/metrics.rs:612-633, packages/d2b-bus/src/metrics.rs:451-534` | | | +| `RS-0867` | `test` | `d2b-bus` | high | actionable | leaf | applied | U1 | 01e8edab3 | packages/d2b-bus/src/metrics.rs | test now drives BusMetrics::emit over every closed label domain; mutation-verified | | | `RS-0868` | `test` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_te` | | | | `RS-0869` | `test` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/operations.rs:1057-1060` | | | | `RS-0870` | `test` | `d2b-contracts-control` | medium | actionable | leaf | | | | `public_wire.rs:167, public_wire.rs:175` | | | @@ -932,7 +934,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0896` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, ` | | | | `RS-0897` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `src/reconcile_state.rs:51-308, src/state_machine.rs:98-100` | | | | `RS-0895` | `test` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `tests/conformance.rs:63-66` | | | -| `RS-0898` | `test` | `d2b-provider-display-wayland` | high | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3213, packages/d2b-provi` | | | +| `RS-0898` | `test` | `d2b-provider-display-wayland` | high | actionable | leaf | applied | U1 | 3b964169f | packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs | registry-handler tests assert advertised-global outcomes; mutation-verified | | | `RS-0900` | `test` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | | | | `src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225` | | | | `RS-0899` | `test` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `tests/provider_lifecycle.rs:536` | | | | `RS-0901` | `test` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `tests/error_redaction.rs:17` | | | @@ -950,7 +952,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0914` | `test` | `d2b-resource-api` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src` | | | | `RS-0913` | `test` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:3377` | | | | `RS-0915` | `test` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/p` | | | -| `RS-0916` | `test` | `d2b-resource-runtime` | high | actionable | leaf | | | | `packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revis` | | | +| `RS-0916` | `test` | `d2b-resource-runtime` | high | actionable | leaf | applied-variant | U1 | 8b191fe39 | packages/d2b-resource-runtime/src/revision.rs (display test) | claim corrected: the committed line was a tautological bare-epoch assertion (not an assertion that cannot pass); the audit's quoted literal is a tool-output redaction artifact, absent from the file and from git history; the row's own fix text applied by deleting the redundant assertion | | | `RS-0917` | `test` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/revision.rs:182` | | | | `RS-0918` | `test` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/lib.rs:66` | | | | `RS-0919` | `test` | `d2b-session` | low | actionable | leaf | | | | `tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139` | | | @@ -959,7 +961,7 @@ Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit messag | `RS-0922` | `test` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helpe` | | | | `RS-0923` | `test` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/engine.rs:3333` | | | | `RS-0924` | `test` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/router.rs:517` | | | -| `RS-0925` | `test` | `d2bd-runtime` | high | actionable | leaf | | | | `runtime_process.rs:543-546, runtime_process.rs:589-594` | | | +| `RS-0925` | `test` | `d2bd-runtime` | high | actionable | leaf | applied | U1 | bea8fa96d | packages/d2bd-runtime/src/runtime_process.rs | sd_notify tests assert observable tracing outcomes; two mutations verified | | | `RS-0926` | `test` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/daemon_audit.rs:2367` | | | | `RS-0928` | `test` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079` | | | | `RS-0927` | `test` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:705` | | | From b76b66fc603a85e7af1d995275141f5313a64744 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:04:34 -0700 Subject: [PATCH 015/726] audit: record the green baseline and start the wave-gate table The untouched head passes the whole gate set - scan, census, 988 Bazel tests, and 11 host-integration checks - so every wave's bar is to stay green instead of improving a recorded red. --- .../2026-09-24-rust-skills-audit/ledger.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 10e73197e..ce7b93818 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -10,14 +10,22 @@ Every id must appear exactly once and end `applied`, `already-fixed`, `policy-co ## Baseline record (gate set at the untouched head) -Filled by wave 0 from `.scratch/w0-baseline/` runs; see the wave-0 commit message for the recorded result. +Measured at `147a536a0` in a dedicated gates worktree before any wave-0 fix landed. The whole gate set is green at the baseline, so a wave's bar is to stay green rather than to improve a red gate; any red a wave introduces is its own. | gate | command | result at baseline | attribution | | --- | --- | --- | --- | -| security scan | `D2B_SCAN_BASE_SHA=6ebdd4cec tests/tools/security-scan.sh` | pending | - | -| blocking census | `make check-census` | pending | - | -| Layer-1 aggregate | `make check` | pending | - | -| host integration | `make test-host-integration` | pending | - | +| security scan | `D2B_SCAN_BASE_SHA=6ebdd4cec tests/tools/security-scan.sh` | pass (clean) | none | +| blocking census | `make check-census` | pass (no crate above its committed baseline) | none | +| Layer-1 aggregate | `make check` | pass (988 of 988 tests) | none | +| host integration | `make test-host-integration` | pass (11 of 11 vmChecks) | Attic closure-upload warning only, non-fatal | + +## Wave gates + +Each wave closes on the same gate set, run on the wave's integrated head in the gates worktree. `base` is the commit the scan measures changed lines against. + +| wave | head | security scan | census | Layer-1 aggregate | host integration | notes | +| --- | --- | --- | --- | --- | --- | --- | +| U1 | `628e27af1` | pending | pending | pending | pending | - | ## Findings (965 rows) From 11bbfe41a32bb20f969f0d4827b2dd55b78fbe4c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:30:23 -0700 Subject: [PATCH 016/726] async-gate: refresh the inventory for the wave-0 line shifts Six marked method-call sites moved lines when the broker's blocking work left the executor; the reasons and the site set are unchanged. --- packages/xtask/data/async-gate-inventory.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index f029681ac..cd769e72a 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -3,12 +3,12 @@ "sites": [ { "file": "packages/d2b-broker/src/ops/host_generation_handoff.rs", - "line": 242, + "line": 245, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { "file": "packages/d2b-broker/src/ops/host_generation_handoff.rs", - "line": 430, + "line": 490, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { @@ -123,22 +123,22 @@ }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8129, + "line": 8127, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8196, + "line": 8194, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8413, + "line": 8411, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8490, + "line": 8488, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 2f82cd641e47168549505245066825d768584dcc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:38:03 -0700 Subject: [PATCH 017/726] audit: close the U1 wave gate green Scan, census, 988 Bazel tests, and 11 host-integration checks pass on the integrated head; the one retry is recorded with its attribution. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index ce7b93818..2bc7fd7aa 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -25,7 +25,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | wave | head | security scan | census | Layer-1 aggregate | host integration | notes | | --- | --- | --- | --- | --- | --- | --- | -| U1 | `628e27af1` | pending | pending | pending | pending | - | +| U1 | `11bbfe41a` | pass | pass | pass (988 of 988 tests) | pass (11 of 11 vmChecks) | First attempt flaked on the load-sensitive `daemon_state_persistence` kill-during-startup race (passes standalone, not an audit row); the retry is green. The head carries the refreshed async-gate inventory for the broker line shifts. | ## Findings (965 rows) From fbf92683a899ae1604050c40209bea0aa742a3ec Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:51:15 -0700 Subject: [PATCH 018/726] bus: avoid clone-and-index and validation double-clone paths --- packages/d2b-bus/src/operations.rs | 30 +++---- packages/d2b-bus/src/router.rs | 78 +++++++++++++++---- packages/d2b-bus/src/session/contract.rs | 66 ++++++++++------ packages/d2b-bus/src/session/prologue.rs | 30 +++++-- .../src/controller_assignment.rs | 22 ++++-- 5 files changed, 160 insertions(+), 66 deletions(-) diff --git a/packages/d2b-bus/src/operations.rs b/packages/d2b-bus/src/operations.rs index 74e7f3f51..e965dd927 100644 --- a/packages/d2b-bus/src/operations.rs +++ b/packages/d2b-bus/src/operations.rs @@ -21,7 +21,12 @@ pub const DEFAULT_MAX_OPERATIONS_PER_SESSION: usize = 256; pub struct OperationId(String); impl OperationId { - /// Parse a bounded printable ASCII identifier. + /// Parse a bounded printable ASCII identifier.. + /// + /// # Errors + /// Returns `OperationError::InvalidOperationId` when the value is empty, + /// longer than 128 bytes, or contains a character outside the ASCII + /// alphanumeric or `-`/`_`/`.`/`:` set. pub fn parse(value: impl Into) -> Result { let value = value.into(); if value.is_empty() @@ -121,6 +126,10 @@ struct CancellationState { notify: Notify, } +/// An opaque cancellation token minted only by the bus for one operation attempt. +/// +/// Construction is crate-private; a clone shares the same attempt's token, and +/// [`Self::is_cancelled`] observes whether the attempt was cancelled. #[derive(Clone)] pub struct Cancellation(Arc); @@ -298,21 +307,14 @@ impl PendingCancelDeliveries { } pub(crate) fn abort_destination(&self, session: SessionId) { - let tasks = { + let aborted = { let mut entries = self.lock_entries(); - let mut tasks = Vec::new(); - entries.retain(|entry| { - if entry.destination == session { - tasks.push(entry.task.clone()); - false - } else { - true - } - }); - tasks + let (aborted, kept) = entries.drain(..).partition(|entry| entry.destination == session); + *entries = kept; + aborted }; - for task in tasks { - task.abort(); + for entry in aborted { + entry.task.abort(); } } diff --git a/packages/d2b-bus/src/router.rs b/packages/d2b-bus/src/router.rs index 88b0afe4a..29072c0e9 100644 --- a/packages/d2b-bus/src/router.rs +++ b/packages/d2b-bus/src/router.rs @@ -64,7 +64,9 @@ use crate::{ /// Default maximum bytes in one method payload. pub const DEFAULT_MAX_PAYLOAD_BYTES: usize = 1024 * 1024; +/// Default maximum routes one source session may hold concurrently. pub const DEFAULT_MAX_ROUTES_PER_SESSION: usize = 128; +/// Default maximum routes one bus may hold across all sessions. pub const DEFAULT_MAX_TOTAL_ROUTES: usize = 4096; const FIRST_CORRELATION_ID: u32 = RESERVED_CORRELATION_MAX + 1; const DEFAULT_MAX_CORRELATIONS_PER_GENERATION: u64 = @@ -477,7 +479,7 @@ impl ResourceCall { assignment, mutations, } => { - if ScopedCommitTransport::new(assignment.clone(), mutations.clone()).is_err() { + if ScopedCommitTransport::validate(&assignment, &mutations).is_err() { return Err(BusError::InvalidResourceCall); } ( @@ -1122,36 +1124,59 @@ pub struct ZoneBus { core: Arc, } +/// One terminal bus-observable outcome class for an operation attempt. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BusEvent { + /// A method-invocation attempt ended in error or cancellation. Invoke, + /// A named-stream operation attempt ended in error or cancellation. OpenStream, + /// A cancellation attempt ended in error or was abandoned. Cancel, + /// A deferred cleanup attempt failed or was abandoned. Cleanup, + /// An expired operation tombstone was evicted. TombstoneEviction, } +/// Why one terminal bus outcome was recorded through [`BusObserver::record`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BusFailureReason { + /// The bus authorization layer refused the operation. Authorization, + /// The operation's route shape, registry, or reference was invalid. Route, + /// The operation's source session was mismatched or closed. Session, + /// An operation or stream capacity limit was exceeded. Capacity, + /// The operation or stream was shed under backpressure. Backpressure, + /// The operation's route was revoked. RouteRevoked, + /// The operation outlived its deadline. Deadline, + /// The operation attempt was cancelled. Cancelled, + /// The endpoint could not authenticate the source. Authentication, + /// The endpoint or bus generation moved beneath the operation. Generation, + /// A transport or endpoint delivery failure occurred. Transport, + /// A protocol or wire-shape failure occurred. Protocol, + /// An endpoint failed without a more specific class. Endpoint, + /// The operation's owner abandoned it. Abandoned, + /// The stream was shed for exceeding the per-source retention bound. StreamShed, + /// The operation hit the per-source retention bound. PerSourceRetention, + /// The operation hit the global retention bound. GlobalRetention, } - impl BusFailureReason { const fn from_error(error: &BusError) -> Self { match error { @@ -1184,10 +1209,17 @@ impl BusFailureReason { } } +/// Observes terminal outcomes for the bus's operation attempts. +/// +/// The observer is invoked once per terminal attempt outcome; see +/// [`BusEvent`] for when each event fires and [`BusFailureReason`] for the +/// reason classes. pub trait BusObserver: Send + Sync { + /// Record one terminal outcome observed by the bus. fn record(&self, event: BusEvent, reason: BusFailureReason); } +/// A [`BusObserver`] that discards every recorded outcome. #[derive(Debug, Default)] pub struct NoopBusObserver; @@ -1770,10 +1802,10 @@ impl AuthoritativeUnixSubjectResolver { .subjects .lock() .unwrap_or_else(|poisoned| poisoned.into_inner()); - let matches = subjects + let mut matches = subjects .iter() .enumerate() - .filter(|(_, subject)| { + .filter_map(|(index, subject)| { let peer_matches = if *service == ServicePackage::ResourceV3 { subject .expected_peer @@ -1786,20 +1818,19 @@ impl AuthoritativeUnixSubjectResolver { .expected_peer_uid .is_some_and(|expected| peer.uid().as_raw() == expected) }; - peer_matches + (peer_matches && subject .service .as_ref() - .is_none_or(|expected| expected == service) - }) - .map(|(index, _)| index) - .collect::>(); - if matches.len() != 1 { - return Err(d2b_session::SessionError::new( + .is_none_or(|expected| expected == service)) + .then_some(index) + }); + let index = match (matches.next(), matches.next()) { + (Some(index), None) => index, + _ => return Err(d2b_session::SessionError::new( d2b_session::contract::SessionErrorCode::SubjectConfigurationMismatch, - )); - } - let index = matches[0]; + )), + }; if subjects[index].expected_peer.is_some() { Ok(subjects.swap_remove(index)) } else { @@ -1892,6 +1923,7 @@ struct InteractionSubjectRegistrar { authority: Arc, } +/// Committed identity material the bus installs for one interaction subject. pub struct CommittedInteractionSubjectInstallBody { pub zone: ZoneId, pub display_subject_ref: ResourceRef, @@ -3258,6 +3290,13 @@ impl ZoneRegistrar { /// Consume an authenticated candidate and install it only after native /// connect authorization succeeds. + /// + /// # Errors + /// Returns the seat's registration rejection when the candidate does not + /// pass the component-session admission gate; `BusError::SessionMismatch` + /// when the candidate is bound to a different Zone; the connect + /// authorization failure; or the registry admission failure (route shape, + /// capacity, or duplicate routing). pub async fn register_component_session( &mut self, session: AuthenticatedComponentSession, @@ -3705,7 +3744,16 @@ impl BusIngress { } } - /// Invoke a non-resource exact service method. +/// Invoke a non-resource exact service method.. +/// +/// # Errors +/// Returns `BusError::SessionClosed` when the bus or session is closed; +/// `BusError::RouteShape` for a non-method route, an oversized payload, or +/// an oversized response;the session's authorization or registry admission +/// failures otherwise;an endpoint rejection wrapped as `BusError::Endpoint`; +/// `BusError::Cancelled` or +/// `BusError::Operation(OperationError::DeadlineExceeded)` when the attempt is +/// cancelled or outlives its deadline. pub async fn invoke( &self, route: RouteKey, diff --git a/packages/d2b-bus/src/session/contract.rs b/packages/d2b-bus/src/session/contract.rs index 66566059c..e11f14f67 100644 --- a/packages/d2b-bus/src/session/contract.rs +++ b/packages/d2b-bus/src/session/contract.rs @@ -162,6 +162,13 @@ impl ZoneEndpointPolicy { /// Fail-closed on every appended Zone member and on a purpose offered /// under a class it does not permit. The class rule is the contract's own /// [`EndpointPurpose::permits_class`]; this module restates none of it. + /// + /// # Errors + /// Returns `ZonePolicyError::PurposeClassRejected` when the purpose class is + /// not permitted under the purpose, and `PurposeNotEncodable`, + /// `InitiatorRoleNotEncodable`, `ResponderRoleNotEncodable`, or + /// `ServiceNotEncodable` when the corresponding member has no + /// component-session spelling. pub fn lower(&self) -> Result { if !self.purpose.permits_class(self.purpose_class) { return Err(ZonePolicyError::PurposeClassRejected); @@ -941,6 +948,21 @@ impl RouteAdmissionVerifier { if route_admission_digest(&evidence.body) != evidence.seal { return Err(RouteAdmissionError::SealMismatch); } + self.verify_body(&evidence.body)?; + Ok(VerifiedRouteAdmission { + authority: Arc::clone(&self.authority), + body: evidence.body, + }) + } + + /// Re-check the runtime-owned authority state against one borrowed + /// admission body, without constructing owned evidence. + + + fn verify_body( + &self, + body: &RouteAdmissionBody, + ) -> Result<(), RouteAdmissionError> { let state = self .authority .state @@ -960,48 +982,48 @@ impl RouteAdmissionVerifier { return Err(RouteAdmissionError::SessionNotLive); } let now = (state.clock)(); - if evidence.body.expires_at_unix_ms <= evidence.body.issued_at_unix_ms - || evidence.body.expires_at_unix_ms - evidence.body.issued_at_unix_ms + if body.expires_at_unix_ms <= body.issued_at_unix_ms + || body.expires_at_unix_ms - body.issued_at_unix_ms > MAX_ROUTE_ADMISSION_LIFETIME_MS - || now < evidence.body.issued_at_unix_ms - || now >= evidence.body.expires_at_unix_ms + || now < body.issued_at_unix_ms + || now >= body.expires_at_unix_ms { return Err(RouteAdmissionError::Expired); } - if evidence.body.zone_link_uid != state.zone_link_uid { + if body.zone_link_uid != state.zone_link_uid { return Err(RouteAdmissionError::ZoneLinkMismatch); } - if evidence.body.edge != state.edge { + if body.edge != state.edge { return Err(RouteAdmissionError::EdgeMismatch); } - if evidence.body.controller_generation != state.controller_generation { + if body.controller_generation != state.controller_generation { return Err(RouteAdmissionError::ControllerGenerationMismatch); } - if evidence.body.reconnect_generation != state.session_binding.reconnect_generation() { + if body.reconnect_generation != state.session_binding.reconnect_generation() { return Err(RouteAdmissionError::ReconnectGenerationMismatch); } - if evidence.body.source_zone_uid != state.source_zone_uid { + if body.source_zone_uid != state.source_zone_uid { return Err(RouteAdmissionError::SourceZoneMismatch); } - if evidence.body.target_zone_uid != state.target_zone_uid { + if body.target_zone_uid != state.target_zone_uid { return Err(RouteAdmissionError::TargetZoneMismatch); } - if evidence.body.verb != state.verb { + if body.verb != state.verb { return Err(RouteAdmissionError::VerbMismatch); } - if evidence.body.required_capability != state.required_capability { + if body.required_capability != state.required_capability { return Err(RouteAdmissionError::CapabilityMismatch); } - if evidence.body.policy_revision != state.policy_revision { + if body.policy_revision != state.policy_revision { return Err(RouteAdmissionError::PolicyRevisionMismatch); } - if evidence.body.session_binding != state.session_binding { + if body.session_binding != state.session_binding { + + + return Err(RouteAdmissionError::SessionBindingMismatch); } - Ok(VerifiedRouteAdmission { - authority: Arc::clone(&self.authority), - body: evidence.body, - }) + Ok(()) } /// Atomically replace the runtime route policy snapshot. @@ -1047,13 +1069,7 @@ impl VerifiedRouteAdmission { let verifier = RouteAdmissionVerifier { authority: Arc::clone(&self.authority), }; - verifier - .verify(RouteAdmissionEvidence { - authority: Arc::clone(&self.authority), - seal: route_admission_digest(&self.body), - body: self.body.clone(), - }) - .map(|_| ()) + verifier.verify_body(&self.body) } pub const fn zone_link_uid(&self) -> &ResourceUid { diff --git a/packages/d2b-bus/src/session/prologue.rs b/packages/d2b-bus/src/session/prologue.rs index 5560b5c29..1ca098ae4 100644 --- a/packages/d2b-bus/src/session/prologue.rs +++ b/packages/d2b-bus/src/session/prologue.rs @@ -69,13 +69,21 @@ impl SubjectContextDigest { pub fn of_subject(context: &AuthenticatedSubjectContext) -> Self { let mut hasher = Sha256::new(); hasher.update(SUBJECT_CONTEXT_DOMAIN); + hash_resource_ref( + &mut hasher, + context.subject_ref().resource_type().as_str(), + context.subject_ref().name().as_str(), + ); + hash_resource_ref( + &mut hasher, + context.zone_ref().resource_type().as_str(), + context.zone_ref().name().as_str(), + ); for field in [ - context.subject_ref().to_canonical_string(), - context.zone_ref().to_canonical_string(), - context.session_purpose().as_str().to_owned(), - context.service().as_str().to_owned(), - evidence_class_label(context.evidence_class()).to_owned(), - locality_label(context.transport_binding().locality()).to_owned(), + context.session_purpose().as_str(), + context.service().as_str(), + evidence_class_label(context.evidence_class()), + locality_label(context.transport_binding().locality()), ] { // Each field is length-prefixed so no two distinct field tuples // can produce one concatenation. @@ -86,6 +94,16 @@ impl SubjectContextDigest { } } +/// Hash one canonical `type/name` reference in the same length-prefixed +/// form as its canonical string, without materializing that string. +fn hash_resource_ref(hasher: &mut Sha256, resource_type: &str, name: &str) { + let canonical_len = resource_type.len() + 1 + name.len(); + hasher.update((canonical_len as u64).to_be_bytes()); + hasher.update(resource_type.as_bytes()); + hasher.update(b"/"); + hasher.update(name.as_bytes()); +} + impl core::fmt::Debug for SubjectContextDigest { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("SubjectContextDigest()") diff --git a/packages/d2b-core-controller/src/controller_assignment.rs b/packages/d2b-core-controller/src/controller_assignment.rs index bbc27df11..5d866d185 100644 --- a/packages/d2b-core-controller/src/controller_assignment.rs +++ b/packages/d2b-core-controller/src/controller_assignment.rs @@ -446,19 +446,29 @@ pub struct ScopedCommitTransport { } impl ScopedCommitTransport { - /// Construct transport evidence from one admitted assignment call. - pub fn new( - assignment: AssignmentIdentity, - mutations: Vec, - ) -> Result { + /// Validate one admitted assignment call's evidence without taking + /// ownership of the identity or mutation list. + pub fn validate( + assignment: &AssignmentIdentity, + mutations: &[ScopedResourceMutation], + ) -> Result<(), AssignmentTransportError> { if mutations.is_empty() || mutations.len() > 128 || mutations.iter().any(|mutation| { - mutation.assignment() != &assignment || !transport_mutation_is_valid(mutation) + mutation.assignment() != assignment || !transport_mutation_is_valid(mutation) }) { return Err(AssignmentTransportError::Malformed); } + Ok(()) + } + + /// Construct transport evidence from one admitted assignment call. + pub fn new( + assignment: AssignmentIdentity, + mutations: Vec, + ) -> Result { + Self::validate(&assignment, &mutations)?; Ok(Self { assignment, mutations, From 4cbf82851942b099beeaf8a5484bf9d0d5800bac Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:58:02 -0700 Subject: [PATCH 019/726] d2b-resource-runtime: tighten manager facade docs, rpc dedupe, borrows, and Default --- packages/d2b-resource-runtime/src/manager.rs | 128 ++++++++++++++++--- 1 file changed, 110 insertions(+), 18 deletions(-) diff --git a/packages/d2b-resource-runtime/src/manager.rs b/packages/d2b-resource-runtime/src/manager.rs index 821170d50..309b4cf60 100644 --- a/packages/d2b-resource-runtime/src/manager.rs +++ b/packages/d2b-resource-runtime/src/manager.rs @@ -48,6 +48,7 @@ //! never touch disk (AE6, R11): they only update the in-memory view and //! publish. +/// The module declared name, asserted by the crate smoke test. pub const MODULE_NAME: &str = "manager"; use std::collections::{HashMap, HashSet}; @@ -204,8 +205,9 @@ impl ResourceView { /// generation N pass as readiness of generation N+1. pub fn observed_status(&self) -> Option { self.status - .clone() + .as_ref() .filter(|_| self.status_generation == Some(self.generation)) + .cloned() } /// The `status.resource` layer published **for this exact row @@ -847,7 +849,9 @@ impl ResourceManagerState { pub struct ResourceManagerArgs { /// The Zone this manager is the runtime authority for (KTD5). pub zone: String, + /// The single-writer spec store persisting desired rows. pub store: Arc, + /// The per-type provider registry producing resource drivers. pub providers: ProviderDirectory, pub hub: Arc, /// Manager-boundary admission hook (KTD2 execution decision). @@ -871,6 +875,7 @@ pub struct ResourceManagerArgs { } /// The per-Zone manager actor (spec section 4). +#[derive(Default)] pub struct ResourceManager; impl ResourceManager { @@ -879,12 +884,6 @@ impl ResourceManager { } } -impl Default for ResourceManager { - fn default() -> Self { - Self::new() - } -} - impl Actor for ResourceManager { type Msg = ResourceManagerMsg; type State = ResourceManagerState; @@ -1403,6 +1402,18 @@ async fn reconcile_children( } +/// Route one request/reply exchange through the manager mailbox. +async fn manager_rpc( + actor: &ActorRef, + build: impl FnOnce(oneshot::Sender>) -> ResourceManagerMsg, +) -> Result { + let (reply, rx) = oneshot::channel(); + actor + .send_message(build(reply)) + .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; + rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? +} + /// The manager endpoint injected into every driver context (R2): all /// durable child mutations and internal-watch registrations ride the manager /// mailbox; replies fire only after the commit (F1, AE1). @@ -1420,11 +1431,7 @@ impl ManagerActorEndpoint { &self, build: impl FnOnce(oneshot::Sender>) -> ResourceManagerMsg, ) -> Result { - let (reply, rx) = oneshot::channel(); - self.manager - .send_message(build(reply)) - .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; - rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? + manager_rpc(&self.manager, build).await } } @@ -1497,10 +1504,12 @@ pub struct ResourceManagerClient { } impl ResourceManagerClient { + /// Wrap the manager's actor handle as a caller-facing client. pub fn new(actor: ActorRef) -> Self { Self { actor } } + /// The underlying manager actor handle, for supervision wiring. pub fn actor(&self) -> &ActorRef { &self.actor } @@ -1509,13 +1518,20 @@ impl ResourceManagerClient { &self, build: impl FnOnce(oneshot::Sender>) -> ResourceManagerMsg, ) -> Result { - let (reply, rx) = oneshot::channel(); - self.actor - .send_message(build(reply)) - .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; - rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? + manager_rpc(&self.actor, build).await } + /// Apply one top-level desired resource; the row commits, then the + /// resource's actor starts (F1: the durable commit precedes the spawn). + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the manager channel is closed or + /// the request is dropped; [`ResourceError::AdmissionDenied`] when + /// mutation admission refuses; [`ResourceError::Provider`] when no + /// driver factory can produce the resource; [`ResourceError::Store`] on + /// durable store failure; [`ResourceError::DeletingConflict`] when the + /// row is marked deleting. pub async fn apply( &self, subject: MutationSubject, @@ -1524,6 +1540,14 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::Apply { subject, desired, reply }).await } + /// Ensure a desired row, optionally bound to an owner; an unknown owner + /// or a row of another Zone is refused. + /// + /// # Errors + /// + /// Beyond the [`Self::apply`] variants: + /// [`ResourceError::ManagerRpc`] also when the desired zone is not the + /// manager's zone or the named owner is not known to the manager. pub async fn ensure( &self, subject: MutationSubject, @@ -1533,6 +1557,15 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::Ensure { subject, owner, desired, reply }).await } + /// Mark a row deleting and run its cleanup; absent rows are a no-op. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the request cannot be routed; + /// [`ResourceError::AdmissionDenied`] when mutation admission refuses; + /// [`ResourceError::Store`] on durable store failure; + /// [`ResourceError::DeletingConflict`] when the row is already marked + /// deleting. pub async fn remove( &self, subject: MutationSubject, @@ -1541,10 +1574,21 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::Remove { subject, key, reply }).await } + /// The runtime view of one row, including the observed status of the + /// row's current generation when there is one. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the request cannot be routed. pub async fn get(&self, key: ResourceKey) -> Result, ResourceError> { self.rpc(|reply| ResourceManagerMsg::Get { key, reply }).await } + /// Every runtime view matching the selector. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the request cannot be routed. pub async fn list( &self, selector: ResourceSelector, @@ -1552,6 +1596,14 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::List { selector, reply }).await } + /// Open a gap-free watch on matching changes: the registration atomically + /// serves a list snapshot (from `after`, when servable) and live delivery. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the request cannot be routed; an + /// unsupported cursor (older or future epoch, or evicted from the ring) + /// is reported as [`WatchRegistration::Expired`] rather than an error. pub async fn watch( &self, selector: ExternalWatchSelector, @@ -1560,6 +1612,11 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::Watch { selector, after, reply }).await } + /// The stored desired row, without the runtime view. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the request cannot be routed. pub async fn get_row( &self, key: ResourceKey, @@ -1567,6 +1624,11 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::GetRow { key, reply }).await } + /// Every stored row owned by one owner uid. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the request cannot be routed. pub async fn list_owned( &self, owner_uid: [u8; 16], @@ -1574,6 +1636,16 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::ListOwned { owner_uid, reply }).await } + /// Ensure one child of `parent`. A child whose row already commits a + /// different owner is refused rather than re-parented (R8). + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the parent is unknown, the child + /// is owned by a different parent, or the request cannot be routed; + /// [`ResourceError::AdmissionDenied`], [`ResourceError::Provider`], + /// [`ResourceError::Store`], and + /// [`ResourceError::DeletingConflict`] as for [`Self::apply`]. pub async fn ensure_child( &self, parent: ResourceKey, @@ -1582,6 +1654,12 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::ChildEnsure { parent, child, reply }).await } + /// Register an internal watch routed to a running target actor. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the watch target has no running + /// actor or the request cannot be routed. pub async fn register_watch( &self, subscriber: ResourceKey, @@ -1590,10 +1668,25 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::RegisterWatch { registration, subscriber, reply }).await } + /// Cancel a watch allocated by [`Self::register_watch`]. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the request cannot be routed. pub async fn cancel_watch(&self, watch: WatchId) -> Result<(), ResourceError> { self.rpc(|reply| ResourceManagerMsg::CancelWatch { watch, reply }).await } + /// Declarative owned-child reconciliation: missing children are ensured, + /// obsolete children are removed, and children already deleting are + /// reported as obsolete. + /// + /// # Errors + /// + /// [`ResourceError::ManagerRpc`] when the owner is unknown, a child + /// would be re-parented, or the request cannot be routed; + /// [`ResourceError::AdmissionDenied`], [`ResourceError::Provider`], and + /// [`ResourceError::Store`] as for [`Self::apply`]. pub async fn reconcile_children( &self, owner: ResourceKey, @@ -1601,7 +1694,6 @@ impl ResourceManagerClient { ) -> Result { self.rpc(|reply| ResourceManagerMsg::ReconcileChildren { owner, desired, reply }).await } - } /// Owner filtering resolves the owner key to its stable uid against the From 0e6061c1e6ac5ab5c1163b9eeff97682b181d13c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:58:02 -0700 Subject: [PATCH 020/726] d2b-resource-runtime: document resource actor spawn, derive Default, and move the row once --- packages/d2b-resource-runtime/src/resource.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/d2b-resource-runtime/src/resource.rs b/packages/d2b-resource-runtime/src/resource.rs index b8b5cc5d6..49a5c8b41 100644 --- a/packages/d2b-resource-runtime/src/resource.rs +++ b/packages/d2b-resource-runtime/src/resource.rs @@ -33,6 +33,7 @@ //! condition that flips while the registration message is still queued //! notifies exactly once. No database participates on this path. +/// The module declared name, asserted by the crate smoke test. pub const MODULE_NAME: &str = "resource"; use std::collections::HashMap; @@ -674,6 +675,7 @@ impl ResourceActorState { /// Implements the plain [`ractor::Actor`] trait: U1 enabled ractor's default /// features only (no `actor-macros`), and the trait's RPITIT methods accept /// plain `async fn` implementations. +#[derive(Default)] pub struct ResourceActor; impl ResourceActor { @@ -682,12 +684,6 @@ impl ResourceActor { } } -impl Default for ResourceActor { - fn default() -> Self { - Self::new() - } -} - impl Actor for ResourceActor { type Msg = ResourceMsg; type State = ResourceActorState; @@ -702,7 +698,8 @@ impl Actor for ResourceActor { // provider fails the spawn AFTER the manager committed the row (F1 // durability boundary) - the row stays durable and a restart or a // later Ensure recovers it. - let driver = args.providers.create_driver(&args.row.key).await.map_err(|error| { + let row = args.row; + let driver = args.providers.create_driver(&row.key).await.map_err(|error| { ActorProcessingErr::from(format!("driver creation failed: {error}")) })?; let timers = Arc::new(ActorTimers::new(myself.get_cell())); @@ -711,7 +708,7 @@ impl Actor for ResourceActor { let (effect_tx, effect_rx) = mpsc::unbounded_channel(); let (watch_tx, watch_rx) = mpsc::unbounded_channel(); let ctx = ResourceContext::new( - args.row.clone(), + row.clone(), args.target, args.decoder.clone(), manager_endpoint.clone(), @@ -729,9 +726,9 @@ impl Actor for ResourceActor { retry_backoff: args.backoff, owner_key: args.owner_key, timers, - row: args.row.clone(), + deleting: row.deleting, status: ResourceStatus::Pending, - deleting: args.row.deleting, + row, driver, ctx, watchers: HashMap::new(), From 69d4b615fe37f1b4c4988d3f19d459efe7be473b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:58:03 -0700 Subject: [PATCH 021/726] d2b-resource-runtime: derive TargetDirectory Default and document binding handles --- packages/d2b-resource-runtime/src/target.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/d2b-resource-runtime/src/target.rs b/packages/d2b-resource-runtime/src/target.rs index d424fd5ab..7e5fe1f88 100644 --- a/packages/d2b-resource-runtime/src/target.rs +++ b/packages/d2b-resource-runtime/src/target.rs @@ -193,6 +193,7 @@ impl GuestTargetHandle { self.session_generation } + /// Whether a live session has ever been registered for this guest. pub const fn is_bound(&self) -> bool { self.session_generation.is_some() } @@ -483,6 +484,8 @@ pub struct TargetBinding { } impl TargetBinding { + /// Bind one resource's recorded assignment to the directory it resolves + /// through. pub fn new(directory: Arc, assignment: TargetAssignment) -> Self { Self { directory, assignment } } @@ -573,17 +576,11 @@ struct DirectoryState { /// that decides *whose* authority they may use. It never changes a resource's /// Zone identity, never synthesizes a desired resource in a guest namespace, /// and never deletes desired state because a target went away. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct TargetDirectory { inner: Arc>, } -impl Default for TargetDirectory { - fn default() -> Self { - Self::new() - } -} - impl TargetDirectory { pub fn new() -> Self { Self { inner: Arc::new(Mutex::new(DirectoryState::default())) } From 75d64d039bb07a5b946866a1bea94c32883afb76 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:58:03 -0700 Subject: [PATCH 022/726] d2b-resource-runtime: document target control surface and move json member values --- .../d2b-resource-runtime/src/guest_target.rs | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/packages/d2b-resource-runtime/src/guest_target.rs b/packages/d2b-resource-runtime/src/guest_target.rs index d53a65cd2..78b001c1d 100644 --- a/packages/d2b-resource-runtime/src/guest_target.rs +++ b/packages/d2b-resource-runtime/src/guest_target.rs @@ -202,6 +202,8 @@ pub struct TargetControlAssignment { } impl TargetControlAssignment { + /// A target-control assignment naming one owned resource and the session + /// generation it was bound under. pub fn new( source: ResourceKey, source_uid: [u8; 16], @@ -211,18 +213,22 @@ impl TargetControlAssignment { Self { source, source_uid, assignment_generation, session_generation } } + /// The owning resource key this assignment was recorded for. pub const fn source(&self) -> &ResourceKey { &self.source } + /// The owning resource's stable uid. pub const fn source_uid(&self) -> &[u8; 16] { &self.source_uid } + /// The desired-generation the assignment was recorded for.. pub const fn assignment_generation(&self) -> u64 { self.assignment_generation } + /// The guest session generation the assignment is bound to. pub const fn session_generation(&self) -> u64 { self.session_generation } @@ -446,6 +452,7 @@ pub struct GuestTargetRuntime { } impl GuestTargetRuntime { + /// The runtime authority for one guest target reference. pub fn new(reference: TargetRef) -> Self { Self { inner: Arc::new(GuestTargetInner { @@ -816,7 +823,7 @@ impl TargetControlFrame { TargetControlRequest::Delete { assignment } => json_request("delete", assignment), TargetControlRequest::Adopt { assignment } => json_request("adopt", assignment), }; - let frame = json_object(&[ + let frame = json_object([ ("protocol", Value::String(self.protocol.clone())), ("request", request), ]); @@ -842,24 +849,24 @@ impl TargetControlResponse { /// Encode this response for the target-control channel. pub fn encode(&self) -> Vec { let response = match self { - Self::Realized { realization } => json_object(&[ + Self::Realized { realization } => json_object([ ("kind", Value::String("realized".to_owned())), ("realization", json_realization(realization)), ]), - Self::Observed(observation) => json_object(&[ + Self::Observed(observation) => json_object([ ("kind", Value::String("observed".to_owned())), ("observation", json_observation(*observation)), ]), - Self::Deleted => json_object(&[("kind", Value::String("deleted".to_owned()))]), - Self::Adopted(adoption) => json_object(&[ + Self::Deleted => json_object([("kind", Value::String("deleted".to_owned()))]), + Self::Adopted(adoption) => json_object([ ("kind", Value::String("adopted".to_owned())), ("adoption", json_adoption(adoption)), ]), Self::SessionUnavailable => { - json_object(&[("kind", Value::String("session-unavailable".to_owned()))]) + json_object([("kind", Value::String("session-unavailable".to_owned()))]) } }; - let frame = json_object(&[("response", response)]); + let frame = json_object([("response", response)]); serde_json::to_vec(&frame).expect("target-control responses are JSON objects") } @@ -1001,16 +1008,16 @@ impl GuestTargetControl for TargetControlClient { } } -fn json_object(members: &[(&str, Value)]) -> Value { - let mut object = serde_json::Map::with_capacity(members.len()); +fn json_object(members: impl IntoIterator) -> Value { + let mut object = serde_json::Map::new(); for (name, value) in members { - object.insert((*name).to_owned(), value.clone()); + object.insert(name.to_owned(), value); } Value::Object(object) } fn json_key(key: &ResourceKey) -> Value { - json_object(&[ + json_object([ ("zone", Value::String(key.zone.clone())), ("typeName", Value::String(key.type_name.clone())), ("name", Value::String(key.name.clone())), @@ -1018,7 +1025,7 @@ fn json_key(key: &ResourceKey) -> Value { } fn json_assignment(assignment: &TargetControlAssignment) -> Value { - json_object(&[ + json_object([ ("source", json_key(assignment.source())), ("sourceUid", Value::String(hex_encode(&assignment.source_uid()[..]))), ( @@ -1033,14 +1040,14 @@ fn json_assignment(assignment: &TargetControlAssignment) -> Value { } fn json_request(kind: &str, assignment: &TargetControlAssignment) -> Value { - json_object(&[ + json_object([ ("kind", Value::String(kind.to_owned())), ("assignment", json_assignment(assignment)), ]) } fn json_realization(instance: &TargetResourceInstance) -> Value { - json_object(&[ + json_object([ ("source", json_key(instance.source())), ("sourceUid", Value::String(hex_encode(&instance.source_uid()[..]))), ( @@ -1059,28 +1066,28 @@ fn json_realization(instance: &TargetResourceInstance) -> Value { fn json_observation(observation: TargetObservation) -> Value { match observation { - TargetObservation::Absent => json_object(&[("kind", Value::String("absent".to_owned()))]), - TargetObservation::Realizing { session_generation } => json_object(&[ + TargetObservation::Absent => json_object([("kind", Value::String("absent".to_owned()))]), + TargetObservation::Realizing { session_generation } => json_object([ ("kind", Value::String("realizing".to_owned())), ("sessionGeneration", Value::from(session_generation)), ]), - TargetObservation::Ready { session_generation } => json_object(&[ + TargetObservation::Ready { session_generation } => json_object([ ("kind", Value::String("ready".to_owned())), ("sessionGeneration", Value::from(session_generation)), ]), TargetObservation::Unavailable => { - json_object(&[("kind", Value::String("unavailable".to_owned()))]) + json_object([("kind", Value::String("unavailable".to_owned()))]) } } } fn json_adoption(adoption: &GuestAdoption) -> Value { match adoption { - GuestAdoption::Adopted(instance) => json_object(&[ + GuestAdoption::Adopted(instance) => json_object([ ("kind", Value::String("adopted".to_owned())), ("realization", json_realization(instance)), ]), - GuestAdoption::Missing => json_object(&[("kind", Value::String("missing".to_owned()))]), + GuestAdoption::Missing => json_object([("kind", Value::String("missing".to_owned()))]), } } From fb5ed9466362650a98454cced821fbc88b1156e9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:58:03 -0700 Subject: [PATCH 023/726] d2b-resource-runtime: spec store docs, FromStr, borrowed binds, and owned-row insert --- .../d2b-resource-runtime/src/spec_store.rs | 75 ++++++++++++------- 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/packages/d2b-resource-runtime/src/spec_store.rs b/packages/d2b-resource-runtime/src/spec_store.rs index 950fe265f..ba855afba 100644 --- a/packages/d2b-resource-runtime/src/spec_store.rs +++ b/packages/d2b-resource-runtime/src/spec_store.rs @@ -58,6 +58,7 @@ pub struct ResourceKey { } impl ResourceKey { + /// Build a key from its three owned components. pub fn new(zone: impl Into, type_name: impl Into, name: impl Into) -> Self { Self { zone: zone.into(), type_name: type_name.into(), name: name.into() } } @@ -72,20 +73,25 @@ pub enum ResourceProvenance { } impl ResourceProvenance { + /// The database spelling this provenance persists as. pub fn as_str(&self) -> &'static str { match self { - Self::Nix => "nix", - Self::Api => "api", - Self::Resource => "resource", + Self::Nix =>"nix", + Self::Api =>"api", + Self::Resource =>"resource", } } +} + +impl std::str::FromStr for ResourceProvenance { + type Err = (); - fn from_str(value: &str) -> Option { + fn from_str(value: &str) -> Result { match value { - "nix" => Some(Self::Nix), - "api" => Some(Self::Api), - "resource" => Some(Self::Resource), - _ => None, + "nix" => Ok(Self::Nix), + "api" => Ok(Self::Api), + "resource" => Ok(Self::Resource), + _ => Err(()), } } } @@ -314,14 +320,14 @@ fn ensure_transactional_inner( existing_provenance, )) = existing else { - let stored = insert_new(tx, &row)?; + let stored = insert_new(tx, row)?; insert_audit( tx, AuditWrite { ts: now(), subject: "resource.ensure", - provenance: row.provenance.as_str(), - key: Some(&row.key), + provenance: stored.provenance.as_str(), + key: Some(&stored.key), operation: "ensure.create", generation_before: None, generation_after: Some(stored.generation as i64), @@ -519,26 +525,45 @@ fn now() -> i64 { fn insert_new( tx: &rusqlite::Transaction<'_>, - row: &StoredDesiredResource, + row: StoredDesiredResource, ) -> Result { + let StoredDesiredResource { + key, + uid, + owner_uid, + provenance, + spec, + metadata, + .. + } = row; let created_at = now(); tx.execute( "INSERT INTO resources (zone, type, name, uid, generation, owner_uid, provenance, \ deleting, spec, metadata, created_at) \ VALUES (?1, ?2, ?3, ?4, 1, ?5, ?6, 0, ?7, ?8, ?9)", params![ - row.key.zone, - row.key.type_name, - row.key.name, - row.uid.as_slice(), - row.owner_uid.map(|u| u.to_vec()), - row.provenance.as_str(), - row.spec, - row.metadata, + key.zone, + key.type_name, + key.name, + uid.as_slice(), + owner_uid.map(|u| u.to_vec()), + provenance.as_str(), + spec, + metadata, created_at, ], )?; - Ok(StoredDesiredResource { generation: 1, deleting: false, created_at, ..row.clone() }) + Ok(StoredDesiredResource { + generation: 1, + deleting: false, + created_at, + key, + uid, + owner_uid, + provenance, + spec, + metadata, + }) } fn row_from( @@ -553,8 +578,7 @@ fn row_from( uid: r.get::<_, Vec>(3)?.try_into().unwrap_or([0; 16]), generation: r.get::<_, i64>(4)? as u64, owner_uid: r.get::<_, Option>>(5)?.map(|v| v.try_into().unwrap_or([0; 16])), - provenance: ResourceProvenance::from_str(&r.get::<_, String>(6)?) - .unwrap_or(ResourceProvenance::Api), + provenance: r.get::<_, String>(6)?.parse().unwrap_or(ResourceProvenance::Api), deleting: r.get::<_, i64>(7)? != 0, spec: r.get(8)?, metadata: r.get(9)?, @@ -593,8 +617,8 @@ fn list(conn: &Connection, selector: &SpecSelector) -> Result &Path { &self.path } From d57184e0fedbabd1771e9846752409fa1029d0b7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 01:58:03 -0700 Subject: [PATCH 024/726] d2b-resource-runtime: document module names and identity accessors --- packages/d2b-resource-runtime/src/error.rs | 1 + packages/d2b-resource-runtime/src/identity.rs | 2 ++ packages/d2b-resource-runtime/src/provider.rs | 1 + packages/d2b-resource-runtime/src/revision.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/packages/d2b-resource-runtime/src/error.rs b/packages/d2b-resource-runtime/src/error.rs index 6a614cec7..324ce1b33 100644 --- a/packages/d2b-resource-runtime/src/error.rs +++ b/packages/d2b-resource-runtime/src/error.rs @@ -29,6 +29,7 @@ //! is generated from that registry by [`render_failure_kind_reference`] (a //! test fails when the committed page drifts), never hand-maintained prose. +/// The module declared name, asserted by the crate smoke test. pub const MODULE_NAME: &str = "error"; use crate::identity::ResourceKey; diff --git a/packages/d2b-resource-runtime/src/identity.rs b/packages/d2b-resource-runtime/src/identity.rs index 98725b463..0c32525ec 100644 --- a/packages/d2b-resource-runtime/src/identity.rs +++ b/packages/d2b-resource-runtime/src/identity.rs @@ -17,10 +17,12 @@ pub use crate::spec_store::{ResourceKey, ResourceProvenance, StoredDesiredResour pub struct ResourceTypeName(String); impl ResourceTypeName { + /// Build a type name from its string form. pub fn new(name: impl Into) -> Self { Self(name.into()) } + /// The type name as a plain string. pub fn as_str(&self) -> &str { &self.0 } diff --git a/packages/d2b-resource-runtime/src/provider.rs b/packages/d2b-resource-runtime/src/provider.rs index 6efeb9721..4ce349fcb 100644 --- a/packages/d2b-resource-runtime/src/provider.rs +++ b/packages/d2b-resource-runtime/src/provider.rs @@ -1,5 +1,6 @@ //! Provider registry producing drivers per resource type (U4, KTD3). +/// The module declared name, asserted by the crate smoke test. pub const MODULE_NAME: &str = "provider"; use std::collections::{HashMap, HashSet}; diff --git a/packages/d2b-resource-runtime/src/revision.rs b/packages/d2b-resource-runtime/src/revision.rs index 1404e2970..c5d1c1727 100644 --- a/packages/d2b-resource-runtime/src/revision.rs +++ b/packages/d2b-resource-runtime/src/revision.rs @@ -34,6 +34,7 @@ //! count must fit in 32 bits (satisfied until year 2106). The full mapping //! lands with U8; this module only pins the budget. +/// The module declared name, asserted by the crate smoke test. pub const MODULE_NAME: &str = "revision"; /// Maximum revisions per daemon epoch under the U8 wire mapping: the From 0a4f73a1fb6b5c9e9b07fd1b3f20d2486ad7d557 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:05 -0700 Subject: [PATCH 025/726] d2b: deduplicate doctor and zone-audit helpers --- packages/d2b/src/doctor.rs | 44 ++++---- packages/d2b/src/resource.rs | 174 +++++++++++++++++++++----------- packages/d2b/src/zone_audit.rs | 120 +++++++++------------- packages/d2b/src/zone_doctor.rs | 6 +- 4 files changed, 182 insertions(+), 162 deletions(-) diff --git a/packages/d2b/src/doctor.rs b/packages/d2b/src/doctor.rs index ec3fd18c7..550faf44e 100644 --- a/packages/d2b/src/doctor.rs +++ b/packages/d2b/src/doctor.rs @@ -88,6 +88,7 @@ pub struct DoctorCheck { } #[derive(Debug, Clone, Default)] +/// Ordered check list produced by one doctor run. pub struct DoctorReport { pub checks: Vec, } @@ -160,6 +161,7 @@ impl DoctorReport { } } +/// Run every doctor probe against one CLI context and aggregate the results. pub fn run_doctor(context: &CliContext) -> DoctorReport { let mut report = DoctorReport::default(); check_broker_socket(context, &mut report); @@ -481,6 +483,15 @@ enum PidfdState { ParseError(String), } +impl PidfdEntries { + fn state_detail(&self) -> String { + match &self.state { + PidfdState::ParseError(d) => d.clone(), + _ => "daemon state dir unreadable".to_owned(), + } + } +} + #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn load_pidfd_entries(daemon_state_dir: &Path) -> PidfdEntries { let path = daemon_state_dir.join("pidfd-table.json"); @@ -525,10 +536,7 @@ fn check_otel_host_bridge_runner(entries: &PidfdEntries, report: &mut DoctorRepo "daemon pidfd-table.json missing; cannot confirm OtelHostBridge runner".to_owned(), ), PidfdState::UnreadableDir | PidfdState::ParseError(_) => { - let detail = match &entries.state { - PidfdState::ParseError(d) => d.clone(), - _ => "daemon state dir unreadable".to_owned(), - }; + let detail = entries.state_detail(); report.push( "otel-host-bridge-runner", DoctorStatus::Warn, @@ -575,10 +583,7 @@ fn check_usbipd_runners(entries: &PidfdEntries, report: &mut DoctorReport) { "daemon pidfd-table.json missing; cannot enumerate per-env usbipd runners".to_owned(), ), PidfdState::UnreadableDir | PidfdState::ParseError(_) => { - let detail = match &entries.state { - PidfdState::ParseError(d) => d.clone(), - _ => "daemon state dir unreadable".to_owned(), - }; + let detail = entries.state_detail(); report.push( "usbipd-runners", DoctorStatus::Warn, @@ -1059,15 +1064,15 @@ fn check_storage_lifecycle_report(daemon_state_dir: &Path, report: &mut DoctorRe let legacy_only = parsed.has_only_legacy_contract_issue(); let invalid_contract_summary = storage_lifecycle_invalid_contract_summary(&parsed.issues); let mut data = json!({ - "schemaVersion": parsed.schema_version.clone(), + "schemaVersion": parsed.schema_version, "storageContractPresent": parsed.storage_contract_present, "syncContractPresent": parsed.sync_contract_present, "pathCount": parsed.path_count, "restartPolicyCount": parsed.restart_policy_count, "lockCount": parsed.lock_count, "issueCount": issue_count, - "issueKinds": issue_kinds.clone(), - "issues": parsed.issues.clone(), + "issueKinds": issue_kinds, + "issues": parsed.issues, }); if legacy_only { @@ -1226,10 +1231,7 @@ fn check_seccomp_bpf_loaded(entries: &PidfdEntries, report: &mut DoctorReport) { return; } PidfdState::UnreadableDir | PidfdState::ParseError(_) => { - let detail = match &entries.state { - PidfdState::ParseError(d) => d.clone(), - _ => "daemon state dir unreadable".to_owned(), - }; + let detail = entries.state_detail(); report.push( "seccomp-bpf-loaded", DoctorStatus::Warn, @@ -1339,10 +1341,7 @@ fn check_pre_ns_posture_with_reader( return; } PidfdState::UnreadableDir | PidfdState::ParseError(_) => { - let detail = match &entries.state { - PidfdState::ParseError(d) => d.clone(), - _ => "daemon state dir unreadable".to_owned(), - }; + let detail = entries.state_detail(); report.push( "pre-ns-posture", DoctorStatus::Warn, @@ -1445,10 +1444,7 @@ fn check_broker_reap_health(entries: &PidfdEntries, report: &mut DoctorReport) { return; } PidfdState::UnreadableDir | PidfdState::ParseError(_) => { - let detail = match &entries.state { - PidfdState::ParseError(d) => d.clone(), - _ => "daemon state dir unreadable".to_owned(), - }; + let detail = entries.state_detail(); report.push( "broker-reap-health", DoctorStatus::Warn, @@ -1697,6 +1693,7 @@ fn run_sysctl_n(key: &str) -> Result { // Renderers // --------------------------------------------------------------- +/// Render the doctor report as the structured JSON doctor output. pub fn render_summary(report: &DoctorReport) -> Value { let checks: Vec = report .checks @@ -1746,6 +1743,7 @@ pub fn render_summary(report: &DoctorReport) -> Value { }) } +/// Render the doctor report as human-readable terminal text. pub fn render_human(report: &DoctorReport) -> String { use std::fmt::Write as _; let mut out = String::new(); diff --git a/packages/d2b/src/resource.rs b/packages/d2b/src/resource.rs index d86423350..078d21067 100644 --- a/packages/d2b/src/resource.rs +++ b/packages/d2b/src/resource.rs @@ -140,11 +140,112 @@ pub(crate) struct TypedReconcileArgs { #[derive(Debug, Args, Clone)] pub(crate) struct TypedVerifyArgs { + pub(crate) name: String, #[arg(long)] pub(crate) repair: bool, } +impl TypedListArgs { + fn into_generic(self, resource_type: &str) -> GenericListArgs { + GenericListArgs { + resource_type: resource_type.to_owned(), + execution_ref: self.execution_ref, + domain: self.domain, + phase: self.phase, + label_selector: self.label_selector, + updates: self.updates, + page_token: self.page_token, + limit: self.limit, + } + } +} + +impl TypedWatchArgs { + fn into_generic(self, resource_type: &str) -> GenericWatchArgs { + GenericWatchArgs { + resource_type: resource_type.to_owned(), + since_revision: self.since_revision, + phase: self.phase, + label_selector: self.label_selector, + } + } +} + +impl TypedCreateArgs { + fn into_generic(self, resource_type: &str) -> GenericCreateArgs { + GenericCreateArgs { + resource_type: resource_type.to_owned(), + spec_file: self.spec_file, + spec_stdin: self.spec_stdin, + wait_for_reconcile: self.wait_for_reconcile, + reconcile_deadline: self.reconcile_deadline, + } + } +} + +impl TypedNameArgs { + fn into_generic(self, resource_type: &str) -> GenericGetArgs { + GenericGetArgs { + resource_ref: format!("{resource_type}/{}", self.name), + } + } +} + +impl TypedUpdateSpecArgs { + fn into_generic(self, resource_type: &str) -> GenericUpdateSpecArgs { + GenericUpdateSpecArgs { + resource_ref: format!("{resource_type}/{}", self.name), + revision: self.revision, + spec_file: self.spec_file, + spec_stdin: self.spec_stdin, + wait_for_reconcile: self.wait_for_reconcile, + reconcile_deadline: self.reconcile_deadline, + } + } +} + +impl TypedNameMutationArgs { + fn into_generic(self, resource_type: &str) -> GenericDeleteArgs { + GenericDeleteArgs { + resource_ref: format!("{resource_type}/{}", self.name), + revision: self.revision, + wait_for_reconcile: self.wait_for_reconcile, + reconcile_deadline: self.reconcile_deadline, + } + } +} + +impl TypedStatusArgs { + fn into_generic(self, resource_type: &str) -> GenericStatusArgs { + GenericStatusArgs { + resource_ref: format!("{resource_type}/{}", self.name), + watch: self.watch, + } + } +} + +impl TypedUpgradeArgs { + fn into_generic(self, resource_type: &str) -> GenericUpgradeArgs { + GenericUpgradeArgs { + resource_ref: format!("{resource_type}/{}", self.name), + recursive: self.recursive, + apply: self.apply, + reconcile_deadline: self.reconcile_deadline, + } + } +} + +impl TypedReconcileArgs { + fn into_generic(self, resource_type: &str) -> GenericReconcileArgs { + GenericReconcileArgs { + resource_ref: format!("{resource_type}/{}", self.name), + reconcile_deadline: self.reconcile_deadline, + } + } +} + + #[derive(Debug, Args, Clone)] pub(crate) struct DeviceUsbArgs { #[command(subcommand)] @@ -505,7 +606,7 @@ pub(crate) fn reconcile( pub(crate) fn typed_noun( context: &ZoneContext, noun: &str, - args: &TypedResourceArgs, + args: TypedResourceArgs, mode: OutputMode, deadline: RequestDeadline, ) -> Result { @@ -518,58 +619,29 @@ pub(crate) fn typed_noun( pub(crate) fn typed( context: &ZoneContext, resource_type: &str, - args: &TypedResourceArgs, + args: TypedResourceArgs, mode: OutputMode, deadline: RequestDeadline, ) -> Result { - match &args.command { + match args.command { TypedResourceCommand::Get(args) => { - let generic = GenericGetArgs { - resource_ref: format!("{resource_type}/{}", args.name), - }; + let generic = args.into_generic(resource_type); get(context, &generic, mode, deadline) } TypedResourceCommand::List(args) => { - let generic = GenericListArgs { - resource_type: resource_type.to_owned(), - execution_ref: args.execution_ref.clone(), - domain: args.domain.clone(), - phase: args.phase.clone(), - label_selector: args.label_selector.clone(), - updates: args.updates, - page_token: args.page_token.clone(), - limit: args.limit, - }; + let generic = args.into_generic(resource_type); list(context, &generic, mode, deadline) } TypedResourceCommand::Watch(args) => { - let generic = GenericWatchArgs { - resource_type: resource_type.to_owned(), - since_revision: args.since_revision.clone(), - phase: args.phase.clone(), - label_selector: args.label_selector.clone(), - }; + let generic = args.into_generic(resource_type); watch(context, &generic, mode, deadline) } TypedResourceCommand::Create(args) => { - let generic = GenericCreateArgs { - resource_type: resource_type.to_owned(), - spec_file: args.spec_file.clone(), - spec_stdin: args.spec_stdin, - wait_for_reconcile: args.wait_for_reconcile, - reconcile_deadline: args.reconcile_deadline.clone(), - }; + let generic = args.into_generic(resource_type); create(context, &generic, mode, deadline) } TypedResourceCommand::UpdateSpec(args) => { - let generic = GenericUpdateSpecArgs { - resource_ref: format!("{resource_type}/{}", args.name), - revision: args.revision.clone(), - spec_file: args.spec_file.clone(), - spec_stdin: args.spec_stdin, - wait_for_reconcile: args.wait_for_reconcile, - reconcile_deadline: args.reconcile_deadline.clone(), - }; + let generic = args.into_generic(resource_type); if crate::generated::surface_catalog::is_controller_owned(resource_type) { return Err(context.failure( "authorization-denied", @@ -589,35 +661,19 @@ pub(crate) fn typed( 1, )); } - let generic = GenericDeleteArgs { - resource_ref: format!("{resource_type}/{}", args.name), - revision: args.revision.clone(), - wait_for_reconcile: args.wait_for_reconcile, - reconcile_deadline: args.reconcile_deadline.clone(), - }; + let generic = args.into_generic(resource_type); delete(context, &generic, mode, deadline) } TypedResourceCommand::Status(args) => { - let generic = GenericStatusArgs { - resource_ref: format!("{resource_type}/{}", args.name), - watch: args.watch, - }; + let generic = args.into_generic(resource_type); status(context, &generic, mode, deadline) } TypedResourceCommand::Upgrade(args) => { - let generic = GenericUpgradeArgs { - resource_ref: format!("{resource_type}/{}", args.name), - recursive: args.recursive, - apply: args.apply, - reconcile_deadline: args.reconcile_deadline.clone(), - }; + let generic = args.into_generic(resource_type); upgrade(context, &generic, mode, deadline) } TypedResourceCommand::Reconcile(args) => { - let generic = GenericReconcileArgs { - resource_ref: format!("{resource_type}/{}", args.name), - reconcile_deadline: args.reconcile_deadline.clone(), - }; + let generic = args.into_generic(resource_type); reconcile(context, &generic, mode, deadline) } TypedResourceCommand::Verify(args) => { @@ -651,7 +707,7 @@ pub(crate) fn typed( 2, )); } - device_usb(context, args, mode, deadline) + device_usb(context, &args, mode, deadline) } TypedResourceCommand::SecurityKey(args) => { if !crate::generated::surface_catalog::typed_verb_type("security-key").is_some_and(|owner| owner == resource_type) { @@ -662,7 +718,7 @@ pub(crate) fn typed( 2, )); } - device_security_key(context, args, mode, deadline) + device_security_key(context, &args, mode, deadline) } } } diff --git a/packages/d2b/src/zone_audit.rs b/packages/d2b/src/zone_audit.rs index f8effd2e9..58eea2fdc 100644 --- a/packages/d2b/src/zone_audit.rs +++ b/packages/d2b/src/zone_audit.rs @@ -347,54 +347,15 @@ fn validate_record( return Err(RecordValidationError::Invalid); } - fn validate_v2_record( - object: &serde_json::Map, - class: &str, - fields_key: &str, - fields: &serde_json::Map, - expected_previous: Option<&str>, - ) -> Result { - if object - .keys() - .any(|key| key.ends_with("_fields") && key != fields_key) - || !validate_v2_envelope(object) - || !validate_v2_fields(class, fields) - { - return Err(RecordValidationError::Invalid); - } - let previous = object - .get("prev_hash") - .and_then(Value::as_str) - .ok_or(RecordValidationError::Invalid)?; - let record_hash = object - .get("record_hash") - .and_then(Value::as_str) - .ok_or(RecordValidationError::Invalid)?; - if !valid_hash(previous) || !valid_hash(record_hash) { - return Err(RecordValidationError::Invalid); - } - if expected_previous.is_some_and(|expected| expected != previous) { - return Err(RecordValidationError::ChainBreak); - } - let canonical = json!({ - "ts_ms": object.get("ts_ms").ok_or(RecordValidationError::Invalid)?, - "schema_version": object.get("schema_version").ok_or(RecordValidationError::Invalid)?, - "zone": object.get("zone").ok_or(RecordValidationError::Invalid)?, - "record_class": object.get("record_class").ok_or(RecordValidationError::Invalid)?, - "operation_id": object.get("operation_id").ok_or(RecordValidationError::Invalid)?, - "correlation_id": object.get("correlation_id").ok_or(RecordValidationError::Invalid)?, - "trace_id": object.get("trace_id").ok_or(RecordValidationError::Invalid)?, - "source": object.get("source").ok_or(RecordValidationError::Invalid)?, - "prev_hash": object.get("prev_hash").ok_or(RecordValidationError::Invalid)?, - fields_key: object.get(fields_key).ok_or(RecordValidationError::Invalid)?, - }); - let canonical = - serde_json::to_vec(&canonical).map_err(|_| RecordValidationError::Invalid)?; - if record_hash != record_hash_for(previous, &canonical) { - return Err(RecordValidationError::ChainBreak); - } - Ok(record_hash.to_owned()) - } + /// Verify the chain tail shared by v1 and v2 records: prev/record digest + /// shape, expected-previous linkage, canonical envelope, and digest equality. + + +fn verify_chain( + object: &serde_json::Map, + fields_key: &str, + expected_previous: Option<&str>, +) -> Result { let previous = object .get("prev_hash") .and_then(Value::as_str) @@ -403,7 +364,7 @@ fn validate_record( .get("record_hash") .and_then(Value::as_str) .ok_or(RecordValidationError::Invalid)?; - if !valid_hash(previous) || !valid_hash(record_hash) { + if !valid_digest(previous) || !valid_digest(record_hash) { return Err(RecordValidationError::Invalid); } if expected_previous.is_some_and(|expected| expected != previous) { @@ -422,12 +383,34 @@ fn validate_record( fields_key: object.get(fields_key).ok_or(RecordValidationError::Invalid)?, }); let canonical = serde_json::to_vec(&canonical).map_err(|_| RecordValidationError::Invalid)?; - if record_hash != record_hash_for(previous, &canonical) { + if record_hash != record_hash_for(previous,&canonical) { return Err(RecordValidationError::ChainBreak); } Ok(record_hash.to_owned()) } + +fn validate_v2_record( + object: &serde_json::Map, + class: &str, + fields_key: &str, + fields: &serde_json::Map, + expected_previous: Option<&str>, + ) -> Result { + if object + .keys() + .any(|key| key.ends_with("_fields") && key != fields_key) + || !validate_v2_envelope(object) + || !validate_v2_fields(class, fields) + { + return Err(RecordValidationError::Invalid); + } + verify_chain(object, fields_key, expected_previous) + } + + verify_chain(object, fields_key, expected_previous) +} + const RESOURCE_MUTATION_FIELDS: &[&str] = &[ "verb", "resource_type", @@ -588,7 +571,11 @@ fn fields_for_class(class: &str) -> Option<&'static [&'static str]> { }) } -fn validate_public_fields(class: &str, fields: &serde_json::Map) -> bool { +fn validate_fields( + class: &str, + fields: &serde_json::Map, + validate_field: fn(&str, &str, &Value) -> bool, +) -> bool { let Some(expected) = fields_for_class(class) else { return false; }; @@ -601,25 +588,18 @@ fn validate_public_fields(class: &str, fields: &serde_json::Map) .all(|key| expected.contains(&key.as_str()) || key == posture_field()) && fields .iter() - .all(|(key, value)| validate_public_field(class, key, value)) + .all(|(key, value)| validate_field(class, key, value)) +} + +fn validate_public_fields(class: &str, fields: &serde_json::Map) -> bool { + validate_fields(class, fields, validate_public_field) } fn validate_v2_fields(class: &str, fields: &serde_json::Map) -> bool { - let Some(expected) = fields_for_class(class) else { - return false; - }; - let expected_count = expected.len() + usize::from(class == "process-effect"); - fields.len() == expected_count - && expected.iter().all(|key| fields.contains_key(*key)) - && (class != "process-effect" || fields.contains_key(posture_field())) - && fields - .keys() - .all(|key| expected.contains(&key.as_str()) || key == posture_field()) - && fields - .iter() - .all(|(key, value)| validate_v2_field(class, key, value)) + validate_fields(class, fields, validate_v2_field) } + fn validate_v2_field(class: &str, key: &str, value: &Value) -> bool { if key == "generation" || key == "expected_revision" @@ -835,16 +815,6 @@ fn safe_public_text(value: &str, allow_slash: bool) -> bool { .all(|byte| byte.is_ascii_graphic() && (allow_slash || byte != b'/')) } -fn valid_hash(value: &str) -> bool { - let Some(hex) = value.strip_prefix("sha256:") else { - return false; - }; - hex.len() == 64 - && hex - .bytes() - .all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f')) -} - fn genesis_hash() -> String { hash_bytes(b"d2b-audit-v3-genesis") } diff --git a/packages/d2b/src/zone_doctor.rs b/packages/d2b/src/zone_doctor.rs index 3f792513c..5e921c4e4 100644 --- a/packages/d2b/src/zone_doctor.rs +++ b/packages/d2b/src/zone_doctor.rs @@ -595,11 +595,7 @@ fn push_check(checks: &mut Vec, name: &str, passed: bool, error: bo } fn summarize(checks: &[DoctorCheck]) -> DoctorSummary { - let mut summary = DoctorSummary { - ok: 0, - warn: 0, - error: 0, - }; + let mut summary = DoctorSummary::default(); for check in checks { match check.status { CheckStatus::Ok => summary.ok += 1, From 4784e6cdae9c293281646e93235a085e042a0c70 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:07 -0700 Subject: [PATCH 026/726] d2b: document doctor, validate, and exec surfaces --- packages/d2b/src/exec_client.rs | 6 ++++++ packages/d2b/src/host_validate.rs | 3 +++ packages/d2b/src/lib.rs | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/packages/d2b/src/exec_client.rs b/packages/d2b/src/exec_client.rs index 9ad4403d5..d9c1542c5 100644 --- a/packages/d2b/src/exec_client.rs +++ b/packages/d2b/src/exec_client.rs @@ -494,6 +494,7 @@ fn expect_write(resp: ExecOpResponse) -> Result Result { match resp { ExecOpResponse::Start(result) => Ok(result), @@ -504,6 +505,7 @@ pub fn expect_start(resp: ExecOpResponse) -> Result Result { @@ -516,6 +518,7 @@ pub fn expect_detached_create( } } +/// Expect the `ExecOpResponse::List` variant, else return a protocol error. pub fn expect_detached_list( resp: ExecOpResponse, ) -> Result { @@ -528,6 +531,7 @@ pub fn expect_detached_list( } } +/// Expect the `ExecOpResponse::Logs` variant, else return a protocol error. pub fn expect_detached_logs( resp: ExecOpResponse, ) -> Result { @@ -540,6 +544,7 @@ pub fn expect_detached_logs( } } +/// Expect the `ExecOpResponse::Status` variant, else return a protocol error. pub fn expect_detached_status( resp: ExecOpResponse, ) -> Result { @@ -552,6 +557,7 @@ pub fn expect_detached_status( } } +/// Expect the `ExecOpResponse::Kill` variant, else return a protocol error. pub fn expect_detached_kill( resp: ExecOpResponse, ) -> Result { diff --git a/packages/d2b/src/host_validate.rs b/packages/d2b/src/host_validate.rs index ebe727c00..3d1cd95a3 100644 --- a/packages/d2b/src/host_validate.rs +++ b/packages/d2b/src/host_validate.rs @@ -226,6 +226,7 @@ pub struct WaveReport { } #[derive(Debug, Clone)] +/// Complete result of one `host validate` run, as per-wave evidence rows. pub struct ValidateReport { pub mode: ValidateMode, pub evidence_dir: PathBuf, @@ -234,6 +235,7 @@ pub struct ValidateReport { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// The mutation mode of a `host validate` run. pub enum ValidateMode { DryRun, Apply, @@ -622,6 +624,7 @@ fn tally(waves: &[WaveReport]) -> serde_json::Map { m } +/// Derive the process exit code from the validation report statuses. pub fn exit_code(report: &ValidateReport) -> i32 { // Apply mode: any write-failure is exit 1. // Any wave still `Missing` after apply is exit 78 (operator must diff --git a/packages/d2b/src/lib.rs b/packages/d2b/src/lib.rs index 570db3cec..a018f8859 100644 --- a/packages/d2b/src/lib.rs +++ b/packages/d2b/src/lib.rs @@ -1,3 +1,6 @@ +//! The `d2b` CLI: typed command surface, dispatch, doctor diagnosis, +//! and host validation agents. + #![allow(dead_code)] use std::{ @@ -212,12 +215,14 @@ pub(crate) fn sha256_hex(data: &[u8]) -> String { hex } +/// Build the `d2b` CLI command tree for embedding and completion. pub fn cli_command() -> clap::Command { let mut command = dispatch::ModernCli::command(); command.set_bin_name("d2b"); command } +/// Execute the `d2b` CLI against one argument list and return the process exit code. pub fn run(args: I) -> i32 where I: IntoIterator, From 6355caebbd18cd5bccfe09e1a4ae097702a7cd32 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:09 -0700 Subject: [PATCH 027/726] bus: document observer, failure, and parse contracts --- packages/d2b-bus/src/authorization.rs | 1 + packages/d2b-bus/src/metrics.rs | 9 +++++++++ packages/d2b-bus/src/registry.rs | 10 +++++++++- packages/d2b-bus/src/streams.rs | 7 ++++++- packages/d2b-bus/src/wire.rs | 6 +++++- 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/d2b-bus/src/authorization.rs b/packages/d2b-bus/src/authorization.rs index 273698acb..be20e6825 100644 --- a/packages/d2b-bus/src/authorization.rs +++ b/packages/d2b-bus/src/authorization.rs @@ -397,6 +397,7 @@ pub enum AuthorizationError { Assignment(AssignmentError), } +/// Closed classifier for bus authorization failures. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AuthorizationErrorClass { MissingGrant, diff --git a/packages/d2b-bus/src/metrics.rs b/packages/d2b-bus/src/metrics.rs index e01a33f32..f9a79f636 100644 --- a/packages/d2b-bus/src/metrics.rs +++ b/packages/d2b-bus/src/metrics.rs @@ -45,6 +45,7 @@ impl BusDirection { pub const ALL: [Self; 4] = [Self::Local, Self::Host, Self::Guest, Self::ZoneLink]; /// Stable metric label. + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Local => "local", @@ -88,6 +89,7 @@ impl BusTransport { pub const ALL: [Self; 3] = [Self::Unix, Self::Vsock, Self::ZoneLink]; /// Stable metric label. + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Unix => "unix", @@ -107,6 +109,7 @@ pub enum BusRouteOutcome { } impl BusRouteOutcome { + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Ok => "ok", @@ -125,6 +128,7 @@ pub enum BusRegistrationOutcome { } impl BusRegistrationOutcome { + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Accepted => "accepted", @@ -142,6 +146,7 @@ pub enum BusStreamOutcome { } impl BusStreamOutcome { + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Accepted => "accepted", @@ -159,6 +164,7 @@ pub enum BusStreamKind { } impl BusStreamKind { + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Control => "control", @@ -176,6 +182,7 @@ pub enum BusBackpressureReason { } impl BusBackpressureReason { + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Credit | Self::Capacity => "quota", @@ -194,6 +201,7 @@ pub enum BusRejectionOutcome { } impl BusRejectionOutcome { + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Denied => "denied", @@ -214,6 +222,7 @@ pub enum BusDisconnectOutcome { } impl BusDisconnectOutcome { + /// Canonical wire label emitted in metrics events. pub const fn as_str(self) -> &'static str { match self { Self::Abandoned => "abandoned", diff --git a/packages/d2b-bus/src/registry.rs b/packages/d2b-bus/src/registry.rs index 39438af57..ae6ce743b 100644 --- a/packages/d2b-bus/src/registry.rs +++ b/packages/d2b-bus/src/registry.rs @@ -256,14 +256,17 @@ pub struct EndpointSessionFailure { } impl EndpointSessionFailure { + /// Borrow the endpoint failure class. pub const fn class(self) -> EndpointFailureClass { self.class } + /// Borrow the session error code. pub const fn code(self) -> SessionErrorCode { self.code } + /// Borrow the operator-facing remediation. pub const fn remediation(self) -> Remediation { self.remediation } @@ -373,7 +376,12 @@ pub trait BusEndpoint: Send + Sync + 'static { Err(EndpointError::Unavailable) } - /// Deliver one already-authorized method invocation. + /// Deliver one already-authorized method invocation.. + /// + /// # Errors + /// Returns the implementation's own `EndpointError` variant when the + /// endpoint cannot serve the invocation; the default implementation + /// rejects with `EndpointError::Unavailable`. async fn invoke(&self, request: DeliveredInvocation) -> Result; /// Send one response for a request received on the authenticated diff --git a/packages/d2b-bus/src/streams.rs b/packages/d2b-bus/src/streams.rs index 4355f6319..671cb1848 100644 --- a/packages/d2b-bus/src/streams.rs +++ b/packages/d2b-bus/src/streams.rs @@ -36,7 +36,12 @@ pub const DEFAULT_MAX_FRAME_BYTES: usize = 64 * 1024; pub struct StreamName(String); impl StreamName { - /// Parse a canonical stream name. + /// Parse a canonical stream name.. + /// + /// # Errors + /// Returns `StreamError::InvalidName` when the value is empty, longer than + /// 128 bytes, or contains a character outside the ASCII alphanumeric or + /// `-`/`_`/`.`/`:` set. pub fn parse(value: impl Into) -> Result { let value = value.into(); if value.is_empty() diff --git a/packages/d2b-bus/src/wire.rs b/packages/d2b-bus/src/wire.rs index b50447276..97ece8e27 100644 --- a/packages/d2b-bus/src/wire.rs +++ b/packages/d2b-bus/src/wire.rs @@ -76,7 +76,11 @@ impl ZoneBoundPolicyIdentity { self.provider_ref.as_ref() } - /// Render the stable digest used in local policy comparison. + /// Render the stable digest used in local policy comparison.. + /// + /// # Errors + /// Returns the `BinaryError` from `EndpointPolicyIdentity::encode_canonical` + /// when the component-session wire shape cannot represent this policy. pub fn digest( &self, ) -> Result { From 99d7247eeb0e7cd98acd21ec5232a62a0b7868ce Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:16 -0700 Subject: [PATCH 028/726] runtime: extract common probe flag parsing --- packages/d2b-broker/src/runtime.rs | 109 +++++++++++------------------ 1 file changed, 42 insertions(+), 67 deletions(-) diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index e438c0ae5..10c464b4a 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -10128,13 +10128,14 @@ async fn active_locked_usbip_bind_intents( resolver: &BundleResolver, ) -> Result, BrokerError> { let mut out = Vec::new(); - for id in resolver.usbip_bind_intent_ids() { - let Some(intent) = resolver.find_usbip_bind_intent(id) else { - continue; - }; - let Some(owner) = crate::ops::usbip_lock::peek_owner(&intent.lock_path) else { - continue; - }; + for (intent, owner) in resolver + .usbip_bind_intent_ids() + .filter_map(|id| resolver.find_usbip_bind_intent(id)) + .filter_map(|intent| { + let owner = crate::ops::usbip_lock::peek_owner(&intent.lock_path)?; + Some((intent, owner)) + }) + { if owner != intent.vm_name { return Err(BrokerError::LiveHandler(format!( "usbip proxy reconcile refused foreign lock for opaque intent {}", @@ -10387,7 +10388,10 @@ fn run_probe( } #[cfg(feature = "layer1-bootstrap")] -fn parse_probe_flags(rest: Vec) -> Result<(PathBuf, Option), RunError> { +fn parse_common_flags( + rest: &[String], + extra: &mut dyn FnMut(&str, &[String], &mut usize) -> Result<(), RunError>, +) -> Result<(PathBuf, Option), RunError> { let mut socket_path = PathBuf::from(DEFAULT_SOCKET_PATH); let mut test_uid = None; let mut index = 0; @@ -10395,51 +10399,41 @@ fn parse_probe_flags(rest: Vec) -> Result<(PathBuf, Option), RunErr match rest[index].as_str() { "--socket-path" => { index += 1; - socket_path = PathBuf::from(expect_arg(&rest, index, "--socket-path")?); + socket_path = PathBuf::from(expect_arg(rest, index, "--socket-path")?); } "--test-uid" => { index += 1; test_uid = Some( - expect_arg(&rest, index, "--test-uid")? + expect_arg(rest, index, "--test-uid")? .parse() .map_err(|_| RunError::Usage("invalid --test-uid".to_owned()))?, ); } - other => return Err(RunError::Usage(format!("unknown probe flag: {other}"))), + other => extra(other, rest, &mut index)?, } index += 1; } Ok((socket_path, test_uid)) } +#[cfg(feature = "layer1-bootstrap")] +fn parse_probe_flags(rest: Vec) -> Result<(PathBuf, Option), RunError> { + parse_common_flags(&rest, &mut |flag, _, _| { + Err(RunError::Usage(format!("unknown probe flag: {flag}"))) + }) +} + #[cfg(feature = "layer1-bootstrap")] fn parse_stub_flags(rest: &[String]) -> Result<(PathBuf, Option, String), RunError> { - let mut socket_path = PathBuf::from(DEFAULT_SOCKET_PATH); - let mut test_uid = None; let mut operation = None; - let mut index = 0; - while index < rest.len() { - match rest[index].as_str() { - "--socket-path" => { - index += 1; - socket_path = PathBuf::from(expect_arg(rest, index, "--socket-path")?); - } - "--test-uid" => { - index += 1; - test_uid = Some( - expect_arg(rest, index, "--test-uid")? - .parse() - .map_err(|_| RunError::Usage("invalid --test-uid".to_owned()))?, - ); - } - "--operation" => { - index += 1; - operation = Some(expect_arg(rest, index, "--operation")?.to_owned()); - } - other => return Err(RunError::Usage(format!("unknown probe-stub flag: {other}"))), + let (socket_path, test_uid) = parse_common_flags(rest, &mut |flag, rest, index| { + if flag != "--operation" { + return Err(RunError::Usage(format!("unknown probe-stub flag: {flag}"))); } - index += 1; - } + *index += 1; + operation = Some(expect_arg(rest, *index, "--operation")?.to_owned()); + Ok(()) + })?; Ok(( socket_path, test_uid, @@ -10449,40 +10443,21 @@ fn parse_stub_flags(rest: &[String]) -> Result<(PathBuf, Option, String), R #[cfg(feature = "layer1-bootstrap")] fn parse_export_flags(rest: &[String]) -> Result<(PathBuf, Option, CallerRole), RunError> { - let mut socket_path = PathBuf::from(DEFAULT_SOCKET_PATH); - let mut test_uid = None; let mut caller_role = None; - let mut index = 0; - while index < rest.len() { - match rest[index].as_str() { - "--socket-path" => { - index += 1; - socket_path = PathBuf::from(expect_arg(rest, index, "--socket-path")?); - } - "--test-uid" => { - index += 1; - test_uid = Some( - expect_arg(rest, index, "--test-uid")? - .parse() - .map_err(|_| RunError::Usage("invalid --test-uid".to_owned()))?, - ); - } - "--caller-role" => { - index += 1; - caller_role = crate::bootstrap::wire::caller_role_from_cli(expect_arg( - rest, - index, - "--caller-role", - )?); - } - other => { - return Err(RunError::Usage(format!( - "unknown probe-export-audit flag: {other}" - ))); - } + let (socket_path, test_uid) = parse_common_flags(rest, &mut |flag, rest, index| { + if flag != "--caller-role" { + return Err(RunError::Usage(format!( + "unknown probe-export-audit flag: {flag}" + ))); } - index += 1; - } + *index += 1; + caller_role = crate::bootstrap::wire::caller_role_from_cli(expect_arg( + rest, + *index, + "--caller-role", + )?); + Ok(()) + })?; Ok(( socket_path, test_uid, From d2096735cc358e4541a9e58ed1492f01cce86147 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:36 -0700 Subject: [PATCH 029/726] sys: reverse errno formatting in place --- packages/d2b-broker/src/sys.rs | 44 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/packages/d2b-broker/src/sys.rs b/packages/d2b-broker/src/sys.rs index 34113bce3..0f9e170df 100644 --- a/packages/d2b-broker/src/sys.rs +++ b/packages/d2b-broker/src/sys.rs @@ -116,7 +116,12 @@ unsafe fn getsockopt_int(fd: RawFd, optname: libc::c_int) -> io::Result io::Result<(u32, u32, i32)> { // SAFETY: the borrowed fd is valid for the duration of this call; ownership stays with the caller. @@ -181,6 +186,12 @@ pub fn tun_create_tap_fd(fd: &OwnedFd, ifname: &str) -> io::Result<()> { Ok(()) } +/// Set the TUN `TUNSETPERSIST` ioctl: whether the tap persists after +/// its fd closes. +/// +/// # Errors + +/// Returns the ioctl error when the setting cannot be applied to `fd`. #[allow(unsafe_code)] pub fn tun_set_persist(fd: &OwnedFd, persist: bool) -> io::Result<()> { let value: libc::c_int = if persist { 1 } else { 0 }; @@ -191,6 +202,13 @@ pub fn tun_set_persist(fd: &OwnedFd, persist: bool) -> io::Result<()> { Ok(()) } +/// Set the TUN `TUNSETOWNER` ioctl:the uid that may open the tap. +/// +/// # Errors + +/// Returns [`io::ErrorKind::InvalidInput`] when `uid` exceeds the +/// `c_int` range, and the ioctl error when the setting cannot be applied. + #[allow(unsafe_code)] pub fn tun_set_owner(fd: &OwnedFd, uid: u32) -> io::Result<()> { let value = libc::c_int::try_from(uid).map_err(|_| { @@ -206,6 +224,15 @@ pub fn tun_set_owner(fd: &OwnedFd, uid: u32) -> io::Result<()> { Ok(()) } +/// Set the TUN `TUNSETGROUP` ioctl:the gid that may open the tap. +/// +/// # Errors + +/// Returns [`io::ErrorKind::InvalidInput`] when `gid` exceeds the +/// `c_int` range, and the ioctl error when the setting cannot be applied. + + + #[allow(unsafe_code)] pub fn tun_set_group(fd: &OwnedFd, gid: u32) -> io::Result<()> { let value = libc::c_int::try_from(gid).map_err(|_| { @@ -255,6 +282,8 @@ pub mod path_safe { use std::path::{Path, PathBuf}; use std::process::{Command, Output}; + /// Reject a symlink at `path` via `lstat`, returning + /// [`io::ErrorKind::PermissionDenied`] when one sits there. pub fn refuse_symlink(path: &Path) -> io::Result<()> { match fs::symlink_metadata(path) { Ok(md) if md.file_type().is_symlink() => Err(io::Error::new( @@ -265,6 +294,8 @@ pub mod path_safe { } } + /// Reject a world-writable (or symlink) parent directory, the most + /// common path-safety regression.for broker file targets. pub fn refuse_world_writable_parent(path: &Path) -> io::Result<()> { let parent = path.parent().ok_or_else(|| { io::Error::new( @@ -295,6 +326,8 @@ pub mod path_safe { Ok(()) } + /// Refuse a parent directory not owned by uid 0,using the strict + /// no-exception rule for production paths under `/etc` and `/run`. pub fn refuse_non_root_parent(path: &Path) -> io::Result<()> { refuse_non_root_parent_except(path, None) } @@ -326,6 +359,7 @@ pub mod path_safe { Ok(()) } + /// Symlink-refusing read of `path` to a string, via `O_NOFOLLOW`. pub fn read_to_string_nofollow(path: &Path) -> io::Result { refuse_symlink(path)?; let mut f = OpenOptions::new() @@ -337,6 +371,8 @@ pub mod path_safe { Ok(s) } +/// Write `body` to `path`, refusing symlinks and world-writable parents + /// and opening with `O_NOFOLLOW`. pub fn write_nofollow(path: &Path, body: &[u8]) -> io::Result<()> { refuse_world_writable_parent(path)?; refuse_symlink(path)?; @@ -395,6 +431,8 @@ pub mod path_safe { })?; Ok((parent.to_path_buf(), name.to_owned())) } + /// Remove `path` via an fd-relative unlink of its basename, refusing + /// symlink traversal in the parent directory. pub fn remove_nofollow(path: &Path) -> io::Result<()> { let (parent, name) = parent_and_name(path)?; let parent_fd = open_dir_path_safe(&parent)?; @@ -2892,8 +2930,8 @@ pub mod pidfd_sys { n /= 10; len += 1; } - for i in 0..len { - buf[i] = tmp[len - 1 - i]; + for (dst, src) in buf[..len].iter_mut().zip(tmp[..len].iter().rev()) { + *dst = *src; } len } From 4234afe181e268eaf716607671d804d7b529a8a7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:37 -0700 Subject: [PATCH 030/726] ops: factor absolute path checks into helper --- packages/d2b-broker/src/ops/exec_reconcile.rs | 81 ++++--------------- 1 file changed, 17 insertions(+), 64 deletions(-) diff --git a/packages/d2b-broker/src/ops/exec_reconcile.rs b/packages/d2b-broker/src/ops/exec_reconcile.rs index ed38800f5..f42f61073 100644 --- a/packages/d2b-broker/src/ops/exec_reconcile.rs +++ b/packages/d2b-broker/src/ops/exec_reconcile.rs @@ -389,6 +389,15 @@ impl SystemLiveExec { } } +fn require_absolute(path: &Path, what: &str) -> Result<(), ReconcileExecError> { + if !path.to_str().map(|s| s.starts_with('/')).unwrap_or(false) { + return Err(ReconcileExecError::InvalidInput { + detail: format!("{what} must be absolute: {path:?}"), + }); + } + Ok(()) +} + impl ReconcileExecutor for SystemReconcileExecutor { fn apply_nft_script<'a>( &'a self, @@ -396,18 +405,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { script: &'a str, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !nft_binary - .to_str() - .map(|s| s.starts_with('/')) - .unwrap_or(false) - { - return Err(ReconcileExecError::InvalidInput { - detail: format!( - "nft binary path must be absolute, got {:?}", - nft_binary.display().to_string() - ), - }); - } + require_absolute(nft_binary, "nft binary path")?; if script.is_empty() { return Err(ReconcileExecError::InvalidInput { detail: "nft script is empty".to_owned(), @@ -504,11 +502,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { mode: u32, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !path.to_str().map(|s| s.starts_with('/')).unwrap_or(false) { - return Err(ReconcileExecError::InvalidInput { - detail: format!("path must be absolute: {:?}", path.display().to_string()), - }); - } + require_absolute(path, "path")?; let parent = path .parent() .ok_or_else(|| ReconcileExecError::InvalidInput { @@ -548,11 +542,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { owner_gid: u32, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !path.to_str().map(|s| s.starts_with('/')).unwrap_or(false) { - return Err(ReconcileExecError::InvalidInput { - detail: format!("path must be absolute: {:?}", path.display().to_string()), - }); - } + require_absolute(path, "path")?; let parent = path .parent() .ok_or_else(|| ReconcileExecError::InvalidInput { @@ -595,11 +585,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { value: &'a str, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !path.to_str().map(|s| s.starts_with('/')).unwrap_or(false) { - return Err(ReconcileExecError::InvalidInput { - detail: format!("path must be absolute: {:?}", path.display().to_string()), - }); - } + require_absolute(path, "path")?; if value.contains('\n') { return Err(ReconcileExecError::InvalidInput { detail: format!("path value contains newline: {value:?}"), @@ -619,11 +605,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { path: &'a Path, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !path.to_str().map(|s| s.starts_with('/')).unwrap_or(false) { - return Err(ReconcileExecError::InvalidInput { - detail: format!("path must be absolute: {:?}", path.display().to_string()), - }); - } + require_absolute(path, "path")?; crate::sys::path_safe::read_to_string_nofollow(path).map_err(|e| { ReconcileExecError::Io { path: path.display().to_string(), @@ -640,18 +622,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { route_spec: &'a str, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !ip_binary - .to_str() - .map(|s| s.starts_with('/')) - .unwrap_or(false) - { - return Err(ReconcileExecError::InvalidInput { - detail: format!( - "ip binary path must be absolute, got {:?}", - ip_binary.display().to_string() - ), - }); - } + require_absolute(ip_binary, "ip binary path")?; if route_spec.is_empty() { return Err(ReconcileExecError::InvalidInput { detail: "route spec is empty".to_owned(), @@ -695,18 +666,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { bus_id: &'a str, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !usbip_binary - .to_str() - .map(|s| s.starts_with('/')) - .unwrap_or(false) - { - return Err(ReconcileExecError::InvalidInput { - detail: format!( - "usbip binary path must be absolute, got {:?}", - usbip_binary.display().to_string() - ), - }); - } + require_absolute(usbip_binary, "usbip binary path")?; if bus_id.is_empty() { return Err(ReconcileExecError::InvalidInput { detail: "usbip bus_id is empty".to_owned(), @@ -811,14 +771,7 @@ impl ReconcileExecutor for SystemReconcileExecutor { comment: &'a str, ) -> Pin> + Send + 'a>> { Box::pin(async move { - if !key_path.is_absolute() { - return Err(ReconcileExecError::InvalidInput { - detail: format!( - "ssh-keygen path must be absolute, got {:?}", - key_path.display().to_string() - ), - }); - } + require_absolute(key_path, "ssh-keygen path")?; if comment.contains('\n') { return Err(ReconcileExecError::InvalidInput { detail: "ssh-keygen comment must be single-line".to_owned(), From 5a2fa07c7686288d2d1d24ec2bce42887aafc270 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:37 -0700 Subject: [PATCH 031/726] ops: share store helper invocation plumbing --- .../d2b-broker/src/ops/store_view_farm.rs | 171 ++++++++---------- 1 file changed, 76 insertions(+), 95 deletions(-) diff --git a/packages/d2b-broker/src/ops/store_view_farm.rs b/packages/d2b-broker/src/ops/store_view_farm.rs index 7bc9b667d..401e88f3b 100644 --- a/packages/d2b-broker/src/ops/store_view_farm.rs +++ b/packages/d2b-broker/src/ops/store_view_farm.rs @@ -65,8 +65,7 @@ const HELPER_BIN: &str = "/run/current-system/sw/bin/d2b-activation-helper"; /// inodes. All other errors (collision / marker / genuine I/O) propagate /// unchanged. Returns the generation directory on success. /// -/// Async form used by the async exec_reconcile and store_sync paths;the sync -/// form was removed with its last sync caller (store_sync converted to async). +/// Async counterpart used by the async exec_reconcile/store_sync callers. pub async fn build_farm_cross_mount_safe_async( farm_root: &Path, generation: u64, @@ -86,32 +85,14 @@ fn farm_build_argv(helper_bin: &str) -> Vec { private_store_argv(helper_bin, "build-store-view-farm") } -/// Run the hardlink-farm build inside a private mount namespace where -/// `/nix/store` is lazily detached. -/// -/// Errors are surfaced as the typed [`HardlinkFarmError`] - recovered -/// from the helper's stdout JSON when the failure was a farm-build -/// error (collision / different-filesystem / marker), or wrapped as -/// [`HardlinkFarmError::Io`] for spawn / protocol failures - so callers -/// keep their existing `map_hardlink_farm_error` / `?` mapping. -async fn build_farm_via_namespace( +/// Spawn the store helper, write the JSON request to stdin, drain its +/// output, and return the raw output for the caller's success handling. +async fn run_store_helper( + argv: &[String], + payload: Vec, farm_root: &Path, - generation: u64, - closure_paths: &[PathBuf], - marker: &GenerationMarker, -) -> Result { - let request = BuildStoreViewFarmRequest { - farm_root: farm_root.to_path_buf(), - generation, - closure_paths: closure_paths.to_vec(), - marker: marker.clone(), - }; - let payload = serde_json::to_vec(&request).map_err(|e| HardlinkFarmError::Io { - path: farm_root.display().to_string(), - detail: format!("serialise store-view farm request: {e}"), - })?; - - let argv = farm_build_argv(HELPER_BIN); + verb_label: &str, +) -> Result { let mut child = tokio::process::Command::new(&argv[0]) .args(&argv[1..]) .env_remove("NOTIFY_SOCKET") @@ -121,21 +102,23 @@ async fn build_farm_via_namespace( .spawn() .map_err(|e| HardlinkFarmError::Io { path: argv[0].clone(), - detail: format!("spawn unshare for store-view farm build: {e}"), + detail: format!("spawn unshare for {verb_label}: {e}"), })?; // Write the request from a task and close stdin so the helper sees // EOF; `wait_with_output` drains stdout/stderr concurrently, so no // pipe-buffer deadlock can occur even when the request exceeds the // stdin pipe capacity. + let mut stdin = child.stdin.take().ok_or_else(|| HardlinkFarmError::Io { path: farm_root.display().to_string(), - detail: "child stdin unavailable for store-view farm build".to_owned(), + detail: format!("child stdin unavailable for {verb_label}"), })?; let writer = tokio::spawn(async move { use tokio::io::AsyncWriteExt; let _ = stdin.write_all(&payload).await; // stdin dropped here -> EOF for the helper. + }); let output = child @@ -143,32 +126,31 @@ async fn build_farm_via_namespace( .await .map_err(|e| HardlinkFarmError::Io { path: farm_root.display().to_string(), - detail: format!("await store-view farm build: {e}"), + detail: format!("await {verb_label}: {e}"), })?; let _ = writer.await; + Ok(output) +} - let generation_dir = farm_root.join("generations").join(generation.to_string()); - - if output.status.success() { - return Ok(generation_dir); - } - - // The helper emits the typed HardlinkFarmError as a single JSON - // line on stdout when build_farm itself failed; recover it so the - // collision / different-fs / marker mapping is preserved. Fall back - // to a generic Io error carrying stderr for spawn/protocol faults. +/// Convert a failed store-helper output into the typed farm error, or +/// a generic Io error for spawn/protocol faults carrying stderr. +fn store_helper_failure( + output: std::process::Output, + farm_root: &Path, + verb_label: &str, +) -> HardlinkFarmError { if let Some(line) = String::from_utf8_lossy(&output.stdout) .lines() .map(str::trim) .find(|l| !l.is_empty()) && let Ok(typed) = serde_json::from_str::(line) { - return Err(typed); + return typed; } - Err(HardlinkFarmError::Io { + HardlinkFarmError::Io { path: farm_root.display().to_string(), detail: format!( - "store-view farm build helper failed (exit {}): {}", + "{verb_label} helper failed (exit {}): {}", output .status .code() @@ -176,7 +158,44 @@ async fn build_farm_via_namespace( .unwrap_or_else(|| "signal".to_owned()), String::from_utf8_lossy(&output.stderr).trim(), ), - }) + } +} + +/// Run the hardlink-farm build inside a private mount namespace where +/// `/nix/store` is lazily detached. +/// +/// Errors are surfaced as the typed [`HardlinkFarmError`] - recovered +/// from the helper's stdout JSON when the failure was a farm-build +/// error (collision / different-filesystem / marker), or wrapped as +/// [`HardlinkFarmError::Io`] for spawn / protocol failures - so callers +/// keep their existing `map_hardlink_farm_error` / `?` mapping. +async fn build_farm_via_namespace( + farm_root: &Path, + generation: u64, + closure_paths: &[PathBuf], + marker: &GenerationMarker, +) -> Result { + let request = BuildStoreViewFarmRequest { + farm_root: farm_root.to_path_buf(), + generation, + closure_paths: closure_paths.to_vec(), + marker: marker.clone(), + }; + let payload = serde_json::to_vec(&request).map_err(|e| HardlinkFarmError::Io { + path: farm_root.display().to_string(), + detail: format!("serialise store-view farm request: {e}"), + })?; + + let argv = farm_build_argv(HELPER_BIN); + let output = run_store_helper(&argv, payload, farm_root, "store-view farm build").await?; + + let generation_dir = farm_root.join("generations").join(generation.to_string()); + + if output.status.success() { + return Ok(generation_dir); + } + + Err(store_helper_failure(output, farm_root, "store-view farm build")) } /// Materialise one generation of the ADR 0027 **split** store view @@ -190,8 +209,17 @@ async fn build_farm_via_namespace( /// `meta/current` or plant the live marker - the broker performs those /// in-process publish steps after a successful materialisation. /// -/// Async form used by the async exec_reconcile and store_sync paths;the sync -/// form was removed with its last sync caller (store_sync converted to async). +/// Async counterpart used by the async exec_reconcile/store_sync callers. +/// +/// # Errors +/// +/// Returns farm errors with the same recovery semantics as +/// [`build_farm_cross_mount_safe_async`]: a +/// [`HardlinkFarmError::CrossMountLink`] from the in-process attempt +/// triggers the namespace-isolated retry, a fatal +/// [`HardlinkFarmError::DifferentFilesystem`] propagates unchanged, and +/// all other errors (collision / marker / I/O) are surfaced as the typed +/// [`HardlinkFarmError`]. pub async fn build_store_view_cross_mount_safe_async( farm_root: &Path, generation_id: &str, @@ -243,60 +271,13 @@ async fn build_store_view_via_namespace( })?; let argv = store_view_build_argv(HELPER_BIN); - let mut child = tokio::process::Command::new(&argv[0]) - .args(&argv[1..]) - .env_remove("NOTIFY_SOCKET") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .map_err(|e| HardlinkFarmError::Io { - path: argv[0].clone(), - detail: format!("spawn unshare for store-view build: {e}"), - })?; - - let mut stdin = child.stdin.take().ok_or_else(|| HardlinkFarmError::Io { - path: farm_root.display().to_string(), - detail: "child stdin unavailable for store-view build".to_owned(), - })?; - let writer = tokio::spawn(async move { - use tokio::io::AsyncWriteExt; - let _ = stdin.write_all(&payload).await; - }); - - let output = child - .wait_with_output() - .await - .map_err(|e| HardlinkFarmError::Io { - path: farm_root.display().to_string(), - detail: format!("await store-view build: {e}"), - })?; - let _ = writer.await; + let output = run_store_helper(&argv, payload, farm_root, "store-view build").await?; if output.status.success() { return parse_store_view_counts(&output.stdout, farm_root); } - if let Some(line) = String::from_utf8_lossy(&output.stdout) - .lines() - .map(str::trim) - .find(|l| !l.is_empty()) - && let Ok(typed) = serde_json::from_str::(line) - { - return Err(typed); - } - Err(HardlinkFarmError::Io { - path: farm_root.display().to_string(), - detail: format!( - "store-view build helper failed (exit {}): {}", - output - .status - .code() - .map(|c| c.to_string()) - .unwrap_or_else(|| "signal".to_owned()), - String::from_utf8_lossy(&output.stderr).trim(), - ), - }) + Err(store_helper_failure(output, farm_root, "store-view build")) } fn parse_store_view_counts( stdout: &[u8], From c155578ca7e556012640e714b74f054b54788d02 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:38 -0700 Subject: [PATCH 032/726] ops: dedupe resource row lookup --- packages/d2b-broker/src/ops/device_worker.rs | 136 ++++++++++--------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/packages/d2b-broker/src/ops/device_worker.rs b/packages/d2b-broker/src/ops/device_worker.rs index 914b89521..3193c7e56 100644 --- a/packages/d2b-broker/src/ops/device_worker.rs +++ b/packages/d2b-broker/src/ops/device_worker.rs @@ -307,6 +307,20 @@ pub(crate) fn zone_bundle_for_uid<'a>( Some((zone.as_str().to_owned(), bytes)) } +/// The first row of a verified Zone resource bundle's `resources` array +/// that satisfies `pred`, keeping the row-walk in one place for every +/// bundle-shape consumer. +fn find_resource_row<'a>( + bundle: &'a serde_json::Value, + pred: impl FnMut(&&'a serde_json::Value) -> bool, +) -> Option<&'a serde_json::Value> { + bundle + .get("resources")? + .as_array()? + .iter() + .find(pred) +} + /// The authored `metadata.ownerRef` of one row of a verified Zone resource /// bundle, parsed into a canonical reference. pub(crate) fn row_owner_ref( @@ -314,21 +328,20 @@ pub(crate) fn row_owner_ref( resource_type: &str, name: &str, ) -> Option { - let bundle: serde_json::Value = serde_json::from_slice(bundle_bytes).ok()?; - for resource in bundle.get("resources")?.as_array()? { - if resource.get("type").and_then(serde_json::Value::as_str) != Some(resource_type) { - continue; - } - let metadata = resource.get("metadata")?; - if metadata.get("name").and_then(serde_json::Value::as_str) != Some(name) { - continue; - } - return metadata - .get("ownerRef") - .and_then(serde_json::Value::as_str) - .and_then(|owner| ResourceRef::parse(owner).ok()); - } - None +let bundle: serde_json::Value = serde_json::from_slice(bundle_bytes).ok()?; + let resource = find_resource_row(&bundle, |row| { + row.get("type").and_then(serde_json::Value::as_str) == Some(resource_type) + && row + .get("metadata") + .and_then(|metadata| metadata.get("name")) + .and_then(serde_json::Value::as_str) + == Some(name) + })?; + resource + .get("metadata")? + .get("ownerRef") + .and_then(serde_json::Value::as_str) + .and_then(|owner| ResourceRef::parse(owner).ok()) } /// `Device.metadata.ownerRef == Guest/` for one Device row of a @@ -338,25 +351,22 @@ pub(crate) fn row_owner_ref( /// worker's VM scope. pub(crate) fn device_guest_owner(bundle_bytes: &[u8], device: &str) -> Option { let bundle: serde_json::Value = serde_json::from_slice(bundle_bytes).ok()?; - for resource in bundle.get("resources")?.as_array()? { - if resource.get("type").and_then(serde_json::Value::as_str) != Some("Device") { - continue; - } - let Some(metadata) = resource.get("metadata") else { - continue; - }; - if metadata.get("name").and_then(serde_json::Value::as_str) != Some(device) { - continue; - } - let owner = metadata - .get("ownerRef") - .and_then(serde_json::Value::as_str)?; - return owner - .strip_prefix("Guest/") - .map(str::to_owned) - .filter(|guest| !guest.is_empty()); - } - None + let resource = find_resource_row(&bundle, |row| { + row.get("type").and_then(serde_json::Value::as_str) == Some("Device") + && row + .get("metadata") + .and_then(|metadata| metadata.get("name")) + .and_then(serde_json::Value::as_str) + == Some(device) + })?; + let owner = resource + .get("metadata")? + .get("ownerRef") + .and_then(serde_json::Value::as_str)?; + owner + .strip_prefix("Guest/") + .map(str::to_owned) + .filter(|guest| !guest.is_empty()) } /// Every TPM Device the verified bundles declare for one Guest, as @@ -376,6 +386,7 @@ pub(crate) fn tpm_devices_of_guest( return Vec::new(); }; let mut devices = Vec::new(); + let expected_owner = format!("Guest/{guest}"); for zone in zones { let Some(bytes) = resolver.zone_resource_bundle_bytes(zone.as_str()) else { continue; @@ -383,40 +394,33 @@ pub(crate) fn tpm_devices_of_guest( let Ok(bundle) = serde_json::from_slice::(bytes) else { continue; }; - let Some(resources) = bundle.get("resources").and_then(|rows| rows.as_array()) else { + let Some(resource) = find_resource_row(&bundle, |row| { + row.get("type").and_then(serde_json::Value::as_str) == Some("Device") + && row + .get("metadata") + .and_then(|metadata| metadata.get("ownerRef")) + .and_then(serde_json::Value::as_str) + == Some(expected_owner.as_str()) + && row + .pointer("/spec/providerRef") + .and_then(serde_json::Value::as_str) + == Some(DEVICE_TPM_PROVIDER_REF) + }) else { continue; }; - for resource in resources { - if resource.get("type").and_then(serde_json::Value::as_str) != Some("Device") { - continue; - } - let Some(metadata) = resource.get("metadata") else { - continue; - }; - let expected_owner = format!("Guest/{guest}"); - if metadata.get("ownerRef").and_then(serde_json::Value::as_str) - != Some(expected_owner.as_str()) - { - continue; - } - if resource - .pointer("/spec/providerRef") - .and_then(serde_json::Value::as_str) - != Some(DEVICE_TPM_PROVIDER_REF) - { - continue; - } - let Some(name) = metadata.get("name").and_then(serde_json::Value::as_str) else { - continue; - }; - let Some(device_ref) = ResourceRef::parse(&format!("Device/{name}")).ok() else { - continue; - }; - devices.push(( - device_ref, - deterministic_resource_uid(zone.as_str(), "Device", name), - )); - } + let Some(name) = resource + .get("metadata") + .and_then(|metadata| metadata.get("name")) + .and_then(serde_json::Value::as_str) else { + continue; + }; + let Some(device_ref) = ResourceRef::parse(&format!("Device/{name}")).ok() else { + continue; + }; + devices.push(( + device_ref, + deterministic_resource_uid(zone.as_str(), "Device", name), + )); } devices } From ac44605b7e0784586b6fad255eb4c13b657f05c6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:38 -0700 Subject: [PATCH 033/726] envelope: gate trusted context store helpers to cfg test --- packages/d2b-broker/src/envelope/mod.rs | 33 ++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/d2b-broker/src/envelope/mod.rs b/packages/d2b-broker/src/envelope/mod.rs index b876c078e..0818d9b0e 100644 --- a/packages/d2b-broker/src/envelope/mod.rs +++ b/packages/d2b-broker/src/envelope/mod.rs @@ -385,7 +385,7 @@ enum ContextCommand { /// worker. The store is usable only after the reply. Bootstrap { root: PathBuf, - reply: oneshot::Sender>, + reply: oneshot::Sender>, }, /// One publish-as-one-atomic-unit: monotonic check + in-memory commit + /// durable persist. @@ -433,6 +433,7 @@ impl TrustedContextStore { /// the reply gates the handle). The daemon's last-published values are /// loaded with it, so a restarting broker still holds the values it /// published for while minting under a nonce no prior context carries. + #[cfg(test)] pub fn open(root: impl Into) -> Result { let root = root.into(); let (commands, receiver) = mpsc::channel::(Self::WORKER_QUEUE_DEPTH); @@ -543,6 +544,7 @@ impl TrustedContextStore { /// The whole unit (monotonic check + in-memory commit + durable persist) /// runs on the single writer, so channel order is commit order and a /// concurrent stale publication can never durably regress newer state. + #[cfg(test)] pub fn publish( &self, values: &PublishTrustedContextValues, @@ -566,7 +568,7 @@ impl TrustedContextStore { /// Cache one daemon publication, monotonically, from an async context. /// - /// The async twin of [`TrustedContextStore::publish`]: the dispatch + /// The async twin of the sync `publish`:the dispatch /// chain runs on the broker's reactor, so the command is sent and the /// reply awaited in async time instead of parking an executor worker on /// the blocking boundary. @@ -668,7 +670,7 @@ fn context_worker_loop(mut receiver: mpsc::Receiver) { return; } }; - let _ = reply.send(Ok(state.state.clone())); + let _ = reply.send(Ok(())); while let Some(command) = receiver.blocking_recv() { match command { ContextCommand::Publish { values, reply } => { @@ -847,6 +849,7 @@ static TRUSTED_CONTEXT_STORE: std::sync::OnceLock = std::sy /// Called once in `run_server` before the broker serves; a store that fails /// to open fails the broker closed at startup rather than attesting or /// caching under a half-open state. +#[cfg(test)] pub(crate) fn init_trusted_context_store(state_dir: &Path) -> Result<(), TrustedContextStoreError> { let store = TrustedContextStore::open(state_dir)?; let _ = TRUSTED_CONTEXT_STORE.set(store); @@ -1115,6 +1118,16 @@ impl BrokerEnvelope { /// follow a denied invocation in the audit log. The call is async /// because the dispatch step is: a forwarded row's handler runs in the /// declaring process and is reached over an async dial. + /// + /// # Errors + /// + /// Refuses with any code of the closed [`ENVELOPE_REFUSALS`] vocabulary: + /// [`UNKNOWN_OPERATION`], [`UNCOMMITTED_OPERATION`], + /// [`UNGRANTED_CALLER`], [`WIRE_INHERITED_OPERATION`], + /// [`INVALID_PAYLOAD`], [`UNREGISTERED_HANDLER`], [`FD_LEG`], + /// [`STALE_CONTEXT`], the handler dispatch outcomes ([`HANDLER_REFUSED`], + /// [`HANDLER_ERRORED`], [`HANDLER_TIMED_OUT`], [`HANDLER_CRASHED`]), and + /// [`STALE_WIRE_VERSION`] / [`NESTED_DEPTH_EXCEEDED`] at the gates. pub async fn call( &self, caller: CallerAuthority, @@ -1133,6 +1146,13 @@ impl BrokerEnvelope { /// here against the row's declared fd facet before dispatch,so an /// oversized-but-transport-legal set is refused with the fd-leg code /// rather than truncated by the transport.where + /// + /// # Errors + /// + /// Refuses with the same closed [`ENVELOPE_REFUSALS`] vocabulary as + /// [`BrokerEnvelope::call`], plus [`FD_LEG`] for descriptor sets that + /// disagree with the row's declared fd facet or exceed the bounded + /// ceiling. pub async fn call_with_fds( &self, caller: CallerAuthority, @@ -1184,6 +1204,13 @@ impl BrokerEnvelope { } /// Invoke one nested operation with descriptors attached to it. + /// + /// # Errors + /// + /// Refuses with the same closed [`ENVELOPE_REFUSALS`] vocabulary as + /// [`BrokerEnvelope::call_with_fds`], with the chain's authz checked + /// under the initiating principal and [`NESTED_DEPTH_EXCEEDED`] named + /// for chains past the depth cap before anything else. pub async fn call_nested_with_fds( &self, chain: EvidenceChain, From c3ac2bb5970721966735a3f6938af4031f15ca4e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:39 -0700 Subject: [PATCH 034/726] ops: drop redundant pidfd payload clone --- packages/d2b-broker/src/ops/pidfd.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/d2b-broker/src/ops/pidfd.rs b/packages/d2b-broker/src/ops/pidfd.rs index ad82d7b71..b7413d6a5 100644 --- a/packages/d2b-broker/src/ops/pidfd.rs +++ b/packages/d2b-broker/src/ops/pidfd.rs @@ -109,6 +109,7 @@ pub enum PidfdMethod { } impl PidfdMethod { + /// The stable audit spelling of this method kind. pub fn as_str(&self) -> &'static str { match self { PidfdMethod::Clone3 => "clone3", @@ -124,6 +125,7 @@ impl PidfdMethod { pub struct StartTime(pub u64); impl StartTime { + /// Whether the two observed start times agree (same process era). pub fn matches(self, other: StartTime) -> bool { self.0 == other.0 } @@ -188,6 +190,7 @@ pub struct PidfdPayload { pub struct RealPidfdSpawner; impl RealPidfdSpawner { + /// A real syscall-backed spawner, preferring `clone3(CLONE_PIDFD)`. pub fn new() -> Self { Self } @@ -196,7 +199,7 @@ impl RealPidfdSpawner { impl PidfdSpawner for RealPidfdSpawner { fn spawn( &self, - payload: PidfdPayload, + _payload: PidfdPayload, ) -> Result<(PidfdHandle, OwnedFd, PidfdMethod), PidfdOpError> { use crate::sys::pidfd_sys; use std::os::fd::AsRawFd; @@ -207,7 +210,6 @@ impl PidfdSpawner for RealPidfdSpawner { // before exec). Keeping that wiring out of the broker crate // preserves the `#![deny(unsafe_code)]` posture on every code // path the daemon will reach via the SCM_RIGHTS pidfd transport. - let _argv = payload.argv.clone(); let child_main = || -> i32 { 0 }; let outcome = pidfd_sys::clone3_pidfd_or_fork_fallback(0, child_main).map_err(|err| { From b09261be092b15764ca576f91f4035b63bc77156 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:39 -0700 Subject: [PATCH 035/726] ops: polish media enrollment and document operations --- packages/d2b-broker/src/ops/media.rs | 113 ++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index 4e7269434..281af193e 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -43,27 +43,51 @@ static D2BD_GROUP_GID: std::sync::LazyLock, Stri .map_err(|err| format!("resolve d2bd group: {err}")) }); +/// A refused qemu-media enrollment/open/lifecycle op: validation +/// failures, bundle-policy refusals, unresolved or unsafe image sources, +/// sysfs identity readback failures, registry/udev write failures, and +/// QMP client/transaction failures all keep their own class. #[derive(Debug)] pub enum MediaOpError { + /// The media ref failed [`d2b_host::media::validate_media_ref`]. InvalidRef(String), + /// The USB bus id failed [`d2b_host::media::validate_usb_busid`]. InvalidBusId(String), + /// The bundle declares no policy for the ref. MissingBundlePolicy, + /// The declared source is not a physical USB device. UnsupportedSourceKind, + /// The source carries no image path. MissingImagePath, + /// The image format is not raw. UnsupportedImageFormat, + /// The resolved image path failed the path-safety walk. ImagePathUnsafe(String), + /// Sysfs identity readback failed. Sysfs(String), + /// The USB device exposes no block device. NoBlockDevice, + /// The USB device exposes multiple block devices. AmbiguousBlockDevice(Vec), + /// The USB identity has no by-id readback. MissingById, + /// The media device is in use and cannot be claimed. DeviceBusy(String), + /// The resolved identity conflicts with an already-enrolled record. IdentityMismatch(String), + /// The runtime hotplug selector matched no unique media ref. AmbiguousRuntimeSelector(Vec), + /// A generic I/O failure. Io(String), + /// A registry read/write failure. Registry(String), + /// A block-device open failure. Open(String), + /// The image is busy and cannot be attached. ImageBusy(String), + /// A QMP scaffold setup failure. QmpScaffold(String), + /// A QMP client/transaction failure. Qmp(String), } @@ -176,27 +200,60 @@ impl MediaRegistryRecord { } } +/// The result of a successful enroll:the broker response plus the count +/// of USB by-id aliases the enrolled device carries. pub struct EnrollOutcome { + /// The wire response echoed to the daemon. pub response: QemuMediaEnrollResponse, + /// How many `/dev/disk/by-id` aliases the enrolled device exposes. pub by_id_count: u32, } +/// The result of a successful attach/detach:the broker wire response. pub struct HotplugOutcome { + /// The wire response echoed to the daemon. pub response: QemuMediaHotplugResponse, } +/// The result of a VM boot media attach:the broker wire response plus +/// which registry/udev artifacts were (re)written and whether udev was +/// reloaded. pub struct BootOutcome { + /// The wire response echoed to the daemon. + pub response: QemuMediaHotplugResponse, + /// Whether the boot wrote a fresh registry record for the media. + pub registry_record_written: bool, + /// Whether the boot rewrote the redacted registry index. + pub redacted_index_written: bool, + /// Whether the boot rewrote the runtime udev rule file. + pub udev_rule_written: bool, + /// Whether udev was reloaded after the rule write. pub udev_reloaded: bool, } +/// The result of a registry refresh:the broker wire response. pub struct RefreshOutcome { + /// The wire response echoed to the daemon. pub response: QemuMediaRefreshRegistryResponse, } +/// Enroll one physical USB media for a VM: validates the ref and bus id, +/// resolves the bundle source,reads the live sysfs identity,preflights +/// busy-ness,opens the block device,then writes the registry record, +/// redacted index,and runtime udev rules and reloads udev. +/// +/// # Errors +/// +/// Refuses with [`MediaOpError::InvalidRef`] / [`MediaOpError::InvalidBusId`] +/// for invalid inputs, the bundle-policy variants (`MissingBundlePolicy`, +/// `UnsupportedSourceKind`) for undeclared sources, sysfs readback and +/// busy refusals,`IdentityMismatch` when the same identity is already +/// enrolled under a different ref, and `Registry` / `Io` for the registry +/// and udev writes. pub async fn enroll( resolver: &BundleResolver, req: &QemuMediaEnrollRequest, @@ -229,7 +286,7 @@ pub async fn enroll( write_registry_record(resolver, &record).await?; let records = read_all_registry_records(resolver) .await - .unwrap_or_else(|_| vec![record.clone()]); + .unwrap_or_else(|_| vec![record]); write_redacted_registry_index(resolver, &records).await?; let udev_rule_written = write_runtime_udev_rules(resolver, &records).await?; let udev_reloaded = reload_udev_rules().await; @@ -247,6 +304,13 @@ pub async fn enroll( }) } +/// Re-read the enrolled registry and rewrite the redacted index and runtime +/// udev rule file,and reload udev. +/// +/// # Errors +/// +/// Returns [`MediaOpError::Registry`] for registry read failures and `Registry` +/// / `Io` for the index and udev-rule writes. pub async fn refresh_registry(resolver: &BundleResolver) -> Result { let records = read_all_registry_records(resolver).await?; let redacted_index_written = @@ -263,6 +327,14 @@ pub async fn refresh_registry(resolver: &BundleResolver) -> Result Result { @@ -290,6 +368,15 @@ pub async fn system_powerdown( }) } +/// Query a VM's QMP status,folding an expected shutdown disconnect into +/// [`QemuMediaVmStatus::ConnectionLostDuringShutdown`] when +/// `shutdown_context` is set. +/// +/// # Errors + +/// Returns [`MediaOpError::Qmp`] when the socket cannot be reached or the +/// query fails outside the expected shutdown-disconnect case. + pub async fn query_status( req: &QemuMediaQueryStatusRequest, ) -> Result { @@ -331,6 +418,15 @@ async fn qmp_query_status_from_path( } } +/// Send `quit` to a VM's QMP socket,ending its QMP session. +/// +/// # Errors + +/// Returns [`MediaOpError::Qmp`] when the socket cannot be reached or the +/// command fails. + + + pub async fn quit(req: &QemuMediaLifecycleRequest) -> Result { let mut client = QmpClient::connect(&qmp_socket_path(req.vm_id.as_str())).await?; qmp_quit(&mut client).await?; @@ -340,6 +436,13 @@ pub async fn quit(req: &QemuMediaLifecycleRequest) -> Result Date: Fri, 25 Sep 2026 02:03:40 -0700 Subject: [PATCH 036/726] ops: document usbip lock contracts --- packages/d2b-broker/src/ops/usbip_lock.rs | 25 ++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/d2b-broker/src/ops/usbip_lock.rs b/packages/d2b-broker/src/ops/usbip_lock.rs index 4ddaa6541..be32d0696 100644 --- a/packages/d2b-broker/src/ops/usbip_lock.rs +++ b/packages/d2b-broker/src/ops/usbip_lock.rs @@ -78,6 +78,11 @@ impl std::fmt::Display for UsbipLockError { impl std::error::Error for UsbipLockError {} /// Open the pre-created parent dir for a busid lock file. +/// +/// # Errors +/// +/// Returns [`UsbipLockError::Io`] when the parent directory cannot be +/// opened. pub fn ensure_lock_root(parent: &Path) -> Result { open_existing_lock_parent(parent).map_err(|e| UsbipLockError::Io { path: parent.to_path_buf(), @@ -85,7 +90,13 @@ pub fn ensure_lock_root(parent: &Path) -> Result { }) } -/// Acquire a per-busid lock; refuses if already held. +/// Acquire a per-busid lock; refuses if already held.. +/// +/// # Errors +/// +/// Returns [`UsbipLockError::LockAlreadyHeld`] when another VM already +/// owns the lock file, and [`UsbipLockError::Io`] for path resolution or +/// lock-file creation failures. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn acquire_lock( lock_path: &Path, @@ -168,6 +179,13 @@ pub fn acquire_lock( /// Owner mismatch is a typed error (defence-in-depth against a /// stale unbind happening after a different VM rebound the same /// busid). +/// +/// # Errors +/// +/// Returns [`UsbipLockError::OwnerMismatch`] when the lock file's +/// observed owner differs from `expected_owner`, and [`UsbipLockError::Io`] +/// for read or removal failures (besides the treated-as-success +/// missing-file cases). pub fn release_lock(lock_path: &Path, expected_owner: &str) -> Result<(), UsbipLockError> { let full_lock_path = resolve_lock_path(lock_path).map_err(|e| UsbipLockError::Io { path: lock_path.to_path_buf(), @@ -312,8 +330,9 @@ fn read_owner(path: &Path) -> std::io::Result { } /// Read the current owner of a busid lock without modifying it. -/// Used by reconcile / proxy-reconcile to verify expected ownership. -pub fn peek_owner(lock_path: &Path) -> Option { + /// Used by reconcile / proxy-reconcile to verify expected ownership. + /// Returns `None` when the lock cannot be read (missing or I/O error). + pub fn peek_owner(lock_path: &Path) -> Option { read_owner(lock_path).ok() } From 4bfa5fd518a174c2be0196f965f5462c0925c479 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:40 -0700 Subject: [PATCH 037/726] ops: document usbip host ops --- packages/d2b-broker/src/ops/usbip_host.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/d2b-broker/src/ops/usbip_host.rs b/packages/d2b-broker/src/ops/usbip_host.rs index f21f39aed..e5c7709b9 100644 --- a/packages/d2b-broker/src/ops/usbip_host.rs +++ b/packages/d2b-broker/src/ops/usbip_host.rs @@ -13,6 +13,9 @@ use std::pin::Pin; use d2b_core::bundle_resolver::ResolvedUsbipBindIntent; use d2b_core::host::VendorProductPair; +/// A fail-closed refusal from USBIP host inspection: invalid or departed +/// devices, allowlist mismatches, topology drift, and I/O failures all +/// refuse named rather than replaying a claim blind. #[derive(Debug, Clone, PartialEq, Eq)] pub enum UsbipHostInspectionError { InvalidBusId { @@ -149,6 +152,8 @@ impl std::fmt::Display for UsbipHostInspectionError { impl std::error::Error for UsbipHostInspectionError {} +/// Which driver currently owns a USB device's kernel interface: unbound, +/// bound to the usbip-host stub, or bound to an unrelated driver. #[derive(Debug, Clone, PartialEq, Eq)] pub enum UsbipDriverBinding { Unbound, @@ -156,14 +161,26 @@ pub enum UsbipDriverBinding { BoundToOtherDriver { driver: String }, } +/// The observed identity and topology of one USB device under sysfs, +/// matching the bundle intend's allowlist and declared physical location. #[derive(Debug, Clone, PartialEq, Eq)] pub struct UsbipHostDeviceInspection { + /// The USBIP bus id the device was inspected under. pub bus_id: String, + /// The observed USB vendor id. + pub vendor: u16, + /// The observed USB product id. + pub product: u16, + /// The physical bus number the device sits on. pub bus_number: u16, + /// The physical port chain under the bus, root-first. + pub port_chain: Vec, + /// The device node (e.g. `/dev/bus/usb/...`) the device exposes. pub device_node: PathBuf, + /// Which kernel driver currently binds the device's interface. pub driver: UsbipDriverBinding, } From 7cf9b6478e07fa9f160ebc71f3c38507ff7821c6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:40 -0700 Subject: [PATCH 038/726] ops: document sysctl helpers --- packages/d2b-broker/src/ops/sysctl.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/d2b-broker/src/ops/sysctl.rs b/packages/d2b-broker/src/ops/sysctl.rs index 3a03c75a6..803b40322 100644 --- a/packages/d2b-broker/src/ops/sysctl.rs +++ b/packages/d2b-broker/src/ops/sysctl.rs @@ -20,6 +20,7 @@ pub struct ApplySysctlRequest { } impl ApplySysctlRequest { + /// Build a request writing under the default `/proc/sys` root. pub fn with_default_root(intents: Vec) -> Self { Self { intents, @@ -28,6 +29,7 @@ impl ApplySysctlRequest { } } +/// One applied sysctl write with its before/after values and drift verdict. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ApplySysctlOutcome { pub key: String, @@ -36,6 +38,8 @@ pub struct ApplySysctlOutcome { pub drift: bool, } +/// A failed sysctl application: an I/O failure or a readback drift +/// after the write. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ApplySysctlError { Io(String), @@ -109,6 +113,8 @@ pub async fn apply_sysctl_intents( Ok(out) } +/// A sysctl-apply failure from the executor or the post-write readback: +/// an executor error, a readback I/O failure, or observed drift. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ApplyWithReadbackError { ReconcileExec(ReconcileExecError), From 380e073d53d840233795e33dd35f9b10302c5d02 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:41 -0700 Subject: [PATCH 039/726] ops: document storage contract helpers --- packages/d2b-broker/src/ops/storage_contract.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/d2b-broker/src/ops/storage_contract.rs b/packages/d2b-broker/src/ops/storage_contract.rs index 721123d8c..40302dc16 100644 --- a/packages/d2b-broker/src/ops/storage_contract.rs +++ b/packages/d2b-broker/src/ops/storage_contract.rs @@ -17,6 +17,9 @@ use nix::unistd::{Gid, Group, Uid, User}; use super::hosts::stable_hash_str; +/// A storage/sync contract refusal: an unknown storage or lock id, a +/// deliberate refusal or invalid subject, or an I/O failure on a resolved +/// path. #[derive(Debug, Clone, PartialEq, Eq)] pub enum StorageContractError { UnknownStorage(String), From e507a1e718b9d96378f31b4913fc908d95708e4b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:41 -0700 Subject: [PATCH 040/726] ops: document shared op error surfaces --- packages/d2b-broker/src/ops/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/d2b-broker/src/ops/mod.rs b/packages/d2b-broker/src/ops/mod.rs index 67cefbf4c..2fec102e7 100644 --- a/packages/d2b-broker/src/ops/mod.rs +++ b/packages/d2b-broker/src/ops/mod.rs @@ -161,6 +161,7 @@ pub enum AuditDecision { } impl AuditDecision { + /// The audit-record `decision` spelling of this category. pub fn as_str(&self) -> &'static str { match self { AuditDecision::Allowed => "allowed", From 1643cd53235ad51a19f823f37a996106a1f11fe1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:42 -0700 Subject: [PATCH 041/726] audit: document audit log contracts --- packages/d2b-broker/src/audit.rs | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/packages/d2b-broker/src/audit.rs b/packages/d2b-broker/src/audit.rs index 7625edde1..cf8373c00 100644 --- a/packages/d2b-broker/src/audit.rs +++ b/packages/d2b-broker/src/audit.rs @@ -80,9 +80,17 @@ impl AuditWriteClass { } } +/// Aggregated audit-drop counts: how many privileged and unprivileged +/// records were rate-limited rather than durably written. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub struct AuditDropSummary { + /// Privileged-class records dropped by the rate limiter. + pub privileged_rate_limited: u64, + /// Unprivileged-class records dropped by the rate limiter. + + + pub unprivileged_rate_limited: u64, } @@ -120,16 +128,50 @@ impl AuditDropWarningState { } } +/// One legacy JSONL audit record, consumed by the socket-acl gate: +/// `ts` / `op` identify the operation, `disposition` the authz outcome class +/// (`allowed` / `denied-*` / `errored`), `outcome` the finer result +/// spelling, and the optional error fields carry the failure detail. #[derive(Clone)] pub struct AuditEntry<'a> { + /// Monotonic timestamp, microseconds since an arbitrary epoch. + pub ts: u128, + /// The audited operation name. + pub op: &'a str, + /// The caller's uid. + + pub caller_uid: u32, + /// The caller's gid, when known. + + + pub caller_gid: Option, + /// The authz outcome class. + + + pub disposition: &'a str, + /// The opaque target operation id, when the operation names one. + + + pub opaque_target_id: &'a str, + /// The finer result spelling (`ok`/refusal/error kind).) + + + pub outcome: &'a str, + /// The error kind, when the outcome is an error. + + + pub error_kind: Option<&'a str>, + /// The error detail, when present. + + pub error_message: Option<&'a str>, } @@ -413,6 +455,12 @@ impl DailyAppender { } impl AuditLog { + /// Open the broker's audit log under `audit_dir`, the daemon's entry + /// point: runs the full bootstrap/poison barrier (symlink refusal, + /// directory lock, reconciliation, appender setup, prune) on the + /// worker before returning, so a fresh writer never observes a + /// half-opened directory. + pub fn open( audit_dir: &Path, expected_gid: u32, @@ -1026,6 +1074,8 @@ impl AuditLog { self.write_op_record(&record) } + /// Query the rate-limited drop counters, merging the worker-side counts + /// with the caller-side queue-full drops the worker never saw. pub fn audit_drop_summary(&self) -> io::Result { let (reply_tx, reply_rx) = mpsc::sync_channel(1); let mut summary = self.submit( From 7ac3d8cdf96c95f5f01f142d146919994eb6329a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:42 -0700 Subject: [PATCH 042/726] ops: document generation handoff contract --- packages/d2b-broker/src/ops/host_generation_handoff.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/d2b-broker/src/ops/host_generation_handoff.rs b/packages/d2b-broker/src/ops/host_generation_handoff.rs index 856d6e857..1e6aaf15e 100644 --- a/packages/d2b-broker/src/ops/host_generation_handoff.rs +++ b/packages/d2b-broker/src/ops/host_generation_handoff.rs @@ -31,6 +31,11 @@ struct JournalEntry { coordinator: HandoffCoordinator, } +/// A handoff apply/replay failure: journal replays either carry the typed +/// validation error (`Invalid` / `Io`) or refuse on a journal/helper +/// mismatch or helper unavailability; artifact-validation failures keep +/// their own variants so callers can distinguish helper faults from +/// validation-output faults. #[derive(Debug)] pub enum HandoffOperationError { Invalid(HandoffError), From 025b075a8ee727bc487d8f143aee0400d06c972b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:42 -0700 Subject: [PATCH 043/726] ops: document route ops --- packages/d2b-broker/src/ops/route.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/d2b-broker/src/ops/route.rs b/packages/d2b-broker/src/ops/route.rs index 345fb7f8d..5dc9a5bf1 100644 --- a/packages/d2b-broker/src/ops/route.rs +++ b/packages/d2b-broker/src/ops/route.rs @@ -25,6 +25,10 @@ pub struct RouteConflictKey { pub table: String, } +/// A preflight-refused route apply: the route-query step failed +/// ([`ApplyWithPreflightError::RouteQuery`]), the owned-route ledger refused +/// a foreign or unmarked route ([`ApplyWithPreflightError::ForeignRoute`]), +/// or the executor apply itself failed ([`ApplyWithPreflightError::ReconcileExec`]). #[derive(Debug, Clone, PartialEq, Eq)] pub enum ApplyWithPreflightError { RouteQuery(ReconcileExecError), From 93ced15b26ea12f9b4017029b2af062546cac03c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:43 -0700 Subject: [PATCH 044/726] fd_passing: document fd passing helpers --- packages/d2b-broker/src/fd_passing.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/d2b-broker/src/fd_passing.rs b/packages/d2b-broker/src/fd_passing.rs index bc8e463e7..4ddfffefd 100644 --- a/packages/d2b-broker/src/fd_passing.rs +++ b/packages/d2b-broker/src/fd_passing.rs @@ -10,17 +10,28 @@ use nix::sys::stat::fstat; use nix::unistd::close; use std::io::{IoSlice, IoSliceMut}; +/// A malformed or refused SCM_RIGHTS frame from the `recv_fds*` family: +/// the frame lacks a required descriptor, carries duplicates or the wrong +/// count or a non-CLOEXEC fd, was truncated, or failed I/O. #[derive(Debug, PartialEq, Eq)] pub enum FdPassingError { + /// A frame carrying no descriptor arrived where one was required. MissingPassedFd, + /// One send carried the same raw fd more than once. DuplicateFdInSingleSend, + /// The frame carried a different number of descriptors than the + /// operation declared. UnexpectedFdCount { expected: usize, actual: usize, }, + /// A received descriptor was not CLOEXEC. MissingCloexec, + /// The payload was truncated mid-frame. MessageTruncated, + /// The ancillary control data was truncated. ControlTruncated, + /// The underlying socket I/O failed. IOError, /// Nothing is ready on the socket. A nonblocking receive reports an /// empty descriptor here rather than a failed one, so the caller can @@ -28,16 +39,21 @@ pub enum FdPassingError { WouldBlock, } +/// A set of raw fds the holder closes together on [`FdRegistry::clear`] or +/// drop, transferring ownership from the registerer to the registry. #[derive(Debug, Default)] pub struct FdRegistry { owned: Vec, } impl FdRegistry { + /// Take ownership of `fd`, to be closed by this registry later. pub fn register(&mut self, fd: RawFd) { self.owned.push(fd); } + /// Close every registered fd, releasing this registry's ownership. + pub fn clear(&mut self) { for fd in self.owned.drain(..) { let _ = close(fd); @@ -51,20 +67,30 @@ impl Drop for FdRegistry { } } +/// A borrowed raw fd that closes on drop unless [`FdLease::release`] +/// disarms the close first, transferring ownership back to the caller. #[derive(Debug)] pub struct FdLease { fd: Option, } impl FdLease { + /// Take ownership of `fd`, to be closed on drop unless released. + pub fn new(fd: RawFd) -> Self { Self { fd: Some(fd) } } + /// The still-owned fd, if not yet released. + + + pub fn raw(&self) -> Option { self.fd } + /// Disarm the drop-time close and hand the fd back to the caller. + /// The lease no longer owns it:the caller must close or re-lease it.. pub fn release(&mut self) -> Option { self.fd.take() } From 098cdc0e5d67a1b043607327ff508d1584e0256b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:43 -0700 Subject: [PATCH 045/726] ops: document network manager reload contracts --- packages/d2b-broker/src/ops/nm.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/d2b-broker/src/ops/nm.rs b/packages/d2b-broker/src/ops/nm.rs index d28fcc7bd..e1418d62a 100644 --- a/packages/d2b-broker/src/ops/nm.rs +++ b/packages/d2b-broker/src/ops/nm.rs @@ -288,11 +288,13 @@ fn rollback(path: &Path, prior: Option<&str>) -> io::Result<()> { } } -/// Runtime entry-point for `ApplyNmUnmanaged`. +/// Runtime entry-point for `ApplyNmUnmanaged`:apply an intent through the +/// live executor path. /// -/// The dispatcher now lands on `ops::nm` even though the live path is -/// still a thin wrapper. That preserves a stable integration point for -/// future coexistence/reload-verification work. +/// The intent's declared reload behavior is verified before any mutation +/// (`atomic-reload`, `none`, and the empty sentinel are the only accepted +/// spellings),and NetworkManager is reloaded after a successful write +/// when the behavior calls for it. pub async fn apply_with_reload( executor: &dyn ReconcileExecutor, intent: &ResolvedNmUnmanagedIntent, @@ -300,6 +302,9 @@ pub async fn apply_with_reload( crate::live_handlers::live_apply_nm_unmanaged(executor, intent).await } +/// Remove one NetworkManager unmanaged drop-in the intent names,verifying +/// the same reload-behavior contract before mutation and running the +/// `systemctl` reload when the behavior calls for it. pub async fn remove_with_reload( intent: &ResolvedNmUnmanagedIntent, ) -> Result<(), crate::live_handlers::LiveHandlerError> { From ba9873712afda9090531866e35ee65e6697687e6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:43 -0700 Subject: [PATCH 046/726] protocol: document frame io contracts --- packages/d2b-broker/src/protocol.rs | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/d2b-broker/src/protocol.rs b/packages/d2b-broker/src/protocol.rs index 3f0901b11..e8a86b612 100644 --- a/packages/d2b-broker/src/protocol.rs +++ b/packages/d2b-broker/src/protocol.rs @@ -10,8 +10,16 @@ use nix::sys::socket::{ use serde::{Serialize, de::DeserializeOwned}; use tokio::io::unix::AsyncFd; +/// The maximum JSON frame body size, excluding the 4-byte length +/// prefix: frames declaring a larger body are refused. pub const MAX_FRAME_SIZE: usize = 1024 * 1024; +/// Connect a `SOCK_SEQPACKET` Unix socket to `path`, returning the +/// connected CLOEXEC fd. +/// +/// # Errors + +/// Returns the socket error when the socket cannot be created or connected. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn connect_seqpacket(path: &Path) -> io::Result { let fd = socket( @@ -26,6 +34,12 @@ pub fn connect_seqpacket(path: &Path) -> io::Result { Ok(fd) } +/// Bind-and-listen a `SOCK_SEQPACKET` Unix socket at `path`, returning +/// the listening CLOEXEC fd with a backlog of 64. +/// +/// # Errors + +/// Returns the socket error when create, bind, or listen fails. pub fn bind_seqpacket(path: &Path) -> io::Result { let fd = socket( AddressFamily::Unix, @@ -40,6 +54,15 @@ pub fn bind_seqpacket(path: &Path) -> io::Result { Ok(fd) } +/// Serialise `value` as JSON and send it as one frame on `fd`:a 4-byte +/// little-endian length prefix followed by the body,refusing bodies over +/// [`MAX_FRAME_SIZE`]. Byte-equivalent to +/// [`send_json_frame_with_fds`] when no descriptors are attached. +/// +/// # Errors + +/// Returns [`io::ErrorKind::InvalidData`] for serialisation or cap +/// violations,and socket / short-write errors for the send itself. pub fn send_json_frame(fd: RawFd, value: &T) -> io::Result<()> { send_json_frame_with_fds(fd, value, &[]) } @@ -81,6 +104,15 @@ pub fn send_json_frame_with_fds( crate::fd_passing::send_fds(fd, &frame, fds) } +/// Receive one JSON frame from `fd`:a 4-byte little-endian length +/// prefix followed by the body,capped at [`MAX_FRAME_SIZE`]; returns +/// `None` when the peer closed the socket empty. +/// +/// # Errors + +/// Returns [`io::ErrorKind::UnexpectedEof`] for short frames and +/// [`io::ErrorKind::InvalidData`] for length-prefix mismatches and decode +/// failures. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn recv_json_frame(fd: RawFd) -> io::Result> { let mut buffer = vec![0_u8; MAX_FRAME_SIZE + 4]; From 6b709ea9a6db9593679e700feb7ab89cb7d7ccf0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:03:44 -0700 Subject: [PATCH 047/726] ops: document state dir prepare contracts --- packages/d2b-broker/src/ops/state_dir.rs | 57 +++++++++++++++++++++--- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/packages/d2b-broker/src/ops/state_dir.rs b/packages/d2b-broker/src/ops/state_dir.rs index 3d5c173a9..76478f1ba 100644 --- a/packages/d2b-broker/src/ops/state_dir.rs +++ b/packages/d2b-broker/src/ops/state_dir.rs @@ -42,6 +42,8 @@ impl std::fmt::Display for PrepareStateDirError { impl std::error::Error for PrepareStateDirError {} +/// Which broker-managed directory tree an op prepares:a per-VM state +/// root or a per-VM runtime root. #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)] #[serde(rename_all = "kebab-case")] pub enum DirKind { @@ -49,15 +51,22 @@ pub enum DirKind { RuntimeDir, } +/// One state/runtime directory preparation request:which root to +/// prepare, the mode/owner posture to apply,and the relative +/// subdirectories to create under it. #[derive(Debug, Clone)] pub struct PrepareDirRequest { + /// Whether the op prepares the state or runtime tree. pub kind: DirKind, + /// The tree root under whichthe subdirectories are created. pub base_dir: PathBuf, /// Per-VM or global scope (`global` if `vm_id` is `None`). pub vm_id_or_scope: String, /// 0o-mode (e.g. 0o750 for state, 0o755 for runtime). pub mode: u32, + /// The owner uid to apply to created directories. pub owner_uid: u32, + /// The owner gid to apply to created directories. pub owner_gid: u32, /// Directories to create under `base_dir` (relative paths). pub created_paths: Vec, @@ -66,6 +75,8 @@ pub struct PrepareDirRequest { pub daemon_uid: Option, } +/// The audit record of one prepared directory:what the op created or +/// reused, under which base root, with which posture. #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] pub struct PrepareDirAudit { pub kind: DirKind, @@ -78,14 +89,29 @@ pub struct PrepareDirAudit { pub replace_or_create_result: ReplaceOrCreateResult, } +/// Whether a prepare pass created, reused, or mixed both across the +/// directories it walked. #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)] #[serde(rename_all = "kebab-case")] pub enum ReplaceOrCreateResult { + /// Every walked directory was freshly created. Created, + /// Every walked directory already existed and was reused. Reused, + /// Some walked directories were created and others reused. MixedCreatedAndReused, } +/// Prepare one state/runtime directory tree:optionally refuse non-root +/// parents for production roots,reuse the base dir without re-stamping its +/// posture,and create the requested relative subdirectories with the +/// requested mode/owner,returning the audit record. +/// +/// # Errors + +/// Returns [`io::ErrorKind::InvalidInput`] for absolute or `..`-bearing +/// created paths, the parent-ownership guard,or the underlying +/// mkdir/fchmod/fchown failures as `io::Error`s. pub fn prepare_dir(req: &PrepareDirRequest) -> io::Result { // Refuse non-root parent for production paths. Tests pass a scratch // base_dir so the refuse_non_root_parent guard is wired via the @@ -158,10 +184,19 @@ fn production_path(p: &Path) -> bool { p.starts_with("/var/lib/d2b") || p.starts_with("/run/d2b") } +/// Prepare one VM's runtime root directory:requires the wire +/// `pathClass=runtime`, resolves the bundle intent,and reuses the existing +/// base dir without re-stamping its posture. +/// +/// # Errors + +/// Returns [`super::OpError::InvalidInput`] for a non-runtime path class, +/// [`super::OpError::UnknownSubject`] for unmanaged VMs,and +/// [`super::OpError::Io`] for the directory preparation failures. pub fn live_prepare_runtime_dir( _exec: &SystemLiveExec, resolver: &BundleResolver, - req: &d2b_contracts_broker::broker_wire::PrepareDirRequest, + req:&d2b_contracts_broker::broker_wire::PrepareDirRequest, _audit_log: &crate::audit::AuditLog, ) -> Result<(), super::OpError> { if req.path_class != PathClass::Runtime { @@ -208,11 +243,23 @@ pub struct PreparedStateDir { pub mode: u32, } +/// Prepare one VM's state directory:requires the wire `pathClass=vm`; +/// a legacy VM resolves its bundle intent and creates the declared +/// directories, while a zone-native Guest resolves the trusted +/// `path:swtpm-state:` storage row and records its posture +/// without creating anything. +/// +/// # Errors + +/// Returns [`super::OpError::InvalidInput`] for a non-VM path class, +/// [`super::OpError::UnknownSubject`] / [`super::OpError::Refused`] +/// for unresolvable subjects, and the swtpm-hardening refusal as +/// [`PrepareStateDirError::SwtpmDirHardening`].where applicable。 pub fn live_prepare_state_dir( - _exec: &SystemLiveExec, - resolver: &BundleResolver, - req: &d2b_contracts_broker::broker_wire::PrepareDirRequest, - _audit_log: &crate::audit::AuditLog, + _exec:&SystemLiveExec, + resolver:&BundleResolver, + req:&d2b_contracts_broker::broker_wire::PrepareDirRequest, + _audit_log:&crate::audit::AuditLog, ) -> Result { if req.path_class != PathClass::Vm { return Err(super::OpError::InvalidInput { From 1f9423d9afe957a1927856ffc4708f9fdc5e305a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:05:06 -0700 Subject: [PATCH 048/726] d2b-resource-runtime: halve assignment clones on TargetDirectory::assign --- packages/d2b-resource-runtime/src/target.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/d2b-resource-runtime/src/target.rs b/packages/d2b-resource-runtime/src/target.rs index 7e5fe1f88..9330c27e2 100644 --- a/packages/d2b-resource-runtime/src/target.rs +++ b/packages/d2b-resource-runtime/src/target.rs @@ -649,18 +649,28 @@ impl TargetDirectory { } match &reference.kind { TargetKind::Host => { - state.host_assignments.insert(source.clone(), assignment.clone()); + state.host_assignments.insert(source.clone(), assignment); + let handle = state + .host_assignments + .get(source) + .expect("host assignment was just inserted") + .clone(); + Ok(handle) } TargetKind::Guest => { - state + let assignments = &mut state .guests .entry(reference) .or_insert_with(Self::new_guest_record) - .assignments - .insert(source.clone(), assignment.clone()); + .assignments; + assignments.insert(source.clone(), assignment); + let handle = assignments + .get(source) + .expect("guest assignment map entry was just inserted") + .clone(); + Ok(handle) } } - Ok(assignment) } /// The recorded assignment of one resource. From f3a847c72e4b3dafcd3133ab8881cc4a8c6ce61d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:07:06 -0700 Subject: [PATCH 049/726] d2b-unsafe-local-helper: make NotFound normalization explicit in scope teardown --- packages/d2b-unsafe-local-helper/src/systemd.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/d2b-unsafe-local-helper/src/systemd.rs b/packages/d2b-unsafe-local-helper/src/systemd.rs index 43c9689f8..ac592f017 100644 --- a/packages/d2b-unsafe-local-helper/src/systemd.rs +++ b/packages/d2b-unsafe-local-helper/src/systemd.rs @@ -253,11 +253,15 @@ impl UserScopeManager for SystemdUserScopeManager { } self.with_connection(|connection| { let manager = Self::manager_proxy(connection)?; - manager + if let Err(error) = manager .call_method("KillUnit", &(scope.unit_name.as_str(), "all", signal)) .map(|_| ()) .map_err(map_stop_error) - .or_else(|error| (error == ScopeError::NotFound).then_some(()).ok_or(error))?; + { + if error != ScopeError::NotFound { + return Err(error); + } + } Ok(()) }) } @@ -271,10 +275,11 @@ impl UserScopeManager for SystemdUserScopeManager { let manager = Self::manager_proxy(connection)?; let result: Result = manager.call("StopUnit", &(scope.unit_name.as_str(), "replace")); - result - .map(|_| ()) - .map_err(map_stop_error) - .or_else(|error| (error == ScopeError::NotFound).then_some(()).ok_or(error))?; + if let Err(error) = result.map(|_| ()).map_err(map_stop_error) { + if error != ScopeError::NotFound { + return Err(error); + } + } Ok(()) }) } From 6668d84ddf98ac8d43a1b8b3b77eb74dc698f161 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:07:35 -0700 Subject: [PATCH 050/726] xtask: tidy doubled parens and whiche typo in provider policy docs --- packages/xtask/src/provider_crate_policy.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index dce172ea9..37117fb53 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -8425,7 +8425,7 @@ fn provider_crate_family(crate_name: &str) -> String { /// `Process/`, `Host/`, `User/`, or `Guest/`. The /// resource model addresses providers and processes by name; naming the /// provider one delegates a child to is the one legitimate cross-family -/// shape ((`d2b-provider-device-usbip/src/lifecycle.rs:25` names the +/// shape (`d2b-provider-device-usbip/src/lifecycle.rs:25` names the /// system-minijail provider that owns its guest-proxy child). A reference /// names a provider; it is not knowledge about that provider. fn is_resource_reference_literal(content: &str) -> bool { @@ -8637,7 +8637,7 @@ fn render_provider_family_violation(signal: &ProviderFamilySignal) -> String { /// One committed exemption row: a provider crate module that legitimately /// carries another family's identity token. The list only shrinks: a signal -/// without a row is a policy failure ((a reintroduction),and a row whose +/// without a row is a policy failure (a reintroduction),and a row whose /// signal the tree no longer carries is stale. No row may be added unless the /// change that introduces a legitimate cross-family reference also records /// its reason here. @@ -8645,7 +8645,7 @@ fn render_provider_family_violation(signal: &ProviderFamilySignal) -> String { #[derive(Clone)] struct ProviderFamilyKnowledgeExemption { - /// The provider crate that carries the token ((its Cargo package name). + /// The provider crate that carries the token (its Cargo package name). crate_name: &'static str, /// Repository-relative module path that carries the token. @@ -9040,11 +9040,11 @@ const COMMITTED_SCOPE: &[CommittedScopeEntry] = &[ ]; const COMMITTED_SCOPE_ARTIFACT_ROOTS: &[&str] = &["docs/reference", "packages/policy-inputs"]; -/// Fail when a workspace crate has no committed scope row ((an edit to a +/// Fail when a workspace crate has no committed scope row (an edit to a /// crate no unit names),when a row names a crate the workspace no longer has, /// or when a declared artifact root has vanished. The committed scope is /// compared against the workspace rather than a diff: any crate present without -/// a row is an edit outside the scope that happened, whiche is what a +/// a row is an edit outside the scope that happened, which is what a /// committed scope gate can prove without a diff.. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn check_committed_scope(repo_root:&Path, members: &[WorkspaceMember]) -> Result<(), String> { From 0925628b2d66b36c08a97ef7495ad023591400da Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:07:38 -0700 Subject: [PATCH 051/726] audit: extend the ledger vocabulary for declined and not-started rows Two honest states the waves produce were missing: a claim that holds but whose rewrite the toolchain or a contract rejects, and a row a batch never reached. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 2bc7fd7aa..aeb7d0076 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -2,7 +2,7 @@ Baseline: branch `refactor-rust-skills-remediation`, base commit `147a536a0` (the audit baseline `v3` @ `6ebdd4cec` plus the audit corpus commit). Authority: `docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md` (R1-R14, KTD1-KTD11). Corpus: `README.md` and `lane/`. -One row per finding id. `outcome` is filled by the owning wave when it disposes of the row: `applied`, `applied-variant` (the claim or the stated fix needed a minimal correction or a recorded deviation), `skipped-stale` (the claim does not hold at HEAD; no change made), `already-fixed` (the stated fix is already present in the tree), `escalated` (moved to the owning wave named in `escalation`), `policy-confirmed` (recorded no-op citing its policy), `needs-contract` (deferred to the contract-adjacent wave), `reclassified` (severity or verdict changed on re-verification, reason recorded). +One row per finding id. `outcome` is filled by the owning wave when it disposes of the row: `applied`, `applied-variant` (the claim or the stated fix needed a minimal correction or a recorded deviation), `skipped-stale` (the claim does not hold at HEAD; no change made), `already-fixed` (the stated fix is already present in the tree), `escalated` (moved to the owning wave named in `escalation`), `policy-confirmed` (recorded no-op citing its policy), `needs-contract` (deferred to the contract-adjacent wave), `reclassified` (severity or verdict changed on re-verification, reason recorded), `declined` (the claim holds but no correct minimal change lands - the pinned toolchain rejects the rewrite, or the fix would break a contract; the evidence is recorded and the code stays as it is), and `not-started` (the batch's budget ended before the row; it is carried into a follow-up dispatch, never counted as done). Corpus caveat: the audit read its sources through a tool path that rewrites long digit runs, so at least one row (RS-0916) quotes a literal that exists nowhere in the tree or in git history. Every row's true state is re-verified at apply time (R3) and the ledger records the corrected finding; the corpus row text is left as the audit wrote it. `anchor` is the apply-time anchor when the wave re-located it; the seed anchor comes from the corpus row. Empty cells mean the row is not yet disposed. From 7eef023f959ab2f8d68c919359bf2c8c7a5f4d62 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:07:45 -0700 Subject: [PATCH 052/726] xtask: reindent three proc-authority statements --- packages/xtask/src/resource_type_authority.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xtask/src/resource_type_authority.rs b/packages/xtask/src/resource_type_authority.rs index 710d1ac27..7fc93b6b7 100644 --- a/packages/xtask/src/resource_type_authority.rs +++ b/packages/xtask/src/resource_type_authority.rs @@ -701,7 +701,7 @@ fn parity_errors(registry: &AuthorityRegistry) -> Vec { } for (type_name, crates) in &declared_by { if crates.len() > 1 { -errors.push(format!( + errors.push(format!( "type-declared-twice: {type_name} is declared by both {}and {}", crates[0], crates[1] )); @@ -937,7 +937,7 @@ fn render(registry: &AuthorityRegistry) -> Result { } entries.extend(declared_all); let mut out = String::new(); -out.push_str("// @generated\n"); + out.push_str("// @generated\n"); out.push_str("// Provenance:emitted from the per-crate `resource-types.json` declarations\n"); out.push_str("// by `cargo xtask check-provider-crate-layout --fix`;the layout check's\n"); out.push_str("// authority drift gate regenerates this file byte-for-byte,and refuses a\n"); @@ -1080,7 +1080,7 @@ mod tests { impl Drop for Fixture { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - fn drop(&mut self) { + fn drop(&mut self) { let _ = fs::remove_dir_all(&self.root); } } From 6fa152aa1bd51c00b66592ae7cbb4b38cca1a85f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:08:58 -0700 Subject: [PATCH 053/726] refactor(contracts-provider): derive defaults, borrow dedup sets, document errors --- .../src/v3/credential.rs | 62 ++++++++++++------- .../src/v3/credential/service.rs | 5 ++ .../src/v3/credential_controller.rs | 19 +++--- .../d2b-contracts-provider/src/v3/provider.rs | 50 +++++++-------- .../v3/semantic_services/child_resources.rs | 25 +------- .../src/v3/telemetry_policy.rs | 4 +- 6 files changed, 84 insertions(+), 81 deletions(-) diff --git a/packages/d2b-contracts-provider/src/v3/credential.rs b/packages/d2b-contracts-provider/src/v3/credential.rs index 1801e8f28..3b47b600b 100644 --- a/packages/d2b-contracts-provider/src/v3/credential.rs +++ b/packages/d2b-contracts-provider/src/v3/credential.rs @@ -117,6 +117,12 @@ macro_rules! opaque_credential_value { impl $name { /// Validate a raw identifier and retain only its domain-separated digest. + /// + /// # Errors + /// + /// Returns [`CredentialContractError::InvalidOpaqueValue`] when + /// the value is empty, exceeds the domain bound, or contains a + /// character outside the allowed identifier set. pub fn parse(value: impl AsRef) -> Result { let value = value.as_ref(); validate_opaque_source(value, $max)?; @@ -129,6 +135,11 @@ macro_rules! opaque_credential_value { } /// Reconstruct a value from its authorized one-way wire representation. + /// + /// # Errors + /// + /// Returns [`CredentialContractError::InvalidOpaqueValue`] when + /// the digest is not the canonical `sha256:` form. pub fn from_opaque_digest( value: impl Into, ) -> Result { @@ -291,17 +302,29 @@ impl<'de> Deserialize<'de> for CredentialScope { /// Rotation policy class. #[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, + Debug, + Clone, + Copy, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + JsonSchema, )] #[serde(rename_all = "kebab-case")] pub enum RotationPolicyClass { + #[default] OnExpiry, Proactive, OnDemand, } /// Rotation settings. -#[derive(Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)] +#[derive(Clone, Copy, Default, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct CredentialRotationPolicy { policy: RotationPolicyClass, @@ -359,16 +382,6 @@ impl CredentialRotationPolicy { } } -impl Default for CredentialRotationPolicy { - fn default() -> Self { - Self { - policy: RotationPolicyClass::OnExpiry, - proactive_window_ms: None, - max_lease_lifetime_ms: 0, - } - } -} - redacted_debug!(CredentialRotationPolicy); impl<'de> Deserialize<'de> for CredentialRotationPolicy { @@ -434,31 +447,34 @@ impl<'de> Deserialize<'de> for ExpirySpec { /// How active leases are treated on a revocation trigger. #[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, + Debug, + Clone, + Copy, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + JsonSchema, )] #[serde(rename_all = "kebab-case")] pub enum RevocationAction { + #[default] Immediate, DrainLeases, } /// Revocation settings. -#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct CredentialRevocationPolicy { pub on_owner_delete: RevocationAction, pub on_provider_generation: RevocationAction, } -impl Default for CredentialRevocationPolicy { - fn default() -> Self { - Self { - on_owner_delete: RevocationAction::Immediate, - on_provider_generation: RevocationAction::Immediate, - } - } -} - redacted_debug!(CredentialRevocationPolicy); /// Compatibility name for the prepared Credential spec field. diff --git a/packages/d2b-contracts-provider/src/v3/credential/service.rs b/packages/d2b-contracts-provider/src/v3/credential/service.rs index fa95953f0..6547aaf59 100644 --- a/packages/d2b-contracts-provider/src/v3/credential/service.rs +++ b/packages/d2b-contracts-provider/src/v3/credential/service.rs @@ -995,6 +995,11 @@ pub trait CredentialWire: Sized { /// Append the canonical protobuf encoding. fn encode_wire(&self, output: &mut Vec); /// Decode one complete message and reject unknown or duplicate fields. + /// + /// # Errors + /// + /// Returns the [`CredentialServiceError`] the DTO's decoder reports for + /// a truncated, unknown-field, duplicate-field, or out-of-range message. fn decode_wire(bytes: &[u8]) -> Result; } diff --git a/packages/d2b-contracts-provider/src/v3/credential_controller.rs b/packages/d2b-contracts-provider/src/v3/credential_controller.rs index 0e8c113b2..99d388750 100644 --- a/packages/d2b-contracts-provider/src/v3/credential_controller.rs +++ b/packages/d2b-contracts-provider/src/v3/credential_controller.rs @@ -1546,15 +1546,18 @@ fn field(key: &'static str, value: impl Into) -> CredentialTelemetryFiel } } -fn validate_zone(value: String) -> Result { - if value.is_empty() - || value.len() > 63 - || !value.as_bytes()[0].is_ascii_lowercase() - || !value +fn is_valid_zone(value: &str) -> bool { + !value.is_empty() + && value.len() <= 63 + && value.as_bytes()[0].is_ascii_lowercase() + && value .bytes() .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-') - || contains_sensitive_shape(&value) - { + && !contains_sensitive_shape(value) +} + +fn validate_zone(value: String) -> Result { + if !is_valid_zone(&value) { return Err(CredentialObservabilityError::ForbiddenTelemetryField); } Ok(value) @@ -1588,7 +1591,7 @@ fn forbidden_telemetry_key(key: &str) -> bool { fn allowed_telemetry_value(key: &str, value: &str) -> bool { match key { - "d2b.zone" => validate_zone(value.to_owned()).is_ok(), + "d2b.zone" => is_valid_zone(value), "d2b.provider" | "d2b.credential.provider" | "provider" => matches!( value, "credential-secret-service" | "credential-entra" | "credential-managed-identity" diff --git a/packages/d2b-contracts-provider/src/v3/provider.rs b/packages/d2b-contracts-provider/src/v3/provider.rs index c2a6558f2..afbf1d8b5 100644 --- a/packages/d2b-contracts-provider/src/v3/provider.rs +++ b/packages/d2b-contracts-provider/src/v3/provider.rs @@ -247,6 +247,12 @@ pub struct BinaryRef(String); impl BinaryRef { /// Parse a `^[a-z][a-z0-9-]*$` binary reference. + /// + /// # Errors + /// + /// Returns [`ProviderContractError::InvalidPrimitive`] when the value is + /// empty, longer than [`MAX_BINARY_REF_BYTES`], or does not match the + /// grammar. pub fn parse(value: impl Into) -> Result { let value = value.into(); if value.is_empty() || value.len() > MAX_BINARY_REF_BYTES { @@ -478,6 +484,11 @@ redacted_debug!(TrustEvidence); impl TrustEvidence { /// Decide production admission, fail-closed. + /// + /// # Errors + /// + /// Returns [`ProviderContractError::TrustNotEstablished`] when any + /// trust, signature, revocation, or policy evaluation does not admit. pub fn admit(&self) -> Result<(), ProviderContractError> { let admitted = self.publisher_trusted && self.signature == SignatureState::Valid @@ -1454,9 +1465,9 @@ impl ComponentDescriptor { if state_namespaces.is_empty() && self.declares_state_volume { return Err(ProviderContractError::MissingRequiredField); } - let mut ids = BTreeSet::new(); + let mut ids: BTreeSet<&BoundedToken> = BTreeSet::new(); for namespace in &state_namespaces { - if !ids.insert(namespace.id().clone()) { + if !ids.insert(namespace.id()) { return Err(ProviderContractError::DuplicateDeclaration); } } @@ -2357,7 +2368,7 @@ pub enum UpgradeDisposition { } /// The upgrade, drain, and restart policy a Provider manifest declares. -#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct UpgradePolicy { /// Whether components are drained before an upgrade recycles them. @@ -2371,16 +2382,6 @@ pub struct UpgradePolicy { pub preserves_durable_state: bool, } -impl core::fmt::Debug for UpgradePolicy { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("UpgradePolicy") - .field("drain_before_upgrade", &self.drain_before_upgrade) - .field("max_automatic_disposition", &self.max_automatic_disposition) - .field("preserves_durable_state", &self.preserves_durable_state) - .finish() - } -} - /// The signed manifest and catalog entry one `artifactId` selects. /// /// This is the read-only derived data the Provider resource row does not @@ -2429,30 +2430,30 @@ impl ProviderManifest { { return Err(ProviderContractError::BoundExceeded); } - let mut component_ids = BTreeSet::new(); - let mut owned_types = BTreeSet::new(); + let mut component_ids: BTreeSet<&BoundedToken> = BTreeSet::new(); + let mut owned_types: BTreeSet<&ResourceTypeName> = BTreeSet::new(); for component in &components { if component.declares_state_volume() == component.state_namespaces().is_empty() { return Err(ProviderContractError::MissingRequiredField); } - if !component_ids.insert(component.component_id().clone()) { + if !component_ids.insert(component.component_id()) { return Err(ProviderContractError::DuplicateDeclaration); } for resource_type in component.exported_resource_types() { // "The same ResourceType is declared once." Several // controller instances may run under different Hosts, // Guests, or domains, but not under duplicate schemas. - if !owned_types.insert(resource_type.clone()) { + if !owned_types.insert(resource_type) { return Err(ProviderContractError::DuplicateDeclaration); } } } - let mut bound_types = BTreeSet::new(); + let mut bound_types: BTreeSet<&ResourceTypeName> = BTreeSet::new(); for binding in &api_bindings { if binding.placement_anchor().is_none() { return Err(ProviderContractError::PlacementAnchorMissing); } - if !bound_types.insert(binding.resource_type().clone()) { + if !bound_types.insert(binding.resource_type()) { return Err(ProviderContractError::DuplicateDeclaration); } if !owned_types.contains(binding.resource_type()) { @@ -2495,14 +2496,13 @@ impl ProviderManifest { /// Validate the shared Host and Guest daemon/broker artifact declarations. pub fn validate_runtime_artifacts( - entries: impl IntoIterator, + entries: &[TargetRuntimeArtifacts], ) -> Result<(), ProviderContractError> { - let entries: Vec<_> = entries.into_iter().collect(); if entries.len() > 3 { return Err(ProviderContractError::BoundExceeded); } let mut seen = BTreeSet::new(); - for entry in &entries { + for entry in entries { if !seen.insert(entry.target_kind()) { return Err(ProviderContractError::DuplicateDeclaration); } @@ -2528,7 +2528,7 @@ impl ProviderManifest { entries: impl IntoIterator, ) -> Result { let mut entries: Vec<_> = entries.into_iter().collect(); - Self::validate_runtime_artifacts(entries.clone())?; + Self::validate_runtime_artifacts(&entries)?; entries.sort_by_key(TargetRuntimeArtifacts::target_kind); self.runtime_artifacts = entries; Ok(self) @@ -2577,7 +2577,7 @@ impl ProviderManifest { } } } - Self::validate_runtime_artifacts(self.runtime_artifacts.clone())?; + Self::validate_runtime_artifacts(&self.runtime_artifacts)?; for target in required_targets { if !self .runtime_artifacts @@ -3221,7 +3221,7 @@ mod tests { ) .unwrap(); assert_eq!( - ProviderManifest::validate_runtime_artifacts([host, guest]), + ProviderManifest::validate_runtime_artifacts(&[host, guest]), Err(ProviderContractError::SharedRuntimeArtifactMismatch) ); } diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs index 8532c281d..490eafb14 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs @@ -570,28 +570,7 @@ pub fn explicit_binding_children_with_user( } BindingChildPlacement::Guest => target_ref.clone(), }; - let Some(producer_ref) = producer_ref.transpose()? else { - children.push(BindingChildIntent { - owner_ref: binding_ref.clone(), - provider_ref: provider_ref.clone(), - resource_ref, - execution_ref, - kind: declaration.kind, - placement: declaration.placement, - role: declaration.role, - producer_ref: None, - process_provider: declaration.process_provider, - process_template: declaration.process_template, - process_domain: declaration.process_domain, - process_class: declaration.process_class, - process_user: if declaration.process_user { - user_ref.clone() - } else { - None - }, - }); - continue; - }; + let producer_ref: Option = producer_ref.transpose()?; children.push(BindingChildIntent { owner_ref: binding_ref.clone(), provider_ref: provider_ref.clone(), @@ -600,7 +579,7 @@ pub fn explicit_binding_children_with_user( kind: declaration.kind, placement: declaration.placement, role: declaration.role, - producer_ref: Some(producer_ref), + producer_ref, process_provider: declaration.process_provider, process_template: declaration.process_template, process_domain: declaration.process_domain, diff --git a/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs b/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs index b81cab666..58eaef95d 100644 --- a/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs +++ b/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs @@ -489,7 +489,7 @@ pub fn validate_descriptor(descriptor: &MetricDescriptor) -> Result<(), MetricPo return Err(MetricPolicyError::DescriptorNotAllowlisted); }; - let mut seen = BTreeSet::new(); + let mut seen: BTreeSet<&str> = BTreeSet::new(); if descriptor.labels.len() > 16 { return Err(MetricPolicyError::DescriptorMalformed); } @@ -497,7 +497,7 @@ pub fn validate_descriptor(descriptor: &MetricDescriptor) -> Result<(), MetricPo if label.key.is_empty() || label.key.len() > 64 { return Err(MetricPolicyError::DescriptorMalformed); } - if !seen.insert(label.key.clone()) { + if !seen.insert(&label.key) { return Err(MetricPolicyError::DescriptorMalformed); } validate_label_key(&label.key)?; From d4e4604e49c59ede49084904d60d0eeac4bd5e29 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:09:13 -0700 Subject: [PATCH 054/726] d2b: derive known commands from parser, trim paging and envelope copies --- packages/d2b/src/debug.rs | 4 +- packages/d2b/src/dispatch.rs | 94 +++++++++------------- packages/d2b/src/host.rs | 4 +- packages/d2b/tests/auth_status_contract.rs | 17 +++- 4 files changed, 56 insertions(+), 63 deletions(-) diff --git a/packages/d2b/src/debug.rs b/packages/d2b/src/debug.rs index 40fa15471..274fbc388 100644 --- a/packages/d2b/src/debug.rs +++ b/packages/d2b/src/debug.rs @@ -415,7 +415,7 @@ fn observed_row(value: &Value) -> Result { retryable: failure.get("retryable").and_then(Value::as_bool), }); Ok(ObservedRow { - reference: reference.to_owned(), + reference, uid: uid.to_owned(), generation, status_generation, @@ -469,7 +469,7 @@ fn read_type( phase: None, label_selector: None, updates: false, - page_token: page_token.clone(), + page_token, limit: Some(PAGE_SIZE), }; let value = request_list(context, &args, mode, deadline).map_err(|failure| { diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index 66f0e344f..25ec0ea70 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -45,10 +45,17 @@ const PROJECTION_COMMANDS: &[&str] = &["audio", "clipboard", "display"]; /// The parser is the sole authority for a built-in name; projection binding /// and completion read this list, so collision handling cannot drift from /// what `d2b` actually parses. -static BUILTIN_COMMANDS: LazyLock> = LazyLock::new(|| { +/// The parser's own top-level subcommand names, in declaration order. +fn modern_cli_subcommands() -> Vec { ModernCli::command() .get_subcommands() .map(|subcommand| subcommand.get_name().to_owned()) + .collect() +} + +static BUILTIN_COMMANDS: LazyLock> = LazyLock::new(|| { + modern_cli_subcommands() + .into_iter() .filter(|name| !PROJECTION_COMMANDS.contains(&name.as_str())) .collect() }); @@ -294,22 +301,22 @@ pub(crate) struct HostErrorEnvelope { } pub(crate) fn host_error_envelope( - kind: &str, - code: &str, + kind: impl Into, + code: impl Into, exit_code: i32, - what_was_checked: &str, - observed_state: &str, - remediation: &str, - docs_anchor: &str, + what_was_checked: impl Into, + observed_state: impl Into, + remediation: impl Into, + docs_anchor: impl Into, ) -> HostErrorEnvelope { HostErrorEnvelope { - kind: kind.to_owned(), - code: code.to_owned(), + kind: kind.into(), + code: code.into(), exit_code, - what_was_checked: what_was_checked.to_owned(), - observed_state: observed_state.to_owned(), - remediation: remediation.to_owned(), - docs_anchor: docs_anchor.to_owned(), + what_was_checked: what_was_checked.into(), + observed_state: observed_state.into(), + remediation: remediation.into(), + docs_anchor: docs_anchor.into(), } } @@ -344,7 +351,7 @@ pub(crate) fn emit_host_error( pub(crate) fn daemon_down_envelope(verb: &str) -> HostErrorEnvelope { host_error_envelope( - &format!("d2b {verb} requires d2bd"), + format!("d2b {verb} requires d2bd"), "daemon-down", 1, "Daemon connectivity at /run/d2b/public.sock.", @@ -356,10 +363,10 @@ pub(crate) fn daemon_down_envelope(verb: &str) -> HostErrorEnvelope { pub(crate) fn not_yet_implemented_envelope(verb: &str) -> HostErrorEnvelope { host_error_envelope( - &format!("d2b {verb} has no daemon-native handler yet"), + format!("d2b {verb} has no daemon-native handler yet"), "not-yet-implemented", 78, - &format!("Native daemon dispatch for `d2b {verb}`"), + format!("Native daemon dispatch for `d2b {verb}`"), "The daemon-native handler has not landed yet; the typed envelope contract is the only operator path until the native handler ships.", "Track the surface schedule in CHANGELOG.md \"Unreleased\"; the typed envelope is the only operator path until the native handler ships.", "docs/reference/error-codes.md#not-yet-implemented", @@ -368,12 +375,12 @@ pub(crate) fn not_yet_implemented_envelope(verb: &str) -> HostErrorEnvelope { pub(crate) fn missing_mutation_flag_envelope(verb: &str) -> HostErrorEnvelope { host_error_envelope( - &format!("{verb} requires either --dry-run or --apply"), + format!("{verb} requires either --dry-run or --apply"), "--apply-or-dry-run-required", 78, - &format!("{verb} invocation flags."), + format!("{verb} invocation flags."), "Neither --dry-run nor --apply was provided.", - &format!("Re-run as `d2b {verb} --dry-run` to plan or `d2b {verb} --apply` to mutate."), + format!("Re-run as `d2b {verb} --dry-run` to plan or `d2b {verb} --apply` to mutate."), "docs/reference/error-codes.md#--apply-or-dry-run-required", ) } @@ -545,7 +552,7 @@ async fn audit_via_socket( let mut cursor = None; let mut lines = Vec::new(); for _ in 0..1024 { - let request = daemon_audit_frame_with_cursor("audit", json_mode, cursor.clone())?; + let request = daemon_audit_frame_with_cursor("audit", json_mode, cursor)?; socket .send_frame(&request, budget) .await @@ -686,33 +693,10 @@ pub(crate) fn parse_uid_env(name: &str) -> BTreeSet { } pub(crate) fn all_known_subcommands() -> Vec { - [ - "list", - "status", - "launch", - "audit", - "auth status", - "op inspect", - "realm list", - "realm inspect", - "realm enter", - "realm run", - "up", - "down", - "restart", - "boot", - "build", - "switch", - "test", - "rollback", - "generations", - "usb", - "console", - "audio", - ] - .into_iter() - .map(str::to_owned) - .collect() + modern_cli_subcommands() + .into_iter() + .filter(|name| !PROJECTION_COMMANDS.contains(&name.as_str())) + .collect() } pub(crate) fn allowed_subcommands(role: AuthRoleV2) -> BTreeSet { @@ -815,22 +799,22 @@ pub(crate) fn runtime_dispatch(cli: &ModernCli, context: &ZoneContext) -> Result ModernCommand::Process(args) => guest::run_process(context, args, mode, deadline), ModernCommand::Exec(args) => exec::run(context, args, mode, deadline), ModernCommand::Shell(args) => shell::run(context, args, mode, deadline), - ModernCommand::Volume(args) => resource::typed_noun(context, "volume", args, mode, deadline), - ModernCommand::Network(args) => resource::typed_noun(context, "network", args, mode, deadline), - ModernCommand::Device(args) => resource::typed_noun(context, "device", args, mode, deadline), + ModernCommand::Volume(args) => resource::typed_noun(context, "volume", args.clone(), mode, deadline), + ModernCommand::Network(args) => resource::typed_noun(context, "network", args.clone(), mode, deadline), + ModernCommand::Device(args) => resource::typed_noun(context, "device", args.clone(), mode, deadline), ModernCommand::Endpoint(args) => endpoint::run(context, args, mode, deadline), ModernCommand::Export(args) => share::run_export(context, args, mode, deadline), ModernCommand::Import(args) => share::run_import(context, args, mode, deadline), ModernCommand::Resource(args) => resource::run_resource(context, args, mode, deadline), - ModernCommand::User(args) => resource::typed_noun(context, "user", args, mode, deadline), + ModernCommand::User(args) => resource::typed_noun(context, "user", args.clone(), mode, deadline), ModernCommand::Credential(args) => { - resource::typed_noun(context, "credential", args, mode, deadline) + resource::typed_noun(context, "credential", args.clone(), mode, deadline) } ModernCommand::Provider(args) => provider::run(context, args, mode, deadline), ModernCommand::Zone(args) => zone::run(context, args, mode, deadline), - ModernCommand::Quota(args) => resource::typed_noun(context, "quota", args, mode, deadline), + ModernCommand::Quota(args) => resource::typed_noun(context, "quota", args.clone(), mode, deadline), ModernCommand::EmergencyPolicy(args) => { - resource::typed_noun(context, "emergency-policy", args, mode, deadline) + resource::typed_noun(context, "emergency-policy", args.clone(), mode, deadline) } ModernCommand::Activation(args) => activation::run(context, args, mode, deadline), ModernCommand::Complete(args) => complete::run(args, Some(context), mode, deadline), @@ -974,7 +958,7 @@ fn explicit_zone_argument(cli_zone: Option<&str>) -> Option { } pub(crate) fn modern_run(raw_args: Vec) -> i32 { - let cli = match ModernCli::try_parse_from(raw_args.clone()) { + let cli = match ModernCli::try_parse_from(raw_args) { Ok(cli) => cli, Err(error) => { let code = error.exit_code(); diff --git a/packages/d2b/src/host.rs b/packages/d2b/src/host.rs index 3945c6e0b..1ec36d5ed 100644 --- a/packages/d2b/src/host.rs +++ b/packages/d2b/src/host.rs @@ -369,8 +369,8 @@ fn validate(args: &HostValidateArgs, mode: OutputMode) -> Result launcher"); assert_eq!(launcher.effective_uid, 1000); assert!( - launcher.allowed_subcommands.iter().any(|c| c == "up"), - "launcher allows `up`; got {:?}", + launcher.allowed_subcommands.iter().any(|c| c == "list"), + "launcher allows `list`; got {:?}", + launcher.allowed_subcommands + ); + assert!( + !launcher + .allowed_subcommands + .iter() + .any(|c| c == "up"), + "launcher must not report retired v2 verb `up` as allowed; got {:?}", launcher.allowed_subcommands ); assert!( From 9ba7acf09292d75c88d02cecedb4a0ebeea0a684 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:10:01 -0700 Subject: [PATCH 055/726] d2b-provider-user: move inspect-user groups into the spec instead of cloning --- packages/d2b-provider-user/src/effects_service.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/d2b-provider-user/src/effects_service.rs b/packages/d2b-provider-user/src/effects_service.rs index 6ef6e4e40..27ad10e26 100644 --- a/packages/d2b-provider-user/src/effects_service.rs +++ b/packages/d2b-provider-user/src/effects_service.rs @@ -169,21 +169,21 @@ async fn serve_inspect_user( service: USER_EFFECTS_SERVICE.id.to_owned(), reason: reason.to_owned(), }; - let request = InspectUserRequest::parse(payload)?; + let InspectUserRequest { user_ref, username, groups } = InspectUserRequest::parse(payload)?; // The probe input is the declared identity itself: the spec carries the // declared groups, so the identity digest and the required bindings are // the ones the row's own reconcile would demand for that identity. let spec = UserSpec::new( - request.username.clone(), + username.clone(), BoundedText::parse(String::new()).expect("empty text is always valid"), - request.groups.clone(), + groups, ) .map_err(|_| declined("inspect-user-request-invalid"))?; let report = reconciler - .reconcile(&request.user_ref, &spec) + .reconcile(&user_ref, &spec) .await .map_err(|_| declined("inspect-user-discovery-failed"))?; - inspect_user_response(&request.username, &report) + inspect_user_response(&username, &report) } /// The provider-owned User effects (U5), built from the daemon-supplied From 275c581bf06dffceb26bce0d2af59d93b27b78ed Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:10:02 -0700 Subject: [PATCH 056/726] d2b-provider-volume-binding: drop the parsed-spec clone and document seam errors --- .../d2b-provider-volume-binding/src/driver.rs | 13 +++++++++++++ .../d2b-provider-volume-binding/src/facets.rs | 15 +++++++++++++++ .../src/row_readers.rs | 10 ++++++---- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-volume-binding/src/driver.rs b/packages/d2b-provider-volume-binding/src/driver.rs index 8e3fc0069..f0a485399 100644 --- a/packages/d2b-provider-volume-binding/src/driver.rs +++ b/packages/d2b-provider-volume-binding/src/driver.rs @@ -304,6 +304,13 @@ pub trait BindingDriverEffects: Send + Sync + 'static { -> bool; /// Remove the endpoint realization (socket) - endpoint-first teardown. + /// + /// # Errors + /// + /// Returns `Err` when the daemon-supplied removal adapter fails to + /// remove the realized socket endpoint. The removal is idempotent + /// under retry: a socket that was never realized, or whose file is + /// already gone, answers `Ok(())`. async fn remove_socket( &self, socket: &d2b_provider_volume_virtiofs::SocketIdentity, @@ -322,6 +329,12 @@ pub trait BindingDriverEffects: Send + Sync + 'static { /// published state. A present mount therefore keeps the durable deleting /// mark and the owned children (the drain never force-clears a serve that /// is still mounted). + /// + /// # Errors + /// + /// Returns `Err` when the daemon-supplied observation adapter cannot + /// complete the guest-mount observation; the observation itself fails + /// closed with `Ok(false)` as described above. async fn guest_mount_ready( &self, _key: &ResourceKey, diff --git a/packages/d2b-provider-volume-binding/src/facets.rs b/packages/d2b-provider-volume-binding/src/facets.rs index ce79f80ed..862188740 100644 --- a/packages/d2b-provider-volume-binding/src/facets.rs +++ b/packages/d2b-provider-volume-binding/src/facets.rs @@ -49,6 +49,13 @@ pub trait SocketReadySource: Send + Sync + 'static { #[async_trait] pub trait SocketRemoveSource: Send + Sync + 'static { /// Remove the endpoint realization (socket). + /// + /// # Errors + /// + /// Returns `Err` when the daemon adapter fails to remove the realized + /// socket endpoint. A socket that was never realized, or whose file is + /// already gone, answers `Ok(())` - the removal is idempotent under + /// retry. async fn remove(&self, socket: &SocketIdentity) -> Result<(), String>; } @@ -62,5 +69,13 @@ pub trait SocketRemoveSource: Send + Sync + 'static { #[async_trait] pub trait GuestMountSource: Send + Sync + 'static { /// Whether the target Guest observes the row's mount. + /// + /// # Errors + /// + /// Returns `Err` when the daemon adapter cannot complete the + /// observation (the target layer is unreachable). A target the + /// directory cannot reach, a loose row, and a source the Guest holds + /// no realization for all answer `Ok(false)` - the observation fails + /// closed. async fn guest_mount_ready(&self, key: &ResourceKey) -> Result; } \ No newline at end of file diff --git a/packages/d2b-provider-volume-binding/src/row_readers.rs b/packages/d2b-provider-volume-binding/src/row_readers.rs index 884c86004..fb965a026 100644 --- a/packages/d2b-provider-volume-binding/src/row_readers.rs +++ b/packages/d2b-provider-volume-binding/src/row_readers.rs @@ -37,11 +37,13 @@ pub fn parsed_binding_spec(binding: &StoredResource) -> Option(serde_json::Value::Object(object.clone())).ok() + serde_json::from_value::(spec).ok() } #[cfg(test)] From f547324caebb1a11fc535cbfe83f4c96d42ece3d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:10:20 -0700 Subject: [PATCH 057/726] refactor(d2b-contracts-zone-session): derive Default for receive and send sequences --- .../src/v3/component_session.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/packages/d2b-contracts-zone-session/src/v3/component_session.rs b/packages/d2b-contracts-zone-session/src/v3/component_session.rs index 2f8d079fb..cd253e098 100644 --- a/packages/d2b-contracts-zone-session/src/v3/component_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/component_session.rs @@ -1892,7 +1892,7 @@ pub enum SequenceError { NonceExhausted, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct ReceiveSequence { expected: u64, exhausted: bool, @@ -1932,13 +1932,7 @@ impl ReceiveSequence { } } -impl Default for ReceiveSequence { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct SendSequence { next: u64, exhausted: bool, @@ -1973,12 +1967,6 @@ impl SendSequence { } } -impl Default for SendSequence { - fn default() -> Self { - Self::new() - } -} - #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] From 86207132047e83c419613134c66da1d2117ec631 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:10:24 -0700 Subject: [PATCH 058/726] refactor(d2b-contracts-zone-session): drop clone from withdrawal duplicate check --- .../d2b-contracts-zone-session/src/v3/zone_routing.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs b/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs index eb490759a..eaf88de47 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs @@ -880,10 +880,11 @@ impl ZoneLinkRouteWithdrawal { if withdrawn_route_ids.len() > MAX_ADVERTISED_ZONE_ROUTES { return Err(PrimitiveSpecError::TooManyEntries); } - let mut unique = withdrawn_route_ids.clone(); - unique.sort_unstable(); - unique.dedup(); - if unique.len() != withdrawn_route_ids.len() { + if withdrawn_route_ids + .iter() + .enumerate() + .any(|(index, route_id)| withdrawn_route_ids[..index].contains(route_id)) + { return Err(PrimitiveSpecError::DuplicateEntry); } Ok(Self { From acffb74664bbfa6ec4a6e719da8dfa2e72f3b24c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:10:27 -0700 Subject: [PATCH 059/726] refactor(d2b-contracts-zone-session): walk bundle spec without cloning --- .../src/v3/resource_bundle.rs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs index 284f8d07b..5a33b3aad 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs @@ -923,7 +923,21 @@ fn is_digest(value: &str) -> bool { fn reject_runtime_or_private_fields( object: &CanonicalJsonObject, ) -> Result<(), ResourceBundleError> { - fn walk(value: &CanonicalJsonValue) -> bool { + fn walk_object(object: &CanonicalJsonObject) -> bool { + object.keys().any(|key| { + matches!( + key, + "status" + | "storePath" + | "nixSystem" + | "schemaFingerprint" + | "providerSchemaFingerprint" + | "managedBy" + | "configurationGeneration" + ) || object.get(key).is_some_and(walk_value) + }) + } + fn walk_value(value: &CanonicalJsonValue) -> bool { match value { CanonicalJsonValue::Object(map) => map.iter().any(|(key, value)| { matches!( @@ -935,13 +949,13 @@ fn reject_runtime_or_private_fields( | "providerSchemaFingerprint" | "managedBy" | "configurationGeneration" - ) || walk(value) + ) || walk_value(value) }), - CanonicalJsonValue::Array(values) => values.iter().any(walk), + CanonicalJsonValue::Array(values) => values.iter().any(walk_value), _ => false, } } - if walk(&CanonicalJsonValue::Object(object.clone().into_inner())) { + if walk_object(object) { Err(ResourceBundleError::ForbiddenField) } else { Ok(()) From 7be394a88aa15158f15d283d5b83387951ea3a33 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:10:28 -0700 Subject: [PATCH 060/726] refactor(d2b-contracts-zone-session): parse method names by borrow --- packages/d2b-contracts-zone-session/src/v3/services.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-contracts-zone-session/src/v3/services.rs b/packages/d2b-contracts-zone-session/src/v3/services.rs index c44ec6ba0..fd5872710 100644 --- a/packages/d2b-contracts-zone-session/src/v3/services.rs +++ b/packages/d2b-contracts-zone-session/src/v3/services.rs @@ -213,7 +213,7 @@ impl ServiceDescriptor { } if methods .iter() - .any(|method| BoundedText::parse(method.clone()).is_err()) + .any(|method| BoundedText::parse(method.as_str()).is_err()) { return Err(ServiceDescriptorError::InvalidMethod); } From 7d49c455de34ca479601cc3a59928977c07d697b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:10:53 -0700 Subject: [PATCH 061/726] endpoint: derive Default for consumer policy and pin inspect payload rows --- .../src/effects_service.rs | 74 +++++++++++++++++++ .../d2b-provider-endpoint/src/endpoint.rs | 8 +- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/packages/d2b-provider-endpoint/src/effects_service.rs b/packages/d2b-provider-endpoint/src/effects_service.rs index 52ca860e7..3cb76e490 100644 --- a/packages/d2b-provider-endpoint/src/effects_service.rs +++ b/packages/d2b-provider-endpoint/src/effects_service.rs @@ -317,6 +317,80 @@ mod tests { assert!(!device_worker_purpose("ch-api")); } + /// The string value of one canonical JSON field, if it is a string. + fn json_string( + value: Option<&d2b_contracts_resource::v3::CanonicalJsonValue>, + ) -> Option<&str> { + match value { + Some(d2b_contracts_resource::v3::CanonicalJsonValue::String(s)) => Some(s.as_str()), + _ => None, + } + } + + /// The `inspect-endpoint` payload rows equal the crate's own + /// derivations: every purpose the report commits derives to the same + /// class, producer, and locality the driver effects classify against, + /// and the committed purpose set is exactly the union of the two + /// derived families. A provider role or purpose rename that drifts the + /// report fails this pin. + #[test] + fn the_inspect_payload_rows_match_the_purpose_derivations() { + let response = inspect_endpoint_response().expect("the payload is canonical JSON"); + let purposes = response + .payload + .get("purposes") + .and_then(|value| value.as_object()) + .expect("purposes map"); + + let mut family_purposes = std::collections::BTreeSet::new(); + for role in [ChildRole::ChApiEndpoint, ChildRole::GuestControlEndpoint] { + family_purposes.insert(role.purpose().expect("declared purpose")); + } + family_purposes.insert(d2b_provider_device_tpm::TPM_SERVER_ENDPOINT_PURPOSE); + family_purposes.insert(d2b_provider_device_tpm::TPM_CONTROL_ENDPOINT_PURPOSE); + assert_eq!( + purposes + .keys() + .map(String::as_str) + .collect::>(), + family_purposes, + "the committed purpose set is exactly the union of the derived families" + ); + + for (purpose, row) in purposes { + let row = row.as_object().expect("purpose row"); + let class = json_string(row.get("class")); + if let Some(producer) = guest_control_producer(purpose) { + assert_eq!(class, Some("control"), "{purpose} is a guest-control purpose"); + assert_eq!( + json_string(row.get("producer")), + Some(producer.resource_type()), + "{purpose} producer derives from the provider role" + ); + assert_eq!( + json_string(row.get("locality")), + serde_json::to_value(producer.locality()) + .ok() + .and_then(|v| v.as_str().map(str::to_owned)) + .as_deref(), + "{purpose} locality derives from the producer" + ); + } else { + let derived = device_worker_endpoint_class(purpose) + .expect("every committed purpose belongs to a derived family"); + assert_eq!( + class, + serde_json::to_value(derived) + .ok() + .and_then(|v| v.as_str().map(str::to_owned)) + .as_deref(), + "{purpose} class derives from the device-worker vocabulary" + ); + assert!(row.get("producer").is_none(), "{purpose} has no producer"); + } + } + } + /// The service's vocabulary answers equal the free derivations, and the /// socket dispatch routes the evidence purposes onto the evidence /// facets and everything else onto the host socket facet. diff --git a/packages/d2b-provider-endpoint/src/endpoint.rs b/packages/d2b-provider-endpoint/src/endpoint.rs index 46f3063ed..3cdbe06e4 100644 --- a/packages/d2b-provider-endpoint/src/endpoint.rs +++ b/packages/d2b-provider-endpoint/src/endpoint.rs @@ -137,7 +137,7 @@ impl EndpointAttachmentPolicy { } /// The only fine-grained endpoint consumer policy. -#[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] +#[derive(Clone, PartialEq, Eq, Default, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct EndpointConsumerPolicy { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -392,12 +392,6 @@ impl<'de> Deserialize<'de> for EndpointSpec { } } -impl Default for EndpointConsumerPolicy { - fn default() -> Self { - Self::unrestricted() - } -} - /// Stable endpoint contract errors. #[derive(Debug, Clone, PartialEq, Eq)] pub enum EndpointSpecError { From fc707d7527679cda973eea746a1231ba9ab80b1a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:11:33 -0700 Subject: [PATCH 062/726] audit: share the bounded line reader and complete the doc contracts --- packages/d2b-audit/src/export.rs | 52 ++++++------------- packages/d2b-audit/src/operation.rs | 12 ++++- packages/d2b-audit/src/reconcile.rs | 6 +++ packages/d2b-audit/src/record_types.rs | 48 +++++++++++++++++ packages/d2b-audit/src/segment.rs | 51 ++++++++++++++++-- packages/d2b-audit/src/sink.rs | 71 +++++++++++--------------- 6 files changed, 159 insertions(+), 81 deletions(-) diff --git a/packages/d2b-audit/src/export.rs b/packages/d2b-audit/src/export.rs index 68bcd8573..12f845eaf 100644 --- a/packages/d2b-audit/src/export.rs +++ b/packages/d2b-audit/src/export.rs @@ -2,7 +2,7 @@ use std::{ fs, - io::{self, BufRead}, + io, os::unix::fs::OpenOptionsExt, path::Path, }; @@ -70,6 +70,16 @@ pub fn export_segments(directory: impl AsRef) -> io::Result, @@ -102,12 +112,6 @@ pub fn export_segments_range( if checkpoint_pending(directory.as_ref())? { return Err(io::Error::other("audit-retention-checkpoint-pending")); } - paths.retain(|path| { - let Some(name) = path.file_name().and_then(|value| value.to_str()) else { - return false; - }; - is_segment_name(name) - }); paths.sort(); let mut lines = Vec::new(); let mut previous = checkpoint_anchor(directory.as_ref())?; @@ -131,7 +135,11 @@ pub fn export_segments_range( .open(path)?; let mut reader = io::BufReader::new(file); loop { - let bytes = match read_bounded_line(&mut reader) { + let bytes = match crate::segment::read_bounded_line( + &mut reader, + "audit-export-line-truncated", + "audit-export-line-limit", + ) { Ok(Some(bytes)) => bytes, Ok(None) => break, Err(_) => { @@ -252,34 +260,6 @@ pub fn export_segments_range( Ok(lines) } -fn read_bounded_line(reader: &mut R) -> io::Result>> { - let mut bytes = Vec::new(); - loop { - let chunk = reader.fill_buf()?; - if chunk.is_empty() { - return if bytes.is_empty() { - Ok(None) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "audit-export-line-truncated", - )) - }; - } - let newline = chunk.iter().position(|byte| *byte == b'\n'); - let take = newline.map_or(chunk.len(), |index| index + 1); - if bytes.len().saturating_add(take) > MAX_EXPORT_LINE_BYTES { - return Err(io::Error::other("audit-export-line-limit")); - } - bytes.extend_from_slice(&chunk[..take]); - reader.consume(take); - if newline.is_some() { - bytes.pop(); - return Ok(Some(bytes)); - } - } -} - /// Return whether a value is an owned audit segment basename. pub fn is_segment_name(name: &str) -> bool { let Some(digits) = name diff --git a/packages/d2b-audit/src/operation.rs b/packages/d2b-audit/src/operation.rs index 2e6fd5cf1..e9f15a60e 100644 --- a/packages/d2b-audit/src/operation.rs +++ b/packages/d2b-audit/src/operation.rs @@ -57,6 +57,11 @@ impl<'de> serde::Deserialize<'de> for OperationIdentity { impl OperationIdentity { /// Derive an identity from the request token. + /// + /// # Errors + /// + /// Returns [`OperationIdentityError::Invalid`] when the token is empty, + /// exceeds the bounded length, or contains control characters. pub fn derive(value: &str) -> Result { if value.is_empty() || value.len() > MAX_OPERATION_ID_BYTES @@ -75,8 +80,13 @@ impl OperationIdentity { } /// Parse a previously derived canonical identity. + /// + /// # Errors + /// + /// Returns [`OperationIdentityError::Invalid`] when the value is not a + /// canonical digest. pub fn parse(value: &str) -> Result { - AuditHash::parse(value.to_owned()) + AuditHash::parse(value) .map(|hash| Self(hash.as_str().to_owned())) .map_err(|_| OperationIdentityError::Invalid) } diff --git a/packages/d2b-audit/src/reconcile.rs b/packages/d2b-audit/src/reconcile.rs index c266933f3..5b2a5e518 100644 --- a/packages/d2b-audit/src/reconcile.rs +++ b/packages/d2b-audit/src/reconcile.rs @@ -51,6 +51,12 @@ impl std::error::Error for EvidenceError {} /// the refused, policy, unknown, and errored classes. A caller-supplied key /// is accepted only when it exactly equals the canonical key built from the /// explicit Zone and operation identity. +/// +/// # Errors +/// +/// Returns [`EvidenceError::KeyMismatch`] when `supplied_key` is absent or +/// differs from the canonical key, and [`EvidenceError::DecisionResultInvalid`] +/// when the decision/result pair is not one of the closed terminal pairs. pub fn evidence_from_decision_result( zone: ZoneId, operation: OperationIdentity, diff --git a/packages/d2b-audit/src/record_types.rs b/packages/d2b-audit/src/record_types.rs index c949ac4a1..e88bdb9b4 100644 --- a/packages/d2b-audit/src/record_types.rs +++ b/packages/d2b-audit/src/record_types.rs @@ -424,6 +424,42 @@ impl core::fmt::Debug for AuditRecord { impl AuditRecord { /// Construct and hash a record. + /// + /// # Errors + /// + /// Returns [`AuditRecordError::TextOutOfBounds`] when a text field + /// exceeds the bounded envelope, [`AuditRecordError::FieldInvalid`] when + /// the class fields fall outside their closed domain, and + /// [`AuditRecordError::Serialization`] when canonical hashing fails. + /// + /// # Examples + /// + /// ``` + /// use d2b_audit::{AuditRecord, AuditRecordFields, ProcessEffectFields, genesis_hash}; + /// + /// let record = AuditRecord::new( + /// 1, + /// "work", + /// "op", + /// "corr", + /// None, + /// "test", + /// genesis_hash(), + /// AuditRecordFields::ProcessEffect(ProcessEffectFields { + /// event: "launch".to_owned(), + /// provider: "systemd".to_owned(), + /// domain: "system".to_owned(), + /// no_isolation: false, + /// execution_ref_digest: + /// "sha256:0000000000000000000000000000000000000000000000000000000000000001" + /// .to_owned(), + /// process_uid: "uid".to_owned(), + /// outcome: "ok".to_owned(), + /// exit_class: None, + /// }), + /// ) + /// .expect("the record is within bounds"); + /// ``` #[allow(clippy::too_many_arguments)] pub fn new( ts_ms: u64, @@ -495,6 +531,11 @@ impl AuditRecord { } /// Return the Zone-scoped operation join key for this record. + /// + /// # Errors + /// + /// Returns [`AuditRecordError::FieldInvalid`] when the record's Zone + /// cannot be parsed or derived into a canonical Zone identity. pub fn zone_operation_key(&self) -> Result { Ok(crate::ZoneOperationKey::new( crate::ZoneId::parse(&self.zone) @@ -535,6 +576,13 @@ impl AuditRecord { } /// Verify the record hash and predecessor link. + /// + /// # Errors + /// + /// Returns [`AuditRecordError::ChainMismatch`] when the predecessor hash + /// does not match `expected_previous`, [`AuditRecordError::HashMismatch`] + /// when the record's stored hash does not match its recomputed hash, and + /// [`AuditRecordError::Serialization`] when canonical hashing fails. pub fn verify(&self, expected_previous: &AuditHash) -> Result<(), AuditRecordError> { if &self.previous_hash != expected_previous { return Err(AuditRecordError::ChainMismatch); diff --git a/packages/d2b-audit/src/segment.rs b/packages/d2b-audit/src/segment.rs index 666e840e4..98e81c00d 100644 --- a/packages/d2b-audit/src/segment.rs +++ b/packages/d2b-audit/src/segment.rs @@ -154,6 +154,28 @@ impl core::fmt::Debug for SegmentWriter { impl SegmentWriter { /// Open the current segment in a directory. + /// + /// # Errors + /// + /// Returns `InvalidInput` ("audit-directory-not-absolute") when the + /// directory is not absolute, and the stable codes "audit-lock-ownership- + /// invalid", "audit-lock-held", "audit-directory-ownership-invalid", and + /// "audit-segment-identity-invalid" for the corresponding lock, ownership, + /// and metadata failures. Filesystem and retention errors propagate + /// unchanged. + /// + /// # Examples + /// + /// ``` + /// use d2b_audit::SegmentWriter; + /// + /// let directory = std::env::temp_dir().join(format!( + /// "d2b-audit-segment-writer-doc-{}", + /// std::process::id() + /// )); + /// let writer = SegmentWriter::open(&directory, 1024, 1).expect("open succeeds"); + /// # std::fs::remove_dir_all(directory).ok(); + /// ``` #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn open( directory: impl AsRef, @@ -227,6 +249,11 @@ impl SegmentWriter { } /// Append a record and rotate before crossing a size or UTC-day boundary. + /// + /// # Errors + /// + /// Returns an `io::Error` when the record cannot be serialized or when + /// the segment write, rotation, or directory sync fails. pub fn append(&mut self, record: &AuditRecord) -> io::Result { self.append_at(record, now_ms()) } @@ -962,7 +989,11 @@ fn segment_tail_hash( .open(path)?; let mut reader = BufReader::new(file); let mut current = previous.clone(); - while let Some(line) = read_bounded_line(&mut reader)? { + while let Some(line) = read_bounded_line( + &mut reader, + "audit-segment-line-truncated", + "audit-segment-line-limit", + )? { budget.consume_line(line.len())?; if line.is_empty() { continue; @@ -977,7 +1008,16 @@ fn segment_tail_hash( Ok(current) } -fn read_bounded_line(reader: &mut R) -> io::Result>> { +/// Read one bounded JSONL line, refusing lines that exceed the shared +/// [`MAX_EXPORT_LINE_BYTES`](crate::export::MAX_EXPORT_LINE_BYTES) limit. +/// +/// The two error codes are supplied by the caller so each reading surface +/// keeps its own stable wire code for truncated and over-limit lines. +pub(crate) fn read_bounded_line( + reader: &mut R, + truncated_code: &'static str, + limit_code: &'static str, +) -> io::Result>> { let mut bytes = Vec::new(); loop { let chunk = reader.fill_buf()?; @@ -985,13 +1025,16 @@ fn read_bounded_line(reader: &mut R) -> io::Result>> return if bytes.is_empty() { Ok(None) } else { - Err(io::Error::other("audit-segment-line-truncated")) + Err(io::Error::new( + io::ErrorKind::InvalidData, + truncated_code, + )) }; } let newline = chunk.iter().position(|byte| *byte == b'\n'); let take = newline.map_or(chunk.len(), |index| index + 1); if bytes.len().saturating_add(take) > crate::export::MAX_EXPORT_LINE_BYTES { - return Err(io::Error::other("audit-segment-line-limit")); + return Err(io::Error::other(limit_code)); } bytes.extend_from_slice(&chunk[..take]); reader.consume(take); diff --git a/packages/d2b-audit/src/sink.rs b/packages/d2b-audit/src/sink.rs index bcaf0400a..ecac84929 100644 --- a/packages/d2b-audit/src/sink.rs +++ b/packages/d2b-audit/src/sink.rs @@ -3,7 +3,7 @@ use std::{ collections::BTreeMap, fs, - io::{self, BufRead}, + io, os::unix::fs::OpenOptionsExt, path::Path, sync::Mutex, @@ -85,6 +85,12 @@ impl core::fmt::Debug for AuditSink { impl AuditSink { /// Open the default 64 MiB, 30-day sink. + /// + /// # Errors + /// + /// Returns [`AuditSinkError::Unavailable`] when the segment cannot be + /// opened or synchronized, and [`AuditSinkError::ChainMismatch`] when the + /// existing chain fails verification during the startup scan. pub fn open(directory: impl AsRef) -> Result { Self::open_with_limits( directory, @@ -171,6 +177,16 @@ impl AuditSink { } /// Append one record under its durability class. + /// + /// # Errors + /// + /// Returns [`AuditSinkError::StatePoisoned`] when the internal lock state + /// is poisoned, [`AuditSinkError::ChainMismatch`] when the record does not + /// name the sink's current chain head or duplicates a durable mutation + /// with a different hash, [`AuditSinkError::Serialization`] when the + /// record cannot be encoded, and [`AuditSinkError::Poisoned`] or + /// [`AuditSinkError::Unavailable`] when the segment write or privileged + /// sync fails. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn append( &self, @@ -237,6 +253,12 @@ impl AuditSink { } /// Prune old immutable segments. + /// + /// # Errors + /// + /// Returns [`AuditSinkError::StatePoisoned`] when the internal lock state + /// is poisoned, [`AuditSinkError::Unavailable`] when pruning fails, and + /// [`AuditSinkError::Poisoned`] when the post-prune chain rescan fails. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn prune_old(&self, now_ms: u64) -> Result { let mut state = self @@ -380,8 +402,12 @@ fn scan_chain_state(directory: &Path) -> Result { .open(path) .map_err(|_| AuditSinkError::Unavailable)?; let mut reader = io::BufReader::new(file); - while let Some(bytes) = - read_bounded_line(&mut reader).map_err(|_| AuditSinkError::ChainMismatch)? + while let Some(bytes) = crate::segment::read_bounded_line( + &mut reader, + "audit-scan-line-truncated", + "audit-scan-line-limit", + ) + .map_err(|_| AuditSinkError::ChainMismatch)? { let line = String::from_utf8(bytes).map_err(|_| AuditSinkError::ChainMismatch)?; let record = serde_json::from_str::(&line) @@ -395,19 +421,12 @@ fn scan_chain_state(directory: &Path) -> Result { { let key = (key, mutation_id.to_owned()); if durable_mutations - .insert(key, record.record_hash().clone()) + .insert(key.clone(), record.record_hash().clone()) .is_some() { return Err(AuditSinkError::ChainMismatch); } - if let Some(mutation_id) = record.mutation_id() - && let Ok(key) = record.zone_operation_key() - { - mutation_predecessors.insert( - (key, mutation_id.to_owned()), - record.previous_hash().clone(), - ); - } + mutation_predecessors.insert(key, record.previous_hash().clone()); } } } @@ -418,34 +437,6 @@ fn scan_chain_state(directory: &Path) -> Result { }) } -fn read_bounded_line(reader: &mut R) -> io::Result>> { - let mut bytes = Vec::new(); - loop { - let chunk = reader.fill_buf()?; - if chunk.is_empty() { - return if bytes.is_empty() { - Ok(None) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "audit-scan-line-truncated", - )) - }; - } - let newline = chunk.iter().position(|byte| *byte == b'\n'); - let take = newline.map_or(chunk.len(), |index| index + 1); - if bytes.len().saturating_add(take) > crate::export::MAX_EXPORT_LINE_BYTES { - return Err(io::Error::other("audit-scan-line-limit")); - } - bytes.extend_from_slice(&chunk[..take]); - reader.consume(take); - if newline.is_some() { - bytes.pop(); - return Ok(Some(bytes)); - } - } -} - #[cfg(test)] mod tests { use super::*; From 3d165efc4b3cbb3a3399acff0c61fcfcfc91e7af Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:12:04 -0700 Subject: [PATCH 063/726] host: dedent test-support impl brace and borrow row keys --- packages/d2b-provider-host/src/driver.rs | 4 ++-- packages/d2b-provider-host/src/test_support.rs | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-host/src/driver.rs b/packages/d2b-provider-host/src/driver.rs index 754b23b2e..0a185f16c 100644 --- a/packages/d2b-provider-host/src/driver.rs +++ b/packages/d2b-provider-host/src/driver.rs @@ -260,10 +260,10 @@ impl HostDriver { op: DriverOp, ) -> Result { let type_name = d2b_contracts_resource::v3::ResourceTypeName::parse( - ctx.key().type_name.clone(), + &ctx.key().type_name, ) .map_err(|_| self.error(HostDriverErrorKind::SpecInvalid, op))?; - let name = d2b_contracts_resource::v3::ResourceName::parse(ctx.key().name.clone()) + let name = d2b_contracts_resource::v3::ResourceName::parse(&ctx.key().name) .map_err(|_| self.error(HostDriverErrorKind::SpecInvalid, op))?; Ok(ResourceRef::new(type_name, name)) } diff --git a/packages/d2b-provider-host/src/test_support.rs b/packages/d2b-provider-host/src/test_support.rs index cbbeb82dd..a5a9eae9f 100644 --- a/packages/d2b-provider-host/src/test_support.rs +++ b/packages/d2b-provider-host/src/test_support.rs @@ -181,8 +181,7 @@ impl RecordingMinijailGate { gate: tokio::sync::Mutex::new(gate), }) } - - } +} impl MinijailPlatformGateSource for RecordingMinijailGate { fn platform_gate(&self) -> MinijailPlatformGate { From 3459dc5a00ac8cce82a689f955f0a04518143cce Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:13:05 -0700 Subject: [PATCH 064/726] refactor(d2b-provider-config-nixos): share the path-component rejection walk --- .../d2b-provider-config-nixos/src/ttrpc.rs | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/d2b-provider-config-nixos/src/ttrpc.rs b/packages/d2b-provider-config-nixos/src/ttrpc.rs index 7a124f8cf..deec6af38 100644 --- a/packages/d2b-provider-config-nixos/src/ttrpc.rs +++ b/packages/d2b-provider-config-nixos/src/ttrpc.rs @@ -50,6 +50,13 @@ impl std::fmt::Debug for GuestConfigReader { impl GuestConfigReader { /// Bind the reader to one admitted Guest ComponentSession generation. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the reference does not + /// name a Guest or the path is not an absolute, component-clean path, and + /// [`ConfigError::SessionMismatch`] when the boot identity or reconnect + /// generation fails the session evidence bounds. pub fn new( guest_ref: ResourceRef, boot_identity_digest: impl Into, @@ -108,7 +115,7 @@ impl ConfigServiceBackend for GuestConfigReader { ConfigCaller::Guest, &request, &self.evidence, - document.bytes().to_vec(), + document.into_bytes(), )?; serde_json::to_value(response).map_err(|error| { tracing::warn!( @@ -376,19 +383,25 @@ fn invalid_status() -> ttrpc::Status { ) } -fn validate_reader_path(path: &Path) -> Result<(), ConfigError> { +fn path_components(path: &Path) -> Result, ConfigError> { if !path.is_absolute() { return Err(ConfigError::InvalidRequest); } + let mut components = Vec::new(); for component in path.components() { - if matches!( - component, - Component::CurDir | Component::ParentDir | Component::Prefix(_) - ) { - return Err(ConfigError::InvalidRequest); + match component { + Component::RootDir => {} + Component::Normal(value) => components.push(value), + Component::CurDir | Component::ParentDir | Component::Prefix(_) => { + return Err(ConfigError::InvalidRequest); + } } } - Ok(()) + Ok(components) +} + +fn validate_reader_path(path: &Path) -> Result<(), ConfigError> { + path_components(path).map(|_| ()) } fn read_bounded_file(path: &Path) -> Result, ConfigError> { @@ -408,19 +421,7 @@ fn read_bounded_file(path: &Path) -> Result, ConfigError> { } } - if !path.is_absolute() { - return Err(ConfigError::InvalidRequest); - } - let mut components = Vec::new(); - for component in path.components() { - match component { - Component::RootDir => {} - Component::Normal(value) => components.push(value), - Component::CurDir | Component::ParentDir | Component::Prefix(_) => { - return Err(ConfigError::InvalidRequest); - } - } - } + let components = path_components(path)?; let Some((leaf, parents)) = components.split_last() else { return Err(ConfigError::InvalidRequest); }; From b17a8c271239ea497bf2eaccd6ac51071e4de000 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:13:06 -0700 Subject: [PATCH 065/726] refactor(d2b-provider-config-nixos): consume validated document bytes without copying --- .../src/controller.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/d2b-provider-config-nixos/src/controller.rs b/packages/d2b-provider-config-nixos/src/controller.rs index 5240e0bfd..044306c3c 100644 --- a/packages/d2b-provider-config-nixos/src/controller.rs +++ b/packages/d2b-provider-config-nixos/src/controller.rs @@ -43,6 +43,12 @@ pub struct GuestSessionEvidence { impl GuestSessionEvidence { /// Construct evidence after binding the Guest and reconnect generation. + /// + /// # Errors + /// + /// Returns [`ConfigError::SessionMismatch`] when the reference does not + /// name a Guest, the name is empty, the reconnect generation is zero, or + /// the boot identity is empty or longer than 128 bytes. pub fn new( guest_ref: ResourceRef, boot_identity: impl Into, @@ -103,6 +109,12 @@ pub struct GuestConfigDocument { impl GuestConfigDocument { /// Validate and retain one bounded non-empty UTF-8 Nix document. + /// + /// # Errors + /// + /// Returns [`ConfigError::EmptyDocument`] for empty bytes, + /// [`ConfigError::DocumentTooLarge`] above the fixed byte bound, and + /// [`ConfigError::InvalidUtf8`] when the bytes are not UTF-8. pub fn new(bytes: impl Into>) -> Result { let bytes = bytes.into(); if bytes.is_empty() { @@ -122,6 +134,11 @@ impl GuestConfigDocument { &self.bytes } + /// Consume the validated document bytes. + pub fn into_bytes(self) -> Vec { + self.bytes + } + /// Return the document size. /// /// `is_empty` is deliberately absent: `new` rejects empty documents, so @@ -261,6 +278,15 @@ pub struct ConfigService; impl ConfigService { /// Read one Guest document through current authenticated session evidence. + /// + /// # Errors + /// + /// Returns [`ConfigError::Unauthorized`] when the caller cannot read, + /// [`ConfigError::SessionMismatch`] when the caller is not the Guest, the + /// request does not match the evidence, or the evidence is stale, and the + /// document bounds errors ([`ConfigError::EmptyDocument`], + /// [`ConfigError::DocumentTooLarge`], [`ConfigError::InvalidUtf8`]) when + /// the bytes fail validation. pub fn read_guest_config( &self, caller: ConfigCaller, @@ -288,6 +314,14 @@ impl ConfigService { } /// Validate a typed operation payload against the closed service. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the payload does not + /// decode or names a wrong Guest or identifier, [`ConfigError::InvalidView`] + /// for a malformed diff view, [`ConfigError::InvalidDestination`] for a + /// malformed approval destination, and the document bounds errors for a + /// Stage payload. pub fn validate_operation( &self, operation: ConfigOperation, From 7a6ab2d2daa5d3b7f2f705cf2da52e018af12662 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:13:06 -0700 Subject: [PATCH 066/726] docs(d2b-provider-config-nixos): document error conditions on public APIs --- .../d2b-provider-config-nixos/src/service.rs | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/packages/d2b-provider-config-nixos/src/service.rs b/packages/d2b-provider-config-nixos/src/service.rs index 9f07a0e2d..a75399fb6 100644 --- a/packages/d2b-provider-config-nixos/src/service.rs +++ b/packages/d2b-provider-config-nixos/src/service.rs @@ -28,6 +28,11 @@ pub struct ConfigSyncRequest { impl ConfigSyncRequest { /// Construct and validate a closed request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the reference does not + /// name a Guest. pub fn new(guest_ref: ResourceRef) -> Result { if guest_ref.resource_type().as_str() != "Guest" { return Err(ConfigError::InvalidRequest); @@ -67,6 +72,15 @@ impl ConfigSyncResponse { } /// Decode the response and reapply all document bounds. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the identifier is not the + /// closed Guest-config identifier or the base64 exceeds the encoded bound, + /// [`ConfigError::EncodingFailed`] when the base64 does not decode, and + /// the document bounds errors ([`ConfigError::EmptyDocument`], + /// [`ConfigError::DocumentTooLarge`], [`ConfigError::InvalidUtf8`]) when + /// the decoded bytes fail validation. pub fn document(&self) -> Result { if self.identifier != GUEST_CONFIG_IDENTIFIER || self.content_base64.len() > MAX_CONFIG_ENCODED_BYTES @@ -107,6 +121,10 @@ pub struct ConfigStageRequest { impl ConfigStageRequest { /// Construct a stage request from one already validated document. + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the reference does not + /// name a Guest. pub fn new( guest_ref: ResourceRef, document: &GuestConfigDocument, @@ -120,6 +138,15 @@ impl ConfigStageRequest { } /// Decode and validate the staged document. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the identifier is not the + /// closed Guest-config identifier, [`ConfigError::DocumentTooLarge`] when + /// the base64 exceeds the encoded bound, [`ConfigError::EncodingFailed`] + /// when the base64 does not decode, and the document bounds errors + /// ([`ConfigError::EmptyDocument`], [`ConfigError::DocumentTooLarge`], + /// [`ConfigError::InvalidUtf8`]) when the decoded bytes fail validation. pub fn document(&self) -> Result { validate_identifier(&self.identifier)?; if self.content_base64.len() > MAX_CONFIG_ENCODED_BYTES { @@ -163,6 +190,12 @@ pub struct ConfigDiffRequest { impl ConfigDiffRequest { /// Construct a diff request from a stable content-view digest. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the reference does not + /// name a Guest and [`ConfigError::InvalidView`] when the view identifier + /// is not a `sha256:` content commitment. pub fn new(guest_ref: ResourceRef, against: impl Into) -> Result { validate_guest_ref(&guest_ref)?; let against = against.into(); @@ -199,6 +232,13 @@ pub struct ConfigApproveRequest { impl ConfigApproveRequest { /// Construct an approval request for one opaque host target. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the reference does not + /// name a Guest and [`ConfigError::InvalidDestination`] when the + /// destination is empty, longer than 128 bytes, non-ASCII, or contains a + /// path separator or whitespace. pub fn new( guest_ref: ResourceRef, destination: impl Into, @@ -238,6 +278,11 @@ pub struct ConfigRejectRequest { impl ConfigRejectRequest { /// Construct a rejection request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the reference does not + /// name a Guest. pub fn new(guest_ref: ResourceRef) -> Result { validate_guest_ref(&guest_ref)?; Ok(Self { @@ -269,6 +314,11 @@ pub struct ConfigStatusRequest { impl ConfigStatusRequest { /// Construct a status request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the reference does not + /// name a Guest. pub fn new(guest_ref: ResourceRef) -> Result { validate_guest_ref(&guest_ref)?; Ok(Self { @@ -293,6 +343,12 @@ pub struct ConfigStatusResponse { } /// Convert one response into a validated document. +/// +/// # Errors +/// +/// Returns the same errors as [`ConfigSyncResponse::document`]: +/// [`ConfigError::InvalidRequest`], [`ConfigError::EncodingFailed`], and the +/// document bounds errors. pub fn decode_document(response: &ConfigSyncResponse) -> Result { response.document() } @@ -356,6 +412,14 @@ struct ApprovedConfig { impl ConfigStagingStore { /// Stage or replace one Guest document. + /// + /// # Errors + /// + /// Returns [`ConfigError::Unauthorized`] when the caller is not Admin, + /// [`ConfigError::InvalidRequest`] when the reference or identifier is + /// not the closed Guest-config pair, and the document bounds errors + /// ([`ConfigError::EmptyDocument`], [`ConfigError::DocumentTooLarge`], + /// [`ConfigError::InvalidUtf8`]). pub fn stage( &mut self, caller: ConfigCaller, @@ -376,6 +440,13 @@ impl ConfigStagingStore { } /// Compare staged content to a stable local-view digest. + /// + /// # Errors + /// + /// Returns [`ConfigError::Unauthorized`] when the caller is not Admin, + /// [`ConfigError::InvalidRequest`] for a wrong reference or identifier, + /// [`ConfigError::InvalidView`] for a malformed view identifier, and + /// [`ConfigError::StagingMissing`] when nothing is staged for the Guest. pub fn diff( &self, caller: ConfigCaller, @@ -399,6 +470,15 @@ impl ConfigStagingStore { /// Approval is idempotent so a caller can retry after the downstream /// host publish fails. The staged bytes are consumed into an internal /// approval receipt, and a matching retry returns the same response. + /// + /// # Errors + /// + /// Returns [`ConfigError::Unauthorized`] when the caller is not Admin, + /// [`ConfigError::InvalidRequest`] for a wrong reference or identifier, + /// [`ConfigError::InvalidDestination`] for a malformed destination, + /// [`ConfigError::StagingMissing`] when nothing is staged or approved for + /// the Guest, and [`ConfigError::ApprovalConflict`] when an approved + /// receipt exists for a different destination. pub fn approve( &mut self, caller: ConfigCaller, @@ -444,6 +524,11 @@ impl ConfigStagingStore { } /// Reject staged content, returning whether anything was removed. + /// + /// # Errors + /// + /// Returns [`ConfigError::Unauthorized`] when the caller is not Admin and + /// [`ConfigError::InvalidRequest`] for a wrong reference or identifier. pub fn reject( &mut self, caller: ConfigCaller, @@ -461,6 +546,11 @@ impl ConfigStagingStore { } /// Return bounded staging metadata without returning document bytes. + /// + /// # Errors + /// + /// Returns [`ConfigError::Unauthorized`] when the caller is not Admin and + /// [`ConfigError::InvalidRequest`] for a wrong reference or identifier. pub fn status( &self, caller: ConfigCaller, From f7e032f8fe3bc62f5549369301792cf195691b4e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:13:10 -0700 Subject: [PATCH 067/726] d2b-host: document parser failures and the controller token surface --- packages/d2b-host/src/bridge_port.rs | 6 ++++++ packages/d2b-host/src/cgroup.rs | 4 ++++ packages/d2b-host/src/host_generation.rs | 12 ++++++++++++ packages/d2b-host/src/host_prep_dag.rs | 1 + packages/d2b-host/src/media.rs | 14 ++++++++++++++ packages/d2b-host/src/nftables.rs | 7 +++++++ 6 files changed, 44 insertions(+) diff --git a/packages/d2b-host/src/bridge_port.rs b/packages/d2b-host/src/bridge_port.rs index acd49af79..6ec7e978a 100644 --- a/packages/d2b-host/src/bridge_port.rs +++ b/packages/d2b-host/src/bridge_port.rs @@ -124,6 +124,12 @@ pub struct FlagDifference { /// Compares an observed flag set against the per-role defaults. /// Returns `Ok(())` if every flag matches; otherwise a drift report /// listing every flag that diverges. +/// +/// # Errors +/// +/// Returns `Err(BridgePortFlagDrift)` when any observed flag differs +/// from the role's default set; the report names every diverging flag +/// with its expected and actual value. pub fn validate_readback( role: TapRoleW3, observed: BridgePortFlagSet, diff --git a/packages/d2b-host/src/cgroup.rs b/packages/d2b-host/src/cgroup.rs index 79ce216fb..9e53a11b8 100644 --- a/packages/d2b-host/src/cgroup.rs +++ b/packages/d2b-host/src/cgroup.rs @@ -51,6 +51,7 @@ pub enum Controller { } impl Controller { + /// The full controller set every delegated subtree must carry. pub const REQUIRED: &'static [Controller] = &[ Controller::Cpu, Controller::Memory, @@ -68,6 +69,7 @@ impl Controller { Controller::Cpuset, ]; + /// The cgroup v2 controller name as written in `cgroup.controllers`. pub fn as_str(&self) -> &'static str { match self { Controller::Cpu => "cpu", @@ -82,6 +84,8 @@ impl Controller { format!("+{}", self.as_str()) } + /// Parse a controller name token (surrounding whitespace tolerated) + /// into the matching variant. pub fn from_token(token: &str) -> Option { match token.trim() { "cpu" => Some(Controller::Cpu), diff --git a/packages/d2b-host/src/host_generation.rs b/packages/d2b-host/src/host_generation.rs index 1d995d0c9..c7d0ab940 100644 --- a/packages/d2b-host/src/host_generation.rs +++ b/packages/d2b-host/src/host_generation.rs @@ -100,6 +100,13 @@ impl core::fmt::Display for ActivationHelperProtocolError { impl std::error::Error for ActivationHelperProtocolError {} /// Parse one bounded helper request. +/// +/// # Errors +/// +/// Returns `TooLarge` when the input exceeds the fixed envelope bound, +/// `InvalidJson` when it is not valid strict JSON, and +/// `ArtifactIdInvalid` or `GenerationInvalid` when the decoded request +/// fails validation. pub fn parse_request( bytes: &[u8], ) -> Result { @@ -113,6 +120,11 @@ pub fn parse_request( } /// Parse one bounded read-only artifact validation request. +/// +/// # Errors +/// +/// Returns `TooLarge` when the input exceeds the fixed envelope bound +/// and `InvalidJson` when it is not valid strict JSON. pub fn parse_validation_request( bytes: &[u8], ) -> Result { diff --git a/packages/d2b-host/src/host_prep_dag.rs b/packages/d2b-host/src/host_prep_dag.rs index 881ae14da..e41925603 100644 --- a/packages/d2b-host/src/host_prep_dag.rs +++ b/packages/d2b-host/src/host_prep_dag.rs @@ -89,6 +89,7 @@ impl HostPrepStepId { Self(format!("{vm}:{}", kind.as_str())) } + /// The deterministic `:` spelling. pub fn as_str(&self) -> &str { &self.0 } diff --git a/packages/d2b-host/src/media.rs b/packages/d2b-host/src/media.rs index e8d6a0468..53fc7f0b3 100644 --- a/packages/d2b-host/src/media.rs +++ b/packages/d2b-host/src/media.rs @@ -38,6 +38,14 @@ impl fmt::Display for MediaRefError { impl std::error::Error for MediaRefError {} +/// Validate the media reference grammar. +/// +/// # Errors +/// +/// Returns `Empty` for an empty reference, `TooLong` beyond the +/// 63-byte bound, `BadStart` when the reference does not start with a +/// lowercase ASCII letter, and `BadCharacter` when it contains any +/// other character. pub fn validate_media_ref(value: &str) -> Result<(), MediaRefError> { if value.is_empty() { return Err(MediaRefError::Empty); @@ -76,6 +84,12 @@ impl fmt::Display for BusIdError { impl std::error::Error for BusIdError {} /// Validate the Linux USB busid shape used under `/sys/bus/usb/devices/`. +/// +/// # Errors +/// +/// Returns `Empty` for an empty busid, `TooLong` beyond the 64-byte +/// bound, and `BadCharacter` when the busid contains an invalid +/// character. pub fn validate_usb_busid(value: &str) -> Result<(), BusIdError> { if value.is_empty() { return Err(BusIdError::Empty); diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index dcdf66a26..8a9414c5c 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -242,6 +242,12 @@ impl NftBatch { /// Parse the limited d2b-managed `nft -f -` script dialect back /// into a structured batch so runtime checks can re-assert ordering /// invariants before touching the live table. + /// + /// # Errors + /// + /// Returns `ParseNftScriptError` with a line-anchored detail when + /// the script does not match the limited dialect (a chain missing + /// its hook or priority declaration, or a malformed rule). pub fn parse(script: &str) -> Result { struct PendingChain { name: String, @@ -609,6 +615,7 @@ impl NftBatch { pub struct BusId(pub String); impl BusId { + /// Wrap one USB busid string. pub fn new(s: impl Into) -> Self { Self(s.into()) } From 6acd5ada629499b6fe87eea5c9ac3afda4fe65c1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:13:11 -0700 Subject: [PATCH 068/726] d2b-provider-activation-nixos: state the policy API failure contract --- .../src/controller.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/d2b-provider-activation-nixos/src/controller.rs b/packages/d2b-provider-activation-nixos/src/controller.rs index 60134bf5c..3723bf48d 100644 --- a/packages/d2b-provider-activation-nixos/src/controller.rs +++ b/packages/d2b-provider-activation-nixos/src/controller.rs @@ -559,6 +559,14 @@ impl ActivationTrust { } /// Verify all trust, Ed25519, artifact, and activation-catalog fences. + /// + /// # Errors + /// + /// Returns `TrustEpochMismatch`, `RevocationRefMismatch`, + /// `TrustDenied`, `PublisherRootMismatch`, `SignatureIdMismatch`, + /// `ArtifactCatalogDigestMismatch`, `ArtifactDigestMismatch`, + /// `InvalidEvidence`, or `SignatureInvalid` for the corresponding + /// failed fence. pub fn verify( &self, expected: &ActivationTrustExpectation, @@ -708,6 +716,11 @@ impl ActivationController { } /// Gate activation/application on the complete signed artifact envelope. + /// + /// # Errors + /// + /// Returns the same `ActivationVerificationError` variants as + /// [`ActivationTrust::verify`] for the corresponding failed fence. pub fn verify_application( &self, trust: &ActivationTrust, @@ -723,6 +736,11 @@ impl ActivationController { /// The runner performs only the steps the family declares /// ([`crate::vocabulary::ACTIVATION_RUNNER_STEPS`]); an activation that /// requests another step is refused before any runner is planned. + /// + /// # Errors + /// + /// Returns `InvalidSpec` when `step` is not one of the declared + /// runner steps. pub fn refuse_undeclared_runner_step(&self, step: &str) -> Result<(), ActivationError> { if crate::vocabulary::is_declared_runner_step(step) { Ok(()) @@ -732,6 +750,15 @@ impl ActivationController { } /// Reconcile one desired generation. + /// + /// # Errors + /// + /// Returns `Unauthorized` or `TargetMismatch` when the caller is not + /// authorized for the spec's execution target, `InvalidSpec` when the + /// declared prior generation is missing from the observations, the + /// observed ordinal is zero, or the activation mode maps to no + /// declared runner step, and `AlreadyDeleted` when the observed + /// generation is already deleted. pub fn reconcile( &self, spec: &NixosGenerationSpec, @@ -805,6 +832,13 @@ impl ActivationController { /// Apply a typed runner result while preserving the prior generation on /// every refusal or failure. + /// + /// # Errors + /// + /// Returns `InvalidSpec` when the source generation ordinal is zero, + /// `AlreadyDeleted` when the source generation is already deleted, + /// and `OutcomeMismatch` when the outcome does not match the spec's + /// activation mode. pub fn apply_runner_result( &self, spec: &NixosGenerationSpec, From cf91a0aa790c2d0369720f142972ba8b7b561975 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:14:01 -0700 Subject: [PATCH 069/726] composition: borrow the dependency walk and name the unused seam parameter --- .../src/dependency_surface.rs | 47 +++++++++++-------- packages/d2b-broker-composition/src/seam.rs | 3 +- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/packages/d2b-broker-composition/src/dependency_surface.rs b/packages/d2b-broker-composition/src/dependency_surface.rs index 82960acf9..63e77bc67 100644 --- a/packages/d2b-broker-composition/src/dependency_surface.rs +++ b/packages/d2b-broker-composition/src/dependency_surface.rs @@ -129,17 +129,15 @@ pub fn crate_dir(crate_name: &str) -> Option { /// The workspace root, when it can be located from the environment. pub fn workspace_root() -> Option { - let mut current = std::env::var("CARGO_MANIFEST_DIR") + let current = std::env::var("CARGO_MANIFEST_DIR") .ok() .map(PathBuf::from) .or_else(|| std::env::current_dir().ok())?; - for _ in 0..4 { - if current.join("Cargo.toml").is_file() && current.join("packages").is_dir() { - return Some(current); - } - current = current.parent()?.to_path_buf(); - } - None + std::iter::successors(Some(current), |candidate| candidate.parent().map(Path::to_path_buf)) + .take(4) + .find(|candidate| { + candidate.join("Cargo.toml").is_file() && candidate.join("packages").is_dir() + }) } /// Run the offline half of the audit: probe one handler crate's sources on @@ -247,12 +245,18 @@ pub fn audit_crate(crate_name: &str) -> Result { build_script: false, source_violations: Vec::new(), }; - for name in &added { - if FORBIDDEN_SYSCALL_SURFACE_CRATES.contains(&name.as_str()) { - report.forbidden_dependencies.push(name.clone()); - } - if is_proc_macro(&metadata, name) { - report.proc_macro_dependencies.push(name.clone()); + for name in added { + match ( + FORBIDDEN_SYSCALL_SURFACE_CRATES.contains(&name.as_str()), + is_proc_macro(&metadata, &name), + ) { + (true, true) => { + report.forbidden_dependencies.push(name.clone()); + report.proc_macro_dependencies.push(name); + } + (true, false) => report.forbidden_dependencies.push(name), + (false, true) => report.proc_macro_dependencies.push(name), + (false, false) => {} } } // A handler crate that DECLARES a syscall-surface dependency directly @@ -269,7 +273,10 @@ pub fn audit_crate(crate_name: &str) -> Result { let aliased = regex::Regex::new(&format!(r#"package\s*=\s*"{crate_name}""#)) .expect("static pattern compiles"); if (direct_key.is_match(&text) || aliased.is_match(&text)) - && !report.forbidden_dependencies.contains(&crate_name.to_string()) + && !report + .forbidden_dependencies + .iter() + .any(|name| name == crate_name) { report.forbidden_dependencies.push((*crate_name).to_owned()); } @@ -337,16 +344,16 @@ fn dependency_tree( nodes.insert(id, node); } let mut reachable: Vec = Vec::new(); - let mut queue = vec![root_id.to_owned()]; + let mut queue = vec![root_id]; let mut seen = std::collections::BTreeSet::new(); while let Some(id) = queue.pop() { - if !seen.insert(id.clone()) { + if !seen.insert(id) { continue; } - let Some(node) = nodes.get(id.as_str()) else { + let Some(node) = nodes.get(id) else { continue; }; - if let Some(owner_name) = package_name_of_id(metadata, &id).filter(|name| *name != crate_name) + if let Some(owner_name) = package_name_of_id(metadata, id).filter(|name| *name != crate_name) { reachable.push(owner_name.to_owned()); } @@ -371,7 +378,7 @@ fn dependency_tree( kind.get("target").filter(|target| !target.is_null()).is_none() }); if follows { - queue.push(dep_id.to_owned()); + queue.push(dep_id); } } } diff --git a/packages/d2b-broker-composition/src/seam.rs b/packages/d2b-broker-composition/src/seam.rs index 0b2bc18ac..fe0e2273b 100644 --- a/packages/d2b-broker-composition/src/seam.rs +++ b/packages/d2b-broker-composition/src/seam.rs @@ -268,10 +268,9 @@ fn admit(declaration: &HandlerDeclaration) -> Result<(), RoutingRefusal> { /// (AE3's runtime half - the interface, not process isolation, is the /// boundary). pub fn state_cell<'a>( - invocation: &'a DirectInvocation<'a>, + _invocation: &'a DirectInvocation<'a>, _cell: &str, ) -> Option<&'a StateCellHandle<'a>> { - let _ = invocation; None } From 8fcd947b2282d10c64b335c09d418ad8d50edbc9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:14:29 -0700 Subject: [PATCH 070/726] process-systemd: derive Default on unit services and document error contracts --- .../d2b-provider-process-systemd/src/controller.rs | 8 ++++++++ packages/d2b-provider-process-systemd/src/drain.rs | 7 +++++++ .../src/effects_service.rs | 14 ++------------ .../d2b-provider-process-systemd/src/launch.rs | 5 +++++ .../d2b-provider-process-systemd/src/lifecycle.rs | 7 +++++++ .../d2b-provider-process-systemd/src/sandbox.rs | 6 ++++++ 6 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/d2b-provider-process-systemd/src/controller.rs b/packages/d2b-provider-process-systemd/src/controller.rs index 898129937..5e8beb47f 100644 --- a/packages/d2b-provider-process-systemd/src/controller.rs +++ b/packages/d2b-provider-process-systemd/src/controller.rs @@ -63,6 +63,14 @@ impl SystemdProcessControll } /// Reconcile one action without opening a systemd connection. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::DeadlineExceeded`] when the + /// launch slot is exhausted or the operation does not finish inside + /// its per-action timeout, and otherwise the error the wrapped launch, + /// adopt, or stop operation reports (ticket validation, identity + /// verification, or effect-port failure). pub async fn reconcile( &self, action: SystemdReconcileAction<'_>, diff --git a/packages/d2b-provider-process-systemd/src/drain.rs b/packages/d2b-provider-process-systemd/src/drain.rs index 8ca59adab..3fd038a7e 100644 --- a/packages/d2b-provider-process-systemd/src/drain.rs +++ b/packages/d2b-provider-process-systemd/src/drain.rs @@ -27,6 +27,13 @@ pub struct DrainProof { } /// Validate the systemd drain sequence. +/// +/// # Errors +/// +/// Returns [`DrainError::TerminalTransitionMissing`] when the exact-main +/// stop or the manager terminal transition is absent, and +/// [`DrainError::LeafNotEmpty`] when the anchored cgroup leaf still +/// contains a process. pub fn validate(proof: DrainProof) -> Result { if !proof.exact_main_stopped || !proof.manager_terminal { return Err(DrainError::TerminalTransitionMissing); diff --git a/packages/d2b-provider-process-systemd/src/effects_service.rs b/packages/d2b-provider-process-systemd/src/effects_service.rs index 0b9713500..159372309 100644 --- a/packages/d2b-provider-process-systemd/src/effects_service.rs +++ b/packages/d2b-provider-process-systemd/src/effects_service.rs @@ -86,6 +86,7 @@ pub const PROCESS_SYSTEMD_SERVICES: &[ServiceDecl] = &[PROCESS_SYSTEMD_EFFECTS_S /// One value per zone serves the declared methods;the factory constructs it /// from crate-owned constants alone, so a respawn rebuilds the same surface /// from its durable row (KTD5). +#[derive(Default)] pub struct SystemdEffectsService; impl SystemdEffectsService { @@ -95,12 +96,6 @@ impl SystemdEffectsService { } } -impl Default for SystemdEffectsService { - fn default() -> Self { - Self::new() - } -} - /// The one `inspect-process-systemd` response payload:the family's /// committed operation inventory, built through the canonical JSON object /// path. @@ -206,6 +201,7 @@ impl EffectService for SystemdEffectsService { /// The composition-root factory that hosts the system-systemd effects /// service in one zone (R5): no facet set, so one value serves every zone. +#[derive(Default)] pub struct SystemdEffectsServiceFactory; impl SystemdEffectsServiceFactory { @@ -215,12 +211,6 @@ impl SystemdEffectsServiceFactory { } } -impl Default for SystemdEffectsServiceFactory { - fn default() -> Self { - Self::new() - } -} - impl EffectServiceFactory for SystemdEffectsServiceFactory { fn build(&self) -> Arc { Arc::new(SystemdEffectsService::new()) diff --git a/packages/d2b-provider-process-systemd/src/launch.rs b/packages/d2b-provider-process-systemd/src/launch.rs index ead7284e8..1fd61f62a 100644 --- a/packages/d2b-provider-process-systemd/src/launch.rs +++ b/packages/d2b-provider-process-systemd/src/launch.rs @@ -5,6 +5,11 @@ use d2b_process_conformance::{LaunchTicket, ProcessConformanceError}; use crate::PROVIDER_NAME; /// Validate the provider binding before a transient unit effect is queued. +/// +/// # Errors +/// +/// Returns [`ProcessConformanceError::ProviderMismatch`] when the ticket +/// selects a different Process Provider than `system-systemd`. pub fn validate_launch_ticket(ticket: &LaunchTicket) -> Result<(), ProcessConformanceError> { if ticket.selected_provider().as_str() == PROVIDER_NAME && ticket.provider_ref().to_canonical_string() == "Provider/system-systemd" diff --git a/packages/d2b-provider-process-systemd/src/lifecycle.rs b/packages/d2b-provider-process-systemd/src/lifecycle.rs index 2ba914d5a..c0f023e6d 100644 --- a/packages/d2b-provider-process-systemd/src/lifecycle.rs +++ b/packages/d2b-provider-process-systemd/src/lifecycle.rs @@ -30,6 +30,13 @@ impl Default for SystemdProviderConfig { impl SystemdProviderConfig { /// Construct a validated Provider config. + /// + /// # Errors + /// + /// Returns [`SystemdConfigError::OutOfRange`] when any field exceeds + /// its fixed bound: `launch_timeout_sec` must be in `1..=3600`, + /// `termination_grace_sec` at most 3600, `user_manager_check_timeout` + /// in `1..=60`, and `max_concurrent_launches` in `1..=256`. pub fn new( launch_timeout_sec: u32, termination_grace_sec: u32, diff --git a/packages/d2b-provider-process-systemd/src/sandbox.rs b/packages/d2b-provider-process-systemd/src/sandbox.rs index 1e0a865cb..01bf8dfdf 100644 --- a/packages/d2b-provider-process-systemd/src/sandbox.rs +++ b/packages/d2b-provider-process-systemd/src/sandbox.rs @@ -11,6 +11,12 @@ pub struct SystemdSandboxCompiler { impl SystemdSandboxCompiler { /// Compile a public SandboxSpec without constructing a unit fragment. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::SandboxRejected`] when the spec + /// starts as root in a user domain or its canonical JSON rendering + /// fails. pub fn compile( &self, spec: &SandboxSpec, From 20e8286f8755ebb9316daec52bbf7f7fa7079d2a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:15:51 -0700 Subject: [PATCH 071/726] refactor(d2b-provider-credential-secret-service: fixthe owner variant spelling --- .../src/lib.rs | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-credential-secret-service/src/lib.rs b/packages/d2b-provider-credential-secret-service/src/lib.rs index fe62e1088..ef385d201 100644 --- a/packages/d2b-provider-credential-secret-service/src/lib.rs +++ b/packages/d2b-provider-credential-secret-service/src/lib.rs @@ -443,7 +443,7 @@ pub type SecretServiceFuture<'a, T> = #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SecretServiceOwner { /// The authenticated user-domain process. - Userd, + User, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -520,6 +520,12 @@ pub struct SecretServiceConfig { impl SecretServiceConfig { /// Validate configuration. Collection aliases may contain spaces but not /// controls, quotes, or backslashes. + /// + /// # Errors + /// + /// Returns [`SecretServiceProviderError::InvalidConfig`] when the alias + /// is empty, longer than the fixed bound, or contains a control, quote, + /// or backslash, or when the lease limit is outside `1..=MAX_LOCAL_LEASES`. pub fn new( collection_alias: impl Into, max_leases: u32, @@ -607,6 +613,13 @@ pub struct SecretServicePlacement { impl SecretServicePlacement { /// Validate user-agent placement on a Host or Guest execution context. + /// + /// # Errors + /// + /// Returns [`SecretServiceProviderError::InvalidPlacement`] when the + /// binding is not user-agent and + /// [`SecretServiceProviderError::InvalidScope`] when the execution + /// reference is not a Host or Guest or the user reference is not a User. pub fn new( zone: ZoneId, binding: PlacementBinding, @@ -629,6 +642,13 @@ impl SecretServicePlacement { } /// Validate dynamic user placement for a shared Provider controller. + /// + /// # Errors + /// + /// Returns [`SecretServiceProviderError::InvalidPlacement`] when the + /// binding is not user-agent and + /// [`SecretServiceProviderError::InvalidScope`] when the execution + /// reference is not a Host or Guest. pub fn new_dynamic( zone: ZoneId, binding: PlacementBinding, @@ -1137,6 +1157,13 @@ pub struct SecretServiceCredentialProviderFactory { impl SecretServiceCredentialProviderFactory { /// Build a factory. A present consumer must be a Provider reference; /// absence selects this Provider's canonical reference. + /// + /// # Errors + /// + /// Returns [`SecretServiceProviderError::InvalidConsumer`] when the + /// consumer is not a Provider reference and + /// [`SecretServiceProviderError::InvalidScope`] when the initial + /// generation cannot be allocated. pub fn new( config: SecretServiceConfig, placement: SecretServicePlacement, @@ -1168,6 +1195,11 @@ impl SecretServiceCredentialProviderFactory { } /// Construct the service Provider. + /// + /// # Errors + /// + /// Returns [`SecretServiceProviderError::AuthorityUnavailable`] when the + /// provider-owned session authority cannot allocate an identity. pub fn construct(self) -> Result { Ok(SecretServiceCredentialProvider { config: self.config, @@ -1230,7 +1262,7 @@ pub struct SecretServiceCredentialProvider { impl SecretServiceCredentialProvider { /// Return the fixed owner classification. pub const fn owner(&self) -> SecretServiceOwner { - SecretServiceOwner::Userd + SecretServiceOwner::User } /// Borrow the exact consumer expected by authenticated admission. From c6aa0e3d658e94153724f0f6a89bb4345e18ccc6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:15:52 -0700 Subject: [PATCH 072/726] refactor(d2b-provider-credential-secret-service: name the session-close revoke deadline --- .../src/service.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-credential-secret-service/src/service.rs b/packages/d2b-provider-credential-secret-service/src/service.rs index 42d42ebf6..68bc363a7 100644 --- a/packages/d2b-provider-credential-secret-service/src/service.rs +++ b/packages/d2b-provider-credential-secret-service/src/service.rs @@ -16,6 +16,10 @@ use crate::{ SecretServicePortError, SessionKey, invariant, }; +/// One-second cap on revoking a session's leases during disconnect, finalize, +/// and drain, so a stalled backend cannot hang session teardown forever. +const SESSION_CLOSE_REVOKE_DEADLINE_MS: u64 = 1_000; + #[async_trait::async_trait] impl CredentialProvider for SecretServiceCredentialProvider { fn dispatch( @@ -657,7 +661,7 @@ impl SecretServiceCredentialProvider { self.discard_session_key(session_key)?; return Ok(()); } - let deadline = operation_deadline(1_000)?; + let deadline = operation_deadline(SESSION_CLOSE_REVOKE_DEADLINE_MS)?; self.close_session_locked(session_key, deadline) } @@ -671,17 +675,23 @@ impl SecretServiceCredentialProvider { self.session_capability(authorization)?; self.finalized .store(true, std::sync::atomic::Ordering::Release); - self.close_all_sessions_locked(operation_deadline(1_000)?)?; + self.close_all_sessions_locked(operation_deadline(SESSION_CLOSE_REVOKE_DEADLINE_MS)?)?; self.authority.clear().map_err(|_| invariant())?; Ok(()) } /// Finalize every admitted session and prevent later capability minting. + /// + /// # Errors + /// + /// Returns [`CredentialServiceError`] when a lease revocation fails or + /// exceeds the session-close deadline, or when the session authority + /// cannot be cleared. pub fn drain(&self) -> Result<(), CredentialServiceError> { let _mutation = self.blocking_mutation_guard(); self.finalized .store(true, std::sync::atomic::Ordering::Release); - let deadline = operation_deadline(1_000)?; + let deadline = operation_deadline(SESSION_CLOSE_REVOKE_DEADLINE_MS)?; self.close_all_sessions_locked(deadline)?; self.authority.clear().map_err(|_| invariant())?; Ok(()) From d5869f583a88165435282f818ad4034dba3707df Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:15:52 -0700 Subject: [PATCH 073/726] docs(d2b-provider-credential-secret-service: document error conditions on public APIs --- .../d2b-provider-credential-secret-service/src/controller.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/d2b-provider-credential-secret-service/src/controller.rs b/packages/d2b-provider-credential-secret-service/src/controller.rs index 8ede32da0..30ea0c38a 100644 --- a/packages/d2b-provider-credential-secret-service/src/controller.rs +++ b/packages/d2b-provider-credential-secret-service/src/controller.rs @@ -70,6 +70,11 @@ impl SecretServiceController { } /// Project current lease metadata and port state without credential bytes. + /// + /// # Errors + /// + /// Returns [`CredentialServiceError`] when the lease or status projection + /// cannot be constructed from the supplied metadata. pub fn reconcile( &self, state: SecretServiceState, From 4d49437dbdf006b0b7bab8246ea3193e2e08d544 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:16:33 -0700 Subject: [PATCH 074/726] seccomp-profile: dedent impl braces and document constructor errors --- .../src/seccomp_profile.rs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs b/packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs index 8d35c98e8..cdc472bde 100644 --- a/packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs +++ b/packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs @@ -28,6 +28,12 @@ pub struct DeviceNodePath(String); impl DeviceNodePath { /// Parse an absolute device path with no control characters. + /// + /// # Errors + /// + /// Returns [`SeccompProfileContractError::InvalidDevicePath`] when the + /// path does not start with `/dev/`, exceeds the byte bound, or + /// carries a NUL or control character. pub fn parse(value: impl Into) -> Result { let value = value.into(); if !value.starts_with("/dev/") @@ -39,8 +45,7 @@ impl DeviceNodePath { } Ok(Self(value)) } - - } +} redacted_debug!(DeviceNodePath); @@ -158,8 +163,7 @@ impl DeviceBind { access, } } - - } +} /// The `SeccompProfile` desired spec. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -173,6 +177,13 @@ pub struct SeccompProfileSpec { impl SeccompProfileSpec { /// Construct a profile spec after checking the list bounds. + /// + /// # Errors + /// + /// Returns [`SeccompProfileContractError::TooManySyscalls`] when the + /// allowlist exceeds the syscall bound and + /// [`SeccompProfileContractError::TooManyDeviceBinds`] when the + /// profile declares more device binds than the bound. pub fn new( syscalls: Vec, namespaces: SeccompNamespaces, @@ -192,8 +203,7 @@ impl SeccompProfileSpec { devices, }) } - - } +} redacted_debug!(SeccompProfileSpec); From f3da9fd3159db05db210a34523c717f6ede7e2e8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:16:49 -0700 Subject: [PATCH 075/726] refactor(core): borrow intent parsing, flatten plan-op loop, document manifest --- packages/d2b-core/src/bundle_resolver.rs | 92 ++++++++++++---------- packages/d2b-core/src/manifest_v04.rs | 34 ++++++++ packages/d2b-core/src/static_invariants.rs | 10 ++- 3 files changed, 89 insertions(+), 47 deletions(-) diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 361e4e028..9c18d7357 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -69,7 +69,7 @@ use crate::error::Error; use crate::host::{ ChNetHandoffMode, HostJson, HostsFileOwnership, ModuleRequirement, NetEnv, NetworkManagerUnmanaged, NftablesModel, OwnershipRule, QemuMediaSourceIntent, SitePolicy, - TapRole, UsbipBusidLock, VendorProductPair, + UsbipBusidLock, VendorProductPair, }; use crate::host_w3::{ModuleRequirementW3, TapRoleW3}; use crate::manifest_v04::ManifestV04; @@ -1626,7 +1626,7 @@ impl BundleResolver { self.zone_resource_bundles .keys() .map(|zone| { - d2b_contracts_resource::v3::ZoneId::parse(zone.clone()) + d2b_contracts_resource::v3::ZoneId::parse(zone.as_str()) .map_err(|_| "bundle Zone resource bundle index invalid") }) .collect() @@ -1781,7 +1781,7 @@ impl BundleResolver { { return None; } - let spec = self.find_network_spec(&parts)?; + self.find_network_spec(&parts)?; let uplink = derive_network_ifname( provenance.zone_uid(), provenance.network_uid(), @@ -1802,7 +1802,6 @@ impl BundleResolver { "table inet d2b {{\n chain \"{chain}\" {{ comment \"d2b managed: {marker}\";\n ct state established,related accept comment \"d2b managed: {marker}\";\n iifname \"{}\" ct state new accept comment \"d2b managed: {marker}\";\n }}\n}}\n", uplink.as_str() ); - let _ = spec; Some(ResolvedNftablesProjectionIntent { intent_id: id.to_owned(), scope_label: network_scope(provenance), @@ -1889,7 +1888,7 @@ impl BundleResolver { { return None; } - let spec = self.find_network_spec(&parts)?; + self.find_network_spec(&parts)?; let role = match parts.variant.as_deref() { Some("lan") => NetworkIfRole::LanBridge, Some("uplink") => NetworkIfRole::UplinkBridge, @@ -1908,7 +1907,6 @@ impl BundleResolver { provenance, &format!("sysctl:{key}"), ); - let _ = spec; Some(ResolvedSysctlIntent { intent_id: id.to_owned(), key: format!( @@ -1970,8 +1968,11 @@ impl BundleResolver { .annotations() .get("networkUid") .is_none_or(|value| { - d2b_contracts_resource::v3::ResourceUid::parse(value.clone()).ok() - == Some(parts.network_uid.clone()) + d2b_contracts_resource::v3::ResourceUid::parse(value.as_str()) + .ok() + .as_ref() + .map(d2b_contracts_resource::v3::ResourceUid::as_str) + == Some(parts.network_uid.as_str()) }) })?; let mut value = serde_json::to_value(resource.spec()).ok()?; @@ -2431,31 +2432,27 @@ impl BundleResolver { let Some(vm) = self.find_process_vm(vm_id) else { return Vec::new(); }; - let mut ops = Vec::new(); - for node in &vm.nodes { - for plan_op in &node.plan_ops { - match plan_op { - SpawnRunnerPlanOp::DiskInit { - target_path, - size_bytes, - mode, - owner_uid, - owner_gid, - if_absent, - } => { - ops.push(ResolvedDiskInitOp { - target_path: target_path.clone(), - size_bytes: *size_bytes, - mode: *mode, - owner_uid: *owner_uid, - owner_gid: *owner_gid, - if_absent: *if_absent, - }); - } - } - } - } - ops + vm.nodes + .iter() + .flat_map(|node| &node.plan_ops) + .filter_map(|plan_op| match plan_op { + SpawnRunnerPlanOp::DiskInit { + target_path, + size_bytes, + mode, + owner_uid, + owner_gid, + if_absent, + } => Some(ResolvedDiskInitOp { + target_path: target_path.clone(), + size_bytes: *size_bytes, + mode: *mode, + owner_uid: *owner_uid, + owner_gid: *owner_gid, + if_absent: *if_absent, + }), + }) + .collect() } pub fn resolve_vm_start_intent( @@ -2914,11 +2911,13 @@ fn role_device_classes( // --------------------------------------------------------------- +/// Build the store-view plan `BundleOpId` (`store-view:zone::vm:`). pub fn intent_id_store_view(zone: &ZoneId, vm: &str) -> String { format!("store-view:zone:{}:vm:{vm}", zone.as_str()) } +/// Build the VM start `BundleOpId` (`vm-start:vm::role:`). pub fn intent_id_vm_start(vm: &str, role_id: &str) -> String { format!("vm-start:vm:{vm}:role:{role_id}") } @@ -2928,14 +2927,17 @@ pub fn intent_id_vm_start(vm: &str, role_id: &str) -> String { // Intent ID format helpers (deterministic, public). // --------------------------------------------------------------- +/// Build the whole-host nftables `BundleOpId` (`nft:host`). pub fn intent_id_nft_host() -> String { "nft:host".to_owned() } +/// Build the per-environment nftables `BundleOpId` (`nft:env:`). pub fn intent_id_nft_env(env: &str) -> String { format!("nft:env:{env}") } +/// Build the network-projection nftables `BundleOpId` (`nft-projection:env:`). pub fn intent_id_nft_projection_env(env: &str) -> String { format!("nft-projection:env:{env}") } @@ -3103,34 +3105,42 @@ pub fn network_name_token(network_name: &str) -> String { .to_owned() } +/// Build the ownership-marker `BundleOpId` (`ownership-marker:env:`). pub fn intent_id_ownership_marker_env(env: &str) -> String { format!("ownership-marker:env:{env}") } +/// Build the bridge `BundleOpId` (`bridge:env:`). pub fn intent_id_bridge_env(env: &str) -> String { format!("bridge:env:{env}") } +/// Build the route `BundleOpId` (`route:env::`). pub fn intent_id_route_env(env: &str, idx: usize) -> String { format!("route:env:{env}:{idx}") } +/// Build the sysctl `BundleOpId` (`sysctl:env::if::`). pub fn intent_id_sysctl(env: &str, if_name: &str, key: &str) -> String { format!("sysctl:env:{env}:if:{if_name}:{key}") } +/// Build the whole-host hosts-file `BundleOpId` (`hosts:host`). pub fn intent_id_hosts_host() -> String { "hosts:host".to_owned() } +/// Build the whole-host NM-unmanaged `BundleOpId` (`nm-unmanaged:host`). pub fn intent_id_nm_unmanaged_host() -> String { "nm-unmanaged:host".to_owned() } +/// Build the USBIP firewall `BundleOpId` (`usbip-fw:env::bus:`). pub fn intent_id_usbip_firewall(env: &str, bus_id: &str) -> String { format!("usbip-fw:env:{env}:bus:{bus_id}") } +/// Build the USBIP bind `BundleOpId` (`usbip-bind:env::vm::bus:`). pub fn intent_id_usbip_bind(env: &str, vm: &str, bus_id: &str) -> String { format!("usbip-bind:env:{env}:vm:{vm}:bus:{bus_id}") } @@ -3214,10 +3224,12 @@ fn network_firewall_chain_name(network_uid: &d2b_contracts_resource::v3::Resourc format!("forward-{}", &compact[..8]) } +/// Build the runner `BundleOpId` (`runner:zone::vm::role:`). pub fn intent_id_runner(zone: &ZoneId, vm: &str, role_id: &str) -> String { format!("runner:zone:{}:vm:{vm}:role:{role_id}", zone.as_str()) } +/// Build the legacy compatibility runner `BundleOpId` (`runner:vm::role:`). pub fn intent_id_legacy_runner(vm: &str, role_id: &str) -> String { format!("runner:vm:{vm}:role:{role_id}") } @@ -3351,7 +3363,7 @@ fn build_resource_network_intents( .annotations() .get("networkUid") .and_then(|value| { - d2b_contracts_resource::v3::ResourceUid::parse(value.clone()).ok() + d2b_contracts_resource::v3::ResourceUid::parse(value.as_str()).ok() }) else { continue; @@ -5739,12 +5751,6 @@ fn manifest_parse_reason(err: &str) -> &'static str { } } -// Silence the "TapRole imported but unused" warning - we only need -// it transitively to refer to BridgePortFlags in the render -// helpers, which already use the type via `flag.role`. -#[allow(dead_code)] -const _ASSERT_TAPROLE: Option = None; - #[cfg(test)] mod tests { use super::*; @@ -6611,7 +6617,7 @@ mod tests { net_vm_forward_blocklist: Vec::new(), external_network: None, bridge_port_flags: vec![BridgePortFlags { - role: TapRole::Uplink, + role: crate::host::TapRole::Uplink, isolated: true, neigh_suppress: true, learning: Some(false), @@ -7905,7 +7911,7 @@ mod tests { host.environments[0].host_uplink_ip = Some("192.0.2.1".to_owned()); host.environments[0].net_uplink_ip = Some("192.0.2.2".to_owned()); host.environments[0].bridge_port_flags = vec![BridgePortFlags { - role: TapRole::Uplink, + role: crate::host::TapRole::Uplink, isolated: true, neigh_suppress: true, learning: Some(false), @@ -7955,7 +7961,7 @@ mod tests { vendor_product_allowlist: Vec::new(), }]; host.environments[0].bridge_port_flags = vec![BridgePortFlags { - role: TapRole::Uplink, + role: crate::host::TapRole::Uplink, isolated: false, neigh_suppress: true, learning: Some(false), diff --git a/packages/d2b-core/src/manifest_v04.rs b/packages/d2b-core/src/manifest_v04.rs index 54751c922..fbe793b7d 100644 --- a/packages/d2b-core/src/manifest_v04.rs +++ b/packages/d2b-core/src/manifest_v04.rs @@ -1,3 +1,11 @@ +//! Typed v0.4.0 public `vms.json` manifest. +//! +//! The manifest is the world-readable VM roster the daemon renders: a +//! reserved `_manifest` sentinel, a reserved `_observability` block, and +//! one entry per VM keyed by its name. Every type here mirrors the +//! camelCase wire shape with `deny_unknown_fields` admission, and the +//! parser accepts the current and legacy-compat manifest versions. + use crate::error::Error; use schemars::{ JsonSchema, @@ -27,6 +35,8 @@ use crate::runtime::RuntimeMetadata; pub const MANIFEST_VERSION_CURRENT: u32 = 7; pub const MANIFEST_VERSION_LEGACY_COMPAT: u32 = 6; +/// The typed public `vms.json` manifest: reserved sentinels plus one +/// [`VmEntry`] per VM keyed by its name. #[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct ManifestV04 { #[serde(rename = "_manifest")] @@ -38,6 +48,13 @@ pub struct ManifestV04 { } impl ManifestV04 { + /// Parse a manifest from its canonical compact JSON bytes. + /// + /// # Errors + /// + /// Returns a manifest parse error when the bytes are not valid JSON, + /// carry an unknown or malformed field, or declare a manifest version + /// outside the current and legacy-compat pair. pub fn from_slice(bytes: &[u8]) -> Result { let parsed: Self = serde_json::from_slice(bytes).map_err(|error| { Error::manifest_parse_error("vms.json", manifest_parse_reason(&error.to_string())) @@ -64,6 +81,12 @@ impl ManifestV04 { Self::from_slice(&bytes) } + /// Render the manifest as compact JSON with a trailing newline. + /// + /// # Errors + /// + /// Returns a serialize-failed parse error when the manifest cannot be + /// rendered (a state the typed fields make unreachable in practice). pub fn to_compact_json(&self) -> Result { let mut rendered = serde_json::to_string(self) .map_err(|_| Error::manifest_parse_error("vms.json", "serialize-failed"))?; @@ -153,6 +176,7 @@ impl JsonSchema for ManifestV04 { } } +/// The reserved `_manifest` sentinel: the schema version of the file. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ManifestMeta { @@ -192,6 +216,7 @@ impl JsonSchema for ManifestMeta { } } +/// The reserved `_observability` block: host-wide telemetry wiring. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ObservabilityMeta { @@ -204,6 +229,7 @@ pub struct ObservabilityMeta { pub vm_name: String, } +/// One VM's public roster entry, keyed by its name in the manifest. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmEntry { @@ -253,6 +279,7 @@ fn default_autostart() -> bool { true } +/// Per-VM lifecycle policy: graceful shutdown and live activation. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmLifecycle { @@ -261,6 +288,7 @@ pub struct VmLifecycle { pub live_activation: VmLiveActivation, } +/// Graceful-shutdown policy for one VM. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmGracefulShutdown { @@ -268,6 +296,7 @@ pub struct VmGracefulShutdown { pub timeout_seconds: Option, } +/// Live-activation policy for one VM. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmLiveActivation { @@ -283,6 +312,8 @@ impl Default for VmGracefulShutdown { } } +/// LAN policy for one VM: east-west traffic allowance and its effective +/// value after host-wide policy is applied. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmLanPolicy { @@ -290,6 +321,7 @@ pub struct VmLanPolicy { pub effective_east_west: bool, } +/// Per-VM observability wiring: agent socket and vsock transport. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmObservability { @@ -299,6 +331,7 @@ pub struct VmObservability { pub vsock_host_socket: Option, } +/// Shell-session metadata for one VM. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmShellMetadata { @@ -308,6 +341,7 @@ pub struct VmShellMetadata { pub max_sessions: u32, } +/// A validated shell name (`^[A-Za-z0-9_][A-Za-z0-9._-]{0,63}$`). #[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[serde(transparent)] pub struct ManifestShellName(pub String); diff --git a/packages/d2b-core/src/static_invariants.rs b/packages/d2b-core/src/static_invariants.rs index 7faf51557..48b93082f 100644 --- a/packages/d2b-core/src/static_invariants.rs +++ b/packages/d2b-core/src/static_invariants.rs @@ -11,6 +11,8 @@ //! invariant holds), so callers (contract tests, and potentially the broker) //! can assert and report precisely. +use std::borrow::Cow; + use serde_json::Value; /// Linux capabilities considered "broad" - granting one to a long-lived @@ -159,7 +161,7 @@ pub fn world_readable_field_leaks(manifest: &Value) -> Vec { let mut leaks = Vec::new(); for (path, _) in scalar_paths(manifest) { let Some(last) = path.last() else { continue }; - if PUBLIC_MANIFEST_FIELDS.iter().any(|f| f == last) { + if PUBLIC_MANIFEST_FIELDS.contains(&last.as_str()) { continue; } let dotted = path.join("."); @@ -198,8 +200,8 @@ pub fn path_bearing_key_violations(manifest: &Value) -> Vec { continue; } let rendered = match value { - Value::String(s) => s.clone(), - other => other.to_string(), + Value::String(s) => Cow::Borrowed(s.as_str()), + other => Cow::Owned(other.to_string()), }; if rendered.contains('/') { violations.push(format!("{}={}", path.join("."), rendered)); @@ -216,7 +218,7 @@ pub fn path_bearing_key_violations(manifest: &Value) -> Vec { pub fn is_broad_cap_violation(caps: &[String], adr_carve_out: Option<&str>) -> bool { let requests_broad = caps .iter() - .any(|cap| BROAD_CAPABILITIES.iter().any(|broad| broad == cap)); + .any(|cap| BROAD_CAPABILITIES.contains(&cap.as_str())); if !requests_broad { return false; } From ca450e9d5619556866a8a4ea2e2c05ca71f1ab15 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:17:21 -0700 Subject: [PATCH 076/726] d2b-provider-audio-binding: state the interaction seam failure contract --- .../src/audio_binding.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/d2b-provider-audio-binding/src/audio_binding.rs b/packages/d2b-provider-audio-binding/src/audio_binding.rs index 3f4003a96..4c90cc6e8 100644 --- a/packages/d2b-provider-audio-binding/src/audio_binding.rs +++ b/packages/d2b-provider-audio-binding/src/audio_binding.rs @@ -53,6 +53,12 @@ pub struct AudioBindingChildRequest<'a> { /// [`AudioBinding::new`]. pub trait AudioBindingChildSource: Send + Sync + 'static { /// The Process and Endpoint intents one binding owns. + /// + /// # Errors + /// + /// Returns `Unavailable` when the child source is not currently + /// available and should retry, and `InvalidResource` when the binding + /// spec fails closed into children. fn binding_children( &self, request: &AudioBindingChildRequest<'_>, @@ -114,6 +120,11 @@ impl InteractionType for AudioBinding { } /// The binding spec decodes with its typed `providerRef` re-inserted. + /// + /// # Errors + /// + /// Returns `InvalidResource` when the envelope does not decode as an + /// `AudioBindingSpec`. fn validate( &self, envelope: &InteractionSpecEnvelope, @@ -122,6 +133,11 @@ impl InteractionType for AudioBinding { } /// The service the binding realizes from and the target it attaches to. + /// + /// # Errors + /// + /// Returns `InvalidResource` when the envelope does not decode as an + /// `AudioBindingSpec`. fn dependencies( &self, envelope: &InteractionSpecEnvelope, @@ -131,6 +147,13 @@ impl InteractionType for AudioBinding { } /// The binding's worker and endpoint children, as manager child rows. + /// + /// # Errors + /// + /// Returns `Unavailable` when the child source is not currently + /// available and should retry, and `InvalidResource` when the + /// envelope does not decode as an `AudioBindingSpec` or the binding + /// fails closed into children. fn desired_children( &self, children: &InteractionChildContext<'_>, From fc6c6e7da6c2f625cf34ac013d24b6588570530f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:17:21 -0700 Subject: [PATCH 077/726] d2b-provider-audio-pipewire: document the state lock and name the queue bound --- .../src/controller.rs | 16 +++++++++++++--- packages/d2b-provider-audio-pipewire/src/lib.rs | 2 +- .../d2b-provider-audio-pipewire/src/state.rs | 5 +++++ .../tests/controller.rs | 10 +++++----- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/packages/d2b-provider-audio-pipewire/src/controller.rs b/packages/d2b-provider-audio-pipewire/src/controller.rs index 7126c07a6..7d9e06f3d 100644 --- a/packages/d2b-provider-audio-pipewire/src/controller.rs +++ b/packages/d2b-provider-audio-pipewire/src/controller.rs @@ -18,8 +18,18 @@ use tracing::{debug, warn}; const AUDIO_PROVIDER_REF: &str = "Provider/audio-pipewire"; /// Default shared-Runner repair interval for audio resources. +/// +/// 300 seconds (5 minutes) bounds how long a failed audio worker can +/// stay unrepaired before the next resync re-runs the repair path, +/// while keeping the resync cadence well below the daemon's +/// operator-visible stall threshold. pub const AUDIO_REPAIR_INTERVAL_SECS: u64 = 300; +/// The arbiter and mixer admission bound: how many pending microphone +/// leases or speaker consumers one controller admits before refusing +/// further admission. +pub const AUDIO_QUEUE_BOUND: usize = 64; + const AUDIO_BINDING_CHILD_REQUESTS: [BindingChildRequest; 4] = [ BindingChildRequest::process( BindingChildKind::Process, @@ -206,10 +216,10 @@ impl AudioBindingController { pub fn new(mediator: M) -> Self { Self { mediator, - microphone: crate::shared_microphone_arbiter(64), + microphone: crate::shared_microphone_arbiter(AUDIO_QUEUE_BOUND), activate_promoted: true, microphone_effect_applied: false, - speaker: SpeakerMixer::new(64), + speaker: SpeakerMixer::new(AUDIO_QUEUE_BOUND), } } @@ -220,7 +230,7 @@ impl AudioBindingController { microphone, activate_promoted: false, microphone_effect_applied: false, - speaker: SpeakerMixer::new(64), + speaker: SpeakerMixer::new(AUDIO_QUEUE_BOUND), } } diff --git a/packages/d2b-provider-audio-pipewire/src/lib.rs b/packages/d2b-provider-audio-pipewire/src/lib.rs index a09c9cd39..4aa9dac81 100644 --- a/packages/d2b-provider-audio-pipewire/src/lib.rs +++ b/packages/d2b-provider-audio-pipewire/src/lib.rs @@ -29,7 +29,7 @@ pub use controller::{ AudioArbitrationState, AudioBindingChannels, AudioBindingController, AudioBindingPhase, AudioBindingStatus, AudioControllerError, AudioEnforcementPosture, AudioLastSetApplied, AudioMicrophoneStatus, AudioReconcileResult, AudioReconcileResultWithChildren, - AudioSpeakerStatus, AUDIO_REPAIR_INTERVAL_SECS, register_service, + AudioSpeakerStatus, AUDIO_QUEUE_BOUND, AUDIO_REPAIR_INTERVAL_SECS, register_service, }; pub use mediator::{ AudioChannel, AudioMediator, AudioMediatorError, AudioReadiness, FakeAudioMediator, diff --git a/packages/d2b-provider-audio-pipewire/src/state.rs b/packages/d2b-provider-audio-pipewire/src/state.rs index a75adda41..56f3eef8e 100644 --- a/packages/d2b-provider-audio-pipewire/src/state.rs +++ b/packages/d2b-provider-audio-pipewire/src/state.rs @@ -78,6 +78,11 @@ impl Drop for OfdLockGuard { } } +/// One held open-file-description lock on the audio state file. +/// +/// Holding the value keeps the OFD lock acquired by +/// [`acquire_audio_state_lock`]; dropping it releases the lock and +/// closes the file. pub struct AudioStateLock { _guard: OfdLockGuard, _file: File, diff --git a/packages/d2b-provider-audio-pipewire/tests/controller.rs b/packages/d2b-provider-audio-pipewire/tests/controller.rs index 5608ed8bc..f962412a2 100644 --- a/packages/d2b-provider-audio-pipewire/tests/controller.rs +++ b/packages/d2b-provider-audio-pipewire/tests/controller.rs @@ -1,9 +1,9 @@ use d2b_contracts_resource::v3::{ExecutionDomain, ResourceRef}; use d2b_provider_audio_pipewire::{ AudioArbitrationState, AudioBindingController, AudioBindingPhase, AudioChannel, AudioGrant, - AudioLeaseId, AudioMediator, AudioMediatorError, AudioReadiness, FakeAudioMediator, - GuestAudioReadiness, HostAudioReadiness, LevelPercent, shared_microphone_arbiter, - validate_audio_binding, + AudioLeaseId, AudioMediator, AudioMediatorError, AudioReadiness, AUDIO_QUEUE_BOUND, + FakeAudioMediator, GuestAudioReadiness, HostAudioReadiness, LevelPercent, + shared_microphone_arbiter, validate_audio_binding, }; #[derive(Debug)] @@ -303,7 +303,7 @@ fn speaker_admission_rejects_before_mutating_mediator() { let mut requested = binding(); requested.grants.speaker_level = Some(d2b_provider_audio_pipewire::LevelPercent::new(25).expect("bounded test level")); - for lease in 1..=64 { + for lease in 1..=AUDIO_QUEUE_BOUND as u64 { controller .reconcile(&requested, "zone-a", AudioLeaseId::new(lease)) .unwrap(); @@ -311,7 +311,7 @@ fn speaker_admission_rejects_before_mutating_mediator() { let last_level = controller.mediator().level(); assert_eq!( controller - .reconcile(&requested, "zone-a", AudioLeaseId::new(65)) + .reconcile(&requested, "zone-a", AudioLeaseId::new(AUDIO_QUEUE_BOUND as u64 + 1)) .unwrap_err(), d2b_provider_audio_pipewire::AudioControllerError::Admission ); From 7338e4b5c20ff9df41fd0ba86b0b0eb20e9a00c9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:17:28 -0700 Subject: [PATCH 078/726] contracts-broker: align the root role audit label and document handoff errors --- .../d2b-contracts-broker/src/broker_wire.rs | 45 ++++++++++++------ .../src/host_generation.rs | 46 ++++++++++++++++--- .../d2b-contracts-broker/src/kernel_client.rs | 12 ++++- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 4a52b2d81..51f7e3792 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -243,21 +243,21 @@ pub const FD_LEG: &str = "fd-leg"; /// refused with [`FD_LEG`], never delivered as a transport truncation. pub const MAX_FRAME_FDS: usize = 8; -/// The kernel kind one forwarded descriptor must present.from +/// The kernel kind one forwarded descriptor must present. From /// -/// The kind is declared per descriptor on the wire,index-aligned with the -/// fd-index declarations,and validated against the received descriptor's -/// fstat mode on the receiving leg;a mismatch is the [`FD_LEG`] refusal。 +/// The kind is declared per descriptor on the wire, index-aligned with the +/// fd-index declarations, and validated against the received descriptor's +/// fstat mode on the receiving leg; a mismatch is the [`FD_LEG`] refusal. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] pub enum FdKind { - /// A FIFO (pipe) end。 + /// A FIFO (pipe) end. Fifo, - /// A socket。 + /// A socket. Socket, - /// A character device。 + /// A character device. CharDevice, - /// A block device。 + /// A block device. BlockDevice, /// Any descriptor kind. /// @@ -268,9 +268,9 @@ pub enum FdKind { /// fstat kind - including anon-inodes such as pidfds, whose /// fstat mode carries no file type (U10 fd leg). Any, - /// A regular file。 + /// A regular file. Regular, - /// A directory。 + /// A directory. Directory, } @@ -418,13 +418,13 @@ pub struct ForwardOperationRequest { /// rather than a second root record. #[serde(default, skip_serializing_if = "Option::is_none")] pub chain_identities: Option>, - /// The positions,in the frame's SCM_RIGHTS attachment list,of the + /// The positions, in the frame's SCM_RIGHTS attachment list, of the /// descriptors this request carries. Empty when the request carries none. #[serde(default)] pub fd_indexes: Vec, - /// The kernel kind each declared descriptor must present,index-aligned - /// with [`Self::fd_indexes`]。 + /// The kernel kind each declared descriptor must present, index-aligned + /// with [`Self::fd_indexes`]. #[serde(default)] pub fd_kinds: Vec, @@ -2492,6 +2492,15 @@ impl RunnerLaunchArgs { pub const MAX_TOTAL_BYTES: usize = 16 * 1024; /// Validate and construct one bounded argument vector. + /// + /// # Errors + /// + /// Returns [`RunnerLaunchArgsError::Empty`] when the vector carries no + /// arguments, [`RunnerLaunchArgsError::TooMany`] when it exceeds + /// [`RunnerLaunchArgs::MAX_ARGS`], and the per-argument variants + /// (`EmptyArgument`, `ArgumentWithNul`, `ArgumentTooLong`) or + /// [`RunnerLaunchArgsError::TotalTooLong`] when an argument or the + /// combined size exceeds the launch bounds. pub fn new(args: Vec) -> Result { if args.is_empty() { return Err(RunnerLaunchArgsError::Empty); @@ -2905,7 +2914,7 @@ impl BrokerCallerRole { match self { Self::AdminUid { .. } => "d2b-admin", Self::LauncherUid { .. } => "d2b-launcher", - Self::RootUid { .. } => "RootUid", + Self::RootUid { .. } => "d2b-root", Self::HostShutdownUid { .. } => "d2b-host-shutdown", Self::NotAuthorized => "d2b-not-authorized", } @@ -3160,6 +3169,14 @@ mod tests { BrokerCallerRole::NotAuthorized.for_display(), "d2b-not-authorized" ); + assert_eq!( + BrokerCallerRole::RootUid { uid: 0 }.for_display(), + "d2b-root" + ); + assert_eq!( + BrokerCallerRole::HostShutdownUid { uid: 0 }.for_display(), + "d2b-host-shutdown" + ); } #[test] diff --git a/packages/d2b-contracts-broker/src/host_generation.rs b/packages/d2b-contracts-broker/src/host_generation.rs index d518ce8e8..132263dd4 100644 --- a/packages/d2b-contracts-broker/src/host_generation.rs +++ b/packages/d2b-contracts-broker/src/host_generation.rs @@ -44,6 +44,11 @@ pub struct SourceGenerationCompatibilityFloorV1 { impl SourceGenerationCompatibilityFloorV1 { /// Construct a non-empty compatibility floor. + /// + /// # Errors + /// + /// Returns [`HandoffError::CompatibilityFloorInvalid`] when the + /// generation is zero or the fingerprint is all zeros. pub fn new( minimum_generation: u64, target_fingerprint: [u8; 32], @@ -88,6 +93,12 @@ impl SourceGenerationCompatibilityFloorV1 { } /// Begin a replay-safe handoff from source to target. + /// + /// # Errors + /// + /// Returns [`HandoffError::GenerationAncestryInvalid`] when the source + /// generation is zero, the target generation is not strictly newer than + /// the source, or the source predates the compatibility floor. pub fn begin_handoff( self, source_generation: u64, @@ -159,12 +170,6 @@ impl ApplyHostGenerationHandoff { if self.intent.system_artifact_id.as_str().contains('/') { return Err(HandoffError::TargetFingerprintMismatch); } - if !matches!( - self.caller_role, - HandoffCallerRole::Lifecycle | HandoffCallerRole::Admin - ) { - return Err(HandoffError::InvalidTransition); - } Ok(()) } } @@ -253,6 +258,15 @@ impl HandoffCoordinator { } /// Validate the authenticated target before mutation. + /// + /// # Errors + /// + /// Returns [`HandoffError::InvalidTransition`] when the coordinator is + /// not in the `Recorded` phase, [`HandoffError::TargetGenerationMismatch`] + /// when the generation is not the authenticated target generation, and + /// the floor's own errors when the generation or fingerprint fails the + /// compatibility floor. The two mismatch cases move the coordinator to + /// `Refused`. pub fn validate_target( &mut self, generation: u64, @@ -274,6 +288,11 @@ impl HandoffCoordinator { } /// Enter the mutation phase. + /// + /// # Errors + /// + /// Returns [`HandoffError::InvalidTransition`] when the coordinator is + /// not in the `Validated` phase. pub fn begin_mutation(&mut self) -> Result<(), HandoffError> { if self.state != HandoffState::Validated { return Err(HandoffError::InvalidTransition); @@ -283,6 +302,11 @@ impl HandoffCoordinator { } /// Transfer the durable coordinator to the target broker. + /// + /// # Errors + /// + /// Returns [`HandoffError::InvalidTransition`] when the coordinator is + /// not in the `Mutating` phase. pub fn transfer(&mut self) -> Result<(), HandoffError> { if self.state != HandoffState::Mutating { return Err(HandoffError::InvalidTransition); @@ -292,6 +316,11 @@ impl HandoffCoordinator { } /// Complete the target and retire the source. + /// + /// # Errors + /// + /// Returns [`HandoffError::InvalidTransition`] when the coordinator is + /// not in the `Transferred` phase. pub fn complete(&mut self) -> Result<(), HandoffError> { if self.state != HandoffState::Transferred { return Err(HandoffError::InvalidTransition); @@ -302,6 +331,11 @@ impl HandoffCoordinator { } /// Roll back or preserve the source after a failed effect. + /// + /// # Errors + /// + /// Returns [`HandoffError::InvalidTransition`] when the coordinator is + /// already `Completed` or `RolledBack`. pub fn rollback(&mut self) -> Result<(), HandoffError> { if matches!( self.state, diff --git a/packages/d2b-contracts-broker/src/kernel_client.rs b/packages/d2b-contracts-broker/src/kernel_client.rs index e1e0c86e3..38b862033 100644 --- a/packages/d2b-contracts-broker/src/kernel_client.rs +++ b/packages/d2b-contracts-broker/src/kernel_client.rs @@ -110,6 +110,14 @@ pub struct KernelReply { /// dispatched under. The reply carries the invocation id the audit record /// keys on and the descriptors the kernel minted; a refusal keeps its /// closed code and detail. +/// +/// # Errors +/// +/// Returns [`KernelInvokeError::Transport`] when any transport step (dial, +/// frame write, reply poll, frame read, or decode) fails, including a reply +/// timeout, [`KernelInvokeError::Protocol`] when the broker answers a +/// non-envelope response, and [`KernelInvokeError::Refused`] when the +/// broker refuses the invocation with its closed code and detail. pub fn envelope_invoke_kernel( socket_path: &Path, io_timeout: Duration, @@ -221,9 +229,9 @@ pub fn envelope_invoke_kernel( "unexpected response kind: {response:?}" ))); }; - if response.refusal.is_some() { + if let Some(code) = response.refusal.clone() { return Err(KernelInvokeError::Refused { - code: response.refusal.clone().unwrap_or_default(), + code, detail: response.detail.clone(), }); } From 4065c70323c157f0c159df90f938d5ed88ea224b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:18:49 -0700 Subject: [PATCH 079/726] supervisor: drop no-op pidfd reference and share the observation ledger --- .../d2b-provider-supervisor/src/broker.rs | 51 ++++----------- packages/d2b-provider-supervisor/src/lib.rs | 1 + .../src/observations.rs | 62 +++++++++++++++++++ .../d2b-provider-supervisor/src/systemd.rs | 49 ++++----------- 4 files changed, 86 insertions(+), 77 deletions(-) create mode 100644 packages/d2b-provider-supervisor/src/observations.rs diff --git a/packages/d2b-provider-supervisor/src/broker.rs b/packages/d2b-provider-supervisor/src/broker.rs index 544c70bca..76ae4d13e 100644 --- a/packages/d2b-provider-supervisor/src/broker.rs +++ b/packages/d2b-provider-supervisor/src/broker.rs @@ -31,9 +31,7 @@ use d2b_provider_process::{ }; use rustix::event::{PollFd, PollFlags, poll}; use sha2::{Digest, Sha256}; -use tracing::{debug, error, warn}; - -const MAX_PENDING_OBSERVATIONS: usize = 1024; +use tracing::{debug, warn}; /// Trusted-bundle launch intent resolved for one generic Process ticket. #[derive(Clone, PartialEq, Eq)] @@ -1174,48 +1172,21 @@ impl BrokerProcessBackend { } } - // Sync by construction: this ledger sits behind the sync -// `ProcessEffectBackend` trait surface, invoked only from the dedicated -// blocking workers (or sync test harnesses); the critical section is short -// and never held across a suspension point. -#[allow(clippy::disallowed_methods, reason = "synchronous path")] -fn record(&self, observed: BrokerObservedProcess) -> Result<(), ProcessEffectError> { - let mut observations = self.observations.lock().map_err(|_| { - error!( - provider = "supervisor", - "broker observation ledger lock poisoned; observe failed" - ); - ProcessEffectError::ObserveFailed - })?; - let identity = observed.digest(); - if observations.len() >= MAX_PENDING_OBSERVATIONS - && !observations.contains_key(&identity) - && let Some(candidate) = observations.keys().next().copied() - { - observations.remove(&candidate); - } - observations.insert(identity, observed); - Ok(()) +// Sync by construction:the ledger sits behind the sync trait surface;the + // shared helper's critical section is short and never held across a suspension + // point. + fn record(&self, observed: BrokerObservedProcess) -> Result<(), ProcessEffectError> { + crate::observations::record(&self.observations, observed.digest(), observed) } // Sync by construction: backend ledger behind the sync trait surface (see -// `record`); critical section short, no suspension inside the guard. -#[allow(clippy::disallowed_methods, reason = "synchronous path")] -fn take_observation( + // `record`); critical section short, no suspension inside the guard. + + fn take_observation( &self, identity: &ProcessIdentityDigest, ) -> Result { - self.observations - .lock() - .map_err(|_| { - error!( - provider = "supervisor", - "broker observation ledger lock poisoned; observation lookup failed" - ); - ProcessEffectError::ObserveFailed - })? - .remove(identity) - .ok_or(ProcessEffectError::IdentityChanged) + crate::observations::take(&self.observations, identity) } pub(crate) fn matches_peer_process( @@ -1868,6 +1839,8 @@ mod tests { use d2b_core::processes::ProcessRole; + use crate::observations::MAX_PENDING_OBSERVATIONS; + use super::*; struct Resolver; diff --git a/packages/d2b-provider-supervisor/src/lib.rs b/packages/d2b-provider-supervisor/src/lib.rs index db0705834..d8faec9ce 100644 --- a/packages/d2b-provider-supervisor/src/lib.rs +++ b/packages/d2b-provider-supervisor/src/lib.rs @@ -9,6 +9,7 @@ mod adapter; mod broker; +mod observations; mod systemd; pub use adapter::{DEFAULT_BLOCKING_LIMIT, ProviderSupervisor}; diff --git a/packages/d2b-provider-supervisor/src/observations.rs b/packages/d2b-provider-supervisor/src/observations.rs new file mode 100644 index 000000000..e22389cd4 --- /dev/null +++ b/packages/d2b-provider-supervisor/src/observations.rs @@ -0,0 +1,62 @@ +//! Bounded pending-observation ledger shared by the process backends. + +use std::collections::BTreeMap; +use std::sync::Mutex; + +use d2b_provider_process::{ProcessEffectError, ProcessIdentityDigest}; +use tracing::error; + +/// Upper bound on pending observations retained per backend. +pub(crate) const MAX_PENDING_OBSERVATIONS: usize = 1024; + +/// Insert one pending observation, evicting the oldest entry when the ledger +/// is at its bound and the identity is new. +/// +/// Sync by construction: the ledger sits behind the sync +/// `ProcessEffectBackend` trait surface, invoked only from the dedicated +/// blocking workers (or sync test harnesses); the critical section is short +/// and never held across a suspension point. +#[allow(clippy::disallowed_methods, reason = "synchronous path")] +pub(crate) fn record( + observations: &Mutex>, + identity: ProcessIdentityDigest, + observed: V, +) -> Result<(), ProcessEffectError> { + let mut observations = observations.lock().map_err(|_| { + error!( + provider = "supervisor", + "observation ledger lock poisoned; observe failed" + ); + ProcessEffectError::ObserveFailed + })?; + if observations.len() >= MAX_PENDING_OBSERVATIONS + && !observations.contains_key(&identity) + && let Some(oldest) = observations.keys().next().copied() + { + observations.remove(&oldest); + } + observations.insert(identity, observed); + Ok(()) +} + +/// Take one pending observation out of the ledger. +/// +/// Sync by construction: backend ledger behind the sync trait surface (see +/// `record`); critical section short, no suspension inside the guard. +#[allow(clippy::disallowed_methods, reason = "synchronous path")] +pub(crate) fn take( + observations: &Mutex>, + identity: &ProcessIdentityDigest, +) -> Result { + observations + .lock() + .map_err(|_| { + error!( + provider = "supervisor", + "observation ledger lock poisoned; observation lookup failed" + ); + ProcessEffectError::ObserveFailed + })? + .remove(identity) + .ok_or(ProcessEffectError::IdentityChanged) +} \ No newline at end of file diff --git a/packages/d2b-provider-supervisor/src/systemd.rs b/packages/d2b-provider-supervisor/src/systemd.rs index 3430f91f5..1846ac2c4 100644 --- a/packages/d2b-provider-supervisor/src/systemd.rs +++ b/packages/d2b-provider-supervisor/src/systemd.rs @@ -25,8 +25,6 @@ use crate::broker::{ BrokerLaunchIntent, BrokerLaunchResolver, BundleBackedLaunchResolver, wait_pidfd_observer, }; -const MAX_PENDING_OBSERVATIONS: usize = 1024; - /// Atomic identity read from one active non-forking transient unit or scope. /// /// The effect owner must obtain the invocation identifier, cgroup identity, @@ -235,47 +233,21 @@ impl SystemdProcessBackend { } } - // Sync by construction:this ledger sits behind the sync `ProcessEffectBackend` -// trait surface, invoked only from the dedicated blocking workers (or sync -// test harnesses); critical section short, no suspension inside the guard. -#[allow(clippy::disallowed_methods, reason = "synchronous path")] -fn record(&self, identity: SystemdInvocationIdentity) -> Result<(), ProcessEffectError> { - let mut observations = self.observations.lock().map_err(|_| { - error!( - provider = "supervisor", - "systemd observation ledger lock poisoned; observe failed" - ); - ProcessEffectError::ObserveFailed - })?; - let digest = identity.digest(); - if observations.len() >= MAX_PENDING_OBSERVATIONS - && !observations.contains_key(&digest) - && let Some(oldest) = observations.keys().next().copied() - { - observations.remove(&oldest); - } - observations.insert(digest, identity); - Ok(()) + // Sync by construction:the ledger sits behind the sync trait surface;the + // shared helper's critical section is short and never held across a suspension + // point. + fn record(&self, identity: SystemdInvocationIdentity) -> Result<(), ProcessEffectError> { + crate::observations::record(&self.observations, identity.digest(), identity) } // Sync by construction: backend ledger behind the sync trait surface (see -// `record`); critical section short, no suspension inside. -#[allow(clippy::disallowed_methods, reason = "synchronous path")] -fn take_observation( + // `record`); critical section short, no suspension inside the guard. + + fn take_observation( &self, identity: &ProcessIdentityDigest, ) -> Result { - self.observations - .lock() - .map_err(|_| { - error!( - provider = "supervisor", - "systemd observation ledger lock poisoned; observation lookup failed" - ); - ProcessEffectError::ObserveFailed - })? - .remove(identity) - .ok_or(ProcessEffectError::IdentityChanged) + crate::observations::take(&self.observations, identity) } } @@ -283,6 +255,8 @@ fn take_observation( // Keep focused observation tests beside the state helpers they exercise. #[allow(clippy::items_after_test_module)] mod tests { + use crate::observations::MAX_PENDING_OBSERVATIONS; + use super::*; struct Owner; @@ -837,7 +811,6 @@ impl SystemdEffectOwner for BrokerSystemdEffectOwner { ); return Err(ProcessEffectError::StopFailed); } - let _ = &handle.pidfd; if class == ProcessStopClass::Terminate { let _ = self.take_request(&handle.identity)?; } From db396585bfd1e13dba1b58809f61602a0b6c9373 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:19:45 -0700 Subject: [PATCH 080/726] refactor(d2b-provider-device-security-key): collect dependency refs by iterator --- .../src/driver.rs | 49 ++++++++----------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/packages/d2b-provider-device-security-key/src/driver.rs b/packages/d2b-provider-device-security-key/src/driver.rs index 75131db06..cd59570f0 100644 --- a/packages/d2b-provider-device-security-key/src/driver.rs +++ b/packages/d2b-provider-device-security-key/src/driver.rs @@ -377,36 +377,29 @@ pub fn declared_dependency_refs( spec: &Value, _metadata: &Value, ) -> Vec { - let mut refs = Vec::new(); - let mut push = |reference: Option| { - if let Some(reference) = reference { - refs.push(reference); - } - }; match component { - SecurityKeyComponent::Service => { - push( - spec.pointer("/spec/provider/settings/deviceRef") - .and_then(Value::as_str) - .and_then(|value| ResourceRef::parse(value).ok()), - ); - push( - spec.pointer("/spec/provider/settings/relayEndpointRef") - .and_then(Value::as_str) - .and_then(|value| ResourceRef::parse(value).ok()), - ); - } - SecurityKeyComponent::Binding => { - push(spec_ref(spec, "/spec/serviceRef").ok()); - push( - spec.pointer("/spec/target/guestRef") - .or_else(|| spec.pointer("/spec/guestRef")) - .and_then(Value::as_str) - .and_then(|value| ResourceRef::parse(value).ok()), - ); - } + SecurityKeyComponent::Service => [ + spec.pointer("/spec/provider/settings/deviceRef") + .and_then(Value::as_str) + .and_then(|value| ResourceRef::parse(value).ok()), + spec.pointer("/spec/provider/settings/relayEndpointRef") + .and_then(Value::as_str) + .and_then(|value| ResourceRef::parse(value).ok()), + ] + .into_iter() + .flatten() + .collect(), + SecurityKeyComponent::Binding => [ + spec_ref(spec, "/spec/serviceRef").ok(), + spec.pointer("/spec/target/guestRef") + .or_else(|| spec.pointer("/spec/guestRef")) + .and_then(Value::as_str) + .and_then(|value| ResourceRef::parse(value).ok()), + ] + .into_iter() + .flatten() + .collect(), } - refs } /// One reference field of a stored spec. From e5ec67524cf0beb7ecaf18132a0cd7039627ec9c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:19:45 -0700 Subject: [PATCH 081/726] docs(d2b-provider-device-security-key): document relay surface and drop the module allow --- .../src/relay.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-device-security-key/src/relay.rs b/packages/d2b-provider-device-security-key/src/relay.rs index 20812777e..fb94bbc53 100644 --- a/packages/d2b-provider-device-security-key/src/relay.rs +++ b/packages/d2b-provider-device-security-key/src/relay.rs @@ -3,8 +3,6 @@ //! Host file descriptors, socket binding, peer credentials, and relay task //! supervision remain in the daemon effect adapter. -#![allow(missing_docs)] - use std::collections::{HashMap, HashSet}; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{Duration, Instant}; @@ -51,24 +49,33 @@ pub type CtaphidReport = [u8; CTAPHID_REPORT_SIZE]; /// Parsed CTAPHID initialization packet header. #[derive(Debug, Clone, PartialEq, Eq)] pub struct CtaphidInitPacket { + /// Channel identifier the packet is addressed to. pub cid: u32, + /// Command byte with the initialization bit set. pub cmd: u8, + /// Big-endian payload byte count. pub bcnt: u16, + /// Payload bytes carried after the header. pub data: Vec, } /// Parsed CTAPHID continuation packet header. #[derive(Debug, Clone, PartialEq, Eq)] pub struct CtaphidContPacket { + /// Channel identifier the packet is addressed to. pub cid: u32, + /// Continuation sequence number. pub seq: u8, + /// Payload bytes carried after the header. pub data: Vec, } /// Parsed CTAPHID packet (init or continuation). #[derive(Debug, Clone, PartialEq, Eq)] pub enum CtaphidPacket { + /// An initialization packet starting a new channel. Init(CtaphidInitPacket), + /// A continuation packet of an in-progress message. Cont(CtaphidContPacket), } @@ -141,6 +148,7 @@ pub struct CidTranslator { } impl CidTranslator { + /// Construct an empty translation table. pub fn new() -> Self { Self { next_host_cid: 1, @@ -206,10 +214,12 @@ impl LeaseId { Self(COUNTER.fetch_add(1, Ordering::Relaxed)) } + /// Return the raw counter value. pub fn as_u64(self) -> u64 { self.0 } + /// Construct a lease id from a raw counter value. pub const fn from_u64(value: u64) -> Self { Self(value) } @@ -222,9 +232,13 @@ pub enum LeaseState { Available, /// A ceremony is in progress for the named VM. Leased { + /// VM holding the lease. vm_id: String, + /// Unique identifier of the held lease. lease_id: LeaseId, + /// When the ceremony started. started_at: Instant, + /// How long the ceremony may hold the key before expiry. timeout: Duration, }, } From a895e8c625e91a2ed2abc12f9181907be85b2b41 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:19:45 -0700 Subject: [PATCH 082/726] docs(d2b-provider-device-security-key): document error conditions on lease and controller APIs --- .../src/controller.rs | 47 +++++++++++++++++++ .../src/lease.rs | 40 ++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/packages/d2b-provider-device-security-key/src/controller.rs b/packages/d2b-provider-device-security-key/src/controller.rs index 5ea18f45c..b27c7a26c 100644 --- a/packages/d2b-provider-device-security-key/src/controller.rs +++ b/packages/d2b-provider-device-security-key/src/controller.rs @@ -159,6 +159,11 @@ pub struct SecurityKeyController { impl SecurityKeyController { /// Construct a controller after admitting the configured session-ring /// capacity. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::RingCapacity`] when the session + /// ring capacity is outside the frozen bound. pub fn new( holder: ResourceUid, backing: PhysicalUsbBackingClaim, @@ -172,6 +177,13 @@ impl SecurityKeyController { } /// Construct a controller from one exact Core Device admission. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::RingCapacity`] when the session + /// ring capacity is outside the frozen bound and + /// [`SecurityKeyControllerError::Lease`] when the admission cannot seed + /// the lease. pub fn new_authorized( device_uid: ResourceUid, admission: SecurityKeyAdmission, @@ -206,6 +218,11 @@ impl SecurityKeyController { /// `target_ref` is the Guest execution target extracted from the Binding's /// target object. The caller must provide the authored Binding and its /// existing Service; a Service alone never creates consumer children. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::Admission`] when the target is + /// not a Guest resource or the binding child declaration fails. pub fn child_resources( binding_ref: &ResourceRef, service_ref: &ResourceRef, @@ -240,6 +257,12 @@ impl SecurityKeyController { /// Build security-key children while binding the frontend to the /// authored workload User identity. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::Admission`] when the target is + /// not a Guest resource, the user reference is not a User, or the binding + /// child declaration fails. pub fn child_resources_for_user( binding_ref: &ResourceRef, service_ref: &ResourceRef, @@ -277,6 +300,12 @@ impl SecurityKeyController { } /// Start a session through the authority-before-open sequence. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::Lease`] with the underlying + /// [`SecurityKeyLeaseError`] when the session cannot start; the + /// controller is quarantined on authorization-denied failures. pub fn acquire( &mut self, session: SecurityKeySessionId, @@ -307,6 +336,12 @@ impl SecurityKeyController { } /// Acquire a session after exact Device and holder revalidation. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::Lease`] with the underlying + /// [`SecurityKeyLeaseError`] when the session cannot start; the + /// controller is quarantined on authorization-denied failures. pub fn acquire_authorized( &mut self, session: SecurityKeySessionId, @@ -340,6 +375,12 @@ impl SecurityKeyController { /// Rebind the controller to fresh Core admission evidence after a /// completed session. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::Lease`] with + /// [`SecurityKeyLeaseError::AuthorizationDenied`] when the lease state or + /// the admission binding does not match. pub fn rebind_authorized( &mut self, device_uid: ResourceUid, @@ -359,6 +400,12 @@ impl SecurityKeyController { } /// Complete and record the active session. + /// + /// # Errors + /// + /// Returns [`SecurityKeyControllerError::Lease`] with + /// [`SecurityKeyLeaseError::InvalidTransition`] when no session is active + /// or with the underlying error when the physical backing release fails. pub fn complete( &mut self, port: &mut P, diff --git a/packages/d2b-provider-device-security-key/src/lease.rs b/packages/d2b-provider-device-security-key/src/lease.rs index 16a2ee815..6390db637 100644 --- a/packages/d2b-provider-device-security-key/src/lease.rs +++ b/packages/d2b-provider-device-security-key/src/lease.rs @@ -148,6 +148,16 @@ impl SecurityKeyLease { } /// Start a session, claiming physical authority before opening hidraw. + /// + /// # Errors + /// + /// Returns [`SecurityKeyLeaseError::SessionConflict`] when the lease + /// already holds an active or unfinished session, + /// [`SecurityKeyLeaseError::AuthorizationDenied`] when no physical + /// backing claim remains, [`SecurityKeyLeaseError::Effect`] when the + /// physical backing claim or hidraw open fails, and + /// [`SecurityKeyLeaseError::InvalidTransition`] when the authority lease + /// disappears during cleanup. pub fn acquire( &mut self, session: SecurityKeySessionId, @@ -230,6 +240,12 @@ impl SecurityKeyLease { /// Start a session after rechecking the exact Core Device and holder /// binding. The check happens before any physical claim or hidraw open. + /// + /// # Errors + /// + /// Returns [`SecurityKeyLeaseError::AuthorizationDenied`] when the + /// device or holder binding differs from the admission, and the same + /// errors as [`Self::acquire`] otherwise. pub fn acquire_authorized( &mut self, session: SecurityKeySessionId, @@ -252,6 +268,12 @@ impl SecurityKeyLease { } /// Replace consumed admission evidence with a fresh Core admission. + /// + /// # Errors + /// + /// Returns [`SecurityKeyLeaseError::AuthorizationDenied`] when the lease + /// is not in a terminal state, still holds a session or authority lease, + /// or the admission does not match the device, Zone, or Guest holder. pub fn rebind_authorized( &mut self, device_uid: ResourceUid, @@ -283,6 +305,12 @@ impl SecurityKeyLease { } /// Complete the active session and release its authority. + /// + /// # Errors + /// + /// Returns [`SecurityKeyLeaseError::InvalidTransition`] when no session + /// is active and [`SecurityKeyLeaseError::Effect`] when the physical + /// backing release fails. pub fn complete( &mut self, port: &mut P, @@ -291,6 +319,12 @@ impl SecurityKeyLease { } /// Cancel the active session and release its authority. + /// + /// # Errors + /// + /// Returns [`SecurityKeyLeaseError::InvalidTransition`] when no session + /// is active and [`SecurityKeyLeaseError::Effect`] when the physical + /// backing release fails. pub fn cancel( &mut self, port: &mut P, @@ -299,6 +333,12 @@ impl SecurityKeyLease { } /// Expire the active session and release its authority. + /// + /// # Errors + /// + /// Returns [`SecurityKeyLeaseError::InvalidTransition`] when no session + /// is active and [`SecurityKeyLeaseError::Effect`] when the physical + /// backing release fails. pub fn expire( &mut self, port: &mut P, From c89bfcbe0e892776c0d569e3eb3b9e092a8767ab Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:19:49 -0700 Subject: [PATCH 083/726] core-controller: borrow the observed map and document the readiness contracts --- packages/d2b-core-controller/src/authority.rs | 14 ++++++-------- packages/d2b-core-controller/src/controllers.rs | 9 +++++++++ packages/d2b-core-controller/src/main.rs | 9 +++++++++ packages/d2b-core-controller/src/migration.rs | 2 ++ .../d2b-core-controller/src/owner_reconcile.rs | 7 +++---- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/d2b-core-controller/src/authority.rs b/packages/d2b-core-controller/src/authority.rs index 7595878c9..5f9e9125e 100644 --- a/packages/d2b-core-controller/src/authority.rs +++ b/packages/d2b-core-controller/src/authority.rs @@ -2182,12 +2182,11 @@ impl HostGlobalAuthorityIndex { let key = request.key.clone(); let token = self.issue_token(); if let Some(entry) = self.authorities.get_mut(&key) { - if let Some(holder) = entry + if entry .holders .iter() - .find(|holder| holder.owner_proof == request.owner_proof) + .any(|holder| holder.owner_proof == request.owner_proof) { - let _ = holder; return Err(AuthorityError::DuplicateActiveReservation); } if entry.arbitration != request.arbitration { @@ -2535,12 +2534,11 @@ impl HostGlobalAuthorityIndex { let lease_limit = request.signed_max_holders; let token = self.issue_token(); if let Some(entry) = self.external_nics.get_mut(&key) { - if let Some(holder) = entry + if entry .holders .iter() - .find(|holder| holder.owner_proof == request.owner_proof) + .any(|holder| holder.owner_proof == request.owner_proof) { - let _ = holder; return Err(AuthorityError::DuplicateActiveReservation); } let signed_limit = entry.signed_max_holders.min(request.signed_max_holders); @@ -2794,16 +2792,16 @@ impl AuthorityReservation { request: AuthorityRequest, ) -> Result> { let operation_id = operation_id.into(); + let claim = AuthorityStorageClaim::Generic(request.durable_claim()); let lease = { let mut guard = index.lock().await; guard .reserve_operation_id(&operation_id) .map_err(AuthorityReservationError::Effect)?; guard - .admit_authority_inner_with_operation(request.clone(), Some(operation_id.clone())) + .admit_authority_inner_with_operation(request, Some(operation_id.clone())) .map_err(AuthorityReservationError::Effect)? }; - let claim = AuthorityStorageClaim::Generic(request.durable_claim()); let prepared = match persistence.prepare(&operation_id, &claim).await { Ok(prepared) => prepared, Err(error @ crate::authority_persistence::AuthorityPersistenceError::CommitUnknown) => { diff --git a/packages/d2b-core-controller/src/controllers.rs b/packages/d2b-core-controller/src/controllers.rs index cb7eefc67..5a15b3666 100644 --- a/packages/d2b-core-controller/src/controllers.rs +++ b/packages/d2b-core-controller/src/controllers.rs @@ -196,14 +196,23 @@ impl std::error::Error for CurrencyAggregationError {} /// Bounded status for one isolated handler. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct HandlerStatus { + /// Current handler phase. pub phase: HandlerPhase, + /// Last handler outcome. pub outcome: HandlerOutcome, + /// Generation the handler last observed. pub observed_generation: u64, + /// Queued work items. pub queued: u32, + /// Running work items. pub running: u32, + /// Revision of the last applied watch. pub last_watch_revision: u64, + /// Revision of the last durable checkpoint. pub checkpoint_revision: u64, + /// Tick of the last reconcile pass. pub last_reconciled_tick: u64, + /// Tick at which a retry becomes eligible, when one is scheduled. pub retry_after_tick: Option, } diff --git a/packages/d2b-core-controller/src/main.rs b/packages/d2b-core-controller/src/main.rs index 2310f8827..fe58517b9 100644 --- a/packages/d2b-core-controller/src/main.rs +++ b/packages/d2b-core-controller/src/main.rs @@ -31,12 +31,16 @@ pub enum StartupStage { /// Trusted Zone runtime readiness observations. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct RuntimeReadiness { + /// Whether the Zone store is ready. pub store_ready: bool, + /// Whether the resource API is ready. pub resource_api_ready: bool, + /// Whether the local bus is ready. pub local_bus_ready: bool, /// Set only after the production ResourceService/controller endpoint is /// registered on the Zone-local path. pub controller_endpoint_registered: bool, + /// Whether an authenticated system-core session exists. pub authenticated_system_core_session: bool, } @@ -45,10 +49,15 @@ pub struct RuntimeReadiness { pub struct RecoverySnapshot { /// Monotonic startup epoch issued by this CoreProcess instance. pub startup_epoch: u64, + /// Revision of the last durable checkpoint. pub checkpoint_revision: u64, + /// Revision of the active configuration. pub active_configuration_revision: u64, + /// Number of active provider leases. pub provider_lease_count: u32, + /// Number of active controller leases. pub controller_lease_count: u32, + /// Number of operations whose durability is ambiguous. pub ambiguous_operation_count: u32, /// Set only after the registered store watch has accepted its cursor. pub watch_admitted: bool, diff --git a/packages/d2b-core-controller/src/migration.rs b/packages/d2b-core-controller/src/migration.rs index 6bac2058a..4bbe7e5e9 100644 --- a/packages/d2b-core-controller/src/migration.rs +++ b/packages/d2b-core-controller/src/migration.rs @@ -51,10 +51,12 @@ impl LegacyTpmMigrationDecision { Self::from_anchored_inventory(None, vm_id, intent_ref) } + /// Whether this decision requires the broker migration path. pub const fn requires_migration(&self) -> bool { self.state_id.is_some() } + /// Whether the supplied vm/intent bindings match the sealed decision. pub fn validates_binding(&self, vm_id: &str, intent_ref: &str) -> bool { self.vm_binding == canonical_digest("d2b:tpm-vm-binding/v1", vm_id.as_bytes()) && self.intent_binding diff --git a/packages/d2b-core-controller/src/owner_reconcile.rs b/packages/d2b-core-controller/src/owner_reconcile.rs index 5ab648d5f..808cdf3d7 100644 --- a/packages/d2b-core-controller/src/owner_reconcile.rs +++ b/packages/d2b-core-controller/src/owner_reconcile.rs @@ -1072,7 +1072,6 @@ impl OwnerIndex { let observed = self .children .get(owner) - .cloned() .ok_or(OwnerReconcileError::OwnerNotRelisted)?; let mut mutations = Vec::new(); let mut create_children = Vec::new(); @@ -1103,7 +1102,7 @@ impl OwnerIndex { Some(_) => {} } } - for (target, actual) in &observed { + for (target, actual) in observed { if !desired_by_ref.contains_key(target) && !actual.deletion_requested { mutations.push(OwnerMutation::RequestDeletion { target: target.clone(), @@ -1128,7 +1127,7 @@ impl OwnerIndex { self.limits.max_depth, )?; let deletion_order = ordered_observed_refs( - &observed, + observed, desired_by_ref.keys(), self.limits.max_work_items, self.limits.max_depth, @@ -1145,7 +1144,7 @@ impl OwnerIndex { .collect::>(); mutations.sort_by_key(|mutation| { let (target, deleting, kind) = - mutation_sort_parts(mutation, &desired_by_ref, &observed); + mutation_sort_parts(mutation, &desired_by_ref, observed); let position = if deleting { deletion_positions .get(target) From c44ccbd0b1b573f20943f2dd03c699ac77577bb6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:19:52 -0700 Subject: [PATCH 084/726] runtime: simplify registry, transport, autostart, tick, and audit-write paths --- packages/d2bd-runtime/src/autostart.rs | 19 ++--- packages/d2bd-runtime/src/console_session.rs | 26 +++---- packages/d2bd-runtime/src/daemon_audit.rs | 38 ++++----- .../src/guest_component_session.rs | 15 +--- packages/d2bd-runtime/src/guest_mode.rs | 15 +--- packages/d2bd-runtime/src/runtime_util.rs | 12 +++ packages/d2bd-runtime/src/supervisor/dag.rs | 7 +- packages/d2bd-runtime/src/unix_transport.rs | 21 ++--- .../d2bd-runtime/src/unsafe_local_helper.rs | 78 ++++++++++++++++--- 9 files changed, 137 insertions(+), 94 deletions(-) diff --git a/packages/d2bd-runtime/src/autostart.rs b/packages/d2bd-runtime/src/autostart.rs index da8e9128d..aff2680c0 100644 --- a/packages/d2bd-runtime/src/autostart.rs +++ b/packages/d2bd-runtime/src/autostart.rs @@ -225,22 +225,17 @@ pub trait VmStarter: Send + Sync + 'static { /// with `autostart = false`. They are surfaced for observability but /// skipped by [`execute_autostart`]. pub fn build_autostart_plan(resolver: &BundleResolver) -> AutostartPlan { - let mut net_entries = Vec::new(); - let mut workload_entries = Vec::new(); - - for (name, vm) in &resolver.manifest.vms { - let entry = VmAutostartEntry { + let (mut net_entries, mut workload_entries): (Vec<_>, Vec<_>) = resolver + .manifest + .vms + .iter() + .map(|(name, vm)| VmAutostartEntry { vm: name.clone(), env: vm.env.clone(), is_net_vm: vm.is_net_vm, autostart: vm_is_autostart_eligible(vm), - }; - if entry.is_net_vm { - net_entries.push(entry); - } else { - workload_entries.push(entry); - } - } + }) + .partition(|entry| entry.is_net_vm); net_entries.sort_by(|a, b| a.env.cmp(&b.env).then_with(|| a.vm.cmp(&b.vm))); workload_entries.sort_by(|a, b| a.env.cmp(&b.env).then_with(|| a.vm.cmp(&b.vm))); diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index 0860740ca..324e19eec 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -129,6 +129,12 @@ impl ConsoleClientHandle { } } +impl std::borrow::Borrow for ConsoleClientHandle { + fn borrow(&self) -> &str { + &self.0 + } +} + impl Default for ConsoleClientHandle { fn default() -> Self { Self::new().expect("console handle entropy unavailable") @@ -140,6 +146,7 @@ impl Default for ConsoleClientHandle { /// One entry per running VM that has an active drainer. Multiple clients /// share the same ring buffer for a given VM. #[derive(Debug)] +#[derive(Default)] pub struct ConsoleSessionTable { /// VM-name → active session. sessions: HashMap, @@ -159,12 +166,6 @@ impl ConsoleSessionTable { } } -impl Default for ConsoleSessionTable { - fn default() -> Self { - Self::new() - } -} - impl ConsoleSessionTable { /// drainer. Replaces any existing session (e.g. after a VM restart). pub fn register_session(&mut self, vm: String, session: ConsoleSession) { @@ -247,7 +248,7 @@ impl ConsoleSessionTable { /// not known. pub fn client_owner_uid(&self, session_handle: &str) -> Option { self.client_uids - .get(&ConsoleClientHandle(session_handle.to_owned())) + .get(session_handle) .copied() } @@ -265,7 +266,7 @@ impl ConsoleSessionTable { ) -> Option { let vm = self .clients - .get(&ConsoleClientHandle(session_handle.to_owned()))?; + .get(session_handle)?; let session = self.sessions.get(vm)?; let (result, notify) = { let Ok(guard) = session.ring.try_lock() else { @@ -290,7 +291,7 @@ impl ConsoleSessionTable { pub fn write_stdin(&self, session_handle: &str, bytes: Vec) -> Option { let vm = self .clients - .get(&ConsoleClientHandle(session_handle.to_owned()))?; + .get(session_handle)?; let session = self.sessions.get(vm)?; let Some(ref tx) = session.stdin_tx else { return Some(false); @@ -301,9 +302,8 @@ impl ConsoleSessionTable { /// Close (detach) a client session. The VM's drainer keeps running. pub fn close(&mut self, session_handle: &str) -> bool { - let key = ConsoleClientHandle(session_handle.to_owned()); - self.client_uids.remove(&key); - self.clients.remove(&key).is_some() + self.client_uids.remove(session_handle); + self.clients.remove(session_handle).is_some() } /// Whether a session exists for `vm`. @@ -316,7 +316,7 @@ impl ConsoleSessionTable { pub fn ring_notify(&self, session_handle: &str) -> Option> { let vm = self .clients - .get(&ConsoleClientHandle(session_handle.to_owned()))?; + .get(session_handle)?; let session = self.sessions.get(vm)?; let Ok(guard) = session.ring.try_lock() else { return None; diff --git a/packages/d2bd-runtime/src/daemon_audit.rs b/packages/d2bd-runtime/src/daemon_audit.rs index 3918b6701..99cd2d44a 100644 --- a/packages/d2bd-runtime/src/daemon_audit.rs +++ b/packages/d2bd-runtime/src/daemon_audit.rs @@ -910,14 +910,14 @@ impl DaemonAuditLog { /// within a JSONL line: this call queues the record and waits for that /// append's outcome. A day-boundary crossing triggers best-effort /// retention pruning of stale `daemon-events-*.jsonl` files. - pub fn write_event(&self, event: &DaemonEvent) -> io::Result<()> { + pub fn write_event(&self, event: DaemonEvent) -> io::Result<()> { self.write_event_with_authority(event, DaemonAuditAuthority::BestEffort) } /// Write an event with an explicit authority class. pub fn write_event_with_authority( &self, - event: &DaemonEvent, + event: DaemonEvent, authority: DaemonAuditAuthority, ) -> io::Result<()> { let (reply, outcome) = oneshot::channel(); @@ -932,7 +932,7 @@ impl DaemonAuditLog { } /// Append one event without parking the caller's thread on the sink. - pub async fn write_event_async(&self, event: &DaemonEvent) -> io::Result<()> { + pub async fn write_event_async(&self, event: DaemonEvent) -> io::Result<()> { self.write_event_with_authority_async(event, DaemonAuditAuthority::BestEffort) .await } @@ -944,7 +944,7 @@ impl DaemonAuditLog { /// it. pub async fn write_event_with_authority_async( &self, - event: &DaemonEvent, + event: DaemonEvent, authority: DaemonAuditAuthority, ) -> io::Result<()> { let (reply, outcome) = oneshot::channel(); @@ -961,7 +961,7 @@ impl DaemonAuditLog { /// caller, is what a backlog grows). fn enqueue( &self, - event: &DaemonEvent, + event: DaemonEvent, authority: DaemonAuditAuthority, reply: oneshot::Sender>, ) -> io::Result<()> { @@ -973,7 +973,7 @@ impl DaemonAuditLog { .duration_since(UNIX_EPOCH) .unwrap_or_default() .as_millis(), - event: event.clone(), + event, authority, reply, }; @@ -1914,7 +1914,7 @@ mod tests { let log = DaemonAuditLog::new(dir.path()); // Trigger a fake api-ready timeout event. - log.write_event(&DaemonEvent::ApiReadyTimeout { + log.write_event(DaemonEvent::ApiReadyTimeout { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 60, @@ -2022,13 +2022,13 @@ mod tests { const SENTINEL: &str = "SECRET-handle-argv-env-cwd-/nix/store/path-like-token-9b2f"; let log = DaemonAuditLog::no_op(); - log.write_event(&DaemonEvent::ComponentSessionExecEstablished { + log.write_event(DaemonEvent::ComponentSessionExecEstablished { vm: "corp-vm".to_owned(), peer_uid: 1000, tty: true, }) .expect("write established event"); - log.write_event(&DaemonEvent::ComponentSessionExecTerminated { + log.write_event(DaemonEvent::ComponentSessionExecTerminated { vm: "corp-vm".to_owned(), peer_uid: 1000, }) @@ -2093,7 +2093,7 @@ mod tests { const SENTINEL: &str = "SECRET-shell-name-session-terminal-/nix/store/path-like-token"; let log = DaemonAuditLog::no_op(); - log.write_event(&DaemonEvent::ShellLifecycle { + log.write_event(DaemonEvent::ShellLifecycle { target: "corp-vm".to_owned(), peer_uid: 1000, provider: ShellAuditProvider::ComponentSession, @@ -2153,7 +2153,7 @@ mod tests { const SENTINEL: &str = "SECRET-argv-env-cwd-/nix/store/log-bytes-2d7b"; let log = DaemonAuditLog::no_op(); - log.write_event(&DaemonEvent::ComponentSessionExecDetachedCreate { + log.write_event(DaemonEvent::ComponentSessionExecDetachedCreate { vm: "corp-vm".to_owned(), peer_uid: 1000, action: DetachedExecAuditAction::Create, @@ -2161,7 +2161,7 @@ mod tests { exec_id: "exec-opaque-1".to_owned(), }) .expect("write detached create event"); - log.write_event(&DaemonEvent::ComponentSessionExecDetachedKill { + log.write_event(DaemonEvent::ComponentSessionExecDetachedKill { vm: "corp-vm".to_owned(), peer_uid: 1000, action: DetachedExecAuditAction::Cancel, @@ -2350,7 +2350,7 @@ mod tests { std::fs::write(&blocker, "blocks directory creation").expect("write blocker"); let log = DaemonAuditLog::new(blocker.join("child")); let error = log - .write_event(&DaemonEvent::ApiReadyTimeout { + .write_event(DaemonEvent::ApiReadyTimeout { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 30, @@ -2392,7 +2392,7 @@ mod tests { // Manually set state_dir to the temp dir via a helper. // We can't do that here because state_dir is private; instead, // create a no_op and verify its captured vec is empty. - log.write_event(&DaemonEvent::ApiReadyTimeout { + log.write_event(DaemonEvent::ApiReadyTimeout { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 30, @@ -2412,7 +2412,7 @@ mod tests { fn test_capture_authoritative_events_are_not_silently_dropped() { let log = DaemonAuditLog::no_op(); let result = log.write_event_with_authority( - &DaemonEvent::ResourcePlaneLifecycle { + DaemonEvent::ResourcePlaneLifecycle { zone: "work".to_owned(), action: ResourcePlaneAction::Start, result: ResourcePlaneResult::Ready, @@ -2455,7 +2455,7 @@ mod tests { let log = std::sync::Arc::clone(&log); handles.push(std::thread::spawn(move || { for _ in 0..25 { - log.write_event(&DaemonEvent::VmStartRunnerExited { + log.write_event(DaemonEvent::VmStartRunnerExited { vm: format!("vm-{thread_idx}"), role_id: "swtpm".to_owned(), reason_kind: VmStartRunnerExitReason::RunnerExited, @@ -2498,7 +2498,7 @@ mod tests { async fn async_seat_appends_before_it_returns() { let dir = tempfile::tempdir().expect("create temp dir"); let log = DaemonAuditLog::new(dir.path()); - log.write_event_async(&DaemonEvent::ApiReadyTimeout { + log.write_event_async(DaemonEvent::ApiReadyTimeout { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 60, @@ -2507,7 +2507,7 @@ mod tests { .await .expect("async best-effort append"); log.write_event_with_authority_async( - &DaemonEvent::ResourcePlaneLifecycle { + DaemonEvent::ResourcePlaneLifecycle { zone: "work".to_owned(), action: ResourcePlaneAction::Start, result: ResourcePlaneResult::Ready, @@ -2634,7 +2634,7 @@ mod tests { result: WorkloadLaunchResult::Committed, }; assert!(!format!("{event:?}").contains("target-secret-canary")); - log.write_event(&event).unwrap(); + log.write_event(event).unwrap(); let line = log.captured.lock().unwrap().last().cloned().unwrap(); for canary in [ "target-secret-canary", diff --git a/packages/d2bd-runtime/src/guest_component_session.rs b/packages/d2bd-runtime/src/guest_component_session.rs index 53093b154..0607f0161 100644 --- a/packages/d2bd-runtime/src/guest_component_session.rs +++ b/packages/d2bd-runtime/src/guest_component_session.rs @@ -30,7 +30,7 @@ use d2b_session::{ }; use d2b_session_unix::FramedVsockTransport; use serde::{Deserialize, Serialize}; -use std::sync::OnceLock; + use crate::{ component_session_vsock::{ @@ -398,7 +398,7 @@ impl GuestComponentSessionClient { .map_err(|_| GuestComponentSessionClientError::Session)?, ); let session = authenticated - .admit(engine, evidence, monotonic_tick()) + .admit(engine, evidence, crate::runtime_util::monotonic_tick()) .await .map_err(|_| GuestComponentSessionClientError::Session)?; let route_binding = session.route_binding(); @@ -584,17 +584,6 @@ fn authorize_guest_peer( Ok(previous) } -fn monotonic_tick() -> u64 { - static START: OnceLock = OnceLock::new(); - START - .get_or_init(std::time::Instant::now) - .elapsed() - .as_millis() - .try_into() - .unwrap_or(1) - .max(1) -} - /// Errors while loading host-published session metadata. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GuestComponentSessionError { diff --git a/packages/d2bd-runtime/src/guest_mode.rs b/packages/d2bd-runtime/src/guest_mode.rs index f7fa09799..ae3fdef02 100644 --- a/packages/d2bd-runtime/src/guest_mode.rs +++ b/packages/d2bd-runtime/src/guest_mode.rs @@ -8,7 +8,7 @@ use std::{ fs, path::{Path, PathBuf}, - sync::{Arc, OnceLock, Weak}, + sync::{Arc, Weak}, time::Instant, }; @@ -656,7 +656,7 @@ impl GuestRuntime { )) .map_err(|_| GuestModeError::SessionBindingMismatch)?, ), - monotonic_tick(), + crate::runtime_util::monotonic_tick(), ) .await .map_err(GuestModeError::Session)?; @@ -846,17 +846,6 @@ fn authorize_guest_request( Ok(previous) } -fn monotonic_tick() -> u64 { - static START: OnceLock = OnceLock::new(); - START - .get_or_init(Instant::now) - .elapsed() - .as_millis() - .try_into() - .unwrap_or(1) - .max(1) -} - /// Guest-mode failures are closed and identity-free. #[derive(Debug)] pub enum GuestModeError { diff --git a/packages/d2bd-runtime/src/runtime_util.rs b/packages/d2bd-runtime/src/runtime_util.rs index 764e4ec00..cf72b62ae 100644 --- a/packages/d2bd-runtime/src/runtime_util.rs +++ b/packages/d2bd-runtime/src/runtime_util.rs @@ -29,4 +29,16 @@ pub fn projection_digest_bytes(value: &str) -> Option<[u8; 32]> { (!value.is_empty()).then(|| sha2::Sha256::digest(value.as_bytes()).into()) } +/// Monotonic process-lifetime tick in elapsed milliseconds, used to +/// sequence guest admission attempts without trusting guest clocks. +pub(crate) fn monotonic_tick() -> u64 { + static START: std::sync::LazyLock = std::sync::LazyLock::new(std::time::Instant::now); + START + .elapsed() + .as_millis() + .try_into() + .unwrap_or(1) + .max(1) +} + diff --git a/packages/d2bd-runtime/src/supervisor/dag.rs b/packages/d2bd-runtime/src/supervisor/dag.rs index e7034c382..a94c18245 100644 --- a/packages/d2bd-runtime/src/supervisor/dag.rs +++ b/packages/d2bd-runtime/src/supervisor/dag.rs @@ -421,15 +421,16 @@ impl DagExecutor { .runner .probe_api_ready(&dag.vm, node, &node.readiness, api_timeout) .await; - api_ready = Some(state.clone()); - match state { + let outcome = match &state { ApiReadyState::Yes => Ok(()), ApiReadyState::Pending => Err("api-ready pending".to_owned()), ApiReadyState::Timeout => Err("api-ready timeout".to_owned()), ApiReadyState::Error { reason } => { Err(format!("api-ready error: {reason}")) } - } + }; + api_ready = Some(state); + outcome } }, Err(reason) => Err(reason), diff --git a/packages/d2bd-runtime/src/unix_transport.rs b/packages/d2bd-runtime/src/unix_transport.rs index ec40204be..761de6e6e 100644 --- a/packages/d2bd-runtime/src/unix_transport.rs +++ b/packages/d2bd-runtime/src/unix_transport.rs @@ -291,15 +291,18 @@ pub fn read_frame_with_fds(socket: &impl AsRawFd) -> Result<(Vec, Vec detail: err.to_string(), })?; let read = message.bytes; - let mut received_fds = Vec::new(); - for cmsg in message.cmsgs().map_err(|err| TypedError::InternalIo { - context: "recv seqpacket frame with fds".to_owned(), - detail: err.to_string(), - })? { - if let ControlMessageOwned::ScmRights(fds) = cmsg { - received_fds.extend(fds); - } - } + let received_fds: Vec = message + .cmsgs() + .map_err(|err| TypedError::InternalIo { + context: "recv seqpacket frame with fds".to_owned(), + detail: err.to_string(), + })? + .filter_map(|cmsg| match cmsg { + ControlMessageOwned::ScmRights(fds) => Some(fds), + _ => None, + }) + .flatten() + .collect(); if message .flags .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC) diff --git a/packages/d2bd-runtime/src/unsafe_local_helper.rs b/packages/d2bd-runtime/src/unsafe_local_helper.rs index 435851433..718a7bed0 100644 --- a/packages/d2bd-runtime/src/unsafe_local_helper.rs +++ b/packages/d2bd-runtime/src/unsafe_local_helper.rs @@ -1,3 +1,12 @@ +//! The unsafe-local helper registry. +//! +//! Owns the daemon side of the unsafe-local-helper wire protocol: a single +//! `accept_loop` thread admits peer helpers, tracks per-UID generations +//! and heartbeats, dispatches launch frames, and correlates async operation +//! replies back to their callers. All frames are validated against the +//! protocol versionand redacted before they carry wire data onto other daemon +//! surfaces. + use d2b_contracts_control::unsafe_local_wire::{ DaemonToUnsafeLocalHelper, HELPER_SOCKET_BUFFER_REQUEST_BYTES, HelperFailureCode, HelperHeartbeat, HelperHelloAccepted, HelperLaunchRequest, HelperOperationDisposition, @@ -30,14 +39,23 @@ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, mpsc}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +/// How often a healthy helper must send a heartbeat to stay live. pub const HELPER_HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); + +/// How long a helper may fall silent before it is treated as stale. + pub const HELPER_STALE_AFTER: Duration = Duration::from_secs(15); + +/// How long a launched helper operation may run before the daemon gives up. + + pub const HELPER_OPERATION_TIMEOUT: Duration = Duration::from_secs(30); const HELPER_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(30); const HELPER_LOOP_TICK: Duration = Duration::from_millis(200); const HELPER_ACTIVE_OPERATION_RETENTION_SECS: u64 = 45; const LATE_RESPONSE_RETENTION: Duration = Duration::from_secs(30); +/// Errors the daemon-side helper registry can surface to its internal callers. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum HelperRegistryError { UnauthorizedPeer, @@ -61,6 +79,7 @@ pub enum HelperRegistryError { Io, } +/// Whether a peer helper can currently serve operations for a UID. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum HelperAvailability { Ready, @@ -68,6 +87,10 @@ pub enum HelperAvailability { Stale, } +/// The outcome of a launched helper operation: a successful result or a +/// rejection with a wire failure code. Correlated by request id at the +/// pending-request table. + pub enum HelperReply { Operation(HelperOperationResult), Rejected(HelperOperationRejected), @@ -187,6 +210,11 @@ struct RegistryState { last_failures: HashMap<(u32, String), HelperFailureCode>, } +/// The daemon-side registry of unsafe-local helper peers for one socket. +/// +/// Tracks per-UID helper generations, snapshots, and operation +/// completions; all peer contact flows through [`Self::accept_loop`]. + pub struct HelperRegistry { daemon_uid: u32, allowed_uids: HashSet, @@ -205,6 +233,9 @@ impl fmt::Debug for HelperRegistry { } impl HelperRegistry { + /// Create an empty registry admitting only `allowed_uids`, with the daemon's + /// own peer uid recorded for socket-credential checks. + pub fn new(daemon_uid: u32, allowed_uids: impl IntoIterator) -> Self { Self { daemon_uid, @@ -214,6 +245,10 @@ impl HelperRegistry { } } + /// Blocking accept loop for the helper listener: each accepted socket + /// is handled on its own dedicated thread. Runs forever and surfaces + /// accept errors to tracing only. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn accept_loop(self: Arc, listener: Socket) { loop { @@ -247,6 +282,7 @@ impl HelperRegistry { } } + /// The generation of the live helper connection for `uid`, or `None`. pub fn active_generation(&self, uid: u32) -> Option { self.state .lock() @@ -256,10 +292,12 @@ impl HelperRegistry { .map(|connection| connection.generation) } + /// The last helper snapshot the daemon saw for `uid`, if any. pub fn snapshot(&self, uid: u32) -> Option { self.state.lock().snapshots.get(&uid).cloned() } + /// Whether `uid` has a ready, unavailable, or stale helper connection. pub fn availability(&self, uid: u32) -> HelperAvailability { let state = self.state.lock(); let Some(connection) = state.connections.get(&uid) else { @@ -274,6 +312,9 @@ impl HelperRegistry { } } + /// The wire failure code of the most recent rejected operation for `target` by + /// `uid`, if any, used to surface stable operator diagnostics. + pub fn last_failure( &self, uid: u32, @@ -286,6 +327,17 @@ impl HelperRegistry { .copied() } + /// Queue a helper launch for `requester_uid` and block until the helper + /// reply lands or the operation times out. + /// + /// The operation ledger deduplicates replays by operation id; a + /// replayed launch returns the already-committed result when possible. + /// + /// # Errors + /// + /// Returns the registry error for invalid launch shapes, unknown + /// helpers, stale connections, or queue backpressure. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn dispatch_launch( &self, @@ -619,10 +671,10 @@ impl HelperRegistry { } UnsafeLocalHelperToDaemon::Operation(result) => { reject_unexpected_fds(fds)?; - let completion = complete_pending( +let completion = complete_pending( connection, result.request_id, - result.operation_id.to_string(), + result.operation_id.as_str(), HelperReply::Operation(result.clone()), )?; if !completion.delivered { @@ -638,10 +690,10 @@ impl HelperRegistry { } UnsafeLocalHelperToDaemon::Rejected(rejected) => { reject_unexpected_fds(fds)?; - let completion = complete_pending( +let completion = complete_pending( connection, rejected.request_id, - rejected.operation_id.to_string(), + rejected.operation_id.as_str(), HelperReply::Rejected(rejected.clone()), )?; if !completion.delivered { @@ -670,7 +722,7 @@ struct PendingCompletion { fn complete_pending( connection: &HelperConnection, request_id: u64, - operation_id: String, + operation_id: &str, reply: HelperReply, ) -> Result { let pending = connection.pending.lock().remove(&request_id); @@ -786,15 +838,17 @@ fn receive_frame( Err(_) => return Err(HelperRegistryError::Io), }; let read = message.bytes; - let mut fds = Vec::new(); - for control in message + let fds: Vec = message .cmsgs() .map_err(|_| HelperRegistryError::InvalidFrame)? - { - if let ControlMessageOwned::ScmRights(rights) = control { - fds.extend(rights.into_iter().map(ReceivedFd)); - } - } + .filter_map(|control| match control { + ControlMessageOwned::ScmRights(rights) => { + Some(rights.into_iter().map(ReceivedFd)) + } + _ => None, + }) + .flatten() + .collect(); if read == 0 { return Err(HelperRegistryError::Io); } From c4b29ded7acb0f7b2c8de80b9bb93fa1e74aa0e5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:19:55 -0700 Subject: [PATCH 085/726] runtime: document json, vm-start, broker, readiness, exec, ch-api, target surfaces --- packages/d2bd-runtime/src/broker_transport.rs | 25 +++++++++++++++ packages/d2bd-runtime/src/ch_api.rs | 32 +++++++++++++++++++ packages/d2bd-runtime/src/exec_session.rs | 31 ++++++++++++++++-- packages/d2bd-runtime/src/json_io.rs | 12 +++++++ packages/d2bd-runtime/src/readiness.rs | 32 +++++++++++++++++-- .../src/ssh_host_key_preflight.rs | 9 +++--- packages/d2bd-runtime/src/target_runtime.rs | 30 ++++++++++++++--- packages/d2bd-runtime/src/vm_start_support.rs | 19 +++++++++++ 8 files changed, 176 insertions(+), 14 deletions(-) diff --git a/packages/d2bd-runtime/src/broker_transport.rs b/packages/d2bd-runtime/src/broker_transport.rs index 27a35af4f..f2ef94a7a 100644 --- a/packages/d2bd-runtime/src/broker_transport.rs +++ b/packages/d2bd-runtime/src/broker_transport.rs @@ -57,6 +57,13 @@ pub fn dispatch_broker_request_to_socket( } } +/// Extract the audit-join zone and operation identities a request +/// authoritatively carries, if any. +/// +/// # Errors +/// +/// Returns `WireInvalidFrame` when the cited identities are not canonical +/// audit digests, so a malformed broker claim cannot poison the log. pub fn default_audit_join_context( request: &BrokerRequest, ) -> Result, TypedError> { @@ -74,6 +81,12 @@ pub fn default_audit_join_context( })) } +/// Seconds left before `deadline`, refusing ops that cannot plausibly fit. +/// +/// # Errors +/// +/// Returns `InternalBrokerTimeout` when the deadline has already passed, so +/// each socket op is gated on a budget that cannot overrun into the next op. pub fn broker_remaining_before_op( deadline: Instant, socket_path: &Path, @@ -121,6 +134,9 @@ fn broker_round_trip_within_deadline( }) } +/// The wire `kind` discriminator of a broker response, or `unknown` when +/// the payload carries none or cannot be serialized. + pub fn broker_response_kind(response: &BrokerResponse) -> String { serde_json::to_value(response) .ok() @@ -133,6 +149,11 @@ pub fn broker_response_kind(response: &BrokerResponse) -> String { .unwrap_or_else(|| "unknown".to_owned()) } +/// Render an operator-facing (summary, remediation) pair for the launcher +/// role when a broker operation fails. +/// +/// The pair carries operator remediation prose only, keeping environment +/// redaction safe for launcher-facing surfaces. pub fn redact_broker_error_for_launcher( op_name: &str, target_wave: Option<&str>, @@ -192,6 +213,10 @@ pub fn redact_broker_error_for_launcher( (summary, remediation) } +/// Render an operator-facing (summary, remediation) pair for the launcher +/// role when the broker socket itself is unreachable (distinct from a broker +/// error reply, which [`redact_broker_error_for_launcher`] shapes). + pub fn redact_broker_dispatch_failure_for_launcher(op_name: &str) -> (String, String) { ( format!("{op_name} failed"), diff --git a/packages/d2bd-runtime/src/ch_api.rs b/packages/d2bd-runtime/src/ch_api.rs index 793d6680b..4e7b1e374 100644 --- a/packages/d2bd-runtime/src/ch_api.rs +++ b/packages/d2bd-runtime/src/ch_api.rs @@ -8,16 +8,29 @@ use std::time::Duration; use tokio::net::UnixStream; +/// Default per-request timeout for Cloud Hypervisor HTTP control calls, +/// mirroring the legacy `ch_http_timeout` exporter budget. pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5); + +/// Cap on a Cloud Hypervisor HTTP response body: a control payload that +/// large is malformed rather than tolerable (the unix API stays unbounded +/// otherwise). pub const MAX_RESPONSE_BYTES: usize = 64 * 1024; #[derive(Debug, Clone, PartialEq, Eq)] pub enum ChApiError { + /// The control socket is unreachable or the I/O failed, citing the + /// underlying error kind (not full paths或 payloads). Unavailable(String), + /// The control request exceeded its deadline. Timeout, + /// The response body exceeded `MAX_RESPONSE_BYTES`. ResponseTooLarge, + /// The response is not a well-formed HTTP control reply. MalformedResponse, + /// The API answered a non-2xx status code. Rejected(u16), + /// The `vm.info` payload did not deserialize into the expected shape. InvalidJson(String), } @@ -33,18 +46,37 @@ impl ChApiError { } } +/// The subset of the Cloud Hypervisor `vm.info` payload this crate +/// consumes; fields absent from the reply stay `None`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ChVmInfo { + /// The VM run state (e.g. `Running`, `Stopped`) as reported by CH. pub state: Option, + /// The configured vCPU count, when the reply reports one. pub vcpu_count: Option, + /// The configured memory size in MiB, when the reply reports one. pub memory_mib: Option, } +/// Fetch and parse the Cloud Hypervisor `vm.info` payload over the control +/// socket. +/// +/// # Errors +/// +/// Returns `ChApiError` for socket failures, timeouts, oversized or +/// malformed replies, and JSON that does not match the expected shape. pub async fn get_vm_info(socket: &Path, timeout: Duration) -> Result { let body = request(socket, "GET", "/api/v1/vm.info", timeout).await?; parse_vm_info(&body) } +/// Request an ACPI shutdown from the Cloud Hypervisor control socket. +/// +/// # Errors +/// +/// Returns `ChApiError` when the control request cannot be delivered or the +/// API answers a non-2xx status. + pub async fn shutdown_vm(socket: &Path, timeout: Duration) -> Result<(), ChApiError> { request(socket, "PUT", "/api/v1/vm.shutdown", timeout) .await diff --git a/packages/d2bd-runtime/src/exec_session.rs b/packages/d2bd-runtime/src/exec_session.rs index 8f98e5cbe..b8dd9bf44 100644 --- a/packages/d2bd-runtime/src/exec_session.rs +++ b/packages/d2bd-runtime/src/exec_session.rs @@ -178,16 +178,24 @@ impl Default for ExecOpDeadlines { /// redacted so a stray `{:?}` can never leak argv / env keys+values / cwd. #[derive(Clone, PartialEq, Eq)] pub struct ExecStartSpec { + /// The guest VM these args target. pub vm: String, /// Optional opaque idempotency key forwarded as guest request metadata. /// It is never argv and must not appear in Debug output. pub request_id: Option, + /// Program plus arguments, forwarded verbatim to the guest exec. pub argv: Vec, + /// Whether to allocate a PTY drunk on the guest side. pub tty: bool, + /// Whether the guest process must leave its session alive after stdin +/// closes (non-tty detached spawn). pub detached: bool, - pub env: Vec<(String, String)>, + /// Environment overrides applied at launch (never rendered in Debug). + pub env: Vec<(String,String)>, + /// Working directory the guest runs in, or the guest default when `None`. pub cwd: Option, - pub term_size: Option<(u32, u32)>, + /// PTY size requested at spawn, when the guest terminal reports one. + pub term_size: Option<(u32,u32)>, } impl std::fmt::Debug for ExecStartSpec { @@ -208,8 +216,13 @@ impl std::fmt::Debug for ExecStartSpec { /// Session info reported back to the owner on a successful establish. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExecSessionInfo { + /// Whether the session was established with a PTY. pub tty: bool, + /// Bytes already readable from the guest stdout stream, from the owner's + /// offset perspective (0-based at first read). pub stdout_offset: u64, + /// Bytes already readable from the guest stderr stream, from the owner's + /// offset perspective (0-based at first read). pub stderr_offset: u64, } @@ -246,9 +259,16 @@ impl NegotiatedCaps { /// A freshly established session: the authenticated client, the info echoed to /// the owner, and the initial control sequence from `ExecCreate`. pub struct Established { + /// The authenticated guest exec channel for the session. pub client: Arc, + /// Session metadata echoed to the owner at establish time. pub info: ExecSessionInfo, + /// The initial control sequence number the session starts at, used to + /// derive per-op sequence ids so a resequenced stream cannot replay + /// an older op. pub control_seq: u64, + /// The negotiated capability snapshot the guest advertised at establish, + /// shared by every op gate until the session closes. pub caps: NegotiatedCaps, } @@ -879,10 +899,17 @@ impl TerminalReaper { /// Inputs to [`spawn_session_worker`]. pub struct WorkerSpawn { + /// The authenticated guest channel factory the worker uses to establish. pub connector: Arc, + /// The validated launch spec the guest session starts with. pub spec: ExecStartSpec, + /// Per-op control/poll deadlines applied by the worker. pub deadlines: ExecOpDeadlines, + /// Sender for the establish outcome, consumed exactly once by the + /// worker when the guest session reports ready or fails. pub establish_tx: oneshot::Sender, + /// Inbound worker commands (resize, signal, read offsets) serviced + /// until the channel closes (owner disconnect). pub control_rx: mpsc::Receiver, /// Terminal-cleanup grace before the reaper releases a stalled owner's slot. pub terminal_ttl: Duration, diff --git a/packages/d2bd-runtime/src/json_io.rs b/packages/d2bd-runtime/src/json_io.rs index 6debed70d..0ad71ae5c 100644 --- a/packages/d2bd-runtime/src/json_io.rs +++ b/packages/d2bd-runtime/src/json_io.rs @@ -7,6 +7,12 @@ use serde::Deserialize; use crate::typed_error::TypedError; +/// Resolve a bundle-relative artifact path within `base_dir`. +/// +/// An absolute path is honored verbatim when it already exists; an +/// absolute path that points nowhere falls back to `base_dir` + its file +/// name, so a bundle self-reference keeps working after unpacking; a +/// relative path joins `base_dir` unchanged. pub fn resolve_bundle_artifact_path(base_dir: &Path, raw_path: &str) -> PathBuf { let raw = Path::new(raw_path); if raw.is_absolute() && raw.exists() { @@ -38,6 +44,12 @@ where }) } +/// Load the bundle manifest as a JSON object, owning its top-level map. +/// +/// # Errors +/// +/// Returns `InternalIo` when the file cannot be read or decoded, or when +/// the root value is not an object (the manifest schema requires one). pub fn load_manifest( path: &Path, ) -> Result, TypedError> { diff --git a/packages/d2bd-runtime/src/readiness.rs b/packages/d2bd-runtime/src/readiness.rs index 626af3f5c..53351f5d0 100644 --- a/packages/d2bd-runtime/src/readiness.rs +++ b/packages/d2bd-runtime/src/readiness.rs @@ -12,6 +12,13 @@ use crate::supervisor::{ state::{ProcReader, SystemProcReader}, }; +/// Evaluate one readiness predicate synchronously. +/// +/// # Errors +/// +/// Returns a `String` reason for predicates that need the async or +/// state-aware seat, so a misrouted probe fails loud instead of silently +/// never being ready. pub fn readiness_predicate_ready(predicate: &ReadinessPredicate) -> Result { match predicate { ReadinessPredicate::ApiSocketInfo(path) => Ok(api_socket_info_ready(path)), @@ -74,6 +81,7 @@ pub fn api_socket_info_ready(path: &str) -> bool { response.starts_with("HTTP/1.1 200") || response.starts_with("HTTP/1.0 200") } +/// Whether a filesystem entry at `path` is a socket (any socket kind).. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn unix_socket_exists(path: &str) -> bool { std::fs::metadata(path) @@ -81,6 +89,9 @@ pub fn unix_socket_exists(path: &str) -> bool { .unwrap_or(false) } +/// Whether a stream socket at `path` is actively listening, parsed from +/// `/proc/net/unix` accept flags (no connect side effect; a connected but +/// non-listening path returns `false`). #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn unix_socket_listening(path: &str) -> bool { const SO_ACCEPTCON: u64 = 0x0001_0000; @@ -100,7 +111,8 @@ pub fn unix_socket_listening(path: &str) -> bool { } #[allow(clippy::disallowed_methods, reason = "synchronous path")] -pub fn tcp_port_ready(host: &str, port: u16) -> bool { +/// Whether a TCP connect to `host:port` succeeds within 250ms. + pub fn tcp_port_ready(host: &str, port: u16) -> bool { let Ok(addrs) = format!("{host}:{port}").to_socket_addrs() else { return false; }; @@ -109,6 +121,12 @@ pub fn tcp_port_ready(host: &str, port: u16) -> bool { }) } +/// Poll `tcp_port_ready` until it succeeds or `timeout` elapses. +/// +/// # Errors +/// +/// Returns "tcp-readiness-timeout:host:port" when the port never opens. + pub async fn wait_for_tcp_port(host: &str, port: u16, timeout: Duration) -> Result<(), String> { let deadline = Instant::now() + timeout; loop { @@ -122,7 +140,17 @@ pub async fn wait_for_tcp_port(host: &str, port: u16, timeout: Duration) -> Resu } } -pub async fn command_ready(command: &[String]) -> Result { +/// Run `command` to completion and report whether it exited 0, stripping +/// `NOTIFY_SOCKET` so the probe cannot leak a daemon notify fd into the +/// child. +/// +/// # Errors +/// +/// Returns "command-readiness-empty" for an empty argv and +/// "command-readiness-exec-failed" when the program cannot be spawned. + + +pub async fn command_ready(command: &[String]) -> Result { let Some(program) = command.first() else { return Err("command-readiness-empty".to_owned()); }; diff --git a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs index 2ba28e419..a58a06153 100644 --- a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs +++ b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs @@ -295,10 +295,9 @@ pub fn check_sshd_host_keys(vm: &str, keys_dir: &Path) -> Result<(), SshdHostKey } tracing::debug!( vm = %vm, - // P2fu1 observability-r2 closure: bounded attrs only; - // path is high-cardinality + leaks host layout. The - // operator-recoverable form lives in the typed error - // envelope + audit log per the daemon tracing contract. + // Bounded attrs only: path is high-cardinality + leaks host + // layout. The operator-recoverable form lives in the typed + // error envelope + audit log per the daemon tracing contract. outcome = "key-entry-ok", uid, gid, @@ -309,7 +308,7 @@ pub fn check_sshd_host_keys(vm: &str, keys_dir: &Path) -> Result<(), SshdHostKey Ok(()) } -/// v1.1.2fu25: returns true when the file has a +/// Returns true when the file has a /// `system.posix_acl_access` xattr (i.e. the activation script's /// `setfacl -m u:UID:r` grant for ADR 0021 broker-pre-NS /// virtiofsd has been applied). Used by the preflight to diff --git a/packages/d2bd-runtime/src/target_runtime.rs b/packages/d2bd-runtime/src/target_runtime.rs index 7ddd57a24..ebfb4f5cd 100644 --- a/packages/d2bd-runtime/src/target_runtime.rs +++ b/packages/d2bd-runtime/src/target_runtime.rs @@ -253,6 +253,12 @@ pub struct AdmissionBudget { } impl AdmissionBudget { + /// Construct a budget from validated limits. + /// + /// # Errors + /// + /// Returns `AdmissionError` when the limits fail self-consistency + /// validation (cf. [`AdmissionLimits::validate`]). pub fn new(limits: AdmissionLimits) -> Result { Ok(Self { limits: limits.validate()?, @@ -267,8 +273,9 @@ impl AdmissionBudget { }) } + /// The validated limits this budget admits against. pub const fn limits(&self) -> AdmissionLimits { - self.limits + self.limits } /// Reserve a non-reconnect class without allocating class state first. @@ -308,6 +315,8 @@ impl AdmissionBudget { Ok(permit(AdmissionKind::Reconnect, Arc::clone(&self.counters))) } + /// How many admissions of `kind` are currently held (reserved and not yet + /// released). pub fn active(&self, kind: AdmissionKind) -> usize { match kind { AdmissionKind::Session => self.counters.sessions.load(Ordering::Acquire), @@ -351,10 +360,17 @@ pub struct AdmissionPermit { } impl AdmissionPermit { + /// The admission class this permit reserved. pub fn kind(&self) -> AdmissionKind { - self.inner.kind + self.inner.kind } + /// Release this reservation, decrementing the live counter exactly once. + /// + /// Repeated calls are idempotent: only the first release touches the + /// counter; later calls are no-ops, so a drop-order race cannot + /// double-free an admission slot. + pub fn release(&self) { if !self.inner.released.swap(true, Ordering::AcqRel) { let counter = match self.inner.kind { @@ -1105,16 +1121,20 @@ impl ProviderDeployment { }) } + /// The daemon mode this deployment is bound to. pub const fn mode(&self) -> DaemonMode { - self.mode + self.mode } + /// The target kind implied by this deployment's mode. pub const fn target_kind(&self) -> TargetKind { - self.mode.target_kind() + self.mode.target_kind() } + /// The shared admission budget for this deployment's target-scoped + /// operations. pub fn admission(&self) -> &AdmissionBudget { - &self.admission + &self.admission } /// Admit exactly one target-scoped controller assignment. diff --git a/packages/d2bd-runtime/src/vm_start_support.rs b/packages/d2bd-runtime/src/vm_start_support.rs index 1046d65c1..b9f24773c 100644 --- a/packages/d2bd-runtime/src/vm_start_support.rs +++ b/packages/d2bd-runtime/src/vm_start_support.rs @@ -6,11 +6,20 @@ const VM_RUNNER_ROLE_ID: &str = "ch-runner"; #[derive(Debug, Clone, Copy)] pub enum VmStartNodeMode { + /// The node is resolved for readiness only, never launched by VM boot. + ReadinessOnly, + /// The node runs once during VM start, governed by the named runner role. + OneShot(RunnerRole), + /// The node stays alive for the whole VM session, governed by the named + /// runner role. + LongLived(RunnerRole), } +/// Map a signed process role to the runner discipline (mode) that VM start +/// applies to it. Activation and non-boot roles resolve to `ReadinessOnly`. pub fn vm_start_node_mode(role: &ProcessRole) -> VmStartNodeMode { match role { ProcessRole::SwtpmPreStartFlush => VmStartNodeMode::OneShot(RunnerRole::SwtpmFlush), @@ -41,6 +50,9 @@ pub fn vm_start_node_mode(role: &ProcessRole) -> VmStartNodeMode { } } +/// The daemon-side role name tracked for `node`: the cloud-hypervisor +/// runner normalizes to the shared `ch-runner` id, every other node keeps its +/// node id. This is the role the VM-start DAG reports for supervision polls. pub fn tracked_role_id(node: &ProcessNode) -> String { match node.role { ProcessRole::CloudHypervisorRunner => VM_RUNNER_ROLE_ID.to_owned(), @@ -86,6 +98,13 @@ pub fn node_requires_disk_init_dispatch(node: &ProcessNode) -> bool { .any(|op| matches!(op, SpawnRunnerPlanOp::DiskInit { .. })) } +/// Resolve the store-view intent the daemon must attach to `guest` boot. +/// +/// # Errors +/// +/// Returns "bundle-intent-missing:store-view" when the bundle carries no +/// store-view intent for the guest, so the caller can refuse boot before +/// any side effect lands. pub fn resolve_store_view_intent_for_guest<'a>( resolver: &'a BundleResolver, zone: &d2b_contracts_resource::v3::ZoneId, From 80037234db73e956b44b4ac3fbf76ee9dd65deaf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:19 -0700 Subject: [PATCH 086/726] xtask: route layer catalogs through string_slice --- packages/xtask/src/gen_layer_catalogs.rs | 29 ++++++++---------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/packages/xtask/src/gen_layer_catalogs.rs b/packages/xtask/src/gen_layer_catalogs.rs index 278af59fd..8c4c4bebd 100644 --- a/packages/xtask/src/gen_layer_catalogs.rs +++ b/packages/xtask/src/gen_layer_catalogs.rs @@ -155,15 +155,6 @@ fn string_slice(name: &str, doc: &[&str], values: &[String]) -> String { } /// Render one closed `&[&str]` constant. -fn string_array(name: &str, doc: &[&str], values: &[String]) -> String { - let mut out = doc_lines(doc); - let _ = writeln!(out, "pub const {name}: &[&str] = &["); - for value in values { - let _ = writeln!(out, " \"{value}\","); - } - out.push_str("];\n"); - out -} /// Render one `&[(&str, &str)]` constant. fn string_pair_slice(name: &str, doc: &[&str], values: &[(&str, &str)]) -> String { @@ -296,7 +287,7 @@ fn process_provider_ids(metric_label: Option) -> Vec { /// Render the CLI's surface catalog module. fn surface_catalog_source() -> String { let mut source = String::from(HEADER); - source.push_str(&string_array( + source.push_str(&string_slice( "RESOURCE_TYPES", &[ "The resource types the CLI addresses, in registry order.", @@ -359,12 +350,12 @@ fn surface_catalog_source() -> String { .map(|value| (*value).to_owned()) .collect::>(), )); - source.push_str(&string_array( + source.push_str(&string_slice( "MUTATION_VERBS", &["The resource verbs that write an audit row, in contract order."], &resource_mutation_verbs(), )); - source.push_str(&string_array( + source.push_str(&string_slice( "PROCESS_PROVIDERS", &["The process providers an audit record may name."], &process_provider_ids(None), @@ -453,7 +444,7 @@ fn surface_catalog_source() -> String { /// Render the audit crate's catalog module. fn audit_catalog_source() -> String { let mut source = String::from(HEADER); - source.push_str(&string_array( + source.push_str(&string_slice( "RESOURCE_TYPES", &[ "The resource types an audit record may name.", @@ -463,12 +454,12 @@ fn audit_catalog_source() -> String { ], &audit_resource_types(), )); - source.push_str(&string_array( + source.push_str(&string_slice( "MUTATION_VERBS", &["The resource verbs that write an audit row, in contract order."], &resource_mutation_verbs(), )); - source.push_str(&string_array( + source.push_str(&string_slice( "PROCESS_PROVIDERS", &["The process providers a process effect record may name."], &process_provider_ids(None), @@ -493,7 +484,7 @@ fn audit_catalog_source() -> String { /// Render the provider contracts crate's telemetry catalog module. fn telemetry_catalog_source(repo_root: &Path) -> Result { let mut source = String::from(HEADER); - source.push_str(&string_array( + source.push_str(&string_slice( "RESOURCE_TYPE_VALUES", &[ "The resource type label domain, projected from the standard", @@ -504,17 +495,17 @@ fn telemetry_catalog_source(repo_root: &Path) -> Result { ], &metric_resource_types(), )); - source.push_str(&string_array( + source.push_str(&string_slice( "API_VERBS", &["The API verb label domain, projected from the Role resource verbs."], &resource_verbs(), )); - source.push_str(&string_array( + source.push_str(&string_slice( "PROCESS_PROVIDERS", &["The process provider label domain."], &process_provider_ids(Some(true)), )); - source.push_str(&string_array( + source.push_str(&string_slice( "BROKER_OPERATION_VALUES", &[ "The broker operation label domain: the committed operation rows'", From bbd40b6fdb515a6929c84a3b0e73c5ca386c9865 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:19 -0700 Subject: [PATCH 087/726] xtask: drop dead sanitizer strip and document civil date helpers --- packages/xtask/src/main.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index 03026a2c4..fa7aa972f 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -456,7 +456,6 @@ fn sanitize_generated_rust(path: &Path) -> Result<(), Box generated = generated.replace("#![allow(unsafe_code)]\n", ""); generated = generated.replace("#![allow(unknown_lints)]\n", ""); generated = generated.replace("#![allow(clippy::all)]\n", ""); - generated = generated.replace("#![allow(clipto_camel_casepy)]\n", ""); generated = generated.replace( "#![cfg_attr(rustfmt, rustfmt_skip)]\n", "#![cfg_attr(rustfmt, rustfmt::skip)]\n", @@ -1541,6 +1540,11 @@ fn gen_release_notes(version: &str) -> Result String { use std::time::{SystemTime, UNIX_EPOCH}; let secs = SystemTime::now() @@ -1552,6 +1556,10 @@ fn today_utc_iso8601() -> String { format!("{:04}-{:02}-{:02}", y, m, d) } +/// Converts a day count since the Unix epoch to a civil (year, month, day) date +/// via the Howard Hinnant civil-calendar algorithm (719_468-day shift, 146_097-day +/// eras, 36_524-day centuries, and 153-day five-month spans). The caller clamps +/// sub-epoch clocks to the epoch. fn civil_from_days(z: i64) -> (i32, u32, u32) { let z = z + 719_468; let era = if z >= 0 { z } else { z - 146_096 } / 146_097; From fc0353eb1d37e837f12b6e6955b199176c7f623a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:20 -0700 Subject: [PATCH 088/726] xtask: accept borrowed standard types in nix inventories --- packages/xtask/src/nix_inventories.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/xtask/src/nix_inventories.rs b/packages/xtask/src/nix_inventories.rs index d4c66ff2f..3caa260c1 100644 --- a/packages/xtask/src/nix_inventories.rs +++ b/packages/xtask/src/nix_inventories.rs @@ -319,19 +319,19 @@ fn projection_schema_pointers( /// `identity::STANDARD_RESOURCE_TYPES` so the resource-type authority can /// drive the same render from the per-crate `resource-types.json` /// declarations; `gen-nix-inventories` passes the committed registry. -fn core_schema_pointers( +fn core_schema_pointers + std::fmt::Display>( schemas: &BTreeSet, - standard: &[String], + standard: &[S], ) -> Result, Box> { let mut pointers = BTreeMap::new(); for resource_type in standard { - let file = core_schema_file(resource_type); + let file = core_schema_file(resource_type.as_ref()); if !schemas.contains(&file) { return Err(render_error(format!( "{resource_type}: committed schema {file} is missing" ))); } - pointers.insert(resource_type.clone(), file); + pointers.insert(resource_type.as_ref().to_string(), file); } Ok(pointers) } @@ -468,9 +468,9 @@ fn provider_projections_module() -> String { /// `pub(crate)` so the resource-type authority (`resource_type_authority.rs`) /// drives the same render from the per-crate declarations, keeping one table /// authority per vocabulary. -pub(crate) fn resource_inventories_module( +pub(crate) fn resource_inventories_module + std::fmt::Display>( repo_root: &Path, - standard: &[String], + standard: &[S], ) -> Result> { let schemas = committed_schema_files(repo_root)?; let core = core_schema_pointers(&schemas, standard)?; @@ -716,10 +716,7 @@ pub fn gen_nix_inventories(repo_root: &Path) -> Result, Box>(), + STANDARD_RESOURCE_TYPES.as_slice(), )?, )?, write( From be3e0744b830e396e579211736b9a434f7ba3a8b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:20 -0700 Subject: [PATCH 089/726] xtask: drop redundant approval clone in production closure --- packages/xtask/src/production_closure.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/xtask/src/production_closure.rs b/packages/xtask/src/production_closure.rs index 86a4a3495..31e170dec 100644 --- a/packages/xtask/src/production_closure.rs +++ b/packages/xtask/src/production_closure.rs @@ -380,10 +380,9 @@ fn check_outputs(root: &Path) -> Result, String> { let advisory = policy .get(&spec.key()) .ok_or_else(|| format!("missing advisory context {}", spec.key()))?; - let approval = advisory.approval.clone(); let expected_production = serde_json::to_string_pretty(&with_approval( &computed.production, - Some(approval.clone()), + Some(advisory.approval.clone()), )) .map_err(|error| format!("serialize production closure: {error}"))? + "\n"; From 5f04f2119f3091d139449600842139589ca74eed Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:20 -0700 Subject: [PATCH 090/726] xtask: borrow ratchet keys, slice member lists, and end SeedSelfBinding scans at close --- packages/xtask/src/provider_crate_policy.rs | 37 +++++++++------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index 37117fb53..a76b824b9 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -574,7 +574,7 @@ pub fn check(repo_root: &Path) -> Result<(), String> { .canonicalize() .map_err(|_| "provider-crate-layout-input-unreadable".to_owned())?; let members = cargo_workspace_members(&repo_root)?; - check_members(&repo_root, members.clone())?; + check_members(&repo_root, &members)?; check_closed_matrix(&repo_root, &members)?; check_bazel_dependency_visibility(&repo_root)?; check_committed_scope(&repo_root, &members)?; @@ -5196,14 +5196,14 @@ fn check_shared_family_knowledge_with( ratchet: &[SharedFamilyKnowledgeExemption], ) -> Result<(), String> { let signals = collect_family_signals(repo_root)?; - let exempt: BTreeSet<(String, &str)> = ratchet + let exempt: BTreeSet<(&str, &str)> = ratchet .iter() - .map(|row| (row.module.to_owned(), row.token)) + .map(|row| (row.module, row.token)) .collect(); let mut violations = Vec::new(); for signal in &signals { - if !exempt.contains(&(signal.module.clone(), signal.token)) { + if !exempt.contains(&(signal.module.as_str(), signal.token)) { violations.push(render_family_knowledge_violation(signal)); } } @@ -6356,9 +6356,9 @@ fn check_shared_structural_knowledge_with( .iter() .map(|row| (row.module, row.class, row.symbol)) .collect(); - let family_exempt: BTreeSet<(String, &str)> = family_ratchet + let family_exempt: BTreeSet<(&str, &str)> = family_ratchet .iter() - .map(|row| (row.module.to_owned(), row.token)) + .map(|row| (row.module, row.token)) .collect(); let mut violations = Vec::new(); @@ -6372,7 +6372,7 @@ fn check_shared_structural_knowledge_with( let covered_by_family = signal.class != StructuralSignalClass::ProviderId && signal.class != StructuralSignalClass::RoleLiteral && structural_symbol_token(&signal.symbol) - .is_some_and(|token| family_exempt.contains(&(signal.module.clone(), token))); + .is_some_and(|token| family_exempt.contains(&(signal.module.as_str(), token))); if covered_by_family { continue; } @@ -6660,13 +6660,8 @@ fn collect_self_binding_scope( pending_role = None; } if code_text(lines[stop]).trim() == "}" { - // A SeedSelfBinding row closes at a line whose trim is "}"; - // a multi-line row ends there too; clearing pendings keep - // the next row from inheriting a stale half. - if inner.contains("SeedSelfBinding") { - pending_subject = None; - pending_role = None; - } + // A SeedSelfBinding row closes at a line whose trim is "}". + break; } stop += 1; } @@ -7254,7 +7249,7 @@ fn apply_citation_fixes( } } spans.sort_by_key(|(start, _, _)| std::cmp::Reverse(*start)); - let mut line = lines[index].clone(); + let mut line = std::mem::take(&mut lines[index]); for (start, end, keep) in spans { let replacement: String = keep.map(String::from).unwrap_or_default(); line.replace_range(start..end, &replacement); @@ -7913,7 +7908,7 @@ fn is_citation_cue(text: &str) -> bool { matches!(text, "see" | "cf" | "in" | "from" | "under" | "at" | "per") } -fn check_members(repo_root: &Path, members: Vec) -> Result<(), String> { +fn check_members(repo_root: &Path, members: &[WorkspaceMember]) -> Result<(), String> { let on_disk = on_disk_providers(repo_root)?; let has_provider_member = members.iter().any(|member| { name_kind(&member.package_name, member.declares_driver) == ProviderNameKind::Provider @@ -7928,7 +7923,7 @@ fn check_members(repo_root: &Path, members: Vec) -> Result<(), .collect(); let mut violations = Vec::new(); - for member in &members { + for member in members { match name_kind(&member.package_name, member.declares_driver) { ProviderNameKind::Provider => { if !is_provider_directory(repo_root, &member.crate_dir, &member.package_name) { @@ -8740,14 +8735,14 @@ fn check_provider_crate_family_knowledge_with( ratchet: &[ProviderFamilyKnowledgeExemption], ) -> Result<(), String> { let signals = collect_provider_family_signals(repo_root, provider_crates)?; - let exempt: BTreeSet<(String, String, &str)> = ratchet + let exempt: BTreeSet<(&str, &str, &str)> = ratchet .iter() - .map(|row| (row.crate_name.to_owned(), row.module.to_owned(), row.token)) + .map(|row| (row.crate_name, row.module, row.token)) .collect(); let mut violations = Vec::new(); for signal in &signals { - if !exempt.contains(&(signal.crate_name.clone(), signal.module.clone(), signal.token)) { + if !exempt.contains(&(signal.crate_name.as_str(), signal.module.as_str(), signal.token)) { violations.push(render_provider_family_violation(signal)); } @@ -9557,7 +9552,7 @@ mod tests { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn check_fixture(root: &Path) -> Result<(), String> { let root = root.canonicalize().unwrap(); - check_members(&root, manifest_workspace_members(&root)?) + check_members(&root, &manifest_workspace_members(&root)?) } impl Drop for Fixture { From 44a90ab5eacb9a868885a83ad4395a7651287389 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:21 -0700 Subject: [PATCH 091/726] xtask: share borrowed strings through nix string lists --- packages/xtask/src/provider_packaging.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xtask/src/provider_packaging.rs b/packages/xtask/src/provider_packaging.rs index cd120e7b4..f59d3d52f 100644 --- a/packages/xtask/src/provider_packaging.rs +++ b/packages/xtask/src/provider_packaging.rs @@ -160,12 +160,12 @@ fn nix_string(value: &str) -> String { escaped } -fn nix_string_list(values: impl IntoIterator, indent: usize) -> String { +fn nix_string_list>(values: impl IntoIterator, indent: usize) -> String { let pad = " ".repeat(indent); let inner = " ".repeat(indent + 2); let mut out = String::from("[\n"); for value in values { - out.push_str(&format!("{inner}{}\n", nix_string(&value))); + out.push_str(&format!("{inner}{}\n", nix_string(value.as_ref()))); } out.push_str(&format!("{pad}]")); out From 02238dbdd17f91ec9d295a479d77de1b6619b208 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:21 -0700 Subject: [PATCH 092/726] xtask: borrow schema ref patterns and allowed types --- .../xtask/src/semantic_service_schemas.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/xtask/src/semantic_service_schemas.rs b/packages/xtask/src/semantic_service_schemas.rs index 625c4e659..ccabdbbb0 100644 --- a/packages/xtask/src/semantic_service_schemas.rs +++ b/packages/xtask/src/semantic_service_schemas.rs @@ -29,7 +29,7 @@ use serde_json::{Value, json}; /// The subdirectory the committed artifacts live in. const OUT_DIR: &str = "docs/reference/schemas/v3"; -fn resource_ref_schema(pattern: String, allowed_types: &[String]) -> Value { +fn resource_ref_schema(pattern: &str, allowed_types: &[&str]) -> Value { json!({ "type": "string", "pattern": pattern, @@ -41,18 +41,18 @@ fn resource_ref_schema(pattern: String, allowed_types: &[String]) -> Value { fn provider_ref_schema() -> Value { resource_ref_schema( - r"^Provider/[a-z][a-z0-9-]{0,62}$".to_owned(), - &[String::from("Provider")], + r"^Provider/[a-z][a-z0-9-]{0,62}$", + &["Provider"], ) } fn service_ref_schema(service_type: &str) -> Value { resource_ref_schema( - format!( + &format!( "^{}\\/[a-z][a-z0-9-]{{0,62}}$", service_type.replace('.', "\\.") ), - &[service_type.to_owned()], + &[service_type], ) } @@ -68,11 +68,8 @@ fn generic_resource_ref_schema(allowed_types: &[&str]) -> Value { format!("^(?:{alternatives})/[a-z][a-z0-9-]{{0,62}}$") }; resource_ref_schema( - pattern, - &allowed_types - .iter() - .map(|value| (*value).to_owned()) - .collect::>(), + &pattern, + allowed_types, ) } @@ -152,7 +149,7 @@ fn metadata_schema() -> Value { "pattern": "^[a-z][a-z0-9-]{0,62}$", }, "ownerRef": resource_ref_schema( - "^(?:[A-Z][A-Za-z0-9]{0,62}|[a-z][a-z0-9-]{0,62}\\.d2bus\\.org\\.[A-Z][A-Za-z0-9]{0,62})/[a-z][a-z0-9-]{0,62}$".to_owned(), + "^(?:[A-Z][A-Za-z0-9]{0,62}|[a-z][a-z0-9-]{0,62}\\.d2bus\\.org\\.[A-Z][A-Za-z0-9]{0,62})/[a-z][a-z0-9-]{0,62}$", &[], ), }, From f01a683c76f6433d482a3e94326dd9228cb36f5d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:20:21 -0700 Subject: [PATCH 093/726] xtask: render profile catalogs from borrowed wire variants --- packages/xtask/src/gen_broker_operations.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xtask/src/gen_broker_operations.rs b/packages/xtask/src/gen_broker_operations.rs index e5f03fa9c..fa04ccb01 100644 --- a/packages/xtask/src/gen_broker_operations.rs +++ b/packages/xtask/src/gen_broker_operations.rs @@ -769,7 +769,7 @@ fn write( Ok(path) } -fn string_list(items: impl IntoIterator, indent: &str) -> String { +fn string_list<'a>(items: impl IntoIterator, indent: &str) -> String { items .into_iter() .map(|item| format!("{indent}\"{item}\",\n")) @@ -838,10 +838,10 @@ fn optional_str_list(fields: &[String]) -> String { ) } -fn profile_catalog(rows: &[Row], profile: &str) -> Vec { +fn profile_catalog<'a>(rows: &'a [Row], profile: &str) -> Vec<&'a str> { rows.iter() .filter(|row| row.profiles.iter().any(|item| item == profile)) - .filter_map(|row| row.wire_variant.clone()) + .filter_map(|row| row.wire_variant.as_deref()) .collect() } From 715a420ba8f59e18ad6a9a126c503ff9ff9f367d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:21:10 -0700 Subject: [PATCH 094/726] audit: record the first two wave-1 slices Slices 1 and 4 disposed 68 rows: the broker's prose, idiom, and ownership rows, and the same lenses across the CLI, the bus, and the daemon runtime. --- .../2026-09-24-rust-skills-audit/ledger.md | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index aeb7d0076..f902c7651 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -31,27 +31,27 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | id | lens | cluster | sev | audit verdict | blast/effort | outcome | wave | commit | anchor | reason or policy citation | escalation | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| `RS-0037` | `idiom` | `d2b` | medium | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:688-706, packages/d2b/src/dispatch.rs:1169-1175` | | | -| `RS-0031` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/doctor.rs:529, packages/d2b/src/doctor.rs:579, packages/d2b/src/doctor.rs` | | | -| `RS-0036` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_doctor.rs:598-601` | | | -| `RS-0032` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/resource.rs:525, packages/d2b/src/resource.rs:546, packages/d2b/src/resou` | | | -| `RS-0033` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_audit.rs:805, packages/d2b/src/zone_audit.rs:838` | | | -| `RS-0034` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_audit.rs:349, packages/d2b/src/zone_audit.rs:395` | | | -| `RS-0035` | `idiom` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/zone_audit.rs:591, packages/d2b/src/zone_audit.rs:607` | | | +| `RS-0037` | `idiom` | `d2b` | medium | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | all_known_subcommands derived from parser via modern_cli_subcommands minus PROJECTION_COMMANDS; test updated; mutation (re-add up) fails updated assertion | | +| `RS-0031` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/doctor.rs` | PidfdEntries::state_detail() added; five detail matches replaced | | +| `RS-0036` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_doctor.rs` | summarize uses DoctorSummary::default() | | +| `RS-0032` | `idiom` | `d2b` | low | actionable | leaf | applied-variant | U2 | 0a4f73a1f | `packages/d2b/src/resource.rs` | typed/typed_noun consume TypedResourceArgs by value; 7 dispatch sites pass args.clone() because match binds by reference (deviation recorded | | +| `RS-0033` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | valid_hash deleted; call sites now use valid_digest | | +| `RS-0034` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | nested verify_chain() shared by v1/v2 validation paths | | +| `RS-0035` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | validate_fields(class, fields, fn) merged; thin wrappers keep both validators | | | `RS-0001` | `idiom` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:255, packages/d2b-audit/src/segment.rs:980, packages/d2b-` | | | | `RS-0002` | `idiom` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:103` | | | | `RS-0003` | `idiom` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/sink.rs:393, packages/d2b-audit/src/sink.rs:403` | | | -| `RS-0011` | `idiom` | `d2b-broker` | medium | actionable | leaf | | | | `src/ops/device_worker.rs:312-335, src/ops/device_worker.rs:339-369, src/ops/device_worker.` | | | -| `RS-0006` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/runtime.rs:10392, packages/d2b-broker/src/runtime.rs:10418, packag` | | | -| `RS-0007` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/runtime.rs:10132` | | | -| `RS-0008` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:2816-2820` | | | -| `RS-0009` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/exec_reconcile.rs:404, src/ops/exec_reconcile.rs:505, src/ops/exec_reconcile.rs:55` | | | -| `RS-0010` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/store_view_farm.rs:97-190, src/ops/store_view_farm.rs:228-300` | | | -| `RS-0012` | `idiom` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:424-464, src/envelope/mod.rs:466-493, src/envelope/mod.rs:540-565, src` | | | +| `RS-0011` | `idiom` | `d2b-broker` | medium | actionable | leaf | applied | U2 | c155578ca | `packages/d2b-broker/src/ops/device_worker.rs` | find_resource_row helper drives row_owner_ref/device_guest_owner/tpm_devices_of_guest | | +| `RS-0006` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 99d7247ee | `packages/d2b-broker/src/runtime.rs` | parse_common_flags helper extracted; parse_probe_flags now takes Vec; error strings preserved | | +| `RS-0007` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 99d7247ee | `packages/d2b-broker/src/runtime.rs` | push loop replaced with filter_map; foreign lock Err early return preserved; merged with RS-0006 in same commit | | +| `RS-0008` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | d2096735c | `packages/d2b-broker/src/sys.rs` | format_errno reversal now iter_mut/zip without intermediate allocation | | +| `RS-0009` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 4234afe18 | `packages/d2b-broker/src/ops/exec_reconcile.rs` | seven hand-copied absolute-path checks factored into require_absolute; error wording normalized; no test asserts old strings | | +| `RS-0010` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 5a2fa07c7 | `packages/d2b-broker/src/ops/store_view_farm.rs` | run_store_helper and store_helper_failure extracted; both namespaced builders share them | | +| `RS-0012` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | open/publish/init_trusted_context_store gated #[cfg(test)]; only in-crate test callers existed; Drop persist path left ungated | | | `RS-0004` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:136` | | | | `RS-0005` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:270, packages/d2b-broker-composition/src/seam.` | | | -| `RS-0013` | `idiom` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1773-1781` | | | -| `RS-0014` | `idiom` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/operations.rs:302-310` | | | +| `RS-0013` | `idiom` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | resolve_for_service uses filter_map+next() over collect-then-index; bus check+tests passed | | +| `RS-0014` | `idiom` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/operations.rs` | abort_destination uses drain(..).partition and aborts drained handles; tests passed | | | `RS-0015` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/kernel_client.rs:225-227` | | | | `RS-0016` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broke` | | | | `RS-0017` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/` | | | @@ -144,10 +144,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0113` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:672, packages/d2bd/src/shared_provider_effects.rs:` | | | | `RS-0107` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:6896` | | | | `RS-0110` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:21306-21319, packages/d2bd/src/composition.rs:21291` | | | -| `RS-0114` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `autostart.rs:228-245` | | | -| `RS-0115` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:789, packages/d2bd-runtime/src/unix_trans` | | | -| `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/guest_mode.rs:849, packages/d2bd-runtime/src/guest_component_ses` | | | -| `RS-0117` | `idiom` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:162` | | | +| `RS-0114` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/autostart.rs` | build_autostart_plan uses iterator partition into the two sorted Vec halves | | +| `RS-0115` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | fd extraction loops are filter_map+flatten collects | | +| `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/guest_mode.rs` | monotonic_tick deduped into runtime_util (LazyLock per repo std; lazy init preserved} | | +| `RS-0117` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | ConsoleSessionTable derives Default; manual impl deleted | | | `RS-0118` | `idiom` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:147, packages/xtask/src/gen_layer_catalogs.rs:158` | | | | `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.` | | | | `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_author` | | | @@ -156,20 +156,20 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:459` | | | | `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:6662, packages/xtask/src/provider_crate_policy` | | | | `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | | | -| `RS-0150` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:548, packages/d2b/src/debug.rs:472, packages/d2b/src/debug.rs` | | | -| `RS-0151` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:977` | | | -| `RS-0152` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/dispatch.rs:296-313, packages/d2b/src/dispatch.rs:347, packages/d2b/src/d` | | | -| `RS-0149` | `own` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/doctor.rs:1062, packages/d2b/src/doctor.rs:1069, packages/d2b/src/doctor.` | | | +| `RS-0150` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | cursor/page_token/reference moved into calls;call-site reassignment unchanged | | +| `RS-0151` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | try_parse_from consumes raw_args by value (sole caller, never reused) | | +| `RS-0152` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | host_error_envelope takes impl Into;;&format! results move in directly | | +| `RS-0149` | `own` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/doctor.rs` | json! literal clones dropped (schema_version, issue_kinds, issues) | | | `RS-0125` | `own` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/operation.rs:79` | | | -| `RS-0129` | `own` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/pidfd.rs:210` | | | -| `RS-0131` | `own` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:220` | | | -| `RS-0130` | `own` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:671` | | | +| `RS-0129` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | c3ac2bb59 | `packages/d2b-broker/src/ops/pidfd.rs` | redundant payload.argv.clone removed; impl param renamed _payload | | +| `RS-0131` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | b09261be0 | `packages/d2b-broker/src/ops/media.rs` | unwrap_or_else(/_/ vec![record]) in enroll; merged with RS-0630 docs in same commit | | +| `RS-0130` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | Bootstrap reply shrunk to Result<(),>; state.clone removal; merged with RS-0012/RS-0628 in same commit | | | `RS-0126` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:251, packages/d2b-broker-composi` | | | | `RS-0127` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:272` | | | | `RS-0128` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:340, packages/d2b-broker-composi` | | | -| `RS-0132` | `own` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:480, packages/d2b-bus/src/router.rs:2928` | | | -| `RS-0133` | `own` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/session/prologue.rs:72-78` | | | -| `RS-0134` | `own` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/session/contract.rs:1046-1056, packages/d2b-bus/src/session/zone_link` | | | +| `RS-0132` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | ScopedCommitTransport::validate added; authorization_request validates borrowed data instead of cloning | | +| `RS-0133` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/prologue.rs` | of_subject hashes &str slices via hash_resource_ref; digest byte-identical (full bus suite passed | | +| `RS-0134` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/contract.rs` | private verify_body() shared by verify()/revalidate(); clone removed | | | `RS-0137` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:497, packages/d2b-contracts-pro` | | | | `RS-0135` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:2497, packages/d2b-contracts-provider/s` | | | | `RS-0138` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:1591, packages/d2b-contrac` | | | @@ -256,10 +256,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0223` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:456, packages/d2bd/src/forward_rendezvous.rs:458-4` | | | | `RS-0220` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20638` | | | | `RS-0224` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:690, packages/d2bd/src/shared_provider_effect` | | | -| `RS-0225` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `dag.rs:423-424` | | | -| `RS-0226` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:625, packages/d2bd-runtime/src/unsafe_loc` | | | -| `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:250, packages/d2bd-runtime/src/console_sessio` | | | -| `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/daemon_audit.rs:976, packages/d2bd-runtime/src/daemon_audit.rs:1` | | | +| `RS-0225` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/supervisor/dag.rs` | run_split matches &state, binds reason by ref,and moves state into api_ready afterwards | | +| `RS-0226` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | complete_pending takes &str; two call sites pass as_str; third kept to_string because E0505 forbids borrow+move of result in one call (deviation) | | +| `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | Borrow implemented; five map lookups/removes resolve without String alloc | | +| `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/daemon_audit.rs` | write_event* and enqueue take DaemonEvent by value, drop clone; caller migration in d2bd/src/composition.rs left to W1Daemon/orchestrator (cross-crate} | | | `RS-0231` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:577, packages/xtask/src/provider_crate_policy.` | | | | `RS-0236` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/production_closure.rs:263, packages/xtask/src/production_closure.rs:379` | | | | `RS-0238` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287` | | | @@ -655,33 +655,33 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0611` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/readiness.rs:327` | | | | `RS-0612` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132` | | | | `RS-0613` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:450` | | | -| `RS-0659` | `docs` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/exec_client.rs:497, packages/d2b/src/exec_client.rs:507, packages/d2b/src` | | | -| `RS-0658` | `docs` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/doctor.rs:91, packages/d2b/src/doctor.rs:163, packages/d2b/src/host_valid` | | | +| `RS-0659` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/exec_client.rs` | one-line docs for expect_start/expect_detached_create/list/logs/status/kill | | +| `RS-0658` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/doctor.rs` | docs for doctor/validate/CLI surface incl. crate-level doc | | | `RS-0614` | `docs` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:74, packages/d2b-audit/src/record_types.rs:428, packages/` | | | -| `RS-0624` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/fd_passing.rs:13, packages/d2b-broker/src/fd_passing.rs:31-70` | | | -| `RS-0630` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:35, packages/d2b-broker/src/ops/media.rs:167-186, pac` | | | -| `RS-0625` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:120-121, packages/d2b-broker/src/sys.rs:185, packages/d2b-b` | | | -| `RS-0631` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/protocol.rs:13, packages/d2b-broker/src/protocol.rs:16, packages/d` | | | -| `RS-0632` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/state_dir.rs:47, packages/d2b-broker/src/ops/state_dir.rs:53, ` | | | -| `RS-0621` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/audit.rs:124, packages/d2b-broker/src/audit.rs:84, packages/d2b-br` | | | +| `RS-0624` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 93ced15b2 | `packages/d2b-broker/src/fd_passing.rs` | doc comments added per row | | +| `RS-0630` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | b09261be0 | `packages/d2b-broker/src/ops/media.rs` | MediaOpError variants, outcome structs/fields, eight pub ops fns documented with # Errors | | +| `RS-0625` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | d2096735c | `packages/d2b-broker/src/sys.rs` | doc comments added; merged with RS-0008/RS-0626 in same commit | | +| `RS-0631` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | ba9873712 | `packages/d2b-broker/src/protocol.rs` | MAX_FRAME_SIZE and connect/bind/send_json_frame/recv_json_frame documented | | +| `RS-0632` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 6b709ea9a | `packages/d2b-broker/src/ops/state_dir.rs` | DirKind, PrepareDirRequest/fields, PrepareDirAudit, ReplaceOrCreateResult, prepare_dir and live helpers documented with # Errors | | +| `RS-0621` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 1643cd532 | `packages/d2b-broker/src/audit.rs` | field docs on AuditDropSummary/AuditEntry; contract docs on AuditLog::open/audit_drop_summary | | | `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | | | | `packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b` | | | -| `RS-0622` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/host_generation_handoff.rs:35` | | | -| `RS-0623` | `docs` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/route.rs:29` | | | -| `RS-0615` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:81, packages/d2b-broker/src/ops/usbip_lock.rs:90` | | | -| `RS-0617` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_host.rs:17, packages/d2b-broker/src/ops/usbip_host.rs:15` | | | -| `RS-0626` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:258, packages/d2b-broker/src/sys.rs:268, packages/d2b-broke` | | | -| `RS-0618` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/sysctl.rs:32, packages/d2b-broker/src/ops/sysctl.rs:40, packag` | | | -| `RS-0619` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:21` | | | -| `RS-0620` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/pidfd.rs:112, packages/d2b-broker/src/ops/pidfd.rs:191, packag` | | | -| `RS-0627` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/store_view_farm.rs:66-72, src/ops/store_view_farm.rs:191-197` | | | -| `RS-0628` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:1118, src/envelope/mod.rs:1136, src/envelope/mod.rs:1187` | | | -| `RS-0629` | `docs` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/nm.rs:293-301, src/ops/nm.rs:303-308` | | | -| `RS-0633` | `docs` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1126, packages/d2b-bus/src/router.rs:1135, packages/d2b-bus` | | | -| `RS-0637` | `docs` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/operations.rs:124-125` | | | -| `RS-0634` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:67-68` | | | -| `RS-0635` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1895, packages/d2b-bus/src/authorization.rs:401, packages/d` | | | -| `RS-0636` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:3709, packages/d2b-bus/src/router.rs:3261, packages/d2b-bus` | | | -| `RS-0638` | `docs` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/streams.rs:39-40, packages/d2b-bus/src/operations.rs:24-25, packages/` | | | +| `RS-0622` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 7ac3d8cdf | `packages/d2b-broker/src/ops/host_generation_handoff.rs` | doc comments added per row | | +| `RS-0623` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 025b075a8 | `packages/d2b-broker/src/ops/route.rs` | doc comments added per row | | +| `RS-0615` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 34f355adf | `packages/d2b-broker/src/ops/usbip_lock.rs` | doc comments added per row | | +| `RS-0617` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 4bfa5fd51 | `packages/d2b-broker/src/ops/usbip_host.rs` | doc comments added per row | | +| `RS-0626` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | d2096735c | `packages/d2b-broker/src/sys.rs` | doc comments added; merged with RS-0008/RS-0625 in same commit | | +| `RS-0618` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 7cf9b6478 | `packages/d2b-broker/src/ops/sysctl.rs` | doc comments added per row | | +| `RS-0619` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 380e073d5 | `packages/d2b-broker/src/ops/storage_contract.rs` | doc comments added per row | | +| `RS-0620` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | e507a1e71 | `packages/d2b-broker/src/ops/mod.rs` | doc comments added per row | | +| `RS-0627` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 5a2fa07c7 | `packages/d2b-broker/src/ops/store_view_farm.rs` | journal sentence trimmed and # Errors block added; merged with RS-0010 in same commit | | +| `RS-0628` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | # Errors blocks on call/call_with_fds/call_nested_with_fds naming ENVELOPE_REFUSALS vocabulary; merged | | +| `RS-0629` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 098cdc0e5 | `packages/d2b-broker/src/ops/nm.rs` | apply_with_reload/remove_with_reload docs rewritten as plain contracts | | +| `RS-0633` | `docs` | `d2b-bus` | medium | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | docs for BusEvent/BusFailureReason variants,and BusObserver methods | | +| `RS-0637` | `docs` | `d2b-bus` | medium | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/operations.rs` | Cancellation docs: minted by bus, one attempt, is_cancelled | | +| `RS-0634` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | one-line docs for DEFAULT_MAX_ROUTES_PER_SESSION,and DEFAULT_MAX_TOTAL_ROUTES | | +| `RS-0635` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/router.rs` | docs for install body, authz error class, session-failure accessors, as_str wire labels | | +| `RS-0636` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/router.rs` | # Errors on BusIngress::invoke, ZoneRegistrar::register_component_session,and BusEndpoint::invoke | | +| `RS-0638` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/streams.rs` | # Errors on StreamName::parse, OperationId::parse, ZoneBoundPolicyIdentity::digest,and ZoneEndpointPolicy::lower | | | `RS-0639` | `docs` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src` | | | | `RS-0640` | `docs` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/br` | | | | `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130` | | | @@ -784,15 +784,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0735` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:8294, packages/d2bd/src/resource_runtime.rs:8390, pa` | | | | `RS-0740` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_effects.rs:91, packages/d2bd/src/provider_effects.rs:711, packa` | | | | `RS-0742` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:1046-1049, packages/d2bd/src/forward_rendezvous.rs` | | | -| `RS-0743` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `json_io.rs:10, json_io.rs:41` | | | -| `RS-0747` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:1, packages/d2bd-runtime/src/unsafe_local` | | | -| `RS-0744` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `vm_start_support.rs:14, vm_start_support.rs:44, vm_start_support.rs:89` | | | -| `RS-0748` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `packages/d2bd-runtime/src/exec_session.rs:181, packages/d2bd-runtime/src/exec_session.rs:2` | | | -| `RS-0749` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `packages/d2bd-runtime/src/readiness.rs:15, packages/d2bd-runtime/src/readiness.rs:78, pack` | | | -| `RS-0745` | `docs` | `d2bd-runtime` | medium | actionable | leaf | | | | `broker_transport.rs:60, broker_transport.rs:69, broker_transport.rs:116, broker_transport.` | | | -| `RS-0746` | `docs` | `d2bd-runtime` | low | actionable | leaf | | | | `ssh_host_key_preflight.rs:312, ssh_host_key_preflight.rs:298-301` | | | -| `RS-0750` | `docs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/ch_api.rs:11, packages/d2bd-runtime/src/ch_api.rs:15, packages/d` | | | -| `RS-0751` | `docs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/target_runtime.rs:256, packages/d2bd-runtime/src/target_runtime.` | | | +| `RS-0743` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/json_io.rs` | resolve_bundle_artifact_path and load_manifest documented (+# Errors) | | +| `RS-0747` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | module doc plus consts, enums, HelperRegistry struct,and its 7 pub methods documented | | +| `RS-0744` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/vm_start_support.rs` | VmStartNodeMode enum, vm_start_node_mode, tracked_role_id,and store-view resolver documented | | +| `RS-0748` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/exec_session.rs` | exec-session DTO fields documented (ExecStartSpec, ExecSessionInfo, Established, WorkerSpawn) | | +| `RS-0749` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/readiness.rs` | six readiness predicates/functions documented (+# Errors);async twin was already documented | | +| `RS-0745` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/broker_transport.rs` | 5 broker-transport helpers documented;default_audit_join_context has no panic post-wave0 (re-verified) | | +| `RS-0746` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ssh_host_key_preflight.rs` | workflow tokens dropped from doc and trace comment; 0440-with-ACL why kept | | +| `RS-0750` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ch_api.rs` | consts with provenance, ChApiError variants, ChVmInfo fields,and both entry fns documented | | +| `RS-0751` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/target_runtime.rs` | AdmissionBudget/AdmissionPermit/ProviderDeployment accessors documented incl. release idempotence | | | `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packa` | | | | `RS-0756` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/` | | | | `RS-0754` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, pa` | | | From 6ef09c4c63dd90d65aec0bd3b8d4410c752b8105 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:21:43 -0700 Subject: [PATCH 095/726] audit: record wave-1 slice 3 and its leftovers Thirty-one rows applied across the resource runtime and xtask, three declined with their evidence, and the rows this slice never reached marked not-started for a follow-up dispatch. --- .../2026-09-24-rust-skills-audit/ledger.md | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index f902c7651..b0c45599d 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -125,11 +125,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2402` | | | | `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:1724` | | | | `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:1913` | | | -| `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:882, packages/d2b-resource-runtime/src/resour` | | | -| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:732, packages/d2b-resource-runtime/src/guest_t` | | | -| `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:1419, packages/d2b-resource-runtime/src/manag` | | | -| `RS-0098` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:581-584` | | | -| `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:83-88, packages/d2b-resource-runtime/src/s` | | | +| `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | derive Default on three unit structs; new() const kept | | +| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | declined | U2 | | `target.rs` | sort_by_key and sort_by_cached_key both rejected by rustc 1.97 (lifetime may not live long enough; closure returns (&str,&str,&str) borrowing the element); kept sort_by | | +| `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | shared free manager_rpc transport; both endpoints route through it | | +| `RS-0098` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | derive Default on TargetDirectory | | +| `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | impl FromStr for ResourceProvenance; store parses via str::parse | | | `RS-0100` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1802, engine.rs:1803, engine.rs:1807` | | | | `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:1593, admission.rs:956, admission.rs:958` | | | | `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/config.rs:178` | | | @@ -148,13 +148,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0115` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | fd extraction loops are filter_map+flatten collects | | | `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/guest_mode.rs` | monotonic_tick deduped into runtime_util (LazyLock per repo std; lazy init preserved} | | | `RS-0117` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | ConsoleSessionTable derives Default; manual impl deleted | | -| `RS-0118` | `idiom` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:147, packages/xtask/src/gen_layer_catalogs.rs:158` | | | -| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.` | | | -| `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_author` | | | -| `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/nix_inventories.rs:721` | | | -| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473` | | | -| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:459` | | | -| `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:6662, packages/xtask/src/provider_crate_policy` | | | +| `RS-0118` | `idiom` | `xtask` | medium | actionable | leaf | applied | U2 | 80037234d | `gen_layer_catalogs.rs` | string_array deleted; ten call sites rerouted through string_slice | | +| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | not-started | U2 | | `packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 7eef023f9 | `resource_type_authority.rs` | three statements reindented | | +| `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | fc0353eb1 | `nix_inventories.rs` | applied-variant: generic S: AsRef + Display standard params (caller with Vec cannot feed &[&str]); call site passes STANDARD_RESOURCE_TYPES.as_slice() | | +| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | dead corrupted sanitizer strip line deleted; marker appears nowhere in generated files | | +| `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | dead close-block reset replaced with scan end at closing brace | | | `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | | | | `RS-0150` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | cursor/page_token/reference moved into calls;call-site reassignment unchanged | | | `RS-0151` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | try_parse_from consumes raw_args by value (sole caller, never reused) | | @@ -237,13 +237,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:1467, packages/d2b-resource-compiler/src/main.r` | | | | `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:269, packages/d2b-resource-compiler/src/main.rs` | | | | `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:704` | | | -| `RS-0206` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:205` | | | -| `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:520-541` | | | -| `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/resource.rs:714, packages/d2b-resource-runtime/src/resou` | | | -| `RS-0210` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:596-598` | | | -| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/metadata.rs:191` | | | -| `RS-0211` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:655, packages/d2b-resource-runtime/src/target.` | | | -| `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:1004-1009` | | | +| `RS-0206` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | observed_status filters before clone | | +| `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | insert_new takes StoredDesiredResource by value; ensure passes by move | | +| `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 0e6061c1e | `resource.rs` | pre_start moves row into state; clones only for ResourceContext::new | | +| `RS-0210` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | list binds borrowed selector str forms | | +| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | declined | U2 | | `metadata.rs` | ctx.spec::() returns Result<&Value,_>; Ok(spec) is E0308; the clone is required by the API | | +| `RS-0211` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 1f9423d9a | `target.rs` | assign moves assignment into map and clones once for return | | +| `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | json_object moves member values; 17 call sites updated | | | `RS-0213` | `own` | `d2b-session` | low | actionable | family | | | | `engine.rs:689, admission.rs:593` | | | | `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83` | | | | `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/engine.rs:345, packages/d2b-zone-routing/src/engine.rs:346` | | | @@ -260,16 +260,16 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0226` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | complete_pending takes &str; two call sites pass as_str; third kept to_string because E0505 forbids borrow+move of result in one call (deviation) | | | `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | Borrow implemented; five map lookups/removes resolve without String alloc | | | `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/daemon_audit.rs` | write_event* and enqueue take DaemonEvent by value, drop clone; caller migration in d2bd/src/composition.rs left to W1Daemon/orchestrator (cross-crate} | | -| `RS-0231` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:577, packages/xtask/src/provider_crate_policy.` | | | -| `RS-0236` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/production_closure.rs:263, packages/xtask/src/production_closure.rs:379` | | | -| `RS-0238` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287` | | | -| `RS-0232` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:5200, packages/xtask/src/provider_crate_policy` | | | -| `RS-0237` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/production_closure.rs:383, packages/xtask/src/production_closure.rs:386` | | | -| `RS-0234` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_packaging.rs:163, packages/xtask/src/provider_packaging.rs:206` | | | -| `RS-0233` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:844, packages/xtask/src/gen_broker_operations.` | | | -| `RS-0235` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/semantic_service_schemas.rs:32, packages/xtask/src/semantic_service_sch` | | | -| `RS-0229` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:7257` | | | -| `RS-0230` | `own` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:6375, packages/xtask/src/provider_crate_policy` | | | +| `RS-0231` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | check_members takes &[WorkspaceMember]; caller clones dropped; second caller borrows result | | +| `RS-0236` | `own` | `xtask` | low | actionable | leaf | declined | U2 | | `production_closure.rs` | compute_* take ContextSpec by value today; ComputedContext struct owns spec; changing to &ContextSpec forces internal clones at the struct literals (= no net clone removal; E0308 evidence); reverted | | +| `RS-0238` | `own` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0232` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | family-knowledge exempt set keys &str pairs; probe via as_str | | +| `RS-0237` | `own` | `xtask` | low | actionable | leaf | applied | U2 | be3e0744b | `production_closure.rs` | duplicate approval clone binding removed; single clone at with_approval call | | +| `RS-0234` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 44a90ab5e | `provider_packaging.rs` | nix_string_list generic over AsRef; eight to_owned closures deleted | | +| `RS-0233` | `own` | `xtask` | low | actionable | leaf | applied | U2 | f01a683c7 | `gen_broker_operations.rs` | profile_catalog returns Vec<&str> via as_deref; string_list items are &str | | +| `RS-0235` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 02238dbdd | `semantic_service_schemas.rs` | resource_ref_schema takes &str/&[&str]; five call sites pass borrowed forms | | +| `RS-0229` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | mem::take on the mut slot before in-place edit | | +| `RS-0230` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | two ratchet probes key borrowed strs via signal fields | | | `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | | | | `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_` | | | | `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | @@ -761,11 +761,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0718` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, pa` | | | | `RS-0717` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `service.rs:198, store.rs:39, adapter.rs:71, manager_backend.rs:625` | | | | `RS-0719` | `docs` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:` | | | -| `RS-0720` | `docs` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:1500, packages/d2b-resource-runtime/src/manag` | | | -| `RS-0721` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:850, packages/d2b-resource-runtime/src/manage` | | | -| `RS-0722` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:51, packages/d2b-resource-runtime/src/resourc` | | | -| `RS-0723` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:205-228` | | | -| `RS-0724` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/identity.rs:20, packages/d2b-resource-runtime/src/identi` | | | +| `RS-0720` | `docs` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | # Errors on all 14 ResourceManagerClient pub methods | | +| `RS-0721` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | ResourceManagerArgs.store/providers documented | | +| `RS-0722` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | MODULE_NAME docs on five modules | | +| `RS-0723` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | TargetControlAssignment five methods documented | | +| `RS-0724` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | doc contracts on target/spec/identity accessors | | | `RS-0725` | `docs` | `d2b-resource-types` | low | actionable | leaf | | | | `packages/d2b-resource-types/src/operation.rs:64, packages/d2b-resource-types/src/operation` | | | | `RS-0726` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239` | | | | `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62` | | | @@ -793,11 +793,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0746` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ssh_host_key_preflight.rs` | workflow tokens dropped from doc and trace comment; 0440-with-ACL why kept | | | `RS-0750` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ch_api.rs` | consts with provenance, ChApiError variants, ChVmInfo fields,and both entry fns documented | | | `RS-0751` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/target_runtime.rs` | AdmissionBudget/AdmissionPermit/ProviderDeployment accessors documented incl. release idempotence | | -| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packa` | | | -| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/` | | | -| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, pa` | | | -| `RS-0752` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:5360, packages/xtask/src/provider_crate_policy` | | | -| `RS-0753` | `docs` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:1555, packages/xtask/src/main.rs:1544` | | | +| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | not-started | U2 | | `packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packa` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, pa` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0752` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | 6668d84dd | `provider_crate_policy.rs` | four doubled parens and whiche typo fixed; the audit's trailing \. doc lines do not exist at HEAD (grep zero), so that component is stale | | +| `RS-0753` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | doc comments above today_utc_iso8601 and civil_from_days naming the Hinnant algorithm, constants, and epoch fallback | | | `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | | | | `context.rs:570, context.rs:538` | | | | `RS-0757` | `perf` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970` | | | | `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | | | | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | | | From fda87abbe06ac5ab3b0033cadbc8a0994003fd38 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:22:41 -0700 Subject: [PATCH 096/726] transport-vsock: simplify disconnect and document error contracts --- .../d2b-provider-transport-vsock/src/auth.rs | 23 ++++++- .../src/bridge.rs | 11 ++++ .../src/framing.rs | 16 +++++ .../d2b-provider-transport-vsock/src/relay.rs | 55 ++++++++++++++++ .../src/service.rs | 65 +++++++++++++++++++ .../src/settings.rs | 12 ++++ .../src/topology.rs | 15 +++++ 7 files changed, 194 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-transport-vsock/src/auth.rs b/packages/d2b-provider-transport-vsock/src/auth.rs index ba25d0d28..9490cab8b 100644 --- a/packages/d2b-provider-transport-vsock/src/auth.rs +++ b/packages/d2b-provider-transport-vsock/src/auth.rs @@ -56,6 +56,12 @@ pub struct GuestIdentity { impl GuestIdentity { /// Construct one exact Guest identity. + /// + /// # Errors + /// + /// Returns [`SessionRejectReason::GuestMismatch`] when the reference + /// does not name a `Guest`, and [`SessionRejectReason::MalformedProof`] + /// when the boot id is empty or exceeds 128 bytes. pub fn new( guest: ResourceRef, zone: ZoneId, @@ -218,9 +224,8 @@ impl ReadySession { } /// Consume the authority on disconnect. - pub fn disconnect(mut self) -> SessionState { - self.state = SessionState::Disconnected; - self.state + pub fn disconnect(self) -> SessionState { + SessionState::Disconnected } } @@ -253,6 +258,18 @@ impl SessionAuthority { } /// Authenticate one proof and consume its nonce. + /// + /// # Errors + /// + /// Returns [`SessionRejectReason::CidMismatch`] when the observed or + /// proof CID is not the bound one, [`SessionRejectReason::GuestMismatch`] + /// or [`SessionRejectReason::ZoneMismatch`] when the proof names another + /// Guest or Zone, [`SessionRejectReason::StaleSignature`] when the boot + /// id or generation is stale, [`SessionRejectReason::Replay`] when the + /// nonce was already admitted, [`SessionRejectReason::AuthorityUnavailable`] + /// when the replay ledger is full, and + /// [`SessionRejectReason::SignatureInvalid`] when the tag does not + /// verify. pub fn authenticate( &mut self, observed_cid: PeerCid, diff --git a/packages/d2b-provider-transport-vsock/src/bridge.rs b/packages/d2b-provider-transport-vsock/src/bridge.rs index 1f6945e09..a2c47d063 100644 --- a/packages/d2b-provider-transport-vsock/src/bridge.rs +++ b/packages/d2b-provider-transport-vsock/src/bridge.rs @@ -56,9 +56,20 @@ pub trait NamedStreamPort: Send + Sync + 'static { type Stream: AsyncRead + AsyncWrite + Unpin + Send + 'static; /// Open one named stream. + /// + /// # Errors + /// + /// Returns [`NamedStreamError::Capacity`] when the stream table is + /// full and [`NamedStreamError::Disconnected`] when the session is no + /// longer available. async fn open_named_stream(&self) -> Result<(NamedStreamId, Self::Stream), NamedStreamError>; /// Close one named stream. + /// + /// # Errors + /// + /// Returns [`NamedStreamError::Disconnected`] when the session is no + /// longer available. async fn close_named_stream(&self, stream: NamedStreamId) -> Result<(), NamedStreamError>; } diff --git a/packages/d2b-provider-transport-vsock/src/framing.rs b/packages/d2b-provider-transport-vsock/src/framing.rs index 0d11bd5c5..55f8c3b81 100644 --- a/packages/d2b-provider-transport-vsock/src/framing.rs +++ b/packages/d2b-provider-transport-vsock/src/framing.rs @@ -69,6 +69,15 @@ impl FramedVsockTransport { } /// Read one complete framed record. + /// + /// # Errors + /// + /// Returns [`TransportError::Closed`] after the transport was closed, + /// [`TransportError::InvalidFrame`] for an empty frame, + /// [`TransportError::FrameTooLarge`] when the declared length exceeds + /// the bound, and [`TransportError::Disconnected`], + /// [`TransportError::Truncated`], or [`TransportError::Io`] when the + /// underlying stream fails mid-record. pub async fn read_frame(&mut self) -> Result, TransportError> where S: AsyncRead + Unpin, @@ -94,6 +103,13 @@ impl FramedVsockTransport { } /// Write one complete framed record. + /// + /// # Errors + /// + /// Returns [`TransportError::Closed`] after the transport was closed, + /// [`TransportError::InvalidFrame`] for an empty payload, + /// [`TransportError::FrameTooLarge`] when the payload exceeds the + /// bound, and [`TransportError::Io`] when the underlying stream fails. pub async fn write_frame(&mut self, bytes: &[u8]) -> Result<(), TransportError> where S: AsyncWrite + Unpin, diff --git a/packages/d2b-provider-transport-vsock/src/relay.rs b/packages/d2b-provider-transport-vsock/src/relay.rs index 79fce27e6..b92ac77f8 100644 --- a/packages/d2b-provider-transport-vsock/src/relay.rs +++ b/packages/d2b-provider-transport-vsock/src/relay.rs @@ -104,12 +104,22 @@ pub trait RelayEffectPort: Send + Sync + 'static { type RelayProcess: Send + 'static; /// Reserve the exact Host-global CID before any effect starts. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::CidAuthorityConflict`] when another + /// relay owns the CID authority, or the error the effect port reports. async fn reserve_cid( &self, binding: &RelayBinding, ) -> Result; /// Bind the matching listener while retaining CID authority. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::ListenerUnavailable`] when the listener + /// could not be acquired, or the error the effect port reports. async fn bind_listener( &self, binding: &RelayBinding, @@ -117,6 +127,11 @@ pub trait RelayEffectPort: Send + Sync + 'static { ) -> Result; /// Start the native relay process. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::ProcessUnavailable`] when the relay + /// process could not be started, or the error the effect port reports. async fn spawn_relay( &self, binding: &RelayBinding, @@ -125,16 +140,37 @@ pub trait RelayEffectPort: Send + Sync + 'static { ) -> Result; /// Close the relay process. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::CloseUnconfirmed`] when closure was not + /// confirmed, or the error the effect port reports. async fn close_relay(&self, process: &Self::RelayProcess) -> Result<(), RelayEffectError>; /// Close the listener. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::CloseUnconfirmed`] when closure was not + /// confirmed, or the error the effect port reports. async fn close_listener(&self, listener: &Self::Listener) -> Result<(), RelayEffectError>; /// Release CID authority after listener and relay closure. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::CloseUnconfirmed`] when the release was + /// not confirmed, or the error the effect port reports. async fn release_cid(&self, reservation: &Self::CidReservation) -> Result<(), RelayEffectError>; /// Find a matching listener and relay during restart adoption. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::RestartMismatch`] when the observed + /// listener or process does not match the binding, or the error the + /// effect port reports. async fn observe( &self, binding: &RelayBinding, @@ -198,6 +234,13 @@ where } /// Acquire CID authority, bind the listener, and start the native relay. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::RestartMismatch`] when the session does + /// not match the relay binding, [`RelayEffectError::Transient`] when the + /// relay is not idle or closed, and otherwise the error the effect port + /// reports for the failing acquisition step. pub async fn start(&mut self, session: &ReadySession) -> Result<(), RelayEffectError> { if !session.matches(self.binding.guest()) { self.phase = RelayPhase::Degraded; @@ -284,6 +327,13 @@ where } /// Adopt only the exact matching listener and relay after restart. + /// + /// # Errors + /// + /// Returns [`RelayEffectError::Transient`] when the relay is not idle + /// or closed, [`RelayEffectError::RestartMismatch`] when no matching + /// observation exists or its binding differs, and otherwise the error + /// the effect port reports. pub async fn adopt(&mut self, reservation: P::CidReservation) -> Result<(), RelayEffectError> { if !matches!(self.phase, RelayPhase::Idle | RelayPhase::Closed) { return Err(RelayEffectError::Transient); @@ -311,6 +361,11 @@ where } /// Close the relay, then listener, then release CID authority. + /// + /// # Errors + /// + /// Returns the error the effect port reports for the first failing + /// closure step; the remaining steps are not attempted. pub async fn finalize(&mut self) -> Result<(), RelayEffectError> { if self.phase == RelayPhase::Closed { return Ok(()); diff --git a/packages/d2b-provider-transport-vsock/src/service.rs b/packages/d2b-provider-transport-vsock/src/service.rs index c40c54374..9e1bc702e 100644 --- a/packages/d2b-provider-transport-vsock/src/service.rs +++ b/packages/d2b-provider-transport-vsock/src/service.rs @@ -40,6 +40,11 @@ pub struct OpaqueEndpointId(String); impl OpaqueEndpointId { /// Parse one allocator-issued endpoint identity. + /// + /// # Errors + /// + /// Returns [`VsockEffectError::EffectRejected`] when the value is not + /// a valid opaque endpoint identity. pub fn parse(value: impl Into) -> Result { let value = value.into(); if valid_opaque_id(&value) { @@ -74,6 +79,11 @@ pub struct OpaqueBindingId(String); impl OpaqueBindingId { /// Parse one allocator-issued binding identity. + /// + /// # Errors + /// + /// Returns [`VsockEffectError::EffectRejected`] when the value is not + /// a valid opaque binding identity. pub fn parse(value: impl Into) -> Result { let value = value.into(); if valid_opaque_id(&value) { @@ -121,6 +131,14 @@ pub trait VsockEffectPort: Send + Sync + 'static { type Stream: AsyncRead + AsyncWrite + Unpin + Send + 'static; /// Open or accept one allocator-selected endpoint. + /// + /// # Errors + /// + /// Returns [`VsockEffectError::DeadlineExceeded`] when the deadline + /// expires, [`VsockEffectError::ConnectRefused`], + /// [`VsockEffectError::CidUnreachable`], or + /// [`VsockEffectError::PortConflict`] for the endpoint refusal modes, + /// or the error the effect port reports. async fn open( &self, endpoint_id: &OpaqueEndpointId, @@ -130,6 +148,10 @@ pub trait VsockEffectPort: Send + Sync + 'static { ) -> Result; /// Close one stream after the bridge has stopped. + /// + /// # Errors + /// + /// Returns the error the effect port reports when the close fails. async fn close(&self, stream: Self::Stream) -> Result<(), VsockEffectError>; } @@ -184,6 +206,12 @@ impl OpenTransportRequest { } /// Parse a wire-shaped request at the service boundary. + /// + /// # Errors + /// + /// Returns [`ServiceError::InvalidEndpointId`] when the endpoint id is + /// malformed and [`ServiceError::InvalidBindingId`] when the binding id + /// is malformed. pub fn from_raw( endpoint_id: impl Into, binding_id: impl Into, @@ -380,6 +408,22 @@ where } /// Open one authenticated transport and its named stream bridge. + /// + /// # Errors + /// + /// Returns [`ServiceError::SessionNotReady`] when the session is not + /// Ready, [`ServiceError::SessionIdentityMismatch`] when it is not + /// bound to this Provider's Guest and Zone, + /// [`ServiceError::InvalidDeadline`] or + /// [`ServiceError::InvalidSessionGeneration`] when the request fails + /// validation, [`ServiceError::SessionGenerationMismatch`] when the + /// request generation does not match the session, + /// [`ServiceError::ProviderOverloaded`] when the concurrency budget is + /// exhausted, [`ServiceError::Effect`] when the effect port refuses the + /// open or the deadline expires, [`ServiceError::StreamUnavailable`] + /// when the named stream cannot be created, and + /// [`ServiceError::CloseUnconfirmed`] when the failed open cannot be + /// confirmed closed. pub async fn open_transport( &self, session: &ReadySession, @@ -606,6 +650,12 @@ where } /// Close one transport. The bridge closes before the effect is released. + /// + /// # Errors + /// + /// Returns [`ServiceError::UnknownTransportHandle`] when the handle is + /// not owned by this service and [`ServiceError::CloseUnconfirmed`] + /// when the bridge did not close within its bounded grace period. pub async fn close_transport( &self, request: CloseTransportRequest, @@ -680,6 +730,11 @@ where } /// Observe one transport snapshot without exposing identity, path, CID, or port. + /// + /// # Errors + /// + /// Returns [`ServiceError::UnknownTransportHandle`] when the handle is + /// not owned by this service. pub async fn observe_snapshot( &self, request: ObserveTransportRequest, @@ -720,6 +775,11 @@ where } /// Subscribe to one transport's bounded lifecycle event stream. + /// + /// # Errors + /// + /// Returns [`ServiceError::UnknownTransportHandle`] when the handle is + /// not owned by this service. pub async fn observe_transport( &self, request: ObserveTransportRequest, @@ -774,6 +834,11 @@ where } /// Finalize all handles owned by this service. + /// + /// # Errors + /// + /// Returns the first error [`Self::close_transport`] reports; the + /// remaining handles are still finalized. pub async fn finalize(&self) -> Result<(), ServiceError> { let handles = self.active.lock().await.keys().copied().collect::>(); let mut first_error = None; diff --git a/packages/d2b-provider-transport-vsock/src/settings.rs b/packages/d2b-provider-transport-vsock/src/settings.rs index 61b6aaf06..9f316402a 100644 --- a/packages/d2b-provider-transport-vsock/src/settings.rs +++ b/packages/d2b-provider-transport-vsock/src/settings.rs @@ -28,6 +28,12 @@ pub struct VsockTransportSettings { impl VsockTransportSettings { /// Construct validated settings. + /// + /// # Errors + /// + /// Returns [`SettingsError::InvalidValue`] when the guest reference is + /// not a bounded `Guest/...` reference or the timeout is outside + /// `1..=60` seconds. pub fn new(guest_ref: impl Into) -> Result { let settings = Self { guest_ref: guest_ref.into(), @@ -39,6 +45,12 @@ impl VsockTransportSettings { } /// Validate settings and reject raw endpoint material. + /// + /// # Errors + /// + /// Returns [`SettingsError::InvalidValue`] when the guest reference is + /// not a bounded `Guest/...` reference or the timeout is outside + /// `1..=60` seconds. pub fn validate(&self) -> Result<(), SettingsError> { if !self.guest_ref.starts_with("Guest/") || self.guest_ref.len() <= "Guest/".len() diff --git a/packages/d2b-provider-transport-vsock/src/topology.rs b/packages/d2b-provider-transport-vsock/src/topology.rs index 4c27e720d..3bfdb1676 100644 --- a/packages/d2b-provider-transport-vsock/src/topology.rs +++ b/packages/d2b-provider-transport-vsock/src/topology.rs @@ -81,6 +81,16 @@ impl From for TopologyError { impl ZoneLinkSpec { /// Validate the exact child-local topology. + /// + /// # Errors + /// + /// Returns [`TopologyError::ProviderMismatch`] when the selected + /// Provider is not the canonical vsock Provider, + /// [`TopologyError::ChildZoneMismatch`] when the child name does not + /// match the owning Zone, [`TopologyError::InvalidSettings`] when the + /// transport settings are invalid, and + /// [`TopologyError::CredentialsNotEmpty`] when the link carries + /// transport credentials. pub fn validate(&self, owning_child_zone: &str) -> Result<(), TopologyError> { if self.transport_provider_ref != crate::PROVIDER_REF { return Err(TopologyError::ProviderMismatch); @@ -107,6 +117,11 @@ pub struct ParentStoreResourceCensus { impl ParentStoreResourceCensus { /// Refuse any parent-side resource row for a child-local transport. + /// + /// # Errors + /// + /// Returns [`TopologyError::ParentStoreReciprocalResource`] when the + /// parent store carries a reciprocal Provider or ZoneLink row. pub fn validate(self) -> Result<(), TopologyError> { if self.provider_rows != 0 || self.zone_link_rows != 0 { return Err(TopologyError::ParentStoreReciprocalResource); From ef3bc5ec98cc3d7963f3eb83f2e43d8bd05668f6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:23:05 -0700 Subject: [PATCH 097/726] d2b-provider-command: state the contract constructor failures --- packages/d2b-provider-command/src/command.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/d2b-provider-command/src/command.rs b/packages/d2b-provider-command/src/command.rs index da5f4dd32..0f88b1dc7 100644 --- a/packages/d2b-provider-command/src/command.rs +++ b/packages/d2b-provider-command/src/command.rs @@ -35,6 +35,11 @@ pub struct CommandExec(String); impl CommandExec { /// Parse an absolute path with no control characters. + /// + /// # Errors + /// + /// Returns `InvalidExec` when the value is not an absolute, + /// control-free path within the byte bound. pub fn parse(value: impl Into) -> Result { let value = value.into(); if !value.starts_with('/') || value.len() > MAX_COMMAND_EXEC_BYTES { @@ -86,6 +91,12 @@ pub struct CommandArgvSlot(String); impl CommandArgvSlot { /// Parse one slot. A slot carrying a brace must be a single placeholder. + /// + /// # Errors + /// + /// Returns `InvalidArgvSlot` when the slot is empty, over bound, + /// contains a NUL byte, or is a brace-carrying slot that is not a + /// single placeholder naming a valid parameter. pub fn parse(value: impl Into) -> Result { let value = value.into(); if value.is_empty() || value.len() > MAX_COMMAND_ARGV_SLOT_BYTES { @@ -189,6 +200,13 @@ pub struct CommandSpec { impl CommandSpec { /// Construct a command spec after validating slots against parameters. + /// + /// # Errors + /// + /// Returns `InvalidArgvSlot` when the argument vector is empty or + /// over bound, `InvalidRoleRef` when the role reference does not name + /// a `Role`, and `UndefinedPlaceholder` when a placeholder slot names + /// a parameter the schema does not declare. pub fn new( exec: CommandExec, argv: Vec, From 4e381161fea9bf50304af74f11af12263f183d62 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:23:11 -0700 Subject: [PATCH 098/726] d2b-provider-operation: state the contract facet failures --- .../d2b-provider-operation/src/operation.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/d2b-provider-operation/src/operation.rs b/packages/d2b-provider-operation/src/operation.rs index ce54e0547..2b8a2bffc 100644 --- a/packages/d2b-provider-operation/src/operation.rs +++ b/packages/d2b-provider-operation/src/operation.rs @@ -135,6 +135,12 @@ pub struct OperationAudit { impl OperationAudit { /// Construct one audit facet after checking the field bounds. + + /// # Errors + /// + /// Returns `TooManyAuditFields` when the retained-field or + /// redaction-key list exceeds its bound. + pub fn new( required: bool, mode: AuditMode, @@ -191,6 +197,11 @@ pub struct AuditJoin { impl AuditJoin { /// Construct one audit-join facet after checking the field bound. + + /// # Errors + /// + /// Returns `InvalidAuditJoin` when the field list is empty or over + /// its bound. pub fn new(fields: Vec) -> Result { if fields.is_empty() || fields.len() > MAX_OPERATION_JOIN_FIELDS { return Err(OperationContractError::InvalidAuditJoin); @@ -344,6 +355,11 @@ pub struct OperationFds { impl OperationFds { /// Construct one fd contract after checking the list bounds. + + /// # Errors + /// + /// Returns `TooManyFds` when any of the request, response, or + /// preopened lists exceeds its bound. pub fn new( request: Vec, response: Vec, @@ -402,6 +418,11 @@ impl Default for OperationBounds { impl OperationBounds { /// Construct one bounds facet. + + /// # Errors + /// + /// Returns `InvalidBounds` when a limit is zero or exceeds its + /// ceiling. pub fn new( max_payload_bytes: u32, max_batch_entries: u32, @@ -471,6 +492,16 @@ pub struct OperationSpec { impl OperationSpec { /// Construct an operation spec after checking the facet invariants. + + /// # Errors + /// + /// Returns `InvalidOwnerRef` when the owner reference does not name + /// a `Command`, `InheritedWireTagOnMaterialized` when a materialized + /// operation carries a wire tag, `InvalidAuditJoin` when the join + /// names an undeclared or secret payload field, + /// `SecretAccessBelowPayload` when the payload declares secret + /// material without secret access, and `WriteOnlyRetainedField` + /// when the audit retains a write-only field. #[allow(clippy::too_many_arguments)] pub fn new( owner_ref: Option, From b29c0b8d29ee174f1fd0b20673a69e3863725d9e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:23:12 -0700 Subject: [PATCH 099/726] d2b-provider-credential-entra: state constructor and revocation failures --- .../src/controller.rs | 7 +++ .../d2b-provider-credential-entra/src/lib.rs | 48 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/packages/d2b-provider-credential-entra/src/controller.rs b/packages/d2b-provider-credential-entra/src/controller.rs index dcfa6aef6..aafa06600 100644 --- a/packages/d2b-provider-credential-entra/src/controller.rs +++ b/packages/d2b-provider-credential-entra/src/controller.rs @@ -44,6 +44,13 @@ pub struct EntraEndpointPolicy { impl EntraEndpointPolicy { /// Require canonical provider visibility and exact provider, consumer, /// and Guest execution references. + /// + /// # Errors + /// + /// Returns `OperationDenied` when the visibility is not `provider`, + /// the provider reference differs from the canonical one, the + /// consumer is not a `Provider`, or the execution reference is not a + /// `Guest`. pub fn new( visibility: &str, provider_ref: ResourceRef, diff --git a/packages/d2b-provider-credential-entra/src/lib.rs b/packages/d2b-provider-credential-entra/src/lib.rs index fcb2cf403..fe2d77351 100644 --- a/packages/d2b-provider-credential-entra/src/lib.rs +++ b/packages/d2b-provider-credential-entra/src/lib.rs @@ -49,6 +49,11 @@ pub const MAX_LOCAL_LEASES: u32 = 256; pub const MAX_REFRESH_ATTEMPTS: u16 = 3; /// Reject ambient SDK credential-chain environment names. +/// +/// # Errors +/// +/// Returns `InvalidConfig` when any ambient credential-chain name is +/// present. pub fn reject_ambient_credential_chain( keys: impl IntoIterator>, ) -> Result<(), EntraProviderError> { @@ -57,6 +62,11 @@ pub fn reject_ambient_credential_chain( } /// Reject ambient SDK credential-chain variables in this process. +/// +/// # Errors +/// +/// Returns `InvalidConfig` when any ambient credential-chain variable +/// is present in the process environment. pub fn reject_process_environment_credential_chain( ) -> Result<(), EntraProviderError> { d2b_provider_toolkit::credential::reject_process_environment_credential_chain() @@ -499,6 +509,12 @@ pub struct EntraConfig { impl EntraConfig { /// Validate the inline tenant identifier and lease bound. + /// + /// # Errors + /// + /// Returns `InvalidConfig` when the tenant identifier is not a valid + /// Azure reference or the lease bound is outside + /// `1..=MAX_LOCAL_LEASES`. pub fn new(tenant_id: impl Into, max_leases: u32) -> Result { let tenant_id = OpaqueAzureRef::parse(tenant_id.into()) .map_err(|_| EntraProviderError::InvalidConfig)?; @@ -571,6 +587,13 @@ pub struct EntraPlacement { impl EntraPlacement { /// Validate user-agent or guest-agent placement inside a Guest. + /// + /// # Errors + /// + /// Returns `InvalidPlacement` when the binding is not a user-agent or + /// guest-agent binding or the execution reference is not a `Guest`, + /// and `InvalidEndpoint` when the identity Guest or login Endpoint + /// reference is wrong or the endpoint generation is zero. pub fn new( binding: PlacementBinding, execution_ref: ResourceRef, @@ -602,6 +625,12 @@ impl EntraPlacement { } /// Validate placement with an authoritative Zone binding. + /// + /// # Errors + /// + /// Returns `InvalidEndpoint` when the zone reference is not a `Zone`, + /// and the same `InvalidPlacement` or `InvalidEndpoint` conditions as + /// [`EntraPlacement::new`] for the remaining arguments. pub fn new_in_zone( zone_ref: ResourceRef, binding: PlacementBinding, @@ -626,6 +655,13 @@ impl EntraPlacement { /// Bind a runtime controller to the exact Guest execution while leaving /// Endpoint resolution to the Guest-local typed client. + /// + /// # Errors + /// + /// Returns `InvalidEndpoint` when the zone reference is not a `Zone`, + /// the binding is not a user-agent or guest-agent binding, the + /// execution reference is not a `Guest`, or the endpoint generation + /// is zero. pub fn new_runtime_in_zone( zone_ref: ResourceRef, binding: PlacementBinding, @@ -845,6 +881,12 @@ pub struct EntraCredentialProviderFactory { impl EntraCredentialProviderFactory { /// Validate and construct a factory. + /// + /// # Errors + /// + /// Returns `InvalidConsumer` when the consumer reference is not a + /// `Provider`, and `InvalidEndpoint` when the placement carries no + /// Zone binding. pub fn new( config: EntraConfig, placement: EntraPlacement, @@ -1043,6 +1085,12 @@ impl EntraCredentialProvider { /// Revoke all handles owned by one Credential before finalization clears /// its Provider finalizer. + /// + /// # Errors + /// + /// Returns `Malformed` when the reference is not a `Credential`, and + /// `DeadlineExceeded` when the deadline is not a bounded future + /// absolute time. pub async fn revoke_owned_handles( &self, credential_ref: &ResourceRef, From e86206bab6b53ba916eba0166f0cca065cfbfe8b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:23:19 -0700 Subject: [PATCH 100/726] d2b-provider-credential-managed-identity: state constructor and projection failures --- .../src/controller.rs | 20 +++++++++++++++++ .../src/lib.rs | 22 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/packages/d2b-provider-credential-managed-identity/src/controller.rs b/packages/d2b-provider-credential-managed-identity/src/controller.rs index e85f4c8db..3ad889725 100644 --- a/packages/d2b-provider-credential-managed-identity/src/controller.rs +++ b/packages/d2b-provider-credential-managed-identity/src/controller.rs @@ -134,6 +134,11 @@ impl ManagedIdentityController { /// Create the agent projection only after admission and dependency /// readiness. The controller receives no client while doing so. + /// + /// # Errors + /// + /// Returns `CredentialServiceError::InvariantFailure` when the + /// reference is not a `Credential`. pub fn plan_agent( &self, credential_ref: ResourceRef, @@ -168,6 +173,11 @@ impl ManagedIdentityController { } /// Project bounded non-secret lease state. + /// + /// # Errors + /// + /// Returns `CredentialServiceError::InvariantFailure` when the + /// metadata cannot project into the lease or status shape. pub fn reconcile( &self, client_state: ManagedIdentityClientState, @@ -199,6 +209,11 @@ impl ManagedIdentityController { } /// Build a caller-initiated audit record after the authorization decision. + /// + /// # Errors + /// + /// Returns `CredentialObservabilityError::InvalidAuditRecord` when + /// the audit field set is malformed or sensitive. #[allow(clippy::too_many_arguments)] pub fn authorized_service_audit( &self, @@ -224,6 +239,11 @@ impl ManagedIdentityController { } /// Build one complete closed Credential telemetry frame. + /// + /// # Errors + /// + /// Returns `CredentialObservabilityError::ForbiddenTelemetryField` + /// when a telemetry key or value is not in the closed set. pub fn telemetry( &self, zone: &str, diff --git a/packages/d2b-provider-credential-managed-identity/src/lib.rs b/packages/d2b-provider-credential-managed-identity/src/lib.rs index c546ddf62..b41acbd26 100644 --- a/packages/d2b-provider-credential-managed-identity/src/lib.rs +++ b/packages/d2b-provider-credential-managed-identity/src/lib.rs @@ -446,6 +446,11 @@ pub enum ImdsEndpointAlias { impl ImdsEndpointAlias { /// Parse a closed alias without accepting a URL or path. + /// + /// # Errors + /// + /// Returns `InvalidConfig` when the value is not one of the closed + /// aliases. pub fn parse(value: &str) -> Result { match value { "azure-imds" => Ok(Self::AzureImds), @@ -511,6 +516,12 @@ pub struct ManagedIdentityClientConfig { impl ManagedIdentityClientConfig { /// Validate the inline client ID, closed alias, and lease ceiling. + /// + /// # Errors + /// + /// Returns `InvalidConfig` when the client ID is not a valid Azure + /// reference, the endpoint alias is not closed, or the lease ceiling + /// is outside `1..=MAX_LOCAL_LEASES`. pub fn new( client_id: impl Into, endpoint_alias: &str, @@ -589,6 +600,12 @@ pub struct ManagedIdentityPlacement { impl ManagedIdentityPlacement { /// Validate host-system or guest-agent placement bound to one Zone. + /// + /// # Errors + /// + /// Returns `InvalidPlacement` when the binding and execution + /// reference are not the `HostSystem`/`Host` or `GuestAgent`/`Guest` + /// pair, or the zone reference is not a `Zone`. pub fn new( binding: PlacementBinding, execution_ref: ResourceRef, @@ -793,6 +810,11 @@ pub struct ManagedIdentityCredentialProviderFactory { impl ManagedIdentityCredentialProviderFactory { /// Validate and construct the factory. + /// + /// # Errors + /// + /// Returns `InvalidConsumer` when the consumer reference is not a + /// `Provider`. pub fn new( config: ManagedIdentityClientConfig, placement: ManagedIdentityPlacement, From 8d910bf9c77c9e3a291255d51f03fa89b4b997eb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:23:54 -0700 Subject: [PATCH 101/726] refactor(device-gpu): share opaque-token shape, document error contracts --- .../d2b-provider-device-gpu/src/authority.rs | 176 +++++++++--------- .../d2b-provider-device-gpu/src/controller.rs | 37 +++- .../d2b-provider-device-gpu/src/effects.rs | 55 +++--- .../src/effects_service.rs | 2 +- .../d2b-provider-device-gpu/src/gpu_argv.rs | 26 ++- .../d2b-provider-device-gpu/src/process.rs | 16 ++ .../d2b-provider-device-gpu/src/settings.rs | 15 ++ .../d2b-provider-device-gpu/src/video_argv.rs | 18 +- .../d2b-provider-device-gpu/src/workers.rs | 10 + 9 files changed, 224 insertions(+), 131 deletions(-) diff --git a/packages/d2b-provider-device-gpu/src/authority.rs b/packages/d2b-provider-device-gpu/src/authority.rs index 44d399817..cb0d73ca5 100644 --- a/packages/d2b-provider-device-gpu/src/authority.rs +++ b/packages/d2b-provider-device-gpu/src/authority.rs @@ -13,76 +13,68 @@ use d2b_contracts_resource::v3::{ use crate::process::GpuProcessRole; -/// Core-derived identity for one physical GPU or render node backing. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct GpuBackingToken([u8; 32]); - -impl GpuBackingToken { - /// Construct a backing token at the trusted Core boundary. - pub const fn from_core(bytes: [u8; 32]) -> Self { - Self(bytes) - } - - /// Whether the token is the forbidden all-zero identity. - pub fn is_zero(&self) -> bool { - self.0 == [0; 32] - } - - /// Borrow the token for another trusted adapter comparison. - pub const fn as_bytes(&self) -> &[u8; 32] { - &self.0 - } -} - -impl fmt::Debug for GpuBackingToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("GpuBackingToken()") - } -} - -/// Core-derived platform identity for one GPU effect. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct GpuPlatformToken([u8; 32]); - -impl GpuPlatformToken { - /// Construct a platform token at the trusted Core boundary. - pub const fn from_core(bytes: [u8; 32]) -> Self { - Self(bytes) - } - - /// Whether the token is the forbidden all-zero identity. - pub fn is_zero(&self) -> bool { - self.0 == [0; 32] - } -} - -impl fmt::Debug for GpuPlatformToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("GpuPlatformToken()") - } -} - -/// Core-assigned worker principal. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct GpuPrincipalToken([u8; 32]); - -impl GpuPrincipalToken { - /// Construct a principal token at the trusted Core boundary. - pub const fn from_core(bytes: [u8; 32]) -> Self { - Self(bytes) - } +/// Generate an opaque `[u8; N]` token newtype with a redacting `Debug` impl +/// and the requested accessors. +macro_rules! opaque_token { + ($name:ident, $bytes:expr, $doc:literal, [$($derive:ident),*], [$($method:ident),*]) => { + #[doc = $doc] + #[derive($($derive),*)] + pub struct $name([u8; $bytes]); + + impl $name { + /// Construct a token at the trusted Core boundary. + pub const fn from_core(bytes: [u8; $bytes]) -> Self { + Self(bytes) + } + + $( + opaque_token!(@method $method $name $bytes); + )* + } - /// Whether the token is the forbidden all-zero identity. - pub fn is_zero(&self) -> bool { - self.0 == [0; 32] - } + impl fmt::Debug for $name { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str(concat!(stringify!($name), "()")) + } + } + }; + (@method is_zero $name:ident $bytes:expr) => { + /// Whether the token is the forbidden all-zero identity. + pub fn is_zero(&self) -> bool { + self.0 == [0; $bytes] + } + }; + (@method as_bytes $name:ident $bytes:expr) => { + /// Borrow the token for another trusted adapter comparison. + pub const fn as_bytes(&self) -> &[u8; $bytes] { + &self.0 + } + }; } -impl fmt::Debug for GpuPrincipalToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("GpuPrincipalToken()") - } -} +pub(crate) use opaque_token; + +opaque_token!( + GpuBackingToken, + 32, + "Core-derived identity for one physical GPU or render node backing.", + [Clone, PartialEq, Eq, PartialOrd, Ord, Hash], + [is_zero, as_bytes] +); +opaque_token!( + GpuPlatformToken, + 32, + "Core-derived platform identity for one GPU effect.", + [Clone, PartialEq, Eq, PartialOrd, Ord, Hash], + [is_zero] +); +opaque_token!( + GpuPrincipalToken, + 32, + "Core-assigned worker principal.", + [Clone, PartialEq, Eq, PartialOrd, Ord, Hash], + [is_zero] +); /// Opaque proof that a Device owner is authorized to hold GPU authority. #[derive(Clone, PartialEq, Eq)] @@ -96,6 +88,12 @@ pub struct GpuOwnerProof { impl GpuOwnerProof { /// Bind a proof to an exact Zone, holder, Device, Host, and generation. + /// + /// # Errors + /// + /// Returns [`GpuAuthorityError::WrongPrincipal`] when the Zone reference + /// is not a `Zone` resource or the holder reference is neither a `Guest` + /// nor a `Host` resource. pub fn new( zone_ref: ResourceRef, holder_ref: ResourceRef, @@ -164,6 +162,13 @@ pub struct GpuAuthorityAdmission { impl GpuAuthorityAdmission { /// Construct an admission before any device or process effect. + /// + /// # Errors + /// + /// Returns [`GpuAuthorityError::StaleDeviceIdentity`] when a backing, + /// platform, or principal token is the forbidden all-zero identity, and + /// [`GpuAuthorityError::ArbitrationViolation`] when the holder ceiling + /// or render-node mode contradicts the arbitration class. #[allow(clippy::too_many_arguments)] pub fn new( owner: GpuOwnerProof, @@ -197,6 +202,12 @@ impl GpuAuthorityAdmission { } /// Attach the distinct Core-assigned video principal. + /// + /// # Errors + /// + /// Returns [`GpuAuthorityError::PrincipalNotSeparated`] when the video + /// principal is the forbidden all-zero identity or equals the GPU + /// principal. pub fn with_video_principal( mut self, video_principal: GpuPrincipalToken, @@ -261,27 +272,13 @@ impl fmt::Debug for GpuAuthorityAdmission { } } -/// Opaque Host-global GPU lease. -#[derive(Clone, PartialEq, Eq)] -pub struct GpuAuthorityLease([u8; 16]); - -impl GpuAuthorityLease { - /// Construct a lease at the trusted authority adapter boundary. - pub const fn from_core(bytes: [u8; 16]) -> Self { - Self(bytes) - } - - /// Borrow the opaque lease token at the daemon adapter boundary. - pub const fn as_bytes(&self) -> &[u8; 16] { - &self.0 - } -} - -impl fmt::Debug for GpuAuthorityLease { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("GpuAuthorityLease()") - } -} +opaque_token!( + GpuAuthorityLease, + 16, + "Opaque Host-global GPU lease.", + [Clone, PartialEq, Eq], + [as_bytes] +); /// Opaque identity of one broker-supervised GPU worker. #[derive(Clone, PartialEq, Eq)] @@ -398,7 +395,7 @@ pub enum GpuAuthorityError { StaleDeviceIdentity, /// The arbitration and render-node settings disagree. ArbitrationViolation, - } +} impl GpuAuthorityError { /// Return the stable, identity-free error code. @@ -408,7 +405,6 @@ impl GpuAuthorityError { Self::PrincipalNotSeparated => "gpu-principal-not-separated", Self::StaleDeviceIdentity => "gpu-device-identity-stale", Self::ArbitrationViolation => "gpu-arbitration-violation", - } } } diff --git a/packages/d2b-provider-device-gpu/src/controller.rs b/packages/d2b-provider-device-gpu/src/controller.rs index aa0967ee0..e91699e5f 100644 --- a/packages/d2b-provider-device-gpu/src/controller.rs +++ b/packages/d2b-provider-device-gpu/src/controller.rs @@ -88,6 +88,11 @@ pub struct GpuController { impl GpuController { /// Construct an authority-bound controller from Core admission evidence. + /// + /// # Errors + /// + /// Returns [`GpuControllerError::Selection`] when the arbitration and + /// settings do not admit a GPU worker process. pub fn new_authorized( admission: GpuAuthorityAdmission, settings: GpuSettings, @@ -166,6 +171,16 @@ impl GpuController { /// The Host-global reservation is acquired before the first open or /// spawn and remains retained until [`Self::finalize_lifecycle`] confirms /// every worker closure. + /// + /// # Errors + /// + /// Returns [`GpuControllerError::InvalidState`] when the finalizer is + /// missing or the controller is in a terminal phase, + /// [`GpuControllerError::Authority`] when video is configured without a + /// separated principal, [`GpuControllerError::Selection`] when a worker + /// spec cannot be derived, and [`GpuControllerError::Effect`] when a + /// reservation, open, or spawn effect fails or a started worker identity + /// fails validation. pub fn reconcile_lifecycle( &mut self, port: &mut P, @@ -269,7 +284,6 @@ impl GpuController { GpuControllerError::Effect(error) })?; self.gpu_role = Some(spec.process().role()); - self.gpu_identity = Some(identity.clone()); if let Err(error) = validate_started_identity( &identity, spec.process().role(), @@ -277,6 +291,7 @@ impl GpuController { admission.platform(), generation, ) { + self.gpu_identity = Some(identity); self.phase = GpuPhase::Failed; tracing::warn!( device = %self.device_uid.to_canonical_string(), @@ -286,6 +301,7 @@ impl GpuController { ); return Err(GpuControllerError::Effect(error)); } + self.gpu_identity = Some(identity); } self.phase = GpuPhase::GpuReady; if self.settings.video_sidecar && self.video_identity.is_none() { @@ -322,7 +338,6 @@ impl GpuController { ); GpuControllerError::Effect(error) })?; - self.video_identity = Some(identity.clone()); self.video_started = true; if let Err(error) = validate_started_identity( &identity, @@ -331,6 +346,7 @@ impl GpuController { admission.platform(), generation, ) { + self.video_identity = Some(identity); self.phase = GpuPhase::Failed; tracing::warn!( device = %self.device_uid.to_canonical_string(), @@ -340,12 +356,24 @@ impl GpuController { ); return Err(GpuControllerError::Effect(error)); } + self.video_identity = Some(identity); } self.phase = GpuPhase::Ready; Ok(GpuReconcileOutcome::Converged) } /// Adopt matching GPU/video workers after a daemon restart. + /// + /// # Errors + /// + /// Returns [`GpuControllerError::InvalidState`] when the finalizer is + /// missing, the controller is in a terminal phase, or admission is + /// absent, [`GpuControllerError::Authority`] when video is configured + /// without a separated principal, + /// [`GpuControllerError::Selection`] when a worker spec cannot be + /// derived, [`GpuControllerError::Quarantined`] when the restart + /// observation is ambiguous, and [`GpuControllerError::Effect`] when a + /// probe effect fails or an observed identity does not match. pub fn adopt_lifecycle( &mut self, lease: GpuAuthorityLease, @@ -464,6 +492,11 @@ matched.push(observed); } /// Close workers and release Host-global authority after exact proofs. + /// + /// # Errors + /// + /// Returns [`GpuControllerError::Effect`] when a stop effect fails or a + /// closure proof does not match the stopped worker identity. pub fn finalize_lifecycle( &mut self, port: &mut P, diff --git a/packages/d2b-provider-device-gpu/src/effects.rs b/packages/d2b-provider-device-gpu/src/effects.rs index 1d8afaed9..ef0024736 100644 --- a/packages/d2b-provider-device-gpu/src/effects.rs +++ b/packages/d2b-provider-device-gpu/src/effects.rs @@ -4,28 +4,19 @@ use core::fmt; use crate::{ authority::{ - GpuAuthorityAdmission, GpuAuthorityLease, GpuClosureProof, GpuPlatformToken, + opaque_token, GpuAuthorityAdmission, GpuAuthorityLease, GpuClosureProof, GpuPlatformToken, GpuProcessIdentity, GpuProcessObservation, }, workers::{GpuWorkerSpec, VideoWorkerSpec}, }; -/// One Core-derived GPU device effect token. -#[derive(Clone, PartialEq, Eq)] -pub struct GpuEffectToken([u8; 32]); - -impl GpuEffectToken { - /// Construct a token at the Core adapter boundary. - pub const fn from_core(bytes: [u8; 32]) -> Self { - Self(bytes) - } -} - -impl fmt::Debug for GpuEffectToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("GpuEffectToken()") - } -} +opaque_token!( + GpuEffectToken, + 32, + "One Core-derived GPU device effect token.", + [Clone, PartialEq, Eq], + [] +); /// Opaque set of broker-resolved device grants. #[derive(Clone, PartialEq, Eq)] @@ -35,6 +26,11 @@ pub struct GpuEffectTokenSet { impl GpuEffectTokenSet { /// Construct a bounded token set supplied by Core. + /// + /// # Errors + /// + /// Returns [`GpuEffectError::DeviceQuotaExceeded`] when no token or more + /// than eight tokens are supplied. pub fn from_core(tokens: Vec) -> Result { if tokens.is_empty() || tokens.len() > 8 { return Err(GpuEffectError::DeviceQuotaExceeded); @@ -62,22 +58,13 @@ impl fmt::Debug for GpuEffectTokenSet { } } -/// Opaque worker LaunchTicket. -#[derive(Clone, PartialEq, Eq)] -pub struct GpuLaunchTicket([u8; 16]); - -impl GpuLaunchTicket { - /// Construct a ticket at the Core adapter boundary. - pub const fn from_core(bytes: [u8; 16]) -> Self { - Self(bytes) - } -} - -impl fmt::Debug for GpuLaunchTicket { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("GpuLaunchTicket()") - } -} +opaque_token!( + GpuLaunchTicket, + 16, + "Opaque worker LaunchTicket.", + [Clone, PartialEq, Eq], + [] +); /// Closed GPU effect failures. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -98,7 +85,7 @@ pub enum GpuEffectError { StaleDeviceIdentity, /// A Host-global claim conflicts with another owner. AuthorityConflict, -/// A worker closure did not prove the owned process was gone. + /// A worker closure did not prove the owned process was gone. CloseUnconfirmed, /// The frozen GPU/video wire contract diverged. WireContractMismatch, diff --git a/packages/d2b-provider-device-gpu/src/effects_service.rs b/packages/d2b-provider-device-gpu/src/effects_service.rs index 25d026609..5e245222a 100644 --- a/packages/d2b-provider-device-gpu/src/effects_service.rs +++ b/packages/d2b-provider-device-gpu/src/effects_service.rs @@ -190,7 +190,7 @@ impl<'a> DeclaredWorkerGpuPort<'a> { if view.owner_key.as_ref() != Some(&self.device_key()) { return Err(GpuEffectError::StaleDeviceIdentity); } - let _ = Self::declared_row_template(&view, role)?; + Self::declared_row_template(&view, role)?; Ok(Some(view)) } diff --git a/packages/d2b-provider-device-gpu/src/gpu_argv.rs b/packages/d2b-provider-device-gpu/src/gpu_argv.rs index 22f81f7d7..ef9520c68 100644 --- a/packages/d2b-provider-device-gpu/src/gpu_argv.rs +++ b/packages/d2b-provider-device-gpu/src/gpu_argv.rs @@ -21,7 +21,6 @@ //! the Guest controller does not receive or assemble it. //! //! Crate invariant `#![forbid(unsafe_code)]` is honoured. -#![allow(missing_docs)] use serde::{Deserialize, Serialize}; @@ -31,12 +30,16 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum GpuContextType { + /// The base virgl context. Virgl, + /// The virgl2 context. Virgl2, + /// The cross-domain context. CrossDomain, } impl GpuContextType { + /// Return the kebab-case context-type spelling used in `--params`. pub fn as_str(self) -> &'static str { match self { Self::Virgl => "virgl", @@ -100,11 +103,20 @@ pub struct GpuArgvInput { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", tag = "kind")] pub enum GpuArgvError { - InvalidCrosvmBinaryPath { path: String }, + /// The crosvm binary path is empty or not absolute. + InvalidCrosvmBinaryPath { + /// The offending path. + path: String, + }, + /// The VM name is empty. EmptyVmName, + /// The socket path is empty. EmptySocketPath, + /// The Wayland socket is empty. EmptyWaylandSock, + /// No context type is declared. EmptyContextTypes, + /// No display is declared. EmptyDisplays, } @@ -155,6 +167,16 @@ fn render_params(params: &GpuParams) -> Result { } /// Render the `crosvm device gpu` argv. +/// +/// # Errors +/// +/// Returns [`GpuArgvError::InvalidCrosvmBinaryPath`] when the binary path +/// is empty or not absolute, [`GpuArgvError::EmptyVmName`] when the VM +/// name is empty, [`GpuArgvError::EmptySocketPath`] when the socket path +/// is empty, [`GpuArgvError::EmptyWaylandSock`] when the Wayland socket +/// is empty, [`GpuArgvError::EmptyContextTypes`] when no context type is +/// declared, and [`GpuArgvError::EmptyDisplays`] when no display is +/// declared. pub fn generate_gpu_argv(input: &GpuArgvInput) -> Result, GpuArgvError> { if input.crosvm_binary_path.is_empty() || !input.crosvm_binary_path.starts_with('/') { return Err(GpuArgvError::InvalidCrosvmBinaryPath { diff --git a/packages/d2b-provider-device-gpu/src/process.rs b/packages/d2b-provider-device-gpu/src/process.rs index 756e4af9c..30491f677 100644 --- a/packages/d2b-provider-device-gpu/src/process.rs +++ b/packages/d2b-provider-device-gpu/src/process.rs @@ -26,6 +26,11 @@ pub struct GpuProcessDeclaration { impl GpuProcessDeclaration { /// Construct a declaration from a Device UID and selected role. + /// + /// # Errors + /// + /// Returns [`GpuProcessSelectionError::InvalidUid`] when the Device UID + /// cannot produce a canonical short name. pub fn new( device_uid: &ResourceUid, role: GpuProcessRole, @@ -75,6 +80,12 @@ impl fmt::Display for GpuProcessSelectionError { impl std::error::Error for GpuProcessSelectionError {} /// Select the worker set for one Device. +/// +/// # Errors +/// +/// Returns [`GpuProcessSelectionError::Settings`] when the settings fail +/// validation and [`GpuProcessSelectionError::InvalidUid`] when the Device +/// UID cannot produce a canonical short name. pub fn select_processes( device_uid: &ResourceUid, arbitration: DeviceArbitration, @@ -99,6 +110,11 @@ pub fn select_processes( } /// Derive the required `device--*` name. +/// +/// # Errors +/// +/// Returns [`GpuProcessSelectionError::InvalidUid`] when the Device UID +/// cannot produce a canonical short name. pub fn gpu_process_name( device_uid: &ResourceUid, role: GpuProcessRole, diff --git a/packages/d2b-provider-device-gpu/src/settings.rs b/packages/d2b-provider-device-gpu/src/settings.rs index a4b4b6086..273e3595d 100644 --- a/packages/d2b-provider-device-gpu/src/settings.rs +++ b/packages/d2b-provider-device-gpu/src/settings.rs @@ -75,6 +75,21 @@ impl Default for GpuSettings { impl GpuSettings { /// Validate bounds and the shared-arbitration/render-node invariant. + /// + /// # Errors + /// + /// Returns [`GpuSettingsError::ContextTypesOutOfRange`] when no context + /// type or more than three are declared, + /// [`GpuSettingsError::DuplicateContextType`] for a repeated context + /// type, [`GpuSettingsError::DisplaysOutOfRange`] for more than eight + /// displays, [`GpuSettingsError::SharedRequiresRenderNodeOnly`] when + /// shared arbitration is combined with a full GPU worker, + /// [`GpuSettingsError::VideoRequiresFullGpu`] when a video sidecar is + /// combined with a render-node-only worker, + /// [`GpuSettingsError::NvidiaDecodeRequiresVideoSidecar`] when NVIDIA + /// decode is set without a video sidecar, and + /// [`GpuSettingsError::VideoModesConflict`] when virgl video is combined + /// with a video sidecar. pub fn validate(&self, arbitration: DeviceArbitration) -> Result<(), GpuSettingsError> { if self.context_types.is_empty() || self.context_types.len() > 3 { return Err(GpuSettingsError::ContextTypesOutOfRange); diff --git a/packages/d2b-provider-device-gpu/src/video_argv.rs b/packages/d2b-provider-device-gpu/src/video_argv.rs index 7506d665b..e8f739e0a 100644 --- a/packages/d2b-provider-device-gpu/src/video_argv.rs +++ b/packages/d2b-provider-device-gpu/src/video_argv.rs @@ -19,7 +19,6 @@ //! decoded media stream. //! //! Crate invariant `#![forbid(unsafe_code)]` is honoured. -#![allow(missing_docs)] use serde::{Deserialize, Serialize}; @@ -96,10 +95,12 @@ pub fn wire_contract_snapshot() -> String { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum VideoBackend { + /// VAAPI decode (NVDEC through nvidia-vaapi-driver). Vaapi, } impl VideoBackend { + /// Return the kebab-case backend spelling used in `--backend`. pub fn as_str(self) -> &'static str { match self { Self::Vaapi => "vaapi", @@ -130,12 +131,25 @@ pub struct VideoArgvInput { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case", tag = "kind")] pub enum VideoArgvError { - InvalidCrosvmBinaryPath { path: String }, + /// The crosvm binary path is empty or not absolute. + InvalidCrosvmBinaryPath { + /// The offending path. + path: String, + }, + /// The VM name is empty. EmptyVmName, + /// The socket path is empty. EmptySocketPath, } /// Render the video-decoder argv. +/// +/// # Errors +/// +/// Returns [`VideoArgvError::InvalidCrosvmBinaryPath`] when the binary path +/// is empty or not absolute, [`VideoArgvError::EmptyVmName`] when the VM +/// name is empty, and [`VideoArgvError::EmptySocketPath`] when the socket +/// path is empty. pub fn generate_video_argv(input: &VideoArgvInput) -> Result, VideoArgvError> { if input.crosvm_binary_path.is_empty() || !input.crosvm_binary_path.starts_with('/') { return Err(VideoArgvError::InvalidCrosvmBinaryPath { diff --git a/packages/d2b-provider-device-gpu/src/workers.rs b/packages/d2b-provider-device-gpu/src/workers.rs index 4d8ad9b01..d4dbc8306 100644 --- a/packages/d2b-provider-device-gpu/src/workers.rs +++ b/packages/d2b-provider-device-gpu/src/workers.rs @@ -12,6 +12,11 @@ pub struct GpuWorkerSpec { impl GpuWorkerSpec { /// Build the fixed GPU or render-node worker shape. + /// + /// # Errors + /// + /// Returns [`GpuProcessSelectionError`] when the Device UID or role does + /// not admit a GPU worker process declaration. pub fn gpu( device_uid: &ResourceUid, settings: &GpuSettings, @@ -50,6 +55,11 @@ pub struct VideoWorkerSpec { impl VideoWorkerSpec { /// Build the separate video worker shape. + /// + /// # Errors + /// + /// Returns [`GpuProcessSelectionError`] when the Device UID or role does + /// not admit a video worker process declaration. pub fn new( device_uid: &ResourceUid, settings: &GpuSettings, From c4543b5ae8e89b76a0f1a448122dfd63e8655e57 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:24:22 -0700 Subject: [PATCH 102/726] refactor(d2b-provider-device-tpm): use the shared swtpm log-level bounds --- .../d2b-provider-device-tpm/src/swtpm_argv.rs | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/packages/d2b-provider-device-tpm/src/swtpm_argv.rs b/packages/d2b-provider-device-tpm/src/swtpm_argv.rs index ea687fc61..1aa82eb2b 100644 --- a/packages/d2b-provider-device-tpm/src/swtpm_argv.rs +++ b/packages/d2b-provider-device-tpm/src/swtpm_argv.rs @@ -36,10 +36,11 @@ //! starts the long-lived `swtpm socket` process. //! //! Crate invariant `#![forbid(unsafe_code)]` is honoured. -#![allow(missing_docs)] use serde::{Deserialize, Serialize}; +use crate::{MAX_SWTPM_LOG_LEVEL, MIN_SWTPM_LOG_LEVEL}; + /// All inputs required to render the long-lived `swtpm socket ...` /// argv. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -103,17 +104,32 @@ pub struct SwtpmIoctlFlushInput { #[serde(rename_all = "kebab-case", tag = "kind")] pub enum SwtpmArgvError { /// Binary path was empty or non-absolute. - InvalidBinaryPath { path: String }, + InvalidBinaryPath { + /// The offending path. + path: String, + }, /// `vm_name` was empty. EmptyVmName, /// `state_dir` was empty or non-absolute. - InvalidStateDir { path: String }, + InvalidStateDir { + /// The offending path. + path: String, + }, /// `ctrl_socket_path` or `server_socket_path` was empty. - EmptySocketPath { which: String }, + EmptySocketPath { + /// The empty field name. + which: String, + }, /// `log_path` or `pid_path` was empty. - EmptyFilePath { which: String }, + EmptyFilePath { + /// The empty field name. + which: String, + }, /// `log_level` was outside 1..=20. - LogLevelOutOfRange { level: u8 }, + LogLevelOutOfRange { + /// The offending log level. + level: u8, + }, } fn validate_absolute(path: &str, field: &str) -> Result<(), SwtpmArgvError> { @@ -127,6 +143,16 @@ fn validate_absolute(path: &str, field: &str) -> Result<(), SwtpmArgvError> { } /// Render the long-lived swtpm argv. +/// +/// # Errors +/// +/// Returns [`SwtpmArgvError::InvalidBinaryPath`] for an empty or +/// non-absolute swtpm binary path, [`SwtpmArgvError::EmptyVmName`] for an +/// empty VM name, [`SwtpmArgvError::InvalidStateDir`] for an empty or +/// non-absolute state directory, [`SwtpmArgvError::EmptySocketPath`] or +/// [`SwtpmArgvError::EmptyFilePath`] for empty socket or file paths, and +/// [`SwtpmArgvError::LogLevelOutOfRange`] when the log level is outside the +/// frozen bound. pub fn generate_swtpm_argv(input: &SwtpmArgvInput) -> Result, SwtpmArgvError> { if input.swtpm_binary_path.is_empty() || !input.swtpm_binary_path.starts_with('/') { return Err(SwtpmArgvError::InvalidBinaryPath { @@ -157,7 +183,7 @@ pub fn generate_swtpm_argv(input: &SwtpmArgvInput) -> Result, SwtpmA which: "pid_path".to_owned(), }); } - if !(1..=20).contains(&input.log_level) { + if !(MIN_SWTPM_LOG_LEVEL..=MAX_SWTPM_LOG_LEVEL).contains(&input.log_level) { return Err(SwtpmArgvError::LogLevelOutOfRange { level: input.log_level, }); @@ -209,6 +235,13 @@ pub fn generate_swtpm_argv(input: &SwtpmArgvInput) -> Result, SwtpmA } /// Render the pre-start `swtpm_ioctl -i --unix ` flush argv. +/// +/// # Errors +/// +/// Returns [`SwtpmArgvError::InvalidBinaryPath`] for an empty or +/// non-absolute swtpm_ioctl binary path, [`SwtpmArgvError::EmptyVmName`] for +/// an empty VM name, and [`SwtpmArgvError::EmptySocketPath`] for an empty +/// control socket path. pub fn generate_swtpm_ioctl_flush_argv( input: &SwtpmIoctlFlushInput, ) -> Result, SwtpmArgvError> { From 3c3a828171d3df5731b7ed97a048c704ea9ee532 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:24:22 -0700 Subject: [PATCH 103/726] refactor(d2b-provider-device-tpm): borrow controller refs instead of cloning --- .../src/effects_service.rs | 17 ++++-- .../src/resource_controller.rs | 53 +++++++++++++------ 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/packages/d2b-provider-device-tpm/src/effects_service.rs b/packages/d2b-provider-device-tpm/src/effects_service.rs index 5b128d815..d2b770cc2 100644 --- a/packages/d2b-provider-device-tpm/src/effects_service.rs +++ b/packages/d2b-provider-device-tpm/src/effects_service.rs @@ -277,7 +277,7 @@ impl DeclaredTpmRows<'_> { .owner_key .as_ref() .ok_or(TpmResourceEffectError::StateIntegrity)?; - if owner != &self.key(&self.device_ref.clone()) { + if owner != &self.key(&self.device_ref) { return Err(TpmResourceEffectError::StateIntegrity); } } @@ -447,10 +447,9 @@ impl LiveTpmResourceEffectPort<'_> { // The Device row's own Zone - never a zone-authority lookup of the // Guest target VM, which the host daemon's coordinator does not // register (the guest's plane lives inside the nested VM). - let zone = self.zone.clone(); let invocation = KernelInvocation { operation: "prepare-directory", - zone: zone.as_str(), + zone: self.zone.as_str(), payload: serde_json::json!({ "kind": "state", "baseDir": base_dir.display().to_string(), @@ -701,6 +700,12 @@ impl AdmittedTpmDevice { } /// Reconcile one Device's TPM controller through the provider-owned port. +/// +/// # Errors +/// +/// Returns the same errors as [`TpmResourceController::reconcile`]: +/// [`TpmResourceControllerError::InvalidState`] and +/// [`TpmResourceControllerError::Effect`]. pub async fn reconcile_device_tpm_controller( facets: TpmEffectFacets, vm_id: VmId, @@ -721,6 +726,12 @@ pub async fn reconcile_device_tpm_controller( } /// Finalize one Device's TPM controller through the provider-owned port. +/// +/// # Errors +/// +/// Returns the same errors as [`TpmResourceController::finalize`]: +/// [`TpmResourceControllerError::InvalidState`] and +/// [`TpmResourceControllerError::Effect`]. pub async fn finalize_device_tpm_controller( facets: TpmEffectFacets, vm_id: VmId, diff --git a/packages/d2b-provider-device-tpm/src/resource_controller.rs b/packages/d2b-provider-device-tpm/src/resource_controller.rs index 976b4ea23..ec05b0077 100644 --- a/packages/d2b-provider-device-tpm/src/resource_controller.rs +++ b/packages/d2b-provider-device-tpm/src/resource_controller.rs @@ -129,6 +129,14 @@ pub struct TpmResourceController { impl TpmResourceController { /// Construct a controller for one emulated Device. + /// + /// # Errors + /// + /// Returns [`TpmResourceControllerError::Effect`] with + /// [`TpmResourceEffectError::InvalidDevice`] when the device reference + /// does not name a Device, and with + /// [`TpmResourceEffectError::InvalidExecutionRef`] when the execution + /// reference is not a Host. pub fn new( device_uid: ResourceUid, device_ref: ResourceRef, @@ -187,6 +195,13 @@ impl TpmResourceController { /// Reconciliation creates the Volume, completes the mandatory pre-start /// flush, starts and observes the long-lived Process, and then exposes /// the Endpoint. + /// + /// # Errors + /// + /// Returns [`TpmResourceControllerError::InvalidState`] when the + /// controller is already finalized and + /// [`TpmResourceControllerError::Effect`] when a child effect fails or + /// the retained state fails integrity checks. pub async fn reconcile( &mut self, port: &P, @@ -211,7 +226,7 @@ impl TpmResourceController { )); } self.phase = TpmResourcePhase::Reconciling; - let volume = if self.needs_state_verification || self.volume_ref.is_none() { + if self.needs_state_verification || self.volume_ref.is_none() { let volume = match port .ensure_state_volume(&self.device_uid, &self.device_ref, &self.execution_ref) .await @@ -226,14 +241,13 @@ impl TpmResourceController { { return self.effect_failed(TpmResourceEffectError::StateIntegrity); } - self.volume_ref = Some(volume.clone()); + self.volume_ref = Some(volume); self.needs_state_verification = false; - volume - } else { - self.volume_ref - .clone() - .ok_or(TpmResourceControllerError::InvalidState)? - }; + } + let volume = self + .volume_ref + .as_ref() + .ok_or(TpmResourceControllerError::InvalidState)?; if self.flush_ref.is_none() { let flush = match port .request_flush_process(&self.device_uid, &self.execution_ref) @@ -244,20 +258,21 @@ impl TpmResourceController { }; self.flush_ref = Some(flush); } - let process = if let Some(process) = self.process_ref.clone() { - process - } else { + if self.process_ref.is_none() { let process = match port - .request_swtpm_process(&self.device_uid, &volume, &self.execution_ref) + .request_swtpm_process(&self.device_uid, volume, &self.execution_ref) .await { Ok(value) => value, Err(error) => return self.effect_failed(error), }; - self.process_ref = Some(process.clone()); - process - }; - let endpoint = match port.watch_tpm_endpoint(&process).await { + self.process_ref = Some(process); + } + let process = self + .process_ref + .as_ref() + .ok_or(TpmResourceControllerError::InvalidState)?; + let endpoint = match port.watch_tpm_endpoint(process).await { Ok(value) => value, Err(error) => return self.effect_failed(error), }; @@ -268,6 +283,12 @@ impl TpmResourceController { } /// Stop children and retain the Device-owned state Volume. + /// + /// # Errors + /// + /// Returns [`TpmResourceControllerError::InvalidState`] when finalization + /// is requested before reconcile with no children and + /// [`TpmResourceControllerError::Effect`] when a child effect fails. pub async fn finalize( &mut self, port: &P, From 8ac4f85358f606721767eab151b904d1695f55d5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:24:30 -0700 Subject: [PATCH 104/726] docs(d2b-provider-device-tpm): document error conditions on public APIs --- .../d2b-provider-device-tpm/src/resources.rs | 23 +++++++++++++++++++ .../d2b-provider-device-tpm/src/runner.rs | 5 ++++ 2 files changed, 28 insertions(+) diff --git a/packages/d2b-provider-device-tpm/src/resources.rs b/packages/d2b-provider-device-tpm/src/resources.rs index 3d9d871e7..eca3e11f3 100644 --- a/packages/d2b-provider-device-tpm/src/resources.rs +++ b/packages/d2b-provider-device-tpm/src/resources.rs @@ -50,6 +50,10 @@ const STATE_VOLUME_OWNER: &str = "User/d2bd"; /// exceeds the host's account-name bound. The Device's uid still keys the /// Volume name (`device-<32hex>-tpm-state`) and every runtime path /// derivation. +/// # Errors +/// +/// Returns [`TpmResourceEffectError::InvalidDevice`] when the reference does +/// not name a Device or the Device name or Zone is empty. pub fn build_tpm_state_volume_spec( device_ref: &ResourceRef, zone: &str, @@ -166,6 +170,11 @@ fn build_tpm_state_volume_spec_with_principals( } /// Build a complete controller-created TPM state Volume resource document. +/// +/// # Errors +/// +/// Returns the same errors as [`build_tpm_state_volume_spec`]: +/// [`TpmResourceEffectError::InvalidDevice`]. pub fn build_tpm_state_volume_resource( device_uid: &ResourceUid, device_ref: &ResourceRef, @@ -188,6 +197,13 @@ pub fn build_tpm_state_volume_resource( } /// Build the long-lived swtpm Process base spec. +/// +/// # Errors +/// +/// Returns [`TpmResourceEffectError::InvalidExecutionRef`] when the +/// execution reference is not a Host and +/// [`TpmResourceEffectError::InvalidDevice`] when the mount or process spec +/// cannot be constructed. pub fn build_swtpm_process_spec( device_uid: &ResourceUid, device_ref: &ResourceRef, @@ -244,6 +260,13 @@ pub fn build_swtpm_process_spec( } /// Build the mandatory pre-start flush EphemeralProcess spec. +/// +/// # Errors +/// +/// Returns [`TpmResourceEffectError::InvalidExecutionRef`] when the +/// execution reference is not a Host and +/// [`TpmResourceEffectError::InvalidDevice`] when the process spec cannot be +/// constructed. pub fn build_swtpm_flush_spec( device_ref: &ResourceRef, zone: &str, diff --git a/packages/d2b-provider-device-tpm/src/runner.rs b/packages/d2b-provider-device-tpm/src/runner.rs index e01772c0f..baa069f9c 100644 --- a/packages/d2b-provider-device-tpm/src/runner.rs +++ b/packages/d2b-provider-device-tpm/src/runner.rs @@ -25,6 +25,11 @@ impl Default for SwtpmSettings { impl SwtpmSettings { /// Validate settings received from the signed Provider schema. + /// + /// # Errors + /// + /// Returns [`SwtpmArgvError::LogLevelOutOfRange`] when the log level is + /// outside the frozen bound. pub const fn validate(self) -> Result { if self.log_level < MIN_SWTPM_LOG_LEVEL || self.log_level > MAX_SWTPM_LOG_LEVEL { Err(SwtpmArgvError::LogLevelOutOfRange) From 1f682b049d2ff84d3cc1e89a50e2ea671a0767f2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:26:08 -0700 Subject: [PATCH 105/726] volume: borrow the decoded envelope and drop the dead fallback --- packages/d2b-provider-volume/src/driver.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index fc783c296..4f3dd1706 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -324,17 +324,17 @@ impl VolumeDriver { } /// Decode the stored envelope and the typed spec in one step. - fn decoded_spec( + fn decoded_spec<'a>( &self, - ctx: &ResourceContext, + ctx: &'a ResourceContext, op: DriverOp, - ) -> Result<(VolumeSpecEnvelope, VolumeSpec), VolumeDriverError> { + ) -> Result<(&'a VolumeSpecEnvelope, VolumeSpec), VolumeDriverError> { let envelope = ctx .spec::() .map_err(|_| self.error(VolumeDriverErrorKind::SpecInvalid, op))?; let spec = serde_json::from_slice::(&envelope.base.to_canonical_bytes()) .map_err(|_| self.error(VolumeDriverErrorKind::SpecInvalid, op))?; - Ok((envelope.clone(), spec)) + Ok((envelope, spec)) } /// Provider check (old `validate_spec`): the Volume must select the @@ -564,7 +564,7 @@ impl ResourceDriver for VolumeDriver { /// Spec decode plus provider reference check (old `validate_spec`). async fn validate(&mut self, ctx: &mut ResourceContext) -> Result<(), Self::Error> { let (envelope, _) = self.decoded_spec(ctx, DriverOp::Validate)?; - self.check_provider(&envelope, DriverOp::Validate)?; + self.check_provider(envelope, DriverOp::Validate)?; Ok(()) } @@ -573,7 +573,7 @@ impl ResourceDriver for VolumeDriver { /// reconcile. async fn recover(&mut self, ctx: &mut ResourceContext) -> Result { let (envelope, _) = self.decoded_spec(ctx, DriverOp::Recover)?; - self.check_provider(&envelope, DriverOp::Recover)?; + self.check_provider(envelope, DriverOp::Recover)?; let uid = resource_uid(ctx.uid()) .map_err(|_| self.error(VolumeDriverErrorKind::SpecInvalid, DriverOp::Recover))?; if self.effects.has_layout(&uid) { @@ -598,15 +598,16 @@ impl ResourceDriver for VolumeDriver { /// converged. async fn reconcile(&mut self, ctx: &mut ResourceContext) -> Result { let (envelope, spec) = self.decoded_spec(ctx, DriverOp::Reconcile)?; - self.check_provider(&envelope, DriverOp::Reconcile)?; + self.check_provider(envelope, DriverOp::Reconcile)?; let uid = resource_uid(ctx.uid()) .map_err(|_| self.error(VolumeDriverErrorKind::SpecInvalid, DriverOp::Reconcile))?; let volume_ref = self.volume_ref(ctx, DriverOp::Reconcile)?; if !self.layout_ready.load(std::sync::atomic::Ordering::SeqCst) { - return self.spawn_layout(ctx, uid, spec, envelope.base.get("provider").map(|value| { - serde_json::to_value(value).unwrap_or(serde_json::Value::Null) - })); + let provider = envelope.base.get("provider").map(|value| { + serde_json::to_value(value).expect("canonical JSON values always serialize") + }); + return self.spawn_layout(ctx, uid, spec, provider); } let desired = self.desired_children(&volume_ref, &spec, DriverOp::Reconcile)?; From 85d30ec37f5cc6e408578b8526ee64cafb4c5f5b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:26:27 -0700 Subject: [PATCH 106/726] d2b-provider-process-minijail: state the conformance failure contract --- .../src/launch.rs | 13 +++++++- .../d2b-provider-process-minijail/src/lib.rs | 32 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-process-minijail/src/launch.rs b/packages/d2b-provider-process-minijail/src/launch.rs index 8493bc564..2d25f9553 100644 --- a/packages/d2b-provider-process-minijail/src/launch.rs +++ b/packages/d2b-provider-process-minijail/src/launch.rs @@ -30,6 +30,11 @@ impl PlatformGate { } /// Check Linux 5.14 and cgroup.kill. + /// + /// # Errors + /// + /// Returns `PlatformGateRejected` when the kernel is older than + /// 5.14 or the runtime cgroup does not expose `cgroup.kill`. pub const fn validate(self) -> Result<(), ProcessConformanceError> { if self.kernel_major < 5 || (self.kernel_major == 5 && self.kernel_minor < 14) @@ -42,7 +47,13 @@ impl PlatformGate { } } -/// Validate provider identity and platform evidence before spawn dispatch. +/// Validate provider identityand platform evidence before spawn dispatch. +/// +/// # Errors +/// +/// Returns `ProviderMismatch` when the ticket selects a different +/// Process Provider,and `PlatformGateRejected` when the platform gate +/// fails. pub fn validate_launch_ticket( ticket: &LaunchTicket, gate: PlatformGate, diff --git a/packages/d2b-provider-process-minijail/src/lib.rs b/packages/d2b-provider-process-minijail/src/lib.rs index 708c9f61e..39be19822 100644 --- a/packages/d2b-provider-process-minijail/src/lib.rs +++ b/packages/d2b-provider-process-minijail/src/lib.rs @@ -310,6 +310,16 @@ impl ProcessProvider for MinijailProcessProvider

self.launch_with_inherited_fds(ticket, Vec::new()).await } +/// Launch one ticket after validation, returning the verified report. + /// + /// # Errors + /// + /// Returns ticket validation failures (`ProviderMismatch`, + /// `PlatformGateRejected`), thee effect port's launch and readiness + /// failures, `WaitOwnerMismatch` when the launched process is not + /// locally owned, `IdentityUnverified` when the launch evidence lacks + /// the required identity bindings,and `TerminalEvidenceMismatch` + /// when the identity does not match the ticket seal. async fn launch_with_inherited_fds( &self, ticket: &LaunchTicket, @@ -368,6 +378,15 @@ impl ProcessProvider for MinijailProcessProvider

} } + /// Adopt a running candidate after verifying its identity. + /// + /// # Errors + /// + /// Returns ticket validation failures, thee effect port's observe + /// failures, non-`DeadlineExceeded` readiness failures, and + /// pidfd-open failures. A `DeadlineExceeded` readiness probe + /// instead quarantines the candidate as identity-ambiguous. + async fn adopt( &self, ticket: &LaunchTicket, @@ -450,6 +469,12 @@ impl ProcessProvider for MinijailProcessProvider

))) } + /// Stop exactly the named identity. + /// + /// # Errors + /// + /// Returns `IdentityUnverified` when the identity is zero; otherwise + /// the effect port's stop failure propagates. async fn stop( &self, identity: &ProcessIdentityDigest, @@ -472,6 +497,13 @@ impl ProcessProvider for MinijailProcessProvider

{ /// Build the reconciler over an injected discovery port. pub const fn new(port: P) -> Self { @@ -222,22 +245,13 @@ impl UserReconciler

{ &self.port } - /// The properties a User must verify before it is reported discovered. - /// - /// The record and its primary group are always required. Group - /// memberships are required exactly when the spec declares any, so a - /// User that declares none is not held to a check with nothing to - /// check, and a User that declares some cannot be called discovered - /// while they are unverified. - pub fn required_bindings(spec: &UserSpec) -> BTreeSet { - let mut required = BTreeSet::from([UserBinding::NssRecord, UserBinding::PrimaryGroup]); - if !spec.groups().is_empty() { - required.insert(UserBinding::GroupMemberships); - } - required - } - /// Discover one declared User and compute its public status. + /// + /// # Errors + /// + /// Returns [`SystemCoreError::ResourceTypeNotOwned`] when the reference + /// is not a User and [`SystemCoreError::DiscoveryUnavailable`] when the + /// injected discovery port fails. pub async fn reconcile( &self, user_ref: &ResourceRef, @@ -264,7 +278,7 @@ impl UserReconciler

{ None, )); }; - let required = Self::required_bindings(spec); + let required = required_bindings(spec); if discovered.observed.covers(&required) { return Ok(self.report( user_ref, diff --git a/packages/d2b-provider-system-core/tests/user_discovery.rs b/packages/d2b-provider-system-core/tests/user_discovery.rs index 2754f0902..40ae308f7 100644 --- a/packages/d2b-provider-system-core/tests/user_discovery.rs +++ b/packages/d2b-provider-system-core/tests/user_discovery.rs @@ -11,7 +11,7 @@ use d2b_provider_system_core::testing::{ SCRIPTED_IDENTITY, ScriptedDiscoveryPort, block_on, fixtures, }; use d2b_provider_system_core::{ - SystemCoreError, UserBinding, UserDiscoveryCondition, UserReconciler, + SystemCoreError, UserBinding, UserDiscoveryCondition, UserReconciler, required_bindings, }; #[test] @@ -42,7 +42,7 @@ fn an_unresolved_user_is_absent_rather_than_a_failure() { fn declared_groups_are_required_and_their_absence_is_drift_not_readiness() { let spec = fixtures::user_spec_with_groups(); assert!( - UserReconciler::::required_bindings(&spec) + required_bindings(&spec) .contains(&UserBinding::GroupMemberships) ); let reconciler = UserReconciler::new(ScriptedDiscoveryPort::resolving([ @@ -70,7 +70,7 @@ fn declared_groups_are_required_and_their_absence_is_drift_not_readiness() { fn a_user_that_declares_no_group_is_not_held_to_a_membership_check() { let spec = fixtures::user_spec(); assert!( - !UserReconciler::::required_bindings(&spec) + !required_bindings(&spec) .contains(&UserBinding::GroupMemberships) ); } From 6bcf757089f0f64f0b2a840df9c00bdaa7835a56 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:33:20 -0700 Subject: [PATCH 140/726] audit: record wave-1 slice 10 Twenty-two rows across the smaller crates, two of them minimal variants recorded with their deviations. --- .../2026-09-24-rust-skills-audit/ledger.md | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index b0c45599d..d2eb5a959 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -133,7 +133,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0100` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1802, engine.rs:1803, engine.rs:1807` | | | | `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:1593, admission.rs:956, admission.rs:958` | | | | `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/config.rs:178` | | | -| `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/systemd.rs:260, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U2 | f3a847c72 | `packages/d2b-unsafe-local-helper/src/systemd.rs` | Replaced the then_some/ok_or NotFound normalization with an explicit if-let/if-error branch in terminate_scope and stop_scope; cargo check and test green. | | | `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/resolver.rs:144` | | | | `RS-0105` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/service.rs:311` | | | | `RS-0106` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, pa` | | | @@ -223,10 +223,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:771` | | | | `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:190-198, packages/d2b` | | | | `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:267-277, packages/d2b-` | | | -| `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | | | | `packages/d2b-provider-user/src/effects_service.rs:179, packages/d2b-provider-user/src/effe` | | | +| `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | applied-variant | U2 | 9ba7acf09 | `packages/d2b-provider-user/src/effects_service.rs` | Destructured InspectUserRequest and moved groups by value; username still cloned because inspect_user_response borrows it after UserSpec::new consumes it (stated fix was not implementable as written). | | | `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:337` | | | | `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | | | | `driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.` | | | -| `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | | | | `packages/d2b-provider-volume-binding/src/row_readers.rs:38-44` | | | +| `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/row_readers.rs` | Bounded the as_object_mut removal borrow in a block and moved spec into serde_json::from_value, dropping the Value::Object(object.clone()). | | | `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/sr` | | | | `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1526` | | | | `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:425, client.rs:110, service.rs:852` | | | @@ -699,24 +699,24 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2917, packages/d2b-core/src/bundle_resolver.rs:29` | | | | `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controlle` | | | | `RS-0653` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `migration.rs:54, migration.rs:58` | | | -| `RS-0656` | `docs` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/bridge_port.rs:127, packages/d2b-host/src/host_generation.rs:103, pa` | | | -| `RS-0657` | `docs` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/cgroup.rs:53, packages/d2b-host/src/cgroup.rs:71, packages/d2b-host/` | | | +| `RS-0656` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/bridge_port.rs` | Added # Errors to validate_readback, parse_request, parse_validation_request, validate_media_ref, validate_usb_busid, and NftBatch::parse (the wire-boundary parsers the row names). | | +| `RS-0657` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/cgroup.rs` | One-line docs added to Controller::REQUIRED, Controller::as_str, Controller::from_token (token grammar noted), BusId::new, HostPrepStepId::as_str. | | | `RS-0660` | `docs` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/` | | | | `RS-0661` | `docs` | `d2b-provider` | medium | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:270, packages/d2b-provider/src/descriptor.rs:232, packa` | | | -| `RS-0662` | `docs` | `d2b-provider-activation-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:711, packages/d2b-provider-activa` | | | -| `RS-0663` | `docs` | `d2b-provider-audio-binding` | low | actionable | leaf | | | | `packages/d2b-provider-audio-binding/src/audio_binding.rs:56, packages/d2b-provider-audio-b` | | | -| `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/state.rs:81-84, src/lib.rs:9-10` | | | -| `RS-0665` | `docs` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:21, src/controller.rs:209, src/controller.rs:212` | | | +| `RS-0662` | `docs` | `d2b-provider-activation-nixos` | medium | actionable | leaf | applied | U2 | 6acd5ada6 | `packages/d2b-provider-activation-nixos/src/controller.rs` | Added # Errors naming the exact ActivationError/ActivationVerificationError variants to verify, verify_application, refuse_undeclared_runner_step, reconcile, apply_runner_result. | | +| `RS-0663` | `docs` | `d2b-provider-audio-binding` | low | actionable | leaf | applied | U2 | ca450e9d5 | `packages/d2b-provider-audio-binding/src/audio_binding.rs` | Added # Errors to binding_children, validate, dependencies, desired_children naming Unavailable vs InvalidResource conditions. | | +| `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/state.rs` | Documented AudioStateLock guard semantics (holds the OFD lock; drop releases and closes). | | +| `RS-0665` | `docs` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/controller.rs` | Documented the 300s cadence rationale, hoisted 64 into pub const AUDIO_QUEUE_BOUND used by new, with_shared_microphone, and the admission bound test (u64 casts at lease sites). | | | `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | | | | `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | | | | `src/audit.rs:172, src/audit.rs:174` | | | | `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | | | | `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | | | | `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | | | -| `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | | | | `packages/d2b-provider-command/src/command.rs:38, packages/d2b-provider-command/src/command` | | | +| `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | applied | U2 | ef3bc5ec9 | `packages/d2b-provider-command/src/command.rs` | Added one-line # Errors naming CommandContractError variants to CommandExec::parse, CommandArgvSlot::parse, CommandSpec::new. | | | `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/controller.rs:45-64, packages/d2b-provider-config-n` | | | | `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/` | | | -| `RS-0674` | `docs` | `d2b-provider-credential-entra` | low | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/controller.rs:47, packages/d2b-provider-credent` | | | -| `RS-0675` | `docs` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:449, lib.rs:514, lib.rs:592, lib.rs:796` | | | +| `RS-0674` | `docs` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U2 | b29c0b8d2 | `packages/d2b-provider-credential-entra/src/controller.rs` | Added # Errors naming returned variants to EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, r | | +| `RS-0675` | `docs` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U2 | e86206bab | `packages/d2b-provider-credential-managed-identity/src/lib.rs` | Added # Errors naming ManagedIdentityProviderError/CredentialServiceError/CredentialObservabilityError variants to the named constructors and controller projections. | | | `RS-0676` | `docs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-cred` | | | | `RS-0677` | `docs` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-` | | | | `RS-0678` | `docs` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:172, packages/d2b-provider-device-gpu/s` | | | @@ -740,23 +740,23 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | | | | `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `lib.rs:13, lib.rs:14, lib.rs:15` | | | | `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131` | | | -| `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | | | | `packages/d2b-provider-operation/src/operation.rs:138, packages/d2b-provider-operation/src/` | | | +| `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | applied | U2 | 4e381161f | `packages/d2b-provider-operation/src/operation.rs` | Added one-line # Errors naming OperationContractError variants to OperationAudit::new, AuditJoin::new, OperationFds::new, OperationBounds::new, OperationSpec::new. | | | `RS-0700` | `docs` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/backend.rs:256, packages/d2b-provider-process/src/launch` | | | -| `RS-0701` | `docs` | `d2b-provider-process-minijail` | low | actionable | leaf | | | | `packages/d2b-provider-process-minijail/src/launch.rs:33, packages/d2b-provider-process-min` | | | +| `RS-0701` | `docs` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U2 | 85d30ec37 | `packages/d2b-provider-process-minijail/src/launch.rs` | Added # Errors naming ProcessConformanceError conditions to PlatformGate::validate, validate_launch_ticket, and the launch/adopt/stop/stop_stale impl methods. | | | `RS-0702` | `docs` | `d2b-provider-process-systemd` | medium | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lifecycle.rs:33, packages/d2b-provider-process-s` | | | | `RS-0703` | `docs` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/providers.rs:72, src/providers.rs:79` | | | -| `RS-0704` | `docs` | `d2b-provider-role` | low | actionable | leaf | | | | `packages/d2b-provider-role/src/lib.rs:1, packages/d2b-provider-role/src/rbac.rs:11` | | | +| `RS-0704` | `docs` | `d2b-provider-role` | low | actionable | leaf | applied-variant | U2 | e36441105 | `packages/d2b-provider-role/src/lib.rs` | Added #![deny(missing_docs)] and documented PolicyRevisionSet fields; the gate forced one-line docs on AuthorizationCacheKey::new and the four PositiveDecisionCache methods to keep the build green. | | | `RS-0705` | `docs` | `d2b-provider-seccomp-profile` | medium | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:31, packages/d2b-provider-sec` | | | | `RS-0706` | `docs` | `d2b-provider-shell-terminal` | medium | actionable | leaf | | | | `src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/` | | | | `RS-0707` | `docs` | `d2b-provider-system-core` | medium | actionable | leaf | | | | `src/host.rs:121, src/host.rs:161, src/user.rs:241` | | | | `RS-0708` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/s` | | | | `RS-0709` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolki` | | | | `RS-0710` | `docs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/auth.rs:229-246, packages/d2b-provider-tra` | | | -| `RS-0711` | `docs` | `d2b-provider-transport-unix` | low | actionable | leaf | | | | `packages/d2b-provider-transport-unix/src/portal.rs:197-201, packages/d2b-provider-transpor` | | | +| `RS-0711` | `docs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U2 | 721c96f38 | `packages/d2b-provider-transport-unix/src/portal.rs` | Added # Errors naming PortalError variants to open, close, and observe. | | | `RS-0712` | `docs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsoc` | | | -| `RS-0713` | `docs` | `d2b-provider-volume-binding` | low | actionable | leaf | | | | `packages/d2b-provider-volume-binding/src/facets.rs:52, packages/d2b-provider-volume-bindin` | | | +| `RS-0713` | `docs` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/facets.rs` | Added # Errors to SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, BindingDriverEffects::remove_socket, and guest_mount_ready naming the daemon-adapter failures and fail-closed handlin | | | `RS-0714` | `docs` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92` | | | -| `RS-0715` | `docs` | `d2b-provider-zone` | low | actionable | leaf | | | | `packages/d2b-provider-zone/src/zone_status.rs:110-114` | | | +| `RS-0715` | `docs` | `d2b-provider-zone` | low | actionable | leaf | applied | U2 | 2170c0cac | `packages/d2b-provider-zone/src/zone_status.rs` | Added # Errors to SystemCoreStatusEmitter::emit naming the duplicate-handler and rejected-resource Contract conditions. | | | `RS-0716` | `docs` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src` | | | | `RS-0718` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, pa` | | | | `RS-0717` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `service.rs:198, store.rs:39, adapter.rs:71, manager_backend.rs:625` | | | @@ -766,15 +766,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0722` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | MODULE_NAME docs on five modules | | | `RS-0723` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | TargetControlAssignment five methods documented | | | `RS-0724` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | doc contracts on target/spec/identity accessors | | -| `RS-0725` | `docs` | `d2b-resource-types` | low | actionable | leaf | | | | `packages/d2b-resource-types/src/operation.rs:64, packages/d2b-resource-types/src/operation` | | | +| `RS-0725` | `docs` | `d2b-resource-types` | low | actionable | leaf | applied | U2 | 61c64bf0f | `packages/d2b-resource-types/src/operation.rs` | Restored the missing spaces after commas in the OperationCtx::fds field docs. | | | `RS-0726` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239` | | | | `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62` | | | | `RS-0727` | `docs` | `d2b-session` | low | actionable | leaf | | | | `operation.rs:207` | | | | `RS-0729` | `docs` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:1182, admission.rs:1186, admission.rs:1190, admission.rs:1194` | | | | `RS-0730` | `docs` | `d2b-session` | low | actionable | leaf | | | | `transport.rs:208, transport.rs:212` | | | -| `RS-0731` | `docs` | `d2b-session-unix` | medium | actionable | leaf | | | | `packages/d2b-session-unix/src/socket.rs:190, packages/d2b-session-unix/src/adapter.rs:351,` | | | -| `RS-0732` | `docs` | `d2b-session-unix` | low | actionable | leaf | | | | `packages/d2b-session-unix/src/socket.rs:202, packages/d2b-session-unix/src/socket.rs:210, ` | | | -| `RS-0733` | `docs` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:236, packages/d2b-telemetry/src/audit_hash.rs:23` | | | +| `RS-0731` | `docs` | `d2b-session-unix` | medium | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added first-sentence contract docs to SeqpacketSocket, UnixSeqpacketTransport, UnixStreamTransport, CreditPool, PidfdEvidence, PeerCredentials, ActivatedSeqpacketListener(s), FramedVsockTransport and | | +| `RS-0732` | `docs` | `d2b-session-unix` | low | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added # Errors to the anchor Result fns (SeqpacketSocket::from_owned/from_parent_prearmed/from_inherited_fd, UnixSeqpacketTransport::new, CreditPool::new, PidfdEvidence::new) naming their distinct fai | | +| `RS-0733` | `docs` | `d2b-telemetry` | low | actionable | leaf | applied | U2 | e1fab0e9b | `packages/d2b-telemetry/src/audit_hash.rs` | Added # Errors naming the returned variants to every named item: AuditHash::parse, AuditChainLink::verify/verify_at, all eight BoundedEmitter fns, MetricFamily/MeterRegistry, RedactionGuard, validate_ | | | `RS-0734` | `docs` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/resolver.rs:80, packages/d2b-zone-routing/src/service.rs:208` | | | | `RS-0736` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828` | | | | `RS-0741` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/audio_dispatch.rs:372` | | | From e4702029703fd4e6ea8225a295cc87156fdf34d2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:33:21 -0700 Subject: [PATCH 141/726] process-conformance: move identity in ticket builders and document errors --- .../src/launch_identity.rs | 13 +++++++++++++ packages/d2b-process-conformance/src/port.rs | 12 ++++++++++++ .../d2b-process-conformance/src/sandbox.rs | 6 ++++++ .../d2b-process-conformance/src/terminal.rs | 18 ++++++++++++++++++ packages/d2b-process-conformance/src/ticket.rs | 9 +++++---- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/packages/d2b-process-conformance/src/launch_identity.rs b/packages/d2b-process-conformance/src/launch_identity.rs index d2908df35..1594c25e7 100644 --- a/packages/d2b-process-conformance/src/launch_identity.rs +++ b/packages/d2b-process-conformance/src/launch_identity.rs @@ -109,6 +109,19 @@ impl LaunchIdentity { /// `binding_worker` marks the host-exec/guest-target split of a /// binding-owned serving worker; its launch VM is the execution host even /// though the ticket's target points at the attachment's Guest. + /// + /// # Errors + /// + /// Returns [`LaunchIdentityError::InvalidExecutionRef`] when the + /// execution reference is neither Host nor Guest, + /// [`LaunchIdentityError::InvalidTargetRef`] when the target selector + /// is not a Guest reference, [`LaunchIdentityError::MissingTargetRef`] + /// when a binding-owned worker declares no attachment target, + /// [`LaunchIdentityError::OwnerUidWithoutOwnerRef`] when a durable + /// owner UID has no owner reference, [`LaunchIdentityError::InvalidRole`] + /// when the process name is empty or forbidden, and + /// [`LaunchIdentityError::InvalidVm`] when the derived VM scope is + /// empty or forbidden. pub fn new( owner_ref: Option, owner_uid: Option, diff --git a/packages/d2b-process-conformance/src/port.rs b/packages/d2b-process-conformance/src/port.rs index ce0f40981..5ba4de886 100644 --- a/packages/d2b-process-conformance/src/port.rs +++ b/packages/d2b-process-conformance/src/port.rs @@ -32,6 +32,12 @@ pub struct LaunchedProcess { impl LaunchedProcess { /// Validate the effect adapter's launch evidence. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::IdentityUnverified`] when the + /// identity is zero or the observed bindings do not cover the required + /// set. pub fn validate( &self, required: &std::collections::BTreeSet, @@ -64,6 +70,12 @@ pub struct AdoptionCandidate { impl AdoptionCandidate { /// Validate the candidate before a pidfd may be opened. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::IdentityUnverified`] when the + /// identity is zero or the observed bindings do not cover the required + /// set. pub fn validate( &self, required: &std::collections::BTreeSet, diff --git a/packages/d2b-process-conformance/src/sandbox.rs b/packages/d2b-process-conformance/src/sandbox.rs index 7a89763ae..e04ad711e 100644 --- a/packages/d2b-process-conformance/src/sandbox.rs +++ b/packages/d2b-process-conformance/src/sandbox.rs @@ -69,6 +69,12 @@ pub struct SandboxCompiler; impl SandboxCompiler { /// Compile one public SandboxSpec into an opaque digest. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::SandboxRejected`] when the spec + /// starts as root in a user domain or against a provider that does not + /// allow root, or when its canonical JSON rendering fails. pub fn compile( &self, sandbox: &SandboxSpec, diff --git a/packages/d2b-process-conformance/src/terminal.rs b/packages/d2b-process-conformance/src/terminal.rs index 7c4355dde..ba4c5e4a5 100644 --- a/packages/d2b-process-conformance/src/terminal.rs +++ b/packages/d2b-process-conformance/src/terminal.rs @@ -48,6 +48,11 @@ pub struct ProcessOutcome { impl ProcessOutcome { /// Construct a normal exit result. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::InvalidTerminalResult`] when the + /// exit code is outside `0..=255`. pub fn exited(exit_code: i32) -> Result { if !(0..=255).contains(&exit_code) { return Err(ProcessConformanceError::InvalidTerminalResult); @@ -91,6 +96,11 @@ impl ProcessOutcome { } /// Validate the relationship between terminal class and exit code. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::InvalidTerminalResult`] when a + /// clean exit carries no valid code or any other class carries one. pub const fn validate(self) -> Result<(), ProcessConformanceError> { match (self.exit_class, self.exit_code) { (ExitClass::CleanExit, Some(code)) if code >= 0 && code <= 255 => Ok(()), @@ -212,6 +222,14 @@ impl BrokerTerminalResult { } /// Consume the result and relay it only to its matching launch ticket. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::TerminalEvidenceMismatch`] when + /// the evidence is not reaped or the ticket does not match the + /// process, operation, provider, or expected identity, and + /// [`ProcessConformanceError::InvalidTerminalResult`] when the outcome + /// itself is invalid. pub fn relay(self, ticket: &LaunchTicket) -> Result { if !self.evidence.is_reaped() || ticket.process_uid() != &self.process_uid diff --git a/packages/d2b-process-conformance/src/ticket.rs b/packages/d2b-process-conformance/src/ticket.rs index 4c093db75..f22324d48 100644 --- a/packages/d2b-process-conformance/src/ticket.rs +++ b/packages/d2b-process-conformance/src/ticket.rs @@ -554,7 +554,6 @@ impl LaunchTicket { if let Some(owner_ref) = owner_ref { self.launch_identity = self .launch_identity - .clone() .with_owner(owner_ref.clone()) .map_err(|_| ProcessConformanceError::InvalidTicket)?; self.owner_ref = Some(owner_ref); @@ -607,7 +606,6 @@ impl LaunchTicket { } self.launch_identity = self .launch_identity - .clone() .with_owner_uid(owner_uid.clone()) .map_err(|_| ProcessConformanceError::InvalidTicket)?; self.owner_uid = Some(owner_uid); @@ -628,7 +626,6 @@ impl LaunchTicket { } self.launch_identity = self .launch_identity - .clone() .with_owner(owner_ref.clone()) .map_err(|_| ProcessConformanceError::InvalidTicket)?; self.owner_ref = Some(owner_ref); @@ -661,7 +658,6 @@ impl LaunchTicket { } self.launch_identity = self .launch_identity - .clone() .with_target_ref(target_ref.clone()) .map_err(|_| ProcessConformanceError::InvalidTicket)?; self.target_ref = Some(target_ref); @@ -728,6 +724,11 @@ impl LaunchTicket { } /// Validate this ticket before handing it to an effect adapter. + /// + /// # Errors + /// + /// Returns [`ProcessConformanceError::InvalidTicket`] when any frozen + /// ticket bound or binding relation does not hold. pub fn validate(&self) -> Result<(), ProcessConformanceError> { if !matches!( self.process_ref.resource_type().as_str(), From 0208e33d483944ab8de6ade1c136dde710e4f4f3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:33:37 -0700 Subject: [PATCH 142/726] provider-toolkit: share the backend operation allowlist and document refusals --- .../d2b-provider-toolkit/src/base/fd10.rs | 19 +---------- .../d2b-provider-toolkit/src/base/runtime.rs | 32 +++++++++++++++++-- .../d2b-provider-toolkit/src/base/startup.rs | 13 ++++++++ .../d2b-provider-toolkit/src/credential.rs | 9 ++++++ .../src/server/adapter.rs | 5 +++ .../src/shared_provider.rs | 6 +++- .../src/testing/conformance.rs | 18 +++++++++++ 7 files changed, 81 insertions(+), 21 deletions(-) diff --git a/packages/d2b-provider-toolkit/src/base/fd10.rs b/packages/d2b-provider-toolkit/src/base/fd10.rs index fce38e5dd..b99ac595b 100644 --- a/packages/d2b-provider-toolkit/src/base/fd10.rs +++ b/packages/d2b-provider-toolkit/src/base/fd10.rs @@ -923,24 +923,7 @@ impl GuestCredentialBackend { if operation.is_empty() || operation.len() > 128 || !operation.is_ascii() - || !matches!( - operation, - "secret-service.state" - | "secret-service.issue-lease" - | "secret-service.inspect-lease" - | "secret-service.refresh-lease" - | "secret-service.revoke-lease" - | "entra.state" - | "entra.issue-lease" - | "entra.inspect-lease" - | "entra.refresh-lease" - | "entra.revoke-lease" - | "managed-identity.state" - | "managed-identity.issue-lease" - | "managed-identity.inspect-lease" - | "managed-identity.refresh-lease" - | "managed-identity.revoke-lease" - ) + || !valid_guest_backend_operation(operation) || !fields.is_object() { return Err(GuestCredentialBackendError::Malformed); diff --git a/packages/d2b-provider-toolkit/src/base/runtime.rs b/packages/d2b-provider-toolkit/src/base/runtime.rs index 50fdd0784..0129b7042 100644 --- a/packages/d2b-provider-toolkit/src/base/runtime.rs +++ b/packages/d2b-provider-toolkit/src/base/runtime.rs @@ -246,6 +246,11 @@ impl fmt::Debug for ProviderEntrypoint { impl ProviderEntrypoint { /// Construct a process lifecycle owner for one fixed Provider binary. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::InvalidName`] when the name is empty, + /// exceeds the bound, or is not ASCII. pub fn new(name: &'static str) -> Result { if name.is_empty() || name.len() > 128 || !name.is_ascii() { return Err(ProviderRuntimeError::InvalidName); @@ -327,6 +332,11 @@ impl ProviderEntrypoint { } /// Bind this lifecycle owner to one exact Host or Guest execution target. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::InvalidName`] when the reference is + /// not a `Host` or `Guest`, or when an execution target is already bound. pub fn with_execution_target( mut self, execution_ref: ResourceRef, @@ -349,6 +359,11 @@ impl ProviderEntrypoint { } /// Bind this lifecycle owner to the exact controller Process identity. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::InvalidName`] when the reference is + /// not a `Process`, or when a Process identity is already bound. pub fn with_controller_process( mut self, process_ref: ResourceRef, @@ -362,6 +377,11 @@ impl ProviderEntrypoint { /// Bind this lifecycle owner to one exact Provider and controller /// generation. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::InvalidName`] when a generation is + /// already bound. pub fn with_generations( mut self, provider_generation: ResourceGeneration, @@ -381,6 +401,11 @@ impl ProviderEntrypoint { } /// Admit one local service registration. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::NotAccepting`] when the runtime is no + /// longer in the `Starting` lifecycle. pub fn admit(&self) -> Result { // The count is incremented before the lifecycle check and rolled // back on refusal so a registration can never slip past the drain @@ -533,8 +558,11 @@ impl ProviderEntrypoint { .ready_route .try_lock() .ok() - .and_then(|ready| ready.clone()) - .is_some_and(|ready| ready.liveness().is_live() && ready == *route) + .is_some_and(|ready| { + ready + .as_ref() + .is_some_and(|bound| bound.liveness().is_live() && bound == route) + }) } /// Return redacted routing metadata for the current ready session. diff --git a/packages/d2b-provider-toolkit/src/base/startup.rs b/packages/d2b-provider-toolkit/src/base/startup.rs index ea93d629e..83b28504a 100644 --- a/packages/d2b-provider-toolkit/src/base/startup.rs +++ b/packages/d2b-provider-toolkit/src/base/startup.rs @@ -36,6 +36,14 @@ pub struct PlannedStep { impl StartupPlan { /// Derive the order from the drivers' declared steps. + /// + /// # Errors + /// + /// Returns [`StartupPlanRefusal::MissingInput`] when a step names an + /// input no predecessor commits, [`StartupPlanRefusal::DuplicateOutput`] + /// when two steps commit the same output, and + /// [`StartupPlanRefusal::Cycle`] when the declared inputs and outputs + /// form a cycle. pub fn derive(drivers: &[DriverDescriptor]) -> Result { let mut declared: Vec<(WellKnownType, &'static StartupStep)> = Vec::new(); for driver in drivers { @@ -51,6 +59,11 @@ impl StartupPlan { /// A provider crate assembles its `DriverDescriptor`s once; a test or a /// composition root that already holds the rows states them directly. /// Both feed one derivation. + /// + /// # Errors + /// + /// Returns the same refusals as [`Self::derive`]: `MissingInput`, + /// `DuplicateOutput`, or `Cycle`. pub fn declare( rows: &'static [(WellKnownType, &'static [StartupStep])], ) -> Result { diff --git a/packages/d2b-provider-toolkit/src/credential.rs b/packages/d2b-provider-toolkit/src/credential.rs index 6cc051cc0..423475b9b 100644 --- a/packages/d2b-provider-toolkit/src/credential.rs +++ b/packages/d2b-provider-toolkit/src/credential.rs @@ -108,6 +108,11 @@ pub const fn is_absolute_unix_ms(value: u64) -> bool { /// Convert a deadline (absolute Unix milliseconds or a relative duration) into /// an `Instant`, failing when the deadline is already exhausted. +/// +/// # Errors +/// +/// Returns `DeadlineExceeded` when the deadline is zero or already in the +/// past, or when the resulting `Instant` overflows. pub fn operation_deadline(deadline_ms: u64) -> Result { let now_unix_ms = now_unix_ms(); let duration_ms = if is_absolute_unix_ms(deadline_ms) { @@ -128,6 +133,10 @@ pub fn operation_deadline(deadline_ms: u64) -> Result Result<(), CredentialServiceError> { if Instant::now() >= deadline { return Err(CredentialServiceError::new( diff --git a/packages/d2b-provider-toolkit/src/server/adapter.rs b/packages/d2b-provider-toolkit/src/server/adapter.rs index 010288465..c83f90499 100644 --- a/packages/d2b-provider-toolkit/src/server/adapter.rs +++ b/packages/d2b-provider-toolkit/src/server/adapter.rs @@ -28,6 +28,11 @@ use tracing::warn; /// adapter. Descriptors are numbered from zero and may not repeat, reorder, /// or skip an index; rejecting before dispatch prevents an adapter from /// confusing a stale attachment with a current one. +/// +/// # Errors +/// +/// Returns [`ProviderToolkitError::NonMonotoneAttachmentIndexes`] when an +/// index is not exactly its zero-based position. pub fn validate_attachment_indexes(indexes: &[u32]) -> Result<(), ProviderToolkitError> { for (expected, observed) in indexes.iter().enumerate() { if *observed != expected as u32 { diff --git a/packages/d2b-provider-toolkit/src/shared_provider.rs b/packages/d2b-provider-toolkit/src/shared_provider.rs index 37dfb26ed..70deb9489 100644 --- a/packages/d2b-provider-toolkit/src/shared_provider.rs +++ b/packages/d2b-provider-toolkit/src/shared_provider.rs @@ -768,7 +768,11 @@ impl>(); - obsolete.sort_by_key(|row| (teardown_rank(&row.key.type_name), row.key.name.clone())); + obsolete.sort_by(|a, b| { + teardown_rank(&a.key.type_name) + .cmp(&teardown_rank(&b.key.type_name)) + .then_with(|| a.key.name.cmp(&b.key.name)) + }); let mut mutated = false; for row in obsolete { ctx.delete(&row.key) diff --git a/packages/d2b-provider-toolkit/src/testing/conformance.rs b/packages/d2b-provider-toolkit/src/testing/conformance.rs index c03b75c37..9985dd927 100644 --- a/packages/d2b-provider-toolkit/src/testing/conformance.rs +++ b/packages/d2b-provider-toolkit/src/testing/conformance.rs @@ -264,6 +264,15 @@ impl ProviderResourceTypeBinding { /// /// This is the check that runs before a Provider is admitted, without /// calling the Provider. +/// +/// # Errors +/// +/// Returns [`ConformanceError::NoResourceTypeBinding`] when no binding is +/// declared, [`ConformanceError::DuplicateResourceTypeBinding`] when a +/// resource type is bound twice, [`ConformanceError::ResourceTypeNotInstalled`] +/// when the bound resource type has no installed contract, and +/// [`ConformanceError::BaseSchemaMismatch`] when the base binding does not +/// match the installed contract. pub fn check_descriptor_conformance( bindings: &[ProviderResourceTypeBinding], installed: &[ResourceSchemaContract], @@ -288,6 +297,15 @@ pub fn check_descriptor_conformance( /// Live conformance for one binding: the Provider advertises the installed /// base schema identity, and the canonical minimal valid base spec is /// accepted without any `spec.provider` extension. +/// +/// # Errors +/// +/// Returns [`ConformanceError::ResourceTypeNotInstalled`] when the bound +/// resource type has no installed contract, +/// [`ConformanceError::BaseSchemaMismatch`] when the base binding does not +/// match the installed contract, and +/// [`ConformanceError::MinimalBaseRejected`] when the canonical minimal base +/// spec is not accepted. pub fn check_provider_conformance( binding: &ProviderResourceTypeBinding, installed: &[ResourceSchemaContract], From 03634ce9c0aa529d9486e8b35d4aec3dfb76d588 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:34:19 -0700 Subject: [PATCH 143/726] audit: record wave-1 slice 6 Thirty-five rows applied or varied across the provider contracts, the bundle resolver, two providers, and the session engine, with the eight rows this slice never reached marked for a follow-up dispatch. --- .../2026-09-24-rust-skills-audit/ledger.md | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index d2eb5a959..ab388144e 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -55,18 +55,18 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0015` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/kernel_client.rs:225-227` | | | | `RS-0016` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broke` | | | | `RS-0017` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/` | | | -| `RS-0018` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential.rs:362, packages/d2b-contracts-provider/` | | | -| `RS-0020` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573, packages/` | | | -| `RS-0019` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:2374` | | | +| `RS-0018` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential.rs` | derive(Default) with #[default] on RotationPolicyClass::OnExpiry and RevocationAction::Immediate; manual Default impls deleted | | +| `RS-0020` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs` | producer_ref.transpose()? bound once; duplicate 15-field BindingChildIntent literal collapsed to one push, else-continue arm deleted | | +| `RS-0019` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | manual Debug impl on UpgradePolicy replaced by #[derive(Debug)] | | | `RS-0022` | `idiom` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume.rs:1210-1213, packages/d2b-contracts-resourc` | | | | `RS-0021` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src` | | | | `RS-0023` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/resource.rs:621-626` | | | | `RS-0024` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223` | | | | `RS-0025` | `idiom` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `src/v3/component_session.rs:1935, src/v3/component_session.rs:1976` | | | -| `RS-0027` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1805, packages/d2b-core/src/bundle_resolver.rs:19` | | | -| `RS-0030` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/static_invariants.rs:162, packages/d2b-core/src/static_invariants.rs` | | | -| `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:5746` | | | -| `RS-0029` | `idiom` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2434, packages/d2b-core/src/processes.rs:180` | | | +| `RS-0027` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | let spec = find_network_spec(&parts)?; let _ = spec; replaced by bare self.find_network_spec(&parts)?; in projection and sysctl intents | | +| `RS-0030` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | iter().any(f == last) replaced with slice contains for PUBLIC_MANIFEST_FIELDS and BROAD_CAPABILITIES | | +| `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | applied-variant | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | row's bare-import removal broke tests using TapRole via use super::*; variant: import dropped, const deleted, 3 test sites qualified crate::host::TapRole (as _ import rejected by -D warnings) | | +| `RS-0029` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | resolve_disk_init_ops flattened to vm.nodes.iter().flat_map(...).filter_map(...).collect() | | | `RS-0026` | `idiom` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:2189-2192, authority.rs:2542-2545` | | | | `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provid` | | | | `RS-0039` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:2812, src/policy.rs:12` | | | @@ -77,9 +77,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:379-386, packages/d2b-provider-config-nixo` | | | | `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | | | | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-e` | | | | `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:446, packages/d2b-provider-cred` | | | -| `RS-0047` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/authority.rs:401, packages/d2b-provider-device-gpu/sr` | | | -| `RS-0048` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/effects_service.rs:193` | | | -| `RS-0049` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/authority.rs:17, packages/d2b-provider-device-gpu/src` | | | +| `RS-0047` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | rustfmt drift normalized: enum closing brace, trailing-whitespace line, reindented variant doc comment | | +| `RS-0048` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/effects_service.rs` | let _ = binding dropped; Self::declared_row_template(&view, role)?; | | +| `RS-0049` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | in-crate macro_rules! opaque_token (derive list + is_zero/as_bytes feature arms, stringify redacting Debug); all 6 newtypes migrated with exact surfaces preserved | | | `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/driver.rs:380-390` | | | | `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `swtpm_argv.rs:160, lib.rs:63, lib.rs:65` | | | | `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `driver.rs:267-281` | | | @@ -92,7 +92,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provid` | | | | `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/effects_service.rs:50-60, packages/d2b-provider-endpoin` | | | | `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/endpoint.rs:395-398` | | | -| `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/bootstrap.rs:138, src/bootstrap.rs:124` | | | +| `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | derive(Default) with #[default] on BootstrapServiceState::Waiting; manual BootstrapService Default impl deleted | | | `RS-0063` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `controller.rs:1712, controller.rs:1744` | | | | `RS-0064` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `controller.rs:1722, controller.rs:1860, controller.rs:2042` | | | | `RS-0065` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:487-494, shutdown.rs:666-673` | | | @@ -130,8 +130,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | shared free manager_rpc transport; both endpoints route through it | | | `RS-0098` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | derive Default on TargetDirectory | | | `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | impl FromStr for ResourceProvenance; store parses via str::parse | | -| `RS-0100` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1802, engine.rs:1803, engine.rs:1807` | | | -| `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:1593, admission.rs:956, admission.rs:958` | | | +| `RS-0100` | `idiom` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/engine.rs` | index loop replaced with chunks_exact().take(count).map(decode_attachment_descriptor).collect::>>() | | +| `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/admission.rs` | send_authorized_ttrpc now calls validate_ttrpc_permit(&permit, now_tick)? instead of re-writing the matches! block | | | `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/config.rs:178` | | | | `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U2 | f3a847c72 | `packages/d2b-unsafe-local-helper/src/systemd.rs` | Replaced the then_some/ok_or NotFound normalization with an explicit if-let/if-error branch in terminate_scope and stop_scope; cargo check and test green. | | | `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/resolver.rs:144` | | | @@ -170,18 +170,18 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0132` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | ScopedCommitTransport::validate added; authorization_request validates borrowed data instead of cloning | | | `RS-0133` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/prologue.rs` | of_subject hashes &str slices via hash_resource_ref; digest byte-identical (full bus suite passed | | | `RS-0134` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/contract.rs` | private verify_body() shared by verify()/revalidate(); clone removed | | -| `RS-0137` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:497, packages/d2b-contracts-pro` | | | -| `RS-0135` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:2497, packages/d2b-contracts-provider/s` | | | -| `RS-0138` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:1591, packages/d2b-contrac` | | | -| `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:2438, packages/d2b-contracts-provider/s` | | | +| `RS-0137` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/telemetry_policy.rs` | duplicate-detection set now BTreeSet<&str> inserting &label.key | | +| `RS-0135` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | validate_runtime_artifacts takes &[TargetRuntimeArtifacts]; entries.clone() and self.runtime_artifacts.clone() dropped; test call site updated | | +| `RS-0138` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs` | is_valid_zone(&str) extracted; validate_zone delegates to it; allowed_telemetry_value no longer allocates | | +| `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | dedup sets now BTreeSet<&BoundedToken>/BTreeSet<&ResourceTypeName> in ProviderManifest::new and with_state_namespaces | | | `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume_state.rs:138` | | | | `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `zone_routing.rs:883` | | | | `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | | `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `resource_bundle.rs:944, resource_bundle.rs:149` | | | | `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | | `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `services.rs:216` | | | -| `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/static_invariants.rs:201` | | | -| `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1973, packages/d2b-core/src/bundle_resolver.rs:33` | | | +| `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | path_bearing_key_violations renders through Cow; string arm borrows instead of cloning | | +| `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | parse(value.as_str()) at 3 sites; network_uid compare via as_str; note: row rationale 'no allocation' inaccurate (Into still allocates) but explicit clones removed | | | `RS-0145` | `own` | `d2b-core-controller` | low | actionable | leaf | | | | `owner_reconcile.rs:1072-1075` | | | | `RS-0146` | `own` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:2803, authority.rs:2806` | | | | `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/t` | | | @@ -189,22 +189,22 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | | | | `RS-0156` | `own` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:111, packages/d2b-provider-config-nixos/sr` | | | | `RS-0157` | `own` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/t` | | | -| `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:272, packages/d2b-provider-device-gpu/s` | | | +| `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | validate &identity before store; identity stored on failure branch preserving test-pinned retain-for-finalize contract | | | `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `resource_controller.rs:233, resource_controller.rs:247, effects_service.rs:280, effects_se` | | | | `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `broker.rs:194-208, broker.rs:218-232, broker.rs:313-321, broker.rs:333-341` | | | | `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provid` | | | | `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/driver.rs:981` | | | | `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/ef` | | | -| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:156-157` | | | -| `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:500-501` | | | -| `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:527` | | | -| `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:417-419, src/controller.rs:469-471` | | | -| `RS-0168` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/controller.rs:892, src/controller.rs:903` | | | -| `RS-0169` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/effects.rs:450-464` | | | -| `RS-0170` | `own` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:791, src/bootstrap.rs:42` | | | -| `RS-0171` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:640, src/controller/mod.rs:764` | | | -| `RS-0172` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:852` | | | -| `RS-0173` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:1046` | | | +| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:156-157` | budget stop before azure-container-apps crate | | +| `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:500-501` | budget stop before azure-container-apps crate | | +| `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:527` | budget stop before azure-container-apps crate | | +| `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:417-419, src/controller.rs:469-471` | budget stop before azure-container-apps crate | | +| `RS-0168` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:892, src/controller.rs:903` | budget stop before azure-container-apps crate | | +| `RS-0169` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/effects.rs:450-464` | budget stop before azure-container-apps crate | | +| `RS-0170` | `own` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied-variant | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | zeroize here lacks into_inner and From> for T; variant: std::mem::take(&mut *delivery) moves buffer out, no plain Vec copy | | +| `RS-0171` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | both vm_handle sites borrow via as_ref().ok_or(AzureVmError::Ambiguous) instead of cloning | | +| `RS-0172` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | pending_delete_operation_id borrowed via as_deref() instead of clone | | +| `RS-0173` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | base32 output truncated in place (id.truncate(20)) instead of a second 20-char copy | | | `RS-0174` | `own` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266` | | | | `RS-0175` | `own` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266` | | | | `RS-0176` | `own` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/controller.rs:416-417` | | | @@ -689,14 +689,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wi` | | | | `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | | | | `terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105` | | | | `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | -| `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:250, packages/d2b-contracts-provider/sr` | | | +| `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | | `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/` | | | | `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | | | | `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/limits.rs:3, packages/d2b-contracts-resource/src/v3` | | | | `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | | | | `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | | | | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | | | -| `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/manifest_v04.rs:1, packages/d2b-core/src/manifest_v04.rs:31, package` | | | -| `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2917, packages/d2b-core/src/bundle_resolver.rs:29` | | | +| `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/manifest_v04.rs` | module doc plus docs on ManifestV04/ManifestMeta/ObservabilityMeta/VmEntry/VmLifecycle/VmGracefulShutdown/VmLiveActivation/VmLanPolicy/VmObservability/VmShellMetadata/ManifestShellName; # Errors on fr | | +| `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | one-line docs naming the exact BundleOpId shape added to all 15 undocumented intent_id_* constructors | | | `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controlle` | | | | `RS-0653` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `migration.rs:54, migration.rs:58` | | | | `RS-0656` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/bridge_port.rs` | Added # Errors to validate_readback, parse_request, parse_validation_request, validate_media_ref, validate_usb_busid, and NftBatch::parse (the wire-boundary parsers the row names). | | @@ -719,8 +719,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0675` | `docs` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U2 | e86206bab | `packages/d2b-provider-credential-managed-identity/src/lib.rs` | Added # Errors naming ManagedIdentityProviderError/CredentialServiceError/CredentialObservabilityError variants to the named constructors and controller projections. | | | `RS-0676` | `docs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-cred` | | | | `RS-0677` | `docs` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-` | | | -| `RS-0678` | `docs` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:172, packages/d2b-provider-device-gpu/s` | | | -| `RS-0679` | `docs` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/gpu_argv.rs:24, packages/d2b-provider-device-gpu/src/` | | | +| `RS-0678` | `docs` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | # Errors sections added to all 16 named Result-returning items with exact error variants | | +| `RS-0679` | `docs` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/gpu_argv.rs` | dropping the allows exposed 15 more undocumented variants/fields under deny(missing_docs); documented GpuContextType variants, GpuArgvError/VideoArgvError variants+path fields, VideoBackend::Vaapi, pl | | | `RS-0681` | `docs` | `d2b-provider-device-security-key` | medium | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/lease.rs:150-303, packages/d2b-provider-devi` | | | | `RS-0680` | `docs` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/relay.rs:7, packages/d2b-provider-device-sec` | | | | `RS-0682` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `resources.rs:53, swtpm_argv.rs:130, resource_controller.rs:132, resource_controller.rs:190` | | | @@ -731,9 +731,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provide` | | | | `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759` | | | | `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/facets.rs:63, packages/d2b-provider-guest/src/target_contr` | | | -| `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/lib.rs:7, src/effects.rs:813-882` | | | -| `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:333, src/controller/mod.rs:446` | | | -| `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/bootstrap.rs:25` | | | +| `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/lib.rs:7, src/effects.rs:813-882` | budget stop before azure-container-apps crate | | +| `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | +| `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | matches() doc states the constant-time-in-presented-length guarantee | | | `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `descriptor.rs:423-429, identity.rs:590-634` | | | | `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs:82, packages/d2b-pro` | | | | `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provide` | | | @@ -767,11 +767,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0723` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | TargetControlAssignment five methods documented | | | `RS-0724` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | doc contracts on target/spec/identity accessors | | | `RS-0725` | `docs` | `d2b-resource-types` | low | actionable | leaf | applied | U2 | 61c64bf0f | `packages/d2b-resource-types/src/operation.rs` | Restored the missing spaces after commas in the OperationCtx::fds field docs. | | -| `RS-0726` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239` | | | -| `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | | | | `lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62` | | | -| `RS-0727` | `docs` | `d2b-session` | low | actionable | leaf | | | | `operation.rs:207` | | | -| `RS-0729` | `docs` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:1182, admission.rs:1186, admission.rs:1190, admission.rs:1194` | | | -| `RS-0730` | `docs` | `d2b-session` | low | actionable | leaf | | | | `transport.rs:208, transport.rs:212` | | | +| `RS-0726` | `docs` | `d2b-session` | medium | actionable | leaf | applied | U2 | 6970c9d9e | `packages/d2b-session/src/handshake.rs` | first-sentence docs plus # Errors naming SessionErrorCode added to x25519_public_key, constants, HandshakeRole, HandshakeCredentials, NegotiatedOffer+accessors, encode_offer, negotiate_offer, generati | | +| `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | not-started | U2 | | `lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62` | budget stop before lifecycle.rs/record.rs/bootstrap.rs/deadline.rs item docs | | +| `RS-0727` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/operation.rs` | MAX_MEMBER_SPELLING_LEN const extracted with wire-bound comment; parse uses it | | +| `RS-0729` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/admission.rs` | one-line docs on route-binding accessors, SessionErrorClass::as_str, SessionError accessors, TransportPacket methods | | +| `RS-0730` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 6970c9d9e | `packages/d2b-session/src/transport.rs` | serialized_transport_split doc rewritten to the serialized-compatibility contract (halves must never be driven concurrently) | | | `RS-0731` | `docs` | `d2b-session-unix` | medium | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added first-sentence contract docs to SeqpacketSocket, UnixSeqpacketTransport, UnixStreamTransport, CreditPool, PidfdEvidence, PeerCredentials, ActivatedSeqpacketListener(s), FramedVsockTransport and | | | `RS-0732` | `docs` | `d2b-session-unix` | low | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added # Errors to the anchor Result fns (SeqpacketSocket::from_owned/from_parent_prearmed/from_inherited_fd, UnixSeqpacketTransport::new, CreditPool::new, PidfdEvidence::new) naming their distinct fai | | | `RS-0733` | `docs` | `d2b-telemetry` | low | actionable | leaf | applied | U2 | e1fab0e9b | `packages/d2b-telemetry/src/audit_hash.rs` | Added # Errors naming the returned variants to every named item: AuditHash::parse, AuditChainLink::verify/verify_at, all eight BoundedEmitter fns, MetricFamily/MeterRegistry, RedactionGuard, validate_ | | From d6adc6a8ed0a0d74d7762e75056b401c3af0498a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:34:45 -0700 Subject: [PATCH 144/726] provider: move dispatch request and document error contracts --- packages/d2b-provider/src/agent.rs | 19 ++++++++++++-- packages/d2b-provider/src/context.rs | 8 ++++++ packages/d2b-provider/src/descriptor.rs | 26 +++++++++++++++++++ packages/d2b-provider/src/identity.rs | 15 +++++++++++ packages/d2b-provider/src/instance.rs | 5 ++++ packages/d2b-provider/src/operation_ledger.rs | 12 +++++++++ packages/d2b-provider/src/registry.rs | 24 +++++++++++++++++ packages/d2b-provider/src/session.rs | 13 ++++++++++ 8 files changed, 120 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider/src/agent.rs b/packages/d2b-provider/src/agent.rs index a36029019..058671e45 100644 --- a/packages/d2b-provider/src/agent.rs +++ b/packages/d2b-provider/src/agent.rs @@ -37,6 +37,11 @@ pub struct ProviderAgentRequest { impl ProviderAgentRequest { /// Construct a bounded request. + /// + /// # Errors + /// + /// Returns [`ProviderAgentError::InvalidTimeout`] when the timeout is + /// zero or exceeds the agent ceiling. pub fn new( service: ServiceName, method: SpecifiedProviderMethod, @@ -267,6 +272,15 @@ where S: ProviderAgentService, { /// Dispatch one request with a bounded timeout. + /// + /// # Errors + /// + /// Returns [`ProviderAgentError::UnsupportedService`] when the request + /// names a service other than `d2b.provider.v3`, + /// [`ProviderAgentError::DispatchSaturated`] when the in-flight budget + /// is exhausted, [`ProviderAgentError::DispatchTimeout`] when the + /// request exceeds its timeout, and + /// [`ProviderAgentError::HandlerFailed`] when the handler refuses. pub async fn dispatch( &self, request: ProviderAgentRequest, @@ -280,6 +294,7 @@ where .await; return Err(ProviderAgentError::UnsupportedService); } + let method = request.method; let permit = self .permits .clone() @@ -287,7 +302,7 @@ where .map_err(|_| ProviderAgentError::DispatchSaturated)?; let result = timeout( Duration::from_millis(request.timeout_ms), - self.service.dispatch(request.clone()), + self.service.dispatch(request), ) .await .map_err(|_| ProviderAgentError::DispatchTimeout)? @@ -299,7 +314,7 @@ where } else { ProviderAgentOutcome::Failed }, - request.method, + method, self.provider_axis, )) .await; diff --git a/packages/d2b-provider/src/context.rs b/packages/d2b-provider/src/context.rs index 966638776..c84e726a3 100644 --- a/packages/d2b-provider/src/context.rs +++ b/packages/d2b-provider/src/context.rs @@ -56,6 +56,14 @@ pub struct OwnedOperationContext { } impl OwnedOperationContext { + /// Link one operation context to its cancellation set. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::DeadlineExpired`] when the deadline + /// is zero, over the ceiling, or overflows the clock, and + /// [`ProviderRuntimeError::Cancelled`] when no cancellation token is + /// linked. pub(crate) fn new_linked( identity: SessionIdentity, method: ProviderMethodName, diff --git a/packages/d2b-provider/src/descriptor.rs b/packages/d2b-provider/src/descriptor.rs index 8785a8438..d76231049 100644 --- a/packages/d2b-provider/src/descriptor.rs +++ b/packages/d2b-provider/src/descriptor.rs @@ -52,6 +52,12 @@ pub enum RepairPolicy { impl RepairPolicy { /// Build a bounded repair policy. + /// + /// # Errors + /// + /// Returns [`RegistryBuildError::InvalidDescriptor`] when a bound is + /// zero, the retry interval exceeds the window, or the window exceeds + /// the repair ceiling. pub const fn bounded( retry_after_ms: u32, max_elapsed_ms: u32, @@ -106,6 +112,12 @@ impl RepairPolicy { } /// Validate this policy against the Provider family. + /// + /// # Errors + /// + /// Returns [`RegistryBuildError::InvalidDescriptor`] when a bound is + /// zero or inverted, the window exceeds the ceiling, or the class + /// device bound is exceeded. pub const fn validate(self, class: ProviderClass) -> Result<(), RegistryBuildError> { match self { Self::Bounded { @@ -192,6 +204,12 @@ pub struct ProviderDescriptor { impl ProviderDescriptor { /// Build a descriptor at the current Provider schema version. + /// + /// # Errors + /// + /// Returns the first [`RegistryBuildError`] the invariant checks + /// report: an unsupported schema version, a non-Provider reference, an + /// invalid or empty capability set, or a repair-policy refusal. #[allow(clippy::too_many_arguments)] pub fn new( zone: ZonePath, @@ -229,6 +247,14 @@ impl ProviderDescriptor { } /// Re-check every descriptor invariant. + /// + /// # Errors + /// + /// Returns [`RegistryBuildError::UnsupportedSchemaVersion`] when the + /// schema version is not current, [`RegistryBuildError::NotAProviderRef`] + /// when the reference does not name a Provider, and + /// [`RegistryBuildError::InvalidDescriptor`] for the remaining + /// invariant or bound refusals. pub fn validate(&self) -> Result<(), RegistryBuildError> { if self.schema_version != PROVIDER_SCHEMA_VERSION { return Err(RegistryBuildError::UnsupportedSchemaVersion); diff --git a/packages/d2b-provider/src/identity.rs b/packages/d2b-provider/src/identity.rs index 9844e3f64..ed47dfced 100644 --- a/packages/d2b-provider/src/identity.rs +++ b/packages/d2b-provider/src/identity.rs @@ -95,6 +95,11 @@ pub struct ProviderImplementationId(BoundedToken); impl ProviderImplementationId { /// Parse one bounded implementation token. + /// + /// # Errors + /// + /// Returns [`PrimitiveSpecError::InvalidToken`] when the value is not + /// a bounded token. pub fn parse(value: impl Into) -> Result { BoundedToken::parse(value).map(Self) } @@ -117,6 +122,11 @@ pub struct ProviderMethodName(BoundedToken); impl ProviderMethodName { /// Parse one bounded method token. + /// + /// # Errors + /// + /// Returns [`PrimitiveSpecError::InvalidToken`] when the value is not + /// a bounded token. pub fn parse(value: impl Into) -> Result { BoundedToken::parse(value).map(Self) } @@ -139,6 +149,11 @@ pub struct ProviderCapabilitySet(BTreeSet); impl ProviderCapabilitySet { /// Build a bounded, non-empty capability set. + /// + /// # Errors + /// + /// Returns [`RegistryBuildError::BoundExceeded`] when the set is empty + /// or exceeds the capability ceiling. pub fn new( methods: impl IntoIterator, ) -> Result { diff --git a/packages/d2b-provider/src/instance.rs b/packages/d2b-provider/src/instance.rs index efa97e8d0..1a6780397 100644 --- a/packages/d2b-provider/src/instance.rs +++ b/packages/d2b-provider/src/instance.rs @@ -25,6 +25,11 @@ pub struct ProviderInstance { impl ProviderInstance { /// Construct a ready instance handle. + /// + /// # Errors + /// + /// Returns [`crate::error::RegistryBuildError::NotAProviderRef`] when + /// the reference does not name a Provider. pub fn new( provider_ref: ResourceRef, generation: ResourceGeneration, diff --git a/packages/d2b-provider/src/operation_ledger.rs b/packages/d2b-provider/src/operation_ledger.rs index 85da55182..c4811280b 100644 --- a/packages/d2b-provider/src/operation_ledger.rs +++ b/packages/d2b-provider/src/operation_ledger.rs @@ -176,6 +176,11 @@ impl OperationLedger { } /// Construct a ledger with a test or owner-local bound. + /// + /// # Errors + /// + /// Returns [`OperationLedgerError::CapacityExceeded`] when the + /// capacity is zero or exceeds the frozen maximum. pub fn with_capacity(capacity: usize) -> Result { if capacity == 0 || capacity > MAX_OPERATION_LEDGER_ROWS { return Err(OperationLedgerError::CapacityExceeded); @@ -192,6 +197,13 @@ impl OperationLedger { /// Rejoining with a newer session generation updates only the reconnect /// binding. Resource identity, desired generation, operation ID, and /// durable state remain unchanged. + /// + /// # Errors + /// + /// Returns [`OperationLedgerError::InvalidSessionGeneration`] when the + /// session generation is zero, [`OperationLedgerError::StaleSessionGeneration`] + /// when it is older than the row's latest, and + /// [`OperationLedgerError::CapacityExceeded`] when the ledger is full. pub fn admit( &mut self, resource_uid: ResourceUid, diff --git a/packages/d2b-provider/src/registry.rs b/packages/d2b-provider/src/registry.rs index d31479b57..17d8f844f 100644 --- a/packages/d2b-provider/src/registry.rs +++ b/packages/d2b-provider/src/registry.rs @@ -61,6 +61,11 @@ pub struct RegistryLimits { impl RegistryLimits { /// Reject a zero cap or a per-provider cap above the total. + /// + /// # Errors + /// + /// Returns [`RegistryBuildError::BoundExceeded`] when a cap is zero or + /// the per-provider cap exceeds the total. pub fn validate(self) -> Result { if self.total_in_flight == 0 || self.per_provider_in_flight == 0 @@ -96,6 +101,12 @@ pub struct RegistryDrainPolicy { impl RegistryDrainPolicy { /// Reject a zero or over-long deadline, or a policy that leaks work past /// retirement. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::InvalidDrainPolicy`] when the + /// deadline is zero or over the ceiling, or the policy does not cancel + /// in-flight work and close sessions at retirement. pub const fn validate(&self) -> Result<(), ProviderRuntimeError> { if self.drain_deadline_ms == 0 || self.drain_deadline_ms > MAX_REGISTRY_DRAIN_MS @@ -326,6 +337,12 @@ impl ProviderRegistryBuilder { } /// Seal the generation. + /// + /// # Errors + /// + /// Returns [`RegistryBuildError::TransactionAborted`] when a prior + /// builder step failed and [`RegistryBuildError::EmptyRegistry`] when + /// no instance was installed. pub fn finish(self) -> Result, RegistryBuildError> { if self.failed { return Err(RegistryBuildError::TransactionAborted); @@ -406,6 +423,13 @@ impl ProviderRegistry { /// Provider must be installed here, the authenticated identity must match /// the descriptor exactly, the Provider must publish the method, and a /// permit must be available. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::NotAccepting`] when the generation + /// is not accepting, [`ProviderRuntimeError::UnknownProvider`] when + /// the Provider is not installed here, and the identity, method, or + /// permit refusal otherwise. pub fn admit( &self, options: AdmissionOptions, diff --git a/packages/d2b-provider/src/session.rs b/packages/d2b-provider/src/session.rs index f6ae87cdf..d0d641474 100644 --- a/packages/d2b-provider/src/session.rs +++ b/packages/d2b-provider/src/session.rs @@ -33,6 +33,13 @@ impl SessionIdentity { /// `zone` is supplied by the local Zone runtime that owns the registry, /// not by the peer. The subject must already carry the Provider binding /// and Provider/session generations its evidence established. + /// + /// # Errors + /// + /// Returns [`ProviderRuntimeError::MissingProviderBinding`] when the + /// subject carries no Provider binding or its reference is not a + /// Provider, and the generation refusal when the evidence is + /// incomplete. pub fn from_authenticated( zone: ZonePath, subject: &AuthenticatedSubjectContext, @@ -91,6 +98,12 @@ impl SessionIdentity { /// /// Zone, Provider reference, Provider generation, and service must all /// match exactly; a near miss is a refusal, never a coercion. + /// + /// # Errors + /// + /// Returns the identity-mismatch refusal when any of the Zone, + /// Provider reference, Provider generation, session generation, or + /// service differs from the descriptor. pub fn matches_descriptor( &self, descriptor: &ProviderDescriptor, From b68a9b55eeb0a8a8cfe6e8d7fd7d751c81c56833 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:35:33 -0700 Subject: [PATCH 145/726] credential: drop dead derives and document revocation errors --- packages/d2b-provider-credential/src/driver.rs | 1 - packages/d2b-provider-credential/src/session.rs | 12 ++++++++++++ packages/d2b-provider-credential/src/test_support.rs | 3 +-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-credential/src/driver.rs b/packages/d2b-provider-credential/src/driver.rs index 6436f7b5c..8ea9c21d0 100644 --- a/packages/d2b-provider-credential/src/driver.rs +++ b/packages/d2b-provider-credential/src/driver.rs @@ -339,7 +339,6 @@ impl ResourceDriverFactory for CredentialDriverFactory { // --------------------------------------------------------------------------- /// One Credential resource's driver. -#[derive(Clone)] pub struct CredentialDriver { zone: String, controller_generation: ControllerGeneration, diff --git a/packages/d2b-provider-credential/src/session.rs b/packages/d2b-provider-credential/src/session.rs index 167b66236..292ee5a08 100644 --- a/packages/d2b-provider-credential/src/session.rs +++ b/packages/d2b-provider-credential/src/session.rs @@ -129,6 +129,13 @@ impl CredentialRevocationRequest { /// constructible for a credential Provider with a live (non-zero) /// session generation; everything else fails closed as /// [`CredentialResourceRuntimeError::InvalidResource`]. + /// + /// # Errors + /// + /// Returns [`CredentialResourceRuntimeError::InvalidResource`] when + /// the session generation is zero or unknown, the rotation generation + /// is zero, or the Provider reference does not name a credential + /// Provider. pub fn new(inputs: CredentialRevocationInputs) -> Result { if inputs.session_generation.get() == 0 || inputs.rotation_generation == 0 @@ -272,6 +279,11 @@ pub trait CredentialSession: Send + Sync { /// Revoke one credential lease through the authenticated Provider /// session. + /// + /// # Errors + /// + /// Returns [`CredentialResourceRuntimeError::Revocation`] when the + /// session refuses or cannot confirm the revocation. async fn revoke_credential( &self, request: &CredentialRevocationRequest, diff --git a/packages/d2b-provider-credential/src/test_support.rs b/packages/d2b-provider-credential/src/test_support.rs index 8a272a503..9c4e2eba4 100644 --- a/packages/d2b-provider-credential/src/test_support.rs +++ b/packages/d2b-provider-credential/src/test_support.rs @@ -174,8 +174,7 @@ impl CredentialSession for RecordingSession { /// settable, so the plane can assert both event ordering and the scripted /// answers. The defaults match [`FakeEffects::new`]'s: provider and /// execution ready, no lease facts, agent ready, and a live session bound -/// to generation 7. -#[derive(Default)] +/// generation 7. pub struct RecordingRuntime { log: Log, facts: Mutex>, From f66537394a56506447db63b41d79825c6193ca66 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:35:37 -0700 Subject: [PATCH 146/726] refactor(d2b-provider-transport-azure-relay): derive Clone and consume requests in deadline rebinding --- .../src/credential_client.rs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/d2b-provider-transport-azure-relay/src/credential_client.rs b/packages/d2b-provider-transport-azure-relay/src/credential_client.rs index 1e05dd444..6d3f61740 100644 --- a/packages/d2b-provider-transport-azure-relay/src/credential_client.rs +++ b/packages/d2b-provider-transport-azure-relay/src/credential_client.rs @@ -187,15 +187,10 @@ impl ScopedCredentialRequest { } /// Rebind only the attempt deadline without widening scope. - pub fn with_deadline(&self, deadline_ms: u32) -> Result { - Self::new( - self.zone.clone(), - self.credential_ref.clone(), - self.execution_ref.clone(), - self.role, - self.binding.clone(), - deadline_ms, - ) + pub fn with_deadline(self, deadline_ms: u32) -> Result { + let request = Self { deadline_ms, ..self }; + request.validate()?; + Ok(request) } } @@ -214,6 +209,7 @@ impl fmt::Debug for ScopedCredentialRequest { } /// Bounded zeroizing secret. +#[derive(Clone)] pub struct RelaySecret(Zeroizing>); impl RelaySecret { @@ -233,12 +229,6 @@ impl RelaySecret { } } -impl Clone for RelaySecret { - fn clone(&self) -> Self { - Self(Zeroizing::new(self.0.to_vec())) - } -} - impl fmt::Debug for RelaySecret { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("RelaySecret()") From 6fe6615afe9abfa1a626848308f1611cfabec9f3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:35:37 -0700 Subject: [PATCH 147/726] refactor(d2b-provider-transport-azure-relay): use a literal bearer scheme --- .../src/auth.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/d2b-provider-transport-azure-relay/src/auth.rs b/packages/d2b-provider-transport-azure-relay/src/auth.rs index e82f2a42d..eb144f323 100644 --- a/packages/d2b-provider-transport-azure-relay/src/auth.rs +++ b/packages/d2b-provider-transport-azure-relay/src/auth.rs @@ -181,6 +181,14 @@ pub const DEFAULT_SAS_TTL_SECS: u64 = MAX_SAS_TTL_SECS; /// /// The returned string is secret (it is a bearer); callers must treat it as /// such (it is never logged by this crate). +/// # Errors +/// +/// Returns [`RelayError::InvalidTtl`] for a zero TTL, +/// [`RelayError::TtlTooLong`] above the fixed bound, +/// [`RelayError::InvalidEndpoint`] for a malformed endpoint, +/// [`RelayError::InvalidCredential`] for a malformed key name or key, +/// [`RelayError::Key`] when the key cannot seed the HMAC, and +/// [`RelayError::Clock`] when the system clock predates the Unix epoch. pub fn mint_sas( endpoint: &RelayEndpoint, key_name: &str, @@ -223,6 +231,10 @@ pub fn mint_sas( /// `ServiceBusAuthorization` header. A pre-minted SAS bearer is /// also accepted for the ACA path; it is already scoped/expiring, so this /// function only URL-encodes it into `sb-hc-token`. +/// # Errors +/// +/// Returns the same errors as [`mint_sas`] for SAS credentials and +/// [`RelayError::InvalidEndpoint`] for a malformed endpoint. pub fn build_connect( endpoint: &RelayEndpoint, role: RelayRole, @@ -245,12 +257,7 @@ pub fn build_connect( match credential { RelayCredential::EntraBearer(token) => Ok(RelayConnect { url: base, - auth_header: Some(format!( - "{} {token}", - ['B', 'e', 'a', 'r', 'e', 'r'] - .into_iter() - .collect::() - )), + auth_header: Some(format!("Bearer {token}")), }), RelayCredential::SasToken(token) => Ok(RelayConnect { url: format!("{base}&sb-hc-token={}", urlencoding::encode(token)), From 72858f53729402d550ddf568d25036393bcef93e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:35:37 -0700 Subject: [PATCH 148/726] refactor(d2b-provider-transport-azure-relay): store gateway credential material by move --- .../src/guest_credential.rs | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs index 10f3e3efe..ead7503d3 100644 --- a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs +++ b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs @@ -128,10 +128,7 @@ pub struct CredentialEnvelopeMeta { /// A loaded gateway credential envelope. `Debug` redacts all secret material. #[derive(Clone)] pub struct GatewayCredential { - listen_key_name: String, - listen_key: String, - send_key_name: String, - send_key: String, + material: GatewayCredentialMaterial, generation: u64, not_after: Option, } @@ -139,9 +136,9 @@ pub struct GatewayCredential { impl core::fmt::Debug for GatewayCredential { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("GatewayCredential") - .field("listen_key_name", &self.listen_key_name) + .field("listen_key_name", &self.material.listen_key_name) .field("listen_key", &"") - .field("send_key_name", &self.send_key_name) + .field("send_key_name", &self.material.send_key_name) .field("send_key", &"") .field("generation", &self.generation) .field("not_after", &self.not_after) @@ -149,15 +146,6 @@ impl core::fmt::Debug for GatewayCredential { } } -impl Drop for GatewayCredential { - fn drop(&mut self) { - self.listen_key_name.zeroize(); - self.listen_key.zeroize(); - self.send_key_name.zeroize(); - self.send_key.zeroize(); - } -} - impl GatewayCredential { /// Load and validate the legacy plaintext credential envelope at `path`. /// @@ -269,10 +257,7 @@ impl GatewayCredential { meta: CredentialEnvelopeMeta, ) -> Result { Ok(Self { - listen_key_name: material.listen_key_name.clone(), - listen_key: material.listen_key.clone(), - send_key_name: material.send_key_name.clone(), - send_key: material.send_key.clone(), + material, generation: meta.generation, not_after: meta.not_after, }) @@ -341,7 +326,7 @@ impl GatewayGuestCredentialPort { /// sealed envelope has been opened; credential bytes never leave this /// port. pub fn safe_observation_digest(&self) -> [u8; 32] { - Sha256::digest(self.credential.send_key.as_bytes()).into() + Sha256::digest(self.credential.material.send_key.as_bytes()).into() } /// Return the number of currently revocable leases. @@ -359,11 +344,11 @@ impl GatewayGuestCredentialPort { ) -> Result { let (key_name, key) = match role { RelayCredentialRole::Listen => ( - &self.credential.listen_key_name, - &self.credential.listen_key, + &self.credential.material.listen_key_name, + &self.credential.material.listen_key, ), RelayCredentialRole::Send => { - (&self.credential.send_key_name, &self.credential.send_key) + (&self.credential.material.send_key_name, &self.credential.material.send_key) } }; Ok(RelayCredentialMaterial::SasRule { From 33a84349d7abdc8b1f9101cb7da15197be6a388e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:35:38 -0700 Subject: [PATCH 149/726] docs(d2b-provider-transport-azure-relay): document error conditions on public APIs --- .../d2b-provider-transport-azure-relay/src/backpressure.rs | 4 ++++ .../src/transport_settings.rs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/packages/d2b-provider-transport-azure-relay/src/backpressure.rs b/packages/d2b-provider-transport-azure-relay/src/backpressure.rs index b9cbf5714..a22133bcc 100644 --- a/packages/d2b-provider-transport-azure-relay/src/backpressure.rs +++ b/packages/d2b-provider-transport-azure-relay/src/backpressure.rs @@ -23,6 +23,10 @@ pub struct CreditWindow { impl CreditWindow { /// Construct a nonzero bounded window. pub fn new(max_bytes: usize) -> Result { + // # Errors + // + // Returns [`BackpressureError::CreditExhausted`] when the window is + // zero or exceeds the fixed bound. if max_bytes == 0 || max_bytes > 16 * 1024 * 1024 { return Err(BackpressureError::CreditExhausted); } diff --git a/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs b/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs index e3e8ceadf..610abf1ca 100644 --- a/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs +++ b/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs @@ -16,6 +16,11 @@ pub struct RelayTransportSettings { impl RelayTransportSettings { /// Construct validated settings. + /// + /// # Errors + /// + /// Returns [`RelayTransportSettingsError`] when the namespace or entity + /// fails validation. pub fn new( relay_namespace_id: impl Into, relay_entity_id: impl Into, From f0a67ccd5bab5c916b16d57ba33a9df60eb118b4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:36:27 -0700 Subject: [PATCH 150/726] guest: borrow sort keys and candidates, document error contracts --- packages/d2b-provider-guest/src/driver.rs | 11 ++++++++++- .../d2b-provider-guest/src/effects_service.rs | 4 ++-- packages/d2b-provider-guest/src/facets.rs | 4 ++++ packages/d2b-provider-guest/src/target_control.rs | 5 +++++ packages/d2b-provider-guest/src/target_service.rs | 15 +++++++++++++++ 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index dece223af..423c963c3 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -400,6 +400,11 @@ pub fn decode_metadata(raw: &[u8]) -> Result { /// Convert one durable 16-byte uid to its canonical identity (the manager /// persists the uid as bytes; the Provider effects key on the canonical /// string). +/// +/// # Errors +/// +/// Returns [`GuestEffectError::InvalidResource`] when the bytes are not a +/// canonical resource uid. pub fn resource_uid(bytes: &[u8; 16]) -> Result { ResourceUid::from_bytes(bytes).map_err(|_| GuestEffectError::InvalidResource) } @@ -978,7 +983,11 @@ impl GuestDriver { .any(|child| owned_child_matches_child_ensure(row, child)) }) .collect::>(); - obsolete.sort_by_key(|row| (teardown_rank(&row.key.type_name), row.key.name.clone())); + obsolete.sort_by(|a, b| { + teardown_rank(&a.key.type_name) + .cmp(&teardown_rank(&b.key.type_name)) + .then_with(|| a.key.name.cmp(&b.key.name)) + }); let mut mutated = false; for row in obsolete { ctx.delete(&row.key) diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index fa2e0db68..6b94d8311 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -240,7 +240,7 @@ impl aca_runtime::AcaControl for FrameworkAcaControl { { sandbox.lifecycle = aca_runtime::AcaSandboxLifecycle::Running; } - aca_runtime::AcaSandboxCandidates::new(state.sandbox.clone().into_iter().collect()) + aca_runtime::AcaSandboxCandidates::new(state.sandbox.iter().cloned().collect()) .map_err(|_| { aca_runtime::AcaControlError::new(aca_runtime::AcaControlErrorKind::InvalidResponse) }) @@ -253,7 +253,7 @@ impl aca_runtime::AcaControl for FrameworkAcaControl { _desired: &aca_runtime::AcaDesiredDiskImage, ) -> Result { let state = self.state.lock().await; - aca_runtime::AcaDiskImageCandidates::new(state.disk_image.clone().into_iter().collect()) + aca_runtime::AcaDiskImageCandidates::new(state.disk_image.iter().cloned().collect()) .map_err(|_| { aca_runtime::AcaControlError::new(aca_runtime::AcaControlErrorKind::InvalidResponse) }) diff --git a/packages/d2b-provider-guest/src/facets.rs b/packages/d2b-provider-guest/src/facets.rs index fe31464cb..1240806fb 100644 --- a/packages/d2b-provider-guest/src/facets.rs +++ b/packages/d2b-provider-guest/src/facets.rs @@ -60,6 +60,10 @@ pub trait GuestManagerView: Send + Sync + 'static { /// The manager view of one row: `Ok(Some(view))` when the manager holds /// the row, `Ok(None)` when it answered that it holds no such row, and /// `Err` when the plane could not answer. + /// + /// # Errors + /// + /// Returns `Err` when the manager plane could not answer. async fn row_view(&self, key: &ResourceKey) -> Result, ()>; /// The committed Provider identity for one canonical Provider diff --git a/packages/d2b-provider-guest/src/target_control.rs b/packages/d2b-provider-guest/src/target_control.rs index 1c72cb6ec..71ff8c1fb 100644 --- a/packages/d2b-provider-guest/src/target_control.rs +++ b/packages/d2b-provider-guest/src/target_control.rs @@ -92,6 +92,11 @@ impl TargetControlChannel for SessionTargetControlChannel /// The returned handle is generation-bound: a request naming another /// generation is refused host-side, and the guest refuses it again on the /// wire. +/// +/// # Errors +/// +/// Returns the [`GuestTargetError`] the client construction reports when +/// the session generation binding cannot be established. pub fn session_target_control( session: S, session_generation: u64, diff --git a/packages/d2b-provider-guest/src/target_service.rs b/packages/d2b-provider-guest/src/target_service.rs index 244f0706f..e12e418ff 100644 --- a/packages/d2b-provider-guest/src/target_service.rs +++ b/packages/d2b-provider-guest/src/target_service.rs @@ -65,16 +65,31 @@ pub trait GuestTargetEffect: Send + Sync + 'static { /// `Ok` means the effect is serving; the realization is then reported /// `ready`. Any error leaves the realization `realizing` - the owning /// Host driver's next realize retries it. + /// + /// # Errors + /// + /// Returns the [`GuestTargetEffectError`] the target-local effect + /// reports; the realization stays `realizing` and is retried. async fn realize( &self, request: &GuestRealizeRequest, ) -> Result<(), GuestTargetEffectError>; /// Remove the target-local effect for one source. + /// + /// # Errors + /// + /// Returns the [`GuestTargetEffectError`] the target-local effect + /// reports when removal fails. async fn delete(&self, source: &ResourceKey) -> Result<(), GuestTargetEffectError>; /// Re-discover the target-local effect after a reconnect (F5) and report /// whether it is present and serving. + /// + /// # Errors + /// + /// Returns the [`GuestTargetEffectError`] the target-local effect + /// reports when discovery fails. async fn adopt(&self, source: &ResourceKey) -> Result; } From 11083ae48b6989699d1c4ff9d3583164be3cf31d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:37:41 -0700 Subject: [PATCH 151/726] observability-otel: borrow token parses, document constants and errors --- .../src/agent.rs | 32 +++++++++++++++---- .../src/config.rs | 5 +++ .../src/controller.rs | 12 +++++++ .../src/emitter_socket.rs | 11 +++++++ .../src/lib.rs | 3 ++ .../src/metric_policy.rs | 7 ++++ 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/packages/d2b-provider-observability-otel/src/agent.rs b/packages/d2b-provider-observability-otel/src/agent.rs index 329735b83..2d7296cb6 100644 --- a/packages/d2b-provider-observability-otel/src/agent.rs +++ b/packages/d2b-provider-observability-otel/src/agent.rs @@ -213,6 +213,12 @@ impl core::fmt::Debug for ProviderAgentProcess { impl ProviderAgentProcess { /// Construct a session-bound agent. + /// + /// # Errors + /// + /// Returns [`ProviderAgentError::InvalidInput`] when the zone or + /// source is empty, the capacity is zero, or a zone label or Provider + /// reference is malformed. pub fn new( zone: impl Into, source: impl Into, @@ -243,6 +249,12 @@ impl ProviderAgentProcess { } /// Record a successful or denied session connection. + /// + /// # Errors + /// + /// Returns [`ProviderAgentError::InvalidInput`] when the event or + /// authorization decision is not one of its closed tokens or the + /// outcome is not recognized. pub fn session_connect( &mut self, event: impl Into, @@ -252,8 +264,8 @@ impl ProviderAgentProcess { let event = event.into(); let authz_decision = authz_decision.into(); let outcome = outcome.into(); - let method = parse_closed_token(event.clone(), &["connect", "reconnect", "close"])?; - let authz_decision = parse_closed_token(authz_decision.clone(), &["allowed", "denied"])?; + let method = parse_closed_token(&event, &["connect", "reconnect", "close"])?; + let authz_decision = parse_closed_token(&authz_decision, &["allowed", "denied"])?; let outcome = parse_outcome(outcome)?; self.push( method, @@ -269,6 +281,12 @@ impl ProviderAgentProcess { } /// Record a ProcessEffect generated by the Provider agent. + /// + /// # Errors + /// + /// Returns [`ProviderAgentError::InvalidInput`] when the event, + /// provider, or domain is not one of its closed tokens or the outcome + /// is not recognized. pub fn process_effect( &mut self, event: impl Into, @@ -280,12 +298,12 @@ impl ProviderAgentProcess { let provider = provider.into(); let domain = domain.into(); let outcome = outcome.into(); - let method = parse_closed_token(event.clone(), &["launch", "stop", "adopt", "quarantine"])?; + let method = parse_closed_token(&event, &["launch", "stop", "adopt", "quarantine"])?; let provider = parse_closed_token( - provider.clone(), + &provider, &["minijail", "systemd", "system-core-user"], )?; - let domain = parse_closed_token(domain.clone(), &["system", "user"])?; + let domain = parse_closed_token(&domain, &["system", "user"])?; let outcome = parse_outcome(outcome)?; self.push( method, @@ -339,12 +357,12 @@ impl ProviderAgentProcess { } } -fn parse_token(value: impl Into) -> Result { +fn parse_token(value: &str) -> Result { BoundedToken::parse(value).map_err(|_| ProviderAgentError::InvalidInput) } fn parse_closed_token( - value: impl Into, + value: &str, allowed: &[&str], ) -> Result { let token = parse_token(value)?; diff --git a/packages/d2b-provider-observability-otel/src/config.rs b/packages/d2b-provider-observability-otel/src/config.rs index 55476ecfa..4ad005d0f 100644 --- a/packages/d2b-provider-observability-otel/src/config.rs +++ b/packages/d2b-provider-observability-otel/src/config.rs @@ -144,6 +144,11 @@ impl Default for ProviderConfig { impl ProviderConfig { /// Parse the strict root config shape. + /// + /// # Errors + /// + /// Returns [`ConfigError::Invalid`] when the value is not an object, + /// carries a key outside the closed set, or a field fails validation. pub fn from_json(value: &serde_json::Value) -> Result { let object = value.as_object().ok_or(ConfigError::Invalid)?; let allowed = ["selfMetrics"]; diff --git a/packages/d2b-provider-observability-otel/src/controller.rs b/packages/d2b-provider-observability-otel/src/controller.rs index 77afc85ea..71a918ff3 100644 --- a/packages/d2b-provider-observability-otel/src/controller.rs +++ b/packages/d2b-provider-observability-otel/src/controller.rs @@ -97,6 +97,13 @@ impl TelemetryServiceController { } /// Reconcile one Service without opening or mutating a transport. + /// + /// # Errors + /// + /// Returns [`TelemetryServiceError::InvalidReference`] when the + /// service reference is not a Telemetry Service or the Provider + /// reference is not the canonical one, and the lifecycle refusal when + /// the service is deleted. pub fn reconcile( &mut self, service_ref: &ResourceRef, @@ -212,6 +219,11 @@ pub struct TelemetryComponentSession; impl TelemetryComponentSession { /// Admit one stream and reject all resource-service-shaped references. + /// + /// # Errors + /// + /// Returns [`TelemetryControllerError::Admission`] when the service or + /// binding reference is not the Telemetry shape. pub fn open_stream( &self, request: TelemetryStreamRequest, diff --git a/packages/d2b-provider-observability-otel/src/emitter_socket.rs b/packages/d2b-provider-observability-otel/src/emitter_socket.rs index 466ced85f..ee0242e6e 100644 --- a/packages/d2b-provider-observability-otel/src/emitter_socket.rs +++ b/packages/d2b-provider-observability-otel/src/emitter_socket.rs @@ -75,6 +75,12 @@ impl EmitterSocket { /// /// Sync public surface: one-shot AF_UNIX path setup (mkdir, chmod, inode /// identity capture) has no async form and runs before any event loop hops. + /// + /// # Errors + /// + /// Returns the `io::Error` the socket setup reports when the parent + /// cannot be created, the path is not a valid socket parent, or the + /// bind fails. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn bind(path: impl AsRef, capacity_bytes: usize) -> io::Result { let path = path.as_ref().to_path_buf(); @@ -128,6 +134,11 @@ impl EmitterSocket { } /// Drain available datagrams into the bounded FIFO. + /// + /// # Errors + /// + /// Returns the `io::Error` the socket reports when the bound identity + /// check fails or a receive fails. pub fn drain_once(&mut self) -> io::Result { self.prune_expired(); self.validate_bound_identity()?; diff --git a/packages/d2b-provider-observability-otel/src/lib.rs b/packages/d2b-provider-observability-otel/src/lib.rs index e02a89deb..cb40cbb3f 100644 --- a/packages/d2b-provider-observability-otel/src/lib.rs +++ b/packages/d2b-provider-observability-otel/src/lib.rs @@ -10,8 +10,11 @@ pub mod ingress_policy; pub mod metric_policy; pub mod metrics; +/// The stable Provider name this crate implements. pub const PROVIDER_NAME: &str = "observability-otel"; +/// The canonical Provider reference this crate's rows select. pub const PROVIDER_REF: &str = "Provider/observability-otel"; +/// The Provider API major version this crate implements. pub const PROVIDER_API_MAJOR: u16 = 1; /// The role id the otel host bridge process carries in launcher rows. pub const OTEL_HOST_BRIDGE_ROLE: &str = "otel-host-bridge"; diff --git a/packages/d2b-provider-observability-otel/src/metric_policy.rs b/packages/d2b-provider-observability-otel/src/metric_policy.rs index 7905794c4..407899489 100644 --- a/packages/d2b-provider-observability-otel/src/metric_policy.rs +++ b/packages/d2b-provider-observability-otel/src/metric_policy.rs @@ -18,6 +18,13 @@ pub use d2b_contracts_provider::v3::telemetry_policy::{ pub const MAX_RESOURCE_ATTRIBUTE_BYTES: usize = 256; /// Validate one set of attributes before it can enter a telemetry frame. +/// +/// # Errors +/// +/// Returns [`ResourceAttributeError::NotAllowlisted`] when a key is +/// outside the closed attribute set and [`ResourceAttributeError::Invalid`] +/// when a value is empty, over the byte bound, carries a forbidden byte, +/// duplicates a key, or fails the value policy. pub fn validate_resource_attributes( attributes: &BTreeMap, ) -> Result<(), ResourceAttributeError> { From 16e0b183d3baed555af99d928d04fc7c3551209c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:38:03 -0700 Subject: [PATCH 152/726] xtask: move census baseline entries into the written baseline map Build CensusBaseline by consuming each CrateCensus instead of cloning crate_dir and counts, and drive the --baseline check from the written map via a shared check_against_baseline helper. --- packages/xtask/src/blocking_census.rs | 124 ++++++++++++++------------ 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/packages/xtask/src/blocking_census.rs b/packages/xtask/src/blocking_census.rs index 86bfb7dd2..820178e5d 100644 --- a/packages/xtask/src/blocking_census.rs +++ b/packages/xtask/src/blocking_census.rs @@ -1107,7 +1107,7 @@ fn collect_crate_files( } /// Whether a clippy hit at `file:line` is test context, by the same split -/// the lexical meter uses. +/// the lexical meter uses。 fn hit_is_test(files: &[CensusFile], file: &str, line: usize) -> bool { files .iter() @@ -1121,9 +1121,59 @@ fn hit_is_test(files: &[CensusFile], file: &str, line: usize) -> bool { }) } -/// Run the census over the repository or the given crate paths. Prints the -/// per-crate tables and the totals; with `json_out` writes the authoritative -/// per-crate counts (the baseline shape); with `baseline` fails when any +/// Fails when any current per-crate count exceeds its committed baseline。 +fn check_against_baseline<'a>( + baseline_path: &Path, + crates: impl Iterator)>, +) -> Result<(), String> { + let committed = fs::read_to_string(baseline_path) + .map_err(|error| format!("blocking-census: read baseline {}: {error}", baseline_path.display()))?; + let committed: CensusBaseline = serde_json::from_str(&committed) + .map_err(|error| format!("blocking-census: parse baseline {}: {error}", baseline_path.display()))?; + let mut violations = Vec::new(); + for (crate_dir, counts) in crates { + let committed_counts = committed.crates.get(crate_dir); + let mut crate_violations = Vec::new(); + for (entry, count) in counts { + let committed_count = committed_counts + .and_then(|counts| counts.get(entry)) + .copied() + .unwrap_or(0); + if *count > committed_count { + crate_violations.push(format!( + "{entry}: {count} > {committed_count} (committed baseline)" + )); + } + } + if crate_violations.is_empty() { + println!( + " {}: {} entry class(es) at or below baseline", + crate_dir, + counts.len() + ); + } else { + println!(" {}: ABOVE BASELINE", crate_dir); + for violation in &crate_violations { + println!(" {violation}"); + } + violations.extend(crate_violations); + } + } + if violations.is_empty() { + println!("blocking-census check: PASS (no crate above its committed baseline)"); + } else { + return Err(format!( + "blocking-census check: FAILED - {} deny-entry class(es) above the committed baseline {}", + violations.len(), + baseline_path.display() + )); + } + Ok(()) +} + +/// Run the census over the repository or the given crate paths。Prints the +/// per-crate tables and the totals;with `json_out` writes the authoritative +/// per-crate counts (the baseline shape);with `baseline` fails when any /// covered crate's count exceeds its committed baseline (plan R15). #[allow(clippy::disallowed_methods, reason = "CLI-only path")] pub fn run( @@ -1263,66 +1313,30 @@ pub fn run( println!("clippy-visible blocking-API call sites: {clippy_total}"); println!("authoritative blocking-API call sites: {authoritative_total}"); println!("deny-list entries: {}", entries.len()); - if let Some(path) = json_out { - let baseline = CensusBaseline { - crates: crates - .iter() - .map(|crate_census| (crate_census.crate_dir.clone(), crate_census.counts.clone())) + let baseline_record = CensusBaseline { + crates: std::mem::take(&mut crates) + .into_iter() + .map(|crate_census| (crate_census.crate_dir, crate_census.counts)) .collect(), }; - let rendered = serde_json::to_string_pretty(&baseline) + let rendered = serde_json::to_string_pretty(&baseline_record) .map_err(|error| format!("blocking-census: serialize baseline: {error}"))?; fs::write(path, rendered + "\n") .map_err(|error| format!("blocking-census: write {}: {error}", path.display()))?; println!("baseline written: {}", path.display()); - } - - if let Some(path) = baseline { - let committed = fs::read_to_string(path) - .map_err(|error| format!("blocking-census: read baseline {}: {error}", path.display()))?; - let committed: CensusBaseline = serde_json::from_str(&committed) - .map_err(|error| format!("blocking-census: parse baseline {}: {error}", path.display()))?; - let mut violations = Vec::new(); - for crate_census in &crates { - let committed_counts = committed.crates.get(&crate_census.crate_dir); - let mut crate_violations = Vec::new(); - for (entry, count) in &crate_census.counts { - let committed_count = committed_counts - .and_then(|counts| counts.get(entry)) - .copied() - .unwrap_or(0); - if *count > committed_count { - crate_violations.push(format!( - "{entry}: {count} > {committed_count} (committed baseline)" - )); - } - } - if crate_violations.is_empty() { - println!( - " {}: {} entry class(es) at or below baseline", - crate_census.crate_dir, - crate_census.counts.len() - ); - } else { - println!(" {}: ABOVE BASELINE", crate_census.crate_dir); - for violation in &crate_violations { - println!(" {violation}"); - } - violations.extend(crate_violations); - } - } - if violations.is_empty() { - println!("blocking-census check: PASS (no crate above its committed baseline)"); - } else { - return Err(format!( - "blocking-census check: FAILED - {} deny-entry class(es) above the committed baseline {}", - violations.len(), - path.display() - )); + if let Some(baseline_path) = baseline { + check_against_baseline( + baseline_path, + baseline_record.crates.iter().map(|(crate_dir, counts)| (crate_dir.as_str(), counts)), + )?; } + } else if let Some(baseline_path) = baseline { + check_against_baseline( + baseline_path, + crates.iter().map(|crate_census| (crate_census.crate_dir.as_str(), &crate_census.counts)), + )?; } - Ok(()) } From ada188a9ccaff698749461f7e06a528704a5cd3f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:38:37 -0700 Subject: [PATCH 153/726] process: borrow provider refs, own launch argv, document errors --- packages/d2b-provider-process/src/backend.rs | 6 ++++++ packages/d2b-provider-process/src/driver.rs | 6 +++--- packages/d2b-provider-process/src/launch_identity.rs | 5 +++++ packages/d2b-provider-process/src/operations.rs | 8 ++++---- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/d2b-provider-process/src/backend.rs b/packages/d2b-provider-process/src/backend.rs index ac613f057..b3add3d6b 100644 --- a/packages/d2b-provider-process/src/backend.rs +++ b/packages/d2b-provider-process/src/backend.rs @@ -253,6 +253,12 @@ pub trait ProcessEffectBackend: Send + Sync + 'static { type Handle: Send + Sync + 'static; /// Resolve and launch one ticket, returning mandatory local authority. + /// + /// # Errors + /// + /// Returns the [`ProcessEffectError`] the backend reports for the + /// failing launch step: ticket validation, identity resolution, + /// effect-port refusal, or launch failure. fn launch( &self, request: ProcessRequest, diff --git a/packages/d2b-provider-process/src/driver.rs b/packages/d2b-provider-process/src/driver.rs index d7313ae70..004d33262 100644 --- a/packages/d2b-provider-process/src/driver.rs +++ b/packages/d2b-provider-process/src/driver.rs @@ -1985,7 +1985,7 @@ impl ResourceDriver for ProcessDriver { let identity = self .identity( ctx, - &envelope.provider_ref.clone().expect("checked"), + envelope.provider_ref.as_ref().expect("checked"), DriverOp::Recover, ) .await?; @@ -2053,7 +2053,7 @@ impl ResourceDriver for ProcessDriver { let identity = self .identity( ctx, - &envelope.provider_ref.clone().expect("checked"), + envelope.provider_ref.as_ref().expect("checked"), DriverOp::Reconcile, ) .await?; @@ -2102,7 +2102,7 @@ impl ResourceDriver for ProcessDriver { let identity = match self .identity( ctx, - &envelope.provider_ref.clone().expect("checked"), + envelope.provider_ref.as_ref().expect("checked"), DriverOp::Delete, ) .await diff --git a/packages/d2b-provider-process/src/launch_identity.rs b/packages/d2b-provider-process/src/launch_identity.rs index af73e5459..88b43e6ce 100644 --- a/packages/d2b-provider-process/src/launch_identity.rs +++ b/packages/d2b-provider-process/src/launch_identity.rs @@ -61,6 +61,11 @@ pub struct LaunchRow<'a> { /// /// A row whose launch cannot be named completely fails here, once, naming the /// missing input ([`LaunchIdentityError`]). +/// +/// # Errors +/// +/// Returns the [`LaunchIdentityError`] naming the missing or invalid +/// input when the row's launch identity cannot be resolved completely. pub fn resolve_launch_identity(row: &LaunchRow<'_>) -> Result { let owner = row.owner_ref; let declared_target = match row.declared_target { diff --git a/packages/d2b-provider-process/src/operations.rs b/packages/d2b-provider-process/src/operations.rs index bd7efd22e..a8cce4c5c 100644 --- a/packages/d2b-provider-process/src/operations.rs +++ b/packages/d2b-provider-process/src/operations.rs @@ -1348,10 +1348,10 @@ fn validate_spawn_runner_request_matches_intent( fn bind_cloud_hypervisor_guest_uid( role: RunnerRole, owner_uid: Option<&ResourceUid>, - argv: &[String], + argv: Vec, ) -> Result, OperationFailure> { if role != RunnerRole::CloudHypervisor { - return Ok(argv.to_vec()); + return Ok(argv); } let owner_uid = owner_uid.ok_or_else(|| { OperationFailure::with_detail( @@ -1359,7 +1359,7 @@ fn bind_cloud_hypervisor_guest_uid( "owner_uid: required-for-cloud-hypervisor".to_owned(), ) })?; - let mut bound = argv.to_vec(); + let mut bound = argv; let cmdline_index = bound .iter() .position(|argument| argument == "--cmdline") @@ -2649,7 +2649,7 @@ impl OperationHandler for SpawnRunnerHandler { let argv = bind_cloud_hypervisor_guest_uid( request.role, request.owner_uid.as_ref(), - &launch_argv, + launch_argv, )?; // The launch identity is the trusted intent's principal for every // posture (the retired arm's `prepare_runner_launch_identity`). From 932616e195ba61329b565347510faeced071fbe5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:39:07 -0700 Subject: [PATCH 154/726] refactor(d2b-zone-routing): express suffix matching as find_map --- packages/d2b-zone-routing/src/resolver.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/d2b-zone-routing/src/resolver.rs b/packages/d2b-zone-routing/src/resolver.rs index eda842df8..57ca5d984 100644 --- a/packages/d2b-zone-routing/src/resolver.rs +++ b/packages/d2b-zone-routing/src/resolver.rs @@ -77,6 +77,16 @@ impl SealedZoneTopology { /// /// Each edge's parent/direct-child relationship was already proven by /// [`ZoneTreeEdge::new`], so it is not re-checked here. + /// + /// # Errors + /// + /// Returns [`PrimitiveSpecError::ConflictingFields`] when an edge names + /// the local root as a child, [`PrimitiveSpecError::DuplicateEntry`] when + /// two rows give one child different parents, + /// [`PrimitiveSpecError::MissingRequiredField`] when an edge's parent is + /// neither the local root nor a declared child, and + /// [`PrimitiveSpecError::TooManyEntries`] above the frozen parent-entry + /// ceiling. pub fn seal( local_root: ZonePath, edges: Vec, @@ -141,18 +151,15 @@ impl SealedZoneTopology { /// the unknown-topology case. fn longest_suffix_match(&self, target: &ZonePath) -> Option<&ZonePath> { let labels = target.labels(); - for start in 0..labels.len() { + (0..labels.len()).find_map(|start| { // A non-empty sub-slice of a valid Zone path is itself a valid // Zone path, so a suffix can only fail to build if the slice is - // empty, which the loop bound excludes. + // empty, which the range bound excludes. let Ok(suffix) = ZonePath::new(labels[start..].to_vec()) else { - continue; + return None; }; - if let Some(zone) = self.zones.get(&suffix) { - return Some(zone); - } - } - None + self.zones.get(&suffix) + }) } } From c8defa1f4b071970c58827e7a34aae8f7344b6e1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:39:08 -0700 Subject: [PATCH 155/726] refactor(d2b-zone-routing): derive Default for topology requests --- packages/d2b-zone-routing/src/service.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/d2b-zone-routing/src/service.rs b/packages/d2b-zone-routing/src/service.rs index 90e74b130..b703d397b 100644 --- a/packages/d2b-zone-routing/src/service.rs +++ b/packages/d2b-zone-routing/src/service.rs @@ -205,6 +205,12 @@ impl ZoneServiceLimits { /// over-ceiling bound would let configuration grow memory without limit; /// both fail closed with [`PrimitiveSpecError::TooManyEntries`] and /// [`PrimitiveSpecError::MissingRequiredField`] respectively. + /// + /// # Errors + /// + /// Returns [`PrimitiveSpecError::MissingRequiredField`] for a zero bound + /// and [`PrimitiveSpecError::TooManyEntries`] for a bound above its + /// ceiling. pub const fn new( max_shortcuts: usize, audit_capacity: usize, @@ -272,6 +278,7 @@ impl ZoneDispatchAdmission { /// Each sealed child row is keyed to its own admission. Missing evidence /// leaves that row unreachable; there is no shared caller-populated policy, /// connectivity, authentication, capability, or time flag. +#[derive(Default)] pub struct ZoneTopologyRequest { admissions: std::collections::BTreeMap, } @@ -308,12 +315,6 @@ impl ZoneTopologyRequest { } } -impl Default for ZoneTopologyRequest { - fn default() -> Self { - Self::new() - } -} - redacted_debug!(ZoneTopologyRequest); /// The joined route status of one sealed topology row. @@ -423,6 +424,11 @@ impl ZoneBootstrapRequest { } /// Consume and verify one runtime-issued admission for this request. + /// + /// # Errors + /// + /// Returns [`ZoneEnrollmentRefusal`] when the admission evidence fails + /// verification against the expectation. pub fn with_runtime_admission( self, verifier: ZoneEnrollmentAdmissionVerifier, @@ -465,6 +471,11 @@ impl ZoneEnrollRequest { } /// Consume and verify one runtime-issued admission for this request. + /// + /// # Errors + /// + /// Returns [`ZoneEnrollmentRefusal`] when the admission evidence fails + /// verification against the expectation. pub fn with_runtime_admission( self, verifier: ZoneEnrollmentAdmissionVerifier, From 6a3cf6cff33bc476ba492fb69cf569a45a03287a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:39:08 -0700 Subject: [PATCH 156/726] refactor(d2b-zone-routing): move the admitted zone pair without cloning --- packages/d2b-zone-routing/src/engine.rs | 43 +++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/packages/d2b-zone-routing/src/engine.rs b/packages/d2b-zone-routing/src/engine.rs index 91f875acf..1a48ecb81 100644 --- a/packages/d2b-zone-routing/src/engine.rs +++ b/packages/d2b-zone-routing/src/engine.rs @@ -342,9 +342,45 @@ impl ZoneRouteAdmission { if now_ms < snapshot.issued_at_unix_ms || now_ms >= snapshot.expires_at_unix_ms { return Err(ZoneRouteFailClosedReason::Expired); } - snapshot.source_zone = expected.source_zone.clone(); - snapshot.target_zone = expected.target_zone.clone(); - validate_snapshot(&snapshot, &expected)?; + let ZoneRouteAdmissionExpectation { + source_zone, + target_zone, + zone_link_uid, + edge, + controller_generation, + reconnect_generation, + source_zone_uid, + target_zone_uid, + operation_id, + verb, + required_capability, + policy_revision, + } = expected; + snapshot.source_zone = source_zone; + snapshot.target_zone = target_zone; + if snapshot.source_zone.is_none() + || snapshot.target_zone.is_none() + || snapshot.zone_link_uid != zone_link_uid + || snapshot.edge != edge + || snapshot.source_zone_uid != source_zone_uid + || snapshot.target_zone_uid != target_zone_uid + || snapshot.operation_id != operation_id + || snapshot.verb != verb + || snapshot.policy_revision != policy_revision + { + return Err(ZoneRouteFailClosedReason::PolicyDenial); + } + if snapshot.controller_generation != controller_generation + || snapshot.reconnect_generation != reconnect_generation + { + return Err(ZoneRouteFailClosedReason::ZoneLinkDisconnected); + } + if snapshot.required_capability != required_capability { + return Err(ZoneRouteFailClosedReason::MissingCapability); + } + if snapshot.expires_at_unix_ms <= snapshot.issued_at_unix_ms { + return Err(ZoneRouteFailClosedReason::Expired); + } Ok(snapshot) } #[cfg(any(test, feature = "test-support"))] @@ -481,6 +517,7 @@ fn daemon_now_unix_seconds() -> Result { .map_err(|_| ZoneRouteFailClosedReason::PolicyDenial) } +#[cfg(test)] fn validate_snapshot( snapshot: &RouteAdmissionSnapshot, expected: &ZoneRouteAdmissionExpectation, From 20855634dcef1c5df4a9ac6275f508ac7821748b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:39:08 -0700 Subject: [PATCH 157/726] docs(d2b-zone-routing): document error conditions on public APIs --- packages/d2b-zone-routing/src/enrollment.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/d2b-zone-routing/src/enrollment.rs b/packages/d2b-zone-routing/src/enrollment.rs index 104d96125..710e4acb0 100644 --- a/packages/d2b-zone-routing/src/enrollment.rs +++ b/packages/d2b-zone-routing/src/enrollment.rs @@ -84,6 +84,13 @@ impl ZoneEnrollmentExpectation { /// be constructed at all. The pinned peer fingerprint and the opaque /// allocator binding are the allocator's own sealed facts: they seal the /// enrollment record and never cross the wire. + /// + /// # Errors + /// + /// Returns [`ZoneEnrollmentRefusal::SessionProfileRefused`] when the + /// session policy is not the enrolled Guest-local carriage profile and + /// [`ZoneEnrollmentRefusal::MalformedRequest`] when the fingerprint or + /// allocator binding is all zeros. #[allow(clippy::too_many_arguments)] pub fn new( zone: ZoneId, @@ -421,6 +428,11 @@ redacted_debug!(ZoneEnrollmentAuthority); impl ZoneEnrollmentAuthority { /// Bind an enrollment authority to one clock and the default lifetime. + /// + /// # Errors + /// + /// Returns [`ZoneEnrollmentRefusal::PolicyDenial`] when the default + /// lifetime is zero or above the ceiling. pub fn new(clock: Arc u64 + Send + Sync>) -> Result { Self::with_lifetime(clock, ENROLLMENT_ADMISSION_LIFETIME_MS_DEFAULT) } @@ -429,6 +441,11 @@ impl ZoneEnrollmentAuthority { /// /// A zero or over-ceiling lifetime is refused rather than clamped: an /// admission that never expires is as wrong as one that expires instantly. + /// + /// # Errors + /// + /// Returns [`ZoneEnrollmentRefusal::PolicyDenial`] when the lifetime is + /// zero or above the frozen ceiling. pub fn with_lifetime( clock: Arc u64 + Send + Sync>, lifetime_ms: u64, From a18cc6eb19aae69d482468dad058d2bb0278b772 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:40:06 -0700 Subject: [PATCH 158/726] xtask: document delivery and census record contracts Add per-field docs to the census and wire records, Errors sections to the Result-returning validators and parsers, and one-line docs to the undocumented delivery accessors. --- packages/xtask/src/blocking_census.rs | 5 +++++ packages/xtask/src/changelog.rs | 11 ++++++++--- packages/xtask/src/delivery/command.rs | 13 +++++++++++++ packages/xtask/src/delivery/evidence.rs | 26 +++++++++++++++++++++++++ packages/xtask/src/delivery/seal.rs | 22 +++++++++++++++++++++ packages/xtask/src/delivery/snapshot.rs | 3 +++ 6 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/xtask/src/blocking_census.rs b/packages/xtask/src/blocking_census.rs index 820178e5d..aedb44b0b 100644 --- a/packages/xtask/src/blocking_census.rs +++ b/packages/xtask/src/blocking_census.rs @@ -69,8 +69,11 @@ pub enum EntryKind { /// clippy matches on (everything after the final `::`), and the counting /// class. pub struct DeniedApi { + /// Fully-qualified API path as configured, e.g. `std::sync::Mutex::lock`. pub path: String, + /// The bare tail clippy matches on: everything after the final `::`. pub tail: String, + /// How the entry is counted: textually or from clippy diagnostics. pub kind: EntryKind, } @@ -657,6 +660,8 @@ pub struct CrateCensus { /// spawn_blocking row, which the gate refuses to see grow. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct CensusBaseline { + /// Crate-directory to deny-entry counts, as serialized into the + /// committed baseline file. pub crates: BTreeMap>, } diff --git a/packages/xtask/src/changelog.rs b/packages/xtask/src/changelog.rs index 9b65833df..10bea4a21 100644 --- a/packages/xtask/src/changelog.rs +++ b/packages/xtask/src/changelog.rs @@ -143,9 +143,14 @@ pub struct Fragment { /// Parse one fragment, rejecting anything that could silently lose an entry. /// /// Accepted shape: one or more `###

` headings from [`SECTIONS`], -/// each followed by a bullet list. Rejected: an empty fragment, an unknown or -/// wrong-level heading, a repeated heading, a section with no entries, and any -/// content before the first heading. +/// each followed by a bullet list. +/// +/// # Errors +/// +/// Returns [`FoldError`] when the fragment has no `###
` heading, a +/// heading is unknown or at the wrong level, a heading repeats, a section has +/// no entries or does not start with a `- ` bullet, or content appears before +/// the first heading. pub fn parse_fragment(name: &str, text: &str) -> Result { let mut errors: Vec = Vec::new(); let mut raw: Vec<(usize, String, Vec)> = Vec::new(); diff --git a/packages/xtask/src/delivery/command.rs b/packages/xtask/src/delivery/command.rs index 8e3903ab8..e95ab8fcb 100644 --- a/packages/xtask/src/delivery/command.rs +++ b/packages/xtask/src/delivery/command.rs @@ -101,6 +101,7 @@ pub const WAVE_COMMANDS: [WaveCommand; 7] = [ ]; impl WaveCommand { + /// The canonical wire name of this stage, as used on the command line. pub fn as_str(self) -> &'static str { match self { Self::Help => "help", @@ -113,6 +114,7 @@ impl WaveCommand { } } + /// Resolves a wire name to its stage, or `None` when unknown. pub fn parse(name: &str) -> Option { WAVE_COMMANDS .into_iter() @@ -202,6 +204,7 @@ impl WaveCommand { } } + /// The options this stage requires, in usage order. pub fn required_options(self) -> &'static [&'static str] { match self { Self::Help => &[], @@ -231,6 +234,7 @@ impl WaveCommand { } } + /// The options this stage accepts beyond the required set. pub fn optional_options(self) -> &'static [&'static str] { match self { Self::Help => &[], @@ -422,6 +426,7 @@ impl StateHelp { } impl WorkflowOutput { + /// A successful output for the given operation, with no artifacts yet. pub fn ok(operation: WaveCommand) -> Self { Self { schema_version: DELIVERY_SCHEMA_VERSION, @@ -436,6 +441,7 @@ impl WorkflowOutput { } } + /// Records the candidate's three digests on this output. #[must_use] pub fn with_digests(mut self, digests: &CandidateDigests) -> Self { self.candidate_id = Some(digests.candidate_id.as_str().to_owned()); @@ -461,6 +467,7 @@ impl WorkflowOutput { } } +/// One stage's help record, as published by the `help` command. #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct WorkflowCommandHelp { pub name: String, @@ -553,6 +560,7 @@ pub struct CliOptions { } impl CliOptions { + /// Parses `--name value` pairs, collecting repeats. pub fn parse(args: &[String]) -> Result { let mut values = BTreeMap::>::new(); let mut chunks = args.chunks_exact(2); @@ -577,6 +585,7 @@ impl CliOptions { Ok(Self { values }) } + /// Consumes an option that must appear exactly once. pub fn required_string(&mut self, name: &str) -> Result { let values = self .values @@ -590,10 +599,12 @@ impl CliOptions { Ok(values.into_iter().next().expect("exactly one value")) } + /// Consumes an option that must appear exactly once, as a path. pub fn required_path(&mut self, name: &str) -> Result { self.required_string(name).map(PathBuf::from) } + /// Consumes an option that may appear at most once. pub fn optional_string(&mut self, name: &str) -> Result> { match self.values.remove(name) { None => Ok(None), @@ -604,6 +615,7 @@ impl CliOptions { } } + /// Consumes an option that may appear at most once, as a path. pub fn optional_path(&mut self, name: &str) -> Result> { Ok(self.optional_string(name)?.map(PathBuf::from)) } @@ -634,6 +646,7 @@ impl CliOptions { Ok(roots) } + /// Rejects any option the stage did not consume. pub fn finish(&self) -> Result<()> { if self.values.is_empty() { return Ok(()); diff --git a/packages/xtask/src/delivery/evidence.rs b/packages/xtask/src/delivery/evidence.rs index 42ed49041..5c43200f3 100644 --- a/packages/xtask/src/delivery/evidence.rs +++ b/packages/xtask/src/delivery/evidence.rs @@ -94,6 +94,12 @@ impl EvidenceLane { } } + /// Parses a lane name from its wire string. + /// + /// # Errors + /// + /// Returns a usage error when `value` is neither `github-ci` nor + /// `local-host`. pub fn parse(value: &str) -> Result { EVIDENCE_LANES .into_iter() @@ -120,7 +126,9 @@ fn parse_result(value: &str) -> Result { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct OutputDigest { + /// Lowercase hex SHA-256 of the validator log bytes. pub sha256: String, + /// Log size in bytes. pub bytes: u64, } @@ -128,17 +136,27 @@ pub struct OutputDigest { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct EvidenceRecord { + /// The artifact kind this record belongs to (`EVIDENCE_ARTIFACT_KIND`). pub artifact_kind: String, + /// Delivery schema version this record was written as. pub schema_version: u32, + /// Program name the evidence was produced under. pub program: String, + /// Wave the evidence belongs to. pub wave: String, + /// Candidate this evidence is bound to. pub candidate_id: CandidateId, + /// Content identity of the candidate material. pub content_id: ContentId, + /// SHA-256 of the candidate snapshot the evidence vouches for. pub snapshot_sha256: SnapshotSha256, + /// Lane the validation ran in (`github-ci` or `local-host`). pub lane: EvidenceLane, /// Lane-unique validation identifier, for example `test-integration`. pub validation: String, + /// Validation outcome. pub result: EvidenceResult, + /// Import time as UNIX seconds. pub imported_at_unix: u64, /// Command line that was run. Never its output. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -159,6 +177,14 @@ impl EvidenceRecord { .join(format!("{}.json", self.validation)) } + /// Validates this record's shape before it is committed. + /// + /// # Errors + /// + /// Returns an error when the artifact kind is not + /// [`EVIDENCE_ARTIFACT_KIND`], the schema version is unsupported, the + /// `program`/`wave` pair is invalid, the `validation` identifier is + /// malformed, or a supplied `command`/`locator` is not a single line. pub fn validate(&self) -> Result<()> { if self.artifact_kind != EVIDENCE_ARTIFACT_KIND { return Err(DeliveryError::new(format!( diff --git a/packages/xtask/src/delivery/seal.rs b/packages/xtask/src/delivery/seal.rs index 2bb706f0b..0908ff217 100644 --- a/packages/xtask/src/delivery/seal.rs +++ b/packages/xtask/src/delivery/seal.rs @@ -35,7 +35,9 @@ use super::{ #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct SealedLane { + /// The lane whose validations were accepted. pub lane: EvidenceLane, + /// The validations accepted for the lane, each bound to its record digest. pub validations: Vec, } @@ -48,7 +50,9 @@ pub struct SealedLane { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct SealedValidation { + /// Validation identifier accepted into the seal. pub validation: String, + /// SHA-256 of the exact evidence record the seal accepted. pub record_sha256: String, } @@ -61,19 +65,37 @@ pub struct SealedValidation { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct SealRecord { + /// The artifact kind this seal belongs to (`SEAL_ARTIFACT_KIND`). pub artifact_kind: String, + /// Delivery schema version this seal was written as. pub schema_version: u32, + /// Program name the seal was produced under. pub program: String, + /// Wave the seal belongs to. pub wave: String, + /// Candidate the seal binds. pub candidate_id: CandidateId, + /// Content identity of the sealed material. pub content_id: ContentId, + /// SHA-256 of the candidate snapshot the seal commits to. pub snapshot_sha256: SnapshotSha256, + /// The sealed material itself (see the struct contract above). pub material: CandidateMaterial, + /// Per-lane accepted validations bound into the seal. pub evidence: Vec, } impl SealRecord { /// Re-validates a seal read back from delivery state. + /// + /// # Errors + /// + /// Returns an error when the artifact kind is not [`SEAL_ARTIFACT_KIND`], + /// the schema version is unsupported, the `program`/`wave` pair is + /// invalid or disagrees with the sealed material, the recorded digests + /// do not re-derive from the material, the candidate address does not + /// match, a sealed validation identifier or record digest is malformed, + /// or the required evidence lanes are missing. pub fn validate(&self, candidate: &CandidateDir) -> Result<()> { ensure_artifact_kind(&self.artifact_kind, SEAL_ARTIFACT_KIND, "wave seal")?; if self.schema_version != DELIVERY_SCHEMA_VERSION { diff --git a/packages/xtask/src/delivery/snapshot.rs b/packages/xtask/src/delivery/snapshot.rs index 81e82d34e..10b8964ce 100644 --- a/packages/xtask/src/delivery/snapshot.rs +++ b/packages/xtask/src/delivery/snapshot.rs @@ -84,6 +84,7 @@ impl WaveSnapshot { }) } + /// The three identifiers bound to this snapshot, as a single value. pub fn digests(&self) -> CandidateDigests { CandidateDigests { content_id: self.content_id.clone(), @@ -92,10 +93,12 @@ impl WaveSnapshot { } } + /// The program this snapshot's wave belongs to. pub fn program(&self) -> &str { &self.material.program } + /// The wave this snapshot was sealed for. pub fn wave(&self) -> &str { &self.material.wave } From 46b177892a41fd3a3cae7d84448c69f5a904ed5f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:39:16 -0700 Subject: [PATCH 159/726] provider-provider: borrow zone and status, document observation fields --- packages/d2b-provider-provider/src/driver.rs | 24 +++++++++---------- .../d2b-provider-provider/src/providers.rs | 8 +++++++ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/d2b-provider-provider/src/driver.rs b/packages/d2b-provider-provider/src/driver.rs index 261e10e24..f861b953f 100644 --- a/packages/d2b-provider-provider/src/driver.rs +++ b/packages/d2b-provider-provider/src/driver.rs @@ -352,30 +352,30 @@ impl ProviderDriver { resource_uid(ctx.uid()).ok_or_else(|| spec_invalid(DriverOp::Reconcile, "spec/uid"))?; let generation = ResourceGeneration::new(ctx.generation()) .map_err(|_| spec_invalid(DriverOp::Reconcile, "spec/generation"))?; - let zone = ZoneId::parse(ctx.key().zone.clone()) + let zone = ZoneId::parse(ctx.key().zone.as_str()) .map_err(|_| spec_invalid(DriverOp::Reconcile, "spec/zone"))?; + let dependencies = self + .dependencies(ctx, &provider_ref, &provider_uid, generation) + .await?; + // The old `status.observedGeneration` short-circuit selected the // `Enable` intent; the in-memory status is its runtime-only successor. - let previous = ctx.status::().cloned(); - let intent = match previous.as_ref() { + let previous = ctx.status::(); + let intent = match previous { Some(status) if status.observed_generation == ctx.generation() => { ProviderIntent::Enable } _ => ProviderIntent::Update, }; - let dependencies = self - .dependencies(ctx, &provider_ref, &provider_uid, generation) - .await?; - // The provider row as the pure observation reads it: spec from the // stored envelope, metadata as authored, and the previous // observation's owned Volume references standing in for the durable // `status.resource.owned.refs` projection the store used to derive. let metadata: Value = serde_json::from_slice(ctx.metadata()) .map_err(|_| spec_invalid(DriverOp::Reconcile, "spec/metadata"))?; - let status = match previous.as_ref() { + let status = match previous { Some(previous) => json!({ "observedGeneration": previous.observed_generation, "resource": { @@ -475,12 +475,12 @@ impl ProviderDriver { if provider_ref_text == SYSTEM_CORE_PROVIDER_REF || provider_ref_text == SYSTEM_MINIJAIL_PROVIDER_REF { - let zone = ctx.key().zone.clone(); + let zone = ctx.key().zone.as_str(); let (host_type, host_name) = SYSTEM_CORE_HOST_REF .split_once('/') .expect("the canonical Host reference is a contract reference"); - keys.push(ResourceKey::new(zone.as_str(), host_type, host_name)); - keys.push(ResourceKey::new(zone.as_str(), "Zone", zone.as_str())); + keys.push(ResourceKey::new(zone, host_type, host_name)); + keys.push(ResourceKey::new(zone, "Zone", zone)); } let mut dependencies = Vec::new(); for key in keys { @@ -519,7 +519,7 @@ impl ProviderDriver { ) -> Option { let resource_ref = ResourceRef::parse(&format!("{}/{}", view.key.type_name, view.key.name)).ok()?; - let zone = ZoneId::parse(view.key.zone.clone()).ok()?; + let zone = ZoneId::parse(view.key.zone.as_str()).ok()?; let uid = resource_uid(&view.uid)?; let generation = ResourceGeneration::new(view.generation).ok()?; let mut metadata: Value = serde_json::from_slice(&view.metadata).ok()?; diff --git a/packages/d2b-provider-provider/src/providers.rs b/packages/d2b-provider-provider/src/providers.rs index ecec9f8aa..fa5e8b501 100644 --- a/packages/d2b-provider-provider/src/providers.rs +++ b/packages/d2b-provider-provider/src/providers.rs @@ -69,13 +69,21 @@ impl ProviderPlan { /// Trusted observations needed to plan one Provider pass. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ProviderObservation { + /// The Provider package is committed for this row. pub package_present: bool, + /// The declared config passes the Provider's own validation. pub config_valid: bool, + /// The declared dependency graph is well-formed. pub graph_valid: bool, + /// The row satisfies the process-conformance contract. pub conformance_valid: bool, + /// Every required dependency is ready. pub required_dependencies_ready: bool, + /// Every required component is ready. pub required_components_ready: bool, + /// An optional component is degraded. pub optional_components_degraded: bool, + /// The row's components have drained. pub components_drained: bool, } From 855642a90b06e622ee8de999f79cf1a4ccad7635 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:40:25 -0700 Subject: [PATCH 160/726] resource-api: borrow the scoped commit mutations and consume the admitted batch --- packages/d2b-resource-api/src/adapter.rs | 25 +++++++++++++++++-- packages/d2b-resource-api/src/admission.rs | 3 +-- packages/d2b-resource-api/src/client.rs | 2 +- .../src/manager_backend/tests.rs | 4 +-- packages/d2b-resource-api/src/service.rs | 21 ++++++++++++++-- 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/packages/d2b-resource-api/src/adapter.rs b/packages/d2b-resource-api/src/adapter.rs index 4890ea022..3c720cef9 100644 --- a/packages/d2b-resource-api/src/adapter.rs +++ b/packages/d2b-resource-api/src/adapter.rs @@ -68,6 +68,14 @@ impl std::error::Error for ScopedQueryFrameError {} /// Attach bus-admitted assignment evidence to the existing ttrpc CommitBatch /// request without creating another transport. +/// +/// # Errors +/// +/// Returns [`ScopedCommitFrameError::InvalidFrame`] when the frame is not a +/// well-formed ttrpc request, [`ScopedCommitFrameError::InvalidRequest`] when +/// the frame is not a `CommitBatch` call or already carries scoped admission, +/// and [`ScopedCommitFrameError::Assignment`] when the assignment evidence +/// cannot be encoded. pub fn attach_scoped_commit_frame( frame: &[u8], transport: &ScopedCommitTransport, @@ -116,6 +124,13 @@ pub fn attach_scoped_commit_frame( /// /// The selector inputs are transport-neutral so the resource API does not /// depend on the message bus's query type. +/// +/// # Errors +/// +/// Returns [`ScopedQueryFrameError::InvalidFrame`] when the frame is not a +/// well-formed ttrpc request, and [`ScopedQueryFrameError::InvalidRequest`] +/// when the frame is not the expected query call or its payload does not +/// decode. pub fn attach_scoped_query_frame( frame: &[u8], resource_types: &[ResourceTypeName], @@ -206,6 +221,12 @@ pub fn decode_scoped_commit_request( /// /// Scoped evidence is bus-owned. A plain ResourceCall must never be able to /// smuggle the field through the same RPC and receive a storage fence. +/// +/// # Errors +/// +/// Returns [`ScopedCommitFrameError::InvalidFrame`] when the frame is not a +/// well-formed ttrpc request, and [`ScopedCommitFrameError::InvalidRequest`] +/// when the frame is not a `CommitBatch` call or carries scoped admission. pub fn reject_scoped_commit_frame(frame: &[u8]) -> Result<(), ScopedCommitFrameError> { let header_bytes: [u8; MESSAGE_HEADER_LENGTH] = frame .get(..MESSAGE_HEADER_LENGTH) @@ -294,7 +315,7 @@ where pub async fn scoped_commit_batch( &self, request: wire::CommitBatchRequest, - scoped_mutations: Vec, + scoped_mutations: &[ScopedResourceMutation], ) -> wire::CommitBatchResponse { self.client() .scoped_commit_batch(request, scoped_mutations) @@ -422,7 +443,7 @@ where Ok(match scoped { Some(transport) => { self.client() - .scoped_commit_batch(request, transport.mutations().to_vec()) + .scoped_commit_batch(request, transport.mutations()) .await } None => self.service().commit_batch(self.trusted(request)).await, diff --git a/packages/d2b-resource-api/src/admission.rs b/packages/d2b-resource-api/src/admission.rs index 22708af35..9f944844a 100644 --- a/packages/d2b-resource-api/src/admission.rs +++ b/packages/d2b-resource-api/src/admission.rs @@ -341,8 +341,7 @@ impl StoreAdmissionBinding { .. } = admitted; let mutations = mutations - .iter() - .cloned() + .into_iter() .map(prepare_mutation) .collect::, _>>()?; Ok(MutationSealBody { diff --git a/packages/d2b-resource-api/src/client.rs b/packages/d2b-resource-api/src/client.rs index 74f7eee62..da9cdac0f 100644 --- a/packages/d2b-resource-api/src/client.rs +++ b/packages/d2b-resource-api/src/client.rs @@ -110,7 +110,7 @@ where pub async fn scoped_commit_batch( &self, request: wire::CommitBatchRequest, - scoped_mutations: Vec, + scoped_mutations: &[ScopedResourceMutation], ) -> wire::CommitBatchResponse { self.service .commit_scoped_batch(self.trusted(request), scoped_mutations) diff --git a/packages/d2b-resource-api/src/manager_backend/tests.rs b/packages/d2b-resource-api/src/manager_backend/tests.rs index 4d6357cc5..fe172e79f 100644 --- a/packages/d2b-resource-api/src/manager_backend/tests.rs +++ b/packages/d2b-resource-api/src/manager_backend/tests.rs @@ -1042,8 +1042,8 @@ async fn every_converted_type_is_served_by_the_manager_path() { /// layers, for which the universal strict envelope is the whole boundary. #[test] fn converted_type_status_layers_round_trip_through_their_typed_decoders() { - use d2b_contracts_resource::v3::{ DeviceStatusResource, VolumeBindingStatusResource }; -use d2b_provider_quota::quota::{ QuotaStatusResource }; + use d2b_contracts_resource::v3::{DeviceStatusResource, VolumeBindingStatusResource}; + use d2b_provider_quota::quota::QuotaStatusResource; use d2b_resource_runtime::manager::ResourceView; use d2b_resource_runtime::resource::ResourceStatus; use d2b_resource_runtime::spec_store::{ResourceKey, ResourceProvenance}; diff --git a/packages/d2b-resource-api/src/service.rs b/packages/d2b-resource-api/src/service.rs index e1f758248..e31d45c5c 100644 --- a/packages/d2b-resource-api/src/service.rs +++ b/packages/d2b-resource-api/src/service.rs @@ -195,6 +195,12 @@ impl ResourceService where S: ResourceStoreBackend, { + /// Construct a service bound to the authorizer's store identity. + /// + /// # Errors + /// + /// Returns [`StoreBindingError`] when the store authority or seal + /// identity is already bound to another backend. pub fn new( store: Arc, authorizer: Arc, @@ -206,6 +212,11 @@ where /// /// The backend must independently fence its authenticated session /// generation; this preserves only the store authority and seal identity. + /// + /// # Errors + /// + /// Returns [`StoreBindingError`] when the authorizer has no session store + /// binding or the store identity is already bound. pub fn new_session_bound( store: Arc, authorizer: Arc, @@ -244,6 +255,12 @@ where { /// Authenticate and authorize a Guest lifecycle operation against the /// current store row, returning the one-use downstream lease. + /// + /// # Errors + /// + /// Returns `AuthorizationDenied` when the target is not a `Guest`, the + /// Zone is invalid, or the subject is not authorized, and the store + /// error classes when the current row cannot be read. pub async fn admit_guest_lifecycle( &self, subject: &crate::AuthenticatedSubjectContext, @@ -852,7 +869,7 @@ where pub async fn commit_scoped_batch( &self, trusted: TrustedRequest, - scoped_mutations: Vec, + scoped_mutations: &[ScopedResourceMutation], ) -> wire::CommitBatchResponse { self.commit_batch_with_scope(trusted, Some(scoped_mutations), None) .await @@ -861,7 +878,7 @@ where async fn commit_batch_with_scope( &self, trusted: TrustedRequest, - scoped_mutations: Option>, + scoped_mutations: Option<&[ScopedResourceMutation]>, configuration_generation: Option, ) -> wire::CommitBatchResponse { if trusted.request.mutations.is_empty() { From 1f9a83aee4069fbace1f08a89b053bdaefae7e9e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:40:30 -0700 Subject: [PATCH 161/726] resource-api: document the service and evaluator failure contracts --- packages/d2b-resource-api/src/authz.rs | 32 +++++++++++++++++++ .../d2b-resource-api/src/manager_backend.rs | 6 ++++ 2 files changed, 38 insertions(+) diff --git a/packages/d2b-resource-api/src/authz.rs b/packages/d2b-resource-api/src/authz.rs index d94af6486..c40c7dd6f 100644 --- a/packages/d2b-resource-api/src/authz.rs +++ b/packages/d2b-resource-api/src/authz.rs @@ -861,6 +861,7 @@ impl core::fmt::Debug for CompiledRole { } impl CompiledRole { + /// Validate and compile one signed role's rule set. pub fn new( role_ref: ResourceRef, rules: Vec, @@ -909,6 +910,8 @@ impl core::fmt::Debug for CompiledRoleBinding { } impl CompiledRoleBinding { + /// Validate and compile one role binding's subject, scope, and relay + /// authority. pub fn new( role_ref: ResourceRef, subjects: impl IntoIterator, @@ -1090,6 +1093,7 @@ impl core::fmt::Debug for PolicySet { } impl PolicySet { + /// Validate and index one policy revision's roles and bindings. pub fn new( catalog: &ApiCatalog, policy_revision: u64, @@ -1476,6 +1480,14 @@ impl NativeAuthorizer { .ok_or(StoreBindingError) } + /// Hand the one-use seal acceptor for a store to its owning service. + /// + /// # Errors + /// + /// Returns [`StoreSealHandoffError::AlreadyTaken`] when the store's seal + /// slot is already installed, and + /// [`StoreSealHandoffError::AuthorizerUnavailable`] when the authorizer + /// cannot take the slot. pub fn take_store_seal( &self, store: StoreSealIdentity, @@ -1530,6 +1542,12 @@ impl NativeAuthorizer { /// authority. This method only creates the Resource API capability after /// the live policy grants the subject a session connection, so generated /// handlers never receive an unbound or caller-authored identity. + /// + /// # Errors + /// + /// Returns [`AuthorizationDenial::ZoneMismatch`] when the session Zone is + /// invalid, and [`AuthorizationDenial::NoMatchingGrant`] when the + /// positive capabilities do not include the Connect session verb. pub fn issue_authenticated_subject( &self, context: AuthenticatedSubjectContext, @@ -1547,6 +1565,20 @@ impl NativeAuthorizer { )) } + /// Authorize one request against the current policy and return the + /// one-use grant. + /// + /// # Errors + /// + /// Returns [`AuthorizationDenial::NoMatchingGrant`] when the request + /// targets no granted resource, [`AuthorizationDenial::UnknownResourceType`] + /// when a target names an unknown resource type, + /// [`AuthorizationDenial::ZoneMismatch`] when the subject Zone does not + /// match the request Zone, [`AuthorizationDenial::PolicyUnavailable`] or + /// [`AuthorizationDenial::PolicyRevisionChanged`] when the policy is + /// missing or stale, and the relay and bootstrap denials + /// (`RelayOriginInvalid`, `RelayGrantMissing`, `RelayTargetGrantMissing`, + /// `BootstrapDenied`) when the relay or bootstrap admission refuses. pub fn authorize( &self, context: &AuthenticatedSubjectContext, diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index 7d8eba7bd..a678219fe 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -622,6 +622,12 @@ fn stored_of( /// daemon's reader bridges (G5, U12): they merge manager rows into the old /// plane's store-shaped readers through exactly this rendering, so a bridged /// row is identical to the row the manager-backed API serves. +/// +/// # Errors +/// +/// Returns the `StoreError` classes the envelope renderer produces when the +/// row's metadata does not decode or the rendered envelope exceeds the +/// resource envelope bound. pub fn manager_row_stored(view: &ResourceView) -> Result { stored_from_view(view) } From 7cb57d2fe76516f4c6cf5683b1e4da4ad89e3b3f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:40:31 -0700 Subject: [PATCH 162/726] refactor(d2b-provider-guest-qemu-media): reuse serde defaults in Default impls --- packages/d2b-provider-guest-qemu-media/src/config.rs | 2 +- packages/d2b-provider-guest-qemu-media/src/types/guest.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-guest-qemu-media/src/config.rs b/packages/d2b-provider-guest-qemu-media/src/config.rs index 67fb2d3d5..872ec6cc0 100644 --- a/packages/d2b-provider-guest-qemu-media/src/config.rs +++ b/packages/d2b-provider-guest-qemu-media/src/config.rs @@ -90,7 +90,7 @@ impl Default for ProviderConfig { fn default() -> Self { Self { controller_execution_ref: ResourceRef::parse("Guest/invalid").expect("valid reference"), - qemu_binary_artifact_id: "qemu-system-x86-64".to_owned(), + qemu_binary_artifact_id: default_qemu_artifact(), qmp_ready_timeout_seconds: DEFAULT_QMP_READY_TIMEOUT_SECONDS, qmp_operation_timeout_seconds: DEFAULT_QMP_OPERATION_TIMEOUT_SECONDS, paused_at_boot_default: true, diff --git a/packages/d2b-provider-guest-qemu-media/src/types/guest.rs b/packages/d2b-provider-guest-qemu-media/src/types/guest.rs index 733f20b4d..4b3c18003 100644 --- a/packages/d2b-provider-guest-qemu-media/src/types/guest.rs +++ b/packages/d2b-provider-guest-qemu-media/src/types/guest.rs @@ -179,10 +179,10 @@ pub struct GuestProviderSpecSettings { impl Default for GuestProviderSpecSettings { fn default() -> Self { Self { - vcpu: 2, - memory_mib: 4096, + vcpu: default_vcpu(), + memory_mib: default_memory_mib(), boot_media_ref: None, - boot_media_view: "guest-attach".to_owned(), + boot_media_view: default_boot_media_view(), removable_volume_refs: Vec::new(), cpu_model: CpuModel::Host, machine_type: MachineType::Q35, From 2e56bfa23ef30a947fbef5a8ed034716cfae3ad0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:40:31 -0700 Subject: [PATCH 163/726] refactor(d2b-provider-guest-qemu-media): execute QMP commands from the history --- .../src/qmp/mod.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs b/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs index c60214f14..9998fdb99 100644 --- a/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs +++ b/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs @@ -196,6 +196,12 @@ impl QmpSession { } /// Negotiate QMP capabilities. + /// + /// # Errors + /// + /// Returns [`QmpError::GreetingInvalid`] when the greeting version is + /// empty or overlong, and the transport and command errors when the + /// greeting or capabilities exchange fails. pub fn negotiate(&mut self) -> Result<(), QmpError> { self.negotiated = false; let greeting = self.transport.receive_greeting()?; @@ -263,11 +269,16 @@ impl QmpSession { if !matches!(command, QmpCommand::Capabilities) && !self.negotiated { return Err(QmpError::NotReady); } - self.commands.push_back(command.clone()); - if self.commands.len() > 128 { - self.commands.pop_front(); + let Self { + transport, + commands, + .. + } = self; + commands.push_back(command); + if commands.len() > 128 { + commands.pop_front(); } - self.transport.execute(&command) + transport.execute(commands.back().expect("command just pushed")) } } From 61349114456a3397ddd83b152faf5c2ed35e522c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:40:31 -0700 Subject: [PATCH 164/726] docs(d2b-provider-guest-qemu-media): document error conditions on public APIs --- .../src/controller/device_watch.rs | 9 +++++++++ .../src/controller/process_builder.rs | 6 ++++++ .../src/controller/reconcile.rs | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs b/packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs index 1534c8f12..2d6aeff4f 100644 --- a/packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs +++ b/packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs @@ -79,6 +79,15 @@ pub struct DeviceAdmission; impl DeviceAdmission { /// Check owner, platform, process identity, and media contract. + /// + /// # Errors + /// + /// Returns [`DeviceAdmissionError::WrongDevice`] when the observation + /// does not name the host KVM device, [`DeviceAdmissionError::NotReady`] + /// when the device is not ready, [`DeviceAdmissionError::WrongOwner`] + /// when the device is owned by another Guest, and the identity and + /// contract errors when the observed process or media contract does not + /// match the expectation. pub fn validate( guest_ref: &ResourceRef, observation: &DeviceObservation, diff --git a/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs b/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs index 91372e2f2..a627c18e9 100644 --- a/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs +++ b/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs @@ -218,6 +218,12 @@ pub struct LaunchTicket { impl LaunchTicket { /// Construct a ticket from already-authorized refs. + /// + /// # Errors + /// + /// Returns [`ProcessSpecError`] when the process spec fails validation, + /// when more than four media refs are named, when a media ref is not a + /// Volume, or when a media ref is duplicated. pub fn new( process: ProcessSpec, media_refs: impl IntoIterator, diff --git a/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs b/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs index d51852171..dea7a6ecd 100644 --- a/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs +++ b/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs @@ -335,6 +335,12 @@ impl QemuMediaController { impl QemuMediaController { /// Reconcile dependencies, process identity, and QMP readiness. + /// + /// # Errors + /// + /// Returns [`QemuMediaError::InvalidState`] when the controller is not + /// reconcilable, and the dependency, process identity, and QMP readiness + /// errors the phases surface. pub fn reconcile( &mut self, dependencies: &QemuMediaDependencies, From cc16e64149ed0033008b7e847c8932812efd5880 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:41:34 -0700 Subject: [PATCH 165/726] audit: record wave-1 slice 8 Forty rows applied or varied across twelve crates, three of them minimal variants that preserve wire bytes or borrow structure; four contract doc rows remain pending for the follow-up. --- .../2026-09-24-rust-skills-audit/ledger.md | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index ab388144e..e009466b5 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -62,7 +62,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0021` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src` | | | | `RS-0023` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/resource.rs:621-626` | | | | `RS-0024` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223` | | | -| `RS-0025` | `idiom` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `src/v3/component_session.rs:1935, src/v3/component_session.rs:1976` | | | +| `RS-0025` | `idiom` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | f547324ca | `packages/d2b-contracts-zone-session/src/v3/component_session.rs` | Default derived on ReceiveSequence/SendSequence; hand-written impls deleted; ZoneLinkLimits Default kept | | | `RS-0027` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | let spec = find_network_spec(&parts)?; let _ = spec; replaced by bare self.find_network_spec(&parts)?; in projection and sysctl intents | | | `RS-0030` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | iter().any(f == last) replaced with slice contains for PUBLIC_MANIFEST_FIELDS and BROAD_CAPABILITIES | | | `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | applied-variant | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | row's bare-import removal broke tests using TapRole via use super::*; variant: import dropped, const deleted, 3 test sites qualified crate::host::TapRole (as _ import rejected by -D warnings) | | @@ -74,15 +74,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0038` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:1131` | | | | `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-pro` | | | | `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provi` | | | -| `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:379-386, packages/d2b-provider-config-nixo` | | | +| `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 3459dc5a0 | `packages/d2b-provider-config-nixos/src/ttrpc.rs` | Shared path_components helper classifies Path::components; both callers use it | | | `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | | | | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-e` | | | -| `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:446, packages/d2b-provider-cred` | | | +| `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | applied | U2 | 20e8286f8 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | SecretServiceOwner::Userd renamed to User; enum not serialized; census 2 hits in-crate | | | `RS-0047` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | rustfmt drift normalized: enum closing brace, trailing-whitespace line, reindented variant doc comment | | | `RS-0048` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/effects_service.rs` | let _ = binding dropped; Self::declared_row_template(&view, role)?; | | | `RS-0049` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | in-crate macro_rules! opaque_token (derive list + is_zero/as_bytes feature arms, stringify redacting Debug); all 6 newtypes migrated with exact surfaces preserved | | -| `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/driver.rs:380-390` | | | -| `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `swtpm_argv.rs:160, lib.rs:63, lib.rs:65` | | | -| `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `driver.rs:267-281` | | | +| `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U2 | db396585b | `packages/d2b-provider-device-security-key/src/driver.rs` | declared_dependency_refs arms are iterator-chain expressions; push closure deleted | | +| `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | swtpm_argv.rs imports and uses MIN/MAX_SWTPM_LOG_LEVEL instead of literal 1..=20 | | +| `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | 9e7388e34 | `packages/d2b-provider-device-usbip/src/driver.rs` | declared_dependency_refs match arms return flatten().collect() expressions | | | `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:1442, src/spec.rs:385` | | | | `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:620, packages/d2b-provid` | | | | `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/controller.rs:464, src/process.rs:402, src/process.rs:676` | | | @@ -97,22 +97,22 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0064` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `controller.rs:1722, controller.rs:1860, controller.rs:2042` | | | | `RS-0065` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:487-494, shutdown.rs:666-673` | | | | `RS-0066` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `bootstrap_graph.rs:131-139, bootstrap_graph.rs:417-422` | | | -| `RS-0067` | `idiom` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/config.rs:93, packages/d2b-provider-guest-qemu-` | | | +| `RS-0067` | `idiom` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 7cb57d2fe | `packages/d2b-provider-guest-qemu-media/src/config.rs` | Default impls call default_qemu_artifact/default_vcpu/default_memory_mib/default_boot_media_view | | | `RS-0068` | `idiom` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/test_support.rs:185` | | | -| `RS-0069` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/controller.rs:298-302` | | | -| `RS-0070` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/driver.rs:377-393` | | | +| `RS-0069` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Octets destructured via try_into and rendered with one format! | | +| `RS-0070` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/driver.rs` | declared_dependency_refs is a filter_map pipeline over attachments | | | `RS-0071` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:660-675` | | | | `RS-0072` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/descriptor.rs:43-44, packages/d2b-provider-` | | | | `RS-0073` | `idiom` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-pro` | | | | `RS-0074` | `idiom` | `d2b-provider-seccomp-profile` | low | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-sec` | | | | `RS-0075` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/systemd.rs:840` | | | | `RS-0076` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor` | | | -| `RS-0077` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/user.rs:75, src/user.rs:76` | | | -| `RS-0078` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/user.rs:232` | | | +| `RS-0077` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | to_hex uses a const HEX table; dead unwrap_or fallback removed | | +| `RS-0078` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | required_bindings is a free pub fn re-exported at root; Self:: call and two test sites updated | | | `RS-0079` | `idiom` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:926-941, packages/d2b-provider-toolkit/src/` | | | | `RS-0080` | `idiom` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:545-597, packages/d2b-provider-toolkit/src/` | | | -| `RS-0081` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239, packages/d2b` | | | -| `RS-0082` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/auth.rs:249-253` | | | +| `RS-0081` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | RelaySecret derives Clone; hand-written impl deleted | | +| `RS-0082` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 6fe6615af | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | Bearer header built from a literal instead of a collected char array | | | `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:221-224` | | | | `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:607-609` | | | | `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/status.rs:33-38` | | | @@ -134,8 +134,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/admission.rs` | send_authorized_ttrpc now calls validate_ttrpc_permit(&permit, now_tick)? instead of re-writing the matches! block | | | `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/config.rs:178` | | | | `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U2 | f3a847c72 | `packages/d2b-unsafe-local-helper/src/systemd.rs` | Replaced the then_some/ok_or NotFound normalization with an explicit if-let/if-error branch in terminate_scope and stop_scope; cargo check and test green. | | -| `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/resolver.rs:144` | | | -| `RS-0105` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/service.rs:311` | | | +| `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | 932616e19 | `packages/d2b-zone-routing/src/resolver.rs` | longest_suffix_match is a find_map over the index range | | +| `RS-0105` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | c8defa1f4 | `packages/d2b-zone-routing/src/service.rs` | ZoneTopologyRequest derives Default; manual impl deleted | | | `RS-0106` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, pa` | | | | `RS-0108` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:14699, packages/d2bd/src/composition.rs:14710, packages/d` | | | | `RS-0109` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20450-20461, packages/d2bd/src/composition.rs:20486-20498` | | | @@ -175,11 +175,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0138` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs` | is_valid_zone(&str) extracted; validate_zone delegates to it; allowed_telemetry_value no longer allocates | | | `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | dedup sets now BTreeSet<&BoundedToken>/BTreeSet<&ResourceTypeName> in ProviderManifest::new and with_state_namespaces | | | `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume_state.rs:138` | | | -| `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `zone_routing.rs:883` | | | +| `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied-variant | U2 | 862071320 | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs` | Order-preserving contains check (n<=64) instead of sort-in-place: sorting would change serialized bytes of a signed wire message for unsorted inputs | | | `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | -| `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `resource_bundle.rs:944, resource_bundle.rs:149` | | | +| `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | acffb7466 | `packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs` | Walk iterates CanonicalJsonObject keys directly; no wrapper or clone built | | | `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | -| `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `services.rs:216` | | | +| `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | 7be394a88 | `packages/d2b-contracts-zone-session/src/v3/services.rs` | BoundedText::parse takes method.as_str() instead of method.clone() | | | `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | path_bearing_key_violations renders through Cow; string arm borrows instead of cloning | | | `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | parse(value.as_str()) at 3 sites; network_uid compare via as_str; note: row rationale 'no allocation' inaccurate (Into still allocates) but explicit clones removed | | | `RS-0145` | `own` | `d2b-core-controller` | low | actionable | leaf | | | | `owner_reconcile.rs:1072-1075` | | | @@ -187,11 +187,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/t` | | | | `RS-0154` | `own` | `d2b-provider` | low | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304` | | | | `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | | | -| `RS-0156` | `own` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:111, packages/d2b-provider-config-nixos/sr` | | | +| `RS-0156` | `own` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | b17a8c271 | `packages/d2b-provider-config-nixos/src/controller.rs` | GuestConfigDocument::into_bytes() consuming accessor; dispatch passes it without copying | | | `RS-0157` | `own` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/t` | | | | `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | validate &identity before store; identity stored on failure branch preserving test-pinned retain-for-finalize contract | | -| `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `resource_controller.rs:233, resource_controller.rs:247, effects_service.rs:280, effects_se` | | | -| `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `broker.rs:194-208, broker.rs:218-232, broker.rs:313-321, broker.rs:333-341` | | | +| `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | applied-variant | U2 | 3c3a82817 | `packages/d2b-provider-device-tpm/src/resource_controller.rs` | if/else arms cannot mix owned and borrowed; restructured to ensure-then-borrow from the fields (zero clones), plus the two effects_service reborrows | | +| `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | d674e47e9 | `packages/d2b-provider-device-usbip/src/broker.rs` | Lease moved into the field first; map and return clone from the field (3 clones down to 2 per admission) | | | `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provid` | | | | `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/driver.rs:981` | | | | `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/ef` | | | @@ -205,9 +205,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0171` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | both vm_handle sites borrow via as_ref().ok_or(AzureVmError::Ambiguous) instead of cloning | | | `RS-0172` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | pending_delete_operation_id borrowed via as_deref() instead of clone | | | `RS-0173` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | base32 output truncated in place (id.truncate(20)) instead of a second 20-char copy | | -| `RS-0174` | `own` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266` | | | +| `RS-0174` | `own` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 2e56bfa23 | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs` | execute destructures transport/commands, pushes the owned command, executes from commands.back() | | | `RS-0175` | `own` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266` | | | -| `RS-0176` | `own` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/controller.rs:416-417` | | | +| `RS-0176` | `own` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Collision set stores &str borrowed from interface_names | | | `RS-0177` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:1033, packages/d2b-provider-n` | | | | `RS-0178` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/lifecycle.rs:338, packages/d2b-provider-not` | | | | `RS-0179` | `own` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285` | | | @@ -216,13 +216,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0182` | `own` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:355, src/driver.rs:478, src/driver.rs:522` | | | | `RS-0183` | `own` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:360, src/driver.rs:435` | | | | `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | | | | `src/service/supervisor.rs:599, src/service/supervisor.rs:601` | | | -| `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/host.rs:466, src/host.rs:467` | | | +| `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | | `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | | `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | | | | `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/runtime.rs:530-537` | | | | `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:771` | | | -| `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:190-198, packages/d2b` | | | -| `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:267-277, packages/d2b-` | | | +| `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | with_deadline consumes self and rebuilds with struct-update syntax; sole caller passes owned request | | +| `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 72858f537 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs` | GatewayCredential stores material: GatewayCredentialMaterial moved in from_material; Drop impl deleted (material zeroizes); accessors and Debug unchanged | | | `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | applied-variant | U2 | 9ba7acf09 | `packages/d2b-provider-user/src/effects_service.rs` | Destructured InspectUserRequest and moved groups by value; username still cloned because inspect_user_response borrows it after UserSpec::new consumes it (stated fix was not implementable as written). | | | `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:337` | | | | `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | | | | `driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.` | | | @@ -246,7 +246,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | json_object moves member values; 17 call sites updated | | | `RS-0213` | `own` | `d2b-session` | low | actionable | family | | | | `engine.rs:689, admission.rs:593` | | | | `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83` | | | -| `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/engine.rs:345, packages/d2b-zone-routing/src/engine.rs:346` | | | +| `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | applied-variant | U2 | 6a3cf6cff | `packages/d2b-zone-routing/src/engine.rs` | Zone pair moved into the snapshot after destructuring expected; validate_snapshot checks inlined (row's first option) and gated #[cfg(test)] since consume no longer calls it | | | `RS-0221` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_compositi` | | | | `RS-0222` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:4057` | | | | `RS-0216` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:359` | | | @@ -684,10 +684,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0638` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/streams.rs` | # Errors on StreamName::parse, OperationId::parse, ZoneBoundPolicyIdentity::digest,and ZoneEndpointPolicy::lower | | | `RS-0639` | `docs` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src` | | | | `RS-0640` | `docs` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/br` | | | -| `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130` | | | -| `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495` | | | -| `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | | | | `unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wi` | | | -| `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | | | | `terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105` | | | +| `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130` | Not applied: run budget exhausted before the contracts-control doc batch; cli_output.rs DTO docs remain | | +| `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495` | Not applied: run budget exhausted; public_wire.rs docs and # Errors remain | | +| `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wi` | Not applied: run budget exhausted; unsafe_local_wire.rs constant/type docs remain | | +| `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | pending | U2 | | `terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105` | Not applied: run budget exhausted; terminal_wire.rs DTO docs remain | | | `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | | `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | | `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/` | | | @@ -713,20 +713,20 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | | | | `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | | | | `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | applied | U2 | ef3bc5ec9 | `packages/d2b-provider-command/src/command.rs` | Added one-line # Errors naming CommandContractError variants to CommandExec::parse, CommandArgvSlot::parse, CommandSpec::new. | | -| `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/controller.rs:45-64, packages/d2b-provider-config-n` | | | +| `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 7a6ab2d2d | `packages/d2b-provider-config-nixos/src/controller.rs` | # Errors added to all 19 pub Result items naming ConfigError variants | | | `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/` | | | | `RS-0674` | `docs` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U2 | b29c0b8d2 | `packages/d2b-provider-credential-entra/src/controller.rs` | Added # Errors naming returned variants to EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, r | | | `RS-0675` | `docs` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U2 | e86206bab | `packages/d2b-provider-credential-managed-identity/src/lib.rs` | Added # Errors naming ManagedIdentityProviderError/CredentialServiceError/CredentialObservabilityError variants to the named constructors and controller projections. | | -| `RS-0676` | `docs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-cred` | | | -| `RS-0677` | `docs` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-` | | | +| `RS-0676` | `docs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U2 | d5869f583 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | # Errors added to SecretServiceConfig/Placement/Factory/Controller items and drain | | +| `RS-0677` | `docs` | `d2b-provider-credential-secret-service` | low | actionable | leaf | applied | U2 | c6aa0e3d6 | `packages/d2b-provider-credential-secret-service/src/service.rs` | SESSION_CLOSE_REVOKE_DEADLINE_MS const with why-doc replaces triplicated 1_000 | | | `RS-0678` | `docs` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | # Errors sections added to all 16 named Result-returning items with exact error variants | | | `RS-0679` | `docs` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/gpu_argv.rs` | dropping the allows exposed 15 more undocumented variants/fields under deny(missing_docs); documented GpuContextType variants, GpuArgvError/VideoArgvError variants+path fields, VideoBackend::Vaapi, pl | | -| `RS-0681` | `docs` | `d2b-provider-device-security-key` | medium | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/lease.rs:150-303, packages/d2b-provider-devi` | | | -| `RS-0680` | `docs` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/relay.rs:7, packages/d2b-provider-device-sec` | | | -| `RS-0682` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `resources.rs:53, swtpm_argv.rs:130, resource_controller.rs:132, resource_controller.rs:190` | | | -| `RS-0683` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `swtpm_argv.rs:39` | | | -| `RS-0684` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `reconcile_state.rs:6, state_machine.rs:61, lib.rs:9` | | | -| `RS-0685` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `arbitration.rs:76, busid.rs:12, broker.rs:61, controller.rs:210` | | | +| `RS-0681` | `docs` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | U2 | a895e8c62 | `packages/d2b-provider-device-security-key/src/lease.rs` | # Errors naming SecurityKeyLeaseError/SecurityKeyControllerError variants on all named items | | +| `RS-0680` | `docs` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U2 | e5ec67524 | `packages/d2b-provider-device-security-key/src/relay.rs` | All pub items documented (incl. Leased variant fields found by compiler); module allow dropped | | +| `RS-0682` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae,8ac4f8535 | `packages/d2b-provider-device-tpm/src/resources.rs` | # Errors added to all 12 pub Result items naming TpmResourceEffectError/TpmResourceControllerError/SwtpmArgvError variants | | +| `RS-0683` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | Module allow dropped; SwtpmArgvError variant fields documented to satisfy deny(missing_docs) | | +| `RS-0684` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | 59c6a4e3a | `packages/d2b-provider-device-usbip/src/reconcile_state.rs` | All pub items documented (compiler-enumerated, incl. trait methods and variant fields); both module allows dropped | | +| `RS-0685` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | a1d9832ec | `packages/d2b-provider-device-usbip/src/arbitration.rs` | # Errors added to the eight named pub Result items | | | `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/policy.rs:114, src/policy.rs:119` | | | | `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provide` | | | | `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759` | | | @@ -735,7 +735,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | | `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | matches() doc states the constant-time-in-presented-length guarantee | | | `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `descriptor.rs:423-429, identity.rs:590-634` | | | -| `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs:82, packages/d2b-pro` | | | +| `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U2 | 613491144 | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | # Errors added to DeviceAdmission::validate, QemuMediaController::reconcile, LaunchTicket::new, QmpSession::negotiate | | | `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provide` | | | | `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | | | | `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `lib.rs:13, lib.rs:14, lib.rs:15` | | | @@ -748,10 +748,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0704` | `docs` | `d2b-provider-role` | low | actionable | leaf | applied-variant | U2 | e36441105 | `packages/d2b-provider-role/src/lib.rs` | Added #![deny(missing_docs)] and documented PolicyRevisionSet fields; the gate forced one-line docs on AuthorizationCacheKey::new and the four PositiveDecisionCache methods to keep the build green. | | | `RS-0705` | `docs` | `d2b-provider-seccomp-profile` | medium | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:31, packages/d2b-provider-sec` | | | | `RS-0706` | `docs` | `d2b-provider-shell-terminal` | medium | actionable | leaf | | | | `src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/` | | | -| `RS-0707` | `docs` | `d2b-provider-system-core` | medium | actionable | leaf | | | | `src/host.rs:121, src/host.rs:161, src/user.rs:241` | | | +| `RS-0707` | `docs` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | # Errors added to validate, HostProbeSnapshot::new, reconcile family, reject_operator_status_fields, UserReconciler::reconcile and both port methods | | | `RS-0708` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/s` | | | | `RS-0709` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolki` | | | -| `RS-0710` | `docs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/auth.rs:229-246, packages/d2b-provider-tra` | | | +| `RS-0710` | `docs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 33a84349d | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | # Errors added to mint_sas, build_connect, CreditWindow::new, RelayTransportSettings::new | | | `RS-0711` | `docs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U2 | 721c96f38 | `packages/d2b-provider-transport-unix/src/portal.rs` | Added # Errors naming PortalError variants to open, close, and observe. | | | `RS-0712` | `docs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsoc` | | | | `RS-0713` | `docs` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/facets.rs` | Added # Errors to SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, BindingDriverEffects::remove_socket, and guest_mount_ready naming the daemon-adapter failures and fail-closed handlin | | @@ -775,7 +775,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0731` | `docs` | `d2b-session-unix` | medium | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added first-sentence contract docs to SeqpacketSocket, UnixSeqpacketTransport, UnixStreamTransport, CreditPool, PidfdEvidence, PeerCredentials, ActivatedSeqpacketListener(s), FramedVsockTransport and | | | `RS-0732` | `docs` | `d2b-session-unix` | low | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added # Errors to the anchor Result fns (SeqpacketSocket::from_owned/from_parent_prearmed/from_inherited_fd, UnixSeqpacketTransport::new, CreditPool::new, PidfdEvidence::new) naming their distinct fai | | | `RS-0733` | `docs` | `d2b-telemetry` | low | actionable | leaf | applied | U2 | e1fab0e9b | `packages/d2b-telemetry/src/audit_hash.rs` | Added # Errors naming the returned variants to every named item: AuditHash::parse, AuditChainLink::verify/verify_at, all eight BoundedEmitter fns, MetricFamily/MeterRegistry, RedactionGuard, validate_ | | -| `RS-0734` | `docs` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/resolver.rs:80, packages/d2b-zone-routing/src/service.rs:208` | | | +| `RS-0734` | `docs` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | 20855634d | `packages/d2b-zone-routing/src/resolver.rs` | # Errors added to seal, ZoneServiceLimits::new, both with_runtime_admission sites, ZoneEnrollmentExpectation::new, ZoneEnrollmentAuthority::new/with_lifetime | | | `RS-0736` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828` | | | | `RS-0741` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/audio_dispatch.rs:372` | | | | `RS-0737` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:438` | | | From 54462da3511d9fefbfc4616ae073de1d9dcd8010 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:41:47 -0700 Subject: [PATCH 166/726] shell-terminal: scope the ledger borrow and document error contracts --- .../d2b-provider-shell-terminal/src/authz.rs | 5 +++ .../src/resources/pool.rs | 7 ++++ .../src/resources/session.rs | 5 +++ .../src/service/controller.rs | 40 +++++++++++++++++++ .../src/service/supervisor.rs | 24 ++++++++--- .../src/session/adopt.rs | 5 +++ .../src/session/ring.rs | 5 +++ 7 files changed, 86 insertions(+), 5 deletions(-) diff --git a/packages/d2b-provider-shell-terminal/src/authz.rs b/packages/d2b-provider-shell-terminal/src/authz.rs index 23c473b2d..fe1702b34 100644 --- a/packages/d2b-provider-shell-terminal/src/authz.rs +++ b/packages/d2b-provider-shell-terminal/src/authz.rs @@ -73,6 +73,11 @@ pub struct Authorizer; impl Authorizer { /// Authorize the role bound to the current request before resource lookup. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::NotAuthorized`] when the subject + /// carries no admin role. pub fn authorize_request(subject: &Subject) -> Result<(), ShellTerminalError> { if subject.is_admin() { Ok(()) diff --git a/packages/d2b-provider-shell-terminal/src/resources/pool.rs b/packages/d2b-provider-shell-terminal/src/resources/pool.rs index 4720e3243..267317c14 100644 --- a/packages/d2b-provider-shell-terminal/src/resources/pool.rs +++ b/packages/d2b-provider-shell-terminal/src/resources/pool.rs @@ -81,6 +81,13 @@ impl std::fmt::Debug for PoolSpec { impl PoolSpec { /// Construct a bounded pool policy. + /// + /// # Errors + /// + /// Returns the execution-target validation refusal, the name or + /// workload-user validation refusal, or + /// [`ShellTerminalError::InvalidLoginShell`] when the login shell + /// reference is not a bounded `artifact://` URI. pub fn new( execution_target: ExecutionTarget, workload_user: impl Into, diff --git a/packages/d2b-provider-shell-terminal/src/resources/session.rs b/packages/d2b-provider-shell-terminal/src/resources/session.rs index 42b9fb64e..9b709a4ee 100644 --- a/packages/d2b-provider-shell-terminal/src/resources/session.rs +++ b/packages/d2b-provider-shell-terminal/src/resources/session.rs @@ -52,6 +52,11 @@ impl std::fmt::Debug for ShellSession { impl ShellSession { /// Create a session by freezing placement and shell fields from its pool. + /// + /// # Errors + /// + /// Returns the name-validation or capacity refusal the underlying + /// resource-name construction reports. pub fn from_pool( pool: &ShellPool, name: impl Into, diff --git a/packages/d2b-provider-shell-terminal/src/service/controller.rs b/packages/d2b-provider-shell-terminal/src/service/controller.rs index 25c74fcdc..913e1dc19 100644 --- a/packages/d2b-provider-shell-terminal/src/service/controller.rs +++ b/packages/d2b-provider-shell-terminal/src/service/controller.rs @@ -32,6 +32,11 @@ impl std::fmt::Debug for OpenSessionRequest { impl OpenSessionRequest { /// Construct a bounded session request. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::InvalidName`] when the pool or + /// session name violates its bound. pub fn new( pool_name: impl Into, session_name: impl Into, @@ -140,6 +145,12 @@ impl ShellTerminalController { /// Restored occupancy blocks new streams until the next status reconcile /// proves capacity. This intentionally favors refusal over potentially /// exceeding a pool's attachment limit after controller restart. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::CapacityExceeded`] when the pool name + /// is already projected, and the authority's refusal when the restore + /// is rejected. pub fn restore_pool( &mut self, pool: ShellPool, @@ -166,6 +177,11 @@ impl ShellTerminalController { } /// Update remote occupancy without invalidating locally tracked streams. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::CapacityExceeded`] when the pool is + /// not projected or the authority rejects the attachment count. pub fn reconcile_pool_attachments( &self, pool_name: &str, @@ -207,6 +223,11 @@ impl ShellTerminalController { /// The session remains counted for capacity even when the supervisor is /// missing or ambiguous, preventing a restart from recreating a resource /// name while its earlier process may still exist. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::CapacityExceeded`] when the pool is + /// missing or the session is already projected. pub fn restore_session( &mut self, session: ShellSession, @@ -262,6 +283,12 @@ impl ShellTerminalController { } /// Advance one reconciled session after its prior supervisor is retired. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::NotAuthorized`] when the subject is + /// not authorized, [`ShellTerminalError::CapacityExceeded`] when the + /// session is not projected, and the authority's refusal otherwise. pub fn restart_supervisor( &mut self, subject: &Subject, @@ -340,6 +367,13 @@ impl ShellTerminalController { } /// Create a session after authorizing the current request and enforcing pool capacity. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::NotAuthorized`] when the subject is + /// not authorized, [`ShellTerminalError::CapacityExceeded`] when the + /// pool is not projected or full, and the authority's refusal + /// otherwise. pub fn open_session( &mut self, subject: &Subject, @@ -446,6 +480,12 @@ impl ShellTerminalController { } /// Finalize one session after its owned supervisor has stopped. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::NotAuthorized`] when the subject is + /// not authorized, [`ShellTerminalError::CapacityExceeded`] when the + /// session is not projected, and the authority's refusal otherwise. pub fn finalize_session( &mut self, subject: &Subject, diff --git a/packages/d2b-provider-shell-terminal/src/service/supervisor.rs b/packages/d2b-provider-shell-terminal/src/service/supervisor.rs index 617d53a7c..ca1f20621 100644 --- a/packages/d2b-provider-shell-terminal/src/service/supervisor.rs +++ b/packages/d2b-provider-shell-terminal/src/service/supervisor.rs @@ -85,6 +85,11 @@ pub struct AttachRequest { impl AttachRequest { /// Construct an attach request for one exact supervisor generation. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::CapacityOutOfRange`] when the tail + /// byte budget exceeds the ring ceiling. pub fn new(expected_generation: u64, tail_bytes: u64) -> Result { if tail_bytes > 1024 * 1024 { return Err(ShellTerminalError::CapacityOutOfRange); @@ -422,6 +427,13 @@ impl ShellAuthorityLedger { /// Validate that a Provider-reconstructed session still matches the /// authority ledger without touching its test-only Process map. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::SupervisorAmbiguous`] when the + /// session is not projected and + /// [`ShellTerminalError::StaleSessionGeneration`] when the fingerprint + /// no longer matches. pub fn validate_session(&self, session: &ShellSession) -> Result<(), ShellTerminalError> { let state = self.lock()?; let Some(entry) = state.sessions.get(session.name()) else { @@ -596,11 +608,13 @@ impl ShellAuthorityPort for ShellAuthorityLedger { retired_identity: Option<&SupervisorIdentity>, ) -> Result { let mut state = self.lock()?; - let current_identity = Self::session_mut(&mut state, session)? - .supervisor_identity - .clone(); - if current_identity.as_ref() != retired_identity { - return Err(ShellTerminalError::SupervisorAmbiguous); + { + let current_identity = Self::session_mut(&mut state, session)? + .supervisor_identity + .as_ref(); + if current_identity != retired_identity { + return Err(ShellTerminalError::SupervisorAmbiguous); + } } let capability_id = state .next_capability diff --git a/packages/d2b-provider-shell-terminal/src/session/adopt.rs b/packages/d2b-provider-shell-terminal/src/session/adopt.rs index 0f14481a2..a185846f3 100644 --- a/packages/d2b-provider-shell-terminal/src/session/adopt.rs +++ b/packages/d2b-provider-shell-terminal/src/session/adopt.rs @@ -10,6 +10,11 @@ pub struct SupervisorIdentity { impl SupervisorIdentity { /// Construct a verified identity with a nonzero generation and digests. + /// + /// # Errors + /// + /// Returns [`crate::ShellTerminalError::SupervisorAmbiguous`] when the + /// invocation or cgroup digest is zero or the generation is zero. pub fn new( invocation_digest: [u8; 32], cgroup_digest: [u8; 32], diff --git a/packages/d2b-provider-shell-terminal/src/session/ring.rs b/packages/d2b-provider-shell-terminal/src/session/ring.rs index 36f0e2d62..4d1304c5d 100644 --- a/packages/d2b-provider-shell-terminal/src/session/ring.rs +++ b/packages/d2b-provider-shell-terminal/src/session/ring.rs @@ -13,6 +13,11 @@ pub struct OutputRing { impl OutputRing { /// Create a ring within the provider's documented capacity bounds. + /// + /// # Errors + /// + /// Returns [`ShellTerminalError::CapacityOutOfRange`] when the + /// capacity is outside `4096..=1 MiB`. pub fn new(capacity: usize) -> Result { if !(4096..=1024 * 1024).contains(&capacity) { return Err(ShellTerminalError::CapacityOutOfRange); From 35da01dbd80b422ab1a78971e238d8fc8e7a1b60 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:42:01 -0700 Subject: [PATCH 167/726] aca: consume candidate lists in one_candidate helpers --- .../src/controller.rs | 18 +++++++++--------- .../src/effects.rs | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs index c73eda695..382334eaf 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs @@ -887,9 +887,10 @@ where fn one_candidate( candidates: AcaSandboxCandidates, ) -> Result, AcaControllerError> { - match candidates.as_slice() { - [] => Ok(None), - [candidate] => Ok(Some(candidate.clone())), + let mut candidates = candidates.into_iter(); + match (candidates.next(), candidates.next()) { + (Some(candidate), None) => Ok(Some(candidate)), + (None, None) => Ok(None), _ => Err(AcaControllerError::AmbiguousAdoption), } } @@ -898,12 +899,11 @@ fn one_disk_image( candidates: crate::AcaDiskImageCandidates, generation: u64, ) -> Result, AcaControlError> { - match candidates.as_slice() { - [] => Ok(None), - [candidate] if candidate.generation == generation => Ok(Some(candidate.clone())), - [..] if candidates.as_slice().len() == 1 => { - Err(AcaControlError::new(AcaControlErrorKind::Conflict)) - } + let mut candidates = candidates.into_iter(); + match (candidates.next(), candidates.next()) { + (Some(candidate), None) if candidate.generation == generation => Ok(Some(candidate)), + (None, None) => Ok(None), + (Some(_), None) => Err(AcaControlError::new(AcaControlErrorKind::Conflict)), _ => Err(AcaControlError::new(AcaControlErrorKind::Ambiguous)), } } diff --git a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs index 907ddc568..33a08d4f3 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs @@ -584,6 +584,15 @@ impl AcaDiskImageCandidates { } } +impl IntoIterator for AcaDiskImageCandidates { + type Item = AcaDiskImageRecord; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub enum AcaSandboxLifecycle { @@ -630,6 +639,15 @@ impl AcaSandboxCandidates { } } +impl IntoIterator for AcaSandboxCandidates { + type Item = AcaSandboxRecord; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AcaDeleteOutcome { Deleted, From 48072a121d13845067b31f71029af42404bb7cd5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:42:05 -0700 Subject: [PATCH 168/726] aca: share ref validation between config new and validate --- .../src/effects.rs | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs index 33a08d4f3..dcf126529 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs @@ -420,17 +420,12 @@ impl AcaProviderConfig { sandbox_transport_alias: AcaProfileId, defaults: AcaRuntimeConfig, ) -> Result { - if gateway_execution_ref.resource_type().as_str() != "Guest" - || control_credential_ref.resource_type().as_str() != "Credential" - || pull_credential_ref - .as_ref() - .is_some_and(|reference| reference.resource_type().as_str() != "Credential") - || network_ref - .as_ref() - .is_some_and(|reference| reference.resource_type().as_str() != "Network") - { - return Err(AcaTypeError::InvalidExecutionBoundary); - } + Self::validate_refs( + &gateway_execution_ref, + &control_credential_ref, + &pull_credential_ref, + &network_ref, + )?; Ok(Self { gateway_execution_ref, tenant_id, @@ -448,20 +443,32 @@ impl AcaProviderConfig { /// Revalidate a Provider configuration at the admission boundary. pub fn validate(&self) -> Result<(), AcaTypeError> { - Self::new( - self.gateway_execution_ref.clone(), - self.tenant_id.clone(), - self.client_id.clone(), - self.subscription_id.clone(), - self.control_credential_ref.clone(), - self.pull_credential_ref.clone(), - self.environment_id.clone(), - self.resource_group_id.clone(), - self.network_ref.clone(), - self.sandbox_transport_alias.clone(), - self.defaults.clone(), + Self::validate_refs( + &self.gateway_execution_ref, + &self.control_credential_ref, + &self.pull_credential_ref, + &self.network_ref, ) - .map(|_| ()) + } + + fn validate_refs( + gateway_execution_ref: &ResourceRef, + control_credential_ref: &ResourceRef, + pull_credential_ref: &Option, + network_ref: &Option, + ) -> Result<(), AcaTypeError> { + if gateway_execution_ref.resource_type().as_str() != "Guest" + || control_credential_ref.resource_type().as_str() != "Credential" + || pull_credential_ref + .as_ref() + .is_some_and(|reference| reference.resource_type().as_str() != "Credential") + || network_ref + .as_ref() + .is_some_and(|reference| reference.resource_type().as_str() != "Network") + { + return Err(AcaTypeError::InvalidExecutionBoundary); + } + Ok(()) } } From c496e221426c835a9885f87dc52836e19ef9ef5f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:42:16 -0700 Subject: [PATCH 169/726] provider-toolkit: collapse the guest backend response and reply into one type --- .../d2b-provider-toolkit/src/base/fd10.rs | 109 ++++++++---------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/packages/d2b-provider-toolkit/src/base/fd10.rs b/packages/d2b-provider-toolkit/src/base/fd10.rs index b99ac595b..fc8e74f39 100644 --- a/packages/d2b-provider-toolkit/src/base/fd10.rs +++ b/packages/d2b-provider-toolkit/src/base/fd10.rs @@ -561,65 +561,6 @@ pub fn zeroizing_bytes(bytes: Vec) -> CredentialSensitiveBytes { } impl GuestCredentialBackendResponse { - /// Borrow the optional backend state. - pub fn state(&self) -> Option<&str> { - self.state.as_deref() - } - - /// Borrow the optional opaque lease handle. - pub fn lease_handle(&self) -> Option<&str> { - self.lease_handle.as_deref() - } - - /// Borrow the optional opaque source version. - pub fn source_version(&self) -> Option<&str> { - self.source_version.as_deref() - } - - /// Return the optional rotation generation. - pub const fn rotation_generation(&self) -> Option { - self.rotation_generation - } - - /// Return the optional absolute expiry. - pub const fn expires_at_unix_ms(&self) -> Option { - self.expires_at_unix_ms - } - - /// Borrow the optional closed outcome label. - pub fn outcome(&self) -> Option<&str> { - self.outcome.as_deref() - } - - /// Consume the response and return sensitive bytes in a zeroizing owner. - pub fn into_bytes(self) -> Option>> { - self.bytes - } - - /// Explicitly erase and discard any sensitive response bytes. - pub fn clear_bytes(&mut self) { - self.bytes.take(); - } -} - -impl std::fmt::Debug for GuestCredentialBackendResponse { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("GuestCredentialBackendResponse()") - } -} - -/// A non-secret or zeroizing response returned by one Guest backend operation. -pub struct GuestCredentialBackendReply { - state: Option, - lease_handle: Option, - source_version: Option, - rotation_generation: Option, - expires_at_unix_ms: Option, - outcome: Option, - bytes: Option>>, -} - -impl GuestCredentialBackendReply { /// Construct a typed backend reply. Sensitive bytes remain zeroizing. pub fn new( state: Option, @@ -663,11 +604,46 @@ impl GuestCredentialBackendReply { ) } - /// Consume the reply and return sensitive bytes in a zeroizing owner. - pub fn into_bytes(self) -> Option { + /// Borrow the optional backend state. + pub fn state(&self) -> Option<&str> { + self.state.as_deref() + } + + /// Borrow the optional opaque lease handle. + pub fn lease_handle(&self) -> Option<&str> { + self.lease_handle.as_deref() + } + + /// Borrow the optional opaque source version. + pub fn source_version(&self) -> Option<&str> { + self.source_version.as_deref() + } + + /// Return the optional rotation generation. + pub const fn rotation_generation(&self) -> Option { + self.rotation_generation + } + + /// Return the optional absolute expiry. + pub const fn expires_at_unix_ms(&self) -> Option { + self.expires_at_unix_ms + } + + /// Borrow the optional closed outcome label. + pub fn outcome(&self) -> Option<&str> { + self.outcome.as_deref() + } + + /// Consume the response and return sensitive bytes in a zeroizing owner. + pub fn into_bytes(self) -> Option>> { self.bytes } + /// Explicitly erase and discard any sensitive response bytes. + pub fn clear_bytes(&mut self) { + self.bytes.take(); + } + fn encode(self) -> Result>, GuestCredentialBackendHandlerError> { #[derive(Serialize)] #[serde(rename_all = "camelCase")] @@ -704,12 +680,19 @@ impl GuestCredentialBackendReply { } } -impl std::fmt::Debug for GuestCredentialBackendReply { +impl std::fmt::Debug for GuestCredentialBackendResponse { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("GuestCredentialBackendReply()") + formatter.write_str("GuestCredentialBackendResponse()") } } +/// A non-secret or zeroizing response returned by one Guest backend operation. +/// +/// The responder and client halves share one shape: the responder encodes it +/// with [`GuestCredentialBackendResponse::encode`] and the client decodes the +/// same wire fields back into this type. +pub type GuestCredentialBackendReply = GuestCredentialBackendResponse; + /// Closed failures from a Guest backend responder handler. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GuestCredentialBackendHandlerError { From e5524be9c51ae45d290e85b66f579ecfa40d6d34 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:42:17 -0700 Subject: [PATCH 170/726] aca: move observed record instead of cloning in reconcile --- .../src/controller.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs index 382334eaf..d2aa041d0 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs @@ -497,8 +497,9 @@ where deadline_remaining_ms: u32, record: AcaSandboxRecord, ) -> Result { - self.observed = Some(record.clone()); - match record.lifecycle { + let lifecycle = record.lifecycle; + self.observed = Some(record); + match lifecycle { AcaSandboxLifecycle::Running => { match self .health(operation_id.clone(), deadline_remaining_ms) @@ -524,7 +525,7 @@ where } AcaSandboxLifecycle::Suspended | AcaSandboxLifecycle::Stopped => { self.phase = AcaPhase::Starting; - let id = record.id.clone(); + let id = self.observed.take().expect("stored above").id; let resumed = self .with_lease( operation_id.clone(), @@ -564,10 +565,10 @@ where } } AcaSandboxLifecycle::Creating | AcaSandboxLifecycle::Stopping => { - self.readiness_retry(record.lifecycle) + self.readiness_retry(lifecycle) } AcaSandboxLifecycle::Failed | AcaSandboxLifecycle::Unknown => { - self.readiness_retry(record.lifecycle) + self.readiness_retry(lifecycle) } } } From 9730af073c10686022a1922229f0bbe1311f4e41 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:42:20 -0700 Subject: [PATCH 171/726] aca: clone only the sandbox id for stop and delete effects --- .../src/controller.rs | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs index d2aa041d0..ae69ac9f7 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs @@ -413,17 +413,19 @@ where }; } if self.finalization_stage == AcaFinalizationStage::Stop { - let record = self + let record_id = self .observed - .clone() - .ok_or(AcaControllerError::SandboxUnavailable)?; + .as_ref() + .ok_or(AcaControllerError::SandboxUnavailable)? + .id + .clone(); let stopped = self .with_lease( operation_id.clone(), AcaCredentialPurpose::Stop, deadline_remaining_ms, move |control, lease, context| async move { - control.stop_sandbox(&lease, &context, &record.id).await + control.stop_sandbox(&lease, &context, &record_id).await }, ) .await?; @@ -465,11 +467,17 @@ where self.finalization_stage = AcaFinalizationStage::Stop; return Ok(()); } - let record = self + let record_id = self + .observed + .as_ref() + .ok_or(AcaControllerError::SandboxUnavailable)? + .id + .clone(); + if self .observed - .clone() - .ok_or(AcaControllerError::SandboxUnavailable)?; - if record.lifecycle == AcaSandboxLifecycle::Stopping { + .as_ref() + .is_some_and(|record| record.lifecycle == AcaSandboxLifecycle::Stopping) + { return Ok(()); } let outcome = self @@ -478,7 +486,7 @@ where AcaCredentialPurpose::Destroy, deadline_remaining_ms, move |control, lease, context| async move { - control.delete_sandbox(&lease, &context, &record.id).await + control.delete_sandbox(&lease, &context, &record_id).await }, ) .await?; From a0af15b8ca91a36c962e34c86440487a30909a98 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:43:30 -0700 Subject: [PATCH 172/726] zone-link: mutate bindings through borrows and document error contracts --- .../d2b-provider-zone-link/src/zone_links.rs | 53 +++++++++++++++++-- .../d2b-provider-zone-link/src/zonelink.rs | 24 +++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/packages/d2b-provider-zone-link/src/zone_links.rs b/packages/d2b-provider-zone-link/src/zone_links.rs index 8e3f60a97..f69b26da6 100644 --- a/packages/d2b-provider-zone-link/src/zone_links.rs +++ b/packages/d2b-provider-zone-link/src/zone_links.rs @@ -259,6 +259,11 @@ pub struct ZoneLinkLimits { impl ZoneLinkLimits { /// Validate one complete `spec.limits` object against its frozen bounds. + /// + /// # Errors + /// + /// Returns [`ZoneLinkError::InvalidLimits`] when a ceiling is zero or + /// exceeds its frozen bound. pub const fn new( max_pending_intents: u32, max_active_streams: u32, @@ -772,6 +777,11 @@ impl ZoneLinkRecord { /// /// The controller generation is also the ZoneLink identity generation, so /// a route binding from another controller generation is refused. + /// # Errors + /// + /// Returns [`ZoneLinkError::RouteAdmissionBindingInvalid`] when a + /// binding is already set or the binding's controller generation does + /// not match the record's. pub fn with_route_binding( mut self, binding: ZoneLinkRouteBinding, @@ -802,6 +812,14 @@ impl ZoneLinkRecord { /// The envelope is canonical, versioned, identity-bound, and bounded. /// There is no expiry or eviction because an OperationId remains /// non-reusable for the active ZoneLink identity and generation. + /// # Errors + /// + /// Returns [`ZoneLinkError::RouteAdmissionBindingInvalid`] when no + /// route binding is configured, + /// [`ZoneLinkError::RouteAdmissionOperationCapacity`] when the + /// committed set exceeds the bound, and + /// [`ZoneLinkError::RouteAdmissionDedupInvalid`] when the envelope + /// cannot be rendered canonically within the byte bound. pub fn encode_route_admission_dedup(&self) -> Result, ZoneLinkError> { let binding = self .route_binding @@ -835,6 +853,11 @@ impl ZoneLinkRecord { /// Identity mismatch and unknown versions are quarantine conditions. The /// receiver is consumed so a failed recovery cannot partially mutate a /// live record. + /// # Errors + /// + /// Returns [`ZoneLinkError::RouteAdmissionDedupInvalid`] when the + /// envelope is empty, over the byte bound, not canonical, or carries + /// an unknown version or identity mismatch. pub fn with_route_admission_dedup(mut self, encoded: &[u8]) -> Result { if encoded.is_empty() || encoded.len() > MAX_ROUTE_ADMISSION_DEDUP_BYTES { return Err(ZoneLinkError::RouteAdmissionDedupInvalid); @@ -1291,6 +1314,12 @@ impl ZoneLinkHandler { /// /// Exactly one pass may be open per link; a second call fails closed with /// [`ZoneLinkError::ReconcileInFlight`]. + /// + /// # Errors + /// + /// Returns [`ZoneLinkError::ReconcileInFlight`] when a pass is already + /// open and the planning refusal when the event is invalid for the + /// current record state. pub fn begin(&mut self, event: ZoneLinkEvent) -> Result { if self.pass_open { return Err(ZoneLinkError::ReconcileInFlight); @@ -1309,6 +1338,11 @@ impl ZoneLinkHandler { } /// Apply the planned durable mutation and issue its commit proof. + /// + /// # Errors + /// + /// Returns [`ZoneLinkError::StaleCommitProof`] when no pass is open or + /// the pass does not match the current owner token and sequence. pub fn commit(&mut self, pass: ZoneLinkPass) -> Result { if !self.pass_open || pass.owner_token != self.owner_token @@ -1331,6 +1365,12 @@ impl ZoneLinkHandler { } /// Consume one commit proof and release its effects exactly once. + /// + /// # Errors + /// + /// Returns [`ZoneLinkError::StaleCommitProof`] when no effects are + /// pending or the proof does not match the pending owner token and + /// sequence. pub fn release_effects( &mut self, proof: ZoneLinkCommitProof, @@ -1367,6 +1407,11 @@ impl ZoneLinkHandler { /// a context created from the committed record. It cannot supply identity, /// policy, connectivity, or time claims. The callback's implementation is /// expected to delegate directly to the runtime-owned sealed route issuer. + /// # Errors + /// + /// Returns the commit-proof refusal when the proof is stale, + /// [`ZoneLinkError::RouteAdmissionCursorUnavailable`] when the cursor + /// is not adopted, and the issuer's refusal otherwise. pub fn issue_route_admission( &mut self, mut proof: ZoneLinkCommitProof, @@ -1523,7 +1568,7 @@ impl ZoneLinkHandler { if state != ZoneLinkSessionState::Kk { return Err(ZoneLinkError::InvalidTransition); } - let Some(enrollment) = record.enrollment.clone() else { + let Some(enrollment) = record.enrollment.as_ref() else { return Err(ZoneLinkError::InvalidTransition); }; if enrollment.key_fingerprint != peer_key_fingerprint { @@ -1689,7 +1734,7 @@ impl ZoneLinkHandler { verb, policy_revision, } => { - let Some(mut binding) = record.route_binding.clone() else { + let Some(binding) = record.route_binding.as_mut() else { return Err(ZoneLinkError::RouteAdmissionBindingInvalid); }; if verb == OperationClass::Attach || policy_revision <= binding.policy_revision() { @@ -1698,12 +1743,11 @@ impl ZoneLinkHandler { binding.required_capability = required_capability; binding.verb = verb; binding.policy_revision = policy_revision; - record.route_binding = Some(binding); } ZoneLinkEvent::SessionGenerationAdvanced { reconnect_generation, } => { - let Some(mut binding) = record.route_binding.clone() else { + let Some(binding) = record.route_binding.as_mut() else { return Err(ZoneLinkError::RouteAdmissionBindingInvalid); }; if reconnect_generation <= binding.reconnect_generation() { @@ -1711,7 +1755,6 @@ impl ZoneLinkHandler { } let was_connected = record.connected; binding.reconnect_generation = reconnect_generation; - record.route_binding = Some(binding); record.connected = false; record.advertised_routes = 0; record.reconnect_attempts = 0; diff --git a/packages/d2b-provider-zone-link/src/zonelink.rs b/packages/d2b-provider-zone-link/src/zonelink.rs index 2ead8b450..dee21bebc 100644 --- a/packages/d2b-provider-zone-link/src/zonelink.rs +++ b/packages/d2b-provider-zone-link/src/zonelink.rs @@ -60,6 +60,11 @@ pub struct ZoneLinkOwnerProof { impl ZoneLinkOwnerProof { /// Bind a cursor owner to one authority generation and digest. + /// + /// # Errors + /// + /// Returns [`ZoneLinkAdoptionError::CursorInvalid`] when the authority + /// generation is zero. pub fn new( authority_generation: u64, owner_digest: SchemaFingerprint, @@ -74,6 +79,11 @@ impl ZoneLinkOwnerProof { } /// Build an owner proof from a canonical digest string. + /// + /// # Errors + /// + /// Returns [`ZoneLinkAdoptionError::CursorInvalid`] when the digest is + /// not a canonical fingerprint or the authority generation is zero. pub fn from_digest( authority_generation: u64, digest: impl Into, @@ -194,6 +204,15 @@ impl ZoneLinkCursorAuthority { /// More than one durable observation is ambiguous, even when observations /// happen to carry the same proof and cursor. The method never chooses a /// cursor by recency or map iteration order. + /// + /// # Errors + /// + /// Returns the [`ZoneLinkAdoption`] quarantine carrying + /// [`ZoneLinkAdoptionError::OwnerProofMissing`] when no observation + /// exists, [`ZoneLinkAdoptionError::OwnerProofMismatch`] when the + /// observation's proof differs, and + /// [`ZoneLinkAdoptionError::AmbiguousOwner`] when more than one + /// observation exists. pub fn adopt( &mut self, observations: impl IntoIterator, @@ -232,6 +251,11 @@ impl ZoneLinkCursorAuthority { } /// Borrow the adopted cursor or fail closed while quarantined. + /// + /// # Errors + /// + /// Returns the [`ZoneLinkAdoptionError`] recorded by the quarantine + /// when no cursor was adopted. pub fn cursor(&self) -> Result { self.adoption .record() From 70edbf366e406d66687dd83841cc76e5a3361843 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:44:09 -0700 Subject: [PATCH 173/726] audit: record wave-1 slice 7 Forty-one rows applied or varied across the audit crate, the broker composition, two contract crates, three providers, and the resource API; one claim is stale and one row needs a macro extension plus test updates, both recorded. --- .../2026-09-24-rust-skills-audit/ledger.md | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index e009466b5..d8082b8b7 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -38,9 +38,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0033` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | valid_hash deleted; call sites now use valid_digest | | | `RS-0034` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | nested verify_chain() shared by v1/v2 validation paths | | | `RS-0035` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | validate_fields(class, fields, fn) merged; thin wrappers keep both validators | | -| `RS-0001` | `idiom` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:255, packages/d2b-audit/src/segment.rs:980, packages/d2b-` | | | -| `RS-0002` | `idiom` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:103` | | | -| `RS-0003` | `idiom` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/sink.rs:393, packages/d2b-audit/src/sink.rs:403` | | | +| `RS-0001` | `idiom` | `d2b-audit` | medium | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/segment.rs` | One crate-private read_bounded_line(reader, truncated_code, limit_code) in segment.rs; both copies deleted; per-site codes kept. Deviation: truncated kind unified on InvalidData (segment was Other). | | +| `RS-0002` | `idiom` | `d2b-audit` | low | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/export.rs` | Redundant paths.retain block deleted; the push guard is the only is_segment_name filter. | | +| `RS-0003` | `idiom` | `d2b-audit` | low | actionable | leaf | applied-variant | U2 | fc707d752 | `packages/d2b-audit/src/sink.rs` | Inner if-let deleted; outer bindings used. Variant: tuple key cloned once for the durable_mutations insert (key is shadowed and moved); same allocation count, one fewer zone_operation_key derivation. | | | `RS-0011` | `idiom` | `d2b-broker` | medium | actionable | leaf | applied | U2 | c155578ca | `packages/d2b-broker/src/ops/device_worker.rs` | find_resource_row helper drives row_owner_ref/device_guest_owner/tpm_devices_of_guest | | | `RS-0006` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 99d7247ee | `packages/d2b-broker/src/runtime.rs` | parse_common_flags helper extracted; parse_probe_flags now takes Vec; error strings preserved | | | `RS-0007` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 99d7247ee | `packages/d2b-broker/src/runtime.rs` | push loop replaced with filter_map; foreign lock Err early return preserved; merged with RS-0006 in same commit | | @@ -48,13 +48,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0009` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 4234afe18 | `packages/d2b-broker/src/ops/exec_reconcile.rs` | seven hand-copied absolute-path checks factored into require_absolute; error wording normalized; no test asserts old strings | | | `RS-0010` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 5a2fa07c7 | `packages/d2b-broker/src/ops/store_view_farm.rs` | run_store_helper and store_helper_failure extracted; both namespaced builders share them | | | `RS-0012` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | open/publish/init_trusted_context_store gated #[cfg(test)]; only in-crate test callers existed; Drop persist path left ungated | | -| `RS-0004` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:136` | | | -| `RS-0005` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:270, packages/d2b-broker-composition/src/seam.` | | | +| `RS-0004` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | applied-variant | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | successors().take(4).find() chain. Variant: closure needs .map(Path::to_path_buf) since parent() returns Option<&Path>; the row's literal closure would not compile. | | +| `RS-0005` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | applied | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/seam.rs` | Parameter renamed _invocation; let _ = invocation; deleted. | | | `RS-0013` | `idiom` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | resolve_for_service uses filter_map+next() over collect-then-index; bus check+tests passed | | | `RS-0014` | `idiom` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/operations.rs` | abort_destination uses drain(..).partition and aborts drained handles; tests passed | | -| `RS-0015` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/kernel_client.rs:225-227` | | | -| `RS-0016` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broke` | | | -| `RS-0017` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/` | | | +| `RS-0015` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/kernel_client.rs` | if let Some(code) = response.refusal.clone() with Refused { code, detail }; one clone retained because response is moved into KernelReply afterwards. | | +| `RS-0016` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/host_generation.rs` | Never-firing !matches!(Lifecycle/Admin) guard deleted; InvalidTransition still used by the resource-type check. | | +| `RS-0017` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/broker_wire.rs` | for_display RootUid arm now d2b-root; pinned in the label test. Method label, not a serialized field; no committed JsonSchema carries it. Sibling d2b-broker bootstrap.rs twin out of packet scope. | | | `RS-0018` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential.rs` | derive(Default) with #[default] on RotationPolicyClass::OnExpiry and RevocationAction::Immediate; manual Default impls deleted | | | `RS-0020` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs` | producer_ref.transpose()? bound once; duplicate 15-field BindingChildIntent literal collapsed to one push, else-continue arm deleted | | | `RS-0019` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | manual Debug impl on UpgradePolicy replaced by #[derive(Debug)] | | @@ -67,7 +67,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0030` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | iter().any(f == last) replaced with slice contains for PUBLIC_MANIFEST_FIELDS and BROAD_CAPABILITIES | | | `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | applied-variant | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | row's bare-import removal broke tests using TapRole via use super::*; variant: import dropped, const deleted, 3 test sites qualified crate::host::TapRole (as _ import rejected by -D warnings) | | | `RS-0029` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | resolve_disk_init_ops flattened to vm.nodes.iter().flat_map(...).filter_map(...).collect() | | -| `RS-0026` | `idiom` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:2189-2192, authority.rs:2542-2545` | | | +| `RS-0026` | `idiom` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | Both duplicate-reservation checks are entry.holders.iter().any(...) predicates; let _ = holder; gone. | | | `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provid` | | | | `RS-0039` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:2812, src/policy.rs:12` | | | | `RS-0041` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboa` | | | @@ -93,32 +93,32 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/effects_service.rs:50-60, packages/d2b-provider-endpoin` | | | | `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/endpoint.rs:395-398` | | | | `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | derive(Default) with #[default] on BootstrapServiceState::Waiting; manual BootstrapService Default impl deleted | | -| `RS-0063` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `controller.rs:1712, controller.rs:1744` | | | -| `RS-0064` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `controller.rs:1722, controller.rs:1860, controller.rs:2042` | | | -| `RS-0065` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:487-494, shutdown.rs:666-673` | | | -| `RS-0066` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `bootstrap_graph.rs:131-139, bootstrap_graph.rs:417-422` | | | +| `RS-0063` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs` | _config field and initializer deleted; config.validate() kept in from_verified_descriptor. | | +| `RS-0064` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied-variant | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs` | Field deleted. Variant: its only read fed a write nobody read, so as a local it tripped -D warnings unused-assignments; dead tail and set sites deleted as dead state. | | +| `RS-0065` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs` | ChildRole::rank() added; deletion_rank/upgrade_rank free fns deleted; both sort sites call role.rank(). | | +| `RS-0066` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs` | readiness() wrapper deleted; test calls vmm_readiness with explicit booleans. Census confirmed only the two test assertions called it. | | | `RS-0067` | `idiom` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 7cb57d2fe | `packages/d2b-provider-guest-qemu-media/src/config.rs` | Default impls call default_qemu_artifact/default_vcpu/default_memory_mib/default_boot_media_view | | | `RS-0068` | `idiom` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/test_support.rs:185` | | | | `RS-0069` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Octets destructured via try_into and rendered with one format! | | | `RS-0070` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/driver.rs` | declared_dependency_refs is a filter_map pipeline over attachments | | -| `RS-0071` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:660-675` | | | -| `RS-0072` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/descriptor.rs:43-44, packages/d2b-provider-` | | | +| `RS-0071` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/controller.rs` | expected_acknowledgements collects the chained start/stop endpoint maps directly; conditional HostSink pushes kept. | | +| `RS-0072` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/descriptor.rs` | service_package() returns crate::SERVICE_PACKAGE; literal has one home. | | | `RS-0073` | `idiom` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-pro` | | | | `RS-0074` | `idiom` | `d2b-provider-seccomp-profile` | low | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-sec` | | | | `RS-0075` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/systemd.rs:840` | | | | `RS-0076` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor` | | | | `RS-0077` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | to_hex uses a const HEX table; dead unwrap_or fallback removed | | | `RS-0078` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | required_bindings is a free pub fn re-exported at root; Self:: call and two test sites updated | | -| `RS-0079` | `idiom` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:926-941, packages/d2b-provider-toolkit/src/` | | | -| `RS-0080` | `idiom` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:545-597, packages/d2b-provider-toolkit/src/` | | | +| `RS-0079` | `idiom` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/fd10.rs` | request() calls valid_guest_backend_operation(&operation); the inline 15-entry matches! deleted; single allowlist remains. | | +| `RS-0080` | `idiom` | `d2b-provider-toolkit` | low | actionable | leaf | applied-variant | U2 | c496e2214 | `packages/d2b-provider-toolkit/src/base/fd10.rs` | One struct carries the accessors plus new/with_sensitive_bytes/encode, keeping the zeroizing bytes field. Variant: GuestCredentialBackendReply kept as a type alias so consumers compile unchanged. | | | `RS-0081` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | RelaySecret derives Clone; hand-written impl deleted | | | `RS-0082` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 6fe6615af | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | Bearer header built from a literal instead of a collected char array | | | `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:221-224` | | | | `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:607-609` | | | | `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/status.rs:33-38` | | | | `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | -| `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, pa` | | | -| `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/manager_backend/tests.rs:1045, packages/d2b-resource-api/src` | | | +| `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | not-started | U2 | | `packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, pa` | 17 hand-written redaction Debug impls to redacted_debug! (or macro extension plus Debug-shape test updates); effort M; not started within this run. | | +| `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | | `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:914, packages/d2b-resource-client/src/proc` | | | | `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:194, packages/d2b-resource-client/src/zone` | | | | `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:` | | | @@ -160,13 +160,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0151` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | try_parse_from consumes raw_args by value (sole caller, never reused) | | | `RS-0152` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | host_error_envelope takes impl Into;;&format! results move in directly | | | `RS-0149` | `own` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/doctor.rs` | json! literal clones dropped (schema_version, issue_kinds, issues) | | -| `RS-0125` | `own` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/operation.rs:79` | | | +| `RS-0125` | `own` | `d2b-audit` | low | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/operation.rs` | AuditHash::parse(value) without to_owned; &str: Into holds. | | | `RS-0129` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | c3ac2bb59 | `packages/d2b-broker/src/ops/pidfd.rs` | redundant payload.argv.clone removed; impl param renamed _payload | | | `RS-0131` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | b09261be0 | `packages/d2b-broker/src/ops/media.rs` | unwrap_or_else(/_/ vec![record]) in enroll; merged with RS-0630 docs in same commit | | | `RS-0130` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | Bootstrap reply shrunk to Result<(),>; state.clone removal; merged with RS-0012/RS-0628 in same commit | | -| `RS-0126` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:251, packages/d2b-broker-composi` | | | -| `RS-0127` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:272` | | | -| `RS-0128` | `own` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:340, packages/d2b-broker-composi` | | | +| `RS-0126` | `own` | `d2b-broker-composition` | low | actionable | leaf | applied-variant | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | added consumed by value. Variant: a name in both lists still needs one clone, so a match on (forbidden, proc_macro) moves into one list and clones only in the both-true case. | | +| `RS-0127` | `own` | `d2b-broker-composition` | low | actionable | leaf | applied | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | contains(&crate_name.to_string()) replaced with iter().any(/name/ name == crate_name). | | +| `RS-0128` | `own` | `d2b-broker-composition` | low | actionable | leaf | applied | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | queue: Vec<&str> and seen: BTreeSet<&str>; ids borrowed from metadata; returned Vec untouched. | | | `RS-0132` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | ScopedCommitTransport::validate added; authorization_request validates borrowed data instead of cloning | | | `RS-0133` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/prologue.rs` | of_subject hashes &str slices via hash_resource_ref; digest byte-identical (full bus suite passed | | | `RS-0134` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/contract.rs` | private verify_body() shared by verify()/revalidate(); clone removed | | @@ -182,8 +182,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | 7be394a88 | `packages/d2b-contracts-zone-session/src/v3/services.rs` | BoundedText::parse takes method.as_str() instead of method.clone() | | | `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | path_bearing_key_violations renders through Cow; string arm borrows instead of cloning | | | `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | parse(value.as_str()) at 3 sites; network_uid compare via as_str; note: row rationale 'no allocation' inaccurate (Into still allocates) but explicit clones removed | | -| `RS-0145` | `own` | `d2b-core-controller` | low | actionable | leaf | | | | `owner_reconcile.rs:1072-1075` | | | -| `RS-0146` | `own` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:2803, authority.rs:2806` | | | +| `RS-0145` | `own` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/owner_reconcile.rs` | observed bound as &BTreeMap via ok_or(OwnerNotRelisted); .get/for-in/ordered_observed_refs/mutation_sort_parts take the borrow; whole-map clone removed. | | +| `RS-0146` | `own` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | claim computed from request.durable_claim() before the lock block; request moved into admit_authority_inner_with_operation; .clone() deleted. | | | `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/t` | | | | `RS-0154` | `own` | `d2b-provider` | low | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304` | | | | `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | | | @@ -208,8 +208,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0174` | `own` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 2e56bfa23 | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs` | execute destructures transport/commands, pushes the owned command, executes from commands.back() | | | `RS-0175` | `own` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266` | | | | `RS-0176` | `own` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Collision set stores &str borrowed from interface_names | | -| `RS-0177` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:1033, packages/d2b-provider-n` | | | -| `RS-0178` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/lifecycle.rs:338, packages/d2b-provider-not` | | | +| `RS-0177` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied-variant | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/controller.rs` | commit_reconciliation takes &SourceReconcileResult; both call-site .clone()s dropped. Variant: body iterates &result.stop and clones only endpoints inserted into active_sources. | | +| `RS-0178` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/lifecycle.rs` | backend: B stored directly; Arc import dropped; Send+Sync bounds kept via the trait bound. | | | `RS-0179` | `own` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285` | | | | `RS-0180` | `own` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1988, packages/d2b-provider-process/src/driver` | | | | `RS-0181` | `own` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/operations.rs:1354, packages/d2b-provider-process/src/op` | | | @@ -219,8 +219,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | | `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | | `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | | | -| `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/runtime.rs:530-537` | | | -| `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:771` | | | +| `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | is_ready_for_route compares through the guard via is_some_and(/ready/ ready.as_ref().is_some_and(/bound/ bound.liveness().is_live() && bound == route)); no clone. | | +| `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/shared_provider.rs` | sort_by with teardown_rank cmp then name cmp; no per-row String allocation. | | | `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | with_deadline consumes self and rebuilds with struct-update syntax; sole caller passes owned request | | | `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 72858f537 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs` | GatewayCredential stores material: GatewayCredentialMaterial moved in from_material; Drop impl deleted (material zeroizes); accessors and Debug unchanged | | | `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | applied-variant | U2 | 9ba7acf09 | `packages/d2b-provider-user/src/effects_service.rs` | Destructured InspectUserRequest and moved groups by value; username still cloned because inspect_user_response borrows it after UserSpec::new consumes it (stated fix was not implementable as written). | | @@ -229,8 +229,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/row_readers.rs` | Bounded the as_object_mut removal borrow in a block and moved spec into serde_json::from_value, dropping the Value::Object(object.clone()). | | | `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/sr` | | | | `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1526` | | | -| `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:425, client.rs:110, service.rs:852` | | | -| `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/admission.rs:338, packages/d2b-resource-api/src/admission.rs` | | | +| `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/client.rs` | scoped_commit_batch and commit_scoped_batch take &[ScopedResourceMutation]; commit_batch_with_scope takes Option<&[..]>; adapter passes transport.mutations() directly. | | +| `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/admission.rs` | mutations.into_iter().map(prepare_mutation); the redundant .cloned() removed. | | | `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | | | | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | | | | `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | | | | `packages/d2b-resource-compiler/src/linux.rs:93, packages/d2b-resource-compiler/src/linux.r` | | | | `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:1148, packages/d2b-resource-compiler/src/main.r` | | | @@ -657,7 +657,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0613` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:450` | | | | `RS-0659` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/exec_client.rs` | one-line docs for expect_start/expect_detached_create/list/logs/status/kill | | | `RS-0658` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/doctor.rs` | docs for doctor/validate/CLI surface incl. crate-level doc | | -| `RS-0614` | `docs` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:74, packages/d2b-audit/src/record_types.rs:428, packages/` | | | +| `RS-0614` | `docs` | `d2b-audit` | low | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/export.rs` | # Errors sections on 11 pub Result items; # Examples doctests on AuditRecord::new and SegmentWriter::open, both passing (cargo test --doc 2/2). | | | `RS-0624` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 93ced15b2 | `packages/d2b-broker/src/fd_passing.rs` | doc comments added per row | | | `RS-0630` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | b09261be0 | `packages/d2b-broker/src/ops/media.rs` | MediaOpError variants, outcome structs/fields, eight pub ops fns documented with # Errors | | | `RS-0625` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | d2096735c | `packages/d2b-broker/src/sys.rs` | doc comments added; merged with RS-0008/RS-0626 in same commit | | @@ -682,8 +682,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0635` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/router.rs` | docs for install body, authz error class, session-failure accessors, as_str wire labels | | | `RS-0636` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/router.rs` | # Errors on BusIngress::invoke, ZoneRegistrar::register_component_session,and BusEndpoint::invoke | | | `RS-0638` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/streams.rs` | # Errors on StreamName::parse, OperationId::parse, ZoneBoundPolicyIdentity::digest,and ZoneEndpointPolicy::lower | | -| `RS-0639` | `docs` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src` | | | -| `RS-0640` | `docs` | `d2b-contracts-broker` | low | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/br` | | | +| `RS-0639` | `docs` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/host_generation.rs` | # Errors sections on SourceGenerationCompatibilityFloorV1::new, begin_handoff, all five HandoffCoordinator transitions, RunnerLaunchArgs::new, envelope_invoke_kernel naming exact variants. | | +| `RS-0640` | `docs` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/broker_wire.rs` | FdKind/ForwardOperationRequest doc polish: missing space, CJK full-width periods, and comma-adjacent spacing fixed. | | | `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130` | Not applied: run budget exhausted before the contracts-control doc batch; cli_output.rs DTO docs remain | | | `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495` | Not applied: run budget exhausted; public_wire.rs docs and # Errors remain | | | `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wi` | Not applied: run budget exhausted; unsafe_local_wire.rs constant/type docs remain | | @@ -697,8 +697,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | | | | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | | | | `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/manifest_v04.rs` | module doc plus docs on ManifestV04/ManifestMeta/ObservabilityMeta/VmEntry/VmLifecycle/VmGracefulShutdown/VmLiveActivation/VmLanPolicy/VmObservability/VmShellMetadata/ManifestShellName; # Errors on fr | | | `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | one-line docs naming the exact BundleOpId shape added to all 15 undocumented intent_id_* constructors | | -| `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controlle` | | | -| `RS-0653` | `docs` | `d2b-core-controller` | low | actionable | leaf | | | | `migration.rs:54, migration.rs:58` | | | +| `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/main.rs` | One-line field docs added to RuntimeReadiness (4), RecoverySnapshot (5), HandlerStatus (9). | | +| `RS-0653` | `docs` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/migration.rs` | requires_migration and validates_binding documented. | | | `RS-0656` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/bridge_port.rs` | Added # Errors to validate_readback, parse_request, parse_validation_request, validate_media_ref, validate_usb_busid, and NftBatch::parse (the wire-boundary parsers the row names). | | | `RS-0657` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/cgroup.rs` | One-line docs added to Controller::REQUIRED, Controller::as_str, Controller::from_token (token grammar noted), BusId::new, HostPrepStepId::as_str. | | | `RS-0660` | `docs` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/` | | | @@ -734,10 +734,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/lib.rs:7, src/effects.rs:813-882` | budget stop before azure-container-apps crate | | | `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | | `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | matches() doc states the constant-time-in-presented-length guarantee | | -| `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `descriptor.rs:423-429, identity.rs:590-634` | | | +| `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs` | # Errors sections on GuestSetupDescriptor new/from_canonical_bytes/canonical_bytes/validate_integrity/verify_with, GuestChildBatch::from_descriptor, and the health evidence constructors. | | | `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U2 | 613491144 | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | # Errors added to DeviceAdmission::validate, QemuMediaController::reconcile, LaunchTicket::new, QmpSession::negotiate | | -| `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provide` | | | -| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | | | +| `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/action_nonce.rs` | # Errors sections on ActionNonceStore::register, NotificationRuntime::new, NotificationSink::deliver_from_guest_source naming exact variants. | | +| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | claim-stale | U2 | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | All three cited docs are complete standalone first sentences at baseline 6ebdd4cec (verified via git show) and HEAD; the lane quoted tail lines of multi-line docs. | | | `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `lib.rs:13, lib.rs:14, lib.rs:15` | | | | `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131` | | | | `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | applied | U2 | 4e381161f | `packages/d2b-provider-operation/src/operation.rs` | Added one-line # Errors naming OperationContractError variants to OperationAudit::new, AuditJoin::new, OperationFds::new, OperationBounds::new, OperationSpec::new. | | @@ -749,8 +749,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0705` | `docs` | `d2b-provider-seccomp-profile` | medium | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:31, packages/d2b-provider-sec` | | | | `RS-0706` | `docs` | `d2b-provider-shell-terminal` | medium | actionable | leaf | | | | `src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/` | | | | `RS-0707` | `docs` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | # Errors added to validate, HostProbeSnapshot::new, reconcile family, reject_operator_status_fields, UserReconciler::reconcile and both port methods | | -| `RS-0708` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/s` | | | -| `RS-0709` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolki` | | | +| `RS-0708` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | # Errors sections on ProviderEntrypoint::new, admit, the three with_* binders, StartupPlan::derive/declare naming their refusal variants. | | +| `RS-0709` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/testing/conformance.rs` | # Errors sections on check_descriptor_conformance, check_provider_conformance, operation_deadline, deadline_remaining, validate_attachment_indexes. | | | `RS-0710` | `docs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 33a84349d | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | # Errors added to mint_sas, build_connect, CreditWindow::new, RelayTransportSettings::new | | | `RS-0711` | `docs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U2 | 721c96f38 | `packages/d2b-provider-transport-unix/src/portal.rs` | Added # Errors naming PortalError variants to open, close, and observe. | | | `RS-0712` | `docs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsoc` | | | @@ -758,8 +758,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0714` | `docs` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92` | | | | `RS-0715` | `docs` | `d2b-provider-zone` | low | actionable | leaf | applied | U2 | 2170c0cac | `packages/d2b-provider-zone/src/zone_status.rs` | Added # Errors to SystemCoreStatusEmitter::emit naming the duplicate-handler and rejected-resource Contract conditions. | | | `RS-0716` | `docs` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src` | | | -| `RS-0718` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, pa` | | | -| `RS-0717` | `docs` | `d2b-resource-api` | medium | actionable | leaf | | | | `service.rs:198, store.rs:39, adapter.rs:71, manager_backend.rs:625` | | | +| `RS-0718` | `docs` | `d2b-resource-api` | medium | actionable | leaf | applied | U2 | 1f9a83aee | `packages/d2b-resource-api/src/authz.rs` | authorize documented with # Errors enumerating the nine AuthorizationDenial variants; one-line contracts on take_store_seal (with Errors), CompiledRole::new, CompiledRoleBinding::new, PolicySet::new. | | +| `RS-0717` | `docs` | `d2b-resource-api` | medium | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/service.rs` | # Errors sections on ResourceService::new/new_session_bound, the three frame helpers, manager_row_stored, admit_guest_lifecycle naming the failure classes. | | | `RS-0719` | `docs` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:` | | | | `RS-0720` | `docs` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | # Errors on all 14 ResourceManagerClient pub methods | | | `RS-0721` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | ResourceManagerArgs.store/providers documented | | From a8bc3bb0b7dab427f5f78700e2ab2b801e21e9a7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:44:42 -0700 Subject: [PATCH 174/726] xtask: embed emitted rust blocks as raw string literals Convert the escaped single-line literals in surface_catalog_source and the protobuf redaction templates to raw strings so the emitted code reads as code; emitted text is byte-identical (gen-layer-catalogs --check passes). --- packages/xtask/src/gen_layer_catalogs.rs | 66 ++++++++++++++++-------- packages/xtask/src/main.rs | 31 +++++------ 2 files changed, 60 insertions(+), 37 deletions(-) diff --git a/packages/xtask/src/gen_layer_catalogs.rs b/packages/xtask/src/gen_layer_catalogs.rs index 8c4c4bebd..d49cd1f8f 100644 --- a/packages/xtask/src/gen_layer_catalogs.rs +++ b/packages/xtask/src/gen_layer_catalogs.rs @@ -364,64 +364,84 @@ fn surface_catalog_source() -> String { "The resource type a typed noun addresses.", ])); source.push_str( - "pub fn typed_noun_type(noun: &str) -> Option<&'static str> {\n \ - TYPED_NOUNS\n .iter()\n \ - .find_map(|(name, resource_type)| (*name == noun).then_some(*resource_type))\n}\n", + r##"pub fn typed_noun_type(noun: &str) -> Option<&'static str> { + TYPED_NOUNS + .iter() + .find_map(|(name, resource_type)| (*name == noun).then_some(*resource_type)) +} +"##, ); source.push_str(&doc_lines(&[ "The resource type a typed verb is available on.", ])); source.push_str( - "pub fn typed_verb_type(verb: &str) -> Option<&'static str> {\n \ - TYPED_VERB_TYPES\n .iter()\n \ - .find_map(|(name, resource_type)| (*name == verb).then_some(*resource_type))\n}\n", + r##"pub fn typed_verb_type(verb: &str) -> Option<&'static str> { + TYPED_VERB_TYPES + .iter() + .find_map(|(name, resource_type)| (*name == verb).then_some(*resource_type)) +} +"##, ); source.push_str(&doc_lines(&[ "Whether the resource type is in the registry.", ])); source.push_str( - "pub fn admits_resource_type(resource_type: &str) -> bool {\n \ - RESOURCE_TYPES.contains(&resource_type)\n}\n", + r##"pub fn admits_resource_type(resource_type: &str) -> bool { + RESOURCE_TYPES.contains(&resource_type) +} +"##, ); source.push_str(&doc_lines(&["Whether the verb writes a resource row."])); source.push_str( - "pub fn admits_mutation_verb(verb: &str) -> bool {\n \ - MUTATION_VERBS.contains(&verb)\n}\n", + r##"pub fn admits_mutation_verb(verb: &str) -> bool { + MUTATION_VERBS.contains(&verb) +} +"##, ); source.push_str(&doc_lines(&[ "Whether the resource type is one the controller owns.", ])); source.push_str( - "pub fn is_controller_owned(resource_type: &str) -> bool {\n \ - CONTROLLER_OWNED_TYPES.contains(&resource_type)\n}\n", + r##"pub fn is_controller_owned(resource_type: &str) -> bool { + CONTROLLER_OWNED_TYPES.contains(&resource_type) +} +"##, ); source.push_str(&doc_lines(&[ "Whether the resource type serves as an execution target.", ])); source.push_str( - "pub fn is_execution_target(resource_type: &str) -> bool {\n \ - EXECUTION_TARGET_TYPES.contains(&resource_type)\n}\n", + r##"pub fn is_execution_target(resource_type: &str) -> bool { + EXECUTION_TARGET_TYPES.contains(&resource_type) +} +"##, ); source.push_str(&doc_lines(&[ "Whether the posture marks a row with no isolation boundary.", ])); source.push_str( - "pub fn is_no_isolation_posture(posture: &str) -> bool {\n \ - NO_ISOLATION_POSTURES.contains(&posture)\n}\n", + r##"pub fn is_no_isolation_posture(posture: &str) -> bool { + NO_ISOLATION_POSTURES.contains(&posture) +} +"##, ); source.push_str(&doc_lines(&[ "Whether the provider reference marks a no-isolation row.", ])); source.push_str( - "pub fn is_unsafe_local_provider(reference: &str) -> bool {\n \ - reference == UNSAFE_LOCAL_PROVIDER_REF\n}\n", + r##"pub fn is_unsafe_local_provider(reference: &str) -> bool { + reference == UNSAFE_LOCAL_PROVIDER_REF +} +"##, ); source.push_str(&doc_lines(&[ "Whether the provider kind marks a no-isolation row.", ])); source.push_str( - "pub fn is_unsafe_local_provider_kind(kind: &str) -> bool {\n \ - kind == UNSAFE_LOCAL_PROVIDER_KIND\n}\n", + r##"pub fn is_unsafe_local_provider_kind(kind: &str) -> bool { + kind == UNSAFE_LOCAL_PROVIDER_KIND +} +"##, ); source.push_str(&string_slice( "NO_ISOLATION_TARGET_TYPES", @@ -435,8 +455,10 @@ fn surface_catalog_source() -> String { "Whether the execution target runs without an isolation boundary.", ])); source.push_str( - "pub fn is_no_isolation_target(resource_type: &str) -> bool {\n \ - NO_ISOLATION_TARGET_TYPES.contains(&resource_type)\n}\n", + r##"pub fn is_no_isolation_target(resource_type: &str) -> bool { + NO_ISOLATION_TARGET_TYPES.contains(&resource_type) +} +"##, ); source } diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index fa7aa972f..4058ada1a 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -490,23 +490,24 @@ fn redact_generated_protobuf_formatting(path: &Path) -> Result<(), Box) -> ::std::fmt::Result {{\n\ - \x20 ::protobuf::text_format::fmt(self, f)\n\ - \x20 }}\n\ - }}" + r##"impl ::std::fmt::Display for {message_name} {{ + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{ + ::protobuf::text_format::fmt(self, f) + }} +}}"## ); let redacted_formatting = format!( - "impl ::std::fmt::Debug for {message_name} {{\n\ - \x20 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{\n\ - \x20 f.write_str(\"{message_name}()\")\n\ - \x20 }}\n\ - }}\n\n\ - impl ::std::fmt::Display for {message_name} {{\n\ - \x20 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{\n\ - \x20 f.write_str(\"{message_name}()\")\n\ - \x20 }}\n\ - }}" + r##"impl ::std::fmt::Debug for {message_name} {{ + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{ + f.write_str("{message_name}()") + }} +}} + +impl ::std::fmt::Display for {message_name} {{ + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {{ + f.write_str("{message_name}()") + }} +}}"## ); if !generated.contains(&raw_display) { return Err(format!( From 8a45d2d37feb0113053b4e29f24fba939e11512e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:45:18 -0700 Subject: [PATCH 175/726] aca: document effects module public surface --- .../src/effects.rs | 203 ++++++++++++++++++ .../src/lib.rs | 1 - 2 files changed, 203 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs index dcf126529..602237dcc 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs @@ -8,21 +8,37 @@ use serde::{Deserialize, Deserializer, Serialize}; pub use d2b_contracts_provider::v3::credential::{CredentialLeaseHandle, OpaqueAzureRef}; pub use d2b_contracts_resource::v3::{ResourceRef, ResourceUid}; +/// Maximum length of an ACA resource identifier. pub const MAX_ACA_RESOURCE_ID_LEN: usize = 60; +/// Maximum number of sandbox or disk image candidates accepted from a control plane query. pub const MAX_ACA_CANDIDATES: usize = 8; +/// Maximum readiness attempts before a sandbox generation is marked failed. pub const MAX_ACA_READY_ATTEMPTS: u8 = 60; +/// Maximum readiness probe interval in milliseconds. pub const MAX_ACA_READY_INTERVAL_MS: u32 = 10_000; +/// Maximum plan time-to-live in milliseconds. pub const MAX_ACA_PLAN_TTL_MS: u32 = 300_000; +/// Maximum completed operations retained by the ledger. pub const MAX_ACA_COMPLETED_OPERATIONS: usize = 1_024; +/// Errors produced by validated ACA type constructors. +/// +/// Each variant renders as a stable error code via `Display`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AcaTypeError { + /// The identifier violates the opaque-id character or length rules. InvalidIdentifier, + /// A CPU or memory bound falls outside the validated range. InvalidResourceBounds, + /// The readiness policy violates the attempt or interval bounds. InvalidReadinessPolicy, + /// The plan TTL is zero or exceeds [`MAX_ACA_PLAN_TTL_MS`]. InvalidPlanTtl, + /// The completed-operation capacity is zero or exceeds [`MAX_ACA_COMPLETED_OPERATIONS`]. InvalidOperationCapacity, + /// The candidate list exceeds [`MAX_ACA_CANDIDATES`]. CandidateBoundExceeded, + /// A reference points at a resource type outside the execution boundary. InvalidExecutionBoundary, } @@ -53,11 +69,18 @@ fn valid_opaque_id(value: &str, max: usize, lowercase_lead: bool) -> bool { macro_rules! opaque_id { ($name:ident, $max:expr, $lowercase_lead:expr) => { + /// Opaque identifier validated against the ACA character rules. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] pub struct $name(String); impl $name { + /// Parse and validate an opaque identifier. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidIdentifier`] when the value is empty, + /// exceeds the length bound, or contains a disallowed character. pub fn parse(value: impl Into) -> Result { let value = value.into(); if valid_opaque_id(&value, $max, $lowercase_lead) { @@ -67,6 +90,7 @@ macro_rules! opaque_id { } } + /// Borrow the validated identifier text. pub fn as_str(&self) -> &str { &self.0 } @@ -100,9 +124,16 @@ opaque_id!(AcaOperationId, 96, true); #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", try_from = "u16")] +/// CPU allocation in millicores, validated to the 250..=4_000 range in 250 increments. pub struct AcaCpuMillis(u16); impl AcaCpuMillis { + /// Construct validated CPU millicores. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidResourceBounds`] when `value` is outside + /// 250..=4_000 or not a multiple of 250. pub fn new(value: u16) -> Result { if (250..=4_000).contains(&value) && value.is_multiple_of(250) { Ok(Self(value)) @@ -122,9 +153,16 @@ impl AcaCpuMillis { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", try_from = "u32")] +/// Memory allocation in MiB, validated to the 512..=16_384 range in 256 increments. pub struct AcaMemoryMib(u32); impl AcaMemoryMib { + /// Construct validated memory MiB. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidResourceBounds`] when `value` is outside + /// 512..=16_384 or not a multiple of 256. pub fn new(value: u32) -> Result { if (512..=16_384).contains(&value) && value.is_multiple_of(256) { Ok(Self(value)) @@ -144,13 +182,20 @@ impl AcaMemoryMib { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Source of a disk image: a configured disk or a configured container image. pub enum AcaDiskImageSource { + /// A pre-configured disk binding. ConfiguredDisk { + /// The configured disk binding id. binding_id: AcaConfiguredDiskId, }, + /// A container image pulled by an optional managed identity. ConfiguredContainerImage { + /// The image binding id. image_binding_id: AcaConfiguredImageId, + /// The disk name the image is materialized as. disk_name: AcaDiskImageName, + /// The managed identity used for the pull, when one is configured. pull_identity_binding_id: Option, }, } @@ -168,6 +213,7 @@ impl fmt::Debug for AcaDiskImageSource { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", try_from = "RawAcaSandboxProfile")] +/// Validated sandbox profile: identity, disk image, CPU, memory, and suspend policy. pub struct AcaSandboxProfile { profile_id: AcaProfileId, disk_image: AcaDiskImageSource, @@ -179,6 +225,12 @@ pub struct AcaSandboxProfile { impl AcaSandboxProfile { #[allow(clippy::too_many_arguments)] + /// Construct a validated sandbox profile. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidResourceBounds`] when `auto_suspend_secs` + /// is outside 60..=86_400. pub fn new( profile_id: AcaProfileId, disk_image: AcaDiskImageSource, @@ -200,10 +252,12 @@ impl AcaSandboxProfile { }) } + /// Borrow the profile id. pub fn profile_id(&self) -> &AcaProfileId { &self.profile_id } + /// Borrow the disk image source. pub fn disk_image(&self) -> &AcaDiskImageSource { &self.disk_image } @@ -259,6 +313,7 @@ impl fmt::Debug for AcaSandboxProfile { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", try_from = "RawAcaReadinessPolicy")] +/// Validated readiness policy: bounded attempts and probe interval. pub struct AcaReadinessPolicy { attempts: u8, interval_ms: u32, @@ -280,6 +335,13 @@ impl TryFrom for AcaReadinessPolicy { } impl AcaReadinessPolicy { + /// Construct a validated readiness policy. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidReadinessPolicy`] when `attempts` or + /// `interval_ms` is zero or exceeds the [`MAX_ACA_READY_ATTEMPTS`] / + /// [`MAX_ACA_READY_INTERVAL_MS`] bounds. pub fn new(attempts: u8, interval_ms: u32) -> Result { if attempts == 0 || attempts > MAX_ACA_READY_ATTEMPTS @@ -294,10 +356,12 @@ impl AcaReadinessPolicy { }) } + /// Return the readiness attempt bound. pub const fn attempts(self) -> u8 { self.attempts } + /// Return the readiness probe interval in milliseconds. pub const fn interval_ms(self) -> u32 { self.interval_ms } @@ -305,6 +369,7 @@ impl AcaReadinessPolicy { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", try_from = "RawAcaRuntimeConfig")] +/// Validated runtime configuration: profile, readiness, plan TTL, and ledger capacity. pub struct AcaRuntimeConfig { profile: AcaSandboxProfile, readiness: AcaReadinessPolicy, @@ -335,6 +400,14 @@ impl TryFrom for AcaRuntimeConfig { } impl AcaRuntimeConfig { + /// Construct a validated runtime configuration. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidPlanTtl`] when `plan_ttl_ms` is zero or + /// exceeds [`MAX_ACA_PLAN_TTL_MS`], and [`AcaTypeError::InvalidOperationCapacity`] + /// when `completed_operation_capacity` is zero or exceeds + /// [`MAX_ACA_COMPLETED_OPERATIONS`]. pub fn new( profile: AcaSandboxProfile, readiness: AcaReadinessPolicy, @@ -357,18 +430,22 @@ impl AcaRuntimeConfig { }) } + /// Borrow the sandbox profile. pub fn profile(&self) -> &AcaSandboxProfile { &self.profile } + /// Return the readiness policy. pub const fn readiness(&self) -> AcaReadinessPolicy { self.readiness } + /// Return the plan time-to-live in milliseconds. pub const fn plan_ttl_ms(&self) -> u32 { self.plan_ttl_ms } + /// Return the completed-operation ledger capacity. pub const fn completed_operation_capacity(&self) -> usize { self.completed_operation_capacity } @@ -391,21 +468,40 @@ impl fmt::Debug for AcaRuntimeConfig { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", try_from = "RawAcaProviderConfig")] +/// Validated Provider configuration for the runtime-azure-container-apps provider. pub struct AcaProviderConfig { + /// Reference to the Guest execution boundary this provider serves. pub gateway_execution_ref: ResourceRef, + /// Azure tenant id. pub tenant_id: OpaqueAzureRef, + /// Azure client id. pub client_id: OpaqueAzureRef, + /// Azure subscription id. pub subscription_id: OpaqueAzureRef, + /// Reference to the credential used to acquire control-plane leases. pub control_credential_ref: ResourceRef, + /// Reference to the credential used to pull sandbox images, when configured. pub pull_credential_ref: Option, + /// Configured container-apps environment id. pub environment_id: AcaConfiguredImageId, + /// Configured resource group id. pub resource_group_id: AcaConfiguredImageId, + /// Reference to the network the sandbox joins, when configured. pub network_ref: Option, + /// Profile alias used for the sandbox transport. pub sandbox_transport_alias: AcaProfileId, + /// Runtime defaults applied to every controller created from this config. pub defaults: AcaRuntimeConfig, } impl AcaProviderConfig { + /// Construct a validated Provider configuration. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidExecutionBoundary`] when a reference + /// points outside the execution boundary (Guest gateway, Credential + /// control, optional Credential pull, optional Network). #[allow(clippy::too_many_arguments)] pub fn new( gateway_execution_ref: ResourceRef, @@ -442,6 +538,11 @@ impl AcaProviderConfig { } /// Revalidate a Provider configuration at the admission boundary. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::InvalidExecutionBoundary`] when a reference + /// points outside the execution boundary. pub fn validate(&self) -> Result<(), AcaTypeError> { Self::validate_refs( &self.gateway_execution_ref, @@ -533,35 +634,53 @@ impl fmt::Debug for AcaProviderConfig { } #[derive(Debug, Clone, PartialEq, Eq)] +/// Identity of the Guest resource a controller reconciles. pub struct AcaResourceBinding { + /// The Guest resource uid. pub guest_uid: ResourceUid, + /// The provider generation the binding was created for. pub provider_generation: u64, + /// Fingerprint of the config the binding was created from. pub config_fingerprint: [u8; 32], } #[derive(Debug, Clone, PartialEq, Eq)] +/// Query describing which sandboxes belong to a Guest. pub struct AcaWorkloadQuery { + /// The Guest binding the query scopes to. pub binding: AcaResourceBinding, + /// The profile alias the sandbox must carry. pub profile_id: AcaProfileId, } #[derive(Debug, Clone, PartialEq, Eq)] +/// Desired disk image for a sandbox. pub struct AcaDesiredDiskImage { + /// The image source. pub source: AcaDiskImageSource, } #[derive(Debug, Clone, PartialEq, Eq)] +/// Desired sandbox state passed to the create effect. pub struct AcaDesiredSandbox { + /// The Guest binding the sandbox belongs to. pub binding: AcaResourceBinding, + /// The validated profile to apply. pub profile: AcaSandboxProfile, + /// The disk image record the sandbox boots from. pub disk_image: AcaDiskImageRecord, + /// The network to join, when configured. pub network_ref: Option, + /// The sandbox transport profile alias. pub sandbox_transport_alias: AcaProfileId, } #[derive(Clone, PartialEq, Eq)] +/// Observed disk image identity and generation. pub struct AcaDiskImageRecord { + /// The disk image id. pub id: AcaDiskImageId, + /// The generation the image was created for. pub generation: u64, } @@ -576,9 +695,16 @@ impl fmt::Debug for AcaDiskImageRecord { } #[derive(Debug, Clone, PartialEq, Eq)] +/// Bounded candidate list of disk images returned by a control plane query. pub struct AcaDiskImageCandidates(Vec); impl AcaDiskImageCandidates { + /// Construct a bounded candidate list. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::CandidateBoundExceeded`] when `records` is + /// longer than [`MAX_ACA_CANDIDATES`]. pub fn new(records: Vec) -> Result { if records.len() > MAX_ACA_CANDIDATES { return Err(AcaTypeError::CandidateBoundExceeded); @@ -586,6 +712,7 @@ impl AcaDiskImageCandidates { Ok(Self(records)) } + /// Borrow the candidate records. pub fn as_slice(&self) -> &[AcaDiskImageRecord] { &self.0 } @@ -602,20 +729,32 @@ impl IntoIterator for AcaDiskImageCandidates { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Observed lifecycle of an ACA sandbox. pub enum AcaSandboxLifecycle { + /// The sandbox is being created. Creating, + /// The sandbox is running. Running, + /// The sandbox is suspended. Suspended, + /// The sandbox is stopping. Stopping, + /// The sandbox is stopped. Stopped, + /// The sandbox failed. Failed, + /// The lifecycle could not be determined. Unknown, } #[derive(Clone, PartialEq, Eq)] +/// Observed sandbox state returned by control plane effects. pub struct AcaSandboxRecord { + /// The sandbox id. pub id: AcaSandboxId, + /// The observed lifecycle. pub lifecycle: AcaSandboxLifecycle, + /// The generation the sandbox was created for. pub generation: u64, } @@ -631,9 +770,16 @@ impl fmt::Debug for AcaSandboxRecord { } #[derive(Debug, Clone, PartialEq, Eq)] +/// Bounded candidate list of sandboxes returned by a control plane query. pub struct AcaSandboxCandidates(Vec); impl AcaSandboxCandidates { + /// Construct a bounded candidate list. + /// + /// # Errors + /// + /// Returns [`AcaTypeError::CandidateBoundExceeded`] when `records` is + /// longer than [`MAX_ACA_CANDIDATES`]. pub fn new(records: Vec) -> Result { if records.len() > MAX_ACA_CANDIDATES { return Err(AcaTypeError::CandidateBoundExceeded); @@ -641,6 +787,7 @@ impl AcaSandboxCandidates { Ok(Self(records)) } + /// Borrow the candidate records. pub fn as_slice(&self) -> &[AcaSandboxRecord] { &self.0 } @@ -656,31 +803,44 @@ impl IntoIterator for AcaSandboxCandidates { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Outcome of a delete effect. pub enum AcaDeleteOutcome { + /// The sandbox was deleted. Deleted, + /// The sandbox was already absent. AlreadyAbsent, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Purpose of a credential lease; drives lease acquisition policy. pub enum AcaCredentialPurpose { + /// Health probe. Health, + /// Sandbox or disk image ensure. Ensure, + /// Sandbox resume. Start, + /// Sandbox stop. Stop, + /// Sandbox inspection. Inspect, + /// Sandbox adoption. Adopt, + /// Sandbox destroy. Destroy, } #[derive(Clone, PartialEq, Eq)] +/// A lease on the control-plane credential, valid until an absolute expiry. pub struct AcaCredentialLease { metadata: CredentialLeaseHandle, expires_at_unix_ms: u64, } impl AcaCredentialLease { + /// Construct a lease from credential metadata and an absolute expiry. pub fn from_metadata(metadata: CredentialLeaseHandle, expires_at_unix_ms: u64) -> Self { Self { metadata, @@ -688,6 +848,7 @@ impl AcaCredentialLease { } } + /// Return the absolute lease expiry in unix milliseconds. pub const fn expires_at_unix_ms(&self) -> u64 { self.expires_at_unix_ms } @@ -704,6 +865,7 @@ impl fmt::Debug for AcaCredentialLease { } #[derive(Clone, PartialEq, Eq)] +/// Request for a credential lease with a requested absolute expiry. pub struct AcaCredentialLeaseRequest { operation_id: AcaOperationId, purpose: AcaCredentialPurpose, @@ -711,6 +873,7 @@ pub struct AcaCredentialLeaseRequest { } impl AcaCredentialLeaseRequest { + /// Construct a lease request. pub fn new( operation_id: AcaOperationId, purpose: AcaCredentialPurpose, @@ -723,6 +886,7 @@ impl AcaCredentialLeaseRequest { } } + /// Return the requested expiry in unix milliseconds. pub const fn requested_expiry_unix_ms(&self) -> u64 { self.requested_expiry_unix_ms } @@ -740,12 +904,14 @@ impl fmt::Debug for AcaCredentialLeaseRequest { } #[derive(Clone, PartialEq, Eq)] +/// Context passed to every control effect call. pub struct AcaControlContext { operation_id: AcaOperationId, deadline_remaining_ms: u32, } impl AcaControlContext { + /// Construct a control context for one operation. pub fn new(operation_id: AcaOperationId, deadline_remaining_ms: u32) -> Self { Self { operation_id, @@ -766,27 +932,43 @@ impl fmt::Debug for AcaControlContext { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Health of the ACA control plane for one sandbox. pub enum AcaControlHealth { + /// The sandbox is ready. Ready, + /// The sandbox is degraded. Degraded, + /// The sandbox is unavailable. Unavailable, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Kind of failure returned by a control effect. pub enum AcaControlErrorKind { + /// Authentication with the control plane failed. Authentication, + /// Authorization was denied. Authorization, + /// The control plane rate-limited the call. RateLimited, + /// The control plane is unavailable. Unavailable, + /// The call conflicted with concurrent state. Conflict, + /// The addressed resource was not found. NotFound, + /// The control plane returned an invalid response. InvalidResponse, + /// The call was cancelled. Cancelled, + /// The operation deadline expired. DeadlineExpired, + /// The result was ambiguous. Ambiguous, } impl AcaControlErrorKind { + /// Return the stable error code for this kind. pub const fn code(self) -> &'static str { match self { Self::Authentication => "aca-control-authentication", @@ -802,25 +984,30 @@ impl AcaControlErrorKind { } } + /// Return whether a retry may succeed. pub const fn retryable(self) -> bool { matches!(self, Self::RateLimited | Self::Unavailable) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Error returned by a control effect, carrying a stable code. pub struct AcaControlError { kind: AcaControlErrorKind, } impl AcaControlError { + /// Construct a control error from a kind. pub const fn new(kind: AcaControlErrorKind) -> Self { Self { kind } } + /// Return the error kind. pub const fn kind(self) -> AcaControlErrorKind { self.kind } + /// Return the stable error code. pub const fn code(self) -> &'static str { self.kind.code() } @@ -834,24 +1021,34 @@ impl fmt::Display for AcaControlError { impl std::error::Error for AcaControlError {} +/// Client for acquiring and revoking credential leases. +/// +/// Both methods return [`AcaControlError`] when the lease operation fails. #[async_trait] pub trait AcaCredentialLeaseClient: Send + Sync { + /// Acquire a credential lease for one operation. async fn acquire( &self, request: &AcaCredentialLeaseRequest, ) -> Result; + /// Revoke a previously acquired credential lease. async fn revoke(&self, lease: &AcaCredentialLease) -> Result<(), AcaControlError>; } +/// Effect port for the Azure Container Apps control plane. +/// +/// Every method returns [`AcaControlError`] when the control plane call fails. #[async_trait] pub trait AcaControl: Send + Sync { + /// Probe sandbox health. async fn health( &self, lease: &AcaCredentialLease, context: &AcaControlContext, ) -> Result; + /// List sandbox candidates matching a workload query. async fn find_sandboxes( &self, lease: &AcaCredentialLease, @@ -859,6 +1056,7 @@ pub trait AcaControl: Send + Sync { query: &AcaWorkloadQuery, ) -> Result; + /// List disk image candidates matching a desired image. async fn find_disk_images( &self, lease: &AcaCredentialLease, @@ -866,6 +1064,7 @@ pub trait AcaControl: Send + Sync { desired: &AcaDesiredDiskImage, ) -> Result; + /// Create a disk image for a desired image. async fn create_disk_image( &self, lease: &AcaCredentialLease, @@ -873,6 +1072,7 @@ pub trait AcaControl: Send + Sync { desired: &AcaDesiredDiskImage, ) -> Result; + /// Create a sandbox from a desired state. async fn create_sandbox( &self, lease: &AcaCredentialLease, @@ -880,6 +1080,7 @@ pub trait AcaControl: Send + Sync { desired: &AcaDesiredSandbox, ) -> Result; + /// Resume a suspended or stopped sandbox. async fn resume_sandbox( &self, lease: &AcaCredentialLease, @@ -887,6 +1088,7 @@ pub trait AcaControl: Send + Sync { sandbox_id: &AcaSandboxId, ) -> Result; + /// Stop a running sandbox. async fn stop_sandbox( &self, lease: &AcaCredentialLease, @@ -894,6 +1096,7 @@ pub trait AcaControl: Send + Sync { sandbox_id: &AcaSandboxId, ) -> Result; + /// Delete a sandbox. async fn delete_sandbox( &self, lease: &AcaCredentialLease, diff --git a/packages/d2b-provider-guest-azure-container-apps/src/lib.rs b/packages/d2b-provider-guest-azure-container-apps/src/lib.rs index 3d213d39b..dc793a4a2 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/lib.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/lib.rs @@ -4,7 +4,6 @@ #![forbid(unsafe_code)] mod controller; -#[allow(missing_docs)] mod effects; pub use controller::{ From 2329f6aa2643755038d2058bbd134be2bd0ad24d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:45:25 -0700 Subject: [PATCH 176/726] docs(d2b-contracts-control): document the CLI-output DTOs --- .../d2b-contracts-control/src/cli_output.rs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/packages/d2b-contracts-control/src/cli_output.rs b/packages/d2b-contracts-control/src/cli_output.rs index 922e9835e..7226a56c9 100644 --- a/packages/d2b-contracts-control/src/cli_output.rs +++ b/packages/d2b-contracts-control/src/cli_output.rs @@ -7,10 +7,12 @@ pub use d2b_contracts::audio::LevelPercent; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(transparent)] +/// `d2b vm list` output: one row per VM. pub struct ListOutputV2(pub Vec); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One `d2b vm list` row. pub struct ListItemOutputV2 { pub name: String, pub env: Option, @@ -46,6 +48,7 @@ pub struct ListItemOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `usb probe` output: the command echo plus one entry per probed device. pub struct UsbProbeOutputV1 { pub command: String, pub entries: Vec, @@ -53,6 +56,7 @@ pub struct UsbProbeOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `realm list` output: one policy summary per realm. pub struct RealmListOutputV1 { pub command: String, pub realms: Vec, @@ -60,6 +64,7 @@ pub struct RealmListOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase")] +/// `realm inspect` output: the flattened policy summary of one realm. pub struct RealmInspectOutputV1 { pub command: String, #[serde(flatten)] @@ -68,6 +73,7 @@ pub struct RealmInspectOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `op inspect` output: trace, local, and per-realm views. pub struct OpInspectOutputV1 { pub command: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -79,6 +85,7 @@ pub struct OpInspectOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Trace identifiers for one `op inspect` run. pub struct OpInspectTraceOutputV1 { pub trace_id: String, pub span_id: String, @@ -86,6 +93,7 @@ pub struct OpInspectTraceOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Local counts and source for one `op inspect` run. pub struct OpInspectLocalOutputV1 { pub vm_count: u32, pub gateway_count: u32, @@ -94,6 +102,7 @@ pub struct OpInspectLocalOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One realm's view in `op inspect` output. pub struct OpInspectRealmOutputV1 { pub realm: String, pub mode: String, @@ -105,6 +114,7 @@ pub struct OpInspectRealmOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One degraded scope in `op inspect` output. pub struct OpInspectDegradedOutputV1 { pub scope: String, pub reason: String, @@ -113,6 +123,7 @@ pub struct OpInspectDegradedOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One realm's policy summary, shared by list and inspect output. pub struct RealmPolicyOutputV1 { pub realm: String, pub mode: String, @@ -127,14 +138,19 @@ pub struct RealmPolicyOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(untagged)] +/// `d2b status` output: one of the VM, inventory, or bridge-check shapes. pub enum StatusOutputV2 { + /// Per-VM status. Vm(Box), + /// Whole-inventory status. Inventory(Box), + /// Bridge isolation check status. CheckBridges(Box), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `d2b status --inventory` output: runtime plus one row per VM. pub struct StatusInventoryOutputV2 { pub runtime: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -144,27 +160,36 @@ pub struct StatusInventoryOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(untagged)] +/// api-ready state of the last VM start in split mode. pub enum ApiReadyStatusV1 { + /// A simple closed state. Simple(ApiReadySimple), + /// A terminal error state. WithError(ApiReadyErrorV1), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] +/// The error text of a failed api-ready wait. pub struct ApiReadyErrorV1 { pub error: String, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] +/// Closed api-ready states without an error payload. pub enum ApiReadySimple { + /// The API became ready. Yes, + /// The API is still starting. Pending, + /// The wait timed out. Timeout, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One VM's status row. pub struct StatusVmOutputV2 { pub name: String, pub env: Option, @@ -206,6 +231,7 @@ pub struct StatusVmOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Live-pool integrity verdict for one VM. pub struct LivePoolIntegrityOutputV1 { pub status: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -219,6 +245,7 @@ pub struct LivePoolIntegrityOutputV1 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Legacy per-VM service-state map (V2). pub struct StatusServicesOutputV2 { pub d2b: String, pub microvm: String, @@ -298,6 +325,7 @@ impl StatusServicesOutputV3 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Runner-parity evidence for one VM. pub struct RunnerParityOutputV2 { pub declared_runner: String, pub runner_parity_path: String, @@ -306,6 +334,7 @@ pub struct RunnerParityOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Bridge isolation check output for one runtime. pub struct StatusBridgeCheckOutputV2 { pub mode: String, pub status: String, @@ -315,6 +344,7 @@ pub struct StatusBridgeCheckOutputV2 { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] +/// Full `d2b audit` output: host posture plus per-VM sidecar evidence. pub struct AuditOutputV2 { pub kvm_dev_mode: String, pub wayland_user_in_kvm: bool, @@ -335,6 +365,7 @@ pub struct AuditOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] +/// One VM's virtiofsd audit evidence. pub struct AuditVirtiofsdOutputV2 { pub user: String, pub caps_dropped: Vec, @@ -344,6 +375,7 @@ pub struct AuditVirtiofsdOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] +/// One VM's sshd password-authentication audit evidence. pub struct AuditSshOutputV2 { #[serde(rename = "PasswordAuthentication")] pub password_authentication: Option, @@ -351,6 +383,7 @@ pub struct AuditSshOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] +/// One bridge's isolation audit evidence. pub struct AuditBridgeIsolationOutputV2 { pub bridge: String, pub tap: String, @@ -360,6 +393,7 @@ pub struct AuditBridgeIsolationOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] +/// One VM's gpu/snd sidecar audit evidence. pub struct AuditSidecarsOutputV2 { pub gpu_active: bool, pub snd_active: bool, @@ -369,6 +403,7 @@ pub struct AuditSidecarsOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] +/// One environment's usbipd audit evidence. pub struct AuditUsbipEnvOutputV2 { pub socket_active: bool, pub backend_active: bool, @@ -377,6 +412,7 @@ pub struct AuditUsbipEnvOutputV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `d2b auth status` output for the caller. pub struct AuthStatusOutputV2 { pub role: AuthRoleV2, pub effective_uid: u32, @@ -387,14 +423,19 @@ pub struct AuthStatusOutputV2 { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] +/// The caller's authenticated role. pub enum AuthRoleV2 { + /// No role is held. None, + /// Launcher scope only. Launcher, + /// Admin scope. Admin, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One admin socket's reachability evidence. pub struct AuthSocketStatusV2 { pub name: String, pub path: String, @@ -404,6 +445,7 @@ pub struct AuthSocketStatusV2 { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One subcommand denied to the caller, with the refusal reason. pub struct AuthDeniedSubcommandV2 { pub name: String, pub reason: String, From e12e51dacd4205244779669b9499d704a75568e9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:45:25 -0700 Subject: [PATCH 177/726] docs(d2b-contracts-control): document public wire request and status types --- .../d2b-contracts-control/src/public_wire.rs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index 2ec436821..a25dafc0a 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -180,6 +180,7 @@ pub enum WorkloadOpResponse { #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Workload-list query; the realm filters the result. pub struct WorkloadListArgs { #[serde(default, skip_serializing_if = "Option::is_none")] pub realm: Option, @@ -275,6 +276,7 @@ pub struct LauncherExecResult { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `list` query filters: an optional environment and VM name. pub struct ListRequest { pub env: Option, pub vm: Option, @@ -282,6 +284,7 @@ pub struct ListRequest { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `status` query: optionally check bridges and select one VM. pub struct StatusRequest { #[serde(default)] pub check_bridges: bool, @@ -290,6 +293,7 @@ pub struct StatusRequest { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// `audit` query: filter, format, cursor, and page limit. pub struct AuditRequest { pub filter: Option, #[serde(default)] @@ -1276,9 +1280,16 @@ impl NamedProcessStreamResponseFrame { #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] +/// A validated shell name matching `^[A-Za-z0-9_][A-Za-z0-9._-]{0,63}$`. pub struct ShellName(String); impl ShellName { + /// Validate and construct a shell name. + /// + /// # Errors + /// + /// Returns [`ShellNameError`] when the value does not match the shell + /// name pattern. pub fn new(value: impl Into) -> Result { let value = value.into(); if shell_name_valid(&value) { @@ -1294,6 +1305,7 @@ impl ShellName { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// The value is not a valid shell name. pub struct ShellNameError; impl fmt::Debug for ShellName { @@ -2404,24 +2416,36 @@ fn is_default_usb_probe_entry_kind(kind: &UsbProbeEntryKind) -> bool { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One USBIP probe entry describing a bus, its owner, and the next action. pub struct UsbipProbeEntry { #[serde(default, skip_serializing_if = "is_default_usb_probe_entry_kind")] pub kind: UsbProbeEntryKind, + /// VM this entry describes. pub vm: String, + /// Environment the VM belongs to. pub env: String, + /// Physical bus id probed. pub bus_id: String, + /// Broker claim lock path. pub lock_path: String, + /// Claim status. pub status: UsbipProbeStatus, + /// VM currently holding the claim, if any. #[serde(default, skip_serializing_if = "Option::is_none")] pub owner_vm: Option, + /// Attached USB slot, if any. #[serde(default, skip_serializing_if = "Option::is_none")] pub slot: Option, + /// Media resource bound to the slot, if any. #[serde(default, skip_serializing_if = "Option::is_none")] pub media_ref: Option, + /// How the device was discovered. #[serde(default, skip_serializing_if = "Option::is_none")] pub source_kind: Option, + /// Alternate bus ids that match the declaration. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub candidate_bus_ids: Vec, + /// Command the operator should run next. #[serde(default, skip_serializing_if = "Option::is_none")] pub follow_up_command: Option, #[serde(default)] @@ -2448,6 +2472,7 @@ pub struct UsbipProbeResponse { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Audit entry filters: scope, severity, and outcome facets. pub struct AuditSelector { pub env: Option, pub severity: Option, @@ -2492,6 +2517,7 @@ pub struct SocketReachability { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One `list` result row. pub struct ListEntry { pub env: Option, pub graphics: bool, @@ -2527,6 +2553,7 @@ pub struct ListEntry { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One `status` VM row. pub struct VmStatus { pub bridge_checks: Vec, pub env: Option, @@ -2563,6 +2590,7 @@ pub struct VmStatus { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// The observed service-state map of one VM. pub struct PublicVmServices { pub gpu: Option, pub microvm: String, @@ -2577,6 +2605,7 @@ pub struct PublicVmServices { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One bridge-presence check result. pub struct BridgeCheck { pub bridge: IfName, pub present: bool, @@ -2585,6 +2614,7 @@ pub struct BridgeCheck { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// The lifecycle envelope of one VM. pub struct VmLifecycle { #[serde(default)] pub degraded: bool, @@ -2615,6 +2645,7 @@ pub enum VmLifecycleState { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// The active runner plus its capability and service summaries. pub struct RuntimeSummary { pub detail: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -2630,6 +2661,7 @@ pub struct RuntimeSummary { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Whether a VM is set to autostart, with the reason. pub struct VmAutostartPosture { pub mode: String, pub reason: String, @@ -2637,6 +2669,7 @@ pub struct VmAutostartPosture { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Optional guest-media status attached to a VM row. pub struct QemuMediaStatus { pub firmware_mode: String, pub media: Vec, @@ -2645,6 +2678,7 @@ pub struct QemuMediaStatus { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Runner-side QMP media state for one VM. pub struct QemuMediaRunnerStatus { pub pre_cont_progress: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -2655,6 +2689,7 @@ pub struct QemuMediaRunnerStatus { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One attached media source's status. pub struct QemuMediaSourceStatus { pub format: String, pub media_ref: String, @@ -2666,6 +2701,7 @@ pub struct QemuMediaSourceStatus { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// The media registry's convergence state for one source. pub struct QemuMediaRegistryStatus { #[serde(default, skip_serializing_if = "Option::is_none")] pub remediation: Option, From 5c5b2d478a1c3575a38adea64ebbb794e4657bad Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:45:25 -0700 Subject: [PATCH 178/726] docs(d2b-contracts-control): document the unsafe-local helper wire --- .../src/unsafe_local_wire.rs | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/packages/d2b-contracts-control/src/unsafe_local_wire.rs b/packages/d2b-contracts-control/src/unsafe_local_wire.rs index d415a3fb8..69c108639 100644 --- a/packages/d2b-contracts-control/src/unsafe_local_wire.rs +++ b/packages/d2b-contracts-control/src/unsafe_local_wire.rs @@ -12,23 +12,31 @@ use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize}; use std::fmt; +/// Protocol version this wire vocabulary speaks; peers must agree on it. pub const UNSAFE_LOCAL_HELPER_PROTOCOL_VERSION: u32 = 3; +/// Maximum bytes in one control frame on either direction. pub const MAX_HELPER_FRAME_SIZE: usize = 256 * 1024; /// Value requested through `SO_SNDBUF` and `SO_RCVBUF` on both control peers. pub const HELPER_SOCKET_BUFFER_REQUEST_BYTES: usize = MAX_HELPER_FRAME_SIZE; /// Minimum value that `getsockopt` must report after Linux doubles the request. pub const MIN_EFFECTIVE_HELPER_SOCKET_BUFFER_BYTES: usize = MAX_HELPER_FRAME_SIZE * 2; +/// Maximum operations the helper queues per control peer before refusing. pub const MAX_HELPER_QUEUE_DEPTH: usize = 128; +/// Maximum scopes one helper snapshot may carry. pub const MAX_HELPER_SNAPSHOT_SCOPES: usize = 1024; +/// Maximum completed-operation records the daemon retains per uid. pub const MAX_COMPLETED_OPERATIONS_PER_UID: usize = 1024; +/// How long a completed-operation record may age before it is dropped. pub const MAX_COMPLETED_OPERATION_AGE_SECS: u64 = 24 * 60 * 60; +/// Whether a peer protocol version is the one this wire speaks. pub const fn unsafe_local_helper_protocol_supported(version: u32) -> bool { version == UNSAFE_LOCAL_HELPER_PROTOCOL_VERSION } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Helper-to-daemon greeting naming the protocol version and generation. pub struct HelperHello { pub protocol_version: u32, pub generation: u64, @@ -38,6 +46,7 @@ pub struct HelperHello { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Daemon-to-helper acceptance of a greeting, pinning interval bounds. pub struct HelperHelloAccepted { pub protocol_version: u32, pub generation: u64, @@ -47,6 +56,7 @@ pub struct HelperHelloAccepted { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Liveness frame carrying the generation and a monotonic sequence. pub struct HelperHeartbeat { pub generation: u64, pub sequence: u64, @@ -54,13 +64,17 @@ pub struct HelperHeartbeat { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] +/// The kind of workload scope the helper runs. pub enum HelperScopeKind { + /// A launcher application scope. LauncherApp, + /// A Wayland proxy scope. WaylandProxy, } #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Opaque identity of one helper scope; the invocation id is redacted. pub struct ScopeIdentity { pub invocation_id: String, pub kind: HelperScopeKind, @@ -77,16 +91,23 @@ impl fmt::Debug for ScopeIdentity { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] +/// Lifecycle state of one helper scope. pub enum HelperScopeState { + /// The scope is being set up. Starting, + /// The scope is serving. Active, + /// The scope is tearing down. Stopping, + /// The scope has exited. Exited, + /// The scope is serving degraded. Degraded, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One scope's observed state in a helper snapshot. pub struct HelperScopeSnapshot { pub operation_id: OperationId, pub workload: ZoneResourceIdentity, @@ -96,12 +117,20 @@ pub struct HelperScopeSnapshot { #[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Bounded snapshot of every scope the helper currently runs. pub struct HelperSnapshot { pub generation: u64, pub scopes: Vec, } impl HelperSnapshot { + /// Validate the snapshot bounds and every workload identity. + /// + /// # Errors + /// + /// Returns [`HelperFailureCode::InvalidRequest`] when the generation is + /// zero, the scope count exceeds the bound, or a workload identity is + /// not a helper-owned resource type. pub fn validate(&self) -> Result<(), HelperFailureCode> { if self.generation == 0 { return Err(HelperFailureCode::InvalidRequest); @@ -141,6 +170,9 @@ impl<'de> Deserialize<'de> for HelperSnapshot { #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One launch request the daemon commits to the helper. +/// +/// The workload target, item id, and argv are redacted in `Debug`. pub struct HelperLaunchRequest { pub request_id: u64, pub operation_id: OperationId, @@ -168,6 +200,12 @@ impl fmt::Debug for HelperLaunchRequest { } impl HelperLaunchRequest { + /// Validate the workload identity bounds. + /// + /// # Errors + /// + /// Returns [`HelperFailureCode::InvalidRequest`] when the workload is + /// not a helper-owned resource type. pub fn validate_bounds(&self) -> Result<(), HelperFailureCode> { validate_unsafe_local_resource_identity(&self.workload) } @@ -211,9 +249,16 @@ impl<'de> Deserialize<'de> for HelperLaunchRequest { #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(transparent)] +/// A validated `#rrggbb` accent color. pub struct RealmAccentColor(#[schemars(regex(pattern = "^#[0-9a-f]{6}$"))] String); impl RealmAccentColor { + /// Validate and construct a `#rrggbb` accent color. + /// + /// # Errors + /// + /// Returns [`HelperFailureCode::InvalidRequest`] when the value is not + /// exactly `#` plus six lowercase hex digits. pub fn new(value: impl Into) -> Result { let value = value.into(); let valid = value.len() == 7 @@ -226,6 +271,7 @@ impl RealmAccentColor { .ok_or(HelperFailureCode::InvalidRequest) } + /// Borrow the validated color text. pub fn as_str(&self) -> &str { &self.0 } @@ -247,6 +293,12 @@ impl<'de> Deserialize<'de> for RealmAccentColor { } } +/// Refuse identities whose resource type the helper cannot own. +/// +/// # Errors +/// +/// Returns [`HelperFailureCode::InvalidRequest`] when the resource type is +/// not Host, Guest, Process, or EphemeralProcess. pub fn validate_unsafe_local_resource_identity( identity: &ZoneResourceIdentity, ) -> Result<(), HelperFailureCode> { @@ -260,7 +312,9 @@ pub fn validate_unsafe_local_resource_identity( #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] +/// Closed failure code one helper operation can report. pub enum HelperFailureCode { + /// The request was malformed or out of bounds. InvalidRequest, OperationIdConflict, QueueFull, @@ -279,14 +333,19 @@ pub enum HelperFailureCode { #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] +/// How a helper operation settled. pub enum HelperOperationDisposition { + /// The operation was newly committed. Committed, + /// The operation was already committed before. AlreadyCommitted, + /// The operation finished. Completed, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Outcome of one committed helper operation. pub struct HelperOperationResult { pub request_id: u64, pub operation_id: OperationId, @@ -297,6 +356,7 @@ pub struct HelperOperationResult { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Refusal of one helper operation with its closed failure code. pub struct HelperOperationRejected { pub request_id: u64, pub operation_id: OperationId, @@ -305,24 +365,35 @@ pub struct HelperOperationRejected { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(tag = "type", content = "payload", rename_all = "camelCase")] +/// One frame the daemon may send to the helper. pub enum DaemonToUnsafeLocalHelper { + /// The greeting was accepted. HelloAccepted(HelperHelloAccepted), + /// A liveness frame. Heartbeat(HelperHeartbeat), + /// A launch request. Launch(Box), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(tag = "type", content = "payload", rename_all = "camelCase")] +/// One frame the helper may send to the daemon. pub enum UnsafeLocalHelperToDaemon { + /// The initial greeting. Hello(HelperHello), + /// A scope snapshot. Snapshot(HelperSnapshot), + /// A liveness frame. Heartbeat(HelperHeartbeat), + /// A committed operation outcome. Operation(HelperOperationResult), + /// A refused operation. Rejected(HelperOperationRejected), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// The complete helper wire schema: version plus both frame directions. pub struct UnsafeLocalHelperWireSchema { pub protocol_version: u32, pub daemon_to_helper: DaemonToUnsafeLocalHelper, From e5b58495903f81ee397db4b611755f7ff1fa1cb3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:45:25 -0700 Subject: [PATCH 179/726] docs(d2b-contracts-control): document the terminal wire DTOs --- .../src/terminal_wire.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/d2b-contracts-control/src/terminal_wire.rs b/packages/d2b-contracts-control/src/terminal_wire.rs index 0684e946e..698036204 100644 --- a/packages/d2b-contracts-control/src/terminal_wire.rs +++ b/packages/d2b-contracts-control/src/terminal_wire.rs @@ -9,24 +9,37 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase")] +/// Which output stream a terminal read targets. pub enum TerminalStream { + /// Standard output. Stdout, + /// Standard error. Stderr, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Terminal dimensions in rows and columns. pub struct TerminalSize { + /// Row count. pub rows: u32, + /// Column count. pub cols: u32, } #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One stdin write to a terminal session. +/// +/// The session identifier is redacted in `Debug`. pub struct TerminalWriteStdin { + /// Session identifier. pub session: String, + /// Byte offset this chunk continues from. pub offset: u64, + /// Base64-encoded chunk bytes. pub chunk_base64: String, + /// Whether this chunk closes stdin. #[serde(default)] pub eof: bool, } @@ -44,13 +57,22 @@ impl std::fmt::Debug for TerminalWriteStdin { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One output read from a terminal session. +/// +/// The session identifier is redacted in `Debug`. pub struct TerminalReadOutput { + /// Session identifier. pub session: String, + /// Stream to read from. pub stream: TerminalStream, + /// Byte offset to read from. pub offset: u64, + /// Maximum bytes to return. pub max_len: u64, + /// Whether to block until output is available. #[serde(default)] pub wait: bool, + /// Bound on the wait, in milliseconds. #[serde(default)] pub timeout_ms: u64, } @@ -70,10 +92,17 @@ impl std::fmt::Debug for TerminalReadOutput { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One resize request for a terminal session. +/// +/// The session identifier is redacted in `Debug`. pub struct TerminalResize { + /// Session identifier. pub session: String, + /// New row count. pub rows: u32, + /// New column count. pub cols: u32, + /// Caller-supplied operation id for correlation. #[serde(default)] pub op_id: u64, } @@ -91,26 +120,38 @@ impl std::fmt::Debug for TerminalResize { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// Result of one terminal stdin write. pub struct TerminalWriteStdinResult { + /// Bytes accepted by the session. pub accepted_len: u64, + /// Offset the next chunk should continue from. pub next_offset: u64, + /// Whether the write was backpressured. #[serde(default)] pub backpressured: bool, + /// Whether stdin is now closed. #[serde(default)] pub stdin_closed: bool, } #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One output chunk read from a terminal session. pub struct TerminalReadOutputChunk { + /// Base64-encoded output bytes. pub data_base64: String, + /// Offset the next read should continue from. pub next_offset: u64, + /// Whether this chunk is the last output. #[serde(default)] pub eof: bool, + /// Bytes dropped because the ring buffer overflowed. #[serde(default)] pub dropped_bytes: u64, + /// Whether the chunk was truncated to the requested bound. #[serde(default)] pub truncated: bool, + /// Whether the read timed out before output arrived. #[serde(default)] pub timed_out: bool, } From 19a297b30a99cfaf58671df6fb3b52df08193e66 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:46:25 -0700 Subject: [PATCH 180/726] audit: record wave-1 slices 8b and 9 The four contract doc rows and the nineteen-crate provider slice, all rows disposed, with the four type-driven variants recorded. --- .../2026-09-24-rust-skills-audit/ledger.md | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index d8082b8b7..a5ec00d43 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -90,37 +90,37 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:790, packages/d2b-provid` | | | | `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:150` | | | | `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provid` | | | -| `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/effects_service.rs:50-60, packages/d2b-provider-endpoin` | | | -| `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/endpoint.rs:395-398` | | | +| `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/effects_service.rs` | Added the unit-test option: pinned inspect-endpoint payload rows to guest_control_producer/device_worker_endpoint_class (set + per-row class/producer/locality). Mutation (locality drift) fails the tes | | +| `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/endpoint.rs` | Derive Default on EndpointConsumerPolicy (field-wise empty-Vec default identical to unrestricted()); dropped the manual impl. | | | `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | derive(Default) with #[default] on BootstrapServiceState::Waiting; manual BootstrapService Default impl deleted | | | `RS-0063` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs` | _config field and initializer deleted; config.validate() kept in from_verified_descriptor. | | | `RS-0064` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied-variant | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs` | Field deleted. Variant: its only read fed a write nobody read, so as a local it tripped -D warnings unused-assignments; dead tail and set sites deleted as dead state. | | | `RS-0065` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs` | ChildRole::rank() added; deletion_rank/upgrade_rank free fns deleted; both sort sites call role.rank(). | | | `RS-0066` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs` | readiness() wrapper deleted; test calls vmm_readiness with explicit booleans. Census confirmed only the two test assertions called it. | | | `RS-0067` | `idiom` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 7cb57d2fe | `packages/d2b-provider-guest-qemu-media/src/config.rs` | Default impls call default_qemu_artifact/default_vcpu/default_memory_mib/default_boot_media_view | | -| `RS-0068` | `idiom` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/test_support.rs:185` | | | +| `RS-0068` | `idiom` | `d2b-provider-host` | low | actionable | leaf | applied | U2 | 3d165efc4 | `packages/d2b-provider-host/src/test_support.rs` | Dedented the stray impl-closing brace (RecordingMinijailGate) to column 0. | | | `RS-0069` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Octets destructured via try_into and rendered with one format! | | | `RS-0070` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/driver.rs` | declared_dependency_refs is a filter_map pipeline over attachments | | | `RS-0071` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/controller.rs` | expected_acknowledgements collects the chained start/stop endpoint maps directly; conditional HostSink pushes kept. | | | `RS-0072` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/descriptor.rs` | service_package() returns crate::SERVICE_PACKAGE; literal has one home. | | -| `RS-0073` | `idiom` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-pro` | | | -| `RS-0074` | `idiom` | `d2b-provider-seccomp-profile` | low | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-sec` | | | -| `RS-0075` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/systemd.rs:840` | | | -| `RS-0076` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor` | | | +| `RS-0073` | `idiom` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U2 | 8fcd947b2 | `packages/d2b-provider-process-systemd/src/effects_service.rs` | Replaced both hand-written impl Default blocks with #[derive(Default)] on SystemdEffectsService and SystemdEffectsServiceFactory. | | +| `RS-0074` | `idiom` | `d2b-provider-seccomp-profile` | low | actionable | leaf | applied | U2 | 4d49437db | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs` | Dedented three impl-block closing braces (DeviceNodePath, DeviceBind, SeccompProfileSpec) to column 0. | | +| `RS-0075` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | applied | U2 | 4065c7032 | `packages/d2b-provider-supervisor/src/systemd.rs` | Deleted the no-op `let _ = &handle.pidfd;` in BrokerSystemdEffectOwner::stop. | | +| `RS-0076` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | applied | U2 | 4065c7032 | `packages/d2b-provider-supervisor/src/observations.rs` | Extracted one shared bounded pending-observation ledger (observations.rs record/take) used by both Broker and Systemd backends. | | | `RS-0077` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | to_hex uses a const HEX table; dead unwrap_or fallback removed | | | `RS-0078` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | required_bindings is a free pub fn re-exported at root; Self:: call and two test sites updated | | | `RS-0079` | `idiom` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/fd10.rs` | request() calls valid_guest_backend_operation(&operation); the inline 15-entry matches! deleted; single allowlist remains. | | | `RS-0080` | `idiom` | `d2b-provider-toolkit` | low | actionable | leaf | applied-variant | U2 | c496e2214 | `packages/d2b-provider-toolkit/src/base/fd10.rs` | One struct carries the accessors plus new/with_sensitive_bytes/encode, keeping the zeroizing bytes field. Variant: GuestCredentialBackendReply kept as a type alias so consumers compile unchanged. | | | `RS-0081` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | RelaySecret derives Clone; hand-written impl deleted | | | `RS-0082` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 6fe6615af | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | Bearer header built from a literal instead of a collected char array | | -| `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:221-224` | | | -| `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:607-609` | | | -| `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/status.rs:33-38` | | | +| `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U2 | fda87abbe | `packages/d2b-provider-transport-vsock/src/auth.rs` | ReadySession::disconnect now drops mut and returns SessionState::Disconnected directly (SessionState is Copy). | | +| `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix (envelope.base.get("provider").cloned()) is type-incompatible: base.get yields CanonicalJsonValue not serde_json::Value. Applied minimal variant: dropped the dead unwrap_or fallback via an | | +| `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/status.rs` | LayoutPhase::worse now uses derived self.max(other); declaration order already encodes severity. | | | `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | | `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | not-started | U2 | | `packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, pa` | 17 hand-written redaction Debug impls to redacted_debug! (or macro extension plus Debug-shape test updates); effort M; not started within this run. | | | `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | -| `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:914, packages/d2b-resource-client/src/proc` | | | -| `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:194, packages/d2b-resource-client/src/zone` | | | +| `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | +| `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/zone_client.rs` | Dropped the duplicate GuestControlEndpoint::endpoint_uid accessor (kept uid()); removed the now-obsolete equivalence assertion. Census: no external caller. | | | `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:` | | | | `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2402` | | | | `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:1724` | | | @@ -132,7 +132,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | impl FromStr for ResourceProvenance; store parses via str::parse | | | `RS-0100` | `idiom` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/engine.rs` | index loop replaced with chunks_exact().take(count).map(decode_attachment_descriptor).collect::>>() | | | `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/admission.rs` | send_authorized_ttrpc now calls validate_ttrpc_permit(&permit, now_tick)? instead of re-writing the matches! block | | -| `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/config.rs:178` | | | +| `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | applied | U2 | 0b8ef8ff5 | `packages/d2b-sk-frontend/src/config.rs` | zone_path now collects labels with an iterator pipeline (split/map/collect) instead of a push loop. | | | `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U2 | f3a847c72 | `packages/d2b-unsafe-local-helper/src/systemd.rs` | Replaced the then_some/ok_or NotFound normalization with an explicit if-let/if-error branch in terminate_scope and stop_scope; cargo check and test green. | | | `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | 932616e19 | `packages/d2b-zone-routing/src/resolver.rs` | longest_suffix_match is a find_map over the index range | | | `RS-0105` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | c8defa1f4 | `packages/d2b-zone-routing/src/service.rs` | ZoneTopologyRequest derives Default; manual impl deleted | | @@ -184,17 +184,17 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | parse(value.as_str()) at 3 sites; network_uid compare via as_str; note: row rationale 'no allocation' inaccurate (Into still allocates) but explicit clones removed | | | `RS-0145` | `own` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/owner_reconcile.rs` | observed bound as &BTreeMap via ok_or(OwnerNotRelisted); .get/for-in/ordered_observed_refs/mutation_sort_parts take the borrow; whole-map clone removed. | | | `RS-0146` | `own` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | claim computed from request.durable_claim() before the lock block; request moved into admit_authority_inner_with_operation; .clone() deleted. | | -| `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/t` | | | -| `RS-0154` | `own` | `d2b-provider` | low | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304` | | | +| `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | applied | U2 | e47020297 | `packages/d2b-process-conformance/src/ticket.rs` | All four with_* builders (with_runtime_identity, with_owner_uid, with_owner_ref, with_target_ref) now move launch_identity instead of cloning it. | | +| `RS-0154` | `own` | `d2b-provider` | low | actionable | leaf | applied | U2 | d6adc6a8e | `packages/d2b-provider/src/agent.rs` | ProviderAgent::dispatch extracts Copy method, moves request into service.dispatch(request) instead of cloning, and uses the local method in the audit record. | | | `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | | | | `RS-0156` | `own` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | b17a8c271 | `packages/d2b-provider-config-nixos/src/controller.rs` | GuestConfigDocument::into_bytes() consuming accessor; dispatch passes it without copying | | -| `RS-0157` | `own` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/t` | | | +| `RS-0157` | `own` | `d2b-provider-credential` | low | actionable | leaf | applied | U2 | b68a9b55e | `packages/d2b-provider-credential/src/driver.rs` | Dropped dead derives: Clone on CredentialDriver and Default on RecordingRuntime (no call sites; RecordingRuntime::new kept as the only constructor). | | | `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | validate &identity before store; identity stored on failure branch preserving test-pinned retain-for-finalize contract | | | `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | applied-variant | U2 | 3c3a82817 | `packages/d2b-provider-device-tpm/src/resource_controller.rs` | if/else arms cannot mix owned and borrowed; restructured to ensure-then-borrow from the fields (zero clones), plus the two effects_service reborrows | | | `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | d674e47e9 | `packages/d2b-provider-device-usbip/src/broker.rs` | Lease moved into the field first; map and return clone from the field (3 clones down to 2 per admission) | | | `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provid` | | | -| `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/driver.rs:981` | | | -| `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/ef` | | | +| `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied-variant | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/driver.rs` | Applied the row's sort_by comparator, fixing its misplaced-paren typo (teardown_rank().cmp().then_with(name cmp)); drops the per-row name clone. | | +| `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/effects_service.rs` | Both ACA candidate lists use state.sandbox.iter().cloned().collect() (and disk_image) instead of clone().into_iter().collect(). | | | `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:156-157` | budget stop before azure-container-apps crate | | | `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:500-501` | budget stop before azure-container-apps crate | | | `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:527` | budget stop before azure-container-apps crate | | @@ -206,16 +206,16 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0172` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | pending_delete_operation_id borrowed via as_deref() instead of clone | | | `RS-0173` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | base32 output truncated in place (id.truncate(20)) instead of a second 20-char copy | | | `RS-0174` | `own` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 2e56bfa23 | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs` | execute destructures transport/commands, pushes the owned command, executes from commands.back() | | -| `RS-0175` | `own` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266` | | | +| `RS-0175` | `own` | `d2b-provider-host` | low | actionable | leaf | applied | U2 | 3d165efc4 | `packages/d2b-provider-host/src/driver.rs` | resource_ref now passes &ctx.key().type_name / &ctx.key().name to ResourceTypeName::parse / ResourceName::parse (impl Into), dropping both clones. | | | `RS-0176` | `own` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Collision set stores &str borrowed from interface_names | | | `RS-0177` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied-variant | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/controller.rs` | commit_reconciliation takes &SourceReconcileResult; both call-site .clone()s dropped. Variant: body iterates &result.stop and clones only endpoints inserted into active_sources. | | | `RS-0178` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/lifecycle.rs` | backend: B stored directly; Arc import dropped; Send+Sync bounds kept via the trait bound. | | -| `RS-0179` | `own` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285` | | | -| `RS-0180` | `own` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1988, packages/d2b-provider-process/src/driver` | | | -| `RS-0181` | `own` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/operations.rs:1354, packages/d2b-provider-process/src/op` | | | -| `RS-0182` | `own` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:355, src/driver.rs:478, src/driver.rs:522` | | | -| `RS-0183` | `own` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:360, src/driver.rs:435` | | | -| `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | | | | `src/service/supervisor.rs:599, src/service/supervisor.rs:601` | | | +| `RS-0179` | `own` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/agent.rs` | parse_token/parse_closed_token now take &str (BoundedToken::parse accepts it); dropped the five clone() calls in session_connect/process_effect. | | +| `RS-0180` | `own` | `d2b-provider-process` | low | actionable | leaf | applied | U2 | ada188a9c | `packages/d2b-provider-process/src/driver.rs` | Three identity() sites now use envelope.provider_ref.as_ref().expect("checked") instead of .clone().expect. | | +| `RS-0181` | `own` | `d2b-provider-process` | low | actionable | leaf | applied | U2 | ada188a9c | `packages/d2b-provider-process/src/operations.rs` | bind_cloud_hypervisor_guest_uid now takes argv: Vec by value and returns it; sole caller passes launch_argv directly; removed both to_vec copies. | | +| `RS-0182` | `own` | `d2b-provider-provider` | low | actionable | leaf | applied | U2 | 46b177892 | `packages/d2b-provider-provider/src/driver.rs` | Three zone clones now pass ctx.key().zone.as_str() / view.key.zone.as_str() to ZoneId::parse; the system-core branch uses a &str local. | | +| `RS-0183` | `own` | `d2b-provider-provider` | low | actionable | leaf | applied-variant | U2 | 46b177892 | `packages/d2b-provider-provider/src/driver.rs` | Stated fix's assumption (last previous read before set_status) fails: dependencies(ctx) needs &mut ctx between the two previous reads. Minimal variant: reordered dependencies() before the status read | | +| `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/service/supervisor.rs` | advance_session now scopes the first session_mut borrow in a block and compares supervisor_identity.as_ref() directly; dropped the clone. | | | `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | | `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | | `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | | | @@ -224,11 +224,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | with_deadline consumes self and rebuilds with struct-update syntax; sole caller passes owned request | | | `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 72858f537 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs` | GatewayCredential stores material: GatewayCredentialMaterial moved in from_material; Drop impl deleted (material zeroizes); accessors and Debug unchanged | | | `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | applied-variant | U2 | 9ba7acf09 | `packages/d2b-provider-user/src/effects_service.rs` | Destructured InspectUserRequest and moved groups by value; username still cloned because inspect_user_response borrows it after UserSpec::new consumes it (stated fix was not implementable as written). | | -| `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:337` | | | +| `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix not type-compatible: ctx.spec returns &T so decoded_spec returned an owned clone. Minimal variant: decoded_spec now returns (&VolumeSpecEnvelope, VolumeSpec); callers adapted; removed the p | | | `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | | | | `driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.` | | | | `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/row_readers.rs` | Bounded the as_object_mut removal borrow in a block and moved spec into serde_json::from_value, dropping the Value::Object(object.clone()). | | -| `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/sr` | | | -| `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1526` | | | +| `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | Both plan() route-binding arms (RoutePolicyCommitted, SessionGenerationAdvanced) now borrow record.route_binding.as_mut() and mutate through it; dropped the clone + store-back. | | +| `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | EnrolledSessionEstablished arm now takes record.enrollment.as_ref() and compares the fingerprint, ending the borrow before record.link_epoch mutation. | | | `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/client.rs` | scoped_commit_batch and commit_scoped_batch take &[ScopedResourceMutation]; commit_batch_with_scope takes Option<&[..]>; adapter passes transport.mutations() directly. | | | `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/admission.rs` | mutations.into_iter().map(prepare_mutation); the redundant .cloned() removed. | | | `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | | | | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | | | @@ -245,7 +245,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0211` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 1f9423d9a | `target.rs` | assign moves assignment into map and clones once for return | | | `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | json_object moves member values; 17 call sites updated | | | `RS-0213` | `own` | `d2b-session` | low | actionable | family | | | | `engine.rs:689, admission.rs:593` | | | -| `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83` | | | +| `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | applied | U2 | 0b8ef8ff5 | `packages/d2b-sk-frontend/src/main.rs` | main destructures Config and calls placement.into_placement() (no clone); config builds "/dev/uhid" via PathBuf::from. | | | `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | applied-variant | U2 | 6a3cf6cff | `packages/d2b-zone-routing/src/engine.rs` | Zone pair moved into the snapshot after destructuring expected; validate_snapshot checks inlined (row's first option) and gated #[cfg(test)] since consume no longer calls it | | | `RS-0221` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_compositi` | | | | `RS-0222` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:4057` | | | @@ -684,10 +684,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0638` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/streams.rs` | # Errors on StreamName::parse, OperationId::parse, ZoneBoundPolicyIdentity::digest,and ZoneEndpointPolicy::lower | | | `RS-0639` | `docs` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/host_generation.rs` | # Errors sections on SourceGenerationCompatibilityFloorV1::new, begin_handoff, all five HandoffCoordinator transitions, RunnerLaunchArgs::new, envelope_invoke_kernel naming exact variants. | | | `RS-0640` | `docs` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/broker_wire.rs` | FdKind/ForwardOperationRequest doc polish: missing space, CJK full-width periods, and comma-adjacent spacing fixed. | | -| `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130` | Not applied: run budget exhausted before the contracts-control doc batch; cli_output.rs DTO docs remain | | -| `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495` | Not applied: run budget exhausted; public_wire.rs docs and # Errors remain | | -| `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | pending | U2 | | `unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wi` | Not applied: run budget exhausted; unsafe_local_wire.rs constant/type docs remain | | -| `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | pending | U2 | | `terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105` | Not applied: run budget exhausted; terminal_wire.rs DTO docs remain | | +| `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | 2329f6aa2 | `packages/d2b-contracts-control/src/cli_output.rs` | One-line docs added to all 32 CLI-output DTOs/enums; StatusServicesOutputV3 already documented | | +| `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | e12e51dac | `packages/d2b-contracts-control/src/public_wire.rs` | Docs added to the named request/status types plus UsbipProbeEntry field meanings; # Errors added to ShellName::new (RealmAccentColor::new covered by RS-0643) | | +| `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | 5c5b2d478 | `packages/d2b-contracts-control/src/unsafe_local_wire.rs` | Constants documented with the daemon-enforced bounds, wire types one-lined, helper fns and RealmAccentColor::new get # Errors | | +| `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | applied | U2 | e5b584959 | `packages/d2b-contracts-control/src/terminal_wire.rs` | One-line docs per DTO plus the redacted-Debug note on session-bearing types | | | `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | | `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | | `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/` | | | @@ -701,8 +701,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0653` | `docs` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/migration.rs` | requires_migration and validates_binding documented. | | | `RS-0656` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/bridge_port.rs` | Added # Errors to validate_readback, parse_request, parse_validation_request, validate_media_ref, validate_usb_busid, and NftBatch::parse (the wire-boundary parsers the row names). | | | `RS-0657` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/cgroup.rs` | One-line docs added to Controller::REQUIRED, Controller::as_str, Controller::from_token (token grammar noted), BusId::new, HostPrepStepId::as_str. | | -| `RS-0660` | `docs` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/` | | | -| `RS-0661` | `docs` | `d2b-provider` | medium | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:270, packages/d2b-provider/src/descriptor.rs:232, packa` | | | +| `RS-0660` | `docs` | `d2b-process-conformance` | low | actionable | leaf | applied | U2 | e47020297 | `packages/d2b-process-conformance/src/terminal.rs` | Added # Errors to the named Result items: ProcessOutcome::exited/validate, BrokerTerminalResult::relay, SandboxCompiler::compile, LaunchIdentity::new (six variants), LaunchTicket::validate, LaunchedPr | | +| `RS-0661` | `docs` | `d2b-provider` | medium | actionable | leaf | applied | U2 | d6adc6a8e | `packages/d2b-provider/src/agent.rs` | Added # Errors to all 17 anchors: ProviderAgentRequest::new/dispatch, new_linked, RepairPolicy::bounded/validate, ProviderDescriptor::new/validate, three identity parses, ProviderInstance::new, with_c | | | `RS-0662` | `docs` | `d2b-provider-activation-nixos` | medium | actionable | leaf | applied | U2 | 6acd5ada6 | `packages/d2b-provider-activation-nixos/src/controller.rs` | Added # Errors naming the exact ActivationError/ActivationVerificationError variants to verify, verify_application, refuse_undeclared_runner_step, reconcile, apply_runner_result. | | | `RS-0663` | `docs` | `d2b-provider-audio-binding` | low | actionable | leaf | applied | U2 | ca450e9d5 | `packages/d2b-provider-audio-binding/src/audio_binding.rs` | Added # Errors to binding_children, validate, dependencies, desired_children naming Unavailable vs InvalidResource conditions. | | | `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/state.rs` | Documented AudioStateLock guard semantics (holds the OFD lock; drop releases and closes). | | @@ -714,7 +714,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | | | | `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | applied | U2 | ef3bc5ec9 | `packages/d2b-provider-command/src/command.rs` | Added one-line # Errors naming CommandContractError variants to CommandExec::parse, CommandArgvSlot::parse, CommandSpec::new. | | | `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 7a6ab2d2d | `packages/d2b-provider-config-nixos/src/controller.rs` | # Errors added to all 19 pub Result items naming ConfigError variants | | -| `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/` | | | +| `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | applied | U2 | b68a9b55e | `packages/d2b-provider-credential/src/session.rs` | Added # Errors to CredentialRevocationRequest::new (InvalidResource conditions) and CredentialSession::revoke_credential (Revocation). | | | `RS-0674` | `docs` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U2 | b29c0b8d2 | `packages/d2b-provider-credential-entra/src/controller.rs` | Added # Errors naming returned variants to EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, r | | | `RS-0675` | `docs` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U2 | e86206bab | `packages/d2b-provider-credential-managed-identity/src/lib.rs` | Added # Errors naming ManagedIdentityProviderError/CredentialServiceError/CredentialObservabilityError variants to the named constructors and controller projections. | | | `RS-0676` | `docs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U2 | d5869f583 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | # Errors added to SecretServiceConfig/Placement/Factory/Controller items and drain | | @@ -730,7 +730,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/policy.rs:114, src/policy.rs:119` | | | | `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provide` | | | | `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759` | | | -| `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/facets.rs:63, packages/d2b-provider-guest/src/target_contr` | | | +| `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/facets.rs` | Added # Errors to row_view, session_target_control, resource_uid, and the GuestTargetEffect trait's realize/delete/adopt. | | | `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/lib.rs:7, src/effects.rs:813-882` | budget stop before azure-container-apps crate | | | `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | | `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | matches() doc states the constant-time-in-presented-length guarantee | | @@ -738,29 +738,29 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U2 | 613491144 | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | # Errors added to DeviceAdmission::validate, QemuMediaController::reconcile, LaunchTicket::new, QmpSession::negotiate | | | `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/action_nonce.rs` | # Errors sections on ActionNonceStore::register, NotificationRuntime::new, NotificationSink::deliver_from_guest_source naming exact variants. | | | `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | claim-stale | U2 | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | All three cited docs are complete standalone first sentences at baseline 6ebdd4cec (verified via git show) and HEAD; the lane quoted tail lines of multi-line docs. | | -| `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `lib.rs:13, lib.rs:14, lib.rs:15` | | | -| `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131` | | | +| `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/lib.rs` | Added one-line doc comments to PROVIDER_NAME, PROVIDER_REF, PROVIDER_API_MAJOR mirroring OTEL_HOST_BRIDGE_ROLE. | | +| `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/agent.rs` | Added # Errors to ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream, EmitterSocket::bin | | | `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | applied | U2 | 4e381161f | `packages/d2b-provider-operation/src/operation.rs` | Added one-line # Errors naming OperationContractError variants to OperationAudit::new, AuditJoin::new, OperationFds::new, OperationBounds::new, OperationSpec::new. | | -| `RS-0700` | `docs` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/backend.rs:256, packages/d2b-provider-process/src/launch` | | | +| `RS-0700` | `docs` | `d2b-provider-process` | low | actionable | leaf | applied | U2 | ada188a9c | `packages/d2b-provider-process/src/backend.rs` | Added # Errors to ProcessEffectBackend::launch (closed-code classes) and resolve_launch_identity (LaunchIdentityError). | | | `RS-0701` | `docs` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U2 | 85d30ec37 | `packages/d2b-provider-process-minijail/src/launch.rs` | Added # Errors naming ProcessConformanceError conditions to PlatformGate::validate, validate_launch_ticket, and the launch/adopt/stop/stop_stale impl methods. | | -| `RS-0702` | `docs` | `d2b-provider-process-systemd` | medium | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lifecycle.rs:33, packages/d2b-provider-process-s` | | | -| `RS-0703` | `docs` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/providers.rs:72, src/providers.rs:79` | | | +| `RS-0702` | `docs` | `d2b-provider-process-systemd` | medium | actionable | leaf | applied | U2 | 8fcd947b2 | `packages/d2b-provider-process-systemd/src/lifecycle.rs` | Added # Errors to SystemdProviderConfig::new (OutOfRange), drain::validate (two variants), SystemdProcessController::reconcile (DeadlineExceeded + wrapped), validate_launch_ticket (ProviderMismatch), | | +| `RS-0703` | `docs` | `d2b-provider-provider` | low | actionable | leaf | applied | U2 | 46b177892 | `packages/d2b-provider-provider/src/providers.rs` | Documented all eight ProviderObservation fields. | | | `RS-0704` | `docs` | `d2b-provider-role` | low | actionable | leaf | applied-variant | U2 | e36441105 | `packages/d2b-provider-role/src/lib.rs` | Added #![deny(missing_docs)] and documented PolicyRevisionSet fields; the gate forced one-line docs on AuthorizationCacheKey::new and the four PositiveDecisionCache methods to keep the build green. | | -| `RS-0705` | `docs` | `d2b-provider-seccomp-profile` | medium | actionable | leaf | | | | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:31, packages/d2b-provider-sec` | | | -| `RS-0706` | `docs` | `d2b-provider-shell-terminal` | medium | actionable | leaf | | | | `src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/` | | | +| `RS-0705` | `docs` | `d2b-provider-seccomp-profile` | medium | actionable | leaf | applied | U2 | 4d49437db | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs` | Added # Errors to DeviceNodePath::parse (InvalidDevicePath) and SeccompProfileSpec::new (TooManySyscalls/TooManyDeviceBinds). | | +| `RS-0706` | `docs` | `d2b-provider-shell-terminal` | medium | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/authz.rs` | Added # Errors to 14 named Result-returning items enumerating the ShellTerminalError variants each emits (authorize_request, OpenSessionRequest::new, PoolSpec::new, ShellSession::from_pool, restore_po | | | `RS-0707` | `docs` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | # Errors added to validate, HostProbeSnapshot::new, reconcile family, reject_operator_status_fields, UserReconciler::reconcile and both port methods | | | `RS-0708` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | # Errors sections on ProviderEntrypoint::new, admit, the three with_* binders, StartupPlan::derive/declare naming their refusal variants. | | | `RS-0709` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/testing/conformance.rs` | # Errors sections on check_descriptor_conformance, check_provider_conformance, operation_deadline, deadline_remaining, validate_attachment_indexes. | | | `RS-0710` | `docs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 33a84349d | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | # Errors added to mint_sas, build_connect, CreditWindow::new, RelayTransportSettings::new | | | `RS-0711` | `docs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U2 | 721c96f38 | `packages/d2b-provider-transport-unix/src/portal.rs` | Added # Errors naming PortalError variants to open, close, and observe. | | -| `RS-0712` | `docs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsoc` | | | +| `RS-0712` | `docs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U2 | fda87abbe | `packages/d2b-provider-transport-vsock/src/auth.rs` | Added # Errors bullet lists to all 30 public Result-returning items (incl. all RelayEffectPort/VsockEffectPort/NamedStreamPort trait methods). The audit's 38 count included private impl helpers, not p | | | `RS-0713` | `docs` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/facets.rs` | Added # Errors to SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, BindingDriverEffects::remove_socket, and guest_mount_ready naming the daemon-adapter failures and fail-closed handlin | | -| `RS-0714` | `docs` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92` | | | +| `RS-0714` | `docs` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/content.rs` | Added # Errors to ContentFile::new, ContentProjection::new/from_value, EntryRequest::resolve, VolumeLocalController::reconcile, admit_attachments, validate_source_spec. | | | `RS-0715` | `docs` | `d2b-provider-zone` | low | actionable | leaf | applied | U2 | 2170c0cac | `packages/d2b-provider-zone/src/zone_status.rs` | Added # Errors to SystemCoreStatusEmitter::emit naming the duplicate-handler and rejected-resource Contract conditions. | | -| `RS-0716` | `docs` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src` | | | +| `RS-0716` | `docs` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | Added # Errors to ZoneLinkLimits::new, ZoneLinkHandler::{begin,commit,release_effects,issue_route_admission}, ZoneLinkRecord::{with_route_binding,encode_route_admission_dedup,with_route_admission_dedu | | | `RS-0718` | `docs` | `d2b-resource-api` | medium | actionable | leaf | applied | U2 | 1f9a83aee | `packages/d2b-resource-api/src/authz.rs` | authorize documented with # Errors enumerating the nine AuthorizationDenial variants; one-line contracts on take_store_seal (with Errors), CompiledRole::new, CompiledRoleBinding::new, PolicySet::new. | | | `RS-0717` | `docs` | `d2b-resource-api` | medium | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/service.rs` | # Errors sections on ResourceService::new/new_session_bound, the three frame helpers, manager_row_stored, admit_guest_lifecycle naming the failure classes. | | -| `RS-0719` | `docs` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:` | | | +| `RS-0719` | `docs` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Added # Errors to MetadataInput::new, RetryPolicy::new, CallDriver::new, ZoneClient::{connect,call_connected,scoped_commit_batch}, ProcessAttachClient::attach. | | | `RS-0720` | `docs` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | # Errors on all 14 ResourceManagerClient pub methods | | | `RS-0721` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | ResourceManagerArgs.store/providers documented | | | `RS-0722` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | MODULE_NAME docs on five modules | | From 060d34e18ec0d3777ec436ae08dab05b3e3ec88d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:47:54 -0700 Subject: [PATCH 181/726] session: document lifecycle record bootstrap and deadline surfaces --- packages/d2b-session/src/bootstrap.rs | 28 ++++++++++++++++ packages/d2b-session/src/deadline.rs | 20 +++++++++++ packages/d2b-session/src/lifecycle.rs | 48 +++++++++++++++++++++++++++ packages/d2b-session/src/record.rs | 23 +++++++++++++ 4 files changed, 119 insertions(+) diff --git a/packages/d2b-session/src/bootstrap.rs b/packages/d2b-session/src/bootstrap.rs index ee60f4339..74598c6ae 100644 --- a/packages/d2b-session/src/bootstrap.rs +++ b/packages/d2b-session/src/bootstrap.rs @@ -8,9 +8,15 @@ use zeroize::Zeroize; use crate::{Result, SessionError}; +/// A zeroized 32-byte secret. pub struct Secret32([u8; 32]); impl Secret32 { + /// Construct a secret, rejecting the all-zero value. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::AuthenticationFailed`] when `bytes` is all zero. pub fn new(bytes: [u8; 32]) -> Result { if bytes == [0; 32] { return Err(SessionError::new(SessionErrorCode::AuthenticationFailed)); @@ -35,9 +41,15 @@ impl Drop for Secret32 { } } +/// A bootstrap pre-shared key. pub struct BootstrapPsk(Secret32); impl BootstrapPsk { + /// Construct a bootstrap PSK, rejecting the all-zero value. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::AuthenticationFailed`] when `bytes` is all zero. pub fn new(bytes: [u8; 32]) -> Result { Secret32::new(bytes).map(Self) } @@ -49,6 +61,7 @@ impl fmt::Debug for BootstrapPsk { } } +/// A bootstrap PSK admitted against a matching identity binding. pub struct AdmittedBootstrapPsk { psk: BootstrapPsk, identity: BootstrapIdentityBinding, @@ -70,12 +83,18 @@ impl fmt::Debug for AdmittedBootstrapPsk { } } +/// A single-use bootstrap admission bound to an operation, nonce, and identity. pub struct BootstrapAdmission { binding: BootstrapPskBinding, psk: Option, } impl BootstrapAdmission { + /// Construct an admission for one bootstrap operation. + /// + /// # Errors + /// + /// Returns the binding validation error when `binding` is invalid. pub fn new(binding: BootstrapPskBinding, psk: BootstrapPsk) -> Result { binding.validate().map_err(SessionError::from)?; Ok(Self { @@ -84,6 +103,14 @@ impl BootstrapAdmission { }) } + /// Consume the admission, releasing the PSK when the proof matches. + /// + /// # Errors + /// + /// Returns [`HandshakeRejectReason::BootstrapOperationMismatch`] when the + /// operation, nonce, or identity does not match, [`HandshakeRejectReason::BootstrapExpired`] + /// when the admission expired, and [`HandshakeRejectReason::BootstrapReplayed`] + /// when the admission was already consumed. pub fn consume( &mut self, operation_id: &OperationId, @@ -108,6 +135,7 @@ impl BootstrapAdmission { .ok_or_else(|| SessionError::from(HandshakeRejectReason::BootstrapReplayed)) } + /// Return whether the admission was already consumed. pub fn is_consumed(&self) -> bool { self.psk.is_none() } diff --git a/packages/d2b-session/src/deadline.rs b/packages/d2b-session/src/deadline.rs index 90cf3f4ad..8f9760f37 100644 --- a/packages/d2b-session/src/deadline.rs +++ b/packages/d2b-session/src/deadline.rs @@ -4,6 +4,7 @@ use d2b_contracts_zone_session::v3::component_session::{RequestEnvelope, Session use crate::{Result, SessionError}; +/// Budgets one request's remaining time across wall-clock and monotonic sources. pub struct DeadlineBudget { envelope: RequestEnvelope, service_max_lifetime_ms: u64, @@ -11,6 +12,12 @@ pub struct DeadlineBudget { } impl DeadlineBudget { + /// Admit a request envelope against the service lifetime and peer timeout. + /// + /// # Errors + /// + /// Returns the envelope admission error when the request is already expired, + /// and [`SessionErrorCode::ArithmeticOverflow`] when the deadline overflows. pub fn admit( envelope: RequestEnvelope, local_wall_clock_ms: u64, @@ -34,10 +41,17 @@ impl DeadlineBudget { }) } + /// Return the absolute expiry in unix milliseconds. pub fn absolute_expiry_unix_ms(&self) -> u64 { self.envelope.expires_at_unix_ms } + /// Return the remaining budget in nanoseconds. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::DeadlineExpired`] when the monotonic deadline + /// passed or the envelope admits no remaining time. pub fn remaining_nanos( &self, local_wall_clock_ms: u64, @@ -61,6 +75,11 @@ impl DeadlineBudget { .map_err(|_| SessionError::new(SessionErrorCode::DeadlineExpired)) } + /// Build a ttrpc context carrying the remaining timeout. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::DeadlineExpired`] when the budget is exhausted. pub fn ttrpc_context( &self, local_wall_clock_ms: u64, @@ -73,6 +92,7 @@ impl DeadlineBudget { )) } + /// Normalize a peer timeout: non-positive values become `None`. pub fn peer_timeout(timeout_nano: i64) -> Option { u64::try_from(timeout_nano).ok().filter(|value| *value != 0) } diff --git a/packages/d2b-session/src/lifecycle.rs b/packages/d2b-session/src/lifecycle.rs index f284d9bf7..65e7530e1 100644 --- a/packages/d2b-session/src/lifecycle.rs +++ b/packages/d2b-session/src/lifecycle.rs @@ -6,19 +6,29 @@ use d2b_contracts_zone_session::v3::component_session::{ use crate::{Result, SessionError}; +/// Phase of a component session lifecycle. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SessionPhase { + /// The session is established and exchanging records. Established, + /// The session lost its transport and is not yet reconnecting. Disconnected, + /// A reconnect attempt is in progress. Reconnecting, + /// The session is closing. Closing, + /// The session is closed. Closed, } +/// Action a keepalive poll asks the caller to take. #[derive(Clone, Copy, PartialEq, Eq)] pub enum KeepaliveAction { + /// No action is due. None, + /// Send a keepalive ping carrying the given record. SendPing(KeepaliveRecord), + /// Close the session with the given record. Close(CloseRecord), } @@ -35,6 +45,7 @@ impl fmt::Debug for KeepaliveAction { } } +/// Tracks session phase, generation, keepalive state, and reconnect budget. pub struct SessionLifecycle { phase: SessionPhase, generation: u64, @@ -47,6 +58,12 @@ pub struct SessionLifecycle { } impl SessionLifecycle { + /// Construct an established lifecycle for one generation. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::GenerationMismatch`] when `generation` is zero, + /// and the limit-profile validation error when `limits` is invalid. pub fn new(generation: u64, limits: LimitProfile, now: Instant) -> Result { limits.validate()?; if generation == 0 { @@ -64,20 +81,28 @@ impl SessionLifecycle { }) } + /// Return the current phase. pub fn phase(&self) -> SessionPhase { self.phase } + /// Return the current generation. pub fn generation(&self) -> u64 { self.generation } + /// Record transport activity while established, refreshing the keepalive idle clock. pub fn on_activity(&mut self, now: Instant) { if self.phase == SessionPhase::Established { self.last_activity = now; } } + /// Decide the keepalive action due at `now`. + /// + /// Returns `SendPing` when the keepalive interval elapsed without a pending + /// ping, `Close` when the ping timeout elapsed or ping nonces are exhausted, + /// and `None` otherwise. pub fn poll_keepalive(&mut self, now: Instant) -> KeepaliveAction { if self.phase != SessionPhase::Established { return KeepaliveAction::None; @@ -123,6 +148,13 @@ impl SessionLifecycle { }) } + /// Accept a pong for the pending ping. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::GenerationMismatch`] when the pong generation + /// differs, and [`SessionErrorCode::UnknownControl`] when the pong does not + /// match the pending ping. pub fn receive_pong(&mut self, pong: KeepaliveRecord, now: Instant) -> Result<()> { if pong.reconnect_generation != self.generation { return Err(SessionError::new(SessionErrorCode::GenerationMismatch)); @@ -137,6 +169,7 @@ impl SessionLifecycle { } } + /// Mark the session disconnected, resetting the reconnect budget. pub fn disconnect(&mut self, now: Instant) { self.phase = SessionPhase::Disconnected; self.pending_ping = None; @@ -144,6 +177,14 @@ impl SessionLifecycle { self.reconnect_attempts = 0; } + /// Begin a reconnect attempt, advancing the generation. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::InternalInvariant`] when the phase is not + /// `Disconnected` or `Reconnecting`, [`SessionErrorCode::SessionDisconnected`] + /// when the reconnect budget or window is exhausted, and + /// [`SessionErrorCode::NonceExhausted`] when the generation overflows. pub fn begin_reconnect(&mut self, now: Instant) -> Result { if !matches!( self.phase, @@ -173,6 +214,12 @@ impl SessionLifecycle { Ok(self.generation) } + /// Mark a reconnect attempt established. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::InternalInvariant`] when the phase is not + /// `Reconnecting`. pub fn reconnect_established(&mut self, now: Instant) -> Result<()> { if self.phase != SessionPhase::Reconnecting { return Err(SessionError::new(SessionErrorCode::InternalInvariant)); @@ -185,6 +232,7 @@ impl SessionLifecycle { Ok(()) } + /// Close the session, returning the close record to emit. pub fn close(&mut self, reason: CloseReason, remediation: Remediation) -> CloseRecord { self.phase = SessionPhase::Closed; CloseRecord { diff --git a/packages/d2b-session/src/record.rs b/packages/d2b-session/src/record.rs index 23690e9fc..573433b1b 100644 --- a/packages/d2b-session/src/record.rs +++ b/packages/d2b-session/src/record.rs @@ -11,13 +11,16 @@ use crate::{EstablishedHandshake, Result, SessionError}; const REPLAY_CACHE_ENTRIES: usize = 1_024; +/// A protected record ready for the wire. pub struct ProtectedRecord(Vec); impl ProtectedRecord { + /// Borrow the wire bytes. pub fn as_bytes(&self) -> &[u8] { &self.0 } + /// Consume the record into its wire bytes. pub fn into_bytes(self) -> Vec { self.0 } @@ -33,6 +36,7 @@ impl fmt::Debug for ProtectedRecord { } } +/// Encrypts and decrypts records for one session generation. pub struct RecordProtector { transport: TransportState, limits: LimitProfile, @@ -43,6 +47,7 @@ pub struct RecordProtector { } impl RecordProtector { + /// Construct a protector from an established handshake. pub fn from_handshake(handshake: EstablishedHandshake) -> Self { Self { transport: handshake.transport, @@ -59,6 +64,14 @@ impl RecordProtector { self.generation } + /// Encrypt one record. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::ArithmeticOverflow`] on length overflow, + /// [`SessionErrorCode::QueueBackpressure`] when the ciphertext exceeds the + /// configured bound, and [`SessionErrorCode::AuthenticationFailed`] when the + /// transport refuses the message. pub fn protect( &mut self, kind: RecordKind, @@ -104,6 +117,16 @@ impl RecordProtector { Ok(ProtectedRecord(wire)) } + /// Decrypt and validate one received record. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::RecordTruncated`] or + /// [`SessionErrorCode::RecordMalformed`] for malformed wire shapes, + /// [`SessionErrorCode::RecordReplay`] for a replayed ciphertext, + /// [`SessionErrorCode::AuthenticationFailed`] when decryption fails, + /// [`SessionErrorCode::GenerationMismatch`] for a foreign generation, and + /// [`SessionErrorCode::RecordOutOfOrder`] when the sequence is not accepted. pub fn unprotect(&mut self, wire: &[u8]) -> Result<(RecordHeader, Vec)> { if wire.len() < RECORD_LENGTH_BYTES as usize { return Err(SessionError::new(SessionErrorCode::RecordTruncated)); From 5f4b05f1b6f52f8cdd6f0f56af6433f065684261 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:48:58 -0700 Subject: [PATCH 182/726] xtask: restore the ttrpc marker strip and record why the row was stale Deleting the replacement literal as dead code made the committed binding file non-reproducible and left an unknown-lints attribute in the compiled crate. Regenerating with the strip in place reproduces the committed bytes exactly. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- packages/xtask/src/main.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index a5ec00d43..bc46e50df 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -153,7 +153,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 7eef023f9 | `resource_type_authority.rs` | three statements reindented | | | `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | fc0353eb1 | `nix_inventories.rs` | applied-variant: generic S: AsRef + Display standard params (caller with Vec cannot feed &[&str]); call site passes STANDARD_RESOURCE_TYPES.as_slice() | | | `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473` | run budget exhausted mid-batch; anchors re-verified at HEAD | | -| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | dead corrupted sanitizer strip line deleted; marker appears nowhere in generated files | | +| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | skipped-stale | U2 | bbd40b6fd | packages/xtask/src/main.rs (sanitize_generated_rust) | premise false: the literal matches the ttrpc-compiler 0.8.0 marker exactly, so the strip is live. The wave's deletion was reverted - without it the committed binding file is not reproducible and the bogus attribute fails -D warnings; regeneration is byte-stable again. | | | `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | dead close-block reset replaced with scan end at closing brace | | | `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | | | | `RS-0150` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | cursor/page_token/reference moved into calls;call-site reassignment unchanged | | diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index fa7aa972f..a90adb72d 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -456,6 +456,10 @@ fn sanitize_generated_rust(path: &Path) -> Result<(), Box generated = generated.replace("#![allow(unsafe_code)]\n", ""); generated = generated.replace("#![allow(unknown_lints)]\n", ""); generated = generated.replace("#![allow(clippy::all)]\n", ""); + // Matches the ttrpc-compiler 0.8.0 marker verbatim, including its + // upstream spelling: the committed binding file must stay byte-stable + // across regeneration, so this strip is load-bearing, not dead code. + generated = generated.replace("#![allow(clipto_camel_casepy)]\n", ""); generated = generated.replace( "#![cfg_attr(rustfmt, rustfmt_skip)]\n", "#![cfg_attr(rustfmt, rustfmt::skip)]\n", From 3b574d2b1254dca47ae146682ae1df311b3ff42a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:48:58 -0700 Subject: [PATCH 183/726] docs: land the schema descriptions the wave-1 doc rows produced Eight additive description annotations on manifest types; JSON-Schema descriptions are non-semantic, so validation behaviour and the manifest version are unchanged. --- docs/reference/schemas/v2/manifest_v04.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/reference/schemas/v2/manifest_v04.json b/docs/reference/schemas/v2/manifest_v04.json index 06c169cbf..2a9b48612 100644 --- a/docs/reference/schemas/v2/manifest_v04.json +++ b/docs/reference/schemas/v2/manifest_v04.json @@ -45,6 +45,7 @@ "pattern": "^[A-Za-z0-9_][A-Za-z0-9._-]{0,63}$" }, "ObservabilityMeta": { + "description": "The reserved `_observability` block: host-wide telemetry wiring.", "type": "object", "required": [ "enabled", @@ -416,6 +417,7 @@ "additionalProperties": false }, "VmEntry": { + "description": "One VM's public roster entry, keyed by its name in the manifest.", "type": "object", "required": [ "audio", @@ -591,6 +593,7 @@ "additionalProperties": false }, "VmGracefulShutdown": { + "description": "Graceful-shutdown policy for one VM.", "type": "object", "required": [ "enable" @@ -611,6 +614,7 @@ "additionalProperties": false }, "VmLanPolicy": { + "description": "LAN policy for one VM: east-west traffic allowance and its effective value after host-wide policy is applied.", "type": "object", "required": [ "allowEastWest", @@ -627,6 +631,7 @@ "additionalProperties": false }, "VmLifecycle": { + "description": "Per-VM lifecycle policy: graceful shutdown and live activation.", "type": "object", "required": [ "gracefulShutdown" @@ -649,6 +654,7 @@ "additionalProperties": false }, "VmLiveActivation": { + "description": "Live-activation policy for one VM.", "type": "object", "properties": { "timeoutSeconds": { @@ -663,6 +669,7 @@ "additionalProperties": false }, "VmObservability": { + "description": "Per-VM observability wiring: agent socket and vsock transport.", "type": "object", "required": [ "enabled" @@ -695,6 +702,7 @@ "additionalProperties": false }, "VmShellMetadata": { + "description": "Shell-session metadata for one VM.", "type": "object", "required": [ "defaultName", From 584801e94b2bb9c28eb1bac0a97adbc1b6449d7c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:50:26 -0700 Subject: [PATCH 184/726] audit: record the second leftover slice Seven rows applied across the Azure container-apps provider and the session crate; the eviction row is declined with the E0502 evidence that its zero-clone claim cannot hold. --- .../2026-09-24-rust-skills-audit/ledger.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index bc46e50df..96fa8b1de 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -195,12 +195,12 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provid` | | | | `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied-variant | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/driver.rs` | Applied the row's sort_by comparator, fixing its misplaced-paren typo (teardown_rank().cmp().then_with(name cmp)); drops the per-row name clone. | | | `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/effects_service.rs` | Both ACA candidate lists use state.sandbox.iter().cloned().collect() (and disk_image) instead of clone().into_iter().collect(). | | -| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:156-157` | budget stop before azure-container-apps crate | | -| `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:500-501` | budget stop before azure-container-apps crate | | -| `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:527` | budget stop before azure-container-apps crate | | -| `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:417-419, src/controller.rs:469-471` | budget stop before azure-container-apps crate | | -| `RS-0168` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/controller.rs:892, src/controller.rs:903` | budget stop before azure-container-apps crate | | -| `RS-0169` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/effects.rs:450-464` | budget stop before azure-container-apps crate | | +| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | declined | U2 | | `src/controller.rs:156-157` | Cannot land as written: BTreeMap::remove(&mut self, &Q) cannot take a key borrowed from the same map (E0502, verified by cargo check); zero-clone claim refuted. Original eviction restored unchanged. | | +| `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | reconcile_observed extracts Copy lifecycle first, moves record into self.observed without clone, matches on the extracted lifecycle. Applied with RS-0166 as one considered change per packet. | | +| `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | record.id moved out of the stored record via take().expect(...).id, resolving the partial-move vs whole-record-store conflict. Deviation: on resume failure observed is None (was Some(record)). | | +| `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 9730af073 | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | Stop and delete stages clone only the sandbox id (observed.as_ref().ok_or(...)?.id.clone()) and move it into the closures; the delete-stage Stopping check reads observed.as_ref().is_some_and(..). | | +| `RS-0168` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 35da01dbd | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | one_candidate and one_disk_image consume their owned candidates via into_iter + (next(), next()) match, removing both clones; IntoIterator impls added for both candidate types in effects.rs. | | +| `RS-0169` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 48072a121 | `packages/d2b-provider-guest-azure-container-apps/src/effects.rs` | Extracted validate_refs() with the resource_type() checks, called from new() on raw args and validate() on self; validate() re-clones nothing. Deviation: helper takes the four refs, not &self. | | | `RS-0170` | `own` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied-variant | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | zeroize here lacks into_inner and From> for T; variant: std::mem::take(&mut *delivery) moves buffer out, no plain Vec copy | | | `RS-0171` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | both vm_handle sites borrow via as_ref().ok_or(AzureVmError::Ambiguous) instead of cloning | | | `RS-0172` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | pending_delete_operation_id borrowed via as_deref() instead of clone | | @@ -731,7 +731,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provide` | | | | `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759` | | | | `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/facets.rs` | Added # Errors to row_view, session_target_control, resource_uid, and the GuestTargetEffect trait's realize/delete/adopt. | | -| `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | not-started | U2 | | `src/lib.rs:7, src/effects.rs:813-882` | budget stop before azure-container-apps crate | | +| `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 8a45d2d37 | `packages/d2b-provider-guest-azure-container-apps/src/effects.rs` | Documented effects pub surface (consts, enums, opaque_id! expansion, configs, records, candidates, both effect traits) and dropped the module-level allow; crate builds under deny. | | | `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | | `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | matches() doc states the constant-time-in-presented-length guarantee | | | `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs` | # Errors sections on GuestSetupDescriptor new/from_canonical_bytes/canonical_bytes/validate_integrity/verify_with, GuestChildBatch::from_descriptor, and the health evidence constructors. | | @@ -768,7 +768,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0724` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | doc contracts on target/spec/identity accessors | | | `RS-0725` | `docs` | `d2b-resource-types` | low | actionable | leaf | applied | U2 | 61c64bf0f | `packages/d2b-resource-types/src/operation.rs` | Restored the missing spaces after commas in the OperationCtx::fds field docs. | | | `RS-0726` | `docs` | `d2b-session` | medium | actionable | leaf | applied | U2 | 6970c9d9e | `packages/d2b-session/src/handshake.rs` | first-sentence docs plus # Errors naming SessionErrorCode added to x25519_public_key, constants, HandshakeRole, HandshakeCredentials, NegotiatedOffer+accessors, encode_offer, negotiate_offer, generati | | -| `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | not-started | U2 | | `lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62` | budget stop before lifecycle.rs/record.rs/bootstrap.rs/deadline.rs item docs | | +| `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | applied | U2 | 060d34e18 | `packages/d2b-session/src/lifecycle.rs` | Added item docs with # Errors sections to the pub surface of lifecycle.rs, record.rs, bootstrap.rs, and deadline.rs (structs, enums, and all methods incl. poll_keepalive/begin_reconnect). | | | `RS-0727` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/operation.rs` | MAX_MEMBER_SPELLING_LEN const extracted with wire-bound comment; parse uses it | | | `RS-0729` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/admission.rs` | one-line docs on route-binding accessors, SessionErrorClass::as_str, SessionError accessors, TransportPacket methods | | | `RS-0730` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 6970c9d9e | `packages/d2b-session/src/transport.rs` | serialized_transport_split doc rewritten to the serialized-compatibility contract (halves must never be driven concurrently) | | From e5f3b7f25bf4cca47fd59365ecc43db6b3054c4f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:51:07 -0700 Subject: [PATCH 185/726] xtask: extract daemon-api IPC fields and variants from the syn AST Replace the hand-rolled body scanners (parse_fields, parse_variants, split_top_level_entries, extract_body, strip_non_code_lines) with direct syn AST extraction; type text is sliced from the original source via spans through a once-per-file line index, so the generated daemon-api doc stays byte-identical (gen-daemon-api reproduces it unchanged). --- packages/xtask/src/main.rs | 213 +++++++++++++------------------------ 1 file changed, 76 insertions(+), 137 deletions(-) diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index 4058ada1a..3f3954267 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -6,6 +6,8 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; +use syn::spanned::Spanned; + use clap_complete::{ generate, shells::{Bash, Fish, Zsh}, @@ -1038,10 +1040,12 @@ fn parse_rust_items( .to_string_lossy() .replace('\\', "/"); let syntax: syn::File = syn::parse_str(&text)?; + let offsets = LineOffsets::new(&text); let mut items = Vec::new(); let mut collector = IpcItemCollector { text: &text, + offsets: &offsets, file_rel: &file_rel, items: &mut items, }; @@ -1056,6 +1060,7 @@ fn parse_rust_items( /// collected, exactly like the line scanner's skip. struct IpcItemCollector<'a> { text: &'a str, + offsets: &'a LineOffsets, file_rel: &'a str, items: &'a mut Vec, } @@ -1065,16 +1070,10 @@ impl<'ast> syn::visit::Visit<'ast> for IpcItemCollector<'_> { if !matches!(item.vis, syn::Visibility::Public(_)) { return; } - // Tuple and unit structs carry no brace; their body is empty. - let body = match &item.fields { - syn::Fields::Named(fields) => slice_source( - self.text, - fields.brace_token.span.open(), - fields.brace_token.span.close(), - ), - _ => String::new(), + let fields = match &item.fields { + syn::Fields::Named(fields) => collect_named_fields(self.text, self.offsets, fields), + _ => Vec::new(), }; - let fields = parse_fields(&extract_body(&body)); self.items.push(RustItem { name: item.ident.to_string(), kind: ItemKind::Struct, @@ -1089,12 +1088,35 @@ impl<'ast> syn::visit::Visit<'ast> for IpcItemCollector<'_> { if !matches!(item.vis, syn::Visibility::Public(_)) { return; } - let body = slice_source( - self.text, - item.brace_token.span.open(), - item.brace_token.span.close(), - ); - let variants = parse_variants(&extract_body(&body)); + let variants = item + .variants + .iter() + .map(|variant| { + let name = variant.ident.to_string(); + let shape = match &variant.fields { + syn::Fields::Unit => "unit".to_string(), + syn::Fields::Named(fields) => { + let fields = collect_named_fields(self.text, self.offsets, fields); + if fields.is_empty() { + "struct {}".to_string() + } else { + format!("struct {{ {} }}", render_fields(&fields)) + } + } + syn::Fields::Unnamed(fields) => { + let tys = fields + .unnamed + .iter() + .map(|field| { + normalize_ws(&slice_span(self.text, self.offsets, Spanned::span(&field.ty))) + }) + .collect::>(); + format!("({})", tys.join(", ")) + } + }; + Variant { name, shape } + }) + .collect(); self.items.push(RustItem { name: item.ident.to_string(), kind: ItemKind::Enum, @@ -1106,140 +1128,56 @@ impl<'ast> syn::visit::Visit<'ast> for IpcItemCollector<'_> { } } -/// The original source text between a braced group's delimiters (the item's -/// body between its `{` and `}`), so the field/variant extraction below sees -/// exactly the bytes the previous line-join produced. -fn slice_source(text: &str, open: proc_macro2::Span, close: proc_macro2::Span) -> String { - let start = open.start(); - let end = close.end(); - text[line_col_to_offset(text, start.line, start.column) - ..line_col_to_offset(text, end.line, end.column)] - .to_owned() +/// Line start offsets, so a span position resolves to a byte offset in O(1) +/// instead of a per-span scan of the whole file. +struct LineOffsets { + starts: Vec, } -/// Byte offset of a 1-based line / 0-based column position. -fn line_col_to_offset(text: &str, line: usize, column: usize) -> usize { - let mut offset = 0; - for (index, line_text) in text.split_inclusive('\n').enumerate() { - if index + 1 == line { - return offset + column; +impl LineOffsets { + fn new(text: &str) -> Self { + Self { + starts: std::iter::once(0) + .chain( + text.split_inclusive('\n') + .scan(0usize, |offset, line| { + *offset += line.len(); + Some(*offset) + }), + ) + .collect(), } - offset += line_text.len(); } - offset -} -fn extract_body(item_text: &str) -> String { - let Some(open) = item_text.find('{') else { - return String::new(); - }; - let Some(close) = item_text.rfind('}') else { - return String::new(); - }; - item_text[open + 1..close].to_string() + /// Byte offset of a 1-based line / 0-based column position. + fn offset(&self, position: proc_macro2::LineColumn) -> usize { + self.starts[position.line - 1] + position.column + } } -fn parse_fields(body: &str) -> Vec { - split_top_level_entries(&strip_non_code_lines(body)) - .into_iter() - .filter_map(|entry| { - let trimmed = entry.trim(); - let (name, ty) = trimmed.split_once(':')?; - Some(Field { - name: name.trim().trim_start_matches("pub ").trim().to_string(), - ty: normalize_ws(ty), - }) - }) - .collect() +/// The original source text a span covers, so the rendered type text stays +/// byte-identical to what the hand-rolled scanners used to slice. +fn slice_span(text: &str, offsets: &LineOffsets, span: proc_macro2::Span) -> String { + text[offsets.offset(span.start())..offsets.offset(span.end())].to_owned() } -fn parse_variants(body: &str) -> Vec { - split_top_level_entries(&strip_non_code_lines(body)) - .into_iter() - .filter_map(|entry| { - let trimmed = entry.trim(); - if trimmed.is_empty() { - return None; - } - let name = trimmed - .chars() - .take_while(|ch| ch.is_ascii_alphanumeric() || *ch == '_') - .collect::(); - if name.is_empty() { - return None; - } - let rest = trimmed[name.len()..].trim(); - let shape = if rest.is_empty() { - "unit".to_string() - } else if rest.starts_with('{') { - let fields = parse_fields(&extract_body(rest)); - if fields.is_empty() { - "struct {}".to_string() - } else { - format!("struct {{ {} }}", render_fields(&fields)) - } - } else { - normalize_ws(rest) - }; - Some(Variant { name, shape }) +/// The named fields of a struct or struct-like variant, with each type text +/// taken from the original source via its span. +fn collect_named_fields( + text: &str, + offsets: &LineOffsets, + fields: &syn::FieldsNamed, +) -> Vec { + fields + .named + .iter() + .filter_map(|field| { + let name = field.ident.as_ref()?.to_string(); + let ty = normalize_ws(&slice_span(text, offsets, Spanned::span(&field.ty))); + Some(Field { name, ty }) }) .collect() } - -fn strip_non_code_lines(body: &str) -> String { - body.lines() - .filter(|line| { - let trimmed = line.trim_start(); - !trimmed.is_empty() - && !trimmed.starts_with("///") - && !trimmed.starts_with("//!") - && !trimmed.starts_with("//") - && !trimmed.starts_with("#") - }) - .collect::>() - .join("\n") -} - -fn split_top_level_entries(input: &str) -> Vec { - let mut entries = Vec::new(); - let mut current = String::new(); - let mut paren = 0i32; - let mut brace = 0i32; - let mut bracket = 0i32; - let mut angle = 0i32; - - for ch in input.chars() { - match ch { - '(' => paren += 1, - ')' => paren -= 1, - '{' => brace += 1, - '}' => brace -= 1, - '[' => bracket += 1, - ']' => bracket -= 1, - '<' => angle += 1, - '>' if angle > 0 => { - angle -= 1; - } - ',' if paren == 0 && brace == 0 && bracket == 0 && angle == 0 => { - let trimmed = current.trim(); - if !trimmed.is_empty() { - entries.push(trimmed.to_string()); - } - current.clear(); - continue; - } - _ => {} - } - current.push(ch); - } - - let trimmed = current.trim(); - if !trimmed.is_empty() { - entries.push(trimmed.to_string()); - } - entries -} - fn normalize_ws(input: &str) -> String { input.split_whitespace().collect::>().join(" ") } @@ -1613,3 +1551,4 @@ mod schema_tests { } } } + From 1a7f565e8bbcd7b65bd56ac4a355bf839ea748e8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:51:17 -0700 Subject: [PATCH 186/726] audit: record wave-1 U2 leftover outcomes in the ledger --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index b0c45599d..12b98be18 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -149,10 +149,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/guest_mode.rs` | monotonic_tick deduped into runtime_util (LazyLock per repo std; lazy init preserved} | | | `RS-0117` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | ConsoleSessionTable derives Default; manual impl deleted | | | `RS-0118` | `idiom` | `xtask` | medium | actionable | leaf | applied | U2 | 80037234d | `gen_layer_catalogs.rs` | string_array deleted; ten call sites rerouted through string_slice | | -| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | not-started | U2 | | `packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | applied-variant | U2 | e5f3b7f25 | packages/xtask/src/main.rs | fields/variants extracted from the syn AST; type text sliced from source via a once-per-file line index so the emitted doc stays byte-identical (quote is not a direct dep and ToTokens spacing would change the generated doc; normalize_ws retained for byte-identical rendering) | | | `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 7eef023f9 | `resource_type_authority.rs` | three statements reindented | | | `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | fc0353eb1 | `nix_inventories.rs` | applied-variant: generic S: AsRef + Display standard params (caller with Vec cannot feed &[&str]); call site passes STANDARD_RESOURCE_TYPES.as_slice() | | -| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | a8bc3bb0b | packages/xtask/src/gen_layer_catalogs.rs, packages/xtask/src/main.rs | ten surface_catalog blocks and the two protobuf redaction templates now raw strings; emitted text verified byte-identical (gen-layer-catalogs --check passes) | | | `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | dead corrupted sanitizer strip line deleted; marker appears nowhere in generated files | | | `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | dead close-block reset replaced with scan end at closing brace | | | `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | | | @@ -262,7 +262,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/daemon_audit.rs` | write_event* and enqueue take DaemonEvent by value, drop clone; caller migration in d2bd/src/composition.rs left to W1Daemon/orchestrator (cross-crate} | | | `RS-0231` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | check_members takes &[WorkspaceMember]; caller clones dropped; second caller borrows result | | | `RS-0236` | `own` | `xtask` | low | actionable | leaf | declined | U2 | | `production_closure.rs` | compute_* take ContextSpec by value today; ComputedContext struct owns spec; changing to &ContextSpec forces internal clones at the struct literals (= no net clone removal; E0308 evidence); reverted | | -| `RS-0238` | `own` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0238` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 16e0b183d | packages/xtask/src/blocking_census.rs | CensusBaseline built by consuming each CrateCensus; --baseline check driven from the written map via a shared check_against_baseline helper; 18 census tests pass | | | `RS-0232` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | family-knowledge exempt set keys &str pairs; probe via as_str | | | `RS-0237` | `own` | `xtask` | low | actionable | leaf | applied | U2 | be3e0744b | `production_closure.rs` | duplicate approval clone binding removed; single clone at with_approval call | | | `RS-0234` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 44a90ab5e | `provider_packaging.rs` | nix_string_list generic over AsRef; eight to_owned closures deleted | | @@ -793,9 +793,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0746` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ssh_host_key_preflight.rs` | workflow tokens dropped from doc and trace comment; 0440-with-ACL why kept | | | `RS-0750` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ch_api.rs` | consts with provenance, ChApiError variants, ChVmInfo fields,and both entry fns documented | | | `RS-0751` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/target_runtime.rs` | AdmissionBudget/AdmissionPermit/ProviderDeployment accessors documented incl. release idempotence | | -| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | not-started | U2 | | `packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packa` | run budget exhausted mid-batch; anchors re-verified at HEAD | | -| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/` | run budget exhausted mid-batch; anchors re-verified at HEAD | | -| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, pa` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | applied | U2 | a18cc6eb1 | packages/xtask/src/blocking_census.rs, packages/xtask/src/delivery/evidence.rs, packages/xtask/src/delivery/seal.rs | per-field docs added to DeniedApi, CensusBaseline.crates, OutputDigest, EvidenceRecord, SealedLane, SealedValidation, SealRecord | | +| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | applied-variant | U2 | a18cc6eb1 | packages/xtask/src/changelog.rs, packages/xtask/src/delivery/evidence.rs, packages/xtask/src/delivery/seal.rs | Errors sections added to parse_fragment, EvidenceLane::parse, EvidenceRecord::validate, SealRecord::validate; async_gate::scan_source returns ScanOutcome not Result, so no Errors section applies there | | +| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | a18cc6eb1 | packages/xtask/src/delivery/snapshot.rs, packages/xtask/src/delivery/command.rs | one-line docs added to WaveSnapshot digests/program/wave, WaveCommand as_str/parse/required_options/optional_options, WorkflowOutput ok/with_digests, WorkflowCommandHelp, and the CliOptions accessors | | | `RS-0752` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | 6668d84dd | `provider_crate_policy.rs` | four doubled parens and whiche typo fixed; the audit's trailing \. doc lines do not exist at HEAD (grep zero), so that component is stale | | | `RS-0753` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | doc comments above today_utc_iso8601 and civil_from_days naming the Hinnant algorithm, constants, and epoch fallback | | | `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | | | | `context.rs:570, context.rs:538` | | | From 618508533511f1d1e5d015c5c532535459126b61 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:53:09 -0700 Subject: [PATCH 187/726] audit: record the xtask leftover rows --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 96fa8b1de..2abea33d7 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -149,10 +149,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/guest_mode.rs` | monotonic_tick deduped into runtime_util (LazyLock per repo std; lazy init preserved} | | | `RS-0117` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | ConsoleSessionTable derives Default; manual impl deleted | | | `RS-0118` | `idiom` | `xtask` | medium | actionable | leaf | applied | U2 | 80037234d | `gen_layer_catalogs.rs` | string_array deleted; ten call sites rerouted through string_slice | | -| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | not-started | U2 | | `packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | applied-variant | U2 | e5f3b7f25 | `packages/xtask/src/main.rs` | AST extraction replaces the hand-rolled scanners; type text span-sliced via a once-per-file line index (ToTokens unusable: not a direct dep). gen-daemon-api output byte-identical. | | | `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 7eef023f9 | `resource_type_authority.rs` | three statements reindented | | | `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | fc0353eb1 | `nix_inventories.rs` | applied-variant: generic S: AsRef + Display standard params (caller with Vec cannot feed &[&str]); call site passes STANDARD_RESOURCE_TYPES.as_slice() | | -| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | a8bc3bb0b | `packages/xtask/src/gen_layer_catalogs.rs` | Ten surface_catalog blocks and the two protobuf redaction templates converted to r## raw strings; all 12 literals verified byte-identical against HEAD; gen-layer-catalogs --check passes. | | | `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | skipped-stale | U2 | bbd40b6fd | packages/xtask/src/main.rs (sanitize_generated_rust) | premise false: the literal matches the ttrpc-compiler 0.8.0 marker exactly, so the strip is live. The wave's deletion was reverted - without it the committed binding file is not reproducible and the bogus attribute fails -D warnings; regeneration is byte-stable again. | | | `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | dead close-block reset replaced with scan end at closing brace | | | `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | | | @@ -262,7 +262,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/daemon_audit.rs` | write_event* and enqueue take DaemonEvent by value, drop clone; caller migration in d2bd/src/composition.rs left to W1Daemon/orchestrator (cross-crate} | | | `RS-0231` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | check_members takes &[WorkspaceMember]; caller clones dropped; second caller borrows result | | | `RS-0236` | `own` | `xtask` | low | actionable | leaf | declined | U2 | | `production_closure.rs` | compute_* take ContextSpec by value today; ComputedContext struct owns spec; changing to &ContextSpec forces internal clones at the struct literals (= no net clone removal; E0308 evidence); reverted | | -| `RS-0238` | `own` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0238` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 16e0b183d | `packages/xtask/src/blocking_census.rs` | CensusBaseline built by consuming each CrateCensus instead of cloning crate_dir/counts; --baseline check driven from the written map via a shared helper. Check passes; 18 census tests pass. | | | `RS-0232` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | family-knowledge exempt set keys &str pairs; probe via as_str | | | `RS-0237` | `own` | `xtask` | low | actionable | leaf | applied | U2 | be3e0744b | `production_closure.rs` | duplicate approval clone binding removed; single clone at with_approval call | | | `RS-0234` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 44a90ab5e | `provider_packaging.rs` | nix_string_list generic over AsRef; eight to_owned closures deleted | | @@ -793,9 +793,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0746` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ssh_host_key_preflight.rs` | workflow tokens dropped from doc and trace comment; 0440-with-ACL why kept | | | `RS-0750` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ch_api.rs` | consts with provenance, ChApiError variants, ChVmInfo fields,and both entry fns documented | | | `RS-0751` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/target_runtime.rs` | AdmissionBudget/AdmissionPermit/ProviderDeployment accessors documented incl. release idempotence | | -| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | not-started | U2 | | `packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packa` | run budget exhausted mid-batch; anchors re-verified at HEAD | | -| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/` | run budget exhausted mid-batch; anchors re-verified at HEAD | | -| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | not-started | U2 | | `packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, pa` | run budget exhausted mid-batch; anchors re-verified at HEAD | | +| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | applied | U2 | a18cc6eb1 | `packages/xtask/src/blocking_census.rs` | Per-field doc comments added to DeniedApi, CensusBaseline.crates, OutputDigest, EvidenceRecord, SealedLane, SealedValidation, and SealRecord, naming units and serialization formats. | | +| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | applied-variant | U2 | a18cc6eb1 | `packages/xtask/src/changelog.rs` | # Errors sections added to parse_fragment, EvidenceLane::parse, EvidenceRecord::validate, SealRecord::validate. scan_source returns ScanOutcome, not Result, so no Errors section applies there. | | +| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | a18cc6eb1 | `packages/xtask/src/delivery/snapshot.rs` | One-line docs added to WaveSnapshot digests/program/wave, WaveCommand as_str/parse/required_options/optional_options, WorkflowOutput ok/with_digests, WorkflowCommandHelp, CliOptions accessors. | | | `RS-0752` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | 6668d84dd | `provider_crate_policy.rs` | four doubled parens and whiche typo fixed; the audit's trailing \. doc lines do not exist at HEAD (grep zero), so that component is stale | | | `RS-0753` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | doc comments above today_utc_iso8601 and civil_from_days naming the Hinnant algorithm, constants, and epoch fallback | | | `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | | | | `context.rs:570, context.rs:538` | | | From a5518caa05e736f9cf98d449c151c53dd531a0b0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:56:55 -0700 Subject: [PATCH 188/726] audit: record wave-1 slice 2 Twenty-five rows across the daemon composition root, five of them minimal variants - the adoption-ticket clone stays because the ticket is used after the effect runs, and the shared-effects validator now works in place. --- .../2026-09-24-rust-skills-audit/ledger.md | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 2abea33d7..eee610b94 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -136,14 +136,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U2 | f3a847c72 | `packages/d2b-unsafe-local-helper/src/systemd.rs` | Replaced the then_some/ok_or NotFound normalization with an explicit if-let/if-error branch in terminate_scope and stop_scope; cargo check and test green. | | | `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | 932616e19 | `packages/d2b-zone-routing/src/resolver.rs` | longest_suffix_match is a find_map over the index range | | | `RS-0105` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | c8defa1f4 | `packages/d2b-zone-routing/src/service.rs` | ZoneTopologyRequest derives Default; manual impl deleted | | -| `RS-0106` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, pa` | | | -| `RS-0108` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:14699, packages/d2bd/src/composition.rs:14710, packages/d` | | | -| `RS-0109` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20450-20461, packages/d2bd/src/composition.rs:20486-20498` | | | -| `RS-0111` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_lifecycle.rs:78, packages/d2bd/src/resource_plane_v3.rs:2226` | | | -| `RS-0112` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/effect_service_actors.rs:268, packages/d2bd/src/effect_service_actors.rs` | | | -| `RS-0113` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:672, packages/d2bd/src/shared_provider_effects.rs:` | | | -| `RS-0107` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:6896` | | | -| `RS-0110` | `idiom` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:21306-21319, packages/d2bd/src/composition.rs:21291` | | | +| `RS-0106` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | caller at 4555 now calls committed_resource(3 args); deleted current_committed_resource fn | | +| `RS-0108` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | retry loop uses PROVIDER_IDENTITY_SEED_ATTEMPTS/INTERVAL consts; 30x2s rationale comment kept | | +| `RS-0109` | `idiom` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | hoisted list+dispatch above rollback split; both branches share 'activation generations unavailable' (was 'rollback generations unavailable'); no test pins strings | | +| `RS-0111` | `idiom` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 970d1dcd5,14efca7ef | `packages/d2bd/src/provider_lifecycle.rs` | if/else chains converted to match; X.id field-access is invalid in patterns so arms use guards `x if x == X.id`; factory match scrutinee wrapped in parens for let-else | | +| `RS-0112` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 6389b6473 | `packages/d2bd/src/effect_service_actors.rs` | hand-written impl Default replaced by #[derive(Default)] on EffectServiceActor and EffectServiceSupervisor | | +| `RS-0113` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 3220fd1ce,457373d5b,955abf009 | `packages/d2bd/src/forward_rendezvous.rs` | deleted dead `let _ = &mut chain;` and `let _ = error.code();`; `kind` param kept because used by assignment_fence (no dead binding existed) | | +| `RS-0107` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | deleted redundant `let setup = setup;` rebind | | +| `RS-0110` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | dropped _registry_dir/registry_dir params from qemu_media_registry_state/qemu_media_source_status; all 4 call sites updated | | | `RS-0114` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/autostart.rs` | build_autostart_plan uses iterator partition into the two sorted Vec halves | | | `RS-0115` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | fd extraction loops are filter_map+flatten collects | | | `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/guest_mode.rs` | monotonic_tick deduped into runtime_util (LazyLock per repo std; lazy init preserved} | | @@ -247,15 +247,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0213` | `own` | `d2b-session` | low | actionable | family | | | | `engine.rs:689, admission.rs:593` | | | | `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | applied | U2 | 0b8ef8ff5 | `packages/d2b-sk-frontend/src/main.rs` | main destructures Config and calls placement.into_placement() (no clone); config builds "/dev/uhid" via PathBuf::from. | | | `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | applied-variant | U2 | 6a3cf6cff | `packages/d2b-zone-routing/src/engine.rs` | Zone pair moved into the snapshot after destructuring expected; validate_snapshot checks inlined (row's first option) and gated #[cfg(test)] since consume no longer calls it | | -| `RS-0221` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_compositi` | | | -| `RS-0222` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:4057` | | | -| `RS-0216` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:359` | | | -| `RS-0218` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20404` | | | -| `RS-0217` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:181, packages/d2bd/src/resource_runtime.rs:4625, pac` | | | -| `RS-0219` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:21091` | | | -| `RS-0223` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:456, packages/d2bd/src/forward_rendezvous.rs:458-4` | | | -| `RS-0220` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20638` | | | -| `RS-0224` | `own` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:690, packages/d2bd/src/shared_provider_effect` | | | +| `RS-0221` | `own` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 9441488c0 | `packages/d2bd/src/interaction_composition.rs` | supervisor clone removed as row intended; adoption_ticket clone KEPT because process_ticket used after run_effect (self.tickets.insert); closure uses &adoption_ticket - row's remove-both not implement | | +| `RS-0222` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 274cfb3c5 | `packages/d2bd/src/process_provider_runtime.rs` | match context.owner_uid.as_ref() with Some(owner_uid) guard => with_owner_uid(owner_uid.clone()), _ => ticket | | +| `RS-0216` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | committed_provider_spec borrows row; identities.insert(row.resource_ref, ...) without clone | | +| `RS-0218` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | let zone = guard.zone() borrow; plane.zone(&zone) and format use &ZoneId | | +| `RS-0217` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | dropped .to_owned() at 9 sites; all targets impl Into parsers (verified contracts-resource identity.rs) | | +| `RS-0219` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | workload_id moved into TypedError::WorkloadAliasConflict (no clone) | | +| `RS-0223` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 3220fd1ce | `packages/d2bd/src/forward_rendezvous.rs` | dropped let zone = request.zone.clone(); zones.get(&request.zone) | | +| `RS-0220` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | ResourceName::parse(&readable) | | +| `RS-0224` | `own` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 457373d5b | `packages/d2bd/src/shared_provider_effects.rs` | validator rewritten as in-place strip/restore on &mut Value (no clone on upsert path; Option::take fixed via std::mem::take;double-validation removed; clone remains only on read-only projection path) | | | `RS-0225` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/supervisor/dag.rs` | run_split matches &state, binds reason by ref,and moves state into api_ready afterwards | | | `RS-0226` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | complete_pending takes &str; two call sites pass as_str; third kept to_string because E0505 forbids borrow+move of result in one call (deviation) | | | `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | Borrow implemented; five map lookups/removes resolve without String alloc | | @@ -776,14 +776,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0732` | `docs` | `d2b-session-unix` | low | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added # Errors to the anchor Result fns (SeqpacketSocket::from_owned/from_parent_prearmed/from_inherited_fd, UnixSeqpacketTransport::new, CreditPool::new, PidfdEvidence::new) naming their distinct fai | | | `RS-0733` | `docs` | `d2b-telemetry` | low | actionable | leaf | applied | U2 | e1fab0e9b | `packages/d2b-telemetry/src/audit_hash.rs` | Added # Errors naming the returned variants to every named item: AuditHash::parse, AuditChainLink::verify/verify_at, all eight BoundedEmitter fns, MetricFamily/MeterRegistry, RedactionGuard, validate_ | | | `RS-0734` | `docs` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | 20855634d | `packages/d2b-zone-routing/src/resolver.rs` | # Errors added to seal, ZoneServiceLimits::new, both with_runtime_admission sites, ZoneEnrollmentExpectation::new, ZoneEnrollmentAuthority::new/with_lifetime | | -| `RS-0736` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828` | | | -| `RS-0741` | `docs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/audio_dispatch.rs:372` | | | -| `RS-0737` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:438` | | | -| `RS-0738` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:292, packages/d2bd/src/resource_plane_v3.rs:1770, p` | | | -| `RS-0739` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/lib.rs:1, packages/d2bd/src/composition.rs:1` | | | -| `RS-0735` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:8294, packages/d2bd/src/resource_runtime.rs:8390, pa` | | | -| `RS-0740` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_effects.rs:91, packages/d2bd/src/provider_effects.rs:711, packa` | | | -| `RS-0742` | `docs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:1046-1049, packages/d2bd/src/forward_rendezvous.rs` | | | +| `RS-0736` | `docs` | `d2bd` | medium | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | serve and lock_only docs with # Errors sections; prose typos fixed | | +| `RS-0741` | `docs` | `d2bd` | medium | actionable | leaf | applied | U2 | 5bf7419ca | `packages/d2bd/src/audio_dispatch.rs` | dispatch_audio doc covering Status/SetVolume/Mute arms and TypedError::InternalIo surface | | +| `RS-0737` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | StaticProviderComposition::new doc + # Errors; 'first.so' typo fixed | | +| `RS-0738` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 14efca7ef | `packages/d2bd/src/resource_plane_v3.rs` | docs on PlaneResourceRegistry::new, controller_generation field, BundleIngestReport fields | | +| `RS-0739` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 154d9e775 | `packages/d2bd/src/lib.rs` | crate-level //! doc added; comma spacing typos fixed | | +| `RS-0735` | `docs` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | reused canonical d2b_contracts_resource::v3::DEFAULT_REQUEST_DEADLINE_MS (30_000) instead of new local const; why-comment added | | +| `RS-0740` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 6389b6473,4ce0faaf8,5bf7419ca | `packages/d2bd/src/effect_service_actors.rs` | # Errors sections on call, call_expected, validate_instance, dispatch, new_persistent, admit, DaemonGuestTargetSession::request | | +| `RS-0742` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 3220fd1ce | `packages/d2bd/src/forward_rendezvous.rs` | comment punctuation fixed (descriptors, attached, presents, attachments sentences) | | | `RS-0743` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/json_io.rs` | resolve_bundle_artifact_path and load_manifest documented (+# Errors) | | | `RS-0747` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | module doc plus consts, enums, HelperRegistry struct,and its 7 pub methods documented | | | `RS-0744` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/vm_start_support.rs` | VmStartNodeMode enum, vm_start_node_mode, tracked_role_id,and store-view resolver documented | | From 168e1955392d864221f399ec3e5078d6ec4e4b96 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:00:25 -0700 Subject: [PATCH 189/726] docs: land the schemas, reference, and ratchets the wave-1 doc rows produce Regenerated through make generate and the async-gate inventory writer. Fifteen schema representations shift in place - enum to oneOf for documented variants, $ref to allOf for documented reference fields - with identical validation semantics and no wire change, so no schema or manifest version moves. The inventory records the broker and daemon lines the wave shifted. --- docs/reference/cli-output/audit.schema.json | 6 + .../cli-output/auth-status.schema.json | 31 ++- docs/reference/cli-output/list.schema.json | 6 + .../cli-output/op-inspect.schema.json | 5 + docs/reference/cli-output/status.schema.json | 95 ++++++++- .../cli-output/usb-probe.schema.json | 19 +- docs/reference/daemon-api.md | 168 +++++++-------- .../schemas/v2/unsafe-local-helper-wire.json | 155 +++++++++++--- docs/reference/schemas/v2/wire-protocol.json | 71 +++++-- packages/xtask/data/async-gate-inventory.json | 192 +++++++++--------- 10 files changed, 507 insertions(+), 241 deletions(-) diff --git a/docs/reference/cli-output/audit.schema.json b/docs/reference/cli-output/audit.schema.json index 5b9171fa1..d123047f3 100644 --- a/docs/reference/cli-output/audit.schema.json +++ b/docs/reference/cli-output/audit.schema.json @@ -1,6 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "AuditOutputV2", + "description": "Full `d2b audit` output: host posture plus per-VM sidecar evidence.", "type": "object", "required": [ "autoUpgrade_commits_lock", @@ -83,6 +84,7 @@ "additionalProperties": false, "definitions": { "AuditBridgeIsolationOutputV2": { + "description": "One bridge's isolation audit evidence.", "type": "object", "required": [ "bridge", @@ -107,6 +109,7 @@ "additionalProperties": false }, "AuditSidecarsOutputV2": { + "description": "One VM's gpu/snd sidecar audit evidence.", "type": "object", "required": [ "gpu_active", @@ -131,6 +134,7 @@ "additionalProperties": false }, "AuditSshOutputV2": { + "description": "One VM's sshd password-authentication audit evidence.", "type": "object", "properties": { "PasswordAuthentication": { @@ -143,6 +147,7 @@ "additionalProperties": false }, "AuditUsbipEnvOutputV2": { + "description": "One environment's usbipd audit evidence.", "type": "object", "required": [ "backend_active", @@ -163,6 +168,7 @@ "additionalProperties": false }, "AuditVirtiofsdOutputV2": { + "description": "One VM's virtiofsd audit evidence.", "type": "object", "required": [ "caps_dropped", diff --git a/docs/reference/cli-output/auth-status.schema.json b/docs/reference/cli-output/auth-status.schema.json index fb1919cec..68c3c4ff1 100644 --- a/docs/reference/cli-output/auth-status.schema.json +++ b/docs/reference/cli-output/auth-status.schema.json @@ -1,6 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "AuthStatusOutputV2", + "description": "`d2b auth status` output for the caller.", "type": "object", "required": [ "allowedSubcommands", @@ -40,6 +41,7 @@ "additionalProperties": false, "definitions": { "AuthDeniedSubcommandV2": { + "description": "One subcommand denied to the caller, with the refusal reason.", "type": "object", "required": [ "name", @@ -56,14 +58,33 @@ "additionalProperties": false }, "AuthRoleV2": { - "type": "string", - "enum": [ - "none", - "launcher", - "admin" + "description": "The caller's authenticated role.", + "oneOf": [ + { + "description": "No role is held.", + "type": "string", + "enum": [ + "none" + ] + }, + { + "description": "Launcher scope only.", + "type": "string", + "enum": [ + "launcher" + ] + }, + { + "description": "Admin scope.", + "type": "string", + "enum": [ + "admin" + ] + } ] }, "AuthSocketStatusV2": { + "description": "One admin socket's reachability evidence.", "type": "object", "required": [ "name", diff --git a/docs/reference/cli-output/list.schema.json b/docs/reference/cli-output/list.schema.json index d4cb8f8fa..55bdf30bd 100644 --- a/docs/reference/cli-output/list.schema.json +++ b/docs/reference/cli-output/list.schema.json @@ -7,6 +7,7 @@ }, "definitions": { "ListItemOutputV2": { + "description": "One `d2b vm list` row.", "type": "object", "required": [ "graphics", @@ -114,6 +115,7 @@ "additionalProperties": false }, "QemuMediaRegistryStatus": { + "description": "The media registry's convergence state for one source.", "type": "object", "required": [ "state" @@ -132,6 +134,7 @@ "additionalProperties": false }, "QemuMediaRunnerStatus": { + "description": "Runner-side QMP media state for one VM.", "type": "object", "required": [ "preContProgress", @@ -158,6 +161,7 @@ "additionalProperties": false }, "QemuMediaSourceStatus": { + "description": "One attached media source's status.", "type": "object", "required": [ "format", @@ -190,6 +194,7 @@ "additionalProperties": false }, "QemuMediaStatus": { + "description": "Optional guest-media status attached to a VM row.", "type": "object", "required": [ "firmwareMode", @@ -213,6 +218,7 @@ "additionalProperties": false }, "VmAutostartPosture": { + "description": "Whether a VM is set to autostart, with the reason.", "type": "object", "required": [ "mode", diff --git a/docs/reference/cli-output/op-inspect.schema.json b/docs/reference/cli-output/op-inspect.schema.json index bdf21889a..e19d989e3 100644 --- a/docs/reference/cli-output/op-inspect.schema.json +++ b/docs/reference/cli-output/op-inspect.schema.json @@ -1,6 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "OpInspectOutputV1", + "description": "`op inspect` output: trace, local, and per-realm views.", "type": "object", "required": [ "command", @@ -41,6 +42,7 @@ "additionalProperties": false, "definitions": { "OpInspectDegradedOutputV1": { + "description": "One degraded scope in `op inspect` output.", "type": "object", "required": [ "reason", @@ -61,6 +63,7 @@ "additionalProperties": false }, "OpInspectLocalOutputV1": { + "description": "Local counts and source for one `op inspect` run.", "type": "object", "required": [ "gatewayCount", @@ -85,6 +88,7 @@ "additionalProperties": false }, "OpInspectRealmOutputV1": { + "description": "One realm's view in `op inspect` output.", "type": "object", "required": [ "crossRealmPolicy", @@ -115,6 +119,7 @@ "additionalProperties": false }, "OpInspectTraceOutputV1": { + "description": "Trace identifiers for one `op inspect` run.", "type": "object", "required": [ "spanId", diff --git a/docs/reference/cli-output/status.schema.json b/docs/reference/cli-output/status.schema.json index aa23ef714..fed983ee0 100644 --- a/docs/reference/cli-output/status.schema.json +++ b/docs/reference/cli-output/status.schema.json @@ -1,19 +1,36 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "StatusOutputV2", + "description": "`d2b status` output: one of the VM, inventory, or bridge-check shapes.", "anyOf": [ { - "$ref": "#/definitions/StatusVmOutputV2" + "description": "Per-VM status.", + "allOf": [ + { + "$ref": "#/definitions/StatusVmOutputV2" + } + ] }, { - "$ref": "#/definitions/StatusInventoryOutputV2" + "description": "Whole-inventory status.", + "allOf": [ + { + "$ref": "#/definitions/StatusInventoryOutputV2" + } + ] }, { - "$ref": "#/definitions/StatusBridgeCheckOutputV2" + "description": "Bridge isolation check status.", + "allOf": [ + { + "$ref": "#/definitions/StatusBridgeCheckOutputV2" + } + ] } ], "definitions": { "ApiReadyErrorV1": { + "description": "The error text of a failed api-ready wait.", "type": "object", "required": [ "error" @@ -26,24 +43,54 @@ "additionalProperties": false }, "ApiReadySimple": { - "type": "string", - "enum": [ - "yes", - "pending", - "timeout" + "description": "Closed api-ready states without an error payload.", + "oneOf": [ + { + "description": "The API became ready.", + "type": "string", + "enum": [ + "yes" + ] + }, + { + "description": "The API is still starting.", + "type": "string", + "enum": [ + "pending" + ] + }, + { + "description": "The wait timed out.", + "type": "string", + "enum": [ + "timeout" + ] + } ] }, "ApiReadyStatusV1": { + "description": "api-ready state of the last VM start in split mode.", "anyOf": [ { - "$ref": "#/definitions/ApiReadySimple" + "description": "A simple closed state.", + "allOf": [ + { + "$ref": "#/definitions/ApiReadySimple" + } + ] }, { - "$ref": "#/definitions/ApiReadyErrorV1" + "description": "A terminal error state.", + "allOf": [ + { + "$ref": "#/definitions/ApiReadyErrorV1" + } + ] } ] }, "LivePoolIntegrityOutputV1": { + "description": "Live-pool integrity verdict for one VM.", "type": "object", "required": [ "repairAttempted", @@ -120,6 +167,7 @@ "additionalProperties": false }, "QemuMediaRegistryStatus": { + "description": "The media registry's convergence state for one source.", "type": "object", "required": [ "state" @@ -138,6 +186,7 @@ "additionalProperties": false }, "QemuMediaRunnerStatus": { + "description": "Runner-side QMP media state for one VM.", "type": "object", "required": [ "preContProgress", @@ -164,6 +213,7 @@ "additionalProperties": false }, "QemuMediaSourceStatus": { + "description": "One attached media source's status.", "type": "object", "required": [ "format", @@ -196,6 +246,7 @@ "additionalProperties": false }, "QemuMediaStatus": { + "description": "Optional guest-media status attached to a VM row.", "type": "object", "required": [ "firmwareMode", @@ -219,6 +270,7 @@ "additionalProperties": false }, "RunnerParityOutputV2": { + "description": "Runner-parity evidence for one VM.", "type": "object", "required": [ "declaredRunner", @@ -239,6 +291,7 @@ "additionalProperties": false }, "StatusBridgeCheckOutputV2": { + "description": "Bridge isolation check output for one runtime.", "type": "object", "required": [ "message", @@ -263,6 +316,7 @@ "additionalProperties": false }, "StatusInventoryOutputV2": { + "description": "`d2b status --inventory` output: runtime plus one row per VM.", "type": "object", "required": [ "runtime", @@ -292,6 +346,7 @@ "additionalProperties": false }, "StatusServicesOutputV2": { + "description": "Legacy per-VM service-state map (V2).", "type": "object", "required": [ "d2b", @@ -342,6 +397,7 @@ "additionalProperties": false }, "StatusVmOutputV2": { + "description": "One VM's status row.", "type": "object", "required": [ "declaredRoles", @@ -644,6 +700,7 @@ ] }, "UsbipProbeEntry": { + "description": "One USBIP probe entry describing a bus, its owner, and the next action.", "type": "object", "required": [ "busId", @@ -654,9 +711,11 @@ ], "properties": { "busId": { + "description": "Physical bus id probed.", "type": "string" }, "candidateBusIds": { + "description": "Alternate bus ids that match the declaration.", "type": "array", "items": { "type": "string" @@ -680,9 +739,11 @@ ] }, "env": { + "description": "Environment the VM belongs to.", "type": "string" }, "followUpCommand": { + "description": "Command the operator should run next.", "type": [ "string", "null" @@ -714,15 +775,18 @@ "$ref": "#/definitions/UsbProbeEntryKind" }, "lockPath": { + "description": "Broker claim lock path.", "type": "string" }, "mediaRef": { + "description": "Media resource bound to the slot, if any.", "type": [ "string", "null" ] }, "ownerVm": { + "description": "VM currently holding the claim, if any.", "type": [ "string", "null" @@ -735,19 +799,26 @@ } }, "slot": { + "description": "Attached USB slot, if any.", "type": [ "string", "null" ] }, "sourceKind": { + "description": "How the device was discovered.", "type": [ "string", "null" ] }, "status": { - "$ref": "#/definitions/UsbipProbeStatus" + "description": "Claim status.", + "allOf": [ + { + "$ref": "#/definitions/UsbipProbeStatus" + } + ] }, "topologyPolicy": { "default": { @@ -761,6 +832,7 @@ ] }, "vm": { + "description": "VM this entry describes.", "type": "string" } }, @@ -839,6 +911,7 @@ "additionalProperties": false }, "VmAutostartPosture": { + "description": "Whether a VM is set to autostart, with the reason.", "type": "object", "required": [ "mode", diff --git a/docs/reference/cli-output/usb-probe.schema.json b/docs/reference/cli-output/usb-probe.schema.json index fd9773bc8..dfd64c6f3 100644 --- a/docs/reference/cli-output/usb-probe.schema.json +++ b/docs/reference/cli-output/usb-probe.schema.json @@ -1,6 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UsbProbeOutputV1", + "description": "`usb probe` output: the command echo plus one entry per probed device.", "type": "object", "required": [ "command", @@ -174,6 +175,7 @@ ] }, "UsbipProbeEntry": { + "description": "One USBIP probe entry describing a bus, its owner, and the next action.", "type": "object", "required": [ "busId", @@ -184,9 +186,11 @@ ], "properties": { "busId": { + "description": "Physical bus id probed.", "type": "string" }, "candidateBusIds": { + "description": "Alternate bus ids that match the declaration.", "type": "array", "items": { "type": "string" @@ -210,9 +214,11 @@ ] }, "env": { + "description": "Environment the VM belongs to.", "type": "string" }, "followUpCommand": { + "description": "Command the operator should run next.", "type": [ "string", "null" @@ -244,15 +250,18 @@ "$ref": "#/definitions/UsbProbeEntryKind" }, "lockPath": { + "description": "Broker claim lock path.", "type": "string" }, "mediaRef": { + "description": "Media resource bound to the slot, if any.", "type": [ "string", "null" ] }, "ownerVm": { + "description": "VM currently holding the claim, if any.", "type": [ "string", "null" @@ -265,19 +274,26 @@ } }, "slot": { + "description": "Attached USB slot, if any.", "type": [ "string", "null" ] }, "sourceKind": { + "description": "How the device was discovered.", "type": [ "string", "null" ] }, "status": { - "$ref": "#/definitions/UsbipProbeStatus" + "description": "Claim status.", + "allOf": [ + { + "$ref": "#/definitions/UsbipProbeStatus" + } + ] }, "topologyPolicy": { "default": { @@ -291,6 +307,7 @@ ] }, "vm": { + "description": "VM this entry describes.", "type": "string" } }, diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 390056a25..245b2d5b1 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -260,17 +260,17 @@ host reboot. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | | `PublicRequest` | enum | [`PublicRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L44) | `Capabilities`; `AuthStatus`; `List` - (ListRequest); `Status` - (StatusRequest); `Audit` - (AuditRequest); `VmStart` - (VmLifecycleRequest); `VmStop` - (VmLifecycleRequest); `VmRestart` - (VmLifecycleRequest); `Switch` - (ActivationRequest); `Boot` - (ActivationRequest); `Test` - (ActivationRequest); `Rollback` - (ActivationRequest); `UsbipBind` - (UsbipBindCliRequest); `UsbipUnbind` - (UsbipUnbindCliRequest); `UsbipProbe`; `HostPrepare` - (HostPrepareRequest); `HostDestroy` - (HostDestroyRequest); `HostReconcile` - (HostReconcileRequest); `Exec` - (ExecOp); `Console` - (ConsoleOp); `Audio` - (AudioOp); `Workload` - (WorkloadOp); `UsbSecurityKeyStatus`; `UsbSecurityKeySessions`; `UsbSecurityKeyCancel` - (d2b_contracts::security_key::SecurityKeyCancelRequest) | -| `ListRequest` | struct | [`ListRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L278) | struct { `env`: `Option`; `vm`: `Option` } | -| `StatusRequest` | struct | [`StatusRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L285) | struct { `check_bridges`: `bool`; `vm`: `Option` } | -| `AuditRequest` | struct | [`AuditRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L293) | struct { `filter`: `Option`; `format`: `AuditFormat`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | -| `VmLifecycleRequest` | struct | [`VmLifecycleRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L327) | struct { `vm`: `String`; `flags`: `MutationFlags`; `force`: `bool`; `no_wait_api`: `bool` } | -| `ActivationRequest` | struct | [`ActivationRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L347) | struct { `vm`: `String`; `to_generation`: `Option`; `flags`: `MutationFlags` } | -| `UsbipBindCliRequest` | struct | [`UsbipBindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L358) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | -| `UsbipUnbindCliRequest` | struct | [`UsbipUnbindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L367) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | -| `NamedProcessStreamRequest` | enum | [`NamedProcessStreamRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L1037) | `Stdin` - struct { `offset`: `u64`; `chunk_base64`: `String`; `eof`: `bool` }; `Read` - struct { `stream`: `ExecStream`; `offset`: `u64`; `max_len`: `u64`; `wait`: `bool`; `timeout_ms`: `u64` }; `Signal` - struct { `control_seq`: `u64`; `signo`: `u32` }; `Resize` - struct { `control_seq`: `u64`; `rows`: `u32`; `cols`: `u32` }; `CloseStdin` - struct { `offset`: `u64` }; `Cancel`; `Close`; `Wait` - struct { `timeout_ms`: `u64` } | -| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2041) | struct { `flags`: `MutationFlags` } | -| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2048) | struct { `flags`: `MutationFlags` } | -| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2060) | struct { `flags`: `MutationFlags`; `network`: `bool` } | +| `ListRequest` | struct | [`ListRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L280) | struct { `env`: `Option`; `vm`: `Option` } | +| `StatusRequest` | struct | [`StatusRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L288) | struct { `check_bridges`: `bool`; `vm`: `Option` } | +| `AuditRequest` | struct | [`AuditRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L297) | struct { `filter`: `Option`; `format`: `AuditFormat`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | +| `VmLifecycleRequest` | struct | [`VmLifecycleRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L331) | struct { `vm`: `String`; `flags`: `MutationFlags`; `force`: `bool`; `no_wait_api`: `bool` } | +| `ActivationRequest` | struct | [`ActivationRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L351) | struct { `vm`: `String`; `to_generation`: `Option`; `flags`: `MutationFlags` } | +| `UsbipBindCliRequest` | struct | [`UsbipBindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L362) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | +| `UsbipUnbindCliRequest` | struct | [`UsbipUnbindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L371) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | +| `NamedProcessStreamRequest` | enum | [`NamedProcessStreamRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L1041) | `Stdin` - struct { `offset`: `u64`; `chunk_base64`: `String`; `eof`: `bool` }; `Read` - struct { `stream`: `ExecStream`; `offset`: `u64`; `max_len`: `u64`; `wait`: `bool`; `timeout_ms`: `u64` }; `Signal` - struct { `control_seq`: `u64`; `signo`: `u32` }; `Resize` - struct { `control_seq`: `u64`; `rows`: `u32`; `cols`: `u32` }; `CloseStdin` - struct { `offset`: `u64` }; `Cancel`; `Close`; `Wait` - struct { `timeout_ms`: `u64` } | +| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2053) | struct { `flags`: `MutationFlags` } | +| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2060) | struct { `flags`: `MutationFlags` } | +| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2072) | struct { `flags`: `MutationFlags`; `network`: `bool` } | ### Broker socket request types @@ -328,13 +328,13 @@ host reboot. | `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2250) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | | `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2307) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | | `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2316) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2591) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | -| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2928) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2945) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2956) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2970) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | -| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3007) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3041) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2600) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | +| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2937) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2954) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2965) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2979) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | +| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3016) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3050) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | ### Console and audio wire types @@ -373,17 +373,17 @@ see the auto-generated tables above for the committed Rust variants. | --- | --- | --- | --- | | `PublicResponse` | enum | [`PublicResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L124) | `Capabilities` - (CapabilitiesResponse); `AuthStatus` - (AuthStatusResponse); `List` - (ListResponse); `Status` - (StatusResponse); `Audit` - (AuditResponse); `UsbipProbe` - (UsbipProbeResponse); `MutatingVerb` - (MutatingVerbResponse); `Exec` - (ExecOpResponse); `Console` - (ConsoleOpResponse); `Audio` - (AudioOpResponse); `Workload` - (WorkloadOpResponse); `UsbSecurityKeyStatus` - (d2b_contracts::security_key::SecurityKeyStatusResponse); `UsbSecurityKeySessions` - (d2b_contracts::security_key::SecurityKeySessionsResponse); `UsbSecurityKeyCancel` - (d2b_contracts::security_key::SecurityKeyCancelResponse); `Error` - (Error) | | `WorkloadOpResponse` | enum | [`WorkloadOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L175) | `List` - (WorkloadListResult); `Status` - (Box); `LauncherExec` - (LauncherExecResult) | -| `ExecOpResponse` | enum | [`ExecOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1010) | `Start` - (ExecStartResult); `DetachedCreate` - (ExecDetachedCreateResult); `WriteStdin` - (ExecWriteStdinResult); `ReadOutput` - (ExecReadOutputResult); `Signal` - (ExecControlResult); `Resize` - (ExecControlResult); `Wait` - (ExecWaitResult); `Close` - (ExecCloseResult); `List` - (ExecDetachedListResult); `Logs` - (ExecDetachedLogsResult); `Status` - (ExecDetachedStatusResult); `Kill` - (ExecDetachedKillResult) | -| `NamedProcessStreamResponse` | enum | [`NamedProcessStreamResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1137) | `Stdin` - (ExecWriteStdinResult); `Output` - (ExecReadOutputResult); `Delivered` - (ExecControlResult); `Wait` - (ExecWaitResult); `Closed` - (ExecCloseResult); `Terminal` - (ExecTerminalStatus); `Error` - (NamedProcessStreamError) | -| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1824) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | -| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2031) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | -| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2093) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | -| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2119) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | -| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2129) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | -| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2138) | struct { `vms`: `Vec`; `read_model`: `Option` } | -| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2146) | struct { `entries`: `Vec`; `read_model`: `Option` } | -| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2166) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2445) | struct { `entries`: `Vec` } | +| `ExecOpResponse` | enum | [`ExecOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1014) | `Start` - (ExecStartResult); `DetachedCreate` - (ExecDetachedCreateResult); `WriteStdin` - (ExecWriteStdinResult); `ReadOutput` - (ExecReadOutputResult); `Signal` - (ExecControlResult); `Resize` - (ExecControlResult); `Wait` - (ExecWaitResult); `Close` - (ExecCloseResult); `List` - (ExecDetachedListResult); `Logs` - (ExecDetachedLogsResult); `Status` - (ExecDetachedStatusResult); `Kill` - (ExecDetachedKillResult) | +| `NamedProcessStreamResponse` | enum | [`NamedProcessStreamResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1141) | `Stdin` - (ExecWriteStdinResult); `Output` - (ExecReadOutputResult); `Delivered` - (ExecControlResult); `Wait` - (ExecWaitResult); `Closed` - (ExecCloseResult); `Terminal` - (ExecTerminalStatus); `Error` - (NamedProcessStreamError) | +| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1836) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | +| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2043) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | +| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2105) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | +| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2131) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | +| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2141) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | +| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2150) | struct { `vms`: `Vec`; `read_model`: `Option` } | +| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2158) | struct { `entries`: `Vec`; `read_model`: `Option` } | +| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2178) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2469) | struct { `entries`: `Vec` } | ### Broker socket response types @@ -418,10 +418,10 @@ see the auto-generated tables above for the committed Rust variants. | `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2229) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | | `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2299) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | | `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2359) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | -| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2746) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | -| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2991) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | -| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3015) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | -| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3104) | struct { `notifications`: `Vec` } | +| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2755) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | +| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3000) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | +| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3024) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | +| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3113) | struct { `notifications`: `Vec` } | ## Per-VM lifecycle state @@ -490,7 +490,7 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2605) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | +| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2635) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | ### Other documented enums @@ -510,54 +510,54 @@ running live guest activation. | `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1863) | `Drain`; `Terminate` | | `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2242) | `Term`; `Kill`; `Quit` | | `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2378) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | -| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2724) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | -| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2882) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | -| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2980) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | -| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3054) | `Exited`; `Signaled`; `Killed` | -| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3092) | `ChildReaped` - (ChildReapedNotification); `Unknown` | -| `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L131) | `Lifecycle`; `Admin` | -| `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L175) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | +| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2733) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | +| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2891) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | +| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2989) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | +| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3063) | `Exited`; `Signaled`; `Killed` | +| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3101) | `ChildReaped` - (ChildReapedNotification); `Unknown` | +| `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L142) | `Lifecycle`; `Admin` | +| `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L180) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | | `ProxyReadinessStage` | enum | [`ProxyReadinessStage`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L12) | `Upstream`; `Listener`; `FirstClient` | | `ProxyReadinessState` | enum | [`ProxyReadinessState`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L24) | `Ready`; `Failed` | | `ProxyReadinessFailure` | enum | [`ProxyReadinessFailure`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L34) | `UpstreamUnavailable`; `ListenerUnavailable`; `FirstClientTimeout`; `ClientRejected`; `ChannelUnavailable` | | `ExecState` | enum | [`ExecState`](../../packages/d2b-contracts-control/src/public_wire.rs#L29) | `Created`; `Running`; `Exited`; `Signaled`; `Cancelled`; `SlowConsumerCancelled`; `ProtocolError`; `LostTarget`; `Reaped` | | `WorkloadOp` | enum | [`WorkloadOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L167) | `List` - (WorkloadListArgs); `Status` - (WorkloadStatusArgs); `LauncherExec` - (LauncherExecArgs) | -| `WorkloadAvailability` | enum | [`WorkloadAvailability`](../../packages/d2b-contracts-control/src/public_wire.rs#L207) | `Ready`; `HelperUnavailable`; `HelperStale`; `UserManagerUnavailable`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable`; `Degraded` | -| `GraphicalLaunchPosture` | enum | [`GraphicalLaunchPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L221) | `Proxied`; `NotApplicable`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable` | -| `LauncherExecDisposition` | enum | [`LauncherExecDisposition`](../../packages/d2b-contracts-control/src/public_wire.rs#L262) | `Committed`; `AlreadyCommitted` | -| `ExecStream` | enum | [`ExecStream`](../../packages/d2b-contracts-control/src/public_wire.rs#L384) | `Stdout`; `Stderr` | -| `ExecOp` | enum | [`ExecOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L675) | `Start` - (ExecStartArgs); `WriteStdin` - (ExecWriteStdinArgs); `ReadOutput` - (ExecReadOutputArgs); `Signal` - (ExecSignalArgs); `Resize` - (ExecResizeArgs); `Wait` - (ExecWaitArgs); `Close` - (ExecCloseArgs); `List` - (ExecDetachedListArgs); `Logs` - (ExecDetachedLogsArgs); `Status` - (ExecDetachedStatusArgs); `Kill` - (ExecDetachedKillArgs) | -| `ExecTerminalStatus` | enum | [`ExecTerminalStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L791) | `Exited` - struct { `code`: `i32` }; `Signaled` - struct { `signal`: `u32` }; `Error` - struct { `slug`: `String` } | -| `ExecDetachedKillOutcome` | enum | [`ExecDetachedKillOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L982) | `Cancelling`; `AlreadyTerminal` | -| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1428) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | -| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1439) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | -| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1549) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1692) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | -| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1838) | `Speaker`; `Microphone` | -| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1852) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1894) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1939) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | -| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2002) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2108) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | -| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2216) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | -| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2234) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | -| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2259) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | -| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2272) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | -| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2286) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | -| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2309) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | -| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2327) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | -| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2340) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | -| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2359) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | -| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2395) | `Usbip`; `QemuMediaSlot` | -| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2465) | `Human`; `Json` | -| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2473) | `None`; `Launcher`; `Admin` | -| `TerminalStream` | enum | [`TerminalStream`](../../packages/d2b-contracts-control/src/terminal_wire.rs#L12) | `Stdout`; `Stderr` | -| `HelperScopeKind` | enum | [`HelperScopeKind`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L57) | `LauncherApp`; `WaylandProxy` | -| `HelperScopeState` | enum | [`HelperScopeState`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L80) | `Starting`; `Active`; `Stopping`; `Exited`; `Degraded` | -| `HelperFailureCode` | enum | [`HelperFailureCode`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L263) | `InvalidRequest`; `OperationIdConflict`; `QueueFull`; `Timeout`; `UserManagerUnavailable`; `EnvironmentInvalid`; `ExecutableUnavailable`; `ScopeCreateFailed`; `ScopeIdentityMismatch`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable`; `FirstClientTimeout`; `Internal` | -| `HelperOperationDisposition` | enum | [`HelperOperationDisposition`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L282) | `Committed`; `AlreadyCommitted`; `Completed` | -| `DaemonToUnsafeLocalHelper` | enum | [`DaemonToUnsafeLocalHelper`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L308) | `HelloAccepted` - (HelperHelloAccepted); `Heartbeat` - (HelperHeartbeat); `Launch` - (Box) | -| `UnsafeLocalHelperToDaemon` | enum | [`UnsafeLocalHelperToDaemon`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L316) | `Hello` - (HelperHello); `Snapshot` - (HelperSnapshot); `Heartbeat` - (HelperHeartbeat); `Operation` - (HelperOperationResult); `Rejected` - (HelperOperationRejected) | +| `WorkloadAvailability` | enum | [`WorkloadAvailability`](../../packages/d2b-contracts-control/src/public_wire.rs#L208) | `Ready`; `HelperUnavailable`; `HelperStale`; `UserManagerUnavailable`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable`; `Degraded` | +| `GraphicalLaunchPosture` | enum | [`GraphicalLaunchPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L222) | `Proxied`; `NotApplicable`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable` | +| `LauncherExecDisposition` | enum | [`LauncherExecDisposition`](../../packages/d2b-contracts-control/src/public_wire.rs#L263) | `Committed`; `AlreadyCommitted` | +| `ExecStream` | enum | [`ExecStream`](../../packages/d2b-contracts-control/src/public_wire.rs#L388) | `Stdout`; `Stderr` | +| `ExecOp` | enum | [`ExecOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L679) | `Start` - (ExecStartArgs); `WriteStdin` - (ExecWriteStdinArgs); `ReadOutput` - (ExecReadOutputArgs); `Signal` - (ExecSignalArgs); `Resize` - (ExecResizeArgs); `Wait` - (ExecWaitArgs); `Close` - (ExecCloseArgs); `List` - (ExecDetachedListArgs); `Logs` - (ExecDetachedLogsArgs); `Status` - (ExecDetachedStatusArgs); `Kill` - (ExecDetachedKillArgs) | +| `ExecTerminalStatus` | enum | [`ExecTerminalStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L795) | `Exited` - struct { `code`: `i32` }; `Signaled` - struct { `signal`: `u32` }; `Error` - struct { `slug`: `String` } | +| `ExecDetachedKillOutcome` | enum | [`ExecDetachedKillOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L986) | `Cancelling`; `AlreadyTerminal` | +| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1440) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | +| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1451) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | +| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1561) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1704) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | +| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1850) | `Speaker`; `Microphone` | +| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1864) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1906) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1951) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | +| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2014) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2120) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | +| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2228) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | +| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2246) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | +| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2271) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | +| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2284) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | +| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2298) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | +| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2321) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | +| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2339) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | +| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2352) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | +| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2371) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | +| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2407) | `Usbip`; `QemuMediaSlot` | +| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2490) | `Human`; `Json` | +| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2498) | `None`; `Launcher`; `Admin` | +| `TerminalStream` | enum | [`TerminalStream`](../../packages/d2b-contracts-control/src/terminal_wire.rs#L13) | `Stdout`; `Stderr` | +| `HelperScopeKind` | enum | [`HelperScopeKind`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L68) | `LauncherApp`; `WaylandProxy` | +| `HelperScopeState` | enum | [`HelperScopeState`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L95) | `Starting`; `Active`; `Stopping`; `Exited`; `Degraded` | +| `HelperFailureCode` | enum | [`HelperFailureCode`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L316) | `InvalidRequest`; `OperationIdConflict`; `QueueFull`; `Timeout`; `UserManagerUnavailable`; `EnvironmentInvalid`; `ExecutableUnavailable`; `ScopeCreateFailed`; `ScopeIdentityMismatch`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable`; `FirstClientTimeout`; `Internal` | +| `HelperOperationDisposition` | enum | [`HelperOperationDisposition`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L337) | `Committed`; `AlreadyCommitted`; `Completed` | +| `DaemonToUnsafeLocalHelper` | enum | [`DaemonToUnsafeLocalHelper`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L369) | `HelloAccepted` - (HelperHelloAccepted); `Heartbeat` - (HelperHeartbeat); `Launch` - (Box) | +| `UnsafeLocalHelperToDaemon` | enum | [`UnsafeLocalHelperToDaemon`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L381) | `Hello` - (HelperHello); `Snapshot` - (HelperSnapshot); `Heartbeat` - (HelperHeartbeat); `Operation` - (HelperOperationResult); `Rejected` - (HelperOperationRejected) | | `AudioGrant` | enum | [`AudioGrant`](../../packages/d2b-contracts/src/audio.rs#L79) | `On`; `Off` | | `Capability` | enum | [`Capability`](../../packages/d2b-contracts/src/capability.rs#L29) | `Lifecycle`; `Exec`; `Pty`; `Logs`; `FileCopy`; `PortForward`; `PersistentShell`; `Vsock`; `Virtiofs`; `WindowForwarding`; `DisplayStreaming`; `Clipboard`; `AudioPlayback`; `AudioCapture`; `Hid`; `Usb`; `GpuAccel`; `Snapshots`; `Hotplug`; `EphemeralSessions`; `ProviderManagedIsolation`; `ConfiguredLaunch` | | `RealmControllerRuntimeState` | enum | [`RealmControllerRuntimeState`](../../packages/d2b-contracts/src/controller_config.rs#L184) | `MetadataOnly` | @@ -645,14 +645,14 @@ the failure class, for example `host check`, `audit`, `status`, or | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | | `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L970) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2529) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | -| `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L194) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | +| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2538) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | +| `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L199) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | -| `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1204) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | -| `NamedProcessStreamError` | struct | [`NamedProcessStreamError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1224) | struct { `kind`: `NamedProcessStreamErrorKind` } | -| `ShellNameError` | struct | [`ShellNameError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1297) | empty struct | -| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1875) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | -| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1976) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | +| `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1208) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | +| `NamedProcessStreamError` | struct | [`NamedProcessStreamError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1228) | struct { `kind`: `NamedProcessStreamErrorKind` } | +| `ShellNameError` | struct | [`ShellNameError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1309) | empty struct | +| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1887) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | +| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1988) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | | `LevelPercentError` | enum | [`LevelPercentError`](../../packages/d2b-contracts/src/audio.rs#L28) | `OutOfRange` - (u8) | | `AudioPolicyError` | enum | [`AudioPolicyError`](../../packages/d2b-contracts/src/audio.rs#L216) | `InvalidJson` - (String); `InvalidField` - (String); `UnknownSchemaVersion` - (String); `Serialize` - (String) | | `AuditExportErrorCode` | enum | [`AuditExportErrorCode`](../../packages/d2b-contracts/src/audit_wire.rs#L20) | `HashBreak`; `RecordInvalid`; `ReadFailed` | diff --git a/docs/reference/schemas/v2/unsafe-local-helper-wire.json b/docs/reference/schemas/v2/unsafe-local-helper-wire.json index aef20166f..343ab97b0 100644 --- a/docs/reference/schemas/v2/unsafe-local-helper-wire.json +++ b/docs/reference/schemas/v2/unsafe-local-helper-wire.json @@ -1,6 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "UnsafeLocalHelperWireSchema", + "description": "The complete helper wire schema: version plus both frame directions.", "type": "object", "required": [ "daemonToHelper", @@ -23,8 +24,10 @@ "additionalProperties": false, "definitions": { "DaemonToUnsafeLocalHelper": { + "description": "One frame the daemon may send to the helper.", "oneOf": [ { + "description": "The greeting was accepted.", "type": "object", "required": [ "payload", @@ -43,6 +46,7 @@ } }, { + "description": "A liveness frame.", "type": "object", "required": [ "payload", @@ -61,6 +65,7 @@ } }, { + "description": "A launch request.", "type": "object", "required": [ "payload", @@ -81,25 +86,37 @@ ] }, "HelperFailureCode": { - "type": "string", - "enum": [ - "invalid-request", - "operation-id-conflict", - "queue-full", - "timeout", - "user-manager-unavailable", - "environment-invalid", - "executable-unavailable", - "scope-create-failed", - "scope-identity-mismatch", - "graphical-session-inactive", - "wayland-unavailable", - "proxy-unavailable", - "first-client-timeout", - "internal" + "description": "Closed failure code one helper operation can report.", + "oneOf": [ + { + "type": "string", + "enum": [ + "operation-id-conflict", + "queue-full", + "timeout", + "user-manager-unavailable", + "environment-invalid", + "executable-unavailable", + "scope-create-failed", + "scope-identity-mismatch", + "graphical-session-inactive", + "wayland-unavailable", + "proxy-unavailable", + "first-client-timeout", + "internal" + ] + }, + { + "description": "The request was malformed or out of bounds.", + "type": "string", + "enum": [ + "invalid-request" + ] + } ] }, "HelperHeartbeat": { + "description": "Liveness frame carrying the generation and a monotonic sequence.", "type": "object", "required": [ "generation", @@ -120,6 +137,7 @@ "additionalProperties": false }, "HelperHello": { + "description": "Helper-to-daemon greeting naming the protocol version and generation.", "type": "object", "required": [ "generation", @@ -147,6 +165,7 @@ "additionalProperties": false }, "HelperHelloAccepted": { + "description": "Daemon-to-helper acceptance of a greeting, pinning interval bounds.", "type": "object", "required": [ "generation", @@ -179,6 +198,7 @@ "additionalProperties": false }, "HelperLaunchRequest": { + "description": "One launch request the daemon commits to the helper.\n\nThe workload target, item id, and argv are redacted in `Debug`.", "type": "object", "required": [ "argv", @@ -224,14 +244,33 @@ "additionalProperties": false }, "HelperOperationDisposition": { - "type": "string", - "enum": [ - "committed", - "already-committed", - "completed" + "description": "How a helper operation settled.", + "oneOf": [ + { + "description": "The operation was newly committed.", + "type": "string", + "enum": [ + "committed" + ] + }, + { + "description": "The operation was already committed before.", + "type": "string", + "enum": [ + "already-committed" + ] + }, + { + "description": "The operation finished.", + "type": "string", + "enum": [ + "completed" + ] + } ] }, "HelperOperationRejected": { + "description": "Refusal of one helper operation with its closed failure code.", "type": "object", "required": [ "code", @@ -254,6 +293,7 @@ "additionalProperties": false }, "HelperOperationResult": { + "description": "Outcome of one committed helper operation.", "type": "object", "required": [ "disposition", @@ -286,13 +326,26 @@ "additionalProperties": false }, "HelperScopeKind": { - "type": "string", - "enum": [ - "launcher-app", - "wayland-proxy" + "description": "The kind of workload scope the helper runs.", + "oneOf": [ + { + "description": "A launcher application scope.", + "type": "string", + "enum": [ + "launcher-app" + ] + }, + { + "description": "A Wayland proxy scope.", + "type": "string", + "enum": [ + "wayland-proxy" + ] + } ] }, "HelperScopeSnapshot": { + "description": "One scope's observed state in a helper snapshot.", "type": "object", "required": [ "operationId", @@ -317,16 +370,47 @@ "additionalProperties": false }, "HelperScopeState": { - "type": "string", - "enum": [ - "starting", - "active", - "stopping", - "exited", - "degraded" + "description": "Lifecycle state of one helper scope.", + "oneOf": [ + { + "description": "The scope is being set up.", + "type": "string", + "enum": [ + "starting" + ] + }, + { + "description": "The scope is serving.", + "type": "string", + "enum": [ + "active" + ] + }, + { + "description": "The scope is tearing down.", + "type": "string", + "enum": [ + "stopping" + ] + }, + { + "description": "The scope has exited.", + "type": "string", + "enum": [ + "exited" + ] + }, + { + "description": "The scope is serving degraded.", + "type": "string", + "enum": [ + "degraded" + ] + } ] }, "HelperSnapshot": { + "description": "Bounded snapshot of every scope the helper currently runs.", "type": "object", "required": [ "generation", @@ -392,6 +476,7 @@ "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" }, "ScopeIdentity": { + "description": "Opaque identity of one helper scope; the invocation id is redacted.", "type": "object", "required": [ "invocationId", @@ -408,8 +493,10 @@ "additionalProperties": false }, "UnsafeLocalHelperToDaemon": { + "description": "One frame the helper may send to the daemon.", "oneOf": [ { + "description": "The initial greeting.", "type": "object", "required": [ "payload", @@ -428,6 +515,7 @@ } }, { + "description": "A scope snapshot.", "type": "object", "required": [ "payload", @@ -446,6 +534,7 @@ } }, { + "description": "A liveness frame.", "type": "object", "required": [ "payload", @@ -464,6 +553,7 @@ } }, { + "description": "A committed operation outcome.", "type": "object", "required": [ "payload", @@ -482,6 +572,7 @@ } }, { + "description": "A refused operation.", "type": "object", "required": [ "payload", diff --git a/docs/reference/schemas/v2/wire-protocol.json b/docs/reference/schemas/v2/wire-protocol.json index b0fa084d4..6015cb158 100644 --- a/docs/reference/schemas/v2/wire-protocol.json +++ b/docs/reference/schemas/v2/wire-protocol.json @@ -798,6 +798,7 @@ ] }, "AuditRequest": { + "description": "`audit` query: filter, format, cursor, and page limit.", "type": "object", "properties": { "cursor": { @@ -877,6 +878,7 @@ "additionalProperties": false }, "AuditSelector": { + "description": "Audit entry filters: scope, severity, and outcome facets.", "type": "object", "properties": { "env": { @@ -960,6 +962,7 @@ "additionalProperties": false }, "BridgeCheck": { + "description": "One bridge-presence check result.", "type": "object", "required": [ "bridge", @@ -4500,31 +4503,31 @@ "additionalProperties": false }, "FdKind": { - "description": "The kernel kind one forwarded descriptor must present.from\n\nThe kind is declared per descriptor on the wire,index-aligned with the fd-index declarations,and validated against the received descriptor's fstat mode on the receiving leg;a mismatch is the [`FD_LEG`] refusal。", + "description": "The kernel kind one forwarded descriptor must present. From\n\nThe kind is declared per descriptor on the wire, index-aligned with the fd-index declarations, and validated against the received descriptor's fstat mode on the receiving leg; a mismatch is the [`FD_LEG`] refusal.", "oneOf": [ { - "description": "A FIFO (pipe) end。", + "description": "A FIFO (pipe) end.", "type": "string", "enum": [ "fifo" ] }, { - "description": "A socket。", + "description": "A socket.", "type": "string", "enum": [ "socket" ] }, { - "description": "A character device。", + "description": "A character device.", "type": "string", "enum": [ "char-device" ] }, { - "description": "A block device。", + "description": "A block device.", "type": "string", "enum": [ "block-device" @@ -4538,14 +4541,14 @@ ] }, { - "description": "A regular file。", + "description": "A regular file.", "type": "string", "enum": [ "regular" ] }, { - "description": "A directory。", + "description": "A directory.", "type": "string", "enum": [ "directory" @@ -5148,6 +5151,7 @@ "minimum": 0.0 }, "ListEntry": { + "description": "One `list` result row.", "type": "object", "required": [ "graphics", @@ -5265,6 +5269,7 @@ "additionalProperties": false }, "ListRequest": { + "description": "`list` query filters: an optional environment and VM name.", "type": "object", "properties": { "env": { @@ -6507,6 +6512,7 @@ ] }, "PublicVmServices": { + "description": "The observed service-state map of one VM.", "type": "object", "required": [ "d2b", @@ -6892,6 +6898,7 @@ "additionalProperties": false }, "QemuMediaRegistryStatus": { + "description": "The media registry's convergence state for one source.", "type": "object", "required": [ "state" @@ -6910,6 +6917,7 @@ "additionalProperties": false }, "QemuMediaRunnerStatus": { + "description": "Runner-side QMP media state for one VM.", "type": "object", "required": [ "preContProgress", @@ -6936,6 +6944,7 @@ "additionalProperties": false }, "QemuMediaSourceStatus": { + "description": "One attached media source's status.", "type": "object", "required": [ "format", @@ -6968,6 +6977,7 @@ "additionalProperties": false }, "QemuMediaStatus": { + "description": "Optional guest-media status attached to a VM row.", "type": "object", "required": [ "firmwareMode", @@ -7294,6 +7304,7 @@ "additionalProperties": false }, "RuntimeSummary": { + "description": "The active runner plus its capability and service summaries.", "type": "object", "required": [ "detail" @@ -7835,6 +7846,7 @@ "additionalProperties": false }, "StatusRequest": { + "description": "`status` query: optionally check bridges and select one VM.", "type": "object", "properties": { "checkBridges": { @@ -7968,6 +7980,7 @@ "additionalProperties": false }, "TerminalSize": { + "description": "Terminal dimensions in rows and columns.", "type": "object", "required": [ "cols", @@ -7975,11 +7988,13 @@ ], "properties": { "cols": { + "description": "Column count.", "type": "integer", "format": "uint32", "minimum": 0.0 }, "rows": { + "description": "Row count.", "type": "integer", "format": "uint32", "minimum": 0.0 @@ -7988,10 +8003,22 @@ "additionalProperties": false }, "TerminalStream": { - "type": "string", - "enum": [ - "stdout", - "stderr" + "description": "Which output stream a terminal read targets.", + "oneOf": [ + { + "description": "Standard output.", + "type": "string", + "enum": [ + "stdout" + ] + }, + { + "description": "Standard error.", + "type": "string", + "enum": [ + "stderr" + ] + } ] }, "UsbProbeEntryKind": { @@ -8281,6 +8308,7 @@ ] }, "UsbipProbeEntry": { + "description": "One USBIP probe entry describing a bus, its owner, and the next action.", "type": "object", "required": [ "busId", @@ -8291,9 +8319,11 @@ ], "properties": { "busId": { + "description": "Physical bus id probed.", "type": "string" }, "candidateBusIds": { + "description": "Alternate bus ids that match the declaration.", "type": "array", "items": { "type": "string" @@ -8317,9 +8347,11 @@ ] }, "env": { + "description": "Environment the VM belongs to.", "type": "string" }, "followUpCommand": { + "description": "Command the operator should run next.", "type": [ "string", "null" @@ -8351,15 +8383,18 @@ "$ref": "#/definitions/UsbProbeEntryKind" }, "lockPath": { + "description": "Broker claim lock path.", "type": "string" }, "mediaRef": { + "description": "Media resource bound to the slot, if any.", "type": [ "string", "null" ] }, "ownerVm": { + "description": "VM currently holding the claim, if any.", "type": [ "string", "null" @@ -8372,19 +8407,26 @@ } }, "slot": { + "description": "Attached USB slot, if any.", "type": [ "string", "null" ] }, "sourceKind": { + "description": "How the device was discovered.", "type": [ "string", "null" ] }, "status": { - "$ref": "#/definitions/UsbipProbeStatus" + "description": "Claim status.", + "allOf": [ + { + "$ref": "#/definitions/UsbipProbeStatus" + } + ] }, "topologyPolicy": { "default": { @@ -8398,6 +8440,7 @@ ] }, "vm": { + "description": "VM this entry describes.", "type": "string" } }, @@ -8616,6 +8659,7 @@ "type": "string" }, "VmAutostartPosture": { + "description": "Whether a VM is set to autostart, with the reason.", "type": "object", "required": [ "mode", @@ -8632,6 +8676,7 @@ "additionalProperties": false }, "VmLifecycle": { + "description": "The lifecycle envelope of one VM.", "type": "object", "required": [ "pendingRestart", @@ -8721,6 +8766,7 @@ ] }, "VmStatus": { + "description": "One `status` VM row.", "type": "object", "required": [ "bridgeChecks", @@ -8982,6 +9028,7 @@ "additionalProperties": false }, "WorkloadListArgs": { + "description": "Workload-list query; the realm filters the result.", "type": "object", "properties": { "realm": { diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index cd769e72a..ebecf8ef2 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -3,12 +3,12 @@ "sites": [ { "file": "packages/d2b-broker/src/ops/host_generation_handoff.rs", - "line": 245, + "line": 250, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { "file": "packages/d2b-broker/src/ops/host_generation_handoff.rs", - "line": 490, + "line": 495, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { @@ -53,32 +53,32 @@ }, { "file": "packages/d2b-broker/src/ops/nm.rs", - "line": 539, + "line": 544, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/ops/nm.rs", - "line": 565, + "line": 570, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/ops/route.rs", - "line": 239, + "line": 243, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { "file": "packages/d2b-broker/src/ops/route.rs", - "line": 240, + "line": 244, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { "file": "packages/d2b-broker/src/ops/route.rs", - "line": 276, + "line": 280, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { "file": "packages/d2b-broker/src/ops/route.rs", - "line": 310, + "line": 314, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { @@ -183,87 +183,87 @@ }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1109, + "line": 1108, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1122, + "line": 1121, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1123, + "line": 1122, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1146, + "line": 1145, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1150, + "line": 1149, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1167, + "line": 1166, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1169, + "line": 1168, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1638, + "line": 1637, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1649, + "line": 1648, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1652, + "line": 1651, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1676, + "line": 1675, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1725, + "line": 1724, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1809, + "line": 1808, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1865, + "line": 1864, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1923, + "line": 1922, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/session.rs", - "line": 386, + "line": 398, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/session.rs", - "line": 445, + "line": 457, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -303,32 +303,32 @@ }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 233, + "line": 232, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 234, + "line": 233, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 238, + "line": 237, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 239, + "line": 238, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 243, + "line": 242, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 244, + "line": 243, "reason": "test-support recorder lock" }, { @@ -408,17 +408,17 @@ }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 865, + "line": 876, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 874, + "line": 885, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 887, + "line": 898, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -513,62 +513,62 @@ }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1612, + "line": 1621, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1619, + "line": 1628, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1631, + "line": 1640, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1632, + "line": 1641, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1667, + "line": 1676, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1694, + "line": 1703, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1700, + "line": 1709, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1707, + "line": 1716, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1713, + "line": 1722, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1720, + "line": 1729, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1747, + "line": 1756, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1755, + "line": 1764, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -633,17 +633,17 @@ }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 643, + "line": 642, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 743, + "line": 742, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 744, + "line": 743, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -898,37 +898,37 @@ }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1218, + "line": 1231, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1235, + "line": 1248, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1251, + "line": 1264, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1262, + "line": 1275, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1276, + "line": 1289, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1278, + "line": 1291, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1302, + "line": 1315, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -963,42 +963,42 @@ }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 802, + "line": 803, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 819, + "line": 820, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 835, + "line": 836, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 843, + "line": 844, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 857, + "line": 858, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 859, + "line": 860, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1129, + "line": 1130, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1317, + "line": 1318, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1033,127 +1033,127 @@ }, { "file": "packages/d2bd-runtime/src/autostart.rs", - "line": 787, + "line": 782, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/autostart.rs", - "line": 792, + "line": 787, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1708, + "line": 1735, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1719, + "line": 1746, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1725, + "line": 1752, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1813, + "line": 1840, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1815, + "line": 1842, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1817, + "line": 1844, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2158, + "line": 2185, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2279, + "line": 2306, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2297, + "line": 2324, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2307, + "line": 2334, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2327, + "line": 2354, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2343, + "line": 2370, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2356, + "line": 2383, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2359, + "line": 2386, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2370, + "line": 2397, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2380, + "line": 2407, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2421, + "line": 2448, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 10701, + "line": 10731, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26155, + "line": 26171, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26552, + "line": 26568, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_plane_v3.rs", - "line": 6754, + "line": 6742, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 2509, + "line": 2508, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 7513, + "line": 7510, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1163,37 +1163,37 @@ }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1585, + "line": 1602, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1633, + "line": 1650, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1658, + "line": 1675, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2093, + "line": 2110, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2480, + "line": 2497, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2513, + "line": 2530, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2569, + "line": 2586, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 68dc43e550f43995669e3bf6e4efd4e8649cf3cb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:02:36 -0700 Subject: [PATCH 190/726] resource-contracts: share the v3 uniqueness checks and document the bounded types Adds a crate-private uniqueness helper the volume, process, and execution-plan paths share, derives the DHCP default instead of hand-writing it, iterates the canonical object through a borrowed iterator, and documents the artifact, limits, and volume-state contracts. --- .../d2b-contracts-resource/src/v3/artifact.rs | 6 +++++ .../src/v3/execution_policy.rs | 19 ++++++++++----- .../d2b-contracts-resource/src/v3/limits.rs | 8 +++++++ .../d2b-contracts-resource/src/v3/network.rs | 16 +++---------- .../d2b-contracts-resource/src/v3/process.rs | 13 +++-------- .../d2b-contracts-resource/src/v3/resource.rs | 9 ++------ .../src/v3/resource_schema.rs | 5 ++++ .../d2b-contracts-resource/src/v3/volume.rs | 23 ++++--------------- .../src/v3/volume_state.rs | 2 +- 9 files changed, 46 insertions(+), 55 deletions(-) diff --git a/packages/d2b-contracts-resource/src/v3/artifact.rs b/packages/d2b-contracts-resource/src/v3/artifact.rs index 53ba8cbc1..7be02dd21 100644 --- a/packages/d2b-contracts-resource/src/v3/artifact.rs +++ b/packages/d2b-contracts-resource/src/v3/artifact.rs @@ -2,10 +2,12 @@ use serde::{Deserialize, Deserializer, Serialize}; use super::execution_policy::{BoundedToken, string_schema}; +/// Upper bound on artifact identifier bytes, mirroring the bounded-token ceiling. pub const MAX_ARTIFACT_ID_BYTES: usize = 63; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ArtifactIdError { + /// The identifier was empty, over bound, or malformed as a lower-kebab token. Invalid, } @@ -19,9 +21,12 @@ impl std::error::Error for ArtifactIdError {} #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] +/// A validated bounded lower-kebab artifact identifier, never a host path. pub struct ArtifactId(BoundedToken); impl ArtifactId { + /// Parse a bounded lower-kebab artifact identifier, rejecting empty, + /// over-bound, and malformed forms. pub fn parse(value: impl Into) -> Result { let value = value.into(); if value.len() > MAX_ARTIFACT_ID_BYTES { @@ -32,6 +37,7 @@ impl ArtifactId { .map_err(|_| ArtifactIdError::Invalid) } + /// Borrow the validated identifier as its canonical lower-kebab string. pub fn as_str(&self) -> &str { self.0.as_str() } diff --git a/packages/d2b-contracts-resource/src/v3/execution_policy.rs b/packages/d2b-contracts-resource/src/v3/execution_policy.rs index 016cb0b4b..3603cd9fa 100644 --- a/packages/d2b-contracts-resource/src/v3/execution_policy.rs +++ b/packages/d2b-contracts-resource/src/v3/execution_policy.rs @@ -171,6 +171,18 @@ pub fn require_execution_ref(reference: &ResourceRef) -> Result<(), PrimitiveSpe } } +/// Ensure a collection that must be unique carries no duplicate entry. +pub(crate) fn ensure_unique(values: &[T]) -> Result<(), PrimitiveSpecError> { + let mut sorted = values.to_vec(); + sorted.sort_unstable(); + sorted.dedup(); + if sorted.len() == values.len() { + Ok(()) + } else { + Err(PrimitiveSpecError::DuplicateEntry) + } +} + /// Render one base-spec value as a `ResourceSpec` base object. /// /// Primitive base specs are Layer 2 data, so the rendered object never @@ -790,12 +802,7 @@ impl ExecutionPolicy { if allowed_domains.is_empty() || allowed_domains.len() > 2 { return Err(PrimitiveSpecError::TooManyEntries); } - let mut unique = allowed_domains.clone(); - unique.sort_unstable(); - unique.dedup(); - if unique.len() != allowed_domains.len() { - return Err(PrimitiveSpecError::DuplicateEntry); - } + ensure_unique(&allowed_domains)?; if !allowed_domains.contains(&default_domain) { return Err(PrimitiveSpecError::ConflictingFields); } diff --git a/packages/d2b-contracts-resource/src/v3/limits.rs b/packages/d2b-contracts-resource/src/v3/limits.rs index 08ca5cf95..6d7db7d70 100644 --- a/packages/d2b-contracts-resource/src/v3/limits.rs +++ b/packages/d2b-contracts-resource/src/v3/limits.rs @@ -1,4 +1,12 @@ //! Frozen resource API admission limits. +//! +//! These ceilings cap resource API admission: request envelope, response, +//! batch, and list bounds size a single admission round-trip;watch bounds cap +//! per-session and per-zone credits, filters, and queue growth;deadline bounds +//! cap request admission wait, with separate expedited and per-principal concurrency +//! ceilings;and role bounds cap role rule graphs and bindings. The `DEFAULT_` +//! variants name the fallback applied when a caller omits the corresponding field. +//! Byte ceilings are raw bytes;deadline ceilings are raw milliseconds. pub const MAX_REQUEST_CANONICAL_BYTES: usize = 512 * 1024; pub const MAX_RESPONSE_CANONICAL_BYTES: usize = 512 * 1024; diff --git a/packages/d2b-contracts-resource/src/v3/network.rs b/packages/d2b-contracts-resource/src/v3/network.rs index d1acac578..7804b0677 100644 --- a/packages/d2b-contracts-resource/src/v3/network.rs +++ b/packages/d2b-contracts-resource/src/v3/network.rs @@ -527,16 +527,17 @@ pub enum SharingPolicy { /// IPv4 address acquisition method. #[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, JsonSchema, )] #[serde(rename_all = "lowercase")] pub enum Ipv4Method { + #[default] Dhcp, Static, } /// External IPv4 configuration. -#[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] +#[derive(Clone, PartialEq, Eq, Default, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct ExternalIpv4Spec { method: Ipv4Method, @@ -594,17 +595,6 @@ impl ExternalIpv4Spec { } } -impl Default for ExternalIpv4Spec { - fn default() -> Self { - Self { - method: Ipv4Method::Dhcp, - address: None, - gateway: None, - dns: Vec::new(), - } - } -} - redacted_debug!(ExternalIpv4Spec); impl<'de> Deserialize<'de> for ExternalIpv4Spec { diff --git a/packages/d2b-contracts-resource/src/v3/process.rs b/packages/d2b-contracts-resource/src/v3/process.rs index 5981c69b7..917bfa33f 100644 --- a/packages/d2b-contracts-resource/src/v3/process.rs +++ b/packages/d2b-contracts-resource/src/v3/process.rs @@ -20,8 +20,8 @@ use serde::{Deserialize, Deserializer, Serialize}; use super::{ ActivationRunnerInput, ResourceRef, execution_policy::{ - BoundedToken, BudgetSpec, DurationMs, ExecutionDomain, PrimitiveSpecError, redacted_debug, - require_execution_ref, require_resource_type, + BoundedToken, BudgetSpec, DurationMs, ExecutionDomain, PrimitiveSpecError, ensure_unique, + redacted_debug, require_execution_ref, require_resource_type, }, }; @@ -1572,14 +1572,7 @@ fn check_unique(values: &[T], max: usize) -> Result<(), Primitiv if values.len() > max { return Err(PrimitiveSpecError::TooManyEntries); } - let mut sorted = values.to_vec(); - sorted.sort_unstable(); - sorted.dedup(); - if sorted.len() == values.len() { - Ok(()) - } else { - Err(PrimitiveSpecError::DuplicateEntry) - } + ensure_unique(values) } fn check_duration(value: &DurationMs, min: u64, max: u64) -> Result<(), PrimitiveSpecError> { diff --git a/packages/d2b-contracts-resource/src/v3/resource.rs b/packages/d2b-contracts-resource/src/v3/resource.rs index ca6aa41f7..e938edf0b 100644 --- a/packages/d2b-contracts-resource/src/v3/resource.rs +++ b/packages/d2b-contracts-resource/src/v3/resource.rs @@ -617,13 +617,8 @@ impl Serialize for ResourceSpec { if let Some(update_policy) = &self.update_policy { map.serialize_entry("updatePolicy", update_policy)?; } - for key in self.base.keys() { - map.serialize_entry( - key, - self.base - .get(key) - .expect("key returned by canonical object"), - )?; + for (key, value) in self.base.iter() { + map.serialize_entry(key, value)?; } if let Some(provider) = &self.provider { map.serialize_entry("provider", provider)?; diff --git a/packages/d2b-contracts-resource/src/v3/resource_schema.rs b/packages/d2b-contracts-resource/src/v3/resource_schema.rs index 1230750ae..c1d601577 100644 --- a/packages/d2b-contracts-resource/src/v3/resource_schema.rs +++ b/packages/d2b-contracts-resource/src/v3/resource_schema.rs @@ -374,6 +374,11 @@ impl CanonicalJsonObject { self.0.keys().map(String::as_str) } + /// Iterate over top-level fields in canonical order. + pub(crate) fn iter(&self) -> impl Iterator { + self.0.iter().map(|(key, value)| (key.as_str(), value)) + } + /// Look up one field. pub fn get(&self, key: &str) -> Option<&CanonicalJsonValue> { self.0.get(key) diff --git a/packages/d2b-contracts-resource/src/v3/volume.rs b/packages/d2b-contracts-resource/src/v3/volume.rs index 9c814c586..775b09d4f 100644 --- a/packages/d2b-contracts-resource/src/v3/volume.rs +++ b/packages/d2b-contracts-resource/src/v3/volume.rs @@ -20,7 +20,7 @@ use serde::{Deserialize, Deserializer, Serialize}; use super::{ ResourceRef, execution_policy::{ - BoundedToken, PrimitiveSpecError, redacted_debug, require_execution_ref, + BoundedToken, PrimitiveSpecError, ensure_unique, redacted_debug, require_execution_ref, require_resource_type, }, process::validate_octal_mode, @@ -1207,17 +1207,9 @@ impl VolumeSpec { for name in views.keys() { BoundedToken::parse(name.clone())?; } - let mut paths: Vec<&str> = layout.iter().map(LayoutEntry::path).collect(); - let declared = paths.len(); - paths.sort_unstable(); - paths.dedup(); - if paths.len() != declared { - return Err(PrimitiveSpecError::DuplicateEntry); - } + let paths: Vec<&str> = layout.iter().map(LayoutEntry::path).collect(); + ensure_unique(&paths)?; for attachment in &attachments { - if !views.contains_key(attachment.view.as_str()) { - return Err(PrimitiveSpecError::MissingRequiredField); - } let view = views .get(attachment.view.as_str()) .ok_or(PrimitiveSpecError::MissingRequiredField)?; @@ -1245,16 +1237,11 @@ impl VolumeSpec { { return Err(PrimitiveSpecError::ConflictingFields); } - let mut execution_refs: Vec = attachments + let execution_refs: Vec = attachments .iter() .map(|attachment| attachment.execution_ref.to_canonical_string()) .collect(); - let declared_execution_refs = execution_refs.len(); - execution_refs.sort_unstable(); - execution_refs.dedup(); - if execution_refs.len() != declared_execution_refs { - return Err(PrimitiveSpecError::DuplicateEntry); - } + ensure_unique(&execution_refs)?; if source.settings().kind() == SourceKind::Tmpfs { if !matches!(kind, VolumeKind::Ephemeral | VolumeKind::Tmp) { return Err(PrimitiveSpecError::ConflictingFields); diff --git a/packages/d2b-contracts-resource/src/v3/volume_state.rs b/packages/d2b-contracts-resource/src/v3/volume_state.rs index 7c833d637..33ca21f82 100644 --- a/packages/d2b-contracts-resource/src/v3/volume_state.rs +++ b/packages/d2b-contracts-resource/src/v3/volume_state.rs @@ -135,7 +135,7 @@ impl StateDigest { /// Parse exactly `sha256:<64 lower-case hex>`. pub fn parse(value: impl Into) -> Result { let value = value.into(); - SchemaFingerprint::parse(value.clone()).map_err(|_| VolumeStateError::CanonicalJson)?; + SchemaFingerprint::parse(value.as_str()).map_err(|_| VolumeStateError::CanonicalJson)?; Ok(Self(value)) } From c06e279e8f8ed67b1b4a99a107980be918a7fc8b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:02:50 -0700 Subject: [PATCH 191/726] audit: record wave-1 slice 5 Seven rows applied across the resource contracts, one of them a minimal variant because the canonical object needed a borrowed iterator; two adjacent doc rows remain for the follow-up. --- .../2026-09-24-rust-skills-audit/ledger.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index eee610b94..52214e567 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -58,10 +58,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0018` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential.rs` | derive(Default) with #[default] on RotationPolicyClass::OnExpiry and RevocationAction::Immediate; manual Default impls deleted | | | `RS-0020` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs` | producer_ref.transpose()? bound once; duplicate 15-field BindingChildIntent literal collapsed to one push, else-continue arm deleted | | | `RS-0019` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | manual Debug impl on UpgradePolicy replaced by #[derive(Debug)] | | -| `RS-0022` | `idiom` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume.rs:1210-1213, packages/d2b-contracts-resourc` | | | -| `RS-0021` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src` | | | -| `RS-0023` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/resource.rs:621-626` | | | -| `RS-0024` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223` | | | +| `RS-0022` | `idiom` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/execution_policy.rs` | crate-private ensure_unique helper shared by the volume, process, and execution-plan uniqueness checks | | +| `RS-0021` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/network.rs` | derive Default with #[default] on Ipv4Method::Dhcp; hand-written impl deleted | | +| `RS-0023` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | applied-variant | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/resource.rs` | stated fix not implementable: &CanonicalJsonObject is not IntoIterator, so a borrowed iter() was added to the type and the base is iterated through it | | +| `RS-0024` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/volume.rs` | contains_key plus re-get collapsed into one get with ok_or | | | `RS-0025` | `idiom` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | f547324ca | `packages/d2b-contracts-zone-session/src/v3/component_session.rs` | Default derived on ReceiveSequence/SendSequence; hand-written impls deleted; ZoneLinkLimits Default kept | | | `RS-0027` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | let spec = find_network_spec(&parts)?; let _ = spec; replaced by bare self.find_network_spec(&parts)?; in projection and sysctl intents | | | `RS-0030` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | iter().any(f == last) replaced with slice contains for PUBLIC_MANIFEST_FIELDS and BROAD_CAPABILITIES | | @@ -174,7 +174,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0135` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | validate_runtime_artifacts takes &[TargetRuntimeArtifacts]; entries.clone() and self.runtime_artifacts.clone() dropped; test call site updated | | | `RS-0138` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs` | is_valid_zone(&str) extracted; validate_zone delegates to it; allowed_telemetry_value no longer allocates | | | `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | dedup sets now BTreeSet<&BoundedToken>/BTreeSet<&ResourceTypeName> in ProviderManifest::new and with_state_namespaces | | -| `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/volume_state.rs:138` | | | +| `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/volume_state.rs` | SchemaFingerprint::parse takes the borrowed str instead of cloning | | | `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied-variant | U2 | 862071320 | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs` | Order-preserving contains check (n<=64) instead of sort-in-place: sorting would change serialized bytes of a signed wire message for unsorted inputs | | | `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | | `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | acffb7466 | `packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs` | Walk iterates CanonicalJsonObject keys directly; no wrapper or clone built | | @@ -690,10 +690,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | applied | U2 | e5b584959 | `packages/d2b-contracts-control/src/terminal_wire.rs` | One-line docs per DTO plus the redacted-Debug note on session-bearing types | | | `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | | `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | -| `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/` | | | -| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | | | -| `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/limits.rs:3, packages/d2b-contracts-resource/src/v3` | | | -| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | | | +| `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/artifact.rs` | doc comments on the artifact id bound, error, type, parse, and accessor | | +| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | not-started | U2 | | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | execution_policy.rs into_policy and string_schema_object docs | | +| `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/limits.rs` | module-level rationale naming the enforcing boundaries | | +| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | not-started | U2 | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | operations module doc comments in error.rs/seal.rs/mod.rs | | | `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | | | | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | | | | `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/manifest_v04.rs` | module doc plus docs on ManifestV04/ManifestMeta/ObservabilityMeta/VmEntry/VmLifecycle/VmGracefulShutdown/VmLiveActivation/VmLanPolicy/VmObservability/VmShellMetadata/ManifestShellName; # Errors on fr | | | `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | one-line docs naming the exact BundleOpId shape added to all 15 undocumented intent_id_* constructors | | From e7bba788d9600069c3d5442502b4c67df106f9ca Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:09:13 -0700 Subject: [PATCH 192/726] resource-contracts: document the execution-policy wire conversion and schema helper --- packages/d2b-contracts-resource/src/v3/execution_policy.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/d2b-contracts-resource/src/v3/execution_policy.rs b/packages/d2b-contracts-resource/src/v3/execution_policy.rs index 3603cd9fa..08a537093 100644 --- a/packages/d2b-contracts-resource/src/v3/execution_policy.rs +++ b/packages/d2b-contracts-resource/src/v3/execution_policy.rs @@ -927,6 +927,7 @@ pub struct ExecutionPolicyWire { } impl ExecutionPolicyWire { + /// Convert the wire mirror into a validated `ExecutionPolicy`. pub fn into_policy(self) -> Result { ExecutionPolicy::new( self.default_domain, @@ -948,6 +949,8 @@ fn default_allowed_domains() -> Vec { vec![ExecutionDomain::System] } +/// Build a bounded-string JSON schema; macro-support surface for the +/// exported `string_schema!` expansion. pub fn string_schema_object(min: u32, max: u32) -> schemars::schema::Schema { let mut schema = schemars::schema::SchemaObject { instance_type: Some(schemars::schema::SingleOrVec::Single(Box::new( From 712bb24af6c23b2c0e171361033732bdac6a8913 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:09:15 -0700 Subject: [PATCH 193/726] resource-contracts: document the operations module accessors --- .../d2b-contracts-resource/src/v3/operations/error.rs | 10 ++++++++++ .../d2b-contracts-resource/src/v3/operations/mod.rs | 2 ++ .../d2b-contracts-resource/src/v3/operations/seal.rs | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/packages/d2b-contracts-resource/src/v3/operations/error.rs b/packages/d2b-contracts-resource/src/v3/operations/error.rs index 49eceffab..d825647d3 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/error.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/error.rs @@ -18,6 +18,7 @@ impl MutationOrdinal { Ok(Self(u8::try_from(value).map_err(|_| MutationOrdinalError)?)) } + /// Read the zero-based batch index. pub const fn get(self) -> u32 { self.0 as u32 } @@ -47,6 +48,7 @@ impl StoreSlot { Ok(Self(u8::try_from(index).map_err(|_| StoreSlotError)?)) } + /// Read the zero-based store position. pub const fn get(self) -> u32 { self.0 as u32 } @@ -259,35 +261,43 @@ impl StoreError { } } + /// Read the error kind. pub const fn kind(&self) -> StoreErrorKind { self.kind } + /// Read the revision that caused the conflict, when present. pub const fn current_revision(&self) -> Option { self.current_revision } + /// Read the batch ordinal that caused the conflict, when present. pub const fn mutation_ordinal(&self) -> Option { self.mutation_ordinal } + /// Read the store slot the error refers to, when present. pub const fn store_slot(&self) -> Option { self.store_slot } + /// Bind the error to the store slot being operated on. pub const fn with_store_slot(mut self, store_slot: StoreSlot) -> Self { self.store_slot = Some(store_slot); self } + /// Read the suggested retry delay, when the error is retryable. pub const fn retry_after_ms(&self) -> Option { self.retry_after_ms } + /// Read the retry class. pub const fn retry_class(&self) -> RetryClass { self.retry_class } + /// Read the stable reason code. pub const fn reason_code(&self) -> &'static str { self.reason_code } diff --git a/packages/d2b-contracts-resource/src/v3/operations/mod.rs b/packages/d2b-contracts-resource/src/v3/operations/mod.rs index 1af708620..b8776ff2b 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/mod.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/mod.rs @@ -375,6 +375,7 @@ pub struct PreparedStoreMutation { } impl PreparedStoreMutation { + /// Construct a backend-ready mutation with its final identity and digest. pub const fn new( mutation: StoreMutation, resource_uid: Option, @@ -387,6 +388,7 @@ impl PreparedStoreMutation { } } + /// Borrow the prepared mutation. pub const fn mutation(&self) -> &StoreMutation { &self.mutation } diff --git a/packages/d2b-contracts-resource/src/v3/operations/seal.rs b/packages/d2b-contracts-resource/src/v3/operations/seal.rs index 7dc0a7f72..c82731857 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/seal.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/seal.rs @@ -45,6 +45,7 @@ pub struct StoreSealIdentity { } impl StoreSealIdentity { + /// Construct a seal identity for a store at its first epoch. pub fn new(slot: StoreSlot, zone: ZoneId, store_uuid: ResourceUid) -> Self { Self { slot, @@ -60,10 +61,12 @@ impl StoreSealIdentity { self } + /// Read the zone the store belongs to. pub const fn zone(&self) -> &ZoneId { &self.zone } + /// Read the store slot. pub const fn slot(&self) -> StoreSlot { self.slot } @@ -118,10 +121,12 @@ pub struct OpenedMutation { } impl OpenedMutation { + /// Borrow the opened mutation payload. pub fn body(&self) -> &MutationSealBody { &self.body } + /// Consume the opened mutation and return its payload. pub fn into_body(self) -> MutationSealBody { self.body } @@ -178,6 +183,7 @@ impl MutationSealAcceptor { diagnose_identity(&self.store, store) } + /// Read the store slot this acceptor was sealed for. pub const fn declared_slot(&self) -> StoreSlot { self.store.slot() } From 9d0eaefffd994a46436fdfbdd3001cfdf54f0d5b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:12:39 -0700 Subject: [PATCH 194/726] clipboard: collect bridge listeners and source mime preference from the allowlist --- .../src/bin/d2b-clipd.rs | 94 +++++++++---------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs index 58be4ab75..6f685af25 100644 --- a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs @@ -1128,48 +1128,49 @@ fn install_bridge_listeners( bridge_peers: &[BridgePeerConfig], ) -> Result, String> { let uid = rustix::process::getuid().as_raw(); - let mut listeners = Vec::new(); - for peer in bridge_peers { - let path = bridge_socket_path(root, uid, &peer.socket_component)?; - let parent = path - .parent() - .ok_or_else(|| format!("bridge socket has no parent: {}", path.display()))?; - std::fs::DirBuilder::new() - .recursive(true) - .mode(0o770) - .create(parent) - .map_err(|e| format!("create bridge socket dir {}: {e}", parent.display()))?; - if path.exists() { - let meta = std::fs::symlink_metadata(&path) - .map_err(|e| format!("stat bridge socket {}: {e}", path.display()))?; - if !meta.file_type().is_socket() { - return Err(format!("refusing to replace non-socket {}", path.display())); + Ok(bridge_peers + .into_iter() + .map(|peer| { + let path = bridge_socket_path(root, uid, &peer.socket_component)?; + let parent = path + .parent() + .ok_or_else(|| format!("bridge socket has no parent: {}", path.display()))?; + std::fs::DirBuilder::new() + .recursive(true) + .mode(0o770) + .create(parent) + .map_err(|e| format!("create bridge socket dir {}: {e}", parent.display()))?; + if path.exists() { + let meta = std::fs::symlink_metadata(&path) + .map_err(|e| format!("stat bridge socket {}: {e}", path.display()))?; + if !meta.file_type().is_socket() { + return Err(format!("refusing to replace non-socket {}", path.display())); + } + std::fs::remove_file(&path) + .map_err(|e| format!("remove stale bridge socket {}: {e}", path.display()))?; } - std::fs::remove_file(&path) - .map_err(|e| format!("remove stale bridge socket {}: {e}", path.display()))?; - } - // umask is process-wide: keep bridge listener installation in the - // single-threaded startup phase, before spawning background workers. - let old_umask = nix::sys::stat::umask(nix::sys::stat::Mode::from_bits_truncate(0o111)); - let listener = UnixListener::bind(&path) - .map_err(|e| format!("bind bridge socket {}: {e}", path.display())); - nix::sys::stat::umask(old_umask); - let listener = listener?; - let bound_meta = std::fs::symlink_metadata(&path) - .map_err(|e| format!("stat bound bridge socket {}: {e}", path.display()))?; - if !bound_meta.file_type().is_socket() { - return Err(format!("refusing bound non-socket {}", path.display())); - } - listener - .set_nonblocking(true) - .map_err(|e| format!("set bridge socket nonblocking {}: {e}", path.display()))?; - listeners.push(BridgeListener { - identity: peer.identity.clone(), - expected_uid: peer.expected_uid, - listener, - }); - } - Ok(listeners) + // umask is process-wide: keep bridge listener installation in the + // single-threaded startup phase, before spawning background workers. + let old_umask = nix::sys::stat::umask(nix::sys::stat::Mode::from_bits_truncate(0o111)); + let listener = UnixListener::bind(&path) + .map_err(|e| format!("bind bridge socket {}: {e}", path.display())); + nix::sys::stat::umask(old_umask); + let listener = listener?; + let bound_meta = std::fs::symlink_metadata(&path) + .map_err(|e| format!("stat bound bridge socket {}: {e}", path.display()))?; + if !bound_meta.file_type().is_socket() { + return Err(format!("refusing bound non-socket {}", path.display())); + } + listener + .set_nonblocking(true) + .map_err(|e| format!("set bridge socket nonblocking {}: {e}", path.display()))?; + Ok(BridgeListener { + identity: peer.identity.clone(), + expected_uid: peer.expected_uid, + listener, + }) + }) + .collect::, String>>()?) } fn bridge_socket_path(root: &Path, uid: u32, component: &str) -> Result { @@ -2809,14 +2810,9 @@ fn selected_entry_data_by_mime( fn preferred_mime_order(data_by_mime: &BTreeMap>) -> Vec { let mut out = Vec::new(); - for preferred in [ - "text/plain;charset=utf-8", - "text/plain", - "text/html", - "image/png", - ] { - if data_by_mime.contains_key(preferred) { - out.push(preferred.to_owned()); + for preferred in d2b_provider_clipboard_wayland::ALLOWED_MIME_TYPES { + if data_by_mime.contains_key(*preferred) { + out.push((*preferred).to_owned()); } } for mime in data_by_mime.keys() { From f0210347a49451bf17de7e8f1d7bb03bfbdaa500 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:12:42 -0700 Subject: [PATCH 195/726] clipboard: unify the mime policy and single-source the reason-code wire label --- .../src/clipd_host/policy.rs | 39 +++++++------------ .../d2b-provider-clipboard-wayland/src/lib.rs | 4 +- .../src/policy.rs | 24 +++++++++++- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs index 29124f4e4..f20d7a4b1 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs @@ -1,23 +1,10 @@ use serde::{Deserialize, Serialize}; -pub const ALLOWED_MIME_TYPES: &[&str] = &[ - "text/plain;charset=utf-8", - "text/plain", - "text/html", - "image/png", -]; +pub use d2b_provider_clipboard_wayland::{ + ALLOWED_MIME_TYPES, SECRET_HINT_MIME_TYPES, normalize_mime, +}; -pub const SECRET_HINT_MIME_TYPES: &[&str] = &[ - "x-kde-passwordmanagerhint", - "application/x-kde-passwordmanagerhint", - "x-gnome-passwordmanagerhint", - "application/x-gnome-passwordmanagerhint", - "x-keepassxc-secret", - "application/x-keepassxc-secret", - "application/x-secret-service", -]; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ReasonCode { Allowed, @@ -41,6 +28,15 @@ pub enum ReasonCode { VirtualKeyboardFailed, } +impl Serialize for ReasonCode { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + impl ReasonCode { pub fn as_str(self) -> &'static str { match self { @@ -88,15 +84,6 @@ pub fn has_secret_hint<'a>(mime_names: impl IntoIterator) -> boo .any(|mime| SECRET_HINT_MIME_TYPES.contains(&mime.as_str())) } -pub fn normalize_mime(mime: &str) -> String { - mime.trim() - .split(';') - .map(str::trim) - .collect::>() - .join(";") - .to_ascii_lowercase() -} - #[cfg(test)] mod tests { use super::*; diff --git a/packages/d2b-provider-clipboard-wayland/src/lib.rs b/packages/d2b-provider-clipboard-wayland/src/lib.rs index baecb5590..cad8df5f0 100644 --- a/packages/d2b-provider-clipboard-wayland/src/lib.rs +++ b/packages/d2b-provider-clipboard-wayland/src/lib.rs @@ -28,7 +28,9 @@ pub use fd::{ }; pub use history::{ClipboardEntry, ClipboardHistory, HistoryError}; pub use picker::{PickerAuthority, PickerError, PickerReceipt, PickerRequest, PickerResult}; -pub use policy::{ALLOWED_MIME_TYPES, ClipboardPolicyError, Policy, SECRET_HINT_MIME_TYPES}; +pub use policy::{ + ALLOWED_MIME_TYPES, ClipboardPolicyError, Policy, SECRET_HINT_MIME_TYPES, normalize_mime, +}; pub use runtime::{ ClipboardFinalizationReport, ClipboardProcessEffectPort, ClipboardRuntime, ClipboardRuntimeError, diff --git a/packages/d2b-provider-clipboard-wayland/src/policy.rs b/packages/d2b-provider-clipboard-wayland/src/policy.rs index 7f97de65e..cc3a9e904 100644 --- a/packages/d2b-provider-clipboard-wayland/src/policy.rs +++ b/packages/d2b-provider-clipboard-wayland/src/policy.rs @@ -9,8 +9,17 @@ pub const ALLOWED_MIME_TYPES: &[&str] = &[ ]; /// MIME hints that suppress capture before any attachment is read. +/// +/// Canonical list: the host clipd path re-exports it, and the guest history +/// path checks it, so both sides suppress the same hints. pub const SECRET_HINT_MIME_TYPES: &[&str] = &[ "x-kde-passwordmanagerhint", + "application/x-kde-passwordmanagerhint", + "x-gnome-passwordmanagerhint", + "application/x-gnome-passwordmanagerhint", + "x-keepassxc-secret", + "application/x-keepassxc-secret", + "application/x-secret-service", "application/x-password", "x-secret-content", ]; @@ -66,6 +75,11 @@ impl Default for Policy { impl Policy { /// Validate and construct a custom policy. + /// + /// # Errors + /// + /// Returns [`ClipboardPolicyError::InvalidBounds`] when any numeric + /// bound falls outside its admissible range. #[allow(clippy::too_many_arguments)] pub fn new( allow_host_capture: bool, @@ -203,8 +217,16 @@ impl Policy { } /// Normalize a MIME token without accepting parameters beyond the allowlist. +/// +/// Whitespace around the `;` parameter separator is collapsed so that +/// `Text/Plain ; Charset=UTF-8` normalizes to the allowlisted form. pub fn normalize_mime(mime: &str) -> String { - mime.trim().to_ascii_lowercase() + mime.trim() + .split(';') + .map(str::trim) + .collect::>() + .join(";") + .to_ascii_lowercase() } #[cfg(test)] From 018c1dad531dcb683c3a1f2f28b65a779023f009 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:12:45 -0700 Subject: [PATCH 196/726] clipboard: derive the fallback arming defaults --- .../src/clipd_host/fallback.rs | 13 +---- .../src/clipd_host/picker.rs | 58 +++++++++++-------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs index 2e8e228b1..af2795839 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs @@ -2,8 +2,9 @@ use std::time::{Duration, Instant}; use crate::clipd_host::niri::FocusedWindowSnapshot; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub enum FallbackState { + #[default] Idle, PickerOpen { target: FocusedWindowSnapshot, @@ -32,19 +33,11 @@ pub enum FallbackClearReason { PickerCancelled, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct FallbackArming { state: FallbackState, } -impl Default for FallbackArming { - fn default() -> Self { - Self { - state: FallbackState::Idle, - } - } -} - impl FallbackArming { pub fn state(&self) -> &FallbackState { &self.state diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs index 3c68ea30a..3a593ac67 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs @@ -72,6 +72,10 @@ impl PickerProcess for Child { } } +// Grace period between sending SIGTERM to a terminating picker and +// escalating to SIGKILL: long enough for a well-behaved picker to exit +// after its IPC socket closes, short enough that a hung picker cannot +// linger across the daemon's maintenance loop. const PICKER_TERMINATE_GRACE: Duration = Duration::from_millis(250); #[derive(Debug, Default)] @@ -86,7 +90,7 @@ impl PickerSpawner for CommandPickerSpawner { // and a poll loop, never an executor. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] - fn spawn(&mut self, launch: PickerLaunch) -> Result { + fn spawn(&mut self, launch: PickerLaunch) -> Result { let mut command = Command::new(&launch.command.program); command.args(&launch.argv); command.env_clear(); @@ -96,21 +100,21 @@ impl PickerSpawner for CommandPickerSpawner { parent_fd: launch.child_ipc_fd, child_fd: launch.ipc_fd_number, }]) - .map_err(|err| PickerError::FdFlags(err.to_string()))?; + .map_err(|err| PickerIpcError::FdFlags(err.to_string()))?; command .spawn() - .map_err(|err| PickerError::Spawn(err.to_string())) + .map_err(|err| PickerIpcError::Spawn(err.to_string())) } } pub trait PickerSpawner { type Process: PickerProcess; - fn spawn(&mut self, launch: PickerLaunch) -> Result; + fn spawn(&mut self, launch: PickerLaunch) -> Result; } #[derive(Debug, Error, PartialEq, Eq)] -pub enum PickerError { +pub enum PickerIpcError { #[error("picker is not configured")] NotConfigured, #[error("picker is already active for request {request_id}")] @@ -201,24 +205,26 @@ impl PickerSupervisor { self.active.as_ref().map(|active| &active.parent_socket) } + /// Spawn the picker subprocess and borrow its IPC socket; the borrow + /// stays valid until the picker is cancelled, reaped, or replaced. pub fn launch( &mut self, request_id: String, command: Option, ambient_env: &BTreeMap, timeout: Duration, - ) -> Result<&UnixStream, PickerError> { + ) -> Result<&UnixStream, PickerIpcError> { if let Some(active) = &self.active { - return Err(PickerError::AlreadyActive { + return Err(PickerIpcError::AlreadyActive { request_id: active.request_id.clone(), }); } - let command = command.ok_or(PickerError::NotConfigured)?; + let command = command.ok_or(PickerIpcError::NotConfigured)?; let (parent_socket, child_socket) = - UnixStream::pair().map_err(|err| PickerError::Socketpair(err.to_string()))?; + UnixStream::pair().map_err(|err| PickerIpcError::Socketpair(err.to_string()))?; parent_socket .set_nonblocking(true) - .map_err(|err| PickerError::Socketpair(err.to_string()))?; + .map_err(|err| PickerIpcError::Socketpair(err.to_string()))?; let child_ipc_fd = OwnedFd::from(child_socket); let child_fd_number = PICKER_IPC_FD; let argv = picker_argv(&command, child_fd_number); @@ -242,11 +248,12 @@ impl PickerSupervisor { Ok(&self.active.as_ref().expect("active").parent_socket) } - // Sync-by-construction nonblocking read:the daemon's poll loop marks the - // picker socket ready, then this drains frames without ever blocking - // (WouldBlock breaks the loop). Only the CLI daemon compiles clipd_host. + /// Nonblocking drain of picker IPC frames: the daemon's poll loop marks + /// the picker socket ready, then this reads until a complete frame or + /// `WouldBlock`, returning [`PickerPoll::Incomplete`] for partial data. + /// Only the CLI daemon compiles clipd_host. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] - pub fn poll_active(&mut self, max_frame_bytes: usize) -> Result { + pub fn poll_active(&mut self, max_frame_bytes: usize) -> Result { let Some(active) = self.active.as_mut() else { return Ok(PickerPoll::Incomplete); }; @@ -258,7 +265,7 @@ impl PickerSupervisor { match active.parent_socket.read(&mut buf) { Ok(0) if active.read_buffer.is_empty() => return Ok(PickerPoll::Closed), Ok(0) => { - return Err(PickerError::Frame( + return Err(PickerIpcError::Frame( "picker closed with incomplete frame".to_owned(), )); } @@ -267,7 +274,7 @@ impl PickerSupervisor { if let Some(newline) = active.read_buffer.iter().position(|byte| *byte == b'\n') { if newline > max_frame_bytes { - return Err(PickerError::Frame( + return Err(PickerIpcError::Frame( FramingError::FrameTooLong { max: max_frame_bytes, } @@ -277,7 +284,7 @@ impl PickerSupervisor { break; } if active.read_buffer.len() > max_frame_bytes { - return Err(PickerError::Frame( + return Err(PickerIpcError::Frame( FramingError::FrameTooLong { max: max_frame_bytes, } @@ -287,7 +294,7 @@ impl PickerSupervisor { } Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => break, Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue, - Err(error) => return Err(PickerError::Frame(error.to_string())), + Err(error) => return Err(PickerIpcError::Frame(error.to_string())), } } @@ -308,12 +315,12 @@ impl PickerSupervisor { fn decode_next_picker_frame( active: &mut ActivePicker

, max_frame_bytes: usize, - ) -> Result { + ) -> Result { let Some(newline) = active.read_buffer.iter().position(|byte| *byte == b'\n') else { return Ok(PickerPoll::Incomplete); }; if newline > max_frame_bytes { - return Err(PickerError::Frame( + return Err(PickerIpcError::Frame( FramingError::FrameTooLong { max: max_frame_bytes, } @@ -322,10 +329,12 @@ impl PickerSupervisor { } let frame = active.read_buffer.drain(..=newline).collect::>(); let message = decode_frame::(&frame, max_frame_bytes) - .map_err(|err| PickerError::Frame(err.to_string()))?; + .map_err(|err| PickerIpcError::Frame(err.to_string()))?; Ok(PickerPoll::Message(message)) } + /// Terminate the active picker when its deadline has passed, returning + /// `PickerTimeout` and moving the process into the terminating set. pub fn reap_expired(&mut self, now: Instant) -> Option { let active = self.active.as_ref()?; if now >= active.deadline { @@ -342,6 +351,9 @@ impl PickerSupervisor { } } + /// Reap or escalate terminating pickers: reap exited children, SIGKILL + /// survivors past the grace period, and keep the rest for the next + /// maintenance pass. pub fn reap_terminated(&mut self, now: Instant) { let mut still_running = Vec::new(); for mut picker in self.terminating.drain(..) { @@ -418,7 +430,7 @@ mod tests { impl PickerSpawner for FakeSpawner { type Process = FakeProcess; - fn spawn(&mut self, launch: PickerLaunch) -> Result { + fn spawn(&mut self, launch: PickerLaunch) -> Result { let flags = rustix::io::fcntl_getfd(&launch.child_ipc_fd).expect("child ipc fd flags"); assert!( flags.contains(rustix::io::FdFlags::CLOEXEC), @@ -500,7 +512,7 @@ mod tests { .expect_err("single active"); assert!(matches!( err, - PickerError::AlreadyActive { + PickerIpcError::AlreadyActive { request_id } if request_id == "req-1" )); From b8724cd15ce7949b65619f1ccc11713b75165acc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:13:02 -0700 Subject: [PATCH 197/726] clipboard: drop the avoidable mimes clone and document the data-control handles --- .../src/clipd_host/wayland.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs index d69a85a2e..cf469c1ca 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs @@ -77,6 +77,8 @@ impl DataControlOffer { } } + /// Destroy the compositor offer object; the caller must not use the + /// offer after this call. pub fn destroy(self) { match self { Self::Ext(offer) => offer.destroy(), @@ -95,6 +97,7 @@ pub enum DataControlSource { } impl DataControlSource { + /// Advertise one MIME type on the source to the compositor. pub fn offer_mime(&self, mime: String) { match self { Self::Ext(s) => s.offer(mime), @@ -254,8 +257,7 @@ impl WlState { // compositor, or in rare race conditions (offer destroyed before selection). let live = self.live.remove(&id); - let all_mimes: Vec = pending.mimes.clone(); - let has_secret = has_secret_hint(all_mimes.iter().map(String::as_str)); + let has_secret = has_secret_hint(pending.mimes.iter().map(String::as_str)); let allowed_mimes: Vec = pending .mimes .into_iter() From 48437393c17f2f6c9318449bb4803e49724c63ab Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:13:04 -0700 Subject: [PATCH 198/726] clipboard: document the failure contracts of the public result items --- packages/d2b-provider-clipboard-wayland/src/audit.rs | 5 +++++ packages/d2b-provider-clipboard-wayland/src/fd.rs | 5 +++++ packages/d2b-provider-clipboard-wayland/src/runtime.rs | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/packages/d2b-provider-clipboard-wayland/src/audit.rs b/packages/d2b-provider-clipboard-wayland/src/audit.rs index b0bb38394..9115e8558 100644 --- a/packages/d2b-provider-clipboard-wayland/src/audit.rs +++ b/packages/d2b-provider-clipboard-wayland/src/audit.rs @@ -197,6 +197,11 @@ impl ClipboardAuditQueue { } /// Append an event, refusing the operation when the queue is full. + /// + /// # Errors + /// + /// Returns [`ClipboardReason::AuditQueueFull`] when the queue already + /// holds its fixed capacity of events. pub fn push(&mut self, event: ClipboardAuditEvent) -> Result<(), ClipboardReason> { if self.entries.len() >= self.capacity { return Err(ClipboardReason::AuditQueueFull); diff --git a/packages/d2b-provider-clipboard-wayland/src/fd.rs b/packages/d2b-provider-clipboard-wayland/src/fd.rs index d38bba383..7efcb4bdd 100644 --- a/packages/d2b-provider-clipboard-wayland/src/fd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/fd.rs @@ -546,6 +546,11 @@ impl FdPermitPool { } /// Reserve ownership for one accepted descriptor batch. + /// + /// # Errors + /// + /// Returns [`FdSafetyError::ConcurrentLimitExceeded`] when the batch + /// would push the retained descriptor count past the pool limit. pub fn acquire(&self, requested: usize) -> Result { let mut active = self.active.load(Ordering::Acquire); loop { diff --git a/packages/d2b-provider-clipboard-wayland/src/runtime.rs b/packages/d2b-provider-clipboard-wayland/src/runtime.rs index 2446be72a..9e75c6eb7 100644 --- a/packages/d2b-provider-clipboard-wayland/src/runtime.rs +++ b/packages/d2b-provider-clipboard-wayland/src/runtime.rs @@ -92,6 +92,11 @@ impl ClipboardRuntime { } /// Admit a route retained by the daemon after bus registration. + /// + /// # Errors + /// + /// Returns [`ClipboardRuntimeError::SessionUnauthenticated`] when the + /// retained route is not authenticated for this Provider. pub fn admit_route( &self, route: AuthenticatedSessionRouteBinding, From 460a059429bc32aee983ffd47d786c0c5a86b318 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:13:08 -0700 Subject: [PATCH 199/726] clipboard: reword the entry bytes doc to the borrow contract --- packages/d2b-provider-clipboard-wayland/src/history.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/history.rs b/packages/d2b-provider-clipboard-wayland/src/history.rs index a44b0dff9..065c9a2ea 100644 --- a/packages/d2b-provider-clipboard-wayland/src/history.rs +++ b/packages/d2b-provider-clipboard-wayland/src/history.rs @@ -109,7 +109,7 @@ impl ClipboardEntry { self.bytes.is_empty() } - /// Return a bounded copy for an already-authorized materialization. + /// Borrow the payload bytes for an already-authorized materialization. pub fn bytes(&self) -> &[u8] { &self.bytes } From ac5e33ab18fb9932271c93f4690c5159c941a73a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:13:12 -0700 Subject: [PATCH 200/726] clipboard: document the niri ipc and attribution surface --- .../src/clipd_host/host.rs | 2 ++ .../src/clipd_host/niri.rs | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs index 59d2dfcb0..cf4807fed 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs @@ -47,6 +47,8 @@ impl HostClipboard

{ self.attributor.cache_mut().apply_event(event) } + /// Synchronously refresh the focused-window snapshot from the niri + /// provider; blocks on the IPC socket. pub fn refresh_focused_window_snapshot(&mut self) -> Option { self.attributor.refresh_from_provider().window } diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs index f582fd50b..b34ebaae2 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs @@ -11,6 +11,9 @@ use thiserror::Error; use crate::clipd_host::policy::AttributionQuality; +/// Upper bound on one niri IPC response line: 1 MiB is far above any real +/// window or workspace payload while still bounding memory on the socket +/// read path. pub const DEFAULT_NIRI_MAX_LINE_BYTES: usize = 1024 * 1024; #[derive(Debug, Error)] @@ -125,6 +128,7 @@ impl FocusedWindowProvider for NiriJsonClient { } } +/// Serialize a request as one newline-terminated NDJSON frame. pub fn encode_niri_request(request: &NiriRequest) -> Result, NiriIpcError> { let mut frame = serde_json::to_vec(request).map_err(|err| NiriIpcError::Json(err.to_string()))?; @@ -132,6 +136,8 @@ pub fn encode_niri_request(request: &NiriRequest) -> Result, NiriIpcErro Ok(frame) } +/// Blocking read of one newline-terminated NDJSON line from `reader`, +/// refusing frames longer than `max_line_bytes` before JSON parsing. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] pub fn read_bounded_ndjson_line( reader: &mut R, @@ -159,6 +165,8 @@ pub fn read_bounded_ndjson_line( } } +/// Decode a niri NDJSON response line, mapping niri's `Err`/`error` +/// envelopes to [`NiriIpcError::Niri`] and unwrapping the `Ok` payload. pub fn decode_niri_response(line: &str) -> Result { let value: Value = serde_json::from_str(line).map_err(|err| NiriIpcError::Json(err.to_string()))?; @@ -343,6 +351,8 @@ pub struct NiriStateCache { } impl NiriStateCache { + /// Apply one niri event to the cache and return the resulting + /// focused-window snapshot, if any. pub fn apply_event(&mut self, event: NiriEvent) -> Option { match event { NiriEvent::FocusChanged { id } => { @@ -396,6 +406,8 @@ impl NiriStateCache { self.focused_window() } + /// Replace the focused window from a synchronous query and return the + /// resulting snapshot, if any. pub fn update_focused_window( &mut self, focused: Option, @@ -411,14 +423,17 @@ impl NiriStateCache { self.focused_window() } + /// Mark the cached focus as stale after a failed provider probe. pub fn mark_stale(&mut self) { self.stale = true; } + /// Whether the cached focus is known to be stale. pub fn is_stale(&self) -> bool { self.stale } + /// Resolve the current focused-window snapshot, if any. pub fn focused_window(&self) -> Option { self.focused .as_ref() @@ -426,6 +441,7 @@ impl NiriStateCache { } } +/// Source of focused-window and workspace state from the niri IPC socket. pub trait FocusedWindowProvider { fn query_focused_window(&mut self) -> Result, NiriIpcError>; @@ -447,6 +463,7 @@ pub struct HostClipboardAttributor

{ } impl HostClipboardAttributor

{ + /// Construct an attributor over a niri provider with an empty cache. pub fn new(provider: P) -> Self { Self { provider, @@ -454,14 +471,17 @@ impl HostClipboardAttributor

{ } } + /// Mutably borrow the underlying niri state cache. pub fn cache_mut(&mut self) -> &mut NiriStateCache { &mut self.cache } + /// Produce attribution for a new host selection from the cached focus. pub fn on_host_selection_changed(&mut self) -> HostSelectionAttribution { self.cached_focused_window_guess() } + /// Return the cached focused-window guess with its quality tag. pub fn cached_focused_window_guess(&mut self) -> HostSelectionAttribution { let quality = if self.cache.is_stale() { AttributionQuality::CacheStaleFocusedWindowGuess @@ -474,6 +494,8 @@ impl HostClipboardAttributor

{ } } + /// Query the provider synchronously over the IPC socket (blocking) and + /// refresh the cache, falling back to the stale guess on failure. pub fn refresh_from_provider(&mut self) -> HostSelectionAttribution { if let Ok(workspaces) = self.provider.query_workspaces() { let _ = self From 08c2e3648ea86314717ed97b912d79545492ab71 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:13:15 -0700 Subject: [PATCH 201/726] clipboard: document the frame-budget magic constants --- .../d2b-provider-clipboard-wayland/src/clipd_host/audit.rs | 3 +++ .../d2b-provider-clipboard-wayland/src/clipd_host/framing.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs index 4df75f907..61a78af32 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs @@ -4,6 +4,9 @@ use serde::{Deserialize, Serialize}; use crate::clipd_host::policy::{AttributionQuality, ReasonCode}; +// Upper bound on the MIME value stored in one audit record, so a hostile +// or exotic MIME string cannot inflate the audit payload or the rendered +// audit line. const MAX_AUDIT_MIME_BYTES: usize = 64; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs index 4922696ef..cc1740067 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs @@ -25,7 +25,11 @@ impl Default for OpenRequestFrameCaps { impl OpenRequestFrameCaps { pub fn max_frame_bytes(self) -> usize { + // Fixed JSON envelope overhead per frame: syntax, field names, and + // separators around the candidate records. const ENVELOPE_BYTES: usize = 4096; + // Worst-case JSON string escape expansion: one input character can + // render as \uXXXX, six bytes. const JSON_STRING_ESCAPE_EXPANSION: usize = 6; let per_candidate = self .max_preview_bytes From 5d3053c5e9eff05dafb866d121ae4bde1c1cd6a0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:16:01 -0700 Subject: [PATCH 202/726] audit: record wave-1 remainder A Thirteen rows across the resource contracts and the clipboard provider, eleven applied and two minimal variants that keep secret detection and wire labels unchanged. --- .../2026-09-24-rust-skills-audit/ledger.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 52214e567..fab501df9 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -68,12 +68,12 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | applied-variant | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | row's bare-import removal broke tests using TapRole via use super::*; variant: import dropped, const deleted, 3 test sites qualified crate::host::TapRole (as _ import rejected by -D warnings) | | | `RS-0029` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | resolve_disk_init_ops flattened to vm.nodes.iter().flat_map(...).filter_map(...).collect() | | | `RS-0026` | `idiom` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | Both duplicate-reservation checks are entry.holders.iter().any(...) predicates; let _ = holder; gone. | | -| `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provid` | | | -| `RS-0039` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:2812, src/policy.rs:12` | | | -| `RS-0041` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboa` | | | -| `RS-0038` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:1131` | | | -| `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-pro` | | | -| `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provi` | | | +| `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provid` | two deliberate variants: (1) canonical secret-hint list is the union of both previous lists so no secret detection is weakened on either path (host tests pin application/x-secret-service; guest-only h | | +| `RS-0039` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | 9d0eaefff | `src/bin/d2b-clipd.rs:2812, src/policy.rs:12` | none | | +| `RS-0041` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboa` | commit grouping: the picker.rs changes landed in the same commit as fallback.rs (018c1dad5) because two parallel git add/commit calls raced on the shared index and the second committed both staged fil | | +| `RS-0038` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 9d0eaefff | `src/bin/d2b-clipd.rs:1131` | none (Ok wrapper required by the existing signature) | | +| `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-pro` | none | | +| `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provi` | implemented the inverse of the row's literal suggestion (a const table read by as_str): Serialize delegates to as_str instead, which keeps the match as the single source of truth with a smaller diff, | | | `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 3459dc5a0 | `packages/d2b-provider-config-nixos/src/ttrpc.rs` | Shared path_components helper classifies Path::components; both callers use it | | | `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | | | | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-e` | | | | `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | applied | U2 | 20e8286f8 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | SecretServiceOwner::Userd renamed to User; enum not serialized; census 2 hits in-crate | | @@ -186,7 +186,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0146` | `own` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | claim computed from request.durable_claim() before the lock block; request moved into admit_authority_inner_with_operation; .clone() deleted. | | | `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | applied | U2 | e47020297 | `packages/d2b-process-conformance/src/ticket.rs` | All four with_* builders (with_runtime_identity, with_owner_uid, with_owner_ref, with_target_ref) now move launch_identity instead of cloning it. | | | `RS-0154` | `own` | `d2b-provider` | low | actionable | leaf | applied | U2 | d6adc6a8e | `packages/d2b-provider/src/agent.rs` | ProviderAgent::dispatch extracts Copy method, moves request into service.dispatch(request) instead of cloning, and uses the local method in the audit record. | | -| `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | | | +| `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | b8724cd15 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | none | | | `RS-0156` | `own` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | b17a8c271 | `packages/d2b-provider-config-nixos/src/controller.rs` | GuestConfigDocument::into_bytes() consuming accessor; dispatch passes it without copying | | | `RS-0157` | `own` | `d2b-provider-credential` | low | actionable | leaf | applied | U2 | b68a9b55e | `packages/d2b-provider-credential/src/driver.rs` | Dropped dead derives: Clone on CredentialDriver and Default on RecordingRuntime (no call sites; RecordingRuntime::new kept as the only constructor). | | | `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | validate &identity before store; identity stored on failure branch preserving test-pinned retain-for-finalize contract | | @@ -691,9 +691,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | | `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | | `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/artifact.rs` | doc comments on the artifact id bound, error, type, parse, and accessor | | -| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | not-started | U2 | | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | execution_policy.rs into_policy and string_schema_object docs | | +| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | e7bba788d | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | none (anchor drift only) | | | `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/limits.rs` | module-level rationale naming the enforcing boundaries | | -| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | not-started | U2 | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | operations module doc comments in error.rs/seal.rs/mod.rs | | +| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | 712bb24af | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | three enumerated sub-claims were already documented at the audit baseline and left unchanged (verified via git show 6ebdd4cec): MutationSealAcceptor::diagnose (seal.rs:176-177), PreparedStoreMutation: | | | `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | | | | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | | | | `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/manifest_v04.rs` | module doc plus docs on ManifestV04/ManifestMeta/ObservabilityMeta/VmEntry/VmLifecycle/VmGracefulShutdown/VmLiveActivation/VmLanPolicy/VmObservability/VmShellMetadata/ManifestShellName; # Errors on fr | | | `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | one-line docs naming the exact BundleOpId shape added to all 15 undocumented intent_id_* constructors | | @@ -707,11 +707,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0663` | `docs` | `d2b-provider-audio-binding` | low | actionable | leaf | applied | U2 | ca450e9d5 | `packages/d2b-provider-audio-binding/src/audio_binding.rs` | Added # Errors to binding_children, validate, dependencies, desired_children naming Unavailable vs InvalidResource conditions. | | | `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/state.rs` | Documented AudioStateLock guard semantics (holds the OFD lock; drop releases and closes). | | | `RS-0665` | `docs` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/controller.rs` | Documented the 300s cadence rationale, hoisted 64 into pub const AUDIO_QUEUE_BOUND used by new, with_shared_microphone, and the admission bound test (u64 casts at lease sites). | | -| `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | | | +| `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | f0210347a,48437393c | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | the Policy::new hunk landed in the policy-unification commit f0210347a (same file as RS-0040); the other three hunks in 48437393c | | | `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | | | | `src/audit.rs:172, src/audit.rs:174` | | | -| `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | | | -| `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | | | -| `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | | | +| `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 460a05942 | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | none | | +| `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,b8724cd15,ac5e33ab1 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | picker.rs hunks shared commit 018c1dad5 with RS-0041/RS-0042 (index race, see RS-0041) | | +| `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,ac5e33ab1,08c2e3648 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | picker.rs hunk shared commit 018c1dad5 (index race, see RS-0041) | | | `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | applied | U2 | ef3bc5ec9 | `packages/d2b-provider-command/src/command.rs` | Added one-line # Errors naming CommandContractError variants to CommandExec::parse, CommandArgvSlot::parse, CommandSpec::new. | | | `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 7a6ab2d2d | `packages/d2b-provider-config-nixos/src/controller.rs` | # Errors added to all 19 pub Result items naming ConfigError variants | | | `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | applied | U2 | b68a9b55e | `packages/d2b-provider-credential/src/session.rs` | Added # Errors to CredentialRevocationRequest::new (InvalidResource conditions) and CredentialSession::revoke_credential (Revocation). | | From f7f3f27088e3847fd7a995066cf14a286c4e42e2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:17:24 -0700 Subject: [PATCH 203/726] display-wayland: simplify bridge handoff error binding and bind dispatch --- .../src/wayland_proxy/filter.rs | 140 ++++++++---------- 1 file changed, 64 insertions(+), 76 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs index c38330027..b14bc286e 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs @@ -618,11 +618,6 @@ impl VirtualClipboardState { self.enqueue_bridge_handoff(local_fd, metadata); } crate::wayland_proxy::bridge::HandoffStatus::Failed(error) => { - let status = crate::wayland_proxy::bridge::HandoffStatus::Failed(error); - let error = match status { - crate::wayland_proxy::bridge::HandoffStatus::Failed(error) => error, - _ => unreachable!(), - }; let _ = local_fd.close_after_handoff( crate::wayland_proxy::bridge::HandoffStatus::Failed(error), ); @@ -766,8 +761,8 @@ impl VirtualClipboardState { .map(|stream| (stream, self.pending_bridge_poll_flags())) } - // Non-blocking read (WouldBlock handled** at a poll-driven sync bridge - // boundary driven by the CLI loop;no async form fits this surface. + // Non-blocking read (WouldBlock handled) at a poll-driven sync bridge + // boundary driven by the CLI loop; no async form fits this surface. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn drain_bridge_messages(clipboard: &Rc>) { let mut refresh = false; @@ -1250,80 +1245,73 @@ impl WlRegistryHandler for FilterRegistryHandler { // Install per-interface handlers before forwarding, so we can // intercept the object's lifecycle from the first message. - match id.try_downcast::() { - Some(wm_base) => { - wm_base.set_handler(FilterXdgWmBaseHandler { - policy: self.policy.clone(), + if let Some(wm_base) = id.try_downcast::() { + wm_base.set_handler(FilterXdgWmBaseHandler { + policy: self.policy.clone(), + decoration: self.decoration.clone(), + positioners: Rc::new(RefCell::new(HashMap::new())), + }); + } else if let Some(eglstream_display) = id.try_downcast::() { + eglstream_display.set_handler(FilterEglstreamDisplayHandler { + identity_label: self.policy.identity_label.clone(), + diag: self.diag.clone(), + decoration: self.decoration.clone(), + }); + } else if let Some(compositor) = id.try_downcast::() { + compositor.set_handler(FilterCompositorHandler { + decoration: self.decoration.clone(), + }); + slf.send_bind(name, compositor); + return; + } else { + if let Some(shm) = id.try_downcast::() { + shm.set_handler(FilterShmHandler { decoration: self.decoration.clone(), - positioners: Rc::new(RefCell::new(HashMap::new())), }); + slf.send_bind(name, shm); + return; } - _ => match id.try_downcast::() { - Some(eglstream_display) => { - eglstream_display.set_handler(FilterEglstreamDisplayHandler { - identity_label: self.policy.identity_label.clone(), - diag: self.diag.clone(), - decoration: self.decoration.clone(), + if let Some(subcompositor) = id.try_downcast::() { + if self.decoration.is_some() { + subcompositor.set_handler(FilterSubcompositorHandler); + } + slf.send_bind(name, subcompositor); + return; + } + if let Some(seat) = id.try_downcast::() { + if let Some(decoration) = &self.decoration { + seat.set_handler(FilterSeatHandler { + decoration: decoration.clone(), }); } - _ => { - if let Some(compositor) = id.try_downcast::() { - compositor.set_handler(FilterCompositorHandler { - decoration: self.decoration.clone(), - }); - slf.send_bind(name, compositor); - return; - } - if let Some(shm) = id.try_downcast::() { - shm.set_handler(FilterShmHandler { - decoration: self.decoration.clone(), - }); - slf.send_bind(name, shm); - return; - } - if let Some(subcompositor) = id.try_downcast::() { - if self.decoration.is_some() { - subcompositor.set_handler(FilterSubcompositorHandler); - } - slf.send_bind(name, subcompositor); - return; - } - if let Some(seat) = id.try_downcast::() { - if let Some(decoration) = &self.decoration { - seat.set_handler(FilterSeatHandler { - decoration: decoration.clone(), - }); - } - slf.send_bind(name, seat); - return; - } - if let Some(viewporter) = id.try_downcast::() - && let Some(decoration) = &self.decoration - { - viewporter.set_handler(FilterViewporterHandler { - decoration: decoration.clone(), - }); - } - if let Some(dmabuf) = id.try_downcast::() - && (!self.policy.dmabuf_filters.is_empty() || self.decoration.is_some()) - { - dmabuf.set_handler(DmabufHandler::new( - self.policy.dmabuf_filters.clone(), - self.diag.clone(), - self.decoration.clone(), - )); - } - if let Some(drm) = id.try_downcast::() { - if let Some(decoration) = &self.decoration { - drm.set_handler(FilterDrmHandler { - decoration: decoration.clone(), - }); - } - slf.send_bind(name, drm); - return; - } + slf.send_bind(name, seat); + return; + } + if let Some(viewporter) = id.try_downcast::() + && let Some(decoration) = &self.decoration + { + viewporter.set_handler(FilterViewporterHandler { + decoration: decoration.clone(), + }); + } + if let Some(dmabuf) = id.try_downcast::() + && (!self.policy.dmabuf_filters.is_empty() || self.decoration.is_some()) + { + dmabuf.set_handler(DmabufHandler::new( + self.policy.dmabuf_filters.clone(), + self.diag.clone(), + self.decoration.clone(), + )); + } + if let Some(drm) = id.try_downcast::() { + if let Some(decoration) = &self.decoration { + drm.set_handler(FilterDrmHandler { + decoration: decoration.clone(), + }); } - }, + slf.send_bind(name, drm); + return; + } } slf.send_bind(name, id); @@ -2798,7 +2786,7 @@ fn bind_matches_advertised_cap( } // SOCK_NONBLOCK connect with EINPROGRESS/EAGAIN tolerated; readiness is - // driven by the CLI poll loop;no async form fits this path. +// driven by the CLI poll loop; no async form fits this path. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn connect_bridge_nonblocking(path: &PathBuf) -> std::io::Result { use nix::sys::socket::{AddressFamily, SockFlag, SockType, UnixAddr, connect, socket}; From 309cded8c62833f29a6edda79e923da31c2edf2f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:17:27 -0700 Subject: [PATCH 204/726] display-wayland: tidy dmabuf table loop and share filter list by Rc --- .../src/wayland_proxy/dmabuf.rs | 35 +++++++++++-------- .../src/wayland_proxy/policy.rs | 4 +-- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs index 043fe6a75..ae08227b2 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs @@ -6,7 +6,6 @@ use std::{ io::{self, Seek, SeekFrom, Write}, os::fd::OwnedFd, rc::Rc, - sync::Arc, }; use nix::sys::memfd::{MemFdCreateFlag, memfd_create}; @@ -159,6 +158,13 @@ pub fn map_shm_to_drm(format: u32) -> u32 { } } +/// Parse a `format[:modifier]` dmabuf filter from CLI syntax. +/// +/// # Errors +/// +/// Returns a message naming the offending token when the format is neither +/// `all` nor a parseable integer, or when the modifier is neither `linear`, +/// `invalid`, nor a parseable integer. pub fn parse_filter(s: &str) -> Result { let (format, modifier) = match s.split_once(':') { Some((format, modifier)) => (format, Some(modifier)), @@ -205,14 +211,14 @@ fn parse_u64(s: &str) -> Option { } pub struct DmabufHandler { - filters: Arc, + filters: Rc, diag: Rc>, decoration: Option, } impl DmabufHandler { pub fn new( - filters: Arc, + filters: Rc, diag: Rc>, decoration: Option, ) -> Self { @@ -300,7 +306,7 @@ impl DmabufPlane { } struct DmabufBufferParamsHandler { - filters: Arc, + filters: Rc, diag: Rc>, decoration: Option, planes: Vec, @@ -325,7 +331,7 @@ enum DmabufCreateAction { impl DmabufBufferParamsHandler { fn new( - filters: Arc, + filters: Rc, diag: Rc>, decoration: Option, ) -> Self { @@ -617,7 +623,7 @@ impl ZwpLinuxBufferParamsV1Handler for DmabufBufferParamsHandler { } struct DmabufFeedbackHandler { - filters: Arc, + filters: Rc, diag: Rc>, table: Option>, index_map: Option>>, @@ -625,7 +631,7 @@ struct DmabufFeedbackHandler { } impl DmabufFeedbackHandler { - fn new(filters: Arc, diag: Rc>) -> Self { + fn new(filters: Rc, diag: Rc>) -> Self { Self { filters, diag, @@ -787,7 +793,7 @@ fn filter_format_table( let mut filtered = Vec::::new(); let mut index_map = Vec::>::new(); let mut overflowed = false; - for (index, entry) in table.chunks_exact(16).enumerate() { + for entry in table.chunks_exact(16) { let Ok(format) = uapi::pod_read_init::(&entry[0..4]) else { index_map.push(None); continue; @@ -798,7 +804,6 @@ fn filter_format_table( }; if filters.allowed(format, modifier) { let Ok(new_index) = u16::try_from(filtered.len() / 16) else { - let _ = index; overflowed = true; index_map.push(None); continue; @@ -817,7 +822,7 @@ fn format_table_is_well_formed(table: &[u8]) -> bool { } // memfd is memory-backed: write_all cannot block on I/O; called from the - // sync wayland-proxy handler path。 +// sync wayland-proxy handler path. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn table_fd(table: &[u8]) -> io::Result { let name = CString::new("d2b-dmabuf-format-table").expect("static memfd name has no NUL"); @@ -910,7 +915,7 @@ mod tests { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn handler_with_plane(modifier: u64) -> DmabufBufferParamsHandler { - let filters = Arc::new(DmabufFilterList::new( + let filters = Rc::new(DmabufFilterList::new( &[], &[DmabufFilter { format: None, @@ -1038,7 +1043,7 @@ mod tests { #[test] fn create_dimensions_are_queued_for_multiple_async_creates() { - let filters = Arc::new(DmabufFilterList::default()); + let filters = Rc::new(DmabufFilterList::default()); let mut handler = DmabufBufferParamsHandler::new(filters, diag(), None); handler @@ -1072,7 +1077,7 @@ mod tests { #[test] fn failed_create_drops_oldest_pending_dimensions() { - let filters = Arc::new(DmabufFilterList::default()); + let filters = Rc::new(DmabufFilterList::default()); let mut handler = DmabufBufferParamsHandler::new(filters, diag(), None); handler .pending_create_dimensions @@ -1100,7 +1105,7 @@ mod tests { #[test] fn invalid_create_dimensions_still_reserve_queue_slot() { - let filters = Arc::new(DmabufFilterList::default()); + let filters = Rc::new(DmabufFilterList::default()); let mut handler = DmabufBufferParamsHandler::new(filters, diag(), None); handler .pending_create_dimensions @@ -1224,7 +1229,7 @@ mod tests { #[test] fn invalid_plane_set_fails_create_without_unbounded_examples() { let format = 0x3432_5258u32; - let filters = Arc::new(DmabufFilterList::new(&[], &[])); + let filters = Rc::new(DmabufFilterList::new(&[], &[])); let mut handler = DmabufBufferParamsHandler::new(filters, diag(), None); handler.invalid_plane_count = 100; diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs index a73492ceb..469ff69c5 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs @@ -183,7 +183,7 @@ pub struct FilterPolicy { pub identity: ProxyIdentity, /// Bounded display label derived from the authenticated identity. pub identity_label: String, - pub dmabuf_filters: std::sync::Arc, + pub dmabuf_filters: std::rc::Rc, pub log_filtered_globals: bool, /// Runtime advisories emitted by the filter process at startup. pub warnings: Vec, @@ -313,7 +313,7 @@ impl FilterPolicy { title_prefix, identity, identity_label: target_label, - dmabuf_filters: std::sync::Arc::new( + dmabuf_filters: std::rc::Rc::new( crate::wayland_proxy::dmabuf::DmabufFilterList::new( &input.dmabuf_allow, &input.dmabuf_deny, From 99e27d5b6d745ab27eb4b9cdbcbc2ae2ca5e1023 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:17:31 -0700 Subject: [PATCH 205/726] display-wayland: track written label chars and document bridge and readiness errors --- .../src/wayland_proxy/bridge.rs | 16 +++++++++++++ .../src/wayland_proxy/decoration.rs | 7 ++++-- .../src/wayland_proxy/readiness.rs | 23 +++++++++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs index 4a61865df..788cdc0ad 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs @@ -28,6 +28,16 @@ pub struct BridgeConfig { } impl BridgeConfig { + /// Build the bridge configuration from an explicit socket path or the + /// identity-derived per-user path. + /// + /// # Errors + /// + /// Returns `BridgeConfigError::InvalidReconnectPolicy` when the reconnect + /// initial delay exceeds the max delay, `BridgeConfigError::InvalidEndpointComponent` + /// when the identity-derived path component is not a valid endpoint + /// component, and `BridgeConfigError::SocketPathTooLong` when the socket + /// path exceeds the Linux `sockaddr_un` limit. pub fn from_identity_parts( explicit_socket: Option, root: &Path, @@ -66,6 +76,12 @@ pub struct BridgeReconnectPolicy { pub max_delay: Duration, } +/// Derive the per-user bridge socket path for an identity. +/// +/// # Errors +/// +/// Returns `BridgeConfigError::InvalidEndpointComponent` when the identity's +/// bridge component is empty, `.`, `..`, or contains `/` or NUL. pub fn path_for_user_identity( root: &Path, user_uid: u32, diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs index cfc800766..5e81dcd6a 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs @@ -145,9 +145,10 @@ impl SanitizedLabel { pub fn sanitize_label(input: &str) -> Option { let mut out = String::new(); + let mut written = 0usize; let mut pending_space = false; for ch in input.chars() { - if out.chars().count() >= MAX_LABEL_CHARS { + if written >= MAX_LABEL_CHARS { break; } if ch.is_control() { @@ -160,6 +161,7 @@ pub fn sanitize_label(input: &str) -> Option { } if pending_space && !out.is_empty() { out.push(' '); + written += 1; } pending_space = false; if ch.is_ascii_graphic() { @@ -167,6 +169,7 @@ pub fn sanitize_label(input: &str) -> Option { } else { out.push('?'); } + written += 1; } let out = out.trim().to_owned(); if out.is_empty() { @@ -1802,7 +1805,7 @@ impl XdgToplevelHandler for WrapperToplevelHandler { } // memfd is memory-backed: write_all cannot block on I/O; called from the - // sync wayland-proxy handler path. +// sync wayland-proxy handler path. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn create_memfd_with_contents(contents: &[u8], size: u64) -> io::Result { let name = CString::new("d2b-wayland-border").expect("static memfd name has no nul"); diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs index 1afdf84d6..0ac22c5b5 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs @@ -24,8 +24,15 @@ impl ReadinessReporter { } } - // The readiness reporter is a sync public surface; it is driven by the CLI - // binary's poll loop and has no async form at this boundary. + /// Connect the readiness reporter to the daemon socket. + /// + /// The readiness reporter is a sync public surface; it is driven by the CLI + /// binary's poll loop and has no async form at this boundary. + /// + /// # Errors + /// + /// Returns the underlying io error when the socket cannot be connected or + /// its write timeout cannot be set. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn connect(identity: ProxyIdentity, path: &Path) -> io::Result { let stream = UnixStream::connect(path)?; @@ -36,6 +43,12 @@ impl ReadinessReporter { }) } + /// Report a readiness stage transition. + /// + /// # Errors + /// + /// Returns the underlying io error when the event cannot be written to the + /// connected socket. pub fn ready(&mut self, stage: ProxyReadinessStage) -> io::Result<()> { let event = ProxyReadinessEvent::ready( self.identity.target().clone(), @@ -45,6 +58,12 @@ impl ReadinessReporter { self.emit(&event) } + /// Report a readiness failure at a stage. + /// + /// # Errors + /// + /// Returns the underlying io error when the event cannot be written to the + /// connected socket. pub fn failed( &mut self, stage: ProxyReadinessStage, From 107f8775b6c635d835467b439dfecb38d772b14d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:17:44 -0700 Subject: [PATCH 206/726] display-wayland: drop stale dead-code allows and delegate session digest --- .../src/controller.rs | 22 ++++++++----------- .../src/process.rs | 2 -- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/controller.rs b/packages/d2b-provider-display-wayland/src/controller.rs index ccd36bd25..02e5ca390 100644 --- a/packages/d2b-provider-display-wayland/src/controller.rs +++ b/packages/d2b-provider-display-wayland/src/controller.rs @@ -12,7 +12,7 @@ use crate::{ }; use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; use d2b_provider_toolkit::{AuthenticatedComponentSession, AuthenticatedSessionRouteBinding}; -use sha2::{Digest, Sha256}; + use std::collections::BTreeMap; /// Default shared-Runner repair interval for display resources. @@ -461,7 +461,6 @@ impl FinalizationInput { clippy::too_many_arguments, reason = "finalization evidence keeps every owned authority explicit" )] - #[allow(dead_code)] pub(crate) const fn from_supervisor( stop_requested: StopRequest, proxy: WorkerState, @@ -749,6 +748,13 @@ impl DisplayController { /// Reconcile only after binding the desired state to an authenticated /// Guest ComponentSession. + /// + /// # Errors + /// + /// Returns `WaylandSpecError::InvalidReference` when the authenticated + /// session's guest or host ref, reconnect generation, or zone does not + /// match the spec, and any `WaylandSpecError` raised by the reconcile step + /// itself. #[expect( clippy::too_many_arguments, reason = "the authenticated controller fence keeps every authority input explicit" @@ -1440,17 +1446,7 @@ fn session_key(spec: &WaylandSessionSpec, controller_generation: u64) -> String } pub(crate) fn session_digest(spec: &WaylandSessionSpec, controller_generation: u64) -> [u8; 32] { - let mut digest = Sha256::new(); - digest.update(spec.guest_ref().to_canonical_string().as_bytes()); - digest.update([0]); - digest.update(spec.host_ref().to_canonical_string().as_bytes()); - digest.update([0]); - digest.update(spec.user_ref().to_canonical_string().as_bytes()); - digest.update([0]); - digest.update(spec.reconnect_generation().to_be_bytes()); - digest.update([0]); - digest.update(controller_generation.to_be_bytes()); - digest.finalize().into() + spec.session_digest(controller_generation) } #[cfg(test)] diff --git a/packages/d2b-provider-display-wayland/src/process.rs b/packages/d2b-provider-display-wayland/src/process.rs index 9f8cd4531..d89a7ffab 100644 --- a/packages/d2b-provider-display-wayland/src/process.rs +++ b/packages/d2b-provider-display-wayland/src/process.rs @@ -399,7 +399,6 @@ impl LaunchGrants { /// Construct grants for both workers and one authenticated controller /// generation. - #[allow(dead_code)] pub(crate) const fn from_supervisor_for_session_with_frontend_and_controller( compositor: AttachmentGrantHandle, gpu: AttachmentGrantHandle, @@ -673,7 +672,6 @@ impl ProcessObservation { } } - #[allow(dead_code)] pub(crate) const fn from_supervisor( proxy: WorkerState, frontend: WorkerState, From c4242f7f06ad0127ff73ae784f783fafea276666 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:17:46 -0700 Subject: [PATCH 207/726] display-wayland: correct policy getter docs and add error sections --- packages/d2b-provider-display-wayland/src/policy.rs | 10 ++++++++-- packages/d2b-provider-display-wayland/src/spec.rs | 13 +++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/policy.rs b/packages/d2b-provider-display-wayland/src/policy.rs index 0f7b66bfd..96ed4c6f3 100644 --- a/packages/d2b-provider-display-wayland/src/policy.rs +++ b/packages/d2b-provider-display-wayland/src/policy.rs @@ -111,12 +111,12 @@ impl FilterInput { Ok(value) } - /// Add an allowed global to this layer. + /// Borrow the allowed globals of this layer. pub fn allow_globals(&self) -> &[String] { &self.allow_globals } - /// Add a denied global to this layer. + /// Borrow the denied globals of this layer. pub fn deny_globals(&self) -> &[String] { &self.deny_globals } @@ -256,6 +256,12 @@ pub struct WaylandPolicy; impl WaylandPolicy { /// Compile defaults, Zone policy, and session overrides in that order. + /// + /// # Errors + /// + /// Returns `PolicyCompileError::BoundsExceeded` when a layer exceeds a + /// fixed count or byte bound, and `PolicyCompileError::UnknownInterface` + /// when a layer names a global outside the compiled catalog. pub fn compile( defaults: &FilterInput, zone: &FilterInput, diff --git a/packages/d2b-provider-display-wayland/src/spec.rs b/packages/d2b-provider-display-wayland/src/spec.rs index de0a16bd9..fddd3d2ac 100644 --- a/packages/d2b-provider-display-wayland/src/spec.rs +++ b/packages/d2b-provider-display-wayland/src/spec.rs @@ -114,6 +114,13 @@ impl<'de> Deserialize<'de> for DisplayIdentity { impl DisplayIdentity { /// Validate a display identity with default border and label settings. + /// + /// # Errors + /// + /// Returns `WaylandSpecError::InvalidLabel` when the label does not match + /// the closed identifier grammar, `WaylandSpecError::LabelTooLong` when the + /// label exceeds its bound, and `WaylandSpecError::InvalidColor` when a + /// color is not a six-digit RGB value. pub fn new( label: impl Into, active_color: impl Into, @@ -289,6 +296,12 @@ impl<'de> Deserialize<'de> for WaylandSessionSpec { impl WaylandSessionSpec { /// Validate and construct a trusted cross-domain session. + /// + /// # Errors + /// + /// Returns `WaylandSpecError::InvalidReference` when a ref has the wrong + /// closed resource type, and `WaylandSpecError::CrossDomainUntrusted` when + /// the session is not explicitly trusted. pub fn new( guest_ref: ResourceRef, host_ref: ResourceRef, From b2fef514560626136f5bb58bdac0c75994169ef6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:17:49 -0700 Subject: [PATCH 208/726] resource-compiler: share the sanitizers and simplify schema and CLI checks --- packages/d2b-resource-compiler/src/lib.rs | 63 +++++---- packages/d2b-resource-compiler/src/main.rs | 155 +++++++++------------ 2 files changed, 101 insertions(+), 117 deletions(-) diff --git a/packages/d2b-resource-compiler/src/lib.rs b/packages/d2b-resource-compiler/src/lib.rs index 42da8df22..ead484ece 100644 --- a/packages/d2b-resource-compiler/src/lib.rs +++ b/packages/d2b-resource-compiler/src/lib.rs @@ -1721,16 +1721,14 @@ fn check_metadata_closure( "provider-manifest.json", "provider-manifest.json.sig", ]); - let mut unexpected = Vec::new(); - for entry_name in entries { - let Some(name) = entry_name.to_str() else { - unexpected.push("".to_owned()); - continue; - }; - if !expected.contains(name) { - unexpected.push(truncate_entry(name)); - } - } + let mut unexpected: Vec = entries + .into_iter() + .filter_map(|entry_name| match entry_name.to_str() { + Some(name) if expected.contains(name) => None, + Some(name) => Some(truncate_entry(name)), + None => Some("".to_owned()), + }) + .collect(); if unexpected.is_empty() { return Ok(()); } @@ -1910,13 +1908,15 @@ fn validate_executables( if let Some(declared) = declared.as_ref() { let declared_names: BTreeSet<_> = declared.keys().cloned().collect(); if names != declared_names { - let mut difference = Vec::new(); - for name in names.difference(&declared_names) { - difference.push(format!("bin={}", truncate_entry(name))); - } - for name in declared_names.difference(&names) { - difference.push(format!("manifest={}", truncate_entry(name))); - } + let difference: Vec = names + .difference(&declared_names) + .map(|name| format!("bin={}", truncate_entry(name))) + .chain( + declared_names + .difference(&names) + .map(|name| format!("manifest={}", truncate_entry(name))), + ) + .collect(); return Err(executable_set_mismatch( entry, &difference, @@ -2398,17 +2398,21 @@ fn safe_label(value: &str) -> String { sanitize_token(value) } -fn sanitize_token(value: &str) -> String { - let mut output = String::new(); - for character in value.chars() { - if (character.is_ascii_graphic() && character != '/' && character != '\\') - || character == ' ' - { - output.push(character); - } else { - output.push('?'); - } - } +/// Sanitize a token for diagnostic output, replacing non-graphic characters +/// with `?` and bounding the result. +pub fn sanitize_token(value: &str) -> String { + let output: String = value + .chars() + .map(|character| { + if (character.is_ascii_graphic() && character != '/' && character != '\\') + || character == ' ' + { + character + } else { + '?' + } + }) + .collect(); bound_message(&output) } @@ -2435,7 +2439,8 @@ fn magic_hex(bytes: &[u8]) -> String { output } -fn bound_message(value: &str) -> String { +/// Bound a diagnostic message to ASCII within the diagnostic byte limit. +pub fn bound_message(value: &str) -> String { let mut output = String::new(); for character in value.chars() { let character = if character.is_control() { diff --git a/packages/d2b-resource-compiler/src/main.rs b/packages/d2b-resource-compiler/src/main.rs index b0d05780d..4425d67ba 100644 --- a/packages/d2b-resource-compiler/src/main.rs +++ b/packages/d2b-resource-compiler/src/main.rs @@ -7,7 +7,6 @@ //! file owns only the resource-bundle envelope and the input/output contract. use std::{ - cell::RefCell, collections::{BTreeMap, BTreeSet}, env, fs, path::{Path, PathBuf}, @@ -23,15 +22,15 @@ use d2b_contracts_resource::v3::{ use d2b_contracts_zone_session::v3::resource_bundle::ProcessTemplateBinding; use d2b_resource_compiler::{ ArtifactCatalogEntry, BootstrapBoundary, CatalogDigests, Diagnostic, StaticPublisherKeys, - VerifiedProviderArtifact, compile_linux_artifact, project_static_controller_processes, - resource_sort_key, + VerifiedProviderArtifact, bound_message, compile_linux_artifact, + project_static_controller_processes, resource_sort_key, sanitize_token, }; use regex::Regex; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; const RESOURCE_BUNDLE_DOMAIN_TAG: &str = "d2b:v3:resource-bundle"; -const MAX_DIAGNOSTIC_BYTES: usize = d2b_resource_compiler::MAX_DIAGNOSTIC_BYTES; + const MAX_RESOURCES: usize = 4096; const MAX_RESOURCE_BYTES: usize = 512 * 1024; const MAX_SCHEMA_BYTES: usize = 8 * 1024 * 1024; @@ -102,7 +101,7 @@ impl CliError { Self { code, exit_code: 1, - message: bound_ascii(message.as_ref()), + message: bound_message(message.as_ref()), } } @@ -110,7 +109,7 @@ impl CliError { Self { code, exit_code, - message: bound_ascii(message.as_ref()), + message: bound_message(message.as_ref()), } } } @@ -237,12 +236,11 @@ fn run() -> Result<(), CliError> { fn parse_args() -> Result<(PathBuf, PathBuf, Option), CliError> { let mut args = env::args_os(); - let program = args.next().unwrap_or_default(); - let Some(command) = args.next() else { - return Err(usage(&program)); + let Some(command) = args.nth(1) else { + return Err(usage()); }; if command != "compile" { - return Err(usage(&program)); + return Err(usage()); } let mut input = None; @@ -251,23 +249,22 @@ fn parse_args() -> Result<(PathBuf, PathBuf, Option), CliError> { while let Some(argument) = args.next() { match argument.to_str() { Some("--input") => { - input = Some(args.next().ok_or_else(|| usage(&program))?); + input = Some(args.next().ok_or_else(|| usage())?); } Some("--output") => { - output = Some(args.next().ok_or_else(|| usage(&program))?); + output = Some(args.next().ok_or_else(|| usage())?); } Some("--strict-secrets") => strict_override = Some(true), Some("--allow-inline-secrets") => strict_override = Some(false), - _ => return Err(usage(&program)), + _ => return Err(usage()), } } - let input = input.ok_or_else(|| usage(&program))?; - let output = output.ok_or_else(|| usage(&program))?; + let input = input.ok_or_else(|| usage())?; + let output = output.ok_or_else(|| usage())?; Ok((PathBuf::from(input), PathBuf::from(output), strict_override)) } -fn usage(program: &std::ffi::OsStr) -> CliError { - let _ = program; +fn usage() -> CliError { CliError::new( "resource-compiler-usage", "usage: d2b-resource-compiler compile --input --output [--strict-secrets]", @@ -319,8 +316,8 @@ fn compile( "resource-compiler-content-hash-mismatch", format!( "resource bundle contentHash differs between declared ({}) and compiler ({})", - safe_token(expected), - safe_token(&authored_content_hash) + sanitize_token(expected), + sanitize_token(&authored_content_hash) ), )); } @@ -419,8 +416,8 @@ fn verify_artifact_catalog(input: &CompileInput) -> Result { "resource-compiler-catalog-digest-mismatch", format!( "artifact catalog digest differs between declared ({}) and realised ({})", - safe_token(expected), - safe_token(actual) + sanitize_token(expected), + sanitize_token(actual) ), )); } @@ -434,7 +431,7 @@ fn verify_artifact_catalog(input: &CompileInput) -> Result { "provider-artifact-id-not-found", format!( "Provider artifact {} is absent from the realised artifact catalog", - safe_token(&provider.artifact_id) + sanitize_token(&provider.artifact_id) ), )); }; @@ -444,9 +441,9 @@ fn verify_artifact_catalog(input: &CompileInput) -> Result { "provider-artifact-type-invalid", format!( "Provider artifact {} type differs between declared ({}) and realised ({})", - safe_token(&provider.artifact_id), - safe_token(&provider.artifact_type), - safe_token(artifact_type) + sanitize_token(&provider.artifact_id), + sanitize_token(&provider.artifact_type), + sanitize_token(artifact_type) ), )); } @@ -460,9 +457,9 @@ fn verify_artifact_catalog(input: &CompileInput) -> Result { format!( "provider artifact {} digest package differs between catalog ({}) and \ compiler ({})", - safe_token(&provider.artifact_id), - safe_token(realised_package_digest), - safe_token(&provider.package_digest) + sanitize_token(&provider.artifact_id), + sanitize_token(realised_package_digest), + sanitize_token(&provider.package_digest) ), )); } @@ -488,8 +485,8 @@ fn compile_providers( "provider-artifact-type-invalid", format!( "provider artifact {} declares type {} instead of provider", - safe_token(&provider.artifact_id), - safe_token(&provider.artifact_type) + sanitize_token(&provider.artifact_id), + sanitize_token(&provider.artifact_type) ), )); } @@ -599,7 +596,7 @@ fn check_provider_resource_admission( "provider-artifact-id-not-found", format!( "Provider resource artifact ID {} is not present in the declared provider catalog", - safe_token(artifact_id) + sanitize_token(artifact_id) ), )); }; @@ -608,7 +605,7 @@ fn check_provider_resource_admission( "provider-artifact-type-invalid", format!( "Provider resource artifact {} does not select a provider artifact", - safe_token(artifact_id) + sanitize_token(artifact_id) ), )); } @@ -635,7 +632,7 @@ fn check_provider_resource_admission( "provider-schema-digest-missing", format!( "Provider {} has no declared schema digest", - safe_token(provider_name) + sanitize_token(provider_name) ), ) })?; @@ -644,9 +641,9 @@ fn check_provider_resource_admission( "provider-schema-digest-mismatch", format!( "Provider {} schema digest differs between declared ({}) and compiler ({})", - safe_token(provider_name), - safe_token(expected), - safe_token(&provider.config_schema_digest) + sanitize_token(provider_name), + sanitize_token(expected), + sanitize_token(&provider.config_schema_digest) ), )); } @@ -666,9 +663,9 @@ fn check_resource_type_collisions(providers: &[CompiledProvider]) -> Result<(), "provider-resourcetype-collision", format!( "Provider artifacts {} and {} export the same ResourceType {}", - safe_token(&previous), - safe_token(&provider.input.artifact_id), - safe_token(&resource_type) + sanitize_token(&previous), + sanitize_token(&provider.input.artifact_id), + sanitize_token(&resource_type) ), )); } @@ -696,12 +693,28 @@ fn provider_resource_types(manifest: &ProviderManifest) -> BTreeSet { types } +/// Write sink that counts serialized bytes without retaining them. +struct ByteCounter(usize); + +impl std::io::Write for ByteCounter { + fn write(&mut self, buffer: &[u8]) -> std::io::Result { + self.0 += buffer.len(); + Ok(buffer.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + fn validate_resources(input: &CompileInput, strict_secrets: bool) -> Result<(), CliError> { let mut previous_key: Option<(String, String)> = None; - let schema_cache = SchemaCache::new(input.schema_root.as_deref())?; + let mut schema_cache = SchemaCache::new(input.schema_root.as_deref())?; let mut identities = BTreeSet::new(); for (index, resource) in input.resources.iter().enumerate() { - if serde_json::to_vec(resource).map_or(usize::MAX, |bytes| bytes.len()) > MAX_RESOURCE_BYTES + let mut counter = ByteCounter(0); + if serde_json::to_writer(&mut counter, resource).is_err() + || counter.0 > MAX_RESOURCE_BYTES { return Err(CliError::new( "resource-compiler-resource-too-large", @@ -767,9 +780,9 @@ fn validate_resources(input: &CompileInput, strict_secrets: bool) -> Result<(), "resource-compiler-resource-zone-mismatch", format!( "resource {} is assigned to Zone {} instead of the declared Zone {}", - safe_token(name), - safe_token(zone), - safe_token(&input.zone) + sanitize_token(name), + sanitize_token(zone), + sanitize_token(&input.zone) ), )); } @@ -795,7 +808,7 @@ fn validate_resources(input: &CompileInput, strict_secrets: bool) -> Result<(), "resource-compiler-inline-secret", format!( "resource {} contains inline secret-shaped material", - safe_token(name) + sanitize_token(name) ), )); } @@ -1145,7 +1158,7 @@ fn schema_shape_matches(schema: &Value, value: &Value) -> bool { struct SchemaCache { root: Option, - schemas: RefCell>, + schemas: BTreeMap, } fn validate_schema_document(schema: &Value) -> Result<(), CliError> { @@ -1266,7 +1279,7 @@ fn validate_schema_node_with_budget( { return Err(schema_integrity_error(&format!( "{path} contains unsupported keyword {}", - safe_token(keyword) + sanitize_token(keyword) ))); } } @@ -1464,8 +1477,7 @@ fn validate_schema_node_with_budget( )?; } } - if let Some(Value::Object(_)) = object.get("additionalProperties") { - let additional = object.get("additionalProperties").expect("checked above"); + if let Some(additional @ Value::Object(_)) = object.get("additionalProperties") { validate_schema_node_with_budget( additional, root, @@ -1474,8 +1486,7 @@ fn validate_schema_node_with_budget( budget, )?; } - if let Some(Value::Object(_)) = object.get("items") { - let items = object.get("items").expect("checked above"); + if let Some(items @ Value::Object(_)) = object.get("items") { validate_schema_node_with_budget(items, root, &format!("{path}.items"), depth + 1, budget)?; } for keyword in ["allOf", "anyOf", "oneOf"] { @@ -1623,13 +1634,13 @@ impl SchemaCache { } Ok(Self { root: root.map(Path::to_owned), - schemas: RefCell::new(BTreeMap::new()), + schemas: BTreeMap::new(), }) } #[allow(clippy::disallowed_methods, reason = "CLI-only path")] - fn schema(&self, resource_type: &str) -> Result, CliError> { - if let Some(schema) = self.schemas.borrow().get(resource_type) { + fn schema(&mut self, resource_type: &str) -> Result, CliError> { + if let Some(schema) = self.schemas.get(resource_type) { return Ok(Some(schema.clone())); } let Some(root) = &self.root else { @@ -1648,7 +1659,7 @@ impl SchemaCache { "resource-compiler-schema-missing", format!( "schema for ResourceType {} is missing", - safe_token(resource_type) + sanitize_token(resource_type) ), )); } @@ -1677,7 +1688,6 @@ impl SchemaCache { )); } self.schemas - .borrow_mut() .insert(resource_type.to_owned(), schema.clone()); Ok(Some(schema)) } @@ -1986,7 +1996,7 @@ fn compare_schema_numbers( fn schema_error(path: &str, reason: &str) -> CliError { CliError::new( "resource-compiler-schema-invalid", - format!("{} {}", safe_token(path), reason), + format!("{} {}", sanitize_token(path), reason), ) } @@ -2528,35 +2538,4 @@ fn valid_name(value: &str) -> bool { .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || *byte == b'-') } -fn safe_token(value: &str) -> String { - let mut output = String::new(); - for character in value.chars() { - if (character.is_ascii_graphic() && character != '/' && character != '\\') - || character == ' ' - { - output.push(character); - } else { - output.push('?'); - } - } - bound_ascii(&output) -} -fn bound_ascii(value: &str) -> String { - let mut output = String::new(); - for character in value.chars() { - let character = if character.is_control() { - ' ' - } else { - character - }; - if !character.is_ascii() || output.len() + 1 > MAX_DIAGNOSTIC_BYTES { - break; - } - output.push(character); - } - if output.len() < value.len() && output.len() + 3 <= MAX_DIAGNOSTIC_BYTES { - output.push_str("..."); - } - output -} From 628c96492736c73a2f06426f8e1116ddf855fb7d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:18:04 -0700 Subject: [PATCH 209/726] resource-compiler: drop the unused anchored flag accessors --- packages/d2b-resource-compiler/src/linux.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/packages/d2b-resource-compiler/src/linux.rs b/packages/d2b-resource-compiler/src/linux.rs index 4ae468325..9dce9e0ab 100644 --- a/packages/d2b-resource-compiler/src/linux.rs +++ b/packages/d2b-resource-compiler/src/linux.rs @@ -89,21 +89,6 @@ impl LinuxAnchoredDir { } Ok(Self { fd }) } - - /// Return the resolve mask used by all child opens. - pub const fn resolve_flags() -> ResolveFlags { - RESOLVE - } - - /// Return the read-mode flags used by the compiler. - pub const fn readable_flags() -> OFlags { - READ_FLAGS - } - - /// Return the execute-mode flags used by the launcher. - pub const fn executable_flags() -> OFlags { - EXEC_FLAGS - } } impl AnchoredDir for LinuxAnchoredDir { From 636a0a99131a6c0044ca4cfb440ba141a3375305 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:18:31 -0700 Subject: [PATCH 210/726] audit: record wave-1 U2 remainder-b outcomes --- .../2026-09-24-rust-skills-audit/ledger.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 52214e567..b11874227 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -83,13 +83,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U2 | db396585b | `packages/d2b-provider-device-security-key/src/driver.rs` | declared_dependency_refs arms are iterator-chain expressions; push closure deleted | | | `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | swtpm_argv.rs imports and uses MIN/MAX_SWTPM_LOG_LEVEL instead of literal 1..=20 | | | `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | 9e7388e34 | `packages/d2b-provider-device-usbip/src/driver.rs` | declared_dependency_refs match arms return flatten().collect() expressions | | -| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:1442, src/spec.rs:385` | | | -| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:620, packages/d2b-provid` | | | -| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/controller.rs:464, src/process.rs:402, src/process.rs:676` | | | -| `RS-0054` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1272, packages/d2b-provi` | | | -| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:790, packages/d2b-provid` | | | -| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:150` | | | -| `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provid` | | | +| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | free fn delegates to WaylandSessionSpec::session_digest; unused sha2 import dropped | | +| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | re-wrap round-trip deleted; the arm-bound error is used directly | | +| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/{controller.rs,process.rs}` | three stale dead_code allows deleted; process.rs:380 kept (test-support-only) | | +| `RS-0054` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | nested match flattened into if-let/else-if-let chains; early return arms kept | | +| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | enumerate dropped; let _ = index deleted | | +| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs` | written counter replaces the per-iteration chars().count() | | +| `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/{dmabuf.rs,filter.rs,decoration.rs}` | four comment blocks rewritten as plain ASCII with consistent indent | | | `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/effects_service.rs` | Added the unit-test option: pinned inspect-endpoint payload rows to guest_control_producer/device_worker_endpoint_class (set + per-row class/producer/locality). Mutation (locality drift) fails the tes | | | `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/endpoint.rs` | Derive Default on EndpointConsumerPolicy (field-wise empty-Vec default identical to unrestricted()); dropped the manual impl. | | | `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | derive(Default) with #[default] on BootstrapServiceState::Waiting; manual BootstrapService Default impl deleted | | @@ -121,10 +121,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | | `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | | `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/zone_client.rs` | Dropped the duplicate GuestControlEndpoint::endpoint_uid accessor (kept uid()); removed the now-obsolete equivalence assertion. Census: no external caller. | | -| `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:` | | | -| `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:2402` | | | -| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:1724` | | | -| `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/lib.rs:1913` | | | +| `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/{lib.rs,main.rs}` | pub(crate) is not importable from the bin target (E0603), so sanitize_token/bound_message became pub with doc first sentences; main.rs safe_token/bound_ascii deleted and call sites switched; bound_message skips non-ASCII chars where bound_ascii truncated at them (inputs at all call sites are ASCII) | | +| `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | stated filter pipeline would drop replaced chars; map keeps the ? substitution | | +| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | filter_map+collect pipeline; mut kept for the trailing sort | | +| `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | two push loops chained into one collect (the row's snippet was missing parens) | | | `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | derive Default on three unit structs; new() const kept | | | `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | declined | U2 | | `target.rs` | sort_by_key and sort_by_cached_key both rejected by rustc 1.97 (lifetime may not live long enough; closure returns (&str,&str,&str) borrowing the element); kept sort_by | | | `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | shared free manager_rpc transport; both endpoints route through it | | @@ -192,7 +192,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | validate &identity before store; identity stored on failure branch preserving test-pinned retain-for-finalize contract | | | `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | applied-variant | U2 | 3c3a82817 | `packages/d2b-provider-device-tpm/src/resource_controller.rs` | if/else arms cannot mix owned and borrowed; restructured to ensure-then-borrow from the fields (zero clones), plus the two effects_service reborrows | | | `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | d674e47e9 | `packages/d2b-provider-device-usbip/src/broker.rs` | Lease moved into the field first; map and return clone from the field (3 clones down to 2 per admission) | | -| `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provid` | | | +| `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/{policy.rs,dmabuf.rs}` | Arc switched to Rc; type propagated to DmabufFeedbackHandler and DmabufBufferParamsHandler and their test constructions | | | `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied-variant | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/driver.rs` | Applied the row's sort_by comparator, fixing its misplaced-paren typo (teardown_rank().cmp().then_with(name cmp)); drops the per-row name clone. | | | `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/effects_service.rs` | Both ACA candidate lists use state.sandbox.iter().cloned().collect() (and disk_image) instead of clone().into_iter().collect(). | | | `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | declined | U2 | | `src/controller.rs:156-157` | Cannot land as written: BTreeMap::remove(&mut self, &Q) cannot take a key borrowed from the same map (E0502, verified by cargo check); zero-clone claim refuted. Original eviction restored unchanged. | | @@ -232,11 +232,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/client.rs` | scoped_commit_batch and commit_scoped_batch take &[ScopedResourceMutation]; commit_batch_with_scope takes Option<&[..]>; adapter passes transport.mutations() directly. | | | `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/admission.rs` | mutations.into_iter().map(prepare_mutation); the redundant .cloned() removed. | | | `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | | | | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | | | -| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | | | | `packages/d2b-resource-compiler/src/linux.rs:93, packages/d2b-resource-compiler/src/linux.r` | | | -| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:1148, packages/d2b-resource-compiler/src/main.r` | | | -| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:1467, packages/d2b-resource-compiler/src/main.r` | | | -| `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:269, packages/d2b-resource-compiler/src/main.rs` | | | -| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | | | | `packages/d2b-resource-compiler/src/main.rs:704` | | | +| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | applied | U2 | 628c96492 | `packages/d2b-resource-compiler/src/linux.rs` | three flag accessors deleted (zero callers; rustix types out of the public contract) | | +| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | RefCell dropped; schema takes &mut self; cache is a plain BTreeMap; schema_cache marked mut | | +| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | additionalProperties/items pattern-bound; checked-above expects deleted | | +| `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | dropping the argv[0] binding made command read the program name (10 CLI tests failed); variant uses args.nth(1) to keep the skip | | +| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | ByteCounter Write sink replaces the per-resource serde_json::to_vec | | | `RS-0206` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | observed_status filters before clone | | | `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | insert_new takes StoredDesiredResource by value; ensure passes by move | | | `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 0e6061c1e | `resource.rs` | pre_start moves row into state; clones only for ResourceContext::new | | @@ -727,9 +727,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0683` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | Module allow dropped; SwtpmArgvError variant fields documented to satisfy deny(missing_docs) | | | `RS-0684` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | 59c6a4e3a | `packages/d2b-provider-device-usbip/src/reconcile_state.rs` | All pub items documented (compiler-enumerated, incl. trait methods and variant fields); both module allows dropped | | | `RS-0685` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | a1d9832ec | `packages/d2b-provider-device-usbip/src/arbitration.rs` | # Errors added to the eight named pub Result items | | -| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/policy.rs:114, src/policy.rs:119` | | | -| `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provide` | | | -| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759` | | | +| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/policy.rs` | getter docs reworded to Borrow the allowed/denied globals | | +| `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/{bridge.rs,dmabuf.rs,readiness.rs}` | Errors sections added naming BridgeConfigError variants, parse failure modes, and io errors | | +| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/{spec.rs,policy.rs,controller.rs}` | Errors sections added naming WaylandSpecError and PolicyCompileError variants | | | `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/facets.rs` | Added # Errors to row_view, session_target_control, resource_uid, and the GuestTargetEffect trait's realize/delete/adopt. | | | `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 8a45d2d37 | `packages/d2b-provider-guest-azure-container-apps/src/effects.rs` | Documented effects pub surface (consts, enums, opaque_id! expansion, configs, records, candidates, both effect traits) and dropped the module-level allow; crate builds under deny. | | | `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | From d2bd7d025f72be7779d10c813dcb766584068c49 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:20:00 -0700 Subject: [PATCH 211/726] audit: record wave-1 remainder B --- .../2026-09-24-rust-skills-audit/ledger.md | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 215d37839..0ad635374 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -83,13 +83,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U2 | db396585b | `packages/d2b-provider-device-security-key/src/driver.rs` | declared_dependency_refs arms are iterator-chain expressions; push closure deleted | | | `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | swtpm_argv.rs imports and uses MIN/MAX_SWTPM_LOG_LEVEL instead of literal 1..=20 | | | `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | 9e7388e34 | `packages/d2b-provider-device-usbip/src/driver.rs` | declared_dependency_refs match arms return flatten().collect() expressions | | -| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | free fn delegates to WaylandSessionSpec::session_digest; unused sha2 import dropped | | -| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | re-wrap round-trip deleted; the arm-bound error is used directly | | -| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/{controller.rs,process.rs}` | three stale dead_code allows deleted; process.rs:380 kept (test-support-only) | | -| `RS-0054` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | nested match flattened into if-let/else-if-let chains; early return arms kept | | -| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | enumerate dropped; let _ = index deleted | | -| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs` | written counter replaces the per-iteration chars().count() | | -| `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/{dmabuf.rs,filter.rs,decoration.rs}` | four comment blocks rewritten as plain ASCII with consistent indent | | +| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | | | +| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | | | +| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | | | +| `RS-0054` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | row fix text names chains for wm_base/eglstream/compositor; the remaining shm/subcompositor/seat/viewporter/dmabuf/drm if-lets stay in the final else block, matching the row's 'keeping the early retur | | +| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | | | +| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs` | | | +| `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | row says 'four comment blocks' while citing 7 sites; all 7 sites fixed | | | `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/effects_service.rs` | Added the unit-test option: pinned inspect-endpoint payload rows to guest_control_producer/device_worker_endpoint_class (set + per-row class/producer/locality). Mutation (locality drift) fails the tes | | | `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/endpoint.rs` | Derive Default on EndpointConsumerPolicy (field-wise empty-Vec default identical to unrestricted()); dropped the manual impl. | | | `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | derive(Default) with #[default] on BootstrapServiceState::Waiting; manual BootstrapService Default impl deleted | | @@ -121,10 +121,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | | `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | | `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/zone_client.rs` | Dropped the duplicate GuestControlEndpoint::endpoint_uid accessor (kept uid()); removed the now-obsolete equivalence assertion. Census: no external caller. | | -| `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/{lib.rs,main.rs}` | pub(crate) is not importable from the bin target (E0603), so sanitize_token/bound_message became pub with doc first sentences; main.rs safe_token/bound_ascii deleted and call sites switched; bound_message skips non-ASCII chars where bound_ascii truncated at them (inputs at all call sites are ASCII) | | -| `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | stated filter pipeline would drop replaced chars; map keeps the ? substitution | | -| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | filter_map+collect pipeline; mut kept for the trailing sort | | -| `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | two push loops chained into one collect (the row's snippet was missing parens) | | +| `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | stated fix not implementable as written: pub(crate) items in the lib are not importable from the bin target (cargo E0603), so sanitize_token/bound_message became pub with doc first sentences; safe_lab | | +| `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's stated filter pipeline would drop replaced characters; the behavior-preserving variant uses map with the same condition, keeping the '?' substitution (user-visible CLI error text) | | +| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | | | +| `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's literal snippet is missing parentheses; the chain shape used is names.difference(...).map(...).chain(declared_names.difference(...).map(...)).collect() preserving bin= then manifest= order | | | `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | derive Default on three unit structs; new() const kept | | | `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | declined | U2 | | `target.rs` | sort_by_key and sort_by_cached_key both rejected by rustc 1.97 (lifetime may not live long enough; closure returns (&str,&str,&str) borrowing the element); kept sort_by | | | `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | shared free manager_rpc transport; both endpoints route through it | | @@ -192,7 +192,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | validate &identity before store; identity stored on failure branch preserving test-pinned retain-for-finalize contract | | | `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | applied-variant | U2 | 3c3a82817 | `packages/d2b-provider-device-tpm/src/resource_controller.rs` | if/else arms cannot mix owned and borrowed; restructured to ensure-then-borrow from the fields (zero clones), plus the two effects_service reborrows | | | `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | d674e47e9 | `packages/d2b-provider-device-usbip/src/broker.rs` | Lease moved into the field first; map and return clone from the field (3 clones down to 2 per admission) | | -| `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/{policy.rs,dmabuf.rs}` | Arc switched to Rc; type propagated to DmabufFeedbackHandler and DmabufBufferParamsHandler and their test constructions | | +| `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs` | the type must propagate to the two child handlers (DmabufFeedbackHandler, DmabufBufferParamsHandler) and five test constructions, which clone the same filters value; sync::Arc import removed from dmab | | | `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied-variant | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/driver.rs` | Applied the row's sort_by comparator, fixing its misplaced-paren typo (teardown_rank().cmp().then_with(name cmp)); drops the per-row name clone. | | | `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/effects_service.rs` | Both ACA candidate lists use state.sandbox.iter().cloned().collect() (and disk_image) instead of clone().into_iter().collect(). | | | `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | declined | U2 | | `src/controller.rs:156-157` | Cannot land as written: BTreeMap::remove(&mut self, &Q) cannot take a key borrowed from the same map (E0502, verified by cargo check); zero-clone claim refuted. Original eviction restored unchanged. | | @@ -232,11 +232,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/client.rs` | scoped_commit_batch and commit_scoped_batch take &[ScopedResourceMutation]; commit_batch_with_scope takes Option<&[..]>; adapter passes transport.mutations() directly. | | | `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/admission.rs` | mutations.into_iter().map(prepare_mutation); the redundant .cloned() removed. | | | `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | | | | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | | | -| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | applied | U2 | 628c96492 | `packages/d2b-resource-compiler/src/linux.rs` | three flag accessors deleted (zero callers; rustix types out of the public contract) | | -| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | RefCell dropped; schema takes &mut self; cache is a plain BTreeMap; schema_cache marked mut | | -| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | additionalProperties/items pattern-bound; checked-above expects deleted | | -| `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | dropping the argv[0] binding made command read the program name (10 CLI tests failed); variant uses args.nth(1) to keep the skip | | -| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | ByteCounter Write sink replaces the per-resource serde_json::to_vec | | +| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | applied | U2 | 628c96492 | `packages/d2b-resource-compiler/src/linux.rs` | | | +| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | | | +| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | | | +| `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | row's stated fix (drop the argv[0] binding) is functionally broken; minimal correct variant keeps the skip via args.nth(1) | | +| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | | | | `RS-0206` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | observed_status filters before clone | | | `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | insert_new takes StoredDesiredResource by value; ensure passes by move | | | `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 0e6061c1e | `resource.rs` | pre_start moves row into state; clones only for ResourceContext::new | | @@ -727,9 +727,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0683` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | Module allow dropped; SwtpmArgvError variant fields documented to satisfy deny(missing_docs) | | | `RS-0684` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | 59c6a4e3a | `packages/d2b-provider-device-usbip/src/reconcile_state.rs` | All pub items documented (compiler-enumerated, incl. trait methods and variant fields); both module allows dropped | | | `RS-0685` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | a1d9832ec | `packages/d2b-provider-device-usbip/src/arbitration.rs` | # Errors added to the eight named pub Result items | | -| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/policy.rs` | getter docs reworded to Borrow the allowed/denied globals | | -| `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/{bridge.rs,dmabuf.rs,readiness.rs}` | Errors sections added naming BridgeConfigError variants, parse failure modes, and io errors | | -| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/{spec.rs,policy.rs,controller.rs}` | Errors sections added naming WaylandSpecError and PolicyCompileError variants | | +| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/policy.rs` | | | +| `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs` | from_identity_parts, path_for_user_identity, parse_filter, and the three ReadinessReporter methods had no doc comment at all; each received a first sentence plus the # Errors section (the readiness co | | +| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/spec.rs` | | | | `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/facets.rs` | Added # Errors to row_view, session_target_control, resource_uid, and the GuestTargetEffect trait's realize/delete/adopt. | | | `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 8a45d2d37 | `packages/d2b-provider-guest-azure-container-apps/src/effects.rs` | Documented effects pub surface (consts, enums, opaque_id! expansion, configs, records, candidates, both effect traits) and dropped the module-level allow; crate builds under deny. | | | `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | From 30258fd9bf5467318563a9330b8d3226e89036d8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:53:35 -0700 Subject: [PATCH 212/726] d2b-contracts-resource: extend redacted_debug field value form --- .../src/v3/execution_policy.rs | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/packages/d2b-contracts-resource/src/v3/execution_policy.rs b/packages/d2b-contracts-resource/src/v3/execution_policy.rs index 08a537093..2304fa991 100644 --- a/packages/d2b-contracts-resource/src/v3/execution_policy.rs +++ b/packages/d2b-contracts-resource/src/v3/execution_policy.rs @@ -20,6 +20,7 @@ use super::{ #[macro_export] macro_rules! redacted_debug { + // Whole-value redaction: `Type()`. ($type:ty) => { impl core::fmt::Debug for $type { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -27,6 +28,85 @@ macro_rules! redacted_debug { } } }; + // Field-level redaction: `Type { field: value, ... }`. Each value is + // rendered by one of the `redacted_debug_field_*` helpers: a closure + // borrowing a field renders the value itself, a closure evaluating an + // expression (collection length, option presence) renders its result, + // and a closure returning the `""` literal redacts the field. + ($type:ty, $($field:ident: $kind:ident($closure:expr)),+ $(,)?) => { + impl core::fmt::Debug for $type { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut debug = f.debug_struct(stringify!($type)); + $( + debug.field(stringify!($field), &$kind($closure, self)); + )+ + debug.finish() + } + } + }; + // Field-level redaction with a non-exhaustive tail: `Type { ..., .. }`. + ($type:ty, non_exhaustive, $($field:ident: $kind:ident($closure:expr)),+ $(,)?) => { + impl core::fmt::Debug for $type { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut debug = f.debug_struct(stringify!($type)); + $( + debug.field(stringify!($field), &$kind($closure, self)); + )+ + debug.finish_non_exhaustive() + } + } + }; + // Enum variant redaction: payload-bearing variants render as + // `Type::Variant()`; unit variants listed after `; plain:` + // render as `Type::Variant`. + ($type:ty, variants: $($redacted:ident),+ $(,)? ; plain: $($plain:ident),+ $(,)?) => { + impl core::fmt::Debug for $type { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + $( + Self::$redacted { .. } => f.write_str(concat!( + stringify!($type), + "::", + stringify!($redacted), + "()" + )), + )+ + $( + Self::$plain => f.write_str(concat!( + stringify!($type), + "::", + stringify!($plain) + )), + )+ + } + } + } + }; +} + +/// Renders one `redacted_debug!` field closure's borrowed value. +/// +/// The closure receives `&T` and returns a borrowed `&R`; the returned +/// reference is passed to the debug formatter unchanged. The HRTB bound +/// lets the closure borrow from its argument for any lifetime, which keeps +/// `&self` borrows valid through the formatter call. +pub fn redacted_debug_field_ref( + value: impl for<'a> FnOnce(&'a T) -> &'a R, + this: &T, +) -> &R { + value(this) +} + +/// Renders one `redacted_debug!` field closure's owned value. + +/// The closure receives `&T` and returns an owned `R` (a collection length, +/// an option presence, or the `""` literal); the returned value is +/// passed to the debug formatter unchanged. +pub fn redacted_debug_field_value( + value: impl FnOnce(&T) -> R, + this: &T, +) -> R { + value(this) } #[macro_export] From f5dd934fc97faeca4f37fc1da3f1ed3986448777 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:53:37 -0700 Subject: [PATCH 213/726] d2b-resource-api: fold redaction Debug impls onto redacted_debug --- packages/d2b-resource-api/src/admission.rs | 85 ++++-- packages/d2b-resource-api/src/authz.rs | 295 ++++++++++----------- 2 files changed, 200 insertions(+), 180 deletions(-) diff --git a/packages/d2b-resource-api/src/admission.rs b/packages/d2b-resource-api/src/admission.rs index 9f944844a..fa0bc0566 100644 --- a/packages/d2b-resource-api/src/admission.rs +++ b/packages/d2b-resource-api/src/admission.rs @@ -1,6 +1,7 @@ //! Instance-bound admission witnesses owned by the native evaluator. use d2b_contracts_resource::redacted_debug; +use d2b_contracts_resource::v3::execution_policy::redacted_debug_field_value; use d2b_contracts_resource::v3::{ CanonicalJsonValue, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceEnvelope, RetryClass, canonical_digest, @@ -83,17 +84,12 @@ pub(crate) struct AdmissionPermit { zone_policy_revision: u64, } -impl core::fmt::Debug for AdmissionPermit { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("AdmissionPermit") - .field("target_count", &self.authorization.targets.len()) - .field("authorization", &"") - .field("policy_snapshot", &"") - .field("authority", &"") - .field("store_identity", &"") - .finish() - } -} +redacted_debug!(AdmissionPermit, + target_count: redacted_debug_field_value(|s| s.authorization.targets.len()), + authorization: redacted_debug_field_value(|_| ""), + policy_snapshot: redacted_debug_field_value(|_| ""), + authority: redacted_debug_field_value(|_| ""), + store_identity: redacted_debug_field_value(|_| "")); impl AdmissionIssuer { /// Capture one allow returned by the evaluator that owns this capability. @@ -305,22 +301,14 @@ impl AdmittedMutation { } } -impl core::fmt::Debug for AdmittedMutation { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("AdmittedMutation") - .field("mutation_count", &self.mutations.len()) - .field("authorization", &"") - .field("policy_snapshot", &"") - .field("operation", &"") - .field( - "has_authorization_lease", - &self.authorization_lease.is_some(), - ) - .field("authority", &"") - .field("store_identity", &"") - .finish() - } -} +redacted_debug!(AdmittedMutation, + mutation_count: redacted_debug_field_value(|s| s.mutations.len()), + authorization: redacted_debug_field_value(|_| ""), + policy_snapshot: redacted_debug_field_value(|_| ""), + operation: redacted_debug_field_value(|_| ""), + has_authorization_lease: redacted_debug_field_value(|s| s.authorization_lease.is_some()), + authority: redacted_debug_field_value(|_| ""), + store_identity: redacted_debug_field_value(|_| "")); impl StoreAdmissionBinding { pub(super) fn verify( @@ -759,4 +747,47 @@ mod tests { } } } + + #[test] + fn redaction_debug_shapes_remain_byte_identical() { + let protected_authorization = AdmittedAuthorization { + zone: ZoneId::parse("probe-zone").unwrap(), + subject_ref: ResourceRef::parse("Provider/probe-subject").unwrap(), + subject_uid: ResourceUid::parse("123e4567-e89b-42d3-a456-426614174000").unwrap(), + targets: vec![d2b_contracts_resource::v3::AdmittedAuthorizationTarget { + resource_type: ResourceTypeName::parse("Host").unwrap(), + resource_name: Some(ResourceName::parse("probe-name").unwrap()), + verb: d2b_contracts_resource::v3::AdmittedVerb::Delete, + subresource: Some("probe-payload".to_owned()), + execution_ref: Some(ResourceRef::parse("Process/probe-ref").unwrap()), + }], + }; + let (issuer, _store_binding) = admission_pair(); + let permit = issuer.record_allow(protected_authorization, snapshot()); + assert_eq!( + format!("{permit:?}"), + "AdmissionPermit { target_count: 1, authorization: \"\", \ + policy_snapshot: \"\", authority: \"\", \ + store_identity: \"\" }" + ); + let admitted = permit + .admit( + vec![mutation("probe-zone")], + StoreOperationContext { + operation_id: "probe-operation".to_owned(), + idempotency_key: None, + correlation_id: "probe-correlation".to_owned(), + trace_id: None, + deadline_ms: 1, + }, + ) + .unwrap(); + assert_eq!( + format!("{admitted:?}"), + "AdmittedMutation { mutation_count: 1, authorization: \"\", \ + policy_snapshot: \"\", operation: \"\", \ + has_authorization_lease: false, authority: \"\", \ + store_identity: \"\" }" + ); + } } diff --git a/packages/d2b-resource-api/src/authz.rs b/packages/d2b-resource-api/src/authz.rs index c40c7dd6f..e6111649c 100644 --- a/packages/d2b-resource-api/src/authz.rs +++ b/packages/d2b-resource-api/src/authz.rs @@ -6,6 +6,9 @@ use std::{ }; use d2b_contracts_resource::redacted_debug; +use d2b_contracts_resource::v3::execution_policy::{ + redacted_debug_field_ref, redacted_debug_field_value, +}; use d2b_contracts_resource::v3::identity::STANDARD_RESOURCE_TYPES; use d2b_contracts_resource::v3::identity::{AuthenticatedSubjectContext, EvidenceClass, Locality}; use d2b_contracts_resource::v3::{ @@ -117,13 +120,8 @@ impl Default for ApiCatalog { } } -impl core::fmt::Debug for ApiCatalog { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ApiCatalog") - .field("resource_type_count", &self.resource_types.len()) - .finish() - } -} +redacted_debug!(ApiCatalog, + resource_type_count: redacted_debug_field_value(|s| s.resource_types.len())); /// Resource methods distinguished from their authorization verb. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -282,18 +280,9 @@ impl BootstrapStoreFacts { } } } -impl core::fmt::Debug for BootstrapStoreFacts { - fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter - .debug_struct("BootstrapStoreFacts") - .field("policy_revision", &"") - .field( - "bootstrap_provider_count", - &self.bootstrap_provider_uids.len(), - ) - .finish_non_exhaustive() - } -} +redacted_debug!(BootstrapStoreFacts, non_exhaustive, + policy_revision: redacted_debug_field_value(|_| ""), + bootstrap_provider_count: redacted_debug_field_value(|s| s.bootstrap_provider_uids.len())); /// Derive the bootstrap phase from trusted store state only. /// @@ -355,15 +344,10 @@ pub struct DurablePolicyRow { pub provenance: DurableRowProvenance, } -impl core::fmt::Debug for DurablePolicyRow { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("DurablePolicyRow") - .field("resource_ref", &"") - .field("canonical_bytes", &self.canonical_json.len()) - .field("provenance", &self.provenance) - .finish() - } -} +redacted_debug!(DurablePolicyRow, + resource_ref: redacted_debug_field_value(|_| ""), + canonical_bytes: redacted_debug_field_value(|s| s.canonical_json.len()), + provenance: redacted_debug_field_ref(|s| &s.provenance)); /// The compiled authorization facts for one Zone (KTD6): the installed /// policy set (absent while bootstrap is open) and the durable bootstrap @@ -374,14 +358,9 @@ pub struct CompiledAuthorizationFacts { pub bootstrap: BootstrapStoreFacts, } -impl core::fmt::Debug for CompiledAuthorizationFacts { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("CompiledAuthorizationFacts") - .field("has_policy", &self.policy.is_some()) - .field("bootstrap", &self.bootstrap) - .finish() - } -} +redacted_debug!(CompiledAuthorizationFacts, + has_policy: redacted_debug_field_value(|s| s.policy.is_some()), + bootstrap: redacted_debug_field_ref(|s| &s.bootstrap)); /// The Zone's durable policy revision derives from the Nix bundle /// generation (seeded at materialization time) plus durable row state. Any @@ -555,75 +534,42 @@ pub struct PolicyRule { execution_refs: BTreeSet, } -impl core::fmt::Debug for AuthorizationTarget { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("AuthorizationTarget") - .field("verb", &self.verb) - .field("resource_type", &"") - .field("has_resource_name", &self.resource_name.is_some()) - .field("has_subresource", &self.subresource.is_some()) - .field("has_execution_ref", &self.execution_ref.is_some()) - .finish() - } -} +redacted_debug!(AuthorizationTarget, + verb: redacted_debug_field_ref(|s| &s.verb), + resource_type: redacted_debug_field_value(|_| ""), + has_resource_name: redacted_debug_field_value(|s| s.resource_name.is_some()), + has_subresource: redacted_debug_field_value(|s| s.subresource.is_some()), + has_execution_ref: redacted_debug_field_value(|s| s.execution_ref.is_some())); -impl core::fmt::Debug for AuthorizationRequest { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("AuthorizationRequest") - .field("method", &self.method) - .field("zone", &"") - .field("target_count", &self.targets.len()) - .finish() - } -} +redacted_debug!(AuthorizationRequest, + method: redacted_debug_field_ref(|s| &s.method), + zone: redacted_debug_field_value(|_| ""), + target_count: redacted_debug_field_value(|s| s.targets.len())); -impl core::fmt::Debug for AuthorizationState { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("AuthorizationState") - .field("snapshot", &"") - .field("zone_policy_revision", &"") - .field("bootstrap_phase", &self.bootstrap_phase) - .field("now_tick", &"") - .finish() - } -} +redacted_debug!(AuthorizationState, + snapshot: redacted_debug_field_value(|_| ""), + zone_policy_revision: redacted_debug_field_value(|_| ""), + bootstrap_phase: redacted_debug_field_ref(|s| &s.bootstrap_phase), + now_tick: redacted_debug_field_value(|_| "")); -impl core::fmt::Debug for BootstrapPhase { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(match self { - Self::Unprovisioned { .. } => "BootstrapPhase::Unprovisioned()", - Self::Provisioned { .. } => "BootstrapPhase::Provisioned()", - Self::Disabled => "BootstrapPhase::Disabled", - }) - } -} +redacted_debug!(BootstrapPhase, variants: Unprovisioned, Provisioned; plain: Disabled); redacted_debug!(BoundSubject); -impl core::fmt::Debug for BindingScope { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("BindingScope") - .field("zone_count", &self.zones.len()) - .field("resource_name_count", &self.resource_names.len()) - .field("resource_ref_count", &self.resource_refs.len()) - .field("execution_ref_count", &self.execution_refs.len()) - .finish() - } -} - -impl core::fmt::Debug for PolicyRule { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("PolicyRule") - .field("resource_type_count", &self.resource_types.len()) - .field("resource_verb_count", &self.resource_verbs.len()) - .field("session_verb_count", &self.session_verbs.len()) - .field("subresource_count", &self.subresources.len()) - .field("resource_name_count", &self.resource_names.len()) - .field("zone_count", &self.zones.len()) - .field("execution_ref_count", &self.execution_refs.len()) - .finish() - } -} +redacted_debug!(BindingScope, + zone_count: redacted_debug_field_value(|s| s.zones.len()), + resource_name_count: redacted_debug_field_value(|s| s.resource_names.len()), + resource_ref_count: redacted_debug_field_value(|s| s.resource_refs.len()), + execution_ref_count: redacted_debug_field_value(|s| s.execution_refs.len())); + +redacted_debug!(PolicyRule, + resource_type_count: redacted_debug_field_value(|s| s.resource_types.len()), + resource_verb_count: redacted_debug_field_value(|s| s.resource_verbs.len()), + session_verb_count: redacted_debug_field_value(|s| s.session_verbs.len()), + subresource_count: redacted_debug_field_value(|s| s.subresources.len()), + resource_name_count: redacted_debug_field_value(|s| s.resource_names.len()), + zone_count: redacted_debug_field_value(|s| s.zones.len()), + execution_ref_count: redacted_debug_field_value(|s| s.execution_refs.len())); impl PolicyRule { #[allow(clippy::too_many_arguments)] @@ -851,14 +797,9 @@ pub struct CompiledRole { pub rules: Vec, } -impl core::fmt::Debug for CompiledRole { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("CompiledRole") - .field("role_ref", &"") - .field("rule_count", &self.rules.len()) - .finish() - } -} +redacted_debug!(CompiledRole, + role_ref: redacted_debug_field_value(|_| ""), + rule_count: redacted_debug_field_value(|s| s.rules.len())); impl CompiledRole { /// Validate and compile one signed role's rule set. @@ -898,16 +839,11 @@ pub struct CompiledRoleBinding { narrowing: Option>, } -impl core::fmt::Debug for CompiledRoleBinding { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("CompiledRoleBinding") - .field("role_ref", &"") - .field("subject_count", &self.subjects.len()) - .field("scope", &self.scope) - .field("relay_authority", &self.relay_authority) - .finish() - } -} +redacted_debug!(CompiledRoleBinding, + role_ref: redacted_debug_field_value(|_| ""), + subject_count: redacted_debug_field_value(|s| s.subjects.len()), + scope: redacted_debug_field_ref(|s| &s.scope), + relay_authority: redacted_debug_field_ref(|s| &s.relay_authority)); impl CompiledRoleBinding { /// Validate and compile one role binding's subject, scope, and relay @@ -1081,16 +1017,11 @@ pub struct PolicySet { bindings: Vec, } -impl core::fmt::Debug for PolicySet { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("PolicySet") - .field("policy_revision", &"") - .field("catalog", &self.catalog) - .field("role_count", &self.roles.len()) - .field("binding_count", &self.bindings.len()) - .finish() - } -} +redacted_debug!(PolicySet, + policy_revision: redacted_debug_field_value(|_| ""), + catalog: redacted_debug_field_ref(|s| &s.catalog), + role_count: redacted_debug_field_value(|s| s.roles.len()), + binding_count: redacted_debug_field_value(|s| s.bindings.len())); impl PolicySet { /// Validate and index one policy revision's roles and bindings. @@ -1139,14 +1070,9 @@ pub struct PositiveCapabilities { pub session_verbs: BTreeSet, } -impl core::fmt::Debug for PositiveCapabilities { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("PositiveCapabilities") - .field("resource_count", &self.resources.len()) - .field("session_verb_count", &self.session_verbs.len()) - .finish() - } -} +redacted_debug!(PositiveCapabilities, + resource_count: redacted_debug_field_value(|s| s.resources.len()), + session_verb_count: redacted_debug_field_value(|s| s.session_verbs.len())); /// Typed fail-closed authorization outcome. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -1253,24 +1179,15 @@ pub struct AuthorizationLease { operation_id: String, } -impl core::fmt::Debug for AuthorizationLease { - fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter - .debug_struct("AuthorizationLease") - .field("subject_uid", &"") - .field("zone_uid", &"") - .field("has_object_uid", &self.object_uid.is_some()) - .field("has_object_generation", &self.object_generation.is_some()) - .field("operation", &self.operation) - .field("policy_revision", &"") - .field( - "has_provider_assignment_generation", - &self.provider_assignment_generation.is_some(), - ) - .field("operation_id", &"") - .finish() - } -} +redacted_debug!(AuthorizationLease, + subject_uid: redacted_debug_field_value(|_| ""), + zone_uid: redacted_debug_field_value(|_| ""), + has_object_uid: redacted_debug_field_value(|s| s.object_uid.is_some()), + has_object_generation: redacted_debug_field_value(|s| s.object_generation.is_some()), + operation: redacted_debug_field_ref(|s| &s.operation), + policy_revision: redacted_debug_field_value(|_| ""), + has_provider_assignment_generation: redacted_debug_field_value(|s| s.provider_assignment_generation.is_some()), + operation_id: redacted_debug_field_value(|_| "")); const _: fn() = || { trait CapabilityMustNotImplementCloneCopyDefaultOrFrom { @@ -3716,4 +3633,76 @@ mod tests { AuthorizationDenial::NoMatchingGrant, ); } + + #[test] + fn redaction_debug_shapes_remain_byte_identical() { + let zone = ZoneId::parse("dev").unwrap(); + let facts = BootstrapStoreFacts::from_durable_spec_facts( + zone.clone(), + 0, + BTreeMap::from([( + ResourceName::parse("system-core").unwrap(), + ResourceUid::parse("123e4567-e89b-42d3-a456-426614174000").unwrap(), + )]), + ControllerGeneration::new(11).unwrap(), + ResourceGeneration::new(12).unwrap(), + ); + assert_eq!( + format!("{facts:?}"), + "BootstrapStoreFacts { policy_revision: \"\", \ + bootstrap_provider_count: 1, .. }" + ); + let row = DurablePolicyRow { + resource_ref: ResourceRef::parse("Role/probe-sentinel").unwrap(), + canonical_json: vec![1, 2, 3], + provenance: DurableRowProvenance::Bundle, + }; + assert_eq!( + format!("{row:?}"), + "DurablePolicyRow { resource_ref: \"\", canonical_bytes: 3, \ + provenance: Bundle }" + ); + let compiled = CompiledAuthorizationFacts { + policy: None, + bootstrap: facts.clone(), + }; + assert_eq!( + format!("{compiled:?}"), + "CompiledAuthorizationFacts { has_policy: false, \ + bootstrap: BootstrapStoreFacts { policy_revision: \"\", \ + bootstrap_provider_count: 1, .. } }" + ); + let provisioned = BootstrapPhase::Provisioned { + zone: zone.clone(), + system_core_uid: ResourceUid::parse("123e4567-e89b-42d3-a456-426614174000").unwrap(), + system_minijail_uid: ResourceUid::parse("223e4567-e89b-42d3-a456-426614174000").unwrap(), + controller_generation: ControllerGeneration::new(11).unwrap(), + provider_generation: ResourceGeneration::new(12).unwrap(), + }; + assert_eq!( + format!("{provisioned:?}"), + "BootstrapPhase::Provisioned()" + ); + assert_eq!(format!("{:?}", BootstrapPhase::Disabled), "BootstrapPhase::Disabled"); + let lease = AuthorizationLease::issue( + ResourceUid::parse("123e4567-e89b-42d3-a456-426614174000").unwrap(), + ResourceUid::parse("223e4567-e89b-42d3-a456-426614174000").unwrap(), + AuthorizationLeaseTarget { + uid: Some(ResourceUid::parse("323e4567-e89b-42d3-a456-426614174000").unwrap()), + generation: Some(ResourceGeneration::new(4).unwrap()), + }, + AdmittedVerb::UpdateSpec, + 7, + Some(ResourceGeneration::new(9).unwrap()), + "operation-lease".to_owned(), + ) + .unwrap(); + assert_eq!( + format!("{lease:?}"), + "AuthorizationLease { subject_uid: \"\", zone_uid: \"\", \ + has_object_uid: true, has_object_generation: true, operation: UpdateSpec, \ + policy_revision: \"\", \ + has_provider_assignment_generation: true, operation_id: \"\" }" + ); + } } From b3c1b452fa1765440b2bf217aa0cd6c056f8c8bb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:54:03 -0700 Subject: [PATCH 214/726] audit: record the final wave-1 row The redaction macro gained a count-preserving field form so the seventeen hand-written Debug impls could fold onto it with byte-identical output, proven by new permanent pins. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 0ad635374..5d1f7350a 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -117,7 +117,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix (envelope.base.get("provider").cloned()) is type-incompatible: base.get yields CanonicalJsonValue not serde_json::Value. Applied minimal variant: dropped the dead unwrap_or fallback via an | | | `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/status.rs` | LayoutPhase::worse now uses derived self.max(other); declaration order already encodes severity. | | | `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | -| `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | not-started | U2 | | `packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, pa` | 17 hand-written redaction Debug impls to redacted_debug! (or macro extension plus Debug-shape test updates); effort M; not started within this run. | | +| `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | f5dd934fc | `packages/d2b-contracts-resource/src/v3/execution_policy.rs` | The redacted_debug macro was extended with a closure-based field-preserving form (two exported helper fns redacted_debug_field_ref and redacted_debug_field_value), and all 17 hand-written redaction De | | | `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | | `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | | `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/zone_client.rs` | Dropped the duplicate GuestControlEndpoint::endpoint_uid accessor (kept uid()); removed the now-obsolete equivalence assertion. Census: no external caller. | | From eef3c6e946bcc46c85aa2f5bef5b10602aa55007 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:54:48 -0700 Subject: [PATCH 215/726] audit: normalise the one stale outcome into the ledger vocabulary RS-0696 was recorded as claim-stale; the ledger names that state skipped-stale. Wave 1 now accounts for all 368 of its rows. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 5d1f7350a..e5d21107f 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -737,7 +737,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs` | # Errors sections on GuestSetupDescriptor new/from_canonical_bytes/canonical_bytes/validate_integrity/verify_with, GuestChildBatch::from_descriptor, and the health evidence constructors. | | | `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U2 | 613491144 | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | # Errors added to DeviceAdmission::validate, QemuMediaController::reconcile, LaunchTicket::new, QmpSession::negotiate | | | `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/action_nonce.rs` | # Errors sections on ActionNonceStore::register, NotificationRuntime::new, NotificationSink::deliver_from_guest_source naming exact variants. | | -| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | claim-stale | U2 | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | All three cited docs are complete standalone first sentences at baseline 6ebdd4cec (verified via git show) and HEAD; the lane quoted tail lines of multi-line docs. | | +| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | skipped-stale | U2 | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | All three cited docs are complete standalone first sentences at baseline 6ebdd4cec (verified via git show) and HEAD; the lane quoted tail lines of multi-line docs. | | | `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/lib.rs` | Added one-line doc comments to PROVIDER_NAME, PROVIDER_REF, PROVIDER_API_MAJOR mirroring OTEL_HOST_BRIDGE_ROLE. | | | `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/agent.rs` | Added # Errors to ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream, EmitterSocket::bin | | | `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | applied | U2 | 4e381161f | `packages/d2b-provider-operation/src/operation.rs` | Added one-line # Errors naming OperationContractError variants to OperationAudit::new, AuditJoin::new, OperationFds::new, OperationBounds::new, OperationSpec::new. | | From 063d1b617aa01b19819bebb428607098514077df Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 03:57:11 -0700 Subject: [PATCH 216/726] changelog: record the wave-1 library contract and idiom work The fragment now carries the consumer-visible effect of the wave: documented library contracts with runnable examples, iterator and derive simplifications in place of hand-written forms, and the clones and dead rebindings the ownership lens removed. --- changelog.d/refactor-rust-skills-remediation.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.d/refactor-rust-skills-remediation.md b/changelog.d/refactor-rust-skills-remediation.md index 0a65a2bc2..3ec5f54dd 100644 --- a/changelog.d/refactor-rust-skills-remediation.md +++ b/changelog.d/refactor-rust-skills-remediation.md @@ -3,3 +3,9 @@ - Repaired three tests that could not fail - the daemon readiness pair, the bus telemetry closed-label check, and the Wayland display registry handlers - so each one now fails when the behaviour it names breaks, and dropped a redundant revision-display assertion that could never fail either way. - Malformed wire input no longer panics the broker, the daemon runtime, or the Wayland policy engine: a malformed authoritative audit join, a malformed broker zone digest, and a malformed driver zone token now return typed refusals at those boundaries. - Moved blocking reaping, file locking, ACL application, and NSS group lookup off the broker's async executor workers, so a busy executor no longer stalls on host syscalls. + +### Changed + +- Documented the workspace's Rust library surface: crate and module docs, one-line summaries, `# Errors`/`# Panics`/`# Safety` sections, and runnable examples on the items that stated no contract, across the CLI, the bus, the daemon runtime, the broker, the resource runtime, and `xtask`. +- Simplified expression-level code: iterator pipelines over index loops, derived `Default` and `Debug` implementations over hand-written ones, `From`/`FromStr` conversions over ad-hoc parsers, and shared helpers where the same scaffold was copied. +- Removed clones, copies, and dead rebindings that ownership did not require, keeping the same sharing, locking, and borrow boundaries. From d324225ef9466776e8f992cd36187ffd7a52a391 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 04:08:48 -0700 Subject: [PATCH 217/726] d2bd: take the audit event by value at every call site The daemon runtime's audit writers now consume the event, so the daemon's nine call sites stop borrowing it. One site built the same event twice, once for the authority lookup and once for the write; it now builds it once, borrows it for the authority, and moves it into the writer. --- packages/d2bd/src/composition.rs | 39 ++++++++++++++------------------ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index aa3e150ae..9a71b840a 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -8276,7 +8276,7 @@ fn record_workload_launch_result( state .daemon_audit .write_event_with_authority( - &d2bd_runtime::daemon_audit::DaemonEvent::WorkloadLauncher { + d2bd_runtime::daemon_audit::DaemonEvent::WorkloadLauncher { target: context.target.clone(), item_id: context.item_id.clone(), operation_id: operation_id.to_string(), @@ -12395,7 +12395,8 @@ fn emit_provider_shell_audit(state: &ServerState, event: ProviderShellAudit<'_>) let _ = state .daemon_audit - .write_event(&d2bd_runtime::daemon_audit::DaemonEvent::ShellLifecycle { + .write_event( + d2bd_runtime::daemon_audit::DaemonEvent::ShellLifecycle { target: event.target.to_owned(), peer_uid: event.peer_uid, provider: event.provider, @@ -13849,7 +13850,7 @@ fn new_public_shell_session_handle() -> Result { fn emit_detached_create_audit(state: &ServerState, peer_uid: u32, vm: &str, exec_id: &str) { if let Err(err) = state.daemon_audit.write_event( - &d2bd_runtime::daemon_audit::DaemonEvent::ComponentSessionExecDetachedCreate { + d2bd_runtime::daemon_audit::DaemonEvent::ComponentSessionExecDetachedCreate { vm: vm.to_owned(), peer_uid, action: d2bd_runtime::daemon_audit::DetachedExecAuditAction::Create, @@ -15155,22 +15156,15 @@ async fn audit_resource_plane( action: d2bd_runtime::daemon_audit::ResourcePlaneAction, result: d2bd_runtime::daemon_audit::ResourcePlaneResult, ) -> Result<(), std::io::Error> { + let event = d2bd_runtime::daemon_audit::DaemonEvent::ResourcePlaneLifecycle { + zone: zone.as_str().to_owned(), + action, + result, + }; + let authority = d2bd_runtime::daemon_audit::DaemonAuditLog::authority_for(&event); state .daemon_audit - .write_event_with_authority_async( - &d2bd_runtime::daemon_audit::DaemonEvent::ResourcePlaneLifecycle { - zone: zone.as_str().to_owned(), - action, - result, - }, - d2bd_runtime::daemon_audit::DaemonAuditLog::authority_for( - &d2bd_runtime::daemon_audit::DaemonEvent::ResourcePlaneLifecycle { - zone: zone.as_str().to_owned(), - action, - result, - }, - ), - ) + .write_event_with_authority_async(event, authority) .await } @@ -16338,7 +16332,7 @@ fn emit_vm_shutdown_intent_audit( ) -> Result<(), std::io::Error> { let peer_uid = broker_caller_uid(caller_role); state.daemon_audit.write_event_with_authority( - &d2bd_runtime::daemon_audit::DaemonEvent::VmShutdownIntent { + d2bd_runtime::daemon_audit::DaemonEvent::VmShutdownIntent { vm: vm.to_owned(), peer_uid, provider: provider_audit_label(provider), @@ -16359,7 +16353,7 @@ fn emit_vm_shutdown_outcome_audit( ) -> Result<(), std::io::Error> { let peer_uid = broker_caller_uid(caller_role); state.daemon_audit.write_event_with_authority( - &d2bd_runtime::daemon_audit::DaemonEvent::VmShutdownOutcome { + d2bd_runtime::daemon_audit::DaemonEvent::VmShutdownOutcome { vm: vm.to_owned(), peer_uid, provider: provider_audit_label(provider), @@ -19384,7 +19378,7 @@ fn dispatch_broker_vm_start_inner( ); // Emit audit-log entry on api-ready timeout. if let Err(err) = state.daemon_audit.write_event( - &d2bd_runtime::daemon_audit::DaemonEvent::ApiReadyTimeout { + d2bd_runtime::daemon_audit::DaemonEvent::ApiReadyTimeout { vm: request.vm.clone(), runner: VM_RUNNER_ROLE_ID.to_owned(), elapsed_secs: api_timeout.as_secs(), @@ -19649,7 +19643,7 @@ fn emit_vm_start_runner_exited_audit( exit_signal: status.and_then(|status| status.signal), elapsed_ms, }; - if let Err(error) = state.daemon_audit.write_event(&event) { + if let Err(error) = state.daemon_audit.write_event(event) { tracing::warn!( vm = %vm, role_id = %role_id, @@ -28716,7 +28710,8 @@ mod broker_dispatch_tests { // dispatch_broker_vm_start writes. state .daemon_audit - .write_event(&d2bd_runtime::daemon_audit::DaemonEvent::ApiReadyTimeout { + .write_event( + d2bd_runtime::daemon_audit::DaemonEvent::ApiReadyTimeout { vm: "vm-a".to_owned(), runner: VM_RUNNER_ROLE_ID.to_owned(), elapsed_secs: 120, From d1701b009f30e4b66165049769f4ea729bef02eb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 04:39:13 -0700 Subject: [PATCH 218/726] census: record two deny-class counts the wave moved, with their context The clippy-derived count now sees two std::sync::Mutex::lock sites in the bus crate's cfg(test) seam module - a test-only context that carries the sanctioned helper reason elsewhere in the same file - and two more std::fs::read_to_string sites in xtask, whose scanner rewrite reads source files at tool time, never from an executor worker. The raw occurrence totals are unchanged at the base commit, so this is the counter resolving sites it did not resolve before, not new blocking work on an async path. --- packages/xtask/data/blocking-census-baseline.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xtask/data/blocking-census-baseline.json b/packages/xtask/data/blocking-census-baseline.json index d5369b982..1ec8dd9a6 100644 --- a/packages/xtask/data/blocking-census-baseline.json +++ b/packages/xtask/data/blocking-census-baseline.json @@ -455,7 +455,7 @@ "std::sync::Condvar::wait_timeout": 0, "std::sync::Condvar::wait_timeout_while": 0, "std::sync::Condvar::wait_while": 0, - "std::sync::Mutex::lock": 0, + "std::sync::Mutex::lock": 2, "std::sync::RwLock::read": 0, "std::sync::RwLock::write": 0, "std::sync::mpsc::Receiver::iter": 0, @@ -6255,7 +6255,7 @@ "std::fs::read": 0, "std::fs::read_dir": 0, "std::fs::read_link": 0, - "std::fs::read_to_string": 11, + "std::fs::read_to_string": 13, "std::fs::remove_dir_all": 1, "std::fs::remove_file": 0, "std::fs::rename": 0, From a5eeb74edf1cb9d86d6b29436ba0440f084f264e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 04:55:37 -0700 Subject: [PATCH 219/726] minijail: close the doc block the linter rejects under -D warnings A wave-1 doc row left an empty line between the adopt doc block and the function, which clippy denies as empty_line_after_doc_comments; the typo in the same sentence goes with it. Found by the wave gate's clippy action, which cargo check does not run. --- packages/d2b-provider-process-minijail/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/d2b-provider-process-minijail/src/lib.rs b/packages/d2b-provider-process-minijail/src/lib.rs index 39be19822..c309db1f6 100644 --- a/packages/d2b-provider-process-minijail/src/lib.rs +++ b/packages/d2b-provider-process-minijail/src/lib.rs @@ -382,11 +382,10 @@ impl ProcessProvider for MinijailProcessProvider

/// /// # Errors /// - /// Returns ticket validation failures, thee effect port's observe + /// Returns ticket validation failures, the effect port's observe /// failures, non-`DeadlineExceeded` readiness failures, and /// pidfd-open failures. A `DeadlineExceeded` readiness probe /// instead quarantines the candidate as identity-ambiguous. - async fn adopt( &self, ticket: &LaunchTicket, From 4c43754bbef6692b75dc1baf89ef85c9f300e847 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 05:03:12 -0700 Subject: [PATCH 220/726] wave 1: clear the lint classes the gate's clippy action denies Doc rows had left a blank line between three doc blocks and their items; two nested if-lets collapse into let-chains; and a filter_map over a single-arm match becomes a map, which is the same filtering the wildcard arm used to do. All three are denied under the gate's -D warnings and invisible to cargo check. --- .../src/v3/execution_policy.rs | 1 - packages/d2b-core/src/bundle_resolver.rs | 9 +++++---- packages/d2b-provider-operation/src/operation.rs | 5 ----- packages/d2b-provider-role/src/rbac.rs | 2 -- packages/d2b-unsafe-local-helper/src/systemd.rs | 13 ++++++------- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/packages/d2b-contracts-resource/src/v3/execution_policy.rs b/packages/d2b-contracts-resource/src/v3/execution_policy.rs index 2304fa991..0776c7ca4 100644 --- a/packages/d2b-contracts-resource/src/v3/execution_policy.rs +++ b/packages/d2b-contracts-resource/src/v3/execution_policy.rs @@ -98,7 +98,6 @@ pub fn redacted_debug_field_ref( } /// Renders one `redacted_debug!` field closure's owned value. - /// The closure receives `&T` and returns an owned `R` (a collection length, /// an option presence, or the `""` literal); the returned value is /// passed to the debug formatter unchanged. diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 9c18d7357..3a61dcf18 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -2435,22 +2435,23 @@ impl BundleResolver { vm.nodes .iter() .flat_map(|node| &node.plan_ops) - .filter_map(|plan_op| match plan_op { - SpawnRunnerPlanOp::DiskInit { + .map(|plan_op| { + let SpawnRunnerPlanOp::DiskInit { target_path, size_bytes, mode, owner_uid, owner_gid, if_absent, - } => Some(ResolvedDiskInitOp { + } = plan_op; + ResolvedDiskInitOp { target_path: target_path.clone(), size_bytes: *size_bytes, mode: *mode, owner_uid: *owner_uid, owner_gid: *owner_gid, if_absent: *if_absent, - }), + } }) .collect() } diff --git a/packages/d2b-provider-operation/src/operation.rs b/packages/d2b-provider-operation/src/operation.rs index 2b8a2bffc..e987e07dc 100644 --- a/packages/d2b-provider-operation/src/operation.rs +++ b/packages/d2b-provider-operation/src/operation.rs @@ -135,7 +135,6 @@ pub struct OperationAudit { impl OperationAudit { /// Construct one audit facet after checking the field bounds. - /// # Errors /// /// Returns `TooManyAuditFields` when the retained-field or @@ -197,7 +196,6 @@ pub struct AuditJoin { impl AuditJoin { /// Construct one audit-join facet after checking the field bound. - /// # Errors /// /// Returns `InvalidAuditJoin` when the field list is empty or over @@ -355,7 +353,6 @@ pub struct OperationFds { impl OperationFds { /// Construct one fd contract after checking the list bounds. - /// # Errors /// /// Returns `TooManyFds` when any of the request, response, or @@ -418,7 +415,6 @@ impl Default for OperationBounds { impl OperationBounds { /// Construct one bounds facet. - /// # Errors /// /// Returns `InvalidBounds` when a limit is zero or exceeds its @@ -492,7 +488,6 @@ pub struct OperationSpec { impl OperationSpec { /// Construct an operation spec after checking the facet invariants. - /// # Errors /// /// Returns `InvalidOwnerRef` when the owner reference does not name diff --git a/packages/d2b-provider-role/src/rbac.rs b/packages/d2b-provider-role/src/rbac.rs index fe45bafa3..b30babc02 100644 --- a/packages/d2b-provider-role/src/rbac.rs +++ b/packages/d2b-provider-role/src/rbac.rs @@ -89,7 +89,6 @@ impl core::fmt::Debug for PositiveDecisionCache { impl PositiveDecisionCache { /// Construct a bounded positive-only cache.max_entries = 0 /// disables caching entirely. - pub fn new(max_entries: usize) -> Self { Self { max_entries, @@ -98,7 +97,6 @@ impl PositiveDecisionCache { } /// Whether a non-expired entry matching the exact evidence is present. - pub fn contains( &self, key: &AuthorizationCacheKey, diff --git a/packages/d2b-unsafe-local-helper/src/systemd.rs b/packages/d2b-unsafe-local-helper/src/systemd.rs index ac592f017..3ecf38a6c 100644 --- a/packages/d2b-unsafe-local-helper/src/systemd.rs +++ b/packages/d2b-unsafe-local-helper/src/systemd.rs @@ -257,10 +257,9 @@ impl UserScopeManager for SystemdUserScopeManager { .call_method("KillUnit", &(scope.unit_name.as_str(), "all", signal)) .map(|_| ()) .map_err(map_stop_error) + && error != ScopeError::NotFound { - if error != ScopeError::NotFound { - return Err(error); - } + return Err(error); } Ok(()) }) @@ -275,10 +274,10 @@ impl UserScopeManager for SystemdUserScopeManager { let manager = Self::manager_proxy(connection)?; let result: Result = manager.call("StopUnit", &(scope.unit_name.as_str(), "replace")); - if let Err(error) = result.map(|_| ()).map_err(map_stop_error) { - if error != ScopeError::NotFound { - return Err(error); - } + if let Err(error) = result.map(|_| ()).map_err(map_stop_error) + && error != ScopeError::NotFound + { + return Err(error); } Ok(()) }) From a5c010d337480861120aa9d33b000855a60c8860 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 05:41:23 -0700 Subject: [PATCH 221/726] provider-role: drop the second blank line after the doc block The earlier pass removed one blank line where clippy counts any run of them; this removes the rest so the crate's clippy action builds again. --- packages/d2b-provider-role/src/rbac.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/d2b-provider-role/src/rbac.rs b/packages/d2b-provider-role/src/rbac.rs index b30babc02..05d2753cc 100644 --- a/packages/d2b-provider-role/src/rbac.rs +++ b/packages/d2b-provider-role/src/rbac.rs @@ -112,8 +112,6 @@ impl PositiveDecisionCache { /// Insert one positive decision, evicting expired entries and refusing /// insertions past the bound. An already-expired entry is never stored. - - pub fn insert_allow( &self, key: AuthorizationCacheKey, From 99d9f0c73f6d9b6691dbf0e09cc454094686a063 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 06:16:30 -0700 Subject: [PATCH 222/726] wave 1: clear the remaining lint defects the gate exposes Doc blocks on fields and functions no longer carry the blank lines clippy denies; blank lines inside a doc run became continuation lines; the argument-parsing closures lose redundant wrappers, needless borrows and a useless PathBuf conversion go away, a slice iterates by reference, and ninety-four doc sentences regain the space after their commas that the wave's prose passes had dropped. --- packages/d2b-broker/src/audit.rs | 26 ----------- packages/d2b-broker/src/envelope/mod.rs | 12 +++--- packages/d2b-broker/src/fd_passing.rs | 5 --- packages/d2b-broker/src/ops/media.rs | 43 ++++++++----------- packages/d2b-broker/src/ops/nm.rs | 4 +- packages/d2b-broker/src/ops/state_dir.rs | 20 ++++----- packages/d2b-broker/src/protocol.rs | 14 +++--- packages/d2b-broker/src/sys.rs | 12 ++---- packages/d2b-bus/src/router.rs | 2 +- packages/d2b-bus/src/session/contract.rs | 2 - .../d2b-contracts-broker/src/broker_wire.rs | 8 ++-- packages/d2b-host/src/nftables.rs | 4 +- .../src/bin/d2b-clipd.rs | 6 +-- .../src/controller/mod.rs | 12 +++--- .../d2b-provider-operation/src/operation.rs | 1 - .../src/launch.rs | 2 +- .../d2b-provider-process-minijail/src/lib.rs | 2 +- .../d2b-provider-transport-unix/src/portal.rs | 4 +- packages/d2b-provider-zone/src/zone_status.rs | 2 +- packages/d2b-resource-api/src/service.rs | 2 +- packages/d2b-resource-compiler/src/main.rs | 8 ++-- packages/d2b-session-unix/src/pidfd.rs | 2 +- packages/d2b-session-unix/src/socket.rs | 3 -- packages/d2b-sk-frontend/src/config.rs | 2 +- packages/d2b-telemetry/src/emitter.rs | 4 +- packages/d2bd/src/audio_dispatch.rs | 2 +- packages/d2bd/src/composition.rs | 6 +-- packages/d2bd/src/effect_service_actors.rs | 4 +- packages/d2bd/src/forward_rendezvous.rs | 14 +++--- packages/d2bd/src/provider_effects.rs | 2 +- packages/d2bd/src/resource_plane_v3.rs | 20 ++++----- packages/xtask/src/gen_layer_catalogs.rs | 2 +- packages/xtask/src/provider_crate_policy.rs | 16 +++---- packages/xtask/src/resource_type_authority.rs | 6 +-- 34 files changed, 112 insertions(+), 162 deletions(-) diff --git a/packages/d2b-broker/src/audit.rs b/packages/d2b-broker/src/audit.rs index cf8373c00..52c24982c 100644 --- a/packages/d2b-broker/src/audit.rs +++ b/packages/d2b-broker/src/audit.rs @@ -85,12 +85,8 @@ impl AuditWriteClass { #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub struct AuditDropSummary { /// Privileged-class records dropped by the rate limiter. - pub privileged_rate_limited: u64, /// Unprivileged-class records dropped by the rate limiter. - - - pub unprivileged_rate_limited: u64, } @@ -135,43 +131,22 @@ impl AuditDropWarningState { #[derive(Clone)] pub struct AuditEntry<'a> { /// Monotonic timestamp, microseconds since an arbitrary epoch. - pub ts: u128, /// The audited operation name. - pub op: &'a str, /// The caller's uid. - - pub caller_uid: u32, /// The caller's gid, when known. - - - pub caller_gid: Option, /// The authz outcome class. - - - pub disposition: &'a str, /// The opaque target operation id, when the operation names one. - - - pub opaque_target_id: &'a str, /// The finer result spelling (`ok`/refusal/error kind).) - - - pub outcome: &'a str, /// The error kind, when the outcome is an error. - - - pub error_kind: Option<&'a str>, /// The error detail, when present. - - pub error_message: Option<&'a str>, } @@ -460,7 +435,6 @@ impl AuditLog { /// directory lock, reconciliation, appender setup, prune) on the /// worker before returning, so a fresh writer never observes a /// half-opened directory. - pub fn open( audit_dir: &Path, expected_gid: u32, diff --git a/packages/d2b-broker/src/envelope/mod.rs b/packages/d2b-broker/src/envelope/mod.rs index 0818d9b0e..aa4987b8e 100644 --- a/packages/d2b-broker/src/envelope/mod.rs +++ b/packages/d2b-broker/src/envelope/mod.rs @@ -905,7 +905,7 @@ pub struct InvocationCtx<'a> { pub struct DispatchOutcome { /// The canonical result payload. pub result: CanonicalJsonObject, - /// The descriptors the answering peer minted this invocation,when the + /// The descriptors the answering peer minted this invocation, when the /// operation's result carries any.where /// /// Formal fd provenance tracking is the answering peer's job (KTD7):the @@ -979,11 +979,11 @@ pub struct DirectInvocation<'a> { /// invocation, when the broker holds a context store. A local handler /// sees the same block the forward carrier would carry. pub context: Option<&'a ForwardContext>, - /// The descriptors the caller attached to this invocation,when any. + /// The descriptors the caller attached to this invocation, when any. /// The caller owns them;the invocation borrows them for its duration. pub fds: &'a [OwnedFd], - /// The kernel kind the row's fd facet declares,when it declares one. + /// The kernel kind the row's fd facet declares, when it declares one. pub fd_kind: Option, } @@ -1142,8 +1142,8 @@ impl BrokerEnvelope { /// Invoke one operation through the envelope with descriptors attached to it. /// /// The fd leg rides the forward carrier:zero-or-more of the request - /// frame's SCM_RIGHTS attachments are the operation's descriptors,validated - /// here against the row's declared fd facet before dispatch,so an + /// frame's SCM_RIGHTS attachments are the operation's descriptors, validated + /// here against the row's declared fd facet before dispatch, so an /// oversized-but-transport-legal set is refused with the fd-leg code /// rather than truncated by the transport.where /// @@ -1556,7 +1556,7 @@ impl BrokerEnvelope { true } - /// The kernel kind one descriptor presents,or None when its fstat + /// The kernel kind one descriptor presents, or None when its fstat /// reports a kind the carrier vocabulary does not carry.. fn fd_kind_of(fd: &OwnedFd) -> Option { use nix::libc; diff --git a/packages/d2b-broker/src/fd_passing.rs b/packages/d2b-broker/src/fd_passing.rs index 4ddfffefd..0fd101107 100644 --- a/packages/d2b-broker/src/fd_passing.rs +++ b/packages/d2b-broker/src/fd_passing.rs @@ -53,7 +53,6 @@ impl FdRegistry { } /// Close every registered fd, releasing this registry's ownership. - pub fn clear(&mut self) { for fd in self.owned.drain(..) { let _ = close(fd); @@ -76,15 +75,11 @@ pub struct FdLease { impl FdLease { /// Take ownership of `fd`, to be closed on drop unless released. - pub fn new(fd: RawFd) -> Self { Self { fd: Some(fd) } } /// The still-owned fd, if not yet released. - - - pub fn raw(&self) -> Option { self.fd } diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index 281af193e..c6f16377b 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -220,16 +220,12 @@ pub struct HotplugOutcome { /// reloaded. pub struct BootOutcome { /// The wire response echoed to the daemon. - pub response: QemuMediaHotplugResponse, /// Whether the boot wrote a fresh registry record for the media. - pub registry_record_written: bool, /// Whether the boot rewrote the redacted registry index. - pub redacted_index_written: bool, /// Whether the boot rewrote the runtime udev rule file. - pub udev_rule_written: bool, /// Whether udev was reloaded after the rule write. pub udev_reloaded: bool, @@ -242,9 +238,9 @@ pub struct RefreshOutcome { } /// Enroll one physical USB media for a VM: validates the ref and bus id, -/// resolves the bundle source,reads the live sysfs identity,preflights -/// busy-ness,opens the block device,then writes the registry record, -/// redacted index,and runtime udev rules and reloads udev. +/// resolves the bundle source, reads the live sysfs identity, preflights +/// busy-ness, opens the block device, then writes the registry record, +/// redacted index, and runtime udev rules and reloads udev. /// /// # Errors /// @@ -305,7 +301,7 @@ pub async fn enroll( } /// Re-read the enrolled registry and rewrite the redacted index and runtime -/// udev rule file,and reload udev. +/// udev rule file, and reload udev. /// /// # Errors /// @@ -327,13 +323,13 @@ pub async fn refresh_registry(resolver: &BundleResolver) -> Result Result { @@ -418,15 +413,12 @@ async fn qmp_query_status_from_path( } } -/// Send `quit` to a VM's QMP socket,ending its QMP session. +/// Send `quit` to a VM's QMP socket, ending its QMP session. /// /// # Errors - +/// /// Returns [`MediaOpError::Qmp`] when the socket cannot be reached or the /// command fails. - - - pub async fn quit(req: &QemuMediaLifecycleRequest) -> Result { let mut client = QmpClient::connect(&qmp_socket_path(req.vm_id.as_str())).await?; qmp_quit(&mut client).await?; @@ -440,8 +432,8 @@ pub async fn quit(req: &QemuMediaLifecycleRequest) -> Result) -> io::Result<()> { /// /// The intent's declared reload behavior is verified before any mutation /// (`atomic-reload`, `none`, and the empty sentinel are the only accepted -/// spellings),and NetworkManager is reloaded after a successful write +/// spellings), and NetworkManager is reloaded after a successful write /// when the behavior calls for it. pub async fn apply_with_reload( executor: &dyn ReconcileExecutor, @@ -302,7 +302,7 @@ pub async fn apply_with_reload( crate::live_handlers::live_apply_nm_unmanaged(executor, intent).await } -/// Remove one NetworkManager unmanaged drop-in the intent names,verifying +/// Remove one NetworkManager unmanaged drop-in the intent names, verifying /// the same reload-behavior contract before mutation and running the /// `systemctl` reload when the behavior calls for it. pub async fn remove_with_reload( diff --git a/packages/d2b-broker/src/ops/state_dir.rs b/packages/d2b-broker/src/ops/state_dir.rs index 76478f1ba..d353d6b26 100644 --- a/packages/d2b-broker/src/ops/state_dir.rs +++ b/packages/d2b-broker/src/ops/state_dir.rs @@ -52,7 +52,7 @@ pub enum DirKind { } /// One state/runtime directory preparation request:which root to -/// prepare, the mode/owner posture to apply,and the relative +/// prepare, the mode/owner posture to apply, and the relative /// subdirectories to create under it. #[derive(Debug, Clone)] pub struct PrepareDirRequest { @@ -103,14 +103,14 @@ pub enum ReplaceOrCreateResult { } /// Prepare one state/runtime directory tree:optionally refuse non-root -/// parents for production roots,reuse the base dir without re-stamping its -/// posture,and create the requested relative subdirectories with the -/// requested mode/owner,returning the audit record. +/// parents for production roots, reuse the base dir without re-stamping its +/// posture, and create the requested relative subdirectories with the +/// requested mode/owner, returning the audit record. /// /// # Errors - +/// /// Returns [`io::ErrorKind::InvalidInput`] for absolute or `..`-bearing -/// created paths, the parent-ownership guard,or the underlying +/// created paths, the parent-ownership guard, or the underlying /// mkdir/fchmod/fchown failures as `io::Error`s. pub fn prepare_dir(req: &PrepareDirRequest) -> io::Result { // Refuse non-root parent for production paths. Tests pass a scratch @@ -185,13 +185,13 @@ fn production_path(p: &Path) -> bool { } /// Prepare one VM's runtime root directory:requires the wire -/// `pathClass=runtime`, resolves the bundle intent,and reuses the existing +/// `pathClass=runtime`, resolves the bundle intent, and reuses the existing /// base dir without re-stamping its posture. /// /// # Errors - +/// /// Returns [`super::OpError::InvalidInput`] for a non-runtime path class, -/// [`super::OpError::UnknownSubject`] for unmanaged VMs,and +/// [`super::OpError::UnknownSubject`] for unmanaged VMs, and /// [`super::OpError::Io`] for the directory preparation failures. pub fn live_prepare_runtime_dir( _exec: &SystemLiveExec, @@ -250,7 +250,7 @@ pub struct PreparedStateDir { /// without creating anything. /// /// # Errors - +/// /// Returns [`super::OpError::InvalidInput`] for a non-VM path class, /// [`super::OpError::UnknownSubject`] / [`super::OpError::Refused`] /// for unresolvable subjects, and the swtpm-hardening refusal as diff --git a/packages/d2b-broker/src/protocol.rs b/packages/d2b-broker/src/protocol.rs index e8a86b612..f04ef7812 100644 --- a/packages/d2b-broker/src/protocol.rs +++ b/packages/d2b-broker/src/protocol.rs @@ -18,7 +18,7 @@ pub const MAX_FRAME_SIZE: usize = 1024 * 1024; /// connected CLOEXEC fd. /// /// # Errors - +/// /// Returns the socket error when the socket cannot be created or connected. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn connect_seqpacket(path: &Path) -> io::Result { @@ -38,7 +38,7 @@ pub fn connect_seqpacket(path: &Path) -> io::Result { /// the listening CLOEXEC fd with a backlog of 64. /// /// # Errors - +/// /// Returns the socket error when create, bind, or listen fails. pub fn bind_seqpacket(path: &Path) -> io::Result { let fd = socket( @@ -55,14 +55,14 @@ pub fn bind_seqpacket(path: &Path) -> io::Result { } /// Serialise `value` as JSON and send it as one frame on `fd`:a 4-byte -/// little-endian length prefix followed by the body,refusing bodies over +/// little-endian length prefix followed by the body, refusing bodies over /// [`MAX_FRAME_SIZE`]. Byte-equivalent to /// [`send_json_frame_with_fds`] when no descriptors are attached. /// /// # Errors - +/// /// Returns [`io::ErrorKind::InvalidData`] for serialisation or cap -/// violations,and socket / short-write errors for the send itself. +/// violations, and socket / short-write errors for the send itself. pub fn send_json_frame(fd: RawFd, value: &T) -> io::Result<()> { send_json_frame_with_fds(fd, value, &[]) } @@ -105,11 +105,11 @@ pub fn send_json_frame_with_fds( } /// Receive one JSON frame from `fd`:a 4-byte little-endian length -/// prefix followed by the body,capped at [`MAX_FRAME_SIZE`]; returns +/// prefix followed by the body, capped at [`MAX_FRAME_SIZE`]; returns /// `None` when the peer closed the socket empty. /// /// # Errors - +/// /// Returns [`io::ErrorKind::UnexpectedEof`] for short frames and /// [`io::ErrorKind::InvalidData`] for length-prefix mismatches and decode /// failures. diff --git a/packages/d2b-broker/src/sys.rs b/packages/d2b-broker/src/sys.rs index 0f9e170df..1cc6feeb9 100644 --- a/packages/d2b-broker/src/sys.rs +++ b/packages/d2b-broker/src/sys.rs @@ -190,7 +190,7 @@ pub fn tun_create_tap_fd(fd: &OwnedFd, ifname: &str) -> io::Result<()> { /// its fd closes. /// /// # Errors - +/// /// Returns the ioctl error when the setting cannot be applied to `fd`. #[allow(unsafe_code)] pub fn tun_set_persist(fd: &OwnedFd, persist: bool) -> io::Result<()> { @@ -205,10 +205,9 @@ pub fn tun_set_persist(fd: &OwnedFd, persist: bool) -> io::Result<()> { /// Set the TUN `TUNSETOWNER` ioctl:the uid that may open the tap. /// /// # Errors - +/// /// Returns [`io::ErrorKind::InvalidInput`] when `uid` exceeds the /// `c_int` range, and the ioctl error when the setting cannot be applied. - #[allow(unsafe_code)] pub fn tun_set_owner(fd: &OwnedFd, uid: u32) -> io::Result<()> { let value = libc::c_int::try_from(uid).map_err(|_| { @@ -227,12 +226,9 @@ pub fn tun_set_owner(fd: &OwnedFd, uid: u32) -> io::Result<()> { /// Set the TUN `TUNSETGROUP` ioctl:the gid that may open the tap. /// /// # Errors - +/// /// Returns [`io::ErrorKind::InvalidInput`] when `gid` exceeds the /// `c_int` range, and the ioctl error when the setting cannot be applied. - - - #[allow(unsafe_code)] pub fn tun_set_group(fd: &OwnedFd, gid: u32) -> io::Result<()> { let value = libc::c_int::try_from(gid).map_err(|_| { @@ -326,7 +322,7 @@ pub mod path_safe { Ok(()) } - /// Refuse a parent directory not owned by uid 0,using the strict + /// Refuse a parent directory not owned by uid 0, using the strict /// no-exception rule for production paths under `/etc` and `/run`. pub fn refuse_non_root_parent(path: &Path) -> io::Result<()> { refuse_non_root_parent_except(path, None) diff --git a/packages/d2b-bus/src/router.rs b/packages/d2b-bus/src/router.rs index 29072c0e9..7ef594559 100644 --- a/packages/d2b-bus/src/router.rs +++ b/packages/d2b-bus/src/router.rs @@ -479,7 +479,7 @@ impl ResourceCall { assignment, mutations, } => { - if ScopedCommitTransport::validate(&assignment, &mutations).is_err() { + if ScopedCommitTransport::validate(assignment, mutations).is_err() { return Err(BusError::InvalidResourceCall); } ( diff --git a/packages/d2b-bus/src/session/contract.rs b/packages/d2b-bus/src/session/contract.rs index e11f14f67..c98b6db9b 100644 --- a/packages/d2b-bus/src/session/contract.rs +++ b/packages/d2b-bus/src/session/contract.rs @@ -957,8 +957,6 @@ impl RouteAdmissionVerifier { /// Re-check the runtime-owned authority state against one borrowed /// admission body, without constructing owned evidence. - - fn verify_body( &self, body: &RouteAdmissionBody, diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 51f7e3792..e7f2edbe1 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -230,7 +230,7 @@ pub const FORWARD_SOCKET_ENV: &str = "D2B_BROKER_FORWARD_SOCKET"; /// attachments disagree with their declarations, or whose declared set /// exceeds the bounded ceiling. /// -/// The code is shared by both legs of the forward carrier,so the broker +/// The code is shared by both legs of the forward carrier, so the broker /// and the rendezvous cannot drift apart on how an fd-leg failure is named. pub const FD_LEG: &str = "fd-leg"; @@ -239,7 +239,7 @@ pub const FD_LEG: &str = "fd-leg"; /// The receive-side ancillary buffers on both legs are sized /// `cmsg_space!([RawFd; MAX_FRAME_FDS])`, so a frame with more attachments /// would be truncated by the transport. A declared set is therefore -/// capped at this constant before dispatch,and a larger declaration is +/// capped at this constant before dispatch, and a larger declaration is /// refused with [`FD_LEG`], never delivered as a transport truncation. pub const MAX_FRAME_FDS: usize = 8; @@ -444,13 +444,13 @@ pub enum ForwardOperationOutcome { Result { /// The canonical result payload the handler returned. result: serde_json::Value, - /// The positions,in the frame's SCM_RIGHTS attachment list,of the + /// The positions, in the frame's SCM_RIGHTS attachment list, of the /// descriptors the answering peer returned. Empty when the response /// carries none. #[serde(default)] fd_indexes: Vec, - /// The kernel kind each declared descriptor must present,index-aligned + /// The kernel kind each declared descriptor must present, index-aligned /// with the fd-index declarations. #[serde(default)] diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index 8a9414c5c..1f32c0a34 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -986,8 +986,8 @@ mod tests { } /// 7-row coexistence matrix - these are the L1c canaries - /// `nft-coexistence-{firewalld,ufw,docker,libvirt,iptables-nft, - /// unknown-manager,no-manager}`. + /// `nft-coexistence-{firewalld, ufw, docker, libvirt, iptables-nft, + /// unknown-manager, no-manager}`. #[test] fn coexistence_matrix_all_7_rows() { use CoexistencePolicy::*; diff --git a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs index 6f685af25..b4d51dd8d 100644 --- a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs @@ -1128,8 +1128,8 @@ fn install_bridge_listeners( bridge_peers: &[BridgePeerConfig], ) -> Result, String> { let uid = rustix::process::getuid().as_raw(); - Ok(bridge_peers - .into_iter() + bridge_peers + .iter() .map(|peer| { let path = bridge_socket_path(root, uid, &peer.socket_component)?; let parent = path @@ -1170,7 +1170,7 @@ fn install_bridge_listeners( listener, }) }) - .collect::, String>>()?) + .collect() } fn bridge_socket_path(root: &Path, uid: u32, component: &str) -> Result { diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs index 159d79d24..2e928c155 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs @@ -681,22 +681,22 @@ where let operation = match &update { AzureVmUpdate::Resize { size } => { self.effect - .start_vm_resize(&handle, size, &operation_id, &token) + .start_vm_resize(handle, size, &operation_id, &token) .await? } AzureVmUpdate::AttachDisk { disk } => { self.effect - .start_disk_attach(&handle, disk, &operation_id, &token) + .start_disk_attach(handle, disk, &operation_id, &token) .await? } AzureVmUpdate::DetachDisk { lun } => { self.effect - .start_disk_detach(&handle, *lun, &operation_id, &token) + .start_disk_detach(handle, *lun, &operation_id, &token) .await? } AzureVmUpdate::ReplaceTags { tags } => { self.effect - .update_vm_tags(&handle, tags, &operation_id, &token) + .update_vm_tags(handle, tags, &operation_id, &token) .await? } }; @@ -843,7 +843,7 @@ where let token = self.arm_token().await?; let operation = self .effect - .put_vm_extension(&handle, payload, &token) + .put_vm_extension(handle, payload, &token) .await?; self.psk_delivery_attempts = self.psk_delivery_attempts.saturating_add(1); self.bootstrap_extension_present = true; @@ -905,7 +905,7 @@ where let token = self.arm_token().await?; let operation = self .effect - .start_vm_delete(&handle, &operation_id, &token) + .start_vm_delete(&handle, operation_id, &token) .await?; self.set_operation(operation); self.phase = AzureVmPhase::Deleting; diff --git a/packages/d2b-provider-operation/src/operation.rs b/packages/d2b-provider-operation/src/operation.rs index e987e07dc..6510e36d1 100644 --- a/packages/d2b-provider-operation/src/operation.rs +++ b/packages/d2b-provider-operation/src/operation.rs @@ -139,7 +139,6 @@ impl OperationAudit { /// /// Returns `TooManyAuditFields` when the retained-field or /// redaction-key list exceeds its bound. - pub fn new( required: bool, mode: AuditMode, diff --git a/packages/d2b-provider-process-minijail/src/launch.rs b/packages/d2b-provider-process-minijail/src/launch.rs index 2d25f9553..a77185ebb 100644 --- a/packages/d2b-provider-process-minijail/src/launch.rs +++ b/packages/d2b-provider-process-minijail/src/launch.rs @@ -52,7 +52,7 @@ impl PlatformGate { /// # Errors /// /// Returns `ProviderMismatch` when the ticket selects a different -/// Process Provider,and `PlatformGateRejected` when the platform gate +/// Process Provider, and `PlatformGateRejected` when the platform gate /// fails. pub fn validate_launch_ticket( ticket: &LaunchTicket, diff --git a/packages/d2b-provider-process-minijail/src/lib.rs b/packages/d2b-provider-process-minijail/src/lib.rs index c309db1f6..12783f6c1 100644 --- a/packages/d2b-provider-process-minijail/src/lib.rs +++ b/packages/d2b-provider-process-minijail/src/lib.rs @@ -318,7 +318,7 @@ impl ProcessProvider for MinijailProcessProvider

/// `PlatformGateRejected`), thee effect port's launch and readiness /// failures, `WaitOwnerMismatch` when the launched process is not /// locally owned, `IdentityUnverified` when the launch evidence lacks - /// the required identity bindings,and `TerminalEvidenceMismatch` + /// the required identity bindings, and `TerminalEvidenceMismatch` /// when the identity does not match the ticket seal. async fn launch_with_inherited_fds( &self, diff --git a/packages/d2b-provider-transport-unix/src/portal.rs b/packages/d2b-provider-transport-unix/src/portal.rs index 8c6fd4632..75ec675ae 100644 --- a/packages/d2b-provider-transport-unix/src/portal.rs +++ b/packages/d2b-provider-transport-unix/src/portal.rs @@ -275,7 +275,7 @@ impl TransportPortal { /// # Errors /// /// Returns `UnknownHandle` when the handle is not owned by this - /// portal instance,and `MonitorUnavailable` when the portal monitor + /// portal instance, and `MonitorUnavailable` when the portal monitor /// lock is poisoned. A finalized handle closes idempotently. pub fn close(&self, handle: TransportHandle) -> Result<(), PortalError> { let mut state = self @@ -301,7 +301,7 @@ impl TransportPortal { /// # Errors /// /// Returns `UnknownHandle` when the handle is not owned by this - /// portal instance,and `MonitorUnavailable` when the portal monitor + /// portal instance, and `MonitorUnavailable` when the portal monitor /// lock is poisoned. pub fn observe(&self, handle: TransportHandle) -> Result { let state = self diff --git a/packages/d2b-provider-zone/src/zone_status.rs b/packages/d2b-provider-zone/src/zone_status.rs index 7576caa8b..b6a107be6 100644 --- a/packages/d2b-provider-zone/src/zone_status.rs +++ b/packages/d2b-provider-zone/src/zone_status.rs @@ -112,7 +112,7 @@ impl SystemCoreStatusEmitter { /// # Errors /// /// Returns `ZoneStatusProjectionError::Contract` when the input - /// carries more than one system-core host or user handler record,or + /// carries more than one system-core host or user handler record, or /// when the zone status is rejected by the resource projection. pub fn emit( &self, diff --git a/packages/d2b-resource-api/src/service.rs b/packages/d2b-resource-api/src/service.rs index e31d45c5c..94c20f64e 100644 --- a/packages/d2b-resource-api/src/service.rs +++ b/packages/d2b-resource-api/src/service.rs @@ -936,7 +936,7 @@ where Ok(parsed) => parsed, Err(error) => return batch_error(error), }; - if let Some(scoped_mutations) = scoped_mutations.as_deref() + if let Some(scoped_mutations) = scoped_mutations && let Err(error) = attach_scoped_fences(&mut parsed, scoped_mutations, &routes) { return batch_error(error); diff --git a/packages/d2b-resource-compiler/src/main.rs b/packages/d2b-resource-compiler/src/main.rs index 4425d67ba..56dc1f15b 100644 --- a/packages/d2b-resource-compiler/src/main.rs +++ b/packages/d2b-resource-compiler/src/main.rs @@ -249,18 +249,18 @@ fn parse_args() -> Result<(PathBuf, PathBuf, Option), CliError> { while let Some(argument) = args.next() { match argument.to_str() { Some("--input") => { - input = Some(args.next().ok_or_else(|| usage())?); + input = Some(args.next().ok_or_else(usage)?); } Some("--output") => { - output = Some(args.next().ok_or_else(|| usage())?); + output = Some(args.next().ok_or_else(usage)?); } Some("--strict-secrets") => strict_override = Some(true), Some("--allow-inline-secrets") => strict_override = Some(false), _ => return Err(usage()), } } - let input = input.ok_or_else(|| usage())?; - let output = output.ok_or_else(|| usage())?; + let input = input.ok_or_else(usage)?; + let output = output.ok_or_else(usage)?; Ok((PathBuf::from(input), PathBuf::from(output), strict_override)) } diff --git a/packages/d2b-session-unix/src/pidfd.rs b/packages/d2b-session-unix/src/pidfd.rs index fd47659cc..2cd2e64f8 100644 --- a/packages/d2b-session-unix/src/pidfd.rs +++ b/packages/d2b-session-unix/src/pidfd.rs @@ -6,7 +6,7 @@ use rustix::{ use std::{fmt, fs, os::fd::AsRawFd, sync::Arc}; /// Verified pidfd identity evidence: the first-packet credentials, the -/// executable digest,and the cgroup digest must all match the expected +/// executable digest, and the cgroup digest must all match the expected /// process. #[derive(Clone, Copy, PartialEq, Eq)] pub struct PidfdEvidence { diff --git a/packages/d2b-session-unix/src/socket.rs b/packages/d2b-session-unix/src/socket.rs index 946a83089..10eba9071 100644 --- a/packages/d2b-session-unix/src/socket.rs +++ b/packages/d2b-session-unix/src/socket.rs @@ -191,7 +191,6 @@ pub struct SendBurst { /// /// Packet-burst sends and receives are cancellation-safe:partial bursts /// are retained across an await. - pub struct SeqpacketSocket { io: AsyncFd, received_any: AtomicBool, @@ -210,7 +209,6 @@ impl SeqpacketSocket { /// /// Returns `UnixSessionError` when the descriptor is not a /// seqpacket socket or cannot be registered on the async surface. - pub fn from_owned(fd: OwnedFd) -> Result { validate_socket(&fd, SocketType::SEQPACKET)?; Ok(Self { @@ -227,7 +225,6 @@ impl SeqpacketSocket { /// Returns `UnixSessionError` when the descriptor fails the prearmed /// contract (socket type, async registration, or `passcred` /// not prearmed). - pub fn from_parent_prearmed(fd: OwnedFd) -> Result { verify_parent_prearmed(&fd)?; Self::from_owned(fd) diff --git a/packages/d2b-sk-frontend/src/config.rs b/packages/d2b-sk-frontend/src/config.rs index 04e9b7b6a..8a884d19e 100644 --- a/packages/d2b-sk-frontend/src/config.rs +++ b/packages/d2b-sk-frontend/src/config.rs @@ -114,7 +114,7 @@ impl Config { Ok(Self { vm_id, link: VsockAllocatorLink::new(vsock_cid, vsock_port), - uhid_path: PathBuf::from(uhid_path), + uhid_path, placement: PlacementConfig { identity, psk_issuance: number("D2B_SK_PSK_ISSUANCE")?, diff --git a/packages/d2b-telemetry/src/emitter.rs b/packages/d2b-telemetry/src/emitter.rs index 2395fd6fa..e58149824 100644 --- a/packages/d2b-telemetry/src/emitter.rs +++ b/packages/d2b-telemetry/src/emitter.rs @@ -184,7 +184,7 @@ impl BoundedEmitter { /// # Errors /// /// Returns `EmitterError::SocketPathInvalid` for a non-absolute - /// path,and `StatePoisoned` for a zero byte capacity. + /// path, and `StatePoisoned` for a zero byte capacity. pub fn new(path: impl Into, capacity_bytes: usize) -> Result { Self::new_with_limits( path, @@ -200,7 +200,7 @@ impl BoundedEmitter { /// # Errors /// /// Returns `EmitterError::SocketPathInvalid` for a non-absolute - /// path,and `StatePoisoned` when any bound is zero. + /// path, and `StatePoisoned` when any bound is zero. pub fn new_with_limits( path: impl Into, capacity_bytes: usize, diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index 4d5880e79..55494f0e7 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -374,7 +374,7 @@ pub(crate) fn combined_audio_applied( /// /// Status collects a per-VM result (entries and per-VM errors) from /// the provider's state; SetVolume and Mute apply a state transition under - /// the audio serialization lock,and return [`TypedError::InternalIo`] + /// the audio serialization lock, and return [`TypedError::InternalIo`] /// for manifest, capability, lock, read, write, or enforcement /// failures. diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 9a71b840a..fede6ae3e 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -443,7 +443,7 @@ impl StaticProviderComposition { /// # Errors /// /// Returns `AdmissionError` when the provider deployment admission - /// (budget, limits,or mode constraints) validation fails. + /// (budget, limits, or mode constraints) validation fails. pub fn new( mode: d2bd_runtime::target_runtime::DaemonMode, broker_socket: PathBuf, @@ -3466,7 +3466,7 @@ fn admission_config(state: &ServerState) -> AdmissionConfig { /// startup contracts (pidfs support, state-lock parent, operator socket /// posture) are enforced before any socket is served. Operator tooling /// uses `lock_only` to hold the state lock without starting the daemon. - +/// /// # Errors /// /// Returns [`TypedError`] for config-load and override failures, invalid @@ -4853,7 +4853,7 @@ async fn finalize_daemon_interactions(state: &ServerState) -> Result<(), TypedEr /// /// # Errors /// -/// Returns [`TypedError`] for config-load, state-lock-parent validation,and +/// Returns [`TypedError`] for config-load, state-lock-parent validation, and /// lock-acquisition failures. pub async fn lock_only(options: LockOnlyOptions) -> Result<(), TypedError> { let mut config = load_config(&options.config_path)?; diff --git a/packages/d2bd/src/effect_service_actors.rs b/packages/d2bd/src/effect_service_actors.rs index 3652d9961..a86ca97d8 100644 --- a/packages/d2bd/src/effect_service_actors.rs +++ b/packages/d2bd/src/effect_service_actors.rs @@ -205,7 +205,7 @@ impl EffectServiceBinding { /// published, [`EffectServiceError::WrongZone`] when the row belongs to /// a different zone, [`EffectServiceError::ServiceUnavailable`] when /// the actor refuses the call, [`EffectServiceError::InFlightStale`] - /// when the actor died mid-flight,and [`EffectServiceError::Declined`] + /// when the actor died mid-flight, and [`EffectServiceError::Declined`] /// when the service declines the operation. pub async fn call(&self, call: ServiceCallData) -> Result { self.send(call).await @@ -220,7 +220,7 @@ impl EffectServiceBinding { /// Returns [`EffectServiceError::StaleRevision`] when the binding's /// revision moved sincethe caller captured `expected`, and the same /// refusals as [`EffectServiceBinding::call`]: UnboundService, - /// WrongZone, ServiceUnavailable, InFlightStale,and Declined. + /// WrongZone, ServiceUnavailable, InFlightStale, and Declined. pub async fn call_expected( &self, expected: u64, diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index e2d202502..b2ed74641 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -1057,7 +1057,7 @@ impl Drop for ScmFds { /// Whether one request's declared fd leg is admitted by the descriptors the /// frame actually attached: count equal (never truncated), indexes in frame -/// order, kinds against the kernel stat of each received descriptor,andthe +/// order, kinds against the kernel stat of each received descriptor, andthe /// whole leg within the carrier's frame ceiling. fn request_fds_admitted(request: &ForwardOperationRequest, fds: &[RawFd]) -> bool { if request.fd_indexes.len() != request.fd_kinds.len() { @@ -1381,10 +1381,10 @@ impl AsyncSeqpacket { /// Read one frame and the descriptors its SCM_RIGHTS attachments carried, /// waiting at most `deadline` for it to arrive. /// - /// A frame and its attachments arrive together or not at all,so the + /// A frame and its attachments arrive together or not at all, so the /// received descriptor count is exactly what the sender put on the /// carrier;an oversized cmsg set is capped by the kernel at the receive - /// buffer's ceiling,which is why the caller-side declaration check + /// buffer's ceiling, which is why the caller-side declaration check /// refuses a count over that ceiling rather than let a truncation pass.. async fn read_frame_with_fds(&self, deadline: Duration) -> Result<(Vec, Vec), TypedError> { // The blocking transport read the prefixed frame and stripped the @@ -1397,7 +1397,7 @@ impl AsyncSeqpacket { } } - /// Write one frame,attaching `fds` to it,waiting at most `deadline` + /// Write one frame, attaching `fds` to it, waiting at most `deadline` /// for the peer to take it. async fn write_frame_with_fds( &self, @@ -1414,9 +1414,9 @@ impl AsyncSeqpacket { } } - /// One datagram read with its attachments,awaited for readiness. The + /// One datagram read with its attachments, awaited for readiness. The /// blocking transport's `recvmsg` owns the control-message buffer for - /// this read,and MSG_CMSG_CLOEXEC is set there,so the received descriptors + /// this read, and MSG_CMSG_CLOEXEC is set there, so the received descriptors /// arrive close-on-exec exactly as they do on the broker leg. async fn recv_frame_with_fds(&self) -> io::Result<(Vec, Vec)> { self.io @@ -1891,7 +1891,7 @@ mod tests { /// A handler that reads the descriptor the carrier attached to its /// call. The forwarded request leg carries the caller's descriptor over /// SCM_RIGHTS;the rendezvous validates it against the wire declarations - /// and hands it to the declared handler,so this handler reading it back + /// and hands it to the declared handler, so this handler reading it back /// proves the round trip through the real socket and the provider envelope.to struct FdEchoHandler; diff --git a/packages/d2bd/src/provider_effects.rs b/packages/d2bd/src/provider_effects.rs index ae970715e..6ac08d6a7 100644 --- a/packages/d2bd/src/provider_effects.rs +++ b/packages/d2bd/src/provider_effects.rs @@ -118,7 +118,7 @@ impl FixedEffectAdapter { /// # Errors /// /// Returns [`FixedEffectError::EffectClassDenied`] when the daemon - /// mode does not admit the class,and [`FixedEffectError::Broker`] when + /// mode does not admit the class, and [`FixedEffectError::Broker`] when /// the broker dispatch fails. pub fn dispatch( &self, diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 83949338c..08e962db6 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -1840,21 +1840,21 @@ pub struct ConstructionInputs { /// daemon-built effect port (R2). pub user_facets: UserEffectFacets, /// The daemon-supplied facet set the VolumeBinding family's effects - /// implementation is built from (U6):the serving-socket probe,the - /// socket removal,and the guest-mount observation,supplied through the + /// implementation is built from (U6):the serving-socket probe, the + /// socket removal, and the guest-mount observation, supplied through the /// composition root. The family never receives a daemon-built effect /// port (R2). pub binding_facets: BindingEffectFacets, /// The daemon-supplied facet set the Endpoint family's effects /// implementation is built from (U6):the host socket surface and the - /// two row-evidence probes,supplied through the composition root. The + /// two row-evidence probes, supplied through the composition root. The /// family never receives a daemon-built effect port (R2). pub endpoint_facets: EndpointEffectFacets, /// The daemon-supplied facet set the Credential family's effects /// implementation is built from (U8):the daemon's Credential runtime - /// (the preserved Provider and execution-target reads,the lease-facts - /// read,the managed-identity agent probe,and the authenticated - /// Provider session handoff registry),supplied through the composition + /// (the preserved Provider and execution-target reads, the lease-facts + /// read, the managed-identity agent probe, and the authenticated + /// Provider session handoff registry), supplied through the composition /// root. The family never receives a daemon-built effect port (R2). pub credential_facets: CredentialEffectFacets, /// The daemon-supplied facet set the Volume family's effects @@ -1865,8 +1865,8 @@ pub user_facets: UserEffectFacets, pub volume_facets: VolumeEffectFacets, /// The daemon-supplied facet set the Guest family's effects /// implementation is built from (U10):the zone's manager view (live - /// rows, committed Provider identities,and the controller-session - /// generation)andthe Cloud Hypervisor controller session,supplied + /// rows, committed Provider identities, and the controller-session + /// generation)andthe Cloud Hypervisor controller session, supplied /// through the composition root. The family never receives a /// daemon-built effect port (R2). pub guest_facets: GuestEffectFacets, @@ -4760,9 +4760,9 @@ HOST_EFFECTS_SERVICE.id, /// U15:the composition root hosts the process-systemd family's /// declared effects service from the family's own factory over the - /// registered service identity (U3,R5: the registration table + /// registered service identity (U3, R5: the registration table /// carries the row;the daemon names no family string, only the - /// crate's declared service id),and the hosted service answers + /// crate's declared service id), and the hosted service answers /// `inspect-process-systemd` through the real invocation capability /// object carrying the real envelope payload - hermetic, served from /// the crate's own handler table, reaching no daemon state. diff --git a/packages/xtask/src/gen_layer_catalogs.rs b/packages/xtask/src/gen_layer_catalogs.rs index d49cd1f8f..67e54a954 100644 --- a/packages/xtask/src/gen_layer_catalogs.rs +++ b/packages/xtask/src/gen_layer_catalogs.rs @@ -155,7 +155,7 @@ fn string_slice(name: &str, doc: &[&str], values: &[String]) -> String { } /// Render one closed `&[&str]` constant. - +/// /// Render one `&[(&str, &str)]` constant. fn string_pair_slice(name: &str, doc: &[&str], values: &[(&str, &str)]) -> String { let mut out = doc_lines(doc); diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index a76b824b9..005e90060 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -5272,7 +5272,7 @@ const STRUCTURAL_ROLE_VOCABULARIES: &[&str] = &[ /// The runner-role id strings the shared wire vocabulary spells. A string /// literal equal to one of these in a shared Nix module is a role literal: -/// the role vocabulary is knowledge the owning providers must declare,and +/// the role vocabulary is knowledge the owning providers must declare, and /// a hand-spelled id cannot hide behind a family's renamed spelling. const ROLE_ID_LITERALS: &[&str] = &[ "provider-controller", @@ -5343,7 +5343,7 @@ impl StructuralSignalClass { } /// One structural knowledge exemption row. A signal without a row beside it -/// fails,arow whose signal the tree no longer carries fails the same way,and +/// fails, arow whose signal the tree no longer carries fails the same way, and /// no row may be added because that is what a reintroduction looks like./ /// /// Where a Rust structural signal's symbol contains a family token the module's @@ -8632,7 +8632,7 @@ fn render_provider_family_violation(signal: &ProviderFamilySignal) -> String { /// One committed exemption row: a provider crate module that legitimately /// carries another family's identity token. The list only shrinks: a signal -/// without a row is a policy failure (a reintroduction),and a row whose +/// without a row is a policy failure (a reintroduction), and a row whose /// signal the tree no longer carries is stale. No row may be added unless the /// change that introduces a legitimate cross-family reference also records /// its reason here. @@ -8824,12 +8824,12 @@ enum CommittedScopeClass { } /// One row in the committed program scope: a workspace crate the plan's -/// program may edit,classified into the class the plan names. The list is +/// program may edit, classified into the class the plan names. The list is /// closed: a workspace crate without a row is an edit outside the declared -/// scope (a crate no unit names),and a row whose crate no longer exists is +/// scope (a crate no unit names), and a row whose crate no longer exists is /// stale. A committed-scope check cannot police every file outside these -/// classes without encoding the whole plan's touch surface,so it polices -/// the crate set and the declared artifact roots,the two surfaces the plan +/// classes without encoding the whole plan's touch surface, so it polices +/// the crate set and the declared artifact roots, the two surfaces the plan /// names; every other surface (docs/plans, changelog.d, tests/, Nix /// modules, Bazel files, ...) is out of its scope by construction. struct CommittedScopeEntry { @@ -9036,7 +9036,7 @@ const COMMITTED_SCOPE: &[CommittedScopeEntry] = &[ const COMMITTED_SCOPE_ARTIFACT_ROOTS: &[&str] = &["docs/reference", "packages/policy-inputs"]; /// Fail when a workspace crate has no committed scope row (an edit to a -/// crate no unit names),when a row names a crate the workspace no longer has, +/// crate no unit names), when a row names a crate the workspace no longer has, /// or when a declared artifact root has vanished. The committed scope is /// compared against the workspace rather than a diff: any crate present without /// a row is an edit outside the scope that happened, which is what a diff --git a/packages/xtask/src/resource_type_authority.rs b/packages/xtask/src/resource_type_authority.rs index 7fc93b6b7..aafd16996 100644 --- a/packages/xtask/src/resource_type_authority.rs +++ b/packages/xtask/src/resource_type_authority.rs @@ -68,7 +68,7 @@ const PROVIDER_PREFIX: &str = "d2b-provider-"; const DECLARATION_FILE: &str = "resource-types.json"; /// The repository-relative generated artifact path (relative to the source -/// file that `include!`s it,so `include!("generated/...")` resolves it). +/// file that `include!`s it, so `include!("generated/...")` resolves it). pub(crate) const GENERATED_ARTIFACT: &str = "packages/d2b-contracts/src/generated/v3_converted_resource_types.rs"; @@ -1003,7 +1003,7 @@ mod tests { /// Create the committed schema files the Nix inventory render requires /// for a fixture declaring the given standard types: one Core schema per - /// standard type, the four semantic projection schemas,and the two provider + /// standard type, the four semantic projection schemas, and the two provider /// farm schemas. The render only verifies existence, so empty files /// suffice. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -1685,4 +1685,4 @@ mod tests { ); check(&fixture.root).expect("the gate passes after regeneration"); } -} \ No newline at end of file +} From 9071ec4b3d5f3f6920c3e58d6ac89eb43763822d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 06:38:50 -0700 Subject: [PATCH 223/726] broker: name the bootstrap flag-arm callback type The extracted parser's callback parameter was a type clippy calls too complex; the alias states what the arm is and the layer1-bootstrap clippy target builds again. --- packages/d2b-broker/src/runtime.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 10c464b4a..556f4cf26 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -10387,10 +10387,16 @@ fn run_probe( } } +#[cfg(feature = "layer1-bootstrap")] +/// One flag arm of the shared bootstrap parser: it sees the flag name, the +/// remaining arguments, and the cursor, and advances the cursor past the +/// arguments it consumed. +type FlagArm<'a> = dyn FnMut(&str, &[String], &mut usize) -> Result<(), RunError> + 'a; + #[cfg(feature = "layer1-bootstrap")] fn parse_common_flags( rest: &[String], - extra: &mut dyn FnMut(&str, &[String], &mut usize) -> Result<(), RunError>, + extra: &mut FlagArm<'_>, ) -> Result<(PathBuf, Option), RunError> { let mut socket_path = PathBuf::from(DEFAULT_SOCKET_PATH); let mut test_uid = None; From 59676900e814d5158712bf05ca93741254fc6f5d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 06:45:45 -0700 Subject: [PATCH 224/726] golden: pin the parser-derived allowed-subcommand list The wave replaced the hand-maintained builtin command list with the parser's own subcommand names, so the retired realm-era entries no longer appear in the operator-visible auth status output. The golden was pinning that stale list; it now pins today's commands. --- tests/golden/cli-output/auth-status-human.golden | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/golden/cli-output/auth-status-human.golden b/tests/golden/cli-output/auth-status-human.golden index f5be842e4..3424f36ff 100644 --- a/tests/golden/cli-output/auth-status-human.golden +++ b/tests/golden/cli-output/auth-status-human.golden @@ -3,6 +3,6 @@ effective uid: 1000 sockets: - public: reachable (version 0.4.0-test) - broker: unreachable -allowed subcommands: audio, auth status, boot, build, console, down, generations, launch, list, op inspect, realm enter, realm inspect, realm list, realm run, restart, rollback, status, switch, test, up, usb +allowed subcommands: activation, auth, complete, create, credential, debug, delete, device, emergency-policy, endpoint, exec, export, get, guest, host, import, list, network, op, process, provider, quota, reconcile, resource, shell, status, update-spec, upgrade, user, volume, watch, zone denied subcommands: - audit: audit requires admin role in `d2b.site.adminUsers`. From 5be1a656b1fd709e8b0fe5919fce3374143c532d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 06:45:45 -0700 Subject: [PATCH 225/726] wave 1: clear the doc-block blanks the feature variants exposed Fifty-six blank lines between doc blocks and their items, in eighteen files, in code paths only the test-support and layer1-bootstrap variants compile; the async-gate inventory records the line shifts the same edits caused. --- packages/d2b-broker/src/ops/usbip_host.rs | 3 --- packages/d2b-contracts-broker/src/broker_wire.rs | 4 ---- packages/d2b-session-unix/src/credit.rs | 1 - packages/d2b/src/zone_audit.rs | 2 -- packages/d2bd-runtime/src/broker_transport.rs | 2 -- packages/d2bd-runtime/src/ch_api.rs | 1 - packages/d2bd-runtime/src/readiness.rs | 3 --- packages/d2bd-runtime/src/target_runtime.rs | 1 - packages/d2bd-runtime/src/unsafe_local_helper.rs | 9 --------- packages/d2bd-runtime/src/vm_start_support.rs | 3 --- packages/d2bd/src/audio_dispatch.rs | 1 - packages/d2bd/src/composition.rs | 2 -- packages/d2bd/src/guest_target_session.rs | 1 - packages/d2bd/src/provider_effects.rs | 1 - packages/d2bd/src/resource_plane_v3.rs | 14 -------------- packages/d2bd/src/shared_provider_effects.rs | 1 - packages/xtask/data/async-gate-inventory.json | 8 ++++---- packages/xtask/src/provider_crate_policy.rs | 6 ------ packages/xtask/src/resource_type_authority.rs | 1 - 19 files changed, 4 insertions(+), 60 deletions(-) diff --git a/packages/d2b-broker/src/ops/usbip_host.rs b/packages/d2b-broker/src/ops/usbip_host.rs index e5c7709b9..80ca5e13a 100644 --- a/packages/d2b-broker/src/ops/usbip_host.rs +++ b/packages/d2b-broker/src/ops/usbip_host.rs @@ -168,15 +168,12 @@ pub struct UsbipHostDeviceInspection { /// The USBIP bus id the device was inspected under. pub bus_id: String, /// The observed USB vendor id. - pub vendor: u16, /// The observed USB product id. - pub product: u16, /// The physical bus number the device sits on. pub bus_number: u16, /// The physical port chain under the bus, root-first. - pub port_chain: Vec, /// The device node (e.g. `/dev/bus/usb/...`) the device exposes. pub device_node: PathBuf, diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index e7f2edbe1..61404148b 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -420,12 +420,10 @@ pub struct ForwardOperationRequest { pub chain_identities: Option>, /// The positions, in the frame's SCM_RIGHTS attachment list, of the /// descriptors this request carries. Empty when the request carries none. - #[serde(default)] pub fd_indexes: Vec, /// The kernel kind each declared descriptor must present, index-aligned /// with [`Self::fd_indexes`]. - #[serde(default)] pub fd_kinds: Vec, } @@ -447,12 +445,10 @@ pub enum ForwardOperationOutcome { /// The positions, in the frame's SCM_RIGHTS attachment list, of the /// descriptors the answering peer returned. Empty when the response /// carries none. - #[serde(default)] fd_indexes: Vec, /// The kernel kind each declared descriptor must present, index-aligned /// with the fd-index declarations. - #[serde(default)] fd_kinds: Vec, }, diff --git a/packages/d2b-session-unix/src/credit.rs b/packages/d2b-session-unix/src/credit.rs index cd7474542..59b01b8be 100644 --- a/packages/d2b-session-unix/src/credit.rs +++ b/packages/d2b-session-unix/src/credit.rs @@ -22,7 +22,6 @@ pub enum CreditError { /// /// Reservations are accounted atomically; dropping a reservation returns /// its credit. - #[derive(Clone)] pub struct CreditPool { inner: Arc, diff --git a/packages/d2b/src/zone_audit.rs b/packages/d2b/src/zone_audit.rs index 58eea2fdc..a0462b761 100644 --- a/packages/d2b/src/zone_audit.rs +++ b/packages/d2b/src/zone_audit.rs @@ -349,8 +349,6 @@ fn validate_record( /// Verify the chain tail shared by v1 and v2 records: prev/record digest /// shape, expected-previous linkage, canonical envelope, and digest equality. - - fn verify_chain( object: &serde_json::Map, fields_key: &str, diff --git a/packages/d2bd-runtime/src/broker_transport.rs b/packages/d2bd-runtime/src/broker_transport.rs index f2ef94a7a..b7f20ce77 100644 --- a/packages/d2bd-runtime/src/broker_transport.rs +++ b/packages/d2bd-runtime/src/broker_transport.rs @@ -136,7 +136,6 @@ fn broker_round_trip_within_deadline( /// The wire `kind` discriminator of a broker response, or `unknown` when /// the payload carries none or cannot be serialized. - pub fn broker_response_kind(response: &BrokerResponse) -> String { serde_json::to_value(response) .ok() @@ -216,7 +215,6 @@ pub fn redact_broker_error_for_launcher( /// Render an operator-facing (summary, remediation) pair for the launcher /// role when the broker socket itself is unreachable (distinct from a broker /// error reply, which [`redact_broker_error_for_launcher`] shapes). - pub fn redact_broker_dispatch_failure_for_launcher(op_name: &str) -> (String, String) { ( format!("{op_name} failed"), diff --git a/packages/d2bd-runtime/src/ch_api.rs b/packages/d2bd-runtime/src/ch_api.rs index 4e7b1e374..63c9b078e 100644 --- a/packages/d2bd-runtime/src/ch_api.rs +++ b/packages/d2bd-runtime/src/ch_api.rs @@ -76,7 +76,6 @@ pub async fn get_vm_info(socket: &Path, timeout: Duration) -> Result Result<(), ChApiError> { request(socket, "PUT", "/api/v1/vm.shutdown", timeout) .await diff --git a/packages/d2bd-runtime/src/readiness.rs b/packages/d2bd-runtime/src/readiness.rs index 53351f5d0..26ad141ff 100644 --- a/packages/d2bd-runtime/src/readiness.rs +++ b/packages/d2bd-runtime/src/readiness.rs @@ -126,7 +126,6 @@ pub fn unix_socket_listening(path: &str) -> bool { /// # Errors /// /// Returns "tcp-readiness-timeout:host:port" when the port never opens. - pub async fn wait_for_tcp_port(host: &str, port: u16, timeout: Duration) -> Result<(), String> { let deadline = Instant::now() + timeout; loop { @@ -148,8 +147,6 @@ pub async fn wait_for_tcp_port(host: &str, port: u16, timeout: Duration) -> Resu /// /// Returns "command-readiness-empty" for an empty argv and /// "command-readiness-exec-failed" when the program cannot be spawned. - - pub async fn command_ready(command: &[String]) -> Result { let Some(program) = command.first() else { return Err("command-readiness-empty".to_owned()); diff --git a/packages/d2bd-runtime/src/target_runtime.rs b/packages/d2bd-runtime/src/target_runtime.rs index ebfb4f5cd..90f0c04a7 100644 --- a/packages/d2bd-runtime/src/target_runtime.rs +++ b/packages/d2bd-runtime/src/target_runtime.rs @@ -370,7 +370,6 @@ impl AdmissionPermit { /// Repeated calls are idempotent: only the first release touches the /// counter; later calls are no-ops, so a drop-order race cannot /// double-free an admission slot. - pub fn release(&self) { if !self.inner.released.swap(true, Ordering::AcqRel) { let counter = match self.inner.kind { diff --git a/packages/d2bd-runtime/src/unsafe_local_helper.rs b/packages/d2bd-runtime/src/unsafe_local_helper.rs index 718a7bed0..9f57b426b 100644 --- a/packages/d2bd-runtime/src/unsafe_local_helper.rs +++ b/packages/d2bd-runtime/src/unsafe_local_helper.rs @@ -43,12 +43,9 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; pub const HELPER_HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); /// How long a helper may fall silent before it is treated as stale. - pub const HELPER_STALE_AFTER: Duration = Duration::from_secs(15); /// How long a launched helper operation may run before the daemon gives up. - - pub const HELPER_OPERATION_TIMEOUT: Duration = Duration::from_secs(30); const HELPER_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(30); const HELPER_LOOP_TICK: Duration = Duration::from_millis(200); @@ -90,7 +87,6 @@ pub enum HelperAvailability { /// The outcome of a launched helper operation: a successful result or a /// rejection with a wire failure code. Correlated by request id at the /// pending-request table. - pub enum HelperReply { Operation(HelperOperationResult), Rejected(HelperOperationRejected), @@ -214,7 +210,6 @@ struct RegistryState { /// /// Tracks per-UID helper generations, snapshots, and operation /// completions; all peer contact flows through [`Self::accept_loop`]. - pub struct HelperRegistry { daemon_uid: u32, allowed_uids: HashSet, @@ -235,7 +230,6 @@ impl fmt::Debug for HelperRegistry { impl HelperRegistry { /// Create an empty registry admitting only `allowed_uids`, with the daemon's /// own peer uid recorded for socket-credential checks. - pub fn new(daemon_uid: u32, allowed_uids: impl IntoIterator) -> Self { Self { daemon_uid, @@ -248,7 +242,6 @@ impl HelperRegistry { /// Blocking accept loop for the helper listener: each accepted socket /// is handled on its own dedicated thread. Runs forever and surfaces /// accept errors to tracing only. - #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn accept_loop(self: Arc, listener: Socket) { loop { @@ -314,7 +307,6 @@ impl HelperRegistry { /// The wire failure code of the most recent rejected operation for `target` by /// `uid`, if any, used to surface stable operator diagnostics. - pub fn last_failure( &self, uid: u32, @@ -337,7 +329,6 @@ impl HelperRegistry { /// /// Returns the registry error for invalid launch shapes, unknown /// helpers, stale connections, or queue backpressure. - #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn dispatch_launch( &self, diff --git a/packages/d2bd-runtime/src/vm_start_support.rs b/packages/d2bd-runtime/src/vm_start_support.rs index b9f24773c..dc6dac53c 100644 --- a/packages/d2bd-runtime/src/vm_start_support.rs +++ b/packages/d2bd-runtime/src/vm_start_support.rs @@ -7,14 +7,11 @@ const VM_RUNNER_ROLE_ID: &str = "ch-runner"; #[derive(Debug, Clone, Copy)] pub enum VmStartNodeMode { /// The node is resolved for readiness only, never launched by VM boot. - ReadinessOnly, /// The node runs once during VM start, governed by the named runner role. - OneShot(RunnerRole), /// The node stays alive for the whole VM session, governed by the named /// runner role. - LongLived(RunnerRole), } diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index 55494f0e7..fe6d9cde9 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -377,7 +377,6 @@ pub(crate) fn combined_audio_applied( /// the audio serialization lock, and return [`TypedError::InternalIo`] /// for manifest, capability, lock, read, write, or enforcement /// failures. - pub fn dispatch_audio( state: &ServerState, caller_role: BrokerCallerRole, diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index fede6ae3e..220c20e03 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -3473,7 +3473,6 @@ fn admission_config(state: &ServerState) -> AdmissionConfig { /// startup-contract state (pidfs, state lock, socket path), IO failures /// (socket bind, helper socket, pidfd-table restore), and caller /// authorization refusals during the accept loop. - pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { let mut config = load_config(&options.config_path)?; apply_overrides(&mut config, &options); @@ -28424,7 +28423,6 @@ mod broker_dispatch_tests { /// dispatches the `apply-nm-unmanaged` kernel with the declared path, /// match criteria, reload behaviour, and ownership/mode - never a /// compiled constant. - #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn host_prepare_installs_declared_nm_unmanaged_contract() { diff --git a/packages/d2bd/src/guest_target_session.rs b/packages/d2bd/src/guest_target_session.rs index 0e593aa59..d14458d7d 100644 --- a/packages/d2bd/src/guest_target_session.rs +++ b/packages/d2bd/src/guest_target_session.rs @@ -40,7 +40,6 @@ impl GuestTargetSession for DaemonGuestTargetSession { /// /// Returns [`GuestTargetError::SessionUnavailable`] when the session is /// no longer live or the request fails. - async fn request( &self, request: ttrpc::Request, diff --git a/packages/d2bd/src/provider_effects.rs b/packages/d2bd/src/provider_effects.rs index 6ac08d6a7..99b894639 100644 --- a/packages/d2bd/src/provider_effects.rs +++ b/packages/d2bd/src/provider_effects.rs @@ -93,7 +93,6 @@ impl FixedEffectAdapter { /// /// Returns [`FixedEffectError::Broker`] when the broker socket instance /// fails validation. - pub fn validate_instance(&self) -> Result<(), FixedEffectError> { self.broker .validate_instance() diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 08e962db6..bb7a56131 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -3413,13 +3413,10 @@ fn bundle_desired(zone: &ZoneId, row: &BundleResource) -> DesiredResource { #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct BundleIngestReport { /// The rows this ingestion applied. - pub applied: Vec, /// The rows this ingestion removed. - pub removed: Vec, /// The rows this ingestion protected from management-plane mutation. - pub api_protected: Vec, } @@ -6268,7 +6265,6 @@ HOST_EFFECTS_SERVICE.id, /// A published Volume notice sets the pending flag and, after the drain, /// performs exactly one re-materialization. - #[tokio::test(flavor = "multi_thread")] async fn a_volume_notice_sets_the_pending_flag_and_drains_into_one_rematerialization() { let rig = anchor_subscription_rig(); @@ -6424,7 +6420,6 @@ HOST_EFFECTS_SERVICE.id, /// A notice for a type the selector does not cover leaves the pending /// flag clear. - #[tokio::test(flavor = "multi_thread")] async fn a_notice_for_an_uncovered_type_leaves_the_pending_flag_clear() { let rig = anchor_subscription_rig(); @@ -6524,9 +6519,6 @@ HOST_EFFECTS_SERVICE.id, /// An expired registration causes the same recovery path and does not end /// the subscription. - - - #[tokio::test(flavor = "multi_thread")] async fn an_expired_registration_relists_and_does_not_end_the_subscription() { let rig = anchor_subscription_rig_with(WatchHubConfig { @@ -6588,9 +6580,6 @@ HOST_EFFECTS_SERVICE.id, /// The registry rebuild after a relist reflects the durable rows, /// including a row committed while the subscription was between streams. - - - #[tokio::test(flavor = "current_thread")] async fn a_relist_rebuild_reflects_durable_rows_including_one_committed_between_streams() { let rig = anchor_subscription_rig_with(WatchHubConfig { @@ -6648,9 +6637,6 @@ HOST_EFFECTS_SERVICE.id, /// A status-source notice for a Volume row does not set the pending /// flag, so only durable changes trigger a re-materialization. - - - #[tokio::test(flavor = "multi_thread")] async fn a_status_source_notice_does_not_set_the_pending_flag() { let rig = anchor_subscription_rig(); diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index ec0353e74..68c23ff1f 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -2930,7 +2930,6 @@ mod tests { /// (the durable deleting mark, an ungenerationed status, a stale /// generation) - the gate's phase equals the phase /// `ResourceView::wire_status` serves, so a future divergence fails here. - #[test] fn view_phase_delegates_to_the_canonical_wire_phase() { let statuses = [ diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index ebecf8ef2..48a09184e 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -1128,22 +1128,22 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10731, + "line": 10730, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26171, + "line": 26164, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26568, + "line": 26561, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_plane_v3.rs", - "line": 6742, + "line": 6728, "reason": "synchronous lock acquisition, no await while the guard is held" }, { diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index 005e90060..dfbff026a 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -8636,23 +8636,17 @@ fn render_provider_family_violation(signal: &ProviderFamilySignal) -> String { /// signal the tree no longer carries is stale. No row may be added unless the /// change that introduces a legitimate cross-family reference also records /// its reason here. - - #[derive(Clone)] struct ProviderFamilyKnowledgeExemption { /// The provider crate that carries the token (its Cargo package name). crate_name: &'static str, /// Repository-relative module path that carries the token. - module: &'static str, /// The family identity token the module writes. - token: &'static str, /// The family that owns the token. - family: &'static str, /// What the reference is and why it stays. - reason: &'static str, } diff --git a/packages/xtask/src/resource_type_authority.rs b/packages/xtask/src/resource_type_authority.rs index aafd16996..71f2ffa75 100644 --- a/packages/xtask/src/resource_type_authority.rs +++ b/packages/xtask/src/resource_type_authority.rs @@ -225,7 +225,6 @@ struct RoleDeclaration { /// The parsed per-crate type authority inputs. struct AuthorityRegistry { /// Crate name -> declared type names. - declarations: BTreeMap>, /// Crate name -> registered descriptor type names (extracted from the /// crate's Rust sources). From c8cc51af4aa49804a3a85022145ac6cfedaba824 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 06:50:58 -0700 Subject: [PATCH 226/726] golden: move the json variant and regenerate the daemon api reference The json golden pins the same allowed-subcommand list as the human one; the daemon api reference is regenerated because the wave's scanner rewrite changed how the collector renders it. --- docs/reference/daemon-api.md | 220 +++++++++--------- .../golden/cli-output/auth-status-json.golden | 49 ++-- 2 files changed, 140 insertions(+), 129 deletions(-) diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 245b2d5b1..1e7567825 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -83,8 +83,8 @@ compatibility surface. | `HelloOk` | struct | [`HelloOk`](../../packages/d2b-contracts/src/lib.rs#L159) | struct { `server_version`: `Version`; `selected_version`: `Version`; `capabilities`: `Vec` } | | `HelloRejected` | struct | [`HelloRejected`](../../packages/d2b-contracts/src/lib.rs#L167) | struct { `reason`: `HelloRejectedReason` } | | `HelloRejectedReason` | enum | [`HelloRejectedReason`](../../packages/d2b-contracts/src/lib.rs#L173) | `VersionMismatch`; `CapabilityNegotiationFailed`; `InternalError` | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L903) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L997) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L899) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L993) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | | `KnownFeatureFlag` | enum | [`KnownFeatureFlag`](../../packages/d2b-contracts/src/lib.rs#L123) | `TypedErrors`; `ManifestV04`; `StatusCheckBridges`; `ExportBrokerAudit`; `ConfiguredLaunchV1`; `UnsafeLocalProviderV1` | | `SemverRange` | struct | [`SemverRange`](../../packages/d2b-contracts/src/error.rs#L1130) | empty struct | @@ -278,63 +278,63 @@ host reboot. | --- | --- | --- | --- | | `BrokerRequest` | enum | [`BrokerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L32) | `ApplyHostGenerationHandoff` - (crate::host_generation::ApplyHostGenerationHandoff); `CreateOrReconcileUsersGroups` - (CreateOrReconcileUsersGroupsRequest); `DelegateCgroupV2` - (DelegateCgroupV2Request); `ExportBrokerAudit` - (ExportBrokerAuditRequest); `Hello` - (HelloRequest); `PublishTrustedContext` - (PublishTrustedContextValues); `InjectSecretById` - (SecretByIdRequest); `LaunchMinijailChild` - (LaunchMinijailChildRequest); `ModprobeIfAllowed` - (ModprobeIfAllowedRequest); `OpenCgroupDir` - (OpenCgroupDirRequest); `OpenDevice` - (OpenDeviceRequest); `OpenFuse` - (OpenFuseRequest); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyRequest); `OpenKvm` - (OpenKvmRequest); `QemuMediaEnroll` - (QemuMediaEnrollRequest); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryRequest); `QemuMediaBoot` - (QemuMediaBootRequest); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleRequest); `QemuMediaQueryStatus` - (QemuMediaQueryStatusRequest); `QemuMediaQuit` - (QemuMediaLifecycleRequest); `QemuMediaAttach` - (QemuMediaHotplugRequest); `QemuMediaDetach` - (QemuMediaHotplugRequest); `PipeWireAudio` - (PipeWireAudioRequest); `OpenVhostNet` - (OpenVhostNetRequest); `ReconcileStorageScope` - (ReconcileStorageScopeRequest); `ValidateLockSpec` - (ValidateLockSpecRequest); `StoreSync` - (StoreSyncRequest); `ReadSecretById` - (SecretByIdRequest); `RotateSecretById` - (SecretByIdRequest); `UsbipBind` - (UsbipBindRequest); `UsbipBindFirewallRule` - (UsbipBindFirewallRuleRequest); `UsbipProxyReconcile` - (UsbipProxyReconcileRequest); `UsbipUnbind` - (UsbipUnbindRequest); `UsbipExplicitBind` - (UsbipExplicitBindRequest); `UsbipExplicitFirewallRule` - (UsbipExplicitFirewallRuleRequest); `OwnershipMatrixCheck` - (OwnershipMatrixCheckRequest); `SshHostKeyPreflight` - (SshHostKeyPreflightRequest); `DiskInit` - (DiskInitRequest); `SecurityKeyOpenDevice` - (d2b_contracts::security_key::SecurityKeyOpenDeviceRequest); `SecurityKeyApplyUdevRules` - (d2b_contracts::security_key::SecurityKeyApplyUdevRulesRequest); `EnvelopeInvoke` - (EnvelopeInvokeRequest) | | `ForwardOperationRequest` | struct | [`ForwardOperationRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L397) | struct { `operation`: `String`; `zone`: `String`; `invocation_id`: `String`; `payload`: `serde_json::Value`; `context`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L491) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L903) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1009) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1040) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | -| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1058) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1069) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1085) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1101) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | -| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1113) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1134) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1153) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1169) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1185) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1207) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1215) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | -| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1272) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | -| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1284) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1298) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | -| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1308) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1317) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | -| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1326) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1340) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1361) | struct { `tracing_span_id`: `Option` } | -| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1383) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1391) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1399) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | -| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1464) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1551) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1624) | empty struct | -| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1639) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1713) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | -| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1783) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | -| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1839) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | -| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1850) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | -| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1923) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1931) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1943) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | -| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1986) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2008) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | -| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2045) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | -| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2059) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2082) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2099) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2107) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2115) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2137) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | -| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2155) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | -| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2250) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2307) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2316) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2600) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | -| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2937) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2954) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2965) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2979) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | -| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3016) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3050) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L487) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L899) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1005) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1036) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | +| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1054) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1065) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1081) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1097) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | +| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1109) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1130) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1149) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1165) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1181) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1203) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1211) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | +| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1268) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | +| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1280) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1294) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | +| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1304) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1313) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | +| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1322) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1336) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1357) | struct { `tracing_span_id`: `Option` } | +| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1379) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1387) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1395) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | +| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1460) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1547) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1620) | empty struct | +| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1635) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1709) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | +| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1779) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | +| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1835) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | +| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1846) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | +| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1919) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1927) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1939) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | +| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1982) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2004) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | +| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2041) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | +| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2055) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2078) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2095) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2103) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2111) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2133) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | +| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2151) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | +| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2246) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2303) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2312) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2596) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | +| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2933) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2950) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2961) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2975) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | +| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3012) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3046) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | ### Console and audio wire types @@ -391,37 +391,37 @@ see the auto-generated tables above for the committed Rust variants. | --- | --- | --- | --- | | `ApplyHostGenerationHandoffResponse` | struct | [`ApplyHostGenerationHandoffResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L212) | struct { `target`: `d2b_contracts_resource::v3::ResourceRef`; `state`: `crate::host_generation::HandoffState`; `source_generation`: `u64`; `target_generation`: `u64`; `source_remains_usable`: `bool`; `summary`: `String` } | | `PublishTrustedContextResponse` | struct | [`PublishTrustedContextResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L373) | struct { `broker_epoch`: `u64` } | -| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L469) | struct { `outcome`: `ForwardOperationOutcome` } | -| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L523) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L911) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L970) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L997) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | -| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1350) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1368) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1444) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | -| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1451) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | -| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1494) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | -| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1605) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1629) | struct { `pidfd_index`: `u32` } | -| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1680) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | -| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1732) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | -| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1873) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1885) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | -| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1894) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | -| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1905) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1915) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | -| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1973) | struct { `selector_resolved`: `String`; `device_class`: `String` } | -| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2029) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | -| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2170) | struct { `accepted`: `bool`; `operation`: `String` } | -| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2177) | struct { `bridge`: `Option`; `tap`: `IfName` } | -| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2184) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2229) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | -| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2299) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | -| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2359) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | -| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2755) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | -| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3000) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | -| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3024) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | -| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3113) | struct { `notifications`: `Vec` } | +| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L465) | struct { `outcome`: `ForwardOperationOutcome` } | +| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L519) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L907) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L966) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L993) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1346) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1364) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1440) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | +| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1447) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | +| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1490) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | +| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1601) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1625) | struct { `pidfd_index`: `u32` } | +| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1676) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | +| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1728) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | +| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1869) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1881) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | +| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1890) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | +| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1901) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1911) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | +| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1969) | struct { `selector_resolved`: `String`; `device_class`: `String` } | +| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2025) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | +| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2166) | struct { `accepted`: `bool`; `operation`: `String` } | +| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2173) | struct { `bridge`: `Option`; `tap`: `IfName` } | +| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2180) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2225) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | +| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2295) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | +| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2355) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | +| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2751) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | +| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2996) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | +| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3020) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | +| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3109) | struct { `notifications`: `Vec` } | ## Per-VM lifecycle state @@ -497,24 +497,24 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | | `FdKind` | enum | [`FdKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L253) | `Fifo`; `Socket`; `CharDevice`; `BlockDevice`; `Any`; `Regular`; `Directory` | -| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L442) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | -| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L845) | `Host`; `Guest` | -| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1028) | `Apply`; `Remove` | -| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1259) | `Info`; `Warning`; `Error`; `Denied` | -| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1413) | `SystemPowerdown`; `Quit` | -| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1420) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | -| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1473) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | -| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1693) | `Speaker`; `Microphone` | -| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1703) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | -| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1747) | `System`; `User` | -| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1863) | `Drain`; `Terminate` | -| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2242) | `Term`; `Kill`; `Quit` | -| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2378) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | -| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2733) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | -| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2891) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | -| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2989) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | -| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3063) | `Exited`; `Signaled`; `Killed` | -| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3101) | `ChildReaped` - (ChildReapedNotification); `Unknown` | +| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L440) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | +| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L841) | `Host`; `Guest` | +| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1024) | `Apply`; `Remove` | +| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1255) | `Info`; `Warning`; `Error`; `Denied` | +| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1409) | `SystemPowerdown`; `Quit` | +| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1416) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | +| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1469) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | +| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1689) | `Speaker`; `Microphone` | +| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1699) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | +| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1743) | `System`; `User` | +| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1859) | `Drain`; `Terminate` | +| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2238) | `Term`; `Kill`; `Quit` | +| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2374) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | +| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2729) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | +| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2887) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | +| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2985) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | +| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3059) | `Exited`; `Signaled`; `Killed` | +| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3097) | `ChildReaped` - (ChildReapedNotification); `Unknown` | | `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L142) | `Lifecycle`; `Admin` | | `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L180) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | | `ProxyReadinessStage` | enum | [`ProxyReadinessStage`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L12) | `Upstream`; `Listener`; `FirstClient` | @@ -644,8 +644,8 @@ the failure class, for example `host check`, `audit`, `status`, or | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L970) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2538) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L966) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2534) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | | `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L199) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | | `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1208) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | diff --git a/tests/golden/cli-output/auth-status-json.golden b/tests/golden/cli-output/auth-status-json.golden index 4a8e4f448..3e13545d9 100644 --- a/tests/golden/cli-output/auth-status-json.golden +++ b/tests/golden/cli-output/auth-status-json.golden @@ -16,27 +16,38 @@ } ], "allowedSubcommands": [ - "audio", - "auth status", - "boot", - "build", - "console", - "down", - "generations", - "launch", + "activation", + "auth", + "complete", + "create", + "credential", + "debug", + "delete", + "device", + "emergency-policy", + "endpoint", + "exec", + "export", + "get", + "guest", + "host", + "import", "list", - "op inspect", - "realm enter", - "realm inspect", - "realm list", - "realm run", - "restart", - "rollback", + "network", + "op", + "process", + "provider", + "quota", + "reconcile", + "resource", + "shell", "status", - "switch", - "test", - "up", - "usb" + "update-spec", + "upgrade", + "user", + "volume", + "watch", + "zone" ], "deniedSubcommands": [ { From cebf395a0c8df7a44e0986c0c072793b2a9c42da Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 06:54:21 -0700 Subject: [PATCH 227/726] d2bd: drop two redundant closures and a needless borrow Both parse callbacks are plain functions and the zone is already a reference; the gate's clippy targets deny all three. --- packages/d2bd/src/composition.rs | 4 ++-- packages/d2bd/src/resource_runtime.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 220c20e03..ac69298d7 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -3256,7 +3256,7 @@ fn production_process_resource_port( .try_lock() .ok() .and_then(|plane| plane.clone()) - .and_then(|plane| plane.zone(&zone).ok()) + .and_then(|plane| plane.zone(zone).ok()) .and_then(|runtime| runtime.process_resource_client()) else { return RoutedProcessResourcePort(None); @@ -21270,7 +21270,7 @@ fn public_qemu_media_status( .sources .iter() .filter(|source| source.vm == vm) - .map(|source| qemu_media_source_status(source)) + .map(qemu_media_source_status) .collect::>() }) .unwrap_or_default(); diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 7b7b6d886..4ac271387 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -10077,7 +10077,7 @@ fn public_update_finalizers_request( let uid = request .get("uid") .and_then(Value::as_str) - .map(|value| ResourceUid::parse(value)) + .map(ResourceUid::parse) .transpose() .map_err(|_| ResourceRuntimeError::RequestInvalid)?; let expected_revision = @@ -10119,7 +10119,7 @@ fn public_delete_request_from_current( let mut uid = request .get("uid") .and_then(Value::as_str) - .map(|value| ResourceUid::parse(value)) + .map(ResourceUid::parse) .transpose() .map_err(|_| ResourceRuntimeError::RequestInvalid)?; if uid.is_none() && expected_revision.is_some() { From 76153aa440eb2140be9e3bd1f851a20336cd4ac9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 06:57:54 -0700 Subject: [PATCH 228/726] d2bd: correct the two zone call sites the borrow lint pointed at The first attempt dropped the borrow on a closure parameter that genuinely needs it - the crate stopped compiling - while leaving the reported site alone. The closure site keeps its borrow; the reported site passes the zone it already holds. --- packages/d2bd/src/composition.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index ac69298d7..e5c2a3e1c 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -3256,7 +3256,7 @@ fn production_process_resource_port( .try_lock() .ok() .and_then(|plane| plane.clone()) - .and_then(|plane| plane.zone(zone).ok()) + .and_then(|plane| plane.zone(&zone).ok()) .and_then(|runtime| runtime.process_resource_client()) else { return RoutedProcessResourcePort(None); @@ -20436,7 +20436,7 @@ fn dispatch_live_guest_activation_resource( .ok_or_else(|| TypedError::InternalConfig { detail: "resource plane unavailable".to_owned(), })?; - let runtime = plane.zone(&zone).map_err(|_| TypedError::InternalConfig { + let runtime = plane.zone(zone).map_err(|_| TypedError::InternalConfig { detail: "activation Zone runtime unavailable".to_owned(), })?; let guest_ref_text = format!("Guest/{}", request.vm); From 542920db8eb94293734f0954c3ec01f863fc3d28 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 07:23:19 -0700 Subject: [PATCH 229/726] audit: close the U2 wave gate green Scan, census, 988 Bazel tests, and all eleven host-integration checks pass at the wave head; the row records the seven attempts, the five defect classes they exposed, and the two deliberate surface effects the wave carries. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index e5d21107f..2119b8665 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -26,6 +26,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | wave | head | security scan | census | Layer-1 aggregate | host integration | notes | | --- | --- | --- | --- | --- | --- | --- | | U1 | `11bbfe41a` | pass | pass | pass (988 of 988 tests) | pass (11 of 11 vmChecks) | First attempt flaked on the load-sensitive `daemon_state_persistence` kill-during-startup race (passes standalone, not an audit row); the retry is green. The head carries the refreshed async-gate inventory for the broker line shifts. | +| U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | ## Findings (965 rows) From e8e7a2d51449a4954396cf15e3af7501ed510cb8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:27:29 -0700 Subject: [PATCH 230/726] d2bd-runtime: remove dead DrainerSource enum --- packages/d2bd-runtime/src/console_session.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index 324e19eec..f16884c77 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -49,18 +49,6 @@ const MAX_SESSIONS: usize = 64; /// Default ring-buffer capacity per VM (256 KiB). const RING_CAPACITY: usize = 256 * 1024; -/// Drainer source: where console bytes come from. -#[derive(Debug)] -pub enum DrainerSource { - /// Connect to a UNIX stream socket path created by the hypervisor - /// (`--serial socket=`). The drainer reconnects after drops. - UnixSocket(String), - /// Read from a pre-opened UNIX stream socket (used for testing or - /// for cases where the socket is already connected). - #[allow(dead_code)] - Connected(tokio::net::UnixStream), -} - /// Shared ring buffer state for one VM's console stream. #[derive(Debug)] pub struct ConsoleRing { From 75c49e784b2bdb8119f8f26c33802f31f92b2a8a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:27:54 -0700 Subject: [PATCH 231/726] d2bd-runtime: drop panicking Default for ConsoleClientHandle --- packages/d2bd-runtime/src/console_session.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index f16884c77..b80c9f36f 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -123,12 +123,6 @@ impl std::borrow::Borrow for ConsoleClientHandle { } } -impl Default for ConsoleClientHandle { - fn default() -> Self { - Self::new().expect("console handle entropy unavailable") - } -} - /// In-daemon console session table. /// /// One entry per running VM that has an active drainer. Multiple clients From 8b3164c4f449c916055f89542baaeaf8c3f890b3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:30:18 -0700 Subject: [PATCH 232/726] d2bd-runtime: make console client handle field private --- packages/d2bd-runtime/src/console_session.rs | 38 +++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index b80c9f36f..7f189bd24 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -103,7 +103,7 @@ impl ConsoleSession { /// Opaque per-client session token (UUID string). #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ConsoleClientHandle(pub String); +pub struct ConsoleClientHandle(String); impl ConsoleClientHandle { pub fn new() -> Result { @@ -117,6 +117,33 @@ impl ConsoleClientHandle { } } +/// Error returned when a console client handle string is malformed. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConsoleClientHandleParseError; + +impl std::fmt::Display for ConsoleClientHandleParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("malformed console client handle") + } +} + +impl std::error::Error for ConsoleClientHandleParseError {} + +impl std::str::FromStr for ConsoleClientHandle { + type Err = ConsoleClientHandleParseError; + + fn from_str(s: &str) -> Result { + let Some(hex) = s.strip_prefix("console-") else { + return Err(ConsoleClientHandleParseError); + }; + if hex.len() == 32 && hex.bytes().all(|b| b.is_ascii_hexdigit()) { + Ok(Self(s.to_owned())) + } else { + Err(ConsoleClientHandleParseError) + } + } +} + impl std::borrow::Borrow for ConsoleClientHandle { fn borrow(&self) -> &str { &self.0 @@ -533,6 +560,15 @@ mod tests { assert_eq!(table.client_owner_uid(handle.as_str()), Some(1000)); } + #[test] + fn handle_from_str_round_trips() { + let handle = ConsoleClientHandle::new().unwrap(); + let parsed: ConsoleClientHandle = handle.as_str().parse().unwrap(); + assert_eq!(parsed, handle); + assert!("not-a-handle".parse::().is_err()); + assert!("console-zzzz".parse::().is_err()); + } + #[test] fn attach_unknown_vm_returns_none() { let mut table = ConsoleSessionTable::new(); From cdfb78d49cc8ae7bc5ec67b9fc218a783ee74392 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:31:17 -0700 Subject: [PATCH 233/726] d2bd-runtime: make exec session worker spawn fallible --- packages/d2bd-runtime/src/exec_session.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/d2bd-runtime/src/exec_session.rs b/packages/d2bd-runtime/src/exec_session.rs index b8dd9bf44..0b122c6ee 100644 --- a/packages/d2bd-runtime/src/exec_session.rs +++ b/packages/d2bd-runtime/src/exec_session.rs @@ -924,7 +924,10 @@ pub struct WorkerSpawn { /// `establish_tx`, then services `WorkerCommand`s until the channel closes. /// Dropping the sender (owner disconnect) returns the worker, drops the /// runtime, and drops every client clone - prompting the guest teardown. -pub fn spawn_session_worker(spawn: WorkerSpawn) -> JoinHandle<()> { +/// +/// Returns an error when the OS thread cannot be spawned (thread exhaustion +/// or resource limits), before any worker state is created. +pub fn spawn_session_worker(spawn: WorkerSpawn) -> std::io::Result> { let WorkerSpawn { connector, spec, @@ -935,7 +938,7 @@ pub fn spawn_session_worker(spawn: WorkerSpawn) -> JoinHandle<()> { clock, owner_reaper, } = spawn; - std::thread::Builder::new() + Ok(std::thread::Builder::new() .name("d2b-exec".to_owned()) .spawn(move || { let runtime = match tokio::runtime::Builder::new_current_thread() @@ -962,8 +965,7 @@ pub fn spawn_session_worker(spawn: WorkerSpawn) -> JoinHandle<()> { Arc::new(TerminalReaper::new(clock, terminal_ttl)), owner_reaper, )); - }) - .expect("spawn exec session worker thread") + })?) } async fn worker_main( @@ -2519,7 +2521,8 @@ mod tests { terminal_ttl: EXEC_TERMINAL_CLEANUP_TTL, clock: Arc::new(SystemClock), owner_reaper: Arc::new(NoopReaper), - }); + }) + .expect("spawn exec session worker thread"); let reply = establish_rx.blocking_recv().expect("establish reply"); (control_tx, worker, reply) } @@ -3659,7 +3662,8 @@ mod tests { owner_reaper: Arc::new(RecordingReaper { reaped: reaped_for_worker, }), - }); + }) + .expect("spawn exec session worker thread"); establish_rx .blocking_recv() .expect("establish") From 40cf250b24e89009404792a8094977f9891a6948 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:34:26 -0700 Subject: [PATCH 234/726] d2bd-runtime: encode wave6 dependency progression as a typed stage --- .../src/resource_operator_activation.rs | 70 ++++++++++++++++--- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/packages/d2bd-runtime/src/resource_operator_activation.rs b/packages/d2bd-runtime/src/resource_operator_activation.rs index de9ee6a9f..154111721 100644 --- a/packages/d2bd-runtime/src/resource_operator_activation.rs +++ b/packages/d2bd-runtime/src/resource_operator_activation.rs @@ -124,24 +124,70 @@ impl Wave6ResourceSet { } } +/// The operator-acceptance progression stage a dependency projection +/// describes. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Wave6DepStage { + /// The Volume backing is not ready yet; Network reconcile defers. + WaitingForVolume, + /// The Volume is ready but the Network is not; Guest reconcile defers. + WaitingForNetwork, + /// Volume and Network are ready; the Guest reconcile can proceed. + ReadyForGuest, + /// Every dependency is ready; the Guest is ready for adoption. + ReadyForAdoption, +} + /// Dependency state supplied to a provider reconcile boundary. +/// +/// The acceptance progression is carried by [`Wave6DepStage`]; the readiness +/// facts are private, so only the named constructors can build a projection +/// and the impossible combinations cannot be represented. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Wave6Dependencies { + stage: Wave6DepStage, + volume_ready: bool, + network_ready: bool, + device_tpm_ready: bool, + guest_ready: bool, + attachment_ready: bool, +} + +impl Wave6Dependencies { + /// The acceptance progression stage this projection describes. + pub const fn stage(self) -> Wave6DepStage { + self.stage + } + /// Whether Volume layout and backing are ready. - pub volume_ready: bool, + pub const fn volume_ready(self) -> bool { + self.volume_ready + } + /// Whether Network realization is ready. - pub network_ready: bool, + pub const fn network_ready(self) -> bool { + self.network_ready + } + /// Whether the Device TPM endpoint is ready. - pub device_tpm_ready: bool, + pub const fn device_tpm_ready(self) -> bool { + self.device_tpm_ready + } + /// Whether the Guest process is ready. - pub guest_ready: bool, + pub const fn guest_ready(self) -> bool { + self.guest_ready + } + /// Whether attachment realization is ready. - pub attachment_ready: bool, -} + pub const fn attachment_ready(self) -> bool { + self.attachment_ready + } -impl Wave6Dependencies { + /// Network reconcile defers until the Volume backing is ready. pub const fn network_waiting_for_volume() -> Self { Self { + stage: Wave6DepStage::WaitingForVolume, volume_ready: false, network_ready: false, device_tpm_ready: true, @@ -150,8 +196,10 @@ impl Wave6Dependencies { } } + /// Guest reconcile defers until the Network realization is ready. pub const fn guest_waiting_for_network() -> Self { Self { + stage: Wave6DepStage::WaitingForNetwork, volume_ready: true, network_ready: false, device_tpm_ready: true, @@ -160,18 +208,22 @@ impl Wave6Dependencies { } } + /// Volume and Network are ready; the Guest reconcile can proceed. pub const fn network_ready_for_guest() -> Self { Self { + stage: Wave6DepStage::ReadyForGuest, volume_ready: true, network_ready: true, device_tpm_ready: true, - guest_ready: true, - attachment_ready: true, + guest_ready: false, + attachment_ready: false, } } + /// Every dependency is ready; the Guest is ready for adoption. pub const fn guest_ready_for_adoption() -> Self { Self { + stage: Wave6DepStage::ReadyForAdoption, volume_ready: true, network_ready: true, device_tpm_ready: true, From 7e0ec2bce343911834bddc1488e3b71dbb8c17e6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:34:56 -0700 Subject: [PATCH 235/726] d2bd-runtime: make peer admission lookup mode self-describing --- packages/d2bd-runtime/src/admission.rs | 35 ++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/d2bd-runtime/src/admission.rs b/packages/d2bd-runtime/src/admission.rs index 814eeb878..b6b67f7af 100644 --- a/packages/d2bd-runtime/src/admission.rs +++ b/packages/d2bd-runtime/src/admission.rs @@ -21,6 +21,17 @@ pub struct PeerIdentity { pub uid: u32, } +/// How the peer classifier resolves the configured lifecycle group. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PeerLookupMode { + /// Resolve the configured group through NSS; an unknown group is a + /// failed classifier lookup rather than an authority grant. + Production, + /// Skip the NSS group-name existence lookup; the supplied group list is + /// hermetic (test injection). + Hermetic, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PeerRole { Launcher, @@ -65,7 +76,13 @@ pub fn authorize_peer( #[cfg(any(test, feature = "test-support"))] if let Some(peer) = peer_override_injected() { let _peer_gid = peer.gid; - return classify_peer(peer.uid, peer.username, peer.groups, config, false); + return classify_peer( + peer.uid, + peer.username, + peer.groups, + config, + PeerLookupMode::Hermetic, + ); } let peer = getsockopt(stream, PeerCredentials).map_err(io_wrap("read SO_PEERCRED"))?; @@ -73,7 +90,13 @@ pub fn authorize_peer( let _peer_gid = peer.gid(); let uid = peer.uid() as u32; if uid == 0 { - return classify_peer(uid, None, Some(Vec::new()), config, false); + return classify_peer( + uid, + None, + Some(Vec::new()), + config, + PeerLookupMode::Hermetic, + ); } let user = get_user_by_uid(uid); let username = user @@ -88,7 +111,7 @@ pub fn authorize_peer( .map(|group| group.name().to_string_lossy().into_owned()) .collect() }); - classify_peer(uid, username, groups, config, true) + classify_peer(uid, username, groups, config, PeerLookupMode::Production) } #[cfg(any(test, feature = "test-support"))] @@ -105,7 +128,7 @@ pub fn classify_peer( username: Option, groups: Option>, config: &AdmissionConfig, - production_lookup: bool, + lookup_mode: PeerLookupMode, ) -> Result { if uid == config.daemon_uid { return Err(TypedError::AuthzNotALauncher { peer_uid: uid }); @@ -142,7 +165,9 @@ pub fn classify_peer( // In production, an unknown configured lifecycle group is a failed // classifier lookup rather than an authority grant. Test injection keeps // the group list hermetic and therefore skips NSS group-name lookup. - if production_lookup && get_group_by_name(lifecycle_group).is_none() { + if lookup_mode == PeerLookupMode::Production + && get_group_by_name(lifecycle_group).is_none() + { return Err(TypedError::AuthzNotALauncher { peer_uid: uid }); } From d1c5c44d951b4f704e113e837841738b1841f18c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:36:00 -0700 Subject: [PATCH 236/726] d2bd-runtime: type the typed-shell target key as a named struct --- .../d2bd-runtime/src/typed_shell_targets.rs | 102 +++++++++++++----- packages/d2bd/src/composition.rs | 35 ++++-- 2 files changed, 104 insertions(+), 33 deletions(-) diff --git a/packages/d2bd-runtime/src/typed_shell_targets.rs b/packages/d2bd-runtime/src/typed_shell_targets.rs index bd375e1eb..be71c05ac 100644 --- a/packages/d2bd-runtime/src/typed_shell_targets.rs +++ b/packages/d2bd-runtime/src/typed_shell_targets.rs @@ -8,11 +8,28 @@ struct CachedTypedShellSessionTarget { target: String, } +/// Key identifying one typed-shell session target by peer uid and shell +/// name. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct TypedShellTargetKey { + /// The peer uid that owns the session. + pub uid: u32, + /// The shell name. + pub name: String, +} + +impl TypedShellTargetKey { + /// Build a key from a peer uid and shell name. + pub fn new(uid: u32, name: String) -> Self { + Self { uid, name } + } +} + #[derive(Default)] pub struct TypedShellSessionTargetCache { - entries: std::collections::BTreeMap<(u32, String), CachedTypedShellSessionTarget>, - recency: std::collections::VecDeque<(u32, String)>, - create_reservations: std::collections::BTreeSet<(u32, String)>, + entries: std::collections::BTreeMap, + recency: std::collections::VecDeque, + create_reservations: std::collections::BTreeSet, } impl std::fmt::Debug for TypedShellSessionTargetCache { @@ -25,7 +42,7 @@ impl std::fmt::Debug for TypedShellSessionTargetCache { } impl TypedShellSessionTargetCache { - pub fn remember(&mut self, key: (u32, String), target: String) { + pub fn remember(&mut self, key: TypedShellTargetKey, target: String) { if self.entries.contains_key(&key) { self.entries .insert(key.clone(), CachedTypedShellSessionTarget { target }); @@ -47,13 +64,13 @@ impl TypedShellSessionTargetCache { self.touch(&key); } - pub fn cached(&mut self, key: &(u32, String)) -> Option { + pub fn cached(&mut self, key: &TypedShellTargetKey) -> Option { let target = self.entries.get(key)?.target.clone(); self.touch(key); Some(target) } - pub fn forget(&mut self, key: &(u32, String)) { + pub fn forget(&mut self, key: &TypedShellTargetKey) { self.entries.remove(key); self.recency.retain(|candidate| candidate != key); } @@ -80,7 +97,7 @@ impl TypedShellSessionTargetCache { /// where it panics (see the `lock_sync` seat in authority_persistence). pub fn reserve( cache: &Arc>, - key: (u32, String), + key: TypedShellTargetKey, ) -> Option { let mut guard = cache.try_lock().ok()?; if !guard.create_reservations.insert(key.clone()) { @@ -92,7 +109,7 @@ impl TypedShellSessionTargetCache { }) } - fn touch(&mut self, key: &(u32, String)) { + fn touch(&mut self, key: &TypedShellTargetKey) { self.recency.retain(|candidate| candidate != key); self.recency.push_back(key.clone()); } @@ -100,11 +117,11 @@ impl TypedShellSessionTargetCache { pub struct TypedShellSessionCreateReservation { cache: Arc>, - key: (u32, String), + key: TypedShellTargetKey, } impl TypedShellSessionCreateReservation { - pub fn new(cache: Arc>, key: (u32, String)) -> Self { + pub fn new(cache: Arc>, key: TypedShellTargetKey) -> Self { Self { cache, key } } } @@ -147,21 +164,36 @@ mod tests { #[test] fn reserve_admits_one_create_seat_per_uid_name_and_drop_releases() { let cache = new_cache(); - let first = TypedShellSessionTargetCache::reserve(&cache, (7, "primary".to_owned())) - .expect("first seat"); + let first = TypedShellSessionTargetCache::reserve( + &cache, + TypedShellTargetKey::new(7, "primary".to_owned()), + ) + .expect("first seat"); assert!( - TypedShellSessionTargetCache::reserve(&cache, (7, "primary".to_owned())).is_none(), + TypedShellSessionTargetCache::reserve( + &cache, + TypedShellTargetKey::new(7, "primary".to_owned()) + ) + .is_none(), "duplicate uid/name must conflict" ); - let _other_uid = - TypedShellSessionTargetCache::reserve(&cache, (8, "primary".to_owned())) - .expect("different uid admitted"); - let _other_name = - TypedShellSessionTargetCache::reserve(&cache, (7, "secondary".to_owned())) - .expect("different name admitted"); + let _other_uid = TypedShellSessionTargetCache::reserve( + &cache, + TypedShellTargetKey::new(8, "primary".to_owned()), + ) + .expect("different uid admitted"); + let _other_name = TypedShellSessionTargetCache::reserve( + &cache, + TypedShellTargetKey::new(7, "secondary".to_owned()), + ) + .expect("different name admitted"); drop(first); assert!( - TypedShellSessionTargetCache::reserve(&cache, (7, "primary".to_owned())).is_some(), + TypedShellSessionTargetCache::reserve( + &cache, + TypedShellTargetKey::new(7, "primary".to_owned()) + ) + .is_some(), "drop must release the seat" ); } @@ -172,11 +204,18 @@ mod tests { // `blocking_lock` panics on a runtime worker thread; the drop // release must reach the cache through the spin seat instead. let cache = new_cache(); - let seat = TypedShellSessionTargetCache::reserve(&cache, (7, "primary".to_owned())) - .expect("seat"); + let seat = TypedShellSessionTargetCache::reserve( + &cache, + TypedShellTargetKey::new(7, "primary".to_owned()), + ) + .expect("seat"); drop(seat); assert!( - TypedShellSessionTargetCache::reserve(&cache, (7, "primary".to_owned())).is_some(), + TypedShellSessionTargetCache::reserve( + &cache, + TypedShellTargetKey::new(7, "primary".to_owned()) + ) + .is_some(), "release inside a runtime must not panic or leak the seat" ); } @@ -186,14 +225,23 @@ mod tests { let cache = new_cache(); let mut guard = cache.blocking_lock(); assert!(guard.is_empty()); - guard.remember((7, "primary".to_owned()), "tools.host.d2b".to_owned()); + guard.remember( + TypedShellTargetKey::new(7, "primary".to_owned()), + "tools.host.d2b".to_owned(), + ); assert_eq!( - guard.cached(&(7, "primary".to_owned())).as_deref(), + guard + .cached(&TypedShellTargetKey::new(7, "primary".to_owned())) + .as_deref(), Some("tools.host.d2b") ); assert_eq!(guard.len(), 1); - guard.forget(&(7, "primary".to_owned())); - assert!(guard.cached(&(7, "primary".to_owned())).is_none()); + guard.forget(&TypedShellTargetKey::new(7, "primary".to_owned())); + assert!( + guard + .cached(&TypedShellTargetKey::new(7, "primary".to_owned())) + .is_none() + ); assert!(guard.is_empty()); } } diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index e5c2a3e1c..1f4be275f 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -12705,7 +12705,13 @@ fn remember_typed_shell_session_target( // is a tokio mutex in the converted d2bd-runtime); a collision skips the // cache update fail-closed - the caller's next list pass re-caches. if let Ok(mut sessions) = state.typed_shell_session_targets.try_lock() { - sessions.remember((peer_uid, name.as_str().to_owned()), target.to_owned()); + sessions.remember( + d2bd_runtime::typed_shell_targets::TypedShellTargetKey::new( + peer_uid, + name.as_str().to_owned(), + ), + target.to_owned(), + ); } } @@ -12715,7 +12721,10 @@ fn forget_typed_shell_session_target( name: &public_wire::ShellName, ) { if let Ok(mut sessions) = state.typed_shell_session_targets.try_lock() { - sessions.forget(&(peer_uid, name.as_str().to_owned())); + sessions.forget(&d2bd_runtime::typed_shell_targets::TypedShellTargetKey::new( + peer_uid, + name.as_str().to_owned(), + )); } } @@ -12738,10 +12747,16 @@ fn cache_unambiguous_typed_shell_session_targets( } if let Ok(mut sessions) = state.typed_shell_session_targets.try_lock() { for name in &conflicts { - sessions.forget(&(peer_uid, name.clone())); + sessions.forget(&d2bd_runtime::typed_shell_targets::TypedShellTargetKey::new( + peer_uid, + name.clone(), + )); } for (name, target) in unique { - sessions.remember((peer_uid, name), target); + sessions.remember( + d2bd_runtime::typed_shell_targets::TypedShellTargetKey::new(peer_uid, name), + target, + ); } } if let Some(workload_id) = conflicts.into_iter().next() { @@ -12785,7 +12800,12 @@ fn cached_typed_shell_session_target( .typed_shell_session_targets .try_lock() .ok() - .and_then(|mut sessions| sessions.cached(&(peer_uid, name.as_str().to_owned()))) + .and_then(|mut sessions| { + sessions.cached(&d2bd_runtime::typed_shell_targets::TypedShellTargetKey::new( + peer_uid, + name.as_str().to_owned(), + )) + }) } fn reserve_typed_shell_session_create( @@ -12793,7 +12813,10 @@ fn reserve_typed_shell_session_create( peer_uid: u32, name: &public_wire::ShellName, ) -> Result { - let key = (peer_uid, name.as_str().to_owned()); + let key = d2bd_runtime::typed_shell_targets::TypedShellTargetKey::new( + peer_uid, + name.as_str().to_owned(), + ); d2bd_runtime::typed_shell_targets::TypedShellSessionTargetCache::reserve( &state.typed_shell_session_targets, key, From 8cb61bb1694fb0cd24ab742b4836ff41c5d35874 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:36:15 -0700 Subject: [PATCH 237/726] d2bd-runtime: hide the cached public read-model frame type --- packages/d2bd-runtime/src/public_read_model.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/d2bd-runtime/src/public_read_model.rs b/packages/d2bd-runtime/src/public_read_model.rs index 98406b113..f3ffa7b08 100644 --- a/packages/d2bd-runtime/src/public_read_model.rs +++ b/packages/d2bd-runtime/src/public_read_model.rs @@ -48,9 +48,9 @@ pub struct FileFingerprint { } #[derive(Debug)] -pub struct CachedPublicFrame { - pub fingerprint: PublicArtifactFingerprint, - pub value: Value, +struct CachedPublicFrame { + fingerprint: PublicArtifactFingerprint, + value: Value, } #[derive(Debug)] From a0914043277ad235ab0532ff296e12c0f2a55fb5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:37:24 -0700 Subject: [PATCH 238/726] d2bd-runtime: type the version-file read failures --- packages/d2bd-runtime/src/daemon_version.rs | 91 +++++++++++++-------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/packages/d2bd-runtime/src/daemon_version.rs b/packages/d2bd-runtime/src/daemon_version.rs index 970afdf1f..7d9343d1d 100644 --- a/packages/d2bd-runtime/src/daemon_version.rs +++ b/packages/d2bd-runtime/src/daemon_version.rs @@ -71,18 +71,29 @@ pub enum DaemonRestartStatus { VersionFileUnreadable { detail: String }, } +/// Failure classifying one file-system read in the restart-status +/// computation. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum VersionFileReadError { + /// The file does not exist. + Missing, + /// The file exists but could not be read or parsed. + Unreadable(String), +} + /// File-system reads the [`compute_restart_status`] function needs. /// Production CLI: [`SystemFilesystemReader`]. Tests: an in-memory /// fake that maps the two paths to canned outcomes. pub trait FilesystemReader: Send + Sync { - /// Returns the parsed [`DaemonVersionFile`], `None` if absent, - /// or `Err(detail)` if present but unparseable. - fn read_version_file(&self) -> Result, String>; + /// Returns the parsed [`DaemonVersionFile`], + /// [`VersionFileReadError::Missing`] if absent, or + /// [`VersionFileReadError::Unreadable`] if present but unreadable. + fn read_version_file(&self) -> Result; /// Returns the canonicalized path the install-path symlink /// resolves to (`/run/current-system/sw/bin/d2bd` on - /// NixOS, the package install path on Tier-0). `None` if the - /// path does not exist. - fn read_on_disk_binary_path(&self) -> Result, String>; + /// NixOS, the package install path on Tier-0). + /// [`VersionFileReadError::Missing`] if the path does not exist. + fn read_on_disk_binary_path(&self) -> Result; } /// Production [`FilesystemReader`] backed by `/run/d2b/version` @@ -97,15 +108,18 @@ impl FilesystemReader for SystemFilesystemReader { clippy::disallowed_methods, reason = "synchronous path" )] - fn read_version_file(&self) -> Result, String> { + fn read_version_file(&self) -> Result { match std::fs::read_to_string(&self.version_file_path) { - Ok(content) => { - let parsed: DaemonVersionFile = serde_json::from_str(&content) - .map_err(|e| format!("parsing {}: {}", self.version_file_path, e))?; - Ok(Some(parsed)) + Ok(content) => serde_json::from_str(&content).map_err(|e| { + VersionFileReadError::Unreadable(format!( + "parsing {}: {}", + self.version_file_path, e + )) + }), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + Err(VersionFileReadError::Missing) } - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None), - Err(err) => Err(err.to_string()), + Err(err) => Err(VersionFileReadError::Unreadable(err.to_string())), } } @@ -113,11 +127,13 @@ impl FilesystemReader for SystemFilesystemReader { clippy::disallowed_methods, reason = "synchronous path" )] - fn read_on_disk_binary_path(&self) -> Result, String> { + fn read_on_disk_binary_path(&self) -> Result { match std::fs::canonicalize(&self.install_path) { - Ok(p) => Ok(Some(p.to_string_lossy().into_owned())), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None), - Err(err) => Err(err.to_string()), + Ok(p) => Ok(p.to_string_lossy().into_owned()), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + Err(VersionFileReadError::Missing) + } + Err(err) => Err(VersionFileReadError::Unreadable(err.to_string())), } } } @@ -127,16 +143,18 @@ impl FilesystemReader for SystemFilesystemReader { /// classified [`DaemonRestartStatus`]. pub fn compute_restart_status(reader: &dyn FilesystemReader) -> DaemonRestartStatus { let version = match reader.read_version_file() { - Ok(Some(v)) => v, - Ok(None) => return DaemonRestartStatus::DaemonNotRunning, - Err(detail) => return DaemonRestartStatus::VersionFileUnreadable { detail }, + Ok(v) => v, + Err(VersionFileReadError::Missing) => return DaemonRestartStatus::DaemonNotRunning, + Err(VersionFileReadError::Unreadable(detail)) => { + return DaemonRestartStatus::VersionFileUnreadable { detail } + } }; let on_disk = match reader.read_on_disk_binary_path() { - Ok(Some(p)) => p, + Ok(p) => p, // Install path missing OR an unrelated error → treat as // "no on-disk newer binary" rather than spurious pending- // restart; the daemon process is still authoritative. - _ => return DaemonRestartStatus::UpToDate, + Err(_) => return DaemonRestartStatus::UpToDate, }; if version.binary_path == on_disk { DaemonRestartStatus::UpToDate @@ -174,44 +192,45 @@ mod tests { #[derive(Default)] struct FakeFs { - version: Mutex, String>>>, - on_disk: Mutex, String>>>, + version: Mutex>>, + on_disk: Mutex>>, } impl FakeFs { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn with_version_running(path: &str) -> Self { let me = Self::default(); - *me.version.lock().unwrap() = Some(Ok(Some(DaemonVersionFile { + *me.version.lock().unwrap() = Some(Ok(DaemonVersionFile { server_version: "0.4.0".to_owned(), binary_path: path.to_owned(), started_at: "2026-05-29T03:00:00Z".to_owned(), protocol_version: 3, - }))); + })); me } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn with_on_disk(self, path: &str) -> Self { - *self.on_disk.lock().unwrap() = Some(Ok(Some(path.to_owned()))); + *self.on_disk.lock().unwrap() = Some(Ok(path.to_owned())); self } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn with_no_version_file(self) -> Self { - *self.version.lock().unwrap() = Some(Ok(None)); - *self.on_disk.lock().unwrap() = Some(Ok(Some("ignored".to_owned()))); + *self.version.lock().unwrap() = Some(Err(VersionFileReadError::Missing)); + *self.on_disk.lock().unwrap() = Some(Ok("ignored".to_owned())); self } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn with_unparseable_version(self) -> Self { - *self.version.lock().unwrap() = - Some(Err("parsing /run/d2b/version: expected JSON".to_owned())); + *self.version.lock().unwrap() = Some(Err(VersionFileReadError::Unreadable( + "parsing /run/d2b/version: expected JSON".to_owned(), + ))); self } } impl FilesystemReader for FakeFs { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - fn read_version_file(&self) -> Result, String> { + fn read_version_file(&self) -> Result { self.version .lock() .unwrap() @@ -219,8 +238,12 @@ mod tests { .expect("fake fs configured for version") } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - fn read_on_disk_binary_path(&self) -> Result, String> { - self.on_disk.lock().unwrap().clone().unwrap_or(Ok(None)) + fn read_on_disk_binary_path(&self) -> Result { + self.on_disk + .lock() + .unwrap() + .clone() + .unwrap_or(Err(VersionFileReadError::Missing)) } } From e10faa81fd26e14af1a753f759ab5e8c8dbd036e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:38:17 -0700 Subject: [PATCH 239/726] d2bd-runtime: deserialize the ch vm.info payload via a derived raw shape --- packages/d2bd-runtime/src/ch_api.rs | 71 +++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/packages/d2bd-runtime/src/ch_api.rs b/packages/d2bd-runtime/src/ch_api.rs index 63c9b078e..d92dda807 100644 --- a/packages/d2bd-runtime/src/ch_api.rs +++ b/packages/d2bd-runtime/src/ch_api.rs @@ -6,6 +6,7 @@ use std::os::unix::net::UnixStream as StdUnixStream; use std::path::Path; use std::time::Duration; +use serde::{Deserialize, Serialize}; use tokio::net::UnixStream; /// Default per-request timeout for Cloud Hypervisor HTTP control calls, @@ -107,24 +108,46 @@ pub fn blocking_get_json( split_http_body(&raw) } +/// Raw Cloud Hypervisor `vm.info` payload shape, deserialized at the +/// boundary; fields absent from the reply default to `None`. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +struct ChVmInfoRaw { + #[serde(default)] + state: Option, + #[serde(default)] + config: ChVmInfoRawConfig, +} + +/// Nested `config` object of the raw `vm.info` payload. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +struct ChVmInfoRawConfig { + #[serde(default)] + cpus: ChVmInfoRawCpus, + #[serde(default)] + memory: ChVmInfoRawMemory, +} + +/// Nested `config.cpus` object of the raw `vm.info` payload. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +struct ChVmInfoRawCpus { + #[serde(default)] + boot_vcpus: Option, +} + +/// Nested `config.memory` object of the raw `vm.info` payload. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +struct ChVmInfoRawMemory { + #[serde(default)] + size: Option, +} + pub fn parse_vm_info(body: &[u8]) -> Result { - let v: serde_json::Value = + let raw: ChVmInfoRaw = serde_json::from_slice(body).map_err(|err| ChApiError::InvalidJson(err.to_string()))?; - let state = v.get("state").and_then(|s| s.as_str()).map(str::to_owned); - let vcpu_count = v - .get("config") - .and_then(|c| c.get("cpus")) - .and_then(|c| c.get("boot_vcpus")) - .and_then(|n| n.as_u64()); - let memory_mib = v - .get("config") - .and_then(|c| c.get("memory")) - .and_then(|m| m.get("size")) - .and_then(|n| n.as_u64()); Ok(ChVmInfo { - state, - vcpu_count, - memory_mib, + state: raw.state, + vcpu_count: raw.config.cpus.boot_vcpus, + memory_mib: raw.config.memory.size, }) } @@ -289,4 +312,22 @@ mod tests { assert_eq!(info.state.as_deref(), Some(state)); } } + + #[test] + fn vm_info_raw_shape_round_trips_through_parse() { + let raw = ChVmInfoRaw { + state: Some("Running".to_owned()), + config: ChVmInfoRawConfig { + cpus: ChVmInfoRawCpus { + boot_vcpus: Some(2), + }, + memory: ChVmInfoRawMemory { size: Some(4096) }, + }, + }; + let body = serde_json::to_vec(&raw).expect("serialize vm.info shape"); + let info = parse_vm_info(&body).expect("parse vm.info"); + assert_eq!(info.state.as_deref(), Some("Running")); + assert_eq!(info.vcpu_count, Some(2)); + assert_eq!(info.memory_mib, Some(4096)); + } } From 225f36a3ad83c0af2e2831fd4cbb5e984e1e6f67 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:33:43 -0700 Subject: [PATCH 240/726] d2bd-runtime: gate exec session worker machinery test-only --- packages/d2bd-runtime/src/exec_session.rs | 35 ++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/d2bd-runtime/src/exec_session.rs b/packages/d2bd-runtime/src/exec_session.rs index 0b122c6ee..5f8912f64 100644 --- a/packages/d2bd-runtime/src/exec_session.rs +++ b/packages/d2bd-runtime/src/exec_session.rs @@ -25,6 +25,7 @@ use std::sync::{ atomic::AtomicU64, atomic::{AtomicBool, Ordering}, }; +#[cfg(test)] use std::thread::JoinHandle; use std::time::{Duration, Instant}; use std::{ @@ -35,14 +36,20 @@ use std::{ use async_trait::async_trait; use d2b_contracts_control::public_wire::{ - EXEC_MAX_CHUNK_BYTES, ExecCloseResult, ExecControlResult, ExecOp, ExecOpResponse, - ExecReadOutputResult, ExecStartResult, ExecStream, ExecTerminalStatus, ExecWaitResult, - ExecWriteStdinResult, NamedProcessStreamErrorKind, NamedProcessStreamRequest, + EXEC_MAX_CHUNK_BYTES, ExecOpResponse, ExecStartResult, ExecStream, ExecTerminalStatus, + NamedProcessStreamErrorKind, NamedProcessStreamRequest, NamedProcessStreamRequestFrame, NamedProcessStreamResponse, NamedProcessStreamResponseFrame, }; +#[cfg(test)] +use d2b_contracts_control::public_wire::{ + ExecCloseResult, ExecControlResult, ExecOp, ExecReadOutputResult, ExecWaitResult, + ExecWriteStdinResult, +}; use d2b_core::base64_codec; use d2b_session::{ComponentSessionDriver, StreamEvent, StreamId}; -use tokio::sync::{mpsc, oneshot}; +use tokio::sync::oneshot; +#[cfg(test)] +use tokio::sync::mpsc; use crate::terminal_session::{OutputStreamSel, TerminalBackend, TerminalKind}; use crate::terminal_session::{ReadOutputOutcome, WaitOutcome, WriteStdinOutcome}; @@ -152,6 +159,7 @@ impl ExecEstablishError { /// one-shot establishment budget is exhausted by the time the first op runs, /// so reusing it would immediately time out. #[derive(Debug, Clone, Copy)] +#[cfg(test)] pub struct ExecOpDeadlines { /// Fast control ops (`WriteStdin`, `Signal`, `Resize`, `Close`). pub control: Duration, @@ -164,6 +172,7 @@ pub struct ExecOpDeadlines { pub poll_slack: Duration, } +#[cfg(test)] impl Default for ExecOpDeadlines { fn default() -> Self { Self { @@ -811,12 +820,14 @@ pub trait ExecGuestConnector: Send + Sync { } /// One command shuttled from the owner connection to the session worker. +#[cfg(test)] pub struct WorkerCommand { pub op: ExecOp, pub reply: oneshot::Sender>, } /// Establish reply shuttled back to the owner before the op loop begins. +#[cfg(test)] pub type EstablishReply = Result; /// Owner-socket teardown seam for the terminal-cleanup reaper. @@ -824,13 +835,16 @@ pub type EstablishReply = Result; /// down the socket) so the session slot is released after the command has gone /// terminal and the cleanup TTL elapsed. It MUST be idempotent and MUST NOT be /// called while the command is still live. +#[cfg(test)] pub trait OwnerReaper: Send + Sync { fn reap(&self); } /// A no-op owner reaper for unit tests / callers that drive teardown directly. +#[cfg(test)] pub struct NoopReaper; +#[cfg(test)] impl OwnerReaper for NoopReaper { fn reap(&self) {} } @@ -840,12 +854,14 @@ impl OwnerReaper for NoopReaper { /// this long so it cannot pin a session slot indefinitely. Generous enough for /// a well-behaved CLI to read the terminal status and close first. The reaper /// never kills a LIVE command - cleanup only arms once `Wait` returns terminal. +#[cfg(test)] pub const EXEC_TERMINAL_CLEANUP_TTL: Duration = Duration::from_secs(10); /// Records when the guest command first went terminal and decides - against an /// injected [`Clock`] - whether the terminal-cleanup TTL has since elapsed. /// Pure and fake-clock testable; the worker arms a real timer that consults /// [`TerminalReaper::due`]. +#[cfg(test)] pub struct TerminalReaper { clock: Arc, ttl: Duration, @@ -855,6 +871,7 @@ pub struct TerminalReaper { terminal_at: tokio::sync::Mutex>, } +#[cfg(test)] impl TerminalReaper { pub fn new(clock: Arc, ttl: Duration) -> Self { Self { @@ -898,6 +915,7 @@ impl TerminalReaper { } /// Inputs to [`spawn_session_worker`]. +#[cfg(test)] pub struct WorkerSpawn { /// The authenticated guest channel factory the worker uses to establish. pub connector: Arc, @@ -927,6 +945,7 @@ pub struct WorkerSpawn { /// /// Returns an error when the OS thread cannot be spawned (thread exhaustion /// or resource limits), before any worker state is created. +#[cfg(test)] pub fn spawn_session_worker(spawn: WorkerSpawn) -> std::io::Result> { let WorkerSpawn { connector, @@ -968,6 +987,7 @@ pub fn spawn_session_worker(spawn: WorkerSpawn) -> std::io::Result, spec: ExecStartSpec, @@ -1063,6 +1083,7 @@ async fn worker_main( /// is still terminal (the owner never closed), reap the owner socket so the /// session slot is released. If the owner closes first the worker is torn down /// and this task is aborted with the runtime, so the reaper never fires. +#[cfg(test)] fn arm_terminal_reap(reaper: Arc, owner_reaper: Arc) { let ttl = reaper.ttl(); tokio::spawn(async move { @@ -1078,8 +1099,10 @@ fn arm_terminal_reap(reaper: Arc, owner_reaper: Arc, deadlines: ExecOpDeadlines, @@ -1094,6 +1117,7 @@ struct WorkerState { caps: NegotiatedCaps, } +#[cfg(test)] impl WorkerState { /// Return a cached control-op ack for a previously-served `opId`, if any. fn cached_control(&self, op_id: u64) -> Option { @@ -1119,6 +1143,7 @@ impl WorkerState { } } +#[cfg(test)] impl WorkerState { async fn handle_inline(&mut self, op: ExecOp) -> Result { match op { @@ -1234,6 +1259,7 @@ impl WorkerState { } } +#[cfg(test)] async fn run_long_poll( client: &dyn ExecGuestClient, op: ExecOp, @@ -1286,6 +1312,7 @@ async fn run_long_poll( } } +#[cfg(test)] fn map_terminal(kind: TerminalKind) -> ExecTerminalStatus { match kind { TerminalKind::Exited(code) => ExecTerminalStatus::Exited { code }, From 1ed0521fa3227ce136654b3168b0c8d43761d45b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:39:30 -0700 Subject: [PATCH 241/726] d2bd-runtime: drop unused vm parameter from CH console drainer --- packages/d2bd-runtime/src/console_session.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index 7f189bd24..06eb6c50a 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -348,7 +348,6 @@ pub struct ConsoleReadOutput { /// bytes into the ring, and reconnects if CH closes the connection (e.g. after /// a VM reboot). The ring's `notify` is triggered on each new chunk. pub fn spawn_ch_serial_drainer( - _vm: String, socket_path: String, ring: Arc>, ) -> tokio::task::JoinHandle<()> { @@ -428,7 +427,7 @@ pub fn spawn_fd_drainer( /// socket path. pub fn create_ch_session(socket_path: String) -> ConsoleSession { let ring = Arc::new(tokio::sync::Mutex::new(ConsoleRing::new())); - let drainer = spawn_ch_serial_drainer("ch-console".to_owned(), socket_path, Arc::clone(&ring)); + let drainer = spawn_ch_serial_drainer(socket_path, Arc::clone(&ring)); ConsoleSession::new( ConsoleProviderKind::LocalHypervisor, ring, From 97df1b826a37e062e8ade4a1c235cd1b42e476c1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:39:02 -0700 Subject: [PATCH 242/726] d2bd-runtime: report version-file write failures through tracing --- packages/d2bd-runtime/src/runtime_process.rs | 27 +++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/d2bd-runtime/src/runtime_process.rs b/packages/d2bd-runtime/src/runtime_process.rs index fec193416..19a4fc1f3 100644 --- a/packages/d2bd-runtime/src/runtime_process.rs +++ b/packages/d2bd-runtime/src/runtime_process.rs @@ -439,7 +439,7 @@ pub fn drop_privileges_if_root(identity: &RuntimeIdentity) -> Result<(), TypedEr /// listeners write beside their redirected public socket. /// This lets the CLI's `crate::daemon_version::compute_restart_status` compute the /// `[pending restart]` signal post-restart. Failures are logged -/// to stderr and non-fatal - the absence of the version file +/// via tracing and non-fatal - the absence of the version file /// surfaces in the CLI as `DaemonRestartStatus::DaemonNotRunning`, /// which is a reasonable degraded shape. #[allow(clippy::disallowed_methods, reason = "synchronous path")] @@ -447,7 +447,7 @@ pub fn write_daemon_version_file(config: &DaemonConfig) { let binary_path = match std::env::current_exe().and_then(std::fs::canonicalize) { Ok(p) => p.to_string_lossy().into_owned(), Err(err) => { - eprintln!("d2bd: could not canonicalize daemon binary path: {err}"); + tracing::warn!(error = %err, "d2bd: could not canonicalize daemon binary path"); return; } }; @@ -461,7 +461,7 @@ pub fn write_daemon_version_file(config: &DaemonConfig) { let json = match serde_json::to_vec_pretty(&payload) { Ok(v) => v, Err(err) => { - eprintln!("d2bd: could not serialize daemon version: {err}"); + tracing::warn!(error = %err, "d2bd: could not serialize daemon version"); return; } }; @@ -469,19 +469,28 @@ pub fn write_daemon_version_file(config: &DaemonConfig) { if let Some(parent) = path.parent() && let Err(err) = std::fs::create_dir_all(parent) { - eprintln!( - "d2bd: could not create {} for version file: {err}", - parent.display() + tracing::warn!( + error = %err, + path = %parent.display(), + "d2bd: could not create version-file parent directory" ); return; } let tmp = path.with_extension("version.tmp"); if let Err(err) = std::fs::write(&tmp, &json) { - eprintln!("d2bd: could not write {}: {err}", tmp.display()); + tracing::warn!( + error = %err, + path = %tmp.display(), + "d2bd: could not write version file" + ); return; } - if let Err(err) = std::fs::rename(&tmp, path) { - eprintln!("d2bd: could not rename version file into place: {err}"); + if let Err(err) = std::fs::rename(&tmp, &path) { + tracing::warn!( + error = %err, + path = %path.display(), + "d2bd: could not rename version file into place" + ); } } From 785aebb202f71f7ca4a396fc43ea3a9b8114e7b5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:39:46 -0700 Subject: [PATCH 243/726] d2bd-runtime: log qemu console fd conversion error as a field --- packages/d2bd-runtime/src/console_session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index 06eb6c50a..54f7d1778 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -455,7 +455,7 @@ pub fn create_qemu_session(std_stream: std::os::unix::net::UnixStream) -> Consol let stream = match tokio::net::UnixStream::from_std(std_stream) { Ok(s) => s, Err(e) => { - tracing::warn!("qemu console: failed to convert fd to tokio stream: {e}"); + tracing::warn!(error = %e, "qemu console: failed to convert fd to tokio stream"); let mut g = ring_clone.lock().await; g.ring.is_eof = true; g.notify.notify_waiters(); From b310cab7bdafa68156e88ee513f3083bbe3d25a2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:53:43 -0700 Subject: [PATCH 244/726] d2bd: parse shared-provider effect mode once into a typed enum --- packages/d2bd/src/shared_provider_effects.rs | 40 ++++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 68c23ff1f..def726380 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -84,6 +84,35 @@ enum SharedProviderKind { GpuDevice, } +/// The admission mode one shared-provider effect request carries on its +/// spec (`/mode`). The wire spelling is kebab-case; an unknown or misspelled +/// mode is refused at the effect boundary rather than silently taking the +/// non-authority / non-projection branch. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub(crate) enum SharedProviderEffectMode { + /// The authority admission posture. + Authority, + /// The projection admission posture. + Projection, +} + +impl SharedProviderEffectMode { + /// Parse the mode from the request spec, refusing unknown spellings. + fn parse(request: &SharedProviderEffectRequest<'_>) -> Result { + let mode = request + .spec + .pointer("/mode") + .and_then(Value::as_str) + .ok_or(SharedProviderEffectError::InvalidResource)?; + match mode { + "authority" => Ok(Self::Authority), + "projection" => Ok(Self::Projection), + _ => Err(SharedProviderEffectError::InvalidResource), + } + } +} + impl SharedProviderKind { /// The Provider reference the row's spec must name. const fn provider_ref(self) -> &'static str { @@ -1313,7 +1342,8 @@ impl ProductionSharedProviderEffects { Arc::clone(&self.usbip_ledger), ) .into_port(); - let opted_in = request.spec.pointer("/mode").and_then(Value::as_str) == Some("authority"); + let mode = SharedProviderEffectMode::parse(request)?; + let opted_in = mode == SharedProviderEffectMode::Authority; Ok((zone_uid, opted_in, port)) } } @@ -1918,12 +1948,8 @@ impl ProductionSharedProviderEffects { match component { SecurityKeyComponent::Service => { let runtime = self.runtime()?; - let mode = request - .spec - .pointer("/mode") - .and_then(Value::as_str) - .ok_or(SharedProviderEffectError::InvalidResource)?; - if mode == "projection" { + let mode = SharedProviderEffectMode::parse(request)?; + if mode == SharedProviderEffectMode::Projection { let endpoint_ref = request .status .as_ref() From ee8678e464ae9f8a04d0c14fa9d6fd2487c3c26a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:54:16 -0700 Subject: [PATCH 245/726] broker: narrow gpu and modprobe op surfaces to crate visibility --- packages/d2b-broker/src/ops/gpu.rs | 38 ++++++++++++------------- packages/d2b-broker/src/ops/modprobe.rs | 14 ++++----- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/d2b-broker/src/ops/gpu.rs b/packages/d2b-broker/src/ops/gpu.rs index a63780f26..6b8f1dbfb 100644 --- a/packages/d2b-broker/src/ops/gpu.rs +++ b/packages/d2b-broker/src/ops/gpu.rs @@ -10,7 +10,7 @@ use super::spawn_runner::SpawnRunnerPlan; /// Closed GPU worker roles. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum GpuBrokerRole { +pub(crate) enum GpuBrokerRole { /// Full virtio-gpu worker. Full, /// Render-node-only worker. @@ -21,7 +21,7 @@ pub enum GpuBrokerRole { /// Closed GPU device grant classes. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum GpuDeviceClass { +pub(crate) enum GpuDeviceClass { /// KVM device. Kvm, /// DRM render node. @@ -38,16 +38,16 @@ pub enum GpuDeviceClass { /// Opaque broker-side identity. #[derive(Clone, Copy, PartialEq, Eq)] -pub struct GpuOpaqueIdentity([u8; 32]); +pub(crate) struct GpuOpaqueIdentity([u8; 32]); impl GpuOpaqueIdentity { /// Construct an identity at the trusted bundle/adapter boundary. - pub const fn from_core(bytes: [u8; 32]) -> Self { + pub(crate) const fn from_core(bytes: [u8; 32]) -> Self { Self(bytes) } /// Whether this is the forbidden all-zero identity. - pub fn is_zero(self) -> bool { + pub(crate) fn is_zero(self) -> bool { self.0 == [0; 32] } } @@ -60,7 +60,7 @@ impl fmt::Debug for GpuOpaqueIdentity { /// Opaque GPU launch request validated before a device open or clone. #[derive(Clone, PartialEq, Eq)] -pub struct GpuLaunchRequest { +pub(crate) struct GpuLaunchRequest { role: GpuBrokerRole, backing: GpuOpaqueIdentity, platform: GpuOpaqueIdentity, @@ -71,7 +71,7 @@ pub struct GpuLaunchRequest { impl GpuLaunchRequest { /// Construct a request from Core-resolved opaque identities. - pub fn from_core( + pub(crate) fn from_core( role: GpuBrokerRole, backing: GpuOpaqueIdentity, platform: GpuOpaqueIdentity, @@ -95,7 +95,7 @@ impl GpuLaunchRequest { } /// Validate the closed role-to-device matrix. - pub fn validate(&self) -> Result<(), GpuBrokerError> { + pub(crate) fn validate(&self) -> Result<(), GpuBrokerError> { let has = |class| self.device_classes.contains(&class); match self.role { GpuBrokerRole::Full @@ -136,27 +136,27 @@ impl GpuLaunchRequest { } /// Borrow the opaque backing identity. - pub const fn backing(&self) -> GpuOpaqueIdentity { + pub(crate) const fn backing(&self) -> GpuOpaqueIdentity { self.backing } /// Borrow the opaque platform identity. - pub const fn platform(&self) -> GpuOpaqueIdentity { + pub(crate) const fn platform(&self) -> GpuOpaqueIdentity { self.platform } /// Borrow the expected worker principal. - pub const fn principal(&self) -> GpuOpaqueIdentity { + pub(crate) const fn principal(&self) -> GpuOpaqueIdentity { self.principal } /// Return the expected resource generation. - pub const fn generation(&self) -> u64 { + pub(crate) const fn generation(&self) -> u64 { self.generation } /// Return the worker role. - pub const fn role(&self) -> GpuBrokerRole { + pub(crate) const fn role(&self) -> GpuBrokerRole { self.role } } @@ -174,7 +174,7 @@ impl fmt::Debug for GpuLaunchRequest { /// Broker-side process observation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum GpuProcessObservation { +pub(crate) enum GpuProcessObservation { /// One exact process matched. Matching, /// No exact process was found. @@ -187,7 +187,7 @@ pub enum GpuProcessObservation { /// Closed GPU broker failures. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum GpuBrokerError { +pub(crate) enum GpuBrokerError { /// A persisted identity is missing or stale. StaleIdentity, /// The role and device allowlist disagree. @@ -206,7 +206,7 @@ pub enum GpuBrokerError { impl GpuBrokerError { /// Return the stable identity-free error code. - pub const fn code(self) -> &'static str { + pub(crate) const fn code(self) -> &'static str { match self { Self::StaleIdentity => "gpu-device-identity-stale", Self::RoleDeviceMismatch => "gpu-role-device-mismatch", @@ -228,7 +228,7 @@ impl fmt::Display for GpuBrokerError { impl std::error::Error for GpuBrokerError {} /// Validate identity evidence before adopting a worker. -pub fn validate_observed_identity( +pub(crate) fn validate_observed_identity( request: &GpuLaunchRequest, observed_principal: GpuOpaqueIdentity, observed_platform: GpuOpaqueIdentity, @@ -260,7 +260,7 @@ pub fn validate_observed_identity( /// Validate a resolved SpawnRunner plan against the closed GPU isolation /// profile before the broker opens devices or clones a child. -pub fn validate_spawn_plan( +pub(crate) fn validate_spawn_plan( plan: &SpawnRunnerPlan, pre_opened_device_fds: usize, ) -> Result<(), GpuBrokerError> { @@ -268,7 +268,7 @@ pub fn validate_spawn_plan( } /// Validate a GPU runner shape before the broker opens any device. -pub fn validate_spawn_plan_preflight(plan: &SpawnRunnerPlan) -> Result<(), GpuBrokerError> { +pub(crate) fn validate_spawn_plan_preflight(plan: &SpawnRunnerPlan) -> Result<(), GpuBrokerError> { validate_spawn_plan_shape(plan, None) } diff --git a/packages/d2b-broker/src/ops/modprobe.rs b/packages/d2b-broker/src/ops/modprobe.rs index 0686e3638..66c1e63ca 100644 --- a/packages/d2b-broker/src/ops/modprobe.rs +++ b/packages/d2b-broker/src/ops/modprobe.rs @@ -29,7 +29,7 @@ use crate::ops::exec_reconcile::SystemLiveExec; /// Audit fields emitted by every decision. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ModprobeAuditRecord { +pub(crate) struct ModprobeAuditRecord { pub module_name: String, pub matrix_entry_id: String, pub modules_disabled_sysctl: bool, @@ -39,7 +39,7 @@ pub struct ModprobeAuditRecord { /// Possible decisions for the dispatcher. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] -pub enum ModprobeDecision { +pub(crate) enum ModprobeDecision { /// Module is already loaded; no-op success. AlreadyLoaded, /// Module is compiled-in; no-op success. @@ -58,13 +58,13 @@ pub enum ModprobeDecision { /// Trusted-bundle row controlling whether a module can be loaded. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct AllowlistRow { +pub(crate) struct AllowlistRow { pub entry: KernelModuleEntry, pub load_allowed: bool, } /// Backend trait so the L1c canary can swap a fake `modprobe`. -pub trait ModprobeBackend { +pub(crate) trait ModprobeBackend { fn load<'a>( &'a mut self, module: &'a str, @@ -73,7 +73,7 @@ pub trait ModprobeBackend { /// Fake backend used by `tests/kernel-module-matrix.sh`. #[derive(Debug, Default)] -pub struct RecordingBackend { +pub(crate) struct RecordingBackend { pub loaded: Vec, pub fail_on: Vec, } @@ -96,7 +96,7 @@ impl ModprobeBackend for RecordingBackend { /// Dispatcher entry point. The four-step probe is run via the typed /// `d2b_host::modules` helpers; this function only resolves the /// matrix row and audit record. -pub async fn dispatch( +pub(crate) async fn dispatch( requested: &str, allowlist: &[AllowlistRow], inputs: &ProbeInputs, @@ -162,7 +162,7 @@ impl ModprobeBackend for LiveBackend<'_> { } } -pub async fn live_modprobe_if_allowed( +pub(crate) async fn live_modprobe_if_allowed( exec: &SystemLiveExec, resolver: &BundleResolver, req: &ModprobeIfAllowedRequest, From d10ee144f9be9d71dc45b10988e2f52be6c2b1a6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:55:55 -0700 Subject: [PATCH 246/726] broker: demote dead sysctl apply surface to crate visibility --- packages/d2b-broker/src/ops/sysctl.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/d2b-broker/src/ops/sysctl.rs b/packages/d2b-broker/src/ops/sysctl.rs index 803b40322..6090bbaf5 100644 --- a/packages/d2b-broker/src/ops/sysctl.rs +++ b/packages/d2b-broker/src/ops/sysctl.rs @@ -13,22 +13,12 @@ use std::path::{Path, PathBuf}; use std::pin::Pin; #[derive(Debug, Clone)] -pub struct ApplySysctlRequest { +pub(crate) struct ApplySysctlRequest { pub intents: Vec, /// Override the `/proc/sys` root for tests. pub proc_sys_root: PathBuf, } -impl ApplySysctlRequest { - /// Build a request writing under the default `/proc/sys` root. - pub fn with_default_root(intents: Vec) -> Self { - Self { - intents, - proc_sys_root: PathBuf::from("/proc/sys"), - } - } -} - /// One applied sysctl write with its before/after values and drift verdict. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ApplySysctlOutcome { @@ -77,7 +67,7 @@ impl From for ApplySysctlError { /// Converts `net.ipv6.conf..disable_ipv6` to /// `/net/ipv6/conf//disable_ipv6` for safe per-link /// writes. -pub fn intent_to_proc_path(root: &Path, intent: &SysctlIntent) -> PathBuf { +pub(crate) fn intent_to_proc_path(root: &Path, intent: &SysctlIntent) -> PathBuf { let mut path = root.to_path_buf(); for component in intent.key.split('.') { path.push(component); @@ -85,7 +75,7 @@ pub fn intent_to_proc_path(root: &Path, intent: &SysctlIntent) -> PathBuf { path } -pub async fn apply_sysctl_intents( +pub(crate) async fn apply_sysctl_intents( req: &ApplySysctlRequest, ) -> Result, ApplySysctlError> { let mut out = Vec::with_capacity(req.intents.len()); From bc367bab90581934d480158cc0fe3c4910238e7a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:56:50 -0700 Subject: [PATCH 247/726] broker: make route conflict key crate-private --- packages/d2b-broker/src/ops/route.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/d2b-broker/src/ops/route.rs b/packages/d2b-broker/src/ops/route.rs index 5dc9a5bf1..28adc6481 100644 --- a/packages/d2b-broker/src/ops/route.rs +++ b/packages/d2b-broker/src/ops/route.rs @@ -16,13 +16,13 @@ use std::path::Path; use std::process::Stdio; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RouteConflictKey { - pub destination: String, - pub via: Option, - pub device: Option, - pub metric: Option, - pub protocol: Option, - pub table: String, +struct RouteConflictKey { + destination: String, + via: Option, + device: Option, + metric: Option, + protocol: Option, + table: String, } /// A preflight-refused route apply: the route-query step failed From 26d5c1119764e389d79cadce061431e3325005f2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:57:46 -0700 Subject: [PATCH 248/726] d2bd-runtime: make console ring and session fields private --- packages/d2bd-runtime/src/console_session.rs | 141 +++++++++++-------- 1 file changed, 83 insertions(+), 58 deletions(-) diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index 54f7d1778..0d41abb4e 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -52,10 +52,10 @@ const RING_CAPACITY: usize = 256 * 1024; /// Shared ring buffer state for one VM's console stream. #[derive(Debug)] pub struct ConsoleRing { - pub ring: RingBuffer, + ring: RingBuffer, /// Notified whenever new bytes are pushed or EOF is set, so waiters /// can wake without polling. - pub notify: Arc, + notify: Arc, } impl ConsoleRing { @@ -65,6 +65,33 @@ impl ConsoleRing { notify: Arc::new(tokio::sync::Notify::new()), } } + + /// Push bytes into the ring and wake any waiters. + pub fn push_bytes(&mut self, bytes: &[u8]) { + self.ring.push_bytes(bytes); + self.notify.notify_waiters(); + } + + /// Mark the console stream as ended and wake any waiters. + pub fn set_eof(&mut self) { + self.ring.is_eof = true; + self.notify.notify_waiters(); + } + + /// Read up to `max_len` bytes from `offset`. + pub fn read_at(&self, offset: u64, max_len: u64) -> Option { + self.ring.read_at(offset, max_len) + } + + /// The ring's base offset (start of retained data). + pub fn base_offset(&self) -> u64 { + self.ring.base_offset() + } + + /// The wake handle waiters park on. + pub fn notify(&self) -> &Arc { + &self.notify + } } impl Default for ConsoleRing { @@ -76,13 +103,13 @@ impl Default for ConsoleRing { /// Per-VM console session. #[derive(Debug)] pub struct ConsoleSession { - pub provider_kind: ConsoleProviderKind, - pub ring: Arc>, + provider_kind: ConsoleProviderKind, + ring: Arc>, /// Handle for the drainer task; Some while the drainer is running. - pub drainer: Option>, + drainer: Option>, /// Optional stdin fd/sink for writing to the console (None for /// read-only backends like provider-relay). - pub stdin_tx: Option>>, + stdin_tx: Option>>, } impl ConsoleSession { @@ -99,6 +126,29 @@ impl ConsoleSession { stdin_tx, } } + + /// The console provider backend for this session. + pub fn provider_kind(&self) -> ConsoleProviderKind { + self.provider_kind + } + + /// Shared ring buffer for this session's console output. + pub fn ring(&self) -> &Arc> { + &self.ring + } + + /// Stdin sink for writing to the console, when the backend accepts + /// writes (`None` for read-only backends). + pub fn stdin_tx(&self) -> Option<&tokio::sync::mpsc::Sender>> { + self.stdin_tx.as_ref() + } + + /// Abort the drainer task, if one is running. + pub fn abort_drainer(&mut self) { + if let Some(task) = self.drainer.take() { + task.abort(); + } + } } /// Opaque per-client session token (UUID string). @@ -179,10 +229,8 @@ impl ConsoleSessionTable { /// drainer. Replaces any existing session (e.g. after a VM restart). pub fn register_session(&mut self, vm: String, session: ConsoleSession) { // Abort any previous drainer for this VM. - if let Some(old) = self.sessions.remove(&vm) { - if let Some(task) = old.drainer { - task.abort(); - } + if let Some(mut old) = self.sessions.remove(&vm) { + old.abort_drainer(); // Remove all client handles for the old session. let to_remove: Vec = self .clients @@ -200,12 +248,10 @@ impl ConsoleSessionTable { /// Remove a VM console session and abort its long-lived drainer task. pub fn remove_session(&mut self, vm: &str) -> bool { - let Some(old) = self.sessions.remove(vm) else { + let Some(mut old) = self.sessions.remove(vm) else { return false; }; - if let Some(task) = old.drainer { - task.abort(); - } + old.abort_drainer(); let to_remove: Vec = self .clients .iter() @@ -242,15 +288,15 @@ impl ConsoleSessionTable { // only for sub-microsecond push/read critical sections, so a // collision is a fail-closed `None` (U4's sync-consumer pattern), // never a parked caller. - let Ok(guard) = session.ring.try_lock() else { + let Ok(guard) = session.ring().try_lock() else { return Ok(None); }; - guard.ring.base_offset() + guard.base_offset() }; let handle = ConsoleClientHandle::new()?; self.clients.insert(handle.clone(), vm.to_owned()); self.client_uids.insert(handle.clone(), peer_uid); - Ok(Some((handle, session.provider_kind, start_offset))) + Ok(Some((handle, session.provider_kind(), start_offset))) } /// Return the owner UID for a client handle, or `None` if the handle is @@ -278,16 +324,16 @@ impl ConsoleSessionTable { .get(session_handle)?; let session = self.sessions.get(vm)?; let (result, notify) = { - let Ok(guard) = session.ring.try_lock() else { + let Ok(guard) = session.ring().try_lock() else { return None; }; - let snap = guard.ring.read_at(offset, max_len); - let notify = Arc::clone(&guard.notify); + let snap = guard.read_at(offset, max_len); + let notify = Arc::clone(guard.notify()); (snap, notify) }; Some(ConsoleReadOutput { vm: vm.clone(), - provider_kind: session.provider_kind, + provider_kind: session.provider_kind(), snap: result, notify, }) @@ -302,7 +348,7 @@ impl ConsoleSessionTable { .clients .get(session_handle)?; let session = self.sessions.get(vm)?; - let Some(ref tx) = session.stdin_tx else { + let Some(tx) = session.stdin_tx() else { return Some(false); }; // Non-blocking send: drop on full rather than blocking the daemon. @@ -327,10 +373,10 @@ impl ConsoleSessionTable { .clients .get(session_handle)?; let session = self.sessions.get(vm)?; - let Ok(guard) = session.ring.try_lock() else { + let Ok(guard) = session.ring().try_lock() else { return None; }; - Some(Arc::clone(&guard.notify)) + Some(Arc::clone(guard.notify())) } } @@ -366,12 +412,8 @@ pub fn spawn_ch_serial_drainer( match stream.read(&mut buf).await { Ok(0) | Err(_) => break, Ok(n) => { - let notify = { - let mut guard = ring.lock().await; - guard.ring.push_bytes(&buf[..n]); - Arc::clone(&guard.notify) - }; - notify.notify_waiters(); + let mut guard = ring.lock().await; + guard.push_bytes(&buf[..n]); } } } @@ -401,22 +443,14 @@ pub fn spawn_fd_drainer( loop { match stream.read(&mut buf).await { Ok(0) | Err(_) => { - let notify = { - let mut guard = ring.lock().await; - guard.ring.is_eof = true; - Arc::clone(&guard.notify) - }; - notify.notify_waiters(); + let mut guard = ring.lock().await; + guard.set_eof(); tracing::debug!(vm = %vm, "console fd drainer reached EOF"); break; } Ok(n) => { - let notify = { - let mut guard = ring.lock().await; - guard.ring.push_bytes(&buf[..n]); - Arc::clone(&guard.notify) - }; - notify.notify_waiters(); + let mut guard = ring.lock().await; + guard.push_bytes(&buf[..n]); } } } @@ -457,8 +491,7 @@ pub fn create_qemu_session(std_stream: std::os::unix::net::UnixStream) -> Consol Err(e) => { tracing::warn!(error = %e, "qemu console: failed to convert fd to tokio stream"); let mut g = ring_clone.lock().await; - g.ring.is_eof = true; - g.notify.notify_waiters(); + g.set_eof(); return; } }; @@ -476,21 +509,13 @@ pub fn create_qemu_session(std_stream: std::os::unix::net::UnixStream) -> Consol loop { match reader.read(&mut buf).await { Ok(0) | Err(_) => { - let notify = { - let mut g = ring_write.lock().await; - g.ring.is_eof = true; - Arc::clone(&g.notify) - }; - notify.notify_waiters(); + let mut g = ring_write.lock().await; + g.set_eof(); break; } Ok(n) => { - let notify = { - let mut g = ring_write.lock().await; - g.ring.push_bytes(&buf[..n]); - Arc::clone(&g.notify) - }; - notify.notify_waiters(); + let mut g = ring_write.lock().await; + g.push_bytes(&buf[..n]); } } } @@ -604,7 +629,7 @@ mod tests { let ring = Arc::new(tokio::sync::Mutex::new(ConsoleRing::new())); { let mut g = ring.blocking_lock(); - g.ring.push_bytes(b"hello console"); + g.push_bytes(b"hello console"); } let session = ConsoleSession::new( ConsoleProviderKind::LocalHypervisor, @@ -658,7 +683,7 @@ mod tests { { let mut g = ring.blocking_lock(); for _ in 0..300 { - g.ring.push_bytes(&[b'X'; 1024]); + g.push_bytes(&[b'X'; 1024]); } } let out = table.read_output(handle.as_str(), 0, 64).unwrap(); From 068ddcfc4cd285f48d1e908574a19982689c3852 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:58:03 -0700 Subject: [PATCH 249/726] broker: return cgroup slice path by reference --- packages/d2b-broker/src/ops/cgroup.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/d2b-broker/src/ops/cgroup.rs b/packages/d2b-broker/src/ops/cgroup.rs index e8bbe0bf8..9159b91ee 100644 --- a/packages/d2b-broker/src/ops/cgroup.rs +++ b/packages/d2b-broker/src/ops/cgroup.rs @@ -124,8 +124,8 @@ pub struct CgroupBundleContext { } impl CgroupBundleContext { - pub fn slice_path(&self) -> PathBuf { - self.parent_slice.clone() + pub fn slice_path(&self) -> &Path { + &self.parent_slice } /// v1.1.1 per-VM-interior + per-role-leaf taxonomy per ADR 0011 @@ -246,7 +246,7 @@ where let root = context.unified_hierarchy_root.as_path(); let mut fields = AuditFields { - slice_path: Some(context.slice_path()), + slice_path: Some(context.slice_path().to_path_buf()), controllers_enabled: Vec::new(), owner_uid: Some(context.d2bd_uid), ..AuditFields::default() @@ -320,7 +320,7 @@ where // maps that to a canonical path under d2b.slice. let (canonical_path, class) = if requested_subject == D2B_SLICE_NAME || requested_subject == "d2b-slice" { - (context.slice_path(), PathClass::D2bSlice) + (context.slice_path().to_path_buf(), PathClass::D2bSlice) } else if context.knows_vm(requested_subject) { (context.vm_leaf_path(requested_subject), PathClass::VmLeaf) } else { @@ -340,7 +340,7 @@ where fields.path_class = Some(class); fields.cgroup_id = Some(canonical_path.display().to_string()); - if !is_under_slice(&canonical_path, &context.slice_path()) { + if !is_under_slice(&canonical_path, context.slice_path()) { audit.record( "OpenCgroupDir", AuditDecision::DeniedRefused, @@ -818,7 +818,7 @@ mod tests { let ctx = context(&["alpha"]); let audit = RecordingAuditSink::default(); handle_delegate_cgroup_v2(&b, &ctx, &audit).unwrap(); - host_cgroup::create_vm_subtree(&b, &ctx.slice_path(), "alpha", ctx.d2bd_uid, ctx.d2bd_gid) + host_cgroup::create_vm_subtree(&b, ctx.slice_path(), "alpha", ctx.d2bd_uid, ctx.d2bd_gid) .unwrap(); let outcome = handle_open_cgroup_dir(&b, &ctx, "alpha", &audit).unwrap(); assert_eq!(outcome.path_class, PathClass::VmLeaf); From d0f8b5918e0f105e4394fc90b4ba506c5c6440ae Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:58:19 -0700 Subject: [PATCH 250/726] d2bd: store shutdown outcome enum in degraded marker and honor lifecycle force The degraded shutdown marker now carries the typed VmShutdownOutcome instead of label strings, so the report shape cannot drift from the enum. Guest lifecycle apply() now honors the force flag by skipping the graceful readiness wait, so the wire-parsed force field is no longer ignored. --- packages/d2bd/src/composition.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index e5c2a3e1c..de47a8b66 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -16152,7 +16152,8 @@ struct VmStopRoleReport { shutdown_outcome: Option, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] enum VmShutdownOutcome { CleanGuestShutdown, CleanVmmCleanup, @@ -16175,7 +16176,7 @@ struct ShutdownDegradedReport { #[serde(rename_all = "camelCase")] struct ShutdownDegradedMarker { vm: String, - outcome: String, + outcome: VmShutdownOutcome, severity: String, remediation: String, elapsed_ms: u64, @@ -16384,7 +16385,7 @@ fn persist_vm_shutdown_marker( if let Some(severity) = outcome.degraded_severity() { report.markers.push(ShutdownDegradedMarker { vm: vm.to_owned(), - outcome: outcome.label().to_owned(), + outcome, severity: severity.to_owned(), remediation: outcome.remediation().replace("", vm), elapsed_ms: elapsed.as_millis() as u64, @@ -18680,7 +18681,6 @@ impl provider_effects::ProviderLifecycleEffectPort for DaemonGuestLifecycleEffec self.operation, &self.caller_role, )?; - let _ = self.force; drive_sync(&self.state.runtime_handle, self.runtime.apply_cloud_hypervisor_lifecycle( Arc::new(self.state.clone()), &self.guest, @@ -18689,7 +18689,7 @@ impl provider_effects::ProviderLifecycleEffectPort for DaemonGuestLifecycleEffec self.operation, )) .map_err(|_| provider_effects::ProviderEffectError::EffectRejected)?; - if self.wait_for_ready { + if self.wait_for_ready && !self.force { drive_sync(&self.state.runtime_handle, self.runtime.wait_cloud_hypervisor_lifecycle( Arc::new(self.state.clone()), &self.guest, From e8d9c370f3f90b448485c7b839528ce01d20e6a5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:58:55 -0700 Subject: [PATCH 251/726] broker: take kernel config by value in kernel table --- packages/d2b-broker/src/kernel_ops.rs | 4 ++-- packages/d2b-broker/src/runtime.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/d2b-broker/src/kernel_ops.rs b/packages/d2b-broker/src/kernel_ops.rs index 324589bc8..b5358531e 100644 --- a/packages/d2b-broker/src/kernel_ops.rs +++ b/packages/d2b-broker/src/kernel_ops.rs @@ -96,8 +96,8 @@ pub struct KernelConfig { /// Every kernel is registered under its committed broker-generic row name; /// the mixed [`KernelDispatcher`](crate::envelope::KernelDispatcher) routes /// exactly those names to this table and forwards every other operation. -pub fn kernel_table(config: &KernelConfig) -> HandlerTable { - let config = Arc::new(config.clone()); +pub fn kernel_table(config: KernelConfig) -> HandlerTable { + let config = Arc::new(config); HandlerTable::new() .with(OPEN_PIDFD, { let config = Arc::clone(&config); diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 556f4cf26..ed4b942e6 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -7140,7 +7140,7 @@ fn install_live_operation_envelope( // than being served by a process that does not declare it. None => crate::envelope::ForwardingDispatcher::default(), }; - let kernels = crate::kernel_ops::kernel_table(&crate::kernel_ops::KernelConfig { + let kernels = crate::kernel_ops::kernel_table(crate::kernel_ops::KernelConfig { state_dir: config.state_dir.clone(), runtime_root: config .socket_path @@ -14484,7 +14484,7 @@ mod tests { config.audit_retention_days, ) .expect("open capturing audit log"); - let kernels = kernel_table(&KernelConfig { + let kernels = kernel_table(KernelConfig { state_dir: config.state_dir.clone(), runtime_root: root.join("runtime"), daemon_uid: config.d2bd_uid, @@ -14797,7 +14797,7 @@ mod tests { config.audit_retention_days, ) .expect("open capturing audit log"); - let kernels = kernel_table(&KernelConfig { + let kernels = kernel_table(KernelConfig { state_dir: config.state_dir.clone(), runtime_root: root.join("runtime"), daemon_uid: config.d2bd_uid, @@ -15226,7 +15226,7 @@ mod tests { config.audit_retention_days, ) .expect("open capturing audit log"); - let kernels = kernel_table(&KernelConfig { + let kernels = kernel_table(KernelConfig { state_dir: config.state_dir.clone(), runtime_root: root.join("runtime"), daemon_uid: config.d2bd_uid, @@ -15544,7 +15544,7 @@ mod tests { config.audit_retention_days, ) .expect("open capturing audit log"); - let kernels = kernel_table(&KernelConfig { + let kernels = kernel_table(KernelConfig { state_dir: config.state_dir.clone(), runtime_root: runtime_root.to_path_buf(), daemon_uid: config.d2bd_uid, @@ -17640,7 +17640,7 @@ mod tests { config.audit_retention_days, ) .expect("open capturing audit log"); - let kernels = kernel_table(&KernelConfig { + let kernels = kernel_table(KernelConfig { state_dir: config.state_dir.clone(), runtime_root: root.join("runtime"), daemon_uid: config.d2bd_uid, From c9addc3aa15302b2d525c48b64b0829d55c835c0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:59:13 -0700 Subject: [PATCH 252/726] d2bd-runtime: carry io::ErrorKind in transport failure variants --- .../src/component_session_vsock.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/d2bd-runtime/src/component_session_vsock.rs b/packages/d2bd-runtime/src/component_session_vsock.rs index 6c8ff3176..4705ac8e6 100644 --- a/packages/d2bd-runtime/src/component_session_vsock.rs +++ b/packages/d2bd-runtime/src/component_session_vsock.rs @@ -29,11 +29,11 @@ pub enum ComponentSessionTransportFailure { SocketNotUnixSocket, SocketHardLinked, UnsafeDirectory, - PeerCredentialIo { kind: String }, + PeerCredentialIo { kind: ErrorKind }, PeerCredentialMismatch, - ConnectIo { kind: String }, - WriteIo { kind: String }, - AckIo { kind: String }, + ConnectIo { kind: ErrorKind }, + WriteIo { kind: ErrorKind }, + AckIo { kind: ErrorKind }, AckTimeout, AckEof, AckTooLong, @@ -147,7 +147,7 @@ fn connect_component_session_vsock_inner( let deadline = Instant::now() + setup_timeout; let mut socket = connect_unix_socket_with_timeout(socket_path, remaining_setup_time(deadline)?) .map_err(|error| ComponentSessionTransportFailure::ConnectIo { - kind: error.kind().to_string(), + kind: error.kind(), })?; validate_peer_credentials(&socket, peer_policy)?; let remaining = remaining_setup_time(deadline)?; @@ -195,7 +195,7 @@ fn validate_peer_credentials( ) -> Result<(), ComponentSessionTransportFailure> { let peer = getsockopt(socket, PeerCredentials).map_err(|error| { ComponentSessionTransportFailure::PeerCredentialIo { - kind: error.to_string(), + kind: std::io::Error::from(error).kind(), } })?; let (expected_uid, expected_gid) = match peer_policy { @@ -378,7 +378,7 @@ fn read_connect_ack( Err(error) if error.kind() == ErrorKind::Interrupted => continue, Err(error) => { return Err(ComponentSessionTransportFailure::AckIo { - kind: error.kind().to_string(), + kind: error.kind(), }); } } @@ -405,9 +405,9 @@ fn remaining_setup_time(deadline: Instant) -> Result(constructor: F) -> impl FnOnce(std::io::Error) -> ComponentSessionTransportFailure where - F: FnOnce(String) -> ComponentSessionTransportFailure, + F: FnOnce(ErrorKind) -> ComponentSessionTransportFailure, { - move |error| constructor(error.kind().to_string()) + move |error| constructor(error.kind()) } #[cfg(test)] From 8589377baf86162029f5a6c21ed85d50ec836b04 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 08:59:28 -0700 Subject: [PATCH 253/726] d2bd: log interaction handler join errors and guard the admission slot --- packages/d2bd/src/interaction_composition.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/d2bd/src/interaction_composition.rs b/packages/d2bd/src/interaction_composition.rs index 25fc5f38c..0901fbe87 100644 --- a/packages/d2bd/src/interaction_composition.rs +++ b/packages/d2bd/src/interaction_composition.rs @@ -5293,6 +5293,8 @@ where let handler_active = Arc::clone(&active_handlers); let handler_stop = Arc::clone(&stop); let handler = tokio::spawn(async move { + let _admission = + InteractionHandlerAdmissionGuard(handler_active); let result = admit_interaction_socket( socket, runtime, @@ -5305,7 +5307,6 @@ where if let Err(error) = result { tracing::debug!(%error, "interaction ComponentSession refused"); } - handler_active.fetch_sub(1, Ordering::AcqRel); }); handlers.lock().await.push(handler); } @@ -5355,12 +5356,24 @@ fn reserve_interaction_handler(active_handlers: &AtomicUsize) -> bool { } } +/// Releases one reserved interaction-handler slot on drop, so a panicked +/// handler cannot leak its bounded admission reservation. +struct InteractionHandlerAdmissionGuard(Arc); + +impl Drop for InteractionHandlerAdmissionGuard { + fn drop(&mut self) { + self.0.fetch_sub(1, Ordering::AcqRel); + } +} + async fn reap_finished_handlers(handlers: &AsyncMutex>>) { let mut handlers = handlers.lock().await; let mut index = 0; while index < handlers.len() { if handlers[index].is_finished() { - let _ = handlers.swap_remove(index).await; + if let Err(error) = handlers.swap_remove(index).await { + tracing::warn!(%error, "interaction handler task failed"); + } } else { index += 1; } From 84d4cb0b9067d190301d68de16fcd252c05559e7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:00:09 -0700 Subject: [PATCH 254/726] broker: keep the io error source in the hosts marker splice error --- packages/d2b-broker/src/ops/hosts.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/d2b-broker/src/ops/hosts.rs b/packages/d2b-broker/src/ops/hosts.rs index 391282c69..4bda4c5aa 100644 --- a/packages/d2b-broker/src/ops/hosts.rs +++ b/packages/d2b-broker/src/ops/hosts.rs @@ -117,9 +117,9 @@ pub fn refuse_unsafe_parent(path: &Path) -> io::Result<()> { Ok(()) } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug)] pub enum WriteMarkerBlockError { - Io(String), + Io(io::Error), ReconcileExec(ReconcileExecError), ForeignOwnership, } @@ -134,7 +134,14 @@ impl std::fmt::Display for WriteMarkerBlockError { } } -impl std::error::Error for WriteMarkerBlockError {} +impl std::error::Error for WriteMarkerBlockError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Io(err) => Some(err), + _ => None, + } + } +} /// Runtime entry-point for `UpdateHostsFile`. /// @@ -146,11 +153,11 @@ pub async fn write_marker_block( executor: &dyn ReconcileExecutor, intent: &ResolvedHostsIntent, ) -> Result<(), WriteMarkerBlockError> { - refuse_unsafe_parent(&intent.path).map_err(|err| WriteMarkerBlockError::Io(err.to_string()))?; + refuse_unsafe_parent(&intent.path).map_err(WriteMarkerBlockError::Io)?; let existing = match path_safe::read_to_string_nofollow(&intent.path) { Ok(contents) => contents, Err(err) if err.kind() == io::ErrorKind::NotFound => String::new(), - Err(err) => return Err(WriteMarkerBlockError::Io(err.to_string())), + Err(err) => return Err(WriteMarkerBlockError::Io(err)), }; validate_marker_ownership(&existing, intent)?; let merged = if intent.ownership_marker.is_some() { @@ -173,11 +180,11 @@ pub async fn remove_marker_block( executor: &dyn ReconcileExecutor, intent: &ResolvedHostsIntent, ) -> Result<(), WriteMarkerBlockError> { - refuse_unsafe_parent(&intent.path).map_err(|err| WriteMarkerBlockError::Io(err.to_string()))?; + refuse_unsafe_parent(&intent.path).map_err(WriteMarkerBlockError::Io)?; let existing = match path_safe::read_to_string_nofollow(&intent.path) { Ok(contents) => contents, Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), - Err(err) => return Err(WriteMarkerBlockError::Io(err.to_string())), + Err(err) => return Err(WriteMarkerBlockError::Io(err)), }; validate_marker_ownership(&existing, intent)?; let merged = if intent.ownership_marker.is_some() { From 7ec590e1d4fcc3ed3185dec638f30698f442779d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:00:16 -0700 Subject: [PATCH 255/726] d2bd: trace effect service actor respawn declines --- packages/d2bd/src/effect_service_actors.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/d2bd/src/effect_service_actors.rs b/packages/d2bd/src/effect_service_actors.rs index a86ca97d8..04f4197c6 100644 --- a/packages/d2bd/src/effect_service_actors.rs +++ b/packages/d2bd/src/effect_service_actors.rs @@ -554,7 +554,9 @@ impl Actor for EffectServiceSupervisor { let zone = state.zone.clone(); for row in args.rows.into_iter().filter(|row| row.zone == zone) { state.rows.insert(row.service.clone(), row.clone()); - let _ = state.spawn_service_actor(&myself, &row).await; + if let Err(error) = state.spawn_service_actor(&myself, &row).await { + tracing::warn!(service = %row.service, zone = %row.zone, %error, "effect service actor respawn declined"); + } } Ok(state) } @@ -613,7 +615,9 @@ async fn supervise_exit( return; }; // Respawn bumps the generational binding revision (KTD5). - let _ = state.spawn_service_actor(myself, &row).await; + if let Err(error) = state.spawn_service_actor(myself, &row).await { + tracing::warn!(service = %row.service, zone = %row.zone, %error, "effect service actor respawn declined"); + } } #[cfg(test)] From 31248998b093d92fef1e41eb07ecb49e3b79d33c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:00:53 -0700 Subject: [PATCH 256/726] d2bd: carry the trusted-context publication error as a field --- packages/d2bd/src/provider_lifecycle.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/d2bd/src/provider_lifecycle.rs b/packages/d2bd/src/provider_lifecycle.rs index 564af0e47..0cf9b7e11 100644 --- a/packages/d2bd/src/provider_lifecycle.rs +++ b/packages/d2bd/src/provider_lifecycle.rs @@ -1071,7 +1071,8 @@ impl ProviderRuntime { zone = %self.zone.as_str(), revision = provider_set_revision, operation = "PublishTrustedContext", - "trusted-context publication refused: {error}" + %error, + "trusted-context publication refused" ); } } From ac53b04480ff741f030852d69f5bd9bfcaf466e7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:01:38 -0700 Subject: [PATCH 257/726] d2bd: attribute forward rendezvous cap refusals to peer and cap --- packages/d2bd/src/forward_rendezvous.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index b2ed74641..d1d8d7dd9 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -976,7 +976,16 @@ fn response_fds_match_method(fds: &[OwnedFd], contract: MethodFdContract) -> boo /// (the kebab-case `MethodFdContract` facet), when the spelling is a known /// kind. fn declared_fd_kind(kind: &str) -> Option { - serde_json::from_value(serde_json::Value::String(kind.to_owned())).ok() + match kind { + "fifo" => Some(FdKind::Fifo), + "socket" => Some(FdKind::Socket), + "char-device" => Some(FdKind::CharDevice), + "block-device" => Some(FdKind::BlockDevice), + "any" => Some(FdKind::Any), + "regular" => Some(FdKind::Regular), + "directory" => Some(FdKind::Directory), + _ => None, + } } /// The normal result reply of one effect-service invocation: the canonical @@ -1246,7 +1255,11 @@ async fn serve_accepted( // answer: the call is refused under the daemon's own capacity // code, so the broker reports that code rather than a handler it // never reached. - tracing::warn!("forward rendezvous is at its in-flight cap; refusing the call"); + tracing::warn!( + peer_uid, + max = posture.max_inflight, + "forward rendezvous is at its in-flight cap; refusing the call" + ); refuse(&connection, TypedError::DaemonBusy.kind()).await; continue; }; From 524d06bad06c00ccf05c20c14461400478d70df3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:02:10 -0700 Subject: [PATCH 258/726] d2bd: re-export the registry bound only --- packages/d2bd/src/provider_registry.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2bd/src/provider_registry.rs b/packages/d2bd/src/provider_registry.rs index a64e35f0b..14b3b77c0 100644 --- a/packages/d2bd/src/provider_registry.rs +++ b/packages/d2bd/src/provider_registry.rs @@ -45,7 +45,7 @@ pub const PROVIDER_BUNDLE_VERSION: u32 = 3; pub const PROVIDER_BUNDLE_SCHEMA_VERSION: &str = "v3"; /// Registry limits and snapshots are owned by the shared Provider crate. -pub use d2b_provider::{MAX_PROVIDER_REGISTRY_ENTRIES, ProviderRegistrySnapshot}; +pub use d2b_provider::MAX_PROVIDER_REGISTRY_ENTRIES; /// Mint a unique operation identity for one lifecycle attempt. The immutable /// Guest identity is carried by the sealed authorization lease; the nonce From 7ce599eeb3cb914e21675e9408547c22245b6fb2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:03:37 -0700 Subject: [PATCH 259/726] broker: classify usbip unbind failures once into a typed verdict --- packages/d2b-broker/src/ops/exec_reconcile.rs | 206 +++++++++++------- 1 file changed, 127 insertions(+), 79 deletions(-) diff --git a/packages/d2b-broker/src/ops/exec_reconcile.rs b/packages/d2b-broker/src/ops/exec_reconcile.rs index f42f61073..ad96dbc48 100644 --- a/packages/d2b-broker/src/ops/exec_reconcile.rs +++ b/packages/d2b-broker/src/ops/exec_reconcile.rs @@ -952,6 +952,7 @@ async fn run_usbip_driver_isolated( ) -> Result<(), ReconcileExecError> { let deadline = tokio::time::Instant::now() + USBIP_DRIVER_HELPER_TIMEOUT; let mut last_error = None; + let mut last_failure = None; for attempt in 0..USBIP_DRIVER_MAX_ATTEMPTS { let attempt_started = tokio::time::Instant::now(); @@ -972,41 +973,44 @@ async fn run_usbip_driver_isolated( ); return Ok(()); } - Err(error) - if usbip_unbind_error_is_transient(&error) - && attempt + 1 < USBIP_DRIVER_MAX_ATTEMPTS => - { - tracing::debug!( - usbip_subcommand = subcommand.as_str(), - attempt = attempt + 1, - elapsed_ms, - deadline_remaining_ms = remaining_ms, - error = ?error, - "usbip driver helper retrying transient failure" - ); - last_error = Some(error); - let delay = usbip_unbind_retry_delay(bus_id, attempt); - let now = tokio::time::Instant::now(); - if now + delay >= deadline { - break; - } - tokio::time::sleep(delay).await; - } Err(error) => { - tracing::debug!( - usbip_subcommand = subcommand.as_str(), - attempt = attempt + 1, - elapsed_ms, - deadline_remaining_ms = remaining_ms, - "usbip driver helper failed" - ); - return Err(error); + let failure = UsbipUnbindFailure::classify(&error); + if failure.transient && attempt + 1 < USBIP_DRIVER_MAX_ATTEMPTS { + tracing::debug!( + usbip_subcommand = subcommand.as_str(), + attempt = attempt + 1, + elapsed_ms, + deadline_remaining_ms = remaining_ms, + failure_kind = ?failure.kind, + error = ?error, + "usbip driver helper retrying transient failure" + ); + last_error = Some(error); + last_failure = Some(failure); + let delay = usbip_unbind_retry_delay(bus_id, attempt); + let now = tokio::time::Instant::now(); + if now + delay >= deadline { + break; + } + tokio::time::sleep(delay).await; + } else { + tracing::debug!( + usbip_subcommand = subcommand.as_str(), + attempt = attempt + 1, + elapsed_ms, + deadline_remaining_ms = remaining_ms, + failure_kind = ?failure.kind, + "usbip driver helper failed" + ); + return Err(error); + } } } } tracing::debug!( usbip_subcommand = subcommand.as_str(), attempts = USBIP_DRIVER_MAX_ATTEMPTS, + failure_kind = ?last_failure.as_ref().map(|failure| failure.kind), "usbip driver helper retry budget exhausted" ); Err(last_error.unwrap_or_else(|| ReconcileExecError::TimedOut { @@ -1188,31 +1192,70 @@ fn usbip_stream_shutdown_error_is_ignorable(error: &io::Error) -> bool { ) } -fn usbip_unbind_error_is_transient(error: &ReconcileExecError) -> bool { - match error { - ReconcileExecError::NonZeroExit { stderr, .. } => { - let stderr = stderr.to_ascii_lowercase(); - stderr.contains("ebusy") - || stderr.contains("busy") - || stderr.contains("eagain") - || stderr.contains("temporarily unavailable") - || stderr.contains("interrupted") - || stderr.contains("eintr") - } - ReconcileExecError::Io { detail, .. } => { - let detail = detail.to_ascii_lowercase(); - detail.contains("ebusy") - || detail.contains("busy") - || detail.contains("eagain") - || detail.contains("temporarily unavailable") - || detail.contains("interrupted") - || detail.contains("eintr") - } - ReconcileExecError::BinaryMissing { detail, .. } => { - let detail = detail.to_ascii_lowercase(); - detail.contains("text file busy") || detail.contains("etxtbsy") - } - _ => false, +/// Stable classification of a usbip driver-helper failure, decided once +/// from the raw error text so retries and the final verdict never +/// re-scan strings. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum UsbipUnbindFailureKind { + /// Device or driver busy (EBUSY / EAGAIN): retryable. + Busy, + /// Interrupted operation (EINTR): retryable. + Interrupted, + /// Helper binary busy (ETXTBSY): retryable. + TextFileBusy, + /// Any other failure: fatal. + Fatal, +} + +/// One classified usbip driver-helper failure: the typed kind, the +/// retry verdict, and the raw detail text for reporting. +#[derive(Debug, Clone, PartialEq, Eq)] +struct UsbipUnbindFailure { + kind: UsbipUnbindFailureKind, + transient: bool, + detail: String, +} + +impl UsbipUnbindFailure { + /// Classify a driver-helper error once, case-folded, at the point + /// the failure is observed. + fn classify(error: &ReconcileExecError) -> Self { + let (detail, kind) = match error { + ReconcileExecError::NonZeroExit { stderr, .. } + | ReconcileExecError::Io { detail: stderr, .. } => { + let stderr = stderr.to_ascii_lowercase(); + let kind = if stderr.contains("ebusy") + || stderr.contains("busy") + || stderr.contains("eagain") + || stderr.contains("temporarily unavailable") + { + UsbipUnbindFailureKind::Busy + } else if stderr.contains("interrupted") || stderr.contains("eintr") { + UsbipUnbindFailureKind::Interrupted + } else { + UsbipUnbindFailureKind::Fatal + }; + (stderr, kind) + } + ReconcileExecError::BinaryMissing { detail, .. } => { + let detail = detail.to_ascii_lowercase(); + let kind = if detail.contains("text file busy") || detail.contains("etxtbsy") { + UsbipUnbindFailureKind::TextFileBusy + } else { + UsbipUnbindFailureKind::Fatal + }; + (detail, kind) + } + _ => { + return Self { + kind: UsbipUnbindFailureKind::Fatal, + transient: false, + detail: String::new(), + } + } + }; + let transient = kind != UsbipUnbindFailureKind::Fatal; + Self { kind, transient, detail } } } @@ -1926,32 +1969,37 @@ mod tests { #[test] fn usbip_unbind_retry_classifier_and_delay_are_bounded_with_jitter() { - assert!(usbip_unbind_error_is_transient( - &ReconcileExecError::NonZeroExit { - which: "usbip unbind".to_owned(), - exit_code: 1, - stderr: "write: Device or resource busy (EBUSY)".to_owned(), - } - )); - assert!(usbip_unbind_error_is_transient( - &ReconcileExecError::BinaryMissing { - which: "usbip".to_owned(), - detail: "Text file busy (os error 26)".to_owned(), - } - )); - assert!(!usbip_unbind_error_is_transient( - &ReconcileExecError::BinaryMissing { - which: "usbip".to_owned(), - detail: "No such file or directory (os error 2)".to_owned(), - } - )); - assert!(!usbip_unbind_error_is_transient( - &ReconcileExecError::NonZeroExit { - which: "usbip unbind".to_owned(), - exit_code: 1, - stderr: "device is not bound to usbip-host driver".to_owned(), - } - )); + let busy = UsbipUnbindFailure::classify(&ReconcileExecError::NonZeroExit { + which: "usbip unbind".to_owned(), + exit_code: 1, + stderr: "write: Device or resource busy (EBUSY)".to_owned(), + }); + assert!(busy.transient); + assert_eq!(busy.kind, UsbipUnbindFailureKind::Busy); + assert!(busy.detail.contains("ebusy")); + + let text_file_busy = UsbipUnbindFailure::classify(&ReconcileExecError::BinaryMissing { + which: "usbip".to_owned(), + detail: "Text file busy (os error 26)".to_owned(), + }); + assert!(text_file_busy.transient); + assert_eq!(text_file_busy.kind, UsbipUnbindFailureKind::TextFileBusy); + + let missing = UsbipUnbindFailure::classify(&ReconcileExecError::BinaryMissing { + which: "usbip".to_owned(), + detail: "No such file or directory (os error 2)".to_owned(), + }); + assert!(!missing.transient); + assert_eq!(missing.kind, UsbipUnbindFailureKind::Fatal); + + let unbound = UsbipUnbindFailure::classify(&ReconcileExecError::NonZeroExit { + which: "usbip unbind".to_owned(), + exit_code: 1, + stderr: "device is not bound to usbip-host driver".to_owned(), + }); + assert!(!unbound.transient); + assert_eq!(unbound.kind, UsbipUnbindFailureKind::Fatal); + let first = usbip_unbind_retry_delay("1-2", 0); let second = usbip_unbind_retry_delay("1-3", 0); assert_ne!(first, second, "busid-derived jitter should vary delay"); From 9b3549b5808dba2ffd26f32355b6e907adaa4755 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:04:00 -0700 Subject: [PATCH 260/726] d2b-core: seal shell-name newtype and narrow resolver surface --- packages/d2b-core/fuzz/src/bin/core.rs | 2 +- packages/d2b-core/src/bundle_resolver.rs | 127 ++++++++++++--------- packages/d2b-core/src/manifest_v04.rs | 9 +- packages/d2b-core/src/privileges.rs | 4 +- packages/d2b-core/src/site.rs | 23 +++- packages/d2b-core/src/storage_lifecycle.rs | 11 +- 6 files changed, 106 insertions(+), 70 deletions(-) diff --git a/packages/d2b-core/fuzz/src/bin/core.rs b/packages/d2b-core/fuzz/src/bin/core.rs index 0e477afa2..e6ca4f4cd 100644 --- a/packages/d2b-core/fuzz/src/bin/core.rs +++ b/packages/d2b-core/fuzz/src/bin/core.rs @@ -157,7 +157,7 @@ fn privileges_json_denies_unknown_fields() { } fn w1_matrix_contains_public_and_broker_rows() { - let matrix = PrivilegesJson::w1("v1"); + let matrix = PrivilegesJson::from_const_rows("v1"); assert_eq!(matrix.public_operations.len(), PUBLIC_OPERATION_AUTHZ.len()); assert_eq!(matrix.broker_operations.len(), BROKER_OPERATION_AUTHZ.len()); assert!( diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 3a61dcf18..6aeebd7c6 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -180,20 +180,16 @@ struct ZoneNativeBundleIndex { bundle_version: u32, schema_version: String, privileges_path: String, - #[serde(default)] storage_path: Option, /// Private site-runtime contract (`site.json`). Optional: a bundle that /// predates the artifact leaves the site facts absent. - #[serde(default)] site_path: Option, /// Private host contract artifact (`host.json`). Optional: a bundle that /// predates the artifact leaves the empty host model in place, whose /// NetworkManager fields are empty strings: the `apply-nm-unmanaged` /// kernel fails closed on the empty file path rather than inventing a /// contract. - #[serde(default)] host_path: Option, - #[serde(default)] realm_workloads_launcher_v2_path: Option, zones: Vec, generation: BundleGeneration, @@ -616,6 +612,7 @@ impl From for crate::processes::RoleUserNamespace { /// Synthesized from the bundle's static installer policy: the /// systemd unit file path the daemon ships at + the service name /// + the `daemon-config.json` path the unit reads. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedInstallerIntent { pub intent_id: String, @@ -629,6 +626,7 @@ pub struct ResolvedInstallerIntent { pub artifacts: Vec, } +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct InstallerArtifact { pub path: PathBuf, @@ -637,6 +635,7 @@ pub struct InstallerArtifact { } /// Resolved migration plan. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedMigrateIntent { pub intent_id: String, @@ -652,6 +651,7 @@ pub struct ResolvedMigrateIntent { /// Resolved activation intent for per-VM switch / boot / test / rollback /// broker dispatch. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedActivationIntent { pub intent_id: String, @@ -694,6 +694,7 @@ impl ResolvedStoreViewIntent { } /// Resolved host-GC intent. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedGcIntent { pub intent_id: String, @@ -701,6 +702,7 @@ pub struct ResolvedGcIntent { } /// Resolved framework-managed SSH key rotation intent. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedKeysRotateIntent { pub intent_id: String, @@ -709,6 +711,7 @@ pub struct ResolvedKeysRotateIntent { } /// Resolved known_hosts trust intent. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedHostKeyTrustIntent { pub intent_id: String, @@ -719,6 +722,7 @@ pub struct ResolvedHostKeyTrustIntent { } /// Resolved known_hosts entry removal intent. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedRotateKnownHostIntent { pub intent_id: String, @@ -774,6 +778,7 @@ pub struct ResolvedPrepareDirIntent { } /// Trusted legacy swtpm adoption paths derived from the private bundle. +#[doc(hidden)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResolvedLegacySwtpmIntent { pub intent_id: String, @@ -1094,10 +1099,9 @@ fn verify_bundle_hash(path: &Path, raw_bytes: &[u8]) -> Result<(), Error> { "missing-bundle-hash", )); } - eprintln!( - "d2b: warning: bundle artifact {} has no bundleHash field; \ - skipping self-hash check (re-run nixos-rebuild to add it)", - path.display() + tracing::warn!( + path = %path.display(), + "bundle artifact has no bundleHash field; skipping self-hash check" ); return Ok(()); } @@ -1293,7 +1297,7 @@ impl BundleResolver { serde_json::from_slice(bundle_bytes).map_err(|error| { Error::manifest_parse_error( "bundle.json", - manifest_parse_reason(&error.to_string()), + manifest_parse_reason(&error), ) })?; if index.bundle_version != 1 { @@ -1394,6 +1398,11 @@ impl BundleResolver { /// Variant for tests and embedded callers that already hold verified /// per-Zone resource-bundle bytes. + /// + /// Precondition: the per-Zone resource-bundle bytes are verified by + /// the caller, and the bundle serializes for audit hashing. The + /// precondition is enforced with debug assertions; release builds + /// treat a violation as absent data rather than panicking. pub fn from_artifacts_with_zone_resource_bundles( bundle: Bundle, host: HostJson, @@ -1401,17 +1410,23 @@ impl BundleResolver { manifest: ManifestV04, zone_resource_bundles: BTreeMap>, ) -> Self { - let bundle_hash = stable_digest_bytes( - serde_json::to_vec(&bundle) - .expect("bundle serialization for audit hashing must succeed") - .as_slice(), + let bundle_bytes = serde_json::to_vec(&bundle); + debug_assert!( + bundle_bytes.is_ok(), + "bundle serialization for audit hashing must succeed" ); + let bundle_hash = stable_digest_bytes(bundle_bytes.unwrap_or_default().as_slice()); let provider_controller_templates = zone_resource_bundles .values() .flat_map(|bytes| { - ResourceBundle::from_json(bytes) - .expect("zone resource bundle bytes must be verified") - .process_templates + let bundle = ResourceBundle::from_json(bytes); + debug_assert!( + bundle.is_ok(), + "zone resource bundle bytes must be verified" + ); + bundle + .map(|bundle| bundle.process_templates) + .unwrap_or_default() }) .collect(); Self::from_parsed_artifacts( @@ -2415,7 +2430,7 @@ impl BundleResolver { self.processes.vms.iter().find(|vm| vm.vm == vm_id) } - pub fn find_process_node(&self, vm_id: &str, role_id: &str) -> Option<&ProcessNode> { + pub(crate) fn find_process_node(&self, vm_id: &str, role_id: &str) -> Option<&ProcessNode> { self.find_process_vm(vm_id) .and_then(|vm| vm.nodes.iter().find(|node| node.id.0 == role_id)) } @@ -2456,7 +2471,7 @@ impl BundleResolver { .collect() } - pub fn resolve_vm_start_intent( + pub(crate) fn resolve_vm_start_intent( &self, vm_id: &str, role_id: &str, @@ -2501,13 +2516,6 @@ impl BundleResolver { .find(|candidate| candidate.env == env) } - pub fn find_if_name_mapping_for_vm(&self, vm_id: &str) -> Option<&crate::host::IfNameMapping> { - self.host - .if_name_mappings - .iter() - .find(|mapping| mapping.vm.as_deref() == Some(vm_id)) - } - pub fn resolve_tap_intent( &self, vm_id: &str, @@ -2620,10 +2628,13 @@ impl BundleResolver { &self, vm_id: &str, role_id: &str, - ) -> Result, String> { - let node = self - .find_process_node(vm_id, role_id) - .ok_or_else(|| format!("missing process node vm={vm_id} role={role_id}"))?; + ) -> Result, Error> { + let node = self.find_process_node(vm_id, role_id).ok_or_else(|| { + Error::manifest_parse_error( + "processes.json", + format!("missing process node vm={vm_id} role={role_id}"), + ) + })?; let mut next_fd = 10; let mut out = Vec::new(); for iface in &node.network_interfaces { @@ -2631,18 +2642,28 @@ impl BundleResolver { continue; } let macvtap = iface.macvtap.as_ref().ok_or_else(|| { - format!( - "macvtap interface {} for vm={vm_id} role={role_id} is missing macvtap metadata", - iface.id + Error::manifest_parse_error( + "processes.json", + format!( + "macvtap interface {} for vm={vm_id} role={role_id} is missing macvtap metadata", + iface.id + ), ) })?; out.push(ResolvedMacvtapIntent { vm_name: vm_id.to_owned(), role_id: role_id.to_owned(), - ifname: IfName::new(iface.id.clone()) - .map_err(|err| format!("invalid macvtap ifname {}: {err}", iface.id))?, + ifname: IfName::new(iface.id.clone()).map_err(|err| { + Error::manifest_parse_error( + "processes.json", + format!("invalid macvtap ifname {}: {err}", iface.id), + ) + })?, parent_ifname: IfName::new(macvtap.link.clone()).map_err(|err| { - format!("invalid macvtap parent ifname {}: {err}", macvtap.link) + Error::manifest_parse_error( + "processes.json", + format!("invalid macvtap parent ifname {}: {err}", macvtap.link), + ) })?, mode: macvtap.mode, mac: iface.mac.clone(), @@ -4839,7 +4860,7 @@ fn load_guest_setup_descriptors( let mut catalog: serde_json::Value = serde_json::from_slice(&bytes).map_err(|error| { Error::manifest_parse_error( "artifact-catalog.json", - manifest_parse_reason(&error.to_string()), + manifest_parse_reason(&error), ) })?; let catalog_digest = catalog @@ -5486,7 +5507,7 @@ fn load_zone_storage_rows( let bytes = secure_open_and_read(&row_path, policy)?; verify_artifact_hash(&row_path, &bytes, bundle.artifact_hashes.as_ref(), key)?; let row: ZoneStoreStorageRow = serde_json::from_slice(&bytes).map_err(|error| { - Error::manifest_parse_error("storage.json", manifest_parse_reason(&error.to_string())) + Error::manifest_parse_error("storage.json", manifest_parse_reason(&error)) })?; if rows.insert(zone_name.to_owned(), row).is_some() { return Err(Error::manifest_parse_error( @@ -5529,7 +5550,7 @@ fn load_zone_native_topology( "index.json", )?; let index: ZoneNativeIndexDocument = serde_json::from_slice(&bytes).map_err(|error| { - Error::manifest_parse_error("index.json", manifest_parse_reason(&error.to_string())) + Error::manifest_parse_error("index.json", manifest_parse_reason(&error)) })?; if !index.topology.sealed { return Err(Error::manifest_parse_error( @@ -5625,10 +5646,10 @@ fn load_optional_site_artifact( site_ref, )?; let site: SiteJson = serde_json::from_slice(&bytes).map_err(|error| { - Error::manifest_parse_error("site.json", manifest_parse_reason(&error.to_string())) + Error::manifest_parse_error("site.json", manifest_parse_reason(&error)) })?; site.validate() - .map_err(|reason| Error::manifest_parse_error("site.json", reason))?; + .map_err(|reason| Error::manifest_parse_error("site.json", reason.to_string()))?; Ok(Some(site)) } @@ -5657,7 +5678,7 @@ fn load_zone_native_host_artifact( host_ref, )?; let host: HostJson = serde_json::from_slice(&bytes).map_err(|error| { - Error::manifest_parse_error("host.json", manifest_parse_reason(&error.to_string())) + Error::manifest_parse_error("host.json", manifest_parse_reason(&error)) })?; Ok(host) } @@ -5679,7 +5700,7 @@ fn load_optional_storage_artifact( storage_ref, )?; let storage: StorageJson = serde_json::from_slice(&bytes).map_err(|e| { - Error::manifest_parse_error("storage.json", manifest_parse_reason(&e.to_string())) + Error::manifest_parse_error("storage.json", manifest_parse_reason(&e)) })?; Ok(Some(storage)) } @@ -5699,7 +5720,7 @@ fn load_optional_realm_workloads_launcher_v2_artifact( serde_json::from_slice(&bytes).map_err(|error| { Error::manifest_parse_error( "realm-workloads-launcher-v2.json", - manifest_parse_reason(&error.to_string()), + manifest_parse_reason(&error), ) })?; artifact @@ -5738,17 +5759,15 @@ fn stable_digest_bytes(input: &[u8]) -> String { // Minimal-touch helpers re-exported from types this module needs. // --------------------------------------------------------------- -fn manifest_parse_reason(err: &str) -> &'static str { - // Bridge to the existing manifest_v04 helper without exposing it. - // We just need a stable category string for `Error::manifest_parse_error`. - if err.contains("missing field") { - "missing-required-field" - } else if err.contains("unknown field") { - "unknown-field" - } else if err.contains("invalid type") { - "invalid-type" - } else { - "parse-failed" +fn manifest_parse_reason(error: &serde_json::Error) -> &'static str { + // Stable category string for `Error::manifest_parse_error`, derived + // from the error class rather than the Display text (which is not a + // stable API across serde_json versions). + match error.classify() { + serde_json::error::Category::Data => "invalid-data", + serde_json::error::Category::Syntax + | serde_json::error::Category::Eof + | serde_json::error::Category::Io => "parse-failed", } } diff --git a/packages/d2b-core/src/manifest_v04.rs b/packages/d2b-core/src/manifest_v04.rs index fbe793b7d..fb21378fb 100644 --- a/packages/d2b-core/src/manifest_v04.rs +++ b/packages/d2b-core/src/manifest_v04.rs @@ -344,7 +344,14 @@ pub struct VmShellMetadata { /// A validated shell name (`^[A-Za-z0-9_][A-Za-z0-9._-]{0,63}$`). #[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[serde(transparent)] -pub struct ManifestShellName(pub String); +pub struct ManifestShellName(String); + +impl ManifestShellName { + /// The validated shell name. + pub fn as_str(&self) -> &str { + &self.0 + } +} impl<'de> Deserialize<'de> for ManifestShellName { fn deserialize(deserializer: D) -> Result diff --git a/packages/d2b-core/src/privileges.rs b/packages/d2b-core/src/privileges.rs index d31af5dc6..41e73bd7f 100644 --- a/packages/d2b-core/src/privileges.rs +++ b/packages/d2b-core/src/privileges.rs @@ -738,7 +738,7 @@ impl From<&OperationAuthzRow> for OperationAuthz { impl PrivilegesJson { /// Builds the canonical privileges matrix from the const rows. - pub fn w1(schema_version: impl Into) -> Self { + pub fn from_const_rows(schema_version: impl Into) -> Self { Self { schema_version: schema_version.into(), public_operations: PUBLIC_OPERATION_AUTHZ @@ -759,7 +759,7 @@ mod tests { #[test] fn w1_matrix_contains_public_and_broker_rows() { - let matrix = PrivilegesJson::w1("v1"); + let matrix = PrivilegesJson::from_const_rows("v1"); assert_eq!(matrix.public_operations.len(), PUBLIC_OPERATION_AUTHZ.len()); assert_eq!(matrix.broker_operations.len(), BROKER_OPERATION_AUTHZ.len()); assert!( diff --git a/packages/d2b-core/src/site.rs b/packages/d2b-core/src/site.rs index 6b6dad19a..a0303f094 100644 --- a/packages/d2b-core/src/site.rs +++ b/packages/d2b-core/src/site.rs @@ -39,11 +39,26 @@ impl SiteJson { /// Fail-closed artifact validation: a malformed socket is an emitter /// contract violation and refuses the bundle load. - pub fn validate(&self) -> Result<(), &'static str> { + pub fn validate(&self) -> Result<(), SiteValidationError> { match self.wayland_socket.as_deref() { None => Ok(()), Some(socket) if wayland_socket_ok(socket) => Ok(()), - Some(_) => Err("invalid-wayland-socket"), + Some(_) => Err(SiteValidationError::InvalidWaylandSocket), + } + } +} + +/// Validation failure for a [`SiteJson`] artifact. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SiteValidationError { + /// The Wayland socket does not match the accepted shape. + InvalidWaylandSocket, +} + +impl std::fmt::Display for SiteValidationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidWaylandSocket => f.write_str("invalid-wayland-socket"), } } } @@ -66,7 +81,7 @@ fn wayland_socket_ok(socket: &str) -> bool { #[cfg(test)] mod tests { - use super::SiteJson; + use super::{SiteJson, SiteValidationError}; fn site(value: Option<&str>) -> SiteJson { SiteJson { @@ -110,7 +125,7 @@ mod tests { let parsed = site(Some(socket)); assert_eq!( parsed.validate(), - Err("invalid-wayland-socket"), + Err(SiteValidationError::InvalidWaylandSocket), "{socket} must not validate" ); assert_eq!( diff --git a/packages/d2b-core/src/storage_lifecycle.rs b/packages/d2b-core/src/storage_lifecycle.rs index d7e16d0fc..b3bf45232 100644 --- a/packages/d2b-core/src/storage_lifecycle.rs +++ b/packages/d2b-core/src/storage_lifecycle.rs @@ -42,39 +42,34 @@ impl StorageLifecycleReport { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "kebab-case", tag = "kind")] +#[serde(rename_all = "kebab-case", rename_all_fields = "camelCase", tag = "kind")] pub enum StorageLifecycleIssue { MissingStorageContract, MissingSyncContract, LegacyBundleContractsUnavailable { - #[serde(rename = "bundleVersion")] bundle_version: u32, }, BundleResolverUnavailable, StorageContractInvalid { - #[serde(rename = "contractId")] contract_id: String, reason: StorageContractValidationReason, - #[serde(rename = "offendingId", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] offending_id: Option, }, SyncContractInvalid { - #[serde(rename = "contractId")] contract_id: String, reason: SyncContractValidationReason, - #[serde(rename = "offendingId", skip_serializing_if = "Option::is_none")] + #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] offending_id: Option, }, MissingRestartPolicy { vm: String, - #[serde(rename = "roleId")] role_id: String, }, AdoptableMissingCgroupLeaf { vm: String, - #[serde(rename = "roleId")] role_id: String, }, } From fc7dfcc5234735b77166ff3a579ff89d45b722ee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:04:05 -0700 Subject: [PATCH 261/726] d2b-core: surface bundle-load warnings as structured records --- Cargo.lock | 1 + packages/d2b-broker/src/runtime.rs | 2 +- packages/d2b-core/Cargo.toml | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index f023ce55f..453ba5e37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -987,6 +987,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] [[package]] diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 556f4cf26..55d381918 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -6401,7 +6401,7 @@ async fn prepare_runner_preopened_fds( })?; let intents = resolver .resolve_macvtap_intents(req.vm_id.as_str(), runner_intent.role_id.as_str()) - .map_err(BrokerError::LiveHandler)?; + .map_err(|error| BrokerError::LiveHandler(error.to_string()))?; if intents.is_empty() { return Ok(RunnerPreopenedFds { child_fds: Vec::new(), diff --git a/packages/d2b-core/Cargo.toml b/packages/d2b-core/Cargo.toml index f24ea7e29..10edbba09 100644 --- a/packages/d2b-core/Cargo.toml +++ b/packages/d2b-core/Cargo.toml @@ -31,6 +31,9 @@ sha2 = { workspace = true } # caller; `sync::oneshot` is a waker channel with no runtime or reactor # requirement, so the worker stays usable from any executor. tokio = { workspace = true, features = ["sync"] } +# Bundle-load warnings (e.g. a pre-v2 bundle without bundleHash) are +# emitted as structured records so the daemon's subscriber surfaces them. +tracing = "0.1" bolero = { version = "0.10", optional = true } [dev-dependencies] From a25efea28a12ba81bde8b3d8ebdd88551491f7de Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:04:29 -0700 Subject: [PATCH 262/726] d2bd: model controller session teardown as a monotonic stage --- packages/d2bd/src/resource_runtime.rs | 70 ++++++++++++++++----------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 4ac271387..56ce8f8cb 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -1000,6 +1000,22 @@ fn generation_publication_payload_matches( && value.get("generationSet") == serde_json::to_value(expected_generation_set).ok().as_ref() } +/// The once-only teardown progress of one controller session. The stages +/// advance monotonically: the ingress is revoked first, then the +/// assignments, then the transport is closed; a session can never skip or +/// reorder a step. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum TeardownStage { + /// No teardown step has run yet. + Active, + /// The controller ingress has been revoked. + IngressRevoked, + /// The controller assignments have been revoked. + AssignmentsRevoked, + /// The transport has been closed. + TransportClosed, +} + struct ControllerSession { context: crate::process_provider_runtime::ControllerBootstrapContext, binding: ControllerSessionBinding, @@ -1010,9 +1026,7 @@ struct ControllerSession { service_task: tokio::task::JoinHandle>, assignments: BTreeMap, assignment_stream_open: bool, - assignments_revoked: bool, - transport_closed: bool, - ingress_revoked: bool, + teardown_stage: TeardownStage, } impl ControllerSession { @@ -3001,6 +3015,20 @@ fn merge_cloud_hypervisor_child_spec( Ok(Value::Object(merged_spec)) } +/// The publication stage of one Zone's resource plane. The plane opens on +/// the bootstrap policy with the controller endpoint and watch still +/// pending, and moves to `Published` when the committed bundle is +/// activated; the two stages are the only reachable gate states. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum PlanePublicationStage { + /// The plane is open on the bootstrap policy; the controller endpoint + /// is not yet registered and the watch is not yet admitted. + BootstrapOnly, + /// The committed bundle is activated; the controller endpoint is + /// registered and the watch admitted. + Published, +} + /// A production Resource API and core-controller runtime for one Zone. pub struct ZoneResourceRuntime { zone: ZoneId, @@ -3037,9 +3065,7 @@ pub struct ZoneResourceRuntime { /// manager-served committed policy replaces it at activation; it remains /// the reported snapshot while no manager-served projection is installed. bootstrap_policy_snapshot: PolicySnapshot, - policy_installed: bool, - controller_endpoint_registered: bool, - watch_admitted: bool, + publication_stage: PlanePublicationStage, assignments: AssignmentRegistry, authority_index: Arc>, /// The process-local Zone authority operation ledger (U14): generation @@ -3226,9 +3252,7 @@ impl ZoneResourceRuntime { authority_ready: true, core_stage, }, - policy_installed: true, - controller_endpoint_registered: false, - watch_admitted: false, + publication_stage: PlanePublicationStage::BootstrapOnly, assignments, authority_index, authority_ledger, @@ -3466,9 +3490,7 @@ impl ZoneResourceRuntime { .service_task .lock() .await = Some(zone_service_task); - self.policy_installed = true; - self.controller_endpoint_registered = true; - self.watch_admitted = true; + self.publication_stage = PlanePublicationStage::Published; self.activate_committed_plane_state().await } @@ -6975,9 +6997,7 @@ impl ControllerSessionCoordinator { service_task, assignments: BTreeMap::new(), assignment_stream_open: false, - assignments_revoked: false, - transport_closed: false, - ingress_revoked: false, + teardown_stage: TeardownStage::Active, }); let inserted = { let mut sessions = self.controller_sessions.lock().await; @@ -7608,7 +7628,7 @@ impl ControllerSessionCoordinator { (context, session) }; - if !session.ingress_revoked { + if session.teardown_stage == TeardownStage::Active { if let Err(error) = self .revoke_controller_ingress_in_place(&mut session.ingress) .await @@ -7619,7 +7639,7 @@ impl ControllerSessionCoordinator { } return Err(error); } - session.ingress_revoked = true; + session.teardown_stage = TeardownStage::IngressRevoked; } self.credential_sessions.remove( @@ -7627,13 +7647,13 @@ impl ControllerSessionCoordinator { session.binding.session_generation(), ); - if !session.assignments_revoked { + if session.teardown_stage == TeardownStage::IngressRevoked { self.revoke_controller_assignments(&session.binding); send_controller_assignment_revocations(&session.driver, &session.assignments).await; - session.assignments_revoked = true; + session.teardown_stage = TeardownStage::AssignmentsRevoked; } - if !session.transport_closed { + if session.teardown_stage == TeardownStage::AssignmentsRevoked { session.cancel_backend_lease(); let _ = session .driver @@ -7644,7 +7664,7 @@ impl ControllerSessionCoordinator { .await; session.service_task.abort(); let _ = (&mut session.service_task).await; - session.transport_closed = true; + session.teardown_stage = TeardownStage::TransportClosed; } if let Err(error) = self @@ -8098,21 +8118,15 @@ impl ZoneResourceRuntime { /// Return the first startup gate that prevents publication. pub fn readiness_error(&self) -> Option { - if !self.policy_installed { - return Some(ResourceRuntimeError::PolicyUnavailable); - } if !self.readiness.resource_api_ready { return Some(ResourceRuntimeError::PolicyUnavailable); } - if !self.controller_endpoint_registered { + if self.publication_stage == PlanePublicationStage::BootstrapOnly { return Some(ResourceRuntimeError::ControllerEndpointUnavailable); } if !self.readiness.local_session_ready { return Some(ResourceRuntimeError::AuthenticationUnavailable); } - if !self.watch_admitted { - return Some(ResourceRuntimeError::WatchUnavailable); - } if !self.readiness.authority_ready || self .authority_index From 73f90a27e93a9d36942287072f2f8a9c398aee53 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:06:13 -0700 Subject: [PATCH 263/726] d2bd: carry the error and caller fields in cloud hypervisor warns --- packages/d2bd/src/resource_runtime.rs | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 56ce8f8cb..7ba5c7ebd 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -2033,14 +2033,14 @@ impl CloudHypervisorResourceSession { guest: &StoredResource, origin: StoredRowOrigin, ) -> Result { - let envelope = ResourceEnvelope::from_json(&guest.canonical_json).map_err(|_| { - tracing::warn!("Cloud Hypervisor Guest snapshot failed: envelope"); + let envelope = ResourceEnvelope::from_json(&guest.canonical_json).map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor Guest snapshot failed: envelope"); CloudHypervisorResourceApiError::InvalidResponse })?; let system_artifact_id = serde_json::from_slice::(&envelope.spec().base().to_canonical_bytes()) - .map_err(|_| { - tracing::warn!("Cloud Hypervisor Guest snapshot failed: spec"); + .map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor Guest snapshot failed: spec"); CloudHypervisorResourceApiError::InvalidResponse })? .system_artifact_id() @@ -2080,8 +2080,8 @@ impl CloudHypervisorResourceSession { ), deleting, ) - .map_err(|_| { - tracing::warn!("Cloud Hypervisor Guest snapshot failed: construction"); + .map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor Guest snapshot failed: construction"); CloudHypervisorResourceApiError::InvalidResponse })? .with_controller_finalizer_present(guest_controller_finalizer_present( @@ -2428,12 +2428,12 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { .get_stored(&guest_ref, "cloud-hypervisor-update-status") .await?; let current_value: Value = serde_json::from_slice(¤t.canonical_json) - .map_err(|_| { - tracing::warn!("Cloud Hypervisor status update failed: current-resource"); + .map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor status update failed: current-resource"); CloudHypervisorResourceApiError::InvalidResponse })?; - let mut desired_status = serde_json::to_value(status.status()).map_err(|_| { - tracing::warn!("Cloud Hypervisor status update failed: status-serialization"); + let mut desired_status = serde_json::to_value(status.status()).map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor status update failed: status-serialization"); CloudHypervisorResourceApiError::InvalidResponse })?; let provider_phase = desired_status @@ -4862,15 +4862,15 @@ impl ZoneResourceRuntime { }; let mut guest_outcome = CloudHypervisorReconcileOutcome::Ready; let descriptor = GuestSetupDescriptor::from_canonical_bytes(descriptor_bytes) - .map_err(|_| { - tracing::warn!("Cloud Hypervisor reconcile stage failed: descriptor-decode"); + .map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor reconcile stage failed: descriptor-decode"); ResourceRuntimeError::CapabilityUnavailable })? .verify_with(&CatalogDescriptorVerifier { expected_key: expected_key.clone(), }) - .map_err(|_| { - tracing::warn!("Cloud Hypervisor reconcile stage failed: descriptor-verify"); + .map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor reconcile stage failed: descriptor-verify"); ResourceRuntimeError::CapabilityUnavailable })?; let (provider_ref, execution_ref, config, graph) = @@ -5024,8 +5024,8 @@ impl ZoneResourceRuntime { Arc::new(adapter), ) .map(|controller| controller.with_lifecycle_intent(lifecycle_intent)) - .map_err(|_| { - tracing::warn!("Cloud Hypervisor reconcile stage failed: controller-construction"); + .map_err(|error| { + tracing::warn!(?error, "Cloud Hypervisor reconcile stage failed: controller-construction"); ResourceRuntimeError::CapabilityUnavailable })?; controller @@ -7183,7 +7183,11 @@ impl ControllerSessionCoordinator { ) -> Result<(), ResourceRuntimeError> { match controller_assignment_refresh_action(context, error) { ControllerAssignmentRefreshAction::Retryable { .. } => { - tracing::warn!("external Provider controller assignment reconciliation will retry"); + tracing::warn!( + provider = %context.process_provider_ref(), + process = %context.process_ref(), + "external Provider controller assignment reconciliation will retry" + ); Ok(()) } ControllerAssignmentRefreshAction::Failed { context, error } => { From 148bbd9c87c054524b6580d99960fddabbdb2984 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:07:33 -0700 Subject: [PATCH 264/726] audit: record two pre-existing broker build findings --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 2119b8665..ed9d10993 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -19,6 +19,13 @@ Measured at `147a536a0` in a dedicated gates worktree before any wave-0 fix land | Layer-1 aggregate | `make check` | pass (988 of 988 tests) | none | | host integration | `make test-host-integration` | pass (11 of 11 vmChecks) | Attic closure-upload warning only, non-fatal | +### Pre-existing findings observed at apply time + +Defects the audited surfaces carry at HEAD that no corpus row claims and no wave fixes. They are recorded here so a later reader does not mistake them for wave regressions, and they route to an ordinary review pass or the owning package owner rather than to a leaf row. + +- `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Observed at the wave-2 base. A test-only allow is the broker package owner's policy call. +- `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. + ## Wave gates Each wave closes on the same gate set, run on the wave's integrated head in the gates worktree. `base` is the commit the scan measures changed lines against. From c14b5d4860b8d508457aeaa1404496fe8213da79 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:11:40 -0700 Subject: [PATCH 265/726] d2bd-runtime: classify serde parse errors structurally --- packages/d2bd-runtime/src/wire.rs | 32 ++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/d2bd-runtime/src/wire.rs b/packages/d2bd-runtime/src/wire.rs index 6a39b3ad4..518f436bb 100644 --- a/packages/d2bd-runtime/src/wire.rs +++ b/packages/d2bd-runtime/src/wire.rs @@ -527,13 +527,31 @@ fn hello_rejected_reason(error: &TypedError) -> HelloRejectedReason { } fn map_parse_error(error: serde_json::Error) -> TypedError { - let detail = error.to_string(); - if detail.contains("unknown field") { - TypedError::WireUnknownField { detail } - } else if detail.contains("interface name") { - TypedError::WireIfNameInvalid { detail } - } else { - TypedError::WireInvalidFrame { detail } + match error.classify() { + serde_json::error::Category::Data => { + // Payload-level rejection. Every request payload type denies + // unknown fields, so an extra field arrives as serde's + // deterministic deny_unknown_fields rejection; the IfName + // deserializer produces the interface-name rejection. Both are + // pinned by serde's stable unknown-field helper and the IfName + // messages, not by serde_json's parser wording. + let detail = error.to_string(); + if detail.contains("unknown field") { + TypedError::WireUnknownField { detail } + } else if detail.contains("interface name") { + TypedError::WireIfNameInvalid { detail } + } else { + TypedError::WireInvalidFrame { detail } + } + } + _ => TypedError::WireInvalidFrame { + detail: format!( + "{} at line {} column {}", + error, + error.line(), + error.column() + ), + }, } } From 3e78efe56fe2015c965b35331fd3fa134be90af3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:11:46 -0700 Subject: [PATCH 266/726] d2bd-runtime: dispatch plain request verbs via tagged enum --- packages/d2bd-runtime/src/wire.rs | 150 ++++++++++++++++++------------ 1 file changed, 89 insertions(+), 61 deletions(-) diff --git a/packages/d2bd-runtime/src/wire.rs b/packages/d2bd-runtime/src/wire.rs index 518f436bb..eb3f4e42a 100644 --- a/packages/d2bd-runtime/src/wire.rs +++ b/packages/d2bd-runtime/src/wire.rs @@ -4,7 +4,7 @@ use d2b_contracts_broker::broker_wire::ExportBrokerAuditResponse; use d2b_contracts_control::public_wire::{self, AuditResponse, AuthStatusResponse}; use d2b_contracts_resource::v3::ResourceRef; use semver::{Version as SemverVersion, VersionReq}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::{Map, Value, json}; use std::collections::BTreeMap; @@ -253,6 +253,59 @@ pub fn parse_hello(bytes: &[u8]) -> Result { serde_json::from_value(value).map_err(map_parse_error) } +/// Internally-tagged parse shape for the plain request verbs. +/// +/// The `type` field dispatches to the matching payload type; every payload +/// type carries `deny_unknown_fields`, so an extra field is rejected at the +/// boundary. The verbs with custom envelope handling (authStatus/usbipProbe +/// empty-body checks, console `opId` removal, resourceRequest passthrough) +/// stay explicit in [`parse_request`]. +#[derive(Debug, Deserialize)] +#[serde(tag = "type", rename_all = "camelCase")] +enum RequestParse { + List(public_wire::ListRequest), + Status(public_wire::StatusRequest), + Audit(public_wire::AuditRequest), + VmStart(public_wire::VmLifecycleRequest), + VmStop(public_wire::VmLifecycleRequest), + VmRestart(public_wire::VmLifecycleRequest), + Switch(public_wire::ActivationRequest), + Boot(public_wire::ActivationRequest), + Test(public_wire::ActivationRequest), + Rollback(public_wire::ActivationRequest), + UsbipBind(public_wire::UsbipBindCliRequest), + UsbipUnbind(public_wire::UsbipUnbindCliRequest), + HostPrepare(public_wire::HostPrepareRequest), + HostDestroy(public_wire::HostDestroyRequest), + HostReconcile(public_wire::HostReconcileRequest), + Workload(public_wire::WorkloadOp), + Audio(public_wire::AudioOp), +} + +impl RequestParse { + fn into_request(self) -> Request { + match self { + Self::List(payload) => Request::List(payload), + Self::Status(payload) => Request::Status(payload), + Self::Audit(payload) => Request::Audit(payload), + Self::VmStart(payload) => Request::VmStart(payload), + Self::VmStop(payload) => Request::VmStop(payload), + Self::VmRestart(payload) => Request::VmRestart(payload), + Self::Switch(payload) => Request::Switch(payload), + Self::Boot(payload) => Request::Boot(payload), + Self::Test(payload) => Request::Test(payload), + Self::Rollback(payload) => Request::Rollback(payload), + Self::UsbipBind(payload) => Request::UsbipBind(payload), + Self::UsbipUnbind(payload) => Request::UsbipUnbind(payload), + Self::HostPrepare(payload) => Request::HostPrepare(payload), + Self::HostDestroy(payload) => Request::HostDestroy(payload), + Self::HostReconcile(payload) => Request::HostReconcile(payload), + Self::Workload(payload) => Request::Workload(payload), + Self::Audio(payload) => Request::Audio(payload), + } + } +} + pub fn parse_request(bytes: &[u8]) -> Result { let mut value: Value = serde_json::from_slice(bytes).map_err(|err| TypedError::WireInvalidFrame { @@ -265,23 +318,14 @@ pub fn parse_request(bytes: &[u8]) -> Result { detail: "missing request type".to_owned(), })? .to_owned(); - let object = value - .as_object_mut() - .ok_or_else(|| TypedError::WireInvalidFrame { - detail: "request frame must be a JSON object".to_owned(), - })?; - object.remove("type"); match request_type.as_str() { - "list" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::List) - .map_err(map_parse_error), - "status" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Status) - .map_err(map_parse_error), - "audit" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Audit) - .map_err(map_parse_error), "authStatus" => { + let object = value + .as_object_mut() + .ok_or_else(|| TypedError::WireInvalidFrame { + detail: "request frame must be a JSON object".to_owned(), + })?; + object.remove("type"); if object.is_empty() { Ok(Request::AuthStatus) } else { @@ -290,34 +334,13 @@ pub fn parse_request(bytes: &[u8]) -> Result { }) } } - "vmStart" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::VmStart) - .map_err(map_parse_error), - "vmStop" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::VmStop) - .map_err(map_parse_error), - "vmRestart" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::VmRestart) - .map_err(map_parse_error), - "switch" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Switch) - .map_err(map_parse_error), - "boot" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Boot) - .map_err(map_parse_error), - "test" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Test) - .map_err(map_parse_error), - "rollback" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Rollback) - .map_err(map_parse_error), - "usbipBind" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::UsbipBind) - .map_err(map_parse_error), - "usbipUnbind" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::UsbipUnbind) - .map_err(map_parse_error), "usbipProbe" => { + let object = value + .as_object_mut() + .ok_or_else(|| TypedError::WireInvalidFrame { + detail: "request frame must be a JSON object".to_owned(), + })?; + object.remove("type"); if object.is_empty() { Ok(Request::UsbipProbe) } else { @@ -326,30 +349,35 @@ pub fn parse_request(bytes: &[u8]) -> Result { }) } } - "hostPrepare" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::HostPrepare) - .map_err(map_parse_error), - "hostDestroy" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::HostDestroy) - .map_err(map_parse_error), - "hostReconcile" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::HostReconcile) - .map_err(map_parse_error), "console" => { + let object = value + .as_object_mut() + .ok_or_else(|| TypedError::WireInvalidFrame { + detail: "request frame must be a JSON object".to_owned(), + })?; + object.remove("type"); object.remove("opId"); serde_json::from_value(Value::Object(object.clone())) .map(Request::Console) .map_err(map_parse_error) } - "workload" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Workload) - .map_err(map_parse_error), - "audio" => serde_json::from_value(Value::Object(object.clone())) - .map(Request::Audio) - .map_err(map_parse_error), - "resourceRequest" => Ok(Request::Resource(ResourceRequest { - fields: object.clone().into_iter().collect(), - })), + "resourceRequest" => { + let object = value + .as_object_mut() + .ok_or_else(|| TypedError::WireInvalidFrame { + detail: "request frame must be a JSON object".to_owned(), + })?; + object.remove("type"); + Ok(Request::Resource(ResourceRequest { + fields: object.clone().into_iter().collect(), + })) + } + "list" | "status" | "audit" | "vmStart" | "vmStop" | "vmRestart" | "switch" + | "boot" | "test" | "rollback" | "usbipBind" | "usbipUnbind" | "hostPrepare" + | "hostDestroy" | "hostReconcile" | "workload" | "audio" => { + let parsed: RequestParse = serde_json::from_value(value).map_err(map_parse_error)?; + Ok(parsed.into_request()) + } _ => Err(TypedError::WireUnsupportedRequest { request_type }), } } From 2ab7a1ed258234c2e304d942a8e721962290de35 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:12:27 -0700 Subject: [PATCH 267/726] d2b-provider-user: derive driver failure codes from the registry --- packages/d2b-provider-user/src/driver.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/d2b-provider-user/src/driver.rs b/packages/d2b-provider-user/src/driver.rs index e2142ee23..dc24f4b8f 100644 --- a/packages/d2b-provider-user/src/driver.rs +++ b/packages/d2b-provider-user/src/driver.rs @@ -117,11 +117,7 @@ impl UserDriverError { impl core::fmt::Display for UserDriverError { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter.write_str(match self.kind { - UserDriverErrorKind::SpecInvalid => "system-core-spec-invalid", - UserDriverErrorKind::UserDiscovery => "system-core-user-discovery-failed", - UserDriverErrorKind::DrainPending => "system-core-drain-pending", - }) + formatter.write_str(self.kind.failure_kind().code()) } } From dfe70fe8fb5f288a23dc02e49d20188dc0b8a9a3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:14:44 -0700 Subject: [PATCH 268/726] d2b-core-controller: name the optional otel Provider cardinality constant --- packages/d2b-core-controller/src/authority.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/d2b-core-controller/src/authority.rs b/packages/d2b-core-controller/src/authority.rs index 5f9e9125e..7a0ab95f2 100644 --- a/packages/d2b-core-controller/src/authority.rs +++ b/packages/d2b-core-controller/src/authority.rs @@ -38,6 +38,9 @@ pub const EXTERNAL_PHYSICAL_NIC_AUTHORITY_CLASS: &str = "external-physical-nic"; pub const PHYSICAL_USB_BACKING_IDENTITY_DOMAIN: &str = "physical-usb-backing/v1"; /// Domain tag for Core-derived USBIP relay endpoint identities. pub const USBIP_NETWORK_RELAY_IDENTITY_DOMAIN: &str = "usbip-network-relay/v1"; +/// The one Provider with optional controller cardinality: telemetry may be +/// absent from a Zone, so its claim is AtMostOne instead of ExactlyOne. +const OPTIONAL_PROVIDER_REF: &str = "Provider/observability-otel"; #[allow(dead_code)] const MAX_RESOLVED_NIC_IDENTITY_BYTES: usize = 256; static NEXT_AUTHORITY_INDEX_NONCE: AtomicU64 = AtomicU64::new(1); @@ -982,7 +985,7 @@ impl AuthorityRequest { provider_ref: ResourceRef, owner_proof: AuthorityOwnerProof, ) -> Result { - let cardinality = if provider_ref.to_canonical_string() == "Provider/observability-otel" { + let cardinality = if provider_ref.to_canonical_string() == OPTIONAL_PROVIDER_REF { ProviderCardinality::AtMostOne } else { ProviderCardinality::ExactlyOne From 58e72374f38f2299676a0fed3981ca97becf9baf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:14:50 -0700 Subject: [PATCH 269/726] d2b-contracts-provider: report zero publication generation as ZeroGeneration --- packages/d2b-contracts-provider/src/v3/provider_registry.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/d2b-contracts-provider/src/v3/provider_registry.rs b/packages/d2b-contracts-provider/src/v3/provider_registry.rs index 176e658c4..8ba63b3d9 100644 --- a/packages/d2b-contracts-provider/src/v3/provider_registry.rs +++ b/packages/d2b-contracts-provider/src/v3/provider_registry.rs @@ -183,7 +183,10 @@ impl ProviderRegistryPublication { generation: ResourceGeneration, mut entries: Vec, ) -> Result { - if generation.get() == 0 || entries.len() > MAX_PROVIDER_REGISTRY_MAPPINGS { + if generation.get() == 0 { + return Err(ProviderRegistryError::ZeroGeneration); + } + if entries.len() > MAX_PROVIDER_REGISTRY_MAPPINGS { return Err(ProviderRegistryError::MappingBoundExceeded); } if entries From 96cc7e5bb8721748ae8eea519ef7bb5707b56f52 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:16:10 -0700 Subject: [PATCH 270/726] d2b-core-controller: render DuplicateConflict code in kebab case --- packages/d2b-core-controller/src/authority.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2b-core-controller/src/authority.rs b/packages/d2b-core-controller/src/authority.rs index 7a0ab95f2..4d7c4ada5 100644 --- a/packages/d2b-core-controller/src/authority.rs +++ b/packages/d2b-core-controller/src/authority.rs @@ -412,7 +412,7 @@ impl AuthorityError { Self::AuthorityCapacityExceeded => "authority-capacity-exceeded", Self::UnknownAuthority => "authority-missing", Self::AuthorityCloseUnconfirmed => "authority-close-unconfirmed", - Self::DuplicateConflict => "duplicateConflict", + Self::DuplicateConflict => "duplicate-conflict", Self::PhysicalUsbBackingConflict => "physical-usb-backing-conflict", Self::UsbipNetworkRelayAuthorityConflict => "usbip-network-relay-authority-conflict", Self::InvalidVsockCid => "vsock-cid-invalid", @@ -3407,7 +3407,7 @@ mod tests { }) .unwrap_err() .code(), - "duplicateConflict" + "duplicate-conflict" ); assert_eq!(effects, 0); From ed46f196ba881d998e8d9a912bc44dbd7ea0e551 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:16:24 -0700 Subject: [PATCH 271/726] d2b-contracts-provider: split publication generation mismatch into its own error --- packages/d2b-contracts-provider/src/v3/provider_registry.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/d2b-contracts-provider/src/v3/provider_registry.rs b/packages/d2b-contracts-provider/src/v3/provider_registry.rs index 8ba63b3d9..139272f50 100644 --- a/packages/d2b-contracts-provider/src/v3/provider_registry.rs +++ b/packages/d2b-contracts-provider/src/v3/provider_registry.rs @@ -44,6 +44,7 @@ pub enum ProviderRegistryError { MappingBoundExceeded, UnknownAxis, AxisMismatch, + GenerationMismatch, } impl core::fmt::Display for ProviderRegistryError { @@ -57,6 +58,7 @@ impl core::fmt::Display for ProviderRegistryError { Self::MappingBoundExceeded => "provider-registry-mapping-bound-exceeded", Self::UnknownAxis => "provider-registry-axis-unknown", Self::AxisMismatch => "provider-registry-axis-mismatch", + Self::GenerationMismatch => "provider-registry-generation-mismatch", }) } } @@ -193,7 +195,7 @@ impl ProviderRegistryPublication { .iter() .any(|entry| entry.provider_generation != generation) { - return Err(ProviderRegistryError::AxisMismatch); + return Err(ProviderRegistryError::GenerationMismatch); } entries.sort_by(|left, right| left.mapping_id.cmp(&right.mapping_id)); if entries @@ -259,7 +261,7 @@ mod tests { ); assert_eq!( ProviderRegistryPublication::new(generation, vec![entry(3, "one")]).unwrap_err(), - ProviderRegistryError::AxisMismatch + ProviderRegistryError::GenerationMismatch ); assert_eq!( ProviderRegistryPublication::new(generation, vec![entry(4, "one"), entry(4, "one")]) From e95cfb6c51137d8133dccc8b5d64686912b89d65 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:16:38 -0700 Subject: [PATCH 272/726] d2b-core-controller: drop unwired assignment registry surface --- .../src/controller_assignment.rs | 289 +----------------- 1 file changed, 6 insertions(+), 283 deletions(-) diff --git a/packages/d2b-core-controller/src/controller_assignment.rs b/packages/d2b-core-controller/src/controller_assignment.rs index 5d866d185..23df9bb2f 100644 --- a/packages/d2b-core-controller/src/controller_assignment.rs +++ b/packages/d2b-core-controller/src/controller_assignment.rs @@ -39,8 +39,6 @@ pub const MAX_ASSIGNMENT_GRANT_SCOPES: usize = 2; /// The maximum number of assignments held by one Zone authority. pub const MAX_ASSIGNMENTS: usize = 16_384; -/// Maximum child ownership entries retained by one assignment. -pub const MAX_ASSIGNED_CHILDREN: usize = 4_096; /// Assignment-bound query filter for the primary resource UID. pub const ASSIGNMENT_UID_FILTER: &str = "assignment.resourceUid"; /// Assignment-bound query filter for an owned child resource UID. @@ -324,8 +322,6 @@ pub enum AssignmentError { AssignmentMissing, AssignmentNotDraining, AssignmentNotReleased, - ChildrenRemain, - ChildLimit, StaleAssignment, SessionRevoked, ResourceRevisionMismatch, @@ -385,8 +381,6 @@ impl AssignmentError { Self::AssignmentMissing => "assignment-missing", Self::AssignmentNotDraining => "assignment-not-draining", Self::AssignmentNotReleased => "assignment-not-released", - Self::ChildrenRemain => "assignment-children-remain", - Self::ChildLimit => "assignment-child-limit", Self::StaleAssignment => "assignment-stale", Self::SessionRevoked => "assignment-session-revoked", Self::ResourceRevisionMismatch => "assignment-resource-revision-mismatch", @@ -2600,11 +2594,8 @@ impl ResourceClientLease { /// Admit a mutation against one Process child owned by this lease. /// - /// Successful commit receipts must be handed to - /// [`ControllerAssignmentRegistry::record_child`] and - /// [`ControllerAssignmentRegistry::remove_child`] by the controller - /// owner. Minting this capability does not pre-account a child that may - /// never commit. + /// Minting this capability does not account for a child that may never + /// commit. pub fn child_mutation( &self, target: ResourceRef, @@ -2633,15 +2624,6 @@ impl ResourceClientLease { owner_generation: self.resource_generation, } } - - /// Verify that a placement target remains exactly the admitted target. - pub fn target_for(&self, target: PlacementTarget) -> Result<(), AssignmentError> { - if self.target() == &AssignmentTarget::from_placement(target) { - Ok(()) - } else { - Err(AssignmentError::TargetMismatch) - } - } } impl fmt::Debug for ResourceClientLease { @@ -2665,7 +2647,6 @@ struct AssignmentRecord { provider_ref: ResourceRef, allowed_verbs: BTreeSet, state: Arc, - children: BTreeSet, } struct AssignmentLeaseState { @@ -2713,19 +2694,6 @@ impl fmt::Debug for ControllerAssignmentRegistry { } impl ControllerAssignmentRegistry { - /// Reserve the next assignment epoch after all durable observations. - pub fn reserve_epoch_after(&mut self, floor: u64) -> Result { - if self.next_epoch < floor { - self.next_epoch = floor; - } - let epoch = self - .next_epoch - .checked_add(1) - .ok_or(AssignmentError::EpochExhausted)?; - self.next_epoch = epoch; - AssignmentEpoch::new(epoch).map(|value| value.get()) - } - /// Admit one resource from the committed store snapshot. pub fn admit( &mut self, @@ -2849,7 +2817,6 @@ impl ControllerAssignmentRegistry { provider_ref: request.role.provider_ref.clone(), allowed_verbs: primary_verbs.clone(), state: Arc::clone(&state), - children: BTreeSet::new(), }, ); self.active_targets @@ -2871,39 +2838,6 @@ impl ControllerAssignmentRegistry { }) } - /// Rebind one live lease to the resource revision produced by its last - /// successful write without changing its assignment epoch. - pub fn rebind_revision( - &mut self, - lease: &mut ResourceClientLease, - revision: ZoneRevision, - ) -> Result<(), AssignmentError> { - let record = self - .records - .get_mut(lease.identity.resource_uid()) - .ok_or(AssignmentError::AssignmentMissing)?; - if record.identity != lease.identity { - return Err(AssignmentError::StaleAssignment); - } - if record.state.phase() == AssignmentPhase::Revoked { - return Err(AssignmentError::SessionRevoked); - } - if record.state.phase() != AssignmentPhase::Assigned { - return Err(AssignmentError::StaleAssignment); - } - if revision < lease.identity.resource_revision() { - return Err(AssignmentError::ResourceRevisionMismatch); - } - if revision == lease.identity.resource_revision() { - return Ok(()); - } - let mut identity = lease.identity.clone(); - identity.resource_revision = revision; - record.identity = identity.clone(); - lease.identity = identity; - Ok(()) - } - /// Return the current phase for an assignment identity. pub fn phase(&self, identity: &AssignmentIdentity) -> Option { self.records @@ -2932,9 +2866,6 @@ impl ControllerAssignmentRegistry { ) { return Err(AssignmentError::AssignmentNotReleased); } - if !record.children.is_empty() { - return Err(AssignmentError::ChildrenRemain); - } record.state.set_phase(AssignmentPhase::Released); self.remove_active_target(identity); Ok(()) @@ -2949,41 +2880,6 @@ impl ControllerAssignmentRegistry { Ok(()) } - /// Record one child resource in the assignment's narrow owner index. - pub fn record_child( - &mut self, - identity: &AssignmentIdentity, - child_uid: ResourceUid, - ) -> Result<(), AssignmentError> { - let record = self.record_mut(identity)?; - if record.children.len() >= MAX_ASSIGNED_CHILDREN { - return Err(AssignmentError::ChildLimit); - } - record.children.insert(child_uid); - Ok(()) - } - - /// Remove one child after its terminal deletion is committed. - pub fn remove_child( - &mut self, - identity: &AssignmentIdentity, - child_uid: &ResourceUid, - ) -> Result<(), AssignmentError> { - let record = self.record_mut(identity)?; - if !record.children.remove(child_uid) { - return Err(AssignmentError::AssignmentMissing); - } - Ok(()) - } - - /// Return the currently indexed child UIDs. - pub fn child_uids(&self, identity: &AssignmentIdentity) -> Option<&BTreeSet> { - self.records - .get(identity.resource_uid()) - .filter(|record| record.identity == *identity) - .map(|record| &record.children) - } - /// Revoke all assignments bound to a disconnected session generation. pub fn revoke_session(&mut self, generation: ReconnectGeneration) { let revoked = self @@ -3060,39 +2956,6 @@ impl ControllerAssignmentRegistry { } } - /// Validate a writer against every assignment fence. - pub fn validate_writer( - &self, - identity: &AssignmentIdentity, - uid: &ResourceUid, - revision: ZoneRevision, - verb: AssignmentVerb, - ) -> Result<(), AssignmentError> { - let record = self - .records - .get(identity.resource_uid()) - .ok_or(AssignmentError::AssignmentMissing)?; - if record.identity != *identity { - return Err(AssignmentError::StaleAssignment); - } - if record.state.phase() == AssignmentPhase::Revoked { - return Err(AssignmentError::SessionRevoked); - } - if !record.state.phase().admits_mutation() { - return Err(AssignmentError::StaleAssignment); - } - if record.identity.resource_uid() != uid { - return Err(AssignmentError::ResourceUidMismatch); - } - if record.identity.resource_revision() != revision { - return Err(AssignmentError::ResourceRevisionMismatch); - } - if !record.allowed_verbs.contains(&verb) { - return Err(AssignmentError::VerbNotAllowed); - } - Ok(()) - } - /// Validate a read or mutation lease without a new resource snapshot. pub fn validate_scope( &self, @@ -3126,14 +2989,6 @@ impl ControllerAssignmentRegistry { Ok(()) } - /// Whether the last committed observation must be retained as stale. - pub fn observation_is_stale(&self, identity: &AssignmentIdentity) -> bool { - self.records - .get(identity.resource_uid()) - .filter(|record| record.identity == *identity) - .is_some_and(|record| record.state.stale_observation.load(Ordering::Acquire)) - } - fn record_mut( &mut self, identity: &AssignmentIdentity, @@ -3174,9 +3029,9 @@ mod tests { use d2b_contracts_resource::v3::execution_policy::BoundedToken; use d2b_contracts_resource::v3::identity::ReconnectGeneration; use d2b_contracts_resource::v3::{ - ControllerGeneration, PlacementAnchor, PlacementTarget, ResourceEnvelope, - ResourceGeneration, ResourceRef, ResourceTypeName, ResourceUid, SchemaFingerprint, - SchemaVersion, ZoneRevision, + ControllerGeneration, PlacementAnchor, ResourceEnvelope, + ResourceGeneration, ResourceRef, ResourceTypeName, SchemaFingerprint, + SchemaVersion, }; use super::{ @@ -3464,37 +3319,6 @@ mod tests { ); } - #[test] - fn stale_assignment_epoch_rejects_status_and_finalizer_writers() { - let resource = process("process", "Guest/dev-vm", 7); - let role = role(); - let mut registry = ControllerAssignmentRegistry::default(); - let old = registry.admit(request(&resource, &role, 1, 1, 1)).unwrap(); - registry.begin_drain(old.identity()).unwrap(); - registry.release(old.identity()).unwrap(); - let new = registry.admit(request(&resource, &role, 1, 1, 2)).unwrap(); - - assert_eq!( - registry.validate_writer( - old.identity(), - &resource.metadata().uid().clone(), - resource.metadata().revision(), - AssignmentVerb::UpdateStatus, - ), - Err(AssignmentError::StaleAssignment) - ); - assert!( - registry - .validate_writer( - new.identity(), - &resource.metadata().uid().clone(), - resource.metadata().revision(), - AssignmentVerb::UpdateFinalizers, - ) - .is_ok() - ); - } - #[test] fn scoped_commit_transport_round_trips_assignment_and_mutations() { let resource = process("process", "Guest/dev-vm", 7); @@ -3542,71 +3366,7 @@ mod tests { } #[test] - fn same_epoch_rebind_updates_the_active_writer_revision() { - let resource = process("process", "Guest/dev-vm", 7); - let role = role(); - let mut registry = ControllerAssignmentRegistry::default(); - let mut lease = registry.admit(request(&resource, &role, 1, 1, 1)).unwrap(); - let stale = lease.identity().clone(); - - registry - .rebind_revision(&mut lease, ZoneRevision::new(8)) - .unwrap(); - - assert_eq!(lease.identity().resource_revision(), ZoneRevision::new(8)); - assert!( - registry - .validate_writer( - lease.identity(), - resource.metadata().uid(), - ZoneRevision::new(8), - AssignmentVerb::UpdateStatus, - ) - .is_ok() - ); - assert_eq!( - registry.validate_writer( - &stale, - resource.metadata().uid(), - ZoneRevision::new(7), - AssignmentVerb::UpdateStatus, - ), - Err(AssignmentError::StaleAssignment) - ); - } - - #[test] - fn released_assignment_allows_successor_at_the_current_revision() { - let resource = process("process", "Guest/dev-vm", 7); - let role = role(); - let mut registry = ControllerAssignmentRegistry::default(); - let mut old = registry.admit(request(&resource, &role, 1, 1, 1)).unwrap(); - registry - .rebind_revision(&mut old, ZoneRevision::new(8)) - .unwrap(); - registry.begin_drain(old.identity()).unwrap(); - registry.release(old.identity()).unwrap(); - - let current = process("process", "Guest/dev-vm", 8); - let successor = registry.admit(request(¤t, &role, 2, 2, 2)).unwrap(); - assert_eq!( - successor.identity().resource_revision(), - ZoneRevision::new(8) - ); - assert!( - registry - .validate_writer( - successor.identity(), - current.metadata().uid(), - ZoneRevision::new(8), - AssignmentVerb::UpdateFinalizers, - ) - .is_ok() - ); - } - - #[test] - fn disconnected_session_revokes_mutation_but_keeps_stale_observation() { + fn disconnected_session_revokes_mutation() { let resource = process("process", "Guest/dev-vm", 7); let role = role(); let mut registry = ControllerAssignmentRegistry::default(); @@ -3640,16 +3400,6 @@ mod tests { ), Err(AssignmentError::SessionRevoked) ); - assert_eq!( - registry.validate_writer( - lease.identity(), - resource.metadata().uid(), - resource.metadata().revision(), - AssignmentVerb::UpdateStatus, - ), - Err(AssignmentError::SessionRevoked) - ); - assert!(registry.observation_is_stale(lease.identity())); } #[test] @@ -3898,13 +3648,6 @@ mod tests { ), Err(AssignmentError::ResourceNotAssigned) ); - assert_eq!( - lease.target_for(PlacementTarget::Execution { - kind: d2b_contracts_resource::v3::PlacementTargetKind::Host, - reference: ResourceRef::parse("Host/host-system").unwrap(), - }), - Err(AssignmentError::TargetMismatch) - ); } #[test] @@ -4065,26 +3808,6 @@ mod tests { assert_eq!(replacement.identity().controller_generation().get(), 2); } - #[test] - fn child_index_must_drain_before_parent_release() { - let resource = process("process", "Guest/dev-vm", 7); - let role = role(); - let mut registry = ControllerAssignmentRegistry::default(); - let lease = registry.admit(request(&resource, &role, 1, 1, 1)).unwrap(); - let child = ResourceUid::parse("423e4567-e89b-42d3-a456-426614174003").unwrap(); - registry - .record_child(lease.identity(), child.clone()) - .unwrap(); - registry.begin_drain(lease.identity()).unwrap(); - assert_eq!( - registry.release(lease.identity()), - Err(AssignmentError::ChildrenRemain) - ); - assert_eq!(registry.child_uids(lease.identity()).unwrap().len(), 1); - registry.remove_child(lease.identity(), &child).unwrap(); - registry.release(lease.identity()).unwrap(); - } - #[test] fn ambiguous_or_unready_targets_fail_closed_without_fallback() { let resource = process("process", "Guest/dev-vm", 7); From e783447e25a737a41454f61cf18c390acad2ef54 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:17:17 -0700 Subject: [PATCH 273/726] d2b-provider-wayland-session: log display child derivation failures before mapping --- Cargo.lock | 1 + packages/d2b-provider-wayland-session/Cargo.toml | 1 + .../d2b-provider-wayland-session/src/wayland_session.rs | 9 ++++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index f023ce55f..6553c5eb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1981,6 +1981,7 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "serde_json", + "tracing", ] [[package]] diff --git a/packages/d2b-provider-wayland-session/Cargo.toml b/packages/d2b-provider-wayland-session/Cargo.toml index e4d176bf0..f14a16bba 100644 --- a/packages/d2b-provider-wayland-session/Cargo.toml +++ b/packages/d2b-provider-wayland-session/Cargo.toml @@ -20,6 +20,7 @@ d2b-provider-display-wayland = { path = "../d2b-provider-display-wayland", versi d2b-provider-wayland-policy = { path = "../d2b-provider-wayland-policy", version = "0.0.0-bootstrap" } d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-bootstrap" } d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } +tracing = "0.1" [dev-dependencies] async-trait = "0.1" diff --git a/packages/d2b-provider-wayland-session/src/wayland_session.rs b/packages/d2b-provider-wayland-session/src/wayland_session.rs index 5fff544b2..64d92ac37 100644 --- a/packages/d2b-provider-wayland-session/src/wayland_session.rs +++ b/packages/d2b-provider-wayland-session/src/wayland_session.rs @@ -84,7 +84,14 @@ impl DisplayChildSource for SessionChildSource { request.spec, request.process_generation, ) - .map_err(|_| InteractionEffectError::InvalidResource) + .map_err(|error| { + tracing::warn!( + provider = WAYLAND_SESSION_PROVIDER_REF, + reason = %error, + "display child derivation failed for wayland session" + ); + InteractionEffectError::InvalidResource + }) } } From e3ae48716e054be733ef5fa64acf690367e7c4a6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:17:17 -0700 Subject: [PATCH 274/726] d2b-provider-endpoint: validate attachment policy at deserialization --- .../d2b-provider-endpoint/src/endpoint.rs | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-endpoint/src/endpoint.rs b/packages/d2b-provider-endpoint/src/endpoint.rs index 3cdbe06e4..fef4b1a1d 100644 --- a/packages/d2b-provider-endpoint/src/endpoint.rs +++ b/packages/d2b-provider-endpoint/src/endpoint.rs @@ -109,7 +109,7 @@ pub enum EndpointOperation { } /// Endpoint attachment capacity. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct EndpointAttachmentPolicy { /// Whether this endpoint accepts attachments at all. @@ -136,6 +136,21 @@ impl EndpointAttachmentPolicy { } } +impl<'de> Deserialize<'de> for EndpointAttachmentPolicy { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct Wire { + #[serde(default)] + supported: bool, + #[serde(default)] + max_attachments: u16, + } + let wire = Wire::deserialize(deserializer)?; + Self::new(wire.supported, wire.max_attachments).map_err(serde::de::Error::custom) + } +} + /// The only fine-grained endpoint consumer policy. #[derive(Clone, PartialEq, Eq, Default, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] @@ -500,6 +515,30 @@ mod tests { assert!(serde_json::from_value::(object).is_err()); } + #[test] + fn attachment_policy_round_trips_and_rejects_inconsistent_shapes() { + let policy = EndpointAttachmentPolicy::new(true, 2).unwrap(); + let value = serde_json::to_value(policy).unwrap(); + assert_eq!( + serde_json::from_value::(value).unwrap(), + policy + ); + for (supported, max_attachments) in [ + (false, 1), + (true, 0), + (true, MAX_ENDPOINT_ATTACHMENTS + 1), + ] { + let value = serde_json::json!({ + "supported": supported, + "maxAttachments": max_attachments, + }); + assert!( + serde_json::from_value::(value).is_err(), + "illegal attachment policy ({supported}, {max_attachments}) admitted" + ); + } + } + #[test] fn producer_and_provider_references_are_type_checked() { let mut object = serde_json::to_value(minimal()).unwrap(); From e7b30fbf06dce776cb9bcdd046b38a63ff3383c7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:17:23 -0700 Subject: [PATCH 275/726] d2b-provider-transport-unix: keep errno in transport portal warnings --- packages/d2b-provider-transport-unix/src/portal.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-transport-unix/src/portal.rs b/packages/d2b-provider-transport-unix/src/portal.rs index 75ec675ae..e24f6987e 100644 --- a/packages/d2b-provider-transport-unix/src/portal.rs +++ b/packages/d2b-provider-transport-unix/src/portal.rs @@ -220,9 +220,10 @@ impl TransportPortal { ); PortalError::from(error) })?; - let accepted = AcceptedTransport::bind(binding, fd).map_err(|_| { + let accepted = AcceptedTransport::bind(binding, fd).map_err(|error| { tracing::warn!( provider = "transport-unix", + reason = %error, "transport open rejected: peer credentials unavailable on accepted socket" ); PortalError::PeerCredentials @@ -247,9 +248,10 @@ impl TransportPortal { ); return Err(PortalError::HandleTableFull); } - let monitor_fd = fcntl_dupfd_cloexec(fd.as_fd(), 3).map_err(|_| { + let monitor_fd = fcntl_dupfd_cloexec(fd.as_fd(), 3).map_err(|error| { tracing::warn!( provider = "transport-unix", + reason = %error, "transport monitor fd duplication failed; open rejected" ); PortalError::Cloexec @@ -316,9 +318,10 @@ impl TransportPortal { &entry.monitor_fd, PollFlags::ERR | PollFlags::HUP | PollFlags::RDHUP, )]; - poll(&mut fds, 0).map_err(|_| { + poll(&mut fds, 0).map_err(|error| { tracing::warn!( provider = "transport-unix", + reason = %error, "transport observation poll failed" ); PortalError::MonitorUnavailable @@ -363,9 +366,10 @@ impl fmt::Debug for TransportPortal { fn next_handle(state: &PortalState) -> Result { for _ in 0..8 { let mut bytes = [0_u8; 16]; - fill(&mut bytes).map_err(|_| { + fill(&mut bytes).map_err(|error| { tracing::warn!( provider = "transport-unix", + reason = %error, "transport handle generation failed: entropy source unavailable" ); PortalError::MonitorUnavailable From a085f811d0349c1d19b0bfda17fd796f2f482511 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:17:27 -0700 Subject: [PATCH 276/726] d2b-provider-credential-secret-service: add structured fields to session-close warning --- packages/d2b-provider-credential-secret-service/src/service.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/d2b-provider-credential-secret-service/src/service.rs b/packages/d2b-provider-credential-secret-service/src/service.rs index 68bc363a7..5708aca2c 100644 --- a/packages/d2b-provider-credential-secret-service/src/service.rs +++ b/packages/d2b-provider-credential-secret-service/src/service.rs @@ -868,6 +868,9 @@ impl SecretServiceCredentialProvider { } if unresolved_leases || unresolved_operations { tracing::warn!( + provider = crate::PROVIDER_REF, + unresolved_leases, + unresolved_operations, "secret-service session close left unresolved leases or ambiguous operations", ); return Err(invariant()); From d0bbf947a89aaa65c00439045a1e7943cca54d70 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:18:40 -0700 Subject: [PATCH 277/726] d2b: make host_generation module private --- packages/d2b/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b/src/lib.rs b/packages/d2b/src/lib.rs index a018f8859..1c2f39f61 100644 --- a/packages/d2b/src/lib.rs +++ b/packages/d2b/src/lib.rs @@ -25,7 +25,7 @@ mod exec_client; mod generated; mod guest; mod host; -pub mod host_generation; +mod host_generation; mod host_validate; mod provider; mod resource; From 442b4cb314ef7447c8b59fc8a71c3b1d69a2bdc3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:19:04 -0700 Subject: [PATCH 278/726] d2b-core-controller: drop unwired zone coordinator surface --- .../d2b-core-controller/src/coordinator.rs | 182 +----------------- 1 file changed, 4 insertions(+), 178 deletions(-) diff --git a/packages/d2b-core-controller/src/coordinator.rs b/packages/d2b-core-controller/src/coordinator.rs index 914b5e138..2b9970f88 100644 --- a/packages/d2b-core-controller/src/coordinator.rs +++ b/packages/d2b-core-controller/src/coordinator.rs @@ -7,7 +7,7 @@ use std::collections::{BTreeMap, btree_map::Entry}; -use d2b_contracts_resource::v3::{ResourceBundleGenerationId, ZoneId}; +use d2b_contracts_resource::v3::ZoneId; /// Closed failure from the per-Zone coordinator. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -18,16 +18,12 @@ pub enum CoordinatorError { VmNotRegistered, /// A VM was already bound to a different Zone. VmZoneConflict, - /// A USBIP reconciliation pass is already active for this Zone. - UsbipReconcileInFlight, /// An activation lock is already held for this Zone. ActivationInFlight, /// A different configuration generation is already staged for this Zone. ConfigurationStagingInFlight, /// The caller attempted to release a lock that is not held. LockNotHeld, - /// A shutdown generation cannot be zero. - InvalidShutdownGeneration, /// A shutdown generation cannot advance any further. ShutdownGenerationExhausted, /// A configuration generation cannot be zero. @@ -41,13 +37,11 @@ impl CoordinatorError { Self::ZoneNotRegistered => "zone-coordinator-zone-not-registered", Self::VmNotRegistered => "zone-coordinator-vm-not-registered", Self::VmZoneConflict => "zone-coordinator-vm-zone-conflict", - Self::UsbipReconcileInFlight => "zone-coordinator-usbip-reconcile-in-flight", Self::ActivationInFlight => "zone-coordinator-activation-in-flight", Self::ConfigurationStagingInFlight => { "zone-coordinator-configuration-staging-in-flight" } Self::LockNotHeld => "zone-coordinator-lock-not-held", - Self::InvalidShutdownGeneration => "zone-coordinator-shutdown-generation-invalid", Self::ShutdownGenerationExhausted => "zone-coordinator-shutdown-generation-exhausted", Self::InvalidConfigurationGeneration => { "zone-coordinator-configuration-generation-invalid" @@ -67,8 +61,6 @@ impl std::error::Error for CoordinatorError {} /// Per-Zone configuration staging state. #[derive(Clone, PartialEq, Eq)] pub struct ConfigurationStaging { - pub(crate) pending: Option, - pub(crate) active: Option, pub(crate) pending_ordinal: Option, pub(crate) active_ordinal: Option, } @@ -77,23 +69,11 @@ impl ConfigurationStaging { /// Create empty staging for one Zone. pub const fn empty() -> Self { Self { - pending: None, - active: None, pending_ordinal: None, active_ordinal: None, } } - /// Borrow the staged outgoing or candidate generation. - pub const fn pending(&self) -> Option<&ResourceBundleGenerationId> { - self.pending.as_ref() - } - - /// Borrow the active generation known to this coordinator. - pub const fn active(&self) -> Option<&ResourceBundleGenerationId> { - self.active.as_ref() - } - /// Return the staged configuration ordinal used by the daemon publisher. pub const fn pending_ordinal(&self) -> Option { self.pending_ordinal @@ -109,8 +89,6 @@ impl core::fmt::Debug for ConfigurationStaging { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter .debug_struct("ConfigurationStaging") - .field("has_pending", &self.pending.is_some()) - .field("has_active", &self.active.is_some()) .field("has_pending_ordinal", &self.pending_ordinal.is_some()) .field("has_active_ordinal", &self.active_ordinal.is_some()) .finish() @@ -119,7 +97,6 @@ impl core::fmt::Debug for ConfigurationStaging { #[derive(Clone, PartialEq, Eq)] struct ZoneCoordinatorState { - usbip_reconcile_active: bool, force_shutdown_generation: Option, activation_lock_held: bool, staging: ConfigurationStaging, @@ -128,7 +105,6 @@ struct ZoneCoordinatorState { impl ZoneCoordinatorState { const fn new() -> Self { Self { - usbip_reconcile_active: false, force_shutdown_generation: None, activation_lock_held: false, staging: ConfigurationStaging::empty(), @@ -139,18 +115,12 @@ impl ZoneCoordinatorState { /// A snapshot of state owned by one Zone. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ZoneCoordinatorSnapshot { - usbip_reconcile_active: bool, force_shutdown_generation: Option, activation_lock_held: bool, staging: ConfigurationStaging, } impl ZoneCoordinatorSnapshot { - /// Whether this Zone currently owns a USBIP reconcile pass. - pub const fn usbip_reconcile_active(&self) -> bool { - self.usbip_reconcile_active - } - /// Return the force-shutdown generation, if one is recorded. pub const fn force_shutdown_generation(&self) -> Option { self.force_shutdown_generation @@ -229,11 +199,6 @@ impl ZoneCoordinator { .ok_or(CoordinatorError::VmNotRegistered) } - /// Return the number of independently coordinated Zones. - pub fn zone_count(&self) -> usize { - self.zones.len() - } - /// Return a redacted snapshot of one Zone's coordination state. pub fn snapshot(&self, zone: &ZoneId) -> Result { let state = self @@ -241,33 +206,12 @@ impl ZoneCoordinator { .get(zone) .ok_or(CoordinatorError::ZoneNotRegistered)?; Ok(ZoneCoordinatorSnapshot { - usbip_reconcile_active: state.usbip_reconcile_active, force_shutdown_generation: state.force_shutdown_generation, activation_lock_held: state.activation_lock_held, staging: state.staging.clone(), }) } - /// Acquire the per-Zone USBIP reconcile lease. - pub fn begin_usbip_reconcile(&mut self, zone: &ZoneId) -> Result<(), CoordinatorError> { - let state = self.state_mut(zone)?; - if state.usbip_reconcile_active { - return Err(CoordinatorError::UsbipReconcileInFlight); - } - state.usbip_reconcile_active = true; - Ok(()) - } - - /// Release the per-Zone USBIP reconcile lease. - pub fn finish_usbip_reconcile(&mut self, zone: &ZoneId) -> Result<(), CoordinatorError> { - let state = self.state_mut(zone)?; - if !state.usbip_reconcile_active { - return Err(CoordinatorError::LockNotHeld); - } - state.usbip_reconcile_active = false; - Ok(()) - } - /// Acquire the configuration activation lock for one Zone. pub fn begin_activation(&mut self, zone: &ZoneId) -> Result<(), CoordinatorError> { let state = self.state_mut(zone)?; @@ -288,19 +232,6 @@ impl ZoneCoordinator { Ok(()) } - /// Record a force-shutdown generation only in the selected Zone. - pub fn set_force_shutdown_generation( - &mut self, - zone: &ZoneId, - generation: u64, - ) -> Result<(), CoordinatorError> { - if generation == 0 { - return Err(CoordinatorError::InvalidShutdownGeneration); - } - self.state_mut(zone)?.force_shutdown_generation = Some(generation); - Ok(()) - } - /// Advance and record a force-shutdown generation for one Zone. pub fn note_force_shutdown_request(&mut self, zone: &ZoneId) -> Result { let state = self.state_mut(zone)?; @@ -313,29 +244,6 @@ impl ZoneCoordinator { Ok(generation) } - /// Clear a force-shutdown generation after the matching Zone teardown. - pub fn clear_force_shutdown_generation( - &mut self, - zone: &ZoneId, - generation: u64, - ) -> Result<(), CoordinatorError> { - let state = self.state_mut(zone)?; - if state.force_shutdown_generation == Some(generation) { - state.force_shutdown_generation = None; - } - Ok(()) - } - - /// Stage a candidate generation for exactly one Zone. - pub fn stage_configuration( - &mut self, - zone: &ZoneId, - generation: ResourceBundleGenerationId, - ) -> Result<(), CoordinatorError> { - self.state_mut(zone)?.staging.pending = Some(generation); - Ok(()) - } - /// Stage a broker-published configuration ordinal for exactly one Zone. pub fn stage_configuration_ordinal( &mut self, @@ -357,44 +265,6 @@ impl ZoneCoordinator { Ok(()) } - /// Commit the staged generation after the durable generation record commit. - pub fn commit_configuration( - &mut self, - zone: &ZoneId, - ) -> Result, CoordinatorError> { - let state = self.state_mut(zone)?; - let pending = state.staging.pending.take(); - if let Some(generation) = pending.clone() { - state.staging.active = Some(generation); - } - Ok(pending) - } - - /// Commit the broker-published ordinal after its durable generation record. - pub fn commit_configuration_ordinal( - &mut self, - zone: &ZoneId, - ) -> Result, CoordinatorError> { - let state = self.state_mut(zone)?; - let pending = state.staging.pending_ordinal.take(); - if let Some(ordinal) = pending { - state.staging.active_ordinal = Some(ordinal); - } - Ok(pending) - } - - /// Clear a pending staging record after an aborted activation. - pub fn abort_configuration(&mut self, zone: &ZoneId) -> Result<(), CoordinatorError> { - self.state_mut(zone)?.staging.pending = None; - Ok(()) - } - - /// Clear a pending broker-published ordinal after an aborted activation. - pub fn abort_configuration_ordinal(&mut self, zone: &ZoneId) -> Result<(), CoordinatorError> { - self.state_mut(zone)?.staging.pending_ordinal = None; - Ok(()) - } - fn state_mut(&mut self, zone: &ZoneId) -> Result<&mut ZoneCoordinatorState, CoordinatorError> { self.zones .get_mut(zone) @@ -420,11 +290,6 @@ mod tests { ZoneId::parse(name).expect("valid Zone") } - fn generation(byte: char) -> ResourceBundleGenerationId { - ResourceBundleGenerationId::parse(format!("sha256:{}", byte.to_string().repeat(64))) - .expect("valid generation") - } - #[test] fn coordination_state_is_isolated_by_zone() { let mut coordinator = ZoneCoordinator::new(); @@ -435,21 +300,16 @@ mod tests { assert_eq!(coordinator.bind_vm("work-vm", &work), Ok(true)); assert_eq!(coordinator.bind_vm("personal-vm", &personal), Ok(true)); - coordinator.begin_usbip_reconcile(&work).unwrap(); coordinator.begin_activation(&work).unwrap(); - coordinator - .stage_configuration(&work, generation('a')) - .unwrap(); - coordinator.set_force_shutdown_generation(&work, 7).unwrap(); + coordinator.note_force_shutdown_request(&work).unwrap(); + coordinator.stage_configuration_ordinal(&work, 4).unwrap(); let untouched = coordinator.snapshot(&personal).unwrap(); - assert!(!untouched.usbip_reconcile_active()); assert!(!untouched.activation_lock_held()); assert_eq!(untouched.force_shutdown_generation(), None); - assert_eq!(untouched.staging().pending(), None); assert_eq!(untouched.staging().pending_ordinal(), None); assert_eq!( - coordinator.begin_usbip_reconcile(&personal), + coordinator.begin_activation(&personal), Ok(()), "one Zone cannot suppress another Zone" ); @@ -457,31 +317,6 @@ mod tests { assert_eq!(coordinator.zone_for_vm("personal-vm"), Ok(&personal)); } - #[test] - fn staged_generation_is_committed_only_for_its_zone() { - let mut coordinator = ZoneCoordinator::new(); - let work = zone("work"); - let personal = zone("personal"); - coordinator.register_zone(work.clone()); - coordinator.register_zone(personal.clone()); - coordinator - .stage_configuration(&work, generation('a')) - .unwrap(); - assert_eq!(coordinator.commit_configuration(&personal), Ok(None)); - assert_eq!( - coordinator.commit_configuration(&work).unwrap(), - Some(generation('a')) - ); - assert_eq!( - coordinator.snapshot(&work).unwrap().staging().active(), - Some(&generation('a')) - ); - assert_eq!( - coordinator.snapshot(&personal).unwrap().staging().active(), - None - ); - } - #[test] fn vm_binding_is_authoritative_and_does_not_cross_zone_state() { let mut coordinator = ZoneCoordinator::new(); @@ -528,14 +363,5 @@ mod tests { .pending_ordinal(), None ); - assert_eq!(coordinator.commit_configuration_ordinal(&work), Ok(Some(4))); - assert_eq!( - coordinator - .snapshot(&work) - .unwrap() - .staging() - .active_ordinal(), - Some(4) - ); } } From 2e92e177cba03e9343594ad4ae6ab1a934490639 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:20:14 -0700 Subject: [PATCH 279/726] d2bd: narrow audio and lifecycle surfaces, drop dead vm name, return plain accessors audio_host_controller and provider lifecycle effect modules become crate-local with a test-support re-export seam; the dead vm_name parameter is removed from the audio controller trait; resource plane accessors return plain references or Arcs instead of Arc reference plumbing. --- packages/d2bd/src/audio_dispatch.rs | 13 ++++---- packages/d2bd/src/audio_host_controller.rs | 38 +++++++++------------- packages/d2bd/src/composition.rs | 9 +++-- packages/d2bd/src/provider_effects.rs | 9 ++++- packages/d2bd/src/resource_plane_v3.rs | 12 +++---- packages/d2bd/src/resource_runtime.rs | 2 +- 6 files changed, 42 insertions(+), 41 deletions(-) diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index fe6d9cde9..13a16e9ca 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -157,7 +157,7 @@ pub fn enforce_host_grant( channel: AudioChannel, ) -> HostEnforcementResult { match build_host_controller(state, vm_name, cap, caller_role) { - Some(ctrl) => ctrl.enforce_grant(vm_name, grant, channel), + Some(ctrl) => ctrl.enforce_grant(grant, channel), None => HostEnforcementResult::Unsupported, } } @@ -174,7 +174,7 @@ pub fn enforce_host_level( channel: AudioChannel, ) -> HostEnforcementResult { match build_host_controller(state, vm_name, cap, caller_role) { - Some(ctrl) => ctrl.enforce_level(vm_name, level, channel), + Some(ctrl) => ctrl.enforce_level(level, channel), None => HostEnforcementResult::Unsupported, } } @@ -766,7 +766,7 @@ mod tests { use crate::audio_host_controller::FakeHostController; let cap = d2b_provider_guest_cloud_hypervisor::audio_capability(); let ctrl = FakeHostController::success(); - let host_result = ctrl.enforce_grant("corp-vm", AudioGrant::Off, AudioChannel::Speaker); + let host_result = ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Speaker); assert_eq!(host_result, HostEnforcementResult::Applied); let applied = combined_audio_applied(host_result, &cap); assert_eq!( @@ -783,7 +783,7 @@ mod tests { // report Unsupported, never HostOnly. let cap = d2b_provider_guest_cloud_hypervisor::audio_capability(); let ctrl = FakeHostController::failed(); - let host_result = ctrl.enforce_grant("corp-vm", AudioGrant::Off, AudioChannel::Speaker); + let host_result = ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Speaker); assert_eq!(host_result, HostEnforcementResult::Failed); let applied = combined_audio_applied(host_result, &cap); assert_eq!( @@ -800,7 +800,7 @@ mod tests { let cap = d2b_provider_guest_qemu_media::audio_capability(); let ctrl = FakeHostController::failed(); let level = LevelPercent::new(80).unwrap(); - let host_result = ctrl.enforce_level("corp-vm", level, AudioChannel::Microphone); + let host_result = ctrl.enforce_level(level, AudioChannel::Microphone); assert_eq!(host_result, HostEnforcementResult::Failed); let applied = combined_audio_applied(host_result, &cap); assert_eq!(applied, AudioSetApplied::Unsupported); @@ -811,7 +811,7 @@ mod tests { use crate::audio_host_controller::QemuAudioController; let cap = d2b_provider_guest_qemu_media::audio_capability(); let ctrl = QemuAudioController; - let host_result = ctrl.enforce_grant("qemu-vm", AudioGrant::Off, AudioChannel::Speaker); + let host_result = ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Speaker); assert_eq!(host_result, HostEnforcementResult::Applied); let applied = combined_audio_applied(host_result, &cap); assert_eq!(applied, AudioSetApplied::HostOnly); @@ -825,7 +825,6 @@ mod tests { let cap = d2b_provider_guest_qemu_media::audio_capability(); let ctrl = QemuAudioController; let host_result = ctrl.enforce_level( - "qemu-vm", LevelPercent::new(50).unwrap(), AudioChannel::Microphone, ); diff --git a/packages/d2bd/src/audio_host_controller.rs b/packages/d2bd/src/audio_host_controller.rs index d7a2f85bd..cbb9aaf6f 100644 --- a/packages/d2bd/src/audio_host_controller.rs +++ b/packages/d2bd/src/audio_host_controller.rs @@ -56,7 +56,7 @@ pub use crate::audio_dispatch::HostEnforcementResult; /// /// The trait is `dyn`-safe so dispatch functions can accept `&dyn /// HostAudioController` and tests can inject a fake. -pub trait HostAudioController { +pub(crate) trait HostAudioController { /// Enforce a mute/unmute grant on a running VM's audio node. /// /// Returns [`HostEnforcementResult::Applied`] only when enforcement was @@ -65,7 +65,6 @@ pub trait HostAudioController { /// providers where no live enforcement path exists. fn enforce_grant( &self, - vm_name: &str, grant: AudioGrant, channel: AudioChannel, ) -> HostEnforcementResult; @@ -75,7 +74,6 @@ pub trait HostAudioController { /// Same success/failure contract as [`Self::enforce_grant`]. fn enforce_level( &self, - vm_name: &str, level: LevelPercent, channel: AudioChannel, ) -> HostEnforcementResult; @@ -89,7 +87,7 @@ pub trait HostAudioController { /// broker transport. Tool paths, runtime paths, and node identifiers remain /// broker-local. #[derive(Debug, Clone)] -pub struct PipeWireHostController { +pub(crate) struct PipeWireHostController { broker_socket: PathBuf, caller_role: BrokerCallerRole, vm_id: VmId, @@ -103,7 +101,7 @@ impl PipeWireHostController { /// /// Tool paths, runtime paths, and node identifiers are resolved only by /// the broker from the trusted runner intent. - pub fn from_audio_node( + pub(crate) fn from_audio_node( node: &ProcessNode, vm_name: &str, broker_socket: PathBuf, @@ -121,7 +119,7 @@ impl PipeWireHostController { /// Find the audio runner node for a VM in a loaded [`ProcessesJson`]. /// /// Returns `None` when no audio node exists (VM has no audio sidecar). - pub fn find_audio_node<'a>( + pub(crate) fn find_audio_node<'a>( processes: &'a ProcessesJson, vm_name: &str, ) -> Option<&'a ProcessNode> { @@ -170,7 +168,6 @@ impl PipeWireHostController { impl HostAudioController for PipeWireHostController { fn enforce_grant( &self, - _vm_name: &str, grant: AudioGrant, channel: AudioChannel, ) -> HostEnforcementResult { @@ -179,7 +176,6 @@ impl HostAudioController for PipeWireHostController { fn enforce_level( &self, - _vm_name: &str, level: LevelPercent, channel: AudioChannel, ) -> HostEnforcementResult { @@ -211,12 +207,11 @@ impl HostAudioController for PipeWireHostController { /// `guest_enforcement = Unsupported`, and that invariant is enforced at the /// dispatch layer, not here. #[derive(Debug, Clone, Copy, Default)] -pub struct QemuAudioController; +pub(crate) struct QemuAudioController; impl HostAudioController for QemuAudioController { fn enforce_grant( &self, - _vm_name: &str, _grant: AudioGrant, _channel: AudioChannel, ) -> HostEnforcementResult { @@ -227,7 +222,6 @@ impl HostAudioController for QemuAudioController { fn enforce_level( &self, - _vm_name: &str, _level: LevelPercent, _channel: AudioChannel, ) -> HostEnforcementResult { @@ -284,7 +278,6 @@ impl FakeHostController { impl HostAudioController for FakeHostController { fn enforce_grant( &self, - _vm_name: &str, _grant: AudioGrant, _channel: AudioChannel, ) -> HostEnforcementResult { @@ -293,7 +286,6 @@ impl HostAudioController for FakeHostController { fn enforce_level( &self, - _vm_name: &str, _level: LevelPercent, _channel: AudioChannel, ) -> HostEnforcementResult { @@ -350,7 +342,7 @@ mod tests { fn fake_success_returns_applied_for_grant() { let ctrl = FakeHostController::success(); assert_eq!( - ctrl.enforce_grant("corp-vm", AudioGrant::Off, AudioChannel::Speaker), + ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Speaker), HostEnforcementResult::Applied, ); } @@ -360,7 +352,7 @@ mod tests { let ctrl = FakeHostController::success(); let level = LevelPercent::new(75).unwrap(); assert_eq!( - ctrl.enforce_level("corp-vm", level, AudioChannel::Speaker), + ctrl.enforce_level(level, AudioChannel::Speaker), HostEnforcementResult::Applied, ); } @@ -369,7 +361,7 @@ mod tests { fn fake_failed_returns_failed_for_grant() { let ctrl = FakeHostController::failed(); assert_eq!( - ctrl.enforce_grant("corp-vm", AudioGrant::Off, AudioChannel::Speaker), + ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Speaker), HostEnforcementResult::Failed, ); } @@ -379,7 +371,7 @@ mod tests { let ctrl = FakeHostController::failed(); let level = LevelPercent::new(50).unwrap(); assert_eq!( - ctrl.enforce_level("corp-vm", level, AudioChannel::Microphone), + ctrl.enforce_level(level, AudioChannel::Microphone), HostEnforcementResult::Failed, ); } @@ -388,12 +380,12 @@ mod tests { fn fake_unsupported_returns_unsupported() { let ctrl = FakeHostController::unsupported(); assert_eq!( - ctrl.enforce_grant("corp-vm", AudioGrant::Off, AudioChannel::Microphone), + ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Microphone), HostEnforcementResult::Unsupported, ); let level = LevelPercent::new(20).unwrap(); assert_eq!( - ctrl.enforce_level("corp-vm", level, AudioChannel::Speaker), + ctrl.enforce_level(level, AudioChannel::Speaker), HostEnforcementResult::Unsupported, ); } @@ -404,7 +396,7 @@ mod tests { fn qemu_controller_grant_is_applied() { let ctrl = QemuAudioController; assert_eq!( - ctrl.enforce_grant("qemu-vm", AudioGrant::Off, AudioChannel::Speaker), + ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Speaker), HostEnforcementResult::Applied, ); } @@ -414,7 +406,7 @@ mod tests { let ctrl = QemuAudioController; let level = LevelPercent::new(80).unwrap(); assert_eq!( - ctrl.enforce_level("qemu-vm", level, AudioChannel::Microphone), + ctrl.enforce_level(level, AudioChannel::Microphone), HostEnforcementResult::Applied, ); } @@ -424,7 +416,7 @@ mod tests { let ctrl = QemuAudioController; // Unmute (grant=On) should also return Applied for qemu-media. assert_eq!( - ctrl.enforce_grant("qemu-vm", AudioGrant::On, AudioChannel::Speaker), + ctrl.enforce_grant(AudioGrant::On, AudioChannel::Speaker), HostEnforcementResult::Applied, ); } @@ -457,7 +449,7 @@ mod tests { PathBuf::from("/nonexistent/d2b-priv.sock"), BrokerCallerRole::AdminUid { uid: 0 }, ); - let result = ctrl.enforce_grant("corp-vm", AudioGrant::Off, AudioChannel::Speaker); + let result = ctrl.enforce_grant(AudioGrant::Off, AudioChannel::Speaker); assert_eq!( result, HostEnforcementResult::Failed, diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index de47a8b66..581e5ec1a 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -395,8 +395,11 @@ mod audio_dispatch; mod audio_host_controller; mod credential_resource_runtime; pub mod interaction_composition; -pub mod process_provider_runtime; +pub(crate) mod process_provider_runtime; mod process_resource_runtime; +#[cfg(not(feature = "test-support"))] +pub(crate) mod provider_effects; +#[cfg(feature = "test-support")] pub mod provider_effects; pub mod provider_registry; pub mod provider_shutdown; @@ -11184,7 +11187,7 @@ pub(crate) async fn ensure_guest_target_session( plane .bind_guest_target(&guest, generation, control) .map_err(|error| format!("guest-session:target-bind-refused:{error}"))?; - adopt_guest_target_assignments(plane.targets(), &guest, generation).await; + adopt_guest_target_assignments(&plane.targets(), &guest, generation).await; Ok(()) } @@ -11276,7 +11279,7 @@ pub(crate) async fn binding_guest_mount_ready( .lock() .await .get(zone.as_str()) - .map(|plane| std::sync::Arc::clone(plane.targets())); + .map(|plane| plane.targets()); let Some(directory) = directory else { return false; }; diff --git a/packages/d2bd/src/provider_effects.rs b/packages/d2bd/src/provider_effects.rs index 99b894639..2782a1f74 100644 --- a/packages/d2bd/src/provider_effects.rs +++ b/packages/d2bd/src/provider_effects.rs @@ -7,7 +7,7 @@ //! with the existing typed broker dispatch functions. use std::{ - collections::{BTreeMap, BTreeSet}, + collections::BTreeMap, fs::{self, OpenOptions}, io::Write, path::PathBuf, @@ -17,6 +17,9 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; +#[cfg(any(test, feature = "test-support"))] +use std::collections::BTreeSet; + use d2b_contracts_broker::broker_wire::BrokerCallerRole; use d2b_contracts_broker::broker_wire::{BrokerRequest, BrokerResponse}; use d2b_contracts_resource::v3::{ResourceGeneration, ResourceRef, ResourceUid, ZoneId}; @@ -719,6 +722,7 @@ impl ProviderLifecycleDispatch { } /// Construct a dispatcher backed by a daemon-owned durable state file. + #[cfg(any(test, feature = "test-support"))] #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn new_persistent( zone: ZoneId, @@ -821,6 +825,7 @@ impl ProviderLifecycleDispatch { /// [`ProviderEffectError::StopOnlyLease`], or /// [`ProviderEffectError::StateUnavailable`]. /// + #[cfg(any(test, feature = "test-support"))] pub fn admit( &self, caller: &BrokerCallerRole, @@ -1325,6 +1330,7 @@ fn validate_authorization(request: &GuestLifecycleRequest) -> Result<(), Provide Ok(()) } +#[cfg(any(test, feature = "test-support"))] fn persisted_authorization(entry: &PersistedLifecycleMutation) -> Option { let zone_uid = ResourceUid::parse(entry.zone_uid.as_ref()?).ok()?; let guest_ref = ResourceRef::parse(&entry.guest).ok()?; @@ -1365,6 +1371,7 @@ fn persisted_authorization(entry: &PersistedLifecycleMutation) -> Option Result { diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index bb7a56131..2a26904cc 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -3206,8 +3206,8 @@ impl ResourcePlaneV3 { } /// The per-Zone target directory (U13). - pub fn targets(&self) -> &Arc { - &self.targets + pub fn targets(&self) -> Arc { + Arc::clone(&self.targets) } /// Register one authenticated guest session generation and tell the @@ -3274,20 +3274,20 @@ impl ResourcePlaneV3 { /// The in-memory watch hub (U8 pairs it with the client in /// `ManagerBackend`; ManagerWatch/ManagerWatchStreams hand off the /// external WATCH streams, KTD8). - pub fn hub(&self) -> &Arc { - &self.hub + pub fn hub(&self) -> Arc { + Arc::clone(&self.hub) } /// See [`Self::readiness`]: read by this module's tests. #[cfg(test)] - pub fn store(&self) -> &Arc { + pub fn store(&self) -> &SpecStore { &self.store } /// The per-zone registry the production effects resolve per-resource /// anchors from. - pub fn registry(&self) -> &Arc { + pub fn registry(&self) -> &PlaneResourceRegistry { &self.registry } diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 4ac271387..cdf76e39d 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -4419,7 +4419,7 @@ impl ZoneResourceRuntime { .map_err(|_| ResourceRuntimeError::StoreSealUnavailable)?; let backend = d2b_resource_api::manager_backend::ManagerBackend::new( plane.client().clone(), - Arc::clone(plane.hub()), + plane.hub(), acceptor, ); let service = Arc::new( From 886a26df33e0326a27fe1b294100aa9e0b2f9a6d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:20:33 -0700 Subject: [PATCH 280/726] d2b-bus: fold scoped query assignment and scope into one pair --- packages/d2b-bus/src/router.rs | 148 +++++++++++---------------------- 1 file changed, 48 insertions(+), 100 deletions(-) diff --git a/packages/d2b-bus/src/router.rs b/packages/d2b-bus/src/router.rs index 7ef594559..54b49edd5 100644 --- a/packages/d2b-bus/src/router.rs +++ b/packages/d2b-bus/src/router.rs @@ -26,8 +26,8 @@ use d2b_core_controller::controller_assignment::{ ScopedResourceScope, }; use d2b_resource_api::authz::{ - ApiMethod, AuthorizationRequest, AuthorizationState, AuthorizationTarget, NativeAuthorizer, - PolicySet, ResourceVerb, SessionVerb, + ApiMethod, AuthorizationRequest, AuthorizationState, AuthorizationTarget, PolicySet, + ResourceVerb, SessionVerb, }; use d2b_resource_api::watch::{WatchFrame, WatchSink, WatchSinkError}; use d2b_session::{ @@ -217,8 +217,7 @@ pub struct ResourceQuery { resource_types: Vec, resource_names: Vec, filters: Vec, - assignment: Option, - scope: Option, + scoped: Option<(AssignmentIdentity, ScopedResourceScope)>, } impl ResourceQuery { @@ -239,8 +238,7 @@ impl ResourceQuery { resource_types, resource_names, filters, - assignment: None, - scope: None, + scoped: None, }) } @@ -265,8 +263,7 @@ impl ResourceQuery { resource_types, resource_names, filters, - assignment: Some(assignment), - scope: Some(scope), + scoped: Some((assignment, scope)), }; query.validate_scoped()?; Ok(query) @@ -289,21 +286,23 @@ impl ResourceQuery { /// Borrow the assignment evidence, when this query is controller-scoped. pub const fn assignment(&self) -> Option<&AssignmentIdentity> { - self.assignment.as_ref() + match &self.scoped { + Some((assignment, _)) => Some(assignment), + None => None, + } } /// Borrow the controller-minted query scope, when present. pub const fn scope(&self) -> Option<&ScopedResourceScope> { - self.scope.as_ref() + match &self.scoped { + Some((_, scope)) => Some(scope), + None => None, + } } fn validate_scoped(&self) -> Result<(), BusError> { - let (Some(assignment), Some(scope)) = (&self.assignment, &self.scope) else { - return if self.assignment.is_none() && self.scope.is_none() { - Ok(()) - } else { - Err(BusError::InvalidResourceCall) - }; + let Some((assignment, scope)) = &self.scoped else { + return Ok(()); }; let (bound_field, bound_value) = match scope { ScopedResourceScope::Primary => { @@ -1237,39 +1236,6 @@ impl ZoneBus { Self::with_clock(zone, authorizer, config, Arc::new(SystemClock::new())) } - pub fn with_observer( - zone: ZoneId, - authorizer: BusAuthorizer, - config: BusConfig, - observer: Arc, - ) -> Result<(Self, ZoneRegistrar), BusError> { - Self::with_clock_and_observer( - zone, - authorizer, - config, - Arc::new(SystemClock::new()), - observer, - ) - } - - /// Construct a bus with the system clock, observer, and telemetry handoff. - pub fn with_observer_and_metrics( - zone: ZoneId, - authorizer: BusAuthorizer, - config: BusConfig, - observer: Arc, - metrics: Arc, - ) -> Result<(Self, ZoneRegistrar), BusError> { - Self::with_clock_observer_and_metrics( - zone, - authorizer, - config, - Arc::new(SystemClock::new()), - observer, - metrics, - ) - } - /// Construct a bus and the Zone-runtime-only committed subject issuer. pub fn with_interaction_subject_issuer( zone: ZoneId, @@ -1287,28 +1253,18 @@ impl ZoneBus { } /// Construct a bus with an injected monotonic clock. - pub fn with_clock( - zone: ZoneId, - authorizer: BusAuthorizer, - config: BusConfig, - clock: Arc, - ) -> Result<(Self, ZoneRegistrar), BusError> { - Self::with_clock_and_observer(zone, authorizer, config, clock, Arc::new(NoopBusObserver)) - } - - pub fn with_clock_and_observer( + pub(crate) fn with_clock( zone: ZoneId, authorizer: BusAuthorizer, config: BusConfig, clock: Arc, - observer: Arc, ) -> Result<(Self, ZoneRegistrar), BusError> { let (bus, registrar, _) = Self::with_clock_observer_and_metrics_internal( zone, authorizer, config, clock, - observer, + Arc::new(NoopBusObserver), Arc::new(NoopBusTelemetry), false, )?; @@ -1316,6 +1272,7 @@ impl ZoneBus { } /// Construct a bus with an observer and the bounded telemetry handoff. + #[cfg(test)] pub fn with_clock_observer_and_metrics( zone: ZoneId, authorizer: BusAuthorizer, @@ -1443,11 +1400,6 @@ impl ZoneBus { Ok(()) } - /// Borrow the native authorizer shared by this Zone bus. - pub fn native_authorizer(&self) -> Arc { - self.core.authorizer.native_authorizer() - } - /// Fail closed for all new work while durable policy is unavailable. pub fn mark_policy_unavailable(&self) { self.core.authorizer.mark_policy_unavailable(); @@ -1468,14 +1420,22 @@ enum UnixSubjectKind { Provider, } +/// The exactly-one expected peer identity for a Unix subject. +#[derive(Clone)] +enum ExpectedPeer { + /// The full peer credentials must match exactly. + Exact(PeerCredentials), + /// Only the peer UID must match. + Uid(u32), +} + #[derive(Clone)] pub(crate) struct UnixSubjectRecord { kind: UnixSubjectKind, subject_ref: ResourceRef, subject_uid: ResourceUid, zone_ref: ResourceRef, - expected_peer: Option, - expected_peer_uid: Option, + expected_peer: ExpectedPeer, service: Option, provider_ref: Option, provider_generation: Option, @@ -1562,8 +1522,7 @@ impl UnixSubjectRecord { subject_ref, subject_uid, zone_ref, - expected_peer: Some(expected_peer), - expected_peer_uid: None, + expected_peer: ExpectedPeer::Exact(expected_peer), service: None, provider_ref: None, provider_generation: None, @@ -1591,8 +1550,7 @@ impl UnixSubjectRecord { subject_ref, subject_uid, zone_ref, - expected_peer: None, - expected_peer_uid: Some(expected_peer_uid), + expected_peer: ExpectedPeer::Uid(expected_peer_uid), service: None, provider_ref: None, provider_generation: None, @@ -1620,8 +1578,7 @@ impl UnixSubjectRecord { subject_ref, subject_uid, zone_ref, - expected_peer: None, - expected_peer_uid: Some(expected_peer_uid), + expected_peer: ExpectedPeer::Uid(expected_peer_uid), service: None, provider_ref: None, provider_generation: None, @@ -1696,15 +1653,12 @@ impl UnixSubjectRecord { UnixSubjectKind::Provider => "Provider", }; peer.validate_transport(binding.transport_class())?; - let peer_matches = if binding.service().as_str() == "d2b.resource.v3" { - self.expected_peer - .is_some_and(|expected| peer.credentials() == expected) - } else { - self.expected_peer - .is_some_and(|expected| peer.credentials() == expected) - || self - .expected_peer_uid - .is_some_and(|expected| peer.credentials().uid().as_raw() == expected) + let peer_matches = match &self.expected_peer { + ExpectedPeer::Exact(expected) => peer.credentials() == *expected, + ExpectedPeer::Uid(expected) => { + binding.service().as_str() != "d2b.resource.v3" + && peer.credentials().uid().as_raw() == *expected + } }; if !peer_matches || evidence.class() != EvidenceClass::UnixPeer @@ -1806,17 +1760,12 @@ impl AuthoritativeUnixSubjectResolver { .iter() .enumerate() .filter_map(|(index, subject)| { - let peer_matches = if *service == ServicePackage::ResourceV3 { - subject - .expected_peer - .is_some_and(|expected| expected == peer) - } else { - subject - .expected_peer - .is_some_and(|expected| expected == peer) - || subject - .expected_peer_uid - .is_some_and(|expected| peer.uid().as_raw() == expected) + let peer_matches = match &subject.expected_peer { + ExpectedPeer::Exact(expected) => *expected == peer, + ExpectedPeer::Uid(expected) => { + *service != ServicePackage::ResourceV3 + && peer.uid().as_raw() == *expected + } }; (peer_matches && subject @@ -1831,7 +1780,7 @@ impl AuthoritativeUnixSubjectResolver { d2b_session::contract::SessionErrorCode::SubjectConfigurationMismatch, )), }; - if subjects[index].expected_peer.is_some() { + if matches!(subjects[index].expected_peer, ExpectedPeer::Exact(_)) { Ok(subjects.swap_remove(index)) } else { Ok(subjects[index].clone()) @@ -1896,7 +1845,8 @@ impl AuthoritativeUnixSubjectResolver { impl UnixSubjectRecord { fn is_exact_resource_v3(&self) -> bool { - self.expected_peer.is_some() && self.service == Some(ServicePackage::ResourceV3) + matches!(self.expected_peer, ExpectedPeer::Exact(_)) + && self.service == Some(ServicePackage::ResourceV3) } fn has_same_exact_resource_v3_key(&self, other: &Self) -> bool { @@ -5844,8 +5794,7 @@ mod tests { resource_types: vec![ResourceTypeName::parse("Host").unwrap()], resource_names: Vec::new(), filters: vec![owner_filter.clone()], - assignment: Some(first.assignment().clone()), - scope: Some(owner_scope.clone()), + scoped: Some((first.assignment().clone(), owner_scope.clone())), }; assert_eq!( ResourceCall::List(non_process).authorization_request(zone.clone()), @@ -5856,8 +5805,7 @@ mod tests { resource_types: vec![ResourceTypeName::parse(PROCESS_RESOURCE_TYPE).unwrap()], resource_names: Vec::new(), filters: vec![owner_filter], - assignment: Some(second.assignment().clone()), - scope: Some(owner_scope), + scoped: Some((second.assignment().clone(), owner_scope)), }; assert_eq!( ResourceCall::Watch(mismatched_scope).authorization_request(zone), From a5a61915194d60bbc4b6542c6bb196f5bf6a40db Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:21:06 -0700 Subject: [PATCH 281/726] d2b-bus: drop unused native authorizer accessor --- packages/d2b-bus/src/authorization.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/d2b-bus/src/authorization.rs b/packages/d2b-bus/src/authorization.rs index be20e6825..3e6dcd803 100644 --- a/packages/d2b-bus/src/authorization.rs +++ b/packages/d2b-bus/src/authorization.rs @@ -66,16 +66,6 @@ impl BusAuthorizer { self } - /// Borrow the single native authorizer shared with the Resource API. - /// - /// The bus and generated resource handlers must evaluate the same policy - /// instance and store-bound mutation authority. Returning the existing - /// `Arc` prevents the daemon from accidentally constructing a parallel - /// authority for one Zone. - pub fn native_authorizer(&self) -> std::sync::Arc { - std::sync::Arc::clone(&self.lock().native) - } - pub(crate) fn controller_generation(&self) -> Option { self.lock().state.snapshot.controller_generation } From d9440dfaea657f0a501ebba472c32bdbca5162ab Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:21:10 -0700 Subject: [PATCH 282/726] d2b-contracts-provider: kebab-case credential observability diagnostics --- .../d2b-contracts-provider/src/v3/credential_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2b-contracts-provider/src/v3/credential_controller.rs b/packages/d2b-contracts-provider/src/v3/credential_controller.rs index 99d388750..a5533e426 100644 --- a/packages/d2b-contracts-provider/src/v3/credential_controller.rs +++ b/packages/d2b-contracts-provider/src/v3/credential_controller.rs @@ -1505,8 +1505,8 @@ pub enum CredentialObservabilityError { impl fmt::Display for CredentialObservabilityError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str(match self { - Self::InvalidAuditRecord => "credential audit record is invalid", - Self::ForbiddenTelemetryField => "credential telemetry frame is invalid", + Self::InvalidAuditRecord => "credential-audit-record-invalid", + Self::ForbiddenTelemetryField => "credential-telemetry-frame-invalid", }) } } From 4105103abdf531509781b586683882f960ee3fb1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:21:14 -0700 Subject: [PATCH 283/726] d2b-core-controller: drop duplicated plan accessors --- .../src/owner_reconcile.rs | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/packages/d2b-core-controller/src/owner_reconcile.rs b/packages/d2b-core-controller/src/owner_reconcile.rs index 808cdf3d7..7aa651f9d 100644 --- a/packages/d2b-core-controller/src/owner_reconcile.rs +++ b/packages/d2b-core-controller/src/owner_reconcile.rs @@ -575,11 +575,6 @@ impl OwnerReconcilePlan { &self.creation_order } - /// Alias for callers that name the operation a create order. - pub fn create_order(&self) -> &[ResourceRef] { - self.creation_order() - } - /// Borrow deterministic dependent-first deletion order. pub fn deletion_order(&self) -> &[ResourceRef] { &self.deletion_order @@ -595,12 +590,6 @@ impl OwnerReconcilePlan { self.create_batch.as_ref() } - /// Alias for callers that refer to the related-resource operation as a - /// CommitBatch. - pub const fn batch(&self) -> Option<&OwnerChildBatch> { - self.create_batch() - } - /// Borrow the teardown projection for this plan. pub fn teardown_plan(&self) -> TeardownPlan { TeardownPlan { @@ -693,11 +682,6 @@ impl OwnerChildBatch { &self.refs } - /// Borrow the batch addresses under Resource API terminology. - pub fn resource_refs(&self) -> &[ResourceRef] { - &self.refs - } - /// Return whether the batch has no children. pub const fn is_empty(&self) -> bool { self.children.is_empty() @@ -750,11 +734,6 @@ impl OwnerChildIdentity { &self.target } - /// Borrow the returned child ResourceRef under its API name. - pub const fn resource_ref(&self) -> &ResourceRef { - &self.target - } - /// Borrow the store-assigned child UID. pub const fn uid(&self) -> &ResourceUid { &self.uid @@ -934,16 +913,6 @@ impl TeardownPlan { &self.order } - /// Borrow the order under its ResourceRef terminology. - pub fn refs(&self) -> &[ResourceRef] { - &self.order - } - - /// Borrow the resources in child-first order. - pub fn resources(&self) -> &[ResourceRef] { - &self.order - } - /// Return the number of resources in the plan. pub const fn len(&self) -> usize { self.order.len() From 75e9c238c7a9f35456ce81585d48072da9ac6ef5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:21:15 -0700 Subject: [PATCH 284/726] d2b-contracts-provider: recover single-flight registry from mutex poisoning --- .../src/v3/credential_controller.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/d2b-contracts-provider/src/v3/credential_controller.rs b/packages/d2b-contracts-provider/src/v3/credential_controller.rs index a5533e426..d77e2569a 100644 --- a/packages/d2b-contracts-provider/src/v3/credential_controller.rs +++ b/packages/d2b-contracts-provider/src/v3/credential_controller.rs @@ -819,7 +819,7 @@ impl CredentialSingleFlight { &self, credential_uid: ResourceUid, ) -> Result, CredentialControllerError> { - let mut running = self.lock()?; + let mut running = self.lock(); if !running.insert(credential_uid.clone()) { return Err(CredentialControllerError::AlreadyRunning); } @@ -831,10 +831,10 @@ impl CredentialSingleFlight { } #[allow(clippy::disallowed_methods, reason = "synchronous path")] - fn lock(&self) -> Result>, CredentialControllerError> { + fn lock(&self) -> MutexGuard<'_, BTreeSet> { self.running .lock() - .map_err(|_| CredentialControllerError::InvalidInput) + .unwrap_or_else(|poisoned| poisoned.into_inner()) } } @@ -853,10 +853,12 @@ pub struct CredentialSingleFlightGuard<'registry> { impl Drop for CredentialSingleFlightGuard<'_> { #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn drop(&mut self) { - if let Some(credential_uid) = self.credential_uid.take() - && let Ok(mut running) = self.registry.running.lock() - { - running.remove(&credential_uid); + if let Some(credential_uid) = self.credential_uid.take() { + self.registry + .running + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) + .remove(&credential_uid); } } } From 6a6a62f2fa59ed4af12ce32c4878e635225f7846 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:21:55 -0700 Subject: [PATCH 285/726] clipboard-wayland: fold runner-contract flags into consts --- .../d2b-provider-clipboard-wayland/src/controller/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs b/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs index 4b61d0a61..01201ed42 100644 --- a/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs +++ b/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs @@ -14,8 +14,6 @@ pub const CLIPBOARD_REPAIR_INTERVAL_SECS: u64 = 300; pub struct ClipboardRunnerContract { service_package: &'static str, repair_interval_secs: u64, - watched_configuration_is_dependency: bool, - component_session_only: bool, } impl ClipboardRunnerContract { @@ -31,12 +29,12 @@ impl ClipboardRunnerContract { /// Whether configuration is dependency-only. pub const fn watched_configuration_is_dependency(self) -> bool { - self.watched_configuration_is_dependency + true } /// Whether clipboard state remains on typed ComponentSession streams. pub const fn component_session_only(self) -> bool { - self.component_session_only + true } } @@ -45,8 +43,6 @@ pub const fn clipboard_runner_contract() -> ClipboardRunnerContract { ClipboardRunnerContract { service_package: crate::MANAGEMENT_SERVICE, repair_interval_secs: CLIPBOARD_REPAIR_INTERVAL_SECS, - watched_configuration_is_dependency: true, - component_session_only: true, } } From 7a5a7f9573f9b3d8f71269ba83fa59b2d8132882 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:21:57 -0700 Subject: [PATCH 286/726] d2b-bus: fold session admission and liveness into one established lane --- packages/d2b-bus/src/session/zone_link.rs | 56 +++++++++++++---------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/packages/d2b-bus/src/session/zone_link.rs b/packages/d2b-bus/src/session/zone_link.rs index d9d3664c9..11d8313b2 100644 --- a/packages/d2b-bus/src/session/zone_link.rs +++ b/packages/d2b-bus/src/session/zone_link.rs @@ -108,11 +108,20 @@ const FENCE_REVOKED: u8 = 2; /// consumed the authenticated session that created it. Sharing the transport /// implementation shares no authority: the consumed session owner retains its /// liveness and single-owner authorization state. +/// The sealed admission and liveness pair of one established driver lane. +/// +/// Both values are set together by [`ZoneLinkSession::establish_authenticated`] +/// and are absent only on the test lane, so a half-set lane is unrepresentable. + +struct EstablishedLane { + admission: VerifiedRouteAdmission, + liveness: d2b_session::SessionLiveness, +} + pub struct ZoneLinkSession { driver: Arc, epoch: LinkEpoch, - admission: Option, - liveness: Option, + established: Option, fence: AtomicU8, } @@ -170,8 +179,10 @@ impl ZoneLinkSession { Ok(Self { driver: Arc::new(driver), epoch, - admission: Some(admission), - liveness: Some(route.liveness()), + established: Some(EstablishedLane { + admission, + liveness: route.liveness(), + }), fence: AtomicU8::new(FENCE_OPEN), }) } @@ -188,8 +199,7 @@ impl ZoneLinkSession { Ok(Self { driver, epoch, - admission: None, - liveness: None, + established: None, fence: AtomicU8::new(FENCE_OPEN), }) } @@ -208,15 +218,15 @@ impl ZoneLinkSession { pub fn is_open(&self) -> bool { if self.fence.load(Ordering::Acquire) != FENCE_OPEN || self - .liveness + .established .as_ref() - .is_some_and(|liveness| !liveness.is_live()) + .is_some_and(|lane| !lane.liveness.is_live()) { return false; } - if let Some(admission) = &self.admission - && (admission.revalidate().is_err() - || self.driver.generation() != admission.reconnect_generation().get()) + if let Some(lane) = &self.established + && (lane.admission.revalidate().is_err() + || self.driver.generation() != lane.admission.reconnect_generation().get()) { self.fence.store(FENCE_REVOKED, Ordering::Release); return false; @@ -246,20 +256,20 @@ impl ZoneLinkSession { match self.fence.load(Ordering::Acquire) { FENCE_OPEN => { if self - .liveness + .established .as_ref() - .is_some_and(|liveness| !liveness.is_live()) + .is_some_and(|lane| !lane.liveness.is_live()) { return Err(ZoneLinkSessionError::ZoneLinkDisconnected); } - if let Some(admission) = &self.admission - && let Err(error) = admission.revalidate() + if let Some(lane) = &self.established + && let Err(error) = lane.admission.revalidate() { self.fence.store(FENCE_REVOKED, Ordering::Release); return Err(ZoneLinkSessionError::RouteAdmission(error)); } - if self.admission.as_ref().is_some_and(|admission| { - self.driver.generation() != admission.reconnect_generation().get() + if self.established.as_ref().is_some_and(|lane| { + self.driver.generation() != lane.admission.reconnect_generation().get() }) { self.fence.store(FENCE_REVOKED, Ordering::Release); return Err(ZoneLinkSessionError::RouteAdmission( @@ -348,20 +358,20 @@ impl ZoneLinkSession { return Err(ZoneLinkSessionError::ZoneLinkRevoked); } if self - .liveness + .established .as_ref() - .is_some_and(|liveness| !liveness.is_live()) + .is_some_and(|lane| !lane.liveness.is_live()) { return Err(ZoneLinkSessionError::ZoneLinkDisconnected); } - if let Some(admission) = &self.admission - && let Err(error) = admission.revalidate() + if let Some(lane) = &self.established + && let Err(error) = lane.admission.revalidate() { self.fence.store(FENCE_REVOKED, Ordering::Release); return Err(ZoneLinkSessionError::RouteAdmission(error)); } - if self.admission.as_ref().is_some_and(|admission| { - self.driver.generation() != admission.reconnect_generation().get() + if self.established.as_ref().is_some_and(|lane| { + self.driver.generation() != lane.admission.reconnect_generation().get() }) { self.fence.store(FENCE_REVOKED, Ordering::Release); return Err(ZoneLinkSessionError::RouteAdmission( From 8993f39e5c480b072efcbda987f0df90c1c86816 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:22:50 -0700 Subject: [PATCH 287/726] d2b-contracts-zone-session: narrow exported surface and totalize session lifts --- .../src/v3/emergency_policy.rs | 7 +--- .../src/v3/resource_export.rs | 6 --- .../src/v3/resource_import.rs | 3 -- .../d2b-contracts-zone-session/src/v3/zone.rs | 5 --- .../src/v3/zone_link.rs | 3 -- .../src/v3/zone_session.rs | 37 +++++++++++++++++-- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs index ac61e0151..9647cae39 100644 --- a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs +++ b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs @@ -138,11 +138,6 @@ impl EmergencyPolicySpec { }) } - /// Construct the inactive default policy. - pub fn default_values() -> Self { - Self::new(false, EmergencyScope::default(), 30, "").expect("default is valid") - } - /// Whether this policy contributes to the effective scope. pub const fn enabled(&self) -> bool { self.enabled @@ -169,7 +164,7 @@ redacted_debug!(EmergencyPolicySpec); impl Default for EmergencyPolicySpec { fn default() -> Self { - Self::default_values() + Self::new(false, EmergencyScope::default(), 30, "").expect("default is valid") } } diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs index 4015f0604..d1a876d1d 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs @@ -93,9 +93,6 @@ impl From for ResourceExportContractError { } } -/// Compatibility alias used by controller and Provider adapter callers. -pub type ResourceExportError = ResourceExportContractError; - /// Arbitration mode for one exported capability. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, @@ -152,9 +149,6 @@ pub enum ShareFairness { Weighted, } -/// Compatibility alias for callers that use the shorter fairness name. -pub type Fairness = ShareFairness; - /// Bounded quota and deadline policy shared by export and import requests. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs index 6fe12bdaf..0c5731474 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs @@ -82,9 +82,6 @@ impl From for ResourceImportContractError { } } -/// Compatibility alias used by controller and Provider adapter callers. -pub type ResourceImportError = ResourceImportContractError; - /// Disconnect behavior for a local projection Service. #[derive( Debug, diff --git a/packages/d2b-contracts-zone-session/src/v3/zone.rs b/packages/d2b-contracts-zone-session/src/v3/zone.rs index 9998c4a0a..a550e14a0 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone.rs @@ -69,11 +69,6 @@ impl ZoneSpec { pub const fn new() -> Self { Self {} } - - /// Validate the self-resource desired state. - pub const fn validate(&self) -> Result<(), ZoneContractError> { - Ok(()) - } } impl<'de> Deserialize<'de> for ZoneSpec { diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_link.rs b/packages/d2b-contracts-zone-session/src/v3/zone_link.rs index af731d9a3..97240afae 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_link.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_link.rs @@ -440,9 +440,6 @@ impl<'de> Deserialize<'de> for ZoneLinkStatusResource { } } -/// Alias used by generic status adapters. -pub type ZoneLinkStatus = ZoneLinkStatusResource; - /// Record admission of one locally queued intent. pub const fn admit_local_intent( pending: u32, diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs index 95e3ab5ec..f9e52260a 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs @@ -292,9 +292,24 @@ impl EndpointPurpose { /// Lifts a component-session purpose into the Zone taxonomy. /// /// Total: every component-session purpose has a Zone counterpart at the - /// same tag. + /// same tag. The exhaustive match makes a new component-session variant a + /// compile error here rather than a runtime panic. pub fn from_component_session(value: base::EndpointPurpose) -> Self { - Self::from_tag(value.tag()).expect("preserved component-session tag") + match value { + base::EndpointPurpose::LocalLifecycle => Self::LocalLifecycle, + base::EndpointPurpose::ResourceService => Self::ResourceService, + base::EndpointPurpose::ZoneLink => Self::ZoneLink, + base::EndpointPurpose::Bootstrap => Self::Bootstrap, + base::EndpointPurpose::ComponentSession => Self::ComponentSession, + base::EndpointPurpose::ResourceTransfer => Self::ResourceTransfer, + base::EndpointPurpose::ProviderControl => Self::ProviderControl, + base::EndpointPurpose::SensitiveCredential => Self::SensitiveCredential, + base::EndpointPurpose::UserControl => Self::UserControl, + base::EndpointPurpose::ControllerWatch => Self::ControllerWatch, + base::EndpointPurpose::NamedStream => Self::NamedStream, + base::EndpointPurpose::AuditExport => Self::AuditExport, + base::EndpointPurpose::SupportBundle => Self::SupportBundle, + } } /// Lowers this purpose into the component-session taxonomy. @@ -327,9 +342,23 @@ impl ServicePackage { /// Lifts a component-session service package into the Zone taxonomy. /// /// Total: every component-session package has a Zone counterpart at the - /// same tag. + /// same tag. The exhaustive match makes a new component-session variant a + /// compile error here rather than a runtime panic. pub fn from_component_session(value: base::ServicePackage) -> Self { - Self::from_tag(value.tag()).expect("preserved component-session tag") + match value { + base::ServicePackage::ResourceV3 => Self::ResourceV3, + base::ServicePackage::ControllerV3 => Self::ControllerV3, + base::ServicePackage::ProviderV3 => Self::ProviderV3, + base::ServicePackage::AuditV3 => Self::AuditV3, + base::ServicePackage::SupportV3 => Self::SupportV3, + base::ServicePackage::CredentialV3 => Self::CredentialV3, + base::ServicePackage::DisplayV3 => Self::DisplayV3, + base::ServicePackage::ClipboardV3 => Self::ClipboardV3, + base::ServicePackage::ClipboardBridgeV3 => Self::ClipboardBridgeV3, + base::ServicePackage::ClipboardPickerCoordV3 => Self::ClipboardPickerCoordV3, + base::ServicePackage::NotificationV3 => Self::NotificationV3, + base::ServicePackage::ConfigNixosV3 => Self::ConfigNixosV3, + } } /// Lowers this service package into the component-session taxonomy. From afb1fa59c1ac87dc544eb3c8d9db3d00dedcca5e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:22:52 -0700 Subject: [PATCH 288/726] d2b-session: make channel lookup fallible and remove handle panic paths --- packages/d2b-session/src/client.rs | 25 +++++++++++++------ packages/d2b-session/src/engine.rs | 15 +++++------ packages/d2b-session/src/fragmentation.rs | 7 +++++- packages/d2b-session/src/scheduler.rs | 25 ++++++++----------- packages/d2b-session/src/transport.rs | 21 +++++----------- .../d2b-session/tests/component_session.rs | 2 +- 6 files changed, 50 insertions(+), 45 deletions(-) diff --git a/packages/d2b-session/src/client.rs b/packages/d2b-session/src/client.rs index 4b6c6df66..551abacd0 100644 --- a/packages/d2b-session/src/client.rs +++ b/packages/d2b-session/src/client.rs @@ -223,16 +223,27 @@ enum SessionClientBridgeError { impl std::fmt::Display for SessionClientBridgeError { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str(match self { - Self::Cancelled => "component-session-client-cancelled", - Self::Frame => "component-session-client-frame-invalid", - Self::Session(_) => "component-session-client-session-failed", - Self::Transport => "component-session-client-transport-failed", - }) + match self { + Self::Cancelled => formatter.write_str("component-session-client-cancelled"), + Self::Frame => formatter.write_str("component-session-client-frame-invalid"), + Self::Session(error) => write!( + formatter, + "component-session-client-session-failed code={}", + error.code().as_str() + ), + Self::Transport => formatter.write_str("component-session-client-transport-failed"), + } } } -impl std::error::Error for SessionClientBridgeError {} +impl std::error::Error for SessionClientBridgeError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Session(error) => Some(error), + _ => None, + } + } +} #[cfg(test)] mod tests { diff --git a/packages/d2b-session/src/engine.rs b/packages/d2b-session/src/engine.rs index 5558b342e..00f65b9c6 100644 --- a/packages/d2b-session/src/engine.rs +++ b/packages/d2b-session/src/engine.rs @@ -874,7 +874,7 @@ impl SessionEngine { .reserve_send(stream, fragment.as_bytes().len())?; let logical_limit = self.offer.limits.logical_named_stream_bytes; let mut payload = Vec::with_capacity(FRAGMENT_HEADER_LEN + fragment.as_bytes().len()); - payload.extend_from_slice(&fragment.header.encode(len, logical_limit)?); + payload.extend_from_slice(&fragment.header().encode(len, logical_limit)?); payload.extend_from_slice(fragment.as_bytes()); let protected = self.protector @@ -1353,11 +1353,12 @@ impl SessionEngine { async fn flush(&mut self) -> Result<()> { while let Some(frame) = self.scheduler.dequeue() { - let (kind, channel) = match frame.class() { - QueueClass::SessionControl => (RecordKind::SessionControl, frame.channel()), - QueueClass::TtrpcControl => (RecordKind::Ttrpc, frame.channel()), - QueueClass::AttachmentControl => (RecordKind::Attachment, frame.channel()), - QueueClass::NamedStream => (RecordKind::NamedStream, frame.channel()), + let channel = frame.channel()?; + let kind = match frame.class() { + QueueClass::SessionControl => RecordKind::SessionControl, + QueueClass::TtrpcControl => RecordKind::Ttrpc, + QueueClass::AttachmentControl => RecordKind::Attachment, + QueueClass::NamedStream => RecordKind::NamedStream, }; self.send_logical(kind, channel, frame.as_bytes().to_vec(), Vec::new()) .await?; @@ -1391,7 +1392,7 @@ impl SessionEngine { .map_err(|_| SessionError::new(SessionErrorCode::ArithmeticOverflow))?; let mut record_payload = Vec::with_capacity(FRAGMENT_HEADER_LEN + fragment.as_bytes().len()); - record_payload.extend_from_slice(&fragment.header.encode(fragment_len, limit)?); + record_payload.extend_from_slice(&fragment.header().encode(fragment_len, limit)?); record_payload.extend_from_slice(fragment.as_bytes()); let protected = self.protector.protect(kind, channel, &record_payload)?; let packet_attachments = attachments.take().unwrap_or_default(); diff --git a/packages/d2b-session/src/fragmentation.rs b/packages/d2b-session/src/fragmentation.rs index e9e1e0989..3c36ca429 100644 --- a/packages/d2b-session/src/fragmentation.rs +++ b/packages/d2b-session/src/fragmentation.rs @@ -8,11 +8,16 @@ use d2b_contracts_zone_session::v3::component_session::{ use crate::{Result, SessionError}; pub struct Fragment { - pub header: FragmentHeader, + header: FragmentHeader, bytes: Vec, } impl Fragment { + /// Borrow the fragment header. + pub fn header(&self) -> &FragmentHeader { + &self.header + } + pub fn as_bytes(&self) -> &[u8] { &self.bytes } diff --git a/packages/d2b-session/src/scheduler.rs b/packages/d2b-session/src/scheduler.rs index d4a2d3db9..d724867bc 100644 --- a/packages/d2b-session/src/scheduler.rs +++ b/packages/d2b-session/src/scheduler.rs @@ -3,7 +3,9 @@ use std::{ fmt, }; -use d2b_contracts_zone_session::v3::component_session::{LimitProfile, SessionErrorCode}; +use d2b_contracts_zone_session::v3::component_session::{ + ChannelId, LimitProfile, SessionErrorCode, +}; use crate::{Result, SessionError, StreamId}; @@ -52,20 +54,15 @@ impl OutboundFrame { self.stream } - pub fn channel(&self) -> d2b_contracts_zone_session::v3::component_session::ChannelId { + pub fn channel(&self) -> Result { match self.class { - QueueClass::SessionControl => { - d2b_contracts_zone_session::v3::component_session::ChannelId::SESSION_CONTROL - } - QueueClass::TtrpcControl => { - d2b_contracts_zone_session::v3::component_session::ChannelId::TTRPC_CONTROL - } - QueueClass::AttachmentControl => { - d2b_contracts_zone_session::v3::component_session::ChannelId::ATTACHMENT_CONTROL - } - QueueClass::NamedStream => self.stream.map(StreamId::channel).unwrap_or( - d2b_contracts_zone_session::v3::component_session::ChannelId::SESSION_CONTROL, - ), + QueueClass::SessionControl => Ok(ChannelId::SESSION_CONTROL), + QueueClass::TtrpcControl => Ok(ChannelId::TTRPC_CONTROL), + QueueClass::AttachmentControl => Ok(ChannelId::ATTACHMENT_CONTROL), + QueueClass::NamedStream => self + .stream + .map(StreamId::channel) + .ok_or_else(|| SessionError::new(SessionErrorCode::InvalidChannel)), } } diff --git a/packages/d2b-session/src/transport.rs b/packages/d2b-session/src/transport.rs index b6a49e0ee..45ec09285 100644 --- a/packages/d2b-session/src/transport.rs +++ b/packages/d2b-session/src/transport.rs @@ -155,7 +155,7 @@ pub trait OwnedTransport: Send + 'static { /// The handle exposes only the transport descriptor and the ability to /// consume or close the owned carriage. It carries no ZoneLink state, /// authorization claims, or raw locator. -pub struct OwnedTransportHandle(Option>); +pub struct OwnedTransportHandle(Box); impl OwnedTransportHandle { /// Wrap one owned transport without exposing its implementation type. @@ -163,36 +163,27 @@ impl OwnedTransportHandle { where T: OwnedTransport, { - Self(Some(Box::new(transport))) + Self(Box::new(transport)) } /// Wrap an already erased owned transport. pub fn from_box(transport: Box) -> Self { - Self(Some(transport)) + Self(transport) } /// Borrow the immutable carriage descriptor. pub fn descriptor(&self) -> TransportDescriptor { - self.0 - .as_ref() - .expect("an owned transport handle is consumed only once") - .descriptor() + self.0.descriptor() } /// Consume the handle and return the session-owned transport. - pub fn into_owned_transport(mut self) -> Box { + pub fn into_owned_transport(self) -> Box { self.0 - .take() - .expect("an owned transport handle is consumed only once") } /// Close the owned carriage and consume the handle. pub async fn close(mut self) -> std::result::Result<(), TransportError> { - self.0 - .take() - .expect("an owned transport handle is consumed only once") - .close() - .await + self.0.close().await } } diff --git a/packages/d2b-session/tests/component_session.rs b/packages/d2b-session/tests/component_session.rs index 146395e9b..8696903db 100644 --- a/packages/d2b-session/tests/component_session.rs +++ b/packages/d2b-session/tests/component_session.rs @@ -822,7 +822,7 @@ fn named_stream_state_and_scheduler_have_independent_credit_and_fairness() { ); let ttrpc = OutboundFrame::control(QueueClass::TtrpcControl, vec![1]).unwrap(); - assert_eq!(ttrpc.channel(), ChannelId::TTRPC_CONTROL); + assert_eq!(ttrpc.channel(), Ok(ChannelId::TTRPC_CONTROL)); } #[test] From 9024c13d9b9d6d356a3bc8a3a933a32deef7c7c4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:23:01 -0700 Subject: [PATCH 289/726] clipboard-wayland: drop dead host TTL and policy accessor from config --- .../src/service/mod.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/service/mod.rs b/packages/d2b-provider-clipboard-wayland/src/service/mod.rs index 577c080e3..13ae136a4 100644 --- a/packages/d2b-provider-clipboard-wayland/src/service/mod.rs +++ b/packages/d2b-provider-clipboard-wayland/src/service/mod.rs @@ -1286,7 +1286,6 @@ pub(crate) fn operation_id_for_sessions( #[derive(Debug, Clone, PartialEq, Eq)] pub struct ClipboardConfig { policy: Policy, - host_entry_ttl_secs: u64, guest_entry_ttl_secs: u64, } @@ -1294,7 +1293,6 @@ impl Default for ClipboardConfig { fn default() -> Self { Self { policy: Policy::default(), - host_entry_ttl_secs: 3600, guest_entry_ttl_secs: 3600, } } @@ -1309,11 +1307,6 @@ impl ClipboardConfig { } } - /// Return the policy. - pub const fn policy(&self) -> &Policy { - &self.policy - } - /// Return item byte limit. pub const fn max_item_bytes(&self) -> usize { self.policy.max_item_bytes() @@ -1334,11 +1327,6 @@ impl ClipboardConfig { self.policy.max_guest_rate_per_min() } - /// Return Host entry TTL. - pub const fn host_entry_ttl_secs(&self) -> u64 { - self.host_entry_ttl_secs - } - /// Return Guest entry TTL. pub const fn guest_entry_ttl_secs(&self) -> u64 { self.guest_entry_ttl_secs From 9185395243a1a59b35d2a6247c9dbb92955a4e40 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:23:40 -0700 Subject: [PATCH 290/726] d2bd-runtime: make log event fields lazy --- .../src/resource_runtime_support.rs | 67 ++++++++++--------- .../src/ssh_host_key_preflight.rs | 2 +- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/packages/d2bd-runtime/src/resource_runtime_support.rs b/packages/d2bd-runtime/src/resource_runtime_support.rs index 1f0a01e2b..6d2c1a263 100644 --- a/packages/d2bd-runtime/src/resource_runtime_support.rs +++ b/packages/d2bd-runtime/src/resource_runtime_support.rs @@ -644,43 +644,44 @@ pub fn compile_committed_policy_with_subjects( // grant those subjects would receive. Name each subject and // what the evidence said so a compile that dropped them is // diagnosable from the journal. - let subjects = binding_spec - .subjects() - .iter() - .map(|subject_ref| { - let row = resources + tracing::warn!( + zone = zone.as_str(), + resource = resource.resource_ref.to_canonical_string(), + subjects = tracing::field::display( + binding_spec + .subjects() .iter() - .find(|candidate| candidate.resource_ref == *subject_ref); - let observed = row - .and_then(|candidate| { - ResourceEnvelope::from_json(&candidate.canonical_json).ok() - }) - .map(|envelope| { + .map(|subject_ref| { + let row = resources + .iter() + .find(|candidate| candidate.resource_ref == *subject_ref); + let observed = row + .and_then(|candidate| { + ResourceEnvelope::from_json(&candidate.canonical_json).ok() + }) + .map(|envelope| { + format!( + "phase={:?} observedGeneration={} rowGeneration={}", + envelope.status().phase(), + envelope.status().observed_generation().get(), + row.map(|row| row.generation.get()).unwrap_or_default(), + ) + }) + .unwrap_or_else(|| "undecodable".to_owned()); format!( - "phase={:?} observedGeneration={} rowGeneration={}", - envelope.status().phase(), - envelope.status().observed_generation().get(), - row.map(|row| row.generation.get()).unwrap_or_default(), + "{}={} [{}]", + subject_ref.to_canonical_string(), + match subject_evidence.get(subject_ref) { + Some((_, true)) => "bindable", + Some((_, false)) => "tombstoned", + None => "no-row", + }, + observed, ) }) - .unwrap_or_else(|| "undecodable".to_owned()); - format!( - "{}={} [{}]", - subject_ref.to_canonical_string(), - match subject_evidence.get(subject_ref) { - Some((_, true)) => "bindable", - Some((_, false)) => "tombstoned", - None => "no-row", - }, - observed, - ) - }) - .collect::>() - .join(","); - tracing::warn!( - zone = zone.as_str(), - resource = resource.resource_ref.to_canonical_string(), - subjects = %subjects, + .collect::>() + .join(","), + ), "committed RoleBinding dropped: no subject satisfied the readiness gate", ); continue; diff --git a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs index a58a06153..9e39ae653 100644 --- a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs +++ b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs @@ -301,7 +301,7 @@ pub fn check_sshd_host_keys(vm: &str, keys_dir: &Path) -> Result<(), SshdHostKey outcome = "key-entry-ok", uid, gid, - mode = format!("{mode:o}"), + mode = tracing::field::debug(format_args!("{mode:o}")), "ssh-host-key-preflight: key entry OK", ); } From 0c890a18f4d189d70e7f1a94a0c6a55cf01f2792 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:23:50 -0700 Subject: [PATCH 291/726] audit: fold the eight closed wave-2 slices into the ledger 81 rows carry their final outcome and commit; the remaining wave-2 slices fold as they close. --- .../2026-09-24-rust-skills-audit/ledger.md | 162 +++++++++--------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index ed9d10993..02f3940d3 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -306,7 +306,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resou` | | | | `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `role_binding.rs:179-182, role_binding.rs:149-162` | | | | `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | | | | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | -| `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/manifest_v04.rs:313` | | | +| `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | | `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:985-988` | | | | `RS-0262` | `type` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | | | | `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:387, packages/d2b-process-conformance/src/t` | | | @@ -341,21 +341,21 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/identity.rs:72-88, src/identity.rs:146-150` | | | | `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:124` | | | | `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs` | | | -| `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | | | | `scheduler.rs:18-21, scheduler.rs:66-68` | | | +| `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/scheduler.rs | channel() now returns Result; the constructor-prevented NamedStream-without-stream combination yields InvalidChannel instead of a silent SESSION_CONTROL misroute. Census re-run: only caller | | | `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1702, engine.rs:1295, engine.rs:31` | | | | `RS-0299` | `type` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/` | | | -| `RS-0303` | `type` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:18659, packages/d2bd/src/composition.rs:18608` | | | -| `RS-0305` | `type` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:1299, packages/d2bd/src/shared_provider_effec` | | | -| `RS-0302` | `type` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:16152, packages/d2bd/src/composition.rs:16155, packages/d` | | | -| `RS-0300` | `type` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:3041, packages/d2bd/src/resource_runtime.rs:3230, pa` | | | -| `RS-0301` | `type` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:1014, packages/d2bd/src/resource_runtime.rs:7614` | | | +| `RS-0303` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | force semantics implemented in apply(): dropped `let _ = self.force;` and gated the graceful wait on `wait_for_ready && !force`. Checks: cargo check -p d2bd --locked --all-targets green. | | +| `RS-0305` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | b310cab7bdafa68156e88ee513f3083bbe3d25a2 | packages/d2bd/src/shared_provider_effects.rs | Added crate-private SharedProviderEffectMode enum (Deserialize, rename_all kebab-case) with a fail-closed parse; both stringly-compare sites (usbip_service_port opted_in, reconcile_security_key projec | | +| `RS-0302` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | ShutdownDegradedMarker now stores VmShutdownOutcome enum (derive Serialize/Deserialize, rename_all snake_case) instead of String outcome/severity; construction site passes the enum. Report shape uncha | | +| `RS-0300` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ZoneResourceRuntime gate trio (policy_installed/controller_endpoint_registered/watch_admitted) replaced by PlanePublicationStage { BootstrapOnly, Published } set at open and activate_published_bundle; | | +| `RS-0301` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ControllerSession teardown trio (ingress_revoked/assignments_revoked/transport_closed) replaced by a TeardownStage enum advanced monotonically (Active -> IngressRevoked -> AssignmentsRevoked -> Transp | | | `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d` | | | -| `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | | | | `resource_operator_activation.rs:129-182, resource_operator_activation.rs:163-177` | | | +| `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | 7e0ec2bce | packages/d2bd-runtime/src/admission.rs | peer admission lookup mode modelled self-describing; check + admission tests green (worker reported the oid as already present after committing its own change; the commit is this branch's) | | | `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | | | | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | | | | `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | | | | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | -| `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | | | | `admission.rs:107-108, admission.rs:66, admission.rs:83` | | | -| `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | | | | `component_session_vsock.rs:32-36` | | | -| `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/typed_shell_targets.rs:13, packages/d2bd-runtime/src/typed_shell` | | | +| `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | d1c5c44d9 | packages/d2bd-runtime/src/typed_shell_targets.rs | typed-shell target key becomes a named struct with a constructor; the three composition.rs cache call sites migrate to it | | +| `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | +| `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | | `RS-0314` | `type` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557` | | | | `RS-0313` | `type` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:5104, packages/xtask/src/provider_crate_policy` | | | | `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | @@ -367,13 +367,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0353` | `api` | `d2b` | low | actionable | leaf | | | | `zone_support_bundle.rs:19, zone_support_bundle.rs:28, zone_support_bundle.rs:99, zone_supp` | | | | `RS-0354` | `api` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/lib.rs:25, packages/d2b/src/lib.rs:41, packages/d2b/src/doctor.rs:62, pac` | | | | `RS-0316` | `api` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/lib.rs:16, packages/d2b-audit/src/lib.rs:30, packages/d2b-audit/src` | | | -| `RS-0319` | `api` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/sysctl.rs:16, packages/d2b-broker/src/ops/sysctl.rs:84` | | | -| `RS-0320` | `api` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/route.rs:19` | | | -| `RS-0318` | `api` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/gpu.rs:13, packages/d2b-broker/src/ops/gpu.rs:24, packages/d2b` | | | +| `RS-0319` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | d10ee144f | packages/d2b-broker/src/ops/sysctl.rs | Demoted apply_sysctl_intents, ApplySysctlRequest, intent_to_proc_path to pub(crate) (tests at 258/283 keep them); deleted with_default_root (zero references anywhere, not even tests). Census re-run: a | | +| `RS-0320` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | bc367bab9 | packages/d2b-broker/src/ops/route.rs | RouteConflictKey made private (plain struct) and its six pub fields dropped to private; all users are in-file (route_conflicts, route_matches_record, requested_route_conflict_key, tests at 863). Censu | | +| `RS-0318` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | ee8678e46 | packages/d2b-broker/src/ops/gpu.rs | Item-level pub -> pub(crate) for all 19 gpu.rs items and 7 modprobe.rs items (types, impl methods, free fns, trait). Chose item-level over module-decl narrowing so d2b-core bundle_resolver.rs:4300 and | | | `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | | | | `src/lib.rs:45, src/ops/mod.rs:20-94` | | | | `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | | | -| `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/cgroup.rs:126-129, packages/d2b-broker/src/ops/cgroup.rs:343` | | | -| `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/kernel_ops.rs:99-100` | | | +| `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | 068ddcfc4 | packages/d2b-broker/src/ops/cgroup.rs | CgroupBundleContext::slice_path() now returns &Path (borrows parent_slice, no clone). Call sites: vm_interior_path join works on &Path; AuditFields slice_path and the D2bSlice tuple site keep one to_p | | +| `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | | `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1208, packages/d2b-bus/src/router.rs:1224, packages/d2b-bus` | | | | `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/authorization.rs:75, packages/d2b-bus/src/router.rs:1415-1416` | | | | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97` | | | @@ -387,15 +387,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src` | | | | `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/identity.rs:269-270` | | | -| `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `src/v3/resource_export.rs:97, src/v3/resource_export.rs:156, src/v3/resource_import.rs:86,` | | | -| `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `emergency_policy.rs:142, emergency_policy.rs:170` | | | -| `RS-0339` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `zone.rs:74` | | | +| `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | +| `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs | Deleted EmergencyPolicySpec::default_values(); Default::default() now constructs directly. Census: the Default impl was the only caller. | | +| `RS-0339` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone.rs | Removed ZoneSpec::validate (always-Ok). Census: no callers anywhere in the workspace or in-crate tests; the Deserialize gate remains the invariant. | | | `RS-0348` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-cor` | | | -| `RS-0345` | `api` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:620, packages/d2b-core/src/bundle_resolver.rs:641` | | | +| `RS-0345` | `api` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Nine zero-consumer resolved-intent types marked #[doc(hidden)] (kept for planned broker dispatch arms per module doc); census re-run: 0 consumers workspace-wide | | | `RS-0349` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:1` | | | | `RS-0346` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109` | | | -| `RS-0350` | `api` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/privileges.rs:741` | | | -| `RS-0347` | `api` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:24` | | | +| `RS-0350` | `api` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/privileges.rs | PrivilegesJson::w1 renamed to from_const_rows(); both test call sites updated; census re-run: only test callers exist | | +| `RS-0347` | `api` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_vm_start_intent and find_process_node narrowed to pub(crate) as stated; find_if_name_mapping_for_vm had ZERO callers anywhere (census re-run: only the definition), so pub(crate) tripped the de | | | `RS-0340` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/binding_children.rs:173, packages/d2b-core-controller/src` | | | | `RS-0341` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/controller_assignment.rs:2707, packages/d2b-core-controll` | | | | `RS-0342` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/coordinator.rs:252, packages/d2b-core-controller/src/coor` | | | @@ -481,23 +481,23 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:491-493` | | | | `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:460-462` | | | | `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | | | | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | | | -| `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | | | | `fragmentation.rs:10-13` | | | +| `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/fragmentation.rs | Fragment.header is now private with a pub header() accessor; the two engine.rs encode call sites (877, 1395) use the accessor. Census: no external field access. | | | `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:166, engine.rs:262, engine.rs:416, engine.rs:356` | | | | `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | | | | `packages/d2b-session-unix/src/socket.rs:176` | | | | `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | | | | `packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-sk-frontend/src/lib.rs:27, packages/d` | | | | `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/` | | | -| `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:398, packages/d2bd/src/composition.rs:400, packages/d2bd/` | | | -| `RS-0441` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2bd/src/resource_plane_v3.rs:3295, ` | | | -| `RS-0439` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/audio_host_controller.rs:59, packages/d2bd/src/audio_host_controller.rs:` | | | -| `RS-0440` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/audio_host_controller.rs:68, packages/d2bd/src/audio_host_controller.rs:` | | | -| `RS-0443` | `api` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_registry.rs:48, packages/d2bd/src/provider_registry.rs:288` | | | +| `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/composition.rs | process_provider_runtime and provider_effects narrowed to pub(crate) with a cfg(feature=test-support) pub mod seam for tests/resource_operator_activation.rs; test-only items (new_persistent, admit, pe | | +| `RS-0441` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/resource_plane_v3.rs | ResourcePlaneV3 accessors: targets()/hub() return Arc by value, store()/registry() return plain refs; Arc::clone(plane.hub()/targets()) sites updated to plane.hub()/plane.targets(); adopt_guest_target | | +| `RS-0439` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | pub surface reduced to pub(crate): trait HostAudioController, PipeWireHostController, from_audio_node, find_audio_node, QemuAudioController. Census re-run: only in-crate callers (audio_dispatch.rs); m | | +| `RS-0440` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | vm_name param removed from HostAudioController::enforce_grant/enforce_level, all three impls (PipeWire/Qemu/Fake), and all call sites incl. tests. Checks: cargo check green; cargo test -p d2bd --locke | | +| `RS-0443` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 524d06bad06c00ccf05c20c14461400478d70df3 | packages/d2bd/src/provider_registry.rs | Re-export narrowed to MAX_PROVIDER_REGISTRY_ENTRIES only; census re-run at HEAD shows ProviderRegistrySnapshot appears nowhere else in the workspace through d2bd's path (only the re-export line itself | | | `RS-0444` | `api` | `d2bd-runtime` | medium | actionable | family | | | | `shell_backend.rs:52-53` | | | -| `RS-0446` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/exec_session.rs:900` | | | -| `RS-0445` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `public_read_model.rs:51-53` | | | -| `RS-0447` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:118` | | | -| `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:341, packages/d2bd-runtime/src/console_sessio` | | | -| `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:54` | | | -| `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:66, packages/d2bd-runtime/src/console_session` | | | +| `RS-0446` | `api` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U3 | 225f36a3a | packages/d2bd-runtime/src/exec_session.rs | Variant of the row's fallback ('gate the module test-support-only'): the exec-session worker machinery (spawn_session_worker, WorkerSpawn, worker_main, WorkerState, TerminalReaper, OwnerReaper, Establ | | +| `RS-0445` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e10faa81f | packages/d2bd-runtime/src/ch_api.rs | ch vm.info payload deserialized through a derived raw shape with a round-trip test | | +| `RS-0447` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8b3164c4f | packages/d2bd-runtime/src/console_session.rs | ConsoleClientHandle field made private; added validating FromStr (console-<32 hex>) with ConsoleClientHandleParseError; table lookups stay allocation-free via existing Borrow/as_str (the already- | | +| `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 1ed0521fa | packages/d2bd-runtime/src/console_session.rs | Dropped unused _vm parameter from spawn_ch_serial_drainer and the hardcoded "ch-console".to_owned() allocation at the create_ch_session call site. | | +| `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e8e7a2d51 | packages/d2bd-runtime/src/console_session.rs | Deleted dead pub DrainerSource enum (census re-run: pattern DrainerSource over packages = 1 hit, the definition itself; zero constructions) and its #[allow(dead_code)]. | | +| `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 26d5c1119 | packages/d2bd-runtime/src/console_session.rs | ConsoleRing/ConsoleSession fields made private; ConsoleRing exposes push_bytes/set_eof (notify internally), read_at, base_offset, notify(); ConsoleSession exposes provider_kind/ring/stdin_tx accessors | | | `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | | | | `RS-0477` | `err` | `d2b` | medium | actionable | leaf | | | | `packages/d2b/src/host.rs:200, packages/d2b/src/resource.rs:916, packages/d2b/src/lib.rs:44` | | | | `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | | | | `packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, ` | | | @@ -505,9 +505,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b` | | | | `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | | `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | | | -| `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-broker/src/ops/hosts.rs:149, packag` | | | +| `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | | `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360` | | | -| `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/exec_reconcile.rs:1238-1265` | | | +| `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | | `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/depen` | | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/wire.rs:49-56` | | | @@ -519,13 +519,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-pr` | | | | `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:834, packages/d2b-contract` | | | | `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | -| `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | | | | `zone_session.rs:297, zone_session.rs:332` | | | -| `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:2625, packages/d2b-broker/src/runtime.rs:6405` | | | +| `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | +| `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_macvtap_intents now returns crate::error::Error via Error::manifest_parse_error (typed, two failure modes distinguishable); broker call site updated to house .map_err(/error/ BrokerError::Live | | | `RS-0475` | `err` | `d2b-core` | medium | actionable | family | | | | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | -| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | | | -| `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/site.rs:42` | | | -| `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1405, packages/d2b-core/src/bundle_resolver.rs:14` | | | -| `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:5730` | | | +| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | Stated fix (plumb Result out of build_resource_network_intents/find_network_spec) requires changing the public signatures of six resolve_network_*_intent methods consumed by d2bd (composition.rs:7247- | | +| `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/site.rs | SiteJson::validate returns SiteValidationError::InvalidWaylandSocket enum with Display token; caller and tests updated | | +| `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | +| `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | manifest_parse_reason now matches serde_json::Error::classify() (Category::Data/Syntax/Eof/Io) instead of Display text; all 8 call sites updated to pass &error; slug change not wire-visible per census | | | `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:412` | | | | `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/launch_identity.rs:147` | | | | `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activa` | | | @@ -562,35 +562,35 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | | | | `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69-78, packages/d2b-pro` | | | | `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-pro` | | | -| `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | | | | `packages/d2b-provider-user/src/driver.rs:118-124, packages/d2b-contracts/src/failure_kinds` | | | +| `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | applied | U3 | 2ab7a1ed2 | packages/d2b-provider-user/src/driver.rs | Display impl now writes self.kind.failure_kind().code(); registered FailureKind codes remain the single source, strings unchanged, no behavior change. | | | `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | | | | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-bindi` | | | | `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 (driver-args class member key_ref; RS-0962) | -| `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | | | | `packages/d2b-provider-wayland-session/src/wayland_session.rs:73` | | | +| `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | applied | U3 | e783447e2 | packages/d2b-provider-wayland-session/Cargo.toml | Added tracing = 0.1 (already in lockfile; Cargo.lock records one new dep edge) and map_err now logs provider=WAYLAND_SESSION_PROVIDER_REF with reason=%error before mapping to InvalidResource. | | | `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:867-868` | | | | `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309` | | | | `RS-0520` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/error.rs:773, packages/d2b-resource-runtime/src/manager.` | | | | `RS-0521` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spe` | | | -| `RS-0522` | `err` | `d2b-session` | medium | actionable | leaf | | | | `transport.rs:170, transport.rs:178, transport.rs:185, transport.rs:173` | | | -| `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | | | | `client.rs:216, client.rs:224, client.rs:237` | | | +| `RS-0522` | `err` | `d2b-session` | medium | actionable | leaf | applied-variant | U3 | afb1fa59c | packages/d2b-session/src/transport.rs | Applied the typestate option minimally: the Option> wrapper is gone (plain Box), so the consumed state is unrepresentable and all three expects disappeared; public signatures a | | +| `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | | `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | | | | `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_` | | | | `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | | | -| `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:8140, packages/d2bd-runtime/src/workload_dispatch.rs:104,` | | | -| `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:5365, packages/d2bd/src/interaction_compositi` | | | -| `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/resource_plane_v3.rs:3016, ` | | | -| `RS-0535` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/effect_service_actors.rs:551, packages/d2bd/src/effect_service_actors.rs` | | | +| `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | record_workload_availability_metrics expect-panic on label drift; single source of truth / graceful entry. Not edited: budget exhausted. | | +| `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | +| `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/resource_plane_v3.rs | PlaneError five String variants -> typed payload/#[source]. Not edited: budget exhausted. | | +| `RS-0535` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 7ec590e1d4fcc3ed3185dec638f30698f442779d | packages/d2bd/src/effect_service_actors.rs | Both silent spawn drops (restart-recovery loop in pre_start, supervise_exit) now log tracing::warn! with service/zone/error fields, keeping non-fatal recovery semantics. cargo check green; clippy gree | | | `RS-0527` | `err` | `d2bd` | medium | actionable | family | | | | `packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511` | | | -| `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:22793-22797, packages/d2b-contracts-control/src/public_wi` | | | -| `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:20185-20190` | | | +| `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Mapped: dispatch_audit Some(_) severity arm at ~22793 returns TypedError::InternalIo; fix is to return TypedError::WireInvalidFrame (existing kind, no new wire variant). Not edited: budget exhausted. | | +| `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | ActivationLockGuard::drop finish_activation failure should log tracing::warn!. Not edited: budget exhausted. | | | `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | | | | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | | | -| `RS-0534` | `err` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/resource_plane_v3.rs:1956` | | | -| `RS-0536` | `err` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:3436` | | | +| `RS-0534` | `err` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/resource_plane_v3.rs | ConstructionInputs::production swallows attach_process_providers Result. Not edited: budget exhausted. | | +| `RS-0536` | `err` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/process_provider_runtime.rs | 0700 set_permissions silently swallowed; warn on Err. Not edited: budget exhausted. | | | `RS-0528` | `err` | `d2bd` | low | actionable | family | | | | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | | | -| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | applied-variant | U1 | ebb3831b1 | packages/d2bd-runtime/src/broker_transport.rs, packages/d2bd/src/composition.rs | claim re-verified unreachable at HEAD (digests canonicalized before parse); applied anyway to remove the latent expect and mirror the sibling typed refusal - callers updated | | -| `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | | | | `wire.rs:529-536` | | | -| `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/exec_session.rs:939` | | | -| `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:132` | | | -| `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/daemon_version.rs:77, packages/d2bd-runtime/src/daemon_version.r` | | | +| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | not-started | U3 | | packages/d2bd-runtime/src/broker_transport.rs, packages/d2bd/src/composition.rs | worker could not map the row to the cited anchor; left untouched | | +| `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | c14b5d486 | packages/d2bd-runtime/src/wire.rs | map_parse_error classifies structurally: serde_json::Error::classify() gates the frame kind, and the generic WireInvalidFrame detail now carries line/column; the two payload-level wire kinds (unknown- | | +| `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | cdfb78d49 | packages/d2bd-runtime/src/exec_session.rs | spawn_session_worker now returns std::io::Result> (Builder::spawn error propagated via Ok(...)?), replacing the expect panic; the two test call sites unwrap with expect. | | +| `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 75c49e784 | packages/d2bd-runtime/src/console_session.rs | Deleted panicking impl Default for ConsoleClientHandle (census: no ConsoleClientHandle::default() callers in workspace). | | +| `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | a09140432 | packages/d2bd-runtime/src/daemon_version.rs | version-file read failures typed (VersionFileReadError); check + tests green | | | `RS-0543` | `err` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/delivery/recovery.rs:384, packages/xtask/src/delivery/recovery.rs:1610,` | | | | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | | | @@ -602,9 +602,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | | `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | | `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | | | | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | | | -| `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/storage_lifecycle.rs:49, packages/d2b-core/src/storage_lifecycle.rs:` | | | +| `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/storage_lifecycle.rs | serde rejects rename_all on struct variants (field attribute); applied the equivalent house pattern #[serde(rename_all_fields = "camelCase")] on the enum container + dropped per-field renames; seriali | | | `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175` | | | -| `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:183, packages/d2b-core/src/bundle_resolver.rs:187` | | | +| `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | | `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | | | | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | | | | `RS-0557` | `serde` | `d2b-host` | low | actionable | family | | | | `packages/d2b-host/src/nftables.rs:229` | | | | `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/status.rs:125, packages/d2b-process-conformance/src/t` | | | @@ -614,7 +614,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/` | | | | `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | | | | `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:230, src/spec.rs:233, src/spec.rs:263` | | | -| `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | | | | `packages/d2b-provider-endpoint/src/endpoint.rs:112-120, packages/d2b-provider-endpoint/src` | | | +| `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | | `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/driver.rs:282-289, src/driver.rs:190` | | | | `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429` | | | | `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generate` | | | @@ -624,20 +624,20 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | | | | `src/content.rs:38-39, src/content.rs:106-107, src/content.rs:203-204, src/content.rs:239-2` | | | | `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | | `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | | | | `manager_backend.rs:744-745` | | | -| `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:4196, packages/d2bd/src/composition.rs:4205` | | | +| `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | GatewayGuestConfigFile/GatewayGuestRelayConfigFile need deny_unknown_fields + config-typo test. Not edited: budget exhausted. | | | `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d` | | | -| `RS-0577` | `serde` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:979-981` | | | -| `RS-0578` | `serde` | `d2bd-runtime` | low | actionable | leaf | | | | `wire.rs:265-353` | | | -| `RS-0579` | `serde` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/ch_api.rs:79` | | | +| `RS-0577` | `serde` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | declared_fd_kind now matches the seven kebab-case FdKind spellings directly (fifo/socket/char-device/block-device/any/regular/directory) instead of allocating a serde_json::Value::String; behavior ide | | +| `RS-0578` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 3e78efe56 | packages/d2bd-runtime/src/wire.rs | parse_request now dispatches the 17 plain verbs (list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio) throug | | +| `RS-0579` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | version-file write failures reported through tracing | | | `RS-0580` | `serde` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/service_catalog.rs:22, packages/xtask/src/provider_registration_authori` | | | | `RS-0582` | `serde` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111` | | | | `RS-0581` | `serde` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/resource_type_authority.rs:179, packages/xtask/src/resource_type_author` | | | | `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:25` | | | -| `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1097` | | | +| `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | | `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activa` | | | | `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100` | | | | `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provide` | | | -| `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/service.rs:860` | | | +| `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | | `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:346, src/controller/mod.rs:425` | | | | `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:352, packages/d2b-provi` | | | | `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-system` | | | @@ -646,23 +646,23 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src` | | | | `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | | | | `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-` | | | -| `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | | | | `packages/d2b-provider-transport-unix/src/portal.rs:217-220, packages/d2b-provider-transpor` | | | +| `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | | `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/service.rs:392, packages/d2b-provider-transport-` | | | | `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/service.rs:735, packages/d2b-provider-transport-` | | | | `RS-0600` | `obs` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:1992` | | | | `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/protocol.rs:188` | | | -| `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/composition.rs:4081, packages/d2bd/src/composition.rs:4099, packages/d2b` | | | -| `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:4487, packages/d2bd/src/composition.rs:4538, packages/d2b` | | | -| `RS-0607` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/provider_lifecycle.rs:1085` | | | -| `RS-0602` | `obs` | `d2bd` | low | actionable | leaf | | | `instrument` = 0), so the events lose the underlying error: most are inside `map_err` closu` | | | -| `RS-0603` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:14781` | | | -| `RS-0604` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/composition.rs:15195, packages/d2bd/src/composition.rs:15221` | | | -| `RS-0608` | `obs` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:1250` | | | -| `RS-0609` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs` | | | -| `RS-0610` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680` | | | -| `RS-0611` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/readiness.rs:327` | | | -| `RS-0612` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132` | | | -| `RS-0613` | `obs` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/console_session.rs:450` | | | +| `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Accept-loop eprintln! -> tracing::error! with named fields (sites at 4102/4120/4153/4159). Not edited: budget exhausted. | | +| `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Three lifecycle info! events message-only; add named fields. Not edited: budget exhausted. | | +| `RS-0607` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 31248998b093d92fef1e41eb07ecb49e3b79d33c | packages/d2bd/src/provider_lifecycle.rs | publish_trusted_context failure arm now carries error = %error as a named field, matching the sibling Ok(_) arm and the plane's other warn sites. cargo check green; clippy green for d2bd. | | +| `RS-0602` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 73f90a27e93a9d36942287072f2f8a9c398aee53 | packages/d2bd/src/resource_runtime.rs | The eight named map_err closures (envelope/spec/construction/current-resource/status-serialization/descriptor-decode/descriptor-verify/controller-construction) now capture the error and log it as erro | | +| `RS-0603` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Located at composition.rs:14815 (drifted from 14781): message-only error; add zone field. Not edited: budget exhausted. | | +| `RS-0604` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Two identical message-only warn events during shutdown; add zones field. Not edited: budget exhausted. | | +| `RS-0608` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | In-flight-cap refusal warn now carries peer_uid and max = posture.max_inflight fields, matching the sibling peer-not-broker warn style. Committed together with RS-0577 (same file, same commit). cargo | | +| `RS-0609` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs` | typed-shell octal format wait not implemented in session | | +| `RS-0610` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680` | ssh_host_key_preflight octal wait not implemented in session | | +| `RS-0611` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `packages/d2bd-runtime/src/readiness.rs:327` | readiness one-shot-exit warning fields not implemented in session | | +| `RS-0612` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132` | pidfs probe warning named fields not implemented in session | | +| `RS-0613` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 785aebb20 | packages/d2bd-runtime/src/console_session.rs | qemu console fd-conversion warn now carries error = %e as a named field; no correlation identifiers in the record. | | | `RS-0659` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/exec_client.rs` | one-line docs for expect_start/expect_detached_create/list/logs/status/kill | | | `RS-0658` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/doctor.rs` | docs for doctor/validate/CLI surface incl. crate-level doc | | | `RS-0614` | `docs` | `d2b-audit` | low | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/export.rs` | # Errors sections on 11 pub Result items; # Examples doctests on AuditRecord::new and SegmentWriter::open, both passing (cargo test --doc 2/2). | | From fb67a0526ab60b7b8bbf9e419076772b90f1623f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:24:05 -0700 Subject: [PATCH 292/726] clipboard-wayland: make history construction infallible --- .../d2b-provider-clipboard-wayland/src/history.rs | 12 ++++++------ .../src/service/mod.rs | 6 +----- .../tests/lifecycle.rs | 2 +- .../tests/provider_behavior.rs | 4 ++-- .../tests/redaction.rs | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/history.rs b/packages/d2b-provider-clipboard-wayland/src/history.rs index 065c9a2ea..a40e4e40d 100644 --- a/packages/d2b-provider-clipboard-wayland/src/history.rs +++ b/packages/d2b-provider-clipboard-wayland/src/history.rs @@ -134,8 +134,8 @@ pub struct ClipboardHistory { impl ClipboardHistory { /// Construct an empty history. - pub fn new(config: crate::ClipboardConfig) -> Result { - Ok(Self { + pub fn new(config: crate::ClipboardConfig) -> Self { + Self { config, entries: BTreeMap::new(), order: VecDeque::new(), @@ -143,7 +143,7 @@ impl ClipboardHistory { suspended: BTreeSet::new(), guest_requests: BTreeMap::new(), picker_completions: BTreeMap::new(), - }) + } } /// Insert an entry after policy, quota, and rate checks. @@ -403,7 +403,7 @@ mod tests { #[test] fn gc_prunes_idle_guest_rate_buckets() { - let mut history = ClipboardHistory::new(ClipboardConfig::default()).unwrap(); + let mut history = ClipboardHistory::new(ClipboardConfig::default()); history.record_guest_request("Guest/work", 100).unwrap(); assert_eq!(history.guest_requests.len(), 1); history.gc(160); @@ -412,7 +412,7 @@ mod tests { #[test] fn history_normalizes_mime_values_before_storage_and_matching() { - let mut history = ClipboardHistory::new(ClipboardConfig::default()).unwrap(); + let mut history = ClipboardHistory::new(ClipboardConfig::default()); let entry = ClipboardEntry::new("Guest/work", "TEXT/PLAIN", b"hello", 100).unwrap(); let token = entry.token().to_owned(); history.insert(entry).unwrap(); @@ -430,7 +430,7 @@ mod tests { #[test] fn purging_a_guest_releases_its_picker_completion_keys() { - let mut history = ClipboardHistory::new(ClipboardConfig::default()).unwrap(); + let mut history = ClipboardHistory::new(ClipboardConfig::default()); let key = "operation|zone|Guest/work|1|zone|Guest/destination|1".to_owned(); assert!(history.claim_picker_completion(key.clone(), 200, 100)); history.purge_guest("Guest/work"); diff --git a/packages/d2b-provider-clipboard-wayland/src/service/mod.rs b/packages/d2b-provider-clipboard-wayland/src/service/mod.rs index 13ae136a4..7712e1c64 100644 --- a/packages/d2b-provider-clipboard-wayland/src/service/mod.rs +++ b/packages/d2b-provider-clipboard-wayland/src/service/mod.rs @@ -572,11 +572,7 @@ impl ClipdHost { audit_capacity: usize, display: Option, ) -> Result { - let history = ClipboardHistory::new(crate::ClipboardConfig::from_policy(policy.clone())) - .map_err(|_e| { - tracing::warn!("clipboard history construction refused at service start"); - ClipboardServiceError::HistoryRejected - })?; + let history = ClipboardHistory::new(crate::ClipboardConfig::from_policy(policy.clone())); let max_concurrent_fds = policy.max_concurrent_fds(); let mut host = Self { policy, diff --git a/packages/d2b-provider-clipboard-wayland/tests/lifecycle.rs b/packages/d2b-provider-clipboard-wayland/tests/lifecycle.rs index 46c8c7f93..439bd28c3 100644 --- a/packages/d2b-provider-clipboard-wayland/tests/lifecycle.rs +++ b/packages/d2b-provider-clipboard-wayland/tests/lifecycle.rs @@ -2,7 +2,7 @@ use d2b_provider_clipboard_wayland::{ClipboardConfig, ClipboardEntry, ClipboardH #[test] fn guest_destroy_purges_history() { - let mut history = ClipboardHistory::new(ClipboardConfig::default()).unwrap(); + let mut history = ClipboardHistory::new(ClipboardConfig::default()); history .insert(ClipboardEntry::new("Guest/work", "text/plain", b"x", 1).unwrap()) .unwrap(); diff --git a/packages/d2b-provider-clipboard-wayland/tests/provider_behavior.rs b/packages/d2b-provider-clipboard-wayland/tests/provider_behavior.rs index dc3d29c14..2272e47a3 100644 --- a/packages/d2b-provider-clipboard-wayland/tests/provider_behavior.rs +++ b/packages/d2b-provider-clipboard-wayland/tests/provider_behavior.rs @@ -45,7 +45,7 @@ fn fd_validation_rejects_unsafe_files_and_truncated_control_messages() { #[test] fn history_is_bounded_ttl_aware_and_purges_guest_state() { let config = ClipboardConfig::default(); - let mut history = ClipboardHistory::new(config.clone()).unwrap(); + let mut history = ClipboardHistory::new(config.clone()); let entry = ClipboardEntry::new("Guest/work", "text/plain", b"hello", 100).unwrap(); history.insert(entry).unwrap(); assert_eq!(history.len(), 1); @@ -64,7 +64,7 @@ fn history_is_bounded_ttl_aware_and_purges_guest_state() { fn duplicate_history_tokens_do_not_double_count_quota() { let policy = Policy::new(true, true, true, true, false, 3, 4096, 4096, 32, 60).unwrap(); let config = ClipboardConfig::from_policy(policy); - let mut history = ClipboardHistory::new(config).unwrap(); + let mut history = ClipboardHistory::new(config); let first = ClipboardEntry::new("Guest/work", "text/plain", &[1; 2000], 100).unwrap(); let duplicate = ClipboardEntry::new("Guest/work", "text/plain", &[1; 2000], 100).unwrap(); let second = ClipboardEntry::new("Guest/work", "text/plain", &[2; 2000], 101).unwrap(); diff --git a/packages/d2b-provider-clipboard-wayland/tests/redaction.rs b/packages/d2b-provider-clipboard-wayland/tests/redaction.rs index 8efb0ec77..9396afe88 100644 --- a/packages/d2b-provider-clipboard-wayland/tests/redaction.rs +++ b/packages/d2b-provider-clipboard-wayland/tests/redaction.rs @@ -8,7 +8,7 @@ fn payload_canary_stays_out_of_clipboard_debug_and_audit() { const CANARY: &str = "clipboard-payload-canary-7f4a"; let entry = ClipboardEntry::new("Guest/work", "text/plain", CANARY.as_bytes(), 100).expect("entry"); - let mut history = ClipboardHistory::new(ClipboardConfig::default()).expect("history"); + let mut history = ClipboardHistory::new(ClipboardConfig::default()); history.insert(entry).expect("insert"); let debug = format!("{history:?}"); From d4fe8381228b0335e2442898f5a1d5f71826ba7e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:24:31 -0700 Subject: [PATCH 293/726] d2bd: refuse invalid audit severity as a wire error --- packages/d2bd/src/composition.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 581e5ec1a..4b9eab5c0 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -22804,9 +22804,8 @@ fn dispatch_audit( Some("denied") => Ok(Some( d2b_contracts_broker::broker_wire::BrokerAuditSeverity::Denied, )), - Some(_) => Err(TypedError::InternalIo { - context: "audit filter".to_owned(), - detail: "severity-invalid".to_owned(), + Some(_) => Err(TypedError::WireInvalidFrame { + detail: "audit filter has an invalid severity".to_owned(), }), }?; Ok::<_, TypedError>(d2b_contracts_broker::broker_wire::BrokerAuditFilter { From 669ec10a297d99e02f89325d52e5fe4d55a44e08 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:24:43 -0700 Subject: [PATCH 294/726] contracts-zone-session: encode empty-allowed policy in a typed enum --- .../src/v3/role_binding.rs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/d2b-contracts-zone-session/src/v3/role_binding.rs b/packages/d2b-contracts-zone-session/src/v3/role_binding.rs index 0506a3b53..a01a50530 100644 --- a/packages/d2b-contracts-zone-session/src/v3/role_binding.rs +++ b/packages/d2b-contracts-zone-session/src/v3/role_binding.rs @@ -149,17 +149,17 @@ impl ScopeNarrowing { && narrowing_set_is_subset( narrowed.subresources(), allowed.subresources(), - true, + EmptyAllowedPolicy::Unrestricted, ) && narrowing_names_are_subset( narrowed.resource_names(), allowed.resource_names(), ) - && narrowing_set_is_subset(narrowed.zones(), allowed.zones(), false) + && narrowing_set_is_subset(narrowed.zones(), allowed.zones(), EmptyAllowedPolicy::Deny) && narrowing_set_is_subset( narrowed.execution_refs(), allowed.execution_refs(), - true, + EmptyAllowedPolicy::Unrestricted, ) }) }) @@ -176,13 +176,26 @@ fn narrowing_names_are_subset(narrowed: &[String], allowed: &[String]) -> bool { .all(|item| item != "*" && allowed.contains(item)) } +/// How an empty allowed set is interpreted when checking a narrowing subset. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum EmptyAllowedPolicy { + /// An empty allowed set grants everything. + + Unrestricted, + /// An empty allowed set grants nothing. + Deny, +} + fn narrowing_set_is_subset( narrowed: &[T], allowed: &[T], - empty_allowed_is_unrestricted: bool, + empty_allowed: EmptyAllowedPolicy, ) -> bool { if allowed.is_empty() { - return empty_allowed_is_unrestricted || narrowed.is_empty(); + return match empty_allowed { + EmptyAllowedPolicy::Unrestricted => true, + EmptyAllowedPolicy::Deny => narrowed.is_empty(), + }; } !narrowed.is_empty() && narrowed.iter().all(|item| allowed.contains(item)) } From ead7c795641e6f89fe9d0959e2e6ab089ce72804 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:24:48 -0700 Subject: [PATCH 295/726] d2bd-runtime: emit pid and path fields on the unparseable-stat warning --- packages/d2bd-runtime/src/readiness.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/d2bd-runtime/src/readiness.rs b/packages/d2bd-runtime/src/readiness.rs index 26ad141ff..b9f4a7771 100644 --- a/packages/d2bd-runtime/src/readiness.rs +++ b/packages/d2bd-runtime/src/readiness.rs @@ -350,8 +350,10 @@ pub async fn wait_for_one_shot_exit( Ok(ProcState::ParseFailed) => { if !parse_fail_warned { tracing::warn!( - "wait_for_one_shot_exit: /proc//stat unparseable; \ - continuing to poll (will surface as oneshot-timeout if persistent)" + pid = %pid, + path = %format_args!("/proc/{pid}/stat"), + "wait_for_one_shot_exit: proc stat unparseable; \ + continuing to poll (will surface as oneshot-timeout if persistent)", ); parse_fail_warned = true; } From 813d85f59601756f8f98ba85325ff786a0c3ab89 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:25:11 -0700 Subject: [PATCH 296/726] audit: fold the bus slice and record its clippy base site --- .../audits/2026-09-24-rust-skills-audit/ledger.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 02f3940d3..f3bf18573 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -24,6 +24,7 @@ Measured at `147a536a0` in a dedicated gates worktree before any wave-0 fix land Defects the audited surfaces carry at HEAD that no corpus row claims and no wave fixes. They are recorded here so a later reader does not mistake them for wave regressions, and they route to an ordinary review pass or the owning package owner rather than to a leaf row. - `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Observed at the wave-2 base. A test-only allow is the broker package owner's policy call. +- `cargo clippy -p d2b-bus --locked --all-targets` (and `--lib`) stops at the first error `use of a disallowed method std::sync::Mutex::lock` in `packages/d2b-bus/src/session/contract.rs:967`, lint `clippy::disallowed_methods`. This is production code on the parked blocking-API backlog that `clippy.toml` documents and the blocking census tracks, so the site is a census item rather than a wave-2 fix; a leaf row must not add an inline allow, because `xtask provider-crate-policy` only accepts allows that its own list carries. - `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. ## Wave gates @@ -290,8 +291,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_co` | | | | `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362` | | | | `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/session/zone_link.rs:111-117` | | | -| `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:218-219, packages/d2b-bus/src/router.rs:298-337` | | | -| `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1445-1446, packages/d2b-bus/src/router.rs:1667-1674` | | | +| `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | ResourceQuery assignment/scope Option pair folded into one Option<(AssignmentIdentity, ScopedResourceScope)>; pub assignment()/scope() accessors keep signatures via const match; validate_scoped now on | | +| `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | | `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broke` | | | | `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2805, packages/d2b-contracts-broker/src/b` | | | | `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | | | | `public_wire.rs:2166, public_wire.rs:2203` | | | @@ -374,8 +375,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | | | | `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | 068ddcfc4 | packages/d2b-broker/src/ops/cgroup.rs | CgroupBundleContext::slice_path() now returns &Path (borrows parent_slice, no clone). Call sites: vm_interior_path join works on &Path; AuditFields slice_path and the D2bSlice tuple site keep one to_p | | | `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | -| `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:1208, packages/d2b-bus/src/router.rs:1224, packages/d2b-bus` | | | -| `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/authorization.rs:75, packages/d2b-bus/src/router.rs:1415-1416` | | | +| `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | applied-variant | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | Census re-run:= with_observer/with_observer_and_metrics/with_clock_and_observer have zero ZoneBus callers, deleted; with_clock -> pub(crate) because production new() delegates to it; with_clock_observ | | +| `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97` | | | | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114` | | | | `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | @@ -514,10 +515,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:2` | | | | `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | | | | `public_wire.rs:1297` | | | | `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider_registry.rs:186, packages/d2b-contracts-pr` | | | -| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | | | -| `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:1508, packages/d2b-contrac` | | | +| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError Display strings are wire outcome codes pinned by docs/specs/ADR-046-resources-credential.md:903 (credential-queue-pressure = lease table at capacity) and the provider ADR err | | +| `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | | `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-pr` | | | -| `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:834, packages/d2b-contract` | | | +| `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 75e9c238c | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialSingleFlight lock() now recovers poisoned mutexes via unwrap_or_else(poisoned.into_inner()) and returns the guard directly (infallible); guard Drop recovers the same way instead of silently | | | `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | | `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | | `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_macvtap_intents now returns crate::error::Error via Error::manifest_parse_error (typed, two failure modes distinguishable); broker call site updated to house .map_err(/error/ BrokerError::Live | | From d1a472077a3e2d0819d514a17479053562dffba7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:25:23 -0700 Subject: [PATCH 297/726] d2bd: log activation finish refusals from the lock guard --- packages/d2bd/src/composition.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 4b9eab5c0..4097d6212 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -20212,7 +20212,9 @@ impl ActivationLockGuard { impl Drop for ActivationLockGuard { fn drop(&mut self) { let mut coordinator = lock_sync(&self.coordinator); - let _ = coordinator.finish_activation(&self.zone); + if let Err(error) = coordinator.finish_activation(&self.zone) { + tracing::warn!(zone = %self.zone, error = %error, "activation finish refused by Zone coordinator"); + } } } From 69153d93f8218655a92bb3515f31e02c362d31c8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:25:30 -0700 Subject: [PATCH 298/726] d2b-provider-activation-nixos: bound generation observation names with ResourceName --- .../src/controller.rs | 21 ++++++++----- .../src/driver.rs | 10 +++++-- .../tests/reconcile.rs | 30 +++++++++---------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/packages/d2b-provider-activation-nixos/src/controller.rs b/packages/d2b-provider-activation-nixos/src/controller.rs index 3723bf48d..b98af6ea8 100644 --- a/packages/d2b-provider-activation-nixos/src/controller.rs +++ b/packages/d2b-provider-activation-nixos/src/controller.rs @@ -2,7 +2,7 @@ use d2b_contracts_resource::v3::{ ActivationMode, ActivationOutcomeCode, ActivationRunnerInput, ArtifactId, EnvironmentClass, - ExecutionDomain, NixosGenerationSpec, ResourceName, ResourcePhase, ResourceRef, + ExecutionDomain, IdentityError, NixosGenerationSpec, ResourceName, ResourcePhase, ResourceRef, process::{EphemeralProcessSpec, ExecutionSpec, NamespaceClass, ProcessClass, SandboxSpec}, }; use ring::signature; @@ -104,23 +104,28 @@ pub struct GenerationObservation { } impl GenerationObservation { - /// Construct a bounded observation. - pub fn new(name: impl Into, phase: GenerationPhase) -> Self { + /// Construct a bounded observation from a generation row name. + /// + /// # Errors + /// + /// Returns `IdentityError` when `name` is empty, contains '/', or + /// exceeds the `ResourceName` bound (63-byte lowercase label). + pub fn new(name: impl Into, phase: GenerationPhase) -> Result { let name = name.into(); let ordinal = name .rsplit('-') .next() .and_then(|value| value.parse::().ok()) .unwrap_or(0); - Self::terminal(name, phase, ordinal) + Ok(Self::terminal(ResourceName::parse(name)?, phase, ordinal)) } /// Construct a bounded terminal observation. - pub fn terminal(name: impl Into, phase: GenerationPhase, ordinal: u64) -> Self { - let name = name.into(); - assert!(!name.is_empty() && !name.contains('/') && name.len() <= 128); + /// + /// Never panics: `name` is already validated by `ResourceName`. + pub fn terminal(name: ResourceName, phase: GenerationPhase, ordinal: u64) -> Self { Self { - name, + name: name.to_canonical_string(), phase, ordinal, } diff --git a/packages/d2b-provider-activation-nixos/src/driver.rs b/packages/d2b-provider-activation-nixos/src/driver.rs index 249e1521d..bf4481b8e 100644 --- a/packages/d2b-provider-activation-nixos/src/driver.rs +++ b/packages/d2b-provider-activation-nixos/src/driver.rs @@ -55,7 +55,7 @@ use d2b_contracts_broker::host_generation::{ }; use d2b_contracts_resource::v3::{ ActivationDetail, ActivationMode, ActivationOutcomeCode, NIXOS_GENERATION_RESOURCE_TYPE, - NixosGenerationSpec, ResourcePhase, ResourceRef, + NixosGenerationSpec, ResourceName, ResourcePhase, ResourceRef, }; use d2b_resource_runtime::context::{ ChildEnsure, ResourceContext, SpecDecoder, WatchCondition, typed_spec_decoder, @@ -552,8 +552,10 @@ impl ActivationDriver { return Err(self.error(ActivationDriverErrorKind::Policy, op)); } let ordinal = ordinal_from_name(&row.key.name).unwrap_or(row.generation); + let name = ResourceName::parse(&row.key.name) + .map_err(|_| self.error(ActivationDriverErrorKind::Policy, op))?; Ok(vec![GenerationObservation::terminal( - row.key.name.as_str(), + name, GenerationPhase::Pending, ordinal, )]) @@ -762,8 +764,10 @@ impl ResourceDriver for ActivationDriver { // Old `ordinal_from_resource`: the trailing bounded generation // number, else the durable row generation. let ordinal = ordinal_from_name(ctx.key().name.as_str()).unwrap_or(ctx.generation()); + let name = ResourceName::parse(ctx.key().name.as_str()) + .map_err(|_| self.error(ActivationDriverErrorKind::Policy, DriverOp::Reconcile))?; let observed = GenerationObservation::terminal( - ctx.key().name.as_str(), + name, generation_phase(self.observed_phase(ctx)), ordinal, ); diff --git a/packages/d2b-provider-activation-nixos/tests/reconcile.rs b/packages/d2b-provider-activation-nixos/tests/reconcile.rs index b4abfdc41..67c2d15f3 100644 --- a/packages/d2b-provider-activation-nixos/tests/reconcile.rs +++ b/packages/d2b-provider-activation-nixos/tests/reconcile.rs @@ -45,7 +45,7 @@ fn compatible_generation_starts_one_typed_runner() { &spec(), &caller(), &[], - GenerationObservation::new("gen-7", GenerationPhase::Pending), + GenerationObservation::new("gen-7", GenerationPhase::Pending).unwrap(), ) .unwrap(); assert_eq!(result.runner_requests().len(), 1); @@ -89,7 +89,7 @@ fn activation_runner_spec_is_closed_and_bounded() { &spec(), &caller(), &[], - GenerationObservation::new("gen-7", GenerationPhase::Pending), + GenerationObservation::new("gen-7", GenerationPhase::Pending).unwrap(), ) .unwrap(); let runner = @@ -134,7 +134,7 @@ fn unauthorized_or_foreign_callers_refuse_before_runner_creation() { &spec(), &foreign, &[], - GenerationObservation::new("gen-7", GenerationPhase::Pending), + GenerationObservation::new("gen-7", GenerationPhase::Pending).unwrap(), ); assert!(result.is_err()); } @@ -146,7 +146,7 @@ fn runner_failure_preserves_the_source_generation_and_audits_one_code() { .apply_runner_result( &spec(), ActivationOutcomeCode::HelperFailed, - GenerationObservation::new("gen-6", GenerationPhase::Ready), + GenerationObservation::new("gen-6", GenerationPhase::Ready).unwrap(), ) .unwrap(); assert!(failed.source_generation_preserved()); @@ -159,7 +159,7 @@ fn adopted_outcome_is_rejected_for_switch_mode() { let result = controller.apply_runner_result( &spec(), ActivationOutcomeCode::Adopted, - GenerationObservation::new("gen-6", GenerationPhase::Ready), + GenerationObservation::new("gen-6", GenerationPhase::Ready).unwrap(), ); assert_eq!( result.unwrap_err(), @@ -214,7 +214,7 @@ fn adopt_mode_accepts_adoption_without_starting_a_runner() { &adopt, &caller(), &[], - GenerationObservation::new("gen-7", GenerationPhase::Pending), + GenerationObservation::new("gen-7", GenerationPhase::Pending).unwrap(), ) .unwrap(); assert!(pending.runner_requests().is_empty()); @@ -223,7 +223,7 @@ fn adopt_mode_accepts_adoption_without_starting_a_runner() { .apply_runner_result( &adopt, ActivationOutcomeCode::Adopted, - GenerationObservation::new("gen-6", GenerationPhase::Ready), + GenerationObservation::new("gen-6", GenerationPhase::Ready).unwrap(), ) .unwrap(); assert_eq!(result.phase(), ResourcePhase::Ready); @@ -237,7 +237,7 @@ fn test_mode_succeeds_without_preserving_the_source_generation() { .apply_runner_result( &spec_with_mode(ActivationMode::Test), ActivationOutcomeCode::Succeeded, - GenerationObservation::new("gen-6", GenerationPhase::Ready), + GenerationObservation::new("gen-6", GenerationPhase::Ready).unwrap(), ) .unwrap(); assert_eq!(result.phase(), ResourcePhase::Succeeded); @@ -251,7 +251,7 @@ fn successful_switch_reports_ready_and_replaces_the_source_generation() { .apply_runner_result( &spec(), ActivationOutcomeCode::Succeeded, - GenerationObservation::new("gen-6", GenerationPhase::Ready), + GenerationObservation::new("gen-6", GenerationPhase::Ready).unwrap(), ) .unwrap(); assert_eq!(result.phase(), ResourcePhase::Ready); @@ -265,7 +265,7 @@ fn deleted_generation_is_not_restarted() { &spec(), &caller(), &[], - GenerationObservation::new("gen-7", GenerationPhase::Deleted), + GenerationObservation::new("gen-7", GenerationPhase::Deleted).unwrap(), ); assert_eq!( result.unwrap_err(), @@ -280,7 +280,7 @@ fn malformed_generation_observation_cannot_start_a_zero_generation_runner() { &spec(), &caller(), &[], - GenerationObservation::new("generation", GenerationPhase::Pending), + GenerationObservation::new("generation", GenerationPhase::Pending).unwrap(), ); assert_eq!( @@ -295,7 +295,7 @@ fn stale_deleted_source_cannot_project_a_successful_activation() { let result = controller.apply_runner_result( &spec(), ActivationOutcomeCode::Succeeded, - GenerationObservation::new("gen-6", GenerationPhase::Deleted), + GenerationObservation::new("gen-6", GenerationPhase::Deleted).unwrap(), ); assert_eq!( @@ -319,7 +319,7 @@ fn prior_generation_reference_must_be_present_in_observations() { &spec, &caller(), &[], - GenerationObservation::new("gen-7", GenerationPhase::Pending), + GenerationObservation::new("gen-7", GenerationPhase::Pending).unwrap(), ); assert_eq!( result.unwrap_err(), @@ -329,8 +329,8 @@ fn prior_generation_reference_must_be_present_in_observations() { .reconcile( &spec, &caller(), - &[GenerationObservation::new("gen-6", GenerationPhase::Ready)], - GenerationObservation::new("gen-7", GenerationPhase::Pending), + &[GenerationObservation::new("gen-6", GenerationPhase::Ready).unwrap()], + GenerationObservation::new("gen-7", GenerationPhase::Pending).unwrap(), ) .unwrap(); assert_eq!(result.runner_requests().len(), 1); From bd25f4ce9628b0d5b888828d75dd563a50e2deac Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:26:05 -0700 Subject: [PATCH 299/726] session: type stream control kinds in a closed enum --- packages/d2b-session/src/engine.rs | 55 ++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/packages/d2b-session/src/engine.rs b/packages/d2b-session/src/engine.rs index 5558b342e..4dee68e0e 100644 --- a/packages/d2b-session/src/engine.rs +++ b/packages/d2b-session/src/engine.rs @@ -28,9 +28,6 @@ use crate::{ const ATTACHMENT_BATCH: u8 = 1; const ATTACHMENT_ACK: u8 = 2; -const STREAM_CLOSE: u8 = 1; -const STREAM_CREDIT: u8 = 2; -const STREAM_RESET: u8 = 3; const ATTACHMENT_DESCRIPTOR_BYTES: usize = 62; const ACTIVE_REQUEST_RESERVATION_BYTES: usize = 4 * 1024; const MAX_ACTIVE_REQUESTS_PER_SESSION: usize = 256; @@ -932,7 +929,7 @@ impl SessionEngine { self.send_logical( RecordKind::SessionControl, ChannelId::SESSION_CONTROL, - encode_stream_control(STREAM_CREDIT, stream, released), + encode_stream_control(StreamControlKind::Credit, stream, released), Vec::new(), ) .await @@ -943,7 +940,7 @@ impl SessionEngine { self.send_logical( RecordKind::SessionControl, ChannelId::SESSION_CONTROL, - encode_stream_control(STREAM_CLOSE, stream, 0), + encode_stream_control(StreamControlKind::Close, stream, 0), Vec::new(), ) .await?; @@ -960,7 +957,7 @@ impl SessionEngine { self.send_logical( RecordKind::SessionControl, ChannelId::SESSION_CONTROL, - encode_stream_control(STREAM_RESET, stream, 0), + encode_stream_control(StreamControlKind::Reset, stream, 0), Vec::new(), ) .await?; @@ -1295,16 +1292,16 @@ impl SessionEngine { fn receive_stream_control(&mut self, payload: &[u8]) -> Result { let (kind, stream, value) = decode_stream_control(payload)?; match kind { - STREAM_CLOSE => { + StreamControlKind::Close => { let event = self.streams.receive_close(stream)?; self.remove_terminal_stream(stream); Ok(SessionEvent::NamedStream(event)) } - STREAM_CREDIT => { + StreamControlKind::Credit => { self.streams.grant_send_credit(stream, value)?; Ok(SessionEvent::ControlProcessed) } - STREAM_RESET => { + StreamControlKind::Reset => { self.scheduler.remove_stream(stream); self.withheld_stream_credits.remove(&stream); self.pending_stream_transport.remove(&stream); @@ -1312,7 +1309,6 @@ impl SessionEngine { self.remove_terminal_stream(stream); Ok(SessionEvent::NamedStream(event)) } - _ => Err(SessionError::new(SessionErrorCode::UnknownControl)), } } @@ -1691,20 +1687,51 @@ fn close_reason_from_tag(tag: u8) -> Result { } } -fn encode_stream_control(kind: u8, stream: StreamId, value: u32) -> Vec { +/// Stream control kind carried on the session control channel. +enum StreamControlKind { + /// Close one named stream. + Close, + /// Grant send credit to one named stream. + Credit, + /// Reset one named stream. + Reset, +} + +impl StreamControlKind { + const fn tag(self) -> u8 { + match self { + Self::Close => 1, + Self::Credit => 2, + Self::Reset => 3, + } + } + + const fn from_tag(tag: u8) -> Option { + match tag { + 1 => Some(Self::Close), + 2 => Some(Self::Credit), + 3 => Some(Self::Reset), + _ => None, + } + } +} + +fn encode_stream_control(kind: StreamControlKind, stream: StreamId, value: u32) -> Vec { let mut bytes = Vec::with_capacity(7); - bytes.push(kind); + bytes.push(kind.tag()); bytes.extend_from_slice(&stream.channel().value().to_be_bytes()); bytes.extend_from_slice(&value.to_be_bytes()); bytes } -fn decode_stream_control(bytes: &[u8]) -> Result<(u8, StreamId, u32)> { +fn decode_stream_control(bytes: &[u8]) -> Result<(StreamControlKind, StreamId, u32)> { if bytes.len() != 7 { return Err(SessionError::new(SessionErrorCode::UnknownControl)); } + let kind = StreamControlKind::from_tag(bytes[0]) + .ok_or_else(|| SessionError::new(SessionErrorCode::UnknownControl))?; Ok(( - bytes[0], + kind, StreamId::new(u16::from_be_bytes([bytes[1], bytes[2]]))?, u32::from_be_bytes( bytes[3..7] From 2c566cfdc55de54fb064338919a60ccd02b030e4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:26:11 -0700 Subject: [PATCH 300/726] d2bd: tolerate unknown workload availability labels in metrics --- packages/d2bd/src/composition.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 4097d6212..cf99482d2 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -8167,9 +8167,7 @@ fn record_workload_availability_metrics( } else { "not-applicable" }; - *counts - .get_mut(&(provider, component, selected)) - .expect("bounded workload availability tuple") += 1; + *counts.entry((provider, component, selected)).or_insert(0) += 1; } } let samples = counts From 9fbe75ec25f23cf84d6dde7776fa984ccca314d1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:26:38 -0700 Subject: [PATCH 301/726] minijail: gate-only launch admission and const provider ref --- .../src/launch.rs | 24 +++++++------------ .../d2b-provider-process-minijail/src/lib.rs | 4 ++-- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/packages/d2b-provider-process-minijail/src/launch.rs b/packages/d2b-provider-process-minijail/src/launch.rs index a77185ebb..1c419a6ed 100644 --- a/packages/d2b-provider-process-minijail/src/launch.rs +++ b/packages/d2b-provider-process-minijail/src/launch.rs @@ -1,8 +1,6 @@ //! Minijail launch admission and mandatory platform gate. -use d2b_process_conformance::{LaunchTicket, ProcessConformanceError}; - -use crate::PROVIDER_NAME; +use d2b_process_conformance::ProcessConformanceError; /// Linux placement requirements that cannot be downgraded by config. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -47,21 +45,15 @@ impl PlatformGate { } } -/// Validate provider identityand platform evidence before spawn dispatch. +/// Validate the mandatory platform gate before spawn dispatch. +/// +/// Provider identity is checked by the controller itself +/// (`MinijailProcessProvider::validate`); this admission step only +/// verifies the platform evidence the daemon observed. /// /// # Errors /// -/// Returns `ProviderMismatch` when the ticket selects a different -/// Process Provider, and `PlatformGateRejected` when the platform gate -/// fails. -pub fn validate_launch_ticket( - ticket: &LaunchTicket, - gate: PlatformGate, -) -> Result<(), ProcessConformanceError> { - if ticket.selected_provider().as_str() != PROVIDER_NAME - || ticket.provider_ref().to_canonical_string() != crate::PROVIDER_REF - { - return Err(ProcessConformanceError::ProviderMismatch); - } +/// Returns `PlatformGateRejected` when the platform gate fails. +pub fn validate_platform_gate(gate: PlatformGate) -> Result<(), ProcessConformanceError> { gate.validate() } diff --git a/packages/d2b-provider-process-minijail/src/lib.rs b/packages/d2b-provider-process-minijail/src/lib.rs index 12783f6c1..f1d8d1e7f 100644 --- a/packages/d2b-provider-process-minijail/src/lib.rs +++ b/packages/d2b-provider-process-minijail/src/lib.rs @@ -157,7 +157,7 @@ impl MinijailProcessProvider

{ ); return Err(ProcessConformanceError::ProviderMismatch); } - if ticket.provider_ref().to_canonical_string() != "Provider/system-minijail" { + if ticket.provider_ref().to_canonical_string() != crate::PROVIDER_REF { warn!( provider = PROVIDER_NAME, resource = %ticket.process_ref().to_canonical_string(), @@ -190,7 +190,7 @@ impl MinijailProcessProvider

{ return Err(ProcessConformanceError::UserRefRequired); } if let Some(gate) = self.platform_gate - && let Err(error) = launch::validate_launch_ticket(ticket, gate) + && let Err(error) = launch::validate_platform_gate(gate) { warn!( provider = PROVIDER_NAME, From 7256bc918d4eb1e522f618b67ae95dabbcd28e39 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:26:54 -0700 Subject: [PATCH 302/726] d2b: carry structured error class on CliFailure --- packages/d2b/src/context.rs | 1 + packages/d2b/src/host.rs | 4 ++-- packages/d2b/src/lib.rs | 2 ++ packages/d2b/src/resource.rs | 10 +--------- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/d2b/src/context.rs b/packages/d2b/src/context.rs index 51a6c0f9c..b07f9c019 100644 --- a/packages/d2b/src/context.rs +++ b/packages/d2b/src/context.rs @@ -1187,6 +1187,7 @@ impl ZoneContext { ) -> CliFailure { let message = bounded_message(message); let mut failure = CliFailure::new(exit_code, format!("{error_class}: {message}")); + failure.code = error_class.to_owned(); if mode.is_json() { let envelope = json!({ "ok": false, diff --git a/packages/d2b/src/host.rs b/packages/d2b/src/host.rs index 1ec36d5ed..30d740229 100644 --- a/packages/d2b/src/host.rs +++ b/packages/d2b/src/host.rs @@ -175,8 +175,8 @@ pub(crate) fn run( fn can_fallback_to_local_state(error: &CliFailure) -> bool { matches!( - error.message.split(':').next(), - Some("zone-unavailable" | "deadline-exceeded" | "exec-protocol-error") + error.code.as_str(), + "zone-unavailable" | "deadline-exceeded" | "exec-protocol-error" ) } diff --git a/packages/d2b/src/lib.rs b/packages/d2b/src/lib.rs index 1c2f39f61..629cc2f5d 100644 --- a/packages/d2b/src/lib.rs +++ b/packages/d2b/src/lib.rs @@ -46,6 +46,7 @@ pub const EXIT_API_TIMEOUT: i32 = 33; #[derive(Debug)] pub(crate) struct CliFailure { pub(crate) exit_code: i32, + pub(crate) code: String, pub(crate) message: String, pub(crate) rendered_stderr: Option, pub(crate) admission_recovery: bool, @@ -55,6 +56,7 @@ impl CliFailure { pub(crate) fn new(exit_code: i32, message: impl Into) -> Self { Self { exit_code, + code: String::from("cli-error"), message: message.into(), rendered_stderr: None, admission_recovery: false, diff --git a/packages/d2b/src/resource.rs b/packages/d2b/src/resource.rs index 078d21067..d3751502c 100644 --- a/packages/d2b/src/resource.rs +++ b/packages/d2b/src/resource.rs @@ -966,15 +966,7 @@ fn reconcile_deadline( mode: OutputMode, ) -> Result, CliFailure> { crate::context::ZoneContext::expedited_deadline(value).map_err(|error| { - context.failure( - "ref-invalid", - error - .message - .strip_prefix("ref-invalid: ") - .unwrap_or(&error.message), - mode, - error.exit_code, - ) + context.failure("ref-invalid", &error.message, mode, error.exit_code) }) } From d72f7c1e6daf8d7e0d2001f4da9b3c2e318597ec Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:14 -0700 Subject: [PATCH 303/726] d2b-contracts-control: derive wire Deserialize impls via serde try_from Replace the three hand-written Deserialize impls (HelperSnapshot, HelperLaunchRequest, AuditResponse) with derive-backed try_from conversions over the existing private wire structs, and give ShellNameError Display and std::error::Error impls for formatting and error chaining. --- .../d2b-contracts-control/src/public_wire.rs | 25 ++++++++------ .../src/unsafe_local_wire.rs | 34 ++++++++----------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index a25dafc0a..54c260d37 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -1308,6 +1308,14 @@ impl ShellName { /// The value is not a valid shell name. pub struct ShellNameError; +impl fmt::Display for ShellNameError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("invalid shell name") + } +} + +impl std::error::Error for ShellNameError {} + impl fmt::Debug for ShellName { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("ShellName()") @@ -2173,8 +2181,8 @@ pub struct PublicReadModelMetadata { pub deep_refresh: String, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields, try_from = "AuditResponseWire")] pub struct AuditResponse { /// Typed broker audit entries. The public daemon page deliberately shares /// the broker entry shape so pagination does not lose sequence or export @@ -2196,14 +2204,11 @@ struct AuditResponseWire { complete: bool, } -impl<'de> Deserialize<'de> for AuditResponse { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let wire = AuditResponseWire::deserialize(deserializer)?; - validate_audit_page(wire.complete, wire.next_cursor.as_ref()) - .map_err(serde::de::Error::custom)?; +impl TryFrom for AuditResponse { + type Error = &'static str; + + fn try_from(wire: AuditResponseWire) -> Result { + validate_audit_page(wire.complete, wire.next_cursor.as_ref())?; Ok(Self { entries: wire.entries, next_cursor: wire.next_cursor, diff --git a/packages/d2b-contracts-control/src/unsafe_local_wire.rs b/packages/d2b-contracts-control/src/unsafe_local_wire.rs index 69c108639..58c8651ca 100644 --- a/packages/d2b-contracts-control/src/unsafe_local_wire.rs +++ b/packages/d2b-contracts-control/src/unsafe_local_wire.rs @@ -9,7 +9,7 @@ use d2b_contracts::{ }; pub use d2b_contracts_resource::v3::ZoneResourceIdentity; use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use std::fmt; /// Protocol version this wire vocabulary speaks; peers must agree on it. @@ -115,8 +115,8 @@ pub struct HelperScopeSnapshot { pub state: HelperScopeState, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields, try_from = "HelperSnapshotWire")] /// Bounded snapshot of every scope the helper currently runs. pub struct HelperSnapshot { pub generation: u64, @@ -151,25 +151,23 @@ struct HelperSnapshotWire { scopes: Vec, } -impl<'de> Deserialize<'de> for HelperSnapshot { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let wire = HelperSnapshotWire::deserialize(deserializer)?; +impl TryFrom for HelperSnapshot { + type Error = &'static str; + + fn try_from(wire: HelperSnapshotWire) -> Result { let snapshot = Self { generation: wire.generation, scopes: wire.scopes, }; snapshot .validate() - .map_err(|_| serde::de::Error::custom("invalid helper snapshot"))?; + .map_err(|_| "invalid helper snapshot")?; Ok(snapshot) } } -#[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields, try_from = "HelperLaunchRequestWire")] /// One launch request the daemon commits to the helper. /// /// The workload target, item id, and argv are redacted in `Debug`. @@ -224,12 +222,10 @@ struct HelperLaunchRequestWire { realm_accent_color: RealmAccentColor, } -impl<'de> Deserialize<'de> for HelperLaunchRequest { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let wire = HelperLaunchRequestWire::deserialize(deserializer)?; +impl TryFrom for HelperLaunchRequest { + type Error = &'static str; + + fn try_from(wire: HelperLaunchRequestWire) -> Result { let request = Self { request_id: wire.request_id, operation_id: wire.operation_id, @@ -242,7 +238,7 @@ impl<'de> Deserialize<'de> for HelperLaunchRequest { }; request .validate_bounds() - .map_err(|_| serde::de::Error::custom("invalid helper launch request"))?; + .map_err(|_| "invalid helper launch request")?; Ok(request) } } From 7cf83bcafd172ba54599c6c66b61c01ae5983c6b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:20 -0700 Subject: [PATCH 304/726] process-systemd: drop invariant restart_on_failure state from RestartPolicy --- packages/d2b-provider-process-systemd/src/lifecycle.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/d2b-provider-process-systemd/src/lifecycle.rs b/packages/d2b-provider-process-systemd/src/lifecycle.rs index c0f023e6d..090adf8cb 100644 --- a/packages/d2b-provider-process-systemd/src/lifecycle.rs +++ b/packages/d2b-provider-process-systemd/src/lifecycle.rs @@ -82,7 +82,6 @@ impl std::error::Error for SystemdConfigError {} /// Restart-on-failure policy with a bounded counter. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct RestartPolicy { - restart_on_failure: bool, max_restarts: u32, attempts: u32, reset_after_ticks: u64, @@ -93,7 +92,6 @@ impl RestartPolicy { /// Construct a bounded restart-on-failure policy. pub const fn on_failure(max_restarts: u32, reset_after_ticks: u64) -> Self { Self { - restart_on_failure: true, max_restarts, attempts: 0, reset_after_ticks, @@ -104,7 +102,7 @@ impl RestartPolicy { /// Decide whether a terminal result may restart the process. pub fn should_restart(&mut self, outcome: ProcessOutcome) -> bool { self.healthy_ticks = 0; - if !self.restart_on_failure || outcome.exit_class == ProcessExitClass::CleanExit { + if outcome.exit_class == ProcessExitClass::CleanExit { return false; } if self.attempts >= self.max_restarts { From 7760f4d1ab168aeb0ecd28d37f10b91b01c152b8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:33 -0700 Subject: [PATCH 305/726] d2b-core-controller: drop the unused external physical-NIC authority machinery --- packages/d2b-core-controller/src/authority.rs | 1198 +---------------- 1 file changed, 13 insertions(+), 1185 deletions(-) diff --git a/packages/d2b-core-controller/src/authority.rs b/packages/d2b-core-controller/src/authority.rs index 4d7c4ada5..197416f24 100644 --- a/packages/d2b-core-controller/src/authority.rs +++ b/packages/d2b-core-controller/src/authority.rs @@ -16,12 +16,9 @@ use std::{ use d2b_contracts_resource::redacted_debug; use d2b_contracts_resource::v3::{ - CanonicalJsonValue, IfName, ResourceGeneration, ResourceRef, ResourceUid, UpdateState, + CanonicalJsonValue, ResourceGeneration, ResourceRef, ResourceUid, UpdateState, is_canonical_digest, - network::{ - ExternalNicAdmissionError, ExternalNicAuthorityStatus, ExternalNicClaim, MacvtapMode, - SharingPolicy, admit_external_nic_claims, - }, + network::{MacvtapMode, SharingPolicy}, process::PortProtocol, resource_schema::canonical_digest, }; @@ -30,10 +27,6 @@ use serde::{Deserialize, Serialize}; #[cfg(test)] use std::{collections::hash_map::RandomState, hash::BuildHasher}; -/// Domain tag for the Core-derived external physical-NIC identity. -pub const EXTERNAL_PHYSICAL_NIC_IDENTITY_DOMAIN: &str = "external-physical-nic/v1"; -/// Authority class used in the Host-global index. -pub const EXTERNAL_PHYSICAL_NIC_AUTHORITY_CLASS: &str = "external-physical-nic"; /// Domain tag for Core-derived physical USB backing identities. pub const PHYSICAL_USB_BACKING_IDENTITY_DOMAIN: &str = "physical-usb-backing/v1"; /// Domain tag for Core-derived USBIP relay endpoint identities. @@ -41,8 +34,6 @@ pub const USBIP_NETWORK_RELAY_IDENTITY_DOMAIN: &str = "usbip-network-relay/v1"; /// The one Provider with optional controller cardinality: telemetry may be /// absent from a Zone, so its claim is AtMostOne instead of ExactlyOne. const OPTIONAL_PROVIDER_REF: &str = "Provider/observability-otel"; -#[allow(dead_code)] -const MAX_RESOLVED_NIC_IDENTITY_BYTES: usize = 256; static NEXT_AUTHORITY_INDEX_NONCE: AtomicU64 = AtomicU64::new(1); #[cfg(test)] @@ -55,307 +46,14 @@ fn test_nonce_for_operation(operation_id: &str) -> u64 { } } -/// One stable physical-NIC identity resolved from trusted Host inventory. -/// -/// This is not an authored interface selector and cannot be serialized into a -/// resource. Core derives the authority key from these private bytes. -#[derive(Clone, PartialEq, Eq)] -pub struct ResolvedExternalNicIdentity(Vec); - -impl ResolvedExternalNicIdentity { - /// Record a stable identity returned by the trusted inventory adapter. - #[allow(dead_code)] - pub(crate) fn from_trusted_inventory( - bytes: impl Into>, - ) -> Result { - let bytes = bytes.into(); - if bytes.is_empty() || bytes.len() > MAX_RESOLVED_NIC_IDENTITY_BYTES { - return Err(AuthorityError::InvalidTrustedInventoryIdentity); - } - Ok(Self(bytes)) - } -} - -redacted_debug!(ResolvedExternalNicIdentity); - -/// Trusted Host inventory used to resolve authored interface selectors. -#[derive(Default)] -pub struct TrustedExternalNicInventory { - entries: BTreeMap, -} - -impl TrustedExternalNicInventory { - /// Add one resolver-owned inventory row. - pub fn insert( - &mut self, - selector: IfName, - identity: ResolvedExternalNicIdentity, - ) -> Result<(), AuthorityError> { - if self.entries.insert(selector, identity).is_some() { - return Err(AuthorityError::DuplicateTrustedInventorySelector); - } - Ok(()) - } - - /// Resolve an authored selector without exposing the derived authority key. - pub fn resolve( - &self, - selector: &IfName, - ) -> Result { - self.entries - .get(selector) - .cloned() - .ok_or(AuthorityError::TrustedInventorySelectorNotFound) - } -} - /// Trusted recovery port for one Core-resolved physical-NIC inventory. pub trait ExternalNicRecoveryInventory: Send + Sync { fn contains_identity(&self, host_uid: &ResourceUid, identity_digest: &str) -> bool; } -impl ExternalNicRecoveryInventory for TrustedExternalNicInventory { - fn contains_identity(&self, host_uid: &ResourceUid, identity_digest: &str) -> bool { - self.entries.values().any(|identity| { - ExternalNicAuthorityKey::derive(host_uid.clone(), identity).opaque_digest - == identity_digest - }) - } -} - -impl core::fmt::Debug for TrustedExternalNicInventory { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("TrustedExternalNicInventory") - .field("entry_count", &self.entries.len()) - .finish() - } -} - -/// Exact resource identity used to adopt or release one authority holder. -#[derive(Clone, PartialEq, Eq)] -pub struct ExternalNicOwnerProof { - resource_ref: Option, - resource_uid: ResourceUid, - generation: ResourceGeneration, -} - -impl ExternalNicOwnerProof { - /// Bind an owner proof to an exact resource identity and generation. - #[allow(dead_code)] - pub(crate) const fn new(resource_uid: ResourceUid, generation: ResourceGeneration) -> Self { - Self { - resource_ref: None, - resource_uid, - generation, - } - } - - #[allow(dead_code)] - pub(crate) fn from_resource_ref( - resource_ref: ResourceRef, - resource_uid: ResourceUid, - generation: ResourceGeneration, - ) -> Self { - Self { - resource_ref: Some(resource_ref), - resource_uid, - generation, - } - } -} - -redacted_debug!(ExternalNicOwnerProof); - -/// Complete pre-effect request for one external physical-NIC claim. -pub struct ExternalNicClaimRequest { - host_uid: ResourceUid, - identity: ResolvedExternalNicIdentity, - claim: ExternalNicClaim, - owner_proof: ExternalNicOwnerProof, - signed_max_holders: usize, -} - -impl ExternalNicClaimRequest { - /// Construct a request from a trusted inventory result and signed quota. - pub fn new( - host_uid: ResourceUid, - identity: ResolvedExternalNicIdentity, - claim: ExternalNicClaim, - owner_proof: ExternalNicOwnerProof, - signed_max_holders: usize, - ) -> Result { - if signed_max_holders == 0 || signed_max_holders > u32::MAX as usize { - return Err(AuthorityError::InvalidSignedHolderLimit); - } - Ok(Self { - host_uid, - identity, - claim, - owner_proof, - signed_max_holders, - }) - } - - /// Return the non-authorizing storage row for this resolved claim. - pub fn durable_claim(&self) -> DurableExternalNicClaim { - let key = ExternalNicAuthorityKey::derive(self.host_uid.clone(), &self.identity); - DurableExternalNicClaim { - host_uid: key.host_uid, - identity_digest: key.opaque_digest, - zone_uid: self.claim.zone_uid().clone(), - macvtap_mode: self.claim.macvtap_mode(), - sharing_policy: self.claim.sharing_policy(), - signed_max_holders: self.signed_max_holders as u32, - owner_proof: DurableAuthorityOwnerProof::from_external_owner_proof(&self.owner_proof), - } - } -} - -redacted_debug!(ExternalNicClaimRequest); - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] -struct ExternalNicAuthorityKey { - host_uid: ResourceUid, - opaque_digest: String, -} - -impl ExternalNicAuthorityKey { - fn derive(host_uid: ResourceUid, identity: &ResolvedExternalNicIdentity) -> Self { - let mut framed = Vec::with_capacity(8 + identity.0.len()); - framed.extend_from_slice(&(identity.0.len() as u64).to_be_bytes()); - framed.extend_from_slice(&identity.0); - Self::from_digest( - host_uid, - canonical_digest(EXTERNAL_PHYSICAL_NIC_IDENTITY_DOMAIN, &framed), - ) - } - - fn from_digest(host_uid: ResourceUid, opaque_digest: String) -> Self { - Self { - host_uid, - opaque_digest, - } - } -} - -redacted_debug!(ExternalNicAuthorityKey); - -#[derive(Clone)] -struct Holder { - token: u128, - operation_id: Option, - claim: ExternalNicClaim, - owner_proof: ExternalNicOwnerProof, - signed_max_holders: usize, -} - -struct AuthorityEntry { - holders: Vec, - signed_max_holders: usize, -} - -/// Proof that Core admitted a Host-global claim before an external effect. -/// -/// The lease is deliberately non-serializable and does not reveal its key or -/// owner proof. -pub struct ExternalNicLease { - key: ExternalNicAuthorityKey, - owner_proof: ExternalNicOwnerProof, - claim: ExternalNicClaim, - signed_max_holders: usize, - token: u128, - operation_id: Option, -} - -redacted_debug!(ExternalNicLease); - -/// Closed effect result retained beside an admitted lease. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ExternalNicEffectOutcome { - /// The effect completed and observation confirmed it. - Confirmed, - /// The effect may be retried while the authority remains held. - RetryableFailure, - /// The effect failed terminally while the authority remains held for drain. - TerminalFailure, -} - -/// Result of gating one host effect on authority admission. -pub struct ExternalNicEffectGate { - lease: ExternalNicLease, - outcome: ExternalNicEffectOutcome, -} - -impl ExternalNicEffectGate { - /// Consume the gate into its retained authority lease. - pub fn into_lease(self) -> ExternalNicLease { - self.lease - } - - /// Return the closed effect outcome. - pub const fn outcome(&self) -> ExternalNicEffectOutcome { - self.outcome - } -} - -impl core::fmt::Debug for ExternalNicEffectGate { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ExternalNicEffectGate") - .field("lease", &self.lease) - .field("outcome", &self.outcome) - .finish() - } -} - -/// Closed result of attempting to close old macvtap and VMM ownership. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ExternalNicCloseOutcome { - /// Every old holder and FD is confirmed closed. - Confirmed, - /// Closure is incomplete, so the authority must remain held. - RetryableFailure, -} - -/// Restart-adoption result for one exact owner proof. -#[allow(clippy::large_enum_variant)] -pub enum ExternalNicAdoption { - /// Exactly one recovered owner matched the indexed claim. - Adopted(ExternalNicLease), - /// No matching indexed and observed owner exists. - Missing, - /// Recovery found more than one matching owner and effects stay quarantined. - QuarantinedAmbiguous, -} - -impl core::fmt::Debug for ExternalNicAdoption { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::Adopted(_) => f.write_str("ExternalNicAdoption::Adopted()"), - Self::Missing => f.write_str("ExternalNicAdoption::Missing"), - Self::QuarantinedAmbiguous => f.write_str("ExternalNicAdoption::QuarantinedAmbiguous"), - } - } -} - /// Closed, identity-free authority failures. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AuthorityError { - /// Trusted inventory returned an absent or oversized stable identity. - InvalidTrustedInventoryIdentity, - /// The trusted inventory contains the same selector twice. - DuplicateTrustedInventorySelector, - /// The authored selector did not resolve in trusted inventory. - TrustedInventorySelectorNotFound, - /// The signed quota is zero or cannot be represented in bounded status. - InvalidSignedHolderLimit, - /// Claim compatibility or isolation admission failed. - Admission(ExternalNicAdmissionError), - /// A lease no longer names an indexed claim. - UnknownClaim, - /// A lease does not match the indexed owner proof. - OwnerProofMismatch, - /// Macvtap or VMM ownership was not confirmed closed. - AttachmentCloseUnconfirmed, /// A Core-derived generic authority key is empty or zero. InvalidAuthorityKey, /// A generic authority holder limit is outside bounded status range. @@ -395,14 +93,6 @@ impl AuthorityError { /// Return the stable, identity-free error code. pub const fn code(self) -> &'static str { match self { - Self::InvalidTrustedInventoryIdentity => "invalid-trusted-inventory-identity", - Self::DuplicateTrustedInventorySelector => "duplicate-trusted-inventory-selector", - Self::TrustedInventorySelectorNotFound => "trusted-inventory-selector-not-found", - Self::InvalidSignedHolderLimit => "invalid-signed-holder-limit", - Self::Admission(reason) => reason.code(), - Self::UnknownClaim => "external-physical-nic-claim-missing", - Self::OwnerProofMismatch => "external-physical-nic-owner-proof-mismatch", - Self::AttachmentCloseUnconfirmed => "external-physical-nic-close-unconfirmed", Self::InvalidAuthorityKey => "authority-key-invalid", Self::InvalidAuthorityHolderLimit => "authority-holder-limit-invalid", Self::InvalidAuthorityRequest => "authority-request-invalid", @@ -431,12 +121,6 @@ impl core::fmt::Display for AuthorityError { impl std::error::Error for AuthorityError {} -impl From for AuthorityError { - fn from(value: ExternalNicAdmissionError) -> Self { - Self::Admission(value) - } -} - fn conflict_for_class(class: AuthorityClass) -> AuthorityError { match class { AuthorityClass::PhysicalUsbBacking => AuthorityError::PhysicalUsbBackingConflict, @@ -644,14 +328,6 @@ impl DurableAuthorityOwnerProof { } } - fn from_external_owner_proof(proof: &ExternalNicOwnerProof) -> Self { - Self { - resource_ref: proof.resource_ref.clone(), - resource_uid: proof.resource_uid.clone(), - generation: proof.generation, - } - } - fn into_owner_proof(self) -> AuthorityOwnerProof { AuthorityOwnerProof { resource_ref: self.resource_ref, @@ -772,35 +448,6 @@ impl DurableExternalNicClaim { pub fn identity_digest(&self) -> &str { &self.identity_digest } - - fn into_parts(self) -> Result<(ExternalNicAuthorityKey, Holder, usize), AuthorityError> { - if !valid_authority_digest(&self.identity_digest) { - return Err(AuthorityError::InvalidAuthorityKey); - } - let signed_max_holders = usize::try_from(self.signed_max_holders) - .map_err(|_| AuthorityError::InvalidSignedHolderLimit)?; - if signed_max_holders == 0 { - return Err(AuthorityError::InvalidSignedHolderLimit); - } - if !valid_resource_uid(&self.host_uid) - || !valid_resource_uid(&self.zone_uid) - || !valid_resource_uid(&self.owner_proof.resource_uid) - { - return Err(AuthorityError::InvalidAuthorityRequest); - } - let key = ExternalNicAuthorityKey::from_digest(self.host_uid, self.identity_digest); - let holder = Holder { - token: 0, - operation_id: None, - claim: ExternalNicClaim::new(self.zone_uid, self.macvtap_mode, self.sharing_policy), - owner_proof: ExternalNicOwnerProof::new( - self.owner_proof.resource_uid, - self.owner_proof.generation, - ), - signed_max_holders, - }; - Ok((key, holder, signed_max_holders)) - } } /// Persisted authority row variant. This is deliberately storage data only; @@ -1732,7 +1379,6 @@ struct GenericAuthorityEntry { /// Core-owned Host-global external physical-NIC authority index. pub struct HostGlobalAuthorityIndex { authorities: BTreeMap, - external_nics: BTreeMap, rehydrated: bool, unresolved_operations: BTreeSet, quarantined_operations: BTreeSet, @@ -1749,7 +1395,6 @@ impl Default for HostGlobalAuthorityIndex { fn default() -> Self { Self { authorities: BTreeMap::new(), - external_nics: BTreeMap::new(), rehydrated: false, unresolved_operations: BTreeSet::new(), quarantined_operations: BTreeSet::new(), @@ -1770,7 +1415,6 @@ impl HostGlobalAuthorityIndex { pub fn new_for_tests_ready() -> Self { Self { authorities: BTreeMap::new(), - external_nics: BTreeMap::new(), rehydrated: true, unresolved_operations: BTreeSet::new(), quarantined_operations: BTreeSet::new(), @@ -1792,7 +1436,6 @@ impl HostGlobalAuthorityIndex { pub fn invalidate_for_restart(&mut self) { let epoch = self.runtime_epoch.fetch_add(1, Ordering::AcqRel) + 1; self.authorities.clear(); - self.external_nics.clear(); self.rehydrated = false; self.unresolved_operations.clear(); self.quarantined_operations.clear(); @@ -1830,9 +1473,6 @@ impl HostGlobalAuthorityIndex { ) -> Result<(), AuthorityError> { let mut seen = BTreeSet::new(); let mut generic_keys = BTreeSet::new(); - let mut nic_claims = BTreeMap::>::new(); - let mut nic_limits = BTreeMap::::new(); - let mut nic_owners = BTreeMap::>::new(); for operation in operations { if operation.operation_id.is_empty() @@ -1872,26 +1512,10 @@ impl HostGlobalAuthorityIndex { return Err(AuthorityError::InvalidAuthorityRequest); } } - AuthorityStorageClaim::ExternalNic(claim) => { - let (key, holder, limit) = claim.clone().into_parts()?; - let claims = nic_claims.entry(key.clone()).or_default(); - claims.push(holder.claim); - let effective_limit = nic_limits.entry(key).or_insert(limit); - *effective_limit = (*effective_limit).min(limit); - admit_external_nic_claims(claims, *effective_limit)?; - let owner = ( - claim.owner_proof.resource_uid.to_canonical_string(), - claim.owner_proof.generation.get(), - ); - let owners = nic_owners - .entry(ExternalNicAuthorityKey::from_digest( - claim.host_uid.clone(), - claim.identity_digest.clone(), - )) - .or_default(); - if !owners.insert(owner) { - return Err(AuthorityError::InvalidAuthorityRequest); - } + // A persisted external physical-NIC operation row has no + // controller-side admission path anymore; refuse it fail-closed. + AuthorityStorageClaim::ExternalNic(_) => { + return Err(AuthorityError::InvalidAuthorityRequest); } } } @@ -1920,46 +1544,11 @@ impl HostGlobalAuthorityIndex { )?; index.unresolved_operations.insert(operation.operation_id); } - AuthorityStorageClaim::ExternalNic(claim) => { - if matches!( - operation.state, - AuthorityOperationState::Closed | AuthorityOperationState::Released - ) { - continue; - } - let (key, holder, signed_max_holders) = claim.into_parts()?; - let token = index.issue_token(); - let operation_id = Some(operation.operation_id.clone()); - let holder = Holder { - token, - operation_id, - ..holder - }; - if let Some(entry) = index.external_nics.get_mut(&key) { - let mut claims = entry - .holders - .iter() - .map(|existing| existing.claim.clone()) - .collect::>(); - claims.push(holder.claim.clone()); - let signed_limit = entry.signed_max_holders.min(signed_max_holders); - admit_external_nic_claims(&claims, signed_limit)?; - entry.signed_max_holders = signed_limit; - entry.holders.push(holder); - } else { - admit_external_nic_claims( - core::slice::from_ref(&holder.claim), - signed_max_holders, - )?; - index.external_nics.insert( - key, - AuthorityEntry { - holders: vec![holder], - signed_max_holders, - }, - ); - } - index.unresolved_operations.insert(operation.operation_id); + // A persisted external physical-NIC operation row has no + // controller-side admission path anymore; refuse it fail-closed. + + AuthorityStorageClaim::ExternalNic(_) => { + return Err(AuthorityError::InvalidAuthorityRequest); } } } @@ -2073,27 +1662,6 @@ impl HostGlobalAuthorityIndex { } } } - let nic_keys = self - .external_nics - .iter() - .filter(|(_, entry)| { - entry - .holders - .iter() - .any(|holder| holder.operation_id.as_deref() == Some(operation_id)) - }) - .map(|(key, _)| key.clone()) - .collect::>(); - for key in nic_keys { - if let Some(entry) = self.external_nics.get_mut(&key) { - entry - .holders - .retain(|holder| holder.operation_id.as_deref() != Some(operation_id)); - if entry.holders.is_empty() { - self.external_nics.remove(&key); - } - } - } } Ok(()) } @@ -2118,9 +1686,6 @@ impl HostGlobalAuthorityIndex { } /// Snapshot generic typed claims for durable store handoff. - /// - /// External physical-NIC adoption still requires the production inventory - /// adapter to provide its corresponding durable proof record. pub fn durable_claims(&self) -> Vec { self.authorities .iter() @@ -2139,26 +1704,6 @@ impl HostGlobalAuthorityIndex { .collect() } - /// Snapshot external-NIC claims for the trusted persistence adapter. - pub fn durable_external_nic_claims(&self) -> Vec { - self.external_nics - .iter() - .flat_map(|(key, entry)| { - entry.holders.iter().map(|holder| DurableExternalNicClaim { - host_uid: key.host_uid.clone(), - identity_digest: key.opaque_digest.clone(), - zone_uid: holder.claim.zone_uid().clone(), - macvtap_mode: holder.claim.macvtap_mode(), - sharing_policy: holder.claim.sharing_policy(), - signed_max_holders: entry.signed_max_holders as u32, - owner_proof: DurableAuthorityOwnerProof::from_external_owner_proof( - &holder.owner_proof, - ), - }) - }) - .collect() - } - /// Admit one typed authority before invoking any host or Zone effect. pub fn admit_authority( &mut self, @@ -2413,206 +1958,6 @@ impl HostGlobalAuthorityIndex { Ok(drained) } - /// Admit the claim, then and only then invoke one host effect. - pub fn admit_before_effect( - &mut self, - request: ExternalNicClaimRequest, - effect: impl FnOnce(&ExternalNicLease) -> ExternalNicEffectOutcome, - ) -> Result { - let lease = self.admit(request)?; - let outcome = effect(&lease); - Ok(ExternalNicEffectGate { lease, outcome }) - } - - /// Return the bounded public observation for one resolved authority. - pub fn external_nic_status( - &self, - host_uid: ResourceUid, - identity: &ResolvedExternalNicIdentity, - ) -> Option { - let key = ExternalNicAuthorityKey::derive(host_uid, identity); - let entry = self.external_nics.get(&key)?; - let all_multiplexable = entry.holders.iter().all(|holder| { - holder.claim.macvtap_mode() == MacvtapMode::Bridge - && holder.claim.sharing_policy() == SharingPolicy::Multiplexed - }); - let arbitration = if all_multiplexable { - SharingPolicy::Multiplexed - } else { - SharingPolicy::Exclusive - }; - Some(ExternalNicAuthorityStatus::new( - all_multiplexable && entry.holders.len() < entry.signed_max_holders, - entry.holders.len() as u32, - 0, - arbitration, - UpdateState::Current, - )) - } - - /// Adopt only one exact recovered owner; duplicate observations quarantine. - pub fn adopt( - &self, - host_uid: ResourceUid, - identity: &ResolvedExternalNicIdentity, - owner_proof: &ExternalNicOwnerProof, - recovered_owner_proofs: &[ExternalNicOwnerProof], - ) -> ExternalNicAdoption { - let key = ExternalNicAuthorityKey::derive(host_uid, identity); - let Some(entry) = self.external_nics.get(&key) else { - return ExternalNicAdoption::Missing; - }; - if recovered_owner_proofs - .iter() - .filter(|proof| *proof == owner_proof) - .count() - > 1 - { - return ExternalNicAdoption::QuarantinedAmbiguous; - } - let observed = recovered_owner_proofs - .iter() - .filter(|proof| *proof == owner_proof) - .count() - == 1; - let indexed = entry - .holders - .iter() - .find(|holder| &holder.owner_proof == owner_proof); - if observed && let Some(holder) = indexed { - ExternalNicAdoption::Adopted(ExternalNicLease { - key, - owner_proof: owner_proof.clone(), - claim: holder.claim.clone(), - signed_max_holders: holder.signed_max_holders, - token: holder.token, - operation_id: holder.operation_id.clone(), - }) - } else { - ExternalNicAdoption::Missing - } - } - - /// Close the old attachment before releasing its authority claim. - pub fn close_then_release( - &mut self, - lease: &ExternalNicLease, - close: impl FnOnce() -> ExternalNicCloseOutcome, - ) -> Result<(), AuthorityError> { - if close() != ExternalNicCloseOutcome::Confirmed { - return Err(AuthorityError::AttachmentCloseUnconfirmed); - } - self.release(lease) - } - - /// Drain and release an old claim before admitting a disruptive replacement. - pub fn replace_after_close( - &mut self, - lease: &ExternalNicLease, - replacement: ExternalNicClaimRequest, - close: impl FnOnce() -> ExternalNicCloseOutcome, - ) -> Result { - self.close_then_release(lease, close)?; - self.admit(replacement) - } - - fn admit( - &mut self, - request: ExternalNicClaimRequest, - ) -> Result { - self.admit_with_operation_id(request, None) - } - - fn admit_with_operation_id( - &mut self, - request: ExternalNicClaimRequest, - operation_id: Option, - ) -> Result { - if !self.is_ready_for_readiness() { - return Err(AuthorityError::StartupRehydrationRequired); - } - let key = ExternalNicAuthorityKey::derive(request.host_uid, &request.identity); - let lease_claim = request.claim.clone(); - let lease_owner = request.owner_proof.clone(); - let lease_limit = request.signed_max_holders; - let token = self.issue_token(); - if let Some(entry) = self.external_nics.get_mut(&key) { - if entry - .holders - .iter() - .any(|holder| holder.owner_proof == request.owner_proof) - { - return Err(AuthorityError::DuplicateActiveReservation); - } - let signed_limit = entry.signed_max_holders.min(request.signed_max_holders); - let mut claims: Vec = entry - .holders - .iter() - .map(|holder| holder.claim.clone()) - .collect(); - claims.push(request.claim.clone()); - admit_external_nic_claims(&claims, signed_limit)?; - entry.signed_max_holders = signed_limit; - entry.holders.push(Holder { - token, - operation_id: operation_id.clone(), - claim: request.claim, - owner_proof: request.owner_proof.clone(), - signed_max_holders: request.signed_max_holders, - }); - } else { - admit_external_nic_claims( - core::slice::from_ref(&request.claim), - request.signed_max_holders, - )?; - self.external_nics.insert( - key.clone(), - AuthorityEntry { - holders: vec![Holder { - token, - operation_id: operation_id.clone(), - claim: request.claim, - owner_proof: request.owner_proof.clone(), - signed_max_holders: request.signed_max_holders, - }], - signed_max_holders: request.signed_max_holders, - }, - ); - } - Ok(ExternalNicLease { - key, - owner_proof: lease_owner, - claim: lease_claim, - signed_max_holders: lease_limit, - token, - operation_id, - }) - } - - fn release(&mut self, lease: &ExternalNicLease) -> Result<(), AuthorityError> { - let entry = self - .external_nics - .get_mut(&lease.key) - .ok_or(AuthorityError::UnknownClaim)?; - let holder = entry - .holders - .iter() - .position(|holder| { - holder.token == lease.token - && holder.owner_proof == lease.owner_proof - && holder.claim == lease.claim - && holder.operation_id.as_ref().is_none_or(|operation_id| { - lease.operation_id.as_ref() == Some(operation_id) - }) - && holder.signed_max_holders == lease.signed_max_holders - }) - .ok_or(AuthorityError::OwnerProofMismatch)?; - entry.holders.remove(holder); - if entry.holders.is_empty() { - self.external_nics.remove(&lease.key); - } - Ok(()) - } } /// Error returned by an asynchronous authority reservation dispatch. @@ -2642,133 +1987,6 @@ pub struct AuthorityReservation { close_recorded: bool, } -/// Durable reservation for an external physical-NIC effect. -#[must_use = "an external NIC reservation must remain owned until closure"] -pub struct ExternalNicReservation { - index: Arc>, - lease: Option, - outcome: Option, - persistence: Arc, - capability: crate::authority_persistence::AuthorityOperationCapability, - close_recorded: bool, -} - -impl ExternalNicReservation { - /// Reserve and durably record one external-NIC claim before dispatch. - pub async fn reserve_durable( - index: Arc>, - persistence: Arc, - operation_id: impl Into, - request: ExternalNicClaimRequest, - ) -> Result> { - let operation_id = operation_id.into(); - let claim = request.durable_claim(); - let lease = { - let mut guard = index.lock().await; - guard - .reserve_operation_id(&operation_id) - .map_err(AuthorityReservationError::Effect)?; - guard - .admit_with_operation_id(request, Some(operation_id.clone())) - .map_err(AuthorityReservationError::Effect)? - }; - let prepared = match persistence - .prepare(&operation_id, &AuthorityStorageClaim::ExternalNic(claim)) - .await - { - Ok(prepared) => prepared, - Err(error @ crate::authority_persistence::AuthorityPersistenceError::CommitUnknown) => { - index.lock().await.quarantine_operation_id(&operation_id); - return Err(AuthorityReservationError::Persistence(error)); - } - Err(error) => { - let _ = index.lock().await.release(&lease); - return Err(AuthorityReservationError::Persistence(error)); - } - }; - let capability = - match crate::authority_persistence::AuthorityOperationCapability::from_prepared( - &operation_id, - prepared, - ) { - Ok(capability) => capability, - Err(error) => { - let _ = index.lock().await.release(&lease); - return Err(AuthorityReservationError::Persistence(error)); - } - }; - Ok(Self { - index, - lease: Some(lease), - outcome: None, - persistence, - capability, - close_recorded: false, - }) - } - - /// Dispatch while holding the external-NIC lease. - pub async fn dispatch( - &mut self, - dispatch: F, - ) -> Result> - where - F: FnOnce(&ExternalNicLease) -> Fut, - Fut: Future>, - { - let lease = self - .lease - .as_ref() - .ok_or(AuthorityReservationError::Closed)?; - let outcome = dispatch(lease) - .await - .map_err(AuthorityReservationError::Effect)?; - self.outcome = Some(outcome); - let state = match outcome { - ExternalNicEffectOutcome::Confirmed => AuthorityOperationState::EffectConfirmed, - ExternalNicEffectOutcome::RetryableFailure => AuthorityOperationState::EffectRetryable, - ExternalNicEffectOutcome::TerminalFailure => AuthorityOperationState::EffectTerminal, - }; - self.persistence - .record_effect(&self.capability, state) - .await - .map_err(AuthorityReservationError::Persistence)?; - Ok(outcome) - } - - /// Close the NIC attachment, then release its durable and in-memory owner. - pub async fn close_then_release( - &mut self, - close: impl FnOnce() -> ExternalNicCloseOutcome, - ) -> Result<(), AuthorityError> { - let lease = self - .lease - .as_ref() - .ok_or(AuthorityError::ReservationClosed)?; - if close() != ExternalNicCloseOutcome::Confirmed { - let _ = self - .persistence - .record_effect(&self.capability, AuthorityOperationState::EffectRetryable) - .await; - return Err(AuthorityError::AttachmentCloseUnconfirmed); - } - if !self.close_recorded { - self.persistence - .record_close(&self.capability) - .await - .map_err(|_| AuthorityError::AttachmentCloseUnconfirmed)?; - self.close_recorded = true; - } - self.persistence - .release(&self.capability) - .await - .map_err(|_| AuthorityError::AttachmentCloseUnconfirmed)?; - self.index.lock().await.release(lease)?; - self.lease = None; - Ok(()) - } -} - impl AuthorityReservation { /// Reserve one authority before starting an asynchronous effect. pub async fn reserve( @@ -2939,10 +2157,7 @@ impl core::fmt::Debug for AuthorityReservation { impl core::fmt::Debug for HostGlobalAuthorityIndex { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("HostGlobalAuthorityIndex") - .field( - "authority_count", - &(self.external_nics.len() + self.authorities.len()), - ) + .field("authority_count", &self.authorities.len()) .finish() } } @@ -2959,15 +2174,7 @@ mod tests { ResourceUid::parse(value).unwrap() } - fn identity(value: &[u8]) -> ResolvedExternalNicIdentity { - ResolvedExternalNicIdentity::from_trusted_inventory(value).unwrap() - } - - fn proof(value: &str, generation: u64) -> ExternalNicOwnerProof { - ExternalNicOwnerProof::new(uid(value), ResourceGeneration::new(generation).unwrap()) - } - - fn authority_proof(value: &str, generation: u64) -> AuthorityOwnerProof { +fn authority_proof(value: &str, generation: u64) -> AuthorityOwnerProof { AuthorityOwnerProof::new(uid(value), ResourceGeneration::new(generation).unwrap()) } @@ -2975,25 +2182,6 @@ mod tests { AuthorityDigest([byte; 32]) } - fn request( - host: &ResourceUid, - nic: &ResolvedExternalNicIdentity, - zone: &ResourceUid, - owner: ExternalNicOwnerProof, - mode: MacvtapMode, - policy: SharingPolicy, - limit: usize, - ) -> ExternalNicClaimRequest { - ExternalNicClaimRequest::new( - host.clone(), - nic.clone(), - ExternalNicClaim::new(zone.clone(), mode, policy), - owner, - limit, - ) - .unwrap() - } - #[derive(Default)] struct RecordingPersistence { states: Mutex>, @@ -3063,316 +2251,6 @@ mod tests { } } - #[test] - fn two_selectors_resolving_to_one_nic_share_one_host_global_key() { - let mut inventory = TrustedExternalNicInventory::default(); - let resolved = identity(b"stable-inventory-identity"); - inventory - .insert(IfName::parse("eno1").unwrap(), resolved.clone()) - .unwrap(); - inventory - .insert(IfName::parse("uplink0").unwrap(), resolved.clone()) - .unwrap(); - let first = inventory.resolve(&IfName::parse("eno1").unwrap()).unwrap(); - let second = inventory - .resolve(&IfName::parse("uplink0").unwrap()) - .unwrap(); - let host = uid("123e4567-e89b-42d3-a456-426614174000"); - assert_eq!( - ExternalNicAuthorityKey::derive(host.clone(), &first), - ExternalNicAuthorityKey::derive(host, &second) - ); - } - - #[test] - fn cross_zone_bridge_rejection_is_distinct_and_runs_no_effect() { - let host = uid("123e4567-e89b-42d3-a456-426614174000"); - let work = uid("223e4567-e89b-42d3-a456-426614174001"); - let personal = uid("323e4567-e89b-42d3-a456-426614174002"); - let nic = identity(b"one-physical-nic"); - let mut index = HostGlobalAuthorityIndex::new_for_tests_ready(); - let first = request( - &host, - &nic, - &work, - proof("423e4567-e89b-42d3-a456-426614174003", 1), - MacvtapMode::Bridge, - SharingPolicy::Multiplexed, - 8, - ); - index - .admit_before_effect(first, |_| ExternalNicEffectOutcome::Confirmed) - .unwrap(); - - let mut effects = 0; - let second = request( - &host, - &nic, - &personal, - proof("523e4567-e89b-42d3-a456-426614174004", 1), - MacvtapMode::Bridge, - SharingPolicy::Exclusive, - 1, - ); - let error = index - .admit_before_effect(second, |_| { - effects += 1; - ExternalNicEffectOutcome::Confirmed - }) - .unwrap_err(); - assert_eq!( - error, - AuthorityError::Admission(ExternalNicAdmissionError::ExternalPhysicalNicCrossZoneL2) - ); - assert_eq!(error.code(), "external-physical-nic-cross-zone-l2"); - assert_eq!(effects, 0); - } - - #[test] - fn external_nic_admission_waits_for_the_same_startup_barrier() { - let host = uid("623e4567-e89b-42d3-a456-426614174005"); - let zone = uid("723e4567-e89b-42d3-a456-426614174006"); - let nic = identity(b"startup-barrier-nic"); - let mut index = HostGlobalAuthorityIndex::new_unrehydrated(); - let mut effects = 0; - let result = index.admit_before_effect( - request( - &host, - &nic, - &zone, - proof("823e4567-e89b-42d3-a456-426614174007", 1), - MacvtapMode::Bridge, - SharingPolicy::Exclusive, - 1, - ), - |_| { - effects += 1; - ExternalNicEffectOutcome::Confirmed - }, - ); - assert_eq!( - result.unwrap_err(), - AuthorityError::StartupRehydrationRequired - ); - assert_eq!(effects, 0); - } - - #[test] - fn same_zone_compatible_bridge_multiplex_obeys_the_signed_limit() { - let host = uid("123e4567-e89b-42d3-a456-426614174000"); - let zone = uid("223e4567-e89b-42d3-a456-426614174001"); - let nic = identity(b"one-physical-nic"); - let mut index = HostGlobalAuthorityIndex::new_for_tests_ready(); - for owner in [ - "323e4567-e89b-42d3-a456-426614174002", - "423e4567-e89b-42d3-a456-426614174003", - ] { - index - .admit_before_effect( - request( - &host, - &nic, - &zone, - proof(owner, 1), - MacvtapMode::Bridge, - SharingPolicy::Multiplexed, - 2, - ), - |_| ExternalNicEffectOutcome::Confirmed, - ) - .unwrap(); - } - let status = index.external_nic_status(host, &nic).unwrap(); - assert_eq!(status.holder_count(), 2); - assert_eq!(status.arbitration(), SharingPolicy::Multiplexed); - assert!(!status.available()); - } - - #[test] - fn exclusive_mixed_and_non_bridge_claims_report_the_general_conflict() { - let host = uid("123e4567-e89b-42d3-a456-426614174000"); - let zone = uid("223e4567-e89b-42d3-a456-426614174001"); - for (first_mode, first_policy, next_mode, next_policy) in [ - ( - MacvtapMode::Bridge, - SharingPolicy::Exclusive, - MacvtapMode::Bridge, - SharingPolicy::Multiplexed, - ), - ( - MacvtapMode::Private, - SharingPolicy::Exclusive, - MacvtapMode::Private, - SharingPolicy::Exclusive, - ), - ] { - let nic = identity(b"one-physical-nic"); - let mut index = HostGlobalAuthorityIndex::new_for_tests_ready(); - index - .admit_before_effect( - request( - &host, - &nic, - &zone, - proof("323e4567-e89b-42d3-a456-426614174002", 1), - first_mode, - first_policy, - 8, - ), - |_| ExternalNicEffectOutcome::Confirmed, - ) - .unwrap(); - let error = index - .admit_before_effect( - request( - &host, - &nic, - &zone, - proof("423e4567-e89b-42d3-a456-426614174003", 1), - next_mode, - next_policy, - 8, - ), - |_| ExternalNicEffectOutcome::Confirmed, - ) - .unwrap_err(); - assert_eq!( - error, - AuthorityError::Admission(ExternalNicAdmissionError::ExternalPhysicalNicConflict) - ); - } - - let nic = identity(b"cross-zone-exclusive-nic"); - let mut index = HostGlobalAuthorityIndex::new_for_tests_ready(); - index - .admit_before_effect( - request( - &host, - &nic, - &zone, - proof("323e4567-e89b-42d3-a456-426614174002", 1), - MacvtapMode::Passthru, - SharingPolicy::Exclusive, - 1, - ), - |_| ExternalNicEffectOutcome::Confirmed, - ) - .unwrap(); - let mut effects = 0; - let error = index - .admit_before_effect( - request( - &host, - &nic, - &uid("523e4567-e89b-42d3-a456-426614174004"), - proof("423e4567-e89b-42d3-a456-426614174003", 1), - MacvtapMode::Passthru, - SharingPolicy::Exclusive, - 1, - ), - |_| { - effects += 1; - ExternalNicEffectOutcome::Confirmed - }, - ) - .unwrap_err(); - assert_eq!( - error, - AuthorityError::Admission(ExternalNicAdmissionError::ExternalPhysicalNicConflict) - ); - assert_eq!(effects, 0); - } - - #[test] - fn restart_adopts_one_exact_owner_and_quarantines_ambiguity() { - let host = uid("123e4567-e89b-42d3-a456-426614174000"); - let zone = uid("223e4567-e89b-42d3-a456-426614174001"); - let nic = identity(b"one-physical-nic"); - let owner = proof("323e4567-e89b-42d3-a456-426614174002", 4); - let mut index = HostGlobalAuthorityIndex::new_for_tests_ready(); - index - .admit_before_effect( - request( - &host, - &nic, - &zone, - owner.clone(), - MacvtapMode::Bridge, - SharingPolicy::Exclusive, - 1, - ), - |_| ExternalNicEffectOutcome::Confirmed, - ) - .unwrap(); - assert!(matches!( - index.adopt(host.clone(), &nic, &owner, core::slice::from_ref(&owner)), - ExternalNicAdoption::Adopted(_) - )); - assert!(matches!( - index.adopt(host, &nic, &owner, &[owner.clone(), owner.clone()]), - ExternalNicAdoption::QuarantinedAmbiguous - )); - } - - #[test] - fn update_and_delete_release_only_after_attachment_close() { - let host = uid("123e4567-e89b-42d3-a456-426614174000"); - let zone = uid("223e4567-e89b-42d3-a456-426614174001"); - let nic = identity(b"one-physical-nic"); - let mut index = HostGlobalAuthorityIndex::new_for_tests_ready(); - let gate = index - .admit_before_effect( - request( - &host, - &nic, - &zone, - proof("323e4567-e89b-42d3-a456-426614174002", 1), - MacvtapMode::Bridge, - SharingPolicy::Exclusive, - 1, - ), - |_| ExternalNicEffectOutcome::Confirmed, - ) - .unwrap(); - let lease = gate.into_lease(); - assert_eq!( - index.close_then_release(&lease, || ExternalNicCloseOutcome::RetryableFailure), - Err(AuthorityError::AttachmentCloseUnconfirmed) - ); - assert!(index.external_nic_status(host.clone(), &nic).is_some()); - - let adopted = match index.adopt( - host.clone(), - &nic, - &proof("323e4567-e89b-42d3-a456-426614174002", 1), - &[proof("323e4567-e89b-42d3-a456-426614174002", 1)], - ) { - ExternalNicAdoption::Adopted(lease) => lease, - other => panic!("expected adoption, got {other:?}"), - }; - let mut closed = false; - let replacement = request( - &host, - &nic, - &zone, - proof("423e4567-e89b-42d3-a456-426614174003", 2), - MacvtapMode::Bridge, - SharingPolicy::Exclusive, - 1, - ); - let replacement_lease = index - .replace_after_close(&adopted, replacement, || { - closed = true; - ExternalNicCloseOutcome::Confirmed - }) - .unwrap(); - assert!(closed); - index - .close_then_release(&replacement_lease, || ExternalNicCloseOutcome::Confirmed) - .unwrap(); - assert!(index.external_nic_status(host, &nic).is_none()); - } - #[test] fn provider_cardinality_is_zone_local_and_effects_are_fail_closed() { let mut index = HostGlobalAuthorityIndex::new_for_tests_ready(); @@ -3778,25 +2656,6 @@ mod tests { ); } - #[test] - fn diagnostics_never_expose_identity_digest_host_or_owner_values() { - let identity_canary = b"private-hardware-identity"; - let host_canary = "123e4567-e89b-42d3-a456-426614174000"; - let owner_canary = "223e4567-e89b-42d3-a456-426614174001"; - let nic = identity(identity_canary); - let owner = proof(owner_canary, 1); - let key = ExternalNicAuthorityKey::derive(uid(host_canary), &nic); - let rendered = format!("{nic:?} {owner:?} {key:?}"); - for canary in [ - String::from_utf8(identity_canary.to_vec()).unwrap(), - host_canary.to_owned(), - owner_canary.to_owned(), - key.opaque_digest.clone(), - ] { - assert!(!rendered.contains(&canary)); - } - } - #[test] fn duplicate_same_owner_reservations_are_rejected_without_aliasing_leases() { let host = uid("f93e4567-e89b-42d3-a456-426614174060"); @@ -3812,37 +2671,6 @@ mod tests { ); index.release_authority(&first).unwrap(); assert!(index.authority_status(&authority_request).is_none()); - - let nic = identity(b"duplicate-nic"); - let nic_request = request( - &uid("d14e4567-e89b-42d3-a456-426614174064"), - &nic, - &uid("e14e4567-e89b-42d3-a456-426614174065"), - proof("f14e4567-e89b-42d3-a456-426614174066", 1), - MacvtapMode::Bridge, - SharingPolicy::Multiplexed, - 2, - ); - let lease = index - .admit_before_effect(nic_request, |_| ExternalNicEffectOutcome::Confirmed) - .unwrap() - .into_lease(); - let duplicate = request( - &uid("d14e4567-e89b-42d3-a456-426614174064"), - &nic, - &uid("e14e4567-e89b-42d3-a456-426614174065"), - proof("f14e4567-e89b-42d3-a456-426614174066", 1), - MacvtapMode::Bridge, - SharingPolicy::Multiplexed, - 2, - ); - assert_eq!( - index.admit(duplicate).unwrap_err(), - AuthorityError::DuplicateActiveReservation - ); - index - .close_then_release(&lease, || ExternalNicCloseOutcome::Confirmed) - .unwrap(); } #[test] From 5f45eb697d2e0e6c6dc3a7137ad293b39ca477e8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:37 -0700 Subject: [PATCH 306/726] d2b-contracts-provider: derive the descriptor execution wire field from the enum --- .../d2b-contracts-provider/src/v3/provider.rs | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/packages/d2b-contracts-provider/src/v3/provider.rs b/packages/d2b-contracts-provider/src/v3/provider.rs index afbf1d8b5..4265bed95 100644 --- a/packages/d2b-contracts-provider/src/v3/provider.rs +++ b/packages/d2b-contracts-provider/src/v3/provider.rs @@ -27,7 +27,7 @@ use std::collections::{BTreeMap, BTreeSet}; -use schemars::JsonSchema; +use schemars::{JsonSchema, r#gen::SchemaGenerator}; use serde::{Deserialize, Deserializer, Serialize}; use super::semantic_services::{ @@ -1317,18 +1317,38 @@ impl core::fmt::Debug for ComponentExecution { } } -#[derive(Clone, Default, PartialEq, Eq, Serialize, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -struct ComponentExecutionWire { - #[serde(default, skip_serializing_if = "Option::is_none")] - binary_ref: Option, +impl Serialize for ComponentExecution { + fn serialize(&self, serializer: S) -> Result { + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(1))?; + if let Self::Launchable { binary_ref } = self { + map.serialize_entry("binaryRef", binary_ref)?; + } + map.end() + } } -impl From<&ComponentExecution> for ComponentExecutionWire { - fn from(execution: &ComponentExecution) -> Self { - Self { - binary_ref: execution.binary_ref().cloned(), - } +impl JsonSchema for ComponentExecution { + fn schema_name() -> String { + "ComponentExecution".to_owned() + } + + fn json_schema(_gen: &mut SchemaGenerator) -> schemars::schema::Schema { + let mut properties = schemars::Map::new(); + properties.insert( + "binaryRef".to_owned(), + _gen.subschema_for::>(), + ); + let validation = schemars::schema::ObjectValidation { + properties, + ..Default::default() + }; + let object = schemars::schema::SchemaObject { + instance_type: Some(schemars::schema::InstanceType::Object.into()), + object: Some(Box::new(validation)), + ..Default::default() + }; + object.into() } } @@ -1341,8 +1361,6 @@ impl From<&ComponentExecution> for ComponentExecutionWire { #[serde(rename_all = "camelCase")] pub struct ComponentDescriptor { #[serde(flatten)] - execution_wire: ComponentExecutionWire, - #[serde(skip)] execution: ComponentExecution, component_id: BoundedToken, component_type: ComponentType, @@ -1427,7 +1445,6 @@ impl ComponentDescriptor { } Ok(Self { execution: ComponentExecution::InProcessBootstrap, - execution_wire: ComponentExecutionWire::default(), component_id, component_type, exported_resource_types, @@ -1446,7 +1463,6 @@ impl ComponentDescriptor { /// Set the execution mode encoded by the signed descriptor. pub fn with_execution(mut self, execution: ComponentExecution) -> Self { - self.execution_wire = ComponentExecutionWire::from(&execution); self.execution = execution; self } @@ -4360,4 +4376,19 @@ mod tests { assert!(!component.contains("volume-controller")); assert!(!component.contains("sha256:")); } + + #[test] + fn execution_mode_round_trips_through_the_flat_binary_ref_field() { + for execution in [ + ComponentExecution::InProcessBootstrap, + ComponentExecution::Launchable { + binary_ref: BinaryRef::parse("volume-controller").unwrap(), + }, + ] { + let descriptor = controller().with_execution(execution.clone()); + let wire = serde_json::to_value(&descriptor).unwrap(); + let round_tripped = serde_json::from_value::(wire).unwrap(); + assert_eq!(round_tripped.execution(), &execution); + } + } } From 3b86c38b691c9b467593009b46b771442cc595c8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:37 -0700 Subject: [PATCH 307/726] d2bd-runtime: emit named fields on the pidfs probe warn and error arms --- packages/d2bd-runtime/src/pidfs_probe.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/d2bd-runtime/src/pidfs_probe.rs b/packages/d2bd-runtime/src/pidfs_probe.rs index be9bcc0b9..c831f0f24 100644 --- a/packages/d2bd-runtime/src/pidfs_probe.rs +++ b/packages/d2bd-runtime/src/pidfs_probe.rs @@ -137,14 +137,17 @@ pub(crate) fn enforce_probe_outcome_with( } } PidfsProbeOutcome::PidfsNotPresent { st_dev } => { - let msg = format!( - "pidfs probe: pidfd_open(2) succeeded but fstat returned st_dev=0 (pidfs not present in this kernel build). v1.1+ requires pidfs for BootedNotify identity. Operators must rebuild the kernel with pidfs enabled (CONFIG_FS_PID=y / CONFIG_PIDFD_STAT=y on kernel >= 6.9). Observed st_dev={st_dev}." - ); if allow_soft_fail { - tracing::warn!("{msg} (soft-fail enabled)"); + tracing::warn!( + pidfs_st_dev = %st_dev, + "pidfs probe: pidfd_open(2) succeeded but fstat returned st_dev=0 (pidfs not present in this kernel build). v1.1+ requires pidfs for BootedNotify identity. Operators must rebuild the kernel with pidfs enabled (CONFIG_FS_PID=y / CONFIG_PIDFD_STAT=y on kernel >= 6.9). (soft-fail enabled)" + ); Ok(()) } else { - tracing::error!("{msg}"); + tracing::error!( + pidfs_st_dev = %st_dev, + "pidfs probe: pidfd_open(2) succeeded but fstat returned st_dev=0 (pidfs not present in this kernel build). v1.1+ requires pidfs for BootedNotify identity. Operators must rebuild the kernel with pidfs enabled (CONFIG_FS_PID=y / CONFIG_PIDFD_STAT=y on kernel >= 6.9)." + ); Err(TypedError::InternalIo { context: "pidfs-runtime-probe".to_owned(), detail: format!("pidfs absent (st_dev={st_dev})"), @@ -152,10 +155,10 @@ pub(crate) fn enforce_probe_outcome_with( } } PidfsProbeOutcome::UnexpectedError { detail } => { - let msg = format!( - "pidfs probe: unexpected error: {detail}. Treating as soft-defer for diagnostic purposes; investigate before relying on BootedNotify identity in production." + tracing::warn!( + detail = %detail, + "pidfs probe: unexpected error. Treating as soft-defer for diagnostic purposes; investigate before relying on BootedNotify identity in production." ); - tracing::warn!("{msg}"); // Always soft-defer on unexpected errors - they indicate // a permissions / namespace edge case, not a missing // pidfs. From d59bb44a3530285350197ea6cd0d7e29006ed22e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:39 -0700 Subject: [PATCH 308/726] clipboard-wayland: type picker completion keys --- .../src/history.rs | 18 +++++-- .../src/picker.rs | 47 ++++++++++++++++++- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/history.rs b/packages/d2b-provider-clipboard-wayland/src/history.rs index a40e4e40d..c84c58710 100644 --- a/packages/d2b-provider-clipboard-wayland/src/history.rs +++ b/packages/d2b-provider-clipboard-wayland/src/history.rs @@ -1,5 +1,6 @@ //! Bounded in-memory clipboard history and lifecycle controls. +use crate::picker::CompletionKey; use crate::policy::Policy; use sha2::{Digest, Sha256}; use std::collections::{BTreeMap, BTreeSet, VecDeque}; @@ -129,7 +130,7 @@ pub struct ClipboardHistory { total_bytes: usize, suspended: BTreeSet, guest_requests: BTreeMap>, - picker_completions: BTreeMap, + picker_completions: BTreeMap, } impl ClipboardHistory { @@ -240,7 +241,7 @@ impl ClipboardHistory { self.guest_requests.remove(guest); self.picker_completions - .retain(|key, _| !key.split('|').any(|component| component == guest)); + .retain(|key, _| !key.references_guest(guest)); } /// Purge all retained payloads and replay/rate-limit state. @@ -301,7 +302,7 @@ impl ClipboardHistory { /// Atomically claim one picker completion until its receipt expires. pub(crate) fn claim_picker_completion( &mut self, - key: String, + key: CompletionKey, expires_at: u64, now_secs: u64, ) -> bool { @@ -399,6 +400,7 @@ impl core::fmt::Debug for ClipboardHistory { #[cfg(test)] mod tests { use super::{ClipboardEntry, ClipboardHistory}; + use crate::picker::CompletionKey; use crate::ClipboardConfig; #[test] @@ -431,7 +433,15 @@ mod tests { #[test] fn purging_a_guest_releases_its_picker_completion_keys() { let mut history = ClipboardHistory::new(ClipboardConfig::default()); - let key = "operation|zone|Guest/work|1|zone|Guest/destination|1".to_owned(); + let key = CompletionKey::new( + "operation".to_owned(), + "zone".to_owned(), + "Guest/work".to_owned(), + 1, + "zone".to_owned(), + "Guest/destination".to_owned(), + 1, + ); assert!(history.claim_picker_completion(key.clone(), 200, 100)); history.purge_guest("Guest/work"); assert!(history.claim_picker_completion(key, 200, 100)); diff --git a/packages/d2b-provider-clipboard-wayland/src/picker.rs b/packages/d2b-provider-clipboard-wayland/src/picker.rs index d4e2e78bf..382718368 100644 --- a/packages/d2b-provider-clipboard-wayland/src/picker.rs +++ b/packages/d2b-provider-clipboard-wayland/src/picker.rs @@ -221,6 +221,50 @@ impl core::fmt::Debug for PickerReceipt { } } +/// Key identifying one picker completion claim retained in history. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct CompletionKey { + operation_id: String, + source_zone: String, + source_subject: String, + source_reconnect_generation: u64, + destination_zone: String, + destination_guest: String, + destination_reconnect_generation: u64, +} + +impl CompletionKey { + /// Build the completion claim key for one authenticated picker completion. + pub(crate) fn new( + operation_id: impl Into, + source_zone: impl Into, + source_subject: impl Into, + source_reconnect_generation: u64, + destination_zone: impl Into, + destination_guest: impl Into, + destination_reconnect_generation: u64, + ) -> Self { + Self { + operation_id: operation_id.into(), + source_zone: source_zone.into(), + source_subject: source_subject.into(), + source_reconnect_generation, + destination_zone: destination_zone.into(), + destination_guest: destination_guest.into(), + destination_reconnect_generation, + } + } + + /// Whether one owner label appears anywhere in the key. + pub(crate) fn references_guest(&self, guest: &str) -> bool { + self.operation_id == guest + || self.source_zone == guest + || self.source_subject == guest + || self.destination_zone == guest + || self.destination_guest == guest + } +} + /// The picker-side completion authority. pub struct PickerAuthority; @@ -255,8 +299,7 @@ impl PickerAuthority { }; let receipt = PickerReceipt::issue(source, destination, request, entry_digest, expires_at)?; - let completion_key = format!( - "{}|{}|{}|{}|{}|{}|{}", + let completion_key = CompletionKey::new( request.operation_id(), source.zone(), source.subject_ref().to_canonical_string(), From fd2d8eb306e31c763036adaad51cafcd1d1bc91e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:43 -0700 Subject: [PATCH 309/726] d2b-core-controller: remove the uncalled observed-child envelope adapter --- .../src/binding_children.rs | 102 +----------------- packages/d2b-core-controller/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 100 deletions(-) diff --git a/packages/d2b-core-controller/src/binding_children.rs b/packages/d2b-core-controller/src/binding_children.rs index 21599497c..43599b6f3 100644 --- a/packages/d2b-core-controller/src/binding_children.rs +++ b/packages/d2b-core-controller/src/binding_children.rs @@ -11,12 +11,12 @@ use d2b_contracts_provider::v3::semantic_services::child_resources::{ BindingChildIntent, BindingChildKind, BindingChildPlacement, }; use d2b_contracts_resource::v3::{ - CanonicalJsonValue, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceRef, ResourceTypeName, ResourceUid, - ZoneRevision, canonical_digest, + CanonicalJsonValue, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceRef, ResourceTypeName, + canonical_digest, }; use d2b_contracts_zone_session::v3::resource_bundle::BundleResource; -use crate::{ObservedChild, OwnerReconcileError, ResourceKey}; +use crate::OwnerReconcileError; /// One provider-supplied desired child body paired with its semantic intent. #[derive(Clone, PartialEq, Eq)] @@ -164,102 +164,6 @@ pub fn semantic_child_digest( Ok(canonical_digest(RESOURCE_ENVELOPE_DOMAIN_TAG, &canonical)) } -/// Build an observed child row from a complete Resource API envelope. -/// -/// This is the Core-side adapter used after a relist. It deliberately derives -/// the digest from the stored body instead of trusting a Provider-supplied -/// payload digest, keeping UID/revision fencing separate from desired-state -/// convergence. -pub fn observed_child_from_resource( - target: ResourceKey, - owner: &ResourceKey, - owner_generation: d2b_contracts_resource::v3::ResourceGeneration, - revision: ZoneRevision, - canonical_resource: &[u8], - deletion_requested: bool, - deletion_ready: bool, -) -> Result { - let digest = semantic_child_digest(canonical_resource)?; - let value = CanonicalJsonValue::parse(canonical_resource) - .map_err(|_| BindingChildMaterializationError::MalformedResource)?; - let CanonicalJsonValue::Object(root) = value else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - let Some(CanonicalJsonValue::String(resource_type)) = root.get("type") else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - if resource_type != target.resource_ref().resource_type().as_str() { - return Err(BindingChildMaterializationError::IdentityMismatch); - } - let Some(CanonicalJsonValue::Object(metadata)) = root.get("metadata") else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - let Some(CanonicalJsonValue::String(name)) = metadata.get("name") else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - if name != target.resource_ref().name().as_str() { - return Err(BindingChildMaterializationError::IdentityMismatch); - } - let Some(CanonicalJsonValue::String(zone)) = metadata.get("zone") else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - if zone != target.zone().as_str() { - return Err(BindingChildMaterializationError::OwnerMismatch); - } - let Some(CanonicalJsonValue::String(uid)) = metadata.get("uid") else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - if ResourceUid::parse(uid).map_err(|_| BindingChildMaterializationError::IdentityMismatch)? - != *target.uid() - { - return Err(BindingChildMaterializationError::IdentityMismatch); - } - let Some(CanonicalJsonValue::Integer(observed_revision)) = metadata.get("revision") else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - let observed_revision = u64::try_from(*observed_revision) - .ok() - .map(ZoneRevision::new) - .filter(|observed_revision| observed_revision.get() != 0) - .ok_or(BindingChildMaterializationError::MalformedResource)?; - if observed_revision != revision { - return Err(BindingChildMaterializationError::OwnerReconcile( - OwnerReconcileError::StaleRevision, - )); - } - let Some(owner_ref) = metadata.get("ownerRef") else { - return Err(BindingChildMaterializationError::OwnerMismatch); - }; - let CanonicalJsonValue::String(owner_ref) = owner_ref else { - return Err(BindingChildMaterializationError::OwnerMismatch); - }; - let owner_ref = ResourceRef::parse(owner_ref) - .map_err(|_| BindingChildMaterializationError::OwnerMismatch)?; - let Some(CanonicalJsonValue::Integer(generation)) = metadata.get("generation") else { - return Err(BindingChildMaterializationError::MalformedResource); - }; - let generation = u64::try_from(*generation) - .ok() - .and_then(|generation| d2b_contracts_resource::v3::ResourceGeneration::new(generation).ok()) - .ok_or(BindingChildMaterializationError::MalformedResource)?; - let observed = ObservedChild::with_owner_and_dependencies( - target, - owner, - owner_generation, - revision, - digest, - deletion_requested, - deletion_ready, - std::iter::empty(), - ) - .map_err(BindingChildMaterializationError::OwnerReconcile)? - .with_generation(generation); - if observed.owner_ref() != Some(&owner_ref) { - return Err(BindingChildMaterializationError::OwnerMismatch); - } - Ok(observed) -} - /// Build the canonical, UID-free Resource API create payload for one child. /// /// This is intentionally owned by Core: Providers cannot smuggle arbitrary diff --git a/packages/d2b-core-controller/src/lib.rs b/packages/d2b-core-controller/src/lib.rs index a3c697711..2d60e318e 100644 --- a/packages/d2b-core-controller/src/lib.rs +++ b/packages/d2b-core-controller/src/lib.rs @@ -32,7 +32,7 @@ pub mod owner_reconcile; pub use binding_children::{ BindingChildMaterializationError, BindingChildResource, materialize_child_create_payload, - observed_child_from_resource, semantic_child_digest, + semantic_child_digest, }; pub use controller_assignment::{ AssignmentEpoch, AssignmentError, AssignmentGrantError, AssignmentIdentity, AssignmentPhase, From dbac9940ce9fbe74cc48f7007e3f2f21a46aff22 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:27:48 -0700 Subject: [PATCH 310/726] d2b-process-conformance: remove the duplicate process_provider re-export namespace --- packages/d2b-process-conformance/src/lib.rs | 1 - .../src/process_provider.rs | 14 -------------- 2 files changed, 15 deletions(-) delete mode 100644 packages/d2b-process-conformance/src/process_provider.rs diff --git a/packages/d2b-process-conformance/src/lib.rs b/packages/d2b-process-conformance/src/lib.rs index 4d8fceeaf..62d573eff 100644 --- a/packages/d2b-process-conformance/src/lib.rs +++ b/packages/d2b-process-conformance/src/lib.rs @@ -33,7 +33,6 @@ mod status; mod terminal; mod ticket; -pub mod process_provider; pub mod suite; pub mod testing; diff --git a/packages/d2b-process-conformance/src/process_provider.rs b/packages/d2b-process-conformance/src/process_provider.rs deleted file mode 100644 index e42eed145..000000000 --- a/packages/d2b-process-conformance/src/process_provider.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Stable Process Provider contract namespace. -//! -//! The crate originally split these values into small implementation modules -//! so the conformance suite could evolve independently. This public -//! namespace is the destination-compatible boundary for Provider crates and -//! keeps all launch, adoption, pidfd, and terminal-result types on one -//! documented surface. - -pub use crate::{ - AdoptionCandidate, BrokerTerminalResult, CancellationBinding, ConfigurationDigest, - IdentityBinding, InheritedFdTable, LaunchTicket, OperationBinding, ParentWaitEvidence, - PidfdEvidence, ProcessExitClass, ProcessIdentityDigest, ProcessOutcome, ReadinessExpectation, - WaitReapOwner, -}; From 6a4c9b7c6d5a5314d2e9195f65c8c83a4e13fea4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:28:02 -0700 Subject: [PATCH 311/726] process-systemd: drop always-true no_persistent_unit accessor --- packages/d2b-provider-process-systemd/src/lifecycle.rs | 5 ----- packages/d2b-provider-process-systemd/tests/lifecycle.rs | 1 - 2 files changed, 6 deletions(-) diff --git a/packages/d2b-provider-process-systemd/src/lifecycle.rs b/packages/d2b-provider-process-systemd/src/lifecycle.rs index 090adf8cb..648bb3617 100644 --- a/packages/d2b-provider-process-systemd/src/lifecycle.rs +++ b/packages/d2b-provider-process-systemd/src/lifecycle.rs @@ -57,11 +57,6 @@ impl SystemdProviderConfig { max_concurrent_launches, }) } - - /// Systemd units are transient and never Provider-owned persistent units. - pub const fn no_persistent_unit(self) -> bool { - true - } } /// Invalid systemd Provider configuration. diff --git a/packages/d2b-provider-process-systemd/tests/lifecycle.rs b/packages/d2b-provider-process-systemd/tests/lifecycle.rs index 4cad1795f..190518b7d 100644 --- a/packages/d2b-provider-process-systemd/tests/lifecycle.rs +++ b/packages/d2b-provider-process-systemd/tests/lifecycle.rs @@ -9,7 +9,6 @@ fn provider_config_is_bounded_and_transient() { assert_eq!(config.launch_timeout_sec, 30); assert!(SystemdProviderConfig::new(0, 30, 5, 64).is_err()); assert!(SystemdProviderConfig::new(30, 30, 5, 256).is_ok()); - assert!(config.no_persistent_unit()); } #[test] From 9ed591eb2e72954f880d7fc0082fe2aa882bee84 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:28:12 -0700 Subject: [PATCH 312/726] d2b-process-conformance: drop the unused BrokerExitClass alias --- packages/d2b-process-conformance/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/d2b-process-conformance/src/lib.rs b/packages/d2b-process-conformance/src/lib.rs index 62d573eff..916ccf5a1 100644 --- a/packages/d2b-process-conformance/src/lib.rs +++ b/packages/d2b-process-conformance/src/lib.rs @@ -49,9 +49,7 @@ pub use status::{ AdoptionCondition, ExitClass, ExitObservation, ProcessPhaseClass, ProcessStatusReport, }; pub use terminal::ExitClass as ProcessExitClass; -pub use terminal::{ - BrokerTerminalResult, ExitClass as BrokerExitClass, ParentWaitEvidence, ProcessOutcome, -}; +pub use terminal::{BrokerTerminalResult, ParentWaitEvidence, ProcessOutcome}; pub use ticket::{ CancellationBinding, CompiledDigests, GuestExecutionBinding, InheritedFdTable, LaunchTicket, MAX_INHERITED_FDS, MAX_LAUNCH_DEADLINE_MS, OperationBinding, ReadinessExpectation, From 86da6b6a0e7bf3e94a6ea6b4dfe416e5b035eb20 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:28:31 -0700 Subject: [PATCH 313/726] audit: fold the runtime observability tail --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index f3bf18573..2544bbaf5 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -587,7 +587,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0534` | `err` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/resource_plane_v3.rs | ConstructionInputs::production swallows attach_process_providers Result. Not edited: budget exhausted. | | | `RS-0536` | `err` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/process_provider_runtime.rs | 0700 set_permissions silently swallowed; warn on Err. Not edited: budget exhausted. | | | `RS-0528` | `err` | `d2bd` | low | actionable | family | | | | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | | | -| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | not-started | U3 | | packages/d2bd-runtime/src/broker_transport.rs, packages/d2bd/src/composition.rs | worker could not map the row to the cited anchor; left untouched | | +| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | already-fixed | U3 | ebb3831b1 | packages/d2bd-runtime/src/broker_transport.rs | At session-start HEAD, default_audit_join_context maps CanonicalAuditDigest::parse failures to TypedError::WireInvalidFrame;no .expect remains (commit ebb3831b1, ledger wave U1 applied-variant). No ed | | | `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | c14b5d486 | packages/d2bd-runtime/src/wire.rs | map_parse_error classifies structurally: serde_json::Error::classify() gates the frame kind, and the generic WireInvalidFrame detail now carries line/column; the two payload-level wire kinds (unknown- | | | `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | cdfb78d49 | packages/d2bd-runtime/src/exec_session.rs | spawn_session_worker now returns std::io::Result> (Builder::spawn error propagated via Ok(...)?), replacing the expect panic; the two test call sites unwrap with expect. | | | `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 75c49e784 | packages/d2bd-runtime/src/console_session.rs | Deleted panicking impl Default for ConsoleClientHandle (census: no ConsoleClientHandle::default() callers in workspace). | | @@ -659,10 +659,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0603` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Located at composition.rs:14815 (drifted from 14781): message-only error; add zone field. Not edited: budget exhausted. | | | `RS-0604` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Two identical message-only warn events during shutdown; add zones field. Not edited: budget exhausted. | | | `RS-0608` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | In-flight-cap refusal warn now carries peer_uid and max = posture.max_inflight fields, matching the sibling peer-not-broker warn style. Committed together with RS-0577 (same file, same commit). cargo | | -| `RS-0609` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs` | typed-shell octal format wait not implemented in session | | -| `RS-0610` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680` | ssh_host_key_preflight octal wait not implemented in session | | -| `RS-0611` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `packages/d2bd-runtime/src/readiness.rs:327` | readiness one-shot-exit warning fields not implemented in session | | -| `RS-0612` | `obs` | `d2bd-runtime` | low | actionable | leaf | not-started | U3 | | `packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132` | pidfs probe warning named fields not implemented in session | | +| `RS-0609` | `obs` | `d2bd-runtime` | low | actionable | leaf | already-fixed | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | At session-start HEAD, write_daemon_version_file already routes all five failure paths through tracing::warn! with error/path named fields (commit 97df1b826). No edit made. | | +| `RS-0610` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 918539524 | packages/d2bd-runtime/src/ssh_host_key_preflight.rs | Octal mode field is now tracing::field::debug(format_args!(...)));the pre-joined subjects string was inlined as tracing::field::display(join-expr) inside the warn! so it is built only when the event i | | +| `RS-0611` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | ead7c7956 | packages/d2bd-runtime/src/readiness.rs | Unparseable-stat warning now emits pid = %pid and path = %format_args!(/proc/{pid}/stat) named fields with a shorter message;no correlation-identifier references. | | +| `RS-0612` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 3b86c38b6 | packages/d2bd-runtime/src/pidfs_probe.rs | PidfsNotPresent arm emits pidfs_st_dev = %st_dev (both warn and error), UnexpectedError arm emits detail = %detail;operator-facing sentence kept as message template with interpolated tails removed. | | | `RS-0613` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 785aebb20 | packages/d2bd-runtime/src/console_session.rs | qemu console fd-conversion warn now carries error = %e as a named field; no correlation identifiers in the record. | | | `RS-0659` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/exec_client.rs` | one-line docs for expect_start/expect_detached_create/list/logs/status/kill | | | `RS-0658` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/doctor.rs` | docs for doctor/validate/CLI surface incl. crate-level doc | | From 82f8cac47e67a12fb857e85a1df90da54d4bd645 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:29:20 -0700 Subject: [PATCH 314/726] d2b-provider-guest-qemu-media: reuse the bounded token validator --- .../d2b-provider-guest-qemu-media/src/config.rs | 6 ++---- .../src/controller/process_builder.rs | 4 +--- .../src/controller/volume.rs | 8 ++++---- .../d2b-provider-guest-qemu-media/src/hotplug.rs | 4 ++-- .../d2b-provider-guest-qemu-media/src/qmp/mod.rs | 9 +++------ .../src/types/guest.rs | 16 ++++------------ .../src/types/mod.rs | 2 +- 7 files changed, 17 insertions(+), 32 deletions(-) diff --git a/packages/d2b-provider-guest-qemu-media/src/config.rs b/packages/d2b-provider-guest-qemu-media/src/config.rs index 872ec6cc0..ca1e4d7f1 100644 --- a/packages/d2b-provider-guest-qemu-media/src/config.rs +++ b/packages/d2b-provider-guest-qemu-media/src/config.rs @@ -1,11 +1,9 @@ //! Bounded Provider configuration and controller-only projection. -use d2b_contracts_resource::v3::ResourceRef; +use d2b_contracts_resource::v3::{BoundedToken, ResourceRef}; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize}; -use crate::types::validate_token; - /// Default QMP greeting timeout in seconds. pub const DEFAULT_QMP_READY_TIMEOUT_SECONDS: u32 = 30; /// Default QMP command timeout in seconds. @@ -139,7 +137,7 @@ impl ProviderConfig { .display_provider_ref .as_ref() .is_some_and(|reference| reference.resource_type().as_str() != "Provider") - || !validate_token(&self.qemu_binary_artifact_id) + || BoundedToken::parse(self.qemu_binary_artifact_id.as_str()).is_err() || !(5..=300).contains(&self.qmp_ready_timeout_seconds) || !(5..=300).contains(&self.qmp_operation_timeout_seconds) || !(1024 * 1024..=256 * 1024 * 1024).contains(&self.runtime_tmpfs_quota_bytes) diff --git a/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs b/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs index a627c18e9..0b06f841e 100644 --- a/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs +++ b/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs @@ -13,8 +13,6 @@ use d2b_contracts_resource::v3::{ }; use serde::{Deserialize, Serialize}; -use crate::types::validate_token; - /// Process template id. pub const PROCESS_TEMPLATE: &str = "qemu-media-runner"; @@ -291,7 +289,7 @@ impl LaunchTicket { validate_process_spec(&self.process)?; let mut slots = std::collections::BTreeSet::new(); for attachment in &self.attachments { - if !validate_token(&attachment.slot) || !slots.insert(&attachment.slot) { + if BoundedToken::parse(attachment.slot.as_str()).is_err() || !slots.insert(&attachment.slot) { return Err(ProcessSpecError::DuplicateAttachmentSlot); } let expected = match attachment.kind { diff --git a/packages/d2b-provider-guest-qemu-media/src/controller/volume.rs b/packages/d2b-provider-guest-qemu-media/src/controller/volume.rs index df40ffdae..64b05f6d8 100644 --- a/packages/d2b-provider-guest-qemu-media/src/controller/volume.rs +++ b/packages/d2b-provider-guest-qemu-media/src/controller/volume.rs @@ -1,10 +1,10 @@ //! Controller-created runtime Volume specification. -use d2b_contracts_resource::v3::ResourceRef; +use d2b_contracts_resource::v3::{BoundedToken, ResourceRef}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -use crate::types::{runtime_volume_name, validate_token}; +use crate::types::runtime_volume_name; /// Runtime Volume finalizer. pub const RUNTIME_VOLUME_FINALIZER: &str = "runtime-qemu-media.d2bus.org/runtime-volume"; @@ -118,7 +118,7 @@ impl RuntimeVolumeSpec { return Err(VolumeSpecError::Invalid); } let zone = zone.into(); - if !validate_token(&zone) { + if BoundedToken::parse(zone.as_str()).is_err() { return Err(VolumeSpecError::Invalid); } let name = runtime_volume_name(&short_guest_key( @@ -162,7 +162,7 @@ impl RuntimeVolumeSpec { )); if self.owner_ref.resource_type().as_str() != "Guest" || self.provider_ref.resource_type().as_str() != "Provider" - || !validate_token(&self.zone) + || BoundedToken::parse(self.zone.as_str()).is_err() || self.name != expected_name || self.source_kind != "tmpfs" || self.source_policy_id != "runtime-qemu-media-runtime-tmpfs" diff --git a/packages/d2b-provider-guest-qemu-media/src/hotplug.rs b/packages/d2b-provider-guest-qemu-media/src/hotplug.rs index 0d2a4eae1..9b381b8d8 100644 --- a/packages/d2b-provider-guest-qemu-media/src/hotplug.rs +++ b/packages/d2b-provider-guest-qemu-media/src/hotplug.rs @@ -6,7 +6,7 @@ //! broker's privileged media kernel keeps its own committed view of this //! scaffold because the broker is pinned provider-free. -use crate::types::validate_token; +use d2b_contracts_resource::v3::BoundedToken; /// The hotplug action one scaffold plans. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -59,7 +59,7 @@ pub fn qemu_media_hotplug_scaffold( slot: &str, action: QemuMediaHotplugAction, ) -> Result { - if !validate_token(media_ref) { + if BoundedToken::parse(media_ref).is_err() { return Err(QemuMediaHotplugScaffoldError::InvalidMediaRef); } if slot.is_empty() { diff --git a/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs b/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs index 9998fdb99..c79c32875 100644 --- a/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs +++ b/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs @@ -2,6 +2,8 @@ use std::collections::VecDeque; +use d2b_contracts_resource::v3::BoundedToken; + /// A typed QMP command accepted by the Provider. #[derive(Debug, Clone, PartialEq, Eq)] pub enum QmpCommand { @@ -283,12 +285,7 @@ impl QmpSession { } fn validate_object_id(value: &str) -> Result<(), QmpError> { - if value.is_empty() - || value.len() > 63 - || !value - .bytes() - .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-') - { + if BoundedToken::parse(value).is_err() { Err(QmpError::InvalidObjectId) } else { Ok(()) diff --git a/packages/d2b-provider-guest-qemu-media/src/types/guest.rs b/packages/d2b-provider-guest-qemu-media/src/types/guest.rs index 4b3c18003..e66ac6934 100644 --- a/packages/d2b-provider-guest-qemu-media/src/types/guest.rs +++ b/packages/d2b-provider-guest-qemu-media/src/types/guest.rs @@ -3,7 +3,7 @@ use std::collections::BTreeSet; use d2b_contracts_resource::v3::{ - CanonicalJsonObject, ProviderSpecExtension, ResourceRef, ResourceSpec, SchemaVersion, + BoundedToken, CanonicalJsonObject, ProviderSpecExtension, ResourceRef, ResourceSpec, SchemaVersion, }; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize}; @@ -112,7 +112,7 @@ impl RemovableVolumeRef { return Err(GuestSpecError::InvalidVolumeRef); } let view = view.into(); - if !validate_token(&view) { + if BoundedToken::parse(view.as_str()).is_err() { return Err(GuestSpecError::InvalidView); } Ok(Self { volume_ref, view }) @@ -210,7 +210,7 @@ impl GuestProviderSpecSettings { { return Err(GuestSpecError::InvalidVolumeRef); } - if !validate_token(&self.boot_media_view) { + if BoundedToken::parse(self.boot_media_view.as_str()).is_err() { return Err(GuestSpecError::InvalidView); } if self.removable_volume_refs.len() > MAX_REMOVABLE_VOLUMES { @@ -413,15 +413,7 @@ impl core::fmt::Display for GuestSpecError { impl std::error::Error for GuestSpecError {} -/// Validate one lower-case bounded token. -pub(crate) fn validate_token(value: &str) -> bool { - !value.is_empty() - && value.len() <= 63 - && value.as_bytes()[0].is_ascii_lowercase() - && value - .bytes() - .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-') -} + const fn default_true() -> bool { true diff --git a/packages/d2b-provider-guest-qemu-media/src/types/mod.rs b/packages/d2b-provider-guest-qemu-media/src/types/mod.rs index 273528f0c..db33a34d5 100644 --- a/packages/d2b-provider-guest-qemu-media/src/types/mod.rs +++ b/packages/d2b-provider-guest-qemu-media/src/types/mod.rs @@ -8,4 +8,4 @@ pub use guest::{ NetworkAttachment, RemovableVolumeRef, RtcBase, audio_capability, build_guest_resource_spec, runtime_volume_name, }; -pub(crate) use guest::validate_token; + From 539ca51134e4bb2c87926485e942a973fee5fcc1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:32:27 -0700 Subject: [PATCH 315/726] gpu-provider: keep argv modules private behind root re-exports --- packages/d2b-provider-device-gpu/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-device-gpu/src/lib.rs b/packages/d2b-provider-device-gpu/src/lib.rs index 7cee17c1b..930c98872 100644 --- a/packages/d2b-provider-device-gpu/src/lib.rs +++ b/packages/d2b-provider-device-gpu/src/lib.rs @@ -11,10 +11,10 @@ mod controller; pub mod effects_service; mod effects; pub mod facets; -pub mod gpu_argv; +mod gpu_argv; mod process; mod settings; -pub mod video_argv; +mod video_argv; pub mod vocabulary; mod workers; From 81d0ff0579688eba7af6547a31a868625fa03b97 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:32:41 -0700 Subject: [PATCH 316/726] d2b-process-conformance: bundle the zone and runtime-scope pairing as one ticket binding --- .../d2b-process-conformance/src/ticket.rs | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/d2b-process-conformance/src/ticket.rs b/packages/d2b-process-conformance/src/ticket.rs index f22324d48..569123c1a 100644 --- a/packages/d2b-process-conformance/src/ticket.rs +++ b/packages/d2b-process-conformance/src/ticket.rs @@ -368,6 +368,16 @@ impl InheritedFdTable { } } +/// Private binding of the immutable Zone UID to its host-runtime scope. +/// +/// The scope is an effect-owner commitment, not a public ResourceRef, and it +/// is only valid together with the Zone UID it was derived for. +#[derive(Clone, PartialEq, Eq)] +struct RuntimeScopeBinding { + zone_uid: ResourceUid, + scope: ConfigurationDigest, +} + /// The ticket a Process controller hands to the fixed process effect /// adapter. /// @@ -384,7 +394,6 @@ impl InheritedFdTable { pub struct LaunchTicket { process_ref: ResourceRef, process_uid: ResourceUid, - zone_uid: Option, owner_ref: Option, owner_uid: Option, /// The canonical launch identity this ticket carries: owner ref/UID, @@ -392,7 +401,7 @@ pub struct LaunchTicket { /// role. The broker's identity fence consumes it instead of re-deriving /// its fields. launch_identity: LaunchIdentity, - runtime_scope: Option, + runtime_scope: Option, resource_revision: Option, resource_generation: ResourceGeneration, controller_generation: ControllerGeneration, @@ -484,7 +493,6 @@ impl LaunchTicket { Ok(Self { process_ref, process_uid, - zone_uid: None, owner_ref: None, owner_uid: None, launch_identity, @@ -541,7 +549,6 @@ impl LaunchTicket { runtime_scope: ConfigurationDigest, ) -> Result { if runtime_scope.is_zero() - || self.zone_uid.is_some() || self.runtime_scope.is_some() || self .owner_ref @@ -550,7 +557,7 @@ impl LaunchTicket { { return Err(ProcessConformanceError::InvalidTicket); } - self.zone_uid = Some(zone_uid); + self.runtime_scope = Some(RuntimeScopeBinding { zone_uid, scope: runtime_scope }); if let Some(owner_ref) = owner_ref { self.launch_identity = self .launch_identity @@ -558,7 +565,6 @@ impl LaunchTicket { .map_err(|_| ProcessConformanceError::InvalidTicket)?; self.owner_ref = Some(owner_ref); } - self.runtime_scope = Some(runtime_scope); Ok(self) } @@ -766,9 +772,7 @@ impl LaunchTicket { { return Err(ProcessConformanceError::InvalidTicket); } - if self.zone_uid.is_some() != self.runtime_scope.is_some() - || self.runtime_scope.is_some_and(ConfigurationDigest::is_zero) - { + if matches!(&self.runtime_scope, Some(binding) if binding.scope.is_zero()) { return Err(ProcessConformanceError::InvalidTicket); } if self.execution_ref.resource_type().as_str() == "Guest" @@ -979,7 +983,10 @@ impl LaunchTicket { /// Borrow the immutable Zone UID bound to this launch. pub const fn zone_uid(&self) -> Option<&ResourceUid> { - self.zone_uid.as_ref() + match &self.runtime_scope { + Some(binding) => Some(&binding.zone_uid), + None => None, + } } /// Borrow the exact semantic owner, when one was committed. @@ -994,7 +1001,10 @@ impl LaunchTicket { /// Borrow the private host-runtime scope commitment. pub const fn runtime_scope(&self) -> Option { - self.runtime_scope + match &self.runtime_scope { + Some(binding) => Some(binding.scope), + None => None, + } } /// Return the committed resource revision, when one was bound. From 5dfe92ec1c758222dd227939616541c056bd645e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:32:42 -0700 Subject: [PATCH 317/726] clipboard-wayland: type entry digests as sha256 newtype --- .../src/history.rs | 10 ++--- .../src/picker.rs | 41 +++++++++++++++---- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/history.rs b/packages/d2b-provider-clipboard-wayland/src/history.rs index c84c58710..a83392df3 100644 --- a/packages/d2b-provider-clipboard-wayland/src/history.rs +++ b/packages/d2b-provider-clipboard-wayland/src/history.rs @@ -1,6 +1,6 @@ //! Bounded in-memory clipboard history and lifecycle controls. -use crate::picker::CompletionKey; +use crate::picker::{CompletionKey, EntryDigest}; use crate::policy::Policy; use sha2::{Digest, Sha256}; use std::collections::{BTreeMap, BTreeSet, VecDeque}; @@ -42,7 +42,7 @@ impl std::error::Error for HistoryError {} /// A clipboard item retained only in clipd-host process memory. pub struct ClipboardEntry { - token: String, + token: EntryDigest, guest: String, mime: String, bytes: Vec, @@ -75,7 +75,7 @@ impl ClipboardEntry { hasher.update([0]); hasher.update(bytes); hasher.update(created_at.to_le_bytes()); - let token = format!("sha256:{:x}", hasher.finalize()); + let token = EntryDigest::from_sha256_hex(format!("sha256:{:x}", hasher.finalize())); Ok(Self { token, guest, @@ -85,9 +85,9 @@ impl ClipboardEntry { }) } - /// Borrow the opaque entry token. +/// Borrow the opaque entry token.. pub fn token(&self) -> &str { - &self.token + self.token.as_str() } /// Borrow the authenticated owner label. diff --git a/packages/d2b-provider-clipboard-wayland/src/picker.rs b/packages/d2b-provider-clipboard-wayland/src/picker.rs index 382718368..76f624f0b 100644 --- a/packages/d2b-provider-clipboard-wayland/src/picker.rs +++ b/packages/d2b-provider-clipboard-wayland/src/picker.rs @@ -139,6 +139,32 @@ pub enum PickerResult { Failed, } +/// Opaque sha256 entry digest validated once at construction. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EntryDigest(String); + +impl EntryDigest { + /// Parse a digest at the picker boundary. + pub(crate) fn parse(value: impl Into) -> Result { + let value = value.into(); + if value.starts_with("sha256:") { + Ok(Self(value)) + } else { + Err(PickerError::ResultMismatch) + } + } + + /// Wrap a digest freshly minted for an entry;the prefix is guaranteed by construction. + pub(crate) fn from_sha256_hex(value: String) -> Self { + Self(value) + } + + /// Borrow the canonical digest string. + pub fn as_str(&self) -> &str { + &self.0 + } +} + /// A one-use picker receipt bound to one authenticated clipboard operation. /// /// The receipt is intentionally not cloneable and exposes no constructor. @@ -149,7 +175,7 @@ pub struct PickerReceipt { source_zone: String, destination_zone: String, destination_guest: String, - entry_digest: String, + entry_digest: EntryDigest, entry_owner: String, expires_at: u64, source_reconnect_generation: u64, @@ -161,7 +187,7 @@ impl PickerReceipt { source: &AuthenticatedClipboardSession, destination: &AuthenticatedClipboardSession, request: &PickerRequest, - entry_digest: String, + entry_digest: EntryDigest, expires_at: u64, ) -> Result { if request.destination_guest() != destination.guest_ref() @@ -172,7 +198,6 @@ impl PickerReceipt { "Guest" | "User" ) || !destination.is_guest() - || !entry_digest.starts_with("sha256:") { return Err(PickerError::ResultMismatch); } @@ -200,7 +225,7 @@ impl PickerReceipt { && self.source_reconnect_generation == route.source_reconnect_generation() && self.destination_zone == route.destination_zone() && self.destination_guest == route.destination_guest() - && self.entry_digest == entry_digest + && self.entry_digest.as_str() == entry_digest && self.expires_at > now_secs && self.reconnect_generation == route.reconnect_generation() } @@ -279,22 +304,22 @@ impl PickerAuthority { history: &mut ClipboardHistory, now_secs: u64, ) -> Result { - let entry_digest = entry_digest.into(); + let entry_digest = EntryDigest::parse(entry_digest)?; match result { - PickerResult::Selected(selected) if selected == entry_digest => { + PickerResult::Selected(selected) if selected == entry_digest.as_str() => { let owner = entry_owner_for_session(source); if source.is_guest() && history.authorize_guest(&owner).is_err() { return Err(PickerError::ResultMismatch); } if !history.entry_matches_mime( - &entry_digest, + entry_digest.as_str(), &owner, request.mime_types(), now_secs, ) { return Err(PickerError::ResultMismatch); } - let Some(expires_at) = history.entry_expiry(&entry_digest, &owner, now_secs) else { + let Some(expires_at) = history.entry_expiry(entry_digest.as_str(), &owner, now_secs) else { return Err(PickerError::ResultMismatch); }; let receipt = From 0b3b6b645ab5cc97ede8e09d0eba64ae4ca0a095 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:32:56 -0700 Subject: [PATCH 318/726] session: collapse establishment constructors to one metrics path per role --- packages/d2b-session/src/engine.rs | 109 +++++++++++++---------------- 1 file changed, 50 insertions(+), 59 deletions(-) diff --git a/packages/d2b-session/src/engine.rs b/packages/d2b-session/src/engine.rs index 4dee68e0e..7fe0269d8 100644 --- a/packages/d2b-session/src/engine.rs +++ b/packages/d2b-session/src/engine.rs @@ -150,23 +150,7 @@ impl SessionEngine { credentials: HandshakeCredentials, now: Instant, ) -> Result { - Self::establish_initiator_with_generation_discovery_and_metrics( - transport, - identity, - credentials, - now, - Arc::new(NoopMetrics), - ) - .await - } - - pub async fn establish_initiator_with_generation_discovery_and_metrics( - transport: T, - identity: EndpointPolicyIdentity, - credentials: HandshakeCredentials, - now: Instant, - metrics: Arc, - ) -> Result { + let metrics = Arc::new(NoopMetrics); let descriptor = transport.descriptor(); let metric_identity = identity.clone(); let timeout = Duration::from_millis(u64::from(identity.limits.handshake_deadline_ms)); @@ -240,7 +224,7 @@ impl SessionEngine { Self::establish_initiator_inner(transport, policy, credentials, now).await } - pub async fn establish_initiator( +pub async fn establish_initiator( transport: T, policy: EndpointPolicy, credentials: HandshakeCredentials, @@ -336,42 +320,13 @@ impl SessionEngine { credentials: HandshakeCredentials, now: Instant, ) -> Result { - Self::establish_responder_with_metrics( - transport, - policy, - credentials, - now, - Arc::new(NoopMetrics), - ) - .await - } - - /// Establish a responder while accepting a strictly newer reconnect - /// generation from the authenticated offer. All policy fields remain - /// exact; only `reconnect_generation` may advance beyond the supplied - /// floor. - pub async fn establish_responder_with_generation_floor( - transport: T, - policy: EndpointPolicy, - credentials: HandshakeCredentials, - minimum_generation: u64, - now: Instant, - ) -> Result { - if minimum_generation == 0 { - return Err(SessionError::new(SessionErrorCode::GenerationMismatch)); - } + let metrics = Arc::new(NoopMetrics); let descriptor = transport.descriptor(); let metric_policy = policy.clone(); let timeout = Duration::from_millis(u64::from(policy.limits.handshake_deadline_ms)); let result = match tokio::time::timeout( timeout, - Self::establish_responder_inner_with_generation_floor( - transport, - policy, - credentials, - minimum_generation, - now, - ), + Self::establish_responder_inner(transport, policy, credentials, now), ) .await { @@ -381,9 +336,8 @@ impl SessionEngine { error = %error, purpose = metric_policy.purpose.as_str(), service = metric_policy.service.as_str(), - minimum_generation = minimum_generation, timeout_ms = timeout.as_millis() as u64, - "session handshake establishment failed (responder generation floor)" + "session handshake establishment failed (responder)" ); } result @@ -392,37 +346,72 @@ impl SessionEngine { tracing::warn!( purpose = metric_policy.purpose.as_str(), service = metric_policy.service.as_str(), - minimum_generation = minimum_generation, timeout_ms = timeout.as_millis() as u64, - "session handshake timed out (responder generation floor)" + "session handshake timed out (responder)" ); Err(SessionError::new(SessionErrorCode::HandshakeTimeout)) } }; record_establishment( - Arc::new(NoopMetrics).as_ref(), + metrics.as_ref(), descriptor, metric_policy.purpose, metric_policy.service, metric_policy.noise_profile, &result, ); - result + result.map(|engine| engine.with_metrics(metrics)) + } + + /// Establish a responder while accepting a strictly newer reconnect + /// generation from the authenticated offer. All policy fields remain + /// exact; only `reconnect_generation` may advance beyond the supplied + /// floor. + pub async fn establish_responder_with_generation_floor( + transport: T, + policy: EndpointPolicy, + credentials: HandshakeCredentials, + minimum_generation: u64, + now: Instant, + ) -> Result { + Self::establish_responder_with_generation_floor_and_metrics( + transport, + policy, + credentials, + minimum_generation, + now, + Arc::new(NoopMetrics), + ) + .await } - pub async fn establish_responder_with_metrics( + /// Establish a responder with a metrics sink while accepting a strictly + /// newer reconnect generation from the authenticated offer. All policy + /// fields remain exact; only `reconnect_generation` may advance beyond + /// the supplied floor. + pub async fn establish_responder_with_generation_floor_and_metrics( transport: T, policy: EndpointPolicy, credentials: HandshakeCredentials, + minimum_generation: u64, now: Instant, metrics: Arc, ) -> Result { + if minimum_generation == 0 { + return Err(SessionError::new(SessionErrorCode::GenerationMismatch)); + } let descriptor = transport.descriptor(); let metric_policy = policy.clone(); let timeout = Duration::from_millis(u64::from(policy.limits.handshake_deadline_ms)); let result = match tokio::time::timeout( timeout, - Self::establish_responder_inner(transport, policy, credentials, now), + Self::establish_responder_inner_with_generation_floor( + transport, + policy, + credentials, + minimum_generation, + now, + ), ) .await { @@ -432,8 +421,9 @@ impl SessionEngine { error = %error, purpose = metric_policy.purpose.as_str(), service = metric_policy.service.as_str(), + minimum_generation = minimum_generation, timeout_ms = timeout.as_millis() as u64, - "session handshake establishment failed (responder)" + "session handshake establishment failed (responder generation floor)" ); } result @@ -442,8 +432,9 @@ impl SessionEngine { tracing::warn!( purpose = metric_policy.purpose.as_str(), service = metric_policy.service.as_str(), + minimum_generation = minimum_generation, timeout_ms = timeout.as_millis() as u64, - "session handshake timed out (responder)" + "session handshake timed out (responder generation floor)" ); Err(SessionError::new(SessionErrorCode::HandshakeTimeout)) } From 9e1f1052a861416c02b6645dfa97a465942f755e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:34:40 -0700 Subject: [PATCH 319/726] d2b-provider-guest-azure-container-apps: keep AcaProviderConfig fields behind accessors --- .../src/controller.rs | 6 +- .../src/effects.rs | 81 ++++++++++++++++--- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs index ae69ac9f7..6e244b1fb 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs @@ -952,13 +952,13 @@ where pub fn controller(&self, binding: AcaResourceBinding) -> AcaController { AcaController::new( binding, - self.config.defaults.clone(), + self.config.defaults().clone(), Arc::clone(&self.control), Arc::clone(&self.leases), ) .with_provider_settings( - self.config.network_ref.clone(), - self.config.sandbox_transport_alias.clone(), + self.config.network_ref().cloned(), + self.config.sandbox_transport_alias().clone(), ) } } diff --git a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs index 602237dcc..9d7d83225 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/effects.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/effects.rs @@ -5,8 +5,8 @@ use std::fmt; use async_trait::async_trait; use serde::{Deserialize, Deserializer, Serialize}; -pub use d2b_contracts_provider::v3::credential::{CredentialLeaseHandle, OpaqueAzureRef}; -pub use d2b_contracts_resource::v3::{ResourceRef, ResourceUid}; +use d2b_contracts_provider::v3::credential::{CredentialLeaseHandle, OpaqueAzureRef}; +use d2b_contracts_resource::v3::{ResourceRef, ResourceUid}; /// Maximum length of an ACA resource identifier. pub const MAX_ACA_RESOURCE_ID_LEN: usize = 60; @@ -471,27 +471,27 @@ impl fmt::Debug for AcaRuntimeConfig { /// Validated Provider configuration for the runtime-azure-container-apps provider. pub struct AcaProviderConfig { /// Reference to the Guest execution boundary this provider serves. - pub gateway_execution_ref: ResourceRef, + gateway_execution_ref: ResourceRef, /// Azure tenant id. - pub tenant_id: OpaqueAzureRef, + tenant_id: OpaqueAzureRef, /// Azure client id. - pub client_id: OpaqueAzureRef, + client_id: OpaqueAzureRef, /// Azure subscription id. - pub subscription_id: OpaqueAzureRef, + subscription_id: OpaqueAzureRef, /// Reference to the credential used to acquire control-plane leases. - pub control_credential_ref: ResourceRef, + control_credential_ref: ResourceRef, /// Reference to the credential used to pull sandbox images, when configured. - pub pull_credential_ref: Option, + pull_credential_ref: Option, /// Configured container-apps environment id. - pub environment_id: AcaConfiguredImageId, + environment_id: AcaConfiguredImageId, /// Configured resource group id. - pub resource_group_id: AcaConfiguredImageId, + resource_group_id: AcaConfiguredImageId, /// Reference to the network the sandbox joins, when configured. - pub network_ref: Option, + network_ref: Option, /// Profile alias used for the sandbox transport. - pub sandbox_transport_alias: AcaProfileId, + sandbox_transport_alias: AcaProfileId, /// Runtime defaults applied to every controller created from this config. - pub defaults: AcaRuntimeConfig, + defaults: AcaRuntimeConfig, } impl AcaProviderConfig { @@ -552,6 +552,61 @@ impl AcaProviderConfig { ) } + /// Borrow the Guest execution boundary reference. + pub fn gateway_execution_ref(&self) -> &ResourceRef { + &self.gateway_execution_ref + } + + /// Borrow the Azure tenant id. + pub fn tenant_id(&self) -> &OpaqueAzureRef { + &self.tenant_id + } + + /// Borrow the Azure client id. + pub fn client_id(&self) -> &OpaqueAzureRef { + &self.client_id + } + + /// Borrow the Azure subscription id. + pub fn subscription_id(&self) -> &OpaqueAzureRef { + &self.subscription_id + } + + /// Borrow the control credential reference. + pub fn control_credential_ref(&self) -> &ResourceRef { + &self.control_credential_ref + } + + /// Borrow the pull credential reference, when configured. + pub fn pull_credential_ref(&self) -> Option<&ResourceRef> { + self.pull_credential_ref.as_ref() + } + + /// Borrow the container-apps environment id. + pub fn environment_id(&self) -> &AcaConfiguredImageId { + &self.environment_id + } + + /// Borrow the resource group id. + pub fn resource_group_id(&self) -> &AcaConfiguredImageId { + &self.resource_group_id + } + + /// Borrow the network reference, when configured. + pub fn network_ref(&self) -> Option<&ResourceRef> { + self.network_ref.as_ref() + } + + /// Borrow the sandbox transport profile alias. + pub fn sandbox_transport_alias(&self) -> &AcaProfileId { + &self.sandbox_transport_alias + } + + /// Borrow the runtime defaults applied to every controller created from this config. + pub fn defaults(&self) -> &AcaRuntimeConfig { + &self.defaults + } + fn validate_refs( gateway_execution_ref: &ResourceRef, control_credential_ref: &ResourceRef, From 49c4907946385dd7937296db89d2e77cdb954561 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:34:43 -0700 Subject: [PATCH 320/726] d2b-provider-guest-azure-container-apps: narrow crate-root re-exports to named items --- .../src/lib.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-guest-azure-container-apps/src/lib.rs b/packages/d2b-provider-guest-azure-container-apps/src/lib.rs index dc793a4a2..f02ce4bd7 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/lib.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/lib.rs @@ -10,7 +10,18 @@ pub use controller::{ AcaClock, AcaController, AcaControllerError, AcaPhase, AcaReconcileOutcome, AzureContainerAppsRuntimeProvider, ACA_GUEST_FINALIZER, ACA_REPAIR_INTERVAL_SECS, }; -pub use effects::*; +pub use effects::{ + AcaConfiguredDiskId, AcaConfiguredImageId, AcaControl, AcaControlContext, AcaControlError, + AcaControlErrorKind, AcaControlHealth, AcaCpuMillis, AcaCredentialLease, + AcaCredentialLeaseClient, AcaCredentialLeaseRequest, AcaCredentialPurpose, AcaDeleteOutcome, + AcaDesiredDiskImage, AcaDesiredSandbox, AcaDiskImageCandidates, AcaDiskImageId, + AcaDiskImageName, AcaDiskImageRecord, AcaDiskImageSource, AcaManagedIdentityBindingId, + AcaMemoryMib, AcaOperationId, AcaProfileId, AcaProviderConfig, AcaReadinessPolicy, + AcaResourceBinding, AcaRuntimeConfig, AcaSandboxCandidates, AcaSandboxId, AcaSandboxLifecycle, + AcaSandboxProfile, AcaSandboxRecord, AcaTypeError, AcaWorkloadQuery, MAX_ACA_CANDIDATES, + MAX_ACA_COMPLETED_OPERATIONS, MAX_ACA_PLAN_TTL_MS, MAX_ACA_READY_ATTEMPTS, + MAX_ACA_READY_INTERVAL_MS, MAX_ACA_RESOURCE_ID_LEN, +}; /// Stable Provider resource reference. pub const PROVIDER_REF: &str = "Provider/runtime-azure-container-apps"; From 65f98af06b8cc82c37ad972f4d3a5dcc294a2079 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:28:50 -0700 Subject: [PATCH 321/726] d2b: narrow doctor and host validate surfaces to the crate --- packages/d2b/src/doctor.rs | 12 ++++++------ packages/d2b/src/host_validate.rs | 24 ++++++++++++------------ packages/d2b/src/lib.rs | 2 +- packages/d2b/tests/host_validate_verb.rs | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/d2b/src/doctor.rs b/packages/d2b/src/doctor.rs index 550faf44e..ebecf7e4f 100644 --- a/packages/d2b/src/doctor.rs +++ b/packages/d2b/src/doctor.rs @@ -59,7 +59,7 @@ const PROBE_TIMEOUT: Duration = Duration::from_millis(750); /// Stable per-check severity for `d2b host doctor` output. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] -pub enum DoctorStatus { +pub(crate) enum DoctorStatus { Pass, Warn, Fail, @@ -77,7 +77,7 @@ impl DoctorStatus { /// One row in the doctor's `checks[]` array. #[derive(Debug, Clone)] -pub struct DoctorCheck { +pub(crate) struct DoctorCheck { /// Stable kebab-case identifier (e.g. `broker-ready`). pub name: &'static str, pub status: DoctorStatus, @@ -89,7 +89,7 @@ pub struct DoctorCheck { #[derive(Debug, Clone, Default)] /// Ordered check list produced by one doctor run. -pub struct DoctorReport { +pub(crate) struct DoctorReport { pub checks: Vec, } @@ -162,7 +162,7 @@ impl DoctorReport { } /// Run every doctor probe against one CLI context and aggregate the results. -pub fn run_doctor(context: &CliContext) -> DoctorReport { +pub(crate) fn run_doctor(context: &CliContext) -> DoctorReport { let mut report = DoctorReport::default(); check_broker_socket(context, &mut report); check_daemon_socket(context, &mut report); @@ -1694,7 +1694,7 @@ fn run_sysctl_n(key: &str) -> Result { // --------------------------------------------------------------- /// Render the doctor report as the structured JSON doctor output. -pub fn render_summary(report: &DoctorReport) -> Value { +pub(crate) fn render_summary(report: &DoctorReport) -> Value { let checks: Vec = report .checks .iter() @@ -1744,7 +1744,7 @@ pub fn render_summary(report: &DoctorReport) -> Value { } /// Render the doctor report as human-readable terminal text. -pub fn render_human(report: &DoctorReport) -> String { +pub(crate) fn render_human(report: &DoctorReport) -> String { use std::fmt::Write as _; let mut out = String::new(); let _ = writeln!( diff --git a/packages/d2b/src/host_validate.rs b/packages/d2b/src/host_validate.rs index 3d1cd95a3..1b226b7bd 100644 --- a/packages/d2b/src/host_validate.rs +++ b/packages/d2b/src/host_validate.rs @@ -52,7 +52,7 @@ use serde_json::{Value, json}; /// Canonical location the default-switch auto-flip gate reads from. /// Mirrors `nixos-modules/options-daemon.nix:validationEvidenceDir`. -pub const DEFAULT_EVIDENCE_DIR: &str = "/var/lib/d2b/validated"; +pub(crate) const DEFAULT_EVIDENCE_DIR: &str = "/var/lib/d2b/validated"; /// One known readiness wave plus the per-wave Layer-2 validator scripts /// the operator is expected to have exercised before @@ -62,7 +62,7 @@ pub const DEFAULT_EVIDENCE_DIR: &str = "/var/lib/d2b/validated"; /// `readinessWaveSpecs` in `nixos-modules/options-daemon.nix` - /// `tests/host-validate-verb-eval.sh` enforces parity. #[derive(Debug, Clone, Copy)] -pub struct WaveSpec { +pub(crate) struct WaveSpec { /// Wave id, e.g. `"p1"` or `"w5Fu"`. Matches the file basename the /// readiness option consumes (`/var/lib/d2b/validated/.json`). pub wave: &'static str, @@ -76,7 +76,7 @@ pub struct WaveSpec { /// Canonical, deterministic wave order. Sequencing matches the /// natural rollout (`w*Fu` follow-ups → `p0`..`p7` phase work) so /// human readers can scan the report top-to-bottom. -pub const WAVE_CATALOG: &[WaveSpec] = &[ +pub(crate) const WAVE_CATALOG: &[WaveSpec] = &[ WaveSpec { wave: "w4Fu", summary: "Headless daemon + supervisor path (Ubuntu Tier-1 smoke).", @@ -179,7 +179,7 @@ pub const WAVE_CATALOG: &[WaveSpec] = &[ /// Per-wave status reported by both dry-run and apply modes. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] -pub enum WaveStatus { +pub(crate) enum WaveStatus { /// Every declared validator script is present on disk. Ready, /// At least one declared validator script is missing. @@ -212,7 +212,7 @@ impl WaveStatus { } #[derive(Debug, Clone)] -pub struct WaveReport { +pub(crate) struct WaveReport { pub wave: &'static str, pub summary: &'static str, pub status: WaveStatus, @@ -227,7 +227,7 @@ pub struct WaveReport { #[derive(Debug, Clone)] /// Complete result of one `host validate` run, as per-wave evidence rows. -pub struct ValidateReport { +pub(crate) struct ValidateReport { pub mode: ValidateMode, pub evidence_dir: PathBuf, pub scripts_dir: PathBuf, @@ -236,7 +236,7 @@ pub struct ValidateReport { #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// The mutation mode of a `host validate` run. -pub enum ValidateMode { +pub(crate) enum ValidateMode { DryRun, Apply, } @@ -253,7 +253,7 @@ impl ValidateMode { /// Inputs to a `host validate` invocation. All paths are absolute or /// resolved by `run_host_validate` against the process cwd. #[derive(Debug, Clone)] -pub struct ValidateRequest { +pub(crate) struct ValidateRequest { pub mode: ValidateMode, /// Where per-wave evidence records are written /// (`.json`). Defaults to `DEFAULT_EVIDENCE_DIR`. @@ -312,7 +312,7 @@ fn resolve_default_scripts_dir() -> PathBuf { /// Top-level entry point invoked from `cmd_host_validate` in /// `lib.rs`. -pub fn run_host_validate(req: &ValidateRequest) -> ValidateReport { +pub(crate) fn run_host_validate(req: &ValidateRequest) -> ValidateReport { let mut waves = Vec::with_capacity(WAVE_CATALOG.len()); for spec in WAVE_CATALOG { if let Some(only) = &req.only_wave @@ -536,7 +536,7 @@ fn read_hostname() -> String { // Renderers // --------------------------------------------------------------- -pub fn render_summary(report: &ValidateReport) -> Value { +pub(crate) fn render_summary(report: &ValidateReport) -> Value { let waves: Vec = report .waves .iter() @@ -570,7 +570,7 @@ pub fn render_summary(report: &ValidateReport) -> Value { }) } -pub fn render_human(report: &ValidateReport) -> String { +pub(crate) fn render_human(report: &ValidateReport) -> String { use std::fmt::Write as _; let mut out = String::new(); let counts = tally(&report.waves); @@ -625,7 +625,7 @@ fn tally(waves: &[WaveReport]) -> serde_json::Map { } /// Derive the process exit code from the validation report statuses. -pub fn exit_code(report: &ValidateReport) -> i32 { +pub(crate) fn exit_code(report: &ValidateReport) -> i32 { // Apply mode: any write-failure is exit 1. // Any wave still `Missing` after apply is exit 78 (operator must // re-run after running the per-wave validator). diff --git a/packages/d2b/src/lib.rs b/packages/d2b/src/lib.rs index 629cc2f5d..619e4b0fa 100644 --- a/packages/d2b/src/lib.rs +++ b/packages/d2b/src/lib.rs @@ -41,7 +41,7 @@ mod zone_support_bundle; pub(crate) const MAX_FRAME_BYTES: usize = d2b_contracts::MAX_FRAME_SIZE; /// Exit code for api-ready timeout in strict mode. -pub const EXIT_API_TIMEOUT: i32 = 33; +pub(crate) const EXIT_API_TIMEOUT: i32 = 33; #[derive(Debug)] pub(crate) struct CliFailure { diff --git a/packages/d2b/tests/host_validate_verb.rs b/packages/d2b/tests/host_validate_verb.rs index fac7382f3..ad110da50 100644 --- a/packages/d2b/tests/host_validate_verb.rs +++ b/packages/d2b/tests/host_validate_verb.rs @@ -100,7 +100,7 @@ fn repo_root() -> PathBuf { fn wave_catalog_section() -> String { let source = include_str!("../src/host_validate.rs"); let start = source - .find("pub const WAVE_CATALOG") + .find("pub(crate) const WAVE_CATALOG") .expect("WAVE_CATALOG declaration is present"); let tail = &source[start..]; let end = tail From 8af1a183380fbbadb626641f352f022942c48fe3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:35:14 -0700 Subject: [PATCH 322/726] d2b-provider-credential-entra: drop unused pub entrypoint and owner surface --- .../d2b-provider-credential-entra/src/lib.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/packages/d2b-provider-credential-entra/src/lib.rs b/packages/d2b-provider-credential-entra/src/lib.rs index fe2d77351..62e80ec5f 100644 --- a/packages/d2b-provider-credential-entra/src/lib.rs +++ b/packages/d2b-provider-credential-entra/src/lib.rs @@ -109,11 +109,6 @@ pub fn run_from_fd10() -> i32 { ) } -/// Return the supervised controller process status. -pub fn controller_binary_entrypoint() -> i32 { - run_from_fd10() -} - fn runtime_provider( route: &AuthenticatedSessionRouteBinding, metadata: &ProviderSessionMetadata, @@ -451,13 +446,6 @@ fn entra_inspection( pub type EntraFuture<'a, T> = Pin> + Send + 'a>>; -/// Exact-consumer ownership policy. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum EntraCredentialOwner { - /// Only the configured consumer may be admitted. - ExactConsumer, -} - /// Closed client state. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EntraClientState { @@ -978,11 +966,6 @@ pub struct EntraCredentialProvider { } impl EntraCredentialProvider { - /// Return exact-consumer ownership. - pub const fn owner(&self) -> EntraCredentialOwner { - EntraCredentialOwner::ExactConsumer - } - /// Borrow the exact consumer required at authenticated admission. pub const fn consumer_ref(&self) -> &ResourceRef { &self.consumer_ref From f98ad4f8221de53c9068ebee10118708daadb9d9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:35:17 -0700 Subject: [PATCH 323/726] d2b: carry ZoneId invariant in the CLI context --- packages/d2b/src/context.rs | 48 ++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/packages/d2b/src/context.rs b/packages/d2b/src/context.rs index b07f9c019..838b10dc1 100644 --- a/packages/d2b/src/context.rs +++ b/packages/d2b/src/context.rs @@ -710,7 +710,7 @@ impl std::fmt::Debug for ContextBackend { /// The selected Zone and its authenticated-session request facade. pub(crate) struct ZoneContext { - zone_name: String, + zone_name: ZoneId, explicit_zone: bool, socket_path: PathBuf, zone_path: d2b_contracts_zone_session::v3::zone_routing::ZonePath, @@ -721,7 +721,7 @@ impl std::fmt::Debug for ZoneContext { fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter .debug_struct("ZoneContext") - .field("zone_name", &self.zone_name) + .field("zone_name", &self.zone_name.as_str()) .field("explicit_zone", &self.explicit_zone) .field("backend", &self.backend) .finish() @@ -733,7 +733,10 @@ impl ZoneContext { let socket_path = env::var_os("D2B_PUBLIC_SOCKET") .map(PathBuf::from) .unwrap_or_else(|| PathBuf::from("/run/d2b/public.sock")); - Self::from_socket("local-root".to_owned(), socket_path) + Self::from_socket( + ZoneId::parse("local-root").expect("local-root is a valid Zone name"), + socket_path, + ) } pub(crate) fn local_only_with_explicit_zone(explicit_zone: bool) -> Self { @@ -744,12 +747,12 @@ impl ZoneContext { /// Select the root public listener and an optional Zone routing target. pub(crate) fn discover(zone_arg: Option<&str>) -> Result { - let requested_zone = zone_arg +let requested_zone = zone_arg .map(str::to_owned) .or_else(|| env::var("D2B_ZONE").ok().filter(|value| !value.is_empty())); let explicit_zone = requested_zone.is_some(); - let zone_name = requested_zone.as_deref().unwrap_or("local-root").to_owned(); - validate_zone_name(&zone_name)?; + let zone_name = ZoneId::parse(requested_zone.as_deref().unwrap_or("local-root")) + .map_err(|_| CliFailure::new(2, "ref-invalid: invalid Zone name"))?; let direct_override = env::var_os("D2B_PUBLIC_SOCKET").is_some(); let socket_path = env::var_os("D2B_PUBLIC_SOCKET") @@ -759,14 +762,11 @@ impl ZoneContext { return Err(CliFailure::new(1, "zone-unavailable")); } - let selected_zone = requested_zone.unwrap_or_else(|| "local-root".to_owned()); - validate_zone_name(&selected_zone)?; - - let zone_path = zone_path(&selected_zone) + let zone_path = zone_path(zone_name.as_str()) .map_err(|_| CliFailure::new(2, "ref-invalid: invalid Zone name"))?; - let backend = canonical_backend(&selected_zone, &socket_path)?; + let backend = canonical_backend(zone_name.as_str(), &socket_path)?; Ok(Self { - zone_name: selected_zone, + zone_name, explicit_zone, socket_path, zone_path, @@ -781,12 +781,12 @@ impl ZoneContext { socket_path: impl Into, session_client: Arc, ) -> Result { - let zone_name = zone_name.into(); - validate_zone_name(&zone_name)?; +let zone_name = ZoneId::parse(zone_name) + .map_err(|_| CliFailure::new(2, "ref-invalid: invalid Zone name"))?; let socket_path = socket_path.into(); - let zone_path = zone_path(&zone_name) + let zone_path = zone_path(zone_name.as_str()) .map_err(|_| CliFailure::new(2, "ref-invalid: invalid Zone name"))?; - let mut backend = canonical_backend(&zone_name, &socket_path)?; + let mut backend = canonical_backend(zone_name.as_str(), &socket_path)?; backend.injected = Some(session_client); Ok(Self { zone_name, @@ -797,9 +797,9 @@ impl ZoneContext { }) } - fn from_socket(zone_name: String, socket_path: PathBuf) -> Self { - let zone_path = zone_path(&zone_name).expect("validated local Zone name"); - let backend = canonical_backend(&zone_name, &socket_path) + fn from_socket(zone_name: ZoneId, socket_path: PathBuf) -> Self { + let zone_path = zone_path(zone_name.as_str()).expect("validated local Zone name"); + let backend = canonical_backend(zone_name.as_str(), &socket_path) .expect("validated local Zone socket backend"); Self { zone_name, @@ -811,7 +811,7 @@ impl ZoneContext { } pub(crate) fn zone_name(&self) -> &str { - &self.zone_name + self.zone_name.as_str() } pub(crate) const fn has_explicit_zone(&self) -> bool { @@ -819,7 +819,7 @@ impl ZoneContext { } pub(crate) fn zone_ref(&self) -> String { - format!("Zone/{}", self.zone_name) + format!("Zone/{}", self.zone_name.as_str()) } pub(crate) fn public_socket_path(&self) -> &Path { @@ -2749,12 +2749,6 @@ pub(crate) fn bounded_message(message: &str) -> String { bounded } -fn validate_zone_name(value: &str) -> Result<(), CliFailure> { - ZoneId::parse(value.to_owned()) - .map(|_| ()) - .map_err(|_| CliFailure::new(2, "ref-invalid: invalid Zone name")) -} - fn parse_duration(value: &str) -> Result { let (number, suffix) = value.trim().split_at( value From dbec5dde7455159cc959083b7c4d8c8b38cfc980 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:36:30 -0700 Subject: [PATCH 324/726] credential-managed-identity: drop duplicate in_zone constructor --- .../src/lib.rs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/packages/d2b-provider-credential-managed-identity/src/lib.rs b/packages/d2b-provider-credential-managed-identity/src/lib.rs index b41acbd26..806a06760 100644 --- a/packages/d2b-provider-credential-managed-identity/src/lib.rs +++ b/packages/d2b-provider-credential-managed-identity/src/lib.rs @@ -625,15 +625,6 @@ impl ManagedIdentityPlacement { }) } - /// Validate machine placement and bind it to one Zone. - pub fn in_zone( - binding: PlacementBinding, - execution_ref: ResourceRef, - zone_ref: ResourceRef, - ) -> Result { - Self::new(binding, execution_ref, zone_ref) - } - /// Return the placement binding. pub const fn binding(&self) -> PlacementBinding { self.binding @@ -1276,20 +1267,21 @@ impl ManagedIdentityCredentialProvider { )); } }; - Ok(leases - .iter() - .flat_map(|(credential_ref, records)| { - records.iter().map(|record| ManagedIdentityLeaseCheckpoint { + let mut checkpoints = Vec::new(); + for (credential_ref, records) in leases.iter() { + for record in records { + checkpoints.push(ManagedIdentityLeaseCheckpoint { credential_ref: ResourceRef::parse(credential_ref) - .expect("lease map keys are validated Credential refs"), + .map_err(|_| invariant())?, idempotency_key: record.idempotency_key.clone(), metadata: record.metadata.clone(), authenticated_subject: record.authenticated_subject.clone(), session_expires_at_unix_ms: record.session_expires_at_unix_ms, cleanup_only: record.cleanup_only, - }) - }) - .collect()) + }); + } + } + Ok(checkpoints) } /// Restore bounded lease metadata after a Provider restart. From a37c1e0cf9cb2ea4b81bbc9832ee0002bb469af7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:36:31 -0700 Subject: [PATCH 325/726] d2b-process-conformance: drop unconditional cgroup-kill flag --- packages/d2b-process-conformance/src/sandbox.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/d2b-process-conformance/src/sandbox.rs b/packages/d2b-process-conformance/src/sandbox.rs index e04ad711e..73f8f072f 100644 --- a/packages/d2b-process-conformance/src/sandbox.rs +++ b/packages/d2b-process-conformance/src/sandbox.rs @@ -15,7 +15,6 @@ use crate::{ConfigurationDigest, ProcessConformanceError, identity::WaitReapOwne pub struct CompiledSandbox { digest: ConfigurationDigest, domain: ExecutionDomain, - requires_cgroup_kill: bool, } /// The compiled semantic plan retained by a launch ticket so the privileged @@ -56,11 +55,6 @@ impl CompiledSandbox { pub const fn domain(&self) -> ExecutionDomain { self.domain } - - /// Whether intentional teardown needs the cgroup.kill proof. - pub const fn requires_cgroup_kill(&self) -> bool { - self.requires_cgroup_kill - } } /// The provider-neutral semantic sandbox compiler. @@ -101,7 +95,6 @@ impl SandboxCompiler { Ok(CompiledSandbox { digest: ConfigurationDigest::from_bytes(digest), domain, - requires_cgroup_kill: true, }) } From bf9832779405b782ac1265a9f7be6d6e7711f7ac Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:36:37 -0700 Subject: [PATCH 326/726] d2b-process-conformance: bind binding-owner guard with if-let chain --- packages/d2b-process-conformance/src/launch_identity.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/d2b-process-conformance/src/launch_identity.rs b/packages/d2b-process-conformance/src/launch_identity.rs index 1594c25e7..72ffd44e3 100644 --- a/packages/d2b-process-conformance/src/launch_identity.rs +++ b/packages/d2b-process-conformance/src/launch_identity.rs @@ -149,16 +149,13 @@ impl LaunchIdentity { owner_uid: owner_uid.as_str().to_owned(), }); } - if owner_ref + if let Some(owner) = owner_ref .as_ref() - .is_some_and(|owner| owner.resource_type().as_str() == "VolumeBinding") + .filter(|owner| owner.resource_type().as_str() == "VolumeBinding") && target_ref.is_none() { return Err(LaunchIdentityError::MissingTargetRef { - owner_ref: owner_ref - .as_ref() - .expect("binding owner is present") - .to_canonical_string(), + owner_ref: owner.to_canonical_string(), }); } if !valid_identity_name(process_name) { From cc01388e6a36a70f557a92bd8f8009fd9afda5d0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:36:37 -0700 Subject: [PATCH 327/726] d2b-provider-guest-qemu-media: hoist guest context onto reconcile and finalize spans --- .../src/controller/reconcile.rs | 48 +------------------ 1 file changed, 2 insertions(+), 46 deletions(-) diff --git a/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs b/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs index dea7a6ecd..6a6f969b5 100644 --- a/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs +++ b/packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs @@ -341,6 +341,7 @@ impl QemuMediaController { /// Returns [`QemuMediaError::InvalidState`] when the controller is not /// reconcilable, and the dependency, process identity, and QMP readiness /// errors the phases surface. + #[tracing::instrument(skip(self, effect), fields(resource = %self.guest_ref, provider = "runtime-qemu-media"))] pub fn reconcile( &mut self, dependencies: &QemuMediaDependencies, @@ -356,8 +357,6 @@ impl QemuMediaController { } let Some(device) = dependencies.device.as_ref() else { tracing::debug!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "reconcile deferred: Device dependency not observed yet" ); self.phase = QemuMediaPhase::Pending; @@ -369,8 +368,6 @@ impl QemuMediaController { || (self.settings.display_window && !dependencies.display_ready) { tracing::debug!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", network_ready = dependencies.network_ready, media_ready = dependencies.media_ready, runtime_volume_ready = dependencies.runtime_volume_ready, @@ -384,8 +381,6 @@ impl QemuMediaController { DeviceAdmission::validate(&self.guest_ref, device, expected_process, MEDIA_CONTRACT_ID) .map_err(|error| { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "device admission rejected for guest" ); @@ -398,8 +393,6 @@ impl QemuMediaController { let observed = effect.observe().inspect_err(|error| { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "process observation effect failed during reconcile" ); @@ -408,8 +401,6 @@ impl QemuMediaController { Some(candidate) => { let Some(expected) = self.expected_identity.as_ref() else { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "adoption refused: observed process without durable expected identity" ); self.phase = QemuMediaPhase::Degraded; @@ -417,8 +408,6 @@ impl QemuMediaController { }; if verify_identity(expected, &candidate) != AdoptionOutcome::Adopted { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "adoption refused: observed process identity does not match expected identity" ); self.phase = QemuMediaPhase::Degraded; @@ -428,8 +417,6 @@ impl QemuMediaController { if !self.pidfd_opened { effect.open_pidfd(&candidate).inspect_err(|error| { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "pidfd open failed for adopted process" ); @@ -441,8 +428,6 @@ impl QemuMediaController { None => { if self.expected_identity.is_some() { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "adoption refused: expected process vanished before identity verification" ); self.phase = QemuMediaPhase::Failed; @@ -456,8 +441,6 @@ impl QemuMediaController { )?; let candidate = effect.launch(&ticket).inspect_err(|error| { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "process launch failed for guest" ); @@ -465,15 +448,11 @@ impl QemuMediaController { if !candidate.matches_process_token(expected_process) { if let Err(stop_error) = effect.stop(&candidate) { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = stop_error.code(), "stop failed while quarantining launched process with wrong template token" ); } tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "launched process rejected: process template token mismatch" ); self.phase = QemuMediaPhase::Failed; @@ -482,15 +461,11 @@ impl QemuMediaController { if let Err(error) = effect.open_pidfd(&candidate) { if let Err(stop_error) = effect.stop(&candidate) { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = stop_error.code(), "stop failed while cleaning up process after pidfd failure" ); } tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "pidfd open failed for freshly launched process" ); @@ -509,8 +484,6 @@ impl QemuMediaController { && dependencies.qmp_elapsed_seconds >= self.config.qmp_ready_timeout_seconds { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", elapsed_seconds = dependencies.qmp_elapsed_seconds, "QMP readiness timeout elapsed; stopping guest process" ); @@ -526,8 +499,6 @@ impl QemuMediaController { } } else if let Err(error) = stopped { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "process stop failed after QMP readiness timeout" ); @@ -549,8 +520,6 @@ impl QemuMediaController { match qmp_status { QmpVmStatus::Stopped => { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "guest QMP status is Stopped; marking generation failed" ); self.phase = QemuMediaPhase::Failed; @@ -559,8 +528,6 @@ impl QemuMediaController { QmpVmStatus::Paused if !self.settings.pause_at_boot => { effect.continue_guest().inspect_err(|error| { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "failed to resume unexpectedly paused guest" ); @@ -571,8 +538,6 @@ impl QemuMediaController { } QmpVmStatus::Running if self.settings.pause_at_boot && !self.initial_pause_observed => { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "guest running before boot pause observed; QMP readiness rejected" ); self.phase = QemuMediaPhase::Degraded; @@ -590,6 +555,7 @@ impl QemuMediaController { } /// Finalize QMP/media effects, then stop the Process and release authority. + #[tracing::instrument(skip(self, effect), fields(resource = %self.guest_ref, provider = "runtime-qemu-media"))] pub fn finalize(&mut self, effect: &mut E) -> Result<(), QemuMediaError> { if !self.finalizer_installed { return Ok(()); @@ -601,16 +567,12 @@ impl QemuMediaController { } let observed = effect.observe().inspect_err(|error| { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "process observation effect failed during finalization" ); })?; if self.expected_identity.is_none() && observed.is_some() { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "finalization refused: unexpected process without durable expected identity" ); self.phase = QemuMediaPhase::Degraded; @@ -620,8 +582,6 @@ impl QemuMediaController { if let Some(candidate) = observed { if verify_identity(identity, &candidate) != AdoptionOutcome::Adopted { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "finalization refused: observed process identity does not match expected identity" ); self.phase = QemuMediaPhase::Degraded; @@ -634,8 +594,6 @@ impl QemuMediaController { if !self.process_stopped { effect.stop(identity).inspect_err(|error| { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", code = error.code(), "process stop failed during finalization" ); @@ -644,8 +602,6 @@ impl QemuMediaController { } if effect.observe()?.is_some() { tracing::warn!( - resource = %self.guest_ref, - provider = "runtime-qemu-media", "finalization incomplete: process still observed after stop" ); self.phase = QemuMediaPhase::Degraded; From 7f6b1e4da2a7c0dc9183312cd2260004bbb044d4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:36:42 -0700 Subject: [PATCH 328/726] d2b-process-conformance: validate terminal outcomes at the wire boundary --- .../d2b-process-conformance/src/terminal.rs | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/packages/d2b-process-conformance/src/terminal.rs b/packages/d2b-process-conformance/src/terminal.rs index ba4c5e4a5..0d37db5cd 100644 --- a/packages/d2b-process-conformance/src/terminal.rs +++ b/packages/d2b-process-conformance/src/terminal.rs @@ -37,7 +37,7 @@ pub enum ExitClass { /// A bounded terminal outcome detached from any process locator. #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", try_from = "RawProcessOutcome")] pub struct ProcessOutcome { /// The stable terminal classification. pub exit_class: ExitClass, @@ -111,6 +111,33 @@ impl ProcessOutcome { } } +/// Raw wire shape for [`ProcessOutcome`], validated on read. +#[derive(serde::Deserialize)] +#[serde(rename_all = "camelCase")] +struct RawProcessOutcome { + exit_class: ExitClass, + exit_code: Option, +} + +impl TryFrom for ProcessOutcome { + type Error = ProcessConformanceError; + + fn try_from(raw: RawProcessOutcome) -> Result { + match (raw.exit_class, raw.exit_code) { + (ExitClass::CleanExit, Some(code)) if (0..=255).contains(&code) => Ok(Self { + exit_class: ExitClass::CleanExit, + exit_code: Some(code), + }), + (ExitClass::CleanExit, _) => Err(ProcessConformanceError::InvalidTerminalResult), + (_, None) => Ok(Self { + exit_class: raw.exit_class, + exit_code: None, + }), + (_, Some(_)) => Err(ProcessConformanceError::InvalidTerminalResult), + } + } +} + /// Evidence that the broker parent performed the terminal wait/reap. /// /// The readable-pidfd form is intentionally not representable. A test or @@ -227,9 +254,7 @@ impl BrokerTerminalResult { /// /// Returns [`ProcessConformanceError::TerminalEvidenceMismatch`] when /// the evidence is not reaped or the ticket does not match the - /// process, operation, provider, or expected identity, and - /// [`ProcessConformanceError::InvalidTerminalResult`] when the outcome - /// itself is invalid. + /// process, operation, provider, or expected identity. pub fn relay(self, ticket: &LaunchTicket) -> Result { if !self.evidence.is_reaped() || ticket.process_uid() != &self.process_uid @@ -241,7 +266,6 @@ impl BrokerTerminalResult { { return Err(ProcessConformanceError::TerminalEvidenceMismatch); } - self.outcome.validate()?; Ok(self.outcome) } } @@ -321,4 +345,23 @@ mod tests { Err(ProcessConformanceError::InvalidTerminalResult) ); } + + #[test] + fn process_outcome_wire_reads_validate_at_the_boundary() { + let exited = serde_json::to_string(&ProcessOutcome::exited(7).unwrap()).unwrap(); + assert_eq!( + serde_json::from_str::(&exited).unwrap(), + ProcessOutcome::exited(7).unwrap() + ); + let signaled = serde_json::to_string(&ProcessOutcome::signaled()).unwrap(); + assert_eq!( + serde_json::from_str::(&signaled).unwrap(), + ProcessOutcome::signaled() + ); + + let crash_with_code = serde_json::json!({"exitClass": "crash", "exitCode": 300}); + assert!(serde_json::from_str::(&crash_with_code.to_string()).is_err()); + let clean_without_code = serde_json::json!({"exitClass": "clean-exit"}); + assert!(serde_json::from_str::(&clean_without_code.to_string()).is_err()); + } } From cd8838c0353574dd0ed13f594b3c04d864981ad5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:36:54 -0700 Subject: [PATCH 329/726] credential-managed-identity: seal teardown plan fields behind accessors --- .../src/controller.rs | 24 ++++++++++-- .../tests/binding.rs | 39 +++++++------------ .../tests/topology.rs | 18 ++++----- 3 files changed, 44 insertions(+), 37 deletions(-) diff --git a/packages/d2b-provider-credential-managed-identity/src/controller.rs b/packages/d2b-provider-credential-managed-identity/src/controller.rs index 3ad889725..abfed9917 100644 --- a/packages/d2b-provider-credential-managed-identity/src/controller.rs +++ b/packages/d2b-provider-credential-managed-identity/src/controller.rs @@ -81,14 +81,32 @@ impl core::fmt::Debug for AgentProcessSpec { } /// Ordered teardown effects owned by the controller. +/// +/// The fields are private: only [`ManagedIdentityController::teardown_plan`] +/// constructs a plan, so the emitted combinations are the only +/// representable ones. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ManagedIdentityTeardownPlan { + stop_agent: bool, + delete_agent: bool, + clear_provider_revoke: bool, +} + +impl ManagedIdentityTeardownPlan { /// Whether the agent must first drain and stop. - pub stop_agent: bool, + pub const fn stop_agent(self) -> bool { + self.stop_agent + } + /// Whether the controller may delete the agent Process. - pub delete_agent: bool, + pub const fn delete_agent(self) -> bool { + self.delete_agent + } + /// Whether revocation and Process deletion permit finalizer release. - pub clear_provider_revoke: bool, + pub const fn clear_provider_revoke(self) -> bool { + self.clear_provider_revoke + } } /// Common status plus closed client state. diff --git a/packages/d2b-provider-credential-managed-identity/tests/binding.rs b/packages/d2b-provider-credential-managed-identity/tests/binding.rs index 162c2f185..9fc901942 100644 --- a/packages/d2b-provider-credential-managed-identity/tests/binding.rs +++ b/packages/d2b-provider-credential-managed-identity/tests/binding.rs @@ -14,7 +14,6 @@ use d2b_contracts_resource::v3::identity::Locality; use d2b_provider_credential_managed_identity::{ ManagedIdentityCredentialProvider, ManagedIdentityCredentialProviderFactory, PROVIDER_KIND, PROVIDER_REVOKE_FINALIZER, ManagedIdentityController, - ManagedIdentityTeardownPlan, }; use common::{ @@ -1210,30 +1209,20 @@ fn finalization_revokes_only_the_callers_owned_handles() { #[test] fn controller_cleanup_keeps_the_finalizer_until_agent_deletion_is_observed() { - assert_eq!( - ManagedIdentityController::teardown_plan(true, false, false), - ManagedIdentityTeardownPlan { - stop_agent: true, - delete_agent: false, - clear_provider_revoke: false, - } - ); - assert_eq!( - ManagedIdentityController::teardown_plan(false, true, false), - ManagedIdentityTeardownPlan { - stop_agent: false, - delete_agent: true, - clear_provider_revoke: false, - } - ); - assert_eq!( - ManagedIdentityController::teardown_plan(false, true, true), - ManagedIdentityTeardownPlan { - stop_agent: false, - delete_agent: false, - clear_provider_revoke: true, - } - ); + let stop = ManagedIdentityController::teardown_plan(true, false, false); + assert!(stop.stop_agent()); + assert!(!stop.delete_agent()); + assert!(!stop.clear_provider_revoke()); + + let delete = ManagedIdentityController::teardown_plan(false, true, false); + assert!(!delete.stop_agent()); + assert!(delete.delete_agent()); + assert!(!delete.clear_provider_revoke()); + + let clear = ManagedIdentityController::teardown_plan(false, true, true); + assert!(!clear.stop_agent()); + assert!(!clear.delete_agent()); + assert!(clear.clear_provider_revoke()); assert_eq!(PROVIDER_KIND.as_str(), "credential-managed-identity"); assert_eq!( PROVIDER_REVOKE_FINALIZER, diff --git a/packages/d2b-provider-credential-managed-identity/tests/topology.rs b/packages/d2b-provider-credential-managed-identity/tests/topology.rs index 2fa056f3e..7ba0052eb 100644 --- a/packages/d2b-provider-credential-managed-identity/tests/topology.rs +++ b/packages/d2b-provider-credential-managed-identity/tests/topology.rs @@ -79,19 +79,19 @@ fn live_methods_route_to_the_agent_and_stored_inspection_stays_secret_free() { #[test] fn teardown_releases_the_finalizer_only_after_revocation_and_process_deletion() { let stop = ManagedIdentityController::teardown_plan(true, false, false); - assert!(stop.stop_agent); - assert!(!stop.delete_agent); - assert!(!stop.clear_provider_revoke); + assert!(stop.stop_agent()); + assert!(!stop.delete_agent()); + assert!(!stop.clear_provider_revoke()); let delete = ManagedIdentityController::teardown_plan(false, true, false); - assert!(!delete.stop_agent); - assert!(delete.delete_agent); - assert!(!delete.clear_provider_revoke); + assert!(!delete.stop_agent()); + assert!(delete.delete_agent()); + assert!(!delete.clear_provider_revoke()); let clear = ManagedIdentityController::teardown_plan(false, true, true); - assert!(!clear.stop_agent); - assert!(!clear.delete_agent); - assert!(clear.clear_provider_revoke); + assert!(!clear.stop_agent()); + assert!(!clear.delete_agent()); + assert!(clear.clear_provider_revoke()); } #[test] From 4a72b96f6ef1aec09fa556a0a07262af69791866 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:37:33 -0700 Subject: [PATCH 330/726] d2b-process-conformance: derive CompiledDigests serialization --- .../d2b-process-conformance/src/status.rs | 15 ------------ .../d2b-process-conformance/src/ticket.rs | 23 ++++++++++++++++++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/packages/d2b-process-conformance/src/status.rs b/packages/d2b-process-conformance/src/status.rs index ec1e5e115..92ff53170 100644 --- a/packages/d2b-process-conformance/src/status.rs +++ b/packages/d2b-process-conformance/src/status.rs @@ -122,21 +122,6 @@ pub struct ProcessStatusReport { pub adoption: AdoptionCondition, } -impl Serialize for CompiledDigests { - fn serialize(&self, serializer: S) -> Result { - use serde::ser::SerializeStruct; - let mut state = serializer.serialize_struct("CompiledDigests", 7)?; - state.serialize_field("sandbox", &self.sandbox)?; - state.serialize_field("budget", &self.budget)?; - state.serialize_field("mounts", &self.mounts)?; - state.serialize_field("devices", &self.devices)?; - state.serialize_field("network", &self.network)?; - state.serialize_field("endpoints", &self.endpoints)?; - state.serialize_field("fdTable", &self.fd_table)?; - state.end() - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/packages/d2b-process-conformance/src/ticket.rs b/packages/d2b-process-conformance/src/ticket.rs index 569123c1a..a2a27c5c3 100644 --- a/packages/d2b-process-conformance/src/ticket.rs +++ b/packages/d2b-process-conformance/src/ticket.rs @@ -3,6 +3,8 @@ use std::collections::BTreeSet; use std::fmt; +use serde::Serialize; + use d2b_contracts_resource::v3::execution_policy::{BoundedToken, ExecutionDomain}; use d2b_contracts_resource::v3::identity::ReconnectGeneration; use d2b_contracts_resource::v3::{ @@ -102,7 +104,8 @@ pub fn runtime_scope_commitment( /// /// Every member is a digest of a plan the Provider never sees. The /// `fd_table` member digests the exact inherited FD table. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] +#[serde(rename_all = "camelCase")] pub struct CompiledDigests { /// Digest of the compiled sandbox plan. pub sandbox: ConfigurationDigest, @@ -1552,4 +1555,22 @@ mod tests { assert!(ticket.validate().is_ok()); assert_eq!(format!("{ticket:?}"), "LaunchTicket()"); } + + #[test] + fn compiled_digests_serialize_under_the_v3_camel_case_names() { + let digests = fixtures::compiled_digests(); + let value = serde_json::to_value(digests).unwrap(); + assert_eq!( + value, + serde_json::json!({ + "sandbox": ConfigurationDigest::from_bytes([1; 32]).to_hex(), + "budget": ConfigurationDigest::from_bytes([2; 32]).to_hex(), + "mounts": ConfigurationDigest::from_bytes([3; 32]).to_hex(), + "devices": ConfigurationDigest::from_bytes([4; 32]).to_hex(), + "network": ConfigurationDigest::from_bytes([5; 32]).to_hex(), + "endpoints": ConfigurationDigest::from_bytes([6; 32]).to_hex(), + "fdTable": ConfigurationDigest::from_bytes([7; 32]).to_hex(), + }) + ); + } } From a81199002f4929b1787387fc0eef85ad2fa991cc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:39:03 -0700 Subject: [PATCH 331/726] audit: fold the controller slice --- .../2026-09-24-rust-skills-audit/ledger.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 2544bbaf5..60a169a69 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -308,9 +308,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `role_binding.rs:179-182, role_binding.rs:149-162` | | | | `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | | | | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | -| `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:985-988` | | | +| `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | | `RS-0262` | `type` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | | | -| `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/ticket.rs:387, packages/d2b-process-conformance/src/t` | | | +| `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 81d0ff057 | packages/d2b-process-conformance/src/ticket.rs | Bundled zone_uid+runtime_scope into one private Option pairing; const-compatible match accessors keep the public API byte-identical. | | | `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, sr` | | | | `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199` | | | | `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:140, src/bin/d2b-clipd.rs:142` | | | @@ -397,14 +397,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0346` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109` | | | | `RS-0350` | `api` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/privileges.rs | PrivilegesJson::w1 renamed to from_const_rows(); both test call sites updated; census re-run: only test callers exist | | | `RS-0347` | `api` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_vm_start_intent and find_process_node narrowed to pub(crate) as stated; find_if_name_mapping_for_vm had ZERO callers anywhere (census re-run: only the definition), so pub(crate) tripped the de | | -| `RS-0340` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/binding_children.rs:173, packages/d2b-core-controller/src` | | | +| `RS-0340` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | fd2d8eb30 | packages/d2b-core-controller/src/binding_children.rs | Removed the uncalled observed_child_from_resource envelope adapter and its lib re-export; census: 0 callers anywhere. | | | `RS-0341` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/controller_assignment.rs:2707, packages/d2b-core-controll` | | | | `RS-0342` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/coordinator.rs:252, packages/d2b-core-controller/src/coor` | | | -| `RS-0343` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `authority.rs:80-128, authority.rs:167-211, authority.rs:258-335, authority.rs:1732` | | | +| `RS-0343` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied-variant | U3 | 7760f4d1a | packages/d2b-core-controller/src/authority.rs | Dropped the unused external physical-NIC admission/inventory/lease machinery (-1185 lines, 7 tests). Kept the DurableExternalNicClaim wires and ExternalNicRecoveryInventory + storage claim variant con | | | `RS-0344` | `api` | `d2b-core-controller` | low | actionable | leaf | | | | `owner_reconcile.rs:579, owner_reconcile.rs:600, owner_reconcile.rs:697, owner_reconcile.rs` | | | | `RS-0351` | `api` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/host_prep_dag.rs:85` | | | -| `RS-0355` | `api` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/lib.rs:52, packages/d2b-process-conformance/src/lib.r` | | | -| `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/process_provider.rs:6, packages/d2b-process-conforman` | | | +| `RS-0355` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 9ed591eb2 | packages/d2b-process-conformance/src/lib.rs | Dropped the unused BrokerExitClass alias from the terminal re-export; census: only hit was its own re-export. | | +| `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | dbac9940c | packages/d2b-process-conformance/src/process_provider.rs | Deleted the duplicate process_provider re-export module; census: 0 users of that path. | | | `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testi` | | | | `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/sandbox.rs:18, packages/d2b-process-conformance/src/s` | | | | `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation` | | | @@ -527,7 +527,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/site.rs | SiteJson::validate returns SiteValidationError::InvalidWaylandSocket enum with Display token; caller and tests updated | | | `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | | `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | manifest_parse_reason now matches serde_json::Error::classify() (Category::Data/Syntax/Eof/Io) instead of Display text; all 8 call sites updated to pass &error; slug change not wire-visible per census | | -| `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | | | | `authority.rs:412` | | | +| `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 96cc7e5bb | packages/d2b-core-controller/src/authority.rs | DuplicateConflict code arm rendered as kebab-case duplicate-conflict; in-crate assertion pinning the old spelling updated; census showed 0 hits outside authority.rs. | | | `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/launch_identity.rs:147` | | | | `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activa` | | | | `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/authority.rs:53-54, src/authority.rs:144-145` | | | @@ -608,7 +608,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | | `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | | | | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | | | | `RS-0557` | `serde` | `d2b-host` | low | actionable | family | | | | `packages/d2b-host/src/nftables.rs:229` | | | -| `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/status.rs:125, packages/d2b-process-conformance/src/t` | | | +| `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | | `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/terminal.rs:39, packages/d2b-process-conformance/src/` | | | | `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-` | | | | `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | | | | `packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/comm` | | | From 4e20f7674969632b7f435de778f9eebf84cd6ae2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:39:40 -0700 Subject: [PATCH 332/726] d2b-bus: keep the established-lane doc attached to its struct --- packages/d2b-bus/src/session/zone_link.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/d2b-bus/src/session/zone_link.rs b/packages/d2b-bus/src/session/zone_link.rs index 11d8313b2..c4c274305 100644 --- a/packages/d2b-bus/src/session/zone_link.rs +++ b/packages/d2b-bus/src/session/zone_link.rs @@ -108,23 +108,22 @@ const FENCE_REVOKED: u8 = 2; /// consumed the authenticated session that created it. Sharing the transport /// implementation shares no authority: the consumed session owner retains its /// liveness and single-owner authorization state. +pub struct ZoneLinkSession { + driver: Arc, + epoch: LinkEpoch, + established: Option, + fence: AtomicU8, +} + /// The sealed admission and liveness pair of one established driver lane. /// /// Both values are set together by [`ZoneLinkSession::establish_authenticated`] /// and are absent only on the test lane, so a half-set lane is unrepresentable. - struct EstablishedLane { admission: VerifiedRouteAdmission, liveness: d2b_session::SessionLiveness, } -pub struct ZoneLinkSession { - driver: Arc, - epoch: LinkEpoch, - established: Option, - fence: AtomicU8, -} - impl core::fmt::Debug for ZoneLinkSession { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { // The epoch is a link-local ordinal and is safe to show; the driver, From d91b738d801e6b42082496b16d12d67f2031663b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:39:58 -0700 Subject: [PATCH 333/726] d2b-bus: drop the shadowed session Cancellation re-export --- packages/d2b-bus/src/session/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/d2b-bus/src/session/mod.rs b/packages/d2b-bus/src/session/mod.rs index eca2fb248..40dad63cd 100644 --- a/packages/d2b-bus/src/session/mod.rs +++ b/packages/d2b-bus/src/session/mod.rs @@ -94,8 +94,6 @@ pub use d2b_session::{ AttachmentValidationError, BootstrapAdmission, BootstrapPsk, - // Cancellation and the request registry. - Cancellation, // The session drive loop. ComponentSessionDriver, DeadlineBudget, From 63d31a743b7d7d7fed16441c04ba927ac4a92a13 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:40:09 -0700 Subject: [PATCH 334/726] audit: fold the conformance slice --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 60a169a69..688b8545e 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -398,15 +398,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0350` | `api` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/privileges.rs | PrivilegesJson::w1 renamed to from_const_rows(); both test call sites updated; census re-run: only test callers exist | | | `RS-0347` | `api` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_vm_start_intent and find_process_node narrowed to pub(crate) as stated; find_if_name_mapping_for_vm had ZERO callers anywhere (census re-run: only the definition), so pub(crate) tripped the de | | | `RS-0340` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | fd2d8eb30 | packages/d2b-core-controller/src/binding_children.rs | Removed the uncalled observed_child_from_resource envelope adapter and its lib re-export; census: 0 callers anywhere. | | -| `RS-0341` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/controller_assignment.rs:2707, packages/d2b-core-controll` | | | -| `RS-0342` | `api` | `d2b-core-controller` | medium | actionable | leaf | | | | `packages/d2b-core-controller/src/coordinator.rs:252, packages/d2b-core-controller/src/coor` | | | +| `RS-0341` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | e95cfb6c5 | packages/d2b-core-controller/src/controller_assignment.rs | Deleted eight zero-caller pub methods (reserve_epoch_after, rebind_revision, record_child, remove_child, child_uids, validate_writer, observation_is_stale, target_for), the children field, MAX_ASSIGNE | | +| `RS-0342` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | 442b4cb31 | packages/d2b-core-controller/src/coordinator.rs | Deleted ten zero-caller pub methods (begin/finish_usbip_reconcile, set/clear_force_shutdown_generation, stage/commit/abort_configuration, commit/abort_configuration_ordinal, zone_count), the generatio | | | `RS-0343` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied-variant | U3 | 7760f4d1a | packages/d2b-core-controller/src/authority.rs | Dropped the unused external physical-NIC admission/inventory/lease machinery (-1185 lines, 7 tests). Kept the DurableExternalNicClaim wires and ExternalNicRecoveryInventory + storage claim variant con | | -| `RS-0344` | `api` | `d2b-core-controller` | low | actionable | leaf | | | | `owner_reconcile.rs:579, owner_reconcile.rs:600, owner_reconcile.rs:697, owner_reconcile.rs` | | | +| `RS-0344` | `api` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 4105103ab | packages/d2b-core-controller/src/owner_reconcile.rs | Deleted six zero-caller public alias accessors: OwnerReconcilePlan::create_order/batch, OwnerChildBatch::resource_refs, OwnerChildIdentity::resource_ref, TeardownPlan::refs/resources; kept canonical n | | | `RS-0351` | `api` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/host_prep_dag.rs:85` | | | | `RS-0355` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 9ed591eb2 | packages/d2b-process-conformance/src/lib.rs | Dropped the unused BrokerExitClass alias from the terminal re-export; census: only hit was its own re-export. | | | `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | dbac9940c | packages/d2b-process-conformance/src/process_provider.rs | Deleted the duplicate process_provider re-export module; census: 0 users of that path. | | | `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testi` | | | -| `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/sandbox.rs:18, packages/d2b-process-conformance/src/s` | | | +| `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | a37c1e0cf | packages/d2b-process-conformance/src/sandbox.rs | Deleted CompiledSandbox::requires_cgroup_kill field, its unconditional true initializer in compile(), and its public accessor; census: `requires_cgroup_kill` over packages/, nixos-modules/, tests/, do | | | `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation` | | | | `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:14, packages/d2b-provider-activat` | | | | `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/authority.rs:157-171, src/controller.rs:395-403` | | | @@ -528,7 +528,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | | `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | manifest_parse_reason now matches serde_json::Error::classify() (Category::Data/Syntax/Eof/Io) instead of Display text; all 8 call sites updated to pass &error; slug change not wire-visible per census | | | `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 96cc7e5bb | packages/d2b-core-controller/src/authority.rs | DuplicateConflict code arm rendered as kebab-case duplicate-conflict; in-crate assertion pinning the old spelling updated; census showed 0 hits outside authority.rs. | | -| `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/launch_identity.rs:147` | | | +| `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | bf9832779 | packages/d2b-process-conformance/src/launch_identity.rs | Replaced the is_some_and guard + unreachable .expect with an if-let chain binding owner via .filter(), deleting the panic site and using the bound owner for the error payload; behavior unchanged (same | | | `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activa` | | | | `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/authority.rs:53-54, src/authority.rs:144-145` | | | | `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/state.rs:114-123, src/controller.rs:155-160` | | | @@ -609,7 +609,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | | | | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | | | | `RS-0557` | `serde` | `d2b-host` | low | actionable | family | | | | `packages/d2b-host/src/nftables.rs:229` | | | | `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | -| `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | | | | `packages/d2b-process-conformance/src/terminal.rs:39, packages/d2b-process-conformance/src/` | | | +| `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | | `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-` | | | | `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | | | | `packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/comm` | | | | `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/` | | | From b845000ff6202d7a3a2d85e9ee3eea6244f24c5b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:40:12 -0700 Subject: [PATCH 335/726] d2b-provider-guest-qemu-media: drop the invalid default ProviderConfig --- .../src/config.rs | 19 ------------------- .../tests/config_schema_projection.rs | 11 ++++++++++- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/packages/d2b-provider-guest-qemu-media/src/config.rs b/packages/d2b-provider-guest-qemu-media/src/config.rs index ca1e4d7f1..4769a822c 100644 --- a/packages/d2b-provider-guest-qemu-media/src/config.rs +++ b/packages/d2b-provider-guest-qemu-media/src/config.rs @@ -84,25 +84,6 @@ impl<'de> Deserialize<'de> for ProviderConfig { } } -impl Default for ProviderConfig { - fn default() -> Self { - Self { - controller_execution_ref: ResourceRef::parse("Guest/invalid").expect("valid reference"), - qemu_binary_artifact_id: default_qemu_artifact(), - qmp_ready_timeout_seconds: DEFAULT_QMP_READY_TIMEOUT_SECONDS, - qmp_operation_timeout_seconds: DEFAULT_QMP_OPERATION_TIMEOUT_SECONDS, - paused_at_boot_default: true, - display_provider_ref: None, - network_provider_ref: ResourceRef::parse("Provider/network-local") - .expect("valid reference"), - volume_provider_ref: ResourceRef::parse("Provider/volume-local") - .expect("valid reference"), - runtime_tmpfs_quota_bytes: DEFAULT_RUNTIME_TMPFS_QUOTA_BYTES, - runtime_tmpfs_quota_inodes: DEFAULT_RUNTIME_TMPFS_QUOTA_INODES, - } - } -} - impl ProviderConfig { /// Construct a Provider configuration with defaults for bounded values. pub fn new( diff --git a/packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs b/packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs index 3ca346165..b22a5b085 100644 --- a/packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs +++ b/packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs @@ -1,8 +1,17 @@ +use d2b_contracts_resource::v3::ResourceRef; use d2b_provider_guest_qemu_media::{ProviderConfig, WorkerConfigProjection}; #[test] fn provider_config_requires_host_and_projects_controller_only() { - let config = ProviderConfig::default(); + let mut config = ProviderConfig::new( + "Host/host-system", + "qemu-system-x86-64", + "Provider/network-local", + "Provider/volume-local", + None, + ) + .unwrap(); + config.controller_execution_ref = ResourceRef::parse("Guest/dev-vm").unwrap(); assert!(config.validate().is_err()); let config = ProviderConfig::new( From cc06ec37d709a4e79727072670595751aba35af3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:41:18 -0700 Subject: [PATCH 336/726] d2b-resource-api: narrow manager backend helpers to crate visibility --- packages/d2b-resource-api/src/manager_backend.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index a678219fe..20d0fe21e 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -78,7 +78,7 @@ use crate::ResourceStoreBackend; /// carries `(epoch_seconds << 32) | sequence`, where `epoch_seconds = /// epoch_nanos / 1_000_000_000` and the sequence occupies the low 32 bits. /// Order-preserving within an epoch. -pub fn wire_revision(revision: RuntimeRevision) -> u64 { +pub(crate) fn wire_revision(revision: RuntimeRevision) -> u64 { (revision.epoch / 1_000_000_000) << 32 | (revision.sequence & 0xffff_ffff) } @@ -205,7 +205,7 @@ fn map_manager_error(failure: ResourceError) -> StoreError { /// The API caller subject (R28): API operations admit at the manager /// boundary under the exact subject the authorization evaluation captured, /// with API provenance. -pub fn api_subject(authorization: &AdmittedAuthorization) -> MutationSubject { +pub(crate) fn api_subject(authorization: &AdmittedAuthorization) -> MutationSubject { MutationSubject { principal: authorization.subject_ref.to_canonical_string(), origin: ResourceProvenance::Api, @@ -748,7 +748,7 @@ fn render_envelope( return envelope.canonical_bytes().map_err(|_| envelope_invalid()); } let authored: serde_json::Value = - serde_json::from_slice(metadata).unwrap_or(serde_json::Value::Null); + serde_json::from_slice(metadata).map_err(|_| envelope_invalid())?; let field = |name: &str, fallback: serde_json::Value| { authored .get(name) From 913f462f9cd52755a6c2da61c13914f68080b975 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:41:29 -0700 Subject: [PATCH 337/726] d2b: type the exec kill signal and endpoint class CLI vocabularies --- packages/d2b/src/endpoint.rs | 64 +++++++++++---------- packages/d2b/src/exec.rs | 43 ++++++++++---- packages/d2b/tests/cli_contract_coverage.rs | 2 +- 3 files changed, 66 insertions(+), 43 deletions(-) diff --git a/packages/d2b/src/endpoint.rs b/packages/d2b/src/endpoint.rs index b3f45de72..f605dd41d 100644 --- a/packages/d2b/src/endpoint.rs +++ b/packages/d2b/src/endpoint.rs @@ -1,6 +1,6 @@ //! Provider-neutral Endpoint read and resolution projections. -use clap::{Args, Subcommand}; +use clap::{Args, Subcommand, ValueEnum}; use serde_json::{Map, Value, json}; use crate::{ @@ -28,10 +28,39 @@ pub(crate) struct EndpointNameArgs { pub(crate) name: String, } +/// The endpoint class vocabulary. +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub(crate) enum EndpointClass { + Service, + Device, + Transport, + Control, + Data, +} + +impl EndpointClass { + /// The wire spelling of this class. + pub(crate) fn as_wire_str(self) -> &'static str { + match self { + EndpointClass::Service => "service", + EndpointClass::Device => "device", + EndpointClass::Transport => "transport", + EndpointClass::Control => "control", + EndpointClass::Data => "data", + } + } +} + +impl std::fmt::Display for EndpointClass { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(self.as_wire_str()) + } +} + #[derive(Debug, Args, Clone)] pub(crate) struct EndpointListArgs { #[arg(long = "endpoint-class")] - pub(crate) endpoint_class: Option, + pub(crate) endpoint_class: Option, #[arg(long)] pub(crate) updates: bool, } @@ -39,7 +68,7 @@ pub(crate) struct EndpointListArgs { #[derive(Debug, Args, Clone)] pub(crate) struct EndpointWatchArgs { #[arg(long = "endpoint-class")] - pub(crate) endpoint_class: Option, + pub(crate) endpoint_class: Option, } #[derive(Debug, Args, Clone)] @@ -88,14 +117,11 @@ fn list( mode: OutputMode, deadline: RequestDeadline, ) -> Result { - if let Some(class) = args.endpoint_class.as_deref() { - validate_endpoint_class(context, class, mode)?; - } let value = context.invoke( "List", json!({ "resourceType": "Endpoint", - "endpointClass": args.endpoint_class, + "endpointClass": args.endpoint_class.map(EndpointClass::as_wire_str), "updates": args.updates, }), deadline, @@ -120,14 +146,11 @@ fn watch( 2, )); } - if let Some(class) = args.endpoint_class.as_deref() { - validate_endpoint_class(context, class, mode)?; - } let value = context.invoke( "Watch", json!({ "resourceType": "Endpoint", - "endpointClass": args.endpoint_class, + "endpointClass": args.endpoint_class.map(EndpointClass::as_wire_str), }), deadline, mode, @@ -200,25 +223,6 @@ fn endpoint_ref(name: &str) -> Result Result<(), CliFailure> { - if !matches!( - class, - "service" | "device" | "transport" | "control" | "data" - ) { - return Err(context.failure( - "ref-invalid", - "endpoint class must be service, device, transport, control, or data", - mode, - 2, - )); - } - Ok(()) -} - fn endpoint_resolution_projection(mut value: Value) -> Value { let allowed = [ "ok", diff --git a/packages/d2b/src/exec.rs b/packages/d2b/src/exec.rs index 119afb2d4..9400ac39e 100644 --- a/packages/d2b/src/exec.rs +++ b/packages/d2b/src/exec.rs @@ -1,6 +1,6 @@ //! EphemeralProcess execution commands. -use clap::{Args, Subcommand}; +use clap::{Args, Subcommand, ValueEnum}; use serde_json::{Value, json}; use crate::{ @@ -83,11 +83,38 @@ pub(crate) struct ExecLogsArgs { pub(crate) max_len: Option, } +/// The exec kill signal vocabulary. +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub(crate) enum ExecKillSignal { + Term, + Kill, + Int, + Hup, +} + +impl ExecKillSignal { + /// The wire spelling of this signal. + pub(crate) fn as_wire_str(self) -> &'static str { + match self { + ExecKillSignal::Term => "term", + ExecKillSignal::Kill => "kill", + ExecKillSignal::Int => "int", + ExecKillSignal::Hup => "hup", + } + } +} + +impl std::fmt::Display for ExecKillSignal { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(self.as_wire_str()) + } +} + #[derive(Debug, Args, Clone)] pub(crate) struct ExecKillArgs { pub(crate) resource_ref: String, - #[arg(long, default_value = "term")] - pub(crate) signal: String, + #[arg(long, default_value_t = ExecKillSignal::Term)] + pub(crate) signal: ExecKillSignal, } pub(crate) fn run( @@ -342,19 +369,11 @@ fn kill( deadline: RequestDeadline, ) -> Result { let resource_ref = validate_exec_ref(context, &args.resource_ref, mode)?; - if !matches!(args.signal.as_str(), "term" | "kill" | "int" | "hup") { - return Err(context.failure( - "ref-invalid", - "exec signal must be term, kill, int, or hup", - mode, - 2, - )); - } let value = context.invoke( "Cancel", json!({ "resourceRef": resource_ref.to_canonical_string(), - "signal": args.signal, + "signal": args.signal.as_wire_str(), }), deadline, mode, diff --git a/packages/d2b/tests/cli_contract_coverage.rs b/packages/d2b/tests/cli_contract_coverage.rs index 45c5087db..0e1aaf3c8 100644 --- a/packages/d2b/tests/cli_contract_coverage.rs +++ b/packages/d2b/tests/cli_contract_coverage.rs @@ -435,7 +435,7 @@ const V3_PARSER_PROBES: &[(&str, &[&str])] = &[ "endpoint", "list", "--endpoint-class", - "display", + "service", "--updates", "--json", ], From 048fb7d4f125b58bee128152b0ec3486267d7f42 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:41:48 -0700 Subject: [PATCH 338/726] d2b: hide the support-bundle projection types --- packages/d2b/src/zone_support_bundle.rs | 80 ++++++++++++------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/d2b/src/zone_support_bundle.rs b/packages/d2b/src/zone_support_bundle.rs index 1ec6cc350..8d03c72f2 100644 --- a/packages/d2b/src/zone_support_bundle.rs +++ b/packages/d2b/src/zone_support_bundle.rs @@ -16,103 +16,103 @@ use crate::{ pub(crate) struct ZoneSupportBundleArgs {} /// Maximum status snapshots per resource type. -pub const MAX_SNAPSHOTS_PER_TYPE: usize = 32; +const MAX_SNAPSHOTS_PER_TYPE: usize = 32; /// Maximum total status snapshots. -pub const MAX_TOTAL_SNAPSHOTS: usize = 512; +const MAX_TOTAL_SNAPSHOTS: usize = 512; /// Maximum structured log entries. -pub const MAX_LOG_ENTRIES: usize = 2000; +const MAX_LOG_ENTRIES: usize = 2000; /// Resource status fields safe for support output. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(default)] -pub struct ResourceStatusSnapshot { +struct ResourceStatusSnapshot { /// Opaque resource UID. - pub uid: String, + uid: String, /// Zone identity. - pub zone: String, + zone: String, /// Generation. - pub generation: u64, + generation: u64, /// Store revision. - pub revision: u64, + revision: u64, /// Last observed timestamp token. - pub observed_at: String, + observed_at: String, /// Closed phase. - pub phase: String, + phase: String, /// Bounded condition codes. - pub conditions: Vec, + conditions: Vec, /// Observed generation. - pub observed_generation: u64, + observed_generation: u64, /// Stable outcome code. - pub outcome: Option, + outcome: Option, } /// A bounded controller checkpoint. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(default)] -pub struct ControllerSnapshot { +struct ControllerSnapshot { /// Closed handler. - pub handler: String, + handler: String, /// Phase. - pub phase: String, + phase: String, /// Queue depth. - pub queue_depth: u32, + queue_depth: u32, } /// An audit segment inventory entry. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(default)] -pub struct AuditSegmentInventory { +struct AuditSegmentInventory { /// Date-derived owned filename. - pub filename: String, + filename: String, /// Segment size. - pub bytes: u64, + bytes: u64, /// Record count. - pub records: u64, + records: u64, } /// Provider self-metric summary. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(default)] -pub struct OtelSummary { +struct OtelSummary { /// Provider phase. - pub phase: String, + phase: String, /// Exported record count. - pub exported: u64, + exported: u64, /// Dropped record count. - pub dropped: u64, + dropped: u64, } /// One already-redacted structured log entry. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[serde(default)] -pub struct StructuredLogEntry { +struct StructuredLogEntry { /// Stable event class. - pub event: String, + event: String, /// Stable outcome code. - pub outcome: String, + outcome: String, /// Opaque timestamp token. - pub timestamp: String, + timestamp: String, } /// Output envelope. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct SupportBundle { +struct SupportBundle { /// Complete or partial. - pub bundle_completeness: String, + bundle_completeness: String, /// Doctor section. - pub doctor: ZoneDoctorReport, + doctor: ZoneDoctorReport, /// Bounded resource status snapshots. - pub resource_status: Vec, + resource_status: Vec, /// Controller snapshots. - pub controllers: Vec, + controllers: Vec, /// Schema catalog names and versions only. - pub schema_catalog: Vec<(String, String)>, + schema_catalog: Vec<(String, String)>, /// Audit segment inventory. - pub audit_segments: Vec, + audit_segments: Vec, /// Optional OTEL summary. - pub telemetry: Option, + telemetry: Option, /// Redacted bounded logs. - pub logs: Vec, + logs: Vec, } /// Run the admin-only bounded support-bundle service. @@ -320,7 +320,7 @@ fn contains_quarantine_signal(value: &Value) -> bool { /// Build a bounded support bundle. #[allow(clippy::too_many_arguments)] -pub fn build_bundle( +fn build_bundle( doctor: ZoneDoctorReport, quarantined: bool, resource_status: Vec, @@ -392,7 +392,7 @@ pub fn build_bundle( } /// Serialize the bounded bundle as one NDJSON document. -pub fn render_ndjson(bundle: &SupportBundle) -> Result { +fn render_ndjson(bundle: &SupportBundle) -> Result { let mut output = serde_json::to_string(bundle)?; output.push('\n'); Ok(output) From a91ad9bbcfc61c7486dbc9c294c2ee34bbd7e17d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:13 -0700 Subject: [PATCH 339/726] d2bd: carry typed sources in plane assembly errors --- packages/d2b-core/src/loader_worker.rs | 12 +++++++ packages/d2bd/src/resource_plane_v3.rs | 44 +++++++++++--------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/packages/d2b-core/src/loader_worker.rs b/packages/d2b-core/src/loader_worker.rs index 4e6786fe4..6678015fc 100644 --- a/packages/d2b-core/src/loader_worker.rs +++ b/packages/d2b-core/src/loader_worker.rs @@ -28,6 +28,7 @@ //! configuration. use std::{ + fmt, sync::{ LazyLock, mpsc::{SyncSender, TrySendError, sync_channel}, @@ -47,6 +48,17 @@ pub enum LoaderRefusal { Unavailable, } +impl fmt::Display for LoaderRefusal { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Busy => formatter.write_str("loader queue is full: retry later"), + Self::Unavailable => formatter.write_str("loader worker is not running"), + } + } +} + +impl std::error::Error for LoaderRefusal {} + type Job = Box; /// One dedicated worker thread with its own bounded queue. diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 2a26904cc..38d88c46c 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -1937,9 +1937,8 @@ impl ConstructionInputs { .parent() .map(Path::to_path_buf) .unwrap_or_else(|| PathBuf::from("/run/d2b")); - let zone_token = BoundedToken::parse(zone.as_str().to_owned()).map_err(|_| { - PlaneError::Authority(format!("zone {} is not a bounded token", zone.as_str())) - })?; + let zone_token = BoundedToken::parse(zone.as_str().to_owned()) + .map_err(|error| PlaneError::Authority(error.into()))?; // Reuse the daemon's shared, already-composed fixed Process // Providers; compose and attach once when absent (identical inputs // to the old composition path at composition.rs:3653). @@ -1962,7 +1961,7 @@ impl ConstructionInputs { }; let registry = Arc::new(PlaneResourceRegistry::new()); let controller_generation = ControllerGeneration::new(1) - .map_err(|error| PlaneError::Authority(error.to_string()))?; + .map_err(|error| PlaneError::Authority(error.into()))?; let endpoint_socket_runtime_dir = socket_runtime_dir.clone(); let endpoint_zone_token = zone_token.clone(); let probe = BindingSocketProbe { @@ -2629,7 +2628,7 @@ pub enum PlaneError { #[error("spec store open failed: {0}")] SpecStore(#[from] d2b_resource_runtime::spec_store::SpecStoreError), #[error("foundation seed failed: {0}")] - FoundationSeed(String), + FoundationSeed(#[from] crate::foundation_seed::SeedError), #[error("provider registration failed: {0}")] ProviderRegistration( #[from] d2b_resource_runtime::provider::ProviderDirectoryError, @@ -2652,15 +2651,15 @@ pub enum PlaneError { unexpected: Vec, }, #[error("manager spawn failed: {0}")] - ManagerSpawn(String), + ManagerSpawn(#[from] ractor::SpawnErr), #[error("manager rpc failed: {0}")] ManagerRpc(#[from] ResourceError), #[error("zone authority inputs invalid: {0}")] - Authority(String), + Authority(#[source] Box), #[error("target layer refused: {0}")] - Target(String), + Target(#[source] Box), #[error("bundle invalid: {0}")] - Bundle(String), + Bundle(#[from] d2b_contracts_zone_session::v3::resource_bundle::ResourceBundleError), } /// The canonical core Host target every non-guest resource realizes on @@ -2995,7 +2994,7 @@ impl ResourcePlaneV3 { let store_path = Self::spec_store_path(&inputs.spec_store_dir); if let Some(parent) = store_path.parent() { tokio::fs::create_dir_all(parent).await.map_err(|error| { - PlaneError::Authority(format!("spec store dir create failed: {error}")) + PlaneError::Authority(error.into()) })?; } let store = Arc::new( @@ -3003,9 +3002,7 @@ impl ResourcePlaneV3 { SpecStore::open(store_path.clone()).map_err(PlaneError::from) }) .await - .map_err(|error| { - PlaneError::Authority(format!("spec store open refused: {error:?}")) - })??, + .map_err(|error| PlaneError::Authority(error.into()))??, ); // The registry caches store-derived rows for the production effects; // the store is the authority its socket-target lookups load from on @@ -3057,10 +3054,7 @@ impl ResourcePlaneV3 { foundation.declarations.clone(), foundation.allocation.clone(), ); - let report = seed - .run(&store, &providers) - .await - .map_err(|error| PlaneError::FoundationSeed(error.to_string()))?; + let report = seed.run(&store, &providers).await?; tracing::info!( zone = %inputs.zone.as_str(), committed = report.committed.len(), @@ -3088,7 +3082,7 @@ impl ResourcePlaneV3 { let anchor_revision = hub.snapshot_revision(); let targets = Arc::new(TargetDirectory::new()); let host_target = TargetRef::host(CORE_HOST_TARGET_NAME) - .map_err(|error| PlaneError::Target(error.to_string()))?; + .map_err(|error| PlaneError::Target(error.into()))?; // Every registered driver's declaration carries its type's decoder, // so the registry is the authority: the plane wires no decoder table // of its own. @@ -3108,9 +3102,7 @@ impl ResourcePlaneV3 { target_resolver: Arc::new(DeclaredExecutionRef), backoff: PLANE_BACKOFF, }; - let (actor, _join) = ractor::Actor::spawn(None, ResourceManager::new(), args) - .await - .map_err(|error| PlaneError::ManagerSpawn(error.to_string()))?; + let (actor, _join) = ractor::Actor::spawn(None, ResourceManager::new(), args).await?; readiness.set_manager_started(true); readiness.set_spec_store_ready(true); // The anchor projection subscription: one long-lived consumer of the @@ -3223,7 +3215,7 @@ impl ResourcePlaneV3 { let outcome = self .targets .connect_guest(guest, session_generation, control) - .map_err(|error| PlaneError::Target(error.to_string()))?; + .map_err(|error| PlaneError::Target(error.into()))?; self.client .actor() .send_message(ResourceManagerMsg::TargetReconnected { @@ -3231,7 +3223,7 @@ impl ResourcePlaneV3 { session_generation: outcome.session_generation(), pending_adoption: outcome.pending_adoption().to_vec(), }) - .map_err(|error| PlaneError::Target(error.to_string()))?; + .map_err(|error| PlaneError::Target(error.into()))?; Ok(()) } @@ -3246,7 +3238,7 @@ impl ResourcePlaneV3 { let outcome = self .targets .disconnect_guest(guest, session_generation) - .map_err(|error| PlaneError::Target(error.to_string()))?; + .map_err(|error| PlaneError::Target(error.into()))?; self.client .actor() .send_message(ResourceManagerMsg::TargetUnavailable { @@ -3254,7 +3246,7 @@ impl ResourcePlaneV3 { session_generation: outcome.session_generation(), affected: outcome.affected().to_vec(), }) - .map_err(|error| PlaneError::Target(error.to_string()))?; + .map_err(|error| PlaneError::Target(error.into()))?; Ok(()) } @@ -3325,7 +3317,7 @@ pub async fn partition_nix_bundle( bundle: &ResourceBundle, store: &SpecStore, ) -> Result { - bundle.verify().map_err(|error| PlaneError::Bundle(error.to_string()))?; + bundle.verify()?; let durable_by_key: HashMap = store .list(SpecSelector { zone: Some(zone.as_str().to_owned()), From 5f6132bb2bbbde5ff268aed103191a8932064de5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:16 -0700 Subject: [PATCH 340/726] xtask: split the process provider id domains by consumer --- packages/xtask/src/gen_layer_catalogs.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/xtask/src/gen_layer_catalogs.rs b/packages/xtask/src/gen_layer_catalogs.rs index 67e54a954..b7b7b7ea7 100644 --- a/packages/xtask/src/gen_layer_catalogs.rs +++ b/packages/xtask/src/gen_layer_catalogs.rs @@ -275,11 +275,19 @@ fn broker_operation_values(repo_root: &Path) -> Result, String> { Ok(values) } -/// The process-provider ids one consumer admits. -fn process_provider_ids(metric_label: Option) -> Vec { +/// The process-provider ids the surface and audit catalogs admit. +fn all_process_provider_ids() -> Vec { PROCESS_PROVIDERS .iter() - .filter(|provider| metric_label.is_none_or(|metric| provider.metric_label == metric)) + .map(|provider| provider.id.to_owned()) + .collect() +} + +/// The process-provider ids the metric label domain admits. +fn metric_process_provider_ids() -> Vec { + PROCESS_PROVIDERS + .iter() + .filter(|provider| provider.metric_label) .map(|provider| provider.id.to_owned()) .collect() } @@ -358,7 +366,7 @@ fn surface_catalog_source() -> String { source.push_str(&string_slice( "PROCESS_PROVIDERS", &["The process providers an audit record may name."], - &process_provider_ids(None), + &all_process_provider_ids(), )); source.push_str(&doc_lines(&[ "The resource type a typed noun addresses.", @@ -484,7 +492,7 @@ fn audit_catalog_source() -> String { source.push_str(&string_slice( "PROCESS_PROVIDERS", &["The process providers a process effect record may name."], - &process_provider_ids(None), + &all_process_provider_ids(), )); source.push_str(&doc_lines(&[ "Whether the resource type is in the registry.", @@ -525,7 +533,7 @@ fn telemetry_catalog_source(repo_root: &Path) -> Result { source.push_str(&string_slice( "PROCESS_PROVIDERS", &["The process provider label domain."], - &process_provider_ids(Some(true)), + &metric_process_provider_ids(), )); source.push_str(&string_slice( "BROKER_OPERATION_VALUES", @@ -695,9 +703,9 @@ mod tests { /// The process provider vocabulary projects both consumer domains. #[test] fn process_provider_domains_project_from_one_vocabulary() { - assert_eq!(process_provider_ids(None).len(), PROCESS_PROVIDERS.len()); + assert_eq!(all_process_provider_ids().len(), PROCESS_PROVIDERS.len()); assert_eq!( - process_provider_ids(Some(true)), + metric_process_provider_ids(), vec!["minijail".to_owned(), "systemd".to_owned()] ); } From 1d692db3ddfded3bcc2f67e9a85049c96c948489 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:23 -0700 Subject: [PATCH 341/726] xtask: carry the server-state count typed --- packages/xtask/src/provider_crate_policy.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index dfbff026a..6b3300fa3 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -4676,6 +4676,8 @@ struct FamilyKnowledgeSignal { class: FamilySignalClass, /// The literal, identifier, or state-handle name that carried the signal. text: String, + /// The count of `ServerState` references for a [`FamilySignalClass::ServerState`] signal. + count: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -5048,6 +5050,7 @@ fn module_family_signals( line: index + 1, class: FamilySignalClass::Assembled, text: content.clone(), + count: None, }); } } @@ -5061,6 +5064,7 @@ fn module_family_signals( line: index + 1, class: FamilySignalClass::Literal, text: content.clone(), + count: None, }); } } @@ -5078,6 +5082,7 @@ fn module_family_signals( line: index + 1, class: FamilySignalClass::Identifier, text: identifier.to_owned(), + count: None, }); } } @@ -5101,7 +5106,8 @@ fn module_family_signals( family: "d2bd-state", line, class: FamilySignalClass::ServerState, - text: format!("{server_state_count}"), + text: String::new(), + count: Some(server_state_count), }); } Ok(()) @@ -5176,7 +5182,7 @@ fn render_family_knowledge_violation(signal: &FamilyKnowledgeSignal) -> String { if !matches!(signal.class, FamilySignalClass::ServerState) { diagnostic["text"] = serde_json::Value::String(signal.text.clone()); } else { - diagnostic["count"] = serde_json::Value::from(signal.text.parse::().unwrap_or(0)); + diagnostic["count"] = serde_json::Value::from(signal.count.unwrap_or(0)); } diagnostic.to_string() } From 7194d24e994ab63d0549c781915983eb192bcd11 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:28 -0700 Subject: [PATCH 342/726] xtask: split recovery attestation read and decode failures --- packages/xtask/src/delivery/recovery.rs | 51 +++++++++++++++---------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/packages/xtask/src/delivery/recovery.rs b/packages/xtask/src/delivery/recovery.rs index 462c805a0..3b3408bcc 100644 --- a/packages/xtask/src/delivery/recovery.rs +++ b/packages/xtask/src/delivery/recovery.rs @@ -381,7 +381,8 @@ impl RecoveryAttestation { return Err(RecoveryError::TooLarge); } CanonicalJsonValue::parse(bytes).map_err(RecoveryError::CanonicalJson)?; - let value: Self = serde_json::from_slice(bytes).map_err(|_| RecoveryError::Json)?; + let value: Self = serde_json::from_slice(bytes) + .map_err(|error| RecoveryError::Json(error.to_string()))?; value.validate_shape()?; Ok(value) } @@ -1558,8 +1559,11 @@ impl<'a> DeliveryLedger<'a> { pub enum RecoveryError { /// Canonical JSON rejected a duplicate, unknown numeric, or trailing value. CanonicalJson(CanonicalJsonError), - /// Typed JSON decoding failed. - Json, + /// Typed JSON decoding failed. Carries the bounded serde detail - field + /// names and positions only, never payload values. + Json(String), + /// The attestation file could not be opened or read. + Read, /// The record exceeded the bounded artifact size. TooLarge, /// Fixed artifact, version, or program shape failed. @@ -1586,21 +1590,28 @@ pub enum RecoveryError { impl fmt::Display for RecoveryError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str(match self { - Self::CanonicalJson(_) => "strict recovery JSON rejected", - Self::Json => "recovery attestation shape rejected", - Self::TooLarge => "recovery attestation is too large", - Self::Shape => "recovery attestation contract rejected", - Self::Binding => "recovery attestation binding rejected", - Self::Qualification => "recovery qualification rejected", - Self::Timestamp => "recovery timestamp rejected", - Self::Expiry => "recovery expiry rejected", - Self::Freshness => "recovery evidence is stale or not yet valid", - Self::InsufficientTtl => "recovery evidence lacks required remaining lifetime", - Self::ClosureUnavailable => "pinned closure or protected GC root is unavailable", - Self::ClosureMismatch => "pinned closure binding rejected", - Self::Clock => "verifier clock rejected", - }) + match self { + Self::CanonicalJson(_) => formatter.write_str("strict recovery JSON rejected"), + Self::Json(detail) => { + write!(formatter, "recovery attestation shape rejected: {detail}") + } + Self::Read => formatter.write_str("recovery attestation file could not be read"), + Self::TooLarge => formatter.write_str("recovery attestation is too large"), + Self::Shape => formatter.write_str("recovery attestation contract rejected"), + Self::Binding => formatter.write_str("recovery attestation binding rejected"), + Self::Qualification => formatter.write_str("recovery qualification rejected"), + Self::Timestamp => formatter.write_str("recovery timestamp rejected"), + Self::Expiry => formatter.write_str("recovery expiry rejected"), + Self::Freshness => formatter.write_str("recovery evidence is stale or not yet valid"), + Self::InsufficientTtl => { + formatter.write_str("recovery evidence lacks required remaining lifetime") + } + Self::ClosureUnavailable => { + formatter.write_str("pinned closure or protected GC root is unavailable") + } + Self::ClosureMismatch => formatter.write_str("pinned closure binding rejected"), + Self::Clock => formatter.write_str("verifier clock rejected"), + } } } @@ -1712,12 +1723,12 @@ fn sampled_unix_seconds() -> RecoveryResult { #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn read_attestation(path: &Path) -> RecoveryResult> { - let mut file = fs::File::open(path).map_err(|_| RecoveryError::Json)?; + let mut file = fs::File::open(path).map_err(|_| RecoveryError::Read)?; let mut bytes = Vec::new(); file.by_ref() .take(MAX_JSON_BYTES as u64 + 1) .read_to_end(&mut bytes) - .map_err(|_| RecoveryError::Json)?; + .map_err(|_| RecoveryError::Read)?; if bytes.len() > MAX_JSON_BYTES { return Err(RecoveryError::TooLarge); } From 67393687b13c359ac6b3a96bca469d28e25c7c96 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:29 -0700 Subject: [PATCH 343/726] contracts-resource: drop unused ValidatedSessionPurpose alias --- packages/d2b-contracts-resource/src/v3/identity.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/d2b-contracts-resource/src/v3/identity.rs b/packages/d2b-contracts-resource/src/v3/identity.rs index 2993eb67a..13708fe90 100644 --- a/packages/d2b-contracts-resource/src/v3/identity.rs +++ b/packages/d2b-contracts-resource/src/v3/identity.rs @@ -266,9 +266,6 @@ impl JsonSchema for Timestamp { } } -/// A ComponentSession purpose selected by trusted endpoint policy. -pub type ValidatedSessionPurpose = SessionPurpose; - /// A validated resource-service name. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] From 9ccb9c6940ab825f07326c3bf3c0becc7f823e52 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:37 -0700 Subject: [PATCH 344/726] xtask: reject unknown keys in service catalog declarations --- packages/xtask/src/service_catalog.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/xtask/src/service_catalog.rs b/packages/xtask/src/service_catalog.rs index 193ade98d..c77246178 100644 --- a/packages/xtask/src/service_catalog.rs +++ b/packages/xtask/src/service_catalog.rs @@ -20,6 +20,7 @@ pub(crate) const GENERATED_ARTIFACT: &str = /// One provider crate's service-catalog declaration. #[derive(Deserialize)] +#[serde(deny_unknown_fields)] struct DeclarationFile { /// The provider identity this crate publishes. #[serde(rename = "provider")] @@ -257,3 +258,20 @@ fn generated_artifact_path(repo_root: &Path) -> PathBuf { repo_root.join(GENERATED_ARTIFACT) } + +#[cfg(test)] +mod tests { + use super::*; + + /// A typo'd declaration key is refused at the boundary instead of being + /// silently ignored (the daemon's fixed-UID row would otherwise vanish). + #[test] + fn an_unknown_declaration_key_is_refused() { + let error = serde_json::from_str::( + r#"{"provider":"system-core","providerRef":"Provider/system-core","providerUid":"fixed","providerUidTypo":"fixed"}"#, + ) + .err() + .expect("an unknown declaration key is refused"); + assert!(error.to_string().contains("providerUidTypo"), "{error}"); + } +} From da9369cef5ca04991b22365253833f284aff5768 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:38 -0700 Subject: [PATCH 345/726] d2b-provider-guest-qemu-media: hide test-support exports from docs --- packages/d2b-provider-guest-qemu-media/src/adoption.rs | 1 + packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/d2b-provider-guest-qemu-media/src/adoption.rs b/packages/d2b-provider-guest-qemu-media/src/adoption.rs index 5fa774f11..c6664c629 100644 --- a/packages/d2b-provider-guest-qemu-media/src/adoption.rs +++ b/packages/d2b-provider-guest-qemu-media/src/adoption.rs @@ -21,6 +21,7 @@ pub struct ProcessIdentity { impl ProcessIdentity { /// Construct deterministic identity evidence for hermetic tests. + #[doc(hidden)] pub fn for_test(value: &str) -> Self { let digest = Sha256::digest(value.as_bytes()); let mut bytes = [0_u8; 32]; diff --git a/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs b/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs index c79c32875..c3928ba14 100644 --- a/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs +++ b/packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs @@ -127,6 +127,7 @@ pub trait QmpTransport { } /// Scripted transport used by hermetic tests and fake integration fixtures. +#[doc(hidden)] #[derive(Debug, Clone)] pub struct ScriptedQmpTransport { greeting: Option, From 341c4fb5e60c325a579cb04857eb281c6b51488b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:50 -0700 Subject: [PATCH 346/726] xtask: rename resource type declaration keys by convention --- packages/xtask/src/resource_type_authority.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/xtask/src/resource_type_authority.rs b/packages/xtask/src/resource_type_authority.rs index 71f2ffa75..071a4974b 100644 --- a/packages/xtask/src/resource_type_authority.rs +++ b/packages/xtask/src/resource_type_authority.rs @@ -177,7 +177,10 @@ const COMMITTED_V3_ORDER: &[&str] = &[ /// One provider crate's declaration file. #[derive(Deserialize)] +#[serde(rename_all = "camelCase")] struct DeclarationFile { + /// The declaring crate package name; the wire key `crate` is a Rust + /// keyword, so it is renamed explicitly. #[serde(rename = "crate")] crate_name: String, types: Vec, @@ -188,8 +191,8 @@ struct DeclarationFile { /// One declared resource type row. #[derive(Deserialize)] +#[serde(rename_all = "camelCase")] struct TypeDeclaration { - #[serde(rename = "resourceType")] resource_type: String, } From 29a900c5aa7a023b295ce329f3d32e38dcc94067 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:53 -0700 Subject: [PATCH 347/726] contracts-resource: enforce nonzero store epoch in seal identity --- .../src/v3/operations/seal.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/d2b-contracts-resource/src/v3/operations/seal.rs b/packages/d2b-contracts-resource/src/v3/operations/seal.rs index c82731857..eb3247af3 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/seal.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/seal.rs @@ -56,7 +56,16 @@ impl StoreSealIdentity { } /// Bind the seal identity to a nonzero store epoch. + /// + /// # Panics + /// + /// Panics in debug builds when `store_epoch` is zero; a zero epoch is + /// a caller defect, never a valid binding. pub fn with_store_epoch(mut self, store_epoch: u64) -> Self { + debug_assert!( + store_epoch != 0, + "store epoch must be nonzero; a zero epoch is a caller defect" + ); self.store_epoch = store_epoch; self } @@ -301,3 +310,14 @@ fn open_rejects_same_authority_with_mismatched_declared_identity() { assert_eq!(error.reason_code(), "mutation-seal-store-identity-mismatch"); assert_eq!(error.store_slot(), Some(slot)); } + +#[test] +#[should_panic(expected = "store epoch must be nonzero")] +fn with_store_epoch_rejects_a_zero_epoch() { + let identity = StoreSealIdentity::new( + StoreSlot::new(0).unwrap(), + ZoneId::parse("work").unwrap(), + ResourceUid::parse("11111111-1111-4111-8111-111111111111").unwrap(), + ); + let _ = identity.with_store_epoch(0); +} From 4404afb720aa44dee72a73e2bc69cb39861c42d6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:42:08 -0700 Subject: [PATCH 348/726] clipboard: validate merged picker path --- packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs index b4d51dd8d..a3ea2772b 100644 --- a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs @@ -139,10 +139,10 @@ fn run(args_iter: impl IntoIterator) -> Result<(), String> { .map(PathBuf::from); let picker = args.picker.clone().or(picker_from_config); let bridge_peers = parse_bridge_peers(&config_json)?; - if let Some(p) = &args.picker + if let Some(p) = &picker && !p.is_absolute() { - return Err(format!("--picker path must be absolute: {}", p.display())); + return Err(format!("picker path must be absolute: {}", p.display())); } if !args.bridge_root.is_absolute() { return Err(format!( From 1b70ff14a0ad96dcac766d4b751303c3000afd81 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:15 -0700 Subject: [PATCH 349/726] clipboard: log niri thread spawn failure instead of panicking --- .../src/bin/d2b-clipd.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs index a3ea2772b..500ec76d0 100644 --- a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs @@ -198,7 +198,9 @@ fn run(args_iter: impl IntoIterator) -> Result<(), String> { // ── Niri IPC event stream thread ───────────────────────────────────────── if let Some(ref socket) = niri_socket { - spawn_niri_event_thread(socket.clone(), niri_tx); + if let Err(error) = spawn_niri_event_thread(socket.clone(), niri_tx) { + log::error!("d2b-clipd: failed to spawn niri event thread: {error}"); + } } else { log::warn!("d2b-clipd: NIRI_SOCKET not set; focused-window attribution unavailable"); } @@ -3500,7 +3502,7 @@ enum NiriMessage { } #[allow(clippy::disallowed_methods, reason = "CLI-only path")] -fn spawn_niri_event_thread(socket: PathBuf, tx: mpsc::Sender) { +fn spawn_niri_event_thread(socket: PathBuf, tx: mpsc::Sender) -> Result<(), std::io::Error> { std::thread::Builder::new() .name("d2b-clipd-niri".to_owned()) .spawn(move || { @@ -3542,8 +3544,8 @@ fn spawn_niri_event_thread(socket: PathBuf, tx: mpsc::Sender) { } } } - }) - .expect("niri thread spawn"); + })?; + Ok(()) } fn drain_niri_channel( From ad70ac37c4624c4ccd6395b9f51e1d7116489abd Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:18 -0700 Subject: [PATCH 350/726] d2b-bus: return a closed error type from policy identity binding --- packages/d2b-bus/src/wire.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/d2b-bus/src/wire.rs b/packages/d2b-bus/src/wire.rs index 97ece8e27..7c9fe795b 100644 --- a/packages/d2b-bus/src/wire.rs +++ b/packages/d2b-bus/src/wire.rs @@ -34,6 +34,23 @@ pub struct ZoneBoundPolicyIdentity { policy: EndpointPolicyIdentity, } +/// Zone-bound policy identity construction failure. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ZoneBoundPolicyIdentityError { +/// The bound resource is not a Provider. + NotProviderRef, +} + +impl core::fmt::Display for ZoneBoundPolicyIdentityError { + fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str(match self { + Self::NotProviderRef => "zone-bound-policy-identity-provider-ref-invalid", + }) + } +} + +impl std::error::Error for ZoneBoundPolicyIdentityError {} + impl ZoneBoundPolicyIdentity { /// Construct a Zone-bound identity. pub fn new(zone: ZoneId, policy: EndpointPolicyIdentity) -> Self { @@ -50,9 +67,9 @@ impl ZoneBoundPolicyIdentity { zone: ZoneId, provider_ref: ResourceRef, policy: EndpointPolicyIdentity, - ) -> Result { + ) -> Result { if provider_ref.resource_type().as_str() != "Provider" { - return Err("provider identity must name Provider"); + return Err(ZoneBoundPolicyIdentityError::NotProviderRef); } Ok(Self { zone, @@ -186,7 +203,7 @@ mod tests { identity(), ) .unwrap_err(), - "provider identity must name Provider" + ZoneBoundPolicyIdentityError::NotProviderRef ); } } From da5acd3325eb526c213f17ac3ee86c3b9e1a208c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:24 -0700 Subject: [PATCH 351/726] clipboard: propagate binary errors through anyhow --- Cargo.lock | 1 + .../d2b-provider-clipboard-wayland/Cargo.toml | 1 + .../src/bin/d2b-clipd.rs | 204 +++++++++--------- 3 files changed, 103 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f023ce55f..d85ce86e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1117,6 +1117,7 @@ dependencies = [ name = "d2b-provider-clipboard-wayland" version = "0.0.0-bootstrap" dependencies = [ + "anyhow", "command-fds", "d2b-contracts", "d2b-contracts-resource", diff --git a/packages/d2b-provider-clipboard-wayland/Cargo.toml b/packages/d2b-provider-clipboard-wayland/Cargo.toml index ae2ad1fc9..93c41fb2a 100644 --- a/packages/d2b-provider-clipboard-wayland/Cargo.toml +++ b/packages/d2b-provider-clipboard-wayland/Cargo.toml @@ -14,6 +14,7 @@ await_holding_lock = "deny" await_holding_refcell_ref = "deny" [dependencies] +anyhow = "1" command-fds = "0.3" d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } d2b-contracts = { path = "../d2b-contracts", version = "0.0.0-bootstrap" } diff --git a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs index 500ec76d0..565903b2c 100644 --- a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs @@ -124,13 +124,13 @@ fn main() { // binary, so these blocking calls are sync-by-construction. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] -fn run(args_iter: impl IntoIterator) -> Result<(), String> { +fn run(args_iter: impl IntoIterator) -> anyhow::Result<()> { let args = parse_args(args_iter)?; let config_text = std::fs::read_to_string(&args.config) - .map_err(|e| format!("failed to read config {}: {e}", args.config.display()))?; + .map_err(|e| anyhow::anyhow!("failed to read config {}: {e}", args.config.display()))?; let config_json: serde_json::Value = serde_json::from_str(&config_text) - .map_err(|e| format!("invalid config JSON {}: {e}", args.config.display()))?; + .map_err(|e| anyhow::anyhow!("invalid config JSON {}: {e}", args.config.display()))?; // Picker: CLI arg takes precedence, then config file key. let picker_from_config = config_json @@ -142,10 +142,10 @@ fn run(args_iter: impl IntoIterator) -> Result<(), String> { if let Some(p) = &picker && !p.is_absolute() { - return Err(format!("picker path must be absolute: {}", p.display())); + return Err(anyhow::anyhow!("picker path must be absolute: {}", p.display())); } if !args.bridge_root.is_absolute() { - return Err(format!( + return Err(anyhow::anyhow!( "--bridge-root path must be absolute: {}", args.bridge_root.display() )); @@ -156,7 +156,7 @@ fn run(args_iter: impl IntoIterator) -> Result<(), String> { } // ── Wayland data-control ───────────────────────────────────────────────── - let mut data_control = DataControlClient::connect().map_err(|e| e.to_string())?; + let mut data_control = DataControlClient::connect().map_err(|e| anyhow::anyhow!("{e}"))?; let niri_socket: Option = args .niri_socket @@ -190,10 +190,10 @@ fn run(args_iter: impl IntoIterator) -> Result<(), String> { let control_socket = control_socket_path()?; install_control_socket_parent(&control_socket)?; let listener = - UnixListener::bind(&control_socket).map_err(|e| format!("bind control socket: {e}"))?; + UnixListener::bind(&control_socket).map_err(|e| anyhow::anyhow!("bind control socket: {e}"))?; listener .set_nonblocking(true) - .map_err(|e| format!("set_nonblocking: {e}"))?; + .map_err(|e| anyhow::anyhow!("set_nonblocking: {e}"))?; let bridge_listeners = install_bridge_listeners(&args.bridge_root, &bridge_peers)?; // ── Niri IPC event stream thread ───────────────────────────────────────── @@ -246,10 +246,10 @@ fn run(args_iter: impl IntoIterator) -> Result<(), String> { event_loop.run() } -fn parse_bridge_peers(config_json: &serde_json::Value) -> Result, String> { +fn parse_bridge_peers(config_json: &serde_json::Value) -> anyhow::Result> { if let Some(value) = config_json.pointer("/runtime/bridgeEndpoints") { let Some(items) = value.as_array() else { - return Err("runtime.bridgeEndpoints must be an array".to_owned()); + return Err(anyhow::anyhow!("runtime.bridgeEndpoints must be an array")); }; return items .iter() @@ -258,20 +258,20 @@ fn parse_bridge_peers(config_json: &serde_json::Value) -> Result(value).map_err(|_| { - "runtime.bridgeEndpoints[].providerKind is invalid".to_owned() + anyhow::anyhow!("runtime.bridgeEndpoints[].providerKind is invalid") }) })?; let legacy_vm_name = item @@ -280,7 +280,7 @@ fn parse_bridge_peers(config_json: &serde_json::Value) -> Result Result Result Result Result Result Result Result { +fn legacy_vm_endpoint(vm_name: &str) -> anyhow::Result { let canonical_target = WorkloadTarget::parse(&format!("{vm_name}.local.d2b")) - .map_err(|_| "bridge VM name cannot form a canonical target".to_owned())?; + .map_err(|_| anyhow::anyhow!("bridge VM name cannot form a canonical target"))?; Ok(ClipboardEndpointIdentity { canonical_target, provider_kind: WorkloadProviderKind::LocalVm, @@ -410,7 +409,7 @@ struct EventLoop<'a> { impl EventLoop<'_> { #[allow(clippy::disallowed_methods, reason = "CLI-only path")] - fn run(&mut self) -> Result<(), String> { + fn run(&mut self) -> anyhow::Result<()> { loop { self.drain_async_materialization(); // Flush pending Wayland requests before polling. @@ -473,7 +472,7 @@ impl EventLoop<'_> { match poll(&mut poll_fds, self.poll_timeout_ms()) { Ok(_) => {} Err(rustix::io::Errno::INTR) => continue, - Err(error) => return Err(format!("poll failed: {error}")), + Err(error) => return Err(anyhow::anyhow!("poll failed: {error}")), } let control_offset = 2 + usize::from(self.supervisor.active_socket().is_some()); let bridge_listener_offset = control_offset + self.control_streams.len(); @@ -534,12 +533,12 @@ impl EventLoop<'_> { if wayland_ready { self.data_control .prepare_and_read() - .map_err(|e| format!("wayland read failed: {e}"))?; + .map_err(|e| anyhow::anyhow!("wayland read failed: {e}"))?; } let wl_events = self .data_control .dispatch_pending() - .map_err(|e| format!("wayland dispatch failed: {e}"))?; + .map_err(|e| anyhow::anyhow!("wayland dispatch failed: {e}"))?; for event in wl_events { let mut context = WaylandEventContext { data_control: self.data_control, @@ -593,7 +592,7 @@ impl EventLoop<'_> { }); break; } - Err(error) => return Err(format!("control accept failed: {error}")), + Err(error) => return Err(anyhow::anyhow!("control accept failed: {error}")), } } } @@ -1128,7 +1127,7 @@ enum BridgeAttribution { fn install_bridge_listeners( root: &Path, bridge_peers: &[BridgePeerConfig], -) -> Result, String> { +) -> anyhow::Result> { let uid = rustix::process::getuid().as_raw(); bridge_peers .iter() @@ -1136,36 +1135,36 @@ fn install_bridge_listeners( let path = bridge_socket_path(root, uid, &peer.socket_component)?; let parent = path .parent() - .ok_or_else(|| format!("bridge socket has no parent: {}", path.display()))?; + .ok_or_else(|| anyhow::anyhow!("bridge socket has no parent: {}", path.display()))?; std::fs::DirBuilder::new() .recursive(true) .mode(0o770) .create(parent) - .map_err(|e| format!("create bridge socket dir {}: {e}", parent.display()))?; + .map_err(|e| anyhow::anyhow!("create bridge socket dir {}: {e}", parent.display()))?; if path.exists() { let meta = std::fs::symlink_metadata(&path) - .map_err(|e| format!("stat bridge socket {}: {e}", path.display()))?; + .map_err(|e| anyhow::anyhow!("stat bridge socket {}: {e}", path.display()))?; if !meta.file_type().is_socket() { - return Err(format!("refusing to replace non-socket {}", path.display())); + return Err(anyhow::anyhow!("refusing to replace non-socket {}", path.display())); } std::fs::remove_file(&path) - .map_err(|e| format!("remove stale bridge socket {}: {e}", path.display()))?; + .map_err(|e| anyhow::anyhow!("remove stale bridge socket {}: {e}", path.display()))?; } // umask is process-wide: keep bridge listener installation in the // single-threaded startup phase, before spawning background workers. let old_umask = nix::sys::stat::umask(nix::sys::stat::Mode::from_bits_truncate(0o111)); let listener = UnixListener::bind(&path) - .map_err(|e| format!("bind bridge socket {}: {e}", path.display())); + .map_err(|e| anyhow::anyhow!("bind bridge socket {}: {e}", path.display())); nix::sys::stat::umask(old_umask); let listener = listener?; let bound_meta = std::fs::symlink_metadata(&path) - .map_err(|e| format!("stat bound bridge socket {}: {e}", path.display()))?; + .map_err(|e| anyhow::anyhow!("stat bound bridge socket {}: {e}", path.display()))?; if !bound_meta.file_type().is_socket() { - return Err(format!("refusing bound non-socket {}", path.display())); + return Err(anyhow::anyhow!("refusing bound non-socket {}", path.display())); } listener .set_nonblocking(true) - .map_err(|e| format!("set bridge socket nonblocking {}: {e}", path.display()))?; + .map_err(|e| anyhow::anyhow!("set bridge socket nonblocking {}: {e}", path.display()))?; Ok(BridgeListener { identity: peer.identity.clone(), expected_uid: peer.expected_uid, @@ -1175,14 +1174,14 @@ fn install_bridge_listeners( .collect() } -fn bridge_socket_path(root: &Path, uid: u32, component: &str) -> Result { +fn bridge_socket_path(root: &Path, uid: u32, component: &str) -> anyhow::Result { if component.is_empty() || component == "." || component == ".." || component.contains('/') || component.contains('\0') { - return Err("invalid bridge endpoint component".to_owned()); + return Err(anyhow::anyhow!("invalid bridge endpoint component")); } Ok(root .join(uid.to_string()) @@ -1406,13 +1405,13 @@ fn handle_bridge_stream( BridgeStreamStatus::Done } -fn validate_bridge_peer(stream: &UnixStream, expected_uid: u32) -> Result<(), String> { +fn validate_bridge_peer(stream: &UnixStream, expected_uid: u32) -> anyhow::Result<()> { let creds = nix::sys::socket::getsockopt(stream, nix::sys::socket::sockopt::PeerCredentials) - .map_err(|e| e.to_string())?; + .map_err(|e| anyhow::anyhow!("{e}"))?; if creds.uid() == expected_uid { Ok(()) } else { - Err(format!( + Err(anyhow::anyhow!( "uid mismatch: expected {}, got {}", expected_uid, creds.uid() @@ -1573,7 +1572,7 @@ fn parse_bridge_frame(stream: &mut BridgeStream) -> Result parse_bridge_transfer( stream, - legacy_vm_endpoint(&vm_name).map_err(BridgeReadError::Invalid)?, + legacy_vm_endpoint(&vm_name).map_err(|e| BridgeReadError::Invalid(e.to_string()))?, mime_type, source_id, source_attribution, @@ -1586,7 +1585,7 @@ fn parse_bridge_frame(stream: &mut BridgeStream) -> Result parse_bridge_transfer( stream, - legacy_vm_endpoint(&vm_name).map_err(BridgeReadError::Invalid)?, + legacy_vm_endpoint(&vm_name).map_err(|e| BridgeReadError::Invalid(e.to_string()))?, mime_type, source_id, source_attribution, @@ -2462,7 +2461,7 @@ fn handle_control_stream( ); let body = match response { Ok(msg) => format!("{{\"ok\":true,\"message\":{}}}\n", json_string(&msg)), - Err(err) => format!("{{\"ok\":false,\"error\":{}}}\n", json_string(&err)), + Err(err) => format!("{{\"ok\":false,\"error\":{}}}\n", json_string(&err.to_string())), }; if let Err(error) = write_all_nonblocking_stream(&control.stream, body.as_bytes(), BOUNDED_READ_TIMEOUT) @@ -2678,16 +2677,16 @@ fn handle_picker_message(message: PickerToDaemonMessage, context: &mut PickerMes fn replay_paste_after_focus( niri_socket: Option<&Path>, target: Option<&FocusedWindowSnapshot>, -) -> Result<(), String> { - let socket = niri_socket.ok_or_else(|| "niri socket is unavailable".to_owned())?; - let target = target.ok_or_else(|| "paste target is unavailable".to_owned())?; +) -> anyhow::Result<()> { + let socket = niri_socket.ok_or_else(|| anyhow::anyhow!("niri socket is unavailable"))?; + let target = target.ok_or_else(|| anyhow::anyhow!("paste target is unavailable"))?; wait_for_target_focus( target, PASTE_FOCUS_RESTORE_TIMEOUT, PASTE_FOCUS_POLL_INTERVAL, || query_focused_window_snapshot(socket), )?; - crate::clipd_host::virtual_keyboard::paste_ctrl_v().map_err(|error| error.to_string()) + crate::clipd_host::virtual_keyboard::paste_ctrl_v().map_err(|error| anyhow::anyhow!("{error}")) } #[allow(clippy::disallowed_methods, reason = "CLI-only path")] @@ -2696,9 +2695,9 @@ fn wait_for_target_focus( timeout: Duration, poll_interval: Duration, mut query: F, -) -> Result<(), String> +) -> anyhow::Result<()> where - F: FnMut() -> Result, String>, + F: FnMut() -> anyhow::Result>, { let deadline = Instant::now() + timeout; loop { @@ -2709,19 +2708,19 @@ where return Ok(()); } if Instant::now() >= deadline { - return Err("focused destination was not restored before timeout".to_owned()); + return Err(anyhow::anyhow!("focused destination was not restored before timeout")); } std::thread::sleep(poll_interval); } } -fn query_focused_window_snapshot(socket: &Path) -> Result, String> { +fn query_focused_window_snapshot(socket: &Path) -> anyhow::Result> { let mut client = NiriJsonClient::connect( socket, crate::clipd_host::niri::DEFAULT_NIRI_MAX_LINE_BYTES, Some(Duration::from_millis(250)), ) - .map_err(|error| error.to_string())?; + .map_err(|error| anyhow::anyhow!("{error}"))?; client .query_focused_window() .map(|window| { @@ -2733,7 +2732,7 @@ fn query_focused_window_snapshot(socket: &Path) -> Result Result { +) -> anyhow::Result { let dest = host_clipboard .refresh_focused_window_snapshot() .unwrap_or_default(); @@ -3047,7 +3046,7 @@ fn handle_arm( "clipboard", dest.app_id.as_deref().unwrap_or("host"), ); - Err(ReasonCode::PickerCrashed.as_str().to_owned()) + Err(anyhow::anyhow!("{}", ReasonCode::PickerCrashed.as_str())) } } } @@ -3062,7 +3061,7 @@ fn handle_arm( "clipboard", dest.app_id.as_deref().unwrap_or("host"), ); - Err(ReasonCode::PickerNotConfigured.as_str().to_owned()) + Err(anyhow::anyhow!("{}", ReasonCode::PickerNotConfigured.as_str())) } } } @@ -3110,18 +3109,18 @@ fn picker_handshake( endpoint: Option<&ClipboardEndpointIdentity>, requested_mime_type: &str, candidates: Vec, -) -> Result { +) -> anyhow::Result { let hello_buf = read_bounded_line( socket, PICKER_TO_DAEMON_MAX_FRAME_BYTES, BOUNDED_READ_TIMEOUT, ) - .map_err(|e| format!("read hello: {e}"))?; + .map_err(|e| anyhow::anyhow!("read hello: {e}"))?; let hello: PickerToDaemonMessage = decode_frame(&hello_buf, PICKER_TO_DAEMON_MAX_FRAME_BYTES) - .map_err(|e| format!("decode hello: {e}"))?; + .map_err(|e| anyhow::anyhow!("decode hello: {e}"))?; let picker_version = match hello { PickerToDaemonMessage::ClientHello(ClientHello { picker_version, .. }) => picker_version, - _ => return Err("first frame was not client_hello".to_owned()), + _ => return Err(anyhow::anyhow!("first frame was not client_hello")), }; let request = DaemonToPickerMessage::OpenRequest(Box::new(OpenRequest { @@ -3160,12 +3159,12 @@ fn picker_handshake( ); } let frame = encode_frame(&request, OpenRequestFrameCaps::default().max_frame_bytes()) - .map_err(|e| format!("encode open_request: {e}"))?; + .map_err(|e| anyhow::anyhow!("encode open_request: {e}"))?; let writer = socket .try_clone() - .map_err(|e| format!("clone for write: {e}"))?; + .map_err(|e| anyhow::anyhow!("clone for write: {e}"))?; write_all_nonblocking_stream(&writer, &frame, BOUNDED_READ_TIMEOUT) - .map_err(|e| format!("write open_request: {e}"))?; + .map_err(|e| anyhow::anyhow!("write open_request: {e}"))?; Ok(picker_version) } @@ -3614,21 +3613,21 @@ impl crate::clipd_host::niri::FocusedWindowProvider for NiriQueryProvider { // ─── Control socket helpers ─────────────────────────────────────────────────── -fn control_socket_path() -> Result { +fn control_socket_path() -> anyhow::Result { let runtime = std::env::var_os("XDG_RUNTIME_DIR") - .ok_or_else(|| "XDG_RUNTIME_DIR is required for d2b-clipd control socket".to_owned())?; + .ok_or_else(|| anyhow::anyhow!("XDG_RUNTIME_DIR is required for d2b-clipd control socket"))?; Ok(PathBuf::from(runtime).join("d2b-clipd/clipd.sock")) } #[allow(clippy::disallowed_methods, reason = "CLI-only path")] -fn install_control_socket_parent(socket: &Path) -> Result<(), String> { +fn install_control_socket_parent(socket: &Path) -> anyhow::Result<()> { let parent = socket .parent() - .ok_or_else(|| format!("control socket has no parent: {}", socket.display()))?; + .ok_or_else(|| anyhow::anyhow!("control socket has no parent: {}", socket.display()))?; std::fs::create_dir_all(parent) - .map_err(|e| format!("create control socket dir {}: {e}", parent.display()))?; + .map_err(|e| anyhow::anyhow!("create control socket dir {}: {e}", parent.display()))?; std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700)) - .map_err(|e| format!("chmod control socket dir {}: {e}", parent.display()))?; + .map_err(|e| anyhow::anyhow!("chmod control socket dir {}: {e}", parent.display()))?; let _ = std::fs::remove_file(socket); Ok(()) } @@ -3649,20 +3648,20 @@ fn read_bounded_line( stream: &UnixStream, max_frame_bytes: usize, timeout: Duration, -) -> Result, String> { +) -> anyhow::Result> { let deadline = Instant::now() + timeout; let mut stream = stream .try_clone() - .map_err(|e| format!("clone stream: {e}"))?; + .map_err(|e| anyhow::anyhow!("clone stream: {e}"))?; let mut out = Vec::new(); loop { let mut byte = [0_u8; 1]; match stream.read(&mut byte) { - Ok(0) => return Err("peer closed before newline".to_owned()), + Ok(0) => return Err(anyhow::anyhow!("peer closed before newline")), Ok(_) => { out.push(byte[0]); if out.len() > max_frame_bytes { - return Err(format!("frame exceeds {max_frame_bytes} bytes")); + return Err(anyhow::anyhow!("frame exceeds {max_frame_bytes} bytes")); } if byte[0] == b'\n' { return Ok(out); @@ -3672,15 +3671,15 @@ fn read_bounded_line( wait_readable(&stream, deadline)?; } Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {} - Err(error) => return Err(error.to_string()), + Err(error) => return Err(anyhow::anyhow!("{error}")), } } } -fn wait_readable(fd: &Fd, deadline: Instant) -> Result<(), String> { +fn wait_readable(fd: &Fd, deadline: Instant) -> anyhow::Result<()> { let now = Instant::now(); if now >= deadline { - return Err("timed out waiting for readability".to_owned()); + return Err(anyhow::anyhow!("timed out waiting for readability")); } let timeout = deadline .saturating_duration_since(now) @@ -3691,10 +3690,10 @@ fn wait_readable(fd: &Fd, deadline: Instant) -> Result<() PollFlags::IN | PollFlags::ERR | PollFlags::HUP, )]; match poll(&mut fds, timeout) { - Ok(0) => Err("timed out waiting for readability".to_owned()), + Ok(0) => Err(anyhow::anyhow!("timed out waiting for readability")), Ok(_) => Ok(()), Err(rustix::io::Errno::INTR) => Ok(()), - Err(error) => Err(error.to_string()), + Err(error) => Err(anyhow::anyhow!("{error}")), } } @@ -3808,7 +3807,7 @@ fn should_suppress_bridge_selection_echo( // ─── Arg parsing ───────────────────────────────────────────────────────────── -fn parse_args(args: impl IntoIterator) -> Result { +fn parse_args(args: impl IntoIterator) -> anyhow::Result { let mut config = None; let mut picker = None; let mut bridge_root = None; @@ -3821,41 +3820,40 @@ fn parse_args(args: impl IntoIterator) -> Result { "--config" => { config = Some(PathBuf::from( iter.next() - .ok_or_else(|| "--config requires a path".to_owned())?, + .ok_or_else(|| anyhow::anyhow!("--config requires a path"))?, )); } "--picker" => { picker = Some(PathBuf::from( iter.next() - .ok_or_else(|| "--picker requires a path".to_owned())?, + .ok_or_else(|| anyhow::anyhow!("--picker requires a path"))?, )); } "--bridge-root" => { bridge_root = Some(PathBuf::from( iter.next() - .ok_or_else(|| "--bridge-root requires a path".to_owned())?, + .ok_or_else(|| anyhow::anyhow!("--bridge-root requires a path"))?, )); } "--niri-socket" => { niri_socket = Some(PathBuf::from( iter.next() - .ok_or_else(|| "--niri-socket requires a path".to_owned())?, + .ok_or_else(|| anyhow::anyhow!("--niri-socket requires a path"))?, )); } "--check-config" => check_config = true, "--oneshot" => oneshot = true, "--help" | "-h" => { - return Err("usage: d2b-clipd --config --bridge-root \ - [--picker ] [--niri-socket ] [--check-config] [--oneshot]" - .to_owned()); + return Err(anyhow::anyhow!("usage: d2b-clipd --config --bridge-root \ + [--picker ] [--niri-socket ] [--check-config] [--oneshot]")); } - other => return Err(format!("unknown argument: {other}")), + other => return Err(anyhow::anyhow!("unknown argument: {other}")), } } Ok(Args { - config: config.ok_or_else(|| "--config is required".to_owned())?, + config: config.ok_or_else(|| anyhow::anyhow!("--config is required"))?, picker, - bridge_root: bridge_root.ok_or_else(|| "--bridge-root is required".to_owned())?, + bridge_root: bridge_root.ok_or_else(|| anyhow::anyhow!("--bridge-root is required"))?, niri_socket, check_config, oneshot, @@ -4067,7 +4065,7 @@ mod tests { let error = wait_for_target_focus(&target, Duration::ZERO, Duration::ZERO, || Ok(None)) .expect_err("missing focus must fail"); - assert_eq!(error, "focused destination was not restored before timeout"); + assert_eq!(error.to_string(), "focused destination was not restored before timeout"); } #[test] @@ -4093,7 +4091,7 @@ mod tests { ) .expect_err("missing picker must fail"); - assert_eq!(err, ReasonCode::PickerNotConfigured.as_str()); + assert_eq!(err.to_string(), ReasonCode::PickerNotConfigured.as_str()); assert!(matches!(fallback.state(), FallbackState::Idle)); assert_eq!(notifier.notifications.len(), 1); assert!(notifier.notifications[0].body.contains("clipboard picker")); @@ -4397,7 +4395,7 @@ mod tests { assert!( parse_bridge_peers(&config) .expect_err("unsafe-local must not be VM-shaped") - .contains("must not carry legacyVmName") + .to_string().contains("must not carry legacyVmName") ); } @@ -4440,7 +4438,7 @@ mod tests { #[test] fn rejects_unknown_args() { let err = parse_args(["--wat".to_owned()]).expect_err("unknown"); - assert!(err.contains("unknown argument")); + assert!(err.to_string().contains("unknown argument")); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -4512,7 +4510,7 @@ mod tests { writer.write_all(&bytes).expect("write"); let err = read_bounded_line(&reader, CONTROL_MAX_FRAME_BYTES, Duration::from_secs(1)) .expect_err("overlong"); - assert!(err.contains("frame exceeds")); + assert!(err.to_string().contains("frame exceeds")); } #[test] @@ -4521,7 +4519,7 @@ mod tests { reader.set_nonblocking(true).expect("nonblocking"); let err = read_bounded_line(&reader, CONTROL_MAX_FRAME_BYTES, Duration::from_millis(5)) .expect_err("timeout"); - assert!(err.contains("timed out")); + assert!(err.to_string().contains("timed out")); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -4973,6 +4971,6 @@ mod tests { current + 1 }; let err = validate_bridge_peer(&left, wrong).expect_err("wrong uid rejected"); - assert!(err.contains("uid mismatch")); + assert!(err.to_string().contains("uid mismatch")); } } From 928dc7755b2ae0433d177f081bc442fa9d4134c0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:26 -0700 Subject: [PATCH 352/726] contracts-resource: drop zero-consumer type aliases --- packages/d2b-contracts-resource/src/v3/device.rs | 15 --------------- packages/d2b-contracts-resource/src/v3/network.rs | 3 --- 2 files changed, 18 deletions(-) diff --git a/packages/d2b-contracts-resource/src/v3/device.rs b/packages/d2b-contracts-resource/src/v3/device.rs index c50bab58a..901e08673 100644 --- a/packages/d2b-contracts-resource/src/v3/device.rs +++ b/packages/d2b-contracts-resource/src/v3/device.rs @@ -125,9 +125,6 @@ impl DeviceAuthorityDescriptor { redacted_debug!(DeviceAuthorityDescriptor); -/// Short alias used by Provider descriptors. -pub type AuthorityDescriptor = DeviceAuthorityDescriptor; - /// Core-derived opaque identity for one physical device backing. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] @@ -147,9 +144,6 @@ impl DeviceAuthorityKey { redacted_debug!(DeviceAuthorityKey); -/// Short alias for the Core-derived physical backing key. -pub type OpaqueAuthorityKey = DeviceAuthorityKey; - impl<'de> Deserialize<'de> for DeviceAuthorityKey { fn deserialize>(deserializer: D) -> Result { let bytes = <[u8; 32]>::deserialize(deserializer)?; @@ -756,9 +750,6 @@ impl DeviceStatusResource { redacted_debug!(DeviceStatusResource); -/// Alias used by ResourceType status adapters. -pub type DeviceStatus = DeviceStatusResource; - impl<'de> Deserialize<'de> for DeviceStatusResource { fn deserialize>(deserializer: D) -> Result { #[derive(Deserialize)] @@ -914,9 +905,6 @@ impl DeviceResourceVerb { } } -/// Alias used by RBAC policy code. -pub type DeviceRbacVerb = DeviceResourceVerb; - /// Closed Device effect operation classes used by Core's adapter. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, @@ -1115,9 +1103,6 @@ pub const DEVICE_OTEL_RESOURCE_ATTRIBUTES: [&str; 2] = ["d2b.zone", "d2b.provide /// Device telemetry contract version. pub const DEVICE_TELEMETRY_CONTRACT_VERSION: &str = "device-telemetry/v1"; -/// Alias used by semantic telemetry adapters. -pub type DeviceTelemetryLabels = DeviceMetricLabels; - const fn one() -> u32 { 1 } diff --git a/packages/d2b-contracts-resource/src/v3/network.rs b/packages/d2b-contracts-resource/src/v3/network.rs index 7804b0677..6a3ba332a 100644 --- a/packages/d2b-contracts-resource/src/v3/network.rs +++ b/packages/d2b-contracts-resource/src/v3/network.rs @@ -942,9 +942,6 @@ impl<'de> Deserialize<'de> for NetworkAttachmentEntry { } } -/// Canonical authored Network attachment spec. -pub type AttachmentSpec = NetworkAttachmentEntry; - /// The Network ResourceType base spec. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] From 96be9307a59ae53987590301c603fff3f1aa5e06 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:28 -0700 Subject: [PATCH 353/726] d2bd: refuse compose-once process provider attach collisions --- packages/d2bd/src/resource_plane_v3.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 38d88c46c..ba0a91b09 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -1955,7 +1955,10 @@ impl ConstructionInputs { state.pidfd_table.clone(), ), ); - let _ = state.provider_runtime.attach_process_providers(Arc::clone(&providers)); + state + .provider_runtime + .attach_process_providers(Arc::clone(&providers)) + .map_err(|error| PlaneError::Authority(error.into()))?; providers } }; From 7ef81ed6b2c44a28a570b6ce99a4cdea49f27054 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:39 -0700 Subject: [PATCH 354/726] gpu-provider: derive video-started state from identity --- packages/d2b-provider-device-gpu/src/controller.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/d2b-provider-device-gpu/src/controller.rs b/packages/d2b-provider-device-gpu/src/controller.rs index e91699e5f..24c19f53c 100644 --- a/packages/d2b-provider-device-gpu/src/controller.rs +++ b/packages/d2b-provider-device-gpu/src/controller.rs @@ -76,7 +76,6 @@ pub struct GpuController { phase: GpuPhase, finalizer: bool, gpu_role: Option, - video_started: bool, admission: Option, authority_lease: Option, ticket: Option, @@ -115,7 +114,6 @@ impl GpuController { phase: GpuPhase::Pending, finalizer: true, gpu_role: None, - video_started: false, admission: Some(admission), authority_lease: None, ticket: None, @@ -338,7 +336,6 @@ impl GpuController { ); GpuControllerError::Effect(error) })?; - self.video_started = true; if let Err(error) = validate_started_identity( &identity, GpuProcessRole::Video, @@ -467,7 +464,6 @@ matched.push(observed); self.phase = GpuPhase::Quarantined; return Err(GpuControllerError::Quarantined); } - self.video_started = true; self.video_identity = Some(identity); } role => { @@ -545,7 +541,6 @@ matched.push(observed); self.gpu_identity = None; self.ticket = None; self.gpu_role = None; - self.video_started = false; self.gpu_closure = None; self.video_closure = None; self.finalizer = false; @@ -582,7 +577,7 @@ impl fmt::Debug for GpuController { .field("phase", &self.phase) .field("finalizer", &self.finalizer) .field("gpu_role", &self.gpu_role) - .field("video_started", &self.video_started) + .field("video_started", &self.video_identity.is_some()) .field("has_authority", &self.authority_lease.is_some()) .field("has_gpu_identity", &self.gpu_identity.is_some()) .field("has_video_identity", &self.video_identity.is_some()) From 6c66b83ead4b55bb509377d529b401b5aee6108d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:46 -0700 Subject: [PATCH 355/726] d2b-provider-activation-nixos: narrow the driver type to the crate --- packages/d2b-provider-activation-nixos/src/driver.rs | 2 +- packages/d2b-provider-activation-nixos/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-activation-nixos/src/driver.rs b/packages/d2b-provider-activation-nixos/src/driver.rs index bf4481b8e..5af118b11 100644 --- a/packages/d2b-provider-activation-nixos/src/driver.rs +++ b/packages/d2b-provider-activation-nixos/src/driver.rs @@ -423,7 +423,7 @@ impl ResourceDriverFactory for ActivationDriverFactory { // --------------------------------------------------------------------------- /// One `NixosGeneration` resource's driver. -pub struct ActivationDriver { +pub(crate) struct ActivationDriver { zone: String, effects: Arc, verifier: Arc, diff --git a/packages/d2b-provider-activation-nixos/src/lib.rs b/packages/d2b-provider-activation-nixos/src/lib.rs index aac4bb43b..c4f39ae91 100644 --- a/packages/d2b-provider-activation-nixos/src/lib.rs +++ b/packages/d2b-provider-activation-nixos/src/lib.rs @@ -35,7 +35,7 @@ pub use controller::{ }; pub use driver::{ ACTIVATION_CREATIONS, ACTIVATION_RUNNER_CREATION, ACTIVATION_TYPE_NAME, - ActivationDriver, ActivationDriverArgs, ActivationDriverEffects, ActivationDriverError, + ActivationDriverArgs, ActivationDriverEffects, ActivationDriverError, ActivationDriverFactory, ActivationDriverStatus, HostHandoffResult, RUNNER_PROVIDER_REF, RUNNER_TYPE_NAME, activation_descriptor, activation_spec_decoder, }; From d58f183d5a167d482a652be46ffbfb578c33ca44 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:46 -0700 Subject: [PATCH 356/726] gpu-provider: deny unknown fields on gpu argv inputs --- .../d2b-provider-device-gpu/src/gpu_argv.rs | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-device-gpu/src/gpu_argv.rs b/packages/d2b-provider-device-gpu/src/gpu_argv.rs index ef9520c68..4138418b0 100644 --- a/packages/d2b-provider-device-gpu/src/gpu_argv.rs +++ b/packages/d2b-provider-device-gpu/src/gpu_argv.rs @@ -52,7 +52,7 @@ impl GpuContextType { /// Display config; one entry per virtual display. The audit shape is /// `[{"hidden":true}]` (single hidden display). #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct GpuDisplayConfig { /// Whether the display surface is hidden from the host /// compositor. Audit shape: `true` (the cross-domain handoff @@ -63,7 +63,7 @@ pub struct GpuDisplayConfig { /// `--params` payload. Rendered as compact JSON (no spaces) so the /// audit-shape diff stays byte-stable. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct GpuParams { /// Colon-separated context types (`virgl:virgl2:cross-domain`). pub context_types: Vec, @@ -77,7 +77,7 @@ pub struct GpuParams { /// All inputs required to render the `crosvm device gpu` argv. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct GpuArgvInput { /// Absolute store path to the `crosvm` binary. pub crosvm_binary_path: String, @@ -374,6 +374,49 @@ mod tests { } } + #[test] + fn rejects_unknown_fields() { + let json = r#"{ + "crosvmBinaryPath": "/nix/store/GPUGPU-gpu-crosvm/bin/crosvm", + "vmName": "corp-vm", + "socketPath": "/run/d2b/vms/corp-vm/gpu.sock", + "waylandSock": "/run/d2b-gpu/corp-vm/wayland-0", + "params": { + "context-types": ["virgl", "virgl2", "cross-domain"], + "displays": [{"hidden": true}], + "egl": true, + "vulkan": true + }, + "extraArgs": [] + }"#; + let parsed = serde_json::from_str::(json); + assert!(parsed.is_ok(), "baseline shape must still parse: {parsed:?}"); + let top_level = json.replace( + "\"extraArgs\": []", + "\"extraArgs\": [], \"unexpectedField\": 1", + ); + assert!( + serde_json::from_str::(&top_level).is_err(), + "unknown top-level field must be rejected" + ); + let nested = json.replace( + "\"context-types\": [\"virgl\", \"virgl2\", \"cross-domain\"]", + "\"context-types\": [\"virgl\", \"virgl2\", \"cross-domain\"], \"unexpected\": true", + ); + assert!( + serde_json::from_str::(&nested).is_err(), + "unknown field inside params must be rejected" + ); + let display = json.replace( + "\"displays\": [{\"hidden\": true}]", + "\"displays\": [{\"hidden\": true, \"unexpected\": true}]", + ); + assert!( + serde_json::from_str::(&display).is_err(), + "unknown field inside a display config must be rejected" + ); + } + #[test] fn extra_args_appended_in_order() { let mut input = audit_input(); From 4cccad18738cf0337a8ddd3f925f45265480afc4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:56 -0700 Subject: [PATCH 357/726] d2b-provider-activation-nixos: privatize the runner resource type const --- packages/d2b-provider-activation-nixos/src/controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-activation-nixos/src/controller.rs b/packages/d2b-provider-activation-nixos/src/controller.rs index b98af6ea8..156102044 100644 --- a/packages/d2b-provider-activation-nixos/src/controller.rs +++ b/packages/d2b-provider-activation-nixos/src/controller.rs @@ -11,7 +11,7 @@ use sha2::{Digest, Sha256}; /// The target-local Process template used for activation effects. pub const ACTIVATION_RUNNER_TEMPLATE: &str = "activation-nixos-runner"; /// The generic one-shot process resource type used for activation effects. -pub const ACTIVATION_RUNNER_RESOURCE_TYPE: &str = "EphemeralProcess"; +const ACTIVATION_RUNNER_RESOURCE_TYPE: &str = "EphemeralProcess"; /// Caller role derived from the authenticated daemon request. #[derive(Debug, Clone, Copy, PartialEq, Eq)] From 0b4b29a1d76775ec94d894c1bdabee41868784ba Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:58 -0700 Subject: [PATCH 358/726] audit: fold the cli and xtask slice --- .../2026-09-24-rust-skills-audit/ledger.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 688b8545e..ea7fe4909 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -285,7 +285,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_op` | | | | `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | escalated | U1 | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | wave 0 applied the panicking constructor member (RS-0516); the five remaining provider-crate zone/key_ref member sites are the family wave's | U5 | | `RS-0263` | `type` | `d2b` | low | actionable | leaf | | | | `context.rs:713, context.rs:2751, context.rs:801` | | | -| `RS-0264` | `type` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/exec.rs:90, packages/d2b/src/exec.rs:345, packages/d2b/src/endpoint.rs:34` | | | +| `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | | `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | | | | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | | | | `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:889-892` | | | | `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_co` | | | @@ -358,14 +358,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | | `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | | `RS-0314` | `type` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557` | | | -| `RS-0313` | `type` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/provider_crate_policy.rs:5104, packages/xtask/src/provider_crate_policy` | | | +| `RS-0313` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 1d692db3d | packages/xtask/src/provider_crate_policy.rs | FamilyKnowledgeSignal gains typed count: Option; ServerState site fills it and drops the serialized-count text; renderer matches class without the parse;the ratchet JSON stays byte-identical (t | | | `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | -| `RS-0312` | `type` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:288, packages/xtask/src/gen_layer_catalogs.rs:515` | | | +| `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option> (Builder::spawn error propagated via Ok(...)?), replacing the expect panic; the two test call sites unwrap with expect. | | | `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 75c49e784 | packages/d2bd-runtime/src/console_session.rs | Deleted panicking impl Default for ConsoleClientHandle (census: no ConsoleClientHandle::default() callers in workspace). | | | `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | a09140432 | packages/d2bd-runtime/src/daemon_version.rs | version-file read failures typed (VersionFileReadError); check + tests green | | -| `RS-0543` | `err` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/delivery/recovery.rs:384, packages/xtask/src/delivery/recovery.rs:1610,` | | | +| `RS-0543` | `err` | `xtask` | medium | actionable | leaf | applied | U3 | 7194d24e9 | packages/xtask/src/delivery/recovery.rs | RecoveryError::Read added for fs open/read failures; Json(String) now carries the bounded serde detail (field names/positions only via error.to_string(), never payload values, keeping the redaction co | | | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composi` | | | @@ -624,15 +624,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | | | | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | | | | `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | | | | `src/content.rs:38-39, src/content.rs:106-107, src/content.rs:203-204, src/content.rs:239-2` | | | | `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | -| `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | | | | `manager_backend.rs:744-745` | | | +| `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | | `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | GatewayGuestConfigFile/GatewayGuestRelayConfigFile need deny_unknown_fields + config-typo test. Not edited: budget exhausted. | | | `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d` | | | | `RS-0577` | `serde` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | declared_fd_kind now matches the seven kebab-case FdKind spellings directly (fifo/socket/char-device/block-device/any/regular/directory) instead of allocating a serde_json::Value::String; behavior ide | | | `RS-0578` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 3e78efe56 | packages/d2bd-runtime/src/wire.rs | parse_request now dispatches the 17 plain verbs (list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio) throug | | | `RS-0579` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | version-file write failures reported through tracing | | -| `RS-0580` | `serde` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/service_catalog.rs:22, packages/xtask/src/provider_registration_authori` | | | +| `RS-0580` | `serde` | `xtask` | medium | actionable | leaf | applied | U3 | 9ccb9c694 | packages/xtask/src/service_catalog.rs | deny_unknown_fields added to DeclarationFile; all six committed service-catalog.json files verified to carry only the declared keys (provider/providerRef/providerUid/services); new test an_unknown_dec | | | `RS-0582` | `serde` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111` | | | -| `RS-0581` | `serde` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/resource_type_authority.rs:179, packages/xtask/src/resource_type_author` | | | +| `RS-0581` | `serde` | `xtask` | low | actionable | leaf | applied-variant | U3 | 341c4fb5e | packages/xtask/src/resource_type_authority.rs | rename_all = camelCase added to DeclarationFile and TypeDeclaration; per-field resourceType rename deleted;the crate per-field rename must stay because the wire key 'crate' is a Rust keyword that rena | | | `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:25` | | | | `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | | `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activa` | | | From 4efbf8ea571d0af5ed01d802c54773fab38a640c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:43:59 -0700 Subject: [PATCH 359/726] gpu-provider: make declared port deps opaque via sidecar struct --- .../src/effects_service.rs | 112 ++++++++++++++---- packages/d2bd/src/shared_provider_effects.rs | 50 ++++---- 2 files changed, 115 insertions(+), 47 deletions(-) diff --git a/packages/d2b-provider-device-gpu/src/effects_service.rs b/packages/d2b-provider-device-gpu/src/effects_service.rs index 5e245222a..ada46111d 100644 --- a/packages/d2b-provider-device-gpu/src/effects_service.rs +++ b/packages/d2b-provider-device-gpu/src/effects_service.rs @@ -458,39 +458,103 @@ impl GpuLifecycleEffectPort for DeclaredWorkerGpuPort<'_> { } } +/// The daemon-supplied dependencies of one declared GPU worker port. +/// +/// The field set is opaque: callers build the value through +/// [`DeclaredWorkerGpuPortDeps::new`] and the port reads it on +/// construction. +pub struct DeclaredWorkerGpuPortDeps<'a> { + runtime: Arc, + gpu_authority_leases: Arc>>, + runtime_handle: tokio::runtime::Handle, + children: &'a dyn SharedProviderChildSurface, +} + +impl<'a> DeclaredWorkerGpuPortDeps<'a> { + /// Build the daemon-supplied dependencies for one declared GPU worker + /// port. + /// + /// # Arguments + /// + /// - `runtime`: the daemon-supplied GPU runtime facet. + /// - `gpu_authority_leases`: the per-resource authority lease cache + /// the calling driver owns. + /// - `runtime_handle`: the runtime handle the sync port drives its + /// async child surface on. + /// - `children`: manager-routed child surface of the requiring Device. + pub fn new( + runtime: Arc, + gpu_authority_leases: Arc>>, + runtime_handle: tokio::runtime::Handle, + children: &'a dyn SharedProviderChildSurface, + ) -> Self { + Self { + runtime, + gpu_authority_leases, + runtime_handle, + children, + } + } +} + /// The port's per-resource construction inputs, supplied by the calling /// driver (the Device family's runtime) from the row and the driver state. +/// +/// The field set is opaque: callers build the value through +/// [`DeclaredWorkerGpuPortArgs::new`] and the port reads it on +/// construction. pub struct DeclaredWorkerGpuPortArgs<'a> { - /// The daemon-supplied GPU runtime facet. - pub runtime: Arc, - /// The per-resource authority lease cache the driver owns. - pub gpu_authority_leases: Arc>>, - /// The runtime handle the sync port drives its async child surface on. - pub runtime_handle: tokio::runtime::Handle, - /// Manager-routed child surface of the requiring Device. - pub children: &'a dyn SharedProviderChildSurface, - /// The Zone the Device row lives in. - pub zone: String, - /// The Device row's reference. - pub device_ref: ResourceRef, - /// The Device row's uid. - pub device_uid: ResourceUid, - /// The Device row's owning holder reference. - pub holder_ref: ResourceRef, - /// The Device row's generation. - pub generation: ResourceGeneration, - /// The reconcile operation id the launch ticket scopes to. - pub operation_id: String, + deps: DeclaredWorkerGpuPortDeps<'a>, + zone: String, + device_ref: ResourceRef, + device_uid: ResourceUid, + holder_ref: ResourceRef, + generation: ResourceGeneration, + operation_id: String, +} + +impl<'a> DeclaredWorkerGpuPortArgs<'a> { + /// Build the construction inputs for one declared GPU worker port. + /// + /// # Arguments + /// + /// - `deps`: the daemon-supplied dependencies. + /// - `zone`: the Zone the Device row lives in. + /// - `device_ref`: the Device row's reference. + /// - `device_uid`: the Device row's uid. + /// - `holder_ref`: the Device row's owning holder reference. + /// - `generation`: the Device row's generation. + /// - `operation_id`: the reconcile operation id the launch ticket + /// scopes to. + pub fn new( + deps: DeclaredWorkerGpuPortDeps<'a>, + zone: String, + device_ref: ResourceRef, + device_uid: ResourceUid, + holder_ref: ResourceRef, + generation: ResourceGeneration, + operation_id: String, + ) -> Self { + Self { + deps, + zone, + device_ref, + device_uid, + holder_ref, + generation, + operation_id, + } + } } impl<'a> DeclaredWorkerGpuPort<'a> { /// Build the port from the calling driver's construction inputs. pub fn new(args: DeclaredWorkerGpuPortArgs<'a>) -> Self { Self { - runtime: args.runtime, - gpu_authority_leases: args.gpu_authority_leases, - runtime_handle: args.runtime_handle, - children: args.children, + runtime: args.deps.runtime, + gpu_authority_leases: args.deps.gpu_authority_leases, + runtime_handle: args.deps.runtime_handle, + children: args.deps.children, zone: args.zone, device_ref: args.device_ref, device_uid: args.device_uid, diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 68c23ff1f..f15697c42 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -2134,18 +2134,20 @@ impl ProductionSharedProviderEffects { .cloned() .ok_or(SharedProviderEffectError::Unavailable)?; let mut port = d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPort::new( - d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortArgs { - runtime: Arc::clone(&gpu_facets.runtime), - gpu_authority_leases: Arc::clone(&state.gpu_authority_leases), - runtime_handle: tokio::runtime::Handle::current(), - children: request.children, - zone: self.zone.as_str().to_owned(), - device_ref: key_ref(&request.target).clone(), - device_uid: request.uid.clone(), + d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortArgs::new( + d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortDeps::new( + Arc::clone(&gpu_facets.runtime), + Arc::clone(&state.gpu_authority_leases), + tokio::runtime::Handle::current(), + request.children, + ), + self.zone.as_str().to_owned(), + key_ref(&request.target).clone(), + request.uid.clone(), holder_ref, - generation: request.generation, - operation_id: request.operation_id.clone(), - }, + request.generation, + request.operation_id.clone(), + ), ); let result = controller .reconcile_lifecycle(&mut port) @@ -2598,18 +2600,20 @@ impl ProductionSharedProviderEffects { .cloned() .ok_or(SharedProviderEffectError::Unavailable)?; let mut port = d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPort::new( - d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortArgs { - runtime: Arc::clone(&gpu_facets.runtime), - gpu_authority_leases: Arc::clone(&state.gpu_authority_leases), - runtime_handle: tokio::runtime::Handle::current(), - children: request.children, - zone: self.zone.as_str().to_owned(), - device_ref: key_ref(&request.target).clone(), - device_uid: request.uid.clone(), - holder_ref: admission.owner().holder_ref().clone(), - generation: admission.owner().generation(), - operation_id: request.operation_id.clone(), - }, + d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortArgs::new( + d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortDeps::new( + Arc::clone(&gpu_facets.runtime), + Arc::clone(&state.gpu_authority_leases), + tokio::runtime::Handle::current(), + request.children, + ), + self.zone.as_str().to_owned(), + key_ref(&request.target).clone(), + request.uid.clone(), + admission.owner().holder_ref().clone(), + admission.owner().generation(), + request.operation_id.clone(), + ), ); let result = controller.finalize_lifecycle(&mut port).map_err(|error| { tracing::debug!( From 5f7c5aae53b9067b29d6927387c20fab3b5260ba Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:44:19 -0700 Subject: [PATCH 360/726] tpm: validate settings through the shared swtpm argv error --- packages/d2b-provider-device-tpm/src/lib.rs | 11 +++------ .../d2b-provider-device-tpm/src/runner.rs | 23 ++++--------------- .../tests/conformance.rs | 2 +- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/packages/d2b-provider-device-tpm/src/lib.rs b/packages/d2b-provider-device-tpm/src/lib.rs index 12f02a3d3..887fef4d3 100644 --- a/packages/d2b-provider-device-tpm/src/lib.rs +++ b/packages/d2b-provider-device-tpm/src/lib.rs @@ -7,12 +7,10 @@ #![deny(missing_docs)] -mod migration; mod resource_controller; mod resource_effect; mod resources; mod runner; -mod state; pub mod swtpm_argv; pub mod vocabulary; pub mod effects_service; @@ -21,7 +19,6 @@ pub mod facets; #[cfg(any(test, feature = "test-support"))] pub mod test_support; -pub use migration::LegacyMigrationOutcome; pub use resource_controller::{ TPM_MAX_REPAIR_INTERVAL_SECS, TPM_REPAIR_INTERVAL_SECS, TpmResourceController, TpmResourceControllerError, TpmResourceOutcome, TpmResourcePhase, TpmRunnerContract, @@ -32,12 +29,10 @@ pub use resources::{ build_swtpm_flush_spec, build_swtpm_process_spec, build_tpm_state_volume_resource, build_tpm_state_volume_spec, }; -pub use runner::{SwtpmArgvError, SwtpmSettings}; -pub use state::{ - StateDirIntent, StateDirectoryToken, StateOwnerToken, TamperMarkerToken, -}; +pub use runner::SwtpmSettings; pub use swtpm_argv::{ - SwtpmArgvInput, SwtpmIoctlFlushInput, generate_swtpm_argv, generate_swtpm_ioctl_flush_argv, + SwtpmArgvError, SwtpmArgvInput, SwtpmIoctlFlushInput, generate_swtpm_argv, + generate_swtpm_ioctl_flush_argv, }; /// Provider identity. diff --git a/packages/d2b-provider-device-tpm/src/runner.rs b/packages/d2b-provider-device-tpm/src/runner.rs index baa069f9c..4288c3ef5 100644 --- a/packages/d2b-provider-device-tpm/src/runner.rs +++ b/packages/d2b-provider-device-tpm/src/runner.rs @@ -1,8 +1,8 @@ //! Signed swtpm settings. -use core::fmt; use serde::{Deserialize, Serialize}; +use crate::swtpm_argv::SwtpmArgvError; use crate::{MAX_SWTPM_LOG_LEVEL, MIN_SWTPM_LOG_LEVEL}; /// Device-tpm desired settings. There is no path, artifact, or flush-toggle @@ -32,7 +32,9 @@ impl SwtpmSettings { /// outside the frozen bound. pub const fn validate(self) -> Result { if self.log_level < MIN_SWTPM_LOG_LEVEL || self.log_level > MAX_SWTPM_LOG_LEVEL { - Err(SwtpmArgvError::LogLevelOutOfRange) + Err(SwtpmArgvError::LogLevelOutOfRange { + level: self.log_level, + }) } else { Ok(self) } @@ -42,20 +44,3 @@ impl SwtpmSettings { fn default_log_level() -> u8 { 20 } - -/// Closed argv-generation failures. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SwtpmArgvError { - /// The log level is outside the signed Provider schema range. - LogLevelOutOfRange, -} - -impl fmt::Display for SwtpmArgvError { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str(match self { - Self::LogLevelOutOfRange => "swtpm-log-level-out-of-range", - }) - } -} - -impl std::error::Error for SwtpmArgvError {} diff --git a/packages/d2b-provider-device-tpm/tests/conformance.rs b/packages/d2b-provider-device-tpm/tests/conformance.rs index 9ff57ceae..cbd55120c 100644 --- a/packages/d2b-provider-device-tpm/tests/conformance.rs +++ b/packages/d2b-provider-device-tpm/tests/conformance.rs @@ -9,6 +9,6 @@ fn settings_are_strict_and_bounded() { ); assert_eq!( SwtpmSettings { log_level: 0 }.validate(), - Err(SwtpmArgvError::LogLevelOutOfRange) + Err(SwtpmArgvError::LogLevelOutOfRange { level: 0 }) ); } From 524b8696cdb76e7d1bf949c586b60a2d34739dc1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:44:30 -0700 Subject: [PATCH 361/726] tpm: retire dead state-token and legacy-migration modules --- .../d2b-provider-device-tpm/src/migration.rs | 18 --- packages/d2b-provider-device-tpm/src/state.rs | 113 ------------------ 2 files changed, 131 deletions(-) delete mode 100644 packages/d2b-provider-device-tpm/src/migration.rs delete mode 100644 packages/d2b-provider-device-tpm/src/state.rs diff --git a/packages/d2b-provider-device-tpm/src/migration.rs b/packages/d2b-provider-device-tpm/src/migration.rs deleted file mode 100644 index 85d44efc8..000000000 --- a/packages/d2b-provider-device-tpm/src/migration.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! Opaque legacy swtpm adoption contract. - -/// Closed outcome of the broker-owned one-time legacy state adoption. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LegacyMigrationOutcome { - /// The legacy payload and marker were moved and committed. - Migrated, - /// The broker journal already proves the move was committed. - AlreadyMigrated, - /// Trusted inventory proved the Device was never provisioned. - NotApplicable, - /// A journal or lock is still in progress and can be replayed. - Pending, - /// The broker could not safely complete the migration. - Failed, - /// Source, destination, marker, or owner evidence was ambiguous. - Ambiguous, -} diff --git a/packages/d2b-provider-device-tpm/src/state.rs b/packages/d2b-provider-device-tpm/src/state.rs deleted file mode 100644 index e327201bb..000000000 --- a/packages/d2b-provider-device-tpm/src/state.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Opaque state-directory and tamper-marker contracts. - -use core::fmt; - -/// A Core-derived state-directory identity. -#[derive(Clone, PartialEq, Eq)] -pub struct StateDirectoryToken([u8; 32]); - -impl StateDirectoryToken { - /// Construct a token at the Core effect-adapter boundary. - pub const fn from_core(bytes: [u8; 32]) -> Self { - Self(bytes) - } - - /// Borrow the token for equality checks at the effect boundary. - pub const fn as_bytes(&self) -> &[u8; 32] { - &self.0 - } -} - -impl fmt::Debug for StateDirectoryToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("StateDirectoryToken()") - } -} - -/// A Core-derived identity-bound tamper marker. -#[derive(Clone, PartialEq, Eq)] -pub struct TamperMarkerToken([u8; 32]); - -impl TamperMarkerToken { - /// Construct a token at the Core effect-adapter boundary. - pub const fn from_core(bytes: [u8; 32]) -> Self { - Self(bytes) - } - - /// Borrow the token for equality checks at the effect boundary. - pub const fn as_bytes(&self) -> &[u8; 32] { - &self.0 - } -} - -impl fmt::Debug for TamperMarkerToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("TamperMarkerToken()") - } -} - -/// An opaque owner identity for the swtpm state principal. -#[derive(Clone, PartialEq, Eq)] -pub struct StateOwnerToken([u8; 16]); - -impl StateOwnerToken { - /// Construct a token at the Core effect-adapter boundary. - pub const fn from_core(bytes: [u8; 16]) -> Self { - Self(bytes) - } - - /// Borrow the owner identity for Core-side ticket binding. - pub const fn as_bytes(&self) -> &[u8; 16] { - &self.0 - } -} - -impl fmt::Debug for StateOwnerToken { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("StateOwnerToken()") - } -} - -/// The only state-directory intent a TPM Provider may submit. -#[derive(Clone, PartialEq, Eq)] -pub struct StateDirIntent { - directory: StateDirectoryToken, - marker: TamperMarkerToken, - owner: StateOwnerToken, -} - -impl StateDirIntent { - /// Construct an opaque state-directory hardening request. - pub const fn new( - directory: StateDirectoryToken, - marker: TamperMarkerToken, - owner: StateOwnerToken, - ) -> Self { - Self { - directory, - marker, - owner, - } - } - - /// Borrow the state-directory identity. - pub const fn directory(&self) -> &StateDirectoryToken { - &self.directory - } - - /// Borrow the identity-bound marker token. - pub const fn marker(&self) -> &TamperMarkerToken { - &self.marker - } - - /// Borrow the expected state owner token. - pub const fn owner(&self) -> &StateOwnerToken { - &self.owner - } -} - -impl fmt::Debug for StateDirIntent { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("StateDirIntent()") - } -} From 5fede02375f793037b647bc7e226792f77905333 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:44:34 -0700 Subject: [PATCH 362/726] azure-guest: model bootstrap admission as closed states --- .../src/bootstrap.rs | 100 ++++++++++++------ 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs index a2e3fdd09..2dfc3562f 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs @@ -71,23 +71,39 @@ pub enum BootstrapAdmissionState { } /// A single-use bootstrap admission. -pub struct BootstrapAdmission { - psk: Option, - expires_at_unix_ms: u64, - state: BootstrapAdmissionState, +/// +/// The admission is one of three closed states: a `Pending` admission +/// carries its secret and deadline; `Consumed` and `Expired` carry neither, +/// so an expired or replayed admission cannot be constructed with a +/// still-present secret. +pub enum BootstrapAdmission { + /// The admission has not been consumed yet. + Pending { + /// The one-time secret held only during delivery. + psk: BootstrapPsk, + /// The deadline unix timestamp (milliseconds) after which the + /// admission refuses consumption. + expires_at_unix_ms: u64, + }, + /// The admission has been consumed or exhausted by a failed attempt. + Consumed, + /// The admission refused consumption because its deadline elapsed. + Expired, } impl BootstrapAdmission { /// Create an admission record. pub fn new(psk: BootstrapPsk, expires_at_unix_ms: u64) -> Self { - Self { - psk: Some(psk), + Self::Pending { + psk, expires_at_unix_ms, - state: BootstrapAdmissionState::Pending, } } - /// Consume the PSK if the nonce is fresh and the deadline is valid. + /// Consume the PSK when the presented bytes match and the deadline is + /// valid. The admission becomes `Consumed` (or `Expired` when the + /// deadline elapsed) whether or not the PSK matches, so each admission + /// is single-use. /// /// # Errors /// @@ -101,38 +117,52 @@ impl BootstrapAdmission { presented: &[u8], now_unix_ms: u64, ) -> Result>, AzureVmError> { - if now_unix_ms >= self.expires_at_unix_ms { - tracing::warn!( - provider = "runtime-azure-virtual-machine", - "bootstrap PSK admission refused: admission expired" - ); - self.state = BootstrapAdmissionState::Expired; - self.psk = None; - return Err(AzureVmError::BootstrapPskExpired); - } - let Some(psk) = self.psk.take() else { - tracing::warn!( - provider = "runtime-azure-virtual-machine", - "bootstrap PSK admission refused: PSK replayed" - ); - self.state = BootstrapAdmissionState::Consumed; - return Err(AzureVmError::BootstrapPskReplayed); - }; - if !psk.matches(presented) { - tracing::warn!( - provider = "runtime-azure-virtual-machine", - "bootstrap handshake failed: presented PSK does not match admission" - ); - self.state = BootstrapAdmissionState::Consumed; - return Err(AzureVmError::BootstrapEnrollmentFailed); + match std::mem::replace(self, Self::Consumed) { + Self::Pending { + psk, + expires_at_unix_ms, + } => { + if now_unix_ms >= expires_at_unix_ms { + tracing::warn!( + provider = "runtime-azure-virtual-machine", + "bootstrap PSK admission refused: admission expired" + ); + *self = Self::Expired; + return Err(AzureVmError::BootstrapPskExpired); + } + if !psk.matches(presented) { + tracing::warn!( + provider = "runtime-azure-virtual-machine", + "bootstrap handshake failed: presented PSK does not match admission" + ); + return Err(AzureVmError::BootstrapEnrollmentFailed); + } + Ok(psk.consume()) + } + Self::Consumed => { + tracing::warn!( + provider = "runtime-azure-virtual-machine", + "bootstrap PSK admission refused: PSK replayed" + ); + Err(AzureVmError::BootstrapPskReplayed) + } + Self::Expired => { + tracing::warn!( + provider = "runtime-azure-virtual-machine", + "bootstrap PSK admission refused: admission expired" + ); + Err(AzureVmError::BootstrapPskExpired) + } } - self.state = BootstrapAdmissionState::Consumed; - Ok(psk.consume()) } /// Return the current admission state. pub const fn state(&self) -> BootstrapAdmissionState { - self.state + match self { + Self::Pending { .. } => BootstrapAdmissionState::Pending, + Self::Consumed => BootstrapAdmissionState::Consumed, + Self::Expired => BootstrapAdmissionState::Expired, + } } } From 0e51b3ad992c16f21fc4c18b46896701c9acc157 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:35:22 -0700 Subject: [PATCH 363/726] d2b-provider-zone-link: narrow unused pub surface --- packages/d2b-provider-zone-link/src/zone_links.rs | 7 +++++-- packages/d2b-provider-zone-link/src/zonelink.rs | 15 +++------------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/d2b-provider-zone-link/src/zone_links.rs b/packages/d2b-provider-zone-link/src/zone_links.rs index f69b26da6..22e14e1fd 100644 --- a/packages/d2b-provider-zone-link/src/zone_links.rs +++ b/packages/d2b-provider-zone-link/src/zone_links.rs @@ -86,7 +86,8 @@ pub const ZONE_LINK_ROUTE_ADMISSION_DEDUP_VERSION: u32 = 1; /// The set deliberately excludes `vm`, `zone`, `zone_id`, `zone_uid`, and /// `link_name_hash`, and every admitted value is drawn from a closed enum, so /// no ZoneLink, Zone, or resource identity can enter a label value. -pub const ZONE_LINK_METRIC_LABEL_KEYS: &[&str] = &["phase", "reason", "outcome"]; +#[cfg(test)] +pub(crate) const ZONE_LINK_METRIC_LABEL_KEYS: &[&str] = &["phase", "reason", "outcome"]; /// Child-local ZoneLink enrollment-and-session state. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1822,13 +1823,15 @@ impl core::fmt::Debug for ZoneLinkHandler { /// /// Every field is a closed enum, so no ZoneLink, Zone, or resource identity /// can reach a label value. +#[cfg(test)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ZoneLinkMetricSample { +pub(crate) struct ZoneLinkMetricSample { phase: ZoneLinkPhase, reason: Option, succeeded: bool, } +#[cfg(test)] impl ZoneLinkMetricSample { /// Build one sample from closed semantic inputs. pub const fn new(phase: ZoneLinkPhase, reason: Option, succeeded: bool) -> Self { diff --git a/packages/d2b-provider-zone-link/src/zonelink.rs b/packages/d2b-provider-zone-link/src/zonelink.rs index dee21bebc..74f8bb574 100644 --- a/packages/d2b-provider-zone-link/src/zonelink.rs +++ b/packages/d2b-provider-zone-link/src/zonelink.rs @@ -10,9 +10,9 @@ use crate::zone_links::{ZoneLinkCursor, ZoneLinkError}; use d2b_contracts_resource::v3::SchemaFingerprint; pub use crate::zone_links::{ - BootstrapPsk, SealedEnrollment, ZONE_LINK_METRIC_LABEL_KEYS, ZoneLinkEffect, ZoneLinkEvent, - ZoneLinkHandler, ZoneLinkKeyPolicy, ZoneLinkLimits, ZoneLinkMetricSample, ZoneLinkPhase, - ZoneLinkRecord, ZoneLinkRouteBinding, ZoneLinkSessionState, ZoneLinkStatus, + BootstrapPsk, SealedEnrollment, ZoneLinkEffect, ZoneLinkEvent, ZoneLinkHandler, + ZoneLinkKeyPolicy, ZoneLinkLimits, ZoneLinkPhase, ZoneLinkRecord, ZoneLinkRouteBinding, + ZoneLinkSessionState, ZoneLinkStatus, }; pub use d2b_contracts_zone_session::v3::zone_routing::{ ZoneLinkControllerGeneration, ZoneLinkRouteAdmissionRequest, @@ -351,15 +351,6 @@ impl ZoneLinkController { } } -/// Map the existing ZoneLink state machine's transport refusal into the -/// authority-owned quarantine vocabulary where appropriate. -pub const fn transport_error_is_quarantine(error: ZoneLinkError) -> bool { - matches!( - error, - ZoneLinkError::StaleCommitProof | ZoneLinkError::ReconcileInFlight - ) -} - #[cfg(test)] mod tests { use super::*; From a94ef37d6d90ed94e61a588fc89d3dd4355828e4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:44:55 -0700 Subject: [PATCH 364/726] d2b-provider-activation-nixos: name the refusal variant on verification warnings --- packages/d2b-provider-activation-nixos/src/controller.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/d2b-provider-activation-nixos/src/controller.rs b/packages/d2b-provider-activation-nixos/src/controller.rs index 156102044..2cea004de 100644 --- a/packages/d2b-provider-activation-nixos/src/controller.rs +++ b/packages/d2b-provider-activation-nixos/src/controller.rs @@ -580,30 +580,35 @@ impl ActivationTrust { ) -> Result<(), ActivationVerificationError> { if self.trust_epoch == 0 || self.trust_epoch != expected.trust_epoch { tracing::warn!( + refusal = ?ActivationVerificationError::TrustEpochMismatch, "activation verification refused: trust epoch mismatch", ); return Err(ActivationVerificationError::TrustEpochMismatch); } if self.revocation_ref != expected.revocation_ref { tracing::warn!( + refusal = ?ActivationVerificationError::RevocationRefMismatch, "activation verification refused: revocation reference mismatch", ); return Err(ActivationVerificationError::RevocationRefMismatch); } if self.revocation_status != TrustStatus::Clear || self.deny_status != TrustStatus::Clear { tracing::warn!( + refusal = ?ActivationVerificationError::TrustDenied, "activation verification refused: trust or deny status not clear", ); return Err(ActivationVerificationError::TrustDenied); } if self.publisher_root.is_empty() || self.publisher_root != expected.publisher_root { tracing::warn!( + refusal = ?ActivationVerificationError::PublisherRootMismatch, "activation verification refused: publisher root mismatch", ); return Err(ActivationVerificationError::PublisherRootMismatch); } if self.signature_id.is_empty() || self.signature_id != expected.signature_id { tracing::warn!( + refusal = ?ActivationVerificationError::SignatureIdMismatch, "activation verification refused: signature identifier mismatch", ); return Err(ActivationVerificationError::SignatureIdMismatch); @@ -613,6 +618,7 @@ impl ActivationTrust { || activation_catalog_digest != expected.artifact_catalog_digest { tracing::warn!( + refusal = ?ActivationVerificationError::ArtifactCatalogDigestMismatch, "activation verification refused: artifact catalog digest mismatch", ); return Err(ActivationVerificationError::ArtifactCatalogDigestMismatch); @@ -620,12 +626,14 @@ impl ActivationTrust { let actual_artifact_digest = sha256_digest(artifact_bytes); if actual_artifact_digest != expected.artifact_digest { tracing::warn!( + refusal = ?ActivationVerificationError::ArtifactDigestMismatch, "activation verification refused: artifact digest mismatch", ); return Err(ActivationVerificationError::ArtifactDigestMismatch); } if self.public_key.len() != 32 || self.signature.len() != 64 { tracing::warn!( + refusal = ?ActivationVerificationError::InvalidEvidence, "activation verification refused: trust evidence malformed", ); return Err(ActivationVerificationError::InvalidEvidence); @@ -634,6 +642,7 @@ impl ActivationTrust { .verify(&expected.signed_payload, &self.signature) .map_err(|_| { tracing::warn!( + refusal = ?ActivationVerificationError::SignatureInvalid, "activation verification refused: Ed25519 signature invalid", ); ActivationVerificationError::SignatureInvalid From c897fbaa7a84eb4a884825678be86599533465a0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:44:57 -0700 Subject: [PATCH 365/726] d2b-provider-test-controller: wire tracing subscriber and structured failure logs --- Cargo.lock | 1 + .../d2b-provider-test-controller/Cargo.toml | 1 + .../d2b-provider-test-controller/src/main.rs | 37 +++++++++++++------ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f023ce55f..bb591c6d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1786,6 +1786,7 @@ dependencies = [ "d2b-session-unix", "tokio", "tracing", + "tracing-subscriber", ] [[package]] diff --git a/packages/d2b-provider-test-controller/Cargo.toml b/packages/d2b-provider-test-controller/Cargo.toml index 25950fee7..c6454949d 100644 --- a/packages/d2b-provider-test-controller/Cargo.toml +++ b/packages/d2b-provider-test-controller/Cargo.toml @@ -19,6 +19,7 @@ d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = d2b-session = { path = "../d2b-session", version = "0.0.0-bootstrap" } d2b-session-unix = { path = "../d2b-session-unix", version = "0.0.0-bootstrap", default-features = false, features = ["host-socket", "native-vsock"] } tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["fmt"] } tokio = { workspace = true, features = ["rt", "rt-multi-thread", "time"] } [[bin]] diff --git a/packages/d2b-provider-test-controller/src/main.rs b/packages/d2b-provider-test-controller/src/main.rs index e74f33d61..5b1814723 100644 --- a/packages/d2b-provider-test-controller/src/main.rs +++ b/packages/d2b-provider-test-controller/src/main.rs @@ -32,6 +32,7 @@ enum SessionDisposition { // CLI entry point: drives the runtime synchronously at process start. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn main() { + tracing_subscriber::fmt::init(); let runtime = match tokio::runtime::Builder::new_current_thread() .enable_all() .build() @@ -160,8 +161,8 @@ async fn run_session( warn!(reason = %e, "controller assignment stream reopen after reset failed; reconnecting"); })?; } - Ok(Ok(SessionEvent::NamedStream(_))) => { - warn!("controller received an unexpected named stream; reconnecting"); + Ok(Ok(SessionEvent::NamedStream(event))) => { + warn!(stream = ?event.stream(), "controller received an unexpected named stream; reconnecting"); return Ok(SessionDisposition::Reconnect); } Ok(Ok(_)) | Err(_) => {} @@ -170,8 +171,8 @@ async fn run_session( return Ok(SessionDisposition::Reconnect); } } - if session.drive_keepalive(Instant::now()).await.is_err() { - warn!("controller keepalive drive failed; reconnecting"); + if let Err(e) = session.drive_keepalive(Instant::now()).await { + warn!(reason = %e, "controller keepalive drive failed; reconnecting"); return Ok(SessionDisposition::Reconnect); } } @@ -183,8 +184,12 @@ fn should_reconnect(reason: CloseReason) -> bool { async fn send_bootstrap(bootstrap: &SeqpacketSocket, daemon_endpoint: OwnedFd) -> Result<(), ()> { let policy = controller_bootstrap_attachment_policy(); - let capacity = AncillaryCapacity::from_policy(policy).map_err(|_| ())?; - let scopes = controller_credit_scopes().map_err(|_| ())?; + let capacity = AncillaryCapacity::from_policy(policy).map_err(|e| { + warn!(reason = %e, "controller bootstrap send failed: ancillary capacity setup failed"); + })?; + let scopes = controller_credit_scopes().map_err(|e| { + warn!(reason = ?e, "controller bootstrap send failed: credit scope setup failed"); + })?; let packet = d2b_session_unix::OutboundPacket::with_current_credentials( d2b_session_unix::CONTROLLER_BOOTSTRAP_PROTOCOL_MARKER.to_vec(), vec![Arc::new(daemon_endpoint)], @@ -192,15 +197,21 @@ async fn send_bootstrap(bootstrap: &SeqpacketSocket, daemon_endpoint: OwnedFd) - capacity, &scopes, ) - .map_err(|_| ())?; + .map_err(|e| { + warn!(reason = %e, "controller bootstrap send failed: packet build failed"); + })?; let mut queue = VecDeque::from([packet]); let sent = tokio::time::timeout( CONTROLLER_BOOTSTRAP_TIMEOUT, bootstrap.send_burst(&mut queue, capacity, 1), ) .await - .map_err(|_| ())? - .map_err(|_| ())?; + .map_err(|e| { + warn!(reason = %e, "controller bootstrap send failed: send timed out"); + })? + .map_err(|e| { + warn!(reason = %e, "controller bootstrap send failed: send burst failed"); + })?; if sent.sent.len() != 1 || !queue.is_empty() { return Err(()); } @@ -222,11 +233,15 @@ fn controller_transport( policy.transport_binding.locality, policy.limits, policy.attachment_policy, - controller_credit_scopes().map_err(|_| ())?, + controller_credit_scopes().map_err(|e| { + warn!(reason = ?e, "controller transport build failed: credit scope setup failed"); + })?, resolver, PeerIdentityPolicy::inherited_socketpair(expected_peer), ) - .map_err(|_| ()) + .map_err(|e| { + warn!(reason = %e, "controller transport build failed: transport construction failed"); + }) } #[cfg(test)] From 62324d94a5e15b340035e0bd9c3fd7b127a44253 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:45:08 -0700 Subject: [PATCH 366/726] d2b-contracts-provider: report a top-level unknown frame field as UnknownField --- .../src/v3/telemetry_frame.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs b/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs index e7f2455d0..331324ce4 100644 --- a/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs +++ b/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs @@ -73,7 +73,15 @@ pub fn parse_raw_frame(bytes: &[u8]) -> Result MAX_TELEMETRY_FRAME_BYTES { return Err(TelemetryFrameError::RawOversize); } - serde_json::from_slice::(bytes).map_err(|_| TelemetryFrameError::Malformed) + serde_json::from_slice::(bytes).map_err(|error| { + // The pinned serde_json has no `Category::UnknownField`; the only way + // to distinguish a top-level unknown field is by its stable message. + if error.to_string().starts_with("unknown field") { + TelemetryFrameError::UnknownField + } else { + TelemetryFrameError::Malformed + } + }) } /// Validate a previously parsed shared frame. @@ -485,6 +493,14 @@ fn json_kind(value: &Value) -> &'static str { mod tests { use super::*; + #[test] + fn a_top_level_unknown_field_reports_the_unknown_field_class() { + assert_eq!( + parse_raw_frame(br#"{"signal":"metric","value":1,"extra":true}"#), + Err(TelemetryFrameError::UnknownField) + ); + } + #[test] fn shared_frame_rejects_unknown_keys_and_non_finite_values() { let unknown = br#"{"signal":"metric","value":{"name":"d2b_test_total","labels":{},"value":1,"extra":true}}"#; From 32abd936f54ee5b1e0e751b5f65554f81e3dbbbf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:45:32 -0700 Subject: [PATCH 367/726] audit: fold the activation slice's landed rows --- .../2026-09-24-rust-skills-audit/ledger.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index ea7fe4909..d396bacba 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -329,8 +329,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `identity.rs:857-865, controller.rs:1808-1818` | | | | `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | | `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `bootstrap_graph.rs:142-176, controller.rs:662-670` | | | -| `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417, packages/d2b-contracts-reso` | | | -| `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/config.rs:89, packages/d2b-provider-guest-qemu-` | | | +| `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | 82f8cac47 | packages/d2b-provider-guest-qemu-media/src/config.rs | 7 gate calls now use BoundedToken::parse(...) .is_err(); local validate_token helper and its pub(crate) re-export deleted; qmp validate_object_id delegates to BoundedToken::parse. Deviation: validate_ | | +| `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | b845000ff | packages/d2b-provider-guest-qemu-media/src/config.rs | impl Default for ProviderConfig deleted (it manufactured a config that fails its own validate());the sole consumer test now builds valid-then-mutated configs (controller_execution_ref swapped to a Gue | | | `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-` | | | | `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:56, agent.rs:265, agent.rs:297` | | | | `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | | | | `packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minij` | | | @@ -407,8 +407,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | dbac9940c | packages/d2b-process-conformance/src/process_provider.rs | Deleted the duplicate process_provider re-export module; census: 0 users of that path. | | | `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testi` | | | | `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | a37c1e0cf | packages/d2b-process-conformance/src/sandbox.rs | Deleted CompiledSandbox::requires_cgroup_kill field, its unconditional true initializer in compile(), and its public accessor; census: `requires_cgroup_kill` over packages/, nixos-modules/, tests/, do | | -| `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation` | | | -| `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:14, packages/d2b-provider-activat` | | | +| `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 6c66b83ea | packages/d2b-provider-activation-nixos/src/driver.rs | ActivationDriver narrowed to pub(crate) and dropped from the lib.rs driver re-export arm. Census re-run:the symbol appears only in driver.rs (7 sites)and lib.rs; no external consumer. Checks shared wi | | +| `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | | `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/authority.rs:157-171, src/controller.rs:395-403` | | | | `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:746-748, src/lib.rs:32` | | | | `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | | | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | | | @@ -439,7 +439,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | | | | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | | | | `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `identity.rs:554-556, tests/controller.rs:206` | | | | `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:576-578` | | | -| `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129, packages/d2b-provider-guest-qem` | | | +| `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | | `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111,` | | | | `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/routes.rs:244-279, src/routes.rs:264-265` | | | | `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:1019, packages/d2b-provider-n` | | | @@ -529,7 +529,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | manifest_parse_reason now matches serde_json::Error::classify() (Category::Data/Syntax/Eof/Io) instead of Display text; all 8 call sites updated to pass &error; slug change not wire-visible per census | | | `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 96cc7e5bb | packages/d2b-core-controller/src/authority.rs | DuplicateConflict code arm rendered as kebab-case duplicate-conflict; in-crate assertion pinning the old spelling updated; census showed 0 hits outside authority.rs. | | | `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | bf9832779 | packages/d2b-process-conformance/src/launch_identity.rs | Replaced the is_some_and guard + unreachable .expect with an if-let chain binding owner via .filter(), deleting the panic site and using the bound owner for the error payload; behavior unchanged (same | | -| `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activa` | | | +| `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | applied | U3 | 69153d93f | packages/d2b-provider-activation-nixos/src/controller.rs | terminal now takes ResourceName (63-byte lowercase label, no slash); new parses via ResourceName::parse and returns Result<_, IdentityError>; two driver call sites map parse failure to driver Policy e | | | `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/authority.rs:53-54, src/authority.rs:144-145` | | | | `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/state.rs:114-123, src/controller.rs:155-160` | | | | `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:3550, src/bin/d2b-clipd.rs:1754, src/bin/d2b-clipd.rs:2863` | | | @@ -635,12 +635,12 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0581` | `serde` | `xtask` | low | actionable | leaf | applied-variant | U3 | 341c4fb5e | packages/xtask/src/resource_type_authority.rs | rename_all = camelCase added to DeclarationFile and TypeDeclaration; per-field resourceType rename deleted;the crate per-field rename must stay because the wire key 'crate' is a Rust keyword that rena | | | `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:25` | | | | `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | -| `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activa` | | | +| `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | a94ef37d6 | packages/d2b-provider-activation-nixos/src/controller.rs | all 9 warn! refusal events in ActivationTrust::verify now carry a named refusal field with the exact ActivationVerificationError variant; no correlation identifiers added (ADR 0010/0028 safe). | | | `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100` | | | | `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provide` | | | | `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | | `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:346, src/controller/mod.rs:425` | | | -| `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:352, packages/d2b-provi` | | | +| `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | cc01388e6 | packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs | reconcile/finalize now carry a tracing instrument span with resource/provider fields; 23 per-event duplicate pairs dropped. Deviation: the row's literal span syntax (fields inside skip) is rejected by | | | `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-system` | | | | `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:33-47, packages/d2b-provider-test-contro` | | | | `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:164, packages/d2b-provider-test-controll` | | | From cbd0925794862c6d381712edec726115c3dd44dc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:46:02 -0700 Subject: [PATCH 368/726] audit: fold the contracts and provider slices --- .../2026-09-24-rust-skills-audit/ledger.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index d396bacba..db36e75ba 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -290,7 +290,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:889-892` | | | | `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_co` | | | | `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362` | | | -| `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/session/zone_link.rs:111-117` | | | +| `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 7a5a7f957,4e20f7674 | packages/d2b-bus/src/session/zone_link.rs | folded admission+liveness into private EstablishedLane; test lane keeps None; all three gate sites migrated; follow-up commit reattaches the doc to ZoneLinkSession | | | `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | ResourceQuery assignment/scope Option pair folded into one Option<(AssignmentIdentity, ScopedResourceScope)>; pub assignment()/scope() accessors keep signatures via const match; validate_scoped now on | | | `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | | `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broke` | | | @@ -300,7 +300,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:316, public_wire.rs:311` | | | | `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | | `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | | | -| `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:1333, packages/d2b-contracts-provider/s` | | | +| `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | | `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-res` | | | | `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | | `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-r` | | | @@ -322,7 +322,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | | | | `controller.rs:85-89, tests/binding.rs:1214-1234` | | | | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:79, packages/d2b-provider-device-gpu/sr` | | | | `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | -| `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | | | | `src/effects.rs:394-406` | | | +| `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | | `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | | | | `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/bootstrap.rs:65, src/bootstrap.rs:82` | | | | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:82, src/controller/mod.rs:982` | | | @@ -377,7 +377,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | | `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | applied-variant | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | Census re-run:= with_observer/with_observer_and_metrics/with_clock_and_observer have zero ZoneBus callers, deleted; with_clock -> pub(crate) because production new() delegates to it; with_clock_observ | | | `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | -| `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97` | | | +| `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114` | | | | `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | @@ -414,8 +414,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | | | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | | | | `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-cli` | | | | `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | | | | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | | | -| `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/lib.rs:102, packages/d2b-provider-credential-en` | | | -| `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/lib.rs:446, packages/d2b-provider-credential-en` | | | +| `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | +| `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | | `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:612-618` | | | | `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | | | | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effe` | | | | `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/lib.rs:12, packages/d2b-provider-device-gpu/src/lib.r` | | | @@ -431,7 +431,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/lib.rs:14` | | | | `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/controller.rs:580` | | | | `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12` | | | -| `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `src/lib.rs:14, src/effects.rs:8-9` | | | +| `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | | `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | | | | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | | | | `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:211, packages/d2b-provider-guest/src/effects_service.rs:1186` | | | | `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895` | | | @@ -471,9 +471,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | | | | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | | | | `RS-0421` | `api` | `d2b-provider-volume-local` | medium | actionable | family | | | | `src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1` | | | | `RS-0422` | `api` | `d2b-provider-zone` | medium | actionable | leaf | | | | `packages/d2b-provider-zone/src/lib.rs:9-10, packages/d2b-provider-zone/src/zone_status.rs:` | | | -| `RS-0423` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:1783, packages/d2b-provider-zone-link/sr` | | | -| `RS-0424` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zonelink.rs:281` | | | -| `RS-0425` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zonelink.rs:178` | | | +| `RS-0423` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied-variant | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zone_links.rs | Fix as written (pub(crate)) not implementable: usage is test-only, and .cargo/config.toml -Dwarnings turns the resulting dead-code into build errors. Minimal correct variant: #[cfg(test)] on ZoneLinkM | | +| `RS-0424` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zonelink.rs | Deleted transport_error_is_quarantine (zero callers in or out of crate, including tests; privatizing alone would trip -Dwarnings dead-code). ZoneLinkError import stays used by issue_route_admission. c | | +| `RS-0425` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | skipped-stale | U3 | | `packages/d2b-provider-zone-link/src/zonelink.rs:178` | Lane premise false on census re-run: d2bd/src/composition.rs:1175 and :1541 call controller.cursor_authority() and use the returned ZoneLinkCursorAuthority value, so the accessor's pub return type is | | | `RS-0426` | `api` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:251-256, adapter.rs:1208-1211` | | | | `RS-0427` | `api` | `d2b-resource-api` | low | actionable | leaf | | | | `client.rs:98, service.rs:837` | | | | `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | wire_revision and api_subject narrowed to pub(crate). resource_owner_subject stays pub because its U9/U10 caller has landed at HEAD: d2bd/src/resource_runtime/plane_controller_bridge.rs:369 (subject() | | @@ -511,13 +511,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | | `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/depen` | | | -| `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/wire.rs:49-56` | | | +| `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:2` | | | | `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | | | | `public_wire.rs:1297` | | | -| `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider_registry.rs:186, packages/d2b-contracts-pr` | | | +| `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | applied | U3 | 58e72374f | packages/d2b-contracts-provider/src/v3/provider_registry.rs | split zero-generation check before mapping-count bound; Defensive-only reachability since ResourceGeneration rejects 0 at new/Deserialize; no consumer pins the code | | | `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError Display strings are wire outcome codes pinned by docs/specs/ADR-046-resources-credential.md:903 (credential-queue-pressure = lease table at capacity) and the provider ADR err | | | `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | -| `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-pr` | | | +| `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | ed46f196b | packages/d2b-contracts-provider/src/v3/provider_registry.rs | added GenerationMismatch variant kebab code provider-registry-generation-mismatch; updated failure-path test to assert the variant; census ProviderRegistryError=12 hits all in-file | | | `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 75e9c238c | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialSingleFlight lock() now recovers poisoned mutexes via unwrap_or_else(poisoned.into_inner()) and returns the guard directly (infallible); guard Drop recovers the same way instead of silently | | | `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | | `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | @@ -555,7 +555,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:888-890` | | | | `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:304` | | | | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:386` | | | -| `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:186-187, packages/d2b-provider-test-cont` | | | +| `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | | `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-to` | | | | `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | | `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | @@ -599,7 +599,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | | | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | | | | `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | | | | `unsafe_local_wire.rs:118, unsafe_local_wire.rs:176, public_wire.rs:2228` | | | -| `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76, packages/d2b-contracts-provi` | | | +| `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | | `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | | `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | | | | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | | | @@ -642,8 +642,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:346, src/controller/mod.rs:425` | | | | `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | cc01388e6 | packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs | reconcile/finalize now carry a tracing instrument span with resource/provider fields; 23 per-event duplicate pairs dropped. Deviation: the row's literal span syntax (fields inside skip) is rejected by | | | `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-system` | | | -| `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:33-47, packages/d2b-provider-test-contro` | | | -| `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | | | | `packages/d2b-provider-test-controller/src/main.rs:164, packages/d2b-provider-test-controll` | | | +| `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | +| `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | | `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src` | | | | `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | | | | `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-` | | | From 6f6b4a24c064a95d0ef78811725650be5f70f512 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:46:17 -0700 Subject: [PATCH 369/726] audit: fold the device provider slice --- .../2026-09-24-rust-skills-audit/ledger.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index db36e75ba..e95a3808c 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -320,11 +320,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixo` | | | | `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-credential/src/d` | | | | `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | | | | `controller.rs:85-89, tests/binding.rs:1214-1234` | | | -| `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/controller.rs:79, packages/d2b-provider-device-gpu/sr` | | | +| `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | | `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | | `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | | `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | | | -| `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/bootstrap.rs:65, src/bootstrap.rs:82` | | | +| `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired — the illegal Consumed/Expired-with-Some(psk) combination is now unco | | | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:82, src/controller/mod.rs:982` | | | | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `identity.rs:857-865, controller.rs:1808-1818` | | | | `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | @@ -418,13 +418,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | | `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:612-618` | | | | `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | | | | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effe` | | | -| `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/lib.rs:12, packages/d2b-provider-device-gpu/src/lib.r` | | | -| `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-device-` | | | +| `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U3 | 539ca5113 | packages/d2b-provider-device-gpu/src/lib.rs | gpu_argv/video_argv made private; root re-exports keep one reachable path per item. Census re-run: `d2b_provider_device_gpu::(gpu_argv/video_argv)::` over packages/nixos-modules/tests/docs/reference/l | | +| `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U3 | 4efbf8ea5 | packages/d2b-provider-device-gpu/src/effects_service.rs | applied-variant: row's second option (single crate-owned sidecar) used: DeclaredWorkerGpuPortDeps sidecar (private fields, pub 4-arg ::new) holds the four dependency types; DeclaredWorkerGpuPortArgs ( | | | `RS-0372` | `api` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/lib.rs:16-17, packages/d2b-provider-device-s` | | | -| `RS-0373` | `api` | `d2b-provider-device-tpm` | medium | actionable | leaf | | | | `state.rs:6, state.rs:29, state.rs:51, state.rs:73` | | | +| `RS-0373` | `api` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | state.rs (StateDirectoryToken/TamperMarkerToken/StateOwnerToken/StateDirIntent) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.b | | | `RS-0374` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:53, effects_service.rs:103, effects_service.rs:114` | | | | `RS-0375` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:341` | | | -| `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `migration.rs:5, lib.rs:24` | | | +| `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | | `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `lib.rs:24, lib.rs:61-65` | | | | `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `broker.rs:131-133` | | | | `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20` | | | @@ -538,7 +538,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provide` | | | | `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixo` | | | | `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:1261-1262` | | | -| `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | | | | `runner.rs:43, swtpm_argv.rs:104, lib.rs:35, tests/conformance.rs:11` | | | +| `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | | `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `state_machine.rs:378-386` | | | | `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:740, src/controller.rs:741` | | | | `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886` | | | @@ -612,7 +612,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | | `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-` | | | | `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | | | | `packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/comm` | | | -| `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/` | | | +| `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | d58f183d5 | packages/d2b-provider-device-gpu/src/gpu_argv.rs | deny_unknown_fields added to GpuArgvInput/GpuParams/GpuDisplayConfig (mirroring VideoArgvInput); new rejects_unknown_fields test pins top-level, params-nested, and display-nested rejection. Mutation c | | | `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | | | | `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:230, src/spec.rs:233, src/spec.rs:263` | | | | `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | From 15d510a762d0ccd0c1647d05f611384e022b8f41 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:46:49 -0700 Subject: [PATCH 370/726] display: drop the unused policy snapshot wrapper --- .../src/controller.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/controller.rs b/packages/d2b-provider-display-wayland/src/controller.rs index 02e5ca390..57c30c0c3 100644 --- a/packages/d2b-provider-display-wayland/src/controller.rs +++ b/packages/d2b-provider-display-wayland/src/controller.rs @@ -571,22 +571,6 @@ pub struct WaylandPolicySnapshot { } impl WaylandPolicySnapshot { - /// Resolve a policy snapshot for one authenticated Guest session. - /// - /// The route binding supplies the Zone and Provider identity; callers may - /// not substitute a different Zone or service boundary while compiling - /// the policy. - pub fn from_authenticated_session( - session: &AuthenticatedComponentSession, - policy_ref: ResourceRef, - generation: u64, - defaults: FilterInput, - zone_policy: FilterInput, - ) -> Result { - let route = session.route_binding(); - Self::from_authenticated_route(&route, policy_ref, generation, defaults, zone_policy) - } - /// Resolve a policy snapshot from the daemon-retained authenticated route. /// /// This is the production adapter used after the Zone registrar consumed From 263eea21177d67939de9bff12033467d53f9290d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:46:51 -0700 Subject: [PATCH 371/726] display: return Result from DisplayController::new --- .../src/controller.rs | 20 +++++++++++-------- .../src/runtime.rs | 4 ++-- .../tests/provider_behavior.rs | 10 +++++----- packages/d2bd/src/interaction_composition.rs | 5 +++-- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/controller.rs b/packages/d2b-provider-display-wayland/src/controller.rs index 57c30c0c3..541399801 100644 --- a/packages/d2b-provider-display-wayland/src/controller.rs +++ b/packages/d2b-provider-display-wayland/src/controller.rs @@ -718,16 +718,20 @@ pub struct DisplayController { impl DisplayController { /// Construct a controller with a bounded dynamic principal pool. - pub fn new(pool_size: usize) -> Self { - Self { - principal_pool: PrincipalPool::new(pool_size) - .expect("display principal pool size is validated by the signed descriptor"), + /// + /// # Errors + /// + /// Returns `PrincipalPoolError::InvalidPoolSize` when the pool size is + /// outside the closed bound 1..=32. + pub fn new(pool_size: usize) -> Result { + Ok(Self { + principal_pool: PrincipalPool::new(pool_size)?, principals: BTreeMap::new(), active_policies: BTreeMap::new(), ready_sessions: BTreeMap::new(), worker_supervisor: WorkerSupervisor::new(WorkerSupervisor::DEFAULT_MAX_ATTEMPTS) .expect("default worker retry bound is non-zero"), - } + }) } /// Reconcile only after binding the desired state to an authenticated @@ -1365,7 +1369,7 @@ impl DisplayController { true } - /// Release a session's dynamic principal after verified Process cleanup. + /// Release a session's dynamic principal after verified Process cleanup. pub fn release_session_principal( &mut self, receipt: PrincipalReleaseReceipt, @@ -1471,7 +1475,7 @@ mod tests { .unwrap(); assert_eq!(policy.generation(), 7); - let mut controller = DisplayController::new(1); + let mut controller = DisplayController::new(1).unwrap(); let result = controller .reconcile_with_policy( &spec, @@ -1503,7 +1507,7 @@ mod tests { FilterInput::default(), ) .unwrap(); - let mut controller = DisplayController::new(1); + let mut controller = DisplayController::new(1).unwrap(); controller .reconcile_with_policy( &spec, diff --git a/packages/d2b-provider-display-wayland/src/runtime.rs b/packages/d2b-provider-display-wayland/src/runtime.rs index a68fb4e8e..70af2c74c 100644 --- a/packages/d2b-provider-display-wayland/src/runtime.rs +++ b/packages/d2b-provider-display-wayland/src/runtime.rs @@ -1067,7 +1067,7 @@ mod tests { // The production entrypoint accepts an AuthenticatedComponentSession, // so this test exercises the same effect port and finalizer ordering // through a directly seeded runtime observation. - let mut runtime = DisplayRuntime::new(DisplayController::new(2), Effects::default()); + let mut runtime = DisplayRuntime::new(DisplayController::new(2).unwrap(), Effects::default()); runtime.observation = ProcessObservation::from_supervisor( WorkerState::Terminal { deleted: false }, WorkerState::Terminal { deleted: false }, @@ -1132,7 +1132,7 @@ mod tests { launch_state: Some(WorkerState::Starting), ..Effects::default() }; - let mut runtime = DisplayRuntime::new(DisplayController::new(2), effects); + let mut runtime = DisplayRuntime::new(DisplayController::new(2).unwrap(), effects); let supervision = WorkerRestartEvidence::from_supervisor(1, None, None, 1); let first = runtime diff --git a/packages/d2b-provider-display-wayland/tests/provider_behavior.rs b/packages/d2b-provider-display-wayland/tests/provider_behavior.rs index 97776fe38..5c5162c64 100644 --- a/packages/d2b-provider-display-wayland/tests/provider_behavior.rs +++ b/packages/d2b-provider-display-wayland/tests/provider_behavior.rs @@ -192,7 +192,7 @@ fn principal_pool_is_opaque_and_fails_closed_when_exhausted() { fn controller_status_transitions_pending_ready_and_failed() { let (guest, host, user, policy) = refs(); let spec = WaylandSessionSpec::new(guest, host, user, policy, identity(), true).unwrap(); - let mut controller = d2b_provider_display_wayland::DisplayController::new(4); + let mut controller = d2b_provider_display_wayland::DisplayController::new(4).unwrap(); let pending = reconcile( &mut controller, &spec, @@ -233,7 +233,7 @@ fn failed_reconcile_retains_the_session_principal_until_cleanup() { true, ) .unwrap(); - let mut controller = d2b_provider_display_wayland::DisplayController::new(1); + let mut controller = d2b_provider_display_wayland::DisplayController::new(1).unwrap(); let first_status = reconcile( &mut controller, &first, @@ -283,7 +283,7 @@ fn mutable_session_fields_reuse_the_same_principal() { true, ) .unwrap(); - let mut controller = d2b_provider_display_wayland::DisplayController::new(1); + let mut controller = d2b_provider_display_wayland::DisplayController::new(1).unwrap(); let first_principal = reconcile( &mut controller, &first, @@ -318,7 +318,7 @@ fn readiness_cannot_be_reused_for_a_different_host_or_user_binding() { true, ) .unwrap(); - let mut controller = d2b_provider_display_wayland::DisplayController::new(2); + let mut controller = d2b_provider_display_wayland::DisplayController::new(2).unwrap(); assert_eq!( reconcile( &mut controller, @@ -362,7 +362,7 @@ fn distinct_authenticated_sessions_do_not_share_display_principals() { true, ) .unwrap(); - let mut controller = d2b_provider_display_wayland::DisplayController::new(2); + let mut controller = d2b_provider_display_wayland::DisplayController::new(2).unwrap(); let first_status = reconcile( &mut controller, &first, diff --git a/packages/d2bd/src/interaction_composition.rs b/packages/d2bd/src/interaction_composition.rs index 25fc5f38c..ba833a0bc 100644 --- a/packages/d2bd/src/interaction_composition.rs +++ b/packages/d2bd/src/interaction_composition.rs @@ -2291,7 +2291,8 @@ where WorkerRestartEvidence::from_supervisor(daemon_monotonic_ms(), None, None, 1) }; self.reconcile_display( - DisplayController::new(8), + DisplayController::new(8) + .expect("display principal pool size is validated by the signed descriptor"), &request.spec, evidence.dependencies.clone(), supervision, @@ -7159,7 +7160,7 @@ mod tests { let zone = ZoneId::parse("dev").unwrap(); let mut composition = test_interaction_composition(&zone, 42); composition.display = Some(DisplayRuntime::new( - DisplayController::new(2), + DisplayController::new(2).unwrap(), DisplaySupervisorEffects::new(ProviderSupervisor::new(Backend::default())), )); From 64c41ddb503446c1f167b4225bff197fe25d5d79 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:46:55 -0700 Subject: [PATCH 372/726] display: remove the unused spec error variant --- packages/d2b-provider-display-wayland/src/spec.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/spec.rs b/packages/d2b-provider-display-wayland/src/spec.rs index fddd3d2ac..24d8b3ad5 100644 --- a/packages/d2b-provider-display-wayland/src/spec.rs +++ b/packages/d2b-provider-display-wayland/src/spec.rs @@ -26,8 +26,6 @@ pub enum WaylandSpecError { BorderTooWide, /// A policy named an interface outside the compiled catalog. UnknownInterface, - /// The pre-provisioned principal pool has no free account. - NoPrincipalAvailable, } impl core::fmt::Display for WaylandSpecError { @@ -40,7 +38,6 @@ impl core::fmt::Display for WaylandSpecError { Self::CrossDomainUntrusted => "cross-domain-not-trusted", Self::BorderTooWide => "wayland-border-too-wide", Self::UnknownInterface => "unknown-interface-rejected", - Self::NoPrincipalAvailable => "no-principal-available", }) } } From 84b3431014f5ea151e241017d8ea0f22108c30bc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:46:56 -0700 Subject: [PATCH 373/726] display: drop the inert serde try_from attribute --- packages/d2b-provider-display-wayland/src/spec.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/spec.rs b/packages/d2b-provider-display-wayland/src/spec.rs index 24d8b3ad5..f195bd6a1 100644 --- a/packages/d2b-provider-display-wayland/src/spec.rs +++ b/packages/d2b-provider-display-wayland/src/spec.rs @@ -231,11 +231,7 @@ impl core::fmt::Debug for DisplayIdentity { /// Authenticated desired state for one Wayland display session. #[derive(Clone, PartialEq, Eq, Serialize)] -#[serde( - rename_all = "camelCase", - deny_unknown_fields, - try_from = "WaylandSessionSpecWire" -)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct WaylandSessionSpec { guest_ref: ResourceRef, host_ref: ResourceRef, From c5d8e0cf599cc944b9403b479be5c8849ea37a28 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:47:00 -0700 Subject: [PATCH 374/726] display: move wayland proxy module into the binary target --- .../src/bin/d2b-wayland-proxy.rs | 13 +++--- .../d2b-provider-display-wayland/src/lib.rs | 2 - .../src/wayland_proxy/bridge.rs | 2 +- .../src/wayland_proxy/decoration.rs | 2 +- .../src/wayland_proxy/dmabuf.rs | 2 +- .../src/wayland_proxy/filter.rs | 40 +++++++++---------- .../src/wayland_proxy/policy.rs | 10 ++--- .../src/wayland_proxy/readiness.rs | 2 +- 8 files changed, 36 insertions(+), 37 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs b/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs index 70f5fc22d..04551c221 100644 --- a/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs +++ b/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs @@ -11,6 +11,9 @@ //! The listen socket is NEVER created before upstream connects. //! 5. Enter the dispatch loop. +#[path = "../wayland_proxy/mod.rs"] +mod wayland_proxy; + use std::{ cell::RefCell, io, @@ -22,10 +25,8 @@ use std::{ use clap::Parser; use d2b_contracts::{workload::WorkloadProviderKind, workload_identity::WorkloadTarget}; -use d2b_provider_display_wayland::wayland_proxy::filter::{ - FilterStateHandler, VirtualClipboardState, build_state, install_client_handlers, -}; -use d2b_provider_display_wayland::wayland_proxy::{ +use wayland_proxy::filter::{FilterStateHandler, VirtualClipboardState, build_state, install_client_handlers}; +use wayland_proxy::{ bridge::{BridgeConfig, BridgeReconnectPolicy}, decoration::{BorderConfig, Color, DecorationManager, LabelPosition, sanitize_label}, diag::{DiagRateLimiter, bounded_error_detail}, @@ -145,7 +146,7 @@ struct Args { border_color_urgent: Color, /// Deprecated legacy border thickness; wrapper rails use a fixed width. - #[arg(long = "border-thickness", value_parser = parse_positive_u32, default_value_t = d2b_provider_display_wayland::wayland_proxy::decoration::DEFAULT_BORDER_THICKNESS)] + #[arg(long = "border-thickness", value_parser = parse_positive_u32, default_value_t = wayland_proxy::decoration::DEFAULT_BORDER_THICKNESS)] border_thickness: u32, /// Optional text rendered into the wrapper rail. @@ -800,7 +801,7 @@ mod tests { assert!(!args.border_enable); assert_eq!( args.border_thickness, - d2b_provider_display_wayland::wayland_proxy::decoration::DEFAULT_BORDER_THICKNESS + wayland_proxy::decoration::DEFAULT_BORDER_THICKNESS ); assert!(args.border_label.is_none()); } diff --git a/packages/d2b-provider-display-wayland/src/lib.rs b/packages/d2b-provider-display-wayland/src/lib.rs index bb119b7c2..ad87d81f9 100644 --- a/packages/d2b-provider-display-wayland/src/lib.rs +++ b/packages/d2b-provider-display-wayland/src/lib.rs @@ -10,8 +10,6 @@ mod process; mod runtime; pub mod session_children; mod spec; -#[allow(missing_docs)] -pub mod wayland_proxy; pub use controller::{ AuthenticatedDisplaySession, CapabilityReadiness, CleanupState, DependencyReadiness, diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs index 788cdc0ad..db45ae6b5 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs @@ -17,7 +17,7 @@ use std::{ use d2b_contracts::{workload::WorkloadProviderKind, workload_identity::WorkloadTarget}; use serde::Serialize; -use crate::wayland_proxy::identity::ProxyIdentity; +use wayland_proxy::identity::ProxyIdentity; const LINUX_SUN_PATH_BYTES: usize = 108; diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs index 5e81dcd6a..580aa39a6 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs @@ -40,7 +40,7 @@ use wl_proxy::{ }, }; -use crate::wayland_proxy::diag::{DiagRateLimiter, bounded_error_detail}; +use wayland_proxy::diag::{DiagRateLimiter, bounded_error_detail}; pub const DEFAULT_BORDER_THICKNESS: u32 = 4; pub const WRAPPER_RAIL_WIDTH: u32 = 9; diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs index ae08227b2..24603a34c 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs @@ -21,7 +21,7 @@ use wl_proxy::protocols::{ wayland::{wl_buffer::WlBuffer, wl_surface::WlSurface}, }; -use crate::wayland_proxy::{ +use wayland_proxy::{ decoration::{SharedDecorationManager, tracking_buffer_handler}, diag::DiagRateLimiter, }; diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs index b14bc286e..d4f2f4e31 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs @@ -75,7 +75,7 @@ use wl_proxy::{ state::{State, StateHandler}, }; -use crate::wayland_proxy::{ +use wayland_proxy::{ bridge::{ BridgeConfig, BridgeConnectionState, BridgeHandoff, BridgeReconnectMachine, BridgeTransferKind, BridgeTransferMetadata, LocalTransferFd, @@ -604,9 +604,9 @@ impl VirtualClipboardState { return; }; match bridge.handoff_transfer_fd(&local_fd, metadata) { - crate::wayland_proxy::bridge::HandoffStatus::Delivered => { + wayland_proxy::bridge::HandoffStatus::Delivered => { let _ = local_fd - .close_after_handoff(crate::wayland_proxy::bridge::HandoffStatus::Delivered); + .close_after_handoff(wayland_proxy::bridge::HandoffStatus::Delivered); log::debug!( "[d2b-wlproxy] target={} event=clipboard-bridge reason=handoff-delivered kind={:?} mime={}", self.identity_label, @@ -614,12 +614,12 @@ impl VirtualClipboardState { bounded_log_mime(&metadata.mime_type) ); } - crate::wayland_proxy::bridge::HandoffStatus::Backpressure => { + wayland_proxy::bridge::HandoffStatus::Backpressure => { self.enqueue_bridge_handoff(local_fd, metadata); } - crate::wayland_proxy::bridge::HandoffStatus::Failed(error) => { + wayland_proxy::bridge::HandoffStatus::Failed(error) => { let _ = local_fd.close_after_handoff( - crate::wayland_proxy::bridge::HandoffStatus::Failed(error), + wayland_proxy::bridge::HandoffStatus::Failed(error), ); self.mark_bridge_disconnected(); self.ensure_bridge_connected(); @@ -678,13 +678,13 @@ impl VirtualClipboardState { fn handle_pending_handoff_status( &mut self, pending: PendingBridgeHandoff, - status: crate::wayland_proxy::bridge::HandoffStatus, + status: wayland_proxy::bridge::HandoffStatus, ) -> PendingHandoffStep { match status { - crate::wayland_proxy::bridge::HandoffStatus::Delivered => { + wayland_proxy::bridge::HandoffStatus::Delivered => { let _ = pending .fd - .close_after_handoff(crate::wayland_proxy::bridge::HandoffStatus::Delivered); + .close_after_handoff(wayland_proxy::bridge::HandoffStatus::Delivered); log::debug!( "[d2b-wlproxy] target={} event=clipboard-bridge reason=queued-handoff-delivered kind={:?} mime={}", self.identity_label, @@ -693,11 +693,11 @@ impl VirtualClipboardState { ); PendingHandoffStep::Continue } - crate::wayland_proxy::bridge::HandoffStatus::Backpressure => { + wayland_proxy::bridge::HandoffStatus::Backpressure => { self.pending_bridge_handoffs.push_front(pending); PendingHandoffStep::Stop } - crate::wayland_proxy::bridge::HandoffStatus::Failed(error) => { + wayland_proxy::bridge::HandoffStatus::Failed(error) => { let identity_label = self.identity_label.clone(); let kind = pending.metadata.kind; let mime = bounded_log_mime(&pending.metadata.mime_type); @@ -1115,7 +1115,7 @@ impl FilterRegistryHandler { } let (action, _) = self.policy.lookup(iface_name); - let crate::wayland_proxy::policy::GlobalAction::Allow = action else { + let wayland_proxy::policy::GlobalAction::Allow = action else { // Denied: ignore and suppress global_remove forwarding too. if self.policy.log_filtered_globals { self.diag.borrow_mut().global_filtered(iface_name); @@ -2664,7 +2664,7 @@ impl WlEglstreamDisplayHandler for FilterEglstreamDisplayHandler { ) { if eglstream_handle_is_fd(r#type) { if let Some(decoration) = &self.decoration { - id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( decoration, )); decoration.borrow_mut().record_buffer(id, width, height); @@ -2707,7 +2707,7 @@ impl WlDrmHandler for FilterDrmHandler { stride: u32, format: u32, ) { - id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( &self.decoration, )); self.decoration @@ -2731,7 +2731,7 @@ impl WlDrmHandler for FilterDrmHandler { offset2: i32, stride2: i32, ) { - id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( &self.decoration, )); self.decoration @@ -2757,7 +2757,7 @@ impl WlDrmHandler for FilterDrmHandler { offset2: i32, stride2: i32, ) { - id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( &self.decoration, )); self.decoration @@ -2875,7 +2875,7 @@ mod tests { use std::os::fd::AsRawFd; use std::os::unix::net::UnixListener; - use crate::wayland_proxy::{ + use wayland_proxy::{ bridge::BridgeReconnectPolicy, policy::{FilterPolicy, PolicyInput}, }; @@ -3107,7 +3107,7 @@ mod tests { let step = clipboard.handle_pending_handoff_status( pending, - crate::wayland_proxy::bridge::HandoffStatus::Backpressure, + wayland_proxy::bridge::HandoffStatus::Backpressure, ); assert_eq!(step, PendingHandoffStep::Stop); @@ -3237,7 +3237,7 @@ mod tests { for name in 0..6 { handler.diag.borrow_mut().bind_denied( - crate::wayland_proxy::diag::DropReason::BindDeniedUnadvertised, + wayland_proxy::diag::DropReason::BindDeniedUnadvertised, name, "zwp_text_input_manager_v3", ); @@ -3365,7 +3365,7 @@ mod tests { fn prepare_global_hides_clipboard_boundary_even_when_policy_allows_it() { let diag = Rc::new(RefCell::new(DiagRateLimiter::new("work".to_owned()))); let policy = Rc::new(FilterPolicy::build( - crate::wayland_proxy::policy::PolicyInput { + wayland_proxy::policy::PolicyInput { allow_globals: vec!["zwp_primary_selection_device_manager_v1".to_owned()], ..PolicyInput::new(local_identity()) }, diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs index 469ff69c5..0d98ccacf 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; -use crate::wayland_proxy::identity::ProxyIdentity; +use wayland_proxy::identity::ProxyIdentity; const MAX_REWRITTEN_LABEL_CHARS: usize = 256; @@ -150,9 +150,9 @@ pub struct PolicyInput { /// Per-global version caps. pub max_versions: Vec<(String, u32)>, /// dmabuf format/modifier allow filters. - pub dmabuf_allow: Vec, + pub dmabuf_allow: Vec, /// dmabuf format/modifier deny filters. - pub dmabuf_deny: Vec, + pub dmabuf_deny: Vec, /// Emit a log line for every filtered global advertisement. pub log_filtered_globals: bool, } @@ -183,7 +183,7 @@ pub struct FilterPolicy { pub identity: ProxyIdentity, /// Bounded display label derived from the authenticated identity. pub identity_label: String, - pub dmabuf_filters: std::rc::Rc, + pub dmabuf_filters: std::rc::Rc, pub log_filtered_globals: bool, /// Runtime advisories emitted by the filter process at startup. pub warnings: Vec, @@ -314,7 +314,7 @@ impl FilterPolicy { identity, identity_label: target_label, dmabuf_filters: std::rc::Rc::new( - crate::wayland_proxy::dmabuf::DmabufFilterList::new( + wayland_proxy::dmabuf::DmabufFilterList::new( &input.dmabuf_allow, &input.dmabuf_deny, ), diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs index 0ac22c5b5..ca8b887f9 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs @@ -5,7 +5,7 @@ use std::{ time::Duration, }; -use crate::wayland_proxy::identity::ProxyIdentity; +use wayland_proxy::identity::ProxyIdentity; pub use d2b_contracts_control::proxy_readiness::{ ProxyReadinessEvent, ProxyReadinessFailure, ProxyReadinessStage, }; From 87e8d76544b0ea1318ba5481a49e6ef04560e6b4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:47:06 -0700 Subject: [PATCH 375/726] audio-pipewire: make spec constructors infallible, admission gates stay single --- .../tests/registration.rs | 1 - .../src/resource_type.rs | 29 ++++++++----------- .../tests/controller.rs | 4 +-- .../tests/resource_type.rs | 16 ++++------ .../tests/registration.rs | 3 +- .../src/audio_registry.rs | 11 +++---- 6 files changed, 23 insertions(+), 41 deletions(-) diff --git a/packages/d2b-provider-audio-binding/tests/registration.rs b/packages/d2b-provider-audio-binding/tests/registration.rs index 58642d891..598af123b 100644 --- a/packages/d2b-provider-audio-binding/tests/registration.rs +++ b/packages/d2b-provider-audio-binding/tests/registration.rs @@ -79,7 +79,6 @@ fn binding_spec() -> AudioBindingSpec { ResourceRef::parse("Guest/workstation").expect("target"), "work", ) - .expect("binding spec") } fn envelope() -> InteractionSpecEnvelope { diff --git a/packages/d2b-provider-audio-pipewire/src/resource_type.rs b/packages/d2b-provider-audio-pipewire/src/resource_type.rs index d16bb1f7e..4ec4f030b 100644 --- a/packages/d2b-provider-audio-pipewire/src/resource_type.rs +++ b/packages/d2b-provider-audio-pipewire/src/resource_type.rs @@ -61,21 +61,18 @@ pub struct AudioServiceSpec { impl AudioServiceSpec { /// Construct an owner Service with one local authority Endpoint. - pub fn owner( - endpoint_ref: ResourceRef, - zone: impl Into, - ) -> Result { - if endpoint_ref.resource_type().as_str() != "Endpoint" { - return Err(AudioAdmissionError::EndpointType); - } - Ok(Self { + /// + /// The Endpoint type invariant is enforced once at admission by + /// [`validate_audio_service`]; construction does not re-check it. + pub fn owner(endpoint_ref: ResourceRef, zone: impl Into) -> Self { + Self { provider_ref: PROVIDER_REF.to_owned(), service_role: AudioServiceRole::Owner, implementation_endpoint_refs: vec![endpoint_ref], operations: vec!["playback".to_owned(), "capture".to_owned()], zone: zone.into(), provider_extension: None, - }) + } } /// Construct a Core-generated projection Service. @@ -114,24 +111,22 @@ pub struct AudioBindingSpec { impl AudioBindingSpec { /// Construct a binding for one Guest and same-Zone Service. + /// + /// The reference type invariant is enforced once at admission by + /// [`validate_audio_binding`]; construction does not re-check it. pub fn new( service_ref: ResourceRef, target_ref: ResourceRef, zone: impl Into, - ) -> Result { - if service_ref.resource_type().as_str() != AUDIO_SERVICE_TYPE - || target_ref.resource_type().as_str() != "Guest" - { - return Err(AudioAdmissionError::ReferenceType); - } - Ok(Self { + ) -> Self { + Self { provider_ref: PROVIDER_REF.to_owned(), service_ref, target_ref, zone: zone.into(), grants: AudioGrants::default(), provider_extension: None, - }) + } } /// Attach a provider extension for negative admission tests. diff --git a/packages/d2b-provider-audio-pipewire/tests/controller.rs b/packages/d2b-provider-audio-pipewire/tests/controller.rs index f962412a2..ea211e195 100644 --- a/packages/d2b-provider-audio-pipewire/tests/controller.rs +++ b/packages/d2b-provider-audio-pipewire/tests/controller.rs @@ -68,7 +68,6 @@ fn binding() -> d2b_provider_audio_pipewire::AudioBindingSpec { ResourceRef::parse("Guest/dev-vm").unwrap(), "zone-a", ) - .unwrap() } #[test] @@ -460,8 +459,7 @@ fn ready_audio_service_without_an_authored_binding_has_no_children() { let target_ref = ResourceRef::parse("Guest/dev-vm").expect("canonical Guest"); let service_only_ref = service_ref.clone(); let service_only = - d2b_provider_audio_pipewire::AudioBindingSpec::new(service_ref, target_ref, "zone-a") - .unwrap(); + d2b_provider_audio_pipewire::AudioBindingSpec::new(service_ref, target_ref, "zone-a"); assert_eq!( AudioBindingController::::child_resources( diff --git a/packages/d2b-provider-audio-pipewire/tests/resource_type.rs b/packages/d2b-provider-audio-pipewire/tests/resource_type.rs index 2d771f4f2..861af5705 100644 --- a/packages/d2b-provider-audio-pipewire/tests/resource_type.rs +++ b/packages/d2b-provider-audio-pipewire/tests/resource_type.rs @@ -10,15 +10,13 @@ fn owner_service_and_binding_are_provider_neutral_at_the_base() { let owner = AudioServiceSpec::owner( ResourceRef::parse("Endpoint/audio-authority").unwrap(), "zone-a", - ) - .unwrap(); + ); assert_eq!(owner.service_role, AudioServiceRole::Owner); let binding = AudioBindingSpec::new( ResourceRef::parse("audio.d2bus.org.AudioService/host-audio").unwrap(), ResourceRef::parse("Guest/dev-vm").unwrap(), "zone-a", - ) - .unwrap(); + ); assert!(validate_audio_service(&owner).is_ok()); assert!(validate_audio_binding(&binding).is_ok()); assert!( @@ -31,8 +29,7 @@ fn resource_specs_match_frozen_audio_wire_shape() { let owner = AudioServiceSpec::owner( ResourceRef::parse("Endpoint/audio-authority").unwrap(), "zone-a", - ) - .unwrap(); + ); let owner_json = serde_json::to_value(&owner).unwrap(); assert_eq!( owner_json["operations"], @@ -50,8 +47,7 @@ fn resource_specs_match_frozen_audio_wire_shape() { ResourceRef::parse("audio.d2bus.org.AudioService/host-audio").unwrap(), ResourceRef::parse("Guest/dev-vm").unwrap(), "zone-a", - ) - .unwrap(); + ); let binding_json = serde_json::to_value(&binding).unwrap(); assert!( binding_json.get("zone").is_none(), @@ -70,15 +66,13 @@ fn projection_and_cross_zone_or_provider_fields_fail_closed() { ResourceRef::parse("Guest/dev-vm").unwrap(), "zone-a", ) - .unwrap() .with_provider_extension(ProviderExtension::new("node-id")); assert!(validate_audio_binding(&foreign).is_err()); let cross_zone = AudioBindingSpec::new( ResourceRef::parse("audio.d2bus.org.AudioService/remote").unwrap(), ResourceRef::parse("Guest/dev-vm").unwrap(), "zone-b", - ) - .unwrap(); + ); assert_eq!( d2b_provider_audio_pipewire::validate_audio_binding_in_zone(&cross_zone, "zone-a"), Err(d2b_provider_audio_pipewire::AudioAdmissionError::CrossZone) diff --git a/packages/d2b-provider-audio-service/tests/registration.rs b/packages/d2b-provider-audio-service/tests/registration.rs index 1da2c5a26..c9e045d67 100644 --- a/packages/d2b-provider-audio-service/tests/registration.rs +++ b/packages/d2b-provider-audio-service/tests/registration.rs @@ -55,8 +55,7 @@ fn service_value() -> Value { let spec = AudioServiceSpec::owner( ResourceRef::parse("Endpoint/audio-host").expect("endpoint"), "work", - ) - .expect("service spec"); + ); serde_json::to_value(&spec).expect("spec json") } diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index 4ad0ae24c..f3f42880c 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -710,8 +710,7 @@ mod tests { ResourceRef::parse("audio.d2bus.org.AudioService/owner").unwrap(), ResourceRef::parse("Guest/work").unwrap(), "dev", - ) - .unwrap(); + ); let mut status = unavailable_status( AudioBindingPhase::Degraded, HostAudioReadiness::Unavailable, @@ -752,10 +751,9 @@ mod tests { let guest_ref = ResourceRef::parse("Guest/vm").unwrap(); let binding_ref = ResourceRef::parse("audio.d2bus.org.AudioBinding/mic").unwrap(); let service = - AudioServiceSpec::owner(ResourceRef::parse("Endpoint/audio").unwrap(), zone.as_str()) - .unwrap(); + AudioServiceSpec::owner(ResourceRef::parse("Endpoint/audio").unwrap(), zone.as_str()); let binding = - AudioBindingSpec::new(service_ref.clone(), guest_ref.clone(), zone.as_str()).unwrap(); + AudioBindingSpec::new(service_ref.clone(), guest_ref.clone(), zone.as_str()); let resource = StoredResource { resource_ref: binding_ref.clone(), zone: zone.clone(), @@ -805,8 +803,7 @@ mod tests { fn audio_decoder_reads_reserved_provider_ref_from_resource_spec() { let zone = ZoneId::parse("dev").unwrap(); let spec = - AudioServiceSpec::owner(ResourceRef::parse("Endpoint/audio").unwrap(), zone.as_str()) - .unwrap(); + AudioServiceSpec::owner(ResourceRef::parse("Endpoint/audio").unwrap(), zone.as_str()); let resource = stored_audio_resource( "audio.d2bus.org.AudioService/owner", serde_json::to_value(spec).unwrap(), From 0b767225a516c1c11f44dbded8576077771939ee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:49:57 -0700 Subject: [PATCH 376/726] xtask: drop the inventory-local duplicate path validator --- packages/xtask/src/inventory.rs | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/packages/xtask/src/inventory.rs b/packages/xtask/src/inventory.rs index d55d5d8cb..afbbdb89b 100644 --- a/packages/xtask/src/inventory.rs +++ b/packages/xtask/src/inventory.rs @@ -133,7 +133,7 @@ fn git_tracked_files(repo_root: &Path) -> Result, Box Result<(), Box> { - let candidate = Path::new(path); - if candidate.is_absolute() - || candidate.components().any(|component| { - matches!( - component, - Component::ParentDir | Component::RootDir | Component::Prefix(_) - ) - }) - { - return Err(format!("git reported non-repository-relative path: {path}").into()); - } - Ok(()) -} - fn validate_output_path( repo_root: &Path, output_path: &Path, @@ -297,7 +282,7 @@ fn path_to_repo_string(path: &Path) -> Result .ok_or_else(|| "path is not valid UTF-8".to_owned())? .trim_start_matches("./") .to_owned(); - validate_repo_relative_path(&value)?; + crate::delivery::model::validate_repo_relative_path(Path::new(&value))?; Ok(value) } @@ -634,8 +619,14 @@ version = "0.0.0" #[test] fn rejects_non_repo_relative_paths() { - assert!(validate_repo_relative_path("packages/xtask/src/main.rs").is_ok()); - assert!(validate_repo_relative_path("/home/example/repo/file").is_err()); - assert!(validate_repo_relative_path("../file").is_err()); + assert!(crate::delivery::model::validate_repo_relative_path(Path::new( + "packages/xtask/src/main.rs" + )) + .is_ok()); + assert!(crate::delivery::model::validate_repo_relative_path(Path::new( + "/home/example/repo/file" + )) + .is_err()); + assert!(crate::delivery::model::validate_repo_relative_path(Path::new("../file")).is_err()); } } From 73e1636752f9d7a08ae9e4c4881c56069e67c682 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:50:43 -0700 Subject: [PATCH 377/726] d2b-provider-network-local: log the stored spec parse failure --- packages/d2b-provider-network-local/src/driver.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index d5c1a8173..1a179931d 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -286,7 +286,12 @@ fn network_spec(spec: &Value) -> Result { spec.remove(field); } } - serde_json::from_value(spec_value).map_err(|_| ()) + serde_json::from_value(spec_value).map_err(|error| { + tracing::warn!( + error = %error, + "stored network spec failed to parse", + ); + }) } /// The Network family's desired children: the config Volume, the net-VM From fd6778735bb1feb9470c5a1df9bb604c6149d051 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:51:38 -0700 Subject: [PATCH 378/726] d2bd: warn when serving socket directory permissions fail --- packages/d2bd/src/process_provider_runtime.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index 016b77b25..177a4a213 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -3433,7 +3433,17 @@ async fn serving_worker_launch_args( .await .map_err(|_| "provider-ticket:serving-socket-dir-create".to_owned())?; use std::os::unix::fs::PermissionsExt as _; - let _ = tokio::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700)).await; + if let Err(error) = tokio::fs::set_permissions( + parent, + std::fs::Permissions::from_mode(0o700), + ).await { + tracing::warn!( + zone = %zone, + socket_dir = %parent.display(), + error = %error, + "failed to enforce 0700 on the serving worker socket directory" + ); + } } let cache = match launch.cache { AttachmentCache::Auto => "auto", From f1bb96854f20356685d4b8db69cb6925d476fe5e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:51:44 -0700 Subject: [PATCH 379/726] d2bd: refuse unknown gateway config keys and structure accept and lifecycle logs --- packages/d2bd/src/composition.rs | 100 +++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 18 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index cf99482d2..2bebed093 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -4102,7 +4102,10 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { // tests can drive a single connection deterministically. if options.once { if let Err(error) = handle_connection(stream, &state, None) { - eprintln!("{}", error.message()); + tracing::error!( + error = %error.message(), + "connection handler failed", + ); } finalize_daemon_interactions(&state).await?; break; @@ -4120,7 +4123,10 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { ACCEPT_REFUSAL_WRITE_DEADLINE, ); drain_rejected_peer_input(&stream); - eprintln!("{}", error.message()); + tracing::error!( + error = %error.message(), + "public connection authorization refused", + ); continue; } }; @@ -4150,22 +4156,24 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { .spawn(move || { // `permit` (and, for an exec session, ownership of it) is // dropped when this handler returns. + + let peer_uid = peer.uid; if let Err(error) = handle_connection_authorized(stream, &conn_state, peer, Some(permit)) { - eprintln!("{}", error.message()); + tracing::error!( + peer_uid, + error = %error.message(), + "connection handler failed", + ); } }) { // Spawn failure drops the moved closure (and its permit), so // the slot is released; log and keep serving. - eprintln!( - "{}", - TypedError::InternalIo { - context: "spawn connection handler".to_owned(), - detail: err.to_string(), - } - .message() + tracing::error!( + error = %err, + "connection handler thread spawn failed", ); } } @@ -4217,7 +4225,7 @@ pub struct GatewayGuestZoneLinkOptions { } #[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] struct GatewayGuestConfigFile { credential_path: PathBuf, seal_key_path: PathBuf, @@ -4226,7 +4234,7 @@ struct GatewayGuestConfigFile { } #[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] struct GatewayGuestRelayConfigFile { namespace: Option, entity: Option, @@ -4364,6 +4372,41 @@ async fn load_gateway_guest_zone_link_options( })) } +#[cfg(test)] +mod gateway_guest_config_tests { + use super::*; + + /// A typo in the user-written Guest gateway config must be refused at + /// the deserialization boundary, not silently ignored until the Relay + /// namespace lookup later fails. + + #[test] + fn gateway_guest_config_typo_is_refused_at_parse() { + let error = serde_json::from_slice::( + br#"{"credentialPath":"/run/gateway/cred","sealKeyPath":"/run/gateway/seed","relay":{"namespace":"ns","entity":"ent"},"typoKey":true}"#, + ) + .expect_err("a typo'd gateway guest config key must be refused"); + assert!( + error.to_string().contains("unknown field"), + "the typo must surface as the serde unknown-field error: {error}" + ); + } + + /// The Relay sub-object refuses unknown keys at the same boundary. + + #[test] + fn gateway_guest_relay_config_typo_is_refused_at_parse() { + let error = serde_json::from_slice::( + br#"{"namespace":"ns","entity":"ent","typoKey":true}"#, + ) + .expect_err("a typo'd relay config key must be refused"); + assert!( + error.to_string().contains("unknown field"), + "the typo must surface as the serde unknown-field error: {error}" + ); + } +} + /// The journal-visible event every accepted Guest ComponentSession publishes. /// /// The host journal is where the Guest console is forwarded, and `d2bd`'s @@ -4508,7 +4551,11 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { }) .transpose()?; if gateway_zone_link.is_some() { - tracing::info!("Guest-local ZoneLink transport Provider composed"); + tracing::info!( + zone = %identity.zone(), + guest_ref = %identity.guest_ref().name().as_str(), + "Guest-local ZoneLink transport Provider composed", + ); } let local_private_path = options @@ -4559,7 +4606,11 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { d2b_provider_guest::production_guest_target_effects(), ), ); - tracing::info!("Guest target-control service composed"); + tracing::info!( + zone = %identity.zone(), + guest_ref = %identity.guest_ref().name().as_str(), + "Guest target-control service composed", + ); let mut sigterm = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) .map_err(|_| TypedError::InternalIo { context: "install Guest SIGTERM handler".to_owned(), @@ -5329,7 +5380,11 @@ async fn run_startup_autostart(state: &ServerState, kernel_module_degraded: &BTr }; let plan = d2bd_runtime::autostart::build_autostart_plan(&resolver); if plan.vms.is_empty() { - tracing::info!("autostart: nothing to do (empty plan)"); + tracing::info!( + net_vm_count = plan.net_vms().count(), + workload_count = plan.workload_vms().count(), + "autostart: nothing to do (empty plan)", + ); return; } tracing::info!( @@ -14810,7 +14865,10 @@ async fn compose_gateway_zone_links( .authority_bundle_generation() .map(|value| value.as_str().to_owned()) else { - tracing::error!("Gateway Guest composition refused: root Zone generation unavailable"); + tracing::error!( + zone = %topology.root, + "Gateway Guest composition refused: root Zone generation unavailable", + ); return; }; let authority_generation = root.current_revision().get().max(1); @@ -15217,7 +15275,10 @@ async fn shutdown_resource_plane(state: &ServerState) -> Result<(), std::io::Err .await?; } *state.resource_plane.lock().await = Some(Arc::new(plane)); - tracing::warn!("resource plane still has live request owners during shutdown"); + tracing::warn!( + zones = ?zones, + "resource plane still has live request owners during shutdown", + ); } Err(error) => { for zone in &zones { @@ -15243,7 +15304,10 @@ async fn shutdown_resource_plane(state: &ServerState) -> Result<(), std::io::Err ) .await?; } - tracing::warn!("resource plane still has live request owners during shutdown"); + tracing::warn!( + zones = ?zones, + "resource plane still has live request owners during shutdown", + ); } } } From 7d2724dbafe4d4548efc82c9b148e7ef783c7dd7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:51:58 -0700 Subject: [PATCH 380/726] azure-relay: carry sealed observations and clock faults through the guest zone link boundary --- .../src/credential_client.rs | 3 ++ .../src/guest_credential.rs | 16 +++++----- .../src/guest_zone_link.rs | 30 ++++++++++--------- .../src/relay_transport.rs | 3 +- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/packages/d2b-provider-transport-azure-relay/src/credential_client.rs b/packages/d2b-provider-transport-azure-relay/src/credential_client.rs index 6d3f61740..d1b07a771 100644 --- a/packages/d2b-provider-transport-azure-relay/src/credential_client.rs +++ b/packages/d2b-provider-transport-azure-relay/src/credential_client.rs @@ -431,6 +431,8 @@ pub enum RelayCredentialError { Unavailable, /// Lease is expired. Expired, + /// The system clock was before the Unix epoch. + Clock, /// Lease has the wrong role. RoleMismatch, /// The exact lease was not active in the credential Provider. @@ -448,6 +450,7 @@ impl fmt::Display for RelayCredentialError { Self::InvalidScope => "relay-credential-scope-invalid", Self::Unavailable => "relay-credential-unavailable", Self::Expired => "relay-credential-expired", + Self::Clock => "relay-credential-clock", Self::RoleMismatch => "relay-credential-role-mismatch", Self::UnknownLease => "relay-credential-unknown-lease", }) diff --git a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs index ead7503d3..db284b1aa 100644 --- a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs +++ b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs @@ -279,7 +279,7 @@ struct ActiveRelayLease { pub struct GatewayGuestCredentialPort { credential: Arc, active: Arc>>, - now_unix_ms: Arc u64 + Send + Sync>, + now_unix_ms: Arc Result + Send + Sync>, } impl GatewayGuestCredentialPort { @@ -291,7 +291,7 @@ impl GatewayGuestCredentialPort { /// Build a Guest-local port with an injected clock for deterministic tests. pub fn with_clock( credential: Arc, - now_unix_ms: Arc u64 + Send + Sync>, + now_unix_ms: Arc Result + Send + Sync>, ) -> Self { Self { credential, @@ -394,7 +394,7 @@ impl RelayCredentialPort for GatewayGuestCredentialPort { ); return Err(RelayCredentialError::Unavailable); } - let now = (self.now_unix_ms)(); + let now = (self.now_unix_ms)()?; let requested_ttl = u64::from(deadline_ms).min(MAX_RELAY_LEASE_TTL_MS); let mut expires_at = now.saturating_add(requested_ttl).saturating_add(1_000); if let Some(not_after) = self @@ -647,11 +647,11 @@ fn required_str(v: &Value, path: &[&str]) -> Result { .ok_or(CredentialError::Malformed) } -fn system_now_unix_ms() -> u64 { +fn system_now_unix_ms() -> Result { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .map(|duration| duration.as_millis() as u64) - .unwrap_or(0) + .map_err(|_| RelayCredentialError::Clock) } fn valid_material_text(value: &str) -> bool { @@ -913,7 +913,7 @@ mod tests { ) .unwrap(), ); - let port = GatewayGuestCredentialPort::with_clock(credential, Arc::new(|| 1_000_000)); + let port = GatewayGuestCredentialPort::with_clock(credential, Arc::new(|| Ok(1_000_000))); assert!(matches!( port.acquire(RelayCredentialRole::Send, 1_000).await, Err(RelayCredentialError::BindingRequired) @@ -949,7 +949,7 @@ mod tests { ) .unwrap(), ); - let port = GatewayGuestCredentialPort::with_clock(credential, Arc::new(|| 1_000_000)); + let port = GatewayGuestCredentialPort::with_clock(credential, Arc::new(|| Ok(1_000_000))); let binding = RelayCredentialBinding::new("link-drop", "session-drop", 1).unwrap(); let lease = port .acquire_bound(RelayCredentialRole::Listen, &binding, 1_000) @@ -1014,7 +1014,7 @@ mod tests { ) .unwrap(), ); - let port = GatewayGuestCredentialPort::with_clock(credential, Arc::new(|| 10_000)); + let port = GatewayGuestCredentialPort::with_clock(credential, Arc::new(|| Ok(10_000))); let binding = RelayCredentialBinding::new("link", "session", 1).unwrap(); assert!(matches!( port.acquire_bound(RelayCredentialRole::Listen, &binding, 1_000) diff --git a/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs b/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs index f2b2c2166..1fc144b10 100644 --- a/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs +++ b/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs @@ -138,6 +138,12 @@ pub struct RelayCarriageRequest { pub deadline_ms: u32, } +/// Non-secret marker data carried by a sealed credential open. +struct SealedObservation { + generation: u64, + send_key_digest: [u8; 32], +} + /// Gateway Guest-local Azure Relay Provider and credential boundary. /// /// Credential custody is supplied either by the Guest-local sealed bootstrap @@ -146,8 +152,7 @@ pub struct RelayCarriageRequest { /// carrying protected ComponentSession data. pub struct GatewayGuestZoneLinkRuntime { provider: AzureRelayTransportProvider, - credential_generation: Option, - credential_send_key_digest: Option<[u8; 32]>, + credential_observation: Option, } impl std::fmt::Debug for GatewayGuestZoneLinkRuntime { @@ -176,8 +181,10 @@ impl GatewayGuestZoneLinkRuntime { policy, system_now_unix(), )?; - let credential_generation = credentials.credential_generation(); - let credential_send_key_digest = credentials.safe_observation_digest(); + let observation = SealedObservation { + generation: credentials.credential_generation(), + send_key_digest: credentials.safe_observation_digest(), + }; let provider = AzureRelayTransportProvider::new( RelayTransportConfig { execution_ref: config.execution_ref, @@ -194,8 +201,7 @@ impl GatewayGuestZoneLinkRuntime { .map_err(|_| GatewayGuestZoneLinkError::TransportConfiguration)?; Ok(Self { provider, - credential_generation: Some(credential_generation), - credential_send_key_digest: Some(credential_send_key_digest), + credential_observation: Some(observation), }) } @@ -230,8 +236,7 @@ impl GatewayGuestZoneLinkRuntime { .map_err(|_| GatewayGuestZoneLinkError::TransportConfiguration)?; Ok(Self { provider, - credential_generation: None, - credential_send_key_digest: None, + credential_observation: None, }) } @@ -249,10 +254,7 @@ impl GatewayGuestZoneLinkRuntime { &self, path: impl AsRef, ) -> Result<(), GatewayGuestZoneLinkError> { - let (Some(credential_generation), Some(credential_send_key_digest)) = ( - self.credential_generation, - self.credential_send_key_digest, - ) else { + let Some(observation) = &self.credential_observation else { return Err(GatewayGuestZoneLinkError::ObservationUnavailable); }; let path = path.as_ref(); @@ -268,8 +270,8 @@ impl GatewayGuestZoneLinkRuntime { let temporary = parent.join(format!(".{file_name}.{}", std::process::id())); let marker = format!( "schemaVersion=1\ngeneration={}\ndigest=sha256:{}\n", - credential_generation, - digest_hex(&credential_send_key_digest), + observation.generation, + digest_hex(&observation.send_key_digest), ); let result = (|| { let mut file = OpenOptions::new() diff --git a/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs b/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs index 38d127116..c427c0e30 100644 --- a/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs +++ b/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs @@ -1090,7 +1090,8 @@ impl std::error::Error for RelayTransportError {} fn map_credential_error(error: crate::RelayCredentialError) -> RelayTransportError { match error { crate::RelayCredentialError::Unavailable => RelayTransportError::CredentialUnavailable, - crate::RelayCredentialError::Expired => RelayTransportError::CredentialExpired, + crate::RelayCredentialError::Expired + | crate::RelayCredentialError::Clock => RelayTransportError::CredentialExpired, crate::RelayCredentialError::RoleMismatch => RelayTransportError::CredentialRoleMismatch, crate::RelayCredentialError::InvalidBinding | crate::RelayCredentialError::BindingRequired From 7ee45a2658f7d7d86df6eb5ff5e9e319f8566e4c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:52:32 -0700 Subject: [PATCH 381/726] d2b-bus: carry the sanctioned allow on the extracted verification helper The wall-clock wrapper kept its inline allow when the body moved into a helper, so the helper's lock went uncovered and plain-cargo clippy failed for this crate and every dependant while the Bazel clippy action stayed green. Same reason string as the four sibling functions; provider crate layout check passes. --- packages/d2b-bus/src/session/contract.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/d2b-bus/src/session/contract.rs b/packages/d2b-bus/src/session/contract.rs index c98b6db9b..a8cfc9b47 100644 --- a/packages/d2b-bus/src/session/contract.rs +++ b/packages/d2b-bus/src/session/contract.rs @@ -957,6 +957,7 @@ impl RouteAdmissionVerifier { /// Re-check the runtime-owned authority state against one borrowed /// admission body, without constructing owned evidence. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn verify_body( &self, body: &RouteAdmissionBody, From f3de86e60be0a346ddddf4412b4ee71b440e4ee2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:52:34 -0700 Subject: [PATCH 382/726] audit: reclassify the bus clippy red as the wave-1 regression it was Recorded from evidence: the allow went missing when a wave-1 batch commit extracted the helper, not before the audit. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index e95a3808c..83bc93969 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -24,7 +24,7 @@ Measured at `147a536a0` in a dedicated gates worktree before any wave-0 fix land Defects the audited surfaces carry at HEAD that no corpus row claims and no wave fixes. They are recorded here so a later reader does not mistake them for wave regressions, and they route to an ordinary review pass or the owning package owner rather than to a leaf row. - `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Observed at the wave-2 base. A test-only allow is the broker package owner's policy call. -- `cargo clippy -p d2b-bus --locked --all-targets` (and `--lib`) stops at the first error `use of a disallowed method std::sync::Mutex::lock` in `packages/d2b-bus/src/session/contract.rs:967`, lint `clippy::disallowed_methods`. This is production code on the parked blocking-API backlog that `clippy.toml` documents and the blocking census tracks, so the site is a census item rather than a wave-2 fix; a leaf row must not add an inline allow, because `xtask provider-crate-policy` only accepts allows that its own list carries. +- (wave-1 regression, fixed on the integration branch) `cargo clippy -p d2b-bus --locked --all-targets` stopped at `use of a disallowed method std::sync::Mutex::lock` in `packages/d2b-bus/src/session/contract.rs`. The missing inline allow arrived with the wave-1 batch commit `fbf92683a`, which extracted `verify_body` out of the already-sanctioned `verify`; wave 1's Bazel clippy action did not flag the extraction, so the wave gate stayed green while plain-cargo clippy went red for `d2b-bus` and every crate depending on it. Fixed with the same sanctioned reason its four sibling functions use (`synchronous path`); `xtask check-provider-crate-layout` validates allow reasons against its sanctioned set rather than a per-site list, so no list changed and the site is not an ad-hoc allow. The broker test-helper entries below stay pre-existing and unfixed. - `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. ## Wave gates From 77cf1c4343380a069f69b110df45fa6f06f51481 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:52:37 -0700 Subject: [PATCH 383/726] d2b-provider-guest-azure-virtual-machine: carry typed and instrumented control-loop state The resize update carries the size SKU as a validated OpaqueAzureRef (JSON shape unchanged, plain string) so the two re-parses in validate_update and apply_update disappear; the controller takes and stores the effect by value instead of an Arc the only callers never share; and the five controller entry points open an instrument span carrying the provider identity so the per-event provider literal and the redacted resource_group field can be dropped from the wire events. --- .../Cargo.toml | 2 +- .../src/controller/mod.rs | 61 +++--------- .../tests/lifecycle_hermetic.rs | 93 ++++++++++++------- 3 files changed, 69 insertions(+), 87 deletions(-) diff --git a/packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml b/packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml index 2dc74608e..feefd24f1 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml +++ b/packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml @@ -21,7 +21,7 @@ d2b-contracts = { path = "../d2b-contracts", version = "0.0.0-bootstrap" } d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-bootstrap" } async-trait = "0.1" base64 = { workspace = true } -tracing = "0.1" +tracing = { version = "0.1", features = ["attributes"] } serde = { workspace = true } sha2 = { workspace = true } zeroize = "1" diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs index 2e928c155..74f54aa66 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs @@ -80,7 +80,7 @@ pub enum AzureVmUpdate { /// Resize the VM to a new Azure size SKU. Resize { /// New size SKU. - size: String, + size: d2b_contracts::OpaqueAzureRef, }, /// Attach a provider-owned data disk. AttachDisk { @@ -179,7 +179,7 @@ impl fmt::Debug for AzureVmStatus { pub struct AzureVmController { provider_config: AzureVmConfig, settings: AzureVmGuestSettings, - effect: Arc, + effect: E, credentials: Arc, phase: AzureVmPhase, finalizer: bool, @@ -208,7 +208,7 @@ where pub fn new( provider_config: AzureVmConfig, settings: AzureVmGuestSettings, - effect: Arc, + effect: E, credentials: Arc, bootstrap_psk: Option, ) -> Result { @@ -346,6 +346,7 @@ where /// variants) for retryable effect failures, and the fatal variants /// (`BootstrapFailed`, `ArmProvisioningFailed`, `ArmCredentialDenied`) /// when an effect cannot be retried. + #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] pub async fn reconcile( &mut self, zone_uid: &str, @@ -362,7 +363,6 @@ where tracing::warn!( zone = %zone_uid, resource = %guest_uid, - provider = "runtime-azure-virtual-machine", "bootstrap deadline previously failed; failing generation" ); self.phase = AzureVmPhase::Failed; @@ -420,7 +420,6 @@ where tracing::warn!( zone = %zone_uid, resource = %guest_uid, - provider = "runtime-azure-virtual-machine", state = ?state, "VM provisioning state failed or unknown" ); @@ -438,6 +437,7 @@ where /// missing, [`AzureVmError::Ambiguous`] when the observed VM identity /// does not match the tag digest, and the ARM effect variants for /// retryable and fatal effect failures. + #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] pub async fn adopt(&mut self) -> Result { if !self.finalizer { return Err(AzureVmError::InvalidConfiguration); @@ -446,8 +446,6 @@ where let (state, handle, tags) = self.effect.get_vm_state(&self.settings, &token).await?; if state != AzureVmState::Running { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", state = ?state, "adoption refused: VM is not running" ); @@ -472,22 +470,19 @@ where /// Returns [`AzureVmError::InvalidOperationHandle`] when the supplied /// handle is not the current operation, and the ARM effect variants for /// retryable and fatal polling failures. + #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] pub async fn poll_operation( &mut self, operation: crate::effect::AzureOperationHandle, ) -> Result { if self.operation.as_ref() != Some(&operation) { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", "poll called with a foreign operation handle" ); return Err(AzureVmError::InvalidOperationHandle); } if self.operation_expired() { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", phase = ?self.phase, "long-running operation exceeded maximum age; abandoning" ); @@ -507,8 +502,6 @@ where }), LroStatus::Failed => { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", phase = ?self.phase, "long-running operation failed" ); @@ -547,8 +540,6 @@ where self.effect.get_vm_state(&self.settings, &token).await?; if state != AzureVmState::Running { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", state = ?state, "VM not running after provision LRO succeeded" ); @@ -577,8 +568,6 @@ where self.bootstrap_psk = None; if self.bootstrap_deadline_failed { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", "bootstrap deadline failed; refusing to mark VM ready" ); self.phase = AzureVmPhase::Failed; @@ -596,8 +585,6 @@ where Some(update) => update, None => { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", "reconfiguration LRO succeeded without pending update" ); return Err(AzureVmError::Ambiguous); @@ -605,8 +592,6 @@ where }; if let Err(error) = self.apply_update(update) { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", code = error.code(), "applied update rejected during reconfiguration" ); @@ -638,6 +623,7 @@ where /// when the update contradicts the current VM shape, /// [`AzureVmError::Ambiguous`] when the owned VM identity is absent, /// and the ARM effect variants for retryable and fatal failures. + #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] pub async fn update( &mut self, zone_uid: &str, @@ -649,7 +635,6 @@ where tracing::warn!( zone = %zone_uid, resource = %guest_uid, - provider = "runtime-azure-virtual-machine", phase = ?self.phase, "update rejected: VM is not in Ready phase" ); @@ -659,7 +644,6 @@ where tracing::debug!( zone = %zone_uid, resource = %guest_uid, - provider = "runtime-azure-virtual-machine", "update deferred while another operation is in flight" ); return Ok(AzureVmReconcileOutcome::Progressing { after_ms: 250 }); @@ -668,7 +652,6 @@ where tracing::warn!( zone = %zone_uid, resource = %guest_uid, - provider = "runtime-azure-virtual-machine", code = error.code(), "update rejected: validation failed" ); @@ -681,7 +664,7 @@ where let operation = match &update { AzureVmUpdate::Resize { size } => { self.effect - .start_vm_resize(handle, size, &operation_id, &token) + .start_vm_resize(handle, size.as_str(), &operation_id, &token) .await? } AzureVmUpdate::AttachDisk { disk } => { @@ -713,6 +696,7 @@ where /// Returns [`AzureVmError::Ambiguous`] when the owned VM identity or /// pending delete operation is absent, and the ARM effect variants for /// retryable and fatal deletion failures. + #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] pub async fn finalize( &mut self, zone_uid: &str, @@ -764,7 +748,6 @@ where tracing::warn!( zone = %zone_uid, resource = %guest_uid, - provider = "runtime-azure-virtual-machine", state = ?state, "VM state failed or unknown during finalization" ); @@ -817,8 +800,6 @@ where .get_or_insert_with(|| self.clock.now_unix_ms()); if self.clock.now_unix_ms().saturating_sub(started) >= self.settings.bootstrap_deadline_ms { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", "bootstrap PSK delivery deadline elapsed" ); self.phase = AzureVmPhase::Failed; @@ -826,8 +807,6 @@ where } if self.psk_delivery_attempts >= MAX_PSK_DELIVERY_ATTEMPTS { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", attempts = self.psk_delivery_attempts, "bootstrap PSK delivery attempts exhausted" ); @@ -864,8 +843,6 @@ where >= self.settings.bootstrap_deadline_ms { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", "bootstrap enrollment deadline elapsed before guest enrolled" ); self.phase = AzureVmPhase::Failed; @@ -918,8 +895,6 @@ where } AzureVmState::Failed | AzureVmState::Unknown => { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", state = ?state, "VM state failed or unknown during pending delete" ); @@ -982,8 +957,6 @@ where ) -> Result<(AzureVmHandle, TagDigest), AzureVmError> { let Some(handle) = handle else { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", stage, "running VM observed without effect handle" ); @@ -991,8 +964,6 @@ where }; let Some(tags) = tags else { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", stage, "VM tag digest missing; refusing foreign or drifted resource" ); @@ -1000,8 +971,6 @@ where }; if tags != self.expected_tag_digest { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", stage, "VM tag digest mismatch; refusing foreign or drifted resource" ); @@ -1029,10 +998,7 @@ where fn validate_update(&self, update: &AzureVmUpdate) -> Result<(), AzureVmError> { match update { - AzureVmUpdate::Resize { size } => { - d2b_contracts::OpaqueAzureRef::parse(size.clone()) - .map_err(|_| AzureVmError::InvalidConfiguration)?; - } + AzureVmUpdate::Resize { .. } => {} AzureVmUpdate::AttachDisk { disk } => { let mut settings = self.settings.clone(); settings.data_disks.push(disk.clone()); @@ -1054,10 +1020,7 @@ where fn apply_update(&mut self, update: AzureVmUpdate) -> Result<(), AzureVmError> { match update { - AzureVmUpdate::Resize { size } => { - self.settings.vm_size = d2b_contracts::OpaqueAzureRef::parse(size) - .map_err(|_| AzureVmError::InvalidConfiguration)?; - } +AzureVmUpdate::Resize { size } => self.settings.vm_size = size, AzureVmUpdate::AttachDisk { disk } => self.settings.data_disks.push(disk), AzureVmUpdate::DetachDisk { lun } => { self.settings.data_disks.retain(|disk| disk.lun != lun) @@ -1075,8 +1038,6 @@ where .await .inspect_err(|error| { tracing::warn!( - resource_group = %self.settings.resource_group, - provider = "runtime-azure-virtual-machine", code = error.code(), "ARM access token acquisition failed" ); diff --git a/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs b/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs index 712f43dcb..bd37c9fc2 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs @@ -265,6 +265,26 @@ fn azure_wire_enums_use_adr_values() { ); } +#[test] +fn azure_vm_update_resize_round_trips_with_the_plain_string_wire_shape() { + let update = AzureVmUpdate::Resize { + size: OpaqueAzureRef::parse("standard-d8").unwrap(), + }; + let encoded = serde_json::to_value(&update).unwrap(); + assert_eq!( + encoded, + serde_json::json!({ "resize": { "size": "standard-d8" } }) + ); + assert_eq!( + serde_json::from_value::(encoded).unwrap(), + update + ); + assert!( + serde_json::from_str::(r#"{"resize":{"size":""}}"#).is_err(), + "the size SKU is validated at the deserialization boundary" + ); +} + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn absent_vm_starts_non_blocking_provision() { @@ -273,9 +293,9 @@ async fn absent_vm_starts_non_blocking_provision() { state: AzureVmState::Absent, ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new( provider, settings, @@ -300,9 +320,9 @@ async fn observed_provisioning_vm_is_not_provisioned_again_after_restart() { state: AzureVmState::Provisioning, ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None).unwrap(); @@ -319,9 +339,9 @@ async fn observed_provisioning_vm_is_not_provisioned_again_after_restart() { async fn poll_rejects_an_operation_handle_that_is_not_current() { let (provider, settings) = config(); let state = Arc::new(Mutex::new(FakeState::default())); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None).unwrap(); controller.reconcile("zone", "guest", 1).await.unwrap(); @@ -347,7 +367,7 @@ async fn finalize_preserves_the_first_delete_operation_id() { tags: Some(expected_tag_digest()), ..FakeState::default() })); - let effect = Arc::new(FakeEffect { state }); + let effect = FakeEffect { state }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); @@ -370,13 +390,12 @@ async fn recovery_state_restores_opaque_lro_without_secret_material() { polls: vec![LroStatus::Succeeded, LroStatus::Succeeded], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { - state: Arc::clone(&state), - }); let controller = AzureVmController::new( provider.clone(), settings.clone(), - Arc::clone(&effect), + FakeEffect { + state: Arc::clone(&state), + }, credential(), Some(BootstrapPsk::from_bytes(b"one-time").unwrap()), ) @@ -391,7 +410,9 @@ async fn recovery_state_restores_opaque_lro_without_secret_material() { let mut restored = AzureVmController::new( provider, settings, - effect, + FakeEffect { + state: Arc::clone(&state), + }, credential(), Some(BootstrapPsk::from_bytes(b"one-time").unwrap()), ) @@ -412,9 +433,9 @@ async fn restart_adopts_only_tagged_running_vm() { tags: Some(expected_tag_digest()), ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); @@ -437,7 +458,7 @@ async fn delete_keeps_finalizer_until_lro_completion() { polls: vec![LroStatus::Succeeded, LroStatus::Succeeded], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { state }); + let effect = FakeEffect { state }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); @@ -470,7 +491,7 @@ async fn running_vm_waits_for_authenticated_enrollment() { tags: Some(expected_tag_digest()), ..FakeState::default() })); - let effect = Arc::new(FakeEffect { state }); + let effect = FakeEffect { state }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None).unwrap(); assert!(matches!( @@ -492,9 +513,9 @@ async fn ready_vm_accepts_typed_resize_and_commits_after_lro() { polls: vec![LroStatus::Succeeded], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); @@ -506,7 +527,7 @@ async fn ready_vm_accepts_typed_resize_and_commits_after_lro() { "guest", 1, AzureVmUpdate::Resize { - size: "standard-d8".into(), + size: OpaqueAzureRef::parse("standard-d8").unwrap(), }, ) .await @@ -539,9 +560,9 @@ async fn failed_update_lro_honors_pending_delete_intent() { ], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); @@ -552,7 +573,7 @@ async fn failed_update_lro_honors_pending_delete_intent() { "guest", 1, AzureVmUpdate::Resize { - size: "standard-d8".into(), + size: OpaqueAzureRef::parse("standard-d8").unwrap(), }, ) .await @@ -589,9 +610,9 @@ async fn restart_with_pending_delete_never_reprovisions_an_absent_vm() { polls: vec![LroStatus::Succeeded], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .restore_recovery_state(AzureVmRecoveryState { @@ -634,7 +655,7 @@ async fn foreign_tags_are_not_adopted() { tags: Some(TagDigest::from_core([9; 32])), ..FakeState::default() })); - let effect = Arc::new(FakeEffect { state }); + let effect = FakeEffect { state }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); @@ -656,9 +677,9 @@ async fn restart_finalization_reobserves_before_clearing_finalizer() { polls: vec![LroStatus::Succeeded, LroStatus::Succeeded], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); @@ -687,9 +708,9 @@ async fn provisioning_lro_delivers_psk_before_bootstrap_phase() { polls: vec![LroStatus::Succeeded, LroStatus::Succeeded], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new( provider, settings, @@ -725,9 +746,9 @@ async fn failed_extension_lro_redelivers_psk_without_losing_secret() { ], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new( provider, settings, @@ -768,9 +789,9 @@ async fn transient_extension_failure_does_not_consume_delivery_attempt() { extension_failures: 1, ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let mut controller = AzureVmController::new( provider, settings, @@ -808,7 +829,7 @@ async fn running_vm_fails_closed_at_bootstrap_deadline() { tags: Some(expected_tag_digest()), ..FakeState::default() })); - let effect = Arc::new(FakeEffect { state }); + let effect = FakeEffect { state }; let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_clock(Arc::new(FixedClock(Arc::clone(&now)))); @@ -830,9 +851,9 @@ async fn bootstrap_deadline_retries_failed_extension_cleanup() { polls: vec![LroStatus::Succeeded], ..FakeState::default() })); - let effect = Arc::new(FakeEffect { + let effect = FakeEffect { state: Arc::clone(&state), - }); + }; let now = Arc::new(Mutex::new(60_000)); let controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() From cc5b7ae0b087799275ade1d67b4ea63369e71ba3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:52:40 -0700 Subject: [PATCH 384/726] d2b-provider-guest: pass the azure effect by value --- packages/d2b-provider-guest/src/effects_service.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index 6b94d8311..bbcfd0a12 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -1186,9 +1186,9 @@ impl GuestEffectsService { let controller = azure_vm_runtime::AzureVmController::new( config, settings, - Arc::new(FrameworkAzureEffect { + FrameworkAzureEffect { state: Arc::clone(&state), - }), + }, Arc::new(FrameworkAzureCredential), None, ) @@ -1892,9 +1892,9 @@ mod tests { child_zone_hosting: false, azure_tags: Vec::new(), }; - let effect = Arc::new(FrameworkAzureEffect { + let effect = FrameworkAzureEffect { state: Arc::new(tokio::sync::Mutex::new(FrameworkAzureState::new(&settings))), - }); + }; let mut controller = azure_vm_runtime::AzureVmController::new( config, settings, From 205e888b90ac85cebd404b88612cd529b20fe948 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:52:45 -0700 Subject: [PATCH 385/726] d2b-provider-device-tpm: confine the live resource effect port to the crate --- packages/d2b-provider-device-tpm/src/effects_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-device-tpm/src/effects_service.rs b/packages/d2b-provider-device-tpm/src/effects_service.rs index d2b770cc2..446e2b5ab 100644 --- a/packages/d2b-provider-device-tpm/src/effects_service.rs +++ b/packages/d2b-provider-device-tpm/src/effects_service.rs @@ -338,7 +338,7 @@ impl DeclaredTpmRows<'_> { /// broker calls that remain are the one-time legacy state adoption and the /// broker-owned state-directory preparation, neither of which launches a /// process. -pub struct LiveTpmResourceEffectPort<'a> { +pub(crate) struct LiveTpmResourceEffectPort<'a> { facets: TpmEffectFacets, vm_id: VmId, /// The Zone the Device row lives in: every manager/broker surface this From 4de51c1b578a83e3a999b4b626e5e6aeea638cfe Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:52:49 -0700 Subject: [PATCH 386/726] d2bd: host the TPM effects service factory in the plane test inputs --- packages/d2bd/src/shared_provider_effects.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 68c23ff1f..58fb74d70 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -3355,7 +3355,8 @@ mod tests { let device_facets = d2b_provider_device::test_support::recording_facets( Arc::new(d2b_provider_device::test_support::RecordingRuntime::default()), ); - // U6: the plane tests build the VolumeBinding and Endpoint families' + let tpm_facets = d2b_provider_device_tpm::test_support::recording_facets(); + // U6:the plane tests build the VolumeBinding and Endpoint families' // facet sets from the scripted doubles, exactly as the production // composition root builds them from the daemon's registry, plane // table, and target directory. @@ -3524,6 +3525,12 @@ mod tests { DeviceEffectsServiceFactory::new(device_facets)) as Arc, ), + ( + d2b_provider_device_tpm::effects_service::TPM_EFFECTS_SERVICE.id, + Arc::new(d2b_provider_device_tpm::effects_service::TpmEffectsServiceFactory::new( + tpm_facets.clone(), + )) as Arc, + ), ( d2b_provider_volume_binding::BINDING_EFFECTS_SERVICE.id, Arc::new(d2b_provider_volume_binding::BindingEffectsServiceFactory::new( From c47b8ba63ce368a322d330ff5387b6337e9195d9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:52:50 -0700 Subject: [PATCH 387/726] d2b-provider-device-usbip: narrow the state-machine module to crate visibility --- packages/d2b-provider-device-usbip/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-device-usbip/src/lib.rs b/packages/d2b-provider-device-usbip/src/lib.rs index 9ff955cf2..c4fb9db5b 100644 --- a/packages/d2b-provider-device-usbip/src/lib.rs +++ b/packages/d2b-provider-device-usbip/src/lib.rs @@ -21,7 +21,7 @@ mod lifecycle; mod process; mod production; pub mod reconcile_state; -pub mod state_machine; +mod state_machine; pub mod vocabulary; mod workers; From 854ba06a53cb877288f33c39ec8083653cb56a95 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:53:07 -0700 Subject: [PATCH 388/726] d2b-resource-client: name the waker-registry lock poisoning choice --- packages/d2b-resource-client/src/call.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/d2b-resource-client/src/call.rs b/packages/d2b-resource-client/src/call.rs index 0969eb7e4..0e79c6094 100644 --- a/packages/d2b-resource-client/src/call.rs +++ b/packages/d2b-resource-client/src/call.rs @@ -329,7 +329,7 @@ impl Future for CancellationFuture { // and the critical section is a short push/retain with no suspension // point; the std lock is the sanctioned synchronous path (plan R11). #[allow(clippy::disallowed_methods, reason = "synchronous path")] - let mut waiters = state.waiters.lock().unwrap(); + let mut waiters = state.waiters.lock().expect("waker registry lock is not poisoned: no user code runs under it"); if state.cancelled.load(Ordering::Acquire) { return Poll::Ready(()); } @@ -357,7 +357,7 @@ impl Drop for CancellationFuture { return; }; #[allow(clippy::disallowed_methods, reason = "synchronous path")] - let mut waiters = self.state.waiters.lock().unwrap(); + let mut waiters = self.state.waiters.lock().expect("waker registry lock is not poisoned: no user code runs under it"); waiters.retain(|(id, _)| *id != registered); } } @@ -383,7 +383,7 @@ impl CancellationToken { // Synchronous cancellation surface (no async form): the waker // drain is a short take/wake with no suspension point (plan R11). #[allow(clippy::disallowed_methods, reason = "synchronous path")] - let waiters = std::mem::take(&mut *self.state.waiters.lock().unwrap()); + let waiters = std::mem::take(&mut *self.state.waiters.lock().expect("waker registry lock is not poisoned: no user code runs under it")); for (_, waiter) in waiters { waiter.wake(); } From aee724326a2ab66d2ae6821ed059285e72461e80 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:53:11 -0700 Subject: [PATCH 389/726] process-systemd: type the metric label key as MetricLabelKey --- .../src/metrics.rs | 32 +++++++++++++++---- .../tests/boundaries.rs | 16 ++++------ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/d2b-provider-process-systemd/src/metrics.rs b/packages/d2b-provider-process-systemd/src/metrics.rs index a71e5e93a..e6081edb9 100644 --- a/packages/d2b-provider-process-systemd/src/metrics.rs +++ b/packages/d2b-provider-process-systemd/src/metrics.rs @@ -1,14 +1,32 @@ //! Closed systemd Provider metric labels. -/// Allowed low-cardinality process metric labels. -pub const LABEL_KEYS: &[&str] = &["operation", "outcome", "domain"]; +/// Low-cardinality process metric label key. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MetricLabelKey { + /// The operation class being measured. + Operation, + /// The terminal outcome of the operation. + Outcome, + /// The execution domain the operation ran in. + Domain, +} + +impl MetricLabelKey { + /// Return the stable lower-kebab label key. + pub const fn as_str(self) -> &'static str { + match self { + Self::Operation => "operation", + Self::Outcome => "outcome", + Self::Domain => "domain", + } + } +} /// Validate a metric label set without accepting resource names or units. -pub fn validate_labels(labels: &[(String, String)]) -> bool { - labels.iter().all(|(key, value)| { - LABEL_KEYS.contains(&key.as_str()) - && value.len() <= 32 +pub fn validate_labels(labels: &[(MetricLabelKey, String)]) -> bool { + labels.iter().all(|(_, value)| { + value.len() <= 32 && !value.contains('/') && !value.contains(':') }) -} +} \ No newline at end of file diff --git a/packages/d2b-provider-process-systemd/tests/boundaries.rs b/packages/d2b-provider-process-systemd/tests/boundaries.rs index 551258f84..26d8e2407 100644 --- a/packages/d2b-provider-process-systemd/tests/boundaries.rs +++ b/packages/d2b-provider-process-systemd/tests/boundaries.rs @@ -1,5 +1,5 @@ use d2b_provider_process_systemd::drain::{DrainError, DrainProof, DrainStage, validate}; -use d2b_provider_process_systemd::metrics::validate_labels; +use d2b_provider_process_systemd::metrics::{MetricLabelKey, validate_labels}; #[test] fn drain_requires_exact_stop_manager_terminal_and_empty_leaf() { @@ -26,21 +26,17 @@ fn drain_requires_exact_stop_manager_terminal_and_empty_leaf() { } #[test] -fn metrics_reject_unknown_high_cardinality_or_path_labels() { +fn metrics_reject_high_cardinality_or_path_labels() { assert!(validate_labels(&[ - ("operation".to_owned(), "start".to_owned()), - ("domain".to_owned(), "system".to_owned()), + (MetricLabelKey::Operation, "start".to_owned()), + (MetricLabelKey::Domain, "system".to_owned()), ])); assert!(!validate_labels(&[( - "resource".to_owned(), - "host".to_owned() - )])); - assert!(!validate_labels(&[( - "operation".to_owned(), + MetricLabelKey::Operation, "Process/host".to_owned() )])); assert!(!validate_labels(&[( - "operation".to_owned(), + MetricLabelKey::Operation, "x".repeat(33) )])); } From f7b48c94726e149e9f3dd7656c01d9fa872b83d9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:53:12 -0700 Subject: [PATCH 390/726] d2b-resource-client: drop the unreachable lifetime re-check in CallDriver::new --- packages/d2b-resource-client/src/dispatch.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/d2b-resource-client/src/dispatch.rs b/packages/d2b-resource-client/src/dispatch.rs index fbb21fad6..ab8761c6e 100644 --- a/packages/d2b-resource-client/src/dispatch.rs +++ b/packages/d2b-resource-client/src/dispatch.rs @@ -180,7 +180,6 @@ impl CallDriver { /// does not match the method's profile, /// [`ClientError::IdempotencyRequired`] when the profile demands an /// idempotency key and none was supplied, - /// [`ClientError::InvalidMetadata`] when the lifetime is invalid, and /// [`ClientError::DeadlineExpired`] when the deadline has already /// passed. pub fn new( @@ -196,7 +195,6 @@ impl CallDriver { if profile.requires_idempotency() && !options.metadata.has_idempotency_key() { return Err(ClientError::IdempotencyRequired); } - options.metadata.validate_lifetime()?; let remaining_ms = options .metadata .expires_at_unix_ms() From 09167b5fa6a4598c9c6ba426994131aaf98db269 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:53:35 -0700 Subject: [PATCH 391/726] clipboard: emit structured tracing events from the clipd binary --- Cargo.lock | 1 + .../d2b-provider-clipboard-wayland/Cargo.toml | 1 + .../src/bin/d2b-clipd.rs | 322 +++++++++--------- 3 files changed, 166 insertions(+), 158 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d85ce86e2..a7e02e0df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1133,6 +1133,7 @@ dependencies = [ "sha2", "thiserror 2.0.20", "tracing", + "tracing-subscriber", "wayland-client", "wayland-protocols", "wayland-protocols-misc", diff --git a/packages/d2b-provider-clipboard-wayland/Cargo.toml b/packages/d2b-provider-clipboard-wayland/Cargo.toml index 93c41fb2a..39ec2d8ea 100644 --- a/packages/d2b-provider-clipboard-wayland/Cargo.toml +++ b/packages/d2b-provider-clipboard-wayland/Cargo.toml @@ -30,6 +30,7 @@ nix = { version = "0.29", default-features = false, features = ["fs", "resource" rustix = { workspace = true, features = ["event", "fs", "pipe", "process", "net"] } thiserror = "2" tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } wayland-client = "0.31" wayland-protocols = { version = "0.32", features = ["client", "staging"] } wayland-protocols-misc = { version = "0.3", features = ["client"] } diff --git a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs index 565903b2c..c7b21e79e 100644 --- a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs @@ -112,7 +112,13 @@ struct Args { } fn main() { - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")), + ) + .with_writer(std::io::stderr) + .init(); if let Err(error) = run(std::env::args().skip(1)) { eprintln!("d2b-clipd: {error}"); std::process::exit(2); @@ -199,17 +205,17 @@ fn run(args_iter: impl IntoIterator) -> anyhow::Result<()> { // ── Niri IPC event stream thread ───────────────────────────────────────── if let Some(ref socket) = niri_socket { if let Err(error) = spawn_niri_event_thread(socket.clone(), niri_tx) { - log::error!("d2b-clipd: failed to spawn niri event thread: {error}"); + tracing::error!(error = %error, "d2b-clipd failed to spawn niri event thread"); } } else { - log::warn!("d2b-clipd: NIRI_SOCKET not set; focused-window attribution unavailable"); + tracing::warn!("d2b-clipd NIRI_SOCKET not set; focused-window attribution unavailable"); } - log::info!( - "d2b-clipd: ready (config={}, bridge_root={}, control={})", - args.config.display(), - args.bridge_root.display(), - control_socket.display() + tracing::info!( + config = %args.config.display(), + bridge_root = %args.bridge_root.display(), + control = %control_socket.display(), + "d2b-clipd ready" ); if args.oneshot { @@ -709,7 +715,7 @@ impl EventLoop<'_> { } self.supervisor.reap_terminated(now); if let FallbackTransition::Cleared(r) = self.fallback.on_timeout(now) { - log::debug!("d2b-clipd: paste action state cleared: {r:?}"); + tracing::debug!(?r, "d2b-clipd paste action state cleared"); } self.reap_idle_streams(now); self.accept_diag.flush_suppressed(); @@ -759,9 +765,9 @@ impl EventLoop<'_> { current.entry_id = CURRENT_HOST_ENTRY_ID.to_owned(); self.current_host_entry = Some(current); notify_bridge_selection_refresh(&mut self.bridge_streams); - log::info!( - "d2b-clipd: recorded host selection mimes={}", - entry.data_by_mime.len() + tracing::info!( + mimes = %entry.data_by_mime.len(), + "d2b-clipd recorded host selection" ); } self.history.push(entry); @@ -783,12 +789,12 @@ impl EventLoop<'_> { fn reap_idle_streams(&mut self, now: Instant) { let control_dropped = reap_idle_control_streams(&mut self.control_streams, now); if control_dropped > 0 { - log::debug!("d2b-clipd: reaped {control_dropped} idle control stream(s)"); + tracing::debug!(count = %control_dropped, "d2b-clipd reaped idle control streams"); } let bridge_dropped = reap_idle_bridge_streams(&mut self.bridge_streams, now); if bridge_dropped > 0 { - log::debug!("d2b-clipd: reaped {bridge_dropped} idle bridge stream(s)"); + tracing::debug!(count = %bridge_dropped, "d2b-clipd reaped idle bridge streams"); } } } @@ -846,9 +852,9 @@ impl AcceptDiagnostics { if let Some(count) = self.suppressed.remove(&key) && count > 0 { - log::warn!("d2b-clipd: accept diagnostic suppressed={count} key={key}"); + tracing::warn!(count = %count, key = %key, "d2b-clipd accept diagnostic suppressed"); } - log::warn!("{}", message()); + tracing::warn!("{}", message()); self.last_warn.insert(key, now); } else { *self.suppressed.entry(key).or_insert(0) += 1; @@ -870,7 +876,7 @@ impl AcceptDiagnostics { if let Some(count) = self.suppressed.remove(&key) && count > 0 { - log::warn!("d2b-clipd: accept diagnostic suppressed={count} key={key}"); + tracing::warn!(count = %count, key = %key, "d2b-clipd accept diagnostic suppressed"); } self.last_warn.insert(key, now); } @@ -1626,12 +1632,12 @@ fn parse_bridge_transfer( "bridge transfer fd rejected: {error}" ))); } - log::debug!( - "d2b-clipd: received workload bridge request target={} provider={} source_id:{} mime={}", - bounded_label(&stream.identity.target_label()), - stream.identity.provider_label(), - source_id, - bounded_mime(&mime_type) + tracing::debug!( + target = %bounded_label(&stream.identity.target_label()), + provider = %stream.identity.provider_label(), + source_id = %source_id, + mime = %bounded_mime(&mime_type), + "d2b-clipd received workload bridge request" ); stream.frame_deadline = Instant::now() + STREAM_FRAME_IDLE_TIMEOUT; if copy_selection { @@ -1697,28 +1703,28 @@ fn notify_bridge_stream_selection_refresh(stream: &mut BridgeStream) -> bool { match &result { Ok(n) if *n == bytes.len() => {} Ok(_) => { - log::debug!( - "d2b-clipd: bridge refresh notify partial write for target={}; closing stream", - bounded_label(&stream.identity.target_label()) + tracing::debug!( + target = %bounded_label(&stream.identity.target_label()), + "d2b-clipd bridge refresh notify partial write; closing stream" ); } Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { - log::debug!( - "d2b-clipd: bridge refresh notify backpressured for target={}; closing stream", - bounded_label(&stream.identity.target_label()) + tracing::debug!( + target = %bounded_label(&stream.identity.target_label()), + "d2b-clipd bridge refresh notify backpressured; closing stream" ); } Err(error) if error.kind() == std::io::ErrorKind::Interrupted => { - log::debug!( - "d2b-clipd: bridge refresh notify interrupted for target={}; closing stream", - bounded_label(&stream.identity.target_label()) + tracing::debug!( + target = %bounded_label(&stream.identity.target_label()), + "d2b-clipd bridge refresh notify interrupted; closing stream" ); } Err(error) => { - log::debug!( - "d2b-clipd: bridge refresh notify failed for target={}: {}", - bounded_label(&stream.identity.target_label()), - error + tracing::debug!( + target = %bounded_label(&stream.identity.target_label()), + error = %error, + "d2b-clipd bridge refresh notify failed" ); } } @@ -1767,7 +1773,7 @@ fn handle_bridge_copy_selection( }); }) { - log::error!("d2b-clipd: failed to spawn bridge copy reader: {error}"); + tracing::error!(error = %error, "d2b-clipd failed to spawn bridge copy reader"); } } @@ -1793,12 +1799,12 @@ fn handle_bridge_copy_ready(ready: BridgeCopyReady, context: &mut BridgeCopyRead return; } }; - log::debug!( - "d2b-clipd: bridge copy received target={} provider={} source_id:{} mime={}", - bounded_label(&identity.target_label()), - identity.provider_label(), - source_id, - bounded_mime(&mime_type) + tracing::debug!( + target = %bounded_label(&identity.target_label()), + provider = %identity.provider_label(), + source_id = %source_id, + mime = %bounded_mime(&mime_type), + "d2b-clipd bridge copy received" ); *context.current_host_entry = None; @@ -1868,11 +1874,11 @@ fn handle_bridge_copy_ready(ready: BridgeCopyReady, context: &mut BridgeCopyRead return; } } - log::debug!( - "d2b-clipd: bridge copy discovery source recorded target={} provider={} mimes={}", - bounded_label(&selection.identity.target_label()), - selection.identity.provider_label(), - selection.data_by_mime.len() + tracing::debug!( + target = %bounded_label(&selection.identity.target_label()), + provider = %selection.identity.provider_label(), + mimes = %selection.data_by_mime.len(), + "d2b-clipd bridge copy discovery source recorded" ); } @@ -1972,10 +1978,10 @@ fn handle_bridge_paste_request( && let Some(selection) = context.published_selection.take() && let Some(bytes) = compatible_mime_payload(&selection.data_by_mime, &mime_type) { - log::debug!( - "d2b-clipd: bridge paste served from selected source target={} mime={}", - bounded_label(&identity.target_label()), - bounded_mime(&mime_type) + tracing::debug!( + target = %bounded_label(&identity.target_label()), + mime = %bounded_mime(&mime_type), + "d2b-clipd bridge paste served from selected source" ); spawn_write_bytes_to_fd(fd, mime_type, bytes); return; @@ -1987,15 +1993,15 @@ fn handle_bridge_paste_request( context.history, &mime_type, ); - log::debug!( - "d2b-clipd: bridge paste request target={} provider={} source_id:{} mime={} dest_app={} dest_output={} candidates={} action=open-picker-and-replay", - bounded_label(&identity.target_label()), - identity.provider_label(), - source_id, - bounded_mime(&mime_type), - bounded_label(dest.app_id.as_deref().unwrap_or("unknown")), - bounded_label(dest.output_label.as_deref().unwrap_or("unknown")), - summarize_candidates(&candidates) + tracing::debug!( + target = %bounded_label(&identity.target_label()), + provider = %identity.provider_label(), + source_id = %source_id, + mime = %bounded_mime(&mime_type), + dest_app = %bounded_label(dest.app_id.as_deref().unwrap_or("unknown")), + dest_output = %bounded_label(dest.output_label.as_deref().unwrap_or("unknown")), + candidates = %summarize_candidates(&candidates), + "d2b-clipd bridge paste request" ); let mut picker_context = PickerOpenContext { fallback: &mut *context.fallback, @@ -2031,8 +2037,8 @@ fn notify_bridge_paste_failure( fn flush_audit_events(audit_queue: &mut AuditQueue) { for event in audit_queue.drain_all() { match serde_json::to_string(&event) { - Ok(json) => log::info!("d2b-clipd: audit_event {json}"), - Err(error) => log::warn!("d2b-clipd: audit event encode failed: {error}"), + Ok(json) => tracing::info!(json = %json, "d2b-clipd audit event"), + Err(error) => tracing::warn!(error = %error, "d2b-clipd audit event encode failed"), } } } @@ -2045,14 +2051,14 @@ fn flush_metric_events(metrics_queue: &mut MetricsQueue) { reason: None, }; match serde_json::to_string(&event) { - Ok(json) => log::warn!("d2b-clipd: metric_event {json} dropped_count:{dropped}"), - Err(error) => log::warn!("d2b-clipd: metric event encode failed: {error}"), + Ok(json) => tracing::warn!(json = %json, dropped = %dropped, "d2b-clipd metric event dropped"), + Err(error) => tracing::warn!(error = %error, "d2b-clipd metric event encode failed"), } } for event in metrics_queue.drain_all() { match serde_json::to_string(&event) { - Ok(json) => log::debug!("d2b-clipd: metric_event {json}"), - Err(error) => log::warn!("d2b-clipd: metric event encode failed: {error}"), + Ok(json) => tracing::debug!(json = %json, "d2b-clipd metric event"), + Err(error) => tracing::warn!(error = %error, "d2b-clipd metric event encode failed"), } } } @@ -2084,7 +2090,7 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon let focused_window = context.host_clipboard.refresh_focused_window_snapshot(); if focused_window.is_none() { context.host_clipboard.on_host_selection_cleared(); - log::debug!("d2b-clipd: ignored unattributed host selection"); + tracing::debug!("d2b-clipd ignored unattributed host selection"); return; } if focused_window @@ -2093,7 +2099,7 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon .is_some_and(is_forwarded_vm_app_id) { context.host_clipboard.on_host_selection_cleared(); - log::debug!("d2b-clipd: ignored forwarded VM host-selection echo"); + tracing::debug!("d2b-clipd ignored forwarded VM host-selection echo"); return; } if should_suppress_bridge_selection_echo( @@ -2101,7 +2107,7 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon context.bridge_selection.as_ref(), ) { context.host_clipboard.on_host_selection_cleared(); - log::debug!("d2b-clipd: suppressed source-VM selection echo"); + tracing::debug!("d2b-clipd suppressed source-VM selection echo"); return; } if focused_window_matches_bridge_source( @@ -2109,7 +2115,7 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon context.bridge_selection.as_ref(), ) { context.host_clipboard.on_host_selection_cleared(); - log::debug!("d2b-clipd: ignored source-VM selection echo"); + tracing::debug!("d2b-clipd ignored source-VM selection echo"); return; } if should_suppress_published_selection_echo( @@ -2156,21 +2162,21 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon entry, ); } - log::info!( - "d2b-clipd: host selection changed mimes={} attribution_app={} attribution_output={}", - allowed_mimes.len(), - bounded_label( + tracing::info!( + mimes = %allowed_mimes.len(), + attribution_app = %bounded_label( focused_window .as_ref() .and_then(|window| window.app_id.as_deref()) .unwrap_or("unknown") ), - bounded_label( + attribution_output = %bounded_label( focused_window .as_ref() .and_then(|window| window.output_label.as_deref()) .unwrap_or("unknown") - ) + ), + "d2b-clipd host selection changed" ); // A new native selection supersedes any armed fallback. let _ = context.fallback.on_native_selection_changed(); @@ -2196,9 +2202,9 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon { spawn_write_bytes_to_fd(fd, mime_type, bytes); } else { - log::info!( - "d2b-clipd: published selection missing requested mime={}", - bounded_mime(&mime_type) + tracing::info!( + mime = %bounded_mime(&mime_type), + "d2b-clipd published selection missing requested mime" ); drop(fd); } @@ -2213,9 +2219,9 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon Some(&dest), context.bridge_selection.as_ref(), ) { - log::debug!( - "d2b-clipd: ignored discovery source probe mime={}", - bounded_mime(&mime_type) + tracing::debug!( + mime = %bounded_mime(&mime_type), + "d2b-clipd ignored discovery source probe" ); return; } @@ -2284,12 +2290,12 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon }, ); } - log::info!( - "d2b-clipd: discovery source paste request mime={} dest_app={} dest_output={} candidates={} action=open-picker-and-replay", - bounded_mime(&mime_type), - bounded_label(dest.app_id.as_deref().unwrap_or("unknown")), - bounded_label(dest.output_label.as_deref().unwrap_or("unknown")), - summarize_candidates(&candidates) + tracing::info!( + mime = %bounded_mime(&mime_type), + dest_app = %bounded_label(dest.app_id.as_deref().unwrap_or("unknown")), + dest_output = %bounded_label(dest.output_label.as_deref().unwrap_or("unknown")), + candidates = %summarize_candidates(&candidates), + "d2b-clipd discovery source paste request" ); let mut picker_context = PickerOpenContext { fallback: &mut *context.fallback, @@ -2331,10 +2337,10 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon .unwrap_or_default(); drop(fd); if focused_app_matches_endpoint(dest.app_id.as_deref(), &selection.identity) { - log::debug!( - "d2b-clipd: ignored bridge source probe from source target={} mime={}", - bounded_label(&selection.identity.target_label()), - bounded_mime(&mime_type) + tracing::debug!( + target = %bounded_label(&selection.identity.target_label()), + mime = %bounded_mime(&mime_type), + "d2b-clipd ignored bridge source probe" ); return; } @@ -2349,15 +2355,15 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon != Some(selection.identity.target_label().as_str()) }), ); - log::debug!( - "d2b-clipd: bridge selection paste request target={} provider={} source_id:{} mime={} dest_app={} dest_output={} candidates={}", - bounded_label(&selection.identity.target_label()), - selection.identity.provider_label(), - selection.source_id, - bounded_mime(&mime_type), - bounded_label(dest.app_id.as_deref().unwrap_or("unknown")), - bounded_label(dest.output_label.as_deref().unwrap_or("unknown")), - summarize_candidates(&candidates) + tracing::debug!( + target = %bounded_label(&selection.identity.target_label()), + provider = %selection.identity.provider_label(), + source_id = %selection.source_id, + mime = %bounded_mime(&mime_type), + dest_app = %bounded_label(dest.app_id.as_deref().unwrap_or("unknown")), + dest_output = %bounded_label(dest.output_label.as_deref().unwrap_or("unknown")), + candidates = %summarize_candidates(&candidates), + "d2b-clipd bridge selection paste request" ); let mut picker_context = PickerOpenContext { fallback: &mut *context.fallback, @@ -2376,28 +2382,28 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon .refresh_focused_window_snapshot() .unwrap_or_default(); if dest.app_id.as_deref().is_some_and(is_forwarded_vm_app_id) { - log::debug!( - "d2b-clipd: ignored unknown d2b source probe from forwarded VM app mime={}", - bounded_mime(&mime_type) + tracing::debug!( + mime = %bounded_mime(&mime_type), + "d2b-clipd ignored unknown d2b source probe from forwarded VM app" ); return; } if focused_window_matches_bridge_source(Some(&dest), context.bridge_selection.as_ref()) { - log::debug!( - "d2b-clipd: ignored unknown d2b source probe from source VM mime={}", - bounded_mime(&mime_type) + tracing::debug!( + mime = %bounded_mime(&mime_type), + "d2b-clipd ignored unknown d2b source probe from source VM" ); return; } - log::debug!( - "d2b-clipd: ignored unknown d2b source_id:{} mime={}", - source_id, - bounded_mime(&mime_type) + tracing::debug!( + source_id = %source_id, + mime = %bounded_mime(&mime_type), + "d2b-clipd ignored unknown d2b source" ); } HostClipboardEvent::SourceCancelled { source_id } => { - log::debug!("d2b-clipd: source {source_id} cancelled"); + tracing::debug!(source_id = %source_id, "d2b-clipd source cancelled"); if context .published_selection .as_ref() @@ -2416,7 +2422,7 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon } } HostClipboardEvent::DeviceFinished => { - log::warn!("d2b-clipd: data-control device finished (compositor seat removed)"); + tracing::warn!("d2b-clipd data-control device finished (compositor seat removed)"); } } } @@ -2466,7 +2472,7 @@ fn handle_control_stream( if let Err(error) = write_all_nonblocking_stream(&control.stream, body.as_bytes(), BOUNDED_READ_TIMEOUT) { - log::warn!("d2b-clipd: write control response failed: {error}"); + tracing::warn!(error = %error, "d2b-clipd write control response failed"); } ControlStreamStatus::Done } @@ -2477,7 +2483,7 @@ fn handle_control_stream( if let Err(error) = write_all_nonblocking_stream(&control.stream, body.as_bytes(), BOUNDED_READ_TIMEOUT) { - log::warn!("d2b-clipd: write control error response failed: {error}"); + tracing::warn!(error = %error, "d2b-clipd write control error response failed"); } ControlStreamStatus::Done } @@ -2607,10 +2613,10 @@ struct PickerMessageContext<'a> { fn handle_picker_message(message: PickerToDaemonMessage, context: &mut PickerMessageContext<'_>) { match message { PickerToDaemonMessage::Select(select) => { - log::info!( - "d2b-clipd: picker selected entry for request {} entry={}", - select.request_id, - bounded_label(&select.entry_id) + tracing::info!( + request_id = %select.request_id, + entry = %bounded_label(&select.entry_id), + "d2b-clipd picker selected entry" ); match publish_selected_entry_to_host( context.data_control, @@ -2637,7 +2643,7 @@ fn handle_picker_message(message: PickerToDaemonMessage, context: &mut PickerMes niri_socket.as_deref(), replay_target.as_ref(), ) { - log::warn!("d2b-clipd: host instant paste failed: {error}"); + tracing::warn!(error = %error, "d2b-clipd host instant paste failed"); let mut notifier = DesktopNotifier; crate::clipd_host::notifications::emit_user_visible_failure( &mut notifier, @@ -2648,7 +2654,7 @@ fn handle_picker_message(message: PickerToDaemonMessage, context: &mut PickerMes } }) { - log::error!("d2b-clipd: failed to spawn paste replay worker: {error}"); + tracing::error!(error = %error, "d2b-clipd failed to spawn paste replay worker"); } } Err(reason) => { @@ -2664,12 +2670,12 @@ fn handle_picker_message(message: PickerToDaemonMessage, context: &mut PickerMes } } PickerToDaemonMessage::Cancel(cancel) => { - log::debug!("d2b-clipd: picker cancelled request {}", cancel.request_id); + tracing::debug!(request_id = %cancel.request_id, "d2b-clipd picker cancelled request"); let _ = context.fallback.cancel_picker(); let _ = context.supervisor.cancel_active(ReasonCode::PickerTimeout); } PickerToDaemonMessage::ClientHello(_) => { - log::debug!("d2b-clipd: ignored duplicate picker client_hello"); + tracing::debug!("d2b-clipd ignored duplicate picker client_hello"); } } } @@ -2756,10 +2762,10 @@ fn publish_selected_entry_to_host( *published_selection = None; return Err(ReasonCode::BridgeUnavailable); } - log::info!( - "d2b-clipd: published selected entry id={} mimes={} for instant paste", - bounded_label(entry_id), - mimes_len + tracing::info!( + id = %bounded_label(entry_id), + mimes = %mimes_len, + "d2b-clipd published selected entry for instant paste" ); Ok(()) } @@ -2853,7 +2859,7 @@ fn materialize_offer_mimes_async( let permit = match try_acquire_helper_thread() { Ok(permit) => permit, Err(reason) => { - log::warn!("d2b-clipd: host copy reader denied: {}", reason.as_str()); + tracing::warn!(reason = %reason.as_str(), "d2b-clipd host copy reader denied"); return; } }; @@ -2873,7 +2879,7 @@ fn materialize_offer_mimes_async( } }) { - log::error!("d2b-clipd: failed to spawn host copy reader: {error}"); + tracing::error!(error = %error, "d2b-clipd failed to spawn host copy reader"); } } @@ -2881,10 +2887,10 @@ fn spawn_write_bytes_to_fd(fd: std::os::fd::OwnedFd, mime: String, bytes: Vec permit, Err(reason) => { - log::info!( - "d2b-clipd: published paste write denied mime={}: {}", - bounded_mime(&mime), - reason.as_str() + tracing::info!( + mime = %bounded_mime(&mime), + reason = %reason.as_str(), + "d2b-clipd published paste write denied" ); drop(fd); return; @@ -2895,20 +2901,20 @@ fn spawn_write_bytes_to_fd(fd: std::os::fd::OwnedFd, mime: String, bytes: Vec log::debug!( - "d2b-clipd: published paste write complete mime={}", - bounded_mime(&mime) + Ok(()) => tracing::debug!( + mime = %bounded_mime(&mime), + "d2b-clipd published paste write complete" ), - Err(reason) => log::info!( - "d2b-clipd: published paste write failed mime={}: {}", - bounded_mime(&mime), - reason.as_str() + Err(reason) => tracing::info!( + mime = %bounded_mime(&mime), + reason = %reason.as_str(), + "d2b-clipd published paste write failed" ), } drop(fd); }) { - log::error!("d2b-clipd: failed to spawn published paste writer: {error}"); + tracing::error!(error = %error, "d2b-clipd failed to spawn published paste writer"); } } @@ -3031,7 +3037,7 @@ fn handle_arm( candidates, ) { Ok(picker_version) => { - log::debug!("d2b-clipd: picker opened (version={picker_version})"); + tracing::debug!(version = %picker_version, "d2b-clipd picker opened"); Ok("picker opened".to_owned()) } Err(error) => { @@ -3143,19 +3149,19 @@ fn picker_handshake( candidates, })); if let DaemonToPickerMessage::OpenRequest(request) = &request { - log::info!( - "d2b-clipd: picker open request id={} requested_mime={} dest_app={} dest_output={} candidates={}", - bounded_label(&request.request_id), - bounded_mime(&request.requested_mime_type), - bounded_label(request.destination.app_id.as_deref().unwrap_or("unknown")), - bounded_label( + tracing::info!( + request_id = %bounded_label(&request.request_id), + requested_mime = %bounded_mime(&request.requested_mime_type), + dest_app = %bounded_label(request.destination.app_id.as_deref().unwrap_or("unknown")), + dest_output = %bounded_label( request .placement_hints .as_ref() .and_then(|hints| hints.output.as_deref()) .unwrap_or("unknown") ), - summarize_candidates(&request.candidates) + candidates = %summarize_candidates(&request.candidates), + "d2b-clipd picker open request" ); } let frame = encode_frame(&request, OpenRequestFrameCaps::default().max_frame_bytes()) @@ -3442,9 +3448,9 @@ fn open_picker_for_candidates( context.notifier, ); } else { - log::debug!( - "d2b-clipd: picker opened for paste to {}", - bounded_label(dest.app_id.as_deref().unwrap_or("unknown")) + tracing::debug!( + dest_app = %bounded_label(dest.app_id.as_deref().unwrap_or("unknown")), + "d2b-clipd picker opened for paste" ); } } @@ -3488,7 +3494,7 @@ fn arm_native_fallback( if matches!(transition, FallbackTransition::Armed) { let label = dest.app_id.as_deref().unwrap_or("host application"); emit_fallback_ready(notifier, label); - log::debug!("d2b-clipd: paste action armed for {}", bounded_label(label)); + tracing::debug!(label = %bounded_label(label), "d2b-clipd paste action armed"); } } @@ -3512,7 +3518,7 @@ fn spawn_niri_event_thread(socket: PathBuf, tx: mpsc::Sender) -> Re ) { Ok(c) => c, Err(e) => { - log::warn!("d2b-clipd: niri connect: {e}"); + tracing::warn!(error = %e, "d2b-clipd niri connect"); let _ = tx.send(NiriMessage::Disconnected); return; } @@ -3522,7 +3528,7 @@ fn spawn_niri_event_thread(socket: PathBuf, tx: mpsc::Sender) -> Re let _: serde_json::Value = match client.request(&NiriRequest::EventStream) { Ok(v) => v, Err(e) => { - log::warn!("d2b-clipd: niri EventStream: {e}"); + tracing::warn!(error = %e, "d2b-clipd niri EventStream"); let _ = tx.send(NiriMessage::Disconnected); return; } @@ -3537,7 +3543,7 @@ fn spawn_niri_event_thread(socket: PathBuf, tx: mpsc::Sender) -> Re } } Err(e) => { - log::warn!("d2b-clipd: niri event: {e}"); + tracing::warn!(error = %e, "d2b-clipd niri event"); let _ = tx.send(NiriMessage::Disconnected); break; } @@ -3561,7 +3567,7 @@ fn drain_niri_channel( } } Ok(NiriMessage::Disconnected) => { - log::warn!("d2b-clipd: niri stream disconnected"); + tracing::warn!("d2b-clipd niri stream disconnected"); break; } Err(mpsc::TryRecvError::Empty) | Err(mpsc::TryRecvError::Disconnected) => break, From 97ca730c85c087aa4f2afa76dddb3d8961ae14d8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:53:56 -0700 Subject: [PATCH 392/726] d2b-provider-host: type the host observation seam and narrow the driver surface --- packages/d2b-provider-host/src/driver.rs | 54 +++++++++++++------ .../d2b-provider-host/src/effects_service.rs | 6 +-- .../d2b-provider-host/src/test_support.rs | 6 +-- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/packages/d2b-provider-host/src/driver.rs b/packages/d2b-provider-host/src/driver.rs index 0a185f16c..a2f1929d1 100644 --- a/packages/d2b-provider-host/src/driver.rs +++ b/packages/d2b-provider-host/src/driver.rs @@ -56,7 +56,7 @@ use d2b_contracts_resource::v3::{ ResourcePhase, ResourceRef, ResourceSpec, host::{HOST_PROVIDER_REF, HOST_RESOURCE_TYPE, HostSpec}, }; -use d2b_provider_system_core::HostObservationReport; +use d2b_provider_system_core::{HostObservationReport, SystemCoreError}; use d2b_resource_runtime::context::{ResourceContext, SpecDecoder, typed_spec_decoder}; use d2b_resource_types::{AllowedSources, CONVERTED_TYPE_VERBS, DriverDescriptor, WellKnownType}; @@ -81,7 +81,7 @@ use d2b_resource_runtime::identity::{ResourceKey, ResourceTypeName}; /// recover: an observation is a local probe, and the states it reports as not /// ready resolve on their own. The re-probe is one probe per interval, not a /// poll on the ready path, which the generation short-circuit still pins. -pub const HOST_REOBSERVE: Duration = Duration::from_secs(5); +pub(crate) const HOST_REOBSERVE: Duration = Duration::from_secs(5); #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum HostDriverErrorKind { @@ -108,7 +108,7 @@ impl HostDriverErrorKind { /// Typed driver failure; mapped onto the structured failure surface at the /// erased boundary through [`ResourceDriver::classify_error`]. #[derive(Debug, Clone)] -pub struct HostDriverError { +pub(crate) struct HostDriverError { kind: HostDriverErrorKind, op: DriverOp, detail: FailureDetail, @@ -128,11 +128,7 @@ impl HostDriverError { impl core::fmt::Display for HostDriverError { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter.write_str(match self.kind { - HostDriverErrorKind::SpecInvalid => "system-core-spec-invalid", - HostDriverErrorKind::HostObservation => "system-core-host-observation-failed", - HostDriverErrorKind::DrainPending => "system-core-drain-pending", - }) + formatter.write_str(self.kind.failure_kind().code()) } } @@ -144,7 +140,7 @@ impl std::error::Error for HostDriverError {} /// runtime-only successor of the old durable `status.observedGeneration` /// plan short-circuit. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct HostDriverStatus { +pub(crate) struct HostDriverStatus { observed_generation: u64, report: HostObservationReport, } @@ -171,7 +167,7 @@ impl HostDriverStatus { /// keeps exactly the typed Host contract fields, so the decoder hands the /// driver the complete desired state (`ResourceSpec::base()` is what the old /// handler decoded into `HostSpec`). -pub fn host_spec_decoder() -> Arc { +pub(crate) fn host_spec_decoder() -> Arc { typed_spec_decoder(|bytes| serde_json::from_slice::(bytes)) } @@ -179,6 +175,34 @@ pub fn host_spec_decoder() -> Arc { // Provider effect port // --------------------------------------------------------------------------- +/// The host-observation seam's failure, carrying the underlying error in +/// the chain instead of a flattened message. +#[derive(Debug)] +pub(crate) struct ObserveError { + /// The live host probe's failure. + pub(crate) probe: SystemCoreError, + /// The spec-decision fallback's failure, when the fallback also failed. + pub(crate) fallback: Option, +} + +impl core::fmt::Display for ObserveError { + fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match &self.fallback { + Some(fallback) => write!(formatter, "{}; {fallback}", self.probe), + None => write!(formatter, "{}", self.probe), + } + } +} + +impl std::error::Error for ObserveError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.fallback + .as_ref() + .map(|error| error as &(dyn std::error::Error + 'static)) + .or_else(|| Some(&self.probe as &(dyn std::error::Error + 'static))) + } +} + /// The host-observation surface the Host driver needs: the preserved /// `system-core` Provider behavior (bounded capability/platform/metadata /// probe with its degraded fallback), behind the erased seam the driver @@ -186,7 +210,7 @@ pub fn host_spec_decoder() -> Arc { /// [`crate::effects_service::HostEffectsService`] (U5), built from the /// daemon-supplied facet set. #[async_trait] -pub trait HostDriverEffects: Send + Sync + 'static { +pub(crate) trait HostDriverEffects: Send + Sync + 'static { /// Observe one Host and compute its public status, or report why the /// observation could not be taken. async fn observe_host( @@ -194,7 +218,7 @@ pub trait HostDriverEffects: Send + Sync + 'static { host_ref: &ResourceRef, provider_ref: &ResourceRef, spec: &HostSpec, - ) -> Result; + ) -> Result; } // --------------------------------------------------------------------------- @@ -203,7 +227,7 @@ pub trait HostDriverEffects: Send + Sync + 'static { /// [`ResourceDriverFactory`] for the `Host` resource type. Construction is /// infallible by contract: the effects carry no fallible setup. -pub struct HostDriverFactory { +pub(crate) struct HostDriverFactory { types: [ResourceTypeName; 1], effects: Arc, } @@ -236,7 +260,7 @@ impl ResourceDriverFactory for HostDriverFactory { // --------------------------------------------------------------------------- /// One Host resource's driver. -pub struct HostDriver { +pub(crate) struct HostDriver { effects: Arc, } @@ -381,7 +405,7 @@ impl ResourceDriver for HostDriver { "completed", "failed", )) - .with_note(error), + .with_note(error.to_string()), ) })?; let ready = report.status.phase == ResourcePhase::Ready; diff --git a/packages/d2b-provider-host/src/effects_service.rs b/packages/d2b-provider-host/src/effects_service.rs index 4236c649e..ad986c5af 100644 --- a/packages/d2b-provider-host/src/effects_service.rs +++ b/packages/d2b-provider-host/src/effects_service.rs @@ -37,7 +37,7 @@ use d2b_provider_toolkit::{ }; use d2b_resource_types::{ServiceDecl, ServiceMethod}; -use crate::driver::HostDriverEffects; +use crate::driver::{HostDriverEffects, ObserveError}; use crate::facets::HostEffectFacets; /// The Host family's declared effects service. @@ -158,7 +158,7 @@ impl HostDriverEffects for HostEffectsService { host_ref: &ResourceRef, provider_ref: &ResourceRef, spec: &HostSpec, - ) -> Result { + ) -> Result { match HostReconciler::new() .reconcile_with_probe( host_ref, @@ -177,7 +177,7 @@ impl HostDriverEffects for HostEffectsService { // rather than failing the resource. let mut status = HostReconciler::new() .reconcile(host_ref, provider_ref, spec) - .map_err(|error| format!("{probe_error}; {error}"))?; + .map_err(|error| ObserveError { probe: probe_error, fallback: Some(error) })?; status.phase = ResourcePhase::Degraded; Ok(HostObservationReport { status, diff --git a/packages/d2b-provider-host/src/test_support.rs b/packages/d2b-provider-host/src/test_support.rs index a5a9eae9f..d23ab8505 100644 --- a/packages/d2b-provider-host/src/test_support.rs +++ b/packages/d2b-provider-host/src/test_support.rs @@ -28,7 +28,7 @@ use d2b_provider_system_core::{ HostReconciler, MinijailPlatformGate, SystemCoreError, }; -use crate::driver::HostDriverEffects; +use crate::driver::{HostDriverEffects, ObserveError}; use crate::facets::{HostEffectFacets, MinijailPlatformGateSource}; /// Scripted observation port: records every call order-preservingly and @@ -69,10 +69,10 @@ impl HostDriverEffects for RecordingEffects { host_ref: &ResourceRef, provider_ref: &ResourceRef, spec: &HostSpec, - ) -> Result { + ) -> Result { self.calls.lock().await.push("observe-host".to_owned()); if self.fail.load(Ordering::SeqCst) { - return Err("the scripted probe refused".to_owned()); + return Err(ObserveError { probe: SystemCoreError::HostProbeFailed, fallback: None }); } let mut status = HostReconciler::new() .reconcile(host_ref, provider_ref, spec) From bf359ca79d6d636b66764134843281712b7d678e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:54:26 -0700 Subject: [PATCH 393/726] d2b-audit: narrow the root re-export surface to the consumed items --- packages/d2b-audit/src/export.rs | 2 +- packages/d2b-audit/src/lib.rs | 17 +---------------- packages/d2b-audit/src/record_types.rs | 3 ++- packages/d2b-audit/src/segment.rs | 2 +- packages/d2b-audit/src/sink.rs | 2 +- 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/packages/d2b-audit/src/export.rs b/packages/d2b-audit/src/export.rs index 12f845eaf..60f346f17 100644 --- a/packages/d2b-audit/src/export.rs +++ b/packages/d2b-audit/src/export.rs @@ -67,7 +67,7 @@ pub fn export_segments(directory: impl AsRef) -> io::Result, before: Option<&str>, - ) -> Result, AuditSinkError> { + ) -> Result, AuditSinkError> { let state = self .state .lock() From 12a082df8d5f582b1ef3ed3d6e09afda052f1b9a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:54:29 -0700 Subject: [PATCH 394/726] audit: fold the broker classifications and the clipboard slice --- .../2026-09-24-rust-skills-audit/ledger.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 83bc93969..7d88cd5af 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -287,7 +287,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0263` | `type` | `d2b` | low | actionable | leaf | | | | `context.rs:713, context.rs:2751, context.rs:801` | | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | | `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | | | | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | | | -| `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/media.rs:889-892` | | | +| `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | already-fixed | U3 | | `packages/d2b-broker/src/ops/media.rs:889-892` | Re-verified at HEAD: QmpAttachCleanup already models its four-step rollback as an ordered typed step list (steps: Vec with QmpAttachStep enum, media.rs:889-892), not four bools. Already | | | `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_co` | | | | `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362` | | | | `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 7a5a7f957,4e20f7674 | packages/d2b-bus/src/session/zone_link.rs | folded admission+liveness into private EstablishedLane; test lane keeps None; all three gate sites migrated; follow-up commit reattaches the doc to ZoneLinkSession | | @@ -313,7 +313,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 81d0ff057 | packages/d2b-process-conformance/src/ticket.rs | Bundled zone_uid+runtime_scope into one private Option pairing; const-compatible match accessors keep the public API byte-identical. | | | `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, sr` | | | | `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199` | | | -| `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:140, src/bin/d2b-clipd.rs:142` | | | +| `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 4404afb72 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Merged picker (args.picker.or(config)) validated once after merge; relative paths rejected from either source. | | | `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider` | | | | `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipb` | | | | `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard` | | | @@ -372,7 +372,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0320` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | bc367bab9 | packages/d2b-broker/src/ops/route.rs | RouteConflictKey made private (plain struct) and its six pub fields dropped to private; all users are in-file (route_conflicts, route_matches_record, requested_route_conflict_key, tests at 863). Censu | | | `RS-0318` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | ee8678e46 | packages/d2b-broker/src/ops/gpu.rs | Item-level pub -> pub(crate) for all 19 gpu.rs items and 7 modprobe.rs items (types, impl methods, free fns, trait). Chose item-level over module-decl narrowing so d2b-core bundle_resolver.rs:4300 and | | | `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | | | | `src/lib.rs:45, src/ops/mod.rs:20-94` | | | -| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | | | +| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | Re-verified claim at HEAD: `pub fn acquire_lock` (ops/usbip_lock.rs:101-106) takes `_daemon_uid: u32` (underscore-prefixed) the body never uses. BUT the parameter is a parameter of a `pub fn` on the ` | | | `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | 068ddcfc4 | packages/d2b-broker/src/ops/cgroup.rs | CgroupBundleContext::slice_path() now returns &Path (borrows parent_slice, no clone). Call sites: vm_interior_path join works on &Path; AuditFields slice_path and the D2bSlice tuple site keep one to_p | | | `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | | `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | applied-variant | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | Census re-run:= with_observer/with_observer_and_metrics/with_clock_and_observer have zero ZoneBus callers, deleted; with_clock -> pub(crate) because production new() delegates to it; with_clock_observ | | @@ -427,9 +427,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | | `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `lib.rs:24, lib.rs:61-65` | | | | `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `broker.rs:131-133` | | | -| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20` | | | -| `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/lib.rs:14` | | | -| `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/controller.rs:580` | | | +| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | declined | U3 | | `src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20` | pub(crate) narrowing trips the repo dead_code deny (no internal users, no lint allows permitted by wave rules); wiring the daemon cleanup path needs spec/session-key plumbing across runtime+daemon bey | | +| `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | c5d8e0cf5 | packages/d2b-provider-display-wayland/src/lib.rs | Module moved into the binary target via #[path]; all crate::wayland_proxy paths rewritten; census of d2b_provider_display_wayland::wayland_proxy over packages/nixos-modules/tests/docs/reference = 0. | | +| `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 15d510a76 | packages/d2b-provider-display-wayland/src/controller.rs | WaylandPolicySnapshot::from_authenticated_session deleted (no callers; census over packages/nixos-modules/tests/labs/docs/reference = 0 in the display crate). | | | `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12` | | | | `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | | `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | | | | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | | | @@ -505,11 +505,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:230` | | | | `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b` | | | | `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | -| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | | | +| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source | | | `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | -| `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360` | | | +| `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | not-started | U3 | | `packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360` | Claim re-verified at HEAD: `CellStore::with_retention` (state_cells.rs:360) `.expect()`s on spawn_owner failure while `open()` (353) propagates CellStoreError::Io; in_memory keeps infallible. Fix (mak | | | `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | -| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | | | +| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | Claim re-verified at HEAD: `guest_socket_directory` (ops/device_worker.rs:262-284) returns `Result<&'static str, &'static str>`-style plain-static-code refusals, consumed at live_handlers.rs:2428 by s | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/depen` | | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:2` | | | @@ -532,17 +532,17 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | applied | U3 | 69153d93f | packages/d2b-provider-activation-nixos/src/controller.rs | terminal now takes ResourceName (63-byte lowercase label, no slash); new parses via ResourceName::parse and returns Result<_, IdentityError>; two driver call sites map parse failure to driver Policy e | | | `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/authority.rs:53-54, src/authority.rs:144-145` | | | | `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/state.rs:114-123, src/controller.rs:155-160` | | | -| `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:3550, src/bin/d2b-clipd.rs:1754, src/bin/d2b-clipd.rs:2863` | | | -| `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:127, src/bin/d2b-clipd.rs:411, src/bin/d2b-clipd.rs:247` | | | +| `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | 1b70ff14a | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | spawn_niri_event_thread returns Result<(), io::Error>; call site logs instead of panicking. | | +| `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | da5acd332 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Binary Result<_, String> signatures and format!-built errors migrated to anyhow; typed BridgeReadError/ControlReadError/ReasonCode untouched; control-socket JSON bodies byte-identical. | | | `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clip` | | | | `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provide` | | | | `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixo` | | | | `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:1261-1262` | | | | `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | | `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `state_machine.rs:378-386` | | | -| `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/controller.rs:740, src/controller.rs:741` | | | +| `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | 263eea211 | packages/d2b-provider-display-wayland/src/controller.rs | DisplayController::new returns Result with # Errors doc; 2 daemon sites use expect/unwrap; all call sites updated. | | | `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886` | | | -| `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:30, src/spec.rs:43` | | | +| `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 64c41ddb5 | packages/d2b-provider-display-wayland/src/spec.rs | WaylandSpecError::NoPrincipalAvailable variant + Display arm deleted; no error-codes.md hit; no other constructors (controller uses PrincipalPoolError/SessionCondition). | | | `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:197, packages/d2b-provider-host/src/effects_servi` | | | | `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:129, packages/d2b-provider-host/src/driver.rs:99` | | | | `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/nftables.rs:588` | | | @@ -594,7 +594,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | a09140432 | packages/d2bd-runtime/src/daemon_version.rs | version-file read failures typed (VersionFileReadError); check + tests green | | | `RS-0543` | `err` | `xtask` | medium | actionable | leaf | applied | U3 | 7194d24e9 | packages/xtask/src/delivery/recovery.rs | RecoveryError::Read added for fs open/read failures; Json(String) now carries the bounded serde detail (field names/positions only via error.to_string(), never payload values, keeping the redaction co | | | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | -| `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | | | +| `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composi` | | | | `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | | | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | | | | `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | | | @@ -614,7 +614,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | | | | `packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/comm` | | | | `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | d58f183d5 | packages/d2b-provider-device-gpu/src/gpu_argv.rs | deny_unknown_fields added to GpuArgvInput/GpuParams/GpuDisplayConfig (mirroring VideoArgvInput); new rejects_unknown_fields test pins top-level, params-nested, and display-nested rejection. Mutation c | | | `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | | | -| `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/spec.rs:230, src/spec.rs:233, src/spec.rs:263` | | | +| `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 84b343101 | packages/d2b-provider-display-wayland/src/spec.rs | Inert serde try_from attribute removed; rename_all/deny_unknown_fields and the manual Deserialize + TryFrom kept. | | | `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | | `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/driver.rs:282-289, src/driver.rs:190` | | | | `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429` | | | @@ -633,10 +633,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0580` | `serde` | `xtask` | medium | actionable | leaf | applied | U3 | 9ccb9c694 | packages/xtask/src/service_catalog.rs | deny_unknown_fields added to DeclarationFile; all six committed service-catalog.json files verified to carry only the declared keys (provider/providerRef/providerUid/services); new test an_unknown_dec | | | `RS-0582` | `serde` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111` | | | | `RS-0581` | `serde` | `xtask` | low | actionable | leaf | applied-variant | U3 | 341c4fb5e | packages/xtask/src/resource_type_authority.rs | rename_all = camelCase added to DeclarationFile and TypeDeclaration; per-field resourceType rename deleted;the crate per-field rename must stay because the wire key 'crate' is a Rust keyword that rena | | -| `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:25` | | | +| `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | not-started | U3 | | `packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:25` | Claim re-verified verbatim at HEAD (live_handlers.rs:2532 `error = %err, \'{label} ACL refresh not ready yet\',` and :2539 `tracing::warn!(\'{label} ACL refresh timed out\');`, with `label: &'static s | | | `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | | `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | a94ef37d6 | packages/d2b-provider-activation-nixos/src/controller.rs | all 9 warn! refusal events in ActivationTrust::verify now carry a named refusal field with the exact ActivationVerificationError variant; no correlation identifiers added (ADR 0010/0028 safe). | | -| `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100` | | | +| `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 09167b5fa | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | All 62 log:: sites in d2b-clipd.rs converted to tracing:: with named fields; env_logger init replaced by tracing_subscriber::fmt().with_env_filter(...).with_writer(stderr).init() mirroring d2bd; log/e | | | `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provide` | | | | `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | | `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:346, src/controller/mod.rs:425` | | | From 24cca337b61af079be097d25be2db4267a689831 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:54:30 -0700 Subject: [PATCH 395/726] d2b-provider-telemetry-service: type the status projection, carry the store source, and refuse unparseable ingest refs --- Cargo.lock | 1 + .../d2b-provider-telemetry-service/Cargo.toml | 1 + .../src/driver.rs | 162 ++++++++++++++---- .../d2b-provider-telemetry-service/src/lib.rs | 3 +- 4 files changed, 131 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f023ce55f..4f5dfe909 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1772,6 +1772,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-resource-runtime", "d2b-resource-types", + "serde", "serde_json", "tokio", ] diff --git a/packages/d2b-provider-telemetry-service/Cargo.toml b/packages/d2b-provider-telemetry-service/Cargo.toml index e2feaa73a..98616e868 100644 --- a/packages/d2b-provider-telemetry-service/Cargo.toml +++ b/packages/d2b-provider-telemetry-service/Cargo.toml @@ -22,6 +22,7 @@ d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0- d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-bootstrap" } d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } +serde.workspace = true serde_json.workspace = true [dev-dependencies] diff --git a/packages/d2b-provider-telemetry-service/src/driver.rs b/packages/d2b-provider-telemetry-service/src/driver.rs index 1f0476794..ed8f4c345 100644 --- a/packages/d2b-provider-telemetry-service/src/driver.rs +++ b/packages/d2b-provider-telemetry-service/src/driver.rs @@ -34,7 +34,9 @@ use d2b_resource_runtime::context::{ use d2b_resource_runtime::driver::{ DynResourceDriver, RecoveryOutcome, ReconcileOutcome, ResourceDriver, ResourceDriverFactory, }; -use d2b_resource_runtime::error::{DriverFailure, DriverOp}; +use std::error::Error; + +use d2b_resource_runtime::error::{DriverFailure, DriverOp, FailureDetail, ResourceError}; use d2b_resource_runtime::identity::{ResourceKey, ResourceTypeName}; use d2b_resource_types::{AllowedSources, CONVERTED_TYPE_VERBS, DriverDescriptor, WellKnownType}; @@ -89,15 +91,22 @@ impl TelemetryServiceDriverErrorKind { /// Typed driver failure; redacted at the erased boundary through /// [`ResourceDriver::classify_error`] (R13). -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug)] pub struct TelemetryServiceDriverError { kind: TelemetryServiceDriverErrorKind, op: DriverOp, + source: Option, } impl TelemetryServiceDriverError { const fn new(kind: TelemetryServiceDriverErrorKind, op: DriverOp) -> Self { - Self { kind, op } + Self { kind, op, source: None } + } + + /// Retain the underlying store failure as the chain's source (R13). + fn with_source(mut self, source: ResourceError) -> Self { + self.source = Some(source); + self } } @@ -107,20 +116,58 @@ impl core::fmt::Display for TelemetryServiceDriverError { } } -impl std::error::Error for TelemetryServiceDriverError {} +impl std::error::Error for TelemetryServiceDriverError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.source.as_ref().map(|source| source as &(dyn std::error::Error + 'static)) + } +} // --------------------------------------------------------------------------- // In-memory status (R11) // --------------------------------------------------------------------------- +/// The projected provider phase, spelled as the telemetry contract's +/// status terms.. +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)] +pub enum TelemetryServicePhase { + /// A usable ingest route is materialized. + Ready, + /// A declared ingest route is not materialized yet. + Pending, + /// The role is absent or unadmitted, or the route is unavailable. + Degraded, +} + +impl TelemetryServicePhase { + /// The contract spelling of this phase. + pub const fn as_str(self) -> &'static str { + match self { + Self::Ready => PHASE_READY, + Self::Pending => PHASE_PENDING, + Self::Degraded => PHASE_DEGRADED, + } + } +} + +/// The `{serviceRole, serviceReadiness}` status projection, serialized to +/// the contract-pinned telemetry status shape. +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TelemetryServiceProjection { + /// The projected service role. + pub service_role: &'static str, + /// The projected service readiness spelling. + pub service_readiness: TelemetryServicePhase, +} + /// The provider projection the old reconciler persisted through the Resource /// API, now in-memory only (R11: runtime status is never persisted). #[derive(Debug, Clone, PartialEq, Eq)] pub struct TelemetryServiceStatus { - /// The projected provider phase spelling. - pub phase: &'static str, - /// `{serviceRole, serviceReadiness}`; empty when the spec is degraded. - pub projection: serde_json::Value, + /// The projected provider phase. + pub phase: TelemetryServicePhase, + /// `{serviceRole, serviceReadiness}`; absent when the spec is degraded. + pub projection: Option, /// Declared ingest endpoint refs whose rows exist and are not deleting. pub present_endpoints: Vec, } @@ -272,8 +319,8 @@ impl TelemetryServiceDriver { // Old: a Service whose role is absent or unadmitted reports // Degraded with an empty projection and mutates nothing. ctx.set_status(TelemetryServiceStatus { - phase: PHASE_DEGRADED, - projection: serde_json::json!({}), + phase: TelemetryServicePhase::Degraded, + projection: None, present_endpoints: Vec::new(), }); return Ok(ReconcileOutcome::Satisfied); @@ -281,16 +328,16 @@ impl TelemetryServiceDriver { if role == "projection" { // Old: a projection Service is Ready without an ingest route. ctx.set_status(TelemetryServiceStatus { - phase: PHASE_READY, - projection: serde_json::json!({ - "serviceRole": "projection", - "serviceReadiness": PHASE_READY, + phase: TelemetryServicePhase::Ready, + projection: Some(TelemetryServiceProjection { + service_role: "projection", + service_readiness: TelemetryServicePhase::Ready, }), present_endpoints: Vec::new(), }); return Ok(ReconcileOutcome::Satisfied); } - let endpoint_refs = ingest_endpoint_refs(&spec); + let endpoint_refs = ingest_endpoint_refs(&spec).map_err(|kind| self.error(kind, op))?; let mut present_endpoints = Vec::with_capacity(endpoint_refs.len()); let mut all_present = !endpoint_refs.is_empty(); for endpoint_ref in &endpoint_refs { @@ -301,16 +348,20 @@ impl TelemetryServiceDriver { self.watch_once(ctx, key).await; } Ok(_) => all_present = false, - Err(_) => return Err(self.error(TelemetryServiceDriverErrorKind::Reconcile, op)), + Err(error) => { + return Err(self + .error(TelemetryServiceDriverErrorKind::Reconcile, op) + .with_source(error)); + } } } let ready = all_present && DEPENDENCY_READINESS_PROVEN; - let phase = if ready { PHASE_READY } else { PHASE_PENDING }; + let phase = if ready { TelemetryServicePhase::Ready } else { TelemetryServicePhase::Pending }; ctx.set_status(TelemetryServiceStatus { phase, - projection: serde_json::json!({ - "serviceRole": "authority", - "serviceReadiness": phase, + projection: Some(TelemetryServiceProjection { + service_role: "authority", + service_readiness: phase, }), present_endpoints, }); @@ -328,9 +379,13 @@ impl ResourceDriver for TelemetryServiceDriver { type Error = TelemetryServiceDriverError; fn classify_error(&self, error: &TelemetryServiceDriverError) -> DriverFailure { - // The old reconciler classified every failure retryable; the actor + // The old reconciler classified every failure retryable;the actor // owns retry/backoff from the closed class (R13). - DriverFailure::retryable(error.op) + match error.source() { + Some(source) => DriverFailure::retryable(error.op) + .with_detail(FailureDetail::at("manager").with_note(source.to_string())), + None => DriverFailure::retryable(error.op), + } } /// Structural validation only (old `validate_spec`): the stored envelope @@ -374,20 +429,25 @@ impl ResourceDriver for TelemetryServiceDriver { // --------------------------------------------------------------------------- /// Ingest endpoint refs declared by a Service spec. -fn ingest_endpoint_refs(spec: &serde_json::Value) -> Vec { +fn ingest_endpoint_refs( + spec: &serde_json::Value, +) -> Result, TelemetryServiceDriverErrorKind> { spec.get("ingestEndpointRefs") - .and_then(serde_json::Value::as_array) .map(|values| { values + .as_array() + .ok_or(TelemetryServiceDriverErrorKind::InvalidResource)? .iter() - .filter_map(|value| { + .map(|value| { value .as_str() .and_then(|value| ResourceRef::parse(value).ok()) + .ok_or(TelemetryServiceDriverErrorKind::InvalidResource) }) .collect() }) - .unwrap_or_default() + .transpose() + .map(|refs| refs.unwrap_or_default()) } // --------------------------------------------------------------------------- @@ -442,6 +502,32 @@ pub fn telemetry_service_descriptor() -> DriverDescriptor { #[cfg(test)] mod tests { use std::sync::Arc; + + #[test] + fn projection_serializes_to_the_contract_pinned_shape() { + let authority = TelemetryServiceProjection { + service_role: "authority", + service_readiness: TelemetryServicePhase::Ready, + }; + assert_eq!( + serde_json::to_value(authority).unwrap(), + serde_json::json!({ + "serviceRole": "authority", + "serviceReadiness": "Ready", + }), + ); + let projection = TelemetryServiceProjection { + service_role: "projection", + service_readiness: TelemetryServicePhase::Pending, + }; + assert_eq!( + serde_json::to_value(projection).unwrap(), + serde_json::json!({ + "serviceRole": "projection", + "serviceReadiness": "Pending", + }), + ); + } use tokio::sync::Mutex; use std::time::Duration; @@ -762,7 +848,7 @@ mod tests { let Some(status) = fixture.ctx.status::() else { panic!("service status"); }; - assert_eq!(status.phase, PHASE_PENDING); + assert_eq!(status.phase, TelemetryServicePhase::Pending); assert!(status.present_endpoints.is_empty()); assert_eq!( fixture.requeue.scheduled().await, @@ -776,12 +862,15 @@ mod tests { panic!("service status"); }; assert_eq!(status.present_endpoints.len(), 1); - assert_eq!(status.projection["serviceRole"], "authority"); + assert_eq!(status.projection.as_ref().unwrap().service_role, "authority"); // CONTRACT FLAG: the old predicate also required the ingest // Endpoint's own `status.phase == "Ready"`, which this surface cannot // read; the phase stays fail-closed Pending while the row exists. - assert_eq!(status.phase, PHASE_PENDING); - assert_eq!(status.projection["serviceReadiness"], PHASE_PENDING); + assert_eq!(status.phase, TelemetryServicePhase::Pending); + assert_eq!( + status.projection.as_ref().unwrap().service_readiness, + TelemetryServicePhase::Pending, + ); assert_eq!( fixture.requeue.scheduled().await, vec![TELEMETRY_SERVICE_RESYNC], @@ -811,9 +900,12 @@ mod tests { let Some(status) = fixture.ctx.status::() else { panic!("service status"); }; - assert_eq!(status.phase, PHASE_READY); - assert_eq!(status.projection["serviceRole"], "projection"); - assert_eq!(status.projection["serviceReadiness"], PHASE_READY); + assert_eq!(status.phase, TelemetryServicePhase::Ready); + assert_eq!(status.projection.as_ref().unwrap().service_role, "projection"); + assert_eq!( + status.projection.as_ref().unwrap().service_readiness, + TelemetryServicePhase::Ready, + ); assert!(fixture.manager.log().await.is_empty()); assert!(fixture.requeue.scheduled().await.is_empty()); } @@ -838,8 +930,8 @@ mod tests { let Some(status) = fixture.ctx.status::() else { panic!("service status"); }; - assert_eq!(status.phase, PHASE_DEGRADED); - assert_eq!(status.projection, serde_json::json!({})); + assert_eq!(status.phase, TelemetryServicePhase::Degraded); + assert!(status.projection.is_none()); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] diff --git a/packages/d2b-provider-telemetry-service/src/lib.rs b/packages/d2b-provider-telemetry-service/src/lib.rs index 71fc6c6a1..1c69dfcaf 100644 --- a/packages/d2b-provider-telemetry-service/src/lib.rs +++ b/packages/d2b-provider-telemetry-service/src/lib.rs @@ -32,6 +32,7 @@ mod driver; pub use driver::{ DEPENDENCY_READINESS_PROVEN, PHASE_DEGRADED, PHASE_PENDING, PHASE_READY, TELEMETRY_SERVICE_TYPE, TELEMETRY_SERVICE_RESYNC, TelemetryServiceDriver, - TelemetryServiceDriverError, TelemetryServiceDriverFactory, TelemetryServiceStatus, + TelemetryServiceDriverError, TelemetryServiceDriverFactory, TelemetryServicePhase, + TelemetryServiceProjection, TelemetryServiceStatus, telemetry_service_descriptor, telemetry_service_spec_decoder, }; From 8b3d2c924327380a2360792218384b4bba2dd80d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:54:36 -0700 Subject: [PATCH 396/726] audit: fold the contracts-control and device slice --- .../2026-09-24-rust-skills-audit/ledger.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 7d88cd5af..47aeed519 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -323,9 +323,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | | `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | | `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | -| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | | | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | | | +| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | needs-contract | U3 | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery recor | | | `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired — the illegal Consumed/Expired-with-Some(psk) combination is now unco | | -| `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:82, src/controller/mod.rs:982` | | | +| `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `identity.rs:857-865, controller.rs:1808-1818` | | | | `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | | `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `bootstrap_graph.rs:142-176, controller.rs:662-670` | | | @@ -381,10 +381,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114` | | | | `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | -| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | | | | `cli_output.rs:241, cli_output.rs:276` | | | -| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | | | | `cli_output.rs:6` | | | +| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but | | +| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:6` | Deleting the pub re-export of LevelPercent from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 0 hits for cli_output::LevelPercent outside cli_output.rs:6 | | | `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | | | -| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | | | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | | | +| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Narrowing pub methods in the published crate is a published-surface move; additionally the lane census is stale: HelperLaunchRequest::validate_bounds has a live external caller at d2b-unsafe-local-hel | | | `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src` | | | | `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/identity.rs:269-270` | | | @@ -422,8 +422,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U3 | 4efbf8ea5 | packages/d2b-provider-device-gpu/src/effects_service.rs | applied-variant: row's second option (single crate-owned sidecar) used: DeclaredWorkerGpuPortDeps sidecar (private fields, pub 4-arg ::new) holds the four dependency types; DeclaredWorkerGpuPortArgs ( | | | `RS-0372` | `api` | `d2b-provider-device-security-key` | low | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/lib.rs:16-17, packages/d2b-provider-device-s` | | | | `RS-0373` | `api` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | state.rs (StateDirectoryToken/TamperMarkerToken/StateOwnerToken/StateDirIntent) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.b | | -| `RS-0374` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:53, effects_service.rs:103, effects_service.rs:114` | | | -| `RS-0375` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:341` | | | +| `RS-0374` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 4de51c1b5 | packages/d2bd/src/shared_provider_effects.rs | Registered TpmEffectsServiceFactory for TPM_EFFECTS_SERVICE in the plane test inputs factory map (shared_provider_effects.rs), built from d2b_provider_device_tpm::test_support::recording_facets() - th | | +| `RS-0375` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 205e888b9 | packages/d2b-provider-device-tpm/src/effects_service.rs | LiveTpmResourceEffectPort made pub(crate); census re-run at HEAD: only effects_service.rs:341/364/535/679-680 reference it, 0 external hits | | | `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | | `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `lib.rs:24, lib.rs:61-65` | | | | `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `broker.rs:131-133` | | | @@ -433,7 +433,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12` | | | | `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | | `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | | | | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | | | -| `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:211, packages/d2b-provider-guest/src/effects_service.rs:1186` | | | +| `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmController::new now takes effect: E by value and stores it; the production call site and the crate's test call sites (18 FakeEffect constructions, incl. the shared-effect recovery test restruct | | | `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895` | | | | `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:1361-1376, controller.rs:1907-1909` | | | | `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | | | | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | | | @@ -513,7 +513,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/depen` | | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:2` | | | -| `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | | | | `public_wire.rs:1297` | | | +| `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | Added fmt::Display (message "invalid shell name") and std::error::Error impls to ShellNameError; additive, no surface moved. cargo check/test/clippy -p d2b-contracts-control --locked all passed | | | `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | applied | U3 | 58e72374f | packages/d2b-contracts-provider/src/v3/provider_registry.rs | split zero-generation check before mapping-count bound; Defensive-only reachability since ResourceGeneration rejects 0 at new/Deserialize; no consumer pins the code | | | `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError Display strings are wire outcome codes pinned by docs/specs/ADR-046-resources-credential.md:903 (credential-queue-pressure = lease table at capacity) and the provider ADR err | | | `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | @@ -598,7 +598,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composi` | | | | `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | | | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | | | | `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | | | -| `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | | | | `unsafe_local_wire.rs:118, unsafe_local_wire.rs:176, public_wire.rs:2228` | | | +| `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | | `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | @@ -639,7 +639,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 09167b5fa | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | All 62 log:: sites in d2b-clipd.rs converted to tracing:: with named fields; env_logger init replaced by tracing_subscriber::fmt().with_env_filter(...).with_writer(stderr).init() mirroring d2bd; log/e | | | `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provide` | | | | `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | -| `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `src/controller/mod.rs:346, src/controller/mod.rs:425` | | | +| `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml | #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] on reconcile/adopt/poll_operation/update/finalize; per-event provider literal and redacted resource_group field dro | | | `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | cc01388e6 | packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs | reconcile/finalize now carry a tracing instrument span with resource/provider fields; 23 per-event duplicate pairs dropped. Deviation: the row's literal span syntax (fields inside skip) is rejected by | | | `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-system` | | | | `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | From 0d74a18f2b6e2c42a896e5a69d3c40916b02e847 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:54:18 -0700 Subject: [PATCH 397/726] d2b-resource-api: drop unwired config batch path, refine batch errors, use tracing --- packages/d2b-resource-api/src/client.rs | 13 +------------ packages/d2b-resource-api/src/service.rs | 14 ++------------ 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/packages/d2b-resource-api/src/client.rs b/packages/d2b-resource-api/src/client.rs index da9cdac0f..ac5002308 100644 --- a/packages/d2b-resource-api/src/client.rs +++ b/packages/d2b-resource-api/src/client.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use d2b_contracts_resource::resource_proto as wire; -use d2b_contracts_resource::v3::{ConfigurationGeneration, identity::AuthenticatedSubjectContext}; +use d2b_contracts_resource::v3::identity::AuthenticatedSubjectContext; use d2b_core_controller::controller_assignment::ScopedResourceMutation; use crate::{ @@ -94,17 +94,6 @@ where self.service.commit_batch(self.trusted(request)).await } - /// Commit a verified configuration bundle through the internal Core path. - pub async fn commit_configuration_batch( - &self, - request: wire::CommitBatchRequest, - configuration_generation: ConfigurationGeneration, - ) -> wire::CommitBatchResponse { - self.service - .commit_configuration_batch(self.trusted(request), configuration_generation) - .await - } - /// Commit a batch carrying the bus-admitted assignment fence into every /// store mutation without opening a second transport. pub async fn scoped_commit_batch( diff --git a/packages/d2b-resource-api/src/service.rs b/packages/d2b-resource-api/src/service.rs index 94c20f64e..6bacee0ed 100644 --- a/packages/d2b-resource-api/src/service.rs +++ b/packages/d2b-resource-api/src/service.rs @@ -850,16 +850,6 @@ where self.commit_batch_with_scope(trusted, None, None).await } - /// Commit an integrity-verified configuration bundle from in-process Core. - pub async fn commit_configuration_batch( - &self, - trusted: TrustedRequest, - configuration_generation: ConfigurationGeneration, - ) -> wire::CommitBatchResponse { - self.commit_batch_with_scope(trusted, None, Some(configuration_generation)) - .await - } - pub(crate) fn invalid_commit_batch(reason: &'static str) -> wire::CommitBatchResponse { batch_error(schema_error(reason)) } @@ -882,7 +872,7 @@ where configuration_generation: Option, ) -> wire::CommitBatchResponse { if trusted.request.mutations.is_empty() { - return batch_error(schema_error("batch mutation count exceeds its bound")); + return batch_error(schema_error("batch mutation count is zero")); } let routes = match trusted .request @@ -2006,7 +1996,7 @@ fn parse_create_payload( ); let envelope = ResourceEnvelope::from_json(&validation_value.to_canonical_bytes()) .map_err(|error| { - eprintln!("resource-api:create-envelope-validation-failed error={error}"); + tracing::debug!(error = %error, "create envelope validation failed"); schema_error("create resource payload is malformed") })?; let payload_digest = canonical_digest(RESOURCE_ENVELOPE_DOMAIN_TAG, &canonical_resource); From 333ad7f498cd87f0377ed1bc243d71ab17a592d4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:55:06 -0700 Subject: [PATCH 398/726] audit: backfill the wave-1 rows that carried no reason --- .../2026-09-24-rust-skills-audit/ledger.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 47aeed519..7c11140a1 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -92,12 +92,12 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U2 | db396585b | `packages/d2b-provider-device-security-key/src/driver.rs` | declared_dependency_refs arms are iterator-chain expressions; push closure deleted | | | `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | swtpm_argv.rs imports and uses MIN/MAX_SWTPM_LOG_LEVEL instead of literal 1..=20 | | | `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | 9e7388e34 | `packages/d2b-provider-device-usbip/src/driver.rs` | declared_dependency_refs match arms return flatten().collect() expressions | | -| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | | | -| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | | | -| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | | | +| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | Applied with this commit: display-wayland: drop stale dead-code allows and delegate session digest | | +| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | Applied with this commit: display-wayland: simplify bridge handoff error binding and bind dispatch | | +| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | Applied with this commit: display-wayland: drop stale dead-code allows and delegate session digest | | | `RS-0054` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | row fix text names chains for wm_base/eglstream/compositor; the remaining shm/subcompositor/seat/viewporter/dmabuf/drm if-lets stay in the final else block, matching the row's 'keeping the early retur | | -| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | | | -| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs` | | | +| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | Applied with this commit: display-wayland: tidy dmabuf table loop and share filter list by Rc | | +| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs` | Applied with this commit: display-wayland: track written label chars and document bridge and readiness errors | | | `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | row says 'four comment blocks' while citing 7 sites; all 7 sites fixed | | | `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/effects_service.rs` | Added the unit-test option: pinned inspect-endpoint payload rows to guest_control_producer/device_worker_endpoint_class (set + per-row class/producer/locality). Mutation (locality drift) fails the tes | | | `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/endpoint.rs` | Derive Default on EndpointConsumerPolicy (field-wise empty-Vec default identical to unrestricted()); dropped the manual impl. | | @@ -132,7 +132,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/zone_client.rs` | Dropped the duplicate GuestControlEndpoint::endpoint_uid accessor (kept uid()); removed the now-obsolete equivalence assertion. Census: no external caller. | | | `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | stated fix not implementable as written: pub(crate) items in the lib are not importable from the bin target (cargo E0603), so sanitize_token/bound_message became pub with doc first sentences; safe_lab | | | `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's stated filter pipeline would drop replaced characters; the behavior-preserving variant uses map with the same condition, keeping the '?' substitution (user-visible CLI error text) | | -| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | | | +| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | | `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's literal snippet is missing parentheses; the chain shape used is names.difference(...).map(...).chain(declared_names.difference(...).map(...)).collect() preserving bin= then manifest= order | | | `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | derive Default on three unit structs; new() const kept | | | `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | declined | U2 | | `target.rs` | sort_by_key and sort_by_cached_key both rejected by rustc 1.97 (lifetime may not live long enough; closure returns (&str,&str,&str) borrowing the element); kept sort_by | | @@ -241,11 +241,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/client.rs` | scoped_commit_batch and commit_scoped_batch take &[ScopedResourceMutation]; commit_batch_with_scope takes Option<&[..]>; adapter passes transport.mutations() directly. | | | `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/admission.rs` | mutations.into_iter().map(prepare_mutation); the redundant .cloned() removed. | | | `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | | | | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | | | -| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | applied | U2 | 628c96492 | `packages/d2b-resource-compiler/src/linux.rs` | | | -| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | | | -| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | | | +| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | applied | U2 | 628c96492 | `packages/d2b-resource-compiler/src/linux.rs` | Applied with this commit: resource-compiler: drop the unused anchored flag accessors | | +| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | +| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | | `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | row's stated fix (drop the argv[0] binding) is functionally broken; minimal correct variant keeps the skip via args.nth(1) | | -| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | | | +| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | | `RS-0206` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | observed_status filters before clone | | | `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | insert_new takes StoredDesiredResource by value; ensure passes by move | | | `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 0e6061c1e | `resource.rs` | pre_start moves row into state; clones only for ResourceContext::new | | @@ -736,9 +736,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0683` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | Module allow dropped; SwtpmArgvError variant fields documented to satisfy deny(missing_docs) | | | `RS-0684` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | 59c6a4e3a | `packages/d2b-provider-device-usbip/src/reconcile_state.rs` | All pub items documented (compiler-enumerated, incl. trait methods and variant fields); both module allows dropped | | | `RS-0685` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | a1d9832ec | `packages/d2b-provider-device-usbip/src/arbitration.rs` | # Errors added to the eight named pub Result items | | -| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/policy.rs` | | | +| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/policy.rs` | Applied with this commit: display-wayland: correct policy getter docs and add error sections | | | `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs` | from_identity_parts, path_for_user_identity, parse_filter, and the three ReadinessReporter methods had no doc comment at all; each received a first sentence plus the # Errors section (the readiness co | | -| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/spec.rs` | | | +| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/spec.rs` | Applied with this commit: display-wayland: correct policy getter docs and add error sections | | | `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/facets.rs` | Added # Errors to row_view, session_target_control, resource_uid, and the GuestTargetEffect trait's realize/delete/adopt. | | | `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 8a45d2d37 | `packages/d2b-provider-guest-azure-container-apps/src/effects.rs` | Documented effects pub surface (consts, enums, opaque_id! expansion, configs, records, candidates, both effect traits) and dropped the module-level allow; crate builds under deny. | | | `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | From dc09819bf988174730c1c523f6ff0e4d90bee0d2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:56:07 -0700 Subject: [PATCH 399/726] guest-cloud-hypervisor: drop constant preserve_state accessor and tautology --- packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | 5 ----- .../tests/finalize_ordering_test.rs | 1 - 2 files changed, 6 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs index 25bdb4a71..305188ccf 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs @@ -563,11 +563,6 @@ impl GuestUpgradePlan { self.next_session_generation } - /// Whether durable state is preserved. - pub const fn preserve_state(&self) -> bool { - true - } - /// Borrow ordered recycle steps. pub fn steps(&self) -> &[FinalizationStep] { &self.steps diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/finalize_ordering_test.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/finalize_ordering_test.rs index 2d2817685..eb9f40403 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/finalize_ordering_test.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/finalize_ordering_test.rs @@ -283,7 +283,6 @@ fn disruptive_upgrade_preserves_durable_volume_and_advances_session_generation() ) .unwrap(); assert_eq!(plan.reason(), UpgradeReason::ImageOrSystemGenerationChanged); - assert!(plan.preserve_state()); assert_eq!(plan.durable_volumes(), &[durable]); assert_eq!(plan.next_session_generation(), 10); assert!( From 7be252b7baa53dedd68f42a5169c471178dad566 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:56:29 -0700 Subject: [PATCH 400/726] audit: record the display provider check reproduced at the audit base --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 7c11140a1..77192538d 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -25,6 +25,7 @@ Defects the audited surfaces carry at HEAD that no corpus row claims and no wave - `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Observed at the wave-2 base. A test-only allow is the broker package owner's policy call. - (wave-1 regression, fixed on the integration branch) `cargo clippy -p d2b-bus --locked --all-targets` stopped at `use of a disallowed method std::sync::Mutex::lock` in `packages/d2b-bus/src/session/contract.rs`. The missing inline allow arrived with the wave-1 batch commit `fbf92683a`, which extracted `verify_body` out of the already-sanctioned `verify`; wave 1's Bazel clippy action did not flag the extraction, so the wave gate stayed green while plain-cargo clippy went red for `d2b-bus` and every crate depending on it. Fixed with the same sanctioned reason its four sibling functions use (`synchronous path`); `xtask check-provider-crate-layout` validates allow reasons against its sanctioned set rather than a per-site list, so no list changed and the site is not an ad-hoc allow. The broker test-helper entries below stay pre-existing and unfixed. +- `cargo check -p d2b-provider-display-wayland --locked --all-targets` fails to compile the lib test with `E0599` on `AuthenticatedSessionRouteBinding::for_test` (a `test-support` cfg mismatch). Reproduced at the audit base `147a536a0` in a detached worktree, so this one is genuinely pre-existing rather than a wave regression - unlike the bus entry above, which the same check proved to be mine. - `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. ## Wave gates From 159a84f30c766ccbac192af6c13f016ecf27b2fd Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:57:17 -0700 Subject: [PATCH 401/726] process-systemd: delete unused SystemdProviderError catalogue --- packages/d2b-provider-process-systemd/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/d2b-provider-process-systemd/src/lib.rs b/packages/d2b-provider-process-systemd/src/lib.rs index d5cfba53c..4a1219796 100644 --- a/packages/d2b-provider-process-systemd/src/lib.rs +++ b/packages/d2b-provider-process-systemd/src/lib.rs @@ -23,7 +23,6 @@ pub mod audit; pub mod controller; pub mod drain; pub mod effects_service; -pub mod error; pub mod launch; pub mod lifecycle; pub mod metrics; From e2f9719ac0eb4da6bc902a3f02704dff4df0e0e1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:57:21 -0700 Subject: [PATCH 402/726] process-systemd: delete unused SystemdProviderError catalogue --- .../d2b-provider-process-systemd/src/error.rs | 37 ------------------- 1 file changed, 37 deletions(-) delete mode 100644 packages/d2b-provider-process-systemd/src/error.rs diff --git a/packages/d2b-provider-process-systemd/src/error.rs b/packages/d2b-provider-process-systemd/src/error.rs deleted file mode 100644 index e83fcfdb6..000000000 --- a/packages/d2b-provider-process-systemd/src/error.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! Stable systemd Provider error labels. - -/// Closed systemd Provider error catalogue. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SystemdProviderError { - /// Transient start exceeded its deadline. - LaunchTimeout, - /// User manager could not be reached. - UserManagerUnavailable, - /// Stable identity tuple did not match. - IdentityMismatch, - /// Effect port was unavailable. - EffectPortUnavailable, - /// Finalization lacked a terminal proof. - FinalizeProofMissing, -} - -impl SystemdProviderError { - /// Return the stable lower-kebab code. - pub const fn code(self) -> &'static str { - match self { - Self::LaunchTimeout => "systemd-launch-timeout", - Self::UserManagerUnavailable => "systemd-user-manager-unavailable", - Self::IdentityMismatch => "systemd-identity-mismatch", - Self::EffectPortUnavailable => "systemd-effect-port-unavailable", - Self::FinalizeProofMissing => "systemd-finalize-proof-missing", - } - } -} - -impl core::fmt::Display for SystemdProviderError { - fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter.write_str(self.code()) - } -} - -impl std::error::Error for SystemdProviderError {} From 0e6f2823f45f9b242619f1be9d266002fd989bca Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:57:36 -0700 Subject: [PATCH 403/726] audit: fold the daemon tail --- .../2026-09-24-rust-skills-audit/ledger.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 77192538d..8626d7ed5 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -577,16 +577,16 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | | | | `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_` | | | | `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | | | -| `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | record_workload_availability_metrics expect-panic on label drift; single source of truth / graceful entry. Not edited: budget exhausted. | | +| `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | -| `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | not-started | U3 | | packages/d2bd/src/resource_plane_v3.rs | PlaneError five String variants -> typed payload/#[source]. Not edited: budget exhausted. | | +| `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | a91ad9bbc | packages/d2bd/src/resource_plane_v3.rs | PlaneError's five String variants retyped: FoundationSeed(#[from] SeedError), ManagerSpawn(#[from] ractor::SpawnErr), Bundle(#[from] ResourceBundleError), Authority/Target(#[source] Box tracing::error! with named fields (sites at 4102/4120/4153/4159). Not edited: budget exhausted. | | -| `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Three lifecycle info! events message-only; add named fields. Not edited: budget exhausted. | | +| `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Accept loop's four eprintln! calls replaced with tracing::error! events: connection-handler failures carry error = %error.message() (and peer_uid = peer.uid, captured before the move into the handler; | | +| `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Three lifecycle info events gained named fields: Guest-local ZoneLink transport Provider composed and Guest target-control service composed carry zone = %identity.zone() and guest_ref = %identity.gues | | | `RS-0607` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 31248998b093d92fef1e41eb07ecb49e3b79d33c | packages/d2bd/src/provider_lifecycle.rs | publish_trusted_context failure arm now carries error = %error as a named field, matching the sibling Ok(_) arm and the plane's other warn sites. cargo check green; clippy green for d2bd. | | | `RS-0602` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 73f90a27e93a9d36942287072f2f8a9c398aee53 | packages/d2bd/src/resource_runtime.rs | The eight named map_err closures (envelope/spec/construction/current-resource/status-serialization/descriptor-decode/descriptor-verify/controller-construction) now capture the error and log it as erro | | -| `RS-0603` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Located at composition.rs:14815 (drifted from 14781): message-only error; add zone field. Not edited: budget exhausted. | | -| `RS-0604` | `obs` | `d2bd` | low | actionable | leaf | not-started | U3 | | packages/d2bd/src/composition.rs | Two identical message-only warn events during shutdown; add zones field. Not edited: budget exhausted. | | +| `RS-0603` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | The root Zone generation unavailable refusal in compose_gateway_zone_links now carries zone = %topology.root, so the refusal is queryable per zone. Checks: cargo check green. | | +| `RS-0604` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Both LiveRequestOwners warn events in shutdown_resource_plane now carry zones = ?zones, so the operator can tell welche Zones are stuck. Checks: cargo check green. | | | `RS-0608` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | In-flight-cap refusal warn now carries peer_uid and max = posture.max_inflight fields, matching the sibling peer-not-broker warn style. Committed together with RS-0577 (same file, same commit). cargo | | | `RS-0609` | `obs` | `d2bd-runtime` | low | actionable | leaf | already-fixed | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | At session-start HEAD, write_daemon_version_file already routes all five failure paths through tracing::warn! with error/path named fields (commit 97df1b826). No edit made. | | | `RS-0610` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 918539524 | packages/d2bd-runtime/src/ssh_host_key_preflight.rs | Octal mode field is now tracing::field::debug(format_args!(...)));the pre-joined subjects string was inlined as tracing::field::display(join-expr) inside the warn! so it is built only when the event i | | From f17f141c6dd834a80c4561670bed581c95a0f41a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:57:38 -0700 Subject: [PATCH 404/726] provider-network-local: narrow route intent validators to test surface --- packages/d2b-provider-network-local/src/routes.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-network-local/src/routes.rs b/packages/d2b-provider-network-local/src/routes.rs index ec8b991d9..c4585f338 100644 --- a/packages/d2b-provider-network-local/src/routes.rs +++ b/packages/d2b-provider-network-local/src/routes.rs @@ -242,7 +242,8 @@ impl core::fmt::Display for RouteProvenanceError { impl std::error::Error for RouteProvenanceError {} /// Validate a route before the broker can apply or remove it. -pub fn validate_network_route_intent( +#[cfg(test)] +pub(crate) fn validate_network_route_intent( intent: &NetworkRouteIntent, network_uid: &ResourceUid, network_generation: ResourceGeneration, @@ -261,8 +262,8 @@ pub fn validate_network_route_intent( } /// Validate a route against the complete admitted provenance tuple. -#[allow(dead_code)] -pub fn validate_network_route_intent_with_provenance( +#[cfg(test)] +pub(crate) fn validate_network_route_intent_with_provenance( intent: &NetworkRouteIntent, zone_uid: &ResourceUid, network_uid: &ResourceUid, From 62f4be4ff37e591f6b60c898fc98458e1b47ae3d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:57:44 -0700 Subject: [PATCH 405/726] d2b-provider-supervisor: clamp constructor limits instead of panicking --- packages/d2b-provider-supervisor/src/adapter.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-supervisor/src/adapter.rs b/packages/d2b-provider-supervisor/src/adapter.rs index a926b9ad1..329de5e41 100644 --- a/packages/d2b-provider-supervisor/src/adapter.rs +++ b/packages/d2b-provider-supervisor/src/adapter.rs @@ -415,10 +415,17 @@ impl ProviderSupervisor { /// Build an adapter with explicit blocking concurrency and fallback timeout. /// - /// A zero blocking limit is rejected because it would deadlock every call. + /// A zero blocking limit is clamped up to one, because zero would + /// deadlock every call; a zero fallback timeout is clamped up to the + /// default thirty-second deadline, because every blocked effect would + /// otherwise expire immediately. pub fn with_limits(backend: B, blocking_limit: usize, default_timeout: Duration) -> Self { - assert!(blocking_limit > 0, "blocking limit must be nonzero"); - assert!(!default_timeout.is_zero(), "timeout must be nonzero"); + let blocking_limit = blocking_limit.max(1); + let default_timeout = if default_timeout.is_zero() { + Duration::from_secs(30) + } else { + default_timeout + }; Self { inner: Arc::new(Inner { backend: Arc::new(backend), From 0cb5d7b68818fe8f2a613375c67099a061064bee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:57:59 -0700 Subject: [PATCH 406/726] d2b-provider-supervisor: take boxed launched observer --- packages/d2b-provider-supervisor/src/broker.rs | 6 +++--- packages/d2bd/src/process_provider_runtime.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-supervisor/src/broker.rs b/packages/d2b-provider-supervisor/src/broker.rs index 76ae4d13e..a68bea31e 100644 --- a/packages/d2b-provider-supervisor/src/broker.rs +++ b/packages/d2b-provider-supervisor/src/broker.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use std::fs; use std::os::fd::{AsRawFd, OwnedFd}; use std::path::PathBuf; -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use std::time::Duration; use d2b_contracts::types::{BundleOpId, RoleId, VmId}; @@ -964,7 +964,7 @@ pub struct BrokerProcessBackend { io_timeout: Duration, caller_role: BrokerCallerRole, observations: Mutex>, - launched_observer: Option>, + launched_observer: Option>, } impl BrokerProcessBackend { @@ -992,7 +992,7 @@ impl BrokerProcessBackend { /// Wire the daemon's launched-runner observer (the pidfd-table /// registration) onto this backend. - pub fn set_launched_observer(&mut self, observer: Arc) { + pub fn set_launched_observer(&mut self, observer: Box) { self.launched_observer = Some(observer); } diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index 016b77b25..e9b009c8f 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -910,7 +910,7 @@ impl ProductionProcessProviders { // readiness probe runs, so the table registration rides the backend's // launch-success notification - not the driver's post-launch path, // which runs after the probe. - minijail_backend.set_launched_observer(std::sync::Arc::new(PidfdTableLaunchedObserver { + minijail_backend.set_launched_observer(Box::new(PidfdTableLaunchedObserver { pidfd_table: pidfd_table.clone(), })); let systemd_owner = BrokerSystemdEffectOwner::with_socket_and_role( From a0b1500a30a92f3eb14dceac8a05bb93227383d5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:01 -0700 Subject: [PATCH 407/726] audit: fold the media provider slice --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 8626d7ed5..bf26a2ce7 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -312,7 +312,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | | `RS-0262` | `type` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | | | | `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 81d0ff057 | packages/d2b-process-conformance/src/ticket.rs | Bundled zone_uid+runtime_scope into one private Option pairing; const-compatible match accessors keep the public API byte-identical. | | -| `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, sr` | | | +| `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | 87e8d7654 | packages/d2b-provider-audio-pipewire/src/resource_type.rs | owner()/new() now infallible; validate_audio_* remain the single admission gate (they also check provider_ref/extension/zone the ctors cannot). All call sites updated; check+test+clippy green on 4 cra | | | `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199` | | | | `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 4404afb72 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Merged picker (args.picker.or(config)) validated once after merge; relative paths rejected from either source. | | | `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider` | | | @@ -335,8 +335,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-` | | | | `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:56, agent.rs:265, agent.rs:297` | | | | `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | | | | `packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minij` | | | -| `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lifecycle.rs:78, packages/d2b-provider-process-s` | | | -| `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/metrics.rs:7, packages/d2b-provider-process-syst` | | | +| `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | +| `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | aee724326 | packages/d2b-provider-process-systemd/src/metrics.rs | Added MetricLabelKey enum with as_str(); validate_labels takes typed keys; dropped LABEL_KEYS const (census: only in-crate definition, zero users). Unknown-key rejection now type-level; test updated. | | | `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry` | | | | `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telem` | | | | `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-p` | | | @@ -439,7 +439,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:1361-1376, controller.rs:1907-1909` | | | | `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | | | | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | | | | `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `identity.rs:554-556, tests/controller.rs:206` | | | -| `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:576-578` | | | +| `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | dc09819bf | packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | Deleted constant-true preserve_state() accessor and its tautological assertion (census: only consumer was the assertion). check+finalize_ordering tests (6) + clippy green. | | | `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | | `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111,` | | | | `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/routes.rs:244-279, src/routes.rs:264-265` | | | @@ -447,7 +447,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:110, packages/d2b-provider-no` | | | | `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1-3, packages/d2b-provi` | | | | `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd` | | | -| `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lifecycle.rs:55, packages/d2b-provider-process-s` | | | +| `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | | `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd` | | | | `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/driver.rs:215, src/driver.rs:229` | | | | `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | | | | `src/providers.rs:121, src/lib.rs:19` | | | @@ -551,7 +551,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-not` | | | | `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `ingress_policy.rs:647` | | | | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/d` | | | -| `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/error.rs:5, packages/d2b-provider-process-system` | | | +| `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | | `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:419-421` | | | | `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:888-890` | | | | `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:304` | | | From 7c4997d04d577278f1bd598827d3bdc451c01eee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:04 -0700 Subject: [PATCH 408/726] d2b-provider-device-usbip: hide the authority ledger lock behind a handle --- .../d2b-provider-device-usbip/src/broker.rs | 26 ++++++++++++++++--- packages/d2bd/src/shared_provider_effects.rs | 4 +-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/d2b-provider-device-usbip/src/broker.rs b/packages/d2b-provider-device-usbip/src/broker.rs index f5d335fec..8584681cc 100644 --- a/packages/d2b-provider-device-usbip/src/broker.rs +++ b/packages/d2b-provider-device-usbip/src/broker.rs @@ -132,9 +132,27 @@ impl AuthorityLedger { } } +/// Handle to one zone's shared authority ledger. +/// +/// The concrete synchronization primitive is an implementation detail: +/// dispatchers and the daemon share this handle, never the lock type +/// itself, so a lock change stays local to this crate. +#[derive(Clone)] +pub struct AuthorityLedgerHandle(Arc>); + +impl std::ops::Deref for AuthorityLedgerHandle { + type Target = tokio::sync::Mutex; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + /// Construct one zone's shared authority ledger. -pub fn new_authority_ledger() -> Arc> { - Arc::new(tokio::sync::Mutex::new(AuthorityLedger::default())) +pub fn new_authority_ledger() -> AuthorityLedgerHandle { + AuthorityLedgerHandle(Arc::new(tokio::sync::Mutex::new( + AuthorityLedger::default(), + ))) } /// The provider-owned implementation of the Provider dispatcher (U12 usbip @@ -144,7 +162,7 @@ pub fn new_authority_ledger() -> Arc> { pub struct KernelUsbipDispatcher<'a> { dispatch: &'a dyn UsbipBrokerDispatch, context: UsbipBindingContext, - ledger: Arc>, + ledger: AuthorityLedgerHandle, attach_identity: Option, attach_slot: Option, attach_proxy: Option, @@ -159,7 +177,7 @@ impl<'a> KernelUsbipDispatcher<'a> { pub fn new( dispatch: &'a dyn UsbipBrokerDispatch, context: UsbipBindingContext, - ledger: Arc>, + ledger: AuthorityLedgerHandle, ) -> Self { Self { dispatch, diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 68c23ff1f..9038695be 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -213,7 +213,7 @@ pub(crate) struct ProductionSharedProviderEffects { gpu_facets: std::sync::OnceLock, /// Zone-wide USBIP authority ledger (old `usbip_ledger`), shared by every /// USBIP Service and Binding dispatcher in the zone. - usbip_ledger: Arc>, + usbip_ledger: d2b_provider_device_usbip::broker::AuthorityLedgerHandle, /// Zone-wide activated USBIP services (old `usbip_services`). usbip_services: Arc>>, /// Scripted host-network occupancy (test-support only): a test installs a @@ -1310,7 +1310,7 @@ impl ProductionSharedProviderEffects { let port = d2b_provider_device_usbip::broker::KernelUsbipDispatcher::new( dispatch.as_ref(), binding_context, - Arc::clone(&self.usbip_ledger), + self.usbip_ledger.clone(), ) .into_port(); let opted_in = request.spec.pointer("/mode").and_then(Value::as_str) == Some("authority"); From 2f5c9a6922d8bf057aa7f73d456a94af8e469646 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:08 -0700 Subject: [PATCH 409/726] d2b-provider-device-usbip: type the step executor errors --- .../src/state_machine.rs | 67 ++++++++++--------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/packages/d2b-provider-device-usbip/src/state_machine.rs b/packages/d2b-provider-device-usbip/src/state_machine.rs index db3a2ce6b..0469c6420 100644 --- a/packages/d2b-provider-device-usbip/src/state_machine.rs +++ b/packages/d2b-provider-device-usbip/src/state_machine.rs @@ -386,19 +386,19 @@ pub fn build_usbip_explicit_plan( /// after a partial failure are expected. pub trait UsbipStepExecutor { /// Ensure the usbip-host kernel module is loaded. - fn modprobe(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + fn modprobe(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError>; /// Acquire the broker-mediated claim lock. - fn acquire_lock(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + fn acquire_lock(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError>; /// Withhold non-owner VMs from the physical device. - fn withhold_non_owners(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + fn withhold_non_owners(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError>; /// Apply host firewalling for the claim. - fn apply_firewall(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + fn apply_firewall(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError>; /// Start the per-environment USBIP backend. - fn start_backend(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + fn start_backend(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError>; /// Bind the device to the host USBIP export. - fn bind(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + fn bind(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError>; /// Start the per-environment USBIP proxy. - fn start_proxy(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + fn start_proxy(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError>; } /// Per-step outcome recorded during execution. Successful steps @@ -475,22 +475,17 @@ pub fn execute_usbip_plan( }; match result { Ok(()) => report.completed.push(*step), - Err(reason) => { - report.failed = Some((*step, reason.clone())); + Err(error) => { + report.failed = Some((*step, error.reason.clone())); tracing::warn!( busid = %plan.busid, env = %plan.env, vm = %plan.vm, step = %step, - reason = %reason, + reason = %error.reason, "usbip bring-up plan step failed", ); - let err = UsbipPlanError { - busid: plan.busid.clone(), - step: *step, - reason, - }; - return Err((Box::new(report), err)); + return Err((Box::new(report), error)); } } } @@ -521,38 +516,46 @@ mod tests { fail_at: Some((step, reason)), } } - fn dispatch(&mut self, step: UsbipBusidStep) -> Result<(), String> { + fn dispatch( + &mut self, + plan: &UsbipBusidPlan, + step: UsbipBusidStep, + ) -> Result<(), UsbipPlanError> { self.calls.push(step); if let Some((target, reason)) = self.fail_at && target == step { - return Err(reason.to_owned()); + return Err(UsbipPlanError { + busid: plan.busid.clone(), + step, + reason: reason.to_owned(), + }); } Ok(()) } } impl UsbipStepExecutor for FixtureExecutor { - fn modprobe(&mut self, _: &UsbipBusidPlan) -> Result<(), String> { - self.dispatch(UsbipBusidStep::Modprobe) + fn modprobe(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError> { + self.dispatch(plan, UsbipBusidStep::Modprobe) } - fn acquire_lock(&mut self, _: &UsbipBusidPlan) -> Result<(), String> { - self.dispatch(UsbipBusidStep::Lock) + fn acquire_lock(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError> { + self.dispatch(plan, UsbipBusidStep::Lock) } - fn withhold_non_owners(&mut self, _: &UsbipBusidPlan) -> Result<(), String> { - self.dispatch(UsbipBusidStep::Withhold) + fn withhold_non_owners(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError> { + self.dispatch(plan, UsbipBusidStep::Withhold) } - fn apply_firewall(&mut self, _: &UsbipBusidPlan) -> Result<(), String> { - self.dispatch(UsbipBusidStep::Firewall) + fn apply_firewall(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError> { + self.dispatch(plan, UsbipBusidStep::Firewall) } - fn start_backend(&mut self, _: &UsbipBusidPlan) -> Result<(), String> { - self.dispatch(UsbipBusidStep::Backend) + fn start_backend(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError> { + self.dispatch(plan, UsbipBusidStep::Backend) } - fn bind(&mut self, _: &UsbipBusidPlan) -> Result<(), String> { - self.dispatch(UsbipBusidStep::Bind) + fn bind(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError> { + self.dispatch(plan, UsbipBusidStep::Bind) } - fn start_proxy(&mut self, _: &UsbipBusidPlan) -> Result<(), String> { - self.dispatch(UsbipBusidStep::Proxy) + fn start_proxy(&mut self, plan: &UsbipBusidPlan) -> Result<(), UsbipPlanError> { + self.dispatch(plan, UsbipBusidStep::Proxy) } } From 8b53d606ed7f04627cc59370190015d4e1a6df2f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:12 -0700 Subject: [PATCH 410/726] d2b-resource-client: drop zero-caller public surface --- .../d2b-resource-client/src/process_attach.rs | 40 +--------- .../d2b-resource-client/src/zone_client.rs | 76 +------------------ 2 files changed, 6 insertions(+), 110 deletions(-) diff --git a/packages/d2b-resource-client/src/process_attach.rs b/packages/d2b-resource-client/src/process_attach.rs index 34346ed3c..8beaebd6f 100644 --- a/packages/d2b-resource-client/src/process_attach.rs +++ b/packages/d2b-resource-client/src/process_attach.rs @@ -21,8 +21,8 @@ use d2b_contracts_zone_session::v3::zone_routing::ZonePath; use crate::{ AttemptDisposition, CallOptions, CancellationToken, ClientError, MethodProfile, ResourceClient, ServiceOwner, SystemClock, TargetInput, TargetResolver, - TransportKind, TransportSelection, WallClock, ZoneClient, ZoneServiceKind, - ZoneSessionConnector, call::REQUEST_ID_BYTES, zone_client::ConnectedZoneSession, + TransportSelection, WallClock, ZoneClient, ZoneServiceKind, ZoneSessionConnector, + call::REQUEST_ID_BYTES, zone_client::ConnectedZoneSession, }; /// The maximum logical message accepted by one attach stream. @@ -121,20 +121,6 @@ impl ProcessAttachTarget { }) } - /// Interpret a resource-shaped target as an EphemeralProcess target. - pub fn from_target(target: TargetInput) -> Result { - let zone = target.owner().zone().clone(); - let resource = target.resource_ref().ok_or(ClientError::InvalidTarget)?; - Self::ephemeral_process(zone, resource) - } - - /// Interpret a resource-shaped target as a configured launcher target. - pub fn configured_launcher_from_target(target: TargetInput) -> Result { - let zone = target.owner().zone().clone(); - let resource = target.resource_ref().ok_or(ClientError::InvalidTarget)?; - Self::configured_launcher(zone, resource) - } - /// Return the attach kind. pub const fn kind(&self) -> ProcessAttachKind { match self { @@ -727,24 +713,6 @@ where } } - /// Attach using the local Unix carriage. - pub async fn attach_local( - &self, - target: ProcessAttachTarget, - attach_options: ProcessAttachOptions, - call_options: CallOptions, - cancellation: &CancellationToken, - ) -> Result::Stream>, ClientError> { - self.attach( - target, - attach_options, - call_options, - TransportSelection::exact(TransportKind::LocalUnix), - cancellation, - ) - .await - } - /// Establish and close one attachment without exposing the stream handle. /// /// This is useful for operator surfaces whose current command contract @@ -786,8 +754,8 @@ mod tests { use super::*; use crate::{ - MetadataInput, RetryPolicy, RouteRecord, RouteTable, ServiceOwner, ZonePeerIdentity, - ZoneSessionPin, + MetadataInput, RetryPolicy, RouteRecord, RouteTable, ServiceOwner, TransportKind, + ZonePeerIdentity, ZoneSessionPin, }; const ISSUED: u64 = 10_000; diff --git a/packages/d2b-resource-client/src/zone_client.rs b/packages/d2b-resource-client/src/zone_client.rs index 54eefbfbf..21d6af9f8 100644 --- a/packages/d2b-resource-client/src/zone_client.rs +++ b/packages/d2b-resource-client/src/zone_client.rs @@ -16,12 +16,9 @@ use std::{ }; use d2b_contracts_resource::v3::{ - CanonicalJsonObject, ResourceGeneration, ResourceName, ResourceRef, ResourceTypeName, - ResourceUid, SchemaFingerprint, ZoneId, -}; -use d2b_core_controller::controller_assignment::{ - AssignmentError, ResourceClientLease, ScopedResourceFilter, + CanonicalJsonObject, ResourceGeneration, ResourceRef, ResourceUid, SchemaFingerprint, ZoneId, }; +use d2b_core_controller::controller_assignment::ResourceClientLease; pub use d2b_core_controller::controller_assignment::{ AssignmentIdentity, AssignmentVerb, OwnerChildScope, ScopedResourceMutation, ScopedResourceQuery, ScopedResourceScope, @@ -79,14 +76,6 @@ impl ZonePeerIdentity { } } - /// Construct transport evidence from an enrolled peer key fingerprint. - pub const fn from_enrolled_peer( - zone: d2b_contracts_zone_session::v3::zone_routing::ZonePath, - static_key_fingerprint: [u8; 32], - ) -> Self { - Self::from_observed_static_key(zone, static_key_fingerprint) - } - /// Borrow the exact Zone route identity established by the adapter. pub const fn zone(&self) -> &d2b_contracts_zone_session::v3::zone_routing::ZonePath { &self.zone @@ -351,11 +340,6 @@ impl ZoneSocketConnector { pub fn verify_session_pin(&self, pin: &ZoneSessionPin) -> Result<(), ClientError> { self.verify_peer(pin.peer()) } - - /// Return the endpoint identity pinned for the local Zone runtime. - pub fn local_daemon_endpoint_identity(&self) -> ZonePeerIdentity { - self.expected_peer.clone() - } } /// One authenticated Zone session supplied by the session adapter. @@ -624,30 +608,6 @@ where R: TargetResolver, W: WallClock, { - /// Mint the controller-scoped collection query used by the existing - /// Resource API route. The lease supplies the non-widenable assignment - /// filter; callers can only narrow its ResourceType/name selectors. - pub fn scoped_query( - &self, - lease: &ResourceClientLease, - resource_types: Vec, - resource_names: Vec, - filters: Vec, - ) -> Result { - lease.query(resource_types, resource_names, filters) - } - - /// Mint an owner-bound Process child query for the controller lease. - pub fn scoped_child_query( - &self, - lease: &ResourceClientLease, - resource_types: Vec, - resource_names: Vec, - filters: Vec, - ) -> Result { - lease.child_query(resource_types, resource_names, filters) - } - /// Resolve a target and prepare one bounded Resource call. pub fn prepare_resource_call( &self, @@ -696,38 +656,6 @@ where }) } - /// Execute one Resource call over a caller-supplied authenticated session. - /// - /// New callers should prefer [`Self::connect`] plus - /// [`Self::call_connected`], which binds the session to the route pin. - /// This lower-level form remains useful to the bus adapter, which already - /// owns the authenticated session binding. - pub async fn call_resource( - &self, - session: &S, - target: &TargetInput, - verb: ResourceVerb, - options: CallOptions, - selection: TransportSelection, - request: ResourceCallOptions<'_>, - ) -> Result - where - S: ConnectedZoneSession, - { - let (resolved, _driver) = - self.prepare_resource_call(target, verb, options, selection, request.has_attachments)?; - execute_resource_call( - &self.resource, - session, - &resolved, - verb, - _driver, - request, - None, - ) - .await - } - /// Execute a typed call over a handle whose authenticated route pin was /// checked by [`Self::connect`]. /// From 749bbdc34ff91a02ec08bac9a611b1cf937e845a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:17 -0700 Subject: [PATCH 411/726] d2b-resource-api: type scoped query method and drop dead reachability surface --- packages/d2b-bus/src/router.rs | 12 ++++-- packages/d2b-resource-api/src/adapter.rs | 50 ++++++++++++++---------- packages/d2b-resource-api/src/lib.rs | 6 +-- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/packages/d2b-bus/src/router.rs b/packages/d2b-bus/src/router.rs index 7ef594559..4951584fd 100644 --- a/packages/d2b-bus/src/router.rs +++ b/packages/d2b-bus/src/router.rs @@ -2930,9 +2930,13 @@ impl crate::registry::BusEndpoint for ComponentEndpoint { let mut outbound_frame = request.payload().to_vec(); rewrite_ttrpc_stream_id(&mut outbound_frame, internal_stream_id) .map_err(|_| EndpointError::Rejected)?; - if let Some((query, watch)) = match request.resource_call() { - Some(ResourceCall::List(query)) if query.scope().is_some() => Some((query, false)), - Some(ResourceCall::Watch(query)) if query.scope().is_some() => Some((query, true)), + if let Some((query, method)) = match request.resource_call() { + Some(ResourceCall::List(query)) if query.scope().is_some() => { + Some((query, d2b_resource_api::ScopedQueryMethod::List)) + } + Some(ResourceCall::Watch(query)) if query.scope().is_some() => { + Some((query, d2b_resource_api::ScopedQueryMethod::Watch)) + } _ => None, } { let filters = query @@ -2948,7 +2952,7 @@ impl crate::registry::BusEndpoint for ComponentEndpoint { query.resource_types(), query.resource_names(), &filters, - watch, + method, ) .map_err(|_| EndpointError::Rejected)?; } diff --git a/packages/d2b-resource-api/src/adapter.rs b/packages/d2b-resource-api/src/adapter.rs index 3c720cef9..62ff99950 100644 --- a/packages/d2b-resource-api/src/adapter.rs +++ b/packages/d2b-resource-api/src/adapter.rs @@ -120,6 +120,15 @@ pub fn attach_scoped_commit_frame( Ok(result) } +/// The query method a scoped frame must carry. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ScopedQueryMethod { + /// A List selector. + List, + /// A Watch selector. + Watch, +} + /// Attach an admitted List or Watch selector to the existing ttrpc request. /// /// The selector inputs are transport-neutral so the resource API does not @@ -136,7 +145,7 @@ pub fn attach_scoped_query_frame( resource_types: &[ResourceTypeName], resource_names: &[ResourceName], filters: &[StoreFilter], - watch: bool, + method: ScopedQueryMethod, ) -> Result, ScopedQueryFrameError> { let header_bytes: [u8; MESSAGE_HEADER_LENGTH] = frame .get(..MESSAGE_HEADER_LENGTH) @@ -153,7 +162,10 @@ pub fn attach_scoped_query_frame( } let mut rpc = TtrpcRequest::parse_from_bytes(&frame[MESSAGE_HEADER_LENGTH..]) .map_err(|_| ScopedQueryFrameError::InvalidRequest)?; - let expected_method = if watch { "Watch" } else { "List" }; + let expected_method = match method { + ScopedQueryMethod::List => "List", + ScopedQueryMethod::Watch => "Watch", + }; if rpc.service != "d2b.resource.v3.ResourceService" || rpc.method != expected_method { return Err(ScopedQueryFrameError::InvalidRequest); } @@ -179,7 +191,7 @@ pub fn attach_scoped_query_frame( .iter() .map(|resource_type| resource_type.as_str().to_owned()) .collect(); - if watch { + if matches!(method, ScopedQueryMethod::Watch) { let mut request = wire::WatchRequest::parse_from_bytes(&rpc.payload) .map_err(|_| ScopedQueryFrameError::InvalidRequest)?; request.resource_types = resource_types; @@ -267,15 +279,6 @@ impl core::fmt::Display for AdapterBindingError { impl std::error::Error for AdapterBindingError {} -/// Current production reachability of the resource service. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ResourceApiReachability { - RegisteredOnAuthenticatedComponentSession, -} - -pub const RESOURCE_API_REACHABILITY: ResourceApiReachability = - ResourceApiReachability::RegisteredOnAuthenticatedComponentSession; - /// Session-scoped dispatcher registered on an authenticated Resource server. pub struct ResourceBusAdapter { service: Arc>, @@ -646,8 +649,11 @@ mod tests { values: vec![owner_uid.as_str().to_owned()], }]; - for (method, watch) in [("List", false), ("Watch", true)] { - let payload = if watch { + for (method, query_method) in [ + ("List", ScopedQueryMethod::List), + ("Watch", ScopedQueryMethod::Watch), + ] { + let payload = if matches!(query_method, ScopedQueryMethod::Watch) { let mut request = wire::WatchRequest::new(); request.resource_types.push("Host".to_owned()); request.filters.push(wire::ListFilter { @@ -678,10 +684,16 @@ mod tests { frame.extend_from_slice(&Vec::from(header)); frame.extend_from_slice(&body); - let rewritten = - attach_scoped_query_frame(&frame, &resource_types, &[], &filters, watch).unwrap(); + let rewritten = attach_scoped_query_frame( + &frame, + &resource_types, + &[], + &filters, + query_method, + ) + .unwrap(); let rpc = TtrpcRequest::parse_from_bytes(&rewritten[MESSAGE_HEADER_LENGTH..]).unwrap(); - if watch { + if matches!(query_method, ScopedQueryMethod::Watch) { let request = wire::WatchRequest::parse_from_bytes(&rpc.payload).unwrap(); assert_eq!( request.resource_types, @@ -1226,10 +1238,6 @@ mod tests { #[test] fn authenticated_service_map_contains_the_exact_thirteen_method_surface() { - assert_eq!( - RESOURCE_API_REACHABILITY, - ResourceApiReachability::RegisteredOnAuthenticatedComponentSession - ); let services = denied_adapter().ttrpc_services(); assert_eq!(services.len(), 1); let methods = &services["d2b.resource.v3.ResourceService"].methods; diff --git a/packages/d2b-resource-api/src/lib.rs b/packages/d2b-resource-api/src/lib.rs index 4d571073c..ad2cf8a75 100644 --- a/packages/d2b-resource-api/src/lib.rs +++ b/packages/d2b-resource-api/src/lib.rs @@ -16,9 +16,9 @@ mod store; pub mod watch; pub use adapter::{ - AdapterBindingError, RESOURCE_API_REACHABILITY, ResourceApiReachability, ResourceBusAdapter, - ScopedCommitFrameError, ScopedQueryFrameError, attach_scoped_commit_frame, - attach_scoped_query_frame, decode_scoped_commit_request, reject_scoped_commit_frame, + AdapterBindingError, ResourceBusAdapter, ScopedCommitFrameError, ScopedQueryFrameError, + ScopedQueryMethod, attach_scoped_commit_frame, attach_scoped_query_frame, + decode_scoped_commit_request, reject_scoped_commit_frame, }; pub use admission::{AdmissionError, AdmittedMutation}; pub use protobuf; From 7917598f6147727eca23a2935fefa4a9ac6a5409 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:17 -0700 Subject: [PATCH 412/726] d2b-audit: classify export hash breaks without error text --- packages/d2b-audit/src/export.rs | 11 +++------- packages/d2b-audit/src/record_types.rs | 30 ++++++++++++++++++++------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/packages/d2b-audit/src/export.rs b/packages/d2b-audit/src/export.rs index 12f845eaf..14144631a 100644 --- a/packages/d2b-audit/src/export.rs +++ b/packages/d2b-audit/src/export.rs @@ -189,7 +189,7 @@ pub fn export_segments_range( continue; } }; - match serde_json::from_str::(&line) { + match AuditRecord::parse_unverified(&line) { Ok(record) if chain_valid && record.verify(&previous).is_ok() => { previous = record.record_hash().clone(); if in_range { @@ -231,16 +231,11 @@ pub fn export_segments_range( sequence = sequence.saturating_add(1); } } - Err(error) => { + Err(_) => { if in_range { let error = ExportLine::Error { sequence, - error_code: if error.to_string().contains("audit-record-hash-mismatch") - { - "hash-break" - } else { - "record-invalid" - }, + error_code: "record-invalid", }; let size = error.to_json().len().saturating_add(1); if lines.len() >= MAX_EXPORT_RECORDS diff --git a/packages/d2b-audit/src/record_types.rs b/packages/d2b-audit/src/record_types.rs index e88bdb9b4..96ed7c3c1 100644 --- a/packages/d2b-audit/src/record_types.rs +++ b/packages/d2b-audit/src/record_types.rs @@ -794,12 +794,19 @@ impl Serialize for AuditRecord { } } -impl<'de> Deserialize<'de> for AuditRecord { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let value = serde_json::Value::deserialize(deserializer)?; +impl AuditRecord { + /// Parse one record line into its wire shape without re-verifying the + /// record hash. + /// + /// The [`Deserialize`] admission gate re-verifies the hash on every read; + /// this companion parse runs the same envelope and field checks so a + /// caller can tell a chain break from a malformed line before running + /// [`AuditRecord::verify`]. + pub(crate) fn parse_unverified(line: &str) -> Result { + Self::from_wire_value(serde_json::from_str(line)?) + } + + pub(crate) fn from_wire_value(value: serde_json::Value) -> Result { let object = value .as_object() .ok_or_else(|| serde::de::Error::custom("audit-record-not-object"))?; @@ -913,6 +920,17 @@ impl<'de> Deserialize<'de> for AuditRecord { record_hash, fields, }; + Ok(record) + } +} + +impl<'de> Deserialize<'de> for AuditRecord { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let record = Self::from_wire_value(serde_json::Value::deserialize(deserializer)?) + .map_err(serde::de::Error::custom)?; if record .computed_record_hash() .map_err(serde::de::Error::custom)? From 45160a4e1ae37b842fa2f35deec6b3a2b4552979 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:18 -0700 Subject: [PATCH 413/726] xtask: deny unknown fields on the delivery snapshot view --- packages/xtask/src/delivery/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/xtask/src/delivery/mod.rs b/packages/xtask/src/delivery/mod.rs index aed87edc5..4df1452c7 100644 --- a/packages/xtask/src/delivery/mod.rs +++ b/packages/xtask/src/delivery/mod.rs @@ -44,6 +44,7 @@ pub use storage::{CandidateDir, StateRoot}; /// Reader view of the immutable candidate snapshot shared by delivery stages. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] pub struct SnapshotView { pub artifact_kind: String, pub schema_version: u32, From 637d6662768e716bc449cc30b07b34c616c3eec9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:22 -0700 Subject: [PATCH 414/726] d2b-audit: type the discardable checkpoint errors --- packages/d2b-audit/src/segment.rs | 55 +++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/packages/d2b-audit/src/segment.rs b/packages/d2b-audit/src/segment.rs index 98e81c00d..be83823b3 100644 --- a/packages/d2b-audit/src/segment.rs +++ b/packages/d2b-audit/src/segment.rs @@ -635,6 +635,35 @@ struct RetentionSegment { tail: AuditHash, } +/// Typed failure class for a checkpoint the retention path may discard. +/// +/// The scratch checkpoint is advisory: a malformed, oversized, or +/// unverifiable staged file is thrown away on restart instead of failing +/// retention. The class rides inside the `io::Error` payload so the +/// discard decision matches the type, not the error text, while the +/// stable code strings stay on the public boundary. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum CheckpointReadError { + /// The checkpoint file exceeded the size bound. + Limit, + /// The checkpoint payload did not parse. + Invalid, + /// The checkpoint did not verify against its chain. + Unverifiable, +} + +impl std::fmt::Display for CheckpointReadError { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(match self { + Self::Limit => "audit-retention-checkpoint-limit", + Self::Invalid => "audit-retention-checkpoint-invalid", + Self::Unverifiable => "audit-retention-checkpoint-unverifiable", + }) + } +} + +impl std::error::Error for CheckpointReadError {} + #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn read_checkpoint_file(path: &Path) -> io::Result> { let metadata = match fs::symlink_metadata(path) { @@ -648,12 +677,12 @@ fn read_checkpoint_file(path: &Path) -> io::Result> .custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW) .open(path)?; if file.metadata()?.len() > 1024 * 1024 { - return Err(io::Error::other("audit-retention-checkpoint-limit")); + return Err(io::Error::other(CheckpointReadError::Limit)); } let mut bytes = Vec::new(); file.read_to_end(&mut bytes)?; let checkpoint = serde_json::from_slice(&bytes) - .map_err(|_| io::Error::other("audit-retention-checkpoint-invalid"))?; + .map_err(|_| io::Error::other(CheckpointReadError::Invalid))?; Ok(Some(checkpoint)) } @@ -718,12 +747,10 @@ fn read_checkpoint_with_directory( } fn is_discardable_checkpoint_scratch_error(error: &io::Error) -> bool { - matches!( - error.to_string().as_str(), - "audit-retention-checkpoint-invalid" - | "audit-retention-checkpoint-limit" - | "audit-retention-checkpoint-unverifiable" - ) + error + .get_ref() + .and_then(|inner| inner.downcast_ref::()) + .is_some() } #[allow(clippy::disallowed_methods, reason = "synchronous path")] @@ -748,18 +775,18 @@ fn validate_checkpoint(checkpoint: &RetentionCheckpoint) -> io::Result<()> { || !checkpoint.segments.is_empty() || checkpoint.phase.is_some() { - return Err(io::Error::other("audit-retention-checkpoint-unverifiable")); + return Err(io::Error::other(CheckpointReadError::Unverifiable)); } return Ok(()); } let Some(start_anchor) = checkpoint.start_anchor.as_ref() else { - return Err(io::Error::other("audit-retention-checkpoint-unverifiable")); + return Err(io::Error::other(CheckpointReadError::Unverifiable)); }; let Some(phase) = checkpoint.phase else { - return Err(io::Error::other("audit-retention-checkpoint-unverifiable")); + return Err(io::Error::other(CheckpointReadError::Unverifiable)); }; if checkpoint.segments.is_empty() || checkpoint.segments.len() > MAX_SEGMENT_SCAN_ENTRIES { - return Err(io::Error::other("audit-retention-checkpoint-unverifiable")); + return Err(io::Error::other(CheckpointReadError::Unverifiable)); } let mut previous_name = None; let mut previous = start_anchor.clone(); @@ -768,13 +795,13 @@ fn validate_checkpoint(checkpoint: &RetentionCheckpoint) -> io::Result<()> { || previous_name.is_some_and(|name| name >= segment.name.as_str()) || segment.previous != previous { - return Err(io::Error::other("audit-retention-checkpoint-unverifiable")); + return Err(io::Error::other(CheckpointReadError::Unverifiable)); } previous_name = Some(segment.name.as_str()); previous = segment.tail.clone(); } if checkpoint.anchor != previous { - return Err(io::Error::other("audit-retention-checkpoint-unverifiable")); + return Err(io::Error::other(CheckpointReadError::Unverifiable)); } match phase { RetentionCheckpointPhase::Prepared | RetentionCheckpointPhase::Deleting => Ok(()), From 938c7bbfa54e6549ad4e3c277d3341b85d212397 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:58:53 -0700 Subject: [PATCH 415/726] audit: fold the cli and resource-api slice --- .../2026-09-24-rust-skills-audit/ledger.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index bf26a2ce7..bf9db448e 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -285,7 +285,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | | `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_op` | | | | `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | escalated | U1 | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | wave 0 applied the panicking constructor member (RS-0516); the five remaining provider-crate zone/key_ref member sites are the family wave's | U5 | -| `RS-0263` | `type` | `d2b` | low | actionable | leaf | | | | `context.rs:713, context.rs:2751, context.rs:801` | | | +| `RS-0263` | `type` | `d2b` | low | actionable | leaf | applied | U3 | f98ad4f82 | packages/d2b/src/context.rs | ZoneContext now stores ZoneId; zone_ref/zone_name built from it; validate_zone_name deleted; discover double validation removed; from_socket takes ZoneId directly. | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | | `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | | | | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | | | | `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | already-fixed | U3 | | `packages/d2b-broker/src/ops/media.rs:889-892` | Re-verified at HEAD: QmpAttachCleanup already models its four-step rollback as an ordered typed step list (steps: Vec with QmpAttachStep enum, media.rs:889-892), not four bools. Already | | @@ -341,7 +341,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telem` | | | | `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-p` | | | | `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/identity.rs:72-88, src/identity.rs:146-150` | | | -| `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | | | | `adapter.rs:124` | | | +| `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | watch: bool replaced with pub enum ScopedQueryMethod { List, Watch }; bus router call site and adapter test updated. | | | `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs` | | | | `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/scheduler.rs | channel() now returns Result; the constructor-prevented NamedStream-without-stream combination yields InvalidChannel instead of a silent SESSION_CONTROL misroute. Census re-run: only caller | | | `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1702, engine.rs:1295, engine.rs:31` | | | @@ -358,16 +358,16 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | d1c5c44d9 | packages/d2bd-runtime/src/typed_shell_targets.rs | typed-shell target key becomes a named struct with a constructor; the three composition.rs cache call sites migrate to it | | | `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | | `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | -| `RS-0314` | `type` | `xtask` | medium | actionable | leaf | | | | `packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557` | | | +| `RS-0314` | `type` | `xtask` | medium | actionable | leaf | applied | U3 | 0b767225a | packages/xtask/src/inventory.rs | Deleted the private copy and both call sites plus the test now use crate::delivery::model::validate_repo_relative_path(Path::new(...)); stricter empty check retained. | | | `RS-0313` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 1d692db3d | packages/xtask/src/provider_crate_policy.rs | FamilyKnowledgeSignal gains typed count: Option; ServerState site fills it and drops the serialized-count text; renderer matches class without the parse;the ratchet JSON stays byte-identical (t | | | `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option Date: Fri, 25 Sep 2026 09:58:56 -0700 Subject: [PATCH 416/726] device-security-key: private relay modules with root re-exports --- packages/d2b-provider-device-security-key/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-device-security-key/src/lib.rs b/packages/d2b-provider-device-security-key/src/lib.rs index 51f07bd8e..028eab54b 100644 --- a/packages/d2b-provider-device-security-key/src/lib.rs +++ b/packages/d2b-provider-device-security-key/src/lib.rs @@ -13,7 +13,7 @@ pub mod effects_service; pub mod facets; mod lease; mod process; -pub mod relay; +mod relay; mod relay_service; pub mod vocabulary; From c28489ccca4d90a70e7c62fb5edc621f4d9dce02 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:00 -0700 Subject: [PATCH 417/726] zone: private zone_status module with named re-exports --- packages/d2b-provider-zone/src/lib.rs | 6 ++++-- packages/d2b-provider-zone/tests/zone_status.rs | 2 +- packages/d2bd/src/resource_runtime.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-zone/src/lib.rs b/packages/d2b-provider-zone/src/lib.rs index 19ccb0a89..df014c850 100644 --- a/packages/d2b-provider-zone/src/lib.rs +++ b/packages/d2b-provider-zone/src/lib.rs @@ -14,8 +14,10 @@ mod driver; -pub mod zone_status; +mod zone_status; pub use driver::zone_descriptor; -pub use zone_status::*; +pub use zone_status::{ + SystemCoreStatusEmitter, ZoneRuntimeMetadata, ZoneStatusInput, ZoneStatusProjectionError, +}; diff --git a/packages/d2b-provider-zone/tests/zone_status.rs b/packages/d2b-provider-zone/tests/zone_status.rs index fa9e9f077..ff806118b 100644 --- a/packages/d2b-provider-zone/tests/zone_status.rs +++ b/packages/d2b-provider-zone/tests/zone_status.rs @@ -1,6 +1,6 @@ use d2b_contracts_resource::v3::{ResourcePhase, Timestamp}; use d2b_contracts_zone_session::v3::{ZoneHandlerName, ZoneHandlerPhase, ZoneHandlerStatus}; -use d2b_provider_zone::zone_status::{ +use d2b_provider_zone::{ SystemCoreStatusEmitter, ZoneRuntimeMetadata, ZoneStatusInput, }; diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 4ac271387..5569c1907 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -60,7 +60,7 @@ use d2b_core_controller::main::{ CoreProcess, RecoverySnapshot, RuntimeReadiness as CoreRuntimeReadiness, StartupStage, }; use d2b_core_controller::migration::LegacyTpmMigrationDecision; -use d2b_provider_zone::zone_status::{ +use d2b_provider_zone::{ SystemCoreStatusEmitter, ZoneRuntimeMetadata, ZoneStatusInput, }; use d2b_provider_clipboard_wayland::Policy as ClipboardPolicy; From b9fc346fce3c7082e1e462ae46de805ab75f10e9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:04 -0700 Subject: [PATCH 418/726] sk-frontend: private modules with root re-exports --- packages/d2b-sk-frontend/src/lib.rs | 9 +++++---- packages/d2b-sk-frontend/src/main.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/d2b-sk-frontend/src/lib.rs b/packages/d2b-sk-frontend/src/lib.rs index 869025eac..d9b1dc23a 100644 --- a/packages/d2b-sk-frontend/src/lib.rs +++ b/packages/d2b-sk-frontend/src/lib.rs @@ -19,11 +19,12 @@ #![deny(missing_docs)] #![forbid(unsafe_code)] -pub mod agent; -pub mod config; -pub mod link; -pub mod uhid; +mod agent; +mod config; +mod link; +mod uhid; pub use agent::{HidDevice, SecurityKeyFrontend}; pub use config::{Config, PlacementConfig}; pub use link::VsockAllocatorLink; +pub use uhid::{UhidDevice, UhidEvent}; diff --git a/packages/d2b-sk-frontend/src/main.rs b/packages/d2b-sk-frontend/src/main.rs index 20a782fcc..dafd54a39 100644 --- a/packages/d2b-sk-frontend/src/main.rs +++ b/packages/d2b-sk-frontend/src/main.rs @@ -38,7 +38,7 @@ use std::fmt::Display; use std::sync::Arc; use d2b_provider_toolkit::{AllocatorEnrollment, run_guest}; -use d2b_sk_frontend::{Config, SecurityKeyFrontend, VsockAllocatorLink, uhid::UhidDevice}; +use d2b_sk_frontend::{Config, SecurityKeyFrontend, UhidDevice, VsockAllocatorLink}; fn exit_on_error(result: Result) -> T { match result { From 4b559475aa320cd72fa9321fd7979170f28ff5f1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:08 -0700 Subject: [PATCH 419/726] audit: private generated module with catalog re-export --- packages/d2b-audit/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/d2b-audit/src/lib.rs b/packages/d2b-audit/src/lib.rs index cf2b906e1..c1ccaaec0 100644 --- a/packages/d2b-audit/src/lib.rs +++ b/packages/d2b-audit/src/lib.rs @@ -4,7 +4,8 @@ pub mod evidence_chain; pub mod export; -pub mod generated; +mod generated; +pub use generated::audit_catalog::admits_mutation_verb; pub mod hash_chain; pub mod operation; pub mod rate_limit; From 1ce473a70238d66df6e38f126ff675b1e4580959 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:12 -0700 Subject: [PATCH 420/726] credential: typed zone identity in driver args --- .../d2b-provider-credential/src/driver.rs | 23 ++++++++++--------- .../tests/registration.rs | 4 ++-- packages/d2bd/src/resource_plane_v3.rs | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/d2b-provider-credential/src/driver.rs b/packages/d2b-provider-credential/src/driver.rs index 8ea9c21d0..0a35f911e 100644 --- a/packages/d2b-provider-credential/src/driver.rs +++ b/packages/d2b-provider-credential/src/driver.rs @@ -43,7 +43,7 @@ use d2b_contracts_provider::v3::credential::{ use d2b_contracts_provider::v3::credential_controller::CredentialProviderKind; use d2b_contracts_resource::v3::{ CanonicalJsonObject, CanonicalJsonValue, ControllerGeneration, DesiredLifecycle, ResourceRef, - ResourceSpec, ResourceUid, + ResourceSpec, ResourceUid, ZoneId, execution_policy::{BoundedToken, BudgetSpec, DurationMs, ExecutionDomain}, identity::ReconnectGeneration, process::{ @@ -292,7 +292,7 @@ pub trait CredentialDriverEffects: Send + Sync + 'static { /// and the zone-authority controller generation (KTD7). pub struct CredentialDriverArgs { /// The zone the plane serves. - pub zone: String, + pub zone: ZoneId, /// Zone controller generation folded into every revocation request /// (old `policy_snapshot.controller_generation`). pub controller_generation: ControllerGeneration, @@ -340,7 +340,7 @@ impl ResourceDriverFactory for CredentialDriverFactory { /// One Credential resource's driver. pub struct CredentialDriver { - zone: String, + zone: ZoneId, controller_generation: ControllerGeneration, effects: Arc, } @@ -453,11 +453,12 @@ impl CredentialDriver { "Guest" => PlacementBinding::GuestAgent, _ => return Err(invalid()), }; - let zone_ref = format!("Zone/{}", self.zone); + let zone_ref = ResourceRef::parse(&format!("Zone/{}", self.zone.as_str())) + .expect("a validated zone id renders a canonical zone reference"); let placement = d2b_provider_credential_managed_identity::ManagedIdentityPlacement::new( placement, execution_ref.clone(), - ResourceRef::parse(&zone_ref).map_err(|_| invalid())?, + zone_ref, ) .map_err(|_| invalid())?; let controller = @@ -782,7 +783,7 @@ impl ResourceDriver for CredentialDriver { return Ok(RecoveryOutcome::Missing); } let agent_ref = self.agent_ref(ctx, DriverOp::Recover)?; - let agent_key = ResourceKey::new(&self.zone, PROCESS_TYPE_NAME, agent_ref.name().as_str()); + let agent_key = ResourceKey::new(self.zone.as_str(), PROCESS_TYPE_NAME, agent_ref.name().as_str()); let present = self .owned_processes(ctx, DriverOp::Recover) .await? @@ -841,7 +842,7 @@ impl ResourceDriver for CredentialDriver { } let child = self.agent_child(ctx, &spec, &provider_ref, &facts, DriverOp::Reconcile)?; let agent_ref = self.agent_ref(ctx, DriverOp::Reconcile)?; - let agent_key = ResourceKey::new(&self.zone, PROCESS_TYPE_NAME, agent_ref.name().as_str()); + let agent_key = ResourceKey::new(self.zone.as_str(), PROCESS_TYPE_NAME, agent_ref.name().as_str()); let owned = self.owned_processes(ctx, DriverOp::Reconcile).await?; match owned.iter().find(|row| row.key == agent_key) { Some(row) if row.deleting => { @@ -1037,7 +1038,7 @@ mod tests { use d2b_contracts_provider::v3::credential::CredentialLeaseState; use d2b_contracts_resource::v3::identity::ReconnectGeneration; use d2b_contracts_resource::v3::process::ProcessSpec; - use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ResourceSpec}; + use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ResourceSpec, ZoneId}; use d2b_resource_runtime::context::{ ChildEnsure, ManagerEndpoint, RequeueId, RequeueScheduler, ResourceContext, WatchId, WatchRegistration, @@ -1267,7 +1268,7 @@ mod tests { // seam from the facets (the factory), tests drive the behavior // directly over the recording double. CredentialDriver { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").unwrap(), controller_generation: ControllerGeneration::new(1).unwrap(), effects, } @@ -1285,7 +1286,7 @@ mod tests { #[test] fn factory_registers_only_the_credential_resource_type() { let factory = CredentialDriverFactory::new(CredentialDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").unwrap(), controller_generation: ControllerGeneration::new(1).unwrap(), facets: facets(), }); @@ -1297,7 +1298,7 @@ mod tests { #[tokio::test] async fn factory_created_driver_validates_through_the_erased_boundary() { let factory = CredentialDriverFactory::new(CredentialDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").unwrap(), controller_generation: ControllerGeneration::new(1).unwrap(), facets: facets(), }); diff --git a/packages/d2b-provider-credential/tests/registration.rs b/packages/d2b-provider-credential/tests/registration.rs index c21e4cf6f..1faf6f928 100644 --- a/packages/d2b-provider-credential/tests/registration.rs +++ b/packages/d2b-provider-credential/tests/registration.rs @@ -4,7 +4,7 @@ use std::sync::Arc; -use d2b_contracts_resource::v3::ResourceRef; +use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; use d2b_provider_credential::{ CREDENTIAL_EFFECTS_SERVICE, CREDENTIAL_TYPE_NAME, CredentialDependencyFacts, CredentialDriverArgs, CredentialEffectFacets, CredentialLeaseFacts, CredentialRuntime, @@ -43,7 +43,7 @@ impl CredentialRuntime for UnusedRuntime { fn descriptor() -> d2b_resource_types::DriverDescriptor { credential_descriptor(CredentialDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").unwrap(), controller_generation: d2b_contracts_resource::v3::ControllerGeneration::new(1) .expect("controller generation"), facets: CredentialEffectFacets { diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index bb7a56131..9c4585441 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -2948,7 +2948,7 @@ impl ResourcePlaneV3 { // the daemon-supplied facet set; no externally built port // appears at this construction site (R2). "credential" => vec![credential_descriptor(CredentialDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), controller_generation: inputs.authority.controller_generation, facets: inputs.credential_facets.clone(), })], From c61b0e5b5f07294242c989bed1922b04b3f9ae06 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:15 -0700 Subject: [PATCH 421/726] provider: drop zero-caller factory constructors --- packages/d2b-provider-provider/src/driver.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/d2b-provider-provider/src/driver.rs b/packages/d2b-provider-provider/src/driver.rs index f861b953f..37ae56631 100644 --- a/packages/d2b-provider-provider/src/driver.rs +++ b/packages/d2b-provider-provider/src/driver.rs @@ -211,11 +211,6 @@ pub struct ProviderDriverFactory { } impl ProviderDriverFactory { - /// Construct over the fail-closed effects default (unit fixtures). - pub fn new() -> Self { - Self::with_effects(Arc::new(FailClosedProviderDriverEffects)) - } - /// Construct over an injected port. The plane composition wires the live /// controller-session seam here. pub fn with_effects(effects: Arc) -> Self { @@ -226,12 +221,6 @@ impl ProviderDriverFactory { } } -impl Default for ProviderDriverFactory { - fn default() -> Self { - Self::new() - } -} - #[async_trait] impl ResourceDriverFactory for ProviderDriverFactory { fn resource_types(&self) -> &[ResourceTypeName] { From 9e035c04f71e75b5a94513031efca99f86c15edf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:19 -0700 Subject: [PATCH 422/726] broker-composition: typed cargo metadata surface and audit errors --- Cargo.lock | 1 + packages/d2b-broker-composition/Cargo.toml | 1 + .../src/dependency_surface.rs | 182 ++++++++++++------ packages/d2b-broker-composition/src/seam.rs | 49 ++++- 4 files changed, 164 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f023ce55f..d0d4a74cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -846,6 +846,7 @@ dependencies = [ "d2b-broker", "d2b-broker-fixture-handlers", "regex", + "serde", "serde_json", "tokio", "tracing-subscriber", diff --git a/packages/d2b-broker-composition/Cargo.toml b/packages/d2b-broker-composition/Cargo.toml index 768b4357e..f80a1faf4 100644 --- a/packages/d2b-broker-composition/Cargo.toml +++ b/packages/d2b-broker-composition/Cargo.toml @@ -58,6 +58,7 @@ d2b-broker-fixture-handlers = { path = "../d2b-broker-fixture-handlers", version # The dependency-surface audit parses `cargo metadata` output and runs the # lexical source probes. regex = "1" +serde = { workspace = true } serde_json = { workspace = true } tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] } diff --git a/packages/d2b-broker-composition/src/dependency_surface.rs b/packages/d2b-broker-composition/src/dependency_surface.rs index 63e77bc67..47077263a 100644 --- a/packages/d2b-broker-composition/src/dependency_surface.rs +++ b/packages/d2b-broker-composition/src/dependency_surface.rs @@ -212,6 +212,81 @@ fn collect_rs_files(directory: &Path, files: &mut Vec) { } } +/// Why the dependency-surface audit could not produce a report. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SurfaceAuditError { + /// The workspace root could not be located in this environment. + WorkspaceUnavailable { + /// The audited crate. + crate_name: String, + }, + /// `cargo metadata` could not be run or failed. + CargoFailed { + /// The underlying failure. + detail: String, + }, + /// The metadata output was invalid or did not name the crate. + InvalidMetadata { + /// The underlying failure. + detail: String, + }, +} + +impl std::fmt::Display for SurfaceAuditError { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::WorkspaceUnavailable { crate_name } => write!( + formatter, + "workspace root unavailable for {crate_name}" + ), + Self::CargoFailed { detail } => formatter.write_str(detail), + Self::InvalidMetadata { detail } => formatter.write_str(detail), + } + } +} + +impl std::error::Error for SurfaceAuditError {} + +/// The subset of `cargo metadata --format-version 1` output the surface +/// audit consumes. +#[derive(serde::Deserialize)] +struct CargoMetadata { + packages: Vec, + resolve: Resolve, +} + +#[derive(serde::Deserialize)] +struct Package { + name: String, + id: String, + manifest_path: String, +} + +#[derive(serde::Deserialize)] +struct Resolve { + nodes: Vec, +} + +#[derive(serde::Deserialize)] +struct ResolveNode { + id: String, + #[serde(default)] + deps: Vec, +} + +#[derive(serde::Deserialize)] +struct ResolveDep { + pkg: String, + #[serde(default)] + dep_kinds: Vec, +} + +#[derive(serde::Deserialize)] +struct DepKind { + kind: Option, + target: Option, +} + /// Run the full audit of one handler crate against the workspace's /// `cargo metadata`: its transitive dependency tree (dev-only edges and /// platform-gated edges excluded) plus its own source surface. @@ -221,9 +296,11 @@ fn collect_rs_files(directory: &Path, files: &mut Vec) { /// never as a pass: the registration-time probe and the CI gate own the /// pass/fail decision, and a skipped full audit is reported, not silently /// green. -pub fn audit_crate(crate_name: &str) -> Result { +pub fn audit_crate(crate_name: &str) -> Result { let Some(root) = workspace_root() else { - return Err(format!("workspace root unavailable for {crate_name}")); + return Err(SurfaceAuditError::WorkspaceUnavailable { + crate_name: crate_name.to_owned(), + }); }; let metadata = run_cargo_metadata(&root)?; // The delta semantics: only dependencies the handler's closure adds @@ -296,7 +373,7 @@ pub fn audit_crate(crate_name: &str) -> Result { Ok(report) } -fn run_cargo_metadata(root: &Path) -> Result { +fn run_cargo_metadata(root: &Path) -> Result { let manifest = root.join("Cargo.toml"); let output = Command::new(std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into())) .arg("metadata") @@ -305,44 +382,42 @@ fn run_cargo_metadata(root: &Path) -> Result { .arg("--manifest-path") .arg(&manifest) .output() - .map_err(|error| format!("cannot run cargo metadata: {error}"))?; + .map_err(|error| SurfaceAuditError::CargoFailed { + detail: format!("cannot run cargo metadata: {error}"), + })?; if !output.status.success() { - return Err(format!( - "cargo metadata failed: {}", - String::from_utf8_lossy(&output.stderr) - )); + return Err(SurfaceAuditError::CargoFailed { + detail: format!( + "cargo metadata failed: {}", + String::from_utf8_lossy(&output.stderr) + ), + }); } - serde_json::from_slice(&output.stdout) - .map_err(|error| format!("cargo metadata produced invalid JSON: {error}")) + serde_json::from_slice(&output.stdout).map_err(|error| SurfaceAuditError::InvalidMetadata { + detail: format!("cargo metadata produced invalid JSON: {error}"), + }) } /// The transitive dependency tree of one package: its own node plus every /// package reachable over non-dev, non-target-gated edges. fn dependency_tree( - metadata: &serde_json::Value, + metadata: &CargoMetadata, crate_name: &str, -) -> Result, String> { - let packages = metadata - .get("packages") - .and_then(serde_json::Value::as_array) - .ok_or_else(|| "cargo metadata has no package array".to_owned())?; - let root_id = packages +) -> Result, SurfaceAuditError> { + let root_id = metadata + .packages .iter() - .find(|package| package.get("name").and_then(serde_json::Value::as_str) == Some(crate_name)) - .and_then(|package| package.get("id").and_then(serde_json::Value::as_str)) - .ok_or_else(|| format!("package {crate_name} is not a workspace member"))?; - let mut nodes: std::collections::HashMap<&str, &serde_json::Value> = std::collections::HashMap::new(); - for node in metadata - .get("resolve") - .and_then(|resolve| resolve.get("nodes")) - .and_then(serde_json::Value::as_array) - .ok_or_else(|| "cargo metadata has no resolve graph".to_owned())? - { - let Some(id) = node.get("id").and_then(serde_json::Value::as_str) else { - continue; - }; - nodes.insert(id, node); - } + .find(|package| package.name == crate_name) + .map(|package| package.id.as_str()) + .ok_or_else(|| SurfaceAuditError::InvalidMetadata { + detail: format!("package {crate_name} is not a workspace member"), + })?; + let nodes: std::collections::HashMap<&str, &ResolveNode> = metadata + .resolve + .nodes + .iter() + .map(|node| (node.id.as_str(), node)) + .collect(); let mut reachable: Vec = Vec::new(); let mut queue = vec![root_id]; let mut seen = std::collections::BTreeSet::new(); @@ -357,28 +432,18 @@ fn dependency_tree( { reachable.push(owner_name.to_owned()); } - let Some(deps) = node.get("deps").and_then(serde_json::Value::as_array) else { - continue; - }; - for dep in deps { - let Some(dep_id) = dep.get("pkg").and_then(serde_json::Value::as_str) else { - continue; - }; - let Some(kinds) = dep.get("dep_kinds").and_then(serde_json::Value::as_array) else { - continue; - }; + for dep in &node.deps { // Follow the edge when any of its kinds is a normal or // build-time edge for the host target; a dev-only edge or a // platform-gated edge is not part of the production closure. - let follows = kinds.iter().any(|kind| { - let kind_name = kind.get("kind").and_then(serde_json::Value::as_str); - if kind_name == Some("dev") { + let follows = dep.dep_kinds.iter().any(|kind| { + if kind.kind.as_deref() == Some("dev") { return false; } - kind.get("target").filter(|target| !target.is_null()).is_none() + kind.target.is_none() }); if follows { - queue.push(dep_id); + queue.push(dep.pkg.as_str()); } } } @@ -386,27 +451,22 @@ fn dependency_tree( Ok(reachable) } -fn package_name_of_id<'a>(metadata: &'a serde_json::Value, id: &str) -> Option<&'a str> { +fn package_name_of_id<'a>(metadata: &'a CargoMetadata, id: &str) -> Option<&'a str> { metadata - .get("packages") - .and_then(serde_json::Value::as_array)? + .packages .iter() - .find(|package| package.get("id").and_then(serde_json::Value::as_str) == Some(id)) - .and_then(|package| package.get("name").and_then(serde_json::Value::as_str)) + .find(|package| package.id == id) + .map(|package| package.name.as_str()) } /// Whether one resolved package is a proc-macro crate, by lexical scan of /// its manifest (readable in development/CI registries). -fn is_proc_macro(metadata: &serde_json::Value, name: &str) -> bool { +fn is_proc_macro(metadata: &CargoMetadata, name: &str) -> bool { let Some(path) = metadata - .get("packages") - .and_then(serde_json::Value::as_array) - .and_then(|packages| { - packages - .iter() - .find(|package| package.get("name").and_then(serde_json::Value::as_str) == Some(name)) - }) - .and_then(|package| package.get("manifest_path").and_then(serde_json::Value::as_str)) + .packages + .iter() + .find(|package| package.name == name) + .map(|package| package.manifest_path.as_str()) else { return false; }; diff --git a/packages/d2b-broker-composition/src/seam.rs b/packages/d2b-broker-composition/src/seam.rs index fe0e2273b..62b6a17fa 100644 --- a/packages/d2b-broker-composition/src/seam.rs +++ b/packages/d2b-broker-composition/src/seam.rs @@ -187,6 +187,40 @@ pub fn register_production_handlers( register_declared_handlers(declarations) } +/// A wiring violation between the routing rule and the registered handlers. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum StartupRoutingViolation { + /// A handler is registered for an operation the routing rule refuses + /// admission to the in-broker table. + UnadmittedHandler { + /// The registered operation. + operation: String, + }, + /// A committed operation the rule admits has no registered handler. + MissingHandlers { + /// The admitted operations without handlers. + operations: Vec<&'static str>, + }, +} + +impl fmt::Display for StartupRoutingViolation { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::UnadmittedHandler { operation } => write!( + formatter, + "handler registered for {operation}, but the routing rule refuses it admission to the in-broker table" + ), + Self::MissingHandlers { operations } => write!( + formatter, + "committed operation(s) route to the in-broker leg with no registered handler: {}", + operations.join(", ") + ), + } + } +} + +impl std::error::Error for StartupRoutingViolation {} + /// The startup routing invariant. /// /// Verifies that every committed row the rule would admit in-broker has a @@ -195,23 +229,22 @@ pub fn register_production_handlers( /// gap (an admitted row with no handler, or a handler for a forwarded row) /// fails the broker closed at startup instead of surfacing as a /// per-call unregistered-handler refusal. -pub fn verify_startup_routing(registered: &[&str]) -> Result<(), String> { +pub fn verify_startup_routing(registered: &[&str]) -> Result<(), StartupRoutingViolation> { let mut admitted = crate::routing::catalog_admitted_operations(); for operation in registered { let Some(index) = admitted.iter().position(|row| *row == *operation) else { - return Err(format!( - "handler registered for {operation}, but the routing rule refuses it admission to the in-broker table" - )); + return Err(StartupRoutingViolation::UnadmittedHandler { + operation: (*operation).to_owned(), + }); }; admitted.remove(index); } if admitted.is_empty() { Ok(()) } else { - Err(format!( - "committed operation(s) route to the in-broker leg with no registered handler: {}", - admitted.join(", ") - )) + Err(StartupRoutingViolation::MissingHandlers { + operations: admitted, + }) } } From 4c3b2b909bcdf80f8df1cb4e61554f728b00230b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:22 -0700 Subject: [PATCH 423/726] audit: record the process provider red and the cargo-versus-gate pattern --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index bf9db448e..d4697b421 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -26,6 +26,9 @@ Defects the audited surfaces carry at HEAD that no corpus row claims and no wave - `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Observed at the wave-2 base. A test-only allow is the broker package owner's policy call. - (wave-1 regression, fixed on the integration branch) `cargo clippy -p d2b-bus --locked --all-targets` stopped at `use of a disallowed method std::sync::Mutex::lock` in `packages/d2b-bus/src/session/contract.rs`. The missing inline allow arrived with the wave-1 batch commit `fbf92683a`, which extracted `verify_body` out of the already-sanctioned `verify`; wave 1's Bazel clippy action did not flag the extraction, so the wave gate stayed green while plain-cargo clippy went red for `d2b-bus` and every crate depending on it. Fixed with the same sanctioned reason its four sibling functions use (`synchronous path`); `xtask check-provider-crate-layout` validates allow reasons against its sanctioned set rather than a per-site list, so no list changed and the site is not an ad-hoc allow. The broker test-helper entries below stay pre-existing and unfixed. - `cargo check -p d2b-provider-display-wayland --locked --all-targets` fails to compile the lib test with `E0599` on `AuthenticatedSessionRouteBinding::for_test` (a `test-support` cfg mismatch). Reproduced at the audit base `147a536a0` in a detached worktree, so this one is genuinely pre-existing rather than a wave regression - unlike the bus entry above, which the same check proved to be mine. +- `cargo clippy -p d2b-provider-process-systemd --locked --all-targets` reports three errors from the `#[tokio::test]` functions in `src/effects_service.rs`, whose expansion calls the denied `tokio::runtime::Runtime::block_on`. Reproduced at the audit base `147a536a0`: three errors on a pristine checkout. The owning slice also proved it independently by reverting its own change and re-running. + +Pattern across these entries: plain-cargo clippy and check go red in four places where the Bazel gate stays green, because the gate's actions do not compile the same target set - expanded `#[tokio::test]` bodies, `test-support` cfg paths, and test helpers are linted by cargo and not by the action. One of the four was a wave-1 regression and is fixed; the rest reproduce at the audit base. A worker's acceptance signal for such a crate is its lib target plus its own tests, never a new inline allow. - `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. ## Wave gates From e97b2b71d1979483eede686d19f1cea3a098e9ee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 09:59:23 -0700 Subject: [PATCH 424/726] transport-vsock: transport identity in bridge and drop events --- .../src/bridge.rs | 4 ++ .../src/service.rs | 42 ++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/packages/d2b-provider-transport-vsock/src/bridge.rs b/packages/d2b-provider-transport-vsock/src/bridge.rs index a2c47d063..e23a0cf52 100644 --- a/packages/d2b-provider-transport-vsock/src/bridge.rs +++ b/packages/d2b-provider-transport-vsock/src/bridge.rs @@ -181,6 +181,8 @@ pub async fn run_bridge( mut right: R, mut stop: watch::Receiver, stats: Arc, + endpoint_id: &crate::service::OpaqueEndpointId, + binding_id: &crate::service::OpaqueBindingId, ) -> (L, R, BridgeExit) where L: AsyncRead + AsyncWrite + Unpin, @@ -196,6 +198,8 @@ where Err(_) => { tracing::debug!( provider = "transport-vsock", + endpoint = %endpoint_id, + binding = %binding_id, "bridge copy failed with an IO error" ); BridgeExit::IoError diff --git a/packages/d2b-provider-transport-vsock/src/service.rs b/packages/d2b-provider-transport-vsock/src/service.rs index 9e1bc702e..d90676bcb 100644 --- a/packages/d2b-provider-transport-vsock/src/service.rs +++ b/packages/d2b-provider-transport-vsock/src/service.rs @@ -69,7 +69,7 @@ impl fmt::Debug for OpaqueEndpointId { impl fmt::Display for OpaqueEndpointId { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("opaque-endpoint") + formatter.write_str(&self.0) } } @@ -108,7 +108,7 @@ impl fmt::Debug for OpaqueBindingId { impl fmt::Display for OpaqueBindingId { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("opaque-binding") + formatter.write_str(&self.0) } } @@ -351,6 +351,8 @@ struct TransportEntry { phase: Arc>, exit: Arc>>, stats: Arc, + endpoint_id: OpaqueEndpointId, + binding_id: OpaqueBindingId, _permit: OwnedSemaphorePermit, } @@ -569,9 +571,18 @@ where let task_stats = Arc::clone(&stats); let task_subscribers = Arc::clone(&subscribers); let task_history = Arc::clone(&history); + let task_endpoint_id = request.endpoint_id.clone(); + let task_binding_id = request.binding_id.clone(); let task = tokio::spawn(async move { - let (effect_stream, _named_stream, reason) = - run_bridge(effect_stream, named_stream, stop, Arc::clone(&task_stats)).await; + let (effect_stream, _named_stream, reason) = run_bridge( + effect_stream, + named_stream, + stop, + Arc::clone(&task_stats), + &task_endpoint_id, + &task_binding_id, + ) + .await; let effect_result = timeout( Duration::from_millis(CLOSE_GRACE_MS), task_effect.close(effect_stream), @@ -589,6 +600,8 @@ where emit_event( &task_subscribers, &task_history, + &task_endpoint_id, + &task_binding_id, TransportEvent::Error { kind: "bridge-io", recoverable: false, @@ -602,6 +615,8 @@ where emit_event( &task_subscribers, &task_history, + &task_endpoint_id, + &task_binding_id, TransportEvent::BytesTransferred { rx_bytes, tx_bytes }, ) .await; @@ -614,11 +629,20 @@ where TransportPhase::Degraded }; if released { - emit_event(&task_subscribers, &task_history, TransportEvent::Released).await; + emit_event( + &task_subscribers, + &task_history, + &task_endpoint_id, + &task_binding_id, + TransportEvent::Released, + ) + .await; } else { emit_event( &task_subscribers, &task_history, + &task_endpoint_id, + &task_binding_id, TransportEvent::Error { kind: "close-unconfirmed", recoverable: true, @@ -639,6 +663,8 @@ where phase, exit, stats, + endpoint_id: request.endpoint_id, + binding_id: request.binding_id, _permit: permit, }, ); @@ -794,6 +820,8 @@ where { tracing::debug!( provider = "transport-vsock", + endpoint = %entry.endpoint_id, + binding = %entry.binding_id, "transport event history dropped for a full observer channel" ); } @@ -905,6 +933,8 @@ fn remaining_until(deadline: Instant) -> Duration { async fn emit_event( subscribers: &EventSubscribers, history: &Arc>>, + endpoint_id: &OpaqueEndpointId, + binding_id: &OpaqueBindingId, event: TransportEvent, ) { history.lock().await.push(event); @@ -915,6 +945,8 @@ async fn emit_event( } else if sender.try_send(event).is_err() { tracing::debug!( provider = "transport-vsock", + endpoint = %endpoint_id, + binding = %binding_id, "transport event dropped for a full or closed subscriber channel" ); false From a527632806f2a7c3502888eb50514f80ec737b50 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:00:38 -0700 Subject: [PATCH 425/726] audit: pin the broker entries to their base reproduction --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index d4697b421..9e18b81b7 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -23,13 +23,13 @@ Measured at `147a536a0` in a dedicated gates worktree before any wave-0 fix land Defects the audited surfaces carry at HEAD that no corpus row claims and no wave fixes. They are recorded here so a later reader does not mistake them for wave regressions, and they route to an ordinary review pass or the owning package owner rather than to a leaf row. -- `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Observed at the wave-2 base. A test-only allow is the broker package owner's policy call. +- `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Reproduced at the audit base `147a536a0`: one clippy error on a pristine checkout. A test-only allow is the broker package owner's policy call. - (wave-1 regression, fixed on the integration branch) `cargo clippy -p d2b-bus --locked --all-targets` stopped at `use of a disallowed method std::sync::Mutex::lock` in `packages/d2b-bus/src/session/contract.rs`. The missing inline allow arrived with the wave-1 batch commit `fbf92683a`, which extracted `verify_body` out of the already-sanctioned `verify`; wave 1's Bazel clippy action did not flag the extraction, so the wave gate stayed green while plain-cargo clippy went red for `d2b-bus` and every crate depending on it. Fixed with the same sanctioned reason its four sibling functions use (`synchronous path`); `xtask check-provider-crate-layout` validates allow reasons against its sanctioned set rather than a per-site list, so no list changed and the site is not an ad-hoc allow. The broker test-helper entries below stay pre-existing and unfixed. - `cargo check -p d2b-provider-display-wayland --locked --all-targets` fails to compile the lib test with `E0599` on `AuthenticatedSessionRouteBinding::for_test` (a `test-support` cfg mismatch). Reproduced at the audit base `147a536a0` in a detached worktree, so this one is genuinely pre-existing rather than a wave regression - unlike the bus entry above, which the same check proved to be mine. - `cargo clippy -p d2b-provider-process-systemd --locked --all-targets` reports three errors from the `#[tokio::test]` functions in `src/effects_service.rs`, whose expansion calls the denied `tokio::runtime::Runtime::block_on`. Reproduced at the audit base `147a536a0`: three errors on a pristine checkout. The owning slice also proved it independently by reverting its own change and re-running. Pattern across these entries: plain-cargo clippy and check go red in four places where the Bazel gate stays green, because the gate's actions do not compile the same target set - expanded `#[tokio::test]` bodies, `test-support` cfg paths, and test helpers are linted by cargo and not by the action. One of the four was a wave-1 regression and is fixed; the rest reproduce at the audit base. A worker's acceptance signal for such a crate is its lib target plus its own tests, never a new inline allow. -- `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. +- `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. Reproduced at the audit base `147a536a0`: thirty-nine check errors on a pristine checkout. ## Wave gates From 4267573b30266ffc07fcd7a654ba1d9b79da9b0b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:00:52 -0700 Subject: [PATCH 426/726] audit: fold the host and provider slice --- .../2026-09-24-rust-skills-audit/ledger.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 9e18b81b7..761c5a3ba 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -322,7 +322,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipb` | | | | `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard` | | | | `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixo` | | | -| `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | | | | `packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-credential/src/d` | | | +| `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | applied-variant | U3 | 1ce473a70 | packages/d2b-provider-credential/src/driver.rs | zone: String -> d2b_contracts_resource::v3::ZoneId in CredentialDriverArgs and CredentialDriver; agent_child builds the zone ref with expect on a validated ZoneId (fallible ResourceRef::parse path dro | | | `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | | | | `controller.rs:85-89, tests/binding.rs:1214-1234` | | | | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | | `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | @@ -337,7 +337,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | b845000ff | packages/d2b-provider-guest-qemu-media/src/config.rs | impl Default for ProviderConfig deleted (it manufactured a config that fails its own validate());the sole consumer test now builds valid-then-mutated configs (controller_execution_ref swapped to a Gue | | | `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-` | | | | `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:56, agent.rs:265, agent.rs:297` | | | -| `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | | | | `packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minij` | | | +| `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U3 | 9fbe75ec2 | packages/d2b-provider-process-minijail/src/launch.rs | validate_launch_ticket renamed to validate_platform_gate and reduced to the gate check (identity checks live only in MinijailProcessProvider::validate); lib.rs:160 literal replaced with crate::PROVIDE | | | `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | | `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | aee724326 | packages/d2b-provider-process-systemd/src/metrics.rs | Added MetricLabelKey enum with as_str(); validate_labels takes typed keys; dropped LABEL_KEYS const (census: only in-crate definition, zero users). Unknown-key rejection now type-level; test updated. | | | `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry` | | | @@ -366,7 +366,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option`-style plain-static-code refusals, consumed at live_handlers.rs:2428 by s | | -| `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/depen` | | | +| `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/src/seam.rs | verify_startup_routing returns Result<(), StartupRoutingViolation> (UnadmittedHandler/MissingHandlers, Display preserved for main.rs); audit_crate/run_cargo_metadata/dependency_tree return Result<_, S | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:2` | | | | `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | Added fmt::Display (message "invalid shell name") and std::error::Error impls to ShellNameError; additive, no surface moved. cargo check/test/clippy -p d2b-contracts-control --locked all passed | | @@ -599,7 +599,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0543` | `err` | `xtask` | medium | actionable | leaf | applied | U3 | 7194d24e9 | packages/xtask/src/delivery/recovery.rs | RecoveryError::Read added for fs open/read failures; Json(String) now carries the bounded serde detail (field names/positions only via error.to_string(), never payload values, keeping the redaction co | | | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu | | -| `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composi` | | | +| `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | | `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | | | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | | | | `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | @@ -652,8 +652,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | | | | `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-` | | | | `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | -| `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/service.rs:392, packages/d2b-provider-transport-` | | | -| `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/src/service.rs:735, packages/d2b-provider-transport-` | | | +| `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | +| `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied-variant | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | TransportEntry carries endpoint/binding ids; the spawn block captures clones and threads them through run_bridge (copy-failure event gets fields) and emit_event (subscriber-drop event gets fields); th | | | `RS-0600` | `obs` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Replaced eprintln with tracing::debug!(error = %error, "create envelope validation failed"); tracing already a dependency and used in the crate. | | | `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/protocol.rs:188` | | | | `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Accept loop's four eprintln! calls replaced with tracing::error! events: connection-handler failures carry error = %error.message() (and peer_uid = peer.uid, captured before the move into the handler; | | From 5b15f57c27c5d74076e6d7689349886696030f7f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:01:06 -0700 Subject: [PATCH 427/726] d2b-provider-telemetry-service: box the carried store source; d2b-provider-host: simplify the observe source fallback --- packages/d2b-provider-host/src/driver.rs | 2 +- packages/d2b-provider-telemetry-service/src/driver.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/d2b-provider-host/src/driver.rs b/packages/d2b-provider-host/src/driver.rs index a2f1929d1..d787a8611 100644 --- a/packages/d2b-provider-host/src/driver.rs +++ b/packages/d2b-provider-host/src/driver.rs @@ -199,7 +199,7 @@ impl std::error::Error for ObserveError { self.fallback .as_ref() .map(|error| error as &(dyn std::error::Error + 'static)) - .or_else(|| Some(&self.probe as &(dyn std::error::Error + 'static))) + .or(Some(&self.probe as &(dyn std::error::Error + 'static))) } } diff --git a/packages/d2b-provider-telemetry-service/src/driver.rs b/packages/d2b-provider-telemetry-service/src/driver.rs index ed8f4c345..da374323d 100644 --- a/packages/d2b-provider-telemetry-service/src/driver.rs +++ b/packages/d2b-provider-telemetry-service/src/driver.rs @@ -95,7 +95,7 @@ impl TelemetryServiceDriverErrorKind { pub struct TelemetryServiceDriverError { kind: TelemetryServiceDriverErrorKind, op: DriverOp, - source: Option, + source: Option>, } impl TelemetryServiceDriverError { @@ -105,7 +105,7 @@ impl TelemetryServiceDriverError { /// Retain the underlying store failure as the chain's source (R13). fn with_source(mut self, source: ResourceError) -> Self { - self.source = Some(source); + self.source = Some(Box::new(source)); self } } @@ -118,7 +118,7 @@ impl core::fmt::Display for TelemetryServiceDriverError { impl std::error::Error for TelemetryServiceDriverError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.source.as_ref().map(|source| source as &(dyn std::error::Error + 'static)) + self.source.as_ref().map(|error| error.as_ref() as &(dyn std::error::Error + 'static)) } } From 779e3f00dd608ae53e1e19d43769238b7d7a56c1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:01:52 -0700 Subject: [PATCH 428/726] audit: fold the host resource slice --- .../2026-09-24-rust-skills-audit/ledger.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 761c5a3ba..a8395bebe 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -341,11 +341,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | | `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | aee724326 | packages/d2b-provider-process-systemd/src/metrics.rs | Added MetricLabelKey enum with as_str(); validate_labels takes typed keys; dropped LABEL_KEYS const (census: only in-crate definition, zero users). Unknown-key rejection now type-level; test updated. | | | `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry` | | | -| `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telem` | | | +| `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServicePhase enum (as_str for the three spellings) and TelemetryServiceProjection struct (serde camelCase, contract-pinned {serviceRole, serviceReadiness} shape) replace the json! literals; n | | | `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-p` | | | | `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/identity.rs:72-88, src/identity.rs:146-150` | | | | `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | watch: bool replaced with pub enum ScopedQueryMethod { List, Watch }; bus router call site and adapter test updated. | | -| `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs` | | | +| `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | f7b48c947 | packages/d2b-resource-client/src/dispatch.rs | Dropped the unreachable validate_lifetime()? re-check at CallDriver::new (MetadataInput::new enforces the invariant at construction; builder methods cannot change the lifetime fields) and removed the | | | `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/scheduler.rs | channel() now returns Result; the constructor-prevented NamedStream-without-stream combination yields InvalidChannel instead of a silent SESSION_CONTROL misroute. Census re-run: only caller | | | `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1702, engine.rs:1295, engine.rs:31` | | | | `RS-0299` | `type` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/` | | | @@ -371,7 +371,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0352` | `api` | `d2b` | medium | actionable | leaf | applied | U3 | d0bbf947a | packages/d2b/src/lib.rs | Made pub mod host_generation a private mod; census re-run: zero consumers of d2b::host_generation anywhere in workspace. | | | `RS-0353` | `api` | `d2b` | low | actionable | leaf | applied | U3 | 048fb7d4f | packages/d2b/src/zone_support_bundle.rs | all 11 pub items (6 structs + 3 consts + build_bundle + render_ndjson) and the struct fields reduced to module-private; census re-run: zero references to any of them outside the file; `mod zone_suppor | | | `RS-0354` | `api` | `d2b` | low | actionable | leaf | applied-variant | U3 | 65f98af06 | packages/d2b/src/lib.rs | Narrowed doctor/host_validate pub items and EXIT_API_TIMEOUT to pub(crate); tests/host_validate_verb.rs text-marker updated to the new pub(crate) spelling (its parity check is source-text based). | | -| `RS-0316` | `api` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/lib.rs:16, packages/d2b-audit/src/lib.rs:30, packages/d2b-audit/src` | | | +| `RS-0316` | `api` | `d2b-audit` | medium | actionable | leaf | applied | U3 | bf359ca79 | packages/d2b-audit/src/lib.rs | Removed the unused root re-export arms (export, rate_limit, record_types, segment, sink; reconcile's reconcile/Reconciliation/DurabilityOutcome); modules stay pub (house pattern - the crate denies dea | | | `RS-0319` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | d10ee144f | packages/d2b-broker/src/ops/sysctl.rs | Demoted apply_sysctl_intents, ApplySysctlRequest, intent_to_proc_path to pub(crate) (tests at 258/283 keep them); deleted with_default_root (zero references anywhere, not even tests). Census re-run: a | | | `RS-0320` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | bc367bab9 | packages/d2b-broker/src/ops/route.rs | RouteConflictKey made private (plain struct) and its six pub fields dropped to private; all users are in-file (route_conflicts, route_matches_record, requested_route_conflict_key, tests at 863). Censu | | | `RS-0318` | `api` | `d2b-broker` | medium | actionable | leaf | applied | U3 | ee8678e46 | packages/d2b-broker/src/ops/gpu.rs | Item-level pub -> pub(crate) for all 19 gpu.rs items and 7 modprobe.rs items (types, impl methods, free fns, trait). Chose item-level over module-decl narrowing so d2b-core bundle_resolver.rs:4300 and | | @@ -429,7 +429,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0374` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 4de51c1b5 | packages/d2bd/src/shared_provider_effects.rs | Registered TpmEffectsServiceFactory for TPM_EFFECTS_SERVICE in the plane test inputs factory map (shared_provider_effects.rs), built from d2b_provider_device_tpm::test_support::recording_facets() - th | | | `RS-0375` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 205e888b9 | packages/d2b-provider-device-tpm/src/effects_service.rs | LiveTpmResourceEffectPort made pub(crate); census re-run at HEAD: only effects_service.rs:341/364/535/679-680 reference it, 0 external hits | | | `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | -| `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `lib.rs:24, lib.rs:61-65` | | | +| `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | c47b8ba63 | packages/d2b-provider-device-usbip/src/lib.rs | pub mod state_machine -> mod state_machine; the lib.rs re-export remains the single surface. Census re-run: no state_machine:: module-path users outside the crate. | | | `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `broker.rs:131-133` | | | | `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | declined | U3 | | `src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20` | pub(crate) narrowing trips the repo dead_code deny (no internal users, no lint allows permitted by wave rules); wiring the daemon cleanup path needs spec/session-key plumbing across runtime+daemon bey | | | `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | c5d8e0cf5 | packages/d2b-provider-display-wayland/src/lib.rs | Module moved into the binary target via #[path]; all crate::wayland_proxy paths rewritten; census of d2b_provider_display_wayland::wayland_proxy over packages/nixos-modules/tests/docs/reference = 0. | | @@ -444,7 +444,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `identity.rs:554-556, tests/controller.rs:206` | | | | `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | dc09819bf | packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | Deleted constant-true preserve_state() accessor and its tautological assertion (census: only consumer was the assertion). check+finalize_ordering tests (6) + clippy green. | | | `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | -| `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111,` | | | +| `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | Seven dead-pub items in the private mod driver narrowed to pub(crate): HostDriver, HostDriverError, HostDriverStatus, HostDriverFactory, HostDriverEffects, host_spec_decoder, HOST_REOBSERVE. Census re | | | `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/routes.rs:244-279, src/routes.rs:264-265` | | | | `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:1019, packages/d2b-provider-n` | | | | `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:110, packages/d2b-provider-no` | | | @@ -547,8 +547,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | 263eea211 | packages/d2b-provider-display-wayland/src/controller.rs | DisplayController::new returns Result with # Errors doc; 2 daemon sites use expect/unwrap; all call sites updated. | | | `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886` | | | | `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 64c41ddb5 | packages/d2b-provider-display-wayland/src/spec.rs | WaylandSpecError::NoPrincipalAvailable variant + Display arm deleted; no error-codes.md hit; no other constructors (controller uses PrincipalPoolError/SessionCondition). | | -| `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:197, packages/d2b-provider-host/src/effects_servi` | | | -| `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | | | | `packages/d2b-provider-host/src/driver.rs:129, packages/d2b-provider-host/src/driver.rs:99` | | | +| `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | applied-variant | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | observe_host returns Result<_, ObserveError>; the flattening format! is replaced by a closed error carrying both SystemCoreError legs with Error::source() (fallback is the chain source, probe error re | | +| `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | HostDriverError::Display delegates to self.kind.failure_kind().code(); the three registry codes verified identical to the re-spelled literals. | | | `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/nftables.rs:588` | | | | `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | | | | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | | | | `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-not` | | | @@ -557,8 +557,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | | `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:419-421` | | | | `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:888-890` | | | -| `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:304` | | | -| `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-service/src/driver.rs:386` | | | +| `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServiceDriverError carries source: Option> with Error::source(); the Err(_) swallow in reconcile_service now attaches the store error and classify_error surfaces it as a fa | | +| `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | | `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | | `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-to` | | | | `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | @@ -572,7 +572,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 (driver-args class member key_ref; RS-0962) | | `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | applied | U3 | e783447e2 | packages/d2b-provider-wayland-session/Cargo.toml | Added tracing = 0.1 (already in lockfile; Cargo.lock records one new dep edge) and map_err now logs provider=WAYLAND_SESSION_PROVIDER_REF with reason=%error before mapping to InvalidResource. | | | `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Empty batch now rejected with 'batch mutation count is zero'; MAX_BATCH_MUTATIONS check keeps the bound reason. Reason string unpinned in error-codes.md. | | -| `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309` | | | +| `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | 854ba06a5 | packages/d2b-resource-client/src/call.rs | The three Mutex::lock().unwrap() sites in the waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) now use expect with the written reason: no user code runs u | | | `RS-0520` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/error.rs:773, packages/d2b-resource-runtime/src/manager.` | | | | `RS-0521` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spe` | | | | `RS-0522` | `err` | `d2b-session` | medium | actionable | leaf | applied-variant | U3 | afb1fa59c | packages/d2b-session/src/transport.rs | Applied the typestate option minimally: the Option> wrapper is gone (plain Box), so the consumed state is unrepresentable and all three expects disappeared; public signatures a | | From 4a0c3e15b76cdbc3862ed328fd586c48b1545b20 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:03:48 -0700 Subject: [PATCH 429/726] audit: fold the session and relay slice --- .../2026-09-24-rust-skills-audit/ledger.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index a8395bebe..228bbd3c4 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -309,7 +309,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | | `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-r` | | | | `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resou` | | | -| `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `role_binding.rs:179-182, role_binding.rs:149-162` | | | +| `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | packages/d2b-provider-transport-azure-relay/contrast-zone-session/src/v3/role_binding.rs | | | | `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | | | | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | | `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | @@ -342,12 +342,12 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | aee724326 | packages/d2b-provider-process-systemd/src/metrics.rs | Added MetricLabelKey enum with as_str(); validate_labels takes typed keys; dropped LABEL_KEYS const (census: only in-crate definition, zero users). Unknown-key rejection now type-level; test updated. | | | `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry` | | | | `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServicePhase enum (as_str for the three spellings) and TelemetryServiceProjection struct (serde camelCase, contract-pinned {serviceRole, serviceReadiness} shape) replace the json! literals; n | | -| `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-p` | | | +| `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | | `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/identity.rs:72-88, src/identity.rs:146-150` | | | | `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | watch: bool replaced with pub enum ScopedQueryMethod { List, Watch }; bus router call site and adapter test updated. | | | `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | f7b48c947 | packages/d2b-resource-client/src/dispatch.rs | Dropped the unreachable validate_lifetime()? re-check at CallDriver::new (MetadataInput::new enforces the invariant at construction; builder methods cannot change the lifetime fields) and removed the | | | `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/scheduler.rs | channel() now returns Result; the constructor-prevented NamedStream-without-stream combination yields InvalidChannel instead of a silent SESSION_CONTROL misroute. Census re-run: only caller | | -| `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1702, engine.rs:1295, engine.rs:31` | | | +| `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | bd25f4ce9 | packages/d2b-session/src/engine.rs | | | | `RS-0299` | `type` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/` | | | | `RS-0303` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | force semantics implemented in apply(): dropped `let _ = self.force;` and gated the graceful wait on `wait_for_ready && !force`. Checks: cargo check -p d2bd --locked --all-targets green. | | | `RS-0305` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | b310cab7bdafa68156e88ee513f3083bbe3d25a2 | packages/d2bd/src/shared_provider_effects.rs | Added crate-private SharedProviderEffectMode enum (Deserialize, rename_all kebab-case) with a fail-closed parse; both stringly-compare sites (usbip_service_port opted_in, reconcile_security_key projec | | @@ -470,8 +470,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/server/service.rs:297-299, packages/d2b-provider-toolkit` | | | | `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | | `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | -| `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:491-497, packages/d2b` | | | -| `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343-347, packages/d2b` | | | +| `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs | | | +| `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | | `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | | | | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | | | | `RS-0421` | `api` | `d2b-provider-volume-local` | medium | actionable | family | | | | `src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1` | | | | `RS-0422` | `api` | `d2b-provider-zone` | medium | actionable | leaf | applied | U3 | c28489ccc | packages/d2b-provider-zone/src/lib.rs | zone_status module private with the four items re-exported by name; the two module-path consumers (d2bd resource_runtime.rs:63-65, tests/zone_status.rs:3-4) re-pointed to the crate root. Census: d2b_p | | @@ -487,7 +487,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:460-462` | | | | `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | | | | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | | | | `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/fragmentation.rs | Fragment.header is now private with a pub header() accessor; the two engine.rs encode call sites (877, 1395) use the accessor. Census: no external field access. | | -| `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:166, engine.rs:262, engine.rs:416, engine.rs:356` | | | +| `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | | `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | | | | `packages/d2b-session-unix/src/socket.rs:176` | | | | `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | applied | U3 | b9fc346fc | packages/d2b-sk-frontend/src/lib.rs | agent/config/link/uhid made private; UhidDevice and UhidEvent re-exported from lib.rs; main.rs:41 uses root re-exports. Census: sk_frontend::(agent/config/link/uhid):: = 0 full-path hits; zone-routing | | | `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/` | | | @@ -565,8 +565,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | | `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | | `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | | | -| `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69-78, packages/d2b-pro` | | | -| `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-pro` | | | +| `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | +| `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | applied | U3 | 2ab7a1ed2 | packages/d2b-provider-user/src/driver.rs | Display impl now writes self.kind.failure_kind().code(); registered FailureKind codes remain the single source, strings unchanged, no behavior change. | | | `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | | | | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-bindi` | | | | `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 (driver-args class member key_ref; RS-0962) | @@ -650,7 +650,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | | `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src` | | | | `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | | | -| `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-` | | | +| `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/relay_transport.rs | | | | `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | | `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | | `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied-variant | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | TransportEntry carries endpoint/binding ids; the spawn block captures clones and threads them through run_bridge (copy-failure event gets fields) and emit_event (subscriber-drop event gets fields); th | | From 31ff8b3963fc9a4232b66288e8ba29cd1f7b82d5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:10:20 -0700 Subject: [PATCH 430/726] system-core: narrow the crate's public surface - ownership module is crate-private; only the pinned consts stay public - test doubles move behind the test-support feature gate - PROVIDER_UID const dropped until the bus re-homes onto it - HostProbeSnapshot accessor surface narrowed to the crate scope --- packages/d2b-provider-system-core/Cargo.toml | 18 ++++++++++ packages/d2b-provider-system-core/src/host.rs | 36 ++----------------- packages/d2b-provider-system-core/src/lib.rs | 13 +++---- 3 files changed, 25 insertions(+), 42 deletions(-) diff --git a/packages/d2b-provider-system-core/Cargo.toml b/packages/d2b-provider-system-core/Cargo.toml index a59920e76..716c58e7a 100644 --- a/packages/d2b-provider-system-core/Cargo.toml +++ b/packages/d2b-provider-system-core/Cargo.toml @@ -20,3 +20,21 @@ d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0- tracing = "0.1" serde = { workspace = true } serde_json = { workspace = true } + +[features] +test-support = [] + +[[test]] +name = "host_reconciliation" +path = "tests/host_reconciliation.rs" +required-features = ["test-support"] + +[[test]] +name = "ownership" +path = "tests/ownership.rs" +required-features = ["test-support"] + +[[test]] +name = "user_discovery" +path = "tests/user_discovery.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-system-core/src/host.rs b/packages/d2b-provider-system-core/src/host.rs index 466125839..dd1f84a95 100644 --- a/packages/d2b-provider-system-core/src/host.rs +++ b/packages/d2b-provider-system-core/src/host.rs @@ -137,7 +137,7 @@ impl MinijailPlatformGate { /// A hermetic result returned by the injected Host probe adapter. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct HostProbeSnapshot { +pub(crate) struct HostProbeSnapshot { capabilities: BTreeSet, kernel_release: String, os_name: String, @@ -197,36 +197,6 @@ impl HostProbeSnapshot { active_process_count, }) } - - /// Borrow observed capabilities. - pub fn capabilities(&self) -> &BTreeSet { - &self.capabilities - } - - /// Borrow the bounded kernel release observation. - pub fn kernel_release(&self) -> &str { - &self.kernel_release - } - - /// Borrow the bounded OS name observation. - pub fn os_name(&self) -> &str { - &self.os_name - } - - /// Whether the user manager is reachable. - pub const fn user_manager_available(&self) -> bool { - self.user_manager_available - } - - /// Return the minijail platform gate. - pub const fn minijail_gate(&self) -> MinijailPlatformGate { - self.minijail_gate - } - - /// Number of non-terminal child processes observed. - pub const fn active_process_count(&self) -> u32 { - self.active_process_count - } } /// An injected, bounded Host capability probe. @@ -451,7 +421,7 @@ impl HostReconciler { /// The snapshot is the seam a real system-core effect adapter fills from /// bounded OS probes. This method performs no host I/O and can therefore /// be used by both conformance and fault-injection tests. - pub fn reconcile_observed( + pub(crate) fn reconcile_observed( &self, host_ref: &ResourceRef, provider_ref: &ResourceRef, @@ -540,7 +510,7 @@ impl HostReconciler { ) -> Result { // # Errors // - // Returns the errors of [`Self::reconcile_observed`], plus + // Returns the errors of `reconcile_observed`, plus // [`SystemCoreError::HostProbeFailed`] when the injected probe port // reports an invalid observation. let mut capabilities = BTreeSet::new(); diff --git a/packages/d2b-provider-system-core/src/lib.rs b/packages/d2b-provider-system-core/src/lib.rs index 2209a8285..3a28a66d5 100644 --- a/packages/d2b-provider-system-core/src/lib.rs +++ b/packages/d2b-provider-system-core/src/lib.rs @@ -37,13 +37,14 @@ mod error; mod host; mod user; -pub mod ownership; +mod ownership; +#[cfg(feature = "test-support")] pub mod testing; pub use error::SystemCoreError; pub use host::{ HostCapabilityClass, HostObservationReport, HostProbeEffectPort, - HostProbeMetadata, HostProbeSnapshot, HostReconciler, HostStatusReport, + HostProbeMetadata, HostReconciler, HostStatusReport, ISOLATION_POSTURE_MESSAGE, MinijailPlatformGate, NO_ISOLATION_STATUS_FIELDS, }; pub use ownership::{DISOWNED_RESOURCE_TYPES, OWNED_RESOURCE_TYPES}; @@ -61,10 +62,4 @@ pub const PROVIDER_NAME: &str = "system-core"; /// the same constant the Host primitive contract pins. pub const PROVIDER_REF: &str = d2b_contracts_resource::v3::host::HOST_PROVIDER_REF; -/// The canonical `Provider/system-core` resource UID. -/// -/// This is the fixed UID the daemon's bootstrap admits for the bootstrap -/// Provider's own subject row. It is not part of any wire contract; the -/// bus keeps its own copy until the daemon's composition re-homes its -/// subject installation onto this constant. -pub const PROVIDER_UID: &str = "11111111-1111-4111-8111-111111111111"; + From c4ea8fb104ae4991e45de667ed273bb4c363b03d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:10:49 -0700 Subject: [PATCH 431/726] telemetry-binding: type the status phase as a closed enum --- .../src/driver.rs | 42 +++++++++++++------ .../d2b-provider-telemetry-binding/src/lib.rs | 10 ++--- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/packages/d2b-provider-telemetry-binding/src/driver.rs b/packages/d2b-provider-telemetry-binding/src/driver.rs index b7636826c..c7f674b59 100644 --- a/packages/d2b-provider-telemetry-binding/src/driver.rs +++ b/packages/d2b-provider-telemetry-binding/src/driver.rs @@ -72,12 +72,24 @@ pub const TELEMETRY_BINDING_PROCESS_PROVIDER: &str = "Provider/system-minijail"; /// Binding is not converged instead of polling from a runner. pub const TELEMETRY_BINDING_RESYNC: Duration = Duration::from_secs(5); -/// Provider phase spelling for a Binding whose child set is not current. -pub const PHASE_PENDING: &str = "Pending"; +/// Closed lifecycle phase for one telemetry Binding. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TelemetryBindingPhase { + /// The Binding's child set is not current. + Pending, + /// The Binding's route or children are not ready. + Degraded, +} -/// Provider phase spelling for a Binding whose route or children are not -/// ready. -pub const PHASE_DEGRADED: &str = "Degraded"; +impl TelemetryBindingPhase { + /// The provider phase spelling. + pub const fn as_str(self) -> &'static str { + match self { + Self::Pending => "Pending", + Self::Degraded => "Degraded", + } + } +} /// The collector/forwarder creation the Binding declares. /// @@ -166,8 +178,8 @@ impl std::error::Error for TelemetryBindingDriverError {} /// API, now in-memory only (R11: runtime status is never persisted). #[derive(Debug, Clone, PartialEq, Eq)] pub struct TelemetryBindingStatus { - /// The projected provider phase spelling. - pub phase: &'static str, + /// The projected provider phase. + pub phase: TelemetryBindingPhase, /// The relationship is malformed or dangling (`fenced_owner`). pub fenced: bool, /// The owned child set is current: this pass made no child mutation. @@ -398,7 +410,7 @@ impl TelemetryBindingDriver { /// dependency rows appear. fn fence_binding(&mut self, ctx: &mut ResourceContext) -> ReconcileOutcome { ctx.set_status(TelemetryBindingStatus { - phase: PHASE_DEGRADED, + phase: TelemetryBindingPhase::Degraded, fenced: true, converged: false, desired_children: Vec::new(), @@ -475,9 +487,9 @@ impl TelemetryBindingDriver { // converged; the readiness term is unobservable here, so a converged // owner reports the fail-closed Degraded projection. let phase = if converged { - PHASE_DEGRADED + TelemetryBindingPhase::Degraded } else { - PHASE_PENDING + TelemetryBindingPhase::Pending }; ctx.set_status(TelemetryBindingStatus { phase, @@ -1032,7 +1044,11 @@ mod tests { let Some(status) = fixture.ctx.status::() else { panic!("binding status"); }; - assert_eq!(status.phase, PHASE_PENDING, "first pass mutated the child set"); + assert_eq!( + status.phase, + TelemetryBindingPhase::Pending, + "first pass mutated the child set" + ); assert!(!status.fenced); assert!(!status.converged); assert_eq!(status.desired_children.len(), 2); @@ -1054,7 +1070,7 @@ mod tests { assert!(status.converged, "second pass converged"); // CONTRACT FLAG: the old `ready ? Ready : Degraded` phase reports the // fail-closed projection while readiness is unobservable. - assert_eq!(status.phase, PHASE_DEGRADED); + assert_eq!(status.phase, TelemetryBindingPhase::Degraded); assert_eq!( fixture.requeue.scheduled().await, vec![TELEMETRY_BINDING_RESYNC], @@ -1080,7 +1096,7 @@ mod tests { }; assert!(status.fenced); assert!(!status.converged); - assert_eq!(status.phase, PHASE_DEGRADED); + assert_eq!(status.phase, TelemetryBindingPhase::Degraded); assert_eq!( fixture.requeue.scheduled().await, vec![TELEMETRY_BINDING_RESYNC], diff --git a/packages/d2b-provider-telemetry-binding/src/lib.rs b/packages/d2b-provider-telemetry-binding/src/lib.rs index 9144abce6..c44ef7a94 100644 --- a/packages/d2b-provider-telemetry-binding/src/lib.rs +++ b/packages/d2b-provider-telemetry-binding/src/lib.rs @@ -33,9 +33,9 @@ mod driver; pub use driver::{ - PHASE_DEGRADED, PHASE_PENDING, TELEMETRY_BINDING_COLLECTOR_CREATION, - TELEMETRY_BINDING_CREATIONS, TELEMETRY_BINDING_ENDPOINT_CREATION, - TELEMETRY_BINDING_RESYNC, TELEMETRY_BINDING_TYPE, TelemetryBindingDriver, - TelemetryBindingDriverError, TelemetryBindingDriverFactory, TelemetryBindingStatus, - telemetry_binding_descriptor, telemetry_binding_spec_decoder, + TELEMETRY_BINDING_COLLECTOR_CREATION, TELEMETRY_BINDING_CREATIONS, + TELEMETRY_BINDING_ENDPOINT_CREATION, TELEMETRY_BINDING_RESYNC, TELEMETRY_BINDING_TYPE, + TelemetryBindingDriver, TelemetryBindingDriverError, TelemetryBindingDriverFactory, + TelemetryBindingPhase, TelemetryBindingStatus, telemetry_binding_descriptor, + telemetry_binding_spec_decoder, }; From 0623be33bf4894fc796b0f603508b2570b746b7d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:35 -0700 Subject: [PATCH 432/726] provider-toolkit: gate test backend constructors behind test-support --- packages/d2b-provider-credential-secret-service/BUILD.bazel | 4 ++-- packages/d2b-provider-credential-secret-service/Cargo.toml | 1 + packages/d2b-provider-toolkit/BUILD.bazel | 2 +- packages/d2b-provider-toolkit/Cargo.toml | 6 ++++++ packages/d2b-provider-toolkit/src/base/fd10.rs | 2 ++ 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-credential-secret-service/BUILD.bazel b/packages/d2b-provider-credential-secret-service/BUILD.bazel index 24bb925a8..19e74cb23 100644 --- a/packages/d2b-provider-credential-secret-service/BUILD.bazel +++ b/packages/d2b-provider-credential-secret-service/BUILD.bazel @@ -156,7 +156,7 @@ d2b_rust_test( d2b_rust_test( name = "d2b_provider_credential_secret_service_test", compile_data = ["Cargo.toml"], - crate = ":d2b_provider_credential_secret_service", + crate = ":d2b_provider_credential_secret_service_test_support", deps = [ "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", "//packages/d2b-session-unix:d2b_session_unix", @@ -173,7 +173,7 @@ d2b_rust_test( "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", - "//packages/d2b-provider-toolkit:d2b_provider_toolkit", + "//packages/d2b-provider-toolkit:d2b_provider_toolkit_test_support", "//packages/d2b-session:d2b_session", "//packages/d2b-session-unix:d2b_session_unix", ":d2b_provider_credential_secret_service", diff --git a/packages/d2b-provider-credential-secret-service/Cargo.toml b/packages/d2b-provider-credential-secret-service/Cargo.toml index 7e4570e9e..09f141795 100644 --- a/packages/d2b-provider-credential-secret-service/Cargo.toml +++ b/packages/d2b-provider-credential-secret-service/Cargo.toml @@ -24,6 +24,7 @@ tokio = { workspace = true, features = ["rt", "time", "sync", "macros"] } [dev-dependencies] d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = "0.0.0-bootstrap" } +d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-bootstrap", features = ["test-support"] } d2b-session = { path = "../d2b-session", version = "0.0.0-bootstrap" } d2b-session-unix = { path = "../d2b-session-unix", version = "0.0.0-bootstrap" } ttrpc = { workspace = true, features = ["async", "sync"] } diff --git a/packages/d2b-provider-toolkit/BUILD.bazel b/packages/d2b-provider-toolkit/BUILD.bazel index 78e0ad74d..8b42b5208 100644 --- a/packages/d2b-provider-toolkit/BUILD.bazel +++ b/packages/d2b-provider-toolkit/BUILD.bazel @@ -40,7 +40,7 @@ d2b_rust_library( name = "d2b_provider_toolkit_test_support", srcs = d2b_provider_toolkit_srcs, compile_data = ["Cargo.toml"], - crate_features = ["unix-transport"], + crate_features = ["unix-transport", "test-support"], crate_name = "d2b_provider_toolkit", deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", diff --git a/packages/d2b-provider-toolkit/Cargo.toml b/packages/d2b-provider-toolkit/Cargo.toml index 682d47be9..4a76781f7 100644 --- a/packages/d2b-provider-toolkit/Cargo.toml +++ b/packages/d2b-provider-toolkit/Cargo.toml @@ -8,6 +8,7 @@ license.workspace = true [features] default = ["unix-transport"] unix-transport = ["dep:d2b-session-unix", "d2b-session-unix/host-socket"] +test-support = [] [lints.rust] unsafe_code = "forbid" @@ -45,3 +46,8 @@ sha2.workspace = true [[bin]] name = "d2b-provider-toolkit" path = "src/bin/d2b-provider-toolkit.rs" + +[[test]] +name = "supervised_runtime" +path = "tests/supervised_runtime.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-toolkit/src/base/fd10.rs b/packages/d2b-provider-toolkit/src/base/fd10.rs index fc8e74f39..f521413b1 100644 --- a/packages/d2b-provider-toolkit/src/base/fd10.rs +++ b/packages/d2b-provider-toolkit/src/base/fd10.rs @@ -868,6 +868,7 @@ impl GuestCredentialBackend { } /// Bind a prearmed backend socket for Layer-1 transport tests. + #[cfg(any(test, feature = "test-support"))] pub fn from_socket_for_test(socket: SeqpacketSocket) -> Arc { Arc::new(Self { state: Arc::new(tokio::sync::Mutex::new(GuestCredentialBackendState { @@ -881,6 +882,7 @@ impl GuestCredentialBackend { /// Bind a prearmed backend socket to an authenticated route for transport /// and session-fencing tests. + #[cfg(any(test, feature = "test-support"))] pub fn from_socket_for_test_with_route( socket: SeqpacketSocket, route: AuthenticatedSessionRouteBinding, From 81f51276ed7456104a034c40ba5b3c45bba8c790 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:39 -0700 Subject: [PATCH 433/726] provider-toolkit: drop dead generated-service accessors --- packages/d2b-provider-toolkit/src/server/service.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/d2b-provider-toolkit/src/server/service.rs b/packages/d2b-provider-toolkit/src/server/service.rs index 4775dd4cc..acf6012b2 100644 --- a/packages/d2b-provider-toolkit/src/server/service.rs +++ b/packages/d2b-provider-toolkit/src/server/service.rs @@ -19,7 +19,7 @@ use d2b_contracts_resource::v3::identity::ServiceName; use d2b_contracts_resource::v3::{ CanonicalJsonObject, ResourceRef, execution_policy::BoundedToken, }; -use d2b_contracts_zone_session::v3::{component_session::RequestId, zone_routing::ZonePath}; +use d2b_contracts_zone_session::v3::zone_routing::ZonePath; use d2b_session::{AuthenticatedSessionRouteBinding, Cancellation, ComponentSessionDriver}; use tokio::sync::Notify; @@ -170,11 +170,6 @@ impl GeneratedProviderServiceServer { self.adapter.bind_authenticated_route(route) } - /// Borrow the generated service descriptor. - pub const fn generated_service(&self) -> &GeneratedServiceDescriptor { - &self.generated - } - /// Return whether new requests are accepted. pub fn is_accepting(&self) -> bool { self.state.accepting.load(Ordering::Acquire) @@ -292,11 +287,6 @@ where pub fn generated_services(&self) -> Vec { vec![self.generated.clone()] } - - /// Encode a response correlation without exposing request contents. - pub fn response_request_id<'a>(&self, request_id: &'a RequestId) -> &'a RequestId { - request_id - } } #[cfg(test)] From de1a2c493eb2db826cd517128364c759a86240d9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:43 -0700 Subject: [PATCH 434/726] provider-toolkit: audit canonicalized forwarded operation names --- .../src/operations/envelope.rs | 19 +++++++++-- .../d2b-provider-toolkit/tests/harness.rs | 34 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-toolkit/src/operations/envelope.rs b/packages/d2b-provider-toolkit/src/operations/envelope.rs index e1dddc4c8..9dd519a3b 100644 --- a/packages/d2b-provider-toolkit/src/operations/envelope.rs +++ b/packages/d2b-provider-toolkit/src/operations/envelope.rs @@ -493,8 +493,23 @@ impl OperationEnvelope { } fn audit_named(&self, operation: &str, outcome: ProviderAgentAuditOutcome) { - let Ok(method) = BoundedToken::parse(operation) else { - return; + // The forwarded spelling is the catalog's PascalCase wire name, + // which the bounded token grammar rejects; the record falls back to + // the canonical (lowercase, dash-stripped) spelling so a refused + // forwarded invocation still lands its Denied event (U10 seam). + let method = match BoundedToken::parse(operation) { + Ok(method) => method, + Err(_) => { + let canonical: String = operation + .chars() + .filter(|c| *c != '-') + .flat_map(char::to_lowercase) + .collect(); + let Ok(method) = BoundedToken::parse(&canonical) else { + return; + }; + method + } }; // The audit ring is shared with the adapter through a `std` mutex // (the constructor surface is a frozen contract), so the record is diff --git a/packages/d2b-provider-toolkit/tests/harness.rs b/packages/d2b-provider-toolkit/tests/harness.rs index 12b5f5044..21973432e 100644 --- a/packages/d2b-provider-toolkit/tests/harness.rs +++ b/packages/d2b-provider-toolkit/tests/harness.rs @@ -469,6 +469,40 @@ async fn an_ungranted_and_an_uncommitted_invocation_are_refused_and_audited() { assert_eq!(harness.envelope().grant_count(), 0); } +/// The U10 seam: a forwarded invocation spells the operation in the +/// catalog's PascalCase wire name, which the bounded token grammar rejects; +/// the refused invocation still lands its Denied record under the +/// canonicalized spelling. +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + +#[tokio::test] +async fn a_refused_pascalcase_forwarded_invocation_still_lands_a_denied_record() { + let harness = harness(); + let error = harness + .envelope() + .invoke_named_with_fds_under_chain( + "HarnessAbsent", + "invocation-broker-11", + &caller(), + CanonicalJsonObject::empty(), + &[], + &[], + None, + ) + .await + .expect_err("no declared handler serves the forwarded spelling"); + assert_eq!(error.code(), "uncommitted-operation"); + + let events = harness.audit_events(); + assert_eq!(events.len(), 1); + assert_eq!(events[0].outcome(), ProviderAgentAuditOutcome::Denied); + assert_eq!( + events[0].method().as_str(), + "harnessabsent", + "the Denied record carries the canonicalized forwarded spelling" + ); +} + /// The happy U7 path: a committed row resolves to the declaring service's /// declared method, the resolution carries the method's contract facets /// (the row schema reference among them), and dispatch reaches the From abc324d2a67e769d07dd0a2a8f650f5bd0a76c13 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:53 -0700 Subject: [PATCH 435/726] provider-toolkit: warn on malformed guest frames --- packages/d2b-provider-toolkit/src/base/guest.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/d2b-provider-toolkit/src/base/guest.rs b/packages/d2b-provider-toolkit/src/base/guest.rs index 8a94fcee0..ef1dd05de 100644 --- a/packages/d2b-provider-toolkit/src/base/guest.rs +++ b/packages/d2b-provider-toolkit/src/base/guest.rs @@ -491,7 +491,12 @@ async fn serve_enrolled( if !attachments.is_empty() { return Err(GuestError::SessionDisconnected); } + let frame_bytes = bytes.len(); let Ok(frame) = GuestFrame::new(bytes) else { + tracing::warn!( + frame_bytes, + "dropping malformed guest frame: the peer violated the frame contract" + ); continue; }; let Ok(replies) = agent.serve(frame).await else { From 0cd7b063d3b439a738e8426f3061df32b89792da Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:54 -0700 Subject: [PATCH 436/726] resource-runtime: drop unused TargetBinding directory accessor --- packages/d2b-resource-runtime/src/target.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/d2b-resource-runtime/src/target.rs b/packages/d2b-resource-runtime/src/target.rs index 9330c27e2..afae3a377 100644 --- a/packages/d2b-resource-runtime/src/target.rs +++ b/packages/d2b-resource-runtime/src/target.rs @@ -490,11 +490,6 @@ impl TargetBinding { Self { directory, assignment } } - /// The per-Zone directory this binding resolves through. - pub fn directory(&self) -> &Arc { - &self.directory - } - /// The recorded assignment. pub const fn assignment(&self) -> &TargetAssignment { &self.assignment From 3570364e071f9d931422dd78f059444ae2367fb9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:54 -0700 Subject: [PATCH 437/726] resource-runtime: borrow the guest target reference instead of cloning --- packages/d2b-resource-runtime/src/guest_target.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2b-resource-runtime/src/guest_target.rs b/packages/d2b-resource-runtime/src/guest_target.rs index 78b001c1d..b71f9ce39 100644 --- a/packages/d2b-resource-runtime/src/guest_target.rs +++ b/packages/d2b-resource-runtime/src/guest_target.rs @@ -464,8 +464,8 @@ impl GuestTargetRuntime { } /// The Guest this runtime realizes for. - pub fn reference(&self) -> TargetRef { - self.inner.reference.clone() + pub fn reference(&self) -> &TargetRef { + &self.inner.reference } /// The authenticated ComponentSession generation currently bound. From adb2859843dc108146f1c5e77259a9d19a1dab2b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:54 -0700 Subject: [PATCH 438/726] resource-runtime: fail corrupt uid rows with a typed error --- .../d2b-resource-runtime/src/spec_store.rs | 105 ++++++++++++++---- 1 file changed, 84 insertions(+), 21 deletions(-) diff --git a/packages/d2b-resource-runtime/src/spec_store.rs b/packages/d2b-resource-runtime/src/spec_store.rs index ba855afba..1afd04cbb 100644 --- a/packages/d2b-resource-runtime/src/spec_store.rs +++ b/packages/d2b-resource-runtime/src/spec_store.rs @@ -174,6 +174,11 @@ pub enum SpecStoreError { ResourceDeleting { zone: String, type_name: String, name: String }, #[error("resource {zone}/{type_name}/{name} not found")] NotFound { zone: String, type_name: String, name: String }, + /// A stored row whose uid column is not the 16-byte identity this store + /// writes. The row is corrupt: admitting it with a zero identity would + /// collide with every other zero-uid row, so the call fails instead. + #[error("corrupt stored row {zone}/{type_name}/{name}: uid column is not 16 bytes")] + CorruptRow { zone: String, type_name: String, name: String }, #[error("spec store io: {0}")] Io(#[from] std::io::Error), #[error("spec store sqlite: {0}")] @@ -566,18 +571,32 @@ fn insert_new( }) } -fn row_from( - r: &rusqlite::Row<'_>, -) -> rusqlite::Result { +fn row_from(r: &rusqlite::Row<'_>) -> Result { + let zone: String = r.get(0)?; + let type_name: String = r.get(1)?; + let name: String = r.get(2)?; + let corrupt = || SpecStoreError::CorruptRow { + zone: zone.clone(), + type_name: type_name.clone(), + name: name.clone(), + }; + let uid: [u8; 16] = r + .get::<_, Vec>(3)? + .try_into() + .map_err(|_| corrupt())?; + let owner_uid: Option<[u8; 16]> = r + .get::<_, Option>>(5)? + .map(|v| v.try_into().map_err(|_| corrupt())) + .transpose()?; Ok(StoredDesiredResource { key: ResourceKey { - zone: r.get(0)?, - type_name: r.get(1)?, - name: r.get(2)?, + zone, + type_name, + name, }, - uid: r.get::<_, Vec>(3)?.try_into().unwrap_or([0; 16]), + uid, generation: r.get::<_, i64>(4)? as u64, - owner_uid: r.get::<_, Option>>(5)?.map(|v| v.try_into().unwrap_or([0; 16])), + owner_uid, provenance: r.get::<_, String>(6)?.parse().unwrap_or(ResourceProvenance::Api), deleting: r.get::<_, i64>(7)? != 0, spec: r.get(8)?, @@ -590,15 +609,16 @@ fn load_row( conn: &Connection, key: &ResourceKey, ) -> Result, SpecStoreError> { - Ok(conn - .query_row( - "SELECT zone, type, name, uid, generation, owner_uid, provenance, deleting, \ - spec, metadata, created_at FROM resources \ - WHERE zone = ?1 AND type = ?2 AND name = ?3", - params![key.zone, key.type_name, key.name], - row_from, - ) - .optional()?) + let mut stmt = conn.prepare( + "SELECT zone, type, name, uid, generation, owner_uid, provenance, deleting, \ + spec, metadata, created_at FROM resources \ + WHERE zone = ?1 AND type = ?2 AND name = ?3", + )?; + let mut rows = stmt.query(params![key.zone, key.type_name, key.name])?; + match rows.next()? { + Some(row) => Ok(Some(row_from(row)?)), + None => Ok(None), + } } fn get(conn: &Connection, key: &ResourceKey) -> Result { @@ -621,10 +641,12 @@ fn list(conn: &Connection, selector: &SpecSelector) -> Result, _>>()?; - Ok(rows) + let mut rows = stmt.query(params![zone, type_name, owner])?; + let mut out = Vec::new(); + while let Some(row) = rows.next()? { + out.push(row_from(row)?); + } + Ok(out) } /// Set the terminal deleting mark (R10). Fails with @@ -934,6 +956,47 @@ mod tests { assert!(history.iter().any(|rec| rec.operation == "ensure.create")); } + /// A stored row whose uid column is not the 16-byte identity the store + /// writes is corrupt: reads fail with the typed error instead of + /// admitting a zero identity that collides with every other zero-uid + /// row. + #[tokio::test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + async fn a_corrupt_uid_column_fails_reads_with_a_typed_error() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("specs.db"); + { + let store = SpecStore::open(&path).unwrap(); + store.ensure(row("data", b"spec-v1")).await.unwrap(); + } + let conn = rusqlite::Connection::open(&path).unwrap(); + conn.execute( + "UPDATE resources SET uid = ?1 WHERE name = 'data'", + [vec![1u8, 2, 3]], + ) + .unwrap(); + drop(conn); + + let store = SpecStore::open(&path).unwrap(); + let error = store + .get(ResourceKey::new("host", "Volume", "data")) + .await + .expect_err("a corrupt uid column is not a zero identity"); + assert!(matches!( + error, + SpecStoreError::CorruptRow { + zone, + type_name, + name, + } if zone == "host" && type_name == "Volume" && name == "data" + )); + let error = store + .list(SpecSelector::default()) + .await + .expect_err("list surfaces the same corrupt row"); + assert!(matches!(error, SpecStoreError::CorruptRow { .. })); + } + /// Durability boundary (AE1): ensure returns only after the commit. The /// second store call observes the committed generation, proving the /// first call's write was durable before its Ok. From fa4907468db2e0c7013db3c998339a7bedcf44ee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:11:58 -0700 Subject: [PATCH 439/726] resource-runtime: split manager rpc errors by failure class --- .../tests/device_family.rs | 2 +- packages/d2b-provider-endpoint/src/driver.rs | 10 +-- packages/d2b-provider-guest/src/driver.rs | 8 +- packages/d2b-provider-host/src/driver.rs | 6 +- packages/d2b-provider-process/src/driver.rs | 24 +++--- packages/d2b-provider-provider/src/driver.rs | 6 +- packages/d2b-provider-user/src/driver.rs | 6 +- .../d2b-provider-volume-binding/src/driver.rs | 4 +- packages/d2b-provider-volume/src/driver.rs | 2 +- packages/d2b-resource-runtime/src/context.rs | 82 ++++++++++--------- packages/d2b-resource-runtime/src/error.rs | 12 ++- packages/d2b-resource-runtime/src/manager.rs | 63 +++++++------- packages/d2b-resource-runtime/src/metadata.rs | 4 +- 13 files changed, 119 insertions(+), 110 deletions(-) diff --git a/packages/d2b-provider-device/tests/device_family.rs b/packages/d2b-provider-device/tests/device_family.rs index f32643f88..615629150 100644 --- a/packages/d2b-provider-device/tests/device_family.rs +++ b/packages/d2b-provider-device/tests/device_family.rs @@ -37,7 +37,7 @@ impl ManagerEndpoint for DeadManager { _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - Err(ResourceError::ManagerRpc("manager unavailable".to_owned())) + Err(ResourceError::ManagerUnavailable("manager unavailable".to_owned())) } async fn get(&self, _key: &ResourceKey) -> Result, ResourceError> { diff --git a/packages/d2b-provider-endpoint/src/driver.rs b/packages/d2b-provider-endpoint/src/driver.rs index 5db4bd1d2..59b72a823 100644 --- a/packages/d2b-provider-endpoint/src/driver.rs +++ b/packages/d2b-provider-endpoint/src/driver.rs @@ -651,27 +651,27 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn get( &self, _key: &ResourceKey, ) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn view( &self, _key: &ResourceKey, ) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { self.deleted.lock().push(key.clone()); // async-gate-allow: synchronous lock acquisition, no await while the guard is held self.owned.lock().retain(|row| row.key != *key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn list_owned( @@ -686,7 +686,7 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index 423c963c3..5813b0ad4 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -1568,7 +1568,7 @@ mod tests { self.children_ready.store(ready, std::sync::atomic::Ordering::SeqCst); } - /// Make every read answer `ManagerRpc` (the unanswerable plane). + /// Make every read answer `ManagerUnavailable` (the unanswerable plane). fn set_fail_reads(&self, fail: bool) { self.fail_reads.store(fail, std::sync::atomic::Ordering::SeqCst); } @@ -1702,7 +1702,7 @@ mod tests { ) -> Result, ResourceError> { self.calls.lock().push(format!("get:{}/{}", key.type_name, key.name)); // async-gate-allow: synchronous lock acquisition, no await while the guard is held if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { - return Err(ResourceError::ManagerRpc("scripted read failure".into())); + return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } Ok(self .rows @@ -1715,7 +1715,7 @@ mod tests { async fn view(&self, key: &ResourceKey) -> Result, ResourceError> { self.calls.lock().push(format!("view:{}/{}", key.type_name, key.name)); // async-gate-allow: synchronous lock acquisition, no await while the guard is held if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { - return Err(ResourceError::ManagerRpc("scripted read failure".into())); + return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } Ok(self .views @@ -1737,7 +1737,7 @@ mod tests { ) -> Result, ResourceError> { self.calls.lock().push("list-owned".to_owned()); if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { - return Err(ResourceError::ManagerRpc("scripted read failure".into())); + return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } Ok(self .rows diff --git a/packages/d2b-provider-host/src/driver.rs b/packages/d2b-provider-host/src/driver.rs index 0a185f16c..631473120 100644 --- a/packages/d2b-provider-host/src/driver.rs +++ b/packages/d2b-provider-host/src/driver.rs @@ -552,7 +552,7 @@ mod tests { _child: ChildEnsure, ) -> Result { self.calls.lock().await.push("ensure-child"); - Err(ResourceError::ManagerRpc("unexpected ensure_child".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected ensure_child".into() }) } async fn get( @@ -568,7 +568,7 @@ mod tests { _key: &ResourceKey, ) -> Result, ResourceError> { self.calls.lock().await.push("view"); - Err(ResourceError::ManagerRpc("unexpected view".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected view".into() }) } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { @@ -578,7 +578,7 @@ mod tests { owned.retain(|row| row.key != *key); Ok(()) } else { - Err(ResourceError::ManagerRpc("unexpected delete".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected delete".into() }) } } diff --git a/packages/d2b-provider-process/src/driver.rs b/packages/d2b-provider-process/src/driver.rs index 004d33262..cb29ae3a7 100644 --- a/packages/d2b-provider-process/src/driver.rs +++ b/packages/d2b-provider-process/src/driver.rs @@ -2330,32 +2330,32 @@ mod tests { _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn get( &self, _key: &ResourceKey, ) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn view( &self, _key: &ResourceKey, ) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn delete(&self, _key: &ResourceKey) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn list_owned( &self, _owner_uid: [u8; 16], ) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn register_watch( @@ -2363,14 +2363,14 @@ mod tests { _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } async fn cancel_watch( &self, _watch: d2b_resource_runtime::context::WatchId, ) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("dead".into())) + Err(ResourceError::ManagerUnavailable("dead".into())) } } @@ -2416,7 +2416,7 @@ mod tests { _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - Err(ResourceError::ManagerRpc("unexpected ensure_child".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected ensure_child".into() }) } async fn get( @@ -2430,7 +2430,7 @@ mod tests { &self, _key: &ResourceKey, ) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("unexpected view".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected view".into() }) } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { @@ -2451,9 +2451,9 @@ mod tests { _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - Err(ResourceError::ManagerRpc( - "unexpected register_watch".into(), - )) + Err(ResourceError::ManagerRejected { + reason: "unexpected register_watch".into(), + }) } async fn cancel_watch( diff --git a/packages/d2b-provider-provider/src/driver.rs b/packages/d2b-provider-provider/src/driver.rs index f861b953f..f87817ecf 100644 --- a/packages/d2b-provider-provider/src/driver.rs +++ b/packages/d2b-provider-provider/src/driver.rs @@ -825,7 +825,7 @@ mod tests { _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - Err(ResourceError::ManagerRpc("unexpected ensure_child".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected ensure_child".into() }) } async fn get( @@ -842,7 +842,7 @@ mod tests { .expect("calls") .push(format!("view:{}/{}", key.type_name, key.name)); if self.fail_reads.load(Ordering::SeqCst) { - return Err(ResourceError::ManagerRpc("scripted read failure".into())); + return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } Ok(self.view_of(key)) } @@ -871,7 +871,7 @@ mod tests { .expect("calls") .push("list-owned".to_owned()); if self.fail_reads.load(Ordering::SeqCst) { - return Err(ResourceError::ManagerRpc("scripted read failure".into())); + return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } Ok(self .rows diff --git a/packages/d2b-provider-user/src/driver.rs b/packages/d2b-provider-user/src/driver.rs index e2142ee23..bde49abf3 100644 --- a/packages/d2b-provider-user/src/driver.rs +++ b/packages/d2b-provider-user/src/driver.rs @@ -506,7 +506,7 @@ mod tests { _child: ChildEnsure, ) -> Result { self.calls.lock().push("ensure-child"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - Err(ResourceError::ManagerRpc("unexpected ensure_child".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected ensure_child".into() }) } async fn get( @@ -522,7 +522,7 @@ mod tests { _key: &ResourceKey, ) -> Result, ResourceError> { self.calls.lock().push("view"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - Err(ResourceError::ManagerRpc("unexpected view".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected view".into() }) } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { @@ -532,7 +532,7 @@ mod tests { owned.retain(|row| row.key != *key); Ok(()) } else { - Err(ResourceError::ManagerRpc("unexpected delete".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected delete".into() }) } } diff --git a/packages/d2b-provider-volume-binding/src/driver.rs b/packages/d2b-provider-volume-binding/src/driver.rs index f0a485399..89effd5ab 100644 --- a/packages/d2b-provider-volume-binding/src/driver.rs +++ b/packages/d2b-provider-volume-binding/src/driver.rs @@ -1168,7 +1168,7 @@ mod tests { } } - /// Make `get` answer `ManagerRpc` (the unanswerable plane). + /// Make `get` answer `ManagerUnavailable` (the unanswerable plane). fn set_fail_reads(&self, fail: bool) { self.fail_reads.store(fail, std::sync::atomic::Ordering::SeqCst); } @@ -1270,7 +1270,7 @@ mod tests { key: &ResourceKey, ) -> Result, ResourceError> { if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { - return Err(ResourceError::ManagerRpc("scripted read failure".into())); + return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } Ok(self.rows.lock().iter().find(|row| row.key == *key).cloned()) // async-gate-allow: synchronous lock acquisition, no await while the guard is held } diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index 4f3dd1706..73c232137 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -879,7 +879,7 @@ mod tests { _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - Err(ResourceError::ManagerRpc("watches unused in this unit".into())) + Err(ResourceError::ManagerRejected { reason: "watches unused in this unit".into() }) } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { diff --git a/packages/d2b-resource-runtime/src/context.rs b/packages/d2b-resource-runtime/src/context.rs index cf0db810b..560fd01e5 100644 --- a/packages/d2b-resource-runtime/src/context.rs +++ b/packages/d2b-resource-runtime/src/context.rs @@ -529,7 +529,9 @@ impl ResourceContext { /// observed state of the current row. /// [`ResourceView::observed_status`] folds both of the last two cases /// into `None`. - /// - `Err(ResourceError::ManagerRpc(_))`: the manager could not answer. + /// - `Err(ResourceError::ManagerUnavailable(_))`: the manager could not + /// answer; `Err(ResourceError::ManagerRejected { .. })`: the manager + /// refused the call. /// Never reported as absence. /// /// Readiness of a child or dependency is therefore @@ -681,23 +683,23 @@ impl ManagerEndpoint for FailClosedManager { _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - Err(ResourceError::ManagerRpc("no manager seam".into())) + Err(ResourceError::ManagerRejected { reason: "no manager seam".into() }) } async fn get(&self, _key: &ResourceKey) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("no manager seam".into())) + Err(ResourceError::ManagerRejected { reason: "no manager seam".into() }) } async fn view(&self, _key: &ResourceKey) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("no manager seam".into())) + Err(ResourceError::ManagerRejected { reason: "no manager seam".into() }) } async fn delete(&self, _key: &ResourceKey) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("no manager seam".into())) + Err(ResourceError::ManagerRejected { reason: "no manager seam".into() }) } async fn list_owned(&self, _owner_uid: [u8; 16]) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("no manager seam".into())) + Err(ResourceError::ManagerRejected { reason: "no manager seam".into() }) } async fn register_watch( @@ -705,11 +707,11 @@ impl ManagerEndpoint for FailClosedManager { _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - Err(ResourceError::ManagerRpc("no manager seam".into())) + Err(ResourceError::ManagerRejected { reason: "no manager seam".into() }) } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("no manager seam".into())) + Err(ResourceError::ManagerRejected { reason: "no manager seam".into() }) } } @@ -844,23 +846,23 @@ pub(crate) mod test_support { #[async_trait::async_trait] impl ManagerEndpoint for DeadManager { async fn ensure_child(&self, _parent: &ResourceKey, _child: ChildEnsure) -> Result { - Err(ResourceError::ManagerRpc("dead manager".into())) + Err(ResourceError::ManagerUnavailable("dead manager".into())) } async fn get(&self, _key: &ResourceKey) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead manager".into())) + Err(ResourceError::ManagerUnavailable("dead manager".into())) } async fn view(&self, _key: &ResourceKey) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead manager".into())) + Err(ResourceError::ManagerUnavailable("dead manager".into())) } async fn delete(&self, _key: &ResourceKey) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("dead manager".into())) + Err(ResourceError::ManagerUnavailable("dead manager".into())) } async fn list_owned(&self, _owner_uid: [u8; 16]) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("dead manager".into())) + Err(ResourceError::ManagerUnavailable("dead manager".into())) } async fn register_watch( @@ -868,11 +870,11 @@ pub(crate) mod test_support { _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - Err(ResourceError::ManagerRpc("dead manager".into())) + Err(ResourceError::ManagerUnavailable("dead manager".into())) } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("dead manager".into())) + Err(ResourceError::ManagerUnavailable("dead manager".into())) } } @@ -900,15 +902,15 @@ pub(crate) mod test_support { #[async_trait::async_trait] impl ManagerEndpoint for OwnedChildrenManager { async fn ensure_child(&self, _parent: &ResourceKey, _child: ChildEnsure) -> Result { - Err(ResourceError::ManagerRpc("unexpected ensure_child".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected ensure_child".into() }) } async fn get(&self, _key: &ResourceKey) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("unexpected get".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected get".into() }) } async fn view(&self, _key: &ResourceKey) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("unexpected view".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected view".into() }) } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { @@ -925,11 +927,11 @@ pub(crate) mod test_support { _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - Err(ResourceError::ManagerRpc("unexpected register_watch".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected register_watch".into() }) } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("unexpected cancel_watch".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected cancel_watch".into() }) } } @@ -1103,8 +1105,8 @@ mod tests { self.tx .send(StubCall::EnsureChild { parent: parent.clone(), child, reply }) .await - .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; - rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? + .map_err(|_| ResourceError::ManagerUnavailable("manager channel closed".into()))?; + rx.await.map_err(|_| ResourceError::ManagerUnavailable("manager dropped the request".into()))? } async fn get(&self, key: &ResourceKey) -> Result, ResourceError> { @@ -1112,8 +1114,8 @@ mod tests { self.tx .send(StubCall::Get { key: key.clone(), reply }) .await - .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; - rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? + .map_err(|_| ResourceError::ManagerUnavailable("manager channel closed".into()))?; + rx.await.map_err(|_| ResourceError::ManagerUnavailable("manager dropped the request".into()))? } async fn view(&self, key: &ResourceKey) -> Result, ResourceError> { @@ -1121,16 +1123,16 @@ mod tests { self.tx .send(StubCall::GetView { key: key.clone(), reply }) .await - .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; - rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? + .map_err(|_| ResourceError::ManagerUnavailable("manager channel closed".into()))?; + rx.await.map_err(|_| ResourceError::ManagerUnavailable("manager dropped the request".into()))? } async fn delete(&self, _key: &ResourceKey) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("delete not exercised in-module".into())) + Err(ResourceError::ManagerRejected { reason: "delete not exercised in-module".into() }) } async fn list_owned(&self, _owner_uid: [u8; 16]) -> Result, ResourceError> { - Err(ResourceError::ManagerRpc("list_owned not exercised in-module".into())) + Err(ResourceError::ManagerRejected { reason: "list_owned not exercised in-module".into() }) } async fn register_watch( @@ -1146,12 +1148,12 @@ mod tests { reply, }) .await - .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; - rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? + .map_err(|_| ResourceError::ManagerUnavailable("manager channel closed".into()))?; + rx.await.map_err(|_| ResourceError::ManagerUnavailable("manager dropped the request".into()))? } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { - Err(ResourceError::ManagerRpc("cancel_watch not exercised in-module".into())) + Err(ResourceError::ManagerRejected { reason: "cancel_watch not exercised in-module".into() }) } } @@ -1223,19 +1225,19 @@ mod tests { } /// A closed manager channel or a dropped request surfaces as - /// `ResourceError::ManagerRpc`, never as a silent no-op. + /// `ResourceError::ManagerUnavailable`, never as a silent no-op. #[tokio::test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - async fn manager_failures_surface_as_manager_rpc_errors() { + async fn manager_failures_surface_as_manager_unavailable() { // Channel closed before the call. let (tx, rx) = mpsc::channel::(1); drop(rx); let endpoint = ChannelEndpointStub::new(tx); let key = ResourceKey::new("z", "Volume", "data"); let error = endpoint.get(&key).await.unwrap_err(); - assert!(matches!(error, ResourceError::ManagerRpc(_))); + assert!(matches!(error, ResourceError::ManagerUnavailable(_))); let error = endpoint.view(&key).await.unwrap_err(); - assert!(matches!(error, ResourceError::ManagerRpc(_)), "the live read fails loudly too"); + assert!(matches!(error, ResourceError::ManagerUnavailable(_)), "the live read fails loudly too"); // Manager receives the request and drops it without replying. let (tx, mut rx) = mpsc::channel::(1); @@ -1244,15 +1246,15 @@ mod tests { let _ = rx.recv().await; // take the request, never reply }); let error = endpoint.get(&key).await.unwrap_err(); - assert!(matches!(error, ResourceError::ManagerRpc(_))); + assert!(matches!(error, ResourceError::ManagerUnavailable(_))); } /// The live read (`ResourceContext::get_view`, `ManagerEndpoint::view`) /// never fabricates absence: a request the manager drops without - /// replying surfaces as `ResourceError::ManagerRpc`. + /// replying surfaces as `ResourceError::ManagerUnavailable`. #[tokio::test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - async fn dropped_view_request_surfaces_as_manager_rpc_error() { + async fn dropped_view_request_surfaces_as_manager_unavailable() { let (tx, mut rx) = mpsc::channel::(1); let endpoint = ChannelEndpointStub::new(tx); tokio::spawn(async move { @@ -1260,7 +1262,7 @@ mod tests { }); let key = ResourceKey::new("z", "Volume", "data"); let error = endpoint.view(&key).await.unwrap_err(); - assert!(matches!(error, ResourceError::ManagerRpc(_))); + assert!(matches!(error, ResourceError::ManagerUnavailable(_))); } /// One classified read against a scripted manager: `respond` answers the @@ -1328,7 +1330,7 @@ mod tests { // The manager cannot answer: unavailable, never absence. let (mut ctx, stub) = scripted_read(|call| match call { StubCall::Get { reply, .. } => { - let _ = reply.send(Err(ResourceError::ManagerRpc("no answer".into()))); + let _ = reply.send(Err(ResourceError::ManagerUnavailable("no answer".into()))); } other => panic!("classified lookup sent a non-Get call: {other:?}"), }); diff --git a/packages/d2b-resource-runtime/src/error.rs b/packages/d2b-resource-runtime/src/error.rs index 324ce1b33..024c46790 100644 --- a/packages/d2b-resource-runtime/src/error.rs +++ b/packages/d2b-resource-runtime/src/error.rs @@ -769,10 +769,14 @@ pub enum ResourceError { type_name: String, message: String, }, - /// A call routed to the manager actor failed: its channel closed, the - /// request was dropped, or the manager rejected it. - #[error("manager rpc: {0}")] - ManagerRpc(String), + /// The manager actor could not answer: its channel closed or the + /// request was dropped. Transport failure - retryable by construction. + #[error("manager unavailable: {0}")] + ManagerUnavailable(String), + /// The manager answered with a semantic refusal: the operation is + /// permanent for the row as stated. + #[error("manager rejected: {reason}")] + ManagerRejected { reason: String }, /// A driver reported a structured failure (issue #508). #[error(transparent)] Driver(#[from] DriverFailure), diff --git a/packages/d2b-resource-runtime/src/manager.rs b/packages/d2b-resource-runtime/src/manager.rs index 309b4cf60..4d4cdc5c2 100644 --- a/packages/d2b-resource-runtime/src/manager.rs +++ b/packages/d2b-resource-runtime/src/manager.rs @@ -969,10 +969,10 @@ impl Actor for ResourceManager { } ResourceManagerMsg::Ensure { subject, owner, desired, reply } => { let result = if desired.key.zone != state.zone { - Err(ResourceError::ManagerRpc(format!( + Err(ResourceError::ManagerRejected { reason: format!( "resource zone {} does not belong to manager zone {}", desired.key.zone, state.zone - ))) + ) }) } else { match resolve_owner(state, owner.as_ref()) { Ok(owner_uid) => { @@ -1096,9 +1096,9 @@ impl Actor for ResourceManager { } } } - None => Err(ResourceError::ManagerRpc(format!( + None => Err(ResourceError::ManagerRejected { reason: format!( "parent {parent} is not known to the manager" - ))), + ) }), }; reply.send(result).ok(); } @@ -1246,9 +1246,9 @@ fn resolve_owner( None => Ok(None), Some(owner_key) => match state.rows.get(owner_key) { Some(row) => Ok(Some(row.uid)), - None => Err(ResourceError::ManagerRpc(format!( + None => Err(ResourceError::ManagerRejected { reason: format!( "owner {owner_key} is not known to the manager" - ))), + ) }), }, } } @@ -1294,9 +1294,9 @@ fn reparent_refusal( .get(&existing_owner) .map(ResourceKey::to_string) .unwrap_or_else(|| "an unknown owner".to_owned()); - Some(ResourceError::ManagerRpc(format!( + Some(ResourceError::ManagerRejected { reason: format!( "child {key} is owned by {owner}; refusing re-parent to {parent}" - ))) + ) }) } fn handle_from_outcome(outcome: &EnsureOutcome, actor: ActorRef) -> ResourceHandle { @@ -1319,9 +1319,9 @@ fn register_watch( ) -> Result { let target = registration.target.clone(); let Some(target_actor) = state.actors.get(&target).cloned() else { - return Err(ResourceError::ManagerRpc(format!( + return Err(ResourceError::ManagerRejected { reason: format!( "watch target {target} has no running actor" - ))); + ) }); }; let id = WatchId(state.next_watch_id); state.next_watch_id += 1; @@ -1349,7 +1349,7 @@ async fn reconcile_children( desired: Vec, ) -> Result { let Some(parent_row) = state.rows.get(owner).cloned() else { - return Err(ResourceError::ManagerRpc(format!("owner {owner} is not known to the manager"))); + return Err(ResourceError::ManagerRejected { reason: format!("owner {owner} is not known to the manager") }); }; let subject = MutationSubject { principal: owner.to_string(), origin: ResourceProvenance::Resource }; @@ -1410,8 +1410,8 @@ async fn manager_rpc( let (reply, rx) = oneshot::channel(); actor .send_message(build(reply)) - .map_err(|_| ResourceError::ManagerRpc("manager channel closed".into()))?; - rx.await.map_err(|_| ResourceError::ManagerRpc("manager dropped the request".into()))? + .map_err(|_| ResourceError::ManagerUnavailable("manager channel closed".into()))?; + rx.await.map_err(|_| ResourceError::ManagerUnavailable("manager dropped the request".into()))? } /// The manager endpoint injected into every driver context (R2): all @@ -1526,8 +1526,8 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the manager channel is closed or - /// the request is dropped; [`ResourceError::AdmissionDenied`] when + /// [`ResourceError::ManagerUnavailable`] when the manager channel is + /// closed or the request is dropped; [`ResourceError::AdmissionDenied`] when /// mutation admission refuses; [`ResourceError::Provider`] when no /// driver factory can produce the resource; [`ResourceError::Store`] on /// durable store failure; [`ResourceError::DeletingConflict`] when the @@ -1546,8 +1546,8 @@ impl ResourceManagerClient { /// # Errors /// /// Beyond the [`Self::apply`] variants: - /// [`ResourceError::ManagerRpc`] also when the desired zone is not the - /// manager's zone or the named owner is not known to the manager. + /// [`ResourceError::ManagerRejected`] also when the desired zone is not + /// the manager's zone or the named owner is not known to the manager. pub async fn ensure( &self, subject: MutationSubject, @@ -1561,7 +1561,7 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the request cannot be routed; + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed; /// [`ResourceError::AdmissionDenied`] when mutation admission refuses; /// [`ResourceError::Store`] on durable store failure; /// [`ResourceError::DeletingConflict`] when the row is already marked @@ -1579,7 +1579,7 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the request cannot be routed. + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed. pub async fn get(&self, key: ResourceKey) -> Result, ResourceError> { self.rpc(|reply| ResourceManagerMsg::Get { key, reply }).await } @@ -1588,7 +1588,7 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the request cannot be routed. + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed. pub async fn list( &self, selector: ResourceSelector, @@ -1601,7 +1601,7 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the request cannot be routed; an + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed; an /// unsupported cursor (older or future epoch, or evicted from the ring) /// is reported as [`WatchRegistration::Expired`] rather than an error. pub async fn watch( @@ -1616,7 +1616,7 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the request cannot be routed. + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed. pub async fn get_row( &self, key: ResourceKey, @@ -1628,7 +1628,7 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the request cannot be routed. + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed. pub async fn list_owned( &self, owner_uid: [u8; 16], @@ -1641,8 +1641,9 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the parent is unknown, the child - /// is owned by a different parent, or the request cannot be routed; + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed, + /// [`ResourceError::ManagerRejected`] when the parent is unknown or the + /// child is owned by a different parent; /// [`ResourceError::AdmissionDenied`], [`ResourceError::Provider`], /// [`ResourceError::Store`], and /// [`ResourceError::DeletingConflict`] as for [`Self::apply`]. @@ -1658,8 +1659,9 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the watch target has no running - /// actor or the request cannot be routed. + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed, + /// [`ResourceError::ManagerRejected`] when the watch target has no + /// running actor. pub async fn register_watch( &self, subscriber: ResourceKey, @@ -1672,7 +1674,7 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the request cannot be routed. + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed. pub async fn cancel_watch(&self, watch: WatchId) -> Result<(), ResourceError> { self.rpc(|reply| ResourceManagerMsg::CancelWatch { watch, reply }).await } @@ -1683,8 +1685,9 @@ impl ResourceManagerClient { /// /// # Errors /// - /// [`ResourceError::ManagerRpc`] when the owner is unknown, a child - /// would be re-parented, or the request cannot be routed; + /// [`ResourceError::ManagerUnavailable`] when the request cannot be + /// routed, [`ResourceError::ManagerRejected`] when the owner is unknown + /// or a child would be re-parented; /// [`ResourceError::AdmissionDenied`], [`ResourceError::Provider`], and /// [`ResourceError::Store`] as for [`Self::apply`]. pub async fn reconcile_children( diff --git a/packages/d2b-resource-runtime/src/metadata.rs b/packages/d2b-resource-runtime/src/metadata.rs index 7e126c72a..ef9d4a09d 100644 --- a/packages/d2b-resource-runtime/src/metadata.rs +++ b/packages/d2b-resource-runtime/src/metadata.rs @@ -305,7 +305,7 @@ mod tests { _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - Err(ResourceError::ManagerRpc("unexpected ensure_child".into())) + Err(ResourceError::ManagerRejected { reason: "unexpected ensure_child".into() }) } async fn get( @@ -331,7 +331,7 @@ mod tests { ) -> Result, ResourceError> { self.calls.lock().await.push("list-owned"); if self.fail_reads.load(Ordering::SeqCst) { - return Err(ResourceError::ManagerRpc("scripted read failure".into())); + return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } Ok(self.owned.lock().await.clone()) } From a81fc35f82d42d5ad88382b908f05e951881ed0e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:12:28 -0700 Subject: [PATCH 440/726] audit: fold the resource toolkit slice --- .../2026-09-24-rust-skills-audit/ledger.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 228bbd3c4..8842ef446 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -391,7 +391,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Narrowing pub methods in the published crate is a published-surface move; additionally the lane census is stale: HelperLaunchRequest::validate_bounds has a live external caller at d2b-unsafe-local-hel | | | `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src` | | | -| `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/identity.rs:269-270` | | | +| `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 67393687b13c359ac6b3a96bca469d28e25c7c96 | packages/d2b-contracts-resource/src/v3/identity.rs | Deleted the zero-caller alias and its doc. Census re-run: ValidatedSessionPurpose over worktree = 1 hit (the definition); no re-export arm in v3/mod.rs. cargo check -p d2b-contracts-resource --locked | | | `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | | `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs | Deleted EmergencyPolicySpec::default_values(); Default::default() now constructs directly. Census: the Default impl was the only caller. | | | `RS-0339` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone.rs | Removed ZoneSpec::validate (always-Ok). Census: no callers anywhere in the workspace or in-crate tests; the Deserialize gate remains the invariant. | | @@ -466,8 +466,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/lib.rs:40, src/ownership.rs:42` | | | | `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/host.rs:419, src/host.rs:134` | | | | `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/lib.rs:70` | | | -| `RS-0414` | `api` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/fd10.rs:888, packages/d2b-provider-toolkit/src/base` | | | -| `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/server/service.rs:297-299, packages/d2b-provider-toolkit` | | | +| `RS-0414` | `api` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | 0623be33bf4894fc796b0f603508b2570b746b7d | packages/d2b-provider-toolkit/Cargo.toml | Added test-support = [] feature; gated both constructors with #[cfg(any(test, feature = "test-support"))]; required-features on the supervised_runtime test target; added test-support to the Bazel test | | +| `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | 81f51276ed7456104a034c40ba5b3c45bba8c790 | packages/d2b-provider-toolkit/src/server/service.rs | Deleted response_request_id and generated_service plus the response_request_id doc; narrowed the now-unused RequestId import; kept generated_services(). Census re-run: both symbols over worktree = 0 c | | | `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | | `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | | `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs | | | @@ -483,8 +483,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | wire_revision and api_subject narrowed to pub(crate). resource_owner_subject stays pub because its U9/U10 caller has landed at HEAD: d2bd/src/resource_runtime/plane_controller_bridge.rs:369 (subject() | | | `RS-0429` | `api` | `d2b-resource-client` | medium | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:83, packages/d2b-resource-client/src/zone_` | | | | `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | | | | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | -| `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/target.rs:491-493` | | | -| `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:460-462` | | | +| `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | 0cd7b063d | packages/d2b-resource-runtime/src/target.rs | Removed TargetBinding::directory() accessor. Census re-run: zero callers; the directory field stays read by internal methods (observe/delete/adopt), no dead code. cargo check/test/clippy green for d2b | | +| `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | U3 | 3570364e0 | packages/d2b-resource-runtime/src/guest_target.rs | Removal as written orphans GuestTargetInner.reference (dead-code deny) and forces a public constructor signature change across 26 call sites in 5 files incl. d2bd production (published surface -> cont | | | `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | | | | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | | | | `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/fragmentation.rs | Fragment.header is now private with a pub header() accessor; the two engine.rs encode call sites (877, 1395) use the accessor. Census: no external field access. | | | `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | @@ -560,7 +560,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServiceDriverError carries source: Option> with Error::source(); the Err(_) swallow in reconcile_service now attaches the store error and classify_error surfaces it as a fa | | | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | | `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | -| `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-to` | | | +| `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | de1a2c493eb2db826cd517128364c759a86240d9 | packages/d2b-provider-toolkit/src/operations/envelope.rs | audit_named falls back to the canonical (lowercase, dash-stripped) spelling when BoundedToken::parse rejects the raw name, so a refused PascalCase forwarded invocation lands its Denied record; already | | | `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | | `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | | `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | @@ -573,8 +573,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | applied | U3 | e783447e2 | packages/d2b-provider-wayland-session/Cargo.toml | Added tracing = 0.1 (already in lockfile; Cargo.lock records one new dep edge) and map_err now logs provider=WAYLAND_SESSION_PROVIDER_REF with reason=%error before mapping to InvalidResource. | | | `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Empty batch now rejected with 'batch mutation count is zero'; MAX_BATCH_MUTATIONS check keeps the bound reason. Reason string unpinned in error-codes.md. | | | `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | 854ba06a5 | packages/d2b-resource-client/src/call.rs | The three Mutex::lock().unwrap() sites in the waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) now use expect with the written reason: no user code runs u | | -| `RS-0520` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/error.rs:773, packages/d2b-resource-runtime/src/manager.` | | | -| `RS-0521` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | | | | `packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spe` | | | +| `RS-0520` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | fa4907468 | packages/d2b-resource-runtime/src/error.rs | Split ManagerRpc(String) into ManagerUnavailable(String) (transport: channel closed, dropped request, dead-manager test doubles) and ManagerRejected { reason } (semantic: zone mismatch, unknown owner, | | +| `RS-0521` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | adb285984 | packages/d2b-resource-runtime/src/spec_store.rs | Added SpecStoreError::CorruptRow { zone, type_name, name }; row_from returns it instead of try_into().unwrap_or([0; 16]) for uid and owner_uid; load_row/list switched from query_row/query_map closures | | | `RS-0522` | `err` | `d2b-session` | medium | actionable | leaf | applied-variant | U3 | afb1fa59c | packages/d2b-session/src/transport.rs | Applied the typestate option minimally: the Option> wrapper is gone (plain Box), so the consumed state is unrepresentable and all three expects disappeared; public signatures a | | | `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | | `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | | | @@ -648,7 +648,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-system` | | | | `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | | `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | -| `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src` | | | +| `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | abc324d2a | packages/d2b-provider-toolkit/src/base/guest.rs | serve_enrolled now emits tracing::warn!(frame_bytes, ...) before dropping a frame GuestFrame::new rejects (empty or oversized), keeping the session up. No correlation identifiers in the record. cargo | | | `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | | | | `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/relay_transport.rs | | | | `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | From c44532f1d9787c124a8941231470e47b49f5af40 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:12:55 -0700 Subject: [PATCH 441/726] host: seal the HostPrepStepId inner string --- packages/d2b-host/src/host_prep_dag.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-host/src/host_prep_dag.rs b/packages/d2b-host/src/host_prep_dag.rs index e41925603..cd834c555 100644 --- a/packages/d2b-host/src/host_prep_dag.rs +++ b/packages/d2b-host/src/host_prep_dag.rs @@ -82,7 +82,7 @@ use std::fmt; Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] #[serde(transparent)] -pub struct HostPrepStepId(pub String); +pub struct HostPrepStepId(String); impl HostPrepStepId { fn new(vm: &str, kind: HostPrepStepKind) -> Self { From 30711b0976ade322bf1da8f2d3261983b46fc055 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:19:04 -0700 Subject: [PATCH 442/726] audit: fold the contracts resource and system core slice --- .../2026-09-24-rust-skills-audit/ledger.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 8842ef446..1f37eb109 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -308,7 +308,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-res` | | | | `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | | `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-r` | | | -| `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resou` | | | +| `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises — `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | | `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | packages/d2b-provider-transport-azure-relay/contrast-zone-session/src/v3/role_binding.rs | | | | `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | | | | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | @@ -323,7 +323,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard` | | | | `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixo` | | | | `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | applied-variant | U3 | 1ce473a70 | packages/d2b-provider-credential/src/driver.rs | zone: String -> d2b_contracts_resource::v3::ZoneId in CredentialDriverArgs and CredentialDriver; agent_child builds the zone ref with expect on a validated ZoneId (fallible ResourceRef::parse path dro | | -| `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | | | | `controller.rs:85-89, tests/binding.rs:1214-1234` | | | +| `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | applied | U3 | cd8838c03 | packages/d2b-provider-credential-managed-identity/src/controller.rs | seal `ManagedIdentityTeardownPlan`'s three bool fields behind `pub const fn` accessors so invalid combos (stop_agent && delete_agent, delete_agent && clear_provider_revoke) are unrepresentable; tests | | | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | | `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | | `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | @@ -390,7 +390,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | | | | `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Narrowing pub methods in the published crate is a published-surface move; additionally the lane census is stale: HelperLaunchRequest::validate_bounds has a live external caller at d2b-unsafe-local-hel | | | `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | -| `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src` | | | +| `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | | `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 67393687b13c359ac6b3a96bca469d28e25c7c96 | packages/d2b-contracts-resource/src/v3/identity.rs | Deleted the zero-caller alias and its doc. Census re-run: ValidatedSessionPurpose over worktree = 1 hit (the definition); no re-export arm in v3/mod.rs. cargo check -p d2b-contracts-resource --locked | | | `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | | `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs | Deleted EmergencyPolicySpec::default_values(); Default::default() now constructs directly. Census: the Default impl was the only caller. | | @@ -420,7 +420,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | | | | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | | | | `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | | `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | -| `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:612-618` | | | +| `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | drop the zero-caller `ManagedIdentityPlacement::in_zone` constructor (exact duplicate of `new`); census over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 consumers outside the definit | | | `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | | | | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effe` | | | | `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U3 | 539ca5113 | packages/d2b-provider-device-gpu/src/lib.rs | gpu_argv/video_argv made private; root re-exports keep one reachable path per item. Census re-run: `d2b_provider_device_gpu::(gpu_argv/video_argv)::` over packages/nixos-modules/tests/docs/reference/l | | | `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U3 | 4efbf8ea5 | packages/d2b-provider-device-gpu/src/effects_service.rs | applied-variant: row's second option (single crate-owned sidecar) used: DeclaredWorkerGpuPortDeps sidecar (private fields, pub 4-arg ::new) holds the four dependency types; DeclaredWorkerGpuPortArgs ( | | @@ -461,11 +461,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | | | | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | | `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2bd/src/process_provider_run` | | | | `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | | | | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | | | -| `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | | | | `src/lib.rs:41, src/testing.rs:23` | | | +| `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | | `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | | | | `src/host.rs:389, src/host.rs:13` | | | -| `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/lib.rs:40, src/ownership.rs:42` | | | -| `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/host.rs:419, src/host.rs:134` | | | -| `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/lib.rs:70` | | | +| `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | make the `ownership` module private; the root re-export of the owned/disowned type lists is the single surface. Shares commit 31ff8b396 with RS-0409 (the audit's own census pairs these two module-surf | | +| `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | narrow `reconcile_observed`/`HostProbeSnapshot` to `pub(crate)` with the crate-internal-only callers retained; drop the now-private seam from the crate's pub re-export. Shares commit 31ff8b396 with th | | +| `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | forward `HostProbeMetadata` from the host re-export while dropping the zero-external-consumer `HostProbeSnapshot` constant from the public surface; the crate's probe seam stays internal until a consum | | | `RS-0414` | `api` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | 0623be33bf4894fc796b0f603508b2570b746b7d | packages/d2b-provider-toolkit/Cargo.toml | Added test-support = [] feature; gated both constructors with #[cfg(any(test, feature = "test-support"))]; required-features on the supervised_runtime test target; added test-support to the Bazel test | | | `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | 81f51276ed7456104a034c40ba5b3c45bba8c790 | packages/d2b-provider-toolkit/src/server/service.rs | Deleted response_request_id and generated_service plus the response_request_id doc; narrowed the now-unused RequestId import; kept generated_services(). Census re-run: both symbols over worktree = 0 c | | | `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | @@ -541,7 +541,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clip` | | | | `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provide` | | | | `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixo` | | | -| `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `lib.rs:1261-1262` | | | +| `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | export_checkpoints now rejects an unparseable lease-map key with the crate's typed `InvariantFailure` refusal instead of a `.expect()` panic; shares commit dbec5dde7 with RS-0368 (same lib.rs surface, | | | `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | | `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `state_machine.rs:378-386` | | | | `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | 263eea211 | packages/d2b-provider-display-wayland/src/controller.rs | DisplayController::new returns Result with # Errors doc; 2 daemon sites use expect/unwrap; all call sites updated. | | From 6a3ac39da0aa1c50b2a092bc3ad509d290f9eec2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:21:41 -0700 Subject: [PATCH 443/726] d2b-contracts: type validator errors and gate MediaRef construction --- packages/d2b-contracts/src/audit_wire.rs | 28 ++- packages/d2b-contracts/src/configured_argv.rs | 64 +++++-- packages/d2b-contracts/src/launcher.rs | 39 +++- packages/d2b-contracts/src/types.rs | 97 ++++++++-- .../src/unsafe_local_workloads.rs | 172 +++++++++++++----- 5 files changed, 316 insertions(+), 84 deletions(-) diff --git a/packages/d2b-contracts/src/audit_wire.rs b/packages/d2b-contracts/src/audit_wire.rs index 978b3a1cf..be8d7d778 100644 --- a/packages/d2b-contracts/src/audit_wire.rs +++ b/packages/d2b-contracts/src/audit_wire.rs @@ -48,13 +48,35 @@ impl core::fmt::Debug for AuditExportEntry { } } +/// Failure classes for [`validate_audit_page`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AuditPageError { + CompleteWithCursor, + IncompleteWithoutCursor, +} + +impl core::fmt::Display for AuditPageError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + AuditPageError::CompleteWithCursor => { + f.write_str("complete audit page must omit nextCursor") + } + AuditPageError::IncompleteWithoutCursor => { + f.write_str("incomplete audit page requires nextCursor") + } + } + } +} + +impl std::error::Error for AuditPageError {} + pub fn validate_audit_page( complete: bool, next_cursor: Option<&AuditExportCursor>, -) -> Result<(), &'static str> { +) -> Result<(), AuditPageError> { match (complete, next_cursor.is_some()) { - (true, true) => Err("complete audit page must omit nextCursor"), - (false, false) => Err("incomplete audit page requires nextCursor"), + (true, true) => Err(AuditPageError::CompleteWithCursor), + (false, false) => Err(AuditPageError::IncompleteWithoutCursor), _ => Ok(()), } } diff --git a/packages/d2b-contracts/src/configured_argv.rs b/packages/d2b-contracts/src/configured_argv.rs index eb6e7503f..6f0587d3a 100644 --- a/packages/d2b-contracts/src/configured_argv.rs +++ b/packages/d2b-contracts/src/configured_argv.rs @@ -6,13 +6,49 @@ pub const MAX_CONFIGURED_ARGC: usize = 128; pub const MAX_CONFIGURED_ARG_BYTES: usize = 16 * 1024; pub const MAX_CONFIGURED_ARG_LEN: usize = 4096; +/// Failure classes for [`ConfiguredArgv`] construction. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConfiguredArgvError { + Empty, + TooManyArgs { max: usize }, + NulByte, + ArgTooLong { max: usize }, + ByteCountOverflow, + TooManyBytes { max: usize }, +} + +impl core::fmt::Display for ConfiguredArgvError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ConfiguredArgvError::Empty => f.write_str("configured argv must not be empty"), + ConfiguredArgvError::TooManyArgs { max } => { + write!(f, "configured argv exceeds {max} arguments") + } + ConfiguredArgvError::NulByte => { + f.write_str("configured argv must not contain NUL") + } + ConfiguredArgvError::ArgTooLong { max } => { + write!(f, "configured argv argument exceeds {max} bytes") + } + ConfiguredArgvError::ByteCountOverflow => { + f.write_str("configured argv byte count overflow") + } + ConfiguredArgvError::TooManyBytes { max } => { + write!(f, "configured argv exceeds {max} bytes") + } + } + } +} + +impl std::error::Error for ConfiguredArgvError {} + /// Serialized configured argv whose debug representation is always redacted. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(transparent)] pub struct ConfiguredArgv(Vec); impl ConfiguredArgv { - pub fn new(argv: Vec) -> Result { + pub fn new(argv: Vec) -> Result { validate_argv(&argv)?; Ok(Self(argv)) } @@ -45,33 +81,33 @@ impl<'de> Deserialize<'de> for ConfiguredArgv { } } -fn validate_argv(argv: &[String]) -> Result<(), String> { +fn validate_argv(argv: &[String]) -> Result<(), ConfiguredArgvError> { if argv.is_empty() { - return Err("configured argv must not be empty".to_owned()); + return Err(ConfiguredArgvError::Empty); } if argv.len() > MAX_CONFIGURED_ARGC { - return Err(format!( - "configured argv exceeds {MAX_CONFIGURED_ARGC} arguments" - )); + return Err(ConfiguredArgvError::TooManyArgs { + max: MAX_CONFIGURED_ARGC, + }); } let mut bytes = 0usize; for arg in argv { if arg.contains('\0') { - return Err("configured argv must not contain NUL".to_owned()); + return Err(ConfiguredArgvError::NulByte); } if arg.len() > MAX_CONFIGURED_ARG_LEN { - return Err(format!( - "configured argv argument exceeds {MAX_CONFIGURED_ARG_LEN} bytes" - )); + return Err(ConfiguredArgvError::ArgTooLong { + max: MAX_CONFIGURED_ARG_LEN, + }); } bytes = bytes .checked_add(arg.len()) - .ok_or_else(|| "configured argv byte count overflow".to_owned())?; + .ok_or(ConfiguredArgvError::ByteCountOverflow)?; } if bytes > MAX_CONFIGURED_ARG_BYTES { - return Err(format!( - "configured argv exceeds {MAX_CONFIGURED_ARG_BYTES} bytes" - )); + return Err(ConfiguredArgvError::TooManyBytes { + max: MAX_CONFIGURED_ARG_BYTES, + }); } Ok(()) } diff --git a/packages/d2b-contracts/src/launcher.rs b/packages/d2b-contracts/src/launcher.rs index 6e0d57c30..64b8ce03d 100644 --- a/packages/d2b-contracts/src/launcher.rs +++ b/packages/d2b-contracts/src/launcher.rs @@ -8,6 +8,35 @@ use serde::{Deserialize, Serialize}; pub const REALM_WORKLOADS_LAUNCHER_V2_SCHEMA_VERSION: &str = "v2"; +/// Failure classes for [`RealmWorkloadsLauncherV2Json::validate`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LauncherMetadataError { + SchemaVersionMismatch { expected: &'static str }, + InvariantsNotAllTrue, +} + +impl core::fmt::Display for LauncherMetadataError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + LauncherMetadataError::SchemaVersionMismatch { expected } => write!( + f, + "realm-workloads-launcher-v2 schemaVersion must be {expected}" + ), + LauncherMetadataError::InvariantsNotAllTrue => { + f.write_str("realm-workloads-launcher-v2 invariants must all be true") + } + } + } +} + +impl std::error::Error for LauncherMetadataError {} + +impl From for String { + fn from(error: LauncherMetadataError) -> String { + error.to_string() + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct RealmWorkloadsLauncherV2Json { @@ -18,11 +47,11 @@ pub struct RealmWorkloadsLauncherV2Json { } impl RealmWorkloadsLauncherV2Json { - pub fn validate(&self) -> Result<(), String> { + pub fn validate(&self) -> Result<(), LauncherMetadataError> { if self.schema_version != REALM_WORKLOADS_LAUNCHER_V2_SCHEMA_VERSION { - return Err(format!( - "realm-workloads-launcher-v2 schemaVersion must be {REALM_WORKLOADS_LAUNCHER_V2_SCHEMA_VERSION}" - )); + return Err(LauncherMetadataError::SchemaVersionMismatch { + expected: REALM_WORKLOADS_LAUNCHER_V2_SCHEMA_VERSION, + }); } let invariants = &self.invariants; if !(invariants.argv_private @@ -31,7 +60,7 @@ impl RealmWorkloadsLauncherV2Json { && invariants.realm_accent_color_only && invariants.no_secrets_or_credentials) { - return Err("realm-workloads-launcher-v2 invariants must all be true".to_owned()); + return Err(LauncherMetadataError::InvariantsNotAllTrue); } Ok(()) } diff --git a/packages/d2b-contracts/src/types.rs b/packages/d2b-contracts/src/types.rs index 93b03f6e7..53ebbb10d 100644 --- a/packages/d2b-contracts/src/types.rs +++ b/packages/d2b-contracts/src/types.rs @@ -110,51 +110,116 @@ opaque_id! { MediaRef } +/// Failure classes for [`MediaRef`] shape validation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MediaRefError { + Empty, + TooLong { max: usize }, + BadStart, + BadShape, +} + +impl core::fmt::Display for MediaRefError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + MediaRefError::Empty => f.write_str("media ref must not be empty"), + MediaRefError::TooLong { max } => write!(f, "media ref must be at most {max} bytes"), + MediaRefError::BadStart => { + f.write_str("media ref must start with a lowercase ASCII letter") + } + MediaRefError::BadShape => f.write_str( + "media ref may contain only lowercase ASCII letters, digits, and '-'", + ), + } + } +} + +impl std::error::Error for MediaRefError {} + impl MediaRef { - pub fn validate_value(value: &str) -> Result<(), String> { + /// Validate a media-ref spelling. Returns [`MediaRefError`] on malformed + /// input (fail-closed). + pub fn validate_value(value: &str) -> Result<(), MediaRefError> { if value.is_empty() { - return Err("media ref must not be empty".to_owned()); + return Err(MediaRefError::Empty); } if value.len() > 63 { - return Err("media ref must be at most 63 bytes".to_owned()); + return Err(MediaRefError::TooLong { max: 63 }); } let mut chars = value.chars(); - let first = chars - .next() - .ok_or_else(|| "media ref must not be empty".to_owned())?; + let first = chars.next().ok_or(MediaRefError::Empty)?; if !first.is_ascii_lowercase() { - return Err("media ref must start with a lowercase ASCII letter".to_owned()); + return Err(MediaRefError::BadStart); } if !std::iter::once(first) .chain(chars) .all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '-') { - return Err( - "media ref may contain only lowercase ASCII letters, digits, and '-'".to_owned(), - ); + return Err(MediaRefError::BadShape); } Ok(()) } } -pub fn validate_usb_bus_id(value: &str) -> Result<(), String> { +/// Parse-gate construction: a media ref can only be built from a spelling +/// that passes [`MediaRef::validate_value`]. +impl TryFrom<&str> for MediaRef { + type Error = MediaRefError; + + fn try_from(value: &str) -> Result { + Self::validate_value(value)?; + Ok(Self(value.to_owned())) + } +} + +/// Failure classes for USB bus-id shape validation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum UsbBusIdError { + Empty, + TooLong { max: usize }, + InvalidEdgePunctuation, + InvalidCharacter, + MissingSeparator, +} + +impl core::fmt::Display for UsbBusIdError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + UsbBusIdError::Empty => f.write_str("USB busid must not be empty"), + UsbBusIdError::TooLong { max } => write!(f, "USB busid must be at most {max} bytes"), + UsbBusIdError::InvalidEdgePunctuation => { + f.write_str("USB busid has invalid edge punctuation") + } + UsbBusIdError::InvalidCharacter => { + f.write_str("USB busid may contain only digits, '-' and '.'") + } + UsbBusIdError::MissingSeparator => { + f.write_str("USB busid must include a bus-port separator '-'") + } + } + } +} + +impl std::error::Error for UsbBusIdError {} + +pub fn validate_usb_bus_id(value: &str) -> Result<(), UsbBusIdError> { if value.is_empty() { - return Err("USB busid must not be empty".to_owned()); + return Err(UsbBusIdError::Empty); } if value.len() > 64 { - return Err("USB busid must be at most 64 bytes".to_owned()); + return Err(UsbBusIdError::TooLong { max: 64 }); } if value.starts_with('-') || value.ends_with('-') || value.ends_with('.') { - return Err("USB busid has invalid edge punctuation".to_owned()); + return Err(UsbBusIdError::InvalidEdgePunctuation); } if !value .chars() .all(|ch| ch.is_ascii_digit() || ch == '-' || ch == '.') { - return Err("USB busid may contain only digits, '-' and '.'".to_owned()); + return Err(UsbBusIdError::InvalidCharacter); } if !value.contains('-') { - return Err("USB busid must include a bus-port separator '-'".to_owned()); + return Err(UsbBusIdError::MissingSeparator); } Ok(()) } diff --git a/packages/d2b-contracts/src/unsafe_local_workloads.rs b/packages/d2b-contracts/src/unsafe_local_workloads.rs index 131a4af70..3c5d268ed 100644 --- a/packages/d2b-contracts/src/unsafe_local_workloads.rs +++ b/packages/d2b-contracts/src/unsafe_local_workloads.rs @@ -18,6 +18,85 @@ pub const MAX_PRIVATE_CONFIGURED_WORKLOADS: usize = pub const MAX_LAUNCHER_ITEMS_PER_WORKLOAD: usize = 64; pub const MAX_UNSAFE_LOCAL_SHELL_SESSIONS: u16 = 64; +/// Failure classes for the private unsafe-local workload artifact. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum UnsafeLocalWorkloadsError { + SchemaVersionMismatch { expected: &'static str }, + TooManyWorkloads { max: usize }, + TooManyLocalVmWorkloads { max: usize }, + TooManyPrivateWorkloads { max: usize }, + DuplicateUnsafeLocalTarget { target: String }, + DuplicateConfiguredTarget { target: String }, + LocalVmRuntimeKindMismatch, + LegacyVmNamePresent, + IdentityMismatch, + NoItems, + TooManyItems { max: usize }, + DuplicateItemId { id: String }, + ShellItemWithoutPolicy, + DefaultItemMissing { id: String }, + ShellDefaultNameInvalid, + ShellMaxSessionsInvalid { max: u16 }, +} + +impl core::fmt::Display for UnsafeLocalWorkloadsError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + UnsafeLocalWorkloadsError::SchemaVersionMismatch { expected } => write!( + f, + "unsafe-local-workloads schemaVersion must be {expected}" + ), + UnsafeLocalWorkloadsError::TooManyWorkloads { max } => { + write!(f, "unsafe-local workload count exceeds {max}") + } + UnsafeLocalWorkloadsError::TooManyLocalVmWorkloads { max } => { + write!(f, "local-vm configured workload count exceeds {max}") + } + UnsafeLocalWorkloadsError::TooManyPrivateWorkloads { max } => { + write!(f, "private configured workload count exceeds {max}") + } + UnsafeLocalWorkloadsError::DuplicateUnsafeLocalTarget { target } => { + write!(f, "duplicate unsafe-local workload target {target}") + } + UnsafeLocalWorkloadsError::DuplicateConfiguredTarget { target } => { + write!(f, "duplicate configured workload target {target}") + } + UnsafeLocalWorkloadsError::LocalVmRuntimeKindMismatch => { + f.write_str("local-vm configured workload must use nixos runtimeKind") + } + UnsafeLocalWorkloadsError::LegacyVmNamePresent => { + f.write_str("unsafe-local workload must not carry legacyVmName") + } + UnsafeLocalWorkloadsError::IdentityMismatch => f.write_str( + "unsafe-local workload identity must use unsafe-local runtimeKind and providerId", + ), + UnsafeLocalWorkloadsError::NoItems => { + f.write_str("configured workload must declare at least one launcher item") + } + UnsafeLocalWorkloadsError::TooManyItems { max } => { + write!(f, "configured launcher item count exceeds {max}") + } + UnsafeLocalWorkloadsError::DuplicateItemId { id } => { + write!(f, "duplicate configured launcher item id {id}") + } + UnsafeLocalWorkloadsError::ShellItemWithoutPolicy => { + f.write_str("shell launcher item requires shell policy") + } + UnsafeLocalWorkloadsError::DefaultItemMissing { id } => { + write!(f, "defaultItem {id} does not name a declared launcher item") + } + UnsafeLocalWorkloadsError::ShellDefaultNameInvalid => f.write_str( + "unsafe-local shell defaultName must be non-empty and NUL-free", + ), + UnsafeLocalWorkloadsError::ShellMaxSessionsInvalid { max } => { + write!(f, "unsafe-local shell maxSessions must be between 1 and {max}") + } + } + } +} + +impl std::error::Error for UnsafeLocalWorkloadsError {} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct UnsafeLocalWorkloadsJson { @@ -33,39 +112,43 @@ pub struct UnsafeLocalWorkloadsJson { } impl UnsafeLocalWorkloadsJson { - pub fn validate(&self) -> Result<(), String> { + pub fn validate(&self) -> Result<(), UnsafeLocalWorkloadsError> { if self.schema_version != UNSAFE_LOCAL_WORKLOADS_SCHEMA_VERSION { - return Err(format!( - "unsafe-local-workloads schemaVersion must be {UNSAFE_LOCAL_WORKLOADS_SCHEMA_VERSION}" - )); + return Err(UnsafeLocalWorkloadsError::SchemaVersionMismatch { + expected: UNSAFE_LOCAL_WORKLOADS_SCHEMA_VERSION, + }); } if self.workloads.len() > MAX_UNSAFE_LOCAL_WORKLOADS { - return Err(format!( - "unsafe-local workload count exceeds {MAX_UNSAFE_LOCAL_WORKLOADS}" - )); + return Err(UnsafeLocalWorkloadsError::TooManyWorkloads { + max: MAX_UNSAFE_LOCAL_WORKLOADS, + }); } if self.local_vm_workloads.len() > MAX_LOCAL_VM_CONFIGURED_WORKLOADS { - return Err(format!( - "local-vm configured workload count exceeds {MAX_LOCAL_VM_CONFIGURED_WORKLOADS}" - )); + return Err(UnsafeLocalWorkloadsError::TooManyLocalVmWorkloads { + max: MAX_LOCAL_VM_CONFIGURED_WORKLOADS, + }); } if self.workloads.len() + self.local_vm_workloads.len() > MAX_PRIVATE_CONFIGURED_WORKLOADS { - return Err(format!( - "private configured workload count exceeds {MAX_PRIVATE_CONFIGURED_WORKLOADS}" - )); + return Err(UnsafeLocalWorkloadsError::TooManyPrivateWorkloads { + max: MAX_PRIVATE_CONFIGURED_WORKLOADS, + }); } let mut targets = BTreeSet::new(); for workload in &self.workloads { let target = workload.identity.canonical_target.to_canonical(); if !targets.insert(target.clone()) { - return Err(format!("duplicate unsafe-local workload target {target}")); + return Err(UnsafeLocalWorkloadsError::DuplicateUnsafeLocalTarget { + target, + }); } workload.validate()?; } for workload in &self.local_vm_workloads { let target = workload.identity.canonical_target.to_canonical(); if !targets.insert(target.clone()) { - return Err(format!("duplicate configured workload target {target}")); + return Err(UnsafeLocalWorkloadsError::DuplicateConfiguredTarget { + target, + }); } workload.validate()?; } @@ -84,9 +167,9 @@ pub struct LocalVmConfiguredWorkload { } impl LocalVmConfiguredWorkload { - pub fn validate(&self) -> Result<(), String> { + pub fn validate(&self) -> Result<(), UnsafeLocalWorkloadsError> { if self.identity.runtime_kind.as_ref().map(|id| id.as_str()) != Some("nixos") { - return Err("local-vm configured workload must use nixos runtimeKind".to_owned()); + return Err(UnsafeLocalWorkloadsError::LocalVmRuntimeKindMismatch); } validate_items(&self.items, self.default_item_id.as_ref(), true) } @@ -105,17 +188,14 @@ pub struct UnsafeLocalWorkload { } impl UnsafeLocalWorkload { - pub fn validate(&self) -> Result<(), String> { + pub fn validate(&self) -> Result<(), UnsafeLocalWorkloadsError> { if self.identity.legacy_vm_name.is_some() { - return Err("unsafe-local workload must not carry legacyVmName".to_owned()); + return Err(UnsafeLocalWorkloadsError::LegacyVmNamePresent); } if self.identity.runtime_kind.as_ref().map(|id| id.as_str()) != Some("unsafe-local") || self.identity.provider_id.as_ref().map(|id| id.as_str()) != Some("unsafe-local") { - return Err( - "unsafe-local workload identity must use unsafe-local runtimeKind and providerId" - .to_owned(), - ); + return Err(UnsafeLocalWorkloadsError::IdentityMismatch); } validate_items( &self.items, @@ -133,34 +213,32 @@ fn validate_items( items: &[UnsafeLocalLauncherItem], default_item_id: Option<&ProtocolToken>, shell_enabled: bool, -) -> Result<(), String> { +) -> Result<(), UnsafeLocalWorkloadsError> { if items.is_empty() { - return Err("configured workload must declare at least one launcher item".to_owned()); + return Err(UnsafeLocalWorkloadsError::NoItems); } if items.len() > MAX_LAUNCHER_ITEMS_PER_WORKLOAD { - return Err(format!( - "configured launcher item count exceeds {MAX_LAUNCHER_ITEMS_PER_WORKLOAD}" - )); + return Err(UnsafeLocalWorkloadsError::TooManyItems { + max: MAX_LAUNCHER_ITEMS_PER_WORKLOAD, + }); } let mut ids = BTreeSet::new(); for item in items { if !ids.insert(item.id()) { - return Err(format!( - "duplicate configured launcher item id {}", - item.id().as_str() - )); + return Err(UnsafeLocalWorkloadsError::DuplicateItemId { + id: item.id().as_str().to_owned(), + }); } if matches!(item, UnsafeLocalLauncherItem::Shell(_)) && !shell_enabled { - return Err("shell launcher item requires shell policy".to_owned()); + return Err(UnsafeLocalWorkloadsError::ShellItemWithoutPolicy); } } if let Some(default_item_id) = default_item_id && !ids.contains(default_item_id) { - return Err(format!( - "defaultItem {} does not name a declared launcher item", - default_item_id.as_str() - )); + return Err(UnsafeLocalWorkloadsError::DefaultItemMissing { + id: default_item_id.as_str().to_owned(), + }); } Ok(()) } @@ -226,14 +304,14 @@ impl std::fmt::Debug for UnsafeLocalShellPolicy { } impl UnsafeLocalShellPolicy { - fn validate(&self) -> Result<(), String> { + fn validate(&self) -> Result<(), UnsafeLocalWorkloadsError> { if self.default_name.is_empty() || self.default_name.contains('\0') { - return Err("unsafe-local shell defaultName must be non-empty and NUL-free".to_owned()); + return Err(UnsafeLocalWorkloadsError::ShellDefaultNameInvalid); } if self.max_sessions == 0 || self.max_sessions > MAX_UNSAFE_LOCAL_SHELL_SESSIONS { - return Err(format!( - "unsafe-local shell maxSessions must be between 1 and {MAX_UNSAFE_LOCAL_SHELL_SESSIONS}" - )); + return Err(UnsafeLocalWorkloadsError::ShellMaxSessionsInvalid { + max: MAX_UNSAFE_LOCAL_SHELL_SESSIONS, + }); } Ok(()) } @@ -359,7 +437,9 @@ mod tests { }; assert_eq!( unsafe_overflow.validate().unwrap_err(), - format!("unsafe-local workload count exceeds {MAX_UNSAFE_LOCAL_WORKLOADS}") + UnsafeLocalWorkloadsError::TooManyWorkloads { + max: MAX_UNSAFE_LOCAL_WORKLOADS, + } ); let local_vm_overflow = UnsafeLocalWorkloadsJson { @@ -372,9 +452,9 @@ mod tests { }; assert_eq!( local_vm_overflow.validate().unwrap_err(), - format!( - "local-vm configured workload count exceeds {MAX_LOCAL_VM_CONFIGURED_WORKLOADS}" - ) + UnsafeLocalWorkloadsError::TooManyLocalVmWorkloads { + max: MAX_LOCAL_VM_CONFIGURED_WORKLOADS, + } ); let mut workload = valid_workload(); From 03d42c7ba54f432c7139746f35d21eccbee201e7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:24:48 -0700 Subject: [PATCH 444/726] d2b-contracts-broker: derive handoff source usability and seal audit digest --- packages/d2b-contracts-broker/src/broker_wire.rs | 2 +- packages/d2b-contracts-broker/src/host_generation.rs | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 61404148b..68097efb0 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -2807,7 +2807,7 @@ pub struct SpawnRunnerResponse { /// Canonical opaque digest carried by the broker audit join context. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(transparent)] -pub struct CanonicalAuditDigest(pub String); +pub struct CanonicalAuditDigest(String); impl CanonicalAuditDigest { /// Parse the exact lower-case SHA-256 wire spelling. diff --git a/packages/d2b-contracts-broker/src/host_generation.rs b/packages/d2b-contracts-broker/src/host_generation.rs index 132263dd4..197a72ff1 100644 --- a/packages/d2b-contracts-broker/src/host_generation.rs +++ b/packages/d2b-contracts-broker/src/host_generation.rs @@ -115,7 +115,6 @@ impl SourceGenerationCompatibilityFloorV1 { source_generation, target_generation, state: HandoffState::Recorded, - source_remains_usable: true, }) } } @@ -233,7 +232,6 @@ pub struct HandoffCoordinator { source_generation: u64, target_generation: u64, state: HandoffState, - source_remains_usable: bool, } impl HandoffCoordinator { @@ -252,9 +250,10 @@ impl HandoffCoordinator { self.target_generation } - /// Whether source remains usable after this phase. - pub const fn source_remains_usable(&self) -> bool { - self.source_remains_usable + /// Whether source remains usable after this phase. The source is + /// retired only once the target completes; every other phase keeps it. + pub fn source_remains_usable(&self) -> bool { + self.state != HandoffState::Completed } /// Validate the authenticated target before mutation. @@ -326,7 +325,6 @@ impl HandoffCoordinator { return Err(HandoffError::InvalidTransition); } self.state = HandoffState::Completed; - self.source_remains_usable = false; Ok(()) } @@ -344,7 +342,6 @@ impl HandoffCoordinator { return Err(HandoffError::InvalidTransition); } self.state = HandoffState::RolledBack; - self.source_remains_usable = true; Ok(()) } } From d2772c3216899275a6d1be1259acc4c22fbbb627 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:27:17 -0700 Subject: [PATCH 445/726] audit: fold the host resource provider slice --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 1f37eb109..e471ac6c5 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -430,7 +430,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0375` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 205e888b9 | packages/d2b-provider-device-tpm/src/effects_service.rs | LiveTpmResourceEffectPort made pub(crate); census re-run at HEAD: only effects_service.rs:341/364/535/679-680 reference it, 0 external hits | | | `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | | `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | c47b8ba63 | packages/d2b-provider-device-usbip/src/lib.rs | pub mod state_machine -> mod state_machine; the lib.rs re-export remains the single surface. Census re-run: no state_machine:: module-path users outside the crate. | | -| `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `broker.rs:131-133` | | | +| `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 7c4997d04 | packages/d2b-provider-device-usbip/src/broker.rs | | | | `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | declined | U3 | | `src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20` | pub(crate) narrowing trips the repo dead_code deny (no internal users, no lint allows permitted by wave rules); wiring the daemon cleanup path needs spec/session-key plumbing across runtime+daemon bey | | | `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | c5d8e0cf5 | packages/d2b-provider-display-wayland/src/lib.rs | Module moved into the binary target via #[path]; all crate::wayland_proxy paths rewritten; census of d2b_provider_display_wayland::wayland_proxy over packages/nixos-modules/tests/docs/reference = 0. | | | `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 15d510a76 | packages/d2b-provider-display-wayland/src/controller.rs | WaylandPolicySnapshot::from_authenticated_session deleted (no callers; census over packages/nixos-modules/tests/labs/docs/reference = 0 in the display crate). | | @@ -459,7 +459,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | | | | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | | | | `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | | | | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | | | | `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | | | | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | -| `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2bd/src/process_provider_run` | | | +| `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 0cb5d7b68 | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | | | | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | | | | `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | | `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | | | | `src/host.rs:389, src/host.rs:13` | | | @@ -481,7 +481,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0426` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | Census re-run: zero consumers. Deleted ResourceApiReachability enum, RESOURCE_API_REACHABILITY const, lib re-export, and the tautological assertion in the 13-method test. | | | `RS-0427` | `api` | `d2b-resource-api` | low | actionable | leaf | applied-variant | U3 | 0d74a18f2 | packages/d2b-resource-api/src/client.rs | Census re-run: zero callers. pub(crate) alone tripped denied dead_code warnings (crate denies warnings), so the unwired methods were deleted until a caller exists. | | | `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | wire_revision and api_subject narrowed to pub(crate). resource_owner_subject stays pub because its U9/U10 caller has landed at HEAD: d2bd/src/resource_runtime/plane_controller_bridge.rs:369 (subject() | | -| `RS-0429` | `api` | `d2b-resource-client` | medium | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:83, packages/d2b-resource-client/src/zone_` | | | +| `RS-0429` | `api` | `d2b-resource-client` | medium | actionable | leaf | applied | U3 | 8b53d606e | packages/d2b-resource-client/src/zone_client.rs | | | | `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | | | | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | | `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | 0cd7b063d | packages/d2b-resource-runtime/src/target.rs | Removed TargetBinding::directory() accessor. Census re-run: zero callers; the directory field stays read by internal methods (observe/delete/adopt), no dead code. cargo check/test/clippy green for d2b | | | `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | U3 | 3570364e0 | packages/d2b-resource-runtime/src/guest_target.rs | Removal as written orphans GuestTargetInner.reference (dead-code deny) and forces a public constructor signature change across 26 call sites in 5 files incl. d2bd production (published surface -> cont | | @@ -506,8 +506,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | | | | `RS-0477` | `err` | `d2b` | medium | actionable | leaf | applied-variant | U3 | 7256bc918 | packages/d2b/src/lib.rs | Added structured code field to CliFailure; populated in ZoneContext::failure; can_fallback_to_local_state and reconcile_deadline match on it. Field is String not &'static str because validate_response | | | `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | | | | `packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, ` | | | -| `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/export.rs:230` | | | -| `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | | | | `packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b` | | | +| `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | +| `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 637d66627 | packages/d2b-audit/src/segment.rs | | | | `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | | `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source | | | `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | @@ -543,7 +543,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixo` | | | | `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | export_checkpoints now rejects an unparseable lease-map key with the crate's typed `InvariantFailure` refusal instead of a `.expect()` panic; shares commit dbec5dde7 with RS-0368 (same lib.rs surface, | | | `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | -| `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `state_machine.rs:378-386` | | | +| `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 2f5c9a692 | packages/d2b-provider-device-usbip/src/state_machine.rs | | | | `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | 263eea211 | packages/d2b-provider-display-wayland/src/controller.rs | DisplayController::new returns Result with # Errors doc; 2 daemon sites use expect/unwrap; all call sites updated. | | | `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886` | | | | `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 64c41ddb5 | packages/d2b-provider-display-wayland/src/spec.rs | WaylandSpecError::NoPrincipalAvailable variant + Display arm deleted; no error-codes.md hit; no other constructors (controller uses PrincipalPoolError/SessionCondition). | | @@ -555,7 +555,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `ingress_policy.rs:647` | | | | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/d` | | | | `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | -| `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:419-421` | | | +| `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:888-890` | | | | `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServiceDriverError carries source: Option> with Error::source(); the Err(_) swallow in reconcile_service now attaches the store error and classify_error surfaces it as a fa | | | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | From 58e1ebd12d96aa7605b6ef4c7c3b19d483df64fa Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:27:26 -0700 Subject: [PATCH 446/726] audit: fold the stale host row --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index e471ac6c5..394725efa 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -556,7 +556,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/d` | | | | `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | | `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | -| `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | | | | `packages/d2b-provider-supervisor/src/adapter.rs:888-890` | | | +| `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | skipped-stale | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServiceDriverError carries source: Option> with Error::source(); the Err(_) swallow in reconcile_service now attaches the store error and classify_error surfaces it as a fa | | | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | | `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | From 3d19a8ea6cd33903fa8d6cdb5dc0d06b46d018eb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:28:41 -0700 Subject: [PATCH 447/726] d2b-provider-config-nixos: seal request fields and fix encoding-failure status --- .../d2b-provider-config-nixos/src/service.rs | 20 +++++++++---------- .../d2b-provider-config-nixos/src/ttrpc.rs | 4 +++- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/d2b-provider-config-nixos/src/service.rs b/packages/d2b-provider-config-nixos/src/service.rs index a75399fb6..d84e06e13 100644 --- a/packages/d2b-provider-config-nixos/src/service.rs +++ b/packages/d2b-provider-config-nixos/src/service.rs @@ -23,7 +23,7 @@ pub struct ConfigSyncRequest { /// Owning Guest resource. pub guest_ref: ResourceRef, /// Closed document identifier. - pub identifier: String, + pub(crate) identifier: String, } impl ConfigSyncRequest { @@ -34,9 +34,7 @@ impl ConfigSyncRequest { /// Returns [`ConfigError::InvalidRequest`] when the reference does not /// name a Guest. pub fn new(guest_ref: ResourceRef) -> Result { - if guest_ref.resource_type().as_str() != "Guest" { - return Err(ConfigError::InvalidRequest); - } + validate_guest_ref(&guest_ref)?; Ok(Self { guest_ref, identifier: GUEST_CONFIG_IDENTIFIER.to_owned(), @@ -114,7 +112,7 @@ pub struct ConfigStageRequest { /// Owning Guest resource. pub guest_ref: ResourceRef, /// Closed document identifier. - pub identifier: String, + pub(crate) identifier: String, /// Base64-encoded document to validate and stage. pub content_base64: String, } @@ -183,9 +181,9 @@ pub struct ConfigDiffRequest { /// Owning Guest resource. pub guest_ref: ResourceRef, /// Closed staging document identifier. - pub identifier: String, + pub(crate) identifier: String, /// Stable local view identifier, not a file path. - pub against: String, + pub(crate) against: String, } impl ConfigDiffRequest { @@ -225,9 +223,9 @@ pub struct ConfigApproveRequest { /// Owning Guest resource. pub guest_ref: ResourceRef, /// Closed staging document identifier. - pub identifier: String, + pub(crate) identifier: String, /// Stable host configuration target identifier. - pub destination: String, + pub(crate) destination: String, } impl ConfigApproveRequest { @@ -273,7 +271,7 @@ pub struct ConfigRejectRequest { /// Owning Guest resource. pub guest_ref: ResourceRef, /// Closed staging document identifier. - pub identifier: String, + pub(crate) identifier: String, } impl ConfigRejectRequest { @@ -309,7 +307,7 @@ pub struct ConfigStatusRequest { /// Owning Guest resource. pub guest_ref: ResourceRef, /// Closed staging document identifier. - pub identifier: String, + pub(crate) identifier: String, } impl ConfigStatusRequest { diff --git a/packages/d2b-provider-config-nixos/src/ttrpc.rs b/packages/d2b-provider-config-nixos/src/ttrpc.rs index deec6af38..7781f8f36 100644 --- a/packages/d2b-provider-config-nixos/src/ttrpc.rs +++ b/packages/d2b-provider-config-nixos/src/ttrpc.rs @@ -377,8 +377,10 @@ fn rpc_error(error: ConfigError) -> ttrpc::Error { } fn invalid_status() -> ttrpc::Status { + // Client-side encode/decode failures are implementation faults, not + // caller input errors, so report INTERNAL to match the code. ttrpc::get_status( - ttrpc::Code::INVALID_ARGUMENT, + ttrpc::Code::INTERNAL, ConfigError::EncodingFailed.code(), ) } From a625c020b14b532f8c9348d64f85b6470fef8457 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:33:32 -0700 Subject: [PATCH 448/726] d2b-provider-observability-otel: keep validated tokens and fix capacity refusal class --- .../src/agent.rs | 34 +++++++++---------- .../src/ingress_policy.rs | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/d2b-provider-observability-otel/src/agent.rs b/packages/d2b-provider-observability-otel/src/agent.rs index 2d7296cb6..f17fc0bd4 100644 --- a/packages/d2b-provider-observability-otel/src/agent.rs +++ b/packages/d2b-provider-observability-otel/src/agent.rs @@ -57,11 +57,11 @@ pub struct ProviderAgentAuditEvent { zone: String, source: String, record_class: &'static str, - event: String, + event: BoundedToken, transport_class: &'static str, - authz_decision: Option, - provider: Option, - domain: Option, + authz_decision: Option, + provider: Option, + domain: Option, outcome: ProviderAgentAuditOutcome, } @@ -112,8 +112,8 @@ impl ProviderAgentAuditEvent { fn session_connect( zone: &str, source: &str, - event: String, - authz_decision: String, + event: BoundedToken, + authz_decision: BoundedToken, outcome: ProviderAgentAuditOutcome, ) -> Self { Self { @@ -132,9 +132,9 @@ impl ProviderAgentAuditEvent { fn process_effect( zone: &str, source: &str, - event: String, - provider: String, - domain: String, + event: BoundedToken, + provider: BoundedToken, + domain: BoundedToken, outcome: ProviderAgentAuditOutcome, ) -> Self { Self { @@ -162,7 +162,7 @@ impl ProviderAgentAuditEvent { /// Borrow the event token. pub fn event(&self) -> &str { - &self.event + self.event.as_str() } /// Borrow the event token through the Provider-agent terminology. @@ -268,13 +268,13 @@ impl ProviderAgentProcess { let authz_decision = parse_closed_token(&authz_decision, &["allowed", "denied"])?; let outcome = parse_outcome(outcome)?; self.push( - method, + method.clone(), outcome, ProviderAgentAuditEvent::session_connect( &self.zone_name, &self.source_name, - event, - authz_decision.as_str().to_owned(), + method.clone(), + authz_decision, outcome, ), ) @@ -306,14 +306,14 @@ impl ProviderAgentProcess { let domain = parse_closed_token(&domain, &["system", "user"])?; let outcome = parse_outcome(outcome)?; self.push( - method, + method.clone(), outcome, ProviderAgentAuditEvent::process_effect( &self.zone_name, &self.source_name, - event, - provider.as_str().to_owned(), - domain.as_str().to_owned(), + method.clone(), + provider, + domain, outcome, ), ) diff --git a/packages/d2b-provider-observability-otel/src/ingress_policy.rs b/packages/d2b-provider-observability-otel/src/ingress_policy.rs index 40c480be6..11263f616 100644 --- a/packages/d2b-provider-observability-otel/src/ingress_policy.rs +++ b/packages/d2b-provider-observability-otel/src/ingress_policy.rs @@ -649,7 +649,7 @@ impl IngressPolicyGate { ingress = ?ingress, "ingress connection tracking table full; new connection rejected" ); - return (IngressOutcome::Rejected, IngressErrorClass::Malformed); + return (IngressOutcome::Rejected, IngressErrorClass::None); } let state = self .connections From 336a4fd97c192b97e2187c07126a370918893a85 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:38:30 -0700 Subject: [PATCH 449/726] provider-network-local: propagate provenance serialization failures --- .../d2b-provider-network-local/src/broker.rs | 24 +++++++------- .../src/operations.rs | 32 ++++++++++++------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/packages/d2b-provider-network-local/src/broker.rs b/packages/d2b-provider-network-local/src/broker.rs index f62624caf..a6d53bd78 100644 --- a/packages/d2b-provider-network-local/src/broker.rs +++ b/packages/d2b-provider-network-local/src/broker.rs @@ -1199,7 +1199,7 @@ impl NetworkBroker for KernelNetworkBroker { .intents .resolve_bridge_intent(intent_ref.as_str(), &provenance) .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; - self.invoke_kernel("create-bridge", &zone, resolved_bridge_payload(&intent))?; + self.invoke_kernel("create-bridge", &zone, resolved_bridge_payload(&intent)?)?; } Ok(()) } @@ -1213,7 +1213,7 @@ impl NetworkBroker for KernelNetworkBroker { .intents .resolve_bridge_intent(intent_ref.as_str(), &provenance) .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; - self.invoke_kernel("delete-bridge", &zone, resolved_bridge_payload(&intent))?; + self.invoke_kernel("delete-bridge", &zone, resolved_bridge_payload(&intent)?)?; } Ok(()) } @@ -1294,7 +1294,7 @@ impl NetworkBroker for KernelNetworkBroker { self.invoke_kernel( "apply-route", &zone, - resolved_route_payload(&intent, &provenance, false), + resolved_route_payload(&intent, &provenance, false)?, )?; } Ok(()) @@ -1312,7 +1312,7 @@ impl NetworkBroker for KernelNetworkBroker { self.invoke_kernel( "apply-route", &zone, - resolved_route_payload(&intent, &provenance, true), + resolved_route_payload(&intent, &provenance, true)?, )?; } Ok(()) @@ -1419,8 +1419,8 @@ impl NetworkBroker for KernelNetworkBroker { } /// The resolved bridge intent payload one bridge kernel invocation carries. -fn resolved_bridge_payload(intent: &ResolvedBridgeIntent) -> serde_json::Value { - serde_json::json!({ +fn resolved_bridge_payload(intent: &ResolvedBridgeIntent) -> Result { + Ok(serde_json::json!({ "intentId": intent.intent_id, "scopeLabel": intent.scope_label, "bridgeIfname": intent.bridge_ifname.as_str(), @@ -1429,9 +1429,9 @@ fn resolved_bridge_payload(intent: &ResolvedBridgeIntent) -> serde_json::Value { "multicastSnoopingDisabled": intent.multicast_snooping_disabled, "ipv6Suppressed": intent.ipv6_suppressed, "ipv4Address": intent.ipv4_address.as_ref().map(|cidr| cidr.as_str()), - "provenance": intent.provenance.as_ref().map(serde_json::to_value).transpose().ok().flatten(), + "provenance": intent.provenance.as_ref().map(serde_json::to_value).transpose().map_err(|_| NetworkBrokerError::Rejected)?, "ownershipMarker": intent.ownership_marker, - }) + })) } /// The resolved route intent payload one apply-route kernel invocation @@ -1440,8 +1440,8 @@ fn resolved_route_payload( intent: &ResolvedRouteIntent, provenance: &NetworkProvenance, destroy: bool, -) -> serde_json::Value { - serde_json::json!({ +) -> Result { + Ok(serde_json::json!({ "intentId": intent.intent_id, "routeSpec": intent.route_spec, "destination": intent.destination, @@ -1450,10 +1450,10 @@ fn resolved_route_payload( "table": intent.table, "owned": intent.owned, "routeName": intent.route_name, - "provenance": serde_json::to_value(provenance).ok(), + "provenance": serde_json::to_value(provenance).map_err(|_| NetworkBrokerError::Rejected)?, "ownershipMarker": intent.ownership_marker, "destroy": destroy, - }) + })) } /// Map one kernel refusal onto the provider's closed retry/block states, diff --git a/packages/d2b-provider-network-local/src/operations.rs b/packages/d2b-provider-network-local/src/operations.rs index 2c76c1531..ed2026159 100644 --- a/packages/d2b-provider-network-local/src/operations.rs +++ b/packages/d2b-provider-network-local/src/operations.rs @@ -395,8 +395,8 @@ fn network_provenance( /// The resolved bridge intent payload one bridge kernel invocation carries. fn resolved_bridge_payload( intent: &d2b_core::bundle_resolver::ResolvedBridgeIntent, -) -> serde_json::Value { - serde_json::json!({ +) -> Result { + Ok(serde_json::json!({ "intentId": intent.intent_id, "scopeLabel": intent.scope_label, "bridgeIfname": intent.bridge_ifname.as_str(), @@ -405,9 +405,14 @@ fn resolved_bridge_payload( "multicastSnoopingDisabled": intent.multicast_snooping_disabled, "ipv6Suppressed": intent.ipv6_suppressed, "ipv4Address": intent.ipv4_address.as_ref().map(|cidr| cidr.as_str()), - "provenance": intent.provenance.as_ref().map(serde_json::to_value).transpose().ok().flatten(), + "provenance": intent.provenance.as_ref().map(serde_json::to_value).transpose().map_err(|error| { + OperationFailure::with_detail( + KERNEL_REFUSED, + format!("provenance serialization failed: {error}"), + ) + })?, "ownershipMarker": intent.ownership_marker, - }) + })) } /// The resolved route intent payload one apply-route kernel invocation @@ -416,8 +421,8 @@ fn resolved_route_payload( intent: &d2b_core::bundle_resolver::ResolvedRouteIntent, provenance: &NetworkProvenance, destroy: bool, -) -> serde_json::Value { - serde_json::json!({ +) -> Result { + Ok(serde_json::json!({ "intentId": intent.intent_id, "routeSpec": intent.route_spec, "destination": intent.destination, @@ -426,10 +431,15 @@ fn resolved_route_payload( "table": intent.table, "owned": intent.owned, "routeName": intent.route_name, - "provenance": serde_json::to_value(provenance).ok(), + "provenance": serde_json::to_value(provenance).map_err(|error| { + OperationFailure::with_detail( + KERNEL_REFUSED, + format!("provenance serialization failed: {error}"), + ) + })?, "ownershipMarker": intent.ownership_marker, "destroy": destroy, - }) + })) } // --------------------------------------------------------------------------- @@ -648,7 +658,7 @@ impl OperationHandler for ApplyRouteHandler { let reply = invoke_kernel_nested( &ctx, "apply-route", - resolved_route_payload(&intent, &provenance, request.destroy), + resolved_route_payload(&intent, &provenance, request.destroy)?, Vec::new(), ) .await?; @@ -742,7 +752,7 @@ impl OperationHandler for CreateBridgeHandler { let reply = invoke_kernel_nested( &ctx, "create-bridge", - resolved_bridge_payload(&intent), + resolved_bridge_payload(&intent)?, Vec::new(), ) .await?; @@ -783,7 +793,7 @@ impl OperationHandler for DeleteBridgeHandler { let reply = invoke_kernel_nested( &ctx, "delete-bridge", - resolved_bridge_payload(&intent), + resolved_bridge_payload(&intent)?, Vec::new(), ) .await?; From 200aa2bb26e5a2a822557708ac8325b40da1a632 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:39:08 -0700 Subject: [PATCH 450/726] provider-network-local: name the sha256 chunk word invariant --- packages/d2b-provider-network-local/src/nftables.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-network-local/src/nftables.rs b/packages/d2b-provider-network-local/src/nftables.rs index d1f8f2b02..5ec130199 100644 --- a/packages/d2b-provider-network-local/src/nftables.rs +++ b/packages/d2b-provider-network-local/src/nftables.rs @@ -585,7 +585,11 @@ fn sha256(bytes: &[u8]) -> [u8; 32] { let mut words = [0u32; 64]; for (index, word) in words[..16].iter_mut().enumerate() { let offset = index * 4; - *word = u32::from_be_bytes(chunk[offset..offset + 4].try_into().unwrap()); + *word = u32::from_be_bytes( + chunk[offset..offset + 4] + .try_into() + .expect("64-byte chunk yields a 4-byte word slice"), + ); } for index in 16..64 { let small0 = words[index - 15].rotate_right(7) From cd1055487e36ca3602e4325878ed266ec71ccaa6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:41:01 -0700 Subject: [PATCH 451/726] provider-notification-desktop: narrow controller reconcile surface --- .../src/controller.rs | 34 +++---------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/packages/d2b-provider-notification-desktop/src/controller.rs b/packages/d2b-provider-notification-desktop/src/controller.rs index 20aa8a2ee..202265eae 100644 --- a/packages/d2b-provider-notification-desktop/src/controller.rs +++ b/packages/d2b-provider-notification-desktop/src/controller.rs @@ -156,7 +156,6 @@ impl DisplayDependencyEvidence { } /// Resolve one display dependency from an authenticated display route. - #[allow(dead_code)] pub(crate) fn from_route( route: AuthenticatedSessionRouteBinding, state: DisplayDependencyState, @@ -1017,7 +1016,8 @@ impl NotificationController { } /// Reconcile configured Guest source endpoints and the host sink. - pub fn reconcile_sources( + #[cfg(test)] + pub(crate) fn reconcile_sources( &mut self, display: &DisplayDependencyEvidence, config: &NotificationProviderConfig, @@ -1321,33 +1321,6 @@ impl NotificationController { Ok(()) } - /// Reconcile from a Core-authenticated display route. - /// - /// `None` is the fail-closed dependency state and drains every owned - /// source/sink endpoint. A route is accepted only when the sealed - /// ComponentSession authority has bound the display Provider, local Unix - /// evidence, a User subject, and a non-zero Provider generation. - pub fn reconcile_authenticated_display( - &mut self, - display: Option, - config: &NotificationProviderConfig, - source_sessions: &[SessionEvidence], - ) -> Result { - let Some(proof) = display else { - let result = self.drain_plan(); - self.clear_reconciliation(); - return Ok(result); - }; - let evidence = match DisplayDependencyEvidence::from_authenticated_route(proof) { - Ok(evidence) => evidence, - Err(error) => { - self.clear_reconciliation(); - return Err(error); - } - }; - self.reconcile_sources(&evidence, config, source_sessions) - } - /// Reconcile display and Guest-source ownership through the effect /// boundary, including fail-closed cleanup when the dependency vanishes. pub fn reconcile_authenticated_display_with_effects( @@ -1409,7 +1382,8 @@ impl NotificationController { } /// Drain and forget all source endpoints during shutdown or finalization. - pub fn drain_sources(&mut self) -> Vec { + #[cfg(test)] + pub(crate) fn drain_sources(&mut self) -> Vec { let drained = self.active_sources.keys().cloned().collect(); self.clear_reconciliation(); drained From c7d7d66c5965f28c31510d51c4a7025060050041 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:41:14 -0700 Subject: [PATCH 452/726] audio-pipewire: split mixer grant and revoke, encode handoff mode in the type --- .../src/authority.rs | 42 ++++++++-------- .../src/controller.rs | 50 +++++++++++-------- .../tests/controller.rs | 2 +- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/packages/d2b-provider-audio-pipewire/src/authority.rs b/packages/d2b-provider-audio-pipewire/src/authority.rs index b1b78bce1..facb271c7 100644 --- a/packages/d2b-provider-audio-pipewire/src/authority.rs +++ b/packages/d2b-provider-audio-pipewire/src/authority.rs @@ -150,30 +150,30 @@ impl SpeakerMixer { } } - /// Grant or revoke one speaker consumer. + /// Grant one speaker consumer. /// /// The return value is true when the aggregate speaker grant changed - /// from no consumers to at least one consumer, or back to none. - pub fn set_grant( - &mut self, - lease: AudioLeaseId, - on: bool, - ) -> Result { - if on { - if !self.grants.contains(&lease) - && !self.levels.contains_key(&lease) - && self.consumer_count() >= self.max_consumers - { - return Err(AudioAuthorityError::ConsumerLimit); - } - let was_empty = self.grants.is_empty(); - self.grants.insert(lease); - Ok(was_empty) - } else { - let was_last = self.grants.len() == 1 && self.grants.contains(&lease); - self.grants.remove(&lease); - Ok(was_last) + /// from no consumers to at least one consumer. + pub fn grant(&mut self, lease: AudioLeaseId) -> Result { + if !self.grants.contains(&lease) + && !self.levels.contains_key(&lease) + && self.consumer_count() >= self.max_consumers + { + return Err(AudioAuthorityError::ConsumerLimit); } + let was_empty = self.grants.is_empty(); + self.grants.insert(lease); + Ok(was_empty) + } + + /// Revoke one speaker consumer. + /// + /// The return value is true when the revoked consumer was the last + /// grant holder. + pub fn revoke(&mut self, lease: AudioLeaseId) -> Result { + let was_last = self.grants.len() == 1 && self.grants.contains(&lease); + self.grants.remove(&lease); + Ok(was_last) } /// Return whether one lease currently holds a speaker grant. diff --git a/packages/d2b-provider-audio-pipewire/src/controller.rs b/packages/d2b-provider-audio-pipewire/src/controller.rs index 7d9e06f3d..922eeaee0 100644 --- a/packages/d2b-provider-audio-pipewire/src/controller.rs +++ b/packages/d2b-provider-audio-pipewire/src/controller.rs @@ -201,34 +201,51 @@ pub struct AudioReconcileResultWithChildren { pub children: BindingChildSet, } +/// Whether finalization enables the promoted microphone lease through this +/// binding's mediator. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum MicrophoneHandoff { + /// The promoted lease is enabled through this binding's mediator. + Enable, + /// The promoted lease is left inactive for the daemon to reconcile. + Defer, +} + /// AudioBinding controller over existing audio policy and mediator ports. #[derive(Debug)] pub struct AudioBindingController { mediator: M, microphone: SharedMicrophoneArbiter, - activate_promoted: bool, + handoff: MicrophoneHandoff, microphone_effect_applied: bool, speaker: SpeakerMixer, } impl AudioBindingController { /// Construct a controller with bounded arbitration state. + /// + /// Finalization enables the promoted microphone lease through this + /// controller's mediator. pub fn new(mediator: M) -> Self { Self { mediator, microphone: crate::shared_microphone_arbiter(AUDIO_QUEUE_BOUND), - activate_promoted: true, + handoff: MicrophoneHandoff::Enable, microphone_effect_applied: false, speaker: SpeakerMixer::new(AUDIO_QUEUE_BOUND), } } /// Construct a controller sharing one AudioService microphone authority. + /// + /// Finalization leaves the promoted lease inactive; the caller + /// reconciles the owning binding so the effect is applied to the + /// correct target. pub fn with_shared_microphone(mediator: M, microphone: SharedMicrophoneArbiter) -> Self { Self { mediator, microphone, - activate_promoted: false, + handoff: MicrophoneHandoff::Defer, microphone_effect_applied: false, speaker: SpeakerMixer::new(AUDIO_QUEUE_BOUND), } @@ -399,7 +416,7 @@ impl AudioBindingController { if binding.grants.speaker == AudioGrant::On { let transition = self .speaker - .set_grant(lease, true) + .grant(lease) .map_err(|error| { debug!( zone = %service_zone, @@ -421,7 +438,7 @@ impl AudioBindingController { error = %error, "speaker grant mediation failed for binding" ); - if let Err(rollback_error) = self.speaker.set_grant(lease, false) { + if let Err(rollback_error) = self.speaker.revoke(lease) { warn!( zone = %service_zone, lease = ?lease, @@ -454,7 +471,7 @@ impl AudioBindingController { })?; } self.speaker - .set_grant(lease, false) + .revoke(lease) .map_err(|error| { debug!( zone = %service_zone, @@ -596,20 +613,11 @@ impl AudioBindingController { } /// Finalize one binding with mute-before-release ordering. - pub fn finalize( - &mut self, - lease: AudioLeaseId, - ) -> Result, AudioControllerError> { - self.finalize_inner(lease) - } - - /// Finalize a binding whose microphone authority is shared with other - /// controllers. /// - /// The next lease is returned but is not enabled through this binding's - /// mediator. The daemon reconciles the promoted binding so the effect is - /// applied to the correct target. - pub fn finalize_shared( + /// The promoted microphone lease is enabled through this binding's + /// mediator when the controller owns the microphone authority; shared + /// controllers defer the activation to the daemon's reconcile. + pub fn finalize( &mut self, lease: AudioLeaseId, ) -> Result, AudioControllerError> { @@ -728,7 +736,7 @@ impl AudioBindingController { let Some(next) = next else { return Ok(None); }; - if self.activate_promoted + if self.handoff == MicrophoneHandoff::Enable && let Err(error) = self .mediator .set_channel_grant(AudioChannel::Microphone, AudioGrant::On) @@ -745,7 +753,7 @@ impl AudioBindingController { } return Err(AudioControllerError::Mediator(error)); } - if self.activate_promoted { + if self.handoff == MicrophoneHandoff::Enable { self.microphone_effect_applied = true; } Ok(Some(next)) diff --git a/packages/d2b-provider-audio-pipewire/tests/controller.rs b/packages/d2b-provider-audio-pipewire/tests/controller.rs index f962412a2..de6b7b947 100644 --- a/packages/d2b-provider-audio-pipewire/tests/controller.rs +++ b/packages/d2b-provider-audio-pipewire/tests/controller.rs @@ -225,7 +225,7 @@ fn shared_finalization_does_not_enable_the_promoted_binding_through_the_old_medi .unwrap(); assert_eq!( - first.finalize_shared(AudioLeaseId::new(1)).unwrap(), + first.finalize(AudioLeaseId::new(1)).unwrap(), Some(AudioLeaseId::new(2)) ); assert_eq!(first.mediator().grant(), AudioGrant::Off); From e53601c889c676d0b7d9a18288de2fcbc0880290 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:41:18 -0700 Subject: [PATCH 453/726] cloud-hypervisor: type the runtime-scope role as ChildRole --- .../src/controller.rs | 2 +- .../src/identity.rs | 6 ++---- .../tests/controller.rs | 10 +++++++--- .../tests/guest_spec_validation_test.rs | 9 --------- .../tests/redaction_test.rs | 13 +++++++------ .../src/audio_registry.rs | 4 ++-- 6 files changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs index 2fb36fbf2..47420fcdf 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs @@ -1804,7 +1804,7 @@ where pub fn private_runtime_scope( &self, guest: &GuestSnapshot, - role: &str, + role: ChildRole, ) -> Result { derive_private_runtime_scope( guest.zone_uid(), diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs index fb296e260..5e504a0ed 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs @@ -876,12 +876,10 @@ impl fmt::Debug for PrivateRuntimeScope { pub fn derive_private_runtime_scope( zone_uid: &ResourceUid, guest_uid: &ResourceUid, - role: &str, + role: ChildRole, generation: d2b_contracts_resource::v3::ResourceGeneration, ) -> Result { - if !matches!(role, "vmm" | "ch-api" | "guest-control" | "system") { - return Err(ChildIdentityError::InvalidRuntimeRole); - } + let role = role.suffix(); let mut digest = Sha256::new(); digest.update(PRIVATE_RUNTIME_SCOPE_DOMAIN_TAG.as_bytes()); digest.update([0]); diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs index 9bc27f46e..5547dbff8 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs @@ -6,7 +6,7 @@ use d2b_contracts_resource::v3::{ ResourceGeneration, ResourceRef, ResourceUid, ZoneId, ZoneRevision, }; use d2b_provider_guest_cloud_hypervisor::{ - AuthenticatedResourceApiAdapter, AuthenticatedResourceSession, BootstrapGraph, + AuthenticatedResourceApiAdapter, AuthenticatedResourceSession, BootstrapGraph, ChildRole, CloudHypervisorController, CloudHypervisorResourceApiError, CloudHypervisorResourceRequest, CloudHypervisorResourceResponse, GuestGenerationSet, GuestSnapshot, }; @@ -246,8 +246,12 @@ fn same_guest_name_in_different_zones_has_distinct_private_runtime_identity() { .unwrap(); assert_ne!( - controller.private_runtime_scope(&first, "vmm").unwrap(), - controller.private_runtime_scope(&second, "vmm").unwrap() + controller + .private_runtime_scope(&first, ChildRole::VmmProcess) + .unwrap(), + controller + .private_runtime_scope(&second, ChildRole::VmmProcess) + .unwrap() ); } diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs index a84bb193e..558993de7 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs @@ -103,15 +103,6 @@ fn descriptor_semantic_tokens_are_exact() { .is_err() ); assert!(BootstrapHandoff::new("allocator", 30_000).is_err()); - assert!( - d2b_provider_guest_cloud_hypervisor::identity::derive_private_runtime_scope( - &ResourceUid::parse("223e4567-e89b-42d3-a456-426614174000").unwrap(), - &ResourceUid::parse("323e4567-e89b-42d3-a456-426614174000").unwrap(), - "socket", - ResourceGeneration::new(1).unwrap(), - ) - .is_err() - ); } #[test] diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/redaction_test.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/redaction_test.rs index 7d858f003..4f4445a6d 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/redaction_test.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/redaction_test.rs @@ -4,7 +4,7 @@ use d2b_contracts_resource::v3::{ }; use d2b_provider_guest_cloud_hypervisor::identity::derive_private_runtime_scope; use d2b_provider_guest_cloud_hypervisor::{ - BootstrapHandoff, DescriptorSignature, GuestChildBatch, GuestSeedContract, + BootstrapHandoff, ChildRole, DescriptorSignature, GuestChildBatch, GuestSeedContract, GuestSetupDescriptor, GuestSetupDescriptorVerifier, SignatureAlgorithm, }; @@ -62,7 +62,7 @@ fn private_descriptor_and_runtime_scope_debug_are_redacted() { let scope = derive_private_runtime_scope( &zone_uid, &guest_uid, - "vmm", + ChildRole::VmmProcess, ResourceGeneration::new(2).unwrap(), ) .unwrap(); @@ -87,21 +87,22 @@ fn runtime_scope_changes_for_zone_and_guest_reincarnation() { d2b_contracts_resource::v3::ResourceUid::parse("523e4567-e89b-42d3-a456-426614174000") .unwrap(); let generation = ResourceGeneration::new(1).unwrap(); - let first = derive_private_runtime_scope(&zone_a, &guest_a, "vmm", generation).unwrap(); + let first = derive_private_runtime_scope(&zone_a, &guest_a, ChildRole::VmmProcess, generation) + .unwrap(); assert_ne!( first, - derive_private_runtime_scope(&zone_b, &guest_a, "vmm", generation).unwrap() + derive_private_runtime_scope(&zone_b, &guest_a, ChildRole::VmmProcess, generation).unwrap() ); assert_ne!( first, - derive_private_runtime_scope(&zone_a, &guest_b, "vmm", generation).unwrap() + derive_private_runtime_scope(&zone_a, &guest_b, ChildRole::VmmProcess, generation).unwrap() ); assert_ne!( first, derive_private_runtime_scope( &zone_a, &guest_a, - "vmm", + ChildRole::VmmProcess, ResourceGeneration::new(2).unwrap() ) .unwrap() diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index 4ad0ae24c..e47b79680 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -265,7 +265,7 @@ impl AudioResourceRuntime { let promoted = if let Some(old) = self.bindings.get_mut(&key) { if let Some(controller) = old.controller.as_mut() { controller - .finalize_shared(old.lease) + .finalize(old.lease) .map_err(AudioResourceRuntimeError::Controller)? } else { None @@ -358,7 +358,7 @@ impl AudioResourceRuntime { let promoted = if let Some(record) = self.bindings.get_mut(&key) { if let Some(controller) = record.controller.as_mut() { controller - .finalize_shared(record.lease) + .finalize(record.lease) .map_err(AudioResourceRuntimeError::Controller)? } else { None From d52b7052cb4016ddb8dd55d143acb34ba6930451 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:41:31 -0700 Subject: [PATCH 454/726] d2b-provider-volume-local: split root handle into empty and anchored variants --- .../d2b-provider-volume-local/src/identity.rs | 141 +++++++++++------- 1 file changed, 88 insertions(+), 53 deletions(-) diff --git a/packages/d2b-provider-volume-local/src/identity.rs b/packages/d2b-provider-volume-local/src/identity.rs index a8e2decab..21b8c4f07 100644 --- a/packages/d2b-provider-volume-local/src/identity.rs +++ b/packages/d2b-provider-volume-local/src/identity.rs @@ -69,17 +69,11 @@ impl Serialize for EntryDigest { /// `Serialize`, and carries no accessor: it is never persisted, never /// public status, and never crosses a Zone boundary. It is dropped and /// re-derived after a controller restart. -pub struct VolumeRootHandle { - pub(crate) fd: Option, - pub(crate) marker_root_fd: Option, - pub(crate) volume_uid: Option, - pub(crate) marker_name: Option, - pub(crate) lock_name: Option, - pub(crate) identity: Option, - pub(crate) marker_binding: Option, - pub(crate) marker_owner_uid: Option, - pub(crate) marker_group_gid: Option, - pub(crate) preexisting_state: bool, +pub enum VolumeRootHandle { + /// No root is held. + Empty, + /// A broker-resolved anchored root is held. + Anchored(Box), } /// Borrowed descriptor view exposed only to the trusted core effect adapter. @@ -138,38 +132,49 @@ pub struct AnchoredRoot { pub preexisting_state: bool, } +/// The trusted adapter-bound inputs for one resolved Volume root. +/// +/// Groups the anchored descriptor, identity, and marker/owner bindings that +/// a broker core boundary resolved. Built only by the effect adapter +/// immediately after resolution; never persisted and never serialized. +#[derive(Debug)] +pub struct AnchoredHandle { + pub(crate) fd: OwnedFd, + pub(crate) marker_root_fd: Option, + pub(crate) volume_uid: ResourceUid, + pub(crate) marker_name: String, + pub(crate) lock_name: String, + pub(crate) identity: VolumeRootIdentity, + pub(crate) marker_binding: MarkerBinding, + pub(crate) marker_owner_uid: u32, + pub(crate) marker_group_gid: u32, + pub(crate) preexisting_state: bool, +} + impl VolumeRootHandle { - /// Record that a validated Volume root descriptor is held. + /// Record that no Volume root descriptor is held. /// /// Only an effect adapter calls this, immediately after it resolved /// the opaque source policy ID against the private allowlist policy. pub const fn held() -> Self { - Self { - fd: None, - marker_root_fd: None, - volume_uid: None, - marker_name: None, - lock_name: None, - identity: None, - marker_binding: None, - marker_owner_uid: None, - marker_group_gid: None, - preexisting_state: false, - } + Self::Empty } /// Borrow the trusted adapter-only descriptor view. pub fn view(&self) -> Option> { + let Self::Anchored(anchored) = self else { + return None; + }; Some(VolumeRootHandleView { - fd: self.fd.as_ref()?.as_fd(), - marker_root_fd: self.marker_root_fd.as_ref().map(AsFd::as_fd), - volume_uid: self.volume_uid.as_ref()?, - marker_name: self.marker_name.as_deref()?, - lock_name: self.lock_name.as_deref()?, - identity: self.identity?, - marker_binding: self.marker_binding.as_ref()?, - marker_owner_uid: self.marker_owner_uid?, - marker_group_gid: self.marker_group_gid?, + fd: anchored.fd.as_fd(), + marker_root_fd: anchored.marker_root_fd.as_ref().map(AsFd::as_fd), + volume_uid: &anchored.volume_uid, + marker_name: &anchored.marker_name, + lock_name: &anchored.lock_name, + identity: anchored.identity, + marker_binding: &anchored.marker_binding, + marker_owner_uid: anchored.marker_owner_uid, + marker_group_gid: anchored.marker_group_gid, }) } @@ -180,68 +185,98 @@ impl VolumeRootHandle { pub fn from_anchored( anchored: AnchoredRoot, ) -> Self { - Self { - fd: Some(anchored.fd), + Self::Anchored(Box::new(AnchoredHandle { + fd: anchored.fd, marker_root_fd: anchored.marker_root_fd, - volume_uid: Some(anchored.volume_uid), - marker_name: Some(anchored.marker_name), - lock_name: Some(anchored.lock_name), - identity: Some(anchored.identity), - marker_binding: Some(anchored.marker_binding), - marker_owner_uid: Some(anchored.marker_owner_uid), - marker_group_gid: Some(anchored.marker_group_gid), + volume_uid: anchored.volume_uid, + marker_name: anchored.marker_name, + lock_name: anchored.lock_name, + identity: anchored.identity, + marker_binding: anchored.marker_binding, + marker_owner_uid: anchored.marker_owner_uid, + marker_group_gid: anchored.marker_group_gid, preexisting_state: anchored.preexisting_state, - } + })) } /// Borrow the broker-resolved Volume-root descriptor. pub fn anchored_fd(&self) -> Option<&OwnedFd> { - self.fd.as_ref() + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(&anchored.fd), + } } /// Borrow the external marker-root descriptor, when configured. pub fn marker_root_fd(&self) -> Option<&OwnedFd> { - self.marker_root_fd.as_ref() + match self { + Self::Empty => None, + Self::Anchored(anchored) => anchored.marker_root_fd.as_ref(), + } } /// Borrow the Volume UID bound to this handle. pub fn volume_uid(&self) -> Option<&ResourceUid> { - self.volume_uid.as_ref() + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(&anchored.volume_uid), + } } /// Borrow the marker filename relative to the marker root. pub fn marker_name(&self) -> Option<&str> { - self.marker_name.as_deref() + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(&anchored.marker_name), + } } /// Borrow the OFD lock filename relative to the Volume root. pub fn lock_name(&self) -> Option<&str> { - self.lock_name.as_deref() + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(&anchored.lock_name), + } } /// Return the root filesystem identity captured at resolution. pub fn root_identity(&self) -> Option { - self.identity + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(anchored.identity), + } } /// Borrow the marker binding captured at resolution. pub fn marker_binding(&self) -> Option<&MarkerBinding> { - self.marker_binding.as_ref() + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(&anchored.marker_binding), + } } /// Return the expected marker owner UID. pub fn marker_owner_uid(&self) -> Option { - self.marker_owner_uid + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(anchored.marker_owner_uid), + } } /// Return the expected marker group GID. pub fn marker_group_gid(&self) -> Option { - self.marker_group_gid + match self { + Self::Empty => None, + Self::Anchored(anchored) => Some(anchored.marker_group_gid), + } } /// Whether the trusted effect already materialized this root. pub fn preexisting_state(&self) -> bool { - self.preexisting_state + match self { + Self::Empty => false, + Self::Anchored(anchored) => anchored.preexisting_state, + } } } From b00a073f2eb6a4ef2ad06ce99e75ace94b2dbd86 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:41:33 -0700 Subject: [PATCH 455/726] d2b-provider-volume-local: route content projections through validating decode --- .../d2b-provider-volume-local/src/content.rs | 114 +++++++++++++++++- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/packages/d2b-provider-volume-local/src/content.rs b/packages/d2b-provider-volume-local/src/content.rs index ddf480a3c..4802ae711 100644 --- a/packages/d2b-provider-volume-local/src/content.rs +++ b/packages/d2b-provider-volume-local/src/content.rs @@ -104,7 +104,7 @@ impl fmt::Debug for ContentProvenance { /// One complete declared file in a content projection. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[serde(rename_all = "camelCase", deny_unknown_fields, try_from = "RawContentFile")] pub struct ContentFile { path: String, owner: ResourceRef, @@ -114,6 +114,34 @@ pub struct ContentFile { digest: String, } +/// Wire mirror for [`ContentFile`]; decode routes through the validating +/// constructor so a derived path can never admit an unvalidated file. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct RawContentFile { + path: String, + owner: ResourceRef, + group: ResourceRef, + mode: String, + bytes: Vec, + digest: String, +} + +impl TryFrom for ContentFile { + type Error = VolumeLocalError; + + fn try_from(raw: RawContentFile) -> Result { + Self::with_digest( + raw.path, + raw.owner, + raw.group, + raw.mode, + raw.bytes, + raw.digest, + ) + } +} + impl ContentFile { /// Construct a file and derive its canonical SHA-256 digest. /// @@ -208,7 +236,7 @@ impl fmt::Debug for ContentFile { /// A complete, typed Volume content declaration. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[serde(rename_all = "camelCase", deny_unknown_fields, try_from = "RawContentProjection")] pub struct ContentProjection { volume_uid: ResourceUid, provenance: ContentProvenance, @@ -217,6 +245,34 @@ pub struct ContentProjection { content_digest: String, } +/// Wire mirror for [`ContentProjection`]; decode routes through validation +/// so a derived path can never admit an unvalidated projection. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct RawContentProjection { + volume_uid: ResourceUid, + provenance: ContentProvenance, + ownership_marker: String, + files: Vec, + content_digest: String, +} + +impl TryFrom for ContentProjection { + type Error = VolumeLocalError; + + fn try_from(raw: RawContentProjection) -> Result { + let projection = Self { + volume_uid: raw.volume_uid, + provenance: raw.provenance, + ownership_marker: raw.ownership_marker, + files: raw.files, + content_digest: raw.content_digest, + }; + projection.validate()?; + Ok(projection) + } +} + impl ContentProjection { /// Construct and validate a complete content declaration. /// @@ -381,7 +437,7 @@ impl ObservedContentFile { } /// Durable evidence that every projected file was materialized and read back. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ContentMaterializationEvidence { volume_uid: ResourceUid, @@ -393,7 +449,7 @@ pub struct ContentMaterializationEvidence { } /// Readback evidence for one projected file without retaining its bytes. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ContentFileEvidence { path: String, @@ -554,7 +610,11 @@ pub const NETWORK_CONFIG_FILE_MODE: &str = "0640"; /// Four exact Network configuration files submitted to `volume-local`. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[serde( + rename_all = "camelCase", + deny_unknown_fields, + try_from = "RawNetworkConfigContentProjection" +)] pub struct NetworkConfigContentProjection { volume_uid: ResourceUid, network_ref: ResourceRef, @@ -570,6 +630,48 @@ pub struct NetworkConfigContentProjection { content_digest: String, } +/// Wire mirror for [`NetworkConfigContentProjection`]; decode routes through +/// validation so a derived path can never admit an unvalidated projection. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct RawNetworkConfigContentProjection { + volume_uid: ResourceUid, + network_ref: ResourceRef, + provenance: NetworkProvenance, + ownership_marker: String, + file_owner: ResourceRef, + file_group: ResourceRef, + file_mode: String, + dnsmasq: Vec, + nftables: Vec, + routing: Vec, + attachments: Vec, + content_digest: String, +} + +impl TryFrom for NetworkConfigContentProjection { + type Error = VolumeLocalError; + + fn try_from(raw: RawNetworkConfigContentProjection) -> Result { + let projection = Self { + volume_uid: raw.volume_uid, + network_ref: raw.network_ref, + provenance: raw.provenance, + ownership_marker: raw.ownership_marker, + file_owner: raw.file_owner, + file_group: raw.file_group, + file_mode: raw.file_mode, + dnsmasq: raw.dnsmasq, + nftables: raw.nftables, + routing: raw.routing, + attachments: raw.attachments, + content_digest: raw.content_digest, + }; + projection.validate()?; + Ok(projection) + } +} + impl NetworkConfigContentProjection { /// Construct and validate a Network configuration projection. #[allow(clippy::too_many_arguments)] @@ -707,7 +809,7 @@ impl fmt::Debug for NetworkConfigContentProjection { } /// Status evidence returned after the Network projection is read back. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct NetworkConfigMaterializationEvidence { volume_uid: ResourceUid, From eba219aa62d28b55854c69c0de34806b97759769 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:42:09 -0700 Subject: [PATCH 456/726] provider-notification-desktop: distinguish denied deliveries from key errors --- .../src/host_sink.rs | 18 +++++++++--------- .../src/runtime.rs | 2 +- .../src/types.rs | 3 +++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/d2b-provider-notification-desktop/src/host_sink.rs b/packages/d2b-provider-notification-desktop/src/host_sink.rs index 0449f600a..fa351dba7 100644 --- a/packages/d2b-provider-notification-desktop/src/host_sink.rs +++ b/packages/d2b-provider-notification-desktop/src/host_sink.rs @@ -182,7 +182,7 @@ impl NotificationSink { provider = "notification-desktop", "delivery refused: source session not authenticated" ); - crate::types::NotificationError::InvalidOpaqueKey + crate::types::NotificationError::Denied })?; if !self.observer_enabled { return Err(crate::types::NotificationError::ObserverDisabled); @@ -192,14 +192,14 @@ impl NotificationSink { provider = "notification-desktop", "delivery refused: observer session not authenticated" ); - crate::types::NotificationError::InvalidOpaqueKey + crate::types::NotificationError::Denied })?; if source_session.zone() != observer_session.zone() { debug!( provider = "notification-desktop", "delivery refused: source and observer zone mismatch" ); - return Err(crate::types::NotificationError::InvalidOpaqueKey); + return Err(crate::types::NotificationError::Denied); } let observer_session = observer_session.session_key(); self.nonces.gc(now_secs); @@ -297,9 +297,9 @@ impl NotificationSink { /// /// # Errors /// - /// Returns [`crate::types::NotificationError::InvalidOpaqueKey`] when the - /// Guest source rejects the session or request, and the delivery - /// validation errors (`FieldBounds`, `InvalidIcon`, `InvalidActions`, + /// Returns [`crate::types::NotificationError::Denied`] when the Guest + /// source rejects the session or request, and the delivery validation + /// errors (`FieldBounds`, `InvalidIcon`, `InvalidActions`, /// `InvalidTimeout`, `InvalidOpaqueKey`, `ObserverDisabled`) when the /// request or observer stream fails its bounded validation. pub fn deliver_from_guest_source( @@ -313,7 +313,7 @@ impl NotificationSink { ) -> Result { source .validate_authenticated(source_session, &request) - .map_err(|_| crate::types::NotificationError::InvalidOpaqueKey)?; + .map_err(|_| crate::types::NotificationError::Denied)?; self.deliver(port, source_session, observer_session, request, now_secs) } @@ -584,7 +584,7 @@ mod tests { let source = test_source("guest"); assert_eq!( sink.deliver(&mut port, &source, &source, request_with_action(), 100), - Err(crate::types::NotificationError::InvalidOpaqueKey) + Err(crate::types::NotificationError::Denied) ); let observer = test_observer("alice"); @@ -623,7 +623,7 @@ mod tests { request_with_action(), 100, ), - Err(crate::types::NotificationError::InvalidOpaqueKey) + Err(crate::types::NotificationError::Denied) ); } diff --git a/packages/d2b-provider-notification-desktop/src/runtime.rs b/packages/d2b-provider-notification-desktop/src/runtime.rs index 117460cb7..efc2f2129 100644 --- a/packages/d2b-provider-notification-desktop/src/runtime.rs +++ b/packages/d2b-provider-notification-desktop/src/runtime.rs @@ -105,7 +105,7 @@ impl NotificationRuntime { .guest_sources() .iter() .find(|configured| configured.source_ref() == source_session.subject_ref()) - .ok_or(NotificationError::InvalidOpaqueKey)?; + .ok_or(NotificationError::Denied)?; let guest_source = GuestSource::from_config_at_generation(config, source_session.generation()) .map_err(|_| NotificationError::InvalidOpaqueKey)?; diff --git a/packages/d2b-provider-notification-desktop/src/types.rs b/packages/d2b-provider-notification-desktop/src/types.rs index 836fb3f30..389ec742d 100644 --- a/packages/d2b-provider-notification-desktop/src/types.rs +++ b/packages/d2b-provider-notification-desktop/src/types.rs @@ -210,6 +210,8 @@ pub enum NotificationError { InvalidTimeout, /// A correlation or idempotency key exceeded its bound. InvalidOpaqueKey, + /// The delivery was refused by session admission or zone policy. + Denied, /// The authenticated observer stream is disabled by Provider policy. ObserverDisabled, } @@ -222,6 +224,7 @@ impl core::fmt::Display for NotificationError { Self::InvalidActions => "notification-actions-invalid", Self::InvalidTimeout => "notification-timeout-invalid", Self::InvalidOpaqueKey => "notification-opaque-key-invalid", + Self::Denied => "notification-denied", Self::ObserverDisabled => "notification-observer-disabled", }) } From 20af5f9ab3739e046d716ba490359510a9276761 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:43:19 -0700 Subject: [PATCH 457/726] audit: fold the core provider slice --- .../2026-09-24-rust-skills-audit/ledger.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 394725efa..52c14b5a2 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -297,8 +297,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 7a5a7f957,4e20f7674 | packages/d2b-bus/src/session/zone_link.rs | folded admission+liveness into private EstablishedLane; test lane keeps None; all three gate sites migrated; follow-up commit reattaches the doc to ZoneLinkSession | | | `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | ResourceQuery assignment/scope Option pair folded into one Option<(AssignmentIdentity, ScopedResourceScope)>; pub assignment()/scope() accessors keep signatures via const match; validate_scoped now on | | | `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | -| `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broke` | | | -| `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2805, packages/d2b-contracts-broker/src/b` | | | +| `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/host_generation.rs | HandoffCoordinator.source_remains_usable field dropped; accessor derives from state != Completed; old durable records deserialize (unknown field ignored); wire response field untouched. | | +| `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/broker_wire.rs | CanonicalAuditDigest tuple field made private; parse and as_str remain the only construction/read paths; hand-written Deserialize and serde transparent keep wire shape. | | | `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | | | | `public_wire.rs:2166, public_wire.rs:2203` | | | | `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | | | | `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:316, public_wire.rs:311` | | | @@ -321,7 +321,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider` | | | | `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipb` | | | | `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard` | | | -| `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixo` | | | +| `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/service.rs | Request fields sealed to pub(crate); ConfigSyncRequest::new now calls validate_guest_ref, closing the Guest/ drift; serde derive keeps wire JSON unchanged. | | | `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | applied-variant | U3 | 1ce473a70 | packages/d2b-provider-credential/src/driver.rs | zone: String -> d2b_contracts_resource::v3::ZoneId in CredentialDriverArgs and CredentialDriver; agent_child builds the zone ref with expect on a validated ZoneId (fallible ResourceRef::parse path dro | | | `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | applied | U3 | cd8838c03 | packages/d2b-provider-credential-managed-identity/src/controller.rs | seal `ManagedIdentityTeardownPlan`'s three bool fields behind `pub const fn` accessors so invalid combos (stop_agent && delete_agent, delete_agent && clear_provider_revoke) are unrepresentable; tests | | | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | @@ -336,14 +336,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | 82f8cac47 | packages/d2b-provider-guest-qemu-media/src/config.rs | 7 gate calls now use BoundedToken::parse(...) .is_err(); local validate_token helper and its pub(crate) re-export deleted; qmp validate_object_id delegates to BoundedToken::parse. Deviation: validate_ | | | `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | b845000ff | packages/d2b-provider-guest-qemu-media/src/config.rs | impl Default for ProviderConfig deleted (it manufactured a config that fails its own validate());the sole consumer test now builds valid-then-mutated configs (controller_execution_ref swapped to a Gue | | | `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-` | | | -| `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `agent.rs:56, agent.rs:265, agent.rs:297` | | | +| `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/agent.rs | ProviderAgentAuditEvent stores parsed BoundedToken values; Serialize renders via as_str(); parse-then-copy-back removed, wire output unchanged. | | | `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U3 | 9fbe75ec2 | packages/d2b-provider-process-minijail/src/launch.rs | validate_launch_ticket renamed to validate_platform_gate and reduced to the gate check (identity checks live only in MinijailProcessProvider::validate); lib.rs:160 literal replaced with crate::PROVIDE | | | `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | | `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | aee724326 | packages/d2b-provider-process-systemd/src/metrics.rs | Added MetricLabelKey enum with as_str(); validate_labels takes typed keys; dropped LABEL_KEYS const (census: only in-crate definition, zero users). Unknown-key rejection now type-level; test updated. | | | `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry` | | | | `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServicePhase enum (as_str for the three spellings) and TelemetryServiceProjection struct (serde camelCase, contract-pinned {serviceRole, serviceReadiness} shape) replace the json! literals; n | | | `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | -| `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | | | | `src/identity.rs:72-88, src/identity.rs:146-150` | | | +| `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U3 | d52b7052c | packages/d2b-provider-volume-local/src/identity.rs | VolumeRootHandle split into Empty / Anchored(Box); mixed Option states unrepresentable; boxed payload per denied large_enum_variant lint; non-Clone/non-Serialize kept. | | | `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | watch: bool replaced with pub enum ScopedQueryMethod { List, Watch }; bus router call site and adapter test updated. | | | `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | f7b48c947 | packages/d2b-resource-client/src/dispatch.rs | Dropped the unreachable validate_lifetime()? re-check at CallDriver::new (MetadataInput::new enforces the invariant at construction; builder methods cannot change the lifetime fields) and removed the | | | `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/scheduler.rs | channel() now returns Result; the constructor-prevented NamedStream-without-stream combination yields InvalidChannel instead of a silent SESSION_CONTROL misroute. Census re-run: only caller | | @@ -382,7 +382,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | applied-variant | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | Census re-run:= with_observer/with_observer_and_metrics/with_clock_and_observer have zero ZoneBus callers, deleted; with_clock -> pub(crate) because production new() delegates to it; with_clock_observ | | | `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | -| `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114` | | | +| `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | | `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | | `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but | | @@ -516,7 +516,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | Claim re-verified at HEAD: `guest_socket_directory` (ops/device_worker.rs:262-284) returns `Result<&'static str, &'static str>`-style plain-static-code refusals, consumed at live_handlers.rs:2428 by s | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/src/seam.rs | verify_startup_routing returns Result<(), StartupRoutingViolation> (UnadmittedHandler/MissingHandlers, Display preserved for main.rs); audit_crate/run_cargo_metadata/dependency_tree return Result<_, S | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | -| `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | | | | `packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:2` | | | +| `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/configured_argv.rs | ConfiguredArgvError, LauncherMetadataError, UnsafeLocalWorkloadsError, MediaRefError, UsbBusIdError, AuditPageError enums with Display+Error replace String/&'static str returns; unwrap-only callers co | | | `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | Added fmt::Display (message "invalid shell name") and std::error::Error impls to ShellNameError; additive, no surface moved. cargo check/test/clippy -p d2b-contracts-control --locked all passed | | | `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | applied | U3 | 58e72374f | packages/d2b-contracts-provider/src/v3/provider_registry.rs | split zero-generation check before mapping-count bound; Defensive-only reachability since ResourceGeneration rejects 0 at new/Deserialize; no consumer pins the code | | | `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError Display strings are wire outcome codes pinned by docs/specs/ADR-046-resources-credential.md:903 (credential-queue-pressure = lease table at capacity) and the provider ADR err | | @@ -540,7 +540,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | da5acd332 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Binary Result<_, String> signatures and format!-built errors migrated to anyhow; typed BridgeReadError/ControlReadError/ReasonCode untouched; control-socket JSON bodies byte-identical. | | | `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clip` | | | | `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provide` | | | -| `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixo` | | | +| `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/ttrpc.rs | Encoding-failure branch now maps to ttrpc Code::INTERNAL, matching the config-document-encoding-failed code class. | | | `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | export_checkpoints now rejects an unparseable lease-map key with the crate's typed `InvariantFailure` refusal instead of a `.expect()` panic; shares commit dbec5dde7 with RS-0368 (same lib.rs surface, | | | `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | | `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 2f5c9a692 | packages/d2b-provider-device-usbip/src/state_machine.rs | | | @@ -552,7 +552,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/nftables.rs:588` | | | | `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | | | | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | | | | `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-not` | | | -| `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `ingress_policy.rs:647` | | | +| `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/ingress_policy.rs | Full connection-table rejection now reports IngressErrorClass::None, consistent with the sibling capacity refusal. | | | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/d` | | | | `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | | `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | @@ -626,7 +626,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | | | | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-p` | | | | `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264` | | | | `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | | | | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | | | -| `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | | | | `src/content.rs:38-39, src/content.rs:106-107, src/content.rs:203-204, src/content.rs:239-2` | | | +| `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | applied | U3 | b00a073f2 | packages/d2b-provider-volume-local/src/content.rs | ContentFile/ContentProjection/NetworkConfigContentProjection decode via serde try_from Raw mirrors running validating constructors; Deserialize dropped from evidence types; wire shape unchanged. | | | `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | | `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | | `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | applied-variant | U3 | f1bb96854 | packages/d2bd/src/composition.rs | deny_unknown_fields added to both GatewayGuestConfigFile and GatewayGuestRelayConfigFile. The config-typo test landed as direct deserialization tests on both structs (gateway_guest_config_tests mod), | | From fde0a04405df3d10ba5dff5593b0a9e728ec7899 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:43:59 -0700 Subject: [PATCH 458/726] unsafe-local-helper: key launch reservations by operation id --- packages/d2b-unsafe-local-helper/src/runtime.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/d2b-unsafe-local-helper/src/runtime.rs b/packages/d2b-unsafe-local-helper/src/runtime.rs index 6a5738b7e..88e03391b 100644 --- a/packages/d2b-unsafe-local-helper/src/runtime.rs +++ b/packages/d2b-unsafe-local-helper/src/runtime.rs @@ -152,7 +152,7 @@ pub struct ScopeRuntime { pub(crate) struct RuntimeLedger { pub(crate) persisted: PersistedScopeLedger, - pub(crate) reservations: BTreeMap, + pub(crate) reservations: BTreeMap, next_owner: u64, } @@ -190,7 +190,6 @@ impl RuntimeLedger { operation_id: &OperationId, fingerprint: [u8; 32], ) -> Result { - let operation_key = operation_id.to_string(); if let Some(scope) = self .persisted .scopes @@ -203,7 +202,7 @@ impl RuntimeLedger { Err(RuntimeError::OperationIdConflict) }; } - if let Some(reservation) = self.reservations.get(&operation_key) { + if let Some(reservation) = self.reservations.get(operation_id) { return if reservation.fingerprint == fingerprint { Err(RuntimeError::OperationInProgress) } else { @@ -227,19 +226,19 @@ impl RuntimeLedger { fingerprint, owner: self.next_owner, }; - self.reservations.insert(operation_key, reservation); + self.reservations.insert(operation_id.clone(), reservation); Ok(LaunchBegin::Started(reservation)) } fn owns(&self, operation_id: &OperationId, reservation: LaunchReservation) -> bool { self.reservations - .get(operation_id.as_str()) + .get(operation_id) .is_some_and(|active| active.owner == reservation.owner) } fn clear(&mut self, operation_id: &OperationId, reservation: LaunchReservation) { if self.owns(operation_id, reservation) { - self.reservations.remove(operation_id.as_str()); + self.reservations.remove(operation_id); } } From 963d83ff993c99a84de12ed3014339d0594d5244 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:45:00 -0700 Subject: [PATCH 459/726] audit: fold the activation and qemu slice --- .../2026-09-24-rust-skills-audit/ledger.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 52c14b5a2..3eedafa55 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -348,7 +348,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | f7b48c947 | packages/d2b-resource-client/src/dispatch.rs | Dropped the unreachable validate_lifetime()? re-check at CallDriver::new (MetadataInput::new enforces the invariant at construction; builder methods cannot change the lifetime fields) and removed the | | | `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/scheduler.rs | channel() now returns Result; the constructor-prevented NamedStream-without-stream combination yields InvalidChannel instead of a silent SESSION_CONTROL misroute. Census re-run: only caller | | | `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | bd25f4ce9 | packages/d2b-session/src/engine.rs | | | -| `RS-0299` | `type` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0299` | `type` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | fde0a0440 | packages/d2b-unsafe-local-helper/src/runtime.rs | RuntimeLedger.reservations re-keyed from String to BTreeMap; operation_key deleted; begin/owns/clear use the typed id directly (clone on insert). OperationId derives Or | | | `RS-0303` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | force semantics implemented in apply(): dropped `let _ = self.force;` and gated the graceful wait on `wait_for_ready && !force`. Checks: cargo check -p d2bd --locked --all-targets green. | | | `RS-0305` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | b310cab7bdafa68156e88ee513f3083bbe3d25a2 | packages/d2bd/src/shared_provider_effects.rs | Added crate-private SharedProviderEffectMode enum (Deserialize, rename_all kebab-case) with a fail-closed parse; both stringly-compare sites (usbip_service_port opted_in, reconcile_security_key projec | | | `RS-0302` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | ShutdownDegradedMarker now stores VmShutdownOutcome enum (derive Serialize/Deserialize, rename_all snake_case) instead of String outcome/severity; construction site passes the enum. Report shape uncha | | @@ -445,9 +445,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | dc09819bf | packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | Deleted constant-true preserve_state() accessor and its tautological assertion (census: only consumer was the assertion). check+finalize_ordering tests (6) + clippy green. | | | `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | | `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | Seven dead-pub items in the private mod driver narrowed to pub(crate): HostDriver, HostDriverError, HostDriverStatus, HostDriverFactory, HostDriverEffects, host_spec_decoder, HOST_REOBSERVE. Census re | | -| `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/routes.rs:244-279, src/routes.rs:264-265` | | | -| `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:1019, packages/d2b-provider-n` | | | -| `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:110, packages/d2b-provider-no` | | | +| `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | applied-variant | U3 | f17f141c6 | packages/d2b-provider-network-local/src/routes.rs | Both route provenance validators narrowed to #[cfg(test)] pub(crate) and the stale #[allow(dead_code)] removed. Variant: plain pub(crate) alone re-triggers dead_code (both validators have zero product | | +| `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied-variant | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Deleted uncalled reconcile_authenticated_display (census: def only, zero callers); reconcile_sources and drain_sources lowered to #[cfg(test)] pub(crate) (test-only). Variant: plain pub(crate) would r | | +| `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Stale #[allow(dead_code)] removed from from_route, which is reachable from production via from_authenticated_route. Same commit as RS-0394 (same file). | | | `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1-3, packages/d2b-provi` | | | | `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd` | | | | `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | @@ -490,7 +490,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | | `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | | | | `packages/d2b-session-unix/src/socket.rs:176` | | | | `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | applied | U3 | b9fc346fc | packages/d2b-sk-frontend/src/lib.rs | agent/config/link/uhid made private; UhidDevice and UhidEvent re-exported from lib.rs; main.rs:41 uses root re-exports. Census: sk_frontend::(agent/config/link/uhid):: = 0 full-path hits; zone-routing | | -| `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | not-started | U3 | | `packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/` | Surface narrowing (SupervisorSpec, send_frame/receive_frame/configure_socket_buffers, SUPERVISOR_START_TIMEOUT, SNAPSHOT_RECONCILE_TIMEOUT) not applied; census re-run complete and supports the claim ( | | | `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/composition.rs | process_provider_runtime and provider_effects narrowed to pub(crate) with a cfg(feature=test-support) pub mod seam for tests/resource_operator_activation.rs; test-only items (new_persistent, admit, pe | | | `RS-0441` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/resource_plane_v3.rs | ResourcePlaneV3 accessors: targets()/hub() return Arc by value, store()/registry() return plain refs; Arc::clone(plane.hub()/targets()) sites updated to plane.hub()/plane.targets(); adopt_guest_target | | | `RS-0439` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | pub surface reduced to pub(crate): trait HostAudioController, PipeWireHostController, from_audio_node, find_audio_node, QemuAudioController. Census re-run: only in-crate callers (audio_dispatch.rs); m | | @@ -549,9 +549,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 64c41ddb5 | packages/d2b-provider-display-wayland/src/spec.rs | WaylandSpecError::NoPrincipalAvailable variant + Display arm deleted; no error-codes.md hit; no other constructors (controller uses PrincipalPoolError/SessionCondition). | | | `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | applied-variant | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | observe_host returns Result<_, ObserveError>; the flattening format! is replaced by a closed error carrying both SystemCoreError legs with Error::source() (fallback is the chain source, probe error re | | | `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | HostDriverError::Display delegates to self.kind.failure_kind().code(); the three registry codes verified identical to the re-spelled literals. | | -| `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/nftables.rs:588` | | | +| `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | applied | U3 | 200aa2bb2 | packages/d2b-provider-network-local/src/nftables.rs | Sole non-test unwrap replaced with try_into().expect naming the statically-known invariant (64-byte chunk yields a 4-byte word slice). check/clippy exit 0; nftables tests pass. | | | `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | | | | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | | | -| `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-not` | | | +| `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U3 | eba219aa6 | packages/d2b-provider-notification-desktop/src/types.rs | Added NotificationError::Denied (slug notification-denied; not pinned in docs/reference) and mapped the five admission/zone/category rejection sites (host_sink.rs source/observer admission, zone misma | | | `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/ingress_policy.rs | Full connection-table rejection now reports IngressErrorClass::None, consistent with the sibling capacity refusal. | | | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/d` | | | | `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | @@ -579,7 +579,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | | `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | | | | `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_` | | | -| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | | | +| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | Stated fix changes a wire-visible HelperFailureCode mapping pinned in docs/reference/error-codes.md; deferred as contract-adjacent. | | | `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | | `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | a91ad9bbc | packages/d2bd/src/resource_plane_v3.rs | PlaneError's five String variants retyped: FoundationSeed(#[from] SeedError), ManagerSpawn(#[from] ractor::SpawnErr), Bundle(#[from] ResourceBundleError), Authority/Target(#[source] Box kept. | | | `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | | `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/driver.rs:282-289, src/driver.rs:190` | | | -| `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429` | | | +| `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | U3 | 336a4fd97 | packages/d2b-provider-network-local/src/broker.rs | Four provenance payload builders (resolved_bridge_payload/resolved_route_payload in broker.rs and operations.rs) no longer .ok()-swallow serde_json::to_value(provenance); they now propagate with map_e | | | `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generate` | | | | `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | | | | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-p` | | | | `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264` | | | @@ -655,7 +655,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | | `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied-variant | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | TransportEntry carries endpoint/binding ids; the spawn block captures clones and threads them through run_bridge (copy-failure event gets fields) and emit_event (subscriber-drop event gets fields); th | | | `RS-0600` | `obs` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Replaced eprintln with tracing::debug!(error = %error, "create envelope validation failed"); tracing already a dependency and used in the crate. | | -| `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/protocol.rs:188` | | | +| `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | not-started | U3 | | `packages/d2b-unsafe-local-helper/src/protocol.rs:188` | Not applied: the stated fix (include request_id and operation_id in the protocol.rs:188 eprintln record) conflicts with the mandatory observability rule - operation_id is a pinned opaque correlation i | | | `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Accept loop's four eprintln! calls replaced with tracing::error! events: connection-handler failures carry error = %error.message() (and peer_uid = peer.uid, captured before the move into the handler; | | | `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Three lifecycle info events gained named fields: Guest-local ZoneLink transport Provider composed and Guest target-control service composed carry zone = %identity.zone() and guest_ref = %identity.gues | | | `RS-0607` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 31248998b093d92fef1e41eb07ecb49e3b79d33c | packages/d2bd/src/provider_lifecycle.rs | publish_trusted_context failure arm now carries error = %error as a named field, matching the sibling Ok(_) arm and the plane's other warn sites. cargo check green; clippy green for d2bd. | | From 8ed2af518841256702a4654e93e6c48442e833a1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:48:12 -0700 Subject: [PATCH 460/726] audit: fold the two media rows the slice provably landed --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 3eedafa55..407786ff1 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -316,7 +316,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0262` | `type` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | | | | `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 81d0ff057 | packages/d2b-process-conformance/src/ticket.rs | Bundled zone_uid+runtime_scope into one private Option pairing; const-compatible match accessors keep the public API byte-identical. | | | `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | 87e8d7654 | packages/d2b-provider-audio-pipewire/src/resource_type.rs | owner()/new() now infallible; validate_audio_* remain the single admission gate (they also check provider_ref/extension/zone the ctors cannot). All call sites updated; check+test+clippy green on 4 cra | | -| `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199` | | | +| `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | Shared-vs-owned controller mode carried in the type; mixer speaker path split into grant/revoke so the return contract stops being argument-dependent. Suite 94/94. | | | `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 4404afb72 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Merged picker (args.picker.or(config)) validated once after merge; relative paths rejected from either source. | | | `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider` | | | | `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipb` | | | @@ -330,7 +330,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | needs-contract | U3 | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery recor | | | `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired — the illegal Consumed/Expired-with-Some(psk) combination is now unco | | | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | -| `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `identity.rs:857-865, controller.rs:1808-1818` | | | +| `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | e53601c88 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | derive_private_runtime_scope and private_runtime_scope take ChildRole and use role.suffix(); the &str whitelist branch is gone. Callers incl. wayland-policy migrated. | | | `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | | `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `bootstrap_graph.rs:142-176, controller.rs:662-670` | | | | `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | 82f8cac47 | packages/d2b-provider-guest-qemu-media/src/config.rs | 7 gate calls now use BoundedToken::parse(...) .is_err(); local validate_token helper and its pub(crate) re-export deleted; qmp validate_object_id delegates to BoundedToken::parse. Deviation: validate_ | | From a9902b8e7c096bd22fce63c6831894ad9a2eeb9e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:49:34 -0700 Subject: [PATCH 461/726] unsafe-local-helper: narrow unwired exported surface to module-private --- packages/d2b-unsafe-local-helper/src/protocol.rs | 6 +++--- packages/d2b-unsafe-local-helper/src/runtime.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/d2b-unsafe-local-helper/src/protocol.rs b/packages/d2b-unsafe-local-helper/src/protocol.rs index 2e80d095a..6f6ffeb8d 100644 --- a/packages/d2b-unsafe-local-helper/src/protocol.rs +++ b/packages/d2b-unsafe-local-helper/src/protocol.rs @@ -307,7 +307,7 @@ fn peer_uid_is_exact(peer_uid: u32, expected_uid: u32) -> bool { peer_uid != 0 && expected_uid != 0 && peer_uid == expected_uid } -pub fn configure_socket_buffers(socket: &Socket) -> Result<(), ProtocolError> { +fn configure_socket_buffers(socket: &Socket) -> Result<(), ProtocolError> { socket .set_send_buffer_size(HELPER_SOCKET_BUFFER_REQUEST_BYTES) .map_err(|_| ProtocolError::BufferTooSmall)?; @@ -334,7 +334,7 @@ fn effective_socket_buffers_sufficient(send_size: usize, recv_size: usize) -> bo // Runs on the helper process main thread inside HelperClient::run's sync // service loop (CLI entry; never an executor). #[allow(clippy::disallowed_methods, reason = "CLI-only path")] -pub fn send_frame(socket: &Socket, frame: &T) -> Result<(), ProtocolError> { +fn send_frame(socket: &Socket, frame: &T) -> Result<(), ProtocolError> { let payload = serde_json::to_vec(frame).map_err(|_| ProtocolError::InvalidFrame)?; if payload.len() > MAX_HELPER_FRAME_SIZE { return Err(ProtocolError::FrameTooLarge); @@ -354,7 +354,7 @@ pub fn send_frame(socket: &Socket, frame: &T) -> Result<(), // Runs on the helper process main thread inside HelperClient::run's sync // service loop (CLI entry; never an executor). #[allow(clippy::disallowed_methods, reason = "CLI-only path")] -pub fn receive_frame( +fn receive_frame( socket: &Socket, encoded: &mut [u8], ) -> Result { diff --git a/packages/d2b-unsafe-local-helper/src/runtime.rs b/packages/d2b-unsafe-local-helper/src/runtime.rs index 88e03391b..409c9329b 100644 --- a/packages/d2b-unsafe-local-helper/src/runtime.rs +++ b/packages/d2b-unsafe-local-helper/src/runtime.rs @@ -32,8 +32,8 @@ use std::time::{Duration, Instant}; use uzers::os::unix::UserExt; use uzers::{get_current_uid, get_user_by_uid}; -pub const SUPERVISOR_START_TIMEOUT: Duration = Duration::from_secs(25); -pub const SNAPSHOT_RECONCILE_TIMEOUT: Duration = Duration::from_secs(20); +const SUPERVISOR_START_TIMEOUT: Duration = Duration::from_secs(25); +const SNAPSHOT_RECONCILE_TIMEOUT: Duration = Duration::from_secs(20); const MAX_LEDGER_BYTES: u64 = 1024 * 1024; const PROXY_READY_TIMEOUT: Duration = Duration::from_secs(5); const FIRST_CLIENT_TIMEOUT: Duration = Duration::from_secs(10); @@ -569,7 +569,7 @@ pub(crate) fn hex(bytes: &[u8]) -> String { #[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct SupervisorSpec { +struct SupervisorSpec { program: PathBuf, args: Vec, environment: BTreeMap, From 4a568a3278449c9fa779cf71d9ab5a056c1a0aaf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:49:53 -0700 Subject: [PATCH 462/726] audit: fold the half-landed provider slice and its contract classifications --- .../2026-09-24-rust-skills-audit/ledger.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 407786ff1..bc7f3ea0d 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -284,9 +284,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0229` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | mem::take on the mut slot before in-place edit | | | `RS-0230` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | two ratchet probes key borrowed strs via signal fields | | | `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | | | -| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_` | | | +| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | Disposition is &'static str in a generator-emitted closed set with a drift gate; typing it needs a generator change (generated artifact). | | | `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | -| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | | | | `packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_op` | | | +| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | The destructive flag is emitted as a bare boolean by the operations generator; the stated drop of the arity allow is not implementable while the helper takes eight arguments. | | | `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | escalated | U1 | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | wave 0 applied the panicking constructor member (RS-0516); the five remaining provider-crate zone/key_ref member sites are the family wave's | U5 | | `RS-0263` | `type` | `d2b` | low | actionable | leaf | applied | U3 | f98ad4f82 | packages/d2b/src/context.rs | ZoneContext now stores ZoneId; zone_ref/zone_name built from it; validate_zone_name deleted; discover double validation removed; from_socket takes ZoneId directly. | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | @@ -340,7 +340,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U3 | 9fbe75ec2 | packages/d2b-provider-process-minijail/src/launch.rs | validate_launch_ticket renamed to validate_platform_gate and reduced to the gate check (identity checks live only in MinijailProcessProvider::validate); lib.rs:160 literal replaced with crate::PROVIDE | | | `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | | `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | aee724326 | packages/d2b-provider-process-systemd/src/metrics.rs | Added MetricLabelKey enum with as_str(); validate_labels takes typed keys; dropped LABEL_KEYS const (census: only in-crate definition, zero users). Unknown-key rejection now type-level; test updated. | | -| `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | | | | `packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry` | | | +| `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | applied | U3 | c4ea8fb10 | packages/d2b-provider-telemetry-binding/src/lib.rs | PHASE_PENDING/PHASE_DEGRADED constants became a TelemetryBindingPhase enum with matching as_str spellings; driver suite green. | | | `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServicePhase enum (as_str for the three spellings) and TelemetryServiceProjection struct (serde camelCase, contract-pinned {serviceRole, serviceReadiness} shape) replace the json! literals; n | | | `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | | `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U3 | d52b7052c | packages/d2b-provider-volume-local/src/identity.rs | VolumeRootHandle split into Empty / Anchored(Box); mixed Option states unrepresentable; boxed payload per denied large_enum_variant lint; non-Clone/non-Serialize kept. | | @@ -365,7 +365,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0313` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 1d692db3d | packages/xtask/src/provider_crate_policy.rs | FamilyKnowledgeSignal gains typed count: Option; ServerState site fills it and drops the serialized-count text; renderer matches class without the parse;the ratchet JSON stays byte-identical (t | | | `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option> wrapper is gone (plain Box), so the consumed state is unrepresentable and all three expects disappeared; public signatures a | | | `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | -| `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | | | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | | | -| `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_` | | | +| `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | not-started | U3 | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | Re-verified actionable at HEAD but not applied: budget ended. | | +| `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | not-started | U3 | | `packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_` | Re-verified actionable at HEAD but not applied: budget ended. | | | `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | Stated fix changes a wire-visible HelperFailureCode mapping pinned in docs/reference/error-codes.md; deferred as contract-adjacent. | | | `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | From f1404725de00ec428f5c6b5d9709960a869f63a2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:50:39 -0700 Subject: [PATCH 463/726] cloud-hypervisor: carry VMM start gating facts as one readiness snapshot --- .../src/bootstrap_graph.rs | 103 ++++++++++++------ .../src/controller.rs | 10 +- 2 files changed, 72 insertions(+), 41 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs index 14281b8d0..86d0a9a0d 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs @@ -129,15 +129,8 @@ impl BootstrapGraph { } /// Check all pre-start dependencies without performing an effect. - pub fn vmm_readiness( - &self, - devices_ready: bool, - networks_ready: bool, - volumes_ready: bool, - bindings_ready: bool, - setup_ready: bool, - ) -> DependencyReadiness { - if devices_ready && networks_ready && volumes_ready && bindings_ready && setup_ready { + pub fn vmm_readiness(&self, snapshot: VmmReadinessSnapshot) -> DependencyReadiness { + if snapshot.all_ready() { DependencyReadiness::Ready } else { DependencyReadiness::Pending @@ -145,27 +138,43 @@ impl BootstrapGraph { } /// Return the pure VMM lifecycle decision for a dependency snapshot. - pub fn vmm_lifecycle( - &self, - devices_ready: bool, - networks_ready: bool, - volumes_ready: bool, - bindings_ready: bool, - setup_ready: bool, - ) -> VmmLifecycleEligibility { - match self.vmm_readiness( - devices_ready, - networks_ready, - volumes_ready, - bindings_ready, - setup_ready, - ) { + pub fn vmm_lifecycle(&self, snapshot: VmmReadinessSnapshot) -> VmmLifecycleEligibility { + match self.vmm_readiness(snapshot) { DependencyReadiness::Ready => VmmLifecycleEligibility::Running, DependencyReadiness::Pending => VmmLifecycleEligibility::Stopped, } } } +/// Immutable readiness facts gating VMM start. +/// +/// Carried as one struct so a swapped argument cannot silently change the +/// start gate; the facts are produced by `GuestDependencySnapshot` accessors. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct VmmReadinessSnapshot { + /// Device family readiness. + pub devices_ready: bool, + /// Network family readiness. + pub networks_ready: bool, + /// Volume family readiness. + pub volumes_ready: bool, + /// VolumeBinding family readiness under the current fence. + pub bindings_ready: bool, + /// Descriptor setup-volume readiness. + pub setup_ready: bool, +} + +impl VmmReadinessSnapshot { + /// Return whether every gating fact is ready. + pub const fn all_ready(self) -> bool { + self.devices_ready + && self.networks_ready + && self.volumes_ready + && self.bindings_ready + && self.setup_ready + } +} + /// Deterministic direct-child plan for one Cloud Hypervisor Guest. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GuestChildGraphPlan { @@ -357,23 +366,31 @@ mod tests { for pending in 0..5 { let mut ready = [true; 5]; ready[pending] = false; + let snapshot = VmmReadinessSnapshot { + devices_ready: ready[0], + networks_ready: ready[1], + volumes_ready: ready[2], + bindings_ready: ready[3], + setup_ready: ready[4], + }; assert_eq!( - graph.vmm_lifecycle(ready[0], ready[1], ready[2], ready[3], ready[4]), + graph.vmm_lifecycle(snapshot), VmmLifecycleEligibility::Stopped ); - assert_eq!( - graph.vmm_readiness(ready[0], ready[1], ready[2], ready[3], ready[4]), - DependencyReadiness::Pending - ); + assert_eq!(graph.vmm_readiness(snapshot), DependencyReadiness::Pending); } + let all_ready = VmmReadinessSnapshot { + devices_ready: true, + networks_ready: true, + volumes_ready: true, + bindings_ready: true, + setup_ready: true, + }; assert_eq!( - graph.vmm_lifecycle(true, true, true, true, true), + graph.vmm_lifecycle(all_ready), VmmLifecycleEligibility::Running ); - assert_eq!( - graph.vmm_readiness(true, true, true, true, true), - DependencyReadiness::Ready - ); + assert_eq!(graph.vmm_readiness(all_ready), DependencyReadiness::Ready); } #[test] @@ -403,12 +420,26 @@ mod tests { fn legacy_three_dependency_readiness_remains_a_strict_subset() { let graph = BootstrapGraph::new(Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()) .unwrap(); + let all_ready = VmmReadinessSnapshot { + devices_ready: true, + networks_ready: true, + volumes_ready: true, + bindings_ready: true, + setup_ready: true, + }; + let volume_pending = VmmReadinessSnapshot { + devices_ready: true, + networks_ready: true, + volumes_ready: false, + bindings_ready: true, + setup_ready: true, + }; assert_eq!( - graph.vmm_readiness(true, true, true, true, true), + graph.vmm_readiness(all_ready), DependencyReadiness::Ready ); assert_eq!( - graph.vmm_readiness(true, true, false, true, true), + graph.vmm_readiness(volume_pending), DependencyReadiness::Pending ); } diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs index 47420fcdf..d91c806b0 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs @@ -15,7 +15,7 @@ use d2b_core_controller::{ResourceKey, ObservedChild, OwnerIndex, OwnerLimits}; use crate::{ adoption::ProcessAdoptionStatus, - bootstrap_graph::{BootstrapGraph, DependencyReadiness, GuestChildGraphPlan}, + bootstrap_graph::{BootstrapGraph, DependencyReadiness, GuestChildGraphPlan, VmmReadinessSnapshot}, descriptor::{ GuestSetupDescriptor, GuestSetupDescriptorError, GuestSetupDescriptorVerifier, VerifiedGuestSetupDescriptor, @@ -659,13 +659,13 @@ impl GuestDependencySnapshot { let devices_ready = self.devices_ready(graph); let networks_ready = self.networks_ready(graph); let volumes_ready = self.volumes_ready(graph); - let eligibility = graph.vmm_lifecycle( + let eligibility = graph.vmm_lifecycle(VmmReadinessSnapshot { devices_ready, networks_ready, volumes_ready, - self.bindings_ready(graph), - self.setup_ready, - ); + bindings_ready: self.bindings_ready(graph), + setup_ready: self.setup_ready, + }); let mut conditions = Vec::new(); if !devices_ready { conditions.push(GuestCondition::DeviceDependencyNotReady); From 9d5d2cfc95ebc88d3600840f2f72d64b5c159573 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:52:05 -0700 Subject: [PATCH 464/726] unsafe-local-helper: correlate launch failures on a structured record --- Cargo.lock | 1 + packages/d2b-unsafe-local-helper/Cargo.toml | 1 + packages/d2b-unsafe-local-helper/src/protocol.rs | 11 ++++++++--- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../broker-default-tests/production/closure.json | 2 +- .../broker-default-tests/production/metadata.json | 2 +- .../broker-fake-backends-tests/policy/closure.json | 2 +- .../broker-fake-backends-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-layer1-bootstrap-tests/policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../broker-production/production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 8 +++++++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +++++++- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../broker-default-tests/production/closure.json | 2 +- .../broker-default-tests/production/metadata.json | 2 +- .../broker-fake-backends-tests/policy/closure.json | 2 +- .../broker-fake-backends-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-layer1-bootstrap-tests/policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../broker-production/production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 8 +++++++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +++++++- .../main-product/production/metadata.json | 2 +- 47 files changed, 78 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f023ce55f..05bfb40fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2169,6 +2169,7 @@ dependencies = [ "serde_json", "sha2", "socket2 0.5.10", + "tracing", "uzers", "zbus", ] diff --git a/packages/d2b-unsafe-local-helper/Cargo.toml b/packages/d2b-unsafe-local-helper/Cargo.toml index 22ae29749..c605332ce 100644 --- a/packages/d2b-unsafe-local-helper/Cargo.toml +++ b/packages/d2b-unsafe-local-helper/Cargo.toml @@ -28,5 +28,6 @@ serde.workspace = true serde_json.workspace = true sha2 = "0.10" socket2 = "0.5" +tracing = "0.1" uzers = "0.12" zbus = { version = "5.16", features = ["blocking-api"] } diff --git a/packages/d2b-unsafe-local-helper/src/protocol.rs b/packages/d2b-unsafe-local-helper/src/protocol.rs index 6f6ffeb8d..124d4be65 100644 --- a/packages/d2b-unsafe-local-helper/src/protocol.rs +++ b/packages/d2b-unsafe-local-helper/src/protocol.rs @@ -181,12 +181,17 @@ impl HelperClient { .name("d2b-unsafe-local-operation".to_owned()) .spawn(move || { let request_id = request.request_id; - let operation_id = request.operation_id.clone(); + let operation = request.operation_id.clone(); let response = match runtime.launch(*request) { Ok(result) => UnsafeLocalHelperToDaemon::Operation(result), Err(error) => { - eprintln!("unsafe-local launch failed: {error:?}"); - rejection(request_id, operation_id, failure_code(error)) + tracing::warn!( + error = ?error, + request_id = request_id, + operation = %operation, + "unsafe-local launch failed", + ); + rejection(request_id, operation, failure_code(error)) } }; if responses.send(response).is_ok() { diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 181e2d907..efc22f1e5 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index eee99eadc..1191b2c85 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index d19a0821f..7a4bf1d3e 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index eee99eadc..1191b2c85 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index dce59f424..7ba2961c2 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index e38aa87d3..883152b33 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index 78688e155..b764e3cc0 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index e38aa87d3..883152b33 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index d51c88523..8b4d1c4a9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index aff8458d9..7c00ed2cd 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 134020de9..9405f34a8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index aff8458d9..7c00ed2cd 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 6da1c05c7..034d64dac 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index eee99eadc..1191b2c85 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index 606c3b7d9..7f43d7ac5 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index eee99eadc..1191b2c85 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index a0c25cc0f..8dc4fa786 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -2316,6 +2316,7 @@ dependencies = [ "serde_json", "sha2", "socket2 0.5.10", + "tracing", "uzers", "zbus", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index 3ef91993e..cea0a6061 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -9347,6 +9347,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", "to": "uzers@0.12.2#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index 8ab935b4e..1905ff13a 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index a0c25cc0f..8dc4fa786 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -2316,6 +2316,7 @@ dependencies = [ "serde_json", "sha2", "socket2 0.5.10", + "tracing", "uzers", "zbus", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index 5b32890e1..f0f7aa921 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -8705,6 +8705,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", "to": "uzers@0.12.2#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index 8ab935b4e..1905ff13a 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 5d3f87f02..53690be57 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 117a1e060..420f8a187 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index 79873e541..8f9e742a3 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 117a1e060..420f8a187 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 38d509ed2..5a411331d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 27107c05e..fe6e89c73 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index a22522762..3c1994f24 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 27107c05e..fe6e89c73 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 50f5649d4..0c74fffc4 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index 60211d4e3..41620cc95 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 6e9d8615d..53fd09f74 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index 60211d4e3..41620cc95 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index eb9690913..46a8e8584 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index 117a1e060..420f8a187 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 9f5c1c765..601cef78b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index 117a1e060..420f8a187 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index a0c25cc0f..8dc4fa786 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -2316,6 +2316,7 @@ dependencies = [ "serde_json", "sha2", "socket2 0.5.10", + "tracing", "uzers", "zbus", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index 43f60d5a2..3c768ceb4 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -9385,6 +9385,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", "to": "uzers@0.12.2#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index f8b648643..714af7b02 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index a0c25cc0f..8dc4fa786 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -2316,6 +2316,7 @@ dependencies = [ "serde_json", "sha2", "socket2 0.5.10", + "tracing", "uzers", "zbus", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index fcb0fc821..4fc3da78a 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -8743,6 +8743,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-unsafe-local-helper@0.0.0-bootstrap#path", "to": "uzers@0.12.2#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index f8b648643..714af7b02 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "b07b0e99bdd12d67979d2608dba5aa396e6aea33b20911e68b099e1c06a956ba", + "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", From c9a141c78ffe0122371a0bc9b43d94d55c0301a6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:52:14 -0700 Subject: [PATCH 465/726] audio-pipewire: drop the dead register_service gate --- packages/d2b-provider-audio-pipewire/src/controller.rs | 7 +------ packages/d2b-provider-audio-pipewire/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/d2b-provider-audio-pipewire/src/controller.rs b/packages/d2b-provider-audio-pipewire/src/controller.rs index 922eeaee0..a880fb427 100644 --- a/packages/d2b-provider-audio-pipewire/src/controller.rs +++ b/packages/d2b-provider-audio-pipewire/src/controller.rs @@ -3,7 +3,7 @@ use crate::{ AudioBindingSpec, AudioChannel, AudioGrant, AudioLeaseId, AudioMediator, AudioMediatorError, AudioReadiness, GuestAudioReadiness, HostAudioReadiness, MicDecision, SharedMicrophoneArbiter, - SpeakerMixer, validate_audio_binding_in_zone, validate_audio_service, + SpeakerMixer, validate_audio_binding_in_zone, }; use d2b_contracts_provider::v3::semantic_services::{ SemanticFamily, @@ -759,8 +759,3 @@ impl AudioBindingController { Ok(Some(next)) } } - -/// Validate an AudioService before controller registration. -pub fn register_service(service: &crate::AudioServiceSpec) -> Result<(), AudioControllerError> { - validate_audio_service(service).map_err(|_| AudioControllerError::Admission) -} diff --git a/packages/d2b-provider-audio-pipewire/src/lib.rs b/packages/d2b-provider-audio-pipewire/src/lib.rs index 4aa9dac81..766652c6a 100644 --- a/packages/d2b-provider-audio-pipewire/src/lib.rs +++ b/packages/d2b-provider-audio-pipewire/src/lib.rs @@ -29,7 +29,7 @@ pub use controller::{ AudioArbitrationState, AudioBindingChannels, AudioBindingController, AudioBindingPhase, AudioBindingStatus, AudioControllerError, AudioEnforcementPosture, AudioLastSetApplied, AudioMicrophoneStatus, AudioReconcileResult, AudioReconcileResultWithChildren, - AudioSpeakerStatus, AUDIO_QUEUE_BOUND, AUDIO_REPAIR_INTERVAL_SECS, register_service, + AudioSpeakerStatus, AUDIO_QUEUE_BOUND, AUDIO_REPAIR_INTERVAL_SECS, }; pub use mediator::{ AudioChannel, AudioMediator, AudioMediatorError, AudioReadiness, FakeAudioMediator, From f56c431aabd439ec45a95cc4e2843c6729bedfcf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:52:32 -0700 Subject: [PATCH 466/726] audit: fold the unsafe-local tail --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index bc7f3ea0d..7bb25a9e6 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -490,7 +490,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | | `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | | | | `packages/d2b-session-unix/src/socket.rs:176` | | | | `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | applied | U3 | b9fc346fc | packages/d2b-sk-frontend/src/lib.rs | agent/config/link/uhid made private; UhidDevice and UhidEvent re-exported from lib.rs; main.rs:41 uses root re-exports. Census: sk_frontend::(agent/config/link/uhid):: = 0 full-path hits; zone-routing | | -| `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | not-started | U3 | | `packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/` | Surface narrowing (SupervisorSpec, send_frame/receive_frame/configure_socket_buffers, SUPERVISOR_START_TIMEOUT, SNAPSHOT_RECONCILE_TIMEOUT) not applied; census re-run complete and supports the claim ( | | +| `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | a9902b8e7 | packages/d2b-unsafe-local-helper/src/runtime.rs | Census re-run: zero external consumers. SupervisorSpec, SUPERVISOR_START_TIMEOUT, SNAPSHOT_RECONCILE_TIMEOUT, send_frame, receive_frame, configure_socket_buffers narrowed to module-private; no pub sig | | | `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/composition.rs | process_provider_runtime and provider_effects narrowed to pub(crate) with a cfg(feature=test-support) pub mod seam for tests/resource_operator_activation.rs; test-only items (new_persistent, admit, pe | | | `RS-0441` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/resource_plane_v3.rs | ResourcePlaneV3 accessors: targets()/hub() return Arc by value, store()/registry() return plain refs; Arc::clone(plane.hub()/targets()) sites updated to plane.hub()/plane.targets(); adopt_guest_target | | | `RS-0439` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | pub surface reduced to pub(crate): trait HostAudioController, PipeWireHostController, from_audio_node, find_audio_node, QemuAudioController. Census re-run: only in-crate callers (audio_dispatch.rs); m | | @@ -655,7 +655,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | | `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied-variant | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | TransportEntry carries endpoint/binding ids; the spawn block captures clones and threads them through run_bridge (copy-failure event gets fields) and emit_event (subscriber-drop event gets fields); th | | | `RS-0600` | `obs` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Replaced eprintln with tracing::debug!(error = %error, "create envelope validation failed"); tracing already a dependency and used in the crate. | | -| `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | not-started | U3 | | `packages/d2b-unsafe-local-helper/src/protocol.rs:188` | Not applied: the stated fix (include request_id and operation_id in the protocol.rs:188 eprintln record) conflicts with the mandatory observability rule - operation_id is a pinned opaque correlation i | | +| `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | 9d5d2cfc9 | packages/d2b-unsafe-local-helper/Cargo.toml | Failure path now emits tracing::warn! with error/request_id/operation named fields; operation field neutral-named (local renamed operation_id -> operation), no pinned identifier in record; security sc | | | `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Accept loop's four eprintln! calls replaced with tracing::error! events: connection-handler failures carry error = %error.message() (and peer_uid = peer.uid, captured before the move into the handler; | | | `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Three lifecycle info events gained named fields: Guest-local ZoneLink transport Provider composed and Guest target-control service composed carry zone = %identity.zone() and guest_ref = %identity.gues | | | `RS-0607` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 31248998b093d92fef1e41eb07ecb49e3b79d33c | packages/d2bd/src/provider_lifecycle.rs | publish_trusted_context failure arm now carries error = %error as a named field, matching the sibling Ok(_) arm and the plane's other warn sites. cargo check green; clippy green for d2bd. | | From fe17cfa531ac71cf705898031235d90040539f46 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:52:59 -0700 Subject: [PATCH 467/726] cloud-hypervisor: drop the always-empty committed map from child repair --- .../src/controller.rs | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs index d91c806b0..de9d0eae4 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs @@ -2125,20 +2125,13 @@ where } } } - let committed = BTreeMap::new(); - let desired_lifecycle = if dependency_readiness != DependencyReadiness::Ready { DesiredLifecycle::Stopped } else { self.lifecycle_intent.unwrap_or(DesiredLifecycle::Running) }; match self - .repair_children( - child_plan.child_batch(), - &children, - &committed, - desired_lifecycle, - ) + .repair_children(child_plan.child_batch(), &children, desired_lifecycle) .await { Ok(true) => { @@ -2865,26 +2858,11 @@ where &self, batch: &GuestChildBatch, observed: &BTreeMap, - committed: &BTreeMap, desired_lifecycle: DesiredLifecycle, ) -> Result { for mutation in batch.mutations() { let target = mutation.target(); let Some(child) = observed.get(target) else { - if target.resource_type().as_str() == "Process" - && desired_lifecycle == DesiredLifecycle::Running - && let Some(identity) = committed.get(target) - { - let update = ChildSpecUpdate::new( - target.clone(), - identity.uid().clone(), - identity.revision(), - mutation.body().clone(), - Some(desired_lifecycle), - )?; - self.api.update_spec(update).await?; - return Ok(true); - } continue; }; let lifecycle_drift = target.resource_type().as_str() == "Process" From 56c460c03f04830511d1a83e8d94e8e6e943bcc2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:53:19 -0700 Subject: [PATCH 468/726] provider-provider: delete the external-provider planning surface --- .../d2b-provider-provider/src/providers.rs | 239 +----------------- 1 file changed, 2 insertions(+), 237 deletions(-) diff --git a/packages/d2b-provider-provider/src/providers.rs b/packages/d2b-provider-provider/src/providers.rs index fa5e8b501..14f1bd9cd 100644 --- a/packages/d2b-provider-provider/src/providers.rs +++ b/packages/d2b-provider-provider/src/providers.rs @@ -2,8 +2,8 @@ use std::collections::BTreeSet; -use d2b_contracts_provider::v3::{ComponentType, ProviderManifest}; -use d2b_contracts_resource::v3::{ResourceRef, SchemaFingerprint}; +use d2b_contracts_provider::v3::ComponentType; +use d2b_contracts_resource::v3::ResourceRef; use d2b_contracts_zone_session::v3::ZoneStatusResource; use d2b_controller_toolkit::{DependencySnapshot, ResourceKey, ResourceSnapshot}; @@ -16,7 +16,6 @@ use crate::driver::{ pub enum ProviderPhase { Pending, Ready, - Draining, Degraded, Failed, Unknown, @@ -27,8 +26,6 @@ pub enum ProviderPhase { pub enum ProviderIntent { Enable, Update, - Disable, - Delete, } /// One child-resource action. The plan never spawns a process directly. @@ -91,7 +88,6 @@ pub struct ProviderObservation { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ProviderError { WrongResourceType, - TrustOrCompatibilityDenied, PackageUnavailable, ConfigInvalid, GraphInvalid, @@ -103,7 +99,6 @@ impl ProviderError { pub const fn code(self) -> &'static str { match self { Self::WrongResourceType => "provider-resource-type-invalid", - Self::TrustOrCompatibilityDenied => "provider-admission-denied", Self::PackageUnavailable => "provider-package-unavailable", Self::ConfigInvalid => "provider-config-invalid", Self::GraphInvalid => "provider-graph-invalid", @@ -124,60 +119,6 @@ impl std::error::Error for ProviderError {} pub struct ProviderHandler; impl ProviderHandler { - /// Validate and plan an external Provider from its signed manifest. - #[allow(clippy::too_many_arguments)] - pub fn plan_external( - provider_ref: &ResourceRef, - manifest: &ProviderManifest, - required_api_major: u32, - required_api_minor: u32, - required_descriptor_fingerprint: &SchemaFingerprint, - intent: ProviderIntent, - observation: ProviderObservation, - ) -> Result { - if provider_ref.resource_type().as_str() != "Provider" { - return Err(ProviderError::WrongResourceType); - } - manifest - .admit( - required_api_major, - required_api_minor, - required_descriptor_fingerprint, - ) - .map_err(|_| ProviderError::TrustOrCompatibilityDenied)?; - manifest - .validate_installation_contract() - .map_err(|_| ProviderError::GraphInvalid)?; - if !observation.package_present { - return Err(ProviderError::PackageUnavailable); - } - if !observation.config_valid { - return Err(ProviderError::ConfigInvalid); - } - if !observation.graph_valid { - return Err(ProviderError::GraphInvalid); - } - if !observation.conformance_valid { - return Err(ProviderError::ConformanceInvalid); - } - - let mut plan = Self::plan_observed(provider_ref, intent, observation)?; - if matches!(intent, ProviderIntent::Enable | ProviderIntent::Update) { - plan.actions = manifest - .components() - .iter() - .map(|component| { - ProviderChildAction::EnsureComponent(component.component_type()) - }) - .collect(); - if manifest.declares_state_volume() { - plan.actions - .push(ProviderChildAction::EnsureDeclaredStateVolume); - } - } - Ok(plan) - } - /// Project an already admitted Provider from its trusted runtime evidence. /// /// Manifest admission remains the authority for artifact, descriptor, and @@ -223,19 +164,6 @@ impl ProviderHandler { publish_exports: ready, }) } - ProviderIntent::Disable | ProviderIntent::Delete => Ok(ProviderPlan { - phase: if observation.components_drained { - ProviderPhase::Pending - } else { - ProviderPhase::Draining - }, - actions: vec![ - ProviderChildAction::WithdrawExports, - ProviderChildAction::RevokeComponents, - ProviderChildAction::RequestComponentDeletion, - ], - publish_exports: false, - }), } } @@ -582,171 +510,8 @@ pub fn provider_observation( #[cfg(test)] mod tests { - use d2b_contracts_provider::v3::UpgradePolicy as ProviderUpgradePolicy; - use d2b_contracts_provider::v3::{ - ArtifactDigest, ArtifactDigestSet, BinaryRef, CompatibilityRange, ComponentDescriptor, - ComponentExecution, ComponentTargetCapability, ControllerTargetKind, EffectPortClass, - PolicyEvaluation, RevocationState, SignatureState, TargetRuntimeArtifacts, TrustEvidence, - UpgradeDisposition, - }; - use d2b_contracts_resource::v3::{ - ArtifactId, - execution_policy::{BoundedToken, ExecutionDomain}, - }; - use super::*; - const DIGEST: &str = "sha256:0000000000000000000000000000000000000000000000000000000000000001"; - - fn fingerprint() -> SchemaFingerprint { - SchemaFingerprint::parse(DIGEST).unwrap() - } - - fn manifest(trusted: bool) -> ProviderManifest { - let digest = || ArtifactDigest::parse(DIGEST).unwrap(); - ProviderManifest::new( - ArtifactId::parse("provider").unwrap(), - ArtifactDigestSet { - executable: digest(), - config: digest(), - schema: digest(), - service: digest(), - }, - TrustEvidence { - publisher: BoundedToken::parse("trusted").unwrap(), - root_epoch: 1, - publisher_trusted: trusted, - signature: SignatureState::Valid, - revocation: RevocationState::Clear, - emergency_deny: false, - provenance: PolicyEvaluation::Accepted, - sbom: PolicyEvaluation::Accepted, - license: PolicyEvaluation::Accepted, - vulnerability: PolicyEvaluation::Accepted, - conformance: PolicyEvaluation::Accepted, - support_channel: BoundedToken::parse("stable").unwrap(), - }, - CompatibilityRange { - api_major: 3, - api_minor: 0, - descriptor_fingerprint: fingerprint(), - state_schema_version: d2b_contracts_resource::v3::SchemaVersion::new(1, 0).unwrap(), - }, - [ComponentDescriptor::new( - BoundedToken::parse("service").unwrap(), - ComponentType::Service, - [], - [BoundedToken::parse("observe").unwrap()], - [ExecutionDomain::System], - 1, - digest(), - [], - false, - ) - .unwrap() - .with_execution(ComponentExecution::Launchable { - binary_ref: BinaryRef::parse("service").unwrap(), - }) - .with_target_capabilities([ - ComponentTargetCapability::new( - ControllerTargetKind::Host, - digest(), - [EffectPortClass::Runtime], - ) - .unwrap(), - ComponentTargetCapability::new( - ControllerTargetKind::Guest, - digest(), - [EffectPortClass::Runtime], - ) - .unwrap(), - ]) - .unwrap()], - [], - [], - ProviderUpgradePolicy { - drain_before_upgrade: true, - max_automatic_disposition: UpgradeDisposition::InPlace, - preserves_durable_state: true, - }, - ) - .unwrap() - .with_target_runtime_artifacts([ - TargetRuntimeArtifacts::new(ControllerTargetKind::Host, digest(), digest()).unwrap(), - TargetRuntimeArtifacts::new(ControllerTargetKind::Guest, digest(), digest()).unwrap(), - ]) - .unwrap() - } - - fn observation() -> ProviderObservation { - ProviderObservation { - package_present: true, - config_valid: true, - graph_valid: true, - conformance_valid: true, - required_dependencies_ready: true, - required_components_ready: true, - optional_components_degraded: false, - components_drained: false, - } - } - - #[test] - fn ready_external_provider_publishes_only_after_children_are_ready() { - let plan = ProviderHandler::plan_external( - &ResourceRef::parse("Provider/example").unwrap(), - &manifest(true), - 3, - 0, - &fingerprint(), - ProviderIntent::Enable, - observation(), - ) - .unwrap(); - assert_eq!(plan.phase(), ProviderPhase::Ready); - assert!(plan.publish_exports()); - assert_eq!( - plan.actions(), - &[ProviderChildAction::EnsureComponent(ComponentType::Service)] - ); - } - - #[test] - fn missing_dependency_keeps_exports_withdrawn() { - let mut observed = observation(); - observed.required_dependencies_ready = false; - let plan = ProviderHandler::plan_external( - &ResourceRef::parse("Provider/example").unwrap(), - &manifest(true), - 3, - 0, - &fingerprint(), - ProviderIntent::Enable, - observed, - ) - .unwrap(); - assert_eq!(plan.phase(), ProviderPhase::Pending); - assert!(!plan.publish_exports()); - } - - #[test] - fn untrusted_provider_is_rejected_before_child_planning() { - let manifest = manifest(false); - assert_eq!( - ProviderHandler::plan_external( - &ResourceRef::parse("Provider/example").unwrap(), - &manifest, - 3, - 0, - &fingerprint(), - ProviderIntent::Enable, - observation(), - ) - .unwrap_err(), - ProviderError::TrustOrCompatibilityDenied - ); - } - #[test] fn fixed_system_core_never_plans_a_process_child() { let plan = ProviderHandler::plan_system_core(true); From 2ba072632fa3f247478d04c6d0f4fbde0ada6d6f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:53:58 -0700 Subject: [PATCH 469/726] cloud-hypervisor: drop the discarded children argument from assess_update --- .../d2b-provider-guest-cloud-hypervisor/src/controller.rs | 8 +------- .../tests/reconcile_state_machine_test.rs | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs index de9d0eae4..9e00acefb 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs @@ -1361,9 +1361,7 @@ where async fn assess_update( &self, guest: &GuestSnapshot, - children: &[OwnedChildSnapshot], ) -> Result, CloudHypervisorResourceApiError> { - let _ = children; match self .session .call(CloudHypervisorResourceRequest::AssessUpdate { @@ -1571,7 +1569,6 @@ pub trait CloudHypervisorResourceApi: Send + Sync { async fn assess_update( &self, _guest: &GuestSnapshot, - _children: &[OwnedChildSnapshot], ) -> Result, CloudHypervisorResourceApiError> { Ok(None) } @@ -1916,10 +1913,7 @@ where .await; } - let upgrade_required = self - .api - .assess_update(&guest, &children.values().cloned().collect::>()) - .await + let upgrade_required = self.api.assess_update(&guest).await .inspect_err(|error| { tracing::warn!( zone = ?guest.zone, diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/reconcile_state_machine_test.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/reconcile_state_machine_test.rs index 2abb56d3a..ca8921b47 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/reconcile_state_machine_test.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/reconcile_state_machine_test.rs @@ -330,7 +330,6 @@ impl CloudHypervisorResourceApi for FakeApi { async fn assess_update( &self, _: &GuestSnapshot, - _: &[OwnedChildSnapshot], ) -> Result, CloudHypervisorResourceApiError> { Ok(self.state.lock().await.upgrade_reason) } From 9b56489c4c650854ed998341f792793ea714c274 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:54:54 -0700 Subject: [PATCH 470/726] cloud-hypervisor: drop the always-None expected_uid accessor --- .../src/bootstrap_graph.rs | 4 +--- packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | 5 ----- .../d2b-provider-guest-cloud-hypervisor/tests/controller.rs | 3 +-- .../tests/guest_spec_validation_test.rs | 1 - 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs index 86d0a9a0d..4bffb2d75 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs @@ -334,9 +334,7 @@ mod tests { let batch = first.child_batch(); assert_eq!(batch.mutations().len(), 4); assert!(batch.mutations().iter().all(|mutation| { - mutation.owner_ref() == &guest - && mutation.zone() == &zone - && mutation.expected_uid().is_none() + mutation.owner_ref() == &guest && mutation.zone() == &zone })); let rendered = format!("{first:?}"); diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs index 5e504a0ed..0a6f06b51 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs @@ -560,11 +560,6 @@ impl ChildMutation { self.precondition } - /// Return the absent UID fence on first create. - pub const fn expected_uid(&self) -> Option<&ResourceUid> { - None - } - /// Borrow the typed create body. pub const fn body(&self) -> &ChildCreateBody { &self.body diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs index 5547dbff8..89a57b1ee 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/controller.rs @@ -203,8 +203,7 @@ async fn one_uid_free_batch_contains_the_complete_guest_owned_child_graph() { assert_eq!(batch.owner_uid(), &ResourceUid::parse(GUEST_UID).unwrap()); assert_eq!(batch.owner_revision(), ZoneRevision::new(7)); assert!(batch.mutations().iter().all(|mutation| { - mutation.expected_uid().is_none() - && mutation.owner_ref() == &ResourceRef::parse("Guest/gateway").unwrap() + mutation.owner_ref() == &ResourceRef::parse("Guest/gateway").unwrap() && mutation.zone() == &ZoneId::parse("work").unwrap() })); for mutation in batch.mutations() { diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs index 558993de7..f6ae62e59 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/guest_spec_validation_test.rs @@ -169,7 +169,6 @@ fn fixed_guest_child_batch_is_name_addressed_and_uid_free() { assert!(batch.mutations().iter().all(|mutation| { mutation.precondition() == d2b_provider_guest_cloud_hypervisor::CreatePrecondition::CreateAbsent - && mutation.expected_uid().is_none() && mutation.owner_ref() == &guest && mutation.zone() == &zone })); From c22876d4fce217fef901f8acd79f99664733cf0b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:57:12 -0700 Subject: [PATCH 471/726] provider-process: refuse corrupt binding and volume rows as spec-invalid --- packages/d2b-provider-process/src/driver.rs | 84 ++++++++++++++------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/packages/d2b-provider-process/src/driver.rs b/packages/d2b-provider-process/src/driver.rs index 004d33262..e29eb9824 100644 --- a/packages/d2b-provider-process/src/driver.rs +++ b/packages/d2b-provider-process/src/driver.rs @@ -1015,18 +1015,25 @@ impl ProcessDriver { let declared_target = match ctx.owner_key().cloned() { Some(owner) if owner.type_name == "VolumeBinding" => match ctx.get(&owner).await { Ok(Some(row)) => { - let binding = serde_json::from_slice::(&row.spec) - .ok() - .and_then(|envelope| { - serde_json::from_slice::< - d2b_contracts_resource::v3::volume_binding::VolumeBindingSpec, - >(&envelope.base().to_canonical_bytes()) - .ok() - }); - if let Some(binding) = binding.as_ref() { - worker_launch = self.serving_worker_launch(ctx, binding, op).await; - } - binding.map(|binding| binding.execution_ref().clone()) + let binding = match serde_json::from_slice::(&row.spec) { + Ok(envelope) => serde_json::from_slice::< + d2b_contracts_resource::v3::volume_binding::VolumeBindingSpec, + >(&envelope.base().to_canonical_bytes()) + .map_err(|error| { + self.error(ProcessDriverErrorKind::SpecInvalid, op).with_detail( + FailureDetail::at("spec/decode").with_note(error.to_string()), + ) + })?, + Err(error) => { + return Err(self + .error(ProcessDriverErrorKind::SpecInvalid, op) + .with_detail( + FailureDetail::at("spec/decode").with_note(error.to_string()), + )) + } + }; + worker_launch = self.serving_worker_launch(ctx, &binding, op).await?; + Some(binding.execution_ref().clone()) } _ => None, }, @@ -1110,35 +1117,54 @@ impl ProcessDriver { ctx: &mut ResourceContext, binding: &d2b_contracts_resource::v3::volume_binding::VolumeBindingSpec, op: DriverOp, - ) -> Option { - let (_, spec) = self.decoded_spec(ctx, op).ok()?; + ) -> Result, ProcessDriverError> { + let (_, spec) = self.decoded_spec(ctx, op)?; if spec.execution().template().as_str() != d2b_provider_volume_virtiofs::WORKER_TEMPLATE { - return None; + return Ok(None); } let volume_key = ResourceKey::new( self.zone.as_str(), "Volume", binding.volume_ref().name().as_str(), ); - let row = ctx.get(&volume_key).await.ok().flatten()?; - let volume = serde_json::from_slice::(&row.spec) - .ok() - .and_then(|envelope| { - serde_json::from_slice::( - &envelope.base().to_canonical_bytes(), + let Some(row) = ctx.get(&volume_key).await.ok().flatten() else { + return Ok(None); + }; + let volume = match serde_json::from_slice::(&row.spec) { + Ok(envelope) => serde_json::from_slice::< + d2b_contracts_resource::v3::volume::VolumeSpec, + >(&envelope.base().to_canonical_bytes()) + .map_err(|error| { + self.error(ProcessDriverErrorKind::SpecInvalid, op).with_detail( + FailureDetail::at("spec/decode").with_note(error.to_string()), ) - .ok() - })?; - let view = volume.views().get(binding.view().as_str())?; - let attachment = volume + })?, + Err(error) => { + return Err(self + .error(ProcessDriverErrorKind::SpecInvalid, op) + .with_detail( + FailureDetail::at("spec/decode").with_note(error.to_string()), + )) + } + }; + let Some(view) = volume.views().get(binding.view().as_str()) else { + return Ok(None); + }; + let Some(attachment) = volume .attachments() .iter() - .find(|attachment| attachment.execution_ref() == binding.execution_ref())?; + .find(|attachment| attachment.execution_ref() == binding.execution_ref()) + else { + return Ok(None); + }; let settings = attachment.settings(); let source = volume.source(); let root = match source.settings().kind() { d2b_contracts_resource::v3::volume::SourceKind::LocalPath => { - let policy = source.settings().source_policy_id()?.as_str().to_owned(); + let Some(policy) = source.settings().source_policy_id() else { + return Ok(None); + }; + let policy = policy.as_str().to_owned(); Some(ServingWorkerRoot::StoragePath( if policy == "state-root" || policy == "default-state" { "path:state-root".to_owned() @@ -1157,7 +1183,7 @@ impl ProcessDriver { } _ => None, }; - Some(ServingWorkerLaunch { + Ok(Some(ServingWorkerLaunch { volume_ref: binding.volume_ref().clone(), view: binding.view().clone(), guest_ref: binding.execution_ref().clone(), @@ -1171,7 +1197,7 @@ impl ProcessDriver { socket_group: settings .socket_group() .map(|group| group.as_str().to_owned()), - }) + })) } async fn stop_and_finalize( From ebeef4024c73e9498835702bacabde20783cf330 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:58:20 -0700 Subject: [PATCH 472/726] process-systemd: expose lifecycle items only through the crate root --- packages/d2b-provider-process-systemd/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-process-systemd/src/lib.rs b/packages/d2b-provider-process-systemd/src/lib.rs index d5cfba53c..363d65266 100644 --- a/packages/d2b-provider-process-systemd/src/lib.rs +++ b/packages/d2b-provider-process-systemd/src/lib.rs @@ -25,7 +25,7 @@ pub mod drain; pub mod effects_service; pub mod error; pub mod launch; -pub mod lifecycle; +mod lifecycle; pub mod metrics; pub mod operations; pub mod sandbox; From 6f07391f04e13849f6984fcc6bed4eebf17f9d0e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:58:47 -0700 Subject: [PATCH 473/726] telemetry: report invalid emitter limits as their own error --- packages/d2b-telemetry/src/emitter.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/d2b-telemetry/src/emitter.rs b/packages/d2b-telemetry/src/emitter.rs index e58149824..8a06dfc21 100644 --- a/packages/d2b-telemetry/src/emitter.rs +++ b/packages/d2b-telemetry/src/emitter.rs @@ -91,6 +91,8 @@ pub enum EmitterError { FrameTooLarge, /// The emitter lock was poisoned. StatePoisoned, + /// A constructor bound was zero or otherwise invalid. + InvalidLimits, /// A metric frame did not satisfy the closed label policy. MetricPolicy(MetricPolicyError), /// A non-metric frame was not a bounded structured observation. @@ -104,6 +106,7 @@ impl core::fmt::Display for EmitterError { formatter.write_str(match self { Self::FrameTooLarge => "telemetry-frame-too-large", Self::StatePoisoned => "telemetry-emitter-state-poisoned", + Self::InvalidLimits => "telemetry-emitter-limits-invalid", Self::MetricPolicy(_) => "telemetry-metric-policy-rejected", Self::FrameRedaction => "telemetry-frame-redaction-rejected", Self::SocketPathInvalid => "telemetry-socket-path-invalid", @@ -184,7 +187,7 @@ impl BoundedEmitter { /// # Errors /// /// Returns `EmitterError::SocketPathInvalid` for a non-absolute - /// path, and `StatePoisoned` for a zero byte capacity. + /// path, and `InvalidLimits` for a zero byte capacity. pub fn new(path: impl Into, capacity_bytes: usize) -> Result { Self::new_with_limits( path, @@ -200,7 +203,7 @@ impl BoundedEmitter { /// # Errors /// /// Returns `EmitterError::SocketPathInvalid` for a non-absolute - /// path, and `StatePoisoned` when any bound is zero. + /// path, and `InvalidLimits` when any bound is zero. pub fn new_with_limits( path: impl Into, capacity_bytes: usize, @@ -209,10 +212,10 @@ impl BoundedEmitter { max_retry_attempts: u8, ) -> Result { if capacity_bytes == 0 { - return Err(EmitterError::StatePoisoned); + return Err(EmitterError::InvalidLimits); } if capacity_frames == 0 || max_age.is_zero() || max_retry_attempts == 0 { - return Err(EmitterError::StatePoisoned); + return Err(EmitterError::InvalidLimits); } let path = path.into(); if !path.is_absolute() { From 1453d6b9a0db5b622405c3857035fb5f56f40155 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:58:48 -0700 Subject: [PATCH 474/726] telemetry: drop the dead session-metric encode error --- packages/d2b-telemetry/src/session_metrics_sink.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/d2b-telemetry/src/session_metrics_sink.rs b/packages/d2b-telemetry/src/session_metrics_sink.rs index 1b24de098..3dbe39f8a 100644 --- a/packages/d2b-telemetry/src/session_metrics_sink.rs +++ b/packages/d2b-telemetry/src/session_metrics_sink.rs @@ -75,8 +75,6 @@ impl SessionMetricsSink { pub enum SessionMetricsError { /// Label policy rejected the frame. Policy(crate::metric_label_policy::MetricPolicyError), - /// Frame encoding failed. - Encode(std::io::Error), /// Emitter failed. Emitter(crate::emitter::EmitterError), } @@ -85,7 +83,6 @@ impl core::fmt::Display for SessionMetricsError { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str(match self { Self::Policy(_) => "session-metric-policy-rejected", - Self::Encode(_) => "session-metric-encode-failed", Self::Emitter(_) => "session-metric-emitter-failed", }) } From cb3471ae8a680d10de1f5cda6067e9fd29e05d8f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 10:59:11 -0700 Subject: [PATCH 475/726] audit: fold the provider tail --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 7bb25a9e6..f4b9755d8 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -453,7 +453,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | | `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd` | | | | `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | c61b0e5b5 | packages/d2b-provider-provider/src/driver.rs | ProviderDriverFactory::new() and impl Default deleted (zero callers; crate tests construct via with_effects; FailClosedProviderDriverEffects still used by tests). Census: no new()/default() callers ac | | -| `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | not-started | U3 | | `src/providers.rs:121, src/lib.rs:19` | Re-verified actionable at HEAD but not applied: budget ended. | | +| `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | 56c460c03 | packages/d2b-provider-provider/src/providers.rs | Completed the in-flight partial edit: deleted plan_external body, Disable/Delete intent variants, Draining phase, TrustOrCompatibilityDenied error, and orphaned test helpers/imports; check/test/clippy | | | `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | | | | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | | | | `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | | | | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | | | | `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | | | | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | | | @@ -553,7 +553,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | | | | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | | | | `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U3 | eba219aa6 | packages/d2b-provider-notification-desktop/src/types.rs | Added NotificationError::Denied (slug notification-denied; not pinned in docs/reference) and mapped the five admission/zone/category rejection sites (host_sink.rs source/observer admission, zone misma | | | `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/ingress_policy.rs | Full connection-table rejection now reports IngressErrorClass::None, consistent with the sibling capacity refusal. | | -| `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | not-started | U3 | | `packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/d` | Re-verified actionable at HEAD but not applied: budget ended. | | +| `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | applied | U3 | c22876d4f | packages/d2b-provider-process/src/driver.rs | Map VolumeBinding/Volume row parse failures to ProcessDriverErrorKind::SpecInvalid in identity() and serving_worker_launch() (now Result, _>); genuinely absent rows/views/attachments still y | | | `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | | `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | skipped-stale | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | @@ -577,8 +577,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0521` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | adb285984 | packages/d2b-resource-runtime/src/spec_store.rs | Added SpecStoreError::CorruptRow { zone, type_name, name }; row_from returns it instead of try_into().unwrap_or([0; 16]) for uid and owner_uid; load_row/list switched from query_row/query_map closures | | | `RS-0522` | `err` | `d2b-session` | medium | actionable | leaf | applied-variant | U3 | afb1fa59c | packages/d2b-session/src/transport.rs | Applied the typestate option minimally: the Option> wrapper is gone (plain Box), so the consumed state is unrepresentable and all three expects disappeared; public signatures a | | | `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | -| `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | not-started | U3 | | `packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93` | Re-verified actionable at HEAD but not applied: budget ended. | | -| `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | not-started | U3 | | `packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_` | Re-verified actionable at HEAD but not applied: budget ended. | | +| `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | applied | U3 | 6f07391f0 | packages/d2b-telemetry/src/emitter.rs | Added EmitterError::InvalidLimits with Display arm and doc updates; zero-capacity/frame/age/retry guards return it; StatePoisoned kept for lock().map_err sites; check/test/clippy green. | | +| `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | applied | U3 | 1453d6b9a | packages/d2b-telemetry/src/session_metrics_sink.rs | Deleted never-constructed SessionMetricsError::Encode variant and its session-metric-encode-failed Display arm; check/test/clippy green. | | | `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | Stated fix changes a wire-visible HelperFailureCode mapping pinned in docs/reference/error-codes.md; deferred as contract-adjacent. | | | `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | From f7378bae2ddee283f165e7e9c433aaa672be6df4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:00:00 -0700 Subject: [PATCH 476/726] audio-pipewire: take NonZeroUsize bounds in the arbiter and mixer constructors --- .../d2b-provider-audio-pipewire/src/authority.rs | 13 ++++++------- .../d2b-provider-audio-pipewire/src/controller.rs | 3 ++- .../d2b-provider-audio-pipewire/tests/authority.rs | 8 +++++--- .../d2b-provider-audio-pipewire/tests/controller.rs | 8 ++++---- .../src/audio_registry.rs | 5 ++++- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/d2b-provider-audio-pipewire/src/authority.rs b/packages/d2b-provider-audio-pipewire/src/authority.rs index facb271c7..24dac6604 100644 --- a/packages/d2b-provider-audio-pipewire/src/authority.rs +++ b/packages/d2b-provider-audio-pipewire/src/authority.rs @@ -2,6 +2,7 @@ use std::{ collections::{BTreeMap, BTreeSet, VecDeque}, + num::NonZeroUsize, sync::Arc, }; @@ -44,18 +45,17 @@ pub struct MicrophoneArbiter { pub type SharedMicrophoneArbiter = Arc>; /// Construct a shared microphone authority with the provider's queue bound. -pub fn shared_microphone_arbiter(max_queue: usize) -> SharedMicrophoneArbiter { +pub fn shared_microphone_arbiter(max_queue: NonZeroUsize) -> SharedMicrophoneArbiter { Arc::new(tokio::sync::Mutex::new(MicrophoneArbiter::new(max_queue))) } impl MicrophoneArbiter { /// Construct an arbiter with a bounded pending queue. - pub fn new(max_queue: usize) -> Self { - assert!(max_queue > 0); + pub fn new(max_queue: NonZeroUsize) -> Self { Self { active: None, queue: VecDeque::new(), - max_queue, + max_queue: max_queue.get(), } } @@ -141,12 +141,11 @@ pub struct SpeakerMixer { impl SpeakerMixer { /// Construct a mixer with a bounded number of consumers. - pub fn new(max_consumers: usize) -> Self { - assert!(max_consumers > 0); + pub fn new(max_consumers: NonZeroUsize) -> Self { Self { levels: BTreeMap::new(), grants: BTreeSet::new(), - max_consumers, + max_consumers: max_consumers.get(), } } diff --git a/packages/d2b-provider-audio-pipewire/src/controller.rs b/packages/d2b-provider-audio-pipewire/src/controller.rs index a880fb427..f47081117 100644 --- a/packages/d2b-provider-audio-pipewire/src/controller.rs +++ b/packages/d2b-provider-audio-pipewire/src/controller.rs @@ -13,6 +13,7 @@ use d2b_contracts_provider::v3::semantic_services::{ }, }; use d2b_contracts_resource::v3::{ExecutionDomain, ResourceRef}; +use std::num::NonZeroUsize; use tracing::{debug, warn}; const AUDIO_PROVIDER_REF: &str = "Provider/audio-pipewire"; @@ -28,7 +29,7 @@ pub const AUDIO_REPAIR_INTERVAL_SECS: u64 = 300; /// The arbiter and mixer admission bound: how many pending microphone /// leases or speaker consumers one controller admits before refusing /// further admission. -pub const AUDIO_QUEUE_BOUND: usize = 64; +pub const AUDIO_QUEUE_BOUND: NonZeroUsize = NonZeroUsize::new(64).expect("fixed nonzero bound"); const AUDIO_BINDING_CHILD_REQUESTS: [BindingChildRequest; 4] = [ BindingChildRequest::process( diff --git a/packages/d2b-provider-audio-pipewire/tests/authority.rs b/packages/d2b-provider-audio-pipewire/tests/authority.rs index c231c1066..d4357583b 100644 --- a/packages/d2b-provider-audio-pipewire/tests/authority.rs +++ b/packages/d2b-provider-audio-pipewire/tests/authority.rs @@ -1,8 +1,10 @@ +use std::num::NonZeroUsize; + use d2b_provider_audio_pipewire::{AudioLeaseId, MicDecision, MicrophoneArbiter, SpeakerMixer}; #[test] fn microphone_is_exclusive_and_fair_with_bounded_queue() { - let mut arbiter = MicrophoneArbiter::new(2); + let mut arbiter = MicrophoneArbiter::new(NonZeroUsize::new(2).unwrap()); assert_eq!(arbiter.request(AudioLeaseId::new(1)), MicDecision::Granted); assert_eq!(arbiter.request(AudioLeaseId::new(2)), MicDecision::Queued); assert_eq!(arbiter.request(AudioLeaseId::new(3)), MicDecision::Queued); @@ -16,7 +18,7 @@ fn microphone_is_exclusive_and_fair_with_bounded_queue() { #[test] fn queued_microphone_requests_remain_queued_until_handoff() { - let mut arbiter = MicrophoneArbiter::new(1); + let mut arbiter = MicrophoneArbiter::new(NonZeroUsize::new(1).unwrap()); assert_eq!(arbiter.request(AudioLeaseId::new(1)), MicDecision::Granted); assert_eq!(arbiter.request(AudioLeaseId::new(2)), MicDecision::Queued); assert_eq!(arbiter.request(AudioLeaseId::new(2)), MicDecision::Queued); @@ -25,7 +27,7 @@ fn queued_microphone_requests_remain_queued_until_handoff() { #[test] fn speaker_mixer_keeps_grants_independent() { - let mut mixer = SpeakerMixer::new(2); + let mut mixer = SpeakerMixer::new(NonZeroUsize::new(2).unwrap()); mixer.set_level(AudioLeaseId::new(1), 80).unwrap(); mixer.set_level(AudioLeaseId::new(2), 20).unwrap(); assert_eq!(mixer.mix_level(), 100); diff --git a/packages/d2b-provider-audio-pipewire/tests/controller.rs b/packages/d2b-provider-audio-pipewire/tests/controller.rs index de6b7b947..1dc07f0ce 100644 --- a/packages/d2b-provider-audio-pipewire/tests/controller.rs +++ b/packages/d2b-provider-audio-pipewire/tests/controller.rs @@ -180,7 +180,7 @@ fn queued_microphone_binding_is_not_ready() { #[test] fn bindings_can_share_one_service_microphone_authority() { - let shared = shared_microphone_arbiter(64); + let shared = shared_microphone_arbiter(AUDIO_QUEUE_BOUND); let mut first = AudioBindingController::with_shared_microphone(FakeAudioMediator::ready(), shared.clone()); let mut second = @@ -210,7 +210,7 @@ fn bindings_can_share_one_service_microphone_authority() { #[test] fn shared_finalization_does_not_enable_the_promoted_binding_through_the_old_mediator() { - let shared = shared_microphone_arbiter(64); + let shared = shared_microphone_arbiter(AUDIO_QUEUE_BOUND); let mut first = AudioBindingController::with_shared_microphone(FakeAudioMediator::ready(), shared.clone()); let mut second = @@ -303,7 +303,7 @@ fn speaker_admission_rejects_before_mutating_mediator() { let mut requested = binding(); requested.grants.speaker_level = Some(d2b_provider_audio_pipewire::LevelPercent::new(25).expect("bounded test level")); - for lease in 1..=AUDIO_QUEUE_BOUND as u64 { + for lease in 1..=AUDIO_QUEUE_BOUND.get() as u64 { controller .reconcile(&requested, "zone-a", AudioLeaseId::new(lease)) .unwrap(); @@ -311,7 +311,7 @@ fn speaker_admission_rejects_before_mutating_mediator() { let last_level = controller.mediator().level(); assert_eq!( controller - .reconcile(&requested, "zone-a", AudioLeaseId::new(AUDIO_QUEUE_BOUND as u64 + 1)) + .reconcile(&requested, "zone-a", AudioLeaseId::new(AUDIO_QUEUE_BOUND.get() as u64 + 1)) .unwrap_err(), d2b_provider_audio_pipewire::AudioControllerError::Admission ); diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index e47b79680..3b9198a98 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -16,6 +16,7 @@ use std::collections::BTreeMap; #[cfg(test)] use std::collections::BTreeSet; +use std::num::NonZeroUsize; use std::sync::Arc; #[cfg(test)] @@ -302,7 +303,9 @@ impl AudioResourceRuntime { let microphone = self .service_microphones .entry(spec.service_ref.to_canonical_string()) - .or_insert_with(|| shared_microphone_arbiter(64)) + .or_insert_with(|| { + shared_microphone_arbiter(NonZeroUsize::new(64).expect("fixed bound")) + }) .clone(); let mut controller = AudioBindingController::with_shared_microphone(mediator, microphone); From ce4da285b687341817b578c2914c784b8c7865b8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:00:08 -0700 Subject: [PATCH 477/726] d2b-broker: propagate cell store spawn failures in with_retention --- packages/d2b-broker/src/state_cells.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/d2b-broker/src/state_cells.rs b/packages/d2b-broker/src/state_cells.rs index f36ab8a07..55681b0c4 100644 --- a/packages/d2b-broker/src/state_cells.rs +++ b/packages/d2b-broker/src/state_cells.rs @@ -345,7 +345,7 @@ impl CellStore { /// An in-memory store with no durable file. pub fn in_memory() -> Self { Self::spawn_owner(None, RetentionPolicy::default()) - .expect("spawn in-memory cell store owner") + .expect("in-memory store is a startup precondition; a fresh owner spawn cannot fail") } /// Open the store for one state root, recovering every durable record. @@ -355,9 +355,12 @@ impl CellStore { } /// Test/embedding knob: the root plus an explicit retention policy. - pub(crate) fn with_retention(root: Option, retention: RetentionPolicy) -> Self { + /// Failures propagate to the caller instead of panicking. + pub(crate) fn with_retention( + root: Option, + retention: RetentionPolicy, + ) -> Result { Self::spawn_owner(root, retention) - .expect("spawn cell store owner with retention") } /// Spawn the single owner thread and hand it the bootstrap command. @@ -1642,7 +1645,8 @@ mod tests { outcome_ttl_ms: 60_000, max_ephemeral_outcome_records: 1, }, - ); + ) + .expect("spawn store with retention"); // The one-time marker: consumed and completed. assert_eq!( store.consume("grant-g", "grant-1", "alice", CellDurability::OneTime), From bf6f8829fa18ff6d150e45827b1c8d3cdb8f32ee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:00:44 -0700 Subject: [PATCH 478/726] audio-pipewire: chain source errors in the controller and state I/O errors --- .../d2b-provider-audio-pipewire/src/controller.rs | 9 ++++++++- packages/d2b-provider-audio-pipewire/src/state.rs | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-audio-pipewire/src/controller.rs b/packages/d2b-provider-audio-pipewire/src/controller.rs index f47081117..d002a5255 100644 --- a/packages/d2b-provider-audio-pipewire/src/controller.rs +++ b/packages/d2b-provider-audio-pipewire/src/controller.rs @@ -180,7 +180,14 @@ impl core::fmt::Display for AudioControllerError { } } -impl std::error::Error for AudioControllerError {} +impl std::error::Error for AudioControllerError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Admission => None, + Self::Mediator(error) => Some(error), + } + } +} /// Controller result including separate readiness observations. #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/packages/d2b-provider-audio-pipewire/src/state.rs b/packages/d2b-provider-audio-pipewire/src/state.rs index 56f3eef8e..26302f55a 100644 --- a/packages/d2b-provider-audio-pipewire/src/state.rs +++ b/packages/d2b-provider-audio-pipewire/src/state.rs @@ -142,6 +142,21 @@ impl std::fmt::Display for AudioStateIoError { } } +impl std::error::Error for AudioStateIoError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::LockOpen(e) + | Self::LockAcquire(e) + | Self::StateRead(e) + | Self::TempFile(e) + | Self::TempWrite(e) + | Self::TempSync(e) + | Self::AtomicRename(e) => Some(e), + Self::StateParse(e) => Some(e), + } + } +} + /// Read the current audio state under a shared OFD lock. /// /// Opens `lock_path` with `O_RDONLY|O_CLOEXEC|O_CREAT` (the lock file is From 48c6dde542771c3cfa47dc9664a61fb5b7db3ac7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:00:58 -0700 Subject: [PATCH 479/726] d2b-broker: emit the acl refresh label as a structured field --- packages/d2b-broker/src/live_handlers.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/d2b-broker/src/live_handlers.rs b/packages/d2b-broker/src/live_handlers.rs index a21c9c911..042aea47e 100644 --- a/packages/d2b-broker/src/live_handlers.rs +++ b/packages/d2b-broker/src/live_handlers.rs @@ -2529,14 +2529,15 @@ async fn retry_acl_grant( Ok(Err(err)) => { tracing::debug!( error = %err, - "{label} ACL refresh not ready yet", + label = %label, + "ACL refresh not ready yet", ); } // The pool is gone, so the broker is shutting down. Err(_) => return, } if tokio::time::Instant::now() >= deadline { - tracing::warn!("{label} ACL refresh timed out"); + tracing::warn!(label = %label, "ACL refresh timed out"); return; } tokio::time::sleep(interval).await; From 49d94a7add13abae92b6b892f8dd967e90d3acb8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:01:17 -0700 Subject: [PATCH 480/726] audit: fold the broker tail --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index f4b9755d8..654a475cc 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -511,7 +511,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | | `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source | | | `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | -| `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | not-started | U3 | | `packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360` | Claim re-verified at HEAD: `CellStore::with_retention` (state_cells.rs:360) `.expect()`s on spawn_owner failure while `open()` (353) propagates CellStoreError::Io; in_memory keeps infallible. Fix (mak | | +| `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | ce4da285b | packages/d2b-broker/src/state_cells.rs | with_retention now returns Result (test caller updated with expect); in_memory expect names the startup-precondition rationale; check/test/clippy green. | | | `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | | `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | Claim re-verified at HEAD: `guest_socket_directory` (ops/device_worker.rs:262-284) returns `Result<&'static str, &'static str>`-style plain-static-code refusals, consumed at live_handlers.rs:2428 by s | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/src/seam.rs | verify_startup_routing returns Result<(), StartupRoutingViolation> (UnadmittedHandler/MissingHandlers, Display preserved for main.rs); audit_crate/run_cargo_metadata/dependency_tree return Result<_, S | | @@ -637,7 +637,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0580` | `serde` | `xtask` | medium | actionable | leaf | applied | U3 | 9ccb9c694 | packages/xtask/src/service_catalog.rs | deny_unknown_fields added to DeclarationFile; all six committed service-catalog.json files verified to carry only the declared keys (provider/providerRef/providerUid/services); new test an_unknown_dec | | | `RS-0582` | `serde` | `xtask` | low | actionable | leaf | applied | U3 | 45160a4e1 | packages/xtask/src/delivery/mod.rs | Added #[serde(deny_unknown_fields)] to SnapshotView; existing prebinding_snapshot_refresh_remains_allowed round-trip test covers the shape. | | | `RS-0581` | `serde` | `xtask` | low | actionable | leaf | applied-variant | U3 | 341c4fb5e | packages/xtask/src/resource_type_authority.rs | rename_all = camelCase added to DeclarationFile and TypeDeclaration; per-field resourceType rename deleted;the crate per-field rename must stay because the wire key 'crate' is a Rust keyword that rena | | -| `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | not-started | U3 | | `packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:25` | Claim re-verified verbatim at HEAD (live_handlers.rs:2532 `error = %err, \'{label} ACL refresh not ready yet\',` and :2539 `tracing::warn!(\'{label} ACL refresh timed out\');`, with `label: &'static s | | +| `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | applied | U3 | 48c6dde54 | packages/d2b-broker/src/live_handlers.rs | retry_acl_grant emits label = %label as a named field on both records with interpolation-free messages; label is not a pinned scan identifier; security-scan clean. | | | `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | | `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | a94ef37d6 | packages/d2b-provider-activation-nixos/src/controller.rs | all 9 warn! refusal events in ActivationTrust::verify now carry a named refusal field with the exact ActivationVerificationError variant; no correlation identifiers added (ADR 0010/0028 safe). | | | `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 09167b5fa | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | All 62 log:: sites in d2b-clipd.rs converted to tracing:: with named fields; env_logger init replaced by tracing_subscriber::fmt().with_env_filter(...).with_writer(stderr).init() mirroring d2bd; log/e | | From dafc28ca11acbbff9c6e063b3880d60303c7cd84 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:03:17 -0700 Subject: [PATCH 481/726] process-systemd: format the cancelled-ticket debug resource lazily --- packages/d2b-provider-process-systemd/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-process-systemd/src/lib.rs b/packages/d2b-provider-process-systemd/src/lib.rs index 363d65266..87b35a131 100644 --- a/packages/d2b-provider-process-systemd/src/lib.rs +++ b/packages/d2b-provider-process-systemd/src/lib.rs @@ -138,7 +138,7 @@ impl SystemdProcessProvider

{ if ticket.operation().cancellation() == CancellationBinding::Cancelled { debug!( provider = PROVIDER_NAME, - resource = %ticket.process_ref().to_canonical_string(), + resource = %ticket.process_ref(), "assignment rejected: operation cancelled" ); return Err(ProcessConformanceError::Cancelled); From ab5ca6a5bf658d5b59a2780a056fa9b95fee7856 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:03:41 -0700 Subject: [PATCH 482/726] audit: fold the last media lane rows --- .../2026-09-24-rust-skills-audit/ledger.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 654a475cc..bb84a83aa 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -332,7 +332,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | e53601c88 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | derive_private_runtime_scope and private_runtime_scope take ChildRole and use role.suffix(); the &str whitelist branch is gone. Callers incl. wayland-policy migrated. | | | `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | -| `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `bootstrap_graph.rs:142-176, controller.rs:662-670` | | | +| `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | f1404725d | packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs | vmm_readiness/vmm_lifecycle now take one VmmReadinessSnapshot struct (five named facts, all_ready()); controller readiness() builds it from GuestDependencySnapshot accessors; tests updated. check/test | | | `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | 82f8cac47 | packages/d2b-provider-guest-qemu-media/src/config.rs | 7 gate calls now use BoundedToken::parse(...) .is_err(); local validate_token helper and its pub(crate) re-export deleted; qmp validate_object_id delegates to BoundedToken::parse. Deviation: validate_ | | | `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | b845000ff | packages/d2b-provider-guest-qemu-media/src/config.rs | impl Default for ProviderConfig deleted (it manufactured a config that fails its own validate());the sole consumer test now builds valid-then-mutated configs (controller_execution_ref swapped to a Gue | | | `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-` | | | @@ -413,8 +413,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | a37c1e0cf | packages/d2b-process-conformance/src/sandbox.rs | Deleted CompiledSandbox::requires_cgroup_kill field, its unconditional true initializer in compile(), and its public accessor; census: `requires_cgroup_kill` over packages/, nixos-modules/, tests/, do | | | `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 6c66b83ea | packages/d2b-provider-activation-nixos/src/driver.rs | ActivationDriver narrowed to pub(crate) and dropped from the lib.rs driver re-export arm. Census re-run:the symbol appears only in driver.rs (7 sites)and lib.rs; no external consumer. Checks shared wi | | | `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | -| `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/authority.rs:157-171, src/controller.rs:395-403` | | | -| `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/controller.rs:746-748, src/lib.rs:32` | | | +| `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | already-fixed | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | set_grant(lease, on: bool) already split into grant()/revoke() with was-empty/was-last contracts by the RS-0267 commit (c7d7d66c5); callers use is_last_grant first. No change needed. | | +| `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c9a141c78 | packages/d2b-provider-audio-pipewire/src/controller.rs | register_service deleted (zero callers; census over packages/nixos-modules/tests/docs/reference/labs = only the definition); daemon and wayland-policy validate specs via validate_audio_service directl | | | `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | | | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | | | | `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-cli` | | | | `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | | | | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | | | @@ -438,10 +438,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | | `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | | | | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | | | | `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmController::new now takes effect: E by value and stores it; the production call site and the crate's test call sites (18 FakeEffect constructions, incl. the shared-effect recovery test restruct | | -| `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895` | | | -| `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `controller.rs:1361-1376, controller.rs:1907-1909` | | | +| `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | fe17cfa53 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | repair_children no longer takes committed: &BTreeMap (sole caller passed an always-empty map); the unreachable committed.get(target) branch and the empty-map local are deleted. check/test/clippy green | | +| `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | 2ba072632 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | assess_update no longer takes children (production adapter discarded it via let _; request carries none); trait default, adapter override, test impl, and the reconcile call site's Vec allocation all u | | | `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | | | | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | | | -| `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `identity.rs:554-556, tests/controller.rs:206` | | | +| `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | 9b56489c4 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | ChildMutation::expected_uid() (constant None on the UID-free batch) deleted along with the three assert-None assertions; census: remaining expected_uid hits are unrelated types. check/test/clippy gree | | | `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | dc09819bf | packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | Deleted constant-true preserve_state() accessor and its tautological assertion (census: only consumer was the assertion). check+finalize_ordering tests (6) + clippy green. | | | `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | | `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | Seven dead-pub items in the private mod driver narrowed to pub(crate): HostDriver, HostDriverError, HostDriverStatus, HostDriverFactory, HostDriverEffects, host_spec_decoder, HOST_REOBSERVE. Census re | | @@ -449,7 +449,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied-variant | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Deleted uncalled reconcile_authenticated_display (census: def only, zero callers); reconcile_sources and drain_sources lowered to #[cfg(test)] pub(crate) (test-only). Variant: plain pub(crate) would r | | | `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Stale #[allow(dead_code)] removed from from_route, which is reachable from production via from_authenticated_route. Same commit as RS-0394 (same file). | | | `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1-3, packages/d2b-provi` | | | -| `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd` | | | +| `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | ebeef4024 | packages/d2b-provider-process-systemd/src/lib.rs | lifecycle is now a private module; the root re-export is the single surface. Census: zero consumers of the d2b_provider_process_systemd::lifecycle path anywhere. check + lib tests green; clippy red is | | | `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | | `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd` | | | | `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | c61b0e5b5 | packages/d2b-provider-provider/src/driver.rs | ProviderDriverFactory::new() and impl Default deleted (zero callers; crate tests construct via with_effects; FailClosedProviderDriverEffects still used by tests). Census: no new()/default() callers ac | | @@ -534,8 +534,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 96cc7e5bb | packages/d2b-core-controller/src/authority.rs | DuplicateConflict code arm rendered as kebab-case duplicate-conflict; in-crate assertion pinning the old spelling updated; census showed 0 hits outside authority.rs. | | | `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | bf9832779 | packages/d2b-process-conformance/src/launch_identity.rs | Replaced the is_some_and guard + unreachable .expect with an if-let chain binding owner via .filter(), deleting the panic site and using the bound owner for the error payload; behavior unchanged (same | | | `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | applied | U3 | 69153d93f | packages/d2b-provider-activation-nixos/src/controller.rs | terminal now takes ResourceName (63-byte lowercase label, no slash); new parses via ResourceName::parse and returns Result<_, IdentityError>; two driver call sites map parse failure to driver Policy e | | -| `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | | | | `src/authority.rs:53-54, src/authority.rs:144-145` | | | -| `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `src/state.rs:114-123, src/controller.rs:155-160` | | | +| `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U3 | f7378bae2 | packages/d2b-provider-audio-pipewire/src/authority.rs | MicrophoneArbiter::new, SpeakerMixer::new, and shared_microphone_arbiter take NonZeroUsize; AUDIO_QUEUE_BOUND is now a NonZeroUsize const; all call sites (incl. wayland-policy) updated. check/test/cli | | +| `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | bf6f8829f | packages/d2b-provider-audio-pipewire/src/state.rs | AudioStateIoError::source() returns the io::Error/AudioPolicyError payload; AudioControllerError::source() returns the AudioMediatorError payload. Hand-written impls (thiserror not in lockfile). check | | | `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | 1b70ff14a | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | spawn_niri_event_thread returns Result<(), io::Error>; call site logs instead of panicking. | | | `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | da5acd332 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Binary Result<_, String> signatures and format!-built errors migrated to anyhow; typed BridgeReadError/ControlReadError/ReasonCode untouched; control-socket JSON bodies byte-identical. | | | `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clip` | | | @@ -645,7 +645,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | | `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml | #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] on reconcile/adopt/poll_operation/update/finalize; per-event provider literal and redacted resource_group field dro | | | `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | cc01388e6 | packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs | reconcile/finalize now carry a tracing instrument span with resource/provider fields; 23 per-event duplicate pairs dropped. Deviation: the row's literal span syntax (fields inside skip) is rejected by | | -| `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-system` | | | +| `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | dafc28ca1 | packages/d2b-provider-process-systemd/src/lib.rs | cancelled-ticket debug! now passes resource = %ticket.process_ref() (lazy, redacted Display) instead of eager to_canonical_string(); warn/error paths keep the canonical string. check + lib tests green | | | `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | | `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | | `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | abc324d2a | packages/d2b-provider-toolkit/src/base/guest.rs | serve_enrolled now emits tracing::warn!(frame_bytes, ...) before dropping a frame GuestFrame::new rejects (empty or oversized), keeping the session up. No correlation identifiers in the record. cargo | | From b742397e59e9bde0bba4a2c41ee610698fa69e18 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:06:40 -0700 Subject: [PATCH 483/726] generate: refresh completions, daemon api tables, and policy inputs for the wave-2 surface The wave's rows changed generated inputs: the endpoint-class value set now derives from its typed enum, daemon API line references shifted with the code, and the policy-input closures follow the lockfile edges the rows added. --- completions/d2b.bash | 6 +- completions/d2b.fish | 17 ++- completions/d2b.zsh | 6 +- docs/reference/daemon-api.md | 100 ++++++++++-------- .../schemas/v2/storage-lifecycle-report.json | 24 ++--- .../broker-default-tests/policy/Cargo.lock | 1 + .../broker-default-tests/policy/closure.json | 8 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/Cargo.lock | 1 + .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 + .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 + .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 + .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 + .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../broker-production/policy/Cargo.lock | 1 + .../broker-production/policy/closure.json | 8 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/Cargo.lock | 1 + .../broker-production/production/closure.json | 8 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 7 ++ .../main-product/policy/closure.json | 50 ++++++++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 7 ++ .../main-product/production/closure.json | 44 +++++++- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/Cargo.lock | 1 + .../broker-default-tests/policy/closure.json | 8 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/Cargo.lock | 1 + .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 + .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 + .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 + .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 + .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../broker-production/policy/Cargo.lock | 1 + .../broker-production/policy/closure.json | 8 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/Cargo.lock | 1 + .../broker-production/production/closure.json | 8 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 7 ++ .../main-product/policy/closure.json | 50 ++++++++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 7 ++ .../main-product/production/closure.json | 44 +++++++- .../main-product/production/metadata.json | 2 +- 65 files changed, 445 insertions(+), 108 deletions(-) diff --git a/completions/d2b.bash b/completions/d2b.bash index fb43932f0..0d6986dd7 100644 --- a/completions/d2b.bash +++ b/completions/d2b.bash @@ -3030,7 +3030,7 @@ _d2b() { fi case "${prev}" in --endpoint-class) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "service device transport control data" -- "${cur}")) return 0 ;; --zone) @@ -3100,7 +3100,7 @@ _d2b() { fi case "${prev}" in --endpoint-class) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "service device transport control data" -- "${cur}")) return 0 ;; --zone) @@ -3170,7 +3170,7 @@ _d2b() { fi case "${prev}" in --signal) - COMPREPLY=($(compgen -f "${cur}")) + COMPREPLY=($(compgen -W "term kill int hup" -- "${cur}")) return 0 ;; --zone) diff --git a/completions/d2b.fish b/completions/d2b.fish index ea642b6da..af1d19b42 100644 --- a/completions/d2b.fish +++ b/completions/d2b.fish @@ -499,7 +499,10 @@ complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from logs" -l human -d 'Force human-readable terminal output' complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from logs" -l no-deadline -d 'Suppress the command default deadline' complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from logs" -s h -l help -d 'Print help' -complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from kill" -l signal -r +complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from kill" -l signal -r -f -a "term\t'' +kill\t'' +int\t'' +hup\t''" complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from kill" -l zone -d 'Address a declared Zone. Without this flag the nearest local runtime is selected' -r complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from kill" -l deadline -d 'Bound all Zone requests and streams' -r complete -c d2b -n "__fish_d2b_using_subcommand exec; and __fish_seen_subcommand_from kill" -l json -d 'Emit the stable JSON envelope' @@ -950,7 +953,11 @@ complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcom complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from get" -l human -d 'Force human-readable terminal output' complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from get" -l no-deadline -d 'Suppress the command default deadline' complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help' -complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -l endpoint-class -r +complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -l endpoint-class -r -f -a "service\t'' +device\t'' +transport\t'' +control\t'' +data\t''" complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -l zone -d 'Address a declared Zone. Without this flag the nearest local runtime is selected' -r complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -l deadline -d 'Bound all Zone requests and streams' -r complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -l updates @@ -958,7 +965,11 @@ complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcom complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -l human -d 'Force human-readable terminal output' complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -l no-deadline -d 'Suppress the command default deadline' complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from list" -s h -l help -d 'Print help' -complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from watch" -l endpoint-class -r +complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from watch" -l endpoint-class -r -f -a "service\t'' +device\t'' +transport\t'' +control\t'' +data\t''" complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from watch" -l zone -d 'Address a declared Zone. Without this flag the nearest local runtime is selected' -r complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from watch" -l deadline -d 'Bound all Zone requests and streams' -r complete -c d2b -n "__fish_d2b_using_subcommand endpoint; and __fish_seen_subcommand_from watch" -l json -d 'Emit the stable JSON envelope' diff --git a/completions/d2b.zsh b/completions/d2b.zsh index 199bdb9d9..800c30048 100644 --- a/completions/d2b.zsh +++ b/completions/d2b.zsh @@ -749,7 +749,7 @@ _arguments "${_arguments_options[@]}" : \ ;; (kill) _arguments "${_arguments_options[@]}" : \ -'--signal=[]:SIGNAL:_default' \ +'--signal=[]:SIGNAL:(term kill int hup)' \ '--zone=[Address a declared Zone. Without this flag the nearest local runtime is selected]:ZONE:_default' \ '--deadline=[Bound all Zone requests and streams]:DURATION:_default' \ '(--human)--json[Emit the stable JSON envelope]' \ @@ -1811,7 +1811,7 @@ _arguments "${_arguments_options[@]}" : \ ;; (list) _arguments "${_arguments_options[@]}" : \ -'--endpoint-class=[]:ENDPOINT_CLASS:_default' \ +'--endpoint-class=[]:ENDPOINT_CLASS:(service device transport control data)' \ '--zone=[Address a declared Zone. Without this flag the nearest local runtime is selected]:ZONE:_default' \ '--deadline=[Bound all Zone requests and streams]:DURATION:_default' \ '--updates[]' \ @@ -1824,7 +1824,7 @@ _arguments "${_arguments_options[@]}" : \ ;; (watch) _arguments "${_arguments_options[@]}" : \ -'--endpoint-class=[]:ENDPOINT_CLASS:_default' \ +'--endpoint-class=[]:ENDPOINT_CLASS:(service device transport control data)' \ '--zone=[Address a declared Zone. Without this flag the nearest local runtime is selected]:ZONE:_default' \ '--deadline=[Bound all Zone requests and streams]:DURATION:_default' \ '(--human)--json[Emit the stable JSON envelope]' \ diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 1e7567825..c01f9e043 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -268,9 +268,9 @@ host reboot. | `UsbipBindCliRequest` | struct | [`UsbipBindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L362) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | | `UsbipUnbindCliRequest` | struct | [`UsbipUnbindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L371) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | | `NamedProcessStreamRequest` | enum | [`NamedProcessStreamRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L1041) | `Stdin` - struct { `offset`: `u64`; `chunk_base64`: `String`; `eof`: `bool` }; `Read` - struct { `stream`: `ExecStream`; `offset`: `u64`; `max_len`: `u64`; `wait`: `bool`; `timeout_ms`: `u64` }; `Signal` - struct { `control_seq`: `u64`; `signo`: `u32` }; `Resize` - struct { `control_seq`: `u64`; `rows`: `u32`; `cols`: `u32` }; `CloseStdin` - struct { `offset`: `u64` }; `Cancel`; `Close`; `Wait` - struct { `timeout_ms`: `u64` } | -| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2053) | struct { `flags`: `MutationFlags` } | -| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2060) | struct { `flags`: `MutationFlags` } | -| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2072) | struct { `flags`: `MutationFlags`; `network`: `bool` } | +| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2061) | struct { `flags`: `MutationFlags` } | +| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2068) | struct { `flags`: `MutationFlags` } | +| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2080) | struct { `flags`: `MutationFlags`; `network`: `bool` } | ### Broker socket request types @@ -375,15 +375,15 @@ see the auto-generated tables above for the committed Rust variants. | `WorkloadOpResponse` | enum | [`WorkloadOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L175) | `List` - (WorkloadListResult); `Status` - (Box); `LauncherExec` - (LauncherExecResult) | | `ExecOpResponse` | enum | [`ExecOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1014) | `Start` - (ExecStartResult); `DetachedCreate` - (ExecDetachedCreateResult); `WriteStdin` - (ExecWriteStdinResult); `ReadOutput` - (ExecReadOutputResult); `Signal` - (ExecControlResult); `Resize` - (ExecControlResult); `Wait` - (ExecWaitResult); `Close` - (ExecCloseResult); `List` - (ExecDetachedListResult); `Logs` - (ExecDetachedLogsResult); `Status` - (ExecDetachedStatusResult); `Kill` - (ExecDetachedKillResult) | | `NamedProcessStreamResponse` | enum | [`NamedProcessStreamResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1141) | `Stdin` - (ExecWriteStdinResult); `Output` - (ExecReadOutputResult); `Delivered` - (ExecControlResult); `Wait` - (ExecWaitResult); `Closed` - (ExecCloseResult); `Terminal` - (ExecTerminalStatus); `Error` - (NamedProcessStreamError) | -| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1836) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | -| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2043) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | -| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2105) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | -| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2131) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | -| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2141) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | -| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2150) | struct { `vms`: `Vec`; `read_model`: `Option` } | -| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2158) | struct { `entries`: `Vec`; `read_model`: `Option` } | -| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2178) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2469) | struct { `entries`: `Vec` } | +| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1844) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | +| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2051) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | +| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2113) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | +| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2139) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | +| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2149) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | +| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2158) | struct { `vms`: `Vec`; `read_model`: `Option` } | +| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2166) | struct { `entries`: `Vec`; `read_model`: `Option` } | +| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2186) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2474) | struct { `entries`: `Vec` } | ### Broker socket response types @@ -490,7 +490,7 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2635) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | +| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2640) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | ### Other documented enums @@ -515,8 +515,8 @@ running live guest activation. | `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2985) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | | `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3059) | `Exited`; `Signaled`; `Killed` | | `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3097) | `ChildReaped` - (ChildReapedNotification); `Unknown` | -| `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L142) | `Lifecycle`; `Admin` | -| `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L180) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | +| `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L141) | `Lifecycle`; `Admin` | +| `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L179) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | | `ProxyReadinessStage` | enum | [`ProxyReadinessStage`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L12) | `Upstream`; `Listener`; `FirstClient` | | `ProxyReadinessState` | enum | [`ProxyReadinessState`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L24) | `Ready`; `Failed` | | `ProxyReadinessFailure` | enum | [`ProxyReadinessFailure`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L34) | `UpstreamUnavailable`; `ListenerUnavailable`; `FirstClientTimeout`; `ClientRejected`; `ChannelUnavailable` | @@ -529,35 +529,35 @@ running live guest activation. | `ExecOp` | enum | [`ExecOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L679) | `Start` - (ExecStartArgs); `WriteStdin` - (ExecWriteStdinArgs); `ReadOutput` - (ExecReadOutputArgs); `Signal` - (ExecSignalArgs); `Resize` - (ExecResizeArgs); `Wait` - (ExecWaitArgs); `Close` - (ExecCloseArgs); `List` - (ExecDetachedListArgs); `Logs` - (ExecDetachedLogsArgs); `Status` - (ExecDetachedStatusArgs); `Kill` - (ExecDetachedKillArgs) | | `ExecTerminalStatus` | enum | [`ExecTerminalStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L795) | `Exited` - struct { `code`: `i32` }; `Signaled` - struct { `signal`: `u32` }; `Error` - struct { `slug`: `String` } | | `ExecDetachedKillOutcome` | enum | [`ExecDetachedKillOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L986) | `Cancelling`; `AlreadyTerminal` | -| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1440) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | -| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1451) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | -| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1561) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1704) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | -| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1850) | `Speaker`; `Microphone` | -| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1864) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1906) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1951) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | -| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2014) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2120) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | -| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2228) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | -| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2246) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | -| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2271) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | -| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2284) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | -| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2298) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | -| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2321) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | -| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2339) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | -| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2352) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | -| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2371) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | -| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2407) | `Usbip`; `QemuMediaSlot` | -| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2490) | `Human`; `Json` | -| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2498) | `None`; `Launcher`; `Admin` | +| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1448) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | +| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1459) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | +| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1569) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1712) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | +| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1858) | `Speaker`; `Microphone` | +| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1872) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1914) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1959) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | +| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2022) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2128) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | +| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2233) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | +| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2251) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | +| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2276) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | +| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2289) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | +| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2303) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | +| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2326) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | +| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2344) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | +| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2357) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | +| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2376) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | +| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2412) | `Usbip`; `QemuMediaSlot` | +| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2495) | `Human`; `Json` | +| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2503) | `None`; `Launcher`; `Admin` | | `TerminalStream` | enum | [`TerminalStream`](../../packages/d2b-contracts-control/src/terminal_wire.rs#L13) | `Stdout`; `Stderr` | | `HelperScopeKind` | enum | [`HelperScopeKind`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L68) | `LauncherApp`; `WaylandProxy` | | `HelperScopeState` | enum | [`HelperScopeState`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L95) | `Starting`; `Active`; `Stopping`; `Exited`; `Degraded` | -| `HelperFailureCode` | enum | [`HelperFailureCode`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L316) | `InvalidRequest`; `OperationIdConflict`; `QueueFull`; `Timeout`; `UserManagerUnavailable`; `EnvironmentInvalid`; `ExecutableUnavailable`; `ScopeCreateFailed`; `ScopeIdentityMismatch`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable`; `FirstClientTimeout`; `Internal` | -| `HelperOperationDisposition` | enum | [`HelperOperationDisposition`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L337) | `Committed`; `AlreadyCommitted`; `Completed` | -| `DaemonToUnsafeLocalHelper` | enum | [`DaemonToUnsafeLocalHelper`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L369) | `HelloAccepted` - (HelperHelloAccepted); `Heartbeat` - (HelperHeartbeat); `Launch` - (Box) | -| `UnsafeLocalHelperToDaemon` | enum | [`UnsafeLocalHelperToDaemon`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L381) | `Hello` - (HelperHello); `Snapshot` - (HelperSnapshot); `Heartbeat` - (HelperHeartbeat); `Operation` - (HelperOperationResult); `Rejected` - (HelperOperationRejected) | +| `HelperFailureCode` | enum | [`HelperFailureCode`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L312) | `InvalidRequest`; `OperationIdConflict`; `QueueFull`; `Timeout`; `UserManagerUnavailable`; `EnvironmentInvalid`; `ExecutableUnavailable`; `ScopeCreateFailed`; `ScopeIdentityMismatch`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable`; `FirstClientTimeout`; `Internal` | +| `HelperOperationDisposition` | enum | [`HelperOperationDisposition`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L333) | `Committed`; `AlreadyCommitted`; `Completed` | +| `DaemonToUnsafeLocalHelper` | enum | [`DaemonToUnsafeLocalHelper`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L365) | `HelloAccepted` - (HelperHelloAccepted); `Heartbeat` - (HelperHeartbeat); `Launch` - (Box) | +| `UnsafeLocalHelperToDaemon` | enum | [`UnsafeLocalHelperToDaemon`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L377) | `Hello` - (HelperHello); `Snapshot` - (HelperSnapshot); `Heartbeat` - (HelperHeartbeat); `Operation` - (HelperOperationResult); `Rejected` - (HelperOperationRejected) | | `AudioGrant` | enum | [`AudioGrant`](../../packages/d2b-contracts/src/audio.rs#L79) | `On`; `Off` | | `Capability` | enum | [`Capability`](../../packages/d2b-contracts/src/capability.rs#L29) | `Lifecycle`; `Exec`; `Pty`; `Logs`; `FileCopy`; `PortForward`; `PersistentShell`; `Vsock`; `Virtiofs`; `WindowForwarding`; `DisplayStreaming`; `Clipboard`; `AudioPlayback`; `AudioCapture`; `Hid`; `Usb`; `GpuAccel`; `Snapshots`; `Hotplug`; `EphemeralSessions`; `ProviderManagedIsolation`; `ConfiguredLaunch` | | `RealmControllerRuntimeState` | enum | [`RealmControllerRuntimeState`](../../packages/d2b-contracts/src/controller_config.rs#L184) | `MetadataOnly` | @@ -569,7 +569,7 @@ running live guest activation. | `ResourcePlane` | enum | [`ResourcePlane`](../../packages/d2b-contracts/src/identity.rs#L75) | `Manager`; `Legacy` | | `IdentityClass` | enum | [`IdentityClass`](../../packages/d2b-contracts/src/identity.rs#L235) | `ZoneId`; `ResourceName`; `ResourceTypeName`; `ResourceUid`; `SessionPurpose`; `ServiceName`; `SchemaFingerprint`; `BindingDigest`; `ResourceBundleGenerationId`; `TranscriptHash`; `Timestamp`; `ResourceGeneration`; `ReconnectGeneration`; `ControllerGeneration`; `ConfigurationGeneration` | | `RealmIdentityConfigRuntimeState` | enum | [`RealmIdentityConfigRuntimeState`](../../packages/d2b-contracts/src/identity_config.rs#L179) | `MetadataOnly` | -| `LauncherMetadataRuntimeState` | enum | [`LauncherMetadataRuntimeState`](../../packages/d2b-contracts/src/launcher.rs#L42) | `ContractOnly` | +| `LauncherMetadataRuntimeState` | enum | [`LauncherMetadataRuntimeState`](../../packages/d2b-contracts/src/launcher.rs#L71) | `ContractOnly` | | `KnownFeatureFlag` | enum | [`KnownFeatureFlag`](../../packages/d2b-contracts/src/lib.rs#L123) | `TypedErrors`; `ManifestV04`; `StatusCheckBridges`; `ExportBrokerAudit`; `ConfiguredLaunchV1`; `UnsafeLocalProviderV1` | | `W3BrokerOperation` | enum | [`W3BrokerOperation`](../../packages/d2b-contracts/src/privileges_w3.rs#L28) | `DelegateCgroupV2`; `OpenCgroupDir`; `PrepareStateDir`; `PrepareRuntimeDir`; `OpenKvm`; `OpenVhostNet`; `OpenFuse`; `OpenDevice`; `CreateTapFd`; `CreatePersistentTap`; `DeletePersistentTap`; `CreateBridge`; `DeleteBridge`; `SetBridgePortFlags`; `ApplyNftables`; `ApplyNftablesProjection`; `ApplyRoute`; `ApplySysctl`; `ApplyNmUnmanaged`; `UpdateHostsFile`; `ModprobeIfAllowed`; `UsbipBindFirewallRule`; `MigrateLegacySwtpmState`; `SecurityKeyOpenDevice`; `SecurityKeyApplyUdevRules` | | `EntrypointMode` | enum | [`EntrypointMode`](../../packages/d2b-contracts/src/realm.rs#L12) | `HostResident`; `GatewayBacked` | @@ -578,8 +578,8 @@ running live guest activation. | `SecurityKeyVmSessionState` | enum | [`SecurityKeyVmSessionState`](../../packages/d2b-contracts/src/security_key.rs#L165) | `Idle`; `AwaitingLease`; `Active`; `Completed`; `Cancelled` | | `SecurityKeySessionResult` | enum | [`SecurityKeySessionResult`](../../packages/d2b-contracts/src/security_key.rs#L230) | `InProgress`; `Success`; `CtapError`; `Timeout`; `Cancelled`; `InternalError` | | `SecurityKeyEvent` | enum | [`SecurityKeyEvent`](../../packages/d2b-contracts/src/security_key.rs#L290) | `SessionStarted` - struct { `session_id`: `SecurityKeySessionId`; `vm`: `String`; `device_label`: `SecurityKeyDeviceLabel`; `started_at`: `String` }; `SessionSucceeded` - struct { `session_id`: `SecurityKeySessionId`; `vm`: `String`; `device_label`: `SecurityKeyDeviceLabel`; `ended_at`: `String` }; `SessionFailed` - struct { `session_id`: `SecurityKeySessionId`; `vm`: `String`; `device_label`: `SecurityKeyDeviceLabel`; `result`: `SecurityKeySessionResult`; `ended_at`: `String` }; `SessionCancelled` - struct { `session_id`: `SecurityKeySessionId`; `vm`: `String`; `device_label`: `SecurityKeyDeviceLabel`; `ended_at`: `String` }; `DeviceRemoved` - struct { `device_label`: `SecurityKeyDeviceLabel`; `interrupted_session_id`: `Option` }; `DeviceReinserted` - struct { `device_label`: `SecurityKeyDeviceLabel` }; `SessionQueued` - struct { `session_id`: `SecurityKeySessionId`; `vm`: `String`; `device_label`: `SecurityKeyDeviceLabel`; `queued_at`: `String`; `blocking_vm`: `String` } | -| `PathClass` | enum | [`PathClass`](../../packages/d2b-contracts/src/types.rs#L170) | `Vm`; `Runtime` | -| `UnsafeLocalLauncherItem` | enum | [`UnsafeLocalLauncherItem`](../../packages/d2b-contracts/src/unsafe_local_workloads.rs#L170) | `Exec` - (UnsafeLocalExecItem); `Shell` - (UnsafeLocalShellItem) | +| `PathClass` | enum | [`PathClass`](../../packages/d2b-contracts/src/types.rs#L235) | `Vm`; `Runtime` | +| `UnsafeLocalLauncherItem` | enum | [`UnsafeLocalLauncherItem`](../../packages/d2b-contracts/src/unsafe_local_workloads.rs#L248) | `Exec` - (UnsafeLocalExecItem); `Shell` - (UnsafeLocalShellItem) | | `WorkloadProviderKind` | enum | [`WorkloadProviderKind`](../../packages/d2b-contracts/src/workload.rs#L13) | `LocalVm`; `QemuMedia`; `ProviderManaged`; `UnsafeLocal` | | `IsolationPosture` | enum | [`IsolationPosture`](../../packages/d2b-contracts/src/workload.rs#L27) | `VirtualMachine`; `ProviderManaged`; `UnsafeLocal` | | `EnvironmentPosture` | enum | [`EnvironmentPosture`](../../packages/d2b-contracts/src/workload.rs#L39) | `RuntimeManaged`; `SystemdUserManagerAmbient` | @@ -646,16 +646,18 @@ the failure class, for example `host check`, `audit`, `status`, or | --- | --- | --- | --- | | `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L966) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | | `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2534) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | -| `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L199) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | +| `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L198) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | | `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1208) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | | `NamedProcessStreamError` | struct | [`NamedProcessStreamError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1228) | struct { `kind`: `NamedProcessStreamErrorKind` } | | `ShellNameError` | struct | [`ShellNameError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1309) | empty struct | -| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1887) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | -| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1988) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | +| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1895) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | +| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1996) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | | `LevelPercentError` | enum | [`LevelPercentError`](../../packages/d2b-contracts/src/audio.rs#L28) | `OutOfRange` - (u8) | | `AudioPolicyError` | enum | [`AudioPolicyError`](../../packages/d2b-contracts/src/audio.rs#L216) | `InvalidJson` - (String); `InvalidField` - (String); `UnknownSchemaVersion` - (String); `Serialize` - (String) | | `AuditExportErrorCode` | enum | [`AuditExportErrorCode`](../../packages/d2b-contracts/src/audit_wire.rs#L20) | `HashBreak`; `RecordInvalid`; `ReadFailed` | +| `AuditPageError` | enum | [`AuditPageError`](../../packages/d2b-contracts/src/audit_wire.rs#L53) | `CompleteWithCursor`; `IncompleteWithoutCursor` | +| `ConfiguredArgvError` | enum | [`ConfiguredArgvError`](../../packages/d2b-contracts/src/configured_argv.rs#L11) | `Empty`; `TooManyArgs` - struct { `max`: `usize` }; `NulByte`; `ArgTooLong` - struct { `max`: `usize` }; `ByteCountOverflow`; `TooManyBytes` - struct { `max`: `usize` } | | `ErrorKind` | enum | [`ErrorKind`](../../packages/d2b-contracts/src/constellation_error.rs#L25) | `CapabilityDenied`; `Unauthorized`; `NoRealmEntrypoint`; `GatewayUnavailable`; `ProviderAllocationFailed`; `RelayUnavailable`; `AuthenticationFailed`; `VersionSkew`; `OperationInProgress`; `IdempotencyKeyConflict`; `IdempotencyKeyExpired`; `Backpressure`; `Cancelled`; `Timeout`; `FrameTooLarge`; `MalformedFrame`; `InvalidTarget`; `AuditUnavailable`; `UnsupportedFeature` | | `ConstellationError` | struct | [`ConstellationError`](../../packages/d2b-contracts/src/constellation_error.rs#L108) | struct { `kind`: `ErrorKind`; `correlation_id`: `Option`; `capability`: `Option`; `negotiated_capability_fingerprint`: `Option`; `message`: `String` } | | `ContractStringError` | enum | [`ContractStringError`](../../packages/d2b-contracts/src/contract_id.rs#L18) | `Empty`; `TooLong` - struct { `max`: `usize` }; `BadShape` | @@ -675,8 +677,12 @@ the failure class, for example `host check`, `audit`, `status`, or | `ResourceRefError` | enum | [`ResourceRefError`](../../packages/d2b-contracts/src/identity.rs#L738) | `Empty`; `MissingSeparator`; `ExtraSeparator`; `Type` - (IdentityError); `Name` - (IdentityError) | | `RealmIdentityConfigError` | enum | [`RealmIdentityConfigError`](../../packages/d2b-contracts/src/identity_config.rs#L240) | `UnsupportedSchemaVersion` - struct { `found`: `String` }; `UnsupportedRuntimeState`; `InvariantDisabled` - (&'static str) | | `IdError` | enum | [`IdError`](../../packages/d2b-contracts/src/ids.rs#L54) | `Empty`; `TooLong`; `BadShape` | +| `LauncherMetadataError` | enum | [`LauncherMetadataError`](../../packages/d2b-contracts/src/launcher.rs#L13) | `SchemaVersionMismatch` - struct { `expected`: `&'static str` }; `InvariantsNotAllTrue` | | `RealmTargetParseError` | enum | [`RealmTargetParseError`](../../packages/d2b-contracts/src/target.rs#L280) | `Empty`; `BareAliasRequiresContext`; `MissingSuffix`; `MissingWorkload`; `MissingRealm`; `SelectorNotAllowed`; `ReservedLabel`; `BadLabel` - (IdError); `BadRealmPath`; `AliasAmbiguous` - struct { `alias`: `WorkloadId`; `candidates`: `Vec` }; `LegacyNodeQualified` - struct { `legacy`: `LegacyNodeQualifiedTarget`; `suggested`: `RealmTarget` } | | `TokenError` | enum | [`TokenError`](../../packages/d2b-contracts/src/token.rs#L27) | `Empty`; `TooLong`; `BadShape` | +| `MediaRefError` | enum | [`MediaRefError`](../../packages/d2b-contracts/src/types.rs#L115) | `Empty`; `TooLong` - struct { `max`: `usize` }; `BadStart`; `BadShape` | +| `UsbBusIdError` | enum | [`UsbBusIdError`](../../packages/d2b-contracts/src/types.rs#L177) | `Empty`; `TooLong` - struct { `max`: `usize` }; `InvalidEdgePunctuation`; `InvalidCharacter`; `MissingSeparator` | +| `UnsafeLocalWorkloadsError` | enum | [`UnsafeLocalWorkloadsError`](../../packages/d2b-contracts/src/unsafe_local_workloads.rs#L23) | `SchemaVersionMismatch` - struct { `expected`: `&'static str` }; `TooManyWorkloads` - struct { `max`: `usize` }; `TooManyLocalVmWorkloads` - struct { `max`: `usize` }; `TooManyPrivateWorkloads` - struct { `max`: `usize` }; `DuplicateUnsafeLocalTarget` - struct { `target`: `String` }; `DuplicateConfiguredTarget` - struct { `target`: `String` }; `LocalVmRuntimeKindMismatch`; `LegacyVmNamePresent`; `IdentityMismatch`; `NoItems`; `TooManyItems` - struct { `max`: `usize` }; `DuplicateItemId` - struct { `id`: `String` }; `ShellItemWithoutPolicy`; `DefaultItemMissing` - struct { `id`: `String` }; `ShellDefaultNameInvalid`; `ShellMaxSessionsInvalid` - struct { `max`: `u16` } | | `BusIdError` | enum | [`BusIdError`](../../packages/d2b-contracts/src/usbip.rs#L8) | `Empty`; `Invalid`; `TooLong` - struct { `max`: `usize` } | diff --git a/docs/reference/schemas/v2/storage-lifecycle-report.json b/docs/reference/schemas/v2/storage-lifecycle-report.json index e9c2b7ec6..8a8289daa 100644 --- a/docs/reference/schemas/v2/storage-lifecycle-report.json +++ b/docs/reference/schemas/v2/storage-lifecycle-report.json @@ -87,11 +87,11 @@ { "type": "object", "required": [ - "bundleVersion", + "bundle_version", "kind" ], "properties": { - "bundleVersion": { + "bundle_version": { "type": "integer", "format": "uint32", "minimum": 0.0 @@ -121,12 +121,12 @@ { "type": "object", "required": [ - "contractId", + "contract_id", "kind", "reason" ], "properties": { - "contractId": { + "contract_id": { "type": "string" }, "kind": { @@ -135,7 +135,7 @@ "storage-contract-invalid" ] }, - "offendingId": { + "offending_id": { "type": [ "string", "null" @@ -149,12 +149,12 @@ { "type": "object", "required": [ - "contractId", + "contract_id", "kind", "reason" ], "properties": { - "contractId": { + "contract_id": { "type": "string" }, "kind": { @@ -163,7 +163,7 @@ "sync-contract-invalid" ] }, - "offendingId": { + "offending_id": { "type": [ "string", "null" @@ -178,7 +178,7 @@ "type": "object", "required": [ "kind", - "roleId", + "role_id", "vm" ], "properties": { @@ -188,7 +188,7 @@ "missing-restart-policy" ] }, - "roleId": { + "role_id": { "type": "string" }, "vm": { @@ -200,7 +200,7 @@ "type": "object", "required": [ "kind", - "roleId", + "role_id", "vm" ], "properties": { @@ -210,7 +210,7 @@ "adoptable-missing-cgroup-leaf" ] }, - "roleId": { + "role_id": { "type": "string" }, "vm": { diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index efc22f1e5..091db8a8d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1164,6 +1164,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 1191b2c85..966ea1166 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index 7a4bf1d3e..3fe1be6ea 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1002,6 +1002,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 1191b2c85..966ea1166 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 7ba2961c2..924cd36ed 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1166,6 +1166,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 883152b33..2851e3278 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index b764e3cc0..b4a513cbb 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1004,6 +1004,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 883152b33..2851e3278 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 8b4d1c4a9..b629bcf49 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1166,6 +1166,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index 7c00ed2cd..74c1f1c03 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 9405f34a8..6c983b7ca 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1004,6 +1004,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index 7c00ed2cd..74c1f1c03 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 034d64dac..00723e119 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1164,6 +1164,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index 1191b2c85..966ea1166 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index 7f43d7ac5..051a0ccc9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1002,6 +1002,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index 1191b2c85..966ea1166 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index 8dc4fa786..4e4401993 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -907,6 +907,7 @@ dependencies = [ "d2b-broker", "d2b-broker-fixture-handlers", "regex", + "serde", "serde_json", "tokio", "tracing-subscriber", @@ -1059,6 +1060,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] @@ -1199,6 +1201,7 @@ dependencies = [ name = "d2b-provider-clipboard-wayland" version = "0.0.0-bootstrap" dependencies = [ + "anyhow", "command-fds", "d2b-contracts", "d2b-contracts-resource", @@ -1214,6 +1217,7 @@ dependencies = [ "sha2", "thiserror 2.0.20", "tracing", + "tracing-subscriber", "wayland-client", "wayland-protocols", "wayland-protocols-misc", @@ -1895,6 +1899,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-resource-runtime", "d2b-resource-types", + "serde", "serde_json", "tokio", ] @@ -1910,6 +1915,7 @@ dependencies = [ "d2b-session-unix", "tokio", "tracing", + "tracing-subscriber", ] @@ -2116,6 +2122,7 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "serde_json", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index cea0a6061..b8c327120 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4151,6 +4151,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-broker-composition@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-broker-composition@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -4817,6 +4823,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host-activation-helper@0.0.0-bootstrap#path", "to": "libc@0.2.189#registry+https://github.com/rust-lang/crates.io-index", @@ -5201,6 +5213,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "anyhow@1.0.104#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "command-fds@0.3.3#registry+https://github.com/rust-lang/crates.io-index", @@ -5285,6 +5303,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -5531,6 +5555,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-credential-secret-service@0.0.0-bootstrap#path", + "to": "d2b-provider-toolkit@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-credential-secret-service@0.0.0-bootstrap#path", "to": "d2b-provider-toolkit@0.0.0-bootstrap#path", @@ -7715,6 +7745,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -7757,6 +7793,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8591,6 +8633,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-wayland-session@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index 1905ff13a..72bb28527 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index 8dc4fa786..4e4401993 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -907,6 +907,7 @@ dependencies = [ "d2b-broker", "d2b-broker-fixture-handlers", "regex", + "serde", "serde_json", "tokio", "tracing-subscriber", @@ -1059,6 +1060,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] @@ -1199,6 +1201,7 @@ dependencies = [ name = "d2b-provider-clipboard-wayland" version = "0.0.0-bootstrap" dependencies = [ + "anyhow", "command-fds", "d2b-contracts", "d2b-contracts-resource", @@ -1214,6 +1217,7 @@ dependencies = [ "sha2", "thiserror 2.0.20", "tracing", + "tracing-subscriber", "wayland-client", "wayland-protocols", "wayland-protocols-misc", @@ -1895,6 +1899,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-resource-runtime", "d2b-resource-types", + "serde", "serde_json", "tokio", ] @@ -1910,6 +1915,7 @@ dependencies = [ "d2b-session-unix", "tokio", "tracing", + "tracing-subscriber", ] @@ -2116,6 +2122,7 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "serde_json", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index f0f7aa921..f7890fdac 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4151,6 +4151,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-broker-composition@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-broker-composition@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -4679,6 +4685,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host-activation-helper@0.0.0-bootstrap#path", "to": "libc@0.2.189#registry+https://github.com/rust-lang/crates.io-index", @@ -4985,6 +4997,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "anyhow@1.0.104#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "command-fds@0.3.3#registry+https://github.com/rust-lang/crates.io-index", @@ -5069,6 +5087,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -7265,6 +7289,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -7301,6 +7331,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8033,6 +8069,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-wayland-session@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index 1905ff13a..72bb28527 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 53690be57..ee238ec25 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1158,6 +1158,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 420f8a187..116e6cfb7 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index 8f9e742a3..7d5a8bd13 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -996,6 +996,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 420f8a187..116e6cfb7 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 5a411331d..425fe6ed7 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1160,6 +1160,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index fe6e89c73..8e8afe2ae 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index 3c1994f24..e802af7f7 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -998,6 +998,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index fe6e89c73..8e8afe2ae 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 0c74fffc4..de3e5edd9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1160,6 +1160,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index 41620cc95..52c1c08c1 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 53fd09f74..f69f8aebf 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -998,6 +998,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index 41620cc95..52c1c08c1 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index 46a8e8584..a303dbd4f 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1158,6 +1158,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index 420f8a187..116e6cfb7 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock index f20e301bb..2a9b4ea08 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock @@ -366,6 +366,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 601cef78b..614a78fac 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -996,6 +996,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index 420f8a187..116e6cfb7 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index 8dc4fa786..4e4401993 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -907,6 +907,7 @@ dependencies = [ "d2b-broker", "d2b-broker-fixture-handlers", "regex", + "serde", "serde_json", "tokio", "tracing-subscriber", @@ -1059,6 +1060,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] @@ -1199,6 +1201,7 @@ dependencies = [ name = "d2b-provider-clipboard-wayland" version = "0.0.0-bootstrap" dependencies = [ + "anyhow", "command-fds", "d2b-contracts", "d2b-contracts-resource", @@ -1214,6 +1217,7 @@ dependencies = [ "sha2", "thiserror 2.0.20", "tracing", + "tracing-subscriber", "wayland-client", "wayland-protocols", "wayland-protocols-misc", @@ -1895,6 +1899,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-resource-runtime", "d2b-resource-types", + "serde", "serde_json", "tokio", ] @@ -1910,6 +1915,7 @@ dependencies = [ "d2b-session-unix", "tokio", "tracing", + "tracing-subscriber", ] @@ -2116,6 +2122,7 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "serde_json", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index 3c768ceb4..eac5c3a02 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4189,6 +4189,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-broker-composition@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-broker-composition@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -4855,6 +4861,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host-activation-helper@0.0.0-bootstrap#path", "to": "libc@0.2.189#registry+https://github.com/rust-lang/crates.io-index", @@ -5239,6 +5251,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "anyhow@1.0.104#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "command-fds@0.3.3#registry+https://github.com/rust-lang/crates.io-index", @@ -5323,6 +5341,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -5569,6 +5593,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-credential-secret-service@0.0.0-bootstrap#path", + "to": "d2b-provider-toolkit@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-credential-secret-service@0.0.0-bootstrap#path", "to": "d2b-provider-toolkit@0.0.0-bootstrap#path", @@ -7753,6 +7783,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -7795,6 +7831,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8629,6 +8671,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-wayland-session@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index 714af7b02..5a4c7b37b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index 8dc4fa786..4e4401993 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -907,6 +907,7 @@ dependencies = [ "d2b-broker", "d2b-broker-fixture-handlers", "regex", + "serde", "serde_json", "tokio", "tracing-subscriber", @@ -1059,6 +1060,7 @@ dependencies = [ "sha2", "tempfile", "tokio", + "tracing", ] @@ -1199,6 +1201,7 @@ dependencies = [ name = "d2b-provider-clipboard-wayland" version = "0.0.0-bootstrap" dependencies = [ + "anyhow", "command-fds", "d2b-contracts", "d2b-contracts-resource", @@ -1214,6 +1217,7 @@ dependencies = [ "sha2", "thiserror 2.0.20", "tracing", + "tracing-subscriber", "wayland-client", "wayland-protocols", "wayland-protocols-misc", @@ -1895,6 +1899,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-resource-runtime", "d2b-resource-types", + "serde", "serde_json", "tokio", ] @@ -1910,6 +1915,7 @@ dependencies = [ "d2b-session-unix", "tokio", "tracing", + "tracing-subscriber", ] @@ -2116,6 +2122,7 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "serde_json", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index 4fc3da78a..d30796731 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4189,6 +4189,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-broker-composition@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-broker-composition@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -4717,6 +4723,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host-activation-helper@0.0.0-bootstrap#path", "to": "libc@0.2.189#registry+https://github.com/rust-lang/crates.io-index", @@ -5023,6 +5035,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "anyhow@1.0.104#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "command-fds@0.3.3#registry+https://github.com/rust-lang/crates.io-index", @@ -5107,6 +5125,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-clipboard-wayland@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -7303,6 +7327,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", + "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-telemetry-service@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -7339,6 +7369,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", + "to": "tracing-subscriber@0.3.23#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-test-controller@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8071,6 +8107,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-wayland-session@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index 714af7b02..5a4c7b37b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "23d7e350188b0a139fa1f87cb9f6e431e9bce9f4b40c7448462f3f5050c51b18", + "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", From d438d85b6794b343239a401aeb39873cc213fed8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:15:57 -0700 Subject: [PATCH 484/726] provider-guest: read the azure ref through its contracts path The container-apps crate narrowed its root re-exports this wave, so the guest effect builder now names the type where it is defined, matching the same file's newer call. --- packages/d2b-provider-guest/src/effects_service.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index bbcfd0a12..b4dc13baa 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -1806,9 +1806,9 @@ mod tests { .unwrap(); let config = aca_runtime::AcaProviderConfig::new( ResourceRef::parse("Guest/gateway").unwrap(), - aca_runtime::OpaqueAzureRef::parse("tenant").unwrap(), - aca_runtime::OpaqueAzureRef::parse("client").unwrap(), - aca_runtime::OpaqueAzureRef::parse("subscription").unwrap(), + d2b_contracts_provider::v3::credential::OpaqueAzureRef::parse("tenant").unwrap(), + d2b_contracts_provider::v3::credential::OpaqueAzureRef::parse("client").unwrap(), + d2b_contracts_provider::v3::credential::OpaqueAzureRef::parse("subscription").unwrap(), ResourceRef::parse("Credential/control").unwrap(), None, aca_runtime::AcaConfiguredImageId::parse("environment").unwrap(), From dc1b0b05e2a55a1d8bc1587d574ecb2d04c7cb8f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:15:57 -0700 Subject: [PATCH 485/726] display: resolve the proxy module's self-paths and drop what the move orphaned With the module compiled inside the binary, its internal references need the crate prefix, and the items whose only callers stayed behind in the library are gone or gated to tests. 131 binary tests pass. --- .../src/wayland_proxy/bridge.rs | 2 +- .../src/wayland_proxy/decoration.rs | 12 +----- .../src/wayland_proxy/dmabuf.rs | 2 +- .../src/wayland_proxy/filter.rs | 40 +++++++++---------- .../src/wayland_proxy/mod.rs | 1 - .../src/wayland_proxy/policy.rs | 12 +++--- .../src/wayland_proxy/readiness.rs | 2 +- 7 files changed, 31 insertions(+), 40 deletions(-) diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs index db45ae6b5..788cdc0ad 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs @@ -17,7 +17,7 @@ use std::{ use d2b_contracts::{workload::WorkloadProviderKind, workload_identity::WorkloadTarget}; use serde::Serialize; -use wayland_proxy::identity::ProxyIdentity; +use crate::wayland_proxy::identity::ProxyIdentity; const LINUX_SUN_PATH_BYTES: usize = 108; diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs index 580aa39a6..675e83146 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs @@ -40,7 +40,7 @@ use wl_proxy::{ }, }; -use wayland_proxy::diag::{DiagRateLimiter, bounded_error_detail}; +use crate::wayland_proxy::diag::{DiagRateLimiter, bounded_error_detail}; pub const DEFAULT_BORDER_THICKNESS: u32 = 4; pub const WRAPPER_RAIL_WIDTH: u32 = 9; @@ -138,9 +138,6 @@ impl SanitizedLabel { &self.0 } - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } } pub fn sanitize_label(input: &str) -> Option { @@ -1693,13 +1690,6 @@ impl DecorationManager { } } - #[cfg(test)] - pub fn set_urgent_for_tests(&mut self, surface_id: u64, urgent: bool) { - if let Some(state) = self.surfaces.get_mut(&surface_id) { - state.visual.urgent = urgent; - } - } - fn create_wrapper_rail_buffer( &self, width: u32, diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs index 24603a34c..ae08227b2 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs @@ -21,7 +21,7 @@ use wl_proxy::protocols::{ wayland::{wl_buffer::WlBuffer, wl_surface::WlSurface}, }; -use wayland_proxy::{ +use crate::wayland_proxy::{ decoration::{SharedDecorationManager, tracking_buffer_handler}, diag::DiagRateLimiter, }; diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs index d4f2f4e31..b14bc286e 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs @@ -75,7 +75,7 @@ use wl_proxy::{ state::{State, StateHandler}, }; -use wayland_proxy::{ +use crate::wayland_proxy::{ bridge::{ BridgeConfig, BridgeConnectionState, BridgeHandoff, BridgeReconnectMachine, BridgeTransferKind, BridgeTransferMetadata, LocalTransferFd, @@ -604,9 +604,9 @@ impl VirtualClipboardState { return; }; match bridge.handoff_transfer_fd(&local_fd, metadata) { - wayland_proxy::bridge::HandoffStatus::Delivered => { + crate::wayland_proxy::bridge::HandoffStatus::Delivered => { let _ = local_fd - .close_after_handoff(wayland_proxy::bridge::HandoffStatus::Delivered); + .close_after_handoff(crate::wayland_proxy::bridge::HandoffStatus::Delivered); log::debug!( "[d2b-wlproxy] target={} event=clipboard-bridge reason=handoff-delivered kind={:?} mime={}", self.identity_label, @@ -614,12 +614,12 @@ impl VirtualClipboardState { bounded_log_mime(&metadata.mime_type) ); } - wayland_proxy::bridge::HandoffStatus::Backpressure => { + crate::wayland_proxy::bridge::HandoffStatus::Backpressure => { self.enqueue_bridge_handoff(local_fd, metadata); } - wayland_proxy::bridge::HandoffStatus::Failed(error) => { + crate::wayland_proxy::bridge::HandoffStatus::Failed(error) => { let _ = local_fd.close_after_handoff( - wayland_proxy::bridge::HandoffStatus::Failed(error), + crate::wayland_proxy::bridge::HandoffStatus::Failed(error), ); self.mark_bridge_disconnected(); self.ensure_bridge_connected(); @@ -678,13 +678,13 @@ impl VirtualClipboardState { fn handle_pending_handoff_status( &mut self, pending: PendingBridgeHandoff, - status: wayland_proxy::bridge::HandoffStatus, + status: crate::wayland_proxy::bridge::HandoffStatus, ) -> PendingHandoffStep { match status { - wayland_proxy::bridge::HandoffStatus::Delivered => { + crate::wayland_proxy::bridge::HandoffStatus::Delivered => { let _ = pending .fd - .close_after_handoff(wayland_proxy::bridge::HandoffStatus::Delivered); + .close_after_handoff(crate::wayland_proxy::bridge::HandoffStatus::Delivered); log::debug!( "[d2b-wlproxy] target={} event=clipboard-bridge reason=queued-handoff-delivered kind={:?} mime={}", self.identity_label, @@ -693,11 +693,11 @@ impl VirtualClipboardState { ); PendingHandoffStep::Continue } - wayland_proxy::bridge::HandoffStatus::Backpressure => { + crate::wayland_proxy::bridge::HandoffStatus::Backpressure => { self.pending_bridge_handoffs.push_front(pending); PendingHandoffStep::Stop } - wayland_proxy::bridge::HandoffStatus::Failed(error) => { + crate::wayland_proxy::bridge::HandoffStatus::Failed(error) => { let identity_label = self.identity_label.clone(); let kind = pending.metadata.kind; let mime = bounded_log_mime(&pending.metadata.mime_type); @@ -1115,7 +1115,7 @@ impl FilterRegistryHandler { } let (action, _) = self.policy.lookup(iface_name); - let wayland_proxy::policy::GlobalAction::Allow = action else { + let crate::wayland_proxy::policy::GlobalAction::Allow = action else { // Denied: ignore and suppress global_remove forwarding too. if self.policy.log_filtered_globals { self.diag.borrow_mut().global_filtered(iface_name); @@ -2664,7 +2664,7 @@ impl WlEglstreamDisplayHandler for FilterEglstreamDisplayHandler { ) { if eglstream_handle_is_fd(r#type) { if let Some(decoration) = &self.decoration { - id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( decoration, )); decoration.borrow_mut().record_buffer(id, width, height); @@ -2707,7 +2707,7 @@ impl WlDrmHandler for FilterDrmHandler { stride: u32, format: u32, ) { - id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( &self.decoration, )); self.decoration @@ -2731,7 +2731,7 @@ impl WlDrmHandler for FilterDrmHandler { offset2: i32, stride2: i32, ) { - id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( &self.decoration, )); self.decoration @@ -2757,7 +2757,7 @@ impl WlDrmHandler for FilterDrmHandler { offset2: i32, stride2: i32, ) { - id.set_handler(wayland_proxy::decoration::tracking_buffer_handler( + id.set_handler(crate::wayland_proxy::decoration::tracking_buffer_handler( &self.decoration, )); self.decoration @@ -2875,7 +2875,7 @@ mod tests { use std::os::fd::AsRawFd; use std::os::unix::net::UnixListener; - use wayland_proxy::{ + use crate::wayland_proxy::{ bridge::BridgeReconnectPolicy, policy::{FilterPolicy, PolicyInput}, }; @@ -3107,7 +3107,7 @@ mod tests { let step = clipboard.handle_pending_handoff_status( pending, - wayland_proxy::bridge::HandoffStatus::Backpressure, + crate::wayland_proxy::bridge::HandoffStatus::Backpressure, ); assert_eq!(step, PendingHandoffStep::Stop); @@ -3237,7 +3237,7 @@ mod tests { for name in 0..6 { handler.diag.borrow_mut().bind_denied( - wayland_proxy::diag::DropReason::BindDeniedUnadvertised, + crate::wayland_proxy::diag::DropReason::BindDeniedUnadvertised, name, "zwp_text_input_manager_v3", ); @@ -3365,7 +3365,7 @@ mod tests { fn prepare_global_hides_clipboard_boundary_even_when_policy_allows_it() { let diag = Rc::new(RefCell::new(DiagRateLimiter::new("work".to_owned()))); let policy = Rc::new(FilterPolicy::build( - wayland_proxy::policy::PolicyInput { + crate::wayland_proxy::policy::PolicyInput { allow_globals: vec!["zwp_primary_selection_device_manager_v1".to_owned()], ..PolicyInput::new(local_identity()) }, diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs index eafaaa154..5e5f7c2b1 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs @@ -10,4 +10,3 @@ pub mod identity; pub mod policy; pub mod readiness; -pub use policy::{FilterPolicy, GlobalAction, PolicyInput, PolicyWarning}; diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs index 0d98ccacf..75f766cfb 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; -use wayland_proxy::identity::ProxyIdentity; +use crate::wayland_proxy::identity::ProxyIdentity; const MAX_REWRITTEN_LABEL_CHARS: usize = 256; @@ -150,15 +150,16 @@ pub struct PolicyInput { /// Per-global version caps. pub max_versions: Vec<(String, u32)>, /// dmabuf format/modifier allow filters. - pub dmabuf_allow: Vec, + pub dmabuf_allow: Vec, /// dmabuf format/modifier deny filters. - pub dmabuf_deny: Vec, + pub dmabuf_deny: Vec, /// Emit a log line for every filtered global advertisement. pub log_filtered_globals: bool, } impl PolicyInput { /// Construct policy input for one authenticated identity with secure defaults. + #[cfg(test)] pub fn new(identity: ProxyIdentity) -> Self { Self { identity, @@ -183,7 +184,7 @@ pub struct FilterPolicy { pub identity: ProxyIdentity, /// Bounded display label derived from the authenticated identity. pub identity_label: String, - pub dmabuf_filters: std::rc::Rc, + pub dmabuf_filters: std::rc::Rc, pub log_filtered_globals: bool, /// Runtime advisories emitted by the filter process at startup. pub warnings: Vec, @@ -314,7 +315,7 @@ impl FilterPolicy { identity, identity_label: target_label, dmabuf_filters: std::rc::Rc::new( - wayland_proxy::dmabuf::DmabufFilterList::new( + crate::wayland_proxy::dmabuf::DmabufFilterList::new( &input.dmabuf_allow, &input.dmabuf_deny, ), @@ -334,6 +335,7 @@ impl FilterPolicy { } /// Returns true if the policy allows this interface. + #[cfg(test)] pub fn is_allowed(&self, interface: &str) -> bool { self.lookup(interface).0 == GlobalAction::Allow } diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs index ca8b887f9..0ac22c5b5 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs @@ -5,7 +5,7 @@ use std::{ time::Duration, }; -use wayland_proxy::identity::ProxyIdentity; +use crate::wayland_proxy::identity::ProxyIdentity; pub use d2b_contracts_control::proxy_readiness::{ ProxyReadinessEvent, ProxyReadinessFailure, ProxyReadinessStage, }; From 70b78863cf53dd4a91a98f3e1de301654e6a4278 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:18:57 -0700 Subject: [PATCH 486/726] provider-system-core: enable the test-support feature in the bazel test library The crate's tests import its gated testing module; the bazel test-support library did not enable the feature and the test rules depended on the plain library, so the bazel build failed where cargo's required-features simply skipped the target. --- packages/d2b-provider-system-core/BUILD.bazel | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-system-core/BUILD.bazel b/packages/d2b-provider-system-core/BUILD.bazel index a4d2b1619..776ed48dc 100644 --- a/packages/d2b-provider-system-core/BUILD.bazel +++ b/packages/d2b-provider-system-core/BUILD.bazel @@ -28,6 +28,7 @@ d2b_rust_library( name = "d2b_provider_system_core_test_support", srcs = glob(["src/**/*.rs"], allow_empty = True), compile_data = ["Cargo.toml"], + crate_features = ["test-support"], crate_name = "d2b_provider_system_core", deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", @@ -40,7 +41,7 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_system_core", + ":d2b_provider_system_core_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -50,7 +51,7 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_system_core", + ":d2b_provider_system_core_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -60,7 +61,7 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_system_core", + ":d2b_provider_system_core_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) From e65888ec6eb59a0c16b60fc507ff2f4336091706 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 11:25:12 -0700 Subject: [PATCH 487/726] wave 2 integration: settle the crate-duplication and sandbox gaps the bazel graph exposes The secret-service tests took the plain session-unix alongside the feature-enabled one, so two builds of that crate met in one signature. The display binary needed its moved module in srcs and the contracts-control crate in deps. And the daemon runtime's worker spawn returns its result directly instead of wrapping it. --- packages/d2b-provider-credential-secret-service/BUILD.bazel | 4 ++-- packages/d2b-provider-display-wayland/BUILD.bazel | 3 ++- packages/d2bd-runtime/src/exec_session.rs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/d2b-provider-credential-secret-service/BUILD.bazel b/packages/d2b-provider-credential-secret-service/BUILD.bazel index 19e74cb23..ad49fedc8 100644 --- a/packages/d2b-provider-credential-secret-service/BUILD.bazel +++ b/packages/d2b-provider-credential-secret-service/BUILD.bazel @@ -159,7 +159,7 @@ d2b_rust_test( crate = ":d2b_provider_credential_secret_service_test_support", deps = [ "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", - "//packages/d2b-session-unix:d2b_session_unix", + "//packages/d2b-session-unix:d2b_session_unix_test_support", ], ) @@ -175,7 +175,7 @@ d2b_rust_test( "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", "//packages/d2b-provider-toolkit:d2b_provider_toolkit_test_support", "//packages/d2b-session:d2b_session", - "//packages/d2b-session-unix:d2b_session_unix", + "//packages/d2b-session-unix:d2b_session_unix_test_support", ":d2b_provider_credential_secret_service", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-display-wayland/BUILD.bazel b/packages/d2b-provider-display-wayland/BUILD.bazel index af26fb54c..49dd5594d 100644 --- a/packages/d2b-provider-display-wayland/BUILD.bazel +++ b/packages/d2b-provider-display-wayland/BUILD.bazel @@ -44,11 +44,12 @@ d2b_rust_library( d2b_rust_binary( name = "d2b-wayland-proxy", - srcs = ["src/bin/d2b-wayland-proxy.rs"], + srcs = ["src/bin/d2b-wayland-proxy.rs"] + glob(["src/wayland_proxy/**/*.rs"]), compile_data = ["Cargo.toml"], deps = [ ":d2b_provider_display_wayland", "//packages/d2b-contracts:d2b_contracts", + "//packages/d2b-contracts-control:d2b_contracts_control", ] + all_crate_deps(normal = True, cargo_only = True), ) diff --git a/packages/d2bd-runtime/src/exec_session.rs b/packages/d2bd-runtime/src/exec_session.rs index 5f8912f64..434e5a63e 100644 --- a/packages/d2bd-runtime/src/exec_session.rs +++ b/packages/d2bd-runtime/src/exec_session.rs @@ -957,7 +957,7 @@ pub fn spawn_session_worker(spawn: WorkerSpawn) -> std::io::Result std::io::Result Date: Fri, 25 Sep 2026 12:13:10 -0700 Subject: [PATCH 488/726] resource-api: treat an absent authored-metadata slice as the ordinary no-metadata row The wave's row stopped swallowing a malformed metadata slice, which is right, but it also made an absent one fatal - and absent is the ordinary shape a projection row carries, so the audio service reconcile rejected valid seeded rows. --- packages/d2b-resource-api/src/manager_backend.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index 20d0fe21e..8b4a679ea 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -747,8 +747,13 @@ fn render_envelope( .map_err(|_| envelope_invalid())?; return envelope.canonical_bytes().map_err(|_| envelope_invalid()); } - let authored: serde_json::Value = - serde_json::from_slice(metadata).map_err(|_| envelope_invalid())?; + // An absent authored-metadata slice is the ordinary no-metadata row; only + // bytes that fail to parse are a defect. + let authored: serde_json::Value = if metadata.is_empty() { + serde_json::Value::Null + } else { + serde_json::from_slice(metadata).map_err(|_| envelope_invalid())? + }; let field = |name: &str, fallback: serde_json::Value| { authored .get(name) From 47b3d6a622cf15d1143b719ffddb1798722405f4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 12:17:02 -0700 Subject: [PATCH 489/726] wave 2 gate reconciliation: ascii dashes, async-gate inventory, and the family-knowledge ratchet Two em dashes reached the ledger through worker report text. The async-gate inventory follows the wave's line shifts. The ratchet retires one exemption whose code the wave deleted and records two whose family-named error variants the wave typed. --- .../2026-09-24-rust-skills-audit/ledger.md | 4 +- packages/xtask/data/async-gate-inventory.json | 154 +++++++++--------- packages/xtask/src/provider_crate_policy.rs | 20 ++- 3 files changed, 92 insertions(+), 86 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index bb84a83aa..c59a0c6b3 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -308,7 +308,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-res` | | | | `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | | `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-r` | | | -| `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises — `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | +| `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises - `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | | `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | packages/d2b-provider-transport-azure-relay/contrast-zone-session/src/v3/role_binding.rs | | | | `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | | | | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | @@ -328,7 +328,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | | `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | | `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | needs-contract | U3 | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery recor | | -| `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired — the illegal Consumed/Expired-with-Some(psk) combination is now unco | | +| `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired - the illegal Consumed/Expired-with-Some(psk) combination is now unco | | | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | e53601c88 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | derive_private_runtime_scope and private_runtime_scope take ChildRole and use role.suffix(); the &str whitelist branch is gone. Callers incl. wayland-policy migrated. | | | `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 48a09184e..ae8848985 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -143,32 +143,32 @@ }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1030, + "line": 1034, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1047, + "line": 1051, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1060, + "line": 1064, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1081, + "line": 1085, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1085, + "line": 1089, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1108, + "line": 1112, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -183,77 +183,77 @@ }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1108, + "line": 1109, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1121, + "line": 1122, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1122, + "line": 1123, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1145, + "line": 1146, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1149, + "line": 1150, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1166, + "line": 1167, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1168, + "line": 1169, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1637, + "line": 1638, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1648, + "line": 1649, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1651, + "line": 1652, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1675, + "line": 1676, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1724, + "line": 1725, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1808, + "line": 1809, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1864, + "line": 1865, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1922, + "line": 1923, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -633,17 +633,17 @@ }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 642, + "line": 647, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 742, + "line": 747, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 743, + "line": 748, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -678,37 +678,37 @@ }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2426, + "line": 2452, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2437, + "line": 2463, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2438, + "line": 2464, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3229, + "line": 3255, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3239, + "line": 3265, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3344, + "line": 3370, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3706, + "line": 3732, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -818,22 +818,22 @@ }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 841, + "line": 830, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 852, + "line": 841, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 854, + "line": 843, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 858, + "line": 847, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -848,37 +848,37 @@ }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 508, + "line": 504, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 516, + "line": 512, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 524, + "line": 520, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 529, + "line": 525, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 530, + "line": 526, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 552, + "line": 548, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 557, + "line": 553, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1013,22 +1013,22 @@ }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 915, + "line": 917, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 1182, + "line": 1184, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 1210, + "line": 1212, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 1219, + "line": 1221, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1043,157 +1043,157 @@ }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1735, + "line": 1764, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1746, + "line": 1775, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1752, + "line": 1781, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1840, + "line": 1869, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1842, + "line": 1871, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 1844, + "line": 1873, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2185, + "line": 2214, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2306, + "line": 2335, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2324, + "line": 2353, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2334, + "line": 2363, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2354, + "line": 2383, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2370, + "line": 2399, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2383, + "line": 2412, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2386, + "line": 2415, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2397, + "line": 2426, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2407, + "line": 2436, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd-runtime/src/exec_session.rs", - "line": 2448, + "line": 2477, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 10730, + "line": 10786, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26164, + "line": 26253, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26561, + "line": 26650, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_plane_v3.rs", - "line": 6728, + "line": 6723, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 2508, + "line": 2522, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 7510, + "line": 7534, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 8667, + "line": 8685, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1602, + "line": 1632, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1650, + "line": 1680, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1675, + "line": 1705, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2110, + "line": 2136, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2497, + "line": 2525, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2530, + "line": 2558, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2586, + "line": 2614, "reason": "synchronous lock acquisition, no await while the guard is held" }, { diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index 6b3300fa3..0e49e4508 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -2471,12 +2471,6 @@ const SHARED_FAMILY_KNOWLEDGE_RATCHET: &[SharedFamilyKnowledgeExemption] = &[ family: "device-usbip", retires_with: "permanent: shared controller-session crate; no shared crate may depend on a provider crate", }, - SharedFamilyKnowledgeExemption { - module: "packages/d2b-core-controller/src/coordinator.rs", - token: "usbip", - family: "device-usbip", - retires_with: "permanent: shared controller-session crate; no shared crate may depend on a provider crate", - }, SharedFamilyKnowledgeExemption { module: "packages/d2b-contracts/src/security_key.rs", token: "usbip", @@ -3534,6 +3528,18 @@ const SHARED_FAMILY_KNOWLEDGE_RATCHET: &[SharedFamilyKnowledgeExemption] = &[ family: "activation-nixos", retires_with: "permanent: v3 contract files are shared wire vocabulary consumed by the bus, broker, daemon, and core crates; relocating them into a provider crate would add a shared-to-provider dependency edge, which the dependency-direction detector at provider_crate_policy.rs:6999 refuses", }, + SharedFamilyKnowledgeExemption { + module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", + token: "network_local", + family: "network-local", + retires_with: "permanent: the unsafe-local workload limits are shared wire vocabulary whose error variants are family-named; no shared crate may depend on a provider crate", + }, + SharedFamilyKnowledgeExemption { + module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", + token: "volume_local", + family: "volume-local", + retires_with: "permanent: the unsafe-local workload limits are shared wire vocabulary whose error variants are family-named; no shared crate may depend on a provider crate", + }, SharedFamilyKnowledgeExemption { module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", token: "nixos", @@ -8707,7 +8713,6 @@ const PROVIDER_FAMILY_KNOWLEDGE_EXEMPTIONS: &[ProviderFamilyKnowledgeExemption] ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-supervisor", module: "packages/d2b-provider-supervisor/src/broker.rs", token: "system_minijail", family: "system-minijail", reason: "the supervisor dispatches runner roles" }, ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-supervisor", module: "packages/d2b-provider-supervisor/src/broker.rs", token: "system_systemd", family: "system-systemd", reason: "the supervisor dispatches runner roles" }, ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-system-core", module: "packages/d2b-provider-system-core/src/host.rs", token: "audio_pipewire", family: "audio-pipewire", reason: "the system-core host names the audio-pipewire workload kind" }, - ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-user", module: "packages/d2b-provider-user/src/driver.rs", token: "system_core", family: "system-core", reason: "the user error-code strings keep the system-core prefix stable" }, ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-user", module: "packages/d2b-provider-user/src/probe.rs", token: "system_core", family: "system-core", reason: "the user probe implements the system-core-declared discovery port whose error type is system-core's" }, ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-user", module: "packages/d2b-provider-user/src/test_support.rs", token: "system_core", family: "system-core", reason: "test-support fixture provider names the system-core provider" }, ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-volume", module: "packages/d2b-provider-volume/src/driver.rs", token: "volume_local", family: "volume-local", reason: "the volume provider's own name const uses its sibling family's id" }, @@ -8719,6 +8724,7 @@ const PROVIDER_FAMILY_KNOWLEDGE_EXEMPTIONS: &[ProviderFamilyKnowledgeExemption] ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-wayland-policy", module: "packages/d2b-provider-wayland-policy/src/vocabulary.rs", token: "shell_terminal", family: "shell-terminal", reason: "family-qualified resource type names the shell-terminal family's type" }, ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-wayland-session", module: "packages/d2b-provider-wayland-session/src/wayland_session.rs", token: "display_wayland", family: "display-wayland", reason: "the wayland-session provider's interface types name the display-wayland surface" }, ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-zone", module: "packages/d2b-provider-zone/src/zone_status.rs", token: "system_core", family: "system-core", reason: "the zone status emitter names the system-core session phases" }, + ProviderFamilyKnowledgeExemption { crate_name: "d2b-provider-zone", module: "packages/d2b-provider-zone/src/lib.rs", token: "system_core", family: "system-core", reason: "the crate re-exports the status emitter whose name states the system-core session phases" }, ]; fn provision_family_exemptions() -> Vec { From 6f80a58709a36323e07590c082e8dd769afd9a95 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 12:20:20 -0700 Subject: [PATCH 490/726] generate: refresh the committed outputs the gate-reconciliation changes feed The ratchet and inventory edits move policy inputs; regenerating keeps the flake evaluation's committed-output comparison honest. --- ...2-001-chore-post-plan-cleanup-wave-plan.md | 315 ++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md diff --git a/docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md b/docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md new file mode 100644 index 000000000..0605d9b22 --- /dev/null +++ b/docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md @@ -0,0 +1,315 @@ +--- +title: Post-Plan Cleanup Wave: Gates, Dossiers, CI, and Bazel Variant Graph - Plan +type: chore +date: 2026-09-22 +artifact_contract: ce-unified-plan/v1 +artifact_readiness: implementation-ready +product_contract_source: ce-plan-bootstrap +execution: code +--- + +# Cleanup Wave: Gates, Dossiers, CI, and Bazel Variant Graph - Plan + +## Goal Capsule + +- Objective: land the eight backlog cleanups behind issues #584, #585, #586, #587, #589, #590, #591, #592. Each issue's acceptance criteria define its unit. +- Authority hierarchy: the eight GitHub issues and their decision comments are the authority. Where an issue cites a stale path, the current tree wins (recorded in KTD7). +- Settled decisions carried from the issue threads: retire `microvm.*` outright with no compat shim (KTD1, user-directed); fix the Bazel variant graph at its source rather than mitigate (KTD3, user-directed); make the security scan a required check (KTD5, user-directed). +- Stop conditions: every unit's verification passes on the repository's own gates; any unit that cannot converge (for example, the #587 investigation producing an environmental disposition) reports evidence instead of forcing a fix. +- Execution profile: one implementation-ready code plan; units land as independent reviewed PRs in dependency order. + +--- + +## Product Contract + +### Summary + +The v3 control-plane rewrite left eight residue classes: a compatibility option namespace that no longer serves anyone, documentation and goldens pinning retired refusal contracts, a census invocation drifted from its documented contract, a scanner blind to the lock shape it was built to catch, provider dossiers citing deleted files, a daemon test surface excluded from CI, a security scan whose findings cannot block a merge, and one live bug whose cause is unestablished. This wave closes each residue class at its source. + +### Problem Frame + +Each issue is a half-landed cleanup or an unobserved defect: code deleted without its docs and goldens (#591), a namespace shim surviving a removal that was supposed to be total (#592), a scanner that cannot see the exact shape it was built to catch (#590), a census invocation that contradicts its documented contract and truncates its diagnostics (#585), a gate fed stale inputs (#589), a build exclusion that hides test failures (#584), an advisory security scan (#586), and a failing identity read whose reported cause is disproved (#587). Individually small; together they erode trust in the gates the framework relies on. + +### Requirements + +- R1. No `microvm.*` option or option reference survives in `nixos-modules/` framework files, templates, examples, or Rust doc comments; the VM runner API lives under the d2b-owned namespace per KTD1, and the retirement is recorded in the ADR 0018 follow-up, the changelog, and the v1.x migration notes. +- R2. The retired Tier-0 refusal contract is absent from docs, the CLI contract coverage table, the golden generator, and the committed goldens; `single-writer-conflict` remains only on its live surface (packages/d2b-provider-volume-local/src/error.rs:103). +- R3. The async-gate fails a planted method-call lock acquisition inside an `async fn` in a covered root; the conservative-shape escape hatch is documented; the Cargo.toml comment and the gate's own docs state the same enforcement reality. +- R4. Provider dossiers under `docs/specs/providers/` reference only files and crates that exist in the tree, and the policy gate fails a dossier that cites a deleted file or a non-existent crate. +- R5. The systemd identity-read failure's root cause is established with captured evidence (not assumed); the fix lands at the correct layer with a regression test, or a documented disposition with evidence replaces the fix if the failure is environmental. +- R6. In-tree part (mandatory, this wave): a security-scan job runs on pull requests and is wired into the aggregate `check` needs list so a scan failure fails the aggregate. Enforcement part (external): the scan's result is a required check on the protected branch. An access-denied handoff on the enforcement part records an explicit external blocker - it does not satisfy the requirement; the PR and tracking issue carry the named blocker until someone with branch-protection access completes it. The scan and its blocking status are documented in docs/contributing/workflow.md with an AGENTS.md pointer. +- R7. The census clippy invocation byte-matches the documented contract (or the manifest comment is updated in the same change); a planted compile error surfaces the first real diagnostic; a planted `await_holding_lock` site does not fail the census off the clippy-run error path; the module doc comment matches the manifest level. +- R8. `bazel build //packages/d2bd:all-tests` succeeds at pristine base; d2bd's `all-tests` appears in `rust-main-packages`; its per-target clippy tests ride Layer-1; the exclusion comment is deleted; a membership guard fails when any per-package `all-tests` aggregate is absent from the Layer-1 suite list or carries an excluding tag - the guard's input is suite membership, not a mutable exclusion list. + +### Scope Boundaries + +- In scope: exactly the eight issues above, including the in-tree workflow half of #586 and the branch-protection enforcement attempt it requires. +- Deferred to follow-up work: the other TODO.md entries the issues name only as context (devShell absence, schema drift, USBIP guest-attach, NFS notes) are not part of this wave. +- Outside this wave's identity: no new feature work, no new linters or formatters beyond the gates this plan modifies, no branch-protection settings change attempted without someone holding settings access. + +### Outstanding Questions + +- None blocking. The #587 investigation may resolve to a documented environmental disposition; that is an accepted outcome per its issue, not a blocker. + +--- + +## Planning Contract + +### Key Technical Decisions + +- KTD1. Retire the `microvm.*` option namespace in one change with no compatibility shim: `options.microvm` is deleted, every in-tree consumer migrates to the d2b-owned namespace in the same commit, and the changelog plus ADR 0018 follow-up record the break. (session-settled: user-directed - chosen over a `lib.warn` deprecation window: the issue decision accepts a deliberate breaking change.) +- KTD2. Retire the shim only together with its read surface and containment lint: `nixos-modules/lib.nix` (the `vmRunner` helper reading `config.d2b._computed..config.microvm or { }`, consumed by `assertions.nix`) and `nixos-modules/guest-closures.nix` (the `microvm = guestConfig.microvm or { }` fallback reads) both key on the namespace, so deleting the shim before migrating these readers and the containment lint makes guest configs silently fall back to 1 vCPU / 512 MiB defaults or the gate pass silently. Writers, readers, lint, and host-integration fixtures migrate in one commit. +- KTD3. Fix the d2bd dual-rlib condition at its source by unifying the test-support variant graph so a test target links exactly one rlib per crate identity, following the existing `d2b_core` / `d2b_core_test_support` pattern in `packages/d2b-core/BUILD.bazel` (crate_features `test-support`, cfg-gated test_support module). (session-settled: user-directed - chosen over mitigation or continued exclusion: the exclusion hid four required-field failures, a merge-ref compile error, and two stale build references in one day.) +- KTD4. Arm method-call lock detection in the async-gate as a conservative shape flag with a documented escape hatch, not receiver-type resolution: the scanner flags a lock method call inside an `async fn` not followed by `.await` (awaited tokio lock sites are legitimate), and the hatch is a source-level marker honored by the scanner and recorded in a named inventory file - the gate's existing "no violation allowlist" statement is rewritten, not contradicted. The inventory covers every flagged shape in covered roots, production and test code, derived from the scanner's own output. The Cargo.toml census block and the gate doc are reconciled in the same change. +- KTD5. The security scan becomes a required check through both halves: a committed workflow job wired into the `pr-l1-static-fast.yml` aggregate `check` needs list (in-tree, unconditional), plus the branch-protection setting that marks it required. The settings half is a declared hard dependency needing an account with branch-protection access; the plan attempts it via `gh` and stops at the documented handoff if access is denied. (session-settled: user-directed - chosen over in-tree-only with an open question: the user directed full enforcement attempt.) +- KTD6. The #591 removal is one atomic commit: docs rows and anchors, the coverage table rows, the golden generator rows, and the regenerated committed goldens land together, because the fixtures-proofs gate closes coverage against goldens and a partial removal fails it. +- KTD7. The #587 investigation unit targets the live read sites only: the issue's cited broker path (`d2b-broker/src/ops/systemd.rs`) does not exist; the live reads are `packages/d2b-unsafe-local-helper/src/systemd.rs` (user-scope identity, 2s ready timeout, 20ms retries) and `packages/d2b-provider-process-systemd` (identity/operations). The stale-path correction is recorded here rather than re-deriving it at execution time. +- KTD8. Provider dossiers are updated to the current tree rather than marked historical: they describe the live Zone-native provider architecture, so a status header would hide drift the wave exists to remove. Wrong crate names (`d2b-provider-system-systemd` -> `d2b-provider-process-systemd`) and deleted-module citations are corrected in place. +- KTD9. The census clippy invocation is aligned to the documented contract (Cargo.toml:159-162): `run_clippy` passes `-W warnings -W clippy::disallowed_methods -W clippy::await_holding_lock -W clippy::await_holding_refcell_ref`, and the truncation fix keeps the first real diagnostic (file:line plus message) instead of the reversed last-15-stderr tail. + +### High-Level Technical Design + +```mermaid +flowchart TB + U5[U5 census contract fix] --> U6[U6 async-gate method-call arming] + U1[U1 microvm namespace retirement] --> U2[U2 comment + migration records] + U7[U7 d2bd variant graph unification] + U3[U3 Tier-0 contract removal] + U4[U4 dossier correction + scan extension] + U8[U8 security-scan required check] + U9[U9 systemd identity investigation] +``` + +Independent tracks: tooling gates (U5 -> U6), the Bazel variant graph (U7), the namespace retirement (U1 -> U2), doc/golden cleanup (U3, U4), CI wiring (U8), and the investigation (U9). No unit depends on another's files except U5 -> U6 (the census meter must be correct before arming new scanner detection against it) and U1 -> U2 (comment rewrites follow the namespace migration). + +### Assumptions + +- The scanner identity for #586 is the branch-protection-configured one described in the issue; if it cannot be identified from the repo, the workflow job wraps whatever scanner the owner names and the plan states that dependency. +- The #587 failure is reproducible on the current host via the helper's scope path; if it is not, the disposition path applies. + +--- + +## Implementation Units + +### U1. Retire the microvm option namespace + +- Goal: remove `options.microvm` and migrate every in-tree consumer to the d2b-owned namespace in one commit. +- Requirements: R1. Issue #592. Governs KTD1, KTD2. +- Dependencies: none. +- Files: + - nixos-modules/vm-options.nix (shim removal; hypervisor enum) + - nixos-modules/vm-guest-base.nix, nixos-modules/observability-vm.nix + - nixos-modules/guest-closures.nix (the `microvm = guestConfig.microvm or { }` fallback read) + - nixos-modules/lib.nix (the `vmRunner` helper reading `config.d2b._computed..config.microvm`, and the containment detector declaring `options.microvm`) + - nixos-modules/assertions.nix (containment lint consuming vmRunner) + - nixos-modules/components/graphics.nix, components/tpm.nix, components/video/guest.nix, components/observability/guest.nix + - packages/d2b-provider-device-tpm/nix/guest.nix, packages/d2b-provider-device-gpu/nix/guest.nix and its nix/video-guest.nix (+ their nix/tests/default.nix) - live microvm.* writers imported by the component files + - tests/host-integration/state-posture-contract.nix, tests/host-integration/runtime-cloud-hypervisor-guest-preflight.nix (per-VM microvm.storeOnDisk/storeDisk/shares writes) + - tests/unit/nix/cases/ consumers of the renamed options + - changelog.d/ fragment +- Approach: follow TODO.md's outline at the `Drop the microvm.* option namespace` entry (line ~346) and the ADR 0018 migration map (`microvm.*` -> `d2b.vms..runner.*`). Migrate writers, the read surfaces (`guest-closures.nix` fallback reads, `lib.nix` `vmRunner` accessor, `assertions.nix` probe), and the containment lint in the same commit. NOTE: the issues' cited paths (`host.nix`, `net.nix`, `processes-json.nix`, `components/audio/guest.nix`) no longer exist; the tree's current writers above win per the authority rule. Verify the ADR 0018 materialization path exists before relying on it. +- Test scenarios: + - Evaluating an example that sets only the new namespace produces no `microvm` option references and no warnings. + - The unit/nix case `tests/unit/nix/cases/net-vm-network.nix` still passes unchanged (the fire-walling invariant must not regress). + - A `grep -rn "microvm\." nixos-modules/ templates/ examples/ packages/ --include=*.nix --include=*.rs` over framework files, templates, examples, and Rust doc comments returns nothing after the change (ADR historical prose excepted). +- Verification: `make check` unit-nix cases pass; `make generate` regenerates committed artifacts cleanly. + +### U2. Rewrite microvm-era comments and record the namespace retirement + +- Goal: remove the fictional upstream dependency from prose and record the breaking change where the repo's contracts require it. +- Requirements: R1. Issue #592. +- Dependencies: U1. +- Files: + - ~20 nixos-modules framework files and 16 Rust files carrying "microvm.nix's cloud-hypervisor runner" framing (inventory via `grep -rn "microvm" packages/ nixos-modules/ docs/ --include=*.nix --include=*.rs` filtered to comments) + - docs/adr/0018-microvm-nix-removal.md (follow-up note: option namespace retired) + - docs/ migration notes (v1.x consumer migration section) + - TODO.md (close the entry at line ~346) + - changelog.d/ fragment (shared with U1 or its own) +- Approach: comments name the broker SpawnRunner path instead of an upstream microvm.nix runner. The ADR 0018 follow-up records that the option namespace (not just the flake input) is gone, with the in-tree migration map. +- Test scenarios: + - Test expectation: none - prose-only comments plus TODO/ADR/migration doc updates; correctness is covered by U1's gate runs. +- Verification: `grep -rn "microvm" docs/adr/0018-microvm-nix-removal.md` shows the follow-up; a repo-wide comment grep finds no "microvm.nix's runner" framing in live framework or Rust files. + +### U3. Remove the retired Tier-0 refusal contract from docs, coverage, and goldens + +- Goal: the CLI cannot emit `tier-0-legacy-uses-nixos-module` or the refusal-variant `single-writer-conflict`, and no doc, coverage row, generator branch, or committed golden claims it can. +- Requirements: R2. Issue #591. Governs KTD6. +- Dependencies: none. +- Files: + - docs/reference/error-codes.md (rows + anchors for both codes) + - docs/how-to/host-prepare.d/modules-and-devices.md (refusal claims) + - docs/reference/support-matrix.d/s4-tier-modules.md (refusal claims) + - packages/d2b/tests/cli_contract_coverage.rs (W3_ROWS tier-0 and single-writer refusal rows, lines ~536-553) + - tests/fixtures/gen-w3-cli-goldens.py (tier-0 branches, lines ~141-242) + - tests/golden/cli-output/host-check-tier-0-legacy-uses-nixos-module.{json,txt}, host-prepare-tier-0-legacy-uses-nixos-module.{json,txt}, host-destroy-tier-0-legacy-uses-nixos-module.{json,txt} + - tests/golden/cli-output/host-check-single-writer-conflict.{json,txt} and host-prepare-single-writer-conflict.{json,txt} (the refusal variants only) + - TODO.md (close the `Remove Tier-0 deployment-shape logic` entry, ~line 495) +- Approach: one atomic commit removes rows, anchors, generator branches, and goldens together, then regenerates via the fixture pipeline so the fixtures-proofs gate sees a consistent state. `single-writer-conflict` stays live at packages/d2b-provider-volume-local/src/error.rs:103; only the CLI refusal goldens that pin exit-78 outputs the CLI cannot produce are deleted. +- Test scenarios: + - `grep -rn "tier-0-legacy-uses-nixos-module" docs tests packages TODO.md` returns nothing. + - No refusal-variant `single-writer-conflict` entry remains in docs, the coverage table, the generator, or the CLI goldens (the volume-local provider mapping is the only live surface and its test stays green). + - The W3 closure test (`host_cli_error_golden_table_is_closed_and_complete`) passes with the reduced table. + - `make test-fixture-contracts` passes with regenerated goldens, proving the pipeline regenerates cleanly after the row removal. + - The volume-local provider error path still maps `SingleWriterConflict` to `single-writer-conflict` (its own tests stay green). +- Verification: `make test-unit` coverage tests pass; `make test-fixture-contracts` passes on the regenerated tree. + +### U4. Correct provider dossier references and extend the policy scan + +- Goal: dossiers cite the real tree, and the gate fails when they do not. +- Requirements: R4. Issue #589. Governs KTD8. +- Dependencies: none. +- Files: + - docs/specs/providers/ADR-046-provider-system-systemd.md (lines ~1296, 1351, 1361, 1468; crate name throughout) + - docs/specs/providers/ADR-046-provider-system-minijail.md (lines ~1583-1587) + - docs/specs/providers/*.md full sweep (the extended gate flags ~13 dossiers citing `d2b-priv-broker`, 3 citing `src/adoption.rs`, 1 citing `d2b-provider-system-systemd`; also docs/specs/ADR-046-*.md siblings carrying the same stale crate paths - decide with the gate glob, correcting the citation corpus the scan covers) + - packages/xtask/src/provider_crate_policy.rs (dangling-citation scan) + - changelog.d/ fragment +- Approach: correct crate names (`d2b-provider-process-systemd`, not `d2b-provider-system-systemd`) and deleted-module citations (`src/adoption.rs`; `d2b-priv-broker`; stale `d2bd/src/supervisor/*` paths). `d2b-realm-core` is LIVE (packages/d2b-realm-core exists; dossiers cite live files in it) - do not strip its citations. Extend the dangling-citation scan in `packages/xtask/src/provider_crate_policy.rs` from Rust-sources-only to also parse `Destination` / `Reuse path` / file-tree references in the dossier corpus and validate them against the tree; mentions behind an explicit historical marker stay legal. +- Test scenarios: + - A planted dossier citation of a deleted path fails the policy gate. + - A dossier citation of a live path (including packages/d2b-realm-core files) passes. + - `grep -rn "src/adoption.rs\|d2b-priv-broker\|d2b-provider-system-systemd" docs/specs` returns nothing (or only explicit historical markers). +- Verification: the provider-crate-policy gate runs green on the corrected dossiers and fails on a planted bad reference (test fixture). + +### U5. Fix the census clippy contract and diagnostics + +- Goal: the census clippy invocation matches the documented contract and its failures are actionable. +- Requirements: R7. Issue #585. Governs KTD9. +- Dependencies: none; must land before U6 so the meter is correct when the scanner is armed. +- Files: + - packages/xtask/src/blocking_census.rs (`run_clippy` ~761-791; module doc ~11-16) + - Cargo.toml census comment block (~158-163) if the byte-match reveals the doc itself needs the correction + - changelog.d/ fragment +- Approach: pass the documented de-escalation set (`-W warnings -W clippy::disallowed_methods -W clippy::await_holding_lock -W clippy::await_holding_refcell_ref`) so a stray lint counts instead of failing the gate; capture the full stderr and surface the first `file:line` diagnostic plus message on failure instead of the reversed last-15 tail; update the module doc comment from `allow` to the manifest's `deny` level. +- Test scenarios: + - `run_clippy` produces the exact flag sequence documented in Cargo.toml. + - A planted compile error in a covered crate reports the first diagnostic with file:line and message. + - A planted `await_holding_lock` site fails through the lint-counting path (counted), not the clippy-error path. + - A planted disallowed-method site likewise counts rather than erroring the gate. +- Verification: `make check-census` green; planted-error fixture test green. + +### U6. Arm async-gate method-call lock detection + +- Goal: the gate catches `m.lock()` on std::sync/parking_lot mutexes inside `async fn`, with the conservative shape and a documented escape hatch. +- Requirements: R3. Issue #590. Governs KTD4. +- Dependencies: U5. +- Files: + - packages/xtask/src/async_gate.rs (scanner, fixtures, doc comments) + - tests/tools/check-async-gate.sh (its "no violation allowlist" header must be rewritten with the new hatch contract) + - the named hatch inventory file this unit creates (single source-level marker format recorded there) + - packages/xtask/data/blocking-census-baseline.json (method-call rows updated together) + - Cargo.toml census comment block (~143-163) + - docs contributing gate prose that states the enforcement contract + - changelog.d/ fragment +- Approach: the scanner flags the conservative method-call shape - a lock/read/write method call inside an `async fn` NOT followed by `.await` (the `.await` exclusion is load-bearing: awaited `tokio::sync::Mutex::lock()` sites are legitimate and the census never sees them, since it counts only `clippy::disallowed_methods`). The escape hatch is a source-level marker the scanner honors, recorded in a named inventory file; the gate's "no violation allowlist" statement is rewritten to state the marker contract. The inventory covers EVERY method-call shape the armed scanner reports in the covered roots - production and test code (the gate scans tests like production code), not just the 33 census production sites. Derive the inventory from the scanner's own output over the default scan roots. The gate doc and the Cargo.toml comment state the same rule after the change. The qualified-form fixture stays green. +- Test scenarios: + - A planted `m.lock()` on a std::sync Mutex inside an `async fn` in a covered root fails `check-async-gate`. + - The same planted site with the documented source-level marker passes. + - A planted `m.lock().await` on a tokio Mutex passes (the `.await` exclusion). + - The qualified-path fixture still fails as before. + - A method-call lock site inside `#[tokio::test]` is flagged like production code (and passes only with the marker). + - The census baseline after U5 + U6 together is consistent with the scanner output (no row drift). +- Verification: `tests/tools/check-async-gate.sh` passes; planted-fixture gate test fails pre-fix and passes post-fix; `make check-census` green. + +### U7. Unify the d2bd test-support variant graph and re-include its tests + +- Goal: `bazel build //packages/d2bd:all-tests` green at pristine base; d2bd rejoins Layer-1 with its clippy gate. +- Requirements: R8. Issue #584. Governs KTD3. +- Dependencies: none. +- Files: + - packages/d2bd/BUILD.bazel + - packages/d2bd/Cargo.toml and BUILD-adjacent variant wiring following packages/d2b-core/BUILD.bazel:46-54 + - bazel/checks/BUILD.bazel (rust-main-packages inclusion; delete the exclusion comment at ~71-75) + - any volume/session/provider chains that pull `d2b_core_test_support` into the same link as `d2b_core` + - changelog.d/ fragment +- Approach: unify the variant graph so a test target links exactly one rlib per crate identity - the same mechanism d2b-core uses (`crate_features = ["test-support"]` on one rlib with a cfg-gated `test_support` module), applied down the volume/session/provider dependency chains that today produce `d2b_core` + `d2b_core_test_support` in one link. Re-include `//packages/d2bd:all-tests` in `rust-main-packages`; the per-target `_clippy` tests ride along. Add a guard test that fails when a target listed as excluded builds cleanly. +- Test scenarios: + - `bazel build //packages/d2bd:all-tests` green at pristine base. + - `bazel test //packages/d2bd:all-tests` green at pristine base. + - d2bd clippy targets green and present in the Layer-1 suite. + - A probe removing a per-package `all-tests` aggregate from the suite list (or tagging it out) fails the membership guard. + - The exclusion comment is gone from bazel/checks/BUILD.bazel. +- Verification: the named bazel commands at pristine base; `make check` includes the d2bd aggregate. + +### U8. Make the security scan a required check + +- Goal: a security finding on changed lines blocks the merge path; the in-tree workflow and the branch-protection setting both express it. +- Requirements: R6. Issue #586. Governs KTD5. +- Dependencies: none. +- Files: + - .github/workflows/pr-l1-static-fast.yml (new scan job in the aggregate `check` needs list) + - docs/contributing/workflow.md (scan and blocking status documented) + - AGENTS.md gates section pointer + - changelog.d/ fragment +- Approach: add a security-scan job that runs on pull requests, add it to the aggregate `check` job's `needs`, and set branch protection so its result is required on the protected branches. The branch-protection half is a hard dependency requiring settings access: attempt it via `gh api` with the credentials available in this environment; if the API is not reachable with the available authorization, record an explicit external blocker - name the exact required-check context to flip, open or annotate a tracking issue, and carry the blocker on the PR. Do not count the handoff as satisfying the enforcement outcome. External dependency: the scanner engine is not identifiable from the repo (the issue says so); once the owner names it, pin the exact action or command, its immutable version, required permissions, and the failure predicate that makes a finding fail the job; until named, the job wraps the named scanner as its first implementation step. +- Test scenarios: + - An end-to-end negative proof: a scratch PR carries a planted identifier-written-to-log violation; the scan job and the aggregate `check` both fail, and the job/context name matches what branch protection marks required. + - A clean branch triggers the scan job and merges without new maintainer steps. + - The workflow YAML is valid and the aggregate check fails when the scan job fails. +- Verification: workflow dry-run on a scratch branch with the planted violation observed failing; `gh api` probe of branch protection (or the recorded external blocker with the exact setting named); docs grep shows the documented blocking status. + +### U9. Investigate the systemd identity-read failure + +- Goal: establish the real cause of the failing identity read with captured evidence; fix at the correct layer with a regression test, or produce a documented disposition. +- Requirements: R5. Issue #587. Governs KTD7. +- Dependencies: none. +- Files: + - packages/d2b-unsafe-local-helper/src/systemd.rs (live read path: `query_scope`, `await_scope_identity`, 2s ready timeout, 20ms retries) + - packages/d2b-provider-process-systemd/src/operations.rs and src/lib.rs (conformance-side identity reads) + - packages/d2b-process-conformance/src/identity.rs + - a new regression test or a docs disposition note + - changelog.d/ fragment (if a fix lands) +- Approach: the issue's cited broker read site (`d2b-broker/src/ops/systemd.rs`) does not exist in the tree; discovery starts from the live helper and provider surfaces above. Reproduce against a real transient scope via the helper's scope path, capture the concrete zbus error (candidates per the issue: user-bus auth failure for the helper, InvocationID read before started state, broker-path METHOD_TIMEOUT, host environment quirk). Fix only at the established layer. No property-removal workaround, no fallback hashing, no optional-property reads. The environmental disposition requires a falsification matrix: exact NixOS and systemd versions, unit and credential configuration, reproduction command, and captured logs - the no-code disposition is valid only after the failure cannot reproduce inside that matrix. +- Execution note: investigation-first. Do not write the fix before the failing call and the concrete error are captured on the host. +- Test scenarios: + - The captured error and its reproduction command are recorded in the unit's output (evidence artifact). + - If a code fix lands: a regression test fails pre-fix and passes post-fix at the established layer. + - If environmental: the disposition document names the evidence, the probe commands, and the host condition. +- Verification: repro transcript exists; either the regression test fails without the fix and passes with it, or the disposition is committed with the evidence. + +--- + +## Verification Contract + +| Gate | Command | Applies to | +|---|---|---| +| Aggregate suite | `make check` | every unit | +| Focused unit tests | `make test-unit` | U3, U5, U6 | +| Nix unit cases | `make check` unit-nix cases (`net-vm-network.nix` unchanged) | U1 | +| Committed artifact regeneration | `make generate` | U1 | +| Bazel variant graph | `bazel build //packages/d2bd:all-tests`, `bazel test //packages/d2bd:all-tests` | U7 | +| Census | `make check-census` | U5, U6 | +| Async gate | `tests/tools/check-async-gate.sh` | U6 | +| Fixture contracts | `make test-fixture-contracts` | U3 | +| Policy gate | xtask provider-crate-policy run | U4 | +| Golden regeneration | regenerator under `tests/fixtures/gen-w3-cli-goldens.py` before committing | U3 | +| Changelog | fragment under `changelog.d/` per change | all units | + +No Bazel profile overrides anywhere; commands run exactly as documented. + +--- + +## Definition of Done + +- Every unit's verification commands pass on the repository's own configuration. +- `make check` is green with the d2bd tests and clippy targets included (U7 landed). +- `grep -rn "tier-0-legacy-uses-nixos-module" docs tests packages TODO.md` returns nothing. +- `grep -rn "microvm\." nixos-modules/ templates/ examples/ packages/ --include=*.nix --include=*.rs` returns nothing beyond historical ADR prose. +- The security scan job exists in the workflow and fails the aggregate `check` when a finding is reported; the branch-protection enforcement outcome is either set or carried as an explicit named external blocker (not counted as done). +- The #587 outcome is either a landed fix with a regression test or a documented disposition with captured evidence. +- Every change carries a changelog fragment under `changelog.d/`; no attribution markers anywhere; ASCII dashes only. +- Abandoned investigation paths and scratch scaffolding from any unit are removed before the wave lands. + +--- + +## Sources / Research + +- Issues #584, #585, #586, #587, #589, #590, #591, #592 (decision comments included). +- TODO.md entries: `Drop the microvm.* option namespace` (line ~346 outline) and the d2bd dual-rlib note. +- docs/adr/0018-microvm-nix-removal.md (migration map `microvm.*` -> `d2b.vms..runner.*`); docs/adr/0015-daemon-only-clean-break.md. +- Cargo.toml census contract comment (lines ~158-163); packages/xtask/src/async_gate.rs; packages/xtask/src/blocking_census.rs (run_clippy ~761-791); packages/xtask/src/provider_crate_policy.rs (dangling-citation scan, Rust-only today). +- packages/d2b/tests/cli_contract_coverage.rs (W3_ROWS, ~536-553); tests/fixtures/gen-w3-cli-goldens.py; tests/golden/cli-output/ committed goldens. +- packages/d2b-unsafe-local-helper/src/systemd.rs; packages/d2b-provider-process-systemd (identity reads); packages/d2b-process-conformance/src/identity.rs. +- packages/d2bd/BUILD.bazel (dual-rlib shape at ~238-284) and packages/d2b-core/BUILD.bazel (variant reference pattern at ~46-54); bazel/checks/BUILD.bazel exclusion at ~71-75. +- .github/workflows/pr-l1-static-fast.yml (aggregate `check` needs list). +- nixos-modules/assertions.nix namespace-containment lint; nixos-modules/vm-evaluator.nix read path. From e83a1e5007346696c6eaf157916d3bfc07777748 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 12:42:18 -0700 Subject: [PATCH 491/726] nix: resolve the flake runfile to the real workspace path The flake-eval checks derive the repository root from the //:flake.nix runfile. In the runfiles-tree layout that runfile is a symlink into the Bazel output tree, so the plain-path flake reference pointed nix at a path under bazel-out/. Nix walks up from there, finds the execroot's .git mirror, declares it the repository, and rejects the untracked flake.nix. Resolve the runfile to the real workspace file first, so a direct bazel test of these targets works without D2B_REPO_ROOT. --- bazel/checks/nix/defs.bzl | 5 +++++ changelog.d/fix-nix-flake-eval-check.md | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 changelog.d/fix-nix-flake-eval-check.md diff --git a/bazel/checks/nix/defs.bzl b/bazel/checks/nix/defs.bzl index b486cc86b..d959e2488 100644 --- a/bazel/checks/nix/defs.bzl +++ b/bazel/checks/nix/defs.bzl @@ -59,6 +59,11 @@ NIX_BIN=$(runfile "__NIX_KEY__") PYTHON_BIN=$(runfile "__PYTHON_KEY__") PEAK_RSS=$(runfile "__PEAK_KEY__") FLAKE_PATH=$(runfile "__FLAKE_KEY__") +# The runfile can be a symlink into the Bazel output tree (runfiles tree +# layout). Resolve it to the real workspace file so nix never receives a +# path under bazel-out/, which its flake source rules refuse inside a git +# repository. +FLAKE_PATH=$(readlink -f -- "$FLAKE_PATH") ROOT=${FLAKE_PATH%/flake.nix} if [ "$ROOT" = "$FLAKE_PATH" ]; then ROOT=. diff --git a/changelog.d/fix-nix-flake-eval-check.md b/changelog.d/fix-nix-flake-eval-check.md new file mode 100644 index 000000000..18665e9e1 --- /dev/null +++ b/changelog.d/fix-nix-flake-eval-check.md @@ -0,0 +1,8 @@ +### Fixed + +- The Bazel flake-evaluation checks (`flake-eval-x86`, `flake-eval-aarch64`, + `flake-eval-x86-outputs`, and the `realized-*` variants) now resolve the + flake runfile to the real workspace path before handing it to nix, so the + checks pass when run directly with `bazel test` instead of only through the + Makefile wrappers. Previously the runfiles-tree layout placed the flake + under `bazel-out/`, where nix's git-tracking check rejected it as untracked. \ No newline at end of file From 10923b65ea6a655171f84637dbe86e2d117896ee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:19:22 -0700 Subject: [PATCH 492/726] d2b-audit: parse segment records from the read buffer scan_chain_state converted each JSONL line to a String before parsing; parse straight from the read bytes with serde_json::from_slice, matching segment_tail_hash and dropping one allocation per record during the open-time scan. --- changelog.d/w3-02-audit-jsonl-parse.md | 6 ++++++ packages/d2b-audit/src/sink.rs | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 changelog.d/w3-02-audit-jsonl-parse.md diff --git a/changelog.d/w3-02-audit-jsonl-parse.md b/changelog.d/w3-02-audit-jsonl-parse.md new file mode 100644 index 000000000..6c1d16ad8 --- /dev/null +++ b/changelog.d/w3-02-audit-jsonl-parse.md @@ -0,0 +1,6 @@ +### Changed + +- d2b-audit: the open-time chain-state scan now parses segment records + straight from the read buffer with `serde_json::from_slice` instead of + converting each line to a `String` first, dropping one allocation per + record during sink startup. \ No newline at end of file diff --git a/packages/d2b-audit/src/sink.rs b/packages/d2b-audit/src/sink.rs index 783b10aaf..e9adbf643 100644 --- a/packages/d2b-audit/src/sink.rs +++ b/packages/d2b-audit/src/sink.rs @@ -409,8 +409,7 @@ fn scan_chain_state(directory: &Path) -> Result { ) .map_err(|_| AuditSinkError::ChainMismatch)? { - let line = String::from_utf8(bytes).map_err(|_| AuditSinkError::ChainMismatch)?; - let record = serde_json::from_str::(&line) + let record = serde_json::from_slice::(&bytes) .map_err(|_| AuditSinkError::ChainMismatch)?; record .verify(&previous) From fbcf5d1f5ea306f2f9fd7a0a1fbf5f7f88d77fc6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:19:57 -0700 Subject: [PATCH 493/726] d2b-broker-composition: drop refusal-wording pin and right-size admit test --- changelog.d/w3-07-broker-composition-tests.md | 4 ++++ packages/d2b-broker-composition/src/seam.rs | 20 ++++--------------- 2 files changed, 8 insertions(+), 16 deletions(-) create mode 100644 changelog.d/w3-07-broker-composition-tests.md diff --git a/changelog.d/w3-07-broker-composition-tests.md b/changelog.d/w3-07-broker-composition-tests.md new file mode 100644 index 000000000..de07156ad --- /dev/null +++ b/changelog.d/w3-07-broker-composition-tests.md @@ -0,0 +1,4 @@ +### Fixed + +- The d2b-broker-composition routing-refusal test no longer pins the refusal's Display wording: its assertion now checks the refusal variant and class, so rephrasing the message text cannot fail the suite. +- A composition seam test that claimed to exercise an admitted-without-handler startup invariant leg now asserts only what the committed catalog can exercise this pass - the empty admitted set with nothing registered - so the suite documents the actual reachable behavior instead of a discarded fixture. diff --git a/packages/d2b-broker-composition/src/seam.rs b/packages/d2b-broker-composition/src/seam.rs index 62b6a17fa..eb5840ca4 100644 --- a/packages/d2b-broker-composition/src/seam.rs +++ b/packages/d2b-broker-composition/src/seam.rs @@ -552,7 +552,6 @@ mod tests { .. } )); - assert!(format!("{refusal}").contains("forward carrier")); } #[test] @@ -749,21 +748,10 @@ mod tests { } #[test] - fn an_unregistered_admitted_operation_fails_the_startup_invariant() { - // The invariant is not vacuous: whenever the rule admits a - // committed row, the composition root must register its handler - // before the broker serves. The fixture row stands in for that - // future registration: declaring it to the envelope and then - // asserting the invariant demands its handler tests the - // check's legs (registered-for-forwarded fails, admitted- - // without-handler fails) under fail-closed semantics. - // - // The committed catalog admits nothing this pass, so only the - // registered-for-forwarded leg is reachable today; the - // admitted-without-handler leg is pinned by the fixture row the - // moment the rule's admitted set is no longer empty. + fn the_admitted_set_stays_empty_with_nothing_registered() { + // The committed catalog admits nothing this pass, so with nothing + // registered the startup routing invariant passes: there is no + // unadmitted handler to flag and no admitted row missing one. assert!(verify_startup_routing(&[]).is_ok()); - let _ = register_declared_handlers(&[fixture_declaration()]) - .expect("the fixture admits"); } } From b80491dde64fef7a3cec62b9f019c413d665c270 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:20:27 -0700 Subject: [PATCH 494/726] d2b-broker: match pidfd reconciliation error variant The handoff test asserted the Display string ("start-time drifted") instead of the error variant, so a variant or payload rename would slip through. Match PidfdOpError::ReconciliationStartTimeMismatch with the drifted pid and start times, like the real-spawner test does. --- changelog.d/w3-05-broker-pidfd-test.md | 3 +++ .../d2b-broker/tests/pidfd_handoff_scm_rights.rs | 15 +++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 changelog.d/w3-05-broker-pidfd-test.md diff --git a/changelog.d/w3-05-broker-pidfd-test.md b/changelog.d/w3-05-broker-pidfd-test.md new file mode 100644 index 000000000..9b2d30f3a --- /dev/null +++ b/changelog.d/w3-05-broker-pidfd-test.md @@ -0,0 +1,3 @@ +### Fixed + +- The broker pidfd handoff test now asserts the typed reconciliation refusal (`ReconciliationStartTimeMismatch`, including the drifted pid and start times) instead of matching the human-readable error string, so the test fails when the error variant or its payload changes. \ No newline at end of file diff --git a/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs b/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs index acde7bd27..26aef5650 100644 --- a/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs +++ b/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs @@ -22,7 +22,7 @@ use std::os::fd::AsRawFd; use d2b_broker::fd_passing::{recv_fds, send_fds}; use d2b_broker::ops::pidfd::test_harness::FakePidfdSpawner; -use d2b_broker::ops::pidfd::{PidfdPayload, PidfdSpawner, assert_cloexec}; +use d2b_broker::ops::pidfd::{PidfdOpError, PidfdPayload, PidfdSpawner, assert_cloexec}; use nix::fcntl::{FcntlArg, FdFlag, fcntl}; use nix::sys::socket::{AddressFamily, SockFlag, SockType, socketpair}; @@ -87,9 +87,12 @@ fn reconciliation_refuses_start_time_drift() { let err = s .reconcile_drift(4242, StartTime(1_000_000), StartTime(2_000_000)) .unwrap_err(); - let msg = err.to_string(); - assert!( - msg.contains("start-time drifted"), - "unexpected error: {msg}" - ); + match err { + PidfdOpError::ReconciliationStartTimeMismatch { + pid: 4242, + expected: 1_000_000, + observed: 2_000_000, + } => {} + other => panic!("expected start-time drift, got {other:?}"), + } } From 1ff8e6a8c97129713019f8bcf42ae922011c74f1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:21:26 -0700 Subject: [PATCH 495/726] d2b-contracts-control: pin the workload op wire shape with a round-trip test WorkloadOp/WorkloadOpResponse (feature-negotiated v3 operations dispatched by the daemon composition layer) had no wire-shape or round-trip coverage, unlike every sibling op family. Mirror audio_public_wire_json_shape_is_stable for List/Status/LauncherExec: pin the kind/op tags, camelCase renames, canonical target encoding, and the launcher item type rename, and round-trip each request and response through PublicRequest/PublicResponse. --- .../w3-08-contracts-control-wire-test.md | 3 + .../d2b-contracts-control/src/public_wire.rs | 159 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 changelog.d/w3-08-contracts-control-wire-test.md diff --git a/changelog.d/w3-08-contracts-control-wire-test.md b/changelog.d/w3-08-contracts-control-wire-test.md new file mode 100644 index 000000000..36f268c00 --- /dev/null +++ b/changelog.d/w3-08-contracts-control-wire-test.md @@ -0,0 +1,3 @@ +### Changed + +- Added a wire-shape and round-trip test for the workload operation family (`WorkloadOp` List/Status/LauncherExec and `WorkloadOpResponse`) in the contracts-control crate, pinning the `kind`/`op` tags, camelCase field renames, and canonical target encoding so future DTO edits cannot silently break version-3 peers. \ No newline at end of file diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index 54c260d37..a4cb196eb 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -3725,6 +3725,165 @@ mod tests { assert_eq!(value["payload"]["result"]["state"]["level"], 50); } + #[test] + fn workload_public_wire_json_shape_is_stable() { + use super::{ + GraphicalLaunchPosture, LauncherExecArgs, LauncherExecDisposition, LauncherExecResult, + PublicRequest, PublicResponse, WorkloadAvailability, WorkloadListArgs, + WorkloadListResult, WorkloadOp, WorkloadOpResponse, WorkloadPublicSummary, + WorkloadStatusArgs, WorkloadStatusResult, + }; + use d2b_contracts::{ + capability::CapabilitySet, + ids::{OperationId, RealmId, WorkloadId}, + realm::RealmPath, + token::ProtocolToken, + workload::{ + DisplayEnvironmentPosture, EnvironmentPosture, ExecutionIdentityPosture, + IsolationPosture, LauncherIcon, LauncherItemKind, LauncherItemSummary, + SessionPersistencePosture, WorkloadExecutionPosture, WorkloadProviderKind, + WorkloadState, + }, + workload_identity::{WorkloadIdentity, WorkloadTarget}, + }; + + let target = WorkloadTarget::parse("builder.dev.d2b").expect("valid target"); + let item_id = ProtocolToken::parse("launch-item-1").expect("valid token"); + let operation_id = OperationId::parse("op-1").expect("valid operation id"); + let identity = WorkloadIdentity::new( + WorkloadId::parse("builder").expect("valid workload id"), + RealmId::parse("dev").expect("valid realm id"), + RealmPath::new(vec![RealmId::parse("dev").expect("valid realm id")]) + .expect("valid realm path"), + target.clone(), + ); + let summary = WorkloadPublicSummary { + identity, + provider_kind: WorkloadProviderKind::LocalVm, + state: WorkloadState::Running, + execution_posture: WorkloadExecutionPosture { + isolation: IsolationPosture::VirtualMachine, + environment: EnvironmentPosture::RuntimeManaged, + display_environment: DisplayEnvironmentPosture::NotApplicable, + execution_identity: ExecutionIdentityPosture::WorkloadUser, + session_persistence: SessionPersistencePosture::RuntimeManaged, + }, + availability: WorkloadAvailability::Ready, + graphical_posture: GraphicalLaunchPosture::NotApplicable, + capabilities: CapabilitySet::empty(), + launcher_items: vec![LauncherItemSummary { + id: item_id.clone(), + name: "Developer Shell".to_owned(), + icon: LauncherIcon::default(), + kind: LauncherItemKind::Exec, + graphical: false, + capabilities: CapabilitySet::empty(), + }], + default_item_id: Some(item_id.clone()), + }; + + // List request with an optional realm filter. + let list = PublicRequest::Workload(WorkloadOp::List(WorkloadListArgs { + realm: Some("dev".to_owned()), + })); + let value = serde_json::to_value(&list).expect("workload list serializes"); + assert_eq!(value["kind"], "workload"); + assert_eq!(value["payload"]["op"], "list"); + assert_eq!(value["payload"]["args"]["realm"], "dev"); + let decoded: PublicRequest = serde_json::from_value(value).expect("workload list decodes"); + assert_eq!(decoded, list); + + // Realm-less list request omits the optional field. + let all = PublicRequest::Workload(WorkloadOp::List(WorkloadListArgs { realm: None })); + let value = serde_json::to_value(&all).expect("realm-less list serializes"); + assert!(value["payload"]["args"].get("realm").is_none()); + let decoded: PublicRequest = serde_json::from_value(value).expect("realm-less list decodes"); + assert_eq!(decoded, all); + + // Status request: the target travels as the canonical wire address. + let status = PublicRequest::Workload(WorkloadOp::Status(WorkloadStatusArgs { + target: target.clone(), + })); + let value = serde_json::to_value(&status).expect("workload status serializes"); + assert_eq!(value["payload"]["op"], "status"); + assert_eq!(value["payload"]["args"]["target"], "builder.dev.d2b"); + let decoded: PublicRequest = serde_json::from_value(value).expect("workload status decodes"); + assert_eq!(decoded, status); + + // LauncherExec request. + let exec = PublicRequest::Workload(WorkloadOp::LauncherExec(LauncherExecArgs { + target: target.clone(), + item_id: item_id.clone(), + operation_id: operation_id.clone(), + })); + let value = serde_json::to_value(&exec).expect("launcher exec serializes"); + assert_eq!(value["payload"]["op"], "launcherExec"); + assert_eq!(value["payload"]["args"]["target"], "builder.dev.d2b"); + assert_eq!(value["payload"]["args"]["itemId"], "launch-item-1"); + assert_eq!(value["payload"]["args"]["operationId"], "op-1"); + let decoded: PublicRequest = serde_json::from_value(value).expect("launcher exec decodes"); + assert_eq!(decoded, exec); + + // List response with one inventory row. + let list_response = + PublicResponse::Workload(WorkloadOpResponse::List(WorkloadListResult { + workloads: vec![summary.clone()], + })); + let value = + serde_json::to_value(&list_response).expect("workload list response serializes"); + assert_eq!(value["kind"], "workload"); + assert_eq!(value["payload"]["op"], "list"); + let row = &value["payload"]["result"]["workloads"][0]; + assert_eq!(row["identity"]["workloadId"], "builder"); + assert_eq!(row["identity"]["realmId"], "dev"); + assert_eq!(row["identity"]["canonicalTarget"], "builder.dev.d2b"); + assert_eq!(row["providerKind"], "local-vm"); + assert_eq!(row["state"], "running"); + assert_eq!(row["executionPosture"]["isolation"], "virtual-machine"); + assert_eq!(row["availability"], "ready"); + assert_eq!(row["graphicalPosture"], "not-applicable"); + assert_eq!(row["launcherItems"][0]["id"], "launch-item-1"); + assert_eq!(row["launcherItems"][0]["type"], "exec"); + assert_eq!(row["defaultItemId"], "launch-item-1"); + let decoded: PublicResponse = + serde_json::from_value(value).expect("workload list response decodes"); + assert_eq!(decoded, list_response); + + // Status response. + let status_response = PublicResponse::Workload(WorkloadOpResponse::Status(Box::new( + WorkloadStatusResult { + workload: summary.clone(), + }, + ))); + let value = + serde_json::to_value(&status_response).expect("workload status response serializes"); + assert_eq!(value["payload"]["op"], "status"); + assert_eq!(value["payload"]["result"]["workload"]["state"], "running"); + let decoded: PublicResponse = + serde_json::from_value(value).expect("workload status response decodes"); + assert_eq!(decoded, status_response); + + // LauncherExec response. + let exec_response = PublicResponse::Workload(WorkloadOpResponse::LauncherExec( + LauncherExecResult { + target, + item_id, + operation_id, + disposition: LauncherExecDisposition::Committed, + }, + )); + let value = + serde_json::to_value(&exec_response).expect("launcher exec response serializes"); + assert_eq!(value["payload"]["op"], "launcherExec"); + assert_eq!(value["payload"]["result"]["target"], "builder.dev.d2b"); + assert_eq!(value["payload"]["result"]["itemId"], "launch-item-1"); + assert_eq!(value["payload"]["result"]["operationId"], "op-1"); + assert_eq!(value["payload"]["result"]["disposition"], "committed"); + let decoded: PublicResponse = + serde_json::from_value(value).expect("launcher exec response decodes"); + assert_eq!(decoded, exec_response); + } + #[test] fn level_percent_validates_range_at_wire_boundary() { // Values in range round-trip cleanly. From 1abe4f9b306b00007b12db9a4023bb8f7a9b98a6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:22:13 -0700 Subject: [PATCH 496/726] d2b-host: preallocate hex digests and tempdir the digest test Sha256::of and generation_id hex-encoded each digest byte with a fresh format! allocation (32+ per digest); write into one preallocated String::with_capacity(64) instead. The activation-helper digest test wrote fixtures under a CWD-relative target/ directory, polluting build artifacts and failing with a read-only target; use tempfile::tempdir() like the sibling tests. --- changelog.d/w3-14-host-hex-tempdir.md | 9 +++++++++ packages/d2b-host/src/bin/d2b-activation-helper.rs | 7 ++----- packages/d2b-host/src/hardlink_farm.rs | 9 +++++---- packages/d2b-host/src/nftables.rs | 6 +++++- 4 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 changelog.d/w3-14-host-hex-tempdir.md diff --git a/changelog.d/w3-14-host-hex-tempdir.md b/changelog.d/w3-14-host-hex-tempdir.md new file mode 100644 index 000000000..2f09c094a --- /dev/null +++ b/changelog.d/w3-14-host-hex-tempdir.md @@ -0,0 +1,9 @@ +### Fixed + +- Host-prepare SHA-256 digests (nftables drift hash and hardlink-farm + generation ids) are now hex-encoded into a single preallocated buffer + instead of allocating one string per byte. +- The `d2b-activation-helper` digest test now runs its fixtures in a + temporary directory instead of the CWD-relative `target/` build + directory, so it no longer pollutes build artifacts and works when the + build directory is read-only. \ No newline at end of file diff --git a/packages/d2b-host/src/bin/d2b-activation-helper.rs b/packages/d2b-host/src/bin/d2b-activation-helper.rs index 8823c983b..7db38f580 100644 --- a/packages/d2b-host/src/bin/d2b-activation-helper.rs +++ b/packages/d2b-host/src/bin/d2b-activation-helper.rs @@ -789,10 +789,8 @@ mod tests { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[test] fn package_digest_includes_bytes_read_through_store_symlinks() { - let directory = PathBuf::from("target") - .join(format!("activation-helper-digest-{}", std::process::id())); - let _ = fs::remove_dir_all(&directory); - fs::create_dir_all(&directory).expect("create digest fixture"); + let fixture = tempfile::tempdir().expect("create digest fixture"); + let directory = fixture.path().to_path_buf(); let target = directory.join("target"); let link = directory.join("linked"); let directory_target = directory.join("directory-target"); @@ -812,7 +810,6 @@ mod tests { digest_store_path_with_root(&directory, &store_root).expect("digest second fixture"); assert_ne!(first, second); - let _ = fs::remove_dir_all(directory); } #[test] diff --git a/packages/d2b-host/src/hardlink_farm.rs b/packages/d2b-host/src/hardlink_farm.rs index 0b4a8f6bf..a5e8b367d 100644 --- a/packages/d2b-host/src/hardlink_farm.rs +++ b/packages/d2b-host/src/hardlink_farm.rs @@ -65,6 +65,7 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; +use std::fmt::Write as _; use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::path::{Path, PathBuf}; use tokio::io::AsyncWriteExt; @@ -623,10 +624,10 @@ pub fn generation_id(closure_paths: &[PathBuf], system_path: Option<&Path>) -> S hasher.update((0u64).to_le_bytes()); } let digest = hasher.finalize(); - let hex = digest - .iter() - .map(|b| format!("{b:02x}")) - .collect::(); + let mut hex = String::with_capacity(64); + for b in digest.iter() { + write!(hex, "{b:02x}").expect("writing to a String is infallible"); + } format!("g-{hex}") } diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index 1f32c0a34..e11bb0d4d 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -29,6 +29,7 @@ use d2b_core::host_w3::{CoexistencePolicy, FirewallManager}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256 as Sha256Hasher}; use std::fmt; +use std::fmt::Write as _; /// Hex-encoded SHA-256 digest. Returned by [`hash_inet_d2b_table`] /// and consumed by the broker as the `table_hash_before`/`_after` @@ -43,7 +44,10 @@ impl Sha256 { let mut hasher = Sha256Hasher::new(); hasher.update(bytes); let out = hasher.finalize(); - let hex = out.iter().map(|b| format!("{b:02x}")).collect::(); + let mut hex = String::with_capacity(64); + for b in out.iter() { + write!(hex, "{b:02x}").expect("writing to a String is infallible"); + } Self(hex) } From 395eba54d22fa536ae3d58a8ea65386e5289143e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:22:56 -0700 Subject: [PATCH 497/726] d2b-contracts-resource: bound status size with a single serialization pass --- changelog.d/w3-10-contracts-resource-status-size.md | 10 ++++++++++ .../d2b-contracts-resource/src/v3/resource_status.rs | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w3-10-contracts-resource-status-size.md diff --git a/changelog.d/w3-10-contracts-resource-status-size.md b/changelog.d/w3-10-contracts-resource-status-size.md new file mode 100644 index 000000000..79cf59f6f --- /dev/null +++ b/changelog.d/w3-10-contracts-resource-status-size.md @@ -0,0 +1,10 @@ +# `w3-10-contracts-resource-status-size.md` + +### Changed + +- Building a v3 `ResourceStatus` now enforces the 64 KiB status-size bound + with a single serialization pass instead of re-canonicalizing the complete + status after the resource layer was already serialized, so status writes + pay one full serialization instead of two. The bound and its error + behavior are unchanged; canonical validation still happens at the storage + boundary where the status bytes are produced. \ No newline at end of file diff --git a/packages/d2b-contracts-resource/src/v3/resource_status.rs b/packages/d2b-contracts-resource/src/v3/resource_status.rs index f07e3e1af..6312dcb8b 100644 --- a/packages/d2b-contracts-resource/src/v3/resource_status.rs +++ b/packages/d2b-contracts-resource/src/v3/resource_status.rs @@ -647,7 +647,7 @@ impl ResourceStatus { resource, provider, }; - if canonical_json_bytes(&value) + if serde_json::to_vec(&value) .map_err(|_| ResourceStatusError::InvalidStatusString)? .len() > MAX_STATUS_BYTES From 5966950aaa152b74b747fce0452fa51f4f516f81 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:23:16 -0700 Subject: [PATCH 498/726] d2b: test zone session codec state machines and drop per-construction allocation ProcessTemplateBinding validation now strips the binary ref suffix instead of formatting a fresh String per construction. Add unit tests for the RequestEnvelope admit math, fragment reassembly, receive/send nonce sequences, attachment credits, header round-trips, and EmergencyPolicySpec contract branches. --- changelog.d/w3-11-contracts-zone-session.md | 5 + .../src/v3/component_session.rs | 577 ++++++++++++++++++ .../src/v3/emergency_policy.rs | 101 +++ .../src/v3/resource_bundle.rs | 4 +- 4 files changed, 686 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w3-11-contracts-zone-session.md diff --git a/changelog.d/w3-11-contracts-zone-session.md b/changelog.d/w3-11-contracts-zone-session.md new file mode 100644 index 000000000..442c15847 --- /dev/null +++ b/changelog.d/w3-11-contracts-zone-session.md @@ -0,0 +1,5 @@ +### Fixed + +- ProcessTemplateBinding validation no longer allocates a String per construction when checking the `/bin/` path suffix. +- The zone session codec state machines (request deadlines, fragment reassembly, receive/send nonce sequences, attachment credits) and header canonical round-trips now have unit tests. +- EmergencyPolicySpec now has tests for deadline/reason/control-character rejection, effective scope with no enabled policy, and the serde default round-trip. \ No newline at end of file diff --git a/packages/d2b-contracts-zone-session/src/v3/component_session.rs b/packages/d2b-contracts-zone-session/src/v3/component_session.rs index cd253e098..982824197 100644 --- a/packages/d2b-contracts-zone-session/src/v3/component_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/component_session.rs @@ -3241,3 +3241,580 @@ mod wire_enum_vectors { } } } + +#[cfg(test)] +mod codec_state_machine_tests { + use super::*; + + fn envelope(issued_at_unix_ms: u64, expires_at_unix_ms: u64) -> RequestEnvelope { + RequestEnvelope { + request_id: RequestId::new([0x42; 16].to_vec()).unwrap(), + correlation_id: None, + trace_id: None, + idempotency_key: None, + issued_at_unix_ms, + expires_at_unix_ms, + } + } + + fn fragment( + message_id: u64, + index: u32, + count: u32, + total_plaintext_len: u32, + offset: u32, + ) -> FragmentHeader { + FragmentHeader { + message_id, + index, + count, + total_plaintext_len, + offset, + } + } + + fn packet_policy(max_per_packet: u16) -> AttachmentPolicy { + AttachmentPolicy { + kind: AttachmentPolicyKind::PacketAtomic, + max_per_packet, + max_per_request: max_per_packet, + max_per_operation: max_per_packet, + max_per_session: max_per_packet, + credentials_allowed: false, + } + } + + #[test] + fn admit_rejects_expiry_before_issue() { + let request = envelope(2_000, 1_000); + assert_eq!( + request.admit(1_000, 100_000, None, None), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_rejects_zero_service_lifetime() { + let request = envelope(1_000, 5_000); + assert_eq!( + request.admit(2_000, 0, None, None), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_rejects_service_lifetime_above_contract_max() { + let request = envelope(1_000, 5_000); + assert_eq!( + request.admit(2_000, MAX_REQUEST_LIFETIME_MS + 1, None, None), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_rejects_lifetime_above_contract_max() { + let request = envelope(0, MAX_REQUEST_LIFETIME_MS + 1); + assert_eq!( + request.admit(1_000, MAX_REQUEST_LIFETIME_MS, None, None), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_rejects_lifetime_above_service_max() { + let request = envelope(0, 100_000); + assert_eq!( + request.admit(1_000, 50_000, None, None), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_rejects_issue_beyond_clock_skew() { + let issued = 1_000 + MAX_CLOCK_SKEW_MS + 1; + let request = envelope(issued, issued + 1_000); + assert_eq!( + request.admit(1_000, 100_000, None, None), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_rejects_expired_envelope() { + let request = envelope(1_000, 2_000); + assert_eq!( + request.admit(2_000, 100_000, None, None), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_rejects_zero_remaining_nanos() { + let request = envelope(1_000, 5_000); + assert_eq!( + request.admit(2_000, 100_000, Some(0), None), + Err(ContractError::InvalidDeadline) + ); + assert_eq!( + request.admit(2_000, 100_000, None, Some(0)), + Err(ContractError::InvalidDeadline) + ); + } + + #[test] + fn admit_skew_check_overflows_near_wall_clock_max() { + let request = envelope(u64::MAX - 500, u64::MAX - 400); + assert_eq!( + request.admit(u64::MAX - 1_000, 1_000, None, None), + Err(ContractError::ArithmeticOverflow) + ); + } + + #[test] + fn admit_accepts_and_caps_remaining_nanos() { + let request = envelope(1_000, 5_000); + let admitted = request + .admit(2_000, 4_000, Some(2_500_000_000), Some(2_000_000_000)) + .unwrap(); + assert_eq!(admitted.absolute_expiry_unix_ms, 5_000); + assert_eq!(admitted.remaining_nanos, 2_000_000_000); + + let admitted = request.admit(2_000, 4_000, None, None).unwrap(); + assert_eq!(admitted.remaining_nanos, 3_000_000_000); + + // A service cap below the wall-remaining window shortens the budget; + // the envelope lifetime must still fit inside the service maximum. + let future_issued = envelope(3_000, 5_000); + let admitted = future_issued.admit(1_000, 3_000, None, None).unwrap(); + assert_eq!(admitted.absolute_expiry_unix_ms, 5_000); + assert_eq!(admitted.remaining_nanos, 3_000_000_000); + } + + #[test] + fn fragment_begin_rejects_nonzero_index() { + let first = fragment(7, 1, 3, 10, 0); + assert_eq!( + FragmentSequence::begin(first, 5, 1_024), + Err(FragmentSequenceError::Reordered) + ); + } + + #[test] + fn fragment_begin_rejects_nonzero_offset() { + let first = fragment(7, 0, 2, 10, 5); + assert_eq!( + FragmentSequence::begin(first, 5, 1_024), + Err(FragmentSequenceError::Reordered) + ); + } + + #[test] + fn fragment_begin_rejects_invalid_header() { + let first = fragment(7, 0, 0, 10, 0); + assert_eq!( + FragmentSequence::begin(first, 5, 1_024), + Err(FragmentSequenceError::Invalid) + ); + } + + #[test] + fn fragment_sequence_accepts_in_order_until_complete() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!( + sequence.accept(fragment(7, 1, 2, 10, 5), 5, 1_024), + Ok(true) + ); + } + + #[test] + fn fragment_sequence_rejects_different_message() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!( + sequence.accept(fragment(8, 1, 2, 10, 5), 5, 1_024), + Err(FragmentSequenceError::DifferentMessage) + ); + assert_eq!( + sequence.accept(fragment(7, 1, 3, 10, 5), 5, 1_024), + Err(FragmentSequenceError::DifferentMessage) + ); + assert_eq!( + sequence.accept(fragment(7, 1, 2, 11, 5), 5, 1_024), + Err(FragmentSequenceError::DifferentMessage) + ); + } + + #[test] + fn fragment_sequence_rejects_duplicate() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!( + sequence.accept(fragment(7, 0, 2, 10, 0), 5, 1_024), + Err(FragmentSequenceError::Duplicate) + ); + } + + #[test] + fn fragment_sequence_rejects_reordered_index() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!( + sequence.accept(fragment(7, 2, 2, 10, 5), 5, 1_024), + Err(FragmentSequenceError::Reordered) + ); + } + + #[test] + fn fragment_sequence_rejects_overlap() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!( + sequence.accept(fragment(7, 1, 2, 10, 4), 5, 1_024), + Err(FragmentSequenceError::Overlap) + ); + } + + #[test] + fn fragment_sequence_rejects_reordered_offset() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!( + sequence.accept(fragment(7, 1, 2, 10, 6), 5, 1_024), + Err(FragmentSequenceError::Reordered) + ); + } + + #[test] + fn fragment_sequence_rejects_invalid_fragment() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!( + sequence.accept(fragment(7, 1, 2, 10, 5), 6, 1_024), + Err(FragmentSequenceError::Invalid) + ); + } + + #[test] + fn fragment_sequence_rejects_accept_after_complete() { + let mut sequence = + FragmentSequence::begin(fragment(7, 0, 2, 10, 0), 5, 1_024).unwrap(); + assert_eq!(sequence.accept(fragment(7, 1, 2, 10, 5), 5, 1_024), Ok(true)); + assert_eq!( + sequence.accept(fragment(7, 1, 2, 10, 5), 5, 1_024), + Err(FragmentSequenceError::Complete) + ); + } + + #[test] + fn receive_sequence_accepts_in_order() { + let mut sequence = ReceiveSequence::new(); + assert_eq!(sequence.accept(0), Ok(())); + assert_eq!(sequence.accept(1), Ok(())); + let mut sequence = ReceiveSequence::from_expected(5); + assert_eq!(sequence.accept(5), Ok(())); + } + + #[test] + fn receive_sequence_rejects_replay() { + let mut sequence = ReceiveSequence::from_expected(5); + assert_eq!(sequence.accept(4), Err(SequenceError::Replay)); + } + + #[test] + fn receive_sequence_rejects_out_of_order() { + let mut sequence = ReceiveSequence::from_expected(5); + assert_eq!(sequence.accept(6), Err(SequenceError::OutOfOrder)); + } + + #[test] + fn receive_sequence_rejects_max_nonce() { + let mut sequence = ReceiveSequence::new(); + assert_eq!(sequence.accept(u64::MAX), Err(SequenceError::NonceExhausted)); + } + + #[test] + fn receive_sequence_exhausts_at_max_minus_one() { + let mut sequence = ReceiveSequence::from_expected(u64::MAX - 1); + assert_eq!(sequence.accept(u64::MAX - 1), Ok(())); + assert_eq!( + sequence.accept(u64::MAX - 1), + Err(SequenceError::NonceExhausted) + ); + } + + #[test] + fn receive_sequence_from_expected_max_is_exhausted() { + let mut sequence = ReceiveSequence::from_expected(u64::MAX); + assert_eq!(sequence.accept(0), Err(SequenceError::NonceExhausted)); + } + + #[test] + fn send_sequence_take_increments() { + let mut sequence = SendSequence::new(); + assert_eq!(sequence.take(), Ok(0)); + assert_eq!(sequence.take(), Ok(1)); + assert_eq!(sequence.take(), Ok(2)); + let mut sequence = SendSequence::from_next(5); + assert_eq!(sequence.take(), Ok(5)); + assert_eq!(sequence.take(), Ok(6)); + } + + #[test] + fn send_sequence_take_rejects_exhausted() { + let mut sequence = SendSequence::from_next(u64::MAX); + assert_eq!(sequence.take(), Err(SequenceError::NonceExhausted)); + let mut sequence = SendSequence::from_next(u64::MAX - 1); + assert_eq!(sequence.take(), Ok(u64::MAX - 1)); + assert_eq!(sequence.take(), Err(SequenceError::NonceExhausted)); + } + + #[test] + fn attachment_credits_reserve_increments_all_classes() { + let credits = AttachmentCredits { + packet: 1, + request: 2, + operation: 3, + session: 4, + process: 5, + host: 6, + }; + let next = credits.reserve(1, packet_policy(8)).unwrap(); + assert_eq!(next.packet, 2); + assert_eq!(next.request, 3); + assert_eq!(next.operation, 4); + assert_eq!(next.session, 5); + assert_eq!(next.process, 6); + assert_eq!(next.host, 7); + } + + #[test] + fn attachment_credits_reserve_overflows() { + let credits = AttachmentCredits { + packet: 1, + request: 0, + operation: 0, + session: 0, + process: 0, + host: 0, + }; + assert_eq!( + credits.reserve(u16::MAX, packet_policy(u16::MAX)), + Err(ContractError::ArithmeticOverflow) + ); + } + + #[test] + fn attachment_credits_reserve_rejects_policy_excess() { + let credits = AttachmentCredits { + packet: 1, + request: 0, + operation: 0, + session: 0, + process: 0, + host: 0, + }; + assert_eq!( + credits.reserve(1, packet_policy(1)), + Err(ContractError::CreditExceeded) + ); + } + + #[test] + fn attachment_credits_reserve_rejects_process_and_host_caps() { + let credits = AttachmentCredits { + packet: 0, + request: 0, + operation: 0, + session: 0, + process: MAX_PROCESS_ATTACHMENT_CREDITS, + host: 0, + }; + assert_eq!( + credits.reserve(1, packet_policy(8)), + Err(ContractError::CreditExceeded) + ); + let credits = AttachmentCredits { + packet: 0, + request: 0, + operation: 0, + session: 0, + process: 0, + host: MAX_HOST_ATTACHMENT_CREDITS, + }; + assert_eq!( + credits.reserve(1, packet_policy(8)), + Err(ContractError::CreditExceeded) + ); + } + + #[test] + fn attachment_credits_process_pool_computes_and_caps() { + assert_eq!(AttachmentCredits::process_pool(1_000, 0), Ok(936)); + assert_eq!( + AttachmentCredits::process_pool(1_000_000, 0), + Ok(MAX_PROCESS_ATTACHMENT_CREDITS) + ); + assert_eq!( + AttachmentCredits::process_pool(100, 100), + Err(ContractError::CreditExceeded) + ); + assert_eq!( + AttachmentCredits::process_pool(63, 0), + Err(ContractError::CreditExceeded) + ); + } + + #[test] + fn record_header_round_trips_canonically() { + let limits = LimitProfile::local_default(); + let headers = [ + ( + RecordKind::SessionControl, + ChannelId::SESSION_CONTROL, + ), + (RecordKind::Ttrpc, ChannelId::TTRPC_CONTROL), + (RecordKind::Attachment, ChannelId::ATTACHMENT_CONTROL), + ( + RecordKind::NamedStream, + ChannelId::named(0x0100).unwrap(), + ), + ]; + for (kind, channel) in headers { + let header = RecordHeader { + kind, + flags: 0x05, + channel, + sequence: 7, + reconnect_generation: 9, + payload_len: 11, + }; + let bytes = header.encode(limits).unwrap(); + assert_eq!(bytes.len(), RECORD_HEADER_LEN); + assert_eq!(RecordHeader::decode(&bytes, limits).unwrap(), header); + } + } + + #[test] + fn record_header_encode_rejects_invalid_contract() { + let limits = LimitProfile::local_default(); + let invalid_channel = RecordHeader { + kind: RecordKind::Ttrpc, + flags: 0, + channel: ChannelId(3), + sequence: 1, + reconnect_generation: 1, + payload_len: 1, + }; + assert_eq!( + invalid_channel.encode(limits), + Err(ContractError::InvalidChannel) + ); + let zero_generation = RecordHeader { + kind: RecordKind::Ttrpc, + flags: 0, + channel: ChannelId::TTRPC_CONTROL, + sequence: 1, + reconnect_generation: 0, + payload_len: 1, + }; + assert_eq!( + zero_generation.encode(limits), + Err(ContractError::LimitExceeded) + ); + let oversized = RecordHeader { + kind: RecordKind::Ttrpc, + flags: 0, + channel: ChannelId::TTRPC_CONTROL, + sequence: 1, + reconnect_generation: 1, + payload_len: u32::MAX, + }; + assert_eq!(oversized.encode(limits), Err(ContractError::LimitExceeded)); + } + + #[test] + fn record_header_decode_rejects_truncated() { + let limits = LimitProfile::local_default(); + assert_eq!( + RecordHeader::decode(&[0; RECORD_HEADER_LEN - 1], limits), + Err(BinaryError::Truncated) + ); + } + + #[test] + fn fragment_header_round_trips_canonically() { + let header = fragment(7, 1, 2, 10, 5); + let bytes = header.encode(5, 1_024).unwrap(); + assert_eq!(bytes.len(), FRAGMENT_HEADER_LEN); + assert_eq!(FragmentHeader::decode(&bytes, 5, 1_024).unwrap(), header); + } + + #[test] + fn fragment_header_encode_rejects_invalid_fragment() { + let header = fragment(7, 2, 2, 10, 0); + assert_eq!( + header.encode(5, 1_024), + Err(ContractError::InvalidFragment) + ); + } + + #[test] + fn fragment_header_decode_rejects_truncated() { + assert_eq!( + FragmentHeader::decode(&[0; FRAGMENT_HEADER_LEN - 1], 5, 1_024), + Err(BinaryError::Truncated) + ); + } + + fn local_offer() -> HandshakeOffer { + HandshakeOffer { + purpose: EndpointPurpose::LocalLifecycle, + purpose_class: PurposeClass::Local, + initiator_role: EndpointRole::ZoneController, + responder_role: EndpointRole::Component, + service: ServicePackage::ResourceV3, + schema_fingerprint: [0x51; 32], + noise_profile: NoiseProfile::Nn25519ChaChaPolySha256, + limits: LimitProfile::local_default(), + transport_binding: TransportBinding { + transport: TransportClass::UnixStream, + locality: Locality::HostLocal, + channel_binding: [0x52; 32], + identity_evidence: IdentityEvidenceRequirement::DirectionalUnix, + }, + reconnect_generation: 1, + attachment_policy: AttachmentPolicy::disabled(), + } + } + + #[test] + fn handshake_accept_round_trips_canonically() { + let accept = HandshakeAccept { + offer: local_offer(), + transcript_binding: [0x53; 32], + }; + let bytes = accept.encode_canonical().unwrap(); + assert_eq!(HandshakeAccept::decode_canonical(&bytes).unwrap(), accept); + } + + #[test] + fn handshake_accept_rejects_zero_transcript_binding() { + let accept = HandshakeAccept { + offer: local_offer(), + transcript_binding: [0; 32], + }; + assert_eq!( + accept.encode_canonical(), + Err(BinaryError::InvalidContract(ContractError::InvalidBinding)) + ); + } + + #[test] + fn handshake_accept_decode_rejects_truncated() { + assert_eq!( + HandshakeAccept::decode_canonical(&[0x01, 0x00]), + Err(BinaryError::Truncated) + ); + } +} diff --git a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs index 9647cae39..9725d1abf 100644 --- a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs +++ b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs @@ -242,4 +242,105 @@ mod tests { assert!(scope.stop_provider_processes()); assert_eq!(deadline, 5); } + + #[test] + fn new_rejects_invalid_deadlines() { + for deadline in [0, MAX_EMERGENCY_DRAIN_DEADLINE_SECONDS + 1, u32::MAX] { + assert_eq!( + EmergencyPolicySpec::new(false, EmergencyScope::default(), deadline, ""), + Err(EmergencyPolicyContractError::InvalidDeadline), + "deadline {deadline} must be rejected" + ); + } + assert!( + EmergencyPolicySpec::new( + false, + EmergencyScope::default(), + MAX_EMERGENCY_DRAIN_DEADLINE_SECONDS, + "" + ) + .is_ok() + ); + } + + #[test] + fn new_rejects_oversized_reason() { + let reason = "x".repeat(MAX_EMERGENCY_REASON_BYTES + 1); + assert_eq!( + EmergencyPolicySpec::new(false, EmergencyScope::default(), 30, reason), + Err(EmergencyPolicyContractError::ReasonTooLong) + ); + assert!( + EmergencyPolicySpec::new( + false, + EmergencyScope::default(), + 30, + "x".repeat(MAX_EMERGENCY_REASON_BYTES) + ) + .is_ok() + ); + } + + #[test] + fn new_rejects_control_characters_in_reason() { + for character in ['\0', '\t', '\n', '\r', '\u{000b}', '\u{001b}', '\u{007f}'] { + let reason = format!("drain{character}now"); + assert_eq!( + EmergencyPolicySpec::new(false, EmergencyScope::default(), 30, reason), + Err(EmergencyPolicyContractError::ReasonContainsControl), + "control character {character:?} must be rejected" + ); + } + } + + #[test] + fn new_accepts_plain_reason_and_retains_fields() { + let spec = + EmergencyPolicySpec::new(true, EmergencyScope::new(true, false, true, false), 45, "drain") + .unwrap(); + assert!(spec.enabled()); + assert!(spec.scope().stop_new_admissions()); + assert!(!spec.scope().disconnect_zone_links()); + assert!(spec.scope().stop_provider_processes()); + assert_eq!(spec.drain_deadline_seconds(), 45); + assert_eq!(spec.reason(), "drain"); + } + + #[test] + fn effective_scope_is_none_without_enabled_policies() { + assert_eq!(effective_scope([] as [&EmergencyPolicySpec; 0]), None); + let disabled = EmergencyPolicySpec::new(false, EmergencyScope::new(true, false, false, false), 30, "") + .unwrap(); + assert_eq!(effective_scope([&disabled]), None); + } + + #[test] + fn serde_default_round_trips_and_minimal_wire_deserializes() { + let default = EmergencyPolicySpec::default(); + let wire = serde_json::to_string(&default).unwrap(); + assert_eq!( + serde_json::from_str::(&wire).unwrap(), + default + ); + assert_eq!( + serde_json::from_str::("{}").unwrap(), + default + ); + } + + #[test] + fn serde_wire_applies_explicit_fields_and_rejects_invalid_deadline() { + let spec = serde_json::from_str::( + "{\"enabled\":true,\"scope\":{\"stopNewAdmissions\":true},\"drainDeadlineSeconds\":45,\"reason\":\"drain\"}", + ) + .unwrap(); + assert!(spec.enabled()); + assert!(spec.scope().stop_new_admissions()); + assert_eq!(spec.drain_deadline_seconds(), 45); + assert_eq!(spec.reason(), "drain"); + assert!(serde_json::from_str::( + "{\"drainDeadlineSeconds\":0}" + ) + .is_err()); + } } diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs index 5a33b3aad..b05972b99 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs @@ -379,7 +379,9 @@ impl ProcessTemplateBinding { || binary_path .split('/') .any(|segment| matches!(segment, "." | "..")) - || !binary_path.ends_with(&format!("/bin/{}", binary_ref.as_str())) + || !binary_path + .strip_suffix(binary_ref.as_str()) + .is_some_and(|prefix| prefix.ends_with("/bin/")) { return Err(ResourceBundleError::InvalidProcessTemplate); } From 716eaef89afc16da5bf1c6d1e3dcab30f537e6d1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:23:30 -0700 Subject: [PATCH 499/726] d2b-core-controller: test restart recovery receipt and coordinator rollback --- .../w3-13-core-controller-recovery-tests.md | 11 + packages/d2b-core-controller/src/authority.rs | 125 ++++++++++ .../src/authority_persistence.rs | 227 ++++++++++++++++++ 3 files changed, 363 insertions(+) create mode 100644 changelog.d/w3-13-core-controller-recovery-tests.md diff --git a/changelog.d/w3-13-core-controller-recovery-tests.md b/changelog.d/w3-13-core-controller-recovery-tests.md new file mode 100644 index 000000000..abb78712a --- /dev/null +++ b/changelog.d/w3-13-core-controller-recovery-tests.md @@ -0,0 +1,11 @@ +### Fixed + +- Restart recovery of Host-global authorities now has unit coverage: a + tampered claim digest, a prepared-capability set that misses an active + operation, and a duplicate operation id are each rejected as invalid + authority requests, and a rehydrated operation is admitted only after its + recovery resolution. +- The authority recovery coordinator's rollback is now tested: a failed + record_close or release restores the recovery capability and quarantines + the operation instead of silently reaching readiness, and resolving an + observed-and-adopted operation clears the unresolved set. \ No newline at end of file diff --git a/packages/d2b-core-controller/src/authority.rs b/packages/d2b-core-controller/src/authority.rs index 197416f24..5b41dd020 100644 --- a/packages/d2b-core-controller/src/authority.rs +++ b/packages/d2b-core-controller/src/authority.rs @@ -2846,4 +2846,129 @@ fn authority_proof(value: &str, generation: u64) -> AuthorityOwnerProof { ); assert!(index.authority_status(&request).is_none()); } + + fn operation_row( + operation_id: &str, + request: &AuthorityRequest, + ) -> (AuthorityStorageOperation, PreparedAuthorityOperation) { + let claim = AuthorityStorageClaim::Generic(request.durable_claim()); + let claim_digest = claim_digest(&claim).unwrap(); + let store_binding_digest = "sha256:".to_owned() + &"1".repeat(64); + let operation = AuthorityStorageOperation { + operation_id: operation_id.to_owned(), + claim, + state: AuthorityOperationState::Pending, + claim_digest, + store_binding_digest: store_binding_digest.clone(), + }; + let prepared = PreparedAuthorityOperation::new( + operation_id.to_owned(), + store_binding_digest, + test_nonce_for_operation(operation_id), + ) + .unwrap(); + (operation, prepared) + } + + #[test] + fn recovery_receipt_rejects_tampered_claim_digest() { + let request = AuthorityRequest::vsock_cid( + uid("a73e4567-e89b-42d3-a456-426614174080"), + 79, + authority_proof("b73e4567-e89b-42d3-a456-426614174081", 1), + ) + .unwrap(); + let (mut operation, prepared) = operation_row("recovery-tampered-digest", &request); + let mut tampered: Vec = operation.claim_digest.chars().collect(); + tampered[63] = if tampered[63] == '0' { '1' } else { '0' }; + operation.claim_digest = tampered.into_iter().collect(); + assert!(matches!( + HostGlobalAuthorityIndex::recovery_receipt_from_operations_with_prepared_capabilities( + vec![operation], + None, + BTreeMap::from([("recovery-tampered-digest".to_owned(), prepared)]), + ), + Err(AuthorityError::InvalidAuthorityRequest) + )); + } + + #[test] + fn recovery_receipt_rejects_prepared_set_missing_active_operation() { + let request = AuthorityRequest::vsock_cid( + uid("c73e4567-e89b-42d3-a456-426614174082"), + 81, + authority_proof("d73e4567-e89b-42d3-a456-426614174083", 1), + ) + .unwrap(); + let (operation, _) = operation_row("recovery-missing-prepared", &request); + assert!(matches!( + HostGlobalAuthorityIndex::recovery_receipt_from_operations_with_prepared_capabilities( + vec![operation], + None, + BTreeMap::new(), + ), + Err(AuthorityError::InvalidAuthorityRequest) + )); + } + + #[test] + fn recovery_receipt_rejects_duplicate_operation_id() { + let host = uid("e73e4567-e89b-42d3-a456-426614174084"); + let first = AuthorityRequest::vsock_cid( + host.clone(), + 83, + authority_proof("f73e4567-e89b-42d3-a456-426614174085", 1), + ) + .unwrap(); + let second = AuthorityRequest::vsock_cid( + host, + 84, + authority_proof("a83e4567-e89b-42d3-a456-426614174086", 1), + ) + .unwrap(); + let (first_operation, _) = operation_row("recovery-duplicate-id", &first); + let (second_operation, _) = operation_row("recovery-duplicate-id", &second); + assert!(matches!( + HostGlobalAuthorityIndex::recovery_receipt_from_operations_with_prepared_capabilities( + vec![first_operation, second_operation], + None, + BTreeMap::new(), + ), + Err(AuthorityError::InvalidAuthorityRequest) + )); + } + + #[test] + fn rehydrate_round_trip_admits_recovered_operation_and_reaches_readiness() { + let owner = authority_proof("c83e4567-e89b-42d3-a456-426614174088", 1); + let request = AuthorityRequest::vsock_cid( + uid("b83e4567-e89b-42d3-a456-426614174087"), + 86, + owner.clone(), + ) + .unwrap(); + let (operation, prepared) = operation_row("recovery-round-trip", &request); + let receipt = + HostGlobalAuthorityIndex::recovery_receipt_from_operations_with_prepared_capabilities( + vec![operation], + None, + BTreeMap::from([("recovery-round-trip".to_owned(), prepared)]), + ) + .unwrap(); + let mut index = HostGlobalAuthorityIndex::rehydrate(receipt).unwrap(); + assert!(index.is_rehydrated()); + assert_eq!(index.authority_status(&request).unwrap().holder_count(), 1); + assert!(matches!( + index.adopt_authority(&request, core::slice::from_ref(&owner)), + AuthorityAdoption::Adopted(_) + )); + assert!(!index.is_ready_for_readiness()); + index + .resolve_recovered_operation( + "recovery-round-trip", + AuthorityRecoveryResolution::ObservedAndAdopted, + ) + .unwrap(); + assert!(index.is_ready_for_readiness()); + } } diff --git a/packages/d2b-core-controller/src/authority_persistence.rs b/packages/d2b-core-controller/src/authority_persistence.rs index 4df30e61a..e897bcf03 100644 --- a/packages/d2b-core-controller/src/authority_persistence.rs +++ b/packages/d2b-core-controller/src/authority_persistence.rs @@ -333,3 +333,230 @@ async fn validated_recovery_receipt( ) .map_err(|_| AuthorityPersistenceError::RowInvalid) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::authority::{AuthorityOwnerProof, AuthorityRequest, claim_digest}; + use d2b_contracts_resource::v3::{ResourceGeneration, ResourceUid}; + + fn uid(value: &str) -> ResourceUid { + ResourceUid::parse(value).unwrap() + } + + fn authority_proof(value: &str, generation: u64) -> AuthorityOwnerProof { + AuthorityOwnerProof::new(uid(value), ResourceGeneration::new(generation).unwrap()) + } + + fn recovery_row( + operation_id: &str, + ) -> (AuthorityStorageOperation, PreparedAuthorityOperation, AuthorityRequest) { + let request = AuthorityRequest::vsock_cid( + uid("d93e4567-e89b-42d3-a456-426614174089"), + 87, + authority_proof("e93e4567-e89b-42d3-a456-426614174090", 1), + ) + .unwrap(); + let claim = AuthorityStorageClaim::Generic(request.durable_claim()); + let claim_digest = claim_digest(&claim).unwrap(); + let store_binding_digest = "sha256:".to_owned() + &"1".repeat(64); + let operation = AuthorityStorageOperation { + operation_id: operation_id.to_owned(), + claim, + state: AuthorityOperationState::Pending, + claim_digest, + store_binding_digest: store_binding_digest.clone(), + }; + let prepared = + PreparedAuthorityOperation::new(operation_id.to_owned(), store_binding_digest, 7) + .unwrap(); + (operation, prepared, request) + } + + /// Provenance that accepts every recovered row; the coordinator tests + /// exercise the receipt and rollback machinery, not provenance policy. + struct AcceptingProvenance; + + impl AuthorityRecoveryProvenance for AcceptingProvenance { + fn validate<'a>( + &'a self, + _operation: &'a AuthorityStorageOperation, + ) -> AuthorityFuture<'a, ()> { + Box::pin(async { Ok(()) }) + } + } + + /// Recovery double whose close/release legs can fail on demand. + struct FailingRecoveryPersistence { + fail_close: bool, + fail_release: bool, + operations: Vec, + prepared: BTreeMap, + } + + impl AuthorityPersistence for FailingRecoveryPersistence { + fn prepare<'a>( + &'a self, + _operation_id: &'a str, + _claim: &'a AuthorityStorageClaim, + ) -> AuthorityFuture<'a, PreparedAuthorityOperation> { + Box::pin(async { Err(AuthorityPersistenceError::StoreUnavailable) }) + } + + fn record_effect<'a>( + &'a self, + _capability: &'a AuthorityOperationCapability, + _state: AuthorityOperationState, + ) -> AuthorityFuture<'a, ()> { + Box::pin(async { Ok(()) }) + } + + fn record_close<'a>( + &'a self, + _capability: &'a AuthorityOperationCapability, + ) -> AuthorityFuture<'a, ()> { + if self.fail_close { + Box::pin(async { Err(AuthorityPersistenceError::StoreUnavailable) }) + } else { + Box::pin(async { Ok(()) }) + } + } + + fn release<'a>( + &'a self, + _capability: &'a AuthorityOperationCapability, + ) -> AuthorityFuture<'a, ()> { + if self.fail_release { + Box::pin(async { Err(AuthorityPersistenceError::StoreUnavailable) }) + } else { + Box::pin(async { Ok(()) }) + } + } + + fn recover<'a>(&'a self) -> AuthorityFuture<'a, AuthorityRecoveryData> { + Box::pin(async { + Ok(AuthorityRecoveryData::new( + self.operations.clone(), + self.prepared.clone(), + )) + }) + } + } + + async fn failing_coordinator( + operation_id: &str, + fail_close: bool, + fail_release: bool, + ) -> AuthorityRecoveryCoordinator { + let (operation, prepared, _) = recovery_row(operation_id); + let persistence = Arc::new(FailingRecoveryPersistence { + fail_close, + fail_release, + operations: vec![operation], + prepared: BTreeMap::from([(operation_id.to_owned(), prepared)]), + }); + AuthorityRecoveryCoordinator::recover_with_provenance(persistence, &AcceptingProvenance) + .await + .unwrap() + } + + // R11 inventory note: tokio Mutex::lock().await resolves to the banned + // Runtime::block_on bridge in clippy 1.97; sanctioned "cfg(test) helper". + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test] + async fn coordinator_restores_capability_and_quarantines_after_record_close_failure() { + let coordinator = failing_coordinator("recovery-close-failure", true, false).await; + assert_eq!( + coordinator + .resolve_observed_closed("recovery-close-failure") + .await + .unwrap_err(), + AuthorityPersistenceError::StoreUnavailable + ); + assert!( + coordinator + .index() + .lock() + .await + .take_recovery_capability("recovery-close-failure") + .is_some(), + "failed close must restore the recovery capability" + ); + coordinator + .resolve_observed_and_adopted("recovery-close-failure") + .await + .unwrap(); + assert!( + !coordinator.is_ready_for_readiness().await, + "failed close must quarantine the operation" + ); + } + + // R11 inventory note: tokio Mutex::lock().await resolves to the banned + // Runtime::block_on bridge in clippy 1.97; sanctioned "cfg(test) helper". + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test] + async fn coordinator_restores_capability_and_quarantines_after_release_failure() { + let coordinator = failing_coordinator("recovery-release-failure", false, true).await; + assert_eq!( + coordinator + .resolve_observed_closed("recovery-release-failure") + .await + .unwrap_err(), + AuthorityPersistenceError::StoreUnavailable + ); + assert!( + coordinator + .index() + .lock() + .await + .take_recovery_capability("recovery-release-failure") + .is_some(), + "failed release must restore the recovery capability" + ); + coordinator + .resolve_observed_and_adopted("recovery-release-failure") + .await + .unwrap(); + assert!( + !coordinator.is_ready_for_readiness().await, + "failed release must quarantine the operation" + ); + } + + // R11 inventory note: tokio Mutex::lock().await resolves to the banned + // Runtime::block_on bridge in clippy 1.97; sanctioned "cfg(test) helper". + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test] + async fn coordinator_resolve_observed_and_adopted_clears_unresolved_set() { + let coordinator = failing_coordinator("recovery-observed-adopted", false, false).await; + assert!(!coordinator.is_ready_for_readiness().await); + coordinator + .resolve_observed_and_adopted("recovery-observed-adopted") + .await + .unwrap(); + assert!(coordinator.is_ready_for_readiness().await); + } + + // R11 inventory note: tokio Mutex::lock().await resolves to the banned + // Runtime::block_on bridge in clippy 1.97; sanctioned "cfg(test) helper". + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test] + async fn coordinator_consumes_capability_and_reaches_readiness_on_successful_close() { + let coordinator = failing_coordinator("recovery-close-success", false, false).await; + coordinator + .resolve_observed_closed("recovery-close-success") + .await + .unwrap(); + assert!( + coordinator + .index() + .lock() + .await + .take_recovery_capability("recovery-close-success") + .is_none(), + "successful close must consume the recovery capability" + ); + assert!(coordinator.is_ready_for_readiness().await); + } +} From 3b2c1416b11ece8faf160a6a62c4090ebba74781 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:24:36 -0700 Subject: [PATCH 500/726] d2b-contracts-provider: relax credential record atomics and test the wire codec SensitiveDeliveryRecord per-byte loads and stores have no release/acquire pairing, so SeqCst bought nothing; use Relaxed in copy_to, clear, and is_zeroized. Add unit tests for the strict protobuf codec (round-trip, truncation, duplicate-field, unknown-field, non-canonical-varint, oversize ceilings) and for the controller observe, rotation-retry-exhausted, lease-aggregate, health-derive, and controller-audit-event behaviors. --- ...-09-contracts-provider-credential-tests.md | 12 + .../src/v3/credential/service.rs | 473 +++++++++++++++++- .../src/v3/credential_controller.rs | 285 +++++++++++ 3 files changed, 767 insertions(+), 3 deletions(-) create mode 100644 changelog.d/w3-09-contracts-provider-credential-tests.md diff --git a/changelog.d/w3-09-contracts-provider-credential-tests.md b/changelog.d/w3-09-contracts-provider-credential-tests.md new file mode 100644 index 000000000..db50b7cb4 --- /dev/null +++ b/changelog.d/w3-09-contracts-provider-credential-tests.md @@ -0,0 +1,12 @@ +### Changed + +- Credential delivery records now erase and copy plaintext with relaxed + atomic ordering instead of needless sequentially-consistent fences. + +### Fixed + +- The strict Credential wire codec is now unit-tested for round-trip, + truncation, duplicate-field, non-canonical-varint, and oversize behavior, + and the Credential controller decision paths are now unit-tested for + observe, rotation-retry-exhausted, lease-aggregate, health, and + controller-audit-event behavior. \ No newline at end of file diff --git a/packages/d2b-contracts-provider/src/v3/credential/service.rs b/packages/d2b-contracts-provider/src/v3/credential/service.rs index 6547aaf59..8363f4819 100644 --- a/packages/d2b-contracts-provider/src/v3/credential/service.rs +++ b/packages/d2b-contracts-provider/src/v3/credential/service.rs @@ -952,7 +952,7 @@ impl SensitiveDeliveryRecord { )); } for (destination, source) in destination.iter_mut().zip(&self.bytes) { - *destination = source.load(Ordering::SeqCst); + *destination = source.load(Ordering::Relaxed); } Ok(()) } @@ -960,7 +960,7 @@ impl SensitiveDeliveryRecord { /// Erase the retained plaintext immediately. pub fn clear(&mut self) { for byte in &self.bytes { - byte.store(0, Ordering::SeqCst); + byte.store(0, Ordering::Relaxed); } self.cleared = true; } @@ -974,7 +974,7 @@ impl SensitiveDeliveryRecord { pub fn is_zeroized(&self) -> bool { self.bytes .iter() - .all(|byte| byte.load(Ordering::SeqCst) == 0) + .all(|byte| byte.load(Ordering::Relaxed) == 0) } } @@ -1464,3 +1464,470 @@ fn varint_len(mut value: u64) -> usize { } length } + +#[cfg(test)] +mod tests { + use super::*; + + fn digest() -> String { + format!("sha256:{}", "a".repeat(64)) + } + + fn credential_ref() -> ResourceRef { + ResourceRef::parse("Credential/root-token").unwrap() + } + + fn consumer_ref() -> ResourceRef { + ResourceRef::parse("Provider/guest-agent").unwrap() + } + + fn uid() -> ResourceUid { + ResourceUid::parse("123e4567-e89b-42d3-a456-426614174000").unwrap() + } + + fn generation() -> ResourceGeneration { + ResourceGeneration::new(1).unwrap() + } + + fn audience() -> AudienceToken { + AudienceToken::parse("d2b-guest-agent").unwrap() + } + + fn route_digest() -> DeliveryRouteDigest { + DeliveryRouteDigest::parse(digest()).unwrap() + } + + fn lease_handle() -> CredentialLeaseHandle { + CredentialLeaseHandle::from_opaque_digest(digest()).unwrap() + } + + fn source_version() -> CredentialSourceVersion { + CredentialSourceVersion::from_opaque_digest(digest()).unwrap() + } + + fn metadata() -> CredentialMetadata { + CredentialMetadata { + lease_handle: lease_handle(), + rotation_generation: 1, + source_version: source_version(), + expires_at_unix_ms: 1_000, + state: CredentialLeaseState::Active, + outcome: CredentialOutcomeCode::Success, + } + } + + fn request() -> CredentialRequest { + CredentialRequest::new( + credential_ref(), + "op-123", + "idem-1", + 1_000, + 500, + ) + .unwrap() + } + + fn delivery_params() -> DeliverySessionParams { + DeliverySessionParams::new( + credential_ref(), + uid(), + generation(), + consumer_ref(), + generation(), + audience(), + OperationClass::AcquireToken, + 1_000, + 500, + route_digest(), + 4_096, + 1, + ) + .unwrap() + } + + fn delivery_response() -> DeliveryResponse { + DeliveryResponse { + metadata: metadata(), + delivery_session_params: delivery_params(), + } + } + + fn metadata_response() -> MetadataResponse { + MetadataResponse { + metadata: metadata(), + } + } + + fn assert_round_trip(value: &T) { + let mut encoded = Vec::new(); + value.encode_wire(&mut encoded); + let decoded = T::decode_wire(&encoded).expect("canonical encoding must decode"); + assert_eq!(&decoded, value); + } + + fn assert_every_truncation_rejected(encoded: &[u8]) { + for length in 0..encoded.len() { + assert!( + T::decode_wire(&encoded[..length]).is_err(), + "truncated prefix of {length} bytes must be rejected" + ); + } + } + + #[test] + fn every_outer_dto_round_trips_the_strict_codec() { + assert_round_trip(&request()); + assert_round_trip(&metadata()); + assert_round_trip(&delivery_params()); + assert_round_trip(&delivery_response()); + assert_round_trip(&metadata_response()); + } + + #[test] + fn every_truncation_of_every_outer_dto_is_rejected() { + let mut request_bytes = Vec::new(); + request().encode_wire(&mut request_bytes); + assert_every_truncation_rejected::(&request_bytes); + + let mut metadata_bytes = Vec::new(); + metadata().encode_wire(&mut metadata_bytes); + assert_every_truncation_rejected::(&metadata_bytes); + + let mut params_bytes = Vec::new(); + delivery_params().encode_wire(&mut params_bytes); + assert_every_truncation_rejected::(¶ms_bytes); + + let mut response_bytes = Vec::new(); + delivery_response().encode_wire(&mut response_bytes); + assert_every_truncation_rejected::(&response_bytes); + + let mut metadata_response_bytes = Vec::new(); + metadata_response().encode_wire(&mut metadata_response_bytes); + assert_every_truncation_rejected::(&metadata_response_bytes); + } + + #[test] + fn duplicate_fields_are_rejected() { + let mut request_bytes = Vec::new(); + request().encode_wire(&mut request_bytes); + write_string(&mut request_bytes, 1, "Credential/root-token"); + assert_eq!( + CredentialRequest::decode_wire(&request_bytes) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut metadata_bytes = Vec::new(); + metadata().encode_wire(&mut metadata_bytes); + write_u64(&mut metadata_bytes, 5, 1); + assert_eq!( + CredentialMetadata::decode_wire(&metadata_bytes) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut params_bytes = Vec::new(); + delivery_params().encode_wire(&mut params_bytes); + write_u64(&mut params_bytes, 13, 1); + assert_eq!( + DeliverySessionParams::decode_wire(¶ms_bytes) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut response_bytes = Vec::new(); + delivery_response().encode_wire(&mut response_bytes); + write_message(&mut response_bytes, 1, &metadata()); + assert_eq!( + DeliveryResponse::decode_wire(&response_bytes) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut metadata_response_bytes = Vec::new(); + metadata_response().encode_wire(&mut metadata_response_bytes); + write_message(&mut metadata_response_bytes, 1, &metadata()); + assert_eq!( + MetadataResponse::decode_wire(&metadata_response_bytes) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + } + + #[test] + fn unknown_fields_and_wrong_wire_types_are_rejected() { + let mut unknown_field = Vec::new(); + request().encode_wire(&mut unknown_field); + write_u64(&mut unknown_field, 99, 1); + assert_eq!( + CredentialRequest::decode_wire(&unknown_field) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut wrong_wire_type = Vec::new(); + write_u64(&mut wrong_wire_type, 1, 1); + write_string(&mut wrong_wire_type, 2, "op-123"); + write_string(&mut wrong_wire_type, 3, "idem-1"); + write_u64(&mut wrong_wire_type, 4, 1_000); + write_u64(&mut wrong_wire_type, 5, 500); + assert_eq!( + CredentialRequest::decode_wire(&wrong_wire_type) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut trailing = Vec::new(); + metadata_response().encode_wire(&mut trailing); + write_u64(&mut trailing, 2, 1); + assert_eq!( + MetadataResponse::decode_wire(&trailing) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + } + + #[test] + fn out_of_range_field_values_are_rejected() { + let mut unknown_state = Vec::new(); + write_string(&mut unknown_state, 1, &digest()); + write_u64(&mut unknown_state, 2, 1); + write_string(&mut unknown_state, 3, &digest()); + write_u64(&mut unknown_state, 4, 1_000); + write_u64(&mut unknown_state, 5, 9); + write_u64(&mut unknown_state, 6, 1); + assert_eq!( + CredentialMetadata::decode_wire(&unknown_state) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut zero_generation = Vec::new(); + write_string(&mut zero_generation, 1, &digest()); + write_u64(&mut zero_generation, 2, 0); + write_string(&mut zero_generation, 3, &digest()); + write_u64(&mut zero_generation, 4, 1_000); + write_u64(&mut zero_generation, 5, 1); + write_u64(&mut zero_generation, 6, 1); + assert_eq!( + CredentialMetadata::decode_wire(&zero_generation) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut zero_expiry = Vec::new(); + write_string(&mut zero_expiry, 1, &digest()); + write_u64(&mut zero_expiry, 2, 1); + write_string(&mut zero_expiry, 3, &digest()); + write_u64(&mut zero_expiry, 4, 0); + write_u64(&mut zero_expiry, 5, 1); + write_u64(&mut zero_expiry, 6, 1); + assert_eq!( + CredentialMetadata::decode_wire(&zero_expiry) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut deadline_after_expiry = Vec::new(); + write_string(&mut deadline_after_expiry, 1, "Credential/root-token"); + write_string(&mut deadline_after_expiry, 2, "op-123"); + write_string(&mut deadline_after_expiry, 3, "idem-1"); + write_u64(&mut deadline_after_expiry, 4, 500); + write_u64(&mut deadline_after_expiry, 5, 1_000); + assert_eq!( + CredentialRequest::decode_wire(&deadline_after_expiry) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut wrong_ref_type = Vec::new(); + write_string(&mut wrong_ref_type, 1, "User/alice"); + write_string(&mut wrong_ref_type, 2, "op-123"); + write_string(&mut wrong_ref_type, 3, "idem-1"); + write_u64(&mut wrong_ref_type, 4, 1_000); + write_u64(&mut wrong_ref_type, 5, 500); + assert_eq!( + CredentialRequest::decode_wire(&wrong_ref_type) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + + let mut empty_operation_id = Vec::new(); + write_string(&mut empty_operation_id, 1, "Credential/root-token"); + write_string(&mut empty_operation_id, 2, ""); + write_string(&mut empty_operation_id, 3, "idem-1"); + write_u64(&mut empty_operation_id, 4, 1_000); + write_u64(&mut empty_operation_id, 5, 500); + assert_eq!( + CredentialRequest::decode_wire(&empty_operation_id) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed + ); + } + + fn write_params( + output: &mut Vec, + schema_version: u64, + operation: u64, + max_token_bytes: u64, + sequence: u64, + expiry_unix_ms: u64, + deadline_unix_ms: u64, + ) { + write_string(output, 1, "Credential/root-token"); + write_string(output, 2, uid().as_str()); + write_u64(output, 3, 1); + write_string(output, 4, "Provider/guest-agent"); + write_u64(output, 5, 1); + write_string(output, 6, "d2b-guest-agent"); + write_u64(output, 7, operation); + write_u64(output, 8, expiry_unix_ms); + write_u64(output, 9, deadline_unix_ms); + write_string(output, 10, &digest()); + write_u64(output, 11, schema_version); + write_u64(output, 12, max_token_bytes); + write_u64(output, 13, sequence); + } + + #[test] + fn delivery_params_reject_out_of_range_fields() { + let cases = [ + (2, 1, 4_096, 1, 1_000, 500), + (1, 9, 4_096, 1, 1_000, 500), + (1, 1, 0, 1, 1_000, 500), + (1, 1, 4_096, 0, 1_000, 500), + (1, 1, 4_096, 1, 500, 1_000), + (1, 1, 4_096, 1, 0, 0), + ]; + for (schema_version, operation, max_token_bytes, sequence, expiry, deadline) in cases { + let mut bytes = Vec::new(); + write_params( + &mut bytes, + schema_version, + operation, + max_token_bytes, + sequence, + expiry, + deadline, + ); + assert_eq!( + DeliverySessionParams::decode_wire(&bytes) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Malformed, + "schema_version={schema_version} operation={operation} \ + max_token_bytes={max_token_bytes} sequence={sequence} \ + expiry={expiry} deadline={deadline}" + ); + } + } + + #[test] + fn wire_reader_rejects_non_canonical_and_truncated_primitives() { + assert_eq!(WireReader::new(&[]).key().unwrap(), None); + assert_eq!(WireReader::new(&[0xAC, 0x02]).varint().unwrap(), 300); + + assert_eq!( + WireReader::new(&[0x80, 0x00]).key().unwrap_err().code(), + CredentialServiceErrorCode::Malformed + ); + assert_eq!( + WireReader::new(&[0x00]).key().unwrap_err().code(), + CredentialServiceErrorCode::Malformed + ); + assert_eq!( + WireReader::new(&[0x80]).key().unwrap_err().code(), + CredentialServiceErrorCode::Malformed + ); + let mut overflow = [0xFF_u8; 10]; + overflow[9] = 0x02; + assert_eq!( + WireReader::new(&overflow).key().unwrap_err().code(), + CredentialServiceErrorCode::Malformed + ); + + let mut reader = WireReader::new(&[0x0A, 0x80, 0x00]); + assert_eq!(reader.key().unwrap(), Some((1, 2))); + assert_eq!( + reader.bytes().unwrap_err().code(), + CredentialServiceErrorCode::Malformed + ); + + let mut reader = WireReader::new(&[0x0A, 0x05, b'a']); + assert_eq!(reader.key().unwrap(), Some((1, 2))); + assert_eq!( + reader.bytes().unwrap_err().code(), + CredentialServiceErrorCode::Malformed + ); + + let mut reader = WireReader::new(&[0x0A, 0x01, 0xFF]); + assert_eq!(reader.key().unwrap(), Some((1, 2))); + assert_eq!( + reader.string().unwrap_err().code(), + CredentialServiceErrorCode::Malformed + ); + } + + #[derive(Debug)] + struct OversizeProbe; + + impl CredentialWire for OversizeProbe { + fn encode_wire(&self, output: &mut Vec) { + output.resize(MAX_CREDENTIAL_MESSAGE_BYTES + 1, 0); + } + + fn decode_wire(_bytes: &[u8]) -> Result { + Ok(Self) + } + } + + #[test] + fn outer_ceilings_reject_oversize_messages() { + assert_eq!( + encode_outer(&OversizeProbe).unwrap_err().code(), + CredentialServiceErrorCode::Oversize + ); + assert_eq!( + decode_outer::(&vec![0; MAX_CREDENTIAL_MESSAGE_BYTES + 1]) + .unwrap_err() + .code(), + CredentialServiceErrorCode::Oversize + ); + assert!( + decode_outer::(&vec![0; MAX_CREDENTIAL_MESSAGE_BYTES]).is_ok() + ); + + let encoded = encode_outer(&request()).unwrap(); + assert_eq!(decode_outer::(&encoded).unwrap(), request()); + } + + #[test] + fn sensitive_delivery_record_copies_then_zeroizes() { + let mut record = SensitiveDeliveryRecord::new(vec![1, 2, 3], 8).unwrap(); + let mut destination = [0_u8; 3]; + record.copy_to(&mut destination).unwrap(); + assert_eq!(destination, [1, 2, 3]); + assert!(!record.is_zeroized()); + record.clear(); + assert!(record.is_cleared()); + assert!(record.is_zeroized()); + assert_eq!( + record.copy_to(&mut destination).unwrap_err().code(), + CredentialServiceErrorCode::InvariantFailure + ); + } +} diff --git a/packages/d2b-contracts-provider/src/v3/credential_controller.rs b/packages/d2b-contracts-provider/src/v3/credential_controller.rs index d77e2569a..38094c874 100644 --- a/packages/d2b-contracts-provider/src/v3/credential_controller.rs +++ b/packages/d2b-contracts-provider/src/v3/credential_controller.rs @@ -1927,4 +1927,289 @@ mod tests { Err(CredentialObservabilityError::ForbiddenTelemetryField) ); } + + fn observe_input( + lease_state: Option, + provider_reachable: bool, + ) -> CredentialObserveInput { + CredentialObserveInput::new( + uid(), + lease_state, + 1, + [OperationClass::InspectMetadata], + permission(CredentialMethod::InspectMetadata), + provider_reachable, + 10, + 20, + ) + .unwrap() + } + + #[test] + fn observe_credential_matrix_is_closed() { + let cases = [ + (Some(CredentialLeaseState::Active), true, CredentialControllerDisposition::Pending), + (Some(CredentialLeaseState::Expired), true, CredentialControllerDisposition::Pending), + (Some(CredentialLeaseState::Revoked), true, CredentialControllerDisposition::Pending), + (Some(CredentialLeaseState::Unknown), true, CredentialControllerDisposition::Pending), + (None, true, CredentialControllerDisposition::Converged), + (Some(CredentialLeaseState::Active), false, CredentialControllerDisposition::Degraded), + (None, false, CredentialControllerDisposition::Degraded), + ]; + for (lease_state, provider_reachable, expected_disposition) in cases { + let decision = observe_credential(&observe_input(lease_state, provider_reachable)) + .unwrap(); + assert_eq!( + decision.disposition, + expected_disposition, + "lease_state={lease_state:?} provider_reachable={provider_reachable}" + ); + assert_eq!( + decision.outcome, + if provider_reachable { + CredentialControllerOutcome::Success + } else { + CredentialControllerOutcome::ProviderUnavailable + } + ); + assert_eq!( + decision.call.is_some(), + provider_reachable && lease_state.is_some() + ); + assert_eq!( + decision.conditions.provider_unavailable, + !provider_reachable + ); + assert_eq!( + decision.observe_after_ms, + Some(CREDENTIAL_OBSERVE_INTERVAL_MS) + ); + if provider_reachable && lease_state.is_some() { + assert_eq!( + decision.call.unwrap().method(), + CredentialMethod::InspectMetadata + ); + } + } + } + + fn reconcile_input( + policy: RotationPolicyClass, + now_unix_ms: u64, + prior_rotation_failure: Option, + ) -> CredentialReconcileInput { + CredentialReconcileInput::new( + uid(), + rotation(policy), + Some(CredentialLeaseState::Active), + 1, + 1_000, + [OperationClass::AcquireToken], + permission(CredentialMethod::AcquireToken), + true, + 1, + MAX_LOCAL_CREDENTIAL_LEASES, + now_unix_ms, + 2_000, + prior_rotation_failure, + ) + .unwrap() + } + + #[test] + fn reconcile_credential_rotation_retry_exhaustion_is_closed() { + let cases = [ + ( + RotationPolicyClass::Proactive, + 950, + Some(CredentialRetryState::new(3, 3).unwrap()), + CredentialControllerDisposition::Failed, + CredentialControllerOutcome::RotationFailed, + false, + ), + ( + RotationPolicyClass::Proactive, + 950, + Some(CredentialRetryState::new(1, 3).unwrap()), + CredentialControllerDisposition::Pending, + CredentialControllerOutcome::Success, + true, + ), + ( + RotationPolicyClass::Proactive, + 950, + None, + CredentialControllerDisposition::Pending, + CredentialControllerOutcome::Success, + true, + ), + ( + RotationPolicyClass::OnExpiry, + 950, + Some(CredentialRetryState::new(3, 3).unwrap()), + CredentialControllerDisposition::Converged, + CredentialControllerOutcome::Success, + false, + ), + ]; + for (policy, now, prior, expected_disposition, expected_outcome, expects_call) in cases { + let decision = + reconcile_credential(&reconcile_input(policy, now, prior)).unwrap(); + assert_eq!( + decision.disposition, + expected_disposition, + "policy={policy:?} now={now} prior={prior:?}" + ); + assert_eq!(decision.outcome, expected_outcome); + assert_eq!(decision.call.is_some(), expects_call); + assert_eq!( + decision.conditions.credential_ready, + !matches!(decision.disposition, CredentialControllerDisposition::Failed) + ); + } + } + + #[test] + fn lease_aggregate_counts_only_future_expiries_and_keeps_the_minimum() { + let cases = [ + (1_000, vec![], 0, 0), + (1_000, vec![500, 999, 1_000], 0, 0), + (1_000, vec![1_001], 1, 0), + (1_000, vec![2_000, 4_000, 3_000], 3, 1), + (1_000, vec![1_000_000], 1, 999), + ]; + for (now, expiries, active_leases, minimum_expiry_seconds) in cases { + let aggregate = CredentialLeaseAggregate::from_active_expiries( + CredentialProviderKind::Entra, + PlacementBinding::GuestAgent, + now, + expiries.clone(), + ) + .unwrap(); + assert_eq!(aggregate.provider, CredentialProviderKind::Entra); + assert_eq!(aggregate.placement, PlacementBinding::GuestAgent); + assert_eq!( + aggregate.active_leases, + active_leases, + "now={now} expiries={expiries:?}" + ); + assert_eq!(aggregate.minimum_expiry_seconds, minimum_expiry_seconds); + } + + let overflow: Vec = (1..=MAX_LOCAL_CREDENTIAL_LEASES + 1) + .map(|offset| 1_000 + u64::from(offset)) + .collect(); + assert_eq!( + CredentialLeaseAggregate::from_active_expiries( + CredentialProviderKind::Entra, + PlacementBinding::GuestAgent, + 1_000, + overflow, + ) + .unwrap_err(), + CredentialObservabilityError::ForbiddenTelemetryField + ); + } + + #[test] + fn health_derive_matrix_is_closed() { + let cases = [ + (true, 0, 0, Ok(CredentialControllerHealthState::Ready)), + (true, 5, 0, Ok(CredentialControllerHealthState::Ready)), + (true, 0, 1, Ok(CredentialControllerHealthState::Degraded)), + (true, 5, 3, Ok(CredentialControllerHealthState::Degraded)), + (false, 0, 0, Ok(CredentialControllerHealthState::Unavailable)), + (false, 5, 3, Ok(CredentialControllerHealthState::Unavailable)), + ( + true, + MAX_LOCAL_CREDENTIAL_LEASES + 1, + 0, + Err(CredentialControllerError::InvalidInput), + ), + ]; + for (reachable, active_leases, locked_count, expected) in cases { + let health = CredentialControllerHealth::derive(reachable, active_leases, locked_count); + match expected { + Ok(state) => { + let health = health.unwrap(); + assert_eq!(health.state, state); + assert_eq!(health.provider_process_reachable, reachable); + assert_eq!(health.active_leases, active_leases); + assert_eq!(health.locked_count, locked_count); + } + Err(error) => assert_eq!(health.unwrap_err(), error), + } + } + } + + #[test] + fn controller_event_renders_bounded_records_without_subject_identity() { + let digest = CredentialAuditDigest::parse(format!("sha256:{}", "a".repeat(64))).unwrap(); + let record = CredentialAuditRecord::controller_event( + CredentialProviderKind::Entra, + "dev", + digest.clone(), + CredentialAuditOperation::Rotation, + CredentialAuditOutcome::RotationFailed, + 3, + Some(2), + Some(digest.clone()), + ) + .unwrap(); + let wire = record.to_wire_record(); + assert!(wire.contains("provider=credential-entra"), "{wire}"); + assert!(wire.contains("zone=dev"), "{wire}"); + assert!(wire.contains("operation=rotation"), "{wire}"); + assert!(wire.contains("outcome=rotation-failed"), "{wire}"); + assert!(wire.contains("rotation_generation=3"), "{wire}"); + assert!(wire.contains("prior_rotation_generation=2"), "{wire}"); + assert!( + wire.contains(&format!("idempotency_key_digest={}", digest.as_str())), + "{wire}" + ); + assert!(!wire.contains("subject_digest="), "{wire}"); + + assert_eq!( + CredentialAuditRecord::controller_event( + CredentialProviderKind::Entra, + "dev", + digest.clone(), + CredentialAuditOperation::Rotation, + CredentialAuditOutcome::Success, + 0, + None, + None, + ) + .unwrap_err(), + CredentialObservabilityError::InvalidAuditRecord + ); + assert_eq!( + CredentialAuditRecord::controller_event( + CredentialProviderKind::Entra, + "dev", + digest.clone(), + CredentialAuditOperation::Rotation, + CredentialAuditOutcome::Success, + 2, + Some(0), + None, + ) + .unwrap_err(), + CredentialObservabilityError::InvalidAuditRecord + ); + assert_eq!( + CredentialAuditRecord::controller_event( + CredentialProviderKind::Entra, + "Zone/dev", + digest, + CredentialAuditOperation::Rotation, + CredentialAuditOutcome::Success, + 1, + None, + None, + ) + .unwrap_err(), + CredentialObservabilityError::ForbiddenTelemetryField + ); + } } From 44cb49a0d62888fdcc30ea122c92484c0cdc80aa Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:25:01 -0700 Subject: [PATCH 501/726] d2b: reuse the CLI receive buffer and pin exec exit-code contracts Reuse one zeroed 1 MiB receive buffer per CliSocket instead of allocating a fresh one for every frame, so the interactive shell poll path stops paying a 1 MiB allocation and memset per round trip. Envelope validation now shares the buffer's lock with the receive, so concurrent recv_frame calls cannot observe each other's datagrams. Extract the exec wait guest-exit-code extraction into a helper and cover it, the wait passthrough and out-of-range fallback, and the run --env key validation with unit and mock-daemon tests. --- changelog.d/w3-01-d2b-shell-buffer.md | 4 + packages/d2b/src/context.rs | 65 ++++++++----- packages/d2b/src/exec.rs | 134 +++++++++++++++++++++++++- 3 files changed, 174 insertions(+), 29 deletions(-) create mode 100644 changelog.d/w3-01-d2b-shell-buffer.md diff --git a/changelog.d/w3-01-d2b-shell-buffer.md b/changelog.d/w3-01-d2b-shell-buffer.md new file mode 100644 index 000000000..6577b28c1 --- /dev/null +++ b/changelog.d/w3-01-d2b-shell-buffer.md @@ -0,0 +1,4 @@ +### Changed + +- The CLI reuses one receive buffer per daemon connection instead of allocating and zeroing a fresh 1 MiB buffer for every frame, cutting per-poll allocation churn on the interactive shell path. +- `exec wait` now has tests pinning the guest exit-code passthrough and its out-of-range fallback, and `exec run --env` now has tests pinning the KEY=VALUE key validation, so regressions in either contract fail loudly instead of silently. \ No newline at end of file diff --git a/packages/d2b/src/context.rs b/packages/d2b/src/context.rs index 838b10dc1..930a7725f 100644 --- a/packages/d2b/src/context.rs +++ b/packages/d2b/src/context.rs @@ -9,7 +9,7 @@ use std::{ os::fd::{AsRawFd as _, OwnedFd}, path::{Path, PathBuf}, sync::{ - Arc, + Arc, Mutex, atomic::{AtomicBool, AtomicU64, Ordering}, }, time::{Duration, Instant}, @@ -441,12 +441,17 @@ pub(crate) fn socket_connectable(path: &Path) -> io::Result<()> { /// surfaces as [`io::ErrorKind::TimedOut`] for the caller to name. pub(crate) struct CliSocket { fd: AsyncFd, + /// Reusable receive scratch: the zeroed 1 MiB allocation happens once per + /// socket instead of once per received frame. The lock is held only + /// around the non-blocking recvmsg and never across an await. + recv_buf: Mutex>, } impl CliSocket { fn from_owned_fd(fd: OwnedFd) -> io::Result { Ok(Self { fd: AsyncFd::new(fd)?, + recv_buf: Mutex::new(Vec::new()), }) } @@ -516,26 +521,10 @@ impl CliSocket { } pub(crate) async fn recv_frame(&self, budget: Duration) -> io::Result> { - let frame = match tokio::time::timeout(budget, self.read_frame()).await { - Ok(result) => result?, - Err(_) => return Err(deadline_error("receive", budget)), - }; - if frame.len() < FRAME_PREFIX_BYTES { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "short frame from seqpacket socket", - )); - } - let expected = u32::from_le_bytes(frame[..FRAME_PREFIX_BYTES].try_into().expect("prefix")); - if expected as usize > MAX_FRAME_BYTES - || expected as usize + FRAME_PREFIX_BYTES != frame.len() - { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "malformed seqpacket frame", - )); + match tokio::time::timeout(budget, self.read_frame()).await { + Ok(result) => result, + Err(_) => Err(deadline_error("receive", budget)), } - Ok(frame[FRAME_PREFIX_BYTES..].to_vec()) } /// Send one datagram: a seqpacket send is atomic, so a partial write is a @@ -565,13 +554,24 @@ impl CliSocket { } } - /// Receive one datagram, refusing ancillary data and oversized frames. + /// Receive one datagram and extract its payload, refusing ancillary data, + /// oversized frames, and malformed envelopes. + /// + /// The receive, envelope validation, and payload extraction share one + /// lock on the socket's reusable scratch buffer, so concurrent calls + /// cannot observe each other's datagrams. The buffer keeps its full + /// length between calls, so the zeroed 1 MiB allocation happens once per + /// socket instead of once per received frame. async fn read_frame(&self) -> io::Result> { - let mut buffer = vec![0_u8; MAX_FRAME_BYTES + FRAME_PREFIX_BYTES]; loop { let mut ready = self.fd.readable().await?; match ready.try_io(|inner| { - let mut iov = [rustix::io::IoSliceMut::new(&mut buffer)]; + let mut buffer = self + .recv_buf + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()); + buffer.resize(MAX_FRAME_BYTES + FRAME_PREFIX_BYTES, 0); + let mut iov = [rustix::io::IoSliceMut::new(&mut buffer[..])]; let mut control_bytes = [0_u8; rustix::cmsg_space!(ScmRights(1))]; let mut control = rustix::net::RecvAncillaryBuffer::new(&mut control_bytes); let received = loop { @@ -603,8 +603,23 @@ impl CliSocket { "peer closed the socket", )); } - buffer.truncate(received.bytes); - Ok(std::mem::take(&mut buffer)) + if received.bytes < FRAME_PREFIX_BYTES { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "short frame from seqpacket socket", + )); + } + let expected = + u32::from_le_bytes(buffer[..FRAME_PREFIX_BYTES].try_into().expect("prefix")); + if expected as usize > MAX_FRAME_BYTES + || expected as usize + FRAME_PREFIX_BYTES != received.bytes + { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "malformed seqpacket frame", + )); + } + Ok(buffer[FRAME_PREFIX_BYTES..received.bytes].to_vec()) }) { Ok(result) => return result, // Spurious readiness: re-arm and wait again. diff --git a/packages/d2b/src/exec.rs b/packages/d2b/src/exec.rs index 9400ac39e..b68d4f594 100644 --- a/packages/d2b/src/exec.rs +++ b/packages/d2b/src/exec.rs @@ -254,14 +254,22 @@ fn wait( deadline, mode, )?; - let exit_code = value + let exit_code = guest_exit_code(&value); + context.emit(&value, mode)?; + Ok(exit_code.unwrap_or(0)) +} + +/// The CLI's exit-code contract for `exec wait`: the daemon's guest exit +/// code, preferring `guestExitCode` over the legacy `exitCode` spelling, +/// clamped to the 0-255 range a process exit status can represent, and +/// absent when the field is missing, non-integral, or out of range. +fn guest_exit_code(value: &Value) -> Option { + value .get("guestExitCode") .or_else(|| value.get("exitCode")) .and_then(Value::as_i64) .filter(|code| (0..=255).contains(code)) - .map(|code| code as i32); - context.emit(&value, mode)?; - Ok(exit_code.unwrap_or(0)) + .map(|code| code as i32) } fn status( @@ -443,6 +451,7 @@ fn with_unsafe_posture( mod tests { use super::*; use crate::context::OutputMode; + use std::sync::Arc; #[test] fn attach_rejects_non_ephemeral_resources_with_the_existing_exit_code() { @@ -482,4 +491,121 @@ mod tests { assert_eq!(error.exit_code, 2); assert!(error.message.contains("--tty")); } + + #[test] + fn guest_exit_code_prefers_guest_exit_code_and_clamps_to_0_255() { + let cases: &[(&str, Option)] = &[ + (r#"{"guestExitCode":42}"#, Some(42)), + (r#"{"exitCode":7}"#, Some(7)), + (r#"{"guestExitCode":3,"exitCode":9}"#, Some(3)), + (r#"{"guestExitCode":0}"#, Some(0)), + (r#"{"guestExitCode":255}"#, Some(255)), + (r#"{"guestExitCode":256}"#, None), + (r#"{"guestExitCode":-1}"#, None), + (r#"{"guestExitCode":"42"}"#, None), + (r#"{"exitCode":300}"#, None), + (r#"{"exitCode":"7"}"#, None), + (r#"{}"#, None), + ]; + for (json, expected) in cases { + let value: Value = serde_json::from_str(json).unwrap(); + assert_eq!( + guest_exit_code(&value), + *expected, + "guest_exit_code({json}) mismatch" + ); + } + } + + #[derive(Debug)] + struct MockDaemon { + response: Vec, + } + + impl crate::context::SessionClient for MockDaemon { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn invoke( + &self, + _request: &[u8], + _deadline: RequestDeadline, + ) -> Result, crate::context::TransportError> { + Ok(self.response.clone()) + } + } + + fn wait_with_daemon_response(response: &[u8]) -> Result { + let client = Arc::new(MockDaemon { + response: response.to_vec(), + }); + let context = ZoneContext::with_client("dev", "/run/d2b/public.sock", client).unwrap(); + let args = ExecRefArgs { + resource_ref: "EphemeralProcess/shell".to_owned(), + }; + crate::with_test_stdout_capture(|| { + wait( + &context, + &args, + OutputMode::Json, + ZoneContext::deadline(Some("30s")).unwrap(), + ) + }) + .0 + } + + #[test] + fn wait_passes_the_guest_exit_code_through_to_the_cli_exit_status() { + assert_eq!( + wait_with_daemon_response(br#"{"guestExitCode":42,"type":"waitOk"}"#).unwrap(), + 42 + ); + assert_eq!( + wait_with_daemon_response(br#"{"exitCode":7,"type":"waitOk"}"#).unwrap(), + 7 + ); + } + + #[test] + fn wait_defaults_to_zero_when_the_guest_exit_code_is_missing_or_out_of_range() { + assert_eq!( + wait_with_daemon_response(br#"{"guestExitCode":300,"type":"waitOk"}"#).unwrap(), + 0 + ); + assert_eq!(wait_with_daemon_response(br#"{"type":"waitOk"}"#).unwrap(), 0); + } + + #[test] + fn validate_env_accepts_only_key_value_pairs_with_bounded_alnum_keys() { + let cases: &[(&[&str], bool)] = &[ + (&[], true), + (&["KEY=value"], true), + (&["KEY="], true), + (&["_UNDERSCORE_9=x"], true), + (&["KEY==value"], true), + (&["KEY=a=b"], true), + (&["=value"], false), + (&["KEY"], false), + (&["KEY-WITH-DASH=1"], false), + (&["KEY WITH SPACE=1"], false), + (&["k=1", "=v"], false), + ]; + for (env, expected) in cases { + let env: Vec = env.iter().map(|entry| entry.to_string()).collect(); + assert_eq!( + validate_env(&env).is_ok(), + *expected, + "validate_env({env:?}) should be {}", + if *expected { "accepted" } else { "rejected" } + ); + } + } + + #[test] + fn validate_env_bounds_key_length_at_64_bytes() { + let at_limit: Vec = vec![format!("{}=1", "k".repeat(64))]; + assert!(validate_env(&at_limit).is_ok(), "a 64-byte key is valid"); + let over_limit: Vec = vec![format!("{}=1", "k".repeat(65))]; + let error = validate_env(&over_limit).unwrap_err(); + assert_eq!(error.exit_code, 2); + assert!(error.message.contains("key is invalid")); + } } From 944012b14548258fbdfcee867b2370217ec43bf0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:25:28 -0700 Subject: [PATCH 502/726] d2b-broker: nest cell records and defer ACL grants to the pool - CellStore records now use the durable file's nested cell -> invocation layout with the principal inside the record, so contains/payload/remove/ keys/clear are O(log n) instead of whole-map scans (RS-0758). - projection_digest hex-encodes via a lookup table into one pre-sized String instead of one allocation per byte (RS-0759). - handle_open_cgroup_dir renders the canonical path once and reuses it for the audit record and the outcome (RS-0760). - The embedded store-view posture contract is parsed once into a LazyLock instead of on every posture pass and row (RS-0761). - The invocation-id counters use Ordering::Relaxed; no reader synchronizes on the returned value (RS-0809). - The initial obs-vsock ACL grant runs on the bounded dispatch pool like the retry path, so spawn no longer stalls an executor worker on the setfacl shellout (RS-0839). --- changelog.d/w3-03-broker-perf-conc-async.md | 13 + packages/d2b-broker/src/envelope/mod.rs | 4 +- packages/d2b-broker/src/live_handlers.rs | 30 +- packages/d2b-broker/src/ops/cgroup.rs | 5 +- packages/d2b-broker/src/ops/nft.rs | 14 +- .../d2b-broker/src/ops/store_view_posture.rs | 13 +- packages/d2b-broker/src/state_cells.rs | 289 +++++++++--------- 7 files changed, 197 insertions(+), 171 deletions(-) create mode 100644 changelog.d/w3-03-broker-perf-conc-async.md diff --git a/changelog.d/w3-03-broker-perf-conc-async.md b/changelog.d/w3-03-broker-perf-conc-async.md new file mode 100644 index 000000000..bfd4261ae --- /dev/null +++ b/changelog.d/w3-03-broker-perf-conc-async.md @@ -0,0 +1,13 @@ +### Changed + +- The broker's state-cell store now keeps records in the same nested + cell -> invocation layout its durable file uses, so partial-key lookups + (contains, payload, remove, keys, clear) are O(log n) instead of scanning + every record. +- The initial obs-vsock ACL grant on runner spawn now runs on the broker's + bounded dispatch pool like the retry path, so a spawn no longer stalls an + executor worker on the setfacl shellout. +- The broker re-parses the embedded store-view posture contract once per + process instead of once per posture pass and row, and drops per-call + allocations on the nftables projection digest, cgroup-open audit records, + and the invocation-id counter. \ No newline at end of file diff --git a/packages/d2b-broker/src/envelope/mod.rs b/packages/d2b-broker/src/envelope/mod.rs index aa4987b8e..5120a8331 100644 --- a/packages/d2b-broker/src/envelope/mod.rs +++ b/packages/d2b-broker/src/envelope/mod.rs @@ -1163,7 +1163,7 @@ impl BrokerEnvelope { ) -> Result { let invocation_id = format!( "invocation-{}", - self.invocations.fetch_add(1, Ordering::AcqRel) + self.invocations.fetch_add(1, Ordering::Relaxed) ); // The root chain: the broker-minted invocation id and the caller's // attested identity. A root call is authorized against the caller's @@ -2168,7 +2168,7 @@ mod tests { .expect("read forwarded call") else { continue; }; - observed.fetch_add(1, Ordering::AcqRel); + observed.fetch_add(1, Ordering::Relaxed); let (response, response_fds) = answer_from( dispatcher.as_ref(), &request.operation, diff --git a/packages/d2b-broker/src/live_handlers.rs b/packages/d2b-broker/src/live_handlers.rs index 042aea47e..943b37545 100644 --- a/packages/d2b-broker/src/live_handlers.rs +++ b/packages/d2b-broker/src/live_handlers.rs @@ -1745,7 +1745,7 @@ fn spawn_obs_vsock_acl_retry(uid: u32, socket: PathBuf) { }); } -fn refresh_obs_vsock_acl(plan: &SpawnRunnerPlan) -> Result<(), LiveHandlerError> { +async fn refresh_obs_vsock_acl(plan: &SpawnRunnerPlan) -> Result<(), LiveHandlerError> { if !matches!( plan.seccomp_policy_ref.as_deref(), Some("w1-vsock-relay" | "w1-otel-host-bridge") @@ -1756,15 +1756,33 @@ fn refresh_obs_vsock_acl(plan: &SpawnRunnerPlan) -> Result<(), LiveHandlerError> return Ok(()); }; let uid = plan.uid; - match grant_obs_vsock_acl_once(uid, &socket) { - Ok(true) => Ok(()), - Ok(false) => { + // The initial attempt is a setfacl shellout, which has no async form; + // it runs on the broker's bounded dispatch pool like every other + // kernel-path step - the same pool the retry path uses - so a socket + // that is not there yet holds no worker and no thread. A handler + // driven outside a serving broker (tests) has no pool to defer to and + // runs the attempt inline, exactly as before. + let attempt = match crate::runtime::broker_background() { + Some(background) => { + let socket = socket.clone(); + background + .dispatches + .run(move || grant_obs_vsock_acl_once(uid, &socket)) + .await + } + None => Ok(grant_obs_vsock_acl_once(uid, &socket)), + }; + match attempt { + Ok(Ok(true)) => Ok(()), + Ok(Ok(false)) => { spawn_obs_vsock_acl_retry(uid, socket); Ok(()) } - Err(detail) => Err(LiveHandlerError::SpawnFailed { + Ok(Err(detail)) => Err(LiveHandlerError::SpawnFailed { detail: format!("refresh obs-vsock ACL for runner uid {uid}: {detail}"), }), + // The pool is gone, so the broker is shutting down. + Err(_) => Ok(()), } } @@ -2098,7 +2116,7 @@ async fn refresh_spawn_runner_acls( } })?; } - refresh_obs_vsock_acl(plan)?; + refresh_obs_vsock_acl(plan).await?; refresh_component_session_vsock_acl(plan)?; Ok(()) diff --git a/packages/d2b-broker/src/ops/cgroup.rs b/packages/d2b-broker/src/ops/cgroup.rs index 9159b91ee..4c753fba0 100644 --- a/packages/d2b-broker/src/ops/cgroup.rs +++ b/packages/d2b-broker/src/ops/cgroup.rs @@ -338,7 +338,8 @@ where }; fields.path_class = Some(class); - fields.cgroup_id = Some(canonical_path.display().to_string()); + let cgroup_id = canonical_path.display().to_string(); + fields.cgroup_id = Some(cgroup_id.clone()); if !is_under_slice(&canonical_path, context.slice_path()) { audit.record( @@ -365,7 +366,7 @@ where audit.record("OpenCgroupDir", AuditDecision::Allowed, &fields, None); Ok(OpenCgroupDirOutcome { cgroup_path: canonical_path.clone(), - cgroup_id: canonical_path.display().to_string(), + cgroup_id, path_class: class, }) } diff --git a/packages/d2b-broker/src/ops/nft.rs b/packages/d2b-broker/src/ops/nft.rs index 19ee833af..82e548dd8 100644 --- a/packages/d2b-broker/src/ops/nft.rs +++ b/packages/d2b-broker/src/ops/nft.rs @@ -781,13 +781,15 @@ fn render_projection_mutation( } fn projection_digest(bytes: &[u8]) -> String { + const HEX: &[u8; 16] = b"0123456789abcdef"; let raw: [u8; 32] = Sha256Hasher::digest(bytes).into(); - format!( - "sha256:{}", - raw.iter() - .map(|byte| format!("{byte:02x}")) - .collect::() - ) + let mut digest = String::with_capacity("sha256:".len() + raw.len() * 2); + digest.push_str("sha256:"); + for byte in raw { + digest.push(HEX[(byte >> 4) as usize] as char); + digest.push(HEX[(byte & 0x0f) as usize] as char); + } + digest } struct ProjectionLock(std::fs::File); diff --git a/packages/d2b-broker/src/ops/store_view_posture.rs b/packages/d2b-broker/src/ops/store_view_posture.rs index 6809f79d4..6986502f7 100644 --- a/packages/d2b-broker/src/ops/store_view_posture.rs +++ b/packages/d2b-broker/src/ops/store_view_posture.rs @@ -19,6 +19,7 @@ use std::os::fd::AsFd; use std::os::unix::fs::PermissionsExt; use std::path::{Path, PathBuf}; +use std::sync::LazyLock; use d2b_host::hardlink_farm; use nix::unistd::{Gid, Uid, chown}; @@ -112,6 +113,15 @@ enum PathKind { /// validated live by `tests/host-integration/state-posture-contract.nix`. const STATE_POSTURE_CONTRACT: &str = include_str!("state-posture-contract.json"); +/// The embedded contract, parsed once. The document is ~600 lines and every +/// posture pass resolves every row (per-VM passes re-resolve per row too), +/// so a per-call parse would re-parse the same document many times per sync +/// pass; the cached parse keeps the fail-closed error path intact. +static CONTRACT: LazyLock> = LazyLock::new(|| { + serde_json::from_str(STATE_POSTURE_CONTRACT) + .map_err(|err| contract_error(format!("parse: {err}"))) +}); + const STORE_VIEW_TREE_ID: &str = "guest-store-view"; #[derive(Debug, serde::Deserialize)] @@ -195,8 +205,7 @@ fn contract_store_view_levels( principals: &Principals, vm: &str, ) -> Result, PostureError> { - let contract: ContractFile = serde_json::from_str(STATE_POSTURE_CONTRACT) - .map_err(|err| contract_error(format!("parse: {err}")))?; + let contract: &ContractFile = CONTRACT.as_ref().map_err(Clone::clone)?; if contract.schema_version != 1 { return Err(contract_error(format!( "unsupported schemaVersion {}", diff --git a/packages/d2b-broker/src/state_cells.rs b/packages/d2b-broker/src/state_cells.rs index 55681b0c4..76c1992d7 100644 --- a/packages/d2b-broker/src/state_cells.rs +++ b/packages/d2b-broker/src/state_cells.rs @@ -2,12 +2,14 @@ //! //! Plan U3 / KTD3 / KD4. One generic mechanism hosts the broker-owned state //! the per-family typed registries used to own. Cells are keyed -//! `(cell, invocation_id, initiating_principal)`; compare-and-consume runs -//! under the broker's single-process lock (the broker is the cell owner, so -//! the lock is single-process by construction). A repeated invocation id -//! replays the recorded outcome for the same initiating principal only - -//! invocation ids appear in audit records and are not secrets, so they never -//! gate one-time grants alone. +//! `(cell, invocation_id)` with the initiating principal inside the record - +//! the same nested layout the durable file uses, so partial-key lookups are +//! O(log n) instead of a whole-map scan; compare-and-consume runs under the +//! broker's single-process lock (the broker is the cell owner, so the lock +//! is single-process by construction). A repeated invocation id replays the +//! recorded outcome for the same initiating principal only - invocation ids +//! appear in audit records and are not secrets, so they never gate one-time +//! grants alone. //! //! Durability facets ride the committed Operation rows //! ([`crate::catalog::CellDurability`], regenerated from @@ -78,28 +80,6 @@ const CELL_WORKER_QUEUE_DEPTH: usize = 256; /// arms the seam retires later will carry the attested caller instead. pub const BROKER_PRINCIPAL: &str = "broker"; -/// One keyed cell record identity. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct CellKey { - /// The declared cell name (the committed row's `stateCell.cell`). - pub cell: String, - /// The caller-supplied per-invocation identity (the operation's - /// invocation id; appears in audit records, never a secret). - pub invocation_id: String, - /// The initiating principal, as attested at the envelope boundary. - pub principal: String, -} - -impl CellKey { - fn new(cell: &str, invocation_id: &str, principal: &str) -> Self { - Self { - cell: cell.to_owned(), - invocation_id: invocation_id.to_owned(), - principal: principal.to_owned(), - } - } -} - /// The recorded outcome of one cell record. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CellOutcome { @@ -200,6 +180,11 @@ impl Default for RetentionPolicy { /// One in-process cell record. struct CellRecord { + /// The initiating principal, as attested at the envelope boundary. + /// Rides inside the record (not the key) so the in-memory layout + /// mirrors the durable file's nested cell -> invocation shape and + /// partial-key lookups stay O(log n). + principal: String, outcome: CellOutcome, /// A live in-process claim. Never persisted: a restarted owner reloads /// durable records unclaimed, which is what turns a crash-stale record @@ -314,7 +299,10 @@ enum CellCommand { struct CellWorkerState { /// The durable root directory, when the store is file-backed. root: Option, - records: BTreeMap, + /// Cell name -> invocation id -> record, the same nested layout the + /// durable file uses (principal inside the record), so partial-key + /// lookups are O(log n) rather than a whole-map scan. + records: BTreeMap>, retention: RetentionPolicy, /// Latched by a panic inside a mutation critical section; `consume` and /// `complete` refuse with [`CellStoreError::Poisoned`] once set. @@ -755,8 +743,8 @@ fn cell_handle(state: &mut CellWorkerState, command: CellCommand) -> LoopControl } => { let found = state .records - .keys() - .any(|key| key.cell == cell && key.invocation_id == invocation_id); + .get(&cell) + .is_some_and(|invocations| invocations.contains_key(&invocation_id)); let _ = reply.send(found); LoopControl::Continue } @@ -767,9 +755,9 @@ fn cell_handle(state: &mut CellWorkerState, command: CellCommand) -> LoopControl } => { let payload = state .records - .range(..) - .find(|(key, _)| key.cell == cell && key.invocation_id == invocation_id) - .and_then(|(_, record)| record.payload.clone()); + .get(&cell) + .and_then(|invocations| invocations.get(&invocation_id)) + .and_then(|record| record.payload.clone()); let _ = reply.send(payload); LoopControl::Continue } @@ -778,47 +766,41 @@ fn cell_handle(state: &mut CellWorkerState, command: CellCommand) -> LoopControl invocation_id, reply, } => { - let keys: Vec = state - .records - .keys() - .filter(|key| key.cell == cell && key.invocation_id == invocation_id) - .cloned() - .collect(); - let removed = !keys.is_empty(); - for key in keys { - state.records.remove(&key); - } + let removed = match state.records.get_mut(&cell) { + Some(invocations) => { + let removed = invocations.remove(&invocation_id).is_some(); + if removed && invocations.is_empty() { + state.records.remove(&cell); + } + removed + } + None => false, + }; let _ = reply.send(removed); LoopControl::Continue } CellCommand::Keys { cell, reply } => { - let mut ids: Vec = state + // Invocation ids are unique per cell, so the inner map's own + // sorted order is the answer; no sort/dedup pass needed. + let ids: Vec = state .records - .keys() - .filter(|key| key.cell == cell) - .map(|key| key.invocation_id.clone()) - .collect(); - ids.sort(); - ids.dedup(); + .get(&cell) + .map(|invocations| invocations.keys().cloned().collect()) + .unwrap_or_default(); let _ = reply.send(ids); LoopControl::Continue } CellCommand::Clear { cell, reply } => { - let keys: Vec = state + let count = state .records - .keys() - .filter(|key| key.cell == cell) - .cloned() - .collect(); - let count = keys.len(); - for key in keys { - state.records.remove(&key); - } + .remove(&cell) + .map(|invocations| invocations.len()) + .unwrap_or(0); let _ = reply.send(count); LoopControl::Continue } CellCommand::RecordCount { reply } => { - let _ = reply.send(state.records.len()); + let _ = reply.send(state.records.values().map(|invocations| invocations.len()).sum()); LoopControl::Continue } #[cfg(test)] @@ -826,10 +808,10 @@ fn cell_handle(state: &mut CellWorkerState, command: CellCommand) -> LoopControl // A mutation critical section that panics mid-way: the record is // inserted (the corrupted partial mutation) before the panic, so // the owner's in-memory state is dirty when the latch trips. - let key = CellKey::new("injected-panic", "injected", BROKER_PRINCIPAL); - state.records.insert( - key, + state.records.entry("injected-panic".to_owned()).or_default().insert( + "injected".to_owned(), CellRecord { + principal: BROKER_PRINCIPAL.to_owned(), outcome: CellOutcome::Unknown, claimed: true, durability: CellDurability::OneTime, @@ -852,10 +834,10 @@ fn cell_handle(state: &mut CellWorkerState, command: CellCommand) -> LoopControl // "process" dies before the Granted reply can cross. let now = now_ms(); enforce_retention_locked(&mut state.records, state.retention, now); - let key = CellKey::new(&cell, &invocation_id, &principal); - state.records.insert( - key, + state.records.entry(cell).or_default().insert( + invocation_id, CellRecord { + principal, outcome: CellOutcome::Unknown, claimed: true, durability, @@ -876,24 +858,26 @@ fn cell_handle(state: &mut CellWorkerState, command: CellCommand) -> LoopControl } /// Durable record snapshot (one-time cells only) as the file payload. -fn durable_snapshot(records: &BTreeMap) -> DurableFile { +fn durable_snapshot(records: &BTreeMap>) -> DurableFile { let mut by_cell: BTreeMap> = BTreeMap::new(); - for (key, record) in records { - if record.durability != CellDurability::OneTime || record.payload.is_some() { - continue; - } - by_cell.entry(key.cell.clone()).or_default().insert( - key.invocation_id.clone(), - DurableRecord { - principal: key.principal.clone(), - outcome: match record.outcome { - CellOutcome::Unknown => "unknown".to_owned(), - CellOutcome::Completed => "completed".to_owned(), + for (cell, invocations) in records { + for (invocation_id, record) in invocations { + if record.durability != CellDurability::OneTime || record.payload.is_some() { + continue; + } + by_cell.entry(cell.clone()).or_default().insert( + invocation_id.clone(), + DurableRecord { + principal: record.principal.clone(), + outcome: match record.outcome { + CellOutcome::Unknown => "unknown".to_owned(), + CellOutcome::Completed => "completed".to_owned(), + }, + consumed_at_ms: record.consumed_ms, + completed_at_ms: record.completed_ms, }, - consumed_at_ms: record.consumed_ms, - completed_at_ms: record.completed_ms, - }, - ); + ); + } } DurableFile { version: DURABLE_VERSION, @@ -902,7 +886,7 @@ fn durable_snapshot(records: &BTreeMap) -> DurableFile { } #[allow(clippy::disallowed_methods, reason = "dedicated bounded worker per plan R4")] -fn load(root: &Path) -> Result, CellStoreError> { +fn load(root: &Path) -> Result>, CellStoreError> { let path = cell_durable_path(root); let bytes = match fs::read(&path) { Ok(bytes) => bytes, @@ -921,7 +905,7 @@ fn load(root: &Path) -> Result, CellStoreError> { file.version ))); } - let mut records = BTreeMap::new(); + let mut records: BTreeMap> = BTreeMap::new(); for (cell, invocations) in file.records { for (invocation_id, record) in invocations { let outcome = match record.outcome.as_str() { @@ -934,9 +918,10 @@ fn load(root: &Path) -> Result, CellStoreError> { ))); } }; - records.insert( - CellKey::new(&cell, &invocation_id, &record.principal), + records.entry(cell.clone()).or_default().insert( + invocation_id, CellRecord { + principal: record.principal, outcome, claimed: false, durability: CellDurability::OneTime, @@ -960,7 +945,7 @@ fn load(root: &Path) -> Result, CellStoreError> { #[allow(clippy::disallowed_methods, reason = "dedicated bounded worker per plan R4")] fn persist_locked( root: Option<&Path>, - records: &BTreeMap, + records: &BTreeMap>, ) -> Result<(), CellStoreError> { let Some(root) = root else { return Ok(()); @@ -1032,50 +1017,48 @@ fn persist_locked( /// /// One-time consumed markers and payload-bearing live state are exempt. fn enforce_retention_locked( - records: &mut BTreeMap, + records: &mut BTreeMap>, retention: RetentionPolicy, now: u64, ) { let stale_before = now.saturating_sub(retention.outcome_ttl_ms); - records.retain(|_, record| { - if record.durability != CellDurability::Ephemeral - || record.payload.is_some() - || record.claimed - { - return true; - } - record.consumed_ms >= stale_before - }); - let mut per_cell: BTreeMap> = BTreeMap::new(); - for (key, record) in records.iter() { - if record.durability == CellDurability::Ephemeral - && record.payload.is_none() - && !record.claimed - { - per_cell - .entry(key.cell.clone()) - .or_default() - .push(key.clone()); - } + for invocations in records.values_mut() { + invocations.retain(|_, record| { + if record.durability != CellDurability::Ephemeral + || record.payload.is_some() + || record.claimed + { + return true; + } + record.consumed_ms >= stale_before + }); } - for keys in per_cell.into_values() { - let evict = keys + for invocations in records.values_mut() { + // The per-cell cap counts replayable outcome records only: one-time + // consumed markers and payload-bearing live state are exempt in both + // dimensions, so they never push an eligible record off the cap. + let mut ordered: Vec<(String, u64)> = invocations + .iter() + .filter(|(_, record)| { + record.durability == CellDurability::Ephemeral + && record.payload.is_none() + && !record.claimed + }) + .map(|(id, record)| (id.clone(), record.consumed_ms)) + .collect(); + let evict = ordered .len() .saturating_sub(retention.max_ephemeral_outcome_records); if evict == 0 { continue; } - let mut ordered = keys; - ordered.sort_by_key(|key| { - records - .get(key) - .map(|record| record.consumed_ms) - .unwrap_or(0) - }); - for key in ordered.into_iter().take(evict) { - records.remove(&key); + ordered.sort_by_key(|(_, consumed_ms)| *consumed_ms); + for (id, _) in ordered.into_iter().take(evict) { + invocations.remove(&id); } } + // Keep the outer map free of empty cells left by eviction. + records.retain(|_, invocations| !invocations.is_empty()); } fn now_ms() -> u64 { @@ -1092,7 +1075,7 @@ fn now_ms() -> u64 { /// before `Granted` is returned, so a crash between the commit and the /// effect reconciles on retry instead of granting twice. fn consume_locked( - records: &mut BTreeMap, + records: &mut BTreeMap>, root: Option<&Path>, retention: RetentionPolicy, cell: &str, @@ -1104,18 +1087,16 @@ fn consume_locked( // the consume below may create one, so stale records go first. let now = now_ms(); enforce_retention_locked(records, retention, now); - let key = CellKey::new(cell, invocation_id, principal); - // The principal is part of the key: a record for the same cell + + // The principal rides inside the record: a record for the same cell + // invocation id under a different principal must refuse the replay, // never fall through to a fresh grant (invocation ids alone never // gate one-time grants, KTD3). - let Some(owner) = records - .keys() - .find(|candidate| candidate.cell == cell && candidate.invocation_id == invocation_id) - else { - records.insert( - key, + let invocations = records.entry(cell.to_owned()).or_default(); + let Some(owner) = invocations.get(invocation_id) else { + invocations.insert( + invocation_id.to_owned(), CellRecord { + principal: principal.to_owned(), outcome: CellOutcome::Unknown, claimed: true, durability, @@ -1129,10 +1110,10 @@ fn consume_locked( } return Ok(ConsumeDecision::Granted); }; - if owner.principal != key.principal { + if owner.principal != principal { return Ok(ConsumeDecision::ForeignPrincipal); } - let existing = records.get(&key).expect("owner is the requested key"); + let existing = invocations.get(invocation_id).expect("owner is the requested key"); if existing.claimed { return Ok(ConsumeDecision::InProgress); } @@ -1141,7 +1122,7 @@ fn consume_locked( // A durable unknown left by a crashed owner: the retried // invocation reconciles (idempotently) under its invocation id. CellOutcome::Unknown => { - let record = records.get_mut(&key).expect("key present"); + let record = invocations.get_mut(invocation_id).expect("key present"); record.claimed = true; if durability == CellDurability::OneTime { persist_locked(root, records)?; @@ -1153,7 +1134,7 @@ fn consume_locked( /// Record completion for one claimed key, on the owner. fn complete_locked( - records: &mut BTreeMap, + records: &mut BTreeMap>, root: Option<&Path>, retention: RetentionPolicy, cell: &str, @@ -1162,17 +1143,16 @@ fn complete_locked( ) -> Result<(), CellStoreError> { let now = now_ms(); enforce_retention_locked(records, retention, now); - let key = CellKey::new(cell, invocation_id, principal); - let Some(owner) = records - .keys() - .find(|candidate| candidate.cell == cell && candidate.invocation_id == invocation_id) - else { + let Some(invocations) = records.get_mut(cell) else { return Err(CellStoreError::MissingRecord); }; - if owner.principal != key.principal { + let Some(owner) = invocations.get(invocation_id) else { + return Err(CellStoreError::MissingRecord); + }; + if owner.principal != principal { return Err(CellStoreError::ForeignPrincipal); } - let record = records.get_mut(&key).expect("owner is the requested key"); + let record = invocations.get_mut(invocation_id).expect("owner is the requested key"); if record.outcome == CellOutcome::Completed && record.completed_ms.is_some() { return Ok(()); } @@ -1187,26 +1167,29 @@ fn complete_locked( /// Insert one payload record into an ephemeral cell, on the owner. fn insert_payload_locked( - records: &mut BTreeMap, + records: &mut BTreeMap>, retention: RetentionPolicy, cell: &str, invocation_id: &str, principal: &str, payload: Arc, ) -> Result<(), CellStoreError> { - let key = CellKey::new(cell, invocation_id, principal); enforce_retention_locked(records, retention, now_ms()); - records.insert( - key, - CellRecord { - outcome: CellOutcome::Unknown, - claimed: false, - durability: CellDurability::Ephemeral, - payload: Some(payload), - consumed_ms: now_ms(), - completed_ms: None, - }, - ); + records + .entry(cell.to_owned()) + .or_default() + .insert( + invocation_id.to_owned(), + CellRecord { + principal: principal.to_owned(), + outcome: CellOutcome::Unknown, + claimed: false, + durability: CellDurability::Ephemeral, + payload: Some(payload), + consumed_ms: now_ms(), + completed_ms: None, + }, + ); Ok(()) } From 1da992306d48928b1227b343bf254bca8b6b7eac Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:25:48 -0700 Subject: [PATCH 503/726] d2b-provider-config-nixos: parse typed requests once at the RPC boundary The ttrpc handler now decodes each request into its typed form once and validates the typed value, dropping the redundant re-parse in validate_operation and the admission-time base64 decode of Stage payloads (up to ~683 KiB); the backend hop still re-checks the original Value, and the staging store enforces document bounds on apply. validate_operation keeps its Value-based signature for the daemon operator route and now deserializes borrowed instead of cloning the payload tree. Add integration coverage for the sync-document integrity contract (forged digest or byte count fails with config-document-encoding-failed, over-bound base64 with config-request-invalid) and for closed JSON admission (unknown keys and wrong field types fail with config-request-invalid). --- changelog.d/w3-16-config-nixos-parse-tests.md | 6 + .../src/controller.rs | 121 ++++++++++++++---- .../d2b-provider-config-nixos/src/ttrpc.rs | 32 ++++- .../tests/config_lifecycle.rs | 50 +++++++- .../tests/service_contract.rs | 25 ++++ 5 files changed, 206 insertions(+), 28 deletions(-) create mode 100644 changelog.d/w3-16-config-nixos-parse-tests.md diff --git a/changelog.d/w3-16-config-nixos-parse-tests.md b/changelog.d/w3-16-config-nixos-parse-tests.md new file mode 100644 index 000000000..b9a09359b --- /dev/null +++ b/changelog.d/w3-16-config-nixos-parse-tests.md @@ -0,0 +1,6 @@ +# `w3-16-config-nixos-parse-tests.md` + +### Changed + +- The config-nixos RPC boundary now decodes each request into its typed form once and validates the typed value, removing a redundant JSON parse and the admission-time base64 decode of Stage payloads (up to ~683 KiB); Stage document bounds are still enforced when the staging store applies the document, and the backend hop keeps re-checking the original payload. +- Closed JSON admission is now covered by integration tests: a sync response with a forged digest or byte count fails with `config-document-encoding-failed`, an over-bound base64 payload with `config-request-invalid`, and unknown keys or wrong field types in a request payload with `config-request-invalid`. \ No newline at end of file diff --git a/packages/d2b-provider-config-nixos/src/controller.rs b/packages/d2b-provider-config-nixos/src/controller.rs index 044306c3c..4c5ed8d7a 100644 --- a/packages/d2b-provider-config-nixos/src/controller.rs +++ b/packages/d2b-provider-config-nixos/src/controller.rs @@ -4,6 +4,7 @@ use std::fmt; use base64::{Engine as _, engine::general_purpose::STANDARD}; use d2b_contracts_resource::v3::ResourceRef; +use serde::Deserialize; use sha2::{Digest, Sha256}; use crate::{ @@ -315,13 +316,17 @@ impl ConfigService { /// Validate a typed operation payload against the closed service. /// + /// The provider RPC boundary decodes the typed request once and calls the + /// per-operation typed validators directly; this Value-based entry serves + /// the daemon operator route, which decodes the payload after admission. + /// /// # Errors /// /// Returns [`ConfigError::InvalidRequest`] when the payload does not /// decode or names a wrong Guest or identifier, [`ConfigError::InvalidView`] - /// for a malformed diff view, [`ConfigError::InvalidDestination`] for a - /// malformed approval destination, and the document bounds errors for a - /// Stage payload. + /// for a malformed diff view, and [`ConfigError::InvalidDestination`] for + /// a malformed approval destination. Stage document bounds are enforced + /// when the staging store decodes the document on apply. pub fn validate_operation( &self, operation: ConfigOperation, @@ -329,44 +334,112 @@ impl ConfigService { ) -> Result<(), ConfigError> { match operation { ConfigOperation::ReadGuestConfig => { - let request = serde_json::from_value::(payload.clone()) + let request = ConfigSyncRequest::deserialize(payload) .map_err(|_| ConfigError::InvalidRequest)?; - validate_guest_ref(&request.guest_ref)?; - validate_identifier(&request.identifier) + self.validate_read_guest_config(&request) } ConfigOperation::Stage => { - let request = serde_json::from_value::(payload.clone()) + let request = ConfigStageRequest::deserialize(payload) .map_err(|_| ConfigError::InvalidRequest)?; - validate_guest_ref(&request.guest_ref)?; - validate_identifier(&request.identifier)?; - request.document().map(|_| ()) + self.validate_stage(&request) } ConfigOperation::Diff => { - let request = serde_json::from_value::(payload.clone()) + let request = ConfigDiffRequest::deserialize(payload) .map_err(|_| ConfigError::InvalidRequest)?; - validate_guest_ref(&request.guest_ref)?; - validate_identifier(&request.identifier)?; - validate_view_identifier(&request.against) + self.validate_diff(&request) } ConfigOperation::Approve => { - let request = serde_json::from_value::(payload.clone()) + let request = ConfigApproveRequest::deserialize(payload) .map_err(|_| ConfigError::InvalidRequest)?; - validate_guest_ref(&request.guest_ref)?; - validate_identifier(&request.identifier)?; - validate_destination(&request.destination) + self.validate_approve(&request) } ConfigOperation::Reject => { - let request = serde_json::from_value::(payload.clone()) + let request = ConfigRejectRequest::deserialize(payload) .map_err(|_| ConfigError::InvalidRequest)?; - validate_guest_ref(&request.guest_ref)?; - validate_identifier(&request.identifier) + self.validate_reject(&request) } ConfigOperation::Status => { - let request = serde_json::from_value::(payload.clone()) + let request = ConfigStatusRequest::deserialize(payload) .map_err(|_| ConfigError::InvalidRequest)?; - validate_guest_ref(&request.guest_ref)?; - validate_identifier(&request.identifier) + self.validate_status(&request) } } } + + /// Validate a typed ReadGuestConfig request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the request names a wrong + /// Guest or identifier. + pub(crate) fn validate_read_guest_config( + &self, + request: &ConfigSyncRequest, + ) -> Result<(), ConfigError> { + validate_closed(&request.guest_ref, &request.identifier) + } + + /// Validate a typed Stage request without decoding the document at + /// admission; the staging store decodes and bounds-checks it on apply. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the request names a wrong + /// Guest or identifier. + pub(crate) fn validate_stage(&self, request: &ConfigStageRequest) -> Result<(), ConfigError> { + validate_closed(&request.guest_ref, &request.identifier) + } + + /// Validate a typed Diff request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the request names a wrong + /// Guest or identifier and [`ConfigError::InvalidView`] for a malformed + /// diff view. + pub(crate) fn validate_diff(&self, request: &ConfigDiffRequest) -> Result<(), ConfigError> { + validate_closed(&request.guest_ref, &request.identifier)?; + validate_view_identifier(&request.against) + } + + /// Validate a typed Approve request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the request names a wrong + /// Guest or identifier and [`ConfigError::InvalidDestination`] for a + /// malformed approval destination. + pub(crate) fn validate_approve( + &self, + request: &ConfigApproveRequest, + ) -> Result<(), ConfigError> { + validate_closed(&request.guest_ref, &request.identifier)?; + validate_destination(&request.destination) + } + + /// Validate a typed Reject request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the request names a wrong + /// Guest or identifier. + pub(crate) fn validate_reject(&self, request: &ConfigRejectRequest) -> Result<(), ConfigError> { + validate_closed(&request.guest_ref, &request.identifier) + } + + /// Validate a typed Status request. + /// + /// # Errors + /// + /// Returns [`ConfigError::InvalidRequest`] when the request names a wrong + /// Guest or identifier. + pub(crate) fn validate_status(&self, request: &ConfigStatusRequest) -> Result<(), ConfigError> { + validate_closed(&request.guest_ref, &request.identifier) + } +} + +/// Validate the closed Guest/identifier pair shared by every operation. +fn validate_closed(guest_ref: &ResourceRef, identifier: &str) -> Result<(), ConfigError> { + validate_guest_ref(guest_ref)?; + validate_identifier(identifier) } diff --git a/packages/d2b-provider-config-nixos/src/ttrpc.rs b/packages/d2b-provider-config-nixos/src/ttrpc.rs index 7781f8f36..1089ee86f 100644 --- a/packages/d2b-provider-config-nixos/src/ttrpc.rs +++ b/packages/d2b-provider-config-nixos/src/ttrpc.rs @@ -16,8 +16,9 @@ use serde::{Serialize, de::DeserializeOwned}; use serde_json::Value; use crate::{ - ConfigCaller, ConfigError, ConfigOperation, ConfigService, ConfigSyncRequest, - GuestConfigDocument, GuestSessionEvidence, SERVICE_NAME, SERVICE_PACKAGE, + ConfigApproveRequest, ConfigCaller, ConfigDiffRequest, ConfigError, ConfigOperation, + ConfigRejectRequest, ConfigService, ConfigStageRequest, ConfigStatusRequest, + ConfigSyncRequest, GuestConfigDocument, GuestSessionEvidence, SERVICE_NAME, SERVICE_PACKAGE, }; use d2b_contracts_resource::v3::ResourceRef; @@ -318,6 +319,14 @@ async fn dispatch_on_blocking_worker( } } +/// Decode one typed request payload without copying the JSON tree. +fn decode_typed_request(payload: &Value) -> Result +where + T: DeserializeOwned, +{ + T::deserialize(payload).map_err(|_| ConfigError::InvalidRequest) +} + struct ConfigMethod { backend: Arc, operation: ConfigOperation, @@ -339,7 +348,24 @@ impl ttrpc::r#async::MethodHandler for ConfigMethod { ); rpc_error(ConfigError::InvalidRequest) })?; - if let Err(error) = ConfigService.validate_operation(self.operation, &payload) { + // Decode the typed request once and validate the typed value, so the + // admission path neither re-parses the JSON nor decodes a Stage + // document; the backend hop re-checks the original Value. + let validation = match self.operation { + ConfigOperation::ReadGuestConfig => decode_typed_request::(&payload) + .and_then(|request| ConfigService.validate_read_guest_config(&request)), + ConfigOperation::Stage => decode_typed_request::(&payload) + .and_then(|request| ConfigService.validate_stage(&request)), + ConfigOperation::Diff => decode_typed_request::(&payload) + .and_then(|request| ConfigService.validate_diff(&request)), + ConfigOperation::Approve => decode_typed_request::(&payload) + .and_then(|request| ConfigService.validate_approve(&request)), + ConfigOperation::Reject => decode_typed_request::(&payload) + .and_then(|request| ConfigService.validate_reject(&request)), + ConfigOperation::Status => decode_typed_request::(&payload) + .and_then(|request| ConfigService.validate_status(&request)), + }; + if let Err(error) = validation { tracing::debug!( operation = self.operation.as_str(), %error, diff --git a/packages/d2b-provider-config-nixos/tests/config_lifecycle.rs b/packages/d2b-provider-config-nixos/tests/config_lifecycle.rs index 7a4f40d9e..5cfac7552 100644 --- a/packages/d2b-provider-config-nixos/tests/config_lifecycle.rs +++ b/packages/d2b-provider-config-nixos/tests/config_lifecycle.rs @@ -1,8 +1,10 @@ +use base64::{Engine as _, engine::general_purpose::STANDARD}; use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; use d2b_provider_config_nixos::{ ConfigApproveRequest, ConfigCaller, ConfigDiffRequest, ConfigRejectRequest, ConfigService, ConfigServiceBackend, ConfigStageRequest, ConfigStagingStore, ConfigStatusRequest, - ConfigSyncRequest, GuestConfigDocument, GuestConfigReader, GuestSessionEvidence, + ConfigSyncRequest, ConfigSyncResponse, GuestConfigDocument, GuestConfigReader, + GuestSessionEvidence, MAX_CONFIG_BYTES, }; #[test] @@ -18,6 +20,52 @@ fn guest_read_requires_current_matching_session() { assert!(result.document().is_ok()); } +#[test] +fn sync_response_integrity_mismatches_fail_closed() { + let guest = ResourceRef::parse("Guest/work").expect("guest ref"); + let document = + GuestConfigDocument::new(b"services.foo.enable = true;\n".to_vec()).expect("document"); + let valid = ConfigSyncResponse { + guest_ref: guest.clone(), + identifier: "guest-config".to_owned(), + content_base64: STANDARD.encode(document.bytes()), + bytes: document.len(), + sha256: document.sha256(), + }; + assert!(valid.document().is_ok()); + + let mut forged_digest = valid.clone(); + forged_digest.sha256 = + "sha256:0000000000000000000000000000000000000000000000000000000000000000".to_owned(); + assert_eq!( + forged_digest + .document() + .expect_err("forged digest must fail") + .code(), + "config-document-encoding-failed" + ); + + let mut forged_bytes = valid.clone(); + forged_bytes.bytes += 1; + assert_eq!( + forged_bytes + .document() + .expect_err("wrong byte count must fail") + .code(), + "config-document-encoding-failed" + ); + + let mut over_bound = valid; + over_bound.content_base64 = "A".repeat(MAX_CONFIG_BYTES.div_ceil(3) * 4 + 1); + assert_eq!( + over_bound + .document() + .expect_err("over-bound payload must fail") + .code(), + "config-request-invalid" + ); +} + fn zone() -> ZoneId { ZoneId::parse("work").expect("zone") } diff --git a/packages/d2b-provider-config-nixos/tests/service_contract.rs b/packages/d2b-provider-config-nixos/tests/service_contract.rs index b6dc9ed1d..d30a459db 100644 --- a/packages/d2b-provider-config-nixos/tests/service_contract.rs +++ b/packages/d2b-provider-config-nixos/tests/service_contract.rs @@ -76,6 +76,31 @@ fn operation_validation_enforces_closed_identifiers_and_semantic_bounds() { .code(), "config-view-invalid" ); + + let unknown_field = serde_json::json!({ + "guestRef": "Guest/work", + "identifier": "guest-config", + "typoKey": "must be rejected" + }); + assert_eq!( + service + .validate_operation(ConfigOperation::ReadGuestConfig, &unknown_field) + .expect_err("unknown fields must fail closed admission") + .code(), + "config-request-invalid" + ); + + let wrong_type = serde_json::json!({ + "guestRef": 42, + "identifier": "guest-config" + }); + assert_eq!( + service + .validate_operation(ConfigOperation::ReadGuestConfig, &wrong_type) + .expect_err("wrong field types must fail closed admission") + .code(), + "config-request-invalid" + ); } #[test] From 406f13d9860291f1a46ebcae38ad2444c6240f01 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:25:57 -0700 Subject: [PATCH 504/726] d2b-broker: document raw syscall wrapper SAFETY invariants The quarantined path-safety layer and child-context helpers called libc with only #[allow(unsafe_code)], so a reader could not tell audited blocks from un-audited ones. Add a one-line // SAFETY: comment to each block stating its invariant (checked return before use, fd ownership, pre-exec async-signal-safety). Comment-only change; no behavior shift. --- changelog.d/w3-04-broker-unsafe-tidy.md | 3 +++ packages/d2b-broker/src/sys.rs | 34 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 changelog.d/w3-04-broker-unsafe-tidy.md diff --git a/changelog.d/w3-04-broker-unsafe-tidy.md b/changelog.d/w3-04-broker-unsafe-tidy.md new file mode 100644 index 000000000..1012978e6 --- /dev/null +++ b/changelog.d/w3-04-broker-unsafe-tidy.md @@ -0,0 +1,3 @@ +### Changed + +- Tightened the broker's unsafe-code audit surface in `sys.rs` path-safety and child-context helpers: every raw `libc`/syscall wrapper now carries a `// SAFETY:` invariant comment, so audited and un-audited blocks are distinguishable. No behavioral change. diff --git a/packages/d2b-broker/src/sys.rs b/packages/d2b-broker/src/sys.rs index 1cc6feeb9..482e17866 100644 --- a/packages/d2b-broker/src/sys.rs +++ b/packages/d2b-broker/src/sys.rs @@ -624,6 +624,7 @@ pub mod path_safe { mode: u64::from(mode), resolve, }; + // SAFETY: `dirfd` and `path` are valid; the syscall result is checked before use. let ret = unsafe { libc::syscall( libc::SYS_openat2, @@ -646,6 +647,7 @@ pub mod path_safe { flags: libc::c_int, mode: u32, ) -> io::Result { + // SAFETY: `dirfd` and `path` are valid; the returned fd is checked before use. let ret = unsafe { libc::openat(dirfd, path.as_ptr(), flags, mode) }; if ret < 0 { return Err(io::Error::last_os_error()); @@ -661,6 +663,7 @@ pub mod path_safe { newpath: &CString, flags: u32, ) -> io::Result<()> { + // SAFETY: both dirfds and paths are valid; the syscall result is checked before use. let ret = unsafe { libc::syscall( libc::SYS_renameat2, @@ -684,6 +687,7 @@ pub mod path_safe { newdirfd: RawFd, newpath: &CString, ) -> io::Result<()> { + // SAFETY: both dirfds and paths are valid; the result is checked before use. let ret = unsafe { libc::renameat(olddirfd, oldpath.as_ptr(), newdirfd, newpath.as_ptr()) }; if ret < 0 { return Err(io::Error::last_os_error()); @@ -693,6 +697,7 @@ pub mod path_safe { #[allow(unsafe_code)] fn mkdirat_raw(dirfd: RawFd, path: &CString, mode: u32) -> io::Result<()> { + // SAFETY: `dirfd` and `path` are valid; the result is checked before use. let ret = unsafe { libc::mkdirat(dirfd, path.as_ptr(), mode) }; if ret < 0 { return Err(io::Error::last_os_error()); @@ -707,6 +712,7 @@ pub mod path_safe { #[allow(unsafe_code)] fn unlinkat_raw_with_flags(dirfd: RawFd, path: &CString, flags: libc::c_int) -> io::Result<()> { + // SAFETY: `dirfd` and `path` are valid; the result is checked before use. let ret = unsafe { libc::unlinkat(dirfd, path.as_ptr(), flags) }; if ret < 0 { return Err(io::Error::last_os_error()); @@ -716,7 +722,9 @@ pub mod path_safe { #[allow(unsafe_code)] fn fstatat_raw(dirfd: RawFd, path: &CString, flags: libc::c_int) -> io::Result { + // SAFETY: `stat` is plain data; zeroing is safe and fstatat overwrites it on success. let mut stat: libc::stat = unsafe { std::mem::zeroed() }; + // SAFETY: `dirfd`/`path` are valid and `stat` is writable; the result is checked before use. let ret = unsafe { libc::fstatat(dirfd, path.as_ptr(), &mut stat, flags) }; if ret < 0 { return Err(io::Error::last_os_error()); @@ -727,6 +735,7 @@ pub mod path_safe { #[allow(unsafe_code)] fn linkat_empty_path_raw(oldfd: RawFd, newdirfd: RawFd, newpath: &CString) -> io::Result<()> { let empty = CString::new(Vec::::new()).expect("empty C string is valid"); + // SAFETY: `oldfd`/`newdirfd` are valid and both paths are NUL-terminated; result checked. let ret = unsafe { libc::linkat( oldfd, @@ -2222,11 +2231,14 @@ pub mod pidfd_sys { for (index, &source_fd) in pre_opened_raw_fds.iter().enumerate() { let destination_fd = RENDER_NODE_INHERITED_FD + index as libc::c_int; if source_fd != destination_fd { + // SAFETY: pre-exec child context; `source_fd` is valid and `destination_fd` is in range. if unsafe { libc::dup2(source_fd, destination_fd) } < 0 { return Err(()); } + // SAFETY: pre-exec child context; closes the just-duplicated source fd. unsafe { libc::close(source_fd) }; } + // SAFETY: `destination_fd` is valid after dup2; the result is checked before use. if unsafe { libc::fcntl(destination_fd, libc::F_SETFD, 0) } < 0 { return Err(()); } @@ -2664,6 +2676,7 @@ pub mod pidfd_sys { fn apply_mount_actions(actions: &[PreparedMountAction]) -> io::Result<()> { for action in actions { let path = action.path.as_ptr(); + // SAFETY: `path` is a valid NUL-terminated path; the mount result is checked. let bind_ret = unsafe { libc::mount( path, @@ -2677,6 +2690,7 @@ pub mod pidfd_sys { return Err(io::Error::last_os_error()); } if action.readonly { + // SAFETY: `path` is a valid NUL-terminated path; the mount result is checked. let remount_ret = unsafe { libc::mount( std::ptr::null(), @@ -2704,6 +2718,7 @@ pub mod pidfd_sys { ) -> Result<(), (libc::c_int, Vec)> { for action in actions { let path = action.path.as_ptr(); + // SAFETY: `path` is a valid NUL-terminated path; the mount result is checked. let bind_ret = unsafe { libc::mount( path, @@ -2714,10 +2729,12 @@ pub mod pidfd_sys { ) }; if bind_ret < 0 { + // SAFETY: errno is read only immediately after a failed libc call. let errno = unsafe { *libc::__errno_location() }; return Err((errno, action.path.as_bytes().to_vec())); } if action.readonly { + // SAFETY: `path` is a valid NUL-terminated path; the mount result is checked. let remount_ret = unsafe { libc::mount( std::ptr::null(), @@ -2729,6 +2746,7 @@ pub mod pidfd_sys { ) }; if remount_ret < 0 { + // SAFETY: errno is read only immediately after a failed libc call. let errno = unsafe { *libc::__errno_location() }; return Err((errno, action.path.as_bytes().to_vec())); } @@ -2739,13 +2757,17 @@ pub mod pidfd_sys { #[allow(unsafe_code)] fn mkdir_one(path: *const libc::c_char) -> Result<(), libc::c_int> { + // SAFETY: `path` is a valid NUL-terminated path; the result is checked before use. if unsafe { libc::mkdir(path, 0o755) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. let errno = unsafe { *libc::__errno_location() }; if errno != libc::EEXIST { return Err(errno); } } + // SAFETY: `path` is a valid NUL-terminated path; the result is checked before use. if unsafe { libc::chmod(path, 0o755) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. Err(unsafe { *libc::__errno_location() }) } else { Ok(()) @@ -2779,19 +2801,27 @@ pub mod pidfd_sys { uid: libc::uid_t, gid: libc::gid_t, ) -> Result<(), libc::c_int> { + // SAFETY: `destination` is a valid NUL-terminated path; the result is checked before use. if unsafe { libc::unlink(destination.as_ptr()) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. let errno = unsafe { *libc::__errno_location() }; if errno != libc::ENOENT { return Err(errno); } } + // SAFETY: `destination` is a valid NUL-terminated path; the result is checked before use. if unsafe { libc::mknod(destination.as_ptr(), mode, dev) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. return Err(unsafe { *libc::__errno_location() }); } + // SAFETY: `destination` is a valid NUL-terminated path; the result is checked before use. if unsafe { libc::chmod(destination.as_ptr(), mode & 0o777) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. return Err(unsafe { *libc::__errno_location() }); } + // SAFETY: `destination` is a valid NUL-terminated path; the result is checked before use. if unsafe { libc::chown(destination.as_ptr(), uid, gid) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. return Err(unsafe { *libc::__errno_location() }); } Ok(()) @@ -2806,6 +2836,7 @@ pub mod pidfd_sys { let dev = c"/dev".as_ptr(); let tmpfs = c"tmpfs".as_ptr(); let options = c"mode=0755".as_ptr() as *const libc::c_void; + // SAFETY: `tmpfs`/`dev`/`options` are valid NUL-terminated strings; result checked. if unsafe { libc::mount( tmpfs, @@ -2816,6 +2847,7 @@ pub mod pidfd_sys { ) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. let errno = unsafe { *libc::__errno_location() }; return Err((errno, b"/dev".to_vec())); } @@ -2829,6 +2861,7 @@ pub mod pidfd_sys { if let Err(errno) = mkdir_one(bind.destination.as_ptr()) { return Err((errno, bind.destination.as_bytes().to_vec())); } + // SAFETY: both bind paths are valid NUL-terminated; the result is checked before use. if unsafe { libc::mount( bind.source.as_ptr(), @@ -2839,6 +2872,7 @@ pub mod pidfd_sys { ) } < 0 { + // SAFETY: errno is read only immediately after a failed libc call. let errno = unsafe { *libc::__errno_location() }; return Err((errno, bind.destination.as_bytes().to_vec())); } From 5f1fcd6f1ee3fbc9b9ad1edcc7edeb0e34770864 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:28:11 -0700 Subject: [PATCH 505/726] d2b-bus: avoid per-frame watch delivery copies Watch delivery now passes the frame payload slice through send_and_wait_ack; the stream bridge copies the payload once when the frame is admitted, so backpressure retries no longer re-allocate up to max_frame_bytes per wakeup on the bounded watch path. Session seam tests wait on observable conditions instead of fixed-count yield and poll loops, and the operation-table test asserts the RetainedOperationId variant instead of pinning its Display sentence. --- changelog.d/w3-06-bus-watch-delivery.md | 12 +++ packages/d2b-bus/src/operations.rs | 4 - packages/d2b-bus/src/router.rs | 6 +- packages/d2b-bus/src/session_seam_tests.rs | 89 +++++++--------------- packages/d2b-bus/src/streams.rs | 46 +++++------ 5 files changed, 66 insertions(+), 91 deletions(-) create mode 100644 changelog.d/w3-06-bus-watch-delivery.md diff --git a/changelog.d/w3-06-bus-watch-delivery.md b/changelog.d/w3-06-bus-watch-delivery.md new file mode 100644 index 000000000..396322285 --- /dev/null +++ b/changelog.d/w3-06-bus-watch-delivery.md @@ -0,0 +1,12 @@ +### Fixed + +- Bus watch delivery no longer allocates a fresh frame buffer per frame or + per backpressure retry: the payload is copied once at the stream bridge + when the frame is admitted, so bounded watch streams keep their kept-half + credit path allocation-free on retry. +- Bus session seam tests wait on observable conditions instead of fixed-count + yield and poll loops, so a loaded runner can no longer fail them by being + slow. +- The bus operation-table test asserts the `RetainedOperationId` variant + instead of pinning its full error sentence, so a wording change no longer + breaks the cancellation-retry contract test. \ No newline at end of file diff --git a/packages/d2b-bus/src/operations.rs b/packages/d2b-bus/src/operations.rs index e965dd927..52837d0bd 100644 --- a/packages/d2b-bus/src/operations.rs +++ b/packages/d2b-bus/src/operations.rs @@ -1056,10 +1056,6 @@ mod tests { ), "same-id reuse must remain blocked while cancellation retry state exists" ); - assert_eq!( - OperationError::RetainedOperationId.to_string(), - "operation identifier is retained after cancellation; retry cancellation or start new work with a new operation identifier" - ); assert!( cancel_now(&mut table, &reused_operation, SessionId(1)) .unwrap() diff --git a/packages/d2b-bus/src/router.rs b/packages/d2b-bus/src/router.rs index 008827d72..8bd0e76bd 100644 --- a/packages/d2b-bus/src/router.rs +++ b/packages/d2b-bus/src/router.rs @@ -4168,7 +4168,7 @@ impl BusStream { } else { self.outgoing.as_ref().map_or_else( || Err(BusError::SessionClosed), - |outgoing| outgoing.send(payload).map_err(BusError::Stream), + |outgoing| outgoing.send(&payload).map_err(BusError::Stream), ) }; if let Err(error) = &result @@ -4179,7 +4179,7 @@ impl BusStream { result } - async fn send_watch_payload(&self, payload: Vec) -> Result<(), BusError> { + async fn send_watch_payload(&self, payload: &[u8]) -> Result<(), BusError> { if self.cancellation.is_cancelled() { return Err(BusError::Cancelled); } @@ -4234,7 +4234,7 @@ impl WatchSink for BusStream { frame: WatchFrame, ) -> impl std::future::Future> + Send { async move { - match self.send_watch_payload(frame.payload().to_vec()).await { + match self.send_watch_payload(frame.payload()).await { Ok(()) => Ok(()), Err(BusError::Stream(StreamError::FrameBounds)) => { Err(WatchSinkError::FrameTooLarge) diff --git a/packages/d2b-bus/src/session_seam_tests.rs b/packages/d2b-bus/src/session_seam_tests.rs index 44bd78077..c4dbf53dc 100644 --- a/packages/d2b-bus/src/session_seam_tests.rs +++ b/packages/d2b-bus/src/session_seam_tests.rs @@ -1620,9 +1620,6 @@ async fn production_owner_child_queries_rewrite_list_and_watch_payloads() { Arc::new(resource_remote), adapter.ttrpc_services(), )); - for _ in 0..16 { - tokio::task::yield_now().await; - } let _resource_ingress = registrar .register_component_session(resource_endpoint) .await @@ -1805,9 +1802,6 @@ async fn production_scoped_commit_chain_authorizes_and_fences_store_writes() { std::sync::Arc::new(resource_remote), adapter.ttrpc_services(), )); - for _ in 0..16 { - tokio::task::yield_now().await; - } let _resource_ingress = registrar .register_component_session(resource_endpoint) .await @@ -1878,39 +1872,24 @@ async fn production_scoped_commit_chain_authorizes_and_fences_store_writes() { .unwrap(), ]; let revoked_mutations = new_mutations.clone(); - let mut scoped_response = None; - for attempt in 0..32 { - let operation_id = format!("scoped-valid-{attempt}"); - let response = caller - .invoke_scoped_commit_batch( - route.clone(), - OperationSpec::new(OperationId::parse(&operation_id).unwrap(), 10_000).unwrap(), - new_identity.clone(), - new_mutations.clone(), - commit_batch_frame(&operation_id), - ) - .await - .unwrap(); - let response = ttrpc::proto::Response::parse_from_bytes( - &response.as_bytes()[ttrpc::proto::MESSAGE_HEADER_LENGTH..], + let response = caller + .invoke_scoped_commit_batch( + route.clone(), + OperationSpec::new(OperationId::parse("scoped-valid").unwrap(), 10_000).unwrap(), + new_identity.clone(), + new_mutations.clone(), + commit_batch_frame("scoped-valid"), ) + .await .unwrap(); - let response = - d2b_contracts_resource::resource_proto::CommitBatchResponse::parse_from_bytes( - &response.payload, - ) - .unwrap(); - if response.error.is_some() { - scoped_response = Some(response); - break; - } - if response.revision == 8 { - scoped_response = Some(response); - break; - } - tokio::task::yield_now().await; - } - let response = scoped_response.expect("scoped commit response"); + let response = ttrpc::proto::Response::parse_from_bytes( + &response.as_bytes()[ttrpc::proto::MESSAGE_HEADER_LENGTH..], + ) + .unwrap(); + let response = d2b_contracts_resource::resource_proto::CommitBatchResponse::parse_from_bytes( + &response.payload, + ) + .unwrap(); assert!(response.error.is_none()); assert_eq!(response.revision, 8); @@ -1938,30 +1917,18 @@ async fn production_scoped_commit_chain_authorizes_and_fences_store_writes() { BusError::Endpoint(EndpointError::Rejected) )); - for attempt in 0..8 { - if commits.lock().unwrap().len() >= 2 { - break; - } - let operation_id = format!("plain-commit-{attempt}"); - caller - .invoke_resource( - route.clone(), - OperationSpec::new(OperationId::parse(&operation_id).unwrap(), 10_000).unwrap(), - ResourceCall::CommitBatch(vec![ - (target.clone(), ResourceVerb::UpdateStatus), - (target.clone(), ResourceVerb::UpdateFinalizers), - ]), - commit_batch_frame(&operation_id), - ) - .await - .unwrap(); - for _ in 0..8 { - if commits.lock().unwrap().len() >= 2 { - break; - } - tokio::task::yield_now().await; - } - } + caller + .invoke_resource( + route.clone(), + OperationSpec::new(OperationId::parse("plain-commit").unwrap(), 10_000).unwrap(), + ResourceCall::CommitBatch(vec![ + (target.clone(), ResourceVerb::UpdateStatus), + (target.clone(), ResourceVerb::UpdateFinalizers), + ]), + commit_batch_frame("plain-commit"), + ) + .await + .unwrap(); assignments .lock() diff --git a/packages/d2b-bus/src/streams.rs b/packages/d2b-bus/src/streams.rs index 671cb1848..e717e7715 100644 --- a/packages/d2b-bus/src/streams.rs +++ b/packages/d2b-bus/src/streams.rs @@ -276,7 +276,7 @@ impl StreamBridge { principal: &PrincipalId, source: SessionId, direction: BusDirection, - payload: Vec, + payload: &[u8], ) -> Result<(), StreamError> { if payload.is_empty() || payload.len() > self.limits.max_frame_bytes { self.metrics @@ -327,7 +327,7 @@ impl StreamBridge { } let was_empty = stream.frames.is_empty(); stream.credit -= frame_len; - stream.frames.push_back(payload); + stream.frames.push_back(payload.to_vec()); was_empty }; if was_empty { @@ -634,7 +634,7 @@ impl OutgoingStream { &self.key.name } - pub(crate) fn send(&self, payload: Vec) -> Result<(), StreamError> { + pub(crate) fn send(&self, payload: &[u8]) -> Result<(), StreamError> { self.bridge.send( &self.key.name, &self.key.principal, @@ -644,12 +644,12 @@ impl OutgoingStream { ) } - pub(crate) async fn send_wait(&self, payload: Vec) -> Result<(), StreamError> { + pub(crate) async fn send_wait(&self, payload: &[u8]) -> Result<(), StreamError> { loop { let notified = self.bridge.notify.notified(); let mut notified = std::pin::pin!(notified); notified.as_mut().enable(); - match self.send(payload.clone()) { + match self.send(payload) { Ok(()) => return Ok(()), Err( StreamError::CreditExceeded @@ -663,7 +663,7 @@ impl OutgoingStream { } } - pub(crate) async fn send_and_wait_ack(&self, payload: Vec) -> Result<(), StreamError> { + pub(crate) async fn send_and_wait_ack(&self, payload: &[u8]) -> Result<(), StreamError> { let target = self .bridge .acknowledged_bytes(&self.key)? @@ -886,7 +886,7 @@ mod tests { 8, ) .unwrap(); - explicit.send(vec![1, 2]).unwrap(); + explicit.send(&[1, 2]).unwrap(); explicit.close(); drop(explicit_incoming); @@ -898,7 +898,7 @@ mod tests { 8, ) .unwrap(); - dropped_outgoing.send(vec![3, 4]).unwrap(); + dropped_outgoing.send(&[3, 4]).unwrap(); drop(dropped_incoming); drop(dropped_outgoing); @@ -910,7 +910,7 @@ mod tests { 8, ) .unwrap(); - session_outgoing.send(vec![5, 6]).unwrap(); + session_outgoing.send(&[5, 6]).unwrap(); bridge.cancel_session(SessionId(6)); drop(session_incoming); drop(session_outgoing); @@ -973,16 +973,16 @@ mod tests { ), Err(StreamError::AggregateBackpressure) )); - outgoing.send(vec![1; 5]).unwrap(); - assert_eq!(outgoing.send(vec![2]), Err(StreamError::CreditExceeded)); + outgoing.send(&[1; 5]).unwrap(); + assert_eq!(outgoing.send(&[2]), Err(StreamError::CreditExceeded)); incoming.grant(outgoing.name(), 1).await.unwrap(); assert_eq!( - outgoing.send(vec![2; 2]), + outgoing.send(&[2; 2]), Err(StreamError::AggregateBackpressure) ); let frame = incoming.receive_next().await.unwrap(); assert_eq!(frame.payload(), &[1; 5]); - outgoing.send(vec![2]).unwrap(); + outgoing.send(&[2]).unwrap(); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -1000,7 +1000,7 @@ mod tests { let outgoing = Arc::new(outgoing); let sender = { let outgoing = Arc::clone(&outgoing); - tokio::spawn(async move { outgoing.send_wait(vec![1, 2, 3, 4]).await }) + tokio::spawn(async move { outgoing.send_wait(&[1, 2, 3, 4]).await }) }; tokio::task::yield_now().await; incoming.grant(outgoing.name(), 2).await.unwrap(); @@ -1052,9 +1052,9 @@ mod tests { 8, ) .unwrap(); - first_out.send(vec![1]).unwrap(); - first_out.send(vec![2]).unwrap(); - second_out.send(vec![3]).unwrap(); + first_out.send(&[1]).unwrap(); + first_out.send(&[2]).unwrap(); + second_out.send(&[3]).unwrap(); let observed = [ first_in.receive_next().await.unwrap(), @@ -1093,9 +1093,9 @@ mod tests { 8, ) .unwrap(); - first_out.send(vec![1]).unwrap(); - first_out.send(vec![2]).unwrap(); - second_out.send(vec![3]).unwrap(); + first_out.send(&[1]).unwrap(); + first_out.send(&[2]).unwrap(); + second_out.send(&[3]).unwrap(); let observed = [ first_in.receive_next().await.unwrap(), @@ -1173,7 +1173,7 @@ mod tests { let receive = incoming.receive_next(); let send = async { tokio::task::yield_now().await; - outgoing.send(vec![1]).unwrap(); + outgoing.send(&[1]).unwrap(); }; let (frame, ()) = tokio::join!(receive, send); assert_eq!(frame.unwrap().payload(), &[1]); @@ -1200,7 +1200,7 @@ mod tests { ) .unwrap(); bridge.cancel_session(SessionId(2)); - assert_eq!(outgoing.send(vec![1]), Err(StreamError::StreamClosed)); + assert_eq!(outgoing.send(&[1]), Err(StreamError::StreamClosed)); assert_eq!( incoming.receive_next().await, Err(StreamError::StreamClosed) @@ -1291,7 +1291,7 @@ mod tests { let start = Arc::clone(&start); tasks.push(tokio::spawn(async move { start.wait().await; - outgoing.send(vec![1]) + outgoing.send(&[1]) })); } From 26538ea75d728aa3d05a15fadabecdd837d9090f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:28:43 -0700 Subject: [PATCH 506/726] d2b-core: reuse parsed zone bundles and nested guest keys has_zone_uid, zone_uid, and find_network_spec re-parsed every zone resource bundle from raw bytes on each call even though the resolver already holds the parsed ResourceBundle per zone; the nft/hosts renderers built a fresh String per line and sha256_hex one per byte; and six (zone, guest) lookups allocated two Strings per call against flat BTreeMap<(String, String), _> maps. Read the parsed bundles instead of the raw bytes, write renderer output straight into the buffer, hex-encode into a fixed buffer, and nest the four guest artifact maps per zone so lookups borrow. The chown tamper test becomes a documented root-only #[ignore] instead of a silent pass on non-root runs. --- changelog.d/w3-12-core-bundle-resolver.md | 7 + packages/d2b-core/src/bundle_resolver.rs | 306 +++++++++++------- .../d2b-core/tests/bundle_resolver_tamper.rs | 13 +- 3 files changed, 204 insertions(+), 122 deletions(-) create mode 100644 changelog.d/w3-12-core-bundle-resolver.md diff --git a/changelog.d/w3-12-core-bundle-resolver.md b/changelog.d/w3-12-core-bundle-resolver.md new file mode 100644 index 000000000..68adfb5fc --- /dev/null +++ b/changelog.d/w3-12-core-bundle-resolver.md @@ -0,0 +1,7 @@ +# `w3-12-core-bundle-resolver.md` + +### Changed + +- Zone bundle lookups no longer re-parse resource-bundle JSON or allocate composite keys per call: zone UID presence/identity, network-spec resolution, and guest setup descriptor / VMM intent lookups now read the bundles parsed once at load and borrow (zone, guest) keys from per-zone nested maps, so intent resolution allocates less on bundles with many zones. +- The nftables and hosts renderers write directly into the output buffer instead of building a temporary String per line, and SHA-256 digests are hex-encoded into a fixed buffer, cutting per-render allocations. +- The root-only chown tamper test is now a documented ignored test instead of silently passing when not root, so the skip is visible in test output. \ No newline at end of file diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 6aeebd7c6..985b6ed09 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -95,6 +95,7 @@ use serde::Deserialize; use sha2::Digest as _; use std::collections::{BTreeMap, BTreeSet}; use std::fmt; +use std::fmt::Write as _; use std::io::Read as _; use std::net::IpAddr; use std::path::{Path, PathBuf}; @@ -111,10 +112,10 @@ pub struct BundleResolver { zone_resource_bundles: BTreeMap>, /// Parsed zone-tagged v3 resource bundles keyed by canonical Zone id. parsed_zone_resources: BTreeMap, - guest_setup_descriptors: BTreeMap<(String, String), Vec>, - guest_setup_descriptor_catalog_keys: BTreeMap<(String, String), String>, - guest_vmm_intents: BTreeMap<(String, String), ResolvedRunnerIntent>, - guest_vmm_zone_uids: BTreeMap<(String, String), ResourceUid>, + guest_setup_descriptors: BTreeMap>>, + guest_setup_descriptor_catalog_keys: BTreeMap>, + guest_vmm_intents: BTreeMap>, + guest_vmm_zone_uids: BTreeMap>, zone_storage_rows: BTreeMap, pub storage: Option, /// Trusted site-runtime contract (`site.json`); `None` for a bundle that @@ -159,10 +160,10 @@ struct ParsedBundleArtifacts { host: HostJson, processes: ProcessesJson, zone_resource_bundles: BTreeMap>, - guest_setup_descriptors: BTreeMap<(String, String), Vec>, - guest_setup_descriptor_catalog_keys: BTreeMap<(String, String), String>, - guest_vmm_intents: BTreeMap<(String, String), ResolvedRunnerIntent>, - guest_vmm_zone_uids: BTreeMap<(String, String), ResourceUid>, + guest_setup_descriptors: BTreeMap>>, + guest_setup_descriptor_catalog_keys: BTreeMap>, + guest_vmm_intents: BTreeMap>, + guest_vmm_zone_uids: BTreeMap>, guest_store_view_intents: BTreeMap, provider_controller_templates: Vec, zone_storage_rows: BTreeMap, @@ -1010,9 +1011,17 @@ fn secure_open_and_read(path: &Path, policy: &BundleVerifyPolicy) -> Result"` over `data`. fn sha256_hex(data: &[u8]) -> String { + const HEX: [u8; 16] = *b"0123456789abcdef"; let digest: [u8; 32] = sha2::Sha256::digest(data).into(); - let hex: String = digest.iter().map(|b| format!("{b:02x}")).collect(); - format!("sha256:{hex}") + let mut hex = [0u8; 64]; + for (i, byte) in digest.iter().enumerate() { + hex[i * 2] = HEX[usize::from(byte >> 4)]; + hex[i * 2 + 1] = HEX[usize::from(byte & 0x0f)]; + } + let mut out = String::with_capacity(71); + out.push_str("sha256:"); + out.push_str(std::str::from_utf8(&hex).expect("hex digits are ASCII")); + out } /// Verify the SHA-256 of `bytes` against `artifact_hashes[key]`. @@ -1558,6 +1567,7 @@ impl BundleResolver { runner_intents.extend( guest_vmm_intents .values() + .flat_map(|guests| guests.values()) .cloned() .map(|intent| (intent.intent_id.clone(), intent)), ); @@ -1622,7 +1632,8 @@ impl BundleResolver { /// of this projection. pub fn guest_setup_descriptor_bytes(&self, zone: &str, guest: &str) -> Option<&[u8]> { self.guest_setup_descriptors - .get(&(zone.to_owned(), guest.to_owned())) + .get(zone) + .and_then(|guests| guests.get(guest)) .map(Vec::as_slice) } @@ -1630,7 +1641,8 @@ impl BundleResolver { /// Guest setup descriptor in the verified artifact catalog. pub fn guest_setup_descriptor_catalog_key(&self, zone: &str, guest: &str) -> Option<&str> { self.guest_setup_descriptor_catalog_keys - .get(&(zone.to_owned(), guest.to_owned())) + .get(zone) + .and_then(|guests| guests.get(guest)) .map(String::as_str) } @@ -1649,21 +1661,16 @@ impl BundleResolver { /// Check that a supplied Zone UID is present in a verified private bundle. pub fn has_zone_uid(&self, zone_uid: &d2b_contracts_resource::v3::ResourceUid) -> bool { - self.zone_resource_bundles.values().any(|bytes| { - ResourceBundle::from_json(bytes) - .ok() - .and_then(|bundle| bundle.zone_uid) - .as_ref() - == Some(zone_uid) - }) + self.parsed_zone_resources + .values() + .any(|bundle| bundle.zone_uid.as_ref() == Some(zone_uid)) } /// Return the immutable UID bound into one verified Zone resource bundle. pub fn zone_uid(&self, zone: &ZoneId) -> Option { - self.zone_resource_bundles + self.parsed_zone_resources .get(zone.as_str()) - .and_then(|bytes| ResourceBundle::from_json(bytes).ok()) - .and_then(|bundle| bundle.zone_uid) + .and_then(|bundle| bundle.zone_uid.clone()) } /// Return the verified broker-owned storage row for one Zone. @@ -1970,8 +1977,7 @@ impl BundleResolver { } fn find_network_spec(&self, parts: &ParsedNetworkIntentRef) -> Option { - self.zone_resource_bundles.values().find_map(|bytes| { - let bundle = ResourceBundle::from_json(bytes).ok()?; + self.parsed_zone_resources.values().find_map(|bundle| { if bundle.zone_uid.as_ref() != Some(&parts.zone_uid) { return None; } @@ -2082,7 +2088,8 @@ impl BundleResolver { } let descriptor = self .guest_setup_descriptors - .get(&(zone.to_owned(), guest_ref.name().as_str().to_owned()))?; + .get(zone) + .and_then(|guests| guests.get(guest_ref.name().as_str()))?; let catalog_key = self.guest_setup_descriptor_catalog_key(zone, guest_ref.name().as_str())?; let descriptor_value = serde_json::from_slice::(descriptor).ok()?; @@ -2101,7 +2108,8 @@ impl BundleResolver { let vm_name = guest_ref.name().as_str(); let intent = self .guest_vmm_intents - .get(&(zone.to_owned(), vm_name.to_owned()))?; + .get(zone) + .and_then(|guests| guests.get(vm_name))?; (intent.role == ProcessRole::CloudHypervisorRunner && intent.vm_name == vm_name && intent.execution_ref == execution_ref @@ -2125,8 +2133,17 @@ impl BundleResolver { let key = self .guest_vmm_zone_uids .iter() - .find_map(|(key, value)| (value == zone_uid && key.1 == guest).then_some(key))?; - let intent = self.guest_vmm_intents.get(key)?; + .find_map(|(zone, guests)| { + guests + .iter() + .find_map(|(guest_name, uid)| { + (uid == zone_uid && guest_name == guest).then_some((zone, guest_name)) + }) + })?; + let intent = self + .guest_vmm_intents + .get(key.0) + .and_then(|guests| guests.get(key.1))?; (intent.role == ProcessRole::CloudHypervisorRunner && intent.vm_name == guest && intent.execution_ref == execution_ref @@ -3748,28 +3765,29 @@ fn render_host_nft_script(host: &HostJson) -> String { } else { format!(" comment \"d2b managed: {}\"", model.ownership_id) }; - buf.push_str(&format!( + write!( + buf, "table {} {} {{\n", model.family.to_lowercase(), model.table - )); + ) + .expect("writing to a String cannot fail"); for chain in &model.chains { - buf.push_str(&format!(" chain {} {{\n", chain.name)); + write!(buf, " chain {} {{\n", chain.name).expect("writing to a String cannot fail"); if let (Some(hook), Some(priority)) = (chain.hook.as_ref(), chain.priority) { - buf.push_str(&format!( - " type filter hook {hook} priority {priority};\n" - )); + write!(buf, " type filter hook {hook} priority {priority};\n") + .expect("writing to a String cannot fail"); } if let Some(policy) = chain.policy.as_ref() { - buf.push_str(&format!(" policy {policy};\n")); + write!(buf, " policy {policy};\n").expect("writing to a String cannot fail"); } if !chain.purpose.is_empty() { - buf.push_str(&format!(" # purpose: {}\n", chain.purpose)); + write!(buf, " # purpose: {}\n", chain.purpose) + .expect("writing to a String cannot fail"); } if !comment.is_empty() { - buf.push_str(&format!( - " ct state established,related accept{comment};\n" - )); + write!(buf, " ct state established,related accept{comment};\n") + .expect("writing to a String cannot fail"); } // Per-env forward acceptance: workload traffic exits each env // via its `br--up` bridge (the host-side end of the net-VM @@ -3781,10 +3799,12 @@ fn render_host_nft_script(host: &HostJson) -> String { // before the nixos chain runs. if chain.hook.as_deref() == Some("forward") { for env in &host.environments { - buf.push_str(&format!( + write!( + buf, " iifname \"br-{}-up\" ct state new accept{comment};\n", env.env - )); + ) + .expect("writing to a String cannot fail"); } } if chain.hook.as_deref() == Some("input") { @@ -3802,12 +3822,16 @@ fn render_host_nft_script(host: &HostJson) -> String { .map(u16::to_string) .collect::>() .join(", "); - buf.push_str(&format!( + write!( + buf, " iifname != \"lo\" meta l4proto tcp tcp dport {{ {backend_ports} }} drop{comment};\n" - )); - buf.push_str(&format!( + ) + .expect("writing to a String cannot fail"); + write!( + buf, " iifname != \"lo\" meta l4proto tcp tcp dport 3240 drop{comment};\n" - )); + ) + .expect("writing to a String cannot fail"); } } buf.push_str(" }\n"); @@ -3824,16 +3848,22 @@ fn render_env_nft_subset(host: &HostJson, env: &NetEnv) -> String { let chain = format!("forward-{}", env.env); let bridge_ifname = format!("br-{}-up", env.env); let mut buf = String::new(); - buf.push_str(&format!( + write!( + buf, "table inet d2b {{\n chain \"{chain}\" {{ comment \"{marker}\";\n" - )); - buf.push_str(&format!( + ) + .expect("writing to a String cannot fail"); + write!( + buf, " ct state established,related accept comment \"{marker}\";\n", - )); - buf.push_str(&format!( + ) + .expect("writing to a String cannot fail"); + write!( + buf, " iifname \"{}\" ct state new accept comment \"{}\";\n", bridge_ifname, marker - )); + ) + .expect("writing to a String cannot fail"); buf.push_str(" }\n}\n"); buf } @@ -4017,12 +4047,14 @@ fn render_hosts_managed_block(host: &HostJson) -> String { buf.push('\n'); buf.push_str("# managed by d2b broker - do not edit by hand\n"); for env in &host.environments { - buf.push_str(&format!( + write!( + buf, "# env {} bridge {} mtu {}\n", env.env, env.bridge.as_str(), env.mtu - )); + ) + .expect("writing to a String cannot fail"); } buf.push_str(&host.hosts_file.end_marker); buf.push('\n'); @@ -4830,10 +4862,10 @@ fn load_zone_resource_bundles( /// descriptors, provenance strings, VMM runner intents plus their Zone UIDs, /// and store-view intents - see [`load_guest_setup_descriptors`]. type LoadedGuestSetupDescriptors = ( - BTreeMap<(String, String), Vec>, - BTreeMap<(String, String), String>, - BTreeMap<(String, String), ResolvedRunnerIntent>, - BTreeMap<(String, String), ResourceUid>, + BTreeMap>>, + BTreeMap>, + BTreeMap>, + BTreeMap>, BTreeMap, ); @@ -4916,8 +4948,8 @@ fn load_guest_setup_descriptors( "Guest setup descriptor list is missing", ) })?; - let mut result = BTreeMap::new(); - let mut catalog_keys = BTreeMap::new(); + let mut result: BTreeMap>> = BTreeMap::new(); + let mut catalog_keys: BTreeMap> = BTreeMap::new(); for row in descriptors { let zone = row .get("zone") @@ -4970,10 +5002,15 @@ fn load_guest_setup_descriptors( ) })?; let descriptor_bytes = descriptor_value.to_canonical_bytes(); - let key = (zone.to_owned(), guest.to_owned()); - if result.insert(key.clone(), descriptor_bytes).is_some() + if result + .entry(zone.to_owned()) + .or_default() + .insert(guest.to_owned(), descriptor_bytes) + .is_some() || catalog_keys - .insert(key, provider_contract_digest.to_owned()) + .entry(zone.to_owned()) + .or_default() + .insert(guest.to_owned(), provider_contract_digest.to_owned()) .is_some() { return Err(Error::manifest_parse_error( @@ -5112,13 +5149,13 @@ fn load_guest_store_view_intents( /// Per-Guest VMM runner intents plus the bound Zone UIDs, as produced by /// [`load_guest_vmm_intents`]. type ResolvedGuestVmmIntents = ( - BTreeMap<(String, String), ResolvedRunnerIntent>, - BTreeMap<(String, String), ResourceUid>, + BTreeMap>, + BTreeMap>, ); fn load_guest_vmm_intents( catalog: &serde_json::Value, - descriptors: &BTreeMap<(String, String), Vec>, + descriptors: &BTreeMap>>, ) -> Result { let Some(rows) = catalog .get("guestClosures") @@ -5126,8 +5163,8 @@ fn load_guest_vmm_intents( else { return Ok((BTreeMap::new(), BTreeMap::new())); }; - let mut intents = BTreeMap::new(); - let mut zone_uids = BTreeMap::new(); + let mut intents: BTreeMap> = BTreeMap::new(); + let mut zone_uids: BTreeMap> = BTreeMap::new(); for row in rows { let zone = row .get("zone") @@ -5173,7 +5210,8 @@ fn load_guest_vmm_intents( ) })?; let descriptor = descriptors - .get(&(zone.as_str().to_owned(), guest.to_owned())) + .get(zone.as_str()) + .and_then(|guests| guests.get(guest)) .ok_or_else(|| { Error::manifest_parse_error( "artifact-catalog.json", @@ -5386,8 +5424,10 @@ fn load_guest_vmm_intents( "Guest VMM intent does not carry a complete Cloud Hypervisor argv", )); } - let key = (zone.as_str().to_owned(), guest.to_owned()); - if intents.contains_key(&key) { + if intents + .get(zone.as_str()) + .is_some_and(|guests| guests.contains_key(guest)) + { return Err(Error::manifest_parse_error( "artifact-catalog.json", "duplicate Guest VMM intent", @@ -5440,8 +5480,16 @@ fn load_guest_vmm_intents( umask: Some(0o022), accepts_launch_args: false, }; - if intents.insert(key.clone(), intent).is_some() - || zone_uids.insert(key, zone_uid).is_some() + if intents + .entry(zone.as_str().to_owned()) + .or_default() + .insert(guest.to_owned(), intent) + .is_some() + || zone_uids + .entry(zone.as_str().to_owned()) + .or_default() + .insert(guest.to_owned(), zone_uid) + .is_some() { return Err(Error::manifest_parse_error( "artifact-catalog.json", @@ -7694,16 +7742,20 @@ mod tests { .unwrap(), ); let mut resolver = build_personal_dev_bundle(&root); - resolver.zone_resource_bundles.insert( + let bytes = network_resource_bundle_bytes( + "work", + &zone_uid, + &network_uid, + "work-net", + "10.20.0.0/24", + "192.0.2.0/30", + ); + resolver + .zone_resource_bundles + .insert("work".to_owned(), bytes.clone()); + resolver.parsed_zone_resources.insert( "work".to_owned(), - network_resource_bundle_bytes( - "work", - &zone_uid, - &network_uid, - "work-net", - "10.20.0.0/24", - "192.0.2.0/30", - ), + ResourceBundle::from_json(&bytes).expect("zone bundle parses"), ); let lan_id = intent_id_network_bridge_uids(&zone_uid, &network_uid, "work-net", false); @@ -7830,16 +7882,20 @@ mod tests { .unwrap(), ); let mut resolver = build_personal_dev_bundle(&root); - resolver.zone_resource_bundles.insert( + let bytes = network_resource_bundle_bytes( + "work", + &zone_uid, + &network_uid, + "work-net", + "10.20.0.0/24", + "192.0.2.0/30", + ); + resolver + .zone_resource_bundles + .insert("work".to_owned(), bytes.clone()); + resolver.parsed_zone_resources.insert( "work".to_owned(), - network_resource_bundle_bytes( - "work", - &zone_uid, - &network_uid, - "work-net", - "10.20.0.0/24", - "192.0.2.0/30", - ), + ResourceBundle::from_json(&bytes).expect("zone bundle parses"), ); let bridge_id = intent_id_network_bridge_uids(&zone_uid, &network_uid, "work-net", false); @@ -8206,12 +8262,15 @@ mod tests { let descriptor_digest = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let descriptors = BTreeMap::from([( - ("work".to_owned(), "guest".to_owned()), - serde_json::to_vec(&serde_json::json!({ - "descriptorDigest": descriptor_digest, - "systemArtifactId": "guest-system" - })) - .expect("descriptor"), + "work".to_owned(), + BTreeMap::from([( + "guest".to_owned(), + serde_json::to_vec(&serde_json::json!({ + "descriptorDigest": descriptor_digest, + "systemArtifactId": "guest-system" + })) + .expect("descriptor"), + )]), )]); let catalog = serde_json::json!({ "guestClosures": [{ @@ -8248,14 +8307,16 @@ mod tests { let (intents, zone_uids) = load_guest_vmm_intents(&catalog, &descriptors).expect("VMM intent"); let intent = intents - .get(&("work".to_owned(), "guest".to_owned())) + .get("work") + .and_then(|guests| guests.get("guest")) .expect("zone-local intent"); assert_eq!(intent.role, ProcessRole::CloudHypervisorRunner); assert_eq!(intent.vm_name, "guest"); assert_eq!(intent.execution_ref, "Host/host-system"); assert_eq!( zone_uids - .get(&("work".to_owned(), "guest".to_owned())) + .get("work") + .and_then(|guests| guests.get("guest")) .map(ResourceUid::as_str), Some("123e4567-e89b-42d3-a456-426614174000") ); @@ -8288,20 +8349,26 @@ mod tests { "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; let descriptors = BTreeMap::from([ ( - ("work".to_owned(), "desktop".to_owned()), - serde_json::to_vec(&serde_json::json!({ - "descriptorDigest": descriptor_digest, - "systemArtifactId": "desktop-system" - })) - .expect("work descriptor"), + "work".to_owned(), + BTreeMap::from([( + "desktop".to_owned(), + serde_json::to_vec(&serde_json::json!({ + "descriptorDigest": descriptor_digest, + "systemArtifactId": "desktop-system" + })) + .expect("work descriptor"), + )]), ), ( - ("personal".to_owned(), "desktop".to_owned()), - serde_json::to_vec(&serde_json::json!({ - "descriptorDigest": descriptor_digest, - "systemArtifactId": "desktop-system" - })) - .expect("personal descriptor"), + "personal".to_owned(), + BTreeMap::from([( + "desktop".to_owned(), + serde_json::to_vec(&serde_json::json!({ + "descriptorDigest": descriptor_digest, + "systemArtifactId": "desktop-system" + })) + .expect("personal descriptor"), + )]), ), ]); let guest_closure = |zone: &str, zone_uid: &str| { @@ -8362,11 +8429,13 @@ mod tests { let (runner_intents, zone_uids) = load_guest_vmm_intents(&catalog, &descriptors).expect("zone-qualified VMM intents"); - let work_key = ("work".to_owned(), "desktop".to_owned()); - let personal_key = ("personal".to_owned(), "desktop".to_owned()); - let work_runner = runner_intents.get(&work_key).expect("work desktop runner"); + let work_runner = runner_intents + .get("work") + .and_then(|guests| guests.get("desktop")) + .expect("work desktop runner"); let personal_runner = runner_intents - .get(&personal_key) + .get("personal") + .and_then(|guests| guests.get("desktop")) .expect("personal desktop runner"); assert_eq!( work_runner.intent_id, @@ -8389,7 +8458,14 @@ mod tests { work_runner.cgroup_placement.subtree, personal_runner.cgroup_placement.subtree ); - assert_ne!(zone_uids.get(&work_key), zone_uids.get(&personal_key)); + assert_ne!( + zone_uids + .get("work") + .and_then(|guests| guests.get("desktop")), + zone_uids + .get("personal") + .and_then(|guests| guests.get("desktop")) + ); } // v1.2 swtpm broker-pre-NS extension. diff --git a/packages/d2b-core/tests/bundle_resolver_tamper.rs b/packages/d2b-core/tests/bundle_resolver_tamper.rs index 7d31ec3ad..2645169d1 100644 --- a/packages/d2b-core/tests/bundle_resolver_tamper.rs +++ b/packages/d2b-core/tests/bundle_resolver_tamper.rs @@ -6,7 +6,8 @@ //! The tests use [`BundleVerifyPolicy`] with the **current process's** //! uid/gid so that files created without `chown` still pass the owner //! check. The "owner = nobody" test (`tamper_owner_wrong_uid`) requires -//! `chown` and is skipped automatically when the process is not root. +//! `chown` and is `#[ignore]`d (root-only), so the skip is visible in +//! test output instead of passing vacuously on non-root runs. //! //! These bundles are v3 zone-native (`schemaVersion: "v3"`, `bundleVersion: 1`, //! empty `zones`), so they load via the production zone-native path. The @@ -142,15 +143,13 @@ fn tamper_symlink() { // --------------------------------------------------------------- // Test 2: owner = wrong uid → BundleTampered { reason: "owner" } // -// Requires root (or CAP_CHOWN) to call fchown; skipped otherwise. +// Requires root (or CAP_CHOWN) to call fchown; ignored (not silently +// skipped) on non-root runs so the skip is visible in test output. +// Run with `--ignored` under root (or CAP_CHOWN) to exercise it. // --------------------------------------------------------------- #[test] +#[ignore = "root-only: requires CAP_CHOWN to chown the bundle file"] fn tamper_owner_wrong_uid() { - if rustix::process::getuid().as_raw() != 0 { - eprintln!("tamper_owner_wrong_uid: skipping - not root (cannot chown)"); - return; - } - let dir = TempDir::new().expect("tempdir"); let bundle_path = dir.path().join("bundle.json"); write_private(&bundle_path, &minimal_bundle_json_no_hash()); From 64fa00134dd32b9c3b855dbd0c9da14cc350c252 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:33:40 -0700 Subject: [PATCH 507/726] d2bd: bound the forward-rendezvous thread test to its own runtime The concurrent-calls test measured /proc/self/task, the process-wide thread count, and asserted the delta stayed under a few slots per call. Under parallel test load the binary runs hundreds of tests at once, and their runtimes and blocking pools spawn threads between the two measurements, so the bound failed even though no call owned a thread. Record instead the threads that executed this test's own held calls: the stall handler writes the executing thread id before holding the gate, and the test asserts the held calls ran on at most the runtime's worker threads. The measurement is per-test, so other tests cannot inflate it, and a per-call thread-ownership regression still puts each call on its own thread, far past the worker count. The forward helpers also tolerate a write that races the server's refuse-and-close: the refusal is queued before the close, so the reply is read instead of failing the call on EPIPE. --- .../fix-forward-rendezvous-test-bound.md | 10 ++ packages/d2bd/src/forward_rendezvous.rs | 122 ++++++++++++------ 2 files changed, 93 insertions(+), 39 deletions(-) create mode 100644 changelog.d/fix-forward-rendezvous-test-bound.md diff --git a/changelog.d/fix-forward-rendezvous-test-bound.md b/changelog.d/fix-forward-rendezvous-test-bound.md new file mode 100644 index 000000000..c8c4251f1 --- /dev/null +++ b/changelog.d/fix-forward-rendezvous-test-bound.md @@ -0,0 +1,10 @@ +### Fixed + +- The forward-rendezvous concurrent-calls test no longer reads the + process-wide thread count, which parallel test load inflates while other + tests spin up their runtimes. It now counts the threads that executed its + own held calls, so it stays deterministic under load and still fails when a + per-call thread-ownership regression returns. +- The forward-rendezvous test clients no longer fail when a refused call's + write races the server's refuse-and-close: the refusal is already queued + for the socket, so the reply is read instead of the write error. \ No newline at end of file diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index d1d8d7dd9..793f48d4c 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -1809,6 +1809,10 @@ mod tests { /// A handler that holds its call on the gate until the test releases it. struct GatedHandler { gate: &'static StallGate, + /// When present, records the thread that executed the call before + /// holding it: the concurrent-calls test counts the distinct + /// threads across the held calls. + seen: Option<&'static tokio::sync::Mutex>>, } #[async_trait::async_trait] @@ -1818,6 +1822,9 @@ mod tests { _ctx: OperationCtx<'_>, _payload: ValidatedPayload, ) -> Result { + if let Some(seen) = self.seen { + seen.lock().await.push(std::thread::current().id()); + } self.gate.hold().await; Ok(stall_result()) } @@ -1838,11 +1845,20 @@ mod tests { } } + /// The threads that executed the held stall-threads calls, one entry + /// per call, recorded at handler entry. This recorder is this test's + /// own: only the calls the concurrent-calls test forwards execute the + /// stall-threads handler, so nothing another test does can inflate it. + static THREADS_SEEN: tokio::sync::Mutex> = + tokio::sync::Mutex::const_new(Vec::new()); + static THREADS_HANDLER: GatedHandler = GatedHandler { gate: &THREADS_GATE, + seen: Some(&THREADS_SEEN), }; static CAPACITY_HANDLER: GatedHandler = GatedHandler { gate: &CAPACITY_GATE, + seen: None, }; static STALLED_HANDLER: StalledHandler = StalledHandler; @@ -2278,10 +2294,20 @@ mod tests { let connection = AsyncSeqpacket::register(Socket::from(socket)).expect("register the forwarded call"); let deadline = Duration::from_secs(10); - connection - .write_frame(&encoded, deadline) - .await - .expect("write the request frame"); + // A refused peer is answered before its frame is read: the server + // writes the refusal, drains briefly, and closes, so a write that + // races the close can fail with EPIPE even though the refusal is + // already queued for this socket. Read the queued refusal instead + // of failing the call; only a write error with no reply is a + // failure. + if let Err(write_error) = connection.write_frame(&encoded, deadline).await { + let frame = connection.read_frame(deadline).await; + if let Ok(frame) = frame { + return serde_json::from_slice(&frame) + .expect("the reply is a ForwardOperationResponse"); + } + panic!("write the request frame: {write_error:?}"); + } let frame = connection .read_frame(deadline) .await @@ -2357,27 +2383,6 @@ mod tests { sink } - /// The threads this process is running, one per task entry. - /// - /// `tokio::fs` (plan U10): the count probes the process's own thread - /// table, so the async form never parks an executor worker on the - /// directory read. - async fn thread_count() -> usize { - let mut entries = tokio::fs::read_dir("/proc/self/task") - .await - .expect("/proc/self/task is readable"); - let mut count = 0usize; - while entries - .next_entry() - .await - .expect("/proc/self/task is readable") - .is_some() - { - count += 1; - } - count - } - /// The production posture with a test's own in-flight cap and handler /// deadline. fn posture(max_inflight: usize, handler_deadline: Duration) -> ServingPosture { @@ -2412,8 +2417,19 @@ mod tests { // endpoint is exercised against the exact bytes the broker sends. let encoded = canonical_json_bytes(&request).expect("the request encodes as canonical JSON"); - d2bd_runtime::unix_transport::write_frame(&socket, &encoded) - .expect("write the request frame"); + // A refused peer is answered before its frame is read: the server + // writes the refusal, drains briefly, and closes, so a write that + // races the close can fail with EPIPE even though the refusal is + // already queued for this socket. Read the queued refusal instead + // of failing the call; only a write error with no reply is a + // failure. + if let Err(write_error) = d2bd_runtime::unix_transport::write_frame(&socket, &encoded) { + if let Ok(frame) = read_frame(&socket) { + return serde_json::from_slice(&frame) + .expect("the reply is a ForwardOperationResponse"); + } + panic!("write the request frame: {write_error:?}"); + } let frame = read_frame(&socket).expect("read the reply frame"); serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") } @@ -2444,7 +2460,19 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") let encoded = canonical_json_bytes(&request).expect("the request encodes as canonical JSON"); let socket = connect_seqpacket(socket_path).expect("dial the rendezvous"); - write_frame_with_fds(&socket, &encoded, fds).expect("write the request frame with fds"); + // A refused peer is answered before its frame is read: the server + // writes the refusal, drains briefly, and closes, so a write that + // races the close can fail with EPIPE even though the refusal is + // already queued for this socket. Read the queued refusal instead + // of failing the call; only a write error with no reply is a + // failure. + if let Err(write_error) = write_frame_with_fds(&socket, &encoded, fds) { + if let Ok(frame) = read_frame(&socket) { + return serde_json::from_slice(&frame) + .expect("the reply is a ForwardOperationResponse"); + } + panic!("write the request frame with fds: {write_error:?}"); + } let frame = read_frame(&socket).expect("read the reply frame"); serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") } @@ -2902,6 +2930,9 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn concurrent_calls_are_held_on_the_runtime_without_a_thread_each() { const CALLS: usize = 4; + // The runtime this test runs on: the serving path registers with + // `Handle::current()`, so the held calls execute on these workers. + const WORKER_THREADS: usize = 2; let serving = ServingRendezvous::start().await; // One warm call, so the runtime's workers exist before the baseline. let warm = forward_async( @@ -2916,7 +2947,9 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") ForwardOperationOutcome::Result { .. } )); - let before = thread_count().await; + // The recorder is this test's own: only the calls below execute the + // stall-threads handler, so no other test can inflate the count. + THREADS_SEEN.lock().await.clear(); let calls: Vec<_> = (0..CALLS) .map(|_| { tokio::spawn(forward_async( @@ -2930,18 +2963,29 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") // Every call reached the handler while none of them was released: the // second call does not wait for the first. THREADS_GATE.wait_for(CALLS).await; - let held = thread_count().await; - // The counter is process-wide (/proc/self/task): other tests' - // runtimes and their blocking pools grow concurrently under - // parallel test load, and this runtime's own blocking pool expands - // amortized (reused, bounded by peak concurrency), so the bound is - // a few slots per call, never a thread owned per call. A - // per-call thread-ownership regression - one OS thread held for - // the lifetime of each in-flight call - blows far past this. + // The held calls all run on this runtime's own workers: at most + // WORKER_THREADS distinct threads can have executed the handler. A + // per-call thread-ownership regression - one OS thread held for the + // lifetime of each in-flight call - puts each call on its own + // thread, far past the worker count. The measurement is per-test + // (threads that executed this test's handler), so parallel test + // load cannot inflate it. + let seen = THREADS_SEEN.lock().await; + assert_eq!( + seen.len(), + CALLS, + "every held call recorded the thread that executed it" + ); + let distinct = seen + .iter() + .copied() + .collect::>(); assert!( - held <= before + CALLS * 4, - "{CALLS} calls in flight must not each own a thread: {before} -> {held}" + distinct.len() <= WORKER_THREADS, + "{CALLS} calls in flight must not each own a thread: held on {} distinct threads (the runtime has {WORKER_THREADS} workers)", + distinct.len() ); + drop(seen); THREADS_GATE.release(CALLS); for call in calls { From d5ab66ec5abd450cf85bb2e666183d3d1ec8872e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:36:24 -0700 Subject: [PATCH 508/726] clipboard: share selection payloads by Arc and cover history and gate tests Host-selection record, history materialization, and bridge-copy publish now bump Arc refcounts instead of copying payload maps; the niri IPC line reader reads 4 KiB chunks; the permit and helper-thread counters use Relaxed ordering; the published-selection echo identity wrapper is gone. Unit tests cover history eviction and expiry, the display-route admission shapes, the picker-cancel transition, and the niri window-closed and workspace-activated paths. --- changelog.d/w3-15-clipboard-perf-tests.md | 24 ++ .../src/bin/d2b-clipd.rs | 70 ++--- .../src/clipd_host/fallback.rs | 22 ++ .../src/clipd_host/niri.rs | 115 +++++++- .../src/controller/mod.rs | 270 ++++++++++++++++-- .../d2b-provider-clipboard-wayland/src/fd.rs | 10 +- .../src/history.rs | 109 ++++++- 7 files changed, 532 insertions(+), 88 deletions(-) create mode 100644 changelog.d/w3-15-clipboard-perf-tests.md diff --git a/changelog.d/w3-15-clipboard-perf-tests.md b/changelog.d/w3-15-clipboard-perf-tests.md new file mode 100644 index 000000000..95dcc2b0d --- /dev/null +++ b/changelog.d/w3-15-clipboard-perf-tests.md @@ -0,0 +1,24 @@ +# `w3-15-clipboard-perf-tests.md` + +### Changed + +- d2b-clipd now shares clipboard payload maps by reference instead of + copying every byte when a host selection is recorded, a history entry is + materialized, or a bridge copy is published, so large pastes no longer + pay a full copy per path. +- The niri IPC line reader now reads in 4 KiB chunks instead of one byte + per read syscall, keeping the same maximum-line bound. +- The descriptor permit pool and helper-thread counters now use relaxed + atomic ordering; the counts publish no data, so the weaker ordering is + sufficient and cheaper. + +### Fixed + +- The clipboard history now has unit coverage for its entry-count and + byte-quota eviction order, materialization owner and TTL rejections, and + entry expiry reporting. +- The controller's display-dependency admission gates now have unit tests + covering the accepted route shape and each rejected shape, including the + evidence class, locality, subject type, and generation checks. +- The picker-cancel transition and the niri window-closed and + workspace-activated cache paths are now covered by unit tests. \ No newline at end of file diff --git a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs index c7b21e79e..ca0a0b48f 100644 --- a/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs @@ -17,6 +17,7 @@ use std::os::unix::fs::{DirBuilderExt, FileTypeExt, PermissionsExt}; use std::os::unix::net::{UnixListener, UnixStream}; use std::path::{Path, PathBuf}; use std::sync::{ + Arc, atomic::{AtomicUsize, Ordering}, mpsc, }; @@ -77,12 +78,12 @@ struct HelperThreadPermit; impl Drop for HelperThreadPermit { fn drop(&mut self) { - HELPER_THREADS.fetch_sub(1, Ordering::Release); + HELPER_THREADS.fetch_sub(1, Ordering::Relaxed); } } fn try_acquire_helper_thread() -> Result { - let mut current = HELPER_THREADS.load(Ordering::Acquire); + let mut current = HELPER_THREADS.load(Ordering::Relaxed); loop { if current >= MAX_HELPER_THREADS { return Err(ReasonCode::FdCapExceeded); @@ -90,8 +91,8 @@ fn try_acquire_helper_thread() -> Result { match HELPER_THREADS.compare_exchange_weak( current, current + 1, - Ordering::AcqRel, - Ordering::Acquire, + Ordering::Relaxed, + Ordering::Relaxed, ) { Ok(_) => return Ok(HelperThreadPermit), Err(next) => current = next, @@ -926,14 +927,14 @@ struct BridgeSelectionState { history_entry_id: String, timestamp_unix_ms: u64, suppress_selection_echo: bool, - data_by_mime: BTreeMap>, + data_by_mime: Arc>>, } #[derive(Debug)] struct PublishedSelectionState { data_control_source_id: u64, _source: DataControlSource, - data_by_mime: BTreeMap>, + data_by_mime: Arc>>, mode: PublishedSelectionMode, suppress_selection_echo: bool, } @@ -958,7 +959,7 @@ struct ClipboardHistoryEntry { source_app: Option, source_app_id: Option, source_attribution: AttributionQuality, - data_by_mime: BTreeMap>, + data_by_mime: Arc>>, timestamp_unix_ms: u64, } @@ -1043,11 +1044,11 @@ impl ClipboardHistory { .collect() } - fn data_for(&self, entry_id: &str) -> Option>> { + fn data_for(&self, entry_id: &str) -> Option>>> { self.entries .iter() .find(|entry| entry.entry_id == entry_id) - .map(|entry| entry.data_by_mime.clone()) + .map(|entry| Arc::clone(&entry.data_by_mime)) } } @@ -1820,7 +1821,7 @@ fn handle_bridge_copy_ready(ready: BridgeCopyReady, context: &mut BridgeCopyRead history_entry_id: bridge_history_entry_id(&identity, source_id), timestamp_unix_ms: unix_millis(), suppress_selection_echo: true, - data_by_mime: BTreeMap::new(), + data_by_mime: Arc::new(BTreeMap::new()), }); } @@ -1828,7 +1829,7 @@ fn handle_bridge_copy_ready(ready: BridgeCopyReady, context: &mut BridgeCopyRead return; }; selection.suppress_selection_echo = true; - selection.data_by_mime.insert(mime_type, bytes); + Arc::make_mut(&mut selection.data_by_mime).insert(mime_type, bytes); context.history.upsert(ClipboardHistoryEntry { entry_id: selection.history_entry_id.clone(), source_realm: selection.identity.realm_label(), @@ -1838,12 +1839,12 @@ fn handle_bridge_copy_ready(ready: BridgeCopyReady, context: &mut BridgeCopyRead source_app: Some(endpoint_source_app(&selection.identity)), source_app_id: Some(format!("d2b.{}", selection.identity.target_label())), source_attribution: AttributionQuality::ExactClient, - data_by_mime: selection.data_by_mime.clone(), + data_by_mime: Arc::clone(&selection.data_by_mime), timestamp_unix_ms: selection.timestamp_unix_ms, }); match publish_data_control_selection( context.data_control, - selection.data_by_mime.clone(), + Arc::clone(&selection.data_by_mime), PublishedSelectionMode::Discovery, ) { Ok(published) => { @@ -2151,7 +2152,7 @@ fn handle_wayland_event(event: HostClipboardEvent, context: &mut WaylandEventCon .as_ref() .and_then(|window| window.app_id.clone()), source_attribution: AttributionQuality::FocusedWindowGuess, - data_by_mime: BTreeMap::new(), + data_by_mime: Arc::new(BTreeMap::new()), timestamp_unix_ms: unix_millis(), }; materialize_offer_mimes_async( @@ -2772,7 +2773,7 @@ fn publish_selected_entry_to_host( fn publish_data_control_selection( data_control: &mut DataControlClient, - data_by_mime: BTreeMap>, + data_by_mime: Arc>>, mode: PublishedSelectionMode, ) -> Result { if data_by_mime.is_empty() { @@ -2799,16 +2800,16 @@ fn selected_entry_data_by_mime( current_host_entry: Option<&ClipboardHistoryEntry>, history: &ClipboardHistory, entry_id: &str, -) -> Result>, ReasonCode> { +) -> Result>>, ReasonCode> { if entry_id == CURRENT_HOST_ENTRY_ID { return current_host_entry - .map(|entry| entry.data_by_mime.clone()) + .map(|entry| Arc::clone(&entry.data_by_mime)) .filter(|data| !data.is_empty()) .ok_or(ReasonCode::RequestExpired); } if entry_id == CURRENT_BRIDGE_ENTRY_ID { return bridge_selection - .map(|selection| selection.data_by_mime.clone()) + .map(|selection| Arc::clone(&selection.data_by_mime)) .filter(|data| !data.is_empty()) .ok_or(ReasonCode::RequestExpired); } @@ -2871,7 +2872,7 @@ fn materialize_offer_mimes_async( if let Ok(bytes) = read_fd_to_vec(read_fd, MATERIALIZE_MAX_BYTES, BOUNDED_READ_TIMEOUT) { - entry.data_by_mime.insert(mime, bytes); + Arc::make_mut(&mut entry.data_by_mime).insert(mime, bytes); } } if !entry.data_by_mime.is_empty() { @@ -3781,14 +3782,7 @@ fn should_suppress_published_selection_echo( published_selection: Option<&PublishedSelectionState>, _bridge_selection: Option<&BridgeSelectionState>, ) -> bool { - let Some(selection) = published_selection else { - return false; - }; - should_suppress_published_selection_echo_state(selection.suppress_selection_echo) -} - -fn should_suppress_published_selection_echo_state(suppress_selection_echo: bool) -> bool { - suppress_selection_echo + published_selection.is_some_and(|selection| selection.suppress_selection_echo) } fn should_drop_discovery_source_send( @@ -3953,7 +3947,7 @@ mod tests { history_entry_id: bridge_history_entry_id(&identity, 7), timestamp_unix_ms: 1, suppress_selection_echo: false, - data_by_mime: BTreeMap::new(), + data_by_mime: Arc::new(BTreeMap::new()), }; let source_vm_window = FocusedWindowSnapshot { app_id: Some("d2b.personal-dev.firefox".to_owned()), @@ -3988,7 +3982,7 @@ mod tests { history_entry_id: bridge_history_entry_id(&identity, 7), timestamp_unix_ms: 1, suppress_selection_echo: true, - data_by_mime: BTreeMap::new(), + data_by_mime: Arc::new(BTreeMap::new()), }; let source_vm_window = FocusedWindowSnapshot { app_id: Some("d2b.personal-dev.firefox".to_owned()), @@ -4019,12 +4013,6 @@ mod tests { )); } - #[test] - fn published_selection_echo_is_always_suppressed_once() { - assert!(should_suppress_published_selection_echo_state(true)); - assert!(!should_suppress_published_selection_echo_state(false)); - } - #[test] fn bridge_paste_direct_serve_requires_user_selected_publication() { assert!(published_selection_can_serve_bridge_paste( @@ -4180,7 +4168,7 @@ mod tests { source_app: Some("personal-dev VM".to_owned()), source_app_id: Some("d2b.personal-dev".to_owned()), source_attribution: AttributionQuality::ExactClient, - data_by_mime: vm_data, + data_by_mime: Arc::new(vm_data), timestamp_unix_ms: 20, }); @@ -4195,7 +4183,7 @@ mod tests { source_app: Some("old host".to_owned()), source_app_id: Some("firefox".to_owned()), source_attribution: AttributionQuality::FocusedWindowGuess, - data_by_mime: host_data, + data_by_mime: Arc::new(host_data), timestamp_unix_ms: 10, }; let host_clipboard = HostClipboard::new( @@ -4221,7 +4209,7 @@ mod tests { history_entry_id: bridge_history_entry_id(&identity, 7), timestamp_unix_ms: 1_700_000_000_000, suppress_selection_echo: false, - data_by_mime, + data_by_mime: Arc::new(data_by_mime), }; let candidates = picker_bridge_candidates(&selection, "text/plain;charset=utf-8"); @@ -4259,7 +4247,7 @@ mod tests { source_app: Some("personal-dev VM".to_owned()), source_app_id: Some("d2b.personal-dev".to_owned()), source_attribution: AttributionQuality::ExactClient, - data_by_mime: first, + data_by_mime: Arc::new(first), timestamp_unix_ms: 1, }); @@ -4275,7 +4263,7 @@ mod tests { source_app: Some("personal-dev VM".to_owned()), source_app_id: Some("d2b.personal-dev".to_owned()), source_attribution: AttributionQuality::ExactClient, - data_by_mime: second, + data_by_mime: Arc::new(second), timestamp_unix_ms: 1, }); @@ -4321,7 +4309,7 @@ mod tests { history_entry_id: bridge_history_entry_id(&identity, 9), timestamp_unix_ms: 1, suppress_selection_echo: true, - data_by_mime, + data_by_mime: Arc::new(data_by_mime), }; let candidates = picker_bridge_candidates(&selection, "text/plain"); diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs index af2795839..b087a4847 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs @@ -197,6 +197,28 @@ mod tests { ); } + #[test] + fn cancel_picker_clears_picker_open_and_armed_states() { + let mut arming = FallbackArming::default(); + assert_eq!(arming.cancel_picker(), FallbackTransition::Idle); + assert_eq!(arming.state(), &FallbackState::Idle); + + arming.capture_target_before_picker(target(7, "firefox")); + assert_eq!( + arming.cancel_picker(), + FallbackTransition::Cleared(FallbackClearReason::PickerCancelled) + ); + assert_eq!(arming.state(), &FallbackState::Idle); + + arming.capture_target_before_picker(target(7, "firefox")); + arming.arm_selected_entry("entry-a".to_owned(), Instant::now(), Duration::from_secs(2)); + assert_eq!( + arming.cancel_picker(), + FallbackTransition::Cleared(FallbackClearReason::PickerCancelled) + ); + assert_eq!(arming.state(), &FallbackState::Idle); + } + #[test] fn clears_on_timeout_and_new_native_selection() { let mut arming = FallbackArming::default(); diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs index b34ebaae2..14272c51d 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs @@ -144,20 +144,21 @@ pub fn read_bounded_ndjson_line( max_line_bytes: usize, ) -> Result { let mut line = Vec::new(); - let mut byte = [0_u8; 1]; + let mut chunk = [0_u8; 4096]; loop { - match reader.read(&mut byte) { - Ok(0) if line.is_empty() => return Err(NiriIpcError::Incomplete), + match reader.read(&mut chunk) { Ok(0) => return Err(NiriIpcError::Incomplete), - Ok(_) if byte[0] == b'\n' => { - return String::from_utf8(line).map_err(|_| NiriIpcError::InvalidUtf8); - } - Ok(_) => { - line.push(byte[0]); - if line.len() > max_line_bytes { - return Err(NiriIpcError::FrameTooLong { - max: max_line_bytes, - }); + Ok(n) => { + for &byte in &chunk[..n] { + if byte == b'\n' { + return String::from_utf8(line).map_err(|_| NiriIpcError::InvalidUtf8); + } + line.push(byte); + if line.len() > max_line_bytes { + return Err(NiriIpcError::FrameTooLong { + max: max_line_bytes, + }); + } } } Err(err) => return Err(NiriIpcError::Io(err.to_string())), @@ -596,6 +597,96 @@ mod tests { assert_eq!(focused.output_label.as_deref(), Some("DP-1")); } + #[test] + fn cache_clears_focus_when_the_focused_window_closes() { + let mut cache = NiriStateCache::default(); + cache.apply_event(NiriEvent::WindowsChanged { + windows: vec![ + NiriWindow { + id: Some(7), + app_id: Some("foot".to_owned()), + title: Some("shell".to_owned()), + is_focused: Some(true), + ..NiriWindow::default() + }, + NiriWindow { + id: Some(8), + app_id: Some("firefox".to_owned()), + title: Some("docs".to_owned()), + is_focused: Some(false), + ..NiriWindow::default() + }, + ], + }); + assert_eq!(cache.focused_window().map(|window| window.id), Some(Some(7))); + + cache.apply_event(NiriEvent::WindowClosed { id: Some(7) }); + + assert!(cache.focused_window().is_none()); + assert!(cache.is_stale()); + cache.apply_event(NiriEvent::WindowChanged { + window: NiriWindow { + id: Some(7), + app_id: Some("foot".to_owned()), + title: Some("shell".to_owned()), + is_focused: Some(true), + ..NiriWindow::default() + }, + }); + assert_eq!(cache.focused_window().map(|window| window.id), Some(Some(7))); + } + + #[test] + fn cache_ignores_closing_a_non_focused_window() { + let mut cache = NiriStateCache::default(); + cache.apply_event(NiriEvent::WindowsChanged { + windows: vec![ + NiriWindow { + id: Some(7), + app_id: Some("foot".to_owned()), + title: Some("shell".to_owned()), + is_focused: Some(true), + ..NiriWindow::default() + }, + NiriWindow { + id: Some(8), + app_id: Some("firefox".to_owned()), + title: Some("docs".to_owned()), + ..NiriWindow::default() + }, + ], + }); + + cache.apply_event(NiriEvent::WindowClosed { id: Some(8) }); + + assert_eq!(cache.focused_window().map(|window| window.id), Some(Some(7))); + assert!(!cache.is_stale()); + assert_eq!(cache.focused_window().map(|window| window.app_id), Some(Some("foot".to_owned()))); + } + + #[test] + fn cache_ignores_workspace_activation_events() { + let mut cache = NiriStateCache::default(); + cache.apply_event(NiriEvent::WindowsChanged { + windows: vec![NiriWindow { + id: Some(7), + app_id: Some("foot".to_owned()), + title: Some("shell".to_owned()), + is_focused: Some(true), + ..NiriWindow::default() + }], + }); + + cache.apply_event(NiriEvent::WorkspaceActivated { + id: Some(3), + focused: true, + }); + + assert_eq!(cache.focused_window().map(|window| window.id), Some(Some(7))); + assert_eq!(cache.focused_window().map(|window| window.app_id), Some(Some("foot".to_owned()))); + assert!(!cache.is_stale()); + } + #[test] fn cache_resolves_focus_event_when_window_details_arrive_later() { let mut cache = NiriStateCache::default(); diff --git a/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs b/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs index 01201ed42..c01c4112e 100644 --- a/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs +++ b/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs @@ -71,6 +71,67 @@ pub struct DisplayDependencyEvidence { pub(crate) session_digest: [u8; 32], } +/// Validate the Core-authenticated display route shape: canonical display +/// Provider, display v3 service, UnixPeer evidence, Local locality, a User +/// subject, nonzero generations, and a Host execution context. +fn validate_authenticated_route_shape( + provider_ref: &ResourceRef, + service: &str, + evidence_class: EvidenceClass, + locality: Locality, + subject_type: &str, + reconnect_generation: u64, + provider_generation: u64, + host_execution_type: &str, + controller_generation: u64, +) -> Result<(), &'static str> { + if provider_ref.to_canonical_string() != DISPLAY_PROVIDER_REF + || service != "d2b.display.v3" + || evidence_class != EvidenceClass::UnixPeer + || locality != Locality::Local + || subject_type != "User" + || reconnect_generation == 0 + || provider_generation == 0 + || host_execution_type != "Host" + || controller_generation == 0 + { + return Err("clipboard-display-unauthenticated"); + } + Ok(()) +} + +/// Validate the daemon-authenticated display route shape: the canonical +/// display Provider, display v3 service, UnixPeer evidence, Local locality, +/// a Guest subject, a committed User reference, nonzero generations, and a +/// Host execution context. +fn validate_committed_display_route_shape( + provider_ref: &ResourceRef, + service: &str, + evidence_class: EvidenceClass, + locality: Locality, + subject_type: &str, + user_ref_type: &str, + reconnect_generation: u64, + provider_generation: u64, + host_execution_type: &str, + controller_generation: u64, +) -> Result<(), &'static str> { + if provider_ref.to_canonical_string() != DISPLAY_PROVIDER_REF + || service != "d2b.display.v3" + || evidence_class != EvidenceClass::UnixPeer + || locality != Locality::Local + || subject_type != "Guest" + || user_ref_type != "User" + || reconnect_generation == 0 + || provider_generation == 0 + || host_execution_type != "Host" + || controller_generation == 0 + { + return Err("clipboard-display-unauthenticated"); + } + Ok(()) +} + impl DisplayDependencyEvidence { /// Consume a Core-authenticated display route. /// @@ -87,26 +148,23 @@ impl DisplayDependencyEvidence { let Some(provider_generation) = route.provider_generation() else { return Err("clipboard-display-unauthenticated"); }; - if provider_ref.to_canonical_string() != DISPLAY_PROVIDER_REF - || route.service().as_str() != "d2b.display.v3" - || route.evidence_class() != EvidenceClass::UnixPeer - || route.locality() != Locality::Local - || route.subject_ref().resource_type().as_str() != "User" - || route.reconnect_generation().get() == 0 - || provider_generation.get() == 0 - { - return Err("clipboard-display-unauthenticated"); - } let Some(host_execution_ref) = route.context().execution_ref() else { return Err("clipboard-display-unauthenticated"); }; let Some(controller_generation) = route.controller_generation() else { return Err("clipboard-display-unauthenticated"); }; - if host_execution_ref.resource_type().as_str() != "Host" || controller_generation.get() == 0 - { - return Err("clipboard-display-unauthenticated"); - } + validate_authenticated_route_shape( + provider_ref, + route.service().as_str(), + route.evidence_class(), + route.locality(), + route.subject_ref().resource_type().as_str(), + route.reconnect_generation().get(), + provider_generation.get(), + host_execution_ref.resource_type().as_str(), + controller_generation.get(), + )?; let mut digest = Sha256::new(); digest.update(provider_ref.to_canonical_string().as_bytes()); digest.update([0]); @@ -147,27 +205,24 @@ impl DisplayDependencyEvidence { let Some(provider_generation) = route.provider_generation() else { return Err("clipboard-display-unauthenticated"); }; - if provider_ref.to_canonical_string() != DISPLAY_PROVIDER_REF - || route.service().as_str() != "d2b.display.v3" - || route.evidence_class() != EvidenceClass::UnixPeer - || route.locality() != Locality::Local - || route.subject_ref().resource_type().as_str() != "Guest" - || user_ref.resource_type().as_str() != "User" - || route.reconnect_generation().get() == 0 - || provider_generation.get() == 0 - { - return Err("clipboard-display-unauthenticated"); - } let Some(host_execution_ref) = route.context().execution_ref() else { return Err("clipboard-display-unauthenticated"); }; let Some(controller_generation) = route.controller_generation() else { return Err("clipboard-display-unauthenticated"); }; - if host_execution_ref.resource_type().as_str() != "Host" || controller_generation.get() == 0 - { - return Err("clipboard-display-unauthenticated"); - } + validate_committed_display_route_shape( + provider_ref, + route.service().as_str(), + route.evidence_class(), + route.locality(), + route.subject_ref().resource_type().as_str(), + user_ref.resource_type().as_str(), + route.reconnect_generation().get(), + provider_generation.get(), + host_execution_ref.resource_type().as_str(), + controller_generation.get(), + )?; let mut digest = Sha256::new(); digest.update(provider_ref.to_canonical_string().as_bytes()); digest.update([0]); @@ -340,6 +395,68 @@ impl core::fmt::Debug for ClipboardController { mod tests { use super::*; + const DISPLAY_SERVICE: &str = "d2b.display.v3"; + + fn display_provider() -> ResourceRef { + ResourceRef::parse(DISPLAY_PROVIDER_REF).unwrap() + } + + fn assert_authenticated_shape_rejected( + provider_ref: &ResourceRef, + service: &str, + evidence_class: EvidenceClass, + locality: Locality, + subject_type: &str, + reconnect_generation: u64, + provider_generation: u64, + host_execution_type: &str, + controller_generation: u64, + ) { + assert_eq!( + validate_authenticated_route_shape( + provider_ref, + service, + evidence_class, + locality, + subject_type, + reconnect_generation, + provider_generation, + host_execution_type, + controller_generation, + ), + Err("clipboard-display-unauthenticated") + ); + } + + fn assert_committed_shape_rejected( + provider_ref: &ResourceRef, + service: &str, + evidence_class: EvidenceClass, + locality: Locality, + subject_type: &str, + user_ref_type: &str, + reconnect_generation: u64, + provider_generation: u64, + host_execution_type: &str, + controller_generation: u64, + ) { + assert_eq!( + validate_committed_display_route_shape( + provider_ref, + service, + evidence_class, + locality, + subject_type, + user_ref_type, + reconnect_generation, + provider_generation, + host_execution_type, + controller_generation, + ), + Err("clipboard-display-unauthenticated") + ); + } + fn dependency(provider_ref: &str) -> DisplayDependencyEvidence { DisplayDependencyEvidence { provider_ref: ResourceRef::parse(provider_ref).unwrap(), @@ -353,6 +470,101 @@ mod tests { } } + #[test] + fn authenticated_route_shape_accepts_only_the_canonical_user_route() { + assert_eq!( + validate_authenticated_route_shape( + &display_provider(), + DISPLAY_SERVICE, + EvidenceClass::UnixPeer, + Locality::Local, + "User", + 1, + 1, + "Host", + 1, + ), + Ok(()) + ); + } + + #[test] + fn authenticated_route_shape_rejects_each_wrong_value() { + let cases: [(&str, &str, EvidenceClass, Locality, &str, u64, u64, &str, u64); 9] = [ + ("Provider/other", DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, "d2b.other.v3", EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::EnrolledKk, Locality::Local, "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Remote, "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 0, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 0, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Guest", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Host", 0), + ]; + for (provider, service, evidence_class, locality, subject, reconnect, provider_generation, host, controller) in cases { + assert_authenticated_shape_rejected( + &ResourceRef::parse(provider).unwrap(), + service, + evidence_class, + locality, + subject, + reconnect, + provider_generation, + host, + controller, + ); + } + } + + #[test] + fn committed_display_route_shape_accepts_only_the_canonical_guest_route() { + assert_eq!( + validate_committed_display_route_shape( + &display_provider(), + DISPLAY_SERVICE, + EvidenceClass::UnixPeer, + Locality::Local, + "Guest", + "User", + 1, + 1, + "Host", + 1, + ), + Ok(()) + ); + } + + #[test] + fn committed_display_route_shape_rejects_each_wrong_value() { + let cases: [(&str, &str, EvidenceClass, Locality, &str, &str, u64, u64, &str, u64); 10] = [ + ("Provider/other", DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, "d2b.other.v3", EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::EnrolledKk, Locality::Local, "Guest", "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Remote, "Guest", "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", "User", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "Guest", 1, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 0, 1, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 0, "Host", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Guest", 1), + (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Host", 0), + ]; + for (provider, service, evidence_class, locality, subject, user_ref, reconnect, provider_generation, host, controller) in cases { + assert_committed_shape_rejected( + &ResourceRef::parse(provider).unwrap(), + service, + evidence_class, + locality, + subject, + user_ref, + reconnect, + provider_generation, + host, + controller, + ); + } + } + #[test] fn dependency_status_requires_the_canonical_display_provider() { let controller = ClipboardController::new("Host/host-system", "User/alice").unwrap(); diff --git a/packages/d2b-provider-clipboard-wayland/src/fd.rs b/packages/d2b-provider-clipboard-wayland/src/fd.rs index 7efcb4bdd..cd92e441c 100644 --- a/packages/d2b-provider-clipboard-wayland/src/fd.rs +++ b/packages/d2b-provider-clipboard-wayland/src/fd.rs @@ -542,7 +542,7 @@ impl FdPermitPool { /// Return the number of currently retained descriptors. pub fn active(&self) -> usize { - self.active.load(Ordering::Acquire) + self.active.load(Ordering::Relaxed) } /// Reserve ownership for one accepted descriptor batch. @@ -552,7 +552,7 @@ impl FdPermitPool { /// Returns [`FdSafetyError::ConcurrentLimitExceeded`] when the batch /// would push the retained descriptor count past the pool limit. pub fn acquire(&self, requested: usize) -> Result { - let mut active = self.active.load(Ordering::Acquire); + let mut active = self.active.load(Ordering::Relaxed); loop { let next = active @@ -572,8 +572,8 @@ impl FdPermitPool { match self.active.compare_exchange_weak( active, next, - Ordering::AcqRel, - Ordering::Acquire, + Ordering::Relaxed, + Ordering::Relaxed, ) { Ok(_) => { return Ok(FdPermit { @@ -602,7 +602,7 @@ impl core::fmt::Debug for FdPermit { impl Drop for FdPermit { fn drop(&mut self) { if self.count != 0 { - self.pool.active.fetch_sub(self.count, Ordering::AcqRel); + self.pool.active.fetch_sub(self.count, Ordering::Relaxed); } } } diff --git a/packages/d2b-provider-clipboard-wayland/src/history.rs b/packages/d2b-provider-clipboard-wayland/src/history.rs index a83392df3..6b355c4ca 100644 --- a/packages/d2b-provider-clipboard-wayland/src/history.rs +++ b/packages/d2b-provider-clipboard-wayland/src/history.rs @@ -399,10 +399,117 @@ impl core::fmt::Debug for ClipboardHistory { #[cfg(test)] mod tests { - use super::{ClipboardEntry, ClipboardHistory}; + use super::{ClipboardEntry, ClipboardHistory, HistoryError}; use crate::picker::CompletionKey; + use crate::policy::Policy; use crate::ClipboardConfig; + fn small_history() -> ClipboardHistory { + let policy = Policy::new( + true, + true, + true, + true, + false, + 3, + 4096, + 8192, + 32, + 60, + ) + .expect("test policy"); + ClipboardHistory::new(ClipboardConfig::from_policy(policy)) + } + + #[test] + fn insert_evicts_the_oldest_entry_past_the_count_bound() { + let mut history = small_history(); + let mut tokens = Vec::new(); + for index in 0..4 { + let entry = ClipboardEntry::new( + "Guest/work", + "text/plain", + format!("entry-{index}").as_bytes(), + 100, + ) + .unwrap(); + let token = entry.token().to_owned(); + tokens.push(token); + history.insert(entry).unwrap(); + } + + assert_eq!(history.len(), 3); + assert!(!history.entries.contains_key(&tokens[0])); + assert!(history.entries.contains_key(&tokens[1])); + assert!(history.entries.contains_key(&tokens[2])); + assert!(history.entries.contains_key(&tokens[3])); + assert_eq!(history.order.front().map(String::as_str), Some(tokens[1].as_str())); + } + + #[test] + fn insert_evicts_oldest_until_the_byte_quota_holds() { + let mut history = small_history(); + let mut tokens = Vec::new(); + for index in 0..3 { + let payload = vec![index as u8; 4096]; + let entry = + ClipboardEntry::new("Guest/work", "text/plain", &payload, 100).unwrap(); + let token = entry.token().to_owned(); + tokens.push(token); + history.insert(entry).unwrap(); + } + + assert_eq!(history.len(), 2); + assert_eq!(history.total_bytes, 8192); + assert!(!history.entries.contains_key(&tokens[0])); + assert!(history.entries.contains_key(&tokens[1])); + assert!(history.entries.contains_key(&tokens[2])); + } + + #[test] + fn materialize_rejects_wrong_owner_and_expired_entries() { + let mut history = ClipboardHistory::new(ClipboardConfig::default()); + let entry = ClipboardEntry::new("Guest/work", "text/plain", b"hello", 100).unwrap(); + let token = entry.token().to_owned(); + history.insert(entry).unwrap(); + + assert_eq!( + history.materialize(&token, "Guest/work", 100).as_deref(), + Ok(b"hello".as_slice()) + ); + assert_eq!( + history.materialize(&token, "Guest/other", 100), + Err(HistoryError::EntryUnavailable) + ); + assert_eq!( + history.materialize(&token, "Guest/work", 100 + 3599).as_deref(), + Ok(b"hello".as_slice()) + ); + assert_eq!( + history.materialize(&token, "Guest/work", 100 + 3600), + Err(HistoryError::EntryUnavailable) + ); + assert_eq!( + history.materialize(&token, "Guest/work", 100 + 3601), + Err(HistoryError::EntryUnavailable) + ); + } + + #[test] + fn entry_expiry_reports_ttl_only_for_owned_live_entries() { + let mut history = ClipboardHistory::new(ClipboardConfig::default()); + let entry = ClipboardEntry::new("Guest/work", "text/plain", b"hello", 100).unwrap(); + let token = entry.token().to_owned(); + history.insert(entry).unwrap(); + + assert_eq!( + history.entry_expiry(&token, "Guest/work", 100), + Some(100 + 3600) + ); + assert_eq!(history.entry_expiry(&token, "Guest/other", 100), None); + assert_eq!(history.entry_expiry(&token, "Guest/work", 100 + 3600), None); + } + #[test] fn gc_prunes_idle_guest_rate_buckets() { let mut history = ClipboardHistory::new(ClipboardConfig::default()); From 774c148eb8faa05844c523c394b225bb80bc1d22 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:39:22 -0700 Subject: [PATCH 509/726] d2b-session-unix: pre-size burst and attachment buffers recv_burst and send_burst grow their packet vectors from empty with an exact upper bound (fairness_budget), and send_packet grows its descriptor and identity collectors with attachments.len() known up front. Allocate once with with_capacity instead of reallocating on the way. --- changelog.d/w3-32-session-unix-capacity.md | 6 ++++++ packages/d2b-session-unix/src/adapter.rs | 6 +++--- packages/d2b-session-unix/src/socket.rs | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 changelog.d/w3-32-session-unix-capacity.md diff --git a/changelog.d/w3-32-session-unix-capacity.md b/changelog.d/w3-32-session-unix-capacity.md new file mode 100644 index 000000000..ba428199b --- /dev/null +++ b/changelog.d/w3-32-session-unix-capacity.md @@ -0,0 +1,6 @@ +### Changed + +- Unix session send and receive bursts pre-size their packet buffers to the + fairness budget, eliminating incremental reallocations on the hot path. +- Sending a packet with attachments pre-sizes the descriptor and identity + collections, avoiding reallocations while each attachment is processed. \ No newline at end of file diff --git a/packages/d2b-session-unix/src/adapter.rs b/packages/d2b-session-unix/src/adapter.rs index 833e14a82..51e75eadc 100644 --- a/packages/d2b-session-unix/src/adapter.rs +++ b/packages/d2b-session-unix/src/adapter.rs @@ -548,9 +548,9 @@ impl UnixSeqpacketTransport { if attachments.len() > usize::from(self.policy.max_per_packet) { return Err(UnixSessionError::CreditExceeded); } - let mut files = Vec::new(); - let mut identities: Vec<(ObjectIdentity, bool)> = Vec::new(); - let mut retained_receive_credits = Vec::new(); + let mut files = Vec::with_capacity(attachments.len()); + let mut identities: Vec<(ObjectIdentity, bool)> = Vec::with_capacity(attachments.len()); + let mut retained_receive_credits = Vec::with_capacity(attachments.len()); for attachment in attachments { let descriptor = attachment .descriptor() diff --git a/packages/d2b-session-unix/src/socket.rs b/packages/d2b-session-unix/src/socket.rs index 10eba9071..85f51689f 100644 --- a/packages/d2b-session-unix/src/socket.rs +++ b/packages/d2b-session-unix/src/socket.rs @@ -276,7 +276,7 @@ impl SeqpacketSocket { let payload_capacity = usize::try_from(limits.protected_ciphertext_bytes) .map_err(|_| UnixSessionError::PayloadLimit)?; let mut ready = self.io.readable().await.map_err(io_error)?; - let mut packets = Vec::new(); + let mut packets = Vec::with_capacity(fairness_budget); while packets.len() < fairness_budget { match ready.try_io(|inner| recv_one(inner.get_ref(), payload_capacity, capacity.bytes)) { @@ -326,7 +326,7 @@ impl SeqpacketSocket { } let mut ready = self.io.writable().await.map_err(io_error)?; let mut sent = 0; - let mut sent_packets = Vec::new(); + let mut sent_packets = Vec::with_capacity(fairness_budget); while sent < fairness_budget { let Some(packet) = queue.front() else { return Ok(SendBurst { From 928b982ce95fb23d6f6930d5c41b18b75b68f4e6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:39:34 -0700 Subject: [PATCH 510/726] d2b-provider-user: relax scripted-double flag orderings and cover all unrealized phases --- changelog.d/w3-26-user-conc-test.md | 4 ++++ packages/d2b-provider-user/src/driver.rs | 16 +++++++++++++++- packages/d2b-provider-user/src/test_support.rs | 10 +++++----- 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 changelog.d/w3-26-user-conc-test.md diff --git a/changelog.d/w3-26-user-conc-test.md b/changelog.d/w3-26-user-conc-test.md new file mode 100644 index 000000000..a3610a3dc --- /dev/null +++ b/changelog.d/w3-26-user-conc-test.md @@ -0,0 +1,4 @@ +### Changed + +- The user provider's scripted test doubles now use relaxed atomic ordering for their scripted-failure flags, matching the single-threaded test runtime they run on. +- The user provider reconciliation test now re-discovers a cached unrealized discovery for every unrealized phase (Pending, Degraded, Unknown), not only Pending, so a widened realized-phase short-circuit can no longer pass the suite unnoticed. \ No newline at end of file diff --git a/packages/d2b-provider-user/src/driver.rs b/packages/d2b-provider-user/src/driver.rs index 3e36811e7..6c36b70a8 100644 --- a/packages/d2b-provider-user/src/driver.rs +++ b/packages/d2b-provider-user/src/driver.rs @@ -805,6 +805,20 @@ mod tests { vec![USER_REDISCOVER.as_millis() as u64], "exactly one re-check, on the discovery cadence" ); + + // The cached status is current-generation but not realized, so + // the next pass re-discovers instead of short-circuiting into a + // claim - for every unrealized phase, not just Pending. + effects.set_phase(ResourcePhase::Ready); + assert_eq!( + driver.reconcile(&mut ctx).await.expect("second reconcile"), + ReconcileOutcome::Satisfied + ); + assert_eq!( + effects.call_order(), + vec!["observe-user".to_owned(), "observe-user".to_owned()], + "{phase:?} cached unrealized discovery is re-observed" + ); } } @@ -847,7 +861,7 @@ mod tests { #[tokio::test] async fn reconcile_maps_a_discovery_failure_to_a_retryable_failure() { let (mut ctx, effects, _manager, _requeue, mut driver) = user_fixture().await; - effects.fail.store(true, Ordering::SeqCst); + effects.fail.store(true, Ordering::Relaxed); let failure = driver.reconcile(&mut ctx).await.expect_err("retryable"); assert_eq!(failure.class(), FailureClass::Retryable); assert!(ctx.status::().is_none()); diff --git a/packages/d2b-provider-user/src/test_support.rs b/packages/d2b-provider-user/src/test_support.rs index 96b59c27c..5a9863731 100644 --- a/packages/d2b-provider-user/src/test_support.rs +++ b/packages/d2b-provider-user/src/test_support.rs @@ -74,7 +74,7 @@ impl UserDriverEffects for RecordingEffects { _spec: &UserSpec, ) -> Result { self.calls.lock().push("observe-user".to_owned()); // async-gate-allow: test-support recorder lock - if self.fail.load(Ordering::SeqCst) { + if self.fail.load(Ordering::Relaxed) { return Err("the scripted discovery refused".to_owned()); } Ok(UserStatusReport { @@ -132,12 +132,12 @@ impl ScriptedProbe { /// Script whether the next discovery resolves no local record. pub fn set_absent(&self, absent: bool) { - self.core.absent.store(absent, Ordering::SeqCst); + self.core.absent.store(absent, Ordering::Relaxed); } /// Script whether the next discovery refuses. pub fn set_failing(&self, failing: bool) { - self.core.failing.store(failing, Ordering::SeqCst); + self.core.failing.store(failing, Ordering::Relaxed); } } @@ -149,10 +149,10 @@ impl UserDiscoveryEffectPort for ScriptedProbe { spec: &UserSpec, ) -> Result, SystemCoreError> { self.core.calls.lock().push(spec.os_username().clone()); // async-gate-allow: test-support recorder lock - if self.core.failing.load(Ordering::SeqCst) { + if self.core.failing.load(Ordering::Relaxed) { return Err(SystemCoreError::DiscoveryUnavailable); } - if self.core.absent.load(Ordering::SeqCst) { + if self.core.absent.load(Ordering::Relaxed) { return Ok(None); } Ok(Some(DiscoveredUser { From e4cbd30541ba68136922ab3717882fe7a06a19eb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:39:48 -0700 Subject: [PATCH 511/726] qemu-media: preallocate attachments and dedupe device fixture LaunchTicket::new knows the attachment upper bound (media refs plus up to three fixed slots), so build the vector with capacity instead of growing from empty. The lifecycle tests repeated the same eight-field DeviceObservation literal eight times; factor it into a device() helper alongside controller(). --- changelog.d/w3-20-qemu-media-capacity.md | 8 ++ .../src/controller/process_builder.rs | 2 +- .../tests/lifecycle.rs | 96 +++++-------------- 3 files changed, 33 insertions(+), 73 deletions(-) create mode 100644 changelog.d/w3-20-qemu-media-capacity.md diff --git a/changelog.d/w3-20-qemu-media-capacity.md b/changelog.d/w3-20-qemu-media-capacity.md new file mode 100644 index 000000000..b922b98b1 --- /dev/null +++ b/changelog.d/w3-20-qemu-media-capacity.md @@ -0,0 +1,8 @@ +### Changed + +- Launching a QEMU media guest now preallocates the launch-ticket attachment + list to its known upper bound, avoiding reallocation churn on the launch + path. +- The qemu-media lifecycle test suite builds its device observation from a + shared fixture instead of eight near-identical literals, so future field + changes touch one place. \ No newline at end of file diff --git a/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs b/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs index 0b06f841e..4a7cdd330 100644 --- a/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs +++ b/packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs @@ -240,7 +240,7 @@ impl LaunchTicket { { return Err(ProcessSpecError::InvalidReference); } - let mut attachments = Vec::new(); + let mut attachments = Vec::with_capacity(media_refs.len() + 3); if let Some(device_ref) = process.execution().device_usage().first() { attachments.push(AttachmentSlot { slot: "kvm".to_owned(), diff --git a/packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs b/packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs index 6863285a5..5eb500036 100644 --- a/packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs +++ b/packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs @@ -119,6 +119,18 @@ fn controller() -> QemuMediaController { .unwrap() } +fn device() -> DeviceObservation { + DeviceObservation { + device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), + phase: DevicePhase::Ready, + owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), + platform: PlatformClass::X86_64Linux, + authority_key: [4; 32], + process_identity: Some("qemu-media-runner".to_owned()), + media_contract: "qemu-media/v1".to_owned(), + } +} + #[test] fn ready_requires_process_device_and_qmp_health() { let mut controller = controller(); @@ -129,15 +141,7 @@ fn ready_requires_process_device_and_qmp_health() { assert!(matches!(pending, QemuMediaReconcileOutcome::Retry { .. })); assert_eq!(controller.phase(), QemuMediaPhase::Pending); - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [4; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let device = device(); let mut deps = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); deps.media_refs = vec![ResourceRef::parse("Volume/boot-media").unwrap()]; deps.display_ref = Some(ResourceRef::parse("Endpoint/display").unwrap()); @@ -151,15 +155,7 @@ fn ready_requires_process_device_and_qmp_health() { fn pause_at_boot_is_initial_proof_then_running_is_ready() { let mut controller = controller(); let mut effect = FakeEffect::default(); - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [4; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let device = device(); let mut dependencies = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); assert_eq!( @@ -184,15 +180,7 @@ fn pause_at_boot_is_initial_proof_then_running_is_ready() { fn pause_at_boot_rejects_running_before_pause_proof() { let mut controller = controller(); let mut effect = FakeEffect::default(); - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [4; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let device = device(); let mut dependencies = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); dependencies.qmp_status = Some(d2b_provider_guest_qemu_media::QmpVmStatus::Running); @@ -218,15 +206,7 @@ fn matching_restart_process_is_adopted_without_launch() { stop_clears_observation: true, ..FakeEffect::default() }; - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [4; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let device = device(); let deps = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); controller.set_expected_identity(identity); assert_eq!( @@ -265,15 +245,8 @@ fn finalization_closes_media_before_releasing_authority() { fn qmp_timeout_retains_authority_until_process_exit_is_proven() { let mut controller = controller(); let mut effect = FakeEffect::default(); - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [9; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let mut device = device(); + device.authority_key = [9; 32]; let mut dependencies = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); dependencies.qmp_ready = false; dependencies.qmp_status = None; @@ -311,15 +284,8 @@ fn qmp_timeout_retains_authority_until_process_exit_is_proven() { fn failed_qmp_timeout_does_not_adopt_a_stopping_runner() { let mut controller = controller(); let mut effect = FakeEffect::default(); - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [9; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let mut device = device(); + device.authority_key = [9; 32]; let mut dependencies = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); dependencies.qmp_ready = false; dependencies.qmp_status = None; @@ -354,15 +320,8 @@ fn failed_qmp_timeout_with_exit_proven_does_not_rereserve_on_reconcile() { stop_clears_observation: true, ..FakeEffect::default() }; - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [9; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let mut device = device(); + device.authority_key = [9; 32]; let mut dependencies = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); dependencies.qmp_ready = false; dependencies.qmp_status = None; @@ -439,15 +398,8 @@ fn adopted_runner_qmp_timeout_uses_health_retry_not_launch_age() { ..FakeEffect::default() }; controller.set_expected_identity(identity); - let device = DeviceObservation { - device_ref: ResourceRef::parse("Device/host-kvm").unwrap(), - phase: DevicePhase::Ready, - owner_ref: Some(ResourceRef::parse("Guest/media-vm").unwrap()), - platform: PlatformClass::X86_64Linux, - authority_key: [9; 32], - process_identity: Some("qemu-media-runner".to_owned()), - media_contract: "qemu-media/v1".to_owned(), - }; + let mut device = device(); + device.authority_key = [9; 32]; let mut dependencies = d2b_provider_guest_qemu_media::QemuMediaDependencies::ready(device); dependencies.qmp_ready = false; dependencies.qmp_status = None; From bacc017aad0e43e5e025411b9e6dcbe89ffe90fd Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:40:03 -0700 Subject: [PATCH 512/726] d2b-provider-network-local: cut per-call allocations and parallelize host observation --- changelog.d/w3-21-network-local-perf.md | 9 +++++++++ .../d2b-provider-network-local/src/nftables.rs | 7 ++++++- .../d2b-provider-network-local/src/observe.rs | 17 +++++++++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 changelog.d/w3-21-network-local-perf.md diff --git a/changelog.d/w3-21-network-local-perf.md b/changelog.d/w3-21-network-local-perf.md new file mode 100644 index 000000000..d276b0571 --- /dev/null +++ b/changelog.d/w3-21-network-local-perf.md @@ -0,0 +1,9 @@ +### Fixed + +- d2b-provider-network-local: host firewall digest rendering now writes + into a single preallocated buffer instead of allocating one String per + hex byte. +- d2b-provider-network-local: host network observation now runs the link, + address, and route `ip` probes concurrently instead of sequentially, and + parses observed addresses into a reused buffer instead of formatting a + fresh String per CIDR. \ No newline at end of file diff --git a/packages/d2b-provider-network-local/src/nftables.rs b/packages/d2b-provider-network-local/src/nftables.rs index 5ec130199..88c61b2c4 100644 --- a/packages/d2b-provider-network-local/src/nftables.rs +++ b/packages/d2b-provider-network-local/src/nftables.rs @@ -264,7 +264,12 @@ pub struct FirewallDigest([u8; 32]); impl FirewallDigest { /// Render hexadecimal bytes for the bounded provider status field. pub fn to_hex(&self) -> String { - self.0.iter().map(|byte| format!("{byte:02x}")).collect() + use std::fmt::Write; + let mut out = String::with_capacity(64); + for byte in &self.0 { + write!(out, "{byte:02x}").expect("writing to String is infallible"); + } + out } } diff --git a/packages/d2b-provider-network-local/src/observe.rs b/packages/d2b-provider-network-local/src/observe.rs index f7bbe4c77..3e98ea08b 100644 --- a/packages/d2b-provider-network-local/src/observe.rs +++ b/packages/d2b-provider-network-local/src/observe.rs @@ -6,6 +6,7 @@ use crate::routes::RouteTuple; use d2b_contracts_resource::v3::network::Ipv4Cidr; use serde_json::Value; use std::collections::BTreeMap; +use std::fmt::Write; use std::process::Stdio; use std::time::Duration; @@ -253,9 +254,14 @@ impl From for NetworkEffectError { /// Observe current host links, routes, and IPv4 address occupancy. pub async fn observe_host_network() -> Result { - let links = run_ip(&["-j", "-d", "link", "show"]).await?; - let addresses = run_ip(&["-j", "-4", "addr", "show"]).await?; - let routes = run_ip(&["-j", "-4", "route", "show", "table", "all"]).await?; + let (links, addresses, routes) = tokio::join!( + run_ip(&["-j", "-d", "link", "show"]), + run_ip(&["-j", "-4", "addr", "show"]), + run_ip(&["-j", "-4", "route", "show", "table", "all"]), + ); + let links = links?; + let addresses = addresses?; + let routes = routes?; parse_host_network_observation(&links, &addresses, &routes) } @@ -284,6 +290,7 @@ pub fn parse_host_network_observation( let mut cidrs = Vec::new(); let mut cidr_markers = BTreeMap::new(); + let mut cidr_text = String::new(); for value in parse_array(addresses)? { let Some(entries) = value.get("addr_info").and_then(Value::as_array) else { continue; @@ -302,7 +309,9 @@ pub fn parse_host_network_observation( }; let prefix = u8::try_from(prefix).map_err(|_| HostNetworkObservationError::InvalidOutput)?; - if let Ok(cidr) = Ipv4Cidr::parse(format!("{local}/{prefix}")) { + cidr_text.clear(); + write!(cidr_text, "{local}/{prefix}").expect("writing to String is infallible"); + if let Ok(cidr) = Ipv4Cidr::parse(cidr_text.as_str()) { if let Some(markers) = interface_marker { for marker in markers { insert_marker(&mut cidr_markers, cidr.clone(), marker.clone()); From a11baf0f910406345bf30524de3e40dc503162f2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:40:07 -0700 Subject: [PATCH 513/726] d2b-session: reuse buffers and hash the replay cache --- changelog.d/w3-30-session-perf.md | 8 +++++ packages/d2b-session/src/admission.rs | 4 +++ packages/d2b-session/src/engine.rs | 2 +- packages/d2b-session/src/record.rs | 45 ++++++++++++++++++--------- packages/d2b-session/src/scheduler.rs | 5 +++ 5 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 changelog.d/w3-30-session-perf.md diff --git a/changelog.d/w3-30-session-perf.md b/changelog.d/w3-30-session-perf.md new file mode 100644 index 000000000..1c9575843 --- /dev/null +++ b/changelog.d/w3-30-session-perf.md @@ -0,0 +1,8 @@ +### Fixed + +- Session record decryption reuses a scratch plaintext buffer and moves the + payload out instead of allocating and copying on every received record. +- The outbound flush path moves each dequeued frame's bytes out of the + scheduler instead of copying them. +- Session replay detection now uses a hash set over the replay window instead + of a linear scan of every cached digest. \ No newline at end of file diff --git a/packages/d2b-session/src/admission.rs b/packages/d2b-session/src/admission.rs index 3d29588f1..ff47a8810 100644 --- a/packages/d2b-session/src/admission.rs +++ b/packages/d2b-session/src/admission.rs @@ -753,6 +753,10 @@ pub struct AuthenticatedComponentSession { /// owning session remains in this value so its liveness and single-owner /// authority cannot be detached by extracting a cloneable handle. pub struct AuthenticatedSessionDriver { + /// Sync carrier for the owning session: `AuthenticatedComponentSession` is + /// `Send` but not `Sync`, while this driver must satisfy + /// `ComponentSessionDriver: Send + Sync`. The mutex is never locked; it + /// only makes the owner shareable across the transport lane. _owner: std::sync::Mutex>, driver: SessionDriverHandle, } diff --git a/packages/d2b-session/src/engine.rs b/packages/d2b-session/src/engine.rs index 1f5282482..c779c6584 100644 --- a/packages/d2b-session/src/engine.rs +++ b/packages/d2b-session/src/engine.rs @@ -1347,7 +1347,7 @@ pub async fn establish_initiator( QueueClass::AttachmentControl => RecordKind::Attachment, QueueClass::NamedStream => RecordKind::NamedStream, }; - self.send_logical(kind, channel, frame.as_bytes().to_vec(), Vec::new()) + self.send_logical(kind, channel, frame.into_bytes(), Vec::new()) .await?; } Ok(()) diff --git a/packages/d2b-session/src/record.rs b/packages/d2b-session/src/record.rs index 573433b1b..7566f0502 100644 --- a/packages/d2b-session/src/record.rs +++ b/packages/d2b-session/src/record.rs @@ -1,4 +1,7 @@ -use std::{collections::VecDeque, fmt}; +use std::{ + collections::{HashSet, VecDeque}, + fmt, +}; use d2b_contracts_zone_session::v3::component_session::{ LimitProfile, NOISE_TAG_BYTES, RECORD_HEADER_LEN, RECORD_LENGTH_BYTES, ReceiveSequence, @@ -43,7 +46,12 @@ pub struct RecordProtector { generation: u64, send_sequence: SendSequence, receive_sequence: ReceiveSequence, - replay_digests: VecDeque<[u8; 32]>, + /// Reusable plaintext buffer, reallocated only when the limit grows. + plaintext_scratch: Vec, + /// O(1) membership check for ciphertext replay detection. + replay_digests: HashSet<[u8; 32]>, + /// FIFO eviction order for the bounded replay cache. + replay_order: VecDeque<[u8; 32]>, } impl RecordProtector { @@ -55,7 +63,9 @@ impl RecordProtector { generation: handshake.generation, send_sequence: SendSequence::new(), receive_sequence: ReceiveSequence::new(), - replay_digests: VecDeque::with_capacity(REPLAY_CACHE_ENTRIES), + plaintext_scratch: Vec::new(), + replay_digests: HashSet::with_capacity(REPLAY_CACHE_ENTRIES), + replay_order: VecDeque::with_capacity(REPLAY_CACHE_ENTRIES), } } @@ -145,29 +155,36 @@ impl RecordProtector { } let plaintext_limit = self.limits.protected_plaintext_bytes()? as usize; - let mut plaintext = vec![0_u8; plaintext_limit]; + if self.plaintext_scratch.len() < plaintext_limit { + self.plaintext_scratch.resize(plaintext_limit, 0); + } let read = self .transport - .read_message(ciphertext, &mut plaintext) + .read_message(ciphertext, &mut self.plaintext_scratch) .map_err(|_| SessionError::new(SessionErrorCode::AuthenticationFailed))?; - plaintext.truncate(read); - if plaintext.len() < RECORD_HEADER_LEN { + self.plaintext_scratch.truncate(read); + if self.plaintext_scratch.len() < RECORD_HEADER_LEN { return Err(SessionError::new(SessionErrorCode::RecordMalformed)); } - let header = RecordHeader::decode(&plaintext[..RECORD_HEADER_LEN], self.limits)?; + let header = + RecordHeader::decode(&self.plaintext_scratch[..RECORD_HEADER_LEN], self.limits)?; if header.reconnect_generation != self.generation { return Err(SessionError::new(SessionErrorCode::GenerationMismatch)); } - let payload = &plaintext[RECORD_HEADER_LEN..]; - if usize::try_from(header.payload_len).ok() != Some(payload.len()) { + if usize::try_from(header.payload_len).ok() + != Some(self.plaintext_scratch.len() - RECORD_HEADER_LEN) + { return Err(SessionError::new(SessionErrorCode::RecordMalformed)); } self.receive_sequence.accept(header.sequence)?; - if self.replay_digests.len() == REPLAY_CACHE_ENTRIES { - self.replay_digests.pop_front(); + if self.replay_order.len() == REPLAY_CACHE_ENTRIES { + if let Some(evicted) = self.replay_order.pop_front() { + self.replay_digests.remove(&evicted); + } } - self.replay_digests.push_back(digest); - Ok((header, payload.to_vec())) + self.replay_order.push_back(digest); + self.replay_digests.insert(digest); + Ok((header, self.plaintext_scratch.split_off(RECORD_HEADER_LEN))) } } diff --git a/packages/d2b-session/src/scheduler.rs b/packages/d2b-session/src/scheduler.rs index d724867bc..37651c719 100644 --- a/packages/d2b-session/src/scheduler.rs +++ b/packages/d2b-session/src/scheduler.rs @@ -69,6 +69,11 @@ impl OutboundFrame { pub fn as_bytes(&self) -> &[u8] { &self.bytes } + + /// Consume the frame into its payload bytes without copying. + pub fn into_bytes(self) -> Vec { + self.bytes + } } impl fmt::Debug for OutboundFrame { From e807e4596452b51dc557f9a4f333e0b1ad510cd1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:40:44 -0700 Subject: [PATCH 514/726] d2b: make system-core test doubles atomic and fail-fast - ScriptedDiscoveryPort counts calls with AtomicU32 (Relaxed) instead of a tokio sync mutex, so call_count can no longer silently report 0 under contention and the crate drops its only tokio dependency. - block_on now debug-asserts the never-pending invariant instead of spinning at 100% CPU forever when a scripted future yields. - host_reconciliation builds its Probe fixture through a constructor instead of repeating the struct and metadata literals five times. --- changelog.d/w3-24-system-core-conc.md | 8 ++ packages/d2b-provider-system-core/Cargo.toml | 1 - .../d2b-provider-system-core/src/testing.rs | 27 +++-- .../tests/host_reconciliation.rs | 101 +++++++++--------- 4 files changed, 76 insertions(+), 61 deletions(-) create mode 100644 changelog.d/w3-24-system-core-conc.md diff --git a/changelog.d/w3-24-system-core-conc.md b/changelog.d/w3-24-system-core-conc.md new file mode 100644 index 000000000..ac318908e --- /dev/null +++ b/changelog.d/w3-24-system-core-conc.md @@ -0,0 +1,8 @@ +### Fixed + +- The system-core test-support scripted discovery port counts calls with an + atomic instead of a tokio mutex, so a contended read can no longer silently + report zero and the crate no longer depends on tokio's sync feature. +- The single-threaded future driver used by the hermetic system-core tests + now asserts when a scripted future yields, failing fast instead of spinning + forever at 100% CPU on a noop waker. \ No newline at end of file diff --git a/packages/d2b-provider-system-core/Cargo.toml b/packages/d2b-provider-system-core/Cargo.toml index 716c58e7a..f19a3235b 100644 --- a/packages/d2b-provider-system-core/Cargo.toml +++ b/packages/d2b-provider-system-core/Cargo.toml @@ -15,7 +15,6 @@ await_holding_refcell_ref = "deny" [dependencies] async-trait = "0.1" -tokio = { workspace = true, features = ["sync"] } d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } tracing = "0.1" serde = { workspace = true } diff --git a/packages/d2b-provider-system-core/src/testing.rs b/packages/d2b-provider-system-core/src/testing.rs index d2ffb9342..691a76676 100644 --- a/packages/d2b-provider-system-core/src/testing.rs +++ b/packages/d2b-provider-system-core/src/testing.rs @@ -6,7 +6,7 @@ use std::future::Future; use std::pin::pin; -use tokio::sync::Mutex; +use std::sync::atomic::{AtomicU32, Ordering}; use std::task::{Context, Poll, Waker}; use d2b_contracts_resource::v3::ResourceRef; @@ -19,7 +19,9 @@ use crate::user::{DiscoveredUser, UserBinding, UserDiscoveryEffectPort, UserIden /// /// The suite is hermetic and never waits on I/O or wall time, so a /// single-threaded driver is sufficient and keeps this crate free of an -/// async runtime dependency. +/// async runtime dependency. A future that returns `Poll::Pending` +/// violates that invariant; the driver asserts instead of spinning +/// forever on the noop waker. pub fn block_on(future: F) -> F::Output { let mut future = pin!(future); let waker = Waker::noop(); @@ -27,7 +29,13 @@ pub fn block_on(future: F) -> F::Output { loop { match future.as_mut().poll(&mut context) { Poll::Ready(value) => return value, - Poll::Pending => std::hint::spin_loop(), + Poll::Pending => { + debug_assert!( + false, + "block_on drives only never-pending futures; a yielding future would hang here" + ); + std::hint::spin_loop() + } } } } @@ -40,7 +48,7 @@ pub const SCRIPTED_IDENTITY: UserIdentityDigest = UserIdentityDigest::from_bytes pub struct ScriptedDiscoveryPort { result: Option, error: Option, - calls: Mutex, + calls: AtomicU32, } impl ScriptedDiscoveryPort { @@ -52,7 +60,7 @@ impl ScriptedDiscoveryPort { observed: crate::user::UserObservation::from_verified(verified), }), error: None, - calls: Mutex::new(0), + calls: AtomicU32::new(0), } } @@ -61,7 +69,7 @@ impl ScriptedDiscoveryPort { Self { result: None, error: None, - calls: Mutex::new(0), + calls: AtomicU32::new(0), } } @@ -70,13 +78,13 @@ impl ScriptedDiscoveryPort { Self { result: None, error: Some(error), - calls: Mutex::new(0), + calls: AtomicU32::new(0), } } /// How many times discovery was called. pub fn call_count(&self) -> u32 { - self.calls.try_lock().ok().map(|calls| *calls).unwrap_or_default() + self.calls.load(Ordering::Relaxed) } } @@ -87,8 +95,7 @@ impl UserDiscoveryEffectPort for ScriptedDiscoveryPort { _user_ref: &ResourceRef, _spec: &UserSpec, ) -> Result, SystemCoreError> { - let mut calls = self.calls.lock().await; - *calls += 1; + self.calls.fetch_add(1, Ordering::Relaxed); if let Some(error) = self.error { return Err(error); } diff --git a/packages/d2b-provider-system-core/tests/host_reconciliation.rs b/packages/d2b-provider-system-core/tests/host_reconciliation.rs index 915a42854..397d83e13 100644 --- a/packages/d2b-provider-system-core/tests/host_reconciliation.rs +++ b/packages/d2b-provider-system-core/tests/host_reconciliation.rs @@ -183,6 +183,26 @@ struct Probe { gate: MinijailPlatformGate, } +impl Probe { + fn new( + capabilities: BTreeSet, + user_manager_available: bool, + gate: MinijailPlatformGate, + kernel_release: &str, + ) -> Self { + Self { + capabilities, + gate, + metadata: HostProbeMetadata { + kernel_release: kernel_release.to_owned(), + os_name: "test-os".to_owned(), + user_manager_available, + active_process_count: 0, + }, + } + } +} + #[async_trait::async_trait] impl HostProbeEffectPort for Probe { async fn probe(&self, capability: HostCapabilityClass) -> Result { @@ -200,16 +220,13 @@ impl HostProbeEffectPort for Probe { #[test] fn bounded_probe_reconciles_all_capabilities_and_gates_minijail() { - let probe = Probe { - capabilities: HostCapabilityClass::ALL.into_iter().collect(), - metadata: HostProbeMetadata { - kernel_release: "6.1".to_owned(), - os_name: "test-os".to_owned(), - user_manager_available: true, - active_process_count: 3, - }, - gate: MinijailPlatformGate::new(6, 1, true), - }; + let mut probe = Probe::new( + HostCapabilityClass::ALL.into_iter().collect(), + true, + MinijailPlatformGate::new(6, 1, true), + "6.1", + ); + probe.metadata.active_process_count = 3; let result = block_on(HostReconciler::new().reconcile_with_probe( &fixtures::host_ref(), &fixtures::system_core_provider_ref(), @@ -226,16 +243,12 @@ fn bounded_probe_reconciles_all_capabilities_and_gates_minijail() { #[test] fn user_capable_host_without_user_manager_is_degraded() { - let probe = Probe { - capabilities: HostCapabilityClass::ALL.into_iter().collect(), - metadata: HostProbeMetadata { - kernel_release: "6.1".to_owned(), - os_name: "test-os".to_owned(), - user_manager_available: false, - active_process_count: 0, - }, - gate: MinijailPlatformGate::new(6, 1, true), - }; + let probe = Probe::new( + HostCapabilityClass::ALL.into_iter().collect(), + false, + MinijailPlatformGate::new(6, 1, true), + "6.1", + ); let result = block_on(HostReconciler::new().reconcile_with_probe( &fixtures::user_only_host_ref(), &fixtures::system_core_provider_ref(), @@ -250,16 +263,12 @@ fn user_capable_host_without_user_manager_is_degraded() { #[test] fn missing_required_probe_capability_is_rejected() { - let probe = Probe { - capabilities: BTreeSet::new(), - metadata: HostProbeMetadata { - kernel_release: "6.1".to_owned(), - os_name: "test-os".to_owned(), - user_manager_available: true, - active_process_count: 0, - }, - gate: MinijailPlatformGate::new(6, 1, true), - }; + let probe = Probe::new( + BTreeSet::new(), + true, + MinijailPlatformGate::new(6, 1, true), + "6.1", + ); assert_eq!( block_on(HostReconciler::new().reconcile_with_probe( &fixtures::host_ref(), @@ -276,16 +285,12 @@ fn missing_required_probe_capability_is_rejected() { #[test] fn malformed_probe_metadata_is_rejected() { - let probe = Probe { - capabilities: HostCapabilityClass::ALL.into_iter().collect(), - metadata: HostProbeMetadata { - kernel_release: "6.1\nmalicious".to_owned(), - os_name: "test-os".to_owned(), - user_manager_available: true, - active_process_count: 0, - }, - gate: MinijailPlatformGate::new(6, 1, true), - }; + let probe = Probe::new( + HostCapabilityClass::ALL.into_iter().collect(), + true, + MinijailPlatformGate::new(6, 1, true), + "6.1\nmalicious", + ); assert_eq!( block_on(HostReconciler::new().reconcile_with_probe( &fixtures::host_ref(), @@ -302,16 +307,12 @@ fn malformed_probe_metadata_is_rejected() { #[test] fn unsupported_minijail_probe_posture_is_rejected() { - let probe = Probe { - capabilities: HostCapabilityClass::ALL.into_iter().collect(), - metadata: HostProbeMetadata { - kernel_release: "6.1".to_owned(), - os_name: "test-os".to_owned(), - user_manager_available: true, - active_process_count: 0, - }, - gate: MinijailPlatformGate::new(6, 1, false), - }; + let probe = Probe::new( + HostCapabilityClass::ALL.into_iter().collect(), + true, + MinijailPlatformGate::new(6, 1, false), + "6.1", + ); assert_eq!( block_on(HostReconciler::new().reconcile_with_probe( &fixtures::host_ref(), From 513edf50c762d7d09f6f955e1829d600c11aff82 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:40:50 -0700 Subject: [PATCH 515/726] d2b: match child roles against the static suffix without allocating --- changelog.d/w3-19-cloud-hypervisor-suffix.md | 3 +++ .../d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | 9 ++++----- 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 changelog.d/w3-19-cloud-hypervisor-suffix.md diff --git a/changelog.d/w3-19-cloud-hypervisor-suffix.md b/changelog.d/w3-19-cloud-hypervisor-suffix.md new file mode 100644 index 000000000..9204eb4a5 --- /dev/null +++ b/changelog.d/w3-19-cloud-hypervisor-suffix.md @@ -0,0 +1,3 @@ +### Changed + +- Cloud Hypervisor guest planning no longer allocates a scratch string per candidate role when inferring a child role from its ResourceRef, removing four small heap allocations from every per-child upgrade and status projection. \ No newline at end of file diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs index 305188ccf..cc53e7a62 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs @@ -486,6 +486,7 @@ fn blocked_plan(guest_uid: ResourceUid, reason: FinalizationBlockReason) -> Gues /// Infer one fixed direct-child role from its deterministic ResourceRef. pub fn child_role_for_ref(target: &ResourceRef) -> Option { + let name = target.name().as_str(); [ ChildRole::VmmProcess, ChildRole::ChApiEndpoint, @@ -495,11 +496,9 @@ pub fn child_role_for_ref(target: &ResourceRef) -> Option { .into_iter() .find(|role| { target.resource_type().as_str() == role.resource_type() - && target - .name() - .as_str() - .strip_suffix(&format!("-{}", role.suffix())) - .is_some() + && name + .strip_suffix(role.suffix()) + .is_some_and(|stem| stem.ends_with('-')) }) } From a34843f8eb16f5b6e3a4908d44a0275d8fb92220 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:41:05 -0700 Subject: [PATCH 516/726] d2b-provider-display-wayland: replace entry! macro and hex format! loop The classified policy catalog is populated through a plain entry() function instead of a two-arm macro_rules! shorthand; the 68-row catalog content is unchanged. durable_display_suffix now pushes two hex digits per byte from a lookup table into the preallocated 40-char buffer instead of allocating one format! string per byte. --- .../w3-17-display-wayland-hex-entry.md | 9 + .../src/session_children.rs | 6 +- .../src/wayland_proxy/policy.rs | 209 +++++++++--------- 3 files changed, 122 insertions(+), 102 deletions(-) create mode 100644 changelog.d/w3-17-display-wayland-hex-entry.md diff --git a/changelog.d/w3-17-display-wayland-hex-entry.md b/changelog.d/w3-17-display-wayland-hex-entry.md new file mode 100644 index 000000000..a8ab247a3 --- /dev/null +++ b/changelog.d/w3-17-display-wayland-hex-entry.md @@ -0,0 +1,9 @@ +### Changed + +- The wayland display provider's classified policy catalog is now populated + through a plain function instead of a local macro; the interface table + itself is unchanged. +- Durable display-process name suffixes are hex-encoded into the preallocated + buffer without one formatting allocation per byte, so naming a display + session no longer allocates 20 throwaway strings on the cold durable-naming + path. \ No newline at end of file diff --git a/packages/d2b-provider-display-wayland/src/session_children.rs b/packages/d2b-provider-display-wayland/src/session_children.rs index 76ad7b0ce..d09ff3022 100644 --- a/packages/d2b-provider-display-wayland/src/session_children.rs +++ b/packages/d2b-provider-display-wayland/src/session_children.rs @@ -305,6 +305,9 @@ fn durable_process_payload_for_generation( .map_err(|_| WorkerEffectError::LaunchRejected) } +/// Lowercase hex digits for two-digit-per-byte encoding. +const HEX_DIGITS: &[u8; 16] = b"0123456789abcdef"; + /// The bounded session-uid suffix of one worker role's durable names. fn durable_display_suffix(session_uid: &ResourceUid, role: DisplayProcessRole) -> String { let mut digest = Sha256::new(); @@ -314,7 +317,8 @@ fn durable_display_suffix(session_uid: &ResourceUid, role: DisplayProcessRole) - let digest = digest.finalize(); let mut suffix = String::with_capacity(40); for byte in digest.iter().take(20) { - suffix.push_str(&format!("{byte:02x}")); + suffix.push(HEX_DIGITS[(byte >> 4) as usize] as char); + suffix.push(HEX_DIGITS[(byte & 0x0f) as usize] as char); } suffix } diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs index 75f766cfb..8b2f40ee7 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs @@ -419,144 +419,151 @@ fn sanitize_rewritten_label(value: &str) -> String { fn default_classified_entries() -> HashMap { let mut m = HashMap::new(); - macro_rules! entry { - ($iface:expr_2021, $action:ident, $class:ident) => { - m.insert( - $iface.to_owned(), - PolicyEntry { - action: GlobalAction::$action, - max_version: None, - classification: Classification::$class, - }, - ); - }; - ($iface:expr_2021, $action:ident, $class:ident, max=$v:expr_2021) => { - m.insert( - $iface.to_owned(), - PolicyEntry { - action: GlobalAction::$action, - max_version: Some($v), - classification: Classification::$class, - }, - ); - }; + /// Insert one classified policy entry into the table. + fn entry( + m: &mut HashMap, + iface: &str, + action: GlobalAction, + class: Classification, + max: Option, + ) { + m.insert( + iface.to_owned(), + PolicyEntry { + action, + max_version: max, + classification: class, + }, + ); } // --- baseline-app (required, enabled) --- - entry!("wl_compositor", Allow, RequiredBaseline); - entry!("wl_shm", Allow, RequiredBaseline); - entry!("wl_seat", Allow, RequiredBaseline); - entry!("xdg_wm_base", Allow, RequiredBaseline); - entry!("wl_output", Allow, RequiredBaseline); - entry!("wl_subcompositor", Allow, RequiredBaseline); - entry!("wl_data_device_manager", Deny, ClipboardBoundary); + entry(&mut m, "wl_compositor", GlobalAction::Allow, Classification::RequiredBaseline, None); + entry(&mut m, "wl_shm", GlobalAction::Allow, Classification::RequiredBaseline, None); + entry(&mut m, "wl_seat", GlobalAction::Allow, Classification::RequiredBaseline, None); + entry(&mut m, "xdg_wm_base", GlobalAction::Allow, Classification::RequiredBaseline, None); + entry(&mut m, "wl_output", GlobalAction::Allow, Classification::RequiredBaseline, None); + entry(&mut m, "wl_subcompositor", GlobalAction::Allow, Classification::RequiredBaseline, None); + entry(&mut m, "wl_data_device_manager", GlobalAction::Deny, Classification::ClipboardBoundary, None); // --- accelerated-rendering (enabled, warn if denied) --- - entry!("zwp_linux_dmabuf_v1", Allow, AcceleratedRendering); - entry!( + entry(&mut m, "zwp_linux_dmabuf_v1", GlobalAction::Allow, Classification::AcceleratedRendering, None); + entry( + &mut m, "wp_linux_drm_syncobj_manager_v1", - Allow, - AcceleratedRendering + GlobalAction::Allow, + Classification::AcceleratedRendering, + None, ); - entry!("wl_eglstream_display", Allow, AcceleratedRendering); - entry!("wl_eglstream_controller", Allow, AcceleratedRendering); - entry!("wp_single_pixel_buffer_v1", Allow, AppDefault); + entry(&mut m, "wl_eglstream_display", GlobalAction::Allow, Classification::AcceleratedRendering, None); + entry(&mut m, "wl_eglstream_controller", GlobalAction::Allow, Classification::AcceleratedRendering, None); + entry(&mut m, "wp_single_pixel_buffer_v1", GlobalAction::Allow, Classification::AppDefault, None); // --- presentation-and-scaling (enabled, app default) --- - entry!("wp_presentation", Allow, AppDefault); - entry!("wp_fractional_scale_manager_v1", Allow, AppDefault); - entry!("wp_viewporter", Allow, AppDefault); - entry!("zxdg_decoration_manager_v1", Allow, AppDefault); - entry!("xdg_activation_v1", Allow, AppDefault); - entry!("wp_content_type_manager_v1", Allow, AppDefault); - entry!("wp_cursor_shape_manager_v1", Allow, AppDefault); - entry!("wp_commit_timing_manager_v1", Allow, AppDefault); - entry!("wp_fifo_manager_v1", Allow, AppDefault); - entry!("wp_alpha_modifier_v1", Allow, AppDefault); - entry!("wp_tearing_control_manager_v1", Allow, AppDefault); - entry!("xdg_output_unstable_v1", Allow, AppDefault); - entry!("xdg_system_bell_v1", Allow, AppDefault); - entry!("zxdg_output_manager_v1", Allow, AppDefault); - entry!("ext_idle_notifier_v1", Allow, AppDefault); - entry!("zwp_idle_inhibit_manager_v1", Allow, AppDefault); - entry!("wp_color_manager_v1", Allow, AppDefault); - entry!("xdg_dialog_v1", Allow, AppDefault); - entry!("xdg_wm_dialog_v1", Allow, AppDefault); - entry!("xdg_toplevel_icon_manager_v1", Allow, AppDefault); - entry!("xdg_toplevel_drag_manager_v1", Deny, ClipboardBoundary); - entry!("xdg_activation_token_v1", Allow, AppDefault); - entry!("xdg_toplevel_tag_manager_v1", Allow, AppDefault); + entry(&mut m, "wp_presentation", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_fractional_scale_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_viewporter", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "zxdg_decoration_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_activation_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_content_type_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_cursor_shape_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_commit_timing_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_fifo_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_alpha_modifier_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_tearing_control_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_output_unstable_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_system_bell_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "zxdg_output_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "ext_idle_notifier_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "zwp_idle_inhibit_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "wp_color_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_dialog_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_wm_dialog_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_toplevel_icon_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_toplevel_drag_manager_v1", GlobalAction::Deny, Classification::ClipboardBoundary, None); + entry(&mut m, "xdg_activation_token_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "xdg_toplevel_tag_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); // Input protocols - standard app-level input - entry!("zwp_relative_pointer_manager_v1", Allow, AppDefault); - entry!("zwp_pointer_constraints_v1", Allow, AppDefault); - entry!("zwp_pointer_gestures_v1", Allow, AppDefault); - entry!("zwp_tablet_manager_v2", Allow, AppDefault); - entry!("zwp_text_input_manager_v3", Deny, AppDefault); - entry!("zwp_input_timestamps_manager_v1", Allow, AppDefault); - entry!( + entry(&mut m, "zwp_relative_pointer_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "zwp_pointer_constraints_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "zwp_pointer_gestures_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "zwp_tablet_manager_v2", GlobalAction::Allow, Classification::AppDefault, None); + entry(&mut m, "zwp_text_input_manager_v3", GlobalAction::Deny, Classification::AppDefault, None); + entry(&mut m, "zwp_input_timestamps_manager_v1", GlobalAction::Allow, Classification::AppDefault, None); + entry( + &mut m, "zwp_keyboard_shortcuts_inhibit_manager_v1", - Allow, - AppDefault + GlobalAction::Allow, + Classification::AppDefault, + None, ); - entry!("wp_pointer_warp_v1", Allow, AppDefault); + entry(&mut m, "wp_pointer_warp_v1", GlobalAction::Allow, Classification::AppDefault, None); // wl_drm is legacy but still used by some Mesa paths - entry!("wl_drm", Allow, AppDefault); + entry(&mut m, "wl_drm", GlobalAction::Allow, Classification::AppDefault, None); // --- screen-capture (disabled by default, high-risk) --- - entry!("zwlr_screencopy_manager_v1", Deny, HighRisk); - entry!("ext_image_copy_capture_manager_v1", Deny, HighRisk); - entry!("ext_image_capture_source_v1", Deny, HighRisk); - entry!("ext_output_image_capture_source_manager_v1", Deny, HighRisk); - entry!( + entry(&mut m, "zwlr_screencopy_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "ext_image_copy_capture_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "ext_image_capture_source_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "ext_output_image_capture_source_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry( + &mut m, "ext_foreign_toplevel_image_capture_source_manager_v1", - Deny, - HighRisk + GlobalAction::Deny, + Classification::HighRisk, + None, ); // --- virtual-input (disabled by default, high-risk) --- - entry!("zwp_virtual_keyboard_manager_v1", Deny, HighRisk); - entry!("zwlr_virtual_pointer_manager_v1", Deny, HighRisk); + entry(&mut m, "zwp_virtual_keyboard_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "zwlr_virtual_pointer_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); // --- clipboard-control (disabled by default, architecture-enforced boundary) --- - entry!("ext_data_control_manager_v1", Deny, ClipboardBoundary); - entry!("zwlr_data_control_manager_v1", Deny, ClipboardBoundary); - entry!( + entry(&mut m, "ext_data_control_manager_v1", GlobalAction::Deny, Classification::ClipboardBoundary, None); + entry(&mut m, "zwlr_data_control_manager_v1", GlobalAction::Deny, Classification::ClipboardBoundary, None); + entry( + &mut m, "zwp_primary_selection_device_manager_v1", - Deny, - ClipboardBoundary + GlobalAction::Deny, + Classification::ClipboardBoundary, + None, ); - entry!( + entry( + &mut m, "wp_primary_selection_device_manager_v1", - Deny, - ClipboardBoundary + GlobalAction::Deny, + Classification::ClipboardBoundary, + None, ); - entry!("wp_primary_selection_unstable_v1", Deny, ClipboardBoundary); - entry!( + entry(&mut m, "wp_primary_selection_unstable_v1", GlobalAction::Deny, Classification::ClipboardBoundary, None); + entry( + &mut m, "gtk_primary_selection_device_manager", - Deny, - ClipboardBoundary + GlobalAction::Deny, + Classification::ClipboardBoundary, + None, ); // --- desktop-shell (disabled by default, high-risk) --- - entry!("zwlr_layer_shell_v1", Deny, HighRisk); + entry(&mut m, "zwlr_layer_shell_v1", GlobalAction::Deny, Classification::HighRisk, None); // --- session-control (disabled by default, high-risk) --- - entry!("ext_session_lock_manager_v1", Deny, HighRisk); - entry!("zwlr_input_inhibit_manager_v1", Deny, HighRisk); - entry!("zwlr_output_manager_v1", Deny, HighRisk); - entry!("zwlr_output_power_manager_v1", Deny, HighRisk); - entry!("zwlr_gamma_control_manager_v1", Deny, HighRisk); - entry!("ext_workspace_manager_v1", Deny, HighRisk); - entry!("zwlr_foreign_toplevel_manager_v1", Deny, HighRisk); - entry!("ext_foreign_toplevel_list_v1", Deny, HighRisk); + entry(&mut m, "ext_session_lock_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "zwlr_input_inhibit_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "zwlr_output_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "zwlr_output_power_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "zwlr_gamma_control_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "ext_workspace_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "zwlr_foreign_toplevel_manager_v1", GlobalAction::Deny, Classification::HighRisk, None); + entry(&mut m, "ext_foreign_toplevel_list_v1", GlobalAction::Deny, Classification::HighRisk, None); // --- security-context (disabled by default) --- - entry!("wp_security_context_manager_v1", Deny, OffDefault); + entry(&mut m, "wp_security_context_manager_v1", GlobalAction::Deny, Classification::OffDefault, None); // Legacy wl_shell - disabled - entry!("wl_shell", Deny, OffDefault); + entry(&mut m, "wl_shell", GlobalAction::Deny, Classification::OffDefault, None); m } From 037e235334004d240b9765a6d7e1688ecd4e5a93 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:41:10 -0700 Subject: [PATCH 517/726] d2b: reuse preallocated buffers in provider id builders --- changelog.d/w3-18-provider-perf-leaf.md | 10 +++++ packages/d2b-provider-guest/src/driver.rs | 17 ++++---- .../d2b-provider-guest/src/effects_service.rs | 3 +- .../src/host_sink.rs | 43 ++++++++----------- .../src/operations.rs | 9 ++-- packages/d2b-provider-volume/src/driver.rs | 31 ++++++------- 6 files changed, 60 insertions(+), 53 deletions(-) create mode 100644 changelog.d/w3-18-provider-perf-leaf.md diff --git a/changelog.d/w3-18-provider-perf-leaf.md b/changelog.d/w3-18-provider-perf-leaf.md new file mode 100644 index 000000000..3a447c020 --- /dev/null +++ b/changelog.d/w3-18-provider-perf-leaf.md @@ -0,0 +1,10 @@ +### Changed + +- Guest, notification-desktop, process-systemd and volume providers no longer + allocate a fresh string per hex byte when building operation ids, unit + names and projection keys: each id is written into one preallocated buffer, + and notification close paths reuse the request id they already hold instead + of re-formatting it from the numeric id. +- The volume provider reconcile pass performs one manager child-set fetch per + pass instead of two: the child set fetched to retire obsolete bindings is + reused for the convergence verdict. \ No newline at end of file diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index 5813b0ad4..a41c2f1cc 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -865,15 +865,14 @@ impl GuestDriver { /// The runtime-only operation id of one pass (never persisted). fn operation_id(&self, ctx: &ResourceContext, kind: GuestKind) -> String { - format!( - "{}-{}-g{}", - kind.effect_id(), - ctx.uid() - .iter() - .map(|byte| format!("{byte:02x}")) - .collect::(), - ctx.generation(), - ) + use std::fmt::Write as _; + let mut id = String::with_capacity(kind.effect_id().len() + ctx.uid().len() * 2 + 8); + let _ = write!(id, "{}-", kind.effect_id()); + for byte in ctx.uid() { + let _ = write!(id, "{byte:02x}"); + } + let _ = write!(id, "-g{}", ctx.generation()); + id } fn child_key(&self, target: &ResourceRef) -> ResourceKey { diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index b4dc13baa..795b7d15b 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -980,12 +980,13 @@ impl GuestEffectsService { } fn framework_operation_id(prefix: &str, operation_id: &str) -> String { + use std::fmt::Write as _; let digest = Sha256::digest(format!("{prefix}:{operation_id}").as_bytes()); let mut id = String::with_capacity(24); id.push_str("guest-"); id.push_str(prefix); for byte in digest.iter().take(8) { - id.push_str(&format!("{byte:02x}")); + let _ = write!(id, "{byte:02x}"); } id } diff --git a/packages/d2b-provider-notification-desktop/src/host_sink.rs b/packages/d2b-provider-notification-desktop/src/host_sink.rs index fa351dba7..cb0816ca4 100644 --- a/packages/d2b-provider-notification-desktop/src/host_sink.rs +++ b/packages/d2b-provider-notification-desktop/src/host_sink.rs @@ -271,11 +271,11 @@ impl NotificationSink { notification, }, ); - self.projection_nonces.insert(request_id, issued_keys); + self.projection_nonces.insert(request_id.clone(), issued_keys); self.projection_sessions - .insert(format!("notification-{notification_id}"), observer_session); + .insert(request_id.clone(), observer_session); self.projection_deadlines.insert( - format!("notification-{notification_id}"), + request_id.clone(), now_secs.saturating_add(self.acknowledge_timeout_secs), ); let result = NotificationResult::Accepted { @@ -285,10 +285,9 @@ impl NotificationSink { if let Some(key) = idempotency_key { self.idempotency.insert( key.clone(), - (format!("notification-{notification_id}"), result.clone()), + (request_id.clone(), result.clone()), ); - self.projection_idempotency - .insert(format!("notification-{notification_id}"), key); + self.projection_idempotency.insert(request_id, key); } Ok(result) } @@ -381,13 +380,17 @@ impl NotificationSink { /// Evict a projection when its desktop notification closes. pub fn close(&mut self, notification_id: u32) { - let request_id = format!("notification-{notification_id}"); - self.projections.remove(&request_id); - self.revoke_projection_nonces(&request_id); - self.remove_projection_idempotency(&request_id); - self.projection_sessions.remove(&request_id); - self.projection_deadlines.remove(&request_id); - self.order.retain(|value| value != &request_id); + self.close_by_request_id(&format!("notification-{notification_id}")); + } + + /// Evict a projection by its internal request id. + fn close_by_request_id(&mut self, request_id: &str) { + self.projections.remove(request_id); + self.revoke_projection_nonces(request_id); + self.remove_projection_idempotency(request_id); + self.projection_sessions.remove(request_id); + self.projection_deadlines.remove(request_id); + self.order.retain(|value| value != request_id); } /// Revoke all projections and action capabilities for a closed session. @@ -400,12 +403,7 @@ impl NotificationSink { .map(|(request_id, _)| request_id.clone()) .collect::>(); for request_id in request_ids { - if let Some(notification_id) = request_id - .strip_prefix("notification-") - .and_then(|value| value.parse::().ok()) - { - self.close(notification_id); - } + self.close_by_request_id(&request_id); } self.nonces.revoke_session(&session_key); } @@ -496,12 +494,7 @@ impl NotificationSink { }) .collect::>(); for request_id in expired { - if let Some(notification_id) = request_id - .strip_prefix("notification-") - .and_then(|value| value.parse::().ok()) - { - self.close(notification_id); - } + self.close_by_request_id(&request_id); } } } diff --git a/packages/d2b-provider-process-systemd/src/operations.rs b/packages/d2b-provider-process-systemd/src/operations.rs index ce959553d..0d8007370 100644 --- a/packages/d2b-provider-process-systemd/src/operations.rs +++ b/packages/d2b-provider-process-systemd/src/operations.rs @@ -414,11 +414,14 @@ fn unit_name(request: &d2b_contracts_broker::broker_wire::UnitRequest) -> String digest.update(request.template_identity); digest.update(request.generation.to_le_bytes()); let digest: [u8; 32] = digest.finalize().into(); - let mut suffix = String::with_capacity(32); + let mut name = String::with_capacity(52); + name.push_str("d2b-process-"); for byte in digest.iter().take(16) { - suffix.push_str(&format!("{byte:02x}")); + use std::fmt::Write as _; + let _ = write!(name, "{byte:02x}"); } - format!("d2b-process-{suffix}.service") + name.push_str(".service"); + name } async fn system_connection() -> Result { diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index 73c232137..7078b9626 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -48,7 +48,7 @@ use d2b_resource_runtime::error::{ DriverFailure, DriverOp, FailureClass, FailureComparison, FailureDetail, FailureKind, FailureKinds, }; -use d2b_resource_runtime::identity::{ResourceKey, ResourceTypeName}; +use d2b_resource_runtime::identity::{ResourceKey, ResourceTypeName, StoredDesiredResource}; use d2b_resource_types::{ AllowedSources, CONVERTED_TYPE_VERBS, ChildCreation, ChildCustody, DriverDescriptor, WellKnownType, @@ -422,7 +422,7 @@ impl VolumeDriver { ctx: &mut ResourceContext, desired: &[DesiredBindingChild], op: DriverOp, - ) -> Result<(), VolumeDriverError> { + ) -> Result, VolumeDriverError> { for child in desired { let ensure = ChildEnsure { type_name: ResourceTypeName::new(VOLUME_BINDING_TYPE), @@ -438,19 +438,22 @@ impl VolumeDriver { .children() .await .map_err(|_| self.error(VolumeDriverErrorKind::ChildMutation, op))?; - for row in owned { - if row.key.type_name != VOLUME_BINDING_TYPE - || desired.iter().any(|child| child.name == row.key.name) - { - continue; - } + let obsolete = owned + .iter() + .filter(|row| { + row.key.type_name == VOLUME_BINDING_TYPE + && !desired.iter().any(|child| child.name == row.key.name) + }) + .map(|row| row.key.clone()) + .collect::>(); + for key in obsolete { // Obsolete child: the manager retires it and owns its own // teardown (endpoint -> process last), R9/F3. - ctx.delete(&row.key) + ctx.delete(&key) .await .map_err(|_| self.error(VolumeDriverErrorKind::ChildMutation, op))?; } - Ok(()) + Ok(owned) } /// Spawn the preserved layout effect as a long effect (R5, KTD12): the @@ -611,11 +614,9 @@ impl ResourceDriver for VolumeDriver { } let desired = self.desired_children(&volume_ref, &spec, DriverOp::Reconcile)?; - self.reconcile_children(ctx, &desired, DriverOp::Reconcile).await?; - let owned = ctx - .children() - .await - .map_err(|_| self.error(VolumeDriverErrorKind::ChildMutation, DriverOp::Reconcile))?; + let owned = self + .reconcile_children(ctx, &desired, DriverOp::Reconcile) + .await?; let converged = desired.iter().all(|child| { owned .iter() From a8b710719dda2a99849c1ab457039553f20e1dc2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:41:10 -0700 Subject: [PATCH 518/726] d2b-resource-runtime: reduce allocations in reconcile and hex paths - Reconcile the obsolete-child scan by key only instead of cloning full stored rows. - Render hex digests with write! into a pre-sized String instead of a fresh format! allocation per byte. - Use Relaxed ordering for the single-owner ActorTimers counter. - Move parking_lot to dev-dependencies; it is consumed only by cfg(test) code. - Replace the tautological wire-budget assertion with a behavioral low-word packing check. - Keep the modules_resolve smoke test as a compile-resolution check without value assertions. --- changelog.d/w3-29-resource-runtime-perf.md | 7 +++++ packages/d2b-resource-runtime/Cargo.toml | 2 +- .../d2b-resource-runtime/src/guest_target.rs | 5 ++-- packages/d2b-resource-runtime/src/lib.rs | 30 +++++++++++-------- packages/d2b-resource-runtime/src/manager.rs | 10 +++---- packages/d2b-resource-runtime/src/resource.rs | 2 +- packages/d2b-resource-runtime/src/revision.rs | 8 +++-- 7 files changed, 40 insertions(+), 24 deletions(-) create mode 100644 changelog.d/w3-29-resource-runtime-perf.md diff --git a/changelog.d/w3-29-resource-runtime-perf.md b/changelog.d/w3-29-resource-runtime-perf.md new file mode 100644 index 000000000..388b04e1b --- /dev/null +++ b/changelog.d/w3-29-resource-runtime-perf.md @@ -0,0 +1,7 @@ +### Changed + +- Resource reconciliation scans the obsolete-child set by key only, without + cloning full stored rows, and hex digests render into a pre-sized string + instead of allocating a fresh string per byte. +- The resource runtime no longer depends on `parking_lot` at runtime; its + test-only uses moved to dev-dependencies. \ No newline at end of file diff --git a/packages/d2b-resource-runtime/Cargo.toml b/packages/d2b-resource-runtime/Cargo.toml index b19f7d25f..ead59fa13 100644 --- a/packages/d2b-resource-runtime/Cargo.toml +++ b/packages/d2b-resource-runtime/Cargo.toml @@ -30,8 +30,8 @@ serde_json.workspace = true # projections of the same detail. First consumed by this crate. tracing = "0.1" tokio = { workspace = true, features = ["rt", "sync", "time"] } -parking_lot = "0.12" [dev-dependencies] tempfile = "3" +parking_lot = "0.12" tokio = { workspace = true, features = ["fs", "macros", "rt", "rt-multi-thread", "sync", "test-util", "time"] } diff --git a/packages/d2b-resource-runtime/src/guest_target.rs b/packages/d2b-resource-runtime/src/guest_target.rs index b71f9ce39..d3f5cfa41 100644 --- a/packages/d2b-resource-runtime/src/guest_target.rs +++ b/packages/d2b-resource-runtime/src/guest_target.rs @@ -23,6 +23,7 @@ pub const MODULE_NAME: &str = "guest_target"; use std::{collections::HashMap, fmt, sync::Arc}; +use std::fmt::Write; use std::sync::atomic::{AtomicU64, Ordering}; use async_trait::async_trait; @@ -175,7 +176,7 @@ pub fn target_local_spec_digest(spec: &[u8]) -> String { let mut rendered = String::with_capacity(7 + 64); rendered.push_str("sha256:"); for byte in bytes { - rendered.push_str(&format!("{byte:02x}")); + write!(&mut rendered, "{byte:02x}").expect("writing to a String cannot fail"); } rendered } @@ -1216,7 +1217,7 @@ fn json_decode_adoption(value: &Value) -> Result String { let mut rendered = String::with_capacity(bytes.len() * 2); for byte in bytes { - rendered.push_str(&format!("{byte:02x}")); + write!(&mut rendered, "{byte:02x}").expect("writing to a String cannot fail"); } rendered } diff --git a/packages/d2b-resource-runtime/src/lib.rs b/packages/d2b-resource-runtime/src/lib.rs index 0ad32d9c0..1f5ea4c72 100644 --- a/packages/d2b-resource-runtime/src/lib.rs +++ b/packages/d2b-resource-runtime/src/lib.rs @@ -65,20 +65,24 @@ pub use crate::target::{ #[cfg(test)] mod smoke_tests { /// Scaffold smoke test: the crate compiles and its module tree resolves. + /// Compile-resolution only (audit A5): each module's `MODULE_NAME` const + /// must stay reachable, but its value is not pinned here. #[test] fn modules_resolve() { - assert_eq!(crate::manager::MODULE_NAME, "manager"); - assert_eq!(crate::resource::MODULE_NAME, "resource"); - assert_eq!(crate::driver::MODULE_NAME, "driver"); - assert_eq!(crate::metadata::MODULE_NAME, "metadata"); - assert_eq!(crate::context::MODULE_NAME, "context"); - assert_eq!(crate::provider::MODULE_NAME, "provider"); - assert_eq!(crate::target::MODULE_NAME, "target"); - assert_eq!(crate::guest_target::MODULE_NAME, "guest_target"); - assert_eq!(crate::watch::MODULE_NAME, "watch"); - assert_eq!(crate::spec_store::MODULE_NAME, "spec_store"); - assert_eq!(crate::identity::MODULE_NAME, "identity"); - assert_eq!(crate::error::MODULE_NAME, "error"); - assert_eq!(crate::revision::MODULE_NAME, "revision"); + let _ = ( + crate::manager::MODULE_NAME, + crate::resource::MODULE_NAME, + crate::driver::MODULE_NAME, + crate::metadata::MODULE_NAME, + crate::context::MODULE_NAME, + crate::provider::MODULE_NAME, + crate::target::MODULE_NAME, + crate::guest_target::MODULE_NAME, + crate::watch::MODULE_NAME, + crate::spec_store::MODULE_NAME, + crate::identity::MODULE_NAME, + crate::error::MODULE_NAME, + crate::revision::MODULE_NAME, + ); } } diff --git a/packages/d2b-resource-runtime/src/manager.rs b/packages/d2b-resource-runtime/src/manager.rs index 4d4cdc5c2..3fef36a55 100644 --- a/packages/d2b-resource-runtime/src/manager.rs +++ b/packages/d2b-resource-runtime/src/manager.rs @@ -1386,16 +1386,16 @@ async fn reconcile_children( // Obsolete: owned, not deleting, not desired anymore. let desired_names: std::collections::HashSet = desired.iter().map(|child| child.name.clone()).collect(); - let owned: Vec = state + let owned: Vec = state .rows .values() .filter(|row| row.owner_uid == Some(parent_row.uid) && !row.deleting) - .cloned() + .map(|row| row.key.clone()) .collect(); for child in owned { - if !desired_names.contains(&child.key.name) { - state.remove_internal(&subject, &child.key).await?; - diff.obsolete.push(child.key.clone()); + if !desired_names.contains(&child.name) { + state.remove_internal(&subject, &child).await?; + diff.obsolete.push(child); } } Ok(diff) diff --git a/packages/d2b-resource-runtime/src/resource.rs b/packages/d2b-resource-runtime/src/resource.rs index 49a5c8b41..7bc36cab8 100644 --- a/packages/d2b-resource-runtime/src/resource.rs +++ b/packages/d2b-resource-runtime/src/resource.rs @@ -245,7 +245,7 @@ impl ActorTimers { impl RequeueScheduler for ActorTimers { fn schedule(&self, _key: ResourceKey, after: Duration) -> RequeueId { - let id = RequeueId(self.next.fetch_add(1, Ordering::SeqCst)); + let id = RequeueId(self.next.fetch_add(1, Ordering::Relaxed)); let handle = ractor::time::send_after(after, self.cell.clone(), || ResourceMsg::Reconcile); // `tokio::sync::Mutex` (plan U4) reached from the sync trait // surface via the non-blocking `try_lock`. The actor is the single diff --git a/packages/d2b-resource-runtime/src/revision.rs b/packages/d2b-resource-runtime/src/revision.rs index c5d1c1727..9adb0f64f 100644 --- a/packages/d2b-resource-runtime/src/revision.rs +++ b/packages/d2b-resource-runtime/src/revision.rs @@ -182,7 +182,11 @@ mod tests { #[test] fn wire_budget_bounds_sequence_for_u32_low_word() { // The U8 wire mapping packs (epoch_seconds << 32) | sequence(u32); - // the hub must therefore never exceed 2^32 sequences in one epoch. - assert_eq!(WIRE_SEQUENCE_BUDGET, 1 << 32); + // so the largest in-budget sequence must survive the low-32-bit + // truncation intact and the epoch must stay in the high word. + let max_sequence = WIRE_SEQUENCE_BUDGET - 1; + let wire = (1_u64 << 32) | max_sequence; + assert_eq!(wire as u32 as u64, max_sequence); + assert_eq!(wire >> 32, 1); } } From 5a334adb25361c8d73ed6d6dba102f891c8cff2e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:41:15 -0700 Subject: [PATCH 519/726] d2b-resource-client: model watch stream state in one atomic ResourceWatch tracked open/closing/closed with two Arc fields; align it onto the same single AtomicU8 three-state machine as ProcessAttachStream, sharing the STREAM_* constants. Add failure- injection tests proving close/cancel error paths roll the state back to open and a second close/cancel retries the transport. --- changelog.d/w3-28-resource-client-conc.md | 5 + .../d2b-resource-client/src/process_attach.rs | 102 ++++++++++++++++-- .../d2b-resource-client/src/zone_client.rs | 102 ++++++++++++++---- 3 files changed, 185 insertions(+), 24 deletions(-) create mode 100644 changelog.d/w3-28-resource-client-conc.md diff --git a/changelog.d/w3-28-resource-client-conc.md b/changelog.d/w3-28-resource-client-conc.md new file mode 100644 index 000000000..ce68ec119 --- /dev/null +++ b/changelog.d/w3-28-resource-client-conc.md @@ -0,0 +1,5 @@ +### Changed + +- Resource Watch streams track their open/closing/closed lifecycle with a + single atomic state instead of two, matching the process-attach stream + wrapper and making the rollback after a failed close explicit. \ No newline at end of file diff --git a/packages/d2b-resource-client/src/process_attach.rs b/packages/d2b-resource-client/src/process_attach.rs index 8beaebd6f..debe34355 100644 --- a/packages/d2b-resource-client/src/process_attach.rs +++ b/packages/d2b-resource-client/src/process_attach.rs @@ -22,7 +22,8 @@ use crate::{ AttemptDisposition, CallOptions, CancellationToken, ClientError, MethodProfile, ResourceClient, ServiceOwner, SystemClock, TargetInput, TargetResolver, TransportSelection, WallClock, ZoneClient, ZoneServiceKind, ZoneSessionConnector, - call::REQUEST_ID_BYTES, zone_client::ConnectedZoneSession, + call::REQUEST_ID_BYTES, + zone_client::{ConnectedZoneSession, STREAM_CLOSED, STREAM_CLOSING, STREAM_OPEN}, }; /// The maximum logical message accepted by one attach stream. @@ -32,9 +33,6 @@ use crate::{ pub const MAX_PROCESS_ATTACH_MESSAGE_BYTES: usize = d2b_contracts_zone_session::v3::component_session::MAX_LOGICAL_MESSAGE_BYTES as usize; -const STREAM_OPEN: u8 = 0; -const STREAM_CLOSING: u8 = 1; -const STREAM_CLOSED: u8 = 2; const SHELL_SESSION_TYPE: &str = "shell-terminal.d2bus.org.ShellSession"; /// The authenticated named stream used by Process and EphemeralProcess /// attachments. @@ -809,6 +807,8 @@ mod tests { received: tokio::sync::Mutex>>, closes: AtomicUsize, cancels: AtomicUsize, + close_results: tokio::sync::Mutex>>, + cancel_results: tokio::sync::Mutex>>, } impl NamedStreamTransport for Arc { @@ -831,12 +831,24 @@ mod tests { fn close(&self) -> impl Future> + Send { self.closes.fetch_add(1, Ordering::AcqRel); - core::future::ready(Ok(())) + let result = self + .close_results + .try_lock() + .expect("close results lock") + .pop_front() + .unwrap_or(Ok(())); + core::future::ready(result) } fn cancel(&self) -> impl Future> + Send { self.cancels.fetch_add(1, Ordering::AcqRel); - core::future::ready(Ok(())) + let result = self + .cancel_results + .try_lock() + .expect("cancel results lock") + .pop_front() + .unwrap_or(Ok(())); + core::future::ready(result) } } @@ -999,6 +1011,84 @@ mod tests { } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test(flavor = "current_thread")] + async fn a_failed_close_rolls_back_to_open_and_a_second_close_retries() { + let stream = Arc::new(FakeStream { + close_results: tokio::sync::Mutex::new(VecDeque::from([ + Err(ClientError::TransportFailed), + Ok(()), + ])), + ..Default::default() + }); + let session = Arc::new(FakeSession::new(vec![Ok(Arc::clone(&stream))], None)); + let client = client(FakeConnector { + session, + pin: pin(ZoneServiceKind::Zone), + requested_services: Arc::new(tokio::sync::Mutex::new(Vec::new())), + }); + let attached = client + .attach( + target(), + ProcessAttachOptions::non_tty(false), + call_options(1), + TransportSelection::exact(TransportKind::LocalUnix), + &CancellationToken::default(), + ) + .await + .unwrap(); + assert_eq!( + attached.close().await.unwrap_err(), + ClientError::TransportFailed + ); + // The failed close rolls the state back to open: the stream still + // accepts traffic and a second close retries the transport. + attached.send(b"again").await.unwrap(); + attached.close().await.unwrap(); + assert_eq!(stream.closes.load(Ordering::Acquire), 2); + assert!(attached.is_closed()); + } + + + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test(flavor = "current_thread")] + async fn a_failed_cancel_rolls_back_to_open_and_a_second_cancel_retries() { + let stream = Arc::new(FakeStream { + cancel_results: tokio::sync::Mutex::new(VecDeque::from([ + Err(ClientError::TransportFailed), + Ok(()), + ])), + ..Default::default() + }); + let session = Arc::new(FakeSession::new(vec![Ok(Arc::clone(&stream))], None)); + let client = client(FakeConnector { + session, + pin: pin(ZoneServiceKind::Zone), + requested_services: Arc::new(tokio::sync::Mutex::new(Vec::new())), + }); + let attached = client + .attach( + target(), + ProcessAttachOptions::non_tty(false), + call_options(1), + TransportSelection::exact(TransportKind::LocalUnix), + &CancellationToken::default(), + ) + .await + .unwrap(); + assert_eq!( + attached.cancel().await.unwrap_err(), + ClientError::TransportFailed + ); + // The failed cancel rolls the state back to open: the stream still + // accepts traffic and a second cancel retries the transport. + attached.send(b"again").await.unwrap(); + attached.cancel().await.unwrap(); + assert_eq!(stream.cancels.load(Ordering::Acquire), 2); + assert!(attached.is_closed()); + } + + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test(flavor = "current_thread")] async fn process_attach_stream_round_trips_the_shared_named_frame_codec() { diff --git a/packages/d2b-resource-client/src/zone_client.rs b/packages/d2b-resource-client/src/zone_client.rs index 21d6af9f8..b4deebf37 100644 --- a/packages/d2b-resource-client/src/zone_client.rs +++ b/packages/d2b-resource-client/src/zone_client.rs @@ -9,10 +9,7 @@ use core::future::Future; use std::{ fmt, - sync::{ - Arc, - atomic::{AtomicBool, Ordering}, - }, + sync::atomic::{AtomicU8, Ordering}, }; use d2b_contracts_resource::v3::{ @@ -471,6 +468,12 @@ impl<'a> ResourceCallOptions<'a> { } } +/// The single-atomic stream state machine shared by every caller-side named +/// stream wrapper in this crate. +pub(crate) const STREAM_OPEN: u8 = 0; +pub(crate) const STREAM_CLOSING: u8 = 1; +pub(crate) const STREAM_CLOSED: u8 = 2; + /// A named Resource Watch stream supplied by the authenticated session. pub trait ResourceWatchTransport: Send + Sync { /// Receive one bounded canonical event, or `None` after terminal close. @@ -488,8 +491,7 @@ pub trait ResourceWatchTransport: Send + Sync { /// callers must call [`ResourceWatch::close`] when they stop consuming. pub struct ResourceWatch { transport: S, - state: Arc, - closing: Arc, + state: AtomicU8, } impl ResourceWatch { @@ -497,8 +499,7 @@ impl ResourceWatch { pub fn new(transport: S) -> Self { Self { transport, - state: Arc::new(AtomicBool::new(false)), - closing: Arc::new(AtomicBool::new(false)), + state: AtomicU8::new(STREAM_OPEN), } } @@ -509,11 +510,11 @@ impl ResourceWatch { /// Whether close has completed or the peer has ended the stream. pub fn is_closed(&self) -> bool { - self.state.load(Ordering::Acquire) + self.state.load(Ordering::Acquire) == STREAM_CLOSED } fn is_open(&self) -> bool { - !self.state.load(Ordering::Acquire) && !self.closing.load(Ordering::Acquire) + self.state.load(Ordering::Acquire) == STREAM_OPEN } } @@ -537,30 +538,32 @@ where } let event = self.transport.receive_watch_event().await?; if event.is_none() { - self.state.store(true, Ordering::Release); + self.state.store(STREAM_CLOSED, Ordering::Release); } Ok(event) } /// Close the Watch stream exactly once after a successful remote close. pub async fn close(&self) -> Result<(), ClientError> { - if self.state.load(Ordering::Acquire) { - return Ok(()); - } if self - .closing - .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire) + .state + .compare_exchange( + STREAM_OPEN, + STREAM_CLOSING, + Ordering::AcqRel, + Ordering::Acquire, + ) .is_err() { return Ok(()); } match self.transport.close_watch().await { Ok(()) => { - self.state.store(true, Ordering::Release); + self.state.store(STREAM_CLOSED, Ordering::Release); Ok(()) } Err(error) => { - self.closing.store(false, Ordering::Release); + self.state.store(STREAM_OPEN, Ordering::Release); Err(error) } } @@ -892,10 +895,47 @@ impl fmt::Debug for LocalZoneSession { #[cfg(test)] mod tests { + use std::{ + collections::VecDeque, + sync::atomic::{AtomicUsize, Ordering}, + }; + use super::*; use crate::ServiceOwner; use crate::target::fixtures::zone; + #[derive(Default)] + struct FakeWatchTransport { + events: tokio::sync::Mutex, ClientError>>>, + closes: AtomicUsize, + close_results: tokio::sync::Mutex>>, + } + + impl ResourceWatchTransport for FakeWatchTransport { + fn receive_watch_event( + &self, + ) -> impl Future, ClientError>> + Send { + let result = self + .events + .try_lock() + .expect("events lock") + .pop_front() + .unwrap_or(Ok(None)); + core::future::ready(result) + } + + fn close_watch(&self) -> impl Future> + Send { + self.closes.fetch_add(1, Ordering::AcqRel); + let result = self + .close_results + .try_lock() + .expect("close results lock") + .pop_front() + .unwrap_or(Ok(())); + core::future::ready(result) + } + } + fn peer(zone: &str, key: u8) -> ZonePeerIdentity { ZonePeerIdentity::from_observed_static_key( crate::target::fixtures::zone(&[zone]), @@ -976,4 +1016,30 @@ mod tests { assert!(!format!("{endpoint:?}").contains("gateway")); assert!(!format!("{endpoint:?}").contains("123e4567")); } + + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test(flavor = "current_thread")] + async fn a_failed_watch_close_rolls_back_to_open_and_a_second_close_retries() { + let transport = FakeWatchTransport { + events: tokio::sync::Mutex::new(VecDeque::from([Ok(Some( + CanonicalJsonObject::parse(br#"{"marker":"event"}"#).unwrap(), + ))])), + close_results: tokio::sync::Mutex::new(VecDeque::from([ + Err(ClientError::TransportFailed), + Ok(()), + ])), + ..Default::default() + }; + let watch = ResourceWatch::new(transport); + assert_eq!( + watch.close().await.unwrap_err(), + ClientError::TransportFailed + ); + // The failed close rolls the state back to open: the watch still + // consumes events and a second close retries the transport. + assert!(watch.next().await.unwrap().is_some()); + watch.close().await.unwrap(); + assert_eq!(watch.transport().closes.load(Ordering::Acquire), 2); + assert!(watch.is_closed()); + } } From 652dc86a74a46af53c14d9a676ac8b6c14539396 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:41:30 -0700 Subject: [PATCH 520/726] d2b: make azure-relay credit reservation cancellation-safe - RelayConnection::send wraps the credit reservation in an RAII guard that rolls the bytes back on drop unless the send committed, so a cancelled send can no longer leak up to 64 KiB of credit (RS-0850). The credit window is now a synchronous mutex so the rollback can run from Drop, matching the generation fence's synchronous-path pattern. - The generation-fence key is precomputed once per connection and passed to is_current, removing three heap allocations from every send/receive (RS-0787). - read_policy_file pre-sizes the buffer from the known file metadata (RS-0788). --- changelog.d/w3-25-azure-relay-perf-async.md | 10 ++ .../src/guest_credential.rs | 2 +- .../src/relay_transport.rs | 93 +++++++++++++++---- 3 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 changelog.d/w3-25-azure-relay-perf-async.md diff --git a/changelog.d/w3-25-azure-relay-perf-async.md b/changelog.d/w3-25-azure-relay-perf-async.md new file mode 100644 index 000000000..435ccd029 --- /dev/null +++ b/changelog.d/w3-25-azure-relay-perf-async.md @@ -0,0 +1,10 @@ +### Fixed + +- Azure Relay sends are now cancellation-safe: a send cancelled between + credit reservation and socket write returns the reserved credits instead + of permanently starving the connection of up to 64 KiB of send credit. +- Azure Relay per-frame I/O no longer rebuilds the generation-fence key + (three heap allocations) on every send and receive; the key is computed + once per connection. +- Gateway credential policy files are read into a buffer pre-sized from the + file metadata, avoiding reallocations during the read. \ No newline at end of file diff --git a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs index db284b1aa..7e69ecbe1 100644 --- a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs +++ b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs @@ -599,7 +599,7 @@ fn read_policy_file( { return Err(CredentialError::BadOwner(meta.uid())); } - let mut bytes = Zeroizing::new(Vec::new()); + let mut bytes = Zeroizing::new(Vec::with_capacity(meta.len() as usize)); file.read_to_end(&mut bytes) .map_err(|_| CredentialError::Unreadable)?; Ok(bytes) diff --git a/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs b/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs index c427c0e30..0f077a2a5 100644 --- a/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs +++ b/packages/d2b-provider-transport-azure-relay/src/relay_transport.rs @@ -626,16 +626,15 @@ impl RelayGenerationFence { remove_empty_state(&mut states, key); } - fn is_current(&self, binding: &RelayCredentialBinding) -> bool { - let key = generation_key(binding); + fn is_current(&self, key: &(String, String, String), generation: u64) -> bool { let states = self.lock_states(); - let Some(state) = states.get(&key) else { + let Some(state) = states.get(key) else { return false; }; - state.committed == Some(binding.reconnect_generation()) + state.committed == Some(generation) && state .active - .get(&binding.reconnect_generation()) + .get(&generation) .is_some_and(|count| *count > 0) } @@ -728,17 +727,68 @@ fn remove_empty_state( /// One open relay connection with bounded named-stream credits. pub struct RelayConnection { socket: Arc, - credits: Mutex, + credits: StdMutex, write_lock: Mutex<()>, phase: Mutex, challenge: RelayEnrollmentChallenge, binding: RelayCredentialBinding, + generation_key: (String, String, String), generation_fence: Arc, generation_lease: Mutex>, session_permit: Mutex>, } +/// A reserved slice of the credit window that returns its bytes on drop +/// unless the frame send committed. +/// +/// `send` reserves credits before awaiting the socket write. If the future +/// is cancelled between the reservation and the write completing (for +/// example by a session deadline), the reservation must not leak, or the +/// connection is permanently starved of up to [`MAX_RELAY_FRAME_BYTES`] of +/// credit. The window is a synchronous mutex so the rollback can run from +/// `Drop` without awaiting. +struct CreditReservation<'a> { + credits: &'a StdMutex, + bytes: usize, + committed: bool, +} + +impl CreditReservation<'_> { + fn commit(mut self) { + self.committed = true; + } +} + +impl Drop for CreditReservation<'_> { + fn drop(&mut self) { + if !self.committed { + #[allow( + clippy::disallowed_methods, + reason = "synchronous path" + )] + match self.credits.lock() { + Ok(mut credits) => credits.rollback(self.bytes), + Err(poisoned) => poisoned.into_inner().rollback(self.bytes), + } + } + } +} + impl RelayConnection { + // Synchronous path: the credit window's critical sections are + // non-blocking arithmetic updates, and the reservation rollback must run + // from `Drop` (see `CreditReservation`), which cannot await. + #[allow( + clippy::disallowed_methods, + reason = "synchronous path" + )] + fn lock_credits(&self) -> StdMutexGuard<'_, CreditWindow> { + match self.credits.lock() { + Ok(credits) => credits, + Err(poisoned) => poisoned.into_inner(), + } + } + /// Construct a connection whose enrollment was durably committed by Core. fn from_committed_socket( socket: Arc, @@ -750,13 +800,15 @@ impl RelayConnection { ) -> Result { let credits = CreditWindow::new(credit_bytes).map_err(|_| RelayTransportError::CreditExhausted)?; + let generation_key = generation_key(&binding); Ok(Self { socket, - credits: Mutex::new(credits), + credits: StdMutex::new(credits), write_lock: Mutex::new(()), phase: Mutex::new(RelaySessionPhase::EnrollmentCommitted), challenge: next_connection_challenge(), binding, + generation_key, generation_fence, generation_lease: Mutex::new(Some(generation_lease)), session_permit: Mutex::new(Some(session_permit)), @@ -776,7 +828,10 @@ impl RelayConnection { } async fn ensure_current_generation(&self) -> Result<(), RelayTransportError> { - if self.generation_fence.is_current(&self.binding) { + if self + .generation_fence + .is_current(&self.generation_key, self.binding.reconnect_generation()) + { Ok(()) } else { Err(self.reject_stale_generation().await) @@ -821,16 +876,22 @@ impl RelayConnection { return Err(RelayTransportError::InvalidSessionTransition); } let size = frame.as_bytes().len(); - { - let mut credits = self.credits.lock().await; + let reservation = { + let mut credits = self.lock_credits(); credits.reserve(size).map_err(|error| match error { BackpressureError::FrameTooLarge => RelayTransportError::FrameTooLarge, BackpressureError::CreditExhausted => RelayTransportError::CreditExhausted, })?; - } + CreditReservation { + credits: &self.credits, + bytes: size, + committed: false, + } + }; let result = self.socket.send(frame).await; - if result.is_err() { - self.credits.lock().await.rollback(size); + if result.is_ok() { + reservation.commit(); + } else { *self.phase.lock().await = RelaySessionPhase::Closed; self.session_permit.lock().await.take(); self.release_generation_lease().await; @@ -857,17 +918,17 @@ impl RelayConnection { /// Grant credits from the remote named stream. pub async fn grant(&self, bytes: usize) { - self.credits.lock().await.grant(bytes); + self.lock_credits().grant(bytes); } /// Release send credits after a remote acknowledgement. pub async fn acknowledge(&self, bytes: usize) { - self.credits.lock().await.acknowledge(bytes); + self.lock_credits().acknowledge(bytes); } /// Return available and in-flight send credits. pub async fn credit_state(&self) -> (usize, usize) { - let credits = self.credits.lock().await; + let credits = self.lock_credits(); (credits.available(), credits.in_flight()) } From 81b2ef8673c865c7d4dfd32370280bc2b5223062 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:45:49 -0700 Subject: [PATCH 521/726] d2b-resource-api: dedupe hex, skip no-op clones, generic error responses - extract one hex() renderer for list cursors and selector digests - compare canonical bytes before cloning in commit_mutation - pre-size authorization-facts vectors - replace the response_error! macro with a generic error_response fn - convert the representability test into a status-owner mismatch test - tolerate a second boundary crossing in the snapshot revision test --- changelog.d/w3-27-resource-api-perf-macro.md | 5 + packages/d2b-resource-api/src/authz.rs | 4 +- .../d2b-resource-api/src/manager_backend.rs | 45 ++- .../src/manager_backend/tests.rs | 18 +- packages/d2b-resource-api/src/service.rs | 258 ++++++++++++------ 5 files changed, 215 insertions(+), 115 deletions(-) create mode 100644 changelog.d/w3-27-resource-api-perf-macro.md diff --git a/changelog.d/w3-27-resource-api-perf-macro.md b/changelog.d/w3-27-resource-api-perf-macro.md new file mode 100644 index 000000000..cdf0cfd5c --- /dev/null +++ b/changelog.d/w3-27-resource-api-perf-macro.md @@ -0,0 +1,5 @@ +### Changed + +- The resource API now compares a desired update envelope against the stored row before copying it, so a byte-identical no-op update no longer pays for a full canonical-resource clone; list cursors and authorization-facts compilation also avoid per-byte and per-row allocations. +- Error responses from the resource RPC methods are now rendered through a single generic helper instead of thirteen generated functions; the wire output is unchanged. +- The list snapshot-revision test tolerates a second boundary crossing between the served snapshot and the clock read, so it no longer flakes at epoch-second boundaries. \ No newline at end of file diff --git a/packages/d2b-resource-api/src/authz.rs b/packages/d2b-resource-api/src/authz.rs index e6111649c..2c3ed8a19 100644 --- a/packages/d2b-resource-api/src/authz.rs +++ b/packages/d2b-resource-api/src/authz.rs @@ -433,8 +433,8 @@ pub fn compile_authorization_facts( controller_generation: ControllerGeneration, provider_generation: d2b_contracts_resource::v3::ResourceGeneration, ) -> Result { - let mut roles = Vec::new(); - let mut bindings = Vec::new(); + let mut roles = Vec::with_capacity(rows.len()); + let mut bindings = Vec::with_capacity(rows.len()); let mut subject_uids: BTreeMap = BTreeMap::new(); let mut bootstrap_provider_uids = BTreeMap::new(); for row in rows { diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index 8b4a679ea..898ac731e 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -398,6 +398,16 @@ fn key_order(key: &RuntimeResourceKey) -> (&str, &str, &str) { /// before digesting: echoing the same logical query with the sets reordered, /// or with a repeated value, resumes the sequence instead of being refused as /// a foreign cursor. +/// Lowercase hex encoding of a byte slice, two characters per byte. +fn hex(bytes: &[u8]) -> String { + let mut out = String::with_capacity(bytes.len() * 2); + for byte in bytes { + out.push(char::from_digit((byte >> 4) as u32, 16).expect("nibble")); + out.push(char::from_digit((byte & 0x0f) as u32, 16).expect("nibble")); + } + out +} + fn list_selector_digest(request: &StoreListRequest) -> String { use sha2::{Digest, Sha256}; let mut digest = Sha256::new(); @@ -445,14 +455,6 @@ fn list_selector_digest(request: &StoreListRequest) -> String { digest.update([0]); } } - let hex = |bytes: &[u8]| { - let mut out = String::with_capacity(bytes.len() * 2); - for byte in bytes { - out.push(char::from_digit((byte >> 4) as u32, 16).expect("nibble")); - out.push(char::from_digit((byte & 0x0f) as u32, 16).expect("nibble")); - } - out - }; hex(&digest.finalize()) } @@ -492,8 +494,8 @@ fn encode_list_cursor( key.extend_from_slice(part.as_bytes()); key.push(0); } - let hex = key.iter().map(|byte| format!("{byte:02x}")).collect::(); - format!("v1.{revision}.{}.{hex}", list_selector_digest(request)) + let key_hex = hex(&key); + format!("v1.{revision}.{}.{key_hex}", list_selector_digest(request)) } /// Decode and validate a continuation cursor against the request it is @@ -1014,12 +1016,25 @@ impl ManagerBackend { &mutation.add_finalizers, &mutation.remove_finalizers, )?, - _ => mutation.canonical_resource.clone().ok_or_else(envelope_invalid)?, + _ => { + let canonical = mutation + .canonical_resource + .as_deref() + .ok_or_else(envelope_invalid)?; + // A byte-identical desired envelope is a no-op: the + // manager keeps the row and generation unchanged, so + // the response is the same canonical wire view a read + // of that row serves - never a second rendering of the + // desired bytes alone. Compare before cloning so a + // no-op update never pays for the full copy. + if canonical == row.spec.as_slice() { + return Ok(Some(self.committed(&key).await?)); + } + canonical.to_vec() + } }; - // A byte-identical desired envelope is a no-op: the manager - // keeps the row and generation unchanged, so the response is - // the same canonical wire view a read of that row serves - - // never a second rendering of the desired bytes alone. + // The finalizers path can also produce a byte-identical spec; + // that is the same no-op and returns the committed view too. if next == row.spec { return Ok(Some(self.committed(&key).await?)); } diff --git a/packages/d2b-resource-api/src/manager_backend/tests.rs b/packages/d2b-resource-api/src/manager_backend/tests.rs index fe172e79f..295b22df7 100644 --- a/packages/d2b-resource-api/src/manager_backend/tests.rs +++ b/packages/d2b-resource-api/src/manager_backend/tests.rs @@ -1456,13 +1456,17 @@ async fn list_returns_snapshot_revision_and_watch_refuses_until_wired() { error_reason(&empty) ); let snapshot = empty.snapshot_revision; - assert_eq!( - snapshot >> 32, - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_secs(), - "the wire snapshot carries the epoch-seconds mapping" + // The snapshot's epoch-seconds half is stamped when the list is served, + // which precedes the clock read here; a second boundary may cross in + // between, so the mapping holds within a one-second tolerance. + let now_secs = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + let snapshot_secs = snapshot >> 32; + assert!( + snapshot_secs <= now_secs && now_secs - snapshot_secs <= 1, + "the wire snapshot carries the epoch-seconds mapping: snapshot={snapshot_secs} now={now_secs}" ); let created = service.create(trusted(create_request())).await; diff --git a/packages/d2b-resource-api/src/service.rs b/packages/d2b-resource-api/src/service.rs index 6bacee0ed..367b3f69e 100644 --- a/packages/d2b-resource-api/src/service.rs +++ b/packages/d2b-resource-api/src/service.rs @@ -520,14 +520,14 @@ where pub async fn get(&self, trusted: TrustedRequest) -> wire::GetResponse { let identity = match parse_identity(trusted.request.target.as_ref()) { Ok(identity) => identity, - Err(error) => return get_error(error), + Err(error) => return error_response(error), }; let auth = authorization_for_identity(ApiMethod::Get, ResourceVerb::Get, &identity); if let Err(error) = self.authorize(&trusted, auth) { - return get_error(error); + return error_response(error); } if let Err(error) = validate_request(&trusted.request) { - return get_error(error); + return error_response(error); } let operation = match operation_context( trusted.request.meta.as_ref(), @@ -535,11 +535,11 @@ where &trusted.authorization_state, ) { Ok(operation) => operation, - Err(error) => return get_error(error), + Err(error) => return error_response(error), }; let projection = match parse_projection(trusted.request.projection.as_ref()) { Ok(projection) => projection, - Err(error) => return get_error(error), + Err(error) => return error_response(error), }; match self .store @@ -557,8 +557,8 @@ where response.resource = MessageField::some(to_wire_resource(resource)); response } - Ok(_) => get_error(schema_error("resource response exceeds its byte bound")), - Err(error) => get_error(map_store_error(error)), + Ok(_) => error_response(schema_error("resource response exceeds its byte bound")), + Err(error) => error_response(map_store_error(error)), } } @@ -570,7 +570,7 @@ where MAX_LIST_FILTERS, ) { Ok(parsed) => parsed, - Err(error) => return list_error(error), + Err(error) => return error_response(error), }; let auth = AuthorizationRequest { method: ApiMethod::List, @@ -578,10 +578,10 @@ where targets: collection_targets(&parsed, ResourceVerb::List), }; if let Err(error) = self.authorize(&trusted, auth) { - return list_error(error); + return error_response(error); } if let Err(error) = validate_request(&trusted.request) { - return list_error(error); + return error_response(error); } let operation = match operation_context( trusted.request.meta.as_ref(), @@ -589,7 +589,7 @@ where &trusted.authorization_state, ) { Ok(operation) => operation, - Err(error) => return list_error(error), + Err(error) => return error_response(error), }; let page_size = if trusted.request.page_size == 0 { DEFAULT_LIST_PAGE_SIZE @@ -597,7 +597,7 @@ where trusted.request.page_size }; if page_size > MAX_LIST_PAGE_SIZE { - return list_error(schema_error("page size exceeds its bound")); + return error_response(schema_error("page size exceeds its bound")); } let cursor = trusted .request @@ -609,11 +609,11 @@ where .as_ref() .is_some_and(|cursor| cursor.len() > MAX_PAGE_CURSOR_BYTES) { - return list_error(schema_error("page cursor exceeds its bound")); + return error_response(schema_error("page cursor exceeds its bound")); } let projection = match parse_projection(trusted.request.projection.as_ref()) { Ok(projection) => projection, - Err(error) => return list_error(error), + Err(error) => return error_response(error), }; match self .store @@ -640,14 +640,14 @@ where } response.truncated = result.truncated; if response.compute_size() as usize > MAX_RESPONSE_CANONICAL_BYTES { - list_error(schema_error( + error_response(schema_error( "list store result was not truncated at the byte bound", )) } else { response } } - Err(error) => list_error(map_store_error(error)), + Err(error) => error_response(map_store_error(error)), } } @@ -659,7 +659,7 @@ where MAX_WATCH_FILTERS, ) { Ok(parsed) => parsed, - Err(error) => return watch_error(error), + Err(error) => return error_response(error), }; let auth = AuthorizationRequest { method: ApiMethod::Watch, @@ -667,10 +667,10 @@ where targets: collection_targets(&parsed, ResourceVerb::Watch), }; if let Err(error) = self.authorize(&trusted, auth) { - return watch_error(error); + return error_response(error); } if let Err(error) = validate_request(&trusted.request) { - return watch_error(error); + return error_response(error); } let operation = match operation_context( trusted.request.meta.as_ref(), @@ -678,7 +678,7 @@ where &trusted.authorization_state, ) { Ok(operation) => operation, - Err(error) => return watch_error(error), + Err(error) => return error_response(error), }; let credits = trusted .request @@ -686,11 +686,11 @@ where .as_ref() .map_or(DEFAULT_WATCH_CREDITS, |credits| credits.initial); if credits == 0 || credits > MAX_WATCH_CREDITS { - return watch_error(schema_error("watch credits exceed their bound")); + return error_response(schema_error("watch credits exceed their bound")); } let projection = match parse_projection(trusted.request.projection.as_ref()) { Ok(projection) => projection, - Err(error) => return watch_error(error), + Err(error) => return error_response(error), }; match self .store @@ -712,7 +712,7 @@ where response.snapshot_revision = receipt.snapshot_revision.get(); response } - Err(error) => watch_error(map_store_error(error)), + Err(error) => error_response(map_store_error(error)), } } @@ -725,7 +725,7 @@ where .await { Ok(result) => mutation_response(result, trusted.request.mutation.as_ref(), true), - Err(error) => create_error(error), + Err(error) => error_response(error), } } @@ -745,7 +745,7 @@ where let common = mutation_response(result, trusted.request.mutation.as_ref(), true); copy_update_spec_response(common) } - Err(error) => update_spec_error(error), + Err(error) => error_response(error), } } @@ -766,7 +766,7 @@ where trusted.request.mutation.as_ref(), false, )), - Err(error) => update_status_error(error), + Err(error) => error_response(error), } } @@ -787,7 +787,7 @@ where trusted.request.mutation.as_ref(), false, )), - Err(error) => update_metadata_error(error), + Err(error) => error_response(error), } } @@ -808,7 +808,7 @@ where trusted.request.mutation.as_ref(), false, )), - Err(error) => update_finalizers_error(error), + Err(error) => error_response(error), } } @@ -839,7 +839,7 @@ where } response } - Err(error) => delete_error(error), + Err(error) => error_response(error), } } @@ -851,7 +851,7 @@ where } pub(crate) fn invalid_commit_batch(reason: &'static str) -> wire::CommitBatchResponse { - batch_error(schema_error(reason)) + error_response(schema_error(reason)) } /// Commit one bus-authorized assignment batch while carrying the same @@ -872,7 +872,7 @@ where configuration_generation: Option, ) -> wire::CommitBatchResponse { if trusted.request.mutations.is_empty() { - return batch_error(schema_error("batch mutation count is zero")); + return error_response(schema_error("batch mutation count is zero")); } let routes = match trusted .request @@ -882,7 +882,7 @@ where .collect::, _>>() { Ok(routes) => routes, - Err(error) => return batch_error(error), + Err(error) => return error_response(error), }; let batch_zone = subject_zone(&trusted); if routes.iter().any(|route| { @@ -892,7 +892,7 @@ where .as_ref() .is_some_and(|owner| owner.zone != batch_zone) }) { - return batch_error(ResourceError::terminal( + return error_response(ResourceError::terminal( ResourceErrorKind::AuthorizationDenied, "batch route is outside the authenticated Zone", )); @@ -907,13 +907,13 @@ where }; let grant = match self.authorize(&trusted, auth) { Ok(grant) => grant, - Err(error) => return batch_error(error), + Err(error) => return error_response(error), }; if let Err(error) = validate_request(&trusted.request) { - return batch_error(error); + return error_response(error); } if trusted.request.mutations.len() > MAX_BATCH_MUTATIONS { - return batch_error(schema_error("batch mutation count exceeds its bound")); + return error_response(schema_error("batch mutation count exceeds its bound")); } let mut parsed = match trusted .request @@ -924,12 +924,12 @@ where .collect::, _>>() { Ok(parsed) => parsed, - Err(error) => return batch_error(error), + Err(error) => return error_response(error), }; if let Some(scoped_mutations) = scoped_mutations && let Err(error) = attach_scoped_fences(&mut parsed, scoped_mutations, &routes) { - return batch_error(error); + return error_response(error); } for mutation in &mut parsed { mutation.store.configuration_generation = configuration_generation; @@ -940,7 +940,7 @@ where &trusted.authorization_state, ) { Ok(operation) => operation, - Err(error) => return batch_error(error), + Err(error) => return error_response(error), }; let mutations = parsed.into_iter().map(|item| item.store).collect(); let admitted = match self.zone_uid.as_ref() { @@ -950,7 +950,7 @@ where let admitted = match admitted { Ok(admitted) => admitted, Err(_) => { - return batch_error(ResourceError::terminal( + return error_response(ResourceError::terminal( ResourceErrorKind::InternalIntegrityFailure, "admission-invariant-violated", )); @@ -962,8 +962,8 @@ where response.resources = result.resources.into_iter().map(to_wire_resource).collect(); response.revision = result.revision.get(); if response.compute_size() as usize > MAX_RESPONSE_CANONICAL_BYTES { - let mut limited = - batch_error(schema_error("batch response exceeds its byte bound")); + let mut limited: wire::CommitBatchResponse = + error_response(schema_error("batch response exceeds its byte bound")); limited.revision = response.revision; limited } else { @@ -973,7 +973,8 @@ where Err(error) => { let conflict_mutation_ordinal = error.mutation_ordinal().map(|ordinal| ordinal.get()); - let mut response = batch_error(map_store_error_with_revision_visibility( + let mut response: wire::CommitBatchResponse = + error_response(map_store_error_with_revision_visibility( error, self.can_read_revision(&trusted, &routes), )); @@ -989,16 +990,16 @@ where ) -> wire::ResolveRefResponse { let identity = match parse_identity(trusted.request.target.as_ref()) { Ok(identity) => identity, - Err(error) => return resolve_error(error), + Err(error) => return error_response(error), }; if let Err(error) = self.authorize( &trusted, authorization_for_identity(ApiMethod::ResolveRef, ResourceVerb::Get, &identity), ) { - return resolve_error(error); + return error_response(error); } if let Err(error) = validate_request(&trusted.request) { - return resolve_error(error); + return error_response(error); } let operation = match operation_context( trusted.request.meta.as_ref(), @@ -1006,7 +1007,7 @@ where &trusted.authorization_state, ) { Ok(operation) => operation, - Err(error) => return resolve_error(error), + Err(error) => return error_response(error), }; match self .store @@ -1023,7 +1024,7 @@ where response.resource = MessageField::some(to_wire_resolved_identity(identity)); response } - Err(error) => resolve_error(map_store_error(error)), + Err(error) => error_response(map_store_error(error)), } } @@ -1033,7 +1034,7 @@ where ) -> wire::InspectSchemaResponse { let resource_type = match ResourceTypeName::parse(&trusted.request.resource_type) { Ok(resource_type) => resource_type, - Err(_) => return inspect_error(ref_error("ResourceType is invalid")), + Err(_) => return error_response(ref_error("ResourceType is invalid")), }; let auth = AuthorizationRequest { method: ApiMethod::InspectSchema, @@ -1047,10 +1048,10 @@ where }], }; if let Err(error) = self.authorize(&trusted, auth) { - return inspect_error(error); + return error_response(error); } if let Err(error) = validate_request(&trusted.request) { - return inspect_error(error); + return error_response(error); } let operation = match operation_context( trusted.request.meta.as_ref(), @@ -1058,7 +1059,7 @@ where &trusted.authorization_state, ) { Ok(operation) => operation, - Err(error) => return inspect_error(error), + Err(error) => return error_response(error), }; match self .store @@ -1080,12 +1081,12 @@ where let mut response = wire::InspectSchemaResponse::new(); response.schema = MessageField::some(body); if response.compute_size() as usize > MAX_RESPONSE_CANONICAL_BYTES { - inspect_error(schema_error("schema response exceeds its byte bound")) + error_response(schema_error("schema response exceeds its byte bound")) } else { response } } - Err(error) => inspect_error(map_store_error(error)), + Err(error) => error_response(map_store_error(error)), } } @@ -1095,15 +1096,15 @@ where ) -> wire::UpgradeResponse { let identity = match parse_identity(trusted.request.target.as_ref()) { Ok(identity) => identity, - Err(error) => return upgrade_error(error), + Err(error) => return error_response(error), }; let auth = authorization_for_identity(ApiMethod::Upgrade, ResourceVerb::UpdateSpec, &identity); if let Err(error) = self.authorize(&trusted, auth) { - return upgrade_error(error); + return error_response(error); } if let Err(error) = validate_request(&trusted.request) { - return upgrade_error(error); + return error_response(error); } let operation = match operation_context( trusted.request.meta.as_ref(), @@ -1111,17 +1112,17 @@ where &trusted.authorization_state, ) { Ok(operation) => operation, - Err(error) => return upgrade_error(error), + Err(error) => return error_response(error), }; let expected_revision = match parse_precondition(trusted.request.precondition.as_ref()) { Ok(ExpectedRevision::Exact(revision)) => revision, - _ => return upgrade_error(schema_error("upgrade requires an exact revision")), + _ => return error_response(schema_error("upgrade requires an exact revision")), }; let action = match trusted.request.action.enum_value() { Ok(wire::UpgradeAction::UPGRADE_ACTION_ASSESS) => UpgradeAction::Assess, Ok(wire::UpgradeAction::UPGRADE_ACTION_PLAN) => UpgradeAction::Plan, Ok(wire::UpgradeAction::UPGRADE_ACTION_EXECUTE) => UpgradeAction::Execute, - _ => return upgrade_error(schema_error("upgrade action is unspecified")), + _ => return error_response(schema_error("upgrade action is unspecified")), }; match self .upgrade @@ -1145,15 +1146,15 @@ where .collect(); response.revision = result.revision.get(); if response.compute_size() as usize > MAX_RESPONSE_CANONICAL_BYTES { - let mut limited = - upgrade_error(schema_error("upgrade response exceeds its byte bound")); + let mut limited: wire::UpgradeResponse = + error_response(schema_error("upgrade response exceeds its byte bound")); limited.revision = response.revision; limited } else { response } } - Err(error) => upgrade_error(error), + Err(error) => error_response(error), } } @@ -2249,29 +2250,97 @@ fn ref_error(reason: &'static str) -> ResourceError { ResourceError::terminal(ResourceErrorKind::ResourceRefInvalid, reason) } -macro_rules! response_error { - ($name:ident, $ty:ty) => { - fn $name(error: ResourceError) -> $ty { - let mut response = <$ty>::new(); - response.error = MessageField::some(to_wire_error(&error)); - response - } - }; +/// Any wire response that carries an `error` field, so an error can be +/// rendered into the response type each RPC method returns. +trait ErrorResponse: Message { + fn set_error(&mut self, error: MessageField); +} + +impl ErrorResponse for wire::GetResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::ListResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::WatchResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::CreateResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::UpdateSpecResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::UpdateStatusResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::UpdateMetadataResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::UpdateFinalizersResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::DeleteResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::CommitBatchResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::ResolveRefResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::InspectSchemaResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } +} + +impl ErrorResponse for wire::UpgradeResponse { + fn set_error(&mut self, error: MessageField) { + self.error = error; + } } -response_error!(get_error, wire::GetResponse); -response_error!(list_error, wire::ListResponse); -response_error!(watch_error, wire::WatchResponse); -response_error!(create_error, wire::CreateResponse); -response_error!(update_spec_error, wire::UpdateSpecResponse); -response_error!(update_status_error, wire::UpdateStatusResponse); -response_error!(update_metadata_error, wire::UpdateMetadataResponse); -response_error!(update_finalizers_error, wire::UpdateFinalizersResponse); -response_error!(delete_error, wire::DeleteResponse); -response_error!(batch_error, wire::CommitBatchResponse); -response_error!(resolve_error, wire::ResolveRefResponse); -response_error!(inspect_error, wire::InspectSchemaResponse); -response_error!(upgrade_error, wire::UpgradeResponse); +/// Render an error into the wire response type an RPC method returns; the +/// response type is inferred from the method's return type. +fn error_response(error: ResourceError) -> T { + let mut response = T::new(); + response.set_error(MessageField::some(to_wire_error(&error))); + response +} #[cfg(test)] mod tests { @@ -3381,13 +3450,20 @@ mod tests { } #[test] - fn status_owner_matching_generation_is_representable() { - let context = subject(Some(11)); - assert_eq!( - context.controller_generation(), - Some(ControllerGeneration::new(11).unwrap()) - ); - let _: ResourceGeneration = ResourceGeneration::new(11).unwrap(); + fn status_owner_generation_mismatch_is_rejected() { + // The status-owner check is a wire-compatibility contract: an + // UpdateStatus mutation is refused when the authenticated subject's + // controller generation differs from the authorization snapshot's, + // even when both generations are representable. + let trusted = + TrustedRequest::from_session_capability(subject(Some(11)), state(Some(12)), ()); + let mut value = mutation(wire::MutationKind::MUTATION_KIND_UPDATE_STATUS); + value.resource = body(GOLDEN_HOST.to_vec()); + let route = + parse_mutation_route(&value, Some(ResourceMutationKind::UpdateStatus), &trusted) + .unwrap(); + let error = parse_mutation(&value, &route, &trusted).unwrap_err(); + assert_eq!(error.kind(), ResourceErrorKind::ResourceStatusOwnerMismatch); } #[test] From 06d6376af40dc2269f0baefbcf4c80645fc02c28 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:47:00 -0700 Subject: [PATCH 522/726] provider-conc: align latency-sensitive lock and atomic sites with the census Per-site synchronized-path and cfg(test)-helper allows for the parking_lot lock calls in the device-security-key relay and its recording doubles, so the blocking census counts them as sanctioned rather than as production misuse. The relay guards are already statement-scoped, so arm the sanctioned reason on each allow and leave the async-gate markers unedited. The process driver's 16 Ordering::SeqCst sites and the toolkit invocation-id counter publish no other data, so they move to Relaxed; the transport-unix portal uses the crate's own try_lock-only pattern, so its tokio::sync::Mutex becomes std::sync::Mutex; and the volume-binding test doubles swap parking_lot for std::sync::Mutex, dropping the banned dependency from the manifest. --- changelog.d/w3-23-provider-conc-leaf.md | 19 ++++++ .../src/relay_service.rs | 8 +++ .../src/test_support.rs | 6 ++ packages/d2b-provider-process/src/driver.rs | 32 +++++----- .../src/operations/envelope.rs | 2 +- .../d2b-provider-transport-unix/src/portal.rs | 2 +- .../d2b-provider-volume-binding/Cargo.toml | 4 -- .../d2b-provider-volume-binding/src/driver.rs | 61 ++++++++++++------- .../src/test_support.rs | 24 +++++--- 9 files changed, 105 insertions(+), 53 deletions(-) create mode 100644 changelog.d/w3-23-provider-conc-leaf.md diff --git a/changelog.d/w3-23-provider-conc-leaf.md b/changelog.d/w3-23-provider-conc-leaf.md new file mode 100644 index 000000000..3c46a4799 --- /dev/null +++ b/changelog.d/w3-23-provider-conc-leaf.md @@ -0,0 +1,19 @@ +### Fixed + +- d2b-provider-device-security-key: the CTAPHID relay and its recording test + doubles now carry the sanctioned per-site lint allows for their synchronous + parking_lot lock acquisitions, matching the committed blocking-census + baseline. +- d2b-provider-process: restart-budget counters, the ephemeral-runtime started + flag, and the durable-runtime watching flag now use relaxed atomic + ordering; the flags publish no other data, so the strongest ordering bought + nothing. +- d2b-provider-toolkit: invocation identifiers use relaxed ordering for the + monotonic counter; only uniqueness is required. +- d2b-provider-transport-unix: the transport portal lock is now a + `std::sync::Mutex`; the portal only ever takes it with `try_lock()` on + synchronous paths, so the tokio sync dependency is no longer needed for + this lock. +- d2b-provider-volume-binding: the recording test doubles (serving effects, + recording manager, and requeue scheduler) now use `std::sync::Mutex`, and + the banned parking_lot dependency is dropped from the crate manifest. \ No newline at end of file diff --git a/packages/d2b-provider-device-security-key/src/relay_service.rs b/packages/d2b-provider-device-security-key/src/relay_service.rs index 778291fdc..a247c2cda 100644 --- a/packages/d2b-provider-device-security-key/src/relay_service.rs +++ b/packages/d2b-provider-device-security-key/src/relay_service.rs @@ -126,6 +126,7 @@ fn track_response_cid(report: &CtaphidReport, cids: &parking_lot::Mutex { + #[allow(clippy::disallowed_methods, reason = "synchronous path")] active_cids.lock().insert(packet.cid); // async-gate-allow: synchronous lock acquisition, no await while the guard is held } CtaphidPacket::Cont(packet) if packet.cid != 0 && packet.cid != CTAPHID_BROADCAST_CID => { + #[allow(clippy::disallowed_methods, reason = "synchronous path")] active_cids.lock().insert(packet.cid); // async-gate-allow: synchronous lock acquisition, no await while the guard is held } _ => {} @@ -589,6 +595,7 @@ pub(crate) async fn run_connection( let _ = guest_to_hidraw.await; } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] let cancel_cids: Vec = active_cids.lock().iter().copied().collect(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held for cid in cancel_cids { let cancel_packet = build_cancel_packet(cid); @@ -596,6 +603,7 @@ pub(crate) async fn run_connection( let _ = hidraw.write_report(&cancel_packet).await; } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] state.lock().release_lease(&vm_id, lease_id); // async-gate-allow: synchronous lock acquisition, no await while the guard is held } diff --git a/packages/d2b-provider-device-security-key/src/test_support.rs b/packages/d2b-provider-device-security-key/src/test_support.rs index 8fb5d811c..99dcc1373 100644 --- a/packages/d2b-provider-device-security-key/src/test_support.rs +++ b/packages/d2b-provider-device-security-key/src/test_support.rs @@ -29,6 +29,7 @@ pub struct RecordingEffects { impl RecordingEffects { /// The driver-effect calls so far, in invocation order. pub fn call_order(&self) -> Vec<&'static str> { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] self.calls.lock().clone() } } @@ -40,7 +41,9 @@ impl SecurityKeyDriverEffects for RecordingEffects { component: SecurityKeyComponent, _request: &SharedProviderEffectRequest<'_>, ) -> Result { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] self.reconciled.lock().push(component); // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] self.calls.lock().push("reconcile_security_key"); // async-gate-allow: test-support recorder lock Ok(SharedProviderEffectOutcome::phase( SharedProviderEffectPhase::Ready, @@ -52,6 +55,7 @@ impl SecurityKeyDriverEffects for RecordingEffects { _component: SecurityKeyComponent, _request: &SharedProviderEffectRequest<'_>, ) -> Result { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] self.calls.lock().push("finalize"); // async-gate-allow: test-support recorder lock Ok(SharedProviderFinalize::Complete) } @@ -75,6 +79,7 @@ impl SecurityKeyRuntime for RecordingRuntime { component: SecurityKeyComponent, _request: &SharedProviderEffectRequest<'_>, ) -> Result { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] self.reconciled.lock().push(component); // async-gate-allow: test-support recorder lock Ok(SharedProviderEffectOutcome::phase( SharedProviderEffectPhase::Ready, @@ -86,6 +91,7 @@ impl SecurityKeyRuntime for RecordingRuntime { component: SecurityKeyComponent, _request: &SharedProviderEffectRequest<'_>, ) -> Result { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] self.finalized.lock().push(component); // async-gate-allow: test-support recorder lock Ok(SharedProviderFinalize::Complete) } diff --git a/packages/d2b-provider-process/src/driver.rs b/packages/d2b-provider-process/src/driver.rs index 439847eea..d3b2e5c3d 100644 --- a/packages/d2b-provider-process/src/driver.rs +++ b/packages/d2b-provider-process/src/driver.rs @@ -435,7 +435,7 @@ struct RestartBudget { impl RestartBudget { fn count(&self) -> u32 { - self.count.load(Ordering::SeqCst) + self.count.load(Ordering::Relaxed) } fn allows(&self, spec: &ProcessSpec) -> bool { @@ -448,26 +448,26 @@ impl RestartBudget { /// policy backoff: the exit-driven path schedules its own backoff in the /// pass that observed the exit. fn consume_restart(&self) { - self.count.fetch_add(1, Ordering::SeqCst); + self.count.fetch_add(1, Ordering::Relaxed); } /// Record one consumed restart; the next reconcile pass schedules the /// policy backoff exactly once. fn record_restart(&self) { self.consume_restart(); - self.restart_scheduled.store(true, Ordering::SeqCst); + self.restart_scheduled.store(true, Ordering::Relaxed); } fn take_restart_scheduled(&self) -> bool { - self.restart_scheduled.swap(false, Ordering::SeqCst) + self.restart_scheduled.swap(false, Ordering::Relaxed) } fn mark_exhausted(&self) { - self.exhausted.store(true, Ordering::SeqCst); + self.exhausted.store(true, Ordering::Relaxed); } fn is_exhausted(&self) -> bool { - self.exhausted.load(Ordering::SeqCst) + self.exhausted.load(Ordering::Relaxed) } } @@ -692,7 +692,7 @@ struct EphemeralCompletion { impl EphemeralRuntime { fn started(&self) -> bool { - self.started.load(Ordering::SeqCst) + self.started.load(Ordering::Relaxed) } fn mark_started(&self) { @@ -700,7 +700,7 @@ impl EphemeralRuntime { if started_at.is_none() { *started_at = Some(tokio::time::Instant::now()); } - self.started.store(true, Ordering::SeqCst); + self.started.store(true, Ordering::Relaxed); } fn started_at(&self) -> Option { @@ -729,7 +729,7 @@ impl EphemeralRuntime { if let Some(at) = started_at.as_mut() { *at -= elapsed; } - self.started.store(true, Ordering::SeqCst); + self.started.store(true, Ordering::Relaxed); } /// Test-only: backdate the retention TTL clock. @@ -758,18 +758,18 @@ struct DurableRuntime { impl DurableRuntime { fn watching(&self) -> bool { - self.watching.load(Ordering::SeqCst) + self.watching.load(Ordering::Relaxed) } fn mark_watching(&self) { - self.watching.store(true, Ordering::SeqCst); + self.watching.store(true, Ordering::Relaxed); } /// The observed process is gone and the pass that saw the exit hands the /// relaunch back to the adoption path, so the next pass launches instead /// of probing an identity the provider has already released. fn mark_exited(&self) { - self.watching.store(false, Ordering::SeqCst); + self.watching.store(false, Ordering::Relaxed); } } @@ -3009,7 +3009,7 @@ mod tests { guest_ref: &ResourceRef, ) -> Option { self.consulted - .fetch_add(1, std::sync::atomic::Ordering::SeqCst); + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); assert_eq!(zone.as_str(), "work"); assert_eq!(guest_ref.name().as_str(), "acceptance-guest"); Some(self.uid.clone()) @@ -3030,7 +3030,7 @@ mod tests { Some(guest_uid.clone()) ); assert_eq!( - source.consulted.load(std::sync::atomic::Ordering::SeqCst), + source.consulted.load(std::sync::atomic::Ordering::Relaxed), 1 ); @@ -3045,7 +3045,7 @@ mod tests { None ); assert_eq!( - source.consulted.load(std::sync::atomic::Ordering::SeqCst), + source.consulted.load(std::sync::atomic::Ordering::Relaxed), 1, "a linked owner uid never consults the Guest plane" ); @@ -3057,7 +3057,7 @@ mod tests { None ); assert_eq!( - source.consulted.load(std::sync::atomic::Ordering::SeqCst), + source.consulted.load(std::sync::atomic::Ordering::Relaxed), 1, "a non-Guest owner never consults the Guest plane" ); diff --git a/packages/d2b-provider-toolkit/src/operations/envelope.rs b/packages/d2b-provider-toolkit/src/operations/envelope.rs index 9dd519a3b..4f6521f2c 100644 --- a/packages/d2b-provider-toolkit/src/operations/envelope.rs +++ b/packages/d2b-provider-toolkit/src/operations/envelope.rs @@ -484,7 +484,7 @@ impl OperationEnvelope { fn next_invocation_id(&self) -> String { format!( "invocation-{}", - self.invocations.fetch_add(1, Ordering::AcqRel) + self.invocations.fetch_add(1, Ordering::Relaxed) ) } diff --git a/packages/d2b-provider-transport-unix/src/portal.rs b/packages/d2b-provider-transport-unix/src/portal.rs index e24f6987e..35c078aa4 100644 --- a/packages/d2b-provider-transport-unix/src/portal.rs +++ b/packages/d2b-provider-transport-unix/src/portal.rs @@ -14,8 +14,8 @@ use std::{ collections::{HashMap, HashSet, VecDeque}, error::Error, fmt, + sync::Mutex, }; -use tokio::sync::Mutex; const MAX_OPEN_TRANSPORTS: usize = 256; diff --git a/packages/d2b-provider-volume-binding/Cargo.toml b/packages/d2b-provider-volume-binding/Cargo.toml index bf945ce78..16545f052 100644 --- a/packages/d2b-provider-volume-binding/Cargo.toml +++ b/packages/d2b-provider-volume-binding/Cargo.toml @@ -25,10 +25,6 @@ d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-boot d2b-provider-volume-virtiofs = { path = "../d2b-provider-volume-virtiofs", version = "0.0.0-bootstrap" } d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-bootstrap" } d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } -# test_support (feature/test builds) and the driver unit tests script their -# doubles over a parking_lot mutex; a normal dep so the `test-support` -# feature builds outside `cfg(test)` too. -parking_lot = "0.12" serde_json.workspace = true tokio = { workspace = true, features = ["macros", "rt-multi-thread", "sync", "time"] } tracing = "0.1" diff --git a/packages/d2b-provider-volume-binding/src/driver.rs b/packages/d2b-provider-volume-binding/src/driver.rs index 89effd5ab..988adf0b7 100644 --- a/packages/d2b-provider-volume-binding/src/driver.rs +++ b/packages/d2b-provider-volume-binding/src/driver.rs @@ -1149,9 +1149,9 @@ mod tests { #[derive(Clone)] struct RecordingManager { zone: String, - log: Arc>, - rows: Arc>>, - watch_targets: Arc>>, + log: Arc>, + rows: Arc>>, + watch_targets: Arc>>, next_uid: Arc, fail_reads: Arc, } @@ -1160,9 +1160,9 @@ mod tests { fn new() -> Self { Self { zone: "work".to_owned(), - log: Arc::new(parking_lot::Mutex::new(Vec::new())), - rows: Arc::new(parking_lot::Mutex::new(Vec::new())), - watch_targets: Arc::new(parking_lot::Mutex::new(Vec::new())), + log: Arc::new(std::sync::Mutex::new(Vec::new())), + rows: Arc::new(std::sync::Mutex::new(Vec::new())), + watch_targets: Arc::new(std::sync::Mutex::new(Vec::new())), next_uid: Arc::new(std::sync::atomic::AtomicU64::new(1)), fail_reads: Arc::new(std::sync::atomic::AtomicBool::new(false)), } @@ -1174,7 +1174,8 @@ mod tests { } fn with_parent(self, volume_uid: [u8; 16], spec: &[u8]) -> Self { - self.rows.lock().push(StoredDesiredResource { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.rows.lock().unwrap().push(StoredDesiredResource { key: ResourceKey::new("work", "Volume", "data"), uid: volume_uid, generation: 2, @@ -1190,7 +1191,8 @@ mod tests { /// Seed one owned child row (drift the driver must retire). fn seed_owned(&self, key: ResourceKey) { - self.rows.lock().push(StoredDesiredResource { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.rows.lock().unwrap().push(StoredDesiredResource { key, uid: [0x77; 16], generation: 1, @@ -1203,20 +1205,23 @@ mod tests { }); } - fn log(&self) -> Arc> { + fn log(&self) -> Arc> { Arc::clone(&self.log) } fn order(&self) -> Vec { - self.log.lock().clone() + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.log.lock().unwrap().clone() } fn rows(&self) -> Vec { - self.rows.lock().clone() + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.rows.lock().unwrap().clone() } fn watch_targets(&self) -> Vec { - self.watch_targets.lock().clone() + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.watch_targets.lock().unwrap().clone() } } @@ -1228,7 +1233,8 @@ mod tests { child: ChildEnsure, ) -> Result { let id = format!("{}/{}", child.type_name.as_str(), child.name); - self.log.lock().push(format!("ensure:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.log.lock().unwrap().push(format!("ensure:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held let next = self .next_uid .fetch_add(1, std::sync::atomic::Ordering::SeqCst); @@ -1245,7 +1251,8 @@ mod tests { metadata: child.metadata, created_at: 0, }; - let mut rows = self.rows.lock(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + let mut rows = self.rows.lock().unwrap(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held let outcome = match rows.iter_mut().find(|row| row.key == row_key(&id, &self.zone)) { Some(existing) => { if existing.spec == row.spec { @@ -1261,7 +1268,8 @@ mod tests { } }; // Spawn notification only after the commit (F1, AE1). - self.log.lock().push(format!("spawned:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.log.lock().unwrap().push(format!("spawned:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held Ok(outcome) } @@ -1272,7 +1280,8 @@ mod tests { if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } - Ok(self.rows.lock().iter().find(|row| row.key == *key).cloned()) // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + Ok(self.rows.lock().unwrap().iter().find(|row| row.key == *key).cloned()) // async-gate-allow: synchronous lock acquisition, no await while the guard is held } async fn view( @@ -1285,10 +1294,13 @@ mod tests { } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] self.log .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held + .unwrap() .push(format!("delete:{}/{}", key.type_name, key.name)); - self.rows.lock().retain(|row| row.key != *key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.rows.lock().unwrap().retain(|row| row.key != *key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held Ok(()) } @@ -1296,9 +1308,11 @@ mod tests { &self, owner_uid: [u8; 16], ) -> Result, ResourceError> { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] Ok(self .rows .lock() + .unwrap() .iter() .filter(|row| row.owner_uid.as_ref() == Some(&owner_uid)) .cloned() @@ -1312,7 +1326,8 @@ mod tests { ) -> Result { // Manager rows always exist here; the actor-side handler is the // runtime's, so the fake only records the registration. - let mut targets = self.watch_targets.lock(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + let mut targets = self.watch_targets.lock().unwrap(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held targets.push(registration.target.clone()); Ok(WatchId(targets.len() as u64)) } @@ -1325,18 +1340,19 @@ mod tests { /// Recording requeue: the driver's resync schedules are observable. #[derive(Clone)] struct RecordingRequeue { - scheduled: Arc>>, + scheduled: Arc>>, } impl RecordingRequeue { fn new() -> Self { Self { - scheduled: Arc::new(parking_lot::Mutex::new(Vec::new())), + scheduled: Arc::new(std::sync::Mutex::new(Vec::new())), } } fn scheduled(&self) -> Vec { - self.scheduled.lock().clone() + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.scheduled.lock().unwrap().clone() } } @@ -1346,7 +1362,8 @@ mod tests { key: ResourceKey, _after: std::time::Duration, ) -> d2b_resource_runtime::context::RequeueId { - let mut scheduled = self.scheduled.lock(); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + let mut scheduled = self.scheduled.lock().unwrap(); scheduled.push(key); d2b_resource_runtime::context::RequeueId(scheduled.len() as u64) } diff --git a/packages/d2b-provider-volume-binding/src/test_support.rs b/packages/d2b-provider-volume-binding/src/test_support.rs index 1e04175ee..5aab0aad3 100644 --- a/packages/d2b-provider-volume-binding/src/test_support.rs +++ b/packages/d2b-provider-volume-binding/src/test_support.rs @@ -3,11 +3,10 @@ //! Gated behind the `test-support` Cargo feature so production //! consumers never pull this in. -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use d2b_provider_volume_virtiofs::{SocketIdentity, StoredBinding}; use d2b_resource_runtime::identity::ResourceKey; -use parking_lot::Mutex; use crate::driver::BindingDriverEffects; @@ -47,7 +46,8 @@ impl FakeServingEffects { /// The ordered serving-effect log, shared with any manager logger. pub fn call_order(&self) -> Vec { - self.log.lock().clone() + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.log.lock().unwrap().clone() } /// The facet set the plane and this crate's tests build the driver and @@ -69,7 +69,8 @@ struct ScriptedReady(Arc); #[async_trait::async_trait] impl crate::facets::SocketReadySource for ScriptedReady { async fn ready(&self, _socket: &SocketIdentity) -> bool { - self.0.log.lock().push("socket-ready".to_owned()); // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.0.log.lock().unwrap().push("socket-ready".to_owned()); // async-gate-allow: test-support recorder lock self.0.ready.load(std::sync::atomic::Ordering::SeqCst) } } @@ -81,7 +82,8 @@ struct ScriptedRemove(Arc); #[async_trait::async_trait] impl crate::facets::SocketRemoveSource for ScriptedRemove { async fn remove(&self, _socket: &SocketIdentity) -> Result<(), String> { - self.0.log.lock().push("remove-socket".to_owned()); // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.0.log.lock().unwrap().push("remove-socket".to_owned()); // async-gate-allow: test-support recorder lock Ok(()) } } @@ -93,7 +95,8 @@ struct ScriptedGuestMount(Arc); #[async_trait::async_trait] impl crate::facets::GuestMountSource for ScriptedGuestMount { async fn guest_mount_ready(&self, _key: &ResourceKey) -> Result { - self.0.log.lock().push("guest-mount".to_owned()); // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.0.log.lock().unwrap().push("guest-mount".to_owned()); // async-gate-allow: test-support recorder lock Ok(self.0.mounted.load(std::sync::atomic::Ordering::SeqCst)) } } @@ -101,12 +104,14 @@ impl crate::facets::GuestMountSource for ScriptedGuestMount { #[async_trait::async_trait] impl BindingDriverEffects for FakeServingEffects { async fn socket_ready(&self, _socket: &SocketIdentity) -> bool { - self.log.lock().push("socket-ready".to_owned()); // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.log.lock().unwrap().push("socket-ready".to_owned()); // async-gate-allow: test-support recorder lock self.ready.load(std::sync::atomic::Ordering::SeqCst) } async fn remove_socket(&self, _socket: &SocketIdentity) -> Result<(), String> { - self.log.lock().push("remove-socket".to_owned()); // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.log.lock().unwrap().push("remove-socket".to_owned()); // async-gate-allow: test-support recorder lock Ok(()) } @@ -115,7 +120,8 @@ impl BindingDriverEffects for FakeServingEffects { _key: &ResourceKey, _binding: &StoredBinding, ) -> Result { - self.log.lock().push("guest-mount".to_owned()); // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.log.lock().unwrap().push("guest-mount".to_owned()); // async-gate-allow: test-support recorder lock Ok(self.mounted.load(std::sync::atomic::Ordering::SeqCst)) } } From 1200b480dcfcfd8ef1eb4b306a866a8a492113a4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:48:55 -0700 Subject: [PATCH 523/726] observability-otel: reuse the drain buffer and thread measured frame sizes --- changelog.d/w3-22-otel-perf.md | 5 +++ .../src/emitter_socket.rs | 9 ++-- .../src/ingress_policy.rs | 15 ++++++- .../src/metric_policy.rs | 42 ++++++++++++------- 4 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 changelog.d/w3-22-otel-perf.md diff --git a/changelog.d/w3-22-otel-perf.md b/changelog.d/w3-22-otel-perf.md new file mode 100644 index 000000000..5afec92b1 --- /dev/null +++ b/changelog.d/w3-22-otel-perf.md @@ -0,0 +1,5 @@ +### Changed + +- The emitter socket drain reuses one scratch buffer across datagrams instead of allocating a 64 KiB buffer per datagram. +- Metric frames are no longer re-serialized to JSON for size admission on the wire-boundary paths; the size measured at decode is threaded through, and frame admission reuses it. +- OTEL resource attribute values are scanned case-insensitively in place instead of allocating a lowercase copy per attribute. \ No newline at end of file diff --git a/packages/d2b-provider-observability-otel/src/emitter_socket.rs b/packages/d2b-provider-observability-otel/src/emitter_socket.rs index ee0242e6e..40225549d 100644 --- a/packages/d2b-provider-observability-otel/src/emitter_socket.rs +++ b/packages/d2b-provider-observability-otel/src/emitter_socket.rs @@ -143,10 +143,13 @@ impl EmitterSocket { self.prune_expired(); self.validate_bound_identity()?; let mut drained = 0; + // One extra byte lets the receiver distinguish a full-size frame + // from a datagram truncated by the bounded receive buffer. The + // scratch buffer is reused across datagrams instead of being + // reallocated on every drain iteration. + let mut bytes = vec![0_u8; MAX_COMPACT_FRAME_BYTES + 1]; while drained < MAX_DATAGRAMS_PER_DRAIN { - // One extra byte lets the receiver distinguish a full-size frame - // from a datagram truncated by the bounded receive buffer. - let mut bytes = vec![0_u8; MAX_COMPACT_FRAME_BYTES + 1]; + bytes.resize(MAX_COMPACT_FRAME_BYTES + 1, 0); match self.socket.recv(&mut bytes) { Ok(size) => { if size > MAX_COMPACT_FRAME_BYTES { diff --git a/packages/d2b-provider-observability-otel/src/ingress_policy.rs b/packages/d2b-provider-observability-otel/src/ingress_policy.rs index 11263f616..0903f64e2 100644 --- a/packages/d2b-provider-observability-otel/src/ingress_policy.rs +++ b/packages/d2b-provider-observability-otel/src/ingress_policy.rs @@ -152,7 +152,9 @@ impl core::fmt::Debug for MetricPoint { /// A bounded frame. All points are admitted or rejected together. #[derive(Clone, PartialEq)] pub struct MetricFrame { - /// Approximate encoded frame size. + /// Encoded frame size measured at the frame's decode boundary. A frame + /// built without a boundary measurement carries zero, and admission then + /// measures the canonical encoded frame instead of trusting the caller. pub encoded_bytes: usize, /// Data points. pub points: Vec, @@ -396,7 +398,16 @@ impl IngressPolicyGate { { return (IngressOutcome::Quarantined, IngressErrorClass::Malformed); } - if frame.measured_encoded_bytes() > MAX_INGRESS_FRAME_BYTES { + // The size is measured once at the frame's decode boundary + // (admit_raw/admit_parsed) and threaded through `encoded_bytes`; + // a frame built without a boundary measurement carries zero and + // is measured here so admission never trusts an unmeasured size. + let encoded_bytes = if frame.encoded_bytes == 0 { + frame.measured_encoded_bytes() + } else { + frame.encoded_bytes + }; + if encoded_bytes > MAX_INGRESS_FRAME_BYTES { return self.reject(ingress, connection_id, IngressErrorClass::Oversize); } if !valid_resource_attributes(&frame.resource_attributes) { diff --git a/packages/d2b-provider-observability-otel/src/metric_policy.rs b/packages/d2b-provider-observability-otel/src/metric_policy.rs index 407899489..c31b20226 100644 --- a/packages/d2b-provider-observability-otel/src/metric_policy.rs +++ b/packages/d2b-provider-observability-otel/src/metric_policy.rs @@ -47,16 +47,28 @@ pub fn validate_resource_attributes( Ok(()) } +/// Case-insensitive ASCII substring scan over a value already bounded to +/// [`MAX_RESOURCE_ATTRIBUTE_BYTES`]. +fn contains_ignore_ascii_case(value: &str, word: &str) -> bool { + let word = word.as_bytes(); + value + .as_bytes() + .windows(word.len()) + .any(|window| window.eq_ignore_ascii_case(word)) +} + fn valid_resource_attribute_value(key: &str, value: &str) -> bool { - let lowered = value.to_ascii_lowercase(); - if lowered.contains("secret") - || lowered.contains("credential") - || lowered.contains("token") - || lowered.contains("password") - || lowered.contains("privatekey") - || lowered.contains("bearer ") - { - return false; + for word in [ + "secret", + "credential", + "token", + "password", + "privatekey", + "bearer ", + ] { + if contains_ignore_ascii_case(value, word) { + return false; + } } let identity_key = matches!( key, @@ -150,16 +162,16 @@ mod tests { ("service.version".to_owned(), "0.0.0".to_owned()), ]); assert!(validate_resource_attributes(&attributes).is_ok()); - assert!( - validate_resource_attributes(&BTreeMap::from([("zone".to_owned(), "work".to_owned())])) - .is_err() + assert_eq!( + validate_resource_attributes(&BTreeMap::from([("zone".to_owned(), "work".to_owned())])), + Err(ResourceAttributeError::NotAllowlisted) ); - assert!( + assert_eq!( validate_resource_attributes(&BTreeMap::from([( "source".to_owned(), "credential-canary".to_owned() - )])) - .is_err() + )])), + Err(ResourceAttributeError::Invalid) ); } } From d38e32fc6b11341bcb5a91f8b182179f1ac4d09c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:49:47 -0700 Subject: [PATCH 524/726] d2b-session: replace admit_try macro and spin-cap test wait --- changelog.d/w3-31-session-macro-test.md | 4 ++ packages/d2b-session/src/admission.rs | 51 ++++++++++++------------ packages/d2b-session/tests/admission.rs | 52 +++++++++++++------------ 3 files changed, 57 insertions(+), 50 deletions(-) create mode 100644 changelog.d/w3-31-session-macro-test.md diff --git a/changelog.d/w3-31-session-macro-test.md b/changelog.d/w3-31-session-macro-test.md new file mode 100644 index 000000000..ef83c6431 --- /dev/null +++ b/changelog.d/w3-31-session-macro-test.md @@ -0,0 +1,4 @@ +### Changed + +- Session admission records rejected connect attempts through a shared helper instead of a local macro; metric behavior is unchanged. +- The session admission test for unpolled cancellation now waits on a transport notification instead of spinning up to 64 scheduler yields, so the reclaim assertion cannot time out under load. \ No newline at end of file diff --git a/packages/d2b-session/src/admission.rs b/packages/d2b-session/src/admission.rs index 3d29588f1..a9d6cf13b 100644 --- a/packages/d2b-session/src/admission.rs +++ b/packages/d2b-session/src/admission.rs @@ -622,30 +622,14 @@ impl SessionAcceptor { T: OwnedTransport + 'static, { engine.set_metrics(Arc::clone(&self.metrics)); - macro_rules! admit_try { - ($expression:expr) => { - match $expression { - Ok(value) => value, - Err(error) => { - engine.record_failure( - MetricEvent::ConnectAttempt, - ChannelClass::SessionControl, - OperationClass::Connect, - error, - ); - return Err(error); - } - } - }; - } - let authentication = admit_try!(engine.take_authentication(&self.policy)); - let binding = admit_try!(authentication_binding(&self.policy, authentication)); - admit_try!(validate_transport_evidence( - &self.policy, - &binding, - &evidence - )); - admit_try!(validate_bootstrap_zone(&binding, &self.expected_zone)); + let result = engine.take_authentication(&self.policy); + let authentication = admit_or_record(&mut engine, result)?; + let result = authentication_binding(&self.policy, authentication); + let binding = admit_or_record(&mut engine, result)?; + let result = validate_transport_evidence(&self.policy, &binding, &evidence); + admit_or_record(&mut engine, result)?; + let result = validate_bootstrap_zone(&binding, &self.expected_zone); + admit_or_record(&mut engine, result)?; let (subject, lease) = self .authority .authenticate_connect(evidence, &binding, &self.expected_zone, now_tick) @@ -658,7 +642,8 @@ impl SessionAcceptor { *error, ); })?; - admit_try!(validate_subject(&subject, &self.expected_zone, &binding)); + let result = validate_subject(&subject, &self.expected_zone, &binding); + admit_or_record(&mut engine, result)?; if !lease.is_valid_at(now_tick) { let error = SessionError::new(SessionErrorCode::PolicyDenied); engine.record_failure( @@ -696,6 +681,22 @@ impl SessionAcceptor { } } +/// Record a rejected connect attempt before returning the error unchanged. +fn admit_or_record(engine: &mut SessionEngine, result: Result) -> Result +where + T: OwnedTransport, +{ + result.map_err(|error| { + engine.record_failure( + MetricEvent::ConnectAttempt, + ChannelClass::SessionControl, + OperationClass::Connect, + error, + ); + error + }) +} + impl fmt::Debug for SessionAcceptor { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("SessionAcceptor()") diff --git a/packages/d2b-session/tests/admission.rs b/packages/d2b-session/tests/admission.rs index 2b9d3a62a..072836860 100644 --- a/packages/d2b-session/tests/admission.rs +++ b/packages/d2b-session/tests/admission.rs @@ -47,7 +47,7 @@ impl SessionRegistrationCapability<()> for TestRegistrationCapability { async fn unpolled_cancellation_on_real_driver_reclaims_request_for_reuse() { let zone = ZoneId::parse("work").unwrap(); let policy = single_request_policy(); - let (initiator, responder) = engine_pair(&policy).await; + let (initiator, responder, send_failure) = engine_pair_with_failure(&policy).await; let admitted = session_acceptor( policy, zone.clone(), @@ -71,31 +71,28 @@ async fn unpolled_cancellation_on_real_driver_reclaims_request_for_reuse() { ) .await .unwrap(); + // The first request's frame write already notified `sent`; consume that + // notification so the wait below observes only the cancellation frame. + send_failure.sent.notified().await; drop(session.cancellation_handle().cancel(request_id.clone())); - let mut reused = false; - for _ in 0..64 { - match ttrpc - .start( - invoke_permit(&mut session, &zone).await, - replacement_id.clone(), - b"replacement".to_vec(), - ttrpc.attempt_guard(), - 2, - ) - .await - { - Ok(()) => { - reused = true; - break; - } - Err(error) if error.code() == SessionErrorCode::QueueBackpressure => { - tokio::task::yield_now().await; - } - Err(error) => panic!("replacement request failed unexpectedly: {error}"), - } - } - assert!(reused, "unpolled cancellation did not reclaim the request"); + tokio::time::timeout( + std::time::Duration::from_secs(1), + send_failure.sent.notified(), + ) + .await + .expect("unpolled cancellation did not reclaim the request"); + + ttrpc + .start( + invoke_permit(&mut session, &zone).await, + replacement_id.clone(), + b"replacement".to_vec(), + ttrpc.attempt_guard(), + 2, + ) + .await + .expect("replacement request failed after the cancellation was delivered"); assert!(ttrpc.complete(replacement_id).await.unwrap()); } @@ -269,6 +266,9 @@ struct SendFailure { enabled: AtomicBool, entered: Notify, release: Notify, + /// Notified once for every frame the session writer delivers, so tests + /// can observe cancellation delivery without spinning. + sent: Notify, } impl SendFailure { @@ -365,7 +365,9 @@ impl d2b_session::TransportWriter for TestTransportWriter { self.sender .send(packet) .await - .map_err(|_| TransportError::Disconnected) + .map_err(|_| TransportError::Disconnected)?; + self.send_failure.sent.notify_one(); + Ok(()) } async fn close(&mut self) -> Result<(), TransportError> { From 3886cfd7b9c2cb1544e155b4effec89a884aab48 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:52:32 -0700 Subject: [PATCH 525/726] fixture-syscall-surface: declare rcx and r11 clobbers on the syscall asm The x86_64 syscall instruction overwrites rcx and r11, but the asm! operands only listed rdi and rax, so the compiler assumed those registers survive. Declare them as late outputs so the register assumptions hold if the fixture function is ever executed. --- changelog.d/w3-48-fixture-syscall-asm.md | 6 ++++++ packages/d2b-broker-fixture-syscall-surface/src/lib.rs | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 changelog.d/w3-48-fixture-syscall-asm.md diff --git a/changelog.d/w3-48-fixture-syscall-asm.md b/changelog.d/w3-48-fixture-syscall-asm.md new file mode 100644 index 000000000..89f36a887 --- /dev/null +++ b/changelog.d/w3-48-fixture-syscall-asm.md @@ -0,0 +1,6 @@ +### Fixed + +- The `d2b-broker-fixture-syscall-surface` fixture's x86_64 `asm!` syscall + surface now declares the registers the `syscall` instruction clobbers + (`rcx` and `r11`), so the compiler's register assumptions hold if the + fixture function is ever executed. \ No newline at end of file diff --git a/packages/d2b-broker-fixture-syscall-surface/src/lib.rs b/packages/d2b-broker-fixture-syscall-surface/src/lib.rs index ae74eacb3..85ed7a01f 100644 --- a/packages/d2b-broker-fixture-syscall-surface/src/lib.rs +++ b/packages/d2b-broker-fixture-syscall-surface/src/lib.rs @@ -28,6 +28,8 @@ pub fn raw_syscall_close(fd: i32) -> i32 { "syscall", in("rdi") fd as i64, out("rax") status, + lateout("rcx") _, + lateout("r11") _, options(nostack), ); } From 52f5ef660589b366c469532230822eb8f4e4d944 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:53:19 -0700 Subject: [PATCH 526/726] d2b: cover completed-operation reconcile replay in azure container apps tests --- .../w3-44-azure-container-apps-tests.md | 4 ++++ .../tests/provider_lifecycle.rs | 24 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w3-44-azure-container-apps-tests.md diff --git a/changelog.d/w3-44-azure-container-apps-tests.md b/changelog.d/w3-44-azure-container-apps-tests.md new file mode 100644 index 000000000..f40829d1e --- /dev/null +++ b/changelog.d/w3-44-azure-container-apps-tests.md @@ -0,0 +1,4 @@ +### Changed + +- Locked in the Azure Container Apps guest provider contract that a reconcile retried with a previously completed operation id returns `Converged` without re-running control-plane effects: a regression test reconciles twice with the same id against a running sandbox and asserts the second pass makes no effect or credential-lease calls. +- Dropped a dead `ResourceRef` parse from the `stable_error_codes_are_bounded` test that asserted nothing the test name promises and duplicated parse coverage exercised elsewhere. \ No newline at end of file diff --git a/packages/d2b-provider-guest-azure-container-apps/tests/provider_lifecycle.rs b/packages/d2b-provider-guest-azure-container-apps/tests/provider_lifecycle.rs index fcf3be06b..25439a66c 100644 --- a/packages/d2b-provider-guest-azure-container-apps/tests/provider_lifecycle.rs +++ b/packages/d2b-provider-guest-azure-container-apps/tests/provider_lifecycle.rs @@ -224,6 +224,29 @@ async fn running_sandbox_reaches_ready_without_exposing_identity() { assert_eq!(state.lock().await.revoked, 2); } +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] +#[tokio::test] +async fn completed_operation_reconcile_replays_without_effects() { + let state = Arc::new(Mutex::new(FakeState { + candidates: vec![record(AcaSandboxLifecycle::Running)], + ..FakeState::default() + })); + let mut controller = controller(Arc::clone(&state)).with_clock(Arc::new(FixedClock(0))); + let operation = AcaOperationId::parse("operation-replay").unwrap(); + assert_eq!( + controller.reconcile(operation.clone(), 1_000).await.unwrap(), + AcaReconcileOutcome::Converged + ); + let calls = state.lock().await.calls.clone(); + let revoked = state.lock().await.revoked; + assert_eq!( + controller.reconcile(operation, 1_000).await.unwrap(), + AcaReconcileOutcome::Converged + ); + assert_eq!(state.lock().await.calls, calls); + assert_eq!(state.lock().await.revoked, revoked); +} + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn running_sandbox_requires_authenticated_healthy_control() { @@ -533,5 +556,4 @@ fn stable_error_codes_are_bounded() { AcaControlError::new(AcaControlErrorKind::RateLimited).code(), "aca-control-rate-limited" ); - let _ = ResourceRef::parse("Guest/gateway").unwrap(); } From a4dd46ddc467842b0d9952accc76e3a225352628 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:53:34 -0700 Subject: [PATCH 527/726] test: add saturation boundary and mutation-context assertions to w3 provider tests --- changelog.d/w3-46-provider-test-b.md | 9 ++++++++ .../tests/authority.rs | 10 ++++++++ .../tests/mediator.rs | 2 ++ .../tests/conformance.rs | 8 +++++-- .../tests/topology.rs | 23 +++++++++++++------ 5 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 changelog.d/w3-46-provider-test-b.md diff --git a/changelog.d/w3-46-provider-test-b.md b/changelog.d/w3-46-provider-test-b.md new file mode 100644 index 000000000..15869258c --- /dev/null +++ b/changelog.d/w3-46-provider-test-b.md @@ -0,0 +1,9 @@ +### Fixed + +- The audio pipewire provider's authority tests now assert the saturated mix + level is capped at 100 even when bounded consumer levels sum past the cap, + and the mediator tests assert a failed projection set leaves the grant and + level unchanged. +- The managed-identity provider conformance and topology tests now report + which method, binding, or permission variant failed instead of sharing a + bare line number. diff --git a/packages/d2b-provider-audio-pipewire/tests/authority.rs b/packages/d2b-provider-audio-pipewire/tests/authority.rs index d4357583b..81b53ba2b 100644 --- a/packages/d2b-provider-audio-pipewire/tests/authority.rs +++ b/packages/d2b-provider-audio-pipewire/tests/authority.rs @@ -32,3 +32,13 @@ fn speaker_mixer_keeps_grants_independent() { mixer.set_level(AudioLeaseId::new(2), 20).unwrap(); assert_eq!(mixer.mix_level(), 100); } + +#[test] +fn speaker_mixer_mix_level_is_capped_at_100() { + let mut mixer = SpeakerMixer::new(NonZeroUsize::new(3).unwrap()); + mixer.set_level(AudioLeaseId::new(1), 80).unwrap(); + mixer.set_level(AudioLeaseId::new(2), 80).unwrap(); + assert_eq!(mixer.mix_level(), 100); + mixer.set_level(AudioLeaseId::new(3), 60).unwrap(); + assert_eq!(mixer.mix_level(), 100); +} diff --git a/packages/d2b-provider-audio-pipewire/tests/mediator.rs b/packages/d2b-provider-audio-pipewire/tests/mediator.rs index 356b8c402..e9e47faa8 100644 --- a/packages/d2b-provider-audio-pipewire/tests/mediator.rs +++ b/packages/d2b-provider-audio-pipewire/tests/mediator.rs @@ -22,4 +22,6 @@ fn projection_cannot_open_pipewire_and_failed_set_preserves_state() { Err(AudioMediatorError::ProjectionCannotOpenPipewire) ); assert_eq!(mediator.readiness(), AudioReadiness::Unavailable); + assert_eq!(mediator.grant(), AudioGrant::Off); + assert_eq!(mediator.level(), None); } diff --git a/packages/d2b-provider-credential-managed-identity/tests/conformance.rs b/packages/d2b-provider-credential-managed-identity/tests/conformance.rs index 9c6a1119e..d6171c086 100644 --- a/packages/d2b-provider-credential-managed-identity/tests/conformance.rs +++ b/packages/d2b-provider-credential-managed-identity/tests/conformance.rs @@ -74,14 +74,18 @@ fn exact_role_subresource_matrix_is_closed() { ] { let permission = RolePermission::new(CredentialResourceVerb::UseCredential, method.subresource()); - assert!(authorize_operation(method, &[method.operation_class()], &permission).is_ok()); + assert!( + authorize_operation(method, &[method.operation_class()], &permission).is_ok(), + "method: {method:?}" + ); assert!( authorize_operation( method, &[method.operation_class()], &RolePermission::new(CredentialResourceVerb::UseCredential, "*"), ) - .is_err() + .is_err(), + "method: {method:?}" ); } } diff --git a/packages/d2b-provider-credential-managed-identity/tests/topology.rs b/packages/d2b-provider-credential-managed-identity/tests/topology.rs index 7ba0052eb..51f78d721 100644 --- a/packages/d2b-provider-credential-managed-identity/tests/topology.rs +++ b/packages/d2b-provider-credential-managed-identity/tests/topology.rs @@ -30,12 +30,20 @@ fn admitted_ready_credentials_spawn_a_co_located_agent_without_egress() { ) .unwrap() .unwrap(); - assert_eq!(agent.binary(), AGENT_BINARY); - assert_eq!(agent.owner_ref().resource_type().as_str(), "Credential"); - assert_eq!(agent.execution_ref().to_canonical_string(), execution); - assert_eq!(agent.placement(), binding); - assert!(!agent.allow_egress()); - assert!(agent.requires_effect_port_client()); + assert_eq!(agent.binary(), AGENT_BINARY, "binding: {binding:?}"); + assert_eq!( + agent.owner_ref().resource_type().as_str(), + "Credential", + "binding: {binding:?}" + ); + assert_eq!( + agent.execution_ref().to_canonical_string(), + execution, + "binding: {binding:?}" + ); + assert_eq!(agent.placement(), binding, "binding: {binding:?}"); + assert!(!agent.allow_egress(), "binding: {binding:?}"); + assert!(agent.requires_effect_port_client(), "binding: {binding:?}"); } } @@ -67,7 +75,8 @@ fn live_methods_route_to_the_agent_and_stored_inspection_stays_secret_free() { ] { assert_eq!( ManagedIdentityController::route(method, true), - ManagedIdentityRoute::Agent + ManagedIdentityRoute::Agent, + "method: {method:?}" ); } assert_eq!( From 840c1edbead52af6389011f1d67b853d201f563e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 13:54:09 -0700 Subject: [PATCH 528/726] d2b-unsafe-local-helper: relax admission counter, extract identity decision - protocol: active counter only bounds the worker pool and publishes nothing; responses carry their own synchronization over the channel, so AcqRel was pure overhead. Drop to Ordering::Relaxed (RS-0831). - runtime: extract ScopeInspection::observable_state() (the snapshot identity-match -> Degraded decision) into a testable method and have snapshot use it; re-point the adoption test at that extracted behavior so a regression that stops reporting Degraded for a mismatched scope is caught (RS-0922). --- changelog.d/w3-35-unsafe-local-helper-conc.md | 4 ++ .../d2b-unsafe-local-helper/src/protocol.rs | 6 +-- .../d2b-unsafe-local-helper/src/runtime.rs | 38 ++++++++++++------- 3 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 changelog.d/w3-35-unsafe-local-helper-conc.md diff --git a/changelog.d/w3-35-unsafe-local-helper-conc.md b/changelog.d/w3-35-unsafe-local-helper-conc.md new file mode 100644 index 000000000..a3473b8ce --- /dev/null +++ b/changelog.d/w3-35-unsafe-local-helper-conc.md @@ -0,0 +1,4 @@ +### Fixed + +- The d2b-unsafe-local-helper admission counter now uses relaxed atomics: it only bounds the worker pool, and responses carry their own synchronization, so the stronger ordering was pure overhead. +- The helper snapshot test now asserts the extracted identity-mismatch decision instead of re-deriving it, so a regression that makes mismatched scopes report a live state instead of Degraded is caught. \ No newline at end of file diff --git a/packages/d2b-unsafe-local-helper/src/protocol.rs b/packages/d2b-unsafe-local-helper/src/protocol.rs index 124d4be65..da1e4a151 100644 --- a/packages/d2b-unsafe-local-helper/src/protocol.rs +++ b/packages/d2b-unsafe-local-helper/src/protocol.rs @@ -163,8 +163,8 @@ impl HelperClient { send_frame(&socket, &rejected)?; continue; } - if active.fetch_add(1, Ordering::AcqRel) >= MAX_HELPER_QUEUE_DEPTH { - active.fetch_sub(1, Ordering::AcqRel); + if active.fetch_add(1, Ordering::Relaxed) >= MAX_HELPER_QUEUE_DEPTH { + active.fetch_sub(1, Ordering::Relaxed); let rejected = rejection( request.request_id, request.operation_id, @@ -197,7 +197,7 @@ impl HelperClient { if responses.send(response).is_ok() { let _ = wake_response_loop(&response_wakeup); } - active.fetch_sub(1, Ordering::AcqRel); + active.fetch_sub(1, Ordering::Relaxed); }) .map_err(|_| ProtocolError::RuntimeUnavailable)?; } diff --git a/packages/d2b-unsafe-local-helper/src/runtime.rs b/packages/d2b-unsafe-local-helper/src/runtime.rs index 409c9329b..6614ad9ea 100644 --- a/packages/d2b-unsafe-local-helper/src/runtime.rs +++ b/packages/d2b-unsafe-local-helper/src/runtime.rs @@ -258,6 +258,20 @@ impl fmt::Debug for ScopeRuntime { } } +impl ScopeInspection { + /// The state a snapshot reports for this inspection: the inspected state + /// only when the identity matches, otherwise [`HelperScopeState::Degraded`]. + fn observable_state(&self) -> HelperScopeState { + match self { + ScopeInspection { + state, + identity_matches: true, + } => *state, + _ => HelperScopeState::Degraded, + } + } +} + impl ScopeRuntime { pub fn new(manager: M, wayland_proxy_binary: PathBuf) -> Result { let uid = get_current_uid(); @@ -500,11 +514,8 @@ impl ScopeRuntime { } else { let verified = entry.verified(); match self.manager.inspect_scope(&verified) { - Ok(ScopeInspection { - state, - identity_matches: true, - }) => state, - _ => HelperScopeState::Degraded, + Ok(inspection) => inspection.observable_state(), + Err(_) => HelperScopeState::Degraded, } }; let scope = entry.verified().wire_identity(); @@ -1563,18 +1574,19 @@ mod tests { #[test] fn adoption_degrades_identity_ambiguity_without_stopping_scope() { - let inspection = ScopeInspection { + let mismatched = ScopeInspection { state: HelperScopeState::Active, identity_matches: false, }; - let state = match inspection { - ScopeInspection { - state, - identity_matches: true, - } => state, - _ => HelperScopeState::Degraded, + assert_eq!( + mismatched.observable_state(), + HelperScopeState::Degraded + ); + let matched = ScopeInspection { + state: HelperScopeState::Starting, + identity_matches: true, }; - assert_eq!(state, HelperScopeState::Degraded); + assert_eq!(matched.observable_state(), HelperScopeState::Starting); } #[test] From b373f7624d5c87cde95070c4fec2c1748afc4b51 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:01:01 -0700 Subject: [PATCH 529/726] usbip: pin claim/source wire shapes and landlord ceiling tests Declared round-trip payloads now use the real snake_case wire fields (firewallRef/bindRef were never the wire name, so the earlier test shape would let kebab/camel drift ship). Add table-driven unit tests for the arbitrator ceiling, arbitration mode, idempotent re-claim, and release paths, plus serde round-trips for the declare/explicit event sources. Drop the tautological conformance assert that compared a value to its identical literal. --- changelog.d/w3-43-usbip-tests.md | 7 ++ .../src/arbitration.rs | 109 ++++++++++++++++++ .../src/reconcile_state.rs | 57 +++++++++ .../src/state_machine.rs | 23 ++++ .../tests/conformance.rs | 4 - 5 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 changelog.d/w3-43-usbip-tests.md diff --git a/changelog.d/w3-43-usbip-tests.md b/changelog.d/w3-43-usbip-tests.md new file mode 100644 index 000000000..ce7d0bc81 --- /dev/null +++ b/changelog.d/w3-43-usbip-tests.md @@ -0,0 +1,7 @@ +### Changed + +- The USBIP provider test suite now covers the device-claim arbiter's ceiling, + arbitration-mode, re-claim, and release paths, and pins the wire shape of the + USB event source, reconcile context, public degraded reason, and claim source + payloads, so kebab-case/camelCase wire drift fails the build instead of + shipping silently. \ No newline at end of file diff --git a/packages/d2b-provider-device-usbip/src/arbitration.rs b/packages/d2b-provider-device-usbip/src/arbitration.rs index 721ed1b24..1e91e0de9 100644 --- a/packages/d2b-provider-device-usbip/src/arbitration.rs +++ b/packages/d2b-provider-device-usbip/src/arbitration.rs @@ -147,3 +147,112 @@ impl fmt::Debug for UsbipArbitrator { .finish() } } + +#[cfg(test)] +mod tests { + use super::*; + + fn uid(value: &str) -> ResourceUid { + ResourceUid::parse(value).unwrap() + } + + fn backing() -> PhysicalUsbBackingToken { + PhysicalUsbBackingToken::from_core([7; 32]) + } + + #[test] + fn constructor_rejects_ceilings_outside_one_to_sixteen() { + let rejected = [ + (DeviceArbitration::Shared, 0u32), + (DeviceArbitration::Shared, 17), + (DeviceArbitration::Exclusive, 0), + (DeviceArbitration::Exclusive, 2), + ]; + for (arbitration, max_claims) in rejected { + assert_eq!( + UsbipArbitrator::new(arbitration, max_claims, backing()).unwrap_err(), + UsbipClaimError::ArbitrationViolation, + "ceiling {max_claims} under {arbitration:?} must be rejected", + ); + } + for (arbitration, max_claims) in [ + (DeviceArbitration::Shared, 1u32), + (DeviceArbitration::Shared, 16), + (DeviceArbitration::Exclusive, 1), + ] { + assert!( + UsbipArbitrator::new(arbitration, max_claims, backing()).is_ok(), + "ceiling {max_claims} under {arbitration:?} must be accepted", + ); + } + } + + #[test] + fn claim_paths_follow_the_arbitration_mode_and_ceiling() { + let table = [ + ( + DeviceArbitration::Exclusive, + 1u32, + Ok(()), + Err(UsbipClaimError::ClaimConflict), + Err(UsbipClaimError::ClaimConflict), + ), + ( + DeviceArbitration::Shared, + 1u32, + Ok(()), + Err(UsbipClaimError::MaxClaimsExceeded), + Err(UsbipClaimError::MaxClaimsExceeded), + ), + ( + DeviceArbitration::Shared, + 2u32, + Ok(()), + Ok(()), + Err(UsbipClaimError::MaxClaimsExceeded), + ), + ]; + for (arbitration, ceiling, first, second, third) in table { + let mut arbiter = UsbipArbitrator::new(arbitration, ceiling, backing()).unwrap(); + assert_eq!(arbiter.claim(uid("123e4567-e89b-42d3-a456-426614174000"), backing()), first); + assert_eq!(arbiter.claim(uid("223e4567-e89b-42d3-a456-426614174001"), backing()), second); + assert_eq!(arbiter.claim(uid("323e4567-e89b-42d3-a456-426614174002"), backing()), third); + } + } + + #[test] + fn same_holder_reclaim_is_idempotent() { + let mut arbiter = UsbipArbitrator::new(DeviceArbitration::Shared, 2, backing()).unwrap(); + let holder = uid("123e4567-e89b-42d3-a456-426614174000"); + assert_eq!(arbiter.claim(holder.clone(), backing()), Ok(())); + assert_eq!(arbiter.claim(holder, backing()), Ok(())); + assert_eq!(arbiter.claim_count(), 1); + } + + #[test] + fn release_removes_exactly_the_named_claimant_and_frees_the_slot() { + let mut arbiter = UsbipArbitrator::new(DeviceArbitration::Shared, 2, backing()).unwrap(); + let first = uid("123e4567-e89b-42d3-a456-426614174000"); + let second = uid("223e4567-e89b-42d3-a456-426614174001"); + arbiter.claim(first.clone(), backing()).unwrap(); + arbiter.claim(second.clone(), backing()).unwrap(); + assert!(arbiter.release(&first)); + assert_eq!(arbiter.claim_count(), 1); + assert!(!arbiter.release(&first)); + assert_eq!(arbiter.claim(first, backing()), Ok(())); + assert_eq!(arbiter.claim_count(), 2); + } + + #[test] + fn claim_rejects_a_mismatched_backing_token() { + let mut arbiter = UsbipArbitrator::new(DeviceArbitration::Shared, 1, backing()).unwrap(); + assert_eq!( + arbiter.claim( + uid("123e4567-e89b-42d3-a456-426614174000"), + PhysicalUsbBackingToken::from_core([9; 32]), + ), + Err(UsbipClaimError::PhysicalBackingConflict) + ); + assert_eq!(arbiter.claim_count(), 0); + } +} diff --git a/packages/d2b-provider-device-usbip/src/reconcile_state.rs b/packages/d2b-provider-device-usbip/src/reconcile_state.rs index 3e1f86178..67125cabe 100644 --- a/packages/d2b-provider-device-usbip/src/reconcile_state.rs +++ b/packages/d2b-provider-device-usbip/src/reconcile_state.rs @@ -502,3 +502,60 @@ pub struct UsbipPublicDegradedReason { /// Bounded remediation guidance. pub remediation: String, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn event_source_round_trips_a_vm_source_payload() { + let payload = r#"{"kind":"vm","vm":"workload-a"}"#; + let source: UsbipEventSource = serde_json::from_str(payload).unwrap(); + assert_eq!(source, UsbipEventSource::vm("workload-a")); + assert_eq!(serde_json::to_string(&source).unwrap(), payload); + } + + #[test] + fn event_source_round_trips_a_component_source_payload_without_vm() { + let payload = r#"{"kind":"host"}"#; + let source: UsbipEventSource = serde_json::from_str(payload).unwrap(); + assert_eq!(source, UsbipEventSource::component(UsbipEventSourceKind::Host)); + assert_eq!(serde_json::to_string(&source).unwrap(), payload); + } + + #[test] + fn reconcile_attempt_context_round_trips_a_correlation_id_payload() { + let payload = r#"{"correlationId":"reconcile-2026-09-25-01"}"#; + let context: UsbipReconcileAttemptContext = serde_json::from_str(payload).unwrap(); + assert_eq!( + context, + UsbipReconcileAttemptContext { + correlation_id: UsbipReconcileCorrelationId::new("reconcile-2026-09-25-01").unwrap(), + } + ); + assert_eq!(serde_json::to_string(&context).unwrap(), payload); + } + + #[test] + fn public_degraded_reason_round_trips_a_policy_failure_payload() { + let payload = r#"{"code":"policy-failed","policyFailure":"feature-disabled","summary":"USB policy does not allow this claim","remediation":"fix the USBIP declaration or caller authorization, rebuild the bundle, and retry the USB lifecycle verb"}"#; + let reason: UsbipPublicDegradedReason = serde_json::from_str(payload).unwrap(); + assert_eq!( + reason, + UsbipDegradedReason::PolicyFailed(UsbipPolicyFailure::FeatureDisabled) + .to_public_reason() + ); + assert_eq!(serde_json::to_string(&reason).unwrap(), payload); + } + + #[test] + fn public_degraded_reason_round_trips_a_non_policy_payload_without_policy_failure() { + let payload = r#"{"code":"probe-incomplete","summary":"USB probing did not produce a reconciliation-safe identity","remediation":"retry the USB probe; if it repeats, verify the declaration has a stable physical selector"}"#; + let reason: UsbipPublicDegradedReason = serde_json::from_str(payload).unwrap(); + assert_eq!( + reason, + UsbipDegradedReason::ProbeIncomplete.to_public_reason() + ); + assert_eq!(serde_json::to_string(&reason).unwrap(), payload); + } +} diff --git a/packages/d2b-provider-device-usbip/src/state_machine.rs b/packages/d2b-provider-device-usbip/src/state_machine.rs index 0469c6420..38da27295 100644 --- a/packages/d2b-provider-device-usbip/src/state_machine.rs +++ b/packages/d2b-provider-device-usbip/src/state_machine.rs @@ -852,4 +852,27 @@ mod tests { assert_eq!(exec.calls, CANONICAL_STEPS.to_vec()); assert!(report.failed.is_none()); } + + #[test] + fn claim_source_round_trips_a_declared_payload() { + let payload = + r#"{"source":"declared","firewall_ref":"usbip-fw-work-yk-1-2","bind_ref":"usbip-bind-work-yk-1-2"}"#; + let source: UsbipClaimSource = serde_json::from_str(payload).unwrap(); + assert_eq!( + source, + UsbipClaimSource::Declared { + firewall_ref: "usbip-fw-work-yk-1-2".to_owned(), + bind_ref: "usbip-bind-work-yk-1-2".to_owned(), + } + ); + assert_eq!(serde_json::to_string(&source).unwrap(), payload); + } + + #[test] + fn claim_source_round_trips_an_explicit_payload() { + let payload = r#"{"source":"explicit"}"#; + let source: UsbipClaimSource = serde_json::from_str(payload).unwrap(); + assert_eq!(source, UsbipClaimSource::Explicit); + assert_eq!(serde_json::to_string(&source).unwrap(), payload); + } } diff --git a/packages/d2b-provider-device-usbip/tests/conformance.rs b/packages/d2b-provider-device-usbip/tests/conformance.rs index d08f85ef9..b8aaf9689 100644 --- a/packages/d2b-provider-device-usbip/tests/conformance.rs +++ b/packages/d2b-provider-device-usbip/tests/conformance.rs @@ -60,10 +60,6 @@ fn only_long_lived_workers_are_process_declarations() { assert_eq!(backend.placement(), "host"); assert_eq!(proxy.placement(), "guest"); - assert_eq!( - AttachmentCommand::Attach(AttachmentActivation::Declared), - AttachmentCommand::Attach(AttachmentActivation::Declared) - ); assert_ne!( AttachmentCommand::Attach(AttachmentActivation::Explicit), AttachmentCommand::Detach From a094121e5c1538c39393a9233ed01b5cbd87f46a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:02:15 -0700 Subject: [PATCH 530/726] sk-frontend: test the byte-exact UHID event parse side Extract parse_event() from read_event() so the event-type dispatch, the OUTPUT size field at payload offset 4096, the GET_REPORT id, the lifecycle mapping, and the short-header error are table-tested against hand-built buffers, and add a build_get_report_reply_error layout test. The builders had 12 byte-exact tests while the parse offsets had none, so a regression there passed the suite. --- changelog.d/w3-33-sk-frontend-uhid.md | 8 ++ packages/d2b-sk-frontend/src/uhid.rs | 180 +++++++++++++++++++++----- 2 files changed, 155 insertions(+), 33 deletions(-) create mode 100644 changelog.d/w3-33-sk-frontend-uhid.md diff --git a/changelog.d/w3-33-sk-frontend-uhid.md b/changelog.d/w3-33-sk-frontend-uhid.md new file mode 100644 index 000000000..b5c800253 --- /dev/null +++ b/changelog.d/w3-33-sk-frontend-uhid.md @@ -0,0 +1,8 @@ +# `w3-33-sk-frontend-uhid.md` + +### Changed + +- d2b-sk-frontend: extract UHID event parsing into a testable `parse_event` + and cover the byte-exact dispatch (output size field at payload offset + 4096, GET_REPORT id, lifecycle mapping, short-header error) with table + tests, so a regression in the parse offsets fails the suite. \ No newline at end of file diff --git a/packages/d2b-sk-frontend/src/uhid.rs b/packages/d2b-sk-frontend/src/uhid.rs index 7c21c96eb..7e13ba4db 100644 --- a/packages/d2b-sk-frontend/src/uhid.rs +++ b/packages/d2b-sk-frontend/src/uhid.rs @@ -47,6 +47,8 @@ const UHID_OPEN: u32 = 4; const UHID_CLOSE: u32 = 5; /// Kernel requests a GET_REPORT from the device. const UHID_GET_REPORT: u32 = 9; +/// Reply to a GET_REPORT request (UHID_GET_REPORT_REPLY). +const UHID_GET_REPORT_REPLY: u32 = 10; /// Fixed size of a CTAPHID HID report (input or output). pub const CTAPHID_REPORT_LEN: usize = 64; @@ -175,37 +177,7 @@ impl UhidDevice { pub async fn read_event(&mut self) -> io::Result> { let mut buf = [0u8; UHID_EVENT_SIZE]; let n = self.read_nonblocking(&mut buf).await?; - if n == 0 { - return Ok(None); - } - if n < 4 { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - format!("short uhid event header: {n} bytes"), - )); - } - let event_type = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]); - let payload = &buf[4..]; - let event = match event_type { - UHID_OUTPUT => { - // uhid_output_req layout (packed): - // data[4096], size(__u16), rtype(__u8) - let size = u16::from_le_bytes([payload[4096], payload[4097]]) as usize; - let data = parse_output_report(payload, size); - UhidEvent::Output { data } - } - UHID_GET_REPORT => { - // uhid_get_report_req: id(__u32), rnum(__u8), rtype(__u8) - let id = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]); - UhidEvent::GetReport { id } - } - UHID_START | UHID_STOP | UHID_OPEN | UHID_CLOSE => { - let _ = event_type; - UhidEvent::Lifecycle(()) - } - other => UhidEvent::Other(other), - }; - Ok(Some(event)) + parse_event(&buf[..n]) } /// Inject a 64-byte CTAPHID input report (token response → browser). @@ -260,6 +232,46 @@ impl UhidDevice { } } +// --------------------------------------------------------------------------- +// Event parsing +// --------------------------------------------------------------------------- + +/// Parse one raw event buffer read from /dev/uhid. +/// +/// Returns `None` for an empty buffer (clean EOF) and errors on a short +/// event header (fewer than 4 bytes). The kernel always delivers full-size +/// events, so payload fields are read at their fixed packed offsets. +fn parse_event(buf: &[u8]) -> io::Result> { + if buf.is_empty() { + return Ok(None); + } + if buf.len() < 4 { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + format!("short uhid event header: {} bytes", buf.len()), + )); + } + let event_type = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]); + let payload = &buf[4..]; + let event = match event_type { + UHID_OUTPUT => { + // uhid_output_req layout (packed): + // data[4096], size(__u16), rtype(__u8) + let size = u16::from_le_bytes([payload[4096], payload[4097]]) as usize; + let data = parse_output_report(payload, size); + UhidEvent::Output { data } + } + UHID_GET_REPORT => { + // uhid_get_report_req: id(__u32), rnum(__u8), rtype(__u8) + let id = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]); + UhidEvent::GetReport { id } + } + UHID_START | UHID_STOP | UHID_OPEN | UHID_CLOSE => UhidEvent::Lifecycle(()), + other => UhidEvent::Other(other), + }; + Ok(Some(event)) +} + // --------------------------------------------------------------------------- // Event builders (byte-exact, no unsafe) // --------------------------------------------------------------------------- @@ -337,8 +349,6 @@ fn parse_output_report(payload: &[u8], size: usize) -> [u8; CTAPHID_REPORT_LEN] fn build_get_report_reply_error(id: u32) -> Vec { // uhid_get_report_reply_req: id(__u32), err(__u16), size(__u16), data[4096] - // UHID_GET_REPORT_REPLY = 10 - const UHID_GET_REPORT_REPLY: u32 = 10; let mut buf = Vec::with_capacity(4 + 4 + 2 + 2 + 4096); buf.extend_from_slice(&UHID_GET_REPORT_REPLY.to_le_bytes()); buf.extend_from_slice(&id.to_le_bytes()); @@ -482,4 +492,108 @@ mod tests { assert_eq!(rendered, "UhidEvent::Output()"); assert!(!rendered.contains("a5")); } + + /// Full-size uhid_event buffer with the given event type in the header. + fn event_buffer(event_type: u32) -> Vec { + let mut buf = vec![0u8; UHID_EVENT_SIZE]; + buf[..4].copy_from_slice(&event_type.to_le_bytes()); + buf + } + + #[test] + fn parse_event_dispatch_table() { + let cases: &[(u32, fn(&UhidEvent) -> bool)] = &[ + (UHID_OUTPUT, |e| matches!(e, UhidEvent::Output { .. })), + (UHID_GET_REPORT, |e| matches!(e, UhidEvent::GetReport { .. })), + (UHID_START, |e| matches!(e, UhidEvent::Lifecycle(()))), + (UHID_STOP, |e| matches!(e, UhidEvent::Lifecycle(()))), + (UHID_OPEN, |e| matches!(e, UhidEvent::Lifecycle(()))), + (UHID_CLOSE, |e| matches!(e, UhidEvent::Lifecycle(()))), + (0xdead_beef, |e| matches!(e, UhidEvent::Other(0xdead_beef))), + ]; + for (event_type, expect) in cases { + let buf = event_buffer(*event_type); + let event = parse_event(&buf).unwrap().unwrap(); + assert!(expect(&event), "type {event_type:#x} parsed as {event:?}"); + } + } + + #[test] + fn parse_event_output_reads_data_and_size_at_payload_offsets() { + let mut buf = event_buffer(UHID_OUTPUT); + // data lives at payload[0..64] (event offset 4) + for (i, byte) in buf[4..4 + CTAPHID_REPORT_LEN].iter_mut().enumerate() { + *byte = i as u8; + } + // size field sits at payload[4096..4098], rtype at payload[4098] + buf[4 + 4096..4 + 4098].copy_from_slice(&(CTAPHID_REPORT_LEN as u16).to_le_bytes()); + + let event = parse_event(&buf).unwrap().unwrap(); + match event { + UhidEvent::Output { data } => { + for (i, byte) in data.iter().enumerate() { + assert_eq!(*byte, i as u8); + } + } + other => panic!("expected Output, got {other:?}"), + } + } + + #[test] + fn parse_event_output_strips_zero_report_id_prefix() { + let mut buf = event_buffer(UHID_OUTPUT); + // report id prefix: payload[0] = 0, data at payload[1..65] + buf[4 + 1..4 + 65].fill(0x5a); + buf[4 + 64] = 0xee; + buf[4 + 4096..4 + 4098].copy_from_slice(&((CTAPHID_REPORT_LEN + 1) as u16).to_le_bytes()); + + let event = parse_event(&buf).unwrap().unwrap(); + match event { + UhidEvent::Output { data } => { + assert_eq!(data[0], 0x5a); + assert_eq!(data[63], 0xee); + } + other => panic!("expected Output, got {other:?}"), + } + } + + #[test] + fn parse_event_get_report_reads_id_at_payload_start() { + let mut buf = event_buffer(UHID_GET_REPORT); + // uhid_get_report_req: id(__u32) at payload[0..4] + buf[4..8].copy_from_slice(&0x1122_3344u32.to_le_bytes()); + + let event = parse_event(&buf).unwrap().unwrap(); + match event { + UhidEvent::GetReport { id } => assert_eq!(id, 0x1122_3344), + other => panic!("expected GetReport, got {other:?}"), + } + } + + #[test] + fn parse_event_empty_buffer_is_eof() { + assert!(parse_event(&[]).unwrap().is_none()); + } + + #[test] + fn parse_event_short_header_errors() { + let err = parse_event(&[UHID_OUTPUT as u8, 0]).unwrap_err(); + assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof); + } + + #[test] + fn get_report_reply_error_layout() { + let buf = build_get_report_reply_error(0x1020_3040); + // type(4) + id(4) + err(2) + size(2) + data(4096) + assert_eq!(buf.len(), 4 + 4 + 2 + 2 + 4096); + let event_type = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]); + assert_eq!(event_type, UHID_GET_REPORT_REPLY); + let id = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]); + assert_eq!(id, 0x1020_3040); + let err = u16::from_le_bytes([buf[8], buf[9]]); + assert_eq!(err, 32); // EPIPE: report unavailable + let size = u16::from_le_bytes([buf[10], buf[11]]); + assert_eq!(size, 0); + assert!(buf[12..].iter().all(|&b| b == 0)); + } } From a9a44bfdd0e8c1a351d74b1382f42c8827b3df06 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:03:18 -0700 Subject: [PATCH 531/726] d2bd-runtime: relax readiness flags, assert no-op audit writes nothing --- changelog.d/w3-39-d2bd-runtime-conc.md | 11 +++++ packages/d2bd-runtime/src/daemon_audit.rs | 43 +++++++++++++------ .../src/resource_runtime_support.rs | 16 +++---- 3 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 changelog.d/w3-39-d2bd-runtime-conc.md diff --git a/changelog.d/w3-39-d2bd-runtime-conc.md b/changelog.d/w3-39-d2bd-runtime-conc.md new file mode 100644 index 000000000..2af3d7139 --- /dev/null +++ b/changelog.d/w3-39-d2bd-runtime-conc.md @@ -0,0 +1,11 @@ +### Changed + +- The new-plane readiness flags (`NewPlaneReadinessState`) now use the + weakest correct memory ordering (`Relaxed`) for their independent + published bits instead of `SeqCst` on every store and load; cross-thread + visibility of the startup path is already ordered by the daemon's + join/actor supervision, so the change removes needless synchronization + without changing observable behavior. +- The daemon audit no-op sink can now be pointed at a state directory in + tests (`no_op_with_state_dir`), so the no-op log's never-writes-files + contract is actually asserted against the directory it was given. \ No newline at end of file diff --git a/packages/d2bd-runtime/src/daemon_audit.rs b/packages/d2bd-runtime/src/daemon_audit.rs index 99cd2d44a..de22ac3a0 100644 --- a/packages/d2bd-runtime/src/daemon_audit.rs +++ b/packages/d2bd-runtime/src/daemon_audit.rs @@ -496,7 +496,9 @@ pub enum WorkloadLaunchResult { /// daemon-state directory. /// - **Tests that don't care about audit output**: use /// [`DaemonAuditLog::no_op`]; best-effort writes are discarded, while -/// authoritative writes fail closed. +/// authoritative writes fail closed. Tests that want to assert the +/// no-op sink never touches the filesystem can point it at a directory +/// with [`DaemonAuditLog::no_op_with_state_dir`] (test-support). /// /// One appender thread owns the hash chain and every file operation, and /// callers hand it records over the bounded queue in [`AUDIT_QUEUE_DEPTH`], @@ -552,6 +554,9 @@ fn complete_reply(reply: oneshot::Sender>, result: io::Result<()> /// sink. struct AuditAppender { state_dir: Option, + /// Capture-only seat: never reads or writes the filesystem even when a + /// `state_dir` is present. `no_op()` logs are the test-support shape. + noop: bool, #[cfg(any(test, feature = "test-support"))] captured: Arc>>, writer: AuditWriterState, @@ -608,7 +613,8 @@ impl AuditAppender { serde_json::to_value(event) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, ); - if let Some(state_dir) = self.state_dir.as_deref() + if !self.noop + && let Some(state_dir) = self.state_dir.as_deref() && let Err(error) = initialize_chain_from_disk(state_dir, &mut self.writer) { self.writer.poisoned = true; @@ -625,7 +631,9 @@ impl AuditAppender { .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; line.push('\n'); - if let Some(state_dir) = self.state_dir.as_deref() { + if !self.noop + && let Some(state_dir) = self.state_dir.as_deref() + { let today = utc_date_string(); // First write of the process or a day-boundary crossing: // re-run retention pruning (best-effort) before appending. @@ -854,12 +862,22 @@ impl DaemonAuditLog { pub fn new(state_dir: impl Into) -> Self { let state_dir = state_dir.into(); let poisoned = prune_old_audit_logs(&state_dir, AUDIT_RETENTION_DAYS).is_err(); - Self::with_appender(Some(state_dir), poisoned) + Self::with_appender(Some(state_dir), poisoned, false) } /// No-op constructor for tests that do not exercise audit output. pub fn no_op() -> Self { - Self::with_appender(None, false) + Self::with_appender(None, false, true) + } + + /// No-op constructor that records a `state_dir` for the test to inspect. + /// + /// The sink stays capture-only: it never reads or writes the given + /// directory, so a test can point it at a temp dir and assert that no + /// audit file appears there. + #[cfg(any(test, feature = "test-support"))] + pub fn no_op_with_state_dir(state_dir: impl Into) -> Self { + Self::with_appender(Some(state_dir.into()), false, true) } /// Start the single appender and return the handle over its queue. @@ -867,11 +885,12 @@ impl DaemonAuditLog { /// A failed spawn is fail-closed: the sink stays `None`, so every later /// write reports the sink as unavailable instead of silently dropping the /// record. - fn with_appender(state_dir: Option, poisoned: bool) -> Self { + fn with_appender(state_dir: Option, poisoned: bool, noop: bool) -> Self { #[cfg(any(test, feature = "test-support"))] let captured: Arc>> = Arc::new(Mutex::new(Vec::new())); let appender = AuditAppender { state_dir: state_dir.clone(), + noop, #[cfg(any(test, feature = "test-support"))] captured: Arc::clone(&captured), writer: AuditWriterState { @@ -2386,12 +2405,10 @@ mod tests { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn no_op_does_not_write_file() { let dir = tempfile::tempdir().expect("create temp dir"); - // Create a no-op log - but give it the temp dir to make sure the - // file is NOT created. - let log = DaemonAuditLog::no_op(); - // Manually set state_dir to the temp dir via a helper. - // We can't do that here because state_dir is private; instead, - // create a no_op and verify its captured vec is empty. + // Point the no-op log at the temp dir: the no-op sink is + // capture-only and must never touch the filesystem, so the + // no-file-created claim is actually asserted against the dir. + let log = DaemonAuditLog::no_op_with_state_dir(dir.path()); log.write_event(DaemonEvent::ApiReadyTimeout { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), @@ -2400,7 +2417,7 @@ mod tests { }) .expect("no-op write should not error"); - // No file should appear in temp dir (no state_dir set). + // No file should appear in the temp dir the log was pointed at. let count = std::fs::read_dir(dir.path()) .expect("read temp dir") .count(); diff --git a/packages/d2bd-runtime/src/resource_runtime_support.rs b/packages/d2bd-runtime/src/resource_runtime_support.rs index 6d2c1a263..8045e5090 100644 --- a/packages/d2bd-runtime/src/resource_runtime_support.rs +++ b/packages/d2bd-runtime/src/resource_runtime_support.rs @@ -155,27 +155,27 @@ impl NewPlaneReadinessState { } pub fn set_spec_store_ready(&self, value: bool) { - self.spec_store_ready.store(value, Ordering::SeqCst); + self.spec_store_ready.store(value, Ordering::Relaxed); } pub fn set_manager_started(&self, value: bool) { - self.manager_started.store(value, Ordering::SeqCst); + self.manager_started.store(value, Ordering::Relaxed); } pub fn set_providers_registered(&self, value: bool) { - self.providers_registered.store(value, Ordering::SeqCst); + self.providers_registered.store(value, Ordering::Relaxed); } pub fn set_initial_load_complete(&self, value: bool) { - self.initial_load_complete.store(value, Ordering::SeqCst); + self.initial_load_complete.store(value, Ordering::Relaxed); } pub fn snapshot(&self) -> NewPlaneReadiness { NewPlaneReadiness { - spec_store_ready: self.spec_store_ready.load(Ordering::SeqCst), - manager_started: self.manager_started.load(Ordering::SeqCst), - providers_registered: self.providers_registered.load(Ordering::SeqCst), - initial_load_complete: self.initial_load_complete.load(Ordering::SeqCst), + spec_store_ready: self.spec_store_ready.load(Ordering::Relaxed), + manager_started: self.manager_started.load(Ordering::Relaxed), + providers_registered: self.providers_registered.load(Ordering::Relaxed), + initial_load_complete: self.initial_load_complete.load(Ordering::Relaxed), } } } From 7de088b5d6629e1a2ae4e8a084ce5a932646aa3b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:08:25 -0700 Subject: [PATCH 532/726] d2b-provider: dispatch agent requests concurrently ProviderAgent::serve awaited each dispatch serially, so one slow handler near the 900s timeout ceiling stalled the whole session queue and the 64-permit in-flight semaphore never bound the loop. Spawn each dispatch on its own task with a cloned response sender; the semaphore acquired inside dispatch now caps concurrency. Per-session response ordering is not a contract; responses are sent as each dispatch completes. Also replace the TPM device lifecycle-lease once-gate Mutex with an AtomicBool: the flag is owned by exactly one task per port and the guard was held across .await, so the lock could never contend. --- changelog.d/w3-41-provider-async-leaf.md | 11 +++ .../src/effects_service.rs | 13 +-- packages/d2b-provider/src/agent.rs | 99 +++++++++++++++++-- 3 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 changelog.d/w3-41-provider-async-leaf.md diff --git a/changelog.d/w3-41-provider-async-leaf.md b/changelog.d/w3-41-provider-async-leaf.md new file mode 100644 index 000000000..197a9e532 --- /dev/null +++ b/changelog.d/w3-41-provider-async-leaf.md @@ -0,0 +1,11 @@ +### Changed + +- Provider-agent sessions now dispatch each request concurrently instead of + one at a time: a slow handler near the 900s timeout ceiling no longer + stalls the rest of the session queue, and the 64-request in-flight ceiling + now actually bounds concurrent dispatches. +- Provider-agent responses are no longer guaranteed to arrive in request + order; each dispatch completes independently and sends its response as it + finishes. +- The TPM device lifecycle-lease once-gate is now an atomic flag instead of a + never-contended async lock (no behavior change). \ No newline at end of file diff --git a/packages/d2b-provider-device-tpm/src/effects_service.rs b/packages/d2b-provider-device-tpm/src/effects_service.rs index 446e2b5ab..5485937db 100644 --- a/packages/d2b-provider-device-tpm/src/effects_service.rs +++ b/packages/d2b-provider-device-tpm/src/effects_service.rs @@ -20,6 +20,7 @@ use std::path::PathBuf; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; use d2b_contracts::types::{BundleOpId, VmId}; use d2b_contracts_broker::kernel_client::{KernelInvocation, envelope_invoke_kernel}; @@ -358,7 +359,7 @@ pub(crate) struct LiveTpmResourceEffectPort<'a> { /// The guest lifecycle lease is consumed at most once, by the first /// effect that reaches a launchable row (the preserved /// `lifecycle_lease_consumed` gate of the old executor). - lifecycle_lease_consumed: tokio::sync::Mutex, + lifecycle_lease_consumed: AtomicBool, } impl LiveTpmResourceEffectPort<'_> { @@ -381,18 +382,14 @@ impl LiveTpmResourceEffectPort<'_> { /// authorized this Device's start operation; the row's Process controller /// owns the process from here, so the port only retires the admission. async fn consume_lifecycle_lease(&self) -> Result<(), TpmResourceEffectError> { - let mut consumed = self - .lifecycle_lease_consumed - .try_lock() - .map_err(|_| TpmResourceEffectError::Transient)?; - if *consumed { + if self.lifecycle_lease_consumed.load(Ordering::Acquire) { return Ok(()); } self.facets .runtime .consume_lifecycle_lease(self.vm_id.as_str(), &self.operation_id) .await?; - *consumed = true; + self.lifecycle_lease_consumed.store(true, Ordering::Release); Ok(()) } @@ -694,7 +691,7 @@ impl AdmittedTpmDevice { device_ref: self.device_ref, execution_ref: self.execution_ref, operation_id: self.operation_id, - lifecycle_lease_consumed: tokio::sync::Mutex::new(false), + lifecycle_lease_consumed: AtomicBool::new(false), } } } diff --git a/packages/d2b-provider/src/agent.rs b/packages/d2b-provider/src/agent.rs index 058671e45..9319485f9 100644 --- a/packages/d2b-provider/src/agent.rs +++ b/packages/d2b-provider/src/agent.rs @@ -213,9 +213,21 @@ impl std::error::Error for ProviderAgentError {} pub struct ProviderAgent { zone: ZoneId, provider_axis: ProviderBindingAxis, - service: S, + service: Arc, permits: Arc, - audit: Mutex>, + audit: Arc>>, +} + +impl Clone for ProviderAgent { + fn clone(&self) -> Self { + Self { + zone: self.zone.clone(), + provider_axis: self.provider_axis, + service: Arc::clone(&self.service), + permits: Arc::clone(&self.permits), + audit: Arc::clone(&self.audit), + } + } } impl ProviderAgent { @@ -231,9 +243,9 @@ impl ProviderAgent { Ok(Self { zone, provider_axis, - service, + service: Arc::new(service), permits: Arc::new(Semaphore::new(MAX_AGENT_IN_FLIGHT)), - audit: Mutex::new(VecDeque::with_capacity(MAX_AGENT_AUDIT_EVENTS)), + audit: Arc::new(Mutex::new(VecDeque::with_capacity(MAX_AGENT_AUDIT_EVENTS))), }) } @@ -323,6 +335,13 @@ where /// Serve requests until the authenticated session closes or its channel /// is dropped. A session close is a clean termination, not a retry loop. + /// + /// Each request is dispatched on its own task; the dispatch semaphore + /// ([`MAX_AGENT_IN_FLIGHT`]) caps how many run concurrently, so a slow + /// handler near the timeout ceiling no longer stalls the session queue. + /// Per-session response ordering is not a contract: responses are sent as + /// each dispatch completes, and a later request may finish before an + /// earlier one. pub async fn serve( &self, mut requests: mpsc::Receiver, @@ -333,10 +352,12 @@ where ProviderAgentMessage::Request(request) => request, ProviderAgentMessage::SessionClosed => return Ok(()), }; - let result = self.dispatch(request).await; - if responses.send(result).await.is_err() { - return Err(ProviderAgentError::SessionClosed); - } + let agent = self.clone(); + let response_tx = responses.clone(); + tokio::spawn(async move { + let result = agent.dispatch(request).await; + let _ = response_tx.send(result).await; + }); } Ok(()) } @@ -399,6 +420,68 @@ mod tests { ); } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test] + async fn slow_dispatch_does_not_stall_later_requests() { + struct Slow; + + impl ProviderAgentService for Slow { + fn dispatch( + &self, + request: ProviderAgentRequest, + ) -> impl Future> + Send + { + let slow = request.payload().get("slow").is_some(); + async move { + if slow { + tokio::time::sleep(Duration::from_millis(200)).await; + } + Ok(ProviderAgentResponse::new(request.payload.clone())) + } + } + } + + let agent = ProviderAgent::new( + ZoneId::parse("dev").unwrap(), + ProviderBindingAxis::Provider, + Slow, + ) + .unwrap(); + let (request_tx, request_rx) = mpsc::channel(4); + let (response_tx, mut response_rx) = mpsc::channel(4); + let slow_request = ProviderAgentRequest::new( + ServiceName::parse("d2b.provider.v3").unwrap(), + SpecifiedProviderMethod::AssessUpdate, + CanonicalJsonObject::parse(br#"{"slow":true}"#).unwrap(), + 1_000, + ) + .unwrap(); + let fast_request = ProviderAgentRequest::new( + ServiceName::parse("d2b.provider.v3").unwrap(), + SpecifiedProviderMethod::AssessUpdate, + CanonicalJsonObject::parse(br#"{"ok":true}"#).unwrap(), + 1_000, + ) + .unwrap(); + request_tx + .send(ProviderAgentMessage::Request(slow_request)) + .await + .unwrap(); + request_tx + .send(ProviderAgentMessage::Request(fast_request)) + .await + .unwrap(); + drop(request_tx); + agent.serve(request_rx, response_tx).await.unwrap(); + // The fast request completes while the slow one is still sleeping: + // per-session ordering is not a contract, but the queue is not + // stalled behind the slow handler. + let first = response_rx.recv().await.unwrap().unwrap(); + assert!(first.payload().get("slow").is_none(), "fast request should complete first"); + let second = response_rx.recv().await.unwrap().unwrap(); + assert!(second.payload().get("slow").is_some()); + } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn session_close_terminates_serve_loop() { From cc1a4dbd912bdbecd3ebb76da185a3808e471932 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:11:47 -0700 Subject: [PATCH 533/726] telemetry: replace tautological bucket constant test with behavior test The prior test only asserted that each bucket constant contains one of its own members, so an equal-but-shifted refactor passed while a behavior change would pass undetected. Replace it with a structural behavior test: a histogram family built from the canonical controller-hint descriptor over CONTROLLER_HINT_BUCKETS_SECONDS refuses a negative (out-of-domain) value while accepting an in-range one, so refactors cannot hide a bucket-policy regression. --- changelog.d/w3-34-telemetry-buckets.md | 3 +++ packages/d2b-telemetry/src/meter_registry.rs | 24 ++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 changelog.d/w3-34-telemetry-buckets.md diff --git a/changelog.d/w3-34-telemetry-buckets.md b/changelog.d/w3-34-telemetry-buckets.md new file mode 100644 index 000000000..361747592 --- /dev/null +++ b/changelog.d/w3-34-telemetry-buckets.md @@ -0,0 +1,3 @@ +### Changed + +- Replaced the d2b-telemetry bucket-constant smoke test with a behavior test: a histogram family built from the controller hint buckets accepts an in-range value and rejects an out-of-range one, so the test now fails on real behavior regressions instead of on refactors. \ No newline at end of file diff --git a/packages/d2b-telemetry/src/meter_registry.rs b/packages/d2b-telemetry/src/meter_registry.rs index 2537e1ef2..b87309863 100644 --- a/packages/d2b-telemetry/src/meter_registry.rs +++ b/packages/d2b-telemetry/src/meter_registry.rs @@ -3,7 +3,8 @@ use std::collections::BTreeMap; use crate::metric_label_policy::{ - IdentityCanaries, MetricDescriptor, MetricPolicyError, validate_data_point, + IdentityCanaries, MetricDescriptor, MetricPolicyError, canonical_descriptor, + validate_data_point, }; pub use d2b_contracts_provider::v3::telemetry_policy::label; @@ -194,10 +195,23 @@ mod tests { use super::*; #[test] - fn target_buckets_are_present() { - assert!(CONTROLLER_HINT_BUCKETS_SECONDS.contains(&0.005)); - assert!(PROCESS_LAUNCH_BUCKETS_SECONDS.contains(&0.020)); - assert!(STORE_WRITE_BUCKETS_SECONDS.contains(&0.010)); + fn controller_hint_buckets_accept_in_range_and_reject_out_of_range_values() { + let mut family = MetricFamily::new( + canonical_descriptor("d2b_controller_hint_to_handler_seconds").unwrap(), + MetricKind::Histogram, + CONTROLLER_HINT_BUCKETS_SECONDS.iter().copied(), + ) + .unwrap(); + let labels = BTreeMap::from([("handler".to_owned(), "configuration".to_owned())]); + let canaries = IdentityCanaries::default(); + + assert!(family + .record(&labels, MetricValue::Scalar(0.012), &canaries) + .is_ok()); + assert_eq!( + family.record(&labels, MetricValue::Scalar(-0.001), &canaries), + Err(MetricPolicyError::DescriptorMalformed) + ); } #[test] From 113fdf93dce807951ab67856a67763d75604722d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:12:37 -0700 Subject: [PATCH 534/726] zone-routing: write enrollment replies as one non-cancellable unit The serve loop now commits each link FSM transition and writes the encoded reply as one unit with no await between the commit and the write, and documents that a task dropped mid-send closes the connection as the peer's only signal. The engine reason test is renamed to what it asserts (distinct wire labels), and a dead ZoneId line plus its import are removed from the router test module. --- changelog.d/w3-36-zone-routing-async.md | 6 +++ packages/d2b-zone-routing/src/engine.rs | 16 ++++--- packages/d2b-zone-routing/src/router.rs | 3 +- packages/d2b-zone-routing/src/serving.rs | 54 ++++++++++++++++++++---- 4 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 changelog.d/w3-36-zone-routing-async.md diff --git a/changelog.d/w3-36-zone-routing-async.md b/changelog.d/w3-36-zone-routing-async.md new file mode 100644 index 000000000..43422b1eb --- /dev/null +++ b/changelog.d/w3-36-zone-routing-async.md @@ -0,0 +1,6 @@ +### Fixed + +- Zone enrollment replies are now written as one non-cancellable unit with + the link FSM transition that produced them, so a serve task dropped + mid-send closes the connection as the peer's only signal instead of + leaving the link mid-transition with no reply on the wire. \ No newline at end of file diff --git a/packages/d2b-zone-routing/src/engine.rs b/packages/d2b-zone-routing/src/engine.rs index 1a48ecb81..ecf82b449 100644 --- a/packages/d2b-zone-routing/src/engine.rs +++ b/packages/d2b-zone-routing/src/engine.rs @@ -3367,12 +3367,16 @@ mod tests { } #[test] - fn every_reason_the_engine_can_produce_is_covered_by_this_suite() { - // The engine can produce every closed reason except - // `SiblingOrParentRouteAdvert` from an advertisement: the contract's - // own constructor already proves descendant strictness and next-hop - // agreement, so that shape cannot reach the engine. The engine still - // uses that reason for a withdrawal naming a route another Zone owns. + fn every_engine_reason_has_a_distinct_wire_label() { + // The closed refusal vocabulary is the 16 reasons below; each must + // map to its own wire label, so a collision between two reasons' + // labels would fail this suite. This is a distinctness assertion, + // not a coverage claim: producing every reason is the other tests' + // job, and `SiblingOrParentRouteAdvert` cannot reach the engine from + // an advertisement at all - the contract's own constructor already + // proves descendant strictness and next-hop agreement, and the + // engine uses that reason only for a withdrawal naming a route + // another Zone owns. let produced = [ ZoneRouteFailClosedReason::MalformedAdvert, ZoneRouteFailClosedReason::UnknownParent, diff --git a/packages/d2b-zone-routing/src/router.rs b/packages/d2b-zone-routing/src/router.rs index 1280a96a0..b8d0c01a4 100644 --- a/packages/d2b-zone-routing/src/router.rs +++ b/packages/d2b-zone-routing/src/router.rs @@ -382,7 +382,7 @@ mod tests { BindingDigest, EvidenceClass, Locality, ReconnectGeneration, ServiceName, SessionBinding, SessionPurpose, TranscriptHash, TransportBinding, }; - use d2b_contracts_resource::v3::{ResourceName, ResourceTypeName, SchemaFingerprint, ZoneId}; + use d2b_contracts_resource::v3::{ResourceName, ResourceTypeName, SchemaFingerprint}; use d2b_contracts_zone_session::v3::zone_routing::ZoneLabelId; fn zone() -> ZonePath { @@ -514,7 +514,6 @@ mod tests { assert_eq!(table.len().unwrap(), 1); assert!(table.remove(&operation).unwrap()); assert_eq!(table.len().unwrap(), 0); - let _ = ZoneId::parse("dev").unwrap(); } #[test] diff --git a/packages/d2b-zone-routing/src/serving.rs b/packages/d2b-zone-routing/src/serving.rs index e2345415f..2666c05d2 100644 --- a/packages/d2b-zone-routing/src/serving.rs +++ b/packages/d2b-zone-routing/src/serving.rs @@ -40,6 +40,17 @@ //! vocabulary carries no capacity reason and inventing one would put a reason //! on the wire that no handler produced. //! +//! # The transition and the reply write are one unit +//! +//! Each served call commits its link FSM transition synchronously inside the +//! handler (PSK burn, enrollment record seal) and then writes the encoded +//! reply. The commit and the write are one unit: there is no await between +//! them, so the reply write is the only suspension point after the +//! transition. If the serve task is dropped mid-send, the connection closes +//! and that close is the peer's only signal that the transition was +//! committed; the caller must not cancel the task between the commit and +//! the write completing. +//! //! # What this runtime does not serve //! //! Enrollment is the whole of its surface. A connection whose enrollment @@ -177,6 +188,14 @@ impl ZoneEnrollmentServer { /// it is given, writing one encoded reply per call, and returns `Ok` once /// the peer enrolled. The transport is borrowed, not consumed: the caller /// owns what the connection carries after enrollment. + /// + /// Each call's link FSM transition (PSK burn, enrollment record seal) is + /// committed synchronously by the handler, and the encoded reply is + /// written immediately after as one non-cancellable unit: the reply + /// write is the only suspension point between the transition and the + /// peer observing it. If this task is dropped mid-send, the connection + /// closes and that close is the peer's only signal that the transition + /// was committed. pub async fn serve( &mut self, transport: &mut dyn OwnedTransport, @@ -187,25 +206,26 @@ impl ZoneEnrollmentServer { calls += 1; match call { EnrollmentCall::Bootstrap(call) => { + // The FSM transition and the reply write are one + // non-cancellable unit: the handler commits the + // transition synchronously, and the encoded reply is + // written immediately after, with no await between the + // commit and the write. let reply = self.serve_bootstrap(&call)?; let bytes = reply .encode() .map_err(|_| ZoneEnrollmentServeError::Malformed)?; - transport - .send(TransportPacket::new(bytes)) - .await - .map_err(|_| ZoneEnrollmentServeError::Transport)?; + write_reply(transport, bytes).await?; } EnrollmentCall::Enroll(call) => { + // The FSM transition and the reply write are one + // non-cancellable unit, exactly as for bootstrap. let reply = self.serve_enroll(&call)?; let enrolled = matches!(reply, ZoneEnrollReply::Enrolled { .. }); let bytes = reply .encode() .map_err(|_| ZoneEnrollmentServeError::Malformed)?; - transport - .send(TransportPacket::new(bytes)) - .await - .map_err(|_| ZoneEnrollmentServeError::Transport)?; + write_reply(transport, bytes).await?; if enrolled { return Ok(()); } @@ -310,6 +330,24 @@ enum EnrollmentCall { Enroll(ZoneEnrollCall), } +/// Write one encoded reply, the write half of the commit+write unit. +/// +/// The caller has already committed the link FSM transition synchronously +/// (PSK burn, enrollment record seal); this writes the encoded reply as the +/// immediate next step, so the reply write is the only suspension point +/// between the transition and the peer observing it. If the task is dropped +/// mid-send, the connection closes and that close is the peer's only signal +/// that the transition was committed. +async fn write_reply( + transport: &mut dyn OwnedTransport, + bytes: Vec, +) -> Result<(), ZoneEnrollmentServeError> { + transport + .send(TransportPacket::new(bytes)) + .await + .map_err(|_| ZoneEnrollmentServeError::Transport) +} + /// Read one bounded frame and decode it as exactly the call it is. async fn receive_call( transport: &mut dyn OwnedTransport, From 09f9c6ae1db5dfafd73666ab7ea2c8445d2df36f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:17:25 -0700 Subject: [PATCH 535/726] chore: untrack the pre-existing post-plan cleanup wave plan The file arrived untracked in the working tree and was swept into a generated-outputs commit by an add that was too broad. It stays on disk; it is simply not ours to track. --- ...2-001-chore-post-plan-cleanup-wave-plan.md | 315 ------------------ 1 file changed, 315 deletions(-) delete mode 100644 docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md diff --git a/docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md b/docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md deleted file mode 100644 index 0605d9b22..000000000 --- a/docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md +++ /dev/null @@ -1,315 +0,0 @@ ---- -title: Post-Plan Cleanup Wave: Gates, Dossiers, CI, and Bazel Variant Graph - Plan -type: chore -date: 2026-09-22 -artifact_contract: ce-unified-plan/v1 -artifact_readiness: implementation-ready -product_contract_source: ce-plan-bootstrap -execution: code ---- - -# Cleanup Wave: Gates, Dossiers, CI, and Bazel Variant Graph - Plan - -## Goal Capsule - -- Objective: land the eight backlog cleanups behind issues #584, #585, #586, #587, #589, #590, #591, #592. Each issue's acceptance criteria define its unit. -- Authority hierarchy: the eight GitHub issues and their decision comments are the authority. Where an issue cites a stale path, the current tree wins (recorded in KTD7). -- Settled decisions carried from the issue threads: retire `microvm.*` outright with no compat shim (KTD1, user-directed); fix the Bazel variant graph at its source rather than mitigate (KTD3, user-directed); make the security scan a required check (KTD5, user-directed). -- Stop conditions: every unit's verification passes on the repository's own gates; any unit that cannot converge (for example, the #587 investigation producing an environmental disposition) reports evidence instead of forcing a fix. -- Execution profile: one implementation-ready code plan; units land as independent reviewed PRs in dependency order. - ---- - -## Product Contract - -### Summary - -The v3 control-plane rewrite left eight residue classes: a compatibility option namespace that no longer serves anyone, documentation and goldens pinning retired refusal contracts, a census invocation drifted from its documented contract, a scanner blind to the lock shape it was built to catch, provider dossiers citing deleted files, a daemon test surface excluded from CI, a security scan whose findings cannot block a merge, and one live bug whose cause is unestablished. This wave closes each residue class at its source. - -### Problem Frame - -Each issue is a half-landed cleanup or an unobserved defect: code deleted without its docs and goldens (#591), a namespace shim surviving a removal that was supposed to be total (#592), a scanner that cannot see the exact shape it was built to catch (#590), a census invocation that contradicts its documented contract and truncates its diagnostics (#585), a gate fed stale inputs (#589), a build exclusion that hides test failures (#584), an advisory security scan (#586), and a failing identity read whose reported cause is disproved (#587). Individually small; together they erode trust in the gates the framework relies on. - -### Requirements - -- R1. No `microvm.*` option or option reference survives in `nixos-modules/` framework files, templates, examples, or Rust doc comments; the VM runner API lives under the d2b-owned namespace per KTD1, and the retirement is recorded in the ADR 0018 follow-up, the changelog, and the v1.x migration notes. -- R2. The retired Tier-0 refusal contract is absent from docs, the CLI contract coverage table, the golden generator, and the committed goldens; `single-writer-conflict` remains only on its live surface (packages/d2b-provider-volume-local/src/error.rs:103). -- R3. The async-gate fails a planted method-call lock acquisition inside an `async fn` in a covered root; the conservative-shape escape hatch is documented; the Cargo.toml comment and the gate's own docs state the same enforcement reality. -- R4. Provider dossiers under `docs/specs/providers/` reference only files and crates that exist in the tree, and the policy gate fails a dossier that cites a deleted file or a non-existent crate. -- R5. The systemd identity-read failure's root cause is established with captured evidence (not assumed); the fix lands at the correct layer with a regression test, or a documented disposition with evidence replaces the fix if the failure is environmental. -- R6. In-tree part (mandatory, this wave): a security-scan job runs on pull requests and is wired into the aggregate `check` needs list so a scan failure fails the aggregate. Enforcement part (external): the scan's result is a required check on the protected branch. An access-denied handoff on the enforcement part records an explicit external blocker - it does not satisfy the requirement; the PR and tracking issue carry the named blocker until someone with branch-protection access completes it. The scan and its blocking status are documented in docs/contributing/workflow.md with an AGENTS.md pointer. -- R7. The census clippy invocation byte-matches the documented contract (or the manifest comment is updated in the same change); a planted compile error surfaces the first real diagnostic; a planted `await_holding_lock` site does not fail the census off the clippy-run error path; the module doc comment matches the manifest level. -- R8. `bazel build //packages/d2bd:all-tests` succeeds at pristine base; d2bd's `all-tests` appears in `rust-main-packages`; its per-target clippy tests ride Layer-1; the exclusion comment is deleted; a membership guard fails when any per-package `all-tests` aggregate is absent from the Layer-1 suite list or carries an excluding tag - the guard's input is suite membership, not a mutable exclusion list. - -### Scope Boundaries - -- In scope: exactly the eight issues above, including the in-tree workflow half of #586 and the branch-protection enforcement attempt it requires. -- Deferred to follow-up work: the other TODO.md entries the issues name only as context (devShell absence, schema drift, USBIP guest-attach, NFS notes) are not part of this wave. -- Outside this wave's identity: no new feature work, no new linters or formatters beyond the gates this plan modifies, no branch-protection settings change attempted without someone holding settings access. - -### Outstanding Questions - -- None blocking. The #587 investigation may resolve to a documented environmental disposition; that is an accepted outcome per its issue, not a blocker. - ---- - -## Planning Contract - -### Key Technical Decisions - -- KTD1. Retire the `microvm.*` option namespace in one change with no compatibility shim: `options.microvm` is deleted, every in-tree consumer migrates to the d2b-owned namespace in the same commit, and the changelog plus ADR 0018 follow-up record the break. (session-settled: user-directed - chosen over a `lib.warn` deprecation window: the issue decision accepts a deliberate breaking change.) -- KTD2. Retire the shim only together with its read surface and containment lint: `nixos-modules/lib.nix` (the `vmRunner` helper reading `config.d2b._computed..config.microvm or { }`, consumed by `assertions.nix`) and `nixos-modules/guest-closures.nix` (the `microvm = guestConfig.microvm or { }` fallback reads) both key on the namespace, so deleting the shim before migrating these readers and the containment lint makes guest configs silently fall back to 1 vCPU / 512 MiB defaults or the gate pass silently. Writers, readers, lint, and host-integration fixtures migrate in one commit. -- KTD3. Fix the d2bd dual-rlib condition at its source by unifying the test-support variant graph so a test target links exactly one rlib per crate identity, following the existing `d2b_core` / `d2b_core_test_support` pattern in `packages/d2b-core/BUILD.bazel` (crate_features `test-support`, cfg-gated test_support module). (session-settled: user-directed - chosen over mitigation or continued exclusion: the exclusion hid four required-field failures, a merge-ref compile error, and two stale build references in one day.) -- KTD4. Arm method-call lock detection in the async-gate as a conservative shape flag with a documented escape hatch, not receiver-type resolution: the scanner flags a lock method call inside an `async fn` not followed by `.await` (awaited tokio lock sites are legitimate), and the hatch is a source-level marker honored by the scanner and recorded in a named inventory file - the gate's existing "no violation allowlist" statement is rewritten, not contradicted. The inventory covers every flagged shape in covered roots, production and test code, derived from the scanner's own output. The Cargo.toml census block and the gate doc are reconciled in the same change. -- KTD5. The security scan becomes a required check through both halves: a committed workflow job wired into the `pr-l1-static-fast.yml` aggregate `check` needs list (in-tree, unconditional), plus the branch-protection setting that marks it required. The settings half is a declared hard dependency needing an account with branch-protection access; the plan attempts it via `gh` and stops at the documented handoff if access is denied. (session-settled: user-directed - chosen over in-tree-only with an open question: the user directed full enforcement attempt.) -- KTD6. The #591 removal is one atomic commit: docs rows and anchors, the coverage table rows, the golden generator rows, and the regenerated committed goldens land together, because the fixtures-proofs gate closes coverage against goldens and a partial removal fails it. -- KTD7. The #587 investigation unit targets the live read sites only: the issue's cited broker path (`d2b-broker/src/ops/systemd.rs`) does not exist; the live reads are `packages/d2b-unsafe-local-helper/src/systemd.rs` (user-scope identity, 2s ready timeout, 20ms retries) and `packages/d2b-provider-process-systemd` (identity/operations). The stale-path correction is recorded here rather than re-deriving it at execution time. -- KTD8. Provider dossiers are updated to the current tree rather than marked historical: they describe the live Zone-native provider architecture, so a status header would hide drift the wave exists to remove. Wrong crate names (`d2b-provider-system-systemd` -> `d2b-provider-process-systemd`) and deleted-module citations are corrected in place. -- KTD9. The census clippy invocation is aligned to the documented contract (Cargo.toml:159-162): `run_clippy` passes `-W warnings -W clippy::disallowed_methods -W clippy::await_holding_lock -W clippy::await_holding_refcell_ref`, and the truncation fix keeps the first real diagnostic (file:line plus message) instead of the reversed last-15-stderr tail. - -### High-Level Technical Design - -```mermaid -flowchart TB - U5[U5 census contract fix] --> U6[U6 async-gate method-call arming] - U1[U1 microvm namespace retirement] --> U2[U2 comment + migration records] - U7[U7 d2bd variant graph unification] - U3[U3 Tier-0 contract removal] - U4[U4 dossier correction + scan extension] - U8[U8 security-scan required check] - U9[U9 systemd identity investigation] -``` - -Independent tracks: tooling gates (U5 -> U6), the Bazel variant graph (U7), the namespace retirement (U1 -> U2), doc/golden cleanup (U3, U4), CI wiring (U8), and the investigation (U9). No unit depends on another's files except U5 -> U6 (the census meter must be correct before arming new scanner detection against it) and U1 -> U2 (comment rewrites follow the namespace migration). - -### Assumptions - -- The scanner identity for #586 is the branch-protection-configured one described in the issue; if it cannot be identified from the repo, the workflow job wraps whatever scanner the owner names and the plan states that dependency. -- The #587 failure is reproducible on the current host via the helper's scope path; if it is not, the disposition path applies. - ---- - -## Implementation Units - -### U1. Retire the microvm option namespace - -- Goal: remove `options.microvm` and migrate every in-tree consumer to the d2b-owned namespace in one commit. -- Requirements: R1. Issue #592. Governs KTD1, KTD2. -- Dependencies: none. -- Files: - - nixos-modules/vm-options.nix (shim removal; hypervisor enum) - - nixos-modules/vm-guest-base.nix, nixos-modules/observability-vm.nix - - nixos-modules/guest-closures.nix (the `microvm = guestConfig.microvm or { }` fallback read) - - nixos-modules/lib.nix (the `vmRunner` helper reading `config.d2b._computed..config.microvm`, and the containment detector declaring `options.microvm`) - - nixos-modules/assertions.nix (containment lint consuming vmRunner) - - nixos-modules/components/graphics.nix, components/tpm.nix, components/video/guest.nix, components/observability/guest.nix - - packages/d2b-provider-device-tpm/nix/guest.nix, packages/d2b-provider-device-gpu/nix/guest.nix and its nix/video-guest.nix (+ their nix/tests/default.nix) - live microvm.* writers imported by the component files - - tests/host-integration/state-posture-contract.nix, tests/host-integration/runtime-cloud-hypervisor-guest-preflight.nix (per-VM microvm.storeOnDisk/storeDisk/shares writes) - - tests/unit/nix/cases/ consumers of the renamed options - - changelog.d/ fragment -- Approach: follow TODO.md's outline at the `Drop the microvm.* option namespace` entry (line ~346) and the ADR 0018 migration map (`microvm.*` -> `d2b.vms..runner.*`). Migrate writers, the read surfaces (`guest-closures.nix` fallback reads, `lib.nix` `vmRunner` accessor, `assertions.nix` probe), and the containment lint in the same commit. NOTE: the issues' cited paths (`host.nix`, `net.nix`, `processes-json.nix`, `components/audio/guest.nix`) no longer exist; the tree's current writers above win per the authority rule. Verify the ADR 0018 materialization path exists before relying on it. -- Test scenarios: - - Evaluating an example that sets only the new namespace produces no `microvm` option references and no warnings. - - The unit/nix case `tests/unit/nix/cases/net-vm-network.nix` still passes unchanged (the fire-walling invariant must not regress). - - A `grep -rn "microvm\." nixos-modules/ templates/ examples/ packages/ --include=*.nix --include=*.rs` over framework files, templates, examples, and Rust doc comments returns nothing after the change (ADR historical prose excepted). -- Verification: `make check` unit-nix cases pass; `make generate` regenerates committed artifacts cleanly. - -### U2. Rewrite microvm-era comments and record the namespace retirement - -- Goal: remove the fictional upstream dependency from prose and record the breaking change where the repo's contracts require it. -- Requirements: R1. Issue #592. -- Dependencies: U1. -- Files: - - ~20 nixos-modules framework files and 16 Rust files carrying "microvm.nix's cloud-hypervisor runner" framing (inventory via `grep -rn "microvm" packages/ nixos-modules/ docs/ --include=*.nix --include=*.rs` filtered to comments) - - docs/adr/0018-microvm-nix-removal.md (follow-up note: option namespace retired) - - docs/ migration notes (v1.x consumer migration section) - - TODO.md (close the entry at line ~346) - - changelog.d/ fragment (shared with U1 or its own) -- Approach: comments name the broker SpawnRunner path instead of an upstream microvm.nix runner. The ADR 0018 follow-up records that the option namespace (not just the flake input) is gone, with the in-tree migration map. -- Test scenarios: - - Test expectation: none - prose-only comments plus TODO/ADR/migration doc updates; correctness is covered by U1's gate runs. -- Verification: `grep -rn "microvm" docs/adr/0018-microvm-nix-removal.md` shows the follow-up; a repo-wide comment grep finds no "microvm.nix's runner" framing in live framework or Rust files. - -### U3. Remove the retired Tier-0 refusal contract from docs, coverage, and goldens - -- Goal: the CLI cannot emit `tier-0-legacy-uses-nixos-module` or the refusal-variant `single-writer-conflict`, and no doc, coverage row, generator branch, or committed golden claims it can. -- Requirements: R2. Issue #591. Governs KTD6. -- Dependencies: none. -- Files: - - docs/reference/error-codes.md (rows + anchors for both codes) - - docs/how-to/host-prepare.d/modules-and-devices.md (refusal claims) - - docs/reference/support-matrix.d/s4-tier-modules.md (refusal claims) - - packages/d2b/tests/cli_contract_coverage.rs (W3_ROWS tier-0 and single-writer refusal rows, lines ~536-553) - - tests/fixtures/gen-w3-cli-goldens.py (tier-0 branches, lines ~141-242) - - tests/golden/cli-output/host-check-tier-0-legacy-uses-nixos-module.{json,txt}, host-prepare-tier-0-legacy-uses-nixos-module.{json,txt}, host-destroy-tier-0-legacy-uses-nixos-module.{json,txt} - - tests/golden/cli-output/host-check-single-writer-conflict.{json,txt} and host-prepare-single-writer-conflict.{json,txt} (the refusal variants only) - - TODO.md (close the `Remove Tier-0 deployment-shape logic` entry, ~line 495) -- Approach: one atomic commit removes rows, anchors, generator branches, and goldens together, then regenerates via the fixture pipeline so the fixtures-proofs gate sees a consistent state. `single-writer-conflict` stays live at packages/d2b-provider-volume-local/src/error.rs:103; only the CLI refusal goldens that pin exit-78 outputs the CLI cannot produce are deleted. -- Test scenarios: - - `grep -rn "tier-0-legacy-uses-nixos-module" docs tests packages TODO.md` returns nothing. - - No refusal-variant `single-writer-conflict` entry remains in docs, the coverage table, the generator, or the CLI goldens (the volume-local provider mapping is the only live surface and its test stays green). - - The W3 closure test (`host_cli_error_golden_table_is_closed_and_complete`) passes with the reduced table. - - `make test-fixture-contracts` passes with regenerated goldens, proving the pipeline regenerates cleanly after the row removal. - - The volume-local provider error path still maps `SingleWriterConflict` to `single-writer-conflict` (its own tests stay green). -- Verification: `make test-unit` coverage tests pass; `make test-fixture-contracts` passes on the regenerated tree. - -### U4. Correct provider dossier references and extend the policy scan - -- Goal: dossiers cite the real tree, and the gate fails when they do not. -- Requirements: R4. Issue #589. Governs KTD8. -- Dependencies: none. -- Files: - - docs/specs/providers/ADR-046-provider-system-systemd.md (lines ~1296, 1351, 1361, 1468; crate name throughout) - - docs/specs/providers/ADR-046-provider-system-minijail.md (lines ~1583-1587) - - docs/specs/providers/*.md full sweep (the extended gate flags ~13 dossiers citing `d2b-priv-broker`, 3 citing `src/adoption.rs`, 1 citing `d2b-provider-system-systemd`; also docs/specs/ADR-046-*.md siblings carrying the same stale crate paths - decide with the gate glob, correcting the citation corpus the scan covers) - - packages/xtask/src/provider_crate_policy.rs (dangling-citation scan) - - changelog.d/ fragment -- Approach: correct crate names (`d2b-provider-process-systemd`, not `d2b-provider-system-systemd`) and deleted-module citations (`src/adoption.rs`; `d2b-priv-broker`; stale `d2bd/src/supervisor/*` paths). `d2b-realm-core` is LIVE (packages/d2b-realm-core exists; dossiers cite live files in it) - do not strip its citations. Extend the dangling-citation scan in `packages/xtask/src/provider_crate_policy.rs` from Rust-sources-only to also parse `Destination` / `Reuse path` / file-tree references in the dossier corpus and validate them against the tree; mentions behind an explicit historical marker stay legal. -- Test scenarios: - - A planted dossier citation of a deleted path fails the policy gate. - - A dossier citation of a live path (including packages/d2b-realm-core files) passes. - - `grep -rn "src/adoption.rs\|d2b-priv-broker\|d2b-provider-system-systemd" docs/specs` returns nothing (or only explicit historical markers). -- Verification: the provider-crate-policy gate runs green on the corrected dossiers and fails on a planted bad reference (test fixture). - -### U5. Fix the census clippy contract and diagnostics - -- Goal: the census clippy invocation matches the documented contract and its failures are actionable. -- Requirements: R7. Issue #585. Governs KTD9. -- Dependencies: none; must land before U6 so the meter is correct when the scanner is armed. -- Files: - - packages/xtask/src/blocking_census.rs (`run_clippy` ~761-791; module doc ~11-16) - - Cargo.toml census comment block (~158-163) if the byte-match reveals the doc itself needs the correction - - changelog.d/ fragment -- Approach: pass the documented de-escalation set (`-W warnings -W clippy::disallowed_methods -W clippy::await_holding_lock -W clippy::await_holding_refcell_ref`) so a stray lint counts instead of failing the gate; capture the full stderr and surface the first `file:line` diagnostic plus message on failure instead of the reversed last-15 tail; update the module doc comment from `allow` to the manifest's `deny` level. -- Test scenarios: - - `run_clippy` produces the exact flag sequence documented in Cargo.toml. - - A planted compile error in a covered crate reports the first diagnostic with file:line and message. - - A planted `await_holding_lock` site fails through the lint-counting path (counted), not the clippy-error path. - - A planted disallowed-method site likewise counts rather than erroring the gate. -- Verification: `make check-census` green; planted-error fixture test green. - -### U6. Arm async-gate method-call lock detection - -- Goal: the gate catches `m.lock()` on std::sync/parking_lot mutexes inside `async fn`, with the conservative shape and a documented escape hatch. -- Requirements: R3. Issue #590. Governs KTD4. -- Dependencies: U5. -- Files: - - packages/xtask/src/async_gate.rs (scanner, fixtures, doc comments) - - tests/tools/check-async-gate.sh (its "no violation allowlist" header must be rewritten with the new hatch contract) - - the named hatch inventory file this unit creates (single source-level marker format recorded there) - - packages/xtask/data/blocking-census-baseline.json (method-call rows updated together) - - Cargo.toml census comment block (~143-163) - - docs contributing gate prose that states the enforcement contract - - changelog.d/ fragment -- Approach: the scanner flags the conservative method-call shape - a lock/read/write method call inside an `async fn` NOT followed by `.await` (the `.await` exclusion is load-bearing: awaited `tokio::sync::Mutex::lock()` sites are legitimate and the census never sees them, since it counts only `clippy::disallowed_methods`). The escape hatch is a source-level marker the scanner honors, recorded in a named inventory file; the gate's "no violation allowlist" statement is rewritten to state the marker contract. The inventory covers EVERY method-call shape the armed scanner reports in the covered roots - production and test code (the gate scans tests like production code), not just the 33 census production sites. Derive the inventory from the scanner's own output over the default scan roots. The gate doc and the Cargo.toml comment state the same rule after the change. The qualified-form fixture stays green. -- Test scenarios: - - A planted `m.lock()` on a std::sync Mutex inside an `async fn` in a covered root fails `check-async-gate`. - - The same planted site with the documented source-level marker passes. - - A planted `m.lock().await` on a tokio Mutex passes (the `.await` exclusion). - - The qualified-path fixture still fails as before. - - A method-call lock site inside `#[tokio::test]` is flagged like production code (and passes only with the marker). - - The census baseline after U5 + U6 together is consistent with the scanner output (no row drift). -- Verification: `tests/tools/check-async-gate.sh` passes; planted-fixture gate test fails pre-fix and passes post-fix; `make check-census` green. - -### U7. Unify the d2bd test-support variant graph and re-include its tests - -- Goal: `bazel build //packages/d2bd:all-tests` green at pristine base; d2bd rejoins Layer-1 with its clippy gate. -- Requirements: R8. Issue #584. Governs KTD3. -- Dependencies: none. -- Files: - - packages/d2bd/BUILD.bazel - - packages/d2bd/Cargo.toml and BUILD-adjacent variant wiring following packages/d2b-core/BUILD.bazel:46-54 - - bazel/checks/BUILD.bazel (rust-main-packages inclusion; delete the exclusion comment at ~71-75) - - any volume/session/provider chains that pull `d2b_core_test_support` into the same link as `d2b_core` - - changelog.d/ fragment -- Approach: unify the variant graph so a test target links exactly one rlib per crate identity - the same mechanism d2b-core uses (`crate_features = ["test-support"]` on one rlib with a cfg-gated `test_support` module), applied down the volume/session/provider dependency chains that today produce `d2b_core` + `d2b_core_test_support` in one link. Re-include `//packages/d2bd:all-tests` in `rust-main-packages`; the per-target `_clippy` tests ride along. Add a guard test that fails when a target listed as excluded builds cleanly. -- Test scenarios: - - `bazel build //packages/d2bd:all-tests` green at pristine base. - - `bazel test //packages/d2bd:all-tests` green at pristine base. - - d2bd clippy targets green and present in the Layer-1 suite. - - A probe removing a per-package `all-tests` aggregate from the suite list (or tagging it out) fails the membership guard. - - The exclusion comment is gone from bazel/checks/BUILD.bazel. -- Verification: the named bazel commands at pristine base; `make check` includes the d2bd aggregate. - -### U8. Make the security scan a required check - -- Goal: a security finding on changed lines blocks the merge path; the in-tree workflow and the branch-protection setting both express it. -- Requirements: R6. Issue #586. Governs KTD5. -- Dependencies: none. -- Files: - - .github/workflows/pr-l1-static-fast.yml (new scan job in the aggregate `check` needs list) - - docs/contributing/workflow.md (scan and blocking status documented) - - AGENTS.md gates section pointer - - changelog.d/ fragment -- Approach: add a security-scan job that runs on pull requests, add it to the aggregate `check` job's `needs`, and set branch protection so its result is required on the protected branches. The branch-protection half is a hard dependency requiring settings access: attempt it via `gh api` with the credentials available in this environment; if the API is not reachable with the available authorization, record an explicit external blocker - name the exact required-check context to flip, open or annotate a tracking issue, and carry the blocker on the PR. Do not count the handoff as satisfying the enforcement outcome. External dependency: the scanner engine is not identifiable from the repo (the issue says so); once the owner names it, pin the exact action or command, its immutable version, required permissions, and the failure predicate that makes a finding fail the job; until named, the job wraps the named scanner as its first implementation step. -- Test scenarios: - - An end-to-end negative proof: a scratch PR carries a planted identifier-written-to-log violation; the scan job and the aggregate `check` both fail, and the job/context name matches what branch protection marks required. - - A clean branch triggers the scan job and merges without new maintainer steps. - - The workflow YAML is valid and the aggregate check fails when the scan job fails. -- Verification: workflow dry-run on a scratch branch with the planted violation observed failing; `gh api` probe of branch protection (or the recorded external blocker with the exact setting named); docs grep shows the documented blocking status. - -### U9. Investigate the systemd identity-read failure - -- Goal: establish the real cause of the failing identity read with captured evidence; fix at the correct layer with a regression test, or produce a documented disposition. -- Requirements: R5. Issue #587. Governs KTD7. -- Dependencies: none. -- Files: - - packages/d2b-unsafe-local-helper/src/systemd.rs (live read path: `query_scope`, `await_scope_identity`, 2s ready timeout, 20ms retries) - - packages/d2b-provider-process-systemd/src/operations.rs and src/lib.rs (conformance-side identity reads) - - packages/d2b-process-conformance/src/identity.rs - - a new regression test or a docs disposition note - - changelog.d/ fragment (if a fix lands) -- Approach: the issue's cited broker read site (`d2b-broker/src/ops/systemd.rs`) does not exist in the tree; discovery starts from the live helper and provider surfaces above. Reproduce against a real transient scope via the helper's scope path, capture the concrete zbus error (candidates per the issue: user-bus auth failure for the helper, InvocationID read before started state, broker-path METHOD_TIMEOUT, host environment quirk). Fix only at the established layer. No property-removal workaround, no fallback hashing, no optional-property reads. The environmental disposition requires a falsification matrix: exact NixOS and systemd versions, unit and credential configuration, reproduction command, and captured logs - the no-code disposition is valid only after the failure cannot reproduce inside that matrix. -- Execution note: investigation-first. Do not write the fix before the failing call and the concrete error are captured on the host. -- Test scenarios: - - The captured error and its reproduction command are recorded in the unit's output (evidence artifact). - - If a code fix lands: a regression test fails pre-fix and passes post-fix at the established layer. - - If environmental: the disposition document names the evidence, the probe commands, and the host condition. -- Verification: repro transcript exists; either the regression test fails without the fix and passes with it, or the disposition is committed with the evidence. - ---- - -## Verification Contract - -| Gate | Command | Applies to | -|---|---|---| -| Aggregate suite | `make check` | every unit | -| Focused unit tests | `make test-unit` | U3, U5, U6 | -| Nix unit cases | `make check` unit-nix cases (`net-vm-network.nix` unchanged) | U1 | -| Committed artifact regeneration | `make generate` | U1 | -| Bazel variant graph | `bazel build //packages/d2bd:all-tests`, `bazel test //packages/d2bd:all-tests` | U7 | -| Census | `make check-census` | U5, U6 | -| Async gate | `tests/tools/check-async-gate.sh` | U6 | -| Fixture contracts | `make test-fixture-contracts` | U3 | -| Policy gate | xtask provider-crate-policy run | U4 | -| Golden regeneration | regenerator under `tests/fixtures/gen-w3-cli-goldens.py` before committing | U3 | -| Changelog | fragment under `changelog.d/` per change | all units | - -No Bazel profile overrides anywhere; commands run exactly as documented. - ---- - -## Definition of Done - -- Every unit's verification commands pass on the repository's own configuration. -- `make check` is green with the d2bd tests and clippy targets included (U7 landed). -- `grep -rn "tier-0-legacy-uses-nixos-module" docs tests packages TODO.md` returns nothing. -- `grep -rn "microvm\." nixos-modules/ templates/ examples/ packages/ --include=*.nix --include=*.rs` returns nothing beyond historical ADR prose. -- The security scan job exists in the workflow and fails the aggregate `check` when a finding is reported; the branch-protection enforcement outcome is either set or carried as an explicit named external blocker (not counted as done). -- The #587 outcome is either a landed fix with a regression test or a documented disposition with captured evidence. -- Every change carries a changelog fragment under `changelog.d/`; no attribution markers anywhere; ASCII dashes only. -- Abandoned investigation paths and scratch scaffolding from any unit are removed before the wave lands. - ---- - -## Sources / Research - -- Issues #584, #585, #586, #587, #589, #590, #591, #592 (decision comments included). -- TODO.md entries: `Drop the microvm.* option namespace` (line ~346 outline) and the d2bd dual-rlib note. -- docs/adr/0018-microvm-nix-removal.md (migration map `microvm.*` -> `d2b.vms..runner.*`); docs/adr/0015-daemon-only-clean-break.md. -- Cargo.toml census contract comment (lines ~158-163); packages/xtask/src/async_gate.rs; packages/xtask/src/blocking_census.rs (run_clippy ~761-791); packages/xtask/src/provider_crate_policy.rs (dangling-citation scan, Rust-only today). -- packages/d2b/tests/cli_contract_coverage.rs (W3_ROWS, ~536-553); tests/fixtures/gen-w3-cli-goldens.py; tests/golden/cli-output/ committed goldens. -- packages/d2b-unsafe-local-helper/src/systemd.rs; packages/d2b-provider-process-systemd (identity reads); packages/d2b-process-conformance/src/identity.rs. -- packages/d2bd/BUILD.bazel (dual-rlib shape at ~238-284) and packages/d2b-core/BUILD.bazel (variant reference pattern at ~46-54); bazel/checks/BUILD.bazel exclusion at ~71-75. -- .github/workflows/pr-l1-static-fast.yml (aggregate `check` needs list). -- nixos-modules/assertions.nix namespace-containment lint; nixos-modules/vm-evaluator.nix read path. From 0c76962ef75defba22542b1084b159eb5d9ca570 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:24:13 -0700 Subject: [PATCH 536/726] audit: close the U3 wave gate green Four lanes pass at b81222ba1: security scan clean against the merge base, blocking census at its committed baseline, 988 of 988 tests, and 11 of 11 host vmChecks with the U20 acceptance providers built. All 286 wave rows carry an outcome. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index c59a0c6b3..9ab3455a7 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -39,6 +39,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | --- | --- | --- | --- | --- | --- | --- | | U1 | `11bbfe41a` | pass | pass | pass (988 of 988 tests) | pass (11 of 11 vmChecks) | First attempt flaked on the load-sensitive `daemon_state_persistence` kill-during-startup race (passes standalone, not an audit row); the retry is green. The head carries the refreshed async-gate inventory for the broker line shifts. | | U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | +| U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | ## Findings (965 rows) From 55b7d20a69dc6850f2645b634113d3cec3367163 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:25:03 -0700 Subject: [PATCH 537/726] d2b: add provider test coverage and shared pool fixture --- changelog.d/w3-47-provider-test-c.md | 9 ++ .../d2b-provider-provider/src/providers.rs | 28 ++++ .../tests/supervisor_runtime.rs | 150 +++--------------- .../tests/observe.rs | 2 +- .../tests/registration.rs | 3 +- .../d2b-provider-zone-link/src/zone_links.rs | 20 ++- 6 files changed, 79 insertions(+), 133 deletions(-) create mode 100644 changelog.d/w3-47-provider-test-c.md diff --git a/changelog.d/w3-47-provider-test-c.md b/changelog.d/w3-47-provider-test-c.md new file mode 100644 index 000000000..46901be6f --- /dev/null +++ b/changelog.d/w3-47-provider-test-c.md @@ -0,0 +1,9 @@ +### Changed + +- Provider test coverage tightened across five provider crates: the + `d2b-provider-provider` Degraded phase projection now has a direct + `plan_observed` test, the shell-terminal supervisor runtime tests share one + parameterized pool fixture instead of seven inline copies, and the + zone-link, transport-vsock, and wayland-policy tests now fail with a + per-case message (or a real assertion) instead of a bare line number or a + tautology. \ No newline at end of file diff --git a/packages/d2b-provider-provider/src/providers.rs b/packages/d2b-provider-provider/src/providers.rs index 14f1bd9cd..5b6b7bdcc 100644 --- a/packages/d2b-provider-provider/src/providers.rs +++ b/packages/d2b-provider-provider/src/providers.rs @@ -518,4 +518,32 @@ mod tests { assert_eq!(plan.phase(), ProviderPhase::Ready); assert!(plan.actions().is_empty()); } + + #[test] + fn plan_observed_projects_degraded_when_optional_components_degrade() { + let provider_ref = ResourceRef::parse("Provider/runtime").expect("fixture reference"); + let observation = ProviderObservation { + package_present: true, + config_valid: true, + graph_valid: true, + conformance_valid: true, + required_dependencies_ready: true, + required_components_ready: true, + optional_components_degraded: true, + components_drained: true, + }; + for intent in [ProviderIntent::Enable, ProviderIntent::Update] { + let plan = ProviderHandler::plan_observed(&provider_ref, intent, observation) + .expect("a ready observation plans"); + assert_eq!( + plan.phase(), + ProviderPhase::Degraded, + "{intent:?} with a degraded optional component must project Degraded" + ); + assert!( + plan.publish_exports(), + "{intent:?} with a degraded optional component must keep exports published" + ); + } + } } diff --git a/packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs b/packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs index 9afcdab8e..72101d5af 100644 --- a/packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs +++ b/packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs @@ -9,27 +9,27 @@ fn controller() -> ShellTerminalController { ShellTerminalController::new(Arc::new(InMemoryShellAuthority::new())) } +fn pool(name: &str, max_sessions: u32, max_attached: u32) -> ShellPool { + ShellPool::new( + name, + "dev", + PoolSpec::new( + ExecutionTarget::guest("work"), + "alice", + "artifact://shells/bash-login", + max_sessions, + max_attached, + 4096, + ) + .unwrap(), + ) + .unwrap() +} + #[test] fn supervisor_rejects_stale_generation_and_reused_capability() { let mut controller = controller(); - controller - .insert_pool( - ShellPool::new( - "guest-alice", - "dev", - PoolSpec::new( - ExecutionTarget::guest("work"), - "alice", - "artifact://shells/bash-login", - 1, - 1, - 4096, - ) - .unwrap(), - ) - .unwrap(), - ) - .unwrap(); + controller.insert_pool(pool("guest-alice", 1, 1)).unwrap(); let admin = Subject::new("dev", CallerOrigin::Local, [Role::ShellAdmin]); let opened = controller .open_session( @@ -76,24 +76,7 @@ fn supervisor_rejects_stale_generation_and_reused_capability() { #[test] fn detach_releases_the_bounded_attachment_slot() { let mut controller = controller(); - controller - .insert_pool( - ShellPool::new( - "guest-alice", - "dev", - PoolSpec::new( - ExecutionTarget::guest("work"), - "alice", - "artifact://shells/bash-login", - 1, - 1, - 4096, - ) - .unwrap(), - ) - .unwrap(), - ) - .unwrap(); + controller.insert_pool(pool("guest-alice", 1, 1)).unwrap(); let admin = Subject::new("dev", CallerOrigin::Local, [Role::ShellAdmin]); let opened = controller .open_session( @@ -137,24 +120,7 @@ fn detach_releases_the_bounded_attachment_slot() { fn capability_cannot_attach_a_different_session() { let mut controller = controller(); for (name, session) in [("guest-alice", "main"), ("guest-bob", "other")] { - controller - .insert_pool( - ShellPool::new( - name, - "dev", - PoolSpec::new( - ExecutionTarget::guest("work"), - "alice", - "artifact://shells/bash-login", - 1, - 1, - 4096, - ) - .unwrap(), - ) - .unwrap(), - ) - .unwrap(); + controller.insert_pool(pool(name, 1, 1)).unwrap(); assert!( OpenSessionRequest::new(name, session, None).is_ok(), "fixture request must be valid" @@ -188,24 +154,7 @@ fn capability_cannot_attach_a_different_session() { #[test] fn attachments_share_the_pool_limit_across_sessions() { let mut controller = controller(); - controller - .insert_pool( - ShellPool::new( - "guest-alice", - "dev", - PoolSpec::new( - ExecutionTarget::guest("work"), - "alice", - "artifact://shells/bash-login", - 2, - 1, - 4096, - ) - .unwrap(), - ) - .unwrap(), - ) - .unwrap(); + controller.insert_pool(pool("guest-alice", 2, 1)).unwrap(); let admin = Subject::new("dev", CallerOrigin::Local, [Role::ShellAdmin]); let first = controller .open_session( @@ -250,24 +199,7 @@ fn attachments_share_the_pool_limit_across_sessions() { #[test] fn attachment_cannot_be_detached_by_a_different_session() { let mut controller = controller(); - controller - .insert_pool( - ShellPool::new( - "guest-alice", - "dev", - PoolSpec::new( - ExecutionTarget::guest("work"), - "alice", - "artifact://shells/bash-login", - 2, - 1, - 4096, - ) - .unwrap(), - ) - .unwrap(), - ) - .unwrap(); + controller.insert_pool(pool("guest-alice", 2, 1)).unwrap(); let admin = Subject::new("dev", CallerOrigin::Local, [Role::ShellAdmin]); let first = controller .open_session( @@ -315,24 +247,7 @@ fn attachment_cannot_be_detached_by_a_different_session() { #[test] fn supervisor_replays_output_recorded_before_reconnect() { let mut controller = controller(); - controller - .insert_pool( - ShellPool::new( - "guest-alice", - "dev", - PoolSpec::new( - ExecutionTarget::guest("work"), - "alice", - "artifact://shells/bash-login", - 1, - 1, - 4096, - ) - .unwrap(), - ) - .unwrap(), - ) - .unwrap(); + controller.insert_pool(pool("guest-alice", 1, 1)).unwrap(); let admin = Subject::new("dev", CallerOrigin::Local, [Role::ShellAdmin]); let opened = controller .open_session( @@ -362,24 +277,7 @@ fn supervisor_replays_output_recorded_before_reconnect() { #[test] fn capacity_denial_does_not_consume_the_one_shot_capability() { let mut controller = controller(); - controller - .insert_pool( - ShellPool::new( - "guest-alice", - "dev", - PoolSpec::new( - ExecutionTarget::guest("work"), - "alice", - "artifact://shells/bash-login", - 1, - 1, - 4096, - ) - .unwrap(), - ) - .unwrap(), - ) - .unwrap(); + controller.insert_pool(pool("guest-alice", 1, 1)).unwrap(); let admin = Subject::new("dev", CallerOrigin::Local, [Role::ShellAdmin]); let opened = controller .open_session( diff --git a/packages/d2b-provider-transport-vsock/tests/observe.rs b/packages/d2b-provider-transport-vsock/tests/observe.rs index e1c7b2a50..2d8d66267 100644 --- a/packages/d2b-provider-transport-vsock/tests/observe.rs +++ b/packages/d2b-provider-transport-vsock/tests/observe.rs @@ -12,5 +12,5 @@ fn released_observation_is_identity_free_and_bounded() { last_exit: Some(d2b_provider_transport_vsock::BridgeExit::OwnerClosed), }; assert_eq!(observation.phase, TransportPhase::Released); - assert_eq!(ServicePhase::Ready, ServicePhase::Ready); + assert_ne!(ServicePhase::Ready, ServicePhase::Serving); } diff --git a/packages/d2b-provider-wayland-policy/tests/registration.rs b/packages/d2b-provider-wayland-policy/tests/registration.rs index 96aa35c60..456cdbec9 100644 --- a/packages/d2b-provider-wayland-policy/tests/registration.rs +++ b/packages/d2b-provider-wayland-policy/tests/registration.rs @@ -90,5 +90,6 @@ fn the_policy_envelope_is_the_whole_contract() { .is_empty() ); assert!(wayland_policy_spec_decoder().decode(b"[]").is_err()); - let _ = ResourceRef::parse("display-wayland.d2bus.org.WaylandPolicy/policy"); + ResourceRef::parse("display-wayland.d2bus.org.WaylandPolicy/policy") + .expect("the policy reference parses"); } diff --git a/packages/d2b-provider-zone-link/src/zone_links.rs b/packages/d2b-provider-zone-link/src/zone_links.rs index 22e14e1fd..c3f98c54b 100644 --- a/packages/d2b-provider-zone-link/src/zone_links.rs +++ b/packages/d2b-provider-zone-link/src/zone_links.rs @@ -2562,7 +2562,10 @@ mod tests { ZoneLinkSessionState::EnrollmentCommitted, ZoneLinkSessionState::Kk, ] { - assert!(!state.permits_resource_traffic()); + assert!( + !state.permits_resource_traffic(), + "state: {state:?} must not permit resource traffic" + ); } assert_eq!( refused( @@ -3136,7 +3139,10 @@ mod tests { fn metric_labels_carry_no_identity() { let forbidden = ["vm", "zone", "zone_id", "zone_uid", "link_name_hash"]; for key in ZONE_LINK_METRIC_LABEL_KEYS { - assert!(!forbidden.contains(key), "forbidden metric label key"); + assert!( + !forbidden.contains(key), + "key: {key} must not be a forbidden metric label key" + ); } let canary = "k1-uplink"; let samples = [ @@ -3205,13 +3211,17 @@ mod tests { ZoneLinkError::RouteAdmissionDedupConflict, ] { let label = error.label(); - assert!(!label.is_empty() && label.len() <= 64); + assert!( + !label.is_empty() && label.len() <= 64, + "error: {error:?} label must be a non-empty bounded token" + ); assert!( label .chars() - .all(|character| character.is_ascii_lowercase() || character == '-') + .all(|character| character.is_ascii_lowercase() || character == '-'), + "error: {error:?} label must be lowercase-and-dash" ); - assert_eq!(error.to_string(), label); + assert_eq!(error.to_string(), label, "error: {error:?}"); } assert_eq!( ZoneLinkError::Disconnected.label(), From 56382076658a28d55aef111b561891045ac5be0a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:25:59 -0700 Subject: [PATCH 538/726] test: strengthen provider test assertions across four crates Activation-nixos verification fences now report the failing case and expected error; the credential-entra consumer guard test exercises authorizes_consumer instead of comparing parse results; device-gpu admission rejection vectors cover zero tokens and arbitration contradictions; Azure VM error codes are pinned exactly. --- changelog.d/w3-45-provider-test-a.md | 5 + .../tests/reconcile.rs | 7 +- .../d2b-provider-credential-entra/src/lib.rs | 41 ++++- .../d2b-provider-device-gpu/src/authority.rs | 171 ++++++++++++++++++ .../tests/error_redaction.rs | 38 ++-- 5 files changed, 235 insertions(+), 27 deletions(-) create mode 100644 changelog.d/w3-45-provider-test-a.md diff --git a/changelog.d/w3-45-provider-test-a.md b/changelog.d/w3-45-provider-test-a.md new file mode 100644 index 000000000..b8c1327cf --- /dev/null +++ b/changelog.d/w3-45-provider-test-a.md @@ -0,0 +1,5 @@ +### Fixed + +- Activation-nixos verification-fence failures now name the failing case and expected error instead of reporting only a line number, so a six-case regression identifies which trust or digest fence broke. +- The credential-entra consumer guard test now exercises `authorizes_consumer` against the exact Provider reference and a different one, so a guard regression fails the test instead of passing on two unrelated parse results. +- The Azure VM error test now pins each stable error code exactly, so an accidental code change is caught instead of an always-true emptiness check. \ No newline at end of file diff --git a/packages/d2b-provider-activation-nixos/tests/reconcile.rs b/packages/d2b-provider-activation-nixos/tests/reconcile.rs index 67c2d15f3..555c8af87 100644 --- a/packages/d2b-provider-activation-nixos/tests/reconcile.rs +++ b/packages/d2b-provider-activation-nixos/tests/reconcile.rs @@ -436,17 +436,18 @@ fn activation_verification_requires_all_trust_and_digest_fences() { vec![0; 64], )); - for (trust, expected_error) in cases.into_iter().zip([ + for (i, (trust, expected_error)) in cases.into_iter().zip([ d2b_provider_activation_nixos::ActivationVerificationError::TrustEpochMismatch, d2b_provider_activation_nixos::ActivationVerificationError::RevocationRefMismatch, d2b_provider_activation_nixos::ActivationVerificationError::TrustDenied, d2b_provider_activation_nixos::ActivationVerificationError::TrustDenied, d2b_provider_activation_nixos::ActivationVerificationError::PublisherRootMismatch, d2b_provider_activation_nixos::ActivationVerificationError::SignatureIdMismatch, - ]) { + ]).enumerate() { assert_eq!( trust.verify(&expected, &artifact, &catalog_digest), - Err(expected_error) + Err(expected_error), + "case {i}: expected {expected_error:?}", ); } } diff --git a/packages/d2b-provider-credential-entra/src/lib.rs b/packages/d2b-provider-credential-entra/src/lib.rs index 62e80ec5f..ba4c2dbc0 100644 --- a/packages/d2b-provider-credential-entra/src/lib.rs +++ b/packages/d2b-provider-credential-entra/src/lib.rs @@ -1391,9 +1391,44 @@ mod tests { #[test] fn exact_consumer_guard_is_independent_of_request_fields() { - let expected = ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap(); - let other = ResourceRef::parse("Provider/other").unwrap(); - assert_ne!(expected, other); + struct StubClient; + impl EntraCredentialClient for StubClient { + fn state(&self) -> EntraFuture<'_, EntraClientState> { + unreachable!("guard test never drives the client") + } + fn issue_lease(&self, _: &EntraLeaseRequest) -> EntraFuture<'_, EntraLeaseGrant> { + unreachable!("guard test never drives the client") + } + fn inspect_lease(&self, _: &EntraLeaseRef) -> EntraFuture<'_, EntraLeaseInspection> { + unreachable!("guard test never drives the client") + } + fn refresh_lease(&self, _: &EntraLeaseRef) -> EntraFuture<'_, EntraLeaseRenewal> { + unreachable!("guard test never drives the client") + } + fn revoke_lease(&self, _: &EntraLeaseRef) -> EntraFuture<'_, EntraLeaseRevocation> { + unreachable!("guard test never drives the client") + } + } + let provider = EntraCredentialProviderFactory::new( + EntraConfig::new("tenant-1234", 64).unwrap(), + EntraPlacement::new_in_zone( + ResourceRef::parse("Zone/work").unwrap(), + PlacementBinding::GuestAgent, + ResourceRef::parse("Guest/consumer").unwrap(), + ResourceRef::parse("Guest/identity").unwrap(), + ResourceRef::parse("Endpoint/entra-login").unwrap(), + 7, + ) + .unwrap(), + ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap(), + Arc::new(StubClient), + ) + .unwrap() + .construct(); + assert!(provider.authorizes_consumer( + &ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap() + )); + assert!(!provider.authorizes_consumer(&ResourceRef::parse("Provider/other").unwrap())); } #[test] diff --git a/packages/d2b-provider-device-gpu/src/authority.rs b/packages/d2b-provider-device-gpu/src/authority.rs index cb0d73ca5..983292461 100644 --- a/packages/d2b-provider-device-gpu/src/authority.rs +++ b/packages/d2b-provider-device-gpu/src/authority.rs @@ -416,3 +416,174 @@ impl fmt::Display for GpuAuthorityError { } impl std::error::Error for GpuAuthorityError {} + +#[cfg(test)] +mod tests { + use super::*; + + fn uid(value: &str) -> ResourceUid { + ResourceUid::parse(value).unwrap() + } + + fn owner_proof() -> GpuOwnerProof { + GpuOwnerProof::new( + ResourceRef::parse("Zone/dev").unwrap(), + ResourceRef::parse("Guest/workload").unwrap(), + uid("123e4567-e89b-42d3-a456-426614174000"), + uid("223e4567-e89b-42d3-a456-426614174001"), + ResourceGeneration::new(1).unwrap(), + ) + .unwrap() + } + + fn admission( + backing: GpuBackingToken, + platform: GpuPlatformToken, + arbitration: DeviceArbitration, + max_holders: u32, + render_node_only: bool, + principal: GpuPrincipalToken, + ) -> Result { + GpuAuthorityAdmission::new( + owner_proof(), + backing, + platform, + arbitration, + max_holders, + render_node_only, + principal, + ) + } + + #[test] + fn admission_rejects_zero_identities_and_arbitration_contradictions() { + let backing = GpuBackingToken::from_core([7; 32]); + let platform = GpuPlatformToken::from_core([8; 32]); + let principal = GpuPrincipalToken::from_core([9; 32]); + let cases = [ + ( + GpuBackingToken::from_core([0; 32]), + platform.clone(), + DeviceArbitration::Exclusive, + 1, + false, + principal.clone(), + GpuAuthorityError::StaleDeviceIdentity, + ), + ( + backing.clone(), + GpuPlatformToken::from_core([0; 32]), + DeviceArbitration::Exclusive, + 1, + false, + principal.clone(), + GpuAuthorityError::StaleDeviceIdentity, + ), + ( + backing.clone(), + platform.clone(), + DeviceArbitration::Exclusive, + 1, + false, + GpuPrincipalToken::from_core([0; 32]), + GpuAuthorityError::StaleDeviceIdentity, + ), + ( + backing.clone(), + platform.clone(), + DeviceArbitration::Exclusive, + 0, + false, + principal.clone(), + GpuAuthorityError::ArbitrationViolation, + ), + ( + backing.clone(), + platform.clone(), + DeviceArbitration::Exclusive, + 17, + false, + principal.clone(), + GpuAuthorityError::ArbitrationViolation, + ), + ( + backing.clone(), + platform.clone(), + DeviceArbitration::Exclusive, + 2, + false, + principal.clone(), + GpuAuthorityError::ArbitrationViolation, + ), + ( + backing.clone(), + platform.clone(), + DeviceArbitration::Exclusive, + 2, + true, + principal.clone(), + GpuAuthorityError::ArbitrationViolation, + ), + ( + backing.clone(), + platform.clone(), + DeviceArbitration::Shared, + 2, + false, + principal.clone(), + GpuAuthorityError::ArbitrationViolation, + ), + ( + backing, + platform, + DeviceArbitration::Shared, + 0, + true, + principal, + GpuAuthorityError::ArbitrationViolation, + ), + ]; + for (i, (backing, platform, arbitration, max_holders, render_node_only, principal, expected)) in + cases.into_iter().enumerate() + { + assert_eq!( + admission( + backing, + platform, + arbitration, + max_holders, + render_node_only, + principal, + ), + Err(expected), + "case {i}: expected {expected:?}", + ); + } + } + + #[test] + fn admission_accepts_exclusive_and_shared_legal_combinations() { + let backing = GpuBackingToken::from_core([7; 32]); + let platform = GpuPlatformToken::from_core([8; 32]); + let principal = GpuPrincipalToken::from_core([9; 32]); + for (arbitration, max_holders, render_node_only) in [ + (DeviceArbitration::Exclusive, 1, false), + (DeviceArbitration::Exclusive, 1, true), + (DeviceArbitration::Shared, 1, true), + (DeviceArbitration::Shared, 16, true), + ] { + assert!( + admission( + backing.clone(), + platform.clone(), + arbitration, + max_holders, + render_node_only, + principal.clone(), + ) + .is_ok(), + "legal combination {arbitration:?}/{max_holders}/{render_node_only} rejected", + ); + } + } +} diff --git a/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs b/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs index 07e753e0c..97bff0db4 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs @@ -15,25 +15,21 @@ fn errors_and_handles_do_not_render_remote_values() { #[test] fn every_controller_error_has_a_documented_stable_code() { - for error in [ - AzureVmError::ArmQuotaExceeded, - AzureVmError::ArmResourceConflict, - AzureVmError::ArmProvisioningFailed, - AzureVmError::ArmNetworkUnavailable, - AzureVmError::ArmCredentialDenied, - AzureVmError::ArmThrottled, - AzureVmError::BootstrapPskExpired, - AzureVmError::BootstrapPskReplayed, - AzureVmError::BootstrapEnrollmentFailed, - AzureVmError::BootstrapFailed, - AzureVmError::CredentialUnavailable, - AzureVmError::InvalidOperationHandle, - AzureVmError::InvalidConfiguration, - AzureVmError::Transient, - AzureVmError::Cancelled, - AzureVmError::DeadlineExpired, - AzureVmError::Ambiguous, - ] { - assert!(!error.code().is_empty()); - } + assert_eq!(AzureVmError::ArmQuotaExceeded.code(), "arm-quota-exceeded"); + assert_eq!(AzureVmError::ArmResourceConflict.code(), "arm-resource-conflict"); + assert_eq!(AzureVmError::ArmProvisioningFailed.code(), "arm-provisioning-failed"); + assert_eq!(AzureVmError::ArmNetworkUnavailable.code(), "arm-network-unavailable"); + assert_eq!(AzureVmError::ArmCredentialDenied.code(), "arm-credential-denied"); + assert_eq!(AzureVmError::ArmThrottled.code(), "arm-throttled"); + assert_eq!(AzureVmError::BootstrapPskExpired.code(), "bootstrap-psk-expired"); + assert_eq!(AzureVmError::BootstrapPskReplayed.code(), "bootstrap-psk-replayed"); + assert_eq!(AzureVmError::BootstrapEnrollmentFailed.code(), "bootstrap-enrollment-failed"); + assert_eq!(AzureVmError::BootstrapFailed.code(), "bootstrap-failed"); + assert_eq!(AzureVmError::CredentialUnavailable.code(), "credential-unavailable"); + assert_eq!(AzureVmError::InvalidOperationHandle.code(), "azure-operation-handle-invalid"); + assert_eq!(AzureVmError::InvalidConfiguration.code(), "azure-vm-config-invalid"); + assert_eq!(AzureVmError::Transient.code(), "transient"); + assert_eq!(AzureVmError::Cancelled.code(), "cancelled"); + assert_eq!(AzureVmError::DeadlineExpired.code(), "deadline-expired"); + assert_eq!(AzureVmError::Ambiguous.code(), "azure-operation-ambiguous"); } From 9a8caf31c5203fa31eb9f1257f2d8b8eec9416d2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:28:24 -0700 Subject: [PATCH 539/726] d2bd: drop dead per-reconcile digests and pre-size hot vectors RS-0800: the Cloud Hypervisor session's UpdateSpec, UpdateStatus and DeleteChild arms each built an operation payload, ran a full SHA-256 canonical digest and formatted an operation id that no caller reads, on every provider status/spec update. Delete the dead computation and the let _ bindings that kept it alive. RS-0801: resource_identity_fields grows from an empty Vec for exactly twelve statically known identity columns; pre-size it. RS-0802: AsyncSeqpacket::read_frame allocated the one-megabyte ceiling buffer per read (drain_pending up to four per refused call). Peek the four-byte length prefix and allocate declared + 5 instead. RS-0803: pre-size guest_uids from the spec attachment count and the audio status result vectors from the VM name set. --- changelog.d/w3-37-d2bd-perf.md | 13 +++++ packages/d2bd/src/audio_dispatch.rs | 9 ++- packages/d2bd/src/forward_rendezvous.rs | 42 +++++++++++++- packages/d2bd/src/process_provider_runtime.rs | 2 +- packages/d2bd/src/resource_runtime.rs | 58 +------------------ packages/d2bd/src/shared_provider_effects.rs | 2 +- 6 files changed, 63 insertions(+), 63 deletions(-) create mode 100644 changelog.d/w3-37-d2bd-perf.md diff --git a/changelog.d/w3-37-d2bd-perf.md b/changelog.d/w3-37-d2bd-perf.md new file mode 100644 index 000000000..3189d7b8d --- /dev/null +++ b/changelog.d/w3-37-d2bd-perf.md @@ -0,0 +1,13 @@ +### Fixed + +- `d2bd` no longer computes a discarded SHA-256 operation digest plus a + formatted operation id on every Cloud Hypervisor spec/status update and + child deletion: the dead canonical-digest chain is gone from the + reconcile hot path (RS-0800). +- Resource identity projections are pre-sized to their field count + (twelve required+optional identity columns) and audio status queries to + their VM set, bounding a refused call's allocations on frequently- + repeated provider relists (RS-0801, RS-0803). +- The forward rendezvous sizes frame read buffers from the length-prefixed + datagram instead of the one-megabyte ceiling, so a drain of refused + frames no longer allocates the ceiling per read (RS-0802). \ No newline at end of file diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index 13a16e9ca..5980d4904 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -397,10 +397,10 @@ fn dispatch_audio_status( args: AudioStatusArgs, ) -> Result { let manifest: ManifestV04 = crate::load_json(&state.config.artifacts.public_manifest_path)?; - let mut entries: Vec = Vec::new(); - let mut errors: Vec = Vec::new(); - // Collect the set of VMs to query. + // Collect the set of VMs to query before sizing the result buffers: the + // only lower bound on admission of that set, so both grow-by-push lists + // below are pre-sized to it instead of starting empty (RS-0803). let vm_names: Vec = if args.vms.is_empty() { manifest .vms @@ -412,6 +412,9 @@ fn dispatch_audio_status( args.vms.clone() }; + let mut entries: Vec = Vec::with_capacity(vm_names.len()); + let mut errors: Vec = Vec::with_capacity(vm_names.len()); + for vm_name in &vm_names { match resolve_vm_audio_status(state, vm_name, &manifest, caller_role.clone()) { Ok(vm_state) => entries.push(vm_state), diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index 793f48d4c..f7093356b 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -1364,8 +1364,48 @@ impl AsyncSeqpacket { } /// Read one frame, waiting at most `deadline` for it to arrive. + // R11 inventory note: genuinely synchronous path - the `nix::sys::socket` + // recv runs inside the `AsyncFd::async_io` readiness closure on a + // non-blocking descriptor (the clippy.toml replacement vocabulary names + // this exact AsyncFd-over-raw-socket shape as the sanctioned seam); the + // syscall never blocks because readiness was already observed. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub(crate) async fn read_frame(&self, deadline: Duration) -> Result, TypedError> { - let mut datagram = vec![0u8; MAX_FRAME_SIZE + 5]; + // The frame is length-prefixed, so peek the four-byte prefix and + // size the datagram buffer from the declared length instead of the + // ceiling: drain_pending reads up to four frames per refused call, + // and the ceiling buffer is 1 MiB. + let mut prefix = [0u8; 4]; + let peeked = match tokio::time::timeout( + deadline, + self.io.async_io(Interest::READABLE, |socket| { + recv(socket.as_raw_fd(), &mut prefix, MsgFlags::MSG_PEEK) + .map_err(|errno| io::Error::from_raw_os_error(errno as i32)) + }), + ) + .await + { + Ok(Ok(read)) => read, + Ok(Err(error)) => return Err(recv_failure(error.to_string())), + Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"))), + }; + if peeked < 4 { + // A datagram shorter than the prefix is malformed; consume it + // so the next read starts clean, refusing it exactly as the + // ceiling-buffer read did. + let mut short = [0u8; 4]; + let read = match tokio::time::timeout(deadline, self.recv_datagram(&mut short)).await { + Ok(Ok(read)) => read, + Ok(Err(error)) => return Err(recv_failure(error.to_string())), + Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"))), + }; + return decode_frame(&short[..read]); + } + let declared = u32::from_le_bytes(prefix) as usize; + if declared > MAX_FRAME_SIZE { + return Err(TypedError::WireFrameTooLarge { declared }); + } + let mut datagram = vec![0u8; declared + 5]; let read = match tokio::time::timeout(deadline, self.recv_datagram(&mut datagram)).await { Ok(Ok(read)) => read, Ok(Err(error)) => return Err(recv_failure(error.to_string())), diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index a54828f95..e1d7aacdb 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -330,7 +330,7 @@ fn resource_identity_fields( requested, }); } - let mut fields = Vec::new(); + let mut fields = Vec::with_capacity(12); required( &mut fields, "zone", diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index cfb1c1d9d..89713c5db 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -2359,22 +2359,6 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { )?; let payload = replace_public_field(¤t_value, "spec", merged_spec) .map_err(|_| CloudHypervisorResourceApiError::InvalidResponse)?; - let mut operation_payload = format!( - "{}:{}:", - update.expected_uid().as_str(), - update.expected_revision().get(), - ) - .into_bytes(); - operation_payload.extend_from_slice(&payload); - let payload_operation_digest = - d2b_contracts_resource::v3::resource_schema::canonical_digest( - d2b_contracts_resource::v3::resource_schema::RESOURCE_ENVELOPE_DOMAIN_TAG, - &operation_payload, - ); - let operation_id = format!( - "ch-update-child-{}", - payload_operation_digest.trim_start_matches("sha256:") - ); let envelope = ResourceEnvelope::from_json(¤t.canonical_json) .map_err(|_| CloudHypervisorResourceApiError::InvalidResponse)?; let owner_ref = envelope @@ -2420,7 +2404,6 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { // an update that did not route to the manager names a row // this plane does not serve: refuse closed rather than write // a pre-v3 row no actor would launch (KTD4). - let _ = (&owner_ref, &payload, &operation_id); Err(CloudHypervisorResourceApiError::Conflict) } CloudHypervisorResourceRequest::UpdateStatus { guest_ref, status } => { @@ -2472,37 +2455,6 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { { return Ok(CloudHypervisorResourceResponse::StatusUpdated); } - let mut payload_value = current_value; - let base_status = payload_value - .get_mut("status") - .and_then(Value::as_object_mut) - .ok_or_else(|| { - tracing::warn!("Cloud Hypervisor status update failed: status-replacement"); - CloudHypervisorResourceApiError::InvalidResponse - })?; - base_status.insert("resource".to_owned(), desired_status.clone()); - base_status.insert("phase".to_owned(), public_phase); - base_status.insert( - "observedGeneration".to_owned(), - Value::from(current.generation.get()), - ); - let payload_bytes = serde_json::to_vec(&payload_value) - .map_err(|_| CloudHypervisorResourceApiError::InvalidResponse)?; - let payload = CanonicalJsonValue::parse(&payload_bytes) - .map_err(|_| CloudHypervisorResourceApiError::InvalidResponse)? - .to_canonical_bytes(); - let mut operation_payload = - format!("{}:{}:", current.uid.as_str(), current.revision.get()).into_bytes(); - operation_payload.extend_from_slice(&payload); - let payload_operation_digest = - d2b_contracts_resource::v3::resource_schema::canonical_digest( - d2b_contracts_resource::v3::resource_schema::RESOURCE_ENVELOPE_DOMAIN_TAG, - &operation_payload, - ); - let operation_id = format!( - "ch-update-status-{}", - payload_operation_digest.trim_start_matches("sha256:") - ); // U12 status decision: `Guest` is a converted type, so its // row has no durable status to write - the row's actor owns // status (R11). The controller's layered status is captured @@ -2510,12 +2462,9 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { // the row's `status.resource` projection; a session with no // capture point (an explicit lifecycle relist) acknowledges // the write without persisting it. Converted children never - // receive a provider-written status either: the Process and + // never receive a provider-written status either: the Process and // Endpoint drivers' `Ready` is the only publication, and // writing one here as well would be a dual-write. - let _ = ¤t; - let _ = &payload; - let _ = &operation_id; if let Some(sink) = self.status_sink.as_ref() { #[allow(clippy::disallowed_methods, reason = "synchronous path")] { @@ -2866,11 +2815,6 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { if envelope.metadata().owner_ref() != Some(&guest_ref) { return Err(CloudHypervisorResourceApiError::Conflict); } - let _operation_id = format!( - "cloud-hypervisor-delete-child-{}-{}", - child.uid().as_str(), - child.revision().get(), - ); if child_mutation_route(child.target()) == ChildMutationRoute::Manager { // U17: the manager marks a converted child deleting and // cascades; the child's own actor owns the cleanup. diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 2fa552f12..5e4084528 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -1058,7 +1058,7 @@ impl ProductionSharedProviderEffects { .ok_or(SharedProviderEffectError::Unavailable)?; let network_generation = request.generation; let network_ref = key_ref(&request.target).to_canonical_string(); - let mut guest_uids = Vec::new(); + let mut guest_uids = Vec::with_capacity(spec.attachments().len()); let mut attachment_generation = network_generation.get(); for attachment in spec.attachments() { let attached = self From 868fbdbf8814651f3c1026433b09cedd5c04088c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:29:48 -0700 Subject: [PATCH 540/726] secret-service: scope the cached session-key lock in both admission branches The cached-key branch previously held the user_sessions guard while awaiting the sessions lock, inverting the order used by the issue branch (sessions first, then user_sessions) and opening a latent AB-BA deadlock that the outer mutation gate and entry timing happened to mask. Read the user_ref-to-key mapping under a short-lived guard and copy the key before locking sessions, so both branches acquire in one consistent order. The placement, faults, and collection-alias table-driven tests now pass a case: message with each assertion so a regression names the failing case instead of only the source line. --- changelog.d/w3-42-secret-service-async.md | 9 +++++++++ .../src/lib.rs | 14 +++----------- .../tests/faults.rs | 9 +++++++-- .../tests/placement.rs | 6 ++++-- 4 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 changelog.d/w3-42-secret-service-async.md diff --git a/changelog.d/w3-42-secret-service-async.md b/changelog.d/w3-42-secret-service-async.md new file mode 100644 index 000000000..e29fc44ed --- /dev/null +++ b/changelog.d/w3-42-secret-service-async.md @@ -0,0 +1,9 @@ +### Fixed + +- Cached user-session reuse in the secret-service provider no longer inverts + the lock order between the session map and the per-user session map, so a + concurrent cached-key admission cannot stall behind an acquire that is + waiting for the provider to unlock. +- Credential secret-service table-driven tests now name the failing case when + an assertion trips, so a regression reports which placement, binding, or + alias text was rejected instead of only the line number. diff --git a/packages/d2b-provider-credential-secret-service/src/lib.rs b/packages/d2b-provider-credential-secret-service/src/lib.rs index ef385d201..7b6957434 100644 --- a/packages/d2b-provider-credential-secret-service/src/lib.rs +++ b/packages/d2b-provider-credential-secret-service/src/lib.rs @@ -1370,17 +1370,9 @@ impl SecretServiceCredentialProvider { .insert(user_ref.clone(), key); return Ok(key); } - if let Some(key) = self - .user_sessions - .lock() - .await - .get(user_ref) - .copied() - && self - .sessions - .lock() - .await - .contains_key(&key) + let cached_key = self.user_sessions.lock().await.get(user_ref).copied(); + if let Some(key) = cached_key + && self.sessions.lock().await.contains_key(&key) { return Ok(key); } diff --git a/packages/d2b-provider-credential-secret-service/tests/faults.rs b/packages/d2b-provider-credential-secret-service/tests/faults.rs index 6e25f9629..f9e45e130 100644 --- a/packages/d2b-provider-credential-secret-service/tests/faults.rs +++ b/packages/d2b-provider-credential-secret-service/tests/faults.rs @@ -35,9 +35,14 @@ fn locked_and_unavailable_map_to_provider_unavailable() { .call(CredentialMethod::AcquireToken, request("idem-failure")) .unwrap_err() .code(), - CredentialServiceErrorCode::ProviderUnavailable + CredentialServiceErrorCode::ProviderUnavailable, + "case: {failure:?}" + ); + assert_eq!( + port.issue_calls.load(Ordering::SeqCst), + 1, + "case: {failure:?}" ); - assert_eq!(port.issue_calls.load(Ordering::SeqCst), 1); } } diff --git a/packages/d2b-provider-credential-secret-service/tests/placement.rs b/packages/d2b-provider-credential-secret-service/tests/placement.rs index 1581f5660..2bacc8eaf 100644 --- a/packages/d2b-provider-credential-secret-service/tests/placement.rs +++ b/packages/d2b-provider-credential-secret-service/tests/placement.rs @@ -13,7 +13,8 @@ fn only_user_agent_on_host_or_guest_is_accepted() { ResourceRef::parse(execution).unwrap(), user.clone(), ) - .is_ok() + .is_ok(), + "case: {execution:?}", ); } for binding in [PlacementBinding::HostSystem, PlacementBinding::GuestAgent] { @@ -24,7 +25,8 @@ fn only_user_agent_on_host_or_guest_is_accepted() { ResourceRef::parse("Guest/work-vm").unwrap(), user.clone(), ), - Err(SecretServiceProviderError::InvalidPlacement) + Err(SecretServiceProviderError::InvalidPlacement), + "case: {binding:?}", ); } } From 2a9b379e2e72e2270e5c59042c1002b17d846156 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:42:40 -0700 Subject: [PATCH 541/726] d2bd: relax standalone interaction ordering seats (RS-0832, RS-0833) --- changelog.d/w3-38-d2bd-conc-async.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog.d/w3-38-d2bd-conc-async.md diff --git a/changelog.d/w3-38-d2bd-conc-async.md b/changelog.d/w3-38-d2bd-conc-async.md new file mode 100644 index 000000000..863d7b01a --- /dev/null +++ b/changelog.d/w3-38-d2bd-conc-async.md @@ -0,0 +1,5 @@ +### Fixed + +- RS-0832: the effect-service binding revision counter (effect_service_actors.rs) and the next-desired-generation mint (provider_effects.rs) now use `Ordering::Relaxed` for their monotonic load/fetch-add/fetch-update seats: these are version-go-tag and unique-value-mint counters used only for staleness equality, so the weakest correct ordering holds and they no longer participate in the SeqCst total order. + +- RS-0833: the standalone `broker_epoch` atomic in forward_rendezvous.rs now stores and loads with `Ordering::Relaxed`: the epoch is self-contained and the zones map it gates is mutex-guarded, so no Acquire/Release publication is owed at either seat. From 87cd335281b87827a85b6c3ba58a31994f7e4829 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:43:47 -0700 Subject: [PATCH 542/726] d2bd: relax standalone atomic ordering seats (RS-0832, RS-0833) --- changelog.d/w3-38-d2bd-conc-async.md | 4 +--- packages/d2bd/src/effect_service_actors.rs | 4 ++-- packages/d2bd/src/provider_effects.rs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/changelog.d/w3-38-d2bd-conc-async.md b/changelog.d/w3-38-d2bd-conc-async.md index 863d7b01a..3291880d3 100644 --- a/changelog.d/w3-38-d2bd-conc-async.md +++ b/changelog.d/w3-38-d2bd-conc-async.md @@ -1,5 +1,3 @@ ### Fixed -- RS-0832: the effect-service binding revision counter (effect_service_actors.rs) and the next-desired-generation mint (provider_effects.rs) now use `Ordering::Relaxed` for their monotonic load/fetch-add/fetch-update seats: these are version-go-tag and unique-value-mint counters used only for staleness equality, so the weakest correct ordering holds and they no longer participate in the SeqCst total order. - -- RS-0833: the standalone `broker_epoch` atomic in forward_rendezvous.rs now stores and loads with `Ordering::Relaxed`: the epoch is self-contained and the zones map it gates is mutex-guarded, so no Acquire/Release publication is owed at either seat. +- The effect-service binding revision counters and the broker-epoch generation mint now use the weakest correct orderings (`Relaxed` loads/stores/fetch_updates) instead of `SeqCst`: the revision is a version tag read only for staleness equality and the generation is a unique-value mint, so the standalone atomics carry no paired publication needing acquisition/release (plan U23 ordering-seat relaxations). diff --git a/packages/d2bd/src/effect_service_actors.rs b/packages/d2bd/src/effect_service_actors.rs index 04f4197c6..77da21ecc 100644 --- a/packages/d2bd/src/effect_service_actors.rs +++ b/packages/d2bd/src/effect_service_actors.rs @@ -171,7 +171,7 @@ impl EffectServiceBinding { /// The current generational revision. A respawn or republish bumps it; /// compare a captured value against this to detect staleness. pub fn revision(&self) -> u64 { - self.revision.load(Ordering::SeqCst) + self.revision.load(Ordering::Relaxed) } /// The actor generation this binding currently names. After a respawn @@ -512,7 +512,7 @@ impl EffectServiceSupervisorState { // Respawn or republish of a live service: bump its generation // and point the shared binding at the fresh actor. Some(existing) => { - existing.revision.fetch_add(1, Ordering::SeqCst); + existing.revision.fetch_add(1, Ordering::Relaxed); existing.actor = actor.clone(); existing.decl = row.decl; existing.clone() diff --git a/packages/d2bd/src/provider_effects.rs b/packages/d2bd/src/provider_effects.rs index 2782a1f74..a80f2d5ab 100644 --- a/packages/d2bd/src/provider_effects.rs +++ b/packages/d2bd/src/provider_effects.rs @@ -1086,7 +1086,7 @@ impl ProviderLifecycleDispatch { fn allocate_desired_generation(&self) -> Result { self.next_desired_generation - .fetch_update(Ordering::AcqRel, Ordering::Acquire, |generation| { + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |generation| { generation.checked_add(1) }) .map(|previous| previous.saturating_add(1)) From 4d6f66bbb2fb2750036ba042b14d8be107fc8ff0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:45:55 -0700 Subject: [PATCH 543/726] xtask: cache the repo root and reuse framed redaction literals --- changelog.d/w3-40-xtask-perf-macro.md | 9 +++ packages/xtask/src/bazel_evidence.rs | 29 ++++++--- packages/xtask/src/changelog.rs | 82 +++++++++++++----------- packages/xtask/src/delivery/command.rs | 54 ++++++---------- packages/xtask/src/gen_layer_catalogs.rs | 11 +--- packages/xtask/src/main.rs | 45 +++++++------ 6 files changed, 123 insertions(+), 107 deletions(-) create mode 100644 changelog.d/w3-40-xtask-perf-macro.md diff --git a/changelog.d/w3-40-xtask-perf-macro.md b/changelog.d/w3-40-xtask-perf-macro.md new file mode 100644 index 000000000..d69674f4c --- /dev/null +++ b/changelog.d/w3-40-xtask-perf-macro.md @@ -0,0 +1,9 @@ +### Changed + +- xtask commands resolve the repository root once per process instead of + re-scanning environment variables and parent directories on every call, and + schema generation mutates each schema document in place instead of cloning + the full document before serializing. +- xtask redaction and proto generation no longer allocate per-line or + per-field strings while scanning build logs and proto sources, and the + test-only crash-hook guard is defined once instead of three times. \ No newline at end of file diff --git a/packages/xtask/src/bazel_evidence.rs b/packages/xtask/src/bazel_evidence.rs index 7896c1197..43dca74d0 100644 --- a/packages/xtask/src/bazel_evidence.rs +++ b/packages/xtask/src/bazel_evidence.rs @@ -393,19 +393,31 @@ fn contains_any_marker(text: &str, markers: &[&str]) -> bool { markers.iter().any(|marker| text.contains(marker)) } -fn contains_quoted_field(lower: &str, field: &str) -> bool { - for quote in ['"', '\''] { - let quoted = format!("{quote}{field}{quote}"); +/// The credential field names framed with both quote styles, built once so +/// the per-line redaction scan never allocates a framed literal. +const QUOTED_CREDENTIAL_FIELDS: [&str; 8] = [ + "\"authorization\"", + "'authorization'", + "\"api-key\"", + "'api-key'", + "\"api_key\"", + "'api_key'", + "\"x-buildbuddy-api-key\"", + "'x-buildbuddy-api-key'", +]; + +fn contains_quoted_field(lower: &str, framed_fields: &[&str]) -> bool { + framed_fields.iter().any(|"ed| { let mut offset = 0; - while let Some(relative) = lower[offset..].find("ed) { + while let Some(relative) = lower[offset..].find(quoted) { let index = offset + relative; if lower[index + quoted.len()..].trim_start().starts_with(':') { return true; } offset = index + quoted.len(); } - } - false + false + }) } fn contains_credential_field(lower: &str) -> bool { @@ -416,10 +428,7 @@ fn contains_credential_field(lower: &str) -> bool { || lower.contains("api-key:") || lower.contains("api_key:") || lower.contains("bearer ") - || contains_quoted_field(lower, "authorization") - || contains_quoted_field(lower, "api-key") - || contains_quoted_field(lower, "api_key") - || contains_quoted_field(lower, "x-buildbuddy-api-key") + || contains_quoted_field(lower, "ED_CREDENTIAL_FIELDS) } fn unescaped_quote_count(line: &str, quote: char) -> usize { diff --git a/packages/xtask/src/changelog.rs b/packages/xtask/src/changelog.rs index 10bea4a21..8f9d8c8a7 100644 --- a/packages/xtask/src/changelog.rs +++ b/packages/xtask/src/changelog.rs @@ -794,6 +794,20 @@ fn recover_hooked( } } +/// Crash-test hook guard shared by every fold path: a `#[cfg(test)]` hook +/// returning `Crash` aborts the fold with the given message, leaving the +/// transaction on disk for recovery to find. The hook is passed in because a +/// module-scope `macro_rules!` body cannot see the calling function's +/// parameter under macro hygiene. +macro_rules! crash_if_hooked { + ($hook:expr, $stage:expr, $message:expr) => { + #[cfg(test)] + if let HookOutcome::Crash = $hook($stage) { + return Err(FoldError::single($message)); + } + }; +} + /// Discard a committed transaction: the promotion already happened, so only the /// consumed fragments and staging state remain to be cleared. /// @@ -814,16 +828,8 @@ fn finish_forward( #[cfg(test)] hook: &mut dyn FnMut(RecoverStage) -> HookOutcome, ) -> Result<(), FoldError> { let txn = &tree.txn; - macro_rules! crash_if_hooked { - ($stage:expr) => { - #[cfg(test)] - if let HookOutcome::Crash = hook($stage) { - return Err(FoldError::single("simulated crash during forward recovery")); - } - }; - } - crash_if_hooked!(RecoverStage::ForwardBeforeReserved); + crash_if_hooked!(hook, RecoverStage::ForwardBeforeReserved, "simulated crash during forward recovery"); remove_dir_all_if_exists(&txn.join(TXN_RESERVED)).map_err(|err| { FoldError::single(format!( "{TXN_DIR}/{TXN_RESERVED}: cannot clear reserved fragments: {err}" @@ -840,7 +846,11 @@ fn finish_forward( )) })?; - crash_if_hooked!(RecoverStage::ForwardBeforeBackup); + crash_if_hooked!( + hook, + RecoverStage::ForwardBeforeBackup, + "simulated crash during forward recovery" + ); remove_file_if_exists(&txn.join(TXN_BACKUP)).map_err(|err| { FoldError::single(format!( "{TXN_DIR}/{TXN_BACKUP}: cannot clear backup: {err}" @@ -852,7 +862,11 @@ fn finish_forward( // The journal is the last thing removed: until this returns, a crashed // re-run still sees COMMITTED and re-enters this idempotent forward path. - crash_if_hooked!(RecoverStage::ForwardBeforeJournal); + crash_if_hooked!( + hook, + RecoverStage::ForwardBeforeJournal, + "simulated crash during forward recovery" + ); remove_file_if_exists(&txn.join(TXN_JOURNAL)).map_err(|err| { FoldError::single(format!( "{TXN_DIR}/{TXN_JOURNAL}: cannot clear journal: {err}" @@ -864,7 +878,11 @@ fn finish_forward( )) })?; - crash_if_hooked!(RecoverStage::ForwardBeforeRmdir); + crash_if_hooked!( + hook, + RecoverStage::ForwardBeforeRmdir, + "simulated crash during forward recovery" + ); remove_dir_all_if_exists(txn).map_err(|err| { FoldError::single(format!( "{TXN_DIR}: cannot finish committed fold recovery: {err}" @@ -888,16 +906,6 @@ fn roll_back( #[cfg(test)] hook: &mut dyn FnMut(RecoverStage) -> HookOutcome, ) -> Result<(), FoldError> { let txn = &tree.txn; - macro_rules! crash_if_hooked { - ($stage:expr) => { - #[cfg(test)] - if let HookOutcome::Crash = hook($stage) { - return Err(FoldError::single( - "simulated crash during rollback recovery", - )); - } - }; - } let fragment_dir = &tree.fragment_dir; let reserved_dir = txn.join(TXN_RESERVED); @@ -927,7 +935,11 @@ fn roll_back( })?; } - crash_if_hooked!(RecoverStage::RollbackBeforeBackup); + crash_if_hooked!( + hook, + RecoverStage::RollbackBeforeBackup, + "simulated crash during rollback recovery" + ); let backup = txn.join(TXN_BACKUP); if backup.exists() { // Renaming the backup over the changelog is atomic and, by removing the @@ -945,7 +957,11 @@ fn roll_back( })?; } - crash_if_hooked!(RecoverStage::RollbackBeforeRmdir); + crash_if_hooked!( + hook, + RecoverStage::RollbackBeforeRmdir, + "simulated crash during rollback recovery" + ); remove_dir_all_if_exists(txn).map_err(|err| { FoldError::single(format!( "{TXN_DIR}: cannot remove rolled-back transaction: {err}" @@ -1021,14 +1037,6 @@ fn apply_fold_hooked( // A crash simulated by a test hook returns this sentinel without running // rollback or cleanup, leaving the transaction on disk for recovery. A real // error (below) instead recovers inline before returning. - macro_rules! crash_if_hooked { - ($stage:expr) => { - #[cfg(test)] - if let HookOutcome::Crash = hook($stage) { - return Err(FoldError::single("simulated crash")); - } - }; - } // `original` and (in non-test builds) the hook are consumed below; nothing // to silence. @@ -1076,7 +1084,7 @@ fn apply_fold_hooked( if let Err(err) = prepare() { return Err(recover_and_chain(tree, err)); } - crash_if_hooked!(FoldStage::AfterPrepare); + crash_if_hooked!(hook, FoldStage::AfterPrepare, "simulated crash"); // --- Reserve ----------------------------------------------------------- // The reservation index is only read by the test crash hook; keep @@ -1097,9 +1105,9 @@ fn apply_fold_hooked( )); return Err(recover_and_chain(tree, err)); } - crash_if_hooked!(FoldStage::AfterReserve(_index)); + crash_if_hooked!(hook, FoldStage::AfterReserve(_index), "simulated crash"); } - crash_if_hooked!(FoldStage::AfterReserveAll); + crash_if_hooked!(hook, FoldStage::AfterReserveAll, "simulated crash"); // --- Commit ------------------------------------------------------------ // The atomic rename is the only moment CHANGELOG.md changes; the fsynced @@ -1115,7 +1123,7 @@ fn apply_fold_hooked( // A crash here - promotion durable, COMMITTED not yet written - must roll // back on recovery, undoing the visible promotion, because the journal // write below is the linearization point. - crash_if_hooked!(FoldStage::AfterPromoteBeforeCommit); + crash_if_hooked!(hook, FoldStage::AfterPromoteBeforeCommit, "simulated crash"); if let Err(err) = write_journal(txn, STATE_COMMITTED) { // The promotion is already durable but the commit marker is not. Rather // than risk a rollback that would undo a visible changelog change, @@ -1126,7 +1134,7 @@ fn apply_fold_hooked( )); return Err(recover_and_chain(tree, err)); } - crash_if_hooked!(FoldStage::AfterCommit); + crash_if_hooked!(hook, FoldStage::AfterCommit, "simulated crash"); // --- Cleanup ----------------------------------------------------------- finish_forward( diff --git a/packages/xtask/src/delivery/command.rs b/packages/xtask/src/delivery/command.rs index e95ab8fcb..f3d497da9 100644 --- a/packages/xtask/src/delivery/command.rs +++ b/packages/xtask/src/delivery/command.rs @@ -1073,18 +1073,15 @@ mod tests { // Belt-and-suspenders guard over the macro-generated domain. Both // `WorkflowStatus::ALL` and the wire strings come from the single // `workflow_status!` declaration, so they cannot drift; this - // wildcard-free match adds a second checkpoint that still fails to - // compile if a variant is ever introduced outside that macro, - // keeping every variant present in `ALL`, which feeds every - // status-domain golden. + // wildcard-free match is the real guard - adding a variant is a + // compile error until an arm is added, keeping every variant + // present in `ALL`, which feeds every status-domain golden. (The + // former `ALL.contains` probe re-derived its expectation from the + // same `ALL` it iterated, so the assert could never fail.) for status in WorkflowStatus::ALL { - let listed = match status { - WorkflowStatus::Ok => WorkflowStatus::ALL.contains(&WorkflowStatus::Ok), - }; - assert!( - listed, - "every WorkflowStatus variant must be listed in WorkflowStatus::ALL" - ); + match status { + WorkflowStatus::Ok => {} + } } } @@ -1092,29 +1089,20 @@ mod tests { fn wave_commands_enumerates_every_stage() { // The operation domain is `WAVE_COMMANDS`, a hand-maintained array. // This wildcard-free guard makes adding a `WaveCommand` variant a - // compile error until an arm is added, and the arm forces the new - // stage into `WAVE_COMMANDS`, so the operation-domain golden cannot - // silently omit a live stage. + // compile error until an arm is added, so the operation-domain + // golden cannot silently omit a live stage. (The former per-arm + // `WAVE_COMMANDS.contains` probe re-derived its expectation from + // the same array it iterated, so the assert could never fail.) fn assert_listed(command: WaveCommand) { - let listed = match command { - WaveCommand::Help => WAVE_COMMANDS.contains(&WaveCommand::Help), - WaveCommand::Snapshot => WAVE_COMMANDS.contains(&WaveCommand::Snapshot), - WaveCommand::ValidateImport => { - WAVE_COMMANDS.contains(&WaveCommand::ValidateImport) - } - WaveCommand::RecoveryImport => { - WAVE_COMMANDS.contains(&WaveCommand::RecoveryImport) - } - WaveCommand::Seal => WAVE_COMMANDS.contains(&WaveCommand::Seal), - WaveCommand::MergeTarget => WAVE_COMMANDS.contains(&WaveCommand::MergeTarget), - WaveCommand::MergeEligibility => { - WAVE_COMMANDS.contains(&WaveCommand::MergeEligibility) - } - }; - assert!( - listed, - "every WaveCommand variant must be listed in WAVE_COMMANDS" - ); + match command { + WaveCommand::Help => {} + WaveCommand::Snapshot => {} + WaveCommand::ValidateImport => {} + WaveCommand::RecoveryImport => {} + WaveCommand::Seal => {} + WaveCommand::MergeTarget => {} + WaveCommand::MergeEligibility => {} + } } for command in WAVE_COMMANDS { assert_listed(command); diff --git a/packages/xtask/src/gen_layer_catalogs.rs b/packages/xtask/src/gen_layer_catalogs.rs index b7b7b7ea7..98dcc6f81 100644 --- a/packages/xtask/src/gen_layer_catalogs.rs +++ b/packages/xtask/src/gen_layer_catalogs.rs @@ -718,14 +718,9 @@ mod tests { fn broker_operation_domain_projects_the_committed_rows() { let root = crate::repo_root().expect("repository root"); let values = broker_operation_values(root).expect("committed broker rows"); - let text = fs::read_to_string(root.join(BROKER_OPERATIONS_PATH)).expect("row catalog"); - let catalog: BrokerOperations = serde_json::from_str(&text).expect("row catalog parses"); - let expected = catalog - .rows - .iter() - .filter_map(|row| row.wire_variant.clone()) - .collect::>(); - assert_eq!(values, expected); + // The pins below are the behaviour; a recomputed expectation derived + // with the same wire-variant projection as `broker_operation_values` + // could never disagree with it, so the equality is not asserted. assert!( values.iter().any(|value| value == "UsbipBind"), "a committed wire operation is in the domain" diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index 5f83af7b3..41879a7c1 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -3,6 +3,7 @@ use std::{ env, fs, path::{Path, PathBuf}, + sync::LazyLock, time::{SystemTime, UNIX_EPOCH}, }; @@ -428,9 +429,10 @@ fn message_only_proto( let mut out = String::new(); let mut skipping_service = false; let mut depth = 0_i32; + let service_marker = format!("service {service_name} "); for line in proto.lines() { let trimmed = line.trim_start(); - if !skipping_service && trimmed.starts_with(&format!("service {service_name} ")) { + if !skipping_service && trimmed.starts_with(&service_marker) { skipping_service = true; } if skipping_service { @@ -561,7 +563,7 @@ where } } -fn repo_root() -> Result<&'static Path, Box> { +static REPO_ROOT: LazyLock> = LazyLock::new(|| { let mut candidates = Vec::new(); for variable in ["D2B_REPO_ROOT", "TEST_SRCDIR", "RUNFILES_DIR"] { if let Some(base) = std::env::var_os(variable).map(PathBuf::from) { @@ -585,14 +587,20 @@ fn repo_root() -> Result<&'static Path, Box> { && path.join("BUILD.bazel").is_file() && path.join("flake.nix").is_file() { - return Ok(Box::leak(path.into_boxed_path())); + return Ok(path); } if !path.pop() { break; } } } - Err("cannot locate repo root".into()) + Err("cannot locate repo root".to_owned()) +}); + +fn repo_root() -> Result<&'static Path, Box> { + REPO_ROOT + .as_deref() + .map_err(|message| message.clone().into()) } fn schema_documents() -> Vec<(&'static str, RootSchema)> { @@ -651,7 +659,7 @@ fn gen_schemas() -> Result, Box> { .join(SCHEMA_VERSION); fs::create_dir_all(&out_dir)?; let schemas = schema_documents(); - let mut written = write_schemas(&out_dir, &schemas)?; + let mut written = write_schemas(&out_dir, schemas)?; let delivery_dir = repo_root.join("docs/reference/schemas/delivery"); fs::create_dir_all(&delivery_dir)?; written.push(write_recovery_schema(&delivery_dir)?); @@ -766,7 +774,7 @@ fn gen_zone_storage_schema() -> Result, Box> fs::create_dir_all(&out_dir)?; write_schemas( &out_dir, - &[( + vec![( "zone-storage.json", schemars::schema_for!(ZoneStoreStorageRow), )], @@ -797,7 +805,7 @@ fn gen_cli_schemas() -> Result, Box> { ), ]; - write_schemas(&out_dir, &schemas) + write_schemas(&out_dir, Vec::from(schemas)) } #[allow(clippy::disallowed_methods, reason = "CLI-only path")] @@ -963,21 +971,20 @@ fn write_manpage(path: &Path, rendered: Vec) -> Result<(), Box, ) -> Result, Box> { let mut written = Vec::with_capacity(schemas.len()); - for (file_name, schema) in schemas { + for (file_name, mut schema) in schemas { let path = out_dir.join(file_name); - fs::write(&path, render_schema(schema)?)?; + fs::write(&path, render_schema(&mut schema)?)?; written.push(path); } Ok(written) } -fn render_schema(schema: &RootSchema) -> Result { - let mut schema = schema.clone(); +fn render_schema(schema: &mut RootSchema) -> Result { schema.meta_schema = Some("https://json-schema.org/draft/2020-12/schema".to_owned()); - let mut data = serde_json::to_string_pretty(&schema)?; + let mut data = serde_json::to_string_pretty(schema)?; data.push('\n'); Ok(data) } @@ -1525,12 +1532,12 @@ mod schema_tests { #[test] fn schema_generation_is_reproducible() { let first = schema_documents() - .iter() - .map(|(name, schema)| ((*name).to_owned(), render_schema(schema).unwrap())) + .into_iter() + .map(|(name, mut schema)| (name.to_owned(), render_schema(&mut schema).unwrap())) .collect::>(); let second = schema_documents() - .iter() - .map(|(name, schema)| ((*name).to_owned(), render_schema(schema).unwrap())) + .into_iter() + .map(|(name, mut schema)| (name.to_owned(), render_schema(&mut schema).unwrap())) .collect::>(); assert_eq!(first, second); } @@ -1539,7 +1546,7 @@ mod schema_tests { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn committed_schemas_match_the_generator() { let root = repo_root().expect("repository root"); - for (name, schema) in schema_documents() { + for (name, mut schema) in schema_documents() { let path = root .join("docs/reference/schemas") .join(SCHEMA_VERSION) @@ -1548,7 +1555,7 @@ mod schema_tests { .unwrap_or_else(|error| panic!("{} is unreadable: {error}", path.display())); assert_eq!( committed, - render_schema(&schema).unwrap(), + render_schema(&mut schema).unwrap(), "{} drifted", path.display() ); From f6b8e60e6f52f6ba768578fe6adb9623be97ff78 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:46:02 -0700 Subject: [PATCH 544/726] d2bd: relax standalone interaction ordering seats (RS-0832, RS-0833) The interaction-runtime binding revision, the broker_epoch mint, and the daemon reconciler generation are version-tag/unique-value atomics observed only for equality/staleness, with the zones map they gate mutex-guarded, so no paired publication needs Acquire/Release; the weakest correct ordering (Relaxed) now seats all of: - effect_service_actors.rs revision load + respawn fetch_add - forward_rendezvous.rs broker_epoch store + load - provider_effects.rs next_desired_generation fetch_update Residuals RS-0853/RS-0854 (per-request dispatch holds the daemon-global interaction-runtime lock across its awaits) are recorded, not half-fixed: moving them off their synchronous seats is the interaction runtime's ownership design change, not a seat swap, and it needs its own concurrency test. --- packages/d2bd/src/forward_rendezvous.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index 793f48d4c..5d955ff70 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -329,7 +329,7 @@ impl ForwardRendezvous { /// pre-restart context stops validating regardless of generation /// equality. pub(crate) fn set_broker_epoch(&self, epoch: u64) { - self.broker_epoch.store(epoch, Ordering::SeqCst); + self.broker_epoch.store(epoch, Ordering::Relaxed); } /// Wire one Zone's U10 family seam (the kernel socket, the caller @@ -411,7 +411,7 @@ impl ForwardRendezvous { /// ceiling. The broker is the sole minter, so any mismatch is a stale /// or mutated attestation. async fn context_admitted(&self, context: &ForwardContext, request_zone: &str) -> bool { - let observed_epoch = self.broker_epoch.load(Ordering::SeqCst); + let observed_epoch = self.broker_epoch.load(Ordering::Relaxed); if observed_epoch == 0 { // No epoch observed yet: the attestation cannot be verified, so // no context is admitted - the fail-closed half of the rule that From 1e9b43ee66d713ecf199b805f86197408cd759a3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:52:24 -0700 Subject: [PATCH 545/726] supply: drop unused workspace deps from provider crates --- Cargo.lock | 3 --- changelog.d/w3-52-workspace-supply.md | 3 +++ packages/d2b-provider-activation-nixos/Cargo.toml | 1 - packages/d2b-provider-audio-pipewire/Cargo.toml | 1 - packages/d2b-provider-guest-azure-container-apps/Cargo.toml | 1 - 5 files changed, 3 insertions(+), 6 deletions(-) create mode 100644 changelog.d/w3-52-workspace-supply.md diff --git a/Cargo.lock b/Cargo.lock index 1148481d4..83cc6f1da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1064,7 +1064,6 @@ dependencies = [ "d2b-resource-types", "parking_lot", "ring", - "serde", "serde_json", "sha2", "tokio", @@ -1094,7 +1093,6 @@ dependencies = [ "d2b-contracts-resource", "libc", "nix 0.29.0", - "schemars", "serde", "serde_json", "tempfile", @@ -1421,7 +1419,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "sha2", "tokio", "tracing", ] diff --git a/changelog.d/w3-52-workspace-supply.md b/changelog.d/w3-52-workspace-supply.md new file mode 100644 index 000000000..9ef016283 --- /dev/null +++ b/changelog.d/w3-52-workspace-supply.md @@ -0,0 +1,3 @@ +### Changed + +- Dropped unused workspace dependencies from three provider crates: `serde` from d2b-provider-activation-nixos, `schemars` from d2b-provider-audio-pipewire, and `sha2` from d2b-provider-guest-azure-container-apps, since no source or test in those crates references them. \ No newline at end of file diff --git a/packages/d2b-provider-activation-nixos/Cargo.toml b/packages/d2b-provider-activation-nixos/Cargo.toml index 9ae131e65..3b4c8ee90 100644 --- a/packages/d2b-provider-activation-nixos/Cargo.toml +++ b/packages/d2b-provider-activation-nixos/Cargo.toml @@ -32,7 +32,6 @@ d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0- d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-bootstrap" } d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-bootstrap" } d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } -serde = { workspace = true } serde_json = { workspace = true } sha2 = { workspace = true } ring = { workspace = true } diff --git a/packages/d2b-provider-audio-pipewire/Cargo.toml b/packages/d2b-provider-audio-pipewire/Cargo.toml index 9596596f1..d83b9717a 100644 --- a/packages/d2b-provider-audio-pipewire/Cargo.toml +++ b/packages/d2b-provider-audio-pipewire/Cargo.toml @@ -22,7 +22,6 @@ tracing = "0.1" nix = { version = "0.29", default-features = false, features = ["fs"] } serde = { workspace = true } serde_json = { workspace = true } -schemars = { workspace = true } tokio = { workspace = true, features = ["sync"] } [dev-dependencies] diff --git a/packages/d2b-provider-guest-azure-container-apps/Cargo.toml b/packages/d2b-provider-guest-azure-container-apps/Cargo.toml index b68a17875..352b574d7 100644 --- a/packages/d2b-provider-guest-azure-container-apps/Cargo.toml +++ b/packages/d2b-provider-guest-azure-container-apps/Cargo.toml @@ -18,7 +18,6 @@ async-trait = "0.1" d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0-bootstrap" } d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } serde = { workspace = true } -sha2 = { workspace = true } tokio = { workspace = true, features = ["time"] } tracing = "0.1" From 0b5f937fe9aab6af0c6909c0e4afc1e2fbe6d491 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:52:32 -0700 Subject: [PATCH 546/726] session: drop unused d2b-audit, d2b-telemetry, and serde_json deps --- Cargo.lock | 3 --- changelog.d/w3-50-session-supply.md | 5 +++++ packages/d2b-session/BUILD.bazel | 4 ---- packages/d2b-session/Cargo.toml | 3 --- 4 files changed, 5 insertions(+), 10 deletions(-) create mode 100644 changelog.d/w3-50-session-supply.md diff --git a/Cargo.lock b/Cargo.lock index 1148481d4..9037a7945 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2098,14 +2098,11 @@ name = "d2b-session" version = "0.0.0-bootstrap" dependencies = [ "async-trait", - "d2b-audit", "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-resource-api", - "d2b-telemetry", "futures-util", "protobuf", - "serde_json", "sha2", "snow", "tokio", diff --git a/changelog.d/w3-50-session-supply.md b/changelog.d/w3-50-session-supply.md new file mode 100644 index 000000000..af1998b4a --- /dev/null +++ b/changelog.d/w3-50-session-supply.md @@ -0,0 +1,5 @@ +### Fixed + +- d2b-session no longer depends on the unused d2b-audit and d2b-telemetry crates; + its bazel targets drop the matching explicit deps. +The unused serde_json dev-dependency is removed from d2b-sessions manifest. \ No newline at end of file diff --git a/packages/d2b-session/BUILD.bazel b/packages/d2b-session/BUILD.bazel index 012c90332..64e175d3f 100644 --- a/packages/d2b-session/BUILD.bazel +++ b/packages/d2b-session/BUILD.bazel @@ -25,10 +25,8 @@ d2b_rust_library( deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", - "//packages/d2b-audit:d2b_audit", "//packages/d2b-contracts:d2b_contracts", "//packages/d2b-resource-api:d2b_resource_api", - "//packages/d2b-telemetry:d2b_telemetry", ] + all_crate_deps(normal = True, cargo_only = True), ) @@ -45,10 +43,8 @@ d2b_rust_library( deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", - "//packages/d2b-audit:d2b_audit_test_support", "//packages/d2b-contracts:d2b_contracts_test_support", "//packages/d2b-resource-api:d2b_resource_api_test_support", - "//packages/d2b-telemetry:d2b_telemetry_test_support", ] + all_crate_deps(normal = True, cargo_only = True), ) diff --git a/packages/d2b-session/Cargo.toml b/packages/d2b-session/Cargo.toml index f5b2d60ca..77096f03c 100644 --- a/packages/d2b-session/Cargo.toml +++ b/packages/d2b-session/Cargo.toml @@ -14,9 +14,7 @@ d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } async-trait = "0.1" tracing = "0.1" -d2b-audit = { path = "../d2b-audit", version = "0.0.0-bootstrap" } d2b-resource-api = { path = "../d2b-resource-api", version = "0.0.0-bootstrap" } -d2b-telemetry = { path = "../d2b-telemetry", version = "0.0.0-bootstrap" } futures-util = "0.3" sha2.workspace = true snow = { version = "0.10", features = ["risky-raw-split"] } @@ -41,5 +39,4 @@ await_holding_refcell_ref = "deny" [dev-dependencies] protobuf = "3.7.2" -serde_json.workspace = true tokio = { workspace = true, features = ["macros", "rt", "test-util"] } From aacd4defb9c035613cc0dd90a1b22f5c73734533 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:52:33 -0700 Subject: [PATCH 547/726] supply: drop unused deps from d2b core manifests d2b-telemetry no longer depends on rustix, d2b-bus drops the unused tempfile dev-dependency, and d2b drops d2b-zone-routing from its manifest and Bazel deps. Cargo.lock refreshed to drop the removed edges. --- Cargo.lock | 3 --- changelog.d/w3-51-core-manifests-supply.md | 5 +++++ packages/d2b-bus/Cargo.toml | 1 - packages/d2b-telemetry/Cargo.toml | 1 - packages/d2b/BUILD.bazel | 1 - packages/d2b/Cargo.toml | 1 - 6 files changed, 5 insertions(+), 7 deletions(-) create mode 100644 changelog.d/w3-51-core-manifests-supply.md diff --git a/Cargo.lock b/Cargo.lock index 1148481d4..862bdb772 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -795,7 +795,6 @@ dependencies = [ "d2b-core", "d2b-provider-config-nixos", "d2b-resource-client", - "d2b-zone-routing", "nix 0.29.0", "rustix 0.38.44", "schemars", @@ -884,7 +883,6 @@ dependencies = [ "serde_json", "sha2", "snow", - "tempfile", "tokio", "ttrpc", ] @@ -2156,7 +2154,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/changelog.d/w3-51-core-manifests-supply.md b/changelog.d/w3-51-core-manifests-supply.md new file mode 100644 index 000000000..4484b4a1c --- /dev/null +++ b/changelog.d/w3-51-core-manifests-supply.md @@ -0,0 +1,5 @@ +### Changed + +- d2b-telemetry: drop the unused `rustix` dependency (the workspace entry stays for other members). +- d2b-bus: drop the unused `tempfile` dev-dependency. +- d2b: drop the unused `d2b-zone-routing` dependency from the manifest and the Bazel deps list. \ No newline at end of file diff --git a/packages/d2b-bus/Cargo.toml b/packages/d2b-bus/Cargo.toml index 3506a951a..220710dfe 100644 --- a/packages/d2b-bus/Cargo.toml +++ b/packages/d2b-bus/Cargo.toml @@ -38,7 +38,6 @@ tokio = { workspace = true, features = ["io-util", "rt", "sync", "time"] } [dev-dependencies] d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0-bootstrap" } -tempfile = "3" tokio = { workspace = true, features = ["macros", "rt", "sync", "test-util"] } protobuf = "3.7.2" ttrpc = { workspace = true, features = ["async"] } diff --git a/packages/d2b-telemetry/Cargo.toml b/packages/d2b-telemetry/Cargo.toml index f69d7964f..597f735f7 100644 --- a/packages/d2b-telemetry/Cargo.toml +++ b/packages/d2b-telemetry/Cargo.toml @@ -11,7 +11,6 @@ d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0- serde = { workspace = true } serde_json = { workspace = true } sha2 = "0.10" -rustix = { workspace = true } # U33: this crate does not inherit `[workspace.lints]` (it carries its own lint # posture), but `clippy.toml` at the workspace root arms diff --git a/packages/d2b/BUILD.bazel b/packages/d2b/BUILD.bazel index a79bdad02..a625e1428 100644 --- a/packages/d2b/BUILD.bazel +++ b/packages/d2b/BUILD.bazel @@ -52,7 +52,6 @@ d2b_rust_library( "//packages/d2b-core:d2b_core", "//packages/d2b-provider-config-nixos:d2b_provider_config_nixos", "//packages/d2b-resource-client:d2b_resource_client", - "//packages/d2b-zone-routing:d2b_zone_routing", ] + all_crate_deps(normal = True, cargo_only = True), ) diff --git a/packages/d2b/Cargo.toml b/packages/d2b/Cargo.toml index 164199ca8..e26865876 100644 --- a/packages/d2b/Cargo.toml +++ b/packages/d2b/Cargo.toml @@ -20,7 +20,6 @@ d2b-contracts-control = { path = "../d2b-contracts-control", version = "0.0.0-bo d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } d2b-provider-config-nixos = { path = "../d2b-provider-config-nixos", version = "0.0.0-bootstrap" } d2b-resource-client = { path = "../d2b-resource-client", version = "0.0.0-bootstrap" } -d2b-zone-routing = { path = "../d2b-zone-routing", version = "0.0.0-bootstrap" } rustix = { workspace = true } schemars.workspace = true serde.workspace = true From 9c20c2cdf51d773ef090d7afe68518739d5a3bac Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:52:49 -0700 Subject: [PATCH 548/726] supply: prune unused provider manifest deps and unify webpki-roots --- Cargo.lock | 7 +------ changelog.d/w3-53-provider-manifests-supply.md | 11 +++++++++++ packages/d2b-provider-audio-pipewire/Cargo.toml | 3 +-- packages/d2b-provider-device-gpu/BUILD.bazel | 2 -- packages/d2b-provider-device-gpu/Cargo.toml | 2 -- .../Cargo.toml | 1 - packages/d2b-provider-quota/Cargo.toml | 1 - .../d2b-provider-transport-azure-relay/Cargo.toml | 2 +- 8 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 changelog.d/w3-53-provider-manifests-supply.md diff --git a/Cargo.lock b/Cargo.lock index 1148481d4..ea0cbddfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1094,7 +1094,6 @@ dependencies = [ "d2b-contracts-resource", "libc", "nix 0.29.0", - "schemars", "serde", "serde_json", "tempfile", @@ -1257,12 +1256,10 @@ dependencies = [ name = "d2b-provider-device-gpu" version = "0.0.0-bootstrap" dependencies = [ - "async-trait", "d2b-contracts-resource", "d2b-core-controller", "d2b-provider-toolkit", "d2b-resource-runtime", - "d2b-resource-types", "parking_lot", "serde", "serde_json", @@ -1421,7 +1418,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "sha2", "tokio", "tracing", ] @@ -1635,7 +1631,6 @@ dependencies = [ "d2b-resource-types", "schemars", "serde", - "serde_json", "tokio", ] @@ -1842,7 +1837,7 @@ dependencies = [ "tokio-tungstenite", "tracing", "urlencoding", - "webpki-roots 0.26.11", + "webpki-roots 1.0.9", "zeroize", ] diff --git a/changelog.d/w3-53-provider-manifests-supply.md b/changelog.d/w3-53-provider-manifests-supply.md new file mode 100644 index 000000000..2b88af4ab --- /dev/null +++ b/changelog.d/w3-53-provider-manifests-supply.md @@ -0,0 +1,11 @@ +### Fixed + +- Provider manifest supply cleanup: `d2b-provider-audio-pipewire` drops the + unused `schemars` dependency and moves `serde_json` to dev-dependencies; + `d2b-provider-device-gpu` drops unused `async-trait` and + `d2b-resource-types` (manifest and Bazel deps); `d2b-provider-quota` drops + unused `serde_json`; `d2b-provider-guest-azure-container-apps` drops unused + `sha2`. +- `d2b-provider-transport-azure-relay` upgrades its direct `webpki-roots` pin + from 0.26 to 1, collapsing the duplicate roots leg already pulled in by + `tokio-tungstenite`'s rustls-tls-webpki-roots feature. \ No newline at end of file diff --git a/packages/d2b-provider-audio-pipewire/Cargo.toml b/packages/d2b-provider-audio-pipewire/Cargo.toml index 9596596f1..679004ce8 100644 --- a/packages/d2b-provider-audio-pipewire/Cargo.toml +++ b/packages/d2b-provider-audio-pipewire/Cargo.toml @@ -21,9 +21,8 @@ libc = "0.2" tracing = "0.1" nix = { version = "0.29", default-features = false, features = ["fs"] } serde = { workspace = true } -serde_json = { workspace = true } -schemars = { workspace = true } tokio = { workspace = true, features = ["sync"] } [dev-dependencies] +serde_json = { workspace = true } tempfile = "3" diff --git a/packages/d2b-provider-device-gpu/BUILD.bazel b/packages/d2b-provider-device-gpu/BUILD.bazel index dcd6601c5..17af6cb54 100644 --- a/packages/d2b-provider-device-gpu/BUILD.bazel +++ b/packages/d2b-provider-device-gpu/BUILD.bazel @@ -36,7 +36,6 @@ d2b_rust_library( "//packages/d2b-core-controller:d2b_core_controller", "//packages/d2b-provider-toolkit:d2b_provider_toolkit", "//packages/d2b-resource-runtime:d2b_resource_runtime", - "//packages/d2b-resource-types:d2b_resource_types", "@crates//:parking_lot", ] + all_crate_deps(normal = True, cargo_only = True), ) @@ -52,7 +51,6 @@ d2b_rust_library( "//packages/d2b-core-controller:d2b_core_controller_test_support", "//packages/d2b-provider-toolkit:d2b_provider_toolkit_test_support", "//packages/d2b-resource-runtime:d2b_resource_runtime", - "//packages/d2b-resource-types:d2b_resource_types_test_support", "@crates//:parking_lot", ] + all_crate_deps(normal = True, cargo_only = True), ) diff --git a/packages/d2b-provider-device-gpu/Cargo.toml b/packages/d2b-provider-device-gpu/Cargo.toml index 6aca3c7a5..d7995fb0e 100644 --- a/packages/d2b-provider-device-gpu/Cargo.toml +++ b/packages/d2b-provider-device-gpu/Cargo.toml @@ -17,12 +17,10 @@ await_holding_refcell_ref = "deny" test-support = [] [dependencies] -async-trait = "0.1" d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } d2b-core-controller = { path = "../d2b-core-controller", version = "0.0.0-bootstrap" } d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-bootstrap" } d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-bootstrap" } -d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } parking_lot = "0.12" serde.workspace = true sha2 = { workspace = true } diff --git a/packages/d2b-provider-guest-azure-container-apps/Cargo.toml b/packages/d2b-provider-guest-azure-container-apps/Cargo.toml index b68a17875..352b574d7 100644 --- a/packages/d2b-provider-guest-azure-container-apps/Cargo.toml +++ b/packages/d2b-provider-guest-azure-container-apps/Cargo.toml @@ -18,7 +18,6 @@ async-trait = "0.1" d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0-bootstrap" } d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } serde = { workspace = true } -sha2 = { workspace = true } tokio = { workspace = true, features = ["time"] } tracing = "0.1" diff --git a/packages/d2b-provider-quota/Cargo.toml b/packages/d2b-provider-quota/Cargo.toml index 38f800a71..4828f3ad3 100644 --- a/packages/d2b-provider-quota/Cargo.toml +++ b/packages/d2b-provider-quota/Cargo.toml @@ -21,7 +21,6 @@ d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0- d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } schemars.workspace = true serde.workspace = true -serde_json.workspace = true [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/packages/d2b-provider-transport-azure-relay/Cargo.toml b/packages/d2b-provider-transport-azure-relay/Cargo.toml index b21d08be9..2d45168c7 100644 --- a/packages/d2b-provider-transport-azure-relay/Cargo.toml +++ b/packages/d2b-provider-transport-azure-relay/Cargo.toml @@ -33,7 +33,7 @@ tokio = { workspace = true, features = ["io-util", "net", "sync", "time", "macro tracing = "0.1" tokio-tungstenite = { version = "0.24", features = ["rustls-tls-webpki-roots"] } urlencoding = "2" -webpki-roots = "0.26" +webpki-roots = "1" zeroize = "1" [dev-dependencies] From 3f4a63bc885967e9b8218dd9ff0f737a5fad56a4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 14:55:31 -0700 Subject: [PATCH 549/726] host-activation-helper: document safety of every unsafe block Add a // SAFETY: comment to each production unsafe block, stating the CString NUL-termination, checked-return, and fd-ownership invariants that make the libc calls sound. No behavior change. --- .../w3-49-host-activation-helper-safety.md | 6 +++++ .../d2b-host-activation-helper/src/main.rs | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 changelog.d/w3-49-host-activation-helper-safety.md diff --git a/changelog.d/w3-49-host-activation-helper-safety.md b/changelog.d/w3-49-host-activation-helper-safety.md new file mode 100644 index 000000000..a347cc096 --- /dev/null +++ b/changelog.d/w3-49-host-activation-helper-safety.md @@ -0,0 +1,6 @@ +### Fixed + +- `d2b-host-activation-helper` now documents the safety invariant of every + production `unsafe` block (libc calls and the `errno` clear): `CString` + NUL-termination, checked return values before use, and fd ownership / + close-once discipline. No behavior change. \ No newline at end of file diff --git a/packages/d2b-host-activation-helper/src/main.rs b/packages/d2b-host-activation-helper/src/main.rs index 9ebd4b698..0fce80697 100644 --- a/packages/d2b-host-activation-helper/src/main.rs +++ b/packages/d2b-host-activation-helper/src/main.rs @@ -93,6 +93,7 @@ fn last_errno() -> io::Error { fn lock_is_held(path: &std::path::Path) -> io::Result { let c_path = cstring_path(path)?; + // SAFETY: `c_path` is a `CString` whose pointer is NUL-terminated and valid for the call; the returned fd is checked for < 0 before any use. let fd = unsafe { libc::open(c_path.as_ptr(), libc::O_RDONLY | libc::O_CLOEXEC) }; if fd < 0 { let err = last_errno(); @@ -109,8 +110,10 @@ fn lock_is_held(path: &std::path::Path) -> io::Result { l_len: 0, l_pid: 0, }; + // SAFETY: fd is a valid open descriptor (checked >= 0 above); `flock` is fully initialized before the call, and the result is checked before use. let rc = unsafe { libc::fcntl(fd, libc::F_OFD_SETLK, &mut flock) }; let saved = last_errno(); + // SAFETY: fd is a valid open descriptor from the open above; it is closed exactly once here after the fcntl result was captured. unsafe { libc::close(fd) }; if rc == 0 { Ok(false) @@ -126,6 +129,7 @@ fn lock_is_held(path: &std::path::Path) -> io::Result { fn open_root(path: &std::path::Path) -> io::Result { let c_path = cstring_path(path)?; + // SAFETY: `c_path` is a `CString` whose pointer is NUL-terminated and valid for the call; the returned fd is checked for < 0 before use, and the caller owns it. let fd = unsafe { libc::open( c_path.as_ptr(), @@ -137,15 +141,18 @@ fn open_root(path: &std::path::Path) -> io::Result { fn gid_for_fd(fd: libc::c_int) -> io::Result { let mut st = std::mem::MaybeUninit::::uninit(); + // SAFETY: fd is a valid open descriptor in the caller's ownership (checked when it was opened); `st` is only read via `assume_init` after the return value is checked for success below. let rc = unsafe { libc::fstat(fd, st.as_mut_ptr()) }; if rc != 0 { return Err(last_errno()); } + // SAFETY: the preceding fstat returned 0, so `st` was initialized by the kernel before `assume_init()` reads it. Ok(unsafe { st.assume_init() }.st_gid) } fn entry_stat(parent_fd: libc::c_int, name: &CStr) -> io::Result { let mut st = std::mem::MaybeUninit::::uninit(); + // SAFETY: parent_fd is a valid open directory fd; `name` is a `CStr` (NUL-terminated, valid for the call); `st` is written by the kernel and only read via `assume_init` after the return value is checked for success. let rc = unsafe { libc::fstatat( parent_fd, @@ -157,6 +164,7 @@ fn entry_stat(parent_fd: libc::c_int, name: &CStr) -> io::Result { if rc != 0 { return Err(last_errno()); } + // SAFETY: the preceding fstatat returned 0, so `st` was initialized by the kernel before `assume_init()` reads it. Ok(unsafe { st.assume_init() }) } @@ -187,22 +195,27 @@ fn walk_dir( migrate: bool, leftovers: &mut u64, ) -> io::Result<()> { + // SAFETY: fd is a valid open descriptor in the caller's ownership (checked when it was opened); `dup` only aliases it for the duration of the call, and its own result is checked below before use. let dup_fd = unsafe { libc::dup(fd) }; if dup_fd < 0 { return Err(last_errno()); } + // SAFETY: dup_fd was checked >= 0 above; fdopendir takes ownership of dup_fd only on success (on failure we close it below, and the returned DIR* is checked for null before use. let dir = unsafe { libc::fdopendir(dup_fd) }; if dir.is_null() { let err = last_errno(); + // SAFETY: dup_fd was checked >= 0 above; fdopendir failed, so the fd is still owned by us, and must be closed to avoid a leak. unsafe { libc::close(dup_fd) }; return Err(err); } loop { errno_clear(); + // SAFETY: dir is a valid non-null DIR* from fdopendir above; errno was cleared before the call so a null result can be distinguished from end-of-stream, and the result is checked for null before dereference. let ent = unsafe { libc::readdir(dir) }; if ent.is_null() { let err = last_errno(); + // SAFETY: dir is a valid DIR* from fdopendir, and we stop reading before closing it, so no entry is dereferenced after the close. unsafe { libc::closedir(dir) }; return if err.raw_os_error() == Some(0) { Ok(()) @@ -210,6 +223,7 @@ fn walk_dir( Err(err) }; } + // SAFETY: ent is non-null (checked above); d_name is a NUL-terminated char array inside a valid dirent, guaranteed by readdir's contract; the CStr is used only within this iteration, before the next readdir or closedir. let name_c = unsafe { CStr::from_ptr((*ent).d_name.as_ptr()) }; let name = name_c.to_bytes(); if name == b"." || name == b".." { @@ -227,6 +241,7 @@ fn walk_dir( if cfg.legacy_gids.contains(&st.st_gid) { if migrate { let entry_path = path.join(std::ffi::OsStr::from_bytes(name)); + // SAFETY: fd is a valid open directory descriptor; `name_owned` is a NUL-terminated `CString` valid for the call; the return value is checked for error before use. let rc = unsafe { libc::fchownat( fd, @@ -245,6 +260,7 @@ fn walk_dir( } } if is_dir(st.st_mode) { + // SAFETY: fd is a valid open directory descriptor; `name_owned` is a NUL-terminated `CString`; the returned fd is checked for < 0 before use, and later closed exactly once here. let child_fd = unsafe { libc::openat( fd, @@ -261,6 +277,7 @@ fn walk_dir( } let child_path = path.join(std::ffi::OsStr::from_bytes(name)); let result = walk_dir(child_fd, &child_path, cfg, migrate, leftovers); + // SAFETY: child_fd was checked >= 0 when opened above; walk_dir dups rather than consumes its descriptors, so it is still owned here, and closed exactly once after the recursive walk completes. unsafe { libc::close(child_fd) }; result?; } @@ -268,6 +285,7 @@ fn walk_dir( } fn errno_clear() { + // SAFETY: __errno_location() returns a valid pointer to the calling thread's errno, which is a plain int; writing 0 to it is always sound. unsafe { *libc::__errno_location() = 0; } @@ -297,9 +315,11 @@ fn run(cfg: Config) -> io::Result { let root_fd = open_root(&cfg.root)?; if cfg.legacy_gids.contains(&gid_for_fd(root_fd)?) { let old_gid = gid_for_fd(root_fd)?; + // SAFETY: root_fd is a valid open directory fd from open_root (checked >= 0); the return value is checked for error before proceeding. let rc = unsafe { libc::fchown(root_fd, libc::uid_t::MAX, cfg.target_gid) }; if rc != 0 { let err = last_errno(); + // SAFETY: root_fd is a valid open descriptor (checked >= 0 at open_root), and is still owned by us on this error path, so it must be closed to avoid a leak. unsafe { libc::close(root_fd) }; return Err(err); } @@ -307,6 +327,7 @@ fn run(cfg: Config) -> io::Result { } let mut migration_leftovers = 0; let result = walk_dir(root_fd, &cfg.root, &cfg, true, &mut migration_leftovers); + // SAFETY: root_fd is a valid open descriptor from open_root; walk_dir dups rather than closes its arguments, so it is still owned here, and closed exactly once after the walk completes. unsafe { libc::close(root_fd) }; result?; @@ -333,6 +354,7 @@ fn scan_for_leftovers(cfg: &Config, leftovers: &mut u64) -> io::Result<()> { } walk_dir(root_fd, &cfg.root, cfg, false, leftovers) })(); + // SAFETY: root_fd is a valid open descriptor from open_root; walk_dir dups rather than closes its arguments, so it is still owned here, and closed exactly once after the walk completes. unsafe { libc::close(root_fd) }; result } From 47667e1497211908be26fb042f01d6289065c123 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 15:02:27 -0700 Subject: [PATCH 550/726] audit: fold the wave-3 ledger outcomes and deferred rows --- .../2026-09-24-rust-skills-audit/ledger.md | 377 +++++++++--------- 1 file changed, 189 insertions(+), 188 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index c59a0c6b3..a43cff3cb 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -39,6 +39,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | --- | --- | --- | --- | --- | --- | --- | | U1 | `11bbfe41a` | pass | pass | pass (988 of 988 tests) | pass (11 of 11 vmChecks) | First attempt flaked on the load-sensitive `daemon_state_persistence` kill-during-startup race (passes standalone, not an audit row); the retry is green. The head carries the refreshed async-gate inventory for the broker line shifts. | | U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | +| W3 | `ab11d3aa6` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. Gates to be run by Main on merge onto `09f9c6ae1`. | ## Findings (965 rows) @@ -811,201 +812,201 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0754` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | a18cc6eb1 | `packages/xtask/src/delivery/snapshot.rs` | One-line docs added to WaveSnapshot digests/program/wave, WaveCommand as_str/parse/required_options/optional_options, WorkflowOutput ok/with_digests, WorkflowCommandHelp, CliOptions accessors. | | | `RS-0752` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | 6668d84dd | `provider_crate_policy.rs` | four doubled parens and whiche typo fixed; the audit's trailing \. doc lines do not exist at HEAD (grep zero), so that component is stale | | | `RS-0753` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | doc comments above today_utc_iso8601 and civil_from_days naming the Hinnant algorithm, constants, and epoch fallback | | -| `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | | | | `context.rs:570, context.rs:538` | | | -| `RS-0757` | `perf` | `d2b-audit` | low | actionable | leaf | | | | `packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970` | | | -| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | | | | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | | | -| `RS-0759` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/nft.rs:784-790` | | | -| `RS-0760` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368` | | | -| `RS-0758` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, pa` | | | -| `RS-0761` | `perf` | `d2b-broker` | low | actionable | leaf | | | | `src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/stor` | | | -| `RS-0763` | `perf` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/router.rs:4228-4235` | | | -| `RS-0764` | `perf` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/streams.rs:642-658` | | | -| `RS-0765` | `perf` | `d2b-contracts-resource` | low | actionable | leaf | | | | `packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-reso` | | | -| `RS-0766` | `perf` | `d2b-contracts-zone-session` | low | actionable | leaf | | | | `resource_bundle.rs:382` | | | -| `RS-0767` | `perf` | `d2b-core` | medium | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:16` | | | -| `RS-0768` | `perf` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:37` | | | -| `RS-0769` | `perf` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:16` | | | -| `RS-0770` | `perf` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628` | | | -| `RS-0772` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2` | | | -| `RS-0773` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159` | | | -| `RS-0774` | `perf` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nix` | | | -| `RS-0775` | `perf` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `src/session_children.rs:316, src/session_children.rs:317` | | | -| `RS-0776` | `perf` | `d2b-provider-guest` | low | actionable | leaf | | | | `packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:8` | | | -| `RS-0777` | `perf` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | | | | `shutdown.rs:505-513` | | | -| `RS-0778` | `perf` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239` | | | -| `RS-0779` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/nftables.rs:266-268` | | | -| `RS-0780` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/observe.rs:305` | | | -| `RS-0781` | `perf` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-not` | | | -| `RS-0782` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `emitter_socket.rs:139` | | | -| `RS-0783` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `ingress_policy.rs:203, ingress_policy.rs:368` | | | -| `RS-0784` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | | | | `metric_policy.rs:44` | | | -| `RS-0785` | `perf` | `d2b-provider-process-systemd` | low | actionable | leaf | | | | `packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process` | | | -| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/sr` | | | -| `RS-0787` | `perf` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-p` | | | -| `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | -| `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | | | | `driver.rs:437-440, driver.rs:614-617` | | | -| `RS-0791` | `perf` | `d2b-resource-api` | medium | actionable | leaf | | | | `manager_backend.rs:1006` | | | -| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | | | | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | | | -| `RS-0793` | `perf` | `d2b-resource-api` | low | actionable | leaf | | | | `packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458` | | | -| `RS-0790` | `perf` | `d2b-resource-api` | low | actionable | leaf | | | | `manager_backend.rs:495, manager_backend.rs:449-455` | | | -| `RS-0794` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/manager.rs:1390` | | | -| `RS-0795` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/g` | | | -| `RS-0796` | `perf` | `d2b-session` | low | actionable | leaf | | | | `record.rs:125, record.rs:147` | | | -| `RS-0797` | `perf` | `d2b-session` | low | actionable | leaf | | | | `engine.rs:1354, engine.rs:1362, scheduler.rs:72` | | | -| `RS-0798` | `perf` | `d2b-session` | low | actionable | leaf | | | | `record.rs:120, record.rs:146` | | | -| `RS-0799` | `perf` | `d2b-session-unix` | low | actionable | leaf | | | | `packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, ` | | | -| `RS-0800` | `perf` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, pa` | | | -| `RS-0801` | `perf` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/process_provider_runtime.rs:333` | | | -| `RS-0802` | `perf` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476` | | | -| `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.r` | | | -| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | | | | `public_read_model.rs:117-118` | | | -| `RS-0808` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packag` | | | -| `RS-0805` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:431` | | | -| `RS-0806` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:582` | | | -| `RS-0807` | `perf` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/main.rs:972` | | | -| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | | | | `clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provide` | | | -| `RS-0809` | `conc` | `d2b-broker` | low | actionable | leaf | | | | `src/envelope/mod.rs:1146, src/envelope/mod.rs:2144` | | | +| `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | applied-variant | W3 | 44cb49a0d | `context.rs:570, context.rs:538` | | | +| `RS-0757` | `perf` | `d2b-audit` | low | actionable | leaf | applied | W3 | 10923b65e | `packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970` | | | +| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | escalated | W3 | | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0759` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/nft.rs:784-790` | | | +| `RS-0760` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368` | | | +| `RS-0758` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, pa` | | | +| `RS-0761` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/stor` | | | +| `RS-0763` | `perf` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/router.rs:4228-4235` | | | +| `RS-0764` | `perf` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/streams.rs:642-658` | | | +| `RS-0765` | `perf` | `d2b-contracts-resource` | low | actionable | leaf | applied | W3 | 395eba54d | `packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-reso` | | | +| `RS-0766` | `perf` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | W3 | 5966950aa | `resource_bundle.rs:382` | | | +| `RS-0767` | `perf` | `d2b-core` | medium | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:16` | | | +| `RS-0768` | `perf` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:37` | | | +| `RS-0769` | `perf` | `d2b-core` | low | actionable | leaf | applied-variant | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:16` | | | +| `RS-0770` | `perf` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628` | | | +| `RS-0772` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2` | | | +| `RS-0773` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159` | | | +| `RS-0774` | `perf` | `d2b-provider-config-nixos` | low | actionable | leaf | applied-variant | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nix` | | | +| `RS-0775` | `perf` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | W3 | a34843f8e | `src/session_children.rs:316, src/session_children.rs:317` | | | +| `RS-0776` | `perf` | `d2b-provider-guest` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:8` | | | +| `RS-0777` | `perf` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | W3 | 513edf50c | `shutdown.rs:505-513` | | | +| `RS-0778` | `perf` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | W3 | e4cbd3054 | `packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239` | | | +| `RS-0779` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/nftables.rs:266-268` | | | +| `RS-0780` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | W3 | bacc017aa | `src/observe.rs:305` | | | +| `RS-0781` | `perf` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-not` | | | +| `RS-0782` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `emitter_socket.rs:139` | | | +| `RS-0783` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `ingress_policy.rs:203, ingress_policy.rs:368` | | | +| `RS-0784` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:44` | | | +| `RS-0785` | `perf` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process` | | | +| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | escalated | W3 | | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/sr` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0787` | `perf` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-p` | | | +| `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | +| `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | applied | W3 | 037e23533 | `driver.rs:437-440, driver.rs:614-617` | | | +| `RS-0791` | `perf` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:1006` | | | +| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | escalated | W3 | | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0793` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458` | | | +| `RS-0790` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:495, manager_backend.rs:449-455` | | | +| `RS-0794` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/manager.rs:1390` | | | +| `RS-0795` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/g` | | | +| `RS-0796` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `record.rs:125, record.rs:147` | | | +| `RS-0797` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `engine.rs:1354, engine.rs:1362, scheduler.rs:72` | | | +| `RS-0798` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `record.rs:120, record.rs:146` | | | +| `RS-0799` | `perf` | `d2b-session-unix` | low | actionable | leaf | applied | W3 | 774c148eb | `packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, ` | | | +| `RS-0800` | `perf` | `d2bd` | medium | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, pa` | | | +| `RS-0801` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/process_provider_runtime.rs:333` | | | +| `RS-0802` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476` | | | +| `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.r` | | | +| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | escalated | W3 | | `public_read_model.rs:117-118` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0808` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packag` | | | +| `RS-0805` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:431` | | | +| `RS-0806` | `perf` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:582` | | | +| `RS-0807` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:972` | | | +| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | policy-confirmed | W3 | | `clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provide` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0809` | `conc` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/envelope/mod.rs:1146, src/envelope/mod.rs:2144` | | | | `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/registry.rs:522-523, packages/d2b-bus/src/registry.rs:573-582` | | | -| `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-p` | | | -| `RS-0812` | `conc` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96` | | | -| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/` | | | -| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | | | | `packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-g` | | | -| `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | | | | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-` | | | -| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | | | | `test_support.rs:25, test_support.rs:35, Cargo.toml:30` | | | -| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | | | | `packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, ` | | | -| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_s` | | | -| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.` | | | -| `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | | | | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.` | | | -| `RS-0821` | `conc` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/testing.rs:43, src/testing.rs:79` | | | -| `RS-0822` | `conc` | `d2b-provider-toolkit` | low | actionable | leaf | | | | `packages/d2b-provider-toolkit/src/operations/envelope.rs:487` | | | -| `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | | | | `packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-uni` | | | -| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | | | | `packages/d2b-provider-user/src/test_support.rs:41-42, packages/d2b-provider-user/src/test_` | | | -| `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | | | | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_sup` | | | -| `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | | | | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-bindin` | | | -| `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone` | | | -| `RS-0828` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/resource.rs:247` | | | -| `RS-0829` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:` | | | -| `RS-0830` | `conc` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:756, admission.rs:1666, driver.rs:33` | | | -| `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src` | | | -| `RS-0832` | `conc` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs` | | | -| `RS-0833` | `conc` | `d2bd` | low | actionable | leaf | | | | `packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414` | | | -| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | | | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34` | | | -| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | | | | `packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189` | | | -| `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | | | | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support` | | | +| `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-p` | | | +| `RS-0812` | `conc` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96` | | | +| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | policy-confirmed | W3 | | `packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-g` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-` | | | +| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | policy-confirmed | W3 | | `test_support.rs:25, test_support.rs:35, Cargo.toml:30` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | policy-confirmed | W3 | | `packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, ` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_s` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.` | | | +| `RS-0821` | `conc` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:43, src/testing.rs:79` | | | +| `RS-0822` | `conc` | `d2b-provider-toolkit` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-toolkit/src/operations/envelope.rs:487` | | | +| `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-uni` | | | +| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-user/src/test_support.rs:41-42, packages/d2b-provider-user/src/test_` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_sup` | | | +| `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-bindin` | | | +| `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone` | | | +| `RS-0828` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/resource.rs:247` | | | +| `RS-0829` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:` | | | +| `RS-0830` | `conc` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `admission.rs:756, admission.rs:1666, driver.rs:33` | | | +| `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src` | | | +| `RS-0832` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs` | | | +| `RS-0833` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414` | | | +| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support` | | | | `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | 9b64eaa27 | packages/d2b-broker/src/runtime.rs (reap fn; kernel_ops.rs callers) | bounded WNOHANG reap poll replaces the blocking waitid; orphaned helpers deleted | | | `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | 25dfa3aee | packages/d2b-broker/src/sys.rs, packages/d2b-broker/src/ops/swtpm_dir.rs | setfacl shellout moved behind an async wrapper on a bounded worker | | | `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | a6d8fb022 | packages/d2b-broker/src/ops/media.rs | nss group lookup hoisted to a LazyLock, off the per-write path | | | `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | f4f09c74c | packages/d2b-broker/src/ops/host_generation_handoff.rs | flock wait moved to a bounded worker (sanctioned allow reason) | | -| `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | -| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | | | | `packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages` | | | -| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | | | -| `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | | | | `packages/d2b-provider/src/agent.rs:316-324` | | | -| `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-cre` | | | -| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | | | | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | | | -| `RS-0847` | `async` | `d2b-provider-device-tpm` | low | actionable | leaf | | | | `effects_service.rs:361, effects_service.rs:384, effects_service.rs:698` | | | -| `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | | | | `src/observe.rs:255-260` | | | -| `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | | | | `src/testing.rs:30, src/testing.rs:19` | | | -| `RS-0850` | `async` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833` | | | +| `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | +| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | policy-confirmed | W3 | | `packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | escalated | W3 | | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | applied | W3 | 7de088b5d | `packages/d2b-provider/src/agent.rs:316-324` | | | +| `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-cre` | | | +| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | escalated | W3 | | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0847` | `async` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | W3 | 7de088b5d | `effects_service.rs:361, effects_service.rs:384, effects_service.rs:698` | | | +| `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/observe.rs:255-260` | | | +| `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:30, src/testing.rs:19` | | | +| `RS-0850` | `async` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833` | | | | `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | policy-confirmed | U1 | | `packages/d2b-provider-user/src/probe.rs:48, packages/d2b-provider-user/src/probe.rs:63, pa` | recorded no-op (KTD8/R14): the deliberate bounded NSS probe is the crate's documented contract - packages/d2b-provider-user/README.md:50-55, src/probe.rs:1-5; audit cluster README.md:2806 | | -| `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | | | | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | -| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/interaction_composition.rs:5518-5530` | | | -| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | | | | `packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_ef` | | | -| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | | | | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | | | -| `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | | | | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broke` | | | -| `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | | | -| `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | | | | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | -| `RS-0859` | `unsafe` | `d2b-host-activation-helper` | medium | actionable | leaf | | | | `packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/sr` | | | -| `RS-0860` | `macro` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420` | | | -| `RS-0861` | `macro` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:2245-2267` | | | -| `RS-0862` | `macro` | `d2b-session` | low | actionable | leaf | | | | `admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643` | | | -| `RS-0863` | `macro` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/s` | | | -| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | | | -| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | | | | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | | | -| `RS-0880` | `test` | `d2b` | medium | actionable | leaf | | | | `packages/d2b/src/exec.rs:227-239` | | | -| `RS-0881` | `test` | `d2b` | low | actionable | leaf | | | | `packages/d2b/src/exec.rs:383-397` | | | -| `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | | | | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | -| `RS-0864` | `test` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:523` | | | -| `RS-0865` | `test` | `d2b-broker-composition` | low | actionable | leaf | | | | `packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.` | | | +| `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | +| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | declined | W3 | f6b8e60e6 | `packages/d2bd/src/interaction_composition.rs:5518-5530` | | | +| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | declined | W3 | f6b8e60e6 | `packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_ef` | | | +| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | escalated | W3 | | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 406f13d98 | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broke` | | | +| `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | skipped-stale | W3 | 406f13d98 | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | | | +| `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | applied | W3 | 3886cfd7b | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | +| `RS-0859` | `unsafe` | `d2b-host-activation-helper` | medium | actionable | leaf | applied | W3 | 3f4a63bc8 | `packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/sr` | | | +| `RS-0860` | `macro` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | W3 | a34843f8e | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420` | | | +| `RS-0861` | `macro` | `d2b-resource-api` | low | actionable | leaf | applied-variant | W3 | 81b2ef867 | `service.rs:2245-2267` | | | +| `RS-0862` | `macro` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643` | | | +| `RS-0863` | `macro` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/s` | | | +| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | escalated | W3 | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | escalated | W3 | | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0880` | `test` | `d2b` | medium | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:227-239` | | | +| `RS-0881` | `test` | `d2b` | low | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:383-397` | | | +| `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | applied | W3 | b80491dde | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | +| `RS-0864` | `test` | `d2b-broker-composition` | low | actionable | leaf | applied | W3 | fbcf5d1f5 | `packages/d2b-broker-composition/src/seam.rs:523` | | | +| `RS-0865` | `test` | `d2b-broker-composition` | low | actionable | leaf | applied | W3 | fbcf5d1f5 | `packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.` | | | | `RS-0867` | `test` | `d2b-bus` | high | actionable | leaf | applied | U1 | 01e8edab3 | packages/d2b-bus/src/metrics.rs | test now drives BusMetrics::emit over every closed label domain; mutation-verified | | -| `RS-0868` | `test` | `d2b-bus` | medium | actionable | leaf | | | | `packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_te` | | | -| `RS-0869` | `test` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/operations.rs:1057-1060` | | | -| `RS-0870` | `test` | `d2b-contracts-control` | medium | actionable | leaf | | | | `public_wire.rs:167, public_wire.rs:175` | | | -| `RS-0871` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-` | | | -| `RS-0872` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contract` | | | -| `RS-0873` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | | | | `src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_sessi` | | | -| `RS-0874` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | | | | `emergency_policy.rs:236, emergency_policy.rs:112` | | | -| `RS-0877` | `test` | `d2b-core` | low | actionable | leaf | | | | `packages/d2b-core/tests/bundle_resolver_tamper.rs:149` | | | -| `RS-0875` | `test` | `d2b-core-controller` | medium | actionable | leaf | | | | `authority.rs:1824, authority.rs:1968, authority.rs:1899` | | | -| `RS-0876` | `test` | `d2b-core-controller` | medium | actionable | leaf | | | | `authority_persistence.rs:246-320` | | | -| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:245` | | | -| `RS-0879` | `test` | `d2b-host` | low | actionable | leaf | | | | `packages/d2b-host/src/bin/d2b-activation-helper.rs:792` | | | -| `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activ` | | | -| `RS-0883` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `tests/authority.rs:26-31, src/authority.rs:236-241` | | | -| `RS-0884` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `tests/mediator.rs:13-24` | | | -| `RS-0885` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787` | | | -| `RS-0886` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clip` | | | -| `RS-0887` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provide` | | | -| `RS-0888` | `test` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-pro` | | | -| `RS-0889` | `test` | `d2b-provider-config-nixos` | medium | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixo` | | | -| `RS-0890` | `test` | `d2b-provider-config-nixos` | low | actionable | leaf | | | | `packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixo` | | | -| `RS-0891` | `test` | `d2b-provider-credential-entra` | low | actionable | leaf | | | | `packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-e` | | | -| `RS-0892` | `test` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | | | | `tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76` | | | -| `RS-0893` | `test` | `d2b-provider-credential-secret-service` | low | actionable | leaf | | | | `packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-` | | | -| `RS-0894` | `test` | `d2b-provider-device-gpu` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/te` | | | -| `RS-0896` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, ` | | | -| `RS-0897` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | | | | `src/reconcile_state.rs:51-308, src/state_machine.rs:98-100` | | | -| `RS-0895` | `test` | `d2b-provider-device-usbip` | low | actionable | leaf | | | | `tests/conformance.rs:63-66` | | | +| `RS-0868` | `test` | `d2b-bus` | medium | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_te` | | | +| `RS-0869` | `test` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/operations.rs:1057-1060` | | | +| `RS-0870` | `test` | `d2b-contracts-control` | medium | actionable | leaf | applied | W3 | 1ff8e6a8c | `public_wire.rs:167, public_wire.rs:175` | | | +| `RS-0871` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-` | | | +| `RS-0872` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contract` | | | +| `RS-0873` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | W3 | 5966950aa | `src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_sessi` | | | +| `RS-0874` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | W3 | 5966950aa | `emergency_policy.rs:236, emergency_policy.rs:112` | | | +| `RS-0877` | `test` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/tests/bundle_resolver_tamper.rs:149` | | | +| `RS-0875` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority.rs:1824, authority.rs:1968, authority.rs:1899` | | | +| `RS-0876` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority_persistence.rs:246-320` | | | +| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | escalated | W3 | | `packages/d2b-host/src/nftables.rs:245` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0879` | `test` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/bin/d2b-activation-helper.rs:792` | | | +| `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activ` | | | +| `RS-0883` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/authority.rs:26-31, src/authority.rs:236-241` | | | +| `RS-0884` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/mediator.rs:13-24` | | | +| `RS-0885` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | W3 | d5ab66ec5 | `src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787` | | | +| `RS-0886` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clip` | | | +| `RS-0887` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provide` | | | +| `RS-0888` | `test` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-pro` | | | +| `RS-0889` | `test` | `d2b-provider-config-nixos` | medium | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixo` | | | +| `RS-0890` | `test` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixo` | | | +| `RS-0891` | `test` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-e` | | | +| `RS-0892` | `test` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76` | | | +| `RS-0893` | `test` | `d2b-provider-credential-secret-service` | low | actionable | leaf | already-fixed | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-` | | | +| `RS-0894` | `test` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/te` | | | +| `RS-0896` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | W3 | b373f7624 | `tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, ` | | | +| `RS-0897` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | W3 | b373f7624 | `src/reconcile_state.rs:51-308, src/state_machine.rs:98-100` | | | +| `RS-0895` | `test` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | W3 | b373f7624 | `tests/conformance.rs:63-66` | | | | `RS-0898` | `test` | `d2b-provider-display-wayland` | high | actionable | leaf | applied | U1 | 3b964169f | packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs | registry-handler tests assert advertised-global outcomes; mutation-verified | | -| `RS-0900` | `test` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | | | | `src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225` | | | -| `RS-0899` | `test` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `tests/provider_lifecycle.rs:536` | | | -| `RS-0901` | `test` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | | | | `tests/error_redaction.rs:17` | | | -| `RS-0902` | `test` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | | | | `finalize_ordering_test.rs:286` | | | -| `RS-0903` | `test` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | | | | `packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest` | | | -| `RS-0904` | `test` | `d2b-provider-observability-otel` | medium | actionable | leaf | | | | `metric_policy.rs:145, metric_policy.rs:150` | | | -| `RS-0905` | `test` | `d2b-provider-provider` | medium | actionable | leaf | | | | `src/providers.rs:206, src/driver.rs:1147` | | | -| `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | | | | `tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.r` | | | -| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:2040-2043` | | | -| `RS-0908` | `test` | `d2b-provider-system-core` | low | actionable | leaf | | | | `tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230` | | | -| `RS-0909` | `test` | `d2b-provider-transport-vsock` | low | actionable | leaf | | | | `packages/d2b-provider-transport-vsock/tests/observe.rs:14-15` | | | -| `RS-0910` | `test` | `d2b-provider-user` | medium | actionable | leaf | | | | `packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs` | | | -| `RS-0911` | `test` | `d2b-provider-wayland-policy` | low | actionable | leaf | | | | `packages/d2b-provider-wayland-policy/tests/registration.rs:93` | | | -| `RS-0912` | `test` | `d2b-provider-zone-link` | low | actionable | leaf | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/sr` | | | -| `RS-0914` | `test` | `d2b-resource-api` | medium | actionable | leaf | | | | `packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src` | | | -| `RS-0913` | `test` | `d2b-resource-api` | low | actionable | leaf | | | | `service.rs:3377` | | | -| `RS-0915` | `test` | `d2b-resource-client` | low | actionable | leaf | | | | `packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/p` | | | +| `RS-0900` | `test` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | W3 | 52f5ef660 | `src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225` | | | +| `RS-0899` | `test` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W3 | 52f5ef660 | `tests/provider_lifecycle.rs:536` | | | +| `RS-0901` | `test` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | W3 | 563820766 | `tests/error_redaction.rs:17` | | | +| `RS-0902` | `test` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | already-fixed | W3 | 513edf50c | `finalize_ordering_test.rs:286` | | | +| `RS-0903` | `test` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | W3 | e4cbd3054 | `packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest` | | | +| `RS-0904` | `test` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:145, metric_policy.rs:150` | | | +| `RS-0905` | `test` | `d2b-provider-provider` | medium | actionable | leaf | applied | W3 | 55b7d20a6 | `src/providers.rs:206, src/driver.rs:1147` | | | +| `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied-variant | W3 | 55b7d20a6 | `tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.r` | | | +| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-supervisor/src/broker.rs:2040-2043` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0908` | `test` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230` | | | +| `RS-0909` | `test` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-transport-vsock/tests/observe.rs:14-15` | | | +| `RS-0910` | `test` | `d2b-provider-user` | medium | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs` | | | +| `RS-0911` | `test` | `d2b-provider-wayland-policy` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-wayland-policy/tests/registration.rs:93` | | | +| `RS-0912` | `test` | `d2b-provider-zone-link` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/sr` | | | +| `RS-0914` | `test` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src` | | | +| `RS-0913` | `test` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `service.rs:3377` | | | +| `RS-0915` | `test` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/p` | | | | `RS-0916` | `test` | `d2b-resource-runtime` | high | actionable | leaf | applied-variant | U1 | 8b191fe39 | packages/d2b-resource-runtime/src/revision.rs (display test) | claim corrected: the committed line was a tautological bare-epoch assertion (not an assertion that cannot pass); the audit's quoted literal is a tool-output redaction artifact, absent from the file and from git history; the row's own fix text applied by deleting the redundant assertion | | -| `RS-0917` | `test` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/revision.rs:182` | | | -| `RS-0918` | `test` | `d2b-resource-runtime` | low | actionable | leaf | | | | `packages/d2b-resource-runtime/src/lib.rs:66` | | | -| `RS-0919` | `test` | `d2b-session` | low | actionable | leaf | | | | `tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139` | | | -| `RS-0920` | `test` | `d2b-sk-frontend` | medium | actionable | leaf | | | | `packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186` | | | -| `RS-0921` | `test` | `d2b-telemetry` | low | actionable | leaf | | | | `packages/d2b-telemetry/src/meter_registry.rs:176-180` | | | -| `RS-0922` | `test` | `d2b-unsafe-local-helper` | low | actionable | leaf | | | | `packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helpe` | | | -| `RS-0923` | `test` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/engine.rs:3333` | | | -| `RS-0924` | `test` | `d2b-zone-routing` | low | actionable | leaf | | | | `packages/d2b-zone-routing/src/router.rs:517` | | | +| `RS-0917` | `test` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/revision.rs:182` | | | +| `RS-0918` | `test` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/lib.rs:66` | | | +| `RS-0919` | `test` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139` | | | +| `RS-0920` | `test` | `d2b-sk-frontend` | medium | actionable | leaf | applied | W3 | a094121e5 | `packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186` | | | +| `RS-0921` | `test` | `d2b-telemetry` | low | actionable | leaf | applied | W3 | c6480efc | `packages/d2b-telemetry/src/meter_registry.rs:176-180` | | | +| `RS-0922` | `test` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helpe` | | | +| `RS-0923` | `test` | `d2b-zone-routing` | low | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/engine.rs:3333` | | | +| `RS-0924` | `test` | `d2b-zone-routing` | low | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/router.rs:517` | | | | `RS-0925` | `test` | `d2bd-runtime` | high | actionable | leaf | applied | U1 | bea8fa96d | packages/d2bd-runtime/src/runtime_process.rs | sd_notify tests assert observable tracing outcomes; two mutations verified | | -| `RS-0926` | `test` | `d2bd-runtime` | low | actionable | leaf | | | | `packages/d2bd-runtime/src/daemon_audit.rs:2367` | | | -| `RS-0928` | `test` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079` | | | -| `RS-0927` | `test` | `xtask` | low | actionable | leaf | | | | `packages/xtask/src/gen_layer_catalogs.rs:705` | | | -| `RS-0933` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28` | | | -| `RS-0934` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31` | | | -| `RS-0935` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-session/Cargo.toml:44` | | | -| `RS-0936` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-telemetry/Cargo.toml:14` | | | -| `RS-0937` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-quota/Cargo.toml:24` | | | -| `RS-0938` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-bus/Cargo.toml:41` | | | -| `RS-0939` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `dependencies` | | | -| `RS-0940` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `dependencies` | | | -| `RS-0941` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `dependencies` | | | -| `RS-0942` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | -| `RS-0943` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.baz` | | | -| `RS-0944` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55` | | | -| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | | | | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | | | -| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | | | | `Cargo.toml:202, deny.toml:2` | | | -| `RS-0948` | `supply` | `X1-supply-chain` | medium | actionable | leaf | | | | `packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport` | | | -| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | | | | `packages/Cargo.guest.lock:1, flake.nix:389` | | | -| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | | | | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | | | -| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | | | | `deny.toml:2` | | | -| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | | | | `deny.toml:21` | | | -| `RS-0929` | `supply` | `d2b-provider-audio-pipewire` | low | actionable | leaf | | | | `Cargo.toml:24, Cargo.toml:25` | | | -| `RS-0930` | `supply` | `d2b-provider-device-gpu` | low | actionable | leaf | | | | `packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.tom` | | | -| `RS-0931` | `supply` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | | | | `Cargo.toml:21` | | | -| `RS-0932` | `supply` | `d2b-provider-quota` | low | actionable | leaf | | | | `dependencies` | | | +| `RS-0926` | `test` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `packages/d2bd-runtime/src/daemon_audit.rs:2367` | | | +| `RS-0928` | `test` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079` | | | +| `RS-0927` | `test` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/gen_layer_catalogs.rs:705` | | | +| `RS-0933` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 0b5f937fe | `packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28` | | | +| `RS-0934` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 0b5f937fe | `packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31` | | | +| `RS-0935` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 0b5f937fe | `packages/d2b-session/Cargo.toml:44` | | | +| `RS-0936` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b-telemetry/Cargo.toml:14` | | | +| `RS-0937` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-quota/Cargo.toml:24` | | | +| `RS-0938` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b-bus/Cargo.toml:41` | | | +| `RS-0939` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `dependencies` | | | +| `RS-0940` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `dependencies` | | | +| `RS-0941` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `dependencies` | | | +| `RS-0942` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | +| `RS-0943` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.baz` | | | +| `RS-0944` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55` | | | +| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | escalated | W3 | | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | escalated | W3 | | `Cargo.toml:202, deny.toml:2` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0948` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport` | | | +| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | escalated | W3 | | `packages/Cargo.guest.lock:1, flake.nix:389` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | escalated | W3 | | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | escalated | W3 | | `deny.toml:2` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | escalated | W3 | | `deny.toml:21` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0929` | `supply` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:24, Cargo.toml:25` | | | +| `RS-0930` | `supply` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.tom` | | | +| `RS-0931` | `supply` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:21` | | | +| `RS-0932` | `supply` | `d2b-provider-quota` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `dependencies` | | | From 6bdd9f83aea8ef2d1a1f6016b3ed69a04006cc83 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 15:06:15 -0700 Subject: [PATCH 551/726] audit: point the wave-3 gate row at the final integration head --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index a43cff3cb..852f34d4f 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -39,7 +39,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | --- | --- | --- | --- | --- | --- | --- | | U1 | `11bbfe41a` | pass | pass | pass (988 of 988 tests) | pass (11 of 11 vmChecks) | First attempt flaked on the load-sensitive `daemon_state_persistence` kill-during-startup race (passes standalone, not an audit row); the retry is green. The head carries the refreshed async-gate inventory for the broker line shifts. | | U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | -| W3 | `ab11d3aa6` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. Gates to be run by Main on merge onto `09f9c6ae1`. | +| W3 | `24198fff7` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. Gates to be run by Main on merge onto `09f9c6ae1`. | ## Findings (965 rows) From d68d0dbcb8f42ebfc62f2d1b4de585941e17719e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 15:54:56 -0700 Subject: [PATCH 552/726] repo: repair the wave-3 gate breaks The wave-3 integration merge left the Layer-1 gate red in six classes: - resource_status and meter_registry kept module-scope imports whose only remaining consumers are their test modules; the imports move to the test modules, matching the sibling crates' pattern. - test_rebuild_runner_intents still read the pre-merge flat guest intent map after the resolver nested it per zone; it now flattens the nested map like the constructor does. - the CLI receive-buffer lock site was missing the sanctioned CLI-only allow its sibling sites carry, tripping the blocking census. - the nft/hosts renderers wrote trailing-newline format strings with write!, tripping write_with_newline under -Dwarnings; they use writeln! (byte-identical output, one multi-line string split to preserve bytes). - the clipboard controller's route-shape validators and their tests exceeded too_many_arguments and type_complexity; both validators now take a plain-field DisplayRouteShape struct and the tests use a named case struct. - the merged Cargo.lock was stale against the merged manifests and the async-gate inventory had drifted; both are regenerated, and the policy-input closures are refreshed to the new lock digest. d2b-session's manual_inspect and collapsible_if sites and the sk-frontend type_complexity case tuple are repaired the same way. The blocking census, the policy-input check, the async-gate check, cargo check, and the full bazel check lane (988 tests) are green again. --- Cargo.lock | 2 - changelog.d/fix-wave3-gate-breaks.md | 5 + .../src/v3/resource_status.rs | 3 +- packages/d2b-core/src/bundle_resolver.rs | 50 ++- .../src/controller/mod.rs | 307 +++++++++--------- packages/d2b-session/src/admission.rs | 3 +- packages/d2b-session/src/record.rs | 8 +- packages/d2b-sk-frontend/src/uhid.rs | 3 +- packages/d2b-telemetry/src/meter_registry.rs | 4 +- packages/d2b/src/context.rs | 1 + .../broker-default-tests/policy/Cargo.lock | 1 - .../broker-default-tests/policy/closure.json | 8 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/Cargo.lock | 1 - .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 - .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 - .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 - .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 - .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../broker-production/policy/Cargo.lock | 1 - .../broker-production/policy/closure.json | 8 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/Cargo.lock | 1 - .../broker-production/production/closure.json | 8 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 16 +- .../main-product/policy/closure.json | 92 +----- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 16 +- .../main-product/production/closure.json | 88 +---- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/Cargo.lock | 1 - .../broker-default-tests/policy/closure.json | 8 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/Cargo.lock | 1 - .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 - .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 - .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../policy/Cargo.lock | 1 - .../policy/closure.json | 8 +- .../policy/metadata.json | 2 +- .../production/Cargo.lock | 1 - .../production/closure.json | 8 +- .../production/metadata.json | 2 +- .../broker-production/policy/Cargo.lock | 1 - .../broker-production/policy/closure.json | 8 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/Cargo.lock | 1 - .../broker-production/production/closure.json | 8 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 16 +- .../main-product/policy/closure.json | 92 +----- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 16 +- .../main-product/production/closure.json | 88 +---- .../main-product/production/metadata.json | 2 +- packages/xtask/data/async-gate-inventory.json | 114 +++---- 71 files changed, 306 insertions(+), 802 deletions(-) create mode 100644 changelog.d/fix-wave3-gate-breaks.md diff --git a/Cargo.lock b/Cargo.lock index 195106564..595332279 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1740,7 +1740,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "tokio", "tracing", ] @@ -1910,7 +1909,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", "tracing", diff --git a/changelog.d/fix-wave3-gate-breaks.md b/changelog.d/fix-wave3-gate-breaks.md new file mode 100644 index 000000000..e9f4e4d94 --- /dev/null +++ b/changelog.d/fix-wave3-gate-breaks.md @@ -0,0 +1,5 @@ +# `fix-wave3-gate-breaks.md` + +### Fixed + +- The wave-3 integration merge left the workspace gate red: the status-size single-pass change dropped the last non-test use of `canonical_json_bytes` in the v3 resource status contract while its import stayed at module scope, the telemetry meter registry kept a module-scope import used only by tests, the test-support runner-intent rebuild hook still read the pre-merge flat guest intent map after the resolver nested it per zone, the CLI receive-buffer slice added a `std::sync::Mutex` critical section without the sanctioned CLI-only allow its sibling sites carry (tripping the blocking census), the nftables/hosts renderers wrote trailing-newline format strings with `write!` where the newline form trips the clippy gate, the clipboard controller's route-shape validators and their tests exceeded the clippy argument and type-complexity limits, and the merged `Cargo.lock` and the async-gate inventory were never regenerated after wave-3 slices changed dependencies and marker sites, leaving the policy-input closures and the inventory stale. The imports now live at their test-module use sites, the hook iterates the nested map, the receive-buffer lock carries the per-site allow, the renderers use `writeln!`, the route-shape checks take a plain-field shape struct, and the lock, policy inputs, and async-gate inventory are regenerated, so `cargo check --workspace --all-targets`, the blocking census, the policy-input check, the async-gate check, the clippy gate, and the Layer-1 gate lanes are green again. \ No newline at end of file diff --git a/packages/d2b-contracts-resource/src/v3/resource_status.rs b/packages/d2b-contracts-resource/src/v3/resource_status.rs index 6312dcb8b..0c0b060a0 100644 --- a/packages/d2b-contracts-resource/src/v3/resource_status.rs +++ b/packages/d2b-contracts-resource/src/v3/resource_status.rs @@ -7,7 +7,7 @@ use super::{ ObservedGeneration, ResourceGeneration, ResourceRef, Timestamp, resource_schema::{ CanonicalJsonObject, ExtensionSchemaId, ExtensionSchemaLayer, SchemaVersion, - canonical_json_bytes, validate_canonical_string, + validate_canonical_string, }, }; use crate::ids::OperationId; @@ -845,6 +845,7 @@ impl std::error::Error for ResourceStatusError {} #[cfg(test)] mod tests { use super::*; + use crate::v3::resource_schema::canonical_json_bytes; fn timestamp() -> Timestamp { Timestamp::parse("2026-07-22T00:00:01.000Z").unwrap() diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 985b6ed09..33cfa7246 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -2429,6 +2429,7 @@ impl BundleResolver { runner_intents.extend( self.guest_vmm_intents .values() + .flat_map(|guests| guests.values()) .cloned() .map(|intent| (intent.intent_id.clone(), intent)), ); @@ -3765,28 +3766,28 @@ fn render_host_nft_script(host: &HostJson) -> String { } else { format!(" comment \"d2b managed: {}\"", model.ownership_id) }; - write!( + writeln!( buf, - "table {} {} {{\n", + "table {} {} {{", model.family.to_lowercase(), model.table ) .expect("writing to a String cannot fail"); for chain in &model.chains { - write!(buf, " chain {} {{\n", chain.name).expect("writing to a String cannot fail"); + writeln!(buf, " chain {} {{", chain.name).expect("writing to a String cannot fail"); if let (Some(hook), Some(priority)) = (chain.hook.as_ref(), chain.priority) { - write!(buf, " type filter hook {hook} priority {priority};\n") + writeln!(buf, " type filter hook {hook} priority {priority};") .expect("writing to a String cannot fail"); } if let Some(policy) = chain.policy.as_ref() { - write!(buf, " policy {policy};\n").expect("writing to a String cannot fail"); + writeln!(buf, " policy {policy};").expect("writing to a String cannot fail"); } if !chain.purpose.is_empty() { - write!(buf, " # purpose: {}\n", chain.purpose) + writeln!(buf, " # purpose: {}", chain.purpose) .expect("writing to a String cannot fail"); } if !comment.is_empty() { - write!(buf, " ct state established,related accept{comment};\n") + writeln!(buf, " ct state established,related accept{comment};") .expect("writing to a String cannot fail"); } // Per-env forward acceptance: workload traffic exits each env @@ -3799,9 +3800,9 @@ fn render_host_nft_script(host: &HostJson) -> String { // before the nixos chain runs. if chain.hook.as_deref() == Some("forward") { for env in &host.environments { - write!( + writeln!( buf, - " iifname \"br-{}-up\" ct state new accept{comment};\n", + " iifname \"br-{}-up\" ct state new accept{comment};", env.env ) .expect("writing to a String cannot fail"); @@ -3822,14 +3823,14 @@ fn render_host_nft_script(host: &HostJson) -> String { .map(u16::to_string) .collect::>() .join(", "); - write!( + writeln!( buf, - " iifname != \"lo\" meta l4proto tcp tcp dport {{ {backend_ports} }} drop{comment};\n" + " iifname != \"lo\" meta l4proto tcp tcp dport {{ {backend_ports} }} drop{comment};" ) .expect("writing to a String cannot fail"); - write!( + writeln!( buf, - " iifname != \"lo\" meta l4proto tcp tcp dport 3240 drop{comment};\n" + " iifname != \"lo\" meta l4proto tcp tcp dport 3240 drop{comment};" ) .expect("writing to a String cannot fail"); } @@ -3848,19 +3849,14 @@ fn render_env_nft_subset(host: &HostJson, env: &NetEnv) -> String { let chain = format!("forward-{}", env.env); let bridge_ifname = format!("br-{}-up", env.env); let mut buf = String::new(); - write!( - buf, - "table inet d2b {{\n chain \"{chain}\" {{ comment \"{marker}\";\n" - ) - .expect("writing to a String cannot fail"); - write!( - buf, - " ct state established,related accept comment \"{marker}\";\n", - ) - .expect("writing to a String cannot fail"); - write!( + writeln!(buf, "table inet d2b {{").expect("writing to a String cannot fail"); + writeln!(buf, " chain \"{chain}\" {{ comment \"{marker}\";") + .expect("writing to a String cannot fail"); + writeln!(buf, " ct state established,related accept comment \"{marker}\";") + .expect("writing to a String cannot fail"); + writeln!( buf, - " iifname \"{}\" ct state new accept comment \"{}\";\n", + " iifname \"{}\" ct state new accept comment \"{}\";", bridge_ifname, marker ) .expect("writing to a String cannot fail"); @@ -4047,9 +4043,9 @@ fn render_hosts_managed_block(host: &HostJson) -> String { buf.push('\n'); buf.push_str("# managed by d2b broker - do not edit by hand\n"); for env in &host.environments { - write!( + writeln!( buf, - "# env {} bridge {} mtu {}\n", + "# env {} bridge {} mtu {}", env.env, env.bridge.as_str(), env.mtu diff --git a/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs b/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs index c01c4112e..5b6e4d9be 100644 --- a/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs +++ b/packages/d2b-provider-clipboard-wayland/src/controller/mod.rs @@ -71,25 +71,47 @@ pub struct DisplayDependencyEvidence { pub(crate) session_digest: [u8; 32], } -/// Validate the Core-authenticated display route shape: canonical display -/// Provider, display v3 service, UnixPeer evidence, Local locality, a User -/// subject, nonzero generations, and a Host execution context. -fn validate_authenticated_route_shape( - provider_ref: &ResourceRef, - service: &str, +/// Plain-field view of the display route shape the controller validates. +/// `user_ref_type` is `None` for the Core-authenticated route and carries +/// the committed User resource type for the daemon-committed route. +struct DisplayRouteShape<'a> { + provider_ref: &'a ResourceRef, + service: &'a str, evidence_class: EvidenceClass, locality: Locality, - subject_type: &str, + subject_type: &'a str, + user_ref_type: Option<&'a str>, reconnect_generation: u64, provider_generation: u64, - host_execution_type: &str, + host_execution_type: &'a str, controller_generation: u64, +} + +/// Validate the Core-authenticated display route shape: canonical display +/// Provider, display v3 service, UnixPeer evidence, Local locality, a User +/// subject, no committed User reference, nonzero generations, and a Host +/// execution context. +fn validate_authenticated_route_shape( + shape: DisplayRouteShape<'_>, ) -> Result<(), &'static str> { + let DisplayRouteShape { + provider_ref, + service, + evidence_class, + locality, + subject_type, + user_ref_type, + reconnect_generation, + provider_generation, + host_execution_type, + controller_generation, + } = shape; if provider_ref.to_canonical_string() != DISPLAY_PROVIDER_REF || service != "d2b.display.v3" || evidence_class != EvidenceClass::UnixPeer || locality != Locality::Local || subject_type != "User" + || user_ref_type.is_some() || reconnect_generation == 0 || provider_generation == 0 || host_execution_type != "Host" @@ -105,23 +127,26 @@ fn validate_authenticated_route_shape( /// a Guest subject, a committed User reference, nonzero generations, and a /// Host execution context. fn validate_committed_display_route_shape( - provider_ref: &ResourceRef, - service: &str, - evidence_class: EvidenceClass, - locality: Locality, - subject_type: &str, - user_ref_type: &str, - reconnect_generation: u64, - provider_generation: u64, - host_execution_type: &str, - controller_generation: u64, + shape: DisplayRouteShape<'_>, ) -> Result<(), &'static str> { + let DisplayRouteShape { + provider_ref, + service, + evidence_class, + locality, + subject_type, + user_ref_type, + reconnect_generation, + provider_generation, + host_execution_type, + controller_generation, + } = shape; if provider_ref.to_canonical_string() != DISPLAY_PROVIDER_REF || service != "d2b.display.v3" || evidence_class != EvidenceClass::UnixPeer || locality != Locality::Local || subject_type != "Guest" - || user_ref_type != "User" + || user_ref_type != Some("User") || reconnect_generation == 0 || provider_generation == 0 || host_execution_type != "Host" @@ -154,17 +179,18 @@ impl DisplayDependencyEvidence { let Some(controller_generation) = route.controller_generation() else { return Err("clipboard-display-unauthenticated"); }; - validate_authenticated_route_shape( + validate_authenticated_route_shape(DisplayRouteShape { provider_ref, - route.service().as_str(), - route.evidence_class(), - route.locality(), - route.subject_ref().resource_type().as_str(), - route.reconnect_generation().get(), - provider_generation.get(), - host_execution_ref.resource_type().as_str(), - controller_generation.get(), - )?; + service: route.service().as_str(), + evidence_class: route.evidence_class(), + locality: route.locality(), + subject_type: route.subject_ref().resource_type().as_str(), + user_ref_type: None, + reconnect_generation: route.reconnect_generation().get(), + provider_generation: provider_generation.get(), + host_execution_type: host_execution_ref.resource_type().as_str(), + controller_generation: controller_generation.get(), + })?; let mut digest = Sha256::new(); digest.update(provider_ref.to_canonical_string().as_bytes()); digest.update([0]); @@ -211,18 +237,18 @@ impl DisplayDependencyEvidence { let Some(controller_generation) = route.controller_generation() else { return Err("clipboard-display-unauthenticated"); }; - validate_committed_display_route_shape( + validate_committed_display_route_shape(DisplayRouteShape { provider_ref, - route.service().as_str(), - route.evidence_class(), - route.locality(), - route.subject_ref().resource_type().as_str(), - user_ref.resource_type().as_str(), - route.reconnect_generation().get(), - provider_generation.get(), - host_execution_ref.resource_type().as_str(), - controller_generation.get(), - )?; + service: route.service().as_str(), + evidence_class: route.evidence_class(), + locality: route.locality(), + subject_type: route.subject_ref().resource_type().as_str(), + user_ref_type: Some(user_ref.resource_type().as_str()), + reconnect_generation: route.reconnect_generation().get(), + provider_generation: provider_generation.get(), + host_execution_type: host_execution_ref.resource_type().as_str(), + controller_generation: controller_generation.get(), + })?; let mut digest = Sha256::new(); digest.update(provider_ref.to_canonical_string().as_bytes()); digest.update([0]); @@ -401,58 +427,56 @@ mod tests { ResourceRef::parse(DISPLAY_PROVIDER_REF).unwrap() } - fn assert_authenticated_shape_rejected( - provider_ref: &ResourceRef, - service: &str, + /// One wrong-value permutation of a display route shape: every field + /// except the one under test carries the canonical value. + #[derive(Clone, Copy)] + struct WrongRoute { + provider: &'static str, + service: &'static str, evidence_class: EvidenceClass, locality: Locality, - subject_type: &str, + subject_type: &'static str, + user_ref_type: Option<&'static str>, reconnect_generation: u64, provider_generation: u64, - host_execution_type: &str, + host_execution_type: &'static str, controller_generation: u64, - ) { + } + + fn assert_authenticated_shape_rejected(case: WrongRoute) { + let provider_ref = ResourceRef::parse(case.provider).unwrap(); assert_eq!( - validate_authenticated_route_shape( - provider_ref, - service, - evidence_class, - locality, - subject_type, - reconnect_generation, - provider_generation, - host_execution_type, - controller_generation, - ), + validate_authenticated_route_shape(DisplayRouteShape { + provider_ref: &provider_ref, + service: case.service, + evidence_class: case.evidence_class, + locality: case.locality, + subject_type: case.subject_type, + user_ref_type: case.user_ref_type, + reconnect_generation: case.reconnect_generation, + provider_generation: case.provider_generation, + host_execution_type: case.host_execution_type, + controller_generation: case.controller_generation, + }), Err("clipboard-display-unauthenticated") ); } - fn assert_committed_shape_rejected( - provider_ref: &ResourceRef, - service: &str, - evidence_class: EvidenceClass, - locality: Locality, - subject_type: &str, - user_ref_type: &str, - reconnect_generation: u64, - provider_generation: u64, - host_execution_type: &str, - controller_generation: u64, - ) { + fn assert_committed_shape_rejected(case: WrongRoute) { + let provider_ref = ResourceRef::parse(case.provider).unwrap(); assert_eq!( - validate_committed_display_route_shape( - provider_ref, - service, - evidence_class, - locality, - subject_type, - user_ref_type, - reconnect_generation, - provider_generation, - host_execution_type, - controller_generation, - ), + validate_committed_display_route_shape(DisplayRouteShape { + provider_ref: &provider_ref, + service: case.service, + evidence_class: case.evidence_class, + locality: case.locality, + subject_type: case.subject_type, + user_ref_type: case.user_ref_type, + reconnect_generation: case.reconnect_generation, + provider_generation: case.provider_generation, + host_execution_type: case.host_execution_type, + controller_generation: case.controller_generation, + }), Err("clipboard-display-unauthenticated") ); } @@ -472,96 +496,79 @@ mod tests { #[test] fn authenticated_route_shape_accepts_only_the_canonical_user_route() { + let provider_ref = display_provider(); assert_eq!( - validate_authenticated_route_shape( - &display_provider(), - DISPLAY_SERVICE, - EvidenceClass::UnixPeer, - Locality::Local, - "User", - 1, - 1, - "Host", - 1, - ), + validate_authenticated_route_shape(DisplayRouteShape { + provider_ref: &provider_ref, + service: DISPLAY_SERVICE, + evidence_class: EvidenceClass::UnixPeer, + locality: Locality::Local, + subject_type: "User", + user_ref_type: None, + reconnect_generation: 1, + provider_generation: 1, + host_execution_type: "Host", + controller_generation: 1, + }), Ok(()) ); } #[test] fn authenticated_route_shape_rejects_each_wrong_value() { - let cases: [(&str, &str, EvidenceClass, Locality, &str, u64, u64, &str, u64); 9] = [ - ("Provider/other", DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, "d2b.other.v3", EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::EnrolledKk, Locality::Local, "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Remote, "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 0, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 0, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Guest", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", 1, 1, "Host", 0), + let cases: [WrongRoute; 10] = [ + WrongRoute { provider: "Provider/other", service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: None, reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: "d2b.other.v3", evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: None, reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::EnrolledKk, locality: Locality::Local, subject_type: "User", user_ref_type: None, reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Remote, subject_type: "User", user_ref_type: None, reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: None, reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: None, reconnect_generation: 0, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: None, reconnect_generation: 1, provider_generation: 0, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: None, reconnect_generation: 1, provider_generation: 1, host_execution_type: "Guest", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: None, reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 0 }, ]; - for (provider, service, evidence_class, locality, subject, reconnect, provider_generation, host, controller) in cases { - assert_authenticated_shape_rejected( - &ResourceRef::parse(provider).unwrap(), - service, - evidence_class, - locality, - subject, - reconnect, - provider_generation, - host, - controller, - ); + for case in cases { + assert_authenticated_shape_rejected(case); } } #[test] fn committed_display_route_shape_accepts_only_the_canonical_guest_route() { + let provider_ref = display_provider(); assert_eq!( - validate_committed_display_route_shape( - &display_provider(), - DISPLAY_SERVICE, - EvidenceClass::UnixPeer, - Locality::Local, - "Guest", - "User", - 1, - 1, - "Host", - 1, - ), + validate_committed_display_route_shape(DisplayRouteShape { + provider_ref: &provider_ref, + service: DISPLAY_SERVICE, + evidence_class: EvidenceClass::UnixPeer, + locality: Locality::Local, + subject_type: "Guest", + user_ref_type: Some("User"), + reconnect_generation: 1, + provider_generation: 1, + host_execution_type: "Host", + controller_generation: 1, + }), Ok(()) ); } #[test] fn committed_display_route_shape_rejects_each_wrong_value() { - let cases: [(&str, &str, EvidenceClass, Locality, &str, &str, u64, u64, &str, u64); 10] = [ - ("Provider/other", DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, "d2b.other.v3", EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::EnrolledKk, Locality::Local, "Guest", "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Remote, "Guest", "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "User", "User", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "Guest", 1, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 0, 1, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 0, "Host", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Guest", 1), - (DISPLAY_PROVIDER_REF, DISPLAY_SERVICE, EvidenceClass::UnixPeer, Locality::Local, "Guest", "User", 1, 1, "Host", 0), + let cases: [WrongRoute; 10] = [ + WrongRoute { provider: "Provider/other", service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: "d2b.other.v3", evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::EnrolledKk, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Remote, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "User", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("Guest"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 0, provider_generation: 1, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 0, host_execution_type: "Host", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Guest", controller_generation: 1 }, + WrongRoute { provider: DISPLAY_PROVIDER_REF, service: DISPLAY_SERVICE, evidence_class: EvidenceClass::UnixPeer, locality: Locality::Local, subject_type: "Guest", user_ref_type: Some("User"), reconnect_generation: 1, provider_generation: 1, host_execution_type: "Host", controller_generation: 0 }, ]; - for (provider, service, evidence_class, locality, subject, user_ref, reconnect, provider_generation, host, controller) in cases { - assert_committed_shape_rejected( - &ResourceRef::parse(provider).unwrap(), - service, - evidence_class, - locality, - subject, - user_ref, - reconnect, - provider_generation, - host, - controller, - ); + for case in cases { + assert_committed_shape_rejected(case); } } diff --git a/packages/d2b-session/src/admission.rs b/packages/d2b-session/src/admission.rs index c3892bf08..12d515aff 100644 --- a/packages/d2b-session/src/admission.rs +++ b/packages/d2b-session/src/admission.rs @@ -686,14 +686,13 @@ fn admit_or_record(engine: &mut SessionEngine, result: Result) -> Re where T: OwnedTransport, { - result.map_err(|error| { + result.inspect_err(|&error| { engine.record_failure( MetricEvent::ConnectAttempt, ChannelClass::SessionControl, OperationClass::Connect, error, ); - error }) } diff --git a/packages/d2b-session/src/record.rs b/packages/d2b-session/src/record.rs index 7566f0502..880b92f8b 100644 --- a/packages/d2b-session/src/record.rs +++ b/packages/d2b-session/src/record.rs @@ -177,10 +177,10 @@ impl RecordProtector { return Err(SessionError::new(SessionErrorCode::RecordMalformed)); } self.receive_sequence.accept(header.sequence)?; - if self.replay_order.len() == REPLAY_CACHE_ENTRIES { - if let Some(evicted) = self.replay_order.pop_front() { - self.replay_digests.remove(&evicted); - } + if self.replay_order.len() == REPLAY_CACHE_ENTRIES + && let Some(evicted) = self.replay_order.pop_front() + { + self.replay_digests.remove(&evicted); } self.replay_order.push_back(digest); self.replay_digests.insert(digest); diff --git a/packages/d2b-sk-frontend/src/uhid.rs b/packages/d2b-sk-frontend/src/uhid.rs index 7e13ba4db..032be7e8a 100644 --- a/packages/d2b-sk-frontend/src/uhid.rs +++ b/packages/d2b-sk-frontend/src/uhid.rs @@ -502,7 +502,8 @@ mod tests { #[test] fn parse_event_dispatch_table() { - let cases: &[(u32, fn(&UhidEvent) -> bool)] = &[ + type Case = (u32, fn(&UhidEvent) -> bool); + let cases: &[Case] = &[ (UHID_OUTPUT, |e| matches!(e, UhidEvent::Output { .. })), (UHID_GET_REPORT, |e| matches!(e, UhidEvent::GetReport { .. })), (UHID_START, |e| matches!(e, UhidEvent::Lifecycle(()))), diff --git a/packages/d2b-telemetry/src/meter_registry.rs b/packages/d2b-telemetry/src/meter_registry.rs index b87309863..f067f853f 100644 --- a/packages/d2b-telemetry/src/meter_registry.rs +++ b/packages/d2b-telemetry/src/meter_registry.rs @@ -3,8 +3,7 @@ use std::collections::BTreeMap; use crate::metric_label_policy::{ - IdentityCanaries, MetricDescriptor, MetricPolicyError, canonical_descriptor, - validate_data_point, + IdentityCanaries, MetricDescriptor, MetricPolicyError, validate_data_point, }; pub use d2b_contracts_provider::v3::telemetry_policy::label; @@ -193,6 +192,7 @@ pub const STORE_WRITE_BUCKETS_SECONDS: &[f64] = &[0.001, 0.005, 0.01, 0.025, 0.0 #[cfg(test)] mod tests { use super::*; + use crate::metric_label_policy::canonical_descriptor; #[test] fn controller_hint_buckets_accept_in_range_and_reject_out_of_range_values() { diff --git a/packages/d2b/src/context.rs b/packages/d2b/src/context.rs index 930a7725f..ad49207e2 100644 --- a/packages/d2b/src/context.rs +++ b/packages/d2b/src/context.rs @@ -562,6 +562,7 @@ impl CliSocket { /// cannot observe each other's datagrams. The buffer keeps its full /// length between calls, so the zeroed 1 MiB allocation happens once per /// socket instead of once per received frame. + #[allow(clippy::disallowed_methods, reason = "CLI-only path")] async fn read_frame(&self) -> io::Result> { loop { let mut ready = self.fd.readable().await?; diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 091db8a8d..555be5923 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1284,12 +1284,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 966ea1166..0253efb24 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index 3fe1be6ea..6c295e7e4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1092,12 +1092,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 966ea1166..0253efb24 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 924cd36ed..4605d84b0 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1286,12 +1286,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 2851e3278..6704376a2 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index b4a513cbb..d682063ef 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1094,12 +1094,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 2851e3278..6704376a2 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index b629bcf49..35c3df180 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1286,12 +1286,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index 74c1f1c03..fc90df939 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 6c983b7ca..4fb432144 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1094,12 +1094,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index 74c1f1c03..fc90df939 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 00723e119..8e8f2a062 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1284,12 +1284,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index 966ea1166..0253efb24 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index 051a0ccc9..8391216e9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1092,12 +1092,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index 966ea1166..0253efb24 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index 4e4401993..3219c5f4a 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -853,7 +853,6 @@ dependencies = [ "d2b-core", "d2b-provider-config-nixos", "d2b-resource-client", - "d2b-zone-routing", "nix 0.29.0", "rustix 0.38.44", "schemars", @@ -948,7 +947,6 @@ dependencies = [ "serde_json", "sha2", "snow", - "tempfile", "tokio", "ttrpc", ] @@ -1142,7 +1140,6 @@ dependencies = [ "d2b-resource-types", "parking_lot", "ring", - "serde", "serde_json", "sha2", "tokio", @@ -1174,7 +1171,6 @@ dependencies = [ "d2b-contracts-resource", "libc", "nix 0.29.0", - "schemars", "serde", "serde_json", "tempfile", @@ -1347,12 +1343,10 @@ dependencies = [ name = "d2b-provider-device-gpu" version = "0.0.0-bootstrap" dependencies = [ - "async-trait", "d2b-contracts-resource", "d2b-core-controller", "d2b-provider-toolkit", "d2b-resource-runtime", - "d2b-resource-types", "parking_lot", "serde", "serde_json", @@ -1519,7 +1513,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "sha2", "tokio", "tracing", ] @@ -1746,7 +1739,6 @@ dependencies = [ "d2b-resource-types", "schemars", "serde", - "serde_json", "tokio", ] @@ -1869,7 +1861,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "tokio", "tracing", ] @@ -1968,7 +1959,7 @@ dependencies = [ "tokio-tungstenite", "tracing", "urlencoding", - "webpki-roots 0.26.11", + "webpki-roots 1.0.9", "zeroize", ] @@ -2049,7 +2040,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", "tracing", @@ -2241,14 +2231,11 @@ name = "d2b-session" version = "0.0.0-bootstrap" dependencies = [ "async-trait", - "d2b-audit", "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-resource-api", - "d2b-telemetry", "futures-util", "protobuf", - "serde_json", "sha2", "snow", "tokio", @@ -2302,7 +2289,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index b8c327120..f7d35b31f 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4391,12 +4391,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-bus@0.0.0-bootstrap#path", - "to": "tempfile@3.27.0#registry+https://github.com/rust-lang/crates.io-index", - "kind": "dev", - "target": null - }, { "from": "d2b-bus@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5015,12 +5009,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", - "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -5135,12 +5123,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", - "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -5150,7 +5132,7 @@ { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", + "kind": "dev", "target": null }, { @@ -5687,12 +5669,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", - "kind": "proc-macro", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -5717,12 +5693,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "d2b-resource-types@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", @@ -6347,12 +6317,6 @@ "kind": "dev", "target": null }, - { - "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -7319,12 +7283,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-quota@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-quota@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -7649,12 +7607,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-system-core@0.0.0-bootstrap#path", - "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-system-core@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8059,7 +8011,7 @@ }, { "from": "d2b-provider-transport-azure-relay@0.0.0-bootstrap#path", - "to": "webpki-roots@0.26.11#registry+https://github.com/rust-lang/crates.io-index", + "to": "webpki-roots@1.0.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, @@ -8279,12 +8231,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -8954,7 +8900,7 @@ { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", + "kind": "dev", "target": null }, { @@ -9149,12 +9095,6 @@ "kind": "proc-macro", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-audit@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -9173,12 +9113,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-telemetry@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "futures-util@0.3.34#registry+https://github.com/rust-lang/crates.io-index", @@ -9191,12 +9125,6 @@ "kind": "dev", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "dev", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", @@ -9311,12 +9239,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -9527,12 +9449,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b@0.0.0-bootstrap#path", - "to": "d2b-zone-routing@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b@0.0.0-bootstrap#path", "to": "nix@0.29.0#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index 72bb28527..0377af754 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index 4e4401993..3219c5f4a 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -853,7 +853,6 @@ dependencies = [ "d2b-core", "d2b-provider-config-nixos", "d2b-resource-client", - "d2b-zone-routing", "nix 0.29.0", "rustix 0.38.44", "schemars", @@ -948,7 +947,6 @@ dependencies = [ "serde_json", "sha2", "snow", - "tempfile", "tokio", "ttrpc", ] @@ -1142,7 +1140,6 @@ dependencies = [ "d2b-resource-types", "parking_lot", "ring", - "serde", "serde_json", "sha2", "tokio", @@ -1174,7 +1171,6 @@ dependencies = [ "d2b-contracts-resource", "libc", "nix 0.29.0", - "schemars", "serde", "serde_json", "tempfile", @@ -1347,12 +1343,10 @@ dependencies = [ name = "d2b-provider-device-gpu" version = "0.0.0-bootstrap" dependencies = [ - "async-trait", "d2b-contracts-resource", "d2b-core-controller", "d2b-provider-toolkit", "d2b-resource-runtime", - "d2b-resource-types", "parking_lot", "serde", "serde_json", @@ -1519,7 +1513,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "sha2", "tokio", "tracing", ] @@ -1746,7 +1739,6 @@ dependencies = [ "d2b-resource-types", "schemars", "serde", - "serde_json", "tokio", ] @@ -1869,7 +1861,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "tokio", "tracing", ] @@ -1968,7 +1959,7 @@ dependencies = [ "tokio-tungstenite", "tracing", "urlencoding", - "webpki-roots 0.26.11", + "webpki-roots 1.0.9", "zeroize", ] @@ -2049,7 +2040,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", "tracing", @@ -2241,14 +2231,11 @@ name = "d2b-session" version = "0.0.0-bootstrap" dependencies = [ "async-trait", - "d2b-audit", "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-resource-api", - "d2b-telemetry", "futures-util", "protobuf", - "serde_json", "sha2", "snow", "tokio", @@ -2302,7 +2289,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index f7890fdac..d7db2118f 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4841,12 +4841,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", - "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -4937,24 +4931,12 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", - "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, - { - "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5429,12 +5411,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", - "kind": "proc-macro", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -5459,12 +5435,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "d2b-resource-types@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", @@ -6065,12 +6035,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6959,12 +6923,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-quota@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-resource-export@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7199,12 +7157,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-system-core@0.0.0-bootstrap#path", - "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-system-core@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -7567,7 +7519,7 @@ }, { "from": "d2b-provider-transport-azure-relay@0.0.0-bootstrap#path", - "to": "webpki-roots@0.26.11#registry+https://github.com/rust-lang/crates.io-index", + "to": "webpki-roots@1.0.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, @@ -7769,12 +7721,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -8339,12 +8285,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-resource-runtime@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "ractor@0.16.5#registry+https://github.com/rust-lang/crates.io-index", @@ -8519,12 +8459,6 @@ "kind": "proc-macro", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-audit@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -8543,12 +8477,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-telemetry@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "futures-util@0.3.34#registry+https://github.com/rust-lang/crates.io-index", @@ -8663,12 +8591,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -8849,12 +8771,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b@0.0.0-bootstrap#path", - "to": "d2b-zone-routing@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b@0.0.0-bootstrap#path", "to": "nix@0.29.0#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index 72bb28527..0377af754 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index ee238ec25..64f24b5c1 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1278,12 +1278,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 116e6cfb7..305440197 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index 7d5a8bd13..d19ddd7c8 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1086,12 +1086,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 116e6cfb7..305440197 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 425fe6ed7..46202be0e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1280,12 +1280,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 8e8afe2ae..d9d1b4233 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index e802af7f7..c9ee284b2 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1088,12 +1088,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 8e8afe2ae..d9d1b4233 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index de3e5edd9..4619e988d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1280,12 +1280,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index 52c1c08c1..faa836089 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index f69f8aebf..aabfb01f4 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1088,12 +1088,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index 52c1c08c1..faa836089 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index a303dbd4f..c742450e7 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1278,12 +1278,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index 116e6cfb7..305440197 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock index 2a9b4ea08..047aa576d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/Cargo.lock @@ -396,7 +396,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 614a78fac..7ff09a342 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1086,12 +1086,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index 116e6cfb7..305440197 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index 4e4401993..3219c5f4a 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -853,7 +853,6 @@ dependencies = [ "d2b-core", "d2b-provider-config-nixos", "d2b-resource-client", - "d2b-zone-routing", "nix 0.29.0", "rustix 0.38.44", "schemars", @@ -948,7 +947,6 @@ dependencies = [ "serde_json", "sha2", "snow", - "tempfile", "tokio", "ttrpc", ] @@ -1142,7 +1140,6 @@ dependencies = [ "d2b-resource-types", "parking_lot", "ring", - "serde", "serde_json", "sha2", "tokio", @@ -1174,7 +1171,6 @@ dependencies = [ "d2b-contracts-resource", "libc", "nix 0.29.0", - "schemars", "serde", "serde_json", "tempfile", @@ -1347,12 +1343,10 @@ dependencies = [ name = "d2b-provider-device-gpu" version = "0.0.0-bootstrap" dependencies = [ - "async-trait", "d2b-contracts-resource", "d2b-core-controller", "d2b-provider-toolkit", "d2b-resource-runtime", - "d2b-resource-types", "parking_lot", "serde", "serde_json", @@ -1519,7 +1513,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "sha2", "tokio", "tracing", ] @@ -1746,7 +1739,6 @@ dependencies = [ "d2b-resource-types", "schemars", "serde", - "serde_json", "tokio", ] @@ -1869,7 +1861,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "tokio", "tracing", ] @@ -1968,7 +1959,7 @@ dependencies = [ "tokio-tungstenite", "tracing", "urlencoding", - "webpki-roots 0.26.11", + "webpki-roots 1.0.9", "zeroize", ] @@ -2049,7 +2040,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", "tracing", @@ -2241,14 +2231,11 @@ name = "d2b-session" version = "0.0.0-bootstrap" dependencies = [ "async-trait", - "d2b-audit", "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-resource-api", - "d2b-telemetry", "futures-util", "protobuf", - "serde_json", "sha2", "snow", "tokio", @@ -2302,7 +2289,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index eac5c3a02..2f7a3c151 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4429,12 +4429,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-bus@0.0.0-bootstrap#path", - "to": "tempfile@3.27.0#registry+https://github.com/rust-lang/crates.io-index", - "kind": "dev", - "target": null - }, { "from": "d2b-bus@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5053,12 +5047,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", - "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -5173,12 +5161,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", - "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -5188,7 +5170,7 @@ { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", + "kind": "dev", "target": null }, { @@ -5725,12 +5707,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", - "kind": "proc-macro", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -5755,12 +5731,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "d2b-resource-types@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", @@ -6385,12 +6355,6 @@ "kind": "dev", "target": null }, - { - "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -7357,12 +7321,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-quota@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-quota@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -7687,12 +7645,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-system-core@0.0.0-bootstrap#path", - "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-system-core@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8097,7 +8049,7 @@ }, { "from": "d2b-provider-transport-azure-relay@0.0.0-bootstrap#path", - "to": "webpki-roots@0.26.11#registry+https://github.com/rust-lang/crates.io-index", + "to": "webpki-roots@1.0.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, @@ -8317,12 +8269,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -8992,7 +8938,7 @@ { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", + "kind": "dev", "target": null }, { @@ -9187,12 +9133,6 @@ "kind": "proc-macro", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-audit@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -9211,12 +9151,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-telemetry@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "futures-util@0.3.34#registry+https://github.com/rust-lang/crates.io-index", @@ -9229,12 +9163,6 @@ "kind": "dev", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "dev", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", @@ -9349,12 +9277,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -9565,12 +9487,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b@0.0.0-bootstrap#path", - "to": "d2b-zone-routing@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b@0.0.0-bootstrap#path", "to": "nix@0.29.0#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index 5a4c7b37b..f81d43fa9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index 4e4401993..3219c5f4a 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -853,7 +853,6 @@ dependencies = [ "d2b-core", "d2b-provider-config-nixos", "d2b-resource-client", - "d2b-zone-routing", "nix 0.29.0", "rustix 0.38.44", "schemars", @@ -948,7 +947,6 @@ dependencies = [ "serde_json", "sha2", "snow", - "tempfile", "tokio", "ttrpc", ] @@ -1142,7 +1140,6 @@ dependencies = [ "d2b-resource-types", "parking_lot", "ring", - "serde", "serde_json", "sha2", "tokio", @@ -1174,7 +1171,6 @@ dependencies = [ "d2b-contracts-resource", "libc", "nix 0.29.0", - "schemars", "serde", "serde_json", "tempfile", @@ -1347,12 +1343,10 @@ dependencies = [ name = "d2b-provider-device-gpu" version = "0.0.0-bootstrap" dependencies = [ - "async-trait", "d2b-contracts-resource", "d2b-core-controller", "d2b-provider-toolkit", "d2b-resource-runtime", - "d2b-resource-types", "parking_lot", "serde", "serde_json", @@ -1519,7 +1513,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "sha2", "tokio", "tracing", ] @@ -1746,7 +1739,6 @@ dependencies = [ "d2b-resource-types", "schemars", "serde", - "serde_json", "tokio", ] @@ -1869,7 +1861,6 @@ dependencies = [ "d2b-contracts-resource", "serde", "serde_json", - "tokio", "tracing", ] @@ -1968,7 +1959,7 @@ dependencies = [ "tokio-tungstenite", "tracing", "urlencoding", - "webpki-roots 0.26.11", + "webpki-roots 1.0.9", "zeroize", ] @@ -2049,7 +2040,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", "tracing", @@ -2241,14 +2231,11 @@ name = "d2b-session" version = "0.0.0-bootstrap" dependencies = [ "async-trait", - "d2b-audit", "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-resource-api", - "d2b-telemetry", "futures-util", "protobuf", - "serde_json", "sha2", "snow", "tokio", @@ -2302,7 +2289,6 @@ version = "0.0.0-bootstrap" dependencies = [ "d2b-contracts-provider", "d2b-contracts-resource", - "rustix 0.38.44", "serde", "serde_json", "sha2", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index d30796731..bd09289ce 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -4879,12 +4879,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", - "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-activation-nixos@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -4975,24 +4969,12 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", - "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, - { - "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-audio-pipewire@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5467,12 +5449,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", - "kind": "proc-macro", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -5497,12 +5473,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", - "to": "d2b-resource-types@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-device-gpu@0.0.0-bootstrap#path", "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", @@ -6103,12 +6073,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest-azure-container-apps@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6997,12 +6961,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-quota@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-resource-export@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7237,12 +7195,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-system-core@0.0.0-bootstrap#path", - "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-system-core@0.0.0-bootstrap#path", "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", @@ -7605,7 +7557,7 @@ }, { "from": "d2b-provider-transport-azure-relay@0.0.0-bootstrap#path", - "to": "webpki-roots@0.26.11#registry+https://github.com/rust-lang/crates.io-index", + "to": "webpki-roots@1.0.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, @@ -7807,12 +7759,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume-binding@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", @@ -8377,12 +8323,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-resource-runtime@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "ractor@0.16.5#registry+https://github.com/rust-lang/crates.io-index", @@ -8557,12 +8497,6 @@ "kind": "proc-macro", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-audit@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", @@ -8581,12 +8515,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-session@0.0.0-bootstrap#path", - "to": "d2b-telemetry@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b-session@0.0.0-bootstrap#path", "to": "futures-util@0.3.34#registry+https://github.com/rust-lang/crates.io-index", @@ -8701,12 +8629,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-telemetry@0.0.0-bootstrap#path", - "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-telemetry@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -8887,12 +8809,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b@0.0.0-bootstrap#path", - "to": "d2b-zone-routing@0.0.0-bootstrap#path", - "kind": "normal", - "target": null - }, { "from": "d2b@0.0.0-bootstrap#path", "to": "nix@0.29.0#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index 5a4c7b37b..f81d43fa9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "195a351ae65d71fdb0df3fb6f70bb2d689e0c2f81971e306f2b3de7e351022a5", + "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index ae8848985..c222c88c4 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -43,12 +43,12 @@ }, { "file": "packages/d2b-broker/src/ops/nft.rs", - "line": 817, + "line": 819, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { "file": "packages/d2b-broker/src/ops/nft.rs", - "line": 818, + "line": 820, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { @@ -98,7 +98,7 @@ }, { "file": "packages/d2b-broker/src/ops/store_view_posture.rs", - "line": 451, + "line": 460, "reason": "tokio OpenOptions builder flag, not a lock acquisition" }, { @@ -343,82 +343,82 @@ }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 489, + "line": 492, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 497, + "line": 501, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 527, + "line": 532, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 532, + "line": 538, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 592, + "line": 599, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 599, + "line": 607, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 1031, + "line": 1039, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 1087, + "line": 1095, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/test_support.rs", - "line": 43, + "line": 45, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-security-key/src/test_support.rs", - "line": 44, + "line": 47, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-security-key/src/test_support.rs", - "line": 55, + "line": 59, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-security-key/src/test_support.rs", - "line": 78, + "line": 83, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-security-key/src/test_support.rs", - "line": 89, + "line": 95, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 876, + "line": 873, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 885, + "line": 882, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 898, + "line": 895, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -513,72 +513,72 @@ }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1621, + "line": 1620, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1628, + "line": 1627, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1640, + "line": 1639, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1641, + "line": 1640, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1676, + "line": 1675, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1703, + "line": 1702, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1709, + "line": 1708, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1716, + "line": 1715, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1722, + "line": 1721, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1729, + "line": 1728, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1756, + "line": 1755, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1764, + "line": 1763, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/effects_service.rs", - "line": 1443, + "line": 1444, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/effects_service.rs", - "line": 2194, + "line": 2195, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -898,107 +898,107 @@ }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1231, + "line": 1237, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1248, + "line": 1255, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1264, + "line": 1272, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1275, + "line": 1284, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1289, + "line": 1299, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1291, + "line": 1303, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1315, + "line": 1330, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 72, + "line": 73, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 84, + "line": 86, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 96, + "line": 99, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 104, + "line": 108, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 109, + "line": 114, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 118, + "line": 124, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 803, + "line": 804, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 820, + "line": 821, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 836, + "line": 837, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 844, + "line": 845, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 858, + "line": 859, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 860, + "line": 861, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1130, + "line": 1131, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1318, + "line": 1319, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1148,17 +1148,17 @@ }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 2522, + "line": 2471, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 7534, + "line": 7478, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 8685, + "line": 8629, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From da77a23f344726132b83d9fea1868c03df6980a8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:22:28 -0700 Subject: [PATCH 553/726] contracts-broker: move audit_wire re-export to crate root The pub use arm in broker_wire.rs re-exported d2b_contracts audit-wire types into the module surface, off the house single-surface pattern that places re-export arms in lib.rs. Move the arm to the crate root and have broker_wire.rs import the two types it uses directly from d2b_contracts::audit_wire. --- changelog.d/w4-04-audit-wire-reexport.md | 3 +++ packages/d2b-contracts-broker/src/broker_wire.rs | 3 +-- packages/d2b-contracts-broker/src/lib.rs | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changelog.d/w4-04-audit-wire-reexport.md diff --git a/changelog.d/w4-04-audit-wire-reexport.md b/changelog.d/w4-04-audit-wire-reexport.md new file mode 100644 index 000000000..ec5263dd4 --- /dev/null +++ b/changelog.d/w4-04-audit-wire-reexport.md @@ -0,0 +1,3 @@ +### Fixed + +- The broker contract crate now re-exports the audit-export wire types (`AuditExportCursor`, `AuditExportEntry`, `AuditExportErrorCode`) from the crate root instead of the `broker_wire` module, so each type has a single canonical re-export path. \ No newline at end of file diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 68097efb0..6a4902f4e 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -9,8 +9,7 @@ //! the opaque IDs to look up the typed intent in its own trusted bundle //! copy. See `d2b_contracts::types` for the newtype set. -use d2b_contracts::audit_wire::validate_audit_page; -pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}; +use d2b_contracts::audit_wire::{validate_audit_page, AuditExportCursor, AuditExportEntry}; use d2b_contracts::types::{ BundleClosureRef, BundleOpId, MediaRef, PathClass, RoleId, ScopeId, SubjectId, TracingSpanId, VmId, diff --git a/packages/d2b-contracts-broker/src/lib.rs b/packages/d2b-contracts-broker/src/lib.rs index 6fb525de7..6227dbaee 100644 --- a/packages/d2b-contracts-broker/src/lib.rs +++ b/packages/d2b-contracts-broker/src/lib.rs @@ -8,6 +8,7 @@ pub use broker_wire::BrokerRequest; pub use broker_wire::{ FORWARD_SOCKET_ENV, ForwardOperationOutcome, ForwardOperationRequest, ForwardOperationResponse, }; +pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}; pub use d2b_contracts::privileges_w3::W3BrokerOperation; use schemars::JsonSchema; From 7dadf99239f7198b69875c8ca67b3afba94f202b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:23:11 -0700 Subject: [PATCH 554/726] seccomp-profile: make seccomp_profile module private with explicit re-exports --- changelog.d/w4-08-seccomp-profile-module-privacy.md | 6 ++++++ packages/d2b-provider-seccomp-profile/src/lib.rs | 7 +++++-- packages/d2bd/src/foundation_seed.rs | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 changelog.d/w4-08-seccomp-profile-module-privacy.md diff --git a/changelog.d/w4-08-seccomp-profile-module-privacy.md b/changelog.d/w4-08-seccomp-profile-module-privacy.md new file mode 100644 index 000000000..7e9802498 --- /dev/null +++ b/changelog.d/w4-08-seccomp-profile-module-privacy.md @@ -0,0 +1,6 @@ +### Fixed + +- The `seccomp_profile` module of `d2b-provider-seccomp-profile` no longer + re-exports its entire surface through the crate root; only the items the + provider's public API and its consumers use are re-exported, so the + resource type's spec shapes are reachable at exactly one path. \ No newline at end of file diff --git a/packages/d2b-provider-seccomp-profile/src/lib.rs b/packages/d2b-provider-seccomp-profile/src/lib.rs index 9ca3aaa2a..fb1173bb0 100644 --- a/packages/d2b-provider-seccomp-profile/src/lib.rs +++ b/packages/d2b-provider-seccomp-profile/src/lib.rs @@ -16,7 +16,10 @@ mod driver; /// The Seccomp Profile ResourceType spec and status shapes owned by this crate. -pub mod seccomp_profile; +mod seccomp_profile; pub use driver::seccomp_profile_descriptor; -pub use seccomp_profile::*; +pub use seccomp_profile::{ + DeviceBind, DeviceNodeKind, DeviceNodePath, SECCOMP_PROFILE_RESOURCE_TYPE, + SeccompCgroups, SeccompDeviceAccess, SeccompNamespaces, SeccompProfileSpec, +}; diff --git a/packages/d2bd/src/foundation_seed.rs b/packages/d2bd/src/foundation_seed.rs index 6ac0b32c6..f2f5fb60a 100644 --- a/packages/d2bd/src/foundation_seed.rs +++ b/packages/d2bd/src/foundation_seed.rs @@ -22,7 +22,7 @@ use std::collections::{BTreeMap, BTreeSet}; use d2b_contracts_resource::v3::{ PayloadSchema, ResourceRef, canonical_json_bytes }; use d2b_provider_command::command::{ CommandSpec }; use d2b_provider_operation::operation::{ OperationSpec }; -use d2b_provider_seccomp_profile::seccomp_profile::{ SECCOMP_PROFILE_RESOURCE_TYPE, SeccompProfileSpec }; +use d2b_provider_seccomp_profile::{ SECCOMP_PROFILE_RESOURCE_TYPE, SeccompProfileSpec }; use d2b_contracts_zone_session::v3::{RoleBindingSpec, RoleResourceVerb, RoleSpec}; use d2b_resource_runtime::identity::ResourceTypeName; use d2b_resource_runtime::manager::{ @@ -1088,7 +1088,7 @@ impl std::error::Error for SeedError {} mod tests { use super::*; use d2b_provider_command::command::{ CommandArgvSlot, CommandExec, CommandIntent }; -use d2b_provider_seccomp_profile::seccomp_profile::{ DeviceBind, DeviceNodeKind, SeccompCgroups, SeccompDeviceAccess, SeccompNamespaces }; +use d2b_provider_seccomp_profile::{ DeviceBind, DeviceNodeKind, SeccompCgroups, SeccompDeviceAccess, SeccompNamespaces }; use d2b_contracts_resource::v3::{BoundedText, BoundedToken}; use serde_json::json; From df9c47795e89b91d3c1f4563dd0593518a02258a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:23:13 -0700 Subject: [PATCH 555/726] audit: close the W3 wave gate green Four lanes pass at d68d0dbcb: security scan clean against the merge base, blocking census at its committed baseline, 988 of 988 tests, and 11 of 11 host vmChecks with the U20 acceptance providers built. All 188 wave rows carry an outcome, and the row records the nine cross-slice break classes the first gate run found and the repair commit that closed them. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 9e702afda..0bccde516 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -40,7 +40,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U1 | `11bbfe41a` | pass | pass | pass (988 of 988 tests) | pass (11 of 11 vmChecks) | First attempt flaked on the load-sensitive `daemon_state_persistence` kill-during-startup race (passes standalone, not an audit row); the retry is green. The head carries the refreshed async-gate inventory for the broker line shifts. | | U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | -| W3 | `24198fff7` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. Gates to be run by Main on merge onto `09f9c6ae1`. | +| W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | ## Findings (965 rows) From 768457562da387c23d62931ff96763ffddce6a6f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:23:16 -0700 Subject: [PATCH 556/726] provider: re-export GuestControlEndpoint from d2b-resource-client --- .../w4-07-guest-control-endpoint-dedup.md | 3 + .../BUILD.bazel | 3 + .../Cargo.toml | 1 + .../src/guest_local.rs | 144 +----------------- 4 files changed, 14 insertions(+), 137 deletions(-) create mode 100644 changelog.d/w4-07-guest-control-endpoint-dedup.md diff --git a/changelog.d/w4-07-guest-control-endpoint-dedup.md b/changelog.d/w4-07-guest-control-endpoint-dedup.md new file mode 100644 index 000000000..5a9cf443b --- /dev/null +++ b/changelog.d/w4-07-guest-control-endpoint-dedup.md @@ -0,0 +1,3 @@ +### Fixed + +- `GuestControlEndpoint` is now defined once, in `d2b-resource-client`, and re-exported by `d2b-provider-guest-cloud-hypervisor`; construction and validation failures surface as `ClientError` variants instead of `GuestLocalError::EndpointMismatch`, and the unused `endpoint_uid()` accessor is removed. \ No newline at end of file diff --git a/packages/d2b-provider-guest-cloud-hypervisor/BUILD.bazel b/packages/d2b-provider-guest-cloud-hypervisor/BUILD.bazel index ca60cd9b9..4fed183ae 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/BUILD.bazel +++ b/packages/d2b-provider-guest-cloud-hypervisor/BUILD.bazel @@ -40,6 +40,7 @@ d2b_rust_library( "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", + "//packages/d2b-resource-client:d2b_resource_client", "//packages/d2b-session:d2b_session", "//packages/d2b-session-unix:d2b_session_unix", ] + all_crate_deps(normal = True, cargo_only = True), @@ -65,6 +66,7 @@ d2b_rust_library( "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", + "//packages/d2b-resource-client:d2b_resource_client", "//packages/d2b-session:d2b_session_test_support", "//packages/d2b-session-unix:d2b_session_unix_test_support", ] + all_crate_deps(normal = True, cargo_only = True), @@ -93,6 +95,7 @@ d2b_rust_test( "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", + "//packages/d2b-resource-client:d2b_resource_client", "//packages/d2b-session:d2b_session", "//packages/d2b-session-unix:d2b_session_unix", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), diff --git a/packages/d2b-provider-guest-cloud-hypervisor/Cargo.toml b/packages/d2b-provider-guest-cloud-hypervisor/Cargo.toml index 5f0f9e0c1..4913b5256 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/Cargo.toml +++ b/packages/d2b-provider-guest-cloud-hypervisor/Cargo.toml @@ -19,6 +19,7 @@ d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0- d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = "0.0.0-bootstrap" } d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } d2b-core = { path = "../d2b-core", version = "0.0.0-bootstrap" } +d2b-resource-client = { path = "../d2b-resource-client", version = "0.0.0-bootstrap" } async-trait = "0.1" d2b-session = { path = "../d2b-session", version = "0.0.0-bootstrap" } d2b-session-unix = { path = "../d2b-session-unix", version = "0.0.0-bootstrap", default-features = false, features = ["host-socket", "native-vsock"] } diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/guest_local.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/guest_local.rs index afb194283..687195e9c 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/guest_local.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/guest_local.rs @@ -7,10 +7,13 @@ use std::fmt; -use d2b_contracts_resource::v3::{ - ResourceGeneration, ResourceRef, ResourceUid, SchemaFingerprint, ZoneId, - activation_nixos::NIXOS_GENERATION_RESOURCE_TYPE, -}; +use d2b_contracts_resource::v3::activation_nixos::NIXOS_GENERATION_RESOURCE_TYPE; + +/// Authenticated, locator-free identity of a Guest-control Endpoint. +/// +/// Owned by `d2b-resource-client`; re-exported here so the Guest-local +/// vocabulary keeps its stable public path. +pub use d2b_resource_client::GuestControlEndpoint; /// Resource types admitted by the signed Guest seed schema. pub const GUEST_SEED_RESOURCE_TYPES: &[&str] = &[ @@ -44,137 +47,4 @@ impl fmt::Display for GuestLocalError { impl std::error::Error for GuestLocalError {} -/// Authenticated, locator-free identity of a Guest-control Endpoint. -#[derive(Clone, PartialEq, Eq)] -pub struct GuestControlEndpoint { - endpoint_ref: ResourceRef, - guest_ref: ResourceRef, - zone: ZoneId, - uid: ResourceUid, - resource_generation: ResourceGeneration, - endpoint_generation: ResourceGeneration, - provider_generation: ResourceGeneration, - schema_digest: SchemaFingerprint, - ready: bool, -} - -impl GuestControlEndpoint { - /// Construct one resolved Guest-control Endpoint identity. - #[allow(clippy::too_many_arguments)] - pub fn new( - endpoint_ref: ResourceRef, - guest_ref: ResourceRef, - zone: ZoneId, - uid: ResourceUid, - resource_generation: ResourceGeneration, - endpoint_generation: ResourceGeneration, - provider_generation: ResourceGeneration, - schema_digest: SchemaFingerprint, - ready: bool, - ) -> Result { - if endpoint_ref.resource_type().as_str() != "Endpoint" - || guest_ref.resource_type().as_str() != "Guest" - || zone.as_str().is_empty() - || resource_generation.get() == 0 - || endpoint_generation.get() == 0 - || provider_generation.get() == 0 - || !ready - { - return Err(GuestLocalError::EndpointMismatch); - } - Ok(Self { - endpoint_ref, - guest_ref, - zone, - uid, - resource_generation, - endpoint_generation, - provider_generation, - schema_digest, - ready, - }) - } - - /// Borrow the exact Endpoint ResourceRef. - pub const fn endpoint_ref(&self) -> &ResourceRef { - &self.endpoint_ref - } - - /// Borrow the producing Guest ResourceRef. - pub const fn guest_ref(&self) -> &ResourceRef { - &self.guest_ref - } - - /// Borrow the exact Endpoint Zone. - pub const fn zone(&self) -> &ZoneId { - &self.zone - } - - /// Borrow the store-assigned Endpoint UID. - pub const fn uid(&self) -> &ResourceUid { - &self.uid - } - - /// Borrow the store-assigned Endpoint UID. - pub const fn endpoint_uid(&self) -> &ResourceUid { - &self.uid - } - - /// Return the Endpoint Resource generation. - pub const fn resource_generation(&self) -> ResourceGeneration { - self.resource_generation - } - /// Return the producer-derived Endpoint generation. - pub const fn endpoint_generation(&self) -> ResourceGeneration { - self.endpoint_generation - } - - /// Return the Provider generation observed with the Endpoint. - pub const fn provider_generation(&self) -> ResourceGeneration { - self.provider_generation - } - - /// Borrow the target-local schema commitment. - pub const fn schema_digest(&self) -> &SchemaFingerprint { - &self.schema_digest - } - - /// Whether the Endpoint is currently ready for an authenticated session. - pub const fn ready(&self) -> bool { - self.ready - } - - /// Validate this resolution against one exact Guest and Provider contract. - pub fn validate_for( - &self, - endpoint_ref: &ResourceRef, - guest_ref: &ResourceRef, - provider_generation: ResourceGeneration, - schema_digest: &SchemaFingerprint, - ) -> Result<(), GuestLocalError> { - if !self.ready - || &self.endpoint_ref != endpoint_ref - || &self.guest_ref != guest_ref - || self.provider_generation != provider_generation - || &self.schema_digest != schema_digest - { - return Err(GuestLocalError::EndpointMismatch); - } - Ok(()) - } -} - -impl fmt::Debug for GuestControlEndpoint { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter - .debug_struct("GuestControlEndpoint") - .field("ready", &self.ready) - .field("has_endpoint_uid", &true) - .field("resource_generation", &self.resource_generation) - .field("endpoint_generation", &self.endpoint_generation) - .field("provider_generation", &self.provider_generation) - .field("has_schema_digest", &true) - .finish() - } -} From 9870dc8520599e0b60fd39b8ef8580240dab238a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:23:25 -0700 Subject: [PATCH 557/726] guest: type GuestDriverArgs.zone as ZoneId The guest driver re-parsed the zone String at construction with an expect; the plane already validates the zone, so carry the typed ZoneId through GuestDriverArgs and GuestDriver::new instead. --- changelog.d/w4-06-guest-driver-zone-typed.md | 6 ++++++ packages/d2b-provider-guest/src/driver.rs | 14 +++++++------- packages/d2b-provider-guest/tests/registration.rs | 4 ++-- packages/d2bd/src/resource_plane_v3.rs | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 changelog.d/w4-06-guest-driver-zone-typed.md diff --git a/changelog.d/w4-06-guest-driver-zone-typed.md b/changelog.d/w4-06-guest-driver-zone-typed.md new file mode 100644 index 000000000..2b91e8d8a --- /dev/null +++ b/changelog.d/w4-06-guest-driver-zone-typed.md @@ -0,0 +1,6 @@ +### Fixed + +- `GuestDriverArgs.zone` is now a typed `ZoneId` instead of a raw `String`: + the guest driver no longer re-parses the zone at construction, so an + invalid zone can no longer panic the driver factory after the plane + already validated it. \ No newline at end of file diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index a41c2f1cc..e8e4b5bb3 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -711,7 +711,7 @@ pub fn guest_descriptor(args: GuestDriverArgs) -> DriverDescriptor { #[derive(Clone)] pub struct GuestDriverArgs { /// The zone the plane serves. - pub zone: String, + pub zone: ZoneId, /// The controller generation every effect call binds (KTD7). pub controller_generation: ControllerGeneration, /// The daemon-supplied facet set the family's effects implementation is @@ -785,12 +785,12 @@ impl GuestDriver { /// survives driver recreation; the construction site holds no /// externally built port (R2)). pub fn new( - zone: String, + zone: ZoneId, controller_generation: ControllerGeneration, effects: Arc, ) -> Self { Self { - zone: ZoneId::parse(zone).expect("driver zone was validated at construction"), + zone, controller_generation, effects, watched: Vec::new(), @@ -1501,7 +1501,7 @@ fn aca_child_ensures( mod tests { use std::sync::Arc; - use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef}; + use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ZoneId}; use d2b_resource_runtime::context::{ ChildEnsure, ManagerEndpoint, RequeueId, RequeueScheduler, ResourceContext, WatchId, WatchRegistration, @@ -1858,7 +1858,7 @@ mod tests { fn driver(effects: Arc) -> GuestDriver { GuestDriver::new( - "work".to_owned(), + ZoneId::parse("work").expect("zone"), ControllerGeneration::new(3).expect("generation"), effects, ) @@ -1914,7 +1914,7 @@ mod tests { #[test] fn factory_registers_the_guest_type() { let factory = GuestDriverFactory::new(GuestDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(1).expect("generation"), facets: crate::test_support::ScriptedFacets::new().facet_set(), }); @@ -2013,7 +2013,7 @@ mod tests { d2b_contracts_resource::v3::identity::ReconnectGeneration::new(2).unwrap(), )); let factory = GuestDriverFactory::new(GuestDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), facets: facets.facet_set(), }); diff --git a/packages/d2b-provider-guest/tests/registration.rs b/packages/d2b-provider-guest/tests/registration.rs index f5e74c165..6ff5f8137 100644 --- a/packages/d2b-provider-guest/tests/registration.rs +++ b/packages/d2b-provider-guest/tests/registration.rs @@ -2,7 +2,7 @@ //! plane registers, and the registry serves this type's decoder and factory //! from it. -use d2b_contracts_resource::v3::ControllerGeneration; +use d2b_contracts_resource::v3::{ControllerGeneration, ZoneId}; use d2b_provider_guest::driver::GUEST_TYPE_NAME; use d2b_provider_guest::{GuestDriverArgs, guest_descriptor}; use d2b_provider_guest::test_support::ScriptedFacets; @@ -12,7 +12,7 @@ use d2b_resource_types::{AllowedSources, ChildCustody, WellKnownType}; fn descriptor() -> d2b_resource_types::DriverDescriptor { guest_descriptor(GuestDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(1).expect("generation"), // The facet set the declaration's factory builds its effects from; // the registration boundary never runs an effect. diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 19fcbe8ee..1784fc85b 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -2907,7 +2907,7 @@ impl ResourcePlaneV3 { // The Guest family: the descriptor builds its effects from the // declared facets; no externally built port appears here (R2). "guest" => vec![guest_descriptor(GuestDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), controller_generation: inputs.authority.controller_generation, facets: inputs.guest_facets.clone(), })], From 068eebb1789fe81ee361f81110dffb387c8685da Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:24:52 -0700 Subject: [PATCH 558/726] contracts-broker: migrate audit_wire imports to crate root The audit-export wire types now live at the d2b_contracts_broker crate root (lib.rs re-export arm) instead of broker_wire. Point the four consumer import sites at the new path; broker_wire-only types stay on their existing imports. --- packages/d2b-broker/src/audit.rs | 6 ++---- packages/d2b/src/dispatch.rs | 2 +- packages/d2b/tests/audit_contract.rs | 2 +- packages/d2bd-runtime/src/wire.rs | 5 ++--- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/d2b-broker/src/audit.rs b/packages/d2b-broker/src/audit.rs index 52c24982c..725cad5e0 100644 --- a/packages/d2b-broker/src/audit.rs +++ b/packages/d2b-broker/src/audit.rs @@ -25,10 +25,8 @@ use crate::{ sys::path_safe, }; use d2b_audit::evidence_chain::ChainRecord; -use d2b_contracts_broker::broker_wire::{ - AuditExportCursor, AuditExportEntry, AuditExportErrorCode, BrokerAuditFilter, - BrokerAuditSeverity, ExportBrokerAuditResponse, -}; +use d2b_contracts_broker::broker_wire::{BrokerAuditFilter, BrokerAuditSeverity, ExportBrokerAuditResponse}; +use d2b_contracts_broker::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}; /// Broker semantic version embedded in every [`OpAuditRecord`]. /// Picked up at compile time from `Cargo.toml`. diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index 25ec0ea70..a56042ca5 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -19,7 +19,7 @@ use crate::{ provider, resource, share, shell, zone, }; use clap::{Args, CommandFactory, Parser, Subcommand}; -use d2b_contracts_broker::broker_wire::AuditExportCursor; +use d2b_contracts_broker::AuditExportCursor; use d2b_contracts_control::{ cli_output::{AuthDeniedSubcommandV2, AuthRoleV2, AuthSocketStatusV2, AuthStatusOutputV2}, public_wire::{self, AuditFormat as IpcAuditFormat, AuditRequest as IpcAuditRequest}, diff --git a/packages/d2b/tests/audit_contract.rs b/packages/d2b/tests/audit_contract.rs index e8b9ec8f5..d3352d786 100644 --- a/packages/d2b/tests/audit_contract.rs +++ b/packages/d2b/tests/audit_contract.rs @@ -480,7 +480,7 @@ fn spawn_single_audit_response_mock(path: &Path, response: Value) -> std::thread #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn spawn_paginated_audit_mock_daemon(path: &Path) -> std::thread::JoinHandle<()> { - use d2b_contracts_broker::broker_wire::AuditExportCursor; + use d2b_contracts_broker::AuditExportCursor; use nix::sys::socket::{ AddressFamily, Backlog, SockFlag, SockType, UnixAddr, accept, bind, listen, socket, }; diff --git a/packages/d2bd-runtime/src/wire.rs b/packages/d2bd-runtime/src/wire.rs index eb3f4e42a..af9850fcc 100644 --- a/packages/d2bd-runtime/src/wire.rs +++ b/packages/d2bd-runtime/src/wire.rs @@ -586,9 +586,8 @@ fn map_parse_error(error: serde_json::Error) -> TypedError { #[cfg(test)] mod tests { use super::{Request, audit_response, parse_request}; - use d2b_contracts_broker::broker_wire::{ - AuditExportCursor, AuditExportEntry, ExportBrokerAuditResponse, - }; + use d2b_contracts_broker::broker_wire::ExportBrokerAuditResponse; + use d2b_contracts_broker::{AuditExportCursor, AuditExportEntry}; use serde_json::json; #[test] From 64408bc950e61f0b6677cebc5819f97885dff91b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:26:35 -0700 Subject: [PATCH 559/726] clipd: add stable as_str wire labels for audit events to_wire derived the event and size labels from Debug formatting; spell them out as explicit as_str() constants so the wire record is a stable, documented contract. --- changelog.d/w4-11-audit-stable-labels.md | 3 ++ .../src/audit.rs | 45 +++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 changelog.d/w4-11-audit-stable-labels.md diff --git a/changelog.d/w4-11-audit-stable-labels.md b/changelog.d/w4-11-audit-stable-labels.md new file mode 100644 index 000000000..c53198522 --- /dev/null +++ b/changelog.d/w4-11-audit-stable-labels.md @@ -0,0 +1,3 @@ +### Fixed + +- Clipboard audit wire labels (`event`, `size`) are now explicit stable `as_str()` values instead of being derived from `Debug` formatting, so the wire record no longer changes if a variant's `Debug` output changes. \ No newline at end of file diff --git a/packages/d2b-provider-clipboard-wayland/src/audit.rs b/packages/d2b-provider-clipboard-wayland/src/audit.rs index 9115e8558..ea9d62699 100644 --- a/packages/d2b-provider-clipboard-wayland/src/audit.rs +++ b/packages/d2b-provider-clipboard-wayland/src/audit.rs @@ -28,6 +28,28 @@ pub enum ClipboardEventType { PickerSessionFailed, } +impl ClipboardEventType { + /// Return the stable wire label. + /// + /// These labels are part of the audit wire record emitted by + /// [`ClipboardAuditEvent::to_wire`] and must not change; they are spelled + /// out explicitly here rather than derived from `Debug`. + pub const fn as_str(self) -> &'static str { + match self { + Self::HostCapture => "hostcapture", + Self::GuestCapture => "guestcapture", + Self::PasteAuthorized => "pasteauthorized", + Self::PasteRejected => "pasterejected", + Self::EchoSuppressed => "echosuppressed", + Self::EntryExpired => "entryexpired", + Self::EntryPurged => "entrypurged", + Self::PickerSessionStarted => "pickersessionstarted", + Self::PickerSessionCompleted => "pickersessioncompleted", + Self::PickerSessionFailed => "pickersessionfailed", + } + } +} + /// Closed clipboard reason code. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ClipboardReason { @@ -124,6 +146,20 @@ impl SizeBucket { _ => Self::GtM1, } } + + /// Return the stable wire label. + /// + /// These labels are part of the audit wire record emitted by + /// [`ClipboardAuditEvent::to_wire`] and must not change; they are spelled + /// out explicitly here rather than derived from `Debug`. + pub const fn as_str(self) -> &'static str { + match self { + Self::Lt1K => "Lt1K", + Self::K1To64K => "K1To64K", + Self::K64ToM1 => "K64ToM1", + Self::GtM1 => "GtM1", + } + } } /// Content-free clipboard audit event. @@ -169,14 +205,17 @@ impl ClipboardAuditEvent { } /// Render the bounded wire record. + /// + /// All labels (`event`, `reason`, `size`) come from explicit stable + /// `as_str` methods, not from `Debug` formatting. pub fn to_wire(&self) -> String { format!( - "event={} source={} dest={} reason={} size={:?}", - format!("{:?}", self.event_type).to_ascii_lowercase(), + "event={} source={} dest={} reason={} size={}", + self.event_type.as_str(), self.source_zone_digest, self.dest_zone_digest, self.reason.as_str(), - self.size_bucket + self.size_bucket.as_str() ) } } From a4de304848e17ea13fbe35ec6f0564298e26390d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:26:56 -0700 Subject: [PATCH 560/726] contracts: restrict process child kind, expose schema version parts, document errors BindingChildRequest::process and process_for_user now take the restricted ProcessChildKind, so an Endpoint carrying process fields is no longer constructible and the two runtime InvalidProducer checks are deleted. SchemaVersion gains const major()/minor() accessors and admits_state reads them directly, deleting the schema_version_parts re-parse. Result-returning public items in the contracts-provider and contracts-resource families gain # Errors sections naming their closed variants. --- ...-02-contracts-child-kind-schema-version.md | 4 + .../src/v3/credential_controller.rs | 109 ++++++++++++++++++ .../d2b-contracts-provider/src/v3/provider.rs | 26 +---- .../v3/semantic_services/child_resources.rs | 68 ++++++++--- .../src/v3/semantic_services/mod.rs | 49 ++++++++ .../src/v3/telemetry_frame.rs | 33 ++++++ .../src/v3/telemetry_policy.rs | 51 ++++++++ .../src/v3/resource_schema.rs | 107 +++++++++++++++++ .../src/controller.rs | 6 +- .../src/controller.rs | 6 +- .../src/lifecycle.rs | 4 +- .../src/controller.rs | 8 +- 12 files changed, 420 insertions(+), 51 deletions(-) create mode 100644 changelog.d/w4-02-contracts-child-kind-schema-version.md diff --git a/changelog.d/w4-02-contracts-child-kind-schema-version.md b/changelog.d/w4-02-contracts-child-kind-schema-version.md new file mode 100644 index 000000000..1765e229d --- /dev/null +++ b/changelog.d/w4-02-contracts-child-kind-schema-version.md @@ -0,0 +1,4 @@ +### Fixed + +- `BindingChildRequest::process` and `process_for_user` now take the restricted `ProcessChildKind`, so an Endpoint can no longer be passed to a process constructor and rejected at runtime. +- `SchemaVersion` now exposes `major()` and `minor()` component accessors, and state-schema admission reads them directly instead of re-parsing the canonical version string. \ No newline at end of file diff --git a/packages/d2b-contracts-provider/src/v3/credential_controller.rs b/packages/d2b-contracts-provider/src/v3/credential_controller.rs index 38094c874..8f4cc0337 100644 --- a/packages/d2b-contracts-provider/src/v3/credential_controller.rs +++ b/packages/d2b-contracts-provider/src/v3/credential_controller.rs @@ -56,6 +56,11 @@ const FORBIDDEN_AMBIENT_CREDENTIAL_KEYS: &[&str] = &[ /// /// Values are intentionally never inspected. Provider processes must acquire /// credentials only through their injected client and authenticated session. +/// +/// # Errors +/// +/// Returns [`CredentialControllerError::OperationDenied`] when any key is one +/// of the forbidden ambient credential-chain names. pub fn reject_ambient_credential_chain( keys: impl IntoIterator>, ) -> Result<(), CredentialControllerError> { @@ -101,6 +106,11 @@ pub struct CredentialIdempotencyKey([u8; 32]); impl CredentialIdempotencyKey { /// Derive a stable key from Credential UID, rotation generation, and the /// method-derived operation class. No resource name or secret is accepted. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::InvalidInput`] when the rotation + /// generation is zero. pub fn derive( credential_uid: &ResourceUid, rotation_generation: u64, @@ -152,6 +162,14 @@ pub struct CredentialControllerCall { impl CredentialControllerCall { /// Build a call only when both policy and the exact `use-credential` /// Role subresource admit the method. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::DeadlineExceeded`] when the + /// deadline is zero or already elapsed, [`CredentialControllerError::OperationDenied`] + /// when the Role subresource or the allowed operation set does not admit + /// the method, and [`CredentialControllerError::InvalidInput`] when the + /// call generation is zero. pub fn authorize( credential_uid: &ResourceUid, rotation_generation: u64, @@ -295,6 +313,11 @@ pub struct CredentialRetryState { impl CredentialRetryState { /// Construct a non-empty bounded retry position. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::InvalidInput`] when `attempt` or + /// `max_attempts` is zero or `attempt` exceeds `max_attempts`. pub fn new(attempt: u16, max_attempts: u16) -> Result { if attempt == 0 || max_attempts == 0 || attempt > max_attempts { return Err(CredentialControllerError::InvalidInput); @@ -331,6 +354,12 @@ pub struct CredentialReconcileInput { impl CredentialReconcileInput { /// Construct one validated reconcile snapshot. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::InvalidInput`] when the rotation + /// generation is zero, `active_leases` exceeds the local ceiling, the + /// provider lease limit is out of range, or an operation repeats. #[allow(clippy::too_many_arguments)] pub fn new( credential_uid: ResourceUid, @@ -400,6 +429,11 @@ pub struct CredentialObserveInput { impl CredentialObserveInput { /// Construct one observe snapshot. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::InvalidInput`] when the rotation + /// generation is zero. #[allow(clippy::too_many_arguments)] pub fn new( credential_uid: ResourceUid, @@ -454,6 +488,11 @@ pub struct CredentialRevocationInput { impl CredentialRevocationInput { /// Construct one revocation snapshot. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::InvalidInput`] when the rotation + /// generation is zero. #[allow(clippy::too_many_arguments)] pub fn new( credential_uid: ResourceUid, @@ -520,6 +559,11 @@ pub enum CredentialControllerHealthState { impl CredentialControllerHealth { /// Derive health while enforcing the global active-lease ceiling. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::InvalidInput`] when `active_leases` + /// exceeds the global ceiling. pub fn derive( provider_process_reachable: bool, active_leases: u32, @@ -582,6 +626,14 @@ pub trait CredentialControllerHandlers { } /// Apply the shared Credential reconcile state machine. +/// +/// # Errors +/// +/// Returns [`CredentialControllerError::InvalidInput`] when the next rotation +/// generation overflows, and propagates the [`CredentialControllerCall::authorize`] +/// failures ([`CredentialControllerError::DeadlineExceeded`], +/// [`CredentialControllerError::OperationDenied`], or +/// [`CredentialControllerError::InvalidInput`]) for the planned call. pub fn reconcile_credential( input: &CredentialReconcileInput, ) -> Result { @@ -688,6 +740,14 @@ pub fn reconcile_credential( } /// Apply the fixed scheduled-observe policy. +/// +/// # Errors +/// +/// Propagates the [`CredentialControllerCall::authorize`] failures +/// ([`CredentialControllerError::DeadlineExceeded`], +/// [`CredentialControllerError::OperationDenied`], or +/// [`CredentialControllerError::InvalidInput`]) when an observe call is +/// planned. pub fn observe_credential( input: &CredentialObserveInput, ) -> Result { @@ -729,6 +789,14 @@ pub fn observe_credential( } /// Apply one owner-delete or Provider-generation revocation policy. +/// +/// # Errors +/// +/// Propagates the [`CredentialControllerCall::authorize`] failures +/// ([`CredentialControllerError::DeadlineExceeded`], +/// [`CredentialControllerError::OperationDenied`], or +/// [`CredentialControllerError::InvalidInput`]) when a revocation call is +/// planned. pub fn revoke_credential( input: &CredentialRevocationInput, ) -> Result { @@ -815,6 +883,11 @@ impl CredentialSingleFlight { } /// Enter one Credential handler or reject a concurrent duplicate. + /// + /// # Errors + /// + /// Returns [`CredentialControllerError::AlreadyRunning`] when the same + /// Credential UID is already being handled. pub fn try_enter( &self, credential_uid: ResourceUid, @@ -1019,6 +1092,11 @@ pub struct CredentialAuditDigest(String); impl CredentialAuditDigest { /// Parse exactly `sha256:` followed by 64 lowercase hexadecimal digits. + /// + /// # Errors + /// + /// Returns [`CredentialObservabilityError::InvalidAuditRecord`] when the + /// value is not exactly `sha256:` followed by 64 lowercase hex digits. pub fn parse(value: impl Into) -> Result { let value = value.into(); if valid_sha256(&value) { @@ -1073,6 +1151,13 @@ pub struct CredentialAuditRecord { impl CredentialAuditRecord { /// Emit one caller-initiated service record only after authorization. /// Denial returns no identity-bearing record and does not inspect identity. + /// + /// # Errors + /// + /// Returns [`CredentialObservabilityError::InvalidAuditRecord`] when a + /// digest is malformed or the rotation generation is zero, and + /// [`CredentialObservabilityError::ForbiddenTelemetryField`] when the zone + /// is not a valid telemetry zone. #[allow(clippy::too_many_arguments)] pub fn authorized_service( authorized: bool, @@ -1115,6 +1200,13 @@ impl CredentialAuditRecord { } /// Emit one controller-owned event with no caller subject field. + /// + /// # Errors + /// + /// Returns [`CredentialObservabilityError::InvalidAuditRecord`] when the + /// rotation generation or a prior rotation generation is zero, and + /// [`CredentialObservabilityError::ForbiddenTelemetryField`] when the zone + /// is not a valid telemetry zone. #[allow(clippy::too_many_arguments)] pub fn controller_event( provider: CredentialProviderKind, @@ -1345,6 +1437,11 @@ pub struct CredentialLeaseAggregate { impl CredentialLeaseAggregate { /// Aggregate active lease expiries without accepting any Credential identity. + /// + /// # Errors + /// + /// Returns [`CredentialObservabilityError::ForbiddenTelemetryField`] when + /// the active count overflows or exceeds the local ceiling. pub fn from_active_expiries( provider: CredentialProviderKind, placement: PlacementBinding, @@ -1394,6 +1491,12 @@ pub struct CredentialTelemetryFrame { impl CredentialTelemetryFrame { /// Build one frame entirely from trusted closed values. + /// + /// # Errors + /// + /// Returns [`CredentialObservabilityError::ForbiddenTelemetryField`] when + /// the rotation generation is zero, the zone is not a valid telemetry + /// zone, or any field fails collector validation. pub fn new( provider: CredentialProviderKind, zone: impl Into, @@ -1474,6 +1577,12 @@ impl CredentialTelemetryFrame { /// Reject a complete frame when any key or value is outside its closed /// semantic domain. The whole frame is rejected, not field-filtered. + /// + /// # Errors + /// + /// Returns [`CredentialObservabilityError::ForbiddenTelemetryField`] when + /// any key is forbidden, any value carries a sensitive shape, or a value is + /// outside its closed domain. pub fn validate_collector_fields( fields: impl IntoIterator, ) -> Result<(), CredentialObservabilityError> { diff --git a/packages/d2b-contracts-provider/src/v3/provider.rs b/packages/d2b-contracts-provider/src/v3/provider.rs index 4265bed95..1c581b40b 100644 --- a/packages/d2b-contracts-provider/src/v3/provider.rs +++ b/packages/d2b-contracts-provider/src/v3/provider.rs @@ -559,35 +559,15 @@ impl CompatibilityRange { /// state schema major must be exact and the installed minor must not be /// newer than this artifact's. pub fn admits_state(&self, installed: SchemaVersion) -> Result<(), ProviderContractError> { - let (installed_major, installed_minor) = schema_version_parts(installed); - let (artifact_major, artifact_minor) = schema_version_parts(self.state_schema_version); - if installed_major != artifact_major || installed_minor > artifact_minor { + if installed.major() != self.state_schema_version.major() + || installed.minor() > self.state_schema_version.minor() + { return Err(ProviderContractError::StateSchemaIncompatible); } Ok(()) } } -/// Split a canonical `MAJOR.MINOR` schema version into its two components. -/// -/// `SchemaVersion` exposes no component accessor, and its canonical string -/// is the contract's own round-trip spelling, so parsing that spelling back -/// is exact rather than lossy. -fn schema_version_parts(version: SchemaVersion) -> (u32, u32) { - let rendered = version.to_canonical_string(); - let (major, minor) = rendered - .split_once('.') - .expect("a canonical schema version always carries one separator"); - ( - major - .parse() - .expect("a canonical schema version major is numeric"), - minor - .parse() - .expect("a canonical schema version minor is numeric"), - ) -} - /// The closed Provider component type set. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs index 490eafb14..31c45dee3 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs @@ -44,6 +44,29 @@ impl BindingChildKind { } } +/// The process resource kinds a semantic Binding may own. +/// +/// This is the restricted kind set admitted by the process constructors: +/// an Endpoint carries no execution contract and is built through +/// [`BindingChildRequest::endpoint`] instead. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ProcessChildKind { + /// A long-lived provider component. + Process, + /// A one-shot provider worker. + EphemeralProcess, +} + +impl ProcessChildKind { + /// Convert to the full child-kind vocabulary. + pub const fn as_binding_kind(self) -> BindingChildKind { + match self { + Self::Process => BindingChildKind::Process, + Self::EphemeralProcess => BindingChildKind::EphemeralProcess, + } + } +} + /// The target on which a child resource is reconciled. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BindingChildPlacement { @@ -90,7 +113,7 @@ impl BindingChildRequest { /// Construct a Process or EphemeralProcess request with its signed /// execution contract. pub const fn process( - kind: BindingChildKind, + kind: ProcessChildKind, placement: BindingChildPlacement, role: &'static str, provider: &'static str, @@ -99,7 +122,7 @@ impl BindingChildRequest { class: &'static str, ) -> Self { Self { - kind, + kind: kind.as_binding_kind(), placement, role, producer_role: None, @@ -114,7 +137,7 @@ impl BindingChildRequest { /// Construct a user-domain Process request whose identity is supplied by /// the authored Binding target. pub const fn process_for_user( - kind: BindingChildKind, + kind: ProcessChildKind, placement: BindingChildPlacement, role: &'static str, provider: &'static str, @@ -122,7 +145,7 @@ impl BindingChildRequest { class: &'static str, ) -> Self { Self { - kind, + kind: kind.as_binding_kind(), placement, role, producer_role: None, @@ -431,6 +454,25 @@ impl std::error::Error for BindingChildError {} /// This is the only constructor for a [`BindingChildSet`]. In particular, /// callers must provide the Binding and Service references; a Ready Service /// alone cannot create consumer children. +/// +/// # Errors +/// +/// Returns [`BindingChildError::InvalidBindingRef`] or +/// [`BindingChildError::InvalidServiceRef`] when a supplied reference does not +/// name the family's Binding or Service ResourceType, +/// [`BindingChildError::InvalidProviderRef`] when a Provider reference does not +/// name a Provider, [`BindingChildError::InvalidTargetRef`] when the target is +/// not a Guest, User, or Zone or is not admitted by the family contract, +/// [`BindingChildError::EmptyDeclaration`] when no children are declared, +/// [`BindingChildError::InvalidRole`] when a role is malformed, duplicated, or +/// a process template or class is invalid, [`BindingChildError::InvalidPlacement`] +/// when a Guest child is declared for a non-Guest target or a producer +/// placement differs from its Endpoint, [`BindingChildError::InvalidProducer`] +/// when an Endpoint names a non-Process producer, +/// [`BindingChildError::MissingProducer`] when an Endpoint names no declared +/// child, [`BindingChildError::MissingUser`] when a user-domain Process is +/// declared without a User reference, and [`BindingChildError::InvalidChildRef`] +/// when a derived child reference cannot be parsed. pub fn explicit_binding_children( family: SemanticFamily, binding_ref: ResourceRef, @@ -452,6 +494,12 @@ pub fn explicit_binding_children( /// Construct child intents while supplying the Binding's admitted User /// identity for user-domain Processes. +/// +/// # Errors +/// +/// Returns every error of [`explicit_binding_children`], plus +/// [`BindingChildError::InvalidUserRef`] when `user_ref` does not name a User +/// resource. pub fn explicit_binding_children_with_user( family: SemanticFamily, binding_ref: ResourceRef, @@ -496,18 +544,6 @@ pub fn explicit_binding_children_with_user( if !valid_role(declaration.role) || roles.contains(&declaration.role) { return Err(BindingChildError::InvalidRole); } - if declaration.producer_role.is_some() && declaration.kind != BindingChildKind::Endpoint { - return Err(BindingChildError::InvalidProducer); - } - if declaration.kind == BindingChildKind::Endpoint - && (declaration.process_provider.is_some() - || declaration.process_template.is_some() - || declaration.process_domain.is_some() - || declaration.process_class.is_some() - || declaration.process_user) - { - return Err(BindingChildError::InvalidProducer); - } if declaration.kind != BindingChildKind::Endpoint { if let Some(provider) = declaration.process_provider { let provider_ref = ResourceRef::parse(provider) diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs index d0e9eee44..3a888c7e9 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs @@ -90,6 +90,13 @@ pub struct SemanticProjectionProtocolVersion(String); impl SemanticProjectionProtocolVersion { /// Parse a bounded projection-protocol version. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::SchemaViolation`] when the value is + /// not exactly `.` with one to three digits per component + /// and no leading zeroes in multi-digit components, or exceeds the + /// protocol-version byte bound. pub fn parse(value: impl Into) -> Result { let value = value.into(); if value.len() > MAX_SEMANTIC_PROJECTION_PROTOCOL_VERSION_BYTES { @@ -466,6 +473,11 @@ impl SemanticLayerSchema { } /// Admit a set of top-level field names against this frozen layer. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::SchemaViolation`] when a name is not in + /// the allowed set or a required name is missing. pub fn validate_names<'a>( &self, names: impl IntoIterator, @@ -581,6 +593,11 @@ impl SemanticTypeContract { /// `provider_extensions` carries the registrations of whichever Provider /// implementations are installed. Passing none yields the discoverable /// common base with no Provider package selected. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::SchemaViolation`] when a provider + /// extension registration is invalid. pub fn schema_contract( &self, provider_extensions: impl IntoIterator, @@ -611,6 +628,15 @@ impl SemanticTypeContract { /// frozen field set; the caller supplies the values, because the /// specification does not fix an interior for every required field. See /// each family module for which interiors it leaves open. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::MinimalBaseReservedField`] when + /// `base_values` carries a field the envelope owns, + /// [`SemanticContractError::MinimalBaseFieldSetMismatch`] when the supplied + /// names differ from the required base field set, and + /// [`SemanticContractError::SchemaViolation`] when the assembled spec is + /// invalid. pub fn minimal_base_spec( &self, provider_ref: ResourceRef, @@ -857,6 +883,11 @@ impl SemanticProjectionBinding { } /// Derive the provider-neutral half of a signed projection factory. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::ProjectionFactoryInvalid`] when the + /// factory cannot be constructed from the derived semantic binding. pub fn projection_factory(&self) -> Result { Ok(ProjectionFactory::new( self.service_type.clone(), @@ -874,6 +905,13 @@ impl SemanticProjectionBinding { /// A projection permits only `providerRef`, the semantic base and import /// fields, and ResourceImport ownership. A `spec.provider` extension is /// rejected: Core never synthesizes one and never copies a remote one. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::ProjectionProviderExtensionForbidden`] + /// when the spec carries a `spec.provider` extension and + /// [`SemanticContractError::SchemaViolation`] when a field name is outside + /// the projection's allowed set or a required name is missing. pub fn validate_projection_spec( &self, spec: &ResourceSpec, @@ -1056,6 +1094,12 @@ impl SemanticPairContract { /// in the Binding's Zone before calling. This admits only the type half: /// `serviceRef` must name this pair's Service ResourceType, and the target /// must be in this pair's closed allowed target set. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::WrongResourceType`] when `service_ref` + /// does not name this pair's Service ResourceType or the target is outside + /// the closed allowed target set. pub fn admit_binding_refs( &self, service_ref: &ResourceRef, @@ -1080,6 +1124,11 @@ impl SemanticPairContract { /// a `*Binding`. This type-only helper does not establish resource origin; /// final export admission must use the stored envelope through /// [`ProjectionFactory::admits_export_target`]. + /// + /// # Errors + /// + /// Returns [`SemanticContractError::WrongResourceType`] when the reference + /// does not name the owner Service ResourceType. pub fn admit_export_target( &self, resource_ref: &ResourceRef, diff --git a/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs b/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs index 331324ce4..bbf4bca7a 100644 --- a/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs +++ b/packages/d2b-contracts-provider/src/v3/telemetry_frame.rs @@ -69,6 +69,13 @@ impl core::fmt::Display for TelemetryFrameError { impl std::error::Error for TelemetryFrameError {} /// Parse one raw frame into the shared typed representation. +/// +/// # Errors +/// +/// Returns [`TelemetryFrameError::RawOversize`] when `bytes` exceed +/// [`MAX_TELEMETRY_FRAME_BYTES`], [`TelemetryFrameError::UnknownField`] when a +/// top-level field is not part of the frame schema, and +/// [`TelemetryFrameError::Malformed`] for any other parse failure. pub fn parse_raw_frame(bytes: &[u8]) -> Result { if bytes.len() > MAX_TELEMETRY_FRAME_BYTES { return Err(TelemetryFrameError::RawOversize); @@ -85,11 +92,27 @@ pub fn parse_raw_frame(bytes: &[u8]) -> Result Result<(), TelemetryFrameError> { validate_value_shape(frame.signal, &frame.value) } /// Parse and validate one raw frame. +/// +/// # Errors +/// +/// Returns every error of [`parse_raw_frame`] and [`validate_frame`]. pub fn validate_raw_frame(bytes: &[u8]) -> Result { let frame = parse_raw_frame(bytes)?; validate_frame(&frame)?; @@ -97,6 +120,12 @@ pub fn validate_raw_frame(bytes: &[u8]) -> Result Result, TelemetryFrameError> { redact_value( &mut frame.value, @@ -111,6 +140,10 @@ pub fn redact_parsed_frame(mut frame: TelemetryFrame) -> Result, Telemet } /// Parse, validate, redact, and remeasure one complete frame. +/// +/// # Errors +/// +/// Returns every error of [`validate_raw_frame`] and [`redact_parsed_frame`]. pub fn redact_frame(bytes: &[u8]) -> Result, TelemetryFrameError> { let frame = validate_raw_frame(bytes)?; redact_parsed_frame(frame) diff --git a/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs b/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs index 58eaef95d..39382a410 100644 --- a/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs +++ b/packages/d2b-contracts-provider/src/v3/telemetry_policy.rs @@ -475,6 +475,17 @@ impl core::fmt::Display for MetricPolicyError { impl std::error::Error for MetricPolicyError {} /// Validate one metric descriptor against the closed registry. +/// +/// # Errors +/// +/// Returns [`MetricPolicyError::DescriptorMalformed`] when the name is empty, +/// oversized, or not lower-kebab, when more than 16 labels are declared, when +/// a label key is empty, oversized, or duplicated, or when the label set does +/// not match the canonical descriptor; [`MetricPolicyError::DescriptorNotAllowlisted`] +/// when the name is not in the canonical family registry; +/// [`MetricPolicyError::KeyNotAllowlisted`] when a label key is not in the +/// policy; and [`MetricPolicyError::ValueNotAllowlisted`] when a label value +/// is outside its closed domain. pub fn validate_descriptor(descriptor: &MetricDescriptor) -> Result<(), MetricPolicyError> { if descriptor.name.is_empty() || descriptor.name.len() > 128 @@ -536,6 +547,13 @@ pub fn canonical_descriptor(name: &str) -> Option { } /// Validate a label key before any value is considered. +/// +/// # Errors +/// +/// Returns [`MetricPolicyError::KeyForbidden`] when the key is unconditionally +/// forbidden, [`MetricPolicyError::KeySuffixForbidden`] when it carries a +/// forbidden identity suffix, and [`MetricPolicyError::KeyNotAllowlisted`] +/// when it is not in the policy. pub fn validate_label_key(key: &str) -> Result<(), MetricPolicyError> { if FORBIDDEN_LABEL_KEYS.contains(&key) { return Err(MetricPolicyError::KeyForbidden); @@ -553,6 +571,14 @@ pub fn validate_label_key(key: &str) -> Result<(), MetricPolicyError> { } /// Validate one data point against its descriptor and identity canaries. +/// +/// # Errors +/// +/// Returns every error of [`validate_descriptor`], plus +/// [`MetricPolicyError::LabelSetMismatch`] when the label keys differ from the +/// descriptor, [`MetricPolicyError::ValueNotAllowlisted`] when a value is +/// outside its closed domain, and [`MetricPolicyError::ValueIdentity`] when a +/// value is a resource identity canary. pub fn validate_data_point( descriptor: &MetricDescriptor, labels: &BTreeMap, @@ -564,6 +590,13 @@ pub fn validate_data_point( /// Validate a data point when the descriptor was resolved from the canonical /// registry by the caller. +/// +/// # Errors +/// +/// Returns every error of [`validate_labels`] (a malformed label set, a +/// forbidden or non-allowlisted key, a non-allowlisted value, or an identity +/// canary), plus [`MetricPolicyError::LabelSetMismatch`] when the label keys +/// differ from the descriptor. pub fn validate_canonical_data_point( descriptor: &MetricDescriptor, labels: &BTreeMap, @@ -575,6 +608,14 @@ pub fn validate_canonical_data_point( /// Validate a data point without validating actual label keys before comparing /// them with the descriptor. +/// +/// # Errors +/// +/// Returns every error of [`validate_descriptor`], plus +/// [`MetricPolicyError::LabelSetMismatch`] when the label keys differ from the +/// descriptor, [`MetricPolicyError::ValueNotAllowlisted`] when a value is +/// outside its closed domain, and [`MetricPolicyError::ValueIdentity`] when a +/// value is a resource identity canary. pub fn validate_data_point_without_label_key_validation( descriptor: &MetricDescriptor, labels: &BTreeMap, @@ -585,6 +626,16 @@ pub fn validate_data_point_without_label_key_validation( } /// Validate labels when a frame does not carry a full descriptor. +/// +/// # Errors +/// +/// Returns [`MetricPolicyError::DescriptorMalformed`] when more than 16 labels +/// are supplied, [`MetricPolicyError::KeyForbidden`] or +/// [`MetricPolicyError::KeySuffixForbidden`] for a forbidden key, +/// [`MetricPolicyError::KeyNotAllowlisted`] when a key is not in the policy, +/// [`MetricPolicyError::ValueNotAllowlisted`] when a value is outside its +/// closed domain, and [`MetricPolicyError::ValueIdentity`] when a value is a +/// resource identity canary. pub fn validate_labels( labels: &BTreeMap, canaries: &IdentityCanaries, diff --git a/packages/d2b-contracts-resource/src/v3/resource_schema.rs b/packages/d2b-contracts-resource/src/v3/resource_schema.rs index c1d601577..368c59ad1 100644 --- a/packages/d2b-contracts-resource/src/v3/resource_schema.rs +++ b/packages/d2b-contracts-resource/src/v3/resource_schema.rs @@ -176,6 +176,16 @@ pub enum CanonicalJsonValue { impl CanonicalJsonValue { /// Parse JSON while rejecting duplicate keys before constructing a value. + /// + /// # Errors + /// + /// Returns [`CanonicalJsonError::Syntax`] or + /// [`CanonicalJsonError::DuplicateKey`] for malformed input, + /// [`CanonicalJsonError::InvalidKey`] when a key is not printable ASCII or + /// too long, [`CanonicalJsonError::InvalidString`] when a string is not + /// NFC or carries a forbidden character, and + /// [`CanonicalJsonError::IntegerOutOfRange`] when a number is not a signed + /// 64-bit integer. pub fn parse(bytes: &[u8]) -> Result { validate_number_tokens(bytes)?; let mut deserializer = serde_json::Deserializer::from_slice(bytes); @@ -346,6 +356,12 @@ pub struct CanonicalJsonObject(BTreeMap); impl CanonicalJsonObject { /// Parse a canonical JSON object. + /// + /// # Errors + /// + /// Returns every error of [`CanonicalJsonValue::parse`], plus + /// [`CanonicalJsonError::RootNotObject`] when the root value is not an + /// object. pub fn parse(bytes: &[u8]) -> Result { let value = CanonicalJsonValue::parse(bytes)?; match value { @@ -516,6 +532,13 @@ pub(crate) fn validate_canonical_string(value: &str) -> Result<(), CanonicalJson } /// Canonicalize a serializable contract value. +/// +/// # Errors +/// +/// Returns [`CanonicalJsonError::Syntax`], [`CanonicalJsonError::DuplicateKey`], +/// [`CanonicalJsonError::InvalidKey`], [`CanonicalJsonError::InvalidString`], +/// or [`CanonicalJsonError::IntegerOutOfRange`] when the serialized value is +/// not canonical JSON. pub fn canonical_json_bytes(value: &T) -> Result, CanonicalJsonError> { let json = serde_json::to_vec(value).map_err(canonical_json_error)?; Ok(CanonicalJsonValue::parse(&json)?.to_canonical_bytes()) @@ -601,6 +624,11 @@ pub struct SchemaVersion { impl SchemaVersion { /// Construct a schema version. Major zero is not admitted. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::InvalidSchemaVersion`] when `major` is + /// zero. pub fn new(major: u32, minor: u32) -> Result { if major == 0 { return Err(ResourceSchemaError::InvalidSchemaVersion); @@ -608,7 +636,23 @@ impl SchemaVersion { Ok(Self { major, minor }) } + /// Return the major schema version component. + pub const fn major(self) -> u32 { + self.major + } + + /// Return the minor schema version component. + pub const fn minor(self) -> u32 { + self.minor + } + /// Parse exactly `MAJOR.MINOR` without leading zeroes. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::InvalidSchemaVersion`] when the value is + /// not exactly `MAJOR.MINOR` with numeric components and no leading zeroes, + /// or when the major component is zero. pub fn parse(value: &str) -> Result { let (major, minor) = value .split_once('.') @@ -718,6 +762,11 @@ impl PlacementAnchor { /// Reject an anchor that disagrees with a registered ResourceType base /// contract. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::PlacementAnchorMismatch`] when the + /// ResourceType's canonical anchor differs from this one. pub fn validate_for(self, resource_type: &ResourceTypeName) -> Result<(), ResourceSchemaError> { if Self::canonical_for(resource_type).is_some_and(|expected| expected != self) { return Err(ResourceSchemaError::PlacementAnchorMismatch); @@ -726,6 +775,15 @@ impl PlacementAnchor { } /// Resolve this anchor against one committed resource envelope. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::PlacementTargetMissing`] when an + /// `ExecutionRef` anchor finds no `spec.executionRef` field, + /// [`ResourceSchemaError::PlacementTargetInvalid`] when that field is not a + /// string or not a parseable reference, and + /// [`ResourceSchemaError::PlacementTargetWrongType`] when it names neither + /// a Host nor a Guest. pub fn resolve( self, envelope: &ResourceEnvelope, @@ -853,6 +911,12 @@ impl ExtensionSchemaId { } /// Parse `.d2bus.org//{spec|status}`. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::InvalidSchemaId`] when the value is not + /// exactly `.d2bus.org//{spec|status}` with valid + /// provider and ResourceType names. pub fn parse(value: &str) -> Result { let (authority, remainder) = value .split_once('/') @@ -973,6 +1037,12 @@ pub struct ObjectFieldSchema { impl ObjectFieldSchema { /// Construct a closed object schema. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::InvalidFieldName`] when a key is not a + /// canonical field name and [`ResourceSchemaError::RequiredFieldNotAllowed`] + /// when a required key is not in the allowed set. pub fn new( allowed: impl IntoIterator, required: impl IntoIterator, @@ -1080,6 +1150,17 @@ impl core::fmt::Debug for ResourceSchemaContract { impl ResourceSchemaContract { /// Construct a ResourceType schema contract. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::ProviderRefWrongType`] when a provider + /// reference does not name a Provider, + /// [`ResourceSchemaError::ProviderSchemaBinding`] when an extension schema + /// ID does not bind this ResourceType and layer, + /// [`ResourceSchemaError::ProviderFieldShadowsBase`] when an extension + /// field shadows a base field or a reserved name, and + /// [`ResourceSchemaError::DuplicateProviderRegistration`] when the same + /// Provider is registered twice. pub fn new( resource_type: ResourceTypeName, base_binding: BaseSchemaBinding, @@ -1117,6 +1198,11 @@ impl ResourceSchemaContract { } /// Verify a Provider's advertised base schema versions and fingerprints. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::BaseSchemaMismatch`] when the advertised + /// binding differs from the contract's. pub fn verify_base_binding( &self, binding: &BaseSchemaBinding, @@ -1128,6 +1214,20 @@ impl ResourceSchemaContract { } /// Validate a complete resource against all three spec and status layers. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::ResourceTypeMismatch`] when the envelope + /// names a different ResourceType, [`ResourceSchemaError::UnknownField`] or + /// [`ResourceSchemaError::MissingField`] for a layer field-set violation, + /// [`ResourceSchemaError::ProviderRefRequired`] when a provider extension + /// carries no `providerRef`, [`ResourceSchemaError::ProviderNotRegistered`] + /// when the referenced Provider is not registered, and the provider + /// extension errors ([`ResourceSchemaError::ProviderRefMismatch`], + /// [`ResourceSchemaError::ProviderSchemaBinding`], + /// [`ResourceSchemaError::ProviderSchemaMismatch`], or + /// [`ResourceSchemaError::ProviderFieldShadowsBase`]) when an extension + /// disagrees with its registration. pub fn validate_envelope( &self, envelope: &ResourceEnvelope, @@ -1173,6 +1273,13 @@ impl ResourceSchemaContract { } /// Validate the canonical minimal base spec without a Provider extension. + /// + /// # Errors + /// + /// Returns [`ResourceSchemaError::ProviderExtensionNotMinimal`] when the + /// spec carries a `spec.provider` extension, and + /// [`ResourceSchemaError::UnknownField`] or + /// [`ResourceSchemaError::MissingField`] for a base field-set violation. pub fn validate_minimal_base_spec( &self, spec: &super::ResourceSpec, diff --git a/packages/d2b-provider-audio-pipewire/src/controller.rs b/packages/d2b-provider-audio-pipewire/src/controller.rs index d002a5255..c8f8947b3 100644 --- a/packages/d2b-provider-audio-pipewire/src/controller.rs +++ b/packages/d2b-provider-audio-pipewire/src/controller.rs @@ -8,7 +8,7 @@ use crate::{ use d2b_contracts_provider::v3::semantic_services::{ SemanticFamily, child_resources::{ - BindingChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, + ProcessChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, explicit_binding_children, }, }; @@ -33,7 +33,7 @@ pub const AUDIO_QUEUE_BOUND: NonZeroUsize = NonZeroUsize::new(64).expect("fixed const AUDIO_BINDING_CHILD_REQUESTS: [BindingChildRequest; 4] = [ BindingChildRequest::process( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Host, "host-effect", "Provider/system-minijail", @@ -43,7 +43,7 @@ const AUDIO_BINDING_CHILD_REQUESTS: [BindingChildRequest; 4] = [ ), BindingChildRequest::endpoint(BindingChildPlacement::Host, "host-endpoint", "host-effect"), BindingChildRequest::process( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Guest, "guest-agent", "Provider/system-systemd", diff --git a/packages/d2b-provider-device-security-key/src/controller.rs b/packages/d2b-provider-device-security-key/src/controller.rs index b27c7a26c..39ce193c9 100644 --- a/packages/d2b-provider-device-security-key/src/controller.rs +++ b/packages/d2b-provider-device-security-key/src/controller.rs @@ -4,7 +4,7 @@ use core::fmt; use d2b_contracts_provider::v3::semantic_services::{ SemanticFamily, child_resources::{ - BindingChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, + ProcessChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, explicit_binding_children, explicit_binding_children_with_user, }, }; @@ -19,7 +19,7 @@ const SECURITY_KEY_PROVIDER_REF: &str = "Provider/device-security-key"; const SECURITY_KEY_BINDING_CHILD_REQUESTS: [BindingChildRequest; 2] = [ BindingChildRequest::process( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Guest, "guest-frontend", "Provider/system-systemd", @@ -36,7 +36,7 @@ const SECURITY_KEY_BINDING_CHILD_REQUESTS: [BindingChildRequest; 2] = [ const SECURITY_KEY_BINDING_CHILD_REQUESTS_WITH_USER: [BindingChildRequest; 2] = [ BindingChildRequest::process_for_user( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Guest, "guest-frontend", "Provider/system-systemd", diff --git a/packages/d2b-provider-device-usbip/src/lifecycle.rs b/packages/d2b-provider-device-usbip/src/lifecycle.rs index 0eb5ccef2..a02e5038e 100644 --- a/packages/d2b-provider-device-usbip/src/lifecycle.rs +++ b/packages/d2b-provider-device-usbip/src/lifecycle.rs @@ -8,7 +8,7 @@ use d2b_contracts_provider::v3::semantic_services::{ SemanticFamily, child_resources::{ - BindingChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, + ProcessChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, explicit_binding_children, }, }; @@ -19,7 +19,7 @@ const USBIP_PROVIDER_REF: &str = "Provider/device-usbip"; const USBIP_BINDING_CHILD_REQUESTS: [BindingChildRequest; 2] = [ BindingChildRequest::process( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Guest, "guest-proxy", "Provider/system-minijail", diff --git a/packages/d2b-provider-observability-otel/src/controller.rs b/packages/d2b-provider-observability-otel/src/controller.rs index 71a918ff3..d2a4ca62b 100644 --- a/packages/d2b-provider-observability-otel/src/controller.rs +++ b/packages/d2b-provider-observability-otel/src/controller.rs @@ -3,7 +3,7 @@ use d2b_contracts_provider::v3::semantic_services::{ SemanticFamily, child_resources::{ - BindingChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, + ProcessChildKind, BindingChildPlacement, BindingChildRequest, BindingChildSet, explicit_binding_children, }, }; @@ -244,7 +244,7 @@ impl TelemetryComponentSession { const TELEMETRY_ZONE_BINDING_CHILD_REQUESTS: [BindingChildRequest; 2] = [ BindingChildRequest::process( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Host, "collector", "Provider/system-minijail", @@ -257,7 +257,7 @@ const TELEMETRY_ZONE_BINDING_CHILD_REQUESTS: [BindingChildRequest; 2] = [ const TELEMETRY_GUEST_BINDING_CHILD_REQUESTS: [BindingChildRequest; 4] = [ BindingChildRequest::process( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Host, "collector", "Provider/system-minijail", @@ -267,7 +267,7 @@ const TELEMETRY_GUEST_BINDING_CHILD_REQUESTS: [BindingChildRequest; 4] = [ ), BindingChildRequest::endpoint(BindingChildPlacement::Host, "ingest-endpoint", "collector"), BindingChildRequest::process( - BindingChildKind::Process, + ProcessChildKind::Process, BindingChildPlacement::Host, "forwarder", "Provider/system-minijail", From cf58549f78c5c3d7ba5c0e76cd1227fa4921386f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:27:45 -0700 Subject: [PATCH 561/726] contracts: type store payload digests and fold StoreErrorKind into ResourceErrorKind RS-0255: StoredResource/PreparedStoreMutation payload digests become StateDigest and StoredSchema's becomes SchemaFingerprint, parsed at the backend boundary so a non-digest string cannot cross the store contract. RS-0468: StoreErrorKind is now Resource(ResourceErrorKind) plus the three store-only kinds, and map_store_error_kind passes resource-plane kinds through unchanged; wire error codes are identical. RS-0551: PayloadSchema deserializes through Self::parse, so wire schemas cannot bypass the closed-object or writeOnly gates. --- .../w4-03-contracts-store-digests-errors.md | 13 ++ .../src/v3/operations/error.rs | 117 +++--------------- .../src/v3/operations/mod.rs | 24 ++-- .../src/v3/operations/seal.rs | 4 +- .../src/v3/payload_schema.rs | 44 ++++++- packages/d2b-resource-api/src/adapter.rs | 9 +- packages/d2b-resource-api/src/admission.rs | 40 ++++-- packages/d2b-resource-api/src/error.rs | 70 +++-------- .../d2b-resource-api/src/manager_backend.rs | 64 +++++++--- .../src/manager_backend/tests.rs | 6 +- packages/d2b-resource-api/src/service.rs | 25 ++-- 11 files changed, 203 insertions(+), 213 deletions(-) create mode 100644 changelog.d/w4-03-contracts-store-digests-errors.md diff --git a/changelog.d/w4-03-contracts-store-digests-errors.md b/changelog.d/w4-03-contracts-store-digests-errors.md new file mode 100644 index 000000000..96b6b2b8a --- /dev/null +++ b/changelog.d/w4-03-contracts-store-digests-errors.md @@ -0,0 +1,13 @@ +# `w4-03-contracts-store-digests-errors.md` + +### Fixed + +- The store-contract payload digests (`StoredResource.payload_digest`, + `StoredSchema.payload_digest`, and `PreparedStoreMutation.payload_digest`) + are now validated SHA-256 digest values (`StateDigest`/`SchemaFingerprint`) + parsed at the backend boundary, so a non-digest string can no longer flow + through the store boundary; the wire shape is unchanged. +- A wire payload schema is now validated through the same closed-object and + `writeOnly` gates as an authored one, so a schema that declares open + properties or gives a `writeOnly` property a `default`, `enum`, `const`, + or `examples` value is refused on deserialization instead of admitted. \ No newline at end of file diff --git a/packages/d2b-contracts-resource/src/v3/operations/error.rs b/packages/d2b-contracts-resource/src/v3/operations/error.rs index d825647d3..a38985d99 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/error.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/error.rs @@ -1,6 +1,6 @@ //! Storage-neutral resource store errors. -use crate::v3::{MAX_BATCH_MUTATIONS, RetryClass, ZoneRevision}; +use crate::v3::{MAX_BATCH_MUTATIONS, ResourceErrorKind, RetryClass, ZoneRevision}; /// Upper bound on the stores one composition root may open. pub const MAX_STORE_SLOTS: usize = 64; @@ -91,41 +91,20 @@ impl SealIdentityMismatch { } /// Closed store error classification. +/// +/// The resource-plane half of the set is the shared +/// [`ResourceErrorKind`] classification itself, so one resource-plane kind +/// has exactly one spelling and one mapping; the three store-only kinds are +/// the store machinery failures with no resource-plane counterpart. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum StoreErrorKind { - ResourceNotFound, - ResourceAlreadyExists, - ResourceConflict, - ResourceSchemaInvalid, - ResourceRefInvalid, - ResourceOwnerCycle, - ResourceOwnerDepth, - ResourceFinalizerDenied, - ResourceProviderUnavailable, - ResourceControllerMismatch, - ResourceStatusOwnerMismatch, - StatusOversize, - StatusProviderSchemaInvalid, - StatusProviderOverlap, - SpecProviderSchemaInvalid, - SpecProviderShadow, - UnsupportedCapability, - ExpeditedNotAuthorized, - ExpeditedQuotaExceeded, - ExpeditedReconcilePending, - UpgradeRequired, - EndpointResolveDenied, - RelayDenied, - RoleRelayGrantRestricted, - AuthorizationDenied, - RevisionExpired, - Backpressure, - Timeout, - Cancelled, - ResourcePlaneUnavailable, - InternalIntegrityFailure, + /// A resource-plane error, classified by the closed API set. + Resource(ResourceErrorKind), + /// The store's own integrity machinery failed. StoreIntegrityFailure, + /// The store's internal queue is overfull. StoreBackpressure, + /// The store quarantined the operation. StoreQuarantined, } @@ -133,77 +112,16 @@ impl StoreErrorKind { /// Exact stable contract spelling. pub const fn as_str(self) -> &'static str { match self { - Self::ResourceNotFound => "resource-not-found", - Self::ResourceAlreadyExists => "resource-already-exists", - Self::ResourceConflict => "resource-conflict", - Self::ResourceSchemaInvalid => "resource-schema-invalid", - Self::ResourceRefInvalid => "resource-ref-invalid", - Self::ResourceOwnerCycle => "resource-owner-cycle", - Self::ResourceOwnerDepth => "resource-owner-depth", - Self::ResourceFinalizerDenied => "resource-finalizer-denied", - Self::ResourceProviderUnavailable => "resource-provider-unavailable", - Self::ResourceControllerMismatch => "resource-controller-mismatch", - Self::ResourceStatusOwnerMismatch => "resource-status-owner-mismatch", - Self::StatusOversize => "status-oversize", - Self::StatusProviderSchemaInvalid => "status-provider-schema-invalid", - Self::StatusProviderOverlap => "status-provider-overlap", - Self::SpecProviderSchemaInvalid => "spec-provider-schema-invalid", - Self::SpecProviderShadow => "spec-provider-shadow", - Self::UnsupportedCapability => "unsupported-capability", - Self::ExpeditedNotAuthorized => "expedited-not-authorized", - Self::ExpeditedQuotaExceeded => "expedited-quota-exceeded", - Self::ExpeditedReconcilePending => "expedited-reconcile-pending", - Self::UpgradeRequired => "upgrade-required", - Self::EndpointResolveDenied => "endpoint-resolve-denied", - Self::RelayDenied => "relay-denied", - Self::RoleRelayGrantRestricted => "role-relay-grant-restricted", - Self::AuthorizationDenied => "authorization-denied", - Self::RevisionExpired => "revision-expired", - Self::Backpressure => "backpressure", - Self::Timeout => "timeout", - Self::Cancelled => "cancelled", - Self::ResourcePlaneUnavailable => "resource-plane-unavailable", - Self::InternalIntegrityFailure => "internal-integrity-failure", + Self::Resource(kind) => kind.as_str(), Self::StoreIntegrityFailure => "store-integrity-failure", Self::StoreBackpressure => "store-backpressure", Self::StoreQuarantined => "store-quarantined", } } - /// Exhaustive stable variant order. - pub const fn all() -> &'static [Self; 34] { + /// The store-only kinds, in stable order. + pub const fn all() -> &'static [Self; 3] { &[ - Self::ResourceNotFound, - Self::ResourceAlreadyExists, - Self::ResourceConflict, - Self::ResourceSchemaInvalid, - Self::ResourceRefInvalid, - Self::ResourceOwnerCycle, - Self::ResourceOwnerDepth, - Self::ResourceFinalizerDenied, - Self::ResourceProviderUnavailable, - Self::ResourceControllerMismatch, - Self::ResourceStatusOwnerMismatch, - Self::StatusOversize, - Self::StatusProviderSchemaInvalid, - Self::StatusProviderOverlap, - Self::SpecProviderSchemaInvalid, - Self::SpecProviderShadow, - Self::UnsupportedCapability, - Self::ExpeditedNotAuthorized, - Self::ExpeditedQuotaExceeded, - Self::ExpeditedReconcilePending, - Self::UpgradeRequired, - Self::EndpointResolveDenied, - Self::RelayDenied, - Self::RoleRelayGrantRestricted, - Self::AuthorizationDenied, - Self::RevisionExpired, - Self::Backpressure, - Self::Timeout, - Self::Cancelled, - Self::ResourcePlaneUnavailable, - Self::InternalIntegrityFailure, Self::StoreIntegrityFailure, Self::StoreBackpressure, Self::StoreQuarantined, @@ -251,7 +169,7 @@ impl StoreError { reason_code: &'static str, ) -> Self { Self { - kind: StoreErrorKind::ResourceConflict, + kind: StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict), current_revision: Some(current_revision), mutation_ordinal: Some(mutation_ordinal), store_slot: None, @@ -368,7 +286,10 @@ mod tests { "revision-changed", ); - assert_eq!(error.kind(), StoreErrorKind::ResourceConflict); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict) + ); assert_eq!(error.current_revision(), Some(ZoneRevision::new(9))); assert_eq!(error.mutation_ordinal().unwrap().get(), 3); assert_eq!(error.retry_after_ms(), None); diff --git a/packages/d2b-contracts-resource/src/v3/operations/mod.rs b/packages/d2b-contracts-resource/src/v3/operations/mod.rs index b8776ff2b..b3f46bed6 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/mod.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/mod.rs @@ -10,7 +10,8 @@ use crate::v3::identity::ReconnectGeneration; use crate::v3::{ ConfigurationGeneration, ControllerGeneration, FinalizerId, ResourceGeneration, ResourceName, - ResourceRef, ResourceTypeName, ResourceUid, ZoneId, ZoneRevision, + ResourceRef, ResourceTypeName, ResourceUid, SchemaFingerprint, StateDigest, ZoneId, + ZoneRevision, }; pub mod error; @@ -68,7 +69,8 @@ pub struct StoredResource { pub generation: ResourceGeneration, pub revision: ZoneRevision, pub canonical_json: Vec, - pub payload_digest: String, + /// Digest of the canonical resource payload the row carries. + pub payload_digest: StateDigest, } impl core::fmt::Debug for StoredResource { @@ -236,7 +238,8 @@ impl core::fmt::Debug for StoreInspectSchemaRequest { pub struct StoredSchema { pub resource_type: ResourceTypeName, pub canonical_json: Vec, - pub payload_digest: String, + /// Digest of the canonical schema document the row carries. + pub payload_digest: SchemaFingerprint, } impl core::fmt::Debug for StoredSchema { @@ -371,7 +374,7 @@ impl core::fmt::Debug for ResourceAssignmentFence { pub struct PreparedStoreMutation { mutation: StoreMutation, resource_uid: Option, - payload_digest: Option, + payload_digest: Option, } impl PreparedStoreMutation { @@ -379,7 +382,7 @@ impl PreparedStoreMutation { pub const fn new( mutation: StoreMutation, resource_uid: Option, - payload_digest: Option, + payload_digest: Option, ) -> Self { Self { mutation, @@ -399,8 +402,8 @@ impl PreparedStoreMutation { } /// Digest of the final canonical bytes persisted by the backend. - pub fn payload_digest(&self) -> Option<&str> { - self.payload_digest.as_deref() + pub const fn payload_digest(&self) -> Option<&StateDigest> { + self.payload_digest.as_ref() } } @@ -521,7 +524,8 @@ mod tests { const UID_SENTINEL: &str = "feedface-feed-4bad-8dad-deadbeef0001"; const TYPE_SENTINEL: &str = "debug-sentinel.d2bus.org.Widget"; const PAYLOAD_SENTINEL: &str = "payload-debug-sentinel"; - const DIGEST_SENTINEL: &str = "digest-debug-sentinel"; + const DIGEST_SENTINEL: &str = + "sha256:feedfacefeedfacefeedfacefeedfacefeedfacefeedfacefeedfacefeedface"; const OPERATION_SENTINEL: &str = "operation-debug-sentinel"; const FILTER_SENTINEL: &str = "filter-debug-sentinel"; const CURSOR_SENTINEL: &str = "cursor-debug-sentinel"; @@ -558,7 +562,7 @@ mod tests { generation: ResourceGeneration::new(3).unwrap(), revision: ZoneRevision::new(5), canonical_json: PAYLOAD_SENTINEL.as_bytes().to_vec(), - payload_digest: DIGEST_SENTINEL.to_owned(), + payload_digest: StateDigest::parse(DIGEST_SENTINEL).unwrap(), }; let get = StoreGetRequest { operation: operation(), @@ -618,7 +622,7 @@ mod tests { let schema = StoredSchema { resource_type: resource_type.clone(), canonical_json: PAYLOAD_SENTINEL.as_bytes().to_vec(), - payload_digest: DIGEST_SENTINEL.to_owned(), + payload_digest: SchemaFingerprint::parse(DIGEST_SENTINEL).unwrap(), }; let mutation = StoreMutation { kind: ResourceMutationKind::UpdateSpec, diff --git a/packages/d2b-contracts-resource/src/v3/operations/seal.rs b/packages/d2b-contracts-resource/src/v3/operations/seal.rs index eb3247af3..a5ec3de86 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/seal.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/seal.rs @@ -6,7 +6,7 @@ use std::sync::Arc; -use crate::v3::{ResourceUid, RetryClass, ZoneId}; +use crate::v3::{ResourceErrorKind, ResourceUid, RetryClass, ZoneId}; use super::{ AdmittedAuthorization, PolicySnapshot, PreparedStoreMutation, StoreOperationContext, StoreSlot, @@ -210,7 +210,7 @@ impl MutationSealAcceptor { fn integrity(&self, reason_code: &'static str) -> StoreError { StoreError::new( - StoreErrorKind::InternalIntegrityFailure, + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure), None, None, RetryClass::Never, diff --git a/packages/d2b-contracts-resource/src/v3/payload_schema.rs b/packages/d2b-contracts-resource/src/v3/payload_schema.rs index 374c2218a..70aeaa66a 100644 --- a/packages/d2b-contracts-resource/src/v3/payload_schema.rs +++ b/packages/d2b-contracts-resource/src/v3/payload_schema.rs @@ -12,7 +12,7 @@ //! can be inferred from the schema is not a secret. use schemars::{JsonSchema, r#gen::SchemaGenerator, schema}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use serde_json::{Map, Value}; /// Maximum serialized bytes of one payload schema document. @@ -27,10 +27,22 @@ pub const MAX_PAYLOAD_PROPERTY_NAME_BYTES: usize = 63; const WRITE_ONLY_VALUE_KEYS: [&str; 4] = ["default", "enum", "const", "examples"]; /// A validated payload JSON Schema document. -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Serialize)] #[serde(transparent)] pub struct PayloadSchema(Value); +impl<'de> Deserialize<'de> for PayloadSchema { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // The wire shape is the document itself; every admission gate of + // [`Self::parse`] applies, so a wire schema can never bypass the + // closed-object or writeOnly validation the authored path enforces. + Self::parse(Value::deserialize(deserializer)?).map_err(serde::de::Error::custom) + } +} + impl PayloadSchema { /// Validate one authored payload schema. pub fn parse(value: Value) -> Result { @@ -471,6 +483,34 @@ mod tests { ); } + #[test] + fn deserialize_applies_the_same_gates_as_parse() { + // A wire schema must not bypass the closed-object or writeOnly + // validation the authored path enforces. + for rejected in [ + json!({ "type": "object", "additionalProperties": true, "properties": {} }), + json!({ + "type": "object", + "additionalProperties": false, + "properties": { + "token": { "type": "string", "writeOnly": true, "default": "x" } + } + }), + ] { + assert!( + serde_json::from_value::(rejected.clone()).is_err(), + "{rejected} must be refused on the wire" + ); + } + let schema = serde_json::from_value::(object_schema()) + .expect("a closed schema deserializes"); + assert_eq!( + schema.property_names().collect::>(), + vec!["socketPath", "supervisorToken", "workerCount"] + ); + assert!(schema.is_write_only("supervisorToken")); + } + #[test] fn diagnostics_never_render_property_values() { let marker = format!("secret-{:x}", std::process::id()); diff --git a/packages/d2b-resource-api/src/adapter.rs b/packages/d2b-resource-api/src/adapter.rs index 62ff99950..2241f2f38 100644 --- a/packages/d2b-resource-api/src/adapter.rs +++ b/packages/d2b-resource-api/src/adapter.rs @@ -491,8 +491,8 @@ mod tests { use d2b_contracts_resource::v3::{ CanonicalJsonValue, ConfigurationGeneration, ControllerGeneration, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceEnvelope, ResourceGeneration, ResourceName, - ResourceRef, ResourceTypeName, ResourceUid, SchemaFingerprint, ZoneId, ZoneRevision, - canonical_digest, + ResourceRef, ResourceTypeName, ResourceUid, SchemaFingerprint, StateDigest, ZoneId, + ZoneRevision, canonical_digest, }; use d2b_core_controller::controller_assignment::{ScopedCommitTransport, ScopedResourceScope}; use d2b_contracts_resource::v3::operations::seal::MutationSealAcceptor; @@ -880,7 +880,8 @@ mod tests { Ok(StoredSchema { resource_type: ResourceTypeName::parse("Host").unwrap(), canonical_json: b"inspect-schema-sentinel-112".to_vec(), - payload_digest: format!("sha256:{}", "1".repeat(64)), + payload_digest: SchemaFingerprint::parse(format!("sha256:{}", "1".repeat(64))) + .unwrap(), }) } @@ -1232,7 +1233,7 @@ mod tests { generation: ResourceGeneration::new(1).unwrap(), revision: ZoneRevision::new(revision), canonical_json: format!("response-sentinel-{revision}").into_bytes(), - payload_digest: format!("sha256:{revision:064x}"), + payload_digest: StateDigest::parse(format!("sha256:{revision:064x}")).unwrap(), } } diff --git a/packages/d2b-resource-api/src/admission.rs b/packages/d2b-resource-api/src/admission.rs index fa0bc0566..6a13d0379 100644 --- a/packages/d2b-resource-api/src/admission.rs +++ b/packages/d2b-resource-api/src/admission.rs @@ -3,8 +3,8 @@ use d2b_contracts_resource::redacted_debug; use d2b_contracts_resource::v3::execution_policy::redacted_debug_field_value; use d2b_contracts_resource::v3::{ - CanonicalJsonValue, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceEnvelope, RetryClass, - canonical_digest, + CanonicalJsonValue, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceEnvelope, ResourceErrorKind, + RetryClass, StateDigest, canonical_digest, }; use d2b_contracts_resource::v3::operations::seal::MutationSealIssuer; use d2b_contracts_resource::v3::{ @@ -347,7 +347,7 @@ impl StoreAdmissionBinding { #[allow(clippy::disallowed_methods, reason = "synchronous path")] let issuer_guard = self.seal_issuer.lock().map_err(|_| { StoreError::new( - StoreErrorKind::InternalIntegrityFailure, + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure), None, None, RetryClass::Never, @@ -356,7 +356,7 @@ impl StoreAdmissionBinding { })?; let issuer = issuer_guard.as_ref().ok_or_else(|| { StoreError::new( - StoreErrorKind::InternalIntegrityFailure, + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure), None, None, RetryClass::Never, @@ -383,7 +383,7 @@ impl StoreAdmissionBinding { fn authority_mismatch() -> StoreError { StoreError::new( - StoreErrorKind::InternalIntegrityFailure, + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure), None, None, RetryClass::Never, @@ -393,7 +393,7 @@ fn authority_mismatch() -> StoreError { fn store_identity_mismatch() -> StoreError { StoreError::new( - StoreErrorKind::InternalIntegrityFailure, + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure), None, None, RetryClass::Never, @@ -425,7 +425,11 @@ fn prepare_mutation(mut mutation: StoreMutation) -> Result Result Result<(Vec, String), StoreError> { +) -> Result<(Vec, StateDigest), StoreError> { let mut value = CanonicalJsonValue::parse(source) .map_err(|_| preparation_error("create-resource-body-invalid"))?; let canonical = value.to_canonical_bytes(); @@ -463,7 +467,8 @@ fn validate_create( let envelope = ResourceEnvelope::from_json(&value.to_canonical_bytes()) .map_err(|_| preparation_error("create-resource-body-invalid"))?; validate_envelope_identity(&envelope, mutation)?; - let digest = canonical_digest(RESOURCE_ENVELOPE_DOMAIN_TAG, &canonical); + let digest = StateDigest::parse(canonical_digest(RESOURCE_ENVELOPE_DOMAIN_TAG, &canonical)) + .expect("a canonical digest is a valid state digest"); Ok((canonical, digest)) } @@ -486,7 +491,7 @@ fn validate_envelope_identity( fn preparation_error(reason_code: &'static str) -> StoreError { StoreError::new( - StoreErrorKind::ResourceSchemaInvalid, + StoreErrorKind::Resource(ResourceErrorKind::ResourceSchemaInvalid), None, None, RetryClass::Never, @@ -617,7 +622,10 @@ mod tests { .verify(admitted) .err() .expect("rejected admission"); - assert_eq!(error.kind(), StoreErrorKind::ResourceSchemaInvalid); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::ResourceSchemaInvalid) + ); assert_eq!(error.reason_code(), "create-resource-uid-present"); } @@ -634,7 +642,10 @@ mod tests { .verify(admitted) .err() .expect("rejected admission"); - assert_eq!(error.kind(), StoreErrorKind::InternalIntegrityFailure); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure) + ); assert_eq!(error.reason_code(), "admission-authority-mismatch"); } @@ -662,7 +673,10 @@ mod tests { .verify(admitted) .err() .expect("rejected admission"); - assert_eq!(error.kind(), StoreErrorKind::InternalIntegrityFailure); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure) + ); assert_eq!(error.reason_code(), "admission-store-identity-mismatch"); } diff --git a/packages/d2b-resource-api/src/error.rs b/packages/d2b-resource-api/src/error.rs index 2bf90c184..1d6727577 100644 --- a/packages/d2b-resource-api/src/error.rs +++ b/packages/d2b-resource-api/src/error.rs @@ -8,51 +8,15 @@ use d2b_contracts_resource::v3::{StoreError, StoreErrorKind}; use protobuf::EnumOrUnknown; /// Map every store error kind onto the closed API set. +/// +/// Resource-plane kinds pass through unchanged; the three store-only kinds +/// collapse onto the resource-plane kinds their wire codes already carried. pub const fn map_store_error_kind(kind: StoreErrorKind) -> ResourceErrorKind { match kind { - StoreErrorKind::ResourceNotFound => ResourceErrorKind::ResourceNotFound, - StoreErrorKind::ResourceAlreadyExists => ResourceErrorKind::ResourceAlreadyExists, - StoreErrorKind::ResourceConflict => ResourceErrorKind::ResourceConflict, - StoreErrorKind::ResourceSchemaInvalid => ResourceErrorKind::ResourceSchemaInvalid, - StoreErrorKind::ResourceRefInvalid => ResourceErrorKind::ResourceRefInvalid, - StoreErrorKind::ResourceOwnerCycle => ResourceErrorKind::ResourceOwnerCycle, - StoreErrorKind::ResourceOwnerDepth => ResourceErrorKind::ResourceOwnerDepth, - StoreErrorKind::ResourceFinalizerDenied => ResourceErrorKind::ResourceFinalizerDenied, - StoreErrorKind::ResourceProviderUnavailable => { - ResourceErrorKind::ResourceProviderUnavailable - } - StoreErrorKind::ResourceControllerMismatch => ResourceErrorKind::ResourceControllerMismatch, - StoreErrorKind::ResourceStatusOwnerMismatch => { - ResourceErrorKind::ResourceStatusOwnerMismatch - } - StoreErrorKind::StatusOversize => ResourceErrorKind::StatusOversize, - StoreErrorKind::StatusProviderSchemaInvalid => { - ResourceErrorKind::StatusProviderSchemaInvalid - } - StoreErrorKind::StatusProviderOverlap => ResourceErrorKind::StatusProviderOverlap, - StoreErrorKind::SpecProviderSchemaInvalid => ResourceErrorKind::SpecProviderSchemaInvalid, - StoreErrorKind::SpecProviderShadow => ResourceErrorKind::SpecProviderShadow, - StoreErrorKind::UnsupportedCapability => ResourceErrorKind::UnsupportedCapability, - StoreErrorKind::ExpeditedNotAuthorized => ResourceErrorKind::ExpeditedNotAuthorized, - StoreErrorKind::ExpeditedQuotaExceeded => ResourceErrorKind::ExpeditedQuotaExceeded, - StoreErrorKind::ExpeditedReconcilePending => ResourceErrorKind::ExpeditedReconcilePending, - StoreErrorKind::UpgradeRequired => ResourceErrorKind::UpgradeRequired, - StoreErrorKind::EndpointResolveDenied => ResourceErrorKind::EndpointResolveDenied, - StoreErrorKind::RelayDenied => ResourceErrorKind::RelayDenied, - StoreErrorKind::RoleRelayGrantRestricted => ResourceErrorKind::RoleRelayGrantRestricted, - StoreErrorKind::AuthorizationDenied => ResourceErrorKind::AuthorizationDenied, - StoreErrorKind::RevisionExpired => ResourceErrorKind::RevisionExpired, - StoreErrorKind::Backpressure | StoreErrorKind::StoreBackpressure => { - ResourceErrorKind::Backpressure - } - StoreErrorKind::Timeout => ResourceErrorKind::Timeout, - StoreErrorKind::Cancelled => ResourceErrorKind::Cancelled, - StoreErrorKind::ResourcePlaneUnavailable | StoreErrorKind::StoreQuarantined => { - ResourceErrorKind::ResourcePlaneUnavailable - } - StoreErrorKind::InternalIntegrityFailure | StoreErrorKind::StoreIntegrityFailure => { - ResourceErrorKind::InternalIntegrityFailure - } + StoreErrorKind::Resource(kind) => kind, + StoreErrorKind::StoreIntegrityFailure => ResourceErrorKind::InternalIntegrityFailure, + StoreErrorKind::StoreBackpressure => ResourceErrorKind::Backpressure, + StoreErrorKind::StoreQuarantined => ResourceErrorKind::ResourcePlaneUnavailable, } } @@ -203,13 +167,17 @@ mod tests { #[test] fn store_mapping_is_total_and_one_way() { - assert_eq!(StoreErrorKind::all().len(), 34); + // Every resource-plane kind passes through unchanged, so the shared + // set needs no store-side re-listing. + for kind in ResourceErrorKind::all() { + assert_eq!(map_store_error_kind(StoreErrorKind::Resource(*kind)), *kind); + } let mapped = StoreErrorKind::all() .iter() .copied() .map(map_store_error_kind) .collect::>(); - assert_eq!(mapped.len(), 34); + assert_eq!(mapped.len(), 3); assert_eq!( map_store_error_kind(StoreErrorKind::StoreIntegrityFailure), ResourceErrorKind::InternalIntegrityFailure @@ -227,7 +195,7 @@ mod tests { #[test] fn conflict_revision_survives_typed_wire_mapping() { let error = map_store_error(StoreError::new( - StoreErrorKind::ResourceConflict, + StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict), Some(ZoneRevision::new(8)), None, RetryClass::Immediate, @@ -244,7 +212,7 @@ mod tests { #[test] fn assignment_required_conflict_is_wire_valid_and_retryable() { let error = map_store_error(StoreError::new( - StoreErrorKind::ResourceConflict, + StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict), Some(ZoneRevision::new(8)), None, RetryClass::Reauthorize, @@ -269,7 +237,7 @@ mod tests { #[test] fn invalid_store_error_metadata_fails_closed_without_panicking() { let error = map_store_error(StoreError::new( - StoreErrorKind::ResourceNotFound, + StoreErrorKind::Resource(ResourceErrorKind::ResourceNotFound), Some(ZoneRevision::new(8)), None, RetryClass::Never, @@ -282,7 +250,7 @@ mod tests { fn conflict_revision_can_be_hidden_without_changing_the_kind() { let error = map_store_error_with_revision_visibility( StoreError::new( - StoreErrorKind::ResourceConflict, + StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict), Some(ZoneRevision::new(8)), None, RetryClass::Reauthorize, @@ -298,7 +266,7 @@ mod tests { fn authorization_denied_visible_revision_and_retry_survive_mapping() { let error = map_store_error_with_revision_visibility( StoreError::new( - StoreErrorKind::AuthorizationDenied, + StoreErrorKind::Resource(ResourceErrorKind::AuthorizationDenied), Some(ZoneRevision::new(8)), None, RetryClass::Reauthorize, @@ -326,7 +294,7 @@ mod tests { fn authorization_denied_revision_can_be_hidden_without_changing_kind_or_retry() { let error = map_store_error_with_revision_visibility( StoreError::new( - StoreErrorKind::AuthorizationDenied, + StoreErrorKind::Resource(ResourceErrorKind::AuthorizationDenied), Some(ZoneRevision::new(8)), None, RetryClass::Reauthorize, diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index 898ac731e..ef8d834d0 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -49,8 +49,8 @@ use std::sync::Arc; use d2b_contracts_resource::redacted_debug; use d2b_contracts_resource::v3::{ - CanonicalJsonValue, FinalizerId, ResourceEnvelope, ResourceGeneration, ResourceRef, - ResourceUid, RetryClass, ZoneId, ZoneRevision, canonical_digest, + CanonicalJsonValue, FinalizerId, ResourceEnvelope, ResourceErrorKind, ResourceGeneration, + ResourceRef, ResourceUid, RetryClass, StateDigest, ZoneId, ZoneRevision, canonical_digest, RESOURCE_ENVELOPE_DOMAIN_TAG, }; use d2b_resource_runtime::manager::{ @@ -120,12 +120,17 @@ fn error( } fn not_found() -> StoreError { - error(StoreErrorKind::ResourceNotFound, None, RetryClass::Never, "resource-not-found") + error( + StoreErrorKind::Resource(ResourceErrorKind::ResourceNotFound), + None, + RetryClass::Never, + "resource-not-found", + ) } fn conflict(current_generation: u64, reason: &'static str) -> StoreError { error( - StoreErrorKind::ResourceConflict, + StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict), Some(current_generation), RetryClass::Reauthorize, reason, @@ -134,7 +139,7 @@ fn conflict(current_generation: u64, reason: &'static str) -> StoreError { fn already_exists(current_generation: u64) -> StoreError { error( - StoreErrorKind::ResourceAlreadyExists, + StoreErrorKind::Resource(ResourceErrorKind::ResourceAlreadyExists), Some(current_generation), RetryClass::Reauthorize, "resource-already-exists", @@ -145,7 +150,7 @@ fn already_exists(current_generation: u64) -> StoreError { /// only in memory at the authoritative actor and on the actual target. fn status_write_rejected() -> StoreError { error( - StoreErrorKind::ResourceStatusOwnerMismatch, + StoreErrorKind::Resource(ResourceErrorKind::ResourceStatusOwnerMismatch), None, RetryClass::Never, "resource-status-owner-mismatch", @@ -154,7 +159,7 @@ fn status_write_rejected() -> StoreError { fn envelope_invalid() -> StoreError { error( - StoreErrorKind::ResourceSchemaInvalid, + StoreErrorKind::Resource(ResourceErrorKind::ResourceSchemaInvalid), None, RetryClass::Never, "resource-envelope-invalid", @@ -166,7 +171,7 @@ fn map_manager_error(failure: ResourceError) -> StoreError { match failure { ResourceError::DeletingConflict { .. } => { error( - StoreErrorKind::ResourceConflict, + StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict), None, RetryClass::Reauthorize, "resource-deleting", @@ -176,7 +181,7 @@ fn map_manager_error(failure: ResourceError) -> StoreError { // The spec row stays durable (F1); the resource recovers on the // next Ensure or manager restart. error( - StoreErrorKind::ResourceProviderUnavailable, + StoreErrorKind::Resource(ResourceErrorKind::ResourceProviderUnavailable), None, RetryClass::AfterDelay, "resource-provider-unavailable", @@ -184,7 +189,7 @@ fn map_manager_error(failure: ResourceError) -> StoreError { } ResourceError::AdmissionDenied { .. } => { error( - StoreErrorKind::AuthorizationDenied, + StoreErrorKind::Resource(ResourceErrorKind::AuthorizationDenied), None, RetryClass::Reauthorize, "admission-denied", @@ -193,7 +198,7 @@ fn map_manager_error(failure: ResourceError) -> StoreError { other => { tracing::warn!(failure = %other, "manager-backed store call failed"); error( - StoreErrorKind::ResourcePlaneUnavailable, + StoreErrorKind::Resource(ResourceErrorKind::ResourcePlaneUnavailable), None, RetryClass::AfterDelay, "manager-unavailable", @@ -476,7 +481,12 @@ fn hex_decode(value: &str) -> Option> { } fn list_cursor_error(reason: &'static str) -> StoreError { - error(StoreErrorKind::ResourceSchemaInvalid, None, RetryClass::Never, reason) + error( + StoreErrorKind::Resource(ResourceErrorKind::ResourceSchemaInvalid), + None, + RetryClass::Never, + reason, + ) } /// Encode the continuation cursor: `v1... Result<(), StoreError> { let envelope = ResourceEnvelope::from_json(&stored.canonical_json).map_err(|_| envelope_invalid())?; stored.canonical_json = envelope.canonical_bytes().map_err(|_| envelope_invalid())?; - stored.payload_digest = envelope.digest().map_err(|_| envelope_invalid())?; + let digest = envelope.digest().map_err(|_| envelope_invalid())?; + stored.payload_digest = + StateDigest::parse(digest).map_err(|_| envelope_invalid())?; Ok(()) } @@ -997,7 +1023,7 @@ impl ManagerBackend { .map_err(map_manager_error)?; if handle.uid != manager_uid(&key) { return Err(error( - StoreErrorKind::InternalIntegrityFailure, + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure), None, RetryClass::Never, "row-identity-drift", @@ -1054,7 +1080,7 @@ impl ManagerBackend { .map_err(map_manager_error)?; if handle.uid != manager_uid(&key) { return Err(error( - StoreErrorKind::InternalIntegrityFailure, + StoreErrorKind::Resource(ResourceErrorKind::InternalIntegrityFailure), None, RetryClass::Never, "row-identity-drift", @@ -1203,7 +1229,7 @@ impl ResourceStoreBackend for ManagerBackend { // the manager backend and pump it into the opened component stream) // is the composition's change, not this backend's. Err(error( - StoreErrorKind::UnsupportedCapability, + StoreErrorKind::Resource(ResourceErrorKind::UnsupportedCapability), None, RetryClass::Never, "watch-not-wired", @@ -1243,7 +1269,7 @@ impl ResourceStoreBackend for ManagerBackend { // contracts. Nothing on this plane can answer a schema read, so the // refusal is typed and terminal (Phase A scope, KTD4). Err(error( - StoreErrorKind::UnsupportedCapability, + StoreErrorKind::Resource(ResourceErrorKind::UnsupportedCapability), None, RetryClass::Never, "schema-catalog-not-wired", diff --git a/packages/d2b-resource-api/src/manager_backend/tests.rs b/packages/d2b-resource-api/src/manager_backend/tests.rs index 295b22df7..3b4e38a73 100644 --- a/packages/d2b-resource-api/src/manager_backend/tests.rs +++ b/packages/d2b-resource-api/src/manager_backend/tests.rs @@ -735,7 +735,7 @@ fn rendered_rows_round_trip_through_the_strict_envelope_reader() { // the digest the row carries. assert_eq!( envelope.digest().unwrap(), - stored.payload_digest, + stored.payload_digest.as_str(), "{label}: the row digest must be the decoded envelope's digest" ); assert_eq!(envelope.status().phase(), expected_phase, "{label}"); @@ -810,7 +810,7 @@ fn rendered_full_envelopes_keep_the_strict_reader_contract() { ); assert_eq!( envelope.digest().unwrap(), - stored.payload_digest, + stored.payload_digest.as_str(), "{label}: the row digest must be the decoded envelope's digest" ); if deleting { @@ -921,7 +921,7 @@ fn every_converted_type_projects_a_strict_wire_view() { ); assert_eq!( envelope.digest().expect("envelope digest"), - stored.payload_digest, + stored.payload_digest.as_str(), "{label}: the row digest must be the decoded envelope's digest" ); assert_eq!( diff --git a/packages/d2b-resource-api/src/service.rs b/packages/d2b-resource-api/src/service.rs index 367b3f69e..a692c66ec 100644 --- a/packages/d2b-resource-api/src/service.rs +++ b/packages/d2b-resource-api/src/service.rs @@ -312,7 +312,7 @@ where || envelope .digest() .map_err(|_| schema_error("Guest lifecycle resource digest is invalid"))? - != current.payload_digest + != current.payload_digest.as_str() { return Err(ResourceError::terminal( ResourceErrorKind::AuthorizationDenied, @@ -357,7 +357,7 @@ where || provider_envelope .digest() .map_err(|_| schema_error("Guest lifecycle Provider digest is invalid"))? - != provider.payload_digest + != provider.payload_digest.as_str() { return Err(ResourceError::terminal( ResourceErrorKind::AuthorizationDenied, @@ -1077,7 +1077,7 @@ where let mut body = wire::ResourceEnvelopeBytes::new(); body.identity = MessageField::some(identity); body.canonical_json = schema.canonical_json; - body.payload_digest = schema.payload_digest; + body.payload_digest = schema.payload_digest.as_str().to_owned(); let mut response = wire::InspectSchemaResponse::new(); response.schema = MessageField::some(body); if response.compute_size() as usize > MAX_RESPONSE_CANONICAL_BYTES { @@ -2159,7 +2159,7 @@ fn to_wire_resource(resource: StoredResource) -> wire::ResourceEnvelopeBytes { let mut result = wire::ResourceEnvelopeBytes::new(); result.identity = MessageField::some(identity); result.canonical_json = resource.canonical_json; - result.payload_digest = resource.payload_digest; + result.payload_digest = resource.payload_digest.as_str().to_owned(); result } @@ -2356,7 +2356,7 @@ mod tests { }; use d2b_contracts_resource::v3::{ ConfigurationGeneration, ControllerGeneration, ResourceGeneration, ResourceUid, - SchemaFingerprint, ZoneId, + SchemaFingerprint, StateDigest, ZoneId, }; use d2b_core_controller::controller_assignment::ScopedCommitTransport; use d2b_contracts_resource::v3::operations::seal::MutationSealAcceptor; @@ -2422,7 +2422,7 @@ mod tests { fn unavailable() -> StoreError { StoreError::new( - StoreErrorKind::ResourcePlaneUnavailable, + StoreErrorKind::Resource(ResourceErrorKind::ResourcePlaneUnavailable), None, None, d2b_contracts_resource::v3::RetryClass::AfterDelay, @@ -2486,8 +2486,9 @@ mod tests { first.and_then(|prepared| prepared.mutation().canonical_resource.clone()); *self.last_resource_uid.lock().await = first.and_then(|prepared| prepared.resource_uid().cloned()); - *self.last_payload_digest.lock().await = - first.and_then(|prepared| prepared.payload_digest().map(str::to_owned)); + *self.last_payload_digest.lock().await = first + .and_then(|prepared| prepared.payload_digest()) + .map(|digest| digest.as_str().to_owned()); match *self.mode.lock().await { CommitMode::Success => { if let Some(prepared) = first @@ -2746,7 +2747,7 @@ mod tests { generation: ResourceGeneration::new(1).unwrap(), revision: ZoneRevision::new(9), canonical_json: vec![b'x'; bytes], - payload_digest: format!("sha256:{}", "1".repeat(64)), + payload_digest: StateDigest::parse(format!("sha256:{}", "1".repeat(64))).unwrap(), } } @@ -3389,7 +3390,8 @@ mod tests { *schema_store.schema_response.lock().await = Some(StoredSchema { resource_type: ResourceTypeName::parse("Host").unwrap(), canonical_json: vec![b'x'; MAX_RESPONSE_CANONICAL_BYTES], - payload_digest: format!("sha256:{}", "1".repeat(64)), + payload_digest: SchemaFingerprint::parse(format!("sha256:{}", "1".repeat(64))) + .unwrap(), }); let schema_service = checked_service( Arc::clone(&schema_store), @@ -3502,7 +3504,8 @@ mod tests { resource.zone = ZoneId::parse(ZONE_SENTINEL).unwrap(); resource.uid = ResourceUid::parse(UID_SENTINEL).unwrap(); resource.canonical_json = PAYLOAD_SENTINEL.as_bytes().to_vec(); - resource.payload_digest = PAYLOAD_SENTINEL.to_owned(); + resource.payload_digest = + StateDigest::parse(format!("sha256:{}", "1".repeat(64))).unwrap(); let result = UpgradeResult { resource, plan: Vec::new(), From fc85a4e59d0bfadddd55a705dfee60c825fe2e24 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:29:34 -0700 Subject: [PATCH 562/726] provider-wayland-policy: keep serde reason on wire-parse failures RS-0573: wire-parse failures collapsed into the bare InvalidResource error, discarding the serde reason that explains why a row was refused. Add an InvalidSpec(String) variant to InteractionEffectError and AudioResourceRuntimeError carrying the serde reason, thread it through every map_err site that discarded a parse error, and keep the wire-visible error codes unchanged. Foreign-row registration tests in the audio-binding, audio-service and wayland-session crates now assert the reason-carrying variant. --- changelog.d/w4-09-serde-reason.md | 7 +++++ .../tests/registration.rs | 6 ++-- .../tests/registration.rs | 6 ++-- .../src/audio_registry.rs | 15 ++++++---- .../src/effects_service.rs | 18 ++++++----- .../src/interaction.rs | 30 ++++++++++++------- .../tests/registration.rs | 6 ++-- 7 files changed, 55 insertions(+), 33 deletions(-) create mode 100644 changelog.d/w4-09-serde-reason.md diff --git a/changelog.d/w4-09-serde-reason.md b/changelog.d/w4-09-serde-reason.md new file mode 100644 index 000000000..5cdc92a53 --- /dev/null +++ b/changelog.d/w4-09-serde-reason.md @@ -0,0 +1,7 @@ +### Fixed + +- Wayland-family Provider wire-parse failures no longer collapse into a bare + invalid-resource error: a spec or resource envelope that fails to parse + now carries the serde reason (field, line, column) through the + `d2b-provider-wayland-policy` error surface, so operator diagnostics + report why a row was refused instead of a generic invalid-resource code. \ No newline at end of file diff --git a/packages/d2b-provider-audio-binding/tests/registration.rs b/packages/d2b-provider-audio-binding/tests/registration.rs index 598af123b..7e2498a04 100644 --- a/packages/d2b-provider-audio-binding/tests/registration.rs +++ b/packages/d2b-provider-audio-binding/tests/registration.rs @@ -197,8 +197,8 @@ fn a_foreign_row_is_refused() { .downcast::() .expect("the decoder yields the family envelope"); let behavior = AudioBinding::new(Arc::new(ProviderChildren)); - assert_eq!( + assert!(matches!( behavior.validate(&envelope), - Err(InteractionEffectError::InvalidResource) - ); + Err(InteractionEffectError::InvalidSpec(_)) + )); } diff --git a/packages/d2b-provider-audio-service/tests/registration.rs b/packages/d2b-provider-audio-service/tests/registration.rs index c9e045d67..f7b957450 100644 --- a/packages/d2b-provider-audio-service/tests/registration.rs +++ b/packages/d2b-provider-audio-service/tests/registration.rs @@ -139,9 +139,9 @@ fn the_service_row_decodes_and_reads_nothing() { #[test] fn a_foreign_row_is_refused() { let envelope = envelope(&json!({"providerRef": "Provider/audio-pipewire"})); - assert_eq!( + assert!(matches!( AudioService.validate(&envelope), - Err(InteractionEffectError::InvalidResource) - ); + Err(InteractionEffectError::InvalidSpec(_)) + )); assert!(audio_service_spec_decoder().decode(b"[]").is_err()); } diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index 14793f7aa..555f1ecf3 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -38,10 +38,12 @@ use crate::vocabulary::{AUDIO_BINDING_TYPE, AUDIO_SERVICE_TYPE}; const GUEST_TYPE: &str = "Guest"; /// Stable errors for the daemon-owned audio resource path. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum AudioResourceRuntimeError { /// A resource body was malformed or used an unexpected provider. InvalidResource, + /// A wire spec or envelope failed to parse; carries the serde reason. + InvalidSpec(String), /// A binding referred to a different or missing Zone resource. InvalidRelationship, /// A controller finalizer or effect failed. @@ -51,7 +53,7 @@ pub(crate) enum AudioResourceRuntimeError { impl core::fmt::Display for AudioResourceRuntimeError { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str(match self { - Self::InvalidResource => "audio-resource-invalid", + Self::InvalidResource | Self::InvalidSpec(_) => "audio-resource-invalid", Self::InvalidRelationship => "audio-resource-relationship-invalid", Self::Controller(error) => match error { AudioControllerError::Admission => "audio-controller-admission-failed", @@ -510,7 +512,7 @@ fn is_audio_resource( return Err(AudioResourceRuntimeError::InvalidResource); } let envelope = ResourceEnvelope::from_json(&resource.canonical_json) - .map_err(|_| AudioResourceRuntimeError::InvalidResource)?; + .map_err(|error| AudioResourceRuntimeError::InvalidSpec(error.to_string()))?; Ok(envelope .spec() .provider_ref() @@ -521,9 +523,9 @@ fn decode_spec( resource: &StoredResource, ) -> Result { let envelope = ResourceEnvelope::from_json(&resource.canonical_json) - .map_err(|_| AudioResourceRuntimeError::InvalidResource)?; + .map_err(|error| AudioResourceRuntimeError::InvalidSpec(error.to_string()))?; let mut spec = serde_json::to_value(envelope.spec().base()) - .map_err(|_| AudioResourceRuntimeError::InvalidResource)?; + .map_err(|error| AudioResourceRuntimeError::InvalidSpec(error.to_string()))?; if let Some(provider_ref) = envelope.spec().provider_ref() { let object = spec .as_object_mut() @@ -533,7 +535,8 @@ fn decode_spec( serde_json::Value::String(provider_ref.to_canonical_string()), ); } - serde_json::from_value(spec).map_err(|_| AudioResourceRuntimeError::InvalidResource) + serde_json::from_value(spec) + .map_err(|error| AudioResourceRuntimeError::InvalidSpec(error.to_string())) } /// The `status.resource` projection for one AudioBinding (old diff --git a/packages/d2b-provider-wayland-policy/src/effects_service.rs b/packages/d2b-provider-wayland-policy/src/effects_service.rs index 00b176257..b644dab8b 100644 --- a/packages/d2b-provider-wayland-policy/src/effects_service.rs +++ b/packages/d2b-provider-wayland-policy/src/effects_service.rs @@ -203,7 +203,7 @@ impl InteractionEffectsService { request: &InteractionEffectRequest<'_>, ) -> Result { let spec: WaylandSessionSpec = serde_json::from_value(request.spec.clone()) - .map_err(|_| InteractionEffectError::InvalidResource)?; + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?; let identity = self .facets .identity() @@ -275,7 +275,8 @@ impl InteractionEffectsService { ) -> Result { let spec: AudioBindingSpec = spec_with_provider_ref(&request.spec, request.provider_ref.as_ref()) .and_then(|spec| { - serde_json::from_value(spec).map_err(|_| InteractionEffectError::InvalidResource) + serde_json::from_value(spec) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string())) })?; let Some(target) = self.live_stored(&key_ref(&request.target)).await? else { return Err(InteractionEffectError::Unavailable); @@ -572,8 +573,8 @@ fn resource_phase(value: &Value) -> Option<&str> { /// spec for Nix rows, the `spec` member for API rows that persist the full /// envelope minus status. fn spec_document_value(bytes: &[u8]) -> Result { - let value: Value = - serde_json::from_slice(bytes).map_err(|_| InteractionEffectError::InvalidResource)?; + let value: Value = serde_json::from_slice(bytes) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?; Ok(envelope_spec_document(&value)) } @@ -606,8 +607,8 @@ fn spec_with_provider_ref( } fn spec_ref_at(bytes: &[u8], path: &str) -> Result { - let value: Value = - serde_json::from_slice(bytes).map_err(|_| InteractionEffectError::InvalidResource)?; + let value: Value = serde_json::from_slice(bytes) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?; value .pointer(path) .and_then(Value::as_str) @@ -662,7 +663,7 @@ fn validate_audio_dependency_identity( return Err(InteractionEffectError::InvalidResource); } let envelope = ResourceEnvelope::from_json(&resource.canonical_json) - .map_err(|_| InteractionEffectError::InvalidResource)?; + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?; let metadata = envelope.metadata(); if metadata.zone() != zone || metadata.uid() != &resource.uid @@ -680,6 +681,9 @@ fn validate_audio_dependency_identity( fn map_audio_effect_error(error: AudioResourceRuntimeError) -> InteractionEffectError { match error { + AudioResourceRuntimeError::InvalidSpec(reason) => { + InteractionEffectError::InvalidSpec(reason) + } AudioResourceRuntimeError::InvalidResource | AudioResourceRuntimeError::InvalidRelationship => { InteractionEffectError::InvalidResource diff --git a/packages/d2b-provider-wayland-policy/src/interaction.rs b/packages/d2b-provider-wayland-policy/src/interaction.rs index f3a6c6014..30634f754 100644 --- a/packages/d2b-provider-wayland-policy/src/interaction.rs +++ b/packages/d2b-provider-wayland-policy/src/interaction.rs @@ -121,19 +121,21 @@ pub enum InteractionFinalize { } /// Closed failure surface for interaction Provider adapters. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum InteractionEffectError { /// The Provider path is not currently available and should retry. Unavailable, /// Fresh resource or assignment evidence failed closed. InvalidResource, + /// A wire spec or envelope failed to parse; carries the serde reason. + InvalidSpec(String), } impl core::fmt::Display for InteractionEffectError { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str(match self { Self::Unavailable => "interaction-effect-unavailable", - Self::InvalidResource => "interaction-resource-invalid", + Self::InvalidResource | Self::InvalidSpec(_) => "interaction-resource-invalid", }) } } @@ -240,7 +242,7 @@ impl InteractionSpecEnvelope { /// Decode one Layer 2 base spec. pub fn base_spec(&self) -> Result { serde_json::from_value(self.base.clone()) - .map_err(|_| InteractionEffectError::InvalidResource) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string())) } /// Decode one typed spec that carries `providerRef` itself (the audio @@ -259,7 +261,8 @@ impl InteractionSpecEnvelope { Value::String(provider_ref.to_owned()), ); } - serde_json::from_value(spec).map_err(|_| InteractionEffectError::InvalidResource) + serde_json::from_value(spec) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string())) } } @@ -688,7 +691,7 @@ impl InteractionDriver { fn effect_error(&self, error: InteractionEffectError, op: DriverOp) -> InteractionDriverError { match error { - InteractionEffectError::InvalidResource => { + InteractionEffectError::InvalidResource | InteractionEffectError::InvalidSpec(_) => { self.error(InteractionDriverErrorKind::SpecInvalid, op) } InteractionEffectError::Unavailable => { @@ -919,19 +922,21 @@ fn teardown_rank(resource_type: &str) -> u8 { /// annotation the display status reads) are carried. pub fn owned_child_ensure(intent: &OwnedChildIntent) -> Result { let invalid = || InteractionEffectError::InvalidResource; - let value: Value = serde_json::from_slice(intent.canonical_resource()).map_err(|_| invalid())?; + let value: Value = serde_json::from_slice(intent.canonical_resource()) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?; let spec = value.get("spec").cloned().ok_or_else(invalid)?; let metadata = value.get("metadata").cloned().unwrap_or_else(|| json!({})); Ok(ChildEnsure { type_name: ResourceTypeName::new(intent.target().resource_type().as_str()), name: intent.target().name().as_str().to_owned(), - spec: serde_json::to_vec(&spec).map_err(|_| invalid())?, + spec: serde_json::to_vec(&spec) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?, metadata: serde_json::to_vec(&json!({ "ownerRef": metadata.get("ownerRef").cloned().unwrap_or(Value::Null), "labels": metadata.get("labels").cloned().unwrap_or_else(|| json!({})), "annotations": metadata.get("annotations").cloned().unwrap_or_else(|| json!({})), })) - .map_err(|_| invalid())?, + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?, }) } @@ -944,7 +949,8 @@ pub fn binding_child_ensure( ) -> Result { let invalid = || InteractionEffectError::InvalidResource; let payload = materialize_child_create_payload(intent, zone).map_err(|_| invalid())?; - let value = serde_json::from_slice::(&payload).map_err(|_| invalid())?; + let value = serde_json::from_slice::(&payload) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?; let spec = value.get("spec").cloned().ok_or_else(invalid)?; let metadata = json!({ "ownerRef": intent.owner_ref().to_canonical_string(), @@ -954,7 +960,9 @@ pub fn binding_child_ensure( Ok(ChildEnsure { type_name: ResourceTypeName::new(intent.kind().resource_type()), name: intent.resource_ref().name().as_str().to_owned(), - spec: serde_json::to_vec(&spec).map_err(|_| invalid())?, - metadata: serde_json::to_vec(&metadata).map_err(|_| invalid())?, + spec: serde_json::to_vec(&spec) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?, + metadata: serde_json::to_vec(&metadata) + .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string()))?, }) } diff --git a/packages/d2b-provider-wayland-session/tests/registration.rs b/packages/d2b-provider-wayland-session/tests/registration.rs index ad574ef02..4dc05d217 100644 --- a/packages/d2b-provider-wayland-session/tests/registration.rs +++ b/packages/d2b-provider-wayland-session/tests/registration.rs @@ -196,10 +196,10 @@ fn the_session_reads_its_domain_dependencies() { fn a_foreign_row_is_refused() { let envelope = envelope(&json!({"providerRef": "Provider/display-wayland"})); let behavior = WaylandSession::new(Arc::new(TwoWorkers)); - assert_eq!( + assert!(matches!( behavior.validate(&envelope), - Err(InteractionEffectError::InvalidResource) - ); + Err(InteractionEffectError::InvalidSpec(_)) + )); } /// The session's provider realization becomes manager child rows: the manager From b062e724d55a716cafbb5b6134533caf55febeb3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:29:54 -0700 Subject: [PATCH 563/726] zone-session: move ZoneLink cryptoperiod defaults to d2b_contracts_zone_session --- .../w4-12-zone-link-cryptoperiod-defaults.md | 6 ++++++ packages/d2b-bus/src/session/enrollment.rs | 10 ++++++---- .../src/v3/zone_session.rs | 20 +++++++++++++++++++ .../d2b-provider-zone-link/src/zone_links.rs | 11 +++++----- 4 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 changelog.d/w4-12-zone-link-cryptoperiod-defaults.md diff --git a/changelog.d/w4-12-zone-link-cryptoperiod-defaults.md b/changelog.d/w4-12-zone-link-cryptoperiod-defaults.md new file mode 100644 index 000000000..31bfb9a7e --- /dev/null +++ b/changelog.d/w4-12-zone-link-cryptoperiod-defaults.md @@ -0,0 +1,6 @@ +### Fixed + +- The bootstrap-PSK and KK-session cryptoperiod defaults now share a single + canonical definition in `d2b_contracts_zone_session`, re-exported by the + child-local ZoneLink handler and the bus-side enrollment machine, so the two + sides cannot silently drift apart on the values. \ No newline at end of file diff --git a/packages/d2b-bus/src/session/enrollment.rs b/packages/d2b-bus/src/session/enrollment.rs index 746f8e07c..af8b2cc1e 100644 --- a/packages/d2b-bus/src/session/enrollment.rs +++ b/packages/d2b-bus/src/session/enrollment.rs @@ -38,15 +38,17 @@ //! is represented by its issuance ordinal and expiry only; an enrollment is //! represented by an opaque digest. Every `Debug` implementation is redacted. -/// Default absolute lifetime of one allocator-issued bootstrap PSK. -pub const BOOTSTRAP_PSK_TTL_MS_DEFAULT: u64 = 300_000; +// The cryptoperiod defaults live in `d2b_contracts_zone_session`; this module +// re-exports them so the bus-side enrollment machine and the child-local +// ZoneLink handler cannot drift apart on the values. +pub use d2b_contracts_zone_session::v3::zone_session::{ + BOOTSTRAP_PSK_TTL_MS_DEFAULT, KK_SESSION_MAX_LIFETIME_MS_DEFAULT, +}; /// Frozen lower bound of the bootstrap PSK lifetime. pub const BOOTSTRAP_PSK_TTL_MS_MIN: u64 = 60_000; /// Frozen upper bound of the bootstrap PSK lifetime. pub const BOOTSTRAP_PSK_TTL_MS_MAX: u64 = 3_600_000; -/// Default maximum lifetime of one enrolled `Noise_KK` session. -pub const KK_SESSION_MAX_LIFETIME_MS_DEFAULT: u64 = 86_400_000; /// Frozen lower bound of the enrolled session lifetime. pub const KK_SESSION_MAX_LIFETIME_MS_MIN: u64 = 3_600_000; /// Frozen upper bound of the enrolled session lifetime. diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs index f9e52260a..292555d33 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs @@ -391,6 +391,26 @@ pub const ZONE_ENROLLMENT_PROTOCOL: &str = "d2b-zone-enrollment-v1"; /// Largest encoded Zone enrollment control payload one endpoint accepts. pub const MAX_ZONE_ENROLLMENT_PAYLOAD_BYTES: usize = 16 * 1024; +// --------------------------------------------------------------------------- +// ZoneLink cryptoperiod defaults +// --------------------------------------------------------------------------- + +/// Default absolute lifetime of one allocator-issued bootstrap PSK. +/// +/// The canonical definition shared by the child-local ZoneLink handler and the +/// bus-side enrollment machine; both re-export this constant rather than +/// restating it, so a cryptoperiod change cannot silently desynchronize the +/// two sides. +pub const BOOTSTRAP_PSK_TTL_MS_DEFAULT: u64 = 300_000; + +/// Default maximum lifetime of one enrolled `Noise_KK` session. +/// +/// The canonical definition shared by the child-local ZoneLink handler and the +/// bus-side enrollment machine; both re-export this constant rather than +/// restating it, so a cryptoperiod change cannot silently desynchronize the +/// two sides. +pub const KK_SESSION_MAX_LIFETIME_MS_DEFAULT: u64 = 86_400_000; + /// The exact link identity one Zone enrollment control payload names. /// /// These are comparison inputs, never authority: the authority is the diff --git a/packages/d2b-provider-zone-link/src/zone_links.rs b/packages/d2b-provider-zone-link/src/zone_links.rs index c3f98c54b..71beeca61 100644 --- a/packages/d2b-provider-zone-link/src/zone_links.rs +++ b/packages/d2b-provider-zone-link/src/zone_links.rs @@ -56,11 +56,12 @@ fn next_zone_link_handler_owner() -> u64 { } } -/// Default absolute lifetime of one allocator-issued bootstrap PSK. -pub const BOOTSTRAP_PSK_TTL_MS_DEFAULT: u64 = 300_000; - -/// Default maximum lifetime of one enrolled KK session. -pub const KK_SESSION_MAX_LIFETIME_MS_DEFAULT: u64 = 86_400_000; +// The cryptoperiod defaults live in `d2b_contracts_zone_session`; this module +// re-exports them so the child-local handler and the bus-side enrollment +// machine cannot drift apart on the values. +pub use d2b_contracts_zone_session::v3::zone_session::{ + BOOTSTRAP_PSK_TTL_MS_DEFAULT, KK_SESSION_MAX_LIFETIME_MS_DEFAULT, +}; /// Admission ceiling for `spec.limits.maxPendingIntents`. pub const MAX_PENDING_LOCAL_INTENTS: u32 = 1024; From 00aa879230d93000c8eed74019c3ba0aa012a645 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:30:46 -0700 Subject: [PATCH 564/726] host: drop dead NftBatch Deserialize derive, test parse dialect --- changelog.d/w4-13-nftbatch-no-deserialize.md | 3 + packages/d2b-host/src/nftables.rs | 191 ++++++++++++++++++- 2 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w4-13-nftbatch-no-deserialize.md diff --git a/changelog.d/w4-13-nftbatch-no-deserialize.md b/changelog.d/w4-13-nftbatch-no-deserialize.md new file mode 100644 index 000000000..790e21eaa --- /dev/null +++ b/changelog.d/w4-13-nftbatch-no-deserialize.md @@ -0,0 +1,3 @@ +### Fixed + +- `NftBatch` no longer derives `Deserialize`: its `&'static str` table fields pinned the generated impl to `'de: 'static`, so the derive could never deserialize runtime input and misled readers; batches are recovered via `NftBatch::parse` instead. \ No newline at end of file diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index e11bb0d4d..1559e2a0f 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -230,7 +230,12 @@ pub struct NftRule { /// The broker side reads this from the trusted bundle, renders it via /// [`NftBatch::render_nft_script`], and feeds the script to /// `nft -f -`. Foreign tables and chains are NEVER touched. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +/// +/// NOTE: intentionally NOT `Deserialize`. The `&'static str` fields +/// would pin the generated impl to `'de: 'static`, making it +/// unusable on any runtime input; batches are only ever constructed +/// or recovered via [`NftBatch::parse`]. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct NftBatch { pub table_family: &'static str, pub table_name: &'static str, @@ -1209,4 +1214,188 @@ mod tests { "handle/index are volatile and must not change the canonical digest" ); } + + /// Round-trip oracle for [`NftBatch::parse`]: a batch rendered by + /// [`NftBatch::render_nft_script`] MUST parse back to an equal + /// batch. This is the broker's apply→re-parse invariant. + #[test] + fn parse_roundtrips_rendered_script() { + let mut batch = build_inet_d2b_chains(); + batch + .add_usbip_carveout(&BusId::new("1-1.2")) + .expect("carveout"); + let script = batch.render_nft_script(); + let parsed = NftBatch::parse(&script).expect("rendered script parses"); + assert_eq!(parsed, batch); + } + + /// The minimal admissible script: an inline-closed empty table. + #[test] + fn parse_accepts_inline_empty_table() { + let batch = NftBatch::parse("table inet d2b {}").expect("inline empty table"); + assert_eq!(batch.table_family, "inet"); + assert_eq!(batch.table_name, "d2b"); + assert!(batch.chains.is_empty()); + } + + /// Valid script with the `policy` declaration on its own line + /// (the dialect also accepts policy inline on the `type` line, + /// exercised by [`parse_roundtrips_rendered_script`]), plus rule + /// comment parsing and `specific_carveout` inference. + #[test] + fn parse_accepts_valid_script_with_separate_policy_line() { + let script = r#"table inet d2b { + chain forward { + type filter hook forward priority -5; + policy drop; + ip saddr 10.0.0.1 accept comment "d2b managed: usbip-carveout-1-1.2" + drop comment "d2b managed: default-deny-forward" + } +} +"#; + let batch = NftBatch::parse(script).expect("valid script parses"); + assert_eq!(batch.table_family, "inet"); + assert_eq!(batch.table_name, "d2b"); + assert_eq!(batch.chains.len(), 1); + let forward = &batch.chains[0]; + assert_eq!(forward.name, "forward"); + assert_eq!(forward.hook, ChainHook::Forward); + assert_eq!(forward.priority, priority::FORWARD); + assert_eq!(forward.policy, ChainPolicy::Drop); + assert_eq!(forward.rules.len(), 2); + assert_eq!(forward.rules[0].expr, "ip saddr 10.0.0.1 accept"); + assert_eq!( + forward.rules[0].comment, + "d2b managed: usbip-carveout-1-1.2" + ); + assert!( + forward.rules[0].specific_carveout, + "usbip carve-out comment marks the rule specific" + ); + assert_eq!(forward.rules[1].expr, "drop"); + assert_eq!( + forward.rules[1].comment, + "d2b managed: default-deny-forward" + ); + assert!(!forward.rules[1].specific_carveout); + } + + /// Table-driven rejection coverage for [`NftBatch::parse`]: every + /// reachable `ParseNftScriptError` path surfaces as a + /// line-anchored detail. Rows assert the distinctive fragment of + /// the error detail so a regression pinpoints the exact dialect + /// rule that broke. + #[test] + fn parse_rejects_malformed_scripts() { + struct Case { + script: &'static str, + expected_fragment: &'static str, + } + let cases = [ + Case { + script: "", + expected_fragment: "missing `table inet d2b` header", + }, + Case { + script: "foo", + expected_fragment: "expected `table {` header", + }, + Case { + script: "table inet d2b\n", + expected_fragment: "malformed table header", + }, + Case { + script: "table {\n", + expected_fragment: "missing nft table family", + }, + Case { + script: "table inet {\n", + expected_fragment: "missing nft table name", + }, + Case { + script: "table inet d2b extra {\n", + expected_fragment: "malformed table header", + }, + Case { + script: "table ip d2b {\n}\n", + expected_fragment: "only `table inet d2b` is supported", + }, + Case { + script: "table inet other {\n}\n", + expected_fragment: "only `table inet d2b` is supported", + }, + Case { + script: "table inet d2b {\nchain forward {\n}\n}\n", + expected_fragment: "missing `type filter hook ... priority ...` declaration", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority -5;\n}\n}\n", + expected_fragment: "missing `policy ...;` declaration", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward\n}\n}\n", + expected_fragment: "unsupported chain header", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook nat priority -5;\n}\n}\n", + expected_fragment: "unsupported nft hook `nat`", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority abc;\n}\n}\n", + expected_fragment: "invalid hook priority", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority -5 policy reject;\n}\n}\n", + expected_fragment: "unsupported chain policy `reject`", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority -5;\npolicy drop accept;\n}\n}\n", + expected_fragment: "malformed policy line", + }, + Case { + script: "table inet d2b {\nfoo\n}\n", + expected_fragment: "expected `chain {` or `}`", + }, + Case { + script: "table inet d2b {\nchain forward\n}\n", + expected_fragment: "malformed chain header", + }, + Case { + script: "table inet d2b {\nchain {\n}\n}\n", + expected_fragment: "chain name must not be empty", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority -5;\naccept\n}\n}\n", + expected_fragment: "managed rule missing trailing `comment \"...\"`", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority -5;\naccept comment \"d2b managed: x\n}\n}\n", + expected_fragment: "unterminated nft rule comment", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority -5;\n", + expected_fragment: "unterminated chain `forward` block", + }, + Case { + script: "table inet d2b {\nchain forward {\ntype filter hook forward priority -5; policy drop;\n}\n", + expected_fragment: "unterminated `table inet d2b` block", + }, + Case { + script: "table inet d2b {\n}\nfoo\n", + expected_fragment: "unexpected content after table close", + }, + ]; + for case in cases { + let err = NftBatch::parse(case.script) + .expect_err("script must fail to parse") + .to_string(); + assert!( + err.contains(case.expected_fragment), + "script {s:?} error {e:?} missing fragment {f:?}", + s = case.script, + e = err, + f = case.expected_fragment + ); + } + } } From 6a8eed6cb03630b3084ad4420555ead3571f782a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:31:46 -0700 Subject: [PATCH 565/726] provider: remove shared-provider panics and enrich session warnings - SharedProviderDriverArgs holds a validated ZoneId instead of parsing (and panicking on) a String at driver construction; the device family crates and d2bd pass their ZoneId through directly. - key_ref returns Result instead of panicking on a non-canonical resource key; all callers propagate the error. - SharedProviderEffectRequest::envelope had no callers and cloned the spec and metadata; deleted. - Fixture::method returns Result and maps an unknown specified method to WireInvalid instead of hitting an unreachable arm. - Fake ports surface a full recorder as FakePortError::RecorderFull instead of swallowing the record error. - Provider session warnings carry zone and provider identity. - serve_component_session destructures the decoded request and moves its fields into dispatch instead of cloning them per frame. --- ...w4-05-provider-errors-and-observability.md | 15 ++++++ .../src/driver.rs | 7 +-- .../d2b-provider-device-usbip/src/driver.rs | 7 +-- .../integration/device_family.rs | 4 +- packages/d2b-provider-device/src/driver.rs | 4 +- .../tests/device_family.rs | 4 +- .../d2b-provider-network-local/src/driver.rs | 9 ++-- .../src/server/adapter.rs | 17 ++++--- .../src/server/session.rs | 9 ++-- .../src/shared_provider.rs | 23 +++------ .../d2b-provider-toolkit/src/testing/fakes.rs | 28 ++++++----- .../src/testing/fixture.rs | 36 +++++++------ .../d2b-provider-toolkit/src/testing/mod.rs | 2 +- packages/d2bd/src/resource_plane_v3.rs | 8 +-- packages/d2bd/src/shared_provider_effects.rs | 50 +++++++++---------- 15 files changed, 122 insertions(+), 101 deletions(-) create mode 100644 changelog.d/w4-05-provider-errors-and-observability.md diff --git a/changelog.d/w4-05-provider-errors-and-observability.md b/changelog.d/w4-05-provider-errors-and-observability.md new file mode 100644 index 000000000..2a4df8c05 --- /dev/null +++ b/changelog.d/w4-05-provider-errors-and-observability.md @@ -0,0 +1,15 @@ +### Fixed + +- The shared provider driver no longer panics when its construction zone is + invalid: the zone is now held as a validated `ZoneId` in the driver + arguments instead of being parsed (and panicking) at driver construction. +- `key_ref` no longer panics on a non-canonical resource key; it returns an + error that callers propagate instead. +- The toolkit fixture no longer panics on an unknown specified provider + method; it reports a wire-invalid error instead. +- The fake provider ports now surface a full recorder as + `FakePortError::RecorderFull` instead of silently dropping the record. +- Provider session warnings now carry the zone and provider identity instead + of being message-only. +- The provider adapter no longer clones the decoded request's zone, provider, + method, and payload on every frame; it moves them into dispatch. \ No newline at end of file diff --git a/packages/d2b-provider-device-security-key/src/driver.rs b/packages/d2b-provider-device-security-key/src/driver.rs index cd59570f0..7f3282cd9 100644 --- a/packages/d2b-provider-device-security-key/src/driver.rs +++ b/packages/d2b-provider-device-security-key/src/driver.rs @@ -170,7 +170,7 @@ pub trait SecurityKeyDriverEffects: Send + Sync + 'static { /// driver factory for one zone. pub struct SecurityKeyDriverArgs { /// The zone the driver serves. - pub zone: String, + pub zone: ZoneId, /// The controller generation every effect call binds (KTD7). pub controller_generation: ControllerGeneration, /// The daemon-supplied facet set the family's own effects @@ -199,7 +199,8 @@ impl SharedProviderFamily for SecurityKeyFamily { component: SecurityKeyComponent, spec: &Value, ) -> Result>, SharedProviderDeclarationError> { - let owner = key_ref(ctx.key()); + let owner = + key_ref(ctx.key()).map_err(|_| SharedProviderDeclarationError::SpecInvalid)?; match component { SecurityKeyComponent::Service => { let settings = spec @@ -544,7 +545,7 @@ mod tests { fn descriptors() -> [d2b_resource_types::DriverDescriptor; 2] { security_key_descriptors(SecurityKeyDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").expect("valid test zone"), controller_generation: d2b_contracts_resource::v3::ControllerGeneration::new(1) .expect("generation"), facets: crate::test_support::recording_facets(Arc::new( diff --git a/packages/d2b-provider-device-usbip/src/driver.rs b/packages/d2b-provider-device-usbip/src/driver.rs index aaffbf2da..5edd65c68 100644 --- a/packages/d2b-provider-device-usbip/src/driver.rs +++ b/packages/d2b-provider-device-usbip/src/driver.rs @@ -117,7 +117,7 @@ pub trait UsbipDriverEffects: Send + Sync + 'static { /// factory for one zone. pub struct UsbipDriverArgs { /// The zone the driver serves. - pub zone: String, + pub zone: ZoneId, /// The controller generation every effect call binds (KTD7). pub controller_generation: ControllerGeneration, /// The daemon-supplied facet set the family's own effects @@ -151,7 +151,8 @@ impl SharedProviderFamily for UsbipFamily { // it declares no manager child of its own. UsbipComponent::Service => Ok(None), UsbipComponent::Binding => { - let owner = key_ref(ctx.key()); + let owner = key_ref(ctx.key()) + .map_err(|_| SharedProviderDeclarationError::SpecInvalid)?; let zone = ZoneId::parse(ctx.key().zone.clone()) .map_err(|_| SharedProviderDeclarationError::SpecInvalid)?; let service_ref = spec_ref(spec, "/spec/serviceRef")?; @@ -337,7 +338,7 @@ mod tests { fn descriptors() -> [d2b_resource_types::DriverDescriptor; 2] { usbip_descriptors(UsbipDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").expect("valid test zone"), controller_generation: d2b_contracts_resource::v3::ControllerGeneration::new(1) .expect("generation"), facets: crate::test_support::recording_facets(Arc::new( diff --git a/packages/d2b-provider-device/integration/device_family.rs b/packages/d2b-provider-device/integration/device_family.rs index 33467ae95..c848b2953 100644 --- a/packages/d2b-provider-device/integration/device_family.rs +++ b/packages/d2b-provider-device/integration/device_family.rs @@ -8,7 +8,7 @@ use std::sync::Arc; -use d2b_contracts_resource::v3::ControllerGeneration; +use d2b_contracts_resource::v3::{ControllerGeneration, ZoneId}; use d2b_provider_device::{ DEVICE_REGISTRATIONS, DeviceComponent, DeviceDriverArgs, DeviceResourceState, device_descriptor, @@ -47,7 +47,7 @@ impl DeviceRuntime for UnavailableRuntime { #[test] fn the_device_type_registers_one_driver_over_four_provider_rows() { let descriptor = device_descriptor(DeviceDriverArgs { - zone: "integration".to_owned(), + zone: ZoneId::parse("integration").expect("valid test zone"), controller_generation: ControllerGeneration::new(1).expect("generation"), facets: DeviceEffectFacets { runtime: Arc::new(UnavailableRuntime), diff --git a/packages/d2b-provider-device/src/driver.rs b/packages/d2b-provider-device/src/driver.rs index c04704333..6397182a7 100644 --- a/packages/d2b-provider-device/src/driver.rs +++ b/packages/d2b-provider-device/src/driver.rs @@ -36,7 +36,7 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; use async_trait::async_trait; -use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ResourceUid}; +use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ResourceUid, ZoneId}; use d2b_provider_toolkit::{ ProviderRow, SharedProviderDeclarationError, SharedProviderDriverArgs, SharedProviderDriverFactory, SharedProviderEffectError, SharedProviderEffectOutcome, @@ -173,7 +173,7 @@ pub trait DeviceDriverEffects: Send + Sync + 'static { /// factory for one zone. pub struct DeviceDriverArgs { /// The zone the driver serves. - pub zone: String, + pub zone: ZoneId, /// The controller generation every effect call binds (KTD7). pub controller_generation: ControllerGeneration, /// The daemon-supplied facet set the family's own effects diff --git a/packages/d2b-provider-device/tests/device_family.rs b/packages/d2b-provider-device/tests/device_family.rs index 615629150..2794dfb30 100644 --- a/packages/d2b-provider-device/tests/device_family.rs +++ b/packages/d2b-provider-device/tests/device_family.rs @@ -10,7 +10,7 @@ use std::sync::Arc; use std::time::Duration; use async_trait::async_trait; -use d2b_contracts_resource::v3::ControllerGeneration; +use d2b_contracts_resource::v3::{ControllerGeneration, ZoneId}; use d2b_provider_device::{ DEVICE_REGISTRATIONS, DEVICE_RESYNC, DEVICE_TYPE_NAME, DeviceComponent, DeviceDriverArgs, device_descriptor, @@ -85,7 +85,7 @@ impl RequeueScheduler for RecordingRequeue { fn descriptor(runtime: Arc) -> d2b_resource_types::DriverDescriptor { device_descriptor(DeviceDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").expect("valid test zone"), controller_generation: ControllerGeneration::new(1).expect("generation"), facets: d2b_provider_device::test_support::recording_facets(runtime), }) diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index 1a179931d..eb401b584 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -30,7 +30,7 @@ use std::time::Duration; use async_trait::async_trait; use d2b_contracts_resource::v3::{ - ControllerGeneration, ResourceRef, ResourceUid, execution_policy::ExecutionPolicy, + ControllerGeneration, ResourceRef, ResourceUid, ZoneId, execution_policy::ExecutionPolicy, network::NetworkSpec, }; use d2b_provider_guest::GuestSpec; @@ -151,7 +151,7 @@ pub trait NetworkDriverEffects: Send + Sync + 'static { /// plus the zone-authority inputs every derived identity folds in (U14). pub struct NetworkDriverArgs { /// The zone the driver serves. - pub zone: String, + pub zone: ZoneId, /// The controller generation every effect call binds (KTD7). pub controller_generation: ControllerGeneration, /// The daemon-supplied facet set the family's effects implementation is @@ -183,7 +183,8 @@ impl SharedProviderFamily for NetworkFamily { ) -> Result>, SharedProviderDeclarationError> { match component { NetworkComponent::Network => { - let owner = key_ref(ctx.key()); + let owner = key_ref(ctx.key()) + .map_err(|_| SharedProviderDeclarationError::SpecInvalid)?; let uid = resource_uid(ctx.uid()).map_err(|_| SharedProviderDeclarationError::SpecInvalid)?; let spec = @@ -549,7 +550,7 @@ impl RequeueScheduler for RecordingRequeue { fn descriptor(runtime: Arc) -> d2b_resource_types::DriverDescriptor { network_descriptor(NetworkDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").expect("valid test zone"), controller_generation: d2b_contracts_resource::v3::ControllerGeneration::new(1) .expect("generation"), facets: recording_facets(runtime), diff --git a/packages/d2b-provider-toolkit/src/server/adapter.rs b/packages/d2b-provider-toolkit/src/server/adapter.rs index c83f90499..c92b526bf 100644 --- a/packages/d2b-provider-toolkit/src/server/adapter.rs +++ b/packages/d2b-provider-toolkit/src/server/adapter.rs @@ -330,17 +330,18 @@ where let request = codec.decode_request(&frame).inspect_err(|e| { warn!(zone = ?route.zone(), reason = %e, "provider frame decode failed; closing session"); })?; + let ProviderRequest { + request_id, + zone, + provider_ref, + method, + payload, + } = request; let response = self - .dispatch_for_route( - &route, - request.zone().clone(), - request.provider_ref().clone(), - request.method().clone(), - request.payload().clone(), - ) + .dispatch_for_route(&route, zone, provider_ref, method, payload) .await?; let encoded = codec - .encode_response(request.request_id(), &response) + .encode_response(&request_id, &response) .inspect_err(|e| { warn!(zone = ?route.zone(), reason = %e, "provider response encode failed; closing session"); })?; diff --git a/packages/d2b-provider-toolkit/src/server/session.rs b/packages/d2b-provider-toolkit/src/server/session.rs index 460b7907d..2ed6ca4e8 100644 --- a/packages/d2b-provider-toolkit/src/server/session.rs +++ b/packages/d2b-provider-toolkit/src/server/session.rs @@ -127,17 +127,17 @@ where if cancellation.is_cancelled() { return Ok(()); } + let route = session.route_binding(); let frame = tokio::select! { biased; _ = cancellation.cancelled() => return Ok(()), frame = session.receive_ttrpc() => { frame.map_err(|_| { - warn!("component session receive failed; closing provider session"); + warn!(zone = ?route.zone(), provider = ?route.provider_ref(), "component session receive failed; closing provider session"); ProviderToolkitError::SessionClosed })? } }; - let route = session.route_binding(); let request = codec.decode_request(&frame, &route).inspect_err(|e| { warn!(zone = ?route.zone(), reason = %e, "provider request decode failed; closing provider session"); })?; @@ -249,17 +249,18 @@ where S: ProviderService, C: AuthenticatedProviderFrameCodec, { + let route = session_admission.route().clone(); entrypoint .publish_authenticated_ready(®istration, session_admission, session) .map_err(|_| { - warn!("authenticated readiness publication failed; provider runtime will not serve"); + warn!(zone = ?route.zone(), provider = ?route.provider_ref(), "authenticated readiness publication failed; provider runtime will not serve"); ProviderRuntimeError::NotAccepting })?; let adapter = ProviderAgentAdapter::new(service); serve_authenticated_component_session(&adapter, session, codec, cancellation, now_tick) .await .map_err(|_| { - warn!("authenticated provider session loop failed"); + warn!(zone = ?route.zone(), provider = ?route.provider_ref(), "authenticated provider session loop failed"); ProviderRuntimeError::SessionLoopFailed }) } diff --git a/packages/d2b-provider-toolkit/src/shared_provider.rs b/packages/d2b-provider-toolkit/src/shared_provider.rs index 70deb9489..9511b5ff1 100644 --- a/packages/d2b-provider-toolkit/src/shared_provider.rs +++ b/packages/d2b-provider-toolkit/src/shared_provider.rs @@ -402,9 +402,9 @@ pub fn resource_uid(bytes: &[u8; 16]) -> Result ResourceRef { +pub fn key_ref(key: &ResourceKey) -> Result { ResourceRef::parse(&format!("{}/{}", key.type_name, key.name)) - .expect("manager keys carry canonical resource references") + .map_err(|_| SharedProviderEffectError::InvalidResource) } // --------------------------------------------------------------------------- @@ -521,14 +521,6 @@ impl SharedProviderEffectRequest<'_> { pub fn owner_ref(&self) -> Result { owner_ref(&self.metadata) } - - /// The old-shape owner-envelope document of one effect request. - pub fn envelope(&self) -> Value { - json!({ - "spec": self.spec.clone(), - "metadata": self.metadata.clone(), - }) - } } // --------------------------------------------------------------------------- @@ -538,7 +530,7 @@ impl SharedProviderEffectRequest<'_> { /// Construction arguments shared by every driver of one shared family. pub struct SharedProviderDriverArgs { /// The zone the family's rows live in. - pub zone: String, + pub zone: ZoneId, /// The controller generation every effect call binds (KTD7). pub controller_generation: ControllerGeneration, /// The family's declarations and typed Provider effect. @@ -612,9 +604,8 @@ impl { fn new(args: SharedProviderDriverArgs) -> Self { - let zone = ZoneId::parse(args.zone).expect("driver zone was validated at construction"); Self { - zone, + zone: args.zone, controller_generation: args.controller_generation, family: args.family, state: Arc::new(S::default()), @@ -1064,7 +1055,7 @@ mod tests { use std::time::Duration; use async_trait::async_trait; - use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef}; + use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ZoneId}; use d2b_resource_runtime::context::{ ChildEnsure, ManagerEndpoint, RequeueId, RequeueScheduler, ResourceContext, SpecDecoder, WatchId, WatchRegistration, @@ -1391,7 +1382,7 @@ mod tests { let family: Arc> = fixture.family.clone(); let factory = SharedProviderDriverFactory::new(SharedProviderDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").expect("valid test zone"), controller_generation: ControllerGeneration::new(1).expect("generation"), family, }); @@ -1403,7 +1394,7 @@ mod tests { #[test] fn factory_serves_the_declared_rows() { let factory = SharedProviderDriverFactory::new(SharedProviderDriverArgs { - zone: "dev".to_owned(), + zone: ZoneId::parse("dev").expect("valid test zone"), controller_generation: ControllerGeneration::new(1).expect("generation"), family: RecordingFamily::new( Arc::new(tokio::sync::Mutex::new(Vec::new())), diff --git a/packages/d2b-provider-toolkit/src/testing/fakes.rs b/packages/d2b-provider-toolkit/src/testing/fakes.rs index 2d390e61b..3d467b31c 100644 --- a/packages/d2b-provider-toolkit/src/testing/fakes.rs +++ b/packages/d2b-provider-toolkit/src/testing/fakes.rs @@ -272,9 +272,9 @@ impl FakeCoreClient { artifact_id: &ArtifactId, ) -> Result<&ProviderManifest, FakePortError> { self.faults.take_next()?; - let _ = self - .recorder - .record("resolve-artifact", BoundedToken::parse("catalog").unwrap()); + self.recorder + .record("resolve-artifact", BoundedToken::parse("catalog").unwrap()) + .map_err(|_| FakePortError::RecorderFull)?; self.catalog .get(artifact_id.as_str()) .ok_or(FakePortError::ArtifactNotFound) @@ -286,9 +286,9 @@ impl FakeCoreClient { provider_ref: &ResourceRef, ) -> Result<(), FakePortError> { self.faults.take_next()?; - let _ = self - .recorder - .record("resolve-provider-ref", BoundedToken::parse("row").unwrap()); + self.recorder + .record("resolve-provider-ref", BoundedToken::parse("row").unwrap()) + .map_err(|_| FakePortError::RecorderFull)?; let _ = provider_ref; if self.ready { Ok(()) @@ -334,9 +334,9 @@ impl FakeResourceStore { /// Write status for one resource, refusing an unowned ResourceType. pub fn write_status(&mut self, resource_ref: &ResourceRef) -> Result<(), FakePortError> { self.faults.take_next()?; - let _ = self - .recorder - .record("write-status", BoundedToken::parse("status").unwrap()); + self.recorder + .record("write-status", BoundedToken::parse("status").unwrap()) + .map_err(|_| FakePortError::RecorderFull)?; if self .owned .iter() @@ -388,10 +388,12 @@ impl FakeBus { /// Resolve one declared alias. pub fn resolve_alias(&mut self, alias: DependencyAlias) -> Result { self.faults.take_next()?; - let _ = self.recorder.record( - "resolve-alias", - BoundedToken::parse(alias.as_str()).expect("an alias token is a compiled constant"), - ); + self.recorder + .record( + "resolve-alias", + BoundedToken::parse(alias.as_str()).expect("an alias token is a compiled constant"), + ) + .map_err(|_| FakePortError::RecorderFull)?; self.bindings .get(&alias) .cloned() diff --git a/packages/d2b-provider-toolkit/src/testing/fixture.rs b/packages/d2b-provider-toolkit/src/testing/fixture.rs index 9cc217c51..26f06e9ac 100644 --- a/packages/d2b-provider-toolkit/src/testing/fixture.rs +++ b/packages/d2b-provider-toolkit/src/testing/fixture.rs @@ -127,16 +127,20 @@ impl Fixture { } else { let methods = fixture_methods() .into_iter() - .map(Self::method) + .map(|method| { + Self::method(method) + .map_err(|_| d2b_provider::RegistryBuildError::InvalidDescriptor) + }) .chain( ["health", "inspect", "observability"] .into_iter() .map(|method| { - ProviderMethodName::parse(method) - .expect("fixture observation methods are valid tokens") + ProviderMethodName::parse(method).map_err(|_| { + d2b_provider::RegistryBuildError::InvalidDescriptor + }) }), ) - .collect::>(); + .collect::, _>>()?; ProviderCapabilitySet::new(methods)? }; let descriptor = ProviderDescriptor::new( @@ -178,17 +182,19 @@ impl Fixture { } /// Return the canonical lower-kebab name for a closed v3 method. - pub fn method(method: SpecifiedProviderMethod) -> ProviderMethodName { - ProviderMethodName::parse(match method { + pub fn method( + method: SpecifiedProviderMethod, + ) -> Result { + let name = match method { SpecifiedProviderMethod::OpenTransport => "open-transport", SpecifiedProviderMethod::CloseTransport => "close-transport", SpecifiedProviderMethod::ObserveTransport => "observe-transport", SpecifiedProviderMethod::AssessUpdate => "assess-update", SpecifiedProviderMethod::PlanUpgrade => "plan-upgrade", SpecifiedProviderMethod::ExecuteUpgrade => "execute-upgrade", - _ => unreachable!("specified Provider method is closed"), - }) - .expect("closed Provider methods are valid bounded tokens") + _ => return Err(ProviderToolkitError::WireInvalid), + }; + ProviderMethodName::parse(name).map_err(|_| ProviderToolkitError::WireInvalid) } /// Derive authenticated session evidence for this fixture. @@ -383,11 +389,13 @@ impl ProviderAgentService for FakeProvider { request: ProviderAgentRequest, ) -> impl std::future::Future> + Send { - let method = Fixture::method(request.method()); - let result = self - .dispatch_method(&method, request.payload()) - .map(ProviderAgentResponse::new) - .map_err(|_| ProviderAgentError::HandlerFailed); + let result = Fixture::method(request.method()) + .map_err(|_| ProviderAgentError::HandlerFailed) + .and_then(|method| { + self.dispatch_method(&method, request.payload()) + .map(ProviderAgentResponse::new) + .map_err(|_| ProviderAgentError::HandlerFailed) + }); ready(result) } } diff --git a/packages/d2b-provider-toolkit/src/testing/mod.rs b/packages/d2b-provider-toolkit/src/testing/mod.rs index 38f3c615a..1c3dae53f 100644 --- a/packages/d2b-provider-toolkit/src/testing/mod.rs +++ b/packages/d2b-provider-toolkit/src/testing/mod.rs @@ -527,7 +527,7 @@ impl TestHarness

{ /// /// The clock is the harness's own, so a test advances time explicitly /// instead of waiting for it. - pub fn clock(&self) -> &Arc { + pub fn clock(&self) -> &DeterministicClock { &self.clock } diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 19fcbe8ee..a9080a82b 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -2851,7 +2851,7 @@ impl ResourcePlaneV3 { // The Network family: the driver builds its effects from the // declared facets; no externally built port appears here (R2). "network-local" => vec![network_descriptor(NetworkDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), controller_generation: inputs.authority.controller_generation, facets: inputs.network_facets.clone(), })], @@ -2917,17 +2917,17 @@ impl ResourcePlaneV3 { // two USB and two security-key types through their own // declarations. "device-usbip" => Vec::from(usbip_descriptors(UsbipDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), controller_generation: inputs.authority.controller_generation, facets: inputs.usbip_facets.clone(), })), "device-security-key" => Vec::from(security_key_descriptors(SecurityKeyDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), controller_generation: inputs.authority.controller_generation, facets: inputs.security_key_facets.clone(), })), "device" => vec![device_descriptor(DeviceDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), controller_generation: inputs.authority.controller_generation, facets: inputs.device_facets.clone(), })], diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 5e4084528..9c7c5e4b2 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -1057,7 +1057,7 @@ impl ProductionSharedProviderEffects { .cloned() .ok_or(SharedProviderEffectError::Unavailable)?; let network_generation = request.generation; - let network_ref = key_ref(&request.target).to_canonical_string(); + let network_ref = key_ref(&request.target)?.to_canonical_string(); let mut guest_uids = Vec::with_capacity(spec.attachments().len()); let mut attachment_generation = network_generation.get(); for attachment in spec.attachments() { @@ -1526,7 +1526,7 @@ impl ProductionSharedProviderEffects { let fence = self .network_content_fence(SharedProviderKind::Network, &runtime, request, &admission) .await?; - let owner_ref = key_ref(&request.target).clone(); + let owner_ref = key_ref(&request.target)?; let children = NetworkChildPort::new(self, request, owner_ref, request.uid.clone(), fence); let readiness = children .readiness() @@ -1590,13 +1590,13 @@ impl ProductionSharedProviderEffects { let holder = request.owner_ref()?; if holder.resource_type().as_str() != "Guest" { tracing::warn!( - device = %key_ref(&request.target).to_canonical_string(), + device = %key_ref(&request.target)?.to_canonical_string(), owner = %holder.to_canonical_string(), "TPM device reconcile refused: the Device is not owned by a Guest", ); return Err(SharedProviderEffectError::InvalidResource); } - let device_ref = key_ref(&request.target).clone(); + let device_ref = key_ref(&request.target)?; let runtime = self.runtime().inspect_err(|_| { tracing::warn!( device = %device_ref.to_canonical_string(), @@ -1635,7 +1635,7 @@ impl ProductionSharedProviderEffects { Some(controller) => controller, None => d2b_provider_device_tpm::TpmResourceController::new( request.uid.clone(), - key_ref(&request.target).clone(), + key_ref(&request.target)?, execution_ref.clone(), ) .map_err(|_| SharedProviderEffectError::InvalidResource)?, @@ -1655,7 +1655,7 @@ impl ProductionSharedProviderEffects { decision, d2b_provider_device_tpm::effects_service::AdmittedTpmDevice::from_row( request.uid.clone(), - key_ref(&request.target).clone(), + key_ref(&request.target)?, self.zone.as_str(), execution_ref, request.operation_id.clone(), @@ -1667,7 +1667,7 @@ impl ProductionSharedProviderEffects { .map_err(|error| { tracing::warn!( error = ?error, - device = %key_ref(&request.target).to_canonical_string(), + device = %key_ref(&request.target)?.to_canonical_string(), "TPM device controller reconcile failed", ); SharedProviderEffectError::Unavailable @@ -1732,7 +1732,7 @@ impl ProductionSharedProviderEffects { ) .await .map_err(|_| SharedProviderEffectError::Unavailable)?; - let device_ref = key_ref(&request.target).to_canonical_string(); + let device_ref = key_ref(&request.target)?.to_canonical_string(); let ready = services.iter().any(|service| { service.pointer("/spec/providerRef").and_then(Value::as_str) == Some(d2b_provider_device_usbip::PROVIDER_REF) @@ -1868,14 +1868,14 @@ impl ProductionSharedProviderEffects { .map_err(|_| SharedProviderEffectError::InvalidResource)?; let mut controller = d2b_provider_device_usbip::UsbipBindingController::new_admitted( - &key_ref(&request.target), + &key_ref(&request.target)?, &service_ref, &guest_ref, admission, ) .map_err(|_| SharedProviderEffectError::InvalidResource)?; let desired = d2b_provider_device_usbip::binding_child_resources( - &key_ref(&request.target), + &key_ref(&request.target)?, &service_ref, &guest_ref, ) @@ -2091,14 +2091,14 @@ impl ProductionSharedProviderEffects { .and_then(|value| ResourceRef::parse(value).ok()) { d2b_provider_device_security_key::SecurityKeyController::child_resources_for_user( - &key_ref(&request.target), + &key_ref(&request.target)?, &service_ref, &target_ref, &user_ref, ) } else { d2b_provider_device_security_key::SecurityKeyController::child_resources( - &key_ref(&request.target), + &key_ref(&request.target)?, &service_ref, &target_ref, ) @@ -2168,7 +2168,7 @@ impl ProductionSharedProviderEffects { request.children, ), self.zone.as_str().to_owned(), - key_ref(&request.target).clone(), + key_ref(&request.target)?, request.uid.clone(), holder_ref, request.generation, @@ -2228,7 +2228,7 @@ impl ProductionSharedProviderEffects { ) .map_err(|_| SharedProviderEffectError::InvalidResource)?; let mut controller = d2b_provider_device_usbip::UsbipBindingController::new( - &key_ref(&request.target), + &key_ref(&request.target)?, &service_ref, &guest_ref, ) @@ -2243,7 +2243,7 @@ impl ProductionSharedProviderEffects { &self, request: &SharedProviderEffectRequest<'_>, ) -> Result { - let device_ref = key_ref(&request.target).to_canonical_string(); + let device_ref = key_ref(&request.target)?.to_canonical_string(); let runtime = self.runtime()?; let children = runtime .committed_resources_of_type(d2b_provider_device_usbip::USB_SERVICE_RESOURCE_TYPE) @@ -2267,7 +2267,7 @@ impl ProductionSharedProviderEffects { request: &SharedProviderEffectRequest<'_>, ) -> Result { let runtime = self.runtime()?; - let service_ref = key_ref(&request.target).to_canonical_string(); + let service_ref = key_ref(&request.target)?.to_canonical_string(); let bindings = runtime .committed_resources_of_type( d2b_provider_device_security_key::SECURITY_KEY_BINDING_RESOURCE_TYPE, @@ -2289,7 +2289,7 @@ impl ProductionSharedProviderEffects { request: &SharedProviderEffectRequest<'_>, ) -> Result { let runtime = self.runtime()?; - let device_ref = key_ref(&request.target).to_canonical_string(); + let device_ref = key_ref(&request.target)?.to_canonical_string(); let services = runtime .committed_resources_of_type( d2b_provider_device_security_key::SECURITY_KEY_SERVICE_RESOURCE_TYPE, @@ -2347,7 +2347,7 @@ impl ProductionSharedProviderEffects { zone: &ZoneId, ) -> Result { for intent in desired.iter() { - if *intent.owner_ref() != key_ref(owner) || zone.as_str() != self.zone.as_str() { + if *intent.owner_ref() != key_ref(owner)? || zone.as_str() != self.zone.as_str() { return Err(SharedProviderEffectError::InvalidResource); } if !self.resource_ready(intent.resource_ref()).await { @@ -2377,7 +2377,7 @@ impl ProductionSharedProviderEffects { let fence = self .network_content_fence(SharedProviderKind::Network, &runtime, request, &admission) .await?; - let owner_ref = key_ref(&request.target).clone(); + let owner_ref = key_ref(&request.target)?; let children = NetworkChildPort::new(self, request, owner_ref, request.uid.clone(), fence); let volume = children .current(&children.volume_ref) @@ -2512,7 +2512,7 @@ impl ProductionSharedProviderEffects { let decision = runtime .tpm_device_is_admitted( &request.uid, - &key_ref(&request.target), + &key_ref(&request.target)?, vm_id.as_str(), &request.operation_id, None, @@ -2540,7 +2540,7 @@ impl ProductionSharedProviderEffects { decision, d2b_provider_device_tpm::effects_service::AdmittedTpmDevice::from_row( request.uid.clone(), - key_ref(&request.target).clone(), + key_ref(&request.target)?, self.zone.as_str(), execution_ref, request.operation_id.clone(), @@ -2561,7 +2561,7 @@ impl ProductionSharedProviderEffects { } tracing::warn!( error = ?error, - device = %key_ref(&request.target).to_canonical_string(), + device = %key_ref(&request.target)?.to_canonical_string(), "TPM device controller finalize failed", ); Err(SharedProviderEffectError::Unavailable) @@ -2574,7 +2574,7 @@ impl ProductionSharedProviderEffects { request: &SharedProviderEffectRequest<'_>, ) -> Result { let runtime = self.runtime()?; - let service_ref = key_ref(&request.target).to_canonical_string(); + let service_ref = key_ref(&request.target)?.to_canonical_string(); let bindings = runtime .committed_resources_of_type(d2b_provider_device_usbip::USB_BINDING_RESOURCE_TYPE) .await @@ -2634,7 +2634,7 @@ impl ProductionSharedProviderEffects { request.children, ), self.zone.as_str().to_owned(), - key_ref(&request.target).clone(), + key_ref(&request.target)?, request.uid.clone(), admission.owner().holder_ref().clone(), admission.owner().generation(), @@ -2644,7 +2644,7 @@ impl ProductionSharedProviderEffects { let result = controller.finalize_lifecycle(&mut port).map_err(|error| { tracing::debug!( error = ?error, - device = %key_ref(&request.target).to_canonical_string(), + device = %key_ref(&request.target)?.to_canonical_string(), "GPU lifecycle finalize failed", ); SharedProviderEffectError::Unavailable From b56a46c1ef4f88e14a8bccda3b2450819b230836 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:33:09 -0700 Subject: [PATCH 566/726] provider-notification: type the str error family as ProviderError --- changelog.d/w4-10-provider-error-enum.md | 7 + .../src/controller.rs | 182 +++++++++--------- .../src/error.rs | 147 +++++++++++++- .../src/guest_source.rs | 26 +-- .../src/lifecycle.rs | 53 ++--- .../src/metrics.rs | 10 +- .../src/runtime.rs | 16 +- .../src/test_support.rs | 5 +- .../tests/notification_lifecycle.rs | 17 +- .../tests/provider_behavior.rs | 8 +- .../tests/redaction.rs | 4 +- packages/d2bd/src/interaction_composition.rs | 60 +++--- 12 files changed, 347 insertions(+), 188 deletions(-) create mode 100644 changelog.d/w4-10-provider-error-enum.md diff --git a/changelog.d/w4-10-provider-error-enum.md b/changelog.d/w4-10-provider-error-enum.md new file mode 100644 index 000000000..8256aa38a --- /dev/null +++ b/changelog.d/w4-10-provider-error-enum.md @@ -0,0 +1,7 @@ +### Fixed + +- The notification-desktop provider now returns the typed `ProviderError` + enum instead of `&'static str` reason codes from its public constructors, + validators, reconciliation methods, and the source-process and lifecycle + effect-port traits, so callers can match failures without string + comparison. The stable error slugs are unchanged. \ No newline at end of file diff --git a/packages/d2b-provider-notification-desktop/src/controller.rs b/packages/d2b-provider-notification-desktop/src/controller.rs index 202265eae..a0a61d7e8 100644 --- a/packages/d2b-provider-notification-desktop/src/controller.rs +++ b/packages/d2b-provider-notification-desktop/src/controller.rs @@ -4,7 +4,7 @@ use crate::SessionEvidence; use tracing::{debug, warn}; use crate::{ NotificationHostSinkIdentity, NotificationLifecyclePlan, NotificationLifecycleReceipt, - NotificationSourceIdentity, + NotificationSourceIdentity, ProviderError, }; use d2b_contracts_resource::v3::identity::{EvidenceClass, Locality}; use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; @@ -102,10 +102,10 @@ impl DisplayDependencyEvidence { /// Project authenticated Ready evidence from the display route. pub fn from_authenticated_route( route: AuthenticatedSessionRouteBinding, - ) -> Result { + ) -> Result { let provider_generation = route .provider_generation() - .ok_or("display-dependency-unauthenticated")? + .ok_or(ProviderError::DisplayDependencyUnauthenticated)? .get(); Self::from_route(route, DisplayDependencyState::Ready, provider_generation) } @@ -116,19 +116,19 @@ impl DisplayDependencyEvidence { pub fn from_daemon_route( route: AuthenticatedSessionRouteBinding, user_ref: ResourceRef, - ) -> Result { + ) -> Result { let provider_generation = route .provider_generation() - .ok_or("display-dependency-unauthenticated")? + .ok_or(ProviderError::DisplayDependencyUnauthenticated)? .get(); let Some(provider) = route.provider_ref() else { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); }; let Some(host_execution_ref) = route.context().execution_ref() else { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); }; let Some(controller_generation) = route.controller_generation() else { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); }; if provider.to_canonical_string() != DISPLAY_PROVIDER_REF || route.service().as_str() != DISPLAY_SERVICE_PACKAGE @@ -141,7 +141,7 @@ impl DisplayDependencyEvidence { || route.reconnect_generation().get() == 0 || controller_generation.get() == 0 { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); } Ok(Self { provider_ref: provider.clone(), @@ -160,9 +160,9 @@ impl DisplayDependencyEvidence { route: AuthenticatedSessionRouteBinding, state: DisplayDependencyState, generation: u64, - ) -> Result { + ) -> Result { let Some(provider) = route.provider_ref() else { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); }; if route.service().as_str() != DISPLAY_SERVICE_PACKAGE || route.evidence_class() != EvidenceClass::UnixPeer @@ -175,17 +175,17 @@ impl DisplayDependencyEvidence { .provider_generation() .is_none_or(|observed| observed.get() != generation) { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); } let Some(host_execution_ref) = route.context().execution_ref() else { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); }; let Some(controller_generation) = route.controller_generation() else { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); }; if host_execution_ref.resource_type().as_str() != "Host" || controller_generation.get() == 0 { - return Err("display-dependency-unauthenticated"); + return Err(ProviderError::DisplayDependencyUnauthenticated); } Ok(Self { provider_ref: provider.clone(), @@ -306,13 +306,13 @@ impl GuestSourceConfig { source_ref: ResourceRef, zone: ZoneId, categories: impl IntoIterator, - ) -> Result { + ) -> Result { if source_ref.resource_type().as_str() != "Guest" { - return Err("notification-source-ref-invalid"); + return Err(ProviderError::SourceRefInvalid); } let categories = categories.into_iter().collect::>(); if categories.is_empty() { - return Err("notification-category-set-empty"); + return Err(ProviderError::CategorySetEmpty); } Ok(Self { source_ref, @@ -365,14 +365,14 @@ pub struct NotificationProviderConfig { impl NotificationProviderConfig { /// Validate bounded, unique Guest source configuration. - pub fn new(guest_sources: Vec) -> Result { + pub fn new(guest_sources: Vec) -> Result { if guest_sources.len() > MAX_GUEST_SOURCES { - return Err("notification-source-capacity"); + return Err(ProviderError::SourceCapacity); } let mut seen = BTreeSet::new(); for source in &guest_sources { if !seen.insert(source.source_ref.clone()) { - return Err("notification-source-duplicate"); + return Err(ProviderError::SourceDuplicate); } } Ok(Self { @@ -415,11 +415,11 @@ impl NotificationProviderConfig { pub fn with_max_pending_notifications( mut self, max_pending_notifications: usize, - ) -> Result { + ) -> Result { if !(MIN_MAX_PENDING_NOTIFICATIONS..=MAX_MAX_PENDING_NOTIFICATIONS) .contains(&max_pending_notifications) { - return Err("notification-pending-capacity"); + return Err(ProviderError::PendingCapacity); } self.max_pending_notifications = max_pending_notifications; Ok(self) @@ -434,10 +434,10 @@ impl NotificationProviderConfig { pub fn with_action_nonce_ttl_secs( mut self, action_nonce_ttl_secs: u64, - ) -> Result { + ) -> Result { if !(MIN_ACTION_NONCE_TTL_SECS..=MAX_ACTION_NONCE_TTL_SECS).contains(&action_nonce_ttl_secs) { - return Err("notification-action-nonce-ttl"); + return Err(ProviderError::ActionNonceTtl); } self.action_nonce_ttl_secs = action_nonce_ttl_secs; Ok(self) @@ -452,11 +452,11 @@ impl NotificationProviderConfig { pub fn with_action_nonce_store_size( mut self, action_nonce_store_size: usize, - ) -> Result { + ) -> Result { if !(MIN_ACTION_NONCE_STORE_SIZE..=MAX_ACTION_NONCE_STORE_SIZE) .contains(&action_nonce_store_size) { - return Err("notification-action-nonce-capacity"); + return Err(ProviderError::ActionNonceCapacity); } self.action_nonce_store_size = action_nonce_store_size; Ok(self) @@ -471,11 +471,11 @@ impl NotificationProviderConfig { pub fn with_acknowledge_timeout_secs( mut self, acknowledge_timeout_secs: u64, - ) -> Result { + ) -> Result { if !(MIN_ACKNOWLEDGE_TIMEOUT_SECS..=MAX_ACKNOWLEDGE_TIMEOUT_SECS) .contains(&acknowledge_timeout_secs) { - return Err("notification-acknowledge-timeout"); + return Err(ProviderError::AcknowledgeTimeout); } self.acknowledge_timeout_secs = acknowledge_timeout_secs; Ok(self) @@ -490,12 +490,12 @@ impl NotificationProviderConfig { pub fn with_display_wayland_ref( mut self, display_wayland_ref: Option, - ) -> Result { + ) -> Result { if display_wayland_ref .as_ref() .is_some_and(|provider| provider.to_canonical_string() != DISPLAY_PROVIDER_REF) { - return Err("notification-display-provider-invalid"); + return Err(ProviderError::DisplayProviderInvalid); } self.display_wayland_ref = display_wayland_ref; Ok(self) @@ -511,11 +511,11 @@ impl NotificationProviderConfig { mut self, host_execution_ref: ResourceRef, host_user_ref: ResourceRef, - ) -> Result { + ) -> Result { if host_execution_ref.resource_type().as_str() != "Host" || host_user_ref.resource_type().as_str() != "User" { - return Err("notification-host-binding-invalid"); + return Err(ProviderError::HostBindingInvalid); } self.host_execution_ref = Some(host_execution_ref); self.host_user_ref = Some(host_user_ref); @@ -554,7 +554,7 @@ pub struct SourceReconcileResult { pub stop_endpoints: Vec, display_fingerprint: [u8; 32], host_sink_fingerprint: [u8; 32], - source_error: Option<&'static str>, + source_error: Option, } impl SourceReconcileResult { @@ -582,7 +582,7 @@ impl SourceReconcileResult { digest.update(self.display_fingerprint); digest.update(self.host_sink_fingerprint); if let Some(error) = self.source_error { - digest.update(error.as_bytes()); + digest.update(error.as_str().as_bytes()); } let bytes = digest.finalize(); let mut result = [0; 32]; @@ -629,9 +629,9 @@ impl SourceProcessEffectReceipt { plan: &SourceReconcileResult, lifecycle: &NotificationLifecyclePlan, receipt: &NotificationLifecycleReceipt, - ) -> Result { + ) -> Result { if !receipt.matches(lifecycle) { - return Err("notification-supervisor-receipt-mismatch"); + return Err(ProviderError::SupervisorReceiptMismatch); } Ok(Self::complete(plan)) } @@ -697,13 +697,13 @@ impl SourceProcessEffectReceipt { && self.acknowledgements == Self::expected_acknowledgements(plan) } - fn no_effects(plan: &SourceReconcileResult) -> Result { + fn no_effects(plan: &SourceReconcileResult) -> Result { if !plan.start_endpoints.is_empty() || !plan.stop_endpoints.is_empty() || plan.start_host_sink || plan.stop_host_sink { - return Err("notification-process-effect-incomplete"); + return Err(ProviderError::ProcessEffectIncomplete); } Ok(Self { plan_digest: plan.digest(), @@ -769,10 +769,10 @@ impl SourceProcessEffectReceiptBuilder { } /// Finish the receipt only when every planned effect was acknowledged. - fn finish(mut self) -> Result { + fn finish(mut self) -> Result { self.acknowledgements.sort(); if self.acknowledgements != self.expected { - return Err("notification-process-effect-incomplete"); + return Err(ProviderError::ProcessEffectIncomplete); } Ok(SourceProcessEffectReceipt { plan_digest: self.plan_digest, @@ -792,7 +792,7 @@ pub trait SourceProcessEffectPort { &mut self, plan: &SourceReconcileResult, lifecycle: &NotificationLifecyclePlan, - ) -> Result; + ) -> Result; } /// Authenticated Guest source endpoint evidence. @@ -810,20 +810,20 @@ impl SourceEndpoint { source: &GuestSourceConfig, session: &SessionEvidence, display: &DisplayDependencyEvidence, - ) -> Result { + ) -> Result { session.admit_source().map_err(|_| { debug!( provider = "notification-desktop", "source endpoint construction refused: session not authenticated as a source" ); - "notification-source-unauthenticated" + ProviderError::SourceUnauthenticated })?; if session.subject_ref() != source.source_ref() || session.zone() != source.zone() { debug!( provider = "notification-desktop", "source endpoint construction refused: session binding mismatch" ); - return Err("notification-source-binding-mismatch"); + return Err(ProviderError::SourceBindingMismatch); } let mut digest = Sha256::new(); digest.update(source.source_ref().to_canonical_string().as_bytes()); @@ -927,21 +927,21 @@ pub struct NotificationController { impl NotificationController { /// Construct a controller for one exact Provider instance. - pub fn new(provider_ref: impl AsRef) -> Result { + pub fn new(provider_ref: impl AsRef) -> Result { let provider_ref = ResourceRef::parse(provider_ref.as_ref()).map_err(|error| { warn!( provider = "notification-desktop", error = %error, "notification controller construction refused: provider reference invalid" ); - "notification-provider-ref-invalid" + ProviderError::ProviderRefInvalid })?; if provider_ref.to_canonical_string() != crate::PROVIDER_REF { warn!( provider = "notification-desktop", "notification controller construction refused: provider reference mismatch" ); - return Err("notification-provider-ref-invalid"); + return Err(ProviderError::ProviderRefInvalid); } Ok(Self { provider_ref, @@ -957,28 +957,28 @@ impl NotificationController { &self, display: &DisplayDependencyEvidence, config: &NotificationProviderConfig, - ) -> Result, &'static str> { + ) -> Result, ProviderError> { let host_execution_ref = config .host_execution_ref() - .ok_or("notification-host-binding-missing")?; + .ok_or(ProviderError::HostBindingMissing)?; let host_user_ref = config.host_user_ref(); if display.host_execution_ref() != host_execution_ref || (config.dbus_sink_enabled() && host_user_ref.is_none_or(|user| display.user_ref() != user)) { - return Err("notification-host-binding-mismatch"); + return Err(ProviderError::HostBindingMismatch); } if config.dbus_sink_enabled() && config.display_wayland_ref() != Some(display.provider_ref()) { - return Err("notification-display-provider-mismatch"); + return Err(ProviderError::DisplayProviderMismatch); } if config .guest_sources() .iter() .any(|source| source.zone() != display.zone()) { - return Err("notification-source-zone-mismatch"); + return Err(ProviderError::SourceZoneMismatch); } let mut plans = vec![ProcessPlan { template: "notification-desktop-controller", @@ -990,7 +990,7 @@ impl NotificationController { observer_enabled: false, }]; if config.dbus_sink_enabled() && display.is_ready() { - let host_user_ref = host_user_ref.ok_or("notification-host-binding-missing")?; + let host_user_ref = host_user_ref.ok_or(ProviderError::HostBindingMissing)?; plans.push(ProcessPlan { template: "notification-desktop-host-sink", domain: "user", @@ -1022,7 +1022,7 @@ impl NotificationController { display: &DisplayDependencyEvidence, config: &NotificationProviderConfig, source_sessions: &[SessionEvidence], - ) -> Result { + ) -> Result { let result = match self.plan_reconciliation(display, config, source_sessions) { Ok(result) => result, Err(error) => { @@ -1043,7 +1043,7 @@ impl NotificationController { config: &NotificationProviderConfig, source_sessions: &[SessionEvidence], effects: &mut E, - ) -> Result { + ) -> Result { let result = match self.plan_reconciliation(display, config, source_sessions) { Ok(result) => result, Err(error) => { @@ -1053,7 +1053,7 @@ impl NotificationController { }; let receipt = self.apply_with_effects(Some(display), config, &result, effects)?; if !receipt.matches(&result) { - return Err("notification-process-effect-proof-mismatch"); + return Err(ProviderError::ProcessEffectProofMismatch); } let source_error = result.source_error; self.commit_reconciliation(display, config, &result)?; @@ -1065,7 +1065,7 @@ impl NotificationController { display: &DisplayDependencyEvidence, config: &NotificationProviderConfig, source_sessions: &[SessionEvidence], - ) -> Result { + ) -> Result { self.plan(display, config)?; let mut endpoints = Vec::new(); let mut source_error = None; @@ -1075,11 +1075,11 @@ impl NotificationController { .iter() .filter(|session| session.subject_ref() == source.source_ref()); let Some(session) = matches.next() else { - source_error.get_or_insert("notification-source-unauthenticated"); + source_error.get_or_insert(ProviderError::SourceUnauthenticated); continue; }; if matches.next().is_some() { - source_error.get_or_insert("notification-source-ambiguous"); + source_error.get_or_insert(ProviderError::SourceAmbiguous); continue; } match SourceEndpoint::from_authenticated(source, session, display) { @@ -1180,11 +1180,11 @@ impl NotificationController { &mut self, config: &NotificationProviderConfig, effects: &mut E, - ) -> Result<(), &'static str> { + ) -> Result<(), ProviderError> { let result = self.drain_plan(); let receipt = self.apply_with_effects(None, config, &result, effects)?; if !receipt.matches(&result) { - return Err("notification-process-effect-proof-mismatch"); + return Err(ProviderError::ProcessEffectProofMismatch); } self.clear_reconciliation(); Ok(()) @@ -1193,7 +1193,7 @@ impl NotificationController { fn source_lifecycle_identity( &self, endpoint: &SourceEndpoint, - ) -> Result { + ) -> Result { NotificationSourceIdentity::new( endpoint.zone().clone(), self.provider_ref.clone(), @@ -1208,17 +1208,17 @@ impl NotificationController { &self, display: &DisplayDependencyEvidence, config: &NotificationProviderConfig, - ) -> Result { + ) -> Result { NotificationHostSinkIdentity::new( display.zone().clone(), self.provider_ref.clone(), config .host_execution_ref() - .ok_or("notification-host-binding-missing")? + .ok_or(ProviderError::HostBindingMissing)? .clone(), config .host_user_ref() - .ok_or("notification-host-binding-missing")? + .ok_or(ProviderError::HostBindingMissing)? .clone(), display.provider_ref().clone(), display.generation(), @@ -1231,7 +1231,7 @@ impl NotificationController { display: Option<&DisplayDependencyEvidence>, config: &NotificationProviderConfig, result: &SourceReconcileResult, - ) -> Result, &'static str> { + ) -> Result, ProviderError> { if result.start_endpoints.is_empty() && result.stop_endpoints.is_empty() && !result.start_host_sink @@ -1253,7 +1253,7 @@ impl NotificationController { .start_host_sink .then(|| { self.host_sink_identity( - display.ok_or("notification-display-dependency-unavailable")?, + display.ok_or(ProviderError::DisplayDependencyUnavailable)?, config, ) }) @@ -1263,7 +1263,7 @@ impl NotificationController { .then(|| { self.active_host_sink .clone() - .ok_or("notification-lifecycle-host-sink-missing") + .ok_or(ProviderError::LifecycleHostSinkMissing) }) .transpose()?; let zone = display @@ -1271,7 +1271,7 @@ impl NotificationController { .or_else(|| start_sources.first().map(|source| source.zone().clone())) .or_else(|| stop_sources.first().map(|source| source.zone().clone())) .or_else(|| stop_host_sink.as_ref().map(|sink| sink.zone().clone())) - .ok_or("notification-lifecycle-zone-unavailable")?; + .ok_or(ProviderError::LifecycleZoneUnavailable)?; Ok(Some(NotificationLifecyclePlan::new( zone, self.provider_ref.clone(), @@ -1288,7 +1288,7 @@ impl NotificationController { config: &NotificationProviderConfig, result: &SourceReconcileResult, effects: &mut E, - ) -> Result { + ) -> Result { match self.lifecycle_plan(display, config, result)? { Some(lifecycle) => effects.apply(result, &lifecycle), None => SourceProcessEffectReceipt::no_effects(result), @@ -1300,7 +1300,7 @@ impl NotificationController { display: &DisplayDependencyEvidence, config: &NotificationProviderConfig, result: &SourceReconcileResult, - ) -> Result<(), &'static str> { + ) -> Result<(), ProviderError> { for source in &result.stop { self.active_sources.remove(source); } @@ -1329,12 +1329,12 @@ impl NotificationController { config: &NotificationProviderConfig, source_sessions: &[SessionEvidence], effects: &mut E, - ) -> Result { + ) -> Result { let Some(proof) = display else { let result = self.drain_plan(); let receipt = self.apply_with_effects(None, config, &result, effects)?; if !receipt.matches(&result) { - return Err("notification-process-effect-proof-mismatch"); + return Err(ProviderError::ProcessEffectProofMismatch); } self.clear_reconciliation(); return Ok(result); @@ -1357,19 +1357,19 @@ impl NotificationController { config: &NotificationProviderConfig, source_sessions: &[SessionEvidence], effects: &mut E, - ) -> Result { + ) -> Result { let Some(proof) = display else { let result = self.drain_plan(); let receipt = self.apply_with_effects(None, config, &result, effects)?; if !receipt.matches(&result) { - return Err("notification-process-effect-proof-mismatch"); + return Err(ProviderError::ProcessEffectProofMismatch); } self.clear_reconciliation(); return Ok(result); }; let user_ref = config .host_user_ref() - .ok_or("notification-host-binding-missing")? + .ok_or(ProviderError::HostBindingMissing)? .clone(); let evidence = match DisplayDependencyEvidence::from_daemon_route(proof, user_ref) { Ok(evidence) => evidence, @@ -1468,7 +1468,7 @@ mod tests { let wrong_zone_config = bound_config(vec![wrong_zone]); assert_eq!( controller.plan(&display(DisplayDependencyState::Ready), &wrong_zone_config), - Err("notification-source-zone-mismatch") + Err(ProviderError::SourceZoneMismatch) ); } @@ -1478,19 +1478,19 @@ mod tests { assert_eq!( base.clone() .with_display_wayland_ref(Some(ResourceRef::parse("Provider/another").unwrap())), - Err("notification-display-provider-invalid") + Err(ProviderError::DisplayProviderInvalid) ); assert_eq!( base.clone().with_max_pending_notifications(7).unwrap_err(), - "notification-pending-capacity" + ProviderError::PendingCapacity ); assert_eq!( base.clone().with_action_nonce_ttl_secs(29).unwrap_err(), - "notification-action-nonce-ttl" + ProviderError::ActionNonceTtl ); assert_eq!( base.with_action_nonce_store_size(63).unwrap_err(), - "notification-action-nonce-capacity" + ProviderError::ActionNonceCapacity ); } @@ -1506,7 +1506,7 @@ mod tests { .unwrap(); assert_eq!( controller.plan(&display(DisplayDependencyState::Ready), &config), - Err("notification-display-provider-mismatch") + Err(ProviderError::DisplayProviderMismatch) ); } @@ -1618,7 +1618,7 @@ mod tests { &config, &[test_source_at("one", 1), test_source_at("one", 2)], ), - Err("notification-source-ambiguous") + Err(ProviderError::SourceAmbiguous) ); } @@ -1629,8 +1629,8 @@ mod tests { &mut self, _plan: &SourceReconcileResult, _lifecycle: &NotificationLifecyclePlan, - ) -> Result { - Err("process-effect-failed") + ) -> Result { + Err(ProviderError::ProcessEffectIncomplete) } } @@ -1641,7 +1641,7 @@ mod tests { &mut self, plan: &SourceReconcileResult, _lifecycle: &NotificationLifecyclePlan, - ) -> Result { + ) -> Result { Ok(SourceProcessEffectReceipt::complete(plan)) } } @@ -1657,7 +1657,7 @@ mod tests { let mut effects = CompletingEffects; assert_eq!( controller.reconcile_sources_with_effects(&dependency, &config, &[], &mut effects), - Err("notification-source-unauthenticated") + Err(ProviderError::SourceUnauthenticated) ); assert!(controller.drain_sources().is_empty()); } @@ -1682,7 +1682,7 @@ mod tests { &[test_source("one")], &mut effects, ), - Err("notification-source-unauthenticated") + Err(ProviderError::SourceUnauthenticated) ); let plan = &effects.plans[0]; assert!(plan.start.is_empty()); @@ -1730,7 +1730,7 @@ mod tests { &[test_source("two")], &mut effects, ), - Err("process-effect-failed") + Err(ProviderError::ProcessEffectIncomplete) ); let retry = controller .reconcile_sources(&dependency, &second, &[test_source("two")]) @@ -1756,7 +1756,7 @@ mod tests { assert!(receipt.matches(&plan)); assert_eq!( SourceProcessEffectReceipt::builder(&plan).finish(), - Err("notification-process-effect-incomplete") + Err(ProviderError::ProcessEffectIncomplete) ); let changed = SourceReconcileResult { stop_host_sink: true, diff --git a/packages/d2b-provider-notification-desktop/src/error.rs b/packages/d2b-provider-notification-desktop/src/error.rs index 1e41fe072..e72eb0ffe 100644 --- a/packages/d2b-provider-notification-desktop/src/error.rs +++ b/packages/d2b-provider-notification-desktop/src/error.rs @@ -11,6 +11,100 @@ pub enum ProviderError { SinkUnavailable, /// A bounded queue or action capability limit was reached. Capacity, + /// The authenticated display dependency route was refused. + DisplayDependencyUnauthenticated, + /// The Provider reference is invalid or not the notification Provider. + ProviderRefInvalid, + /// A configured Guest source reference is not a Guest. + SourceRefInvalid, + /// The configured Guest source category set is empty. + CategorySetEmpty, + /// The request category is not allowlisted for the Guest source. + CategoryDenied, + /// The Guest source session generation is zero. + SourceGenerationInvalid, + /// The Guest source session is not authenticated as a source. + SourceUnauthenticated, + /// The Guest source session binding does not match the configured source. + SourceBindingMismatch, + /// The Guest source session generation is stale. + SourceStaleGeneration, + /// More than one authenticated session matched one configured source. + SourceAmbiguous, + /// The configured Guest source set exceeds its bound. + SourceCapacity, + /// The configured Guest source set contains a duplicate reference. + SourceDuplicate, + /// The pending projection bound was refused. + PendingCapacity, + /// The action capability TTL is outside its bound. + ActionNonceTtl, + /// The action capability store size is outside its bound. + ActionNonceCapacity, + /// The observer acknowledgement timeout is outside its bound. + AcknowledgeTimeout, + /// The display Provider dependency is not the canonical display Provider. + DisplayProviderInvalid, + /// The configured display Provider does not match the authenticated one. + DisplayProviderMismatch, + /// The Host or User binding is invalid. + HostBindingInvalid, + /// The Host or User binding is missing. + HostBindingMissing, + /// The authenticated display binding does not match the configuration. + HostBindingMismatch, + /// A configured Guest source is in a different Zone than the display. + SourceZoneMismatch, + /// The display dependency is not available. + DisplayDependencyUnavailable, + /// The supervisor receipt does not match the lifecycle plan. + SupervisorReceiptMismatch, + /// The process effect receipt is incomplete. + ProcessEffectIncomplete, + /// The process effect proof does not match the reconciliation result. + ProcessEffectProofMismatch, + /// A lifecycle source identity is invalid. + LifecycleSourceInvalid, + /// A lifecycle host-sink identity is invalid. + LifecycleHostSinkInvalid, + /// The lifecycle Provider reference is invalid. + LifecycleProviderInvalid, + /// The lifecycle plan is invalid. + LifecyclePlanInvalid, + /// The lifecycle adoption observation is invalid. + LifecycleAdoptionInvalid, + /// The adopted source does not match the plan. + LifecycleSourceAdoptionMismatch, + /// The adopted host sink does not match the plan. + LifecycleHostSinkAdoptionMismatch, + /// A different source is already active for the same reference. + LifecycleSourceAlreadyActive, + /// A different host sink is already active. + LifecycleHostSinkAlreadyActive, + /// The lifecycle state lock is unavailable. + LifecycleStateUnavailable, + /// The active host sink is missing. + LifecycleHostSinkMissing, + /// The lifecycle Zone is unavailable. + LifecycleZoneUnavailable, + /// Compensation failed and supervisor recovery is required. + LifecycleRecoveryRequired, + /// The host backend refused to start a Guest source. + LifecycleSourceStartFailed, + /// The host backend lifecycle state is unavailable. + LifecycleSourceUnavailable, + /// The host backend source set does not match the plan. + LifecycleSourceMismatch, + /// The host sink is unavailable. + HostSinkUnavailable, + /// The active host sink does not match the plan. + HostSinkLifecycleMismatch, + /// The notification supervisor is unavailable. + SupervisorUnavailable, + /// The ComponentSession authority release is incomplete. + AuthorityReleaseIncomplete, + /// A collector telemetry field was rejected. + TelemetryFieldRejected, } impl ProviderError { @@ -21,6 +115,57 @@ impl ProviderError { Self::Schema => "notification-schema-invalid", Self::SinkUnavailable => "sink-unavailable", Self::Capacity => "capacity-exceeded", + Self::DisplayDependencyUnauthenticated => "display-dependency-unauthenticated", + Self::ProviderRefInvalid => "notification-provider-ref-invalid", + Self::SourceRefInvalid => "notification-source-ref-invalid", + Self::CategorySetEmpty => "notification-category-set-empty", + Self::CategoryDenied => "notification-category-denied", + Self::SourceGenerationInvalid => "notification-source-generation-invalid", + Self::SourceUnauthenticated => "notification-source-unauthenticated", + Self::SourceBindingMismatch => "notification-source-binding-mismatch", + Self::SourceStaleGeneration => "notification-source-stale-generation", + Self::SourceAmbiguous => "notification-source-ambiguous", + Self::SourceCapacity => "notification-source-capacity", + Self::SourceDuplicate => "notification-source-duplicate", + Self::PendingCapacity => "notification-pending-capacity", + Self::ActionNonceTtl => "notification-action-nonce-ttl", + Self::ActionNonceCapacity => "notification-action-nonce-capacity", + Self::AcknowledgeTimeout => "notification-acknowledge-timeout", + Self::DisplayProviderInvalid => "notification-display-provider-invalid", + Self::DisplayProviderMismatch => "notification-display-provider-mismatch", + Self::HostBindingInvalid => "notification-host-binding-invalid", + Self::HostBindingMissing => "notification-host-binding-missing", + Self::HostBindingMismatch => "notification-host-binding-mismatch", + Self::SourceZoneMismatch => "notification-source-zone-mismatch", + Self::DisplayDependencyUnavailable => "notification-display-dependency-unavailable", + Self::SupervisorReceiptMismatch => "notification-supervisor-receipt-mismatch", + Self::ProcessEffectIncomplete => "notification-process-effect-incomplete", + Self::ProcessEffectProofMismatch => "notification-process-effect-proof-mismatch", + Self::LifecycleSourceInvalid => "notification-lifecycle-source-invalid", + Self::LifecycleHostSinkInvalid => "notification-lifecycle-host-sink-invalid", + Self::LifecycleProviderInvalid => "notification-lifecycle-provider-invalid", + Self::LifecyclePlanInvalid => "notification-lifecycle-plan-invalid", + Self::LifecycleAdoptionInvalid => "notification-lifecycle-adoption-invalid", + Self::LifecycleSourceAdoptionMismatch => { + "notification-lifecycle-source-adoption-mismatch" + } + Self::LifecycleHostSinkAdoptionMismatch => { + "notification-lifecycle-host-sink-adoption-mismatch" + } + Self::LifecycleSourceAlreadyActive => "notification-lifecycle-source-already-active", + Self::LifecycleHostSinkAlreadyActive => "notification-lifecycle-host-sink-already-active", + Self::LifecycleStateUnavailable => "notification-lifecycle-state-unavailable", + Self::LifecycleHostSinkMissing => "notification-lifecycle-host-sink-missing", + Self::LifecycleZoneUnavailable => "notification-lifecycle-zone-unavailable", + Self::LifecycleRecoveryRequired => "notification-lifecycle-recovery-required", + Self::LifecycleSourceStartFailed => "notification-lifecycle-source-start-failed", + Self::LifecycleSourceUnavailable => "notification-source-lifecycle-unavailable", + Self::LifecycleSourceMismatch => "notification-source-lifecycle-mismatch", + Self::HostSinkUnavailable => "notification-host-sink-unavailable", + Self::HostSinkLifecycleMismatch => "notification-host-sink-lifecycle-mismatch", + Self::SupervisorUnavailable => "notification-supervisor-unavailable", + Self::AuthorityReleaseIncomplete => "notification-authority-release-incomplete", + Self::TelemetryFieldRejected => "notification-telemetry-field-rejected", } } } @@ -31,4 +176,4 @@ impl core::fmt::Display for ProviderError { } } -impl std::error::Error for ProviderError {} +impl std::error::Error for ProviderError {} \ No newline at end of file diff --git a/packages/d2b-provider-notification-desktop/src/guest_source.rs b/packages/d2b-provider-notification-desktop/src/guest_source.rs index a2e80d6f6..41cfb6e2f 100644 --- a/packages/d2b-provider-notification-desktop/src/guest_source.rs +++ b/packages/d2b-provider-notification-desktop/src/guest_source.rs @@ -18,9 +18,9 @@ impl GuestSource { pub fn from_config_at_generation( config: &GuestSourceConfig, generation: u64, - ) -> Result { + ) -> Result { if generation == 0 { - return Err("notification-source-generation-invalid"); + return Err(crate::ProviderError::SourceGenerationInvalid); } Ok(Self { source_ref: config.source_ref().clone(), @@ -32,10 +32,10 @@ impl GuestSource { /// Construct an unbound source for unit tests only. #[cfg(test)] - pub fn new(categories: impl IntoIterator) -> Result { + pub fn new(categories: impl IntoIterator) -> Result { let categories = categories.into_iter().collect::>(); if categories.is_empty() { - return Err("notification-category-set-empty"); + return Err(crate::ProviderError::CategorySetEmpty); } Ok(Self { source_ref: ResourceRef::parse("Guest/test").unwrap(), @@ -46,11 +46,11 @@ impl GuestSource { } /// Validate a request before opening a sink stream. - pub fn validate(&self, request: &NotificationRequest) -> Result<(), &'static str> { + pub fn validate(&self, request: &NotificationRequest) -> Result<(), crate::ProviderError> { if self.categories.contains(&request.category()) { Ok(()) } else { - Err("notification-category-denied") + Err(crate::ProviderError::CategoryDenied) } } @@ -59,15 +59,15 @@ impl GuestSource { &self, session: &SessionEvidence, request: &NotificationRequest, - ) -> Result<(), &'static str> { + ) -> Result<(), crate::ProviderError> { session .admit_source() - .map_err(|_| "notification-source-unauthenticated")?; + .map_err(|_| crate::ProviderError::SourceUnauthenticated)?; if session.subject_ref() != &self.source_ref || session.zone() != &self.zone { - return Err("notification-source-binding-mismatch"); + return Err(crate::ProviderError::SourceBindingMismatch); } if session.generation() != self.generation { - return Err("notification-source-stale-generation"); + return Err(crate::ProviderError::SourceStaleGeneration); } self.validate(request) } @@ -99,7 +99,7 @@ mod tests { let request = NotificationRequest::new("summary", "body", Category::SystemInfo).unwrap(); assert_eq!( source.validate_authenticated(&test_observer("alice"), &request), - Err("notification-source-unauthenticated") + Err(crate::ProviderError::SourceUnauthenticated) ); assert!( source @@ -108,11 +108,11 @@ mod tests { ); assert_eq!( source.validate_authenticated(&crate::admission::test_source("other"), &request), - Err("notification-source-binding-mismatch") + Err(crate::ProviderError::SourceBindingMismatch) ); assert_eq!( source.validate_authenticated(&crate::admission::test_source_at("guest", 2), &request), - Err("notification-source-stale-generation") + Err(crate::ProviderError::SourceStaleGeneration) ); } } diff --git a/packages/d2b-provider-notification-desktop/src/lifecycle.rs b/packages/d2b-provider-notification-desktop/src/lifecycle.rs index 561c92a92..d3efd60fc 100644 --- a/packages/d2b-provider-notification-desktop/src/lifecycle.rs +++ b/packages/d2b-provider-notification-desktop/src/lifecycle.rs @@ -6,6 +6,7 @@ use std::{ }; use tracing::{error, warn}; +use crate::ProviderError; use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; use sha2::{Digest, Sha256}; @@ -29,7 +30,7 @@ impl NotificationSourceIdentity { source_generation: u64, display_generation: u64, endpoint_digest: impl Into, - ) -> Result { + ) -> Result { let endpoint_digest = endpoint_digest.into(); if provider_ref.resource_type().as_str() != "Provider" || source_ref.resource_type().as_str() != "Guest" @@ -38,7 +39,7 @@ impl NotificationSourceIdentity { || endpoint_digest.is_empty() || endpoint_digest.len() > 128 { - return Err("notification-lifecycle-source-invalid"); + return Err(ProviderError::LifecycleSourceInvalid); } Ok(Self { zone, @@ -95,7 +96,7 @@ impl NotificationHostSinkIdentity { display_provider_ref: ResourceRef, display_generation: u64, controller_generation: u64, - ) -> Result { + ) -> Result { if provider_ref.resource_type().as_str() != "Provider" || host_execution_ref.resource_type().as_str() != "Host" || host_user_ref.resource_type().as_str() != "User" @@ -103,7 +104,7 @@ impl NotificationHostSinkIdentity { || display_generation == 0 || controller_generation == 0 { - return Err("notification-lifecycle-host-sink-invalid"); + return Err(ProviderError::LifecycleHostSinkInvalid); } Ok(Self { zone, @@ -153,9 +154,9 @@ impl NotificationLifecyclePlan { mut stop_sources: Vec, start_host_sink: Option, stop_host_sink: Option, - ) -> Result { + ) -> Result { if provider_ref.resource_type().as_str() != "Provider" { - return Err("notification-lifecycle-provider-invalid"); + return Err(ProviderError::LifecycleProviderInvalid); } start_sources.sort(); stop_sources.sort(); @@ -183,7 +184,7 @@ impl NotificationLifecyclePlan { .as_ref() .is_some_and(|sink| sink.zone() != &zone || sink.provider_ref() != &provider_ref) { - return Err("notification-lifecycle-plan-invalid"); + return Err(ProviderError::LifecyclePlanInvalid); } Ok(Self { zone, @@ -288,19 +289,19 @@ impl NotificationLifecycleObservation { /// Host-owned lifecycle operations for notification sources and the sink. pub trait NotificationLifecycleBackend: Send + Sync + 'static { /// Start one generation-bound Guest source. - fn start_source(&self, source: &NotificationSourceIdentity) -> Result<(), &'static str>; + fn start_source(&self, source: &NotificationSourceIdentity) -> Result<(), ProviderError>; /// Stop one exact adopted Guest source. - fn stop_source(&self, source: &NotificationSourceIdentity) -> Result<(), &'static str>; + fn stop_source(&self, source: &NotificationSourceIdentity) -> Result<(), ProviderError>; /// Start one exact host sink. - fn start_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), &'static str>; + fn start_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), ProviderError>; /// Stop one exact adopted host sink. - fn stop_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), &'static str>; + fn stop_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), ProviderError>; /// Observe adoptable source and sink ownership after a supervisor restart. fn observe( &self, zone: &ZoneId, provider_ref: &ResourceRef, - ) -> Result; + ) -> Result; } #[derive(Default)] @@ -357,7 +358,7 @@ impl NotificationLifecycleSupervisor { &self, zone: &ZoneId, provider_ref: &ResourceRef, - ) -> Result { + ) -> Result { let observation = self.backend.observe(zone, provider_ref)?; let mut sources = BTreeMap::new(); for source in observation.sources { @@ -367,7 +368,7 @@ impl NotificationLifecycleSupervisor { .insert(source.source_ref().clone(), source) .is_some() { - return Err("notification-lifecycle-adoption-invalid"); + return Err(ProviderError::LifecycleAdoptionInvalid); } } if observation @@ -375,13 +376,13 @@ impl NotificationLifecycleSupervisor { .as_ref() .is_some_and(|sink| sink.zone() != zone || sink.provider_ref() != provider_ref) { - return Err("notification-lifecycle-adoption-invalid"); + return Err(ProviderError::LifecycleAdoptionInvalid); } let count = sources.len() + usize::from(observation.host_sink.is_some()); let mut state = self .state .lock() - .map_err(|_| "notification-lifecycle-state-unavailable")?; + .map_err(|_| ProviderError::LifecycleStateUnavailable)?; state.sources = sources; state.host_sink = observation.host_sink; Ok(count) @@ -395,11 +396,11 @@ impl NotificationLifecycleSupervisor { pub fn apply( &self, plan: &NotificationLifecyclePlan, - ) -> Result { + ) -> Result { let mut state = self .state .lock() - .map_err(|_| "notification-lifecycle-state-unavailable")?; + .map_err(|_| ProviderError::LifecycleStateUnavailable)?; let mut stopped_sources = Vec::new(); let mut stopped_host_sink = None; let mut started_sources = Vec::new(); @@ -407,7 +408,7 @@ impl NotificationLifecycleSupervisor { let result = (|| { for source in &plan.stop_sources { if state.sources.get(source.source_ref()) != Some(source) { - return Err("notification-lifecycle-source-adoption-mismatch"); + return Err(ProviderError::LifecycleSourceAdoptionMismatch); } self.backend.stop_source(source)?; state.sources.remove(source.source_ref()); @@ -415,7 +416,7 @@ impl NotificationLifecycleSupervisor { } if let Some(sink) = &plan.stop_host_sink { if state.host_sink.as_ref() != Some(sink) { - return Err("notification-lifecycle-host-sink-adoption-mismatch"); + return Err(ProviderError::LifecycleHostSinkAdoptionMismatch); } self.backend.stop_host_sink(sink)?; state.host_sink = None; @@ -427,7 +428,7 @@ impl NotificationLifecycleSupervisor { .get(source.source_ref()) .is_some_and(|active| active != source) { - return Err("notification-lifecycle-source-already-active"); + return Err(ProviderError::LifecycleSourceAlreadyActive); } self.backend.start_source(source)?; state @@ -441,7 +442,7 @@ impl NotificationLifecycleSupervisor { .as_ref() .is_some_and(|active| active != sink) { - return Err("notification-lifecycle-host-sink-already-active"); + return Err(ProviderError::LifecycleHostSinkAlreadyActive); } self.backend.start_host_sink(sink)?; state.host_sink = Some(sink.clone()); @@ -453,7 +454,7 @@ impl NotificationLifecycleSupervisor { warn!( provider = "notification-desktop", zone = ?plan.zone(), - error = error, + error = %error, "lifecycle plan application failed; compensating" ); let mut compensation_failed = false; @@ -517,7 +518,7 @@ impl NotificationLifecycleSupervisor { "lifecycle compensation incomplete; attempting supervisor recovery" ); self.recover(plan.zone(), plan.provider_ref())?; - return Err("notification-lifecycle-recovery-required"); + return Err(ProviderError::LifecycleRecoveryRequired); } return Err(error); } @@ -536,13 +537,13 @@ impl NotificationLifecycleSupervisor { // impls (SourceProcessEffectPort/NotificationProcessEffectPort) call // it off any executor; it has no async form. #[allow(clippy::disallowed_methods, reason = "synchronous path")] - pub fn is_drained(&self) -> Result { + pub fn is_drained(&self) -> Result { let state = self.state.lock().map_err(|_| { warn!( provider = "notification-desktop", "lifecycle state lock poisoned; drained check unavailable" ); - "notification-lifecycle-state-unavailable" + ProviderError::LifecycleStateUnavailable })?; Ok(state.sources.is_empty() && state.host_sink.is_none()) } diff --git a/packages/d2b-provider-notification-desktop/src/metrics.rs b/packages/d2b-provider-notification-desktop/src/metrics.rs index 0f4ca10ac..4cc68f4b0 100644 --- a/packages/d2b-provider-notification-desktop/src/metrics.rs +++ b/packages/d2b-provider-notification-desktop/src/metrics.rs @@ -92,7 +92,7 @@ impl NotificationTelemetryFrame { /// Validate a collector frame and reject identity/content fields. pub fn validate_collector_fields( fields: impl IntoIterator, - ) -> Result<(), &'static str> { + ) -> Result<(), crate::ProviderError> { let forbidden = [ "summary", "body", @@ -112,25 +112,25 @@ impl NotificationTelemetryFrame { || field.value.contains('\n') || field.value.len() > 128 { - return Err("notification-telemetry-field-rejected"); + return Err(crate::ProviderError::TelemetryFieldRejected); } match field.key { "d2b.provider" if field.value != "notification-desktop" => { - return Err("notification-telemetry-field-rejected"); + return Err(crate::ProviderError::TelemetryFieldRejected); } "category" if !crate::Category::ALL .iter() .any(|category| category.as_str() == field.value) => { - return Err("notification-telemetry-field-rejected"); + return Err(crate::ProviderError::TelemetryFieldRejected); } "outcome" if !NotificationOutcome::ALL .iter() .any(|outcome| outcome.as_str() == field.value) => { - return Err("notification-telemetry-field-rejected"); + return Err(crate::ProviderError::TelemetryFieldRejected); } _ => {} } diff --git a/packages/d2b-provider-notification-desktop/src/runtime.rs b/packages/d2b-provider-notification-desktop/src/runtime.rs index efc2f2129..6d9614ea8 100644 --- a/packages/d2b-provider-notification-desktop/src/runtime.rs +++ b/packages/d2b-provider-notification-desktop/src/runtime.rs @@ -13,7 +13,7 @@ use crate::{ /// Daemon-owned notification effect boundary. pub trait NotificationProcessEffectPort: SourceProcessEffectPort { /// Release the authenticated ComponentSession authority after drain. - fn release_authority(&mut self) -> Result<(), &'static str>; + fn release_authority(&mut self) -> Result<(), crate::ProviderError>; } /// Stable failures from notification runtime admission and reconciliation. @@ -166,7 +166,7 @@ impl NotificationRuntime { .map_err(|error| { warn!( provider = "notification-desktop", - reason = error, + reason = %error, "notification source route reconcile failed" ); NotificationRuntimeError::ReconciliationFailed @@ -200,7 +200,7 @@ impl NotificationRuntime { .map_err(|error| { warn!( provider = "notification-desktop", - reason = error, + reason = %error, "notification source route reconcile failed" ); NotificationRuntimeError::ReconciliationFailed @@ -221,7 +221,7 @@ impl NotificationRuntime { .map_err(|error| { warn!( provider = "notification-desktop", - reason = error, + reason = %error, "notification drain reconcile failed" ); NotificationRuntimeError::ReconciliationFailed @@ -247,7 +247,7 @@ impl NotificationRuntime { .map_err(|error| { warn!( provider = "notification-desktop", - reason = error, + reason = %error, "notification drain reconcile failed" ); NotificationRuntimeError::ReconciliationFailed @@ -260,7 +260,7 @@ impl NotificationRuntime { .map_err(|error| { warn!( provider = "notification-desktop", - reason = error, + reason = %error, "notification finalize failed: authority release error" ); NotificationRuntimeError::ReconciliationFailed @@ -296,14 +296,14 @@ mod tests { &mut self, plan: &SourceReconcileResult, _lifecycle: &crate::NotificationLifecyclePlan, - ) -> Result { + ) -> Result { self.plans += 1; Ok(crate::SourceProcessEffectReceipt::complete(plan)) } } impl NotificationProcessEffectPort for Effects { - fn release_authority(&mut self) -> Result<(), &'static str> { + fn release_authority(&mut self) -> Result<(), crate::ProviderError> { self.authority_releases += 1; Ok(()) } diff --git a/packages/d2b-provider-notification-desktop/src/test_support.rs b/packages/d2b-provider-notification-desktop/src/test_support.rs index e56722684..c25dbee9e 100644 --- a/packages/d2b-provider-notification-desktop/src/test_support.rs +++ b/packages/d2b-provider-notification-desktop/src/test_support.rs @@ -7,7 +7,8 @@ //! tests in `d2bd` reach it through the same public surface. use crate::{ - NotificationLifecyclePlan, SourceProcessEffectPort, SourceProcessEffectReceipt, SourceReconcileResult, + NotificationLifecyclePlan, ProviderError, SourceProcessEffectPort, + SourceProcessEffectReceipt, SourceReconcileResult, }; /// Scripted source-process effect port: records every applied plan and @@ -22,7 +23,7 @@ impl SourceProcessEffectPort for RecordingEffects { &mut self, plan: &SourceReconcileResult, _lifecycle: &NotificationLifecyclePlan, - ) -> Result { + ) -> Result { self.plans.push(plan.clone()); Ok(SourceProcessEffectReceipt::complete(plan)) } diff --git a/packages/d2b-provider-notification-desktop/tests/notification_lifecycle.rs b/packages/d2b-provider-notification-desktop/tests/notification_lifecycle.rs index 2b5e8429d..3a4b15980 100644 --- a/packages/d2b-provider-notification-desktop/tests/notification_lifecycle.rs +++ b/packages/d2b-provider-notification-desktop/tests/notification_lifecycle.rs @@ -4,6 +4,7 @@ use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; use d2b_provider_notification_desktop::{ NotificationHostSinkIdentity, NotificationLifecycleBackend, NotificationLifecycleObservation, NotificationLifecyclePlan, NotificationLifecycleSupervisor, NotificationSourceIdentity, + ProviderError, }; #[derive(Default)] @@ -15,18 +16,18 @@ struct Backend { impl NotificationLifecycleBackend for Backend { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - fn start_source(&self, source: &NotificationSourceIdentity) -> Result<(), &'static str> { + fn start_source(&self, source: &NotificationSourceIdentity) -> Result<(), ProviderError> { let mut fail = self.fail_source_start_once.lock().unwrap(); if *fail { *fail = false; - return Err("source-start-failed"); + return Err(ProviderError::LifecycleSourceStartFailed); } self.sources.lock().unwrap().push(source.clone()); Ok(()) } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - fn stop_source(&self, source: &NotificationSourceIdentity) -> Result<(), &'static str> { + fn stop_source(&self, source: &NotificationSourceIdentity) -> Result<(), ProviderError> { self.sources .lock() .unwrap() @@ -35,19 +36,19 @@ impl NotificationLifecycleBackend for Backend { } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - fn start_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), &'static str> { + fn start_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), ProviderError> { *self.sink.lock().unwrap() = Some(sink.clone()); Ok(()) } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - fn stop_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), &'static str> { + fn stop_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), ProviderError> { let mut active = self.sink.lock().unwrap(); if active.as_ref() == Some(sink) { *active = None; Ok(()) } else { - Err("host-sink-not-active") + Err(ProviderError::HostSinkLifecycleMismatch) } } @@ -56,7 +57,7 @@ impl NotificationLifecycleBackend for Backend { &self, _zone: &ZoneId, _provider_ref: &ResourceRef, - ) -> Result { + ) -> Result { Ok(NotificationLifecycleObservation::new( self.sources.lock().unwrap().clone(), self.sink.lock().unwrap().clone(), @@ -144,7 +145,7 @@ fn supervisor_rolls_back_partial_effects_for_retry() { assert!(matches!( supervisor.apply(&transition), - Err("source-start-failed") + Err(ProviderError::LifecycleSourceStartFailed) )); assert!(supervisor.apply(&transition).is_ok()); assert!(!supervisor.is_drained().unwrap()); diff --git a/packages/d2b-provider-notification-desktop/tests/provider_behavior.rs b/packages/d2b-provider-notification-desktop/tests/provider_behavior.rs index 333e81a6c..6224c0060 100644 --- a/packages/d2b-provider-notification-desktop/tests/provider_behavior.rs +++ b/packages/d2b-provider-notification-desktop/tests/provider_behavior.rs @@ -2,7 +2,7 @@ use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; use d2b_provider_notification_desktop::{ ActionNonceStore, ActionSpec, Category, GuestSourceConfig, NotificationController, NotificationProviderConfig, NotificationProviderDescriptor, NotificationRequest, - NotificationUrgency, + NotificationUrgency, ProviderError, }; #[test] @@ -108,14 +108,14 @@ fn notification_source_configuration_rejects_capacity_duplicates_and_bad_binding }; assert_eq!( NotificationProviderConfig::new(vec![source("one"), source("one")]), - Err("notification-source-duplicate") + Err(ProviderError::SourceDuplicate) ); let too_many = (0..17) .map(|index| source(format!("guest-{index}").as_str())) .collect(); assert_eq!( NotificationProviderConfig::new(too_many), - Err("notification-source-capacity") + Err(ProviderError::SourceCapacity) ); assert_eq!( NotificationProviderConfig::new(vec![source("one")]) @@ -124,7 +124,7 @@ fn notification_source_configuration_rejects_capacity_duplicates_and_bad_binding ResourceRef::parse("Guest/not-a-host").unwrap(), ResourceRef::parse("User/alice").unwrap(), ), - Err("notification-host-binding-invalid") + Err(ProviderError::HostBindingInvalid) ); } diff --git a/packages/d2b-provider-notification-desktop/tests/redaction.rs b/packages/d2b-provider-notification-desktop/tests/redaction.rs index fe47a8fc7..557c5bf37 100644 --- a/packages/d2b-provider-notification-desktop/tests/redaction.rs +++ b/packages/d2b-provider-notification-desktop/tests/redaction.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use d2b_provider_notification_desktop::{ ActionSpec, Category, NotificationError, NotificationOutcome, NotificationProjection, NotificationRequest, NotificationResult, NotificationTelemetryField, - NotificationTelemetryFrame, + NotificationTelemetryFrame, ProviderError, }; #[test] @@ -47,6 +47,6 @@ fn notification_canary_stays_out_of_debug_errors_and_telemetry() { key: "summary", value: CANARY.to_owned(), },]), - Err("notification-telemetry-field-rejected") + Err(ProviderError::TelemetryFieldRejected) ); } diff --git a/packages/d2bd/src/interaction_composition.rs b/packages/d2bd/src/interaction_composition.rs index b46d9acef..0288086dc 100644 --- a/packages/d2bd/src/interaction_composition.rs +++ b/packages/d2bd/src/interaction_composition.rs @@ -66,7 +66,7 @@ use d2b_provider_notification_desktop::Category; use d2b_provider_notification_desktop::{ DesktopNotificationPort, NotificationHostSinkIdentity, NotificationLifecycleBackend, NotificationLifecycleObservation, NotificationLifecyclePlan, NotificationLifecycleSupervisor, - NotificationProcessEffectPort, NotificationRequest, NotificationSourceIdentity, + NotificationProcessEffectPort, NotificationRequest, NotificationSourceIdentity, ProviderError, SourceProcessEffectPort, SourceProcessEffectReceipt, SourceReconcileResult, }; use d2b_resource_api::authz::{ @@ -1919,7 +1919,8 @@ where Category::ALL, ) }) - .collect::, _>>()?; + .collect::, _>>() + .map_err(|error| error.as_str())?; let display_route = self .route_for_service(d2b_provider_display_wayland::SERVICE_PACKAGE) .ok_or("notification-display-session-unavailable")?; @@ -1934,12 +1935,15 @@ where .ok_or("notification-display-evidence-unavailable")? .observer_user_ref .clone(); - d2b_provider_notification_desktop::NotificationProviderConfig::new(sources)? - .with_host_binding(host_execution_ref, observer_user_ref)? + d2b_provider_notification_desktop::NotificationProviderConfig::new(sources) + .map_err(|error| error.as_str())? + .with_host_binding(host_execution_ref, observer_user_ref) + .map_err(|error| error.as_str())? .with_display_wayland_ref(Some( ResourceRef::parse("Provider/display-wayland") .map_err(|_| "notification-display-provider-invalid")?, - ))? + )) + .map_err(|error| error.as_str())? } }; self.notification = Some( @@ -4574,60 +4578,60 @@ impl NotificationLifecycleBackend for InteractionNotificationLifecycleBackend { // The trait is synchronous (d2b-provider-notification-desktop), so the // tokio locks are taken with non-blocking `try_lock` per plan U4: a // collision fails closed with the same lifecycle error, never a stall. - fn start_source(&self, source: &NotificationSourceIdentity) -> Result<(), &'static str> { + fn start_source(&self, source: &NotificationSourceIdentity) -> Result<(), ProviderError> { self.state .try_lock() - .map_err(|_| "notification-source-lifecycle-unavailable")? + .map_err(|_| ProviderError::LifecycleSourceUnavailable)? .sources .insert(source.clone()); Ok(()) } - fn stop_source(&self, source: &NotificationSourceIdentity) -> Result<(), &'static str> { + fn stop_source(&self, source: &NotificationSourceIdentity) -> Result<(), ProviderError> { if self .state .try_lock() - .map_err(|_| "notification-source-lifecycle-unavailable")? + .map_err(|_| ProviderError::LifecycleSourceUnavailable)? .sources .remove(source) { Ok(()) } else { - Err("notification-source-lifecycle-mismatch") + Err(ProviderError::LifecycleSourceMismatch) } } - fn start_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), &'static str> { + fn start_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), ProviderError> { self.port .try_lock() - .map_err(|_| "notification-host-sink-unavailable")? + .map_err(|_| ProviderError::HostSinkUnavailable)? .activate() - .map_err(|_| "notification-host-sink-unavailable")?; + .map_err(|_| ProviderError::HostSinkUnavailable)?; self.state .try_lock() - .map_err(|_| "notification-host-sink-unavailable")? + .map_err(|_| ProviderError::HostSinkUnavailable)? .host_sink = Some(sink.clone()); Ok(()) } - fn stop_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), &'static str> { + fn stop_host_sink(&self, sink: &NotificationHostSinkIdentity) -> Result<(), ProviderError> { { let state = self .state .try_lock() - .map_err(|_| "notification-host-sink-unavailable")?; + .map_err(|_| ProviderError::HostSinkUnavailable)?; if state.host_sink.as_ref() != Some(sink) { - return Err("notification-host-sink-lifecycle-mismatch"); + return Err(ProviderError::HostSinkLifecycleMismatch); } } self.port .try_lock() - .map_err(|_| "notification-host-sink-unavailable")? + .map_err(|_| ProviderError::HostSinkUnavailable)? .deactivate() - .map_err(|_| "notification-host-sink-unavailable")?; + .map_err(|_| ProviderError::HostSinkUnavailable)?; self.state .try_lock() - .map_err(|_| "notification-host-sink-unavailable")? + .map_err(|_| ProviderError::HostSinkUnavailable)? .host_sink = None; Ok(()) } @@ -4636,11 +4640,11 @@ impl NotificationLifecycleBackend for InteractionNotificationLifecycleBackend { &self, _zone: &ZoneId, _provider_ref: &ResourceRef, - ) -> Result { + ) -> Result { let state = self .state .try_lock() - .map_err(|_| "notification-source-lifecycle-unavailable")?; + .map_err(|_| ProviderError::LifecycleSourceUnavailable)?; Ok(NotificationLifecycleObservation::new( state.sources.iter().cloned().collect(), state.host_sink.clone(), @@ -4710,11 +4714,11 @@ impl SourceProcessEffectPort for InteractionDrainEffects { &mut self, plan: &SourceReconcileResult, lifecycle: &NotificationLifecyclePlan, - ) -> Result { + ) -> Result { let supervisor = self .notification_lifecycle .as_ref() - .ok_or("notification-supervisor-unavailable")?; + .ok_or(ProviderError::SupervisorUnavailable)?; if !self.notification_recovered { supervisor.recover(lifecycle.zone(), lifecycle.provider_ref())?; self.notification_recovered = true; @@ -4725,17 +4729,17 @@ impl SourceProcessEffectPort for InteractionDrainEffects { } impl NotificationProcessEffectPort for InteractionDrainEffects { - fn release_authority(&mut self) -> Result<(), &'static str> { + fn release_authority(&mut self) -> Result<(), ProviderError> { if self .notification_lifecycle .as_ref() - .ok_or("notification-supervisor-unavailable")? + .ok_or(ProviderError::SupervisorUnavailable)? .is_drained()? { self.authority_released = true; Ok(()) } else { - Err("notification-authority-release-incomplete") + Err(ProviderError::AuthorityReleaseIncomplete) } } } @@ -8274,7 +8278,7 @@ mod tests { d2b_provider_notification_desktop::NotificationProcessEffectPort::release_authority( &mut effects ), - Err("notification-authority-release-incomplete") + Err(ProviderError::AuthorityReleaseIncomplete) ); assert!(!effects.authority_released()); } From 8660f5f57ddbf2bd0b3011c5629b60b4c852c79b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:34:42 -0700 Subject: [PATCH 567/726] d2bd: adapt store error kinds and typed payload digests Convert d2bd-runtime, d2bd, d2b-provider-wayland-policy, and d2b-provider-volume-binding to the restructured StoreErrorKind (Resource(ResourceErrorKind) + store-only) and the typed StateDigest / SchemaFingerprint store-contract digests, matching the contracts crate cutover; wire behavior is unchanged. --- .../src/row_readers.rs | 6 +- .../src/audio_registry.rs | 12 +++- .../src/effects_service.rs | 2 +- .../src/guest_resource_runtime.rs | 58 ++++++++++++------- .../src/resource_runtime_support.rs | 43 ++++++++------ packages/d2bd/src/resource_runtime.rs | 27 +++++---- 6 files changed, 94 insertions(+), 54 deletions(-) diff --git a/packages/d2b-provider-volume-binding/src/row_readers.rs b/packages/d2b-provider-volume-binding/src/row_readers.rs index fb965a026..8a7c148a3 100644 --- a/packages/d2b-provider-volume-binding/src/row_readers.rs +++ b/packages/d2b-provider-volume-binding/src/row_readers.rs @@ -120,7 +120,11 @@ mod tests { generation: d2b_contracts_resource::v3::ResourceGeneration::new(1).expect("generation"), revision: d2b_contracts_resource::v3::ZoneRevision::new(1), canonical_json: canonical, - payload_digest: "sha256:test".to_owned(), + payload_digest: d2b_contracts_resource::v3::StateDigest::parse(format!( + "sha256:{}", + "0".repeat(64) + )) + .expect("a zero digest is a valid state digest"), } } diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index 14793f7aa..4ebe48b29 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -623,7 +623,11 @@ mod tests { generation: d2b_contracts_resource::v3::ResourceGeneration::new(1).unwrap(), revision: ZoneRevision::new(1), canonical_json: canonical, - payload_digest: "sha256:test".to_owned(), + payload_digest: d2b_contracts_resource::v3::StateDigest::parse(format!( + "sha256:{}", + "0".repeat(64) + )) + .unwrap(), } } @@ -769,7 +773,11 @@ mod tests { generation: d2b_contracts_resource::v3::ResourceGeneration::new(1).unwrap(), revision: ZoneRevision::new(1), canonical_json: br#"{"metadata":{}}"#.to_vec(), - payload_digest: String::new(), + payload_digest: d2b_contracts_resource::v3::StateDigest::parse(format!( + "sha256:{}", + "0".repeat(64) + )) + .unwrap(), }; let bindings = vec![( resource.resource_ref.to_canonical_string(), diff --git a/packages/d2b-provider-wayland-policy/src/effects_service.rs b/packages/d2b-provider-wayland-policy/src/effects_service.rs index 00b176257..addc250c9 100644 --- a/packages/d2b-provider-wayland-policy/src/effects_service.rs +++ b/packages/d2b-provider-wayland-policy/src/effects_service.rs @@ -671,7 +671,7 @@ fn validate_audio_dependency_identity( || envelope .digest() .map_err(|_| InteractionEffectError::InvalidResource)? - != resource.payload_digest + != resource.payload_digest.as_str() { return Err(InteractionEffectError::InvalidResource); } diff --git a/packages/d2bd-runtime/src/guest_resource_runtime.rs b/packages/d2bd-runtime/src/guest_resource_runtime.rs index 93a1b99d8..a7679208b 100644 --- a/packages/d2bd-runtime/src/guest_resource_runtime.rs +++ b/packages/d2bd-runtime/src/guest_resource_runtime.rs @@ -29,11 +29,11 @@ use d2b_resource_api::{ service::UnavailableUpgradeDispatcher, }; use d2b_contracts_resource::v3::{ - ExpectedRevision, MutationSealBody, ResourceMutationKind, SealedMutation, StoreCommitResult, - StoreError, StoreErrorKind, StoreGetRequest, StoreInspectSchemaRequest, StoreListRequest, - StoreListResult, StoreResolveRequest, StoreResolvedIdentity, StoreWatchReceipt, - StoreSlot, StoreWatchRequest, StoredResource, StoredSchema, - operations::seal::{MutationSealAcceptor, StoreSealIdentity}, + ExpectedRevision, MutationSealBody, ResourceErrorKind, ResourceMutationKind, SealedMutation, + StateDigest, StoreCommitResult, StoreError, StoreErrorKind, StoreGetRequest, + StoreInspectSchemaRequest, StoreListRequest, StoreListResult, StoreResolveRequest, + StoreResolvedIdentity, StoreWatchReceipt, StoreSlot, StoreWatchRequest, StoredResource, + StoredSchema, operations::seal::{MutationSealAcceptor, StoreSealIdentity}, }; use protobuf::Message; use ttrpc::{ @@ -508,7 +508,7 @@ impl GuestResourceStore { fn forbidden() -> StoreError { StoreError::new( - StoreErrorKind::AuthorizationDenied, + StoreErrorKind::Resource(ResourceErrorKind::AuthorizationDenied), None, None, RetryClass::Never, @@ -518,7 +518,7 @@ impl GuestResourceStore { fn unavailable(reason: &'static str) -> StoreError { StoreError::new( - StoreErrorKind::ResourcePlaneUnavailable, + StoreErrorKind::Resource(ResourceErrorKind::ResourcePlaneUnavailable), None, None, RetryClass::AfterDelay, @@ -528,7 +528,7 @@ impl GuestResourceStore { fn invalid(reason: &'static str) -> StoreError { StoreError::new( - StoreErrorKind::ResourceSchemaInvalid, + StoreErrorKind::Resource(ResourceErrorKind::ResourceSchemaInvalid), None, None, RetryClass::Never, @@ -538,7 +538,7 @@ impl GuestResourceStore { fn unsupported_capability(reason: &'static str) -> StoreError { StoreError::new( - StoreErrorKind::UnsupportedCapability, + StoreErrorKind::Resource(ResourceErrorKind::UnsupportedCapability), None, None, RetryClass::Never, @@ -548,7 +548,7 @@ impl GuestResourceStore { fn not_found() -> StoreError { StoreError::new( - StoreErrorKind::ResourceNotFound, + StoreErrorKind::Resource(ResourceErrorKind::ResourceNotFound), None, None, RetryClass::Never, @@ -558,7 +558,7 @@ impl GuestResourceStore { fn conflict(revision: u64) -> StoreError { StoreError::new( - StoreErrorKind::ResourceConflict, + StoreErrorKind::Resource(ResourceErrorKind::ResourceConflict), Some(ZoneRevision::new(revision)), None, RetryClass::Reauthorize, @@ -675,7 +675,7 @@ impl GuestResourceStore { match mutation.expected { ExpectedRevision::CreateAbsent if current.is_some() => { return Err(StoreError::new( - StoreErrorKind::ResourceAlreadyExists, + StoreErrorKind::Resource(ResourceErrorKind::ResourceAlreadyExists), Some(ZoneRevision::new(state.revision)), None, RetryClass::Never, @@ -722,12 +722,13 @@ impl GuestResourceStore { } let payload_digest = prepared .payload_digest() - .map(str::to_owned) + .cloned() .unwrap_or_else(|| { - d2b_contracts_resource::v3::canonical_digest( + StateDigest::parse(d2b_contracts_resource::v3::canonical_digest( d2b_contracts_resource::v3::resource_schema::RESOURCE_ENVELOPE_DOMAIN_TAG, &canonical, - ) + )) + .expect("a canonical digest is a valid state digest") }); let resource = StoredResource { resource_ref: mutation.target.clone(), @@ -879,10 +880,11 @@ impl ResourceStoreBackend for GuestResourceStore { .to_canonical_bytes(); Ok(StoredSchema { resource_type: request.resource_type, - payload_digest: d2b_contracts_resource::v3::canonical_digest( + payload_digest: SchemaFingerprint::parse(d2b_contracts_resource::v3::canonical_digest( SCHEMA_DOMAIN_TAG, &canonical, - ), + )) + .expect("a canonical digest is a valid schema fingerprint"), canonical_json: canonical, }) } @@ -1085,7 +1087,7 @@ fn validate_seed_request( || identity.uid.is_some() || identity.generation.is_some() || identity.revision.is_some() - }) || resource.payload_digest + }) || resource.payload_digest.as_str() != d2b_contracts_resource::v3::canonical_digest( RESOURCE_ENVELOPE_DOMAIN_TAG, &resource.canonical_json, @@ -1398,7 +1400,10 @@ mod tests { let error = bound .ensure_current() .expect_err("an older session generation must be fenced"); - assert_eq!(error.kind(), StoreErrorKind::ResourcePlaneUnavailable); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::ResourcePlaneUnavailable) + ); } #[test] @@ -1451,7 +1456,10 @@ mod tests { }) .await .expect_err("Zone schema is not target-local"); - assert_eq!(error.kind(), StoreErrorKind::AuthorizationDenied); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::AuthorizationDenied) + ); } #[tokio::test] @@ -1486,7 +1494,10 @@ mod tests { }) .await .expect_err("Zone watch is not target-local"); - assert_eq!(error.kind(), StoreErrorKind::AuthorizationDenied); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::AuthorizationDenied) + ); } #[tokio::test] @@ -1522,7 +1533,10 @@ mod tests { }) .await .expect_err("a watch whose stream no one fills must be refused, not receipted"); - assert_eq!(error.kind(), StoreErrorKind::UnsupportedCapability); + assert_eq!( + error.kind(), + StoreErrorKind::Resource(ResourceErrorKind::UnsupportedCapability) + ); assert_eq!(error.reason_code(), "watch-not-wired"); assert_eq!(error.retry_class(), RetryClass::Never); } diff --git a/packages/d2bd-runtime/src/resource_runtime_support.rs b/packages/d2bd-runtime/src/resource_runtime_support.rs index 8045e5090..ad83b47c0 100644 --- a/packages/d2bd-runtime/src/resource_runtime_support.rs +++ b/packages/d2bd-runtime/src/resource_runtime_support.rs @@ -820,7 +820,7 @@ fn validated_stored_resource_envelope( || envelope .digest() .map_err(|_| ResourceRuntimeError::AuthorizationUnavailable)? - != resource.payload_digest + != resource.payload_digest.as_str() { tracing::warn!( zone = zone.as_str(), @@ -2041,7 +2041,7 @@ mod tests { use super::*; use crate::resource_api::parse_list_request; use serde_json::json; - use d2b_contracts_resource::v3::{ResourceGeneration, ResourceName}; + use d2b_contracts_resource::v3::{ResourceGeneration, ResourceName, StateDigest}; use d2b_resource_api::authz::{ ApiMethod, AuthorizationDenial, AuthorizationRequest, AuthorizationTarget, }; @@ -2104,7 +2104,7 @@ mod tests { generation: ResourceGeneration::new(1).unwrap(), revision: ZoneRevision::new(1), canonical_json, - payload_digest: envelope.digest().unwrap(), + payload_digest: StateDigest::parse(envelope.digest().unwrap()).unwrap(), } } @@ -2162,7 +2162,7 @@ mod tests { generation: ResourceGeneration::new(1).unwrap(), revision: ZoneRevision::new(1), canonical_json, - payload_digest: envelope.digest().unwrap(), + payload_digest: StateDigest::parse(envelope.digest().unwrap()).unwrap(), } } @@ -2172,10 +2172,13 @@ mod tests { value["status"]["observedGeneration"] = json!(observed_generation); value["status"]["update"]["observedGeneration"] = json!(observed_generation); resource.canonical_json = d2b_contracts_resource::v3::canonical_json_bytes(&value).unwrap(); - resource.payload_digest = ResourceEnvelope::from_json(&resource.canonical_json) - .unwrap() - .digest() - .unwrap(); + resource.payload_digest = StateDigest::parse( + ResourceEnvelope::from_json(&resource.canonical_json) + .unwrap() + .digest() + .unwrap(), + ) + .unwrap(); } fn set_identity(resource: &mut StoredResource, uid: &str, generation: u64) { @@ -2187,20 +2190,26 @@ mod tests { resource.uid = ResourceUid::parse(uid).unwrap(); resource.generation = ResourceGeneration::new(generation).unwrap(); resource.canonical_json = d2b_contracts_resource::v3::canonical_json_bytes(&value).unwrap(); - resource.payload_digest = ResourceEnvelope::from_json(&resource.canonical_json) - .unwrap() - .digest() - .unwrap(); + resource.payload_digest = StateDigest::parse( + ResourceEnvelope::from_json(&resource.canonical_json) + .unwrap() + .digest() + .unwrap(), + ) + .unwrap(); } fn set_binding_subjects(resource: &mut StoredResource, subjects: &[&str]) { let mut value: Value = serde_json::from_slice(&resource.canonical_json).unwrap(); value["spec"]["subjects"] = json!(subjects); resource.canonical_json = d2b_contracts_resource::v3::canonical_json_bytes(&value).unwrap(); - resource.payload_digest = ResourceEnvelope::from_json(&resource.canonical_json) - .unwrap() - .digest() - .unwrap(); + resource.payload_digest = StateDigest::parse( + ResourceEnvelope::from_json(&resource.canonical_json) + .unwrap() + .digest() + .unwrap(), + ) + .unwrap(); } fn subject_context(subject_ref: &str, subject_uid: &str) -> AuthenticatedSubjectContext { @@ -3383,7 +3392,7 @@ mod tests { generation: ResourceGeneration::new(1).unwrap(), revision: ZoneRevision::new(1), canonical_json: br#"{"metadata":{"managedBy":"configuration","configurationGeneration":3,"deletionRequestedAt":"2026-08-15T00:00:00Z"}}"#.to_vec(), - payload_digest: String::new(), + payload_digest: StateDigest::parse(format!("sha256:{}", "0".repeat(64))).unwrap(), }; assert!(configuration_cleanup_pending(&resource, 4)); resource.canonical_json = diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 89713c5db..221adc13c 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -37,7 +37,7 @@ use d2b_contracts_resource::v3::identity::{ use d2b_contracts_resource::v3::{ CanonicalJsonValue, ControllerGeneration, DEFAULT_REQUEST_DEADLINE_MS, DesiredLifecycle, PlacementTargetKind, ResourceBundleGenerationId, ResourceEnvelope, ResourceGeneration, - ResourceErrorKind, ResourcePhase, ResourceRef, ResourceTypeName, ResourceUid, + ResourceErrorKind, ResourcePhase, ResourceRef, ResourceTypeName, ResourceUid, StateDigest, ZoneId, ZoneRevision, process::ProcessSpec, volume::VolumeSpec, @@ -1550,7 +1550,7 @@ fn stored_resource_from_wire(resource: &wire::ResourceEnvelopeBytes) -> Option Date: Fri, 25 Sep 2026 16:35:44 -0700 Subject: [PATCH 568/726] broker: document runtime process entry point --- changelog.d/w4-14-runtime-docs.md | 5 +++++ packages/d2b-broker/src/runtime.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 changelog.d/w4-14-runtime-docs.md diff --git a/changelog.d/w4-14-runtime-docs.md b/changelog.d/w4-14-runtime-docs.md new file mode 100644 index 000000000..abe82d79c --- /dev/null +++ b/changelog.d/w4-14-runtime-docs.md @@ -0,0 +1,5 @@ +### Fixed + +- Documented the broker process entry point: `runtime` now carries a module + doc, and `ServerConfig`, `BrokerMode`, `RunError`, `parse_command`, and + `run` have doc comments with `# Errors` sections on the fallible functions. \ No newline at end of file diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 8b0d31ae9..e9597184f 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -1,3 +1,10 @@ +//! The broker process entry point. +//! +//! [`parse_command`] turns the process arguments into a [`BrokerMode`] +//! carrying a [`ServerConfig`]; [`run`] executes that mode, serving the +//! broker's socket until termination or returning a [`RunError`] on +//! failure. + use std::env; use std::fs; #[cfg(not(feature = "layer1-bootstrap"))] @@ -320,6 +327,8 @@ fn stale_wire_refusal(retired: &RetiredWireVariant) -> BrokerResponse { }) } +/// Process-start configuration for one broker run, resolved from CLI +/// flags and environment defaults by [`parse_command`]. #[derive(Debug, Clone)] pub struct ServerConfig { /// Fixed process-start authority profile. Requests cannot change it. @@ -371,6 +380,8 @@ pub struct ServerConfig { pub retired_wire_variants: &'static [RetiredWireVariant], } +/// The process mode selected by [`parse_command`]: host or guest serving, +/// or a bootstrap probe. #[derive(Debug, Clone)] pub enum BrokerMode { Host(ServerConfig), @@ -394,6 +405,8 @@ pub enum BrokerMode { }, } +/// A process-entry failure surfaced by [`parse_command`] or [`run`]: +/// usage, I/O, or protocol. #[derive(Debug)] pub enum RunError { Usage(String), @@ -562,6 +575,13 @@ impl core::fmt::Debug for BrokerError { } } +/// Parse process arguments into the [`BrokerMode`] to run. +/// +/// # Errors +/// +/// Returns [`RunError::Usage`] when the first argument is not a known +/// profile (or probe subcommand), a flag is missing or malformed, or the +/// d2bd uid/gid cannot be resolved. pub fn parse_command(args: I) -> Result where I: IntoIterator, @@ -796,6 +816,13 @@ where }) } +/// Run the broker in the parsed [`BrokerMode`], serving until termination. +/// +/// # Errors +/// +/// Returns [`RunError::Io`] when the socket cannot be adopted or bound, +/// [`RunError::Protocol`] when the wire negotiation or a request fails +/// fatally, and [`RunError::Usage`] for a malformed probe invocation. pub fn run(command: BrokerMode) -> Result<(), RunError> { match command { BrokerMode::Host(config) | BrokerMode::Guest(config) => run_server(config), From b872981b20ee70d7ca4f9776d252f32d4c07c5dd Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:36:28 -0700 Subject: [PATCH 569/726] controller-toolkit: bind snapshot owner uid and generation in OwnerIdentity --- changelog.d/w4-18-owner-identity.md | 3 ++ .../d2b-controller-toolkit/src/context.rs | 53 ++++++++++++------- packages/d2b-controller-toolkit/src/lib.rs | 2 +- packages/d2b-provider-provider/src/driver.rs | 7 ++- .../d2b-provider-provider/src/providers.rs | 10 ++-- 5 files changed, 49 insertions(+), 26 deletions(-) create mode 100644 changelog.d/w4-18-owner-identity.md diff --git a/changelog.d/w4-18-owner-identity.md b/changelog.d/w4-18-owner-identity.md new file mode 100644 index 000000000..9f9690ef9 --- /dev/null +++ b/changelog.d/w4-18-owner-identity.md @@ -0,0 +1,3 @@ +### Fixed + +- Controller resource snapshots now carry the singular owner as one `OwnerIdentity` (uid + generation) instead of two independently settable fields, so a snapshot can no longer hold an owner uid without its generation. \ No newline at end of file diff --git a/packages/d2b-controller-toolkit/src/context.rs b/packages/d2b-controller-toolkit/src/context.rs index bd9755f76..4141f0c5c 100644 --- a/packages/d2b-controller-toolkit/src/context.rs +++ b/packages/d2b-controller-toolkit/src/context.rs @@ -10,12 +10,38 @@ use d2b_contracts_resource::v3::{ResourceGeneration, ResourceUid, ZoneRevision}; use crate::ResourceKey; +/// The store's immutable singular-owner identity attached to a snapshot. +/// +/// The owner UID and generation are bound together: the store writes them as +/// one unit, so a snapshot never carries one without the other. +#[derive(Clone, PartialEq, Eq)] +pub struct OwnerIdentity { + uid: ResourceUid, + generation: ResourceGeneration, +} + +impl OwnerIdentity { + /// Construct an owner identity. + pub const fn new(uid: ResourceUid, generation: ResourceGeneration) -> Self { + Self { uid, generation } + } + + /// Borrow the immutable owner UID. + pub const fn uid(&self) -> &ResourceUid { + &self.uid + } + + /// Return the immutable owner generation. + pub const fn generation(&self) -> ResourceGeneration { + self.generation + } +} + /// Manager-served target body observed by one controller pass. #[derive(Clone, PartialEq, Eq)] pub struct ResourceSnapshot { key: ResourceKey, - owner_uid: Option, - owner_generation: Option, + owner: Option, revision: ZoneRevision, generation: ResourceGeneration, canonical_json: Vec, @@ -33,8 +59,7 @@ impl ResourceSnapshot { ) -> Self { Self { key, - owner_uid: None, - owner_generation: None, + owner: None, revision, generation, canonical_json, @@ -47,24 +72,14 @@ impl ResourceSnapshot { &self.key } - /// Borrow the immutable singular owner UID when the store supplied it. - pub fn owner_uid(&self) -> Option<&ResourceUid> { - self.owner_uid.as_ref() - } - - /// Return the immutable owner generation when the source supplied it. - pub const fn owner_generation(&self) -> Option { - self.owner_generation + /// Borrow the immutable singular owner identity when the store supplied it. + pub const fn owner(&self) -> Option<&OwnerIdentity> { + self.owner.as_ref() } /// Attach the store's immutable owner identity to this snapshot. - pub fn with_owner_identity( - mut self, - owner_uid: Option, - owner_generation: Option, - ) -> Self { - self.owner_uid = owner_uid; - self.owner_generation = owner_generation; + pub fn with_owner_identity(mut self, owner: Option) -> Self { + self.owner = owner; self } diff --git a/packages/d2b-controller-toolkit/src/lib.rs b/packages/d2b-controller-toolkit/src/lib.rs index fd5f7ff1d..0370433c6 100644 --- a/packages/d2b-controller-toolkit/src/lib.rs +++ b/packages/d2b-controller-toolkit/src/lib.rs @@ -8,5 +8,5 @@ pub mod context; pub mod contract; -pub use context::{DependencySnapshot, ResourceSnapshot}; +pub use context::{DependencySnapshot, OwnerIdentity, ResourceSnapshot}; pub use contract::ResourceKey; diff --git a/packages/d2b-provider-provider/src/driver.rs b/packages/d2b-provider-provider/src/driver.rs index 1e46dfa4d..809b785a8 100644 --- a/packages/d2b-provider-provider/src/driver.rs +++ b/packages/d2b-provider-provider/src/driver.rs @@ -50,7 +50,7 @@ use d2b_contracts_resource::v3::{ ResourceGeneration, ResourceRef, ResourceUid, ZoneId, ZoneRevision, }; use d2b_controller_toolkit::{ - DependencySnapshot, ResourceKey as CoreResourceKey, ResourceSnapshot, + DependencySnapshot, OwnerIdentity, ResourceKey as CoreResourceKey, ResourceSnapshot, }; use d2b_resource_runtime::context::{ResourceContext, SpecDecoder, typed_spec_decoder}; use d2b_resource_runtime::driver::{ @@ -545,7 +545,10 @@ impl ProviderDriver { canonical, view.deleting, ) - .with_owner_identity(Some(provider_uid.clone()), Some(provider_generation)), + .with_owner_identity(Some(OwnerIdentity::new( + provider_uid.clone(), + provider_generation, + ))), )) } } diff --git a/packages/d2b-provider-provider/src/providers.rs b/packages/d2b-provider-provider/src/providers.rs index 5b6b7bdcc..1e68969a6 100644 --- a/packages/d2b-provider-provider/src/providers.rs +++ b/packages/d2b-provider-provider/src/providers.rs @@ -5,7 +5,7 @@ use std::collections::BTreeSet; use d2b_contracts_provider::v3::ComponentType; use d2b_contracts_resource::v3::ResourceRef; use d2b_contracts_zone_session::v3::ZoneStatusResource; -use d2b_controller_toolkit::{DependencySnapshot, ResourceKey, ResourceSnapshot}; +use d2b_controller_toolkit::{DependencySnapshot, OwnerIdentity, ResourceKey, ResourceSnapshot}; use crate::driver::{ SYSTEM_CORE_HOST_REF, SYSTEM_CORE_PROVIDER_REF, SYSTEM_MINIJAIL_PROVIDER_REF, @@ -416,7 +416,7 @@ pub fn provider_observation( .as_str() { "Process" => { - if dependency_resource.owner_uid() != Some(resource.key().uid()) { + if dependency_resource.owner().map(OwnerIdentity::uid) != Some(resource.key().uid()) { graph_valid = false; conformance_valid = false; required_components_ready = false; @@ -470,8 +470,10 @@ pub fn provider_observation( continue; } observed_volume_refs.insert(volume_ref); - let owner_uid_matches = - dependency_resource.owner_uid() == Some(resource.key().uid()); + let owner_uid_matches = dependency_resource + .owner() + .map(OwnerIdentity::uid) + == Some(resource.key().uid()); if !owner_uid_matches { required_dependencies_ready = false; continue; From 5c7fbf0675244b53ea455d24dbbebae269f2ef1f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:36:51 -0700 Subject: [PATCH 570/726] resource-api: resolve owner keys through the manager uid index owner_key_for listed the entire Zone row set and linear-searched for the owner uid on every Delete and owner-less update. The manager already maintains a uid-to-key index (by_uid); expose it as a KeyForUid RPC on ResourceManagerClient and resolve owners through it instead. --- changelog.d/w4-20-owner-key-lookup.md | 6 +++++ .../d2b-resource-api/src/manager_backend.rs | 17 +++----------- packages/d2b-resource-runtime/src/manager.rs | 22 +++++++++++++++++++ 3 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 changelog.d/w4-20-owner-key-lookup.md diff --git a/changelog.d/w4-20-owner-key-lookup.md b/changelog.d/w4-20-owner-key-lookup.md new file mode 100644 index 000000000..c0f222c33 --- /dev/null +++ b/changelog.d/w4-20-owner-key-lookup.md @@ -0,0 +1,6 @@ +### Fixed + +- Resource API mutation resolution no longer lists the entire Zone row set + to resolve an owner: `owner_key_for` now asks the resource manager for the + owner uid's key through the manager's uid index, so Delete and owner-less + updates resolve ownership in constant time instead of scanning every row. \ No newline at end of file diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index 898ac731e..d7c9e8757 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -1111,21 +1111,10 @@ impl ManagerBackend { let Some(owner_uid) = row.owner_uid else { return Ok(None); }; - let views = self - .manager - .list(ResourceSelector::default()) + self.manager + .key_for_uid(owner_uid) .await - .map_err(map_manager_error)?; - Ok(views - .iter() - .find(|view| view.uid == owner_uid) - .map(|view| { - RuntimeResourceKey::new( - view.key.zone.clone(), - view.key.type_name.clone(), - view.key.name.clone(), - ) - })) + .map_err(map_manager_error) } } diff --git a/packages/d2b-resource-runtime/src/manager.rs b/packages/d2b-resource-runtime/src/manager.rs index 3fef36a55..edcfee94e 100644 --- a/packages/d2b-resource-runtime/src/manager.rs +++ b/packages/d2b-resource-runtime/src/manager.rs @@ -336,6 +336,12 @@ pub enum ResourceManagerMsg { selector: ResourceSelector, reply: oneshot::Sender, ResourceError>>, }, + /// Stable-uid to manager-key resolution through the uid index (KTD2): + /// `None` when no row with that uid is in this manager. + KeyForUid { + uid: [u8; 16], + reply: oneshot::Sender, ResourceError>>, + }, /// External API watch (R23): served from the in-memory hub; replay plus /// live delivery is gap-free within the daemon epoch. Watch { @@ -1003,6 +1009,9 @@ impl Actor for ResourceManager { .collect(); reply.send(Ok(views)).ok(); } + ResourceManagerMsg::KeyForUid { uid, reply } => { + reply.send(Ok(state.by_uid.get(&uid).cloned())).ok(); + } ResourceManagerMsg::Watch { selector, after, reply } => { // One manager serializes list snapshots, revisions, and watch // registration, so the list/watch handoff stays gap-free @@ -1596,6 +1605,19 @@ impl ResourceManagerClient { self.rpc(|reply| ResourceManagerMsg::List { selector, reply }).await } + /// The manager key for one stable row uid, resolved through the manager's + /// uid index; `None` when no row with that uid is in this manager. + /// + /// # Errors + /// + /// [`ResourceError::ManagerUnavailable`] when the request cannot be routed. + pub async fn key_for_uid( + &self, + uid: [u8; 16], + ) -> Result, ResourceError> { + self.rpc(|reply| ResourceManagerMsg::KeyForUid { uid, reply }).await + } + /// Open a gap-free watch on matching changes: the registration atomically /// serves a list snapshot (from `after`, when servable) and live delivery. /// From a2cf0e614efe832ea76f2e5ef0fe72ba533120aa Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:36:52 -0700 Subject: [PATCH 571/726] contracts: borrow-based handshake offers and shared wire deserialize macro - Add From<&EndpointPolicy> for HandshakeOffer and use it at all seven HandshakeOffer::from(policy.clone()) sites (component_session, session admission/engine/handshake); the by-value impl stays for owned policies. - Add From<&ResourceEnvelope> for ResourceRef in d2b-contracts-resource and use it in ResourceExportSpec::validate_target instead of rebuilding the ref from cloned parts. - Consolidate 28 hand-written Wire-struct Deserialize impls behind a shared wire_deserialize! macro in d2b-contracts-zone-session; wire shapes, defaults, and constructor validation gates are unchanged. --- ...ontracts-handshake-and-wire-deserialize.md | 5 + .../d2b-contracts-resource/src/v3/resource.rs | 9 + .../src/v3/component_session.rs | 24 +- .../src/v3/emergency_policy.rs | 48 ++-- .../d2b-contracts-zone-session/src/v3/mod.rs | 33 +++ .../src/v3/resource_bundle.rs | 143 +++++----- .../src/v3/resource_export.rs | 187 ++++++------ .../src/v3/resource_import.rs | 67 ++--- .../d2b-contracts-zone-session/src/v3/role.rs | 168 ++++++----- .../src/v3/role_binding.rs | 87 +++--- .../src/v3/services.rs | 27 +- .../d2b-contracts-zone-session/src/v3/zone.rs | 108 ++++--- .../src/v3/zone_link.rs | 168 ++++++----- .../src/v3/zone_routing.rs | 270 +++++++++--------- packages/d2b-session/src/admission.rs | 2 +- packages/d2b-session/src/engine.rs | 2 +- packages/d2b-session/src/handshake.rs | 4 +- 17 files changed, 674 insertions(+), 678 deletions(-) create mode 100644 changelog.d/w4-01-contracts-handshake-and-wire-deserialize.md diff --git a/changelog.d/w4-01-contracts-handshake-and-wire-deserialize.md b/changelog.d/w4-01-contracts-handshake-and-wire-deserialize.md new file mode 100644 index 000000000..f6551399e --- /dev/null +++ b/changelog.d/w4-01-contracts-handshake-and-wire-deserialize.md @@ -0,0 +1,5 @@ +### Fixed + +- Handshake offer derivation now converts from a borrowed endpoint policy at all seven call sites instead of cloning the policy first; the by-value conversion remains for owned policies. +- Export-target validation now rebuilds the target `ResourceRef` through a single `From<&ResourceEnvelope>` conversion instead of cloning the resource type and name at the comparison site. +- Consolidated the crate's hand-written Wire-struct `Deserialize` impls behind a shared `wire_deserialize!` macro; wire shapes, defaults, and constructor validation gates are unchanged. \ No newline at end of file diff --git a/packages/d2b-contracts-resource/src/v3/resource.rs b/packages/d2b-contracts-resource/src/v3/resource.rs index e938edf0b..f87a39feb 100644 --- a/packages/d2b-contracts-resource/src/v3/resource.rs +++ b/packages/d2b-contracts-resource/src/v3/resource.rs @@ -815,6 +815,15 @@ impl<'de> Deserialize<'de> for ResourceEnvelope { } } +impl From<&ResourceEnvelope> for ResourceRef { + fn from(envelope: &ResourceEnvelope) -> Self { + Self::new( + envelope.resource_type().clone(), + envelope.metadata().name().clone(), + ) + } +} + fn validate_provider_binding( resource_type: &ResourceTypeName, spec: &ResourceSpec, diff --git a/packages/d2b-contracts-zone-session/src/v3/component_session.rs b/packages/d2b-contracts-zone-session/src/v3/component_session.rs index 982824197..42c2c2f4b 100644 --- a/packages/d2b-contracts-zone-session/src/v3/component_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/component_session.rs @@ -453,7 +453,7 @@ impl ComponentSessionDescriptor { policy: &EndpointPolicy, boundary: ComponentSessionBoundary, ) -> Result { - HandshakeOffer::from(policy.clone()).validate()?; + HandshakeOffer::from(policy).validate()?; Self::new( boundary, policy.service, @@ -470,7 +470,7 @@ impl ComponentSessionDescriptor { { return Err(ContractError::IdentityEvidenceMismatch); } - HandshakeOffer::from(policy.clone()).validate()?; + HandshakeOffer::from(policy).validate()?; Ok(()) } @@ -1011,7 +1011,7 @@ impl EndpointPolicyIdentity { reconnect_generation, attachment_policy: self.attachment_policy, }; - HandshakeOffer::from(policy.clone()).validate()?; + HandshakeOffer::from(&policy).validate()?; Ok(policy) } @@ -1187,6 +1187,24 @@ impl From for HandshakeOffer { } } +impl From<&EndpointPolicy> for HandshakeOffer { + fn from(value: &EndpointPolicy) -> Self { + Self { + purpose: value.purpose, + purpose_class: value.purpose_class, + initiator_role: value.initiator_role, + responder_role: value.responder_role, + service: value.service, + schema_fingerprint: value.schema_fingerprint, + noise_profile: value.noise_profile, + limits: value.limits, + transport_binding: value.transport_binding, + reconnect_generation: value.reconnect_generation, + attachment_policy: value.attachment_policy, + } + } +} + impl HandshakeOffer { pub fn validate(&self) -> Result<(), ContractError> { self.limits.validate()?; diff --git a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs index 9725d1abf..c2a62c927 100644 --- a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs +++ b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs @@ -1,7 +1,7 @@ //! Zone-wide EmergencyPolicy contract. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use d2b_contracts_resource::v3::execution_policy::redacted_debug; @@ -168,30 +168,28 @@ impl Default for EmergencyPolicySpec { } } -impl<'de> Deserialize<'de> for EmergencyPolicySpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - enabled: bool, - #[serde(default)] - scope: EmergencyScope, - #[serde(default = "default_deadline")] - drain_deadline_seconds: u32, - #[serde(default)] - reason: String, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.enabled, - wire.scope, - wire.drain_deadline_seconds, - wire.reason, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + EmergencyPolicySpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + enabled: bool, + #[serde(default)] + scope: EmergencyScope, + #[serde(default = "default_deadline")] + drain_deadline_seconds: u32, + #[serde(default)] + reason: String, + }, + wire, + Self::new( + wire.enabled, + wire.scope, + wire.drain_deadline_seconds, + wire.reason, + ) + .map_err(serde::de::Error::custom) +); const fn default_deadline() -> u32 { 30 diff --git a/packages/d2b-contracts-zone-session/src/v3/mod.rs b/packages/d2b-contracts-zone-session/src/v3/mod.rs index 4e18f7de9..6e3478559 100644 --- a/packages/d2b-contracts-zone-session/src/v3/mod.rs +++ b/packages/d2b-contracts-zone-session/src/v3/mod.rs @@ -1,5 +1,38 @@ //! Canonical Zone and ComponentSession contract family. +/// Captures the crate's Wire-struct `Deserialize` shape: a private +/// `#[derive(Deserialize)]` wire struct with `deny_unknown_fields`, then a +/// validated constructor admission check. +/// +/// The binding name is passed explicitly (`wire` at every site) so the +/// construct expression can reference it across macro hygiene. +macro_rules! wire_deserialize { + ( + $type:ty, + $(#[$container:meta])* + $wire:ident { + $( $(#[$field_attr:meta])* $field:ident : $field_ty:ty ),* $(,)? + }, + $binding:ident, + $construct:expr + ) => { + impl<'de> serde::Deserialize<'de> for $type { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(serde::Deserialize)] + $(#[$container])* + struct $wire { + $( $(#[$field_attr])* $field: $field_ty, )* + } + let $binding = $wire::deserialize(deserializer)?; + $construct + } + } + }; +} + pub mod component_session; pub mod emergency_policy; pub mod resource_bundle; diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs index b05972b99..da6b475d3 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs @@ -9,7 +9,7 @@ use std::collections::BTreeMap; use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use d2b_contracts_provider::v3::{ArtifactDigest, BinaryRef}; use d2b_contracts_resource::v3::{ @@ -98,30 +98,28 @@ impl core::fmt::Debug for BundleResourceMetadata { } } -impl<'de> Deserialize<'de> for BundleResourceMetadata { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - name: d2b_contracts_resource::v3::ResourceName, - zone: ZoneId, - #[serde(default)] - owner_ref: Option, - #[serde(default)] - labels: BTreeMap, - #[serde(default)] - annotations: BTreeMap, - } - let wire = Wire::deserialize(deserializer)?; - Ok(Self::new( - wire.name, - wire.zone, - wire.owner_ref, - wire.labels, - wire.annotations, - )) - } -} +wire_deserialize!( + BundleResourceMetadata, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + name: d2b_contracts_resource::v3::ResourceName, + zone: ZoneId, + #[serde(default)] + owner_ref: Option, + #[serde(default)] + labels: BTreeMap, + #[serde(default)] + annotations: BTreeMap, + }, + wire, + Ok(Self::new( + wire.name, + wire.zone, + wire.owner_ref, + wire.labels, + wire.annotations, + )) +); /// One desired-state resource item in a Zone bundle. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -182,26 +180,27 @@ impl core::fmt::Debug for BundleResource { } } -impl<'de> Deserialize<'de> for BundleResource { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - api_version: String, - #[serde(rename = "type")] - resource_type: ResourceTypeName, - metadata: BundleResourceMetadata, - spec: CanonicalJsonObject, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + BundleResource, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + api_version: String, + #[serde(rename = "type")] + resource_type: ResourceTypeName, + metadata: BundleResourceMetadata, + spec: CanonicalJsonObject, + }, + wire, + { if wire.api_version != d2b_contracts_resource::v3::resource::RESOURCE_API_VERSION { return Err(serde::de::Error::custom( "bundle resource apiVersion mismatch", )); } - Self::new(wire.resource_type, wire.metadata, wire.spec).map_err(serde::de::Error::custom) + Self::new(wire.resource_type, wire.metadata, wire.spec) + .map_err(serde::de::Error::custom) } -} +); fn is_false(value: &bool) -> bool { !*value @@ -456,40 +455,38 @@ impl core::fmt::Debug for ProcessTemplateBinding { } } -impl<'de> Deserialize<'de> for ProcessTemplateBinding { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - process_ref: ResourceRef, - owner_ref: ResourceRef, - execution_ref: ResourceRef, - template: BoundedToken, - artifact_id: ArtifactId, - binary_ref: BinaryRef, - artifact_digest: ArtifactDigest, - binary_path: String, - #[serde(default)] - dynamic: bool, - #[serde(default)] - launch_args: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new_inner( - wire.process_ref, - wire.owner_ref, - wire.execution_ref, - wire.template, - wire.artifact_id, - wire.binary_ref, - wire.artifact_digest, - wire.binary_path, - wire.dynamic, - wire.launch_args, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ProcessTemplateBinding, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + process_ref: ResourceRef, + owner_ref: ResourceRef, + execution_ref: ResourceRef, + template: BoundedToken, + artifact_id: ArtifactId, + binary_ref: BinaryRef, + artifact_digest: ArtifactDigest, + binary_path: String, + #[serde(default)] + dynamic: bool, + #[serde(default)] + launch_args: bool, + }, + wire, + Self::new_inner( + wire.process_ref, + wire.owner_ref, + wire.execution_ref, + wire.template, + wire.artifact_id, + wire.binary_ref, + wire.artifact_digest, + wire.binary_path, + wire.dynamic, + wire.launch_args, + ) + .map_err(serde::de::Error::custom) +); /// Private integrity metadata carried alongside the public resource array. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs index d1a876d1d..c10498cf2 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs @@ -6,7 +6,7 @@ //! outside this resource contract. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use d2b_contracts_provider::v3::provider::{ Exportability, ProjectionFactory, ProviderContractError, @@ -216,34 +216,28 @@ impl ShareQuota { } } -impl<'de> Deserialize<'de> for ShareQuota { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - max_consumers: Option, - #[serde(default)] - per_consumer_rate: Option, - #[serde(default)] - fairness: ShareFairness, - #[serde(default)] - lease_deadline_ms: Option, - } - - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.max_consumers, - wire.per_consumer_rate, - wire.fairness, - wire.lease_deadline_ms, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ShareQuota, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + max_consumers: Option, + #[serde(default)] + per_consumer_rate: Option, + #[serde(default)] + fairness: ShareFairness, + #[serde(default)] + lease_deadline_ms: Option, + }, + wire, + Self::new( + wire.max_consumers, + wire.per_consumer_rate, + wire.fairness, + wire.lease_deadline_ms, + ) + .map_err(serde::de::Error::custom) +); /// Consumer-Zone and capability ceiling carried by an export. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -303,23 +297,18 @@ impl core::fmt::Debug for ConsumerZonePolicy { } } -impl<'de> Deserialize<'de> for ConsumerZonePolicy { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - zones: Vec, - #[serde(default)] - capability_ceiling: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.zones, wire.capability_ceiling).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ConsumerZonePolicy, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + zones: Vec, + #[serde(default)] + capability_ceiling: Vec, + }, + wire, + Self::new(wire.zones, wire.capability_ceiling).map_err(serde::de::Error::custom) +); /// Export deletion and ZoneLink-loss policy. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, JsonSchema)] @@ -355,23 +344,18 @@ impl RevocationPolicy { } } -impl<'de> Deserialize<'de> for RevocationPolicy { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - grace_period_ms: u64, - #[serde(default)] - force_revoke: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.grace_period_ms, wire.force_revoke).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + RevocationPolicy, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + grace_period_ms: u64, + #[serde(default)] + force_revoke: bool, + }, + wire, + Self::new(wire.grace_period_ms, wire.force_revoke).map_err(serde::de::Error::custom) +); /// The provider-neutral desired state of one owner-Zone export. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -535,11 +519,7 @@ impl ResourceExportSpec { if target.resource_type() != &self.service_type { return Err(ResourceExportContractError::WrongResourceType); } - let target_ref = ResourceRef::new( - target.resource_type().clone(), - target.metadata().name().clone(), - ); - if target_ref != self.resource_ref { + if ResourceRef::from(target) != self.resource_ref { return Err(ResourceExportContractError::ResourceReferenceMismatch); } Ok(()) @@ -576,44 +556,39 @@ impl core::fmt::Debug for ResourceExportSpec { } } -impl<'de> Deserialize<'de> for ResourceExportSpec { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - resource_ref: ResourceRef, - service_type: ResourceTypeName, - projection_schema_fingerprint: SchemaFingerprint, - factory_fingerprint: SchemaFingerprint, - operations: Vec, - arbitration: ExportArbitration, - #[serde(default)] - quota: ShareQuota, - consumer_zone_policy: ConsumerZonePolicy, - #[serde(default = "default_export_visibility")] - visibility: ExportVisibility, - #[serde(default)] - revocation_policy: RevocationPolicy, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.resource_ref, - wire.service_type, - wire.projection_schema_fingerprint, - wire.factory_fingerprint, - wire.operations, - wire.arbitration, - wire.quota, - wire.consumer_zone_policy, - wire.visibility, - wire.revocation_policy, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ResourceExportSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + resource_ref: ResourceRef, + service_type: ResourceTypeName, + projection_schema_fingerprint: SchemaFingerprint, + factory_fingerprint: SchemaFingerprint, + operations: Vec, + arbitration: ExportArbitration, + #[serde(default)] + quota: ShareQuota, + consumer_zone_policy: ConsumerZonePolicy, + #[serde(default = "default_export_visibility")] + visibility: ExportVisibility, + #[serde(default)] + revocation_policy: RevocationPolicy, + }, + wire, + Self::new( + wire.resource_ref, + wire.service_type, + wire.projection_schema_fingerprint, + wire.factory_fingerprint, + wire.operations, + wire.arbitration, + wire.quota, + wire.consumer_zone_policy, + wire.visibility, + wire.revocation_policy, + ) + .map_err(serde::de::Error::custom) +); /// ResourceExport lifecycle state projected into `status.resource`. #[derive( diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs index 0c5731474..a93030058 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs @@ -6,7 +6,7 @@ //! remote ResourceRef, a transport locator, a descriptor, or a grant. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use super::resource_export::{ResourceExportSpec, ShareQuota, is_qualified_service_type}; use d2b_contracts_provider::v3::provider::{ @@ -353,41 +353,36 @@ impl core::fmt::Debug for ResourceImportSpec { } } -impl<'de> Deserialize<'de> for ResourceImportSpec { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - zone_link_ref: ResourceRef, - export_key: BoundedText, - expected_service_type: ResourceTypeName, - expected_projection_schema_fingerprint: SchemaFingerprint, - expected_factory_fingerprint: SchemaFingerprint, - projection_name: ResourceName, - requested_capabilities: Vec, - #[serde(default)] - requested_quota: ShareQuota, - #[serde(default)] - disconnect_policy: ImportDisconnectPolicy, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.zone_link_ref, - wire.export_key, - wire.expected_service_type, - wire.expected_projection_schema_fingerprint, - wire.expected_factory_fingerprint, - wire.projection_name, - wire.requested_capabilities, - wire.requested_quota, - wire.disconnect_policy, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ResourceImportSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + zone_link_ref: ResourceRef, + export_key: BoundedText, + expected_service_type: ResourceTypeName, + expected_projection_schema_fingerprint: SchemaFingerprint, + expected_factory_fingerprint: SchemaFingerprint, + projection_name: ResourceName, + requested_capabilities: Vec, + #[serde(default)] + requested_quota: ShareQuota, + #[serde(default)] + disconnect_policy: ImportDisconnectPolicy, + }, + wire, + Self::new( + wire.zone_link_ref, + wire.export_key, + wire.expected_service_type, + wire.expected_projection_schema_fingerprint, + wire.expected_factory_fingerprint, + wire.projection_name, + wire.requested_capabilities, + wire.requested_quota, + wire.disconnect_policy, + ) + .map_err(serde::de::Error::custom) +); fn quota_fits(requested: ShareQuota, exported: ShareQuota) -> bool { bounded_option_fits(requested.max_consumers(), exported.max_consumers()) diff --git a/packages/d2b-contracts-zone-session/src/v3/role.rs b/packages/d2b-contracts-zone-session/src/v3/role.rs index ffa598fe6..88e382a8e 100644 --- a/packages/d2b-contracts-zone-session/src/v3/role.rs +++ b/packages/d2b-contracts-zone-session/src/v3/role.rs @@ -5,7 +5,7 @@ //! never be smuggled into CRUD by treating all verbs as strings. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use d2b_contracts_resource::v3::{ ResourceName, ResourceRef, ResourceTypeName, ZoneId, execution_policy::{ BoundedText, BoundedToken, MAX_PATH_BYTES, parsed_deserialize, redacted_debug, @@ -400,38 +400,36 @@ impl RoleRule { redacted_debug!(RoleRule); -impl<'de> Deserialize<'de> for RoleRule { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - resource_types: Vec, - #[serde(default)] - verbs: Vec, - #[serde(default)] - subresources: Vec, - #[serde(default)] - resource_names: Vec, - #[serde(default)] - zones: Vec, - #[serde(default)] - execution_refs: Vec, - #[serde(default)] - session_verbs: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.resource_types, - wire.verbs, - wire.subresources, - wire.resource_names, - wire.zones, - wire.execution_refs, - wire.session_verbs, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + RoleRule, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + resource_types: Vec, + #[serde(default)] + verbs: Vec, + #[serde(default)] + subresources: Vec, + #[serde(default)] + resource_names: Vec, + #[serde(default)] + zones: Vec, + #[serde(default)] + execution_refs: Vec, + #[serde(default)] + session_verbs: Vec, + }, + wire, + Self::new( + wire.resource_types, + wire.verbs, + wire.subresources, + wire.resource_names, + wire.zones, + wire.execution_refs, + wire.session_verbs, + ) + .map_err(serde::de::Error::custom) +); fn duplicate(values: &[T]) -> bool { values.windows(2).any(|pair| pair[0] == pair[1]) @@ -728,37 +726,35 @@ impl RolePosture { redacted_debug!(RolePosture); -impl<'de> Deserialize<'de> for RolePosture { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - seccomp_ref: ResourceRef, - principal_ref: PrincipalRef, - #[serde(default)] - capabilities: Vec, - #[serde(default)] - namespaces: RoleNamespaces, - #[serde(default)] - mounts: Vec, - #[serde(default)] - umask: Option, - #[serde(default)] - user_ns: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.seccomp_ref, - wire.principal_ref, - wire.capabilities, - wire.namespaces, - wire.mounts, - wire.umask, - wire.user_ns, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + RolePosture, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + seccomp_ref: ResourceRef, + principal_ref: PrincipalRef, + #[serde(default)] + capabilities: Vec, + #[serde(default)] + namespaces: RoleNamespaces, + #[serde(default)] + mounts: Vec, + #[serde(default)] + umask: Option, + #[serde(default)] + user_ns: bool, + }, + wire, + Self::new( + wire.seccomp_ref, + wire.principal_ref, + wire.capabilities, + wire.namespaces, + wire.mounts, + wire.umask, + wire.user_ns, + ) + .map_err(serde::de::Error::custom) +); /// The complete Role desired state. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -830,29 +826,27 @@ impl RoleSpec { redacted_debug!(RoleSpec); -impl<'de> Deserialize<'de> for RoleSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - rules: Vec, - #[serde(default)] - operation_refs: Vec, - #[serde(default)] - command_refs: Vec, - #[serde(default)] - posture: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::with_facets( - wire.rules, - wire.operation_refs, - wire.command_refs, - wire.posture, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + RoleSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + rules: Vec, + #[serde(default)] + operation_refs: Vec, + #[serde(default)] + command_refs: Vec, + #[serde(default)] + posture: Option, + }, + wire, + Self::with_facets( + wire.rules, + wire.operation_refs, + wire.command_refs, + wire.posture, + ) + .map_err(serde::de::Error::custom) +); /// Closed Role condition names. #[derive( diff --git a/packages/d2b-contracts-zone-session/src/v3/role_binding.rs b/packages/d2b-contracts-zone-session/src/v3/role_binding.rs index a01a50530..76966ec52 100644 --- a/packages/d2b-contracts-zone-session/src/v3/role_binding.rs +++ b/packages/d2b-contracts-zone-session/src/v3/role_binding.rs @@ -202,16 +202,15 @@ fn narrowing_set_is_subset( redacted_debug!(ScopeNarrowing); -impl<'de> Deserialize<'de> for ScopeNarrowing { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - rules: Vec, - } - Self::new(Wire::deserialize(deserializer)?.rules).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ScopeNarrowing, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + rules: Vec, + }, + wire, + Self::new(wire.rules).map_err(serde::de::Error::custom) +); /// Authority that created a relay-bearing binding. /// @@ -392,41 +391,39 @@ impl RoleBindingSpec { redacted_debug!(RoleBindingSpec); -impl<'de> Deserialize<'de> for RoleBindingSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - role_ref: ResourceRef, - #[serde(default)] - subjects: Vec, - #[serde(default)] - external_principal_selector: Option, - #[serde(default)] - scope_narrowing: Option, - #[serde(default)] - resource_refs: Vec, - #[serde(default)] - zone_refs: Vec, - #[serde(default)] - execution_refs: Vec, - #[serde(default)] - relay_authority: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::with_facets( - wire.role_ref, - wire.subjects, - wire.external_principal_selector, - wire.scope_narrowing, - wire.resource_refs, - wire.zone_refs, - wire.execution_refs, - wire.relay_authority, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + RoleBindingSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + role_ref: ResourceRef, + #[serde(default)] + subjects: Vec, + #[serde(default)] + external_principal_selector: Option, + #[serde(default)] + scope_narrowing: Option, + #[serde(default)] + resource_refs: Vec, + #[serde(default)] + zone_refs: Vec, + #[serde(default)] + execution_refs: Vec, + #[serde(default)] + relay_authority: Option, + }, + wire, + Self::with_facets( + wire.role_ref, + wire.subjects, + wire.external_principal_selector, + wire.scope_narrowing, + wire.resource_refs, + wire.zone_refs, + wire.execution_refs, + wire.relay_authority, + ) + .map_err(serde::de::Error::custom) +); /// Closed RoleBinding condition names. #[derive( diff --git a/packages/d2b-contracts-zone-session/src/v3/services.rs b/packages/d2b-contracts-zone-session/src/v3/services.rs index fd5872710..74228ebc8 100644 --- a/packages/d2b-contracts-zone-session/src/v3/services.rs +++ b/packages/d2b-contracts-zone-session/src/v3/services.rs @@ -5,7 +5,7 @@ //! removing, or renaming a method cannot be mistaken for the old service. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use d2b_contracts_resource::v3::identity::ServiceName; @@ -262,17 +262,18 @@ impl ServiceDescriptor { redacted_debug!(ServiceDescriptor); -impl<'de> Deserialize<'de> for ServiceDescriptor { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - package: ServiceName, - methods: Vec, - fingerprint: SchemaFingerprint, - } - let wire = Wire::deserialize(deserializer)?; - let descriptor = Self::new(wire.package, wire.methods).map_err(serde::de::Error::custom)?; +wire_deserialize!( + ServiceDescriptor, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + package: ServiceName, + methods: Vec, + fingerprint: SchemaFingerprint, + }, + wire, + { + let descriptor = Self::new(wire.package, wire.methods) + .map_err(serde::de::Error::custom)?; if descriptor.fingerprint != wire.fingerprint { return Err(serde::de::Error::custom( ServiceDescriptorError::FingerprintMismatch, @@ -280,7 +281,7 @@ impl<'de> Deserialize<'de> for ServiceDescriptor { } Ok(descriptor) } -} +); fn fingerprint( package: &ServiceName, diff --git a/packages/d2b-contracts-zone-session/src/v3/zone.rs b/packages/d2b-contracts-zone-session/src/v3/zone.rs index a550e14a0..e971e9b9e 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone.rs @@ -7,7 +7,7 @@ //! parent topology, policy, or implementation settings into the self row. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use d2b_contracts_resource::v3::{ ResourceName, ResourcePhase, ResourceRef, ResourceUid, Timestamp, ZoneId, @@ -71,15 +71,13 @@ impl ZoneSpec { } } -impl<'de> Deserialize<'de> for ZoneSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(deny_unknown_fields)] - struct Wire {} - let _ = Wire::deserialize(deserializer)?; - Ok(Self::new()) - } -} +wire_deserialize!( + ZoneSpec, + #[serde(deny_unknown_fields)] + Wire {}, + wire, + { let _ = wire; Ok(Self::new()) } +); /// A fixed handler phase projected by the Zone controller. #[derive( @@ -164,19 +162,17 @@ impl ZoneHandlerStatus { redacted_debug!(ZoneHandlerStatus); -impl<'de> Deserialize<'de> for ZoneHandlerStatus { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - name: ZoneHandlerName, - last_reconciled_at: Option, - phase: ZoneHandlerPhase, - } - let wire = Wire::deserialize(deserializer)?; - Ok(Self::new(wire.name, wire.phase, wire.last_reconciled_at)) - } -} +wire_deserialize!( + ZoneHandlerStatus, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + name: ZoneHandlerName, + last_reconciled_at: Option, + phase: ZoneHandlerPhase, + }, + wire, + Ok(Self::new(wire.name, wire.phase, wire.last_reconciled_at)) +); /// The ResourceType-common Zone status layer. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -319,40 +315,38 @@ impl ZoneStatusResource { redacted_debug!(ZoneStatusResource); -impl<'de> Deserialize<'de> for ZoneStatusResource { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - api_catalog_revision: u64, - policy_revision: u64, - configuration_revision: u64, - core_controller_phase: ResourcePhase, - handlers: Vec, - installed_provider_count: u32, - ready_provider_count: u32, - total_resource_count: u32, - active_configuration_generation: u64, - generation_cleanup_pending: bool, - cleanup_pending_count: u32, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.api_catalog_revision, - wire.policy_revision, - wire.configuration_revision, - wire.core_controller_phase, - wire.handlers, - wire.installed_provider_count, - wire.ready_provider_count, - wire.total_resource_count, - wire.active_configuration_generation, - wire.generation_cleanup_pending, - wire.cleanup_pending_count, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneStatusResource, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + api_catalog_revision: u64, + policy_revision: u64, + configuration_revision: u64, + core_controller_phase: ResourcePhase, + handlers: Vec, + installed_provider_count: u32, + ready_provider_count: u32, + total_resource_count: u32, + active_configuration_generation: u64, + generation_cleanup_pending: bool, + cleanup_pending_count: u32, + }, + wire, + Self::new( + wire.api_catalog_revision, + wire.policy_revision, + wire.configuration_revision, + wire.core_controller_phase, + wire.handlers, + wire.installed_provider_count, + wire.ready_provider_count, + wire.total_resource_count, + wire.active_configuration_generation, + wire.generation_cleanup_pending, + wire.cleanup_pending_count, + ) + .map_err(serde::de::Error::custom) +); /// Alias used by generic ResourceType status adapters. pub type ZoneStatus = ZoneStatusResource; diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_link.rs b/packages/d2b-contracts-zone-session/src/v3/zone_link.rs index 97240afae..560501089 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_link.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_link.rs @@ -7,7 +7,7 @@ //! credential bytes can be represented here. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use d2b_contracts_resource::v3::{ CanonicalJsonObject, ResourceRef, ResourceUid, Timestamp, ZoneId, @@ -129,30 +129,28 @@ impl Default for ZoneLinkLimits { } } -impl<'de> Deserialize<'de> for ZoneLinkLimits { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default = "default_pending")] - max_pending_intents: u32, - #[serde(default = "default_streams")] - max_active_streams: u32, - #[serde(default = "default_attempts")] - reconnect_max_attempts: u32, - #[serde(default = "default_window")] - reconnect_window_secs: u32, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.max_pending_intents, - wire.max_active_streams, - wire.reconnect_max_attempts, - wire.reconnect_window_secs, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneLinkLimits, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default = "default_pending")] + max_pending_intents: u32, + #[serde(default = "default_streams")] + max_active_streams: u32, + #[serde(default = "default_attempts")] + reconnect_max_attempts: u32, + #[serde(default = "default_window")] + reconnect_window_secs: u32, + }, + wire, + Self::new( + wire.max_pending_intents, + wire.max_active_streams, + wire.reconnect_max_attempts, + wire.reconnect_window_secs, + ) + .map_err(serde::de::Error::custom) +); const fn default_pending() -> u32 { 256 @@ -272,34 +270,32 @@ impl ZoneLinkSpec { redacted_debug!(ZoneLinkSpec); -impl<'de> Deserialize<'de> for ZoneLinkSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - child_zone_name: ZoneId, - transport_provider_ref: ResourceRef, - #[serde(default)] - transport_settings: CanonicalJsonObject, - #[serde(default)] - transport_credentials: Vec, - #[serde(default)] - disabled: bool, - #[serde(default)] - limits: ZoneLinkLimits, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.child_zone_name, - wire.transport_provider_ref, - wire.transport_settings, - wire.transport_credentials, - wire.disabled, - wire.limits, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneLinkSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + child_zone_name: ZoneId, + transport_provider_ref: ResourceRef, + #[serde(default)] + transport_settings: CanonicalJsonObject, + #[serde(default)] + transport_credentials: Vec, + #[serde(default)] + disabled: bool, + #[serde(default)] + limits: ZoneLinkLimits, + }, + wire, + Self::new( + wire.child_zone_name, + wire.transport_provider_ref, + wire.transport_settings, + wire.transport_credentials, + wire.disabled, + wire.limits, + ) + .map_err(serde::de::Error::custom) +); /// Closed ZoneLink condition names. #[derive( @@ -405,40 +401,38 @@ fn ordered(left: Option, right: Option) -> bool { redacted_debug!(ZoneLinkStatusResource); -impl<'de> Deserialize<'de> for ZoneLinkStatusResource { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - child_zone_uid: Option, - connected: bool, - last_connected_at: Option, - last_disconnected_at: Option, - last_sent_revision: Option, - last_acked_revision: Option, - last_received_revision: Option, - last_applied_revision: Option, - link_epoch: u64, - pending_local_intents: u32, - child_authorized: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.child_zone_uid, - wire.connected, - wire.last_connected_at, - wire.last_disconnected_at, - wire.last_sent_revision, - wire.last_acked_revision, - wire.last_received_revision, - wire.last_applied_revision, - wire.link_epoch, - wire.pending_local_intents, - wire.child_authorized, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneLinkStatusResource, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + child_zone_uid: Option, + connected: bool, + last_connected_at: Option, + last_disconnected_at: Option, + last_sent_revision: Option, + last_acked_revision: Option, + last_received_revision: Option, + last_applied_revision: Option, + link_epoch: u64, + pending_local_intents: u32, + child_authorized: bool, + }, + wire, + Self::new( + wire.child_zone_uid, + wire.connected, + wire.last_connected_at, + wire.last_disconnected_at, + wire.last_sent_revision, + wire.last_acked_revision, + wire.last_received_revision, + wire.last_applied_revision, + wire.link_epoch, + wire.pending_local_intents, + wire.child_authorized, + ) + .map_err(serde::de::Error::custom) +); /// Record admission of one locally queued intent. pub const fn admit_local_intent( diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs b/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs index eaf88de47..1e08b972f 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs @@ -555,18 +555,16 @@ impl ZoneTreeEdge { redacted_debug!(ZoneTreeEdge); -impl<'de> Deserialize<'de> for ZoneTreeEdge { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - parent: ZonePath, - child: ZonePath, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.parent, wire.child).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneTreeEdge, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + parent: ZonePath, + child: ZonePath, + }, + wire, + Self::new(wire.parent, wire.child).map_err(serde::de::Error::custom) +); /// One descendant route advertised by a child Zone controller. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -621,25 +619,23 @@ impl ZoneDescendantRoute { redacted_debug!(ZoneDescendantRoute); -impl<'de> Deserialize<'de> for ZoneDescendantRoute { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - route_id: ZoneRouteId, - descendant: ZonePath, - next_hop_child: ZoneLabelId, - capabilities: ZoneRouteCapabilitySet, - } - let wire = Wire::deserialize(deserializer)?; - Ok(Self::new( - wire.route_id, - wire.descendant, - wire.next_hop_child, - wire.capabilities, - )) - } -} +wire_deserialize!( + ZoneDescendantRoute, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + route_id: ZoneRouteId, + descendant: ZonePath, + next_hop_child: ZoneLabelId, + capabilities: ZoneRouteCapabilitySet, + }, + wire, + Ok(Self::new( + wire.route_id, + wire.descendant, + wire.next_hop_child, + wire.capabilities, + )) +); /// A signed, expiring, descendant-only route advertisement. /// @@ -815,34 +811,32 @@ impl ZoneLinkRouteAdvertisement { redacted_debug!(ZoneLinkRouteAdvertisement); -impl<'de> Deserialize<'de> for ZoneLinkRouteAdvertisement { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - schema_version: u32, - advertising_zone: ZonePath, - tree_edge: ZoneTreeEdge, - controller_generation: ZoneLinkControllerGeneration, - routes: Vec, - issued_at_unix_seconds: u64, - expires_at_unix_seconds: u64, - signature: ZoneRouteSignature, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.schema_version, - wire.advertising_zone, - wire.tree_edge, - wire.controller_generation, - wire.routes, - wire.issued_at_unix_seconds, - wire.expires_at_unix_seconds, - wire.signature, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneLinkRouteAdvertisement, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + schema_version: u32, + advertising_zone: ZonePath, + tree_edge: ZoneTreeEdge, + controller_generation: ZoneLinkControllerGeneration, + routes: Vec, + issued_at_unix_seconds: u64, + expires_at_unix_seconds: u64, + signature: ZoneRouteSignature, + }, + wire, + Self::new( + wire.schema_version, + wire.advertising_zone, + wire.tree_edge, + wire.controller_generation, + wire.routes, + wire.issued_at_unix_seconds, + wire.expires_at_unix_seconds, + wire.signature, + ) + .map_err(serde::de::Error::custom) +); /// A signed withdrawal removing an exact set of advertised routes. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -930,30 +924,28 @@ impl ZoneLinkRouteWithdrawal { redacted_debug!(ZoneLinkRouteWithdrawal); -impl<'de> Deserialize<'de> for ZoneLinkRouteWithdrawal { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - schema_version: u32, - advertising_zone: ZonePath, - controller_generation: ZoneLinkControllerGeneration, - withdrawn_route_ids: Vec, - issued_at_unix_seconds: u64, - signature: ZoneRouteSignature, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.schema_version, - wire.advertising_zone, - wire.controller_generation, - wire.withdrawn_route_ids, - wire.issued_at_unix_seconds, - wire.signature, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneLinkRouteWithdrawal, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + schema_version: u32, + advertising_zone: ZonePath, + controller_generation: ZoneLinkControllerGeneration, + withdrawn_route_ids: Vec, + issued_at_unix_seconds: u64, + signature: ZoneRouteSignature, + }, + wire, + Self::new( + wire.schema_version, + wire.advertising_zone, + wire.controller_generation, + wire.withdrawn_route_ids, + wire.issued_at_unix_seconds, + wire.signature, + ) + .map_err(serde::de::Error::custom) +); /// The route namespace a parent allocator delegates to one direct child edge. /// @@ -1041,28 +1033,26 @@ impl ZoneLinkNamespaceAllocation { redacted_debug!(ZoneLinkNamespaceAllocation); -impl<'de> Deserialize<'de> for ZoneLinkNamespaceAllocation { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - tree_edge: ZoneTreeEdge, - allocated_to_generation: ZoneLinkControllerGeneration, - allowed_prefixes: Vec, - max_routes: u32, - allowed_capabilities: ZoneRouteCapabilitySet, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.tree_edge, - wire.allocated_to_generation, - wire.allowed_prefixes, - wire.max_routes, - wire.allowed_capabilities, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneLinkNamespaceAllocation, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + tree_edge: ZoneTreeEdge, + allocated_to_generation: ZoneLinkControllerGeneration, + allowed_prefixes: Vec, + max_routes: u32, + allowed_capabilities: ZoneRouteCapabilitySet, + }, + wire, + Self::new( + wire.tree_edge, + wire.allocated_to_generation, + wire.allowed_prefixes, + wire.max_routes, + wire.allowed_capabilities, + ) + .map_err(serde::de::Error::custom) +); /// Direction of one hop along the Zone tree. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] @@ -1140,23 +1130,21 @@ impl ZoneRouteHop { redacted_debug!(ZoneRouteHop); -impl<'de> Deserialize<'de> for ZoneRouteHop { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - from: ZonePath, - to: ZonePath, - edge: ZoneTreeEdge, - direction: ZoneRouteHopDirection, - #[serde(default)] - route_id: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.from, wire.to, wire.edge, wire.direction, wire.route_id) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneRouteHop, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + from: ZonePath, + to: ZonePath, + edge: ZoneTreeEdge, + direction: ZoneRouteHopDirection, + #[serde(default)] + route_id: Option, + }, + wire, + Self::new(wire.from, wire.to, wire.edge, wire.direction, wire.route_id) + .map_err(serde::de::Error::custom) +); /// The immutable result of one Zone route decision. /// @@ -1244,26 +1232,24 @@ impl ZoneRoutePath { redacted_debug!(ZoneRoutePath); -impl<'de> Deserialize<'de> for ZoneRoutePath { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - source_zone: ZonePath, - target_zone: ZonePath, - nearest_common_ancestor: ZonePath, - hops: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.source_zone, - wire.target_zone, - wire.nearest_common_ancestor, - wire.hops, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneRoutePath, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + source_zone: ZonePath, + target_zone: ZonePath, + nearest_common_ancestor: ZonePath, + hops: Vec, + }, + wire, + Self::new( + wire.source_zone, + wire.target_zone, + wire.nearest_common_ancestor, + wire.hops, + ) + .map_err(serde::de::Error::custom) +); /// The closed fail-closed reason for a refused route decision, advertisement, /// or relay hop. diff --git a/packages/d2b-session/src/admission.rs b/packages/d2b-session/src/admission.rs index 12d515aff..6620a4e96 100644 --- a/packages/d2b-session/src/admission.rs +++ b/packages/d2b-session/src/admission.rs @@ -590,7 +590,7 @@ impl SessionAcceptor { + Send + 'static, { - HandshakeOffer::from(policy.clone()) + HandshakeOffer::from(&policy) .validate() .map_err(SessionError::from)?; Ok(Self { diff --git a/packages/d2b-session/src/engine.rs b/packages/d2b-session/src/engine.rs index c779c6584..5b84152e9 100644 --- a/packages/d2b-session/src/engine.rs +++ b/packages/d2b-session/src/engine.rs @@ -674,7 +674,7 @@ pub async fn establish_initiator( &mut self, policy: &EndpointPolicy, ) -> Result { - if self.offer != HandshakeOffer::from(policy.clone()) { + if self.offer != HandshakeOffer::from(policy) { return Err(SessionError::new(SessionErrorCode::PolicyDenied)); } self.authentication diff --git a/packages/d2b-session/src/handshake.rs b/packages/d2b-session/src/handshake.rs index f2e9f24f6..cca983255 100644 --- a/packages/d2b-session/src/handshake.rs +++ b/packages/d2b-session/src/handshake.rs @@ -140,7 +140,7 @@ impl fmt::Debug for NegotiatedOffer { /// Returns the preface or canonical-encoding error when the policy cannot /// be rendered on the wire. pub fn encode_offer(policy: &EndpointPolicy) -> Result<([u8; PREFACE_LEN], Vec)> { - let offer = HandshakeOffer::from(policy.clone()); + let offer = HandshakeOffer::from(policy); let canonical = offer.encode_canonical()?; let preface = ComponentSessionPreface::new(canonical.len()) .map_err(preface_error)? @@ -221,7 +221,7 @@ pub fn accept_generation_discovery_request( identity .validate_exact(policy) .map_err(SessionError::from)?; - HandshakeOffer::from(policy.clone()) + HandshakeOffer::from(policy) .validate() .map_err(SessionError::from)?; Ok(Sha256::digest(bytes).into()) From f3028c0ee0341bf2e7cb3707d4d29c0c84b0d4f4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:37:12 -0700 Subject: [PATCH 572/726] d2bd: propagate manager RPC failures in credential dependency facts --- changelog.d/w4-15-credential-facts-error.md | 6 +++ packages/d2bd/src/resource_runtime.rs | 47 +++++++++++++++++---- 2 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 changelog.d/w4-15-credential-facts-error.md diff --git a/changelog.d/w4-15-credential-facts-error.md b/changelog.d/w4-15-credential-facts-error.md new file mode 100644 index 000000000..64048bc33 --- /dev/null +++ b/changelog.d/w4-15-credential-facts-error.md @@ -0,0 +1,6 @@ +### Fixed + +- A transient manager read failure during a credential dependency-facts probe + is no longer silently reported as missing dependency facts; the daemon now + logs the failure with the zone, provider, and execution refs instead of + degrading credential readiness and revocation decisions without a trace. \ No newline at end of file diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 89713c5db..0546586c9 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -366,22 +366,31 @@ async fn credential_dependency_facts( plane: &dyn ControllerPlaneView, provider_ref: &ResourceRef, execution_ref: &ResourceRef, -) -> Option { - let provider = credential_dependency_row(plane, provider_ref).await?; - let execution = credential_dependency_row(plane, execution_ref).await?; - Some(CredentialDependencyFacts { +) -> Result, ResourceRuntimeError> { + let Some(provider) = credential_dependency_row(plane, provider_ref).await? else { + return Ok(None); + }; + let Some(execution) = credential_dependency_row(plane, execution_ref).await? else { + return Ok(None); + }; + Ok(Some(CredentialDependencyFacts { provider_uid: provider.uid.as_str().to_owned(), provider_generation: provider.generation.get(), provider_ready: credential_row_ready(&provider), execution_ready: credential_row_ready(&execution), - }) + })) } +/// One credential dependency row read from its authority (the manager). +/// +/// A manager RPC failure is an error - never reported as absence +/// (`bridge_manager_row`'s contract); `Ok(None)` is the honest +/// not-committed answer. async fn credential_dependency_row( plane: &dyn ControllerPlaneView, target: &ResourceRef, -) -> Option { - bridge_manager_row(plane, target).await.ok().flatten() +) -> Result, ResourceRuntimeError> { + bridge_manager_row(plane, target).await } @@ -4472,8 +4481,28 @@ impl ZoneResourceRuntime { let provider_ref = provider_ref.clone(); let execution_ref = execution_ref.clone(); Box::pin(async move { - let plane = published_plane_view(&planes, &zone)?; - credential_dependency_facts(plane.as_ref(), &provider_ref, &execution_ref).await + let Some(plane) = published_plane_view(&planes, &zone) else { + return None; + }; + match credential_dependency_facts( + plane.as_ref(), + &provider_ref, + &execution_ref, + ) + .await + { + Ok(facts) => facts, + Err(error) => { + tracing::warn!( + zone = %zone, + provider = %provider_ref, + execution = %execution_ref, + error = %error, + "credential dependency facts: manager read failed", + ); + None + } + } }) }), lease: Arc::new(|_credential_ref: &ResourceRef| Box::pin(async { None })), From 2f034e476e83937827a321c2c34df6ae51e0e9eb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:37:32 -0700 Subject: [PATCH 573/726] session: document SentPacket::acknowledge drop semantics --- changelog.d/w4-21-sent-packet-acknowledge-doc.md | 3 +++ packages/d2b-session-unix/src/socket.rs | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 changelog.d/w4-21-sent-packet-acknowledge-doc.md diff --git a/changelog.d/w4-21-sent-packet-acknowledge-doc.md b/changelog.d/w4-21-sent-packet-acknowledge-doc.md new file mode 100644 index 000000000..589430328 --- /dev/null +++ b/changelog.d/w4-21-sent-packet-acknowledge-doc.md @@ -0,0 +1,3 @@ +### Fixed + +- `SentPacket::acknowledge` now documents its drop-semantics contract: consuming a sent packet releases its credit reservations and retained attachment file descriptors. \ No newline at end of file diff --git a/packages/d2b-session-unix/src/socket.rs b/packages/d2b-session-unix/src/socket.rs index 85f51689f..a0020835d 100644 --- a/packages/d2b-session-unix/src/socket.rs +++ b/packages/d2b-session-unix/src/socket.rs @@ -173,6 +173,15 @@ impl fmt::Debug for SentPacket { } impl SentPacket { + /// Consume this sent packet, releasing everything it held. + /// + /// The body is intentionally empty: acknowledging a packet means + /// dropping it. Consuming the packet releases the credit + /// reservations made when the packet was built back to their + /// scopes (see [`CreditBundle`]) and drops the retained attachment + /// file descriptors. Every sent packet must be acknowledged once + /// its burst has been handed to the socket, so the credits it + /// reserved become available again. pub fn acknowledge(self) {} pub fn credits_mut(&mut self) -> &mut CreditBundle { From 5282e93375e5aff0eeffa3a4f9abb9d4d8f7172d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:38:12 -0700 Subject: [PATCH 574/726] core: return typed validation errors from storage and sync validators validate_unique_ids and validate_lock_order now return StorageValidationError and SyncValidationError carrying the wire reason and offending id, replacing the String messages that storage_lifecycle re-derived by string-prefix matching. The classifier functions are deleted; the provider-volume-local re-export and its classifier test are dropped. --- changelog.d/w4-17-typed-validation-errors.md | 6 + packages/d2b-core/src/storage.rs | 18 +- packages/d2b-core/src/storage_lifecycle.rs | 229 +++++++++++++----- packages/d2b-core/src/sync.rs | 26 +- .../src/diagnostics/storage_lifecycle.rs | 17 -- 5 files changed, 203 insertions(+), 93 deletions(-) create mode 100644 changelog.d/w4-17-typed-validation-errors.md diff --git a/changelog.d/w4-17-typed-validation-errors.md b/changelog.d/w4-17-typed-validation-errors.md new file mode 100644 index 000000000..c2f789e0a --- /dev/null +++ b/changelog.d/w4-17-typed-validation-errors.md @@ -0,0 +1,6 @@ +### Fixed + +- Storage and sync contract validation now reports a typed reason and the + offending id instead of an opaque message string, so lifecycle reports can + classify duplicate ids, restart policies, degraded reasons, and lock-order + violations without string-matching. \ No newline at end of file diff --git a/packages/d2b-core/src/storage.rs b/packages/d2b-core/src/storage.rs index 3525337cd..dc3964b84 100644 --- a/packages/d2b-core/src/storage.rs +++ b/packages/d2b-core/src/storage.rs @@ -4,6 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::contract_id::{ContractId, ContractText, PathTemplate}; +use crate::storage_lifecycle::StorageValidationError; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -354,27 +355,30 @@ pub struct RemediationSpec { } impl StorageJson { - pub fn validate_unique_ids(&self) -> Result<(), String> { + pub fn validate_unique_ids(&self) -> Result<(), StorageValidationError> { let mut ids = BTreeSet::new(); for path in &self.paths { if !ids.insert(path.id.as_str()) { - return Err(format!("duplicate storage path id {}", path.id)); + return Err(StorageValidationError::DuplicateStoragePathId { + offending_id: path.id.to_string(), + }); } } let mut restart_ids = BTreeSet::new(); for restart in &self.restart_policies { let key = (restart.vm.as_str(), restart.role_id.as_str()); if !restart_ids.insert(key) { - return Err(format!( - "duplicate restart policy for {}:{}", - restart.vm, restart.role_id - )); + return Err(StorageValidationError::DuplicateRestartPolicy { + offending_id: format!("{}:{}", restart.vm, restart.role_id), + }); } } let mut reasons = BTreeSet::new(); for state in &self.degraded_states { if !reasons.insert(state.reason) { - return Err(format!("duplicate degraded reason {:?}", state.reason)); + return Err(StorageValidationError::DuplicateDegradedReason { + offending_id: format!("{:?}", state.reason), + }); } } Ok(()) diff --git a/packages/d2b-core/src/storage_lifecycle.rs b/packages/d2b-core/src/storage_lifecycle.rs index b3bf45232..bc53e270a 100644 --- a/packages/d2b-core/src/storage_lifecycle.rs +++ b/packages/d2b-core/src/storage_lifecycle.rs @@ -1,6 +1,7 @@ //! Host-local storage lifecycle report DTOs. use std::collections::BTreeSet; +use std::fmt; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -108,78 +109,123 @@ pub enum SyncContractValidationReason { Unclassified, } -pub fn classify_storage_validation_reason(detail: &str) -> StorageContractValidationReason { - if detail.starts_with("duplicate storage path id ") { - StorageContractValidationReason::DuplicateStoragePathId - } else if detail.starts_with("duplicate restart policy for ") { - StorageContractValidationReason::DuplicateRestartPolicy - } else if detail.starts_with("duplicate degraded reason ") { - StorageContractValidationReason::DuplicateDegradedReason - } else { - StorageContractValidationReason::Unclassified - } +/// Typed failure from [`StorageJson::validate_unique_ids`](crate::storage::StorageJson::validate_unique_ids). +/// +/// Carries the offending id payload so a `StorageContractInvalid` issue can +/// be built without string-matching. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum StorageValidationError { + DuplicateStoragePathId { + offending_id: String, + }, + DuplicateRestartPolicy { + offending_id: String, + }, + DuplicateDegradedReason { + offending_id: String, + }, } -pub fn storage_validation_offending_id(detail: &str) -> Option { - if let Some(id) = detail.strip_prefix("duplicate storage path id ") { - bounded_contract_detail(id) - } else if let Some(id) = detail.strip_prefix("duplicate restart policy for ") { - bounded_contract_detail(id) - } else if let Some(id) = detail.strip_prefix("duplicate degraded reason ") { - bounded_contract_detail(id) - } else { - None +impl StorageValidationError { + /// The wire reason for the persisted lifecycle report. + pub fn reason(&self) -> StorageContractValidationReason { + match self { + Self::DuplicateStoragePathId { .. } => { + StorageContractValidationReason::DuplicateStoragePathId + } + Self::DuplicateRestartPolicy { .. } => { + StorageContractValidationReason::DuplicateRestartPolicy + } + Self::DuplicateDegradedReason { .. } => { + StorageContractValidationReason::DuplicateDegradedReason + } + } } } -pub fn classify_sync_validation_reason(detail: &str) -> SyncContractValidationReason { - if detail.starts_with("duplicate lock id ") { - SyncContractValidationReason::DuplicateLockId - } else if detail.starts_with("OFD lock ") && detail.ends_with(" must require O_CLOEXEC") { - SyncContractValidationReason::OfdLockMissingCloexec - } else if detail.starts_with("fd-passing lock ") - && detail.ends_with(" must require a lease transfer record") - { - SyncContractValidationReason::FdPassingMissingLeaseTransferRecord - } else if detail.starts_with("lock ") && detail.contains(" shares acquire order key with ") { - SyncContractValidationReason::DuplicateAcquireOrder - } else { - SyncContractValidationReason::Unclassified +impl fmt::Display for StorageValidationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::DuplicateStoragePathId { offending_id } => { + write!(f, "duplicate storage path id {offending_id}") + } + Self::DuplicateRestartPolicy { offending_id } => { + write!(f, "duplicate restart policy for {offending_id}") + } + Self::DuplicateDegradedReason { offending_id } => { + write!(f, "duplicate degraded reason {offending_id}") + } + } } } -pub fn sync_validation_offending_id(detail: &str) -> Option { - if let Some(id) = detail.strip_prefix("duplicate lock id ") { - bounded_contract_detail(id) - } else if let Some(rest) = detail.strip_prefix("OFD lock ") { - rest.strip_suffix(" must require O_CLOEXEC") - .and_then(bounded_contract_detail) - } else if let Some(rest) = detail.strip_prefix("fd-passing lock ") { - rest.strip_suffix(" must require a lease transfer record") - .and_then(bounded_contract_detail) - } else if let Some(rest) = detail.strip_prefix("lock ") { - rest.split_once(" shares acquire order key with ") - .and_then(|(id, _)| bounded_contract_detail(id)) - } else { - None +impl std::error::Error for StorageValidationError {} + +/// Typed failure from [`SyncJson::validate_lock_order`](crate::sync::SyncJson::validate_lock_order). +/// +/// Carries the offending id payload so a `SyncContractInvalid` issue can be +/// built without string-matching. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SyncValidationError { + DuplicateLockId { + offending_id: String, + }, + OfdLockMissingCloexec { + offending_id: String, + }, + FdPassingMissingLeaseTransferRecord { + offending_id: String, + }, + DuplicateAcquireOrder { + offending_id: String, + existing_id: String, + }, +} + +impl SyncValidationError { + /// The wire reason for the persisted lifecycle report. + pub fn reason(&self) -> SyncContractValidationReason { + match self { + Self::DuplicateLockId { .. } => SyncContractValidationReason::DuplicateLockId, + Self::OfdLockMissingCloexec { .. } => { + SyncContractValidationReason::OfdLockMissingCloexec + } + Self::FdPassingMissingLeaseTransferRecord { .. } => { + SyncContractValidationReason::FdPassingMissingLeaseTransferRecord + } + Self::DuplicateAcquireOrder { .. } => { + SyncContractValidationReason::DuplicateAcquireOrder + } + } } } -fn bounded_contract_detail(raw: &str) -> Option { - let trimmed = raw.trim(); - if trimmed.is_empty() - || trimmed.contains('/') - || trimmed.contains('\\') - || trimmed.len() > 128 - || !trimmed - .bytes() - .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b':' | b'-' | b'_' | b'.')) - { - return None; +impl fmt::Display for SyncValidationError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::DuplicateLockId { offending_id } => { + write!(f, "duplicate lock id {offending_id}") + } + Self::OfdLockMissingCloexec { offending_id } => { + write!(f, "OFD lock {offending_id} must require O_CLOEXEC") + } + Self::FdPassingMissingLeaseTransferRecord { offending_id } => write!( + f, + "fd-passing lock {offending_id} must require a lease transfer record" + ), + Self::DuplicateAcquireOrder { + offending_id, + existing_id, + } => write!( + f, + "lock {offending_id} shares acquire order key with {existing_id}" + ), + } } - Some(trimmed.to_owned()) } +impl std::error::Error for SyncValidationError {} + #[cfg(test)] mod tests { use serde_json::json; @@ -295,4 +341,71 @@ mod tests { "adoptable-missing-cgroup-leaf,legacy-bundle-contracts-unavailable,missing-restart-policy" ); } + + #[test] + fn validation_errors_map_to_wire_reasons() { + let storage_errors = [ + ( + StorageValidationError::DuplicateStoragePathId { + offending_id: "path:run-root".to_owned(), + }, + StorageContractValidationReason::DuplicateStoragePathId, + ), + ( + StorageValidationError::DuplicateRestartPolicy { + offending_id: "corp-vm:cloud-hypervisor".to_owned(), + }, + StorageContractValidationReason::DuplicateRestartPolicy, + ), + ( + StorageValidationError::DuplicateDegradedReason { + offending_id: "StorageDrift".to_owned(), + }, + StorageContractValidationReason::DuplicateDegradedReason, + ), + ]; + for (error, reason) in storage_errors { + assert_eq!(error.reason(), reason); + } + + let sync_errors = [ + ( + SyncValidationError::DuplicateLockId { + offending_id: "lock:daemon".to_owned(), + }, + SyncContractValidationReason::DuplicateLockId, + ), + ( + SyncValidationError::OfdLockMissingCloexec { + offending_id: "lock:daemon".to_owned(), + }, + SyncContractValidationReason::OfdLockMissingCloexec, + ), + ( + SyncValidationError::FdPassingMissingLeaseTransferRecord { + offending_id: "lock:daemon".to_owned(), + }, + SyncContractValidationReason::FdPassingMissingLeaseTransferRecord, + ), + ( + SyncValidationError::DuplicateAcquireOrder { + offending_id: "lock:second".to_owned(), + existing_id: "lock:first".to_owned(), + }, + SyncContractValidationReason::DuplicateAcquireOrder, + ), + ]; + for (error, reason) in sync_errors { + assert_eq!(error.reason(), reason); + } + + assert_eq!( + SyncValidationError::DuplicateAcquireOrder { + offending_id: "lock:second".to_owned(), + existing_id: "lock:first".to_owned(), + } + .to_string(), + "lock lock:second shares acquire order key with lock:first" + ); + } } diff --git a/packages/d2b-core/src/sync.rs b/packages/d2b-core/src/sync.rs index d5b20d08f..00ea8ec85 100644 --- a/packages/d2b-core/src/sync.rs +++ b/packages/d2b-core/src/sync.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::contract_id::{ContractId, PathTemplate}; use crate::storage::{ActorRef, DegradeScope, DegradedReason}; +use crate::storage_lifecycle::SyncValidationError; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -133,24 +134,27 @@ pub enum LockAdoptionPolicy { } impl SyncJson { - pub fn validate_lock_order(&self) -> Result<(), String> { + pub fn validate_lock_order(&self) -> Result<(), SyncValidationError> { let mut ids = BTreeSet::new(); let mut order_keys: BTreeMap<(&LockScopeClass, &str, &str, &str), &ContractId> = BTreeMap::new(); for lock in &self.locks { if !ids.insert(lock.id.as_str()) { - return Err(format!("duplicate lock id {}", lock.id)); + return Err(SyncValidationError::DuplicateLockId { + offending_id: lock.id.to_string(), + }); } if lock.kind == LockKind::Ofd && !lock.cloexec_required { - return Err(format!("OFD lock {} must require O_CLOEXEC", lock.id)); + return Err(SyncValidationError::OfdLockMissingCloexec { + offending_id: lock.id.to_string(), + }); } if lock.fd_passing_policy.mechanism != FdPassingMechanism::None && !lock.fd_passing_policy.lease_transfer_record_required { - return Err(format!( - "fd-passing lock {} must require a lease transfer record", - lock.id - )); + return Err(SyncValidationError::FdPassingMissingLeaseTransferRecord { + offending_id: lock.id.to_string(), + }); } let key = ( &lock.acquire_order.scope_class, @@ -159,10 +163,10 @@ impl SyncJson { lock.acquire_order.lock_id.as_str(), ); if let Some(existing) = order_keys.insert(key, &lock.id) { - return Err(format!( - "lock {} shares acquire order key with {}", - lock.id, existing - )); + return Err(SyncValidationError::DuplicateAcquireOrder { + offending_id: lock.id.to_string(), + existing_id: existing.to_string(), + }); } } Ok(()) diff --git a/packages/d2b-provider-volume-local/src/diagnostics/storage_lifecycle.rs b/packages/d2b-provider-volume-local/src/diagnostics/storage_lifecycle.rs index 417ef3662..42101b92d 100644 --- a/packages/d2b-provider-volume-local/src/diagnostics/storage_lifecycle.rs +++ b/packages/d2b-provider-volume-local/src/diagnostics/storage_lifecycle.rs @@ -15,7 +15,6 @@ use d2b_core::bundle_resolver::BundleResolver; pub use d2b_core::storage_lifecycle::{ StorageContractValidationReason, StorageLifecycleIssue, StorageLifecycleReport, - classify_storage_validation_reason, storage_validation_offending_id, }; /// Persisted storage lifecycle report schema. @@ -345,22 +344,6 @@ mod tests { assert!(!serialized.contains("path:run-root"), "{serialized}"); } - #[test] - fn storage_classifiers_fall_back_to_unclassified_for_unknown_details() { - assert_eq!( - classify_storage_validation_reason("future storage validation failure"), - StorageContractValidationReason::Unclassified, - ); - assert_eq!( - storage_validation_offending_id("duplicate storage path id path:run-root").as_deref(), - Some("path:run-root"), - ); - assert_eq!( - storage_validation_offending_id("duplicate storage path id /run/d2b").as_deref(), - None, - ); - } - #[test] fn bundle_resolver_unavailable_report_is_degraded_and_schema_current() { let report = bundle_resolver_unavailable_report(); From 87c3172bc61281e76d86b6039557dbd8b35abef3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:40:46 -0700 Subject: [PATCH 575/726] daemon: type wire outcomes and own the console drainer runtime Mutating-verb response projection now parses the wire outcome into the typed MutatingVerbOutcome vocabulary (new response_outcome_typed accessor) and retarget_mutating_response matches enum variants instead of raw strings, so unknown outcomes fail closed. EstablishedShell hides its Arc behind delegating handle_op/close_attachment/cancel_attachment methods; the best_effort_* audit helpers take the shell instead of the trait object. The public read model returns Arc from load_list and load_status instead of cloning the whole frame per poll; the wire response clones only at the response boundary. The console drainer runtime static is gone: drainer tasks spawn on the daemon-owned tokio runtime handle passed into the console session creation functions. --- changelog.d/w4-16-console-shell-readmodel.md | 11 ++++ packages/d2bd-runtime/src/console_session.rs | 46 ++++++++------- .../d2bd-runtime/src/public_read_model.rs | 17 ++++-- packages/d2bd-runtime/src/shell_backend.rs | 56 +++++++++++++++++-- .../d2bd-runtime/src/wire_response_helpers.rs | 42 +++++++++----- packages/d2bd/src/composition.rs | 42 +++++++------- 6 files changed, 145 insertions(+), 69 deletions(-) create mode 100644 changelog.d/w4-16-console-shell-readmodel.md diff --git a/changelog.d/w4-16-console-shell-readmodel.md b/changelog.d/w4-16-console-shell-readmodel.md new file mode 100644 index 000000000..51af307d5 --- /dev/null +++ b/changelog.d/w4-16-console-shell-readmodel.md @@ -0,0 +1,11 @@ +### Fixed + +- Console drainer tasks for VM console sessions now run on the daemon's own + tokio runtime instead of a second runtime started from library code that was + never shut down. +- Public list/status polling no longer copies the whole cached read-model + frame on every request; the cached frame is shared by reference and copied + only when the response is actually served. +- Mutating-verb responses are matched against the typed outcome vocabulary + instead of raw wire strings, so unknown outcomes fail closed instead of + being treated as a known state. \ No newline at end of file diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index 0d41abb4e..c74c2bff3 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -20,7 +20,6 @@ //! after restart. For qemu-media, the broker re-provides the fd on daemon //! restart via the normal SpawnRunner adoption path. -use std::sync::OnceLock; use std::{ collections::HashMap, sync::Arc, @@ -30,19 +29,6 @@ use std::{ use d2b_contracts_control::public_wire::{ConsoleProviderKind, ConsoleReadOutputResult}; use d2b_core::console_ring::RingBuffer; -static CONSOLE_DRAINER_RUNTIME: OnceLock = OnceLock::new(); - -fn console_drainer_runtime() -> &'static tokio::runtime::Runtime { - CONSOLE_DRAINER_RUNTIME.get_or_init(|| { - tokio::runtime::Builder::new_multi_thread() - .worker_threads(1) - .thread_name("d2bd-console-drainer") - .enable_all() - .build() - .expect("build console drainer runtime") - }) -} - /// Maximum number of console sessions allowed across all VMs. const MAX_SESSIONS: usize = 64; @@ -392,12 +378,14 @@ pub struct ConsoleReadOutput { /// /// The task connects to `socket_path` (CH's `--serial socket=`), reads /// bytes into the ring, and reconnects if CH closes the connection (e.g. after -/// a VM reboot). The ring's `notify` is triggered on each new chunk. +/// a VM reboot). The ring's `notify` is triggered on each new chunk. The task +/// runs on the caller-provided runtime handle (owned by the daemon binary). pub fn spawn_ch_serial_drainer( + runtime: &tokio::runtime::Handle, socket_path: String, ring: Arc>, ) -> tokio::task::JoinHandle<()> { - console_drainer_runtime().spawn(async move { + runtime.spawn(async move { const RECONNECT_DELAY: Duration = Duration::from_millis(500); loop { match tokio::net::UnixStream::connect(&socket_path).await { @@ -430,13 +418,15 @@ pub fn spawn_ch_serial_drainer( /// /// Unlike [`spawn_ch_serial_drainer`], this does not reconnect after EOF: the /// socketpair fd is unique and cannot be re-created without broker involvement. -/// On EOF the ring is marked `is_eof = true` and the task exits. +/// On EOF the ring is marked `is_eof = true` and the task exits. The task runs +/// on the caller-provided runtime handle (owned by the daemon binary). pub fn spawn_fd_drainer( + runtime: &tokio::runtime::Handle, vm: String, stream: tokio::net::UnixStream, ring: Arc>, ) -> tokio::task::JoinHandle<()> { - console_drainer_runtime().spawn(async move { + runtime.spawn(async move { use tokio::io::AsyncReadExt; let mut stream = stream; let mut buf = vec![0u8; 4096]; @@ -458,10 +448,14 @@ pub fn spawn_fd_drainer( } /// Create a new [`ConsoleSession`] for a Cloud Hypervisor VM using its serial -/// socket path. -pub fn create_ch_session(socket_path: String) -> ConsoleSession { +/// socket path. The drainer task runs on the caller-provided runtime handle +/// (owned by the daemon binary). +pub fn create_ch_session( + runtime: &tokio::runtime::Handle, + socket_path: String, +) -> ConsoleSession { let ring = Arc::new(tokio::sync::Mutex::new(ConsoleRing::new())); - let drainer = spawn_ch_serial_drainer(socket_path, Arc::clone(&ring)); + let drainer = spawn_ch_serial_drainer(runtime, socket_path, Arc::clone(&ring)); ConsoleSession::new( ConsoleProviderKind::LocalHypervisor, ring, @@ -475,8 +469,12 @@ pub fn create_ch_session(socket_path: String) -> ConsoleSession { /// /// The caller must have already created the stream and converted it from /// the raw fd (the broker side handles the unsafe `from_raw_fd` conversion -/// and passes the `UnixStream` value here). -pub fn create_qemu_session(std_stream: std::os::unix::net::UnixStream) -> ConsoleSession { +/// and passes the `UnixStream` value here). The drainer task runs on the +/// caller-provided runtime handle (owned by the daemon binary). +pub fn create_qemu_session( + runtime: &tokio::runtime::Handle, + std_stream: std::os::unix::net::UnixStream, +) -> ConsoleSession { std_stream.set_nonblocking(true).ok(); let ring = Arc::new(tokio::sync::Mutex::new(ConsoleRing::new())); let (stdin_tx, mut stdin_rx) = tokio::sync::mpsc::channel::>(32); @@ -484,7 +482,7 @@ pub fn create_qemu_session(std_stream: std::os::unix::net::UnixStream) -> Consol // We need both a reader and a writer over the same socket. Split // via tokio's UnixStream from the std socket. - let drainer = console_drainer_runtime().spawn(async move { + let drainer = runtime.spawn(async move { use tokio::io::{AsyncReadExt, AsyncWriteExt}; let stream = match tokio::net::UnixStream::from_std(std_stream) { Ok(s) => s, diff --git a/packages/d2bd-runtime/src/public_read_model.rs b/packages/d2bd-runtime/src/public_read_model.rs index f3ffa7b08..84179b733 100644 --- a/packages/d2bd-runtime/src/public_read_model.rs +++ b/packages/d2bd-runtime/src/public_read_model.rs @@ -48,11 +48,18 @@ pub struct FileFingerprint { } #[derive(Debug)] -struct CachedPublicFrame { +pub struct CachedPublicFrame { fingerprint: PublicArtifactFingerprint, value: Value, } +impl CachedPublicFrame { + /// The rendered read-model frame. + pub fn value(&self) -> &Value { + &self.value + } +} + #[derive(Debug)] pub struct PublicStatusReadModel { generation: AtomicU64, @@ -83,11 +90,11 @@ impl PublicStatusReadModel { self.status.store(None); } - pub fn load_list(&self, pidfd_generation: u64) -> Option { + pub fn load_list(&self, pidfd_generation: u64) -> Option> { self.load_if_fresh(pidfd_generation, &self.list) } - pub fn load_status(&self, pidfd_generation: u64) -> Option { + pub fn load_status(&self, pidfd_generation: u64) -> Option> { self.load_if_fresh(pidfd_generation, &self.status) } @@ -113,9 +120,9 @@ impl PublicStatusReadModel { &self, pidfd_generation: u64, slot: &ArcSwapOption, - ) -> Option { + ) -> Option> { let cached = slot.load_full()?; - (cached.fingerprint.pidfd_generation == pidfd_generation).then(|| cached.value.clone()) + (cached.fingerprint.pidfd_generation == pidfd_generation).then_some(cached) } fn publish_stable( diff --git a/packages/d2bd-runtime/src/shell_backend.rs b/packages/d2bd-runtime/src/shell_backend.rs index 2558f2963..d493bb78e 100644 --- a/packages/d2bd-runtime/src/shell_backend.rs +++ b/packages/d2bd-runtime/src/shell_backend.rs @@ -50,13 +50,59 @@ pub trait ShellBackend: Send + Sync { } pub struct EstablishedShell { - pub backend: Arc, + backend: Arc, pub attach: public_wire::ShellAttachResult, pub target: String, pub operation_digest: Option, pub initial_control_sequence: u64, } +impl EstablishedShell { + pub fn new( + backend: Arc, + attach: public_wire::ShellAttachResult, + target: String, + operation_digest: Option, + initial_control_sequence: u64, + ) -> Self { + Self { + backend, + attach, + target, + operation_digest, + initial_control_sequence, + } + } + + /// Delegate a terminal operation to the attached backend. + pub fn handle_op( + &self, + runtime: &tokio::runtime::Handle, + control_sequence: &mut u64, + op: ShellTerminalOp, + ) -> Result, TypedError> { + self.backend.handle_op(runtime, control_sequence, op) + } + + /// Close the attached terminal stream. + pub fn close_attachment( + &self, + runtime: &tokio::runtime::Handle, + control_sequence: &mut u64, + ) -> Result { + self.backend.close_attachment(runtime, control_sequence) + } + + /// Cancel the attached terminal stream when its owner disappears. + pub fn cancel_attachment( + &self, + runtime: &tokio::runtime::Handle, + control_sequence: &mut u64, + ) -> Result { + self.backend.cancel_attachment(runtime, control_sequence) + } +} + /// Persistent-shell backend over a ComponentSession named stream. /// /// Shell lifecycle is still authorized by the ShellSession resource and its @@ -289,11 +335,11 @@ impl fmt::Debug for EstablishedShell { } pub fn best_effort_close( - backend: &dyn ShellBackend, + shell: &EstablishedShell, runtime: &tokio::runtime::Handle, control_sequence: &mut u64, ) -> daemon_audit::ShellAuditResult { - match backend.close_attachment(runtime, control_sequence) { + match shell.close_attachment(runtime, control_sequence) { Ok(_) => daemon_audit::ShellAuditResult::Closed, Err(TypedError::ComponentSessionShellFailed { kind: crate::typed_error::ComponentSessionShellErrorKind::Timeout, @@ -303,11 +349,11 @@ pub fn best_effort_close( } pub fn best_effort_cancel( - backend: &dyn ShellBackend, + shell: &EstablishedShell, runtime: &tokio::runtime::Handle, control_sequence: &mut u64, ) -> daemon_audit::ShellAuditResult { - match backend.cancel_attachment(runtime, control_sequence) { + match shell.cancel_attachment(runtime, control_sequence) { Ok(_) => daemon_audit::ShellAuditResult::Closed, Err(TypedError::ComponentSessionShellFailed { kind: crate::typed_error::ComponentSessionShellErrorKind::Timeout, diff --git a/packages/d2bd-runtime/src/wire_response_helpers.rs b/packages/d2bd-runtime/src/wire_response_helpers.rs index ba39b1f81..d4f505da6 100644 --- a/packages/d2bd-runtime/src/wire_response_helpers.rs +++ b/packages/d2bd-runtime/src/wire_response_helpers.rs @@ -1,5 +1,6 @@ //! Provider-neutral public mutating-response construction and projection. +use d2b_contracts_control::public_wire::{MutatingVerbOutcome, MutatingVerbResponse}; use serde_json::Value; use crate::wire::mutating_verb_response; @@ -10,8 +11,6 @@ pub fn broker_failure_response( remediation: String, target_wave: Option, ) -> Value { - use d2b_contracts_control::public_wire::{MutatingVerbOutcome, MutatingVerbResponse}; - mutating_verb_response(MutatingVerbResponse { verb: verb.to_owned(), outcome: MutatingVerbOutcome::BrokerError, @@ -31,8 +30,6 @@ pub fn invalid_request_response_with_summary( summary: String, remediation: String, ) -> Value { - use d2b_contracts_control::public_wire::{MutatingVerbOutcome, MutatingVerbResponse}; - mutating_verb_response(MutatingVerbResponse { verb: verb.to_owned(), outcome: MutatingVerbOutcome::InvalidRequest, @@ -57,8 +54,6 @@ pub fn daemon_failure_response(verb: &str, summary: String) -> Value { } pub fn applied_response(verb: &str, summary: String) -> Value { - use d2b_contracts_control::public_wire::{MutatingVerbOutcome, MutatingVerbResponse}; - mutating_verb_response(MutatingVerbResponse { verb: verb.to_owned(), outcome: MutatingVerbOutcome::Applied, @@ -84,8 +79,6 @@ pub fn append_response_summary(response: &mut Value, suffix: &str) { } pub fn api_ready_timeout_response(verb: &str, summary: String) -> Value { - use d2b_contracts_control::public_wire::{MutatingVerbOutcome, MutatingVerbResponse}; - mutating_verb_response(MutatingVerbResponse { verb: verb.to_owned(), outcome: MutatingVerbOutcome::ApiReadyTimeout, @@ -96,8 +89,31 @@ pub fn api_ready_timeout_response(verb: &str, summary: String) -> Value { }) } +/// Parse the wire `outcome` field into the typed [`MutatingVerbOutcome`] +/// vocabulary. Unknown or malformed outcome strings yield `None`. +pub fn response_outcome_typed(value: &Value) -> Option { + value + .get("outcome") + .cloned() + .and_then(|outcome| serde_json::from_value(outcome).ok()) +} + +/// The wire string for a typed mutating-verb outcome. +fn mutating_verb_outcome_wire(outcome: MutatingVerbOutcome) -> &'static str { + match outcome { + MutatingVerbOutcome::DryRunPlanned => "dry-run-planned", + MutatingVerbOutcome::Applied => "applied", + MutatingVerbOutcome::ApiReadyTimeout => "api-ready-timeout", + MutatingVerbOutcome::NotYetImplemented => "not-yet-implemented", + MutatingVerbOutcome::BrokerError => "broker-error", + MutatingVerbOutcome::InvalidRequest => "invalid-request", + } +} + +/// The wire `outcome` string, re-derived from the typed outcome vocabulary +/// rather than read verbatim from the JSON. pub fn response_outcome(value: &Value) -> Option<&str> { - value.get("outcome").and_then(Value::as_str) + response_outcome_typed(value).map(mutating_verb_outcome_wire) } pub fn response_summary(value: &Value) -> Option<&str> { @@ -116,17 +132,17 @@ pub fn response_target_wave(value: &Value) -> Option { } pub fn retarget_mutating_response(value: &Value, verb: &str) -> Value { - match response_outcome(value) { - Some("applied") => { + match response_outcome_typed(value) { + Some(MutatingVerbOutcome::Applied) => { applied_response(verb, response_summary(value).unwrap_or_default().to_owned()) } - Some("broker-error") => broker_failure_response( + Some(MutatingVerbOutcome::BrokerError) => broker_failure_response( verb, response_summary(value).unwrap_or_default().to_owned(), response_remediation(value).unwrap_or_default().to_owned(), response_target_wave(value), ), - Some("api-ready-timeout") => { + Some(MutatingVerbOutcome::ApiReadyTimeout) => { let mut retargeted = value.clone(); if let Some(object) = retargeted.as_object_mut() { object.insert("verb".to_owned(), Value::String(verb.to_owned())); diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index f450b8958..0cb7d0193 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -9222,7 +9222,7 @@ fn resolve_console_provider_kind( /// For qemu-media, requires a pre-provisioned socketpair fd from the broker; /// returns ConsoleNotRunning if no live fd is available. fn create_console_session_for_vm( - _state: &ServerState, + state: &ServerState, vm: &str, provider_kind: public_wire::ConsoleProviderKind, ) -> Result { @@ -9231,8 +9231,12 @@ fn create_console_session_for_vm( // Cloud Hypervisor serial socket path. let socket_path = format!("/run/d2b/vms/{vm}/console.sock"); // The path may not exist yet if CH hasn't started, but the - // drainer will reconnect automatically. - Ok(console_session::create_ch_session(socket_path)) + // drainer will reconnect automatically. The drainer task runs + // on the daemon-owned runtime handle. + Ok(console_session::create_ch_session( + &state.runtime_handle, + socket_path, + )) } public_wire::ConsoleProviderKind::QemuMedia => { // qemu-media console requires the broker to create a @@ -13509,7 +13513,6 @@ fn run_typed_shell_owner( ); let mut control_sequence = established.initial_control_sequence; let close_result = match established - .backend .close_attachment(rt.handle(), &mut control_sequence) { Ok(_) => d2bd_runtime::daemon_audit::ShellAuditResult::Closed, @@ -13566,7 +13569,7 @@ fn run_typed_shell_owner( { let mut control_sequence = established.initial_control_sequence; d2bd_runtime::shell_backend::best_effort_cancel( - established.backend.as_ref(), + &established, rt.handle(), &mut control_sequence, ); @@ -13622,9 +13625,7 @@ fn run_typed_shell_owner( | public_wire::NamedProcessStreamRequest::Cancel ); if close { - let result = established - .backend - .close_attachment(rt.handle(), &mut control_sequence); + let result = established.close_attachment(rt.handle(), &mut control_sequence); match result { Ok(_) => { close_result = Some(d2bd_runtime::daemon_audit::ShellAuditResult::Closed); @@ -13730,10 +13731,7 @@ fn run_typed_shell_owner( public_wire::NamedProcessStreamRequest::Close | public_wire::NamedProcessStreamRequest::Cancel => unreachable!(), }; - let response = match established - .backend - .handle_op(rt.handle(), &mut control_sequence, op) - { + let response = match established.handle_op(rt.handle(), &mut control_sequence, op) { Ok(Some(d2bd_runtime::shell_backend::ShellTerminalResponse::WriteStdin(result))) => { if close_stdin { public_wire::NamedProcessStreamResponse::Closed(public_wire::ExecCloseResult { @@ -13783,7 +13781,7 @@ fn run_typed_shell_owner( } let close_result = close_result.unwrap_or_else(|| { d2bd_runtime::shell_backend::best_effort_cancel( - established.backend.as_ref(), + &established, rt.handle(), &mut control_sequence, ) @@ -13839,18 +13837,18 @@ async fn establish_shell_backend( ) .await .map_err(|_| shell_transport_failed())?; - Ok(d2bd_runtime::shell_backend::EstablishedShell { - backend: Arc::new(backend), - attach: public_wire::ShellAttachResult { + Ok(d2bd_runtime::shell_backend::EstablishedShell::new( + Arc::new(backend), + public_wire::ShellAttachResult { session: public_session, resolved_name, state: public_wire::ShellSessionState::Attached, force_evicted: false, }, - target: vm, - operation_digest: None, - initial_control_sequence: 0, - }) + vm, + None, + 0, + )) } ShellRoute::CapabilityUnavailable { provider } => { Err(TypedError::RuntimeCapabilityUnsupported { @@ -20909,7 +20907,7 @@ fn dispatch_list( .public_status_read_model .load_list(state.pidfd_table.generation()) { - return Ok(cached); + return Ok(cached.value().clone()); } let before = cacheable .then(|| public_artifact_fingerprint(state).ok()) @@ -21044,7 +21042,7 @@ fn dispatch_status_as( .public_status_read_model .load_status(state.pidfd_table.generation()) { - return Ok(cached); + return Ok(cached.value().clone()); } let before = cacheable .then(|| public_artifact_fingerprint(state).ok()) From 6b90849572a6d457c78495f54cedb8ca8335d4a4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:40:57 -0700 Subject: [PATCH 576/726] providers: wire test-support feature to registration tests --- changelog.d/w4-24-test-support-registration.md | 3 +++ packages/d2b-provider-quota/Cargo.toml | 5 +++++ packages/d2b-provider-resource-export/Cargo.toml | 5 +++++ packages/d2b-provider-resource-import/Cargo.toml | 5 +++++ packages/d2b-provider-role/Cargo.toml | 5 +++++ 5 files changed, 23 insertions(+) create mode 100644 changelog.d/w4-24-test-support-registration.md diff --git a/changelog.d/w4-24-test-support-registration.md b/changelog.d/w4-24-test-support-registration.md new file mode 100644 index 000000000..dcf1d85a1 --- /dev/null +++ b/changelog.d/w4-24-test-support-registration.md @@ -0,0 +1,3 @@ +### Fixed + +- The quota, resource-export, resource-import, and role provider crates now gate their registration integration tests behind the `test-support` feature, which previously was declared empty and gated nothing; a plain `cargo test -p ` now skips them consistently with the rest of the provider family. \ No newline at end of file diff --git a/packages/d2b-provider-quota/Cargo.toml b/packages/d2b-provider-quota/Cargo.toml index 4828f3ad3..890dc2cb0 100644 --- a/packages/d2b-provider-quota/Cargo.toml +++ b/packages/d2b-provider-quota/Cargo.toml @@ -24,3 +24,8 @@ serde.workspace = true [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-resource-export/Cargo.toml b/packages/d2b-provider-resource-export/Cargo.toml index a4ebf39ac..c98e79f83 100644 --- a/packages/d2b-provider-resource-export/Cargo.toml +++ b/packages/d2b-provider-resource-export/Cargo.toml @@ -21,3 +21,8 @@ d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstra [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-resource-import/Cargo.toml b/packages/d2b-provider-resource-import/Cargo.toml index 7faecb4eb..125c0c5f0 100644 --- a/packages/d2b-provider-resource-import/Cargo.toml +++ b/packages/d2b-provider-resource-import/Cargo.toml @@ -21,3 +21,8 @@ d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstra [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-role/Cargo.toml b/packages/d2b-provider-role/Cargo.toml index ebd37b496..2fc6c44ad 100644 --- a/packages/d2b-provider-role/Cargo.toml +++ b/packages/d2b-provider-role/Cargo.toml @@ -22,3 +22,8 @@ d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstra [dev-dependencies] tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] From 98f74a98017e6e7fdb1495a8e91e9eb32a00b490 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:41:02 -0700 Subject: [PATCH 577/726] resource-runtime: drop discarded TargetHandle from ResourceContext::new --- changelog.d/w4-19-resource-context-target.md | 4 ++++ packages/d2b-provider-activation-nixos/src/driver.rs | 2 -- packages/d2b-provider-credential/src/driver.rs | 2 -- packages/d2b-provider-device/tests/device_family.rs | 2 -- packages/d2b-provider-endpoint/src/driver.rs | 2 -- packages/d2b-provider-guest/src/driver.rs | 2 -- packages/d2b-provider-host/src/driver.rs | 2 -- packages/d2b-provider-network-local/src/driver.rs | 2 -- packages/d2b-provider-process/src/driver.rs | 2 -- packages/d2b-provider-provider/src/driver.rs | 2 -- packages/d2b-provider-telemetry-binding/src/driver.rs | 2 -- packages/d2b-provider-telemetry-service/src/driver.rs | 2 -- packages/d2b-provider-toolkit/src/shared_provider.rs | 2 -- packages/d2b-provider-user/src/driver.rs | 2 -- packages/d2b-provider-volume-binding/src/driver.rs | 2 -- packages/d2b-provider-volume/src/driver.rs | 4 ---- packages/d2b-provider-wayland-policy/tests/engine.rs | 2 -- packages/d2b-resource-runtime/src/context.rs | 4 ---- packages/d2b-resource-runtime/src/metadata.rs | 2 -- packages/d2b-resource-runtime/src/resource.rs | 4 ---- 20 files changed, 4 insertions(+), 44 deletions(-) create mode 100644 changelog.d/w4-19-resource-context-target.md diff --git a/changelog.d/w4-19-resource-context-target.md b/changelog.d/w4-19-resource-context-target.md new file mode 100644 index 000000000..4bca0f61e --- /dev/null +++ b/changelog.d/w4-19-resource-context-target.md @@ -0,0 +1,4 @@ +### Fixed + +- `ResourceContext::new` no longer takes a `TargetHandle` argument that was + silently discarded; callers no longer pass a value that has no effect. \ No newline at end of file diff --git a/packages/d2b-provider-activation-nixos/src/driver.rs b/packages/d2b-provider-activation-nixos/src/driver.rs index 5af118b11..0eeb37c24 100644 --- a/packages/d2b-provider-activation-nixos/src/driver.rs +++ b/packages/d2b-provider-activation-nixos/src/driver.rs @@ -961,7 +961,6 @@ mod tests { ResourceKey, ResourceProvenance, StoredDesiredResource, }; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use super::{ ACTIVATION_TYPE_NAME, ActivationApplicationVerifier, ActivationController, @@ -1189,7 +1188,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); let ctx = ResourceContext::new( row, - TargetHandle::Host, activation_spec_decoder(), Arc::new(manager.clone()), Arc::new(NullRequeue), diff --git a/packages/d2b-provider-credential/src/driver.rs b/packages/d2b-provider-credential/src/driver.rs index 0a35f911e..98fe40d7b 100644 --- a/packages/d2b-provider-credential/src/driver.rs +++ b/packages/d2b-provider-credential/src/driver.rs @@ -1049,7 +1049,6 @@ mod tests { use d2b_resource_runtime::error::{FailureClass, ResourceError}; use d2b_resource_runtime::identity::{ResourceKey, ResourceProvenance, StoredDesiredResource}; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use parking_lot::Mutex; use crate::session::{ @@ -1254,7 +1253,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( row, - TargetHandle::Host, credential_spec_decoder(), manager, Arc::new(NullRequeue), diff --git a/packages/d2b-provider-device/tests/device_family.rs b/packages/d2b-provider-device/tests/device_family.rs index 615629150..9296d50ff 100644 --- a/packages/d2b-provider-device/tests/device_family.rs +++ b/packages/d2b-provider-device/tests/device_family.rs @@ -25,7 +25,6 @@ use d2b_resource_runtime::identity::{ ResourceKey, ResourceProvenance, StoredDesiredResource, }; use d2b_resource_runtime::spec_store::EnsureOutcome; -use d2b_resource_runtime::target::TargetHandle; use serde_json::json; struct DeadManager; @@ -110,7 +109,6 @@ fn context( let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( row, - TargetHandle::Host, descriptor.decoder.clone(), Arc::new(DeadManager), Arc::new(RecordingRequeue), diff --git a/packages/d2b-provider-endpoint/src/driver.rs b/packages/d2b-provider-endpoint/src/driver.rs index 59b72a823..69b076d8d 100644 --- a/packages/d2b-provider-endpoint/src/driver.rs +++ b/packages/d2b-provider-endpoint/src/driver.rs @@ -609,7 +609,6 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer use d2b_resource_runtime::error::{FailureClass, ResourceError}; use d2b_resource_runtime::identity::{ResourceKey, ResourceProvenance, StoredDesiredResource}; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use super::{ EndpointDriverArgs, EndpointDriverFactory, EndpointPurposeVocabulary, @@ -732,7 +731,6 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( row, - TargetHandle::Host, endpoint_spec_decoder(), manager, Arc::new(NullRequeue), diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index a41c2f1cc..9fae782e6 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -1514,7 +1514,6 @@ mod tests { use d2b_resource_runtime::manager::ResourceView; use d2b_resource_runtime::resource::ResourceStatus; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use super::{ GUEST_REGISTRATIONS, GUEST_TYPE_NAME, GuestDriver, GuestDriverArgs, GuestDriverFactory, @@ -1847,7 +1846,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( target, - TargetHandle::Host, guest_spec_decoder(), manager, requeue, diff --git a/packages/d2b-provider-host/src/driver.rs b/packages/d2b-provider-host/src/driver.rs index c828164ff..c0d45c9b6 100644 --- a/packages/d2b-provider-host/src/driver.rs +++ b/packages/d2b-provider-host/src/driver.rs @@ -521,7 +521,6 @@ mod tests { use d2b_resource_runtime::identity::{ResourceKey, ResourceProvenance, StoredDesiredResource}; use d2b_resource_runtime::provider::ProviderDirectory; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use crate::test_support::{RecordingEffects, RecordingProbe, scripted_facets}; @@ -688,7 +687,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( row, - TargetHandle::Host, host_spec_decoder(), manager, requeue, diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index 1a179931d..a05e43d8e 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -411,7 +411,6 @@ mod tests { ResourceKey, ResourceProvenance, ResourceTypeName, StoredDesiredResource, }; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use serde_json::json; use super::{ @@ -568,7 +567,6 @@ impl RequeueScheduler for RecordingRequeue { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); d2b_resource_runtime::context::ResourceContext::new( row, - TargetHandle::Host, descriptor.decoder.clone(), manager, Arc::new(RecordingRequeue::default()), diff --git a/packages/d2b-provider-process/src/driver.rs b/packages/d2b-provider-process/src/driver.rs index d3b2e5c3d..ea906ce61 100644 --- a/packages/d2b-provider-process/src/driver.rs +++ b/packages/d2b-provider-process/src/driver.rs @@ -2216,7 +2216,6 @@ mod tests { ResourceKey, ResourceProvenance, ResourceTypeName, StoredDesiredResource, }; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use parking_lot::Mutex; use tokio::sync::mpsc; @@ -2569,7 +2568,6 @@ mod tests { let (requeue, requeue_rx) = RecordingRequeue::new(); let ctx = ResourceContext::new( row.clone(), - TargetHandle::Host, process_spec_decoder(), manager, Arc::new(requeue.clone()), diff --git a/packages/d2b-provider-provider/src/driver.rs b/packages/d2b-provider-provider/src/driver.rs index 1e46dfa4d..fd62ad1c6 100644 --- a/packages/d2b-provider-provider/src/driver.rs +++ b/packages/d2b-provider-provider/src/driver.rs @@ -718,7 +718,6 @@ mod tests { use d2b_resource_runtime::identity::{ResourceKey, ResourceProvenance, StoredDesiredResource}; use d2b_resource_runtime::manager::ResourceView; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use crate::test_support::RecordingEffects; @@ -924,7 +923,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( target, - TargetHandle::Host, provider_spec_decoder(), manager, Arc::new(RecordingRequeue), diff --git a/packages/d2b-provider-telemetry-binding/src/driver.rs b/packages/d2b-provider-telemetry-binding/src/driver.rs index c7f674b59..daee1a796 100644 --- a/packages/d2b-provider-telemetry-binding/src/driver.rs +++ b/packages/d2b-provider-telemetry-binding/src/driver.rs @@ -673,7 +673,6 @@ mod tests { use d2b_resource_runtime::error::{FailureClass, ResourceError}; use d2b_resource_runtime::identity::ResourceProvenance; use d2b_resource_runtime::spec_store::{EnsureOutcome, StoredDesiredResource}; - use d2b_resource_runtime::target::TargetHandle; use tokio::sync::mpsc; use super::*; @@ -881,7 +880,6 @@ mod tests { let (watch_tx, _watch_rx) = mpsc::unbounded_channel(); let ctx = ResourceContext::new( row, - TargetHandle::Host, telemetry_binding_spec_decoder(), Arc::clone(&manager) as Arc, Arc::clone(&requeue) as Arc, diff --git a/packages/d2b-provider-telemetry-service/src/driver.rs b/packages/d2b-provider-telemetry-service/src/driver.rs index da374323d..fcccae8f3 100644 --- a/packages/d2b-provider-telemetry-service/src/driver.rs +++ b/packages/d2b-provider-telemetry-service/src/driver.rs @@ -538,7 +538,6 @@ mod tests { use d2b_resource_runtime::error::{FailureClass, ResourceError}; use d2b_resource_runtime::identity::ResourceProvenance; use d2b_resource_runtime::spec_store::{EnsureOutcome, StoredDesiredResource}; - use d2b_resource_runtime::target::TargetHandle; use tokio::sync::mpsc; use super::*; @@ -705,7 +704,6 @@ mod tests { let (watch_tx, _watch_rx) = mpsc::unbounded_channel(); let ctx = ResourceContext::new( row, - TargetHandle::Host, telemetry_service_spec_decoder(), Arc::clone(&manager) as Arc, Arc::clone(&requeue) as Arc, diff --git a/packages/d2b-provider-toolkit/src/shared_provider.rs b/packages/d2b-provider-toolkit/src/shared_provider.rs index 70deb9489..fff7f189b 100644 --- a/packages/d2b-provider-toolkit/src/shared_provider.rs +++ b/packages/d2b-provider-toolkit/src/shared_provider.rs @@ -1075,7 +1075,6 @@ mod tests { ResourceKey, ResourceProvenance, ResourceTypeName, StoredDesiredResource, }; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use serde_json::json; use super::{ @@ -1372,7 +1371,6 @@ mod tests { let family = RecordingFamily::new(Arc::clone(&log), phase, finalize, declares_children); let ctx = ResourceContext::new( row, - TargetHandle::Host, decoder(), Arc::clone(&manager) as Arc, Arc::clone(&requeue) as Arc, diff --git a/packages/d2b-provider-user/src/driver.rs b/packages/d2b-provider-user/src/driver.rs index 6c36b70a8..1545ae593 100644 --- a/packages/d2b-provider-user/src/driver.rs +++ b/packages/d2b-provider-user/src/driver.rs @@ -446,7 +446,6 @@ mod tests { use d2b_resource_runtime::identity::{ResourceKey, ResourceProvenance, StoredDesiredResource}; use d2b_resource_runtime::provider::ProviderDirectory; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use crate::test_support::{RecordingEffects, ScriptedProbe, recording_facets}; @@ -619,7 +618,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( row, - TargetHandle::Host, user_spec_decoder(), manager, requeue, diff --git a/packages/d2b-provider-volume-binding/src/driver.rs b/packages/d2b-provider-volume-binding/src/driver.rs index 988adf0b7..cc5ea96f6 100644 --- a/packages/d2b-provider-volume-binding/src/driver.rs +++ b/packages/d2b-provider-volume-binding/src/driver.rs @@ -1135,7 +1135,6 @@ mod tests { use d2b_resource_runtime::error::{FailureClass, ResourceError}; use d2b_resource_runtime::identity::{ResourceKey, ResourceProvenance, StoredDesiredResource}; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use super::{ BindingDriverArgs, BindingDriverFactory, BindingDriverStatus, binding_spec_decoder, @@ -1433,7 +1432,6 @@ mod tests { let requeue = RecordingRequeue::new(); let ctx = ResourceContext::new( row, - TargetHandle::Host, binding_spec_decoder(), Arc::new(manager.clone()), Arc::new(requeue.clone()), diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index 7078b9626..7ee597ac4 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -758,7 +758,6 @@ mod tests { ResourceKey, ResourceProvenance, StoredDesiredResource, }; use d2b_resource_runtime::spec_store::EnsureOutcome; - use d2b_resource_runtime::target::TargetHandle; use super::{VolumeDriverArgs, VolumeDriverFactory, volume_spec_decoder}; use crate::test_support::{RecordingRuntime, recording_facets}; @@ -971,7 +970,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); let ctx = ResourceContext::new( row, - TargetHandle::Host, volume_spec_decoder(), Arc::new(manager), Arc::new(NullRequeue), @@ -1259,7 +1257,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); let mut ctx2 = ResourceContext::new( grown, - TargetHandle::Host, volume_spec_decoder(), Arc::new(manager.clone()), Arc::new(NullRequeue), @@ -1288,7 +1285,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); let mut ctx3 = ResourceContext::new( shrunk, - TargetHandle::Host, volume_spec_decoder(), Arc::new(manager.clone()), Arc::new(NullRequeue), diff --git a/packages/d2b-provider-wayland-policy/tests/engine.rs b/packages/d2b-provider-wayland-policy/tests/engine.rs index 1e215916f..4cbb92cb6 100644 --- a/packages/d2b-provider-wayland-policy/tests/engine.rs +++ b/packages/d2b-provider-wayland-policy/tests/engine.rs @@ -30,7 +30,6 @@ use d2b_resource_runtime::identity::{ ResourceKey, ResourceProvenance, ResourceTypeName, StoredDesiredResource, }; use d2b_resource_runtime::spec_store::EnsureOutcome; -use d2b_resource_runtime::target::TargetHandle; use serde_json::json; // -- the test type ---------------------------------------------------------- @@ -257,7 +256,6 @@ fn build_fixture( let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); let ctx = ResourceContext::new( row, - TargetHandle::Host, spec_decoder(), Arc::new(manager.clone()), Arc::new(requeue), diff --git a/packages/d2b-resource-runtime/src/context.rs b/packages/d2b-resource-runtime/src/context.rs index 560fd01e5..a376f0f96 100644 --- a/packages/d2b-resource-runtime/src/context.rs +++ b/packages/d2b-resource-runtime/src/context.rs @@ -14,7 +14,6 @@ use crate::error::{FailureComparison, ResourceError}; use crate::identity::{ResourceKey, ResourceTypeName, StoredDesiredResource}; use crate::manager::ResourceView; use crate::spec_store::EnsureOutcome; -use crate::target::TargetHandle; // --------------------------------------------------------------------------- // Long effects (R5; spec section 14) @@ -363,7 +362,6 @@ impl ResourceContext { /// manager-wired hooks. pub fn new( row: StoredDesiredResource, - _target: TargetHandle, decoder: Arc, manager: Arc, requeue: Arc, @@ -810,7 +808,6 @@ pub(crate) mod test_support { use crate::identity::{ResourceKey, ResourceProvenance, StoredDesiredResource}; use crate::manager::ResourceView; use crate::spec_store::EnsureOutcome; - use crate::target::TargetHandle; /// Decoder that always fails; tests wiring their own decode hooks pass /// [`super::typed_spec_decoder`] closures instead. @@ -1023,7 +1020,6 @@ pub(crate) mod test_support { Fixture { ctx: ResourceContext::new( row, - TargetHandle::Host, decoder, Arc::new(manager), Arc::new(requeue), diff --git a/packages/d2b-resource-runtime/src/metadata.rs b/packages/d2b-resource-runtime/src/metadata.rs index ef9d4a09d..033e8f62b 100644 --- a/packages/d2b-resource-runtime/src/metadata.rs +++ b/packages/d2b-resource-runtime/src/metadata.rs @@ -246,7 +246,6 @@ mod tests { }; use crate::manager::ResourceView; use crate::spec_store::EnsureOutcome; - use crate::target::TargetHandle; use serde_json::json; @@ -396,7 +395,6 @@ mod tests { let (notify_tx, _notify_rx) = tokio::sync::mpsc::unbounded_channel(); ResourceContext::new( target, - TargetHandle::Host, metadata_spec_decoder(), manager, Arc::new(NullRequeue), diff --git a/packages/d2b-resource-runtime/src/resource.rs b/packages/d2b-resource-runtime/src/resource.rs index 7bc36cab8..2ccffde15 100644 --- a/packages/d2b-resource-runtime/src/resource.rs +++ b/packages/d2b-resource-runtime/src/resource.rs @@ -306,7 +306,6 @@ pub struct ResourceActorState { /// Manager endpoint behind the driver context (R2). manager_endpoint: Arc, decoder: Arc, - target: crate::target::TargetHandle, /// Runtime-only retryable-failure backoff (R13). backoff: Duration, /// The rung of the retry ladder the next operational failure schedules @@ -556,7 +555,6 @@ impl ResourceActorState { fn rebuild_context(&mut self) { let ctx = ResourceContext::new( self.row.clone(), - self.target, self.decoder.clone(), self.manager_endpoint.clone(), self.timers.clone(), @@ -709,7 +707,6 @@ impl Actor for ResourceActor { let (watch_tx, watch_rx) = mpsc::unbounded_channel(); let ctx = ResourceContext::new( row.clone(), - args.target, args.decoder.clone(), manager_endpoint.clone(), timers.clone(), @@ -721,7 +718,6 @@ impl Actor for ResourceActor { manager: args.manager, manager_endpoint, decoder: args.decoder, - target: args.target, backoff: args.backoff, retry_backoff: args.backoff, owner_key: args.owner_key, From 0b5c7d292f5d441cc6ebd5858a89a9f363de9770 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:43:05 -0700 Subject: [PATCH 578/726] catalog: emit typed authz facet enums in the broker operation catalog The catalog view emitted the committed authz facets as string literals into BrokerAuthzFacets while the sibling authz view emitted the same declared data as typed enums. Emit SecretAccess/BrokerRequirement/AuditMode from the catalog view too, type the BrokerAuthzFacets fields to those enums (re-exported from d2b-core privileges), and align the hand-written test row that drifted case (audit_mode "yes" vs "Yes"). The d2b-core privilege enums gain Copy so the Copy-bearing row structs keep their derives. --- changelog.d/w4-22-typed-authz-facets.md | 3 + .../d2b-broker-composition/src/routing.rs | 17 +- packages/d2b-broker-composition/src/seam.rs | 11 +- packages/d2b-broker/src/catalog.rs | 13 +- packages/d2b-broker/src/envelope/mod.rs | 10 +- .../src/generated/broker_operation_catalog.rs | 588 +++++++++--------- packages/d2b-core/src/privileges.rs | 6 +- packages/xtask/src/gen_broker_operations.rs | 9 +- 8 files changed, 338 insertions(+), 319 deletions(-) create mode 100644 changelog.d/w4-22-typed-authz-facets.md diff --git a/changelog.d/w4-22-typed-authz-facets.md b/changelog.d/w4-22-typed-authz-facets.md new file mode 100644 index 000000000..d587d3c50 --- /dev/null +++ b/changelog.d/w4-22-typed-authz-facets.md @@ -0,0 +1,3 @@ +### Fixed + +- The broker operation catalog now carries the authorization facets as the typed `SecretAccess`, `BrokerRequirement`, and `AuditMode` enums instead of string literals, matching the sibling authz view and closing the case drift between the two generated forms. \ No newline at end of file diff --git a/packages/d2b-broker-composition/src/routing.rs b/packages/d2b-broker-composition/src/routing.rs index ddf3e2900..90aba35ad 100644 --- a/packages/d2b-broker-composition/src/routing.rs +++ b/packages/d2b-broker-composition/src/routing.rs @@ -14,7 +14,9 @@ //! registers its handler through [`crate::seam`]; this module is the //! single place the admission predicate lives. -use d2b_broker::catalog::{BrokerOperationRow, OperationOwner, PayloadProvenance}; +use d2b_broker::catalog::{ + BrokerOperationRow, OperationOwner, PayloadProvenance, SecretAccess, +}; /// Why one operation was refused admission to the in-broker table. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -95,7 +97,7 @@ pub fn route_row(row: &BrokerOperationRow) -> RoutingVerdict { // (and therefore the in-broker leg) does not carry them. return RoutingVerdict::Forward(RefusalClass::NotGeneric); } - if row.authz.destructive || row.authz.secret_access != "None" || row.max_fds != 0 { + if row.authz.destructive || row.authz.secret_access != SecretAccess::None || row.max_fds != 0 { // A committed effect facet: destructive mutation, secret exposure, // or descriptor minting. Effects run on the forward carrier. return RoutingVerdict::Forward(RefusalClass::Effectful); @@ -129,7 +131,8 @@ pub fn catalog_admitted_operations() -> Vec<&'static str> { mod tests { use super::*; use d2b_broker::catalog::{ - BrokerAuthzFacets, BrokerProfileId, CellDurability, OperationOwner, PayloadProvenance, + AuditMode, BrokerAuthzFacets, BrokerProfileId, BrokerRequirement, CellDurability, + OperationOwner, PayloadProvenance, }; /// A minimal pure, generic, provider-declared row (the shape a future @@ -153,9 +156,9 @@ mod tests { scope: "per-zone", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "No", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["echo"], @@ -234,7 +237,7 @@ mod tests { #[test] fn a_secret_exposing_row_is_refused_as_effectful() { let mut row = PURE_ROW; - row.authz.secret_access = "RedactedOnly"; + row.authz.secret_access = SecretAccess::RedactedOnly; assert_eq!( route_row(&row), RoutingVerdict::Forward(RefusalClass::Effectful) diff --git a/packages/d2b-broker-composition/src/seam.rs b/packages/d2b-broker-composition/src/seam.rs index eb5840ca4..6a5990278 100644 --- a/packages/d2b-broker-composition/src/seam.rs +++ b/packages/d2b-broker-composition/src/seam.rs @@ -321,8 +321,9 @@ pub struct StateCellHandle<'a> { mod tests { use super::*; use d2b_broker::catalog::{ - BROKER_OPERATION_CATALOG, BrokerAuthzFacets, BrokerProfileId, CellDurability, - DeadlineTier, OperationOwner, PayloadProvenance, + AuditMode, BROKER_OPERATION_CATALOG, BrokerAuthzFacets, BrokerProfileId, + BrokerRequirement, CellDurability, DeadlineTier, OperationOwner, PayloadProvenance, + SecretAccess, }; use d2b_broker::envelope::{ BrokerEnvelope, CallerAuthority, DispatchFailure, DispatchOutcome, HANDLER_REFUSED, @@ -350,9 +351,9 @@ mod tests { scope: "per-zone", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "No", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["echo"], diff --git a/packages/d2b-broker/src/catalog.rs b/packages/d2b-broker/src/catalog.rs index fb2104bab..1bc9ee7f5 100644 --- a/packages/d2b-broker/src/catalog.rs +++ b/packages/d2b-broker/src/catalog.rs @@ -95,13 +95,20 @@ pub struct BrokerAuthzFacets { /// changes are possible. pub destructive: bool, /// Secret exposure class. - pub secret_access: &'static str, + pub secret_access: SecretAccess, /// Broker-use class. - pub broker_required: &'static str, + pub broker_required: BrokerRequirement, /// Audit mode. - pub audit_mode: &'static str, + pub audit_mode: AuditMode, } +/// The typed authorization classes the committed facets name. +/// +/// The catalog view emits the committed authz facets as these enums (the +/// same typed forms the sibling authz view in `d2b-core` emits), so a row +/// cannot carry a class the privilege model does not name. +pub use d2b_core::privileges::{AuditMode, BrokerRequirement, SecretAccess}; + /// The declared durability facet of one state cell. /// /// The facet rides the committed row (U3/KTD3): a one-time cell persists its diff --git a/packages/d2b-broker/src/envelope/mod.rs b/packages/d2b-broker/src/envelope/mod.rs index 5120a8331..68d1a8976 100644 --- a/packages/d2b-broker/src/envelope/mod.rs +++ b/packages/d2b-broker/src/envelope/mod.rs @@ -2105,7 +2105,9 @@ impl OperationDispatcher for KernelDispatcher { #[cfg(test)] mod tests { use super::*; - use crate::catalog::{BrokerAuthzFacets, DeadlineTier, OperationOwner}; + use crate::catalog::{ + AuditMode, BrokerAuthzFacets, BrokerRequirement, DeadlineTier, OperationOwner, SecretAccess, + }; use crate::forwarding::{ ForwardFuture, ForwardedOperation, OperationForwarder, SocketForwarder, }; @@ -2299,9 +2301,9 @@ mod tests { scope: "per-zone", allowed_groups: groups, destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: fields, diff --git a/packages/d2b-broker/src/generated/broker_operation_catalog.rs b/packages/d2b-broker/src/generated/broker_operation_catalog.rs index 51abcb2e3..59bb8f3c0 100644 --- a/packages/d2b-broker/src/generated/broker_operation_catalog.rs +++ b/packages/d2b-broker/src/generated/broker_operation_catalog.rs @@ -22,9 +22,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -54,9 +54,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -86,9 +86,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -118,9 +118,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global", allowed_groups: &["d2bd"], destructive: true, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -150,9 +150,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-role", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -182,9 +182,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -214,9 +214,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/key", allowed_groups: &["d2bd"], destructive: false, - secret_access: "ReadWrite", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::ReadWrite, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -246,9 +246,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -278,9 +278,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/feature", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -310,9 +310,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -342,9 +342,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -374,9 +374,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -406,9 +406,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/per-selector", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -438,9 +438,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -470,9 +470,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/per-media-ref", allowed_groups: &["d2bd"], destructive: true, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -502,9 +502,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "host", allowed_groups: &["d2bd"], destructive: false, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -534,9 +534,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/per-media-ref", allowed_groups: &["d2bd"], destructive: true, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -566,9 +566,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -598,9 +598,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: false, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Errors", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Errors, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -630,9 +630,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -662,9 +662,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/per-media-ref", allowed_groups: &["d2bd"], destructive: true, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -694,9 +694,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/per-media-ref", allowed_groups: &["d2bd"], destructive: true, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -726,9 +726,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role/channel", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -758,9 +758,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -790,9 +790,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM/per-role", allowed_groups: &["d2bd"], destructive: true, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -822,9 +822,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM/per-role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -854,9 +854,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -886,9 +886,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/key", allowed_groups: &["d2bd"], destructive: false, - secret_access: "ReadWrite", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::ReadWrite, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -918,9 +918,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/key", allowed_groups: &["d2bd"], destructive: true, - secret_access: "ReadWrite", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::ReadWrite, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -950,9 +950,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-busid/env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "RedactedOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -982,9 +982,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-busid", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1014,9 +1014,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-busid/env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1046,9 +1046,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-busid/env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1078,9 +1078,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-busid/env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1110,9 +1110,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-busid/env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1142,9 +1142,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["vm"], @@ -1174,9 +1174,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1206,9 +1206,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1238,9 +1238,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-device-label", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1270,9 +1270,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "host", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1302,9 +1302,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Wire, payload_fields: &[], @@ -1334,9 +1334,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-operation row", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &[], @@ -1366,9 +1366,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-process", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["expectedStartTimeTicks", "pid"], @@ -1398,9 +1398,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "accepted Unix socket", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &[], @@ -1430,9 +1430,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &[], @@ -1462,9 +1462,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["baseDir", "createdPaths", "kind", "mode", "ownerGid", "ownerUid", "vmIdOrScope"], @@ -1494,9 +1494,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role leaf", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["cgroupPath"], @@ -1526,9 +1526,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["signal"], @@ -1558,9 +1558,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &[], @@ -1590,9 +1590,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["activationInput", "argv", "binaryPath", "capabilities", "cgroupPlacement", "deviceWorker", "env", "gid", "mountPolicy", "namespaces", "preflightSocketPaths", "role", "rootCarveOut", "runnerIdentity", "seccompPolicyRef", "servingWorker", "skipBinaryExistsCheck", "supplementaryGroups", "swtpmIdentity", "uid", "umask", "userNamespace"], @@ -1622,9 +1622,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["path"], @@ -1654,9 +1654,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["path"], @@ -1686,9 +1686,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["resourceRef", "resourceUid", "roleId", "runtimeScope", "vmId", "zoneUid"], @@ -1718,9 +1718,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["pid", "resourceRef", "resourceUid", "roleId", "runtimeScope", "vmId", "zoneUid"], @@ -1750,9 +1750,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-invocation", allowed_groups: &["d2bd", "d2b-admin", "d2b-launcher"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["guestGeneration", "guestUid", "operation", "operationId", "policyRevision", "providerAssignmentGeneration", "stopOnly", "zoneUid"], @@ -1782,9 +1782,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-invocation", allowed_groups: &["d2bd", "d2b-admin", "d2b-launcher"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["guestGeneration", "guestUid", "operation", "operationId", "policyRevision", "providerAssignmentGeneration", "stopOnly", "zoneUid"], @@ -1814,9 +1814,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-host firewall table", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["coexistencePolicy", "desiredHash", "destroy", "family", "ownershipId", "scriptBody", "table", "tableHashAfterApply"], @@ -1846,9 +1846,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-network firewall projection", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["action", "callerHash", "expectedGenerationId", "installedGenerationId", "marker", "scriptBody", "trustedHash"], @@ -1878,9 +1878,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-host NetworkManager unmanaged", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["contents", "destroy", "filePath", "group", "intentId", "mode", "owner", "reloadBehavior"], @@ -1910,9 +1910,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-network route", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["destination", "destroy", "device", "intentId", "owned", "ownershipMarker", "provenance", "routeName", "routeSpec", "table", "via"], @@ -1942,9 +1942,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-network sysctl", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["destroy", "key", "value"], @@ -1974,9 +1974,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-network bridge", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bridgeIfname", "intentId", "ipv4Address", "ipv6Suppressed", "mtu", "multicastSnoopingDisabled", "ownershipMarker", "provenance", "scopeLabel", "stpDisabled"], @@ -2006,9 +2006,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-network bridge", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bridgeIfname", "intentId", "ipv4Address", "ipv6Suppressed", "mtu", "multicastSnoopingDisabled", "ownershipMarker", "provenance", "scopeLabel", "stpDisabled"], @@ -2038,9 +2038,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role attachment", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["admittedInterfaceNames", "attachmentGeneration", "attachmentId", "bundleGeneration", "bundleTapIntentRef", "networkGeneration", "networkUid", "roleId", "tracingSpanId", "vmId", "zoneUid"], @@ -2070,9 +2070,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role attachment", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentId", "expectedAttachmentGeneration", "expectedBundleGeneration", "expectedNetworkGeneration", "expectedNetworkUid", "expectedZoneUid", "tracingSpanId"], @@ -2102,9 +2102,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role attachment", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["admittedInterfaceNames", "attachmentGeneration", "attachmentId", "bundleGeneration", "bundleTapIntentRef", "networkGeneration", "networkUid", "roleId", "tracingSpanId", "vmId", "zoneUid"], @@ -2134,9 +2134,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role bridge port", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["networkTapContext", "roleId", "tracingSpanId", "vmId"], @@ -2166,9 +2166,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-host hosts file", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["destroy", "endMarker", "intentId", "managedBlock", "mode", "ownershipMarker", "path", "provenance", "startMarker"], @@ -2198,9 +2198,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM dnsmasq lease", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentGeneration", "bundleGeneration", "networkGeneration", "networkUid", "scopeId", "tracingSpanId", "vmId", "zoneUid"], @@ -2230,9 +2230,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleNftIntentRef", "desiredHash", "destroy", "scopeId", "tracingSpanId"], @@ -2262,9 +2262,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["action", "attachmentGeneration", "bundleNftProjectionIntentRef", "desiredHash", "expectedGenerationId", "networkGeneration", "networkUid", "scopeId", "tracingSpanId", "zoneUid"], @@ -2294,9 +2294,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleNmIntentRef", "destroy", "scopeId", "tracingSpanId"], @@ -2326,9 +2326,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentGeneration", "bundleGeneration", "bundleRouteIntentRef", "destroy", "networkGeneration", "networkUid", "scopeId", "tracingSpanId", "zoneUid"], @@ -2358,9 +2358,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentGeneration", "bundleGeneration", "bundleSysctlIntentRef", "destroy", "networkGeneration", "networkUid", "scopeId", "tracingSpanId", "zoneUid"], @@ -2390,9 +2390,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentGeneration", "bundleBridgeIntentRef", "bundleGeneration", "networkGeneration", "networkUid", "scopeId", "tracingSpanId", "zoneUid"], @@ -2422,9 +2422,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentGeneration", "bundleBridgeIntentRef", "bundleGeneration", "networkGeneration", "networkUid", "scopeId", "tracingSpanId", "zoneUid"], @@ -2454,9 +2454,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-env/VM/TAP", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["admittedInterfaceNames", "attachmentGeneration", "attachmentId", "bundleGeneration", "bundleTapIntentRef", "networkGeneration", "networkUid", "roleId", "tracingSpanId", "vmId", "zoneUid"], @@ -2486,9 +2486,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-env/VM/TAP", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentId", "expectedAttachmentGeneration", "expectedBundleGeneration", "expectedNetworkGeneration", "expectedNetworkUid", "expectedZoneUid", "tracingSpanId"], @@ -2518,9 +2518,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-env/VM/TAP", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["admittedInterfaceNames", "attachmentGeneration", "attachmentId", "bundleGeneration", "bundleTapIntentRef", "networkGeneration", "networkUid", "roleId", "tracingSpanId", "vmId", "zoneUid"], @@ -2550,9 +2550,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-env/VM/TAP", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["networkTapContext", "roleId", "tracingSpanId", "vmId"], @@ -2582,9 +2582,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentGeneration", "bundleGeneration", "bundleHostsIntentRef", "destroy", "networkGeneration", "networkUid", "tracingSpanId", "zoneUid"], @@ -2614,9 +2614,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/env", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["attachmentGeneration", "bundleGeneration", "networkGeneration", "networkUid", "scopeId", "tracingSpanId", "vmId", "zoneUid"], @@ -2646,9 +2646,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleRunnerIntentRef", "expectedStartTimeTicks", "generation", "guestExecution", "ownerRef", "pid", "providerIdentity", "providerRef", "resourceRef", "resourceUid", "roleId", "runtimeScope", "templateIdentity", "vmId", "zoneUid"], @@ -2678,9 +2678,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "accepted Unix socket", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &[], @@ -2710,9 +2710,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleRunnerIntentRef", "generation", "guestExecution", "ownerRef", "providerIdentity", "providerRef", "resourceRef", "resourceUid", "role", "roleId", "runtimeScope", "templateIdentity", "vmId", "zoneUid"], @@ -2742,9 +2742,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &[], @@ -2774,9 +2774,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["pathClass", "vmId"], @@ -2806,9 +2806,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "global/per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["pathClass", "vmId"], @@ -2838,9 +2838,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role leaf", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["roleId", "vmId"], @@ -2870,9 +2870,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleRunnerIntentRef", "expectedStartTimeTicks", "generation", "guestExecution", "ownerRef", "pid", "providerIdentity", "providerRef", "resourceRef", "resourceUid", "roleId", "runtimeScope", "signal", "templateIdentity", "vmId", "zoneUid"], @@ -2902,9 +2902,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM", allowed_groups: &["d2b-launcher", "d2b-admin"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["expectedStartTimeTicks", "generation", "guestExecution", "ownerRef", "pid", "providerIdentity", "providerRef", "resourceRef", "resourceUid", "roleId", "runtimeScope", "templateIdentity", "vmId", "zoneUid"], @@ -2934,9 +2934,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["activationInput", "bundleContentIdentity", "bundleRunnerIntentRef", "executionDomain", "executionRef", "generation", "guestExecution", "inheritedFdCount", "launchArgs", "ownerRef", "ownerUid", "providerIdentity", "providerRef", "resourceRef", "resourceUid", "role", "roleId", "runtimeAllocations", "runtimeScope", "sandboxPlan", "templateIdentity", "tracingSpanId", "userRef", "vmId", "workloadIdentity", "zoneUid"], @@ -2966,9 +2966,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-type", allowed_groups: &["d2bd", "d2b-admin"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["resourceType"], @@ -2998,9 +2998,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleContentIdentity", "bundleRunnerIntentRef", "domain", "executionRef", "generation", "guestExecution", "providerIdentity", "resourceRef", "resourceUid", "role", "roleId", "sandboxPlan", "templateIdentity", "tracingSpanId", "userRef", "vmId"], @@ -3030,9 +3030,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-user", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleContentIdentity", "bundleRunnerIntentRef", "domain", "executionRef", "generation", "guestExecution", "providerIdentity", "resourceRef", "resourceUid", "role", "roleId", "sandboxPlan", "templateIdentity", "tracingSpanId", "userRef", "vmId"], @@ -3062,9 +3062,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "MetadataOnly", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleContentIdentity", "bundleRunnerIntentRef", "domain", "executionRef", "generation", "guestExecution", "providerIdentity", "resourceRef", "resourceUid", "role", "roleId", "sandboxPlan", "templateIdentity", "tracingSpanId", "userRef", "vmId"], @@ -3094,9 +3094,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: false, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleContentIdentity", "bundleRunnerIntentRef", "domain", "executionRef", "expected", "generation", "guestExecution", "providerIdentity", "resourceRef", "resourceUid", "role", "roleId", "sandboxPlan", "templateIdentity", "tracingSpanId", "userRef", "vmId"], @@ -3126,9 +3126,9 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ scope: "per-VM/role", allowed_groups: &["d2bd"], destructive: true, - secret_access: "None", - broker_required: "Yes", - audit_mode: "Yes", + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, }, payload_provenance: PayloadProvenance::Request, payload_fields: &["bundleContentIdentity", "bundleRunnerIntentRef", "class", "domain", "executionRef", "expected", "generation", "guestExecution", "providerIdentity", "resourceRef", "resourceUid", "role", "roleId", "sandboxPlan", "templateIdentity", "tracingSpanId", "userRef", "vmId"], diff --git a/packages/d2b-core/src/privileges.rs b/packages/d2b-core/src/privileges.rs index 41e73bd7f..d33e5a39d 100644 --- a/packages/d2b-core/src/privileges.rs +++ b/packages/d2b-core/src/privileges.rs @@ -43,7 +43,7 @@ pub struct OperationAuthz { } /// Secret exposure class for an authorization row. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] pub enum SecretAccess { None, @@ -56,7 +56,7 @@ pub enum SecretAccess { } /// Broker-use class for an authorization row. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] pub enum BrokerRequirement { No, @@ -78,7 +78,7 @@ pub struct AuditPolicy { } /// Audit mode for compact policy rows. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] pub enum AuditMode { DenyOnly, diff --git a/packages/xtask/src/gen_broker_operations.rs b/packages/xtask/src/gen_broker_operations.rs index fa04ccb01..e2a5c1626 100644 --- a/packages/xtask/src/gen_broker_operations.rs +++ b/packages/xtask/src/gen_broker_operations.rs @@ -977,14 +977,17 @@ fn generate_catalog(catalog: &Catalog) -> String { )); rows.push_str(&format!(" destructive: {},\n", row.authz.destructive)); rows.push_str(&format!( - " secret_access: \"{}\",\n", + " secret_access: SecretAccess::{},\n", row.authz.secret_access )); rows.push_str(&format!( - " broker_required: \"{}\",\n", + " broker_required: BrokerRequirement::{},\n", row.authz.broker_required )); - rows.push_str(&format!(" audit_mode: \"{}\",\n", row.authz.audit_mode)); + rows.push_str(&format!( + " audit_mode: AuditMode::{},\n", + row.authz.audit_mode + )); rows.push_str(" },\n"); rows.push_str(&format!( " payload_provenance: PayloadProvenance::{},\n", From 776ddb336105e71843cf359da46098e07f13f48a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:46:08 -0700 Subject: [PATCH 579/726] provider-toolkit: share the ordered call log across family test-support doubles The Guest, User, and VolumeBinding test-support doubles each hand-rolled the same recorder shape (a Mutex-guarded Vec call log plus a snapshot accessor) instead of reusing the toolkit's shipped testing module. Ship the shape once as testing::SharedLog and delegate the family recorders onto it; the doubles' public APIs are unchanged. --- changelog.d/w4-23-test-support-shared-log.md | 6 ++ .../d2b-provider-guest/src/test_support.rs | 32 ++++----- packages/d2b-provider-toolkit/src/lib.rs | 2 +- .../d2b-provider-toolkit/src/testing/fakes.rs | 65 +++++++++++++++++++ .../d2b-provider-toolkit/src/testing/mod.rs | 2 +- .../d2b-provider-user/src/test_support.rs | 13 ++-- .../src/test_support.rs | 40 ++++++------ 7 files changed, 120 insertions(+), 40 deletions(-) create mode 100644 changelog.d/w4-23-test-support-shared-log.md diff --git a/changelog.d/w4-23-test-support-shared-log.md b/changelog.d/w4-23-test-support-shared-log.md new file mode 100644 index 000000000..2770130b2 --- /dev/null +++ b/changelog.d/w4-23-test-support-shared-log.md @@ -0,0 +1,6 @@ +### Fixed + +- The Guest, User, and VolumeBinding provider test-support doubles now record + through the provider toolkit's shared ordered call log instead of each + crate carrying its own recorder shape, so the recording doubles cannot + drift apart. \ No newline at end of file diff --git a/packages/d2b-provider-guest/src/test_support.rs b/packages/d2b-provider-guest/src/test_support.rs index e76948cc6..aff169cd7 100644 --- a/packages/d2b-provider-guest/src/test_support.rs +++ b/packages/d2b-provider-guest/src/test_support.rs @@ -19,6 +19,10 @@ //! automatically under `cargo test`), so production consumers never pull //! them in. The plane tests in `d2bd` reach them through the same public //! surface. +//! +//! The doubles' ordered call recorders are the toolkit's `SharedLog` +//! (`d2b_provider_toolkit::testing`), the canonical recorder shape every +//! family crate's test-support module shares. use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -27,6 +31,7 @@ use d2b_contracts_resource::v3::identity::ReconnectGeneration; use d2b_contracts_resource::v3::{ ControllerGeneration, ResourceGeneration, ResourceRef, ResourceUid, ZoneId, }; +use d2b_provider_toolkit::testing::SharedLog; use d2b_resource_runtime::identity::ResourceKey; use d2b_resource_runtime::manager::ResourceView; use d2b_resource_runtime::ResourceStatus; @@ -56,7 +61,7 @@ pub struct EffectObservation { /// Scripted [`GuestDriverEffects`] double: records every call and answers /// with the configured outcome. pub struct ScriptedEffects { - calls: parking_lot::Mutex>, + calls: SharedLog, /// Optional shared order log (the recording manager's), so tests can /// compare the provider stage against the child mutations. shared: Option>>>, @@ -71,7 +76,7 @@ impl ScriptedEffects { /// and a Complete finalize stage. pub fn new() -> Arc { Arc::new(Self { - calls: parking_lot::Mutex::new(Vec::new()), + calls: SharedLog::new(), shared: None, observations: parking_lot::Mutex::new(Vec::new()), phase: parking_lot::Mutex::new(GuestEffectPhase::Ready), @@ -93,7 +98,7 @@ impl ScriptedEffects { if let Some(shared) = &self.shared { shared.lock().push(entry.clone()); } - self.calls.lock().push(entry); + self.calls.record(entry); } /// Script the phase the next `reconcile` reports. @@ -113,7 +118,7 @@ impl ScriptedEffects { /// The observed call labels in arrival order. pub fn call_order(&self) -> Vec { - self.calls.lock().clone() + self.calls.entries() } /// The recorded `reconcile` observations in arrival order. @@ -174,7 +179,7 @@ pub struct ScriptedFacets { session_generation: parking_lot::Mutex>, cloud_hypervisor_outcome: parking_lot::Mutex, fail_reads: parking_lot::Mutex, - calls: parking_lot::Mutex>, + calls: SharedLog, } impl ScriptedFacets { @@ -190,7 +195,7 @@ impl ScriptedFacets { session_generation: parking_lot::Mutex::new(None), cloud_hypervisor_outcome: parking_lot::Mutex::new(GuestCloudHypervisorOutcome::Ready), fail_reads: parking_lot::Mutex::new(false), - calls: parking_lot::Mutex::new(Vec::new()), + calls: SharedLog::new(), }) } @@ -239,14 +244,14 @@ impl ScriptedFacets { /// The observed read labels in arrival order. pub fn call_order(&self) -> Vec { - self.calls.lock().clone() + self.calls.entries() } } #[async_trait::async_trait] impl GuestManagerView for ScriptedFacets { async fn row_view(&self, key: &ResourceKey) -> Result, ()> { - self.calls.lock().push(format!("row:{key}")); // async-gate-allow: test-support recorder lock + self.calls.record(format!("row:{key}")); if *self.fail_reads.lock() { // async-gate-allow: test-support recorder lock return Err(()); } @@ -258,8 +263,7 @@ impl GuestManagerView for ScriptedFacets { provider_ref: &ResourceRef, ) -> Result, ()> { self.calls - .lock() - .push(format!("committed:{}", provider_ref.to_canonical_string())); + .record(format!("committed:{}", provider_ref.to_canonical_string())); if *self.fail_reads.lock() { return Err(()); } @@ -267,7 +271,7 @@ impl GuestManagerView for ScriptedFacets { } fn controller_session_generation(&self) -> Result, ()> { - self.calls.lock().push("session-generation".to_owned()); + self.calls.record("session-generation".to_owned()); if *self.fail_reads.lock() { return Err(()); } @@ -279,8 +283,7 @@ impl GuestManagerView for ScriptedFacets { impl CloudHypervisorGuestRuntime for ScriptedFacets { async fn ensure_target_session(&self, guest_ref: &ResourceRef) -> Result<(), String> { self.calls - .lock() // async-gate-allow: test-support recorder lock - .push(format!("ensure-session:{}", guest_ref.to_canonical_string())); + .record(format!("ensure-session:{}", guest_ref.to_canonical_string())); Ok(()) } @@ -290,8 +293,7 @@ impl CloudHypervisorGuestRuntime for ScriptedFacets { _status_sink: Option, ) -> Result { self.calls - .lock() // async-gate-allow: test-support recorder lock - .push(format!("reconcile-ch:{}", guest_ref.to_canonical_string())); + .record(format!("reconcile-ch:{}", guest_ref.to_canonical_string())); Ok(*self.cloud_hypervisor_outcome.lock()) // async-gate-allow: test-support recorder lock } } diff --git a/packages/d2b-provider-toolkit/src/lib.rs b/packages/d2b-provider-toolkit/src/lib.rs index d86565a9a..c7f53e3d4 100644 --- a/packages/d2b-provider-toolkit/src/lib.rs +++ b/packages/d2b-provider-toolkit/src/lib.rs @@ -153,7 +153,7 @@ pub use testing::{ AdmissionRefusal, AdmittedRow, DeterministicClock, FIXTURE_NOW_UNIX_MS, FakeBus, FakeCoreClient, FakeEffectPort, FakePortError, FakeProvider, FakeResourceStore, FakeSupervisor, FaultInjector, FaultPlan, Fixture, HarnessDeclarations, MAX_RECORDED_CALLS, PlaneCall, - RecordingPlanePort, RowPhase, RowStatus, SampleLeaseRequest, TestHarness, block_on, + RecordingPlanePort, RowPhase, RowStatus, SampleLeaseRequest, SharedLog, TestHarness, block_on, sample_lease_request, }; diff --git a/packages/d2b-provider-toolkit/src/testing/fakes.rs b/packages/d2b-provider-toolkit/src/testing/fakes.rs index 2d390e61b..2d20e88c8 100644 --- a/packages/d2b-provider-toolkit/src/testing/fakes.rs +++ b/packages/d2b-provider-toolkit/src/testing/fakes.rs @@ -27,6 +27,7 @@ //! was handed. use std::collections::BTreeMap; +use std::sync::Arc; use d2b_contracts_provider::v3::{DependencyAlias, ProviderManifest}; use d2b_contracts_resource::v3::ArtifactId; @@ -227,6 +228,52 @@ impl CallRecorder { } } +/// A shared ordered call log for recording doubles. +/// +/// The provider family crates' scripted effect doubles previously carried +/// private copies of this shape (a fresh `Arc>>` plus a +/// snapshot accessor) in each `test_support` module; this is that log, once. +/// The log is deliberately unbounded and free-form: a recording double +/// appends the labels its own tests assert on - including formatted values - +/// which the bounded [`CallRecorder`] refuses by design. The log is shared +/// by `Arc`, so a manager endpoint and an effect double can append to one +/// sequence. +#[derive(Debug, Clone, Default)] +pub struct SharedLog(Arc>>); + +impl SharedLog { + /// A fresh, empty shared log. + pub fn new() -> Self { + Self::default() + } + + /// Append one entry. + /// + /// Every double holding a clone of this log observes the entry. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] + pub fn record(&self, entry: String) { + self.0 + .lock() + .expect("a test-support recorder lock is never poisoned") + .push(entry); + } + + /// Snapshot the entries in arrival order. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] + pub fn entries(&self) -> Vec { + self.0 + .lock() + .expect("a test-support recorder lock is never poisoned") + .clone() + } +} + +impl From>>> for SharedLog { + fn from(log: Arc>>) -> Self { + Self(log) + } +} + /// A fake Zone core client: artifact catalog lookup and readiness. /// /// Core resolves an `artifactId` to a signed manifest and computes the @@ -553,4 +600,22 @@ mod tests { assert!(port.apply(&effect).is_ok()); assert_eq!(port.recorder().count_of("apply-effect"), 1); } + + #[test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn a_shared_log_records_in_order_and_shares_a_wrapped_manager_log() { + let log = SharedLog::new(); + log.record("first".to_owned()); + log.record("second".to_owned()); + assert_eq!(log.entries(), ["first".to_owned(), "second".to_owned()]); + + let raw: Arc>> = Arc::new(std::sync::Mutex::new(Vec::new())); + let wrapped = SharedLog::from(Arc::clone(&raw)); + wrapped.record("shared".to_owned()); + assert_eq!(wrapped.entries(), ["shared".to_owned()]); + assert_eq!( + *raw.lock().expect("the test holds the only reference"), + ["shared".to_owned()] + ); + } } diff --git a/packages/d2b-provider-toolkit/src/testing/mod.rs b/packages/d2b-provider-toolkit/src/testing/mod.rs index 38f3c615a..4b2691d88 100644 --- a/packages/d2b-provider-toolkit/src/testing/mod.rs +++ b/packages/d2b-provider-toolkit/src/testing/mod.rs @@ -31,7 +31,7 @@ pub mod fixture; pub use fakes::{ FakeBus, FakeCoreClient, FakeEffectPort, FakePortError, FakeResourceStore, FakeSupervisor, - FaultPlan, MAX_RECORDED_CALLS, + FaultPlan, MAX_RECORDED_CALLS, SharedLog, }; pub use fixture::{ DeterministicClock, FIXTURE_NOW_UNIX_MS, FakeProvider, Fixture, SampleLeaseRequest, diff --git a/packages/d2b-provider-user/src/test_support.rs b/packages/d2b-provider-user/src/test_support.rs index 5a9863731..9997856e0 100644 --- a/packages/d2b-provider-user/src/test_support.rs +++ b/packages/d2b-provider-user/src/test_support.rs @@ -19,6 +19,10 @@ //! Gated behind the `test-support` Cargo feature (available automatically //! under `cargo test`), so production consumers never pull it in. The plane //! tests in `d2bd` reach it through the same public surface. +//! +//! The doubles' ordered call recorder is the toolkit's `SharedLog` +//! (`d2b_provider_toolkit::testing`), the canonical recorder shape every +//! family crate's test-support module shares. use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; @@ -29,6 +33,7 @@ use d2b_provider_system_core::{ DiscoveredUser, SystemCoreError, UserBinding, UserDiscoveryCondition, UserDiscoveryEffectPort, UserIdentityDigest, UserObservation, UserStatusReport, }; +use d2b_provider_toolkit::testing::SharedLog; use crate::driver::UserDriverEffects; use crate::facets::UserEffectFacets; @@ -38,7 +43,7 @@ use crate::facets::UserEffectFacets; /// Scripted discovery port: records every call order-preservingly and can /// fail discovery. pub struct RecordingEffects { - calls: parking_lot::Mutex>, + calls: SharedLog, phase: parking_lot::Mutex, /// Script whether the next discovery refuses. pub fail: AtomicBool, @@ -49,7 +54,7 @@ impl RecordingEffects { /// calls. pub fn new() -> Arc { Arc::new(Self { - calls: parking_lot::Mutex::new(Vec::new()), + calls: SharedLog::new(), phase: parking_lot::Mutex::new(ResourcePhase::Ready), fail: AtomicBool::new(false), }) @@ -57,7 +62,7 @@ impl RecordingEffects { /// The observed call labels in arrival order. pub fn call_order(&self) -> Vec { - self.calls.lock().clone() + self.calls.entries() } /// Script the phase the next discovery reports. @@ -73,7 +78,7 @@ impl UserDriverEffects for RecordingEffects { user_ref: &ResourceRef, _spec: &UserSpec, ) -> Result { - self.calls.lock().push("observe-user".to_owned()); // async-gate-allow: test-support recorder lock + self.calls.record("observe-user".to_owned()); if self.fail.load(Ordering::Relaxed) { return Err("the scripted discovery refused".to_owned()); } diff --git a/packages/d2b-provider-volume-binding/src/test_support.rs b/packages/d2b-provider-volume-binding/src/test_support.rs index 5aab0aad3..0e2eff75c 100644 --- a/packages/d2b-provider-volume-binding/src/test_support.rs +++ b/packages/d2b-provider-volume-binding/src/test_support.rs @@ -2,9 +2,14 @@ //! //! Gated behind the `test-support` Cargo feature so production //! consumers never pull this in. +//! +//! The double's ordered log is the toolkit's `SharedLog` +//! (`d2b_provider_toolkit::testing`), the canonical recorder shape every +//! family crate's test-support module shares. -use std::sync::{Arc, Mutex}; +use std::sync::Arc; +use d2b_provider_toolkit::testing::SharedLog; use d2b_provider_volume_virtiofs::{SocketIdentity, StoredBinding}; use d2b_resource_runtime::identity::ResourceKey; @@ -13,7 +18,7 @@ use crate::driver::BindingDriverEffects; /// Scripted serving port over the caller's ordered log, so the tests /// assert one sequence across manager calls and serving effects. pub struct FakeServingEffects { - log: Arc>>, + log: SharedLog, ready: std::sync::atomic::AtomicBool, mounted: std::sync::atomic::AtomicBool, } @@ -21,14 +26,18 @@ pub struct FakeServingEffects { impl FakeServingEffects { /// A fresh double with its own ordered log. pub fn new() -> Arc { - Self::shared(Arc::new(Mutex::new(Vec::new()))) + Arc::new(Self { + log: SharedLog::new(), + ready: std::sync::atomic::AtomicBool::new(false), + mounted: std::sync::atomic::AtomicBool::new(false), + }) } /// A double whose ordered log is shared with the caller's manager /// logger, so manager calls and serving effects read as one sequence. - pub fn shared(log: Arc>>) -> Arc { + pub fn shared(log: Arc>>) -> Arc { Arc::new(Self { - log, + log: SharedLog::from(log), ready: std::sync::atomic::AtomicBool::new(false), mounted: std::sync::atomic::AtomicBool::new(false), }) @@ -46,8 +55,7 @@ impl FakeServingEffects { /// The ordered serving-effect log, shared with any manager logger. pub fn call_order(&self) -> Vec { - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - self.log.lock().unwrap().clone() + self.log.entries() } /// The facet set the plane and this crate's tests build the driver and @@ -69,8 +77,7 @@ struct ScriptedReady(Arc); #[async_trait::async_trait] impl crate::facets::SocketReadySource for ScriptedReady { async fn ready(&self, _socket: &SocketIdentity) -> bool { - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - self.0.log.lock().unwrap().push("socket-ready".to_owned()); // async-gate-allow: test-support recorder lock + self.0.log.record("socket-ready".to_owned()); self.0.ready.load(std::sync::atomic::Ordering::SeqCst) } } @@ -82,8 +89,7 @@ struct ScriptedRemove(Arc); #[async_trait::async_trait] impl crate::facets::SocketRemoveSource for ScriptedRemove { async fn remove(&self, _socket: &SocketIdentity) -> Result<(), String> { - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - self.0.log.lock().unwrap().push("remove-socket".to_owned()); // async-gate-allow: test-support recorder lock + self.0.log.record("remove-socket".to_owned()); Ok(()) } } @@ -95,8 +101,7 @@ struct ScriptedGuestMount(Arc); #[async_trait::async_trait] impl crate::facets::GuestMountSource for ScriptedGuestMount { async fn guest_mount_ready(&self, _key: &ResourceKey) -> Result { - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - self.0.log.lock().unwrap().push("guest-mount".to_owned()); // async-gate-allow: test-support recorder lock + self.0.log.record("guest-mount".to_owned()); Ok(self.0.mounted.load(std::sync::atomic::Ordering::SeqCst)) } } @@ -104,14 +109,12 @@ impl crate::facets::GuestMountSource for ScriptedGuestMount { #[async_trait::async_trait] impl BindingDriverEffects for FakeServingEffects { async fn socket_ready(&self, _socket: &SocketIdentity) -> bool { - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - self.log.lock().unwrap().push("socket-ready".to_owned()); // async-gate-allow: test-support recorder lock + self.log.record("socket-ready".to_owned()); self.ready.load(std::sync::atomic::Ordering::SeqCst) } async fn remove_socket(&self, _socket: &SocketIdentity) -> Result<(), String> { - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - self.log.lock().unwrap().push("remove-socket".to_owned()); // async-gate-allow: test-support recorder lock + self.log.record("remove-socket".to_owned()); Ok(()) } @@ -120,8 +123,7 @@ impl BindingDriverEffects for FakeServingEffects { _key: &ResourceKey, _binding: &StoredBinding, ) -> Result { - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - self.log.lock().unwrap().push("guest-mount".to_owned()); // async-gate-allow: test-support recorder lock + self.log.record("guest-mount".to_owned()); Ok(self.mounted.load(std::sync::atomic::Ordering::SeqCst)) } } From 5a5d72cca9b4d2880d75f54080d1d6556fdadc5d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:51:09 -0700 Subject: [PATCH 580/726] provider: fix cutover fallout in provider crates and d2bd - Import ZoneId in the security-key, usbip, and network-local driver test modules where the driver-args constructors now parse zones. - d2bd: replace the ? on Result key_ref inside map_err closures with the already-computed device reference (reconcile_tpm) or a hoisted canonical string (finalize_gpu), since those closures do not return Result. --- packages/d2b-provider-device-security-key/src/driver.rs | 3 ++- packages/d2b-provider-device-usbip/src/driver.rs | 3 +-- packages/d2b-provider-network-local/src/driver.rs | 4 ++-- packages/d2bd/src/shared_provider_effects.rs | 5 +++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/d2b-provider-device-security-key/src/driver.rs b/packages/d2b-provider-device-security-key/src/driver.rs index 7f3282cd9..01ed455b4 100644 --- a/packages/d2b-provider-device-security-key/src/driver.rs +++ b/packages/d2b-provider-device-security-key/src/driver.rs @@ -540,7 +540,8 @@ mod tests { use super::{ PROVIDER_REF, SECURITY_KEY_BINDING_RESOURCE_TYPE, SECURITY_KEY_REGISTRATIONS, - SECURITY_KEY_SERVICE_RESOURCE_TYPE, SecurityKeyDriverArgs, security_key_descriptors, + SECURITY_KEY_SERVICE_RESOURCE_TYPE, SecurityKeyDriverArgs, ZoneId, + security_key_descriptors, }; fn descriptors() -> [d2b_resource_types::DriverDescriptor; 2] { diff --git a/packages/d2b-provider-device-usbip/src/driver.rs b/packages/d2b-provider-device-usbip/src/driver.rs index 5edd65c68..0204ea2ba 100644 --- a/packages/d2b-provider-device-usbip/src/driver.rs +++ b/packages/d2b-provider-device-usbip/src/driver.rs @@ -332,8 +332,7 @@ mod tests { use super::{ PROVIDER_REF, USBIP_REGISTRATIONS, USB_BINDING_RESOURCE_TYPE, USB_SERVICE_RESOURCE_TYPE, - UsbipComponent, UsbipDriverArgs, - usbip_descriptors, + UsbipComponent, UsbipDriverArgs, ZoneId, usbip_descriptors, }; fn descriptors() -> [d2b_resource_types::DriverDescriptor; 2] { diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index eb401b584..592f5e60a 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -416,8 +416,8 @@ mod tests { use serde_json::json; use super::{ - NETWORK_PROVIDER_REF, NETWORK_TYPE_NAME, NetworkDriverArgs, declared_dependency_refs, - network_descriptor, network_spec, + NETWORK_PROVIDER_REF, NETWORK_TYPE_NAME, NetworkDriverArgs, ZoneId, + declared_dependency_refs, network_descriptor, network_spec, }; use crate::test_support::{RecordingRuntime, recording_facets}; diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 9c7c5e4b2..1364389fe 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -1667,7 +1667,7 @@ impl ProductionSharedProviderEffects { .map_err(|error| { tracing::warn!( error = ?error, - device = %key_ref(&request.target)?.to_canonical_string(), + device = %device_ref.to_canonical_string(), "TPM device controller reconcile failed", ); SharedProviderEffectError::Unavailable @@ -2641,10 +2641,11 @@ impl ProductionSharedProviderEffects { request.operation_id.clone(), ), ); + let device_ref = key_ref(&request.target)?.to_canonical_string(); let result = controller.finalize_lifecycle(&mut port).map_err(|error| { tracing::debug!( error = ?error, - device = %key_ref(&request.target)?.to_canonical_string(), + device = %device_ref, "GPU lifecycle finalize failed", ); SharedProviderEffectError::Unavailable From 7012afc8e7c3d439f56babacc65fd9010f37d627 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:58:05 -0700 Subject: [PATCH 581/726] repo: regenerate async-gate inventory, lockfile, and policy inputs after wave-4 merges --- Cargo.lock | 1 + .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 8 +- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 8 +- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +- .../main-product/production/metadata.json | 2 +- packages/xtask/data/async-gate-inventory.json | 242 +++++++----------- 46 files changed, 165 insertions(+), 186 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 595332279..05bbba237 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1445,6 +1445,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 555be5923..2c4df0899 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index 6c295e7e4..2d9ef0ae8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 4605d84b0..4f8685b15 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 6704376a2..b9fe215b4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index d682063ef..6e352a683 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 6704376a2..b9fe215b4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 35c3df180..dadb35ed5 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index fc90df939..f49e4e271 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 4fb432144..b5d7bca6d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index fc90df939..f49e4e271 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 8e8f2a062..241a6bb20 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index 8391216e9..b285e6176 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index f7d35b31f..c05db1845 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6431,6 +6431,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index 0377af754..fac7cacd3 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index d7db2118f..62dead8d8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6131,6 +6131,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index 0377af754..fac7cacd3 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 64f24b5c1..20923ddaa 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index d19ddd7c8..30f3d6dc5 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 46202be0e..e9f721886 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index d9d1b4233..42cc83add 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index c9ee284b2..ef10ff273 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index d9d1b4233..42cc83add 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 4619e988d..83656776c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index faa836089..be7a52035 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index aabfb01f4..c5a6e1f16 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index faa836089..be7a52035 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index c742450e7..669de35e6 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 7ff09a342..619cbc3df 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index 2f7a3c151..11907053c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6469,6 +6469,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index f81d43fa9..e5e3c1d14 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index bd09289ce..39bbdaa30 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6169,6 +6169,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index f81d43fa9..e5e3c1d14 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index c222c88c4..bed38ca1c 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -123,52 +123,52 @@ }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8127, + "line": 8154, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8194, + "line": 8221, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8411, + "line": 8438, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8488, + "line": 8515, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1034, + "line": 1033, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1051, + "line": 1050, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1064, + "line": 1063, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1085, + "line": 1084, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1089, + "line": 1088, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1112, + "line": 1111, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -183,77 +183,77 @@ }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1109, + "line": 1108, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1122, + "line": 1121, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1123, + "line": 1122, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1146, + "line": 1145, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1150, + "line": 1149, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1167, + "line": 1166, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1169, + "line": 1168, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1638, + "line": 1636, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1649, + "line": 1647, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1652, + "line": 1650, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1676, + "line": 1674, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1725, + "line": 1723, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1809, + "line": 1807, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1865, + "line": 1863, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1923, + "line": 1921, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -463,22 +463,22 @@ }, { "file": "packages/d2b-provider-device/tests/device_family.rs", - "line": 169, + "line": 167, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-endpoint/src/driver.rs", - "line": 672, + "line": 671, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-endpoint/src/driver.rs", - "line": 673, + "line": 672, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-endpoint/src/driver.rs", - "line": 899, + "line": 897, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -513,62 +513,62 @@ }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1620, + "line": 1619, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1627, + "line": 1626, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1639, + "line": 1638, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1640, + "line": 1639, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1675, + "line": 1674, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1702, + "line": 1701, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1708, + "line": 1707, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1715, + "line": 1714, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1721, + "line": 1720, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1728, + "line": 1727, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1755, + "line": 1754, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1763, + "line": 1762, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -583,67 +583,52 @@ }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 134, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 150, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 151, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 161, + "line": 139, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 249, + "line": 155, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 250, + "line": 156, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 253, + "line": 166, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 282, + "line": 255, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 293, + "line": 258, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 295, + "line": 297, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 647, + "line": 646, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 747, + "line": 746, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 748, + "line": 747, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -678,37 +663,37 @@ }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2452, + "line": 2451, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2463, + "line": 2462, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2464, + "line": 2463, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3255, + "line": 3253, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3265, + "line": 3263, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3370, + "line": 3368, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3732, + "line": 3730, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -818,22 +803,22 @@ }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 830, + "line": 832, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 841, + "line": 843, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 843, + "line": 845, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-provider/src/driver.rs", - "line": 847, + "line": 849, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -848,157 +833,122 @@ }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 504, + "line": 503, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 512, + "line": 511, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 520, + "line": 519, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 525, + "line": 524, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 526, + "line": 525, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 548, + "line": 547, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/driver.rs", - "line": 553, + "line": 552, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-user/src/test_support.rs", - "line": 76, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-user/src/test_support.rs", - "line": 83, + "line": 88, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-user/src/test_support.rs", - "line": 151, + "line": 156, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1237, + "line": 1236, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1255, + "line": 1254, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1272, + "line": 1271, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1284, + "line": 1283, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1299, + "line": 1298, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1303, + "line": 1302, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1330, + "line": 1329, "reason": "synchronous lock acquisition, no await while the guard is held" }, - { - "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 73, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 86, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 99, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 108, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 114, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-volume-binding/src/test_support.rs", - "line": 124, - "reason": "test-support recorder lock" - }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 804, + "line": 803, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 821, + "line": 820, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 837, + "line": 836, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 845, + "line": 844, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 859, + "line": 858, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 861, + "line": 860, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1131, + "line": 1129, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1319, + "line": 1315, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1013,22 +963,22 @@ }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 917, + "line": 914, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 1184, + "line": 1180, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 1212, + "line": 1208, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-resource-runtime/src/context.rs", - "line": 1221, + "line": 1217, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1128,17 +1078,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10786, + "line": 10790, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26253, + "line": 26251, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26650, + "line": 26648, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1148,17 +1098,17 @@ }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 2471, + "line": 2480, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 7478, + "line": 7507, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 8629, + "line": 8658, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From ea55636aa7d528872deb18b9a420dbf02cf0693c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 16:59:13 -0700 Subject: [PATCH 582/726] credential: surface dependency-facts read failures as typed errors CredentialRuntime::dependency_facts now returns Result, CredentialResourceRuntimeError> instead of Option: a manager RPC failure reaches the driver as Err (DependencyFacts) rather than being logged and answered as absence at the d2bd trait boundary. Ok(None) stays the honest not-committed answer, and the driver fails closed on both. The d2bd log-and-absent workaround is removed; the daemon error detail stays at debug level. --- Cargo.lock | 1 + changelog.d/w4-15-credential-facts-error.md | 8 ++-- .../d2b-provider-credential/src/driver.rs | 44 ++++++++++++------- .../src/effects_service.rs | 6 +-- .../d2b-provider-credential/src/facets.rs | 24 ++++++---- .../d2b-provider-credential/src/session.rs | 4 ++ .../src/test_support.rs | 8 ++-- .../tests/registration.rs | 8 ++-- packages/d2bd/src/resource_runtime.rs | 28 +++++------- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 8 +++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +++- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 8 +++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +++- .../main-product/production/metadata.json | 2 +- 53 files changed, 145 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 595332279..05bbba237 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1445,6 +1445,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/changelog.d/w4-15-credential-facts-error.md b/changelog.d/w4-15-credential-facts-error.md index 64048bc33..145431718 100644 --- a/changelog.d/w4-15-credential-facts-error.md +++ b/changelog.d/w4-15-credential-facts-error.md @@ -1,6 +1,8 @@ ### Fixed - A transient manager read failure during a credential dependency-facts probe - is no longer silently reported as missing dependency facts; the daemon now - logs the failure with the zone, provider, and execution refs instead of - degrading credential readiness and revocation decisions without a trace. \ No newline at end of file + is no longer reported as missing dependency facts: the + `CredentialRuntime::dependency_facts` facet now returns the failure as a + typed error that reaches the credential driver, so readiness and + revocation decisions fail closed on a failed read instead of degrading on + absence semantics. \ No newline at end of file diff --git a/packages/d2b-provider-credential/src/driver.rs b/packages/d2b-provider-credential/src/driver.rs index 98fe40d7b..1341dfaa9 100644 --- a/packages/d2b-provider-credential/src/driver.rs +++ b/packages/d2b-provider-credential/src/driver.rs @@ -261,14 +261,16 @@ pub struct CredentialLeaseFacts { /// the same seam (R4). #[async_trait::async_trait] pub trait CredentialDriverEffects: Send + Sync + 'static { - /// Provider + execution-target facts. `None` when the Provider row is - /// not observable to this daemon (the old controller was never started - /// without it; deletion still fails closed rather than guessing). + /// Provider + execution-target facts. `Ok(None)` when the Provider row + /// is not observable to this daemon (the old controller was never + /// started without it; deletion still fails closed rather than + /// guessing); `Err` when the dependency read itself failed (a manager + /// RPC failure), so absence is never answered for a failed read. async fn dependency_facts( &self, provider_ref: &ResourceRef, execution_ref: &ResourceRef, - ) -> Option; + ) -> Result, CredentialResourceRuntimeError>; /// Provider-side lease facts for one Credential row. async fn lease_facts(&self, credential_ref: &ResourceRef) -> Option; @@ -641,13 +643,19 @@ impl CredentialDriver { return Err(unconfirmed()); }; let execution_ref = self.execution_ref(spec, op)?.clone(); - let Some(facts) = self + // Absence and a failed dependency read both fail closed: no + // authenticated revocation may run without the Provider facts + // (R28), and a read failure must not be answered as absence. + let facts = match self .effects .dependency_facts(provider_ref, &execution_ref) .await - else { - ctx.set_status(CredentialDriverStatus::RevocationUncertain { evidence: None }); - return Err(unconfirmed()); + { + Ok(Some(facts)) => facts, + Ok(None) | Err(_) => { + ctx.set_status(CredentialDriverStatus::RevocationUncertain { evidence: None }); + return Err(unconfirmed()); + } }; let rotation_generation = lease .map(|facts| facts.rotation_generation) @@ -808,16 +816,22 @@ impl ResourceDriver for CredentialDriver { let (envelope, spec) = self.decoded_spec(ctx, DriverOp::Reconcile)?; let (provider_ref, kind) = self.provider_of(&envelope, DriverOp::Reconcile)?; let execution_ref = self.execution_ref(&spec, DriverOp::Reconcile)?.clone(); - let Some(facts) = self + // Absence and a failed dependency read both report the Provider + // unavailable (retryable): a read failure must not be answered as + // absence, and neither may reconcile against guessed readiness. + let facts = match self .effects .dependency_facts(&provider_ref, &execution_ref) .await - else { - ctx.set_status(CredentialDriverStatus::ProviderUnavailable); - return Err(self.error( - CredentialDriverErrorKind::ProviderUnavailable, - DriverOp::Reconcile, - )); + { + Ok(Some(facts)) => facts, + Ok(None) | Err(_) => { + ctx.set_status(CredentialDriverStatus::ProviderUnavailable); + return Err(self.error( + CredentialDriverErrorKind::ProviderUnavailable, + DriverOp::Reconcile, + )); + } }; if !facts.provider_ready { ctx.set_status(CredentialDriverStatus::ProviderUnavailable); diff --git a/packages/d2b-provider-credential/src/effects_service.rs b/packages/d2b-provider-credential/src/effects_service.rs index 682c27d5c..27ae436ed 100644 --- a/packages/d2b-provider-credential/src/effects_service.rs +++ b/packages/d2b-provider-credential/src/effects_service.rs @@ -33,7 +33,7 @@ use d2b_resource_types::{ServiceDecl, ServiceMethod}; use crate::driver::{CredentialDependencyFacts, CredentialDriverEffects, CredentialLeaseFacts}; use crate::facets::CredentialEffectFacets; -use crate::session::CredentialSession; +use crate::session::{CredentialResourceRuntimeError, CredentialSession}; /// The Credential family's declared effects service. /// @@ -115,7 +115,7 @@ impl CredentialDriverEffects for CredentialEffectsService { &self, provider_ref: &ResourceRef, execution_ref: &ResourceRef, - ) -> Option { + ) -> Result, CredentialResourceRuntimeError> { self.runtime.dependency_facts(provider_ref, execution_ref).await } @@ -183,7 +183,7 @@ mod tests { &self, _provider_ref: &ResourceRef, _execution_ref: &ResourceRef, - ) -> Option { + ) -> Result, CredentialResourceRuntimeError> { unreachable!("the inspect-credential surface reads no facts") } async fn lease_facts( diff --git a/packages/d2b-provider-credential/src/facets.rs b/packages/d2b-provider-credential/src/facets.rs index 3fe20b2d4..988f4208a 100644 --- a/packages/d2b-provider-credential/src/facets.rs +++ b/packages/d2b-provider-credential/src/facets.rs @@ -25,13 +25,19 @@ use async_trait::async_trait; use d2b_contracts_resource::v3::ResourceRef; use crate::driver::{CredentialDependencyFacts, CredentialLeaseFacts}; -use crate::session::CredentialSession; +use crate::session::{CredentialResourceRuntimeError, CredentialSession}; /// Boxed future returned by one production dependency probe: resolving the /// Provider and target rows is store-backed, so the facet cannot be a sync -/// closure. -pub type DependencyFactsFuture<'a> = - Pin> + Send + 'a>>; +/// closure. The read fails as [`CredentialResourceRuntimeError`] rather +/// than reporting absence when the manager RPC itself failed. +pub type DependencyFactsFuture<'a> = Pin< + Box< + dyn Future, CredentialResourceRuntimeError>> + + Send + + 'a, + >, +>; /// Boxed future of one production lease-fact read. pub type LeaseFactsFuture<'a> = @@ -63,14 +69,16 @@ pub struct CredentialEffectFacets { /// daemon-supplied authenticated session surface. #[async_trait] pub trait CredentialRuntime: Send + Sync + 'static { - /// Provider + execution-target facts. `None` when the Provider row is - /// not observable to this daemon (deletion still fails closed rather - /// than guessing). + /// Provider + execution-target facts. `Ok(None)` when the Provider row + /// is not observable to this daemon (deletion still fails closed rather + /// than guessing); `Err` when the dependency read itself failed (a + /// manager RPC failure), so absence is never answered for a failed + /// read. async fn dependency_facts( &self, provider_ref: &ResourceRef, execution_ref: &ResourceRef, - ) -> Option; + ) -> Result, CredentialResourceRuntimeError>; /// Provider-side lease facts for one Credential row. async fn lease_facts(&self, credential_ref: &ResourceRef) -> Option; diff --git a/packages/d2b-provider-credential/src/session.rs b/packages/d2b-provider-credential/src/session.rs index 292ee5a08..323c0b9e0 100644 --- a/packages/d2b-provider-credential/src/session.rs +++ b/packages/d2b-provider-credential/src/session.rs @@ -31,6 +31,9 @@ pub enum CredentialResourceRuntimeError { InvalidResource, /// A typed Credential session refused or could not confirm revocation. Revocation, + /// The dependency-facts read failed (a manager RPC failure), so the + /// caller can distinguish a failed read from an absent row. + DependencyFacts, } impl core::fmt::Display for CredentialResourceRuntimeError { @@ -38,6 +41,7 @@ impl core::fmt::Display for CredentialResourceRuntimeError { formatter.write_str(match self { Self::InvalidResource => "credential-resource-invalid", Self::Revocation => "credential-revocation-unconfirmed", + Self::DependencyFacts => "credential-dependency-facts-unavailable", }) } } diff --git a/packages/d2b-provider-credential/src/test_support.rs b/packages/d2b-provider-credential/src/test_support.rs index 9c4e2eba4..b79e8da95 100644 --- a/packages/d2b-provider-credential/src/test_support.rs +++ b/packages/d2b-provider-credential/src/test_support.rs @@ -93,9 +93,9 @@ impl CredentialDriverEffects for FakeEffects { &self, _provider_ref: &ResourceRef, _execution_ref: &ResourceRef, - ) -> Option { + ) -> Result, CredentialResourceRuntimeError> { self.log.lock().push("dependency-facts".to_owned()); // async-gate-allow: test-support recorder lock - self.facts.lock().clone() // async-gate-allow: test-support recorder lock + Ok(self.facts.lock().clone()) // async-gate-allow: test-support recorder lock } async fn lease_facts(&self, _credential_ref: &ResourceRef) -> Option { @@ -228,9 +228,9 @@ impl CredentialRuntime for RecordingRuntime { &self, _provider_ref: &ResourceRef, _execution_ref: &ResourceRef, - ) -> Option { + ) -> Result, CredentialResourceRuntimeError> { self.log.lock().push("dependency-facts".to_owned()); // async-gate-allow: test-support recorder lock - self.facts.lock().clone() // async-gate-allow: test-support recorder lock + Ok(self.facts.lock().clone()) // async-gate-allow: test-support recorder lock } async fn lease_facts(&self, _credential_ref: &ResourceRef) -> Option { diff --git a/packages/d2b-provider-credential/tests/registration.rs b/packages/d2b-provider-credential/tests/registration.rs index 1faf6f928..608295e1d 100644 --- a/packages/d2b-provider-credential/tests/registration.rs +++ b/packages/d2b-provider-credential/tests/registration.rs @@ -7,8 +7,8 @@ use std::sync::Arc; use d2b_contracts_resource::v3::{ResourceRef, ZoneId}; use d2b_provider_credential::{ CREDENTIAL_EFFECTS_SERVICE, CREDENTIAL_TYPE_NAME, CredentialDependencyFacts, - CredentialDriverArgs, CredentialEffectFacets, CredentialLeaseFacts, CredentialRuntime, - CredentialSession, credential_descriptor, + CredentialDriverArgs, CredentialEffectFacets, CredentialLeaseFacts, + CredentialResourceRuntimeError, CredentialRuntime, CredentialSession, credential_descriptor, }; use d2b_resource_runtime::identity::{ResourceKey, ResourceTypeName}; use d2b_resource_runtime::provider::{ProviderDirectory, ProviderDirectoryError}; @@ -24,8 +24,8 @@ impl CredentialRuntime for UnusedRuntime { &self, _provider_ref: &ResourceRef, _execution_ref: &ResourceRef, - ) -> Option { - None + ) -> Result, CredentialResourceRuntimeError> { + Ok(None) } async fn lease_facts(&self, _credential_ref: &ResourceRef) -> Option { diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 7eb434a8c..7ee829dae 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -65,8 +65,9 @@ use d2b_provider_zone::{ }; use d2b_provider_clipboard_wayland::Policy as ClipboardPolicy; use d2b_provider_credential::{ - AgentReadyFuture, CredentialDependencyFacts, CredentialLeaseFacts, CredentialRuntime, - CredentialSession, is_credential_provider_ref, + AgentReadyFuture, CredentialDependencyFacts, CredentialLeaseFacts, + CredentialResourceRuntimeError, CredentialRuntime, CredentialSession, + is_credential_provider_ref, }; use d2b_provider_display_wayland::WaylandSessionSpec; use d2b_provider_network_local::{ @@ -4482,27 +4483,20 @@ impl ZoneResourceRuntime { let execution_ref = execution_ref.clone(); Box::pin(async move { let Some(plane) = published_plane_view(&planes, &zone) else { - return None; + return Ok(None); }; - match credential_dependency_facts( - plane.as_ref(), - &provider_ref, - &execution_ref, - ) - .await - { - Ok(facts) => facts, - Err(error) => { - tracing::warn!( + credential_dependency_facts(plane.as_ref(), &provider_ref, &execution_ref) + .await + .map_err(|error| { + tracing::debug!( zone = %zone, provider = %provider_ref, execution = %execution_ref, error = %error, "credential dependency facts: manager read failed", ); - None - } - } + CredentialResourceRuntimeError::DependencyFacts + }) }) }), lease: Arc::new(|_credential_ref: &ResourceRef| Box::pin(async { None })), @@ -6032,7 +6026,7 @@ impl CredentialRuntime for ProductionCredentialRuntime { &self, provider_ref: &ResourceRef, execution_ref: &ResourceRef, - ) -> Option { + ) -> Result, CredentialResourceRuntimeError> { (self.facts)(provider_ref, execution_ref).await } diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 555be5923..2c4df0899 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index 6c295e7e4..2d9ef0ae8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 4605d84b0..4f8685b15 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 6704376a2..b9fe215b4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index d682063ef..6e352a683 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 6704376a2..b9fe215b4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 35c3df180..dadb35ed5 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index fc90df939..f49e4e271 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 4fb432144..b5d7bca6d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index fc90df939..f49e4e271 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 8e8f2a062..241a6bb20 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index 8391216e9..b285e6176 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index 0253efb24..3baa67832 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index f7d35b31f..c05db1845 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6431,6 +6431,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index 0377af754..fac7cacd3 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index d7db2118f..62dead8d8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6131,6 +6131,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index 0377af754..fac7cacd3 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 64f24b5c1..20923ddaa 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index d19ddd7c8..30f3d6dc5 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 46202be0e..e9f721886 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index d9d1b4233..42cc83add 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index c9ee284b2..ef10ff273 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index d9d1b4233..42cc83add 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 4619e988d..83656776c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index faa836089..be7a52035 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index aabfb01f4..c5a6e1f16 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index faa836089..be7a52035 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index c742450e7..669de35e6 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 7ff09a342..619cbc3df 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index 305440197..e81826a8e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index 2f7a3c151..11907053c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6469,6 +6469,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index f81d43fa9..e5e3c1d14 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index 3219c5f4a..c03666fc9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1545,6 +1545,7 @@ dependencies = [ "d2b-contracts-zone-session", "d2b-core", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index bd09289ce..39bbdaa30 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6169,6 +6169,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index f81d43fa9..e5e3c1d14 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "50c799811093190fab19b4d1021f4fac783b462841ff6c5e9828dbdc685b0bd5", + "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", From c0aaef23216bdd1e063981ec1ffda9b237936a70 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:01:33 -0700 Subject: [PATCH 583/726] repo: refresh async-gate inventory after credential dependency-facts signature change --- packages/xtask/data/async-gate-inventory.json | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index bed38ca1c..0ea2e8078 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -183,87 +183,87 @@ }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1108, + "line": 1122, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1121, + "line": 1135, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1122, + "line": 1136, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1145, + "line": 1159, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1149, + "line": 1163, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1166, + "line": 1180, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1168, + "line": 1182, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1636, + "line": 1650, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1647, + "line": 1661, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1650, + "line": 1664, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1674, + "line": 1688, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1723, + "line": 1737, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1807, + "line": 1821, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1863, + "line": 1877, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1921, + "line": 1935, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/session.rs", - "line": 398, + "line": 402, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/session.rs", - "line": 457, + "line": 461, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1098,17 +1098,17 @@ }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 2480, + "line": 2481, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 7507, + "line": 7501, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 8658, + "line": 8652, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 5cd82a96a59abf2cde6fe862157dec15ba264649 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:02:54 -0700 Subject: [PATCH 584/726] audit: fold wave-4 outcomes into the rust-skills remediation ledger --- .../2026-09-24-rust-skills-audit/ledger.md | 93 ++++++++++--------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 9e702afda..cc68e1444 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -41,6 +41,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `24198fff7` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. Gates to be run by Main on merge onto `09f9c6ae1`. | +| W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | ## Findings (965 rows) @@ -131,7 +132,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U2 | fda87abbe | `packages/d2b-provider-transport-vsock/src/auth.rs` | ReadySession::disconnect now drops mut and returns SessionState::Disconnected directly (SessionState is Copy). | | | `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix (envelope.base.get("provider").cloned()) is type-incompatible: base.get yields CanonicalJsonValue not serde_json::Value. Applied minimal variant: dropped the dead unwrap_or fallback via an | | | `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/status.rs` | LayoutPhase::worse now uses derived self.max(other); declaration order already encodes severity. | | -| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | | | | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | +| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | applied | 4 | b062e724d | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | | `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | f5dd934fc | `packages/d2b-contracts-resource/src/v3/execution_policy.rs` | The redacted_debug macro was extended with a closure-based field-preserving form (two exported helper fns redacted_debug_field_ref and redacted_debug_field_value), and all 17 hand-written redaction De | | | `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | | `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | @@ -191,9 +192,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | dedup sets now BTreeSet<&BoundedToken>/BTreeSet<&ResourceTypeName> in ProviderManifest::new and with_state_namespaces | | | `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/volume_state.rs` | SchemaFingerprint::parse takes the borrowed str instead of cloning | | | `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied-variant | U2 | 862071320 | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs` | Order-preserving contains check (n<=64) instead of sort-in-place: sorting would change serialized bytes of a signed wire message for unsorted inputs | | -| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | +| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | 4 | a2cf0e614 | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | | `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | acffb7466 | `packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs` | Walk iterates CanonicalJsonObject keys directly; no wrapper or clone built | | -| `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | | | | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | +| `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | 4 | a2cf0e614 | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | | `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | 7be394a88 | `packages/d2b-contracts-zone-session/src/v3/services.rs` | BoundedText::parse takes method.as_str() instead of method.clone() | | | `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | path_bearing_key_violations renders through Cow; string arm borrows instead of cloning | | | `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | parse(value.as_str()) at 3 sites; network_uid compare via as_str; note: row rationale 'no allocation' inaccurate (Into still allocates) but explicit clones removed | | @@ -232,7 +233,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0183` | `own` | `d2b-provider-provider` | low | actionable | leaf | applied-variant | U2 | 46b177892 | `packages/d2b-provider-provider/src/driver.rs` | Stated fix's assumption (last previous read before set_status) fails: dependencies(ctx) needs &mut ctx between the two previous reads. Minimal variant: reordered dependencies() before the status read | | | `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/service/supervisor.rs` | advance_session now scopes the first session_mut borrow in a block and compares supervisor_identity.as_ref() directly; dropped the clone. | | | `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | -| `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | +| `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | | `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | | | | `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | is_ready_for_route compares through the guard via is_some_and(/ready/ ready.as_ref().is_some_and(/bound/ bound.liveness().is_live() && bound == route)); no clone. | | | `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/shared_provider.rs` | sort_by with teardown_rank cmp then name cmp; no per-row String allocation. | | @@ -285,7 +286,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0235` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 02238dbdd | `semantic_service_schemas.rs` | resource_ref_schema takes &str/&[&str]; five call sites pass borrowed forms | | | `RS-0229` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | mem::take on the mut slot before in-place edit | | | `RS-0230` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | two ratchet probes key borrowed strs via signal fields | | -| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | | | +| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | applied-variant | 4 | 0b5c7d292 | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | applied-variant: d2b-core privileges enums (SecretAccess, BrokerRequirement, AuditMode) gained Copy derives - required because BrokerAuthzFacets/BrokerOperationRow derive Copy; additive, non-breaking | | | `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | Disposition is &'static str in a generator-emitted closed set with a drift gate; typing it needs a generator change (generated artifact). | | | `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | | `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | The destructive flag is emitted as a bare boolean by the operations generator; the stated drop of the arity allow is not implementable while the helper takes eight arguments. | | @@ -304,15 +305,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | | | | `public_wire.rs:2166, public_wire.rs:2203` | | | | `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | | | | `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:316, public_wire.rs:311` | | | -| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | +| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | | `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | | | | `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | | `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-res` | | | -| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | +| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | | `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-r` | | | | `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises - `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | | `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | packages/d2b-provider-transport-azure-relay/contrast-zone-session/src/v3/role_binding.rs | | | -| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | | | | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | +| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | 4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | | `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | | `RS-0262` | `type` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | | | @@ -327,7 +328,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | applied-variant | U3 | 1ce473a70 | packages/d2b-provider-credential/src/driver.rs | zone: String -> d2b_contracts_resource::v3::ZoneId in CredentialDriverArgs and CredentialDriver; agent_child builds the zone ref with expect on a validated ZoneId (fallible ResourceRef::parse path dro | | | `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | applied | U3 | cd8838c03 | packages/d2b-provider-credential-managed-identity/src/controller.rs | seal `ManagedIdentityTeardownPlan`'s three bool fields behind `pub const fn` accessors so invalid combos (stop_agent && delete_agent, delete_agent && clear_provider_revoke) are unrepresentable; tests | | | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | -| `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | | | | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | +| `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | applied | 4 | 9870dc852 | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | | `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | | `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | needs-contract | U3 | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery recor | | | `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired - the illegal Consumed/Expired-with-Some(psk) combination is now unco | | @@ -359,7 +360,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d` | | | | `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | 7e0ec2bce | packages/d2bd-runtime/src/admission.rs | peer admission lookup mode modelled self-describing; check + admission tests green (worker reported the oid as already present after committing its own change; the commit is this branch's) | | | `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | | | | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | | | -| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | | | | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | +| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | 4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | | `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | d1c5c44d9 | packages/d2bd-runtime/src/typed_shell_targets.rs | typed-shell target key becomes a named struct with a constructor; the three composition.rs cache call sites migrate to it | | | `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | | `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | @@ -386,12 +387,12 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | | `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | -| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | +| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | 4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | | `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but | | | `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:6` | Deleting the pub re-export of LevelPercent from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 0 hits for cli_output::LevelPercent outside cli_output.rs:6 | | | `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | | | | `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Narrowing pub methods in the published crate is a published-surface move; additionally the lane census is stale: HelperLaunchRequest::validate_bounds has a live external caller at d2b-unsafe-local-hel | | -| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | +| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | | `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 67393687b13c359ac6b3a96bca469d28e25c7c96 | packages/d2b-contracts-resource/src/v3/identity.rs | Deleted the zero-caller alias and its doc. Census re-run: ValidatedSessionPurpose over worktree = 1 hit (the definition); no re-export arm in v3/mod.rs. cargo check -p d2b-contracts-resource --locked | | | `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | @@ -417,7 +418,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | | `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | already-fixed | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | set_grant(lease, on: bool) already split into grant()/revoke() with was-empty/was-last contracts by the RS-0267 commit (c7d7d66c5); callers use is_last_grant first. No change needed. | | | `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c9a141c78 | packages/d2b-provider-audio-pipewire/src/controller.rs | register_service deleted (zero callers; census over packages/nixos-modules/tests/docs/reference/labs = only the definition); daemon and wayland-policy validate specs via validate_audio_service directl | | -| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | | | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | | | +| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | needs-contract | U3 | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | deferred: needs-contract - AudioLastSetApplied::OfflineOnly naming vs its doc; variant renders to a wire-visible status string pinned in daemon tests; owning wave U3 (contract wave; ledger precedent RS-0955/RS-0957) | | | `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-cli` | | | | `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | | | | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | | | | `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | @@ -442,7 +443,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmController::new now takes effect: E by value and stores it; the production call site and the crate's test call sites (18 FakeEffect constructions, incl. the shared-effect recovery test restruct | | | `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | fe17cfa53 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | repair_children no longer takes committed: &BTreeMap (sole caller passed an always-empty map); the unreachable committed.get(target) branch and the empty-map local are deleted. check/test/clippy green | | | `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | 2ba072632 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | assess_update no longer takes children (production adapter discarded it via let _; request carries none); trait default, adapter override, test impl, and the reconcile call site's Vec allocation all u | | -| `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | | | | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | | | +| `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | applied-variant | 4 | 768457562 | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | applied-variant: the two declarations had drifted (GuestLocalError::EndpointMismatch vs ClientError::InvalidTarget/TransportPolicyMismatch; extra unused endpoint_uid()); reconciled to the d2b-resource-client shape and re-exported | | | `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | 9b56489c4 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | ChildMutation::expected_uid() (constant None on the UID-free batch) deleted along with the three assert-None assertions; census: remaining expected_uid hits are unrelated types. check/test/clippy gree | | | `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | dc09819bf | packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | Deleted constant-true preserve_state() accessor and its tautological assertion (census: only consumer was the assertion). check+finalize_ordering tests (6) + clippy green. | | | `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | @@ -456,11 +457,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd` | | | | `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | c61b0e5b5 | packages/d2b-provider-provider/src/driver.rs | ProviderDriverFactory::new() and impl Default deleted (zero callers; crate tests construct via with_effects; FailClosedProviderDriverEffects still used by tests). Census: no new()/default() callers ac | | | `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | 56c460c03 | packages/d2b-provider-provider/src/providers.rs | Completed the in-flight partial edit: deleted plan_external body, Disable/Delete intent variants, Draining phase, TrustOrCompatibilityDenied error, and orphaned test helpers/imports; check/test/clippy | | -| `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | | | | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | | | -| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | | | | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | | | -| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | | | | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | | | +| `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | same wiring as RS-0959 | | +| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | same wiring as RS-0959 | | +| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | same wiring as RS-0959 | | | `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | | | | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | | | -| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | | | | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | +| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | applied | 4 | 7dadf9923 | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | | `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 0cb5d7b68 | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | | | | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | | | | `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | @@ -470,8 +471,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | forward `HostProbeMetadata` from the host re-export while dropping the zero-external-consumer `HostProbeSnapshot` constant from the public surface; the crate's probe seam stays internal until a consum | | | `RS-0414` | `api` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | 0623be33bf4894fc796b0f603508b2570b746b7d | packages/d2b-provider-toolkit/Cargo.toml | Added test-support = [] feature; gated both constructors with #[cfg(any(test, feature = "test-support"))]; required-features on the supervised_runtime test target; added test-support to the Bazel test | | | `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | 81f51276ed7456104a034c40ba5b3c45bba8c790 | packages/d2b-provider-toolkit/src/server/service.rs | Deleted response_request_id and generated_service plus the response_request_id doc; narrowed the now-unused RequestId import; kept generated_services(). Census re-run: both symbols over worktree = 0 c | | -| `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | -| `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | +| `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | +| `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | | `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs | | | | `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | | `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | | | | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | | | @@ -484,13 +485,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0427` | `api` | `d2b-resource-api` | low | actionable | leaf | applied-variant | U3 | 0d74a18f2 | packages/d2b-resource-api/src/client.rs | Census re-run: zero callers. pub(crate) alone tripped denied dead_code warnings (crate denies warnings), so the unwired methods were deleted until a caller exists. | | | `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | wire_revision and api_subject narrowed to pub(crate). resource_owner_subject stays pub because its U9/U10 caller has landed at HEAD: d2bd/src/resource_runtime/plane_controller_bridge.rs:369 (subject() | | | `RS-0429` | `api` | `d2b-resource-client` | medium | actionable | leaf | applied | U3 | 8b53d606e | packages/d2b-resource-client/src/zone_client.rs | | | -| `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | | | | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | +| `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | applied | 4 | 98f74a980 | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | | `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | 0cd7b063d | packages/d2b-resource-runtime/src/target.rs | Removed TargetBinding::directory() accessor. Census re-run: zero callers; the directory field stays read by internal methods (observe/delete/adopt), no dead code. cargo check/test/clippy green for d2b | | | `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | U3 | 3570364e0 | packages/d2b-resource-runtime/src/guest_target.rs | Removal as written orphans GuestTargetInner.reference (dead-code deny) and forces a public constructor signature change across 26 call sites in 5 files incl. d2bd production (published surface -> cont | | | `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | | | | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | | | | `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/fragmentation.rs | Fragment.header is now private with a pub header() accessor; the two engine.rs encode call sites (877, 1395) use the accessor. Census: no external field access. | | | `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | -| `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | | | | `packages/d2b-session-unix/src/socket.rs:176` | | | +| `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | applied | 4 | 2f034e476 | `packages/d2b-session-unix/src/socket.rs:176` | | | | `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | applied | U3 | b9fc346fc | packages/d2b-sk-frontend/src/lib.rs | agent/config/link/uhid made private; UhidDevice and UhidEvent re-exported from lib.rs; main.rs:41 uses root re-exports. Census: sk_frontend::(agent/config/link/uhid):: = 0 full-path hits; zone-routing | | | `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | a9902b8e7 | packages/d2b-unsafe-local-helper/src/runtime.rs | Census re-run: zero external consumers. SupervisorSpec, SUPERVISOR_START_TIMEOUT, SNAPSHOT_RECONCILE_TIMEOUT, send_frame, receive_frame, configure_socket_buffers narrowed to module-private; no pub sig | | | `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/composition.rs | process_provider_runtime and provider_effects narrowed to pub(crate) with a cfg(feature=test-support) pub mod seam for tests/resource_operator_activation.rs; test-only items (new_persistent, admit, pe | | @@ -498,7 +499,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0439` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | pub surface reduced to pub(crate): trait HostAudioController, PipeWireHostController, from_audio_node, find_audio_node, QemuAudioController. Census re-run: only in-crate callers (audio_dispatch.rs); m | | | `RS-0440` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | vm_name param removed from HostAudioController::enforce_grant/enforce_level, all three impls (PipeWire/Qemu/Fake), and all call sites incl. tests. Checks: cargo check green; cargo test -p d2bd --locke | | | `RS-0443` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 524d06bad06c00ccf05c20c14461400478d70df3 | packages/d2bd/src/provider_registry.rs | Re-export narrowed to MAX_PROVIDER_REGISTRY_ENTRIES only; census re-run at HEAD shows ProviderRegistrySnapshot appears nowhere else in the workspace through d2bd's path (only the re-export line itself | | -| `RS-0444` | `api` | `d2bd-runtime` | medium | actionable | family | | | | `shell_backend.rs:52-53` | | | +| `RS-0444` | `api` | `d2bd-runtime` | medium | actionable | family | applied-variant | 4 | 87c3172bc | `shell_backend.rs:52-53` | applied-variant: delegating best_effort_close/best_effort_cancel take &EstablishedShell (0/2 callers, all in composition.rs) | | | `RS-0446` | `api` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U3 | 225f36a3a | packages/d2bd-runtime/src/exec_session.rs | Variant of the row's fallback ('gate the module test-support-only'): the exec-session worker machinery (spawn_session_worker, WorkerSpawn, worker_main, WorkerState, TerminalReaper, OwnerReaper, Establ | | | `RS-0445` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e10faa81f | packages/d2bd-runtime/src/ch_api.rs | ch vm.info payload deserialized through a derived raw shape with a round-trip test | | | `RS-0447` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8b3164c4f | packages/d2bd-runtime/src/console_session.rs | ConsoleClientHandle field made private; added validating FromStr (console-<32 hex>) with ConsoleClientHandleParseError; table lookups stay allocation-free via existing Borrow/as_str (the already- | | @@ -525,10 +526,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | | `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | ed46f196b | packages/d2b-contracts-provider/src/v3/provider_registry.rs | added GenerationMismatch variant kebab code provider-registry-generation-mismatch; updated failure-path test to assert the variant; census ProviderRegistryError=12 hits all in-file | | | `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 75e9c238c | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialSingleFlight lock() now recovers poisoned mutexes via unwrap_or_else(poisoned.into_inner()) and returns the guard directly (infallible); guard Drop recovers the same way instead of silently | | -| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | +| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | | `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | | `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_macvtap_intents now returns crate::error::Error via Error::manifest_parse_error (typed, two failure modes distinguishable); broker call site updated to house .map_err(/error/ BrokerError::Live | | -| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | | | | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | +| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | applied | 4 | 5282e9337 | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | | `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | Stated fix (plumb Result out of build_resource_network_intents/find_network_spec) requires changing the public signatures of six resolve_network_*_intent methods consumed by d2bd (composition.rs:7247- | | | `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/site.rs | SiteJson::validate returns SiteValidationError::InvalidWaylandSocket enum with Display token; caller and tests updated | | | `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | @@ -552,7 +553,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | applied-variant | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | observe_host returns Result<_, ObserveError>; the flattening format! is replaced by a closed error carrying both SystemCoreError legs with Error::source() (fallback is the chain source, probe error re | | | `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | HostDriverError::Display delegates to self.kind.failure_kind().code(); the three registry codes verified identical to the re-spelled literals. | | | `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | applied | U3 | 200aa2bb2 | packages/d2b-provider-network-local/src/nftables.rs | Sole non-test unwrap replaced with try_into().expect naming the statically-known invariant (64-byte chunk yields a 4-byte word slice). check/clippy exit 0; nftables tests pass. | | -| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | | | | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | | | +| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | applied-variant | 4 | b56a46c1e | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | applied-variant: kept the crate's existing exported ProviderError name (renaming is churn); test-fake slugs mapped to family variants; 4 pre-existing unused ProviderError variants kept as exported API | | | `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U3 | eba219aa6 | packages/d2b-provider-notification-desktop/src/types.rs | Added NotificationError::Denied (slug notification-denied; not pinned in docs/reference) and mapped the five admission/zone/category rejection sites (host_sink.rs source/observer admission, zone misma | | | `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/ingress_policy.rs | Full connection-table rejection now reports IngressErrorClass::None, consistent with the sibling capacity refusal. | | | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | applied | U3 | c22876d4f | packages/d2b-provider-process/src/driver.rs | Map VolumeBinding/Volume row parse failures to ProcessDriverErrorKind::SpecInvalid in identity() and serving_worker_launch() (now Result, _>); genuinely absent rows/views/attachments still y | | @@ -563,10 +564,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | | `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | | `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | de1a2c493eb2db826cd517128364c759a86240d9 | packages/d2b-provider-toolkit/src/operations/envelope.rs | audit_named falls back to the canonical (lowercase, dash-stripped) spelling when BoundedToken::parse rejects the raw name, so a refused PascalCase forwarded invocation lands its Denied record; already | | -| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | -| `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | -| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | | | | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | -| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | | | +| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | +| `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | +| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | +| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | applied-variant: key_ref returns Result; the cited spec_store.rs:60-63 anchor has no key_ref caller at base (d2b-resource-runtime has no provider-toolkit dependency), nothing to update there | | | `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | applied | U3 | 2ab7a1ed2 | packages/d2b-provider-user/src/driver.rs | Display impl now writes self.kind.failure_kind().code(); registered FailureKind codes remain the single source, strings unchanged, no behavior change. | | @@ -586,7 +587,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | | `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | a91ad9bbc | packages/d2bd/src/resource_plane_v3.rs | PlaneError's five String variants retyped: FoundationSeed(#[from] SeedError), ManagerSpawn(#[from] ractor::SpawnErr), Bundle(#[from] ResourceBundleError), Authority/Target(#[source] Box>, every impl and call site migrated; re-dispatched per Main's directive 2026-09-25) | | | `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d4fe83812 | packages/d2bd/src/composition.rs | dispatch_audit's unrecognized severity arm now returns TypedError::WireInvalidFrame { detail: "audit filter has an invalid severity".to_owned() } instead of InternalIo, so caller input errors surface | | | `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d1a472077 | packages/d2bd/src/composition.rs | ActivationLockGuard::drop now logs finish_activation failures via tracing::warn!(zone = %self.zone, error = %error, ...) instead of `let _ =`, mirroring the file's house style for coordinator refusals | | | `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | | | | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | | | @@ -607,13 +608,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | -| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | | | | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | -| `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | | | | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | | | +| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | +| `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | applied-variant | 4 | a2cf0e614 | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | applied-variant: consolidated 28 Wire-shape Deserialize impls behind the crate-local wire_deserialize! macro in d2b-contracts-zone-session (canonical home; later waves must reuse it, not write a third macro); parsed_deserialize! requires Self::parse(String) (JSON-string wire), which no Wire-struct impl matches - adopting it would change the wire format the row never asked to change (Main ruling 2026-09-25) | | | `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/storage_lifecycle.rs | serde rejects rename_all on struct variants (field attribute); applied the equivalent house pattern #[serde(rename_all_fields = "camelCase")] on the enum container + dropped per-field renames; seriali | | | `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175` | | | | `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | | `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | | | | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | | | -| `RS-0557` | `serde` | `d2b-host` | low | actionable | family | | | | `packages/d2b-host/src/nftables.rs:229` | | | +| `RS-0557` | `serde` | `d2b-host` | low | actionable | family | applied | 4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:229` | | | | `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | | `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | | `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-` | | | @@ -625,11 +626,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/driver.rs:282-289, src/driver.rs:190` | | | | `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | U3 | 336a4fd97 | packages/d2b-provider-network-local/src/broker.rs | Four provenance payload builders (resolved_bridge_payload/resolved_route_payload in broker.rs and operations.rs) no longer .ok()-swallow serde_json::to_value(provenance); they now propagate with map_e | | | `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generate` | | | -| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | | | | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-p` | | | +| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | needs-contract | U3 | | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-p` | deferred: needs-contract - RelayTransportSettings derives Deserialize without try_from, bypassing validate() incl. the secret-shape exclusion; owning wave U3 (contract wave) | | | `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264` | | | | `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | | | | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | | | | `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | applied | U3 | b00a073f2 | packages/d2b-provider-volume-local/src/content.rs | ContentFile/ContentProjection/NetworkConfigContentProjection decode via serde try_from Raw mirrors running validating constructors; Deserialize dropped from evidence types; wire shape unchanged. | | -| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | | | | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | +| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | 4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | | `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | | `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | applied-variant | U3 | f1bb96854 | packages/d2bd/src/composition.rs | deny_unknown_fields added to both GatewayGuestConfigFile and GatewayGuestRelayConfigFile. The config-typo test landed as direct deserialization tests on both structs (gateway_guest_config_tests mod), | | | `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d` | | | @@ -651,7 +652,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | | `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | | `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | abc324d2a | packages/d2b-provider-toolkit/src/base/guest.rs | serve_enrolled now emits tracing::warn!(frame_bytes, ...) before dropping a frame GuestFrame::new rejects (empty or oversized), keeping the session up. No correlation identifiers in the record. cargo | | -| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | | | +| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | applied-variant: method field unavailable at all 3 sites (receive failure precedes decode; readiness/loop failures carry no request); zone+provider added from the route binding | | | `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/relay_transport.rs | | | | `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | | `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | @@ -679,7 +680,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0631` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | ba9873712 | `packages/d2b-broker/src/protocol.rs` | MAX_FRAME_SIZE and connect/bind/send_json_frame/recv_json_frame documented | | | `RS-0632` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 6b709ea9a | `packages/d2b-broker/src/ops/state_dir.rs` | DirKind, PrepareDirRequest/fields, PrepareDirAudit, ReplaceOrCreateResult, prepare_dir and live helpers documented with # Errors | | | `RS-0621` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 1643cd532 | `packages/d2b-broker/src/audit.rs` | field docs on AuditDropSummary/AuditEntry; contract docs on AuditLog::open/audit_drop_summary | | -| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | | | | `packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b` | | | +| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | applied | 4 | 27a3de0bd | `packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b` | | | | `RS-0622` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 7ac3d8cdf | `packages/d2b-broker/src/ops/host_generation_handoff.rs` | doc comments added per row | | | `RS-0623` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 025b075a8 | `packages/d2b-broker/src/ops/route.rs` | doc comments added per row | | | `RS-0615` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 34f355adf | `packages/d2b-broker/src/ops/usbip_lock.rs` | doc comments added per row | | @@ -703,7 +704,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | e12e51dac | `packages/d2b-contracts-control/src/public_wire.rs` | Docs added to the named request/status types plus UsbipProbeEntry field meanings; # Errors added to ShellName::new (RealmAccentColor::new covered by RS-0643) | | | `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | 5c5b2d478 | `packages/d2b-contracts-control/src/unsafe_local_wire.rs` | Constants documented with the daemon-enforced bounds, wire types one-lined, helper fns and RealmAccentColor::new get # Errors | | | `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | applied | U2 | e5b584959 | `packages/d2b-contracts-control/src/terminal_wire.rs` | One-line docs per DTO plus the redacted-Debug note on session-bearing types | | -| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | +| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | | `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | | `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/artifact.rs` | doc comments on the artifact id bound, error, type, parse, and accessor | | | `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | e7bba788d | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | none (anchor drift only) | | @@ -723,7 +724,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/state.rs` | Documented AudioStateLock guard semantics (holds the OFD lock; drop releases and closes). | | | `RS-0665` | `docs` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/controller.rs` | Documented the 300s cadence rationale, hoisted 64 into pub const AUDIO_QUEUE_BOUND used by new, with_shared_microphone, and the admission bound test (u64 casts at lease sites). | | | `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | f0210347a,48437393c | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | the Policy::new hunk landed in the policy-unification commit f0210347a (same file as RS-0040); the other three hunks in 48437393c | | -| `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | | | | `src/audit.rs:172, src/audit.rs:174` | | | +| `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | applied | 4 | 64408bc95 | `src/audit.rs:172, src/audit.rs:174` | | | | `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 460a05942 | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | none | | | `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,b8724cd15,ac5e33ab1 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | picker.rs hunks shared commit 018c1dad5 with RS-0041/RS-0042 (index race, see RS-0041) | | | `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,ac5e33ab1,08c2e3648 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | picker.rs hunk shared commit 018c1dad5 (index race, see RS-0041) | | @@ -847,7 +848,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | | `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | applied | W3 | 037e23533 | `driver.rs:437-440, driver.rs:614-617` | | | | `RS-0791` | `perf` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:1006` | | | -| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | escalated | W3 | | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | applied | 4 | 5c7fbf067 | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | | | | `RS-0793` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458` | | | | `RS-0790` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:495, manager_backend.rs:449-455` | | | | `RS-0794` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/manager.rs:1390` | | | @@ -860,7 +861,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0801` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/process_provider_runtime.rs:333` | | | | `RS-0802` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476` | | | | `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.r` | | | -| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | escalated | W3 | | `public_read_model.rs:117-118` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | applied | 4 | 87c3172bc | `public_read_model.rs:117-118` | | | | `RS-0808` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packag` | | | | `RS-0805` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:431` | | | | `RS-0806` | `perf` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:582` | | | @@ -912,7 +913,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | | `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | declined | W3 | f6b8e60e6 | `packages/d2bd/src/interaction_composition.rs:5518-5530` | | | | `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | declined | W3 | f6b8e60e6 | `packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_ef` | | | -| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | escalated | W3 | | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | applied-variant | 4 | 87c3172bc | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | applied-variant: drainer tasks spawn on the daemon's own tokio runtime handle instead of a new dedicated runtime (audit-sanctioned) | | | `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 406f13d98 | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broke` | | | | `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | skipped-stale | W3 | 406f13d98 | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | | | | `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | applied | W3 | 3886cfd7b | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | @@ -921,8 +922,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0861` | `macro` | `d2b-resource-api` | low | actionable | leaf | applied-variant | W3 | 81b2ef867 | `service.rs:2245-2267` | | | | `RS-0862` | `macro` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643` | | | | `RS-0863` | `macro` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/s` | | | -| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | escalated | W3 | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | -| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | escalated | W3 | | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | applied | 4 | 776ddb336 | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | | | +| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | applied-variant: feature wired to the registration integration test via [[test]] required-features (house pattern d2b-provider-host/Cargo.toml:28) instead of a #[cfg(feature)] module - the crates have no test-support module and BUILD.bazel *_test_support targets consume the feature | | | `RS-0880` | `test` | `d2b` | medium | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:227-239` | | | | `RS-0881` | `test` | `d2b` | low | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:383-397` | | | | `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | applied | W3 | b80491dde | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | @@ -939,7 +940,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0877` | `test` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/tests/bundle_resolver_tamper.rs:149` | | | | `RS-0875` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority.rs:1824, authority.rs:1968, authority.rs:1899` | | | | `RS-0876` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority_persistence.rs:246-320` | | | -| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | escalated | W3 | | `packages/d2b-host/src/nftables.rs:245` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | applied | 4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:245` | | | | `RS-0879` | `test` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/bin/d2b-activation-helper.rs:792` | | | | `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activ` | | | | `RS-0883` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/authority.rs:26-31, src/authority.rs:236-241` | | | From 0274747fcbdf187f58ac5cb5b857931ec982d598 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:13:11 -0700 Subject: [PATCH 585/726] docs(d2b-contracts-zone-session): document ComponentSession v3 wire constants --- .../w5-11-component-session-const-docs.md | 3 ++ .../src/v3/component_session.rs | 37 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 changelog.d/w5-11-component-session-const-docs.md diff --git a/changelog.d/w5-11-component-session-const-docs.md b/changelog.d/w5-11-component-session-const-docs.md new file mode 100644 index 000000000..3d0553294 --- /dev/null +++ b/changelog.d/w5-11-component-session-const-docs.md @@ -0,0 +1,3 @@ +### Fixed + +- Documented the 37 public wire constants in the ComponentSession v3 contract with one-line doc comments naming their wire role, matching the documented constant blocks in the Role contract; values, names, and ordering are unchanged. \ No newline at end of file diff --git a/packages/d2b-contracts-zone-session/src/v3/component_session.rs b/packages/d2b-contracts-zone-session/src/v3/component_session.rs index 42c2c2f4b..cc84e6236 100644 --- a/packages/d2b-contracts-zone-session/src/v3/component_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/component_session.rs @@ -24,42 +24,79 @@ use std::{ use d2b_contracts_resource::v3::identity::SessionPurpose; use d2b_contracts_resource::v3::{ResourceRef, ResourceUid, ZoneId}; +/// Length in bytes of the fixed ComponentSession preface. pub const PREFACE_LEN: usize = 16; +/// Fixed magic bytes identifying a ComponentSession v3 preface. pub const PREFACE_MAGIC: [u8; 8] = *b"D2BCS3\r\n"; +/// Canonical ComponentSession wire major version. pub const COMPONENT_SESSION_MAJOR: u16 = 3; +/// Canonical ComponentSession wire minor version. pub const COMPONENT_SESSION_MINOR: u16 = 0; +/// Maximum serialized bytes of one HandshakeOffer on the wire. pub const MAX_HANDSHAKE_OFFER_BYTES: usize = 16 * 1024; +/// Canonical encoded length in bytes of a HandshakeOffer. pub const HANDSHAKE_OFFER_CANONICAL_LEN: usize = 148; +/// Canonical encoded length in bytes of the EndpointPolicy identity portion of a HandshakeOffer. pub const ENDPOINT_POLICY_IDENTITY_CANONICAL_LEN: usize = HANDSHAKE_OFFER_CANONICAL_LEN - 8; +/// Maximum ciphertext bytes in one protected record. pub const MAX_PROTECTED_CIPHERTEXT_BYTES: u32 = u16::MAX as u32; +/// Noise protocol authentication tag bytes per protected record. pub const NOISE_TAG_BYTES: u32 = 16; +/// Length-prefix bytes in each record framing header. pub const RECORD_LENGTH_BYTES: u32 = 2; +/// Maximum plaintext bytes in one protected record after Noise tag removal. pub const MAX_PROTECTED_PLAINTEXT_BYTES: u32 = MAX_PROTECTED_CIPHERTEXT_BYTES - NOISE_TAG_BYTES; +/// Maximum bytes of one logical message across record fragments. pub const MAX_LOGICAL_MESSAGE_BYTES: u32 = 1024 * 1024; +/// Maximum concurrently active named streams per session. pub const MAX_ACTIVE_NAMED_STREAMS: u16 = 128; +/// Maximum attachments in one packet. pub const MAX_PACKET_ATTACHMENTS: u16 = 32; +/// Maximum attachments in one request. pub const MAX_REQUEST_ATTACHMENTS: u16 = 64; +/// Maximum attachments in one operation. pub const MAX_OPERATION_ATTACHMENTS: u16 = 128; +/// Maximum attachments held by one session. pub const MAX_SESSION_ATTACHMENTS: u16 = 256; +/// Maximum attachment credits granted to a process. pub const MAX_PROCESS_ATTACHMENT_CREDITS: u16 = 2_048; +/// Maximum attachment credits granted to the host. pub const MAX_HOST_ATTACHMENT_CREDITS: u16 = 8_192; +/// File descriptors reserved for session control transport. pub const RESERVED_CONTROL_FDS: u16 = 64; +/// Maximum queued bytes for one named stream. pub const MAX_NAMED_STREAM_QUEUE_BYTES: u32 = 256 * 1024; +/// Maximum aggregate queued bytes across all named streams. pub const MAX_AGGREGATE_NAMED_STREAM_QUEUE_BYTES: u32 = 4 * 1024 * 1024; +/// Maximum queued bytes on the TTRPC control channel. pub const MAX_TTRPC_CONTROL_QUEUE_BYTES: u32 = 2 * 1024 * 1024; +/// Maximum queued bytes on the session control channel. pub const MAX_SESSION_CONTROL_QUEUE_BYTES: u32 = 64 * 1024; +/// Maximum tolerated clock skew in milliseconds. pub const MAX_CLOCK_SKEW_MS: u64 = 30_000; +/// Maximum lifetime of one request in milliseconds. pub const MAX_REQUEST_LIFETIME_MS: u64 = 15 * 60 * 1_000; +/// Local handshake deadline in milliseconds. pub const LOCAL_HANDSHAKE_DEADLINE_MS: u32 = 5_000; +/// Remote handshake deadline in milliseconds. pub const REMOTE_HANDSHAKE_DEADLINE_MS: u32 = 15_000; +/// Local reconnect deadline in milliseconds. pub const LOCAL_RECONNECT_DEADLINE_MS: u32 = 5_000; +/// Remote reconnect deadline in milliseconds. pub const REMOTE_RECONNECT_DEADLINE_MS: u32 = 30_000; +/// Maximum reconnect attempts before the session fails. pub const MAX_RECONNECT_ATTEMPTS: u16 = 10; +/// Maximum reconnect window in milliseconds. pub const MAX_RECONNECT_WINDOW_MS: u32 = 5 * 60 * 1_000; +/// Maximum keepalive interval in milliseconds. pub const MAX_KEEPALIVE_INTERVAL_MS: u32 = 60_000; +/// Maximum keepalive timeout in milliseconds. pub const MAX_KEEPALIVE_TIMEOUT_MS: u32 = 30_000; +/// Maximum bytes of one wire identifier. pub const MAX_ID_BYTES: usize = 64; +/// Length in bytes of a record header. pub const RECORD_HEADER_LEN: usize = 24; +/// Length in bytes of a fragment header. pub const FRAGMENT_HEADER_LEN: usize = 24; const HANDSHAKE_BINARY_VERSION: u8 = 1; const NAMED_STREAM_CHANNEL_MIN: u16 = 0x0100; From 6b9187e442a8ac32419fac66b32cd93d7442f23f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:13:16 -0700 Subject: [PATCH 586/726] fix(d2b-audit): reject empty evidence-chain identities at the deserialization gate --- changelog.d/w5-07-evidence-chain-admission.md | 3 + packages/d2b-audit/src/evidence_chain.rs | 55 ++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w5-07-evidence-chain-admission.md diff --git a/changelog.d/w5-07-evidence-chain-admission.md b/changelog.d/w5-07-evidence-chain-admission.md new file mode 100644 index 000000000..882e22b88 --- /dev/null +++ b/changelog.d/w5-07-evidence-chain-admission.md @@ -0,0 +1,3 @@ +### Fixed + +- `EvidenceChain` now deserializes through an admission gate that rejects an empty `identities` list, so a wire payload can no longer produce a chain whose `depth()` underflows or whose `initiating_identity()`/`invoking_identity()` accessors panic. The serialized wire shape is unchanged. \ No newline at end of file diff --git a/packages/d2b-audit/src/evidence_chain.rs b/packages/d2b-audit/src/evidence_chain.rs index 45ae5f157..2337a1456 100644 --- a/packages/d2b-audit/src/evidence_chain.rs +++ b/packages/d2b-audit/src/evidence_chain.rs @@ -47,7 +47,7 @@ pub const NESTED_DEPTH_EXCEEDED: &str = "nested-depth-exceeded"; /// one invocation always key on the same id. The identities are the /// invoking principals, ordered from the initiating principal at index /// zero to the invoking handler of the leg itself at the end. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct EvidenceChain { /// The invocation identifier the root call was minted under; every /// nested leg of the invocation carries the same id. @@ -57,6 +57,29 @@ pub struct EvidenceChain { identities: Vec, } +impl<'de> serde::Deserialize<'de> for EvidenceChain { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(serde::Deserialize)] + struct Wire { + root_invocation_id: String, + identities: Vec, + } + let wire = Wire::deserialize(deserializer)?; + if wire.identities.is_empty() { + return Err(serde::de::Error::custom( + "evidence-chain-empty-identities", + )); + } + Ok(Self { + root_invocation_id: wire.root_invocation_id, + identities: wire.identities, + }) + } +} + impl EvidenceChain { /// The root chain of one invocation: the broker-minted invocation /// identifier and the identity the call was initiated under. @@ -366,4 +389,34 @@ mod tests { .collect::>(); assert_eq!(root_record_count(&only_nested, "invocation-1"), 0); } + + #[test] + fn an_evidence_chain_round_trips_through_the_wire_shape() { + let chain = EvidenceChain::root("invocation-1", "provider-alpha") + .nested("provider-beta"); + let json = serde_json::to_value(&chain).expect("the chain serializes"); + assert_eq!( + json, + serde_json::json!({ + "root_invocation_id": "invocation-1", + "identities": ["provider-alpha", "provider-beta"], + }) + ); + let parsed: EvidenceChain = + serde_json::from_value(json).expect("the chain deserializes"); + assert_eq!(parsed, chain); + } + + #[test] + fn an_empty_identities_chain_is_refused_at_the_admission_gate() { + let err = serde_json::from_value::(serde_json::json!({ + "root_invocation_id": "invocation-1", + "identities": [], + })) + .expect_err("an empty identities list is not a legal chain"); + assert!( + err.to_string().contains("evidence-chain-empty-identities"), + "the refusal names the admission gate: {err}" + ); + } } \ No newline at end of file From e77bf4940ce78c5d3c3a56061e4c9d7565035e7d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:13:43 -0700 Subject: [PATCH 587/726] fix(d2b-contracts-resource): admit ResourceError through constructor invariants on deserialize --- changelog.d/w5-08-resource-error-admission.md | 3 + .../d2b-contracts-resource/src/v3/error.rs | 68 ++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w5-08-resource-error-admission.md diff --git a/changelog.d/w5-08-resource-error-admission.md b/changelog.d/w5-08-resource-error-admission.md new file mode 100644 index 000000000..44baf43ff --- /dev/null +++ b/changelog.d/w5-08-resource-error-admission.md @@ -0,0 +1,3 @@ +### Fixed + +- ResourceError wire admission now routes deserialization through the validating constructor, so payloads carrying a revision for a kind that forbids it, or inconsistent retry fields, are rejected on the wire instead of admitted past the constructor invariants. The wire shape is unchanged. \ No newline at end of file diff --git a/packages/d2b-contracts-resource/src/v3/error.rs b/packages/d2b-contracts-resource/src/v3/error.rs index 420c48301..fc5d9cb48 100644 --- a/packages/d2b-contracts-resource/src/v3/error.rs +++ b/packages/d2b-contracts-resource/src/v3/error.rs @@ -172,7 +172,7 @@ impl<'de> Deserialize<'de> for ResourceErrorReason { } /// Typed resource-plane domain error. -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Serialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ResourceError { kind: ResourceErrorKind, @@ -270,6 +270,32 @@ impl core::fmt::Debug for ResourceError { } } +impl<'de> Deserialize<'de> for ResourceError { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct Wire { + kind: ResourceErrorKind, + current_revision: Option, + retry_after_ms: Option, + retry_class: RetryClass, + reason: ResourceErrorReason, + } + let wire = Wire::deserialize(deserializer)?; + Self::new( + wire.kind, + wire.current_revision, + wire.retry_after_ms, + wire.retry_class, + wire.reason, + ) + .map_err(serde::de::Error::custom) + } +} + /// Invalid typed error construction. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ResourceErrorValidation { @@ -378,4 +404,44 @@ mod tests { Err(ResourceErrorValidation::InvalidRetryAfter) ); } + + #[test] + fn resource_error_round_trips_through_the_wire() { + let error = ResourceError::new( + ResourceErrorKind::ResourceConflict, + Some(ZoneRevision::new(4)), + None, + RetryClass::Reauthorize, + ResourceErrorReason::parse("revision changed").unwrap(), + ) + .unwrap(); + let encoded = serde_json::to_vec(&error).unwrap(); + let decoded: ResourceError = serde_json::from_slice(&encoded).unwrap(); + assert_eq!(decoded, error); + } + + #[test] + fn resource_error_wire_admission_enforces_constructor_invariants() { + let revision_not_allowed = br#"{ + "kind": "resource-not-found", + "currentRevision": 4, + "retryClass": "never", + "reason": "gone" + }"#; + assert!( + serde_json::from_slice::(revision_not_allowed).is_err(), + "currentRevision must be refused for resource-not-found" + ); + + let inconsistent_retry = br#"{ + "kind": "backpressure", + "retryAfterMs": 0, + "retryClass": "after-delay", + "reason": "slow down" + }"#; + assert!( + serde_json::from_slice::(inconsistent_retry).is_err(), + "a zero retryAfterMs must be refused" + ); + } } From 379eb3b3393951fa60544d7574242b04741e8491 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:13:52 -0700 Subject: [PATCH 588/726] refactor(d2b-provider-transport-vsock): validate settings at the wire boundary --- changelog.d/w5-10-vsock-settings-admission.md | 3 + .../src/settings.rs | 55 ++++++++++++++++--- .../tests/schema.rs | 20 ++++++- 3 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 changelog.d/w5-10-vsock-settings-admission.md diff --git a/changelog.d/w5-10-vsock-settings-admission.md b/changelog.d/w5-10-vsock-settings-admission.md new file mode 100644 index 000000000..622763de7 --- /dev/null +++ b/changelog.d/w5-10-vsock-settings-admission.md @@ -0,0 +1,3 @@ +### Fixed + +- `VsockTransportSettings` now deserializes through a private wire mirror with `TryFrom` validation, so untrusted transport-settings JSON is rejected at the boundary instead of landing unvalidated for a later `validate()` call; the fields are private with accessors, and the wire field names and JSON schema are unchanged. \ No newline at end of file diff --git a/packages/d2b-provider-transport-vsock/src/settings.rs b/packages/d2b-provider-transport-vsock/src/settings.rs index 9f316402a..37c6ec039 100644 --- a/packages/d2b-provider-transport-vsock/src/settings.rs +++ b/packages/d2b-provider-transport-vsock/src/settings.rs @@ -14,16 +14,28 @@ pub enum PortClass { /// Provider-specific transport settings. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[serde( + rename_all = "camelCase", + deny_unknown_fields, + try_from = "VsockTransportSettingsWire" +)] pub struct VsockTransportSettings { - /// Same-child-Zone Guest reference. - pub guest_ref: String, - /// Allocator-owned port class. + guest_ref: String, + port_class: PortClass, + connect_timeout_seconds: u16, +} + +/// Untrusted wire mirror for [`VsockTransportSettings`]; deserialization +/// routes through the validating conversion so a derived path can never admit +/// unvalidated settings. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct VsockTransportSettingsWire { + guest_ref: String, #[serde(default)] - pub port_class: PortClass, - /// Open deadline in seconds. + port_class: PortClass, #[serde(default = "default_timeout_seconds")] - pub connect_timeout_seconds: u16, + connect_timeout_seconds: u16, } impl VsockTransportSettings { @@ -44,6 +56,21 @@ impl VsockTransportSettings { Ok(settings) } + /// Borrow the same-child-Zone Guest reference. + pub fn guest_ref(&self) -> &str { + &self.guest_ref + } + + /// Return the allocator-owned port class. + pub const fn port_class(&self) -> PortClass { + self.port_class + } + + /// Return the open deadline in seconds. + pub const fn connect_timeout_seconds(&self) -> u16 { + self.connect_timeout_seconds + } + /// Validate settings and reject raw endpoint material. /// /// # Errors @@ -70,6 +97,20 @@ impl VsockTransportSettings { } } +impl TryFrom for VsockTransportSettings { + type Error = SettingsError; + + fn try_from(wire: VsockTransportSettingsWire) -> Result { + let settings = Self { + guest_ref: wire.guest_ref, + port_class: wire.port_class, + connect_timeout_seconds: wire.connect_timeout_seconds, + }; + settings.validate()?; + Ok(settings) + } +} + impl fmt::Debug for VsockTransportSettings { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter diff --git a/packages/d2b-provider-transport-vsock/tests/schema.rs b/packages/d2b-provider-transport-vsock/tests/schema.rs index b551ccecc..7063f997c 100644 --- a/packages/d2b-provider-transport-vsock/tests/schema.rs +++ b/packages/d2b-provider-transport-vsock/tests/schema.rs @@ -13,7 +13,23 @@ fn transport_settings_schema_rejects_cid_and_port_fields() { fn transport_settings_round_trip_keeps_the_closed_port_class() { let settings: VsockTransportSettings = serde_json::from_str(r#"{"guestRef":"Guest/guest-a"}"#).unwrap(); - assert_eq!(settings.port_class, PortClass::D2bLink); - assert_eq!(settings.connect_timeout_seconds, 30); + assert_eq!(settings.port_class(), PortClass::D2bLink); + assert_eq!(settings.connect_timeout_seconds(), 30); settings.validate().unwrap(); } + +#[test] +fn transport_settings_rejects_invalid_payloads_on_deserialize() { + // A guest reference that `new()` rejects must not deserialize. + let settings: Result = + serde_json::from_str(r#"{"guestRef":"guest-a"}"#); + assert!(settings.is_err()); + // Timeouts outside `1..=60` seconds that `new()` rejects must not + // deserialize. + let settings: Result = + serde_json::from_str(r#"{"guestRef":"Guest/guest-a","connectTimeoutSeconds":0}"#); + assert!(settings.is_err()); + let settings: Result = + serde_json::from_str(r#"{"guestRef":"Guest/guest-a","connectTimeoutSeconds":61}"#); + assert!(settings.is_err()); +} From eee03f2a9b57e126da4bde9ae8b11fa7cd0050f5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:14:34 -0700 Subject: [PATCH 589/726] refactor(d2b-provider-volume-local): take volume ref by borrow in desired_binding_intents --- .../w5-02-volume-binding-intents-borrow.md | 3 +++ .../d2b-provider-volume-local/src/bindings.rs | 16 ++++++++-------- packages/d2b-provider-volume/src/driver.rs | 2 +- packages/d2bd/src/resource_runtime.rs | 4 ++-- 4 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 changelog.d/w5-02-volume-binding-intents-borrow.md diff --git a/changelog.d/w5-02-volume-binding-intents-borrow.md b/changelog.d/w5-02-volume-binding-intents-borrow.md new file mode 100644 index 000000000..af5904dd8 --- /dev/null +++ b/changelog.d/w5-02-volume-binding-intents-borrow.md @@ -0,0 +1,3 @@ +### Fixed + +- `desired_binding_intents` now takes the volume `ResourceRef` by borrow instead of by value, so the volume driver and the shared runtime no longer clone the reference before every binding-intent derivation; the owned references stored inside each `BindingIntent` are cloned from the borrow as before. \ No newline at end of file diff --git a/packages/d2b-provider-volume-local/src/bindings.rs b/packages/d2b-provider-volume-local/src/bindings.rs index 8de62c608..eddf77dc3 100644 --- a/packages/d2b-provider-volume-local/src/bindings.rs +++ b/packages/d2b-provider-volume-local/src/bindings.rs @@ -78,7 +78,7 @@ impl core::fmt::Debug for BindingIntent { /// and guest mount path -- never from the attachment index -- so reordering /// declared attachments never churns identities. pub fn desired_binding_intents( - volume_ref: ResourceRef, + volume_ref: &ResourceRef, spec: &VolumeSpec, supports_shared_write: bool, ) -> Result, VolumeLocalError> { @@ -170,7 +170,7 @@ mod tests { fn every_virtiofs_attachment_becomes_a_stable_owned_intent() { let volume = ResourceRef::parse("Volume/work-state").unwrap(); let intents = - desired_binding_intents(volume.clone(), &fixtures::attached_state_volume(), false) + desired_binding_intents(&volume, &fixtures::attached_state_volume(), false) .expect("intent"); assert_eq!(intents.len(), 1); assert_eq!(intents[0].owner_ref(), &volume); @@ -178,7 +178,7 @@ mod tests { assert!(intents[0].name().as_str().starts_with("vol-binding-")); assert_eq!( intents[0].name(), - desired_binding_intents(volume, &fixtures::attached_state_volume(), false,).unwrap()[0] + desired_binding_intents(&volume, &fixtures::attached_state_volume(), false,).unwrap()[0] .name() ); } @@ -187,13 +187,13 @@ mod tests { fn reordering_attachments_never_churns_binding_names() { let volume = ResourceRef::parse("Volume/work-state").unwrap(); let spec = two_attachment_volume(); - let forward = desired_binding_intents(volume.clone(), &spec, false).expect("intents"); + let forward = desired_binding_intents(&volume, &spec, false).expect("intents"); let mut reordered = serde_json::to_value(&spec).unwrap(); let attachments = reordered["attachments"].as_array().unwrap().clone(); let swapped: Vec<_> = attachments.into_iter().rev().collect(); reordered["attachments"] = serde_json::Value::Array(swapped); let backward_spec: VolumeSpec = serde_json::from_value(reordered).unwrap(); - let backward = desired_binding_intents(volume, &backward_spec, false).expect("intents"); + let backward = desired_binding_intents(&volume, &backward_spec, false).expect("intents"); assert_eq!(forward.len(), backward.len()); for intent in &forward { @@ -206,11 +206,11 @@ mod tests { let volume = ResourceRef::parse("Volume/work-state").unwrap(); let mut value = serde_json::to_value(fixtures::attached_state_volume()).unwrap(); let spec: VolumeSpec = serde_json::from_value(value.clone()).unwrap(); - let controller = desired_binding_intents(volume.clone(), &spec, false).unwrap(); + let controller = desired_binding_intents(&volume, &spec, false).unwrap(); value["attachments"][0]["view"] = serde_json::json!("reader"); value["attachments"][0]["access"] = serde_json::json!("read-only"); let reader_spec: VolumeSpec = serde_json::from_value(value).unwrap(); - let reader = desired_binding_intents(volume, &reader_spec, false).unwrap(); + let reader = desired_binding_intents(&volume, &reader_spec, false).unwrap(); assert_eq!(controller[0].execution_ref(), reader[0].execution_ref()); assert_eq!(controller[0].mount_path(), reader[0].mount_path()); @@ -233,7 +233,7 @@ mod tests { let spec: VolumeSpec = serde_json::from_value(value).unwrap(); assert!( desired_binding_intents( - ResourceRef::parse("Volume/work-state").unwrap(), + &ResourceRef::parse("Volume/work-state").unwrap(), &spec, false, ) diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index 7ee597ac4..9197c1af9 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -377,7 +377,7 @@ impl VolumeDriver { spec: &VolumeSpec, op: DriverOp, ) -> Result, VolumeDriverError> { - let intents = desired_binding_intents(volume_ref.clone(), spec, false).map_err(|error| { + let intents = desired_binding_intents(volume_ref, spec, false).map_err(|error| { self.error(VolumeDriverErrorKind::ChildDerivation, op) .with_detail(derivation_detail(error.code())) })?; diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 7ee829dae..55e017861 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -5867,7 +5867,7 @@ impl ZoneResourceRuntime { volume_spec: &VolumeSpec, ) -> bool { d2b_provider_volume_local::desired_binding_intents( - spec.volume_ref().clone(), + spec.volume_ref(), volume_spec, false, ) @@ -12888,7 +12888,7 @@ mod tests { let volume_ref = ResourceRef::parse("Volume/store-view-work-vm") .expect("volume ref"); let intents = d2b_provider_volume_local::desired_binding_intents( - volume_ref.clone(), + &volume_ref, &volume, false, ) From 4524b7e4542a04d9843bf6f1b19e277c2bc853c8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:14:38 -0700 Subject: [PATCH 590/726] refactor(d2b-provider-config-nixos): drop decode_document forwarder in favor of ConfigSyncResponse::document() Remove the public one-line decode_document helper duplicating the already-public ConfigSyncResponse::document() and re-point the sole caller in d2bd composition at the method directly, leaving one API path for validating a synced guest config document. --- .../w5-06-config-nixos-decode-document-dedup.md | 3 +++ packages/d2b-provider-config-nixos/src/lib.rs | 2 +- packages/d2b-provider-config-nixos/src/service.rs | 11 ----------- packages/d2bd/src/composition.rs | 2 +- 4 files changed, 5 insertions(+), 13 deletions(-) create mode 100644 changelog.d/w5-06-config-nixos-decode-document-dedup.md diff --git a/changelog.d/w5-06-config-nixos-decode-document-dedup.md b/changelog.d/w5-06-config-nixos-decode-document-dedup.md new file mode 100644 index 000000000..902dc520a --- /dev/null +++ b/changelog.d/w5-06-config-nixos-decode-document-dedup.md @@ -0,0 +1,3 @@ +### Fixed + +- Removed the public `decode_document` forwarder from d2b-provider-config-nixos; the sole caller in d2bd now uses `ConfigSyncResponse::document()` directly, leaving one API path for validating a synced guest config document. \ No newline at end of file diff --git a/packages/d2b-provider-config-nixos/src/lib.rs b/packages/d2b-provider-config-nixos/src/lib.rs index 67d0b856d..1b52ed06d 100644 --- a/packages/d2b-provider-config-nixos/src/lib.rs +++ b/packages/d2b-provider-config-nixos/src/lib.rs @@ -19,7 +19,7 @@ pub use service::{ ConfigApproveRequest, ConfigApproveResponse, ConfigDiffRequest, ConfigDiffResponse, ConfigRejectRequest, ConfigRejectResponse, ConfigStageRequest, ConfigStageResponse, ConfigStagingStore, ConfigStatusRequest, ConfigStatusResponse, ConfigSyncRequest, - ConfigSyncResponse, GUEST_CONFIG_IDENTIFIER, MAX_CONFIG_BYTES, decode_document, + ConfigSyncResponse, GUEST_CONFIG_IDENTIFIER, MAX_CONFIG_BYTES, }; pub use ttrpc::{ ConfigNixosClient, ConfigServiceBackend, GuestConfigReader, create_ttrpc_services, diff --git a/packages/d2b-provider-config-nixos/src/service.rs b/packages/d2b-provider-config-nixos/src/service.rs index d84e06e13..7f0c2d239 100644 --- a/packages/d2b-provider-config-nixos/src/service.rs +++ b/packages/d2b-provider-config-nixos/src/service.rs @@ -340,17 +340,6 @@ pub struct ConfigStatusResponse { pub sha256: Option, } -/// Convert one response into a validated document. -/// -/// # Errors -/// -/// Returns the same errors as [`ConfigSyncResponse::document`]: -/// [`ConfigError::InvalidRequest`], [`ConfigError::EncodingFailed`], and the -/// document bounds errors. -pub fn decode_document(response: &ConfigSyncResponse) -> Result { - response.document() -} - pub(crate) fn validate_guest_ref(guest_ref: &ResourceRef) -> Result<(), ConfigError> { if guest_ref.resource_type().as_str() == "Guest" && !guest_ref.name().as_str().is_empty() { Ok(()) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..7c5236796 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -11671,7 +11671,7 @@ fn read_guest_config_typed( result.map_err(config_read_error_kind) }) .map_err(|kind| TypedError::ConfigReadFailed { kind })?; - d2b_provider_config_nixos::decode_document(&response).map_err(|_| { + response.document().map_err(|_| { TypedError::ConfigReadFailed { kind: d2bd_runtime::typed_error::ConfigReadErrorKind::Protocol, } From 6ecf465b77dfbafd2329ae68e8c8bd03093f0441 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:21:48 -0700 Subject: [PATCH 591/726] refactor(d2b-core-controller): typed serde codecs for assignment transport and child create payload Replace the hand-rolled serde_json::Value-walking encode/decode for the scoped commit envelope, assignment grant, revocation notice, owner-child scope, and mutation with typed serde structs (rename_all camelCase, deny_unknown_fields). Wire shape is preserved: exact keys, version 1, strictly ascending verb arrays, canonical bytes, and bounded size. The child create payload builder now materializes through typed envelopes instead of json! literals. Dead Value-walking helpers removed; encode_bounded_json remains as the generic bounded-canonical egress and decode_string_set remains as the sorted-array admission check. --- changelog.d/w5-09-assignment-codec-typed.md | 5 + .../src/binding_children.rs | 320 ++++--- .../src/controller_assignment.rs | 839 +++++++++--------- 3 files changed, 589 insertions(+), 575 deletions(-) create mode 100644 changelog.d/w5-09-assignment-codec-typed.md diff --git a/changelog.d/w5-09-assignment-codec-typed.md b/changelog.d/w5-09-assignment-codec-typed.md new file mode 100644 index 000000000..4ca76695b --- /dev/null +++ b/changelog.d/w5-09-assignment-codec-typed.md @@ -0,0 +1,5 @@ +### Fixed + +- Assignment transport codecs (scoped commit envelope, assignment grant, revocation notice, owner-child scope, mutation) now encode and decode through typed serde structs with `rename_all = "camelCase"` and `deny_unknown_fields`, replacing the hand-rolled `serde_json::Value` walking. Wire shape is unchanged: exact keys, version 1, strictly ascending verb arrays, canonical bytes, and the existing size bounds all still hold. +- The child create payload builder now materializes through typed serde envelopes instead of `json!` literals and `serde_json::Map` spec assembly; the canonical UID-free payload shape is unchanged. +- Removed the dead Value-walking helpers (`require_exact_keys`, the hand-rolled decode functions); `encode_bounded_json` remains as the generic bounded-canonical egress and `decode_string_set` remains as the sorted-array admission check. \ No newline at end of file diff --git a/packages/d2b-core-controller/src/binding_children.rs b/packages/d2b-core-controller/src/binding_children.rs index 43599b6f3..4510f45b1 100644 --- a/packages/d2b-core-controller/src/binding_children.rs +++ b/packages/d2b-core-controller/src/binding_children.rs @@ -11,10 +11,11 @@ use d2b_contracts_provider::v3::semantic_services::child_resources::{ BindingChildIntent, BindingChildKind, BindingChildPlacement, }; use d2b_contracts_resource::v3::{ - CanonicalJsonValue, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceRef, ResourceTypeName, - canonical_digest, + CanonicalJsonObject, CanonicalJsonValue, RESOURCE_ENVELOPE_DOMAIN_TAG, ResourceRef, + ResourceTypeName, canonical_digest, }; use d2b_contracts_zone_session::v3::resource_bundle::BundleResource; +use serde::Serialize; use crate::OwnerReconcileError; @@ -164,6 +165,121 @@ pub fn semantic_child_digest( Ok(canonical_digest(RESOURCE_ENVELOPE_DOMAIN_TAG, &canonical)) } +/// Typed wire form of the UID-free create payload Core materializes for one +/// Binding child. The store remains responsible for minting the +/// authoritative UID and revision. +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ChildCreateEnvelope<'a> { + api_version: &'static str, + #[serde(rename = "type")] + resource_type: &'a str, + metadata: ChildCreateMetadata<'a>, + spec: ChildCreateSpec, + status: ChildCreateStatus, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ChildCreateMetadata<'a> { + name: &'a str, + zone: &'a str, + owner_ref: &'a str, + finalizers: &'static [&'static str], + deletion_requested_at: Option<&'static str>, + created_at: &'static str, + updated_at: &'static str, + generation: u64, + revision: u64, + managed_by: &'static str, +} + +/// Process and Endpoint child specs carry disjoint field sets, so the spec +/// is exactly one of the two strict structs. +#[derive(Serialize)] +#[serde(untagged)] +enum ChildCreateSpec { + Process(ProcessChildSpec), + Endpoint(EndpointChildSpec), +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ProcessChildSpec { + execution_ref: String, + process_class: String, + template: String, + provider_ref: String, + #[serde(skip_serializing_if = "Option::is_none")] + domain: Option, + #[serde(skip_serializing_if = "Option::is_none")] + user_ref: Option, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct EndpointChildSpec { + provider_ref: String, + producer_ref: String, + endpoint_class: String, + transport: String, + purpose: String, + locality: String, + visibility: String, + attachment_policy: AttachmentPolicy, + consumer_policy: ConsumerPolicy, + lifecycle_policy: String, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct AttachmentPolicy { + supported: bool, + max_attachments: u64, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ConsumerPolicy { + allowed_operations: &'static [&'static str], +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ChildCreateStatus { + observed_generation: u64, + phase: &'static str, + conditions: &'static [&'static str], + last_reconciled_at: Option<&'static str>, + started_at: Option<&'static str>, + completed_at: Option<&'static str>, + outcome: Option<&'static str>, + update: ChildCreateUpdate, + resource: CanonicalJsonObject, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ChildCreateUpdate { + dependencies: ChildCreateCurrencySet, + disruption: &'static str, + last_assessed_at: Option<&'static str>, + observed_generation: u64, + operation_id: Option<&'static str>, + owned: ChildCreateCurrencySet, + preserve_state: bool, + reasons: &'static [&'static str], + state: &'static str, + target_generation: u64, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ChildCreateCurrencySet { + count: u64, + refs: &'static [&'static str], +} + /// Build the canonical, UID-free Resource API create payload for one child. /// /// This is intentionally owned by Core: Providers cannot smuggle arbitrary @@ -175,14 +291,7 @@ pub fn materialize_child_create_payload( zone: &d2b_contracts_resource::v3::ZoneId, ) -> Result, BindingChildMaterializationError> { let owner_ref = intent.owner_ref().to_canonical_string(); - let provider_ref = match intent.kind() { - BindingChildKind::Process | BindingChildKind::EphemeralProcess => { - "Provider/system-systemd".to_owned() - } - BindingChildKind::Endpoint => intent.provider_ref().to_canonical_string(), - }; - let mut spec = serde_json::Map::new(); - match intent.kind() { + let spec = match intent.kind() { BindingChildKind::Process | BindingChildKind::EphemeralProcess => { let process_provider = intent .process_provider() @@ -200,139 +309,88 @@ pub fn materialize_child_create_payload( } else { "worker" }); - spec.insert( - "executionRef".to_owned(), - serde_json::Value::String(intent.execution_ref().to_canonical_string()), - ); - spec.insert( - "processClass".to_owned(), - serde_json::Value::String(process_class.to_owned()), - ); - spec.insert( - "template".to_owned(), - serde_json::Value::String(process_template.to_owned()), - ); - spec.insert( - "providerRef".to_owned(), - serde_json::Value::String(process_provider.to_owned()), - ); - if let Some(process_domain) = process_domain { - spec.insert( - "domain".to_owned(), - serde_json::Value::String(process_domain.to_owned()), - ); - } - if let Some(user_ref) = intent.process_user() { - spec.insert( - "userRef".to_owned(), - serde_json::Value::String(user_ref.to_canonical_string()), - ); - } + ChildCreateSpec::Process(ProcessChildSpec { + execution_ref: intent.execution_ref().to_canonical_string(), + process_class: process_class.to_owned(), + template: process_template.to_owned(), + provider_ref: process_provider.to_owned(), + domain: process_domain.map(str::to_owned), + user_ref: intent + .process_user() + .map(|user_ref| user_ref.to_canonical_string()), + }) } BindingChildKind::Endpoint => { let producer = intent .producer_ref() .ok_or(BindingChildMaterializationError::ProducerMismatch)?; - spec.insert( - "providerRef".to_owned(), - serde_json::Value::String(provider_ref), - ); - spec.insert( - "producerRef".to_owned(), - serde_json::Value::String(producer.to_canonical_string()), - ); - spec.insert( - "endpointClass".to_owned(), - serde_json::Value::String("service".to_owned()), - ); - spec.insert( - "transport".to_owned(), - serde_json::Value::String("opaque-carriage".to_owned()), - ); - spec.insert( - "purpose".to_owned(), - serde_json::Value::String(intent.role().to_owned()), - ); - spec.insert( - "locality".to_owned(), - serde_json::Value::String( - match intent.placement() { - BindingChildPlacement::Host => "host-local", - BindingChildPlacement::Guest => "guest-local", - } - .to_owned(), - ), - ); - spec.insert( - "visibility".to_owned(), - serde_json::Value::String("provider".to_owned()), - ); - spec.insert( - "attachmentPolicy".to_owned(), - serde_json::json!({ - "supported": true, - "maxAttachments": 1 - }), - ); - spec.insert( - "consumerPolicy".to_owned(), - serde_json::json!({ - "allowedOperations": ["resolve", "attach", "observe"] - }), - ); - spec.insert( - "lifecyclePolicy".to_owned(), - serde_json::Value::String("recycle-with-producer".to_owned()), - ); + ChildCreateSpec::Endpoint(EndpointChildSpec { + provider_ref: intent.provider_ref().to_canonical_string(), + producer_ref: producer.to_canonical_string(), + endpoint_class: "service".to_owned(), + transport: "opaque-carriage".to_owned(), + purpose: intent.role().to_owned(), + locality: match intent.placement() { + BindingChildPlacement::Host => "host-local", + BindingChildPlacement::Guest => "guest-local", + } + .to_owned(), + visibility: "provider".to_owned(), + attachment_policy: AttachmentPolicy { + supported: true, + max_attachments: 1, + }, + consumer_policy: ConsumerPolicy { + allowed_operations: &["resolve", "attach", "observe"], + }, + lifecycle_policy: "recycle-with-producer".to_owned(), + }) } - } - let value = serde_json::json!({ - "apiVersion": "resources.d2bus.org/v3", - "type": intent.kind().resource_type(), - "metadata": { - "name": intent.resource_ref().name().as_str(), - "zone": zone.as_str(), - "ownerRef": owner_ref, - "finalizers": [], - "deletionRequestedAt": null, - "createdAt": "1970-01-01T00:00:00.000Z", - "updatedAt": "1970-01-01T00:00:00.000Z", - "generation": 1, - "revision": 1, - "managedBy": "controller" + }; + let envelope = ChildCreateEnvelope { + api_version: "resources.d2bus.org/v3", + resource_type: intent.kind().resource_type(), + metadata: ChildCreateMetadata { + name: intent.resource_ref().name().as_str(), + zone: zone.as_str(), + owner_ref: &owner_ref, + finalizers: &[], + deletion_requested_at: None, + created_at: "1970-01-01T00:00:00.000Z", + updated_at: "1970-01-01T00:00:00.000Z", + generation: 1, + revision: 1, + managed_by: "controller", }, - "spec": spec, - "status": { - "observedGeneration": 0, - "phase": "Pending", - "conditions": [], - "lastReconciledAt": null, - "startedAt": null, - "completedAt": null, - "outcome": null, - "update": { - "dependencies": {"count": 0, "refs": []}, - "disruption": "None", - "lastAssessedAt": null, - "observedGeneration": 0, - "operationId": null, - "owned": {"count": 0, "refs": []}, - "preserveState": true, - "reasons": [], - "state": "Unknown", - "targetGeneration": 1 + spec, + status: ChildCreateStatus { + observed_generation: 0, + phase: "Pending", + conditions: &[], + last_reconciled_at: None, + started_at: None, + completed_at: None, + outcome: None, + update: ChildCreateUpdate { + dependencies: ChildCreateCurrencySet { count: 0, refs: &[] }, + disruption: "None", + last_assessed_at: None, + observed_generation: 0, + operation_id: None, + owned: ChildCreateCurrencySet { count: 0, refs: &[] }, + preserve_state: true, + reasons: &[], + state: "Unknown", + target_generation: 1, }, - "resource": {} - } - }); - let bytes = serde_json::to_vec(&value) + resource: CanonicalJsonObject::default(), + }, + }; + let bytes = serde_json::to_vec(&envelope) .map_err(|_| BindingChildMaterializationError::MalformedResource)?; let canonical = CanonicalJsonValue::parse(&bytes) .map_err(|_| BindingChildMaterializationError::MalformedResource)? .to_canonical_bytes(); - if canonical != bytes { - return Err(BindingChildMaterializationError::NonCanonicalResource); - } Ok(canonical) } diff --git a/packages/d2b-core-controller/src/controller_assignment.rs b/packages/d2b-core-controller/src/controller_assignment.rs index 23df9bb2f..e097eb99b 100644 --- a/packages/d2b-core-controller/src/controller_assignment.rs +++ b/packages/d2b-core-controller/src/controller_assignment.rs @@ -20,7 +20,7 @@ use d2b_contracts_resource::v3::{ PlacementTargetKind, ResourceEnvelope, ResourceGeneration, ResourceName, ResourceRef, ResourceTypeName, ResourceUid, ZoneId, ZoneRevision, }; -use serde_json::{Map, Value, json}; +use serde::{Deserialize, Serialize}; /// Maximum encoded assignment evidence carried by one scoped commit. pub const MAX_SCOPED_COMMIT_TRANSPORT_BYTES: usize = 64 * 1024; @@ -481,16 +481,18 @@ impl ScopedCommitTransport { /// Encode the evidence as bounded canonical JSON bytes. pub fn encode(&self) -> Result, AssignmentTransportError> { - let value = json!({ - "version": 1, - "assignment": encode_assignment(&self.assignment), - "mutations": self - .mutations - .iter() - .map(encode_mutation) - .collect::>(), - }); - encode_bounded_json(&value, MAX_SCOPED_COMMIT_TRANSPORT_BYTES) + encode_bounded_json( + &ScopedCommitEnvelope { + version: 1, + assignment: AssignmentEnvelope::from_identity(&self.assignment), + mutations: self + .mutations + .iter() + .map(MutationEnvelope::from_mutation) + .collect(), + }, + MAX_SCOPED_COMMIT_TRANSPORT_BYTES, + ) } /// Decode bounded evidence produced by [`Self::encode`]. @@ -499,62 +501,19 @@ impl ScopedCommitTransport { return Err(AssignmentTransportError::TooLarge); } CanonicalJsonValue::parse(bytes).map_err(|_| AssignmentTransportError::Malformed)?; - let value = serde_json::from_slice::(bytes) + let envelope = serde_json::from_slice::(bytes) .map_err(|_| AssignmentTransportError::Malformed)?; - let object = value - .as_object() - .ok_or(AssignmentTransportError::Malformed)?; - require_exact_keys(object, &["version", "assignment", "mutations"])?; - if object.get("version").and_then(Value::as_u64) != Some(1) { - return Err(AssignmentTransportError::Malformed); - } - let assignment = decode_assignment( - object - .get("assignment") - .ok_or(AssignmentTransportError::Malformed)?, - )?; - let mutation_values = object - .get("mutations") - .and_then(Value::as_array) - .ok_or(AssignmentTransportError::Malformed)?; - if mutation_values.is_empty() || mutation_values.len() > 128 { + if envelope.version != 1 + || envelope.mutations.is_empty() + || envelope.mutations.len() > 128 + { return Err(AssignmentTransportError::Malformed); } - let mutations = mutation_values - .iter() - .map(|value| { - let object = value - .as_object() - .ok_or(AssignmentTransportError::Malformed)?; - let scope = match object.get("scope") { - None => ScopedResourceScope::Primary, - Some(scope) => decode_scoped_resource_scope(scope)?, - }; - if matches!(scope, ScopedResourceScope::Primary) { - require_exact_keys(object, &["target", "verb"])?; - } else { - require_exact_keys(object, &["target", "verb", "scope"])?; - } - let target = ResourceRef::parse( - object - .get("target") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let verb = decode_assignment_verb( - object - .get("verb") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - )?; - Ok(ScopedResourceMutation { - assignment: assignment.clone(), - target, - verb, - scope, - }) - }) + let assignment = envelope.assignment.into_identity()?; + let mutations = envelope + .mutations + .into_iter() + .map(|mutation| mutation.into_mutation(&assignment)) .collect::, _>>()?; Self::new(assignment, mutations) } @@ -597,112 +556,286 @@ impl fmt::Debug for ScopedCommitTransport { } } -fn encode_assignment(identity: &AssignmentIdentity) -> Value { - let target = match identity.target() { - AssignmentTarget::Zone(zone) => json!({ - "kind": "zone", - "zone": zone.as_str(), - }), - AssignmentTarget::Execution { kind, reference } => json!({ - "kind": "execution", - "targetKind": match kind { - PlacementTargetKind::Host => "host", - PlacementTargetKind::Guest => "guest", +/// Strict wire form of one assignment identity. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct AssignmentEnvelope { + resource_uid: String, + resource_revision: u64, + provider_ref: String, + provider_generation: u64, + controller_generation: u64, + controller_role: String, + target: AssignmentTargetEnvelope, + session_owner: String, + session_generation: u64, + epoch: u64, +} + +impl AssignmentEnvelope { + fn from_identity(identity: &AssignmentIdentity) -> Self { + Self { + resource_uid: identity.resource_uid().as_str().to_owned(), + resource_revision: identity.resource_revision().get(), + provider_ref: identity.session_binding().provider_ref().to_canonical_string(), + provider_generation: identity.provider_generation().get(), + controller_generation: identity.controller_generation().get(), + controller_role: identity.controller_role().to_canonical_string(), + target: AssignmentTargetEnvelope::from_target(identity.target()), + session_owner: identity.session_owner().to_canonical_string(), + session_generation: identity.session_generation().get(), + epoch: identity.epoch().get(), + } + } + + fn into_identity(self) -> Result { + let provider_ref = ResourceRef::parse(&self.provider_ref) + .map_err(|_| AssignmentTransportError::Malformed)?; + let target = self.target.into_target()?; + let provider_generation = ResourceGeneration::new(self.provider_generation) + .map_err(|_| AssignmentTransportError::Malformed)?; + let controller_generation = ControllerGeneration::new(self.controller_generation) + .map_err(|_| AssignmentTransportError::Malformed)?; + let controller_role = ResourceRef::parse(&self.controller_role) + .map_err(|_| AssignmentTransportError::Malformed)?; + let session_owner = ResourceRef::parse(&self.session_owner) + .map_err(|_| AssignmentTransportError::Malformed)?; + let session_generation = ReconnectGeneration::new(self.session_generation) + .map_err(|_| AssignmentTransportError::Malformed)?; + let session = ControllerSessionBinding::new( + session_owner, + provider_ref, + controller_role, + target, + provider_generation, + controller_generation, + session_generation, + ) + .map_err(|_| AssignmentTransportError::Malformed)?; + Ok(AssignmentIdentity::new( + ResourceUid::parse(&self.resource_uid) + .map_err(|_| AssignmentTransportError::Malformed)?, + ZoneRevision::new(self.resource_revision), + session, + AssignmentEpoch::new(self.epoch).map_err(|_| AssignmentTransportError::Malformed)?, + )) + } +} + +/// Strict wire form of one assignment target. +/// +/// Serde cannot apply `deny_unknown_fields` to an internally tagged enum, so +/// the flat union is parsed strictly: variant fields are optional on the +/// wire and rejected when they do not belong to the selected `kind`. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct AssignmentTargetEnvelope { + kind: String, + #[serde( + skip_serializing_if = "Option::is_none", + default, + deserialize_with = "deserialize_non_null_string" + )] + zone: Option, + #[serde( + skip_serializing_if = "Option::is_none", + default, + deserialize_with = "deserialize_non_null_string" + )] + target_kind: Option, + #[serde( + skip_serializing_if = "Option::is_none", + default, + deserialize_with = "deserialize_non_null_string" + )] + reference: Option, +} + +/// Reject an explicit JSON `null` for an optional wire field: a variant +/// field must be absent, not null, when it does not belong to the selected +/// target kind. +fn deserialize_non_null_string<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Option::::deserialize(deserializer)? + .ok_or_else(|| serde::de::Error::custom("expected a string field, found null")) + .map(Some) +} + +impl AssignmentTargetEnvelope { + fn from_target(target: &AssignmentTarget) -> Self { + match target { + AssignmentTarget::Zone(zone) => Self { + kind: "zone".to_owned(), + zone: Some(zone.as_str().to_owned()), + target_kind: None, + reference: None, }, - "reference": reference.to_canonical_string(), - }), - }; - json!({ - "resourceUid": identity.resource_uid().as_str(), - "resourceRevision": identity.resource_revision().get(), - "providerRef": identity.session_binding().provider_ref().to_canonical_string(), - "providerGeneration": identity.provider_generation().get(), - "controllerGeneration": identity.controller_generation().get(), - "controllerRole": identity.controller_role().to_canonical_string(), - "target": target, - "sessionOwner": identity.session_owner().to_canonical_string(), - "sessionGeneration": identity.session_generation().get(), - "epoch": identity.epoch().get(), - }) + AssignmentTarget::Execution { kind, reference } => Self { + kind: "execution".to_owned(), + zone: None, + target_kind: Some( + match kind { + PlacementTargetKind::Host => "host", + PlacementTargetKind::Guest => "guest", + } + .to_owned(), + ), + reference: Some(reference.to_canonical_string()), + }, + } + } + + fn into_target(self) -> Result { + match self.kind.as_str() { + "zone" => { + let Some(zone) = self.zone else { + return Err(AssignmentTransportError::Malformed); + }; + if self.target_kind.is_some() || self.reference.is_some() { + return Err(AssignmentTransportError::Malformed); + } + Ok(AssignmentTarget::Zone( + ZoneId::parse(&zone).map_err(|_| AssignmentTransportError::Malformed)?, + )) + } + "execution" => { + let (Some(target_kind), Some(reference)) = (self.target_kind, self.reference) + else { + return Err(AssignmentTransportError::Malformed); + }; + if self.zone.is_some() { + return Err(AssignmentTransportError::Malformed); + } + let target_kind = match target_kind.as_str() { + "host" => PlacementTargetKind::Host, + "guest" => PlacementTargetKind::Guest, + _ => return Err(AssignmentTransportError::Malformed), + }; + let reference = + ResourceRef::parse(&reference).map_err(|_| AssignmentTransportError::Malformed)?; + if (target_kind == PlacementTargetKind::Host + && reference.resource_type().as_str() != "Host") + || (target_kind == PlacementTargetKind::Guest + && reference.resource_type().as_str() != "Guest") + { + return Err(AssignmentTransportError::Malformed); + } + Ok(AssignmentTarget::Execution { + kind: target_kind, + reference, + }) + } + _ => Err(AssignmentTransportError::Malformed), + } + } } -fn encode_mutation(mutation: &ScopedResourceMutation) -> Value { - let mut value = json!({ - "target": mutation.target().to_canonical_string(), - "verb": encode_assignment_verb(mutation.verb()), - }) - .as_object() - .cloned() - .expect("scoped mutation encoding is an object"); - if let ScopedResourceScope::OwnerChild(scope) = mutation.scope() { - value.insert("scope".to_owned(), encode_owner_child_scope(scope)); - } - Value::Object(value) +/// Strict wire form of one owner-child scope. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct OwnerChildScopeEnvelope { + kind: String, + owner_ref: String, + owner_uid: String, + owner_revision: u64, + owner_generation: u64, +} + +impl OwnerChildScopeEnvelope { + fn from_scope(scope: &OwnerChildScope) -> Self { + Self { + kind: "owner-child".to_owned(), + owner_ref: scope.owner_ref().to_canonical_string(), + owner_uid: scope.owner_uid().as_str().to_owned(), + owner_revision: scope.owner_revision().get(), + owner_generation: scope.owner_generation().get(), + } + } + + fn into_scope(self) -> Result { + if self.kind != "owner-child" || self.owner_revision == 0 { + return Err(AssignmentTransportError::Malformed); + } + Ok(ScopedResourceScope::OwnerChild(OwnerChildScope { + owner_ref: ResourceRef::parse(&self.owner_ref) + .map_err(|_| AssignmentTransportError::Malformed)?, + owner_uid: ResourceUid::parse(&self.owner_uid) + .map_err(|_| AssignmentTransportError::Malformed)?, + owner_revision: ZoneRevision::new(self.owner_revision), + owner_generation: ResourceGeneration::new(self.owner_generation) + .map_err(|_| AssignmentTransportError::Malformed)?, + })) + } } -fn encode_owner_child_scope(scope: &OwnerChildScope) -> Value { - json!({ - "kind": "owner-child", - "ownerRef": scope.owner_ref().to_canonical_string(), - "ownerUid": scope.owner_uid().as_str(), - "ownerRevision": scope.owner_revision().get(), - "ownerGeneration": scope.owner_generation().get(), - }) +/// Strict wire form of one scoped mutation. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct MutationEnvelope { + target: String, + verb: String, + #[serde( + skip_serializing_if = "Option::is_none", + default, + deserialize_with = "deserialize_non_null_scope" + )] + scope: Option, } -fn decode_scoped_resource_scope( - value: &Value, -) -> Result { - let object = value - .as_object() - .ok_or(AssignmentTransportError::Malformed)?; - require_exact_keys( - object, - &[ - "kind", - "ownerRef", - "ownerUid", - "ownerRevision", - "ownerGeneration", - ], - )?; - if object.get("kind").and_then(Value::as_str) != Some("owner-child") { - return Err(AssignmentTransportError::Malformed); +/// Reject an explicit JSON `null` for the optional scope: a mutation either +/// omits the key (primary scope) or carries a full owner-child object. +fn deserialize_non_null_scope<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Option::::deserialize(deserializer)? + .ok_or_else(|| serde::de::Error::custom("expected an owner-child scope object, found null")) + .map(Some) +} + +impl MutationEnvelope { + fn from_mutation(mutation: &ScopedResourceMutation) -> Self { + Self { + target: mutation.target().to_canonical_string(), + verb: encode_assignment_verb(mutation.verb()).to_owned(), + scope: match mutation.scope() { + ScopedResourceScope::Primary => None, + ScopedResourceScope::OwnerChild(scope) => { + Some(OwnerChildScopeEnvelope::from_scope(scope)) + } + }, + } } - let owner_ref = ResourceRef::parse( - object - .get("ownerRef") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let owner_uid = ResourceUid::parse( - object - .get("ownerUid") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let owner_revision = ZoneRevision::new( - object - .get("ownerRevision") - .and_then(Value::as_u64) - .filter(|revision| *revision != 0) - .ok_or(AssignmentTransportError::Malformed)?, - ); - let owner_generation = ResourceGeneration::new( - object - .get("ownerGeneration") - .and_then(Value::as_u64) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - Ok(ScopedResourceScope::OwnerChild(OwnerChildScope { - owner_ref, - owner_uid, - owner_revision, - owner_generation, - })) + + fn into_mutation( + self, + assignment: &AssignmentIdentity, + ) -> Result { + let scope = match self.scope { + None => ScopedResourceScope::Primary, + Some(scope) => scope.into_scope()?, + }; + Ok(ScopedResourceMutation { + assignment: assignment.clone(), + target: ResourceRef::parse(&self.target) + .map_err(|_| AssignmentTransportError::Malformed)?, + verb: decode_assignment_verb(&self.verb)?, + scope, + }) + } +} + +/// Strict wire form of one scoped commit transport envelope. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct ScopedCommitEnvelope { + version: u64, + assignment: AssignmentEnvelope, + mutations: Vec, } fn encode_assignment_verb(verb: AssignmentVerb) -> &'static str { @@ -736,174 +869,13 @@ fn decode_assignment_verb(value: &str) -> Result Result { - let object = value - .as_object() - .ok_or(AssignmentTransportError::Malformed)?; - require_exact_keys( - object, - &[ - "resourceUid", - "resourceRevision", - "providerRef", - "providerGeneration", - "controllerGeneration", - "controllerRole", - "target", - "sessionOwner", - "sessionGeneration", - "epoch", - ], - )?; - let provider_ref = ResourceRef::parse( - object - .get("providerRef") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let target = decode_assignment_target( - object - .get("target") - .ok_or(AssignmentTransportError::Malformed)?, - )?; - let provider_generation = ResourceGeneration::new( - object - .get("providerGeneration") - .and_then(Value::as_u64) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let controller_generation = ControllerGeneration::new( - object - .get("controllerGeneration") - .and_then(Value::as_u64) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let controller_role = ResourceRef::parse( - object - .get("controllerRole") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let session_owner = ResourceRef::parse( - object - .get("sessionOwner") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let session_generation = ReconnectGeneration::new( - object - .get("sessionGeneration") - .and_then(Value::as_u64) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let session = ControllerSessionBinding::new( - session_owner, - provider_ref, - controller_role, - target, - provider_generation, - controller_generation, - session_generation, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - Ok(AssignmentIdentity::new( - ResourceUid::parse( - object - .get("resourceUid") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?, - ZoneRevision::new( - object - .get("resourceRevision") - .and_then(Value::as_u64) - .ok_or(AssignmentTransportError::Malformed)?, - ), - session, - AssignmentEpoch::new( - object - .get("epoch") - .and_then(Value::as_u64) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?, - )) -} - -fn decode_assignment_target(value: &Value) -> Result { - let object = value - .as_object() - .ok_or(AssignmentTransportError::Malformed)?; - let kind = object - .get("kind") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?; - match kind { - "zone" => { - require_exact_keys(object, &["kind", "zone"])?; - Ok(AssignmentTarget::Zone( - ZoneId::parse( - object - .get("zone") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?, - )) - } - "execution" => { - require_exact_keys(object, &["kind", "targetKind", "reference"])?; - let reference = ResourceRef::parse( - object - .get("reference") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let target_kind = match object - .get("targetKind") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)? - { - "host" => PlacementTargetKind::Host, - "guest" => PlacementTargetKind::Guest, - _ => return Err(AssignmentTransportError::Malformed), - }; - if (target_kind == PlacementTargetKind::Host - && reference.resource_type().as_str() != "Host") - || (target_kind == PlacementTargetKind::Guest - && reference.resource_type().as_str() != "Guest") - { - return Err(AssignmentTransportError::Malformed); - } - Ok(AssignmentTarget::Execution { - kind: target_kind, - reference, - }) - } - _ => Err(AssignmentTransportError::Malformed), - } -} - -fn require_exact_keys( - object: &Map, - expected: &[&str], -) -> Result<(), AssignmentTransportError> { - if object.len() != expected.len() || expected.iter().any(|key| !object.contains_key(*key)) { - return Err(AssignmentTransportError::Malformed); - } - Ok(()) -} - +/// Serialize one typed envelope to bounded canonical JSON bytes. +/// +/// Kept as the single bounded-canonical egress: the transport contract pins +/// canonical bytes and a size ceiling, which typed serde alone does not +/// enforce. fn encode_bounded_json( - value: &Value, + value: &impl Serialize, max_bytes: usize, ) -> Result, AssignmentTransportError> { let bytes = serde_json::to_vec(value).map_err(|_| AssignmentTransportError::Malformed)?; @@ -1674,6 +1646,63 @@ pub struct ControllerAssignmentGrant { scopes: BTreeSet, } +/// Strict wire form of one controller assignment grant. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct AssignmentGrantEnvelope { + version: u64, + provider_ref: String, + assignment: AssignmentEnvelope, + resource_ref: String, + resource_generation: u64, + resource_types: Vec, + primary_verbs: Vec, + owner_child_process_verbs: Vec, + scopes: Vec, +} + +impl AssignmentGrantEnvelope { + fn from_grant(grant: &ControllerAssignmentGrant) -> Self { + Self { + version: 1, + provider_ref: grant.provider_ref.to_canonical_string(), + assignment: AssignmentEnvelope::from_identity(&grant.assignment), + resource_ref: grant.resource_ref.to_canonical_string(), + resource_generation: grant.resource_generation.get(), + resource_types: grant + .resource_types + .iter() + .map(|resource_type| resource_type.as_str().to_owned()) + .collect(), + primary_verbs: grant + .primary_verbs + .iter() + .map(|verb| encode_assignment_verb(*verb).to_owned()) + .collect(), + owner_child_process_verbs: grant + .owner_child_process_verbs + .iter() + .map(|verb| encode_assignment_verb(*verb).to_owned()) + .collect(), + scopes: grant + .scopes + .iter() + .map(|scope| encode_assignment_scope(*scope).to_owned()) + .collect(), + } + } +} + +/// Strict wire form of one revocation notice. +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct AssignmentRevocationEnvelope { + version: u64, + kind: String, + provider_ref: String, + assignment: AssignmentEnvelope, +} + impl ControllerAssignmentGrant { /// Build a grant from one admitted Core ResourceClient lease. pub fn from_lease(lease: &ResourceClientLease) -> Self { @@ -1851,30 +1880,10 @@ impl ControllerAssignmentGrant { /// Encode this grant as bounded canonical JSON. pub fn encode(&self) -> Result, AssignmentTransportError> { - let value = json!({ - "version": 1, - "providerRef": self.provider_ref.to_canonical_string(), - "assignment": encode_assignment(&self.assignment), - "resourceRef": self.resource_ref.to_canonical_string(), - "resourceGeneration": self.resource_generation.get(), - "resourceTypes": self.resource_types - .iter() - .map(|resource_type| resource_type.as_str()) - .collect::>(), - "primaryVerbs": self.primary_verbs - .iter() - .map(|verb| encode_assignment_verb(*verb)) - .collect::>(), - "ownerChildProcessVerbs": self.owner_child_process_verbs - .iter() - .map(|verb| encode_assignment_verb(*verb)) - .collect::>(), - "scopes": self.scopes - .iter() - .map(|scope| encode_assignment_scope(*scope)) - .collect::>(), - }); - encode_bounded_json(&value, MAX_CONTROLLER_ASSIGNMENT_GRANT_BYTES) + encode_bounded_json( + &AssignmentGrantEnvelope::from_grant(self), + MAX_CONTROLLER_ASSIGNMENT_GRANT_BYTES, + ) } /// Decode one bounded canonical grant. @@ -1883,88 +1892,39 @@ impl ControllerAssignmentGrant { return Err(AssignmentTransportError::TooLarge); } CanonicalJsonValue::parse(bytes).map_err(|_| AssignmentTransportError::Malformed)?; - let value = serde_json::from_slice::(bytes) + let envelope = serde_json::from_slice::(bytes) .map_err(|_| AssignmentTransportError::Malformed)?; - let object = value - .as_object() - .ok_or(AssignmentTransportError::Malformed)?; - require_exact_keys( - object, - &[ - "version", - "providerRef", - "assignment", - "resourceRef", - "resourceGeneration", - "resourceTypes", - "primaryVerbs", - "ownerChildProcessVerbs", - "scopes", - ], - )?; - if object.get("version").and_then(Value::as_u64) != Some(1) { + if envelope.version != 1 { return Err(AssignmentTransportError::Malformed); } - let provider_ref = ResourceRef::parse( - object - .get("providerRef") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let assignment = decode_assignment( - object - .get("assignment") - .ok_or(AssignmentTransportError::Malformed)?, - )?; - let resource_ref = ResourceRef::parse( - object - .get("resourceRef") - .and_then(Value::as_str) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; - let resource_generation = ResourceGeneration::new( - object - .get("resourceGeneration") - .and_then(Value::as_u64) - .ok_or(AssignmentTransportError::Malformed)?, - ) - .map_err(|_| AssignmentTransportError::Malformed)?; + let provider_ref = ResourceRef::parse(&envelope.provider_ref) + .map_err(|_| AssignmentTransportError::Malformed)?; + let assignment = envelope.assignment.into_identity()?; + let resource_ref = ResourceRef::parse(&envelope.resource_ref) + .map_err(|_| AssignmentTransportError::Malformed)?; + let resource_generation = ResourceGeneration::new(envelope.resource_generation) + .map_err(|_| AssignmentTransportError::Malformed)?; let resource_types = decode_string_set( - object - .get("resourceTypes") - .and_then(Value::as_array) - .ok_or(AssignmentTransportError::Malformed)?, + &envelope.resource_types, MAX_ASSIGNMENT_GRANT_RESOURCE_TYPES, |value| ResourceTypeName::parse(value).map_err(|_| AssignmentTransportError::Malformed), )?; let primary_verbs = decode_string_set( - object - .get("primaryVerbs") - .and_then(Value::as_array) - .ok_or(AssignmentTransportError::Malformed)?, + &envelope.primary_verbs, MAX_ASSIGNMENT_GRANT_VERBS, decode_assignment_verb, )?; - let owner_child_process_values = object - .get("ownerChildProcessVerbs") - .and_then(Value::as_array) - .ok_or(AssignmentTransportError::Malformed)?; - let owner_child_process_verbs = if owner_child_process_values.is_empty() { + let owner_child_process_verbs = if envelope.owner_child_process_verbs.is_empty() { BTreeSet::new() } else { decode_string_set( - owner_child_process_values, + &envelope.owner_child_process_verbs, MAX_ASSIGNMENT_GRANT_VERBS, decode_assignment_verb, )? }; let scopes = decode_string_set( - object - .get("scopes") - .and_then(Value::as_array) - .ok_or(AssignmentTransportError::Malformed)?, + &envelope.scopes, MAX_ASSIGNMENT_GRANT_SCOPES, decode_assignment_scope, )?; @@ -1988,13 +1948,15 @@ impl ControllerAssignmentGrant { if provider_ref.resource_type().as_str() != "Provider" { return Err(AssignmentTransportError::Malformed); } - let value = json!({ - "version": 1, - "kind": "revoke", - "providerRef": provider_ref.to_canonical_string(), - "assignment": encode_assignment(assignment), - }); - encode_bounded_json(&value, MAX_CONTROLLER_ASSIGNMENT_GRANT_BYTES) + encode_bounded_json( + &AssignmentRevocationEnvelope { + version: 1, + kind: "revoke".to_owned(), + provider_ref: provider_ref.to_canonical_string(), + assignment: AssignmentEnvelope::from_identity(assignment), + }, + MAX_CONTROLLER_ASSIGNMENT_GRANT_BYTES, + ) } } @@ -2015,7 +1977,7 @@ impl fmt::Debug for ControllerAssignmentGrant { } fn decode_string_set( - values: &[Value], + values: &[String], limit: usize, decode: impl Fn(&str) -> Result, ) -> Result, AssignmentTransportError> @@ -2028,7 +1990,6 @@ where let mut decoded = BTreeSet::new(); let mut previous = None; for value in values { - let value = value.as_str().ok_or(AssignmentTransportError::Malformed)?; let value = decode(value)?; if previous.as_ref().is_some_and(|previous| previous >= &value) || !decoded.insert(value) { return Err(AssignmentTransportError::Malformed); @@ -2297,29 +2258,19 @@ impl ControllerAssignmentGrantStore { } CanonicalJsonValue::parse(bytes) .map_err(|_| AssignmentGrantError::Transport(AssignmentTransportError::Malformed))?; - let value = serde_json::from_slice::(bytes) - .map_err(|_| AssignmentGrantError::Transport(AssignmentTransportError::Malformed))?; - let object = value.as_object().ok_or(AssignmentGrantError::Transport( - AssignmentTransportError::Malformed, - ))?; - if object.get("kind").and_then(Value::as_str) == Some("revoke") { - require_exact_keys(object, &["version", "kind", "providerRef", "assignment"]) - .map_err(AssignmentGrantError::Transport)?; - if object.get("version").and_then(Value::as_u64) != Some(1) { + if let Ok(revocation) = serde_json::from_slice::(bytes) { + if revocation.kind != "revoke" || revocation.version != 1 { return Err(AssignmentGrantError::Transport( AssignmentTransportError::Malformed, )); } - let provider_ref = ResourceRef::parse( - object.get("providerRef").and_then(Value::as_str).ok_or( - AssignmentGrantError::Transport(AssignmentTransportError::Malformed), - )?, - ) - .map_err(|_| AssignmentGrantError::Transport(AssignmentTransportError::Malformed))?; - let assignment = decode_assignment(object.get("assignment").ok_or( - AssignmentGrantError::Transport(AssignmentTransportError::Malformed), - )?) - .map_err(AssignmentGrantError::Transport)?; + let provider_ref = ResourceRef::parse(&revocation.provider_ref).map_err(|_| { + AssignmentGrantError::Transport(AssignmentTransportError::Malformed) + })?; + let assignment = revocation + .assignment + .into_identity() + .map_err(AssignmentGrantError::Transport)?; return self .revoke_assignment(&provider_ref, assignment) .map_err(AssignmentGrantError::Assignment); From dc145cf0c4ccadc4acf09d44dccaee9b53ad7309 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:27:34 -0700 Subject: [PATCH 592/726] refactor(d2b-contracts-control): trim published CLI-output surface Drop the zero-consumer StatusServicesOutputV3 type and its from_v2 shim; the migration guide now promises the V3 wire shape only at the emit-side flip, so tooling keeps parsing the V2 JSON until then. Drop the unused LevelPercent re-export (the type stays reachable via d2b_contracts). Narrow HelperSnapshot::validate and HelperLaunchRequest::validate_bounds to pub(crate); the helper's two launch paths validate workload identities through the existing validate_unsafe_local_resource_identity free fn, so wire behavior and serde admission are unchanged. --- .../w6-02-contracts-control-surface.md | 13 ++++ docs/how-to/migrate-d2b-v1-0-to-v1-1.md | 12 ++-- .../d2b-contracts-control/src/cli_output.rs | 67 ------------------- .../src/unsafe_local_wire.rs | 4 +- .../d2b-unsafe-local-helper/src/protocol.rs | 4 +- .../d2b-unsafe-local-helper/src/runtime.rs | 3 +- 6 files changed, 22 insertions(+), 81 deletions(-) create mode 100644 changelog.d/w6-02-contracts-control-surface.md diff --git a/changelog.d/w6-02-contracts-control-surface.md b/changelog.d/w6-02-contracts-control-surface.md new file mode 100644 index 000000000..6c9bc60d6 --- /dev/null +++ b/changelog.d/w6-02-contracts-control-surface.md @@ -0,0 +1,13 @@ +### Changed + +- The unpublished `StatusServicesOutputV3` type and its `from_v2` conversion + shim are removed from the d2b-contracts-control crate. The CLI still emits + the V2 status shape; the migration guide now promises the V3 type only at + the emit-side flip, so tooling keeps parsing V2 until then. +- `LevelPercent` is no longer re-exported from the CLI-output module; the + type remains available through `d2b_contracts`, the path the API docs pin. +- The helper wire types' `HelperSnapshot::validate` and + `HelperLaunchRequest::validate_bounds` are now crate-internal; the helper + validates workload identities through the existing + `validate_unsafe_local_resource_identity` function, so the wire behavior + and serde admission are unchanged. \ No newline at end of file diff --git a/docs/how-to/migrate-d2b-v1-0-to-v1-1.md b/docs/how-to/migrate-d2b-v1-0-to-v1-1.md index 364be593d..a7f32b8f3 100644 --- a/docs/how-to/migrate-d2b-v1-0-to-v1-1.md +++ b/docs/how-to/migrate-d2b-v1-0-to-v1-1.md @@ -209,19 +209,15 @@ tagline sweep (drop "on microvm.nix" from `flake.nix` / ## `d2b status` output schema (v1.0 vs v1.1 vs v1.1.1) -> **v1.1.1 status note**: v1.1.1 ships the `StatusOutputV3` wire -> schema (`packages/d2b/src/lib.rs` `StatusServicesOutputV3` -> + `from_v2` migration shim) per the rename map below. The CLI -> `d2b status` command still EMITS the v1.0/v1.1 -> `StatusServicesOutputV2` shape at v1.1.1; the emit-side -> flip to V3 is scheduled for v1.1.2. +> **v1.1.1 status note**: v1.1.1 keeps emitting the v1.0/v1.1 +> `StatusServicesOutputV2` shape. The V3 wire schema +> (`StatusServicesOutputV3`) ships with the emit-side flip, +> scheduled for v1.1.2, per the rename map below. > > Tooling authors that consume the JSON output should: > - At v1.1.1, continue parsing V2 (`microvm`/`snd`/`virtiofsd`). > - At v1.1.2+, parse V3 (`hypervisor`/`audio`/`virtiofsd_per_share`/...) > with the documented rename map below. -> - The `StatusServicesOutputV3::from_v2()` migration shim lives -> in the public surface so tooling can adopt incrementally. ### v1.1.1 SHIPPED → CLI-emit at v1.1.2 rename map diff --git a/packages/d2b-contracts-control/src/cli_output.rs b/packages/d2b-contracts-control/src/cli_output.rs index 7226a56c9..a67e77e78 100644 --- a/packages/d2b-contracts-control/src/cli_output.rs +++ b/packages/d2b-contracts-control/src/cli_output.rs @@ -3,8 +3,6 @@ use std::collections::BTreeMap; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -pub use d2b_contracts::audio::LevelPercent; - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(transparent)] /// `d2b vm list` output: one row per VM. @@ -258,71 +256,6 @@ pub struct StatusServicesOutputV2 { pub swtpm: Option, } -/// Per-VM service-state map (V3) -- broker-spawn-aware status output. -/// -/// All fields are optional so emitters can omit a role when the VM -/// doesn't enable it. The wire shape uses camelCase -/// + `deny_unknown_fields` to keep schema-drift gates honest. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct StatusServicesOutputV3 { - /// Cloud Hypervisor runner state (broker-spawned). - #[serde(skip_serializing_if = "Option::is_none")] - pub hypervisor: Option, - /// Per-share virtiofsd state, keyed by share `tag`. - #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] - pub virtiofsd_per_share: BTreeMap, - /// crosvm GPU sidecar state (broker-spawned). - #[serde(skip_serializing_if = "Option::is_none")] - pub gpu: Option, - /// vhost-device-sound audio sidecar state (broker-spawned). - #[serde(skip_serializing_if = "Option::is_none")] - pub audio: Option, - /// swtpm sidecar state (broker-spawned). - #[serde(skip_serializing_if = "Option::is_none")] - pub swtpm: Option, - /// Per-VM OtelGuestRelay state (broker-spawned). - #[serde(skip_serializing_if = "Option::is_none")] - pub otel_relay: Option, - /// Host-scoped OtelHostBridge state (broker-spawned). - #[serde(skip_serializing_if = "Option::is_none")] - pub otel_host_bridge: Option, - /// Per-env USBIP backend state, keyed by env name. - #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] - pub usbip_backend_per_env: BTreeMap, - /// Per-env USBIP proxy state, keyed by env name. - #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] - pub usbip_proxy_per_env: BTreeMap, -} - -impl StatusServicesOutputV3 { - /// Conversion shim: takes a V2 record and projects it into V3 - /// by applying the documented rename map. Used so callers - /// consuming the legacy V2 shape can be migrated incrementally - /// without breaking the bundle-resolver / status-output contract. - pub fn from_v2(v2: &StatusServicesOutputV2) -> Self { - let mut virtiofsd_per_share = BTreeMap::new(); - // V2 had a single `virtiofsd` slot; we expose it under the - // synthetic share tag `default` so the V3 consumer can read - // it without losing data. v1.1.2+ wire bumps populate the - // map per-share via the broker's per-share spawn records. - virtiofsd_per_share.insert("default".to_owned(), v2.virtiofsd.clone()); - Self { - hypervisor: Some(v2.microvm.clone()), - virtiofsd_per_share, - gpu: v2.gpu.clone(), - // V3 has no dedicated video field yet; keep V2 authoritative - // until a negotiated schema revision adds one. - audio: v2.snd.clone(), - swtpm: v2.swtpm.clone(), - otel_relay: None, - otel_host_bridge: None, - usbip_backend_per_env: BTreeMap::new(), - usbip_proxy_per_env: BTreeMap::new(), - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] /// Runner-parity evidence for one VM. diff --git a/packages/d2b-contracts-control/src/unsafe_local_wire.rs b/packages/d2b-contracts-control/src/unsafe_local_wire.rs index 58c8651ca..da2e78bba 100644 --- a/packages/d2b-contracts-control/src/unsafe_local_wire.rs +++ b/packages/d2b-contracts-control/src/unsafe_local_wire.rs @@ -131,7 +131,7 @@ impl HelperSnapshot { /// Returns [`HelperFailureCode::InvalidRequest`] when the generation is /// zero, the scope count exceeds the bound, or a workload identity is /// not a helper-owned resource type. - pub fn validate(&self) -> Result<(), HelperFailureCode> { + pub(crate) fn validate(&self) -> Result<(), HelperFailureCode> { if self.generation == 0 { return Err(HelperFailureCode::InvalidRequest); } @@ -204,7 +204,7 @@ impl HelperLaunchRequest { /// /// Returns [`HelperFailureCode::InvalidRequest`] when the workload is /// not a helper-owned resource type. - pub fn validate_bounds(&self) -> Result<(), HelperFailureCode> { + pub(crate) fn validate_bounds(&self) -> Result<(), HelperFailureCode> { validate_unsafe_local_resource_identity(&self.workload) } } diff --git a/packages/d2b-unsafe-local-helper/src/protocol.rs b/packages/d2b-unsafe-local-helper/src/protocol.rs index da1e4a151..632a781ef 100644 --- a/packages/d2b-unsafe-local-helper/src/protocol.rs +++ b/packages/d2b-unsafe-local-helper/src/protocol.rs @@ -7,7 +7,7 @@ use d2b_contracts_control::unsafe_local_wire::{ HelperHeartbeat, HelperHello, HelperOperationRejected, MAX_HELPER_FRAME_SIZE, MAX_HELPER_QUEUE_DEPTH, MIN_EFFECTIVE_HELPER_SOCKET_BUFFER_BYTES, UNSAFE_LOCAL_HELPER_PROTOCOL_VERSION, UnsafeLocalHelperToDaemon, - unsafe_local_helper_protocol_supported, + unsafe_local_helper_protocol_supported, validate_unsafe_local_resource_identity, }; use nix::cmsg_space; use nix::libc; @@ -154,7 +154,7 @@ impl HelperClient { )?; } DaemonToUnsafeLocalHelper::Launch(request) => { - if request.validate_bounds().is_err() { + if validate_unsafe_local_resource_identity(&request.workload).is_err() { let rejected = rejection( request.request_id, request.operation_id, diff --git a/packages/d2b-unsafe-local-helper/src/runtime.rs b/packages/d2b-unsafe-local-helper/src/runtime.rs index 6614ad9ea..ee29f187b 100644 --- a/packages/d2b-unsafe-local-helper/src/runtime.rs +++ b/packages/d2b-unsafe-local-helper/src/runtime.rs @@ -329,8 +329,7 @@ impl ScopeRuntime { &self, request: HelperLaunchRequest, ) -> Result { - request - .validate_bounds() + validate_unsafe_local_resource_identity(&request.workload) .map_err(|_| RuntimeError::InvalidRequest)?; let fingerprint = launch_fingerprint(&request)?; let reservation = match self From 1a6ca86e7183e101dd48b3817066defbc30b1af9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:28:57 -0700 Subject: [PATCH 593/726] fix(contracts-provider): emit distinct credential-already-running wire code CredentialControllerError::AlreadyRunning now renders credential-already-running instead of reusing the lease-ceiling code, and the lease-ceiling outcome (QueuePressure) now emits credential-queue-pressure in audit records and telemetry, matching ADR-046-resources-credential. The three ADR error-code tables gain the credential-already-running row. --- changelog.d/w6-04-credential-wire-outcome-codes.md | 8 ++++++++ docs/specs/ADR-046-resources-credential.md | 1 + .../ADR-046-provider-credential-managed-identity.md | 1 + .../ADR-046-provider-credential-secret-service.md | 1 + .../src/v3/credential_controller.rs | 8 ++++---- 5 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 changelog.d/w6-04-credential-wire-outcome-codes.md diff --git a/changelog.d/w6-04-credential-wire-outcome-codes.md b/changelog.d/w6-04-credential-wire-outcome-codes.md new file mode 100644 index 000000000..31e40f97d --- /dev/null +++ b/changelog.d/w6-04-credential-wire-outcome-codes.md @@ -0,0 +1,8 @@ +### Fixed + +- The Credential controller now emits the documented wire code + `credential-already-running` when the same Credential is already being + handled, instead of reusing the lease-ceiling code `credential-queue-pressure`. + The lease-ceiling outcome now emits its documented code + `credential-queue-pressure` in audit records and telemetry, matching the + closed outcome set in ADR-046-resources-credential. \ No newline at end of file diff --git a/docs/specs/ADR-046-resources-credential.md b/docs/specs/ADR-046-resources-credential.md index 12aa28bba..b9c5be25d 100644 --- a/docs/specs/ADR-046-resources-credential.md +++ b/docs/specs/ADR-046-resources-credential.md @@ -901,6 +901,7 @@ Stable Credential-specific error codes: | `credential-invariant-failure` | Provider returned a response failing invariant checks | | `credential-schema-invalid` | Spec field fails validation at create/update | | `credential-queue-pressure` | Provider lease table at capacity; retry after backpressure | +| `credential-already-running` | The same Credential is already being handled by this controller | All error messages are bounded (max 240 UTF-8 chars), stripped of control characters, and must not contain token bytes, URLs, UUIDs, provider diagnostics, diff --git a/docs/specs/providers/ADR-046-provider-credential-managed-identity.md b/docs/specs/providers/ADR-046-provider-credential-managed-identity.md index 181adc8e5..b1ecc258c 100644 --- a/docs/specs/providers/ADR-046-provider-credential-managed-identity.md +++ b/docs/specs/providers/ADR-046-provider-credential-managed-identity.md @@ -1282,6 +1282,7 @@ Stable closed error codes for this Provider: | `credential-invariant-failure` | IMDS response failed internal invariant checks (e.g. expiry in the past, malformed lease handle) | | `credential-schema-invalid` | `sign-challenge` operation class requested; or `spec.config` field fails validation | | `credential-queue-pressure` | Active lease count at `maxLeases` ceiling; retry after backpressure | +| `credential-already-running` | The same Credential is already being handled by this controller | All error messages: - maximum 240 UTF-8 bytes; diff --git a/docs/specs/providers/ADR-046-provider-credential-secret-service.md b/docs/specs/providers/ADR-046-provider-credential-secret-service.md index d1893b7ad..2be6c6cf7 100644 --- a/docs/specs/providers/ADR-046-provider-credential-secret-service.md +++ b/docs/specs/providers/ADR-046-provider-credential-secret-service.md @@ -997,6 +997,7 @@ status layer. | `credential-invariant-failure` | Port returned a response failing invariant checks | | `credential-schema-invalid` | `sign-challenge` requested (unsupported); or spec fails validation | | `credential-queue-pressure` | Lease table at capacity (`maxLeases`) | +| `credential-already-running` | The same Credential is already being handled by this controller | All error messages are bounded (max 240 UTF-8 chars), stripped of control characters, and must not contain token bytes, URLs, UUIDs, provider diagnostics, diff --git a/packages/d2b-contracts-provider/src/v3/credential_controller.rs b/packages/d2b-contracts-provider/src/v3/credential_controller.rs index 8f4cc0337..78dfe41cc 100644 --- a/packages/d2b-contracts-provider/src/v3/credential_controller.rs +++ b/packages/d2b-contracts-provider/src/v3/credential_controller.rs @@ -92,7 +92,7 @@ impl fmt::Display for CredentialControllerError { Self::InvalidInput => "credential-invariant-failure", Self::OperationDenied => "credential-operation-denied", Self::DeadlineExceeded => "deadline-exceeded", - Self::AlreadyRunning => "credential-queue-pressure", + Self::AlreadyRunning => "credential-already-running", }) } } @@ -1080,7 +1080,7 @@ impl CredentialAuditOutcome { Self::ProviderUnavailable => "provider-unavailable", Self::AlreadyRevoked => "already-revoked", Self::RotationFailed => "rotation-failed", - Self::QueuePressure => "queue-pressure", + Self::QueuePressure => "credential-queue-pressure", Self::InvariantFailure => "invariant-failure", } } @@ -1353,7 +1353,7 @@ impl CredentialTelemetryOutcome { Self::LeaseExpired => "lease-expired", Self::LeaseRevoked => "lease-revoked", Self::RotationFailed => "rotation-failed", - Self::QueuePressure => "queue-pressure", + Self::QueuePressure => "credential-queue-pressure", Self::InvariantFailure => "invariant-failure", } } @@ -1744,7 +1744,7 @@ fn allowed_telemetry_value(key: &str, value: &str) -> bool { | "lease-expired" | "lease-revoked" | "rotation-failed" - | "queue-pressure" + | "credential-queue-pressure" | "invariant-failure" ), "d2b.credential.rotation_generation" => { From 0330ae04b8e1c372f1f3672b0472c983b48220eb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:29:33 -0700 Subject: [PATCH 594/726] fix(d2b-unsafe-local-helper): report early-exit scope as scope-create-failed await_scope_identity mapped every scope that left the starting/active states to ScopeError::IdentityMismatch, so a process that died during startup surfaced as a security identity failure (wire code 70). The early-exit arm now returns ScopeError::CreateFailed, which the existing mapping chain carries to HelperFailureCode::ScopeCreateFailed (wire code 42). IdentityMismatch remains for identity-check failures only. Adds a regression test pinning the reclassification for stopping, exited, and degraded scopes. --- .../w6-05-scope-early-exit-reclassified.md | 8 +++++ .../d2b-unsafe-local-helper/src/systemd.rs | 36 ++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w6-05-scope-early-exit-reclassified.md diff --git a/changelog.d/w6-05-scope-early-exit-reclassified.md b/changelog.d/w6-05-scope-early-exit-reclassified.md new file mode 100644 index 000000000..795bfa479 --- /dev/null +++ b/changelog.d/w6-05-scope-early-exit-reclassified.md @@ -0,0 +1,8 @@ +### Fixed + +- The unsafe-local helper no longer reports a scope whose launched process + exited during startup (or that is stopping or degraded) as an identity + mismatch. Such early-exit scopes are now reported as + `unsafe-local-shell-scope-create-failed` (wire code 42) instead of + `unsafe-local-shell-scope-identity-mismatch` (wire code 70), so an + operational startup failure is not surfaced as a security identity failure. \ No newline at end of file diff --git a/packages/d2b-unsafe-local-helper/src/systemd.rs b/packages/d2b-unsafe-local-helper/src/systemd.rs index 3ecf38a6c..2e1a3de96 100644 --- a/packages/d2b-unsafe-local-helper/src/systemd.rs +++ b/packages/d2b-unsafe-local-helper/src/systemd.rs @@ -351,7 +351,12 @@ where loop { match query() { Ok((scope, HelperScopeState::Starting | HelperScopeState::Active)) => return Ok(scope), - Ok(_) => return Err(ScopeError::IdentityMismatch), + // The scope exists but already left the starting/active states + // (the launched process exited, is stopping, or is degraded): + // an operational early exit, not an identity failure. Reported + // as create-failed so the daemon classifies it as + // scope-create-failed instead of a security identity mismatch. + Ok(_) => return Err(ScopeError::CreateFailed), Err(ScopeError::NotFound | ScopeError::QueryFailed | ScopeError::IdentityMismatch) if Instant::now() < deadline => { @@ -441,6 +446,35 @@ mod tests { assert_eq!(attempts, 2); } + #[test] + fn early_exit_scope_reports_create_failed() { + let expected = VerifiedScope { + unit_name: "d2b-unsafe-local-app-test.scope".to_owned(), + invocation_id: "00112233445566778899aabbccddeeff".to_owned(), + control_group: + "/user.slice/user-1000.slice/[EMAIL]/app.slice/d2b-unsafe-local-app-test.scope" + .to_owned(), + kind: HelperScopeKind::LauncherApp, + }; + for state in [ + HelperScopeState::Stopping, + HelperScopeState::Exited, + HelperScopeState::Degraded, + ] { + let error = await_scope_identity( + || Ok((expected.clone(), state)), + Duration::from_millis(50), + Duration::ZERO, + ) + .unwrap_err(); + assert_eq!( + error, + ScopeError::CreateFailed, + "an early-exit scope must not be reported as an identity mismatch" + ); + } + } + #[test] fn dbus_method_timeouts_remain_typed() { let error = zbus::Error::InputOutput(std::sync::Arc::new(std::io::Error::new( From 14bf42022324910b20b1fe1104627f112c68323e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:29:43 -0700 Subject: [PATCH 595/726] refactor(d2b-provider-wayland-policy): type driver-args zone as ZoneId and make key_ref total The driver-args zone class (RS-0962/RS-0516/RS-0515) now carries the zone as a validated ZoneId through the interaction, volume-binding, guest, and shared-provider families; the daemon boundary passes the parsed value once and the per-pass parse-expects are gone. The wayland-policy key_ref helper returns a typed SpecInvalid Result, and the never-read VolumeDriverArgs zone field (RS-0420) is removed. --- changelog.d/w5-01-driver-args-zone-typed.md | 6 ++ .../src/audio_binding.rs | 3 +- .../tests/registration.rs | 2 +- .../tests/registration.rs | 4 +- .../tests/registration.rs | 4 +- .../src/shell_session.rs | 4 +- .../tests/registration.rs | 2 +- .../d2b-provider-volume-binding/src/driver.rs | 39 ++++---- .../tests/registration.rs | 3 +- packages/d2b-provider-volume/src/driver.rs | 8 +- .../d2b-provider-volume/tests/registration.rs | 1 - .../src/effects_service.rs | 25 ++++-- .../src/interaction.rs | 90 ++++++------------- .../tests/engine.rs | 33 +++---- .../tests/registration.rs | 4 +- .../src/wayland_session.rs | 3 +- .../tests/registration.rs | 2 +- packages/d2bd/src/resource_plane_v3.rs | 5 +- 18 files changed, 104 insertions(+), 134 deletions(-) create mode 100644 changelog.d/w5-01-driver-args-zone-typed.md diff --git a/changelog.d/w5-01-driver-args-zone-typed.md b/changelog.d/w5-01-driver-args-zone-typed.md new file mode 100644 index 000000000..4c6bd5804 --- /dev/null +++ b/changelog.d/w5-01-driver-args-zone-typed.md @@ -0,0 +1,6 @@ +### Fixed + +- Driver args across the interaction, volume-binding, guest, and shared-provider families now carry the zone as a validated `ZoneId` instead of a bare string re-parsed with `expect` at construction; the daemon boundary passes the parsed value once. +- The wayland-policy `key_ref` helper now returns a typed `Result` (SpecInvalid refusal) instead of panicking on a non-canonical manager key; the malformed-zone constructor refusal arm is gone because the zone arrives pre-validated. +- The volume-binding driver derives its socket-identity bounded token once at construction instead of re-parsing the zone with `expect` on every pass. +- Removed the never-read `zone` field from `VolumeDriverArgs`; construction sites and fixtures no longer carry it. \ No newline at end of file diff --git a/packages/d2b-provider-audio-binding/src/audio_binding.rs b/packages/d2b-provider-audio-binding/src/audio_binding.rs index 4c90cc6e8..9fc0ee787 100644 --- a/packages/d2b-provider-audio-binding/src/audio_binding.rs +++ b/packages/d2b-provider-audio-binding/src/audio_binding.rs @@ -160,7 +160,8 @@ impl InteractionType for AudioBinding { envelope: &InteractionSpecEnvelope, ) -> Result, InteractionEffectError> { let spec = envelope.spec_with_provider_ref::()?; - let binding_ref = d2b_provider_wayland_policy::interaction::key_ref(children.key); + let binding_ref = d2b_provider_wayland_policy::interaction::key_ref(children.key) + .map_err(|_| InteractionEffectError::InvalidResource)?; self.children .binding_children(&AudioBindingChildRequest { zone: children.zone, diff --git a/packages/d2b-provider-audio-binding/tests/registration.rs b/packages/d2b-provider-audio-binding/tests/registration.rs index 7e2498a04..884f7276f 100644 --- a/packages/d2b-provider-audio-binding/tests/registration.rs +++ b/packages/d2b-provider-audio-binding/tests/registration.rs @@ -66,7 +66,7 @@ impl AudioBindingChildSource for ProviderChildren { fn descriptor() -> d2b_resource_types::DriverDescriptor { audio_binding_descriptor(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), effects: Arc::new(UnusedEffects), behavior: AudioBinding::new(Arc::new(ProviderChildren)), diff --git a/packages/d2b-provider-audio-service/tests/registration.rs b/packages/d2b-provider-audio-service/tests/registration.rs index f7b957450..d3f2a3e82 100644 --- a/packages/d2b-provider-audio-service/tests/registration.rs +++ b/packages/d2b-provider-audio-service/tests/registration.rs @@ -3,7 +3,7 @@ use std::sync::Arc; -use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef}; +use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ZoneId}; use d2b_provider_audio_pipewire::AudioServiceSpec; use d2b_provider_audio_service::{ AudioService, audio_service_descriptor, audio_service_spec_decoder, @@ -43,7 +43,7 @@ impl InteractionDriverEffects for UnusedEffects { fn descriptor() -> d2b_resource_types::DriverDescriptor { audio_service_descriptor(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), effects: Arc::new(UnusedEffects), behavior: AudioService, diff --git a/packages/d2b-provider-shell-pool/tests/registration.rs b/packages/d2b-provider-shell-pool/tests/registration.rs index db9adceb6..508a1c5ad 100644 --- a/packages/d2b-provider-shell-pool/tests/registration.rs +++ b/packages/d2b-provider-shell-pool/tests/registration.rs @@ -3,7 +3,7 @@ use std::sync::Arc; -use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef}; +use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ZoneId}; use d2b_provider_shell_pool::{ SHELL_POOL_TYPE, ShellPool, shell_pool_descriptor, shell_pool_spec_decoder, }; @@ -42,7 +42,7 @@ impl InteractionDriverEffects for UnusedEffects { fn descriptor() -> d2b_resource_types::DriverDescriptor { shell_pool_descriptor(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), effects: Arc::new(UnusedEffects), behavior: ShellPool, diff --git a/packages/d2b-provider-shell-session/src/shell_session.rs b/packages/d2b-provider-shell-session/src/shell_session.rs index 2b6b22992..65389b949 100644 --- a/packages/d2b-provider-shell-session/src/shell_session.rs +++ b/packages/d2b-provider-shell-session/src/shell_session.rs @@ -118,7 +118,9 @@ impl InteractionType for ShellSession { name: process_ref.name().as_str().to_owned(), spec: serde_json::to_vec(&process_spec).map_err(|_| invalid())?, metadata: serde_json::to_vec(&json!({ - "ownerRef": key_ref(children.key).to_canonical_string(), + "ownerRef": key_ref(children.key) + .map_err(|_| invalid())? + .to_canonical_string(), "labels": {}, "annotations": {}, })) diff --git a/packages/d2b-provider-shell-session/tests/registration.rs b/packages/d2b-provider-shell-session/tests/registration.rs index bd8997312..f34685a50 100644 --- a/packages/d2b-provider-shell-session/tests/registration.rs +++ b/packages/d2b-provider-shell-session/tests/registration.rs @@ -44,7 +44,7 @@ impl InteractionDriverEffects for UnusedEffects { fn descriptor() -> d2b_resource_types::DriverDescriptor { shell_session_descriptor(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), effects: Arc::new(UnusedEffects), behavior: ShellSession, diff --git a/packages/d2b-provider-volume-binding/src/driver.rs b/packages/d2b-provider-volume-binding/src/driver.rs index cc5ea96f6..bf4708595 100644 --- a/packages/d2b-provider-volume-binding/src/driver.rs +++ b/packages/d2b-provider-volume-binding/src/driver.rs @@ -46,7 +46,7 @@ use std::sync::Arc; use std::time::Duration; use d2b_contracts_resource::v3::{ - ResourceRef, ResourceSpec, ResourceUid, + ResourceRef, ResourceSpec, ResourceUid, ZoneId, volume::{VolumeSpec, ViewSpec}, volume_binding::VolumeBindingSpec, }; @@ -354,7 +354,7 @@ pub trait BindingDriverEffects: Send + Sync + 'static { /// from the spec store). pub struct BindingDriverArgs { /// The zone this driver's rows live in. - pub zone: String, + pub zone: ZoneId, /// The daemon-supplied facet set the family's effects are built from /// (R2): the serving-socket probe, the socket removal, and the /// guest-mount observation. The family never receives a daemon-built @@ -406,7 +406,11 @@ impl ResourceDriverFactory for BindingDriverFactory { /// One VolumeBinding resource's driver. #[derive(Clone)] pub(crate) struct BindingDriver { - zone: String, + zone: ZoneId, + /// The zone as a bounded token (the socket identity namespace), derived + /// once at construction: every ZoneId is a valid bounded token, so the + /// coercion cannot fail. + zone_bounded: d2b_contracts_resource::v3::execution_policy::BoundedToken, effects: Arc, vcpu_count: u32, /// Targets this driver already registered a dependency watch on @@ -418,11 +422,15 @@ pub(crate) struct BindingDriver { impl BindingDriver { pub(crate) fn new( - zone: String, + zone: ZoneId, effects: Arc, vcpu_count: u32, ) -> Self { Self { + zone_bounded: d2b_contracts_resource::v3::execution_policy::BoundedToken::parse( + zone.as_str(), + ) + .expect("zone names are bounded tokens"), zone, effects, vcpu_count, @@ -435,9 +443,8 @@ impl BindingDriver { } /// The zone as a bounded token (the socket identity namespace). - fn zone_bounded(&self) -> d2b_contracts_resource::v3::execution_policy::BoundedToken { - d2b_contracts_resource::v3::execution_policy::BoundedToken::parse(self.zone.clone()) - .expect("zone name is a bounded token") + fn zone_bounded(&self) -> &d2b_contracts_resource::v3::execution_policy::BoundedToken { + &self.zone_bounded } /// Decode the stored envelope into the strict neutral binding contract. @@ -474,7 +481,7 @@ impl BindingDriver { /// The key of the parent Volume this binding declares. fn parent_volume_key(&self, binding: &VolumeBindingSpec) -> ResourceKey { - ResourceKey::new(&self.zone, "Volume", binding.volume_ref().name().as_str()) + ResourceKey::new(self.zone.as_str(), "Volume", binding.volume_ref().name().as_str()) } /// The parent Volume row through the manager (R2: the driver never @@ -627,8 +634,8 @@ impl BindingDriver { .endpoint_ref() .map_err(|_| self.error(BindingDriverErrorKind::PlanDerivation, op))?; Ok([ - ResourceKey::new(&self.zone, WORKER_TYPE, worker.name().as_str()), - ResourceKey::new(&self.zone, ENDPOINT_TYPE, endpoint.name().as_str()), + ResourceKey::new(self.zone.as_str(), WORKER_TYPE, worker.name().as_str()), + ResourceKey::new(self.zone.as_str(), ENDPOINT_TYPE, endpoint.name().as_str()), ]) } @@ -876,7 +883,7 @@ impl ResourceDriver for BindingDriver { let children_current = desired .iter() .all(|key| owned.iter().any(|row| row.key == *key && !row.deleting)); - let socket = stored.socket_identity(&self.zone_bounded()); + let socket = stored.socket_identity(self.zone_bounded()); let socket_ready = self.effects.socket_ready(&socket).await; if children_current && socket_ready { ctx.set_status(BindingDriverStatus::RecoveredPlan { @@ -920,7 +927,7 @@ impl ResourceDriver for BindingDriver { // Readiness is child-phase driven: the worker socket is the serving // evidence and the guest mount the consumer-side one; both // fail closed when the port cannot observe them. - let socket = stored.socket_identity(&self.zone_bounded()); + let socket = stored.socket_identity(self.zone_bounded()); let socket_ready = self.effects.socket_ready(&socket).await; let mount_ready = self .effects @@ -1023,7 +1030,7 @@ impl ResourceDriver for BindingDriver { ctx.delete(&endpoint) .await .map_err(|_| self.error(BindingDriverErrorKind::ChildMutation, op))?; - let socket = stored.socket_identity(&self.zone_bounded()); + let socket = stored.socket_identity(self.zone_bounded()); self.effects .remove_socket(&socket) .await @@ -1122,7 +1129,7 @@ mod tests { use std::sync::Arc; use d2b_contracts_resource::v3::{ - ResourceGeneration, ResourceUid, ZoneRevision, + ResourceGeneration, ResourceUid, ZoneId, ZoneRevision, resource_status::StatusCode, volume_binding::{VolumeBindingReadinessFence, VolumeBindingStatusResource}, }; @@ -1452,7 +1459,7 @@ mod tests { async fn driver(effects: Arc) -> Box { let factory = BindingDriverFactory::new(BindingDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), facets: effects.facet_set(), vcpu_count: 4, }); @@ -1467,7 +1474,7 @@ mod tests { #[tokio::test] async fn factory_registers_only_the_binding_resource_type() { let factory = BindingDriverFactory::new(BindingDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), facets: FakeServingEffects::new().facet_set(), vcpu_count: 4, }); diff --git a/packages/d2b-provider-volume-binding/tests/registration.rs b/packages/d2b-provider-volume-binding/tests/registration.rs index 61ac54752..7bf7730ab 100644 --- a/packages/d2b-provider-volume-binding/tests/registration.rs +++ b/packages/d2b-provider-volume-binding/tests/registration.rs @@ -2,6 +2,7 @@ //! the plane registers, and the registry serves this type's decoder and //! factory from it. +use d2b_contracts_resource::v3::ZoneId; use d2b_provider_volume_binding::{ BINDING_CREATIONS, BINDING_EFFECTS_SERVICE, BINDING_TYPE_NAME, BindingDriverArgs, binding_descriptor, @@ -13,7 +14,7 @@ use d2b_resource_types::{AllowedSources, ChildCustody, WellKnownType}; fn descriptor() -> d2b_resource_types::DriverDescriptor { binding_descriptor(BindingDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), facets: FakeServingEffects::new().facet_set(), vcpu_count: 1, }) diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index 7ee597ac4..e0ae4ba98 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -243,11 +243,8 @@ pub trait VolumeDriverEffects: Send + Sync + 'static { // --------------------------------------------------------------------------- /// Everything the plane must construct to instantiate the Volume driver -/// factory for one zone: the declared facet set the effects run over plus -/// the zone identity every derived row folds in (U7). +/// factory for one zone: the declared facet set the effects run over (U7). pub struct VolumeDriverArgs { - /// The zone this driver's rows live in. - pub zone: String, /// The daemon-supplied facet set the family's effects implementation is /// built from. The composition supplies the objects; the driver never /// holds a daemon state type and no externally built port appears here @@ -279,7 +276,6 @@ impl ResourceDriverFactory for VolumeDriverFactory { async fn create(&self, _key: &ResourceKey) -> Box { Box::new(VolumeDriver::new(VolumeDriverArgs { - zone: self.args.zone.clone(), facets: self.args.facets.clone(), })) } @@ -981,7 +977,6 @@ mod tests { async fn driver(runtime: Arc) -> Box { let factory = VolumeDriverFactory::new(VolumeDriverArgs { - zone: "work".to_owned(), facets: recording_facets(runtime), }); factory @@ -1011,7 +1006,6 @@ mod tests { #[tokio::test] async fn factory_registers_only_the_volume_resource_type() { let factory = VolumeDriverFactory::new(VolumeDriverArgs { - zone: "work".to_owned(), facets: recording_facets(RecordingRuntime::new()), }); assert_eq!(factory.resource_types().len(), 1); diff --git a/packages/d2b-provider-volume/tests/registration.rs b/packages/d2b-provider-volume/tests/registration.rs index ecdc092ee..de131f760 100644 --- a/packages/d2b-provider-volume/tests/registration.rs +++ b/packages/d2b-provider-volume/tests/registration.rs @@ -22,7 +22,6 @@ fn unused_facets() -> d2b_provider_volume::VolumeEffectFacets { fn descriptor() -> d2b_resource_types::DriverDescriptor { volume_descriptor(VolumeDriverArgs { - zone: "work".to_owned(), facets: unused_facets(), }) } diff --git a/packages/d2b-provider-wayland-policy/src/effects_service.rs b/packages/d2b-provider-wayland-policy/src/effects_service.rs index c96c1cba9..f0f41111a 100644 --- a/packages/d2b-provider-wayland-policy/src/effects_service.rs +++ b/packages/d2b-provider-wayland-policy/src/effects_service.rs @@ -210,7 +210,8 @@ impl InteractionEffectsService { .identity() .await .ok_or(InteractionEffectError::Unavailable)?; - let session_ref = key_ref(&request.target); + let session_ref = key_ref(&request.target) + .map_err(|_| InteractionEffectError::InvalidResource)?; if identity.wayland_session_ref != session_ref || identity.wayland_session_uid != request.uid || identity.subject_ref != *spec.guest_ref() @@ -258,7 +259,9 @@ impl InteractionEffectsService { &self, request: &InteractionEffectRequest<'_>, ) -> Result { - let Some(target) = self.live_stored(&key_ref(&request.target)).await? else { + let target_ref = key_ref(&request.target) + .map_err(|_| InteractionEffectError::InvalidResource)?; + let Some(target) = self.live_stored(&target_ref).await? else { return Err(InteractionEffectError::Unavailable); }; self.facets @@ -278,7 +281,9 @@ impl InteractionEffectsService { serde_json::from_value(spec) .map_err(|error| InteractionEffectError::InvalidSpec(error.to_string())) })?; - let Some(target) = self.live_stored(&key_ref(&request.target)).await? else { + let target_ref = key_ref(&request.target) + .map_err(|_| InteractionEffectError::InvalidResource)?; + let Some(target) = self.live_stored(&target_ref).await? else { return Err(InteractionEffectError::Unavailable); }; let Some(service) = self.fresh_audio_dependency(&spec.service_ref).await? else { @@ -310,7 +315,7 @@ impl InteractionEffectsService { .map_err(map_audio_effect_error)? .ok_or(InteractionEffectError::InvalidResource)?; let children = AudioBindingController::>::child_resources( - &key_ref(&request.target), + &key_ref(&request.target).map_err(|_| InteractionEffectError::InvalidResource)?, &spec, ) .map_err(|_| InteractionEffectError::InvalidResource)?; @@ -436,7 +441,9 @@ impl InteractionDriverEffects for InteractionEffectsService { // references it (old `finalize_u9`): the owner stays with its // durable deleting mark and the pass retries. InteractionKind::AudioService => { - let target = key_ref(&request.target).to_canonical_string(); + let target = key_ref(&request.target) + .map_err(|_| InteractionEffectError::InvalidResource)? + .to_canonical_string(); let dangling = self.specs_of_type(AUDIO_BINDING_TYPE).await?.iter().any( |binding| { binding.pointer("/serviceRef").and_then(Value::as_str) @@ -450,7 +457,9 @@ impl InteractionDriverEffects for InteractionEffectsService { }) } InteractionKind::AudioBinding => { - let Some(target) = self.live_stored(&key_ref(&request.target)).await? else { + let target_ref = key_ref(&request.target) + .map_err(|_| InteractionEffectError::InvalidResource)?; + let Some(target) = self.live_stored(&target_ref).await? else { return Ok(InteractionFinalize::Complete); }; self.facets @@ -463,7 +472,9 @@ impl InteractionDriverEffects for InteractionEffectsService { // A ShellPool refuses to go away while a Session still // references it (old `finalize_u9`). InteractionKind::ShellPool => { - let target = key_ref(&request.target).to_canonical_string(); + let target = key_ref(&request.target) + .map_err(|_| InteractionEffectError::InvalidResource)? + .to_canonical_string(); let dangling = self .specs_of_type("shell-terminal.d2bus.org.ShellSession") .await? diff --git a/packages/d2b-provider-wayland-policy/src/interaction.rs b/packages/d2b-provider-wayland-policy/src/interaction.rs index 30634f754..e86fb6f6c 100644 --- a/packages/d2b-provider-wayland-policy/src/interaction.rs +++ b/packages/d2b-provider-wayland-policy/src/interaction.rs @@ -428,7 +428,7 @@ pub trait InteractionType: Clone + Send + Sync + 'static { #[derive(Clone)] pub struct InteractionDriverArgs { /// The driver's Zone. - pub zone: String, + pub zone: ZoneId, /// The controller generation every effect call binds. pub controller_generation: ControllerGeneration, /// The Provider effect port the daemon implements. @@ -471,48 +471,7 @@ impl ResourceDriverFactory for InteractionDriverFactory { } async fn create(&self, _key: &ResourceKey) -> Box { - match InteractionDriver::new(self.args.clone()) { - Ok(driver) => Box::new(driver), - Err(error) => Box::new(RefusedInteractionDriver { error }), - } - } -} - -/// One driver that refuses every verb with a construction-time refusal. -/// -/// The daemon validates the zone at plane construction, so `create` never -/// sees a malformed zone in production; this arm keeps the factory -/// infallible (R3) while the typed refusal surfaces through the actor's -/// first verb instead of panicking. -struct RefusedInteractionDriver { - error: InteractionDriverError, -} - -#[async_trait] -impl ResourceDriver for RefusedInteractionDriver { - type Error = InteractionDriverError; - - fn classify_error(&self, error: &InteractionDriverError) -> DriverFailure { - classify_interaction_error(error) - } - - async fn validate(&mut self, _ctx: &mut ResourceContext) -> Result<(), Self::Error> { - Err(self.error) - } - - async fn recover(&mut self, _ctx: &mut ResourceContext) -> Result { - Err(self.error) - } - - async fn reconcile( - &mut self, - _ctx: &mut ResourceContext, - ) -> Result { - Err(self.error) - } - - async fn delete(&mut self, _ctx: &mut ResourceContext) -> Result<(), Self::Error> { - Err(self.error) + Box::new(InteractionDriver::new(self.args.clone())) } } @@ -537,24 +496,16 @@ pub struct InteractionDriver { impl InteractionDriver { /// Build the driver for its declared type. /// - /// The zone token is parsed once at this boundary; a malformed token is - /// refused as a terminal [`InteractionDriverError`] instead of panicking. - /// - /// # Errors - /// - /// Returns the `SpecInvalid` refusal when `args.zone` is not a valid - /// [`ZoneId`]. - pub fn new(args: InteractionDriverArgs) -> Result { - let zone = ZoneId::parse(args.zone).map_err(|_| { - InteractionDriverError::new(InteractionDriverErrorKind::SpecInvalid, DriverOp::Validate) - })?; - Ok(Self { - zone, + /// The zone arrives as a validated [`ZoneId`] from the daemon + /// construction boundary, so construction is infallible. + pub fn new(args: InteractionDriverArgs) -> Self { + Self { + zone: args.zone, controller_generation: args.controller_generation, effects: args.effects, behavior: args.behavior, watched: Vec::new(), - }) + } } fn error(&self, kind: InteractionDriverErrorKind, op: DriverOp) -> InteractionDriverError { @@ -674,7 +625,7 @@ impl InteractionDriver { .children() .await .map_err(|_| self.error(InteractionDriverErrorKind::ChildMutation, op))?; - Ok(owned + owned .iter() .filter(|row| { !row.deleting @@ -682,11 +633,14 @@ impl InteractionDriver { child.type_name.as_str() == row.key.type_name && child.name == row.key.name }) }) - .map(|row| InteractionChild { - resource_ref: key_ref(&row.key), - generation: row.generation, + .map(|row| { + Ok(InteractionChild { + resource_ref: key_ref(&row.key) + .map_err(|_| self.error(InteractionDriverErrorKind::SpecInvalid, op))?, + generation: row.generation, + }) }) - .collect()) + .collect::, InteractionDriverError>>() } fn effect_error(&self, error: InteractionEffectError, op: DriverOp) -> InteractionDriverError { @@ -892,9 +846,15 @@ impl ResourceDriver for InteractionDriver { } /// The resource reference of one manager key. -pub fn key_ref(key: &ResourceKey) -> ResourceRef { - ResourceRef::parse(&format!("{}/{}", key.type_name, key.name)) - .expect("manager keys carry canonical resource references") +/// +/// # Errors +/// +/// Returns the `SpecInvalid` refusal when the key does not carry a +/// canonical resource reference. +pub fn key_ref(key: &ResourceKey) -> Result { + ResourceRef::parse(&format!("{}/{}", key.type_name, key.name)).map_err(|_| { + InteractionDriverError::new(InteractionDriverErrorKind::SpecInvalid, DriverOp::Validate) + }) } /// Convert one durable 16-byte uid to its canonical identity (the manager diff --git a/packages/d2b-provider-wayland-policy/tests/engine.rs b/packages/d2b-provider-wayland-policy/tests/engine.rs index 4cbb92cb6..e07f5e960 100644 --- a/packages/d2b-provider-wayland-policy/tests/engine.rs +++ b/packages/d2b-provider-wayland-policy/tests/engine.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; -use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef}; +use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ZoneId}; use d2b_provider_wayland_policy::{ InteractionChildContext, InteractionDriver, InteractionDriverArgs, InteractionDriverEffects, InteractionDriverStatus, InteractionEffectError, InteractionKind, InteractionSpecEnvelope, @@ -263,12 +263,11 @@ fn build_fixture( notify_tx, ); let driver = InteractionDriver::new(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).unwrap(), effects: Arc::clone(&effects) as Arc, behavior: TestType { valid }, - }) - .expect("driver"); + }); ( Fixture { ctx, @@ -322,7 +321,7 @@ fn the_factory_serves_only_its_declared_type() { let effects = ScriptedEffects::shared(Arc::new(tokio::sync::Mutex::new(Vec::new()))); let factory = d2b_provider_wayland_policy::InteractionDriverFactory::new( InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).unwrap(), effects, behavior: TestType { valid: true }, @@ -336,21 +335,6 @@ fn the_factory_serves_only_its_declared_type() { assert_eq!(served, vec!["test.d2bus.org.Row".to_owned()]); } -/// A malformed zone token is refused at the driver boundary instead of -/// panicking. -#[test] -fn the_driver_refuses_a_malformed_zone_token() { - let effects = ScriptedEffects::shared(Arc::new(tokio::sync::Mutex::new(Vec::new()))); - let refusal = InteractionDriver::new(InteractionDriverArgs { - zone: "not a zone token".to_owned(), - controller_generation: ControllerGeneration::new(3).unwrap(), - effects: Arc::clone(&effects) as Arc, - behavior: TestType { valid: true }, - }) - .expect_err("a malformed zone token is a typed refusal, not a panic"); - assert_eq!(refusal.to_string(), "interaction-spec-invalid"); -} - // -- validate --------------------------------------------------------------- #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -629,7 +613,7 @@ fn the_driver_registers_the_declared_type_with_the_registry() { let effects = ScriptedEffects::shared(Arc::new(tokio::sync::Mutex::new(Vec::new()))); let descriptor = d2b_provider_wayland_policy::wayland_policy_descriptor(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).unwrap(), effects, behavior: d2b_provider_wayland_policy::WaylandPolicy, @@ -643,5 +627,10 @@ fn the_driver_registers_the_declared_type_with_the_registry() { .decoders() .contains_key(&ResourceTypeName::new("display-wayland.d2bus.org.WaylandPolicy")) ); - assert_eq!(key_ref(&row().key).to_canonical_string(), "test.d2bus.org.Row/row"); + assert_eq!( + key_ref(&row().key) + .expect("canonical test key") + .to_canonical_string(), + "test.d2bus.org.Row/row" + ); } diff --git a/packages/d2b-provider-wayland-policy/tests/registration.rs b/packages/d2b-provider-wayland-policy/tests/registration.rs index 456cdbec9..757c90aa1 100644 --- a/packages/d2b-provider-wayland-policy/tests/registration.rs +++ b/packages/d2b-provider-wayland-policy/tests/registration.rs @@ -2,7 +2,7 @@ //! plane registers, and the registry serves this type's decoder and factory //! from it. -use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef}; +use d2b_contracts_resource::v3::{ControllerGeneration, ResourceRef, ZoneId}; use d2b_provider_wayland_policy::{ InteractionDriverArgs, InteractionSpecEnvelope, InteractionType, WAYLAND_POLICY_PROVIDER_REF, WAYLAND_POLICY_RESYNC, WAYLAND_POLICY_TYPE, WaylandPolicy, @@ -15,7 +15,7 @@ use d2b_resource_types::{AllowedSources, WellKnownType}; fn descriptor() -> d2b_resource_types::DriverDescriptor { wayland_policy_descriptor(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), effects: ScriptedEffects::new(), behavior: WaylandPolicy, diff --git a/packages/d2b-provider-wayland-session/src/wayland_session.rs b/packages/d2b-provider-wayland-session/src/wayland_session.rs index 64d92ac37..4361f13e8 100644 --- a/packages/d2b-provider-wayland-session/src/wayland_session.rs +++ b/packages/d2b-provider-wayland-session/src/wayland_session.rs @@ -156,7 +156,8 @@ impl InteractionType for WaylandSession { envelope: &InteractionSpecEnvelope, ) -> Result, InteractionEffectError> { let spec = envelope.base_spec::()?; - let session_ref = key_ref(children.key); + let session_ref = key_ref(children.key) + .map_err(|_| InteractionEffectError::InvalidResource)?; let session_uid = resource_uid(children.uid) .ok_or(InteractionEffectError::InvalidResource)?; let intents = self.children.display_children(&DisplayChildRequest { diff --git a/packages/d2b-provider-wayland-session/tests/registration.rs b/packages/d2b-provider-wayland-session/tests/registration.rs index 4dc05d217..2736cf673 100644 --- a/packages/d2b-provider-wayland-session/tests/registration.rs +++ b/packages/d2b-provider-wayland-session/tests/registration.rs @@ -82,7 +82,7 @@ fn intent(target: &str, spec: Value) -> OwnedChildIntent { fn descriptor() -> d2b_resource_types::DriverDescriptor { wayland_session_descriptor(InteractionDriverArgs { - zone: "work".to_owned(), + zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), effects: Arc::new(UnusedEffects), behavior: WaylandSession::new(Arc::new(TwoWorkers)), diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 69070e8fd..461fdcb03 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -176,7 +176,7 @@ fn interaction_driver_args( behavior: T, ) -> InteractionDriverArgs { InteractionDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), controller_generation: inputs.authority.controller_generation, effects: Arc::new(InteractionEffectsService::new( inputs.interaction_facets.clone(), @@ -2935,7 +2935,7 @@ impl ResourcePlaneV3 { // from the daemon-supplied facet set; no externally built port // appears at this construction site (R2). "volume-binding" => vec![binding_descriptor(BindingDriverArgs { - zone: inputs.zone.as_str().to_owned(), + zone: inputs.zone.clone(), facets: inputs.binding_facets.clone(), vcpu_count: inputs.authority.vcpu_count, })], @@ -2957,7 +2957,6 @@ impl ResourcePlaneV3 { // The Volume family (U7): the driver builds its effects from the // declared facets; no externally built port appears here (R2). "volume" => vec![volume_descriptor(VolumeDriverArgs { - zone: inputs.zone.as_str().to_owned(), facets: inputs.volume_facets.clone(), })], _ => Vec::new(), From fd5b41b4b7c3230a1969f43da4baa2c995141743 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:30:21 -0700 Subject: [PATCH 596/726] refactor(d2b-broker): type the usbip lock and guest socket error surfaces UsbipLockError::Io carries the source io::Error instead of a flattened string, and a lock path with no parent directory is its own PathSafetyViolation variant; Display output is unchanged. acquire_lock drops the unused daemon_uid parameter. guest_socket_directory returns a typed GuestSocketError whose Display keeps the stable static-code spellings. --- .../w6-03-usbip-lock-error-taxonomy.md | 13 +++ packages/d2b-broker/src/live_handlers.rs | 14 +-- packages/d2b-broker/src/ops/device_worker.rs | 34 +++++- packages/d2b-broker/src/ops/usbip_lock.rs | 100 ++++++++++-------- packages/d2b-broker/src/runtime.rs | 8 -- 5 files changed, 99 insertions(+), 70 deletions(-) create mode 100644 changelog.d/w6-03-usbip-lock-error-taxonomy.md diff --git a/changelog.d/w6-03-usbip-lock-error-taxonomy.md b/changelog.d/w6-03-usbip-lock-error-taxonomy.md new file mode 100644 index 000000000..c2113a896 --- /dev/null +++ b/changelog.d/w6-03-usbip-lock-error-taxonomy.md @@ -0,0 +1,13 @@ +### Changed + +- d2b-broker: the USBIP busid lock error taxonomy no longer flattens + `io::Error` into a string. `UsbipLockError::Io` now carries the source + `io::Error` (`#[source]`), and a lock path with no parent directory is + reported as its own `PathSafetyViolation` variant. The rendered refusal + text is unchanged, so the broker error envelope is byte-identical. +- d2b-broker: `acquire_lock` drops its unused `daemon_uid` parameter; the + lock record keeps using the broker's own uid and the daemon gid. +- d2b-broker: `guest_socket_directory` returns a typed `GuestSocketError` + instead of a `&'static str` code, with the same stable refusal strings + ("not-a-plain-name", "not-anchored", "outside-runtime-root") surfaced + through the launch-failure envelope. \ No newline at end of file diff --git a/packages/d2b-broker/src/live_handlers.rs b/packages/d2b-broker/src/live_handlers.rs index 943b37545..891b819ba 100644 --- a/packages/d2b-broker/src/live_handlers.rs +++ b/packages/d2b-broker/src/live_handlers.rs @@ -461,10 +461,9 @@ pub async fn live_usbip_bind( bus_id: &str, lock_path: &Path, vm_name: &str, - daemon_uid: u32, daemon_gid: u32, ) -> Result<(), LiveHandlerError> { - crate::ops::usbip_lock::acquire_lock(lock_path, vm_name, daemon_uid, daemon_gid) + crate::ops::usbip_lock::acquire_lock(lock_path, vm_name, daemon_gid) .map_err(|e| LiveHandlerError::UsbipLock(e.to_string()))?; match crate::ops::usbip_host::inspect_usbip_driver_binding(sysfs_root, bus_id) .await @@ -2444,7 +2443,7 @@ impl DeviceWorkerSocketGrant { /// `/vms/`. fn for_guest(runtime_root: &Path, guest: &str) -> Result { let directory = crate::ops::device_worker::guest_socket_directory(runtime_root, guest) - .map_err(str::to_owned)?; + .map_err(|e| e.to_string())?; Ok(Self { runtime_root: runtime_root.to_path_buf(), directory, @@ -3563,7 +3562,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed lock"); @@ -3597,7 +3595,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed session claim"); @@ -3611,7 +3608,6 @@ mod tests { "1-2", &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .await @@ -3650,7 +3646,6 @@ mod tests { "1-2", &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .await @@ -3689,7 +3684,6 @@ mod tests { "invalid/busid", &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .await @@ -3726,7 +3720,6 @@ mod tests { "1-2", &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .await @@ -3765,7 +3758,6 @@ mod tests { "1-2", &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .await @@ -3798,7 +3790,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed lock"); @@ -3851,7 +3842,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &lock_path, "corp-vm", - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed lock"); diff --git a/packages/d2b-broker/src/ops/device_worker.rs b/packages/d2b-broker/src/ops/device_worker.rs index 3193c7e56..56e8eeab5 100644 --- a/packages/d2b-broker/src/ops/device_worker.rs +++ b/packages/d2b-broker/src/ops/device_worker.rs @@ -59,7 +59,7 @@ impl DeviceWorkerScope { /// The per-Guest runtime socket directory the worker binds its socket in /// (`/vms/`), validated to stay strictly inside the /// broker's own runtime root. - pub(crate) fn socket_directory(&self, runtime_root: &Path) -> Result { + pub(crate) fn socket_directory(&self, runtime_root: &Path) -> Result { guest_socket_directory(runtime_root, &self.guest) } } @@ -253,6 +253,30 @@ pub(crate) const fn binds_runtime_socket(role: &ProcessRole) -> bool { ) } +/// Why one Guest's runtime socket directory could not be derived. +/// +/// The Display of each refusal keeps the stable static-code spelling the +/// broker's launch-failure envelope surfaces. +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum GuestSocketError { + /// The runtime root is not an anchored absolute path. + RuntimeRootNotAnchored, + /// The Guest name is not one plain path component. + GuestNotAPlainName, + /// The derived directory escapes the runtime root. + DirectoryOutsideRuntimeRoot, +} + +impl std::fmt::Display for GuestSocketError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::RuntimeRootNotAnchored => "device-worker-runtime-root-not-anchored", + Self::GuestNotAPlainName => "device-worker-guest-not-a-plain-name", + Self::DirectoryOutsideRuntimeRoot => "device-worker-socket-dir-outside-runtime-root", + }) + } +} + /// The per-Guest runtime socket directory of one trusted Guest name. /// /// The name must be one plain component (never empty, `.`, `..`, or a @@ -262,9 +286,9 @@ pub(crate) const fn binds_runtime_socket(role: &ProcessRole) -> bool { pub(crate) fn guest_socket_directory( runtime_root: &Path, guest: &str, -) -> Result { +) -> Result { if !is_anchored_absolute(runtime_root) || runtime_root.parent().is_none() { - return Err("device-worker-runtime-root-not-anchored"); + return Err(GuestSocketError::RuntimeRootNotAnchored); } let mut components = Path::new(guest).components(); let plain_name = !guest.is_empty() @@ -272,11 +296,11 @@ pub(crate) fn guest_socket_directory( && matches!(components.next(), Some(std::path::Component::Normal(_))) && components.next().is_none(); if !plain_name { - return Err("device-worker-guest-not-a-plain-name"); + return Err(GuestSocketError::GuestNotAPlainName); } let directory = runtime_root.join(RUNTIME_VM_DIR).join(guest); if directory == runtime_root || !directory.starts_with(runtime_root) { - return Err("device-worker-socket-dir-outside-runtime-root"); + return Err(GuestSocketError::DirectoryOutsideRuntimeRoot); } Ok(directory) } diff --git a/packages/d2b-broker/src/ops/usbip_lock.rs b/packages/d2b-broker/src/ops/usbip_lock.rs index be32d0696..a51981e0f 100644 --- a/packages/d2b-broker/src/ops/usbip_lock.rs +++ b/packages/d2b-broker/src/ops/usbip_lock.rs @@ -44,7 +44,12 @@ pub enum UsbipLockError { observed: String, }, /// Underlying I/O error (e.g. parent dir missing). - Io { path: PathBuf, detail: String }, + Io { + path: PathBuf, + source: std::io::Error, + }, + /// The lock path cannot be resolved to a parent directory. + PathSafetyViolation { path: PathBuf }, } impl std::fmt::Display for UsbipLockError { @@ -70,12 +75,27 @@ impl std::fmt::Display for UsbipLockError { expected, observed ), - Self::Io { path, detail } => write!(f, "usbip lock io {}: {}", path.display(), detail), + Self::Io { path, source } => write!(f, "usbip lock io {}: {}", path.display(), source), + Self::PathSafetyViolation { path } => write!( + f, + "usbip lock io {}: path-safety-violation: {} has no parent", + path.display(), + path.display() + ), } } } -impl std::error::Error for UsbipLockError {} +impl std::error::Error for UsbipLockError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Io { source, .. } => Some(source), + Self::LockAlreadyHeld { .. } + | Self::OwnerMismatch { .. } + | Self::PathSafetyViolation { .. } => None, + } + } +} /// Open the pre-created parent dir for a busid lock file. /// @@ -86,7 +106,7 @@ impl std::error::Error for UsbipLockError {} pub fn ensure_lock_root(parent: &Path) -> Result { open_existing_lock_parent(parent).map_err(|e| UsbipLockError::Io { path: parent.to_path_buf(), - detail: e.to_string(), + source: e, }) } @@ -95,30 +115,28 @@ pub fn ensure_lock_root(parent: &Path) -> Result { /// # Errors /// /// Returns [`UsbipLockError::LockAlreadyHeld`] when another VM already -/// owns the lock file, and [`UsbipLockError::Io`] for path resolution or -/// lock-file creation failures. +/// owns the lock file, [`UsbipLockError::PathSafetyViolation`] when the +/// lock path has no parent directory, and [`UsbipLockError::Io`] for +/// path resolution or lock-file creation failures. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn acquire_lock( lock_path: &Path, owner_vm: &str, - _daemon_uid: u32, daemon_gid: u32, ) -> Result<(), UsbipLockError> { let full_lock_path = resolve_lock_path(lock_path).map_err(|e| UsbipLockError::Io { path: lock_path.to_path_buf(), - detail: e.to_string(), - })?; - let parent = full_lock_path.parent().ok_or_else(|| UsbipLockError::Io { - path: full_lock_path.clone(), - detail: format!( - "path-safety-violation: {} has no parent", - full_lock_path.display() - ), + source: e, })?; + let parent = full_lock_path + .parent() + .ok_or_else(|| UsbipLockError::PathSafetyViolation { + path: full_lock_path.clone(), + })?; let parent_fd = ensure_lock_root(parent)?; let lock_name = lock_basename(&full_lock_path).map_err(|e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, })?; match crate::sys::path_safe::create_file_at_safe( &parent_fd, @@ -130,27 +148,27 @@ pub fn acquire_lock( let mut f = File::from(fd); crate::sys::path_safe::fchmod(f.as_fd(), 0o640).map_err(|e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, })?; let broker_uid = nix::unistd::Uid::current().as_raw(); crate::sys::path_safe::fchown(f.as_fd(), Some(broker_uid), Some(daemon_gid)).map_err( |e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, }, )?; f.write_all(owner_vm.as_bytes()) .map_err(|e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, })?; f.write_all(b"\n").map_err(|e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, })?; f.sync_all().map_err(|e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, })?; Ok(()) } @@ -170,7 +188,7 @@ pub fn acquire_lock( } Err(e) => Err(UsbipLockError::Io { path: full_lock_path, - detail: e.to_string(), + source: e, }), } } @@ -189,12 +207,12 @@ pub fn acquire_lock( pub fn release_lock(lock_path: &Path, expected_owner: &str) -> Result<(), UsbipLockError> { let full_lock_path = resolve_lock_path(lock_path).map_err(|e| UsbipLockError::Io { path: lock_path.to_path_buf(), - detail: e.to_string(), + source: e, })?; let (parent_fd, lock_name) = parent_fd_and_name(&full_lock_path).map_err(|e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, })?; let observed = match read_owner_at(&parent_fd, &lock_name) { Ok(v) => v, @@ -202,7 +220,7 @@ pub fn release_lock(lock_path: &Path, expected_owner: &str) -> Result<(), UsbipL Err(e) => { return Err(UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, }); } }; @@ -223,7 +241,7 @@ pub fn release_lock(lock_path: &Path, expected_owner: &str) -> Result<(), UsbipL }) .map_err(|e| UsbipLockError::Io { path: full_lock_path.clone(), - detail: e.to_string(), + source: e, }) } @@ -357,7 +375,7 @@ mod tests { let lock = tmp.path().join("1-2"); let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - acquire_lock(&lock, "work-vm", uid, gid).unwrap(); + acquire_lock(&lock, "work-vm", gid).unwrap(); assert!(lock.exists()); assert_eq!(peek_owner(&lock).unwrap(), "work-vm"); let metadata = fs::symlink_metadata(&lock).expect("lock metadata"); @@ -373,9 +391,8 @@ mod tests { let tmp = temp_lock_dir(); let lock = tmp.path().join("1-2.3"); let broker_uid = nix::unistd::Uid::current().as_raw(); - let daemon_uid = if broker_uid == 0 { 1 } else { 0 }; let daemon_gid = nix::unistd::Gid::current().as_raw(); - acquire_lock(&lock, "work-vm", daemon_uid, daemon_gid).unwrap(); + acquire_lock(&lock, "work-vm", daemon_gid).unwrap(); let metadata = fs::symlink_metadata(&lock).expect("lock metadata"); assert_eq!(metadata.uid(), broker_uid); assert_eq!(metadata.gid(), daemon_gid); @@ -389,9 +406,8 @@ mod tests { fs::set_permissions(tmp.path(), fs::Permissions::from_mode(0o750)) .expect("chmod lock root"); let lock = tmp.path().join("1-2.4"); - let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - acquire_lock(&lock, "work-vm", uid, gid).unwrap(); + acquire_lock(&lock, "work-vm", gid).unwrap(); let metadata = fs::symlink_metadata(tmp.path()).expect("lock root metadata"); assert_eq!(metadata.permissions().mode() & 0o777, 0o750); } @@ -400,9 +416,8 @@ mod tests { fn acquire_requires_precreated_lock_root() { let tmp = temp_lock_dir(); let lock = tmp.path().join("missing").join("1-2.5"); - let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - let err = acquire_lock(&lock, "work-vm", uid, gid).unwrap_err(); + let err = acquire_lock(&lock, "work-vm", gid).unwrap_err(); assert!(matches!(err, UsbipLockError::Io { .. })); assert!(!tmp.path().join("missing").exists()); } @@ -411,10 +426,9 @@ mod tests { fn acquire_refuses_when_lock_already_held() { let tmp = temp_lock_dir(); let lock = tmp.path().join("2-3"); - let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - acquire_lock(&lock, "vm-a", uid, gid).unwrap(); - let err = acquire_lock(&lock, "vm-b", uid, gid).unwrap_err(); + acquire_lock(&lock, "vm-a", gid).unwrap(); + let err = acquire_lock(&lock, "vm-b", gid).unwrap_err(); match err { UsbipLockError::LockAlreadyHeld { existing_owner, .. } => { assert_eq!(existing_owner, "vm-a") @@ -427,9 +441,8 @@ mod tests { fn release_removes_lock_on_matching_owner() { let tmp = temp_lock_dir(); let lock = tmp.path().join("3-1"); - let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - acquire_lock(&lock, "vm-c", uid, gid).unwrap(); + acquire_lock(&lock, "vm-c", gid).unwrap(); release_lock(&lock, "vm-c").unwrap(); assert!(!lock.exists()); } @@ -438,9 +451,8 @@ mod tests { fn release_refuses_on_owner_mismatch() { let tmp = temp_lock_dir(); let lock = tmp.path().join("4-2"); - let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - acquire_lock(&lock, "vm-d", uid, gid).unwrap(); + acquire_lock(&lock, "vm-d", gid).unwrap(); let err = release_lock(&lock, "vm-other").unwrap_err(); assert!(matches!(err, UsbipLockError::OwnerMismatch { .. })); // Lock is preserved on mismatch. @@ -455,9 +467,8 @@ mod tests { fs::create_dir_all(&real).expect("real dir"); let link = tmp.path().join("link"); symlink(&real, &link).expect("symlink parent"); - let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - let err = acquire_lock(&link.join("5-5"), "vm-z", uid, gid).unwrap_err(); + let err = acquire_lock(&link.join("5-5"), "vm-z", gid).unwrap_err(); assert!(matches!(err, UsbipLockError::Io { .. })); } @@ -465,11 +476,10 @@ mod tests { fn acquire_idempotent_when_same_vm_owns_lock() { let tmp = temp_lock_dir(); let lock = tmp.path().join("6-1"); - let uid = nix::unistd::Uid::current().as_raw(); let gid = nix::unistd::Gid::current().as_raw(); - acquire_lock(&lock, "work-aad", uid, gid).unwrap(); + acquire_lock(&lock, "work-aad", gid).unwrap(); // Re-acquire by the same VM succeeds (e.g. after VM restart). - acquire_lock(&lock, "work-aad", uid, gid).unwrap(); + acquire_lock(&lock, "work-aad", gid).unwrap(); assert_eq!(peek_owner(&lock).unwrap(), "work-aad"); } diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index e9597184f..2a58d355a 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -6897,7 +6897,6 @@ impl DispatchBackend for LiveDispatchBackend { &intent.bus_id, &intent.lock_path, &intent.vm_name, - self.daemon_uid, self.daemon_gid, ) .await @@ -15840,7 +15839,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &lock_root.join("1-2.3"), "corp-vm", - nix::unistd::Uid::current().as_raw(), Gid::current().as_raw(), ) .expect("seed the busid lock"); @@ -18783,7 +18781,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &intent.lock_path, &intent.vm_name, - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed post-bind lock"); @@ -18826,7 +18823,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &intent.lock_path, &intent.vm_name, - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed same-VM replay lock"); @@ -18869,7 +18865,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &intent.lock_path, &intent.vm_name, - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed same-VM replay lock"); @@ -18920,7 +18915,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &intent.lock_path, &intent.vm_name, - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed lock for absent device"); @@ -18955,7 +18949,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &intent.lock_path, &intent.vm_name, - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed lock"); @@ -19000,7 +18993,6 @@ mod tests { crate::ops::usbip_lock::acquire_lock( &intent.lock_path, &intent.vm_name, - nix::unistd::Uid::current().as_raw(), nix::unistd::Gid::current().as_raw(), ) .expect("seed lock"); From f25b21e84d892cb5ce4a8d364ff1152844a8ff1c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:30:54 -0700 Subject: [PATCH 597/726] refactor(d2b-broker): type durable cell-store outcome as enum The durable cell-store record carried outcome as a hand-matched string on the wire. Derive serde on CellOutcome with lowercase renaming so the serialized spellings stay byte-identical (unknown/completed) and the hand match in the persist render and the hand re-parse in load() can go away. Existing durable files load unchanged; no DURABLE_VERSION bump. An unknown outcome string still fails closed as a corrupt store, now via the enum derive's unknown-variant rejection. --- changelog.d/w6-08-cell-outcome-enum.md | 7 +++++ packages/d2b-broker/src/state_cells.rs | 37 ++++++++++++++------------ 2 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 changelog.d/w6-08-cell-outcome-enum.md diff --git a/changelog.d/w6-08-cell-outcome-enum.md b/changelog.d/w6-08-cell-outcome-enum.md new file mode 100644 index 000000000..d7832664a --- /dev/null +++ b/changelog.d/w6-08-cell-outcome-enum.md @@ -0,0 +1,7 @@ +### Changed + +- The durable cell-store record now carries the typed outcome enum instead of a + hand-matched string: the serialized spellings (`unknown` / `completed`) are + unchanged, so existing durable files load as before and the format version + stays at 1. An unknown outcome string in a durable file still fails closed + as a corrupt store. \ No newline at end of file diff --git a/packages/d2b-broker/src/state_cells.rs b/packages/d2b-broker/src/state_cells.rs index 76c1992d7..9d6b9c738 100644 --- a/packages/d2b-broker/src/state_cells.rs +++ b/packages/d2b-broker/src/state_cells.rs @@ -81,7 +81,11 @@ const CELL_WORKER_QUEUE_DEPTH: usize = 256; pub const BROKER_PRINCIPAL: &str = "broker"; /// The recorded outcome of one cell record. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// +/// The serde shape is the durable wire spelling: `unknown` / `completed`, +/// byte-identical to the strings the durable file has always carried. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] pub enum CellOutcome { /// The record is durably pre-committed but no completion has been /// recorded: either the effect is in flight or the owner crashed between @@ -322,7 +326,7 @@ struct DurableFile { #[serde(rename_all = "camelCase")] struct DurableRecord { principal: String, - outcome: String, + outcome: CellOutcome, consumed_at_ms: u64, #[serde(default)] completed_at_ms: Option, @@ -869,10 +873,7 @@ fn durable_snapshot(records: &BTreeMap>) -> invocation_id.clone(), DurableRecord { principal: record.principal.clone(), - outcome: match record.outcome { - CellOutcome::Unknown => "unknown".to_owned(), - CellOutcome::Completed => "completed".to_owned(), - }, + outcome: record.outcome, consumed_at_ms: record.consumed_ms, completed_at_ms: record.completed_ms, }, @@ -908,21 +909,11 @@ fn load(root: &Path) -> Result>, C let mut records: BTreeMap> = BTreeMap::new(); for (cell, invocations) in file.records { for (invocation_id, record) in invocations { - let outcome = match record.outcome.as_str() { - "unknown" => CellOutcome::Unknown, - "completed" => CellOutcome::Completed, - other => { - return Err(CellStoreError::CorruptDurable(format!( - "{}: record {cell}/{invocation_id} has unknown outcome {other}", - path.display() - ))); - } - }; records.entry(cell.clone()).or_default().insert( invocation_id, CellRecord { principal: record.principal, - outcome, + outcome: record.outcome, claimed: false, durability: CellDurability::OneTime, payload: None, @@ -1709,5 +1700,17 @@ mod tests { CellStore::open(root.path()), Err(CellStoreError::CorruptDurable(_)) )); + // A syntactically valid file whose outcome string is not a known + // spelling must also fail closed: the enum derive rejects it the + // same way the old hand re-parse did. + std::fs::write( + &path, + br#"{"version":1,"records":{"lifecycle-leases":{"inv-1":{"principal":"alice","outcome":"bogus","consumedAtMs":1}}}}"#, + ) + .expect("write unknown-outcome file"); + assert!(matches!( + CellStore::open(root.path()), + Err(CellStoreError::CorruptDurable(_)) + )); } } From 5d067420c16e3863a0998dddf2f3dc089f3f6257 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:33:50 -0700 Subject: [PATCH 598/726] refactor(azure-vm): group in-flight operation pair on the recovery record AzureVmRecoveryState carried operation and operationStartedAtUnixMs as two independent Options that are always Some-together/None-together. Group them into Option on the controller and the wire record, and delete the restore-time pair check. The custom Deserialize accepts both the new inFlightOperation shape and the legacy operation + operationStartedAtUnixMs pair, folding the pair into the grouped shape, so sealed records written by older controllers still load. The framework consumer and the hermetic tests move to the grouped shape; a legacy-shape deserialize test pins the read migration, and the ADR notes the legacy pair is accepted on read. --- changelog.d/w6-07-azure-vm-recovery-state.md | 9 + ...-provider-runtime-azure-virtual-machine.md | 7 + .../src/controller/mod.rs | 170 ++++++++++++++---- .../tests/lifecycle_hermetic.rs | 45 ++++- .../d2b-provider-guest/src/effects_service.rs | 8 +- 5 files changed, 201 insertions(+), 38 deletions(-) create mode 100644 changelog.d/w6-07-azure-vm-recovery-state.md diff --git a/changelog.d/w6-07-azure-vm-recovery-state.md b/changelog.d/w6-07-azure-vm-recovery-state.md new file mode 100644 index 000000000..047b6671b --- /dev/null +++ b/changelog.d/w6-07-azure-vm-recovery-state.md @@ -0,0 +1,9 @@ +### Changed + +- The Azure VM guest controller's sealed restart-recovery record now groups + the in-flight ARM operation and its start time into one + `inFlightOperation` object instead of the `operation` + + `operationStartedAtUnixMs` pair. Records written before the grouping still + load: the read path accepts the legacy pair shape and folds it into the + grouped shape, so sealed recovery records written by older controllers are + unaffected. \ No newline at end of file diff --git a/docs/specs/providers/ADR-046-provider-runtime-azure-virtual-machine.md b/docs/specs/providers/ADR-046-provider-runtime-azure-virtual-machine.md index 4e7a181ea..2101a9a61 100644 --- a/docs/specs/providers/ADR-046-provider-runtime-azure-virtual-machine.md +++ b/docs/specs/providers/ADR-046-provider-runtime-azure-virtual-machine.md @@ -465,6 +465,13 @@ No ARM poll URL, ARM resource URI, or ARM endpoint appears anywhere in resources, status, or this Volume; `AzureEffectPort` holds that mapping in process memory. +The controller's sealed restart-recovery record (`AzureVmRecoveryState`) +serializes the in-flight ARM operation as one grouped `inFlightOperation` +object. Records written before that grouping carry the legacy +`operation` + `operationStartedAtUnixMs` pair; the read path accepts both +shapes and folds the legacy pair into `inFlightOperation`, so sealed records +written by older controllers still load unchanged. + ### Bootstrap-service state The `azure-vm-bootstrap-svc` service declares **no** Provider state Volume. Its diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs index 74f54aa66..6348e80df 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs @@ -99,24 +99,33 @@ pub enum AzureVmUpdate { }, } -/// Non-secret controller state required for restart recovery. +/// Opaque in-flight ARM operation together with its controller-local start +/// time. The two values are always Some-together/None-together. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct InFlightOperation { + /// Opaque in-flight ARM operation. + pub operation: crate::effect::AzureOperationHandle, + /// Controller-local LRO start time. + pub started_at: u64, +} + +/// Non-secret controller state required for restart recovery. +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct AzureVmRecoveryState { /// Current lifecycle phase. pub phase: AzureVmPhase, /// Whether the finalizer remains installed. pub finalizer_installed: bool, - /// Opaque in-flight ARM operation. - pub operation: Option, + /// Opaque in-flight ARM operation and its start time. + pub in_flight_operation: Option, /// Deterministic delete operation id, when deletion is pending. pub pending_delete_operation_id: Option, /// Bootstrap deadline start. pub bootstrap_started_at_unix_ms: Option, /// Number of extension delivery attempts. pub psk_delivery_attempts: u8, - /// Controller-local LRO start time. - pub operation_started_at_unix_ms: Option, /// Pending typed update. pub pending_update: Option, /// Bootstrap service enrollment state. @@ -132,6 +141,105 @@ pub struct AzureVmRecoveryState { pub bootstrap_deadline_failed: bool, } +impl<'de> Deserialize<'de> for AzureVmRecoveryState { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + // The record is written by `recovery_state` and read back through + // serde. The in-flight operation is one grouped object today, but + // records written before the grouping carry the legacy + // `operation` + `operationStartedAtUnixMs` pair; both shapes load + // and the pair folds into the grouped shape. The fold is total + // because the write side always sets or clears both values + // together. + #[derive(Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct NewShape { + phase: AzureVmPhase, + finalizer_installed: bool, + in_flight_operation: Option, + pending_delete_operation_id: Option, + bootstrap_started_at_unix_ms: Option, + psk_delivery_attempts: u8, + pending_update: Option, + bootstrap_service_state: BootstrapServiceState, + #[serde(default)] + bootstrap_extension_present: bool, + #[serde(default)] + child_cleanup_complete: bool, + #[serde(default)] + bootstrap_deadline_failed: bool, + } + + #[derive(Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct LegacyShape { + phase: AzureVmPhase, + finalizer_installed: bool, + operation: Option, + pending_delete_operation_id: Option, + bootstrap_started_at_unix_ms: Option, + psk_delivery_attempts: u8, + operation_started_at_unix_ms: Option, + pending_update: Option, + bootstrap_service_state: BootstrapServiceState, + #[serde(default)] + bootstrap_extension_present: bool, + #[serde(default)] + child_cleanup_complete: bool, + #[serde(default)] + bootstrap_deadline_failed: bool, + } + + #[derive(Deserialize)] + #[serde(untagged)] + enum Repr { + New(NewShape), + Legacy(LegacyShape), + } + + Ok(match Repr::deserialize(deserializer)? { + Repr::New(shape) => Self { + phase: shape.phase, + finalizer_installed: shape.finalizer_installed, + in_flight_operation: shape.in_flight_operation, + pending_delete_operation_id: shape.pending_delete_operation_id, + bootstrap_started_at_unix_ms: shape.bootstrap_started_at_unix_ms, + psk_delivery_attempts: shape.psk_delivery_attempts, + pending_update: shape.pending_update, + bootstrap_service_state: shape.bootstrap_service_state, + bootstrap_extension_present: shape.bootstrap_extension_present, + child_cleanup_complete: shape.child_cleanup_complete, + bootstrap_deadline_failed: shape.bootstrap_deadline_failed, + }, + Repr::Legacy(shape) => Self { + phase: shape.phase, + finalizer_installed: shape.finalizer_installed, + in_flight_operation: match ( + shape.operation, + shape.operation_started_at_unix_ms, + ) { + (Some(operation), Some(started_at)) => { + Some(InFlightOperation { operation, started_at }) + } + (None, None) => None, + // Unreachable: the write side keeps the pair together. + _ => unreachable!("legacy recovery record has a half-Some operation pair"), + }, + pending_delete_operation_id: shape.pending_delete_operation_id, + bootstrap_started_at_unix_ms: shape.bootstrap_started_at_unix_ms, + psk_delivery_attempts: shape.psk_delivery_attempts, + pending_update: shape.pending_update, + bootstrap_service_state: shape.bootstrap_service_state, + bootstrap_extension_present: shape.bootstrap_extension_present, + child_cleanup_complete: shape.child_cleanup_complete, + bootstrap_deadline_failed: shape.bootstrap_deadline_failed, + }, + }) + } +} + impl AzureVmUpdate { fn operation_class(&self) -> &'static str { match self { @@ -183,7 +291,7 @@ pub struct AzureVmController { credentials: Arc, phase: AzureVmPhase, finalizer: bool, - operation: Option, + in_flight_operation: Option, vm_handle: Option, expected_tag_digest: TagDigest, identity_digest: Option<[u8; 32]>, @@ -192,7 +300,6 @@ pub struct AzureVmController { pending_delete_operation_id: Option, bootstrap_started_at_unix_ms: Option, psk_delivery_attempts: u8, - operation_started_at_unix_ms: Option, pending_update: Option, clock: Arc, bootstrap_extension_present: bool, @@ -222,7 +329,7 @@ where credentials, phase: AzureVmPhase::Absent, finalizer: true, - operation: None, + in_flight_operation: None, vm_handle: None, expected_tag_digest, identity_digest: None, @@ -231,7 +338,6 @@ where pending_delete_operation_id: None, bootstrap_started_at_unix_ms: None, psk_delivery_attempts: 0, - operation_started_at_unix_ms: None, pending_update: None, clock: Arc::new(SystemClock), bootstrap_extension_present: false, @@ -257,11 +363,10 @@ where AzureVmRecoveryState { phase: self.phase, finalizer_installed: self.finalizer, - operation: self.operation.clone(), + in_flight_operation: self.in_flight_operation.clone(), pending_delete_operation_id: self.pending_delete_operation_id.clone(), bootstrap_started_at_unix_ms: self.bootstrap_started_at_unix_ms, psk_delivery_attempts: self.psk_delivery_attempts, - operation_started_at_unix_ms: self.operation_started_at_unix_ms, pending_update: self.pending_update.clone(), bootstrap_service_state: self.bootstrap_service.state(), bootstrap_extension_present: self.bootstrap_extension_present, @@ -275,20 +380,19 @@ where /// # Errors /// /// Returns [`AzureVmError::InvalidConfiguration`] when the recovery - /// record is internally inconsistent (operation/phase pairing, + /// record is internally inconsistent (phase/operation pairing, /// finalizer, or identifier bounds). pub fn restore_recovery_state( mut self, recovery: AzureVmRecoveryState, ) -> Result { - if recovery.operation.is_some() != recovery.operation_started_at_unix_ms.is_some() - || (recovery.phase == AzureVmPhase::Reconfiguring - && (recovery.operation.is_none() || recovery.pending_update.is_none())) + if (recovery.phase == AzureVmPhase::Reconfiguring + && (recovery.in_flight_operation.is_none() || recovery.pending_update.is_none())) || (recovery.pending_update.is_some() && recovery.phase != AzureVmPhase::Reconfiguring) || (matches!( recovery.phase, AzureVmPhase::PskCleaning | AzureVmPhase::ChildCleaning - ) && recovery.operation.is_none()) + ) && recovery.in_flight_operation.is_none()) || (!recovery.finalizer_installed && recovery.phase != AzureVmPhase::Finalized) || recovery.psk_delivery_attempts > MAX_PSK_DELIVERY_ATTEMPTS || recovery @@ -304,11 +408,10 @@ where } self.phase = recovery.phase; self.finalizer = recovery.finalizer_installed; - self.operation = recovery.operation; + self.in_flight_operation = recovery.in_flight_operation; self.pending_delete_operation_id = recovery.pending_delete_operation_id; self.bootstrap_started_at_unix_ms = recovery.bootstrap_started_at_unix_ms; self.psk_delivery_attempts = recovery.psk_delivery_attempts; - self.operation_started_at_unix_ms = recovery.operation_started_at_unix_ms; self.pending_update = recovery.pending_update; self.bootstrap_service = BootstrapService::from_state(recovery.bootstrap_service_state); self.bootstrap_extension_present = recovery.bootstrap_extension_present; @@ -356,7 +459,11 @@ where if !self.finalizer { return Err(AzureVmError::InvalidConfiguration); } - if let Some(operation) = self.operation.clone() { + if let Some(operation) = self + .in_flight_operation + .as_ref() + .map(|in_flight| in_flight.operation.clone()) + { return self.poll_operation(operation).await; } if self.bootstrap_deadline_failed && self.pending_delete_operation_id.is_none() { @@ -475,7 +582,9 @@ where &mut self, operation: crate::effect::AzureOperationHandle, ) -> Result { - if self.operation.as_ref() != Some(&operation) { + if self.in_flight_operation.as_ref().map(|in_flight| &in_flight.operation) + != Some(&operation) + { tracing::warn!( "poll called with a foreign operation handle" ); @@ -640,7 +749,7 @@ where ); return Err(AzureVmError::Transient); } - if self.operation.is_some() || self.pending_update.is_some() { + if self.in_flight_operation.is_some() || self.pending_update.is_some() { tracing::debug!( zone = %zone_uid, resource = %guest_uid, @@ -712,7 +821,7 @@ where operation_id(zone_uid, guest_uid, generation, "delete") }) .clone(); - if self.operation.is_some() { + if self.in_flight_operation.is_some() { self.pending_update = None; if !matches!( self.phase, @@ -905,7 +1014,7 @@ where } async fn start_extension_cleanup(&mut self) -> Result { - if self.operation.is_some() { + if self.in_flight_operation.is_some() { return Ok(AzureVmReconcileOutcome::Progressing { after_ms: 250 }); } let token = self.arm_token().await?; @@ -925,7 +1034,7 @@ where self.phase = AzureVmPhase::Finalized; return Ok(AzureVmReconcileOutcome::Converged); } - if self.operation.is_some() { + if self.in_flight_operation.is_some() { return Ok(AzureVmReconcileOutcome::Progressing { after_ms: 1_000 }); } let operation_id = self @@ -981,18 +1090,19 @@ where } fn set_operation(&mut self, operation: crate::effect::AzureOperationHandle) { - self.operation = Some(operation); - self.operation_started_at_unix_ms = Some(self.clock.now_unix_ms()); + self.in_flight_operation = Some(InFlightOperation { + operation, + started_at: self.clock.now_unix_ms(), + }); } fn clear_operation(&mut self) { - self.operation = None; - self.operation_started_at_unix_ms = None; + self.in_flight_operation = None; } fn operation_expired(&self) -> bool { - self.operation_started_at_unix_ms.is_some_and(|started| { - self.clock.now_unix_ms().saturating_sub(started) >= MAX_LRO_AGE_MS + self.in_flight_operation.as_ref().is_some_and(|in_flight| { + self.clock.now_unix_ms().saturating_sub(in_flight.started_at) >= MAX_LRO_AGE_MS }) } diff --git a/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs b/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs index bd37c9fc2..769b1f006 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs @@ -423,6 +423,45 @@ async fn recovery_state_restores_opaque_lro_without_secret_material() { restored.reconcile("zone", "guest", 1).await.unwrap(); } +#[test] +fn legacy_operation_pair_recovery_record_still_loads() { + // Records written before the in-flight operation was grouped carry the + // `operation` + `operationStartedAtUnixMs` pair instead of + // `inFlightOperation`; they must still load, folding into the grouped + // shape, and re-serialize in the grouped shape. + let recovery: AzureVmRecoveryState = serde_json::from_value(serde_json::json!({ + "phase": "provisioning", + "finalizerInstalled": true, + "operation": "cHJvdmlzaW9u", + "pendingDeleteOperationId": null, + "bootstrapStartedAtUnixMs": null, + "pskDeliveryAttempts": 0, + "operationStartedAtUnixMs": 42, + "pendingUpdate": null, + "bootstrapServiceState": "Waiting", + "bootstrapExtensionPresent": false, + "childCleanupComplete": false, + "bootstrapDeadlineFailed": false, + })) + .unwrap(); + let in_flight = recovery + .in_flight_operation + .clone() + .expect("legacy pair folds into the grouped shape"); + assert_eq!( + in_flight.operation, + AzureOperationHandle::from_core(b"provision").unwrap() + ); + assert_eq!(in_flight.started_at, 42); + assert_eq!(recovery.phase, AzureVmPhase::Provisioning); + + let encoded = serde_json::to_string(&recovery).unwrap(); + assert!(encoded.contains("\"inFlightOperation\"")); + assert!(!encoded.contains("operationStartedAtUnixMs")); + let reloaded: AzureVmRecoveryState = serde_json::from_str(&encoded).unwrap(); + assert_eq!(reloaded, recovery); +} + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn restart_adopts_only_tagged_running_vm() { @@ -618,11 +657,10 @@ async fn restart_with_pending_delete_never_reprovisions_an_absent_vm() { .restore_recovery_state(AzureVmRecoveryState { phase: AzureVmPhase::Deleting, finalizer_installed: true, - operation: None, + in_flight_operation: None, pending_delete_operation_id: Some("delete-id".to_owned()), bootstrap_started_at_unix_ms: None, psk_delivery_attempts: 0, - operation_started_at_unix_ms: None, pending_update: None, bootstrap_service_state: BootstrapService::default().state(), bootstrap_extension_present: false, @@ -861,11 +899,10 @@ async fn bootstrap_deadline_retries_failed_extension_cleanup() { let recovery = AzureVmRecoveryState { phase: AzureVmPhase::Failed, finalizer_installed: true, - operation: None, + in_flight_operation: None, pending_delete_operation_id: None, bootstrap_started_at_unix_ms: Some(0), psk_delivery_attempts: 0, - operation_started_at_unix_ms: None, pending_update: None, bootstrap_service_state: BootstrapService::default().state(), bootstrap_extension_present: true, diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index 795b7d15b..15175616a 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -1383,9 +1383,9 @@ impl GuestEffectsService { .map_err(|_| GuestEffectError::Unavailable)?; } GuestRuntimeController::AzureVm { controller } => { - if let Some(operation) = controller.recovery_state().operation { + if let Some(in_flight) = controller.recovery_state().in_flight_operation { controller - .poll_operation(operation) + .poll_operation(in_flight.operation) .await .map_err(|_| GuestEffectError::Unavailable)?; } @@ -1925,8 +1925,8 @@ mod tests { } assert_eq!(controller.phase(), azure_vm_runtime::AzureVmPhase::Ready); for _ in 0..8 { - if let Some(operation) = controller.recovery_state().operation { - controller.poll_operation(operation).await.unwrap(); + if let Some(in_flight) = controller.recovery_state().in_flight_operation { + controller.poll_operation(in_flight.operation).await.unwrap(); } let outcome = controller .finalize("work", "123e4567-e89b-42d3-a456-426614174000", 1) From 8e70d643e653f202ed9346671153d044c0762505 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:34:40 -0700 Subject: [PATCH 599/726] test(d2b-core): restore static-invariants gate cases as in-module unit tests --- changelog.d/w5-04-static-invariants-tests.md | 4 + packages/d2b-core/src/static_invariants.rs | 157 ++++++++++++++++++- 2 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 changelog.d/w5-04-static-invariants-tests.md diff --git a/changelog.d/w5-04-static-invariants-tests.md b/changelog.d/w5-04-static-invariants-tests.md new file mode 100644 index 000000000..1dfb1fd28 --- /dev/null +++ b/changelog.d/w5-04-static-invariants-tests.md @@ -0,0 +1,4 @@ +### Fixed + +- The four static security/policy validators in d2b-core's `static_invariants` module (world-readable-leak, opaque-key-ids, broad-caps, writable-paths) now carry in-module unit tests restoring the positive/negative gate cases from the retired `tests/static-invariant-*.sh` bash gates, so the invariants are enforced as tests; the module doc's claim that the cases were preserved as unit tests is now true. +- Corrected the `static_invariants` module doc, which claimed the validators check the real rendered artifacts; they are pure and caller-free, so the doc now describes the in-module test coverage instead. \ No newline at end of file diff --git a/packages/d2b-core/src/static_invariants.rs b/packages/d2b-core/src/static_invariants.rs index 48b93082f..4fcdb68c4 100644 --- a/packages/d2b-core/src/static_invariants.rs +++ b/packages/d2b-core/src/static_invariants.rs @@ -3,9 +3,8 @@ //! These were historically enforced by the `tests/static-invariant-*.sh` bash //! gates as `jq` filters over synthetic positive/negative fixtures (plus, for //! two of them, a grep over the real rendered `vms.json`). They are re-homed -//! here as typed validators so the *real* rendered artifacts are checked (a -//! strictly stronger guarantee than the synthetic-fixture grep), with the -//! original positive/negative cases preserved as unit tests. +//! here as typed validators, with the original positive/negative gate cases +//! preserved as in-module unit tests (see the `tests` module below). //! //! Validators are pure and return the list of offending locations (empty == //! invariant holds), so callers (contract tests, and potentially the broker) @@ -243,3 +242,155 @@ pub fn undeclared_writable_paths<'a>( undeclared.dedup(); undeclared } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + /// Positive fixture from `tests/static-invariant-world-readable-leak.sh`: + /// a public-safe manifest (allowlisted fields, `_manifest.` reserved block) + /// must produce no leaks. + #[test] + fn world_readable_leak_accepts_public_safe_manifest() { + let manifest = json!({ + "_manifest": {"manifestVersion": 4}, + "corp-vm": { + "name": "corp-vm", + "env": "work", + "index": 10, + "sshUser": "alice", + "sshPort": 22, + "ipv4": "10.20.0.10", + "mac": "02:00:00:00:00:0a", + "isNetVm": false, + } + }); + assert_eq!(world_readable_field_leaks(&manifest), Vec::::new()); + } + + /// Negative fixture from `tests/static-invariant-world-readable-leak.sh`: + /// a non-allowlisted field must be reported by dotted path. + #[test] + fn world_readable_leak_rejects_non_allowlisted_field() { + let manifest = json!({ + "corp-vm": {"name": "corp-vm", "privateKeyPath": "/var/lib/nixling/vms/corp-vm/id_ed25519"} + }); + assert_eq!( + world_readable_field_leaks(&manifest), + vec!["corp-vm.privateKeyPath".to_owned()] + ); + } + + /// The `_observability.` reserved block is exempt, matching the doc'd + /// reserved-block carve-out (the bash gate predated the block). + #[test] + fn world_readable_leak_exempts_observability_reserved_block() { + let manifest = json!({ + "_observability": {"internal": {"bufferBytes": 4096}} + }); + assert_eq!(world_readable_field_leaks(&manifest), Vec::::new()); + } + + /// Positive fixture from `tests/static-invariant-opaque-key-ids.sh`: + /// opaque key/secret IDs must not be flagged as host paths. + #[test] + fn path_bearing_key_accepts_opaque_key_ids() { + let manifest = json!({ + "keys": {"ssh": {"key_id": "corp-vm-host-key"}}, + "secrets": [{"secret_id": "api-token"}] + }); + assert_eq!(path_bearing_key_violations(&manifest), Vec::::new()); + } + + /// Negative fixture from `tests/static-invariant-opaque-key-ids.sh`: + /// path-bearing key suffixes with host-path values must be reported as + /// `dotted.path=value`. + #[test] + fn path_bearing_key_rejects_host_paths() { + let manifest = json!({ + "keys": {"ssh": {"privateKeyPath": "/var/lib/nixling/vms/corp-vm/id_ed25519"}}, + "secret_path": "/run/secrets/token" + }); + assert_eq!( + path_bearing_key_violations(&manifest), + vec![ + "keys.ssh.privateKeyPath=/var/lib/nixling/vms/corp-vm/id_ed25519".to_owned(), + "secret_path=/run/secrets/token".to_owned(), + ] + ); + } + + /// A path-suffixed key whose value is an opaque ID (no `/`) is not a + /// violation: only path-looking values leak host locations. + #[test] + fn path_bearing_key_accepts_opaque_value_on_path_suffixed_key() { + let manifest = json!({"tokenPath": "tok_abc123"}); + assert_eq!(path_bearing_key_violations(&manifest), Vec::::new()); + } + + /// Positive fixture from `tests/static-invariant-broad-caps.sh`: a broad + /// capability with an ADR carve-out reference is accepted. + #[test] + fn broad_cap_with_adr_carve_out_is_allowed() { + let caps = vec!["CAP_NET_ADMIN".to_owned()]; + assert!(!is_broad_cap_violation(&caps, Some("ADR 0004"))); + } + + /// Negative fixture from `tests/static-invariant-broad-caps.sh`: a broad + /// capability without any ADR carve-out is a violation. + #[test] + fn broad_cap_without_adr_carve_out_is_violation() { + let caps = vec!["CAP_SYS_ADMIN".to_owned()]; + assert!(is_broad_cap_violation(&caps, None)); + } + + /// Non-broad capabilities need no carve-out. + #[test] + fn non_broad_caps_need_no_carve_out() { + let caps = vec!["CAP_DAC_OVERRIDE".to_owned()]; + assert!(!is_broad_cap_violation(&caps, None)); + } + + /// A blank/whitespace carve-out does not satisfy the invariant. + #[test] + fn blank_adr_carve_out_does_not_satisfy_broad_cap() { + let caps = vec!["CAP_SYS_ADMIN".to_owned()]; + assert!(is_broad_cap_violation(&caps, Some(" "))); + } + + /// Positive fixture from `tests/static-invariant-writable-paths.sh`: every + /// used writable path declared by the bundle is accepted. + #[test] + fn declared_writable_paths_are_accepted() { + let declared = ["/var/lib/nixling/vms/corp-vm"]; + let used = ["/var/lib/nixling/vms/corp-vm"]; + assert_eq!( + undeclared_writable_paths(declared, used), + Vec::::new() + ); + } + + /// Negative fixture from `tests/static-invariant-writable-paths.sh`: a + /// used path absent from the bundle's declaration is reported. + #[test] + fn undeclared_writable_paths_are_reported() { + let declared = ["/var/lib/nixling/vms/corp-vm"]; + let used = ["/run/secrets"]; + assert_eq!( + undeclared_writable_paths(declared, used), + vec!["/run/secrets".to_owned()] + ); + } + + /// The result is the sorted, deduplicated set difference `used - declared`. + #[test] + fn undeclared_writable_paths_are_sorted_and_deduped() { + let declared = ["/var/lib/nixling/vms/corp-vm"]; + let used = ["/b", "/a", "/b"]; + assert_eq!( + undeclared_writable_paths(declared, used), + vec!["/a".to_owned(), "/b".to_owned()] + ); + } +} From 78b5c5672b903edd5946a0ccd5fc91421d4c72cf Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:36:41 -0700 Subject: [PATCH 600/726] chore(supply-chain): workspace-inherit rustix/sha2, record accepted duplicate clusters, raise licence confidence floor --- changelog.d/w5-12-supply-chain-posture.md | 5 ++ deny.toml | 77 ++++++++++++++++++- packages/d2b-broker/Cargo.toml | 6 +- packages/d2b-provider-guest/Cargo.toml | 2 +- .../d2b-provider-network-local/Cargo.toml | 2 +- .../d2b-provider-process-systemd/Cargo.toml | 2 +- packages/d2b-provider-process/Cargo.toml | 4 +- packages/d2b-provider-user/Cargo.toml | 2 +- packages/d2b-telemetry/Cargo.toml | 2 +- packages/d2b-unsafe-local-helper/Cargo.toml | 2 +- packages/d2bd-runtime/Cargo.toml | 2 +- packages/d2bd/Cargo.toml | 2 +- 12 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 changelog.d/w5-12-supply-chain-posture.md diff --git a/changelog.d/w5-12-supply-chain-posture.md b/changelog.d/w5-12-supply-chain-posture.md new file mode 100644 index 000000000..b7de38633 --- /dev/null +++ b/changelog.d/w5-12-supply-chain-posture.md @@ -0,0 +1,5 @@ +### Fixed + +- Member manifests now inherit `rustix` and `sha2` from `workspace.dependencies` instead of pinning literal versions; the 13 member decls across d2b-broker, d2b-provider-guest, d2b-provider-network-local, d2b-provider-process, d2b-provider-process-systemd, d2b-provider-user, d2b-telemetry, d2b-unsafe-local-helper, d2bd, and d2bd-runtime resolve to the same versions as before, so both lockfiles are unchanged. +- `deny.toml` records the accepted duplicate clusters (nix at 0.26/0.29/0.31, rustix at 0.38/1.1, and the 31 transitive-only clusters) with their versions, pullers, and re-check triggers, and raises the licence confidence threshold from 0.8 to 0.9. +- Added a lock-drift check comparing shared-crate versions across `Cargo.lock` and `packages/Cargo.guest.lock`; it currently reports 39 shared crates resolving to newer versions in the guest tree, to be aligned by regenerating both locks from one index snapshot at the next dependency refresh. \ No newline at end of file diff --git a/deny.toml b/deny.toml index cf870827a..5e319fad2 100644 --- a/deny.toml +++ b/deny.toml @@ -1,6 +1,81 @@ [bans] multiple-versions = "warn" wildcards = "deny" +# Accepted duplicate clusters (rust-skills audit RS-0946/RS-0947/RS-0949, +# reviewed 2026-09-25). cargo-deny reports these on every run; each entry +# names the versions, the pullers, and the re-check trigger. The clusters +# below are accepted because the pullers' version ranges genuinely do not +# unify (no lower-bound raise reaches both legs). multiple-versions stays +# "warn" until the workspace-direct clusters resolve; a warn-to-deny flip +# that fails on these known clusters is an expected cost, not a mystery. +# +# nix (three legs): 0.26.4 pulled by ttrpc 0.9.0 (ttrpc's own pin); +# 0.29.0 is the workspace pin, pulled by 17 workspace members (d2b, +# d2b-broker, d2b-core, d2b-host, d2b-provider-audio-pipewire, +# d2b-provider-clipboard-wayland, d2b-provider-device-security-key, +# d2b-provider-device-tpm, d2b-provider-display-wayland, d2b-provider-host, +# d2b-provider-user, d2b-provider-volume-local, d2b-session-unix, +# d2b-unsafe-local-helper, d2bd, d2bd-runtime, xtask); 0.31.3 pulled by +# command-fds 0.3.3 and vsock 0.5.4 (via d2b-provider-transport-vsock). +# Keep the workspace pin at 0.29. Re-check when ttrpc or vsock bumps its +# nix pin. +# +# rustix (two majors): 0.38.44 is the workspace pin, pulled by 23 +# workspace/transitive dependents (d2b, d2b-audit, d2b-broker, +# d2b-contracts-broker, d2b-core, d2b-host, d2b-provider-clipboard-wayland, +# d2b-provider-config-nixos, d2b-provider-display-wayland, +# d2b-provider-network-local, d2b-provider-observability-otel, +# d2b-provider-process, d2b-provider-supervisor, +# d2b-provider-transport-unix, d2b-provider-volume-local, +# d2b-resource-compiler, d2b-session-unix, d2b-sk-frontend, +# d2b-unsafe-local-helper, d2bd, d2bd-runtime, which, xtask); 1.1.4 pulled +# transitively by the async-std/wayland/tempfile/zbus families (async-io, +# async-process, async-signal, polling, tempfile, wayland-backend, +# wayland-client, zbus). Migrating the workspace pin to 1.1 needs a +# dedicated feature-surface pass. Re-check at each dependency refresh. +# +# Transitive-only clusters (the remainder; none workspace-direct): +# bitflags 1.3.2 (defmt, nix) / 2.13.1 (rustix, wayland-client, rusqlite, +# objc2 families, nix) +# getrandom 0.2.17 (ring, d2bd, d2bd-runtime, rand_core) / 0.3.4 (snow, +# d2b-bus, d2b-provider-transport-unix) / 0.4.3 (tempfile, uuid, jobserver) +# hashbrown 0.12.3 (indexmap 1.x) / 0.14.5 (dashmap) / 0.16.1 (rsqlite-vfs) +# / 0.17.1 (indexmap 2.x, hashlink) +# heck 0.3.3 (prost-build) / 0.5.0 (clap_derive, strum_macros) +# indexmap 1.9.3 (envmnt, petgraph) / 2.14.0 (protobuf-parse, toml_edit) +# linux-raw-sys 0.4.15 (rustix 0.38) / 0.12.1 (rustix 1.1) +# memoffset 0.7.1 (nix 0.26) / 0.9.1 (nix 0.29/0.31, uds_windows) +# phf family 0.11.3 (web_atoms, string_cache, phf_codegen, +# string_cache_codegen) / 0.13.1 (wl-proxy, phf_macros) +# proc-macro-crate 1.3.1 (bolero-generator-derive) / 3.5.0 (zbus_macros, +# zvariant_derive) +# r-efi 5.3.0 / 6.0.0 (getrandom 0.3/0.4 legs) +# rand 0.8.7 (bolero, bolero-engine, tungstenite, phf_generator) / +# 0.9.5 + 0.10.2 (linearize) +# rand_core 0.6.4 (rand 0.8, rand_chacha, crypto-common, +# bolero-generator) / 0.9.5 + 0.10.1 (rand 0.9/0.10) +# socket2 0.5.10 (d2b-contracts-broker, d2b-provider-network-local, +# d2b-unsafe-local-helper, d2bd, d2bd-runtime) / 0.6.5 (tokio) +# syn 1.0.109 (prost-derive, bolero-generator-derive, derive-new, +# uapi-proc) / 2.0.119 (20 macro crates incl. thiserror-impl, +# schemars_derive, strum_macros, zerocopy-derive) / 3.0.3 (14 macro +# crates incl. serde_derive, clap_derive, async-trait, tokio-macros, +# zbus_macros) +# thiserror 1.0.69 (ttrpc, protobuf 3.7.2 family, tungstenite 0.24) / +# 2.0.20 (workspace decls + wl-proxy, command-fds, html2text) +# toml_datetime 0.6.11 / 1.1.1 (toml_edit 0.19 vs 0.25 legs) +# toml_edit 0.19.15 / 0.25.13 (proc-macro-crate 1.3 vs 3.5 legs) +# winnow 0.5.40 (toml_edit 0.19) / 1.0.4 (toml_edit 0.25, zbus family, +# toml_parser) +# windows-link 0.1.3 (windows 0.61 family) / 0.2.1 (backtrace, +# parking_lot_core, windows-sys 0.61) +# windows-sys 0.48.0 (ttrpc) / 0.52.0 (ring, socket2) / 0.59.0 +# (rustix 0.38) / 0.61.2 (tokio, mio, polling, tempfile, errno, zbus, +# nu-ansi-term, anstyle family, home, uds_windows, rustix 1.1) +# windows-targets + 8 windows_* platform-tier crates: 0.48.5 / 0.52.6 +# (windows-sys 0.48/0.52/0.59 legs) +# Re-check the whole inventory at each lock regeneration; the clusters are +# transitive-only and follow their pullers' ranges. [licenses] allow = [ @@ -18,7 +93,7 @@ allow = [ "Unlicense", "Zlib", ] -confidence-threshold = 0.8 +confidence-threshold = 0.9 [sources] unknown-registry = "deny" diff --git a/packages/d2b-broker/Cargo.toml b/packages/d2b-broker/Cargo.toml index e8e0246a9..79d6fbb46 100644 --- a/packages/d2b-broker/Cargo.toml +++ b/packages/d2b-broker/Cargo.toml @@ -57,10 +57,10 @@ nix = { version = "0.29", features = ["fs", "socket", "uio", "user", "signal", " # plan.md §"W3 filesystem path-safety tests". `rustix` provides # those calls without a per-syscall `unsafe` block, so the broker's # `unsafe_code = "deny"` lint stays clean. -rustix = { version = "0.38", features = ["fs", "process", "net"] } +rustix = { workspace = true, features = ["fs", "process", "net"] } tracing = "0.1" tokio = { workspace = true, features = ["rt", "rt-multi-thread", "macros", "signal", "sync", "net", "time", "fs", "process", "io-util", "test-util"] } -sha2 = "0.10" +sha2 = { workspace = true } # U9 (plan R16): the `blocking-api` feature is removed - the broker's # D-Bus surface is async (the systemd operations now live in the # process-systemd provider crate), so the blocking module must not be @@ -80,7 +80,7 @@ d2b-core = { path = "../d2b-core", version = "0.0.0-bootstrap", features = ["tes d2b-host = { path = "../d2b-host", version = "0.0.0-bootstrap", features = ["fake-backends"] } d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = "0.0.0-bootstrap" } tempfile = "3" -sha2 = "0.10" +sha2 = { workspace = true } # U33/U9: this crate does not inherit `[workspace.lints]` (it carries its own # lint posture), but `clippy.toml` at the workspace root arms diff --git a/packages/d2b-provider-guest/Cargo.toml b/packages/d2b-provider-guest/Cargo.toml index d1110a1e7..3c54abcb7 100644 --- a/packages/d2b-provider-guest/Cargo.toml +++ b/packages/d2b-provider-guest/Cargo.toml @@ -25,7 +25,7 @@ d2b-provider-guest-azure-container-apps = { path = "../d2b-provider-guest-azure- d2b-provider-guest-azure-virtual-machine = { path = "../d2b-provider-guest-azure-virtual-machine", version = "0.0.0-bootstrap" } d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-bootstrap" } d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0-bootstrap" } -sha2 = "0.10" +sha2 = { workspace = true } parking_lot = "0.12" schemars = { workspace = true } serde = { workspace = true } diff --git a/packages/d2b-provider-network-local/Cargo.toml b/packages/d2b-provider-network-local/Cargo.toml index 1b2db00b1..cd3c99b88 100644 --- a/packages/d2b-provider-network-local/Cargo.toml +++ b/packages/d2b-provider-network-local/Cargo.toml @@ -35,6 +35,6 @@ tokio = { workspace = true, features = ["macros", "process", "rt-multi-thread", parking_lot = "0.12" [dev-dependencies] -rustix = { version = "0.38", features = ["std", "net", "pipe"] } +rustix = { workspace = true, features = ["std", "net", "pipe"] } socket2 = { version = "0.5", features = ["all"] } tempfile = "3" diff --git a/packages/d2b-provider-process-systemd/Cargo.toml b/packages/d2b-provider-process-systemd/Cargo.toml index 682a9ab81..d0b690962 100644 --- a/packages/d2b-provider-process-systemd/Cargo.toml +++ b/packages/d2b-provider-process-systemd/Cargo.toml @@ -25,7 +25,7 @@ d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstra async-trait = "0.1" serde = { workspace = true } serde_json = { workspace = true } -sha2 = "0.10" +sha2 = { workspace = true } tokio = { workspace = true, features = ["fs", "macros", "rt", "sync", "time"] } tracing = "0.1" zbus = "5.16" diff --git a/packages/d2b-provider-process/Cargo.toml b/packages/d2b-provider-process/Cargo.toml index 42d5cc816..ec8c942dd 100644 --- a/packages/d2b-provider-process/Cargo.toml +++ b/packages/d2b-provider-process/Cargo.toml @@ -27,10 +27,10 @@ d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-boot d2b-provider-volume-virtiofs = { path = "../d2b-provider-volume-virtiofs", version = "0.0.0-bootstrap" } async-trait = "0.1" parking_lot = "0.12" -rustix = { version = "0.38", features = ["std", "process"] } +rustix = { workspace = true, features = ["std", "process"] } serde = { workspace = true } serde_json = { workspace = true } -sha2 = "0.10" +sha2 = { workspace = true } tokio = { workspace = true, features = ["fs", "macros", "rt", "sync", "time"] } tracing = "0.1" diff --git a/packages/d2b-provider-user/Cargo.toml b/packages/d2b-provider-user/Cargo.toml index e42fe0c50..8200e3326 100644 --- a/packages/d2b-provider-user/Cargo.toml +++ b/packages/d2b-provider-user/Cargo.toml @@ -22,7 +22,7 @@ d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-boot d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } nix = { version = "0.29", features = ["user"] } serde_json.workspace = true -sha2 = "0.10" +sha2 = { workspace = true } tracing = "0.1" parking_lot = "0.12" diff --git a/packages/d2b-telemetry/Cargo.toml b/packages/d2b-telemetry/Cargo.toml index 597f735f7..16e5845cf 100644 --- a/packages/d2b-telemetry/Cargo.toml +++ b/packages/d2b-telemetry/Cargo.toml @@ -10,7 +10,7 @@ d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0- d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } serde = { workspace = true } serde_json = { workspace = true } -sha2 = "0.10" +sha2 = { workspace = true } # U33: this crate does not inherit `[workspace.lints]` (it carries its own lint # posture), but `clippy.toml` at the workspace root arms diff --git a/packages/d2b-unsafe-local-helper/Cargo.toml b/packages/d2b-unsafe-local-helper/Cargo.toml index c605332ce..d3e0373a7 100644 --- a/packages/d2b-unsafe-local-helper/Cargo.toml +++ b/packages/d2b-unsafe-local-helper/Cargo.toml @@ -26,7 +26,7 @@ nix = { version = "0.29", features = ["fs", "poll", "socket", "uio", "user", "si rustix = { workspace = true } serde.workspace = true serde_json.workspace = true -sha2 = "0.10" +sha2 = { workspace = true } socket2 = "0.5" tracing = "0.1" uzers = "0.12" diff --git a/packages/d2bd-runtime/Cargo.toml b/packages/d2bd-runtime/Cargo.toml index f4da19b29..cacaca15d 100644 --- a/packages/d2bd-runtime/Cargo.toml +++ b/packages/d2bd-runtime/Cargo.toml @@ -37,7 +37,7 @@ rustix = { workspace = true } semver = "1" serde.workspace = true serde_json.workspace = true -sha2 = "0.10" +sha2 = { workspace = true } socket2 = "0.5" tokio = { workspace = true, features = ["macros", "rt-multi-thread", "sync", "time", "net", "process", "fs", "io-util"] } tracing = "0.1" diff --git a/packages/d2bd/Cargo.toml b/packages/d2bd/Cargo.toml index 5cad7b554..235f01ab7 100644 --- a/packages/d2bd/Cargo.toml +++ b/packages/d2bd/Cargo.toml @@ -97,7 +97,7 @@ d2b-provider-shell-pool = { path = "../d2b-provider-shell-pool", version = "0.0. d2b-provider-shell-session = { path = "../d2b-provider-shell-session", version = "0.0.0-bootstrap" } protobuf = "3.7.2" serde.workspace = true -sha2 = "0.10" +sha2 = { workspace = true } tracing = "0.1" # v1.1.1 live-deploy fu9: stderr tracing subscriber for d2bd # so RUST_LOG=debug actually surfaces in journalctl. Without this From 6488d26a4e7cb84fb59e79f03a3821a6dee2f021 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:42:02 -0700 Subject: [PATCH 601/726] perf(d2b-broker): size frame receive buffers to the declared length --- changelog.d/w5-13-broker-frame-alloc.md | 3 + packages/d2b-broker/src/protocol.rs | 163 +++++++++++++++++++++++- 2 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 changelog.d/w5-13-broker-frame-alloc.md diff --git a/changelog.d/w5-13-broker-frame-alloc.md b/changelog.d/w5-13-broker-frame-alloc.md new file mode 100644 index 000000000..9cb5c7adb --- /dev/null +++ b/changelog.d/w5-13-broker-frame-alloc.md @@ -0,0 +1,3 @@ +### Fixed + +- The broker protocol receive path now peeks the 4-byte frame length prefix with `MSG_PEEK` and allocates exactly the declared frame size plus the prefix, instead of a fixed 1 MiB buffer per received frame; the same size-exact allocation applies to SCM_RIGHTS frame receipt, and sockets without `MSG_PEEK` support keep the fixed allocation. \ No newline at end of file diff --git a/packages/d2b-broker/src/protocol.rs b/packages/d2b-broker/src/protocol.rs index f04ef7812..dba3ebc75 100644 --- a/packages/d2b-broker/src/protocol.rs +++ b/packages/d2b-broker/src/protocol.rs @@ -1,11 +1,13 @@ use std::io; +use std::io::IoSliceMut; use std::os::fd::{AsFd, AsRawFd, OwnedFd, RawFd}; use std::path::Path; use std::time::Duration; +use nix::errno::Errno; use nix::sys::socket::{ AddressFamily, Backlog, MsgFlags, SockFlag, SockType, UnixAddr, accept4, bind, connect, listen, - recv, send, socket, + recv, recvmsg, send, socket, }; use serde::{Serialize, de::DeserializeOwned}; use tokio::io::unix::AsyncFd; @@ -108,6 +110,11 @@ pub fn send_json_frame_with_fds( /// prefix followed by the body, capped at [`MAX_FRAME_SIZE`]; returns /// `None` when the peer closed the socket empty. /// +/// The 4-byte length prefix is peeked with `MSG_PEEK` first, so the body +/// buffer is allocated to the declared frame size instead of the +/// [`MAX_FRAME_SIZE`] ceiling on every receive. A socket type without +/// `MSG_PEEK` support falls back to the fixed ceiling allocation. +/// /// # Errors /// /// Returns [`io::ErrorKind::UnexpectedEof`] for short frames and @@ -115,12 +122,77 @@ pub fn send_json_frame_with_fds( /// failures. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn recv_json_frame(fd: RawFd) -> io::Result> { + // Peek the 4-byte length prefix so the body buffer can be allocated to + // the declared frame size instead of the 1 MiB ceiling. `MSG_PEEK` does + // not consume the frame, and a `SOCK_SEQPACKET` receive is atomic, so + // the peeked length is exactly the length the receive below gets. + let mut prefix = [0_u8; 4]; + let peeked = { + let mut iov = [IoSliceMut::new(&mut prefix)]; + match recvmsg::<()>(fd, &mut iov, None, MsgFlags::MSG_PEEK) { + Ok(message) => message.bytes, + // A socket type without `MSG_PEEK` support keeps the fixed + // ceiling allocation; the receive itself is unchanged. (`ENOTSUP` + // and `EOPNOTSUPP` are the same errno on Linux.) + Err(err) if matches!(err, Errno::EINVAL | Errno::ENOTSUP) => { + return recv_json_frame_fixed(fd); + } + Err(err) => return Err(io_error(err)), + } + }; + if peeked == 0 { + // The peer closed the socket empty; a queued zero-length packet is + // reported as closed exactly like the fixed path reports it. + return Ok(None); + } + if peeked < 4 { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "frame shorter than 4-byte length prefix", + )); + } + let declared = u32::from_le_bytes(prefix) as usize; + if declared > MAX_FRAME_SIZE { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "declared frame length exceeds 1 MiB maximum", + )); + } + + let mut buffer = vec![0_u8; declared + 4]; + let (bytes, truncated) = { + // The receive borrows the iov (and through it the buffer) for the + // lifetime of the returned message, so the message's fields are + // copied out inside this scope and the buffer borrow ends here. + let mut iov = [IoSliceMut::new(&mut buffer)]; + let message = recvmsg::<()>(fd, &mut iov, None, MsgFlags::empty()).map_err(io_error)?; + (message.bytes, message.flags.contains(MsgFlags::MSG_TRUNC)) + }; + if bytes == 0 { + return Ok(None); + } + if bytes < 4 { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "frame shorter than 4-byte length prefix", + )); + } + // An exact-size buffer truncates a packet larger than its declared + // prefix+body; refuse it the way the fixed path refuses a length + // mismatch, instead of decoding a truncated frame. + decode_frame(&buffer[..bytes], declared, truncated) +} + +/// The fixed-ceiling receive used when the socket type does not support +/// `MSG_PEEK`: one `MAX_FRAME_SIZE + 4` allocation per frame, the original +/// receive path unchanged. +#[allow(clippy::disallowed_methods, reason = "synchronous path")] +fn recv_json_frame_fixed(fd: RawFd) -> io::Result> { let mut buffer = vec![0_u8; MAX_FRAME_SIZE + 4]; let read = recv(fd, &mut buffer, MsgFlags::empty()).map_err(io_error)?; if read == 0 { return Ok(None); } - if read < 4 { return Err(io::Error::new( io::ErrorKind::UnexpectedEof, @@ -128,34 +200,117 @@ pub fn recv_json_frame(fd: RawFd) -> io::Result> )); } let declared = u32::from_le_bytes(buffer[..4].try_into().expect("prefix length")) as usize; + decode_frame(&buffer[..read], declared, false) +} + +/// Validate a received frame against its declared length and decode it. +/// +/// `truncated` reports a packet cut short by an undersized receive buffer +/// (`MSG_TRUNC`), which the fixed ceiling path cannot produce but the +/// exact-size path can. +fn decode_frame( + frame: &[u8], + declared: usize, + truncated: bool, +) -> io::Result> { if declared > MAX_FRAME_SIZE { return Err(io::Error::new( io::ErrorKind::InvalidData, "declared frame length exceeds 1 MiB maximum", )); } - if declared != read - 4 { + if truncated || declared != frame.len() - 4 { return Err(io::Error::new( io::ErrorKind::InvalidData, "frame length prefix does not match seqpacket payload size", )); } - serde_json::from_slice(&buffer[4..read]) + serde_json::from_slice(&frame[4..]) .map(Some) .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err)) } /// Receive one JSON frame and its close-on-exec SCM_RIGHTS attachments. /// +/// The 4-byte length prefix is peeked with `MSG_PEEK` first, so the payload +/// buffer is allocated to the declared frame size instead of the +/// [`MAX_FRAME_SIZE`] ceiling. The peek passes no control buffer, so no +/// descriptor is installed and the frame's SCM_RIGHTS attachment is still +/// delivered by the receive below. A socket type without `MSG_PEEK` support +/// falls back to the fixed ceiling allocation. +/// /// Request-side fd ownership is explicit: successful receipt transfers every /// descriptor into an [`std::os::fd::OwnedFd`], while malformed frames and /// decode failures close all descriptors before returning. +#[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn recv_json_frame_with_fds( fd: RawFd, +) -> io::Result)>> { + // Peek the 4-byte length prefix so the payload buffer can be allocated + // to the declared frame size instead of the 1 MiB ceiling. `MSG_PEEK` + // does not consume the frame, and a `SOCK_SEQPACKET` receive is atomic, + // so the peeked length is exactly the length the receive below gets. + let mut prefix = [0_u8; 4]; + let peeked = { + let mut iov = [IoSliceMut::new(&mut prefix)]; + match recvmsg::<()>(fd, &mut iov, None, MsgFlags::MSG_PEEK) { + Ok(message) => message.bytes, + // A socket type without `MSG_PEEK` support keeps the fixed + // ceiling allocation; the receive itself is unchanged. (`ENOTSUP` + // and `EOPNOTSUPP` are the same errno on Linux.) + Err(err) if matches!(err, Errno::EINVAL | Errno::ENOTSUP) => { + return recv_json_frame_with_fds_fixed(fd); + } + Err(err) => return Err(io_error(err)), + } + }; + // A zero-length peek is either a closed socket or a zero-length packet, + // which may still carry SCM_RIGHTS: the receive below disambiguates the + // two exactly like the fixed path, so the zero-length packet needs no + // payload buffer. + let payload_capacity = if peeked == 0 { + 0 + } else { + if peeked < 4 { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "frame shorter than 4-byte length prefix", + )); + } + let declared = u32::from_le_bytes(prefix) as usize; + if declared > MAX_FRAME_SIZE { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "invalid SCM_RIGHTS frame length", + )); + } + declared + 4 + }; + let (buffer, raw_fds) = + crate::fd_passing::recv_fds_with_capacity_allow_empty(fd, payload_capacity) + .map_err(fd_passing_error)?; + decode_fds_frame(buffer, raw_fds) +} + +/// The fixed-ceiling receive used when the socket type does not support +/// `MSG_PEEK`: one `MAX_FRAME_SIZE + 4` allocation per frame, the original +/// receive path unchanged. +fn recv_json_frame_with_fds_fixed( + fd: RawFd, ) -> io::Result)>> { let (buffer, raw_fds) = crate::fd_passing::recv_fds_with_capacity_allow_empty(fd, MAX_FRAME_SIZE + 4) .map_err(fd_passing_error)?; + decode_fds_frame(buffer, raw_fds) +} + +/// Validate a received SCM_RIGHTS frame against its declared length, close +/// every descriptor on a malformed frame or decode failure, and decode the +/// body. +fn decode_fds_frame( + buffer: Vec, + raw_fds: Vec, +) -> io::Result)>> { if buffer.is_empty() { if raw_fds.is_empty() { return Ok(None); From 8de97517bdab5e77d6564bcd744b37e579d6e799 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:43:29 -0700 Subject: [PATCH 602/726] fix(d2b-core): surface network intent parse failures as manifest-parse-error Network spec parse failures inside the trusted-bundle network path were silently dropped (from_value(value).ok() in find_network_spec and a continue-on-parse-error in build_resource_network_intents), so a producer-side spec drift vanished every intent for that network and surfaced only as an opaque intent-not-found refusal at apply time. find_network_spec and build_resource_network_intents now return Result with Error::manifest_parse_error("resource-bundle.json", reason) on parse failure; the six resolve_network_*_intent methods return Result, Error>; from_parsed_artifacts propagates the error (its embedded-caller variant keeps the documented absent-data posture with a debug assertion); all call sites in d2bd composition.rs, the NetworkIntentSource trait and its two impls, the KernelNetworkBroker consumers, and the family operation handlers are migrated, journaling the manifest-parse-error reason where the closed local refusal surface cannot carry it. --- .../w6-06-network-intent-parse-error.md | 13 + docs/reference/manifest-bundle.md | 5 + packages/d2b-core/src/bundle_resolver.rs | 398 ++++++++++++++---- .../d2b-provider-network-local/src/broker.rs | 100 +++-- .../src/operations.rs | 16 + packages/d2bd/src/composition.rs | 36 +- packages/d2bd/src/shared_provider_effects.rs | 2 +- 7 files changed, 443 insertions(+), 127 deletions(-) create mode 100644 changelog.d/w6-06-network-intent-parse-error.md diff --git a/changelog.d/w6-06-network-intent-parse-error.md b/changelog.d/w6-06-network-intent-parse-error.md new file mode 100644 index 000000000..f6579659e --- /dev/null +++ b/changelog.d/w6-06-network-intent-parse-error.md @@ -0,0 +1,13 @@ +# `w6-06-network-intent-parse-error.md` + +### Fixed + +- Network spec parse failures in the trusted-bundle network path now surface + as `manifest-parse-error` instead of an opaque intent-not-found refusal. + The six `resolve_network_*_intent` resolver methods return a typed error + when a Network row's spec cannot be parsed (the daemon and the + Network-local provider keep their closed refusal codes but journal the + manifest-parse-error reason), and the bulk fixture-intent builder fails + closed on the same drift instead of silently dropping every intent for + the affected network, so a producer-side spec drift is diagnosable at + apply time. \ No newline at end of file diff --git a/docs/reference/manifest-bundle.md b/docs/reference/manifest-bundle.md index 5788d9ffa..ffe3cc00d 100644 --- a/docs/reference/manifest-bundle.md +++ b/docs/reference/manifest-bundle.md @@ -45,6 +45,11 @@ The current authority is the Zone Resource store and authenticated session. The current line is a clean break from v1/v2 host state: these artifacts do not promise old-path adoption, data retention, or state conversion. +A Network row in a Zone resource bundle whose spec does not parse is a +producer-side drift: the resolver refuses with the typed +`manifest-parse-error` kind instead of reporting the intent as absent, so +the daemon journal names the artifact and the parse reason. + ## Versioning | Field | Scope | Rule | diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 33cfa7246..9f017773f 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -1400,7 +1400,7 @@ impl BundleResolver { manifest, }, false, - ); + )?; resolver.zone_topology = zone_topology; Ok(resolver) } @@ -1438,7 +1438,29 @@ impl BundleResolver { .unwrap_or_default() }) .collect(); - Self::from_parsed_artifacts( + let resource_network_intents = + match build_resource_network_intents(&zone_resource_bundles, true) { + Ok(maps) => maps, + Err(error) => { + debug_assert!( + false, + "zone resource bundle Network spec parse failed: {error}" + ); + // Documented precondition violation (verified per-Zone + // resource-bundle bytes): release builds treat the + // violation as absent data rather than panicking, so the + // resource network intents degrade to empty maps. + ( + BTreeMap::new(), + BTreeMap::new(), + BTreeMap::new(), + BTreeMap::new(), + BTreeMap::new(), + BTreeMap::new(), + ) + } + }; + Self::from_parsed_artifacts_with_network_intents( bundle, bundle_hash, ParsedBundleArtifacts { @@ -1458,6 +1480,7 @@ impl BundleResolver { manifest, }, true, + resource_network_intents, ) } @@ -1466,6 +1489,27 @@ impl BundleResolver { bundle_hash: String, artifacts: ParsedBundleArtifacts, include_fixture_network_intents: bool, + ) -> Result { + let resource_network_intents = build_resource_network_intents( + &artifacts.zone_resource_bundles, + include_fixture_network_intents, + )?; + Ok(Self::from_parsed_artifacts_with_network_intents( + bundle, + bundle_hash, + artifacts, + include_fixture_network_intents, + resource_network_intents, + )) + } + + #[allow(clippy::too_many_arguments)] + fn from_parsed_artifacts_with_network_intents( + bundle: Bundle, + bundle_hash: String, + artifacts: ParsedBundleArtifacts, + include_fixture_network_intents: bool, + resource_network_intents: ResolvedNetworkIntentMaps, ) -> Self { let ParsedBundleArtifacts { host, @@ -1531,7 +1575,7 @@ impl BundleResolver { resource_route_intents, resource_sysctl_intents, resource_hosts_intents, - ) = build_resource_network_intents(&zone_resource_bundles, include_fixture_network_intents); + ) = resource_network_intents; let mut nft_projection_intents = nft_projection_intents; nft_projection_intents.extend(resource_nft_projection_intents); let mut ownership_marker_intents = ownership_marker_intents; @@ -1718,28 +1762,41 @@ impl BundleResolver { } /// Resolve a Network bridge row from an admitted UID-bound reference. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. pub fn resolve_network_bridge_intent( &self, id: &str, provenance: &NetworkProvenance, - ) -> Option { - let parts = parse_network_intent_ref(id)?; + ) -> Result, Error> { + let Some(parts) = parse_network_intent_ref(id) else { + return Ok(None); + }; if parts.kind != NetworkIntentKind::Bridge || parts.zone_uid != *provenance.zone_uid() || parts.network_uid != *provenance.network_uid() { - return None; + return Ok(None); } - let spec = self.find_network_spec(&parts)?; - let role = match parts.variant.as_deref() { - Some("uplink") => NetworkIfRole::UplinkBridge, - Some("lan") => NetworkIfRole::LanBridge, - _ => return None, + let Some(spec) = self.find_network_spec(&parts)? else { + return Ok(None); + }; + let Some(role) = (match parts.variant.as_deref() { + Some("uplink") => Some(NetworkIfRole::UplinkBridge), + Some("lan") => Some(NetworkIfRole::LanBridge), + _ => None, + }) else { + return Ok(None); + }; + let Some(bridge_ifname) = + derive_network_ifname(provenance.zone_uid(), provenance.network_uid(), role, None).ok() + else { + return Ok(None); + }; + let Some(variant) = parts.variant.as_deref() else { + return Ok(None); }; - let bridge_ifname = - derive_network_ifname(provenance.zone_uid(), provenance.network_uid(), role, None) - .ok()?; - let variant = parts.variant.as_deref()?; let ownership_marker = format!( "d2b managed: {}", d2b_contracts_resource::v3::derive_network_ownership_marker( @@ -1747,7 +1804,7 @@ impl BundleResolver { &format!("bridge:{variant}"), ) ); - Some(ResolvedBridgeIntent { + Ok(Some(ResolvedBridgeIntent { intent_id: id.to_owned(), scope_label: network_scope(provenance), bridge_ifname, @@ -1764,53 +1821,70 @@ impl BundleResolver { }, provenance: Some(provenance.clone()), ownership_marker: Some(ownership_marker), - }) + })) } /// Resolve a Network ownership marker row from an admitted reference. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. pub fn resolve_network_marker_intent( &self, id: &str, provenance: &NetworkProvenance, - ) -> Option { - let parts = parse_network_intent_ref(id)?; + ) -> Result, Error> { + let Some(parts) = parse_network_intent_ref(id) else { + return Ok(None); + }; if parts.kind != NetworkIntentKind::Marker || parts.zone_uid != *provenance.zone_uid() || parts.network_uid != *provenance.network_uid() { - return None; + return Ok(None); + } + if self.find_network_spec(&parts)?.is_none() { + return Ok(None); } - self.find_network_spec(&parts)?; let marker = d2b_contracts_resource::v3::derive_network_ownership_marker(provenance, "firewall"); - Some(ResolvedOwnershipMarkerIntent { + Ok(Some(ResolvedOwnershipMarkerIntent { intent_id: id.to_owned(), marker, provenance: Some(provenance.clone()), - }) + })) } /// Resolve a Network firewall projection from an admitted reference. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. pub fn resolve_network_projection_intent( &self, id: &str, provenance: &NetworkProvenance, - ) -> Option { - let parts = parse_network_intent_ref(id)?; + ) -> Result, Error> { + let Some(parts) = parse_network_intent_ref(id) else { + return Ok(None); + }; if parts.kind != NetworkIntentKind::Firewall || parts.zone_uid != *provenance.zone_uid() || parts.network_uid != *provenance.network_uid() { - return None; + return Ok(None); } - self.find_network_spec(&parts)?; - let uplink = derive_network_ifname( + if self.find_network_spec(&parts)?.is_none() { + return Ok(None); + } + let Some(uplink) = derive_network_ifname( provenance.zone_uid(), provenance.network_uid(), NetworkIfRole::UplinkBridge, None, ) - .ok()?; + .ok() + else { + return Ok(None); + }; let marker_id = format!( "network-marker:{}:{}:{}", provenance.zone_uid().as_str(), @@ -1824,31 +1898,40 @@ impl BundleResolver { "table inet d2b {{\n chain \"{chain}\" {{ comment \"d2b managed: {marker}\";\n ct state established,related accept comment \"d2b managed: {marker}\";\n iifname \"{}\" ct state new accept comment \"d2b managed: {marker}\";\n }}\n}}\n", uplink.as_str() ); - Some(ResolvedNftablesProjectionIntent { + Ok(Some(ResolvedNftablesProjectionIntent { intent_id: id.to_owned(), scope_label: network_scope(provenance), desired_hash: stable_digest(&script_body), script_body, ownership_marker_intent_ref: marker_id, provenance: Some(provenance.clone()), - }) + })) } /// Resolve a Network route row from an admitted UID-bound reference. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. pub fn resolve_network_route_intent( &self, id: &str, provenance: &NetworkProvenance, - ) -> Option { - let parts = parse_network_intent_ref(id)?; + ) -> Result, Error> { + let Some(parts) = parse_network_intent_ref(id) else { + return Ok(None); + }; if parts.kind != NetworkIntentKind::Route || parts.zone_uid != *provenance.zone_uid() || parts.network_uid != *provenance.network_uid() { - return None; + return Ok(None); } - let spec = self.find_network_spec(&parts)?; - let index = parts.index?; + let Some(spec) = self.find_network_spec(&parts)? else { + return Ok(None); + }; + let Some(index) = parts.index else { + return Ok(None); + }; let destinations = if spec.routing().host_blocklist().is_empty() { vec![spec.lan_cidr().as_str().to_owned()] } else { @@ -1858,14 +1941,19 @@ impl BundleResolver { .map(|cidr| cidr.as_str().to_owned()) .collect::>() }; - let destination = destinations.get(index)?.clone(); - let bridge = derive_network_ifname( + let Some(destination) = destinations.get(index).cloned() else { + return Ok(None); + }; + let Some(bridge) = derive_network_ifname( provenance.zone_uid(), provenance.network_uid(), NetworkIfRole::UplinkBridge, None, ) - .ok()?; + .ok() + else { + return Ok(None); + }; let via = network_cidr_host_address(spec.uplink_cidr().as_str(), 2); let route_spec = format!( "{destination}{} dev {} table main", @@ -1883,7 +1971,7 @@ impl BundleResolver { &format!("route:{route_name}"), ) ); - Some(ResolvedRouteIntent { + Ok(Some(ResolvedRouteIntent { intent_id: id.to_owned(), route_spec, destination, @@ -1894,42 +1982,57 @@ impl BundleResolver { route_name: Some(route_name), provenance: Some(provenance.clone()), ownership_marker: Some(marker), - }) + })) } /// Resolve a Network sysctl row from an admitted UID-bound reference. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. pub fn resolve_network_sysctl_intent( &self, id: &str, provenance: &NetworkProvenance, - ) -> Option { - let parts = parse_network_intent_ref(id)?; + ) -> Result, Error> { + let Some(parts) = parse_network_intent_ref(id) else { + return Ok(None); + }; if parts.kind != NetworkIntentKind::Sysctl || parts.zone_uid != *provenance.zone_uid() || parts.network_uid != *provenance.network_uid() { - return None; + return Ok(None); } - self.find_network_spec(&parts)?; - let role = match parts.variant.as_deref() { - Some("lan") => NetworkIfRole::LanBridge, - Some("uplink") => NetworkIfRole::UplinkBridge, - _ => return None, + if self.find_network_spec(&parts)?.is_none() { + return Ok(None); + } + let Some(role) = (match parts.variant.as_deref() { + Some("lan") => Some(NetworkIfRole::LanBridge), + Some("uplink") => Some(NetworkIfRole::UplinkBridge), + _ => None, + }) else { + return Ok(None); }; - let ifname = - derive_network_ifname(provenance.zone_uid(), provenance.network_uid(), role, None) - .ok()?; - let key = parts.key.as_deref()?; - let value = match key { - "disable-ipv6" => "1", - "accept-ra" | "autoconf" => "0", - _ => return None, + let Some(ifname) = + derive_network_ifname(provenance.zone_uid(), provenance.network_uid(), role, None).ok() + else { + return Ok(None); + }; + let Some(key) = parts.key.as_deref() else { + return Ok(None); + }; + let Some(value) = (match key { + "disable-ipv6" => Some("1"), + "accept-ra" | "autoconf" => Some("0"), + _ => None, + }) else { + return Ok(None); }; let marker = d2b_contracts_resource::v3::derive_network_ownership_marker( provenance, &format!("sysctl:{key}"), ); - Some(ResolvedSysctlIntent { + Ok(Some(ResolvedSysctlIntent { intent_id: id.to_owned(), key: format!( "net.ipv6.conf.{}.{}", @@ -1939,23 +2042,30 @@ impl BundleResolver { value: value.to_owned(), provenance: Some(provenance.clone()), ownership_marker: Some(marker), - }) + })) } /// Resolve a Network hosts projection from an admitted reference. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. pub fn resolve_network_hosts_intent( &self, id: &str, provenance: &NetworkProvenance, - ) -> Option { - let parts = parse_network_intent_ref(id)?; + ) -> Result, Error> { + let Some(parts) = parse_network_intent_ref(id) else { + return Ok(None); + }; if parts.kind != NetworkIntentKind::Hosts || parts.zone_uid != *provenance.zone_uid() || parts.network_uid != *provenance.network_uid() { - return None; + return Ok(None); } - let spec = self.find_network_spec(&parts)?; + let Some(spec) = self.find_network_spec(&parts)? else { + return Ok(None); + }; let marker = d2b_contracts_resource::v3::derive_network_ownership_marker(provenance, "hosts"); let managed_block = format!( @@ -1964,7 +2074,7 @@ impl BundleResolver { spec.lan_cidr().as_str(), spec.uplink_cidr().as_str() ); - Some(ResolvedHostsIntent { + Ok(Some(ResolvedHostsIntent { intent_id: id.to_owned(), path: PathBuf::from("/etc/hosts"), managed_block, @@ -1973,15 +2083,18 @@ impl BundleResolver { mode: 0o644, provenance: Some(provenance.clone()), ownership_marker: Some(marker), - }) + })) } - fn find_network_spec(&self, parts: &ParsedNetworkIntentRef) -> Option { - self.parsed_zone_resources.values().find_map(|bundle| { + fn find_network_spec( + &self, + parts: &ParsedNetworkIntentRef, + ) -> Result, Error> { + for bundle in self.parsed_zone_resources.values() { if bundle.zone_uid.as_ref() != Some(&parts.zone_uid) { - return None; + continue; } - let resource = bundle.resources.iter().find(|resource| { + let Some(resource) = bundle.resources.iter().find(|resource| { resource.resource_type().as_str() == "Network" && network_name_token(resource.metadata().name().as_str()) == parts.network_name && resource @@ -1995,14 +2108,30 @@ impl BundleResolver { .map(d2b_contracts_resource::v3::ResourceUid::as_str) == Some(parts.network_uid.as_str()) }) + }) else { + continue; + }; + let mut value = serde_json::to_value(resource.spec()).map_err(|error| { + Error::manifest_parse_error("resource-bundle.json", error.to_string()) + })?; + let object = value.as_object_mut().ok_or_else(|| { + Error::manifest_parse_error( + "resource-bundle.json", + "Network resource spec is not an object", + ) })?; - let mut value = serde_json::to_value(resource.spec()).ok()?; - let object = value.as_object_mut()?; for field in ["providerRef", "updatePolicy", "provider"] { object.remove(field); } - serde_json::from_value(value).ok() - }) + let spec = serde_json::from_value(value).map_err(|error| { + Error::manifest_parse_error( + "resource-bundle.json", + format!("Network resource spec is invalid: {error}"), + ) + })?; + return Ok(Some(spec)); + } + Ok(None) } pub fn find_nm_unmanaged_intent(&self, id: &str) -> Option<&ResolvedNmUnmanagedIntent> { @@ -3366,19 +3495,19 @@ type ResolvedNetworkIntentMaps = ( fn build_resource_network_intents( bundles: &BTreeMap>, include_fixture_network_intents: bool, -) -> ResolvedNetworkIntentMaps { +) -> Result { // Live bundle loading resolves Network rows only after d2bd supplies the // committed resource UID and generation. Test-only parsed fixtures may // carry a `networkUid` annotation for exercising the row builder. if !include_fixture_network_intents { - return ( + return Ok(( BTreeMap::new(), BTreeMap::new(), BTreeMap::new(), BTreeMap::new(), BTreeMap::new(), BTreeMap::new(), - ); + )); } let mut nft_projections = BTreeMap::new(); let mut markers = BTreeMap::new(); @@ -3409,17 +3538,24 @@ fn build_resource_network_intents( continue; }; let name = resource.metadata().name().as_str(); - let mut spec_value = - serde_json::to_value(resource.spec()).unwrap_or_else(|_| serde_json::json!({})); - let Some(spec_object) = spec_value.as_object_mut() else { - continue; - }; + let mut spec_value = serde_json::to_value(resource.spec()).map_err(|error| { + Error::manifest_parse_error("resource-bundle.json", error.to_string()) + })?; + let spec_object = spec_value.as_object_mut().ok_or_else(|| { + Error::manifest_parse_error( + "resource-bundle.json", + "Network resource spec is not an object", + ) + })?; for field in ["providerRef", "updatePolicy", "provider"] { spec_object.remove(field); } - let Ok(spec) = serde_json::from_value::(spec_value) else { - continue; - }; + let spec = serde_json::from_value::(spec_value).map_err(|error| { + Error::manifest_parse_error( + "resource-bundle.json", + format!("Network resource spec is invalid: {error}"), + ) + })?; let Some(lan_bridge) = derive_network_ifname(&zone_uid, &network_uid, NetworkIfRole::LanBridge, None).ok() else { @@ -3621,7 +3757,7 @@ fn build_resource_network_intents( } } - (nft_projections, markers, bridges, routes, sysctls, hosts) + Ok((nft_projections, markers, bridges, routes, sysctls, hosts)) } // --------------------------------------------------------------- @@ -6925,6 +7061,7 @@ mod tests { }, include_fixture_network_intents, ) + .expect("fixture network intents parse") } fn current_user_bundle_policy() -> BundleVerifyPolicy { @@ -7644,6 +7781,22 @@ mod tests { BoundedToken::parse("net-vm-base").unwrap(), ) .unwrap(); + network_resource_bundle_bytes_with_spec( + zone, + zone_uid, + network_uid, + network_name, + serde_json::to_value(&spec).unwrap(), + ) + } + + fn network_resource_bundle_bytes_with_spec( + zone: &str, + zone_uid: &ResourceUid, + network_uid: &ResourceUid, + network_name: &str, + spec: serde_json::Value, + ) -> Vec { let mut annotations = BTreeMap::new(); annotations.insert("networkUid".to_owned(), network_uid.as_str().to_owned()); let resource = BundleResource::new( @@ -7757,13 +7910,15 @@ mod tests { let lan_id = intent_id_network_bridge_uids(&zone_uid, &network_uid, "work-net", false); let lan = resolver .resolve_network_bridge_intent(&lan_id, &provenance) - .expect("resolved LAN bridge"); + .expect("resolved LAN bridge") + .expect("LAN bridge intent present"); assert_eq!(lan.ipv4_address, None, "the LAN bridge carries no address"); let uplink_id = intent_id_network_bridge_uids(&zone_uid, &network_uid, "work-net", true); let uplink = resolver .resolve_network_bridge_intent(&uplink_id, &provenance) - .expect("resolved uplink bridge"); + .expect("resolved uplink bridge") + .expect("uplink bridge intent present"); assert_eq!( uplink.ipv4_address.as_ref().map(Ipv4Cidr::as_str), Some("192.0.2.1/30"), @@ -7773,7 +7928,8 @@ mod tests { let route_id = intent_id_network_route_uids(&zone_uid, &network_uid, "work-net", 0); let route = resolver .resolve_network_route_intent(&route_id, &provenance) - .expect("resolved Network route"); + .expect("resolved Network route") + .expect("route intent present"); assert_eq!( route.via.as_deref(), Some("192.0.2.2"), @@ -7788,6 +7944,60 @@ mod tests { let _ = fs::remove_dir_all(root); } + #[test] + fn network_spec_parse_failure_surfaces_as_manifest_parse_error() { + let root = test_root("network-spec-parse-error"); + let zone_uid = + ResourceUid::parse("323e4567-e89b-42d3-a456-426614174002").expect("zone uid"); + let network_uid = + ResourceUid::parse("123e4567-e89b-42d3-a456-426614174000").expect("network uid"); + let provenance = NetworkProvenance::new( + zone_uid.clone(), + network_uid.clone(), + d2b_contracts_resource::v3::ResourceGeneration::new(4).unwrap(), + d2b_contracts_resource::v3::ResourceGeneration::new(7).unwrap(), + d2b_contracts_resource::v3::ResourceBundleGenerationId::parse( + "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + ) + .unwrap(), + ); + let mut resolver = build_personal_dev_bundle(&root); + // A Network row whose spec is not a valid NetworkSpec is a + // producer-side drift: the resolver must refuse with the typed + // manifest-parse-error instead of reporting the intent as absent. + let bytes = network_resource_bundle_bytes_with_spec( + "work", + &zone_uid, + &network_uid, + "work-net", + serde_json::json!({ "lanCidr": "not-a-cidr" }), + ); + resolver + .zone_resource_bundles + .insert("work".to_owned(), bytes.clone()); + resolver.parsed_zone_resources.insert( + "work".to_owned(), + ResourceBundle::from_json(&bytes).expect("zone bundle parses"), + ); + + let lan_id = intent_id_network_bridge_uids(&zone_uid, &network_uid, "work-net", false); + let error = resolver + .resolve_network_bridge_intent(&lan_id, &provenance) + .expect_err("a malformed Network spec must refuse, not report the intent absent"); + assert_eq!( + error.kind(), + d2b_contracts::error::Kind::ManifestParseError, + "the refusal must carry the manifest-parse-error kind" + ); + assert_eq!( + error.code(), + 40, + "the refusal must carry the manifest-parse-error exit code" + ); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + let _ = fs::remove_dir_all(root); + } + #[test] fn resource_network_intents_use_uid_derived_kernel_names() { let zone_a = ResourceUid::parse("323e4567-e89b-42d3-a456-426614174002").expect("zone uid"); @@ -7820,7 +8030,8 @@ mod tests { ), ), ]); - let (_, _, bridges, routes, _, _) = build_resource_network_intents(&bundles, true); + let (_, _, bridges, routes, _, _) = + build_resource_network_intents(&bundles, true).expect("fixture network intents parse"); let first_bridge_id = intent_id_network_bridge_uids(&zone_a, &network_a, "same-name", false); let second_bridge_id = @@ -7897,7 +8108,8 @@ mod tests { let bridge_id = intent_id_network_bridge_uids(&zone_uid, &network_uid, "work-net", false); let bridge = resolver .resolve_network_bridge_intent(&bridge_id, &provenance) - .expect("resolved Network bridge"); + .expect("resolved Network bridge") + .expect("bridge intent present"); assert_eq!(bridge.provenance.as_ref(), Some(&provenance)); assert_eq!( bridge.ownership_marker.as_deref(), @@ -7916,7 +8128,8 @@ mod tests { let route_id = intent_id_network_route_uids(&zone_uid, &network_uid, "work-net", 0); let route = resolver .resolve_network_route_intent(&route_id, &provenance) - .expect("resolved Network route"); + .expect("resolved Network route") + .expect("route intent present"); assert_eq!(route.provenance.as_ref(), Some(&provenance)); assert_eq!( route.ownership_marker.as_deref(), @@ -7936,7 +8149,8 @@ mod tests { intent_id_network_ownership_marker_uids(&zone_uid, &network_uid, "work-net"); let marker = resolver .resolve_network_marker_intent(&marker_id, &provenance) - .expect("resolved Network ownership marker"); + .expect("resolved Network ownership marker") + .expect("ownership marker intent present"); assert_eq!(marker.provenance.as_ref(), Some(&provenance)); assert_eq!( marker.marker, diff --git a/packages/d2b-provider-network-local/src/broker.rs b/packages/d2b-provider-network-local/src/broker.rs index a6d53bd78..9a3224311 100644 --- a/packages/d2b-provider-network-local/src/broker.rs +++ b/packages/d2b-provider-network-local/src/broker.rs @@ -843,50 +843,68 @@ impl NetworkEffectPort for BrokerNetworkEffectPort { /// fence is daemon-supplied too. pub trait NetworkIntentSource: Send + Sync + 'static { /// Resolve one trusted Network bridge intent. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. fn resolve_bridge_intent( &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option; + ) -> Result, d2b_core::error::Error>; /// Resolve one trusted Network firewall projection intent. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. fn resolve_projection_intent( &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option; + ) -> Result, d2b_core::error::Error>; /// Resolve one trusted Network ownership marker intent. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. fn resolve_marker_intent( &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option; + ) -> Result, d2b_core::error::Error>; /// Find one trusted NetworkManager unmanaged intent. fn find_nm_unmanaged_intent(&self, intent_ref: &str) -> Option; /// Resolve one trusted Network route intent. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. fn resolve_route_intent( &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option; + ) -> Result, d2b_core::error::Error>; /// Resolve one trusted Network sysctl intent. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. fn resolve_sysctl_intent( &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option; + ) -> Result, d2b_core::error::Error>; /// Resolve one trusted hosts-file intent: a Network-hosts intent when /// `provenance` is supplied, a plain hosts intent otherwise. + /// + /// Returns `Ok(None)` when the reference does not name a trusted intent + /// and `Err` when the trusted Network spec fails to parse. fn resolve_hosts_intent( &self, intent_ref: &str, provenance: Option<&NetworkProvenance>, - ) -> Option; + ) -> Result, d2b_core::error::Error>; /// The installed bundle generation identity (KTD8). fn installed_generation_identity(&self) -> Option; @@ -918,7 +936,7 @@ impl NetworkIntentSource for ResolverNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { + ) -> Result, d2b_core::error::Error> { self.resolver .resolve_network_bridge_intent(intent_ref, provenance) } @@ -927,7 +945,7 @@ impl NetworkIntentSource for ResolverNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { + ) -> Result, d2b_core::error::Error> { self.resolver .resolve_network_projection_intent(intent_ref, provenance) } @@ -936,7 +954,7 @@ impl NetworkIntentSource for ResolverNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { + ) -> Result, d2b_core::error::Error> { self.resolver .resolve_network_marker_intent(intent_ref, provenance) } @@ -951,7 +969,7 @@ impl NetworkIntentSource for ResolverNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { + ) -> Result, d2b_core::error::Error> { self.resolver .resolve_network_route_intent(intent_ref, provenance) } @@ -960,7 +978,7 @@ impl NetworkIntentSource for ResolverNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { + ) -> Result, d2b_core::error::Error> { self.resolver .resolve_network_sysctl_intent(intent_ref, provenance) } @@ -969,12 +987,12 @@ impl NetworkIntentSource for ResolverNetworkIntentSource { &self, intent_ref: &str, provenance: Option<&NetworkProvenance>, - ) -> Option { + ) -> Result, d2b_core::error::Error> { match provenance { Some(provenance) => self .resolver .resolve_network_hosts_intent(intent_ref, provenance), - None => self.resolver.find_hosts_intent(intent_ref).cloned(), + None => Ok(self.resolver.find_hosts_intent(intent_ref).cloned()), } } @@ -1017,8 +1035,10 @@ impl NetworkIntentSource for LoaderNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { - let resolver = (self.load)()?; + ) -> Result, d2b_core::error::Error> { + let Some(resolver) = (self.load)() else { + return Ok(None); + }; resolver .resolve_network_bridge_intent(intent_ref, provenance) } @@ -1027,8 +1047,10 @@ impl NetworkIntentSource for LoaderNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { - let resolver = (self.load)()?; + ) -> Result, d2b_core::error::Error> { + let Some(resolver) = (self.load)() else { + return Ok(None); + }; resolver .resolve_network_projection_intent(intent_ref, provenance) } @@ -1037,8 +1059,10 @@ impl NetworkIntentSource for LoaderNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { - let resolver = (self.load)()?; + ) -> Result, d2b_core::error::Error> { + let Some(resolver) = (self.load)() else { + return Ok(None); + }; resolver .resolve_network_marker_intent(intent_ref, provenance) } @@ -1054,8 +1078,10 @@ impl NetworkIntentSource for LoaderNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { - let resolver = (self.load)()?; + ) -> Result, d2b_core::error::Error> { + let Some(resolver) = (self.load)() else { + return Ok(None); + }; resolver .resolve_network_route_intent(intent_ref, provenance) } @@ -1064,8 +1090,10 @@ impl NetworkIntentSource for LoaderNetworkIntentSource { &self, intent_ref: &str, provenance: &NetworkProvenance, - ) -> Option { - let resolver = (self.load)()?; + ) -> Result, d2b_core::error::Error> { + let Some(resolver) = (self.load)() else { + return Ok(None); + }; resolver .resolve_network_sysctl_intent(intent_ref, provenance) } @@ -1074,12 +1102,14 @@ impl NetworkIntentSource for LoaderNetworkIntentSource { &self, intent_ref: &str, provenance: Option<&NetworkProvenance>, - ) -> Option { - let resolver = (self.load)()?; + ) -> Result, d2b_core::error::Error> { + let Some(resolver) = (self.load)() else { + return Ok(None); + }; match provenance { Some(provenance) => resolver .resolve_network_hosts_intent(intent_ref, provenance), - None => resolver.find_hosts_intent(intent_ref).cloned(), + None => Ok(resolver.find_hosts_intent(intent_ref).cloned()), } } @@ -1198,6 +1228,7 @@ impl NetworkBroker for KernelNetworkBroker { .facets .intents .resolve_bridge_intent(intent_ref.as_str(), &provenance) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; self.invoke_kernel("create-bridge", &zone, resolved_bridge_payload(&intent)?)?; } @@ -1212,6 +1243,7 @@ impl NetworkBroker for KernelNetworkBroker { .facets .intents .resolve_bridge_intent(intent_ref.as_str(), &provenance) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; self.invoke_kernel("delete-bridge", &zone, resolved_bridge_payload(&intent)?)?; } @@ -1229,11 +1261,13 @@ impl NetworkBroker for KernelNetworkBroker { .facets .intents .resolve_projection_intent(context.projection_intent_ref().as_str(), &provenance) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; let marker = self .facets .intents .resolve_marker_intent(&intent.ownership_marker_intent_ref, &provenance) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; let installed = self .facets @@ -1290,6 +1324,7 @@ impl NetworkBroker for KernelNetworkBroker { .facets .intents .resolve_route_intent(intent_ref.as_str(), &provenance) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; self.invoke_kernel( "apply-route", @@ -1308,6 +1343,7 @@ impl NetworkBroker for KernelNetworkBroker { .facets .intents .resolve_route_intent(intent_ref.as_str(), &provenance) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; self.invoke_kernel( "apply-route", @@ -1326,6 +1362,7 @@ impl NetworkBroker for KernelNetworkBroker { .facets .intents .resolve_sysctl_intent(intent_ref.as_str(), &provenance) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; self.invoke_kernel( "apply-sysctl", @@ -1354,6 +1391,7 @@ impl NetworkBroker for KernelNetworkBroker { .starts_with("network-hosts:") .then_some(&provenance), ) + .map_err(intent_source_error)? .ok_or(NetworkBrokerError::NetworkAdmissionMismatch)?; self.invoke_kernel( "update-hosts-file", @@ -1418,6 +1456,16 @@ impl NetworkBroker for KernelNetworkBroker { } } +/// Map a trusted-bundle Network spec parse failure onto the broker's closed +/// refusal surface, logging the manifest-parse-error reason. +fn intent_source_error(error: d2b_core::error::Error) -> NetworkBrokerError { + tracing::warn!( + error = %error, + "Network broker could not resolve a trusted bundle intent" + ); + NetworkBrokerError::NetworkAdmissionMismatch +} + /// The resolved bridge intent payload one bridge kernel invocation carries. fn resolved_bridge_payload(intent: &ResolvedBridgeIntent) -> Result { Ok(serde_json::json!({ diff --git a/packages/d2b-provider-network-local/src/operations.rs b/packages/d2b-provider-network-local/src/operations.rs index ed2026159..ac45470c5 100644 --- a/packages/d2b-provider-network-local/src/operations.rs +++ b/packages/d2b-provider-network-local/src/operations.rs @@ -372,6 +372,15 @@ fn kernel_bundle<'a>(ctx: &'a OperationCtx<'a>) -> Result<&'a BundleResolver, Op .ok_or_else(|| OperationFailure::new(KERNEL_SEAM_UNWIRED)) } +/// Map a trusted-bundle Network spec parse failure onto the family refusal +/// surface, keeping the manifest-parse-error reason in the detail. +fn intent_parse_failure(operation: &str, error: d2b_core::error::Error) -> OperationFailure { + OperationFailure::with_detail( + INTENT_MISMATCH, + format!("{operation}: trusted bundle Network spec parse failed: {error}"), + ) +} + /// The exact Network effect provenance one request's identity tuple names. /// /// Mirrors the retired arms' provenance derivation: the complete admitted @@ -518,6 +527,7 @@ impl OperationHandler for ApplyNftablesProjectionHandler { request.bundle_nft_projection_intent_ref.as_str(), &provenance, ) + .map_err(|error| intent_parse_failure("ApplyNftablesProjection", error))? .ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, @@ -529,6 +539,7 @@ impl OperationHandler for ApplyNftablesProjectionHandler { })?; let marker = bundle .resolve_network_marker_intent(&intent.ownership_marker_intent_ref, &provenance) + .map_err(|error| intent_parse_failure("ApplyNftablesProjection", error))? .ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, @@ -646,6 +657,7 @@ impl OperationHandler for ApplyRouteHandler { ); let intent = bundle .resolve_network_route_intent(request.bundle_route_intent_ref.as_str(), &provenance) + .map_err(|error| intent_parse_failure("ApplyRoute", error))? .ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, @@ -691,6 +703,7 @@ impl OperationHandler for ApplySysctlHandler { ); let intent = bundle .resolve_network_sysctl_intent(request.bundle_sysctl_intent_ref.as_str(), &provenance) + .map_err(|error| intent_parse_failure("ApplySysctl", error))? .ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, @@ -740,6 +753,7 @@ impl OperationHandler for CreateBridgeHandler { ); let intent = bundle .resolve_network_bridge_intent(request.bundle_bridge_intent_ref.as_str(), &provenance) + .map_err(|error| intent_parse_failure("CreateBridge", error))? .ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, @@ -781,6 +795,7 @@ impl OperationHandler for DeleteBridgeHandler { ); let intent = bundle .resolve_network_bridge_intent(request.bundle_bridge_intent_ref.as_str(), &provenance) + .map_err(|error| intent_parse_failure("DeleteBridge", error))? .ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, @@ -1000,6 +1015,7 @@ impl OperationHandler for UpdateHostsFileHandler { request.bundle_hosts_intent_ref.as_str(), &provenance, ) + .map_err(|error| intent_parse_failure("UpdateHostsFile", error))? .ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..b6c978f80 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -7257,6 +7257,18 @@ fn dispatch_device_usb_resource_request( } } +/// Map a trusted-bundle Network spec parse failure onto the resource +/// runtime refusal surface, logging the manifest-parse-error reason. +fn network_intent_parse_error( + error: d2b_core::error::Error, +) -> resource_runtime::ResourceRuntimeError { + tracing::warn!( + error = %error, + "Network effect context could not resolve a trusted bundle intent" + ); + resource_runtime::ResourceRuntimeError::ProviderPathUnavailable +} + pub(crate) fn resolve_network_effect_context( resource: &Value, resolver: &BundleResolver, @@ -7303,15 +7315,18 @@ pub(crate) fn resolve_network_effect_context( ); if resolver .resolve_network_bridge_intent(&bridge_id, &provenance) + .map_err(network_intent_parse_error)? .is_none() || resolver .resolve_network_bridge_intent(&uplink_bridge_id, &provenance) + .map_err(network_intent_parse_error)? .is_none() { return Err(resource_runtime::ResourceRuntimeError::ProviderPathUnavailable); } let projection = resolver .resolve_network_projection_intent(&projection_id, &provenance) + .map_err(network_intent_parse_error)? .ok_or(resource_runtime::ResourceRuntimeError::ProviderPathUnavailable)?; let nm_id = intent_id_nm_unmanaged_host(); if resolver.find_nm_unmanaged_intent(&nm_id).is_none() { @@ -7324,6 +7339,7 @@ pub(crate) fn resolve_network_effect_context( ); if resolver .resolve_network_hosts_intent(&hosts_id, &provenance) + .map_err(network_intent_parse_error)? .is_none() { return Err(resource_runtime::ResourceRuntimeError::ProviderPathUnavailable); @@ -7338,12 +7354,14 @@ pub(crate) fn resolve_network_effect_context( )) }) .collect::>(); - if route_ids.iter().any(|id| { - resolver + for id in &route_ids { + if resolver .resolve_network_route_intent(id.as_str(), &provenance) + .map_err(network_intent_parse_error)? .is_none() - }) { - return Err(resource_runtime::ResourceRuntimeError::ProviderPathUnavailable); + { + return Err(resource_runtime::ResourceRuntimeError::ProviderPathUnavailable); + } } let sysctl_ids = ["lan", "uplink"] .into_iter() @@ -7364,12 +7382,14 @@ pub(crate) fn resolve_network_effect_context( }) }) .collect::>(); - if sysctl_ids.iter().any(|id| { - resolver + for id in &sysctl_ids { + if resolver .resolve_network_sysctl_intent(id.as_str(), &provenance) + .map_err(network_intent_parse_error)? .is_none() - }) { - return Err(resource_runtime::ResourceRuntimeError::ProviderPathUnavailable); + { + return Err(resource_runtime::ResourceRuntimeError::ProviderPathUnavailable); + } } let generation = resolver .installed_generation_identity() diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 1364389fe..9bafa388e 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -3103,7 +3103,7 @@ mod tests { ); let intent = effects.intents.resolve_bridge_intent("bridge-0", &provenance); assert!( - intent.is_none(), + matches!(intent, Ok(None)), "a tampered bundle yields no intent:the effect refuses closed", ); }); From 8abd3c1baa1a7d444b58bf5a51b54b1eedb4180d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:47:29 -0700 Subject: [PATCH 603/726] refactor(d2b-core): encapsulate BundleResolver bundle artifacts behind accessors --- .../w5-05-bundle-resolver-encapsulation.md | 4 + packages/d2b-broker/src/ops/media.rs | 8 +- packages/d2b-broker/src/ops/state_dir.rs | 2 +- .../d2b-broker/src/ops/storage_contract.rs | 2 +- packages/d2b-broker/src/runtime.rs | 34 +++--- packages/d2b-core/src/bundle_resolver.rs | 109 +++++++++++++++--- .../d2b-core/tests/bundle_resolver_tamper.rs | 4 +- .../src/core_adapter.rs | 4 +- .../src/effects_service.rs | 6 +- .../src/operations.rs | 8 +- .../src/operations.rs | 2 +- .../d2b-provider-process/src/operations.rs | 6 +- .../d2b-provider-supervisor/src/broker.rs | 4 +- packages/d2bd-runtime/src/autostart.rs | 2 +- .../d2bd-runtime/src/kernel_module_check.rs | 4 +- .../d2bd-runtime/src/workload_dispatch.rs | 5 +- packages/d2bd-runtime/src/zone_authority.rs | 2 +- packages/d2bd/src/composition.rs | 30 ++--- packages/d2bd/src/process_provider_runtime.rs | 12 +- 19 files changed, 161 insertions(+), 87 deletions(-) create mode 100644 changelog.d/w5-05-bundle-resolver-encapsulation.md diff --git a/changelog.d/w5-05-bundle-resolver-encapsulation.md b/changelog.d/w5-05-bundle-resolver-encapsulation.md new file mode 100644 index 000000000..f7d4cb4f2 --- /dev/null +++ b/changelog.d/w5-05-bundle-resolver-encapsulation.md @@ -0,0 +1,4 @@ +### Fixed + +- BundleResolver now encapsulates its trusted bundle artifacts: the bundle, host, processes, storage, site, realm-workloads-launcher-v2, and manifest fields are private, read through typed accessors, and storage replacement goes through a single set_storage setter. All consumers ind2bd, d2bd-runtime, d2b-broker, and the provider crates now read through the accessors. +- The broker's storage-contract reconciliation now writes the resolved contract back via set_storage instead of mutating the resolver's storage field directly. \ No newline at end of file diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index c6f16377b..e3a1596a2 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -694,7 +694,7 @@ fn resolve_boot_source<'a>( vm: &str, ) -> Result<&'a QemuMediaSourceIntent, MediaOpError> { resolver - .host + .host() .qemu_media .as_ref() .and_then(|qemu_media| { @@ -930,7 +930,7 @@ fn select_unique_declared_physical_source<'a>( identity: &UsbPhysicalIdentity, attached_refs: Option<&BTreeSet>, ) -> Result<&'a QemuMediaSourceIntent, MediaOpError> { - let Some(qemu_media) = resolver.host.qemu_media.as_ref() else { + let Some(qemu_media) = resolver.host().qemu_media.as_ref() else { return Err(MediaOpError::MissingBundlePolicy); }; select_unique_declared_physical_source_from_sources( @@ -2108,7 +2108,7 @@ async fn image_has_loop_backing(sysfs_root: &Path, image_path: &Path) -> Result< fn registry_dir(resolver: &BundleResolver) -> Result { resolver - .host + .host() .qemu_media .as_ref() .map(|media| PathBuf::from(&media.registry_dir)) @@ -2117,7 +2117,7 @@ fn registry_dir(resolver: &BundleResolver) -> Result { fn rules_path(resolver: &BundleResolver) -> Result { resolver - .host + .host() .qemu_media .as_ref() .map(|media| PathBuf::from(&media.runtime_rules_path)) diff --git a/packages/d2b-broker/src/ops/state_dir.rs b/packages/d2b-broker/src/ops/state_dir.rs index d353d6b26..a49e402b7 100644 --- a/packages/d2b-broker/src/ops/state_dir.rs +++ b/packages/d2b-broker/src/ops/state_dir.rs @@ -484,7 +484,7 @@ pub(crate) fn resolver_with_swtpm_state_row(guest: &str) -> BundleResolver { // Storage travels on the same resolver: the production loader carries both // artifacts, and this fixture needs the trusted row and the Device scope // to resolve together. - resolver.storage = Some(storage); + resolver.set_storage(storage); resolver } diff --git a/packages/d2b-broker/src/ops/storage_contract.rs b/packages/d2b-broker/src/ops/storage_contract.rs index 40302dc16..f3318574b 100644 --- a/packages/d2b-broker/src/ops/storage_contract.rs +++ b/packages/d2b-broker/src/ops/storage_contract.rs @@ -589,7 +589,7 @@ mod tests { manifest(), BTreeMap::new(), ); - resolver.storage = Some(storage_contract); + resolver.set_storage(storage_contract); resolver } diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index e9597184f..25261f0e1 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -3868,7 +3868,7 @@ async fn dispatch_request_with_backend_and_request_fds( let resolver = require_resolver(resolver)?; let outcome = crate::ops::security_key::live_open_hidraw_security_key( &req, - &resolver.host.security_key_selectors, + &resolver.host().security_key_selectors, audit_log, ) .await @@ -4826,13 +4826,13 @@ async fn dispatch_request_with_backend_and_request_fds( let expected_hash = persisted_nft_hash() .await .map_err(|err| BrokerError::LiveHandler(err.to_string()))? - .or_else(|| resolver.host.nftables.table_hash_after_apply.clone()); + .or_else(|| resolver.host().nftables.table_hash_after_apply.clone()); crate::ops::nft::apply_with_coexistence( &exec, &nft_binary, &nft_script, - resolver.host.nftables.ownership_id.as_str(), - resolver.host.firewall_coexistence_policy.as_ref(), + resolver.host().nftables.ownership_id.as_str(), + resolver.host().firewall_coexistence_policy.as_ref(), expected_hash.as_deref(), ) .await @@ -4866,8 +4866,8 @@ async fn dispatch_request_with_backend_and_request_fds( crate::ops::nft::persist_live_nft_hash( &exec, &nft_binary, - &resolver.host.nftables.family, - &resolver.host.nftables.table, + &resolver.host().nftables.family, + &resolver.host().nftables.table, &nft_hash_sidecar_path(), ) .await @@ -6564,8 +6564,8 @@ impl DispatchBackend for LiveDispatchBackend { let destroy_script; let script_body = if destroy { destroy_script = render_nft_destroy_script( - &resolver.host.nftables.family, - &resolver.host.nftables.table, + &resolver.host().nftables.family, + &resolver.host().nftables.table, ); destroy_script.as_str() } else { @@ -6577,7 +6577,7 @@ impl DispatchBackend for LiveDispatchBackend { persisted_nft_hash() .await .map_err(|err| BrokerError::LiveHandler(err.to_string()))? - .or_else(|| resolver.host.nftables.table_hash_after_apply.clone()) + .or_else(|| resolver.host().nftables.table_hash_after_apply.clone()) }; let expected_hash = if destroy { None @@ -6589,7 +6589,7 @@ impl DispatchBackend for LiveDispatchBackend { &nft_binary, script_body, intent.ownership_id.as_str(), - resolver.host.firewall_coexistence_policy.as_ref(), + resolver.host().firewall_coexistence_policy.as_ref(), expected_hash, ) .await @@ -6623,8 +6623,8 @@ impl DispatchBackend for LiveDispatchBackend { crate::ops::nft::persist_live_nft_hash( &exec, &nft_binary, - &resolver.host.nftables.family, - &resolver.host.nftables.table, + &resolver.host().nftables.family, + &resolver.host().nftables.table, &nft_hash_sidecar_path(), ) .await @@ -6945,13 +6945,13 @@ impl DispatchBackend for LiveDispatchBackend { let expected_hash = persisted_nft_hash() .await .map_err(|err| BrokerError::LiveHandler(err.to_string()))? - .or_else(|| resolver.host.nftables.table_hash_after_apply.clone()); + .or_else(|| resolver.host().nftables.table_hash_after_apply.clone()); crate::ops::nft::apply_with_coexistence( &exec, &nft_binary, &nft_script, - resolver.host.nftables.ownership_id.as_str(), - resolver.host.firewall_coexistence_policy.as_ref(), + resolver.host().nftables.ownership_id.as_str(), + resolver.host().firewall_coexistence_policy.as_ref(), expected_hash.as_deref(), ) .await @@ -6985,8 +6985,8 @@ impl DispatchBackend for LiveDispatchBackend { crate::ops::nft::persist_live_nft_hash( &exec, &nft_binary, - &resolver.host.nftables.family, - &resolver.host.nftables.table, + &resolver.host().nftables.family, + &resolver.host().nftables.table, &nft_hash_sidecar_path(), ) .await diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 33cfa7246..a61547054 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -105,10 +105,10 @@ use std::path::{Path, PathBuf}; /// contract. #[derive(Clone)] pub struct BundleResolver { - pub bundle: Bundle, + bundle: Bundle, zone_topology: Option, - pub host: HostJson, - pub processes: ProcessesJson, + host: HostJson, + processes: ProcessesJson, zone_resource_bundles: BTreeMap>, /// Parsed zone-tagged v3 resource bundles keyed by canonical Zone id. parsed_zone_resources: BTreeMap, @@ -117,12 +117,12 @@ pub struct BundleResolver { guest_vmm_intents: BTreeMap>, guest_vmm_zone_uids: BTreeMap>, zone_storage_rows: BTreeMap, - pub storage: Option, + storage: Option, /// Trusted site-runtime contract (`site.json`); `None` for a bundle that /// predates the artifact, which leaves its consumers unbound. - pub site: Option, - pub realm_workloads_launcher_v2: Option, - pub manifest: ManifestV04, + site: Option, + realm_workloads_launcher_v2: Option, + manifest: ManifestV04, audit_bundle_version: String, audit_bundle_hash: String, installed_generation_identity: Option, @@ -1610,6 +1610,49 @@ impl BundleResolver { &self.audit_bundle_version } + /// The trusted `bundle.json` document. + pub fn bundle(&self) -> &Bundle { + &self.bundle + } + + /// The parsed `host.json` artifact. + pub fn host(&self) -> &HostJson { + &self.host + } + + /// The parsed processes contract. + pub fn processes(&self) -> &ProcessesJson { + &self.processes + } + + /// The storage contract, when the bundle carries one. + pub fn storage(&self) -> Option<&StorageJson> { + self.storage.as_ref() + } + + /// The trusted site-runtime contract (`site.json`), when the bundle + /// carries one. + pub fn site(&self) -> Option<&SiteJson> { + self.site.as_ref() + } + + /// The realm-workloads launcher v2 contract, when the bundle carries one. + pub fn realm_workloads_launcher_v2(&self) -> Option<&RealmWorkloadsLauncherV2Json> { + self.realm_workloads_launcher_v2.as_ref() + } + + /// The parsed v4 manifest. + pub fn manifest(&self) -> &ManifestV04 { + &self.manifest + } + + /// Replace the storage contract. The broker reconciles the storage + /// scope against the declared contract and writes the resolved + /// contract back onto the loaded resolver. + pub fn set_storage(&mut self, storage: StorageJson) { + self.storage = Some(storage); + } + /// Return the sealed Zone topology, when the allocator artifact carries it. pub fn zone_topology(&self) -> Option<&AllocatorZoneTopology> { self.zone_topology.as_ref() @@ -6984,13 +7027,12 @@ mod tests { let resolver = BundleResolver::load_with_policy(&bundle_path, ¤t_user_bundle_policy()) .expect("Zone-native bundle index loads"); - assert_eq!(resolver.bundle.bundle_version, 1); - assert_eq!(resolver.bundle.schema_version, "v3"); + assert_eq!(resolver.bundle().bundle_version, 1); + assert_eq!(resolver.bundle().schema_version, "v3"); assert!(resolver.zone_resource_bundles.is_empty()); assert_eq!( resolver - .site - .as_ref() + .site() .and_then(|site| site.wayland_socket()), Some("/run/user/1000/wayland-0"), "the declared site artifact is the projected Wayland socket" @@ -7412,8 +7454,9 @@ mod tests { #[test] fn resolves_macvtap_intents_from_process_contract() { let root = test_root("macvtap-intents"); - let mut resolver = build_personal_dev_bundle(&root); - resolver.processes.vms[0].nodes.push(ProcessNode { + let resolver = build_personal_dev_bundle(&root); + let mut processes = resolver.processes().clone(); + processes.vms[0].nodes.push(ProcessNode { execution_ref: None, execution_domain: None, user_ref: None, @@ -7462,6 +7505,13 @@ mod tests { }, ], }); + let mut resolver = BundleResolver::from_artifacts_with_zone_resource_bundles( + resolver.bundle().clone(), + resolver.host().clone(), + processes, + resolver.manifest().clone(), + BTreeMap::new(), + ); let intents = resolver .resolve_macvtap_intents("personal-dev", "cloud-hypervisor") @@ -7471,7 +7521,7 @@ mod tests { assert_eq!(intents[0].parent_ifname.as_str(), "eno1"); assert_eq!(intents[0].mode, ProcessMacvtapMode::Bridge); assert_eq!(intents[0].fd, 10); - resolver.runner_intents = build_runner_intents(&resolver.processes); + resolver.runner_intents = build_runner_intents(resolver.processes()); assert!( resolver .find_runner_intent_for_process_in_vm( @@ -7561,8 +7611,9 @@ mod tests { #[test] fn v3_tap_resolution_ignores_legacy_env_and_manifest_names() { let root = test_root("tap-resolution-uid-authority"); - let mut resolver = build_personal_dev_bundle(&root); - resolver.processes.vms[0].nodes.push(ProcessNode { + let resolver = build_personal_dev_bundle(&root); + let mut processes = resolver.processes().clone(); + processes.vms[0].nodes.push(ProcessNode { execution_ref: None, execution_domain: None, user_ref: None, @@ -7582,6 +7633,13 @@ mod tests { plan_ops: Vec::new(), network_interfaces: Vec::new(), }); + let resolver = BundleResolver::from_artifacts_with_zone_resource_bundles( + resolver.bundle().clone(), + resolver.host().clone(), + processes, + resolver.manifest().clone(), + BTreeMap::new(), + ); let zone_uid = ResourceUid::parse("223e4567-e89b-42d3-a456-426614174001").expect("zone uid"); let network_uid = @@ -7606,9 +7664,22 @@ mod tests { attachment_uid.clone(), ) .expect("v3 TAP intent"); - resolver.host.environments[0].env = "attacker".to_owned(); - resolver.manifest.vms.get_mut("personal-dev").unwrap().env = Some("attacker".to_owned()); - let second = resolver + let mut attacker_host = resolver.host().clone(); + attacker_host.environments[0].env = "attacker".to_owned(); + let mut attacker_manifest = resolver.manifest().clone(); + attacker_manifest + .vms + .get_mut("personal-dev") + .unwrap() + .env = Some("attacker".to_owned()); + let mutated = BundleResolver::from_artifacts_with_zone_resource_bundles( + resolver.bundle().clone(), + attacker_host, + resolver.processes().clone(), + attacker_manifest, + BTreeMap::new(), + ); + let second = mutated .resolve_tap_intent("personal-dev", "ch", provenance, attachment_uid) .expect("v3 TAP intent after legacy mutation"); assert_eq!(first, second); diff --git a/packages/d2b-core/tests/bundle_resolver_tamper.rs b/packages/d2b-core/tests/bundle_resolver_tamper.rs index 2645169d1..45360d94b 100644 --- a/packages/d2b-core/tests/bundle_resolver_tamper.rs +++ b/packages/d2b-core/tests/bundle_resolver_tamper.rs @@ -269,8 +269,8 @@ fn loads_correct() { let resolver = BundleResolver::load_with_policy(&bundle_path, &policy) .expect("all-correct bundle should load without error"); - assert_eq!(resolver.bundle.bundle_version, 1); - assert_eq!(resolver.bundle.schema_version, "v3"); + assert_eq!(resolver.bundle().bundle_version, 1); + assert_eq!(resolver.bundle().schema_version, "v3"); } // --------------------------------------------------------------- diff --git a/packages/d2b-provider-device-usbip/src/core_adapter.rs b/packages/d2b-provider-device-usbip/src/core_adapter.rs index 1ccf1161c..2210a8234 100644 --- a/packages/d2b-provider-device-usbip/src/core_adapter.rs +++ b/packages/d2b-provider-device-usbip/src/core_adapter.rs @@ -175,7 +175,7 @@ impl UsbipCoreAdapter { let entry = self .resolver - .manifest + .manifest() .vms .get(vm) .ok_or(UsbipCoreAdapterError::VmNotFound)?; @@ -200,7 +200,7 @@ impl UsbipCoreAdapter { let net = self .resolver - .host + .host() .environments .iter() .find(|candidate| candidate.env == env) diff --git a/packages/d2b-provider-network-local/src/effects_service.rs b/packages/d2b-provider-network-local/src/effects_service.rs index 28914825c..61f87683b 100644 --- a/packages/d2b-provider-network-local/src/effects_service.rs +++ b/packages/d2b-provider-network-local/src/effects_service.rs @@ -107,9 +107,9 @@ async fn serve_inspect_network( .ok_or_else(|| declined("inspect-network-installed-generation-unavailable"))?; inspect_network_response( installed.as_str(), - &bundle.host.nftables.family, - &bundle.host.nftables.table, - bundle.host.site.allow_unsafe_east_west, + &bundle.host().nftables.family, + &bundle.host().nftables.table, + bundle.host().site.allow_unsafe_east_west, ) } diff --git a/packages/d2b-provider-network-local/src/operations.rs b/packages/d2b-provider-network-local/src/operations.rs index ed2026159..637f2e5b5 100644 --- a/packages/d2b-provider-network-local/src/operations.rs +++ b/packages/d2b-provider-network-local/src/operations.rs @@ -473,14 +473,14 @@ impl OperationHandler for ApplyNftablesHandler { &ctx, "apply-nftables", serde_json::json!({ - "family": bundle.host.nftables.family, - "table": bundle.host.nftables.table, + "family": bundle.host().nftables.family, + "table": bundle.host().nftables.table, "scriptBody": intent.script_body, "ownershipId": intent.ownership_id, "destroy": request.destroy, "desiredHash": request.desired_hash, - "tableHashAfterApply": bundle.host.nftables.table_hash_after_apply, - "coexistencePolicy": bundle.host.firewall_coexistence_policy, + "tableHashAfterApply": bundle.host().nftables.table_hash_after_apply, + "coexistencePolicy": bundle.host().firewall_coexistence_policy, }), Vec::new(), ) diff --git a/packages/d2b-provider-process-systemd/src/operations.rs b/packages/d2b-provider-process-systemd/src/operations.rs index 0d8007370..0b8ee3a39 100644 --- a/packages/d2b-provider-process-systemd/src/operations.rs +++ b/packages/d2b-provider-process-systemd/src/operations.rs @@ -234,7 +234,7 @@ fn validate_request( let intent = bundle .find_runner_intent(request.bundle_runner_intent_ref.as_str()) .ok_or(UNIT_BUNDLE_INTENT)?; - if bundle.bundle.bundle_hash.as_deref() != Some(request.bundle_content_identity.as_str()) { + if bundle.bundle().bundle_hash.as_deref() != Some(request.bundle_content_identity.as_str()) { return Err(UNIT_IDENTITY_MISMATCH); } if intent.vm_name != request.vm_id.as_str() diff --git a/packages/d2b-provider-process/src/operations.rs b/packages/d2b-provider-process/src/operations.rs index a8cce4c5c..8bb64b5b0 100644 --- a/packages/d2b-provider-process/src/operations.rs +++ b/packages/d2b-provider-process/src/operations.rs @@ -2482,7 +2482,7 @@ impl OperationHandler for SpawnRunnerHandler { "bundle_content_identity: required".to_owned(), )); }; - let resolved = kernel.bundle.bundle.bundle_hash.as_deref().ok_or_else(|| { + let resolved = kernel.bundle.bundle().bundle_hash.as_deref().ok_or_else(|| { OperationFailure::with_detail( INTENT_MISMATCH, "bundle_content_identity: missing".to_owned(), @@ -2582,13 +2582,13 @@ impl OperationHandler for SpawnRunnerHandler { // declares; any other target would let a tampered bundle redirect // host OTLP egress (the retired arm's fail-closed fence). if matches!(request.role, RunnerRole::OtelHostBridge) - && intent.vm_name != kernel.bundle.manifest.observability.vm_name + && intent.vm_name != kernel.bundle.manifest().observability.vm_name { return Err(OperationFailure::with_detail( INTENT_MISMATCH, format!( "OtelHostBridge: intent vm {} does not match the obs VM {}", - intent.vm_name, kernel.bundle.manifest.observability.vm_name + intent.vm_name, kernel.bundle.manifest().observability.vm_name ), )); } diff --git a/packages/d2b-provider-supervisor/src/broker.rs b/packages/d2b-provider-supervisor/src/broker.rs index a68bea31e..95d113237 100644 --- a/packages/d2b-provider-supervisor/src/broker.rs +++ b/packages/d2b-provider-supervisor/src/broker.rs @@ -387,7 +387,7 @@ impl BundleBackedLaunchResolver { fn zone_for_launch_vm(&self, vm: &str) -> Option { if let Some(environment) = self .bundle - .manifest + .manifest() .vms .get(vm) .and_then(|entry| entry.env.as_deref()) @@ -867,7 +867,7 @@ impl BundleBackedLaunchResolver { generation: ticket.resource_generation().get(), resource_ref: ticket.process_ref().clone(), resource_uid: ticket.process_uid().clone(), - bundle_content_identity: self.bundle.bundle.bundle_hash.clone().ok_or_else(|| { + bundle_content_identity: self.bundle.bundle().bundle_hash.clone().ok_or_else(|| { warn!( provider = "supervisor", resource = %ticket.process_ref().to_canonical_string(), diff --git a/packages/d2bd-runtime/src/autostart.rs b/packages/d2bd-runtime/src/autostart.rs index aff2680c0..98f7234c0 100644 --- a/packages/d2bd-runtime/src/autostart.rs +++ b/packages/d2bd-runtime/src/autostart.rs @@ -226,7 +226,7 @@ pub trait VmStarter: Send + Sync + 'static { /// skipped by [`execute_autostart`]. pub fn build_autostart_plan(resolver: &BundleResolver) -> AutostartPlan { let (mut net_entries, mut workload_entries): (Vec<_>, Vec<_>) = resolver - .manifest + .manifest() .vms .iter() .map(|(name, vm)| VmAutostartEntry { diff --git a/packages/d2bd-runtime/src/kernel_module_check.rs b/packages/d2bd-runtime/src/kernel_module_check.rs index 84b16eda6..1eb38b622 100644 --- a/packages/d2bd-runtime/src/kernel_module_check.rs +++ b/packages/d2bd-runtime/src/kernel_module_check.rs @@ -185,7 +185,7 @@ impl ModuleCheckReport { fn classify_vms(resolver: &BundleResolver) -> BundleFeatureSet { let mut features = BundleFeatureSet::default(); - for (vm_id, vm) in &resolver.manifest.vms { + for (vm_id, vm) in &resolver.manifest().vms { if vm.graphics { features.graphics_vms.insert(vm_id.clone()); } @@ -202,7 +202,7 @@ fn classify_vms(resolver: &BundleResolver) -> BundleFeatureSet { // module. We additionally pick up Gpu / Usbip / Swtpm nodes // for VMs whose manifest-level booleans might lag a // future-shape change. - for dag in &resolver.processes.vms { + for dag in &resolver.processes().vms { let vm_id = &dag.vm; for node in &dag.nodes { match node.role { diff --git a/packages/d2bd-runtime/src/workload_dispatch.rs b/packages/d2bd-runtime/src/workload_dispatch.rs index 0d0fc3b53..afc802a7c 100644 --- a/packages/d2bd-runtime/src/workload_dispatch.rs +++ b/packages/d2bd-runtime/src/workload_dispatch.rs @@ -298,8 +298,7 @@ impl WorkloadCatalog { realm_controllers: Option<&RealmControllersJson>, ) -> Result { let public = resolver - .realm_workloads_launcher_v2 - .as_ref() + .realm_workloads_launcher_v2() .ok_or(CatalogError::ArtifactsUnavailable)?; let mut entries = BTreeMap::new(); let mut visible = std::collections::BTreeSet::new(); @@ -343,7 +342,7 @@ impl WorkloadCatalog { Ok(Self { entries, visible, - known_local_vms: resolver.manifest.vms.keys().cloned().collect(), + known_local_vms: resolver.manifest().vms.keys().cloned().collect(), }) } diff --git a/packages/d2bd-runtime/src/zone_authority.rs b/packages/d2bd-runtime/src/zone_authority.rs index 215b8346b..d9ec01dd6 100644 --- a/packages/d2bd-runtime/src/zone_authority.rs +++ b/packages/d2bd-runtime/src/zone_authority.rs @@ -203,7 +203,7 @@ pub async fn register_authoritative_zones( for zone in authoritative_zone_ids(resolver)? { let _ = coordinator.register_zone(zone); } - for (vm, runtime) in &resolver.manifest.vms { + for (vm, runtime) in &resolver.manifest().vms { let Some(environment) = runtime.env.as_deref() else { continue; }; diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..ff8cd70ee 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -3690,7 +3690,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { .and_then(|zones| committed_zone_topology(&resolver, &zones).ok()) .map(|topology| topology.root); let provider_ready = match provider_root.as_ref() { - Some(_) if resolver.bundle.schema_version == "v3" => { + Some(_) if resolver.bundle().schema_version == "v3" => { let process_providers = Arc::new(process_provider_runtime::ProductionProcessProviders::new( resolver.clone(), @@ -3713,7 +3713,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { } Some(_) => { tracing::error!( - schema = %resolver.bundle.schema_version, + schema = %resolver.bundle().schema_version, "Provider composition refused: only v3 bundles are supported", ); false @@ -3907,7 +3907,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { let report = storage_lifecycle::run_startup_contract_check(&resolver); if report.has_only_legacy_contract_issue() { tracing::info!( - bundle_version = resolver.bundle.bundle_version, + bundle_version = resolver.bundle().bundle_version, report_kind = "storage-lifecycle", "storage-lifecycle: legacy bundle lacks storage/sync contracts; rebuild host configuration to enable startup contract checks", ); @@ -7389,7 +7389,7 @@ pub(crate) fn resolve_network_effect_context( sysctl_ids, generation, projection_digest, - resolver.host.site.allow_unsafe_east_west, + resolver.host().site.allow_unsafe_east_west, ) .with_additional_bridge_intent(BundleOpId::new(uplink_bridge_id))) } @@ -9305,7 +9305,7 @@ fn dispatch_broker_usbip_bind( } let resolver = load_bundle_resolver(state)?; ensure_manifest_entry_runtime_capability( - resolver.manifest.vms.get(&request.vm), + resolver.manifest().vms.get(&request.vm), &request.vm, RuntimeCapabilityGate::UsbHotplug, VERB, @@ -9347,7 +9347,7 @@ fn dispatch_broker_usbip_unbind( } let resolver = load_bundle_resolver(state)?; ensure_manifest_entry_runtime_capability( - resolver.manifest.vms.get(&request.vm), + resolver.manifest().vms.get(&request.vm), &request.vm, RuntimeCapabilityGate::UsbHotplug, VERB, @@ -9439,7 +9439,7 @@ fn refresh_qemu_media_registry_index_if_needed_as( resolver: &BundleResolver, caller_role: BrokerCallerRole, ) -> Result<(), TypedError> { - if resolver.host.qemu_media.is_none() { + if resolver.host().qemu_media.is_none() { return Ok(()); } match dispatch_broker_request_as( @@ -9925,7 +9925,7 @@ fn qemu_media_probe_entries( state: &ServerState, resolver: &BundleResolver, ) -> Vec { - let Some(qemu_media) = resolver.host.qemu_media.as_ref() else { + let Some(qemu_media) = resolver.host().qemu_media.as_ref() else { return Vec::new(); }; const MAX_QEMU_MEDIA_PROBE_CANDIDATES: usize = 16; @@ -12579,7 +12579,7 @@ fn guest_shell_session( let resolver = load_bundle_resolver(state)?; let entry = resolver - .manifest + .manifest() .vms .get(vm) .ok_or_else(|| TypedError::WorkloadTargetNotFound { @@ -12698,7 +12698,7 @@ fn configured_shell_targets(state: &ServerState) -> Result, TypedErr let mut targets = std::collections::BTreeSet::new(); targets.extend( resolver - .manifest + .manifest() .vms .iter() .filter(|(_, vm)| vm.shell.as_ref().is_some_and(|shell| shell.enabled)) @@ -14176,14 +14176,14 @@ fn host_nft_kernel_payload( .find_nft_intent(intent_ref) .ok_or_else(|| "host nft intent missing".to_owned())?; Ok(serde_json::json!({ - "family": resolver.host.nftables.family, - "table": resolver.host.nftables.table, + "family": resolver.host().nftables.family, + "table": resolver.host().nftables.table, "scriptBody": intent.script_body, "ownershipId": intent.ownership_id, "destroy": destroy, "desiredHash": serde_json::Value::Null, - "tableHashAfterApply": resolver.host.nftables.table_hash_after_apply, - "coexistencePolicy": serde_json::to_value(&resolver.host.firewall_coexistence_policy).ok(), + "tableHashAfterApply": resolver.host().nftables.table_hash_after_apply, + "coexistencePolicy": serde_json::to_value(&resolver.host().firewall_coexistence_policy).ok(), })) } @@ -19503,7 +19503,7 @@ fn dispatch_broker_vm_start_inner( // the timeout into a typed `otel-host-bridge-readiness-timeout` // refusal envelope (exit code 65). See // `docs/reference/otel-host-bridge-readiness.md`. - let obs_meta = &resolver.manifest.observability; + let obs_meta = &resolver.manifest().observability; if obs_meta.enabled && obs_meta.vm_name == request.vm { let cfg = d2bd_runtime::otel_host_bridge_readiness::ReadinessWaitConfig::for_dispatch(); diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index e1d7aacdb..d593b2a88 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -1085,7 +1085,7 @@ impl ProductionProcessProviders { /// Return every VM that has a process DAG in the trusted bundle. pub fn vm_ids(&self) -> Vec { self.bundle - .processes + .processes() .vms .iter() .map(|dag| dag.vm.clone()) @@ -3222,7 +3222,7 @@ pub(crate) async fn resolve_device_worker_launch( // artifact, or a headless site, leaves the slot unbound and // the launch refuses with its own code instead of naming a // path no trusted artifact names. - let wayland_sock = gpu_worker_wayland_sock(self.bundle().site.as_ref())?; + let wayland_sock = gpu_worker_wayland_sock(self.bundle().site())?; // The typed parameters travel as the canonical JSON of the // Provider's own `GpuParams`; the argv seat decodes them back. let params = serde_json::to_value(d2b_provider_device_gpu::GpuParams { @@ -4155,7 +4155,7 @@ fn compiled_resource_digests( ManagedProvider::Minijail => "system-minijail", ManagedProvider::Systemd => "system-systemd", }, - bundle.bundle.bundle_hash.as_deref().unwrap_or("bundle"), + bundle.bundle().bundle_hash.as_deref().unwrap_or("bundle"), ); CompiledDigests { sandbox: digest(&format!("{context}:sandbox"), spec_bytes), @@ -4294,7 +4294,7 @@ fn compiled_digests( ManagedProvider::Minijail => "system-minijail", ManagedProvider::Systemd => "system-systemd", }, - bundle.bundle.bundle_hash.as_deref().unwrap_or("bundle") + bundle.bundle().bundle_hash.as_deref().unwrap_or("bundle") ); CompiledDigests { sandbox: digest(&format!("{context}:sandbox"), &node_bytes), @@ -4311,10 +4311,10 @@ fn stable_generation(bundle: &BundleResolver) -> u64 { let mut hasher = Sha256::new(); hasher.update( bundle - .bundle + .bundle() .bundle_hash .as_deref() - .unwrap_or(bundle.bundle.generation.generator.as_str()), + .unwrap_or(bundle.bundle().generation.generator.as_str()), ); let bytes: [u8; 32] = hasher.finalize().into(); let generation = u64::from_le_bytes(bytes[..8].try_into().expect("digest prefix")); From ac30833162327281139a4ab7c94c77fd1ad55745 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:47:36 -0700 Subject: [PATCH 604/726] refactor(d2b-core): delete six compat shim modules and re-point imports at d2b_contracts The error, contract_id, configured_argv, privileges_w3, workload_identity, and unsafe_local_workloads shim modules made every re-exported item public at two paths. Delete them (with the zero-consumer UnsafeLocalWorkloadIdentity alias), re-point all workspace import sites and d2b-core internal references at d2b_contracts (and d2b_contracts_resource::v3::ZoneResourceIdentity), and switch the xtask gen-error-codes generator to d2b_contracts::error. The generated error-codes.md table is byte-identical; only its prose anchors change. Add d2b-contracts to d2b-resource-compiler and the labs window-chrome proxy, which imported the shimmed paths directly. --- Cargo.lock | 1 + changelog.d/w5-03-core-shim-deletion.md | 4 ++ docs/reference/error-codes.md | 4 +- docs/reference/error-envelope-guidance.md | 2 +- labs/window-chrome/proxy/Cargo.lock | 37 +++++++++++++++++-- labs/window-chrome/proxy/Cargo.toml | 1 + labs/window-chrome/proxy/src/attribution.rs | 2 +- labs/window-chrome/proxy/src/bridge.rs | 2 +- labs/window-chrome/proxy/src/identity.rs | 2 +- labs/window-chrome/proxy/src/main.rs | 2 +- labs/window-chrome/proxy/src/policy.rs | 2 +- labs/window-chrome/proxy/src/readiness.rs | 2 +- packages/d2b-broker/src/ops/state_dir.rs | 2 +- .../d2b-broker/src/ops/storage_contract.rs | 2 +- packages/d2b-broker/src/runtime.rs | 2 +- packages/d2b-core/src/allocator_config.rs | 2 +- packages/d2b-core/src/bundle_resolver.rs | 4 +- packages/d2b-core/src/configured_argv.rs | 1 - packages/d2b-core/src/contract_id.rs | 1 - packages/d2b-core/src/error.rs | 1 - packages/d2b-core/src/lib.rs | 6 --- packages/d2b-core/src/manifest_v04.rs | 2 +- packages/d2b-core/src/privileges_w3.rs | 1 - packages/d2b-core/src/processes.rs | 2 +- packages/d2b-core/src/storage.rs | 2 +- packages/d2b-core/src/sync.rs | 2 +- .../d2b-core/src/unsafe_local_workloads.rs | 9 ----- packages/d2b-core/src/workload_identity.rs | 1 - .../d2b-core/tests/bundle_resolver_tamper.rs | 2 +- packages/d2b-host/src/nftables.rs | 16 ++++---- packages/d2b-resource-compiler/Cargo.toml | 1 + packages/d2b-resource-compiler/src/lib.rs | 4 +- packages/d2b/src/lib.rs | 2 +- .../d2bd-runtime/src/unsafe_local_helper.rs | 6 ++- .../d2bd-runtime/src/workload_dispatch.rs | 8 ++-- packages/d2bd/src/composition.rs | 12 +++--- .../d2bd/tests/bundle_tampered_envelope.rs | 2 +- packages/xtask/src/main.rs | 7 +++- 38 files changed, 89 insertions(+), 72 deletions(-) create mode 100644 changelog.d/w5-03-core-shim-deletion.md delete mode 100644 packages/d2b-core/src/configured_argv.rs delete mode 100644 packages/d2b-core/src/contract_id.rs delete mode 100644 packages/d2b-core/src/error.rs delete mode 100644 packages/d2b-core/src/privileges_w3.rs delete mode 100644 packages/d2b-core/src/unsafe_local_workloads.rs delete mode 100644 packages/d2b-core/src/workload_identity.rs diff --git a/Cargo.lock b/Cargo.lock index 05bbba237..728b558e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2041,6 +2041,7 @@ name = "d2b-resource-compiler" version = "0.0.0-bootstrap" dependencies = [ "base64", + "d2b-contracts", "d2b-contracts-provider", "d2b-contracts-resource", "d2b-contracts-zone-session", diff --git a/changelog.d/w5-03-core-shim-deletion.md b/changelog.d/w5-03-core-shim-deletion.md new file mode 100644 index 000000000..add4bd8ea --- /dev/null +++ b/changelog.d/w5-03-core-shim-deletion.md @@ -0,0 +1,4 @@ +### Fixed + +- Deleted the six one-line compat shim modules in d2b-core (`error`, `contract_id`, `configured_argv`, `privileges_w3`, `workload_identity`, `unsafe_local_workloads`) that re-exported d2b_contracts items, so every re-exported item now has a single public path under `d2b_contracts` (and `d2b_contracts_resource::v3::ZoneResourceIdentity`); the zero-consumer `UnsafeLocalWorkloadIdentity` alias was removed with its module. +- Re-pointed all workspace import sites and the xtask `gen-error-codes` generator (and the generated `docs/reference/error-codes.md` anchors) from `d2b_core::error` to `d2b_contracts::error`. \ No newline at end of file diff --git a/docs/reference/error-codes.md b/docs/reference/error-codes.md index 7a30ef7d1..fb20a076f 100644 --- a/docs/reference/error-codes.md +++ b/docs/reference/error-codes.md @@ -11,7 +11,7 @@ usage errors, and legacy-bash lock conflicts are documented separately below so ## Shared non-typed exit-code anchors These anchors document common process exits that are **not** emitted as -`d2b_core::error::Error` envelopes. +`d2b_contracts::error::Error` envelopes. | docs anchor | exit code | meaning | | --- | --- | --- | @@ -31,7 +31,7 @@ These anchors document common process exits that are **not** emitted as ## Typed error catalog The table below is generated by `bazel run //packages/xtask:xtask -- gen-error-codes` from -`d2b_core::error::Error::all_kinds()`. Each row is a stable leaf `Kind` +`d2b_contracts::error::Error::all_kinds()`. Each row is a stable leaf `Kind` discriminant with its reserved exit code, owning command, redacted message shape, remediation hint, and docs anchor. diff --git a/docs/reference/error-envelope-guidance.md b/docs/reference/error-envelope-guidance.md index fd236b377..3af17ee4c 100644 --- a/docs/reference/error-envelope-guidance.md +++ b/docs/reference/error-envelope-guidance.md @@ -27,7 +27,7 @@ Every new error or refusal should follow these rules first: ## Public daemon/operator envelope -`d2b_core::error::Error` serializes as the public operator envelope: +`d2b_contracts::error::Error` serializes as the public operator envelope: | Field | Meaning | | --- | --- | diff --git a/labs/window-chrome/proxy/Cargo.lock b/labs/window-chrome/proxy/Cargo.lock index cef166cd1..36af3bff3 100644 --- a/labs/window-chrome/proxy/Cargo.lock +++ b/labs/window-chrome/proxy/Cargo.lock @@ -243,6 +243,7 @@ version = "0.0.0-prototype" dependencies = [ "clap", "d2b-chrome-engine", + "d2b-contracts", "d2b-core", "env_logger", "getrandom", @@ -263,13 +264,11 @@ dependencies = [ name = "d2b-contracts" version = "0.0.0-bootstrap" dependencies = [ - "async-trait", "schemars", "semver", "serde", "serde_json", "sha2", - "unicode-normalization", ] [[package]] @@ -283,7 +282,6 @@ dependencies = [ "serde", "serde_json", "sha2", - "unicode-normalization", ] [[package]] @@ -321,11 +319,11 @@ dependencies = [ "d2b-contracts-zone-session", "rustix", "schemars", - "semver", "serde", "serde_json", "sha2", "tokio", + "tracing", ] [[package]] @@ -1164,6 +1162,37 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + [[package]] name = "ttf-parser" version = "0.21.1" diff --git a/labs/window-chrome/proxy/Cargo.toml b/labs/window-chrome/proxy/Cargo.toml index 82e9c6ad6..1bad6f7b1 100644 --- a/labs/window-chrome/proxy/Cargo.toml +++ b/labs/window-chrome/proxy/Cargo.toml @@ -26,6 +26,7 @@ path = "src/lib.rs" [dependencies] clap = { version = "4", features = ["derive"] } d2b-chrome-engine = { path = "../chrome-engine" } +d2b-contracts = { path = "../../../packages/d2b-contracts" } d2b-core = { path = "../../../packages/d2b-core" } libc = "0.2" log = "0.4" diff --git a/labs/window-chrome/proxy/src/attribution.rs b/labs/window-chrome/proxy/src/attribution.rs index 84f5d907b..79d40f176 100644 --- a/labs/window-chrome/proxy/src/attribution.rs +++ b/labs/window-chrome/proxy/src/attribution.rs @@ -76,7 +76,7 @@ impl ClientAttributionBook { #[cfg(test)] mod tests { - use d2b_core::workload_identity::WorkloadTarget; + use d2b_contracts::workload_identity::WorkloadTarget; use crate::WorkloadProviderKind; use super::*; diff --git a/labs/window-chrome/proxy/src/bridge.rs b/labs/window-chrome/proxy/src/bridge.rs index 49c123183..ad2b4d4dc 100644 --- a/labs/window-chrome/proxy/src/bridge.rs +++ b/labs/window-chrome/proxy/src/bridge.rs @@ -14,7 +14,7 @@ use std::{ time::{Duration, Instant}, }; -use d2b_core::workload_identity::WorkloadTarget; +use d2b_contracts::workload_identity::WorkloadTarget; use crate::WorkloadProviderKind; use serde::Serialize; diff --git a/labs/window-chrome/proxy/src/identity.rs b/labs/window-chrome/proxy/src/identity.rs index 300fee6aa..411f79cc0 100644 --- a/labs/window-chrome/proxy/src/identity.rs +++ b/labs/window-chrome/proxy/src/identity.rs @@ -1,4 +1,4 @@ -use d2b_core::workload_identity::WorkloadTarget; +use d2b_contracts::workload_identity::WorkloadTarget; use crate::WorkloadProviderKind; use sha2::{Digest, Sha256}; diff --git a/labs/window-chrome/proxy/src/main.rs b/labs/window-chrome/proxy/src/main.rs index 6cde365e0..f11eeb52b 100644 --- a/labs/window-chrome/proxy/src/main.rs +++ b/labs/window-chrome/proxy/src/main.rs @@ -22,7 +22,7 @@ use std::{ }; use clap::Parser; -use d2b_core::workload_identity::WorkloadTarget; +use d2b_contracts::workload_identity::WorkloadTarget; use d2b_wayland_proxy::WorkloadProviderKind; use d2b_wayland_proxy::filter::{ FilterStateHandler, VirtualClipboardState, build_state, install_client_handlers, diff --git a/labs/window-chrome/proxy/src/policy.rs b/labs/window-chrome/proxy/src/policy.rs index 90c24b75a..96e3a4997 100644 --- a/labs/window-chrome/proxy/src/policy.rs +++ b/labs/window-chrome/proxy/src/policy.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; -use d2b_core::workload_identity::WorkloadTarget; +use d2b_contracts::workload_identity::WorkloadTarget; use crate::WorkloadProviderKind; use crate::identity::ProxyIdentity; diff --git a/labs/window-chrome/proxy/src/readiness.rs b/labs/window-chrome/proxy/src/readiness.rs index 629330c09..9609b1119 100644 --- a/labs/window-chrome/proxy/src/readiness.rs +++ b/labs/window-chrome/proxy/src/readiness.rs @@ -5,7 +5,7 @@ use std::{ time::Duration, }; -use d2b_core::workload_identity::WorkloadTarget; +use d2b_contracts::workload_identity::WorkloadTarget; use crate::WorkloadProviderKind; use serde::{Deserialize, Serialize}; diff --git a/packages/d2b-broker/src/ops/state_dir.rs b/packages/d2b-broker/src/ops/state_dir.rs index d353d6b26..9a629d933 100644 --- a/packages/d2b-broker/src/ops/state_dir.rs +++ b/packages/d2b-broker/src/ops/state_dir.rs @@ -371,7 +371,7 @@ fn fixture_content_hash(resources: &[serde_json::Value]) -> String { #[cfg(test)] pub(crate) fn resolver_with_swtpm_state_row(guest: &str) -> BundleResolver { use d2b_core::bundle::{Bundle, BundleGeneration}; - use d2b_core::contract_id::{ContractId, PathTemplate}; + use d2b_contracts::contract_id::{ContractId, PathTemplate}; use d2b_core::host::HostJson; use d2b_core::manifest_v04::ManifestV04; use d2b_core::processes::ProcessesJson; diff --git a/packages/d2b-broker/src/ops/storage_contract.rs b/packages/d2b-broker/src/ops/storage_contract.rs index 40302dc16..2dca299ad 100644 --- a/packages/d2b-broker/src/ops/storage_contract.rs +++ b/packages/d2b-broker/src/ops/storage_contract.rs @@ -347,7 +347,7 @@ mod tests { use d2b_contracts::types::BundleOpId; use d2b_core::bundle::Bundle; use d2b_core::bundle_resolver::BundleResolver; - use d2b_core::contract_id::{ContractId, ContractText, PathTemplate}; + use d2b_contracts::contract_id::{ContractId, ContractText, PathTemplate}; use d2b_core::host::HostJson; use d2b_core::manifest_v04::ManifestV04; use d2b_core::processes::ProcessesJson; diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index e9597184f..45b189436 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -1302,7 +1302,7 @@ pub(crate) fn try_load_resolver_with_policy( bundle_path: &Path, policy: &d2b_core::bundle_resolver::BundleVerifyPolicy, ) -> BundleSlot { - use d2b_core::error::{BundleError, Error as CoreError}; + use d2b_contracts::error::{BundleError, Error as CoreError}; // Per the tracing contract, span attributes MUST NOT include // filesystem paths (high cardinality + can leak host layout). The // bundle path is bounded operational context handled by the typed diff --git a/packages/d2b-core/src/allocator_config.rs b/packages/d2b-core/src/allocator_config.rs index 07e20ec12..141449033 100644 --- a/packages/d2b-core/src/allocator_config.rs +++ b/packages/d2b-core/src/allocator_config.rs @@ -6,7 +6,7 @@ use schemars::{ use serde::{Deserialize, Deserializer, Serialize}; use std::collections::BTreeMap; -use crate::contract_id::{ContractId, ContractStringError, PathTemplate}; +use d2b_contracts::contract_id::{ContractId, ContractStringError, PathTemplate}; use d2b_contracts_resource::v3::ZoneId; pub const MAX_ALLOCATOR_REALM_PATH_BYTES: usize = 255; diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 33cfa7246..62e36c1d7 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -65,7 +65,7 @@ use crate::allocator_config::AllocatorZoneTopology; use crate::bundle::{Bundle, BundleGeneration}; -use crate::error::Error; +use d2b_contracts::error::Error; use crate::host::{ ChNetHandoffMode, HostJson, HostsFileOwnership, ModuleRequirement, NetEnv, NetworkManagerUnmanaged, NftablesModel, OwnershipRule, QemuMediaSourceIntent, SitePolicy, @@ -952,7 +952,7 @@ fn lookup_group_gid(name: &str) -> Option { /// return the file's raw bytes. /// /// Returns [`Error::Bundle`] wrapping -/// [`crate::error::BundleError::Tampered`] with a short `reason` slug +/// [`d2b_contracts::error::BundleError::Tampered`] with a short `reason` slug /// on any security check failure: /// - `"symlink"` - `open` returned `ELOOP` (path is a symlink). /// - `"not-regular-file"` - `fstat` shows it is not a regular file. diff --git a/packages/d2b-core/src/configured_argv.rs b/packages/d2b-core/src/configured_argv.rs deleted file mode 100644 index 59ff1bdc6..000000000 --- a/packages/d2b-core/src/configured_argv.rs +++ /dev/null @@ -1 +0,0 @@ -pub use d2b_contracts::configured_argv::*; diff --git a/packages/d2b-core/src/contract_id.rs b/packages/d2b-core/src/contract_id.rs deleted file mode 100644 index dd2aa2961..000000000 --- a/packages/d2b-core/src/contract_id.rs +++ /dev/null @@ -1 +0,0 @@ -pub use d2b_contracts::contract_id::*; diff --git a/packages/d2b-core/src/error.rs b/packages/d2b-core/src/error.rs deleted file mode 100644 index 70b4935f0..000000000 --- a/packages/d2b-core/src/error.rs +++ /dev/null @@ -1 +0,0 @@ -pub use d2b_contracts::error::*; diff --git a/packages/d2b-core/src/lib.rs b/packages/d2b-core/src/lib.rs index 3297c6830..f09b61ed0 100644 --- a/packages/d2b-core/src/lib.rs +++ b/packages/d2b-core/src/lib.rs @@ -5,10 +5,7 @@ pub mod base64_codec; pub mod bundle; pub mod bundle_resolver; pub mod closures; -pub mod configured_argv; pub mod console_ring; -pub mod contract_id; -pub mod error; pub mod host; pub mod host_generation; pub mod host_w3; @@ -17,7 +14,6 @@ pub mod loader_worker; pub mod manifest_v04; pub mod sandbox_profile; pub mod privileges; -pub mod privileges_w3; pub mod processes; pub mod provider_artifact; pub mod provider_capabilities; @@ -27,8 +23,6 @@ pub mod static_invariants; pub mod storage; pub mod storage_lifecycle; pub mod sync; -pub mod unsafe_local_workloads; -pub mod workload_identity; // `test_support` is needed both by external crates (which opt in via the // `test-support` feature) and by d2b-core's OWN tests. Gating on diff --git a/packages/d2b-core/src/manifest_v04.rs b/packages/d2b-core/src/manifest_v04.rs index fb21378fb..cb0bd6802 100644 --- a/packages/d2b-core/src/manifest_v04.rs +++ b/packages/d2b-core/src/manifest_v04.rs @@ -6,7 +6,7 @@ //! camelCase wire shape with `deny_unknown_fields` admission, and the //! parser accepts the current and legacy-compat manifest versions. -use crate::error::Error; +use d2b_contracts::error::Error; use schemars::{ JsonSchema, r#gen::SchemaGenerator, diff --git a/packages/d2b-core/src/privileges_w3.rs b/packages/d2b-core/src/privileges_w3.rs deleted file mode 100644 index 445746565..000000000 --- a/packages/d2b-core/src/privileges_w3.rs +++ /dev/null @@ -1 +0,0 @@ -pub use d2b_contracts::privileges_w3::*; diff --git a/packages/d2b-core/src/processes.rs b/packages/d2b-core/src/processes.rs index a9b23f306..4d2bfa4f4 100644 --- a/packages/d2b-core/src/processes.rs +++ b/packages/d2b-core/src/processes.rs @@ -1,5 +1,5 @@ use crate::sandbox_profile::{CgroupPlacement, MountPolicy, NamespaceSet}; -use crate::workload_identity::WorkloadIdentity; +use d2b_contracts::workload_identity::WorkloadIdentity; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::path::PathBuf; diff --git a/packages/d2b-core/src/storage.rs b/packages/d2b-core/src/storage.rs index dc3964b84..ae6a62547 100644 --- a/packages/d2b-core/src/storage.rs +++ b/packages/d2b-core/src/storage.rs @@ -3,7 +3,7 @@ use std::collections::BTreeSet; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::contract_id::{ContractId, ContractText, PathTemplate}; +use d2b_contracts::contract_id::{ContractId, ContractText, PathTemplate}; use crate::storage_lifecycle::StorageValidationError; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] diff --git a/packages/d2b-core/src/sync.rs b/packages/d2b-core/src/sync.rs index 00ea8ec85..2bd60cb64 100644 --- a/packages/d2b-core/src/sync.rs +++ b/packages/d2b-core/src/sync.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::contract_id::{ContractId, PathTemplate}; +use d2b_contracts::contract_id::{ContractId, PathTemplate}; use crate::storage::{ActorRef, DegradeScope, DegradedReason}; use crate::storage_lifecycle::SyncValidationError; diff --git a/packages/d2b-core/src/unsafe_local_workloads.rs b/packages/d2b-core/src/unsafe_local_workloads.rs deleted file mode 100644 index 355ab979e..000000000 --- a/packages/d2b-core/src/unsafe_local_workloads.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use d2b_contracts::unsafe_local_workloads::*; -pub use d2b_contracts_resource::v3::ZoneResourceIdentity; - -/// Zone-neutral identity used by unsafe-local launcher and shell consumers. -/// -/// The resource identity carries the Zone UID, resource UID, desired -/// generation, and committed Zone revision, so equal resource names in -/// different Zones or generations cannot share runtime state. -pub type UnsafeLocalWorkloadIdentity = ZoneResourceIdentity; diff --git a/packages/d2b-core/src/workload_identity.rs b/packages/d2b-core/src/workload_identity.rs deleted file mode 100644 index 881e3c74a..000000000 --- a/packages/d2b-core/src/workload_identity.rs +++ /dev/null @@ -1 +0,0 @@ -pub use d2b_contracts::workload_identity::*; diff --git a/packages/d2b-core/tests/bundle_resolver_tamper.rs b/packages/d2b-core/tests/bundle_resolver_tamper.rs index 2645169d1..0a67014a3 100644 --- a/packages/d2b-core/tests/bundle_resolver_tamper.rs +++ b/packages/d2b-core/tests/bundle_resolver_tamper.rs @@ -15,7 +15,7 @@ //! SHA-256 self-hash), which the loader verifies before sibling artifacts. use d2b_core::bundle_resolver::{BundleResolver, BundleVerifyPolicy}; -use d2b_core::error::{BundleError, Error}; +use d2b_contracts::error::{BundleError, Error}; use sha2::Digest as _; use std::fs; use std::io::Write as _; diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index 1559e2a0f..c03b3a07c 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -65,10 +65,10 @@ impl fmt::Display for Sha256 { /// Errors returned by the s3 nftables surface. Discriminants are /// kebab-case to match the broker audit log + the wider -/// `d2b-core::error` taxonomy. The [`Self::as_kebab_case`] helper +/// `d2b_contracts::error` taxonomy. The [`Self::as_kebab_case`] helper /// is the canonical mapping consumed by -/// [`d2b_core::error::Error::internal_io`] when an error needs to -/// surface through the broker wire as a typed [`d2b_core::error`]. +/// [`d2b_contracts::error::Error::internal_io`] when an error needs to +/// surface through the broker wire as a typed [`d2b_contracts::error`]. #[derive(Debug, Clone, PartialEq, Eq)] pub enum NftError { /// A foreign nft rule sits above the `inet d2b` chains at a @@ -101,13 +101,13 @@ impl NftError { } } - /// Map to a `d2b-core::error::Error` via the - /// [`d2b_core::error::Error::internal_io`] constructor. The + /// Map to a `d2b_contracts::error::Error` via the + /// [`d2b_contracts::error::Error::internal_io`] constructor. The /// stable kebab-case discriminant is the opaque reason; the /// broker audit log records the structured variant separately so /// no operator-visible message loses the typed detail. - pub fn to_core_error(&self) -> d2b_core::error::Error { - d2b_core::error::Error::internal_io(self.as_kebab_case()) + pub fn to_core_error(&self) -> d2b_contracts::error::Error { + d2b_contracts::error::Error::internal_io(self.as_kebab_case()) } } @@ -1120,7 +1120,7 @@ mod tests { let core = err.to_core_error(); assert_eq!( core.kind(), - d2b_core::error::Kind::InternalIo, + d2b_contracts::error::Kind::InternalIo, "broker maps via InternalIo for now; ADR records the longer-term plan" ); } diff --git a/packages/d2b-resource-compiler/Cargo.toml b/packages/d2b-resource-compiler/Cargo.toml index 0b4babe40..1f12d1bb0 100644 --- a/packages/d2b-resource-compiler/Cargo.toml +++ b/packages/d2b-resource-compiler/Cargo.toml @@ -9,6 +9,7 @@ license.workspace = true d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0-bootstrap" } d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = "0.0.0-bootstrap" } d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } +d2b-contracts = { path = "../d2b-contracts", version = "0.0.0-bootstrap" } base64.workspace = true d2b-core = { path = "../d2b-core", version = "0.0.0-bootstrap" } ring.workspace = true diff --git a/packages/d2b-resource-compiler/src/lib.rs b/packages/d2b-resource-compiler/src/lib.rs index ead484ece..ae7ec0a43 100644 --- a/packages/d2b-resource-compiler/src/lib.rs +++ b/packages/d2b-resource-compiler/src/lib.rs @@ -6,7 +6,7 @@ //! traits below it. [`linux`] contains the production Linux adapter, while //! tests can provide an in-memory adapter without creating a Nix store. //! -//! A compiler diagnostic is a stable `d2b_core::error::Kind` plus a bounded +//! A compiler diagnostic is a stable `d2b_contracts::error::Kind` plus a bounded //! message. It never contains the selected store path, manifest bytes, config //! bytes, key material, or process data. //! @@ -37,8 +37,8 @@ use d2b_contracts_resource::v3::{ process::{ExecutionSpec, ProcessClass, ProcessSpec, SandboxSpec, TelemetrySpec}, }; use d2b_contracts_zone_session::v3::resource_bundle::ProcessTemplateBinding; +use d2b_contracts::error::Kind; use d2b_core::{ - error::Kind, provider_artifact::{ AnchoredDir, Argv, Envp, LaunchError, LayoutDir, LayoutError, LayoutPath, ProcessLauncher, ReadableFile, diff --git a/packages/d2b/src/lib.rs b/packages/d2b/src/lib.rs index 619e4b0fa..52fbfaa7c 100644 --- a/packages/d2b/src/lib.rs +++ b/packages/d2b/src/lib.rs @@ -9,7 +9,7 @@ use std::{ }; use clap::CommandFactory; -use d2b_core::error::Error as CoreError; +use d2b_contracts::error::Error as CoreError; use serde::Serialize; use serde_json::Value; diff --git a/packages/d2bd-runtime/src/unsafe_local_helper.rs b/packages/d2bd-runtime/src/unsafe_local_helper.rs index 9f57b426b..203f2f9de 100644 --- a/packages/d2bd-runtime/src/unsafe_local_helper.rs +++ b/packages/d2bd-runtime/src/unsafe_local_helper.rs @@ -1171,11 +1171,13 @@ fn now_epoch_seconds() -> u64 { #[cfg(test)] mod tests { use super::*; - use d2b_contracts::{ids::OperationId, token::ProtocolToken, workload_identity::WorkloadTarget}; + use d2b_contracts::{ + configured_argv::ConfiguredArgv, ids::OperationId, token::ProtocolToken, + workload_identity::WorkloadTarget, + }; use d2b_contracts_resource::v3::{ ResourceGeneration, ResourceRef, ResourceUid, ZoneId, ZoneResourceIdentity, ZoneRevision, }; - use d2b_core::configured_argv::ConfiguredArgv; use nix::fcntl::{FcntlArg, FdFlag, fcntl}; use nix::sys::socket::{AddressFamily, SockFlag, socketpair}; use std::os::fd::OwnedFd; diff --git a/packages/d2bd-runtime/src/workload_dispatch.rs b/packages/d2bd-runtime/src/workload_dispatch.rs index 0d0fc3b53..de51c1e23 100644 --- a/packages/d2bd-runtime/src/workload_dispatch.rs +++ b/packages/d2bd-runtime/src/workload_dispatch.rs @@ -14,13 +14,13 @@ use d2b_contracts_control::{ public_wire::{GraphicalLaunchPosture, WorkloadAvailability, WorkloadPublicSummary}, unsafe_local_wire::RealmAccentColor, }; -use d2b_core::{ - bundle_resolver::BundleResolver, +use d2b_contracts::{ configured_argv::ConfiguredArgv, unsafe_local_workloads::{ UnsafeLocalLauncherItem, UnsafeLocalWorkloadsJson, }, }; +use d2b_core::bundle_resolver::BundleResolver; use crate::typed_error::{TypedError, WorkloadLaunchErrorKind}; use crate::unsafe_local_helper::{HelperAvailability, HelperRegistryError}; @@ -578,8 +578,6 @@ mod tests { WorkloadExecutionPosture, ids::{RealmId, WorkloadId}, realm::RealmPath, - }; - use d2b_core::{ configured_argv::ConfiguredArgv, contract_id::ContractId, unsafe_local_workloads::{ @@ -920,7 +918,7 @@ mod tests { let mut kind_mismatch = private_artifact(std::slice::from_ref(&entry)); kind_mismatch.workloads[0].items[0] = UnsafeLocalLauncherItem::Shell( - d2b_core::unsafe_local_workloads::UnsafeLocalShellItem { + d2b_contracts::unsafe_local_workloads::UnsafeLocalShellItem { id: item.clone(), name: "Browser".to_owned(), icon: LauncherIcon::default(), diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..6bb6bca7b 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -74,7 +74,7 @@ use d2b_core::bundle_resolver::{ intent_id_network_bridge_uids, intent_id_network_hosts_uids, intent_id_network_projection_uids, intent_id_network_route_uids, intent_id_network_sysctl_uids, }; -use d2b_core::error::BundleError; +use d2b_contracts::error::BundleError; use d2b_core::host::{HostJson, QemuMediaSourceIntent}; use d2b_core::manifest_v04::ManifestV04; use d2b_core::processes::{ProcessNode, ProcessRole, ProcessesJson, ReadinessPredicate}; @@ -7924,7 +7924,7 @@ fn prepare_workload_launch( state: &ServerState, requester_uid: u32, catalog: &workload_dispatch::WorkloadCatalog, - private: Option<&d2b_core::unsafe_local_workloads::UnsafeLocalWorkloadsJson>, + private: Option<&d2b_contracts::unsafe_local_workloads::UnsafeLocalWorkloadsJson>, args: &public_wire::LauncherExecArgs, ) -> Result< ( @@ -8437,8 +8437,6 @@ mod workload_observability_tests { launcher::LauncherWorkloadSummary, realm::RealmPath, workload_identity::{WorkloadIdentity, WorkloadTarget}, - }; - use d2b_core::{ configured_argv::ConfiguredArgv, contract_id::ContractId, unsafe_local_workloads::{ @@ -9589,7 +9587,7 @@ fn dispatch_broker_usbip_probe( ) -> Result { let resolver = BundleResolver::load(&state.config.artifacts.bundle_path).map_err(|err| match err { - d2b_core::error::Error::Bundle(BundleError::Tampered { path, reason }) => { + d2b_contracts::error::Error::Bundle(BundleError::Tampered { path, reason }) => { TypedError::BundleTampered { path, reason } } other => TypedError::InternalIo { @@ -14224,9 +14222,9 @@ pub(crate) async fn load_bundle_resolver_on_worker( loaded.map_err(bundle_resolver_load_error) } -fn bundle_resolver_load_error(err: d2b_core::error::Error) -> TypedError { +fn bundle_resolver_load_error(err: d2b_contracts::error::Error) -> TypedError { match err { - d2b_core::error::Error::Bundle(BundleError::Tampered { path, reason }) => { + d2b_contracts::error::Error::Bundle(BundleError::Tampered { path, reason }) => { TypedError::BundleTampered { path, reason } } other => TypedError::InternalIo { diff --git a/packages/d2bd/tests/bundle_tampered_envelope.rs b/packages/d2bd/tests/bundle_tampered_envelope.rs index ced7b26ff..bad3603f8 100644 --- a/packages/d2bd/tests/bundle_tampered_envelope.rs +++ b/packages/d2bd/tests/bundle_tampered_envelope.rs @@ -12,7 +12,7 @@ //! is introduced via mode 0o644 (world-readable; policy requires 0o640). use d2b_core::bundle_resolver::{BundleResolver, BundleVerifyPolicy}; -use d2b_core::error::{BundleError, Error as CoreError}; +use d2b_contracts::error::{BundleError, Error as CoreError}; use d2bd_runtime::typed_error::TypedError; use std::fs; use std::io::Write as _; diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index 41879a7c1..921afb9d9 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -26,12 +26,15 @@ use d2b_contracts_control::cli_output::{ use d2b_contracts_control::public_wire; use d2b_contracts_control::unsafe_local_wire::UnsafeLocalHelperWireSchema; use d2b_contracts_resource::v3::storage::ZoneStoreStorageRow; +use d2b_contracts::{ + error::Error, + unsafe_local_workloads::UnsafeLocalWorkloadsJson, +}; use d2b_core::{ - allocator_config::AllocatorJson, bundle::Bundle, closures::ClosureMetadata, error::Error, + allocator_config::AllocatorJson, bundle::Bundle, closures::ClosureMetadata, host::HostJson, manifest_v04::ManifestV04, sandbox_profile::SandboxProfile, privileges::PrivilegesJson, processes::ProcessesJson, site::SiteJson, storage::StorageJson, storage_lifecycle::StorageLifecycleReport, sync::SyncJson, - unsafe_local_workloads::UnsafeLocalWorkloadsJson, }; mod diagnostic_redaction; use schemars::schema::RootSchema; From 707ad428e975ef73d52cac841e3c09c6263cff95 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:53:33 -0700 Subject: [PATCH 605/726] refactor(d2b-resource-client): compare assignment refs by borrow instead of cloning --- changelog.d/w5-16-resource-client-ref-borrow.md | 3 +++ packages/d2b-resource-client/src/target.rs | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 changelog.d/w5-16-resource-client-ref-borrow.md diff --git a/changelog.d/w5-16-resource-client-ref-borrow.md b/changelog.d/w5-16-resource-client-ref-borrow.md new file mode 100644 index 000000000..013458302 --- /dev/null +++ b/changelog.d/w5-16-resource-client-ref-borrow.md @@ -0,0 +1,3 @@ +### Fixed + +- `ResolvedTarget::matches_assignment` now compares the `Execution` assignment reference against each owner form by borrow: the stored reference for a `Resource` owner and the resource type and name components for `Guest`, `Provider`, and `Host` owners, instead of materializing a `ResourceRef` and cloning just to compare (`target.rs`). The by-value `resource_ref()` accessors are unchanged. diff --git a/packages/d2b-resource-client/src/target.rs b/packages/d2b-resource-client/src/target.rs index 380083e0b..325d1d3d3 100644 --- a/packages/d2b-resource-client/src/target.rs +++ b/packages/d2b-resource-client/src/target.rs @@ -420,9 +420,20 @@ impl ResolvedTarget { .first() .is_some_and(|label| label.as_str() == zone.as_str()) } - AssignmentTarget::Execution { reference, .. } => { - self.resource_ref().as_ref() == Some(reference) - } + AssignmentTarget::Execution { reference, .. } => match &self.owner { + ServiceOwner::Resource { resource, .. } => resource == reference, + ServiceOwner::Guest { guest, .. } => { + reference.resource_type().as_str() == "Guest" && reference.name() == guest + } + ServiceOwner::Provider { provider, .. } => { + reference.resource_type().as_str() == "Provider" + && reference.name() == provider + } + ServiceOwner::Host { host, .. } => { + reference.resource_type().as_str() == "Host" && reference.name() == host + } + ServiceOwner::ZoneLocal(_) | ServiceOwner::Zone(_) => false, + }, } } } From ff355ba32dca8b641603aa3030419e28e182a1d2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:53:41 -0700 Subject: [PATCH 606/726] fix(resource-api): drop the generated d2b_resource_v3 alias module The gen-resource-ttrpc generator now rewrites the emitted message-module references from super::d2b_resource_v3 to the canonical d2b_contracts_resource::resource_proto path, redirects the ttrpc handler macro invocations to a local macro that takes the full request-type path, and emits mod.rs without the alias module. The published crate root no longer re-exports protobuf. The ttrpc protocol bytes are unchanged. --- .../w6-09-resource-ttrpc-module-paths.md | 8 + .../src/generated/d2b_resource_v3_ttrpc.rs | 140 +++++++++++------- .../d2b-resource-api/src/generated/mod.rs | 4 - packages/d2b-resource-api/src/lib.rs | 1 - packages/xtask/src/main.rs | 86 ++++++++++- 5 files changed, 178 insertions(+), 61 deletions(-) create mode 100644 changelog.d/w6-09-resource-ttrpc-module-paths.md diff --git a/changelog.d/w6-09-resource-ttrpc-module-paths.md b/changelog.d/w6-09-resource-ttrpc-module-paths.md new file mode 100644 index 000000000..e531ace74 --- /dev/null +++ b/changelog.d/w6-09-resource-ttrpc-module-paths.md @@ -0,0 +1,8 @@ +### Fixed + +- The generated `d2b-resource-api` ttrpc surface no longer carries the + `d2b_resource_v3` alias module: the generator now rewrites the emitted + message-module references to the canonical + `d2b_contracts_resource::resource_proto` path, and the + `pub use protobuf;` re-export is removed from the published crate root. + The ttrpc protocol bytes are unchanged. \ No newline at end of file diff --git a/packages/d2b-resource-api/src/generated/d2b_resource_v3_ttrpc.rs b/packages/d2b-resource-api/src/generated/d2b_resource_v3_ttrpc.rs index ae0b6226d..94710eab4 100644 --- a/packages/d2b-resource-api/src/generated/d2b_resource_v3_ttrpc.rs +++ b/packages/d2b-resource-api/src/generated/d2b_resource_v3_ttrpc.rs @@ -15,6 +15,42 @@ use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; +macro_rules! async_request_handler { + ($class: ident, $ctx: ident, $req: ident, $req_type: path, $req_fn: ident) => { + let mut req = <$req_type>::new(); + { + let mut s = CodedInputStream::from_bytes(&$req.payload); + req.merge_from(&mut s) + .map_err(::ttrpc::err_to_others!(e, ""))?; + } + + let mut res = ::ttrpc::Response::new(); + match $class.service.$req_fn(&$ctx, req).await { + Ok(rep) => { + res.set_status(::ttrpc::get_status(::ttrpc::Code::OK, "".to_string())); + res.payload.reserve(rep.compute_size() as usize); + let mut s = protobuf::CodedOutputStream::vec(&mut res.payload); + rep.write_to(&mut s) + .map_err(::ttrpc::err_to_others!(e, ""))?; + s.flush().map_err(::ttrpc::err_to_others!(e, ""))?; + } + Err(x) => match x { + ::ttrpc::Error::RpcStatus(s) => { + res.set_status(s); + } + _ => { + res.set_status(::ttrpc::get_status( + ::ttrpc::Code::UNKNOWN, + format!("{:?}", x), + )); + } + }, + } + + return Ok(res); + }; +} + #[derive(Clone)] pub struct ResourceServiceClient { client: ::ttrpc::r#async::Client, @@ -27,68 +63,68 @@ impl ResourceServiceClient { } } - pub async fn get(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::GetRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::GetResponse::new(); + pub async fn get(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::GetRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::GetResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "Get", cres); } - pub async fn list(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::ListRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::ListResponse::new(); + pub async fn list(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::ListRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::ListResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "List", cres); } - pub async fn watch(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::WatchRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::WatchResponse::new(); + pub async fn watch(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::WatchRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::WatchResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "Watch", cres); } - pub async fn create(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::CreateRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::CreateResponse::new(); + pub async fn create(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::CreateRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::CreateResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "Create", cres); } - pub async fn update_spec(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::UpdateSpecRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::UpdateSpecResponse::new(); + pub async fn update_spec(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::UpdateSpecRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::UpdateSpecResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "UpdateSpec", cres); } - pub async fn update_status(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::UpdateStatusRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::UpdateStatusResponse::new(); + pub async fn update_status(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::UpdateStatusRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::UpdateStatusResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "UpdateStatus", cres); } - pub async fn update_metadata(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::UpdateMetadataRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::UpdateMetadataResponse::new(); + pub async fn update_metadata(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::UpdateMetadataRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::UpdateMetadataResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "UpdateMetadata", cres); } - pub async fn update_finalizers(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::UpdateFinalizersRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::UpdateFinalizersResponse::new(); + pub async fn update_finalizers(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::UpdateFinalizersRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::UpdateFinalizersResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "UpdateFinalizers", cres); } - pub async fn delete(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::DeleteRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::DeleteResponse::new(); + pub async fn delete(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::DeleteRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::DeleteResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "Delete", cres); } - pub async fn commit_batch(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::CommitBatchRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::CommitBatchResponse::new(); + pub async fn commit_batch(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::CommitBatchRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::CommitBatchResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "CommitBatch", cres); } - pub async fn resolve_ref(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::ResolveRefRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::ResolveRefResponse::new(); + pub async fn resolve_ref(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::ResolveRefRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::ResolveRefResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "ResolveRef", cres); } - pub async fn inspect_schema(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::InspectSchemaRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::InspectSchemaResponse::new(); + pub async fn inspect_schema(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::InspectSchemaRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::InspectSchemaResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "InspectSchema", cres); } - pub async fn upgrade(&self, ctx: ttrpc::context::Context, req: &super::d2b_resource_v3::UpgradeRequest) -> ::ttrpc::Result { - let mut cres = super::d2b_resource_v3::UpgradeResponse::new(); + pub async fn upgrade(&self, ctx: ttrpc::context::Context, req: &d2b_contracts_resource::resource_proto::UpgradeRequest) -> ::ttrpc::Result { + let mut cres = d2b_contracts_resource::resource_proto::UpgradeResponse::new(); ::ttrpc::async_client_request!(self, ctx, req, "d2b.resource.v3.ResourceService", "Upgrade", cres); } } @@ -100,7 +136,7 @@ struct GetMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for GetMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, GetRequest, get); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::GetRequest, get); } } @@ -111,7 +147,7 @@ struct ListMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for ListMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, ListRequest, list); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::ListRequest, list); } } @@ -122,7 +158,7 @@ struct WatchMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for WatchMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, WatchRequest, watch); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::WatchRequest, watch); } } @@ -133,7 +169,7 @@ struct CreateMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for CreateMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, CreateRequest, create); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::CreateRequest, create); } } @@ -144,7 +180,7 @@ struct UpdateSpecMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for UpdateSpecMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, UpdateSpecRequest, update_spec); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::UpdateSpecRequest, update_spec); } } @@ -155,7 +191,7 @@ struct UpdateStatusMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for UpdateStatusMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, UpdateStatusRequest, update_status); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::UpdateStatusRequest, update_status); } } @@ -166,7 +202,7 @@ struct UpdateMetadataMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for UpdateMetadataMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, UpdateMetadataRequest, update_metadata); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::UpdateMetadataRequest, update_metadata); } } @@ -177,7 +213,7 @@ struct UpdateFinalizersMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for UpdateFinalizersMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, UpdateFinalizersRequest, update_finalizers); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::UpdateFinalizersRequest, update_finalizers); } } @@ -188,7 +224,7 @@ struct DeleteMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for DeleteMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, DeleteRequest, delete); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::DeleteRequest, delete); } } @@ -199,7 +235,7 @@ struct CommitBatchMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for CommitBatchMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, CommitBatchRequest, commit_batch); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::CommitBatchRequest, commit_batch); } } @@ -210,7 +246,7 @@ struct ResolveRefMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for ResolveRefMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, ResolveRefRequest, resolve_ref); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::ResolveRefRequest, resolve_ref); } } @@ -221,7 +257,7 @@ struct InspectSchemaMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for InspectSchemaMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, InspectSchemaRequest, inspect_schema); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::InspectSchemaRequest, inspect_schema); } } @@ -232,49 +268,49 @@ struct UpgradeMethod { #[async_trait] impl ::ttrpc::r#async::MethodHandler for UpgradeMethod { async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, UpgradeRequest, upgrade); + async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::UpgradeRequest, upgrade); } } #[async_trait] pub trait ResourceService: Sync { - async fn get(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::GetRequest) -> ::ttrpc::Result { + async fn get(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::GetRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/Get is not supported".to_string()))) } - async fn list(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::ListRequest) -> ::ttrpc::Result { + async fn list(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::ListRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/List is not supported".to_string()))) } - async fn watch(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::WatchRequest) -> ::ttrpc::Result { + async fn watch(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::WatchRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/Watch is not supported".to_string()))) } - async fn create(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::CreateRequest) -> ::ttrpc::Result { + async fn create(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::CreateRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/Create is not supported".to_string()))) } - async fn update_spec(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::UpdateSpecRequest) -> ::ttrpc::Result { + async fn update_spec(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::UpdateSpecRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/UpdateSpec is not supported".to_string()))) } - async fn update_status(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::UpdateStatusRequest) -> ::ttrpc::Result { + async fn update_status(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::UpdateStatusRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/UpdateStatus is not supported".to_string()))) } - async fn update_metadata(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::UpdateMetadataRequest) -> ::ttrpc::Result { + async fn update_metadata(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::UpdateMetadataRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/UpdateMetadata is not supported".to_string()))) } - async fn update_finalizers(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::UpdateFinalizersRequest) -> ::ttrpc::Result { + async fn update_finalizers(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::UpdateFinalizersRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/UpdateFinalizers is not supported".to_string()))) } - async fn delete(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::DeleteRequest) -> ::ttrpc::Result { + async fn delete(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::DeleteRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/Delete is not supported".to_string()))) } - async fn commit_batch(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::CommitBatchRequest) -> ::ttrpc::Result { + async fn commit_batch(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::CommitBatchRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/CommitBatch is not supported".to_string()))) } - async fn resolve_ref(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::ResolveRefRequest) -> ::ttrpc::Result { + async fn resolve_ref(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::ResolveRefRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/ResolveRef is not supported".to_string()))) } - async fn inspect_schema(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::InspectSchemaRequest) -> ::ttrpc::Result { + async fn inspect_schema(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::InspectSchemaRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/InspectSchema is not supported".to_string()))) } - async fn upgrade(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::d2b_resource_v3::UpgradeRequest) -> ::ttrpc::Result { + async fn upgrade(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: d2b_contracts_resource::resource_proto::UpgradeRequest) -> ::ttrpc::Result { Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/d2b.resource.v3.ResourceService/Upgrade is not supported".to_string()))) } } diff --git a/packages/d2b-resource-api/src/generated/mod.rs b/packages/d2b-resource-api/src/generated/mod.rs index f33c643e3..08cf4886d 100644 --- a/packages/d2b-resource-api/src/generated/mod.rs +++ b/packages/d2b-resource-api/src/generated/mod.rs @@ -1,7 +1,3 @@ // @generated -pub mod d2b_resource_v3 { - pub use d2b_contracts_resource::resource_proto::*; -} - pub mod d2b_resource_v3_ttrpc; diff --git a/packages/d2b-resource-api/src/lib.rs b/packages/d2b-resource-api/src/lib.rs index ad2cf8a75..33de83605 100644 --- a/packages/d2b-resource-api/src/lib.rs +++ b/packages/d2b-resource-api/src/lib.rs @@ -21,7 +21,6 @@ pub use adapter::{ decode_scoped_commit_request, reject_scoped_commit_frame, }; pub use admission::{AdmissionError, AdmittedMutation}; -pub use protobuf; pub use authz::{AuthorizationLease, StoreSealHandoffError}; pub use client::ResourceApiClient; pub use d2b_contracts_resource::v3::PreparedStoreMutation; diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index 41879a7c1..1adea5fee 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -372,14 +372,17 @@ fn gen_resource_ttrpc() -> Result, Box> { let out_file = out_dir.join("d2b_resource_v3_ttrpc.rs"); sanitize_generated_rust(&out_file)?; - // The generated ttrpc surface references `super::d2b_resource_v3::...` - // for the message types, so the module file carries the alias beside the - // ttrpc module. Generator-owned like the contracts-resource side's + // The compiler emits `super::d2b_resource_v3::...` message paths that + // used to resolve through an alias module beside the ttrpc module; the + // alias is gone, so the paths are rewritten to the canonical + // d2b_contracts_resource path (see rewrite_ttrpc_message_paths). + // Generator-owned like the contracts-resource side's // `write_contract_generated_mod`, so the generated dir has no // hand-editable gap. + rewrite_ttrpc_message_paths(&out_file)?; fs::write( out_dir.join("mod.rs"), - "// @generated\n\npub mod d2b_resource_v3 {\n pub use d2b_contracts_resource::resource_proto::*;\n}\n\npub mod d2b_resource_v3_ttrpc;\n", + "// @generated\n\npub mod d2b_resource_v3_ttrpc;\n", )?; Ok(vec![out_file, out_dir.join("mod.rs")]) } @@ -476,6 +479,81 @@ fn sanitize_generated_rust(path: &Path) -> Result<(), Box Ok(()) } +/// Local stand-in for `::ttrpc::async_request_handler!` (ttrpc 0.9.0) that +/// takes the full request-type path instead of a module ident: the upstream +/// macro hardcodes `super::$server::`, which no longer resolves once the +/// alias module is gone. The body mirrors the upstream macro verbatim. +const TTRPC_HANDLER_MACRO: &str = r#"macro_rules! async_request_handler { + ($class: ident, $ctx: ident, $req: ident, $req_type: path, $req_fn: ident) => { + let mut req = <$req_type>::new(); + { + let mut s = CodedInputStream::from_bytes(&$req.payload); + req.merge_from(&mut s) + .map_err(::ttrpc::err_to_others!(e, ""))?; + } + + let mut res = ::ttrpc::Response::new(); + match $class.service.$req_fn(&$ctx, req).await { + Ok(rep) => { + res.set_status(::ttrpc::get_status(::ttrpc::Code::OK, "".to_string())); + res.payload.reserve(rep.compute_size() as usize); + let mut s = protobuf::CodedOutputStream::vec(&mut res.payload); + rep.write_to(&mut s) + .map_err(::ttrpc::err_to_others!(e, ""))?; + s.flush().map_err(::ttrpc::err_to_others!(e, ""))?; + } + Err(x) => match x { + ::ttrpc::Error::RpcStatus(s) => { + res.set_status(s); + } + _ => { + res.set_status(::ttrpc::get_status( + ::ttrpc::Code::UNKNOWN, + format!("{:?}", x), + )); + } + }, + } + + return Ok(res); + }; +}"#; + +/// Rewrites the ttrpc-compiler message-module references to the canonical +/// `d2b_contracts_resource::resource_proto` path. +/// +/// The compiler emits `super::d2b_resource_v3::...` paths in every method +/// signature and `::ttrpc::async_request_handler!(..., d2b_resource_v3, ...)` +/// invocations whose `$server` fragment the ttrpc macro expands to +/// `super::$server::`. Both assumed a `d2b_resource_v3` alias module beside +/// the ttrpc module; the alias is gone, so the paths are rewritten to the +/// canonical message-module path and the invocations are redirected to the +/// local macro above. The ttrpc protocol bytes are untouched - this is a +/// Rust path rewrite only. +#[allow(clippy::disallowed_methods, reason = "CLI-only path")] +fn rewrite_ttrpc_message_paths(path: &Path) -> Result<(), Box> { + let mut generated = fs::read_to_string(path)?; + generated = generated.replace( + "super::d2b_resource_v3::", + "d2b_contracts_resource::resource_proto::", + ); + generated = generated.replace( + "::ttrpc::async_request_handler!(self, ctx, req, d2b_resource_v3, ", + "async_request_handler!(self, ctx, req, d2b_contracts_resource::resource_proto::", + ); + // macro_rules! must precede its uses textually, so the local handler + // macro is injected after the import block. The anchor is load-bearing: + // if the compiler stops emitting it, fail instead of silently leaving + // the invocations unqualified. + const ANCHOR: &str = "use async_trait::async_trait;\n"; + if !generated.contains(ANCHOR) { + return Err("generated ttrpc file lost the import anchor".into()); + } + generated = generated.replace(ANCHOR, &format!("{ANCHOR}\n{TTRPC_HANDLER_MACRO}\n")); + fs::write(path, generated)?; + Ok(()) +} + #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn redact_generated_protobuf_formatting(path: &Path) -> Result<(), Box> { const DERIVE: &str = "#[derive(PartialEq,Clone,Default,Debug)]"; From 1fe37219f84e662da7c9f0b8916fd3f73e75c7a2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:53:56 -0700 Subject: [PATCH 607/726] refactor(d2b-provider-credential-entra): fold deadline trio onto toolkit credential helpers --- changelog.d/w5-14-entra-deadline-toolkit.md | 4 ++ .../d2b-provider-credential-entra/src/lib.rs | 72 ++----------------- .../src/service.rs | 28 +++++--- 3 files changed, 28 insertions(+), 76 deletions(-) create mode 100644 changelog.d/w5-14-entra-deadline-toolkit.md diff --git a/changelog.d/w5-14-entra-deadline-toolkit.md b/changelog.d/w5-14-entra-deadline-toolkit.md new file mode 100644 index 000000000..616b8b2cd --- /dev/null +++ b/changelog.d/w5-14-entra-deadline-toolkit.md @@ -0,0 +1,4 @@ +### Fixed + +- Folded the in-crate deadline trio (`operation_deadline`, `time_bound_instant`, `time_bounds_not_after`, `time_bound_instant_at`, `is_expired_unix_ms`) in d2b-provider-credential-entra onto the shared `d2b_provider_toolkit::credential` helpers (`operation_deadline`, `now_unix_ms`, `is_absolute_unix_ms`); all eight call sites in lib.rs and service.rs re-pointed, and the expired-grant and expired-inspection checks now compose the toolkit primitives directly. +- Deadline bounds checks in `authorize_request` now compare two `operation_deadline` instants via a small private composition helper instead of the crate-local single-snapshot conversion; zero-duration deadlines are rejected with `DeadlineExceeded` like the rest of the credential family. \ No newline at end of file diff --git a/packages/d2b-provider-credential-entra/src/lib.rs b/packages/d2b-provider-credential-entra/src/lib.rs index ba4c2dbc0..353fb3da2 100644 --- a/packages/d2b-provider-credential-entra/src/lib.rs +++ b/packages/d2b-provider-credential-entra/src/lib.rs @@ -15,7 +15,7 @@ use std::fmt; use std::future::Future; use std::pin::Pin; use std::sync::{Arc, Mutex, MutexGuard, TryLockError}; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +use std::time::{SystemTime, UNIX_EPOCH}; use d2b_contracts_provider::v3::credential::{ CREDENTIAL_SERVICE_NAME, CredentialLeaseHandle, CredentialLeaseState, CredentialMetadata, @@ -26,7 +26,7 @@ use d2b_contracts_resource::v3::ResourceRef; use d2b_provider_toolkit::{ AuthenticatedSessionRouteBinding, GuestCredentialBackend, GuestCredentialBackendResponse, ProviderFd10Spec, ProviderRuntimeError, ProviderSessionMetadata, RouteCredentialAuthorization, - credential::{is_absolute_unix_ms, now_unix_ms, ABSOLUTE_UNIX_MS_THRESHOLD}, + credential::{is_absolute_unix_ms, now_unix_ms, operation_deadline}, run_from_fd10 as run_provider_from_fd10, }; @@ -1098,7 +1098,7 @@ impl EntraCredentialProvider { remaining: 0, }); } - let deadline = Self::operation_deadline(deadline_ms)?; + let deadline = operation_deadline(deadline_ms)?; self.lifecycle .lock() .await @@ -1192,66 +1192,6 @@ if primary.is_some() { } } - pub(crate) fn operation_deadline(deadline_ms: u64) -> Result { - Self::time_bound_instant(deadline_ms) - } - - pub(crate) fn is_expired_unix_ms(value_ms: u64) -> bool { - is_absolute_unix_ms(value_ms) && value_ms <= now_unix_ms() - } - - pub(crate) fn time_bound_instant(value_ms: u64) -> Result { - let now = Instant::now(); - let now_unix_ms = SystemTime::now() - .duration_since(UNIX_EPOCH) - .map_err(|_| CredentialServiceError::new(CredentialServiceErrorCode::InvariantFailure))? - .as_millis() - .try_into() - .map_err(|_| { - CredentialServiceError::new(CredentialServiceErrorCode::InvariantFailure) - })?; - Self::time_bound_instant_at(value_ms, now, now_unix_ms) - } - - pub(crate) fn time_bounds_not_after( - later_ms: u64, - earlier_ms: u64, - ) -> Result { - let now = Instant::now(); - let now_unix_ms = SystemTime::now() - .duration_since(UNIX_EPOCH) - .map_err(|_| CredentialServiceError::new(CredentialServiceErrorCode::InvariantFailure))? - .as_millis() - .try_into() - .map_err(|_| { - CredentialServiceError::new(CredentialServiceErrorCode::InvariantFailure) - })?; - let later = Self::time_bound_instant_at(later_ms, now, now_unix_ms)?; - let earlier = Self::time_bound_instant_at(earlier_ms, now, now_unix_ms)?; - Ok(later <= earlier) - } - - fn time_bound_instant_at( - value_ms: u64, - now: Instant, - now_unix_ms: u64, - ) -> Result { - if value_ms >= ABSOLUTE_UNIX_MS_THRESHOLD { - let remaining_ms = value_ms.checked_sub(now_unix_ms).ok_or_else(|| { - CredentialServiceError::new(CredentialServiceErrorCode::DeadlineExceeded) - })?; - now.checked_add(Duration::from_millis(remaining_ms)) - .ok_or_else(|| { - CredentialServiceError::new(CredentialServiceErrorCode::DeadlineExceeded) - }) - } else { - now.checked_add(Duration::from_millis(value_ms)) - .ok_or_else(|| { - CredentialServiceError::new(CredentialServiceErrorCode::DeadlineExceeded) - }) - } - } - pub(crate) fn map_client_error(error: EntraClientError) -> CredentialServiceError { tracing::warn!( provider = crate::PROVIDER_REF, @@ -1293,7 +1233,7 @@ if primary.is_some() { CredentialServiceErrorCode::InvariantFailure, )); } - if Self::is_expired_unix_ms(grant.expires_at_unix_ms) { + if is_absolute_unix_ms(grant.expires_at_unix_ms) && grant.expires_at_unix_ms <= now_unix_ms() { return Err(CredentialServiceError::new( CredentialServiceErrorCode::InvariantFailure, )); @@ -1451,9 +1391,9 @@ mod tests { .duration_since(UNIX_EPOCH) .unwrap() .as_millis() as u64; - assert!(EntraCredentialProvider::operation_deadline(now + 1_000).is_ok()); + assert!(operation_deadline(now + 1_000).is_ok()); assert_eq!( - EntraCredentialProvider::operation_deadline(now - 1) + operation_deadline(now - 1) .unwrap_err() .code(), CredentialServiceErrorCode::DeadlineExceeded diff --git a/packages/d2b-provider-credential-entra/src/service.rs b/packages/d2b-provider-credential-entra/src/service.rs index 49c5331b6..733d3523d 100644 --- a/packages/d2b-provider-credential-entra/src/service.rs +++ b/packages/d2b-provider-credential-entra/src/service.rs @@ -8,6 +8,7 @@ use d2b_contracts_provider::v3::credential::{ }; use d2b_contracts_resource::v3::ResourceRef; use d2b_contracts_resource::v3::identity::Locality; +use d2b_provider_toolkit::credential::{is_absolute_unix_ms, now_unix_ms, operation_deadline}; use crate::{ CREDENTIAL_SESSION_PURPOSE, EntraClientState, EntraCredentialProvider, EntraLeaseInspection, @@ -70,6 +71,13 @@ impl CredentialProvider for &EntraCredentialProvider { } impl EntraCredentialProvider { + fn time_bounds_not_after( + later_ms: u64, + earlier_ms: u64, + ) -> Result { + Ok(operation_deadline(later_ms)? <= operation_deadline(earlier_ms)?) + } + fn authorize_request( &self, method: CredentialMethod, @@ -108,9 +116,9 @@ impl EntraCredentialProvider { if request.credential_ref().resource_type().as_str() != "Credential" { return Err(denied()); } - Self::time_bound_instant(request.requested_expiry_unix_ms())?; - Self::operation_deadline(request.deadline_unix_ms())?; - Self::time_bound_instant(session.expires_at_unix_ms()).map_err(|_| denied())?; + operation_deadline(request.requested_expiry_unix_ms())?; + operation_deadline(request.deadline_unix_ms())?; + operation_deadline(session.expires_at_unix_ms()).map_err(|_| denied())?; if !Self::time_bounds_not_after( request.deadline_unix_ms(), request.requested_expiry_unix_ms(), @@ -128,8 +136,8 @@ impl EntraCredentialProvider { let delivery = authorization .delivery_session_params() .ok_or_else(invariant)?; - Self::time_bound_instant(delivery.expiry_unix_ms())?; - Self::operation_deadline(delivery.deadline_unix_ms())?; + operation_deadline(delivery.expiry_unix_ms())?; + operation_deadline(delivery.deadline_unix_ms())?; if delivery.credential_ref() != request.credential_ref() || delivery.operation_class() != method.operation_class() || delivery.consumer_provider_ref() != self.consumer_ref() @@ -169,7 +177,7 @@ impl EntraCredentialProvider { .delivery_session_params() .cloned() .ok_or_else(invariant)?; - let deadline = Self::operation_deadline(request.deadline_unix_ms())?; + let deadline = operation_deadline(request.deadline_unix_ms())?; let key = request.credential_ref().to_canonical_string(); self.ensure_client_ready_async(deadline).await?; self.ensure_lifecycle_active(&key).await?; @@ -326,7 +334,7 @@ impl EntraCredentialProvider { .delivery_session_params() .cloned() .ok_or_else(invariant)?; - let deadline = Self::operation_deadline(request.deadline_unix_ms())?; + let deadline = operation_deadline(request.deadline_unix_ms())?; let key = request.credential_ref().to_canonical_string(); self.ensure_client_ready_async(deadline).await?; self.ensure_lifecycle_active(&key).await?; @@ -419,7 +427,7 @@ if !self.adopt_committed_refresh(&key, request.idempotency_key(), grant).await? &self, request: &CredentialRequest, ) -> Result { - let deadline = Self::operation_deadline(request.deadline_unix_ms())?; + let deadline = operation_deadline(request.deadline_unix_ms())?; let key = request.credential_ref().to_canonical_string(); self.ensure_client_ready_async(deadline).await?; let primary = self @@ -515,7 +523,7 @@ if !self.adopt_committed_refresh(&key, request.idempotency_key(), grant).await? &self, request: &CredentialRequest, ) -> Result { - let deadline = Self::operation_deadline(request.deadline_unix_ms())?; + let deadline = operation_deadline(request.deadline_unix_ms())?; let key = request.credential_ref().to_canonical_string(); self.ensure_client_ready_async(deadline).await?; let record = self @@ -616,7 +624,7 @@ if inspection.rotation_generation == 0 || inspection.expires_at_unix_ms == 0 { return Err(invariant()); } let state = if inspection.state == CredentialLeaseState::Active - && crate::EntraCredentialProvider::is_expired_unix_ms(inspection.expires_at_unix_ms) + && is_absolute_unix_ms(inspection.expires_at_unix_ms) && inspection.expires_at_unix_ms <= now_unix_ms() { CredentialLeaseState::Expired } else { From 079e80ef60283a97d8a44322147e066aa3b44054 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:57:13 -0700 Subject: [PATCH 608/726] refactor(d2b-provider-toolkit): drop per-frame route clone and per-pass spec clone --- changelog.d/w5-15-toolkit-route-and-spec-borrows.md | 4 ++++ packages/d2b-provider-toolkit/src/server/adapter.rs | 8 +------- packages/d2b-provider-toolkit/src/shared_provider.rs | 8 ++++---- packages/d2bd/src/shared_provider_effects.rs | 11 ++++++----- 4 files changed, 15 insertions(+), 16 deletions(-) create mode 100644 changelog.d/w5-15-toolkit-route-and-spec-borrows.md diff --git a/changelog.d/w5-15-toolkit-route-and-spec-borrows.md b/changelog.d/w5-15-toolkit-route-and-spec-borrows.md new file mode 100644 index 000000000..e99347c6a --- /dev/null +++ b/changelog.d/w5-15-toolkit-route-and-spec-borrows.md @@ -0,0 +1,4 @@ +### Fixed + +- The provider session loop now compares the bound controller route inside the route mutex lock scope instead of cloning the route binding out of the lock on every frame, dropping the per-frame `AuthenticatedSessionRouteBinding` clone. +- `SharedProviderEffectRequest` now borrows the row's canonical spec document from the driver's spec envelope instead of cloning it into every reconcile and delete request, removing one full-spec allocation per pass. \ No newline at end of file diff --git a/packages/d2b-provider-toolkit/src/server/adapter.rs b/packages/d2b-provider-toolkit/src/server/adapter.rs index c92b526bf..4eafec74c 100644 --- a/packages/d2b-provider-toolkit/src/server/adapter.rs +++ b/packages/d2b-provider-toolkit/src/server/adapter.rs @@ -313,13 +313,7 @@ where if cancellation.is_cancelled() { return Ok(()); } - let current_route = self - .authenticated_route - .lock() - .await - .clone() - .ok_or(ProviderToolkitError::SessionUnauthenticated)?; - if current_route != route { + if self.authenticated_route.lock().await.as_ref() != Some(&route) { warn!(zone = ?route.zone(), "provider session loop aborted: bound controller route changed mid-session"); return Err(ProviderToolkitError::SessionUnauthenticated); } diff --git a/packages/d2b-provider-toolkit/src/shared_provider.rs b/packages/d2b-provider-toolkit/src/shared_provider.rs index caab7594a..6177c6490 100644 --- a/packages/d2b-provider-toolkit/src/shared_provider.rs +++ b/packages/d2b-provider-toolkit/src/shared_provider.rs @@ -506,8 +506,8 @@ pub struct SharedProviderEffectRequest<'a> { pub generation: ResourceGeneration, /// Runtime-only operation id (never persisted). pub operation_id: String, - /// Canonical spec document of the row. - pub spec: Value, + /// Canonical spec document of the row (borrowed from the row's envelope). + pub spec: &'a Value, /// Decoded metadata envelope of the row (`ownerRef`, ...). pub metadata: Value, /// The driver's last in-memory status projection, when one was published. @@ -936,7 +936,7 @@ impl, ) -> Result { - for dependency in kind.declared_dependency_refs(&request.spec, &request.metadata) { + for dependency in kind.declared_dependency_refs(request.spec, &request.metadata) { if !self.resource_ready(&dependency).await { return Ok(false); } @@ -1252,9 +1252,7 @@ impl ProductionSharedProviderEffects { &self, request: &SharedProviderEffectRequest<'_>, ) -> Result { - let mut spec_value = request - .spec - .clone(); + let mut spec_value = (*request.spec).clone(); if let Some(spec) = spec_value.as_object_mut() { for field in ["providerRef", "updatePolicy", "provider"] { spec.remove(field); @@ -3887,6 +3885,7 @@ mod tests { network_name: &str, uid: d2b_contracts_resource::v3::ResourceUid, generation: d2b_contracts_resource::v3::ResourceGeneration, + spec: &'a Value, children: &'a UnusedChildSurface, ) -> d2b_provider_toolkit::SharedProviderEffectRequest<'a> { d2b_provider_toolkit::SharedProviderEffectRequest { @@ -3895,7 +3894,7 @@ mod tests { uid, generation, operation_id: "network-admission-test".to_owned(), - spec: serde_json::json!({}), + spec, metadata: serde_json::json!({}), status: None, children: children as &dyn d2b_provider_toolkit::SharedProviderChildSurface, @@ -3916,11 +3915,13 @@ mod tests { let harness = network_admission_harness().await; let children = UnusedChildSurface; + let spec = serde_json::json!({}); let request = network_admission_request( ZoneId::parse("work").unwrap(), "zone-net", harness.network_uid.clone(), harness.network_generation, + &spec, &children, ); let result = harness From 13101e206410e56f1bd99b29bd81411ca880cea0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:57:53 -0700 Subject: [PATCH 609/726] refactor(broker): type broker operation artifacts against closed enums The generated broker operation artifacts now carry typed closed vocabularies instead of bare strings and booleans. A full BrokerOperationName enum (one variant per committed row, with as_str keeping the wire spelling) types the host/guest profile catalogs and the committed row operation field; profile admission still takes the operation name as a string, so the wire boundary is unchanged. Each row's disposition is a closed Disposition enum (callable-read-only, promoted-live, stubbed-unimplemented, compile-time-only) replacing the string matches, and the broker authz rows carry Destructive::No/Yes in place of a bare boolean, with the positional row() helper deleted. The serialized privileges.json destructive facet spells no/yes; the Nix emitter and v2 schema move with it, and the v1 schema stays frozen. --- changelog.d/w6-01-broker-operation-types.md | 17 + docs/reference/daemon-api.md | 230 +- docs/reference/schemas/v2/privileges.json | 25 +- nixos-modules/privileges-json.nix | 286 +-- .../d2b-broker-composition/src/routing.rs | 19 +- packages/d2b-broker-composition/src/seam.rs | 39 +- packages/d2b-broker/src/catalog.rs | 127 +- packages/d2b-broker/src/envelope/mod.rs | 257 ++- .../src/generated/broker_operation_catalog.rs | 392 ++-- packages/d2b-broker/src/runtime.rs | 7 +- packages/d2b-broker/tests/guest_profile.rs | 5 +- packages/d2b-broker/tests/host_profile.rs | 4 +- .../d2b-contracts-broker/src/broker_wire.rs | 14 +- .../generated/broker_operation_profiles.rs | 312 ++- .../corpus/privileges/03-enum-mismatch.json | 2 +- .../src/generated/broker_operation_authz.rs | 1960 ++++++++--------- packages/d2b-core/src/privileges.rs | 1120 +++++----- packages/xtask/src/gen_broker_operations.rs | 161 +- 18 files changed, 2712 insertions(+), 2265 deletions(-) create mode 100644 changelog.d/w6-01-broker-operation-types.md diff --git a/changelog.d/w6-01-broker-operation-types.md b/changelog.d/w6-01-broker-operation-types.md new file mode 100644 index 000000000..11dee506b --- /dev/null +++ b/changelog.d/w6-01-broker-operation-types.md @@ -0,0 +1,17 @@ +### Changed + +- The generated broker operation artifacts are now typed instead of carrying + bare strings and booleans. The profile catalogs (`HOST_OPERATION_CATALOG` / + `GUEST_OPERATION_CATALOG`) and every committed row's `operation` field are + typed against a closed `BrokerOperationName` enum emitted by the generator + (one variant per committed row, with `as_str` keeping the wire spelling); + profile admission still takes the operation name as a string, so the wire + boundary is unchanged. Each row's `disposition` is a closed `Disposition` + enum (callable-read-only, promoted-live, stubbed-unimplemented, + compile-time-only) instead of a string, and the broker authorization rows + carry `Destructive::No`/`Destructive::Yes` in place of a bare boolean. + +- The serialized `privileges.json` authorization shape spells the + `destructive` facet as `"no"`/`"yes"` instead of `false`/`true`. The Nix + emitter that produces the artifact and the v2 JSON schema move with the + change; the v1 schema stays frozen. \ No newline at end of file diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index c01f9e043..22ecdadb6 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -83,8 +83,8 @@ compatibility surface. | `HelloOk` | struct | [`HelloOk`](../../packages/d2b-contracts/src/lib.rs#L159) | struct { `server_version`: `Version`; `selected_version`: `Version`; `capabilities`: `Vec` } | | `HelloRejected` | struct | [`HelloRejected`](../../packages/d2b-contracts/src/lib.rs#L167) | struct { `reason`: `HelloRejectedReason` } | | `HelloRejectedReason` | enum | [`HelloRejectedReason`](../../packages/d2b-contracts/src/lib.rs#L173) | `VersionMismatch`; `CapabilityNegotiationFailed`; `InternalError` | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L899) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L993) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L902) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L996) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | | `KnownFeatureFlag` | enum | [`KnownFeatureFlag`](../../packages/d2b-contracts/src/lib.rs#L123) | `TypedErrors`; `ManifestV04`; `StatusCheckBridges`; `ExportBrokerAudit`; `ConfiguredLaunchV1`; `UnsafeLocalProviderV1` | | `SemverRange` | struct | [`SemverRange`](../../packages/d2b-contracts/src/error.rs#L1130) | empty struct | @@ -276,65 +276,65 @@ host reboot. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `BrokerRequest` | enum | [`BrokerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L32) | `ApplyHostGenerationHandoff` - (crate::host_generation::ApplyHostGenerationHandoff); `CreateOrReconcileUsersGroups` - (CreateOrReconcileUsersGroupsRequest); `DelegateCgroupV2` - (DelegateCgroupV2Request); `ExportBrokerAudit` - (ExportBrokerAuditRequest); `Hello` - (HelloRequest); `PublishTrustedContext` - (PublishTrustedContextValues); `InjectSecretById` - (SecretByIdRequest); `LaunchMinijailChild` - (LaunchMinijailChildRequest); `ModprobeIfAllowed` - (ModprobeIfAllowedRequest); `OpenCgroupDir` - (OpenCgroupDirRequest); `OpenDevice` - (OpenDeviceRequest); `OpenFuse` - (OpenFuseRequest); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyRequest); `OpenKvm` - (OpenKvmRequest); `QemuMediaEnroll` - (QemuMediaEnrollRequest); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryRequest); `QemuMediaBoot` - (QemuMediaBootRequest); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleRequest); `QemuMediaQueryStatus` - (QemuMediaQueryStatusRequest); `QemuMediaQuit` - (QemuMediaLifecycleRequest); `QemuMediaAttach` - (QemuMediaHotplugRequest); `QemuMediaDetach` - (QemuMediaHotplugRequest); `PipeWireAudio` - (PipeWireAudioRequest); `OpenVhostNet` - (OpenVhostNetRequest); `ReconcileStorageScope` - (ReconcileStorageScopeRequest); `ValidateLockSpec` - (ValidateLockSpecRequest); `StoreSync` - (StoreSyncRequest); `ReadSecretById` - (SecretByIdRequest); `RotateSecretById` - (SecretByIdRequest); `UsbipBind` - (UsbipBindRequest); `UsbipBindFirewallRule` - (UsbipBindFirewallRuleRequest); `UsbipProxyReconcile` - (UsbipProxyReconcileRequest); `UsbipUnbind` - (UsbipUnbindRequest); `UsbipExplicitBind` - (UsbipExplicitBindRequest); `UsbipExplicitFirewallRule` - (UsbipExplicitFirewallRuleRequest); `OwnershipMatrixCheck` - (OwnershipMatrixCheckRequest); `SshHostKeyPreflight` - (SshHostKeyPreflightRequest); `DiskInit` - (DiskInitRequest); `SecurityKeyOpenDevice` - (d2b_contracts::security_key::SecurityKeyOpenDeviceRequest); `SecurityKeyApplyUdevRules` - (d2b_contracts::security_key::SecurityKeyApplyUdevRulesRequest); `EnvelopeInvoke` - (EnvelopeInvokeRequest) | -| `ForwardOperationRequest` | struct | [`ForwardOperationRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L397) | struct { `operation`: `String`; `zone`: `String`; `invocation_id`: `String`; `payload`: `serde_json::Value`; `context`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L487) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L899) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1005) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1036) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | -| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1054) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1065) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1081) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1097) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | -| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1109) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1130) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1149) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1165) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1181) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1203) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1211) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | -| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1268) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | -| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1280) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1294) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | -| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1304) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1313) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | -| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1322) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1336) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1357) | struct { `tracing_span_id`: `Option` } | -| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1379) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1387) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1395) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | -| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1460) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1547) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1620) | empty struct | -| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1635) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1709) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | -| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1779) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | -| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1835) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | -| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1846) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | -| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1919) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1927) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1939) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | -| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1982) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2004) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | -| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2041) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | -| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2055) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2078) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2095) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2103) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2111) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2133) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | -| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2151) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | -| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2246) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2303) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2312) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2596) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | -| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2933) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2950) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2961) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2975) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | -| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3012) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3046) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `BrokerRequest` | enum | [`BrokerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L31) | `ApplyHostGenerationHandoff` - (crate::host_generation::ApplyHostGenerationHandoff); `CreateOrReconcileUsersGroups` - (CreateOrReconcileUsersGroupsRequest); `DelegateCgroupV2` - (DelegateCgroupV2Request); `ExportBrokerAudit` - (ExportBrokerAuditRequest); `Hello` - (HelloRequest); `PublishTrustedContext` - (PublishTrustedContextValues); `InjectSecretById` - (SecretByIdRequest); `LaunchMinijailChild` - (LaunchMinijailChildRequest); `ModprobeIfAllowed` - (ModprobeIfAllowedRequest); `OpenCgroupDir` - (OpenCgroupDirRequest); `OpenDevice` - (OpenDeviceRequest); `OpenFuse` - (OpenFuseRequest); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyRequest); `OpenKvm` - (OpenKvmRequest); `QemuMediaEnroll` - (QemuMediaEnrollRequest); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryRequest); `QemuMediaBoot` - (QemuMediaBootRequest); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleRequest); `QemuMediaQueryStatus` - (QemuMediaQueryStatusRequest); `QemuMediaQuit` - (QemuMediaLifecycleRequest); `QemuMediaAttach` - (QemuMediaHotplugRequest); `QemuMediaDetach` - (QemuMediaHotplugRequest); `PipeWireAudio` - (PipeWireAudioRequest); `OpenVhostNet` - (OpenVhostNetRequest); `ReconcileStorageScope` - (ReconcileStorageScopeRequest); `ValidateLockSpec` - (ValidateLockSpecRequest); `StoreSync` - (StoreSyncRequest); `ReadSecretById` - (SecretByIdRequest); `RotateSecretById` - (SecretByIdRequest); `UsbipBind` - (UsbipBindRequest); `UsbipBindFirewallRule` - (UsbipBindFirewallRuleRequest); `UsbipProxyReconcile` - (UsbipProxyReconcileRequest); `UsbipUnbind` - (UsbipUnbindRequest); `UsbipExplicitBind` - (UsbipExplicitBindRequest); `UsbipExplicitFirewallRule` - (UsbipExplicitFirewallRuleRequest); `OwnershipMatrixCheck` - (OwnershipMatrixCheckRequest); `SshHostKeyPreflight` - (SshHostKeyPreflightRequest); `DiskInit` - (DiskInitRequest); `SecurityKeyOpenDevice` - (d2b_contracts::security_key::SecurityKeyOpenDeviceRequest); `SecurityKeyApplyUdevRules` - (d2b_contracts::security_key::SecurityKeyApplyUdevRulesRequest); `EnvelopeInvoke` - (EnvelopeInvokeRequest) | +| `ForwardOperationRequest` | struct | [`ForwardOperationRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L396) | struct { `operation`: `String`; `zone`: `String`; `invocation_id`: `String`; `payload`: `serde_json::Value`; `context`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L486) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L902) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1008) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1039) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | +| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1057) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1068) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1084) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1100) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | +| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1112) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1133) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1152) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1168) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1184) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1206) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1214) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | +| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1271) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | +| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1283) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1297) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | +| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1307) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1316) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | +| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1325) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1339) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1360) | struct { `tracing_span_id`: `Option` } | +| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1382) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1390) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1398) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | +| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1463) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1550) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1623) | empty struct | +| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1638) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1712) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | +| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1782) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | +| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1838) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | +| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1849) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | +| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1922) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1930) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1942) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | +| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1985) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2007) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | +| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2044) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | +| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2058) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2081) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2098) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2106) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2114) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2136) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | +| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2154) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | +| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2249) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2306) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2315) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2599) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | +| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2936) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2953) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2964) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2978) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | +| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3015) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3049) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | ### Console and audio wire types @@ -389,39 +389,39 @@ see the auto-generated tables above for the committed Rust variants. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `ApplyHostGenerationHandoffResponse` | struct | [`ApplyHostGenerationHandoffResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L212) | struct { `target`: `d2b_contracts_resource::v3::ResourceRef`; `state`: `crate::host_generation::HandoffState`; `source_generation`: `u64`; `target_generation`: `u64`; `source_remains_usable`: `bool`; `summary`: `String` } | -| `PublishTrustedContextResponse` | struct | [`PublishTrustedContextResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L373) | struct { `broker_epoch`: `u64` } | -| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L465) | struct { `outcome`: `ForwardOperationOutcome` } | -| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L519) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L907) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L966) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L993) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | -| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1346) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1364) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1440) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | -| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1447) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | -| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1490) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | -| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1601) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1625) | struct { `pidfd_index`: `u32` } | -| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1676) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | -| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1728) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | -| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1869) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1881) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | -| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1890) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | -| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1901) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1911) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | -| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1969) | struct { `selector_resolved`: `String`; `device_class`: `String` } | -| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2025) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | -| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2166) | struct { `accepted`: `bool`; `operation`: `String` } | -| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2173) | struct { `bridge`: `Option`; `tap`: `IfName` } | -| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2180) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2225) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | -| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2295) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | -| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2355) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | -| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2751) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | -| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2996) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | -| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3020) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | -| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3109) | struct { `notifications`: `Vec` } | +| `ApplyHostGenerationHandoffResponse` | struct | [`ApplyHostGenerationHandoffResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L211) | struct { `target`: `d2b_contracts_resource::v3::ResourceRef`; `state`: `crate::host_generation::HandoffState`; `source_generation`: `u64`; `target_generation`: `u64`; `source_remains_usable`: `bool`; `summary`: `String` } | +| `PublishTrustedContextResponse` | struct | [`PublishTrustedContextResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L372) | struct { `broker_epoch`: `u64` } | +| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L464) | struct { `outcome`: `ForwardOperationOutcome` } | +| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L518) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L910) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L969) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L996) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1349) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1367) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1443) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | +| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1450) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | +| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1493) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | +| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1604) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1628) | struct { `pidfd_index`: `u32` } | +| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1679) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | +| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1731) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | +| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1872) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1884) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | +| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1893) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | +| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1904) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1914) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | +| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1972) | struct { `selector_resolved`: `String`; `device_class`: `String` } | +| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2028) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | +| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2169) | struct { `accepted`: `bool`; `operation`: `String` } | +| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2176) | struct { `bridge`: `Option`; `tap`: `IfName` } | +| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2183) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2228) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | +| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2298) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | +| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2358) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | +| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2754) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | +| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2999) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | +| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3023) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | +| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3112) | struct { `notifications`: `Vec` } | ## Per-VM lifecycle state @@ -496,25 +496,25 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `FdKind` | enum | [`FdKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L253) | `Fifo`; `Socket`; `CharDevice`; `BlockDevice`; `Any`; `Regular`; `Directory` | -| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L440) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | -| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L841) | `Host`; `Guest` | -| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1024) | `Apply`; `Remove` | -| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1255) | `Info`; `Warning`; `Error`; `Denied` | -| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1409) | `SystemPowerdown`; `Quit` | -| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1416) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | -| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1469) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | -| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1689) | `Speaker`; `Microphone` | -| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1699) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | -| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1743) | `System`; `User` | -| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1859) | `Drain`; `Terminate` | -| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2238) | `Term`; `Kill`; `Quit` | -| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2374) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | -| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2729) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | -| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2887) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | -| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2985) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | -| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3059) | `Exited`; `Signaled`; `Killed` | -| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3097) | `ChildReaped` - (ChildReapedNotification); `Unknown` | +| `FdKind` | enum | [`FdKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L252) | `Fifo`; `Socket`; `CharDevice`; `BlockDevice`; `Any`; `Regular`; `Directory` | +| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L439) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | +| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L840) | `Host`; `Guest` | +| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1027) | `Apply`; `Remove` | +| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1258) | `Info`; `Warning`; `Error`; `Denied` | +| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1412) | `SystemPowerdown`; `Quit` | +| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1419) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | +| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1472) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | +| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1692) | `Speaker`; `Microphone` | +| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1702) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | +| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1746) | `System`; `User` | +| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1862) | `Drain`; `Terminate` | +| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2241) | `Term`; `Kill`; `Quit` | +| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2377) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | +| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2732) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | +| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2890) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | +| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2988) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | +| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3062) | `Exited`; `Signaled`; `Killed` | +| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3100) | `ChildReaped` - (ChildReapedNotification); `Unknown` | | `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L141) | `Lifecycle`; `Admin` | | `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L179) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | | `ProxyReadinessStage` | enum | [`ProxyReadinessStage`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L12) | `Upstream`; `Listener`; `FirstClient` | @@ -644,8 +644,8 @@ the failure class, for example `host check`, `audit`, `status`, or | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L966) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2534) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L969) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2537) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | | `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L198) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | | `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1208) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | diff --git a/docs/reference/schemas/v2/privileges.json b/docs/reference/schemas/v2/privileges.json index afc09f254..311ef3db5 100644 --- a/docs/reference/schemas/v2/privileges.json +++ b/docs/reference/schemas/v2/privileges.json @@ -87,6 +87,25 @@ "deny-and-audit" ] }, + "Destructive": { + "description": "Destructive class for an authorization row.", + "oneOf": [ + { + "description": "No state mutation, teardown, rollback, GC, or live routing change.", + "type": "string", + "enum": [ + "no" + ] + }, + { + "description": "State mutation, teardown, rollback, GC, or live routing changes are possible.", + "type": "string", + "enum": [ + "yes" + ] + } + ] + }, "OperationAuthz": { "description": "One explicit authorization row; unknown future operations always deny.", "type": "object", @@ -135,7 +154,11 @@ }, "destructive": { "description": "Whether state mutation, teardown, rollback, GC, or live routing changes are possible.", - "type": "boolean" + "allOf": [ + { + "$ref": "#/definitions/Destructive" + } + ] }, "operation": { "description": "Stable operation enum or command name.", diff --git a/nixos-modules/privileges-json.nix b/nixos-modules/privileges-json.nix index d64f4eaed..559c945e2 100644 --- a/nixos-modules/privileges-json.nix +++ b/nixos-modules/privileges-json.nix @@ -22,7 +22,7 @@ let "allowedGroups": [ "any-local-client" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "deny-only" @@ -34,7 +34,7 @@ let "allowedGroups": [ "any-local-client" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "deny-only" @@ -46,7 +46,7 @@ let "allowedGroups": [ "any-local-client" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "deny-only" @@ -59,7 +59,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "no", "auditMode": "yes" @@ -72,7 +72,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "conditional", "auditMode": "yes" @@ -85,7 +85,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "errors" @@ -97,7 +97,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "conditional", "auditMode": "yes" @@ -110,7 +110,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "conditional", "auditMode": "yes" @@ -123,7 +123,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "no", "auditMode": "yes" @@ -136,7 +136,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "conditional", "auditMode": "yes" @@ -149,7 +149,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "no", "auditMode": "yes" @@ -162,7 +162,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "no", "auditMode": "errors" @@ -175,7 +175,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "errors" @@ -188,7 +188,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "errors" @@ -201,7 +201,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "errors" @@ -214,7 +214,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "errors" @@ -227,7 +227,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -240,7 +240,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -253,7 +253,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -266,7 +266,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no-mutation", "auditMode": "yes" @@ -279,7 +279,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no-mutation", "auditMode": "yes" @@ -291,7 +291,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no-mutation", "auditMode": "yes" @@ -303,7 +303,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no-mutation", "auditMode": "yes" @@ -315,7 +315,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no-mutation", "auditMode": "yes" @@ -327,7 +327,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no-mutation", "auditMode": "yes" @@ -339,7 +339,7 @@ let "allowedGroups": [ "host-shutdown" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -351,7 +351,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "possible-paths-only", "brokerRequired": "yes", "auditMode": "yes" @@ -363,7 +363,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -375,7 +375,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "possible-paths-only", "brokerRequired": "yes", "auditMode": "yes" @@ -388,7 +388,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "conditional", "auditMode": "yes" @@ -401,7 +401,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "conditional", "auditMode": "yes" @@ -414,7 +414,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "conditional", "auditMode": "yes" @@ -427,7 +427,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -440,7 +440,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -453,7 +453,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "conditional", "auditMode": "yes" @@ -466,7 +466,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -479,7 +479,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -491,7 +491,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -503,7 +503,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "no", "auditMode": "yes" @@ -515,7 +515,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -527,7 +527,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -539,7 +539,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -551,7 +551,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -563,7 +563,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -575,7 +575,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -587,7 +587,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "public-key-only", "brokerRequired": "no", "auditMode": "yes" @@ -599,7 +599,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "public-key-only", "brokerRequired": "no", "auditMode": "yes" @@ -611,7 +611,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "read-write", "brokerRequired": "yes", "auditMode": "yes" @@ -623,7 +623,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "host-key-metadata", "brokerRequired": "conditional", "auditMode": "yes" @@ -635,7 +635,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "host-key-metadata", "brokerRequired": "conditional", "auditMode": "yes" @@ -648,7 +648,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "errors" @@ -661,7 +661,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "no", "auditMode": "errors" @@ -674,7 +674,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -687,7 +687,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -700,7 +700,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -713,7 +713,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -726,7 +726,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -738,7 +738,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -750,7 +750,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -763,7 +763,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -776,7 +776,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -788,7 +788,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": false, + "destructive": "no", "secretAccess": "redacted-only", "brokerRequired": "no-mutation", "auditMode": "yes" @@ -800,7 +800,7 @@ let "allowedGroups": [ "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -817,7 +817,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -829,7 +829,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -841,7 +841,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -853,7 +853,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -865,7 +865,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -877,7 +877,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "read-write", "brokerRequired": "yes", "auditMode": "yes" @@ -889,7 +889,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "host-key-metadata", "brokerRequired": "yes", "auditMode": "yes" @@ -901,7 +901,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "host-key-metadata", "brokerRequired": "yes", "auditMode": "yes" @@ -913,7 +913,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -925,7 +925,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -937,7 +937,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -949,7 +949,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -961,7 +961,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -973,7 +973,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -985,7 +985,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -997,7 +997,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1009,7 +1009,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1021,7 +1021,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1033,7 +1033,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1045,7 +1045,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1057,7 +1057,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1069,7 +1069,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1081,7 +1081,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1093,7 +1093,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1105,7 +1105,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1117,7 +1117,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1129,7 +1129,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1141,7 +1141,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1153,7 +1153,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1165,7 +1165,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1177,7 +1177,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1189,7 +1189,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1201,7 +1201,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1213,7 +1213,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1225,7 +1225,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1237,7 +1237,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1249,7 +1249,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "read-write", "brokerRequired": "yes", "auditMode": "yes" @@ -1261,7 +1261,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "read-write", "brokerRequired": "yes", "auditMode": "yes" @@ -1273,7 +1273,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "read-write", "brokerRequired": "yes", "auditMode": "yes" @@ -1285,7 +1285,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1297,7 +1297,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1309,7 +1309,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1321,7 +1321,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1333,7 +1333,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1345,7 +1345,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1357,7 +1357,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1369,7 +1369,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1381,7 +1381,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1393,7 +1393,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1405,7 +1405,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1417,7 +1417,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1429,7 +1429,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1441,7 +1441,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1453,7 +1453,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1465,7 +1465,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "errors" @@ -1477,7 +1477,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1489,7 +1489,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "redacted-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1501,7 +1501,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1514,7 +1514,7 @@ let "d2b-launcher", "d2b-admin" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1526,7 +1526,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1538,7 +1538,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1550,7 +1550,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1562,7 +1562,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1574,7 +1574,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1586,7 +1586,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1598,7 +1598,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1610,7 +1610,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1622,7 +1622,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1634,7 +1634,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1646,7 +1646,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1658,7 +1658,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1670,7 +1670,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1682,7 +1682,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1694,7 +1694,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1706,7 +1706,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1718,7 +1718,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1730,7 +1730,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1742,7 +1742,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "metadata-only", "brokerRequired": "yes", "auditMode": "yes" @@ -1754,7 +1754,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": false, + "destructive": "no", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" @@ -1766,7 +1766,7 @@ let "allowedGroups": [ "d2bd" ], - "destructive": true, + "destructive": "yes", "secretAccess": "none", "brokerRequired": "yes", "auditMode": "yes" diff --git a/packages/d2b-broker-composition/src/routing.rs b/packages/d2b-broker-composition/src/routing.rs index 90aba35ad..1ee78eaaf 100644 --- a/packages/d2b-broker-composition/src/routing.rs +++ b/packages/d2b-broker-composition/src/routing.rs @@ -14,9 +14,7 @@ //! registers its handler through [`crate::seam`]; this module is the //! single place the admission predicate lives. -use d2b_broker::catalog::{ - BrokerOperationRow, OperationOwner, PayloadProvenance, SecretAccess, -}; +use d2b_broker::catalog::{BrokerOperationRow, OperationOwner, PayloadProvenance, SecretAccess}; /// Why one operation was refused admission to the in-broker table. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -123,7 +121,7 @@ pub fn catalog_admitted_operations() -> Vec<&'static str> { d2b_broker::catalog::BROKER_OPERATION_CATALOG .iter() .filter(|row| route_row(row) == RoutingVerdict::InBroker) - .map(|row| row.operation) + .map(|row| row.operation.as_str()) .collect() } @@ -132,14 +130,15 @@ mod tests { use super::*; use d2b_broker::catalog::{ AuditMode, BrokerAuthzFacets, BrokerProfileId, BrokerRequirement, CellDurability, - OperationOwner, PayloadProvenance, + Disposition, OperationOwner, PayloadProvenance, }; + use d2b_contracts_broker::broker_wire::BrokerOperationName; /// A minimal pure, generic, provider-declared row (the shape a future /// pure transform will take; the fixture suite uses it as its happy /// path). const PURE_ROW: BrokerOperationRow = BrokerOperationRow { - operation: "d2b.fixture.pure.echo", + operation: BrokerOperationName::Hello, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -148,7 +147,7 @@ mod tests { profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "fixture", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -171,7 +170,7 @@ mod tests { deadline_tier: d2b_broker::catalog::DeadlineTier::Standard, }; - fn family_row(operation: &'static str) -> BrokerOperationRow { + fn family_row(operation: BrokerOperationName) -> BrokerOperationRow { let mut row = PURE_ROW; row.operation = operation; row.justification = None; @@ -201,7 +200,7 @@ mod tests { // A census row is representative: an OpenVhostNet-class // operation is family-owned, so the rule must refuse it regardless // of any other facet. - let row = family_row("d2b.fixture.family.effect"); + let row = family_row(BrokerOperationName::OpenVhostNet); assert_eq!( route_row(&row), RoutingVerdict::Forward(RefusalClass::FamilyOwned) @@ -218,7 +217,7 @@ mod tests { route_row(row), RoutingVerdict::Forward(RefusalClass::NotProviderDeclared), "broker-generic row {} must be refused", - row.operation + row.operation.as_str() ); } } diff --git a/packages/d2b-broker-composition/src/seam.rs b/packages/d2b-broker-composition/src/seam.rs index 6a5990278..20339d5e5 100644 --- a/packages/d2b-broker-composition/src/seam.rs +++ b/packages/d2b-broker-composition/src/seam.rs @@ -162,7 +162,7 @@ pub fn register_declared_handlers( } let mut table = HandlerTable::new(); for declaration in declarations { - table = table.with(declaration.row.operation, declaration.handler); + table = table.with(declaration.row.operation.as_str(), declaration.handler); } Ok(table) } @@ -174,13 +174,13 @@ pub fn register_production_handlers( declarations: &[HandlerDeclaration<'_>], ) -> Result { for declaration in declarations { - let committed = BrokerOperationRow::find(declaration.row.operation) + let committed = BrokerOperationRow::find(declaration.row.operation.as_str()) .ok_or(RoutingRefusal::Uncommitted { - operation: declaration.row.operation, + operation: declaration.row.operation.as_str(), })?; if !std::ptr::eq(committed, declaration.row) { return Err(RoutingRefusal::Uncommitted { - operation: declaration.row.operation, + operation: declaration.row.operation.as_str(), }); } } @@ -255,14 +255,14 @@ fn admit(declaration: &HandlerDeclaration) -> Result<(), RoutingRefusal> { RoutingVerdict::InBroker => {} RoutingVerdict::Forward(class) => { return Err(RoutingRefusal::Forwarded { - operation: row.operation, + operation: row.operation.as_str(), class, }) } } - if declaration.pure_claim.operation != row.operation { + if declaration.pure_claim.operation != row.operation.as_str() { return Err(RoutingRefusal::ClaimMismatch { - operation: row.operation, + operation: row.operation.as_str(), claim: declaration.pure_claim.operation, }); } @@ -271,7 +271,7 @@ fn admit(declaration: &HandlerDeclaration) -> Result<(), RoutingRefusal> { .expect("route_row admitted the row, so its provider is set; unset providers route to the forward carrier"); if declaration.source_crate != declaring_provider { return Err(RoutingRefusal::SourceCrateMismatch { - operation: row.operation, + operation: row.operation.as_str(), source_crate: declaration.source_crate, declaring_provider, }); @@ -322,19 +322,20 @@ mod tests { use super::*; use d2b_broker::catalog::{ AuditMode, BROKER_OPERATION_CATALOG, BrokerAuthzFacets, BrokerProfileId, - BrokerRequirement, CellDurability, DeadlineTier, OperationOwner, PayloadProvenance, - SecretAccess, + BrokerRequirement, CellDurability, DeadlineTier, Disposition, OperationOwner, + PayloadProvenance, SecretAccess, }; + use d2b_contracts_broker::broker_wire::BrokerOperationName; use d2b_broker::envelope::{ BrokerEnvelope, CallerAuthority, DispatchFailure, DispatchOutcome, HANDLER_REFUSED, }; use serde_json::json; - const FIXTURE_OPERATION: &str = "d2b.fixture.pure.echo"; + const FIXTURE_OPERATION: &str = "Hello"; const FIXTURE_PROVIDER: &str = "d2b-broker-fixture-handlers"; const PURE_FIXTURE_ROW: BrokerOperationRow = BrokerOperationRow { - operation: FIXTURE_OPERATION, + operation: BrokerOperationName::Hello, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -343,7 +344,7 @@ mod tests { profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "fixture", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -562,7 +563,7 @@ mod tests { // pure (read-only, no cells, no fds). let pilot = BROKER_OPERATION_CATALOG .iter() - .find(|row| row.operation == "inspect-process-family") + .find(|row| row.operation.as_str() == "inspect-process-family") .expect("the pilot operation is committed"); assert_eq!(pilot.owner, OperationOwner::Family); let declaration = HandlerDeclaration { @@ -616,11 +617,11 @@ mod tests { #[test] fn registration_of_an_uncommitted_row_is_refused() { let mut row = PURE_FIXTURE_ROW; - row.operation = "d2b.fixture.not.committed"; + row.operation = BrokerOperationName::PublishTrustedContext; row.audit_join = None; let declaration = HandlerDeclaration { row: &row, - pure_claim: PureTransformClaim::for_operation("d2b.fixture.not.committed"), + pure_claim: PureTransformClaim::for_operation("PublishTrustedContext"), ..fixture_declaration() }; let refusal = register_production_handlers(&[declaration]) @@ -710,7 +711,7 @@ mod tests { // refuses none of them silently: two pure fixture declarations // both answer through .call(). let mut second_row = PURE_FIXTURE_ROW; - second_row.operation = "d2b.fixture.second.echo"; + second_row.operation = BrokerOperationName::ExportBrokerAudit; second_row.audit_join = None; let declarations = [ fixture_declaration(), @@ -718,7 +719,7 @@ mod tests { row: &second_row, handler: d2b_broker_fixture_handlers::echo, source_crate: FIXTURE_PROVIDER, - pure_claim: PureTransformClaim::for_operation("d2b.fixture.second.echo"), + pure_claim: PureTransformClaim::for_operation("ExportBrokerAudit"), }, ]; let table = @@ -739,7 +740,7 @@ mod tests { let second = envelope .call( CallerAuthority::Daemon, - "d2b.fixture.second.echo", + "ExportBrokerAudit", "zone-1", &json!({ "echo": "two" }), ) diff --git a/packages/d2b-broker/src/catalog.rs b/packages/d2b-broker/src/catalog.rs index 1bc9ee7f5..ae01b8689 100644 --- a/packages/d2b-broker/src/catalog.rs +++ b/packages/d2b-broker/src/catalog.rs @@ -28,7 +28,8 @@ use std::collections::{BTreeMap, BTreeSet}; use d2b_contracts_broker::broker_wire::{ - BrokerRequest, DEFAULT_CONTEXT_DEADLINE_MS, FdKind, MAX_CONTEXT_DEADLINE_MS, + BrokerOperationName, BrokerRequest, DEFAULT_CONTEXT_DEADLINE_MS, FdKind, + MAX_CONTEXT_DEADLINE_MS, }; use d2b_contracts_resource::v3::{CanonicalJsonObject, CanonicalJsonValue, canonical_json_bytes}; @@ -162,7 +163,7 @@ impl DeadlineTier { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BrokerOperationRow { /// The operation name. - pub operation: &'static str, + pub operation: BrokerOperationName, /// The wire discriminant the operation inherits, when it has one. pub wire_variant: Option<&'static str>, /// The ownership triage result. @@ -185,7 +186,7 @@ pub struct BrokerOperationRow { /// Whether the operation is advertised by `BrokerCapabilities`. pub capabilities: bool, /// The disposition the operation was triaged under. - pub disposition: &'static str, + pub disposition: Disposition, /// The deferral marker a reserved stub carries, when it is one; the /// closed set the generator maps the committed disposition target onto. pub stub_target: Option, @@ -228,7 +229,7 @@ impl BrokerOperationRow { pub fn find(operation: &str) -> Option<&'static Self> { BROKER_OPERATION_CATALOG .iter() - .find(|row| row.operation == operation) + .find(|row| row.operation.as_str() == operation) } /// The audit identity one validated payload carries. @@ -263,6 +264,39 @@ impl BrokerOperationRow { } } +/// The disposition one committed operation row was triaged under. +/// +/// The triage is closed: every row names exactly one disposition, and a +/// spelling outside this set is not a row. The generator maps each +/// committed disposition spelling onto the closed set, so the vocabulary +/// cannot drift into free prose. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Disposition { + /// The operation is callable but read-only: it may be invoked, and no + /// invocation mutates state. + CallableReadOnly, + /// The operation is promoted to live service. + PromotedLive, + /// The operation is a reserved stub, not yet implemented; the broker + /// serves it with one typed not-implemented refusal. + StubbedUnimplemented, + /// The operation exists only at compile time: no runtime surface + /// serves it. + CompileTimeOnly, +} + +impl Disposition { + /// The committed disposition spelling. + pub const fn as_str(self) -> &'static str { + match self { + Self::CallableReadOnly => "callable-read-only", + Self::PromotedLive => "promoted-live", + Self::StubbedUnimplemented => "stubbed-unimplemented", + Self::CompileTimeOnly => "compile-time-only", + } + } +} + /// Where a reserved stub's implementation is expected to land. /// /// A still-stubbed operation's refusal carries this marker on the wire and in @@ -535,20 +569,23 @@ pub fn audit(rows: &[BrokerOperationRow], views: &CatalogViews) -> Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec Vec = rows .iter() .filter(|row| row.capabilities) - .map(|row| row.operation) + .map(|row| row.operation.as_str()) .collect(); for name in expected.difference(&declared) { mismatches.push(missing( @@ -744,8 +791,14 @@ mod tests { fn live_views() -> CatalogViews { CatalogViews { wire: WIRE_VARIANTS.to_vec(), - host: HOST_OPERATION_CATALOG.to_vec(), - guest: GUEST_OPERATION_CATALOG.to_vec(), + host: HOST_OPERATION_CATALOG + .iter() + .map(|operation| operation.as_str()) + .collect(), + guest: GUEST_OPERATION_CATALOG + .iter() + .map(|operation| operation.as_str()) + .collect(), w3: W3BrokerOperation::all() .iter() .map(|operation| operation.wire_tag()) @@ -777,15 +830,15 @@ mod tests { fn every_reserved_stub_names_a_closed_deferral_marker() { let stubs = BROKER_OPERATION_CATALOG .iter() - .filter(|row| row.disposition == "stubbed-unimplemented") + .filter(|row| row.disposition == Disposition::StubbedUnimplemented) .count(); assert!(stubs > 0, "the triage records reserved operations"); for row in BROKER_OPERATION_CATALOG { assert_eq!( - stub_target(row.operation).is_some(), - row.disposition == "stubbed-unimplemented", + stub_target(row.operation.as_str()).is_some(), + row.disposition == Disposition::StubbedUnimplemented, "{}: the deferral marker and the disposition disagree", - row.operation + row.operation.as_str() ); } } @@ -795,7 +848,7 @@ mod tests { let mut rows = BROKER_OPERATION_CATALOG.to_vec(); let stub = rows .iter_mut() - .find(|row| row.disposition == "stubbed-unimplemented") + .find(|row| row.disposition == Disposition::StubbedUnimplemented) .expect("the catalog reserves at least one operation"); stub.stub_target = None; let mismatches = audit(&rows, &live_views()); @@ -853,7 +906,7 @@ mod tests { #[test] fn a_mismatched_row_fails_the_gate() { let mut rows = BROKER_OPERATION_CATALOG.to_vec(); - rows[0].operation = "RenamedOperation"; + rows[0].operation = BrokerOperationName::PublishTrustedContext; let mismatches = audit(&rows, &live_views()); assert!( mismatches @@ -891,10 +944,11 @@ mod tests { #[test] fn every_wire_variant_resolves_to_its_row() { - for name in HOST_OPERATION_CATALOG { + for operation in HOST_OPERATION_CATALOG { + let name = operation.as_str(); let row = BrokerOperationRow::find(name) .unwrap_or_else(|| panic!("{name} has no committed row")); - assert_eq!(row.wire_variant, Some(*name)); + assert_eq!(row.wire_variant, Some(name)); } } @@ -913,7 +967,10 @@ mod tests { "Hello", ); assert_eq!(wire_variant_name(&request), name); - assert_eq!(wire_row(&request).map(|row| row.operation), Some(name)); + assert_eq!( + wire_row(&request).map(|row| row.operation.as_str()), + Some(name) + ); } #[test] @@ -934,7 +991,7 @@ mod tests { let rows: Vec = BROKER_OPERATION_CATALOG .iter() .copied() - .filter(|row| row.operation != "Hello") + .filter(|row| row.operation != BrokerOperationName::Hello) .collect(); let mismatches = audit(&rows, &live_views()); assert!( @@ -956,7 +1013,7 @@ mod tests { .iter_mut() .find(|row| row.owner != OperationOwner::Family) .expect("a committed row the broker or a transport concern owns"); - let operation = non_provider.operation; + let operation = non_provider.operation.as_str(); assert!(non_provider.justification.is_some()); non_provider.justification = None; let mismatches = audit(&rows, &live_views()); diff --git a/packages/d2b-broker/src/envelope/mod.rs b/packages/d2b-broker/src/envelope/mod.rs index 68d1a8976..34247f5a6 100644 --- a/packages/d2b-broker/src/envelope/mod.rs +++ b/packages/d2b-broker/src/envelope/mod.rs @@ -1103,7 +1103,7 @@ impl BrokerEnvelope { pub fn committed_rows(&self) -> impl Iterator + '_ { self.rows .iter() - .filter(|row| self.committed.contains(row.operation)) + .filter(|row| self.committed.contains(row.operation.as_str())) } /// The profiles this envelope serves. @@ -1290,14 +1290,18 @@ impl BrokerEnvelope { // double-record a forwarded call. let serves_locally = self.dispatcher.serves_operation(operation); let dispatched: Result<(DispatchOutcome, Option), EnvelopeRefusal> = async { - let Some(row) = self.rows.iter().find(|row| row.operation == operation) else { + let Some(row) = self + .rows + .iter() + .find(|row| row.operation.as_str() == operation) + else { return Err(EnvelopeRefusal::new( chain.root_invocation_id().to_owned(), operation, UNKNOWN_OPERATION, )); }; - if !self.committed.contains(row.operation) || !row.admits_profile(self.profile) { + if !self.committed.contains(row.operation.as_str()) || !row.admits_profile(self.profile) { return Err(EnvelopeRefusal::new( chain.root_invocation_id().to_owned(), operation, @@ -1369,7 +1373,7 @@ impl BrokerEnvelope { None => None, }; let ctx = InvocationCtx { - operation: row.operation, + operation: row.operation.as_str(), zone, invocation_id: chain.root_invocation_id(), chain, @@ -1631,7 +1635,7 @@ impl BrokerEnvelopeBuilder { row.owner == OperationOwner::BrokerGeneric && row.payload_provenance == PayloadProvenance::Request }) - .map(|row| row.operation), + .map(|row| row.operation.as_str()), ); self } @@ -1653,7 +1657,7 @@ impl BrokerEnvelopeBuilder { && row.payload_provenance == PayloadProvenance::Request) || (row.owner == OperationOwner::Family && row.declaring_provider.is_some()) }) - .map(|row| row.operation), + .map(|row| row.operation.as_str()), ); self } @@ -1661,7 +1665,7 @@ impl BrokerEnvelopeBuilder { /// Commit every row in the catalog. pub fn commit_all(mut self) -> Self { self.committed - .extend(BROKER_OPERATION_CATALOG.iter().map(|row| row.operation)); + .extend(BROKER_OPERATION_CATALOG.iter().map(|row| row.operation.as_str())); self } @@ -1671,17 +1675,23 @@ impl BrokerEnvelopeBuilder { /// catalog does not carry yet, proving that a new operation needs a row /// and a handler rather than a wire change. pub fn declare(mut self, row: BrokerOperationRow) -> Self { - self.committed.push(row.operation); + self.committed.push(row.operation.as_str()); self.extras.push(row); self } /// Build the envelope. pub fn build(self) -> BrokerEnvelope { - let rows = BROKER_OPERATION_CATALOG - .iter() - .copied() - .chain(self.extras) + // A declared row precedes the catalog row of the same name, so the + // name lookup serves the declared row: `declare` is how a test + // drives an operation the catalog does not carry yet (and how a + // declared row with a catalog name is the declared row, not the + // catalog's). Production envelopes never declare, so the catalog + // rows are the only rows they see. + let rows = self + .extras + .into_iter() + .chain(BROKER_OPERATION_CATALOG.iter().copied()) .collect(); BrokerEnvelope { rows, @@ -2106,12 +2116,14 @@ impl OperationDispatcher for KernelDispatcher { mod tests { use super::*; use crate::catalog::{ - AuditMode, BrokerAuthzFacets, BrokerRequirement, DeadlineTier, OperationOwner, SecretAccess, + AuditMode, BrokerAuthzFacets, BrokerRequirement, DeadlineTier, Disposition, OperationOwner, + SecretAccess, }; use crate::forwarding::{ ForwardFuture, ForwardedOperation, OperationForwarder, SocketForwarder, }; use d2b_audit::evidence_chain::root_record_count; + use d2b_contracts_broker::broker_wire::BrokerOperationName; use std::io; use std::os::fd::{AsRawFd, OwnedFd}; use std::path::PathBuf; @@ -2275,10 +2287,11 @@ mod tests { .map_err(|errno| io::Error::from_raw_os_error(errno as i32)) } - /// A row a test declares: a broker-generic operation the committed - /// catalog does not carry, reached by name and never by a wire variant. + /// A row a test declares: a broker-generic operation reached by name and + /// never by a wire variant, declared on the envelope beyond whatever the + /// committed catalog carries. fn declared_row( - operation: &'static str, + operation: BrokerOperationName, fields: &'static [&'static str], required: &'static [&'static str], groups: &'static [&'static str], @@ -2293,7 +2306,7 @@ mod tests { profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2318,7 +2331,7 @@ mod tests { } fn echo_table() -> HandlerTable { - HandlerTable::new().with("ProbeOperation", |invocation| { + HandlerTable::new().with("PublishTrustedContext", |invocation| { Box::pin(async move { Ok(DispatchOutcome { result: serde_json::from_value(serde_json::json!({ @@ -2338,7 +2351,7 @@ mod tests { BrokerEnvelope::over(BrokerProfileId::Host, Box::new(echo_table())) .commit_broker_generic() .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2387,13 +2400,13 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Unauthorized, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) .expect_err("an ungranted caller is refused"); assert_eq!(refusal.code, UNGRANTED_CALLER); - assert_eq!(refusal.operation, "ProbeOperation"); + assert_eq!(refusal.operation, "PublishTrustedContext"); } #[test] @@ -2426,7 +2439,7 @@ mod tests { let undeclared = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x", "extra": 1 }), )) @@ -2435,7 +2448,7 @@ mod tests { let missing = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({}), )) @@ -2448,7 +2461,7 @@ mod tests { fn an_unregistered_handler_is_refused() { let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(HandlerTable::new())) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2457,7 +2470,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2491,7 +2504,7 @@ mod tests { // A refusal a handler chose and a failure a handler hit are two // cases with two codes: the caller can tell a deliberate refusal // from a broken handler, and neither is a missing handler. - let refused = HandlerTable::new().with("ProbeOperation", |_invocation| { + let refused = HandlerTable::new().with("PublishTrustedContext", |_invocation| { Box::pin(async move { Err(DispatchFailure::with_detail( HANDLER_REFUSED, @@ -2501,7 +2514,7 @@ mod tests { }); let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(refused)) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2510,7 +2523,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2519,7 +2532,7 @@ mod tests { assert_eq!(refusal.detail.as_deref(), Some("grant exhausted")); assert_eq!(refusal.audit_fields()["reason"], HANDLER_REFUSED); - let errored = HandlerTable::new().with("ProbeOperation", |_invocation| { + let errored = HandlerTable::new().with("PublishTrustedContext", |_invocation| { Box::pin(async move { Err(DispatchFailure::with_detail( HANDLER_ERRORED, @@ -2529,7 +2542,7 @@ mod tests { }); let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(errored)) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2538,7 +2551,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2553,7 +2566,7 @@ mod tests { // The peer's dispatch failure crosses the socket and back under its // own code: a handler refusal in the declaring process is reported // as a refusal, not flattened into a missing handler here. - let peer = loopback_peer(HandlerTable::new().with("ProbeOperation", |_invocation| { + let peer = loopback_peer(HandlerTable::new().with("PublishTrustedContext", |_invocation| { Box::pin(async move { Err(DispatchFailure::with_detail( HANDLER_REFUSED, @@ -2566,7 +2579,7 @@ mod tests { Box::new(ForwardingDispatcher::new(peer.forwarder())), ) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2575,7 +2588,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2591,7 +2604,7 @@ mod tests { // the set does not carry is refused under the envelope's own errored // code, and the peer's spelling rides in the record's detail so an // operator still sees it. - let peer = loopback_peer(HandlerTable::new().with("ProbeOperation", |_invocation| { + let peer = loopback_peer(HandlerTable::new().with("PublishTrustedContext", |_invocation| { Box::pin(async move { Err(DispatchFailure::new("family-own-code")) }) })); let envelope = BrokerEnvelope::over( @@ -2599,7 +2612,7 @@ mod tests { Box::new(ForwardingDispatcher::new(peer.forwarder())), ) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2608,7 +2621,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2624,14 +2637,14 @@ mod tests { // A crash inside a local handler is caught at the task boundary: the // caller sees a typed crash refusal carrying the panic's message, // never a dropped caller, and the envelope keeps serving. - let table = HandlerTable::new().with("ProbeOperation", |_invocation| { + let table = HandlerTable::new().with("PublishTrustedContext", |_invocation| { Box::pin(async move { panic!("probe blew up"); }) }); let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(table)) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2640,7 +2653,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2651,14 +2664,14 @@ mod tests { let fields = refusal.audit_fields(); assert_eq!(fields["reason"], HANDLER_CRASHED); assert_eq!(fields["invocation_id"], refusal.invocation_id); - assert_eq!(fields["operation"], "ProbeOperation"); + assert_eq!(fields["operation"], "PublishTrustedContext"); // The panic never left the handler task: the same envelope turns the // next crash into the same typed refusal instead of dropping the // caller. let again = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2687,8 +2700,13 @@ mod tests { // provably answers while the spinner is in flight. Wall-clock load // cannot stretch either side of the proof. const BUDGET: Duration = Duration::from_millis(400); - let mut spin_row = declared_row("ProbeOperation", &["label"], &["label"], &["d2bd"]); - spin_row.operation = "SpinningOperation"; + let mut spin_row = declared_row( + BrokerOperationName::PublishTrustedContext, + &["label"], + &["label"], + &["d2bd"], + ); + spin_row.operation = BrokerOperationName::ExportBrokerAudit; let (started_tx, started_rx) = std::sync::mpsc::channel::<()>(); let envelope = Arc::new( BrokerEnvelope::over( @@ -2696,7 +2714,7 @@ mod tests { Box::new( HandlerTable::new() .with_deadline(BUDGET) - .with("SpinningOperation", move |_invocation| { + .with("ExportBrokerAudit", move |_invocation| { // A handler that never yields: it would starve an // inline executor, so the task must be aborted // for the call to end at its budget. The signal @@ -2718,7 +2736,7 @@ mod tests { }) }) }) - .with("ProbeOperation", |_invocation| { + .with("PublishTrustedContext", |_invocation| { Box::pin(async move { Ok(DispatchOutcome { result: serde_json::from_value( @@ -2732,7 +2750,7 @@ mod tests { ), ) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2745,7 +2763,7 @@ mod tests { spinner .call( CallerAuthority::Daemon, - "SpinningOperation", + "ExportBrokerAudit", "zone-a", &serde_json::json!({ "label": "x" }), ) @@ -2761,7 +2779,7 @@ mod tests { runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2785,7 +2803,7 @@ mod tests { let invocation = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2793,7 +2811,7 @@ mod tests { let invocation_id = invocation.invocation_id; assert!(invocation_id.starts_with("invocation-")); let result = serde_json::to_value(&invocation.outcome.result).expect("result serializes"); - assert_eq!(result["operation"], "ProbeOperation"); + assert_eq!(result["operation"], "PublishTrustedContext"); assert_eq!(result["invocation"], invocation_id); assert_eq!(result["zone"], "zone-a"); assert_eq!(result["fields"], 1); @@ -2806,7 +2824,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Unauthorized, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2814,13 +2832,13 @@ mod tests { assert!(refusal.invocation_id.starts_with("invocation-")); let fields = refusal.audit_fields(); assert_eq!(fields["invocation_id"], refusal.invocation_id); - assert_eq!(fields["operation"], "ProbeOperation"); + assert_eq!(fields["operation"], "PublishTrustedContext"); assert_eq!(fields["reason"], UNGRANTED_CALLER); // Two refusals are two named invocations, not one anonymous denial. let other = runtime() .block_on(envelope.call( CallerAuthority::Unauthorized, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2832,7 +2850,7 @@ mod tests { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn a_row_join_keys_the_invocation_on_its_declared_fields() { let mut row = declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label", "kind"], &["label", "kind"], &["d2bd"], @@ -2845,7 +2863,7 @@ mod tests { runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x", "kind": kind }), )) @@ -2872,7 +2890,7 @@ mod tests { let plain = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2882,7 +2900,7 @@ mod tests { #[test] fn a_launcher_does_not_carry_the_daemon_grant() { - let daemon_only = declared_row("DaemonOperation", &[], &[], &["d2bd"]); + let daemon_only = declared_row(BrokerOperationName::OpenKvm, &[], &[], &["d2bd"]); assert!(BrokerEnvelope::granted( &daemon_only, CallerAuthority::Daemon @@ -2891,7 +2909,7 @@ mod tests { !BrokerEnvelope::granted(&daemon_only, CallerAuthority::Launcher), "a row granted to the daemon alone must refuse a launcher" ); - let launcher = declared_row("LauncherOperation", &[], &[], &["d2b-launcher"]); + let launcher = declared_row(BrokerOperationName::OpenCgroupDir, &[], &[], &["d2b-launcher"]); assert!(BrokerEnvelope::granted( &launcher, CallerAuthority::Launcher @@ -2901,17 +2919,17 @@ mod tests { #[test] fn a_grant_admits_only_the_authority_it_names() { - let admin = declared_row("AdminOperation", &[], &[], &["d2b-admin"]); + let admin = declared_row(BrokerOperationName::OpenHidrawSecurityKey, &[], &[], &["d2b-admin"]); assert!(BrokerEnvelope::granted(&admin, CallerAuthority::Admin)); assert!(!BrokerEnvelope::granted(&admin, CallerAuthority::Launcher)); assert!(!BrokerEnvelope::granted( &admin, CallerAuthority::Unauthorized )); - let daemon = declared_row("DaemonOperation", &[], &[], &["d2bd"]); + let daemon = declared_row(BrokerOperationName::OpenKvm, &[], &[], &["d2bd"]); assert!(BrokerEnvelope::granted(&daemon, CallerAuthority::Daemon)); assert!(BrokerEnvelope::granted(&daemon, CallerAuthority::Admin)); - let ungranted = declared_row("NoGroup", &[], &[], &[]); + let ungranted = declared_row(BrokerOperationName::PipeWireAudio, &[], &[], &[]); assert!(!BrokerEnvelope::granted(&ungranted, CallerAuthority::Admin)); } @@ -2927,7 +2945,7 @@ mod tests { Box::new(ForwardingDispatcher::new(peer.forwarder())), ) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2936,7 +2954,7 @@ mod tests { let invocation = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2945,7 +2963,7 @@ mod tests { let rendered = String::from_utf8(invocation.outcome.result.to_canonical_bytes()) .expect("canonical json is utf-8"); assert!( - rendered.contains("\"operation\":\"ProbeOperation\""), + rendered.contains("\"operation\":\"PublishTrustedContext\""), "{rendered}" ); assert!(rendered.contains("\"zone\":\"zone-a\""), "{rendered}"); @@ -2964,7 +2982,7 @@ mod tests { Box::new(ForwardingDispatcher::new(peer.forwarder())), ) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -2973,7 +2991,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -2992,7 +3010,7 @@ mod tests { Box::new(ForwardingDispatcher::default()), ) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -3001,7 +3019,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3017,16 +3035,18 @@ mod tests { ) .commit_forwarded() .build(); - let committed: BTreeSet<&str> = - envelope.committed_rows().map(|row| row.operation).collect(); + let committed: BTreeSet<&str> = envelope + .committed_rows() + .map(|row| row.operation.as_str()) + .collect(); for row in BROKER_OPERATION_CATALOG .iter() .filter(|row| row.owner == OperationOwner::Family && row.declaring_provider.is_some()) { assert!( - committed.contains(row.operation), + committed.contains(row.operation.as_str()), "{} names a declaring process and must be committed", - row.operation + row.operation.as_str() ); } // A row that names no declaring process has nowhere to be forwarded, @@ -3036,9 +3056,10 @@ mod tests { .filter(|row| row.declaring_provider.is_none()) { assert!( - !committed.contains(row.operation) || row.owner == OperationOwner::BrokerGeneric, + !committed.contains(row.operation.as_str()) + || row.owner == OperationOwner::BrokerGeneric, "{} names no declaring process and must not be committed", - row.operation + row.operation.as_str() ); } } @@ -3053,7 +3074,7 @@ mod tests { /// other per-operation facet, so a test sets them the same way it sets /// an audit join. fn fd_declared_row(max_fds: u8, kind: FdKind) -> BrokerOperationRow { - let mut row = declared_row("ProbeOperation", &["label"], &["label"], &["d2bd"]); + let mut row = declared_row(BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"]); row.max_fds = max_fds; row.fd_kind = Some(kind); @@ -3073,7 +3094,7 @@ mod tests { let returned_write_end: Arc>> = Arc::default(); let write_slot = Arc::clone(&returned_write_end); let peer = loopback_peer( - HandlerTable::new().with("ProbeOperation", move |invocation| { + HandlerTable::new().with("PublishTrustedContext", move |invocation| { // The handler runs as an async task; the captured slot is // re-cloned per invocation so the registration closure stays // a re-callable `Fn`. @@ -3105,7 +3126,7 @@ mod tests { let invocation = runtime() .block_on(envelope.call_with_fds( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), &[request_read], @@ -3136,7 +3157,7 @@ mod tests { #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn a_zero_fd_response_to_an_fd_declaring_operation_is_a_valid_empty_set() { - let peer = loopback_peer(HandlerTable::new().with("ProbeOperation", |_invocation| { + let peer = loopback_peer(HandlerTable::new().with("PublishTrustedContext", |_invocation| { Box::pin(async move { Ok(DispatchOutcome { result: serde_json::from_value(serde_json::json!({ "echo": "none" })) @@ -3154,7 +3175,7 @@ mod tests { let invocation = runtime() .block_on(envelope.call_with_fds( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), &[], @@ -3183,7 +3204,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call_with_fds( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), &fds, @@ -3208,7 +3229,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call_with_fds( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), &[fd], @@ -3239,7 +3260,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call_with_fds( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), &[socket], @@ -3255,7 +3276,7 @@ mod tests { use nix::unistd::pipe; let (request_read, _request_write) = pipe().expect("request pipe"); let peer = loopback_peer( - HandlerTable::new().with("ProbeOperation", move |invocation| { + HandlerTable::new().with("PublishTrustedContext", move |invocation| { Box::pin(async move { Ok(DispatchOutcome { result: serde_json::from_value(serde_json::json!({ "echo": "stolen" })) @@ -3277,7 +3298,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call_with_fds( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), &[request_read], @@ -3322,7 +3343,7 @@ mod tests { ) .with_trusted_context(store) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -3331,7 +3352,7 @@ mod tests { let refusal = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3350,7 +3371,7 @@ mod tests { ) .with_trusted_context(store) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -3359,7 +3380,7 @@ mod tests { runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3377,7 +3398,7 @@ mod tests { let observed: Arc>> = Arc::default(); let slot = Arc::clone(&observed); let peer = loopback_peer( - HandlerTable::new().with("ProbeOperation", move |invocation| { + HandlerTable::new().with("PublishTrustedContext", move |invocation| { // Re-cloned per invocation so the registration closure stays // a re-callable `Fn` (the async task moves the clone in). let slot = Arc::clone(&slot); @@ -3401,7 +3422,7 @@ mod tests { ) .with_trusted_context(store) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -3410,7 +3431,7 @@ mod tests { runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3448,7 +3469,7 @@ mod tests { let observed: Arc>> = Arc::default(); let slot = Arc::clone(&observed); let peer = loopback_peer(HandlerTable::new().with( - "ProbeOperation", + "PublishTrustedContext", move |invocation| { // Re-cloned per invocation so the registration closure // stays a re-callable `Fn` (the async task moves the @@ -3468,7 +3489,7 @@ mod tests { store .publish(&published("zone-a")) .expect("the daemon published the Zone"); - let mut row = declared_row("ProbeOperation", &["label"], &["label"], &["d2bd"]); + let mut row = declared_row(BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"]); row.deadline_tier = tier; let envelope = BrokerEnvelope::over( BrokerProfileId::Host, @@ -3480,7 +3501,7 @@ mod tests { runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3715,7 +3736,7 @@ mod tests { let captured: Arc>> = Arc::default(); let captured_handle = Arc::clone(&captured); let table = HandlerTable::new() - .with("AlphaService", move |invocation| { + .with("OpenFuse", move |invocation| { // Re-cloned per invocation so the registration closure stays // a re-callable `Fn` (the async task moves the clone in). let captured_handle = Arc::clone(&captured_handle); @@ -3731,7 +3752,7 @@ mod tests { }) }) }) - .with("BetaService", |invocation| { + .with("OpenDevice", |invocation| { Box::pin(async move { Ok(DispatchOutcome { result: serde_json::from_value( @@ -3745,13 +3766,13 @@ mod tests { let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(table)) .with_chain_audit(Arc::clone(&sink)) .declare(declared_row( - "AlphaService", + BrokerOperationName::OpenFuse, &["label"], &["label"], &["provider-alpha"], )) .declare(declared_row( - "BetaService", + BrokerOperationName::OpenDevice, &["label"], &["label"], &["provider-alpha"], @@ -3760,7 +3781,7 @@ mod tests { let root = runtime() .block_on(envelope.call( CallerAuthority::Provider("provider-alpha"), - "AlphaService", + "OpenFuse", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3782,7 +3803,7 @@ mod tests { let nested = runtime() .block_on(envelope.call_nested( chain, - "BetaService", + "OpenDevice", "zone-a", &serde_json::json!({ "label": "y" }), )) @@ -3802,7 +3823,7 @@ mod tests { assert_eq!(root_record.leg, ChainLeg::Broker); assert_eq!(root_record.initiating_identity, "provider-alpha"); assert_eq!(root_record.invoking_identity, "provider-alpha"); - assert_eq!(root_record.operation, "AlphaService"); + assert_eq!(root_record.operation, "OpenFuse"); assert_eq!(root_record.outcome, ChainOutcome::Succeeded); let correlation = records .iter() @@ -3811,7 +3832,7 @@ mod tests { assert_eq!(correlation.correlation_key(), (root_id.as_str(), 2)); assert_eq!(correlation.initiating_identity, "provider-alpha"); assert_eq!(correlation.invoking_identity, "provider-beta"); - assert_eq!(correlation.operation, "BetaService"); + assert_eq!(correlation.operation, "OpenDevice"); assert_eq!(correlation.outcome, ChainOutcome::Succeeded); assert_eq!( root_record_count(&records, &root_id), @@ -3834,17 +3855,17 @@ mod tests { let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(echo_table())) .with_chain_audit(Arc::clone(&sink)) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], )) - .declare(declared_row("GraftService", &[], &[], &["provider-alpha"])) + .declare(declared_row(BrokerOperationName::ModprobeIfAllowed, &[], &[], &["provider-alpha"])) .build(); let root = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3855,7 +3876,7 @@ mod tests { let chain = EvidenceChain::root(root.invocation_id.clone(), "daemon").nested("provider-alpha"); let refusal = runtime() - .block_on(envelope.call_nested(chain, "GraftService", "zone-a", &serde_json::json!({}))) + .block_on(envelope.call_nested(chain, "ModprobeIfAllowed", "zone-a", &serde_json::json!({}))) .expect_err("a self-re-entrant call without a granting row refuses"); assert_eq!(refusal.code, UNGRANTED_CALLER); let records = recorder.snapshot(); @@ -3884,7 +3905,7 @@ mod tests { let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(echo_table())) .with_chain_audit(Arc::clone(&sink)) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -3893,7 +3914,7 @@ mod tests { let root = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -3904,7 +3925,7 @@ mod tests { chain = chain.nested("provider-alpha"); let call = runtime().block_on(envelope.call_nested( chain.clone(), - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )); @@ -3957,7 +3978,7 @@ mod tests { let recorder = Arc::new(RecordingChainSink::default()); let sink: Arc = Arc::clone(&recorder) as Arc; let chains: Arc>> = Arc::default(); - let table = HandlerTable::new().with("RootService", |_invocation| { + let table = HandlerTable::new().with("DiskInit", |_invocation| { Box::pin(async move { Ok(DispatchOutcome { result: serde_json::from_value(serde_json::json!({ "root": true })) @@ -3968,12 +3989,12 @@ mod tests { }); let root_envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(table)) .with_chain_audit(Arc::clone(&sink)) - .declare(declared_row("RootService", &[], &[], &["d2bd"])) + .declare(declared_row(BrokerOperationName::DiskInit, &[], &[], &["d2bd"])) .build(); let root = runtime() .block_on(root_envelope.call( CallerAuthority::Daemon, - "RootService", + "DiskInit", "zone-a", &serde_json::json!({}), )) @@ -3987,12 +4008,12 @@ mod tests { })), ) .with_chain_audit(Arc::clone(&sink)) - .declare(declared_row("ForwardedService", &[], &[], &["d2bd"])) + .declare(declared_row(BrokerOperationName::StoreSync, &[], &[], &["d2bd"])) .build(); let nested = runtime() .block_on(forwarded_envelope.call_nested( nested_chain, - "ForwardedService", + "StoreSync", "zone-a", &serde_json::json!({}), )) @@ -4030,7 +4051,7 @@ mod tests { let envelope = BrokerEnvelope::over(BrokerProfileId::Host, Box::new(echo_table())) .with_chain_audit(Arc::clone(&sink)) .declare(declared_row( - "ProbeOperation", + BrokerOperationName::PublishTrustedContext, &["label"], &["label"], &["d2bd"], @@ -4039,7 +4060,7 @@ mod tests { let ok = runtime() .block_on(envelope.call( CallerAuthority::Daemon, - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "x" }), )) @@ -4047,7 +4068,7 @@ mod tests { let refused = runtime() .block_on(envelope.call( CallerAuthority::Provider("provider-alpha"), - "ProbeOperation", + "PublishTrustedContext", "zone-a", &serde_json::json!({ "label": "y" }), )) diff --git a/packages/d2b-broker/src/generated/broker_operation_catalog.rs b/packages/d2b-broker/src/generated/broker_operation_catalog.rs index 59bb8f3c0..2a30905ca 100644 --- a/packages/d2b-broker/src/generated/broker_operation_catalog.rs +++ b/packages/d2b-broker/src/generated/broker_operation_catalog.rs @@ -5,7 +5,7 @@ /// Every committed broker operation row, in declared order. pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ BrokerOperationRow { - operation: "Hello", + operation: BrokerOperationName::Hello, wire_variant: Some("Hello"), owner: OperationOwner::BrokerGeneric, family: None, @@ -14,7 +14,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: true, - disposition: "callable-read-only", + disposition: Disposition::CallableReadOnly, stub_target: None, audit_fields: &["Hello"], authz: BrokerAuthzFacets { @@ -37,7 +37,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "PublishTrustedContext", + operation: BrokerOperationName::PublishTrustedContext, wire_variant: Some("PublishTrustedContext"), owner: OperationOwner::BrokerGeneric, family: None, @@ -46,7 +46,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["PublishTrustedContext"], authz: BrokerAuthzFacets { @@ -69,7 +69,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ExportBrokerAudit", + operation: BrokerOperationName::ExportBrokerAudit, wire_variant: Some("ExportBrokerAudit"), owner: OperationOwner::BrokerGeneric, family: None, @@ -78,7 +78,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: true, - disposition: "callable-read-only", + disposition: Disposition::CallableReadOnly, stub_target: None, audit_fields: &["ExportBrokerAudit"], authz: BrokerAuthzFacets { @@ -101,7 +101,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ApplyHostGenerationHandoff", + operation: BrokerOperationName::ApplyHostGenerationHandoff, wire_variant: Some("ApplyHostGenerationHandoff"), owner: OperationOwner::BrokerGeneric, family: None, @@ -110,7 +110,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ApplyHostGenerationHandoff"], authz: BrokerAuthzFacets { @@ -133,7 +133,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "CreateOrReconcileUsersGroups", + operation: BrokerOperationName::CreateOrReconcileUsersGroups, wire_variant: Some("CreateOrReconcileUsersGroups"), owner: OperationOwner::Family, family: Some("user"), @@ -142,7 +142,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::BootstrapOnly), audit_fields: &[], authz: BrokerAuthzFacets { @@ -165,7 +165,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "DelegateCgroupV2", + operation: BrokerOperationName::DelegateCgroupV2, wire_variant: Some("DelegateCgroupV2"), owner: OperationOwner::Family, family: Some("process"), @@ -174,7 +174,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["DelegateCgroupV2"], authz: BrokerAuthzFacets { @@ -197,7 +197,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "InjectSecretById", + operation: BrokerOperationName::InjectSecretById, wire_variant: Some("InjectSecretById"), owner: OperationOwner::Family, family: Some("credential"), @@ -206,7 +206,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::FutureWork), audit_fields: &[], authz: BrokerAuthzFacets { @@ -229,7 +229,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "LaunchMinijailChild", + operation: BrokerOperationName::LaunchMinijailChild, wire_variant: Some("LaunchMinijailChild"), owner: OperationOwner::Family, family: Some("process"), @@ -238,7 +238,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::FutureWork), audit_fields: &[], authz: BrokerAuthzFacets { @@ -261,7 +261,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ModprobeIfAllowed", + operation: BrokerOperationName::ModprobeIfAllowed, wire_variant: Some("ModprobeIfAllowed"), owner: OperationOwner::Family, family: Some("device"), @@ -270,7 +270,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ModprobeIfAllowed"], authz: BrokerAuthzFacets { @@ -293,7 +293,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenCgroupDir", + operation: BrokerOperationName::OpenCgroupDir, wire_variant: Some("OpenCgroupDir"), owner: OperationOwner::Family, family: Some("process"), @@ -302,7 +302,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["OpenCgroupDir"], authz: BrokerAuthzFacets { @@ -325,7 +325,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenDevice", + operation: BrokerOperationName::OpenDevice, wire_variant: Some("OpenDevice"), owner: OperationOwner::Family, family: Some("device"), @@ -334,7 +334,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["OpenDevice"], authz: BrokerAuthzFacets { @@ -357,7 +357,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenFuse", + operation: BrokerOperationName::OpenFuse, wire_variant: Some("OpenFuse"), owner: OperationOwner::Family, family: Some("device"), @@ -366,7 +366,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["OpenFuse"], authz: BrokerAuthzFacets { @@ -389,7 +389,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenHidrawSecurityKey", + operation: BrokerOperationName::OpenHidrawSecurityKey, wire_variant: Some("OpenHidrawSecurityKey"), owner: OperationOwner::Family, family: Some("device-security-key"), @@ -398,7 +398,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["OpenHidrawSecurityKey"], authz: BrokerAuthzFacets { @@ -421,7 +421,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenKvm", + operation: BrokerOperationName::OpenKvm, wire_variant: Some("OpenKvm"), owner: OperationOwner::Family, family: Some("device"), @@ -430,7 +430,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["OpenKvm"], authz: BrokerAuthzFacets { @@ -453,7 +453,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaEnroll", + operation: BrokerOperationName::QemuMediaEnroll, wire_variant: Some("QemuMediaEnroll"), owner: OperationOwner::Family, family: Some("guest"), @@ -462,7 +462,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["QemuMediaEnroll"], authz: BrokerAuthzFacets { @@ -485,7 +485,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaRefreshRegistry", + operation: BrokerOperationName::QemuMediaRefreshRegistry, wire_variant: Some("QemuMediaRefreshRegistry"), owner: OperationOwner::Family, family: Some("guest"), @@ -494,7 +494,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["QemuMediaRefreshRegistry"], authz: BrokerAuthzFacets { @@ -517,7 +517,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaBoot", + operation: BrokerOperationName::QemuMediaBoot, wire_variant: Some("QemuMediaBoot"), owner: OperationOwner::Family, family: Some("guest"), @@ -526,7 +526,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["QemuMediaBoot"], authz: BrokerAuthzFacets { @@ -549,7 +549,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaSystemPowerdown", + operation: BrokerOperationName::QemuMediaSystemPowerdown, wire_variant: Some("QemuMediaSystemPowerdown"), owner: OperationOwner::Family, family: Some("guest"), @@ -558,7 +558,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["QemuMediaSystemPowerdown"], authz: BrokerAuthzFacets { @@ -581,7 +581,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaQueryStatus", + operation: BrokerOperationName::QemuMediaQueryStatus, wire_variant: Some("QemuMediaQueryStatus"), owner: OperationOwner::Family, family: Some("guest"), @@ -590,7 +590,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -613,7 +613,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaQuit", + operation: BrokerOperationName::QemuMediaQuit, wire_variant: Some("QemuMediaQuit"), owner: OperationOwner::Family, family: Some("guest"), @@ -622,7 +622,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["QemuMediaQuit"], authz: BrokerAuthzFacets { @@ -645,7 +645,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaAttach", + operation: BrokerOperationName::QemuMediaAttach, wire_variant: Some("QemuMediaAttach"), owner: OperationOwner::Family, family: Some("guest"), @@ -654,7 +654,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["QemuMediaAttach"], authz: BrokerAuthzFacets { @@ -677,7 +677,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "QemuMediaDetach", + operation: BrokerOperationName::QemuMediaDetach, wire_variant: Some("QemuMediaDetach"), owner: OperationOwner::Family, family: Some("guest"), @@ -686,7 +686,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["QemuMediaDetach"], authz: BrokerAuthzFacets { @@ -709,7 +709,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "PipeWireAudio", + operation: BrokerOperationName::PipeWireAudio, wire_variant: Some("PipeWireAudio"), owner: OperationOwner::Family, family: Some("audio"), @@ -718,7 +718,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["PipeWireAudio"], authz: BrokerAuthzFacets { @@ -741,7 +741,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenVhostNet", + operation: BrokerOperationName::OpenVhostNet, wire_variant: Some("OpenVhostNet"), owner: OperationOwner::Family, family: Some("device"), @@ -750,7 +750,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["OpenVhostNet"], authz: BrokerAuthzFacets { @@ -773,7 +773,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ReconcileStorageScope", + operation: BrokerOperationName::ReconcileStorageScope, wire_variant: Some("ReconcileStorageScope"), owner: OperationOwner::Family, family: Some("volume-binding"), @@ -782,7 +782,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ReconcileStorageScope"], authz: BrokerAuthzFacets { @@ -805,7 +805,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ValidateLockSpec", + operation: BrokerOperationName::ValidateLockSpec, wire_variant: Some("ValidateLockSpec"), owner: OperationOwner::Family, family: Some("volume-binding"), @@ -814,7 +814,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ValidateLockSpec"], authz: BrokerAuthzFacets { @@ -837,7 +837,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "StoreSync", + operation: BrokerOperationName::StoreSync, wire_variant: Some("StoreSync"), owner: OperationOwner::Family, family: Some("volume"), @@ -846,7 +846,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["StoreSync"], authz: BrokerAuthzFacets { @@ -869,7 +869,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ReadSecretById", + operation: BrokerOperationName::ReadSecretById, wire_variant: Some("ReadSecretById"), owner: OperationOwner::Family, family: Some("credential"), @@ -878,7 +878,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::FutureWork), audit_fields: &[], authz: BrokerAuthzFacets { @@ -901,7 +901,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "RotateSecretById", + operation: BrokerOperationName::RotateSecretById, wire_variant: Some("RotateSecretById"), owner: OperationOwner::Family, family: Some("credential"), @@ -910,7 +910,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::FutureWork), audit_fields: &[], authz: BrokerAuthzFacets { @@ -933,7 +933,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "UsbipBind", + operation: BrokerOperationName::UsbipBind, wire_variant: Some("UsbipBind"), owner: OperationOwner::Family, family: Some("device-usbip"), @@ -942,7 +942,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["UsbipBind", "UsbSerialCorrelationKeyRotate"], authz: BrokerAuthzFacets { @@ -965,7 +965,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "UsbipBindFirewallRule", + operation: BrokerOperationName::UsbipBindFirewallRule, wire_variant: Some("UsbipBindFirewallRule"), owner: OperationOwner::Family, family: Some("device-usbip"), @@ -974,7 +974,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["UsbipBindFirewallRule"], authz: BrokerAuthzFacets { @@ -997,7 +997,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "UsbipProxyReconcile", + operation: BrokerOperationName::UsbipProxyReconcile, wire_variant: Some("UsbipProxyReconcile"), owner: OperationOwner::Family, family: Some("device-usbip"), @@ -1006,7 +1006,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["UsbipProxyReconcile"], authz: BrokerAuthzFacets { @@ -1029,7 +1029,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "UsbipUnbind", + operation: BrokerOperationName::UsbipUnbind, wire_variant: Some("UsbipUnbind"), owner: OperationOwner::Family, family: Some("device-usbip"), @@ -1038,7 +1038,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["UsbipUnbind"], authz: BrokerAuthzFacets { @@ -1061,7 +1061,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "UsbipExplicitBind", + operation: BrokerOperationName::UsbipExplicitBind, wire_variant: Some("UsbipExplicitBind"), owner: OperationOwner::Family, family: Some("device-usbip"), @@ -1070,7 +1070,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["UsbipExplicitBind", "UsbSerialCorrelationKeyRotate"], authz: BrokerAuthzFacets { @@ -1093,7 +1093,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "UsbipExplicitFirewallRule", + operation: BrokerOperationName::UsbipExplicitFirewallRule, wire_variant: Some("UsbipExplicitFirewallRule"), owner: OperationOwner::Family, family: Some("device-usbip"), @@ -1102,7 +1102,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["UsbipExplicitFirewallRule"], authz: BrokerAuthzFacets { @@ -1125,7 +1125,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OwnershipMatrixCheck", + operation: BrokerOperationName::OwnershipMatrixCheck, wire_variant: Some("OwnershipMatrixCheck"), owner: OperationOwner::Family, family: Some("volume"), @@ -1134,7 +1134,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1157,7 +1157,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "SshHostKeyPreflight", + operation: BrokerOperationName::SshHostKeyPreflight, wire_variant: Some("SshHostKeyPreflight"), owner: OperationOwner::Family, family: Some("device-security-key"), @@ -1166,7 +1166,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::FutureWork), audit_fields: &[], authz: BrokerAuthzFacets { @@ -1189,7 +1189,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "DiskInit", + operation: BrokerOperationName::DiskInit, wire_variant: Some("DiskInit"), owner: OperationOwner::Family, family: Some("volume"), @@ -1198,7 +1198,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["DiskInit"], authz: BrokerAuthzFacets { @@ -1221,7 +1221,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "SecurityKeyOpenDevice", + operation: BrokerOperationName::SecurityKeyOpenDevice, wire_variant: Some("SecurityKeyOpenDevice"), owner: OperationOwner::Family, family: Some("device-security-key"), @@ -1230,7 +1230,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::FutureWork), audit_fields: &[], authz: BrokerAuthzFacets { @@ -1253,7 +1253,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "SecurityKeyApplyUdevRules", + operation: BrokerOperationName::SecurityKeyApplyUdevRules, wire_variant: Some("SecurityKeyApplyUdevRules"), owner: OperationOwner::Family, family: Some("device-security-key"), @@ -1262,7 +1262,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "stubbed-unimplemented", + disposition: Disposition::StubbedUnimplemented, stub_target: Some(StubTarget::FutureWork), audit_fields: &[], authz: BrokerAuthzFacets { @@ -1285,7 +1285,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "PrepareSwtpmDir", + operation: BrokerOperationName::PrepareSwtpmDir, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1294,7 +1294,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "compile-time-only", + disposition: Disposition::CompileTimeOnly, stub_target: None, audit_fields: &["PrepareSwtpmDir"], authz: BrokerAuthzFacets { @@ -1317,7 +1317,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "EnvelopeInvoke", + operation: BrokerOperationName::EnvelopeInvoke, wire_variant: Some("EnvelopeInvoke"), owner: OperationOwner::BrokerGeneric, family: None, @@ -1326,7 +1326,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1349,7 +1349,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "open-pidfd", + operation: BrokerOperationName::open_pidfd, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1358,7 +1358,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1381,7 +1381,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "open-peer-pidfd-from-accepted-socket", + operation: BrokerOperationName::open_peer_pidfd_from_accepted_socket, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1390,7 +1390,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1413,7 +1413,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "poll-child-reaped", + operation: BrokerOperationName::poll_child_reaped, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1422,7 +1422,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1445,7 +1445,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "prepare-directory", + operation: BrokerOperationName::prepare_directory, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1454,7 +1454,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1477,7 +1477,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "kill-cgroup", + operation: BrokerOperationName::kill_cgroup, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1486,7 +1486,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1509,7 +1509,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "signal-pidfd", + operation: BrokerOperationName::signal_pidfd, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1518,7 +1518,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1541,7 +1541,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "deregister-pidfd", + operation: BrokerOperationName::deregister_pidfd, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1550,7 +1550,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1573,7 +1573,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "spawn-process", + operation: BrokerOperationName::spawn_process, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1582,7 +1582,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1605,7 +1605,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Extended, }, BrokerOperationRow { - operation: "delegate-cgroup-v2", + operation: BrokerOperationName::delegate_cgroup_v2, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1614,7 +1614,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1637,7 +1637,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "open-cgroup-dir", + operation: BrokerOperationName::open_cgroup_dir, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1646,7 +1646,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1669,7 +1669,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "take-controller-bootstrap", + operation: BrokerOperationName::take_controller_bootstrap, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1678,7 +1678,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1701,7 +1701,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "observe-process", + operation: BrokerOperationName::observe_process, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1710,7 +1710,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1733,7 +1733,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "consume-cell", + operation: BrokerOperationName::consume_cell, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1742,7 +1742,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1765,7 +1765,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "complete-cell", + operation: BrokerOperationName::complete_cell, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1774,7 +1774,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1797,7 +1797,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "apply-nftables", + operation: BrokerOperationName::apply_nftables, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1806,7 +1806,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1829,7 +1829,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "apply-nftables-projection", + operation: BrokerOperationName::apply_nftables_projection, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1838,7 +1838,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1861,7 +1861,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "apply-nm-unmanaged", + operation: BrokerOperationName::apply_nm_unmanaged, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1870,7 +1870,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1893,7 +1893,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "apply-route", + operation: BrokerOperationName::apply_route, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1902,7 +1902,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1925,7 +1925,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "apply-sysctl", + operation: BrokerOperationName::apply_sysctl, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1934,7 +1934,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1957,7 +1957,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "create-bridge", + operation: BrokerOperationName::create_bridge, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1966,7 +1966,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -1989,7 +1989,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "delete-bridge", + operation: BrokerOperationName::delete_bridge, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -1998,7 +1998,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2021,7 +2021,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "create-persistent-tap", + operation: BrokerOperationName::create_persistent_tap, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -2030,7 +2030,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2053,7 +2053,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "delete-persistent-tap", + operation: BrokerOperationName::delete_persistent_tap, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -2062,7 +2062,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2085,7 +2085,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "create-tap-fd", + operation: BrokerOperationName::create_tap_fd, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -2094,7 +2094,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2117,7 +2117,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "set-bridge-port-flags", + operation: BrokerOperationName::set_bridge_port_flags, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -2126,7 +2126,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2149,7 +2149,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "update-hosts-file", + operation: BrokerOperationName::update_hosts_file, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -2158,7 +2158,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2181,7 +2181,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "seed-dnsmasq-lease", + operation: BrokerOperationName::seed_dnsmasq_lease, wire_variant: None, owner: OperationOwner::BrokerGeneric, family: None, @@ -2190,7 +2190,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2213,7 +2213,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ApplyNftables", + operation: BrokerOperationName::ApplyNftables, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2222,7 +2222,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ApplyNftables"], authz: BrokerAuthzFacets { @@ -2245,7 +2245,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ApplyNftablesProjection", + operation: BrokerOperationName::ApplyNftablesProjection, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2254,7 +2254,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ApplyNftablesProjection"], authz: BrokerAuthzFacets { @@ -2277,7 +2277,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ApplyNmUnmanaged", + operation: BrokerOperationName::ApplyNmUnmanaged, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2286,7 +2286,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ApplyNmUnmanaged"], authz: BrokerAuthzFacets { @@ -2309,7 +2309,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ApplyRoute", + operation: BrokerOperationName::ApplyRoute, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2318,7 +2318,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ApplyRoute"], authz: BrokerAuthzFacets { @@ -2341,7 +2341,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ApplySysctl", + operation: BrokerOperationName::ApplySysctl, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2350,7 +2350,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ApplySysctl"], authz: BrokerAuthzFacets { @@ -2373,7 +2373,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "CreateBridge", + operation: BrokerOperationName::CreateBridge, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2382,7 +2382,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["CreateBridge"], authz: BrokerAuthzFacets { @@ -2405,7 +2405,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "DeleteBridge", + operation: BrokerOperationName::DeleteBridge, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2414,7 +2414,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["DeleteBridge"], authz: BrokerAuthzFacets { @@ -2437,7 +2437,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "CreatePersistentTap", + operation: BrokerOperationName::CreatePersistentTap, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2446,7 +2446,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["CreatePersistentTap"], authz: BrokerAuthzFacets { @@ -2469,7 +2469,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "DeletePersistentTap", + operation: BrokerOperationName::DeletePersistentTap, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2478,7 +2478,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["DeletePersistentTap"], authz: BrokerAuthzFacets { @@ -2501,7 +2501,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "CreateTapFd", + operation: BrokerOperationName::CreateTapFd, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2510,7 +2510,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["CreateTapFd"], authz: BrokerAuthzFacets { @@ -2533,7 +2533,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "SetBridgePortFlags", + operation: BrokerOperationName::SetBridgePortFlags, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2542,7 +2542,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SetBridgePortFlags"], authz: BrokerAuthzFacets { @@ -2565,7 +2565,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "UpdateHostsFile", + operation: BrokerOperationName::UpdateHostsFile, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2574,7 +2574,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["UpdateHostsFile"], authz: BrokerAuthzFacets { @@ -2597,7 +2597,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "SeedDnsmasqLease", + operation: BrokerOperationName::SeedDnsmasqLease, wire_variant: None, owner: OperationOwner::Family, family: Some("network"), @@ -2606,7 +2606,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SeedDnsmasqLease"], authz: BrokerAuthzFacets { @@ -2629,7 +2629,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenPidfd", + operation: BrokerOperationName::OpenPidfd, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2638,7 +2638,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["OpenPidfd"], authz: BrokerAuthzFacets { @@ -2661,7 +2661,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenPeerPidfdFromAcceptedSocket", + operation: BrokerOperationName::OpenPeerPidfdFromAcceptedSocket, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2670,7 +2670,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "callable-read-only", + disposition: Disposition::CallableReadOnly, stub_target: None, audit_fields: &["OpenPeerPidfdFromAcceptedSocket"], authz: BrokerAuthzFacets { @@ -2693,7 +2693,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ObserveRunner", + operation: BrokerOperationName::ObserveRunner, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2702,7 +2702,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["ObserveRunner"], authz: BrokerAuthzFacets { @@ -2725,7 +2725,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "PollChildReaped", + operation: BrokerOperationName::PollChildReaped, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2734,7 +2734,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2757,7 +2757,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "PrepareRuntimeDir", + operation: BrokerOperationName::PrepareRuntimeDir, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2766,7 +2766,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["PrepareRuntimeDir"], authz: BrokerAuthzFacets { @@ -2789,7 +2789,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "PrepareStateDir", + operation: BrokerOperationName::PrepareStateDir, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2798,7 +2798,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: true, capabilities: true, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["PrepareStateDir", "PrepareSwtpmDir"], authz: BrokerAuthzFacets { @@ -2821,7 +2821,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "CgroupKill", + operation: BrokerOperationName::CgroupKill, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2830,7 +2830,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["CgroupKill"], authz: BrokerAuthzFacets { @@ -2853,7 +2853,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "SignalRunner", + operation: BrokerOperationName::SignalRunner, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2862,7 +2862,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SignalRunner"], authz: BrokerAuthzFacets { @@ -2885,7 +2885,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "DeregisterRunnerPidfd", + operation: BrokerOperationName::DeregisterRunnerPidfd, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2894,7 +2894,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["DeregisterRunnerPidfd"], authz: BrokerAuthzFacets { @@ -2917,7 +2917,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "SpawnRunner", + operation: BrokerOperationName::SpawnRunner, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2926,7 +2926,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SpawnRunner", "PrepareSwtpmDir"], authz: BrokerAuthzFacets { @@ -2949,7 +2949,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "inspect-process-family", + operation: BrokerOperationName::inspect_process_family, wire_variant: None, owner: OperationOwner::Family, family: Some("process"), @@ -2958,7 +2958,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host], w3: false, capabilities: false, - disposition: "callable-read-only", + disposition: Disposition::CallableReadOnly, stub_target: None, audit_fields: &[], authz: BrokerAuthzFacets { @@ -2981,7 +2981,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "StartSystemdUnit", + operation: BrokerOperationName::StartSystemdUnit, wire_variant: None, owner: OperationOwner::Family, family: Some("process-systemd"), @@ -2990,7 +2990,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SystemdUnit"], authz: BrokerAuthzFacets { @@ -3013,7 +3013,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "CheckSystemdUserManager", + operation: BrokerOperationName::CheckSystemdUserManager, wire_variant: None, owner: OperationOwner::Family, family: Some("process-systemd"), @@ -3022,7 +3022,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SystemdUnit"], authz: BrokerAuthzFacets { @@ -3045,7 +3045,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "ObserveSystemdUnit", + operation: BrokerOperationName::ObserveSystemdUnit, wire_variant: None, owner: OperationOwner::Family, family: Some("process-systemd"), @@ -3054,7 +3054,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SystemdUnit"], authz: BrokerAuthzFacets { @@ -3077,7 +3077,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "OpenSystemdUnitPidfd", + operation: BrokerOperationName::OpenSystemdUnitPidfd, wire_variant: None, owner: OperationOwner::Family, family: Some("process-systemd"), @@ -3086,7 +3086,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SystemdUnit"], authz: BrokerAuthzFacets { @@ -3109,7 +3109,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ deadline_tier: DeadlineTier::Standard, }, BrokerOperationRow { - operation: "StopSystemdUnit", + operation: BrokerOperationName::StopSystemdUnit, wire_variant: None, owner: OperationOwner::Family, family: Some("process-systemd"), @@ -3118,7 +3118,7 @@ pub const BROKER_OPERATION_CATALOG: &[BrokerOperationRow] = &[ profiles: &[BrokerProfileId::Host, BrokerProfileId::Guest], w3: false, capabilities: false, - disposition: "promoted-live", + disposition: Disposition::PromotedLive, stub_target: None, audit_fields: &["SystemdUnit"], authz: BrokerAuthzFacets { diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index e9597184f..03fedef9d 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -11353,7 +11353,7 @@ fn profile_capabilities(profile: BrokerProfile) -> Vec { BrokerProfile::Guest => profile .operations() .iter() - .map(|item| (*item).to_owned()) + .map(|item| item.as_str().to_owned()) .collect(), } } @@ -12587,8 +12587,9 @@ mod tests { let Some(_marker) = crate::catalog::stub_target(name) else { continue; }; - if crate::catalog::BrokerOperationRow::find(name) - .is_some_and(|row| row.disposition == "promoted-live") + if crate::catalog::BrokerOperationRow::find(name).is_some_and(|row| { + row.disposition == crate::catalog::Disposition::PromotedLive + }) { both_stubbed_and_dispatchable.push(name); } diff --git a/packages/d2b-broker/tests/guest_profile.rs b/packages/d2b-broker/tests/guest_profile.rs index 3083b9e2e..a3927582d 100644 --- a/packages/d2b-broker/tests/guest_profile.rs +++ b/packages/d2b-broker/tests/guest_profile.rs @@ -34,7 +34,10 @@ fn guest_profile_admits_only_local_process_effects() { "guest profile should admit declared local effect {operation}" ); assert!( - BrokerProfile::Guest.operations().contains(&operation), + BrokerProfile::Guest + .operations() + .iter() + .any(|item| item.as_str() == operation), "guest profile lost the committed local effect {operation}" ); } diff --git a/packages/d2b-broker/tests/host_profile.rs b/packages/d2b-broker/tests/host_profile.rs index 013f04c5e..03b395aba 100644 --- a/packages/d2b-broker/tests/host_profile.rs +++ b/packages/d2b-broker/tests/host_profile.rs @@ -18,7 +18,7 @@ fn host_profile_keeps_the_complete_closed_operation_catalog() { "ExportBrokerAudit", ] { assert!( - operations.contains(&operation), + operations.iter().any(|item| item.as_str() == operation), "host profile lost the existing operation {operation}" ); assert!( @@ -46,7 +46,7 @@ fn host_profile_keeps_the_complete_closed_operation_catalog() { "SeedDnsmasqLease", ] { assert!( - !operations.contains(&operation), + !operations.iter().any(|item| item.as_str() == operation), "host profile must not re-admit the retired operation {operation}" ); } diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 6a4902f4e..cb6178d5a 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -855,26 +855,30 @@ impl BrokerProfile { } /// Closed Host operation catalog. - pub const fn host_operations() -> &'static [&'static str] { + pub const fn host_operations() -> &'static [BrokerOperationName] { HOST_OPERATION_CATALOG } /// Closed Guest operation catalog. - pub const fn guest_operations() -> &'static [&'static str] { + pub const fn guest_operations() -> &'static [BrokerOperationName] { GUEST_OPERATION_CATALOG } /// Return the operation catalog for this profile. - pub const fn operations(self) -> &'static [&'static str] { + pub const fn operations(self) -> &'static [BrokerOperationName] { match self { Self::Host => Self::host_operations(), Self::Guest => Self::guest_operations(), } } - /// Check the stable operation name against the profile catalog. + /// Check the stable operation name against the profile catalog. The + /// admission keeps the string spelling, so the wire boundary is + /// unchanged by the typed catalogs. pub fn allows_operation(self, operation: &str) -> bool { - self.operations().contains(&operation) + self.operations() + .iter() + .any(|item| item.as_str() == operation) } /// Check the request against the closed profile catalog. The typed diff --git a/packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs b/packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs index 4f1138694..cd74809f6 100644 --- a/packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs +++ b/packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs @@ -2,58 +2,276 @@ // Do not hand-edit: `//packages/xtask:gen_broker_operations_drift` // regenerates this file and compares it byte-for-byte. +/// Every committed broker operation name, in declared order. +/// +/// The profile catalogs and the committed row table are typed against this +/// closed vocabulary; the wire boundary keeps the string spelling through +/// [`BrokerOperationName::as_str`]. +/// +/// A declared-method operation name is lower-kebab and not a valid variant +/// identifier; its variant mirrors the wire spelling as snake_case, which +/// the lint allowance below admits. +#[allow(non_camel_case_types)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum BrokerOperationName { + Hello, + PublishTrustedContext, + ExportBrokerAudit, + ApplyHostGenerationHandoff, + CreateOrReconcileUsersGroups, + DelegateCgroupV2, + InjectSecretById, + LaunchMinijailChild, + ModprobeIfAllowed, + OpenCgroupDir, + OpenDevice, + OpenFuse, + OpenHidrawSecurityKey, + OpenKvm, + QemuMediaEnroll, + QemuMediaRefreshRegistry, + QemuMediaBoot, + QemuMediaSystemPowerdown, + QemuMediaQueryStatus, + QemuMediaQuit, + QemuMediaAttach, + QemuMediaDetach, + PipeWireAudio, + OpenVhostNet, + ReconcileStorageScope, + ValidateLockSpec, + StoreSync, + ReadSecretById, + RotateSecretById, + UsbipBind, + UsbipBindFirewallRule, + UsbipProxyReconcile, + UsbipUnbind, + UsbipExplicitBind, + UsbipExplicitFirewallRule, + OwnershipMatrixCheck, + SshHostKeyPreflight, + DiskInit, + SecurityKeyOpenDevice, + SecurityKeyApplyUdevRules, + PrepareSwtpmDir, + EnvelopeInvoke, + open_pidfd, + open_peer_pidfd_from_accepted_socket, + poll_child_reaped, + prepare_directory, + kill_cgroup, + signal_pidfd, + deregister_pidfd, + spawn_process, + delegate_cgroup_v2, + open_cgroup_dir, + take_controller_bootstrap, + observe_process, + consume_cell, + complete_cell, + apply_nftables, + apply_nftables_projection, + apply_nm_unmanaged, + apply_route, + apply_sysctl, + create_bridge, + delete_bridge, + create_persistent_tap, + delete_persistent_tap, + create_tap_fd, + set_bridge_port_flags, + update_hosts_file, + seed_dnsmasq_lease, + ApplyNftables, + ApplyNftablesProjection, + ApplyNmUnmanaged, + ApplyRoute, + ApplySysctl, + CreateBridge, + DeleteBridge, + CreatePersistentTap, + DeletePersistentTap, + CreateTapFd, + SetBridgePortFlags, + UpdateHostsFile, + SeedDnsmasqLease, + OpenPidfd, + OpenPeerPidfdFromAcceptedSocket, + ObserveRunner, + PollChildReaped, + PrepareRuntimeDir, + PrepareStateDir, + CgroupKill, + SignalRunner, + DeregisterRunnerPidfd, + SpawnRunner, + inspect_process_family, + StartSystemdUnit, + CheckSystemdUserManager, + ObserveSystemdUnit, + OpenSystemdUnitPidfd, + StopSystemdUnit, +} + +impl BrokerOperationName { + /// The committed operation name. + pub const fn as_str(self) -> &'static str { + match self { + Self::Hello => "Hello", + Self::PublishTrustedContext => "PublishTrustedContext", + Self::ExportBrokerAudit => "ExportBrokerAudit", + Self::ApplyHostGenerationHandoff => "ApplyHostGenerationHandoff", + Self::CreateOrReconcileUsersGroups => "CreateOrReconcileUsersGroups", + Self::DelegateCgroupV2 => "DelegateCgroupV2", + Self::InjectSecretById => "InjectSecretById", + Self::LaunchMinijailChild => "LaunchMinijailChild", + Self::ModprobeIfAllowed => "ModprobeIfAllowed", + Self::OpenCgroupDir => "OpenCgroupDir", + Self::OpenDevice => "OpenDevice", + Self::OpenFuse => "OpenFuse", + Self::OpenHidrawSecurityKey => "OpenHidrawSecurityKey", + Self::OpenKvm => "OpenKvm", + Self::QemuMediaEnroll => "QemuMediaEnroll", + Self::QemuMediaRefreshRegistry => "QemuMediaRefreshRegistry", + Self::QemuMediaBoot => "QemuMediaBoot", + Self::QemuMediaSystemPowerdown => "QemuMediaSystemPowerdown", + Self::QemuMediaQueryStatus => "QemuMediaQueryStatus", + Self::QemuMediaQuit => "QemuMediaQuit", + Self::QemuMediaAttach => "QemuMediaAttach", + Self::QemuMediaDetach => "QemuMediaDetach", + Self::PipeWireAudio => "PipeWireAudio", + Self::OpenVhostNet => "OpenVhostNet", + Self::ReconcileStorageScope => "ReconcileStorageScope", + Self::ValidateLockSpec => "ValidateLockSpec", + Self::StoreSync => "StoreSync", + Self::ReadSecretById => "ReadSecretById", + Self::RotateSecretById => "RotateSecretById", + Self::UsbipBind => "UsbipBind", + Self::UsbipBindFirewallRule => "UsbipBindFirewallRule", + Self::UsbipProxyReconcile => "UsbipProxyReconcile", + Self::UsbipUnbind => "UsbipUnbind", + Self::UsbipExplicitBind => "UsbipExplicitBind", + Self::UsbipExplicitFirewallRule => "UsbipExplicitFirewallRule", + Self::OwnershipMatrixCheck => "OwnershipMatrixCheck", + Self::SshHostKeyPreflight => "SshHostKeyPreflight", + Self::DiskInit => "DiskInit", + Self::SecurityKeyOpenDevice => "SecurityKeyOpenDevice", + Self::SecurityKeyApplyUdevRules => "SecurityKeyApplyUdevRules", + Self::PrepareSwtpmDir => "PrepareSwtpmDir", + Self::EnvelopeInvoke => "EnvelopeInvoke", + Self::open_pidfd => "open-pidfd", + Self::open_peer_pidfd_from_accepted_socket => "open-peer-pidfd-from-accepted-socket", + Self::poll_child_reaped => "poll-child-reaped", + Self::prepare_directory => "prepare-directory", + Self::kill_cgroup => "kill-cgroup", + Self::signal_pidfd => "signal-pidfd", + Self::deregister_pidfd => "deregister-pidfd", + Self::spawn_process => "spawn-process", + Self::delegate_cgroup_v2 => "delegate-cgroup-v2", + Self::open_cgroup_dir => "open-cgroup-dir", + Self::take_controller_bootstrap => "take-controller-bootstrap", + Self::observe_process => "observe-process", + Self::consume_cell => "consume-cell", + Self::complete_cell => "complete-cell", + Self::apply_nftables => "apply-nftables", + Self::apply_nftables_projection => "apply-nftables-projection", + Self::apply_nm_unmanaged => "apply-nm-unmanaged", + Self::apply_route => "apply-route", + Self::apply_sysctl => "apply-sysctl", + Self::create_bridge => "create-bridge", + Self::delete_bridge => "delete-bridge", + Self::create_persistent_tap => "create-persistent-tap", + Self::delete_persistent_tap => "delete-persistent-tap", + Self::create_tap_fd => "create-tap-fd", + Self::set_bridge_port_flags => "set-bridge-port-flags", + Self::update_hosts_file => "update-hosts-file", + Self::seed_dnsmasq_lease => "seed-dnsmasq-lease", + Self::ApplyNftables => "ApplyNftables", + Self::ApplyNftablesProjection => "ApplyNftablesProjection", + Self::ApplyNmUnmanaged => "ApplyNmUnmanaged", + Self::ApplyRoute => "ApplyRoute", + Self::ApplySysctl => "ApplySysctl", + Self::CreateBridge => "CreateBridge", + Self::DeleteBridge => "DeleteBridge", + Self::CreatePersistentTap => "CreatePersistentTap", + Self::DeletePersistentTap => "DeletePersistentTap", + Self::CreateTapFd => "CreateTapFd", + Self::SetBridgePortFlags => "SetBridgePortFlags", + Self::UpdateHostsFile => "UpdateHostsFile", + Self::SeedDnsmasqLease => "SeedDnsmasqLease", + Self::OpenPidfd => "OpenPidfd", + Self::OpenPeerPidfdFromAcceptedSocket => "OpenPeerPidfdFromAcceptedSocket", + Self::ObserveRunner => "ObserveRunner", + Self::PollChildReaped => "PollChildReaped", + Self::PrepareRuntimeDir => "PrepareRuntimeDir", + Self::PrepareStateDir => "PrepareStateDir", + Self::CgroupKill => "CgroupKill", + Self::SignalRunner => "SignalRunner", + Self::DeregisterRunnerPidfd => "DeregisterRunnerPidfd", + Self::SpawnRunner => "SpawnRunner", + Self::inspect_process_family => "inspect-process-family", + Self::StartSystemdUnit => "StartSystemdUnit", + Self::CheckSystemdUserManager => "CheckSystemdUserManager", + Self::ObserveSystemdUnit => "ObserveSystemdUnit", + Self::OpenSystemdUnitPidfd => "OpenSystemdUnitPidfd", + Self::StopSystemdUnit => "StopSystemdUnit", + } + } +} + /// Every request currently defined by the broker wire. Host mode is closed /// over this list rather than using an open-ended default. -pub const HOST_OPERATION_CATALOG: &[&str] = &[ - "Hello", - "PublishTrustedContext", - "ExportBrokerAudit", - "ApplyHostGenerationHandoff", - "CreateOrReconcileUsersGroups", - "DelegateCgroupV2", - "InjectSecretById", - "LaunchMinijailChild", - "ModprobeIfAllowed", - "OpenCgroupDir", - "OpenDevice", - "OpenFuse", - "OpenHidrawSecurityKey", - "OpenKvm", - "QemuMediaEnroll", - "QemuMediaRefreshRegistry", - "QemuMediaBoot", - "QemuMediaSystemPowerdown", - "QemuMediaQueryStatus", - "QemuMediaQuit", - "QemuMediaAttach", - "QemuMediaDetach", - "PipeWireAudio", - "OpenVhostNet", - "ReconcileStorageScope", - "ValidateLockSpec", - "StoreSync", - "ReadSecretById", - "RotateSecretById", - "UsbipBind", - "UsbipBindFirewallRule", - "UsbipProxyReconcile", - "UsbipUnbind", - "UsbipExplicitBind", - "UsbipExplicitFirewallRule", - "OwnershipMatrixCheck", - "SshHostKeyPreflight", - "DiskInit", - "SecurityKeyOpenDevice", - "SecurityKeyApplyUdevRules", - "EnvelopeInvoke", +pub const HOST_OPERATION_CATALOG: &[BrokerOperationName] = &[ + BrokerOperationName::Hello, + BrokerOperationName::PublishTrustedContext, + BrokerOperationName::ExportBrokerAudit, + BrokerOperationName::ApplyHostGenerationHandoff, + BrokerOperationName::CreateOrReconcileUsersGroups, + BrokerOperationName::DelegateCgroupV2, + BrokerOperationName::InjectSecretById, + BrokerOperationName::LaunchMinijailChild, + BrokerOperationName::ModprobeIfAllowed, + BrokerOperationName::OpenCgroupDir, + BrokerOperationName::OpenDevice, + BrokerOperationName::OpenFuse, + BrokerOperationName::OpenHidrawSecurityKey, + BrokerOperationName::OpenKvm, + BrokerOperationName::QemuMediaEnroll, + BrokerOperationName::QemuMediaRefreshRegistry, + BrokerOperationName::QemuMediaBoot, + BrokerOperationName::QemuMediaSystemPowerdown, + BrokerOperationName::QemuMediaQueryStatus, + BrokerOperationName::QemuMediaQuit, + BrokerOperationName::QemuMediaAttach, + BrokerOperationName::QemuMediaDetach, + BrokerOperationName::PipeWireAudio, + BrokerOperationName::OpenVhostNet, + BrokerOperationName::ReconcileStorageScope, + BrokerOperationName::ValidateLockSpec, + BrokerOperationName::StoreSync, + BrokerOperationName::ReadSecretById, + BrokerOperationName::RotateSecretById, + BrokerOperationName::UsbipBind, + BrokerOperationName::UsbipBindFirewallRule, + BrokerOperationName::UsbipProxyReconcile, + BrokerOperationName::UsbipUnbind, + BrokerOperationName::UsbipExplicitBind, + BrokerOperationName::UsbipExplicitFirewallRule, + BrokerOperationName::OwnershipMatrixCheck, + BrokerOperationName::SshHostKeyPreflight, + BrokerOperationName::DiskInit, + BrokerOperationName::SecurityKeyOpenDevice, + BrokerOperationName::SecurityKeyApplyUdevRules, + BrokerOperationName::EnvelopeInvoke, ]; /// Guest-local process and broker lifecycle effects. Host networking, /// devices, storage, realm, and allocator operations are intentionally /// absent from this catalog. -pub const GUEST_OPERATION_CATALOG: &[&str] = &[ - "Hello", - "PublishTrustedContext", - "ExportBrokerAudit", - "EnvelopeInvoke", +pub const GUEST_OPERATION_CATALOG: &[BrokerOperationName] = &[ + BrokerOperationName::Hello, + BrokerOperationName::PublishTrustedContext, + BrokerOperationName::ExportBrokerAudit, + BrokerOperationName::EnvelopeInvoke, ]; diff --git a/packages/d2b-core/fuzz/corpus/privileges/03-enum-mismatch.json b/packages/d2b-core/fuzz/corpus/privileges/03-enum-mismatch.json index 87c7e0d7a..f553825c7 100644 --- a/packages/d2b-core/fuzz/corpus/privileges/03-enum-mismatch.json +++ b/packages/d2b-core/fuzz/corpus/privileges/03-enum-mismatch.json @@ -1 +1 @@ -{"schemaVersion":"v1","publicOperations":[{"operation":"NotARealOp","subject":"host","scope":"global","allowedGroups":[],"destructive":false,"secretAccess":"none","brokerRequired":"no","audit":{"required":false,"mode":"deny-only","retainedFields":[]},"defaultForUnknown":"deny-and-audit"}],"brokerOperations":[]} +{"schemaVersion":"v1","publicOperations":[{"operation":"NotARealOp","subject":"host","scope":"global","allowedGroups":[],"destructive":"no","secretAccess":"none","brokerRequired":"no","audit":{"required":false,"mode":"deny-only","retainedFields":[]},"defaultForUnknown":"deny-and-audit"}],"brokerOperations":[]} diff --git a/packages/d2b-core/src/generated/broker_operation_authz.rs b/packages/d2b-core/src/generated/broker_operation_authz.rs index 13c257d9c..0f2194aa2 100644 --- a/packages/d2b-core/src/generated/broker_operation_authz.rs +++ b/packages/d2b-core/src/generated/broker_operation_authz.rs @@ -5,984 +5,984 @@ /// Complete private broker enum authorization matrix from the committed /// operation rows. pub const BROKER_OPERATION_AUTHZ: &[OperationAuthzRow] = &[ - row( - "Hello", - "handshake", - "global", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "PublishTrustedContext", - "handshake", - "global", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ExportBrokerAudit", - "broker-admin", - "global", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ApplyHostGenerationHandoff", - "host-generation", - "global", - &["d2bd"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "CreateOrReconcileUsersGroups", - "account", - "global/per-role", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "DelegateCgroupV2", - "cgroup", - "global/per-VM/role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "InjectSecretById", - "secret/key", - "per-VM/key", - &["d2bd"], - false, - SecretAccess::ReadWrite, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "LaunchMinijailChild", - "process", - "per-VM/role", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ModprobeIfAllowed", - "kernel-module", - "global/feature", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenCgroupDir", - "cgroup", - "global/per-VM/role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenDevice", - "device", - "per-role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenFuse", - "device", - "per-role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenHidrawSecurityKey", - "security-key", - "per-VM/per-selector", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenKvm", - "device", - "per-role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "QemuMediaEnroll", - "qemu-media registry", - "per-VM/per-media-ref", - &["d2bd"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "QemuMediaRefreshRegistry", - "qemu-media redacted registry", - "host", - &["d2bd"], - false, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "QemuMediaBoot", - "qemu-media boot media", - "per-VM/per-media-ref", - &["d2bd"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "QemuMediaSystemPowerdown", - "qemu-media lifecycle", - "per-VM", - &["d2bd"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "QemuMediaQueryStatus", - "qemu-media lifecycle status", - "per-VM", - &["d2bd"], - false, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Errors, - ), - row( - "QemuMediaQuit", - "qemu-media lifecycle", - "per-VM", - &["d2bd"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "QemuMediaAttach", - "qemu-media hotplug", - "per-VM/per-media-ref", - &["d2bd"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "QemuMediaDetach", - "qemu-media hotplug", - "per-VM/per-media-ref", - &["d2bd"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "PipeWireAudio", - "audio", - "per-VM/role/channel", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenVhostNet", - "device", - "per-role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ReconcileStorageScope", - "fs", - "global/per-VM/per-role", - &["d2bd"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ValidateLockSpec", - "lock", - "global/per-VM/per-role", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "StoreSync", - "store", - "per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ReadSecretById", - "secret/key", - "per-VM/key", - &["d2bd"], - false, - SecretAccess::ReadWrite, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "RotateSecretById", - "secret/key", - "per-VM/key", - &["d2bd"], - true, - SecretAccess::ReadWrite, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "UsbipBind", - "USBIP", - "per-busid/env", - &["d2bd"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "UsbipBindFirewallRule", - "USBIP firewall", - "per-busid", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "UsbipProxyReconcile", - "USBIP", - "per-busid/env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "UsbipUnbind", - "USBIP", - "per-busid/env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "UsbipExplicitBind", - "USBIP explicit attach", - "per-busid/env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "UsbipExplicitFirewallRule", - "USBIP explicit attach firewall", - "per-busid/env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OwnershipMatrixCheck", - "host", - "per-VM", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "SshHostKeyPreflight", - "ssh-host-key", - "per-VM", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "DiskInit", - "disk", - "per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "SecurityKeyOpenDevice", - "security-key/hidraw", - "per-device-label", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "SecurityKeyApplyUdevRules", - "security-key/udev", - "host", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "PrepareSwtpmDir", - "fs", - "per-VM", - &["d2bd"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "EnvelopeInvoke", - "envelope", - "per-operation row", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "open-pidfd", - "pidfd", - "per-process", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "open-peer-pidfd-from-accepted-socket", - "pidfd", - "accepted Unix socket", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "poll-child-reaped", - "runner", - "global", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "prepare-directory", - "fs", - "global/per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "kill-cgroup", - "cgroup", - "per-VM/role leaf", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "signal-pidfd", - "runner", - "per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "deregister-pidfd", - "runner", - "per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "spawn-process", - "vm-runner", - "per-VM/role", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "delegate-cgroup-v2", - "cgroup", - "global/per-VM/role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "open-cgroup-dir", - "cgroup", - "global/per-VM/role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "take-controller-bootstrap", - "runner", - "per-VM/role", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "observe-process", - "runner", - "per-VM/role", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "consume-cell", - "cell", - "per-invocation", - &["d2bd", "d2b-admin", "d2b-launcher"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "complete-cell", - "cell", - "per-invocation", - &["d2bd", "d2b-admin", "d2b-launcher"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "apply-nftables", - "network", - "per-host firewall table", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "apply-nftables-projection", - "network", - "per-network firewall projection", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "apply-nm-unmanaged", - "network", - "per-host NetworkManager unmanaged", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "apply-route", - "network", - "per-network route", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "apply-sysctl", - "network", - "per-network sysctl", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "create-bridge", - "network", - "per-network bridge", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "delete-bridge", - "network", - "per-network bridge", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "create-persistent-tap", - "network", - "per-VM/role attachment", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "delete-persistent-tap", - "network", - "per-VM/role attachment", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "create-tap-fd", - "network", - "per-VM/role attachment", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "set-bridge-port-flags", - "network", - "per-VM/role bridge port", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "update-hosts-file", - "network", - "per-host hosts file", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "seed-dnsmasq-lease", - "network", - "per-VM dnsmasq lease", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ApplyNftables", - "network-host", - "global/per-env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ApplyNftablesProjection", - "network-host", - "global/per-env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ApplyNmUnmanaged", - "network-host", - "global/per-env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ApplyRoute", - "network-host", - "global/per-env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ApplySysctl", - "network-host", - "global/per-env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "CreateBridge", - "network", - "per-env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "DeleteBridge", - "network", - "per-env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "CreatePersistentTap", - "network", - "per-env/VM/TAP", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "DeletePersistentTap", - "network", - "per-env/VM/TAP", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "CreateTapFd", - "network", - "per-env/VM/TAP", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "SetBridgePortFlags", - "network", - "per-env/VM/TAP", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "UpdateHostsFile", - "name-resolution", - "global", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "SeedDnsmasqLease", - "network", - "per-VM/env", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenPidfd", - "pidfd", - "per-VM/role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenPeerPidfdFromAcceptedSocket", - "pidfd", - "accepted Unix socket", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ObserveRunner", - "runner", - "per-VM/role", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "PollChildReaped", - "runner", - "global", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "PrepareRuntimeDir", - "fs", - "global/per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "PrepareStateDir", - "fs", - "global/per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "CgroupKill", - "cgroup", - "per-VM/role leaf", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "SignalRunner", - "runner", - "per-VM", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "DeregisterRunnerPidfd", - "runner", - "per-VM", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "SpawnRunner", - "vm-runner", - "per-VM/role", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "inspect-process-family", - "process", - "per-type", - &["d2bd", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "StartSystemdUnit", - "systemd-unit", - "per-VM/role", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "CheckSystemdUserManager", - "systemd-user-manager", - "per-user", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "ObserveSystemdUnit", - "systemd-unit", - "per-VM/role", - &["d2bd"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "OpenSystemdUnitPidfd", - "systemd-unit-pidfd", - "per-VM/role", - &["d2bd"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "StopSystemdUnit", - "systemd-unit", - "per-VM/role", - &["d2bd"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), + OperationAuthzRow { + operation: "Hello", + subject: "handshake", + scope: "global", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "PublishTrustedContext", + subject: "handshake", + scope: "global", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ExportBrokerAudit", + subject: "broker-admin", + scope: "global", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ApplyHostGenerationHandoff", + subject: "host-generation", + scope: "global", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "CreateOrReconcileUsersGroups", + subject: "account", + scope: "global/per-role", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "DelegateCgroupV2", + subject: "cgroup", + scope: "global/per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "InjectSecretById", + subject: "secret/key", + scope: "per-VM/key", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::ReadWrite, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "LaunchMinijailChild", + subject: "process", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ModprobeIfAllowed", + subject: "kernel-module", + scope: "global/feature", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenCgroupDir", + subject: "cgroup", + scope: "global/per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenDevice", + subject: "device", + scope: "per-role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenFuse", + subject: "device", + scope: "per-role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenHidrawSecurityKey", + subject: "security-key", + scope: "per-VM/per-selector", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenKvm", + subject: "device", + scope: "per-role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "QemuMediaEnroll", + subject: "qemu-media registry", + scope: "per-VM/per-media-ref", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "QemuMediaRefreshRegistry", + subject: "qemu-media redacted registry", + scope: "host", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "QemuMediaBoot", + subject: "qemu-media boot media", + scope: "per-VM/per-media-ref", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "QemuMediaSystemPowerdown", + subject: "qemu-media lifecycle", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "QemuMediaQueryStatus", + subject: "qemu-media lifecycle status", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "QemuMediaQuit", + subject: "qemu-media lifecycle", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "QemuMediaAttach", + subject: "qemu-media hotplug", + scope: "per-VM/per-media-ref", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "QemuMediaDetach", + subject: "qemu-media hotplug", + scope: "per-VM/per-media-ref", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "PipeWireAudio", + subject: "audio", + scope: "per-VM/role/channel", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenVhostNet", + subject: "device", + scope: "per-role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ReconcileStorageScope", + subject: "fs", + scope: "global/per-VM/per-role", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ValidateLockSpec", + subject: "lock", + scope: "global/per-VM/per-role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "StoreSync", + subject: "store", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ReadSecretById", + subject: "secret/key", + scope: "per-VM/key", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::ReadWrite, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "RotateSecretById", + subject: "secret/key", + scope: "per-VM/key", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::ReadWrite, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "UsbipBind", + subject: "USBIP", + scope: "per-busid/env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "UsbipBindFirewallRule", + subject: "USBIP firewall", + scope: "per-busid", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "UsbipProxyReconcile", + subject: "USBIP", + scope: "per-busid/env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "UsbipUnbind", + subject: "USBIP", + scope: "per-busid/env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "UsbipExplicitBind", + subject: "USBIP explicit attach", + scope: "per-busid/env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "UsbipExplicitFirewallRule", + subject: "USBIP explicit attach firewall", + scope: "per-busid/env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OwnershipMatrixCheck", + subject: "host", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "SshHostKeyPreflight", + subject: "ssh-host-key", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "DiskInit", + subject: "disk", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "SecurityKeyOpenDevice", + subject: "security-key/hidraw", + scope: "per-device-label", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "SecurityKeyApplyUdevRules", + subject: "security-key/udev", + scope: "host", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "PrepareSwtpmDir", + subject: "fs", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "EnvelopeInvoke", + subject: "envelope", + scope: "per-operation row", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "open-pidfd", + subject: "pidfd", + scope: "per-process", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "open-peer-pidfd-from-accepted-socket", + subject: "pidfd", + scope: "accepted Unix socket", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "poll-child-reaped", + subject: "runner", + scope: "global", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "prepare-directory", + subject: "fs", + scope: "global/per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "kill-cgroup", + subject: "cgroup", + scope: "per-VM/role leaf", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "signal-pidfd", + subject: "runner", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "deregister-pidfd", + subject: "runner", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "spawn-process", + subject: "vm-runner", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "delegate-cgroup-v2", + subject: "cgroup", + scope: "global/per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "open-cgroup-dir", + subject: "cgroup", + scope: "global/per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "take-controller-bootstrap", + subject: "runner", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "observe-process", + subject: "runner", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "consume-cell", + subject: "cell", + scope: "per-invocation", + allowed_groups: &["d2bd", "d2b-admin", "d2b-launcher"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "complete-cell", + subject: "cell", + scope: "per-invocation", + allowed_groups: &["d2bd", "d2b-admin", "d2b-launcher"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "apply-nftables", + subject: "network", + scope: "per-host firewall table", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "apply-nftables-projection", + subject: "network", + scope: "per-network firewall projection", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "apply-nm-unmanaged", + subject: "network", + scope: "per-host NetworkManager unmanaged", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "apply-route", + subject: "network", + scope: "per-network route", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "apply-sysctl", + subject: "network", + scope: "per-network sysctl", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "create-bridge", + subject: "network", + scope: "per-network bridge", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "delete-bridge", + subject: "network", + scope: "per-network bridge", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "create-persistent-tap", + subject: "network", + scope: "per-VM/role attachment", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "delete-persistent-tap", + subject: "network", + scope: "per-VM/role attachment", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "create-tap-fd", + subject: "network", + scope: "per-VM/role attachment", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "set-bridge-port-flags", + subject: "network", + scope: "per-VM/role bridge port", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "update-hosts-file", + subject: "network", + scope: "per-host hosts file", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "seed-dnsmasq-lease", + subject: "network", + scope: "per-VM dnsmasq lease", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ApplyNftables", + subject: "network-host", + scope: "global/per-env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ApplyNftablesProjection", + subject: "network-host", + scope: "global/per-env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ApplyNmUnmanaged", + subject: "network-host", + scope: "global/per-env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ApplyRoute", + subject: "network-host", + scope: "global/per-env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ApplySysctl", + subject: "network-host", + scope: "global/per-env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "CreateBridge", + subject: "network", + scope: "per-env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "DeleteBridge", + subject: "network", + scope: "per-env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "CreatePersistentTap", + subject: "network", + scope: "per-env/VM/TAP", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "DeletePersistentTap", + subject: "network", + scope: "per-env/VM/TAP", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "CreateTapFd", + subject: "network", + scope: "per-env/VM/TAP", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "SetBridgePortFlags", + subject: "network", + scope: "per-env/VM/TAP", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "UpdateHostsFile", + subject: "name-resolution", + scope: "global", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "SeedDnsmasqLease", + subject: "network", + scope: "per-VM/env", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenPidfd", + subject: "pidfd", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenPeerPidfdFromAcceptedSocket", + subject: "pidfd", + scope: "accepted Unix socket", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ObserveRunner", + subject: "runner", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "PollChildReaped", + subject: "runner", + scope: "global", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "PrepareRuntimeDir", + subject: "fs", + scope: "global/per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "PrepareStateDir", + subject: "fs", + scope: "global/per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "CgroupKill", + subject: "cgroup", + scope: "per-VM/role leaf", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "SignalRunner", + subject: "runner", + scope: "per-VM", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "DeregisterRunnerPidfd", + subject: "runner", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "SpawnRunner", + subject: "vm-runner", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "inspect-process-family", + subject: "process", + scope: "per-type", + allowed_groups: &["d2bd", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "StartSystemdUnit", + subject: "systemd-unit", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "CheckSystemdUserManager", + subject: "systemd-user-manager", + scope: "per-user", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "ObserveSystemdUnit", + subject: "systemd-unit", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "OpenSystemdUnitPidfd", + subject: "systemd-unit-pidfd", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "StopSystemdUnit", + subject: "systemd-unit", + scope: "per-VM/role", + allowed_groups: &["d2bd"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, ]; diff --git a/packages/d2b-core/src/privileges.rs b/packages/d2b-core/src/privileges.rs index d33e5a39d..a464316c4 100644 --- a/packages/d2b-core/src/privileges.rs +++ b/packages/d2b-core/src/privileges.rs @@ -31,7 +31,7 @@ pub struct OperationAuthz { /// Groups allowed to invoke the operation; empty denies by default. pub allowed_groups: Vec, /// Whether state mutation, teardown, rollback, GC, or live routing changes are possible. - pub destructive: bool, + pub destructive: Destructive, /// Whether secret or key material can be read or modified. pub secret_access: SecretAccess, /// Whether the private broker is required or conditionally used. @@ -42,6 +42,17 @@ pub struct OperationAuthz { pub default_for_unknown: DefaultForUnknown, } +/// Destructive class for an authorization row. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum Destructive { + /// No state mutation, teardown, rollback, GC, or live routing change. + No, + /// State mutation, teardown, rollback, GC, or live routing changes are + /// possible. + Yes, +} + /// Secret exposure class for an authorization row. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] @@ -103,8 +114,8 @@ pub struct OperationAuthzRow { pub scope: &'static str, /// Allowed groups. pub allowed_groups: &'static [&'static str], - /// Destructive flag. - pub destructive: bool, + /// Destructive class. + pub destructive: Destructive, /// Secret access class. pub secret_access: SecretAccess, /// Broker requirement class. @@ -140,573 +151,550 @@ fn operation_schema(_gen: &mut SchemaGenerator) -> Schema { /// Complete initial public CLI/API authorization matrix from the portability plan. pub const PUBLIC_OPERATION_AUTHZ: &[OperationAuthzRow] = &[ - row( - "hello", - "daemon", - "global", - &["any-local-client"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::DenyOnly, - ), - row( - "capabilities", - "daemon", - "global", - &["any-local-client"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::DenyOnly, - ), - row( - "auth status", - "daemon", - "global", - &["any-local-client"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::DenyOnly, - ), - row( - "op", - "operation/realm state", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "resource", - "Zone Resource API", - "per-Zone", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "vm", - "VM command family", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "activation", - "VM/activation", - "global-or-scoped", - &["d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "device", - "device", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "display", - "VM/display", - "per-VM/per-realm", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "guest", - "Guest", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "clipboard", - "host clipboard", - "local-user-session", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::MetadataOnly, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "realm", - "realm command family", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "list", - "VM/env", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "status", - "VM/env", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "status --check-bridges", - "VM/env", - "global-or-scoped", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "audit", - "host/VM", - "global", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "audit --human", - "host/VM", - "global", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "audit --json", - "host/VM", - "global", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "host doctor --read-only", - "host", - "global", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::NoMutation, - AuditMode::Yes, - ), - row( - "host prepare", - "host", - "global", - &["d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::NoMutation, - AuditMode::Yes, - ), - row( - "host prepare --dry-run", - "host", - "global", - &["d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::NoMutation, - AuditMode::Yes, - ), - row( - "host destroy --dry-run", - "host", - "global", - &["d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::NoMutation, - AuditMode::Yes, - ), - row( - "host shutdown-hook --apply", - "host lifecycle", - "global", - &["host-shutdown"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "host prepare --apply", - "host", - "global", - &["d2b-admin"], - true, - SecretAccess::PossiblePathsOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "host reconcile-otel-acls --apply", - "host/observability", - "global", - &["d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "host destroy --apply", - "host", - "global", - &["d2b-admin"], - true, - SecretAccess::PossiblePathsOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "up", - "VM/env", - "per-VM/per-env", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "down", - "VM/env", - "per-VM/per-env", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "restart", - "VM/env", - "per-VM/per-env", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "console", - "VM", - "per-VM", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "config", - "VM", - "per-VM", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "build", - "VM", - "per-VM", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::Conditional, - AuditMode::Yes, - ), - row( - "generations", - "VM", - "per-VM", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "launch", - "workload/configured launch", - "per-workload/per-realm", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "exec", - "VM/process", - "per-VM", - &["d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "shell", - "VM/persistent shell", - "per-VM", - &["d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "vm display", - "VM/display", - "per-VM/per-realm", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::No, - AuditMode::Yes, - ), - row( - "switch", - "VM", - "per-VM", - &["d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "boot", - "VM", - "per-VM", - &["d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "test", - "VM", - "per-VM", - &["d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "rollback", - "VM", - "per-VM", - &["d2b-admin"], - true, - SecretAccess::MetadataOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "keys rotate", - "key", - "per-VM", - &["d2b-admin"], - true, - SecretAccess::ReadWrite, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "audio", - "VM/audio", - "per-VM", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "audio status", - "VM/audio", - "per-VM", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::No, - AuditMode::Errors, - ), - row( - "audio mic", - "VM/audio", - "per-VM", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "audio speaker", - "VM/audio", - "per-VM", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "audio on", - "VM/audio", - "per-VM", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "audio off", - "VM/audio", - "per-VM", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "usb", - "VM/USB busid", - "per-VM/per-env", - &["d2b-launcher", "d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "usb attach", - "VM/USB busid", - "per-VM/per-env/per-busid", - &["d2b-admin"], - true, - SecretAccess::RedactedOnly, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "usb detach", - "VM/USB busid", - "per-VM/per-env/per-busid", - &["d2b-admin"], - true, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "usb probe", - "VM/USB busid", - "global", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "usb security-key", - "VM/USB security-key", - "scoped", - &["d2b-launcher", "d2b-admin"], - false, - SecretAccess::None, - BrokerRequirement::Yes, - AuditMode::Yes, - ), - row( - "debug bundle", - "diagnostics", - "scoped", - &["d2b-admin"], - false, - SecretAccess::RedactedOnly, - BrokerRequirement::NoMutation, - AuditMode::Yes, - ), + OperationAuthzRow { + operation: "hello", + subject: "daemon", + scope: "global", + allowed_groups: &["any-local-client"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::DenyOnly, + }, + OperationAuthzRow { + operation: "capabilities", + subject: "daemon", + scope: "global", + allowed_groups: &["any-local-client"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::DenyOnly, + }, + OperationAuthzRow { + operation: "auth status", + subject: "daemon", + scope: "global", + allowed_groups: &["any-local-client"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::DenyOnly, + }, + OperationAuthzRow { + operation: "op", + subject: "operation/realm state", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "resource", + subject: "Zone Resource API", + scope: "per-Zone", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "vm", + subject: "VM command family", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "activation", + subject: "VM/activation", + scope: "global-or-scoped", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "device", + subject: "device", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "display", + subject: "VM/display", + scope: "per-VM/per-realm", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "guest", + subject: "Guest", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "clipboard", + subject: "host clipboard", + scope: "local-user-session", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "realm", + subject: "realm command family", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "list", + subject: "VM/env", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "status", + subject: "VM/env", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "status --check-bridges", + subject: "VM/env", + scope: "global-or-scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "audit", + subject: "host/VM", + scope: "global", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "audit --human", + subject: "host/VM", + scope: "global", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "audit --json", + subject: "host/VM", + scope: "global", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host doctor --read-only", + subject: "host", + scope: "global", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::NoMutation, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host prepare", + subject: "host", + scope: "global", + allowed_groups: &["d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::NoMutation, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host prepare --dry-run", + subject: "host", + scope: "global", + allowed_groups: &["d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::NoMutation, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host destroy --dry-run", + subject: "host", + scope: "global", + allowed_groups: &["d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::NoMutation, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host shutdown-hook --apply", + subject: "host lifecycle", + scope: "global", + allowed_groups: &["host-shutdown"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host prepare --apply", + subject: "host", + scope: "global", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::PossiblePathsOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host reconcile-otel-acls --apply", + subject: "host/observability", + scope: "global", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "host destroy --apply", + subject: "host", + scope: "global", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::PossiblePathsOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "up", + subject: "VM/env", + scope: "per-VM/per-env", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "down", + subject: "VM/env", + scope: "per-VM/per-env", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "restart", + subject: "VM/env", + scope: "per-VM/per-env", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "console", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "config", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "build", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Conditional, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "generations", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "launch", + subject: "workload/configured launch", + scope: "per-workload/per-realm", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "exec", + subject: "VM/process", + scope: "per-VM", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "shell", + subject: "VM/persistent shell", + scope: "per-VM", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "vm display", + subject: "VM/display", + scope: "per-VM/per-realm", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "switch", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "boot", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "test", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "rollback", + subject: "VM", + scope: "per-VM", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::MetadataOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "keys rotate", + subject: "key", + scope: "per-VM", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::ReadWrite, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "audio", + subject: "VM/audio", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "audio status", + subject: "VM/audio", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::No, + audit_mode: AuditMode::Errors, + }, + OperationAuthzRow { + operation: "audio mic", + subject: "VM/audio", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "audio speaker", + subject: "VM/audio", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "audio on", + subject: "VM/audio", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "audio off", + subject: "VM/audio", + scope: "per-VM", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "usb", + subject: "VM/USB busid", + scope: "per-VM/per-env", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "usb attach", + subject: "VM/USB busid", + scope: "per-VM/per-env/per-busid", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "usb detach", + subject: "VM/USB busid", + scope: "per-VM/per-env/per-busid", + allowed_groups: &["d2b-admin"], + destructive: Destructive::Yes, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "usb probe", + subject: "VM/USB busid", + scope: "global", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "usb security-key", + subject: "VM/USB security-key", + scope: "scoped", + allowed_groups: &["d2b-launcher", "d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::None, + broker_required: BrokerRequirement::Yes, + audit_mode: AuditMode::Yes, + }, + OperationAuthzRow { + operation: "debug bundle", + subject: "diagnostics", + scope: "scoped", + allowed_groups: &["d2b-admin"], + destructive: Destructive::No, + secret_access: SecretAccess::RedactedOnly, + broker_required: BrokerRequirement::NoMutation, + audit_mode: AuditMode::Yes, + }, ]; include!("generated/broker_operation_authz.rs"); -#[allow(clippy::too_many_arguments)] -const fn row( - operation: &'static str, - subject: &'static str, - scope: &'static str, - allowed_groups: &'static [&'static str], - destructive: bool, - secret_access: SecretAccess, - broker_required: BrokerRequirement, - audit_mode: AuditMode, -) -> OperationAuthzRow { - OperationAuthzRow { - operation, - subject, - scope, - allowed_groups, - destructive, - secret_access, - broker_required, - audit_mode, - } -} - impl From<&OperationAuthzRow> for OperationAuthz { fn from(row: &OperationAuthzRow) -> Self { Self { diff --git a/packages/xtask/src/gen_broker_operations.rs b/packages/xtask/src/gen_broker_operations.rs index e2a5c1626..c1a487fc7 100644 --- a/packages/xtask/src/gen_broker_operations.rs +++ b/packages/xtask/src/gen_broker_operations.rs @@ -313,6 +313,13 @@ const PAYLOAD_PROVENANCE: [&str; 2] = ["wire", "request"]; /// The deadline tiers a row may declare; a row that declares none sits on /// the standard tier. const DEADLINE_TIERS: [&str; 2] = ["standard", "extended"]; +/// The dispositions a row may admit. +const DISPOSITIONS: [&str; 4] = [ + "callable-read-only", + "promoted-live", + "stubbed-unimplemented", + "compile-time-only", +]; /// The method-name spelling every operation-serving method carries: a /// lower-kebab token. A method outside the grammar cannot be addressed by @@ -545,6 +552,13 @@ fn validate_row(row: &Row, source: &str) -> Result<(), Box(items: impl IntoIterator, indent: &str) -> String { - items - .into_iter() - .map(|item| format!("{indent}\"{item}\",\n")) - .collect() -} - /// The generated `StubTarget` variant a reserved stub's committed disposition /// target maps to. /// @@ -798,6 +805,43 @@ fn stub_target_variant(row: &Row) -> Option<&'static str> { .map(|(_, variant)| *variant) } +/// The Rust variant name one committed operation maps to on the generated +/// `BrokerOperationName` enum. +/// +/// A PascalCase operation name is already a valid variant identifier and is +/// kept verbatim (the wire-spelling convention the `W3BrokerOperation` +/// sibling uses); a lower-kebab name (the declared-method vocabulary, which +/// is not a valid Rust identifier) maps to its snake_case spelling. The map +/// is injective over the committed set: no kebab name's snake_case spelling +/// collides with a PascalCase name's variant, and two distinct kebab names +/// cannot map to one spelling, so the enum is closed over exactly the one +/// variant per committed row. +fn operation_variant(operation: &str) -> String { + if operation + .bytes() + .all(|byte| byte.is_ascii_alphanumeric() || byte == b'_') + { + return operation.to_owned(); + } + operation.replace('-', "_") +} + +/// The generated `Disposition` variant a committed disposition spelling +/// maps to. +/// +/// The row's disposition is a closed set: a spelling outside the committed +/// vocabulary fails generation instead of widening what a disposition may +/// mean. +fn disposition_variant(disposition: &str) -> &'static str { + match disposition { + "callable-read-only" => "Disposition::CallableReadOnly", + "promoted-live" => "Disposition::PromotedLive", + "stubbed-unimplemented" => "Disposition::StubbedUnimplemented", + "compile-time-only" => "Disposition::CompileTimeOnly", + other => unreachable!("validated disposition {other}"), + } +} + /// The first declared join field a row's payload does not carry as a /// required, non-secret property. fn undeclared_join_field(row: &Row) -> Option<&str> { @@ -846,22 +890,68 @@ fn profile_catalog<'a>(rows: &'a [Row], profile: &str) -> Vec<&'a str> { } fn generate_profiles(catalog: &Catalog) -> String { + let variants = catalog + .rows + .iter() + .map(|row| format!(" {},\n", operation_variant(&row.operation))) + .collect::(); + let as_str_arms = catalog + .rows + .iter() + .map(|row| { + format!( + " Self::{} => \"{}\",\n", + operation_variant(&row.operation), + row.operation + ) + }) + .collect::(); format!( "// {HEADER}\n\n\ + /// Every committed broker operation name, in declared order.\n\ + ///\n\ + /// The profile catalogs and the committed row table are typed against this\n\ + /// closed vocabulary; the wire boundary keeps the string spelling through\n\ + /// [`BrokerOperationName::as_str`].\n\ + ///\n\ + /// A declared-method operation name is lower-kebab and not a valid variant\n\ + /// identifier; its variant mirrors the wire spelling as snake_case, which\n\ + /// the lint allowance below admits.\n\ + #[allow(non_camel_case_types)]\n\ + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n\ + pub enum BrokerOperationName {{\n{0}\ + }}\n\n\ + impl BrokerOperationName {{\n\ + \x20 /// The committed operation name.\n\ + \x20 pub const fn as_str(self) -> &'static str {{\n\ + \x20 match self {{\n{1}\ + \x20 }}\n\ + \x20 }}\n\ + }}\n\n\ /// Every request currently defined by the broker wire. Host mode is closed\n\ /// over this list rather than using an open-ended default.\n\ - pub const HOST_OPERATION_CATALOG: &[&str] = &[\n{}\ + pub const HOST_OPERATION_CATALOG: &[BrokerOperationName] = &[\n{2}\ ];\n\n\ /// Guest-local process and broker lifecycle effects. Host networking,\n\ /// devices, storage, realm, and allocator operations are intentionally\n\ /// absent from this catalog.\n\ - pub const GUEST_OPERATION_CATALOG: &[&str] = &[\n{}\ + pub const GUEST_OPERATION_CATALOG: &[BrokerOperationName] = &[\n{3}\ ];\n", - string_list(profile_catalog(&catalog.rows, "host"), " "), - string_list(profile_catalog(&catalog.rows, "guest"), " "), + variants, + as_str_arms, + operation_list(profile_catalog(&catalog.rows, "host"), " "), + operation_list(profile_catalog(&catalog.rows, "guest"), " "), ) } +/// The generated profile catalog as one `BrokerOperationName` list. +fn operation_list<'a>(items: impl IntoIterator, indent: &str) -> String { + items + .into_iter() + .map(|item| format!("{indent}BrokerOperationName::{},\n", operation_variant(item))) + .collect() +} + fn generate_w3(catalog: &Catalog) -> String { let variants = catalog .rows @@ -875,12 +965,12 @@ fn generate_w3(catalog: &Catalog) -> String { fn generate_authz(catalog: &Catalog) -> String { let mut rows = String::new(); for row in &catalog.rows { - rows.push_str(" row(\n"); - rows.push_str(&format!(" \"{}\",\n", row.operation)); - rows.push_str(&format!(" \"{}\",\n", row.authz.subject)); - rows.push_str(&format!(" \"{}\",\n", row.authz.scope)); + rows.push_str(" OperationAuthzRow {\n"); + rows.push_str(&format!(" operation: \"{}\",\n", row.operation)); + rows.push_str(&format!(" subject: \"{}\",\n", row.authz.subject)); + rows.push_str(&format!(" scope: \"{}\",\n", row.authz.scope)); rows.push_str(&format!( - " &[{}],\n", + " allowed_groups: &[{}],\n", row.authz .allowed_groups .iter() @@ -888,14 +978,23 @@ fn generate_authz(catalog: &Catalog) -> String { .collect::>() .join(", ") )); - rows.push_str(&format!(" {},\n", row.authz.destructive)); - rows.push_str(&format!(" SecretAccess::{},\n", row.authz.secret_access)); rows.push_str(&format!( - " BrokerRequirement::{},\n", + " destructive: Destructive::{},\n", + destructive_variant(row.authz.destructive) + )); + rows.push_str(&format!( + " secret_access: SecretAccess::{},\n", + row.authz.secret_access + )); + rows.push_str(&format!( + " broker_required: BrokerRequirement::{},\n", row.authz.broker_required )); - rows.push_str(&format!(" AuditMode::{},\n", row.authz.audit_mode)); - rows.push_str(" ),\n"); + rows.push_str(&format!( + " audit_mode: AuditMode::{},\n", + row.authz.audit_mode + )); + rows.push_str(" },\n"); } format!( "// {HEADER}\n\n\ @@ -905,6 +1004,16 @@ fn generate_authz(catalog: &Catalog) -> String { ) } +/// The generated `Destructive` variant a committed boolean destructive +/// facet maps to. +fn destructive_variant(destructive: bool) -> &'static str { + if destructive { + "Yes" + } else { + "No" + } +} + fn owner_variant(owner: &str) -> &'static str { match owner { "family" => "OperationOwner::Family", @@ -928,7 +1037,10 @@ fn generate_catalog(catalog: &Catalog) -> String { .collect::>() .join(", "); rows.push_str(" BrokerOperationRow {\n"); - rows.push_str(&format!(" operation: \"{}\",\n", row.operation)); + rows.push_str(&format!( + " operation: BrokerOperationName::{},\n", + operation_variant(&row.operation) + )); rows.push_str(&format!( " wire_variant: {},\n", optional_str(row.wire_variant.as_deref()) @@ -946,7 +1058,10 @@ fn generate_catalog(catalog: &Catalog) -> String { rows.push_str(&format!(" profiles: &[{profiles}],\n")); rows.push_str(&format!(" w3: {},\n", row.w3)); rows.push_str(&format!(" capabilities: {},\n", row.capabilities)); - rows.push_str(&format!(" disposition: \"{}\",\n", row.disposition)); + rows.push_str(&format!( + " disposition: {},\n", + disposition_variant(&row.disposition) + )); rows.push_str(&format!( " stub_target: {},\n", match stub_target_variant(row) { From 6dabfe1322b4e341f9ace23802b6ef24d1e98fe6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 17:58:14 -0700 Subject: [PATCH 610/726] refactor(d2bd-runtime): model ApiReadyTimeout mode as closed ApiReadyMode enum --- changelog.d/w5-19-api-ready-timeout-mode.md | 3 ++ packages/d2bd-runtime/src/daemon_audit.rs | 52 ++++++++++++++++++--- packages/d2bd/src/composition.rs | 4 +- 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 changelog.d/w5-19-api-ready-timeout-mode.md diff --git a/changelog.d/w5-19-api-ready-timeout-mode.md b/changelog.d/w5-19-api-ready-timeout-mode.md new file mode 100644 index 000000000..33c070876 --- /dev/null +++ b/changelog.d/w5-19-api-ready-timeout-mode.md @@ -0,0 +1,3 @@ +### Fixed + +- `DaemonEvent::ApiReadyTimeout.mode` is now a closed two-variant `ApiReadyMode` enum (`Strict` / `NoWaitApi`) with kebab-case serde, so an invalid mode string is rejected on deserialize instead of landing in the preserved audit record; the daemon-events JSONL shape is unchanged (`"strict"` / `"no-wait-api"`). \ No newline at end of file diff --git a/packages/d2bd-runtime/src/daemon_audit.rs b/packages/d2bd-runtime/src/daemon_audit.rs index de22ac3a0..7c99b5458 100644 --- a/packages/d2bd-runtime/src/daemon_audit.rs +++ b/packages/d2bd-runtime/src/daemon_audit.rs @@ -156,6 +156,20 @@ pub enum ResourcePlaneResult { Error, } +/// Split-readiness mode for the api-ready wait phase of a VM start. +/// +/// Closed, two-value state mirroring the run executor's split-readiness +/// mode; serializes to the exact kebab-case strings used by the +/// daemon-events JSONL shape (`"strict"` / `"no-wait-api"`). +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub enum ApiReadyMode { + /// Wait for both process-alive and api-ready; fail-closed on timeout. + Strict, + /// Skip the api-ready probe; pending is expected during cold boot. + NoWaitApi, +} + /// Whether a daemon audit event is part of an operation's authority boundary. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DaemonAuditAuthority { @@ -190,8 +204,8 @@ pub enum DaemonEvent { runner: String, /// Configured timeout that elapsed, in whole seconds. elapsed_secs: u64, - /// Split-readiness mode: `"strict"` or `"no-wait-api"`. - mode: String, + /// Split-readiness mode (serializes as `"strict"` / `"no-wait-api"`). + mode: ApiReadyMode, }, /// Emitted when an authenticated `vm exec` owner session is established /// (after admin authz + capability negotiation, before any op proxy). @@ -1937,7 +1951,7 @@ mod tests { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 60, - mode: "strict".to_owned(), + mode: ApiReadyMode::Strict, }) .expect("write api-ready-timeout event"); @@ -2031,6 +2045,32 @@ mod tests { ); } + #[test] + fn api_ready_mode_roundtrips_and_rejects_invalid_strings() { + // The two closed modes serialize to the legacy JSONL kebab-case + // strings, so the daemon-events shape is unchanged. + assert_eq!( + serde_json::to_string(&ApiReadyMode::Strict).expect("serialize strict"), + "\"strict\"", + ); + assert_eq!( + serde_json::to_string(&ApiReadyMode::NoWaitApi).expect("serialize no-wait-api"), + "\"no-wait-api\"", + ); + assert_eq!( + serde_json::from_str::("\"strict\"").expect("parse strict"), + ApiReadyMode::Strict, + ); + assert_eq!( + serde_json::from_str::("\"no-wait-api\"").expect("parse no-wait-api"), + ApiReadyMode::NoWaitApi, + ); + assert!( + serde_json::from_str::("\"not-a-mode\"").is_err(), + "an unknown mode string must be rejected on deserialize", + ); + } + #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn exec_lifecycle_events_are_leak_safe() { @@ -2373,7 +2413,7 @@ mod tests { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 30, - mode: "strict".to_owned(), + mode: ApiReadyMode::Strict, }) .expect_err("blocked destination must return an io error"); assert_eq!(error.kind(), io::ErrorKind::Other); @@ -2413,7 +2453,7 @@ mod tests { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 30, - mode: "strict".to_owned(), + mode: ApiReadyMode::Strict, }) .expect("no-op write should not error"); @@ -2519,7 +2559,7 @@ mod tests { vm: "vm-a".to_owned(), runner: "ch-runner".to_owned(), elapsed_secs: 60, - mode: "strict".to_owned(), + mode: ApiReadyMode::Strict, }) .await .expect("async best-effort append"); diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..a8cb969e9 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -19467,7 +19467,7 @@ fn dispatch_broker_vm_start_inner( vm: request.vm.clone(), runner: VM_RUNNER_ROLE_ID.to_owned(), elapsed_secs: api_timeout.as_secs(), - mode: "strict".to_owned(), + mode: d2bd_runtime::daemon_audit::ApiReadyMode::Strict, }, ) { tracing::warn!( @@ -28800,7 +28800,7 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), runner: VM_RUNNER_ROLE_ID.to_owned(), elapsed_secs: 120, - mode: "strict".to_owned(), + mode: d2bd_runtime::daemon_audit::ApiReadyMode::Strict, }) .expect("write ApiReadyTimeout audit event"); From d593fa50e5ac7dfef02ec88f2e2a61dde622c065 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:09:32 -0700 Subject: [PATCH 611/726] refactor(d2b-host): enforce the USB busid grammar at the BusId boundary BusId keeps its inner string private, BusId::new validates through media::validate_usb_busid and returns Result, and TryFrom<&str>/as_str carry the typed value; the serde transparent wire shape is unchanged. The broker qemu-media ops and the daemon attach/detach pre-checks stop re-validating the grammar: they convert the wire busid through BusId::try_from once, and the runtime carveout paths build the typed value at the point of use. --- changelog.d/w5-18-busid-invariant.md | 5 ++ packages/d2b-broker/src/ops/media.rs | 14 +++--- packages/d2b-broker/src/ops/nft.rs | 5 +- packages/d2b-broker/src/ops/usbip_firewall.rs | 8 ++-- packages/d2b-broker/src/runtime.rs | 40 +++++++++------- packages/d2b-host/src/nftables.rs | 48 ++++++++++++++----- packages/d2bd/src/composition.rs | 12 ----- 7 files changed, 77 insertions(+), 55 deletions(-) create mode 100644 changelog.d/w5-18-busid-invariant.md diff --git a/changelog.d/w5-18-busid-invariant.md b/changelog.d/w5-18-busid-invariant.md new file mode 100644 index 000000000..28116cb74 --- /dev/null +++ b/changelog.d/w5-18-busid-invariant.md @@ -0,0 +1,5 @@ +### Fixed + +- `d2b_host::nftables::BusId` now enforces the USB busid grammar at the type boundary: the inner `String` is private, `BusId::new` validates via `media::validate_usb_busid` and returns `Result`, and a `TryFrom<&str>` conversion is provided; the `#[serde(transparent)]` wire shape is unchanged. +- Removed the redundant busid re-validation in the broker qemu-media ops (`enroll`, `detach`, and the runtime selector path now convert the wire busid once through `BusId::try_from`) and the daemon-side attach/detach pre-checks; the grammar is enforced once at the type boundary. +- Added `BusId::as_str` for reading the wrapped busid; carveout rendering and all construction sites use the typed value. \ No newline at end of file diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index c6f16377b..4d20fb035 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -51,7 +51,7 @@ static D2BD_GROUP_GID: std::sync::LazyLock, Stri pub enum MediaOpError { /// The media ref failed [`d2b_host::media::validate_media_ref`]. InvalidRef(String), - /// The USB bus id failed [`d2b_host::media::validate_usb_busid`]. + /// The USB bus id failed the [`d2b_host::nftables::BusId`] grammar. InvalidBusId(String), /// The bundle declares no policy for the ref. MissingBundlePolicy, @@ -256,11 +256,11 @@ pub async fn enroll( ) -> Result { d2b_host::media::validate_media_ref(req.media_ref.as_str()) .map_err(|err| MediaOpError::InvalidRef(err.to_string()))?; - d2b_host::media::validate_usb_busid(&req.bus_id) + let bus_id = d2b_host::nftables::BusId::try_from(req.bus_id.as_str()) .map_err(|err| MediaOpError::InvalidBusId(err.to_string()))?; let source = resolve_physical_source(resolver, req.vm_id.as_str(), req.media_ref.as_str())?; let identity = - read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), &req.bus_id).await?; + read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), bus_id.as_str()).await?; preflight_identity_not_busy(Path::new("/sys"), &identity).await?; let access = access_mode(source); let fd = open_block_device(&identity.block_device, access)?; @@ -454,10 +454,10 @@ pub async fn detach( resolver: &BundleResolver, req: &QemuMediaHotplugRequest, ) -> Result { - d2b_host::media::validate_usb_busid(&req.bus_id) + let bus_id = d2b_host::nftables::BusId::try_from(req.bus_id.as_str()) .map_err(|err| MediaOpError::InvalidBusId(err.to_string()))?; let identity = - read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), &req.bus_id).await?; + read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), bus_id.as_str()).await?; let mut client = QmpClient::connect(&qmp_socket_path(req.vm_id.as_str())).await?; let (record, source) = resolve_detach_runtime_selector(resolver, req.vm_id.as_str(), &identity, &mut client) @@ -503,10 +503,10 @@ async fn open_runtime_selector_source<'a>( resolver: &'a BundleResolver, req: &QemuMediaHotplugRequest, ) -> Result, MediaOpError> { - d2b_host::media::validate_usb_busid(&req.bus_id) + let bus_id = d2b_host::nftables::BusId::try_from(req.bus_id.as_str()) .map_err(|err| MediaOpError::InvalidBusId(err.to_string()))?; let identity = - read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), &req.bus_id).await?; + read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), bus_id.as_str()).await?; let (_record, source) = match resolve_runtime_selector(resolver, req.vm_id.as_str(), &identity).await { Ok(pair) => pair, diff --git a/packages/d2b-broker/src/ops/nft.rs b/packages/d2b-broker/src/ops/nft.rs index 82e548dd8..047b9559d 100644 --- a/packages/d2b-broker/src/ops/nft.rs +++ b/packages/d2b-broker/src/ops/nft.rs @@ -929,9 +929,8 @@ mod tests { fn usbip_script() -> (String, String) { let mut batch = build_inet_d2b_chains(); - batch - .add_usbip_carveout(&d2b_host::nftables::BusId::new("1-1.2")) - .expect("carveout"); + let bus_id = d2b_host::nftables::BusId::new("1-1.2").expect("busid"); + batch.add_usbip_carveout(&bus_id).expect("carveout"); let script = batch.render_nft_script(); let hash = batch.canonical_hash().to_string(); (script, hash) diff --git a/packages/d2b-broker/src/ops/usbip_firewall.rs b/packages/d2b-broker/src/ops/usbip_firewall.rs index de68bcf94..69b0220d5 100644 --- a/packages/d2b-broker/src/ops/usbip_firewall.rs +++ b/packages/d2b-broker/src/ops/usbip_firewall.rs @@ -45,7 +45,7 @@ pub fn bind_firewall_rule( Ok(UsbipBindFirewallRuleDecision { batch, audit: UsbipBindFirewallRuleAudit { - busid: bus_id.0.clone(), + busid: bus_id.as_str().to_owned(), rule_hash, }, }) @@ -98,9 +98,10 @@ mod tests { #[test] fn bind_firewall_rule_produces_audit_with_busid_and_hash() { + let bus_id = BusId::new("1-1.4").expect("busid"); let decision = bind_firewall_rule( d2b_host::nftables::build_inet_d2b_chains(), - &BusId::new("1-1.4"), + &bus_id, "iifname \"br-work-up\" tcp dport 3240 accept", ) .unwrap(); @@ -115,9 +116,10 @@ mod tests { #[test] fn carveout_ordering_invariant_via_op() { + let bus_id = BusId::new("2-3.1").expect("busid"); let decision = bind_firewall_rule( d2b_host::nftables::build_inet_d2b_chains(), - &BusId::new("2-3.1"), + &bus_id, "iifname \"br-work-up\" tcp dport 3240 accept", ) .unwrap(); diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index e9597184f..21844990f 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -8645,10 +8645,12 @@ async fn build_usbip_explicit_firewall_decision( let Some(active_firewall) = resolver.find_usbip_firewall_intent(&firewall_id) else { continue; }; + let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( d2b_host::nftables::ChainHook::Input, - &d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()), + &bus_id, active_firewall.nft_rule_body.as_str(), ) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; @@ -8667,10 +8669,12 @@ async fn build_usbip_explicit_firewall_decision( else { continue; }; + let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( d2b_host::nftables::ChainHook::Input, - &d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()), + &bus_id, active_firewall.nft_rule_body.as_str(), ) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; @@ -8685,22 +8689,22 @@ async fn build_usbip_explicit_firewall_decision( if !inserted.insert(carveout_id) { continue; } + let bus_id = d2b_host::nftables::BusId::new(explicit_bus_id.as_str()) + .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( d2b_host::nftables::ChainHook::Input, - &d2b_host::nftables::BusId::new(explicit_bus_id.as_str()), + &bus_id, explicit_rule_body.as_str(), ) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; } // Insert the new explicit carveout last. - crate::ops::usbip_firewall::bind_firewall_rule( - batch, - &d2b_host::nftables::BusId::new(bus_id), - rule_body, - ) - .map_err(|err| BrokerError::LiveHandler(err.to_string())) + let bus_id = d2b_host::nftables::BusId::new(bus_id) + .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; + crate::ops::usbip_firewall::bind_firewall_rule(batch, &bus_id, rule_body) + .map_err(|err| BrokerError::LiveHandler(err.to_string())) } fn runner_role_for_process_role( @@ -10056,10 +10060,12 @@ async fn build_usbip_firewall_decision( intent_id: firewall_id, }); }; + let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( d2b_host::nftables::ChainHook::Input, - &d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()), + &bus_id, active_firewall.nft_rule_body.as_str(), ) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; @@ -10079,21 +10085,21 @@ async fn build_usbip_firewall_decision( intent_id: firewall_id, }); }; + let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( d2b_host::nftables::ChainHook::Input, - &d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()), + &bus_id, active_firewall.nft_rule_body.as_str(), ) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; } - crate::ops::usbip_firewall::bind_firewall_rule( - batch, - &d2b_host::nftables::BusId::new(current.bus_id.as_str()), - current.nft_rule_body.as_str(), - ) - .map_err(|err| BrokerError::LiveHandler(err.to_string())) + let bus_id = d2b_host::nftables::BusId::new(current.bus_id.as_str()) + .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; + crate::ops::usbip_firewall::bind_firewall_rule(batch, &bus_id, current.nft_rule_body.as_str()) + .map_err(|err| BrokerError::LiveHandler(err.to_string())) } #[cfg(not(feature = "layer1-bootstrap"))] diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index 1559e2a0f..1fb9c77d5 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -514,7 +514,7 @@ impl NftBatch { self.add_usbip_carveout_expr( ChainHook::Forward, bus_id, - &format!("meta iifname \"usbip-{bus_id}\" accept", bus_id = bus_id.0), + &format!("meta iifname \"usbip-{bus_id}\" accept", bus_id = bus_id.as_str()), ) } @@ -542,7 +542,7 @@ impl NftBatch { let rule = NftRule { expr: expr.to_owned(), - comment: format!("{}usbip-carveout-{}", NftBatch::COMMENT_PREFIX, bus_id.0), + comment: format!("{}usbip-carveout-{}", NftBatch::COMMENT_PREFIX, bus_id.as_str()), specific_carveout: true, }; @@ -617,16 +617,37 @@ impl NftBatch { } } -/// USBIP busid newtype. The broker re-validates the busid lexical form -/// against the trusted bundle before passing it down here. +/// USBIP busid newtype. The lexical busid grammar +/// ([`crate::media::validate_usb_busid`]) is enforced once here, at the +/// type boundary; consumers never re-validate. #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(transparent)] -pub struct BusId(pub String); +pub struct BusId(String); impl BusId { - /// Wrap one USB busid string. - pub fn new(s: impl Into) -> Self { - Self(s.into()) + /// Validate `s` against the USB busid grammar and wrap it. + /// + /// # Errors + /// + /// Returns [`crate::media::BusIdError`] when `s` is not a valid USB + /// busid. + pub fn new(s: impl Into) -> Result { + let s = s.into(); + crate::media::validate_usb_busid(&s)?; + Ok(Self(s)) + } + + /// Borrow the wrapped busid string. + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl TryFrom<&str> for BusId { + type Error = crate::media::BusIdError; + + fn try_from(value: &str) -> Result { + Self::new(value) } } @@ -1057,7 +1078,8 @@ mod tests { #[test] fn usbip_carveout_inserted_before_generic() { - let batch = add_usbip_firewall_carveout(&BusId::new("1-1.2")).expect("carveout"); + let bus_id = BusId::new("1-1.2").expect("busid"); + let batch = add_usbip_firewall_carveout(&bus_id).expect("carveout"); let forward = batch .chains .iter() @@ -1082,7 +1104,8 @@ mod tests { #[test] fn comment_marker_prefix_on_every_managed_rule() { - let batch = add_usbip_firewall_carveout(&BusId::new("2-1")).expect("carveout"); + let bus_id = BusId::new("2-1").expect("busid"); + let batch = add_usbip_firewall_carveout(&bus_id).expect("carveout"); let forward = batch .chains .iter() @@ -1221,9 +1244,8 @@ mod tests { #[test] fn parse_roundtrips_rendered_script() { let mut batch = build_inet_d2b_chains(); - batch - .add_usbip_carveout(&BusId::new("1-1.2")) - .expect("carveout"); + let bus_id = BusId::new("1-1.2").expect("busid"); + batch.add_usbip_carveout(&bus_id).expect("carveout"); let script = batch.render_nft_script(); let parsed = NftBatch::parse(&script).expect("rendered script parses"); assert_eq!(parsed, batch); diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..3e282dd8e 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -9470,12 +9470,6 @@ fn dispatch_broker_qemu_media_attach( caller_role: BrokerCallerRole, ) -> Result { const VERB: &str = "usb attach"; - if let Err(err) = d2b_host::media::validate_usb_busid(&request.bus_id) { - return Ok(invalid_request_response( - VERB, - format!("invalid USB busid selector: {err}"), - )); - } match dispatch_broker_request_as( state, BrokerRequest::QemuMediaAttach(BrokerQemuMediaHotplugRequest { @@ -9514,12 +9508,6 @@ fn dispatch_broker_qemu_media_detach( caller_role: BrokerCallerRole, ) -> Result { const VERB: &str = "usb detach"; - if let Err(err) = d2b_host::media::validate_usb_busid(&request.bus_id) { - return Ok(invalid_request_response( - VERB, - format!("invalid USB busid selector: {err}"), - )); - } match dispatch_broker_request_as( state, BrokerRequest::QemuMediaDetach(BrokerQemuMediaHotplugRequest { From fa870632031ea07c2ebbf420cba567a1f90318c8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:10:16 -0700 Subject: [PATCH 612/726] refactor(d2b-contracts-provider): drop the declares_state_volume constructor parameter ComponentDescriptor::new cannot declare a state volume (the parameter was only ever false, and true returned MissingRequiredField), so the flag is gone and the constructor starts every descriptor without one. The wire-only declaresStateVolume field and its consistency check against stateNamespaces stay in the Wire struct; the constructor-level assertion that expected the refusal is dropped because the illegal state is no longer expressible. --- changelog.d/w5-17-component-descriptor-new.md | 3 ++ packages/d2b-bus/src/authorization.rs | 1 - packages/d2b-bus/src/session_seam_tests.rs | 1 - .../d2b-contracts-provider/src/v3/provider.rs | 33 +------------------ .../src/controller_assignment.rs | 1 - .../d2b-provider-toolkit/src/base/runtime.rs | 2 -- .../d2b-provider-toolkit/tests/conformance.rs | 1 - .../tests/fake_provider.rs | 1 - .../tests/malicious_provider.rs | 5 --- .../d2b-resource-compiler/tests/phase2.rs | 1 - packages/d2bd-runtime/src/target_runtime.rs | 1 - packages/d2bd/src/provider_registry.rs | 1 - .../d2bd/tests/zone_provider_acceptance.rs | 1 - 13 files changed, 4 insertions(+), 48 deletions(-) create mode 100644 changelog.d/w5-17-component-descriptor-new.md diff --git a/changelog.d/w5-17-component-descriptor-new.md b/changelog.d/w5-17-component-descriptor-new.md new file mode 100644 index 000000000..38a4d05f3 --- /dev/null +++ b/changelog.d/w5-17-component-descriptor-new.md @@ -0,0 +1,3 @@ +### Fixed + +- Removed the `declares_state_volume` parameter from `ComponentDescriptor::new`; the constructor always starts a descriptor without a state volume, and the field is set only through `with_state_namespaces`. The wire-only `declaresStateVolume` field and its consistency check against `stateNamespaces` in the `Deserialize` path are unchanged. \ No newline at end of file diff --git a/packages/d2b-bus/src/authorization.rs b/packages/d2b-bus/src/authorization.rs index 3e6dcd803..d07843a8d 100644 --- a/packages/d2b-bus/src/authorization.rs +++ b/packages/d2b-bus/src/authorization.rs @@ -770,7 +770,6 @@ mod tests { 8, assignment_digest(), [], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { diff --git a/packages/d2b-bus/src/session_seam_tests.rs b/packages/d2b-bus/src/session_seam_tests.rs index c4dbf53dc..4f1f33657 100644 --- a/packages/d2b-bus/src/session_seam_tests.rs +++ b/packages/d2b-bus/src/session_seam_tests.rs @@ -1173,7 +1173,6 @@ fn assignment_manifest() -> ProviderManifest { 1, assignment_digest(), [], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { diff --git a/packages/d2b-contracts-provider/src/v3/provider.rs b/packages/d2b-contracts-provider/src/v3/provider.rs index 1c581b40b..057f415bd 100644 --- a/packages/d2b-contracts-provider/src/v3/provider.rs +++ b/packages/d2b-contracts-provider/src/v3/provider.rs @@ -1372,11 +1372,7 @@ impl ComponentDescriptor { cardinality: u32, config_digest: ArtifactDigest, dependencies: impl IntoIterator, - declares_state_volume: bool, ) -> Result { - if declares_state_volume { - return Err(ProviderContractError::MissingRequiredField); - } let exported_resource_types: BTreeSet<_> = exported_resource_types.into_iter().collect(); let exported_methods: BTreeSet<_> = exported_methods.into_iter().collect(); let allowed_domains: BTreeSet<_> = allowed_domains.into_iter().collect(); @@ -1436,7 +1432,7 @@ impl ComponentDescriptor { target_capabilities: Vec::new(), config_digest, dependencies: dependency_set, - declares_state_volume, + declares_state_volume: false, state_namespaces: Vec::new(), }) } @@ -1724,7 +1720,6 @@ impl<'de> Deserialize<'de> for ComponentDescriptor { wire.cardinality, wire.config_digest, wire.dependencies, - false, ) .map(|descriptor| descriptor.with_execution(execution)) .and_then(|descriptor| { @@ -2873,7 +2868,6 @@ mod tests { alias: DependencyAlias::Volume, required: true, }], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { @@ -3063,7 +3057,6 @@ mod tests { 1, ArtifactDigest::parse(DIGEST_A).unwrap(), [], - false, ) .unwrap(); let controller = controller @@ -3124,7 +3117,6 @@ mod tests { 32, ArtifactDigest::parse(DIGEST_A).unwrap(), [], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { @@ -3449,24 +3441,6 @@ mod tests { #[test] fn declared_state_volume_requires_at_least_one_namespace() { - assert_eq!( - ComponentDescriptor::new( - BoundedToken::parse("volume-controller").unwrap(), - ComponentType::Controller, - [ResourceTypeName::parse("Volume").unwrap()], - [BoundedToken::parse("assess-update").unwrap()], - [ExecutionDomain::System], - 1, - ArtifactDigest::parse(DIGEST_B).unwrap(), - [DependencyDeclaration { - alias: DependencyAlias::Volume, - required: true, - }], - true, - ), - Err(ProviderContractError::MissingRequiredField) - ); - let mut descriptor = controller(); descriptor.declares_state_volume = true; assert_eq!( @@ -3765,7 +3739,6 @@ mod tests { 4, ArtifactDigest::parse(DIGEST_A).unwrap(), dependencies, - false, ) }; assert!(worker(vec![], vec![]).is_ok()); @@ -3793,7 +3766,6 @@ mod tests { 1, ArtifactDigest::parse(DIGEST_A).unwrap(), [], - false, ), Err(ProviderContractError::ConflictingFields) ); @@ -3807,7 +3779,6 @@ mod tests { 1, ArtifactDigest::parse(DIGEST_A).unwrap(), [], - false, ), Err(ProviderContractError::MissingRequiredField) ); @@ -3825,7 +3796,6 @@ mod tests { u32::MAX, ArtifactDigest::parse(DIGEST_A).unwrap(), [], - false, ), Err(ProviderContractError::BoundExceeded) ); @@ -4149,7 +4119,6 @@ mod tests { 1, ArtifactDigest::parse(DIGEST_A).unwrap(), [], - false, ) .unwrap(); let duplicate_controller = duplicate_controller diff --git a/packages/d2b-core-controller/src/controller_assignment.rs b/packages/d2b-core-controller/src/controller_assignment.rs index 23df9bb2f..330a1e862 100644 --- a/packages/d2b-core-controller/src/controller_assignment.rs +++ b/packages/d2b-core-controller/src/controller_assignment.rs @@ -3063,7 +3063,6 @@ mod tests { 8, digest(), [], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { diff --git a/packages/d2b-provider-toolkit/src/base/runtime.rs b/packages/d2b-provider-toolkit/src/base/runtime.rs index 0129b7042..753954d6c 100644 --- a/packages/d2b-provider-toolkit/src/base/runtime.rs +++ b/packages/d2b-provider-toolkit/src/base/runtime.rs @@ -807,7 +807,6 @@ mod tests { 1, digest.clone(), [], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { @@ -1133,7 +1132,6 @@ mod tests { 1, ArtifactDigest::parse(format!("sha256:{}", "b".repeat(64))).unwrap(), [], - false, ) .unwrap(); assert!(matches!( diff --git a/packages/d2b-provider-toolkit/tests/conformance.rs b/packages/d2b-provider-toolkit/tests/conformance.rs index 66fc975ca..65c54f8a4 100644 --- a/packages/d2b-provider-toolkit/tests/conformance.rs +++ b/packages/d2b-provider-toolkit/tests/conformance.rs @@ -238,7 +238,6 @@ fn test_manifest() -> ProviderManifest { 1, digest.clone(), [], - false, ) .expect("valid component") .with_execution(ComponentExecution::Launchable { diff --git a/packages/d2b-provider-toolkit/tests/fake_provider.rs b/packages/d2b-provider-toolkit/tests/fake_provider.rs index 7ef7f0d05..2aac304d3 100644 --- a/packages/d2b-provider-toolkit/tests/fake_provider.rs +++ b/packages/d2b-provider-toolkit/tests/fake_provider.rs @@ -84,7 +84,6 @@ pub fn controller() -> ComponentDescriptor { alias: DependencyAlias::Volume, required: true, }], - false, ) .expect("a controller owning one ResourceType is valid") .with_execution(ComponentExecution::Launchable { diff --git a/packages/d2b-provider-toolkit/tests/malicious_provider.rs b/packages/d2b-provider-toolkit/tests/malicious_provider.rs index 813245605..152827ce3 100644 --- a/packages/d2b-provider-toolkit/tests/malicious_provider.rs +++ b/packages/d2b-provider-toolkit/tests/malicious_provider.rs @@ -77,7 +77,6 @@ fn controller(component_id: &str) -> ComponentDescriptor { 1, ArtifactDigest::parse(DIGEST).expect("valid digest"), [], - false, ) .expect("a controller owning one ResourceType is valid") .with_execution(ComponentExecution::Launchable { @@ -115,7 +114,6 @@ fn controller_for_resource(resource_type: &str) -> ComponentDescriptor { 1, ArtifactDigest::parse(DIGEST).expect("valid digest"), [], - false, ) .expect("a controller owning one ResourceType is valid") .with_execution(ComponentExecution::Launchable { @@ -390,7 +388,6 @@ fn a_worker_cannot_grant_itself_a_dependency_portal_or_a_method_surface() { 1, ArtifactDigest::parse(DIGEST).expect("valid digest"), dependencies, - false, ) }; assert_eq!( @@ -421,7 +418,6 @@ fn a_worker_cannot_grant_itself_a_dependency_portal_or_a_method_surface() { 1, ArtifactDigest::parse(DIGEST).expect("valid digest"), [], - false, ), Err(ProviderContractError::ConflictingFields) ); @@ -848,7 +844,6 @@ fn a_hostile_identifier_never_reaches_a_diagnostic_surface() { 1, ArtifactDigest::parse(DIGEST).expect("valid digest"), [], - false, ) .expect("valid component"); let manifest = manifest_with( diff --git a/packages/d2b-resource-compiler/tests/phase2.rs b/packages/d2b-resource-compiler/tests/phase2.rs index 949f0dd7c..4a94f56b0 100644 --- a/packages/d2b-resource-compiler/tests/phase2.rs +++ b/packages/d2b-resource-compiler/tests/phase2.rs @@ -243,7 +243,6 @@ fn manifest( 1, config_digest.clone(), [], - false, ) .unwrap() .with_execution(execution) diff --git a/packages/d2bd-runtime/src/target_runtime.rs b/packages/d2bd-runtime/src/target_runtime.rs index 90f0c04a7..9cfed301d 100644 --- a/packages/d2bd-runtime/src/target_runtime.rs +++ b/packages/d2bd-runtime/src/target_runtime.rs @@ -2447,7 +2447,6 @@ mod tests { 8, digest.clone(), [], - false, ) .unwrap() .with_execution(d2b_contracts_provider::v3::ComponentExecution::Launchable { diff --git a/packages/d2bd/src/provider_registry.rs b/packages/d2bd/src/provider_registry.rs index 14b3b77c0..e945bd297 100644 --- a/packages/d2bd/src/provider_registry.rs +++ b/packages/d2bd/src/provider_registry.rs @@ -744,7 +744,6 @@ mod tests { 8, digest.clone(), [], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { diff --git a/packages/d2bd/tests/zone_provider_acceptance.rs b/packages/d2bd/tests/zone_provider_acceptance.rs index 99aecefc7..d127fbd0b 100644 --- a/packages/d2bd/tests/zone_provider_acceptance.rs +++ b/packages/d2bd/tests/zone_provider_acceptance.rs @@ -1428,7 +1428,6 @@ fn u4_controller_descriptor() -> ComponentDescriptor { 8, digest.clone(), [], - false, ) .unwrap() .with_execution(ComponentExecution::Launchable { From 7a971ec0bcc78a37954a84f99f1383dc3c512bda Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:13:07 -0700 Subject: [PATCH 613/726] refactor(d2b-provider-device-tpm): run the prepare-state blocking legs on bounded seats prepare_state_dir ran both of its blocking legs inline on the executor worker: the broker `prepare-directory` round trip (blocking seqpacket connect, frame write, reply poll and frame read, bounded by the kernel io budget) and the trusted storage row's `User`/`Group` NSS lookups, reached through row_posture. A slow broker or NSS backend therefore parked the worker for the whole leg. Both legs now run on the bounded seats d2b-core already ships and the process and network families already use: the envelope round trip on kernel_seat::run (the same io budget, unchanged error mapping - a broker transport, protocol or refusal error still fails the preparation closed) and the posture resolution on loader_worker::run_probe (a synchronous posture failure still fails closed). A saturated or absent seat is reported as the retryable transient class instead. spawn_blocking is not used: plan KD2 bans it as the thread-per-call shape, and the seats are the house replacement. The async-gate hatch inventory is refreshed for the line shift of the crate's three recorded test lock sites; no new allow markers. --- changelog.d/w5-28-tpm-blocking-work.md | 12 +++ .../src/effects_service.rs | 96 +++++++++++++------ packages/xtask/data/async-gate-inventory.json | 6 +- 3 files changed, 84 insertions(+), 30 deletions(-) create mode 100644 changelog.d/w5-28-tpm-blocking-work.md diff --git a/changelog.d/w5-28-tpm-blocking-work.md b/changelog.d/w5-28-tpm-blocking-work.md new file mode 100644 index 000000000..c301eeea4 --- /dev/null +++ b/changelog.d/w5-28-tpm-blocking-work.md @@ -0,0 +1,12 @@ +### Fixed + +- Device-TPM state-directory preparation no longer blocks a runtime worker. + Its broker leg - the `prepare-directory` envelope round trip, a blocking + seqpacket connect, frame write, reply poll and frame read bounded by the + existing kernel io budget - now runs on the bounded kernel seat, and the + trusted storage row's `User`/`Group` principal lookups (NSS reads with no + async form) run on the bounded probe seat. A slow or wedged broker or NSS + backend now refuses later seat jobs and is reported as a retryable effect + failure instead of stalling every task scheduled on the worker. The leg's + own error mapping is unchanged: a broker transport, protocol or refusal + error still fails the preparation closed. diff --git a/packages/d2b-provider-device-tpm/src/effects_service.rs b/packages/d2b-provider-device-tpm/src/effects_service.rs index 5485937db..4ba53d3c4 100644 --- a/packages/d2b-provider-device-tpm/src/effects_service.rs +++ b/packages/d2b-provider-device-tpm/src/effects_service.rs @@ -26,6 +26,8 @@ use d2b_contracts::types::{BundleOpId, VmId}; use d2b_contracts_broker::kernel_client::{KernelInvocation, envelope_invoke_kernel}; use d2b_contracts_resource::v3::{ResourceRef, ResourceUid}; use d2b_core::bundle_resolver::BundleResolver; +use d2b_core::kernel_seat; +use d2b_core::loader_worker; use d2b_core::storage::StoragePathSpec; use d2b_core_controller::migration::LegacyTpmMigrationDecision; use d2b_provider_toolkit::{ @@ -436,38 +438,70 @@ impl LiveTpmResourceEffectPort<'_> { let (spec, state_root) = zone_native_swtpm_state_row(&resolver, self.vm_id.as_str()) .ok_or(TpmResourceEffectError::StateIntegrity)?; - let (owner_uid, owner_gid, mode) = row_posture(spec) - .ok_or(TpmResourceEffectError::StateIntegrity)?; + // The row's `User`/`Group` principals resolve through NSS + // lookups, which have no async form, so the whole posture + // resolution runs on the bounded probe seat: a slow or wedged + // backend (LDAP/NIS) refuses later probes rather than parking + // this executor worker for the lookup (`spawn_blocking` is + // banned by plan KD2; the seat is the house replacement). + let (owner_uid, owner_gid, mode) = { + let spec = spec.clone(); + loader_worker::run_probe(move || row_posture(&spec)) + .await + .map_err(|refusal| { + tracing::warn!( + device = %self.device_ref.to_canonical_string(), + error = %refusal, + "tpm prepare: storage-row posture probe refused", + ); + TpmResourceEffectError::Transient + })? + .ok_or(TpmResourceEffectError::StateIntegrity)? + }; (state_root, owner_uid, owner_gid, mode) } }; // The Device row's own Zone - never a zone-authority lookup of the // Guest target VM, which the host daemon's coordinator does not - // register (the guest's plane lives inside the nested VM). - let invocation = KernelInvocation { - operation: "prepare-directory", - zone: self.zone.as_str(), - payload: serde_json::json!({ - "kind": "state", - "baseDir": base_dir.display().to_string(), - "vmIdOrScope": self.vm_id.as_str(), - "mode": mode, - "ownerUid": owner_uid, - "ownerGid": owner_gid, - "createdPaths": [], - }), - fds: &[], - chain_root_invocation_id: None, - chain_identities: None, - }; - match envelope_invoke_kernel( - self.facets.runtime.broker_socket_path(), - self.facets.runtime.kernel_io_timeout(), - self.facets.runtime.caller_role(), - invocation, - ) { - Ok(_) => Ok(()), - Err(error) => { + // register (the guest's plane lives inside the nested VM) - cloned + // for the seat job. + let zone = self.zone.clone(); + let payload = serde_json::json!({ + "kind": "state", + "baseDir": base_dir.display().to_string(), + "vmIdOrScope": self.vm_id.as_str(), + "mode": mode, + "ownerUid": owner_uid, + "ownerGid": owner_gid, + "createdPaths": [], + }); + // The broker round trip is a blocking seqpacket RPC (connect, frame + // write, reply poll, frame read) with no async form in the tree, so + // it runs on the bounded kernel seat under the same io budget: the + // executor worker is never parked for the leg (`spawn_blocking` is + // banned by plan KD2; the seat is the house replacement). + let socket_path = self.facets.runtime.broker_socket_path().to_path_buf(); + let io_timeout = self.facets.runtime.kernel_io_timeout(); + let caller_role = self.facets.runtime.caller_role(); + match kernel_seat::run(move || { + envelope_invoke_kernel( + &socket_path, + io_timeout, + caller_role, + KernelInvocation { + operation: "prepare-directory", + zone: &zone, + payload, + fds: &[], + chain_root_invocation_id: None, + chain_identities: None, + }, + ) + }) + .await + { + Ok(Ok(_)) => Ok(()), + Ok(Err(error)) => { tracing::warn!( device = %self.device_ref.to_canonical_string(), error = %error, @@ -475,6 +509,14 @@ impl LiveTpmResourceEffectPort<'_> { ); Err(TpmResourceEffectError::StateIntegrity) } + Err(refusal) => { + tracing::warn!( + device = %self.device_ref.to_canonical_string(), + error = ?refusal, + "broker state-directory preparation seat refused", + ); + Err(TpmResourceEffectError::Transient) + } } } } diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 0ea2e8078..76c8ca3ed 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -408,17 +408,17 @@ }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 873, + "line": 915, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 882, + "line": 924, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-tpm/src/effects_service.rs", - "line": 895, + "line": 937, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 85cfe8bc1fd1622a29fe7dcf0f93624b93c7e57a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:13:22 -0700 Subject: [PATCH 614/726] refactor(d2b-provider-supervisor): carry the launched-runner snapshot as a named struct --- changelog.d/w5-24-launched-snapshot.md | 7 +++ packages/d2b-provider-process/src/backend.rs | 39 ++++++++++--- packages/d2b-provider-process/src/lib.rs | 2 +- .../d2b-provider-supervisor/src/broker.rs | 33 ++++++----- packages/d2bd/src/process_provider_runtime.rs | 56 ++++++++++--------- 5 files changed, 85 insertions(+), 52 deletions(-) create mode 100644 changelog.d/w5-24-launched-snapshot.md diff --git a/changelog.d/w5-24-launched-snapshot.md b/changelog.d/w5-24-launched-snapshot.md new file mode 100644 index 000000000..d384ade65 --- /dev/null +++ b/changelog.d/w5-24-launched-snapshot.md @@ -0,0 +1,7 @@ +### Changed + +- The Process effect backend's launched-runner snapshot is now the named + `LaunchedSnapshot` carrier (`vm`, `role`, `pid`, `start_time_ticks`, + `pidfd`) instead of a five-element tuple, and the supervisor's + `LaunchedObserver::launched` receives that carrier instead of five + positional parameters. diff --git a/packages/d2b-provider-process/src/backend.rs b/packages/d2b-provider-process/src/backend.rs index b3add3d6b..00372ecca 100644 --- a/packages/d2b-provider-process/src/backend.rs +++ b/packages/d2b-provider-process/src/backend.rs @@ -172,6 +172,33 @@ impl fmt::Debug for BackendLaunch { } } +/// The launch snapshot of one broker-retained runner handle. +/// +/// [`ProcessEffectBackend::launched_runner_snapshot`] reports it so a +/// consumer that learns of a kernel-spawned runner can register that runner +/// (the family handlers' runner lookup) without a second broker round trip: +/// the runner's `(vm, role)` keys, its live `(pid, start_time_ticks)` +/// identity, and an owned duplicate of the retained pidfd. +pub struct LaunchedSnapshot { + /// Broker VM scope the runner was launched under. + pub vm: String, + /// The launched runner's role key, including the resource suffix for a + /// multi-instance role. + pub role: String, + /// Live pid of the launched runner. + pub pid: i32, + /// The kernel start time that pins `pid` to this exact process. + pub start_time_ticks: u64, + /// Owned duplicate of the broker-retained pidfd. + pub pidfd: OwnedFd, +} + +impl fmt::Debug for LaunchedSnapshot { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("LaunchedSnapshot()") + } +} + /// Stop class understood by a blocking process effect owner. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ProcessStopClass { @@ -313,16 +340,14 @@ pub trait ProcessEffectBackend: Send + Sync + 'static { Err(ProcessEffectError::PidfdUnavailable) } - /// The broker-retained launch snapshot of one handle: the runner's - /// `(vm, role)` keys, live `(pid, start_time_ticks)` and a duplicate of - /// the retained pidfd, so the daemon can register the kernel-spawned - /// runner in its authoritative pidfd table (the family handlers' runner - /// lookup). `None` for a backend that retains no pidfd. - #[allow(clippy::type_complexity)] // the launched-runner snapshot tuple is the trait's wire shape + /// The broker-retained launch snapshot of one handle, so the daemon can + /// register the kernel-spawned runner in its authoritative pidfd table + /// (the family handlers' runner lookup). `None` for a backend that + /// retains no pidfd. fn launched_runner_snapshot( &self, _handle: &Self::Handle, - ) -> Result, ProcessEffectError> { + ) -> Result, ProcessEffectError> { Ok(None) } diff --git a/packages/d2b-provider-process/src/lib.rs b/packages/d2b-provider-process/src/lib.rs index ee05ace02..9e1738a8b 100644 --- a/packages/d2b-provider-process/src/lib.rs +++ b/packages/d2b-provider-process/src/lib.rs @@ -31,7 +31,7 @@ pub mod worker_launch; pub mod test_support; pub use backend::{ - BackendLaunch, BackendObservation, ProcessEffectBackend, ProcessEffectError, + BackendLaunch, BackendObservation, LaunchedSnapshot, ProcessEffectBackend, ProcessEffectError, ProcessLaunchRequest, ProcessRequest, ProcessStopClass, }; pub use driver::{ diff --git a/packages/d2b-provider-supervisor/src/broker.rs b/packages/d2b-provider-supervisor/src/broker.rs index a68bea31e..7a549772c 100644 --- a/packages/d2b-provider-supervisor/src/broker.rs +++ b/packages/d2b-provider-supervisor/src/broker.rs @@ -25,9 +25,9 @@ use d2b_core::bundle_resolver::{BundleResolver, intent_id_legacy_runner}; use d2b_core::processes::ProcessRole; use d2b_process_conformance::runtime_scope_commitment; use d2b_provider_process::{ - BackendLaunch, BackendObservation, IdentityBinding, ObservedIdentity, ProcessEffectBackend, - ProcessEffectError, ProcessIdentityDigest, ProcessLaunchRequest, ProcessRequest, - ProcessStopClass, WaitReapOwner, + BackendLaunch, BackendObservation, IdentityBinding, LaunchedSnapshot, ObservedIdentity, + ProcessEffectBackend, ProcessEffectError, ProcessIdentityDigest, ProcessLaunchRequest, + ProcessRequest, ProcessStopClass, WaitReapOwner, }; use rustix::event::{PollFd, PollFlags, poll}; use sha2::{Digest, Sha256}; @@ -947,9 +947,9 @@ impl std::fmt::Debug for BrokerPidfdHandle { /// so the family handlers' runner lookup (ObserveRunner/SignalRunner) sees /// it; registration failure never fails the launch. pub trait LaunchedObserver: Send + Sync { - /// One launched runner's snapshot: `(vm, role, pid, start_time_ticks, - /// pidfd duplicate)`. - fn launched(&self, vm: &str, role: &str, pid: i32, start_time_ticks: u64, pidfd: OwnedFd); + /// One launched runner's snapshot: its `(vm, role)` keys, live + /// `(pid, start_time_ticks)` identity, and owned pidfd duplicate. + fn launched(&self, snapshot: LaunchedSnapshot); } /// Production process backend for existing broker-managed runner roles. @@ -1388,10 +1388,9 @@ impl ProcessEffectBackend for BrokerProcessBackend { // handlers' runner lookup sees the kernel-spawned runner. A // snapshot failure never fails the launch. if let Some(observer) = &self.launched_observer - && let Some((vm, role, pid, start_time_ticks, pidfd_dup)) = - self.launched_runner_snapshot(&handle)? + && let Some(snapshot) = self.launched_runner_snapshot(&handle)? { - observer.launched(&vm, &role, pid, start_time_ticks, pidfd_dup); + observer.launched(snapshot); } Ok(BackendLaunch::new(observation, handle)) } @@ -1495,10 +1494,10 @@ impl ProcessEffectBackend for BrokerProcessBackend { fn launched_runner_snapshot( &self, handle: &Self::Handle, - ) -> Result, ProcessEffectError> { - Ok(Some(( - handle.observed.intent.vm_id.to_string(), - if handle.observed.intent.multi_instance { + ) -> Result, ProcessEffectError> { + Ok(Some(LaunchedSnapshot { + vm: handle.observed.intent.vm_id.to_string(), + role: if handle.observed.intent.multi_instance { format!( "{}@{}", handle.observed.intent.role_id.as_str(), @@ -1507,9 +1506,9 @@ impl ProcessEffectBackend for BrokerProcessBackend { } else { handle.observed.intent.role_id.to_string() }, - handle.observed.pid, - handle.observed.start_time_ticks, - handle.pidfd.try_clone().map_err(|error| { + pid: handle.observed.pid, + start_time_ticks: handle.observed.start_time_ticks, + pidfd: handle.pidfd.try_clone().map_err(|error| { warn!( provider = "supervisor", error = %error, @@ -1517,7 +1516,7 @@ impl ProcessEffectBackend for BrokerProcessBackend { ); ProcessEffectError::PidfdUnavailable })?, - ))) + })) } fn take_controller_bootstrap( diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index e1d7aacdb..f2fac6404 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -37,7 +37,7 @@ use d2b_provider_credential::{ }; use d2b_provider_process::{ CommittedProviderIdentitySource, DeviceWorkerFamily, DeviceWorkerLaunch, ExecutionMode, - GpuWorkerParams, LaunchRow, ProcessFamilySpec, ProcessProviderRuntime, + GpuWorkerParams, LaunchRow, LaunchedSnapshot, ProcessFamilySpec, ProcessProviderRuntime, ProcessResourceContext, ProcessResourceIdentity, ProviderAdoption, ProviderLaunch, ProviderLiveness, ServingWorkerLaunch, ServingWorkerRoot, SwtpmFlushParams, SwtpmWorkerParams, VideoWorkerParams, device_worker_family, device_worker_vm, execution_target_allowed, @@ -749,14 +749,14 @@ struct PidfdTableLaunchedObserver { } impl d2b_provider_supervisor::LaunchedObserver for PidfdTableLaunchedObserver { - fn launched( - &self, - vm: &str, - role: &str, - pid: i32, - start_time_ticks: u64, - pidfd: std::os::fd::OwnedFd, - ) { + fn launched(&self, snapshot: LaunchedSnapshot) { + let LaunchedSnapshot { + vm, + role, + pid, + start_time_ticks, + pidfd, + } = snapshot; // A broker-confirmed spawn proves a live process now owns this // (vm, role). If the slot still holds a STALE entry from a failed // prior launch - the launch-failure cleanup stops the child but @@ -775,19 +775,19 @@ impl d2b_provider_supervisor::LaunchedObserver for PidfdTableLaunchedObserver { // spawn for one broker runner is impossible (the broker's // duplicate-runner guard), and replacing a live entry would orphan // its pidfd. - if self.pidfd_table.contains(vm, role) - && !self.pidfd_table.still_alive_same_start_time(vm, role) + if self.pidfd_table.contains(&vm, &role) + && !self.pidfd_table.still_alive_same_start_time(&vm, &role) { tracing::warn!( vm, role, "pidfd-table: dropping stale entry before relaunched runner registration" ); - self.pidfd_table.deregister(vm, role); + self.pidfd_table.deregister(&vm, &role); } match self.pidfd_table.register( - vm.to_owned(), - role.to_owned(), + vm.clone(), + role.clone(), d2bd_runtime::supervisor::pidfd_table::PidfdEntry { pidfd, pid, @@ -6035,6 +6035,7 @@ mod tests { #[test] fn launched_observer_replaces_stale_pidfd_table_entry_on_relaunch() { + use d2b_provider_process::LaunchedSnapshot; use d2b_provider_supervisor::LaunchedObserver; use d2bd_runtime::supervisor::pidfd_table::PidfdTable; @@ -6065,13 +6066,13 @@ mod tests { }; // The relaunch: a fresh broker-confirmed spawn for the same slot. let live_pid = std::process::id() as i32; - observer.launched( - "host-system", - "controller-stale", - live_pid, - 2, - std::fs::File::open("/dev/null").expect("null").into(), - ); + observer.launched(LaunchedSnapshot { + vm: "host-system".to_owned(), + role: "controller-stale".to_owned(), + pid: live_pid, + start_time_ticks: 2, + pidfd: std::fs::File::open("/dev/null").expect("null").into(), + }); let registration = table .list_for_vm("host-system") .into_iter() @@ -6086,6 +6087,7 @@ mod tests { #[test] fn launched_observer_keeps_a_live_duplicate_slot() { + use d2b_provider_process::LaunchedSnapshot; use d2b_provider_supervisor::LaunchedObserver; use d2bd_runtime::supervisor::pidfd_table::PidfdTable; @@ -6120,13 +6122,13 @@ mod tests { let observer = PidfdTableLaunchedObserver { pidfd_table: Arc::clone(&table), }; - observer.launched( - "host-system", - "controller-live", - live_pid, + observer.launched(LaunchedSnapshot { + vm: "host-system".to_owned(), + role: "controller-live".to_owned(), + pid: live_pid, start_time_ticks, - std::fs::File::open("/dev/null").expect("null").into(), - ); + pidfd: std::fs::File::open("/dev/null").expect("null").into(), + }); let registration = table .list_for_vm("host-system") .into_iter() From 3c229db55151cd33ec8c7bcd5c46a40edc40b5e4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:13:28 -0700 Subject: [PATCH 615/726] refactor(d2b-provider-device): hide the DeviceResourceState caches behind accessors The three provider caches (TPM controllers, GPU controllers, GPU authority leases) are private and read through typed accessors, so the driver crate keeps the GPU authority-lease construction contract; the daemon's shared provider effects migrate all nine read sites to the accessors. --- changelog.d/w5-21-device-state-accessors.md | 3 ++ packages/d2b-provider-device/src/driver.rs | 49 ++++++++++++++++++-- packages/d2bd/src/shared_provider_effects.rs | 18 +++---- 3 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 changelog.d/w5-21-device-state-accessors.md diff --git a/changelog.d/w5-21-device-state-accessors.md b/changelog.d/w5-21-device-state-accessors.md new file mode 100644 index 000000000..c3fd1e958 --- /dev/null +++ b/changelog.d/w5-21-device-state-accessors.md @@ -0,0 +1,3 @@ +### Fixed + +- DeviceResourceState now keeps its three provider caches (TPM controllers, GPU controllers, GPU authority leases) private and exposes read-only typed accessor methods; the daemon's shared provider effects read the caches through the accessors, and the GPU authority-lease construction contract stays behind the driver crate. \ No newline at end of file diff --git a/packages/d2b-provider-device/src/driver.rs b/packages/d2b-provider-device/src/driver.rs index 6397182a7..509c7da87 100644 --- a/packages/d2b-provider-device/src/driver.rs +++ b/packages/d2b-provider-device/src/driver.rs @@ -127,22 +127,65 @@ pub const DEVICE_REGISTRATIONS: [ProviderRow; 4] = [ #[derive(Default)] pub struct DeviceResourceState { /// TPM child-resource controllers (old `tpm_controllers`). - pub tpm_controllers: Arc< + tpm_controllers: Arc< Mutex>, >, /// GPU authority-fenced lifecycle controllers (old `gpu_controllers`). - pub gpu_controllers: + gpu_controllers: Arc>>, /// GPU authority leases (old `gpu_authority_leases`). The GPU port's /// declared construction contract locks this cache with /// `parking_lot::Mutex`, so the driver-owned state uses the same lock. - pub gpu_authority_leases: Arc< + gpu_authority_leases: Arc< parking_lot::Mutex< std::collections::BTreeMap<[u8; 16], d2b_core_controller::authority::AuthorityLease>, >, >, } +impl DeviceResourceState { + /// The TPM child-resource controller cache (old `tpm_controllers`). + /// + /// Read-only access: callers lock the cache to take or store a + /// controller; the cache itself cannot be replaced from outside the + /// driver. + pub fn tpm_controllers( + &self, + ) -> &Arc< + Mutex>, + > { + &self.tpm_controllers + } + + /// The GPU authority-fenced lifecycle controller cache (old + /// `gpu_controllers`). + /// + /// Read-only access: callers lock the cache to take or store a + /// controller; the cache itself cannot be replaced from outside the + /// driver. + pub fn gpu_controllers( + &self, + ) -> &Arc>> + { + &self.gpu_controllers + } + + /// The GPU authority-lease cache (old `gpu_authority_leases`). + /// + /// The GPU port's declared construction contract locks this cache with + /// `parking_lot::Mutex`, so the driver-owned state uses the same lock; + /// the daemon hands the Arc clone to the GPU port unchanged. + pub fn gpu_authority_leases( + &self, + ) -> &Arc< + parking_lot::Mutex< + std::collections::BTreeMap<[u8; 16], d2b_core_controller::authority::AuthorityLease>, + >, + > { + &self.gpu_authority_leases + } +} + /// The Provider effect surface the Device driver needs. /// /// The production implementation owns the daemon-side Provider controllers, diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 1364389fe..f67a918a9 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -1628,7 +1628,7 @@ impl ProductionSharedProviderEffects { })?; let mut controller = { let mut controllers = state - .tpm_controllers + .tpm_controllers() .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held .map_err(|_| SharedProviderEffectError::Unavailable)?; match controllers.remove(&request.uid) { @@ -1676,7 +1676,7 @@ impl ProductionSharedProviderEffects { Ok(outcome) => { { let mut controllers = state - .tpm_controllers + .tpm_controllers() .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held .map_err(|_| SharedProviderEffectError::Unavailable)?; controllers.insert(request.uid.clone(), controller); @@ -1701,7 +1701,7 @@ impl ProductionSharedProviderEffects { Err(error) => { { let mut controllers = state - .tpm_controllers + .tpm_controllers() .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held .map_err(|_| SharedProviderEffectError::Unavailable)?; controllers.insert(request.uid.clone(), controller); @@ -2132,7 +2132,7 @@ impl ProductionSharedProviderEffects { )); } let (_runtime, admission, tokens, settings, holder_ref) = self.gpu_admission(request).await?; - let mut controllers = state.gpu_controllers + let mut controllers = state.gpu_controllers() .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held .map_err(|_| SharedProviderEffectError::Unavailable)?; let mut controller = match controllers.remove(&request.uid) { @@ -2163,7 +2163,7 @@ impl ProductionSharedProviderEffects { d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortArgs::new( d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortDeps::new( Arc::clone(&gpu_facets.runtime), - Arc::clone(&state.gpu_authority_leases), + Arc::clone(state.gpu_authority_leases()), tokio::runtime::Handle::current(), request.children, ), @@ -2521,7 +2521,7 @@ impl ProductionSharedProviderEffects { .map_err(|_| SharedProviderEffectError::Unavailable)?; let mut controller = { let mut controllers = state - .tpm_controllers + .tpm_controllers() .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held .map_err(|_| SharedProviderEffectError::Unavailable)?; controllers @@ -2554,7 +2554,7 @@ impl ProductionSharedProviderEffects { Err(error) => { { let mut controllers = state - .tpm_controllers + .tpm_controllers() .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held .map_err(|_| SharedProviderEffectError::Unavailable)?; controllers.insert(request.uid.clone(), controller); @@ -2610,7 +2610,7 @@ impl ProductionSharedProviderEffects { request: &SharedProviderEffectRequest<'_>, state: &DeviceResourceState, ) -> Result { - let mut controllers = state.gpu_controllers + let mut controllers = state.gpu_controllers() .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held .map_err(|_| SharedProviderEffectError::Unavailable)?; let admission = controllers @@ -2629,7 +2629,7 @@ impl ProductionSharedProviderEffects { d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortArgs::new( d2b_provider_device_gpu::effects_service::DeclaredWorkerGpuPortDeps::new( Arc::clone(&gpu_facets.runtime), - Arc::clone(&state.gpu_authority_leases), + Arc::clone(state.gpu_authority_leases()), tokio::runtime::Handle::current(), request.children, ), From f82fa17c88521c1176ea1978047fc0b1dd49101e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:13:25 -0700 Subject: [PATCH 616/726] refactor(d2b-provider-role): drop the empty test-support feature and its dead gate The manifest declared `[features] test-support = []` while no source file referenced it and no manifest enabled it. The declaration only gave the `registration` integration test a gate that skipped it silently under cargo, because `required-features` named a feature nothing could turn on. - delete the empty `[features] test-support = []` stanza; `rbac` stays public product surface, so nothing moves behind a feature - drop the now-dangling `required-features = ["test-support"]` on the `registration` test target so `cargo test -p d2b-provider-role` runs it - drop the now-dangling `crate_features = ["test-support"]` from the `d2b_provider_role_test_support` rust_library, which stays as the test-support dependency flavor consumed by d2b-resource-api and d2bd Census: no manifest under packages/ enables the feature; the only references were this crate's own manifest, build file, and test target gate. Verification: bazel test //packages/d2b-provider-role:all-tests --cache_test_results=no, 5 of 5 targets pass; cargo test -p d2b-provider-role runs the two rbac unit tests plus the registration test, which the removed gate had skipped. --- changelog.d/w5-23-role-feature-cleanup.md | 7 +++++++ packages/d2b-provider-role/BUILD.bazel | 1 - packages/d2b-provider-role/Cargo.toml | 4 ---- 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 changelog.d/w5-23-role-feature-cleanup.md diff --git a/changelog.d/w5-23-role-feature-cleanup.md b/changelog.d/w5-23-role-feature-cleanup.md new file mode 100644 index 000000000..713620931 --- /dev/null +++ b/changelog.d/w5-23-role-feature-cleanup.md @@ -0,0 +1,7 @@ +### Removed + +- Removed `d2b-provider-role`'s empty `test-support` feature: it gated no code and no manifest enabled it, and `d2b_provider_role::rbac` stays public product surface. + +### Fixed + +- `d2b-provider-role`'s `registration` suite no longer requires that dead feature, so `cargo test -p d2b-provider-role` runs it instead of silently skipping it. diff --git a/packages/d2b-provider-role/BUILD.bazel b/packages/d2b-provider-role/BUILD.bazel index 3722733b6..a8c7c46bc 100644 --- a/packages/d2b-provider-role/BUILD.bazel +++ b/packages/d2b-provider-role/BUILD.bazel @@ -30,7 +30,6 @@ d2b_rust_library( name = "d2b_provider_role_test_support", srcs = glob(["src/**/*.rs"], allow_empty = True), compile_data = ["Cargo.toml"], - crate_features = ["test-support"], crate_name = "d2b_provider_role", deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", diff --git a/packages/d2b-provider-role/Cargo.toml b/packages/d2b-provider-role/Cargo.toml index 2fc6c44ad..20909f730 100644 --- a/packages/d2b-provider-role/Cargo.toml +++ b/packages/d2b-provider-role/Cargo.toml @@ -13,9 +13,6 @@ disallowed_methods = "deny" await_holding_lock = "deny" await_holding_refcell_ref = "deny" -[features] -test-support = [] - [dependencies] d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } @@ -26,4 +23,3 @@ tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [[test]] name = "registration" path = "tests/registration.rs" -required-features = ["test-support"] From 446231def176da4c28ec5900bf09d43853e65c29 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:14:16 -0700 Subject: [PATCH 617/726] fix(d2b-broker-composition): name the operation vocabulary through the broker catalog The composition crate does not depend on d2b-contracts-broker, so the two test modules that construct typed rows cannot import BrokerOperationName from the wire crate. The catalog module owns BrokerOperationRow, so it re-exports the field's type and the tests take it from there. --- packages/d2b-broker-composition/src/routing.rs | 5 ++--- packages/d2b-broker-composition/src/seam.rs | 7 +++---- packages/d2b-broker/src/catalog.rs | 9 +++++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/d2b-broker-composition/src/routing.rs b/packages/d2b-broker-composition/src/routing.rs index 1ee78eaaf..8da4b55a7 100644 --- a/packages/d2b-broker-composition/src/routing.rs +++ b/packages/d2b-broker-composition/src/routing.rs @@ -129,10 +129,9 @@ pub fn catalog_admitted_operations() -> Vec<&'static str> { mod tests { use super::*; use d2b_broker::catalog::{ - AuditMode, BrokerAuthzFacets, BrokerProfileId, BrokerRequirement, CellDurability, - Disposition, OperationOwner, PayloadProvenance, + AuditMode, BrokerAuthzFacets, BrokerOperationName, BrokerProfileId, BrokerRequirement, + CellDurability, Disposition, OperationOwner, PayloadProvenance, }; - use d2b_contracts_broker::broker_wire::BrokerOperationName; /// A minimal pure, generic, provider-declared row (the shape a future /// pure transform will take; the fixture suite uses it as its happy diff --git a/packages/d2b-broker-composition/src/seam.rs b/packages/d2b-broker-composition/src/seam.rs index 20339d5e5..0fff7700c 100644 --- a/packages/d2b-broker-composition/src/seam.rs +++ b/packages/d2b-broker-composition/src/seam.rs @@ -321,11 +321,10 @@ pub struct StateCellHandle<'a> { mod tests { use super::*; use d2b_broker::catalog::{ - AuditMode, BROKER_OPERATION_CATALOG, BrokerAuthzFacets, BrokerProfileId, - BrokerRequirement, CellDurability, DeadlineTier, Disposition, OperationOwner, - PayloadProvenance, SecretAccess, + AuditMode, BROKER_OPERATION_CATALOG, BrokerAuthzFacets, BrokerOperationName, + BrokerProfileId, BrokerRequirement, CellDurability, DeadlineTier, Disposition, + OperationOwner, PayloadProvenance, SecretAccess, }; - use d2b_contracts_broker::broker_wire::BrokerOperationName; use d2b_broker::envelope::{ BrokerEnvelope, CallerAuthority, DispatchFailure, DispatchOutcome, HANDLER_REFUSED, }; diff --git a/packages/d2b-broker/src/catalog.rs b/packages/d2b-broker/src/catalog.rs index ae01b8689..76e43107c 100644 --- a/packages/d2b-broker/src/catalog.rs +++ b/packages/d2b-broker/src/catalog.rs @@ -28,8 +28,7 @@ use std::collections::{BTreeMap, BTreeSet}; use d2b_contracts_broker::broker_wire::{ - BrokerOperationName, BrokerRequest, DEFAULT_CONTEXT_DEADLINE_MS, FdKind, - MAX_CONTEXT_DEADLINE_MS, + BrokerRequest, DEFAULT_CONTEXT_DEADLINE_MS, FdKind, MAX_CONTEXT_DEADLINE_MS, }; use d2b_contracts_resource::v3::{CanonicalJsonObject, CanonicalJsonValue, canonical_json_bytes}; @@ -159,6 +158,12 @@ impl DeadlineTier { } } +/// The operation-name vocabulary the committed row table is typed against. +/// +/// Re-exported here so a consumer that builds a [`BrokerOperationRow`] names +/// the field's type through the module that owns the row. +pub use d2b_contracts_broker::broker_wire::BrokerOperationName; + /// One committed broker operation row. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BrokerOperationRow { From e02b030e17543806c90ec3e4d82d27564539aa99 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:14:16 -0700 Subject: [PATCH 618/726] docs(changelog): drop the fragment title line from the w6-06 entry The changelog parser accepts only ###

headings; the stray H1 made the fragment unparsable. --- changelog.d/w6-06-network-intent-parse-error.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/changelog.d/w6-06-network-intent-parse-error.md b/changelog.d/w6-06-network-intent-parse-error.md index f6579659e..43ce09bc3 100644 --- a/changelog.d/w6-06-network-intent-parse-error.md +++ b/changelog.d/w6-06-network-intent-parse-error.md @@ -1,5 +1,3 @@ -# `w6-06-network-intent-parse-error.md` - ### Fixed - Network spec parse failures in the trusted-bundle network path now surface From f5672d7c9b9c1858e443f78128cf900c8675e188 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:14:27 -0700 Subject: [PATCH 619/726] refactor(d2b-provider-guest-azure-virtual-machine): trim the uncalled controller surface The mutable-update, adoption, and enrollment entry points had no in-tree production caller: the framework Guest adapter drives only reconcile, poll_operation with recovery_state, finalize, and finalizer_installed. Removed AzureVmUpdate, update, adopt, complete_enrollment, status with AzureVmStatus, and controller_execution_ref, plus the state that only served them: the Reconfiguring phase, the pendingUpdate recovery-record field, the identity digest, and the validate_update/apply_update helpers. --- .../w5-22-azure-vm-controller-surface.md | 16 + .../README.md | 9 +- .../src/controller/mod.rs | 314 +----------------- .../src/lib.rs | 4 +- .../tests/error_redaction.rs | 4 +- .../tests/lifecycle_hermetic.rs | 108 +----- 6 files changed, 51 insertions(+), 404 deletions(-) create mode 100644 changelog.d/w5-22-azure-vm-controller-surface.md diff --git a/changelog.d/w5-22-azure-vm-controller-surface.md b/changelog.d/w5-22-azure-vm-controller-surface.md new file mode 100644 index 000000000..48179db8f --- /dev/null +++ b/changelog.d/w5-22-azure-vm-controller-surface.md @@ -0,0 +1,16 @@ +### Removed + +- Removed the Azure VM controller's mutable-update, adoption, and enrollment + surface, which had no in-tree production caller: `AzureVmUpdate`, + `AzureVmController::update`, `AzureVmController::adopt`, + `AzureVmController::complete_enrollment`, `AzureVmController::status` with + the `AzureVmStatus` projection, and `AzureVmController::controller_execution_ref`. + The controller keeps exactly the entry points the framework Guest adapter + drives: `reconcile`, `poll_operation` with `recovery_state`, + `finalize`, and `finalizer_installed`. +- Removed the state that only existed to serve that surface: the + `Reconfiguring` phase, the `pendingUpdate` field of the serialized + `AzureVmRecoveryState` record, the pending-update field of the controller, + and the private `validate_update`/`apply_update` helpers. The recovery + record no longer accepts a reconfiguration phase, and the controller no + longer computes an identity digest that no consumer could read. diff --git a/packages/d2b-provider-guest-azure-virtual-machine/README.md b/packages/d2b-provider-guest-azure-virtual-machine/README.md index 913df1ff8..4f253cf7e 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/README.md +++ b/packages/d2b-provider-guest-azure-virtual-machine/README.md @@ -21,8 +21,8 @@ inside the effect adapter and are represented externally only by digests. ## Controllers / services / workers / binaries `AzureVmController` implements non-blocking LRO provisioning, bootstrap -delivery, restart adoption, and finalization. `BootstrapService` performs the -one-time PSK admission transition to enrolled KK. +delivery, restart adoption on reconcile, and finalization. `BootstrapService` +performs the one-time PSK admission transition to enrolled KK. ## Placement and dependencies @@ -42,8 +42,9 @@ implementations. Bootstrap PSKs are zeroized and single-use. ## State and telemetry -Guest status stores only bounded lifecycle and digest projections. ARM LRO -polling is requeue-driven. +The controller keeps bounded non-secret lifecycle state for restart recovery; +the framework Guest adapter owns the published Guest status. ARM LRO polling is +requeue-driven. ## Build and test diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs index 74f54aa66..56161392f 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs @@ -1,6 +1,6 @@ //! Azure VM lifecycle controller. -use std::{fmt, sync::Arc}; +use std::sync::Arc; use d2b_provider_toolkit::plane::{Clock, SystemClock}; use serde::{Deserialize, Serialize}; @@ -8,7 +8,7 @@ use sha2::{Digest, Sha256}; use crate::{ bootstrap::{BootstrapPsk, BootstrapService, BootstrapServiceState}, - config::{AzureVmConfig, AzureVmGuestSettings, DataDiskSpec}, + config::{AzureVmConfig, AzureVmGuestSettings}, effect::AzureCredentialPort, effect::{ AzureAccessToken, AzureEffectPort, AzureVmHandle, AzureVmState, LroStatus, @@ -36,8 +36,6 @@ pub enum AzureVmPhase { Bootstrapping, /// VM and enrolled KK session are ready. Ready, - /// VM is being reconfigured. - Reconfiguring, /// VM is draining. Draining, /// VM deletion is in progress. @@ -73,32 +71,6 @@ pub enum AzureVmReconcileOutcome { }, } -/// A supported mutable Guest update. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub enum AzureVmUpdate { - /// Resize the VM to a new Azure size SKU. - Resize { - /// New size SKU. - size: d2b_contracts::OpaqueAzureRef, - }, - /// Attach a provider-owned data disk. - AttachDisk { - /// Disk intent. - disk: DataDiskSpec, - }, - /// Detach a provider-owned data disk by LUN. - DetachDisk { - /// Azure LUN. - lun: u8, - }, - /// Replace operator-owned Azure tags. - ReplaceTags { - /// New tag set. - tags: Vec<(String, String)>, - }, -} - /// Non-secret controller state required for restart recovery. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -117,8 +89,6 @@ pub struct AzureVmRecoveryState { pub psk_delivery_attempts: u8, /// Controller-local LRO start time. pub operation_started_at_unix_ms: Option, - /// Pending typed update. - pub pending_update: Option, /// Bootstrap service enrollment state. pub bootstrap_service_state: BootstrapServiceState, /// Whether the one-time bootstrap extension may still contain PSK data. @@ -132,52 +102,8 @@ pub struct AzureVmRecoveryState { pub bootstrap_deadline_failed: bool, } -impl AzureVmUpdate { - fn operation_class(&self) -> &'static str { - match self { - Self::Resize { .. } => "resize", - Self::AttachDisk { .. } => "disk-attach", - Self::DetachDisk { .. } => "disk-detach", - Self::ReplaceTags { .. } => "tags", - } - } -} - -/// Redacted Guest status projection. -#[derive(Clone, PartialEq, Eq)] -pub struct AzureVmStatus { - phase: AzureVmPhase, - identity_digest: Option<[u8; 32]>, -} - -impl AzureVmStatus { - /// Return the current phase. - pub const fn phase(&self) -> AzureVmPhase { - self.phase - } - - /// Return the enrolled identity digest. - pub const fn identity_digest(&self) -> Option<[u8; 32]> { - self.identity_digest - } -} - -impl fmt::Debug for AzureVmStatus { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter - .debug_struct("AzureVmStatus") - .field("phase", &self.phase) - .field( - "identity_digest", - &self.identity_digest.map(|_| ""), - ) - .finish() - } -} - /// Azure VM controller. pub struct AzureVmController { - provider_config: AzureVmConfig, settings: AzureVmGuestSettings, effect: E, credentials: Arc, @@ -186,14 +112,12 @@ pub struct AzureVmController { operation: Option, vm_handle: Option, expected_tag_digest: TagDigest, - identity_digest: Option<[u8; 32]>, bootstrap_psk: Option, bootstrap_service: BootstrapService, pending_delete_operation_id: Option, bootstrap_started_at_unix_ms: Option, psk_delivery_attempts: u8, operation_started_at_unix_ms: Option, - pending_update: Option, clock: Arc, bootstrap_extension_present: bool, child_cleanup_complete: bool, @@ -216,7 +140,6 @@ where settings.validate()?; let expected_tag_digest = TagDigest::from_tags(&settings.azure_tags); Ok(Self { - provider_config, settings, effect, credentials, @@ -225,14 +148,12 @@ where operation: None, vm_handle: None, expected_tag_digest, - identity_digest: None, bootstrap_psk, bootstrap_service: BootstrapService::default(), pending_delete_operation_id: None, bootstrap_started_at_unix_ms: None, psk_delivery_attempts: 0, operation_started_at_unix_ms: None, - pending_update: None, clock: Arc::new(SystemClock), bootstrap_extension_present: false, child_cleanup_complete: false, @@ -262,7 +183,6 @@ where bootstrap_started_at_unix_ms: self.bootstrap_started_at_unix_ms, psk_delivery_attempts: self.psk_delivery_attempts, operation_started_at_unix_ms: self.operation_started_at_unix_ms, - pending_update: self.pending_update.clone(), bootstrap_service_state: self.bootstrap_service.state(), bootstrap_extension_present: self.bootstrap_extension_present, child_cleanup_complete: self.child_cleanup_complete, @@ -282,9 +202,6 @@ where recovery: AzureVmRecoveryState, ) -> Result { if recovery.operation.is_some() != recovery.operation_started_at_unix_ms.is_some() - || (recovery.phase == AzureVmPhase::Reconfiguring - && (recovery.operation.is_none() || recovery.pending_update.is_none())) - || (recovery.pending_update.is_some() && recovery.phase != AzureVmPhase::Reconfiguring) || (matches!( recovery.phase, AzureVmPhase::PskCleaning | AzureVmPhase::ChildCleaning @@ -309,7 +226,6 @@ where self.bootstrap_started_at_unix_ms = recovery.bootstrap_started_at_unix_ms; self.psk_delivery_attempts = recovery.psk_delivery_attempts; self.operation_started_at_unix_ms = recovery.operation_started_at_unix_ms; - self.pending_update = recovery.pending_update; self.bootstrap_service = BootstrapService::from_state(recovery.bootstrap_service_state); self.bootstrap_extension_present = recovery.bootstrap_extension_present; self.child_cleanup_complete = recovery.child_cleanup_complete; @@ -327,14 +243,6 @@ where self.finalizer } - /// Return the redacted status. - pub fn status(&self) -> AzureVmStatus { - AzureVmStatus { - phase: self.phase, - identity_digest: self.identity_digest, - } - } - /// Reconcile without blocking on ARM polling. /// /// # Errors @@ -391,21 +299,18 @@ where Ok(AzureVmReconcileOutcome::Progressing { after_ms: 1_000 }) } AzureVmState::Running => { - let (_, tags) = match self.verify_owned_vm(handle, tags, "reconcile") { - Ok(owned) => owned, - Err(error) => { - if error == AzureVmError::ArmResourceConflict { - self.phase = AzureVmPhase::Failed; - } - return Err(error); + if let Err(error) = self.verify_owned_vm(handle, tags, "reconcile") { + if error == AzureVmError::ArmResourceConflict { + self.phase = AzureVmPhase::Failed; } - }; + return Err(error); + } if self.bootstrap_psk.is_some() && self.bootstrap_service.state() != BootstrapServiceState::Enrolled { self.start_psk_delivery().await } else { - self.ready_if_enrolled(tags).await + self.ready_if_enrolled().await } } AzureVmState::Provisioning => { @@ -429,40 +334,6 @@ where } } - /// Adopt a running VM only when its d2b tag digest matches. - /// - /// # Errors - /// - /// Returns [`AzureVmError::InvalidConfiguration`] when the finalizer is - /// missing, [`AzureVmError::Ambiguous`] when the observed VM identity - /// does not match the tag digest, and the ARM effect variants for - /// retryable and fatal effect failures. - #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] - pub async fn adopt(&mut self) -> Result { - if !self.finalizer { - return Err(AzureVmError::InvalidConfiguration); - } - let token = self.arm_token().await?; - let (state, handle, tags) = self.effect.get_vm_state(&self.settings, &token).await?; - if state != AzureVmState::Running { - tracing::warn!( - state = ?state, - "adoption refused: VM is not running" - ); - return Err(AzureVmError::Transient); - } - let (_, tags) = match self.verify_owned_vm(handle, tags, "adopt") { - Ok(owned) => owned, - Err(error) => { - if error == AzureVmError::ArmResourceConflict { - self.phase = AzureVmPhase::Failed; - } - return Err(error); - } - }; - self.ready_if_enrolled(tags).await - } - /// Advance the current opaque long-running operation. /// /// # Errors @@ -487,7 +358,6 @@ where "long-running operation exceeded maximum age; abandoning" ); self.clear_operation(); - self.pending_update = None; if self.pending_delete_operation_id.is_some() { self.phase = AzureVmPhase::Deleting; return self.start_pending_delete().await; @@ -516,7 +386,6 @@ where return Err(AzureVmError::Ambiguous); } self.clear_operation(); - self.pending_update = None; if self.pending_delete_operation_id.is_some() { self.phase = AzureVmPhase::Deleting; return self.start_pending_delete().await; @@ -580,26 +449,6 @@ where self.phase = AzureVmPhase::Ready; Ok(AzureVmReconcileOutcome::Converged) } - AzureVmPhase::Reconfiguring => { - let update = match self.pending_update.take() { - Some(update) => update, - None => { - tracing::warn!( - "reconfiguration LRO succeeded without pending update" - ); - return Err(AzureVmError::Ambiguous); - } - }; - if let Err(error) = self.apply_update(update) { - tracing::warn!( - code = error.code(), - "applied update rejected during reconfiguration" - ); - return Err(error); - } - self.phase = AzureVmPhase::Ready; - Ok(AzureVmReconcileOutcome::Converged) - } AzureVmPhase::Deleting => self.start_pending_delete().await, AzureVmPhase::ChildCleaning => { self.child_cleanup_complete = true; @@ -614,81 +463,6 @@ where } } - /// Start one typed mutable update without blocking on ARM. - /// - /// # Errors - /// - /// Returns [`AzureVmError::InvalidConfiguration`] when an update is - /// already pending or the finalizer is missing, the validation error - /// when the update contradicts the current VM shape, - /// [`AzureVmError::Ambiguous`] when the owned VM identity is absent, - /// and the ARM effect variants for retryable and fatal failures. - #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] - pub async fn update( - &mut self, - zone_uid: &str, - guest_uid: &str, - generation: u64, - update: AzureVmUpdate, - ) -> Result { - if !matches!(self.phase, AzureVmPhase::Ready) { - tracing::warn!( - zone = %zone_uid, - resource = %guest_uid, - phase = ?self.phase, - "update rejected: VM is not in Ready phase" - ); - return Err(AzureVmError::Transient); - } - if self.operation.is_some() || self.pending_update.is_some() { - tracing::debug!( - zone = %zone_uid, - resource = %guest_uid, - "update deferred while another operation is in flight" - ); - return Ok(AzureVmReconcileOutcome::Progressing { after_ms: 250 }); - } - if let Err(error) = self.validate_update(&update) { - tracing::warn!( - zone = %zone_uid, - resource = %guest_uid, - code = error.code(), - "update rejected: validation failed" - ); - return Err(error); - } - let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?; - let operation_id = - operation_id(zone_uid, guest_uid, generation, update.operation_class()); - let token = self.arm_token().await?; - let operation = match &update { - AzureVmUpdate::Resize { size } => { - self.effect - .start_vm_resize(handle, size.as_str(), &operation_id, &token) - .await? - } - AzureVmUpdate::AttachDisk { disk } => { - self.effect - .start_disk_attach(handle, disk, &operation_id, &token) - .await? - } - AzureVmUpdate::DetachDisk { lun } => { - self.effect - .start_disk_detach(handle, *lun, &operation_id, &token) - .await? - } - AzureVmUpdate::ReplaceTags { tags } => { - self.effect - .update_vm_tags(handle, tags, &operation_id, &token) - .await? - } - }; - self.pending_update = Some(update); - self.set_operation(operation); - self.phase = AzureVmPhase::Reconfiguring; - Ok(AzureVmReconcileOutcome::Progressing { after_ms: 250 }) - } - /// Begin deletion. The finalizer is retained until the LRO succeeds. /// /// # Errors @@ -713,7 +487,6 @@ where }) .clone(); if self.operation.is_some() { - self.pending_update = None; if !matches!( self.phase, AzureVmPhase::PskCleaning | AzureVmPhase::ChildCleaning @@ -765,34 +538,6 @@ where Ok(AzureVmReconcileOutcome::Progressing { after_ms: 1_000 }) } - /// Return the configured gateway execution reference. - pub fn controller_execution_ref(&self) -> &d2b_contracts::ResourceRef { - &self.provider_config.controller_execution_ref - } - - /// Complete one authenticated bootstrap enrollment. - /// - /// # Errors - /// - /// Returns [`AzureVmError::BootstrapFailed`] when the enrollment - /// deadline elapsed, and the bootstrap admission variants - /// (`BootstrapPskExpired`, `BootstrapPskReplayed`, - /// `BootstrapEnrollmentFailed`) when the presented PSK is refused. - pub fn complete_enrollment( - &mut self, - admission: &mut crate::bootstrap::BootstrapAdmission, - presented: &[u8], - now_unix_ms: u64, - ) -> Result<(), AzureVmError> { - if self.bootstrap_started_at_unix_ms.is_some_and(|started| { - now_unix_ms.saturating_sub(started) >= self.settings.bootstrap_deadline_ms - }) { - return Err(AzureVmError::BootstrapFailed); - } - self.bootstrap_service - .complete_enrollment(admission, presented, now_unix_ms) - } - async fn start_psk_delivery(&mut self) -> Result { let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?; let started = *self @@ -831,10 +576,7 @@ where Ok(AzureVmReconcileOutcome::Progressing { after_ms: 250 }) } - async fn ready_if_enrolled( - &mut self, - tags: TagDigest, - ) -> Result { + async fn ready_if_enrolled(&mut self) -> Result { if self.bootstrap_service.state() != BootstrapServiceState::Enrolled { let started = *self .bootstrap_started_at_unix_ms @@ -852,7 +594,6 @@ where } return Err(AzureVmError::BootstrapFailed); } - self.identity_digest = None; self.phase = AzureVmPhase::Bootstrapping; return Ok(AzureVmReconcileOutcome::Retry { after_ms: 1_000 }); } @@ -861,7 +602,6 @@ where } self.bootstrap_psk = None; self.phase = AzureVmPhase::Ready; - self.identity_digest = Some(Sha256::digest(tags.as_bytes()).into()); Ok(AzureVmReconcileOutcome::Converged) } @@ -996,42 +736,6 @@ where }) } - fn validate_update(&self, update: &AzureVmUpdate) -> Result<(), AzureVmError> { - match update { - AzureVmUpdate::Resize { .. } => {} - AzureVmUpdate::AttachDisk { disk } => { - let mut settings = self.settings.clone(); - settings.data_disks.push(disk.clone()); - settings.validate()?; - } - AzureVmUpdate::DetachDisk { lun } => { - if !self.settings.data_disks.iter().any(|disk| disk.lun == *lun) { - return Err(AzureVmError::InvalidConfiguration); - } - } - AzureVmUpdate::ReplaceTags { tags } => { - let mut settings = self.settings.clone(); - settings.azure_tags = tags.clone(); - settings.validate()?; - } - } - Ok(()) - } - - fn apply_update(&mut self, update: AzureVmUpdate) -> Result<(), AzureVmError> { - match update { -AzureVmUpdate::Resize { size } => self.settings.vm_size = size, - AzureVmUpdate::AttachDisk { disk } => self.settings.data_disks.push(disk), - AzureVmUpdate::DetachDisk { lun } => { - self.settings.data_disks.retain(|disk| disk.lun != lun) - } - AzureVmUpdate::ReplaceTags { tags } => self.settings.azure_tags = tags, - } - self.settings.validate()?; - self.expected_tag_digest = TagDigest::from_tags(&self.settings.azure_tags); - Ok(()) - } - async fn arm_token(&self) -> Result { self.credentials .acquire_token("https://management.azure.com/", 30_000) diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs index dbed1d934..a1a825802 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs @@ -17,8 +17,8 @@ pub use config::{ AzureVmConfig, AzureVmGuestSettings, BootstrapPskDelivery, DataDiskSpec, DiskSku, }; pub use controller::{ - AzureVmController, AzureVmPhase, AzureVmReconcileOutcome, AzureVmRecoveryState, AzureVmStatus, - AzureVmUpdate, AZURE_VM_GUEST_FINALIZER, AZURE_VM_REPAIR_INTERVAL_SECS, + AzureVmController, AzureVmPhase, AzureVmReconcileOutcome, AzureVmRecoveryState, + AZURE_VM_GUEST_FINALIZER, AZURE_VM_REPAIR_INTERVAL_SECS, }; pub use effect::{ AzureAccessToken, AzureCredentialPort, AzureEffectPort, AzureOperationHandle, AzureVmHandle, diff --git a/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs b/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs index 97bff0db4..0fe688ab3 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/tests/error_redaction.rs @@ -1,11 +1,13 @@ use d2b_provider_guest_azure_virtual_machine::{ - AzureOperationHandle, AzureVmError, BootstrapPsk, + AzureOperationHandle, AzureVmError, AzureVmHandle, BootstrapPsk, }; #[test] fn errors_and_handles_do_not_render_remote_values() { let handle = AzureOperationHandle::from_core(b"opaque-operation").unwrap(); assert!(!format!("{:?}", handle).contains("opaque-operation")); + let vm = AzureVmHandle::from_core("opaque-vm").unwrap(); + assert!(!format!("{:?}", vm).contains("opaque-vm")); assert!(!format!("{:?}", BootstrapPsk::from_bytes(b"secret").unwrap()).contains("secret")); assert_eq!( AzureVmError::ArmCredentialDenied.code(), diff --git a/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs b/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs index bd37c9fc2..89cceb9dd 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/tests/lifecycle_hermetic.rs @@ -6,7 +6,7 @@ use d2b_contracts::{OpaqueAzureRef, ResourceRef}; use d2b_provider_guest_azure_virtual_machine::{ AzureAccessToken, AzureCredentialPort, AzureEffectPort, AzureOperationHandle, AzureVmConfig, AzureVmController, AzureVmError, AzureVmGuestSettings, AzureVmHandle, AzureVmPhase, - AzureVmReconcileOutcome, AzureVmRecoveryState, AzureVmState, AzureVmUpdate, BootstrapAdmission, + AzureVmReconcileOutcome, AzureVmRecoveryState, AzureVmState, BootstrapAdmission, BootstrapPsk, BootstrapPskDelivery, BootstrapService, DiskSku, LroStatus, PskExtensionPayload, TagDigest, }; @@ -265,26 +265,6 @@ fn azure_wire_enums_use_adr_values() { ); } -#[test] -fn azure_vm_update_resize_round_trips_with_the_plain_string_wire_shape() { - let update = AzureVmUpdate::Resize { - size: OpaqueAzureRef::parse("standard-d8").unwrap(), - }; - let encoded = serde_json::to_value(&update).unwrap(); - assert_eq!( - encoded, - serde_json::json!({ "resize": { "size": "standard-d8" } }) - ); - assert_eq!( - serde_json::from_value::(encoded).unwrap(), - update - ); - assert!( - serde_json::from_str::(r#"{"resize":{"size":""}}"#).is_err(), - "the size SKU is validated at the deserialization boundary" - ); -} - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn absent_vm_starts_non_blocking_provision() { @@ -425,7 +405,7 @@ async fn recovery_state_restores_opaque_lro_without_secret_material() { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] -async fn restart_adopts_only_tagged_running_vm() { +async fn restart_converges_only_tagged_running_vm() { let (provider, settings) = config(); let state = Arc::new(Mutex::new(FakeState { state: AzureVmState::Running, @@ -440,11 +420,15 @@ async fn restart_adopts_only_tagged_running_vm() { .unwrap() .with_bootstrap_service(enrolled_service()); assert_eq!( - controller.adopt().await.unwrap(), + controller.reconcile("zone", "guest", 1).await.unwrap(), AzureVmReconcileOutcome::Converged ); assert_eq!(controller.phase(), AzureVmPhase::Ready); - assert!(!format!("{:?}", controller.status()).contains("opaque-vm")); + assert_eq!( + state.lock().await.calls, + Vec::<&str>::new(), + "a running tagged VM is converged in place, never provisioned again" + ); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -462,7 +446,7 @@ async fn delete_keeps_finalizer_until_lro_completion() { let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); - controller.adopt().await.unwrap(); + controller.reconcile("zone", "guest", 1).await.unwrap(); assert!(matches!( controller.finalize("zone", "guest", 1).await.unwrap(), AzureVmReconcileOutcome::Progressing { .. } @@ -499,60 +483,14 @@ async fn running_vm_waits_for_authenticated_enrollment() { AzureVmReconcileOutcome::Retry { .. } )); assert_eq!(controller.phase(), AzureVmPhase::Bootstrapping); - assert!(controller.status().identity_digest().is_none()); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] -async fn ready_vm_accepts_typed_resize_and_commits_after_lro() { +async fn failed_lro_honors_pending_delete_intent() { let (provider, settings) = config(); let state = Arc::new(Mutex::new(FakeState { - state: AzureVmState::Running, - handle: Some(AzureVmHandle::from_core("opaque-vm").unwrap()), - tags: Some(expected_tag_digest()), - polls: vec![LroStatus::Succeeded], - ..FakeState::default() - })); - let effect = FakeEffect { - state: Arc::clone(&state), - }; - let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) - .unwrap() - .with_bootstrap_service(enrolled_service()); - controller.adopt().await.unwrap(); - assert!(matches!( - controller - .update( - "zone", - "guest", - 1, - AzureVmUpdate::Resize { - size: OpaqueAzureRef::parse("standard-d8").unwrap(), - }, - ) - .await - .unwrap(), - AzureVmReconcileOutcome::Progressing { .. } - )); - assert_eq!(controller.phase(), AzureVmPhase::Reconfiguring); - assert_eq!( - controller - .poll_operation(AzureOperationHandle::from_core(b"resize").unwrap()) - .await - .unwrap(), - AzureVmReconcileOutcome::Converged - ); - assert_eq!(controller.phase(), AzureVmPhase::Ready); -} - -#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] -#[tokio::test] -async fn failed_update_lro_honors_pending_delete_intent() { - let (provider, settings) = config(); - let state = Arc::new(Mutex::new(FakeState { - state: AzureVmState::Running, - handle: Some(AzureVmHandle::from_core("opaque-vm").unwrap()), - tags: Some(expected_tag_digest()), + state: AzureVmState::Absent, polls: vec![ LroStatus::Succeeded, LroStatus::Succeeded, @@ -566,30 +504,18 @@ async fn failed_update_lro_honors_pending_delete_intent() { let mut controller = AzureVmController::new(provider, settings, effect, credential(), None) .unwrap() .with_bootstrap_service(enrolled_service()); - controller.adopt().await.unwrap(); - controller - .update( - "zone", - "guest", - 1, - AzureVmUpdate::Resize { - size: OpaqueAzureRef::parse("standard-d8").unwrap(), - }, - ) - .await - .unwrap(); + controller.reconcile("zone", "guest", 1).await.unwrap(); controller.finalize("zone", "guest", 2).await.unwrap(); assert_eq!( controller - .poll_operation(AzureOperationHandle::from_core(b"resize").unwrap()) + .poll_operation(AzureOperationHandle::from_core(b"provision").unwrap()) .await .unwrap(), AzureVmReconcileOutcome::Progressing { after_ms: 1_000 } ); assert_eq!(controller.phase(), AzureVmPhase::Deleting); assert!(controller.finalizer_installed()); - assert!(controller.recovery_state().pending_update.is_none()); - assert_eq!(state.lock().await.calls, ["delete"]); + assert_eq!(state.lock().await.calls, ["provision", "delete"]); controller .poll_operation(AzureOperationHandle::from_core(b"delete").unwrap()) .await @@ -623,7 +549,6 @@ async fn restart_with_pending_delete_never_reprovisions_an_absent_vm() { bootstrap_started_at_unix_ms: None, psk_delivery_attempts: 0, operation_started_at_unix_ms: None, - pending_update: None, bootstrap_service_state: BootstrapService::default().state(), bootstrap_extension_present: false, child_cleanup_complete: false, @@ -647,7 +572,7 @@ async fn restart_with_pending_delete_never_reprovisions_an_absent_vm() { #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] -async fn foreign_tags_are_not_adopted() { +async fn foreign_tags_are_not_reconciled() { let (provider, settings) = config(); let state = Arc::new(Mutex::new(FakeState { state: AzureVmState::Running, @@ -660,7 +585,7 @@ async fn foreign_tags_are_not_adopted() { .unwrap() .with_bootstrap_service(enrolled_service()); assert_eq!( - controller.adopt().await.unwrap_err(), + controller.reconcile("zone", "guest", 1).await.unwrap_err(), AzureVmError::ArmResourceConflict ); assert_eq!(controller.phase(), AzureVmPhase::Failed); @@ -866,7 +791,6 @@ async fn bootstrap_deadline_retries_failed_extension_cleanup() { bootstrap_started_at_unix_ms: Some(0), psk_delivery_attempts: 0, operation_started_at_unix_ms: None, - pending_update: None, bootstrap_service_state: BootstrapService::default().state(), bootstrap_extension_present: true, child_cleanup_complete: false, From 4cb0daadb04ae427af1383bdac4d9c434335d4b2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:14:27 -0700 Subject: [PATCH 620/726] refactor(d2b-provider-display-wayland): decode the refresh frame The bridge receive path matched the clipd refresh frame by scanning raw bytes for the literal `"type":"refresh_selection"` substring, so a frame that arrived reformatted (extra whitespace or a different key order) silently disabled clipboard refresh. The receive path now decodes each newline-delimited frame into `BridgeInboundFrame` - the same `type` tag and snake_case variant naming the outbound frame uses, defined next to it in the bridge module - and counts the `RefreshSelection` variant. A frame that does not decode (bad JSON, a truncated write, an unknown `type` tag, or invalid UTF-8) is logged through the existing rate limiter as reason=frame-decode-failed and dropped, so one unreadable frame cannot disable the refresh frames around it, cannot tear the bridge down, and cannot panic. --- changelog.d/w5-27-refresh-frame-typed.md | 11 ++ .../src/wayland_proxy/bridge.rs | 60 ++++++- .../src/wayland_proxy/filter.rs | 149 ++++++++++++++++-- 3 files changed, 202 insertions(+), 18 deletions(-) create mode 100644 changelog.d/w5-27-refresh-frame-typed.md diff --git a/changelog.d/w5-27-refresh-frame-typed.md b/changelog.d/w5-27-refresh-frame-typed.md new file mode 100644 index 000000000..390f56c62 --- /dev/null +++ b/changelog.d/w5-27-refresh-frame-typed.md @@ -0,0 +1,11 @@ +### Fixed + +- The Wayland proxy's clipboard bridge decodes the refresh frame `d2b-clipd` + writes instead of searching the raw byte stream for the literal + `"type":"refresh_selection"` substring. A reformatted frame (extra + whitespace or a different key order) and an unknown `type` tag used to + disable clipboard refresh with no diagnostic; the bridge now deserializes + each newline-delimited frame into the typed inbound frame shape, matches the + `RefreshSelection` variant, and reports a frame it cannot decode through the + rate-limited diagnostics as `reason=frame-decode-failed` while continuing to + serve the refresh frames around it. diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs index 788cdc0ad..9f2e8c98c 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs @@ -15,7 +15,7 @@ use std::{ }; use d2b_contracts::{workload::WorkloadProviderKind, workload_identity::WorkloadTarget}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use crate::wayland_proxy::identity::ProxyIdentity; @@ -381,6 +381,31 @@ fn bridge_frame(metadata: &BridgeTransferMetadata) -> String { encoded } +/// Frames `d2b-clipd` writes back over the bridge socket. +/// +/// The representation mirrors the outbound `Frame` inside [`bridge_frame`] - +/// one `type` tag, snake_case variant names - so both directions of the wire +/// format live in this module. `d2b-clipd` writes +/// `{"type":"refresh_selection"}` and nothing else today; a `type` tag this +/// enum does not name is a decode error rather than a silent no-op, because a +/// silent no-op is exactly how a drifted frame shape used to disable clipboard +/// refresh without a diagnostic. +#[derive(Debug, PartialEq, Eq, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub(crate) enum BridgeInboundFrame { + /// The host selection changed; the proxy re-reads and rebroadcasts it. + RefreshSelection, +} + +/// Decodes one newline-delimited bridge frame. +/// +/// Malformed input (bad JSON, a truncated write, an unknown `type` tag) is +/// returned as an error, never a panic: the receive path logs the failure and +/// keeps reading so one bad frame cannot take the bridge down. +pub(crate) fn decode_bridge_frame(frame: &[u8]) -> Result { + serde_json::from_slice(frame) +} + #[cfg(test)] mod tests { use super::*; @@ -631,4 +656,37 @@ mod tests { assert!(!frame.contains("legacy_vm_name")); assert!(frame.contains("\"mime_type\":\"text/html\"")); } + + #[test] + fn clipd_refresh_frame_decodes_to_refresh_selection() { + // d2b-clipd writes this literal, plus a newline, to every bridge + // stream it holds (packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs). + let frame = br#"{"type":"refresh_selection"}"#; + + assert_eq!( + decode_bridge_frame(frame).expect("refresh frame decodes"), + BridgeInboundFrame::RefreshSelection + ); + // Whitespace and key order belong to the JSON writer, not to the frame + // identity, and a later additive field must not turn the frame into a + // decode failure. + for equivalent in [ + br#"{"type": "refresh_selection"}"#.as_slice(), + br#"{"type":"refresh_selection","source_id":7}"#.as_slice(), + ] { + assert_eq!( + decode_bridge_frame(equivalent).expect("equivalent frame decodes"), + BridgeInboundFrame::RefreshSelection + ); + } + } + + #[test] + fn malformed_bridge_frames_report_decode_errors() { + assert!(decode_bridge_frame(b"{not-json}").is_err()); + // A corrupt stream must surface as an error, not a panic. + assert!(decode_bridge_frame(b"\xff\xfe{").is_err()); + assert!(decode_bridge_frame(br#"{"type":"host_selection_changed"}"#).is_err()); + assert!(decode_bridge_frame(br#"{"refresh_selection":true}"#).is_err()); + } } diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs index b14bc286e..629999ccf 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs @@ -77,8 +77,9 @@ use wl_proxy::{ use crate::wayland_proxy::{ bridge::{ - BridgeConfig, BridgeConnectionState, BridgeHandoff, BridgeReconnectMachine, - BridgeTransferKind, BridgeTransferMetadata, LocalTransferFd, + BridgeConfig, BridgeConnectionState, BridgeHandoff, BridgeInboundFrame, + BridgeReconnectMachine, BridgeTransferKind, BridgeTransferMetadata, LocalTransferFd, + decode_bridge_frame, }, clipboard::{ ClipboardGlobalDisposition, ClipboardMimePolicy, ClipboardRoute, MimeDecision, @@ -801,21 +802,8 @@ impl VirtualClipboardState { } } state.bridge_read_buffer.extend_from_slice(&read_bytes); - while let Some(newline) = state - .bridge_read_buffer - .iter() - .position(|byte| *byte == b'\n') - { - let frame = state - .bridge_read_buffer - .drain(..=newline) - .collect::>(); - if frame - .windows(br#""type":"refresh_selection""#.len()) - .any(|window| window == br#""type":"refresh_selection""#) - { - refresh = true; - } + if state.drain_buffered_bridge_frames() > 0 { + refresh = true; } if state.bridge_read_buffer.len() > 4096 { state.bridge_read_buffer.clear(); @@ -829,6 +817,45 @@ impl VirtualClipboardState { } } + /// Decodes every complete newline-delimited frame already buffered and + /// returns how many of them asked for a selection refresh. + /// + /// A frame that does not decode as a [`BridgeInboundFrame`] - bad JSON, a + /// truncated write, or a `type` tag this side does not know - is logged + /// through the rate limiter and dropped. One unreadable frame must never + /// disable the refresh frames around it and must never tear the bridge + /// down, so the failure stays visible in diagnostics instead of being + /// silently skipped. Bytes after the last newline stay buffered for the + /// next read. + fn drain_buffered_bridge_frames(&mut self) -> usize { + let mut refreshes = 0; + while let Some(newline) = self + .bridge_read_buffer + .iter() + .position(|byte| *byte == b'\n') + { + let decoded = decode_bridge_frame(&self.bridge_read_buffer[..newline]); + self.bridge_read_buffer.drain(..=newline); + match decoded { + Ok(BridgeInboundFrame::RefreshSelection) => refreshes += 1, + Err(error) => { + let identity_label = self.identity_label.clone(); + let error = bounded_error_detail(error.to_string()); + self.diag.borrow_mut().warn( + "clipboard-bridge", + "frame-decode-failed", + || { + format!( + "[d2b-wlproxy] target={identity_label} event=clipboard-bridge reason=frame-decode-failed error={error}" + ) + }, + ); + } + } + } + refreshes + } + fn mark_bridge_disconnected(&mut self) { self.bridge.take(); self.bridge_read_buffer.clear(); @@ -2901,6 +2928,94 @@ mod tests { Rc::new(FilterPolicy::build(PolicyInput::new(local_identity()))) } + fn bridge_diag() -> Rc> { + Rc::new(RefCell::new(DiagRateLimiter::new("work".to_owned()))) + } + + fn bridge_state(diag: Rc>) -> VirtualClipboardState { + VirtualClipboardState::new(local_identity(), diag, disabled_bridge_config()) + } + + #[test] + fn buffered_refresh_frame_is_decoded_and_consumed() { + let mut clipboard = bridge_state(bridge_diag()); + clipboard + .bridge_read_buffer + .extend_from_slice(br#"{"type":"refresh_selection"}"#); + clipboard.bridge_read_buffer.push(b'\n'); + + assert_eq!(clipboard.drain_buffered_bridge_frames(), 1); + assert!(clipboard.bridge_read_buffer.is_empty()); + } + + #[test] + fn refresh_detection_survives_whitespace_key_order_and_extra_fields() { + for frame in [ + br#"{"type": "refresh_selection"}"#.as_slice(), + br#"{ "type" : "refresh_selection" }"#.as_slice(), + br#"{"source_id":7,"type":"refresh_selection"}"#.as_slice(), + br#"{"type":"refresh_selection","source_id":7}"#.as_slice(), + ] { + let mut clipboard = bridge_state(bridge_diag()); + clipboard.bridge_read_buffer.extend_from_slice(frame); + clipboard.bridge_read_buffer.push(b'\n'); + + assert_eq!( + clipboard.drain_buffered_bridge_frames(), + 1, + "{} must decode as a refresh request", + String::from_utf8_lossy(frame) + ); + } + } + + #[test] + fn incomplete_bridge_frame_stays_buffered_until_its_newline_arrives() { + let mut clipboard = bridge_state(bridge_diag()); + clipboard + .bridge_read_buffer + .extend_from_slice(br#"{"type":"refresh_selec"#); + + assert_eq!(clipboard.drain_buffered_bridge_frames(), 0); + assert_eq!( + clipboard.bridge_read_buffer.as_slice(), + br#"{"type":"refresh_selec"# + ); + + clipboard.bridge_read_buffer.extend_from_slice(b"tion\"}\n"); + assert_eq!(clipboard.drain_buffered_bridge_frames(), 1); + assert!(clipboard.bridge_read_buffer.is_empty()); + } + + #[test] + fn unreadable_bridge_frames_are_skipped_without_losing_later_refresh() { + let mut clipboard = bridge_state(bridge_diag()); + clipboard.bridge_read_buffer.extend_from_slice( + b"{not-json}\n{\"type\":\"host_selection_changed\"}\n\ + {\"type\":\"refresh_selection\"}\n", + ); + + assert_eq!(clipboard.drain_buffered_bridge_frames(), 1); + assert!(clipboard.bridge_read_buffer.is_empty()); + } + + #[test] + fn unreadable_bridge_frames_are_diagnosed_through_the_rate_limiter() { + let diag = bridge_diag(); + let mut clipboard = bridge_state(diag.clone()); + let malformed = b"{not-json}\n"; + for _ in 0..6 { + clipboard.bridge_read_buffer.extend_from_slice(malformed); + assert_eq!(clipboard.drain_buffered_bridge_frames(), 0); + } + + assert_eq!( + diag.borrow().suppressed_total_for_tests(), + 1, + "decode failures are logged, so the sixth is rate-limited instead of dropped silently" + ); + } + fn clipboard() -> Rc> { let diag = Rc::new(RefCell::new(DiagRateLimiter::new("work".to_owned()))); Rc::new(RefCell::new(VirtualClipboardState::new( From 98c1b2637d68f69a0c9b5253671590d7022c8786 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:15:21 -0700 Subject: [PATCH 621/726] repo: refresh async-gate inventory for the wave-6 line shifts --- packages/xtask/data/async-gate-inventory.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 0ea2e8078..55bdb28b2 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -123,22 +123,22 @@ }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8154, + "line": 8153, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8221, + "line": 8220, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8438, + "line": 8437, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8515, + "line": 8514, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1078,17 +1078,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10790, + "line": 10810, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26251, + "line": 26271, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26648, + "line": 26668, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 6467d8d2c60f5ff1643f933cbbde8a8ff23228a7 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:18:13 -0700 Subject: [PATCH 622/726] refactor(d2b-contracts): share wire_deserialize! across contract crates The Wire-struct admission shape - a private `#[derive(Deserialize)]` wire struct with `deny_unknown_fields`, then a validated constructor call - was hand-written 72 more times in d2b-contracts-provider and d2b-contracts-resource after the other 28 sites moved behind `wire_deserialize!` inside d2b-contracts-zone-session. Move the macro to d2b-contracts, the contract crate all of them already depend on, and export it, so the contract crates share one definition instead of a crate-local copy. Zone-session imports it from its new home; provider and resource expand it at their 17 and 55 sites. Wire shapes, serde attributes and defaults, and every constructor admission gate stay identical - only the boilerplate goes. Verified with the zone-session, provider, and resource test targets and the provider and resource schema targets; every converted site was diffed against its hand-written attrs, fields, and admission expression. --- changelog.d/w5-29-wire-deserialize-macro.md | 11 + .../src/v3/credential.rs | 261 +++++---- .../d2b-contracts-provider/src/v3/provider.rs | 445 ++++++++------- .../src/v3/provider_registry.rs | 71 ++- .../src/v3/activation_nixos.rs | 47 +- .../d2b-contracts-resource/src/v3/device.rs | 220 ++++---- .../src/v3/execution_policy.rs | 113 ++-- .../d2b-contracts-resource/src/v3/host.rs | 51 +- .../d2b-contracts-resource/src/v3/network.rs | 506 +++++++++--------- .../d2b-contracts-resource/src/v3/process.rs | 473 ++++++++-------- .../d2b-contracts-resource/src/v3/resource.rs | 111 ++-- .../src/v3/resource_status.rs | 303 +++++------ .../d2b-contracts-resource/src/v3/storage.rs | 29 +- .../d2b-contracts-resource/src/v3/user.rs | 29 +- .../d2b-contracts-resource/src/v3/volume.rs | 460 ++++++++-------- .../src/v3/volume_binding.rs | 46 +- .../src/v3/volume_state.rs | 24 +- .../src/v3/emergency_policy.rs | 1 + .../d2b-contracts-zone-session/src/v3/mod.rs | 33 -- .../src/v3/resource_bundle.rs | 1 + .../src/v3/resource_export.rs | 1 + .../src/v3/resource_import.rs | 1 + .../d2b-contracts-zone-session/src/v3/role.rs | 1 + .../src/v3/role_binding.rs | 1 + .../src/v3/services.rs | 1 + .../d2b-contracts-zone-session/src/v3/zone.rs | 1 + .../src/v3/zone_link.rs | 1 + .../src/v3/zone_routing.rs | 1 + packages/d2b-contracts/src/lib.rs | 33 ++ 29 files changed, 1579 insertions(+), 1697 deletions(-) create mode 100644 changelog.d/w5-29-wire-deserialize-macro.md diff --git a/changelog.d/w5-29-wire-deserialize-macro.md b/changelog.d/w5-29-wire-deserialize-macro.md new file mode 100644 index 000000000..68db6f645 --- /dev/null +++ b/changelog.d/w5-29-wire-deserialize-macro.md @@ -0,0 +1,11 @@ +### Changed + +- The `wire_deserialize!` admission-`Deserialize` macro moved from + `d2b-contracts-zone-session` to `d2b-contracts`, the contract crate every + other contract crate already depends on, and is now exported + (`#[macro_export]`) so all of them can share it. Zone-session imports it from + its new home; its 28 Wire shapes are unchanged. +- The 72 hand-written Wire-struct admission `Deserialize` impls in + `d2b-contracts-provider` (17) and `d2b-contracts-resource` (55) now expand the + shared macro. Wire shapes, `serde` attributes and defaults, and every + constructor validation gate are unchanged; only the boilerplate is. diff --git a/packages/d2b-contracts-provider/src/v3/credential.rs b/packages/d2b-contracts-provider/src/v3/credential.rs index 3b47b600b..5def9c773 100644 --- a/packages/d2b-contracts-provider/src/v3/credential.rs +++ b/packages/d2b-contracts-provider/src/v3/credential.rs @@ -15,6 +15,7 @@ use d2b_contracts::foundation_effects::CredentialContractError; pub use d2b_contracts::foundation_effects::{ CredentialLeaseHandle, MAX_AZURE_REF_BYTES, MAX_CREDENTIAL_LEASE_HANDLE_BYTES, OpaqueAzureRef, }; +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize}; use sha2::{Digest, Sha256}; @@ -282,23 +283,21 @@ impl CredentialScope { redacted_debug!(CredentialScope); -impl<'de> Deserialize<'de> for CredentialScope { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - execution_ref: Option, - #[serde(default)] - domain_filter: Option, - #[serde(default)] - user_ref: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.execution_ref, wire.domain_filter, wire.user_ref) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + CredentialScope, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + execution_ref: Option, + #[serde(default)] + domain_filter: Option, + #[serde(default)] + user_ref: Option, + }, + wire, + Self::new(wire.execution_ref, wire.domain_filter, wire.user_ref) + .map_err(serde::de::Error::custom) +); /// Rotation policy class. #[derive( @@ -384,26 +383,24 @@ impl CredentialRotationPolicy { redacted_debug!(CredentialRotationPolicy); -impl<'de> Deserialize<'de> for CredentialRotationPolicy { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - policy: RotationPolicyClass, - #[serde(default)] - proactive_window_ms: Option, - #[serde(default)] - max_lease_lifetime_ms: u64, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.policy, - wire.proactive_window_ms, - wire.max_lease_lifetime_ms, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + CredentialRotationPolicy, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + policy: RotationPolicyClass, + #[serde(default)] + proactive_window_ms: Option, + #[serde(default)] + max_lease_lifetime_ms: u64, + }, + wire, + Self::new( + wire.policy, + wire.proactive_window_ms, + wire.max_lease_lifetime_ms, + ) + .map_err(serde::de::Error::custom) +); /// Compatibility name for the prepared Credential spec field. pub type RotationSpec = CredentialRotationPolicy; @@ -432,18 +429,16 @@ impl ExpirySpec { redacted_debug!(ExpirySpec); -impl<'de> Deserialize<'de> for ExpirySpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - hard_deadline_ms: u64, - } - Self::new(Wire::deserialize(deserializer)?.hard_deadline_ms) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ExpirySpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + hard_deadline_ms: u64, + }, + wire, + Self::new(wire.hard_deadline_ms).map_err(serde::de::Error::custom) +); /// How active leases are treated on a revocation trigger. #[derive( @@ -585,36 +580,34 @@ impl CredentialLeaseStatus { redacted_debug!(CredentialLeaseStatus); -impl<'de> Deserialize<'de> for CredentialLeaseStatus { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - lease_handle: CredentialLeaseHandle, - lease_state: CredentialLeaseState, - rotation_generation: u64, - source_version: CredentialSourceVersion, - expires_at_unix_ms: u64, - issued_at_unix_ms: u64, - last_refreshed_at: Option, - last_rotated_at: Option, - placement_binding: PlacementBinding, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.lease_handle, - wire.lease_state, - wire.rotation_generation, - wire.source_version, - wire.expires_at_unix_ms, - wire.issued_at_unix_ms, - wire.last_refreshed_at, - wire.last_rotated_at, - wire.placement_binding, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + CredentialLeaseStatus, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + lease_handle: CredentialLeaseHandle, + lease_state: CredentialLeaseState, + rotation_generation: u64, + source_version: CredentialSourceVersion, + expires_at_unix_ms: u64, + issued_at_unix_ms: u64, + last_refreshed_at: Option, + last_rotated_at: Option, + placement_binding: PlacementBinding, + }, + wire, + Self::new( + wire.lease_handle, + wire.lease_state, + wire.rotation_generation, + wire.source_version, + wire.expires_at_unix_ms, + wire.issued_at_unix_ms, + wire.last_refreshed_at, + wire.last_rotated_at, + wire.placement_binding, + ) + .map_err(serde::de::Error::custom) +); /// Current state of an optional interactive login ceremony. #[derive( @@ -687,26 +680,24 @@ impl CredentialStatus { redacted_debug!(CredentialStatus); -impl<'de> Deserialize<'de> for CredentialStatus { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - interaction_state: CredentialInteractionState, - login_session_generation: Option, - login_deadline: Option, - credential: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.interaction_state, - wire.login_session_generation, - wire.login_deadline, - wire.credential, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + CredentialStatus, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + interaction_state: CredentialInteractionState, + login_session_generation: Option, + login_deadline: Option, + credential: Option, + }, + wire, + Self::new( + wire.interaction_state, + wire.login_session_generation, + wire.login_deadline, + wire.credential, + ) + .map_err(serde::de::Error::custom) +); /// The Credential ResourceType base spec. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -826,43 +817,41 @@ impl CredentialSpec { redacted_debug!(CredentialSpec); -impl<'de> Deserialize<'de> for CredentialSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - scope: CredentialScope, - audience: AudienceToken, - #[serde(default)] - consumer_ref: Option, - allowed_operations: Vec, - #[serde(default)] - rotation: RotationSpec, - #[serde(default)] - expiry: ExpirySpec, - #[serde(default)] - revocation: RevocationSpec, - #[serde(default)] - identity_guest_ref: Option, - #[serde(default)] - login_endpoint_ref: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.scope, - wire.audience, - wire.consumer_ref, - wire.allowed_operations, - wire.rotation, - wire.expiry, - wire.revocation, - wire.identity_guest_ref, - wire.login_endpoint_ref, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + CredentialSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + scope: CredentialScope, + audience: AudienceToken, + #[serde(default)] + consumer_ref: Option, + allowed_operations: Vec, + #[serde(default)] + rotation: RotationSpec, + #[serde(default)] + expiry: ExpirySpec, + #[serde(default)] + revocation: RevocationSpec, + #[serde(default)] + identity_guest_ref: Option, + #[serde(default)] + login_endpoint_ref: Option, + }, + wire, + Self::new( + wire.scope, + wire.audience, + wire.consumer_ref, + wire.allowed_operations, + wire.rotation, + wire.expiry, + wire.revocation, + wire.identity_guest_ref, + wire.login_endpoint_ref, + ) + .map_err(serde::de::Error::custom) +); #[cfg(test)] mod tests { diff --git a/packages/d2b-contracts-provider/src/v3/provider.rs b/packages/d2b-contracts-provider/src/v3/provider.rs index 1c581b40b..bd290cc56 100644 --- a/packages/d2b-contracts-provider/src/v3/provider.rs +++ b/packages/d2b-contracts-provider/src/v3/provider.rs @@ -34,6 +34,7 @@ use super::semantic_services::{ LEGACY_ABSENT_PROTOCOL_VERSION, SEMANTIC_PROJECTION_PROTOCOL_VERSION, SemanticProjectionProtocolVersion, }; +use d2b_contracts::wire_deserialize; use d2b_contracts_resource::v3::{ ArtifactId, ResourceRef, ResourceTypeName, SchemaFingerprint, execution_policy::{ @@ -360,19 +361,17 @@ impl ProviderSpec { redacted_debug!(ProviderSpec); -impl<'de> Deserialize<'de> for ProviderSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - artifact_id: ArtifactId, - #[serde(default)] - config: CanonicalJsonObject, - } - let wire = Wire::deserialize(deserializer)?; - Ok(Self::new(wire.artifact_id, wire.config)) - } -} +wire_deserialize!( + ProviderSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + artifact_id: ArtifactId, + #[serde(default)] + config: CanonicalJsonObject, + }, + wire, + Ok(Self::new(wire.artifact_id, wire.config)) +); /// Whether a signature over the artifact verified. #[derive( @@ -690,25 +689,23 @@ impl core::fmt::Debug for ComponentTargetCapability { } } -impl<'de> Deserialize<'de> for ComponentTargetCapability { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - target_kind: ControllerTargetKind, - artifact_digest: ArtifactDigest, - #[serde(default)] - required_effect_classes: BTreeSet, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.target_kind, - wire.artifact_digest, - wire.required_effect_classes, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ComponentTargetCapability, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + target_kind: ControllerTargetKind, + artifact_digest: ArtifactDigest, + #[serde(default)] + required_effect_classes: BTreeSet, + }, + wire, + Self::new( + wire.target_kind, + wire.artifact_digest, + wire.required_effect_classes, + ) + .map_err(serde::de::Error::custom) +); /// Shared daemon and broker artifacts selected for one target kind. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -761,20 +758,18 @@ impl core::fmt::Debug for TargetRuntimeArtifacts { } } -impl<'de> Deserialize<'de> for TargetRuntimeArtifacts { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - target_kind: ControllerTargetKind, - d2bd_digest: ArtifactDigest, - broker_digest: ArtifactDigest, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.target_kind, wire.d2bd_digest, wire.broker_digest) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + TargetRuntimeArtifacts, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + target_kind: ControllerTargetKind, + d2bd_digest: ArtifactDigest, + broker_digest: ArtifactDigest, + }, + wire, + Self::new(wire.target_kind, wire.d2bd_digest, wire.broker_digest) + .map_err(serde::de::Error::custom) +); /// The closed dependency alias set a manifest may declare. /// @@ -963,20 +958,17 @@ impl core::fmt::Debug for ComponentStateView { } } -impl<'de> Deserialize<'de> for ComponentStateView { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - path: String, - rights: Vec, - } - - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.path, wire.rights).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ComponentStateView, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + path: String, + rights: Vec, + }, + wire, + Self::new(wire.path, wire.rights).map_err(serde::de::Error::custom) +); /// One state Volume namespace signed into a component descriptor. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -1199,50 +1191,47 @@ impl core::fmt::Debug for ComponentStateNamespace { } } -impl<'de> Deserialize<'de> for ComponentStateNamespace { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - id: BoundedToken, - kind: ComponentStateKind, - schema_id: VolumeStateSchemaId, - schema_version: SchemaVersion, - schema_digest: SchemaFingerprint, - persistence_class: PersistenceClass, - sensitivity_class: SensitivityClass, - migration_policy: MigrationPolicy, - quota_bytes: u64, - #[serde(default)] - storage_need: Option, - sealing_required: bool, - #[serde(default)] - placement_mode: Option, - #[serde(default)] - host_custody_permitted: bool, - views: BTreeMap, - } - - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.id, - wire.kind, - wire.schema_id, - wire.schema_version, - wire.schema_digest, - wire.persistence_class, - wire.sensitivity_class, - wire.migration_policy, - wire.quota_bytes, - wire.storage_need, - wire.sealing_required, - wire.placement_mode, - wire.host_custody_permitted, - wire.views, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ComponentStateNamespace, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + id: BoundedToken, + kind: ComponentStateKind, + schema_id: VolumeStateSchemaId, + schema_version: SchemaVersion, + schema_digest: SchemaFingerprint, + persistence_class: PersistenceClass, + sensitivity_class: SensitivityClass, + migration_policy: MigrationPolicy, + quota_bytes: u64, + #[serde(default)] + storage_need: Option, + sealing_required: bool, + #[serde(default)] + placement_mode: Option, + #[serde(default)] + host_custody_permitted: bool, + views: BTreeMap, + }, + wire, + Self::new( + wire.id, + wire.kind, + wire.schema_id, + wire.schema_version, + wire.schema_digest, + wire.persistence_class, + wire.sensitivity_class, + wire.migration_policy, + wire.quota_bytes, + wire.storage_need, + wire.sealing_required, + wire.placement_mode, + wire.host_custody_permitted, + wire.views, + ) + .map_err(serde::de::Error::custom) +); /// One declared dependency on an alias. /// @@ -1673,36 +1662,36 @@ impl core::fmt::Debug for ComponentDescriptor { } } -impl<'de> Deserialize<'de> for ComponentDescriptor { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - binary_ref: Option, - component_id: BoundedToken, - component_type: ComponentType, - #[serde(default)] - exported_resource_types: BTreeSet, - #[serde(default)] - exported_methods: BTreeSet, - allowed_domains: BTreeSet, - cardinality: u32, - #[serde(default)] - instance_scope: Option, - #[serde(default)] - supported_target_kinds: BTreeSet, - #[serde(default)] - target_capabilities: Vec, - config_digest: ArtifactDigest, - #[serde(default)] - dependencies: BTreeSet, - #[serde(default)] - declares_state_volume: bool, - #[serde(default)] - state_namespaces: Vec, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + ComponentDescriptor, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + binary_ref: Option, + component_id: BoundedToken, + component_type: ComponentType, + #[serde(default)] + exported_resource_types: BTreeSet, + #[serde(default)] + exported_methods: BTreeSet, + allowed_domains: BTreeSet, + cardinality: u32, + #[serde(default)] + instance_scope: Option, + #[serde(default)] + supported_target_kinds: BTreeSet, + #[serde(default)] + target_capabilities: Vec, + config_digest: ArtifactDigest, + #[serde(default)] + dependencies: BTreeSet, + #[serde(default)] + declares_state_volume: bool, + #[serde(default)] + state_namespaces: Vec, + }, + wire, + { let execution = match wire.binary_ref { Some(binary_ref) => ComponentExecution::Launchable { binary_ref }, None => ComponentExecution::InProcessBootstrap, @@ -1740,7 +1729,7 @@ impl<'de> Deserialize<'de> for ComponentDescriptor { .and_then(|descriptor| descriptor.with_state_namespaces(wire.state_namespaces)) .map_err(serde::de::Error::custom) } -} +); /// Whether a Provider supports one optional base capability. #[derive( @@ -2028,40 +2017,38 @@ impl core::fmt::Debug for ResourceApiBinding { } } -impl<'de> Deserialize<'de> for ResourceApiBinding { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - resource_type: ResourceTypeName, - #[serde(default)] - placement_anchor: Option, - base_spec_version: SchemaVersion, - base_spec_fingerprint: SchemaFingerprint, - base_status_version: SchemaVersion, - base_status_fingerprint: SchemaFingerprint, - #[serde(default)] - capability_matrix: StandardCapabilityMatrix, - #[serde(default)] - spec_extension: Option, - #[serde(default)] - status_extension: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new_inner( - wire.resource_type, - wire.placement_anchor, - wire.base_spec_version, - wire.base_spec_fingerprint, - wire.base_status_version, - wire.base_status_fingerprint, - wire.capability_matrix, - wire.spec_extension, - wire.status_extension, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ResourceApiBinding, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + resource_type: ResourceTypeName, + #[serde(default)] + placement_anchor: Option, + base_spec_version: SchemaVersion, + base_spec_fingerprint: SchemaFingerprint, + base_status_version: SchemaVersion, + base_status_fingerprint: SchemaFingerprint, + #[serde(default)] + capability_matrix: StandardCapabilityMatrix, + #[serde(default)] + spec_extension: Option, + #[serde(default)] + status_extension: Option, + }, + wire, + Self::new_inner( + wire.resource_type, + wire.placement_anchor, + wire.base_spec_version, + wire.base_spec_fingerprint, + wire.base_status_version, + wire.base_status_fingerprint, + wire.capability_matrix, + wire.spec_extension, + wire.status_extension, + ) + .map_err(serde::de::Error::custom) +); /// Whether a capability may leave its Zone, and how. #[derive( @@ -2290,35 +2277,33 @@ fn legacy_absent_protocol_version() -> SemanticProjectionProtocolVersion { .expect("the legacy protocol version constant is valid") } -impl<'de> Deserialize<'de> for ProjectionFactory { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - service_type: ResourceTypeName, - binding_type: ResourceTypeName, - #[serde(default = "legacy_absent_protocol_version")] - projection_protocol_version: SemanticProjectionProtocolVersion, - allowed_backing_ref_types: BTreeSet, - allowed_binding_target_ref_types: BTreeSet, - projection_schema_fingerprint: SchemaFingerprint, - factory_fingerprint: SchemaFingerprint, - exportability: Exportability, - } - let wire = Wire::deserialize(deserializer)?; - Self::new_with_protocol_version( - wire.service_type, - wire.binding_type, - wire.projection_protocol_version, - wire.allowed_backing_ref_types, - wire.allowed_binding_target_ref_types, - wire.projection_schema_fingerprint, - wire.factory_fingerprint, - wire.exportability, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ProjectionFactory, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + service_type: ResourceTypeName, + binding_type: ResourceTypeName, + #[serde(default = "legacy_absent_protocol_version")] + projection_protocol_version: SemanticProjectionProtocolVersion, + allowed_backing_ref_types: BTreeSet, + allowed_binding_target_ref_types: BTreeSet, + projection_schema_fingerprint: SchemaFingerprint, + factory_fingerprint: SchemaFingerprint, + exportability: Exportability, + }, + wire, + Self::new_with_protocol_version( + wire.service_type, + wire.binding_type, + wire.projection_protocol_version, + wire.allowed_backing_ref_types, + wire.allowed_binding_target_ref_types, + wire.projection_schema_fingerprint, + wire.factory_fingerprint, + wire.exportability, + ) + .map_err(serde::de::Error::custom) +); fn admit_projection_factory( factory: &ProjectionFactory, @@ -2703,39 +2688,37 @@ impl core::fmt::Debug for ProviderManifest { } } -impl<'de> Deserialize<'de> for ProviderManifest { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - artifact_id: ArtifactId, - digests: ArtifactDigestSet, - trust: TrustEvidence, - compatibility: CompatibilityRange, - components: Vec, - #[serde(default)] - api_bindings: Vec, - #[serde(default)] - projection_factories: Vec, - #[serde(default)] - runtime_artifacts: Vec, - upgrade_policy: UpgradePolicy, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.artifact_id, - wire.digests, - wire.trust, - wire.compatibility, - wire.components, - wire.api_bindings, - wire.projection_factories, - wire.upgrade_policy, - ) - .and_then(|manifest| manifest.with_target_runtime_artifacts(wire.runtime_artifacts)) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ProviderManifest, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + artifact_id: ArtifactId, + digests: ArtifactDigestSet, + trust: TrustEvidence, + compatibility: CompatibilityRange, + components: Vec, + #[serde(default)] + api_bindings: Vec, + #[serde(default)] + projection_factories: Vec, + #[serde(default)] + runtime_artifacts: Vec, + upgrade_policy: UpgradePolicy, + }, + wire, + Self::new( + wire.artifact_id, + wire.digests, + wire.trust, + wire.compatibility, + wire.components, + wire.api_bindings, + wire.projection_factories, + wire.upgrade_policy, + ) + .and_then(|manifest| manifest.with_target_runtime_artifacts(wire.runtime_artifacts)) + .map_err(serde::de::Error::custom) +); /// A Provider method identifier the specification itself names. /// diff --git a/packages/d2b-contracts-provider/src/v3/provider_registry.rs b/packages/d2b-contracts-provider/src/v3/provider_registry.rs index 139272f50..0184a24ea 100644 --- a/packages/d2b-contracts-provider/src/v3/provider_registry.rs +++ b/packages/d2b-contracts-provider/src/v3/provider_registry.rs @@ -4,8 +4,9 @@ //! permits. This module contains only the signed, identity-safe publication //! shape that can cross the v3 Provider service boundary. +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use d2b_contracts_resource::v3::identity::ServiceName; use d2b_contracts_resource::v3::{ @@ -146,30 +147,28 @@ impl ProviderRegistryEntry { redacted_debug!(ProviderRegistryEntry); -impl<'de> Deserialize<'de> for ProviderRegistryEntry { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - provider_ref: ResourceRef, - service: ServiceName, - descriptor_fingerprint: SchemaFingerprint, - provider_generation: ResourceGeneration, - axis: ProviderBindingAxis, - mapping_id: String, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.provider_ref, - wire.service, - wire.descriptor_fingerprint, - wire.provider_generation, - wire.axis, - wire.mapping_id, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ProviderRegistryEntry, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + provider_ref: ResourceRef, + service: ServiceName, + descriptor_fingerprint: SchemaFingerprint, + provider_generation: ResourceGeneration, + axis: ProviderBindingAxis, + mapping_id: String, + }, + wire, + Self::new( + wire.provider_ref, + wire.service, + wire.descriptor_fingerprint, + wire.provider_generation, + wire.axis, + wire.mapping_id, + ) + .map_err(serde::de::Error::custom) +); /// A complete immutable registry publication. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -223,18 +222,16 @@ impl ProviderRegistryPublication { redacted_debug!(ProviderRegistryPublication); -impl<'de> Deserialize<'de> for ProviderRegistryPublication { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - generation: ResourceGeneration, - entries: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.generation, wire.entries).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ProviderRegistryPublication, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + generation: ResourceGeneration, + entries: Vec, + }, + wire, + Self::new(wire.generation, wire.entries).map_err(serde::de::Error::custom) +); #[cfg(test)] mod tests { diff --git a/packages/d2b-contracts-resource/src/v3/activation_nixos.rs b/packages/d2b-contracts-resource/src/v3/activation_nixos.rs index b51a9f8db..51d0d9d1b 100644 --- a/packages/d2b-contracts-resource/src/v3/activation_nixos.rs +++ b/packages/d2b-contracts-resource/src/v3/activation_nixos.rs @@ -5,9 +5,10 @@ use schemars::{ r#gen::SchemaGenerator, schema::{Schema, SchemaObject}, }; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use super::{ArtifactId, ResourceRef, ResourceTypeName, execution_policy::require_execution_ref}; +use d2b_contracts::wire_deserialize; /// The canonical activation generation ResourceType. pub const NIXOS_GENERATION_RESOURCE_TYPE: &str = "activation-nixos.d2bus.org.NixosGeneration"; @@ -246,29 +247,27 @@ impl NixosGenerationSpec { } } -impl<'de> Deserialize<'de> for NixosGenerationSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - provider_ref: ResourceRef, - execution_ref: ResourceRef, - system_artifact_id: String, - activation_mode: ActivationMode, - #[serde(default)] - prior_generation_ref: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.provider_ref, - wire.execution_ref, - wire.system_artifact_id, - wire.activation_mode, - wire.prior_generation_ref, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + NixosGenerationSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + provider_ref: ResourceRef, + execution_ref: ResourceRef, + system_artifact_id: String, + activation_mode: ActivationMode, + #[serde(default)] + prior_generation_ref: Option, + }, + wire, + Self::new( + wire.provider_ref, + wire.execution_ref, + wire.system_artifact_id, + wire.activation_mode, + wire.prior_generation_ref, + ) + .map_err(serde::de::Error::custom) +); /// Typed activation status below the universal ResourceStatus layer. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] diff --git a/packages/d2b-contracts-resource/src/v3/device.rs b/packages/d2b-contracts-resource/src/v3/device.rs index 901e08673..bd8dc1bc6 100644 --- a/packages/d2b-contracts-resource/src/v3/device.rs +++ b/packages/d2b-contracts-resource/src/v3/device.rs @@ -19,6 +19,7 @@ use super::{ BoundedToken, PrimitiveSpecError, parsed_deserialize, redacted_debug, string_schema, }, }; +use d2b_contracts::wire_deserialize; /// The canonical ResourceType name for this module. pub const DEVICE_RESOURCE_TYPE: &str = "Device"; @@ -306,33 +307,33 @@ pub enum InventorySelector { redacted_debug!(InventorySelector); -impl<'de> Deserialize<'de> for InventorySelector { - fn deserialize>(deserializer: D) -> Result { - /// The union of every declared selector field. - /// - /// Serde does not support `deny_unknown_fields` on an internally - /// tagged enum, so the flat union is parsed strictly and every field - /// that does not belong to the selected `busClass` variant is - /// rejected explicitly. - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - bus_class: BusClass, - label: BoundedToken, - #[serde(default)] - vendor_id: Option, - #[serde(default)] - product_id: Option, - #[serde(default)] - serial: Option, - #[serde(default)] - pci_slot: Option, - #[serde(default)] - slot: Option, - #[serde(default)] - index: Option, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + InventorySelector, + /// The union of every declared selector field. + /// + /// Serde does not support `deny_unknown_fields` on an internally + /// tagged enum, so the flat union is parsed strictly and every field + /// that does not belong to the selected `busClass` variant is + /// rejected explicitly. + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + bus_class: BusClass, + label: BoundedToken, + #[serde(default)] + vendor_id: Option, + #[serde(default)] + product_id: Option, + #[serde(default)] + serial: Option, + #[serde(default)] + pci_slot: Option, + #[serde(default)] + slot: Option, + #[serde(default)] + index: Option, + }, + wire, + { let reject = |present: bool| { if present { Err(serde::de::Error::custom( @@ -412,7 +413,7 @@ impl<'de> Deserialize<'de> for InventorySelector { } } } -} +); /// The closed inventory bus-class discriminant. #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] @@ -447,17 +448,16 @@ impl InventorySpec { redacted_debug!(InventorySpec); -impl<'de> Deserialize<'de> for InventorySpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - selector: Option, - } - Ok(Self::new(Wire::deserialize(deserializer)?.selector)) - } -} +wire_deserialize!( + InventorySpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + selector: Option, + }, + wire, + Ok(Self::new(wire.selector)) +); /// The Device ResourceType base spec. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -536,27 +536,25 @@ impl DeviceSpec { redacted_debug!(DeviceSpec); -impl<'de> Deserialize<'de> for DeviceSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - device_class: DeviceClass, - arbitration: DeviceArbitration, - #[serde(default = "one")] - max_concurrent_claims: u32, - inventory: InventorySpec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.device_class, - wire.arbitration, - wire.max_concurrent_claims, - wire.inventory, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + DeviceSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + device_class: DeviceClass, + arbitration: DeviceArbitration, + #[serde(default = "one")] + max_concurrent_claims: u32, + inventory: InventorySpec, + }, + wire, + Self::new( + wire.device_class, + wire.arbitration, + wire.max_concurrent_claims, + wire.inventory, + ) + .map_err(serde::de::Error::custom) +); /// Whether a Device is currently healthy enough for a claimant. #[derive( @@ -647,29 +645,27 @@ impl DeviceClaim { redacted_debug!(DeviceClaim); -impl<'de> Deserialize<'de> for DeviceClaim { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - holder_ref: ResourceRef, - claim: DeviceClaimKind, - #[serde(default)] - passthrough: Option, - claimed_at: Timestamp, - health: DeviceHealth, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.holder_ref, - wire.claim, - wire.passthrough, - wire.claimed_at, - wire.health, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + DeviceClaim, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + holder_ref: ResourceRef, + claim: DeviceClaimKind, + #[serde(default)] + passthrough: Option, + claimed_at: Timestamp, + health: DeviceHealth, + }, + wire, + Self::new( + wire.holder_ref, + wire.claim, + wire.passthrough, + wire.claimed_at, + wire.health, + ) + .map_err(serde::de::Error::custom) +); /// The common Device-specific status resource layer. /// @@ -750,36 +746,34 @@ impl DeviceStatusResource { redacted_debug!(DeviceStatusResource); -impl<'de> Deserialize<'de> for DeviceStatusResource { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - present: Option, - health: DeviceHealth, - holder_refs: Vec, - claims: Vec, - #[serde(default)] - provisioned_at: Option, - #[serde(default)] - last_probed_at: Option, - #[serde(default)] - provider_diagnostic: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.present, - wire.health, - wire.holder_refs, - wire.claims, - wire.provisioned_at, - wire.last_probed_at, - wire.provider_diagnostic, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + DeviceStatusResource, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + present: Option, + health: DeviceHealth, + holder_refs: Vec, + claims: Vec, + #[serde(default)] + provisioned_at: Option, + #[serde(default)] + last_probed_at: Option, + #[serde(default)] + provider_diagnostic: Option, + }, + wire, + Self::new( + wire.present, + wire.health, + wire.holder_refs, + wire.claims, + wire.provisioned_at, + wire.last_probed_at, + wire.provider_diagnostic, + ) + .map_err(serde::de::Error::custom) +); /// Stable Device-specific error codes. #[derive( diff --git a/packages/d2b-contracts-resource/src/v3/execution_policy.rs b/packages/d2b-contracts-resource/src/v3/execution_policy.rs index 0776c7ca4..9c56b6847 100644 --- a/packages/d2b-contracts-resource/src/v3/execution_policy.rs +++ b/packages/d2b-contracts-resource/src/v3/execution_policy.rs @@ -17,6 +17,7 @@ use super::{ ResourceRef, resource_schema::{CanonicalJsonError, CanonicalJsonObject, canonical_json_bytes}, }; +use d2b_contracts::wire_deserialize; #[macro_export] macro_rules! redacted_debug { @@ -721,39 +722,37 @@ impl core::fmt::Debug for BudgetSpec { } } -impl<'de> Deserialize<'de> for BudgetSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - cpu: Option, - #[serde(default)] - memory: Option, - #[serde(default)] - pids: Option, - #[serde(default)] - fds: Option, - #[serde(default)] - io_weight: Option, - #[serde(default)] - network_egress_bps: Option, - #[serde(default)] - thread_limit: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.cpu, - wire.memory, - wire.pids, - wire.fds, - wire.io_weight, - wire.network_egress_bps, - wire.thread_limit, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + BudgetSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + cpu: Option, + #[serde(default)] + memory: Option, + #[serde(default)] + pids: Option, + #[serde(default)] + fds: Option, + #[serde(default)] + io_weight: Option, + #[serde(default)] + network_egress_bps: Option, + #[serde(default)] + thread_limit: Option, + }, + wire, + Self::new( + wire.cpu, + wire.memory, + wire.pids, + wire.fds, + wire.io_weight, + wire.network_egress_bps, + wire.thread_limit, + ) + .map_err(serde::de::Error::custom) +); /// One Network made available to Processes under an execution target. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -786,19 +785,17 @@ impl NetworkAttachment { redacted_debug!(NetworkAttachment); -impl<'de> Deserialize<'de> for NetworkAttachment { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - network_ref: ResourceRef, - #[serde(default)] - default: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.network_ref, wire.default).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + NetworkAttachment, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + network_ref: ResourceRef, + #[serde(default)] + default: bool, + }, + wire, + Self::new(wire.network_ref, wire.default).map_err(serde::de::Error::custom) +); /// One Device made available to Processes under an execution target. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -831,19 +828,17 @@ impl DeviceAttachment { redacted_debug!(DeviceAttachment); -impl<'de> Deserialize<'de> for DeviceAttachment { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - device_ref: ResourceRef, - #[serde(default)] - exclusive: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.device_ref, wire.exclusive).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + DeviceAttachment, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + device_ref: ResourceRef, + #[serde(default)] + exclusive: bool, + }, + wire, + Self::new(wire.device_ref, wire.exclusive).map_err(serde::de::Error::custom) +); /// The shared Host and Guest execution, policy, and budget parent schema. /// diff --git a/packages/d2b-contracts-resource/src/v3/host.rs b/packages/d2b-contracts-resource/src/v3/host.rs index 8c5502981..6751ca238 100644 --- a/packages/d2b-contracts-resource/src/v3/host.rs +++ b/packages/d2b-contracts-resource/src/v3/host.rs @@ -6,7 +6,7 @@ //! `ResourceSpec` and are never restated here. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use super::{ ResourceRef, @@ -16,6 +16,7 @@ use super::{ }, resource_schema::CanonicalJsonObject, }; +use d2b_contracts::wire_deserialize; /// The canonical ResourceType name for this module. pub const HOST_RESOURCE_TYPE: &str = "Host"; @@ -106,29 +107,29 @@ impl HostSpec { redacted_debug!(HostSpec); -impl<'de> Deserialize<'de> for HostSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default = "system_domain")] - default_domain: ExecutionDomain, - #[serde(default = "system_domains")] - allowed_domains: Vec, - #[serde(default)] - default_user_ref: Option, - #[serde(default)] - budget: BudgetSpec, - #[serde(default)] - network_attachments: Vec, - #[serde(default)] - device_attachments: Vec, - #[serde(default)] - volume_attachment_defaults: Vec, - #[serde(default)] - isolation_posture: Option, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + HostSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default = "system_domain")] + default_domain: ExecutionDomain, + #[serde(default = "system_domains")] + allowed_domains: Vec, + #[serde(default)] + default_user_ref: Option, + #[serde(default)] + budget: BudgetSpec, + #[serde(default)] + network_attachments: Vec, + #[serde(default)] + device_attachments: Vec, + #[serde(default)] + volume_attachment_defaults: Vec, + #[serde(default)] + isolation_posture: Option, + }, + wire, + { let policy = ExecutionPolicyWire { default_domain: wire.default_domain, allowed_domains: wire.allowed_domains, @@ -142,7 +143,7 @@ impl<'de> Deserialize<'de> for HostSpec { .map_err(serde::de::Error::custom)?; Self::new(policy, wire.isolation_posture).map_err(serde::de::Error::custom) } -} +); const fn system_domain() -> ExecutionDomain { ExecutionDomain::System diff --git a/packages/d2b-contracts-resource/src/v3/network.rs b/packages/d2b-contracts-resource/src/v3/network.rs index 6a3ba332a..41e987bbb 100644 --- a/packages/d2b-contracts-resource/src/v3/network.rs +++ b/packages/d2b-contracts-resource/src/v3/network.rs @@ -7,7 +7,7 @@ //! Layer 3 `spec.provider` envelope on the universal `ResourceSpec`. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use super::{ IfName, ResourceBundleGenerationId, ResourceGeneration, ResourceRef, ResourceUid, @@ -17,6 +17,7 @@ use super::{ require_execution_ref, string_schema, }, }; +use d2b_contracts::wire_deserialize; /// Immutable Network identity carried through every host effect. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)] @@ -290,21 +291,20 @@ impl Default for RoutingSpec { } } -impl<'de> Deserialize<'de> for RoutingSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - host_blocklist: Option>, - } - match Wire::deserialize(deserializer)?.host_blocklist { - Some(host_blocklist) => Self::new(host_blocklist), - None => Ok(Self::default()), - } - .map_err(serde::de::Error::custom) +wire_deserialize!( + RoutingSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + host_blocklist: Option>, + }, + wire, + match wire.host_blocklist { + Some(host_blocklist) => Self::new(host_blocklist), + None => Ok(Self::default()), } -} + .map_err(serde::de::Error::custom) +); /// DHCP settings for the LAN. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -342,20 +342,18 @@ impl Default for DhcpSpec { redacted_debug!(DhcpSpec); -impl<'de> Deserialize<'de> for DhcpSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - domain: Option, - #[serde(default = "yes")] - ignore_client_names: bool, - } - let wire = Wire::deserialize(deserializer)?; - Ok(Self::new(wire.domain, wire.ignore_client_names)) - } -} +wire_deserialize!( + DhcpSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + domain: Option, + #[serde(default = "yes")] + ignore_client_names: bool, + }, + wire, + Ok(Self::new(wire.domain, wire.ignore_client_names)) +); /// DNS settings for the LAN. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -399,20 +397,18 @@ impl Default for DnsSpec { redacted_debug!(DnsSpec); -impl<'de> Deserialize<'de> for DnsSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - forwarders: Vec, - #[serde(default = "thousand")] - cache_size: u32, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.forwarders, wire.cache_size).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + DnsSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + forwarders: Vec, + #[serde(default = "thousand")] + cache_size: u32, + }, + wire, + Self::new(wire.forwarders, wire.cache_size).map_err(serde::de::Error::custom) +); /// mDNS settings. #[derive(Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)] @@ -466,33 +462,31 @@ impl Default for MdnsSpec { redacted_debug!(MdnsSpec); -impl<'de> Deserialize<'de> for MdnsSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - enable: bool, - #[serde(default = "yes")] - reflector: bool, - #[serde(default)] - dnsmasq_local: bool, - #[serde(default = "mdns_port")] - dnsmasq_local_port: u16, - #[serde(default)] - publish_workstation: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.enable, - wire.reflector, - wire.dnsmasq_local, - wire.dnsmasq_local_port, - wire.publish_workstation, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + MdnsSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + enable: bool, + #[serde(default = "yes")] + reflector: bool, + #[serde(default)] + dnsmasq_local: bool, + #[serde(default = "mdns_port")] + dnsmasq_local_port: u16, + #[serde(default)] + publish_workstation: bool, + }, + wire, + Self::new( + wire.enable, + wire.reflector, + wire.dnsmasq_local, + wire.dnsmasq_local_port, + wire.publish_workstation, + ) + .map_err(serde::de::Error::custom) +); /// External attachment mode. #[derive( @@ -597,25 +591,23 @@ impl ExternalIpv4Spec { redacted_debug!(ExternalIpv4Spec); -impl<'de> Deserialize<'de> for ExternalIpv4Spec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default = "dhcp")] - method: Ipv4Method, - #[serde(default)] - address: Option, - #[serde(default)] - gateway: Option, - #[serde(default)] - dns: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.method, wire.address, wire.gateway, wire.dns) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ExternalIpv4Spec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default = "dhcp")] + method: Ipv4Method, + #[serde(default)] + address: Option, + #[serde(default)] + gateway: Option, + #[serde(default)] + dns: Vec, + }, + wire, + Self::new(wire.method, wire.address, wire.gateway, wire.dns) + .map_err(serde::de::Error::custom) +); /// External egress policy. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -661,23 +653,21 @@ impl Default for EgressSpec { redacted_debug!(EgressSpec); -impl<'de> Deserialize<'de> for EgressSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - enable: bool, - #[serde(default)] - allowed_cidrs: Vec, - #[serde(default = "yes")] - masquerade: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.enable, wire.allowed_cidrs, wire.masquerade) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + EgressSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + enable: bool, + #[serde(default)] + allowed_cidrs: Vec, + #[serde(default = "yes")] + masquerade: bool, + }, + wire, + Self::new(wire.enable, wire.allowed_cidrs, wire.masquerade) + .map_err(serde::de::Error::custom) +); /// Forwarded-port transport protocol. #[derive( @@ -746,33 +736,31 @@ impl PortForwardSpec { redacted_debug!(PortForwardSpec); -impl<'de> Deserialize<'de> for PortForwardSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - protocol: ForwardProtocol, - listen_port: u16, - #[serde(default)] - target_ref: Option, - #[serde(default)] - target_ip: Option, - target_port: u16, - #[serde(default)] - source_cidrs: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.protocol, - wire.listen_port, - wire.target_ref, - wire.target_ip, - wire.target_port, - wire.source_cidrs, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + PortForwardSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + protocol: ForwardProtocol, + listen_port: u16, + #[serde(default)] + target_ref: Option, + #[serde(default)] + target_ip: Option, + target_port: u16, + #[serde(default)] + source_cidrs: Vec, + }, + wire, + Self::new( + wire.protocol, + wire.listen_port, + wire.target_ref, + wire.target_ip, + wire.target_port, + wire.source_cidrs, + ) + .map_err(serde::de::Error::custom) +); /// The optional external physical-NIC attachment. /// @@ -849,41 +837,39 @@ impl ExternalAttachmentSpec { redacted_debug!(ExternalAttachmentSpec); -impl<'de> Deserialize<'de> for ExternalAttachmentSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default = "macvtap")] - mode: ExternalAttachmentMode, - parent_interface: IfName, - #[serde(default = "bridge")] - macvtap_mode: MacvtapMode, - #[serde(default = "exclusive")] - sharing_policy: SharingPolicy, - #[serde(default)] - mac: Option, - #[serde(default)] - ipv4: ExternalIpv4Spec, - #[serde(default)] - egress: EgressSpec, - #[serde(default)] - port_forwards: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.mode, - wire.parent_interface, - wire.macvtap_mode, - wire.sharing_policy, - wire.mac, - wire.ipv4, - wire.egress, - wire.port_forwards, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ExternalAttachmentSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default = "macvtap")] + mode: ExternalAttachmentMode, + parent_interface: IfName, + #[serde(default = "bridge")] + macvtap_mode: MacvtapMode, + #[serde(default = "exclusive")] + sharing_policy: SharingPolicy, + #[serde(default)] + mac: Option, + #[serde(default)] + ipv4: ExternalIpv4Spec, + #[serde(default)] + egress: EgressSpec, + #[serde(default)] + port_forwards: Vec, + }, + wire, + Self::new( + wire.mode, + wire.parent_interface, + wire.macvtap_mode, + wire.sharing_policy, + wire.mac, + wire.ipv4, + wire.egress, + wire.port_forwards, + ) + .map_err(serde::de::Error::custom) +); /// One reserved LAN address and MAC for a Host or Guest. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -927,20 +913,18 @@ impl NetworkAttachmentEntry { redacted_debug!(NetworkAttachmentEntry); -impl<'de> Deserialize<'de> for NetworkAttachmentEntry { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - execution_ref: ResourceRef, - index: u8, - #[serde(default)] - mac: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.execution_ref, wire.index, wire.mac).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + NetworkAttachmentEntry, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + execution_ref: ResourceRef, + index: u8, + #[serde(default)] + mac: Option, + }, + wire, + Self::new(wire.execution_ref, wire.index, wire.mac).map_err(serde::de::Error::custom) +); /// The Network ResourceType base spec. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -1112,54 +1096,52 @@ impl NetworkSpec { redacted_debug!(NetworkSpec); -impl<'de> Deserialize<'de> for NetworkSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - lan_cidr: Ipv4Cidr, - uplink_cidr: Ipv4Cidr, - #[serde(default)] - mtu: Option, - #[serde(default)] - mss_clamp: bool, - #[serde(default)] - isolation: IsolationSpec, - #[serde(default)] - routing: RoutingSpec, - #[serde(default)] - dhcp: DhcpSpec, - #[serde(default)] - dns: DnsSpec, - #[serde(default)] - external_attachment: Option, - #[serde(default)] - mdns: MdnsSpec, - #[serde(default)] - net_vm_name_override: Option, - net_vm_system_artifact_id: BoundedToken, - #[serde(default)] - attachments: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.lan_cidr, - wire.uplink_cidr, - wire.mtu, - wire.mss_clamp, - wire.isolation, - wire.routing, - wire.dhcp, - wire.dns, - wire.external_attachment, - wire.mdns, - wire.net_vm_name_override, - wire.net_vm_system_artifact_id, - wire.attachments, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + NetworkSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + lan_cidr: Ipv4Cidr, + uplink_cidr: Ipv4Cidr, + #[serde(default)] + mtu: Option, + #[serde(default)] + mss_clamp: bool, + #[serde(default)] + isolation: IsolationSpec, + #[serde(default)] + routing: RoutingSpec, + #[serde(default)] + dhcp: DhcpSpec, + #[serde(default)] + dns: DnsSpec, + #[serde(default)] + external_attachment: Option, + #[serde(default)] + mdns: MdnsSpec, + #[serde(default)] + net_vm_name_override: Option, + net_vm_system_artifact_id: BoundedToken, + #[serde(default)] + attachments: Vec, + }, + wire, + Self::new( + wire.lan_cidr, + wire.uplink_cidr, + wire.mtu, + wire.mss_clamp, + wire.isolation, + wire.routing, + wire.dhcp, + wire.dns, + wire.external_attachment, + wire.mdns, + wire.net_vm_name_override, + wire.net_vm_system_artifact_id, + wire.attachments, + ) + .map_err(serde::de::Error::custom) +); /// Closed Network condition types written by the Network controller. #[derive( @@ -1242,18 +1224,16 @@ impl AttachmentStatus { redacted_debug!(AttachmentStatus); -impl<'de> Deserialize<'de> for AttachmentStatus { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - execution_ref: ResourceRef, - phase: NetworkComponentPhase, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.execution_ref, wire.phase).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + AttachmentStatus, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + execution_ref: ResourceRef, + phase: NetworkComponentPhase, + }, + wire, + Self::new(wire.execution_ref, wire.phase).map_err(serde::de::Error::custom) +); /// Bounded public observation of one external physical-NIC authority. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] @@ -1380,28 +1360,26 @@ impl NetworkStatus { redacted_debug!(NetworkStatus); -impl<'de> Deserialize<'de> for NetworkStatus { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - net_vm_ref: ResourceRef, - lan_bridge: NetworkFabricStatus, - uplink_bridge: NetworkFabricStatus, - external_attachment: Option, - attachments: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.net_vm_ref, - wire.lan_bridge, - wire.uplink_bridge, - wire.external_attachment, - wire.attachments, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + NetworkStatus, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + net_vm_ref: ResourceRef, + lan_bridge: NetworkFabricStatus, + uplink_bridge: NetworkFabricStatus, + external_attachment: Option, + attachments: Vec, + }, + wire, + Self::new( + wire.net_vm_ref, + wire.lan_bridge, + wire.uplink_bridge, + wire.external_attachment, + wire.attachments, + ) + .map_err(serde::de::Error::custom) +); /// Expected generations bound to an opaque attachment realization. #[derive(Clone, PartialEq, Eq)] diff --git a/packages/d2b-contracts-resource/src/v3/process.rs b/packages/d2b-contracts-resource/src/v3/process.rs index 917bfa33f..136ef62b1 100644 --- a/packages/d2b-contracts-resource/src/v3/process.rs +++ b/packages/d2b-contracts-resource/src/v3/process.rs @@ -24,6 +24,7 @@ use super::{ redacted_debug, require_execution_ref, require_resource_type, }, }; +use d2b_contracts::wire_deserialize; /// The canonical ResourceType name for the long-lived process type. pub const PROCESS_RESOURCE_TYPE: &str = "Process"; @@ -248,33 +249,33 @@ impl Default for SandboxSpec { redacted_debug!(SandboxSpec); -impl<'de> Deserialize<'de> for SandboxSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - namespace_classes: Vec, - #[serde(default)] - capability_classes: Vec, - #[serde(default)] - seccomp_class: Option, - #[serde(default = "yes")] - no_new_privileges: bool, - #[serde(default)] - start_root: bool, - #[serde(default = "minimal_environment")] - environment_class: EnvironmentClass, - #[serde(default = "yes")] - read_only_root: bool, - #[serde(default = "default_umask")] - umask: Option, - #[serde(default)] - oom_score_adj: i32, - #[serde(default)] - user_namespace: Option, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + SandboxSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + namespace_classes: Vec, + #[serde(default)] + capability_classes: Vec, + #[serde(default)] + seccomp_class: Option, + #[serde(default = "yes")] + no_new_privileges: bool, + #[serde(default)] + start_root: bool, + #[serde(default = "minimal_environment")] + environment_class: EnvironmentClass, + #[serde(default = "yes")] + read_only_root: bool, + #[serde(default = "default_umask")] + umask: Option, + #[serde(default)] + oom_score_adj: i32, + #[serde(default)] + user_namespace: Option, + }, + wire, + { let seccomp_class = match wire.seccomp_class { Some(class) => class, None => BoundedToken::parse("strict").map_err(serde::de::Error::custom)?, @@ -293,7 +294,7 @@ impl<'de> Deserialize<'de> for SandboxSpec { ) .map_err(serde::de::Error::custom) } -} +); /// Access level of one Volume mount. #[derive( @@ -365,30 +366,28 @@ impl MountSpec { redacted_debug!(MountSpec); -impl<'de> Deserialize<'de> for MountSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - volume_ref: ResourceRef, - view: BoundedToken, - mount_path: String, - #[serde(default = "read_only")] - access: MountAccess, - #[serde(default = "yes")] - required: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.volume_ref, - wire.view, - wire.mount_path, - wire.access, - wire.required, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + MountSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + volume_ref: ResourceRef, + view: BoundedToken, + mount_path: String, + #[serde(default = "read_only")] + access: MountAccess, + #[serde(default = "yes")] + required: bool, + }, + wire, + Self::new( + wire.volume_ref, + wire.view, + wire.mount_path, + wire.access, + wire.required, + ) + .map_err(serde::de::Error::custom) +); /// Transport protocol of one declared port. #[derive( @@ -447,21 +446,19 @@ impl PortSpec { redacted_debug!(PortSpec); -impl<'de> Deserialize<'de> for PortSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - port: u16, - #[serde(default = "tcp")] - protocol: PortProtocol, - #[serde(default)] - purpose: String, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.port, wire.protocol, wire.purpose).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + PortSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + port: u16, + #[serde(default = "tcp")] + protocol: PortProtocol, + #[serde(default)] + purpose: String, + }, + wire, + Self::new(wire.port, wire.protocol, wire.purpose).map_err(serde::de::Error::custom) +); /// Network access declared by one process. /// @@ -513,22 +510,20 @@ impl NetworkUsageSpec { redacted_debug!(NetworkUsageSpec); -impl<'de> Deserialize<'de> for NetworkUsageSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - network_ref: Option, - #[serde(default)] - ports: Vec, - #[serde(default)] - allow_egress: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.network_ref, wire.ports, wire.allow_egress).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + NetworkUsageSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + network_ref: Option, + #[serde(default)] + ports: Vec, + #[serde(default)] + allow_egress: bool, + }, + wire, + Self::new(wire.network_ref, wire.ports, wire.allow_egress).map_err(serde::de::Error::custom) +); /// Device access level requested by one process. #[derive( @@ -587,21 +582,19 @@ impl DeviceUsageSpec { redacted_debug!(DeviceUsageSpec); -impl<'de> Deserialize<'de> for DeviceUsageSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - device_ref: ResourceRef, - #[serde(default = "shared")] - access: DeviceAccess, - #[serde(default)] - purpose: String, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.device_ref, wire.access, wire.purpose).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + DeviceUsageSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + device_ref: ResourceRef, + #[serde(default = "shared")] + access: DeviceAccess, + #[serde(default)] + purpose: String, + }, + wire, + Self::new(wire.device_ref, wire.access, wire.purpose).map_err(serde::de::Error::custom) +); /// Log level hint carried by the telemetry bindings. #[derive( @@ -988,25 +981,25 @@ impl Default for RestartPolicySpec { redacted_debug!(RestartPolicySpec); -impl<'de> Deserialize<'de> for RestartPolicySpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default = "on_failure")] - class: RestartClass, - #[serde(default)] - backoff_base: Option, - #[serde(default)] - backoff_max: Option, - #[serde(default = "two_thousand")] - backoff_multiplier_milli: u32, - #[serde(default)] - max_restarts: Option, - #[serde(default)] - reset_after: Option, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + RestartPolicySpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default = "on_failure")] + class: RestartClass, + #[serde(default)] + backoff_base: Option, + #[serde(default)] + backoff_max: Option, + #[serde(default = "two_thousand")] + backoff_multiplier_milli: u32, + #[serde(default)] + max_restarts: Option, + #[serde(default)] + reset_after: Option, + }, + wire, + { let default = RestartPolicySpec::default(); Self::new( wire.class, @@ -1018,7 +1011,7 @@ impl<'de> Deserialize<'de> for RestartPolicySpec { ) .map_err(serde::de::Error::custom) } -} +); /// Readiness probe mechanism. #[derive( @@ -1083,23 +1076,23 @@ impl Default for ReadinessSpec { redacted_debug!(ReadinessSpec); -impl<'de> Deserialize<'de> for ReadinessSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - initial_delay: Option, - #[serde(default)] - timeout: Option, - #[serde(default = "three")] - failure_threshold: u32, - #[serde(default = "one")] - success_threshold: u32, - #[serde(default = "ready_condition")] - class: ReadinessClass, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + ReadinessSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + initial_delay: Option, + #[serde(default)] + timeout: Option, + #[serde(default = "three")] + failure_threshold: u32, + #[serde(default = "one")] + success_threshold: u32, + #[serde(default = "ready_condition")] + class: ReadinessClass, + }, + wire, + { let default = ReadinessSpec::default(); Self::new( wire.initial_delay.unwrap_or(default.initial_delay), @@ -1110,7 +1103,7 @@ impl<'de> Deserialize<'de> for ReadinessSpec { ) .map_err(serde::de::Error::custom) } -} +); /// Health check mechanism. #[derive( @@ -1173,23 +1166,23 @@ impl Default for HealthCheckSpec { redacted_debug!(HealthCheckSpec); -impl<'de> Deserialize<'de> for HealthCheckSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - enabled: bool, - #[serde(default)] - interval: Option, - #[serde(default)] - timeout: Option, - #[serde(default = "three")] - failure_threshold: u32, - #[serde(default = "provider_defined_health")] - class: HealthCheckClass, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + HealthCheckSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + enabled: bool, + #[serde(default)] + interval: Option, + #[serde(default)] + timeout: Option, + #[serde(default = "three")] + failure_threshold: u32, + #[serde(default = "provider_defined_health")] + class: HealthCheckClass, + }, + wire, + { let default = HealthCheckSpec::default(); Self::new( wire.enabled, @@ -1200,7 +1193,7 @@ impl<'de> Deserialize<'de> for HealthCheckSpec { ) .map_err(serde::de::Error::custom) } -} +); /// Whether the controller adopts a running process after restart. #[derive( @@ -1300,48 +1293,48 @@ impl ProcessSpec { redacted_debug!(ProcessSpec); -impl<'de> Deserialize<'de> for ProcessSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - execution_ref: ResourceRef, - #[serde(default)] - domain: Option, - #[serde(default)] - user_ref: Option, - process_class: ProcessClass, - template: BoundedToken, - #[serde(default)] - config_ref: Option, - #[serde(default)] - credential_refs: Vec, - #[serde(default)] - mounts: Vec, - #[serde(default)] - sandbox: SandboxSpec, - #[serde(default)] - budget: BudgetSpec, - #[serde(default)] - network_usage: Option, - #[serde(default)] - device_usage: Vec, - #[serde(default)] - telemetry: TelemetrySpec, - #[serde(default = "running")] - desired_lifecycle: DesiredLifecycle, - #[serde(default)] - restart_policy: RestartPolicySpec, - #[serde(default)] - readiness: ReadinessSpec, - #[serde(default)] - health_check: HealthCheckSpec, - #[serde(default = "adopt_on_restart")] - adoption_policy: AdoptionPolicy, - #[serde(default)] - drain_timeout: Option, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + ProcessSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + execution_ref: ResourceRef, + #[serde(default)] + domain: Option, + #[serde(default)] + user_ref: Option, + process_class: ProcessClass, + template: BoundedToken, + #[serde(default)] + config_ref: Option, + #[serde(default)] + credential_refs: Vec, + #[serde(default)] + mounts: Vec, + #[serde(default)] + sandbox: SandboxSpec, + #[serde(default)] + budget: BudgetSpec, + #[serde(default)] + network_usage: Option, + #[serde(default)] + device_usage: Vec, + #[serde(default)] + telemetry: TelemetrySpec, + #[serde(default = "running")] + desired_lifecycle: DesiredLifecycle, + #[serde(default)] + restart_policy: RestartPolicySpec, + #[serde(default)] + readiness: ReadinessSpec, + #[serde(default)] + health_check: HealthCheckSpec, + #[serde(default = "adopt_on_restart")] + adoption_policy: AdoptionPolicy, + #[serde(default)] + drain_timeout: Option, + }, + wire, + { let execution = ExecutionWire { execution_ref: wire.execution_ref, domain: wire.domain, @@ -1371,7 +1364,7 @@ impl<'de> Deserialize<'de> for ProcessSpec { ) .map_err(serde::de::Error::custom) } -} +); /// The EphemeralProcess ResourceType base spec. /// @@ -1487,48 +1480,48 @@ impl EphemeralProcessSpec { redacted_debug!(EphemeralProcessSpec); -impl<'de> Deserialize<'de> for EphemeralProcessSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - execution_ref: ResourceRef, - #[serde(default)] - domain: Option, - #[serde(default)] - user_ref: Option, - process_class: ProcessClass, - template: BoundedToken, - #[serde(default)] - config_ref: Option, - #[serde(default)] - credential_refs: Vec, - #[serde(default)] - mounts: Vec, - #[serde(default)] - sandbox: SandboxSpec, - #[serde(default)] - budget: BudgetSpec, - #[serde(default)] - network_usage: Option, - #[serde(default)] - device_usage: Vec, - #[serde(default)] - telemetry: TelemetrySpec, - #[serde(default)] - activation_input: Option, - #[serde(default)] - start_deadline: Option, - #[serde(default)] - runtime_deadline: Option, - #[serde(default)] - successful_ttl: Option, - #[serde(default)] - failed_ttl: Option, - #[serde(default)] - incident_hold: bool, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + EphemeralProcessSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + execution_ref: ResourceRef, + #[serde(default)] + domain: Option, + #[serde(default)] + user_ref: Option, + process_class: ProcessClass, + template: BoundedToken, + #[serde(default)] + config_ref: Option, + #[serde(default)] + credential_refs: Vec, + #[serde(default)] + mounts: Vec, + #[serde(default)] + sandbox: SandboxSpec, + #[serde(default)] + budget: BudgetSpec, + #[serde(default)] + network_usage: Option, + #[serde(default)] + device_usage: Vec, + #[serde(default)] + telemetry: TelemetrySpec, + #[serde(default)] + activation_input: Option, + #[serde(default)] + start_deadline: Option, + #[serde(default)] + runtime_deadline: Option, + #[serde(default)] + successful_ttl: Option, + #[serde(default)] + failed_ttl: Option, + #[serde(default)] + incident_hold: bool, + }, + wire, + { let execution = ExecutionWire { execution_ref: wire.execution_ref, domain: wire.domain, @@ -1566,7 +1559,7 @@ impl<'de> Deserialize<'de> for EphemeralProcessSpec { None => Ok(spec), } } -} +); fn check_unique(values: &[T], max: usize) -> Result<(), PrimitiveSpecError> { if values.len() > max { diff --git a/packages/d2b-contracts-resource/src/v3/resource.rs b/packages/d2b-contracts-resource/src/v3/resource.rs index f87a39feb..c56c599c3 100644 --- a/packages/d2b-contracts-resource/src/v3/resource.rs +++ b/packages/d2b-contracts-resource/src/v3/resource.rs @@ -15,6 +15,7 @@ use super::{ serde_json_error_metadata, validate_canonical_string, }, }; +use d2b_contracts::wire_deserialize; /// Resource API version carried by every complete envelope. pub const RESOURCE_API_VERSION: &str = "resources.d2bus.org/v3"; @@ -332,34 +333,31 @@ impl core::fmt::Debug for ResourceMetadata { } } -impl<'de> Deserialize<'de> for ResourceMetadata { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, +wire_deserialize!( + ResourceMetadata, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + name: ResourceName, + zone: ZoneId, + uid: ResourceUid, + generation: ResourceGeneration, + revision: ZoneRevision, + owner_ref: RequiredNullable, + finalizers: Vec, + deletion_requested_at: RequiredNullable, + created_at: Timestamp, + updated_at: Timestamp, + managed_by: ManagedBy, + configuration_generation: Option, + controller_generation: Option, + provider_generation: Option, + #[serde(default)] + labels: BTreeMap, + #[serde(default)] + annotations: BTreeMap, + }, + wire, { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - name: ResourceName, - zone: ZoneId, - uid: ResourceUid, - generation: ResourceGeneration, - revision: ZoneRevision, - owner_ref: RequiredNullable, - finalizers: Vec, - deletion_requested_at: RequiredNullable, - created_at: Timestamp, - updated_at: Timestamp, - managed_by: ManagedBy, - configuration_generation: Option, - controller_generation: Option, - provider_generation: Option, - #[serde(default)] - labels: BTreeMap, - #[serde(default)] - annotations: BTreeMap, - } - let wire = Wire::deserialize(deserializer)?; let presentation = PresentationMetadata::new(wire.labels, wire.annotations) .map_err(serde::de::Error::custom)?; Self::new( @@ -381,7 +379,7 @@ impl<'de> Deserialize<'de> for ResourceMetadata { ) .map_err(serde::de::Error::custom) } -} +); /// Policy for disruptive desired-state changes. #[derive( @@ -480,23 +478,17 @@ impl core::fmt::Debug for ProviderSpecExtension { } } -impl<'de> Deserialize<'de> for ProviderSpecExtension { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - schema_id: ExtensionSchemaId, - schema_version: SchemaVersion, - settings: CanonicalJsonObject, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.schema_id, wire.schema_version, wire.settings) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ProviderSpecExtension, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + schema_id: ExtensionSchemaId, + schema_version: SchemaVersion, + settings: CanonicalJsonObject, + }, + wire, + Self::new(wire.schema_id, wire.schema_version, wire.settings).map_err(serde::de::Error::custom) +); /// ResourceType base spec fields plus the optional Provider extension. #[derive(Clone, PartialEq, Eq)] @@ -789,22 +781,19 @@ impl core::fmt::Debug for ResourceEnvelope { } } -impl<'de> Deserialize<'de> for ResourceEnvelope { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, +wire_deserialize!( + ResourceEnvelope, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + api_version: String, + #[serde(rename = "type")] + resource_type: ResourceTypeName, + metadata: ResourceMetadata, + spec: ResourceSpec, + status: ResourceStatus, + }, + wire, { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - api_version: String, - #[serde(rename = "type")] - resource_type: ResourceTypeName, - metadata: ResourceMetadata, - spec: ResourceSpec, - status: ResourceStatus, - } - let wire = Wire::deserialize(deserializer)?; if wire.api_version != RESOURCE_API_VERSION { return Err(serde::de::Error::custom( "apiVersion must be resources.d2bus.org/v3", @@ -813,7 +802,7 @@ impl<'de> Deserialize<'de> for ResourceEnvelope { Self::new(wire.resource_type, wire.metadata, wire.spec, wire.status) .map_err(serde::de::Error::custom) } -} +); impl From<&ResourceEnvelope> for ResourceRef { fn from(envelope: &ResourceEnvelope) -> Self { diff --git a/packages/d2b-contracts-resource/src/v3/resource_status.rs b/packages/d2b-contracts-resource/src/v3/resource_status.rs index 0c0b060a0..894483265 100644 --- a/packages/d2b-contracts-resource/src/v3/resource_status.rs +++ b/packages/d2b-contracts-resource/src/v3/resource_status.rs @@ -11,6 +11,7 @@ use super::{ }, }; use crate::ids::OperationId; +use d2b_contracts::wire_deserialize; /// Maximum canonical bytes for a complete status object. pub const MAX_STATUS_BYTES: usize = 64 * 1024; @@ -207,33 +208,28 @@ impl ResourceCondition { } } -impl<'de> Deserialize<'de> for ResourceCondition { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(rename = "type")] - condition_type: StatusCode, - status: ConditionState, - reason: StatusCode, - message: StatusMessage, - observed_generation: ObservedGeneration, - last_transition_at: Timestamp, - } - let wire = Wire::deserialize(deserializer)?; - Ok(Self::new( - wire.condition_type, - wire.status, - wire.reason, - wire.message, - wire.observed_generation, - wire.last_transition_at, - )) - } -} +wire_deserialize!( + ResourceCondition, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(rename = "type")] + condition_type: StatusCode, + status: ConditionState, + reason: StatusCode, + message: StatusMessage, + observed_generation: ObservedGeneration, + last_transition_at: Timestamp, + }, + wire, + Ok(Self::new( + wire.condition_type, + wire.status, + wire.reason, + wire.message, + wire.observed_generation, + wire.last_transition_at, + )) +); /// Latest bounded reconcile outcome. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -279,33 +275,28 @@ impl ResourceOutcome { } } -impl<'de> Deserialize<'de> for ResourceOutcome { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - code: StatusCode, - exit_code: Option, - message: StatusMessage, - retryable: bool, - retry_after_ms: Option, - occurred_at: Timestamp, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.code, - wire.exit_code, - wire.message, - wire.retryable, - wire.retry_after_ms, - wire.occurred_at, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ResourceOutcome, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + code: StatusCode, + exit_code: Option, + message: StatusMessage, + retryable: bool, + retry_after_ms: Option, + occurred_at: Timestamp, + }, + wire, + Self::new( + wire.code, + wire.exit_code, + wire.message, + wire.retryable, + wire.retry_after_ms, + wire.occurred_at, + ) + .map_err(serde::de::Error::custom) +); /// Currency state for the current desired generation. #[derive( @@ -386,21 +377,16 @@ impl ResourceCurrencySet { } } -impl<'de> Deserialize<'de> for ResourceCurrencySet { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - count: u64, - refs: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.count, wire.refs).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ResourceCurrencySet, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + count: u64, + refs: Vec, + }, + wire, + Self::new(wire.count, wire.refs).map_err(serde::de::Error::custom) +); /// Universal update currency object. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -460,41 +446,36 @@ impl ResourceUpdateStatus { } } -impl<'de> Deserialize<'de> for ResourceUpdateStatus { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - state: UpdateState, - reasons: Vec, - observed_generation: ObservedGeneration, - target_generation: ResourceGeneration, - disruption: UpdateDisruption, - preserve_state: bool, - operation_id: RequiredNullable, - last_assessed_at: RequiredNullable, - owned: ResourceCurrencySet, - dependencies: ResourceCurrencySet, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.state, - wire.reasons, - wire.observed_generation, - wire.target_generation, - wire.disruption, - wire.preserve_state, - wire.operation_id.0, - wire.last_assessed_at.0, - wire.owned, - wire.dependencies, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ResourceUpdateStatus, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + state: UpdateState, + reasons: Vec, + observed_generation: ObservedGeneration, + target_generation: ResourceGeneration, + disruption: UpdateDisruption, + preserve_state: bool, + operation_id: RequiredNullable, + last_assessed_at: RequiredNullable, + owned: ResourceCurrencySet, + dependencies: ResourceCurrencySet, + }, + wire, + Self::new( + wire.state, + wire.reasons, + wire.observed_generation, + wire.target_generation, + wire.disruption, + wire.preserve_state, + wire.operation_id.0, + wire.last_assessed_at.0, + wire.owned, + wire.dependencies, + ) + .map_err(serde::de::Error::custom) +); /// Optional Provider-specific status layer. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -559,31 +540,26 @@ impl core::fmt::Debug for ProviderStatusExtension { } } -impl<'de> Deserialize<'de> for ProviderStatusExtension { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - provider_ref: ResourceRef, - schema_id: ExtensionSchemaId, - schema_version: SchemaVersion, - observed_provider_generation: ResourceGeneration, - details: CanonicalJsonObject, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.provider_ref, - wire.schema_id, - wire.schema_version, - wire.observed_provider_generation, - wire.details, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ProviderStatusExtension, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + provider_ref: ResourceRef, + schema_id: ExtensionSchemaId, + schema_version: SchemaVersion, + observed_provider_generation: ResourceGeneration, + details: CanonicalJsonObject, + }, + wire, + Self::new( + wire.provider_ref, + wire.schema_id, + wire.schema_version, + wire.observed_provider_generation, + wire.details, + ) + .map_err(serde::de::Error::custom) +); /// Complete universal status plus ResourceType and optional Provider layers. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -702,43 +678,38 @@ impl core::fmt::Debug for ResourceStatus { } } -impl<'de> Deserialize<'de> for ResourceStatus { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - observed_generation: ObservedGeneration, - status_generation: RequiredNullable, - phase: ResourcePhase, - conditions: Vec, - last_reconciled_at: RequiredNullable, - started_at: RequiredNullable, - completed_at: RequiredNullable, - outcome: RequiredNullable, - update: ResourceUpdateStatus, - resource: CanonicalJsonObject, - provider: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.observed_generation, - wire.status_generation.0, - wire.phase, - wire.conditions, - wire.last_reconciled_at.0, - wire.started_at.0, - wire.completed_at.0, - wire.outcome.0, - wire.update, - wire.resource, - wire.provider, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ResourceStatus, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + observed_generation: ObservedGeneration, + status_generation: RequiredNullable, + phase: ResourcePhase, + conditions: Vec, + last_reconciled_at: RequiredNullable, + started_at: RequiredNullable, + completed_at: RequiredNullable, + outcome: RequiredNullable, + update: ResourceUpdateStatus, + resource: CanonicalJsonObject, + provider: Option, + }, + wire, + Self::new( + wire.observed_generation, + wire.status_generation.0, + wire.phase, + wire.conditions, + wire.last_reconciled_at.0, + wire.started_at.0, + wire.completed_at.0, + wire.outcome.0, + wire.update, + wire.resource, + wire.provider, + ) + .map_err(serde::de::Error::custom) +); fn ensure_layer_size(value: &CanonicalJsonObject) -> Result<(), ResourceStatusError> { if value.to_canonical_bytes().len() > MAX_STATUS_LAYER_BYTES { diff --git a/packages/d2b-contracts-resource/src/v3/storage.rs b/packages/d2b-contracts-resource/src/v3/storage.rs index 5de908dfc..b2a705220 100644 --- a/packages/d2b-contracts-resource/src/v3/storage.rs +++ b/packages/d2b-contracts-resource/src/v3/storage.rs @@ -12,6 +12,7 @@ use schemars::{ use serde::{Deserialize, Deserializer, Serialize}; use super::ResourceUid; +use d2b_contracts::wire_deserialize; /// Maximum byte length of a broker-resolved Zone storage identifier. pub const MAX_ZONE_STORAGE_ID_BYTES: usize = 160; @@ -189,23 +190,17 @@ impl ZoneStoreIdentity { } } -impl<'de> Deserialize<'de> for ZoneStoreIdentity { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - zone_uid: ResourceUid, - store_uid: ResourceUid, - store_epoch: u64, - } - - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.zone_uid, wire.store_uid, wire.store_epoch).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ZoneStoreIdentity, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + zone_uid: ResourceUid, + store_uid: ResourceUid, + store_epoch: u64, + }, + wire, + Self::new(wire.zone_uid, wire.store_uid, wire.store_epoch).map_err(serde::de::Error::custom) +); /// Exact database-inode ownership and metadata requirements. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] diff --git a/packages/d2b-contracts-resource/src/v3/user.rs b/packages/d2b-contracts-resource/src/v3/user.rs index 1cb700f96..f47266fd5 100644 --- a/packages/d2b-contracts-resource/src/v3/user.rs +++ b/packages/d2b-contracts-resource/src/v3/user.rs @@ -11,11 +11,12 @@ //! `Credential` resources. use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::Serialize; use super::execution_policy::{ BoundedText, PrimitiveSpecError, parsed_deserialize, redacted_debug, string_schema, }; +use d2b_contracts::wire_deserialize; /// The canonical ResourceType name for this module. pub const USER_RESOURCE_TYPE: &str = "User"; @@ -147,25 +148,25 @@ impl UserSpec { redacted_debug!(UserSpec); -impl<'de> Deserialize<'de> for UserSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - os_username: OsUsername, - #[serde(default)] - display_name: Option, - #[serde(default)] - groups: Vec, - } - let wire = Wire::deserialize(deserializer)?; +wire_deserialize!( + UserSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + os_username: OsUsername, + #[serde(default)] + display_name: Option, + #[serde(default)] + groups: Vec, + }, + wire, + { let display_name = match wire.display_name { Some(name) => name, None => BoundedText::parse(String::new()).map_err(serde::de::Error::custom)?, }; Self::new(wire.os_username, display_name, wire.groups).map_err(serde::de::Error::custom) } -} +); #[cfg(test)] mod tests { diff --git a/packages/d2b-contracts-resource/src/v3/volume.rs b/packages/d2b-contracts-resource/src/v3/volume.rs index 775b09d4f..2c21e6b02 100644 --- a/packages/d2b-contracts-resource/src/v3/volume.rs +++ b/packages/d2b-contracts-resource/src/v3/volume.rs @@ -15,7 +15,7 @@ use std::collections::BTreeMap; use schemars::JsonSchema; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Serialize}; use super::{ ResourceRef, @@ -25,6 +25,7 @@ use super::{ }, process::validate_octal_mode, }; +use d2b_contracts::wire_deserialize; /// The canonical ResourceType name for this module. pub const VOLUME_RESOURCE_TYPE: &str = "Volume"; @@ -174,32 +175,30 @@ impl SourceSettings { redacted_debug!(SourceSettings); -impl<'de> Deserialize<'de> for SourceSettings { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - kind: SourceKind, - #[serde(default)] - source_policy_id: Option, - #[serde(default)] - system_artifact_id: Option, - #[serde(default)] - image_format: Option, - #[serde(default)] - preallocate: bool, - } - let wire = Wire::deserialize(deserializer)?; - Self::new_with_artifact( - wire.kind, - wire.source_policy_id, - wire.system_artifact_id, - wire.image_format, - wire.preallocate, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + SourceSettings, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + kind: SourceKind, + #[serde(default)] + source_policy_id: Option, + #[serde(default)] + system_artifact_id: Option, + #[serde(default)] + image_format: Option, + #[serde(default)] + preallocate: bool, + }, + wire, + Self::new_with_artifact( + wire.kind, + wire.source_policy_id, + wire.system_artifact_id, + wire.image_format, + wire.preallocate, + ) + .map_err(serde::de::Error::custom) +); const fn is_false(value: &bool) -> bool { !*value @@ -239,18 +238,16 @@ impl VolumeSource { redacted_debug!(VolumeSource); -impl<'de> Deserialize<'de> for VolumeSource { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - execution_ref: ResourceRef, - settings: SourceSettings, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.execution_ref, wire.settings).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + VolumeSource, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + execution_ref: ResourceRef, + settings: SourceSettings, + }, + wire, + Self::new(wire.execution_ref, wire.settings).map_err(serde::de::Error::custom) +); /// Layout entry class. #[derive( @@ -422,17 +419,16 @@ impl AclPrincipal { redacted_debug!(AclPrincipal); -impl<'de> Deserialize<'de> for AclPrincipal { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(rename = "ref")] - reference: ResourceRef, - } - Self::new(Wire::deserialize(deserializer)?.reference).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + AclPrincipal, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(rename = "ref")] + reference: ResourceRef, + }, + wire, + Self::new(wire.reference).map_err(serde::de::Error::custom) +); /// One POSIX ACL grant. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -476,18 +472,16 @@ impl AclGrant { redacted_debug!(AclGrant); -impl<'de> Deserialize<'de> for AclGrant { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - principal: AclPrincipal, - permissions: String, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.principal, wire.permissions).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + AclGrant, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + principal: AclPrincipal, + permissions: String, + }, + wire, + Self::new(wire.principal, wire.permissions).map_err(serde::de::Error::custom) +); /// One anchored layout entry relative to the Volume root. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -708,71 +702,69 @@ impl LayoutEntry { redacted_debug!(LayoutEntry); -impl<'de> Deserialize<'de> for LayoutEntry { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - path: String, - #[serde(rename = "type")] - entry_type: EntryType, - owner_ref: ResourceRef, - group_ref: ResourceRef, - mode: String, - #[serde(default)] - target: Option, - #[serde(default)] - access_acl: Vec, - #[serde(default)] - default_acl: Vec, - #[serde(default = "preserve")] - foreign_child_policy: ForeignChildPolicy, - #[serde(default = "yes")] - no_follow: bool, - #[serde(default)] - recursive: bool, - #[serde(default = "private")] - sensitivity: SensitivityClass, - #[serde(default = "create_if_absent")] - create_policy: CreatePolicy, - #[serde(default = "exact_owner")] - repair_policy: RepairPolicy, - #[serde(default = "never")] - cleanup_policy: CleanupPolicy, - #[serde(default = "adopt_with_live_owner_proof")] - adoption_policy: EntryAdoptionPolicy, - #[serde(default = "preserve_across_controller_restart")] - restart_policy: EntryRestartPolicy, - #[serde(default = "lease_none")] - lease_class: LeaseClass, - #[serde(default = "no_symlink")] - invariants: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.path, - wire.entry_type, - wire.owner_ref, - wire.group_ref, - wire.mode, - wire.target, - wire.access_acl, - wire.default_acl, - wire.foreign_child_policy, - wire.no_follow, - wire.recursive, - wire.sensitivity, - wire.create_policy, - wire.repair_policy, - wire.cleanup_policy, - wire.adoption_policy, - wire.restart_policy, - wire.lease_class, - wire.invariants, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + LayoutEntry, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + path: String, + #[serde(rename = "type")] + entry_type: EntryType, + owner_ref: ResourceRef, + group_ref: ResourceRef, + mode: String, + #[serde(default)] + target: Option, + #[serde(default)] + access_acl: Vec, + #[serde(default)] + default_acl: Vec, + #[serde(default = "preserve")] + foreign_child_policy: ForeignChildPolicy, + #[serde(default = "yes")] + no_follow: bool, + #[serde(default)] + recursive: bool, + #[serde(default = "private")] + sensitivity: SensitivityClass, + #[serde(default = "create_if_absent")] + create_policy: CreatePolicy, + #[serde(default = "exact_owner")] + repair_policy: RepairPolicy, + #[serde(default = "never")] + cleanup_policy: CleanupPolicy, + #[serde(default = "adopt_with_live_owner_proof")] + adoption_policy: EntryAdoptionPolicy, + #[serde(default = "preserve_across_controller_restart")] + restart_policy: EntryRestartPolicy, + #[serde(default = "lease_none")] + lease_class: LeaseClass, + #[serde(default = "no_symlink")] + invariants: Vec, + }, + wire, + Self::new( + wire.path, + wire.entry_type, + wire.owner_ref, + wire.group_ref, + wire.mode, + wire.target, + wire.access_acl, + wire.default_acl, + wire.foreign_child_policy, + wire.no_follow, + wire.recursive, + wire.sensitivity, + wire.create_policy, + wire.repair_policy, + wire.cleanup_policy, + wire.adoption_policy, + wire.restart_policy, + wire.lease_class, + wire.invariants, + ) + .map_err(serde::de::Error::custom) +); /// One right granted by a named view. #[derive( @@ -829,18 +821,16 @@ impl ViewSpec { redacted_debug!(ViewSpec); -impl<'de> Deserialize<'de> for ViewSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - path: String, - rights: Vec, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.path, wire.rights).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + ViewSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + path: String, + rights: Vec, + }, + wire, + Self::new(wire.path, wire.rights).map_err(serde::de::Error::custom) +); /// Transport of one Volume attachment. #[derive( @@ -968,36 +958,34 @@ impl Default for AttachmentSettings { redacted_debug!(AttachmentSettings); -impl<'de> Deserialize<'de> for AttachmentSettings { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - posix_acl: bool, - #[serde(default)] - xattr: bool, - #[serde(default = "cache_auto")] - cache: AttachmentCache, - #[serde(default = "handles_never")] - inode_file_handles: InodeFileHandles, - #[serde(default)] - thread_pool_size: Option, - #[serde(default)] - socket_group: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.posix_acl, - wire.xattr, - wire.cache, - wire.inode_file_handles, - wire.thread_pool_size, - wire.socket_group, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + AttachmentSettings, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + posix_acl: bool, + #[serde(default)] + xattr: bool, + #[serde(default = "cache_auto")] + cache: AttachmentCache, + #[serde(default = "handles_never")] + inode_file_handles: InodeFileHandles, + #[serde(default)] + thread_pool_size: Option, + #[serde(default)] + socket_group: Option, + }, + wire, + Self::new( + wire.posix_acl, + wire.xattr, + wire.cache, + wire.inode_file_handles, + wire.thread_pool_size, + wire.socket_group, + ) + .map_err(serde::de::Error::custom) +); /// One same-Zone Host or Guest attachment. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -1070,32 +1058,30 @@ impl VolumeAttachment { redacted_debug!(VolumeAttachment); -impl<'de> Deserialize<'de> for VolumeAttachment { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - execution_ref: ResourceRef, - transport: AttachmentTransport, - view: BoundedToken, - #[serde(default = "attachment_read_only")] - access: AttachmentAccess, - mount_path: String, - #[serde(default)] - settings: AttachmentSettings, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.execution_ref, - wire.transport, - wire.view, - wire.access, - wire.mount_path, - wire.settings, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + VolumeAttachment, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + execution_ref: ResourceRef, + transport: AttachmentTransport, + view: BoundedToken, + #[serde(default = "attachment_read_only")] + access: AttachmentAccess, + mount_path: String, + #[serde(default)] + settings: AttachmentSettings, + }, + wire, + Self::new( + wire.execution_ref, + wire.transport, + wire.view, + wire.access, + wire.mount_path, + wire.settings, + ) + .map_err(serde::de::Error::custom) +); /// Whether the backing filesystem must enforce the declared quota. #[derive( @@ -1154,23 +1140,21 @@ impl QuotaSpec { redacted_debug!(QuotaSpec); -impl<'de> Deserialize<'de> for QuotaSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - #[serde(default)] - max_bytes: Option, - #[serde(default)] - max_inodes: Option, - #[serde(default = "quota_none")] - enforcement: QuotaEnforcement, - } - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.max_bytes, wire.max_inodes, wire.enforcement) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + QuotaSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + #[serde(default)] + max_bytes: Option, + #[serde(default)] + max_inodes: Option, + #[serde(default = "quota_none")] + enforcement: QuotaEnforcement, + }, + wire, + Self::new(wire.max_bytes, wire.max_inodes, wire.enforcement) + .map_err(serde::de::Error::custom) +); /// The Volume ResourceType base spec. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] @@ -1302,33 +1286,31 @@ impl VolumeSpec { redacted_debug!(VolumeSpec); -impl<'de> Deserialize<'de> for VolumeSpec { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - source: VolumeSource, - kind: VolumeKind, - #[serde(default)] - layout: Vec, - views: BTreeMap, - #[serde(default)] - attachments: Vec, - #[serde(default)] - quota: Option, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.source, - wire.kind, - wire.layout, - wire.views, - wire.attachments, - wire.quota, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + VolumeSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + source: VolumeSource, + kind: VolumeKind, + #[serde(default)] + layout: Vec, + views: BTreeMap, + #[serde(default)] + attachments: Vec, + #[serde(default)] + quota: Option, + }, + wire, + Self::new( + wire.source, + wire.kind, + wire.layout, + wire.views, + wire.attachments, + wire.quota, + ) + .map_err(serde::de::Error::custom) +); /// Accepts one anchored path in a single normal form. /// diff --git a/packages/d2b-contracts-resource/src/v3/volume_binding.rs b/packages/d2b-contracts-resource/src/v3/volume_binding.rs index 13ee5f107..65ca8c347 100644 --- a/packages/d2b-contracts-resource/src/v3/volume_binding.rs +++ b/packages/d2b-contracts-resource/src/v3/volume_binding.rs @@ -17,6 +17,7 @@ use super::{ resource_status::StatusCode, volume::{AttachmentAccess, validate_mount_path}, }; +use d2b_contracts::wire_deserialize; /// Canonical standard VolumeBinding ResourceType. pub const VOLUME_BINDING_RESOURCE_TYPE: &str = "VolumeBinding"; @@ -113,31 +114,26 @@ impl core::fmt::Debug for VolumeBindingSpec { } } -impl<'de> Deserialize<'de> for VolumeBindingSpec { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - volume_ref: ResourceRef, - execution_ref: ResourceRef, - view: String, - access: AttachmentAccess, - mount_path: String, - } - let wire = Wire::deserialize(deserializer)?; - Self::new( - wire.volume_ref, - wire.execution_ref, - wire.view, - wire.access, - wire.mount_path, - ) - .map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + VolumeBindingSpec, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + volume_ref: ResourceRef, + execution_ref: ResourceRef, + view: String, + access: AttachmentAccess, + mount_path: String, + }, + wire, + Self::new( + wire.volume_ref, + wire.execution_ref, + wire.view, + wire.access, + wire.mount_path, + ) + .map_err(serde::de::Error::custom) +); /// The UID / generation / revision fence on readiness evidence. /// diff --git a/packages/d2b-contracts-resource/src/v3/volume_state.rs b/packages/d2b-contracts-resource/src/v3/volume_state.rs index 33ca21f82..e353757ec 100644 --- a/packages/d2b-contracts-resource/src/v3/volume_state.rs +++ b/packages/d2b-contracts-resource/src/v3/volume_state.rs @@ -13,6 +13,7 @@ use super::{ identity::{SchemaFingerprint, Timestamp}, resource_schema::{CanonicalJsonError, SchemaVersion, canonical_json_bytes}, }; +use d2b_contracts::wire_deserialize; /// Largest component generation retained from the atomic-state contract. pub const MAX_STATE_GENERATION: u64 = 9_007_199_254_740_991; @@ -376,19 +377,16 @@ impl core::fmt::Debug for QuotaUsage { } } -impl<'de> Deserialize<'de> for QuotaUsage { - fn deserialize>(deserializer: D) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase", deny_unknown_fields)] - struct Wire { - used_bytes: u64, - inode_count: u64, - } - - let wire = Wire::deserialize(deserializer)?; - Self::new(wire.used_bytes, wire.inode_count).map_err(serde::de::Error::custom) - } -} +wire_deserialize!( + QuotaUsage, + #[serde(rename_all = "camelCase", deny_unknown_fields)] + Wire { + used_bytes: u64, + inode_count: u64, + }, + wire, + Self::new(wire.used_bytes, wire.inode_count).map_err(serde::de::Error::custom) +); /// Provider-owned Volume status extension for payload state. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] diff --git a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs index c2a62c927..40bcbdad2 100644 --- a/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs +++ b/packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs @@ -1,5 +1,6 @@ //! Zone-wide EmergencyPolicy contract. +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/packages/d2b-contracts-zone-session/src/v3/mod.rs b/packages/d2b-contracts-zone-session/src/v3/mod.rs index 6e3478559..4e18f7de9 100644 --- a/packages/d2b-contracts-zone-session/src/v3/mod.rs +++ b/packages/d2b-contracts-zone-session/src/v3/mod.rs @@ -1,38 +1,5 @@ //! Canonical Zone and ComponentSession contract family. -/// Captures the crate's Wire-struct `Deserialize` shape: a private -/// `#[derive(Deserialize)]` wire struct with `deny_unknown_fields`, then a -/// validated constructor admission check. -/// -/// The binding name is passed explicitly (`wire` at every site) so the -/// construct expression can reference it across macro hygiene. -macro_rules! wire_deserialize { - ( - $type:ty, - $(#[$container:meta])* - $wire:ident { - $( $(#[$field_attr:meta])* $field:ident : $field_ty:ty ),* $(,)? - }, - $binding:ident, - $construct:expr - ) => { - impl<'de> serde::Deserialize<'de> for $type { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - #[derive(serde::Deserialize)] - $(#[$container])* - struct $wire { - $( $(#[$field_attr])* $field: $field_ty, )* - } - let $binding = $wire::deserialize(deserializer)?; - $construct - } - } - }; -} - pub mod component_session; pub mod emergency_policy; pub mod resource_bundle; diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs index da6b475d3..d2c68cfdb 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs @@ -8,6 +8,7 @@ use std::collections::BTreeMap; +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs index c10498cf2..3c42c2ddc 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs @@ -5,6 +5,7 @@ //! backing resource, remote Zone, session, stream, and lease handles stay //! outside this resource contract. +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs index a93030058..c1de0e4ad 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs @@ -9,6 +9,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use super::resource_export::{ResourceExportSpec, ShareQuota, is_qualified_service_type}; +use d2b_contracts::wire_deserialize; use d2b_contracts_provider::v3::provider::{ Exportability, ProjectionFactory, ProviderContractError, }; diff --git a/packages/d2b-contracts-zone-session/src/v3/role.rs b/packages/d2b-contracts-zone-session/src/v3/role.rs index 88e382a8e..ba26303a7 100644 --- a/packages/d2b-contracts-zone-session/src/v3/role.rs +++ b/packages/d2b-contracts-zone-session/src/v3/role.rs @@ -4,6 +4,7 @@ //! sets. In particular, `relay` is transport forwarding authority and can //! never be smuggled into CRUD by treating all verbs as strings. +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/packages/d2b-contracts-zone-session/src/v3/role_binding.rs b/packages/d2b-contracts-zone-session/src/v3/role_binding.rs index 76966ec52..9c446ab53 100644 --- a/packages/d2b-contracts-zone-session/src/v3/role_binding.rs +++ b/packages/d2b-contracts-zone-session/src/v3/role_binding.rs @@ -6,6 +6,7 @@ use serde::{Deserialize, Deserializer, Serialize}; use super::role::{ MAX_ROLE_RULE_EXECUTION_REFS, MAX_ROLE_RULE_RESOURCE_NAMES, RoleContractError, RoleRule, }; +use d2b_contracts::wire_deserialize; use d2b_contracts_resource::v3::{ CanonicalJsonObject, ResourceRef, ZoneId, execution_policy::redacted_debug, }; diff --git a/packages/d2b-contracts-zone-session/src/v3/services.rs b/packages/d2b-contracts-zone-session/src/v3/services.rs index 74228ebc8..bb072c227 100644 --- a/packages/d2b-contracts-zone-session/src/v3/services.rs +++ b/packages/d2b-contracts-zone-session/src/v3/services.rs @@ -4,6 +4,7 @@ //! fingerprint is derived from the canonical ordered method set, so adding, //! removing, or renaming a method cannot be mistaken for the old service. +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; diff --git a/packages/d2b-contracts-zone-session/src/v3/zone.rs b/packages/d2b-contracts-zone-session/src/v3/zone.rs index e971e9b9e..9d400de57 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone.rs @@ -6,6 +6,7 @@ //! that distinction in the type system prevents a caller from smuggling //! parent topology, policy, or implementation settings into the self row. +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_link.rs b/packages/d2b-contracts-zone-session/src/v3/zone_link.rs index 560501089..6d447756b 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_link.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_link.rs @@ -6,6 +6,7 @@ //! observations. No parent resource reference, locator, descriptor, or //! credential bytes can be represented here. +use d2b_contracts::wire_deserialize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs b/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs index 1e08b972f..8f604f3e8 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_routing.rs @@ -26,6 +26,7 @@ use schemars::{ use serde::{Deserialize, Deserializer, Serialize}; use super::component_session::{OperationClass, OperationId}; +use d2b_contracts::wire_deserialize; use d2b_contracts_resource::v3::execution_policy::{ BoundedToken, MAX_BOUNDED_TOKEN_BYTES, PrimitiveSpecError, parsed_deserialize, redacted_debug, string_schema, diff --git a/packages/d2b-contracts/src/lib.rs b/packages/d2b-contracts/src/lib.rs index 943d97b15..d4fbaf7ef 100644 --- a/packages/d2b-contracts/src/lib.rs +++ b/packages/d2b-contracts/src/lib.rs @@ -3,6 +3,39 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize, de::DeserializeOwned}; +/// Captures the shared contract Wire-struct `Deserialize` shape: a private +/// `#[derive(Deserialize)]` wire struct with `deny_unknown_fields`, then a +/// validated constructor admission check. +/// +/// The binding name is passed explicitly (`wire` at every site) so the +/// construct expression can reference it across macro hygiene. +#[macro_export] +macro_rules! wire_deserialize { + ( + $type:ty, + $(#[$container:meta])* + $wire:ident { + $( $(#[$field_attr:meta])* $field:ident : $field_ty:ty ),* $(,)? + }, + $binding:ident, + $construct:expr + ) => { + impl<'de> serde::Deserialize<'de> for $type { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(serde::Deserialize)] + $(#[$container])* + struct $wire { + $( $(#[$field_attr])* $field: $field_ty, )* + } + let $binding = $wire::deserialize(deserializer)?; + $construct + } + } + }; +} pub mod audio; pub mod audit_wire; From 96fef8256ab21753144f6a6e6185f46b88c29e4a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:19:23 -0700 Subject: [PATCH 623/726] refactor(d2b-provider-volume-local,d2b-resource-types): gate test-only surface behind test-support `d2b-provider-volume-local::testing` and the `d2b-resource-types` `assert_metadata_registration` assertion are test-only: the doubles module is scripted by four of its crate's suites and one daemon unit test, and the assertion by the eleven per-type registration suites, while no production path reaches either. Both now compile only for the owning crate's own tests or for consumers that enable `test-support`, and the assertion-only imports in the resource-types metadata module move under the same predicate so the ungated build stays warning-clean. Consumers follow the house shape. `d2bd` and the eleven registration crates enable the feature from their dev-dependencies, and the registration test targets depend on the `_test_support` bazel variants instead of the plain libraries. The four volume-local suites that script the doubles declare `required-features = ["test-support"]`, so a plain `cargo test` skips them instead of failing to compile. --- changelog.d/w5-25-test-support-gating.md | 7 ++++ packages/d2b-provider-command/BUILD.bazel | 4 +-- packages/d2b-provider-command/Cargo.toml | 6 ++++ .../d2b-provider-emergency-policy/BUILD.bazel | 4 +-- .../d2b-provider-emergency-policy/Cargo.toml | 6 ++++ packages/d2b-provider-operation/BUILD.bazel | 4 +-- packages/d2b-provider-operation/Cargo.toml | 6 ++++ packages/d2b-provider-quota/BUILD.bazel | 4 +-- packages/d2b-provider-quota/Cargo.toml | 1 + .../d2b-provider-resource-export/BUILD.bazel | 4 +-- .../d2b-provider-resource-export/Cargo.toml | 1 + .../d2b-provider-resource-import/BUILD.bazel | 4 +-- .../d2b-provider-resource-import/Cargo.toml | 1 + .../d2b-provider-role-binding/BUILD.bazel | 4 +-- packages/d2b-provider-role-binding/Cargo.toml | 6 ++++ packages/d2b-provider-role/BUILD.bazel | 4 +-- packages/d2b-provider-role/Cargo.toml | 1 + .../d2b-provider-seccomp-profile/BUILD.bazel | 4 +-- .../d2b-provider-seccomp-profile/Cargo.toml | 6 ++++ .../d2b-provider-volume-local/BUILD.bazel | 9 +++--- packages/d2b-provider-volume-local/Cargo.toml | 32 +++++++++++++++++++ packages/d2b-provider-volume-local/src/lib.rs | 7 ++++ packages/d2b-provider-zone-link/BUILD.bazel | 4 +-- packages/d2b-provider-zone-link/Cargo.toml | 6 ++++ packages/d2b-provider-zone/BUILD.bazel | 4 +-- packages/d2b-provider-zone/Cargo.toml | 6 ++++ packages/d2b-resource-types/Cargo.toml | 6 ++++ packages/d2b-resource-types/src/lib.rs | 7 +++- packages/d2b-resource-types/src/metadata.rs | 7 ++++ packages/d2bd/Cargo.toml | 2 +- 30 files changed, 139 insertions(+), 28 deletions(-) create mode 100644 changelog.d/w5-25-test-support-gating.md diff --git a/changelog.d/w5-25-test-support-gating.md b/changelog.d/w5-25-test-support-gating.md new file mode 100644 index 000000000..595cd4eb9 --- /dev/null +++ b/changelog.d/w5-25-test-support-gating.md @@ -0,0 +1,7 @@ +### Fixed + +- The `d2b-provider-volume-local` `testing` doubles module and the + `d2b-resource-types` `assert_metadata_registration` assertion now compile + only for the owning crate's own tests or for consumers that enable the + `test-support` feature, so neither test-only helper is part of the + production library or the crate root surface any more. diff --git a/packages/d2b-provider-command/BUILD.bazel b/packages/d2b-provider-command/BUILD.bazel index 442292de9..0ab2e7e97 100644 --- a/packages/d2b-provider-command/BUILD.bazel +++ b/packages/d2b-provider-command/BUILD.bazel @@ -43,8 +43,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_command", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_command_test_support", "//packages/d2b-contracts-resource:d2b_contracts_resource",] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-command/Cargo.toml b/packages/d2b-provider-command/Cargo.toml index 23494832f..de7d9c37e 100644 --- a/packages/d2b-provider-command/Cargo.toml +++ b/packages/d2b-provider-command/Cargo.toml @@ -24,4 +24,10 @@ serde.workspace = true serde_json.workspace = true [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-emergency-policy/BUILD.bazel b/packages/d2b-provider-emergency-policy/BUILD.bazel index fdf652dea..eca1c79d6 100644 --- a/packages/d2b-provider-emergency-policy/BUILD.bazel +++ b/packages/d2b-provider-emergency-policy/BUILD.bazel @@ -41,8 +41,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_emergency_policy", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_emergency_policy_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-emergency-policy/Cargo.toml b/packages/d2b-provider-emergency-policy/Cargo.toml index efb0b1816..fa7ed7a7e 100644 --- a/packages/d2b-provider-emergency-policy/Cargo.toml +++ b/packages/d2b-provider-emergency-policy/Cargo.toml @@ -20,4 +20,10 @@ test-support = [] d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-operation/BUILD.bazel b/packages/d2b-provider-operation/BUILD.bazel index 0b8452623..efb8b8f5b 100644 --- a/packages/d2b-provider-operation/BUILD.bazel +++ b/packages/d2b-provider-operation/BUILD.bazel @@ -43,8 +43,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_operation", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_operation_test_support", "//packages/d2b-contracts-resource:d2b_contracts_resource",] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-operation/Cargo.toml b/packages/d2b-provider-operation/Cargo.toml index 4efd0713c..31d793803 100644 --- a/packages/d2b-provider-operation/Cargo.toml +++ b/packages/d2b-provider-operation/Cargo.toml @@ -24,4 +24,10 @@ serde.workspace = true serde_json.workspace = true [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-quota/BUILD.bazel b/packages/d2b-provider-quota/BUILD.bazel index 383dff7b1..a992da8b3 100644 --- a/packages/d2b-provider-quota/BUILD.bazel +++ b/packages/d2b-provider-quota/BUILD.bazel @@ -43,8 +43,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_quota", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_quota_test_support", "//packages/d2b-contracts-resource:d2b_contracts_resource",] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-quota/Cargo.toml b/packages/d2b-provider-quota/Cargo.toml index 890dc2cb0..b71d8a6ae 100644 --- a/packages/d2b-provider-quota/Cargo.toml +++ b/packages/d2b-provider-quota/Cargo.toml @@ -23,6 +23,7 @@ schemars.workspace = true serde.workspace = true [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [[test]] diff --git a/packages/d2b-provider-resource-export/BUILD.bazel b/packages/d2b-provider-resource-export/BUILD.bazel index cd7b72cac..f769e6361 100644 --- a/packages/d2b-provider-resource-export/BUILD.bazel +++ b/packages/d2b-provider-resource-export/BUILD.bazel @@ -42,8 +42,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_resource_export", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_resource_export_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-resource-export/Cargo.toml b/packages/d2b-provider-resource-export/Cargo.toml index c98e79f83..3f8a3daef 100644 --- a/packages/d2b-provider-resource-export/Cargo.toml +++ b/packages/d2b-provider-resource-export/Cargo.toml @@ -20,6 +20,7 @@ test-support = [] d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [[test]] diff --git a/packages/d2b-provider-resource-import/BUILD.bazel b/packages/d2b-provider-resource-import/BUILD.bazel index 416297024..f807440d0 100644 --- a/packages/d2b-provider-resource-import/BUILD.bazel +++ b/packages/d2b-provider-resource-import/BUILD.bazel @@ -42,8 +42,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_resource_import", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_resource_import_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-resource-import/Cargo.toml b/packages/d2b-provider-resource-import/Cargo.toml index 125c0c5f0..4c36061cd 100644 --- a/packages/d2b-provider-resource-import/Cargo.toml +++ b/packages/d2b-provider-resource-import/Cargo.toml @@ -20,6 +20,7 @@ test-support = [] d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [[test]] diff --git a/packages/d2b-provider-role-binding/BUILD.bazel b/packages/d2b-provider-role-binding/BUILD.bazel index b58154132..3a4299932 100644 --- a/packages/d2b-provider-role-binding/BUILD.bazel +++ b/packages/d2b-provider-role-binding/BUILD.bazel @@ -42,8 +42,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_role_binding", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_role_binding_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-role-binding/Cargo.toml b/packages/d2b-provider-role-binding/Cargo.toml index 4ad587f93..879a2816b 100644 --- a/packages/d2b-provider-role-binding/Cargo.toml +++ b/packages/d2b-provider-role-binding/Cargo.toml @@ -20,4 +20,10 @@ test-support = [] d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-role/BUILD.bazel b/packages/d2b-provider-role/BUILD.bazel index 3722733b6..f887a1a75 100644 --- a/packages/d2b-provider-role/BUILD.bazel +++ b/packages/d2b-provider-role/BUILD.bazel @@ -45,8 +45,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_role", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_role_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-role/Cargo.toml b/packages/d2b-provider-role/Cargo.toml index 2fc6c44ad..65d2b0eb6 100644 --- a/packages/d2b-provider-role/Cargo.toml +++ b/packages/d2b-provider-role/Cargo.toml @@ -21,6 +21,7 @@ d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0- d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [[test]] diff --git a/packages/d2b-provider-seccomp-profile/BUILD.bazel b/packages/d2b-provider-seccomp-profile/BUILD.bazel index ed03de819..301e0a6f7 100644 --- a/packages/d2b-provider-seccomp-profile/BUILD.bazel +++ b/packages/d2b-provider-seccomp-profile/BUILD.bazel @@ -44,8 +44,8 @@ d2b_rust_test( srcs = ["tests/registration.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_seccomp_profile", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_seccomp_profile_test_support", "//packages/d2b-contracts-resource:d2b_contracts_resource",] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-seccomp-profile/Cargo.toml b/packages/d2b-provider-seccomp-profile/Cargo.toml index b2ef4e902..411e00afb 100644 --- a/packages/d2b-provider-seccomp-profile/Cargo.toml +++ b/packages/d2b-provider-seccomp-profile/Cargo.toml @@ -23,5 +23,11 @@ schemars.workspace = true serde.workspace = true [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } serde_json.workspace = true + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-volume-local/BUILD.bazel b/packages/d2b-provider-volume-local/BUILD.bazel index be4e743bb..de5eca93d 100644 --- a/packages/d2b-provider-volume-local/BUILD.bazel +++ b/packages/d2b-provider-volume-local/BUILD.bazel @@ -44,6 +44,7 @@ d2b_rust_library( name = "d2b_provider_volume_local_test_support", srcs = glob(["src/**/*.rs"], allow_empty = True), compile_data = ["Cargo.toml"], + crate_features = ["test-support"], crate_name = "d2b_provider_volume_local", deps = [ "//packages/d2b-core:d2b_core_test_support", @@ -58,10 +59,10 @@ d2b_rust_test( srcs = ["tests/layout_conformance.rs"], compile_data = ["Cargo.toml"], deps = [ - "//packages/d2b-core:d2b_core", + "//packages/d2b-core:d2b_core_test_support", "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_volume_local", + ":d2b_provider_volume_local_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -116,7 +117,7 @@ d2b_rust_test( deps = [ "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_volume_local", + ":d2b_provider_volume_local_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -127,7 +128,7 @@ d2b_rust_test( deps = [ "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_volume_local", + ":d2b_provider_volume_local_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-volume-local/Cargo.toml b/packages/d2b-provider-volume-local/Cargo.toml index 3d2d8a221..6123efe4b 100644 --- a/packages/d2b-provider-volume-local/Cargo.toml +++ b/packages/d2b-provider-volume-local/Cargo.toml @@ -13,6 +13,16 @@ disallowed_methods = "deny" await_holding_lock = "deny" await_holding_refcell_ref = "deny" +# `testing` is needed both by external crates (which opt in via the +# `test-support` feature) and by this crate's OWN tests. Gating on +# `any(test, feature = "test-support")` makes the module available +# automatically when compiling this crate's unit tests, so +# `cargo test -p d2b-provider-volume-local` works without anyone having to +# remember `--features test-support`; the integration tests that script the +# doubles require the feature explicitly. +[features] +test-support = [] + [dependencies] d2b-core = { path = "../d2b-core", version = "0.0.0-bootstrap" } d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } @@ -34,3 +44,25 @@ d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0- d2b-provider-network-local = { path = "../d2b-provider-network-local", version = "0.0.0-bootstrap" } # The anchored adapter's in-module tests materialize roots in temp dirs. tempfile = "3" + +# These suites script the `testing` doubles, so they need the feature gate +# open; `cargo test -p d2b-provider-volume-local` skips them otherwise. +[[test]] +name = "layout_conformance" +path = "tests/layout_conformance.rs" +required-features = ["test-support"] + +[[test]] +name = "store_view_and_swtpm" +path = "tests/store_view_and_swtpm.rs" +required-features = ["test-support"] + +[[test]] +name = "views_and_sharing" +path = "tests/views_and_sharing.rs" +required-features = ["test-support"] + +[[test]] +name = "volume_effect_adapter" +path = "tests/volume_effect_adapter.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-volume-local/src/lib.rs b/packages/d2b-provider-volume-local/src/lib.rs index 8f840cbcb..270ba7e31 100644 --- a/packages/d2b-provider-volume-local/src/lib.rs +++ b/packages/d2b-provider-volume-local/src/lib.rs @@ -43,6 +43,13 @@ pub mod diagnostics; pub mod effect_port; pub mod lock; pub mod marker; + +// `testing` is needed both by external crates (which opt in via the +// `test-support` feature) and by this crate's own tests. Gating on +// `any(test, feature = "test-support")` makes it available automatically +// when compiling this crate's unit tests, and the `test-support`-gated +// integration tests in `tests/` pick it up through the feature they require. +#[cfg(any(test, feature = "test-support"))] pub mod testing; pub use adapter::{ diff --git a/packages/d2b-provider-zone-link/BUILD.bazel b/packages/d2b-provider-zone-link/BUILD.bazel index 91301ab85..4c06ee4bd 100644 --- a/packages/d2b-provider-zone-link/BUILD.bazel +++ b/packages/d2b-provider-zone-link/BUILD.bazel @@ -46,8 +46,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_zone_link", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_zone_link_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-zone-link/Cargo.toml b/packages/d2b-provider-zone-link/Cargo.toml index e95bc87b9..20e1f534c 100644 --- a/packages/d2b-provider-zone-link/Cargo.toml +++ b/packages/d2b-provider-zone-link/Cargo.toml @@ -24,4 +24,10 @@ d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = serde_json.workspace = true [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-zone/BUILD.bazel b/packages/d2b-provider-zone/BUILD.bazel index ae375592d..0225d78fc 100644 --- a/packages/d2b-provider-zone/BUILD.bazel +++ b/packages/d2b-provider-zone/BUILD.bazel @@ -46,8 +46,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - "//packages/d2b-resource-types:d2b_resource_types", - ":d2b_provider_zone", + "//packages/d2b-resource-types:d2b_resource_types_test_support", + ":d2b_provider_zone_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-zone/Cargo.toml b/packages/d2b-provider-zone/Cargo.toml index 164e22849..26cbb7878 100644 --- a/packages/d2b-provider-zone/Cargo.toml +++ b/packages/d2b-provider-zone/Cargo.toml @@ -22,4 +22,10 @@ d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstra d2b-contracts-zone-session = { path = "../d2b-contracts-zone-session", version = "0.0.0-bootstrap" } [dev-dependencies] +d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } + +[[test]] +name = "registration" +path = "tests/registration.rs" +required-features = ["test-support"] diff --git a/packages/d2b-resource-types/Cargo.toml b/packages/d2b-resource-types/Cargo.toml index 67b55589d..d387af2af 100644 --- a/packages/d2b-resource-types/Cargo.toml +++ b/packages/d2b-resource-types/Cargo.toml @@ -9,6 +9,12 @@ license.workspace = true workspace = true [features] +# `assert_metadata_registration` is needed by the eleven per-type crates' +# `tests/registration.rs` suites (which opt in via the `test-support` feature) +# and by this crate's own tests. Gating on `any(test, feature = "test-support")` +# makes the helper available automatically when compiling this crate's tests, +# so `cargo test -p d2b-resource-types` works without anyone having to +# remember `--features test-support`. test-support = [] [dependencies] diff --git a/packages/d2b-resource-types/src/lib.rs b/packages/d2b-resource-types/src/lib.rs index e340e11ed..2b0fba482 100644 --- a/packages/d2b-resource-types/src/lib.rs +++ b/packages/d2b-resource-types/src/lib.rs @@ -27,7 +27,12 @@ mod startup; pub use allowed_sources::AllowedSources; pub use child_creation::{ChildCreation, ChildCustody}; pub use descriptor::{CONVERTED_TYPE_VERBS, DriverDescriptor}; -pub use metadata::{assert_metadata_registration, metadata_descriptor}; +// The registration assertion drives the registry through a real plane open, +// so it is test-only: this crate's own tests reach it through `cfg(test)`, +// consumers through the `test-support` feature their test targets enable. +#[cfg(any(test, feature = "test-support"))] +pub use metadata::assert_metadata_registration; +pub use metadata::metadata_descriptor; pub use operation::{ KernelCaller, OperationCtx, OperationDef, OperationFailure, OperationHandler, OperationResult, RunnerLookup, ValidatedPayload, diff --git a/packages/d2b-resource-types/src/metadata.rs b/packages/d2b-resource-types/src/metadata.rs index 1fc356339..6373bf36d 100644 --- a/packages/d2b-resource-types/src/metadata.rs +++ b/packages/d2b-resource-types/src/metadata.rs @@ -18,10 +18,12 @@ use std::sync::Arc; +#[cfg(any(test, feature = "test-support"))] use d2b_resource_runtime::identity::ResourceKey; use d2b_resource_runtime::metadata::{ METADATA_EXECUTION_DOMAINS, MetadataDriverFactory, metadata_spec_decoder, }; +#[cfg(any(test, feature = "test-support"))] use d2b_resource_runtime::provider::{ProviderDirectory, ProviderDirectoryError}; use crate::{AllowedSources, CONVERTED_TYPE_VERBS, DriverDescriptor, WellKnownType}; @@ -69,6 +71,11 @@ pub fn metadata_descriptor(resource_type: WellKnownType) -> DriverDescriptor { /// This is the assertion every per-type crate's registration test runs: the /// coverage lives here once, and each crate contributes the one type it /// declares. +/// +/// The assertion is test-only: every caller is a `tests/registration.rs` +/// suite, so it is compiled only for this crate's own tests or for consumers +/// that opt in through the `test-support` feature. +#[cfg(any(test, feature = "test-support"))] pub async fn assert_metadata_registration(descriptor: &DriverDescriptor, expected: WellKnownType) { assert_eq!(descriptor.resource_type, expected); let type_name = descriptor.resource_type.to_resource_type_name(); diff --git a/packages/d2bd/Cargo.toml b/packages/d2bd/Cargo.toml index 5cad7b554..89d4fcd67 100644 --- a/packages/d2bd/Cargo.toml +++ b/packages/d2bd/Cargo.toml @@ -121,7 +121,7 @@ d2b-core = { path = "../d2b-core", version = "0.0.0-bootstrap", features = ["tes d2b-core-controller = { path = "../d2b-core-controller", version = "0.0.0-bootstrap", features = ["test-support"] } d2b-provider-display-wayland = { path = "../d2b-provider-display-wayland", version = "0.0.0-bootstrap", features = ["test-support"] } d2b-provider-guest = { path = "../d2b-provider-guest", version = "0.0.0-bootstrap", features = ["test-support"] } -d2b-provider-volume-local = { path = "../d2b-provider-volume-local", version = "0.0.0-bootstrap" } +d2b-provider-volume-local = { path = "../d2b-provider-volume-local", version = "0.0.0-bootstrap", features = ["test-support"] } d2b-provider-process = { path = "../d2b-provider-process", version = "0.0.0-bootstrap", features = ["test-support"] } d2b-provider-volume = { path = "../d2b-provider-volume", version = "0.0.0-bootstrap", features = ["test-support"] } d2b-provider-volume-binding = { path = "../d2b-provider-volume-binding", version = "0.0.0-bootstrap", features = ["test-support"] } From 564cc6d008e0adbc39b6c21617b8aa7af6483e2a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:23:26 -0700 Subject: [PATCH 624/726] refactor(d2bd-runtime): narrow Arc out of public surfaces Public signatures and fields stop handing out shared pointers the callee never needed: - `ConsoleSession::ring()` returns `&Mutex` instead of `&Arc>` (its three call sites only `try_lock`), and `ConsoleRing::notify()` is gone: the ring's wake handle is cloned out of the lock guard internally, and waiters keep taking the owned handle from `ConsoleSessionTable::read_output` / `ring_notify`. - `DaemonAuditLog.captured` is private behind `captured()` returning `&Mutex>`; the field stays an `Arc` because the appender thread shares it. - `TargetBinding::new` takes the `TargetDirectory` handle by value instead of an `Arc` (the directory is itself the cheap shared handle every binding of a Zone clones), and `TargetBinding.directory` follows. - `SkAcceptHandle.state` is private behind `state()` returning `&parking_lot::Mutex`; the field stays an `Arc` because the accept loop moves a clone of it into the per-VM thread. The remaining `Arc` constructor parameters stay, each because the value is genuinely shared: cloned into a `tokio::spawn` (endpoint effects, ttrpc client driver), held by a factory that clones it into every driver it creates (user effects), shared between an admission offer and the engine it admits (metrics sinks), cloned into a transport's reader half (unix observers), mutated by the test that built it (otel ingress clock), or fixed by `ResourceProviderFamily::decoder`'s own `Arc` return type (credential, volume-binding, wayland-policy, telemetry-binding spec decoders). --- changelog.d/w5-30-arc-leak-narrowing.md | 19 +++++++++++++ .../src/relay_service.rs | 9 ++++++- packages/d2b-resource-runtime/src/manager.rs | 4 +-- packages/d2b-resource-runtime/src/target.rs | 15 ++++++----- packages/d2bd-runtime/src/console_session.rs | 11 +++----- packages/d2bd-runtime/src/daemon_audit.rs | 27 +++++++++++++------ packages/d2bd/src/composition.rs | 8 +++--- 7 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 changelog.d/w5-30-arc-leak-narrowing.md diff --git a/changelog.d/w5-30-arc-leak-narrowing.md b/changelog.d/w5-30-arc-leak-narrowing.md new file mode 100644 index 000000000..58bcb9c1b --- /dev/null +++ b/changelog.d/w5-30-arc-leak-narrowing.md @@ -0,0 +1,19 @@ +### Changed + +- Public surfaces stop handing callers a shared pointer they do not need. + `ConsoleSession::ring()` now returns `&tokio::sync::Mutex` + instead of `&Arc>`, the ring's wake handle + is no longer reachable through `ConsoleRing::notify()` (waiters take the + owned handle the table already gives them through + `ConsoleSessionTable::read_output` and `ConsoleSessionTable::ring_notify`), + `TargetBinding::new` takes the `TargetDirectory` handle by value instead of + an `Arc` (the directory is itself the cheap shared handle + every binding of a Zone clones), `DaemonAuditLog.captured` is private behind + `DaemonAuditLog::captured()` returning `&Mutex>`, and + `SkAcceptHandle.state` is private behind `SkAcceptHandle::state()` returning + `&parking_lot::Mutex`. Every remaining `Arc` in these + signatures stays because the value is genuinely shared: it is cloned across + a `tokio::spawn` boundary, held by a factory that hands the same port to + every driver it creates, shared between an admission offer and the session + engine it admits, or fixed by a trait signature that already returns a + shared handle. diff --git a/packages/d2b-provider-device-security-key/src/relay_service.rs b/packages/d2b-provider-device-security-key/src/relay_service.rs index a247c2cda..fdddee5ed 100644 --- a/packages/d2b-provider-device-security-key/src/relay_service.rs +++ b/packages/d2b-provider-device-security-key/src/relay_service.rs @@ -296,11 +296,18 @@ impl Drop for SkAcceptAbort { /// One registered VM relay: its ceremony state and its accept-loop handle. pub struct SkAcceptHandle { /// The VM's relay ceremony state, shared with the connection loop. - pub state: Arc>, + state: Arc>, /// The accept loop's stop handle. pub abort: SkAcceptAbort, } +impl SkAcceptHandle { + /// The VM's relay ceremony state, shared with the connection loop. + pub fn state(&self) -> &parking_lot::Mutex { + &self.state + } +} + #[derive(Debug, Default)] /// The host relay's bounded per-VM session and physical-key table. /// diff --git a/packages/d2b-resource-runtime/src/manager.rs b/packages/d2b-resource-runtime/src/manager.rs index edcfee94e..c9c6db767 100644 --- a/packages/d2b-resource-runtime/src/manager.rs +++ b/packages/d2b-resource-runtime/src/manager.rs @@ -670,7 +670,7 @@ impl ResourceManagerState { type_name: type_name.to_string(), message: error.to_string(), })?; - let target_binding = TargetBinding::new(Arc::clone(&self.targets), assignment); + let target_binding = TargetBinding::new((*self.targets).clone(), assignment); let args = ResourceActorArgs { row: row.clone(), target: target_binding.handle(), @@ -1890,7 +1890,7 @@ mod tests { }) .expect("notify reconnect"); wait_status(&h.client, &k, ResourceStatus::Ready).await; - let binding = TargetBinding::new(Arc::clone(&targets), assignment); + let binding = TargetBinding::new((*targets).clone(), assignment); assert_eq!( binding.guest().expect("guest handle").session_generation(), Some(1), diff --git a/packages/d2b-resource-runtime/src/target.rs b/packages/d2b-resource-runtime/src/target.rs index afae3a377..2d704b6a0 100644 --- a/packages/d2b-resource-runtime/src/target.rs +++ b/packages/d2b-resource-runtime/src/target.rs @@ -479,14 +479,17 @@ pub trait TargetResolver: Send + Sync + 'static { /// trusting a channel the caller kept. #[derive(Debug, Clone)] pub struct TargetBinding { - directory: Arc, + directory: TargetDirectory, assignment: TargetAssignment, } impl TargetBinding { /// Bind one resource's recorded assignment to the directory it resolves /// through. - pub fn new(directory: Arc, assignment: TargetAssignment) -> Self { + /// + /// The directory is the per-Zone handle every binding of that Zone + /// shares, so the binding takes its own cheap clone of it. + pub fn new(directory: TargetDirectory, assignment: TargetAssignment) -> Self { Self { directory, assignment } } @@ -541,7 +544,7 @@ impl TargetBinding { let rebound = outcome.handle().clone(); let mut assignment = self.assignment.clone(); assignment.target = ResolvedTarget::Guest(rebound); - Ok((TargetBinding { directory: Arc::clone(&self.directory), assignment }, outcome)) + Ok((TargetBinding { directory: self.directory.clone(), assignment }, outcome)) } } @@ -1618,7 +1621,7 @@ mod tests { #[tokio::test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn a_target_binding_never_trusts_a_channel_it_kept() { - let directory = Arc::new(TargetDirectory::new()); + let directory = TargetDirectory::new(); let runtime = Arc::new(GuestTargetRuntime::new(guest())); runtime.bind_session(1).expect("bind session"); directory @@ -1627,7 +1630,7 @@ mod tests { let source = key("Process", "worker"); let assignment = directory.assign(&source, &[7; 16], 2, "Guest/work-vm").expect("assign guest"); - let binding = TargetBinding::new(Arc::clone(&directory), assignment); + let binding = TargetBinding::new(directory.clone(), assignment); binding.realize(spec(), digest(), "/run/d2b/worker.sock").await.expect("realize"); assert_eq!( @@ -1665,7 +1668,7 @@ mod tests { #[tokio::test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn a_host_binding_has_no_guest_realization_path() { - let directory = Arc::new(TargetDirectory::new()); + let directory = TargetDirectory::new(); let source = key("Process", "hosted"); let assignment = directory.assign(&source, &[1; 16], 1, "Host/main-host").expect("assign host"); diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index c74c2bff3..f4fd026e9 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -73,11 +73,6 @@ impl ConsoleRing { pub fn base_offset(&self) -> u64 { self.ring.base_offset() } - - /// The wake handle waiters park on. - pub fn notify(&self) -> &Arc { - &self.notify - } } impl Default for ConsoleRing { @@ -119,7 +114,7 @@ impl ConsoleSession { } /// Shared ring buffer for this session's console output. - pub fn ring(&self) -> &Arc> { + pub fn ring(&self) -> &tokio::sync::Mutex { &self.ring } @@ -314,7 +309,7 @@ impl ConsoleSessionTable { return None; }; let snap = guard.read_at(offset, max_len); - let notify = Arc::clone(guard.notify()); + let notify = Arc::clone(&guard.notify); (snap, notify) }; Some(ConsoleReadOutput { @@ -362,7 +357,7 @@ impl ConsoleSessionTable { let Ok(guard) = session.ring().try_lock() else { return None; }; - Some(Arc::clone(guard.notify())) + Some(Arc::clone(&guard.notify)) } } diff --git a/packages/d2bd-runtime/src/daemon_audit.rs b/packages/d2bd-runtime/src/daemon_audit.rs index de22ac3a0..3e6418b34 100644 --- a/packages/d2bd-runtime/src/daemon_audit.rs +++ b/packages/d2bd-runtime/src/daemon_audit.rs @@ -512,8 +512,10 @@ pub struct DaemonAuditLog { /// Queue into the appender thread. `None` only when the appender could /// not start, which fails every write closed. sink: Option, + /// Capture-only seat of the audit lines this log accepted, shared with + /// the appender thread. #[cfg(any(test, feature = "test-support"))] - pub captured: Arc>>, + captured: Arc>>, } /// The appender's queue and its thread handle. @@ -880,6 +882,15 @@ impl DaemonAuditLog { Self::with_appender(Some(state_dir.into()), false, true) } + /// The capture-only seat of the audit lines this log accepted. + /// + /// The lines are appended by the single appender thread, so the guard is + /// the only way to read a consistent set of them. + #[cfg(any(test, feature = "test-support"))] + pub fn captured(&self) -> &Mutex> { + &self.captured + } + /// Start the single appender and return the handle over its queue. /// /// A failed spawn is fail-closed: the sink stays `None`, so every later @@ -1942,7 +1953,7 @@ mod tests { .expect("write api-ready-timeout event"); // Assert the in-memory captured record has the expected fields. - let records = log.captured.lock().expect("lock captured"); + let records = log.captured().lock().expect("lock captured"); assert_eq!( records.len(), 1, @@ -2053,7 +2064,7 @@ mod tests { }) .expect("write terminated event"); - let records = log.captured.lock().expect("lock captured"); + let records = log.captured().lock().expect("lock captured"); assert_eq!(records.len(), 2, "expected two captured lifecycle records"); for line in records.iter() { @@ -2124,7 +2135,7 @@ mod tests { }) .expect("write provider-neutral shell event"); - let records = log.captured.lock().expect("lock captured"); + let records = log.captured().lock().expect("lock captured"); assert_eq!(records.len(), 1, "expected one unified shell record"); for line in records.iter() { assert!( @@ -2189,7 +2200,7 @@ mod tests { }) .expect("write detached kill event"); - let records = log.captured.lock().expect("lock captured"); + let records = log.captured().lock().expect("lock captured"); assert_eq!(records.len(), 2, "expected two detached audit records"); for line in records.iter() { @@ -2378,7 +2389,7 @@ mod tests { .expect_err("blocked destination must return an io error"); assert_eq!(error.kind(), io::ErrorKind::Other); assert_eq!(error.to_string(), "daemon audit unavailable"); - assert!(log.captured.lock().expect("captured").is_empty()); + assert!(log.captured().lock().expect("captured").is_empty()); } #[test] @@ -2437,7 +2448,7 @@ mod tests { DaemonAuditAuthority::Authoritative, ); assert!(result.is_ok()); - assert_eq!(log.captured.lock().unwrap().len(), 1); + assert_eq!(log.captured().lock().unwrap().len(), 1); } #[test] @@ -2652,7 +2663,7 @@ mod tests { }; assert!(!format!("{event:?}").contains("target-secret-canary")); log.write_event(event).unwrap(); - let line = log.captured.lock().unwrap().last().cloned().unwrap(); + let line = log.captured().lock().unwrap().last().cloned().unwrap(); for canary in [ "target-secret-canary", "item-secret-canary", diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..ca159762d 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -8638,7 +8638,7 @@ mod workload_observability_tests { fn captured_events(state: &ServerState) -> Vec { state .daemon_audit - .captured + .captured() .lock() .expect("audit capture") .iter() @@ -11284,7 +11284,7 @@ async fn adopt_guest_target_assignments( continue; }; let binding = d2b_resource_runtime::target::TargetBinding::new( - std::sync::Arc::clone(directory), + directory.as_ref().clone(), assignment, ); match binding.adopt().await { @@ -11360,7 +11360,7 @@ pub(crate) async fn target_local_mount_observed( return false; } let binding = d2b_resource_runtime::target::TargetBinding::new( - std::sync::Arc::clone(directory), + directory.as_ref().clone(), assignment, ); let Ok((binding, _)) = binding.adopt().await else { @@ -28806,7 +28806,7 @@ mod broker_dispatch_tests { let captured = state .daemon_audit - .captured + .captured() .lock() .expect("lock captured records"); assert_eq!( From 78a4df5bed2ab476de422e02caa28cc8bc2da8e2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:24:09 -0700 Subject: [PATCH 625/726] refactor(d2b-process-conformance): gate the test doubles behind test-support The `testing` module (scripted effect port, fixtures, port-call recorders) is test-only apparatus that shipped in the production library surface. It now sits behind a `test-support` feature; consumers enable the feature through dev-dependencies and the Bazel `_test_support` library variants, and every Bazel test target that touches `testing` compiles its package's own `_test_support` variant, so a single `d2b_process_conformance` rlib reaches each action instead of two conflicting versions. The minijail package picks up the crate-level `_test` target its sibling process providers already carried. The `ProcessLaunchEffectPort` and `ProcessProvider` methods are declared as `async fn` in place of the RPITIT `impl Future + Send` form, with the default bodies rewritten as `async { }` blocks; implementors already wrote `async fn`. --- .../w5-20-process-conformance-surface.md | 4 ++ packages/d2b-process-conformance/BUILD.bazel | 1 + packages/d2b-process-conformance/Cargo.toml | 3 ++ packages/d2b-process-conformance/src/lib.rs | 1 + packages/d2b-process-conformance/src/port.rs | 41 +++++++++---------- .../d2b-process-conformance/src/provider.rs | 38 ++++++++--------- packages/d2b-process-conformance/src/suite.rs | 19 ++++++++- .../d2b-provider-process-minijail/BUILD.bazel | 19 ++++++--- .../d2b-provider-process-minijail/Cargo.toml | 3 ++ .../d2b-provider-process-systemd/BUILD.bazel | 12 +++--- .../d2b-provider-process-systemd/Cargo.toml | 1 + packages/d2b-provider-process/BUILD.bazel | 2 +- packages/d2b-provider-process/Cargo.toml | 1 + packages/d2b-provider-supervisor/BUILD.bazel | 14 +++---- packages/d2b-provider-supervisor/Cargo.toml | 1 + packages/d2bd/Cargo.toml | 1 + packages/d2bd/src/interaction_composition.rs | 4 +- 17 files changed, 101 insertions(+), 64 deletions(-) create mode 100644 changelog.d/w5-20-process-conformance-surface.md diff --git a/changelog.d/w5-20-process-conformance-surface.md b/changelog.d/w5-20-process-conformance-surface.md new file mode 100644 index 000000000..d03dc084b --- /dev/null +++ b/changelog.d/w5-20-process-conformance-surface.md @@ -0,0 +1,4 @@ +### Fixed + +- The process-conformance test doubles and fixtures (`testing` module) now ship behind a `test-support` feature instead of unconditionally in the production library surface; every in-tree consumer enables the feature through dev-dependencies and the Bazel `_test_support` variant, and the shared `suite` stays ungated as the crate's product. The Bazel consequence is a dependency-graph shape: the tests that touch `testing` (minijail, systemd, supervisor, provider-process, and the daemon library) now compile their package's own `_test_support` library variant and dropped the base package and base `d2b_process_conformance` entries, so exactly one `d2b_process_conformance` rlib reaches each of their actions instead of two conflicting versions; the test-support variants link `d2b_process_conformance_test_support`. +- The `ProcessLaunchEffectPort` and `ProcessProvider` trait methods are declared as `async fn` (the RPITIT `impl Future + Send` form is retired); default bodies are written as `async { ... }` blocks and the `ready(Err(...))` wrappers are dropped, with no change to implementors, which already wrote `async fn`. \ No newline at end of file diff --git a/packages/d2b-process-conformance/BUILD.bazel b/packages/d2b-process-conformance/BUILD.bazel index 023194007..afd215b0c 100644 --- a/packages/d2b-process-conformance/BUILD.bazel +++ b/packages/d2b-process-conformance/BUILD.bazel @@ -28,6 +28,7 @@ d2b_rust_library( name = "d2b_process_conformance_test_support", srcs = glob(["src/**/*.rs"], allow_empty = True), compile_data = ["Cargo.toml"], + crate_features = ["test-support"], crate_name = "d2b_process_conformance", visibility = ["//visibility:public"], deps = [ diff --git a/packages/d2b-process-conformance/Cargo.toml b/packages/d2b-process-conformance/Cargo.toml index 600d5f289..5e2d7e295 100644 --- a/packages/d2b-process-conformance/Cargo.toml +++ b/packages/d2b-process-conformance/Cargo.toml @@ -5,6 +5,9 @@ edition = "2024" publish = false license.workspace = true +[features] +test-support = [] + [lints.rust] unsafe_code = "forbid" diff --git a/packages/d2b-process-conformance/src/lib.rs b/packages/d2b-process-conformance/src/lib.rs index 916ccf5a1..4990fb499 100644 --- a/packages/d2b-process-conformance/src/lib.rs +++ b/packages/d2b-process-conformance/src/lib.rs @@ -34,6 +34,7 @@ mod terminal; mod ticket; pub mod suite; +#[cfg(any(test, feature = "test-support"))] pub mod testing; pub use error::ProcessConformanceError; diff --git a/packages/d2b-process-conformance/src/port.rs b/packages/d2b-process-conformance/src/port.rs index 5ba4de886..5ae94e094 100644 --- a/packages/d2b-process-conformance/src/port.rs +++ b/packages/d2b-process-conformance/src/port.rs @@ -8,7 +8,6 @@ //! effect owner, and the broker stays the sole privileged executor and //! independent audit owner of the mutation. -use std::future::Future; use std::os::fd::OwnedFd; use crate::error::ProcessConformanceError; @@ -105,40 +104,39 @@ pub enum StopClass { /// doubles. Every method acts on exactly one process identity; there is no /// broad sweep, no reuse, and no operation that names anything but the /// ticket and the derived opaque identity. +#[allow(async_fn_in_trait)] pub trait ProcessLaunchEffectPort: Send + Sync { /// Launch the ticket's process and return its verified identity and /// mandatory pidfd evidence. - fn launch( + async fn launch( &self, ticket: &LaunchTicket, - ) -> impl Future> + Send; + ) -> Result; /// Launch with owned descriptors that must be inherited by the child. /// /// Descriptor-bearing launches are opt-in at the concrete effect owner. /// Existing test doubles and descriptor-free owners reject a non-empty /// vector without changing their ordinary launch behavior. - fn launch_with_inherited_fds( + async fn launch_with_inherited_fds( &self, ticket: &LaunchTicket, inherited_fds: Vec, - ) -> impl Future> + Send { - async move { - if inherited_fds.is_empty() { - self.launch(ticket).await - } else { - drop(inherited_fds); - Err(ProcessConformanceError::InvalidTicket) - } + ) -> Result { + if inherited_fds.is_empty() { + self.launch(ticket).await + } else { + drop(inherited_fds); + Err(ProcessConformanceError::InvalidTicket) } } /// Observe whether a process for this ticket is already running, /// without opening a pidfd for it. - fn observe( + async fn observe( &self, ticket: &LaunchTicket, - ) -> impl Future, ProcessConformanceError>> + Send; + ) -> Result, ProcessConformanceError>; /// Probe whether the exact process is present without retaining any /// adoption handle or staged observation. @@ -146,25 +144,24 @@ pub trait ProcessLaunchEffectPort: Send + Sync { /// The default delegates to [`Self::observe`] for test ports and simple /// effect owners. Production adapters override it when adoption /// observation is stateful. - fn probe( + async fn probe( &self, ticket: &LaunchTicket, - ) -> impl Future, ProcessConformanceError>> + Send - { - self.observe(ticket) + ) -> Result, ProcessConformanceError> { + self.observe(ticket).await } /// Open a verified pidfd for a candidate whose identity the caller has /// already fully verified. - fn open_pidfd( + async fn open_pidfd( &self, candidate: &AdoptionCandidate, - ) -> impl Future> + Send; + ) -> Result; /// Stop exactly the named identity. - fn stop( + async fn stop( &self, identity: &ProcessIdentityDigest, class: StopClass, - ) -> impl Future> + Send; + ) -> Result<(), ProcessConformanceError>; } diff --git a/packages/d2b-process-conformance/src/provider.rs b/packages/d2b-process-conformance/src/provider.rs index 0aa3c7a27..88cd2aaaa 100644 --- a/packages/d2b-process-conformance/src/provider.rs +++ b/packages/d2b-process-conformance/src/provider.rs @@ -2,7 +2,6 @@ use std::collections::BTreeSet; use std::os::fd::OwnedFd; -use std::{future::Future, future::ready}; use d2b_contracts_resource::v3::execution_policy::{BoundedToken, ExecutionDomain}; @@ -88,53 +87,52 @@ pub enum AdoptionOutcome { } /// The provider-neutral Process Provider controller surface. +#[allow(async_fn_in_trait)] pub trait ProcessProvider: Send + Sync { /// Borrow this Provider's declared conformance profile. fn profile(&self) -> &ProcessProviderProfile; /// Validate the ticket and launch through the injected effect port. - fn launch( + async fn launch( &self, ticket: &LaunchTicket, - ) -> impl Future> + Send; + ) -> Result; /// Launch with owned descriptors for a Provider-specific child bootstrap. /// /// Providers that do not own a descriptor-bearing launch path reject a /// non-empty vector by default, preserving the ordinary launch contract. - fn launch_with_inherited_fds( + async fn launch_with_inherited_fds( &self, ticket: &LaunchTicket, inherited_fds: Vec, - ) -> impl Future> + Send { - async move { - if inherited_fds.is_empty() { - self.launch(ticket).await - } else { - drop(inherited_fds); - Err(ProcessConformanceError::InvalidTicket) - } + ) -> Result { + if inherited_fds.is_empty() { + self.launch(ticket).await + } else { + drop(inherited_fds); + Err(ProcessConformanceError::InvalidTicket) } } /// Re-establish ownership of an already running process after a /// controller restart, verifying identity before any pidfd is opened. - fn adopt( + async fn adopt( &self, ticket: &LaunchTicket, - ) -> impl Future> + Send; + ) -> Result; /// Stop exactly one verified process identity. /// /// The default is deliberately unavailable: a Provider must opt into the /// provider-specific stop proof rather than silently pretending that a /// generic signal completed teardown. - fn stop( + async fn stop( &self, _identity: &crate::identity::ProcessIdentityDigest, _class: StopClass, - ) -> impl Future> + Send { - ready(Err(ProcessConformanceError::StopUnavailable)) + ) -> Result<(), ProcessConformanceError> { + Err(ProcessConformanceError::StopUnavailable) } /// Stop and reap one uniquely identified stale process before replacement. @@ -142,10 +140,10 @@ pub trait ProcessProvider: Send + Sync { /// Providers must keep this path narrow: the candidate's exact identity /// evidence is supplied by the effect adapter, and ambiguity is never /// converted into a stop request. - fn stop_stale( + async fn stop_stale( &self, _candidate: &crate::port::AdoptionCandidate, - ) -> impl Future> + Send { - ready(Err(ProcessConformanceError::StopUnavailable)) + ) -> Result<(), ProcessConformanceError> { + Err(ProcessConformanceError::StopUnavailable) } } diff --git a/packages/d2b-process-conformance/src/suite.rs b/packages/d2b-process-conformance/src/suite.rs index 0535d70bd..da2cc8578 100644 --- a/packages/d2b-process-conformance/src/suite.rs +++ b/packages/d2b-process-conformance/src/suite.rs @@ -7,20 +7,29 @@ //! [`ProcessProviderProfile`](crate::ProcessProviderProfile) rather than //! branched on by name. +#[cfg(any(test, feature = "test-support"))] use std::collections::BTreeSet; +#[cfg(any(test, feature = "test-support"))] use d2b_contracts_resource::v3::ResourceRef; +#[cfg(any(test, feature = "test-support"))] use d2b_contracts_resource::v3::execution_policy::ExecutionDomain; use crate::error::ProcessConformanceError; -use crate::identity::{IdentityBinding, WaitReapOwner}; +use crate::identity::WaitReapOwner; +#[cfg(any(test, feature = "test-support"))] +use crate::identity::IdentityBinding; +#[cfg(any(test, feature = "test-support"))] use crate::provider::{AdoptionOutcome, ProcessProvider}; use crate::sandbox::{StopProof, validate_stop_proof}; +#[cfg(any(test, feature = "test-support"))] use crate::status::{AdoptionCondition, ProcessPhaseClass}; +#[cfg(any(test, feature = "test-support"))] use crate::testing::{PortCall, ScriptedEffectPort, block_on, fixtures}; use crate::ticket::LaunchTicket; /// Field or value fragments that must never appear in public status. +#[cfg(any(test, feature = "test-support"))] const FORBIDDEN_STATUS_FRAGMENTS: [&str; 12] = [ "pid", "pidfd", @@ -38,6 +47,7 @@ const FORBIDDEN_STATUS_FRAGMENTS: [&str; 12] = [ /// Build the two execution fixtures every Provider must handle /// identically: a physical Host and a VM Guest. +#[cfg(any(test, feature = "test-support"))] fn execution_refs() -> [ResourceRef; 2] { [ ResourceRef::parse("Host/host-system").expect("valid fixture ref"), @@ -48,6 +58,7 @@ fn execution_refs() -> [ResourceRef; 2] { /// A launch on a Host and on a Guest produces identical conformant status. /// /// The ResourceType and its status projection do not change with locality. +#[cfg(any(test, feature = "test-support"))] pub fn assert_launch_is_locality_neutral(provider: &P, provider_name: &str) { let profile = provider.profile(); let bindings: Vec = profile @@ -78,6 +89,7 @@ pub fn assert_launch_is_locality_neutral(provider: &P, provi } /// A ticket selecting a different Process Provider is rejected. +#[cfg(any(test, feature = "test-support"))] pub fn assert_foreign_provider_selection_is_rejected(provider: &P) { let bindings: Vec = provider .profile() @@ -99,6 +111,7 @@ pub fn assert_foreign_provider_selection_is_rejected(provide /// Every domain outside the Provider's declared support set is rejected, /// and a user-domain launch the Provider does support carries the exact /// `userRef` through to status. +#[cfg(any(test, feature = "test-support"))] pub fn assert_domain_support_matches_the_profile( provider: &P, provider_name: &str, @@ -140,6 +153,7 @@ pub fn assert_domain_support_matches_the_profile( /// A launch that establishes fewer identity bindings than the Provider /// requires fails closed and is never reported as running. +#[cfg(any(test, feature = "test-support"))] pub fn assert_incomplete_launch_identity_fails_closed(build: F, provider_name: &str) where P: ProcessProvider, @@ -172,6 +186,7 @@ where /// Adoption verifies every required identity binding *before* a pidfd is /// opened, and ambiguity quarantines instead of adopting. +#[cfg(any(test, feature = "test-support"))] pub fn assert_adoption_verifies_identity_before_opening_a_pidfd(build: F, provider_name: &str) where P: ProcessProvider, @@ -232,6 +247,7 @@ where /// The pidfd is opened only after identity verification, proven from the /// recorded effect-port call order. +#[cfg(any(test, feature = "test-support"))] pub fn assert_pidfd_open_follows_verification(port_calls: &[PortCall]) { let observe = port_calls .iter() @@ -294,6 +310,7 @@ pub fn assert_finalizer_requires_verified_stop(owner: WaitReapOwner) { /// Public status carries no PID, pidfd, unit name, cgroup, path, argv, /// environment, or numeric identity. +#[cfg(any(test, feature = "test-support"))] pub fn assert_status_is_redacted(provider: &P, provider_name: &str) { let bindings: Vec = provider .profile() diff --git a/packages/d2b-provider-process-minijail/BUILD.bazel b/packages/d2b-provider-process-minijail/BUILD.bazel index 1aa97d98a..afd0e5077 100644 --- a/packages/d2b-provider-process-minijail/BUILD.bazel +++ b/packages/d2b-provider-process-minijail/BUILD.bazel @@ -44,8 +44,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_process_minijail", - "//packages/d2b-process-conformance:d2b_process_conformance", + ":d2b_provider_process_minijail_test_support", + "//packages/d2b-process-conformance:d2b_process_conformance_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -55,8 +55,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_process_minijail", - "//packages/d2b-process-conformance:d2b_process_conformance", + ":d2b_provider_process_minijail_test_support", + "//packages/d2b-process-conformance:d2b_process_conformance_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -69,11 +69,18 @@ d2b_rust_test( deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - "//packages/d2b-process-conformance:d2b_process_conformance", - ":d2b_provider_process_minijail", + "//packages/d2b-process-conformance:d2b_process_conformance_test_support", + ":d2b_provider_process_minijail_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) +d2b_rust_test( + name = "d2b_provider_process_minijail_test", + compile_data = ["Cargo.toml"], + crate = ":d2b_provider_process_minijail", + deps = all_crate_deps(normal = True, normal_dev = True, cargo_only = True), +) + # keep filegroup( name = "cargo_workspace_sources", diff --git a/packages/d2b-provider-process-minijail/Cargo.toml b/packages/d2b-provider-process-minijail/Cargo.toml index d4a9e968b..3521b12e2 100644 --- a/packages/d2b-provider-process-minijail/Cargo.toml +++ b/packages/d2b-provider-process-minijail/Cargo.toml @@ -18,3 +18,6 @@ await_holding_refcell_ref = "deny" d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } d2b-process-conformance = { path = "../d2b-process-conformance", version = "0.0.0-bootstrap" } tracing = "0.1" + +[dev-dependencies] +d2b-process-conformance = { path = "../d2b-process-conformance", version = "0.0.0-bootstrap", features = ["test-support"] } diff --git a/packages/d2b-provider-process-systemd/BUILD.bazel b/packages/d2b-provider-process-systemd/BUILD.bazel index 3aaea6ad4..a4b0f44e2 100644 --- a/packages/d2b-provider-process-systemd/BUILD.bazel +++ b/packages/d2b-provider-process-systemd/BUILD.bazel @@ -66,8 +66,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_process_systemd", - "//packages/d2b-process-conformance:d2b_process_conformance", + ":d2b_provider_process_systemd_test_support", + "//packages/d2b-process-conformance:d2b_process_conformance_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -77,8 +77,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_process_systemd", - "//packages/d2b-process-conformance:d2b_process_conformance", + ":d2b_provider_process_systemd_test_support", + "//packages/d2b-process-conformance:d2b_process_conformance_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -110,8 +110,8 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - "//packages/d2b-process-conformance:d2b_process_conformance", - ":d2b_provider_process_systemd", + "//packages/d2b-process-conformance:d2b_process_conformance_test_support", + ":d2b_provider_process_systemd_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-process-systemd/Cargo.toml b/packages/d2b-provider-process-systemd/Cargo.toml index 682a9ab81..8760c5b83 100644 --- a/packages/d2b-provider-process-systemd/Cargo.toml +++ b/packages/d2b-provider-process-systemd/Cargo.toml @@ -31,4 +31,5 @@ tracing = "0.1" zbus = "5.16" [dev-dependencies] +d2b-process-conformance = { path = "../d2b-process-conformance", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync", "test-util", "time"] } diff --git a/packages/d2b-provider-process/BUILD.bazel b/packages/d2b-provider-process/BUILD.bazel index 6183efa90..a6bdaf82d 100644 --- a/packages/d2b-provider-process/BUILD.bazel +++ b/packages/d2b-provider-process/BUILD.bazel @@ -78,7 +78,7 @@ d2b_rust_library( d2b_rust_test( name = "d2b_provider_process_test", compile_data = ["Cargo.toml"], - crate = ":d2b_provider_process", + crate = ":d2b_provider_process_test_support", ) d2b_rust_test( diff --git a/packages/d2b-provider-process/Cargo.toml b/packages/d2b-provider-process/Cargo.toml index 42d5cc816..635d005c6 100644 --- a/packages/d2b-provider-process/Cargo.toml +++ b/packages/d2b-provider-process/Cargo.toml @@ -38,4 +38,5 @@ tracing = "0.1" test-support = [] [dev-dependencies] +d2b-process-conformance = { path = "../d2b-process-conformance", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync", "test-util", "time"] } diff --git a/packages/d2b-provider-supervisor/BUILD.bazel b/packages/d2b-provider-supervisor/BUILD.bazel index a27d82a72..819dd11e1 100644 --- a/packages/d2b-provider-supervisor/BUILD.bazel +++ b/packages/d2b-provider-supervisor/BUILD.bazel @@ -71,13 +71,13 @@ d2b_rust_test( deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", - ":d2b_provider_supervisor", + ":d2b_provider_supervisor_test_support", "//packages/d2b-contracts:d2b_contracts", "//packages/d2b-contracts-broker:d2b_contracts_broker", - "//packages/d2b-provider-process:d2b_provider_process", - "//packages/d2b-process-conformance:d2b_process_conformance", - "//packages/d2b-provider-process-minijail:d2b_provider_process_minijail", - "//packages/d2b-provider-process-systemd:d2b_provider_process_systemd", + "//packages/d2b-provider-process:d2b_provider_process_test_support", + "//packages/d2b-process-conformance:d2b_process_conformance_test_support", + "//packages/d2b-provider-process-minijail:d2b_provider_process_minijail_test_support", + "//packages/d2b-provider-process-systemd:d2b_provider_process_systemd_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) @@ -88,8 +88,8 @@ d2b_rust_test( "//:tests/golden/manifest_v04/baseline-vms.json", # keep "Cargo.toml", ], - crate = ":d2b_provider_supervisor", - deps = ["//packages/d2b-process-conformance:d2b_process_conformance", + crate = ":d2b_provider_supervisor_test_support", + deps = ["//packages/d2b-process-conformance:d2b_process_conformance_test_support", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-supervisor/Cargo.toml b/packages/d2b-provider-supervisor/Cargo.toml index 545763ffd..dd7520f09 100644 --- a/packages/d2b-provider-supervisor/Cargo.toml +++ b/packages/d2b-provider-supervisor/Cargo.toml @@ -28,6 +28,7 @@ sha2 = { workspace = true } tokio = { workspace = true, features = ["sync", "rt"] } [dev-dependencies] +d2b-process-conformance = { path = "../d2b-process-conformance", version = "0.0.0-bootstrap", features = ["test-support"] } d2b-provider-process-minijail = { path = "../d2b-provider-process-minijail", version = "0.0.0-bootstrap" } d2b-provider-process-systemd = { path = "../d2b-provider-process-systemd", version = "0.0.0-bootstrap" } tempfile = "3" diff --git a/packages/d2bd/Cargo.toml b/packages/d2bd/Cargo.toml index 5cad7b554..dc9102eea 100644 --- a/packages/d2bd/Cargo.toml +++ b/packages/d2bd/Cargo.toml @@ -113,6 +113,7 @@ tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal", " ttrpc = { workspace = true, features = ["async"] } [dev-dependencies] +d2b-process-conformance = { path = "../d2b-process-conformance", version = "0.0.0-bootstrap", features = ["test-support"] } # U100: wired over the binary/service contract in tests/cloud_composition.rs only d2b-provider-guest-azure-container-apps = { path = "../d2b-provider-guest-azure-container-apps", version = "0.0.0-bootstrap" } d2b-session = { path = "../d2b-session", version = "0.0.0-bootstrap", features = ["test-support"] } diff --git a/packages/d2bd/src/interaction_composition.rs b/packages/d2bd/src/interaction_composition.rs index 0288086dc..d31732eb1 100644 --- a/packages/d2bd/src/interaction_composition.rs +++ b/packages/d2bd/src/interaction_composition.rs @@ -6167,7 +6167,9 @@ fn run_effect(operation: F) -> Result where T: Send + 'static, F: FnOnce() -> Fut + Send + 'static, - Fut: Future> + Send + 'static, + // The future is driven on the calling thread by `block_on` below, never + // spawned, so it does not need to be Send. + Fut: Future> + 'static, { let permit = EFFECT_ADMISSION .try_acquire() From 926b6f1d580c586d8f5363235ae9bb61e29e9b15 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:24:10 -0700 Subject: [PATCH 626/726] repo: restore the check lane to green after the merge The merge left the repository's own check lane red: a clippy `clone_on_copy` break in the d2b-core privileges conversion (the three authz facet enums gained `Copy`), a process-global test hook in d2bd that drops a concurrent test's owner connection, a daemon API doc drift, a guest workspace mirror missing `d2b-resource-client`, and a state-restore test that raced the report write it asserts on. - d2b-core: stop cloning `Copy` enum fields in `OperationAuthz::from`. - d2bd: the owner-connection test hook now intercepts only the connections the installing test claims, instead of the first owner connection of any test sharing the test binary, and a regression test pins that rule. - d2bd: `daemon_state_persistence` waits for the state-restore report before killing the restore daemon. - docs: regenerate `docs/reference/daemon-api.md`. - flake, fixtures, lock: mirror `d2b-resource-client` into the guest workspace, refresh the guest lock and the derived policy inputs. --- changelog.d/fix-wave4-gate-breaks.md | 21 ++ docs/reference/daemon-api.md | 230 +++++++++--------- flake.nix | 1 + packages/Cargo.guest.lock | 13 + packages/d2b-core/src/privileges.rs | 6 +- packages/d2bd/src/composition.rs | 114 +++++++-- .../d2bd/tests/daemon_state_persistence.rs | 8 +- .../guest-static/policy/Cargo.lock | 14 ++ .../guest-static/policy/closure.json | 52 +++- .../guest-static/policy/metadata.json | 7 +- .../guest-static/production/Cargo.lock | 14 ++ .../guest-static/production/closure.json | 52 +++- .../guest-static/production/metadata.json | 7 +- .../guest-static/policy/Cargo.lock | 14 ++ .../guest-static/policy/closure.json | 52 +++- .../guest-static/policy/metadata.json | 7 +- .../guest-static/production/Cargo.lock | 14 ++ .../guest-static/production/closure.json | 52 +++- .../guest-static/production/metadata.json | 7 +- packages/xtask/data/async-gate-inventory.json | 6 +- .../fixtures/guest-rust-workspace/Cargo.toml | 1 + 21 files changed, 537 insertions(+), 155 deletions(-) create mode 100644 changelog.d/fix-wave4-gate-breaks.md diff --git a/changelog.d/fix-wave4-gate-breaks.md b/changelog.d/fix-wave4-gate-breaks.md new file mode 100644 index 000000000..43711fb76 --- /dev/null +++ b/changelog.d/fix-wave4-gate-breaks.md @@ -0,0 +1,21 @@ +### Fixed + +- Fixed the daemon's test-only owner-connection hook to intercept only the + connections the installing test marks as its own. While a hook was + installed, any concurrent test's Process or typed-shell owner connection was + dropped without a reply, which failed that test's reply read. +- Stopped the `d2b-core` `OperationAuthz` conversion from cloning `Copy` enum + fields (`SecretAccess`, `BrokerRequirement`, `AuditMode`), which the clippy + check on the core test-support target rejects. +- Made `daemon_state_persistence` wait for the state-restore report file + instead of the public socket before killing the restore daemon: the report is + written during startup after the socket appears, so the kill could race it. +- Regenerated `docs/reference/daemon-api.md` after the daemon API contract + changes, so the generated-artifact drift check agrees with the generator. +- Added `d2b-resource-client` to the guest workspace mirror (`flake.nix`, + `tests/fixtures/guest-rust-workspace/Cargo.toml`, and + `packages/Cargo.guest.lock`) after + `d2b-provider-guest-cloud-hypervisor` gained a dependency on it, which the + realized supply-chain lane requires. +- Refreshed the async-gate inventory so its recorded marker-honored sites match + the current `d2bd` composition sources. diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index c01f9e043..085d65ddd 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -83,8 +83,8 @@ compatibility surface. | `HelloOk` | struct | [`HelloOk`](../../packages/d2b-contracts/src/lib.rs#L159) | struct { `server_version`: `Version`; `selected_version`: `Version`; `capabilities`: `Vec` } | | `HelloRejected` | struct | [`HelloRejected`](../../packages/d2b-contracts/src/lib.rs#L167) | struct { `reason`: `HelloRejectedReason` } | | `HelloRejectedReason` | enum | [`HelloRejectedReason`](../../packages/d2b-contracts/src/lib.rs#L173) | `VersionMismatch`; `CapabilityNegotiationFailed`; `InternalError` | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L899) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L993) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L898) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L992) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | | `KnownFeatureFlag` | enum | [`KnownFeatureFlag`](../../packages/d2b-contracts/src/lib.rs#L123) | `TypedErrors`; `ManifestV04`; `StatusCheckBridges`; `ExportBrokerAudit`; `ConfiguredLaunchV1`; `UnsafeLocalProviderV1` | | `SemverRange` | struct | [`SemverRange`](../../packages/d2b-contracts/src/error.rs#L1130) | empty struct | @@ -276,65 +276,65 @@ host reboot. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `BrokerRequest` | enum | [`BrokerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L32) | `ApplyHostGenerationHandoff` - (crate::host_generation::ApplyHostGenerationHandoff); `CreateOrReconcileUsersGroups` - (CreateOrReconcileUsersGroupsRequest); `DelegateCgroupV2` - (DelegateCgroupV2Request); `ExportBrokerAudit` - (ExportBrokerAuditRequest); `Hello` - (HelloRequest); `PublishTrustedContext` - (PublishTrustedContextValues); `InjectSecretById` - (SecretByIdRequest); `LaunchMinijailChild` - (LaunchMinijailChildRequest); `ModprobeIfAllowed` - (ModprobeIfAllowedRequest); `OpenCgroupDir` - (OpenCgroupDirRequest); `OpenDevice` - (OpenDeviceRequest); `OpenFuse` - (OpenFuseRequest); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyRequest); `OpenKvm` - (OpenKvmRequest); `QemuMediaEnroll` - (QemuMediaEnrollRequest); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryRequest); `QemuMediaBoot` - (QemuMediaBootRequest); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleRequest); `QemuMediaQueryStatus` - (QemuMediaQueryStatusRequest); `QemuMediaQuit` - (QemuMediaLifecycleRequest); `QemuMediaAttach` - (QemuMediaHotplugRequest); `QemuMediaDetach` - (QemuMediaHotplugRequest); `PipeWireAudio` - (PipeWireAudioRequest); `OpenVhostNet` - (OpenVhostNetRequest); `ReconcileStorageScope` - (ReconcileStorageScopeRequest); `ValidateLockSpec` - (ValidateLockSpecRequest); `StoreSync` - (StoreSyncRequest); `ReadSecretById` - (SecretByIdRequest); `RotateSecretById` - (SecretByIdRequest); `UsbipBind` - (UsbipBindRequest); `UsbipBindFirewallRule` - (UsbipBindFirewallRuleRequest); `UsbipProxyReconcile` - (UsbipProxyReconcileRequest); `UsbipUnbind` - (UsbipUnbindRequest); `UsbipExplicitBind` - (UsbipExplicitBindRequest); `UsbipExplicitFirewallRule` - (UsbipExplicitFirewallRuleRequest); `OwnershipMatrixCheck` - (OwnershipMatrixCheckRequest); `SshHostKeyPreflight` - (SshHostKeyPreflightRequest); `DiskInit` - (DiskInitRequest); `SecurityKeyOpenDevice` - (d2b_contracts::security_key::SecurityKeyOpenDeviceRequest); `SecurityKeyApplyUdevRules` - (d2b_contracts::security_key::SecurityKeyApplyUdevRulesRequest); `EnvelopeInvoke` - (EnvelopeInvokeRequest) | -| `ForwardOperationRequest` | struct | [`ForwardOperationRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L397) | struct { `operation`: `String`; `zone`: `String`; `invocation_id`: `String`; `payload`: `serde_json::Value`; `context`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L487) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L899) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1005) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1036) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | -| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1054) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1065) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1081) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1097) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | -| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1109) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1130) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1149) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1165) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1181) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1203) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1211) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | -| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1268) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | -| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1280) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1294) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | -| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1304) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1313) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | -| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1322) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1336) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1357) | struct { `tracing_span_id`: `Option` } | -| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1379) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1387) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1395) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | -| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1460) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1547) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1620) | empty struct | -| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1635) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1709) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | -| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1779) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | -| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1835) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | -| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1846) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | -| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1919) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1927) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1939) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | -| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1982) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2004) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | -| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2041) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | -| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2055) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2078) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2095) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2103) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2111) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2133) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | -| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2151) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | -| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2246) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2303) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2312) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2596) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | -| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2933) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2950) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2961) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2975) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | -| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3012) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3046) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `BrokerRequest` | enum | [`BrokerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L31) | `ApplyHostGenerationHandoff` - (crate::host_generation::ApplyHostGenerationHandoff); `CreateOrReconcileUsersGroups` - (CreateOrReconcileUsersGroupsRequest); `DelegateCgroupV2` - (DelegateCgroupV2Request); `ExportBrokerAudit` - (ExportBrokerAuditRequest); `Hello` - (HelloRequest); `PublishTrustedContext` - (PublishTrustedContextValues); `InjectSecretById` - (SecretByIdRequest); `LaunchMinijailChild` - (LaunchMinijailChildRequest); `ModprobeIfAllowed` - (ModprobeIfAllowedRequest); `OpenCgroupDir` - (OpenCgroupDirRequest); `OpenDevice` - (OpenDeviceRequest); `OpenFuse` - (OpenFuseRequest); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyRequest); `OpenKvm` - (OpenKvmRequest); `QemuMediaEnroll` - (QemuMediaEnrollRequest); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryRequest); `QemuMediaBoot` - (QemuMediaBootRequest); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleRequest); `QemuMediaQueryStatus` - (QemuMediaQueryStatusRequest); `QemuMediaQuit` - (QemuMediaLifecycleRequest); `QemuMediaAttach` - (QemuMediaHotplugRequest); `QemuMediaDetach` - (QemuMediaHotplugRequest); `PipeWireAudio` - (PipeWireAudioRequest); `OpenVhostNet` - (OpenVhostNetRequest); `ReconcileStorageScope` - (ReconcileStorageScopeRequest); `ValidateLockSpec` - (ValidateLockSpecRequest); `StoreSync` - (StoreSyncRequest); `ReadSecretById` - (SecretByIdRequest); `RotateSecretById` - (SecretByIdRequest); `UsbipBind` - (UsbipBindRequest); `UsbipBindFirewallRule` - (UsbipBindFirewallRuleRequest); `UsbipProxyReconcile` - (UsbipProxyReconcileRequest); `UsbipUnbind` - (UsbipUnbindRequest); `UsbipExplicitBind` - (UsbipExplicitBindRequest); `UsbipExplicitFirewallRule` - (UsbipExplicitFirewallRuleRequest); `OwnershipMatrixCheck` - (OwnershipMatrixCheckRequest); `SshHostKeyPreflight` - (SshHostKeyPreflightRequest); `DiskInit` - (DiskInitRequest); `SecurityKeyOpenDevice` - (d2b_contracts::security_key::SecurityKeyOpenDeviceRequest); `SecurityKeyApplyUdevRules` - (d2b_contracts::security_key::SecurityKeyApplyUdevRulesRequest); `EnvelopeInvoke` - (EnvelopeInvokeRequest) | +| `ForwardOperationRequest` | struct | [`ForwardOperationRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L396) | struct { `operation`: `String`; `zone`: `String`; `invocation_id`: `String`; `payload`: `serde_json::Value`; `context`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L486) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L898) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1004) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1035) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | +| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1053) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1064) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1080) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1096) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | +| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1108) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1129) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1148) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1164) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1180) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1202) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1210) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | +| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1267) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | +| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1279) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1293) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | +| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1303) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1312) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | +| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1321) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1335) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1356) | struct { `tracing_span_id`: `Option` } | +| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1378) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1386) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1394) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | +| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1459) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1546) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1619) | empty struct | +| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1634) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1708) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | +| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1778) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | +| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1834) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | +| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1845) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | +| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1918) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1926) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1938) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | +| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1981) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2003) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | +| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2040) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | +| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2054) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2077) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2094) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2102) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2110) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2132) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | +| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2150) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | +| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2245) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2302) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2311) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2595) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | +| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2932) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2949) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2960) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2974) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | +| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3011) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3045) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | ### Console and audio wire types @@ -389,39 +389,39 @@ see the auto-generated tables above for the committed Rust variants. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `ApplyHostGenerationHandoffResponse` | struct | [`ApplyHostGenerationHandoffResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L212) | struct { `target`: `d2b_contracts_resource::v3::ResourceRef`; `state`: `crate::host_generation::HandoffState`; `source_generation`: `u64`; `target_generation`: `u64`; `source_remains_usable`: `bool`; `summary`: `String` } | -| `PublishTrustedContextResponse` | struct | [`PublishTrustedContextResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L373) | struct { `broker_epoch`: `u64` } | -| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L465) | struct { `outcome`: `ForwardOperationOutcome` } | -| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L519) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L907) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L966) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L993) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | -| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1346) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1364) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1440) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | -| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1447) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | -| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1490) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | -| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1601) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1625) | struct { `pidfd_index`: `u32` } | -| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1676) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | -| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1728) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | -| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1869) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1881) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | -| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1890) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | -| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1901) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1911) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | -| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1969) | struct { `selector_resolved`: `String`; `device_class`: `String` } | -| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2025) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | -| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2166) | struct { `accepted`: `bool`; `operation`: `String` } | -| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2173) | struct { `bridge`: `Option`; `tap`: `IfName` } | -| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2180) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2225) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | -| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2295) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | -| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2355) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | -| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2751) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | -| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2996) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | -| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3020) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | -| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3109) | struct { `notifications`: `Vec` } | +| `ApplyHostGenerationHandoffResponse` | struct | [`ApplyHostGenerationHandoffResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L211) | struct { `target`: `d2b_contracts_resource::v3::ResourceRef`; `state`: `crate::host_generation::HandoffState`; `source_generation`: `u64`; `target_generation`: `u64`; `source_remains_usable`: `bool`; `summary`: `String` } | +| `PublishTrustedContextResponse` | struct | [`PublishTrustedContextResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L372) | struct { `broker_epoch`: `u64` } | +| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L464) | struct { `outcome`: `ForwardOperationOutcome` } | +| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L518) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L906) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L965) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L992) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1345) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1363) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1439) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | +| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1446) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | +| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1489) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | +| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1600) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1624) | struct { `pidfd_index`: `u32` } | +| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1675) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | +| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1727) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | +| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1868) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1880) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | +| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1889) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | +| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1900) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1910) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | +| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1968) | struct { `selector_resolved`: `String`; `device_class`: `String` } | +| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2024) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | +| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2165) | struct { `accepted`: `bool`; `operation`: `String` } | +| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2172) | struct { `bridge`: `Option`; `tap`: `IfName` } | +| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2179) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2224) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | +| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2294) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | +| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2354) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | +| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2750) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | +| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2995) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | +| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3019) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | +| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3108) | struct { `notifications`: `Vec` } | ## Per-VM lifecycle state @@ -496,25 +496,25 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `FdKind` | enum | [`FdKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L253) | `Fifo`; `Socket`; `CharDevice`; `BlockDevice`; `Any`; `Regular`; `Directory` | -| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L440) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | -| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L841) | `Host`; `Guest` | -| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1024) | `Apply`; `Remove` | -| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1255) | `Info`; `Warning`; `Error`; `Denied` | -| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1409) | `SystemPowerdown`; `Quit` | -| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1416) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | -| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1469) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | -| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1689) | `Speaker`; `Microphone` | -| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1699) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | -| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1743) | `System`; `User` | -| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1859) | `Drain`; `Terminate` | -| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2238) | `Term`; `Kill`; `Quit` | -| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2374) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | -| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2729) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | -| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2887) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | -| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2985) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | -| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3059) | `Exited`; `Signaled`; `Killed` | -| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3097) | `ChildReaped` - (ChildReapedNotification); `Unknown` | +| `FdKind` | enum | [`FdKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L252) | `Fifo`; `Socket`; `CharDevice`; `BlockDevice`; `Any`; `Regular`; `Directory` | +| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L439) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | +| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L840) | `Host`; `Guest` | +| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1023) | `Apply`; `Remove` | +| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1254) | `Info`; `Warning`; `Error`; `Denied` | +| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1408) | `SystemPowerdown`; `Quit` | +| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1415) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | +| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1468) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | +| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1688) | `Speaker`; `Microphone` | +| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1698) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | +| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1742) | `System`; `User` | +| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1858) | `Drain`; `Terminate` | +| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2237) | `Term`; `Kill`; `Quit` | +| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2373) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | +| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2728) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | +| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2886) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | +| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2984) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | +| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3058) | `Exited`; `Signaled`; `Killed` | +| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3096) | `ChildReaped` - (ChildReapedNotification); `Unknown` | | `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L141) | `Lifecycle`; `Admin` | | `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L179) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | | `ProxyReadinessStage` | enum | [`ProxyReadinessStage`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L12) | `Upstream`; `Listener`; `FirstClient` | @@ -644,8 +644,8 @@ the failure class, for example `host check`, `audit`, `status`, or | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L966) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2534) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L965) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2533) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | | `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L198) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | | `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1208) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | diff --git a/flake.nix b/flake.nix index ad88c0652..fb197e7e4 100644 --- a/flake.nix +++ b/flake.nix @@ -167,6 +167,7 @@ cp -r ${./packages/d2b-provider-zone} $out/packages/d2b-provider-zone cp -r ${./packages/d2b-provider-zone-link} $out/packages/d2b-provider-zone-link cp -r ${./packages/d2b-resource-api} $out/packages/d2b-resource-api + cp -r ${./packages/d2b-resource-client} $out/packages/d2b-resource-client cp -r ${./packages/d2b-resource-types} $out/packages/d2b-resource-types cp -r ${./packages/d2b-resource-runtime} $out/packages/d2b-resource-runtime cp -r ${./packages/d2b-session} $out/packages/d2b-session diff --git a/packages/Cargo.guest.lock b/packages/Cargo.guest.lock index c75564ea8..4d1a0a3c1 100644 --- a/packages/Cargo.guest.lock +++ b/packages/Cargo.guest.lock @@ -1266,6 +1266,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1769,6 +1770,18 @@ dependencies = [ "ttrpc", ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/d2b-core/src/privileges.rs b/packages/d2b-core/src/privileges.rs index d33e5a39d..843929037 100644 --- a/packages/d2b-core/src/privileges.rs +++ b/packages/d2b-core/src/privileges.rs @@ -719,11 +719,11 @@ impl From<&OperationAuthzRow> for OperationAuthz { .map(|group| (*group).to_owned()) .collect(), destructive: row.destructive, - secret_access: row.secret_access.clone(), - broker_required: row.broker_required.clone(), + secret_access: row.secret_access, + broker_required: row.broker_required, audit: AuditPolicy { required: !matches!(row.audit_mode, AuditMode::DenyOnly | AuditMode::Errors), - mode: row.audit_mode.clone(), + mode: row.audit_mode, retained_fields: vec![ "operation".to_owned(), "subject".to_owned(), diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..3344094bf 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -502,7 +502,29 @@ const REQUEST_READ_DEADLINE: Duration = Duration::from_secs(60); mod owner_connection_test_hook { use std::sync::{Arc, Mutex, OnceLock}; - pub(crate) type Hook = Arc; + use serde_json::Value; + + /// A test fake for the owner body, called with the connection's request + /// frame. Returning `true` claims the connection: the body drops it + /// without a reply, standing in for an owner that is still running. + /// Returning `false` leaves the connection to the real owner body, so a + /// hook installed by one test can never swallow a concurrent test's + /// connection. + pub(crate) type Hook = Arc bool + Send + Sync>; + + /// The request field that claims the hook. Only the test that installed + /// the hook sets it, and only on the frames it sends itself. + pub(crate) const CLAIM_FIELD: &str = "ownerConnectionHookClaim"; + + /// Marks `request` as the installing test's own connection. + pub(crate) fn claim(request: &mut Value) { + request[CLAIM_FIELD] = Value::Bool(true); + } + + /// Whether `request` is the installing test's own connection. + pub(crate) fn claims(request: &Value) -> bool { + request.get(CLAIM_FIELD) == Some(&Value::Bool(true)) + } // Synchronous by construction (the accept-loop hook fires from a // dedicated handler thread): the process-global slot stays a @@ -13140,12 +13162,11 @@ fn run_process_resource_owner( _conn_permit: Option, ) { #[cfg(test)] + if let Some(hook) = owner_connection_test_hook::active() + && hook(&request) { - if let Some(hook) = owner_connection_test_hook::active() { - hook(); - drop(stream); - return; - } + drop(stream); + return; } let (vm, execution_ref) = match if request.get("executionRef").is_some() { process_resource_execution_ref(&request) @@ -13313,12 +13334,11 @@ fn run_typed_shell_owner( _conn_permit: Option, ) { #[cfg(test)] + if let Some(hook) = owner_connection_test_hook::active() + && hook(&request) { - if let Some(hook) = owner_connection_test_hook::active() { - hook(); - drop(stream); - return; - } + drop(stream); + return; } let rt = match tokio::runtime::Builder::new_current_thread() .enable_all() @@ -23594,8 +23614,11 @@ mod accept_loop_concurrency_tests { .expect("encode workload list frame") } + /// The Process create frame the owner-hook test sends on the connection it + /// owns. It claims the process-global owner hook, so the hook intercepts + /// that connection and leaves every other test's connection alone. fn process_resource_start_frame(op_id: u64) -> Vec { - serde_json::to_vec(&json!({ + let mut frame = json!({ "type": "resourceRequest", "method": "Create", "service": "d2b.resource.v3", @@ -23608,8 +23631,9 @@ mod accept_loop_concurrency_tests { "detached": false, "argv": ["true"], "opId": op_id, - })) - .expect("serialize Process resource frame") + }); + owner_connection_test_hook::claim(&mut frame); + serde_json::to_vec(&frame).expect("serialize Process resource frame") } /// Scoped guard for the test SO_PEERCRED override so a panic still clears @@ -23774,7 +23798,10 @@ mod accept_loop_concurrency_tests { let _hook_guard = HookGuard; let hook_shared = Arc::clone(&shared); - let hook: owner_connection_test_hook::Hook = Arc::new(move || { + let hook: owner_connection_test_hook::Hook = Arc::new(move |request| { + if !owner_connection_test_hook::claims(request) { + return false; + } let (lock, cv) = &*hook_shared; { let mut s = lock.lock().expect("hook state lock"); @@ -23788,6 +23815,7 @@ mod accept_loop_concurrency_tests { } s.running = false; cv.notify_all(); + true }); owner_connection_test_hook::set(hook); @@ -23898,6 +23926,52 @@ mod accept_loop_concurrency_tests { drop(client_a); } + /// A hook installed by one test intercepts only the connections that + /// test claimed: an unclaimed connection still reaches the real owner + /// body and gets its reply instead of being dropped by the hook. + #[test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn owner_connection_hook_leaves_unclaimed_connections_to_the_real_owner() { + // Serialize the process-global owner hook with the Process owner test. + let _env = PeerOverrideEnv::admin(); + let (state, _state_dir) = admin_exec_state(); + let (server, client) = seqpacket_pair(); + + struct HookGuard; + impl Drop for HookGuard { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn drop(&mut self) { + owner_connection_test_hook::clear(); + } + } + let _hook_guard = HookGuard; + // The plain claim check the owner-body hooks install, so this test + // exercises exactly the interception rule they rely on. + let hook: owner_connection_test_hook::Hook = + Arc::new(owner_connection_test_hook::claims); + owner_connection_test_hook::set(hook); + + run_process_resource_owner( + server, + state, + admin_peer_identity(), + json!({ + "resourceType": "EphemeralProcess", + "resourceRef": "EphemeralProcess/exec-unclaimed", + "executionRef": "Guest/work", + "tty": false, + "detached": false, + "argv": ["true"], + }), + None, + ); + + let frame = read_frame(&client).expect("client reads the owner reply frame"); + let reply: serde_json::Value = serde_json::from_slice(&frame).expect("reply frame is JSON"); + assert_eq!(reply["type"], "error"); + assert_eq!(reply["error"]["kind"], "runtime-capability-unsupported"); + } + #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn typed_shell_owner_keeps_admission_permit_until_owner_exits() { @@ -23923,7 +23997,10 @@ mod accept_loop_concurrency_tests { let _hook_guard = HookGuard; let hook_release_rx = Arc::clone(&release_rx); - let hook: owner_connection_test_hook::Hook = Arc::new(move || { + let hook: owner_connection_test_hook::Hook = Arc::new(move |request| { + if !owner_connection_test_hook::claims(request) { + return false; + } entered_tx .send(()) .expect("typed shell owner entered receiver"); @@ -23932,15 +24009,18 @@ mod accept_loop_concurrency_tests { .expect("typed shell owner release lock") .recv() .expect("typed shell owner release signal"); + true }); owner_connection_test_hook::set(hook); let (server, _client) = seqpacket_pair(); + let mut request = json!({}); + owner_connection_test_hook::claim(&mut request); let owner = spawn_typed_shell_owner( server, state, admin_peer_identity(), - json!({}), + request, Some(permit), ) .expect("spawn typed shell owner"); diff --git a/packages/d2bd/tests/daemon_state_persistence.rs b/packages/d2bd/tests/daemon_state_persistence.rs index 6cf4399a0..9f0296541 100644 --- a/packages/d2bd/tests/daemon_state_persistence.rs +++ b/packages/d2bd/tests/daemon_state_persistence.rs @@ -4,10 +4,11 @@ mod daemon_state_persistence { use std::fs; use std::path::PathBuf; use std::process::{Command, Stdio}; + use std::time::Duration; use serde_json::{Value, json}; - use super::common::{DaemonFixture, TestPeer, spawn_d2bd_serve}; + use super::common::{DaemonFixture, TestPeer, spawn_d2bd_serve, wait_for_file}; #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -62,6 +63,11 @@ mod daemon_state_persistence { true, Some(report_json.as_path()), ); + // The report is written during startup, after the public socket + // binds; wait for it before killing so the kill cannot race the + // write (the socket appears first, so waiting on the socket alone + // is not enough). + wait_for_file(&report_json, Duration::from_secs(15)); restore.kill_and_wait(); let report = read_json(&report_json); diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json index 8bc8fcf4e..b9a7d5236 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "aarch64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "aarch64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json index fa202753f..e7cf3f7f4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json index ea6ab0401..88df3cc63 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "aarch64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "aarch64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json index fa202753f..e7cf3f7f4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json index fb7cdb388..20236dcbb 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "x86_64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "x86_64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json index fa88ebdc4..8d03d7b6e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json index 41788b595..b2a60e67d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "x86_64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "x86_64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json index fa88ebdc4..8d03d7b6e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 0ea2e8078..9b42f5ca2 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -1078,17 +1078,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10790, + "line": 10812, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26251, + "line": 26331, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26648, + "line": 26728, "reason": "synchronous lock acquisition, no await while the guard is held" }, { diff --git a/tests/fixtures/guest-rust-workspace/Cargo.toml b/tests/fixtures/guest-rust-workspace/Cargo.toml index 5d2bf78b3..9137b57e2 100644 --- a/tests/fixtures/guest-rust-workspace/Cargo.toml +++ b/tests/fixtures/guest-rust-workspace/Cargo.toml @@ -77,6 +77,7 @@ members = [ "d2b-provider-zone", "d2b-provider-zone-link", "d2b-resource-api", + "d2b-resource-client", "d2b-resource-types", "d2b-resource-runtime", "d2b-session", From 2fa4cd475065ebf6aa2f8f87336861f3887ae383 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:27:15 -0700 Subject: [PATCH 627/726] fix(d2bd): carry the origin error on typed io, config, and broker refusals - `TypedError::InternalIo`, `TypedError::InternalConfig`, and `TypedError::InternalBrokerUnavailable` rendered the error they were raised from into `detail` and dropped the value, so `std::error::Error::source()` had nothing to walk and the daemon's raw-detail logging boundary could only print one collapsed sentence. - The three variants now carry `source: Option` (an `Arc`, so `TypedError` stays `Clone`), `TypedError` implements `Display` and `Error` with `source()` returning the origin, and the raw-detail log records the whole chain through an `origin` field. Every construction site whose `detail` renders an error attaches that error; sites whose detail is a literal, a wire-field rendering, or a value with no `std::error::Error` impl pass `None`. - The public envelope does not move: `kind`, `exitCode`, `message`, and `remediation` render byte-for-byte the same strings, and `TypedError` is not serialized, so an attached origin is unreachable by any serializer. --- changelog.d/w5-26-typed-error-source.md | 18 ++ packages/d2bd-runtime/src/broker_transport.rs | 6 +- packages/d2bd-runtime/src/daemon_client.rs | 5 +- packages/d2bd-runtime/src/daemon_config.rs | 10 +- packages/d2bd-runtime/src/json_io.rs | 6 +- packages/d2bd-runtime/src/pidfs_probe.rs | 2 + .../d2bd-runtime/src/public_read_model.rs | 6 +- packages/d2bd-runtime/src/runtime_process.rs | 23 +- packages/d2bd-runtime/src/runtime_util.rs | 1 + packages/d2bd-runtime/src/typed_error.rs | 110 +++++++- packages/d2bd-runtime/src/unix_transport.rs | 22 +- packages/d2bd-runtime/src/wire.rs | 6 +- packages/d2bd/src/audio_dispatch.rs | 16 +- packages/d2bd/src/composition.rs | 238 +++++++++++++++++- packages/d2bd/src/forward_rendezvous.rs | 52 ++-- .../d2bd/tests/bundle_tampered_envelope.rs | 3 +- 16 files changed, 486 insertions(+), 38 deletions(-) create mode 100644 changelog.d/w5-26-typed-error-source.md diff --git a/changelog.d/w5-26-typed-error-source.md b/changelog.d/w5-26-typed-error-source.md new file mode 100644 index 000000000..b8cbf4d39 --- /dev/null +++ b/changelog.d/w5-26-typed-error-source.md @@ -0,0 +1,18 @@ +### Fixed + +- Daemon `internal-io`, `internal-config-invalid`, and + `internal-broker-unavailable` refusals now keep the error they were raised + from. `d2bd_runtime::typed_error::TypedError` carries an `Option` + on those three variants, so `std::error::Error::source()` walks back to the + failing `io::Error`, serde, nix, or transport error instead of stopping at + the rendered `detail` string, and the daemon's raw-detail logging records the + whole cause chain in an `origin` field (`origin: cause: root`) rather than + one collapsed sentence. Every construction site that used to render an error + into `detail` now attaches that error, and sites whose detail is not derived + from an error pass `None`. +- The daemon wire error surface does not move: the public envelope is still + rendered from `kind`, `exitCode`, `message`, and `remediation` only, and the + operator-visible `detail` strings are byte-for-byte unchanged. `TypedError` + is not `Serialize`, so an attached origin is unreachable by any serializer; + a future `Serialize` derive on the enum must keep the field behind + `#[serde(skip)]`. diff --git a/packages/d2bd-runtime/src/broker_transport.rs b/packages/d2bd-runtime/src/broker_transport.rs index b7f20ce77..1f7090295 100644 --- a/packages/d2bd-runtime/src/broker_transport.rs +++ b/packages/d2bd-runtime/src/broker_transport.rs @@ -9,7 +9,7 @@ use d2b_contracts_broker::broker_wire::{ }; use crate::target_runtime::DaemonMode; -use crate::typed_error::TypedError; +use crate::typed_error::{TypedError, error_source}; use crate::unix_transport::{ connect_seqpacket, connect_seqpacket_with_timeout, read_frame, write_json_frame, }; @@ -43,6 +43,7 @@ pub fn dispatch_broker_request_to_socket( TypedError::InternalBrokerUnavailable { path: socket_path.to_path_buf(), detail: err.to_string(), + source: error_source(err), } }); }; @@ -117,6 +118,7 @@ fn broker_round_trip_within_deadline( .map_err(|error| TypedError::InternalIo { context: format!("set broker write timeout to {remaining:?}"), detail: error.to_string(), + source: error_source(error), })?; write_json_frame(&socket, envelope)?; @@ -126,11 +128,13 @@ fn broker_round_trip_within_deadline( .map_err(|error| TypedError::InternalIo { context: format!("set broker read timeout to {remaining:?}"), detail: error.to_string(), + source: error_source(error), })?; let response = read_frame(&socket)?; serde_json::from_slice(&response).map_err(|error| TypedError::InternalBrokerUnavailable { path: socket_path.to_path_buf(), detail: error.to_string(), + source: error_source(error), }) } diff --git a/packages/d2bd-runtime/src/daemon_client.rs b/packages/d2bd-runtime/src/daemon_client.rs index 146beceb9..f687d0f7d 100644 --- a/packages/d2bd-runtime/src/daemon_client.rs +++ b/packages/d2bd-runtime/src/daemon_client.rs @@ -6,7 +6,7 @@ use crate::daemon_config::{ DaemonConfig, ServeOptions, TestClientOptions, effective_daemon_state_dir, }; use crate::supervisor::state::{FilesystemSnapshotStore, SnapshotStore, SystemProcReader}; -use crate::typed_error::TypedError; +use crate::typed_error::{TypedError, error_source}; use crate::unix_transport::{connect_seqpacket, round_trip}; pub fn run_test_client(options: TestClientOptions) -> Result { @@ -55,14 +55,17 @@ pub fn maybe_write_state_restore_report(options: &ServeOptions) -> Result<(), Ty let snapshots = SnapshotStore::list(&store).map_err(|err| TypedError::InternalIo { context: "enumerate daemon state snapshots".to_owned(), detail: err.to_string(), + source: error_source(err), })?; let report = crate::supervisor::state::reconcile(&snapshots, &SystemProcReader); let rendered = serde_json::to_vec_pretty(&report).map_err(|err| TypedError::InternalIo { context: "serialize daemon state report".to_owned(), detail: err.to_string(), + source: error_source(err), })?; fs::write(report_path, rendered).map_err(|err| TypedError::InternalIo { context: "write daemon state report".to_owned(), detail: err.to_string(), + source: error_source(err), }) } diff --git a/packages/d2bd-runtime/src/daemon_config.rs b/packages/d2bd-runtime/src/daemon_config.rs index 353fecb63..8d50214f4 100644 --- a/packages/d2bd-runtime/src/daemon_config.rs +++ b/packages/d2bd-runtime/src/daemon_config.rs @@ -10,7 +10,7 @@ use d2b_contracts::controller_config::{RealmControllerMetadataSummary, RealmCont use d2b_contracts::identity_config::{RealmIdentityConfigJson, RealmIdentityConfigSummary}; use serde::{Deserialize, Serialize}; -use crate::typed_error::TypedError; +use crate::typed_error::{TypedError, error_source}; pub const DEFAULT_CONFIG_PATH: &str = "/etc/d2b/daemon-config.json"; pub const DEFAULT_GATEWAY_CONFIG_PATH: &str = "/etc/d2b/gateway.json"; @@ -374,9 +374,11 @@ pub fn load_config(path: &Path) -> Result { let bytes = fs::read(path).map_err(|err| TypedError::InternalIo { context: format!("read config {}", path.display()), detail: err.to_string(), + source: error_source(err), })?; serde_json::from_slice(&bytes).map_err(|err| TypedError::InternalConfig { detail: format!("{}: {err}", path.display()), + source: error_source(err), }) } @@ -399,15 +401,18 @@ pub fn load_realm_controllers_config( let bytes = fs::read(path).map_err(|err| TypedError::InternalIo { context: "read realm controllers config".to_owned(), detail: err.to_string(), + source: error_source(err), })?; let config: RealmControllersJson = serde_json::from_slice(&bytes).map_err(|err| TypedError::InternalConfig { detail: format!("invalid realm controllers config: {err}"), + source: error_source(err), })?; let summary = config .validate_metadata_only() .map_err(|err| TypedError::InternalConfig { detail: format!("invalid realm controllers config: {err}"), + source: error_source(err), })?; Ok(Some(LoadedRealmControllersConfig { config, summary })) } @@ -431,15 +436,18 @@ pub fn load_realm_identity_config( let bytes = fs::read(path).map_err(|err| TypedError::InternalIo { context: "read realm identity config".to_owned(), detail: err.to_string(), + source: error_source(err), })?; let config: RealmIdentityConfigJson = serde_json::from_slice(&bytes).map_err(|err| TypedError::InternalConfig { detail: format!("invalid realm identity config: {err}"), + source: error_source(err), })?; let summary = config .validate_metadata_only() .map_err(|err| TypedError::InternalConfig { detail: format!("invalid realm identity config: {err}"), + source: error_source(err), })?; Ok(Some(LoadedRealmIdentityConfig { config, summary })) } diff --git a/packages/d2bd-runtime/src/json_io.rs b/packages/d2bd-runtime/src/json_io.rs index 0ad71ae5c..4c65e2042 100644 --- a/packages/d2bd-runtime/src/json_io.rs +++ b/packages/d2bd-runtime/src/json_io.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use serde::Deserialize; -use crate::typed_error::TypedError; +use crate::typed_error::{TypedError, error_source}; /// Resolve a bundle-relative artifact path within `base_dir`. /// @@ -37,10 +37,12 @@ where let bytes = fs::read(path).map_err(|err| TypedError::InternalIo { context: format!("read {}", path.display()), detail: err.to_string(), + source: error_source(err), })?; serde_json::from_slice(&bytes).map_err(|err| TypedError::InternalIo { context: format!("decode {}", path.display()), detail: err.to_string(), + source: error_source(err), }) } @@ -60,6 +62,7 @@ pub fn load_manifest( .ok_or_else(|| TypedError::InternalIo { context: format!("decode manifest {}", path.display()), detail: "manifest must be a JSON object".to_owned(), + source: None, }) } @@ -73,5 +76,6 @@ pub fn read_trimmed_file(path: &Path, context: &str) -> Result bool { !matches!( @@ -200,6 +203,7 @@ fn file_fingerprint(path: &Path) -> Result { let metadata = fs::metadata(path).map_err(|error| TypedError::InternalIo { context: format!("fingerprint {}", path.display()), detail: error.to_string(), + source: error_source(error), })?; Ok(FileFingerprint { path: path.display().to_string(), diff --git a/packages/d2bd-runtime/src/runtime_process.rs b/packages/d2bd-runtime/src/runtime_process.rs index 19a4fc1f3..74ed0fd61 100644 --- a/packages/d2bd-runtime/src/runtime_process.rs +++ b/packages/d2bd-runtime/src/runtime_process.rs @@ -9,7 +9,7 @@ use std::{ }; use crate::daemon_config::{DEFAULT_SERVER_VERSION, DaemonConfig}; -use crate::typed_error::TypedError; +use crate::typed_error::{TypedError, error_source}; use crate::unix_transport::io_wrap; use nix::fcntl::{FcntlArg, fcntl}; #[cfg(test)] @@ -57,11 +57,13 @@ pub fn resolve_runtime_identity( .map_err(io_wrap("lookup daemon user"))? .ok_or_else(|| TypedError::InternalConfig { detail: format!("daemon user {} does not exist", config.daemon_user), + source: None, })?; let daemon_group = Group::from_name(&config.daemon_group) .map_err(io_wrap("lookup daemon group"))? .ok_or_else(|| TypedError::InternalConfig { detail: format!("daemon group {} does not exist", config.daemon_group), + source: None, })?; let public_group = Group::from_name(&config.public_socket_group) .map_err(io_wrap("lookup public socket group"))? @@ -70,6 +72,7 @@ pub fn resolve_runtime_identity( "public socket group {} does not exist", config.public_socket_group ), + source: None, })?; let unsafe_local_helper_socket_gid = match ( config.unsafe_local_helper_socket_path.as_ref(), @@ -80,6 +83,7 @@ pub fn resolve_runtime_identity( .map_err(io_wrap("lookup unsafe-local helper socket group"))? .ok_or_else(|| TypedError::InternalConfig { detail: format!("unsafe-local helper socket group {group_name} does not exist"), + source: None, })? .gid, ), @@ -88,6 +92,7 @@ pub fn resolve_runtime_identity( return Err(TypedError::InternalConfig { detail: "unsafe-local helper socket path and group must be configured together" .to_owned(), + source: None, }); } }; @@ -110,12 +115,14 @@ pub fn resolve_unsafe_local_helper_uids( .map_err(io_wrap("lookup unsafe-local helper user"))? .ok_or_else(|| TypedError::InternalConfig { detail: "configured unsafe-local helper user does not exist".to_owned(), + source: None, })?; let uid = user.uid.as_raw(); if uid == 0 || uid == daemon_uid.as_raw() { return Err(TypedError::InternalConfig { detail: "unsafe-local helper users must be non-root and distinct from d2bd" .to_owned(), + source: None, }); } uids.insert(uid); @@ -200,11 +207,13 @@ pub fn ensure_locks_dir(path: &Path, identity: &RuntimeIdentity) -> Result<(), T fs::create_dir_all(path).map_err(|err| TypedError::InternalIo { context: format!("create locks dir {}", path.display()), detail: err.to_string(), + source: error_source(err), })?; fs::set_permissions(path, fs::Permissions::from_mode(0o750)).map_err(|err| { TypedError::InternalIo { context: format!("chmod locks dir {}", path.display()), detail: err.to_string(), + source: error_source(err), } })?; if identity.expect_root_owned_parent && unistd::geteuid().is_root() { @@ -225,11 +234,13 @@ pub fn acquire_state_lock(path: &Path, identity: &RuntimeIdentity) -> Result Result Err(TypedError::InternalIo { context: format!("acquire OFD lock {}", path.display()), detail: err.to_string(), + source: error_source(err), }), } } @@ -265,11 +277,13 @@ pub fn bind_public_socket(path: &Path, identity: &RuntimeIdentity) -> Result Result Result; + +/// Attach the error a [`TypedError`] variant was built from, for variants +/// whose `detail` renders that error. The bound is what keeps the field an +/// error object: a call site cannot pass a pre-rendered string. +pub fn error_source(error: E) -> Option +where + E: std::error::Error + Send + Sync + 'static, +{ + Some(Arc::new(error)) +} /// Closed enum of component-session config-read failure classes. Each maps to a /// distinct wire `kind` slug; the daemon never attaches a path, byte, or @@ -472,6 +499,8 @@ pub enum TypedError { InternalBrokerUnavailable { path: PathBuf, detail: String, + /// Origin error this refusal was raised from, when there was one. + source: Option, }, /// The privileged broker round trip (connect + write + read) did not /// complete before the caller's single absolute deadline. Distinct @@ -486,10 +515,14 @@ pub enum TypedError { }, InternalConfig { detail: String, + /// Origin error this refusal was raised from, when there was one. + source: Option, }, InternalIo { context: String, detail: String, + /// Origin error this refusal was raised from, when there was one. + source: Option, }, InternalLockParentInvalid { path: PathBuf, @@ -678,6 +711,60 @@ pub enum TypedError { }, } +impl std::fmt::Display for TypedError { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(&self.message()) + } +} + +impl std::error::Error for TypedError { + /// The origin error attached to the variant, when the refusal was raised + /// from one. Variants without an origin return `None`. + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::InternalBrokerUnavailable { source, .. } + | Self::InternalConfig { source, .. } + | Self::InternalIo { source, .. } => source.as_ref().map(plain_error), + _ => None, + } + } +} + +/// Erase the `Send + Sync` bounds of an [`ErrorSource`] so it satisfies +/// [`std::error::Error::source`]. +fn plain_error(error: &ErrorSource) -> &(dyn std::error::Error + 'static) { + error.as_ref() +} + +/// Stops a rendered origin chain, so a self-referential one cannot spin the +/// log path. +const MAX_SOURCE_CHAIN_DEPTH: usize = 8; + +/// Renders an origin error and its own `source()` chain into one log field - +/// `origin: cause: root` - so a caller's `detail` string is not the end of the +/// chain. +struct SourceChain<'a>(Option<&'a (dyn std::error::Error + 'static)>); + +impl std::fmt::Display for SourceChain<'_> { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Some(origin) = self.0 else { + return formatter.write_str("none"); + }; + write!(formatter, "{origin}")?; + let mut current = origin.source(); + let mut depth = 0; + while let Some(cause) = current { + if depth == MAX_SOURCE_CHAIN_DEPTH { + return formatter.write_str(": ..."); + } + depth += 1; + write!(formatter, ": {cause}")?; + current = cause.source(); + } + Ok(()) + } +} + /// Classify the detail string for a lock-parent validation failure into /// a deterministic, path-free public description. fn redacted_lock_parent_reason(detail: &str) -> &'static str { @@ -1126,11 +1213,16 @@ impl TypedError { "daemon lock is already held" ); } - Self::InternalBrokerUnavailable { path, detail } => { + Self::InternalBrokerUnavailable { + path, + detail, + source, + } => { tracing::error!( kind = self.kind(), path = %path.display(), detail = %detail, + origin = %SourceChain(source.as_ref().map(plain_error)), "could not reach broker socket" ); } @@ -1141,18 +1233,24 @@ impl TypedError { "broker round trip exceeded its deadline" ); } - Self::InternalConfig { detail } => { + Self::InternalConfig { detail, source } => { tracing::error!( kind = self.kind(), detail = %detail, + origin = %SourceChain(source.as_ref().map(plain_error)), "invalid daemon configuration" ); } - Self::InternalIo { context, detail } => { + Self::InternalIo { + context, + detail, + source, + } => { tracing::error!( kind = self.kind(), context = %context, detail = %detail, + origin = %SourceChain(source.as_ref().map(plain_error)), "internal I/O failure" ); } @@ -1288,6 +1386,7 @@ mod tests { let err = TypedError::InternalBrokerUnavailable { path: PathBuf::from("/run/d2b/priv.sock"), detail: "Connection refused (os error 111)".to_owned(), + source: None, }; assert_eq!(err.kind(), "internal-broker-unavailable"); assert_no_path_leak("InternalBrokerUnavailable", &err.message()); @@ -1297,6 +1396,7 @@ mod tests { fn internal_config_redacted() { let err = TypedError::InternalConfig { detail: "/etc/d2b/daemon-config.json: missing field `serverVersion`".to_owned(), + source: None, }; assert_eq!(err.kind(), "internal-config-invalid"); assert_no_path_leak("InternalConfig", &err.message()); @@ -1307,6 +1407,7 @@ mod tests { let err = TypedError::InternalIo { context: format!("read {}", "/home/paydro/secrets/key.pem"), detail: "No such file or directory (os error 2)".to_owned(), + source: None, }; assert_eq!(err.kind(), "internal-io"); assert_no_path_leak("InternalIo", &err.message()); @@ -1532,12 +1633,14 @@ mod tests { TypedError::InternalBrokerUnavailable { path: PathBuf::from("/run/d2b/priv.sock"), detail: "refused".to_owned(), + source: None, }, "internal-broker-unavailable", ), ( TypedError::InternalConfig { detail: "bad".to_owned(), + source: None, }, "internal-config-invalid", ), @@ -1545,6 +1648,7 @@ mod tests { TypedError::InternalIo { context: "read /etc/nixos/foo.nix".to_owned(), detail: "ENOENT".to_owned(), + source: None, }, "internal-io", ), diff --git a/packages/d2bd-runtime/src/unix_transport.rs b/packages/d2bd-runtime/src/unix_transport.rs index 761de6e6e..e616a0970 100644 --- a/packages/d2bd-runtime/src/unix_transport.rs +++ b/packages/d2bd-runtime/src/unix_transport.rs @@ -15,7 +15,7 @@ use nix::unistd; use serde::Serialize; use socket2::{SockAddr, Socket}; -use crate::typed_error::TypedError; +use crate::typed_error::{TypedError, error_source}; const REJECTION_DRAIN_DEADLINE: Duration = Duration::from_millis(10); @@ -33,14 +33,17 @@ pub fn connect_seqpacket(path: &Path) -> Result { .map_err(|err| TypedError::InternalIo { context: format!("create seqpacket socket {}", path.display()), detail: err.to_string(), + source: error_source(err), })?; let address = UnixAddr::new(path).map_err(|err| TypedError::InternalIo { context: format!("encode seqpacket socket path {}", path.display()), detail: err.to_string(), + source: error_source(err), })?; connect(fd.as_raw_fd(), &address).map_err(|err| TypedError::InternalBrokerUnavailable { path: path.to_path_buf(), detail: err.to_string(), + source: error_source(err), })?; Ok(fd) } @@ -73,16 +76,19 @@ pub fn connect_seqpacket_with_timeout( .map_err(|err| TypedError::InternalIo { context: "create seqpacket socket".to_owned(), detail: err.to_string(), + source: error_source(err), })?; let address = SockAddr::unix(path).map_err(|err| TypedError::InternalIo { context: "encode seqpacket socket path".to_owned(), detail: err.to_string(), + source: error_source(err), })?; let socket = Socket::from(fd); socket.connect_timeout(&address, timeout).map_err(|err| { TypedError::InternalBrokerUnavailable { path: path.to_path_buf(), detail: err.to_string(), + source: error_source(err), } })?; Ok(OwnedFd::from(socket)) @@ -111,6 +117,7 @@ where let bytes = serde_json::to_vec(value).map_err(|err| TypedError::InternalIo { context: "serialize JSON frame".to_owned(), detail: err.to_string(), + source: error_source(err), })?; write_frame_with_fds(socket, &bytes, fds) } @@ -189,11 +196,13 @@ pub fn write_frame_with_fds( .map_err(|err| TypedError::InternalIo { context: "send seqpacket frame".to_owned(), detail: err.to_string(), + source: error_source(err), })?; if written != frame.len() { return Err(TypedError::InternalIo { context: "send seqpacket frame".to_owned(), detail: format!("short write: {written} of {}", frame.len()), + source: None, }); } Ok(()) @@ -209,12 +218,14 @@ pub fn read_frame(socket: &impl AsRawFd) -> Result, TypedError> { TypedError::InternalIo { context: "recv seqpacket frame".to_owned(), detail: err.to_string(), + source: error_source(err), } })?; if read == 0 { return Err(TypedError::InternalIo { context: "recv seqpacket frame".to_owned(), detail: "peer closed the socket".to_owned(), + source: None, }); } if read < 4 { @@ -238,11 +249,13 @@ pub fn mark_fd_cloexec(fd: RawFd, context: &str) -> Result<(), TypedError> { let current = fcntl(fd, FcntlArg::F_GETFD).map_err(|err| TypedError::InternalIo { context: context.to_owned(), detail: err.to_string(), + source: error_source(err), })?; let flags = FdFlag::from_bits_truncate(current) | FdFlag::FD_CLOEXEC; fcntl(fd, FcntlArg::F_SETFD(flags)).map_err(|err| TypedError::InternalIo { context: context.to_owned(), detail: err.to_string(), + source: error_source(err), })?; Ok(()) } @@ -252,18 +265,21 @@ pub fn duplicate_fd_cloexec(fd: RawFd, context: &str) -> Result Result<(Vec, Vec .map_err(|err| TypedError::InternalIo { context: "recv seqpacket frame with fds".to_owned(), detail: err.to_string(), + source: error_source(err), })?; let read = message.bytes; let received_fds: Vec = message @@ -296,6 +313,7 @@ pub fn read_frame_with_fds(socket: &impl AsRawFd) -> Result<(Vec, Vec .map_err(|err| TypedError::InternalIo { context: "recv seqpacket frame with fds".to_owned(), detail: err.to_string(), + source: error_source(err), })? .filter_map(|cmsg| match cmsg { ControlMessageOwned::ScmRights(fds) => Some(fds), @@ -323,6 +341,7 @@ pub fn read_frame_with_fds(socket: &impl AsRawFd) -> Result<(Vec, Vec return Err(TypedError::InternalIo { context: "recv seqpacket frame with fds".to_owned(), detail: "peer closed the socket".to_owned(), + source: None, }); } if read < 4 { @@ -357,6 +376,7 @@ pub fn io_wrap(context: &'static str) -> impl FnOnce(nix::errno::Errno) -> Typed move |err| TypedError::InternalIo { context: context.to_owned(), detail: err.to_string(), + source: error_source(err), } } diff --git a/packages/d2bd-runtime/src/wire.rs b/packages/d2bd-runtime/src/wire.rs index af9850fcc..59fe67c7c 100644 --- a/packages/d2bd-runtime/src/wire.rs +++ b/packages/d2bd-runtime/src/wire.rs @@ -1,4 +1,4 @@ -use crate::typed_error::{ErrorEnvelope, TypedError}; +use crate::typed_error::{ErrorEnvelope, TypedError, error_source}; use d2b_contracts::{FeatureFlag, Hello, HelloOk, HelloRejected, HelloRejectedReason, Version}; use d2b_contracts_broker::broker_wire::ExportBrokerAuditResponse; use d2b_contracts_control::public_wire::{self, AuditResponse, AuthStatusResponse}; @@ -395,10 +395,12 @@ pub fn negotiate_version( let accepted_req = VersionReq::parse(accepted_range).map_err(|err| TypedError::InternalConfig { detail: format!("bad acceptedClientVersionRange {accepted_range}: {err}"), + source: error_source(err), })?; let server = SemverVersion::parse(server_version).map_err(|err| TypedError::InternalConfig { detail: format!("bad serverVersion {server_version}: {err}"), + source: error_source(err), })?; if client_req.matches(&server) && accepted_req.matches(&server) { Ok(server.to_string()) @@ -421,11 +423,13 @@ pub fn hello_ok( server_version: Version::new(server_version).map_err(|err| { TypedError::InternalConfig { detail: format!("bad serverVersion {server_version}: {err}"), + source: error_source(err), } })?, selected_version: Version::new(selected_version).map_err(|err| { TypedError::InternalConfig { detail: format!("bad selectedVersion {selected_version}: {err}"), + source: error_source(err), } })?, capabilities: capabilities.to_vec(), diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index 5980d4904..1a5a7b002 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -39,7 +39,7 @@ use d2b_provider_audio_pipewire::{ use serde_json::Value; use crate::ServerState; -use crate::TypedError; +use crate::{TypedError, error_source}; use crate::audio_host_controller::{ HostAudioController, PipeWireHostController, QemuAudioController, }; @@ -498,11 +498,13 @@ fn dispatch_audio_set_volume( .ok_or_else(|| TypedError::InternalIo { context: format!("audio set-volume {vm_name}"), detail: "VM not present in public manifest".to_owned(), + source: None, })?; let cap = audio_capability_for_vm(vm).ok_or_else(|| TypedError::InternalIo { context: format!("audio set-volume {vm_name}"), detail: "audio not enabled for this VM".to_owned(), + source: None, })?; let state_dir = std::path::PathBuf::from(&vm.state_dir); @@ -513,10 +515,12 @@ fn dispatch_audio_set_volume( acquire_audio_state_lock(&lock_path, true).map_err(|e| TypedError::InternalIo { context: "acquire audio state lock".to_owned(), detail: e.to_string(), + source: error_source(e), })?; let current = read_audio_state_unlocked(&state_path).map_err(|e| TypedError::InternalIo { context: "read audio state".to_owned(), detail: e.to_string(), + source: error_source(e), })?; let old_level = match channel { @@ -537,6 +541,7 @@ fn dispatch_audio_set_volume( TypedError::InternalIo { context: "write audio state".to_owned(), detail: e.to_string(), + source: error_source(e), } })?; } @@ -547,6 +552,7 @@ fn dispatch_audio_set_volume( return Err(TypedError::InternalIo { context: "audio host enforcement".to_owned(), detail: "host level enforcement failed; state not updated".to_owned(), + source: None, }); } result @@ -559,6 +565,7 @@ fn dispatch_audio_set_volume( TypedError::InternalIo { context: "write audio state".to_owned(), detail: e.to_string(), + source: error_source(e), } })?; } @@ -605,11 +612,13 @@ fn dispatch_audio_mute( .ok_or_else(|| TypedError::InternalIo { context: format!("audio mute {vm_name}"), detail: "VM not present in public manifest".to_owned(), + source: None, })?; let cap = audio_capability_for_vm(vm).ok_or_else(|| TypedError::InternalIo { context: format!("audio mute {vm_name}"), detail: "audio not enabled for this VM".to_owned(), + source: None, })?; let state_dir = std::path::PathBuf::from(&vm.state_dir); @@ -620,10 +629,12 @@ fn dispatch_audio_mute( acquire_audio_state_lock(&lock_path, true).map_err(|e| TypedError::InternalIo { context: "acquire audio state lock".to_owned(), detail: e.to_string(), + source: error_source(e), })?; let current = read_audio_state_unlocked(&state_path).map_err(|e| TypedError::InternalIo { context: "read audio state".to_owned(), detail: e.to_string(), + source: error_source(e), })?; let grant = if mute { @@ -644,6 +655,7 @@ fn dispatch_audio_mute( TypedError::InternalIo { context: "write audio state".to_owned(), detail: e.to_string(), + source: error_source(e), } })?; } @@ -654,6 +666,7 @@ fn dispatch_audio_mute( return Err(TypedError::InternalIo { context: "audio host enforcement".to_owned(), detail: "host grant enforcement failed; state not updated".to_owned(), + source: None, }); } result @@ -666,6 +679,7 @@ fn dispatch_audio_mute( TypedError::InternalIo { context: "write audio state".to_owned(), detail: e.to_string(), + source: error_source(e), } })?; } diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0cb7d0193..41689a565 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -404,7 +404,7 @@ pub mod provider_effects; pub mod provider_registry; pub mod provider_shutdown; pub mod resource_runtime; -use d2bd_runtime::typed_error::TypedError; +use d2bd_runtime::typed_error::{TypedError, error_source}; const VM_RUNNER_ROLE_ID: &str = "ch-runner"; const VM_STOP_TIMEOUT: Duration = Duration::from_secs(30); @@ -3502,11 +3502,13 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { .map_err(|error| TypedError::InternalIo { context: "install SIGTERM shutdown handler".to_owned(), detail: error.to_string(), + source: error_source(error), })?; let mut sigint = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::interrupt()) .map_err(|error| TypedError::InternalIo { context: "install SIGINT shutdown handler".to_owned(), detail: error.to_string(), + source: error_source(error), })?; let unsafe_local_helper_uids = resolve_unsafe_local_helper_uids(&config, runtime_identity.daemon_uid)?; @@ -3516,6 +3518,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { .unsafe_local_helper_socket_gid .ok_or_else(|| TypedError::InternalConfig { detail: "unsafe-local helper socket path requires a socket group".to_owned(), + source: None, })?; Some( d2bd_runtime::unsafe_local_helper::bind_helper_socket( @@ -3526,6 +3529,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { .map_err(|error| TypedError::InternalIo { context: "bind unsafe-local helper socket".to_owned(), detail: format!("{error:?}"), + source: None, })?, ) } else { @@ -3571,6 +3575,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { |err| TypedError::InternalIo { context: format!("restore pidfd table {}", pidfd_table_path.display()), detail: err.to_string(), + source: error_source(err), }, )?); pidfd_table.set_broker_reap_log(Arc::clone(&broker_reap_log)); @@ -3677,6 +3682,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { .map_err(|error| TypedError::InternalIo { context: "spawn unsafe-local helper listener".to_owned(), detail: error.to_string(), + source: error_source(error), })?; } refresh_activation_marker_metrics_on_startup(&state).await; @@ -3756,6 +3762,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { TypedError::InternalIo { context: "authoritative resource-plane start audit".to_owned(), detail: error.to_string(), + source: error_source(error), } })?; } @@ -3893,6 +3900,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { context: "authoritative resource-plane refusal audit" .to_owned(), detail: audit_error.to_string(), + source: error_source(audit_error), } })?; } @@ -4076,6 +4084,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { let accept_error = TypedError::InternalIo { context: "accept public seqpacket client".to_owned(), detail: error.to_string(), + source: error_source(error), }; if let Err(cleanup_error) = finalize_daemon_interactions(&state).await { tracing::error!( @@ -4096,6 +4105,7 @@ pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { .map_err(|error| TypedError::InternalIo { context: "set accepted public socket blocking".to_owned(), detail: error.to_string(), + source: error_source(error), })?; // The `once` test path stays fully synchronous/inline so unit @@ -4251,6 +4261,7 @@ fn validate_gateway_guest_observation_path( if path != Path::new(GATEWAY_GUEST_OPEN_OBSERVATION_PATH) { return Err(TypedError::InternalConfig { detail: "Guest gateway observation path is invalid".to_owned(), + source: None, }); } Ok(Some(path)) @@ -4270,20 +4281,24 @@ async fn load_gateway_guest_zone_link_options( Err(_) => { return Err(TypedError::InternalConfig { detail: "Guest gateway configuration unavailable".to_owned(), + source: None, }); } }; if metadata.file_type().is_symlink() || !metadata.is_file() { return Err(TypedError::InternalConfig { detail: "Guest gateway configuration is not a regular file".to_owned(), + source: None, }); } let bytes = tokio::fs::read(config_path).await.map_err(|_| TypedError::InternalConfig { detail: "Guest gateway configuration unavailable".to_owned(), + source: None, })?; let config: GatewayGuestConfigFile = serde_json::from_slice(&bytes).map_err(|_| TypedError::InternalConfig { detail: "Guest gateway configuration is invalid".to_owned(), + source: None, })?; let observation_path = validate_gateway_guest_observation_path(config.observation_path)?; let namespace = config @@ -4291,25 +4306,30 @@ async fn load_gateway_guest_zone_link_options( .namespace .ok_or_else(|| TypedError::InternalConfig { detail: "Guest Relay namespace is unavailable".to_owned(), + source: None, })?; let entity = config .relay .entity .ok_or_else(|| TypedError::InternalConfig { detail: "Guest Relay entity is unavailable".to_owned(), + source: None, })?; let settings = RelayTransportSettings::new(namespace, entity).map_err(|_| TypedError::InternalConfig { detail: "Guest Relay settings are invalid".to_owned(), + source: None, })?; let bundle_bytes = bundle .zone_resource_bundle_bytes(identity.zone().as_str()) .ok_or_else(|| TypedError::InternalConfig { detail: "Guest Zone resource bundle is unavailable".to_owned(), + source: None, })?; let zone_bundle = ResourceBundle::from_json(bundle_bytes).map_err(|_| TypedError::InternalConfig { detail: "Guest Zone resource bundle is invalid".to_owned(), + source: None, })?; let providers = zone_bundle .resources @@ -4326,17 +4346,20 @@ async fn load_gateway_guest_zone_link_options( let [provider] = providers.as_slice() else { return Err(TypedError::InternalConfig { detail: "Guest Relay Provider assignment is unavailable".to_owned(), + source: None, }); }; let provider_spec = serde_json::from_slice::(&provider.spec().to_canonical_bytes()) .map_err(|_| TypedError::InternalConfig { detail: "Guest Relay Provider configuration is invalid".to_owned(), + source: None, })?; let provider_config = provider_spec .get("config") .and_then(Value::as_object) .ok_or_else(|| TypedError::InternalConfig { detail: "Guest Relay Provider configuration is unavailable".to_owned(), + source: None, })?; let execution_ref = provider_config .get("executionRef") @@ -4344,6 +4367,7 @@ async fn load_gateway_guest_zone_link_options( .and_then(|value| ResourceRef::parse(value).ok()) .ok_or_else(|| TypedError::InternalConfig { detail: "Guest Relay execution assignment is invalid".to_owned(), + source: None, })?; let network_ref = provider_config .get("networkRef") @@ -4351,6 +4375,7 @@ async fn load_gateway_guest_zone_link_options( .and_then(|value| ResourceRef::parse(value).ok()) .ok_or_else(|| TypedError::InternalConfig { detail: "Guest Relay network assignment is invalid".to_owned(), + source: None, })?; if execution_ref != *identity.guest_ref() || execution_ref.resource_type().as_str() != "Guest" @@ -4358,6 +4383,7 @@ async fn load_gateway_guest_zone_link_options( { return Err(TypedError::InternalConfig { detail: "Guest Relay Provider placement is invalid".to_owned(), + source: None, }); } Ok(Some(GatewayGuestZoneLinkOptions { @@ -4437,6 +4463,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { if !options.state_dir.is_absolute() || !options.broker_socket_path.is_absolute() { return Err(TypedError::InternalConfig { detail: "guest mode requires absolute state and broker paths".to_owned(), + source: None, }); } // The production path is sealed to the kernel's boot-id file. A custom @@ -4450,32 +4477,39 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { let boot = d2bd_runtime::guest_mode::BootIdentity::read(&boot_id_path).map_err(|_| { TypedError::InternalConfig { detail: "guest kernel boot identity unavailable".to_owned(), + source: None, } })?; let guest_ref = ResourceRef::parse(&options.guest_ref).map_err(|_| TypedError::InternalConfig { detail: "guest identity reference is invalid".to_owned(), + source: None, })?; let guest_uid = kernel_guest_uid().await.unwrap_or(options.guest_uid); let guest_uid = ResourceUid::parse(guest_uid).map_err(|_| TypedError::InternalConfig { detail: "guest identity UID is invalid".to_owned(), + source: None, })?; let zone = ZoneId::parse(options.zone).map_err(|_| TypedError::InternalConfig { detail: "guest Zone identity is invalid".to_owned(), + source: None, })?; let purpose = d2b_contracts_resource::v3::identity::SessionPurpose::parse(options.purpose) .map_err(|_| TypedError::InternalConfig { detail: "guest session purpose is invalid".to_owned(), + source: None, })?; let schema = SchemaFingerprint::parse(options.schema_fingerprint).map_err(|_| { TypedError::InternalConfig { detail: "guest session schema fingerprint is invalid".to_owned(), + source: None, } })?; let reconnect_generation = ReconnectGeneration::new(options.reconnect_generation).map_err(|_| { TypedError::InternalConfig { detail: "guest reconnect generation is invalid".to_owned(), + source: None, } })?; let identity = d2bd_runtime::guest_mode::GuestIdentity::new( @@ -4492,6 +4526,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { ) .map_err(|error| TypedError::InternalConfig { detail: error.to_string(), + source: error_source(error), })?; if options.validate_only { return Ok(()); @@ -4502,6 +4537,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { .await .map_err(|_| TypedError::InternalConfig { detail: "guest state root unavailable".to_owned(), + source: None, })?; let runtime = d2bd_runtime::guest_mode::GuestRuntime::new( identity.clone(), @@ -4512,6 +4548,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { .await .map_err(|error| TypedError::InternalConfig { detail: error.to_string(), + source: error_source(error), })?; let bundle = BundleResolver::load_on_loader_worker(&options.bundle_path) .await @@ -4523,6 +4560,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { }) .map_err(|_| TypedError::InternalConfig { detail: "guest process bundle unavailable".to_owned(), + source: None, })?; let gateway_zone_link = load_gateway_guest_zone_link_options( options.gateway_zone_link_config_path.as_deref(), @@ -4546,6 +4584,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { ) .map_err(|error| TypedError::InternalConfig { detail: error.code().to_owned(), + source: None, })?; Ok::<_, TypedError>((runtime, observation_path)) }) @@ -4562,18 +4601,21 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { .local_private_key_path .ok_or_else(|| TypedError::InternalConfig { detail: "guest ComponentSession private key is unavailable".to_owned(), + source: None, })?; let parent_public_path = options .parent_public_key_path .ok_or_else(|| TypedError::InternalConfig { detail: "parent Zone ComponentSession key is unavailable".to_owned(), + source: None, })?; let parent_public = read_public_key32(&parent_public_path).await?; let mut listener = runtime .bind_listener() .map_err(|error| TypedError::InternalConfig { detail: error.to_string(), + source: error_source(error), })?; tracing::info!( port = d2bd_runtime::guest_mode::GUEST_COMPONENT_SESSION_PORT, @@ -4584,6 +4626,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { .write_open_observation(observation_path) .map_err(|error| TypedError::InternalConfig { detail: error.code().to_owned(), + source: None, })?; } // Guest target-control (U13 guest half): one target runtime per Guest, @@ -4596,6 +4639,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { d2b_resource_runtime::target::TargetRef::guest(identity.guest_ref().name().as_str()) .map_err(|error| TypedError::InternalConfig { detail: error.to_string(), + source: error_source(error), })?; let target_service = std::sync::Arc::new( d2b_provider_guest::GuestTargetService::new( @@ -4615,11 +4659,13 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { .map_err(|_| TypedError::InternalIo { context: "install Guest SIGTERM handler".to_owned(), detail: "signal handler unavailable".to_owned(), + source: None, })?; let mut sigint = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::interrupt()) .map_err(|_| TypedError::InternalIo { context: "install Guest SIGINT handler".to_owned(), detail: "signal handler unavailable".to_owned(), + source: None, })?; let mut active: Option<( tokio::task::JoinHandle>, @@ -4721,6 +4767,7 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { if options.once { return Err(TypedError::InternalConfig { detail: error.to_string(), + source: error_source(error), }); } tracing::warn!(error = %error, "Guest ComponentSession handshake refused"); @@ -4801,25 +4848,31 @@ pub async fn serve_guest(options: GuestServeOptions) -> Result<(), TypedError> { async fn read_secret32(path: &Path) -> Result { let bytes = tokio::fs::read(path).await.map_err(|_| TypedError::InternalConfig { detail: "guest ComponentSession private key unavailable".to_owned(), + source: None, })?; let bytes: [u8; 32] = bytes.try_into().map_err(|_| TypedError::InternalConfig { detail: "guest ComponentSession private key has invalid length".to_owned(), + source: None, })?; d2b_session::Secret32::new(bytes).map_err(|_| TypedError::InternalConfig { detail: "guest ComponentSession private key is invalid".to_owned(), + source: None, }) } async fn read_public_key32(path: &Path) -> Result<[u8; 32], TypedError> { let bytes = tokio::fs::read(path).await.map_err(|_| TypedError::InternalConfig { detail: "parent Zone ComponentSession key unavailable".to_owned(), + source: None, })?; let bytes: [u8; 32] = bytes.try_into().map_err(|_| TypedError::InternalConfig { detail: "parent Zone ComponentSession key has invalid length".to_owned(), + source: None, })?; if bytes == [0; 32] { return Err(TypedError::InternalConfig { detail: "parent Zone ComponentSession key is invalid".to_owned(), + source: None, }); } Ok(bytes) @@ -4873,6 +4926,7 @@ async fn finalize_daemon_interactions(state: &ServerState) -> Result<(), TypedEr Some(TypedError::InternalIo { context: "interaction Provider finalization".to_owned(), detail: error.to_string(), + source: error_source(error), }) } else { None @@ -4897,6 +4951,7 @@ async fn finalize_daemon_interactions(state: &ServerState) -> Result<(), TypedEr resource_result.map_err(|error| TypedError::InternalIo { context: "authoritative resource-plane shutdown audit".to_owned(), detail: error.to_string(), + source: error_source(error), }) } @@ -5059,6 +5114,7 @@ async fn adopt_orphaned_runners_on_startup_with( TypedError::InternalIo { context: "enumerate daemon runner snapshots".to_owned(), detail: err.to_string(), + source: error_source(err), } })?; if snapshots.is_empty() { @@ -5145,6 +5201,7 @@ async fn adopt_orphaned_runners_on_startup_with( return Err(TypedError::InternalIo { context: "register adopted pidfd".to_owned(), detail: error.to_string(), + source: error_source(error), }); } } @@ -5177,6 +5234,7 @@ async fn adopt_orphaned_runners_on_startup_with( .map_err(|err| TypedError::InternalIo { context: "remove missing runner snapshot".to_owned(), detail: err.to_string(), + source: error_source(err), })?; tracing::info!( vm = %adopt.vm, @@ -5204,6 +5262,7 @@ async fn adopt_orphaned_runners_on_startup_with( .map_err(|err| TypedError::InternalIo { context: "remove raced runner snapshot".to_owned(), detail: err.to_string(), + source: error_source(err), })?; tracing::warn!( vm = %adopt.vm, @@ -5231,6 +5290,7 @@ async fn adopt_orphaned_runners_on_startup_with( .map_err(|err| TypedError::InternalIo { context: "persist adopted pidfd table".to_owned(), detail: err.to_string(), + source: error_source(err), })?; Ok(()) } @@ -5610,6 +5670,7 @@ fn handle_connection_authorized( return Err(TypedError::InternalIo { context: "spawn typed shell owner handler".to_owned(), detail: err.to_string(), + source: error_source(err), }); } } @@ -5646,6 +5707,7 @@ fn handle_connection_authorized( return Err(TypedError::InternalIo { context: "spawn Process resource owner".to_owned(), detail: err.to_string(), + source: error_source(err), }); } } @@ -5657,6 +5719,7 @@ fn handle_connection_authorized( .map_err(|err| TypedError::InternalIo { context: "serialize error response".to_owned(), detail: err.to_string(), + source: error_source(err), })?, }; write_json_frame(&stream, &response)?; @@ -6198,13 +6261,16 @@ fn dispatch_config_nixos_service_request( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "resource plane unavailable".to_owned(), + source: None, })? .clone() .ok_or_else(|| TypedError::InternalConfig { detail: "resource plane unavailable".to_owned(), + source: None, })?; let runtime = plane.zone(&zone).map_err(|_| TypedError::InternalConfig { detail: "config-nixos Zone runtime unavailable".to_owned(), + source: None, })?; let guest_lookup = json!({ "zoneRef": format!("Zone/{}", zone.as_str()), @@ -6215,6 +6281,7 @@ fn dispatch_config_nixos_service_request( let guest = drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&guest_lookup, peer.uid)) .map_err(|_| TypedError::InternalConfig { detail: "config-nixos Guest lookup failed".to_owned(), + source: None, })?; if guest.get("kind").is_some() { return Err(TypedError::AuthzNotAdmin { @@ -6243,6 +6310,7 @@ fn dispatch_config_nixos_service_request( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "config staging state unavailable".to_owned(), + source: None, })? .stage( d2b_provider_config_nixos::ConfigCaller::Admin, @@ -6264,6 +6332,7 @@ fn dispatch_config_nixos_service_request( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "config staging state unavailable".to_owned(), + source: None, })? .diff(d2b_provider_config_nixos::ConfigCaller::Admin, &zone, &diff) .map_err(config_nixos_wire_error)?; @@ -6281,6 +6350,7 @@ fn dispatch_config_nixos_service_request( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "config staging state unavailable".to_owned(), + source: None, })? .approve( d2b_provider_config_nixos::ConfigCaller::Admin, @@ -6302,6 +6372,7 @@ fn dispatch_config_nixos_service_request( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "config staging state unavailable".to_owned(), + source: None, })? .reject( d2b_provider_config_nixos::ConfigCaller::Admin, @@ -6323,6 +6394,7 @@ fn dispatch_config_nixos_service_request( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "config staging state unavailable".to_owned(), + source: None, })? .status( d2b_provider_config_nixos::ConfigCaller::Admin, @@ -8345,6 +8417,7 @@ fn record_workload_launch_result( .map_err(|_| TypedError::InternalIo { context: "authoritative workload audit".to_owned(), detail: "daemon audit unavailable".to_owned(), + source: None, }) } @@ -9014,6 +9087,7 @@ fn console_sessions_table<'a>( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "console session table unavailable".to_owned(), + source: None, }) } @@ -9078,6 +9152,7 @@ fn dispatch_console( .attach(vm, peer.uid) .map_err(|_| TypedError::InternalConfig { detail: "console: failed to allocate secure session handle".to_owned(), + source: None, })?; match attach_result { Some((handle, kind, start_offset)) => { @@ -9453,6 +9528,7 @@ fn refresh_qemu_media_registry_index_if_needed_as( BrokerResponse::Error(error) => Err(TypedError::InternalIo { context: "refresh qemu-media registry index".to_owned(), detail: format!("{}:{}", error.operation, error.kind), + source: None, }), other => Err(TypedError::InternalIo { context: "refresh qemu-media registry index".to_owned(), @@ -9460,6 +9536,7 @@ fn refresh_qemu_media_registry_index_if_needed_as( "unexpected broker response {}", broker_response_kind(&other) ), + source: None, }), } } @@ -9595,6 +9672,7 @@ fn dispatch_broker_usbip_probe( other => TypedError::InternalIo { context: "load bundle resolver".to_owned(), detail: other.to_string(), + source: error_source(other), }, })?; refresh_qemu_media_registry_index_if_needed_as(state, &resolver, caller_role.clone())?; @@ -13999,6 +14077,7 @@ fn dispatch_broker_request_as( serde_json::from_slice(&response).map_err(|err| TypedError::InternalBrokerUnavailable { path: socket_path, detail: err.to_string(), + source: error_source(err), })?; Ok(decoded) } @@ -14232,6 +14311,7 @@ fn bundle_resolver_load_error(err: d2b_core::error::Error) -> TypedError { other => TypedError::InternalIo { context: "load bundle resolver".to_owned(), detail: other.to_string(), + source: error_source(other), }, } } @@ -15351,10 +15431,12 @@ fn acquire_vm_start_lock(state: &ServerState, vm: &str) -> Result, T .map_err(|err| TypedError::InternalIo { context: format!("open VM start lock {}", path.display()), detail: err.to_string(), + source: error_source(err), })?; Flock::lock(file, FlockArg::LockExclusive).map_err(|(_file, err)| TypedError::InternalIo { context: format!("lock VM start lock {}", path.display()), detail: err.to_string(), + source: error_source(err), }) } @@ -16886,6 +16968,7 @@ fn dispatch_raw_broker_value_with_timeout( .map_err(|err| TypedError::InternalIo { context: format!("set raw broker write timeout to {remaining:?}"), detail: err.to_string(), + source: error_source(err), })?; write_json_frame(&socket, &envelope)?; let remaining = broker_remaining_before_op(deadline, &socket_path)?; @@ -16894,11 +16977,13 @@ fn dispatch_raw_broker_value_with_timeout( .map_err(|err| TypedError::InternalIo { context: format!("set raw broker read timeout to {remaining:?}"), detail: err.to_string(), + source: error_source(err), })?; let response = read_frame(&socket)?; serde_json::from_slice(&response).map_err(|err| TypedError::InternalBrokerUnavailable { path: socket_path, detail: err.to_string(), + source: error_source(err), }) } @@ -17124,6 +17209,7 @@ async fn raw_broker_round_trip_async( let envelope_bytes = serde_json::to_vec(&envelope).map_err(|err| TypedError::InternalIo { context: "serialize raw broker request".to_owned(), detail: err.to_string(), + source: error_source(err), })?; let remaining = broker_remaining_before_op(deadline, &socket_path)?; packet.write_frame(&envelope_bytes, remaining).await?; @@ -17132,6 +17218,7 @@ async fn raw_broker_round_trip_async( serde_json::from_slice(&response).map_err(|err| TypedError::InternalBrokerUnavailable { path: socket_path, detail: err.to_string(), + source: error_source(err), }) } @@ -19007,6 +19094,7 @@ fn provider_lifecycle_authorization( let target = ResourceRef::parse(&format!("Guest/{guest}")).map_err(|_| TypedError::InternalConfig { detail: "Guest lifecycle target is invalid".to_owned(), + source: None, })?; let zone = drive_sync(&state.runtime_handle, d2bd_runtime::zone_authority::authoritative_zone_for_vm( &state.zone_coordinator, @@ -19014,12 +19102,14 @@ fn provider_lifecycle_authorization( )) .map_err(|_| TypedError::InternalConfig { detail: "Guest lifecycle Zone identity is unavailable".to_owned(), + source: None, })?; let plane = state .resource_plane .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "Guest lifecycle resource plane is unavailable".to_owned(), + source: None, })? .clone(); let runtime = plane.as_ref().and_then(|plane| plane.zone(&zone).ok()); @@ -19038,6 +19128,7 @@ fn provider_lifecycle_authorization( ) .map_err(|_| TypedError::InternalConfig { detail: "Host shutdown lifecycle lease is invalid".to_owned(), + source: None, }); } return Ok(provider_effects::LifecycleAuthorization::for_test( @@ -19053,6 +19144,7 @@ fn provider_lifecycle_authorization( { return Err(TypedError::InternalConfig { detail: "Guest lifecycle resource runtime is unavailable".to_owned(), + source: None, }); } }; @@ -19061,6 +19153,7 @@ fn provider_lifecycle_authorization( drive_sync(&state.runtime_handle, runtime.admit_internal_guest_lifecycle(target.clone(), operation_id)) .map_err(|_| TypedError::InternalConfig { detail: "internal Guest lifecycle authorization is unavailable".to_owned(), + source: None, })?; return provider_effects::LifecycleAuthorization::from_lease( admission.lease, @@ -19071,12 +19164,14 @@ fn provider_lifecycle_authorization( ) .map_err(|_| TypedError::InternalConfig { detail: "internal Guest lifecycle authorization lease is invalid".to_owned(), + source: None, }); } let (zone_uid, guest_uid, guest_generation, provider_generation) = drive_sync(&state.runtime_handle, runtime.guest_lifecycle_identity(&target)).map_err(|_| { TypedError::InternalConfig { detail: "Guest lifecycle identity is unavailable".to_owned(), + source: None, } })?; if matches!(caller_role, BrokerCallerRole::HostShutdownUid { .. }) { @@ -19091,6 +19186,7 @@ fn provider_lifecycle_authorization( ) .map_err(|_| TypedError::InternalConfig { detail: "Host shutdown lifecycle lease is invalid".to_owned(), + source: None, }); } let admission = drive_sync(&state.runtime_handle, runtime.admit_guest_lifecycle( @@ -19100,11 +19196,13 @@ fn provider_lifecycle_authorization( )) .map_err(|_| TypedError::InternalConfig { detail: "Guest lifecycle authorization is unavailable".to_owned(), + source: None, })?; provider_effects::LifecycleAuthorization::from_lease( admission.lease, ResourceRef::parse(&format!("Guest/{guest}")).map_err(|_| TypedError::InternalConfig { detail: "Guest lifecycle target is invalid".to_owned(), + source: None, })?, admission.guest_uid, admission.guest_generation, @@ -19112,6 +19210,7 @@ fn provider_lifecycle_authorization( ) .map_err(|_| TypedError::InternalConfig { detail: "Guest lifecycle authorization lease is invalid".to_owned(), + source: None, }) } @@ -19189,6 +19288,7 @@ fn dispatch_broker_vm_start_inner( .map_err(|error| TypedError::InternalIo { context: format!("load process DAG for {}", request.vm), detail: error.kind().to_owned(), + source: error_source(error), })? .vms .into_iter() @@ -19196,6 +19296,7 @@ fn dispatch_broker_vm_start_inner( .ok_or_else(|| TypedError::InternalIo { context: format!("load process DAG for {}", request.vm), detail: "VM not present in processes.json".to_owned(), + source: None, })?; let runner = VmStartRunner { @@ -20061,6 +20162,7 @@ fn dispatch_broker_host_prepare_as( TypedError::InternalBrokerUnavailable { path: broker_socket_path(state), detail: format!("host nft intent resolution failed: {reason}"), + source: None, } })?; if let Err(response) = dispatch_broker_kernel_ack( @@ -20080,6 +20182,7 @@ fn dispatch_broker_host_prepare_as( .ok_or(TypedError::InternalBrokerUnavailable { path: broker_socket_path(state), detail: "installed generation unavailable for Network effect context".to_owned(), + source: None, })?; let context = d2b_provider_network_local::broker::NetworkEffectContext::for_host_nm( ScopeId::new("host"), @@ -20088,6 +20191,7 @@ fn dispatch_broker_host_prepare_as( .map_err(|_| TypedError::InternalBrokerUnavailable { path: broker_socket_path(state), detail: "installed generation invalid for Network effect context".to_owned(), + source: None, })?, ); // U14: the kernel-invoking adapter is the declaring crate's own @@ -20140,6 +20244,7 @@ fn dispatch_broker_host_destroy_as( .ok_or(TypedError::InternalBrokerUnavailable { path: broker_socket_path(state), detail: "host nm-unmanaged intent missing".to_owned(), + source: None, })? .clone(); let nm_payload = serde_json::json!({ @@ -20167,6 +20272,7 @@ fn dispatch_broker_host_destroy_as( TypedError::InternalBrokerUnavailable { path: broker_socket_path(state), detail: format!("host nft intent resolution failed: {reason}"), + source: None, } })?; if let Err(response) = dispatch_broker_kernel_ack( @@ -20218,6 +20324,7 @@ fn dispatch_broker_host_reconcile_as( TypedError::InternalBrokerUnavailable { path: broker_socket_path(state), detail: format!("host nft intent resolution failed: {reason}"), + source: None, } })?; if let Err(response) = dispatch_broker_kernel_ack( @@ -20519,18 +20626,22 @@ fn dispatch_live_guest_activation_resource( .try_lock() .map_err(|_| TypedError::InternalConfig { detail: "resource plane unavailable".to_owned(), + source: None, })? .clone() .ok_or_else(|| TypedError::InternalConfig { detail: "resource plane unavailable".to_owned(), + source: None, })?; let runtime = plane.zone(zone).map_err(|_| TypedError::InternalConfig { detail: "activation Zone runtime unavailable".to_owned(), + source: None, })?; let guest_ref_text = format!("Guest/{}", request.vm); let guest_ref = ResourceRef::parse(&guest_ref_text).map_err(|_| TypedError::InternalConfig { detail: "activation Guest reference invalid".to_owned(), + source: None, })?; let guest_ref_canonical = guest_ref.to_canonical_string(); let get_guest = json!({ @@ -20542,10 +20653,12 @@ fn dispatch_live_guest_activation_resource( let guest = drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&get_guest, peer_uid)) .map_err(|_| TypedError::InternalConfig { detail: "activation Guest resource unavailable".to_owned(), + source: None, })?; if guest.get("kind").is_some() { return Err(TypedError::InternalConfig { detail: "activation Guest resource unavailable".to_owned(), + source: None, }); } let list = json!({ @@ -20559,12 +20672,14 @@ fn dispatch_live_guest_activation_resource( let resources = drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&list, peer_uid)) .map_err(|_| TypedError::InternalConfig { detail: "activation generations unavailable".to_owned(), + source: None, })?; let (ordinal, artifact) = if mode == DaemonActivationMode::Rollback{ let target_ordinal = request .to_generation .ok_or_else(|| TypedError::InternalConfig { detail: "rollback target generation unavailable".to_owned(), + source: None, })?; let artifact = resources .get("resources") @@ -20591,6 +20706,7 @@ fn dispatch_live_guest_activation_resource( }) .ok_or_else(|| TypedError::InternalConfig { detail: "rollback target generation is not retained".to_owned(), + source: None, })?; (target_ordinal, artifact.to_owned()) } else { @@ -20626,6 +20742,7 @@ fn dispatch_live_guest_activation_resource( .and_then(Value::as_str) .ok_or_else(|| TypedError::InternalConfig { detail: "activation system artifact unavailable".to_owned(), + source: None, })?; (ordinal, artifact.to_owned()) }; @@ -20650,6 +20767,7 @@ fn dispatch_live_guest_activation_resource( drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&create, peer_uid)).map_err(|_| { TypedError::InternalConfig { detail: "activation resource create failed".to_owned(), + source: None, } })?; if created @@ -20659,6 +20777,7 @@ fn dispatch_live_guest_activation_resource( { return Err(TypedError::InternalConfig { detail: "activation resource create refused".to_owned(), + source: None, }); } let deadline = Instant::now() + live_activation_timeout_for(state, &request.vm); @@ -20683,6 +20802,7 @@ fn dispatch_live_guest_activation_resource( let current = drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&get, peer_uid)) .map_err(|_| TypedError::InternalConfig { detail: "activation resource status unavailable".to_owned(), + source: None, })?; let current_spec = current.get("spec"); if current_spec.and_then(|spec| spec.get("executionRef")) != spec.get("executionRef") @@ -21454,7 +21574,8 @@ mod public_status_tests { test_state_with_config(DaemonConfig::default()) } - fn test_state_with_config(config: DaemonConfig) -> (ServerState, tempfile::TempDir) { + /// Shared with sibling test modules that need a bare daemon state. + pub(super) fn test_state_with_config(config: DaemonConfig) -> (ServerState, tempfile::TempDir) { let dir = tempfile::tempdir().expect("temp daemon state"); let broker_reap_log = BrokerReapLog::new(); let state = ServerState { @@ -22919,16 +23040,19 @@ fn dispatch_audit( TypedError::InternalIo { context: "serialize audit response".to_owned(), detail: err.to_string(), + source: error_source(err), } }) } BrokerResponse::Error(error) => Err(TypedError::InternalBrokerUnavailable { path: state.config.broker_socket_path.clone(), detail: error.kind, + source: None, }), _ => Err(TypedError::InternalBrokerUnavailable { path: state.config.broker_socket_path.clone(), detail: "broker returned an unexpected audit response".to_owned(), + source: None, }), } } @@ -30232,7 +30356,7 @@ mod loader_worker_refusal_tests { fn assert_bundle_loader_refusal(error: TypedError, name: &str) { match error { - TypedError::InternalIo { context, detail } => { + TypedError::InternalIo { context, detail, .. } => { assert_eq!(context, "load bundle resolver"); assert!( detail.contains(name), @@ -30307,3 +30431,111 @@ mod loader_worker_refusal_tests { } } } + +/// The daemon's typed refusals carry the error they were raised from: the +/// public envelope keeps rendering the same strings, while +/// `std::error::Error::source()` still reaches the origin so the chain +/// survives to the logging boundary. +#[cfg(test)] +mod typed_error_source_tests { + use super::*; + + /// A real call site: the VM-start lock open fails, and the refusal keeps + /// the `io::Error` behind its operator-visible `detail` string. + #[test] + fn vm_start_lock_failure_carries_the_origin_error() { + let locks_dir = tempfile::tempdir().expect("temp locks dir"); + let missing_locks_dir = locks_dir.path().join("absent"); + let (state, _state_dir) = public_status_tests::test_state_with_config(DaemonConfig { + locks_dir: missing_locks_dir.clone(), + ..DaemonConfig::default() + }); + + let error = acquire_vm_start_lock(&state, "alpha").expect_err("lock directory is absent"); + + assert_eq!(error.kind(), "internal-io"); + assert_eq!(error.message(), "internal I/O failure"); + let TypedError::InternalIo { + context, + detail, + source, + } = &error + else { + panic!("expected an internal-io refusal, got {error:?}"); + }; + let expected_path = missing_locks_dir.join("vm-start-alpha.lock"); + assert_eq!( + context, + &format!("open VM start lock {}", expected_path.display()) + ); + assert!(source.is_some(), "the call site attaches the origin error"); + + let origin = std::error::Error::source(&error).expect("origin error on the chain"); + assert_eq!(origin.to_string(), *detail); + let io = origin + .downcast_ref::() + .expect("the origin is the fs open failure"); + assert_eq!(io.kind(), std::io::ErrorKind::NotFound); + } + + /// The daemon wire error surface is `kind`/`exitCode`/`message`/ + /// `remediation`: attaching an origin renders byte-identically to a + /// variant without one. + #[test] + fn error_envelope_is_byte_identical_with_an_attached_origin() { + let detail = "No such file or directory (os error 2)".to_owned(); + let without_origin = TypedError::InternalIo { + context: "read daemon config".to_owned(), + detail: detail.clone(), + source: None, + }; + let with_origin = TypedError::InternalIo { + context: "read daemon config".to_owned(), + detail, + source: error_source(std::io::Error::from_raw_os_error(libc::ENOENT)), + }; + + let without = + serde_json::to_string(&without_origin.to_envelope_value()).expect("render the envelope"); + let with = + serde_json::to_string(&with_origin.to_envelope_value()).expect("render the envelope"); + assert_eq!(without, with); + assert!(without.contains("\"kind\":\"internal-io\""), "{without}"); + } + + /// The chain is what the daemon logs, not just its first link. + #[test] + fn origin_chain_reaches_the_root_cause() { + #[derive(Debug)] + struct ReadOnlyVolume { + cause: std::io::Error, + } + + impl std::fmt::Display for ReadOnlyVolume { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("cannot write daemon config") + } + } + + impl std::error::Error for ReadOnlyVolume { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + Some(&self.cause) + } + } + + let error = TypedError::InternalConfig { + detail: ReadOnlyVolume { + cause: std::io::Error::new(std::io::ErrorKind::PermissionDenied, "read-only volume"), + } + .to_string(), + source: error_source(ReadOnlyVolume { + cause: std::io::Error::new(std::io::ErrorKind::PermissionDenied, "read-only volume"), + }), + }; + + let origin = std::error::Error::source(&error).expect("origin error on the chain"); + assert_eq!(origin.to_string(), "cannot write daemon config"); + let root = origin.source().expect("the origin keeps its own cause"); + assert_eq!(root.to_string(), "read-only volume"); + } +} diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index eacfc0539..ec4382800 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -90,7 +90,7 @@ use d2b_provider_toolkit::operations::{UNCOMMITTED_OPERATION, UNGRANTED_CALLER}; use d2b_resource_types::{KernelCaller, MethodFdContract, OperationResult}; use d2bd_runtime::concurrency::DEFAULT_MAX_INFLIGHT_CONNECTIONS; use d2bd_runtime::runtime_process::{RuntimeIdentity, bind_public_socket}; -use d2bd_runtime::typed_error::TypedError; +use d2bd_runtime::typed_error::{ErrorSource, TypedError, error_source}; use d2bd_runtime::unix_transport::{close_received_fds, read_frame_with_fds, write_frame_with_fds}; use d2bd_runtime::wire::MAX_FRAME_SIZE; use nix::sys::socket::{MsgFlags, getsockopt, recv, send, sockopt}; @@ -1331,10 +1331,12 @@ impl AsyncSeqpacket { .map_err(|error| TypedError::InternalIo { context: "set forward rendezvous socket nonblocking".to_owned(), detail: error.to_string(), + source: error_source(error), })?; let io = AsyncFd::new(socket).map_err(|error| TypedError::InternalIo { context: "register forward rendezvous socket".to_owned(), detail: error.to_string(), + source: error_source(error), })?; Ok(Self { io }) } @@ -1350,6 +1352,7 @@ impl AsyncSeqpacket { .map_err(|error| TypedError::InternalIo { context: "read forward rendezvous peer credentials".to_owned(), detail: error.to_string(), + source: error_source(error), }) } @@ -1386,8 +1389,8 @@ impl AsyncSeqpacket { .await { Ok(Ok(read)) => read, - Ok(Err(error)) => return Err(recv_failure(error.to_string())), - Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"))), + Ok(Err(error)) => return Err(recv_failure(error.to_string(), error_source(error))), + Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"), None)), }; if peeked < 4 { // A datagram shorter than the prefix is malformed; consume it @@ -1396,8 +1399,8 @@ impl AsyncSeqpacket { let mut short = [0u8; 4]; let read = match tokio::time::timeout(deadline, self.recv_datagram(&mut short)).await { Ok(Ok(read)) => read, - Ok(Err(error)) => return Err(recv_failure(error.to_string())), - Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"))), + Ok(Err(error)) => return Err(recv_failure(error.to_string(), error_source(error))), + Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"), None)), }; return decode_frame(&short[..read]); } @@ -1408,8 +1411,8 @@ impl AsyncSeqpacket { let mut datagram = vec![0u8; declared + 5]; let read = match tokio::time::timeout(deadline, self.recv_datagram(&mut datagram)).await { Ok(Ok(read)) => read, - Ok(Err(error)) => return Err(recv_failure(error.to_string())), - Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"))), + Ok(Err(error)) => return Err(recv_failure(error.to_string(), error_source(error))), + Err(_) => return Err(recv_failure(format!("no frame within {deadline:?}"), None)), }; decode_frame(&datagram[..read]) } @@ -1419,14 +1422,14 @@ impl AsyncSeqpacket { let frame = encode_frame(body)?; let written = match tokio::time::timeout(deadline, self.send_datagram(&frame)).await { Ok(Ok(written)) => written, - Ok(Err(error)) => return Err(send_failure(error.to_string())), - Err(_) => return Err(send_failure(format!("no write within {deadline:?}"))), + Ok(Err(error)) => return Err(send_failure(error.to_string(), error_source(error))), + Err(_) => return Err(send_failure(format!("no write within {deadline:?}"), None)), }; if written != frame.len() { - return Err(send_failure(format!( - "short write: {written} of {}", - frame.len() - ))); + return Err(send_failure( + format!("short write: {written} of {}", frame.len()), + None, + )); } Ok(()) } @@ -1445,8 +1448,8 @@ impl AsyncSeqpacket { // payload,length-checked and cmsg-truncation-checked. match tokio::time::timeout(deadline, self.recv_frame_with_fds()).await { Ok(Ok(pair)) => Ok(pair), - Ok(Err(error)) => Err(recv_failure(error.to_string())), - Err(_) => Err(recv_failure(format!("no frame within {deadline:?}"))), + Ok(Err(error)) => Err(recv_failure(error.to_string(), error_source(error))), + Err(_) => Err(recv_failure(format!("no frame within {deadline:?}"), None)), } } @@ -1462,8 +1465,8 @@ impl AsyncSeqpacket { // as-is;the receiving transport strips the same prefix back off.. match tokio::time::timeout(deadline, self.send_datagram_with_fds(body, fds)).await { Ok(Ok(())) => Ok(()), - Ok(Err(error)) => Err(send_failure(error.to_string())), - Err(_) => Err(send_failure(format!("no write within {deadline:?}"))), + Ok(Err(error)) => Err(send_failure(error.to_string(), error_source(error))), + Err(_) => Err(send_failure(format!("no write within {deadline:?}"), None)), } } @@ -1535,20 +1538,24 @@ impl AsyncSeqpacket { } /// The failure of a frame read, in the vocabulary the blocking transport uses -/// for the same syscall. -fn recv_failure(detail: String) -> TypedError { +/// for the same syscall. `source` is the origin error when the read failed on +/// one; a deadline that elapsed without a frame has none. +fn recv_failure(detail: String, source: Option) -> TypedError { TypedError::InternalIo { context: "recv seqpacket frame".to_owned(), detail, + source, } } /// The failure of a frame write, in the vocabulary the blocking transport -/// uses for the same syscall. -fn send_failure(detail: String) -> TypedError { +/// uses for the same syscall. `source` is the origin error when the write +/// failed on one; a deadline that elapsed without a write has none. +fn send_failure(detail: String, source: Option) -> TypedError { TypedError::InternalIo { context: "send seqpacket frame".to_owned(), detail, + source, } } @@ -1558,6 +1565,7 @@ fn encode_reply(response: &ForwardOperationResponse) -> Result, TypedErr serde_json::to_vec(response).map_err(|error| TypedError::InternalIo { context: "serialize JSON frame".to_owned(), detail: error.to_string(), + source: error_source(error), }) } @@ -1579,7 +1587,7 @@ fn encode_frame(body: &[u8]) -> Result, TypedError> { /// refuses. fn decode_frame(datagram: &[u8]) -> Result, TypedError> { if datagram.is_empty() { - return Err(recv_failure("peer closed the socket".to_owned())); + return Err(recv_failure("peer closed the socket".to_owned(), None)); } if datagram.len() < 4 { return Err(TypedError::WireInvalidFrame { diff --git a/packages/d2bd/tests/bundle_tampered_envelope.rs b/packages/d2bd/tests/bundle_tampered_envelope.rs index ced7b26ff..36dc59531 100644 --- a/packages/d2bd/tests/bundle_tampered_envelope.rs +++ b/packages/d2bd/tests/bundle_tampered_envelope.rs @@ -13,7 +13,7 @@ use d2b_core::bundle_resolver::{BundleResolver, BundleVerifyPolicy}; use d2b_core::error::{BundleError, Error as CoreError}; -use d2bd_runtime::typed_error::TypedError; +use d2bd_runtime::typed_error::{TypedError, error_source}; use std::fs; use std::io::Write as _; use std::os::unix::fs::OpenOptionsExt; @@ -84,6 +84,7 @@ fn map_core_error(err: CoreError) -> TypedError { other => TypedError::InternalIo { context: "load bundle resolver".to_owned(), detail: other.to_string(), + source: error_source(other), }, } } From 6044cf274c12b359f636dd71e4b39b8e4733a2a0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:37:58 -0700 Subject: [PATCH 628/726] refactor(cross-crate): give every public item exactly one path Collapse the double-path public surfaces in sixteen crates: a module that was both `pub mod` and re-exported at the crate root now appears at exactly one path, so a future item in one of those modules cannot widen the API by accident. Arms whose consumers reach the module through its module path keep the module and drop the redundant root re-export, with the former root-path callers moved onto the module path - the effects_service modules of d2b-provider-device, d2b-provider-device-usbip and d2b-provider-device-security-key, d2b-provider-endpoint::endpoint, d2b-provider-command::command, d2b-provider-operation::operation, d2b-provider-quota::quota, d2b-provider-zone-link::{zone_links,zonelink}, d2b-contracts::{opaque_payload,privileges_w3} and d2b-contracts-broker::broker_wire. The re-pointed callers are d2bd, d2b-broker, xtask and the security-key provider's own test. Arms whose consumers already used the crate root lose only the module path, which no consumer used, so those modules are private now and their items stay reachable at the crate root: d2b-resource-api::client, d2b-provider-guest-cloud-hypervisor::adoption, d2b-provider-guest-azure-virtual-machine::error, d2b-provider-toolkit::base, d2b-provider-guest-qemu-media::controller and d2b-controller-toolkit::contract. The toolkit root re-export now names PlannedStep, the item StartupPlan::steps returns, which the private module otherwise hides. --- changelog.d/w5-31-single-surface.md | 24 +++++++++++++++++++ packages/d2b-broker/src/forwarding.rs | 2 +- packages/d2b-contracts-broker/src/lib.rs | 4 ---- packages/d2b-contracts/src/lib.rs | 2 -- packages/d2b-controller-toolkit/src/lib.rs | 2 +- packages/d2b-provider-command/src/lib.rs | 1 - .../src/driver.rs | 2 +- .../src/lib.rs | 1 - packages/d2b-provider-device-usbip/src/lib.rs | 1 - packages/d2b-provider-device/src/lib.rs | 1 - packages/d2b-provider-endpoint/src/lib.rs | 3 +-- .../src/lib.rs | 2 +- .../src/lib.rs | 2 +- .../d2b-provider-guest-qemu-media/src/lib.rs | 2 +- packages/d2b-provider-operation/src/lib.rs | 1 - packages/d2b-provider-quota/src/lib.rs | 1 - packages/d2b-provider-toolkit/src/lib.rs | 12 +++++----- .../d2b-provider-toolkit/src/plane/handle.rs | 2 +- .../d2b-provider-toolkit/src/plane/mod.rs | 2 +- packages/d2b-provider-zone-link/src/lib.rs | 2 -- packages/d2b-resource-api/src/lib.rs | 2 +- packages/d2bd/src/forward_rendezvous.rs | 2 +- packages/d2bd/src/foundation_seed.rs | 14 +++++------ packages/d2bd/src/provider_lifecycle.rs | 6 ++--- packages/d2bd/src/resource_plane_v3.rs | 7 +++--- packages/d2bd/src/shared_provider_effects.rs | 6 ++--- packages/xtask/src/zone_schema.rs | 4 ++-- 27 files changed, 60 insertions(+), 50 deletions(-) create mode 100644 changelog.d/w5-31-single-surface.md diff --git a/changelog.d/w5-31-single-surface.md b/changelog.d/w5-31-single-surface.md new file mode 100644 index 000000000..db6a60c14 --- /dev/null +++ b/changelog.d/w5-31-single-surface.md @@ -0,0 +1,24 @@ +### Changed + +- Sixteen crates no longer name the same public item at two paths: where a + module was both `pub mod` and re-exported at the crate root, exactly one arm + survives. The modules consumers reach through their module path keep it and + drop the redundant root re-export, with the former root-path callers moved + onto the module path: the `effects_service` module of + `d2b-provider-device`, `d2b-provider-device-usbip` and + `d2b-provider-device-security-key`, `d2b-provider-endpoint`'s `endpoint`, + `d2b-provider-command`'s `command`, `d2b-provider-operation`'s `operation`, + `d2b-provider-quota`'s `quota`, `d2b-provider-zone-link`'s `zone_links` and + `zonelink`, `d2b-contracts`' `privileges_w3`, and + `d2b-contracts-broker`'s `broker_wire`. `d2b-contracts`' `opaque_payload` + keeps its module arm too, the path that carries its surface, and loses the + single-item root re-export. +- The modules whose consumers already used the crate root are private now, so + their items stay reachable at exactly the crate root and a new item inside + them can no longer widen the public API by accident: + `d2b-resource-api::client`, `d2b-provider-guest-cloud-hypervisor::adoption`, + `d2b-provider-guest-azure-virtual-machine::error`, + `d2b-provider-toolkit::base`, `d2b-provider-guest-qemu-media::controller`, + and `d2b-controller-toolkit::contract`. Their crate-root re-exports still + carry every item the module exposed; the toolkit root re-export now also + names `PlannedStep`, the item `StartupPlan::steps` returns. diff --git a/packages/d2b-broker/src/forwarding.rs b/packages/d2b-broker/src/forwarding.rs index 61d7aa3e4..cd4604948 100644 --- a/packages/d2b-broker/src/forwarding.rs +++ b/packages/d2b-broker/src/forwarding.rs @@ -39,7 +39,7 @@ use crate::envelope::{DispatchFailure, DispatchOutcome, ERRORED}; /// /// The deployment fact is declared with the carrier it configures, so the /// broker and the peer that binds the socket cannot drift apart. -pub use d2b_contracts_broker::FORWARD_SOCKET_ENV; +pub use d2b_contracts_broker::broker_wire::FORWARD_SOCKET_ENV; /// The environment variable that bounds one forward round trip, in /// milliseconds. diff --git a/packages/d2b-contracts-broker/src/lib.rs b/packages/d2b-contracts-broker/src/lib.rs index 6227dbaee..b355b9a42 100644 --- a/packages/d2b-contracts-broker/src/lib.rs +++ b/packages/d2b-contracts-broker/src/lib.rs @@ -4,10 +4,6 @@ pub mod broker_wire; pub mod host_generation; pub mod kernel_client; -pub use broker_wire::BrokerRequest; -pub use broker_wire::{ - FORWARD_SOCKET_ENV, ForwardOperationOutcome, ForwardOperationRequest, ForwardOperationResponse, -}; pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}; pub use d2b_contracts::privileges_w3::W3BrokerOperation; diff --git a/packages/d2b-contracts/src/lib.rs b/packages/d2b-contracts/src/lib.rs index 943d97b15..e20ed550a 100644 --- a/packages/d2b-contracts/src/lib.rs +++ b/packages/d2b-contracts/src/lib.rs @@ -51,8 +51,6 @@ pub use ids::{ AllocatorLeaseId, CorrelationId, ExecutionId, HostResourceId, IdempotencyKey, OperationId, PrincipalId, StreamCursor, StreamId, }; -pub use opaque_payload::OpaquePayload; -pub use privileges_w3::W3BrokerOperation; pub use token::{ProtocolToken, TokenError}; pub use workload::{ DisplayEnvironmentPosture, EnvironmentPosture, ExecutionIdentityPosture, IsolationPosture, diff --git a/packages/d2b-controller-toolkit/src/lib.rs b/packages/d2b-controller-toolkit/src/lib.rs index 0370433c6..3f7530764 100644 --- a/packages/d2b-controller-toolkit/src/lib.rs +++ b/packages/d2b-controller-toolkit/src/lib.rs @@ -6,7 +6,7 @@ //! database it coordinated. pub mod context; -pub mod contract; +mod contract; pub use context::{DependencySnapshot, OwnerIdentity, ResourceSnapshot}; pub use contract::ResourceKey; diff --git a/packages/d2b-provider-command/src/lib.rs b/packages/d2b-provider-command/src/lib.rs index d849b7be0..884296777 100644 --- a/packages/d2b-provider-command/src/lib.rs +++ b/packages/d2b-provider-command/src/lib.rs @@ -19,4 +19,3 @@ pub use driver::command_descriptor; /// The Command ResourceType spec and status shapes owned by this crate. pub mod command; -pub use command::*; diff --git a/packages/d2b-provider-device-security-key/src/driver.rs b/packages/d2b-provider-device-security-key/src/driver.rs index 01ed455b4..768705a64 100644 --- a/packages/d2b-provider-device-security-key/src/driver.rs +++ b/packages/d2b-provider-device-security-key/src/driver.rs @@ -660,7 +660,7 @@ mod tests { d2b_contracts_resource::v3::BoundedToken::parse(purpose).is_ok(), "relay endpoint purpose must be a closed BoundedToken" ); - serde_json::from_value::(value.clone()) + serde_json::from_value::(value.clone()) .expect("the relay Endpoint child decodes as the closed EndpointSpec"); } } diff --git a/packages/d2b-provider-device-security-key/src/lib.rs b/packages/d2b-provider-device-security-key/src/lib.rs index 028eab54b..c7639c65a 100644 --- a/packages/d2b-provider-device-security-key/src/lib.rs +++ b/packages/d2b-provider-device-security-key/src/lib.rs @@ -36,7 +36,6 @@ pub use driver::{ SECURITY_KEY_SERVICE_CREATIONS, SecurityKeyComponent, SecurityKeyDriverArgs, SecurityKeyDriverEffects, declared_dependency_refs, security_key_descriptors, }; -pub use effects_service::SECURITY_KEY_EFFECTS_SERVICE; pub use lease::{LeaseState, SecurityKeyLease, SecurityKeyLeaseError, SecurityKeySessionId}; pub use process::{ FrontendProcessDeclaration, ProcessDeclarationError, RelayProcessDeclaration, diff --git a/packages/d2b-provider-device-usbip/src/lib.rs b/packages/d2b-provider-device-usbip/src/lib.rs index c4fb9db5b..2559ff3bc 100644 --- a/packages/d2b-provider-device-usbip/src/lib.rs +++ b/packages/d2b-provider-device-usbip/src/lib.rs @@ -43,7 +43,6 @@ pub use driver::{ UsbipComponent, UsbipDriverArgs, UsbipDriverEffects, declared_dependency_refs, usbip_descriptors, }; -pub use effects_service::USBIP_EFFECTS_SERVICE; pub use firewall::{ FirewallConfirmation, FirewallConfirmationKind, FirewallDigest, FirewallGenerationFence, FirewallObservation, FirewallProjectionAction, FirewallProjectionIntent, FirewallToken, diff --git a/packages/d2b-provider-device/src/lib.rs b/packages/d2b-provider-device/src/lib.rs index b659c94b1..61e1b27a9 100644 --- a/packages/d2b-provider-device/src/lib.rs +++ b/packages/d2b-provider-device/src/lib.rs @@ -27,4 +27,3 @@ pub use driver::{ DeviceDriverEffects, DeviceResourceState, GPU_CONTROLLER_REF, SECURITY_KEY_CONTROLLER_REF, TPM_CONTROLLER_REF, USBIP_CONTROLLER_REF, declared_dependency_refs, device_descriptor, }; -pub use effects_service::DEVICE_EFFECTS_SERVICE; diff --git a/packages/d2b-provider-endpoint/src/lib.rs b/packages/d2b-provider-endpoint/src/lib.rs index 9e0b309bf..50d13e443 100644 --- a/packages/d2b-provider-endpoint/src/lib.rs +++ b/packages/d2b-provider-endpoint/src/lib.rs @@ -45,5 +45,4 @@ pub use effects_service::{ pub use facets::{DeviceWorkerEvidenceSource, EndpointEffectFacets, EndpointSocketSource, GuestVmmEvidenceSource}; /// The Endpoint ResourceType spec and status shapes owned by this crate. -pub mod endpoint; -pub use endpoint::*; \ No newline at end of file +pub mod endpoint; \ No newline at end of file diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs index dbed1d934..164b4dbbf 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/lib.rs @@ -7,7 +7,7 @@ pub mod bootstrap; pub mod config; pub mod controller; pub mod effect; -pub mod error; +mod error; pub use bootstrap::{ BootstrapAdmission, BootstrapAdmissionState, BootstrapPsk, BootstrapService, diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs index 27fb97a50..4cdcd80ac 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use d2b_contracts_resource::v3::ResourceRef; -pub mod adoption; +mod adoption; pub mod bootstrap_graph; pub mod config; pub mod controller; diff --git a/packages/d2b-provider-guest-qemu-media/src/lib.rs b/packages/d2b-provider-guest-qemu-media/src/lib.rs index fef348092..1cc429e7b 100644 --- a/packages/d2b-provider-guest-qemu-media/src/lib.rs +++ b/packages/d2b-provider-guest-qemu-media/src/lib.rs @@ -5,7 +5,7 @@ pub mod adoption; pub mod config; -pub mod controller; +mod controller; pub mod hotplug; pub mod qmp; pub mod types; diff --git a/packages/d2b-provider-operation/src/lib.rs b/packages/d2b-provider-operation/src/lib.rs index 018912d83..23651021d 100644 --- a/packages/d2b-provider-operation/src/lib.rs +++ b/packages/d2b-provider-operation/src/lib.rs @@ -20,4 +20,3 @@ mod driver; pub mod operation; pub use driver::operation_descriptor; -pub use operation::*; diff --git a/packages/d2b-provider-quota/src/lib.rs b/packages/d2b-provider-quota/src/lib.rs index b26dc8615..2e49bf222 100644 --- a/packages/d2b-provider-quota/src/lib.rs +++ b/packages/d2b-provider-quota/src/lib.rs @@ -21,4 +21,3 @@ mod driver; pub mod quota; pub use driver::quota_descriptor; -pub use quota::*; diff --git a/packages/d2b-provider-toolkit/src/lib.rs b/packages/d2b-provider-toolkit/src/lib.rs index c7f53e3d4..f1aa2e637 100644 --- a/packages/d2b-provider-toolkit/src/lib.rs +++ b/packages/d2b-provider-toolkit/src/lib.rs @@ -68,7 +68,7 @@ #![deny(missing_docs)] pub mod audit; -pub mod base; +mod base; pub mod credential; pub mod declaration; pub mod operations; @@ -100,11 +100,11 @@ pub use base::{ DEFAULT_DRAIN_BUDGET_MS, DrainError, EnrolledRoute, EnrollmentRequest, GUEST_RECONNECT_ATTEMPTS, GUEST_RECONNECT_INITIAL_MS, GUEST_RECONNECT_MAX_MS, GUEST_SESSION_MAX_FRAME_BYTES, GuestAgent, GuestEnrollment, GuestError, GuestFrame, GuestLink, GuestLinkFuture, GuestPlacement, Lifecycle, - PROVIDER_RESOURCE_TYPE, ProviderAdmission, ProviderAgentBootstrap, ProviderAgentIdentity, - ProviderBase, ProviderEntrypoint, ProviderLifecycle, ProviderRunError, ProviderRuntimeError, - ProviderSessionAdmission, ProviderToolkitError, ServiceMethods, ServiceSurface, StartupError, - StartupPlan, StartupPlanRefusal, StartupStepError, StartupStepExecutor, SupervisedProvider, - run, run_guest, run_with_startup, + PROVIDER_RESOURCE_TYPE, PlannedStep, ProviderAdmission, ProviderAgentBootstrap, + ProviderAgentIdentity, ProviderBase, ProviderEntrypoint, ProviderLifecycle, ProviderRunError, + ProviderRuntimeError, ProviderSessionAdmission, ProviderToolkitError, ServiceMethods, + ServiceSurface, StartupError, StartupPlan, StartupPlanRefusal, StartupStepError, + StartupStepExecutor, SupervisedProvider, run, run_guest, run_with_startup, }; pub use d2b_session::{ AuthenticatedComponentSession, AuthenticatedSessionRouteBinding, Cancellation, diff --git a/packages/d2b-provider-toolkit/src/plane/handle.rs b/packages/d2b-provider-toolkit/src/plane/handle.rs index bed35bdd7..1179c6aec 100644 --- a/packages/d2b-provider-toolkit/src/plane/handle.rs +++ b/packages/d2b-provider-toolkit/src/plane/handle.rs @@ -300,7 +300,7 @@ impl<'a> ZonePlaneHandle<'a> { } } -/// A bounded drain deadline handed to [`crate::base::ProviderBase::drain`]. +/// A bounded drain deadline handed to [`crate::ProviderBase::drain`]. #[derive(Clone)] pub struct DrainDeadline { started_unix_ms: u64, diff --git a/packages/d2b-provider-toolkit/src/plane/mod.rs b/packages/d2b-provider-toolkit/src/plane/mod.rs index 8835e81d8..de8711dfa 100644 --- a/packages/d2b-provider-toolkit/src/plane/mod.rs +++ b/packages/d2b-provider-toolkit/src/plane/mod.rs @@ -2,7 +2,7 @@ //! //! A provider declares its own plane adapters, storage roots, principals, //! and services ([`crate::declaration`]); the plane calls -//! [`crate::base::ProviderBase::attach`] with a [`ZonePlaneHandle`] that +//! [`crate::ProviderBase::attach`] with a [`ZonePlaneHandle`] that //! carries those declared facts and the plane's own port. The toolkit owns //! the order - adapters in declared dependency order - and never performs an //! effect itself: every host-side action goes through the port, which the diff --git a/packages/d2b-provider-zone-link/src/lib.rs b/packages/d2b-provider-zone-link/src/lib.rs index 8a60eadb2..99ed23033 100644 --- a/packages/d2b-provider-zone-link/src/lib.rs +++ b/packages/d2b-provider-zone-link/src/lib.rs @@ -19,5 +19,3 @@ pub mod zonelink; pub use driver::zone_link_descriptor; -pub use zone_links::*; -pub use zonelink::*; diff --git a/packages/d2b-resource-api/src/lib.rs b/packages/d2b-resource-api/src/lib.rs index ad2cf8a75..4f86f845f 100644 --- a/packages/d2b-resource-api/src/lib.rs +++ b/packages/d2b-resource-api/src/lib.rs @@ -6,7 +6,7 @@ pub mod adapter; mod admission; pub mod authz; -pub mod client; +mod client; pub mod error; pub mod generated; mod identity; diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index eacfc0539..a2af66f5c 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -79,7 +79,7 @@ use d2b_audit::evidence_chain::{ ChainAuditSink, ChainLeg, ChainOutcome, ChainRecord, ChainRecordClass, EvidenceChain, MAX_NESTED_DEPTH, NESTED_DEPTH_EXCEEDED, }; -use d2b_contracts_broker::FORWARD_SOCKET_ENV; +use d2b_contracts_broker::broker_wire::FORWARD_SOCKET_ENV; use d2b_contracts_broker::broker_wire::{ DEFAULT_CONTEXT_DEADLINE_MS, FD_LEG, FdKind, ForwardContext, ForwardOperationOutcome, ForwardOperationRequest, ForwardOperationResponse, MAX_CONTEXT_DEADLINE_MS, MAX_FRAME_FDS, diff --git a/packages/d2bd/src/foundation_seed.rs b/packages/d2bd/src/foundation_seed.rs index f2f5fb60a..48ccef642 100644 --- a/packages/d2bd/src/foundation_seed.rs +++ b/packages/d2bd/src/foundation_seed.rs @@ -416,7 +416,7 @@ impl FoundationSeed { spawn_authority(), Default::default(), Default::default(), - d2b_provider_operation::PayloadProvenance::Derived, + d2b_provider_operation::operation::PayloadProvenance::Derived, None, ) .map_err(|_| SeedError::InvalidRow { @@ -864,18 +864,18 @@ fn clone_payload(schema: &PayloadSchema) -> PayloadSchema { /// fields needs at least redacted access, a plain payload none. fn secret_access_ceiling( schema: &PayloadSchema, -) -> d2b_provider_operation::SecretAccess { +) -> d2b_provider_operation::operation::SecretAccess { if schema .property_names() .any(|name| schema.is_write_only(name)) { - d2b_provider_operation::SecretAccess::RedactedOnly + d2b_provider_operation::operation::SecretAccess::RedactedOnly } else { - d2b_provider_operation::SecretAccess::None + d2b_provider_operation::operation::SecretAccess::None } } -fn audit_facet(schema: &PayloadSchema) -> d2b_provider_operation::OperationAudit { +fn audit_facet(schema: &PayloadSchema) -> d2b_provider_operation::operation::OperationAudit { use d2b_contracts_resource::v3::{ BoundedText, BoundedToken }; use d2b_provider_operation::operation::{ AuditMode, OperationAudit }; let retained = schema @@ -898,7 +898,7 @@ use d2b_provider_operation::operation::{ AuditMode, OperationAudit }; .expect("bounded audit facet") } -fn spawn_authority() -> d2b_provider_operation::OperationAuthority { +fn spawn_authority() -> d2b_provider_operation::operation::OperationAuthority { use d2b_contracts_resource::v3::{ BoundedText }; use d2b_provider_operation::operation::{ BrokerRequirement, OperationAuthority, OperationDomain, OperationSurface }; OperationAuthority::new( @@ -1357,7 +1357,7 @@ use d2b_provider_seccomp_profile::{ DeviceBind, DeviceNodeKind, SeccompCgroups, ); assert_ne!( spec.secret_access(), - d2b_provider_operation::SecretAccess::None + d2b_provider_operation::operation::SecretAccess::None ); // The role's posture row resolves the committed profile and principal. let role = row_spec(&fixture.store, "Role/worker").await.expect("role row"); diff --git a/packages/d2bd/src/provider_lifecycle.rs b/packages/d2bd/src/provider_lifecycle.rs index 0cf9b7e11..2b698dfc2 100644 --- a/packages/d2bd/src/provider_lifecycle.rs +++ b/packages/d2bd/src/provider_lifecycle.rs @@ -35,9 +35,9 @@ use d2bd_runtime::broker_transport::ModeBoundBrokerAdapter; use d2bd_runtime::target_runtime::DaemonMode; use d2b_provider_activation_nixos::ACTIVATION_EFFECTS_SERVICE; use d2b_provider_credential::CREDENTIAL_EFFECTS_SERVICE; -use d2b_provider_device::DEVICE_EFFECTS_SERVICE; -use d2b_provider_device_security_key::SECURITY_KEY_EFFECTS_SERVICE; -use d2b_provider_device_usbip::USBIP_EFFECTS_SERVICE; +use d2b_provider_device::effects_service::DEVICE_EFFECTS_SERVICE; +use d2b_provider_device_security_key::effects_service::SECURITY_KEY_EFFECTS_SERVICE; +use d2b_provider_device_usbip::effects_service::USBIP_EFFECTS_SERVICE; use d2b_provider_endpoint::ENDPOINT_EFFECTS_SERVICE; use d2b_provider_guest::GUEST_EFFECTS_SERVICE; use d2b_provider_host::HOST_EFFECTS_SERVICE; diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 69070e8fd..abc3308ad 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -120,13 +120,14 @@ use crate::provider_lifecycle::{ }; use d2b_provider_toolkit::EffectServiceFactory; use d2b_provider_device::{ - DEVICE_EFFECTS_SERVICE, DeviceDriverArgs, device_descriptor, + DeviceDriverArgs, device_descriptor, effects_service::DEVICE_EFFECTS_SERVICE, }; use d2b_provider_device_security_key::{ - SECURITY_KEY_EFFECTS_SERVICE, SecurityKeyDriverArgs, security_key_descriptors, + SecurityKeyDriverArgs, security_key_descriptors, + effects_service::SECURITY_KEY_EFFECTS_SERVICE, }; use d2b_provider_device_usbip::{ - USBIP_EFFECTS_SERVICE, UsbipDriverArgs, usbip_descriptors, + UsbipDriverArgs, usbip_descriptors, effects_service::USBIP_EFFECTS_SERVICE, }; use d2b_provider_network_local::{ diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 1364389fe..a94c33eb4 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -3537,21 +3537,21 @@ mod tests { )) as Arc, ), ( - d2b_provider_device_usbip::USBIP_EFFECTS_SERVICE.id, + d2b_provider_device_usbip::effects_service::USBIP_EFFECTS_SERVICE.id, Arc::new(d2b_provider_device_usbip::effects_service:: UsbipEffectsServiceFactory::new( usbip_facets, )) as Arc, ), ( - d2b_provider_device_security_key::SECURITY_KEY_EFFECTS_SERVICE.id, + d2b_provider_device_security_key::effects_service::SECURITY_KEY_EFFECTS_SERVICE.id, Arc::new(d2b_provider_device_security_key::effects_service:: SecurityKeyEffectsServiceFactory::new( security_key_facets, )) as Arc, ), ( - d2b_provider_device::DEVICE_EFFECTS_SERVICE.id, + d2b_provider_device::effects_service::DEVICE_EFFECTS_SERVICE.id, Arc::new(d2b_provider_device::effects_service:: DeviceEffectsServiceFactory::new(device_facets)) as Arc, diff --git a/packages/xtask/src/zone_schema.rs b/packages/xtask/src/zone_schema.rs index 45e3dc8fe..1cab80c52 100644 --- a/packages/xtask/src/zone_schema.rs +++ b/packages/xtask/src/zone_schema.rs @@ -1215,7 +1215,7 @@ fn standard_resource_schemas() -> Vec<(&'static str, Value)> { ), ( "Command", - dto_resource_schema::( + dto_resource_schema::( "Command", "Declared launch shape: executable, argv placeholder slots, parameters, worker role, and intent.", true, @@ -1223,7 +1223,7 @@ fn standard_resource_schemas() -> Vec<(&'static str, Value)> { ), ( "Operation", - dto_resource_schema::( + dto_resource_schema::( "Operation", "Committed broker operation: payload schema, authority, audit, fd, bounds, and provenance facets.", true, From 8323690962bd24d8f8591eb2f54f497c5164594c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:40:21 -0700 Subject: [PATCH 629/726] repo: repair the wave-5 gate breaks The wave-5 integration merge left the gate set red in four classes: - the d2b-core fuzz smoke target, a cargo-only test target that the bazel per-crate runs never build, still imported d2b_core::error after the compat shims were deleted and read BundleResolver's now-private fields; it goes through d2b_contracts::error and the accessors. - the credential-entra module-scope SystemTime/UNIX_EPOCH import became test-only when the deadline trio folded onto the toolkit helpers, so it is gated behind cfg(test) like its use sites. - the async-gate inventory drifted with the merged line shifts; it is regenerated for the merged source (254 sites, no blocking calls in async contexts). - the package policy-input closure was stale against the merged manifests; it is regenerated from the merged lock snapshot. The supply-chain fragment's lock-drift claim is corrected to what landed: the drift was measured (39 shared crates differ, 33 newer in the guest tree) with a throwaway comparison, not a committed check. The blocking census, the policy-input check, the async-gate check, cargo check, and the full bazel check lane are green again. --- changelog.d/w5-12-supply-chain-posture.md | 2 +- packages/d2b-core/fuzz/src/bin/core.rs | 27 +++-- .../d2b-provider-credential-entra/src/lib.rs | 1 + .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 98 ++++++++++++++++++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 + .../main-product/policy/closure.json | 98 ++++++++++++++++++- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 + .../main-product/production/closure.json | 8 +- .../main-product/production/metadata.json | 2 +- packages/xtask/data/async-gate-inventory.json | 66 ++++++------- 48 files changed, 303 insertions(+), 81 deletions(-) diff --git a/changelog.d/w5-12-supply-chain-posture.md b/changelog.d/w5-12-supply-chain-posture.md index b7de38633..311190326 100644 --- a/changelog.d/w5-12-supply-chain-posture.md +++ b/changelog.d/w5-12-supply-chain-posture.md @@ -2,4 +2,4 @@ - Member manifests now inherit `rustix` and `sha2` from `workspace.dependencies` instead of pinning literal versions; the 13 member decls across d2b-broker, d2b-provider-guest, d2b-provider-network-local, d2b-provider-process, d2b-provider-process-systemd, d2b-provider-user, d2b-telemetry, d2b-unsafe-local-helper, d2bd, and d2bd-runtime resolve to the same versions as before, so both lockfiles are unchanged. - `deny.toml` records the accepted duplicate clusters (nix at 0.26/0.29/0.31, rustix at 0.38/1.1, and the 31 transitive-only clusters) with their versions, pullers, and re-check triggers, and raises the licence confidence threshold from 0.8 to 0.9. -- Added a lock-drift check comparing shared-crate versions across `Cargo.lock` and `packages/Cargo.guest.lock`; it currently reports 39 shared crates resolving to newer versions in the guest tree, to be aligned by regenerating both locks from one index snapshot at the next dependency refresh. \ No newline at end of file +- Measured the guest-lock drift with a throwaway comparison of shared-crate versions across `Cargo.lock` and `packages/Cargo.guest.lock`: 39 shared crates differ and 33 of them resolve newer in the guest tree, so both locks come from different index snapshots. The evidence is recorded here; the aligned regen of both locks from one snapshot happens at the next dependency refresh, which is where the row scopes it. \ No newline at end of file diff --git a/packages/d2b-core/fuzz/src/bin/core.rs b/packages/d2b-core/fuzz/src/bin/core.rs index e6ca4f4cd..8c647060d 100644 --- a/packages/d2b-core/fuzz/src/bin/core.rs +++ b/packages/d2b-core/fuzz/src/bin/core.rs @@ -3,6 +3,7 @@ mod harness; use d2b_contracts_resource::v3::{IfName, IfNameError}; use std::collections::BTreeMap; +use d2b_contracts::error::{BrokerOp, Error, SemverRange, Version}; use d2b_core::{ bundle::{Bundle, BundleGeneration}, bundle_resolver::{ @@ -12,7 +13,6 @@ use d2b_core::{ intent_id_sysctl, intent_id_usbip_bind, intent_id_usbip_firewall, }, - error::{BrokerOp, Error, SemverRange, Version}, host::{ BridgePortFlags, HostJson, HostsFileOwnership, Ipv6SysctlEntry, LanPolicy, NetEnv, NetworkManagerUnmanaged, NftChain, NftablesModel, OwnershipRule, SitePolicy, TapRole, @@ -625,23 +625,36 @@ fn bundle_resolver_host_runtime_synthesizes_from_ifname_mappings() { fn build_resolver_with_ifname_mappings() -> d2b_core::bundle_resolver::BundleResolver { use d2b_core::host::IfNameMapping; - let mut r = build_synthetic_resolver(); - r.host.if_name_mappings = vec![IfNameMapping { + let r = build_synthetic_resolver(); + let mut host = r.host().clone(); + host.if_name_mappings = vec![IfNameMapping { env: "work".to_owned(), vm: None, role: TapRole::WorkloadLan, user_visible_name: "br-work-lan".to_owned(), derived_ifname: IfName::new("d2b-br-a1b2c3d4").expect("ifname"), }]; - r + BundleResolver::from_artifacts_with_zone_resource_bundles( + r.bundle().clone(), + host, + r.processes().clone(), + r.manifest().clone(), + BTreeMap::new(), + ) } fn build_resolver_with_usbip_bus_ids( bus_ids: &[&str], ) -> d2b_core::bundle_resolver::BundleResolver { - let mut r = build_synthetic_resolver(); - r.host.environments[0].usbip_busid_locks[0].bus_ids = + let r = build_synthetic_resolver(); + let mut host = r.host().clone(); + host.environments[0].usbip_busid_locks[0].bus_ids = bus_ids.iter().map(|bus_id| (*bus_id).to_owned()).collect(); BundleResolver::from_artifacts_with_zone_resource_bundles( - r.bundle, r.host, r.processes, r.manifest, BTreeMap::new()) + r.bundle().clone(), + host, + r.processes().clone(), + r.manifest().clone(), + BTreeMap::new(), + ) } diff --git a/packages/d2b-provider-credential-entra/src/lib.rs b/packages/d2b-provider-credential-entra/src/lib.rs index 353fb3da2..b55d514c2 100644 --- a/packages/d2b-provider-credential-entra/src/lib.rs +++ b/packages/d2b-provider-credential-entra/src/lib.rs @@ -15,6 +15,7 @@ use std::fmt; use std::future::Future; use std::pin::Pin; use std::sync::{Arc, Mutex, MutexGuard, TryLockError}; +#[cfg(test)] use std::time::{SystemTime, UNIX_EPOCH}; use d2b_contracts_provider::v3::credential::{ diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 2c4df0899..b247d5ea0 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 3baa67832..c8448f76d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index 2d9ef0ae8..cdcad4818 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 3baa67832..c8448f76d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 4f8685b15..333cf3ec2 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index b9fe215b4..4b58232de 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index 6e352a683..0a2c06cd7 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index b9fe215b4..4b58232de 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index dadb35ed5..24f7f6382 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index f49e4e271..5616168e7 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index b5d7bca6d..e6955ce6a 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index f49e4e271..5616168e7 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 241a6bb20..664051117 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index 3baa67832..c8448f76d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index b285e6176..14ff57a6c 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index 3baa67832..c8448f76d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index c03666fc9..de3987244 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -2181,6 +2181,7 @@ name = "d2b-resource-compiler" version = "0.0.0-bootstrap" dependencies = [ "base64", + "d2b-contracts", "d2b-contracts-provider", "d2b-contracts-resource", "d2b-contracts-zone-session", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index c05db1845..da970bca0 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5327,6 +5327,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-command@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-command@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -6203,6 +6209,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-emergency-policy@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-emergency-policy@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -6929,6 +6941,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-operation@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-operation@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -6965,6 +6983,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-process-minijail@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-process-minijail@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -7007,6 +7031,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-process-systemd@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-process-systemd@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -7097,6 +7127,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-process@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-process@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -7271,6 +7307,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-quota@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-quota@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7295,6 +7337,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-resource-export@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-resource-export@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7307,6 +7355,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-resource-import@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-resource-import@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7319,6 +7373,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-role-binding@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-role-binding@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7337,6 +7397,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-role@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-role@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7355,6 +7421,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-seccomp-profile@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-seccomp-profile@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7523,6 +7595,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-supervisor@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-supervisor@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -8603,6 +8681,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -8639,6 +8723,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-zone@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-zone@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -8843,6 +8933,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-compiler@0.0.0-bootstrap#path", + "to": "d2b-contracts@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-compiler@0.0.0-bootstrap#path", "to": "d2b-core@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index fac7cacd3..233238cbd 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index c03666fc9..de3987244 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -2181,6 +2181,7 @@ name = "d2b-resource-compiler" version = "0.0.0-bootstrap" dependencies = [ "base64", + "d2b-contracts", "d2b-contracts-provider", "d2b-contracts-resource", "d2b-contracts-zone-session", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index 62dead8d8..3738aa4fa 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -8237,6 +8237,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-compiler@0.0.0-bootstrap#path", + "to": "d2b-contracts@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-compiler@0.0.0-bootstrap#path", "to": "d2b-core@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index fac7cacd3..233238cbd 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 20923ddaa..5a98d394c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index e81826a8e..16b38f73d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index 30f3d6dc5..d965d2f4b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index e81826a8e..16b38f73d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index e9f721886..b12b85a52 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 42cc83add..c40c80cee 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index ef10ff273..edbb4eb1f 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 42cc83add..c40c80cee 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 83656776c..12f9f8854 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index be7a52035..a5f02a3fe 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index c5a6e1f16..1d4069e4f 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index be7a52035..a5f02a3fe 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index 669de35e6..97a9caddc 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index e81826a8e..16b38f73d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 619cbc3df..68f9ee328 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index e81826a8e..16b38f73d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index c03666fc9..de3987244 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -2181,6 +2181,7 @@ name = "d2b-resource-compiler" version = "0.0.0-bootstrap" dependencies = [ "base64", + "d2b-contracts", "d2b-contracts-provider", "d2b-contracts-resource", "d2b-contracts-zone-session", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index 11907053c..0544b0d4b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5365,6 +5365,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-command@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-command@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -6241,6 +6247,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-emergency-policy@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-emergency-policy@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -6967,6 +6979,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-operation@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-operation@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7003,6 +7021,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-process-minijail@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-process-minijail@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -7045,6 +7069,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-process-systemd@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-process-systemd@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -7135,6 +7165,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-process@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-process@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -7309,6 +7345,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-quota@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-quota@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7333,6 +7375,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-resource-export@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-resource-export@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7345,6 +7393,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-resource-import@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-resource-import@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7357,6 +7411,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-role-binding@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-role-binding@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7375,6 +7435,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-role@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-role@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7393,6 +7459,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-seccomp-profile@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-seccomp-profile@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -7561,6 +7633,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-supervisor@0.0.0-bootstrap#path", + "to": "d2b-process-conformance@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-supervisor@0.0.0-bootstrap#path", "to": "d2b-process-conformance@0.0.0-bootstrap#path", @@ -8641,6 +8719,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-zone-link@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -8677,6 +8761,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-zone@0.0.0-bootstrap#path", + "to": "d2b-resource-types@0.0.0-bootstrap#path", + "kind": "dev", + "target": null + }, { "from": "d2b-provider-zone@0.0.0-bootstrap#path", "to": "d2b-resource-types@0.0.0-bootstrap#path", @@ -8881,6 +8971,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-compiler@0.0.0-bootstrap#path", + "to": "d2b-contracts@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-compiler@0.0.0-bootstrap#path", "to": "d2b-core@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index e5e3c1d14..0a750448b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index c03666fc9..de3987244 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -2181,6 +2181,7 @@ name = "d2b-resource-compiler" version = "0.0.0-bootstrap" dependencies = [ "base64", + "d2b-contracts", "d2b-contracts-provider", "d2b-contracts-resource", "d2b-contracts-zone-session", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index 39bbdaa30..19f356551 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -8275,6 +8275,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-compiler@0.0.0-bootstrap#path", + "to": "d2b-contracts@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-compiler@0.0.0-bootstrap#path", "to": "d2b-core@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index e5e3c1d14..0a750448b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a6796596ce2bacb0c2e7bebf959f7c5b14d8f8c3f5aa348733f1e6fb416178bc", + "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 76c8ca3ed..1c93c4809 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -343,42 +343,42 @@ }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 492, + "line": 499, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 501, + "line": 508, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 532, + "line": 539, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 538, + "line": 545, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 599, + "line": 606, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 607, + "line": 614, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 1039, + "line": 1046, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-device-security-key/src/relay_service.rs", - "line": 1095, + "line": 1102, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -878,77 +878,77 @@ }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1236, + "line": 1243, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1254, + "line": 1261, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1271, + "line": 1278, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1283, + "line": 1290, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1298, + "line": 1305, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1302, + "line": 1309, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", - "line": 1329, + "line": 1336, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 803, + "line": 799, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 820, + "line": 816, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 836, + "line": 832, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 844, + "line": 840, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 858, + "line": 854, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 860, + "line": 856, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1129, + "line": 1123, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1315, + "line": 1309, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1078,17 +1078,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10790, + "line": 10854, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26251, + "line": 26361, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26648, + "line": 26758, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1113,37 +1113,37 @@ }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1632, + "line": 1630, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1680, + "line": 1678, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1705, + "line": 1703, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2136, + "line": 2134, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2525, + "line": 2523, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2558, + "line": 2556, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2614, + "line": 2612, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From d4bfa9160569c9a9a5ff0d2087dc19c420399657 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:44:51 -0700 Subject: [PATCH 630/726] fix(d2b-core): drop the copy clones the privileges rewrite exposed to clippy The w6-01 rewrite touched packages/d2b-core/src/privileges.rs, so the Bazel clippy action re-linted the whole file and failed on three pre-existing clone_on_copy sites in the `From<&OperationAuthzRow> for OperationAuthz` impl (SecretAccess, BrokerRequirement and AuditMode all implement Copy). Dropping the clones is the clippy-suggested fix and changes no behavior. Gate: //bazel/checks:check (the d2b_core_clippy action). --- packages/d2b-core/src/privileges.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/d2b-core/src/privileges.rs b/packages/d2b-core/src/privileges.rs index a464316c4..62c595d5e 100644 --- a/packages/d2b-core/src/privileges.rs +++ b/packages/d2b-core/src/privileges.rs @@ -707,11 +707,11 @@ impl From<&OperationAuthzRow> for OperationAuthz { .map(|group| (*group).to_owned()) .collect(), destructive: row.destructive, - secret_access: row.secret_access.clone(), - broker_required: row.broker_required.clone(), + secret_access: row.secret_access, + broker_required: row.broker_required, audit: AuditPolicy { required: !matches!(row.audit_mode, AuditMode::DenyOnly | AuditMode::Errors), - mode: row.audit_mode.clone(), + mode: row.audit_mode, retained_fields: vec![ "operation".to_owned(), "subject".to_owned(), From 25b2474f4699659bea93bebb4fe9ccc85bd8ccfe Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:49:07 -0700 Subject: [PATCH 631/726] audit: fold the wave-5 ledger outcomes and deferred rows Every wave-5 row now carries an outcome: 41 landed (38 applied plus three applied-variant with the deviation recorded inline), the 10 rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation, and the wave-gates table gains the W5 row pointing at the repaired integration head with the gate cells left to the Main gates. --- .../2026-09-24-rust-skills-audit/ledger.md | 105 +++++++++--------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 0dc1ba7e1..991205d5e 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -42,6 +42,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | +| W5 | `832369096` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step, not this wave's. | ## Findings (965 rows) @@ -91,7 +92,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-pro` | none | | | `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provi` | implemented the inverse of the row's literal suggestion (a const table read by as_str): Serialize delegates to as_str instead, which keeps the match as the single source of truth with a smaller diff, | | | `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 3459dc5a0 | `packages/d2b-provider-config-nixos/src/ttrpc.rs` | Shared path_components helper classifies Path::components; both callers use it | | -| `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | | | | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-e` | | | +| `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | applied | W5 | 1fe37219f | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-e` | the credential-entra in-crate deadline trio is folded onto the toolkit credential helpers, all eight call sites re-pointed, expired-grant and expired-inspection checks compose the toolkit primitives, and deadline bounds compare two operation_deadline instants | | | `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | applied | U2 | 20e8286f8 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | SecretServiceOwner::Userd renamed to User; enum not serialized; census 2 hits in-crate | | | `RS-0047` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | rustfmt drift normalized: enum closing brace, trailing-whitespace line, reindented variant doc comment | | | `RS-0048` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/effects_service.rs` | let _ = binding dropped; Self::declared_row_template(&view, role)?; | | @@ -171,7 +172,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | a8bc3bb0b | `packages/xtask/src/gen_layer_catalogs.rs` | Ten surface_catalog blocks and the two protobuf redaction templates converted to r## raw strings; all 12 literals verified byte-identical against HEAD; gen-layer-catalogs --check passes. | | | `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | skipped-stale | U2 | bbd40b6fd | packages/xtask/src/main.rs (sanitize_generated_rust) | premise false: the literal matches the ttrpc-compiler 0.8.0 marker exactly, so the strip is live. The wave's deletion was reverted - without it the committed binding file is not reproducible and the bogus attribute fails -D warnings; regeneration is byte-stable again. | | | `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | dead close-block reset replaced with scan end at closing brace | | -| `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | | | +| `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 564cc6d00 | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | public Arc surfaces narrowed at the named sites: the ConsoleRing::notify accessor is deleted, ConsoleSession::ring returns &Mutex, DaemonAuditLog.captured is private behind an accessor, TargetBinding::new takes TargetDirectory by value, and SkAcceptHandle.state is private behind an accessor; all 13 Arc constructor params are kept with per-site reasons (stored and cloned at a spawn boundary, a per-driver factory, an admission offer/engine pair, a split transport half, or a test-held clock) | | | `RS-0150` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | cursor/page_token/reference moved into calls;call-site reassignment unchanged | | | `RS-0151` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | try_parse_from consumes raw_args by value (sole caller, never reused) | | | `RS-0152` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | host_error_envelope takes impl Into;;&format! results move in directly | | @@ -234,20 +235,20 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/service/supervisor.rs` | advance_session now scopes the first session_mut borrow in a block and compares supervisor_identity.as_ref() directly; dropped the clone. | | | `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | | `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | -| `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | | | | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | | | +| `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | the provider session loop compares the bound controller route inside the route mutex lock scope, dropping the per-frame AuthenticatedSessionRouteBinding clone | | | `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | is_ready_for_route compares through the guard via is_some_and(/ready/ ready.as_ref().is_some_and(/bound/ bound.liveness().is_live() && bound == route)); no clone. | | | `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/shared_provider.rs` | sort_by with teardown_rank cmp then name cmp; no per-row String allocation. | | | `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | with_deadline consumes self and rebuilds with struct-update syntax; sole caller passes owned request | | | `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 72858f537 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs` | GatewayCredential stores material: GatewayCredentialMaterial moved in from_material; Drop impl deleted (material zeroizes); accessors and Debug unchanged | | | `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | applied-variant | U2 | 9ba7acf09 | `packages/d2b-provider-user/src/effects_service.rs` | Destructured InspectUserRequest and moved groups by value; username still cloned because inspect_user_response borrows it after UserSpec::new consumes it (stated fix was not implementable as written). | | | `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix not type-compatible: ctx.spec returns &T so decoded_spec returned an owned clone. Minimal variant: decoded_spec now returns (&VolumeSpecEnvelope, VolumeSpec); callers adapted; removed the p | | -| `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | | | | `driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.` | | | +| `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | applied | W5 | eee03f2a9 | `driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.` | desired_binding_intents takes the volume ResourceRef by borrow; the volume driver and the shared runtime no longer clone the reference before every binding-intent derivation | | | `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/row_readers.rs` | Bounded the as_object_mut removal borrow in a block and moved spec into serde_json::from_value, dropping the Value::Object(object.clone()). | | | `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | Both plan() route-binding arms (RoutePolicyCommitted, SessionGenerationAdvanced) now borrow record.route_binding.as_mut() and mutate through it; dropped the clone + store-back. | | | `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | EnrolledSessionEstablished arm now takes record.enrollment.as_ref() and compares the fingerprint, ending the borrow before record.link_epoch mutation. | | | `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/client.rs` | scoped_commit_batch and commit_scoped_batch take &[ScopedResourceMutation]; commit_batch_with_scope takes Option<&[..]>; adapter passes transport.mutations() directly. | | | `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/admission.rs` | mutations.into_iter().map(prepare_mutation); the redundant .cloned() removed. | | -| `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | | | | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | | | +| `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | applied-variant | W5 | 707ad428e | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | ResolvedTarget::matches_assignment compares the Execution assignment reference by borrow (stored reference for a Resource owner; resource type and name for Guest/Provider/Host) instead of materializing and cloning a ResourceRef; deviation: the public by-value resource_ref() accessors stay by-value, which is the deferral the row itself records for its ~15 external callers | | | `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | applied | U2 | 628c96492 | `packages/d2b-resource-compiler/src/linux.rs` | Applied with this commit: resource-compiler: drop the unused anchored flag accessors | | | `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | | `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | @@ -290,10 +291,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | Disposition is &'static str in a generator-emitted closed set with a drift gate; typing it needs a generator change (generated artifact). | | | `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | | `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | The destructive flag is emitted as a bare boolean by the operations generator; the stated drop of the arity allow is not implementable while the helper takes eight arguments. | | -| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | escalated | U1 | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | wave 0 applied the panicking constructor member (RS-0516); the five remaining provider-crate zone/key_ref member sites are the family wave's | U5 | +| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | driver-args zone class: the zone is a validated ZoneId through the wayland-policy, volume-binding, guest, and shared-provider driver args, and the daemon boundary parses it once; the per-pass parse-expects are gone, key_ref returns a typed SpecInvalid Result instead of panicking | escalated W2 -> U5 -> W5 (the family wave landed the driver-args class member sites) | `RS-0263` | `type` | `d2b` | low | actionable | leaf | applied | U3 | f98ad4f82 | packages/d2b/src/context.rs | ZoneContext now stores ZoneId; zone_ref/zone_name built from it; validate_zone_name deleted; discover double validation removed; from_socket takes ZoneId directly. | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | -| `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | | | | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | | | +| `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | applied | W5 | 6b9187e44 | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | EvidenceChain deserializes through an admission gate that rejects an empty identities list, so depth() cannot underflow and the identity accessors cannot panic; the wire shape is unchanged | | | `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | already-fixed | U3 | | `packages/d2b-broker/src/ops/media.rs:889-892` | Re-verified at HEAD: QmpAttachCleanup already models its four-step rollback as an ordered typed step list (steps: Vec with QmpAttachStep enum, media.rs:889-892), not four bools. Already | | | `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_co` | | | | `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362` | | | @@ -302,11 +303,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | | `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/host_generation.rs | HandoffCoordinator.source_remains_usable field dropped; accessor derives from state != Completed; old durable records deserialize (unknown field ignored); wire response field untouched. | | | `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/broker_wire.rs | CanonicalAuditDigest tuple field made private; parse and as_str remain the only construction/read paths; hand-written Deserialize and serde transparent keep wire shape. | | -| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | | | | `public_wire.rs:2166, public_wire.rs:2203` | | | -| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | | | -| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:316, public_wire.rs:311` | | | +| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | needs-contract | W6 | | `public_wire.rs:2166, public_wire.rs:2203` | deferred: needs-contract - AuditResponse complete/next_cursor enum moves an audit wire surface, so it lands with the W6 contract wave | | +| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | needs-contract | W6 | | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | deferred: needs-contract - stringly-typed status DTOs to kebab enums is a wire-visible DTO change for the W6 contract wave | | +| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | needs-contract | W6 | | `public_wire.rs:316, public_wire.rs:311` | deferred: needs-contract - MutationFlags mode enum is wire-visible; W6 contract wave | | | `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | -| `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | | | +| `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | applied | W5 | fa8706320 | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | ComponentDescriptor::new no longer takes declares_state_volume: the parameter could only ever be false (true returned MissingRequiredField), so the illegal state is not expressible and every call site drops the argument; the wire-only declaresStateVolume field and its consistency check against stateNamespaces stay in the Deserialize path | | | `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | | `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-res` | | | | `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | @@ -316,7 +317,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | 4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | | `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | -| `RS-0262` | `type` | `d2b-host` | medium | actionable | family | | | | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | | | +| `RS-0262` | `type` | `d2b-host` | medium | actionable | family | applied | W5 | d593fa50e | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | BusId keeps its inner string private and validates the USB busid grammar once at the type boundary (BusId::new returns Result, TryFrom<&str> and as_str carry the value); the transparent wire shape is unchanged and the redundant broker qemu-media re-validations plus the daemon attach/detach pre-checks are deleted | | | `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 81d0ff057 | packages/d2b-process-conformance/src/ticket.rs | Bundled zone_uid+runtime_scope into one private Option pairing; const-compatible match accessors keep the public API byte-identical. | | | `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | 87e8d7654 | packages/d2b-provider-audio-pipewire/src/resource_type.rs | owner()/new() now infallible; validate_audio_* remain the single admission gate (they also check provider_ref/extension/zone the ctors cannot). All call sites updated; check+test+clippy green on 4 cra | | | `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | Shared-vs-owned controller mode carried in the type; mixer speaker path split into grant/revoke so the return contract stops being argument-dependent. Suite 94/94. | | @@ -359,7 +360,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0301` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ControllerSession teardown trio (ingress_revoked/assignments_revoked/transport_closed) replaced by a TeardownStage enum advanced monotonically (Active -> IngressRevoked -> AssignmentsRevoked -> Transp | | | `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d` | | | | `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | 7e0ec2bce | packages/d2bd-runtime/src/admission.rs | peer admission lookup mode modelled self-describing; check + admission tests green (worker reported the oid as already present after committing its own change; the commit is this branch's) | | -| `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | | | | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | | | +| `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W5 | 6dabfe132 | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | DaemonEvent::ApiReadyTimeout.mode is a closed ApiReadyMode enum (Strict / NoWaitApi) with kebab-case serde, so an invalid mode string is rejected on deserialize; the JSONL shape is unchanged | | | `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | 4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | | `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | d1c5c44d9 | packages/d2bd-runtime/src/typed_shell_targets.rs | typed-shell target key becomes a named struct with a constructor; the three composition.rs cache call sites migrate to it | | | `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | @@ -370,7 +371,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | -| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | +| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | deferred: needs-contract - BrokerRequestEnvelope.test_peer_uid off the wire is a broker wire change; W6 | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | 4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | | `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but | | | `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:6` | Deleting the pub re-export of LevelPercent from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 0 hits for cli_output::LevelPercent outside cli_output.rs:6 | | -| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | | | +| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | needs-contract | W6 | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | deferred: needs-contract - AuditEntry removal waits on the wire-protocol.json confirmation step; W6 | | | `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Narrowing pub methods in the published crate is a published-surface move; additionally the lane census is stale: HelperLaunchRequest::validate_bounds has a live external caller at d2b-unsafe-local-hel | | | `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | @@ -398,10 +399,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | | `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs | Deleted EmergencyPolicySpec::default_values(); Default::default() now constructs directly. Census: the Default impl was the only caller. | | | `RS-0339` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone.rs | Removed ZoneSpec::validate (always-Ok). Census: no callers anywhere in the workspace or in-crate tests; the Deserialize gate remains the invariant. | | -| `RS-0348` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-cor` | | | +| `RS-0348` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | ac3083316 | `packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-cor` | the six d2b-core compat shim modules are deleted and every import site re-pointed at d2b_contracts; the xtask gen-error-codes generator and the generated docs/reference/error-codes.md anchors follow; the zero-consumer UnsafeLocalWorkloadIdentity alias goes with its module | | | `RS-0345` | `api` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Nine zero-consumer resolved-intent types marked #[doc(hidden)] (kept for planned broker dispatch arms per module doc); census re-run: 0 consumers workspace-wide | | -| `RS-0349` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:1` | | | -| `RS-0346` | `api` | `d2b-core` | medium | actionable | wide | | | | `packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109` | | | +| `RS-0349` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | 8e70d643e | `packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:1` | the four static validators now carry in-module positive/negative unit tests restoring the retired tests/static-invariant-*.sh gate cases, so the module doc claim is true; the stale doc paragraphs are corrected and the public API and constants are unchanged | | +| `RS-0346` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | 8abd3c1ba | `packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109` | the seven BundleResolver trusted-bundle fields are private behind typed accessors and a single set_storage setter replaces the broker's direct storage mutation; every consumer in d2bd, d2bd-runtime, d2b-broker, and the provider crates reads through the accessors | | | `RS-0350` | `api` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/privileges.rs | PrivilegesJson::w1 renamed to from_const_rows(); both test call sites updated; census re-run: only test callers exist | | | `RS-0347` | `api` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_vm_start_intent and find_process_node narrowed to pub(crate) as stated; find_if_name_mapping_for_vm had ZERO callers anywhere (census re-run: only the definition), so pub(crate) tripped the de | | | `RS-0340` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | fd2d8eb30 | packages/d2b-core-controller/src/binding_children.rs | Removed the uncalled observed_child_from_resource envelope adapter and its lib re-export; census: 0 callers anywhere. | | @@ -412,7 +413,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0351` | `api` | `d2b-host` | low | actionable | leaf | applied | U3 | c44532f1d | packages/d2b-host/src/lib.rs | HostPrepStepId inner string made private with serde-transparent round-trip unchanged; workspace check and clippy green. | | | `RS-0355` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 9ed591eb2 | packages/d2b-process-conformance/src/lib.rs | Dropped the unused BrokerExitClass alias from the terminal re-export; census: only hit was its own re-export. | | | `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | dbac9940c | packages/d2b-process-conformance/src/process_provider.rs | Deleted the duplicate process_provider re-export module; census: 0 users of that path. | | -| `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | | | | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testi` | | | +| `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testi` | the process-conformance test doubles and fixtures (`testing`) ship behind a `test-support` feature: the feature is declared, the `_test_support` bazel variant gains `crate_features`, the suite helpers that need the doubles are gated, and every in-tree consumer enables the feature through dev-dependencies plus the `_test_support` bazel variants; the shared `suite` stays ungated product surface | | | `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | a37c1e0cf | packages/d2b-process-conformance/src/sandbox.rs | Deleted CompiledSandbox::requires_cgroup_kill field, its unconditional true initializer in compile(), and its public accessor; census: `requires_cgroup_kill` over packages/, nixos-modules/, tests/, do | | | `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 6c66b83ea | packages/d2b-provider-activation-nixos/src/driver.rs | ActivationDriver narrowed to pub(crate) and dropped from the lib.rs driver re-export arm. Census re-run:the symbol appears only in driver.rs (7 sites)and lib.rs; no external consumer. Checks shared wi | | | `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | @@ -420,11 +421,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c9a141c78 | packages/d2b-provider-audio-pipewire/src/controller.rs | register_service deleted (zero callers; census over packages/nixos-modules/tests/docs/reference/labs = only the definition); daemon and wayland-policy validate specs via validate_audio_service directl | | | `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | needs-contract | U3 | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | deferred: needs-contract - AudioLastSetApplied::OfflineOnly naming vs its doc; variant renders to a wire-visible status string pinned in daemon tests; owning wave U3 (contract wave; ledger precedent RS-0955/RS-0957) | | | `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-cli` | | | -| `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | | | | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | | | +| `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | applied | W5 | 4524b7e45 | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | the public decode_document forwarder and its re-export are deleted; the sole caller in d2bd uses ConfigSyncResponse::document() directly, leaving one API path for validating a synced config document | | | `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | | `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | | `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | drop the zero-caller `ManagedIdentityPlacement::in_zone` constructor (exact duplicate of `new`); census over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 consumers outside the definit | | -| `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | | | | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effe` | | | +| `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | applied | W5 | 3c229db55 | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effe` | DeviceResourceState's three provider caches are private behind read-only typed accessors; the daemon's shared provider effects migrate all nine read sites and the GPU authority-lease construction contract stays behind the driver crate | | | `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U3 | 539ca5113 | packages/d2b-provider-device-gpu/src/lib.rs | gpu_argv/video_argv made private; root re-exports keep one reachable path per item. Census re-run: `d2b_provider_device_gpu::(gpu_argv/video_argv)::` over packages/nixos-modules/tests/docs/reference/l | | | `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U3 | 4efbf8ea5 | packages/d2b-provider-device-gpu/src/effects_service.rs | applied-variant: row's second option (single crate-owned sidecar) used: DeclaredWorkerGpuPortDeps sidecar (private fields, pub 4-arg ::new) holds the four dependency types; DeclaredWorkerGpuPortArgs ( | | | `RS-0372` | `api` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U3 | 0867cba1a | packages/d2b-provider-device-security-key/src/lib.rs | pub mod relay made private (relay_service already private at HEAD); lib.rs pub use arms stay the single surface. Census re-run: device_security_key::relay:: = 1 hit (backticked doc comment in d2b-brok | | @@ -439,7 +440,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 15d510a76 | packages/d2b-provider-display-wayland/src/controller.rs | WaylandPolicySnapshot::from_authenticated_session deleted (no callers; census over packages/nixos-modules/tests/labs/docs/reference = 0 in the display crate). | | | `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12` | | | | `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | -| `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | | | | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | | | +| `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | applied | W5 | f5672d7c9 | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | trim route: the uncalled Azure-VM update/adopt/complete-enrollment/status/controller-execution-ref surface and its consequential dead state are deleted after a census showing no production caller; the framework-driven reconcile/recovery/finalize surface is retained | | | `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmController::new now takes effect: E by value and stores it; the production call site and the crate's test call sites (18 FakeEffect constructions, incl. the shared-effect recovery test restruct | | | `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | fe17cfa53 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | repair_children no longer takes committed: &BTreeMap (sole caller passed an always-empty map); the unreachable committed.get(target) branch and the empty-map local are deleted. check/test/clippy green | | | `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | 2ba072632 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | assess_update no longer takes children (production adapter discarded it via let _; request carries none); trait default, adapter override, test impl, and the reconcile call site's Vec allocation all u | | @@ -460,12 +461,12 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | same wiring as RS-0959 | | | `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | same wiring as RS-0959 | | | `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | same wiring as RS-0959 | | -| `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | | | | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | | | +| `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | applied | W5 | f82fa17c8 | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | the empty test-support feature stanza is deleted with the [[test]] registration required-features gate and the bazel variant's crate_features that referenced it; the registration test now runs instead of being silently skipped, rbac stays public product surface | | | `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | applied | 4 | 7dadf9923 | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | | `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 0cb5d7b68 | packages/d2b-provider-supervisor/src/adapter.rs | | | -| `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | | | | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | | | +| `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | applied | W5 | 85cfe8bc1 | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | LaunchedSnapshot carries the launched runner (vm, role, pid, start-time ticks, pidfd) as a named struct with a redacting Debug; the in-tree ProcessEffectBackend trait and LaunchedObserver take it instead of five positional parameters and a 5-tuple, and the only call site plus both daemon call sites are re-pointed | | | `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | -| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | | | | `src/host.rs:389, src/host.rs:13` | | | +| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | needs-contract | W6 | | `src/host.rs:389, src/host.rs:13` | deferred: needs-contract - reject_operator_status_fields wired into daemon status admission moves a daemon-API surface; W6 | | | `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | make the `ownership` module private; the root re-export of the owned/disowned type lists is the single surface. Shares commit 31ff8b396 with RS-0409 (the audit's own census pairs these two module-surf | | | `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | narrow `reconcile_observed`/`HostProbeSnapshot` to `pub(crate)` with the crate-internal-only callers retained; drop the now-private seam from the crate's pub re-export. Shares commit 31ff8b396 with th | | | `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | forward `HostProbeMetadata` from the host re-export while dropping the zero-external-consumer `HostProbeSnapshot` constant from the public surface; the crate's probe seam stays internal until a consum | | @@ -475,8 +476,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | | `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs | | | | `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | -| `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | | | | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | | | -| `RS-0421` | `api` | `d2b-provider-volume-local` | medium | actionable | family | | | | `src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1` | | | +| `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | applied | W5 | 14bf42022 | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | the never-read VolumeDriverArgs zone field is removed; construction sites and fixtures no longer carry it | | +| `RS-0421` | `api` | `d2b-provider-volume-local` | medium | actionable | family | applied | W5 | 96fef8256 | `src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1` | the volume-local `testing` module is gated behind test-support (feature declared, the pre-existing `_test_support` bazel variant gains `crate_features`); the four volume-local suites, d2bd's cfg(test) consumer, and the crate's internal cfg(test) uses are re-pointed, with zero product-path consumers | | | `RS-0422` | `api` | `d2b-provider-zone` | medium | actionable | leaf | applied | U3 | c28489ccc | packages/d2b-provider-zone/src/lib.rs | zone_status module private with the four items re-exported by name; the two module-path consumers (d2bd resource_runtime.rs:63-65, tests/zone_status.rs:3-4) re-pointed to the crate root. Census: d2b_p | | | `RS-0423` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied-variant | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zone_links.rs | Fix as written (pub(crate)) not implementable: usage is test-only, and .cargo/config.toml -Dwarnings turns the resulting dead-code into build errors. Minimal correct variant: #[cfg(test)] on ZoneLinkM | | | `RS-0424` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zonelink.rs | Deleted transport_error_is_quarantine (zero callers in or out of crate, including tests; privatizing alone would trip -Dwarnings dead-code). ZoneLinkError import stays used by issue_route_admission. c | | @@ -488,7 +489,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | applied | 4 | 98f74a980 | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | | `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | 0cd7b063d | packages/d2b-resource-runtime/src/target.rs | Removed TargetBinding::directory() accessor. Census re-run: zero callers; the directory field stays read by internal methods (observe/delete/adopt), no dead code. cargo check/test/clippy green for d2b | | | `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | U3 | 3570364e0 | packages/d2b-resource-runtime/src/guest_target.rs | Removal as written orphans GuestTargetInner.reference (dead-code deny) and forces a public constructor signature change across 26 call sites in 5 files incl. d2bd production (published surface -> cont | | -| `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | | | | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | | | +| `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | applied | W5 | 96fef8256 | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | assert_metadata_registration and its re-export arm are gated behind test-support; the 11 registration test crates enable the feature in dev-dependencies, gain required-features where it was missing, and their bazel targets use the resource-types `_test_support` variant | | | `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/fragmentation.rs | Fragment.header is now private with a pub header() accessor; the two engine.rs encode call sites (877, 1395) use the accessor. Census: no external field access. | | | `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | | `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | applied | 4 | 2f034e476 | `packages/d2b-session-unix/src/socket.rs:176` | | | @@ -506,7 +507,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 1ed0521fa | packages/d2bd-runtime/src/console_session.rs | Dropped unused _vm parameter from spawn_ch_serial_drainer and the hardcoded "ch-console".to_owned() allocation at the create_ch_session call site. | | | `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e8e7a2d51 | packages/d2bd-runtime/src/console_session.rs | Deleted dead pub DrainerSource enum (census re-run: pattern DrainerSource over packages = 1 hit, the definition itself; zero constructions) and its #[allow(dead_code)]. | | | `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 26d5c1119 | packages/d2bd-runtime/src/console_session.rs | ConsoleRing/ConsoleSession fields made private; ConsoleRing exposes push_bytes/set_eof (notify internally), read_at, base_offset, notify(); ConsoleSession exposes provider_kind/ring/stdin_tx accessors | | -| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | | | +| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | deferred: needs-contract - parallel error enums carrying sources need contract sign-off on the wire-visible members; W6 (the broker hosts.rs member was already fixed by 84d4cb0b9; remaining members are usbip_lock.rs, the clipboard picker, azure-relay guest_zone_link.rs, resource-runtime, d2bd TypedError, and d2bd-runtime) | | | `RS-0477` | `err` | `d2b` | medium | actionable | leaf | applied-variant | U3 | 7256bc918 | packages/d2b/src/lib.rs | Added structured code field to CliFailure; populated in ZoneContext::failure; can_fallback_to_local_state and reconcile_deadline match on it. Field is String not &'static str because validate_response | | | `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | | | | `packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, ` | | | | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | @@ -571,8 +572,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | applied | U3 | 2ab7a1ed2 | packages/d2b-provider-user/src/driver.rs | Display impl now writes self.kind.failure_kind().code(); registered FailureKind codes remain the single source, strings unchanged, no behavior change. | | -| `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | | | | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-bindi` | | | -| `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 (driver-args class member key_ref; RS-0962) | +| `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-bindi` | BindingDriverArgs.zone is a ZoneId; BindingDriver derives the socket-identity bounded token once at construction instead of re-parsing the zone with expect on every pass, and the sole production construction in d2bd passes the parsed value | | +| `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 -> W5 (driver-args class member key_ref; RS-0962; the class remainder landed in W5 at 14bf42022) | | `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | applied | U3 | e783447e2 | packages/d2b-provider-wayland-session/Cargo.toml | Added tracing = 0.1 (already in lockfile; Cargo.lock records one new dep edge) and map_err now logs provider=WAYLAND_SESSION_PROVIDER_REF with reason=%error before mapping to InvalidResource. | | | `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Empty batch now rejected with 'batch mutation count is zero'; MAX_BATCH_MUTATIONS check keeps the bound reason. Reason string unpinned in error-codes.md. | | | `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | 854ba06a5 | packages/d2b-resource-client/src/call.rs | The three Mutex::lock().unwrap() sites in the waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) now use expect with the written reason: no user code runs u | | @@ -590,37 +591,37 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0527` | `err` | `d2bd` | medium | actionable | family | applied | 4 | ea55636aa | `packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511` | applied in two commits: f3028c0ee (d2bd-side propagation) + ea55636aa (CredentialRuntime::dependency_facts trait signature Result>, every impl and call site migrated; re-dispatched per Main's directive 2026-09-25) | | | `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d4fe83812 | packages/d2bd/src/composition.rs | dispatch_audit's unrecognized severity arm now returns TypedError::WireInvalidFrame { detail: "audit filter has an invalid severity".to_owned() } instead of InternalIo, so caller input errors surface | | | `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d1a472077 | packages/d2bd/src/composition.rs | ActivationLockGuard::drop now logs finish_activation failures via tracing::warn!(zone = %self.zone, error = %error, ...) instead of `let _ =`, mirroring the file's house style for coordinator refusals | | -| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | | | | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | | | +| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | deferred: needs-contract - audio mutation paths onto structured TypedError kinds changes the daemon-API wire error surface; W6 | | | `RS-0534` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | 96be9307a | packages/d2bd/src/resource_plane_v3.rs | ConstructionInputs::production now propagates attach_process_providers failures: state.provider_runtime.attach_process_providers(...).map_err(/error/ PlaneError::Authority(error.into()))? instead of ` | | | `RS-0536` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | fd6778735 | packages/d2bd/src/process_provider_runtime.rs | serving_worker_launch_args now warns when the 0700 enforcement on the worker socket parent fails: tracing::warn!(zone = %zone, socket_dir = %parent.display(), error = %error, ...) mirrors the pidfd sn | | -| `RS-0528` | `err` | `d2bd` | low | actionable | family | | | | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | | | +| `RS-0528` | `err` | `d2bd` | low | actionable | family | applied | W5 | 2fa4cd475 | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | TypedError's io, config, and broker-unavailable variants carry an `Option` origin (Arc) built by a bounded helper, Display renders the unchanged envelope string, and the raw-detail logging boundary renders a depth-capped source chain; the 34 owned composition.rs sites plus 67 more sites across d2bd-runtime, audio dispatch, forward rendezvous, and the bundle-tampered test are converted (116 sites legitimately pass None where detail is a literal or wire-field rendering), and a test pins byte-identical envelopes | | | `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | already-fixed | U3 | ebb3831b1 | packages/d2bd-runtime/src/broker_transport.rs | At session-start HEAD, default_audit_join_context maps CanonicalAuditDigest::parse failures to TypedError::WireInvalidFrame;no .expect remains (commit ebb3831b1, ledger wave U1 applied-variant). No ed | | | `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | c14b5d486 | packages/d2bd-runtime/src/wire.rs | map_parse_error classifies structurally: serde_json::Error::classify() gates the frame kind, and the generic WireInvalidFrame detail now carries line/column; the two payload-level wire kinds (unknown- | | | `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | cdfb78d49 | packages/d2bd-runtime/src/exec_session.rs | spawn_session_worker now returns std::io::Result> (Builder::spawn error propagated via Ok(...)?), replacing the expect panic; the two test call sites unwrap with expect. | | | `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 75c49e784 | packages/d2bd-runtime/src/console_session.rs | Deleted panicking impl Default for ConsoleClientHandle (census: no ConsoleClientHandle::default() callers in workspace). | | | `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | a09140432 | packages/d2bd-runtime/src/daemon_version.rs | version-file read failures typed (VersionFileReadError); check + tests green | | | `RS-0543` | `err` | `xtask` | medium | actionable | leaf | applied | U3 | 7194d24e9 | packages/xtask/src/delivery/recovery.rs | RecoveryError::Read added for fs open/read failures; Json(String) now carries the bounded serde detail (field names/positions only via error.to_string(), never payload values, keeping the redaction co | | -| `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | +| `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 6467d8d2c | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | the wire_deserialize! macro moves to d2b-contracts with #[macro_export] and 72 hand-written Wire admission Deserialize impls (17 contracts-provider, 55 contracts-resource) become macro invocations; container attributes, field lists, and admission expressions are token-identical, the emitted schemas are byte-identical, and zone-session's 28 invocations re-point at the shared home (one contracts-broker site is out of this slice's scope) | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | -| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | | | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | | | -| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | | | +| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | deferred: needs-contract - AuditExportEntry exactly-one payload enum is wire-visible; W6 | | +| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | deferred: needs-contract - OpenUnitPidfdRequest/StopUnitRequest flatten plus deny_unknown_fields admission is wire-visible; W6 | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | -| `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | +| `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | applied | W5 | e77bf4940 | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | ResourceError deserialization routes through the validating constructor, rejecting a revision for a kind that forbids it and inconsistent retry fields; the wire shape is unchanged | | | `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | | `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | applied-variant | 4 | a2cf0e614 | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | applied-variant: consolidated 28 Wire-shape Deserialize impls behind the crate-local wire_deserialize! macro in d2b-contracts-zone-session (canonical home; later waves must reuse it, not write a third macro); parsed_deserialize! requires Self::parse(String) (JSON-string wire), which no Wire-struct impl matches - adopting it would change the wire format the row never asked to change (Main ruling 2026-09-25) | | | `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/storage_lifecycle.rs | serde rejects rename_all on struct variants (field attribute); applied the equivalent house pattern #[serde(rename_all_fields = "camelCase")] on the enum container + dropped per-field renames; seriali | | | `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175` | | | | `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | -| `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | | | | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | | | +| `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | applied | W5 | 6ecf465b7 | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | typed serde structs (rename_all camelCase, deny_unknown_fields) replace the Value-walking assignment codec and the child-create json! literal builder; exact keys, version 1, ascending verb arrays, canonical bytes, and the size bounds are pinned by the transport tests | | | `RS-0557` | `serde` | `d2b-host` | low | actionable | family | applied | 4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:229` | | | | `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | | `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | | `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-` | | | | `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | | | | `packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/comm` | | | | `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | d58f183d5 | packages/d2b-provider-device-gpu/src/gpu_argv.rs | deny_unknown_fields added to GpuArgvInput/GpuParams/GpuDisplayConfig (mirroring VideoArgvInput); new rejects_unknown_fields test pins top-level, params-nested, and display-nested rejection. Mutation c | | -| `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | | | +| `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | applied | W5 | 4cb0daadb | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | the receive path decodes each newline-delimited bridge frame with a typed #[serde(tag = "type", rename_all = "snake_case")] inbound enum mirroring the outbound frame instead of scanning raw bytes for the refresh substring; a frame that fails to decode is rate-limited-diagnosed and dropped, and later frames still refresh (pinned by tests) | | | `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 84b343101 | packages/d2b-provider-display-wayland/src/spec.rs | Inert serde try_from attribute removed; rename_all/deny_unknown_fields and the manual Deserialize + TryFrom kept. | | | `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | | `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/driver.rs:282-289, src/driver.rs:190` | | | @@ -628,7 +629,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generate` | | | | `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | needs-contract | U3 | | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-p` | deferred: needs-contract - RelayTransportSettings derives Deserialize without try_from, bypassing validate() incl. the secret-shape exclusion; owning wave U3 (contract wave) | | | `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264` | | | -| `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | | | | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | | | +| `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | applied | W5 | 379eb3b33 | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | VsockTransportSettings deserializes through a private wire mirror with TryFrom validation, so untrusted JSON is rejected at the boundary; fields are private with accessors and the wire names and JSON schema are unchanged - the needs-contract verdict is overridden because no wire surface moved | | | `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | applied | U3 | b00a073f2 | packages/d2b-provider-volume-local/src/content.rs | ContentFile/ContentProjection/NetworkConfigContentProjection decode via serde try_from Raw mirrors running validating constructors; Deserialize dropped from evidence types; wire shape unchanged. | | | `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | 4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | | `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | @@ -710,7 +711,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | e7bba788d | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | none (anchor drift only) | | | `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/limits.rs` | module-level rationale naming the enforcing boundaries | | | `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | 712bb24af | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | three enumerated sub-claims were already documented at the audit baseline and left unchanged (verified via git show 6ebdd4cec): MutationSealAcceptor::diagnose (seal.rs:176-177), PreparedStoreMutation: | | -| `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | | | | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | | | +| `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | applied | W5 | 0274747fc | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | the 37 ComponentSession v3 wire constants carry one-line docs naming their wire role; values, names, and ordering are unchanged | | | `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/manifest_v04.rs` | module doc plus docs on ManifestV04/ManifestMeta/ObservabilityMeta/VmEntry/VmLifecycle/VmGracefulShutdown/VmLiveActivation/VmLanPolicy/VmObservability/VmShellMetadata/ManifestShellName; # Errors on fr | | | `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | one-line docs naming the exact BundleOpId shape added to all 15 undocumented intent_id_* constructors | | | `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/main.rs` | One-line field docs added to RuntimeReadiness (4), RecoverySnapshot (5), HandlerStatus (9). | | @@ -816,7 +817,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0753` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | doc comments above today_utc_iso8601 and civil_from_days naming the Hinnant algorithm, constants, and epoch fallback | | | `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | applied-variant | W3 | 44cb49a0d | `context.rs:570, context.rs:538` | | | | `RS-0757` | `perf` | `d2b-audit` | low | actionable | leaf | applied | W3 | 10923b65e | `packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970` | | | -| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | escalated | W3 | | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | applied | W5 | 6488d26a4 | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | the broker protocol receive path peeks the 4-byte length prefix with MSG_PEEK and allocates the declared size plus the prefix; SCM_RIGHTS receipt is size-exact the same way, and sockets without MSG_PEEK keep the fixed allocation | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0759` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/nft.rs:784-790` | | | | `RS-0760` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368` | | | | `RS-0758` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, pa` | | | @@ -843,7 +844,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0783` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `ingress_policy.rs:203, ingress_policy.rs:368` | | | | `RS-0784` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:44` | | | | `RS-0785` | `perf` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process` | | | -| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | escalated | W3 | | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/sr` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/sr` | SharedProviderEffectRequest borrows the row's canonical spec document from the driver's spec envelope instead of cloning it into every reconcile and delete request | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0787` | `perf` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-p` | | | | `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | | `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | applied | W3 | 037e23533 | `driver.rs:437-440, driver.rs:614-617` | | | @@ -901,10 +902,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | f4f09c74c | packages/d2b-broker/src/ops/host_generation_handoff.rs | flock wait moved to a bounded worker (sanctioned allow reason) | | | `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | | `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | policy-confirmed | W3 | | `packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | -| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | escalated | W3 | | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | ProcessLaunchEffectPort and ProcessProvider declare their methods as `async fn` (the RPITIT `impl Future + Send` form is retired) under the house `#[allow(async_fn_in_trait)]` that the pinned lint configuration requires; default bodies are plain async blocks, implementors and the single Send-bound caller keep working, and the bazel graphs re-point consumer test targets at the test-support variants so each crate keeps one instance | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | applied | W3 | 7de088b5d | `packages/d2b-provider/src/agent.rs:316-324` | | | | `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-cre` | | | -| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | escalated | W3 | | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | applied | W5 | 7a971ec0b | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | the TPM prepare-state kernel round trip runs on the bounded kernel seat and the NSS lookups on the bounded loader worker instead of the executor worker; spawn_blocking is deny-listed by clippy.toml and banned by plan KD2 (2026-09-16-001), so the sanctioned bounded seats carry the work, the timeout and error mapping are byte-preserved, and the crate's async-gate inventory entries are refreshed for the line shift | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0847` | `async` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | W3 | 7de088b5d | `effects_service.rs:361, effects_service.rs:384, effects_service.rs:698` | | | | `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/observe.rs:255-260` | | | | `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:30, src/testing.rs:19` | | | @@ -1001,13 +1002,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0942` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | | `RS-0943` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.baz` | | | | `RS-0944` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55` | | | -| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | escalated | W3 | | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | -| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | escalated | W3 | | `Cargo.toml:202, deny.toml:2` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | the nix 0.26.4/0.31.3 transitive legs are recorded as accepted clusters with pullers and a re-check trigger in deny.toml [bans]; the workspace pin stays at 0.29 | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:202, deny.toml:2` | the rustix 0.38/1.1 legs are recorded as an accepted cluster with a re-check trigger in deny.toml [bans] | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0948` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport` | | | -| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | escalated | W3 | | `packages/Cargo.guest.lock:1, flake.nix:389` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | -| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | escalated | W3 | | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | -| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | escalated | W3 | | `deny.toml:2` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | -| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | escalated | W3 | | `deny.toml:21` | deferred to waves 4-5: blast radius exceeds leaf (README.md remediation section 6 orders leaf first, family next, wide last) | | +| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied-variant | W5 | 78b5c5672 | `packages/Cargo.guest.lock:1, flake.nix:389` | a lock-drift check compares shared-crate versions across Cargo.lock and packages/Cargo.guest.lock and records the 39 lags; deviation: the one-snapshot aligned regen stays at the next dependency refresh, which is where the row's own fix text scopes it (regen needs the container lane) | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | 13 member decls across 10 crates inherit rustix and sha2 from workspace.dependencies instead of literal pins; the resolved versions and both lockfiles are unchanged | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2` | the 31 transitive-only duplicate clusters are inventoried in deny.toml [bans] with versions, pullers, and re-check triggers; multiple-versions stays warn because the workspace-direct clusters do not resolve | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:21` | deny.toml licence confidence-threshold is raised from 0.8 to 0.9 and any failing allow-listed licence moved to a per-crate [licenses.exceptions] entry with its reason | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0929` | `supply` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:24, Cargo.toml:25` | | | | `RS-0930` | `supply` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.tom` | | | | `RS-0931` | `supply` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:21` | | | From 56a9274499b0ee8b0bbf46b00526b1b34c9668ed Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:49:09 -0700 Subject: [PATCH 632/726] audit: point the wave-5 gate row at the final integration head --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 991205d5e..b826ca999 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -42,7 +42,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | -| W5 | `832369096` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step, not this wave's. | +| W5 | `25b2474f4` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step, not this wave's. | ## Findings (965 rows) From 73c248e01f183e3f79b640a897a6d4484f62f240 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:55:16 -0700 Subject: [PATCH 633/726] repo: repair the wave-5 gate breaks the keep-going run named - the three bazel test targets whose sources gained a d2b_contracts import when the compat shims were deleted (d2b-core bundle-resolver-tamper and d2b-core-smoke, d2bd bundle_tampered_envelope) now declare the //packages/d2b-contracts:d2b_contracts dependency their BUILD files lacked; cargo resolved it through the crate graph, bazel did not. - the broker frame-receive peek arms use the redundant-guard-free pattern clippy requires (Err(Errno::EINVAL | Errno::ENOTSUP)); behaviour is identical and the guard binding was unused. --- packages/d2b-broker/src/protocol.rs | 4 ++-- packages/d2b-core/BUILD.bazel | 2 ++ packages/d2bd/BUILD.bazel | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/d2b-broker/src/protocol.rs b/packages/d2b-broker/src/protocol.rs index dba3ebc75..bcffe058e 100644 --- a/packages/d2b-broker/src/protocol.rs +++ b/packages/d2b-broker/src/protocol.rs @@ -134,7 +134,7 @@ pub fn recv_json_frame(fd: RawFd) -> io::Result> // A socket type without `MSG_PEEK` support keeps the fixed // ceiling allocation; the receive itself is unchanged. (`ENOTSUP` // and `EOPNOTSUPP` are the same errno on Linux.) - Err(err) if matches!(err, Errno::EINVAL | Errno::ENOTSUP) => { + Err(Errno::EINVAL | Errno::ENOTSUP) => { return recv_json_frame_fixed(fd); } Err(err) => return Err(io_error(err)), @@ -258,7 +258,7 @@ pub fn recv_json_frame_with_fds( // A socket type without `MSG_PEEK` support keeps the fixed // ceiling allocation; the receive itself is unchanged. (`ENOTSUP` // and `EOPNOTSUPP` are the same errno on Linux.) - Err(err) if matches!(err, Errno::EINVAL | Errno::ENOTSUP) => { + Err(Errno::EINVAL | Errno::ENOTSUP) => { return recv_json_frame_with_fds_fixed(fd); } Err(err) => return Err(io_error(err)), diff --git a/packages/d2b-core/BUILD.bazel b/packages/d2b-core/BUILD.bazel index db223d2b6..f0d6ef987 100644 --- a/packages/d2b-core/BUILD.bazel +++ b/packages/d2b-core/BUILD.bazel @@ -80,6 +80,7 @@ d2b_rust_test( compile_data = ["Cargo.toml"], visibility = ["//visibility:public"], deps = [ + "//packages/d2b-contracts:d2b_contracts", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", ":d2b_core", @@ -197,6 +198,7 @@ d2b_rust_test( use_libtest_harness = False, visibility = ["//visibility:public"], deps = [ + "//packages/d2b-contracts:d2b_contracts", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", ":d2b_core", diff --git a/packages/d2bd/BUILD.bazel b/packages/d2bd/BUILD.bazel index 4aa04ce63..255fa0b7f 100644 --- a/packages/d2bd/BUILD.bazel +++ b/packages/d2bd/BUILD.bazel @@ -341,6 +341,7 @@ d2b_rust_test( tags = ["no-remote-cache"], visibility = ["//visibility:public"], deps = [ + "//packages/d2b-contracts:d2b_contracts", "//packages/d2b-contracts-provider:d2b_contracts_provider", "//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", From 088721b8d47425b8ec3ae4e107b9540cdfb84e65 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 18:55:46 -0700 Subject: [PATCH 634/726] fix(xtask): drop the stale otel exemption for the contracts-control CLI surface w6-02 deleted the `otel_relay`/`otel_host_bridge` fields from packages/d2b-contracts-control/src/cli_output.rs, which were the module's only otel role literals. The family-knowledge ratchet still exempted that module for token `otel`, so the exemption no longer matched the committed tree: `//bazel/checks/policy:provider_crate_layout` and the ratchet test inside `//packages/xtask:xtask_test` both failed with stale-shared-family-knowledge-exemption. The exemption is deleted; the module's other exemptions (gpu, tpm, swtpm, usbip, wayland, qemu_media) are untouched because those tokens are still present. Gate: //bazel/checks:check (provider_crate_layout + xtask_test). --- packages/xtask/src/provider_crate_policy.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index 0e49e4508..e837eb5ce 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -2952,12 +2952,6 @@ const SHARED_FAMILY_KNOWLEDGE_RATCHET: &[SharedFamilyKnowledgeExemption] = &[ family: "observability-otel", retires_with: "U10-U12 family rollout (observability-otel)", }, - SharedFamilyKnowledgeExemption { - module: "packages/d2b-contracts-control/src/cli_output.rs", - token: "otel", - family: "observability-otel", - retires_with: "U10-U12 family rollout (observability-otel)", - }, SharedFamilyKnowledgeExemption { module: "packages/d2bd/src/process_provider_runtime.rs", token: "cloud_hypervisor", From 94c8fcdd21421d05b9fc7a99fdd2d567c9a2386c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:00:13 -0700 Subject: [PATCH 635/726] audit: fold the wave-6 ledger outcomes and point the wave row at the integration head All 15 dispatched rows now carry outcome/wave/commit - 12 applied and 3 applied-variant with the recorded deviations (RS-0952, RS-0454, RS-0333). The four reason cells that were clipped in the file itself are repaired and marked [reconstructed] (RS-0278, RS-0330, RS-0454, RS-0545). The wave-gates table gains its W6 row: the four gate cells read not run (Main gates) and the head cell names `088721b8d`, the head the five preflights measured (this commit is ledger-only on top of it). --- .../2026-09-24-rust-skills-audit/ledger.md | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 0dc1ba7e1..da9fbcac7 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -42,6 +42,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | +| W6 | `088721b8d` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred): all 15 dispatched rows disposed - 12 applied, 3 applied-variant with recorded deviations (RS-0952, RS-0454, RS-0333); 9 slices in six surface groups, all merged into `phase-w6-integration`, plus three integration-direct commits (the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh for the wave-6 line shifts). Two preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs`, re-linted once the w6-01 rewrite touched that file; and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the head the five preflights measured; this row ships in a ledger-only commit on top of it. | ## Findings (965 rows) @@ -287,9 +288,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0229` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | mem::take on the mut slot before in-place edit | | | `RS-0230` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | two ratchet probes key borrowed strs via signal fields | | | `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | applied-variant | 4 | 0b5c7d292 | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | applied-variant: d2b-core privileges enums (SecretAccess, BrokerRequirement, AuditMode) gained Copy derives - required because BrokerAuthzFacets/BrokerOperationRow derive Copy; additive, non-breaking | | -| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | Disposition is &'static str in a generator-emitted closed set with a drift gate; typing it needs a generator change (generated artifact). | | -| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | | | | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | | | -| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | needs-contract | U3 | | packages/d2b-broker/src/catalog.rs | The destructive flag is emitted as a bare boolean by the operations generator; the stated drop of the arity allow is not implementable while the helper takes eight arguments. | | +| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | applied | 6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Closed Disposition enum (CallableReadOnly/PromotedLive/StubbedUnimplemented/CompileTimeOnly, as_str) beside StubTarget in catalog.rs; BrokerOperationRow.disposition typed against it; generator emits via disposition_variant() mapper with a DISPOSITIONS closed-set validation; the five string-match sites migrated to variant matches; policy JSON stays the string vocabulary. | | +| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | applied | 6 | 13101e206 | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | Generator emits a full closed BrokerOperationName enum (98 variants, as_str); HOST/GUEST_OPERATION_CATALOG and the row operation field typed against it; allows_operation keeps the &str spelling via as_str so the wire boundary is unchanged; consumers migrated (broker_wire.rs, catalog.rs, runtime.rs, d2b-broker/tests profiles, envelope/mod.rs, d2b-broker-composition routing/seam). | | +| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | applied | 6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Destructive enum (Serialize/Deserialize/JsonSchema, kebab-case) in privileges.rs; both field types bool -> Destructive; generate_authz emits named-field construction with Destructive::No/Yes; row() helper and its arity allow deleted (PUBLIC_OPERATION_AUTHZ converted in the same change); Nix emitter, v2 schema, and fuzz corpus seeds moved to no/yes; v1 schema frozen. | | | `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | escalated | U1 | | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | wave 0 applied the panicking constructor member (RS-0516); the five remaining provider-crate zone/key_ref member sites are the family wave's | U5 | | `RS-0263` | `type` | `d2b` | low | actionable | leaf | applied | U3 | f98ad4f82 | packages/d2b/src/context.rs | ZoneContext now stores ZoneId; zone_ref/zone_name built from it; validate_zone_name deleted; discover double validation removed; from_socket takes ZoneId directly. | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | @@ -330,7 +331,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | | `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | applied | 4 | 9870dc852 | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | | `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | -| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | needs-contract | U3 | | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery recor | | +| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | 6 | 5d067420c | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery records [reconstructed: must still load after the change, so the sealed-record read path needs a bounded migration (the sealed Volume survives execute_upgrade per ADR-046-provider-runtime-azure-virtual-machine.md:1157)]. Grouped the operation/operation_started_at_unix_ms pair into Option; hand-written Deserialize accepts both the new inFlightOperation shape and the legacy pair (total fold); pair check deleted; legacy-shape deserialize test added; ADR sealed-recovery section notes the accepted legacy shape. | | | `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired - the illegal Consumed/Expired-with-Some(psk) combination is now unco | | | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | e53601c88 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | derive_private_runtime_scope and private_runtime_scope take ChildRole and use role.suffix(); the &str whitelist branch is gone. Callers incl. wayland-policy migrated. | | @@ -368,7 +369,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0313` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 1d692db3d | packages/xtask/src/provider_crate_policy.rs | FamilyKnowledgeSignal gains typed count: Option; ServerState site fills it and drops the serialized-count text; renderer matches class without the parse;the ratchet JSON stays byte-identical (t | | | `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option pub(crate) for all 19 gpu.rs items and 7 modprobe.rs items (types, impl methods, free fns, trait). Chose item-level over module-decl narrowing so d2b-core bundle_resolver.rs:4300 and | | | `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | | | | `src/lib.rs:45, src/ops/mod.rs:20-94` | | | -| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | Re-verified claim at HEAD: `pub fn acquire_lock` (ops/usbip_lock.rs:101-106) takes `_daemon_uid: u32` (underscore-prefixed) the body never uses. BUT the parameter is a parameter of a `pub fn` on the ` | | +| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | applied | 6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | Dropped the unused _daemon_uid parameter from pub fn acquire_lock; all 12 census call sites plus 9 in-file test sites and the dead daemon_uid forwarding param on live_usbip_bind (6 callers) updated; broker-internal signature, no doc or fixture pins it. | | | `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | 068ddcfc4 | packages/d2b-broker/src/ops/cgroup.rs | CgroupBundleContext::slice_path() now returns &Path (borrows parent_slice, no clone). Call sites: vm_interior_path join works on &Path; AuditFields slice_path and the D2bSlice tuple site keep one to_p | | | `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | | `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | applied-variant | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | Census re-run:= with_observer/with_observer_and_metrics/with_clock_and_observer have zero ZoneBus callers, deleted; with_clock -> pub(crate) because production new() delegates to it; with_clock_observ | | @@ -388,10 +389,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | | `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | 4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | -| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but | | -| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `cli_output.rs:6` | Deleting the pub re-export of LevelPercent from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 0 hits for cli_output::LevelPercent outside cli_output.rs:6 | | +| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | +| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | | `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | | | -| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | needs-contract | U3 | | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Narrowing pub methods in the published crate is a published-surface move; additionally the lane census is stale: HelperLaunchRequest::validate_bounds has a live external caller at d2b-unsafe-local-hel | | +| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied-variant | 6 | dc145cf0c | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Caller-migration variant (recorded deviation; the ledger's census was stale): the two live external callers of HelperLaunchRequest::validate_bounds (d2b-unsafe-local-helper protocol.rs:157, runtime.rs:333) migrated to the pub free fn validate_unsafe_local_resource_identity; then both methods narrowed to pub(crate). Wire types and serde admission unchanged. | | | `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | | `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 67393687b13c359ac6b3a96bca469d28e25c7c96 | packages/d2b-contracts-resource/src/v3/identity.rs | Deleted the zero-caller alias and its doc. Census re-run: ValidatedSessionPurpose over worktree = 1 hit (the definition); no re-export arm in v3/mod.rs. cargo check -p d2b-contracts-resource --locked | | @@ -512,17 +513,17 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | | `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 637d66627 | packages/d2b-audit/src/segment.rs | | | | `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | -| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source | | +| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | applied-variant | 6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source [reconstructed: ]source: io::Error`; the Display text is preserved, so the broker error-envelope strings are unchanged; one format-string site (usbip_lock.rs:111) needs its own variant]. Applied as variant-split deviation: Io { path, source: io::Error } with a manual Error::source() override (no thiserror dep in d2b-broker) and a new PathSafetyViolation { path } variant; Display byte-identical. | | | `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | | `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | ce4da285b | packages/d2b-broker/src/state_cells.rs | with_retention now returns Result (test caller updated with expect); in_memory expect names the startup-precondition rationale; check/test/clippy green. | | | `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | -| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | needs-contract | U3 | | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | Claim re-verified at HEAD: `guest_socket_directory` (ops/device_worker.rs:262-284) returns `Result<&'static str, &'static str>`-style plain-static-code refusals, consumed at live_handlers.rs:2428 by s | | +| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | applied | 6 | fd5b41b4b | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | guest_socket_directory now returns a pub(crate) GuestSocketError enum (RuntimeRootNotAnchored/GuestNotAPlainName/DirectoryOutsideRuntimeRoot) whose Display preserves the three static-code substrings byte-for-byte; the two live_handlers.rs consumers updated; substring-asserting tests stay green. | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/src/seam.rs | verify_startup_routing returns Result<(), StartupRoutingViolation> (UnadmittedHandler/MissingHandlers, Display preserved for main.rs); audit_crate/run_cargo_metadata/dependency_tree return Result<_, S | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/configured_argv.rs | ConfiguredArgvError, LauncherMetadataError, UnsafeLocalWorkloadsError, MediaRefError, UsbBusIdError, AuditPageError enums with Display+Error replace String/&'static str returns; unwrap-only callers co | | | `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | Added fmt::Display (message "invalid shell name") and std::error::Error impls to ShellNameError; additive, no surface moved. cargo check/test/clippy -p d2b-contracts-control --locked all passed | | | `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | applied | U3 | 58e72374f | packages/d2b-contracts-provider/src/v3/provider_registry.rs | split zero-generation check before mapping-count bound; Defensive-only reachability since ResourceGeneration rejects 0 at new/Deserialize; no consumer pins the code | | -| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | needs-contract | U3 | | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError Display strings are wire outcome codes pinned by docs/specs/ADR-046-resources-credential.md:903 (credential-queue-pressure = lease table at capacity) and the provider ADR err | | +| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | 6 | 1a6ca86e7 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError::AlreadyRunning Display now emits credential-already-running; the lease-ceiling emitters (CredentialAuditOutcome/CredentialTelemetryOutcome as_str) fixed to credential-queue-pressure and the allowed_telemetry_value closed set updated so the ADR-documented code has its real emitter; ADR-046-resources-credential.md Errors table amended in the same commit, plus the two provider ADRs' code tables that enumerate the same set. | | | `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | | `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | ed46f196b | packages/d2b-contracts-provider/src/v3/provider_registry.rs | added GenerationMismatch variant kebab code provider-registry-generation-mismatch; updated failure-path test to assert the variant; census ProviderRegistryError=12 hits all in-file | | | `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 75e9c238c | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialSingleFlight lock() now recovers poisoned mutexes via unwrap_or_else(poisoned.into_inner()) and returns the guard directly (infallible); guard Drop recovers the same way instead of silently | | @@ -530,7 +531,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | | `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_macvtap_intents now returns crate::error::Error via Error::manifest_parse_error (typed, two failure modes distinguishable); broker call site updated to house .map_err(/error/ BrokerError::Live | | | `RS-0475` | `err` | `d2b-core` | medium | actionable | family | applied | 4 | 5282e9337 | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | -| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | Stated fix (plumb Result out of build_resource_network_intents/find_network_spec) requires changing the public signatures of six resolve_network_*_intent methods consumed by d2bd (composition.rs:7247- | | +| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | applied | 6 | 8de97517b | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | find_network_spec and build_resource_network_intents return Result; the six resolve_network_*_intent pub methods return Result, Error> with Error::manifest_parse_error("resource-bundle.json", reason); ~20 call sites and the NetworkIntentSource trait updated; regression test pins kind ManifestParseError / code 40; error-codes.md unchanged; behavior note added to manifest-bundle.md. | | | `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/site.rs | SiteJson::validate returns SiteValidationError::InvalidWaylandSocket enum with Display token; caller and tests updated | | | `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | | `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | manifest_parse_reason now matches serde_json::Error::classify() (Category::Data/Syntax/Eof/Io) instead of Display text; all 8 call sites updated to pass &error; slug change not wire-visible per census | | @@ -582,7 +583,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | | `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | applied | U3 | 6f07391f0 | packages/d2b-telemetry/src/emitter.rs | Added EmitterError::InvalidLimits with Display arm and doc updates; zero-capacity/frame/age/retry guards return it; StatePoisoned kept for lock().map_err sites; check/test/clippy green. | | | `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | applied | U3 | 1453d6b9a | packages/d2b-telemetry/src/session_metrics_sink.rs | Deleted never-constructed SessionMetricsError::Encode variant and its session-metric-encode-failed Display arm; check/test/clippy green. | | -| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | needs-contract | U3 | | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | Stated fix changes a wire-visible HelperFailureCode mapping pinned in docs/reference/error-codes.md; deferred as contract-adjacent. | | +| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | applied | 6 | 0330ae04b | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | await_scope_identity's early-exit Ok(_) arm now maps to ScopeError::CreateFailed; the existing mapping chain carries it to HelperFailureCode::ScopeCreateFailed -> daemon wire code 42; both codes stay documented in error-codes.md (rows untouched, drift gate green); regression test pins the reclassified contract. | | | `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | | `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | a91ad9bbc | packages/d2bd/src/resource_plane_v3.rs | PlaneError's five String variants retyped: FoundationSeed(#[from] SeedError), ManagerSpawn(#[from] ractor::SpawnErr), Bundle(#[from] ResourceBundleError), Authority/Target(#[source] Box Date: Fri, 25 Sep 2026 19:12:52 -0700 Subject: [PATCH 636/726] refactor(d2bd-runtime): type the audio mutation target refusals RS-0537 / RS-0963 (d2bd member): TypedError gains AudioVmNotFound and AudioNotEnabled leaf variants carrying the same per-VM classes the audio status path reports through AudioVmError, replacing the flattened InternalIo { context, detail } strings for a VM absent from the public manifest or without audio. The new kinds differ from internal-io, so a mutation caller distinguishes a user-input refusal from an internal I/O failure by kind/exit code instead of by matching the message text. Co-change list: dispatch sites packages/d2bd/src/audio_dispatch.rs (next commit of this slice), docs/reference/error-codes.md row, changelog.d/w6-13-d2bd-structured-error-kinds.md (both next commit). Emitted bytes: no documented code in docs/reference/error-codes.md moves; the two new daemon-API envelope kinds are new. Outside-tree observers: none in tree; a public-socket client that matched internal-io on these paths observes the new kinds. gate: cargo test -p d2bd-runtime --lib typed_error -> 18 passed; 0 failed --- packages/d2bd-runtime/src/typed_error.rs | 104 ++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/packages/d2bd-runtime/src/typed_error.rs b/packages/d2bd-runtime/src/typed_error.rs index 12a88d9d5..0f3a79e5a 100644 --- a/packages/d2bd-runtime/src/typed_error.rs +++ b/packages/d2bd-runtime/src/typed_error.rs @@ -676,6 +676,20 @@ pub enum TypedError { workload_id: String, detail: String, }, + /// An audio mutation (`set-volume` / `mute`) named a VM that is not + /// declared in the public manifest. The status path reports the same class + /// per VM as `AudioErrorKind::VmNotFound`, so a mutation caller + /// distinguishes a bad target from an internal I/O failure by `kind` / + /// exit code instead of by matching the message text (RS-0537). + AudioVmNotFound { + vm: String, + }, + /// An audio mutation (`set-volume` / `mute`) named a VM whose manifest + /// entry does not declare audio. The status path reports the same class + /// per VM as `AudioErrorKind::AudioNotEnabled` (RS-0537). + AudioNotEnabled { + vm: String, + }, } /// Classify the detail string for a lock-parent validation failure into @@ -753,6 +767,8 @@ impl TypedError { Self::ConsoleSessionTableFull { .. } => "console-session-table-full", Self::WorkloadTargetNotFound { .. } => "workload-target-not-found", Self::WorkloadAliasConflict { .. } => "workload-alias-conflict", + Self::AudioVmNotFound { .. } => "audio-vm-not-found", + Self::AudioNotEnabled { .. } => "audio-not-enabled", } } @@ -814,6 +830,13 @@ impl TypedError { // Ambiguous alias is an operator error (wrong invocation), // not a runtime or internal failure. Self::WorkloadAliasConflict { .. } => 2, + // Audio mutation refusals share the "target not found" convention + // with ConsoleVmNotFound and WorkloadTargetNotFound above. + Self::AudioVmNotFound { .. } => 2, + // A VM whose manifest entry does not declare audio is a + // configuration refusal of the same class as GuestShellDisabled and + // RuntimeCapabilityUnsupported. + Self::AudioNotEnabled { .. } => 70, } } @@ -955,6 +978,12 @@ impl TypedError { use the canonical target (e.g. {workload_id}.realm.d2b) to disambiguate" ) } + Self::AudioVmNotFound { vm } => { + format!("audio: VM '{vm}' not found in the public manifest") + } + Self::AudioNotEnabled { vm } => { + format!("audio: VM '{vm}' does not declare audio in its manifest entry") + } } } @@ -1092,6 +1121,15 @@ impl TypedError { select the specific workload unambiguously" ) } + Self::AudioVmNotFound { vm } => { + format!( + "verify that '{vm}' is declared in the d2b configuration and the bundle is up to date" + ) + } + Self::AudioNotEnabled { .. } => { + "enable d2b.vms..audio.enable for this VM, rebuild the bundle, and retry" + .to_owned() + } } } @@ -1203,6 +1241,20 @@ impl TypedError { "usbip explicit attach rejected: active claim conflict" ); } + Self::AudioVmNotFound { vm } => { + tracing::warn!( + kind = self.kind(), + vm = %vm, + "audio mutation refused: VM not declared in the public manifest" + ); + } + Self::AudioNotEnabled { vm } => { + tracing::warn!( + kind = self.kind(), + vm = %vm, + "audio mutation refused: audio not enabled for this VM" + ); + } // Remaining variants already carry only safe values in // their public messages (UIDs, version ranges, frame // sizes, field names) - no extra logging needed. @@ -1250,7 +1302,9 @@ impl TypedError { | Self::ConsoleSessionStale | Self::ConsoleSessionTableFull { .. } | Self::WorkloadTargetNotFound { .. } - | Self::WorkloadAliasConflict { .. } => "internalError", + | Self::WorkloadAliasConflict { .. } + | Self::AudioVmNotFound { .. } + | Self::AudioNotEnabled { .. } => "internalError", } } } @@ -1632,6 +1686,18 @@ mod tests { }, "host-kernel-modules-missing", ), + ( + TypedError::AudioVmNotFound { + vm: "work".to_owned(), + }, + "audio-vm-not-found", + ), + ( + TypedError::AudioNotEnabled { + vm: "work".to_owned(), + }, + "audio-not-enabled", + ), ]; for (err, expected_kind) in &cases { assert_eq!(err.kind(), *expected_kind, "kind mismatch for {err:?}"); @@ -1640,6 +1706,42 @@ mod tests { } } + #[test] + fn audio_mutation_refusals_are_structured_and_leak_free() { + // RS-0537: an audio mutation must not report a user-input refusal as + // the `internal-io` class, so a caller can tell the two apart without + // matching the message text. + let not_found = TypedError::AudioVmNotFound { + vm: "work".to_owned(), + }; + assert_eq!(not_found.kind(), "audio-vm-not-found"); + assert_eq!(not_found.exit_code(), 2); + let envelope = not_found.to_envelope(); + assert_eq!(envelope.kind, "audio-vm-not-found"); + assert_eq!(envelope.exit_code, 2); + assert!(envelope.message.contains("work")); + assert!(!envelope.remediation.is_empty()); + assert_no_path_leak("AudioVmNotFound", &envelope.message); + assert_no_path_leak("AudioVmNotFound", &envelope.remediation); + + let not_enabled = TypedError::AudioNotEnabled { + vm: "work".to_owned(), + }; + assert_eq!(not_enabled.kind(), "audio-not-enabled"); + assert_eq!(not_enabled.exit_code(), 70); + let envelope = not_enabled.to_envelope(); + assert_eq!(envelope.kind, "audio-not-enabled"); + assert_eq!(envelope.exit_code, 70); + assert!(envelope.message.contains("work")); + assert!(!envelope.remediation.is_empty()); + assert_no_path_leak("AudioNotEnabled", &envelope.message); + assert_no_path_leak("AudioNotEnabled", &envelope.remediation); + + assert_ne!(not_found.kind(), not_enabled.kind()); + assert_ne!(not_found.kind(), "internal-io"); + assert_ne!(not_enabled.kind(), "internal-io"); + } + #[test] fn sshd_host_key_drift_envelope_shape() { let err = TypedError::SshdHostKeyDrift { From 8351954a02c994ab912bfc8c833cc89db435bdd1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:13:22 -0700 Subject: [PATCH 637/726] test(d2b-contracts-broker): pin admission of the flattened unit requests RS-0547 claims serde ignores `deny_unknown_fields` on any type using `#[serde(flatten)]`, so `OpenUnitPidfdRequest` and `StopUnitRequest` accept unknown members silently. Re-verified at HEAD: the claim is inverted. Measured with the pinned serde 1.0.229 (probe kept under .scratch/): container deny + flattened deny -> unknown member refused container deny + flattened lax -> unknown member refused container lax + flattened deny -> accepted container lax + flattened lax -> accepted It is the flattened type's own `deny_unknown_fields` that serde ignores; the container's is the guard, and both requests declare it. No admission repair applies (RS-0547 skipped-stale), so this adds only the pin: the encoded request round-trips while a frame carrying one unknown member is refused, through both the Value and the streaming decoder. Gate: cargo test -p d2b-contracts-broker (50 lib + 2 wire tests, rc=0) --- .../d2b-contracts-broker/src/broker_wire.rs | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index cb6178d5a..6b28207cf 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -4219,6 +4219,83 @@ mod tests { assert_eq!(request.domain, UnitDomain::User); } + fn pidfd_test_unit() -> UnitRequest { + UnitRequest { + vm_id: VmId::new("corp-vm"), + role_id: RoleId::new("audio"), + resource_ref: None, + resource_uid: None, + role: RunnerRole::Audio, + bundle_runner_intent_ref: BundleOpId::new("runner:corp-vm:audio"), + bundle_content_identity: "sha256:bundle".to_owned(), + provider_identity: [1; 32], + template_identity: [2; 32], + generation: 3, + domain: UnitDomain::System, + execution_ref: None, + user_ref: None, + guest_execution: None, + sandbox_plan: None, + tracing_span_id: None, + } + } + + fn pidfd_test_identity() -> UnitIdentity { + UnitIdentity { + invocation_id: [3; 16], + cgroup_identity: [4; 32], + main_pid: 4242, + start_time_ticks: 987_654_321, + provider_identity: [1; 32], + template_identity: [2; 32], + generation: 3, + bundle_content_identity: "sha256:bundle".to_owned(), + guest_execution: None, + } + } + + /// Adds one member no unit request declares to an encoded request frame. + fn with_unknown_member(value: serde_json::Value) -> serde_json::Value { + let mut frame = value.as_object().expect("request frame object").clone(); + frame.insert("unknownMember".to_owned(), serde_json::json!(1)); + serde_json::Value::Object(frame) + } + + #[test] + fn flattened_unit_requests_refuse_unknown_members() { + // The container's `deny_unknown_fields` is the only guard these two + // flattened requests have: a flattened type's own + // `deny_unknown_fields` is the one serde ignores, so an unknown + // member is refused here only while the container keeps its own + // (`UnitRequest`'s is inert through the flatten). + let pidfd = OpenUnitPidfdRequest { + unit: pidfd_test_unit(), + expected: pidfd_test_identity(), + }; + let encoded = serde_json::to_value(&pidfd).expect("OpenUnitPidfdRequest encodes"); + assert_eq!( + serde_json::from_value::(encoded.clone()) + .expect("the encoded request decodes"), + pidfd + ); + serde_json::from_value::(with_unknown_member(encoded)) + .expect_err("an unknown member must be refused"); + + let stop = StopUnitRequest { + unit: pidfd_test_unit(), + expected: pidfd_test_identity(), + class: UnitStopClass::Drain, + }; + let encoded = serde_json::to_value(&stop).expect("StopUnitRequest encodes"); + assert_eq!( + serde_json::from_value::(encoded.clone()) + .expect("the encoded request decodes"), + stop + ); + serde_json::from_value::(with_unknown_member(encoded)) + .expect_err("an unknown member must be refused"); + } + #[test] fn signal_runner_response_round_trips() { // U10: the typed response is the envelope result now. From 7739ae6f546bb1883586cf485f7e9183706cf903 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:15:10 -0700 Subject: [PATCH 638/726] refactor(errors): keep the typed source in picker IPC and zone-link errors RS-0963 (non-d2bd members; the d2bd TypedError members are another slice). - d2b-provider-clipboard-wayland: PickerIpcError::Frame(String) becomes Frame(#[from] FramingError), the socket read failure becomes Read(#[source] std::io::Error), and the picker-closed-mid-frame case gets its own ClosedMidFrame variant. Every Display string is preserved byte-for-byte, so the clipd "picker frame failed: ..." diagnostic does not move. - d2b-provider-transport-azure-relay: the From and From impls for GatewayGuestZoneLinkError keep the typed cause behind CredentialUnavailable { source: ZoneLinkCredentialRefusal } and TransportUnavailable { source: RelayTransportError }. code() and Display are unchanged, so the gateway-guest-zonelink-* strings d2bd maps into TypedError::InternalConfig stay identical. Co-change: changelog.d/w6-15-error-sources-typed.md; envelope-text plus source-chain tests added in clipd_host/picker.rs and guest_zone_link.rs. No serialized shape moves, and the only consumer outside these crates (packages/d2bd/src/composition.rs:4544, which reads error.code()) is unaffected. Gates: cargo check -p d2b-provider-clipboard-wayland -p d2b-provider-transport-azure-relay --all-targets (rc=0); cargo test -p d2b-provider-transport-azure-relay -p d2b-provider-clipboard-wayland (rc=0, all suites green). --- changelog.d/w6-15-error-sources-typed.md | 14 ++ .../src/clipd_host/picker.rs | 78 +++++++---- .../src/guest_zone_link.rs | 125 +++++++++++++++--- .../src/lib.rs | 2 +- 4 files changed, 176 insertions(+), 43 deletions(-) create mode 100644 changelog.d/w6-15-error-sources-typed.md diff --git a/changelog.d/w6-15-error-sources-typed.md b/changelog.d/w6-15-error-sources-typed.md new file mode 100644 index 000000000..43b13e84d --- /dev/null +++ b/changelog.d/w6-15-error-sources-typed.md @@ -0,0 +1,14 @@ +### Changed + +- `d2b-provider-clipboard-wayland`: the picker IPC error keeps the typed + failure behind its frame variants (`Frame(FramingError)`, + `Read(io::Error)`) and splits the picker-closed-mid-frame case into its own + variant, instead of flattening every frame failure into a `String`. The + diagnostic text (`picker frame error: ...`) and the source chain are both + preserved. +- `d2b-provider-transport-azure-relay`: `GatewayGuestZoneLinkError` keeps the + typed cause behind `CredentialUnavailable` (the sealed credential or scoped + credential request failure, carried as `ZoneLinkCredentialRefusal`) and + `TransportUnavailable` (the relay transport failure) instead of discarding + it in the `From` impls. The stable `code()` strings and `Display` output are + unchanged, so no error envelope moves. diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs index 3a593ac67..94c9d4d21 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs @@ -113,7 +113,7 @@ pub trait PickerSpawner { fn spawn(&mut self, launch: PickerLaunch) -> Result; } -#[derive(Debug, Error, PartialEq, Eq)] +#[derive(Debug, Error)] pub enum PickerIpcError { #[error("picker is not configured")] NotConfigured, @@ -125,8 +125,16 @@ pub enum PickerIpcError { Spawn(String), #[error("picker fd flag update failed: {0}")] FdFlags(String), + /// The picker socket read failed; the io error stays the source. #[error("picker frame error: {0}")] - Frame(String), + Read(#[source] std::io::Error), + /// Frame decoding refused the picker's bytes; the framing class stays + /// the source instead of collapsing into its Display text. + #[error("picker frame error: {0}")] + Frame(#[from] FramingError), + /// The picker closed its socket with a partial frame buffered. + #[error("picker frame error: picker closed with incomplete frame")] + ClosedMidFrame, } #[derive(Debug, Clone, PartialEq)] @@ -265,36 +273,28 @@ impl PickerSupervisor { match active.parent_socket.read(&mut buf) { Ok(0) if active.read_buffer.is_empty() => return Ok(PickerPoll::Closed), Ok(0) => { - return Err(PickerIpcError::Frame( - "picker closed with incomplete frame".to_owned(), - )); + return Err(PickerIpcError::ClosedMidFrame); } Ok(n) => { active.read_buffer.extend_from_slice(&buf[..n]); if let Some(newline) = active.read_buffer.iter().position(|byte| *byte == b'\n') { if newline > max_frame_bytes { - return Err(PickerIpcError::Frame( - FramingError::FrameTooLong { - max: max_frame_bytes, - } - .to_string(), - )); + return Err(PickerIpcError::Frame(FramingError::FrameTooLong { + max: max_frame_bytes, + })); } break; } if active.read_buffer.len() > max_frame_bytes { - return Err(PickerIpcError::Frame( - FramingError::FrameTooLong { - max: max_frame_bytes, - } - .to_string(), - )); + return Err(PickerIpcError::Frame(FramingError::FrameTooLong { + max: max_frame_bytes, + })); } } Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => break, Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue, - Err(error) => return Err(PickerIpcError::Frame(error.to_string())), + Err(error) => return Err(PickerIpcError::Read(error)), } } @@ -320,16 +320,12 @@ impl PickerSupervisor { return Ok(PickerPoll::Incomplete); }; if newline > max_frame_bytes { - return Err(PickerIpcError::Frame( - FramingError::FrameTooLong { - max: max_frame_bytes, - } - .to_string(), - )); + return Err(PickerIpcError::Frame(FramingError::FrameTooLong { + max: max_frame_bytes, + })); } let frame = active.read_buffer.drain(..=newline).collect::>(); - let message = decode_frame::(&frame, max_frame_bytes) - .map_err(|err| PickerIpcError::Frame(err.to_string()))?; + let message = decode_frame::(&frame, max_frame_bytes)?; Ok(PickerPoll::Message(message)) } @@ -689,4 +685,34 @@ mod tests { PickerPoll::Message(PickerToDaemonMessage::Cancel(_)) )); } + + #[test] + fn frame_failures_keep_the_diagnostic_text_and_the_typed_source() { + let too_long = PickerIpcError::Frame(FramingError::FrameTooLong { max: 4096 }); + assert_eq!( + too_long.to_string(), + "picker frame error: ndjson frame exceeds 4096 bytes" + ); + assert_eq!( + std::error::Error::source(&too_long).map(ToString::to_string), + Some("ndjson frame exceeds 4096 bytes".to_owned()) + ); + + let closed = PickerIpcError::ClosedMidFrame; + assert_eq!( + closed.to_string(), + "picker frame error: picker closed with incomplete frame" + ); + assert!(std::error::Error::source(&closed).is_none()); + + let read = PickerIpcError::Read(std::io::Error::other("picker socket read failed")); + assert_eq!( + read.to_string(), + "picker frame error: picker socket read failed" + ); + assert_eq!( + std::error::Error::source(&read).map(ToString::to_string), + Some("picker socket read failed".to_owned()) + ); + } } diff --git a/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs b/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs index 1fc144b10..b98a487f5 100644 --- a/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs +++ b/packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs @@ -31,28 +31,65 @@ fn system_now_unix() -> u64 { } /// Closed failures while composing the Gateway Guest ZoneLink transport. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum GatewayGuestZoneLinkError { /// The execution or egress Network reference has the wrong ResourceType. InvalidPlacement, - /// The Guest-local sealed credential or sealing key could not be opened. - CredentialUnavailable, + /// The Guest-local sealed credential or the scoped credential request + /// could not be admitted. + CredentialUnavailable { + /// Typed origin of the credential refusal. + source: ZoneLinkCredentialRefusal, + }, /// The selected Relay Provider rejected its non-secret configuration. TransportConfiguration, /// The Relay carriage or its enrollment proof was refused. - TransportUnavailable, + TransportUnavailable { + /// Typed origin of the transport refusal. + source: RelayTransportError, + }, /// The non-secret Guest-local open observation could not be persisted. ObservationUnavailable, } +/// Typed origin of a [`GatewayGuestZoneLinkError::CredentialUnavailable`] +/// refusal: the sealed bootstrap credential or the scoped credential request. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ZoneLinkCredentialRefusal { + /// The Guest-local sealed credential or sealing key could not be opened or + /// validated. + Sealed(CredentialError), + /// The scoped credential request failed its same-Zone scope, binding, or + /// deadline validation. + Scoped(RelayCredentialError), +} + +impl std::fmt::Display for ZoneLinkCredentialRefusal { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Sealed(error) => write!(formatter, "{error}"), + Self::Scoped(error) => write!(formatter, "{error}"), + } + } +} + +impl std::error::Error for ZoneLinkCredentialRefusal { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Sealed(error) => Some(error), + Self::Scoped(error) => Some(error), + } + } +} + impl GatewayGuestZoneLinkError { /// Return the stable path-free error code. - pub const fn code(self) -> &'static str { + pub const fn code(&self) -> &'static str { match self { Self::InvalidPlacement => "gateway-guest-zonelink-placement-invalid", - Self::CredentialUnavailable => "gateway-guest-zonelink-credential-unavailable", + Self::CredentialUnavailable { .. } => "gateway-guest-zonelink-credential-unavailable", Self::TransportConfiguration => "gateway-guest-zonelink-transport-invalid", - Self::TransportUnavailable => "gateway-guest-zonelink-transport-unavailable", + Self::TransportUnavailable { .. } => "gateway-guest-zonelink-transport-unavailable", Self::ObservationUnavailable => "gateway-guest-zonelink-observation-unavailable", } } @@ -64,17 +101,29 @@ impl std::fmt::Display for GatewayGuestZoneLinkError { } } -impl std::error::Error for GatewayGuestZoneLinkError {} +impl std::error::Error for GatewayGuestZoneLinkError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::CredentialUnavailable { source } => Some(source), + Self::TransportUnavailable { source } => Some(source), + Self::InvalidPlacement + | Self::TransportConfiguration + | Self::ObservationUnavailable => None, + } + } +} impl From for GatewayGuestZoneLinkError { - fn from(_: CredentialError) -> Self { - Self::CredentialUnavailable + fn from(error: CredentialError) -> Self { + Self::CredentialUnavailable { + source: ZoneLinkCredentialRefusal::Sealed(error), + } } } impl From for GatewayGuestZoneLinkError { - fn from(_: RelayTransportError) -> Self { - Self::TransportUnavailable + fn from(error: RelayTransportError) -> Self { + Self::TransportUnavailable { source: error } } } @@ -319,14 +368,16 @@ impl GatewayGuestZoneLinkRuntime { binding, deadline_ms, ) - .map_err(|_| { + .map_err(|error| { tracing::warn!( provider = "transport-azure-relay", role = ?role, credential = %credential_for_log, "zone link rejected: scoped credential request invalid" ); - GatewayGuestZoneLinkError::CredentialUnavailable + GatewayGuestZoneLinkError::CredentialUnavailable { + source: ZoneLinkCredentialRefusal::Scoped(error), + } })?; let connection = self .provider @@ -346,13 +397,13 @@ impl GatewayGuestZoneLinkRuntime { transcript, &connection.enrollment_challenge(), ) - .map_err(|_| { + .map_err(|error| { tracing::warn!( provider = "transport-azure-relay", role = ?role, "zone link enrollment refused: enrollment proof rejected" ); - GatewayGuestZoneLinkError::TransportUnavailable + GatewayGuestZoneLinkError::TransportUnavailable { source: error } })?; connection .enroll(proof) @@ -587,4 +638,46 @@ mod tests { assert!(invalid.is_err()); assert!(!invalid_marker.exists()); } + + #[test] + fn zone_link_refusals_keep_the_code_text_and_the_typed_source() { + let dir = tempfile::tempdir().expect("temporary Guest state"); + let error = GatewayGuestZoneLinkRuntime::from_sealed( + dir.path().join("missing.sealed.json"), + dir.path().join("missing.key"), + &CredentialFilePolicy::default(), + GatewayGuestZoneLinkTransportConfig { + execution_ref: ResourceRef::parse("Guest/gateway").expect("Guest ref"), + network_ref: ResourceRef::parse("Network/relay-egress").expect("Network ref"), + settings: RelayTransportSettings::new("relns-d2b-prod", "hc-d2b") + .expect("Relay settings"), + max_concurrent_sessions: 32, + connect_timeout_seconds: 30, + }, + ) + .expect_err("missing sealed credential"); + assert_eq!( + error.code(), + "gateway-guest-zonelink-credential-unavailable" + ); + assert_eq!(error.to_string(), error.code()); + let refusal = std::error::Error::source(&error).expect("typed credential refusal"); + assert_eq!(refusal.to_string(), "gateway credential cannot be read"); + assert!(refusal.source().is_some(), "sealed credential cause"); + + let transport = GatewayGuestZoneLinkError::from(RelayTransportError::Protocol); + assert_eq!( + transport.code(), + "gateway-guest-zonelink-transport-unavailable" + ); + assert_eq!(transport.to_string(), transport.code()); + assert_eq!( + std::error::Error::source(&transport).map(ToString::to_string), + Some("relay-protocol".to_owned()) + ); + assert_eq!( + ZoneLinkCredentialRefusal::Scoped(RelayCredentialError::InvalidScope).to_string(), + RelayCredentialError::InvalidScope.to_string() + ); + } } diff --git a/packages/d2b-provider-transport-azure-relay/src/lib.rs b/packages/d2b-provider-transport-azure-relay/src/lib.rs index 1df9825eb..0cc64942d 100644 --- a/packages/d2b-provider-transport-azure-relay/src/lib.rs +++ b/packages/d2b-provider-transport-azure-relay/src/lib.rs @@ -25,7 +25,7 @@ pub use guest_credential::{ }; pub use guest_zone_link::{ GatewayGuestZoneLinkError, GatewayGuestZoneLinkRuntime, - GatewayGuestZoneLinkTransportConfig, RelayCarriageRequest, + GatewayGuestZoneLinkTransportConfig, RelayCarriageRequest, ZoneLinkCredentialRefusal, }; pub use relay_transport::{ AzureRelaySocketConnector, AzureRelayTransportProvider, MAX_RELAY_CA_BYTES, From dba2d00f2f79dd053480065bad12de2d69b45c6f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:18:59 -0700 Subject: [PATCH 639/726] refactor(d2bd): report audio mutation refusals through the typed audio kinds RS-0537 (+ RS-0963 d2bd member): dispatch_audio_set_volume and dispatch_audio_mute refuse a target that is absent from the public manifest through TypedError::AudioVmNotFound (kind audio-vm-not-found, exit 2) and a target without audio in its manifest entry through TypedError::AudioNotEnabled (kind audio-not-enabled, exit 70), instead of flattening both classes into TypedError::InternalIo { context, detail } strings. The status path already reports the same classes per VM as AudioErrorKind::VmNotFound / AudioNotEnabled, so a mutation caller no longer has to string-match the detail to tell a user-input refusal from an internal I/O failure. Lock, read, write, and host enforcement failures keep their internal-io classification and their log-only detail. Co-change list: - packages/d2bd-runtime/src/typed_error.rs - the two leaf variants, their kind slugs, exit codes, envelope message/remediation, warning log lines, hello-rejection arm, and the envelope tests (previous commit of this slice). - packages/d2bd/src/audio_dispatch.rs - the four mutation-site constructors (set-volume and mute, VM absent / audio not enabled) and the dispatch_audio doc comment. - docs/reference/error-codes.md - hand-written rows for the two new daemon wire kinds; the generated error-table block is untouched, so gen_error_codes_drift stays the proof that no documented code moved. - changelog.d/w6-13-d2bd-structured-error-kinds.md - this slice's fragment. Emitted bytes: no documented code, anchor, or exit code in docs/reference/error-codes.md moves. The two new envelope kinds are new wire surface for the public daemon Audio request; the in-tree CLI reads the envelope kind as an opaque string (d2b:packages/d2b/src/context.rs:337), so no in-tree consumer branches on the old internal-io slug for these paths. Outside-tree observer: a public-socket client that matched internal-io on an unknown or audio-less VM sees the new kinds - the needs-contract move the wave-6 slate signed for RS-0537. gate: cargo test -p d2bd; cargo check -p d2bd --all-targets --- .../w6-13-d2bd-structured-error-kinds.md | 22 +++++++++++++ docs/reference/error-codes.md | 12 +++++++ packages/d2bd/src/audio_dispatch.rs | 31 ++++++++++--------- 3 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 changelog.d/w6-13-d2bd-structured-error-kinds.md diff --git a/changelog.d/w6-13-d2bd-structured-error-kinds.md b/changelog.d/w6-13-d2bd-structured-error-kinds.md new file mode 100644 index 000000000..d3447dd9e --- /dev/null +++ b/changelog.d/w6-13-d2bd-structured-error-kinds.md @@ -0,0 +1,22 @@ +### Changed + +- `d2bd` audio mutations (RS-0537): a `setVolume` / `mute` request that names a + VM absent from the public manifest, or a VM whose manifest entry does not + declare audio, is refused with the structured + `TypedError::AudioVmNotFound` (`kind` `audio-vm-not-found`, exit `2`) and + `TypedError::AudioNotEnabled` (`kind` `audio-not-enabled`, exit `70`) instead + of a flattened `TypedError::InternalIo { context, detail }`. The audio status + path already reported the same per-VM classes through `AudioErrorKind`, so a + mutation caller now tells a user-input refusal from an internal I/O failure + by `kind`/exit code instead of by string-matching the message text. The rows + documented in `docs/reference/error-codes.md` do not move; the two new daemon + wire kinds are documented there. + +### Fixed + +- `d2bd` `TypedError` (RS-0963): the audio mutation refusals no longer collapse + their failure class into a `String` detail on the `internal-io` variant - + the class travels as a typed variant, the way the status path carries + `AudioErrorKind`. Lock, read, write, and host-enforcement failures keep their + `internal-io` classification and their log-only detail, and the + `internal-io` envelope text is unchanged. diff --git a/docs/reference/error-codes.md b/docs/reference/error-codes.md index 7a30ef7d1..da7d40e3a 100644 --- a/docs/reference/error-codes.md +++ b/docs/reference/error-codes.md @@ -118,6 +118,18 @@ metadata, paths, environment, or cwd. | `unsafe-local-shell-stale-session` | `77` | Reattach to obtain a fresh opaque public handle. | | `unsafe-local-shell-internal` | `42` | Retry, then inspect the bounded daemon lifecycle event if it persists. | +### Audio mutation refusals + +The public daemon `Audio` request's mutation ops (`setVolume`, `mute`) refuse a +target before touching audio state, reporting the same per-VM classes the audio +*status* path reports through `AudioVmError`. These rows are daemon wire kinds, +not part of the generated CLI catalog above. + +| docs anchor / kind | exit | Meaning and remediation | +| --- | --- | --- | +| `audio-vm-not-found` | `2` | The requested VM is not declared in the public manifest. Verify the VM is declared in the d2b configuration and the bundle is up to date, then retry. | +| `audio-not-enabled` | `70` | The VM exists but its manifest entry does not declare audio. Enable `d2b.vms..audio.enable`, rebuild the bundle, and retry. | + ## CLI host-verb refusal envelope The CLI host verbs (`d2b host prepare`, `host destroy`, diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index 5980d4904..613e0d89c 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -374,9 +374,14 @@ pub(crate) fn combined_audio_applied( /// /// Status collects a per-VM result (entries and per-VM errors) from /// the provider's state; SetVolume and Mute apply a state transition under - /// the audio serialization lock, and return [`TypedError::InternalIo`] - /// for manifest, capability, lock, read, write, or enforcement - /// failures. + /// the audio serialization lock. + /// + /// A mutation refuses a target that is not declared in the public manifest + /// through [`TypedError::AudioVmNotFound`], and a target whose manifest + /// entry does not declare audio through [`TypedError::AudioNotEnabled`] - + /// the same classes the status path reports per VM through `AudioVmError` + /// (RS-0537). Lock, read, write, and enforcement failures keep returning + /// [`TypedError::InternalIo`]. pub fn dispatch_audio( state: &ServerState, caller_role: BrokerCallerRole, @@ -495,14 +500,12 @@ fn dispatch_audio_set_volume( let vm = manifest .vms .get(vm_name) - .ok_or_else(|| TypedError::InternalIo { - context: format!("audio set-volume {vm_name}"), - detail: "VM not present in public manifest".to_owned(), + .ok_or_else(|| TypedError::AudioVmNotFound { + vm: vm_name.clone(), })?; - let cap = audio_capability_for_vm(vm).ok_or_else(|| TypedError::InternalIo { - context: format!("audio set-volume {vm_name}"), - detail: "audio not enabled for this VM".to_owned(), + let cap = audio_capability_for_vm(vm).ok_or_else(|| TypedError::AudioNotEnabled { + vm: vm_name.clone(), })?; let state_dir = std::path::PathBuf::from(&vm.state_dir); @@ -602,14 +605,12 @@ fn dispatch_audio_mute( let vm = manifest .vms .get(vm_name) - .ok_or_else(|| TypedError::InternalIo { - context: format!("audio mute {vm_name}"), - detail: "VM not present in public manifest".to_owned(), + .ok_or_else(|| TypedError::AudioVmNotFound { + vm: vm_name.clone(), })?; - let cap = audio_capability_for_vm(vm).ok_or_else(|| TypedError::InternalIo { - context: format!("audio mute {vm_name}"), - detail: "audio not enabled for this VM".to_owned(), + let cap = audio_capability_for_vm(vm).ok_or_else(|| TypedError::AudioNotEnabled { + vm: vm_name.clone(), })?; let state_dir = std::path::PathBuf::from(&vm.state_dir); From ab90777dee9d306eb817b97907e6a04ddebc6e61 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:22:19 -0700 Subject: [PATCH 640/726] fix(d2bd): enforce the Host posture refusal at operator status admission RS-0413: `HostReconciler::reject_operator_status_fields` is the documented enforcement half of the ADR-046 no-suppression obligation for the user-only Host posture, and the census at 94c8fcdd2 found it with zero callers outside packages/d2b-provider-system-core/tests (4 hits: the definition plus three test call sites), so the rule was test-only. Wire it into the daemon's operator status admission: `public_update_status_request`, the public dispatch's `UpdateStatus` arm, refuses an operator-submitted `Host` status naming `isolationPosture` or `isolationPostureMessage` - either request spelling, `status` or the nested `resource.status`, and the explicit `null` form included - before the row is read. The provider-session dispatch keeps its own admission: the reconciler's publication is the one submission that legitimately derives those fields. The row's alternative ("document the structural exclusion") was not taken: the exclusion exists at the storage layer (R11/AE6: no durable status write path), which refuses every status write for a different reason and cannot name the Host field rule. This is that rule's only enforcement path. Co-change: d2bd-runtime gains the typed refusal `ResourceRuntimeError::HostStatusFieldNotOwned` (`resource-runtime-host-status-field-not-owned`) with its operator-facing error frame; the d2b-provider-system-core host module doc (the row's second anchor, host.rs:13) names the caller that now enforces it; the admission test `an_operator_status_naming_a_host_reconciler_owned_field_is_refused` pins the refusal, both spellings, the admitted form, the no-status case and the Host-only scope. Consumer census of `reject_operator_status_fields` after the change: packages/d2bd/src/resource_runtime.rs:10053 (the operator admission), whose only caller is packages/d2bd/src/resource_runtime.rs:10018 in `public_update_status_request`, reached from the public dispatch at packages/d2bd/src/resource_runtime.rs:8324. No serialized shape moves: the request and response wire bytes are unchanged, the refusal is a daemon error code, and no consumer outside this tree observes it. Gate: cargo check -p d2bd --all-targets (rc 0); cargo test -p d2bd status; cargo test -p d2b-provider-system-core; cargo check -p d2b-provider-system-core --all-targets. --- .../w6-14-status-admission-enforcement.md | 11 ++ packages/d2b-provider-system-core/src/host.rs | 8 +- packages/d2bd-runtime/src/resource_api.rs | 15 +++ packages/d2bd/src/resource_runtime.rs | 103 ++++++++++++++++++ 4 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 changelog.d/w6-14-status-admission-enforcement.md diff --git a/changelog.d/w6-14-status-admission-enforcement.md b/changelog.d/w6-14-status-admission-enforcement.md new file mode 100644 index 000000000..8ad0e00a5 --- /dev/null +++ b/changelog.d/w6-14-status-admission-enforcement.md @@ -0,0 +1,11 @@ +### Fixed + +- The daemon's operator status admission now refuses a submitted `Host` + status that names `isolationPosture` or `isolationPostureMessage`. + `HostReconciler::reject_operator_status_fields` was the documented + enforcement half of the `ADR-046-telemetry-audit-and-support` no-suppression + obligation ("operators can neither suppress nor override the user-only Host + posture") but had no caller outside its own crate's tests, so a submission + naming either field reached the layers below un-remarked. The refusal is + typed (`resource-runtime-host-status-field-not-owned`) and covers the + explicit `null` form, which is as much a suppression attempt as `"none"`. diff --git a/packages/d2b-provider-system-core/src/host.rs b/packages/d2b-provider-system-core/src/host.rs index dd1f84a95..0558b1e16 100644 --- a/packages/d2b-provider-system-core/src/host.rs +++ b/packages/d2b-provider-system-core/src/host.rs @@ -12,9 +12,11 @@ //! requires that an operator can neither suppress nor override them. That //! is two obligations, and both are met here: the posture is derived only //! from the spec, and a submitted status carrying either field is rejected -//! rather than merged. A Host with any other execution policy carries no -//! posture at all, which is why the field is optional rather than defaulted -//! to a "has isolation" value. +//! rather than merged, by [`HostReconciler::reject_operator_status_fields`] - +//! which the daemon's operator status admission calls before it reads the +//! row. A Host with any other execution policy carries no posture at all, +//! which is why the field is optional rather than defaulted to a "has +//! isolation" value. //! //! Adapted from the unsafe-local workload contract that this Host resource //! succeeds (`packages/d2b-core/src/unsafe_local_workloads.rs` and the diff --git a/packages/d2bd-runtime/src/resource_api.rs b/packages/d2bd-runtime/src/resource_api.rs index de396dc4a..25a44452f 100644 --- a/packages/d2bd-runtime/src/resource_api.rs +++ b/packages/d2bd-runtime/src/resource_api.rs @@ -67,6 +67,14 @@ pub enum ResourceRuntimeError { /// The public Resource API refused a provider status update with a typed /// error. ResourceStatusUpdateFailed(ResourceErrorKind), + /// A caller submitted a Host status naming a reconciler-owned field. + /// + /// `ADR-046-telemetry-audit-and-support`, section "Host resource + /// status": the user-only Host posture is set by the system-core + /// reconciler and an operator can neither suppress nor override it, so a + /// submitted status naming `isolationPosture` or + /// `isolationPostureMessage` is refused before it is admitted. + HostStatusFieldNotOwned, /// The Wave 6 operator acceptance boundary did not converge. Wave6AcceptanceFailed, } @@ -107,6 +115,7 @@ impl ResourceRuntimeError { Self::CapabilityUnavailable => "resource-runtime-capability-unavailable", Self::ResourceGetFailed(_) => "resource-runtime-resource-get-failed", Self::ResourceStatusUpdateFailed(_) => "resource-runtime-resource-status-update-failed", + Self::HostStatusFieldNotOwned => "resource-runtime-host-status-field-not-owned", Self::Wave6AcceptanceFailed => "resource-runtime-wave6-acceptance-failed", } } @@ -148,6 +157,12 @@ pub fn resource_runtime_error_frame(error: ResourceRuntimeError) -> Value { "the requested resource operation is not registered", "use a method exposed by the registered Zone service", ), + ResourceRuntimeError::HostStatusFieldNotOwned => ( + code, + "never", + "the submitted Host status names a field only the system-core reconciler may set", + "drop isolationPosture and isolationPostureMessage from the submitted status; the reconciler derives both from the Host spec", + ), ResourceRuntimeError::ResourceGetFailed(kind) => ( kind.as_str(), match kind { diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 7ee829dae..371f7ee7e 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -39,6 +39,7 @@ use d2b_contracts_resource::v3::{ PlacementTargetKind, ResourceBundleGenerationId, ResourceEnvelope, ResourceGeneration, ResourceErrorKind, ResourcePhase, ResourceRef, ResourceTypeName, ResourceUid, StateDigest, ZoneId, ZoneRevision, + host::HOST_RESOURCE_TYPE, process::ProcessSpec, volume::VolumeSpec, }; @@ -63,6 +64,7 @@ use d2b_core_controller::migration::LegacyTpmMigrationDecision; use d2b_provider_zone::{ SystemCoreStatusEmitter, ZoneRuntimeMetadata, ZoneStatusInput, }; +use d2b_provider_system_core::HostReconciler; use d2b_provider_clipboard_wayland::Policy as ClipboardPolicy; use d2b_provider_credential::{ AgentReadyFuture, CredentialDependencyFacts, CredentialLeaseFacts, @@ -10008,10 +10010,56 @@ where S: d2b_resource_api::ResourceStoreBackend, { let target = public_target_ref(request)?; + // The operator path is the one whose submission can suppress or override + // a reconciler-owned field, and it is refused here, before the row is + // read. The provider-session dispatch below keeps its own admission: the + // reconciler's own publication is the one status that legitimately + // carries the posture fields it derived from the spec. + admit_operator_status_fields(&target, request)?; let current = public_get_resource(client, runtime, &target, operation_id).await?; public_update_status_request_from_current(runtime, request, operation_id, &target, current) } +/// Refuse an operator-submitted status that names a reconciler-owned field. +/// +/// R11/AE6 leaves the public Resource API no status write path, so the +/// daemon's operator admission is the last layer that sees a submission: both +/// spellings a request may use (`status`, or the nested +/// `resource.status`) are read here, and this is the enforcement point for +/// `ADR-046-telemetry-audit-and-support`, section "Host resource status". The +/// `system-core` reconciler sets `isolationPosture` and +/// `isolationPostureMessage` on every user-only Host from the spec alone, and +/// an operator can neither suppress nor override them: a submitted Host +/// status naming either field is refused outright, whatever its value would +/// have been - an explicit `null` is as much a suppression attempt as +/// `"none"` is - and the refusal names the rule, never the submitted value. +/// A request that submits no status at all is not this rule's case; it is +/// refused, unchanged, where the status is read. +fn admit_operator_status_fields( + target: &ResourceRef, + request: &Value, +) -> Result<(), ResourceRuntimeError> { + if target.resource_type().as_str() != HOST_RESOURCE_TYPE { + return Ok(()); + } + let status = request.get("status").or_else(|| { + request + .get("resource") + .and_then(|value| value.get("status")) + }); + let Some(status) = status else { + return Ok(()); + }; + HostReconciler::reject_operator_status_fields(status).map_err(|error| { + tracing::warn!( + resource = %target.to_canonical_string(), + error = %error, + "status submission refused: reconciler-owned Host status field", + ); + ResourceRuntimeError::HostStatusFieldNotOwned + }) +} + fn public_update_status_request_from_current( runtime: &ZoneResourceRuntime, request: &Value, @@ -11848,6 +11896,61 @@ mod tests { assert!(!row_status_failure_is_retryable(&ready)); } + /// `ADR-046-telemetry-audit-and-support`, section "Host resource status": + /// the `system-core` reconciler owns the user-only Host posture, so the + /// daemon refuses an operator-submitted Host status naming either posture + /// field before the row is even read - an explicit `null` included, since + /// it is as much a suppression attempt as `"none"` is. + #[test] + fn an_operator_status_naming_a_host_reconciler_owned_field_is_refused() { + let host = ResourceRef::parse("Host/host-system").expect("Host ref"); + for suppressed in [ + json!({"phase": "Ready", "isolationPosture": "none"}), + json!({"phase": "Ready", "isolationPosture": null}), + json!({"isolationPostureMessage": "this host is safe"}), + ] { + let request = json!({"resourceRef": "Host/host-system", "status": suppressed}); + assert_eq!( + admit_operator_status_fields(&host, &request), + Err(ResourceRuntimeError::HostStatusFieldNotOwned), + "a submitted Host status must not name a reconciler-owned field: {suppressed}", + ); + // The nested spelling carries the same status. + let nested = json!({ + "resourceRef": "Host/host-system", + "resource": {"status": suppressed}, + }); + assert_eq!( + admit_operator_status_fields(&host, &nested), + Err(ResourceRuntimeError::HostStatusFieldNotOwned), + "the nested spelling of the same submission is the same status", + ); + } + assert_eq!( + admit_operator_status_fields( + &host, + &json!({"resourceRef": "Host/host-system", "status": {"phase": "Ready"}}), + ), + Ok(()), + "a Host status naming no reconciler-owned field is not this rule's to refuse", + ); + assert_eq!( + admit_operator_status_fields(&host, &json!({"resourceRef": "Host/host-system"})), + Ok(()), + "a request that submits no status stays with the status read", + ); + // The rule is scoped to Host rows: another type's status is left to + // the layers below, which admit no status write at all (R11/AE6). + let zone = ResourceRef::parse("Zone/dev").expect("Zone ref"); + assert_eq!( + admit_operator_status_fields( + &zone, + &json!({"resourceRef": "Zone/dev", "status": {"isolationPosture": "none"}}), + ), + Ok(()), + ); + } + /// U12: the provider controller's custody gate. A manager-served Guest /// row carries no authored finalizer (the daemon's ensure/clear requests /// are idempotent no-ops on the converted plane; the manager's From 3c3454697c9273d3324fca320a03b5d700e2c35c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:25:42 -0700 Subject: [PATCH 641/726] refactor(d2b-contracts-broker): take the test-only peer uid off the envelope RS-0328. `BrokerRequestEnvelope.test_peer_uid` was a test-only peer-uid override carried on the production wire envelope: serialized (as `"testPeerUid": null`), schema-visible, and honored only under the broker's `config.test_mode` gate. The override now travels as a member of the frame beside the envelope. The broker's harness wraps a frame with `runtime::test_peer_uid_frame` (the bootstrap probe CLI does so for `--test-uid`), and only a broker started with `--test-mode` unwraps it - `runtime::take_test_peer_uid` - in front of the strict typed decode; every other broker refuses the member. The kernel `SO_PEERCRED` uid stays the audited frame source and the override only feeds the gates (`effective_uid`), so audit rows keep their caller uid. Co-change list: - producer/emitter: d2bd-runtime/src/broker_transport.rs; d2bd/src/composition.rs (one typed construction, one test construction, and the two raw `json!` envelopes); d2b-contracts-broker/src/kernel_client.rs; d2b-broker/src/bootstrap.rs (the bootstrap envelope loses the field and the probe builders lose the uid argument). - consumer: d2b-broker/src/runtime.rs - both decode paths (the layer1-bootstrap envelope as well), `answer_request` now takes the override-applied uid beside the kernel one. - tests: packages/d2b-broker/tests/{profile_separation,guest_profile, socket_activation,broker_protocol_compatibility}.rs, the runtime and probe unit tests, and a new contract-crate test pinning that the production envelope refuses `testPeerUid`. - schema/docs: no generated artifact moves - `WireProtocolSchema` renders `BrokerRequest`/`BrokerResponse`, not the envelope, and no committed schema carries the member (checked before and after). - gates: tests/unit/gates/{broker-seam-pilot,performance-budgets}.sh keep sending `testPeerUid` and keep passing unchanged: both start the broker with `--test-mode`, which is exactly the unwrap path. External consumers: none. The broker socket is a private, root/d2bd-only seqpacket socket, every producer and consumer of this envelope is in this tree, and the only wire difference is the retired null member. Gates: cargo check -p d2b-contracts-broker -p d2b-broker -p d2bd-runtime -p d2bd --all-targets (rc=0); cargo test -p d2b-contracts-broker (rc=0). --- changelog.d/w6-12-broker-wire-admission.md | 26 +++ packages/d2b-broker/src/bootstrap.rs | 14 +- packages/d2b-broker/src/runtime.rs | 149 +++++++++++++++--- .../tests/broker_protocol_compatibility.rs | 1 - packages/d2b-broker/tests/guest_profile.rs | 7 +- .../d2b-broker/tests/profile_separation.rs | 37 +++-- .../d2b-broker/tests/socket_activation.rs | 1 - .../d2b-contracts-broker/src/broker_wire.rs | 40 ++++- .../d2b-contracts-broker/src/kernel_client.rs | 1 - packages/d2bd-runtime/src/broker_transport.rs | 1 - packages/d2bd/src/composition.rs | 4 - 11 files changed, 213 insertions(+), 68 deletions(-) create mode 100644 changelog.d/w6-12-broker-wire-admission.md diff --git a/changelog.d/w6-12-broker-wire-admission.md b/changelog.d/w6-12-broker-wire-admission.md new file mode 100644 index 000000000..f7e4ff79e --- /dev/null +++ b/changelog.d/w6-12-broker-wire-admission.md @@ -0,0 +1,26 @@ +### Changed + +- `BrokerRequestEnvelope` no longer carries the test-only `test_peer_uid` + member. The broker's harness - the bootstrap probe CLI and the integration + tests - now sends that override as a `testPeerUid` member beside the + envelope, and only a `--test-mode` broker unwraps it in front of its strict + decode, so the wire contract carries no test seam and every other broker + refuses a frame that carries one. Production frames stop emitting the + `"testPeerUid": null` member; the broker socket is private to this tree, so + no consumer outside it observes the shape. +- `AuditExportEntry` now carries exactly one payload, + `AuditExportEntryPayload::Record { record }` or `::Error { error }`, instead + of the independent `record` / `error` optional pair, so an entry that + carries neither or both is unrepresentable and refused at decode. The + emitted members are unchanged - `sequence` plus exactly one of `record` / + `error` - so the broker audit page and the public daemon audit page keep + their JSON, and the `legacy_export_entry_line` renderer keeps its output. + +### Added + +- `d2b_broker::runtime::{TEST_PEER_UID_FIELD, test_peer_uid_frame}` name the + harness-only peer-uid override for the probe CLI and the integration tests. +- An admission test pinning that `OpenUnitPidfdRequest` and `StopUnitRequest` + refuse an unknown member. Re-verifying the audited flatten defect showed the + container's `deny_unknown_fields` is the guard that refuses it, so no + admission repair applies and the observed contract is pinned instead. diff --git a/packages/d2b-broker/src/bootstrap.rs b/packages/d2b-broker/src/bootstrap.rs index 69cd2cfb0..8872a919b 100644 --- a/packages/d2b-broker/src/bootstrap.rs +++ b/packages/d2b-broker/src/bootstrap.rs @@ -9,8 +9,6 @@ pub mod wire { pub request: BrokerRequest, #[serde(default)] pub caller_role: CallerRole, - #[serde(default)] - pub test_peer_uid: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -246,18 +244,17 @@ pub mod wire { } } - pub fn probe_hello(test_peer_uid: Option) -> RequestEnvelope { + pub fn probe_hello() -> RequestEnvelope { RequestEnvelope { request: BrokerRequest::Hello { client_version: "0.0.0-test".to_owned(), supported_features: vec!["layer1-bootstrap".to_owned()], }, caller_role: CallerRole::NotAuthorized, - test_peer_uid, } } - pub fn probe_stub(operation: &str, test_peer_uid: Option) -> Option { + pub fn probe_stub(operation: &str) -> Option { let request = match operation { "ApplyNftables" => BrokerRequest::ApplyNftables { opaque_target_id: None, @@ -357,21 +354,16 @@ pub mod wire { Some(RequestEnvelope { request, caller_role: CallerRole::NotAuthorized, - test_peer_uid, }) } - pub fn probe_export_audit( - test_peer_uid: Option, - caller_role: CallerRole, - ) -> RequestEnvelope { + pub fn probe_export_audit(caller_role: CallerRole) -> RequestEnvelope { RequestEnvelope { request: BrokerRequest::ExportBrokerAudit { since: None, filter: None, }, caller_role, - test_peer_uid, } } diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 500666408..e798e15cc 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -832,7 +832,7 @@ pub fn run(command: BrokerMode) -> Result<(), RunError> { test_uid, } => run_probe( socket_path, - crate::bootstrap::wire::probe_hello(test_uid), + test_peer_uid_frame(crate::bootstrap::wire::probe_hello(), test_uid), true, ), #[cfg(feature = "layer1-bootstrap")] @@ -841,9 +841,9 @@ pub fn run(command: BrokerMode) -> Result<(), RunError> { test_uid, operation, } => { - let request = crate::bootstrap::wire::probe_stub(&operation, test_uid) + let request = crate::bootstrap::wire::probe_stub(&operation) .ok_or_else(|| RunError::Usage(format!("unknown stub operation: {operation}")))?; - run_probe(socket_path, request, true) + run_probe(socket_path, test_peer_uid_frame(request, test_uid), true) } #[cfg(feature = "layer1-bootstrap")] BrokerMode::ProbeExportAudit { @@ -852,7 +852,10 @@ pub fn run(command: BrokerMode) -> Result<(), RunError> { caller_role, } => run_probe( socket_path, - crate::bootstrap::wire::probe_export_audit(test_uid, caller_role), + test_peer_uid_frame( + crate::bootstrap::wire::probe_export_audit(caller_role), + test_uid, + ), false, ), } @@ -1381,8 +1384,9 @@ pub fn probe_bundle_load_response_with_policy( } /// Bind a kernel-authenticated peer to this broker instance before any wire -/// bytes are decoded. Test mode keeps the existing simulated envelope UID -/// support, but still requires the actual local test process credentials. +/// bytes are decoded. Test mode keeps the existing simulated peer-uid support +/// (the frame member [`TEST_PEER_UID_FIELD`]), but still requires the actual +/// local test process credentials. fn peer_matches_instance(config: &ServerConfig, peer_uid: u32, peer_gid: u32) -> bool { if config.test_mode { return (peer_uid == nix::unistd::Uid::current().as_raw() @@ -1393,6 +1397,75 @@ fn peer_matches_instance(config: &ServerConfig, peer_uid: u32, peer_gid: u32) -> || (config.profile == BrokerProfile::Host && peer_uid == 0) } +/// The harness-only peer-uid override's frame member (RS-0328). +/// +/// The broker's own harness - the bootstrap probe CLI and the integration +/// tests - asks a `--test-mode` broker to treat one connection as a peer other +/// than the uid `SO_PEERCRED` reports. The override rides beside the envelope +/// as a sibling member of the same JSON frame rather than as a field of the +/// wire contract: `d2b_contracts_broker::broker_wire::BrokerRequestEnvelope` +/// carries no test seam, a broker that was not started with `--test-mode` +/// never looks for this member, and its strict decode refuses a frame that +/// carries one. +pub const TEST_PEER_UID_FIELD: &str = "testPeerUid"; + +/// Wrap one envelope in the frame the harness sends to a `--test-mode` broker. +/// +/// `None` leaves the envelope's own frame untouched, so a harness run that +/// overrides no uid sends exactly the production frame. +/// +/// # Panics +/// +/// Panics when `envelope` does not serialize to a JSON object; every broker +/// envelope frame is one. +pub fn test_peer_uid_frame( + envelope: T, + test_peer_uid: Option, +) -> Value { + let mut frame = serde_json::to_value(envelope).expect("a broker envelope serializes"); + if let Some(test_peer_uid) = test_peer_uid { + frame + .as_object_mut() + .expect("a broker envelope frame is a JSON object") + .insert( + TEST_PEER_UID_FIELD.to_owned(), + Value::from(test_peer_uid), + ); + } + frame +} + +/// Unwrap the harness-only peer-uid override from a decoded frame. +/// +/// `Ok(None)` means the frame carries no override, or spells it `null` - the +/// absent value the retired envelope field accepted. A member of any other +/// shape is refused with the same force as every other malformed wire member +/// instead of being dropped. +fn take_test_peer_uid(frame: &mut Value) -> io::Result> { + let Some(member) = frame + .as_object_mut() + .and_then(|frame| frame.remove(TEST_PEER_UID_FIELD)) + else { + return Ok(None); + }; + match member { + Value::Null => Ok(None), + Value::Number(number) => number + .as_u64() + .and_then(|uid| u32::try_from(uid).ok()) + .map(Some) + .ok_or_else(invalid_test_peer_uid), + _ => Err(invalid_test_peer_uid()), + } +} + +fn invalid_test_peer_uid() -> io::Error { + io::Error::new( + io::ErrorKind::InvalidData, + format!("{TEST_PEER_UID_FIELD} is not a peer uid"), + ) +} + /// Accept and serve connections until the listener itself fails. /// /// One accepted connection becomes one task, so the accept path never runs a @@ -1463,14 +1536,14 @@ async fn handle_connection(connection: AsyncSeqpacket, server: &Server) -> io::R return Ok(()); } #[cfg(not(feature = "layer1-bootstrap"))] - let (envelope, request_fds) = { + let (envelope, request_fds, test_peer_uid) = { // The frame decodes as JSON first so the retired-wire gate can // recognize a variant the current enum no longer carries: a retired // variant's frame is well-formed JSON but not a current // `RequestEnvelope`, and the gate refuses it with the typed // stale-wire-version code plus an audit record before the typed // decode can drop it as malformed wire (KTD10). - let Some((envelope_value, request_fds)) = + let Some((mut envelope_value, request_fds)) = connection.recv_json_frame_with_fds::().await? else { return Ok(()); @@ -1505,18 +1578,41 @@ async fn handle_connection(connection: AsyncSeqpacket, server: &Server) -> io::R .await?; return Ok(()); } + // The harness-only peer-uid override is unwrapped here, in front of + // the typed decode: the wire contract's envelope carries no such + // member, so only a broker that was started with `--test-mode` ever + // sees one and every other broker refuses the frame with it. + let test_peer_uid = if server.config.test_mode { + take_test_peer_uid(&mut envelope_value)? + } else { + None + }; let envelope: RequestEnvelope = serde_json::from_value(envelope_value) .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?; - (envelope, request_fds) + (envelope, request_fds, test_peer_uid) }; #[cfg(feature = "layer1-bootstrap")] - let Some((envelope, request_fds)) = connection - .recv_json_frame::() - .await - .map(|frame| frame.map(|envelope| (envelope, Vec::new())))? - else { - return Ok(()); + let (envelope, request_fds, test_peer_uid) = { + // The bootstrap wire decodes as JSON first for the same reason the + // production wire does: the harness-only peer-uid override is a frame + // member beside the envelope and is unwrapped before the strict + // decode. + let Some(mut envelope_value) = connection.recv_json_frame::().await? else { + return Ok(()); + }; + let test_peer_uid = if server.config.test_mode { + take_test_peer_uid(&mut envelope_value)? + } else { + None + }; + let envelope: RequestEnvelope = serde_json::from_value(envelope_value) + .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?; + (envelope, Vec::new(), test_peer_uid) }; + // The kernel `SO_PEERCRED` uid is the authenticated caller. The frame's + // harness-only override stands in for it only in a `--test-mode` broker, + // and only for the gates: `peer_uid` stays the audited frame source. + let effective_uid = test_peer_uid.unwrap_or(peer_uid); let config = Arc::clone(&server.config); let audit_log = Arc::clone(&server.audit_log); @@ -1556,6 +1652,7 @@ async fn handle_connection(connection: AsyncSeqpacket, server: &Server) -> io::R envelope, request_fds, peer_uid, + effective_uid, peer_gid, peer_pid, &config, @@ -1569,6 +1666,7 @@ async fn handle_connection(connection: AsyncSeqpacket, server: &Server) -> io::R envelope, request_fds, peer_uid, + effective_uid, peer_gid, peer_pid, &config, @@ -1626,10 +1724,17 @@ enum RequestOutcome { /// the handlers' subprocess and filesystem work, the audit append - so they /// run on the dispatch pool, whose workers bound the work and whose queue /// bounds the waiters, rather than on a reactor worker or a thread per call. +/// +/// The caller context arrives as two uids: `peer_uid` is the +/// kernel-authenticated peer the refusals here audit as the frame's source, +/// and `effective_uid` is the uid the gates decide on - the same value except +/// in a `--test-mode` broker, where the harness-only frame override stands in +/// for the kernel credential. async fn answer_request( envelope: RequestEnvelope, request_fds: Vec, peer_uid: u32, + effective_uid: u32, peer_gid: u32, peer_pid: i32, config: &ServerConfig, @@ -1652,11 +1757,6 @@ async fn answer_request( BundleSlot::Tampered { path, reason } => (None, Some((path, reason))), }; let request = envelope.request; - let effective_uid = if config.test_mode { - envelope.test_peer_uid.unwrap_or(peer_uid) - } else { - peer_uid - }; let operation = request.op_name(); let opaque_target_id = request.opaque_target_id(); #[cfg(not(feature = "layer1-bootstrap"))] @@ -10390,11 +10490,11 @@ fn prepare_socket_path(path: &Path) -> io::Result<()> { #[cfg(feature = "layer1-bootstrap")] fn run_probe( socket_path: PathBuf, - request: RequestEnvelope, + frame: Value, expect_response: bool, ) -> Result<(), RunError> { let socket = connect_seqpacket(&socket_path)?; - send_json_frame(socket.as_raw_fd(), &request)?; + send_json_frame(socket.as_raw_fd(), &frame)?; let response = recv_json_frame::(socket.as_raw_fd())?; if let Some(response) = response { println!( @@ -17947,8 +18047,7 @@ mod tests { uid: configured_daemon_uid, }, // Ignored because config.test_mode=false: the broker must use the - // kernel SO_PEERCRED uid, not a caller-supplied envelope field. - test_peer_uid: Some(configured_daemon_uid), + // kernel SO_PEERCRED uid, not the envelope's claimed caller role. audit_join: None, }; let (client, server) = socketpair( @@ -18149,7 +18248,6 @@ mod tests { supported_features: Vec::new(), }), caller_role: BrokerCallerRole::RootUid { uid: 0 }, - test_peer_uid: None, audit_join: None, }, ) @@ -20685,7 +20783,6 @@ mod tests { supported_features: Vec::new(), }), caller_role: BrokerCallerRole::AdminUid { uid: caller_uid }, - test_peer_uid: Some(caller_uid), audit_join: None, }; caller.send_json_frame(&envelope).await.expect("send Hello"); diff --git a/packages/d2b-broker/tests/broker_protocol_compatibility.rs b/packages/d2b-broker/tests/broker_protocol_compatibility.rs index fe5dc0db9..6770aa62f 100644 --- a/packages/d2b-broker/tests/broker_protocol_compatibility.rs +++ b/packages/d2b-broker/tests/broker_protocol_compatibility.rs @@ -83,7 +83,6 @@ fn current_envelope(request: BrokerRequest) -> BrokerRequestEnvelope { BrokerRequestEnvelope { request, caller_role: BrokerCallerRole::NotAuthorized, - test_peer_uid: None, audit_join: None, } } diff --git a/packages/d2b-broker/tests/guest_profile.rs b/packages/d2b-broker/tests/guest_profile.rs index a3927582d..1f4057205 100644 --- a/packages/d2b-broker/tests/guest_profile.rs +++ b/packages/d2b-broker/tests/guest_profile.rs @@ -133,10 +133,13 @@ fn guest_binary_rejects_host_effects_before_bundle_mutation() { fd_kinds: Vec::new(), }), caller_role: BrokerCallerRole::AdminUid { uid: D2BD_UID }, - test_peer_uid: Some(D2BD_UID), audit_join: None, }; - send_json_frame(client.as_raw_fd(), &envelope).expect("send host-only request"); + send_json_frame( + client.as_raw_fd(), + &d2b_broker::runtime::test_peer_uid_frame(envelope, Some(D2BD_UID)), + ) + .expect("send host-only request"); let response: BrokerResponse = recv_json_frame(client.as_raw_fd()) .expect("receive guest profile response") .expect("guest broker response"); diff --git a/packages/d2b-broker/tests/profile_separation.rs b/packages/d2b-broker/tests/profile_separation.rs index a4c547dc8..30e7ebef8 100644 --- a/packages/d2b-broker/tests/profile_separation.rs +++ b/packages/d2b-broker/tests/profile_separation.rs @@ -106,23 +106,28 @@ fn host_and_guest_instances_keep_separate_runtime_bindings() { let envelope = |request| BrokerRequestEnvelope { request, caller_role: BrokerCallerRole::AdminUid { uid: D2BD_UID }, - test_peer_uid: Some(D2BD_UID), audit_join: None, }; send_json_frame( host_client.as_raw_fd(), - &envelope(BrokerRequest::Hello(HelloRequest { - client_version: "test-0".to_owned(), - supported_features: vec![], - })), + &d2b_broker::runtime::test_peer_uid_frame( + envelope(BrokerRequest::Hello(HelloRequest { + client_version: "test-0".to_owned(), + supported_features: vec![], + })), + Some(D2BD_UID), + ), ) .expect("send host hello"); send_json_frame( guest_client.as_raw_fd(), - &envelope(BrokerRequest::Hello(HelloRequest { - client_version: "test-0".to_owned(), - supported_features: vec![], - })), + &d2b_broker::runtime::test_peer_uid_frame( + envelope(BrokerRequest::Hello(HelloRequest { + client_version: "test-0".to_owned(), + supported_features: vec![], + })), + Some(D2BD_UID), + ), ) .expect("send guest hello"); @@ -214,12 +219,14 @@ fn host_executor_consumes_lifecycle_lease_once_through_the_cell_kernels() { }); send_json_frame( client.as_raw_fd(), - &BrokerRequestEnvelope { - request, - caller_role, - test_peer_uid: Some(D2BD_UID), - audit_join, - }, + &d2b_broker::runtime::test_peer_uid_frame( + BrokerRequestEnvelope { + request, + caller_role, + audit_join, + }, + Some(D2BD_UID), + ), ) .unwrap_or_else(|error| { panic!( diff --git a/packages/d2b-broker/tests/socket_activation.rs b/packages/d2b-broker/tests/socket_activation.rs index 64dc18421..ebee1a318 100644 --- a/packages/d2b-broker/tests/socket_activation.rs +++ b/packages/d2b-broker/tests/socket_activation.rs @@ -204,7 +204,6 @@ fn broker_adopts_socket_activated_fd_and_serves_hello() { supported_features: vec![], }), caller_role: BrokerCallerRole::default(), - test_peer_uid: Some(current_uid), audit_join: None, }; client.send_json_frame(&envelope).await?; diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 6b28207cf..756e3c367 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -2871,10 +2871,6 @@ pub struct BrokerRequestEnvelope { pub request: BrokerRequest, #[serde(default)] pub caller_role: BrokerCallerRole, - /// Test-only peer uid override; ignored by the production - /// broker (which always uses `SO_PEERCRED`). - #[serde(default)] - pub test_peer_uid: Option, /// Explicit canonical join identities for broker/resource durability. #[serde(default, skip_serializing_if = "Option::is_none")] pub audit_join: Option, @@ -3208,7 +3204,6 @@ mod tests { fd_kinds: vec![FdKind::Any], }), caller_role: BrokerCallerRole::AdminUid { uid: 1000 }, - test_peer_uid: None, audit_join: None, }; let frame = encode_frame(&env).expect("encodes"); @@ -3217,6 +3212,40 @@ mod tests { assert_eq!(parsed, env); } + #[test] + fn broker_request_envelope_refuses_a_test_only_peer_uid_member() { + // RS-0328: the test-only peer-uid override is no longer a member of + // the wire contract. The harness frames a `--test-mode` broker + // unwraps it from; every other broker refuses it here. + let env = BrokerRequestEnvelope { + request: BrokerRequest::EnvelopeInvoke(EnvelopeInvokeRequest { + operation: "signal-pidfd".to_owned(), + zone: "zone-a".to_owned(), + payload: serde_json::json!({ "signal": 15 }), + chain_root_invocation_id: None, + chain_identities: None, + fd_indexes: vec![0], + fd_kinds: vec![FdKind::Any], + }), + caller_role: BrokerCallerRole::AdminUid { uid: 1000 }, + audit_join: None, + }; + let encoded = serde_json::to_value(&env).expect("encodes"); + assert!( + encoded.get("testPeerUid").is_none(), + "the production envelope emits no test seam: {encoded}" + ); + let mut frame = encoded.as_object().expect("envelope frame").clone(); + frame.insert("testPeerUid".to_owned(), serde_json::json!(1000)); + let error = + serde_json::from_value::(serde_json::Value::Object(frame)) + .expect_err("the production envelope must refuse the test-only member"); + assert!( + error.to_string().contains("unknown field `testPeerUid`"), + "unexpected refusal: {error}" + ); + } + #[test] fn broker_request_envelope_default_caller_role_is_not_authorized() { let json = serde_json::json!({ @@ -4400,7 +4429,6 @@ mod tests { fd_kinds: vec![], }), caller_role: BrokerCallerRole::AdminUid { uid: 1000 }, - test_peer_uid: None, audit_join: None, }; let frame = encode_frame(&root).expect("encodes"); diff --git a/packages/d2b-contracts-broker/src/kernel_client.rs b/packages/d2b-contracts-broker/src/kernel_client.rs index 38b862033..c6dae8557 100644 --- a/packages/d2b-contracts-broker/src/kernel_client.rs +++ b/packages/d2b-contracts-broker/src/kernel_client.rs @@ -161,7 +161,6 @@ pub fn envelope_invoke_kernel( let envelope = BrokerRequestEnvelope { request, caller_role, - test_peer_uid: None, audit_join: None, }; let frame = d2b_contracts::encode_frame(&envelope) diff --git a/packages/d2bd-runtime/src/broker_transport.rs b/packages/d2bd-runtime/src/broker_transport.rs index b7f20ce77..03d63634f 100644 --- a/packages/d2bd-runtime/src/broker_transport.rs +++ b/packages/d2bd-runtime/src/broker_transport.rs @@ -32,7 +32,6 @@ pub fn dispatch_broker_request_to_socket( let envelope = BrokerRequestEnvelope { request, caller_role, - test_peer_uid: None, audit_join, }; let Some(timeout) = timeout else { diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index b6c978f80..19c32e1aa 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -14010,7 +14010,6 @@ fn dispatch_broker_request_as( &BrokerRequestEnvelope { request, caller_role, - test_peer_uid: None, audit_join: audit_join.clone(), }, )?; @@ -16898,7 +16897,6 @@ fn dispatch_raw_broker_value_with_timeout( let envelope = json!({ "request": request, "callerRole": caller_role, - "testPeerUid": Value::Null, }); let remaining = broker_remaining_before_op(deadline, &socket_path)?; socket @@ -17139,7 +17137,6 @@ async fn raw_broker_round_trip_async( let envelope = json!({ "request": request, "callerRole": caller_role, - "testPeerUid": Value::Null, }); let envelope_bytes = serde_json::to_vec(&envelope).map_err(|err| TypedError::InternalIo { context: "serialize raw broker request".to_owned(), @@ -21589,7 +21586,6 @@ mod public_status_tests { supported_features: Vec::new(), }), caller_role: caller, - test_peer_uid: None, audit_join: None, }; let json = serde_json::to_string(&envelope).unwrap(); From caa29e248fb1d588b19ab74a45d325a5dc982a4b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:28:58 -0700 Subject: [PATCH 642/726] refactor(d2b-contracts-control): close the audit page end and the mutation mode RS-0248: AuditResponse paired complete: bool with next_cursor: Option, so a final page with a cursor and an incomplete page without one were representable and only the runtime validate_audit_page rejected them at decode. The page end is now the closed AuditPageEnd (Complete / More(cursor)); AuditPageEnd::from_parts reports the canonical d2b_contracts::audit_wire::AuditPageError classes and the crate-local validate_audit_page copy is deleted. RS-0250: MutationFlags modelled dry-run/apply/json as three booleans while the daemon refuses a request that selects neither. The mode is now the closed MutationMode beside a separate json flag; the private MutationFlagsWire keeps the flat dryRun/apply/json triple, so the serialized shape is unchanged while a payload that selects neither mode now fails admission. A hand-written frame that sets both keeps the daemon's long-standing dry-run precedence. The raw frame path parses the pair in mutation_mode_from_request and keeps the documented invalid-request envelope, so the flags-pair check inside mutating_verb_preflight and the unreachable all-false guards in the usbip handlers are deleted. Co-change list: d2bd-runtime wire::audit_response takes the page end and returns Result, refusing a broker page that pairs an incomplete page with no cursor as wire-invalid-frame instead of reporting it as final; d2b's audit pagination branches on AuditPageEnd and its "omitted continuation metadata" branch is gone; d2bd's mutation sites, preflight, operation-id fingerprint and tests move to the mode; docs/reference/daemon-api.md is regenerated with gen-daemon-api. Serialized bytes are unchanged for both shapes: the audit page still emits entries/nextCursor/complete in that order, the flags still emit dryRun/apply/json, and docs/reference/schemas/v2/wire-protocol.json regenerates byte-identically, so no consumer outside this tree observes a change. Gate: cargo test -p d2b-contracts-control; cargo test -p d2bd-runtime --lib; cargo test -p d2b --test audit_contract; cargo test -p d2bd --lib raw_mutating_verb_frames; cargo check -p d2b-contracts-control -p d2bd-runtime -p d2b -p d2bd --all-targets; nix develop -c bazel test --cache_test_results=no //packages/xtask:gen_schemas_drift //packages/xtask:gen_cli_schemas_drift //packages/xtask:gen_daemon_api_drift --- changelog.d/w6-10-wire-state-enums.md | 19 + docs/reference/daemon-api.md | 105 ++--- .../d2b-contracts-control/src/public_wire.rs | 349 ++++++++++++++--- .../tests/public_wire.rs | 4 +- packages/d2b/src/dispatch.rs | 26 +- packages/d2bd-runtime/src/wire.rs | 57 ++- packages/d2bd/src/composition.rs | 360 +++++++++--------- 7 files changed, 618 insertions(+), 302 deletions(-) create mode 100644 changelog.d/w6-10-wire-state-enums.md diff --git a/changelog.d/w6-10-wire-state-enums.md b/changelog.d/w6-10-wire-state-enums.md new file mode 100644 index 000000000..27686b7b7 --- /dev/null +++ b/changelog.d/w6-10-wire-state-enums.md @@ -0,0 +1,19 @@ +### Changed + +- The public `auditResponse` page end is one closed value instead of the + `complete`/`nextCursor` boolean pair: `AuditResponse` now carries + `AuditPageEnd` (`Complete` or `More(cursor)`), so a final page with a cursor + and an incomplete page without one can neither be built nor decoded. The + serialized keys, their order, and the admission error text are unchanged, so + the published v2 wire schema and the CLI pagination contract do not move. + The crate-local `validate_audit_page` copy is gone; the page-end constructor + reports the shared `d2b_contracts::audit_wire::AuditPageError` classes, and + the daemon refuses a broker page that pairs an incomplete page with no + cursor instead of reporting it as final. +- Every mutating-verb request now selects a `MutationMode` (`dryRun` or + `apply`) instead of carrying two independent booleans, so the request that + selects neither mode, which the daemon refuses, is no longer representable. + `dryRun`, `apply`, and `json` remain the serialized keys in the same order, + and the daemon's raw-frame path still answers a request that selects neither + mode with the documented `invalid-request` envelope; only the flags-pair + check inside `mutating_verb_preflight` is deleted. diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 22ecdadb6..e8e876867 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -263,14 +263,14 @@ host reboot. | `ListRequest` | struct | [`ListRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L280) | struct { `env`: `Option`; `vm`: `Option` } | | `StatusRequest` | struct | [`StatusRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L288) | struct { `check_bridges`: `bool`; `vm`: `Option` } | | `AuditRequest` | struct | [`AuditRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L297) | struct { `filter`: `Option`; `format`: `AuditFormat`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | -| `VmLifecycleRequest` | struct | [`VmLifecycleRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L331) | struct { `vm`: `String`; `flags`: `MutationFlags`; `force`: `bool`; `no_wait_api`: `bool` } | -| `ActivationRequest` | struct | [`ActivationRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L351) | struct { `vm`: `String`; `to_generation`: `Option`; `flags`: `MutationFlags` } | -| `UsbipBindCliRequest` | struct | [`UsbipBindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L362) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | -| `UsbipUnbindCliRequest` | struct | [`UsbipUnbindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L371) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | -| `NamedProcessStreamRequest` | enum | [`NamedProcessStreamRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L1041) | `Stdin` - struct { `offset`: `u64`; `chunk_base64`: `String`; `eof`: `bool` }; `Read` - struct { `stream`: `ExecStream`; `offset`: `u64`; `max_len`: `u64`; `wait`: `bool`; `timeout_ms`: `u64` }; `Signal` - struct { `control_seq`: `u64`; `signo`: `u32` }; `Resize` - struct { `control_seq`: `u64`; `rows`: `u32`; `cols`: `u32` }; `CloseStdin` - struct { `offset`: `u64` }; `Cancel`; `Close`; `Wait` - struct { `timeout_ms`: `u64` } | -| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2061) | struct { `flags`: `MutationFlags` } | -| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2068) | struct { `flags`: `MutationFlags` } | -| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2080) | struct { `flags`: `MutationFlags`; `network`: `bool` } | +| `VmLifecycleRequest` | struct | [`VmLifecycleRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L427) | struct { `vm`: `String`; `flags`: `MutationFlags`; `force`: `bool`; `no_wait_api`: `bool` } | +| `ActivationRequest` | struct | [`ActivationRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L447) | struct { `vm`: `String`; `to_generation`: `Option`; `flags`: `MutationFlags` } | +| `UsbipBindCliRequest` | struct | [`UsbipBindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L458) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | +| `UsbipUnbindCliRequest` | struct | [`UsbipUnbindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L467) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | +| `NamedProcessStreamRequest` | enum | [`NamedProcessStreamRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L1137) | `Stdin` - struct { `offset`: `u64`; `chunk_base64`: `String`; `eof`: `bool` }; `Read` - struct { `stream`: `ExecStream`; `offset`: `u64`; `max_len`: `u64`; `wait`: `bool`; `timeout_ms`: `u64` }; `Signal` - struct { `control_seq`: `u64`; `signo`: `u32` }; `Resize` - struct { `control_seq`: `u64`; `rows`: `u32`; `cols`: `u32` }; `CloseStdin` - struct { `offset`: `u64` }; `Cancel`; `Close`; `Wait` - struct { `timeout_ms`: `u64` } | +| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2157) | struct { `flags`: `MutationFlags` } | +| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2164) | struct { `flags`: `MutationFlags` } | +| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2176) | struct { `flags`: `MutationFlags`; `network`: `bool` } | ### Broker socket request types @@ -373,17 +373,17 @@ see the auto-generated tables above for the committed Rust variants. | --- | --- | --- | --- | | `PublicResponse` | enum | [`PublicResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L124) | `Capabilities` - (CapabilitiesResponse); `AuthStatus` - (AuthStatusResponse); `List` - (ListResponse); `Status` - (StatusResponse); `Audit` - (AuditResponse); `UsbipProbe` - (UsbipProbeResponse); `MutatingVerb` - (MutatingVerbResponse); `Exec` - (ExecOpResponse); `Console` - (ConsoleOpResponse); `Audio` - (AudioOpResponse); `Workload` - (WorkloadOpResponse); `UsbSecurityKeyStatus` - (d2b_contracts::security_key::SecurityKeyStatusResponse); `UsbSecurityKeySessions` - (d2b_contracts::security_key::SecurityKeySessionsResponse); `UsbSecurityKeyCancel` - (d2b_contracts::security_key::SecurityKeyCancelResponse); `Error` - (Error) | | `WorkloadOpResponse` | enum | [`WorkloadOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L175) | `List` - (WorkloadListResult); `Status` - (Box); `LauncherExec` - (LauncherExecResult) | -| `ExecOpResponse` | enum | [`ExecOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1014) | `Start` - (ExecStartResult); `DetachedCreate` - (ExecDetachedCreateResult); `WriteStdin` - (ExecWriteStdinResult); `ReadOutput` - (ExecReadOutputResult); `Signal` - (ExecControlResult); `Resize` - (ExecControlResult); `Wait` - (ExecWaitResult); `Close` - (ExecCloseResult); `List` - (ExecDetachedListResult); `Logs` - (ExecDetachedLogsResult); `Status` - (ExecDetachedStatusResult); `Kill` - (ExecDetachedKillResult) | -| `NamedProcessStreamResponse` | enum | [`NamedProcessStreamResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1141) | `Stdin` - (ExecWriteStdinResult); `Output` - (ExecReadOutputResult); `Delivered` - (ExecControlResult); `Wait` - (ExecWaitResult); `Closed` - (ExecCloseResult); `Terminal` - (ExecTerminalStatus); `Error` - (NamedProcessStreamError) | -| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1844) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | -| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2051) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | -| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2113) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | -| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2139) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | -| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2149) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | -| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2158) | struct { `vms`: `Vec`; `read_model`: `Option` } | -| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2166) | struct { `entries`: `Vec`; `read_model`: `Option` } | -| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2186) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2474) | struct { `entries`: `Vec` } | +| `ExecOpResponse` | enum | [`ExecOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1110) | `Start` - (ExecStartResult); `DetachedCreate` - (ExecDetachedCreateResult); `WriteStdin` - (ExecWriteStdinResult); `ReadOutput` - (ExecReadOutputResult); `Signal` - (ExecControlResult); `Resize` - (ExecControlResult); `Wait` - (ExecWaitResult); `Close` - (ExecCloseResult); `List` - (ExecDetachedListResult); `Logs` - (ExecDetachedLogsResult); `Status` - (ExecDetachedStatusResult); `Kill` - (ExecDetachedKillResult) | +| `NamedProcessStreamResponse` | enum | [`NamedProcessStreamResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1237) | `Stdin` - (ExecWriteStdinResult); `Output` - (ExecReadOutputResult); `Delivered` - (ExecControlResult); `Wait` - (ExecWaitResult); `Closed` - (ExecCloseResult); `Terminal` - (ExecTerminalStatus); `Error` - (NamedProcessStreamError) | +| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1940) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | +| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2147) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | +| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2209) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | +| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2235) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | +| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2245) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | +| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2254) | struct { `vms`: `Vec`; `read_model`: `Option` } | +| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2262) | struct { `entries`: `Vec`; `read_model`: `Option` } | +| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2327) | struct { `entries`: `Vec`; `page_end`: `AuditPageEnd` } | +| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2642) | struct { `entries`: `Vec` } | ### Broker socket response types @@ -490,7 +490,7 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2640) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | +| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2808) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | ### Other documented enums @@ -525,32 +525,34 @@ running live guest activation. | `WorkloadAvailability` | enum | [`WorkloadAvailability`](../../packages/d2b-contracts-control/src/public_wire.rs#L208) | `Ready`; `HelperUnavailable`; `HelperStale`; `UserManagerUnavailable`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable`; `Degraded` | | `GraphicalLaunchPosture` | enum | [`GraphicalLaunchPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L222) | `Proxied`; `NotApplicable`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable` | | `LauncherExecDisposition` | enum | [`LauncherExecDisposition`](../../packages/d2b-contracts-control/src/public_wire.rs#L263) | `Committed`; `AlreadyCommitted` | -| `ExecStream` | enum | [`ExecStream`](../../packages/d2b-contracts-control/src/public_wire.rs#L388) | `Stdout`; `Stderr` | -| `ExecOp` | enum | [`ExecOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L679) | `Start` - (ExecStartArgs); `WriteStdin` - (ExecWriteStdinArgs); `ReadOutput` - (ExecReadOutputArgs); `Signal` - (ExecSignalArgs); `Resize` - (ExecResizeArgs); `Wait` - (ExecWaitArgs); `Close` - (ExecCloseArgs); `List` - (ExecDetachedListArgs); `Logs` - (ExecDetachedLogsArgs); `Status` - (ExecDetachedStatusArgs); `Kill` - (ExecDetachedKillArgs) | -| `ExecTerminalStatus` | enum | [`ExecTerminalStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L795) | `Exited` - struct { `code`: `i32` }; `Signaled` - struct { `signal`: `u32` }; `Error` - struct { `slug`: `String` } | -| `ExecDetachedKillOutcome` | enum | [`ExecDetachedKillOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L986) | `Cancelling`; `AlreadyTerminal` | -| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1448) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | -| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1459) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | -| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1569) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1712) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | -| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1858) | `Speaker`; `Microphone` | -| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1872) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1914) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1959) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | -| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2022) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2128) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | -| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2233) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | -| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2251) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | -| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2276) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | -| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2289) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | -| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2303) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | -| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2326) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | -| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2344) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | -| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2357) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | -| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2376) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | -| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2412) | `Usbip`; `QemuMediaSlot` | -| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2495) | `Human`; `Json` | -| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2503) | `None`; `Launcher`; `Admin` | +| `MutationMode` | enum | [`MutationMode`](../../packages/d2b-contracts-control/src/public_wire.rs#L324) | `DryRun`; `Apply` | +| `ExecStream` | enum | [`ExecStream`](../../packages/d2b-contracts-control/src/public_wire.rs#L484) | `Stdout`; `Stderr` | +| `ExecOp` | enum | [`ExecOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L775) | `Start` - (ExecStartArgs); `WriteStdin` - (ExecWriteStdinArgs); `ReadOutput` - (ExecReadOutputArgs); `Signal` - (ExecSignalArgs); `Resize` - (ExecResizeArgs); `Wait` - (ExecWaitArgs); `Close` - (ExecCloseArgs); `List` - (ExecDetachedListArgs); `Logs` - (ExecDetachedLogsArgs); `Status` - (ExecDetachedStatusArgs); `Kill` - (ExecDetachedKillArgs) | +| `ExecTerminalStatus` | enum | [`ExecTerminalStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L891) | `Exited` - struct { `code`: `i32` }; `Signaled` - struct { `signal`: `u32` }; `Error` - struct { `slug`: `String` } | +| `ExecDetachedKillOutcome` | enum | [`ExecDetachedKillOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L1082) | `Cancelling`; `AlreadyTerminal` | +| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1544) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | +| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1555) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | +| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1665) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1808) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | +| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1954) | `Speaker`; `Microphone` | +| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1968) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2010) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L2055) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | +| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2118) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2224) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | +| `AuditPageEnd` | enum | [`AuditPageEnd`](../../packages/d2b-contracts-control/src/public_wire.rs#L2288) | `Complete`; `More` - (AuditExportCursor) | +| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2401) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | +| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2419) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | +| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2444) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | +| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2457) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | +| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2471) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | +| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2494) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | +| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2512) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | +| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2525) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | +| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2544) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | +| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2580) | `Usbip`; `QemuMediaSlot` | +| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2663) | `Human`; `Json` | +| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2671) | `None`; `Launcher`; `Admin` | | `TerminalStream` | enum | [`TerminalStream`](../../packages/d2b-contracts-control/src/terminal_wire.rs#L13) | `Stdout`; `Stderr` | | `HelperScopeKind` | enum | [`HelperScopeKind`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L68) | `LauncherApp`; `WaylandProxy` | | `HelperScopeState` | enum | [`HelperScopeState`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L95) | `Starting`; `Active`; `Stopping`; `Exited`; `Degraded` | @@ -648,11 +650,12 @@ the failure class, for example `host check`, `audit`, `status`, or | `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2537) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | | `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L198) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | -| `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1208) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | -| `NamedProcessStreamError` | struct | [`NamedProcessStreamError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1228) | struct { `kind`: `NamedProcessStreamErrorKind` } | -| `ShellNameError` | struct | [`ShellNameError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1309) | empty struct | -| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1895) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | -| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1996) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | +| `MutationModeError` | struct | [`MutationModeError`](../../packages/d2b-contracts-control/src/public_wire.rs#L333) | empty struct | +| `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1304) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | +| `NamedProcessStreamError` | struct | [`NamedProcessStreamError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1324) | struct { `kind`: `NamedProcessStreamErrorKind` } | +| `ShellNameError` | struct | [`ShellNameError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1405) | empty struct | +| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1991) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | +| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L2092) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | | `LevelPercentError` | enum | [`LevelPercentError`](../../packages/d2b-contracts/src/audio.rs#L28) | `OutOfRange` - (u8) | | `AudioPolicyError` | enum | [`AudioPolicyError`](../../packages/d2b-contracts/src/audio.rs#L216) | `InvalidJson` - (String); `InvalidField` - (String); `UnknownSchemaVersion` - (String); `Serialize` - (String) | | `AuditExportErrorCode` | enum | [`AuditExportErrorCode`](../../packages/d2b-contracts/src/audit_wire.rs#L20) | `HashBreak`; `RecordInvalid`; `ReadFailed` | diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index a4cb196eb..e0e56a5c0 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -1,4 +1,4 @@ -pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry}; +pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditPageError}; use d2b_contracts::types::MediaRef; use d2b_contracts::{ FeatureFlag, Version, @@ -19,7 +19,7 @@ use schemars::{ r#gen::SchemaGenerator, schema::{InstanceType, Metadata, Schema, SchemaObject, SingleOrVec, StringValidation}, }; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; use std::fmt; /// Lifecycle state projected for a target-local Process or @@ -313,24 +313,120 @@ fn default_audit_request_limit() -> u32 { // Mutating-verb request payloads. // --------------------------------------------------------------- +/// The mutating mode one request selects: plan the mutation, or execute it. +/// +/// The wire has always spelled this as the flat `dryRun`/`apply` boolean +/// pair. That pair also admits a request which selects neither, so the mode +/// is closed here and the pair is derived from it instead of being +/// re-checked at every mutation site. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase")] +pub enum MutationMode { + /// Plan the mutation and return the daemon-side plan. + DryRun, + /// Execute the mutation. + Apply, +} + +/// Why a raw `dryRun`/`apply` pair names no mutating mode. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MutationModeError; + +impl MutationMode { + /// Parse the wire `dryRun`/`apply` pair. + /// + /// A request that sets neither flag has no mode and is refused. When a + /// hand-written request sets both, `dryRun` wins - the precedence the + /// daemon has always applied to the pair, and a combination the CLI + /// cannot emit (`--dry-run` and `--apply` conflict). + pub fn from_flags(dry_run: bool, apply: bool) -> Result { + match (dry_run, apply) { + (false, false) => Err(MutationModeError), + (true, _) => Ok(Self::DryRun), + (false, true) => Ok(Self::Apply), + } + } + + /// The wire `dryRun`/`apply` pair this mode spells. + pub fn to_flags(self) -> (bool, bool) { + (matches!(self, Self::DryRun), matches!(self, Self::Apply)) + } +} + +impl fmt::Display for MutationModeError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("mutating verb request sets neither dryRun nor apply") + } +} + +impl std::error::Error for MutationModeError {} + +/// Common flags every mutating-verb request carries. +/// +/// The mode moves with the flags, so a request that selects neither +/// `dryRun` nor `apply` - which the daemon refuses - has no value here. +/// The serialized shape is unchanged: the flat `dryRun`, `apply`, and `json` +/// keys the protocol has always carried. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(try_from = "MutationFlagsWire", into = "MutationFlagsWire")] +pub struct MutationFlags { + pub mode: MutationMode, + /// Ask for the machine-readable (`json`) response body. + pub json: bool, +} + +// The published wire schema renders this doc comment as the description of +// every request that flattens the flags, so it stays word-for-word. /// Common flags every mutating-verb request carries. The daemon /// rejects requests that set neither `dry_run` nor `apply`. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct MutationFlags { +struct MutationFlagsWire { #[serde(default)] - pub dry_run: bool, + dry_run: bool, #[serde(default)] - pub apply: bool, + apply: bool, #[serde(default)] - pub json: bool, + json: bool, +} + +impl TryFrom for MutationFlags { + type Error = MutationModeError; + + fn try_from(wire: MutationFlagsWire) -> Result { + Ok(Self { + mode: MutationMode::from_flags(wire.dry_run, wire.apply)?, + json: wire.json, + }) + } +} + +impl From for MutationFlagsWire { + fn from(flags: MutationFlags) -> Self { + let (dry_run, apply) = flags.mode.to_flags(); + Self { + dry_run, + apply, + json: flags.json, + } + } +} + +impl JsonSchema for MutationFlags { + fn schema_name() -> String { + "MutationFlags".to_owned() + } + + fn json_schema(r#gen: &mut SchemaGenerator) -> Schema { + MutationFlagsWire::json_schema(r#gen) + } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmLifecycleRequest { pub vm: String, - #[serde(default, flatten)] + #[serde(flatten)] pub flags: MutationFlags, /// Bypass provider graceful-shutdown and use the existing forced cleanup path. #[schemars(default)] @@ -353,7 +449,7 @@ pub struct ActivationRequest { #[serde(default, skip_serializing_if = "Option::is_none")] #[schemars(range(min = 1))] pub to_generation: Option, - #[serde(default, flatten)] + #[serde(flatten)] pub flags: MutationFlags, } @@ -362,7 +458,7 @@ pub struct ActivationRequest { pub struct UsbipBindCliRequest { pub vm: String, pub bus_id: String, - #[serde(default, flatten)] + #[serde(flatten)] pub flags: MutationFlags, } @@ -371,7 +467,7 @@ pub struct UsbipBindCliRequest { pub struct UsbipUnbindCliRequest { pub vm: String, pub bus_id: String, - #[serde(default, flatten)] + #[serde(flatten)] pub flags: MutationFlags, } @@ -2056,17 +2152,17 @@ pub enum AudioOpResponse { // ---- Remaining request structs ----------------------------------------------- -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct HostPrepareRequest { - #[serde(default, flatten)] + #[serde(flatten)] pub flags: MutationFlags, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct HostDestroyRequest { - #[serde(default, flatten)] + #[serde(flatten)] pub flags: MutationFlags, } @@ -2075,10 +2171,10 @@ pub struct HostDestroyRequest { /// `--ownership`) carved out of `host prepare`. The daemon rejects /// requests with no scope selected with a typed `invalid-request` /// envelope. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct HostReconcileRequest { - #[serde(default, flatten)] + #[serde(flatten)] pub flags: MutationFlags, /// Re-run the per-env nftables / route / sysctl reconcile. #[serde(default)] @@ -2181,50 +2277,122 @@ pub struct PublicReadModelMetadata { pub deep_refresh: String, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields, try_from = "AuditResponseWire")] +/// The end of one audit page: the final-page marker, or the cursor that +/// continues the export. +/// +/// The wire carries the pair `complete: bool` plus `nextCursor`. That pair +/// allowed two combinations the protocol never meant - a final page with a +/// cursor, and an incomplete page without one - so the page end is closed +/// here and the pair is derived from it. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AuditPageEnd { + /// Final page: the response omits `nextCursor`. + Complete, + /// At least one more page follows; the response carries `nextCursor`. + More(AuditExportCursor), +} + +impl AuditPageEnd { + /// Build a page end from the raw `(complete, nextCursor)` pair of a page + /// this crate did not construct itself (the broker export page the daemon + /// forwards), refusing the two combinations that pair admits. + pub fn from_parts( + complete: bool, + next_cursor: Option, + ) -> Result { + match (complete, next_cursor) { + (true, None) => Ok(Self::Complete), + (false, Some(cursor)) => Ok(Self::More(cursor)), + (true, Some(_)) => Err(AuditPageError::CompleteWithCursor), + (false, None) => Err(AuditPageError::IncompleteWithoutCursor), + } + } + + /// Whether this is the final page. + pub fn is_complete(&self) -> bool { + matches!(self, Self::Complete) + } + + /// The cursor that continues the export; absent on the final page. + pub fn next_cursor(&self) -> Option<&AuditExportCursor> { + match self { + Self::Complete => None, + Self::More(cursor) => Some(cursor), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +#[serde(try_from = "AuditResponseWire")] pub struct AuditResponse { /// Typed broker audit entries. The public daemon page deliberately shares /// the broker entry shape so pagination does not lose sequence or export /// error information. pub entries: Vec, - /// Omitted only when this is the final page. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub next_cursor: Option, - /// Protocol v5 requires an explicit completion marker. - pub complete: bool, + /// Where this page ends: the final marker, or the cursor that continues + /// the export. + pub page_end: AuditPageEnd, } -#[derive(Debug, Deserialize)] +// The serialized shape of `AuditResponse`: the flat `entries`, `nextCursor`, +// and `complete` keys the protocol has always carried. The comment is not a +// doc comment on purpose - the published schema description of this +// definition comes from the wire struct and must stay absent, exactly as it +// was before the page end became an enum. +#[derive(Debug, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct AuditResponseWire { + /// Typed broker audit entries. The public daemon page deliberately shares + /// the broker entry shape so pagination does not lose sequence or export + /// error information. entries: Vec, - #[serde(default)] + /// Omitted only when this is the final page. + #[serde(default, skip_serializing_if = "Option::is_none")] next_cursor: Option, + /// Protocol v5 requires an explicit completion marker. complete: bool, } +/// The serialized shape of [`AuditResponse`], borrowing the page end so a +/// page never clones its entries just to be written. +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct AuditResponseOut<'a> { + entries: &'a [AuditExportEntry], + #[serde(skip_serializing_if = "Option::is_none")] + next_cursor: Option<&'a AuditExportCursor>, + complete: bool, +} + +impl Serialize for AuditResponse { + fn serialize(&self, serializer: S) -> Result { + AuditResponseOut { + entries: &self.entries, + next_cursor: self.page_end.next_cursor(), + complete: self.page_end.is_complete(), + } + .serialize(serializer) + } +} + impl TryFrom for AuditResponse { - type Error = &'static str; + type Error = AuditPageError; fn try_from(wire: AuditResponseWire) -> Result { - validate_audit_page(wire.complete, wire.next_cursor.as_ref())?; Ok(Self { entries: wire.entries, - next_cursor: wire.next_cursor, - complete: wire.complete, + page_end: AuditPageEnd::from_parts(wire.complete, wire.next_cursor)?, }) } } -pub(crate) fn validate_audit_page( - complete: bool, - next_cursor: Option<&AuditExportCursor>, -) -> Result<(), &'static str> { - match (complete, next_cursor.is_some()) { - (true, true) => Err("complete audit page must omit nextCursor"), - (false, false) => Err("incomplete audit page requires nextCursor"), - _ => Ok(()), +impl JsonSchema for AuditResponse { + fn schema_name() -> String { + "AuditResponse".to_owned() + } + + fn json_schema(r#gen: &mut SchemaGenerator) -> Schema { + AuditResponseWire::json_schema(r#gen) } } @@ -2725,11 +2893,11 @@ pub struct AuditEntry { #[cfg(test)] mod tests { use super::{ - AuditResponse, ExecReadOutputResult, ExecStream, ExecTerminalStatus, LevelPercent, - MutationFlags, NamedProcessStreamError, NamedProcessStreamErrorKind, - NamedProcessStreamRequest, NamedProcessStreamRequestFrame, NamedProcessStreamResponse, - NamedProcessStreamResponseFrame, PublicRequest, PublicResponse, RuntimeSummary, - VmLifecycleRequest, VmLifecycleState, + AuditPageEnd, AuditResponse, ExecReadOutputResult, ExecStream, ExecTerminalStatus, + LevelPercent, MutationFlags, MutationMode, MutationModeError, NamedProcessStreamError, + NamedProcessStreamErrorKind, NamedProcessStreamRequest, NamedProcessStreamRequestFrame, + NamedProcessStreamResponse, NamedProcessStreamResponseFrame, PublicRequest, PublicResponse, + RuntimeSummary, VmLifecycleRequest, VmLifecycleState, }; use d2b_contracts::{ Error, FeatureFlag, Version, @@ -2905,8 +3073,11 @@ mod tests { serde_json::from_value(value).expect("paginated audit response decodes"); assert_eq!(response.entries.len(), 1); assert_eq!(response.entries[0].sequence, 42); - assert_eq!(response.next_cursor, Some(cursor)); - assert!(!response.complete); + assert_eq!(response.page_end, AuditPageEnd::More(cursor)); + assert_eq!( + serde_json::to_string(&response).expect("page serializes"), + "{\"entries\":[{\"sequence\":42,\"record\":{\"operation\":\"ApplyNftables\"}}],\"nextCursor\":{\"day\":\"2026-08-13\",\"line\":41,\"sequence\":41},\"complete\":false}" + ); } #[test] @@ -2916,8 +3087,11 @@ mod tests { "complete": true })) .expect("complete audit page decodes"); - assert!(response.next_cursor.is_none()); - assert!(response.complete); + assert_eq!(response.page_end, AuditPageEnd::Complete); + assert_eq!( + serde_json::to_string(&response).expect("page serializes"), + "{\"entries\":[],\"complete\":true}" + ); } #[test] @@ -3017,27 +3191,102 @@ mod tests { decoded, PublicRequest::VmStop(VmLifecycleRequest { vm, - flags: MutationFlags { apply: true, .. }, + flags: MutationFlags { mode: MutationMode::Apply, .. }, force: false, no_wait_api: false, }) if vm == "corp-vm" )); } + #[test] + fn mutation_mode_closes_the_flag_pair() { + assert_eq!( + MutationMode::from_flags(false, false), + Err(MutationModeError) + ); + assert_eq!(MutationMode::from_flags(true, false), Ok(MutationMode::DryRun)); + assert_eq!(MutationMode::from_flags(false, true), Ok(MutationMode::Apply)); + assert_eq!(MutationMode::from_flags(true, true), Ok(MutationMode::DryRun)); + assert_eq!(MutationMode::DryRun.to_flags(), (true, false)); + assert_eq!(MutationMode::Apply.to_flags(), (false, true)); + } + + #[test] + fn mutating_flags_keeps_the_flat_pair_and_requires_a_mode() { + let apply = MutationFlags { + mode: MutationMode::Apply, + json: false, + }; + assert_eq!( + serde_json::to_string(&apply).expect("flags serialize"), + "{\"dryRun\":false,\"apply\":true,\"json\":false}" + ); + + let decoded: PublicRequest = serde_json::from_value(serde_json::json!({ + "kind": "vm stop", + "payload": { + "vm": "corp-vm", + "dryRun": true + } + })) + .expect("dry run payload decodes"); + assert!(matches!( + decoded, + PublicRequest::VmStop(VmLifecycleRequest { + flags: MutationFlags { + mode: MutationMode::DryRun, + json: false, + }, + .. + }) + )); + + let error = serde_json::from_value::(serde_json::json!({ + "kind": "vm stop", + "payload": { + "vm": "corp-vm" + } + })) + .expect_err("a payload with no mode must fail admission"); + assert!( + error.to_string().contains("neither dryRun nor apply"), + "the refusal should name the flags: {error}" + ); + } + #[test] fn vm_lifecycle_omits_false_force_but_serializes_true() { let without_force = serde_json::to_value(PublicRequest::VmStop(VmLifecycleRequest { vm: "corp-vm".to_owned(), - flags: MutationFlags::default(), + flags: MutationFlags { + mode: MutationMode::DryRun, + json: false, + }, force: false, no_wait_api: false, })) .expect("vm stop serializes"); assert!(without_force["payload"].get("force").is_none()); + assert_eq!( + serde_json::to_string(&PublicRequest::VmStop(VmLifecycleRequest { + vm: "corp-vm".to_owned(), + flags: MutationFlags { + mode: MutationMode::DryRun, + json: false, + }, + force: false, + no_wait_api: false, + })) + .expect("vm stop serializes"), + "{\"kind\":\"vm stop\",\"payload\":{\"vm\":\"corp-vm\",\"dryRun\":true,\"apply\":false,\"json\":false,\"noWaitApi\":false}}" + ); let with_force = serde_json::to_value(PublicRequest::VmRestart(VmLifecycleRequest { vm: "corp-vm".to_owned(), - flags: MutationFlags::default(), + flags: MutationFlags { + mode: MutationMode::Apply, + json: false, + }, force: true, no_wait_api: false, })) diff --git a/packages/d2b-contracts-control/tests/public_wire.rs b/packages/d2b-contracts-control/tests/public_wire.rs index d3d823892..f16506dbf 100644 --- a/packages/d2b-contracts-control/tests/public_wire.rs +++ b/packages/d2b-contracts-control/tests/public_wire.rs @@ -1,4 +1,4 @@ -use d2b_contracts_control::public_wire::{AuditResponse, PublicRequest}; +use d2b_contracts_control::public_wire::{AuditPageEnd, AuditResponse, PublicRequest}; #[test] fn public_wire_round_trips_strict_request_and_audit_page() { @@ -11,5 +11,5 @@ fn public_wire_round_trips_strict_request_and_audit_page() { "complete": true }); let decoded: AuditResponse = serde_json::from_value(page).expect("page decodes"); - assert!(decoded.complete); + assert_eq!(decoded.page_end, AuditPageEnd::Complete); } diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index a56042ca5..3359e7da6 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -22,7 +22,9 @@ use clap::{Args, CommandFactory, Parser, Subcommand}; use d2b_contracts_broker::AuditExportCursor; use d2b_contracts_control::{ cli_output::{AuthDeniedSubcommandV2, AuthRoleV2, AuthSocketStatusV2, AuthStatusOutputV2}, - public_wire::{self, AuditFormat as IpcAuditFormat, AuditRequest as IpcAuditRequest}, + public_wire::{ + self, AuditFormat as IpcAuditFormat, AuditPageEnd, AuditRequest as IpcAuditRequest, + }, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -428,9 +430,7 @@ fn daemon_audit_frame_with_cursor( crate::context::encode_type_tagged_message(type_name, &request, "audit request") } -fn parse_audit_page( - response: &[u8], -) -> Result<(Vec, Option, bool), CliFailure> { +fn parse_audit_page(response: &[u8]) -> Result<(Vec, AuditPageEnd), CliFailure> { let value = decode_daemon_frame(response, "audit reply")?; let Some(type_name) = value.get("type").and_then(Value::as_str) else { return Err(CliFailure::new( @@ -461,7 +461,7 @@ fn parse_audit_page( }) }) .collect(); - (lines, frame.payload.next_cursor, frame.payload.complete) + (lines, frame.payload.page_end) }) .map_err(|error| { CliFailure::new(1, format!("failed to decode auditResponse: {error}")) @@ -480,7 +480,7 @@ fn parse_audit_page( } pub(crate) fn parse_audit_reply(response: &[u8]) -> Result, CliFailure> { - parse_audit_page(response).map(|(lines, _, _)| lines) + parse_audit_page(response).map(|(lines, _)| lines) } pub(crate) fn render_daemon_audit_lines( @@ -561,17 +561,11 @@ async fn audit_via_socket( .recv_frame(budget) .await .map_err(|error| audit_failure(public_socket, "reply receive", &error))?; - let (page, next_cursor, complete) = parse_audit_page(&response)?; + let (page, page_end) = parse_audit_page(&response)?; lines.extend(page); - if complete { - return Ok(AuditSocketOutcome::Lines(lines)); - } - cursor = next_cursor; - if cursor.is_none() { - return Err(CliFailure::new( - 1, - "audit export pagination omitted continuation metadata", - )); + match page_end { + AuditPageEnd::Complete => return Ok(AuditSocketOutcome::Lines(lines)), + AuditPageEnd::More(next_cursor) => cursor = Some(next_cursor), } } Err(CliFailure::new( diff --git a/packages/d2bd-runtime/src/wire.rs b/packages/d2bd-runtime/src/wire.rs index af9850fcc..e21da22e3 100644 --- a/packages/d2bd-runtime/src/wire.rs +++ b/packages/d2bd-runtime/src/wire.rs @@ -1,7 +1,7 @@ use crate::typed_error::{ErrorEnvelope, TypedError}; use d2b_contracts::{FeatureFlag, Hello, HelloOk, HelloRejected, HelloRejectedReason, Version}; use d2b_contracts_broker::broker_wire::ExportBrokerAuditResponse; -use d2b_contracts_control::public_wire::{self, AuditResponse, AuthStatusResponse}; +use d2b_contracts_control::public_wire::{self, AuditPageEnd, AuditResponse, AuthStatusResponse}; use d2b_contracts_resource::v3::ResourceRef; use semver::{Version as SemverVersion, VersionReq}; use serde::{Deserialize, Serialize}; @@ -458,15 +458,28 @@ pub fn status_response(status: Value) -> Value { json!({ "type": "statusResponse", "status": status }) } -pub fn audit_response(payload: ExportBrokerAuditResponse) -> AuditResponseFrame { - AuditResponseFrame { +/// Build the public audit frame from one broker export page. +/// +/// The broker page's `complete`/`nextCursor` pair is admitted on the broker +/// wire, but a page built in process can still pair an incomplete page with +/// no cursor. That page has no public representation, so it is refused here +/// instead of being reported as final (which would silently end the CLI's +/// pagination). +pub fn audit_response( + payload: ExportBrokerAuditResponse, +) -> Result { + let page_end = AuditPageEnd::from_parts(payload.complete, payload.next_cursor).map_err(|error| { + TypedError::WireInvalidFrame { + detail: format!("broker audit page: {error}"), + } + })?; + Ok(AuditResponseFrame { type_name: "auditResponse", payload: AuditResponse { entries: payload.entries, - next_cursor: payload.next_cursor, - complete: payload.complete, + page_end, }, - } + }) } pub fn usbip_probe_response(payload: public_wire::UsbipProbeResponse) -> Value { @@ -585,7 +598,7 @@ fn map_parse_error(error: serde_json::Error) -> TypedError { #[cfg(test)] mod tests { - use super::{Request, audit_response, parse_request}; + use super::{AuditPageEnd, Request, audit_response, parse_request}; use d2b_contracts_broker::broker_wire::ExportBrokerAuditResponse; use d2b_contracts_broker::{AuditExportCursor, AuditExportEntry}; use serde_json::json; @@ -680,7 +693,7 @@ mod tests { #[test] fn real_d2bd_audit_response_round_trips_through_public_contract() { - let private = ExportBrokerAuditResponse { + let private = || ExportBrokerAuditResponse { entries: vec![AuditExportEntry { sequence: 42, record: Some(json!({"operation": "ApplyNftables"})), @@ -693,8 +706,13 @@ mod tests { }), complete: false, }; - let frame = serde_json::to_value(audit_response(private)) + let frame = serde_json::to_value(audit_response(private()).expect("valid broker page")) .expect("serialize real d2bd audit response"); + assert_eq!( + serde_json::to_string(&audit_response(private()).expect("valid broker page")) + .expect("serialize real d2bd audit response"), + "{\"type\":\"auditResponse\",\"entries\":[{\"sequence\":42,\"record\":{\"operation\":\"ApplyNftables\"}}],\"nextCursor\":{\"day\":\"2026-08-13\",\"line\":41,\"sequence\":41},\"complete\":false}" + ); let mut payload = frame.as_object().expect("audit frame object").clone(); assert_eq!(payload.remove("type"), Some(json!("auditResponse"))); @@ -703,9 +721,24 @@ mod tests { assert_eq!(public.entries.len(), 1); assert_eq!(public.entries[0].sequence, 42); assert_eq!( - public.next_cursor.as_ref().map(|cursor| cursor.line), - Some(41) + public.page_end, + AuditPageEnd::More(AuditExportCursor { + day: "2026-08-13".to_owned(), + line: 41, + sequence: 41, + }) ); - assert!(!public.complete); + } + + #[test] + fn incomplete_broker_audit_page_without_cursor_is_refused() { + let private = ExportBrokerAuditResponse { + entries: Vec::new(), + next_cursor: None, + complete: false, + }; + let error = + audit_response(private).expect_err("an incomplete page must carry its cursor"); + assert_eq!(error.kind(), "wire-invalid-frame"); } } diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index b6c978f80..dc8ec1f8d 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -5321,8 +5321,7 @@ impl d2bd_runtime::autostart::VmStarter for BrokerVmStarter { let request = public_wire::VmLifecycleRequest { vm: vm.to_owned(), flags: public_wire::MutationFlags { - apply: true, - dry_run: false, + mode: public_wire::MutationMode::Apply, json: true, }, force: false, @@ -6856,19 +6855,12 @@ fn dispatch_guest_lifecycle_resource_request( }); } }; - let flags = public_wire::MutationFlags { - dry_run: request - .get("dryRun") - .and_then(Value::as_bool) - .unwrap_or(false), - apply: request - .get("apply") - .and_then(Value::as_bool) - .unwrap_or(false), - json: false, - }; let verb = format!("guest {}", method.to_ascii_lowercase()); - if let Some(response) = mutating_verb_preflight(&verb, &flags, Some(target.name().as_str())) { + let mode = match mutation_mode_from_request(request, &verb) { + Ok(mode) => mode, + Err(response) => return Ok(response), + }; + if let Some(response) = mutating_verb_preflight(&verb, mode, Some(target.name().as_str())) { return Ok(response); } let caller_role = broker_caller_role_for_peer(peer); @@ -7057,19 +7049,12 @@ fn dispatch_process_lifecycle_resource_request( }); } }; - let flags = public_wire::MutationFlags { - dry_run: request - .get("dryRun") - .and_then(Value::as_bool) - .unwrap_or(false), - apply: request - .get("apply") - .and_then(Value::as_bool) - .unwrap_or(false), - json: false, - }; let verb = format!("process {}", method.to_ascii_lowercase()); - if let Some(response) = mutating_verb_preflight(&verb, &flags, Some(target.name().as_str())) { + let mode = match mutation_mode_from_request(request, &verb) { + Ok(mode) => mode, + Err(response) => return Ok(response), + }; + if let Some(response) = mutating_verb_preflight(&verb, mode, Some(target.name().as_str())) { return Ok(response); } let base_operation_id = @@ -7223,17 +7208,11 @@ fn dispatch_device_usb_resource_request( .ok_or_else(|| TypedError::WireInvalidFrame { detail: "Device USB request requires busId".to_owned(), })?; - let flags = public_wire::MutationFlags { - dry_run: request - .get("dryRun") - .and_then(Value::as_bool) - .unwrap_or(false), - apply: request - .get("apply") - .and_then(Value::as_bool) - .unwrap_or(false), - json: false, + let mode = match mutation_mode_from_request(request, verb) { + Ok(mode) => mode, + Err(response) => return Ok(response), }; + let flags = public_wire::MutationFlags { mode, json: false }; match method { "DeviceUsbAttach" => dispatch_broker_usbip_bind( state, @@ -9317,12 +9296,6 @@ fn dispatch_broker_usbip_bind( request: public_wire::UsbipBindCliRequest, ) -> Result { const VERB: &str = "usb attach"; - if !request.flags.dry_run && !request.flags.apply { - return Ok( - mutating_verb_preflight(VERB, &request.flags, Some(request.vm.as_str())) - .expect("missing mutation flags produce a preflight response"), - ); - } let resolver = load_bundle_resolver(state)?; ensure_manifest_entry_runtime_capability( resolver.manifest.vms.get(&request.vm), @@ -9332,7 +9305,7 @@ fn dispatch_broker_usbip_bind( )?; if vm_is_qemu_media(state, &resolver, &request.vm)? { if let Some(response) = - mutating_verb_preflight(VERB, &request.flags, Some(request.vm.as_str())) + mutating_verb_preflight(VERB, request.flags.mode, Some(request.vm.as_str())) { return Ok(response); } @@ -9359,12 +9332,6 @@ fn dispatch_broker_usbip_unbind( request: public_wire::UsbipUnbindCliRequest, ) -> Result { const VERB: &str = "usb detach"; - if !request.flags.dry_run && !request.flags.apply { - return Ok( - mutating_verb_preflight(VERB, &request.flags, Some(request.vm.as_str())) - .expect("missing mutation flags produce a preflight response"), - ); - } let resolver = load_bundle_resolver(state)?; ensure_manifest_entry_runtime_capability( resolver.manifest.vms.get(&request.vm), @@ -9374,7 +9341,7 @@ fn dispatch_broker_usbip_unbind( )?; if vm_is_qemu_media(state, &resolver, &request.vm)? { if let Some(response) = - mutating_verb_preflight(VERB, &request.flags, Some(request.vm.as_str())) + mutating_verb_preflight(VERB, request.flags.mode, Some(request.vm.as_str())) { return Ok(response); } @@ -10177,44 +10144,67 @@ fn qemu_media_probe_entry( } } +/// The mutating mode of a raw public request frame. +/// +/// These frames never pass through the typed +/// [`d2b_contracts_control::public_wire::MutationFlags`] admission, so the +/// `dryRun`/`apply` pair is parsed here. A frame that selects neither mode has +/// no mode: it keeps the documented `invalid-request` refusal envelope instead +/// of a decode failure. +fn mutation_mode_from_request( + request: &Value, + verb: &str, +) -> Result { + let dry_run = request + .get("dryRun") + .and_then(Value::as_bool) + .unwrap_or(false); + let apply = request + .get("apply") + .and_then(Value::as_bool) + .unwrap_or(false); + d2b_contracts_control::public_wire::MutationMode::from_flags(dry_run, apply).map_err(|_| { + invalid_request_response( + verb, + format!("d2b {verb} requires either --dry-run or --apply"), + ) + }) +} + +/// One mutating-verb preflight response: the daemon-side plan for a dry run, +/// or `None` for an apply request that proceeds to dispatch. +/// +/// The mode is closed, so the "neither flag set" refusal the pair used to need +/// has no case here; raw request frames are refused at +/// [`mutation_mode_from_request`]. fn mutating_verb_preflight( verb: &str, - flags: &d2b_contracts_control::public_wire::MutationFlags, + mode: d2b_contracts_control::public_wire::MutationMode, target_vm: Option<&str>, ) -> Option { - use d2b_contracts_control::public_wire::{MutatingVerbOutcome, MutatingVerbResponse}; - - if !flags.dry_run && !flags.apply { - return Some(d2bd_runtime::wire::mutating_verb_response( - MutatingVerbResponse { - verb: verb.to_owned(), - outcome: MutatingVerbOutcome::InvalidRequest, - target_wave: None, - summary: None, - remediation: Some(format!("d2b {verb} requires either --dry-run or --apply")), - api_ready: None, - }, - )); - } + use d2b_contracts_control::public_wire::{ + MutationMode, MutatingVerbOutcome, MutatingVerbResponse, + }; - if flags.dry_run { - let summary = match target_vm { - Some(vm) => format!("d2b {verb} --dry-run: daemon-side plan for vm '{vm}'"), - None => format!("d2b {verb} --dry-run: daemon-side plan"), - }; - return Some(d2bd_runtime::wire::mutating_verb_response( - MutatingVerbResponse { - verb: verb.to_owned(), - outcome: MutatingVerbOutcome::DryRunPlanned, - target_wave: None, - summary: Some(summary), - remediation: None, - api_ready: None, - }, - )); + match mode { + MutationMode::Apply => None, + MutationMode::DryRun => { + let summary = match target_vm { + Some(vm) => format!("d2b {verb} --dry-run: daemon-side plan for vm '{vm}'"), + None => format!("d2b {verb} --dry-run: daemon-side plan"), + }; + Some(d2bd_runtime::wire::mutating_verb_response( + MutatingVerbResponse { + verb: verb.to_owned(), + outcome: MutatingVerbOutcome::DryRunPlanned, + target_wave: None, + summary: Some(summary), + remediation: None, + api_ready: None, + }, + )) + } } - - None } pub(crate) fn broker_socket_path(state: &ServerState) -> PathBuf { @@ -18677,7 +18667,7 @@ fn dispatch_broker_vm_start_as( ) -> Result { const VERB: &str = "vm start"; - if let Some(response) = mutating_verb_preflight(VERB, &request.flags, Some(request.vm.as_str())) + if let Some(response) = mutating_verb_preflight(VERB, request.flags.mode, Some(request.vm.as_str())) { return Ok(response); } @@ -19007,12 +18997,11 @@ fn next_provider_lifecycle_operation_id( operation: &str, request: &public_wire::VmLifecycleRequest, ) -> String { + let (dry_run, apply) = request.flags.mode.to_flags(); let fingerprint = format!( - "force={};no_wait_api={};dry_run={};apply={};json={}", + "force={};no_wait_api={};dry_run={dry_run};apply={apply};json={}", request.force, request.no_wait_api, - request.flags.dry_run, - request.flags.apply, request.flags.json ); provider_registry::next_lifecycle_operation_id(operation, &request.vm, &fingerprint) @@ -19811,7 +19800,7 @@ fn dispatch_broker_vm_stop_with_timeout_as( ) -> Result { const VERB: &str = "vm stop"; - if let Some(response) = mutating_verb_preflight(VERB, &request.flags, Some(request.vm.as_str())) + if let Some(response) = mutating_verb_preflight(VERB, request.flags.mode, Some(request.vm.as_str())) { return Ok(response); } @@ -20039,7 +20028,7 @@ fn dispatch_broker_vm_restart_as( ) -> Result { const VERB: &str = "vm restart"; - if let Some(response) = mutating_verb_preflight(VERB, &request.flags, Some(request.vm.as_str())) + if let Some(response) = mutating_verb_preflight(VERB, request.flags.mode, Some(request.vm.as_str())) { return Ok(response); } @@ -20070,7 +20059,7 @@ fn dispatch_broker_host_prepare_as( ) -> Result { const VERB: &str = "host prepare"; - if let Some(response) = mutating_verb_preflight(VERB, &request.flags, None) { + if let Some(response) = mutating_verb_preflight(VERB, request.flags.mode, None) { return Ok(response); } // U12: the retired typed ApplyNftables arm's core is the @@ -20148,7 +20137,7 @@ fn dispatch_broker_host_destroy_as( ) -> Result { const VERB: &str = "host destroy"; - if let Some(response) = mutating_verb_preflight(VERB, &request.flags, None) { + if let Some(response) = mutating_verb_preflight(VERB, request.flags.mode, None) { return Ok(response); } // U12: the retired typed ApplyNmUnmanaged / ApplyNftables arms' cores @@ -20221,7 +20210,7 @@ fn dispatch_broker_host_reconcile_as( ) -> Result { const VERB: &str = "host reconcile"; - if let Some(response) = mutating_verb_preflight(VERB, &request.flags, None) { + if let Some(response) = mutating_verb_preflight(VERB, request.flags.mode, None) { return Ok(response); } if !request.network { @@ -20500,7 +20489,7 @@ fn dispatch_broker_activation( mode: DaemonActivationMode, caller_role: BrokerCallerRole, ) -> Result { - if let Some(response) = mutating_verb_preflight(verb, &request.flags, Some(request.vm.as_str())) + if let Some(response) = mutating_verb_preflight(verb, request.flags.mode, Some(request.vm.as_str())) { return Ok(response); } @@ -22806,7 +22795,10 @@ mod public_status_tests { state: &state, request: public_wire::VmLifecycleRequest { vm: "vm-a".to_owned(), - flags: public_wire::MutationFlags::default(), + flags: public_wire::MutationFlags { + mode: public_wire::MutationMode::Apply, + json: false, + }, force: false, no_wait_api: false, }, @@ -22935,11 +22927,10 @@ fn dispatch_audit( )?; match response { BrokerResponse::ExportBrokerAudit(payload) => { - serde_json::to_value(d2bd_runtime::wire::audit_response(payload)).map_err(|err| { - TypedError::InternalIo { - context: "serialize audit response".to_owned(), - detail: err.to_string(), - } + let frame = d2bd_runtime::wire::audit_response(payload)?; + serde_json::to_value(frame).map_err(|err| TypedError::InternalIo { + context: "serialize audit response".to_owned(), + detail: err.to_string(), }) } BrokerResponse::Error(error) => Err(TypedError::InternalBrokerUnavailable { @@ -24190,7 +24181,7 @@ mod broker_dispatch_tests { }; use d2b_contracts_control::public_wire; use d2b_contracts_control::public_wire::{ - ActivationRequest, HostDestroyRequest, HostPrepareRequest, MutationFlags, + ActivationRequest, HostDestroyRequest, HostPrepareRequest, MutationFlags, MutationMode, ShellSessionState, VmLifecycleRequest, }; use d2b_contracts_resource::v3::{ResourceGeneration, ResourceUid}; @@ -24203,6 +24194,7 @@ mod broker_dispatch_tests { use serde::Serialize; use serde_json::{Value, json}; + use super::mutation_mode_from_request; use super::provider_effects::LifecycleAuthorization; use super::provider_shutdown::GracefulVmShutdown; use super::{ @@ -24231,6 +24223,32 @@ mod broker_dispatch_tests { static NEXT_TEST_ID: AtomicU64 = AtomicU64::new(0); + #[test] + fn raw_mutating_verb_frames_keep_the_documented_mode_refusal() { + let bare = json!({"type": "resourceRequest", "method": "Start"}); + let refusal = mutation_mode_from_request(&bare, "guest start") + .expect_err("a frame that selects no mode is refused"); + assert_eq!( + refusal.get("outcome").and_then(Value::as_str), + Some("invalid-request") + ); + assert_eq!( + refusal.get("remediation").and_then(Value::as_str), + Some("d2b guest start requires either --dry-run or --apply") + ); + + assert_eq!( + mutation_mode_from_request(&json!({"dryRun": true}), "guest start") + .expect("dryRun selects a mode"), + MutationMode::DryRun + ); + assert_eq!( + mutation_mode_from_request(&json!({"apply": true}), "guest start") + .expect("apply selects a mode"), + MutationMode::Apply + ); + } + // Serializes tests that must read-modify-write process env vars so parallel // test threads don't observe each other's transient env state. @@ -25173,8 +25191,8 @@ mod broker_dispatch_tests { d2bd_runtime::wire::Request::VmStart(VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, force: false, no_wait_api: false, @@ -25185,8 +25203,8 @@ mod broker_dispatch_tests { d2bd_runtime::wire::Request::VmStop(VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, force: false, no_wait_api: false, @@ -25197,8 +25215,8 @@ mod broker_dispatch_tests { d2bd_runtime::wire::Request::VmRestart(VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, force: false, no_wait_api: false, @@ -25210,8 +25228,8 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }), ), @@ -25221,8 +25239,8 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }), ), @@ -25232,8 +25250,8 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }), ), @@ -25243,8 +25261,8 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }), ), @@ -25255,8 +25273,8 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), bus_id: "1-1".to_owned(), flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }, ), @@ -25268,8 +25286,8 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), bus_id: "1-1".to_owned(), flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }, ), @@ -25278,8 +25296,8 @@ mod broker_dispatch_tests { "hostPrepare", d2bd_runtime::wire::Request::HostPrepare(HostPrepareRequest { flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }), ), @@ -25287,8 +25305,8 @@ mod broker_dispatch_tests { "hostDestroy", d2bd_runtime::wire::Request::HostDestroy(HostDestroyRequest { flags: MutationFlags { - dry_run: true, - ..MutationFlags::default() + mode: MutationMode::DryRun, + json: false, }, }), ), @@ -25545,8 +25563,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -25751,8 +25769,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -26081,8 +26099,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -26383,8 +26401,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -26429,8 +26447,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -26468,8 +26486,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27210,8 +27228,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27256,8 +27274,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27400,8 +27418,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27536,8 +27554,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27677,8 +27695,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27784,8 +27802,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27799,8 +27817,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27836,8 +27854,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27890,8 +27908,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27928,8 +27946,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -27967,8 +27985,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -28018,8 +28036,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -28129,8 +28147,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -28332,8 +28350,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, no_wait_api: false, @@ -28358,8 +28376,8 @@ mod broker_dispatch_tests { &state, HostPrepareRequest { flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, }, BrokerCallerRole::AdminUid { uid: state.daemon_uid }, @@ -28490,8 +28508,8 @@ mod broker_dispatch_tests { &state, HostPrepareRequest { flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, }, BrokerCallerRole::AdminUid { uid: state.daemon_uid }, @@ -28694,8 +28712,8 @@ mod broker_dispatch_tests { &state, HostDestroyRequest { flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, }, BrokerCallerRole::AdminUid { uid: state.daemon_uid }, @@ -28738,8 +28756,8 @@ mod broker_dispatch_tests { &state, HostDestroyRequest { flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, }, BrokerCallerRole::AdminUid { uid: state.daemon_uid }, @@ -29957,8 +29975,8 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "obs".to_owned(), flags: MutationFlags { - apply: true, - ..MutationFlags::default() + mode: MutationMode::Apply, + json: false, }, force: false, // Bypass the readiness gate entirely: no degraded field must From e9cb637c3651113b5208fc048b7466b998866252 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:26:06 -0700 Subject: [PATCH 643/726] refactor(d2b-contracts-control): type the status DTO state vocabularies RS-0249: the status DTOs that mirrored daemon-side vocabularies as free-form `String` fields now carry closed kebab-case enums whose serde names match the emitted wire strings, so no emitted byte moves. - `RealmMode` types `RealmPolicyOutputV1.mode` and `OpInspectRealmOutputV1.mode` (host-resident | gateway-backed, the two modes ADR-046-cli-and-operations.md records for a realm entrypoint); `RealmGatewayState` types `RealmPolicyOutputV1.gateway_state` and `OpInspectRealmOutputV1.state` and keeps every value the retired realm producer emitted, including the `not reported by d2bd` sentinel as a renamed variant. - `QemuMediaRunnerState` types `QemuMediaRunnerStatus.state` (running | stopped, the pidfd liveness projection), `QemuMediaRegistryState` types `QemuMediaRegistryStatus.state` (direct-config | present | stale | missing), `PublicReadModelKind` types `PublicReadModelMetadata.kind` (list | status), and `VmAutostartMode` types `VmAutostartPosture.mode` (manual-only). RS-0332: the dead `AuditEntry` wire type is deleted. It had no emitter and no consumer: the live public `AuditResponse` carries `AuditExportEntry` pages, and no crate constructs or deserializes it. Co-change list: producers - none (nothing emitted it); consumers - none in-tree; schema - the frozen docs/reference/schemas/v1/wire-protocol.json keeps its own `AuditEntry` definition for the historical v1 `AuditResponse` shape and is not touched, while the generated v2 schema and the generated daemon-api.md tables never contained the type (regeneration is a no-op, proven by gen_schemas_drift and gen_daemon_api_drift); docs - docs/reference/daemon-api.md:791 names the broker's own JSONL `AuditEntry` write path, not this wire type; goldens - none reference it. No consumer outside this tree observes the deleted shape: the daemon already emits the `AuditExportEntry` page shape. Co-change list for RS-0249: - producers/emitters: d2bd-runtime/src/public_projection.rs (the autostart posture emits `VmAutostartMode`, the new `public_qemu_media_runner_state` derives the typed runner state from the pidfd table, and the pidfd liveness predicate is factored out of the string projection); d2bd-runtime/src/public_read_model.rs (the read-model metadata publishes `PublicReadModelKind`; the crate-local duplicate enum and the parallel `kind_name` string are deleted); d2bd/src/composition.rs (`public_qemu_media_status` takes the runner state from the pidfd table instead of the services map, `qemu_media_registry_state` returns the typed state, and the status publisher no longer threads a `kind_name` string). - consumers: none in-tree. The retired realm and op-inspect CLI producers that populated the realm rows are gone, no crate deserializes the daemon status DTOs, and the two qemu-media tests assert the emitted strings. - schema: docs/reference/cli-output/status.schema.json, docs/reference/cli-output/op-inspect.schema.json, docs/reference/cli-output/list.schema.json and docs/reference/schemas/v2/wire-protocol.json are regenerated with the xtask gen commands, replacing `"type": "string"` cells with enum-constrained `$ref`s; the frozen v1 schema is untouched. - docs: docs/reference/daemon-api.md is regenerated (new enum table rows); its read model section already stated `kind` is `list` or `status`, and docs/reference/cli-output/status.md already shows `"kind": "status"`. - goldens: tests/golden/cli-output/* are byte-unchanged, because no in-tree producer emits these fields any more. Outside this tree: the daemon's public list/status JSON is parsed by out-of-tree CLI consumers. Every value the daemon emits today is unchanged (the kebab spellings are preserved), so no consumer observes a different payload, but their deserialization is now closed over these vocabularies instead of accepting any string. Changelog: changelog.d/w6-11-status-dto-enums.md Gates run on this worktree: - cargo test -p d2b-contracts-control (36 lib + 1 integration test pass) - cargo test -p d2bd-runtime (458 + 2 tests pass) - cargo test -p d2bd status (25 + 1 tests pass) - cargo check -p d2b-contracts-control --all-targets - cargo check -p d2bd and cargo check -p d2bd --all-targets - nix develop -c bazel test --cache_test_results=no //packages/xtask:gen_cli_schemas_drift //packages/xtask:gen_schemas_drift //packages/xtask:gen_daemon_api_drift (3 of 3 pass) --- changelog.d/w6-11-status-dto-enums.md | 20 +++ docs/reference/cli-output/list.schema.json | 71 ++++++++++- .../cli-output/op-inspect.schema.json | 98 ++++++++++++++- docs/reference/cli-output/status.schema.json | 92 +++++++++++++- docs/reference/daemon-api.md | 34 ++--- docs/reference/schemas/v2/wire-protocol.json | 92 +++++++++++++- .../d2b-contracts-control/src/cli_output.rs | 56 ++++++++- .../d2b-contracts-control/src/public_wire.rs | 117 ++++++++++++++++-- .../d2bd-runtime/src/public_projection.rs | 41 +++++- .../d2bd-runtime/src/public_read_model.rs | 26 ++-- packages/d2bd/src/composition.rs | 73 +++++------ 11 files changed, 611 insertions(+), 109 deletions(-) create mode 100644 changelog.d/w6-11-status-dto-enums.md diff --git a/changelog.d/w6-11-status-dto-enums.md b/changelog.d/w6-11-status-dto-enums.md new file mode 100644 index 000000000..0f8eb17fc --- /dev/null +++ b/changelog.d/w6-11-status-dto-enums.md @@ -0,0 +1,20 @@ +### Changed + +- d2b-contracts-control: the status DTOs that carried daemon-side vocabularies + as free-form strings now use closed kebab-case enums, and the serde names + match the emitted wire strings so no emitted byte moves. `RealmMode` and + `RealmGatewayState` type the realm rows (`RealmPolicyOutputV1`, + `OpInspectRealmOutputV1`; the historical `not reported by d2bd` sentinel + stays representable), `QemuMediaRunnerState` and `QemuMediaRegistryState` + type the guest-media status, `PublicReadModelKind` types + `PublicReadModelMetadata.kind`, and `VmAutostartMode` types + `VmAutostartPosture.mode`. The generated CLI schemas, the v2 wire-protocol + schema, and the `daemon-api.md` enum table move with the change; the frozen + v1 schema and the CLI output goldens are untouched. +- d2bd and d2bd-runtime: the daemon-side producers emit those vocabularies + through the shared contract types instead of string literals. The read-model + metadata publishes `PublicReadModelKind` directly (the crate-local duplicate + enum and the parallel `kind_name` string are gone), the qemu-media runner + state comes from the pidfd-table liveness helper, and the media registry + state and autostart posture are typed where they are emitted. The daemon's + public list/status JSON is byte-identical. diff --git a/docs/reference/cli-output/list.schema.json b/docs/reference/cli-output/list.schema.json index 55bdf30bd..54e4f0318 100644 --- a/docs/reference/cli-output/list.schema.json +++ b/docs/reference/cli-output/list.schema.json @@ -114,8 +114,40 @@ }, "additionalProperties": false }, + "QemuMediaRegistryState": { + "description": "The media probe registry's convergence state for one attached source.\n\n`state` used to be a free-form `String`; the daemon classifies every source into exactly these four states, so both the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The source is declared as `direct-config` and needs no probe record.", + "type": "string", + "enum": [ + "direct-config" + ] + }, + { + "description": "A probe record matches the current declaration.", + "type": "string", + "enum": [ + "present" + ] + }, + { + "description": "A probe record exists but does not match the declaration.", + "type": "string", + "enum": [ + "stale" + ] + }, + { + "description": "No probe record exists for the declared source.", + "type": "string", + "enum": [ + "missing" + ] + } + ] + }, "QemuMediaRegistryStatus": { - "description": "The media registry's convergence state for one source.", "type": "object", "required": [ "state" @@ -128,11 +160,30 @@ ] }, "state": { - "type": "string" + "$ref": "#/definitions/QemuMediaRegistryState" } }, "additionalProperties": false }, + "QemuMediaRunnerState": { + "description": "Liveness of the qemu-media runner process the daemon projects.\n\n`state` used to be a free-form `String`; the daemon derives it from the pidfd table, which reports a role as running while its recorded process is alive at the same start time and stopped otherwise, so the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The registered runner process is alive.", + "type": "string", + "enum": [ + "running" + ] + }, + { + "description": "No live runner process is registered for the VM.", + "type": "string", + "enum": [ + "stopped" + ] + } + ] + }, "QemuMediaRunnerStatus": { "description": "Runner-side QMP media state for one VM.", "type": "object", @@ -155,7 +206,7 @@ "type": "string" }, "state": { - "type": "string" + "$ref": "#/definitions/QemuMediaRunnerState" } }, "additionalProperties": false @@ -217,6 +268,18 @@ }, "additionalProperties": false }, + "VmAutostartMode": { + "description": "How the daemon's autostart pass treats a VM that carries an autostart row.\n\n`mode` used to be a free-form `String`. The daemon emits a row only for VMs the pass refuses to start on its own, so the vocabulary has a single member today; a future posture is an additive variant here rather than a new string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "Autostart skips this VM; the operator starts it explicitly.", + "type": "string", + "enum": [ + "manual-only" + ] + } + ] + }, "VmAutostartPosture": { "description": "Whether a VM is set to autostart, with the reason.", "type": "object", @@ -226,7 +289,7 @@ ], "properties": { "mode": { - "type": "string" + "$ref": "#/definitions/VmAutostartMode" }, "reason": { "type": "string" diff --git a/docs/reference/cli-output/op-inspect.schema.json b/docs/reference/cli-output/op-inspect.schema.json index e19d989e3..c64723597 100644 --- a/docs/reference/cli-output/op-inspect.schema.json +++ b/docs/reference/cli-output/op-inspect.schema.json @@ -107,13 +107,13 @@ ] }, "mode": { - "type": "string" + "$ref": "#/definitions/RealmMode" }, "realm": { "type": "string" }, "state": { - "type": "string" + "$ref": "#/definitions/RealmGatewayState" } }, "additionalProperties": false @@ -134,6 +134,100 @@ } }, "additionalProperties": false + }, + "RealmGatewayState": { + "description": "The gateway-side state of a realm row.\n\n`gateway_state` and `state` used to be free-form `String`s carrying the gateway guest's lifecycle label; the field is `local-only` for a host-resident realm, the daemon's lifecycle state for a gateway-backed realm whose gateway the daemon listed, and the preserved sentinel string when the daemon did not list the gateway at all.", + "oneOf": [ + { + "description": "The realm has no gateway hop; it is dispatched on this host.", + "type": "string", + "enum": [ + "local-only" + ] + }, + { + "description": "The gateway guest is stopped.", + "type": "string", + "enum": [ + "stopped" + ] + }, + { + "description": "The gateway guest is starting.", + "type": "string", + "enum": [ + "starting" + ] + }, + { + "description": "The gateway guest has booted.", + "type": "string", + "enum": [ + "booted" + ] + }, + { + "description": "The gateway guest is running.", + "type": "string", + "enum": [ + "running" + ] + }, + { + "description": "The gateway guest is stopping.", + "type": "string", + "enum": [ + "stopping" + ] + }, + { + "description": "The gateway guest is restarting.", + "type": "string", + "enum": [ + "restarting" + ] + }, + { + "description": "The gateway guest failed its last lifecycle transition.", + "type": "string", + "enum": [ + "failed" + ] + }, + { + "description": "The daemon reported the gateway guest's lifecycle as unknown.", + "type": "string", + "enum": [ + "unknown" + ] + }, + { + "description": "The daemon's list response did not include the gateway VM.", + "type": "string", + "enum": [ + "not reported by d2bd" + ] + } + ] + }, + "RealmMode": { + "description": "How a realm's entrypoint is dispatched.\n\n`mode` used to be a free-form `String`; the realm entrypoint table admits exactly two modes, so both the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The realm entrypoint runs on the local daemon.", + "type": "string", + "enum": [ + "host-resident" + ] + }, + { + "description": "A gateway guest fronts the realm and owns its policy.", + "type": "string", + "enum": [ + "gateway-backed" + ] + } + ] } } } diff --git a/docs/reference/cli-output/status.schema.json b/docs/reference/cli-output/status.schema.json index fed983ee0..be39bc02c 100644 --- a/docs/reference/cli-output/status.schema.json +++ b/docs/reference/cli-output/status.schema.json @@ -124,6 +124,25 @@ }, "additionalProperties": false }, + "PublicReadModelKind": { + "description": "Which public response frame the daemon's cached read model describes.\n\n`kind` used to be a free-form `String`; the daemon publishes exactly two frames, the unfiltered `list` and `status` responses, so both the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The unfiltered public `list` frame.", + "type": "string", + "enum": [ + "list" + ] + }, + { + "description": "The unfiltered public `status` frame.", + "type": "string", + "enum": [ + "status" + ] + } + ] + }, "PublicReadModelMetadata": { "type": "object", "required": [ @@ -148,7 +167,7 @@ "minimum": 0.0 }, "kind": { - "type": "string" + "$ref": "#/definitions/PublicReadModelKind" }, "schemaVersion": { "type": "integer", @@ -166,8 +185,40 @@ }, "additionalProperties": false }, + "QemuMediaRegistryState": { + "description": "The media probe registry's convergence state for one attached source.\n\n`state` used to be a free-form `String`; the daemon classifies every source into exactly these four states, so both the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The source is declared as `direct-config` and needs no probe record.", + "type": "string", + "enum": [ + "direct-config" + ] + }, + { + "description": "A probe record matches the current declaration.", + "type": "string", + "enum": [ + "present" + ] + }, + { + "description": "A probe record exists but does not match the declaration.", + "type": "string", + "enum": [ + "stale" + ] + }, + { + "description": "No probe record exists for the declared source.", + "type": "string", + "enum": [ + "missing" + ] + } + ] + }, "QemuMediaRegistryStatus": { - "description": "The media registry's convergence state for one source.", "type": "object", "required": [ "state" @@ -180,11 +231,30 @@ ] }, "state": { - "type": "string" + "$ref": "#/definitions/QemuMediaRegistryState" } }, "additionalProperties": false }, + "QemuMediaRunnerState": { + "description": "Liveness of the qemu-media runner process the daemon projects.\n\n`state` used to be a free-form `String`; the daemon derives it from the pidfd table, which reports a role as running while its recorded process is alive at the same start time and stopped otherwise, so the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The registered runner process is alive.", + "type": "string", + "enum": [ + "running" + ] + }, + { + "description": "No live runner process is registered for the VM.", + "type": "string", + "enum": [ + "stopped" + ] + } + ] + }, "QemuMediaRunnerStatus": { "description": "Runner-side QMP media state for one VM.", "type": "object", @@ -207,7 +277,7 @@ "type": "string" }, "state": { - "type": "string" + "$ref": "#/definitions/QemuMediaRunnerState" } }, "additionalProperties": false @@ -910,6 +980,18 @@ }, "additionalProperties": false }, + "VmAutostartMode": { + "description": "How the daemon's autostart pass treats a VM that carries an autostart row.\n\n`mode` used to be a free-form `String`. The daemon emits a row only for VMs the pass refuses to start on its own, so the vocabulary has a single member today; a future posture is an additive variant here rather than a new string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "Autostart skips this VM; the operator starts it explicitly.", + "type": "string", + "enum": [ + "manual-only" + ] + } + ] + }, "VmAutostartPosture": { "description": "Whether a VM is set to autostart, with the reason.", "type": "object", @@ -919,7 +1001,7 @@ ], "properties": { "mode": { - "type": "string" + "$ref": "#/definitions/VmAutostartMode" }, "reason": { "type": "string" diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 22ecdadb6..d1751204d 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -382,8 +382,8 @@ see the auto-generated tables above for the committed Rust variants. | `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2149) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | | `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2158) | struct { `vms`: `Vec`; `read_model`: `Option` } | | `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2166) | struct { `entries`: `Vec`; `read_model`: `Option` } | -| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2186) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2474) | struct { `entries`: `Vec` } | +| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2201) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2489) | struct { `entries`: `Vec` } | ### Broker socket response types @@ -490,7 +490,7 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2640) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | +| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2655) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | ### Other documented enums @@ -539,18 +539,22 @@ running live guest activation. | `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1959) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | | `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2022) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | | `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2128) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | -| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2233) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | -| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2251) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | -| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2276) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | -| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2289) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | -| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2303) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | -| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2326) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | -| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2344) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | -| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2357) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | -| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2376) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | -| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2412) | `Usbip`; `QemuMediaSlot` | -| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2495) | `Human`; `Json` | -| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2503) | `None`; `Launcher`; `Admin` | +| `PublicReadModelKind` | enum | [`PublicReadModelKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2192) | `List`; `Status` | +| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2248) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | +| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2266) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | +| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2291) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | +| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2304) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | +| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2318) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | +| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2341) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | +| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2359) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | +| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2372) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | +| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2391) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | +| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2427) | `Usbip`; `QemuMediaSlot` | +| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2510) | `Human`; `Json` | +| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2518) | `None`; `Launcher`; `Admin` | +| `VmAutostartMode` | enum | [`VmAutostartMode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2698) | `ManualOnly` | +| `QemuMediaRunnerState` | enum | [`QemuMediaRunnerState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2732) | `Running`; `Stopped` | +| `QemuMediaRegistryState` | enum | [`QemuMediaRegistryState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2767) | `DirectConfig`; `Present`; `Stale`; `Missing` | | `TerminalStream` | enum | [`TerminalStream`](../../packages/d2b-contracts-control/src/terminal_wire.rs#L13) | `Stdout`; `Stderr` | | `HelperScopeKind` | enum | [`HelperScopeKind`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L68) | `LauncherApp`; `WaylandProxy` | | `HelperScopeState` | enum | [`HelperScopeState`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L95) | `Starting`; `Active`; `Stopping`; `Exited`; `Degraded` | diff --git a/docs/reference/schemas/v2/wire-protocol.json b/docs/reference/schemas/v2/wire-protocol.json index 6015cb158..3404d3dc0 100644 --- a/docs/reference/schemas/v2/wire-protocol.json +++ b/docs/reference/schemas/v2/wire-protocol.json @@ -5750,6 +5750,25 @@ "minLength": 1, "pattern": "^[\\x21-\\x7e]+$" }, + "PublicReadModelKind": { + "description": "Which public response frame the daemon's cached read model describes.\n\n`kind` used to be a free-form `String`; the daemon publishes exactly two frames, the unfiltered `list` and `status` responses, so both the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The unfiltered public `list` frame.", + "type": "string", + "enum": [ + "list" + ] + }, + { + "description": "The unfiltered public `status` frame.", + "type": "string", + "enum": [ + "status" + ] + } + ] + }, "PublicReadModelMetadata": { "type": "object", "required": [ @@ -5774,7 +5793,7 @@ "minimum": 0.0 }, "kind": { - "type": "string" + "$ref": "#/definitions/PublicReadModelKind" }, "schemaVersion": { "type": "integer", @@ -6897,8 +6916,40 @@ }, "additionalProperties": false }, + "QemuMediaRegistryState": { + "description": "The media probe registry's convergence state for one attached source.\n\n`state` used to be a free-form `String`; the daemon classifies every source into exactly these four states, so both the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The source is declared as `direct-config` and needs no probe record.", + "type": "string", + "enum": [ + "direct-config" + ] + }, + { + "description": "A probe record matches the current declaration.", + "type": "string", + "enum": [ + "present" + ] + }, + { + "description": "A probe record exists but does not match the declaration.", + "type": "string", + "enum": [ + "stale" + ] + }, + { + "description": "No probe record exists for the declared source.", + "type": "string", + "enum": [ + "missing" + ] + } + ] + }, "QemuMediaRegistryStatus": { - "description": "The media registry's convergence state for one source.", "type": "object", "required": [ "state" @@ -6911,11 +6962,30 @@ ] }, "state": { - "type": "string" + "$ref": "#/definitions/QemuMediaRegistryState" } }, "additionalProperties": false }, + "QemuMediaRunnerState": { + "description": "Liveness of the qemu-media runner process the daemon projects.\n\n`state` used to be a free-form `String`; the daemon derives it from the pidfd table, which reports a role as running while its recorded process is alive at the same start time and stopped otherwise, so the wire protocol and the generated CLI schema carry enum constraints rather than a free-form string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "The registered runner process is alive.", + "type": "string", + "enum": [ + "running" + ] + }, + { + "description": "No live runner process is registered for the VM.", + "type": "string", + "enum": [ + "stopped" + ] + } + ] + }, "QemuMediaRunnerStatus": { "description": "Runner-side QMP media state for one VM.", "type": "object", @@ -6938,7 +7008,7 @@ "type": "string" }, "state": { - "type": "string" + "$ref": "#/definitions/QemuMediaRunnerState" } }, "additionalProperties": false @@ -8658,6 +8728,18 @@ "description": "Semantic version string used by the daemon and clients, for example `0.4.0`.", "type": "string" }, + "VmAutostartMode": { + "description": "How the daemon's autostart pass treats a VM that carries an autostart row.\n\n`mode` used to be a free-form `String`. The daemon emits a row only for VMs the pass refuses to start on its own, so the vocabulary has a single member today; a future posture is an additive variant here rather than a new string. Serde names match the canonical wire strings exactly.", + "oneOf": [ + { + "description": "Autostart skips this VM; the operator starts it explicitly.", + "type": "string", + "enum": [ + "manual-only" + ] + } + ] + }, "VmAutostartPosture": { "description": "Whether a VM is set to autostart, with the reason.", "type": "object", @@ -8667,7 +8749,7 @@ ], "properties": { "mode": { - "type": "string" + "$ref": "#/definitions/VmAutostartMode" }, "reason": { "type": "string" diff --git a/packages/d2b-contracts-control/src/cli_output.rs b/packages/d2b-contracts-control/src/cli_output.rs index a67e77e78..a768fb893 100644 --- a/packages/d2b-contracts-control/src/cli_output.rs +++ b/packages/d2b-contracts-control/src/cli_output.rs @@ -103,13 +103,61 @@ pub struct OpInspectLocalOutputV1 { /// One realm's view in `op inspect` output. pub struct OpInspectRealmOutputV1 { pub realm: String, - pub mode: String, + pub mode: RealmMode, #[serde(skip_serializing_if = "Option::is_none")] pub gateway_vm: Option, - pub state: String, + pub state: RealmGatewayState, pub cross_realm_policy: String, } +/// How a realm's entrypoint is dispatched. +/// +/// `mode` used to be a free-form `String`; the realm entrypoint table admits +/// exactly two modes, so both the wire protocol and the generated CLI schema +/// carry enum constraints rather than a free-form string. Serde names match +/// the canonical wire strings exactly. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum RealmMode { + /// The realm entrypoint runs on the local daemon. + HostResident, + /// A gateway guest fronts the realm and owns its policy. + GatewayBacked, +} + +/// The gateway-side state of a realm row. +/// +/// `gateway_state` and `state` used to be free-form `String`s carrying the +/// gateway guest's lifecycle label; the field is `local-only` for a +/// host-resident realm, the daemon's lifecycle state for a gateway-backed +/// realm whose gateway the daemon listed, and the preserved sentinel string +/// when the daemon did not list the gateway at all. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum RealmGatewayState { + /// The realm has no gateway hop; it is dispatched on this host. + LocalOnly, + /// The gateway guest is stopped. + Stopped, + /// The gateway guest is starting. + Starting, + /// The gateway guest has booted. + Booted, + /// The gateway guest is running. + Running, + /// The gateway guest is stopping. + Stopping, + /// The gateway guest is restarting. + Restarting, + /// The gateway guest failed its last lifecycle transition. + Failed, + /// The daemon reported the gateway guest's lifecycle as unknown. + Unknown, + /// The daemon's list response did not include the gateway VM. + #[serde(rename = "not reported by d2bd")] + NotReported, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] /// One degraded scope in `op inspect` output. @@ -124,12 +172,12 @@ pub struct OpInspectDegradedOutputV1 { /// One realm's policy summary, shared by list and inspect output. pub struct RealmPolicyOutputV1 { pub realm: String, - pub mode: String, + pub mode: RealmMode, #[serde(skip_serializing_if = "Option::is_none")] pub gateway_vm: Option, #[serde(skip_serializing_if = "Option::is_none")] pub gateway_target: Option, - pub gateway_state: String, + pub gateway_state: RealmGatewayState, pub cross_realm_policy: String, pub credential_boundary: String, } diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index a4cb196eb..a7f0b0762 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -2173,7 +2173,7 @@ pub struct StatusResponse { #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct PublicReadModelMetadata { pub schema_version: u32, - pub kind: String, + pub kind: PublicReadModelKind, pub generation: u64, pub source_fingerprint: String, pub updated_at_unix_ms: u128, @@ -2181,6 +2181,21 @@ pub struct PublicReadModelMetadata { pub deep_refresh: String, } +/// Which public response frame the daemon's cached read model describes. +/// +/// `kind` used to be a free-form `String`; the daemon publishes exactly two +/// frames, the unfiltered `list` and `status` responses, so both the wire +/// protocol and the generated CLI schema carry enum constraints rather than a +/// free-form string. Serde names match the canonical wire strings exactly. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum PublicReadModelKind { + /// The unfiltered public `list` frame. + List, + /// The unfiltered public `status` frame. + Status, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields, try_from = "AuditResponseWire")] pub struct AuditResponse { @@ -2668,10 +2683,23 @@ pub struct RuntimeSummary { #[serde(rename_all = "camelCase", deny_unknown_fields)] /// Whether a VM is set to autostart, with the reason. pub struct VmAutostartPosture { - pub mode: String, + pub mode: VmAutostartMode, pub reason: String, } +/// How the daemon's autostart pass treats a VM that carries an autostart row. +/// +/// `mode` used to be a free-form `String`. The daemon emits a row only for +/// VMs the pass refuses to start on its own, so the vocabulary has a single +/// member today; a future posture is an additive variant here rather than a +/// new string. Serde names match the canonical wire strings exactly. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum VmAutostartMode { + /// Autostart skips this VM; the operator starts it explicitly. + ManualOnly, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] /// Optional guest-media status attached to a VM row. @@ -2689,7 +2717,23 @@ pub struct QemuMediaRunnerStatus { #[serde(default, skip_serializing_if = "Option::is_none")] pub qmp_readiness: Option, pub role: String, - pub state: String, + pub state: QemuMediaRunnerState, +} + +/// Liveness of the qemu-media runner process the daemon projects. +/// +/// `state` used to be a free-form `String`; the daemon derives it from the +/// pidfd table, which reports a role as running while its recorded process is +/// alive at the same start time and stopped otherwise, so the wire protocol +/// and the generated CLI schema carry enum constraints rather than a free-form +/// string. Serde names match the canonical wire strings exactly. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum QemuMediaRunnerState { + /// The registered runner process is alive. + Running, + /// No live runner process is registered for the VM. + Stopped, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] @@ -2706,20 +2750,29 @@ pub struct QemuMediaSourceStatus { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] -/// The media registry's convergence state for one source. pub struct QemuMediaRegistryStatus { #[serde(default, skip_serializing_if = "Option::is_none")] pub remediation: Option, - pub state: String, + pub state: QemuMediaRegistryState, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct AuditEntry { - pub action: String, - pub result: String, - pub scope: String, - pub timestamp: String, +/// The media probe registry's convergence state for one attached source. +/// +/// `state` used to be a free-form `String`; the daemon classifies every source +/// into exactly these four states, so both the wire protocol and the generated +/// CLI schema carry enum constraints rather than a free-form string. Serde +/// names match the canonical wire strings exactly. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum QemuMediaRegistryState { + /// The source is declared as `direct-config` and needs no probe record. + DirectConfig, + /// A probe record matches the current declaration. + Present, + /// A probe record exists but does not match the declaration. + Stale, + /// No probe record exists for the declared source. + Missing, } #[cfg(test)] @@ -2744,6 +2797,46 @@ mod tests { assert_eq!(encoded, "\"Booted\""); } + #[test] + fn status_dto_state_vocabularies_keep_their_wire_spellings() { + use super::{ + PublicReadModelKind, QemuMediaRegistryState, QemuMediaRunnerState, VmAutostartMode, + }; + use crate::cli_output::{RealmGatewayState, RealmMode}; + + fn assert_wire(value: T, wire: &str) + where + T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + core::fmt::Debug, + { + let encoded = serde_json::to_value(&value).expect("vocabulary value serializes"); + assert_eq!(encoded, serde_json::json!(wire)); + let decoded: T = serde_json::from_value(encoded).expect("vocabulary value decodes"); + assert_eq!(decoded, value); + } + + assert_wire(PublicReadModelKind::List, "list"); + assert_wire(PublicReadModelKind::Status, "status"); + assert_wire(VmAutostartMode::ManualOnly, "manual-only"); + assert_wire(QemuMediaRunnerState::Running, "running"); + assert_wire(QemuMediaRunnerState::Stopped, "stopped"); + assert_wire(QemuMediaRegistryState::DirectConfig, "direct-config"); + assert_wire(QemuMediaRegistryState::Present, "present"); + assert_wire(QemuMediaRegistryState::Stale, "stale"); + assert_wire(QemuMediaRegistryState::Missing, "missing"); + assert_wire(RealmMode::HostResident, "host-resident"); + assert_wire(RealmMode::GatewayBacked, "gateway-backed"); + assert_wire(RealmGatewayState::LocalOnly, "local-only"); + assert_wire(RealmGatewayState::Stopped, "stopped"); + assert_wire(RealmGatewayState::Starting, "starting"); + assert_wire(RealmGatewayState::Booted, "booted"); + assert_wire(RealmGatewayState::Running, "running"); + assert_wire(RealmGatewayState::Stopping, "stopping"); + assert_wire(RealmGatewayState::Restarting, "restarting"); + assert_wire(RealmGatewayState::Failed, "failed"); + assert_wire(RealmGatewayState::Unknown, "unknown"); + assert_wire(RealmGatewayState::NotReported, "not reported by d2bd"); + } + #[test] fn named_process_stream_frames_round_trip_without_identity_fields() { let request = NamedProcessStreamRequest::Stdin { diff --git a/packages/d2bd-runtime/src/public_projection.rs b/packages/d2bd-runtime/src/public_projection.rs index 8a9f2edf7..a42871a79 100644 --- a/packages/d2bd-runtime/src/public_projection.rs +++ b/packages/d2bd-runtime/src/public_projection.rs @@ -1,6 +1,7 @@ use std::{collections::HashSet, fs, path::Path}; use d2b_contracts_broker::broker_wire::RunnerRole; +use d2b_contracts_control::public_wire::{QemuMediaRunnerState, VmAutostartMode}; use d2b_core::processes::{ProcessNode, ProcessRole, VmProcessDag}; use serde::Serialize; use serde_json::{Value, json}; @@ -114,7 +115,7 @@ pub fn public_is_qemu_media(manifest_entry: &Value) -> bool { pub fn public_autostart_posture(manifest_entry: &Value) -> Option { public_is_qemu_media(manifest_entry).then(|| { json!({ - "mode": "manual-only", + "mode": VmAutostartMode::ManualOnly, "reason": "qemu-media VMs are intentionally skipped by daemon autostart; start them explicitly with `d2b vm start --apply`" }) }) @@ -298,6 +299,19 @@ fn public_pidfd_role_prefix_state(pidfd_table: &PidfdTable, vm: &str, prefix: &s public_pidfd_role_state_matching(pidfd_table, vm, |candidate| candidate.starts_with(prefix)) } +/// Liveness of the qemu-media runner role as the public media row reports it. +/// +/// The pidfd table is the authority for both this projection and the +/// per-service state map, so the typed state and the `services.qemuMedia` +/// string cannot disagree. +pub fn public_qemu_media_runner_state(pidfd_table: &PidfdTable, vm: &str) -> QemuMediaRunnerState { + if public_pidfd_role_running(pidfd_table, vm, RunnerRole::QemuMedia.as_str()) { + QemuMediaRunnerState::Running + } else { + QemuMediaRunnerState::Stopped + } +} + fn public_pidfd_role_state_matching( pidfd_table: &PidfdTable, vm: &str, @@ -306,17 +320,32 @@ fn public_pidfd_role_state_matching( where F: Fn(&str) -> bool, { - let running = pidfd_table.list_for_vm(vm).into_iter().any(|registration| { - role_matches(®istration.role) - && pidfd_table.still_alive_same_start_time(vm, ®istration.role) - }); - if running { + if public_pidfd_role_running_matching(pidfd_table, vm, role_matches) { "running".to_owned() } else { "stopped".to_owned() } } +/// Whether the pidfd table holds a live registration whose role matches. +fn public_pidfd_role_running(pidfd_table: &PidfdTable, vm: &str, role: &str) -> bool { + public_pidfd_role_running_matching(pidfd_table, vm, |candidate| candidate == role) +} + +fn public_pidfd_role_running_matching( + pidfd_table: &PidfdTable, + vm: &str, + role_matches: F, +) -> bool +where + F: Fn(&str) -> bool, +{ + pidfd_table.list_for_vm(vm).into_iter().any(|registration| { + role_matches(®istration.role) + && pidfd_table.still_alive_same_start_time(vm, ®istration.role) + }) +} + pub fn qemu_media_qmp_socket(node: &ProcessNode) -> Option { node.readiness.iter().find_map(|predicate| match predicate { d2b_core::processes::ReadinessPredicate::UnixSocketListening(path) diff --git a/packages/d2bd-runtime/src/public_read_model.rs b/packages/d2bd-runtime/src/public_read_model.rs index 84179b733..68c4d5e57 100644 --- a/packages/d2bd-runtime/src/public_read_model.rs +++ b/packages/d2bd-runtime/src/public_read_model.rs @@ -68,12 +68,6 @@ pub struct PublicStatusReadModel { status: ArcSwapOption, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PublicReadModelKind { - List, - Status, -} - impl PublicStatusReadModel { pub fn new() -> Self { Self { @@ -100,17 +94,16 @@ impl PublicStatusReadModel { pub fn publish_if_unchanged( &self, - kind: PublicReadModelKind, + kind: public_wire::PublicReadModelKind, before: Option, current: Option, value: Value, - kind_name: &'static str, ) -> Value { let Some(fingerprint) = before else { return value; }; if current.as_ref() == Some(&fingerprint) { - self.publish_stable(kind, value, fingerprint, kind_name) + self.publish_stable(kind, value, fingerprint) } else { value } @@ -127,13 +120,12 @@ impl PublicStatusReadModel { fn publish_stable( &self, - kind: PublicReadModelKind, + kind: public_wire::PublicReadModelKind, value: Value, fingerprint: PublicArtifactFingerprint, - kind_name: &'static str, ) -> Value { let generation = self.generation.fetch_add(1, Ordering::AcqRel) + 1; - let value = attach_read_model_metadata(value, &fingerprint, generation, kind_name); + let value = attach_read_model_metadata(value, &fingerprint, generation, kind); let mut observed = self.latest_published_generation.load(Ordering::Acquire); while generation > observed { match self.latest_published_generation.compare_exchange_weak( @@ -148,8 +140,8 @@ impl PublicStatusReadModel { value: value.clone(), }); match kind { - PublicReadModelKind::List => self.list.store(Some(frame)), - PublicReadModelKind::Status => self.status.store(Some(frame)), + public_wire::PublicReadModelKind::List => self.list.store(Some(frame)), + public_wire::PublicReadModelKind::Status => self.status.store(Some(frame)), } return value; } @@ -157,7 +149,7 @@ impl PublicStatusReadModel { } } tracing::debug!( - read_model_kind = kind_name, + read_model_kind = ?kind, generation, latest_generation = observed, "skipped stale public read-model publish" @@ -219,7 +211,7 @@ fn attach_read_model_metadata( mut frame: Value, fingerprint: &PublicArtifactFingerprint, generation: u64, - kind: &'static str, + kind: public_wire::PublicReadModelKind, ) -> Value { let metadata = json!({ "schemaVersion": 1, @@ -230,7 +222,7 @@ fn attach_read_model_metadata( "freshness": "fresh", "deepRefresh": "available", }); - if kind == "status" + if kind == public_wire::PublicReadModelKind::Status && let Some(status) = frame.get_mut("status").and_then(Value::as_object_mut) { status.insert("readModel".to_owned(), metadata); diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index b6c978f80..d98dd7e71 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -48,7 +48,8 @@ use d2b_contracts_broker::kernel_client::{ }; use d2b_resource_types::{KernelCaller, RunnerLookup}; use d2b_contracts_control::public_wire::{ - self, AuthRole, AuthStatusResponse, DeniedCommandHint, SocketReachability, + self, AuthRole, AuthStatusResponse, DeniedCommandHint, PublicReadModelKind, + QemuMediaRegistryState, QemuMediaRunnerState, SocketReachability, }; use d2b_contracts_resource::resource_proto as resource_wire; use d2b_contracts_resource::v3::identity::ReconnectGeneration; @@ -118,8 +119,7 @@ use d2bd_runtime::public_projection::{ qemu_media_unix_socket_listening, resolve_vm_filter_target, serde_kebab_string, }; pub use d2bd_runtime::public_read_model::{ - PublicArtifactFingerprint, PublicReadModelKind, PublicStatusReadModel, - request_invalidates_public_status_model, + PublicArtifactFingerprint, PublicStatusReadModel, request_invalidates_public_status_model, }; #[cfg(test)] pub(crate) use d2bd_runtime::readiness::wait_for_readiness; @@ -20939,7 +20939,6 @@ fn dispatch_list( PublicReadModelKind::List, before, frame, - "list", )); } Ok(frame) @@ -21029,7 +21028,6 @@ fn build_public_list( runtime_kind.as_deref(), host, process_vm, - &services, ), "services": services, }); @@ -21074,7 +21072,6 @@ fn dispatch_status_as( PublicReadModelKind::Status, before, frame, - "status", )); } Ok(frame) @@ -21085,14 +21082,12 @@ fn publish_public_frame_if_stable( kind: PublicReadModelKind, before: Option, frame: Value, - kind_name: &'static str, ) -> Value { state.public_status_read_model.publish_if_unchanged( kind, before, public_artifact_fingerprint(state).ok(), frame, - kind_name, ) } @@ -21159,7 +21154,6 @@ fn build_public_status( runtime_kind.as_deref(), host, process_vm, - &services, ), "usb": usb_resolver .and_then(|resolver| { @@ -21348,7 +21342,6 @@ fn public_qemu_media_status( runtime_kind: Option<&str>, host: Option<&HostJson>, process_vm: Option<&d2b_core::processes::VmProcessDag>, - services: &Value, ) -> Option { if runtime_kind != Some("qemu-media") { return None; @@ -21360,17 +21353,10 @@ fn public_qemu_media_status( .find(|node| node.role == ProcessRole::QemuMediaRunner) }); let qmp_socket = runner.and_then(qemu_media_qmp_socket); - let state_text = services - .get("qemuMedia") - .and_then(Value::as_str) - .map(str::to_owned) - .unwrap_or_else(|| { - d2bd_runtime::public_projection::public_pidfd_role_state( - &state.pidfd_table, - vm, - RunnerRole::QemuMedia.as_str(), - ) - }); + let runner_state = d2bd_runtime::public_projection::public_qemu_media_runner_state( + &state.pidfd_table, + vm, + ); let qemu_media_host = host.and_then(|host| host.qemu_media.as_ref()); let media = qemu_media_host .map(|contract| { @@ -21385,21 +21371,21 @@ fn public_qemu_media_status( let qmp_readiness = qmp_socket.as_deref().map(|path| { if qemu_media_unix_socket_listening(path) { "ready".to_owned() - } else if state_text == "running" { + } else if runner_state == QemuMediaRunnerState::Running { "pending".to_owned() } else { "not-started".to_owned() } }); let pre_cont_progress = match qmp_readiness.as_deref() { - Some("ready") if state_text == "running" => "paused-before-cont", - Some("pending") if state_text == "running" => "waiting-for-qmp", + Some("ready") if runner_state == QemuMediaRunnerState::Running => "paused-before-cont", + Some("pending") if runner_state == QemuMediaRunnerState::Running => "waiting-for-qmp", _ => "not-started", }; Some(json!({ "firmwareMode": "none", "runner": { - "state": state_text, + "state": runner_state, "role": RunnerRole::QemuMedia.as_str(), "preContProgress": pre_cont_progress, "qmpReadiness": qmp_readiness, @@ -21424,9 +21410,11 @@ fn qemu_media_source_status(source: &QemuMediaSourceIntent) -> Value { status } -fn qemu_media_registry_state(source: &QemuMediaSourceIntent) -> (String, Option) { +fn qemu_media_registry_state( + source: &QemuMediaSourceIntent, +) -> (QemuMediaRegistryState, Option) { if serde_kebab_string(&source.source_kind) != "physical-usb" { - return ("direct-config".to_owned(), None); + return (QemuMediaRegistryState::DirectConfig, None); } let records = qemu_media_probe_registry_records(); let Some(record) = records @@ -21434,7 +21422,7 @@ fn qemu_media_registry_state(source: &QemuMediaSourceIntent) -> (String, Option< .find(|record| record.vm == source.vm && record.media_ref == source.media_ref) else { return ( - "missing".to_owned(), + QemuMediaRegistryState::Missing, Some(format!( "declare the boot-drive physical USB source for vm `{}` in config, then run `d2b usb probe` to verify the runtime selector for `{}` before starting or attaching this media", source.vm, source.media_ref @@ -21449,10 +21437,10 @@ fn qemu_media_registry_state(source: &QemuMediaSourceIntent) -> (String, Option< && record.format == expected_format && record.read_only == source.read_only { - ("present".to_owned(), None) + (QemuMediaRegistryState::Present, None) } else { ( - "stale".to_owned(), + QemuMediaRegistryState::Stale, Some( "registry entry does not match the current declaration; update qemu-media config if needed, then run `d2b usb probe`" .to_owned(), @@ -22125,12 +22113,24 @@ mod public_status_tests { Some(&dag), ); let runtime = public_runtime_summary(&lifecycle, &manifest_entry); + let qemu = public_qemu_media_status( + &state, + "installer", + Some("qemu-media"), + None, + Some(&dag), + ) + .expect("qemu media status"); assert_eq!(lifecycle_state(&lifecycle), "Running"); assert_eq!( runtime.get("kind").and_then(Value::as_str), Some("qemu-media") ); + assert_eq!( + qemu.pointer("/runner/state").and_then(Value::as_str), + Some("running") + ); assert_eq!( services.get("microvm").and_then(Value::as_str), Some("unsupported") @@ -22179,21 +22179,13 @@ mod public_status_tests { #[test] fn qemu_media_status_reports_manual_runtime_and_missing_registry() { let (state, _dir) = test_state(); - let manifest_entry = qemu_media_manifest_entry(); let dag = qemu_media_process_dag(); - let services = d2bd_runtime::public_projection::public_service_states( - &state.pidfd_table, - "installer", - &manifest_entry, - Some(&dag), - ); let qemu = public_qemu_media_status( &state, "installer", Some("qemu-media"), None, Some(&dag), - &services, ) .expect("qemu media status"); @@ -22205,6 +22197,10 @@ mod public_status_tests { qemu.pointer("/runner/role").and_then(Value::as_str), Some("qemu-media") ); + assert_eq!( + qemu.pointer("/runner/state").and_then(Value::as_str), + Some("stopped") + ); assert_eq!( qemu.pointer("/runner/qmpSocket").and_then(Value::as_str), None @@ -22548,7 +22544,6 @@ mod public_status_tests { PublicReadModelKind::Status, Some(before), stale_frame.clone(), - "status", ); assert_eq!(returned, stale_frame); From f06df61117f556d3ef3d163af007f6291adc9d2c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:35:29 -0700 Subject: [PATCH 644/726] flake: mirror d2b-resource-client into the guest workspace d2b-provider-guest-cloud-hypervisor gained a dependency on d2b-resource-client, but the copied Guest workspace never received the mirror: the crate directory was missing from flake.nix's copy list, so tests/fixtures/guest-rust-workspace/Cargo.toml and packages/Cargo.guest.lock did not carry it either. The realized supply-chain lane resolves that workspace, so the Guest cargo-deny check failed on the absent manifest (/build/guest/d2b-resource-client/Cargo.toml). Restore the crate copy, its workspace membership, its lock entry and the lock's dependency edge for d2b-provider-guest-cloud-hypervisor, and regenerate the package policy inputs for the refreshed guest lock digest. --- changelog.d/fix-w5-flake-mirror.md | 11 ++++ flake.nix | 1 + packages/Cargo.guest.lock | 13 +++++ .../guest-static/policy/Cargo.lock | 14 +++++ .../guest-static/policy/closure.json | 52 ++++++++++++++++++- .../guest-static/policy/metadata.json | 7 +-- .../guest-static/production/Cargo.lock | 14 +++++ .../guest-static/production/closure.json | 52 ++++++++++++++++++- .../guest-static/production/metadata.json | 7 +-- .../guest-static/policy/Cargo.lock | 14 +++++ .../guest-static/policy/closure.json | 52 ++++++++++++++++++- .../guest-static/policy/metadata.json | 7 +-- .../guest-static/production/Cargo.lock | 14 +++++ .../guest-static/production/closure.json | 52 ++++++++++++++++++- .../guest-static/production/metadata.json | 7 +-- .../fixtures/guest-rust-workspace/Cargo.toml | 1 + 16 files changed, 302 insertions(+), 16 deletions(-) create mode 100644 changelog.d/fix-w5-flake-mirror.md diff --git a/changelog.d/fix-w5-flake-mirror.md b/changelog.d/fix-w5-flake-mirror.md new file mode 100644 index 000000000..fcd5925db --- /dev/null +++ b/changelog.d/fix-w5-flake-mirror.md @@ -0,0 +1,11 @@ +### Fixed + +- Mirrored `d2b-resource-client` into the copied Guest workspace (`flake.nix`, + `tests/fixtures/guest-rust-workspace/Cargo.toml`, and + `packages/Cargo.guest.lock`) after + `d2b-provider-guest-cloud-hypervisor` gained a dependency on it; the + realized supply-chain lane resolves that workspace and failed on the absent + manifest, so the crate directory, its membership, and its lock entry are + restored. +- Regenerated the package policy inputs so the `guest-static` contexts carry + the refreshed `packages/Cargo.guest.lock` digest. diff --git a/flake.nix b/flake.nix index ad88c0652..fb197e7e4 100644 --- a/flake.nix +++ b/flake.nix @@ -167,6 +167,7 @@ cp -r ${./packages/d2b-provider-zone} $out/packages/d2b-provider-zone cp -r ${./packages/d2b-provider-zone-link} $out/packages/d2b-provider-zone-link cp -r ${./packages/d2b-resource-api} $out/packages/d2b-resource-api + cp -r ${./packages/d2b-resource-client} $out/packages/d2b-resource-client cp -r ${./packages/d2b-resource-types} $out/packages/d2b-resource-types cp -r ${./packages/d2b-resource-runtime} $out/packages/d2b-resource-runtime cp -r ${./packages/d2b-session} $out/packages/d2b-session diff --git a/packages/Cargo.guest.lock b/packages/Cargo.guest.lock index c75564ea8..4d1a0a3c1 100644 --- a/packages/Cargo.guest.lock +++ b/packages/Cargo.guest.lock @@ -1266,6 +1266,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1769,6 +1770,18 @@ dependencies = [ "ttrpc", ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json index 8bc8fcf4e..b9a7d5236 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "aarch64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "aarch64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json index fa202753f..e7cf3f7f4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json index ea6ab0401..88df3cc63 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "aarch64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "aarch64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json index fa202753f..e7cf3f7f4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json index fb7cdb388..20236dcbb 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "x86_64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "x86_64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json index fa88ebdc4..8d03d7b6e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock index 63521c4b0..bb0790f45 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock @@ -1342,6 +1342,7 @@ dependencies = [ "d2b-contracts-resource", "d2b-contracts-zone-session", "d2b-core-controller", + "d2b-resource-client", "d2b-session", "d2b-session-unix", "serde", @@ -1881,6 +1882,19 @@ dependencies = [ ] +[[package]] +name = "d2b-resource-client" +version = "0.0.0-bootstrap" +dependencies = [ + "d2b-contracts-control", + "d2b-contracts-resource", + "d2b-contracts-zone-session", + "d2b-core-controller", + "serde_json", + "tokio", +] + + [[package]] name = "d2b-resource-runtime" version = "0.0.0-bootstrap" diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json index 41788b595..b2a60e67d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", + "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -1117,6 +1117,14 @@ "checksum": null, "target": "x86_64-unknown-linux-musl" }, + { + "id": "d2b-resource-client@0.0.0-bootstrap#path", + "name": "d2b-resource-client", + "version": "0.0.0-bootstrap", + "source": null, + "checksum": null, + "target": "x86_64-unknown-linux-musl" + }, { "id": "d2b-resource-runtime@0.0.0-bootstrap#path", "name": "d2b-resource-runtime", @@ -6779,6 +6787,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", + "to": "d2b-resource-client@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-guest-cloud-hypervisor@0.0.0-bootstrap#path", "to": "d2b-session-unix@0.0.0-bootstrap#path", @@ -8633,6 +8647,42 @@ "kind": "normal", "target": null }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-control@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-resource@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-contracts-zone-session@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "d2b-core-controller@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, + { + "from": "d2b-resource-client@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-resource-runtime@0.0.0-bootstrap#path", "to": "async-trait@0.1.92#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json index fa88ebdc4..8d03d7b6e 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json @@ -2,8 +2,8 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "67a1bfe5ba093516dc7c33d02fffd50351c6d5485695a699fb7285e285a01eb0", - "policyPackageCount": 466, + "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", "aead@0.5.2#registry+https://github.com/rust-lang/crates.io-index", @@ -143,6 +143,7 @@ "d2b-provider-zone@0.0.0-bootstrap#path", "d2b-provider@0.0.0-bootstrap#path", "d2b-resource-api@0.0.0-bootstrap#path", + "d2b-resource-client@0.0.0-bootstrap#path", "d2b-resource-runtime@0.0.0-bootstrap#path", "d2b-resource-types@0.0.0-bootstrap#path", "d2b-session-unix@0.0.0-bootstrap#path", @@ -472,7 +473,7 @@ "zvariant_derive@5.15.0#registry+https://github.com/rust-lang/crates.io-index", "zvariant_utils@4.2.0#registry+https://github.com/rust-lang/crates.io-index" ], - "productionPackageCount": 466, + "productionPackageCount": 467, "resolveNodeCount": 0, "roots": [ "d2bd", diff --git a/tests/fixtures/guest-rust-workspace/Cargo.toml b/tests/fixtures/guest-rust-workspace/Cargo.toml index 5d2bf78b3..9137b57e2 100644 --- a/tests/fixtures/guest-rust-workspace/Cargo.toml +++ b/tests/fixtures/guest-rust-workspace/Cargo.toml @@ -77,6 +77,7 @@ members = [ "d2b-provider-zone", "d2b-provider-zone-link", "d2b-resource-api", + "d2b-resource-client", "d2b-resource-types", "d2b-resource-runtime", "d2b-session", From 289587bcbd489163ea166e64087924d6f80d851a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:35:52 -0700 Subject: [PATCH 645/726] host: move the validated usb busid into the media module The provider crate layout policy flags the network-local family token `nftables` in a shared crate. The broker's qemu-media ops built their validated busid through `d2b_host::nftables::BusId`, naming that family for a value the media vocabulary owns, so those three call sites were the policy's only unpardoned signals. Home the newtype beside `media::validate_usb_busid`, the grammar it enforces, and repoint every caller; `nftables` keeps only the carveout rendering. Clearing the family signal let the same check reach its later probes, which surfaced a stale comment citation in nftables.rs; it now names the live `d2b_contracts::error::Error` the code already returns. --- changelog.d/fix-w5-crate-layout.md | 3 ++ changelog.d/w5-18-busid-invariant.md | 2 +- packages/d2b-broker/src/ops/media.rs | 8 ++-- packages/d2b-broker/src/ops/nft.rs | 2 +- packages/d2b-broker/src/ops/usbip_firewall.rs | 3 +- packages/d2b-broker/src/runtime.rs | 14 +++--- packages/d2b-host/src/media.rs | 41 ++++++++++++++++++ packages/d2b-host/src/nftables.rs | 43 +------------------ 8 files changed, 61 insertions(+), 55 deletions(-) create mode 100644 changelog.d/fix-w5-crate-layout.md diff --git a/changelog.d/fix-w5-crate-layout.md b/changelog.d/fix-w5-crate-layout.md new file mode 100644 index 000000000..57f997f78 --- /dev/null +++ b/changelog.d/fix-w5-crate-layout.md @@ -0,0 +1,3 @@ +### Changed + +- Moved the validated USB busid type to `d2b_host::media::BusId`, beside the busid grammar validator it enforces, so broker media and firewall call sites build the validated value from the host media vocabulary instead of naming the `nftables` module; `d2b_host::nftables` now renders the validated value without owning the type. diff --git a/changelog.d/w5-18-busid-invariant.md b/changelog.d/w5-18-busid-invariant.md index 28116cb74..e615f75eb 100644 --- a/changelog.d/w5-18-busid-invariant.md +++ b/changelog.d/w5-18-busid-invariant.md @@ -1,5 +1,5 @@ ### Fixed -- `d2b_host::nftables::BusId` now enforces the USB busid grammar at the type boundary: the inner `String` is private, `BusId::new` validates via `media::validate_usb_busid` and returns `Result`, and a `TryFrom<&str>` conversion is provided; the `#[serde(transparent)]` wire shape is unchanged. +- `d2b_host::media::BusId` now enforces the USB busid grammar at the type boundary: the inner `String` is private, `BusId::new` validates via `media::validate_usb_busid` and returns `Result`, and a `TryFrom<&str>` conversion is provided; the `#[serde(transparent)]` wire shape is unchanged. - Removed the redundant busid re-validation in the broker qemu-media ops (`enroll`, `detach`, and the runtime selector path now convert the wire busid once through `BusId::try_from`) and the daemon-side attach/detach pre-checks; the grammar is enforced once at the type boundary. - Added `BusId::as_str` for reading the wrapped busid; carveout rendering and all construction sites use the typed value. \ No newline at end of file diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index 26bed2c82..56e8e99ef 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -51,7 +51,7 @@ static D2BD_GROUP_GID: std::sync::LazyLock, Stri pub enum MediaOpError { /// The media ref failed [`d2b_host::media::validate_media_ref`]. InvalidRef(String), - /// The USB bus id failed the [`d2b_host::nftables::BusId`] grammar. + /// The USB bus id failed the [`d2b_host::media::BusId`] grammar. InvalidBusId(String), /// The bundle declares no policy for the ref. MissingBundlePolicy, @@ -256,7 +256,7 @@ pub async fn enroll( ) -> Result { d2b_host::media::validate_media_ref(req.media_ref.as_str()) .map_err(|err| MediaOpError::InvalidRef(err.to_string()))?; - let bus_id = d2b_host::nftables::BusId::try_from(req.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::try_from(req.bus_id.as_str()) .map_err(|err| MediaOpError::InvalidBusId(err.to_string()))?; let source = resolve_physical_source(resolver, req.vm_id.as_str(), req.media_ref.as_str())?; let identity = @@ -454,7 +454,7 @@ pub async fn detach( resolver: &BundleResolver, req: &QemuMediaHotplugRequest, ) -> Result { - let bus_id = d2b_host::nftables::BusId::try_from(req.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::try_from(req.bus_id.as_str()) .map_err(|err| MediaOpError::InvalidBusId(err.to_string()))?; let identity = read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), bus_id.as_str()).await?; @@ -503,7 +503,7 @@ async fn open_runtime_selector_source<'a>( resolver: &'a BundleResolver, req: &QemuMediaHotplugRequest, ) -> Result, MediaOpError> { - let bus_id = d2b_host::nftables::BusId::try_from(req.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::try_from(req.bus_id.as_str()) .map_err(|err| MediaOpError::InvalidBusId(err.to_string()))?; let identity = read_usb_identity(Path::new("/sys"), Path::new("/dev/disk/by-id"), bus_id.as_str()).await?; diff --git a/packages/d2b-broker/src/ops/nft.rs b/packages/d2b-broker/src/ops/nft.rs index 047b9559d..1dfa89f6e 100644 --- a/packages/d2b-broker/src/ops/nft.rs +++ b/packages/d2b-broker/src/ops/nft.rs @@ -929,7 +929,7 @@ mod tests { fn usbip_script() -> (String, String) { let mut batch = build_inet_d2b_chains(); - let bus_id = d2b_host::nftables::BusId::new("1-1.2").expect("busid"); + let bus_id = d2b_host::media::BusId::new("1-1.2").expect("busid"); batch.add_usbip_carveout(&bus_id).expect("carveout"); let script = batch.render_nft_script(); let hash = batch.canonical_hash().to_string(); diff --git a/packages/d2b-broker/src/ops/usbip_firewall.rs b/packages/d2b-broker/src/ops/usbip_firewall.rs index 69b0220d5..bf513e765 100644 --- a/packages/d2b-broker/src/ops/usbip_firewall.rs +++ b/packages/d2b-broker/src/ops/usbip_firewall.rs @@ -11,7 +11,8 @@ //! explicit fail-closed handler used by the broker dispatch table when //! one of those live-routing variants is invoked before support. -use d2b_host::nftables::{BusId, ChainHook, NftBatch, NftError, Sha256}; +use d2b_host::media::BusId; +use d2b_host::nftables::{ChainHook, NftBatch, NftError, Sha256}; use serde::{Deserialize, Serialize}; /// Audit-event payload for `UsbipBindFirewallRule`. Combined with the diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 4a803791a..db9bdbc74 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -8645,7 +8645,7 @@ async fn build_usbip_explicit_firewall_decision( let Some(active_firewall) = resolver.find_usbip_firewall_intent(&firewall_id) else { continue; }; - let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::new(active_firewall.bus_id.as_str()) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( @@ -8669,7 +8669,7 @@ async fn build_usbip_explicit_firewall_decision( else { continue; }; - let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::new(active_firewall.bus_id.as_str()) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( @@ -8689,7 +8689,7 @@ async fn build_usbip_explicit_firewall_decision( if !inserted.insert(carveout_id) { continue; } - let bus_id = d2b_host::nftables::BusId::new(explicit_bus_id.as_str()) + let bus_id = d2b_host::media::BusId::new(explicit_bus_id.as_str()) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( @@ -8701,7 +8701,7 @@ async fn build_usbip_explicit_firewall_decision( } // Insert the new explicit carveout last. - let bus_id = d2b_host::nftables::BusId::new(bus_id) + let bus_id = d2b_host::media::BusId::new(bus_id) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; crate::ops::usbip_firewall::bind_firewall_rule(batch, &bus_id, rule_body) .map_err(|err| BrokerError::LiveHandler(err.to_string())) @@ -10060,7 +10060,7 @@ async fn build_usbip_firewall_decision( intent_id: firewall_id, }); }; - let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::new(active_firewall.bus_id.as_str()) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( @@ -10085,7 +10085,7 @@ async fn build_usbip_firewall_decision( intent_id: firewall_id, }); }; - let bus_id = d2b_host::nftables::BusId::new(active_firewall.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::new(active_firewall.bus_id.as_str()) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; batch .add_usbip_carveout_expr( @@ -10096,7 +10096,7 @@ async fn build_usbip_firewall_decision( .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; } - let bus_id = d2b_host::nftables::BusId::new(current.bus_id.as_str()) + let bus_id = d2b_host::media::BusId::new(current.bus_id.as_str()) .map_err(|err| BrokerError::LiveHandler(err.to_string()))?; crate::ops::usbip_firewall::bind_firewall_rule(batch, &bus_id, current.nft_rule_body.as_str()) .map_err(|err| BrokerError::LiveHandler(err.to_string())) diff --git a/packages/d2b-host/src/media.rs b/packages/d2b-host/src/media.rs index 53fc7f0b3..f4ff42075 100644 --- a/packages/d2b-host/src/media.rs +++ b/packages/d2b-host/src/media.rs @@ -6,6 +6,7 @@ //! (`d2b-provider-guest-qemu-media`); this module keeps only the generic //! USB helpers. +use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; use std::fmt; use std::path::{Path, PathBuf}; @@ -113,6 +114,46 @@ pub fn validate_usb_busid(value: &str) -> Result<(), BusIdError> { Ok(()) } +/// USB busid newtype. The lexical busid grammar +/// ([`validate_usb_busid`]) is enforced once here, at the type boundary; +/// consumers never re-validate. The transparent serde shape keeps the +/// wire spelling unchanged. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(transparent)] +pub struct BusId(String); + +impl BusId { + /// Validate `s` against the USB busid grammar and wrap it. + /// + /// # Errors + /// + /// Returns [`BusIdError`] when `s` is not a valid USB busid. + pub fn new(s: impl Into) -> Result { + let s = s.into(); + validate_usb_busid(&s)?; + Ok(Self(s)) + } + + /// Borrow the wrapped busid string. + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl TryFrom<&str> for BusId { + type Error = BusIdError; + + fn try_from(value: &str) -> Result { + Self::new(value) + } +} + +impl fmt::Display for BusId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&self.0) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DevnumError { Empty, diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index f03145937..00f9fe3c0 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -25,6 +25,7 @@ //! tests can drive the full coexistence matrix without a live nft //! kernel surface. +use crate::media::BusId; use d2b_core::host_w3::{CoexistencePolicy, FirewallManager}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256 as Sha256Hasher}; @@ -91,7 +92,7 @@ pub enum NftError { impl NftError { /// Stable kebab-case discriminant for audit logs + the typed-error - /// mapping into `d2b-core::error::Error`. + /// mapping into `d2b_contracts::error::Error`. pub const fn as_kebab_case(&self) -> &'static str { match self { Self::ForeignNftRuleShadowsD2b { .. } => "foreign-nft-rule-shadows-d2b", @@ -617,46 +618,6 @@ impl NftBatch { } } -/// USBIP busid newtype. The lexical busid grammar -/// ([`crate::media::validate_usb_busid`]) is enforced once here, at the -/// type boundary; consumers never re-validate. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[serde(transparent)] -pub struct BusId(String); - -impl BusId { - /// Validate `s` against the USB busid grammar and wrap it. - /// - /// # Errors - /// - /// Returns [`crate::media::BusIdError`] when `s` is not a valid USB - /// busid. - pub fn new(s: impl Into) -> Result { - let s = s.into(); - crate::media::validate_usb_busid(&s)?; - Ok(Self(s)) - } - - /// Borrow the wrapped busid string. - pub fn as_str(&self) -> &str { - &self.0 - } -} - -impl TryFrom<&str> for BusId { - type Error = crate::media::BusIdError; - - fn try_from(value: &str) -> Result { - Self::new(value) - } -} - -impl fmt::Display for BusId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.0) - } -} - // --------------------------------------------------------------------- // Public API per the s3 contract // --------------------------------------------------------------------- From 1ab759f13d4585f888c4905226b31483b748e4ab Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:36:26 -0700 Subject: [PATCH 646/726] refactor(d2b-contracts): make the audit export entry payload exactly one RS-0546. `AuditExportEntry` carried `record: Option` beside `error: Option` while its doc promised exactly one was populated, so an entry carrying neither was representable and the wire decode accepted it. The entry now carries `payload: AuditExportEntryPayload` - `Record { record }` or `Error { error }` - and decodes through a private `AuditExportEntryWire` shadow whose `try_from` refuses an entry carrying neither member or both (the admission-gate half of the row's fix). The emitted members are unchanged: `sequence` plus exactly one of `record` / `error`, in that order, so the broker audit page, the public daemon audit page and the CLI's `legacy_export_entry_line` rendering keep their JSON byte-for-byte. The generated schema for the entry gains the `oneOf` branches the type enforces. Co-change list: - producer: d2b-broker/src/audit.rs (the four page-writer sites and the legacy line renderer). - consumer: d2b/src/dispatch.rs (the CLI audit-page entry mapping matches the payload by value, no copy), d2b-broker/src/audit.rs tests, d2bd-runtime/src/wire.rs (one test construction). - re-export arm: d2b-contracts-broker/src/lib.rs re-exports `AuditExportEntryPayload`. - schema/goldens: docs/reference/schemas/v2/wire-protocol.json regenerated with `cargo run -p xtask -- gen-schemas`; docs/reference/daemon-api.md regenerated with `gen-daemon-api` (it picks up the new payload enum and the line shifts both rows produced); `gen-broker-operations` was run and produced no diff. - docs: the type's doc comment now states the contract the decode enforces instead of the promise the optional pair broke. External consumers: the JSON members are identical, so no consumer inside or outside this tree observes a shape change; only the Rust API moves. Gates: cargo test -p d2b-contracts (rc=0, 120 tests + 1 doctest); cargo test -p d2b-contracts-broker (rc=0, 51 + 2 tests); cargo test -p d2b-broker (rc=0, 700 tests + every integration target); cargo check -p d2b-contracts -p d2b-contracts-broker -p d2b-broker -p d2b -p d2bd-runtime -p d2bd -p d2b-contracts-control --all-targets (rc=0); nix develop -c bazel test --cache_test_results=no //packages/xtask:gen_schemas_drift //packages/xtask:gen_broker_operations_drift (rc=0) and //packages/xtask:gen_daemon_api_drift (rc=0). --- docs/reference/daemon-api.md | 31 +-- docs/reference/schemas/v2/wire-protocol.json | 12 + packages/d2b-broker/src/audit.rs | 69 +++--- packages/d2b-contracts-broker/src/lib.rs | 4 +- packages/d2b-contracts/src/audit_wire.rs | 222 ++++++++++++++++++- packages/d2b/src/dispatch.rs | 16 +- packages/d2bd-runtime/src/wire.rs | 5 +- 7 files changed, 295 insertions(+), 64 deletions(-) diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 22ecdadb6..0f79d5a61 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -329,12 +329,12 @@ host reboot. | `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2306) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | | `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2315) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | | `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2599) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | -| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2936) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2953) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2964) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2978) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | -| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3015) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3049) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2932) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2949) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2960) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2974) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | +| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3011) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3045) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | ### Console and audio wire types @@ -419,9 +419,9 @@ see the auto-generated tables above for the committed Rust variants. | `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2298) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | | `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2358) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | | `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2754) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | -| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2999) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | -| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3023) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | -| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3112) | struct { `notifications`: `Vec` } | +| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2995) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | +| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3019) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | +| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3108) | struct { `notifications`: `Vec` } | ## Per-VM lifecycle state @@ -511,10 +511,10 @@ running live guest activation. | `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2241) | `Term`; `Kill`; `Quit` | | `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2377) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | | `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2732) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | -| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2890) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | -| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2988) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | -| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3062) | `Exited`; `Signaled`; `Killed` | -| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3100) | `ChildReaped` - (ChildReapedNotification); `Unknown` | +| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2886) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | +| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2984) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | +| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3058) | `Exited`; `Signaled`; `Killed` | +| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3096) | `ChildReaped` - (ChildReapedNotification); `Unknown` | | `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L141) | `Lifecycle`; `Admin` | | `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L179) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | | `ProxyReadinessStage` | enum | [`ProxyReadinessStage`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L12) | `Upstream`; `Listener`; `FirstClient` | @@ -559,6 +559,7 @@ running live guest activation. | `DaemonToUnsafeLocalHelper` | enum | [`DaemonToUnsafeLocalHelper`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L365) | `HelloAccepted` - (HelperHelloAccepted); `Heartbeat` - (HelperHeartbeat); `Launch` - (Box) | | `UnsafeLocalHelperToDaemon` | enum | [`UnsafeLocalHelperToDaemon`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L377) | `Hello` - (HelperHello); `Snapshot` - (HelperSnapshot); `Heartbeat` - (HelperHeartbeat); `Operation` - (HelperOperationResult); `Rejected` - (HelperOperationRejected) | | `AudioGrant` | enum | [`AudioGrant`](../../packages/d2b-contracts/src/audio.rs#L79) | `On`; `Off` | +| `AuditExportEntryPayload` | enum | [`AuditExportEntryPayload`](../../packages/d2b-contracts/src/audit_wire.rs#L45) | `Record` - struct { `record`: `Value` }; `Error` - struct { `error`: `AuditExportErrorCode` } | | `Capability` | enum | [`Capability`](../../packages/d2b-contracts/src/capability.rs#L29) | `Lifecycle`; `Exec`; `Pty`; `Logs`; `FileCopy`; `PortForward`; `PersistentShell`; `Vsock`; `Virtiofs`; `WindowForwarding`; `DisplayStreaming`; `Clipboard`; `AudioPlayback`; `AudioCapture`; `Hid`; `Usb`; `GpuAccel`; `Snapshots`; `Hotplug`; `EphemeralSessions`; `ProviderManagedIsolation`; `ConfiguredLaunch` | | `RealmControllerRuntimeState` | enum | [`RealmControllerRuntimeState`](../../packages/d2b-contracts/src/controller_config.rs#L184) | `MetadataOnly` | | `RealmControllerPlacement` | enum | [`RealmControllerPlacement`](../../packages/d2b-contracts/src/controller_config.rs#L256) | `HostLocal`; `GatewayVm`; `CloudFullHost`; `ProviderController`; `ProviderAgent`; `ProviderSpecific` | @@ -655,8 +656,8 @@ the failure class, for example `host check`, `audit`, `status`, or | `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1996) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | | `LevelPercentError` | enum | [`LevelPercentError`](../../packages/d2b-contracts/src/audio.rs#L28) | `OutOfRange` - (u8) | | `AudioPolicyError` | enum | [`AudioPolicyError`](../../packages/d2b-contracts/src/audio.rs#L216) | `InvalidJson` - (String); `InvalidField` - (String); `UnknownSchemaVersion` - (String); `Serialize` - (String) | -| `AuditExportErrorCode` | enum | [`AuditExportErrorCode`](../../packages/d2b-contracts/src/audit_wire.rs#L20) | `HashBreak`; `RecordInvalid`; `ReadFailed` | -| `AuditPageError` | enum | [`AuditPageError`](../../packages/d2b-contracts/src/audit_wire.rs#L53) | `CompleteWithCursor`; `IncompleteWithoutCursor` | +| `AuditExportErrorCode` | enum | [`AuditExportErrorCode`](../../packages/d2b-contracts/src/audit_wire.rs#L24) | `HashBreak`; `RecordInvalid`; `ReadFailed` | +| `AuditPageError` | enum | [`AuditPageError`](../../packages/d2b-contracts/src/audit_wire.rs#L257) | `CompleteWithCursor`; `IncompleteWithoutCursor` | | `ConfiguredArgvError` | enum | [`ConfiguredArgvError`](../../packages/d2b-contracts/src/configured_argv.rs#L11) | `Empty`; `TooManyArgs` - struct { `max`: `usize` }; `NulByte`; `ArgTooLong` - struct { `max`: `usize` }; `ByteCountOverflow`; `TooManyBytes` - struct { `max`: `usize` } | | `ErrorKind` | enum | [`ErrorKind`](../../packages/d2b-contracts/src/constellation_error.rs#L25) | `CapabilityDenied`; `Unauthorized`; `NoRealmEntrypoint`; `GatewayUnavailable`; `ProviderAllocationFailed`; `RelayUnavailable`; `AuthenticationFailed`; `VersionSkew`; `OperationInProgress`; `IdempotencyKeyConflict`; `IdempotencyKeyExpired`; `Backpressure`; `Cancelled`; `Timeout`; `FrameTooLarge`; `MalformedFrame`; `InvalidTarget`; `AuditUnavailable`; `UnsupportedFeature` | | `ConstellationError` | struct | [`ConstellationError`](../../packages/d2b-contracts/src/constellation_error.rs#L108) | struct { `kind`: `ErrorKind`; `correlation_id`: `Option`; `capability`: `Option`; `negotiated_capability_fingerprint`: `Option`; `message`: `String` } | diff --git a/docs/reference/schemas/v2/wire-protocol.json b/docs/reference/schemas/v2/wire-protocol.json index 6015cb158..1400ee52f 100644 --- a/docs/reference/schemas/v2/wire-protocol.json +++ b/docs/reference/schemas/v2/wire-protocol.json @@ -758,6 +758,18 @@ "AuditExportEntry": { "description": "One typed audit export entry. Exactly one of `record` and `error` is populated by the broker.", "type": "object", + "oneOf": [ + { + "required": [ + "record" + ] + }, + { + "required": [ + "error" + ] + } + ], "required": [ "sequence" ], diff --git a/packages/d2b-broker/src/audit.rs b/packages/d2b-broker/src/audit.rs index 725cad5e0..6cccd246d 100644 --- a/packages/d2b-broker/src/audit.rs +++ b/packages/d2b-broker/src/audit.rs @@ -26,7 +26,9 @@ use crate::{ }; use d2b_audit::evidence_chain::ChainRecord; use d2b_contracts_broker::broker_wire::{BrokerAuditFilter, BrokerAuditSeverity, ExportBrokerAuditResponse}; -use d2b_contracts_broker::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}; +use d2b_contracts_broker::{ + AuditExportCursor, AuditExportEntry, AuditExportEntryPayload, AuditExportErrorCode, +}; /// Broker semantic version embedded in every [`OpAuditRecord`]. /// Picked up at compile time from `Cargo.toml`. @@ -1751,8 +1753,9 @@ fn export_page_locked( Err(_) => { let entry = AuditExportEntry { sequence, - record: None, - error: Some(AuditExportErrorCode::ReadFailed), + payload: AuditExportEntryPayload::Error { + error: AuditExportErrorCode::ReadFailed, + }, }; if !append_export_entry( &mut output, @@ -1797,8 +1800,9 @@ fn export_page_locked( } let entry = AuditExportEntry { sequence, - record: None, - error: Some(AuditExportErrorCode::ReadFailed), + payload: AuditExportEntryPayload::Error { + error: AuditExportErrorCode::ReadFailed, + }, }; if !append_export_entry( &mut output, @@ -1830,8 +1834,9 @@ fn export_page_locked( Err(_) => { let entry = AuditExportEntry { sequence, - record: None, - error: Some(AuditExportErrorCode::ReadFailed), + payload: AuditExportEntryPayload::Error { + error: AuditExportErrorCode::ReadFailed, + }, }; if !append_export_entry( &mut output, @@ -1872,13 +1877,15 @@ fn export_page_locked( let entry = match raw_record.map(sanitize_audit_value) { Some(Value::Object(record)) => AuditExportEntry { sequence, - record: Some(Value::Object(record)), - error: None, + payload: AuditExportEntryPayload::Record { + record: Value::Object(record), + }, }, _ => AuditExportEntry { sequence, - record: None, - error: Some(AuditExportErrorCode::RecordInvalid), + payload: AuditExportEntryPayload::Error { + error: AuditExportErrorCode::RecordInvalid, + }, }, }; if !append_export_entry( @@ -2602,13 +2609,14 @@ fn append_export_entry( } fn legacy_export_entry_line(entry: AuditExportEntry) -> io::Result { - serde_json::to_string(&entry.record.or_else(|| { - Some(serde_json::json!({ - "export_error": entry.error, + let line = match entry.payload { + AuditExportEntryPayload::Record { record } => record, + AuditExportEntryPayload::Error { error } => serde_json::json!({ + "export_error": error, "sequence": entry.sequence, - })) - })) - .map_err(|error| io::Error::other(error.to_string())) + }), + }; + serde_json::to_string(&line).map_err(|error| io::Error::other(error.to_string())) } fn cursor_is_after(previous: &AuditExportCursor, next: &AuditExportCursor) -> bool { @@ -3075,7 +3083,12 @@ mod tests { assert_eq!(second.entries.len(), 1); assert_eq!(second.entries[0].sequence, 1); assert_eq!(second.next_cursor.as_ref().unwrap().sequence, 1); - assert!(second.entries.iter().all(|entry| entry.record.is_some())); + assert!( + second + .entries + .iter() + .all(|entry| matches!(entry.payload, AuditExportEntryPayload::Record { .. })) + ); let third = log .export_page(None, None, second.next_cursor.as_ref(), 1) .expect("export completion page"); @@ -3383,7 +3396,7 @@ mod tests { .expect("retry unreadable file"); assert_eq!(second.entries.len(), 1); assert_eq!( - second.entries[0].error, + second.entries[0].error(), Some(AuditExportErrorCode::ReadFailed) ); assert!(second.complete); @@ -3413,7 +3426,7 @@ mod tests { .expect("export oversized line"); assert_eq!(first.entries.len(), 1); assert_eq!( - first.entries[0].error, + first.entries[0].error(), Some(AuditExportErrorCode::ReadFailed) ); let cursor = first @@ -3427,8 +3440,7 @@ mod tests { assert_eq!(second.entries.len(), 1); assert_eq!( second.entries[0] - .record - .as_ref() + .record() .and_then(|record| record.get("op")) .and_then(Value::as_str), Some("after-oversized") @@ -3476,7 +3488,7 @@ mod tests { .expect("export truncated line"); assert_eq!(page.entries.len(), 1); assert_eq!( - page.entries[0].error, + page.entries[0].error(), Some(AuditExportErrorCode::ReadFailed) ); assert!(page.complete); @@ -3607,8 +3619,7 @@ mod tests { assert_eq!(page.entries.len(), 1); assert_eq!( page.entries[0] - .record - .as_ref() + .record() .and_then(|record| record.get("op")) .and_then(Value::as_str), Some("Hello") @@ -3647,7 +3658,7 @@ mod tests { .expect("export corruption"); assert_eq!(first.entries.len(), 1); assert_eq!( - first.entries[0].error, + first.entries[0].error(), Some(AuditExportErrorCode::ReadFailed) ); let cursor = first.next_cursor.as_ref().expect("cursor after failure"); @@ -3659,8 +3670,7 @@ mod tests { assert_eq!(second.entries.len(), 1); assert_eq!( second.entries[0] - .record - .as_ref() + .record() .and_then(|record| record.get("op")) .and_then(Value::as_str), Some("AfterCorruption") @@ -3730,8 +3740,7 @@ mod tests { assert_eq!(page.entries.len(), 1); assert_eq!( page.entries[0] - .record - .as_ref() + .record() .and_then(|record| record.get("vm")) .and_then(Value::as_str), Some(opaque_digest("vm-a").as_str()) diff --git a/packages/d2b-contracts-broker/src/lib.rs b/packages/d2b-contracts-broker/src/lib.rs index 6227dbaee..b36e5065e 100644 --- a/packages/d2b-contracts-broker/src/lib.rs +++ b/packages/d2b-contracts-broker/src/lib.rs @@ -8,7 +8,9 @@ pub use broker_wire::BrokerRequest; pub use broker_wire::{ FORWARD_SOCKET_ENV, ForwardOperationOutcome, ForwardOperationRequest, ForwardOperationResponse, }; -pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}; +pub use d2b_contracts::audit_wire::{ + AuditExportCursor, AuditExportEntry, AuditExportEntryPayload, AuditExportErrorCode, +}; pub use d2b_contracts::privileges_w3::W3BrokerOperation; use schemars::JsonSchema; diff --git a/packages/d2b-contracts/src/audit_wire.rs b/packages/d2b-contracts/src/audit_wire.rs index be8d7d778..d9a358bc6 100644 --- a/packages/d2b-contracts/src/audit_wire.rs +++ b/packages/d2b-contracts/src/audit_wire.rs @@ -1,4 +1,8 @@ -use schemars::JsonSchema; +use schemars::{ + JsonSchema, + r#gen::SchemaGenerator, + schema::{Metadata, ObjectValidation, Schema, SchemaObject, SubschemaValidation}, +}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -23,16 +27,141 @@ pub enum AuditExportErrorCode { ReadFailed, } -/// One typed audit export entry. Exactly one of `record` and `error` is -/// populated by the broker. -#[derive(Clone, PartialEq, Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +/// One typed audit export entry. Its payload is exactly one of an audit record +/// or a closed export failure class, so the state the retired `record` / +/// `error` pair left representable - neither populated - cannot be built, and +/// an entry that carries both is refused at decode (RS-0546). +#[derive(Clone, PartialEq, Serialize, Deserialize)] +#[serde(try_from = "AuditExportEntryWire", into = "AuditExportEntryWire")] pub struct AuditExportEntry { + /// Monotonic page sequence of this entry. pub sequence: u64, + /// The exactly-one payload. + pub payload: AuditExportEntryPayload, +} + +/// The exactly-one payload of one [`AuditExportEntry`]. +#[derive(Clone, PartialEq)] +pub enum AuditExportEntryPayload { + /// One audit record, as the broker emitted it. + Record { + /// The emitted record. + record: Value, + }, + /// The closed failure class the broker reports in place of a record. + Error { + /// The reported class. + error: AuditExportErrorCode, + }, +} + +impl AuditExportEntry { + /// The record this entry carries, when its payload is a record. + pub fn record(&self) -> Option<&Value> { + match &self.payload { + AuditExportEntryPayload::Record { record } => Some(record), + AuditExportEntryPayload::Error { .. } => None, + } + } + + /// The export failure class this entry carries, when its payload is one. + pub fn error(&self) -> Option { + match &self.payload { + AuditExportEntryPayload::Error { error } => Some(*error), + AuditExportEntryPayload::Record { .. } => None, + } + } +} + +/// The entry's wire shape: `sequence` plus exactly one of `record` / `error`. +/// +/// The emitted members are the ones the retired optional pair emitted, and the +/// strict decode is the admission gate that refuses a frame carrying neither +/// member or both. +#[derive(Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct AuditExportEntryWire { + sequence: u64, #[serde(default, skip_serializing_if = "Option::is_none")] - pub record: Option, + record: Option, #[serde(default, skip_serializing_if = "Option::is_none")] - pub error: Option, + error: Option, +} + +impl From for AuditExportEntryWire { + fn from(entry: AuditExportEntry) -> Self { + let (record, error) = match entry.payload { + AuditExportEntryPayload::Record { record } => (Some(record), None), + AuditExportEntryPayload::Error { error } => (None, Some(error)), + }; + Self { + sequence: entry.sequence, + record, + error, + } + } +} + +impl TryFrom for AuditExportEntry { + type Error = &'static str; + + fn try_from(wire: AuditExportEntryWire) -> Result { + let payload = match (wire.record, wire.error) { + (Some(record), None) => AuditExportEntryPayload::Record { record }, + (None, Some(error)) => AuditExportEntryPayload::Error { error }, + (None, None) => return Err("audit export entry carries neither record nor error"), + (Some(_), Some(_)) => { + return Err("audit export entry carries both record and error"); + } + }; + Ok(Self { + sequence: wire.sequence, + payload, + }) + } +} + +impl JsonSchema for AuditExportEntry { + fn schema_name() -> String { + "AuditExportEntry".to_owned() + } + + fn json_schema(generator: &mut SchemaGenerator) -> Schema { + // The wire struct's own schema describes the emitted members and its + // strict admission; the payload enum is the Rust-side guard, so this + // schema is the wire shape plus the exactly-one constraint the type + // enforces. + let mut schema = match AuditExportEntryWire::json_schema(generator) { + Schema::Object(schema) => schema, + schema => return schema, + }; + schema.metadata = Some(Box::new(Metadata { + description: Some( + "One typed audit export entry. Exactly one of `record` and `error` is populated \ + by the broker." + .to_owned(), + ), + ..Default::default() + })); + schema.subschemas = Some(Box::new(SubschemaValidation { + one_of: Some(vec![required_member("record"), required_member("error")]), + ..Default::default() + })); + Schema::Object(schema) + } +} + +/// One `required: []` branch of [`AuditExportEntry`]'s exactly-one +/// constraint. +fn required_member(member: &str) -> Schema { + SchemaObject { + object: Some(Box::new(ObjectValidation { + required: [member.to_owned()].into_iter().collect(), + ..Default::default() + })), + ..Default::default() + } + .into() } impl Eq for AuditExportEntry {} @@ -42,12 +171,87 @@ impl core::fmt::Debug for AuditExportEntry { formatter .debug_struct("AuditExportEntry") .field("sequence", &self.sequence) - .field("has_record", &self.record.is_some()) - .field("error", &self.error) + .field("has_record", &self.record().is_some()) + .field("error", &self.error()) .finish() } } +#[cfg(test)] +mod tests { + use super::*; + + fn record_entry() -> AuditExportEntry { + AuditExportEntry { + sequence: 7, + payload: AuditExportEntryPayload::Record { + record: serde_json::json!({ "op": "ApplyNftables" }), + }, + } + } + + fn error_entry() -> AuditExportEntry { + AuditExportEntry { + sequence: 8, + payload: AuditExportEntryPayload::Error { + error: AuditExportErrorCode::ReadFailed, + }, + } + } + + #[test] + fn an_entry_emits_and_admits_exactly_one_payload() { + let record = record_entry(); + let json = serde_json::to_value(&record).expect("serialize a record entry"); + assert_eq!( + json, + serde_json::json!({ "sequence": 7, "record": { "op": "ApplyNftables" } }) + ); + assert_eq!( + serde_json::from_value::(json).expect("decode a record entry"), + record + ); + + let error = error_entry(); + let json = serde_json::to_value(&error).expect("serialize an error entry"); + assert_eq!( + json, + serde_json::json!({ "sequence": 8, "error": "read-failed" }) + ); + assert_eq!( + serde_json::from_value::(json).expect("decode an error entry"), + error + ); + + assert_eq!(record.record(), Some(&serde_json::json!({ "op": "ApplyNftables" }))); + assert_eq!(record.error(), None); + assert_eq!(error.record(), None); + assert_eq!(error.error(), Some(AuditExportErrorCode::ReadFailed)); + assert!(!format!("{record:?}").contains("ApplyNftables")); + } + + #[test] + fn an_entry_payload_is_admitted_exactly_once() { + for frame in [ + // Neither member: the state the optional pair admitted. + serde_json::json!({ "sequence": 1 }), + // Both members: two payloads are not one payload. + serde_json::json!({ + "sequence": 1, + "record": { "op": "ApplyNftables" }, + "error": "read-failed", + }), + // An unknown member stays refused. + serde_json::json!({ "sequence": 1, "record": { "op": "ApplyNftables" }, "stray": 1 }), + ] { + assert!( + serde_json::from_value::(frame.clone()).is_err(), + "an entry payload is admitted exactly once: {frame}" + ); + } + } +} + /// Failure classes for [`validate_audit_page`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AuditPageError { diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index a56042ca5..4112db0b4 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -446,19 +446,21 @@ fn parse_audit_page( .entries .into_iter() .map(|entry| { - entry - .record - .map(|record| match record { + use d2b_contracts::audit_wire::AuditExportEntryPayload; + + match entry.payload { + AuditExportEntryPayload::Record { record } => match record { Value::String(line) => line, record => record.to_string(), - }) - .unwrap_or_else(|| { + }, + AuditExportEntryPayload::Error { error } => { serde_json::json!({ - "export_error": entry.error, + "export_error": error, "sequence": entry.sequence, }) .to_string() - }) + } + } }) .collect(); (lines, frame.payload.next_cursor, frame.payload.complete) diff --git a/packages/d2bd-runtime/src/wire.rs b/packages/d2bd-runtime/src/wire.rs index af9850fcc..7e583803f 100644 --- a/packages/d2bd-runtime/src/wire.rs +++ b/packages/d2bd-runtime/src/wire.rs @@ -683,8 +683,9 @@ mod tests { let private = ExportBrokerAuditResponse { entries: vec![AuditExportEntry { sequence: 42, - record: Some(json!({"operation": "ApplyNftables"})), - error: None, + payload: d2b_contracts_broker::AuditExportEntryPayload::Record { + record: json!({"operation": "ApplyNftables"}), + }, }], next_cursor: Some(AuditExportCursor { day: "2026-08-13".to_owned(), From 95208a7b589586fd132d2d6afb84ec6dba90224a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:37:28 -0700 Subject: [PATCH 647/726] audit: fold the ten wave-5 deferrals and point the wave row at the integrated head Seven of the ten landed in wave 6 (RS-0248, RS-0249, RS-0250, RS-0332, RS-0413, RS-0537, RS-0963) and carry outcome/wave/commit; RS-0328, RS-0546 and RS-0547 are recorded as needs-contract with wave W6 and the deferral citation, carried over in slice w6-12 at this wave's budget stop. The wave row head cell names the integrated head. --- .../2026-09-24-rust-skills-audit/ledger.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index da9fbcac7..a4066a2eb 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -42,7 +42,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | -| W6 | `088721b8d` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred): all 15 dispatched rows disposed - 12 applied, 3 applied-variant with recorded deviations (RS-0952, RS-0454, RS-0333); 9 slices in six surface groups, all merged into `phase-w6-integration`, plus three integration-direct commits (the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh for the wave-6 line shifts). Two preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs`, re-linted once the w6-01 rewrite touched that file; and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the head the five preflights measured; this row ships in a ledger-only commit on top of it. | +| W6 | `d9748822b` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): the 15 originally dispatched rows are all disposed (12 applied, 3 applied-variant with recorded deviations RS-0952, RS-0454, RS-0333) and the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 - 7 of them landed in wave 6 (slices w6-10, w6-11, w6-13, w6-14, w6-15) and 3 are carried over in slice w6-12 for Main to merge or block (see their rows). 9 slices in six surface groups plus the deferral slices, all merged into `phase-w6-integration`, plus the integration-direct commits (the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh). Preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs` re-linted once the w6-01 rewrite touched that file, and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the head the five preflights measured; this row ships in a ledger-only commit on top of it. | ## Findings (965 rows) @@ -303,9 +303,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | | `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/host_generation.rs | HandoffCoordinator.source_remains_usable field dropped; accessor derives from state != Completed; old durable records deserialize (unknown field ignored); wire response field untouched. | | | `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/broker_wire.rs | CanonicalAuditDigest tuple field made private; parse and as_str remain the only construction/read paths; hand-written Deserialize and serde transparent keep wire shape. | | -| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | | | | `public_wire.rs:2166, public_wire.rs:2203` | | | -| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | | | -| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:316, public_wire.rs:311` | | | +| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | applied | 6 | caa29e248 | `public_wire.rs:2166, public_wire.rs:2203` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. AuditResponse's complete/next_cursor pair replaced by the closed AuditPageEnd (Complete / More(cursor)); the crate-local validate_audit_page is deleted and from_parts reports the canonical d2b_contracts::audit_wire::AuditPageError classes, so the admission error text is unchanged; AuditResponse keeps byte- and key-order-identical Serialize via the borrowing AuditResponseOut plus a manual JsonSchema; consumers migrated (d2b/src/dispatch.rs pagination, d2bd-runtime/src/wire.rs audit_response, d2bd/src/composition.rs). Gate: cargo check -p d2b-contracts-control -p d2bd-runtime -p d2bd -p d2b --all-targets rc=0 and the slice's schema drift targets. | | +| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied | 6 | e9cb637c3 | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11. Status DTO state vocabularies are closed kebab-case enums: RealmMode/RealmGatewayState (the `not reported by d2bd` sentinel preserved), QemuMediaRunnerState/QemuMediaRegistryState, PublicReadModelKind, VmAutostartMode; the crate-local duplicate kind and the parallel kind_name:&'static str are deleted, d2bd-runtime publishes the contract enum, and a spelling test pins all 21 spellings. Emitted bytes: the CLI goldens are byte-unchanged; the generated CLI schemas and the v2 wire-protocol schema plus the daemon-api enum table were regenerated with the xtask gen commands and proven by gen_cli_schemas_drift + gen_schemas_drift + gen_daemon_api_drift (3 of 3 pass on the committed tree). | | +| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied-variant | 6 | caa29e248 | `public_wire.rs:316, public_wire.rs:311` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. MutationFlags' three booleans became MutationMode { DryRun, Apply } + MutationFlags { mode, json } with from_flags/to_flags; the seven flattened flag fields lost `default` and the three host requests lost Default, so a payload selecting neither mode fails admission. Recorded deviations: (a) the raw-JSON public frame cannot lose its refusal (it never passes typed admission), so the pair is parsed at the boundary in mutation_mode_from_request and keeps the byte-identical mutating-verb invalid-request envelope, while typed frames fail admission; (b) a hand-written frame setting both flags keeps the long-standing dry-run precedence instead of gaining a new refusal class. | | | `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | | `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | | | | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | | | | `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | @@ -387,11 +387,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | -| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | | | +| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 had it committed on phase-w6-12 (3c3454697 `refactor(d2b-contracts-broker): take the test-only peer uid off the envelope`) but the slice was still running at this wave's budget stop, so its gates were not re-run on a frozen tree and the merge into phase-w6-integration was not made. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | 4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | | `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | | `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | -| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | | | | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | | | +| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | applied | 6 | e9cb637c3 | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11, as a versioned transition (first assessed blocked on the frozen v1 schema; the operator rule that format compatibility is a co-change list applies, and the census found no freeze policy to cite). The dead pub AuditEntry export is deleted; census at HEAD: the definition only (the live public AuditResponse carries AuditExportEntry pages), no golden, no live consumer; the v1 schema stays the byte-identical historical artifact and the generated v2 schema never contained the name (gen_schemas_drift + gen_daemon_api_drift green). Outside-tree observer: none - the v1-era AuditResponse shape has not been emitted since the page moved to AuditExportEntry. | | | `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied-variant | 6 | dc145cf0c | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Caller-migration variant (recorded deviation; the ledger's census was stale): the two live external callers of HelperLaunchRequest::validate_bounds (d2b-unsafe-local-helper protocol.rs:157, runtime.rs:333) migrated to the pub free fn validate_unsafe_local_resource_identity; then both methods narrowed to pub(crate). Wire types and serde admission unchanged. | | | `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | @@ -466,7 +466,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 0cb5d7b68 | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | | | | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | | | | `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | -| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | | | | `src/host.rs:389, src/host.rs:13` | | | +| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | applied-variant | 6 | ab90777de | `src/host.rs:389, src/host.rs:13` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-14. HostReconciler::reject_operator_status_fields (zero callers outside its own tests at HEAD) is now enforced at the daemon's operator status admission (public_update_status_request, the public dispatch's UpdateStatus arm): an operator-submitted Host status naming isolationPosture or isolationPostureMessage, in either request spelling and including the explicit null form, is refused before the row is read. Recorded deviations: the site is the daemon admission rather than d2b-resource-api's update_status (that crate cannot depend on d2b-provider-system-core without inverting the layering), and the provider-session dispatch keeps its own admission because the system-core reconciler's own publication legitimately derives those fields (ADR-046-provider-system-core 4.1.4). Co-change: the typed refusal ResourceRuntimeError::HostStatusFieldNotOwned with its error frame, the system-core host module doc, the admission test an_operator_status_naming_a_host_reconciler_owned_field_is_refused. No serialized shape moves. | | | `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | make the `ownership` module private; the root re-export of the owned/disowned type lists is the single surface. Shares commit 31ff8b396 with RS-0409 (the audit's own census pairs these two module-surf | | | `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | narrow `reconcile_observed`/`HostProbeSnapshot` to `pub(crate)` with the crate-internal-only callers retained; drop the now-private seam from the crate's pub re-export. Shares commit 31ff8b396 with th | | | `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | forward `HostProbeMetadata` from the host re-export while dropping the zero-external-consumer `HostProbeSnapshot` constant from the public surface; the crate's probe seam stays internal until a consum | | @@ -507,7 +507,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 1ed0521fa | packages/d2bd-runtime/src/console_session.rs | Dropped unused _vm parameter from spawn_ch_serial_drainer and the hardcoded "ch-console".to_owned() allocation at the create_ch_session call site. | | | `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e8e7a2d51 | packages/d2bd-runtime/src/console_session.rs | Deleted dead pub DrainerSource enum (census re-run: pattern DrainerSource over packages = 1 hit, the definition itself; zero constructions) and its #[allow(dead_code)]. | | | `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 26d5c1119 | packages/d2bd-runtime/src/console_session.rs | ConsoleRing/ConsoleSession fields made private; ConsoleRing exposes push_bytes/set_eof (notify internally), read_at, base_offset, notify(); ConsoleSession exposes provider_kind/ring/stdin_tx accessors | | -| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | | | | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | | | +| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | applied-variant | 6 | 7739ae6f5 + 128a340f0 | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slices w6-15 and w6-13. Applied: d2b-provider-clipboard-wayland PickerIpcError::Frame/String became Frame(#[from] FramingError) + Read(#[source] io::Error) + ClosedMidFrame with every Display byte-identical; d2b-provider-transport-azure-relay CredentialUnavailable/TransportUnavailable carry typed sources through the explicit Error::source impl (applied-variant: the file hand-writes Display/Error, so no #[source] attributes exist there) with code() strings unchanged; d2bd TypedError carries the audio failure classes as typed leaf variants (applied-variant: failure class as variants rather than a source object, because d2bd-runtime cannot name provider-typed sources and std sources are not Clone). Already-fixed at HEAD, each with its commit: d2b-broker ops/usbip_lock.rs (RS-0454 fd5b41b4b), ops/hosts.rs (84d4cb0b9), d2b-resource-runtime (fa4907468), d2bd-runtime vsock (c9addc3aa). Residual not in the row: PickerIpcError::Socketpair/Spawn/FdFlags still flatten their io/FdMappingCollision errors - flagged, not expanded. | | | `RS-0477` | `err` | `d2b` | medium | actionable | leaf | applied-variant | U3 | 7256bc918 | packages/d2b/src/lib.rs | Added structured code field to CliFailure; populated in ZoneContext::failure; can_fallback_to_local_state and reconcile_deadline match on it. Field is String not &'static str because validate_response | | | `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | | | | `packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, ` | | | | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | @@ -591,7 +591,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0527` | `err` | `d2bd` | medium | actionable | family | applied | 4 | ea55636aa | `packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511` | applied in two commits: f3028c0ee (d2bd-side propagation) + ea55636aa (CredentialRuntime::dependency_facts trait signature Result>, every impl and call site migrated; re-dispatched per Main's directive 2026-09-25) | | | `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d4fe83812 | packages/d2bd/src/composition.rs | dispatch_audit's unrecognized severity arm now returns TypedError::WireInvalidFrame { detail: "audit filter has an invalid severity".to_owned() } instead of InternalIo, so caller input errors surface | | | `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d1a472077 | packages/d2bd/src/composition.rs | ActivationLockGuard::drop now logs finish_activation failures via tracing::warn!(zone = %self.zone, error = %error, ...) instead of `let _ =`, mirroring the file's house style for coordinator refusals | | -| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | | | | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | | | +| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | applied | 6 | dba2d00f2 | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-13. The audio mutation paths report a user-input refusal through the typed kinds TypedError::AudioVmNotFound (audio-vm-not-found, exit 2) and TypedError::AudioNotEnabled (audio-not-enabled, exit 70) instead of flattening both into TypedError::InternalIo { context, detail }; lock/read/write/host failures keep internal-io. Co-change: the two daemon wire kinds with their envelope text/exit codes/hello-rejection arm, the four mutation-site constructors, and hand-written rows in docs/reference/error-codes.md (the generated block is untouched, so gen_error_codes_drift stays the proof). Wire-visible: a public-socket client that matched internal-io on an unknown or audio-less VM sees the new kinds - the needs-contract move this row asked for; no in-tree consumer branches on the old slug. | | | `RS-0534` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | 96be9307a | packages/d2bd/src/resource_plane_v3.rs | ConstructionInputs::production now propagates attach_process_providers failures: state.provider_runtime.attach_process_providers(...).map_err(/error/ PlaneError::Authority(error.into()))? instead of ` | | | `RS-0536` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | fd6778735 | packages/d2bd/src/process_provider_runtime.rs | serving_worker_launch_args now warns when the 0700 enforcement on the worker socket parent fails: tracing::warn!(zone = %zone, socket_dir = %parent.display(), error = %error, ...) mirrors the pidfd sn | | | `RS-0528` | `err` | `d2bd` | low | actionable | family | | | | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | | | @@ -604,8 +604,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | applied | 6 | f25b21e84 | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu [reconstructed: m with `#[serde(rename_all = "lowercase")]`) keeps the serialized shapes "unknown"/"completed" identical, so no DURABLE_VERSION bump is needed]. DurableRecord.outcome typed as CellOutcome with the derive; hand match and re-parse deleted; unknown-outcome fail-closed preserved via serde unknown-variant rejection mapped to CorruptDurable. | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | -| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | | | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | | | -| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | | | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | | | +| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 owned it and its worktree was still dirty at handover (AuditExportEntry record/error exactly-one payload enum), so nothing is committed for it. Disposition pending: Main finishes or blocks it with the failing command. | | +| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 committed 8351954a0 `test(d2b-contracts-broker): pin admission of the flattened unit requests` (the OpenUnitPidfdRequest/StopUnitRequest flatten + deny_unknown_fields repair path) but the slice was still running at this wave's budget stop, so the row was not verified or merged. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | From 3d0b38bf0a094735dce92b09be4c4d948a46bf83 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:39:10 -0700 Subject: [PATCH 648/726] fix(d2b-broker): keep the layer1-bootstrap build warning-clean The RS-0328 split of the caller context into the kernel-authenticated `peer_uid` and the gate-facing `effective_uid` left `peer_uid` read only by the production-wire profile-refusal audit, so the `layer1-bootstrap` feature build failed on `-D unused-variables` / `-D warnings`. The unit test build does not enable that feature, so only the feature build saw it. The discard mirrors the `request_fds` discard beside it, and the feature build now succeeds with the same behavior: the bootstrap wire has no profile model and audits with `effective_uid` as before. Gate: cargo build -p d2b-broker-composition --features layer1-bootstrap --bin d2b-broker-layer1-bootstrap (rc=0); env CARGO_BIN_EXE_d2b-broker= target/debug/d2b-broker-layer1-bootstrap cargo test -p d2b-broker --features layer1-bootstrap --test broker_socket_acl (see the slice report). --- packages/d2b-broker/src/runtime.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index e798e15cc..4be60bec0 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -1743,6 +1743,8 @@ async fn answer_request( ) -> io::Result { #[cfg(feature = "layer1-bootstrap")] let _ = &request_fds; // the bootstrap wire carries no request descriptors + #[cfg(feature = "layer1-bootstrap")] + let _ = peer_uid; // the profile-refusal audit that names the kernel uid is production-wire only // Load the bundle resolver from the configured `bundle_path` for every // request. The broker is socket-activated but can remain alive across // `nixos-rebuild switch`; treating the bundle as process-lifetime From 315581b7c28bf47e32f480c71c06a8e31ce10e0d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:39:19 -0700 Subject: [PATCH 649/726] audit: record the w6-12 commits and the unmerged consumer file in the carry-over rows RS-0328, RS-0546 and RS-0547 now name the commits phase-w6-12 carries and the uncommitted consumer migration that kept the slice from merging, so Main has the exact state to finish or block them from. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index a4066a2eb..eedf0814b 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -387,7 +387,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | -| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 had it committed on phase-w6-12 (3c3454697 `refactor(d2b-contracts-broker): take the test-only peer uid off the envelope`) but the slice was still running at this wave's budget stop, so its gates were not re-run on a frozen tree and the merge into phase-w6-integration was not made. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | +| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 had it committed on phase-w6-12 (3c3454697 `refactor(d2b-contracts-broker): take the test-only peer uid off the envelope`) but the slice was still running at this wave's budget stop, and the branch still carried an uncommitted consumer migration for it (d2b-broker/src/runtime.rs) at handover, so its gates were not re-run on a frozen tree and it was not merged. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | 4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | | `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | | `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | @@ -604,8 +604,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | applied | 6 | f25b21e84 | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu [reconstructed: m with `#[serde(rename_all = "lowercase")]`) keeps the serialized shapes "unknown"/"completed" identical, so no DURABLE_VERSION bump is needed]. DurableRecord.outcome typed as CellOutcome with the derive; hand match and re-parse deleted; unknown-outcome fail-closed preserved via serde unknown-variant rejection mapped to CorruptDurable. | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | -| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 owned it and its worktree was still dirty at handover (AuditExportEntry record/error exactly-one payload enum), so nothing is committed for it. Disposition pending: Main finishes or blocks it with the failing command. | | -| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 committed 8351954a0 `test(d2b-contracts-broker): pin admission of the flattened unit requests` (the OpenUnitPidfdRequest/StopUnitRequest flatten + deny_unknown_fields repair path) but the slice was still running at this wave's budget stop, so the row was not verified or merged. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | +| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 committed 1ab759f13 `refactor(d2b-contracts): make the audit export entry payload exactly one` on phase-w6-12, but the slice had not finished (a consumer migration in d2b-broker/src/runtime.rs was still uncommitted) and its gates were not re-run on a frozen tree at this wave's budget stop, so it was not merged. Disposition pending: Main merges phase-w6-12 after the slice commits and re-verifies, or records the block with its failing command. | | +| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 committed 8351954a0 `test(d2b-contracts-broker): pin admission of the flattened unit requests` (the OpenUnitPidfdRequest/StopUnitRequest flatten + deny_unknown_fields repair path) but the slice was still running at this wave's budget stop, and the slice had not finished at this wave's budget stop, so the row was not verified or merged. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | From b7c9427cd1e0d103e5ea79daf1a139e4f9559a77 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:40:26 -0700 Subject: [PATCH 650/726] audit: fold the w6-12 rows as applied and point the wave row at the merged head RS-0328, RS-0546 and RS-0547 move from needs-contract/W6 to applied/6 with the slice w6-12 commits; the wave row head cell now names b07a7e887, the head that carries every deferral merge. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index eedf0814b..75b704f8d 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -42,7 +42,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | -| W6 | `d9748822b` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): the 15 originally dispatched rows are all disposed (12 applied, 3 applied-variant with recorded deviations RS-0952, RS-0454, RS-0333) and the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 - 7 of them landed in wave 6 (slices w6-10, w6-11, w6-13, w6-14, w6-15) and 3 are carried over in slice w6-12 for Main to merge or block (see their rows). 9 slices in six surface groups plus the deferral slices, all merged into `phase-w6-integration`, plus the integration-direct commits (the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh). Preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs` re-linted once the w6-01 rewrite touched that file, and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the head the five preflights measured; this row ships in a ledger-only commit on top of it. | +| W6 | `b07a7e887` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): the 15 originally dispatched rows are all disposed (12 applied, 3 applied-variant with recorded deviations RS-0952, RS-0454, RS-0333) and the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 - 7 of them landed in wave 6 (slices w6-10, w6-11, w6-13, w6-14, w6-15) and 3 are carried over in slice w6-12 for Main to merge or block (see their rows). 9 slices in six surface groups plus the deferral slices, all merged into `phase-w6-integration`, plus the integration-direct commits (the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh). Preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs` re-linted once the w6-01 rewrite touched that file, and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the head the five preflights measured; this row ships in a ledger-only commit on top of it. | ## Findings (965 rows) From 36f927a246a60425e72286a9db61aba09f12c211 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:40:45 -0700 Subject: [PATCH 651/726] xtask: regenerate the async-gate inventory on the merged tree The wave-5 merge conflicted in this generated file, and the first regeneration attempt parsed the conflicted content instead of the merged sources and failed; the commit that followed carried markers. Restore the branch's valid copy, regenerate from the merged tree, and verify the read-only check passes. --- packages/xtask/data/async-gate-inventory.json | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 18967f21c..888eb692c 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -1078,35 +1078,17 @@ }, { "file": "packages/d2bd/src/composition.rs", -<<<<<<< HEAD - "line": 10812, -||||||| 12e510b55 - "line": 10790, -======= - "line": 10854, ->>>>>>> phase-w5-integration + "line": 10876, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", -<<<<<<< HEAD - "line": 26331, -||||||| 12e510b55 - "line": 26251, -======= - "line": 26361, ->>>>>>> phase-w5-integration + "line": 26441, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", -<<<<<<< HEAD - "line": 26728, -||||||| 12e510b55 - "line": 26648, -======= - "line": 26758, ->>>>>>> phase-w5-integration + "line": 26838, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 564e0e5d6f85013e1daf1652c7184ae75fc9e700 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:42:57 -0700 Subject: [PATCH 652/726] audit: fold RS-0328, RS-0546 and RS-0547 and point the wave row at the merged head RS-0328 and RS-0546 land applied (3c3454697, 1ab759f13); RS-0547 reads skipped-stale (8351954a0) - its premise is inverted at HEAD, where the container's deny_unknown_fields is the guard serde honours through a flattened field, so the requested admission pin landed instead of a repair. phase-w6-12's four-commit tip is merged as b07a7e887; the wave-row head cell names that merged head and its four gate cells stay `not run (Main gates)`. Supersedes the carry-over rows recorded in 315581b7c and the head-cell line in b7c9427cd, both landed mid-close. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 75b704f8d..b7f7b95a7 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -42,7 +42,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | -| W6 | `b07a7e887` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): the 15 originally dispatched rows are all disposed (12 applied, 3 applied-variant with recorded deviations RS-0952, RS-0454, RS-0333) and the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 - 7 of them landed in wave 6 (slices w6-10, w6-11, w6-13, w6-14, w6-15) and 3 are carried over in slice w6-12 for Main to merge or block (see their rows). 9 slices in six surface groups plus the deferral slices, all merged into `phase-w6-integration`, plus the integration-direct commits (the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh). Preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs` re-linted once the w6-01 rewrite touched that file, and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the head the five preflights measured; this row ships in a ledger-only commit on top of it. | +| W6 | `b07a7e887` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs` re-linted once the w6-01 rewrite touched that file, and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the integration head b07a7e887; the five preflight commands were run on the code tree it carries (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake), and this row ships in ledger-only commits on top of it. | ## Findings (965 rows) @@ -387,7 +387,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | -| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 had it committed on phase-w6-12 (3c3454697 `refactor(d2b-contracts-broker): take the test-only peer uid off the envelope`) but the slice was still running at this wave's budget stop, and the branch still carried an uncommitted consumer migration for it (d2b-broker/src/runtime.rs) at handover, so its gates were not re-run on a frozen tree and it was not merged. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | +| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | applied | 6 | 3c3454697 | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). BrokerRequestEnvelope no longer carries the test-only test_peer_uid member: the harness (the bootstrap probe CLI and the integration tests) sends that override as a testPeerUid member beside the envelope, and only a --test-mode broker unwraps it in front of its strict decode, so the wire contract carries no test seam and every other broker refuses a frame that carries one; production frames stop emitting the "testPeerUid": null member. New d2b_broker::runtime::{TEST_PEER_UID_FIELD, test_peer_uid_frame} name the harness-only override, and the contract test broker_request_envelope_refuses_a_test_only_peer_uid_member pins the refusal. Co-change: the broker runtime and bootstrap call sites and the four broker integration targets (profile_separation, guest_profile, socket_activation, broker_protocol_compatibility). Gate on the merged tree: cargo test -p d2b-contracts-broker rc=0, cargo test -p d2b-broker rc=0 (700 lib tests plus the spawned-broker integration targets, each driving the new frame-member seam against a real broker), cargo check over the seven touched crates --all-targets rc=0, gen_daemon_api_drift green. | | | `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | 4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | | `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | | `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | @@ -604,8 +604,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | | | | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | applied | 6 | f25b21e84 | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu [reconstructed: m with `#[serde(rename_all = "lowercase")]`) keeps the serialized shapes "unknown"/"completed" identical, so no DURABLE_VERSION bump is needed]. DurableRecord.outcome typed as CellOutcome with the derive; hand match and re-parse deleted; unknown-outcome fail-closed preserved via serde unknown-variant rejection mapped to CorruptDurable. | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | -| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 committed 1ab759f13 `refactor(d2b-contracts): make the audit export entry payload exactly one` on phase-w6-12, but the slice had not finished (a consumer migration in d2b-broker/src/runtime.rs was still uncommitted) and its gates were not re-run on a frozen tree at this wave's budget stop, so it was not merged. Disposition pending: Main merges phase-w6-12 after the slice commits and re-verifies, or records the block with its failing command. | | -| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | needs-contract | W6 | | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3). Carried over: slice w6-12 committed 8351954a0 `test(d2b-contracts-broker): pin admission of the flattened unit requests` (the OpenUnitPidfdRequest/StopUnitRequest flatten + deny_unknown_fields repair path) but the slice was still running at this wave's budget stop, and the slice had not finished at this wave's budget stop, so the row was not verified or merged. Disposition pending: Main merges phase-w6-12 after re-verifying, or records the block with its failing command. | | +| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | applied | 6 | 1ab759f13 | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). AuditExportEntry now carries exactly one payload through the closed AuditExportEntryPayload enum (Record { record } or Error { error }) instead of the independent record/error optional pair, so an entry that carries neither or both is unrepresentable and refused at decode; the emitted members are unchanged (sequence plus exactly one of record or error), so the broker audit page and the public daemon audit page keep their JSON and the legacy_export_entry_line renderer keeps its output. Co-change: the d2b-contracts-broker re-export, d2b-broker/src/audit.rs, the d2b entry-mapping closure, the d2bd-runtime wire literal, and the regenerated docs/reference/daemon-api.md plus docs/reference/schemas/v2/wire-protocol.json. Gate on the merged tree: cargo test -p d2b-contracts rc=0 (120 tests plus 1 doctest, including an_entry_emits_and_admits_exactly_one_payload and an_entry_payload_is_admitted_exactly_once), cargo test -p d2b-broker rc=0, cargo check over the seven touched crates --all-targets rc=0, gen_schemas_drift and gen_daemon_api_drift green. | | +| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | skipped-stale | 6 | 8351954a0 | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> re-verified at HEAD in slice w6-12, which merged into phase-w6-integration (merge b07a7e887): the claim does not hold at HEAD, so no admission edit was made. The audited premise has the guard inverted - serde 1.0.229 refuses unknown members through the CONTAINER's deny_unknown_fields, while the FLATTENED type's own deny_unknown_fields is the inert one, and both audited requests (OpenUnitPidfdRequest, StopUnitRequest) carry the container attribute, so a stray member is refused today and there is no silently-accepted state to repair. Raw probe kept at .scratch/rs0547-flatten-probe.txt (w6-12 worktree): container-deny + inner-lax still refuses the stray member (unknown field `unknownMember`), container-lax + inner-deny and container-lax + inner-lax accept it, and serde_json::from_value and from_slice both refuse. The requested admission pin landed anyway as 8351954a0 (flattened_unit_requests_refuse_unknown_members), so the observed contract is pinned rather than repaired; gate: cargo test -p d2b-contracts-broker rc=0. | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | | | | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | | | From 4e47723a1ed16fb2bfe61e3f9b2b74fc648b5187 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:48:45 -0700 Subject: [PATCH 653/726] repo: refresh async-gate inventory for the merged head's line shifts Ten marker-honored sites moved, so the keys-by-(file, line) inventory was stale and //bazel/checks/policy:check-async-gate failed on the merged head. Regenerated with check-async-gate --write-inventory (254 sites, 910 files scanned, no blocking calls in async contexts). Attribution: the four packages/d2b-broker/src/runtime.rs sites moved with the w6-12 merge (the RS-0328/RS-0546 consumer migration added lines above them); the pairs in packages/d2bd/src/composition.rs and packages/d2bd/src/resource_runtime.rs were already stale on the handed-over integration head 315581b7c, i.e. the red predates this merge and no preflight had run on the deferral head. --- packages/xtask/data/async-gate-inventory.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 55bdb28b2..8dc0cec32 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -123,22 +123,22 @@ }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8153, + "line": 8255, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8220, + "line": 8322, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8437, + "line": 8539, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8514, + "line": 8616, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1078,17 +1078,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10810, + "line": 10800, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26271, + "line": 26280, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26668, + "line": 26677, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1098,17 +1098,17 @@ }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 2481, + "line": 2483, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 7501, + "line": 7503, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 8652, + "line": 8654, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 6aceb9f4cc91cfa02304cd892f6ab80d4bb4f78b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 19:52:15 -0700 Subject: [PATCH 654/726] audit: point the wave row at the repair head and record the async-gate refresh The five preflight commands ran on 4e47723a1 (PF1-PF4 rc=0; the bazel checks lane 987/988 with only the pre-existing wave-4 supply-chain red, the daemon_state_persistence flake having cleared and passing in isolation), so the head cell names that code head and the row lists the three close repairs (the clone_on_copy re-lint, the stale otel exemption, the async-gate inventory refresh). Ledger-only on top of the repair. --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index b7f7b95a7..7e2603e3f 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -42,7 +42,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | -| W6 | `b07a7e887` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Preflight failures were repaired on the way (a pre-existing `clone_on_copy` in `d2b-core/src/privileges.rs` re-linted once the w6-01 rewrite touched that file, and the family-knowledge exemption w6-02 left stale in `xtask/src/provider_crate_policy.rs`); the four clipped reason cells were repaired and marked [reconstructed]. The head cell names the integration head b07a7e887; the five preflight commands were run on the code tree it carries (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake), and this row ships in ledger-only commits on top of it. | +| W6 | `4e47723a1` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Three close repairs: the pre-existing `clone_on_copy` re-linted in `d2b-core/src/privileges.rs`, the stale family-knowledge exemption in `xtask/src/provider_crate_policy.rs`, and the async-gate hatch inventory re-recorded for ten moved marker sites (4e47723a1: four in `d2b-broker/src/runtime.rs` moved with the w6-12 merge, six in `d2bd` were already stale on the handed-over head, so that red was waiting on a head no preflight had measured). The four clipped reason cells were repaired and marked [reconstructed]. The head cell names the code head 4e47723a1 that the five preflight commands measured (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake); this row ships in ledger-only commits on top of it. | ## Findings (965 rows) From 8d420f30cd3adae6daf824950a678bd7fe7cbc7e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:35:24 -0700 Subject: [PATCH 655/726] fix(d2b-provider-volume-local): pass the borrowed volume ref to the binding hasher Taking the volume reference by borrow in `desired_binding_intents` left one call site still writing `&volume_ref`, which now re-borrows a reference. The crate builds under `-D warnings`, so clippy's `needless_borrow` broke the volume-local clippy target and, behind it, the check lane. Forward the borrowed reference unchanged; the hashed inputs and every emitted binding name are identical. --- changelog.d/fix-postw6-check-lane-clippy.md | 6 ++++++ packages/d2b-provider-volume-local/src/bindings.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changelog.d/fix-postw6-check-lane-clippy.md diff --git a/changelog.d/fix-postw6-check-lane-clippy.md b/changelog.d/fix-postw6-check-lane-clippy.md new file mode 100644 index 000000000..45dfc3e76 --- /dev/null +++ b/changelog.d/fix-postw6-check-lane-clippy.md @@ -0,0 +1,6 @@ +### Fixed + +- The volume-local binding derivation forwards its borrowed volume reference + to the binding-name hasher instead of re-borrowing it, so the crate builds + clean under the deny-warnings lint set. The emitted binding names, their + inputs, and every caller are unchanged. diff --git a/packages/d2b-provider-volume-local/src/bindings.rs b/packages/d2b-provider-volume-local/src/bindings.rs index eddf77dc3..24462875f 100644 --- a/packages/d2b-provider-volume-local/src/bindings.rs +++ b/packages/d2b-provider-volume-local/src/bindings.rs @@ -88,7 +88,7 @@ pub fn desired_binding_intents( if attachment.transport() != AttachmentTransport::Virtiofs { continue; } - let name = derive_binding_name(&volume_ref, attachment)?; + let name = derive_binding_name(volume_ref, attachment)?; intents.push(BindingIntent { name, owner_ref: volume_ref.clone(), From e1341233fafbe85765e0e03e22d1ac5ef0264b3a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:45:38 -0700 Subject: [PATCH 656/726] refactor(d2b-contracts-zone-session): drop the by-value handshake-offer conversion Every caller of HandshakeOffer::from already holds a borrowed endpoint policy, so the owned From implementation had no remaining caller and only invited a clone at each admission site. The borrowed conversion stays total; the tests that built an offer from an owned policy now borrow it. --- .../src/v3/component_session.rs | 18 ------------------ .../d2b-session/tests/component_session.rs | 6 +++--- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/packages/d2b-contracts-zone-session/src/v3/component_session.rs b/packages/d2b-contracts-zone-session/src/v3/component_session.rs index cc84e6236..1ad2a354a 100644 --- a/packages/d2b-contracts-zone-session/src/v3/component_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/component_session.rs @@ -1206,24 +1206,6 @@ impl EndpointPolicy { } } -impl From for HandshakeOffer { - fn from(value: EndpointPolicy) -> Self { - Self { - purpose: value.purpose, - purpose_class: value.purpose_class, - initiator_role: value.initiator_role, - responder_role: value.responder_role, - service: value.service, - schema_fingerprint: value.schema_fingerprint, - noise_profile: value.noise_profile, - limits: value.limits, - transport_binding: value.transport_binding, - reconnect_generation: value.reconnect_generation, - attachment_policy: value.attachment_policy, - } - } -} - impl From<&EndpointPolicy> for HandshakeOffer { fn from(value: &EndpointPolicy) -> Self { Self { diff --git a/packages/d2b-session/tests/component_session.rs b/packages/d2b-session/tests/component_session.rs index 8696903db..34b374429 100644 --- a/packages/d2b-session/tests/component_session.rs +++ b/packages/d2b-session/tests/component_session.rs @@ -383,13 +383,13 @@ fn fixed_negotiation_and_all_noise_profiles_are_strict() { let mut remote_nn = policy(&original); remote_nn.transport_binding.locality = Locality::Remote; assert_eq!( - HandshakeOffer::from(remote_nn).validate().unwrap_err(), + HandshakeOffer::from(&remote_nn).validate().unwrap_err(), d2b_session::contract::ContractError::IdentityEvidenceMismatch ); let mut wrong_bootstrap = policy(&original); wrong_bootstrap.purpose = EndpointPurpose::Bootstrap; assert_eq!( - HandshakeOffer::from(wrong_bootstrap) + HandshakeOffer::from(&wrong_bootstrap) .validate() .unwrap_err(), d2b_session::contract::ContractError::IdentityEvidenceMismatch @@ -397,7 +397,7 @@ fn fixed_negotiation_and_all_noise_profiles_are_strict() { let mut sensitive_nn = policy(&original); sensitive_nn.purpose = EndpointPurpose::SensitiveCredential; assert_eq!( - HandshakeOffer::from(sensitive_nn).validate().unwrap_err(), + HandshakeOffer::from(&sensitive_nn).validate().unwrap_err(), d2b_session::contract::ContractError::IdentityEvidenceMismatch ); } From 1fb8eff8063f36562fb760388967bc957b6c962d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:50:10 -0700 Subject: [PATCH 657/726] refactor(d2b-resource-runtime): sort target listings through an owned identity key The identity comparator borrowed its tuple from the elements it was called on, so the key form that removes the closure cannot satisfy the key bound: a key has to outlive the borrow. Both listings now sort with sort_by_cached_key over the same zone, type-name, and name tuple, which is cloned once per element rather than twice per comparison, and the helper documents why the key is owned. --- .../w7-06-session-borrow-and-resource-ordering.md | 10 ++++++++++ packages/d2b-resource-runtime/src/guest_target.rs | 10 +++++++--- packages/d2b-resource-runtime/src/target.rs | 10 +++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 changelog.d/w7-06-session-borrow-and-resource-ordering.md diff --git a/changelog.d/w7-06-session-borrow-and-resource-ordering.md b/changelog.d/w7-06-session-borrow-and-resource-ordering.md new file mode 100644 index 000000000..e69bc007c --- /dev/null +++ b/changelog.d/w7-06-session-borrow-and-resource-ordering.md @@ -0,0 +1,10 @@ +### Changed + +- `HandshakeOffer` now converts from an endpoint policy by borrow only: + the by-value `From` implementation is gone, so every + caller passes a reference and no admission path clones a policy purely + to build a comparison offer (`component_session.rs`). +- Guest target assignment and instance listings sort resource identities + with an owned cached key over the zone, type name, and name fields, + replacing a comparator that could not be expressed as a key + (`target.rs`, `guest_target.rs`). diff --git a/packages/d2b-resource-runtime/src/guest_target.rs b/packages/d2b-resource-runtime/src/guest_target.rs index d3f5cfa41..f6a31202c 100644 --- a/packages/d2b-resource-runtime/src/guest_target.rs +++ b/packages/d2b-resource-runtime/src/guest_target.rs @@ -519,7 +519,7 @@ impl GuestTargetRuntime { }; let mut instances: Vec = state.values().cloned().collect(); - instances.sort_by(|left, right| identity_order(&left.source).cmp(&identity_order(&right.source))); + instances.sort_by_cached_key(|instance| identity_order(&instance.source)); instances } @@ -1279,8 +1279,12 @@ impl fmt::Display for GuestTargetError { impl std::error::Error for GuestTargetError {} /// Stable ordering for resource identities inside a target. -fn identity_order(key: &ResourceKey) -> (&str, &str, &str) { - (&key.zone, &key.type_name, &key.name) +/// +/// The key is owned rather than a tuple of borrows because the ordering is +/// applied through `sort_by_cached_key`, which caches one key per element and +/// so cannot take a key borrowed from the element it is called on. +fn identity_order(key: &ResourceKey) -> (String, String, String) { + (key.zone.clone(), key.type_name.clone(), key.name.clone()) } #[cfg(test)] diff --git a/packages/d2b-resource-runtime/src/target.rs b/packages/d2b-resource-runtime/src/target.rs index 2d704b6a0..f2864acbb 100644 --- a/packages/d2b-resource-runtime/src/target.rs +++ b/packages/d2b-resource-runtime/src/target.rs @@ -734,7 +734,7 @@ impl TargetDirectory { .get(guest) .map(|record| record.assignments.keys().cloned().collect()) .unwrap_or_default(); - assigned.sort_by(|left, right| identity_order(left).cmp(&identity_order(right))); + assigned.sort_by_cached_key(identity_order); assigned } @@ -1046,8 +1046,12 @@ impl TargetDirectory { } /// Stable ordering for resource identities inside the directory. -fn identity_order(key: &ResourceKey) -> (&str, &str, &str) { - (&key.zone, &key.type_name, &key.name) +/// +/// The key is owned rather than a tuple of borrows because the ordering is +/// applied through `sort_by_cached_key`, which caches one key per element and +/// so cannot take a key borrowed from the element it is called on. +fn identity_order(key: &ResourceKey) -> (String, String, String) { + (key.zone.clone(), key.type_name.clone(), key.name.clone()) } #[cfg(test)] From d738367eb979c0e1d99f31e718fd74f15e60a311 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:50:23 -0700 Subject: [PATCH 658/726] provider(credential): sanction the recording-double lock sites The shared recording test doubles and the driver/session test fakes hold parking_lot Mutex guards on synchronous accessors and short recorder pushes, and only the #[tokio::test] functions carried a sanctioned allow. Put every locking method under the per-site #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] the banned-API allow policy recognises, so the recorders match the security-key recorder precedent. No lock type, accessor signature, or crate dependency changes. --- .../w7-08-parking-lot-sanctioned-sites.md | 10 ++++++++++ .../d2b-provider-credential/src/driver.rs | 7 +++++++ .../d2b-provider-credential/src/session.rs | 1 + .../src/test_support.rs | 19 +++++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 changelog.d/w7-08-parking-lot-sanctioned-sites.md diff --git a/changelog.d/w7-08-parking-lot-sanctioned-sites.md b/changelog.d/w7-08-parking-lot-sanctioned-sites.md new file mode 100644 index 000000000..38a50731f --- /dev/null +++ b/changelog.d/w7-08-parking-lot-sanctioned-sites.md @@ -0,0 +1,10 @@ +### Changed + +- Credential, Device-GPU, and Device-USBIP provider crate lock + acquisitions are now covered by per-site lint allows whose recorded + reasons name the two genuine classes: the Device-GPU authority-lease + cache is a synchronous provider port, and the recording test doubles + are test-only helpers. The locks, the shared recording-double types + the daemon builds its facet sets from, and every crate dependency are + unchanged; the recorded reasons are what the banned-API allow policy + validates. diff --git a/packages/d2b-provider-credential/src/driver.rs b/packages/d2b-provider-credential/src/driver.rs index 1341dfaa9..8c14c1649 100644 --- a/packages/d2b-provider-credential/src/driver.rs +++ b/packages/d2b-provider-credential/src/driver.rs @@ -1097,16 +1097,19 @@ mod tests { }) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn with_child(log: Log, child: StoredDesiredResource) -> Arc { let manager = Self::new(log); manager.children.lock().push(child); manager } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn ensured(&self) -> Vec { self.ensured.lock().clone() } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn children(&self) -> Vec { self.children.lock().clone() } @@ -1114,6 +1117,7 @@ mod tests { #[async_trait::async_trait] impl ManagerEndpoint for RecordingManager { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn ensure_child( &self, parent: &ResourceKey, @@ -1151,6 +1155,7 @@ mod tests { } } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn get( &self, key: &ResourceKey, @@ -1175,6 +1180,7 @@ mod tests { Ok(None) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { self.log .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held @@ -1187,6 +1193,7 @@ mod tests { Ok(()) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn list_owned( &self, _owner_uid: [u8; 16], diff --git a/packages/d2b-provider-credential/src/session.rs b/packages/d2b-provider-credential/src/session.rs index 323c0b9e0..d4c40e691 100644 --- a/packages/d2b-provider-credential/src/session.rs +++ b/packages/d2b-provider-credential/src/session.rs @@ -452,6 +452,7 @@ mod tests { Some(ReconnectGeneration::new(7).expect("recording session generation")) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn revoke_credential( &self, request: &CredentialRevocationRequest, diff --git a/packages/d2b-provider-credential/src/test_support.rs b/packages/d2b-provider-credential/src/test_support.rs index b79e8da95..f201432a3 100644 --- a/packages/d2b-provider-credential/src/test_support.rs +++ b/packages/d2b-provider-credential/src/test_support.rs @@ -62,26 +62,31 @@ impl FakeEffects { /// The calls recorded so far, in order (the shared log also carries the /// manager endpoint's `ensure`/`get`/`delete`/`list-owned` entries). + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn call_order(&self) -> Vec { self.log.lock().clone() } /// Script the Provider + execution-target facts. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_facts(&self, value: Option) { *self.facts.lock() = value; } /// Script the provider-side lease facts. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_lease(&self, value: Option) { *self.lease.lock() = value; } /// Script whether the managed-identity agent Process is live. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_agent_ready(&self, value: bool) { *self.agent_ready.lock() = value; } /// Script the session the delete path binds for the revocation call. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_session(&self, value: Option>) { *self.session.lock() = value; } @@ -89,6 +94,7 @@ impl FakeEffects { #[async_trait::async_trait] impl CredentialDriverEffects for FakeEffects { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn dependency_facts( &self, _provider_ref: &ResourceRef, @@ -98,16 +104,19 @@ impl CredentialDriverEffects for FakeEffects { Ok(self.facts.lock().clone()) // async-gate-allow: test-support recorder lock } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn lease_facts(&self, _credential_ref: &ResourceRef) -> Option { self.log.lock().push("lease-facts".to_owned()); // async-gate-allow: test-support recorder lock *self.lease.lock() // async-gate-allow: test-support recorder lock } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn agent_ready(&self, _agent_ref: &ResourceRef) -> bool { self.log.lock().push("agent-ready".to_owned()); // async-gate-allow: test-support recorder lock *self.agent_ready.lock() // async-gate-allow: test-support recorder lock } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn session(&self, _provider_ref: &ResourceRef) -> Option> { self.log.lock().push("session".to_owned()); self.session.lock().clone() @@ -149,6 +158,7 @@ impl CredentialSession for RecordingSession { self.generation } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn revoke_credential( &self, request: &CredentialRevocationRequest, @@ -197,26 +207,31 @@ impl RecordingRuntime { } /// The calls recorded so far, in order. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn call_order(&self) -> Vec { self.log.lock().clone() } /// Script the Provider + execution-target facts. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_facts(&self, value: Option) { *self.facts.lock() = value; } /// Script the provider-side lease facts. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_lease(&self, value: Option) { *self.lease.lock() = value; } /// Script whether the managed-identity agent Process is live. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_agent_ready(&self, value: bool) { *self.agent_ready.lock() = value; } /// Script the session the delete path binds for the revocation call. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn set_session(&self, value: Option>) { *self.session.lock() = value; } @@ -224,6 +239,7 @@ impl RecordingRuntime { #[async_trait] impl CredentialRuntime for RecordingRuntime { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn dependency_facts( &self, _provider_ref: &ResourceRef, @@ -233,16 +249,19 @@ impl CredentialRuntime for RecordingRuntime { Ok(self.facts.lock().clone()) // async-gate-allow: test-support recorder lock } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn lease_facts(&self, _credential_ref: &ResourceRef) -> Option { self.log.lock().push("lease-facts".to_owned()); // async-gate-allow: test-support recorder lock *self.lease.lock() // async-gate-allow: test-support recorder lock } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn agent_ready(&self, _agent_ref: &ResourceRef) -> bool { self.log.lock().push("agent-ready".to_owned()); // async-gate-allow: test-support recorder lock *self.agent_ready.lock() // async-gate-allow: test-support recorder lock } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn session(&self, _provider_ref: &ResourceRef) -> Option> { self.log.lock().push("session".to_owned()); self.session.lock().clone() From e38e867233e7350938b95c579188d82ab502bcc1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:50:27 -0700 Subject: [PATCH 659/726] provider(device): sanction the GPU and USBIP lock sites The GPU authority-lease cache is locked from the genuinely synchronous GpuLifecycleEffectPort methods, so reserve_authority and release_authority take the same #[allow(clippy::disallowed_methods, reason = "synchronous path")] the file already carries on drive_sync. The USBIP recording doubles take the test-helper reason on each locking method. Both ports keep the parking_lot Mutex type the Device family construction contract declares, so no Arc or dependency moves. --- packages/d2b-provider-device-gpu/src/effects_service.rs | 2 ++ packages/d2b-provider-device-usbip/src/test_support.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/packages/d2b-provider-device-gpu/src/effects_service.rs b/packages/d2b-provider-device-gpu/src/effects_service.rs index ada46111d..6206ff81c 100644 --- a/packages/d2b-provider-device-gpu/src/effects_service.rs +++ b/packages/d2b-provider-device-gpu/src/effects_service.rs @@ -281,6 +281,7 @@ impl<'a> DeclaredWorkerGpuPort<'a> { } impl GpuLifecycleEffectPort for DeclaredWorkerGpuPort<'_> { + #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn reserve_authority( &mut self, admission: &crate::authority::GpuAuthorityAdmission, @@ -434,6 +435,7 @@ impl GpuLifecycleEffectPort for DeclaredWorkerGpuPort<'_> { )) } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn release_authority( &mut self, lease: crate::authority::GpuAuthorityLease, diff --git a/packages/d2b-provider-device-usbip/src/test_support.rs b/packages/d2b-provider-device-usbip/src/test_support.rs index 0e00ef176..ca87984f4 100644 --- a/packages/d2b-provider-device-usbip/src/test_support.rs +++ b/packages/d2b-provider-device-usbip/src/test_support.rs @@ -31,6 +31,7 @@ pub struct RecordingEffects { impl RecordingEffects { /// Snapshot of the effect-method invocation order. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn call_order(&self) -> Vec<&'static str> { self.calls.lock().clone() } @@ -38,6 +39,7 @@ impl RecordingEffects { #[async_trait] impl UsbipDriverEffects for RecordingEffects { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn reconcile_usbip( &self, component: UsbipComponent, @@ -50,6 +52,7 @@ impl UsbipDriverEffects for RecordingEffects { )) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn finalize( &self, component: UsbipComponent, @@ -74,6 +77,7 @@ pub struct RecordingRuntime { #[async_trait] impl UsbipRuntime for RecordingRuntime { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn reconcile_usbip( &self, component: UsbipComponent, @@ -85,6 +89,7 @@ impl UsbipRuntime for RecordingRuntime { )) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn finalize( &self, component: UsbipComponent, From 7e194b77c14daa69815188c3c878006060bf124b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:51:40 -0700 Subject: [PATCH 660/726] xtask: refresh the async-gate inventory for the shifted marker lines The new per-method attributes push every // async-gate-allow: marker in the credential and USBIP recording sources down, and the hatch inventory keys sites by (file, line), so regenerate it through the gate's own --write-inventory mode. The site count is unchanged at 254; only the shifted lines move and every reason is preserved. --- packages/xtask/data/async-gate-inventory.json | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index f823664ce..099caba59 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -183,77 +183,77 @@ }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1122, + "line": 1126, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1135, + "line": 1139, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1136, + "line": 1140, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1159, + "line": 1164, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1163, + "line": 1168, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1180, + "line": 1186, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1182, + "line": 1188, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1650, + "line": 1657, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1661, + "line": 1668, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1664, + "line": 1671, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1688, + "line": 1695, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1737, + "line": 1744, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1821, + "line": 1828, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1877, + "line": 1884, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/driver.rs", - "line": 1935, + "line": 1942, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -263,72 +263,72 @@ }, { "file": "packages/d2b-provider-credential/src/session.rs", - "line": 461, + "line": 462, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 97, + "line": 103, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 98, + "line": 104, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 102, + "line": 109, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 103, + "line": 110, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 107, + "line": 115, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 108, + "line": 116, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 159, + "line": 169, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 232, + "line": 248, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 233, + "line": 249, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 237, + "line": 254, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 238, + "line": 255, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 242, + "line": 260, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-credential/src/test_support.rs", - "line": 243, + "line": 261, "reason": "test-support recorder lock" }, { @@ -423,32 +423,32 @@ }, { "file": "packages/d2b-provider-device-usbip/src/test_support.rs", - "line": 46, + "line": 48, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-usbip/src/test_support.rs", - "line": 47, + "line": 49, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-usbip/src/test_support.rs", - "line": 58, + "line": 61, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-usbip/src/test_support.rs", - "line": 59, + "line": 62, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-usbip/src/test_support.rs", - "line": 82, + "line": 86, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-device-usbip/src/test_support.rs", - "line": 93, + "line": 98, "reason": "test-support recorder lock" }, { From 58ac8df53e54172786ecedabb045f51351363986 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:52:28 -0700 Subject: [PATCH 661/726] refactor(notification-desktop): re-export admission types without a shim The private stream_admission module was a three-line re-export of the admission module's public items. Re-export them from the crate root straight from admission and delete the shim; the crate-root type paths are unchanged, so no consumer edit is needed. The provider dossier's layout tree and work-item rows now cite the module the tree actually has. --- .../providers/ADR-046-provider-notification-desktop.md | 10 +++++----- packages/d2b-provider-notification-desktop/src/lib.rs | 3 +-- .../src/stream_admission.rs | 3 --- 3 files changed, 6 insertions(+), 10 deletions(-) delete mode 100644 packages/d2b-provider-notification-desktop/src/stream_admission.rs diff --git a/docs/specs/providers/ADR-046-provider-notification-desktop.md b/docs/specs/providers/ADR-046-provider-notification-desktop.md index 7907c044f..70b6f5e91 100644 --- a/docs/specs/providers/ADR-046-provider-notification-desktop.md +++ b/docs/specs/providers/ADR-046-provider-notification-desktop.md @@ -73,7 +73,7 @@ packages/d2b-provider-notification-desktop/ host_sink.rs # host-side sink process - consumes stream, calls D-Bus, # manages observer projection action_nonce.rs # bounded single-use action capability store - stream_admission.rs # ComponentSession admission checks + admission.rs # ComponentSession admission checks redact.rs # sanitize() - strip/cap notification text before use error.rs # typed stable error enum; no content in messages tests/ @@ -668,9 +668,9 @@ NN is allowed for the observer because: KK is required for the Guest→Host sink because the guest-source crosses a Zone boundary (Host Zone ← Guest Zone vsock transport). -### 6.5 Admission checks - stream_admission.rs +### 6.5 Admission checks - admission.rs -`stream_admission.rs` checks on every session establishment: +`admission.rs` checks on every session establishment: 1. Session is established and authenticated (`is_established() && is_authenticated()`). 2. Service package exactly equals `d2b.notification.v3`. @@ -1350,7 +1350,7 @@ are candidates for copy/adapt: | `packages/d2b-notify/src/nonce.rs` - `ActionNonce`, `ActionNonceStore`, `NONCE_BYTES`, `NONCE_TTL_SECS`, `MAX_STORE_SIZE`, `notification_action_key`, `parse_notification_action_key` | copy/adapt | `packages/d2b-provider-notification-desktop/src/action_nonce.rs` | | `packages/d2b-notify/src/events.rs` - event enum, field bounds, `SecurityKeyEvent` | extract/adapt; generalize from security-key to generic category | `packages/d2b-provider-notification-desktop/src/types.rs` | | `packages/d2b-notify/src/state.rs` - `CeremonySummary`, `SkNotifyState`, bound constants | adapt; generalize | `packages/d2b-provider-notification-desktop/src/types.rs` | -| `packages/d2b-notify/src/services/mod.rs` - `EstablishedDesktopSession`, `DesktopServices`, session evidence mapping, `DesktopStartupError` | copy/adapt | `packages/d2b-provider-notification-desktop/src/stream_admission.rs` | +| `packages/d2b-notify/src/services/mod.rs` - `EstablishedDesktopSession`, `DesktopServices`, session evidence mapping, `DesktopStartupError` | copy/adapt | `packages/d2b-provider-notification-desktop/src/admission.rs` | | `packages/d2b-notify/src/services/actions.rs` - `ActionService`, `ActionSession`, `ActionOffer`, `InvokeActionRequest` | copy/adapt | `packages/d2b-provider-notification-desktop/src/action_nonce.rs` (client side) | | `packages/d2b-notify/src/services/observer.rs` - `ObserverService`, `ObserverSession`, projection logic | adapt | `packages/d2b-provider-notification-desktop/src/host_sink.rs` (observer projection) | | `packages/d2b-contracts/src/generated_v2_services/notify_ttrpc.rs` - `NotifyServiceClient`, `NotifyService` ttrpc shape | replace with v3 protobuf/ttrpc regenerated under `d2b.notification.v3` | `packages/d2b-provider-notification-desktop/src/` (generated) | @@ -1387,7 +1387,7 @@ The v2 `d2b.notify.v2.NotifyService` ttrpc contract is superseded by | Dependency/owner | ADR046-session-001, ADR046-bus-001; session/bus wiring | | Current source | `packages/d2b-notify/src/services/` | | Reuse action | adapt | -| Destination | `packages/d2b-provider-notification-desktop/src/stream_admission.rs` | +| Destination | `packages/d2b-provider-notification-desktop/src/admission.rs` | | Detailed design | Session admission checks, Noise profile enforcement, transport class validation Primary reuse disposition: `adapt`. Preserved source-plan detail: copy/adapt. | | Integration | ComponentSession/d2b-bus | | Data migration | None - full d2b 3.0 reset; no prior state to migrate | diff --git a/packages/d2b-provider-notification-desktop/src/lib.rs b/packages/d2b-provider-notification-desktop/src/lib.rs index 7495dd157..b119269be 100644 --- a/packages/d2b-provider-notification-desktop/src/lib.rs +++ b/packages/d2b-provider-notification-desktop/src/lib.rs @@ -26,10 +26,10 @@ mod metrics; mod rbac; mod redact; mod runtime; -mod stream_admission; mod types; pub use action_nonce::{ActionNonce, ActionNonceError, ActionNonceStore}; +pub use admission::{AdmissionError, AdmissionPurpose, SessionEvidence, TransportClass}; pub use audit::{NotificationAuditKind, NotificationAuditRecord}; pub use controller::{ DisplayDependencyEvidence, DisplayDependencyState, GuestSourceConfig, NotificationController, @@ -56,7 +56,6 @@ pub use runtime::{ NotificationFinalizationReport, NotificationProcessEffectPort, NotificationRuntime, NotificationRuntimeError, }; -pub use stream_admission::{AdmissionError, AdmissionPurpose, SessionEvidence, TransportClass}; pub use types::{ ActionSpec, Category, MAX_ACTIONS, MAX_BODY_CHARS, MAX_SUMMARY_CHARS, NotificationError, NotificationRequest, NotificationUrgency, diff --git a/packages/d2b-provider-notification-desktop/src/stream_admission.rs b/packages/d2b-provider-notification-desktop/src/stream_admission.rs deleted file mode 100644 index 07892a1bb..000000000 --- a/packages/d2b-provider-notification-desktop/src/stream_admission.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! Canonical source path for the notification ComponentSession admission. - -pub use crate::admission::{AdmissionError, AdmissionPurpose, SessionEvidence, TransportClass}; From bcdb699ea13e7440a26f7e19ed9e86b2f14cec45 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:52:29 -0700 Subject: [PATCH 662/726] fix(clipd): stop deriving Deserialize for the audit event AuditEvent serializes mime_type through the bounded-MIME adapter, which truncates an over-long value, while the derived Deserialize would have accepted an unbounded one: the round trip was asymmetric. Nothing reads an AuditEvent back, so the record keeps only Serialize. --- packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs index 61a78af32..439bd49f4 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs @@ -9,7 +9,7 @@ use crate::clipd_host::policy::{AttributionQuality, ReasonCode}; // audit line. const MAX_AUDIT_MIME_BYTES: usize = 64; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct AuditEvent { pub request_id: String, pub source_realm: String, From e1ab1525f0c7296d292a808f72c4802ed65280e6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:52:29 -0700 Subject: [PATCH 663/726] refactor(clipd): emit clipd host events as tracing fields The host selection change, niri probe failure, desktop notification failure, picker terminate and kill failures, and data-control connect events interpolated their values into the message, which left them unqueryable by field. Emit them through tracing with named fields; the messages are unchanged apart from the values that moved into fields. --- .../w7-05-notification-shim-and-clipd-logs.md | 19 +++++++++++++++++++ .../src/clipd_host/host.rs | 10 +++++----- .../src/clipd_host/niri.rs | 5 ++++- .../src/clipd_host/notifications.rs | 2 +- .../src/clipd_host/picker.rs | 8 ++++++-- .../src/clipd_host/wayland.rs | 6 +++--- 6 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 changelog.d/w7-05-notification-shim-and-clipd-logs.md diff --git a/changelog.d/w7-05-notification-shim-and-clipd-logs.md b/changelog.d/w7-05-notification-shim-and-clipd-logs.md new file mode 100644 index 000000000..662ef4a73 --- /dev/null +++ b/changelog.d/w7-05-notification-shim-and-clipd-logs.md @@ -0,0 +1,19 @@ +### Changed + +- `d2b-provider-notification-desktop` re-exports its session admission + types (`AdmissionError`, `AdmissionPurpose`, `SessionEvidence`, + `TransportClass`) straight from the `admission` module. The private + three-line re-export shim is gone; the public type paths are + unchanged, so no consumer changes. +- The clipd host-selection, niri probe failure, desktop notification + failure, picker terminate/kill failure, and data-control connect + events now emit through `tracing` with named fields (`quality`, + `mimes`, `secret`, `pid`, `protocol`, `error`) instead of + interpolated messages. + +### Fixed + +- `clipd_host::audit::AuditEvent` no longer derives `Deserialize`. Its + `mime_type` field serializes through the bounded-MIME adapter with no + matching deserializer, so a read-back would have accepted unbounded + values the writer never emits. The record is write-only. diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs index cf4807fed..00f696f67 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs @@ -63,11 +63,11 @@ impl HostClipboard

{ has_secret: bool, ) { let attribution = self.attributor.on_host_selection_changed(); - log::debug!( - "d2b-clipd: host selection changed, attribution={:?}, mimes={}, secret={}", - attribution.quality, - allowed_mimes.len(), - has_secret + tracing::debug!( + quality = ?attribution.quality, + mimes = allowed_mimes.len(), + secret = has_secret, + "d2b-clipd: host selection changed" ); // Replace any old offer (drops it, sending destroy). self.current_selection = Some(HostSelection { diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs index 14272c51d..dc4891cc7 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs @@ -509,7 +509,10 @@ impl HostClipboardAttributor

{ quality: AttributionQuality::FocusedWindowGuess, }, Err(e) => { - log::debug!("d2b-clipd: niri focused-window probe failed; falling back to stale cache for attribution: {e:?}"); + tracing::debug!( + error = ?e, + "d2b-clipd: niri focused-window probe failed; falling back to stale cache for attribution" + ); self.cache.mark_stale(); HostSelectionAttribution { window: self.cache.focused_window(), diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs index aa09d9c07..929316485 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs @@ -21,7 +21,7 @@ impl Notifier for DesktopNotifier { .body(¬ification.body) .show() { - log::warn!("d2b-clipd: desktop notification failed: {error}"); + tracing::warn!(error = %error, "d2b-clipd: desktop notification failed"); } } } diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs index 94c9d4d21..638f4f9dd 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs @@ -57,13 +57,17 @@ impl PickerProcess for Child { if let Some(pid) = rustix::process::Pid::from_raw(self.id() as i32) && let Err(e) = rustix::process::kill_process(pid, rustix::process::Signal::Term) { - log::debug!("d2b-clipd: picker terminate signal failed for pid {}; relying on kill/reap path: {e}", self.id()); + tracing::debug!( + pid = self.id(), + error = %e, + "d2b-clipd: picker terminate signal failed; relying on kill/reap path" + ); } } fn kill(&mut self) { if let Err(e) = Child::kill(self) { - log::debug!("d2b-clipd: picker kill failed; child may already be gone: {e}"); + tracing::debug!(error = %e, "d2b-clipd: picker kill failed; child may already be gone"); } } diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs index cf469c1ca..81cea1165 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs @@ -551,9 +551,9 @@ impl DataControlClient { .roundtrip(&mut state) .map_err(|e| DataControlError::Protocol(e.to_string()))?; - log::info!( - "d2b-clipd: data-control connected via {}", - state.manager_state.protocol_name() + tracing::info!( + protocol = %state.manager_state.protocol_name(), + "d2b-clipd: data-control connected" ); Ok(Self { From 5d378716b6cb9e647398ff7f2106ae4a6cad4472 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:55:39 -0700 Subject: [PATCH 664/726] provider-cloud-hypervisor: type the root machine type as a closed enum `CloudHypervisorConfig::default_machine_type` reused the credential vocabulary type `OpaqueAzureRef`, so the root config accepted any opaque identifier for a field whose only valid values are `q35` and `microvm`, and `validate()` had to re-check the closed set after decoding. Introduce `MachineType` with the kebab-case wire spelling the config already advertised (`Q35` pinned to `q35`, `Microvm` to `microvm`), replace the field type, and delete the validation arm the enum makes unrepresentable. The config fixture and the two d2bd controller test constructors move to the enum. --- .../src/config.rs | 55 ++++++++++++++++++- .../src/lib.rs | 2 +- .../tests/common/mod.rs | 5 +- packages/d2bd/tests/cloud_composition.rs | 10 ++-- .../d2bd/tests/zone_provider_acceptance.rs | 6 +- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/config.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/config.rs index e2ad6239d..f032c2912 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/config.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/config.rs @@ -2,10 +2,20 @@ use std::fmt; -use d2b_contracts_provider::v3::credential::OpaqueAzureRef; use d2b_contracts_resource::v3::ResourceRef; use serde::{Deserialize, Serialize}; +/// Machine type a Cloud Hypervisor VMM starts with. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum MachineType { + /// Modern Q35 chipset. + #[serde(rename = "q35")] + Q35, + /// Minimal MicroVM chipset. + Microvm, +} + /// Provider root configuration. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -17,7 +27,7 @@ pub struct CloudHypervisorConfig { /// Default memory in MiB. pub default_memory_mb: u32, /// Default machine type. - pub default_machine_type: OpaqueAzureRef, + pub default_machine_type: MachineType, /// Whether the VMM watchdog is enabled. pub watchdog: bool, /// Maximum adoption window in milliseconds. @@ -50,7 +60,6 @@ impl CloudHypervisorConfig { if self.controller_execution_ref.resource_type().as_str() != "Host" || !(1..=1024).contains(&self.default_vcpus) || !(128..=524_288).contains(&self.default_memory_mb) - || !matches!(self.default_machine_type.as_str(), "q35" | "microvm") || !(1..=900_000).contains(&self.adoption_window_ms) || !(5_000..=300_000).contains(&self.health_check_interval_ms) || !(1_000..=60_000).contains(&self.health_check_timeout_ms) @@ -83,3 +92,43 @@ impl fmt::Debug for CloudHypervisorConfig { .finish() } } + +#[cfg(test)] +mod tests { + use super::*; + + const ROOT_CONFIG: &str = r#"{ + "controllerExecutionRef": "Host/host-system", + "defaultVcpus": 2, + "defaultMemoryMb": 512, + "defaultMachineType": "q35", + "watchdog": true, + "adoptionWindowMs": 30000, + "healthCheckIntervalMs": 30000, + "healthCheckTimeoutMs": 5000, + "healthCheckFailureThreshold": 3, + "startupDeadlineMs": 120000 + }"#; + + #[test] + fn machine_type_is_the_closed_q35_microvm_wire() { + let config: CloudHypervisorConfig = + serde_json::from_str(ROOT_CONFIG).expect("q35 root config decodes"); + assert_eq!(config.default_machine_type, MachineType::Q35); + assert!(config.validate().is_ok()); + + let microvm: CloudHypervisorConfig = + serde_json::from_str(&ROOT_CONFIG.replace(r#""q35""#, r#""microvm""#)) + .expect("microvm root config decodes"); + assert_eq!(microvm.default_machine_type, MachineType::Microvm); + assert!(microvm.validate().is_ok()); + + let unknown = ROOT_CONFIG.replace(r#""q35""#, r#""guest-vm""#); + assert!(serde_json::from_str::(&unknown).is_err()); + + let q35 = serde_json::to_string(&MachineType::Q35).expect("q35 wire"); + let microvm_wire = serde_json::to_string(&MachineType::Microvm).expect("microvm wire"); + assert_eq!(q35, r#""q35""#); + assert_eq!(microvm_wire, r#""microvm""#); + } +} diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs index 4cdcd80ac..aebd685b5 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/lib.rs @@ -24,7 +24,7 @@ pub use bootstrap_graph::{ BootstrapGraph, BootstrapGraphError, DependencyReadiness, GuestChildGraphPlan, VmmLifecycleEligibility, }; -pub use config::{CloudHypervisorConfig, ConfigValidationError}; +pub use config::{CloudHypervisorConfig, ConfigValidationError, MachineType}; pub use controller::{CLOUD_HYPERVISOR_REPAIR_INTERVAL_SECS, GUEST_CONTROLLER_FINALIZER}; pub use controller::{ AuthenticatedResourceApiAdapter, AuthenticatedResourceSession, ChildSpecUpdate, diff --git a/packages/d2b-provider-guest-cloud-hypervisor/tests/common/mod.rs b/packages/d2b-provider-guest-cloud-hypervisor/tests/common/mod.rs index bdfc98795..f0fea3d11 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/tests/common/mod.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/tests/common/mod.rs @@ -3,13 +3,12 @@ //! Harness shared by the Cloud Hypervisor controller test binaries. use d2b_contracts_provider::v3::ArtifactDigest; -use d2b_contracts_provider::v3::credential::OpaqueAzureRef; use d2b_contracts_resource::v3::{ ArtifactId, ResourceGeneration, ResourceRef, SchemaFingerprint, SchemaVersion, }; use d2b_provider_guest_cloud_hypervisor::{ BootstrapHandoff, CloudHypervisorConfig, DescriptorSignature, GuestSeedContract, - GuestSetupDescriptor, GuestSetupDescriptorVerifier, SignatureAlgorithm, + GuestSetupDescriptor, GuestSetupDescriptorVerifier, MachineType, SignatureAlgorithm, VerifiedGuestSetupDescriptor, }; @@ -67,7 +66,7 @@ pub fn config() -> CloudHypervisorConfig { controller_execution_ref: ResourceRef::parse("Host/host-system").unwrap(), default_vcpus: 2, default_memory_mb: 512, - default_machine_type: OpaqueAzureRef::parse("q35").unwrap(), + default_machine_type: MachineType::Q35, watchdog: true, adoption_window_ms: 30_000, health_check_interval_ms: 30_000, diff --git a/packages/d2bd/tests/cloud_composition.rs b/packages/d2bd/tests/cloud_composition.rs index 149899813..64c5a099c 100644 --- a/packages/d2bd/tests/cloud_composition.rs +++ b/packages/d2bd/tests/cloud_composition.rs @@ -4,10 +4,7 @@ use std::{ }; use async_trait::async_trait; -use d2b_contracts_provider::v3::{ - ArtifactDigest, - credential::{CredentialLeaseHandle, OpaqueAzureRef}, -}; +use d2b_contracts_provider::v3::{ArtifactDigest, credential::CredentialLeaseHandle}; use d2b_contracts_resource::v3::{ ArtifactId, DesiredLifecycle, ResourceGeneration, ResourcePhase, ResourceRef, ResourceUid, SchemaFingerprint, SchemaVersion, ZoneId, ZoneRevision, @@ -30,7 +27,8 @@ use d2b_provider_guest_cloud_hypervisor::{ CloudHypervisorResourceRequest, CloudHypervisorResourceResponse, CommittedChild, DescriptorSignature, GuestChildCommitResponse, GuestGenerationSet, GuestSeedContract, GuestSessionEvidence, GuestSetupDescriptor, GuestSetupDescriptorVerifier, GuestSnapshot, - GuestStatusPhase, OwnedChildSnapshot, SignatureAlgorithm, health::GuestSessionEvidenceBinding, + GuestStatusPhase, MachineType, OwnedChildSnapshot, SignatureAlgorithm, + health::GuestSessionEvidenceBinding, }; #[derive(Default)] @@ -438,7 +436,7 @@ fn cloud_controller( controller_execution_ref: ResourceRef::parse("Host/host-system").unwrap(), default_vcpus: 2, default_memory_mb: 512, - default_machine_type: OpaqueAzureRef::parse("q35").unwrap(), + default_machine_type: MachineType::Q35, watchdog: true, adoption_window_ms: 30_000, health_check_interval_ms: 30_000, diff --git a/packages/d2bd/tests/zone_provider_acceptance.rs b/packages/d2bd/tests/zone_provider_acceptance.rs index d127fbd0b..6cb498712 100644 --- a/packages/d2bd/tests/zone_provider_acceptance.rs +++ b/packages/d2bd/tests/zone_provider_acceptance.rs @@ -52,7 +52,8 @@ use d2b_provider_guest_cloud_hypervisor::{ CloudHypervisorResourceRequest, CloudHypervisorResourceResponse, CommittedChild, DescriptorSignature, GuestChildCommitResponse, GuestGenerationSet, GuestSeedContract, GuestSessionEvidence, GuestSetupDescriptor, GuestSetupDescriptorVerifier, GuestSnapshot, - GuestStatusPhase, OwnedChildSnapshot, SignatureAlgorithm, health::GuestSessionEvidenceBinding, + GuestStatusPhase, MachineType, OwnedChildSnapshot, SignatureAlgorithm, + health::GuestSessionEvidenceBinding, }; use d2b_provider_volume_local::{ DriftClass, MarkerState, OwnerProof, QuotaCapability, VolumeLayoutEffectPort, @@ -1352,8 +1353,7 @@ fn cloud_controller(session: Arc) -> CloudCo controller_execution_ref: ResourceRef::parse("Host/host-system").unwrap(), default_vcpus: 2, default_memory_mb: 512, - default_machine_type: d2b_contracts_provider::v3::credential::OpaqueAzureRef::parse("q35") - .unwrap(), + default_machine_type: MachineType::Q35, watchdog: true, adoption_window_ms: 30_000, health_check_interval_ms: 30_000, From 2ca9a22dd6959c258cbd4fa0085f4d25fea230c6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:55:40 -0700 Subject: [PATCH 665/726] provider-cloud-hypervisor: publish the closed machine type in the root schema The committed root config schema still described `defaultMachineType` through the `OpaqueAzureRef` reference, so it advertised a charset pattern instead of the closed value set the config now enforces. Replace the reference with the `q35` | `microvm` enum and drop the definition nothing references any more. The packaging expression derives the catalog `configDigest` from the schema file bytes and the committed provider manifest embeds that same digest, so bump both embedded copies in the manifest to the digest the new schema bytes hash to. The committed manifest signature is not renewed: the publisher private key is not in the repository and no build step verifies the signature against the manifest bytes. --- changelog.d/w7-04-cloud-hypervisor-machine-type.md | 9 +++++++++ .../provider-manifest.json | 2 +- .../root-config.schema.json | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 changelog.d/w7-04-cloud-hypervisor-machine-type.md diff --git a/changelog.d/w7-04-cloud-hypervisor-machine-type.md b/changelog.d/w7-04-cloud-hypervisor-machine-type.md new file mode 100644 index 000000000..dc187a51a --- /dev/null +++ b/changelog.d/w7-04-cloud-hypervisor-machine-type.md @@ -0,0 +1,9 @@ +### Changed + +- `runtime-cloud-hypervisor` Provider root configuration types + `defaultMachineType` as a closed `q35` | `microvm` value instead of a + free-form opaque identifier string. A root configuration naming any + other machine type is refused when the config is decoded, and the + artifact's published `config-schema.json` advertises the same closed + value set, so a bad machine type fails at parse time rather than as an + opaque `cloud-hypervisor-config-invalid` after installation. diff --git a/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json b/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json index cc2b6fffe..378c1546f 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json +++ b/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json @@ -1 +1 @@ -{"apiBindings":[{"baseSpecFingerprint":"sha256:0000000000000000000000000000000000000000000000000000000000000001","baseSpecVersion":"1.0","baseStatusFingerprint":"sha256:0000000000000000000000000000000000000000000000000000000000000002","baseStatusVersion":"1.0","capabilityMatrix":{},"placementAnchor":"execution-ref","resourceType":"Guest"}],"artifactId":"runtime-cloud-hypervisor","compatibility":{"apiMajor":3,"apiMinor":0,"descriptorFingerprint":"sha256:0000000000000000000000000000000000000000000000000000000000000003","stateSchemaVersion":"1.0"},"components":[{"allowedDomains":["system"],"binaryRef":"d2b-cloud-hypervisor-controller","cardinality":1,"componentId":"cloud-hypervisor-controller","componentType":"controller","configDigest":"sha256:e4a434b81458b42579a26db11be50b97ec3fbb0f42ef0e378698a0a8152cbe7a","declaresStateVolume":false,"dependencies":[],"exportedMethods":["assess-update"],"exportedResourceTypes":["Guest"],"instanceScope":"fixed-execution-target","stateNamespaces":[],"supportedTargetKinds":["host"],"targetCapabilities":[{"artifactDigest":"sha256:d07fd0ec297c888d15a4e15890d3bbf1987ffe4db6e8ebe1753deaa2d8672587","requiredEffectClasses":["process"],"targetKind":"host"}]}],"digests":{"config":"sha256:e4a434b81458b42579a26db11be50b97ec3fbb0f42ef0e378698a0a8152cbe7a","executable":"sha256:d07fd0ec297c888d15a4e15890d3bbf1987ffe4db6e8ebe1753deaa2d8672587","schema":"sha256:d754bcfda30fc88cb80065333ab8290623555b7357eee2a8a9f624301b4b30a2","service":"sha256:f4cdf2f8c1a8b579b8423f2845123353bfc515d102932f77c69b957c0677ffbf"},"projectionFactories":[],"runtimeArtifacts":[{"brokerDigest":"sha256:faa2a9bdcc837728fffdebbca0ada344aca67ebe6aa54836d298377820590de2","d2bdDigest":"sha256:d0088a1511899dccc1b22d46ccacd4d52fc433d3aeb4592d0a7996c43604e84c","targetKind":"host"}],"trust":{"conformance":"accepted","emergencyDeny":false,"license":"accepted","provenance":"accepted","publisher":"d2b-cloud-hypervisor","publisherTrusted":true,"revocation":"clear","rootEpoch":1,"sbom":"accepted","signature":"valid","supportChannel":"stable","vulnerability":"accepted"},"upgradePolicy":{"drainBeforeUpgrade":true,"maxAutomaticDisposition":"in-place","preservesDurableState":true}} \ No newline at end of file +{"apiBindings":[{"baseSpecFingerprint":"sha256:0000000000000000000000000000000000000000000000000000000000000001","baseSpecVersion":"1.0","baseStatusFingerprint":"sha256:0000000000000000000000000000000000000000000000000000000000000002","baseStatusVersion":"1.0","capabilityMatrix":{},"placementAnchor":"execution-ref","resourceType":"Guest"}],"artifactId":"runtime-cloud-hypervisor","compatibility":{"apiMajor":3,"apiMinor":0,"descriptorFingerprint":"sha256:0000000000000000000000000000000000000000000000000000000000000003","stateSchemaVersion":"1.0"},"components":[{"allowedDomains":["system"],"binaryRef":"d2b-cloud-hypervisor-controller","cardinality":1,"componentId":"cloud-hypervisor-controller","componentType":"controller","configDigest":"sha256:1962ab36cc527cf99a924936b57e4daf77a5416805c245c99a2c64e121c2bf9c","declaresStateVolume":false,"dependencies":[],"exportedMethods":["assess-update"],"exportedResourceTypes":["Guest"],"instanceScope":"fixed-execution-target","stateNamespaces":[],"supportedTargetKinds":["host"],"targetCapabilities":[{"artifactDigest":"sha256:d07fd0ec297c888d15a4e15890d3bbf1987ffe4db6e8ebe1753deaa2d8672587","requiredEffectClasses":["process"],"targetKind":"host"}]}],"digests":{"config":"sha256:1962ab36cc527cf99a924936b57e4daf77a5416805c245c99a2c64e121c2bf9c","executable":"sha256:d07fd0ec297c888d15a4e15890d3bbf1987ffe4db6e8ebe1753deaa2d8672587","schema":"sha256:d754bcfda30fc88cb80065333ab8290623555b7357eee2a8a9f624301b4b30a2","service":"sha256:f4cdf2f8c1a8b579b8423f2845123353bfc515d102932f77c69b957c0677ffbf"},"projectionFactories":[],"runtimeArtifacts":[{"brokerDigest":"sha256:faa2a9bdcc837728fffdebbca0ada344aca67ebe6aa54836d298377820590de2","d2bdDigest":"sha256:d0088a1511899dccc1b22d46ccacd4d52fc433d3aeb4592d0a7996c43604e84c","targetKind":"host"}],"trust":{"conformance":"accepted","emergencyDeny":false,"license":"accepted","provenance":"accepted","publisher":"d2b-cloud-hypervisor","publisherTrusted":true,"revocation":"clear","rootEpoch":1,"sbom":"accepted","signature":"valid","supportChannel":"stable","vulnerability":"accepted"},"upgradePolicy":{"drainBeforeUpgrade":true,"maxAutomaticDisposition":"in-place","preservesDurableState":true}} \ No newline at end of file diff --git a/packages/d2b-provider-guest-cloud-hypervisor/root-config.schema.json b/packages/d2b-provider-guest-cloud-hypervisor/root-config.schema.json index 89b6e57ba..086ec8ab3 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/root-config.schema.json +++ b/packages/d2b-provider-guest-cloud-hypervisor/root-config.schema.json @@ -1 +1 @@ -{"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"definitions":{"OpaqueAzureRef":{"maxLength":128,"minLength":1,"pattern":"^[A-Za-z0-9._-]+$","type":"string"},"ResourceRef":{"oneOf":[{"maxLength":80,"minLength":6,"pattern":"^(Zone|ZoneLink|Provider|Role|RoleBinding|Quota|EmergencyPolicy|Host|Guest|Process|EphemeralProcess|Volume|Network|Device|User|Credential|Endpoint|ResourceExport|ResourceImport)/[a-z][a-z0-9-]{0,62}$","type":"string"},{"maxLength":201,"minLength":15,"pattern":"^[a-z][a-z0-9-]{0,62}\\.d2bus\\.org\\.[A-Z][A-Za-z0-9]{0,62}/[a-z][a-z0-9-]{0,62}$","type":"string"}]}},"description":"Provider root configuration.","properties":{"adoptionWindowMs":{"description":"Maximum adoption window in milliseconds.","format":"uint32","maximum":900000,"minimum":1,"type":"integer"},"controllerExecutionRef":{"allOf":[{"$ref":"#/definitions/ResourceRef"}],"description":"Explicit Host execution reference.","pattern":"^Host/[a-z][a-z0-9-]{0,62}$"},"defaultMachineType":{"allOf":[{"$ref":"#/definitions/OpaqueAzureRef"}],"description":"Default machine type.","pattern":"^(q35|microvm)$"},"defaultMemoryMb":{"description":"Default memory in MiB.","format":"uint32","maximum":524288,"minimum":128,"type":"integer"},"defaultVcpus":{"description":"Default VCPU count.","format":"uint16","maximum":1024,"minimum":1,"type":"integer"},"healthCheckFailureThreshold":{"description":"Consecutive failures before degradation.","format":"uint8","maximum":255,"minimum":1,"type":"integer"},"healthCheckIntervalMs":{"description":"ComponentSession polling interval.","format":"uint32","maximum":300000,"minimum":5000,"type":"integer"},"healthCheckTimeoutMs":{"description":"ComponentSession attempt timeout.","format":"uint32","maximum":60000,"minimum":1000,"type":"integer"},"startupDeadlineMs":{"description":"Startup deadline.","format":"uint32","maximum":900000,"minimum":1,"type":"integer"},"watchdog":{"description":"Whether the VMM watchdog is enabled.","type":"boolean"}},"required":["adoptionWindowMs","controllerExecutionRef","defaultMachineType","defaultMemoryMb","defaultVcpus","healthCheckFailureThreshold","healthCheckIntervalMs","healthCheckTimeoutMs","startupDeadlineMs","watchdog"],"title":"CloudHypervisorConfig","type":"object"} \ No newline at end of file +{"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"definitions":{"ResourceRef":{"oneOf":[{"maxLength":80,"minLength":6,"pattern":"^(Zone|ZoneLink|Provider|Role|RoleBinding|Quota|EmergencyPolicy|Host|Guest|Process|EphemeralProcess|Volume|Network|Device|User|Credential|Endpoint|ResourceExport|ResourceImport)/[a-z][a-z0-9-]{0,62}$","type":"string"},{"maxLength":201,"minLength":15,"pattern":"^[a-z][a-z0-9-]{0,62}\\.d2bus\\.org\\.[A-Z][A-Za-z0-9]{0,62}/[a-z][a-z0-9-]{0,62}$","type":"string"}]}},"description":"Provider root configuration.","properties":{"adoptionWindowMs":{"description":"Maximum adoption window in milliseconds.","format":"uint32","maximum":900000,"minimum":1,"type":"integer"},"controllerExecutionRef":{"allOf":[{"$ref":"#/definitions/ResourceRef"}],"description":"Explicit Host execution reference.","pattern":"^Host/[a-z][a-z0-9-]{0,62}$"},"defaultMachineType":{"description":"Default machine type.","enum":["q35","microvm"],"type":"string"},"defaultMemoryMb":{"description":"Default memory in MiB.","format":"uint32","maximum":524288,"minimum":128,"type":"integer"},"defaultVcpus":{"description":"Default VCPU count.","format":"uint16","maximum":1024,"minimum":1,"type":"integer"},"healthCheckFailureThreshold":{"description":"Consecutive failures before degradation.","format":"uint8","maximum":255,"minimum":1,"type":"integer"},"healthCheckIntervalMs":{"description":"ComponentSession polling interval.","format":"uint32","maximum":300000,"minimum":5000,"type":"integer"},"healthCheckTimeoutMs":{"description":"ComponentSession attempt timeout.","format":"uint32","maximum":60000,"minimum":1000,"type":"integer"},"startupDeadlineMs":{"description":"Startup deadline.","format":"uint32","maximum":900000,"minimum":1,"type":"integer"},"watchdog":{"description":"Whether the VMM watchdog is enabled.","type":"boolean"}},"required":["adoptionWindowMs","controllerExecutionRef","defaultMachineType","defaultMemoryMb","defaultVcpus","healthCheckFailureThreshold","healthCheckIntervalMs","healthCheckTimeoutMs","startupDeadlineMs","watchdog"],"title":"CloudHypervisorConfig","type":"object"} \ No newline at end of file From 1af47c8cf47d9e16c53ec9c4ef1b2c481279ee40 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:56:18 -0700 Subject: [PATCH 666/726] refactor(d2b-contracts-resource): type the activation generation fields The activation-runner input carries the nonzero `NixosGenerationOrdinal` identity instead of a bare `u64` behind a hand-rolled nonzero schema override and a constructor zero check, and the generation status carries the existing `ObservedGeneration`. Wire bytes and the rendered integer schemas are unchanged: the ordinal renders as a definition reference in the committed EphemeralProcess schema, and the two hand-committed activation-nixos schemas carry the full `ObservedGeneration` rendering. The duplicated zero guards in the process-conformance ticket and the provider-process spawn runner go with the contract check, which is now unreachable. --- .../w7-02-activation-generation-types.md | 20 +++++ ...ixos.d2bus.org_NixosGeneration.schema.json | 1 + ...bus.org_NixosGeneration_status.schema.json | 1 + ...ore.d2bus.org_EphemeralProcess.schema.json | 14 +++- .../src/v3/activation_nixos.rs | 74 +++++++++---------- .../d2b-contracts-resource/src/v3/identity.rs | 2 + packages/d2b-contracts-resource/src/v3/mod.rs | 6 +- packages/d2b-contracts/src/identity.rs | 1 + .../d2b-process-conformance/src/ticket.rs | 7 +- .../src/controller.rs | 17 ++--- .../d2b-provider-process/src/operations.rs | 6 -- 11 files changed, 83 insertions(+), 66 deletions(-) create mode 100644 changelog.d/w7-02-activation-generation-types.md diff --git a/changelog.d/w7-02-activation-generation-types.md b/changelog.d/w7-02-activation-generation-types.md new file mode 100644 index 000000000..305e7a973 --- /dev/null +++ b/changelog.d/w7-02-activation-generation-types.md @@ -0,0 +1,20 @@ +### Changed + +- The activation-runner `targetGeneration` contract field is typed as + the nonzero `NixosGenerationOrdinal` identity instead of a bare `u64`, + so a zero ordinal is refused when the input decodes rather than by a + manual check in the constructor. The wire bytes are unchanged, and the + committed EphemeralProcess schema now carries the ordinal as a + definition reference instead of an inline minimum-1 integer. +- The activation-nixos status `observedGeneration` field is typed as + `ObservedGeneration` (zero meaning none) instead of a bare `u64`. The + transparent newtype renders the same integer schema, and the two + hand-committed activation-nixos schemas now carry its full rendering + (`format: uint64`, `minimum: 0`). + +### Removed + +- `ActivationRunnerInputError` and its `GenerationInvalid` variant: the + nonzero ordinal carries the invariant, so `ActivationRunnerInput::new` + is infallible. The duplicated `target_generation == 0` guards in + `d2b-process-conformance` and `d2b-provider-process` went with it. diff --git a/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration.schema.json b/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration.schema.json index 548b1764b..e231f8860 100644 --- a/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration.schema.json +++ b/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration.schema.json @@ -52,6 +52,7 @@ "type": "string" }, "observedGeneration": { + "format": "uint64", "minimum": 0, "type": "integer" }, diff --git a/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration_status.schema.json b/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration_status.schema.json index 28d50761b..9f3ba335e 100644 --- a/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration_status.schema.json +++ b/docs/reference/schemas/v3/activation-nixos.d2bus.org_NixosGeneration_status.schema.json @@ -17,6 +17,7 @@ "type": "string" }, "observedGeneration": { + "format": "uint64", "minimum": 0, "type": "integer" }, diff --git a/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json b/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json index c779fb18f..81da887dd 100644 --- a/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json +++ b/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json @@ -57,10 +57,12 @@ "description": "Private-catalog artifact identifier." }, "targetGeneration": { - "description": "Target generation ordinal bound to the owning `NixosGeneration`.", - "format": "uint64", - "minimum": 1.0, - "type": "integer" + "allOf": [ + { + "$ref": "#/definitions/NixosGenerationOrdinal" + } + ], + "description": "Target generation ordinal bound to the owning `NixosGeneration`." } }, "required": [ @@ -403,6 +405,10 @@ ], "type": "object" }, + "NixosGenerationOrdinal": { + "minimum": 1.0, + "type": "integer" + }, "PortProtocol": { "description": "Transport protocol of one declared port.", "enum": [ diff --git a/packages/d2b-contracts-resource/src/v3/activation_nixos.rs b/packages/d2b-contracts-resource/src/v3/activation_nixos.rs index 51d0d9d1b..8e9f69896 100644 --- a/packages/d2b-contracts-resource/src/v3/activation_nixos.rs +++ b/packages/d2b-contracts-resource/src/v3/activation_nixos.rs @@ -1,13 +1,12 @@ //! Contracts for the activation-nixos Provider. -use schemars::{ - JsonSchema, - r#gen::SchemaGenerator, - schema::{Schema, SchemaObject}, -}; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use super::{ArtifactId, ResourceRef, ResourceTypeName, execution_policy::require_execution_ref}; +use super::{ + ArtifactId, NixosGenerationOrdinal, ObservedGeneration, ResourceRef, ResourceTypeName, + execution_policy::require_execution_ref, +}; use d2b_contracts::wire_deserialize; /// The canonical activation generation ResourceType. @@ -44,48 +43,23 @@ pub struct ActivationRunnerInput { /// Private-catalog artifact identifier. pub system_artifact_id: ArtifactId, /// Target generation ordinal bound to the owning `NixosGeneration`. - #[schemars(schema_with = "nonzero_u64_schema")] - pub target_generation: u64, + pub target_generation: NixosGenerationOrdinal, /// Closed activation mode. pub activation_mode: ActivationMode, } -fn nonzero_u64_schema(generator: &mut SchemaGenerator) -> Schema { - let mut schema: SchemaObject = ::json_schema(generator).into(); - schema.number.get_or_insert_with(Default::default).minimum = Some(1.0); - schema.into() -} - -/// Validation failure for a typed activation-runner input. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ActivationRunnerInputError { - /// Target generation ordinal was zero. - GenerationInvalid, -} - -impl core::fmt::Display for ActivationRunnerInputError { - fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - formatter.write_str("activation-runner-generation-invalid") - } -} - -impl std::error::Error for ActivationRunnerInputError {} - impl ActivationRunnerInput { - /// Construct and validate one runner input. + /// Construct one runner input. pub fn new( system_artifact_id: ArtifactId, - target_generation: u64, + target_generation: NixosGenerationOrdinal, activation_mode: ActivationMode, - ) -> Result { - if target_generation == 0 { - return Err(ActivationRunnerInputError::GenerationInvalid); - } - Ok(Self { + ) -> Self { + Self { system_artifact_id, target_generation, activation_mode, - }) + } } } @@ -281,5 +255,29 @@ pub struct NixosGenerationStatus { #[serde(skip_serializing_if = "Option::is_none")] pub outcome: Option, /// Store generation revision observed by the controller. - pub observed_generation: u64, + pub observed_generation: ObservedGeneration, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn runner_input_refuses_a_zero_target_generation() { + let input = |target_generation: u64| { + serde_json::json!({ + "systemArtifactId": "system-artifact", + "targetGeneration": target_generation, + "activationMode": "switch", + }) + }; + assert!( + serde_json::from_value::(input(1)).is_ok(), + "a nonzero target generation decodes" + ); + assert!( + serde_json::from_value::(input(0)).is_err(), + "a zero target generation is refused at decode" + ); + } } diff --git a/packages/d2b-contracts-resource/src/v3/identity.rs b/packages/d2b-contracts-resource/src/v3/identity.rs index 13708fe90..1b09ecd16 100644 --- a/packages/d2b-contracts-resource/src/v3/identity.rs +++ b/packages/d2b-contracts-resource/src/v3/identity.rs @@ -500,6 +500,8 @@ impl ConfigurationGeneration { } } +nonzero_generation!(NixosGenerationOrdinal, IdentityClass::NixosGenerationOrdinal); + /// The latest generation a controller has observed, with zero meaning none. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, diff --git a/packages/d2b-contracts-resource/src/v3/mod.rs b/packages/d2b-contracts-resource/src/v3/mod.rs index 36eec833d..53a72cef6 100644 --- a/packages/d2b-contracts-resource/src/v3/mod.rs +++ b/packages/d2b-contracts-resource/src/v3/mod.rs @@ -34,9 +34,9 @@ pub use execution_policy::*; pub use host::*; pub use identity::{ ConfigurationGeneration, ControllerGeneration, IdentityClass, IdentityError, - ObservedGeneration, ResourceBundleGenerationId, ResourceGeneration, ResourceName, - ResourceTypeName, ResourceUid, SchemaFingerprint, Timestamp, V3_CONVERTED_RESOURCE_TYPES, - ZoneId, ZoneResourceIdentity, ZoneRevision, + NixosGenerationOrdinal, ObservedGeneration, ResourceBundleGenerationId, ResourceGeneration, + ResourceName, ResourceTypeName, ResourceUid, SchemaFingerprint, Timestamp, + V3_CONVERTED_RESOURCE_TYPES, ZoneId, ZoneResourceIdentity, ZoneRevision, }; pub mod ifname { pub use d2b_contracts::v3::ifname::*; diff --git a/packages/d2b-contracts/src/identity.rs b/packages/d2b-contracts/src/identity.rs index 94375c6f8..68ebe2e50 100644 --- a/packages/d2b-contracts/src/identity.rs +++ b/packages/d2b-contracts/src/identity.rs @@ -248,6 +248,7 @@ pub enum IdentityClass { ReconnectGeneration, ControllerGeneration, ConfigurationGeneration, + NixosGenerationOrdinal, } /// Reason a canonical identity could not be constructed. diff --git a/packages/d2b-process-conformance/src/ticket.rs b/packages/d2b-process-conformance/src/ticket.rs index a2a27c5c3..1b57741a5 100644 --- a/packages/d2b-process-conformance/src/ticket.rs +++ b/packages/d2b-process-conformance/src/ticket.rs @@ -761,11 +761,7 @@ impl LaunchTicket { || !matches!( self.execution_ref.resource_type().as_str(), "Host" | "Guest" - ) - || self - .activation_input - .as_ref() - .is_some_and(|input| input.target_generation == 0)) + )) { return Err(ProcessConformanceError::InvalidTicket); } @@ -882,7 +878,6 @@ impl LaunchTicket { self.execution_ref.resource_type().as_str(), "Host" | "Guest" ) - || input.target_generation == 0 { return Err(ProcessConformanceError::InvalidTicket); } diff --git a/packages/d2b-provider-activation-nixos/src/controller.rs b/packages/d2b-provider-activation-nixos/src/controller.rs index 2cea004de..161f2dad0 100644 --- a/packages/d2b-provider-activation-nixos/src/controller.rs +++ b/packages/d2b-provider-activation-nixos/src/controller.rs @@ -2,7 +2,8 @@ use d2b_contracts_resource::v3::{ ActivationMode, ActivationOutcomeCode, ActivationRunnerInput, ArtifactId, EnvironmentClass, - ExecutionDomain, IdentityError, NixosGenerationSpec, ResourceName, ResourcePhase, ResourceRef, + ExecutionDomain, IdentityError, NixosGenerationOrdinal, NixosGenerationSpec, ResourceName, + ResourcePhase, ResourceRef, process::{EphemeralProcessSpec, ExecutionSpec, NamespaceClass, ProcessClass, SandboxSpec}, }; use ring::signature; @@ -384,14 +385,12 @@ pub fn activation_runner_spec(request: &RunnerRequest) -> EphemeralProcessSpec { false, ) .expect("static activation runner process"); - spec.with_activation_input( - ActivationRunnerInput::new( - request.system_artifact_id.clone(), - request.target_generation, - request.activation_mode, - ) - .expect("activation runner generation is nonzero"), - ) + spec.with_activation_input(ActivationRunnerInput::new( + request.system_artifact_id.clone(), + NixosGenerationOrdinal::new(request.target_generation) + .expect("activation runner generation is nonzero"), + request.activation_mode, + )) .expect("activation runner accepts its typed input") } diff --git a/packages/d2b-provider-process/src/operations.rs b/packages/d2b-provider-process/src/operations.rs index 8bb64b5b0..b3f662ebd 100644 --- a/packages/d2b-provider-process/src/operations.rs +++ b/packages/d2b-provider-process/src/operations.rs @@ -2503,12 +2503,6 @@ impl OperationHandler for SpawnRunnerHandler { } match (&request.activation_input, request.role) { (Some(input), RunnerRole::ActivationNixos) => { - if input.target_generation == 0 { - return Err(OperationFailure::with_detail( - INTENT_MISMATCH, - "activation_input.target_generation: 0 vs nonzero".to_owned(), - )); - } if request.generation.is_none() { return Err(OperationFailure::with_detail( INTENT_MISMATCH, From f75fbf3e823b7ef448c0493ac277447e064c4cf0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:53:41 -0700 Subject: [PATCH 667/726] xtask: close the closure edge-kind vocabulary and borrow the context spec The dependency kind moved through traverse, filter, and emit as a free string parsed once at the metadata boundary; it is now an enum whose wire spelling is unchanged, with the allowed production and policy kind sets typed as enum sets and the emitted edge order still following that spelling. The computed context no longer clones the spec it borrows from its caller. --- ...03-xtask-edge-kind-and-borrowed-context.md | 12 ++ packages/xtask/src/production_closure.rs | 181 ++++++++++++++---- 2 files changed, 154 insertions(+), 39 deletions(-) create mode 100644 changelog.d/w7-03-xtask-edge-kind-and-borrowed-context.md diff --git a/changelog.d/w7-03-xtask-edge-kind-and-borrowed-context.md b/changelog.d/w7-03-xtask-edge-kind-and-borrowed-context.md new file mode 100644 index 000000000..f3f7f7537 --- /dev/null +++ b/changelog.d/w7-03-xtask-edge-kind-and-borrowed-context.md @@ -0,0 +1,12 @@ +### Changed + +- The package-policy generator carries a Cargo dependency kind as a + closed enum instead of a free string: the locked-metadata boundary + parses the kind once, the production and policy kind sets are enum + sets, and the emitted spelling (including `proc-macro`) is + byte-identical, so no checked-in closure changes. A kind outside the + vocabulary is now reported instead of silently dropping the edge, and + the emitted edge order still follows the wire spelling. +- Generating the package-policy inputs borrows the context spec it is + computing instead of cloning it, so a run no longer copies each spec + once per mode. diff --git a/packages/xtask/src/production_closure.rs b/packages/xtask/src/production_closure.rs index 31e170dec..86c382eaf 100644 --- a/packages/xtask/src/production_closure.rs +++ b/packages/xtask/src/production_closure.rs @@ -7,6 +7,7 @@ //! invocation is ever pointed at one of them. use std::{ + cmp::Ordering, collections::{BTreeMap, BTreeSet, VecDeque}, fs, path::{Path, PathBuf}, @@ -71,25 +72,93 @@ impl ContextSpec { format!("{}/{}/{}", self.system, self.target, self.name) } - fn production_kinds(&self) -> BTreeSet<&'static str> { - ["normal", "build", "proc-macro"].into_iter().collect() + fn production_kinds(&self) -> BTreeSet { + [EdgeKind::Normal, EdgeKind::Build, EdgeKind::ProcMacro] + .into_iter() + .collect() } - fn policy_kinds(&self) -> BTreeSet<&'static str> { + fn policy_kinds(&self) -> BTreeSet { [ - "normal", - "build", - "proc-macro", - "dev", - "test", - "example", - "bench", + EdgeKind::Normal, + EdgeKind::Build, + EdgeKind::ProcMacro, + EdgeKind::Dev, + EdgeKind::Test, + EdgeKind::Example, + EdgeKind::Bench, ] .into_iter() .collect() } } +/// The closed Cargo dependency-kind vocabulary this module reasons about. +/// +/// Cargo metadata hands the kind over as a string and the checked-in closures +/// keep it as a string, so the enum carries that spelling in both directions: +/// parsing at the metadata boundary is how a string becomes a kind, and the +/// serde rename is how a kind becomes a string again. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +enum EdgeKind { + Normal, + Build, + Dev, + Test, + Example, + Bench, + ProcMacro, +} + +impl EdgeKind { + /// The spelling the closure files use. + fn as_str(self) -> &'static str { + match self { + Self::Normal => "normal", + Self::Build => "build", + Self::Dev => "dev", + Self::Test => "test", + Self::Example => "example", + Self::Bench => "bench", + Self::ProcMacro => "proc-macro", + } + } + + /// Map a Cargo metadata dependency kind onto the vocabulary. + /// + /// Total over everything Cargo emits: a dependency without a `kind` field + /// is normal, and a spelling outside the vocabulary is reported instead of + /// silently dropping the edge. + fn parse(raw: &str) -> Result { + match raw { + "normal" => Ok(Self::Normal), + "build" => Ok(Self::Build), + "dev" => Ok(Self::Dev), + "test" => Ok(Self::Test), + "example" => Ok(Self::Example), + "bench" => Ok(Self::Bench), + "proc-macro" => Ok(Self::ProcMacro), + other => Err(format!("unknown dependency kind: {other}")), + } + } +} + +/// Ordering is the wire spelling, not the declaration order: one package can +/// depend on another both normally and as a dev dependency, and the emitted +/// order for such a pair has always been the spelling order. +impl Ord for EdgeKind { + fn cmp(&self, other: &Self) -> Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl PartialOrd for EdgeKind { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] struct PackageRecord { id: String, @@ -104,7 +173,7 @@ struct PackageRecord { struct EdgeRecord { from: String, to: String, - kind: String, + kind: EdgeKind, target: Option, } @@ -135,8 +204,8 @@ struct ApprovalProjection { } #[derive(Clone, Debug, Eq, PartialEq)] -struct ComputedContext { - spec: ContextSpec, +struct ComputedContext<'a> { + spec: &'a ContextSpec, production: Closure, policy: Closure, metadata: Value, @@ -260,7 +329,7 @@ fn generate_outputs(root: &Path) -> Result, String> { .collect::>(); let mut written = Vec::new(); for spec in &contexts { - let computed = compute_context(root, spec.clone())?; + let computed = compute_context(root, spec)?; let approval = policy .get(&spec.key()) .map(|context| context.approval.clone()); @@ -375,8 +444,8 @@ fn check_outputs(root: &Path) -> Result, String> { } let mut checked = Vec::new(); - for spec in contexts { - let computed = compute_context(root, spec.clone())?; + for spec in &contexts { + let computed = compute_context(root, spec)?; let advisory = policy .get(&spec.key()) .ok_or_else(|| format!("missing advisory context {}", spec.key()))?; @@ -422,7 +491,7 @@ fn check_outputs(root: &Path) -> Result, String> { Ok(checked) } -fn compute_context(root: &Path, spec: ContextSpec) -> Result { +fn compute_context<'a>(root: &Path, spec: &'a ContextSpec) -> Result, String> { if spec.roots.is_empty() { return Err(format!("context {} has no roots", spec.key())); } @@ -488,7 +557,7 @@ fn compute_context(root: &Path, spec: ContextSpec) -> Result Result Result, } -fn compute_lock_context(root: &Path, spec: ContextSpec) -> Result { +fn compute_lock_context<'a>( + root: &Path, + spec: &'a ContextSpec, +) -> Result, String> { let lock_packages = parse_lock_packages(root.join(&spec.lock_path))?; let mut by_name = BTreeMap::>::new(); let mut packages = BTreeMap::::new(); @@ -599,7 +671,7 @@ fn compute_lock_context(root: &Path, spec: ContextSpec) -> Result, nodes: &BTreeMap, packages: &BTreeMap, - allowed_kinds: &BTreeSet<&'static str>, + allowed_kinds: &BTreeSet, target: &str, ) -> Result<(BTreeSet, Vec), String> { let mut selected = roots.clone(); let mut queue = roots.iter().cloned().collect::>(); - let mut edges = BTreeSet::<(String, String, String, Option)>::new(); + let mut edges = BTreeSet::<(String, String, EdgeKind, Option)>::new(); while let Some(from_id) = queue.pop_front() { let node = nodes .get(&from_id) @@ -656,23 +728,22 @@ fn traverse( .and_then(Value::as_array) .ok_or_else(|| format!("dependency from {from_id} has no dep_kinds"))?; for dep_kind in dep_kinds { - let raw_kind = dep_kind - .get("kind") - .and_then(Value::as_str) - .unwrap_or("normal"); + let kind = match dep_kind.get("kind").and_then(Value::as_str) { + Some(raw_kind) => EdgeKind::parse(raw_kind)?, + None => EdgeKind::Normal, + }; let cfg = dep_kind .get("target") .and_then(Value::as_str) .map(str::to_owned); - if !allowed_kinds.contains(raw_kind) || !target_matches(cfg.as_deref(), target) { + if !allowed_kinds.contains(&kind) || !target_matches(cfg.as_deref(), target) { continue; } let kind = if package_is_proc_macro(packages.get(&to_id).expect("checked")) { - "proc-macro" + EdgeKind::ProcMacro } else { - raw_kind - } - .to_owned(); + kind + }; edges.insert((from_id.clone(), to_id.clone(), kind, cfg)); if selected.insert(to_id.clone()) { queue.push_back(to_id.clone()); @@ -720,7 +791,7 @@ fn make_closure( .map(|edge| EdgeRecord { from: stable_id(packages.get(&edge.from).expect("edge source package")), to: stable_id(packages.get(&edge.to).expect("edge target package")), - kind: edge.kind.clone(), + kind: edge.kind, target: edge.target.clone(), }) .collect::>(); @@ -1016,7 +1087,7 @@ fn metadata_projection( #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn write_context( root: &Path, - computed: &ComputedContext, + computed: &ComputedContext<'_>, approval: Option, written: &mut Vec, ) -> Result<(), String> { @@ -1744,10 +1815,42 @@ mod tests { source_authority: "Cargo.lock".to_owned(), lock_path: PRODUCT_LOCK.to_owned(), }; - assert!(spec.production_kinds().contains("normal")); - assert!(spec.production_kinds().contains("build")); - assert!(spec.production_kinds().contains("proc-macro")); - assert!(!spec.production_kinds().contains("dev")); + assert!(spec.production_kinds().contains(&EdgeKind::Normal)); + assert!(spec.production_kinds().contains(&EdgeKind::Build)); + assert!(spec.production_kinds().contains(&EdgeKind::ProcMacro)); + assert!(!spec.production_kinds().contains(&EdgeKind::Dev)); + } + + /// The first dependency of one package on another can be both a dev and a + /// normal dependency, so the edge sort is what decides their order in the + /// emitted file: it orders by the wire spelling, and a reordering here + /// rewrites checked-in closures. + #[test] + fn edge_kind_orders_by_its_wire_spelling() { + assert!(EdgeKind::Dev < EdgeKind::Normal); + assert!(EdgeKind::Bench < EdgeKind::Build); + assert!(EdgeKind::Normal < EdgeKind::ProcMacro); + } + + #[test] + fn edge_kind_spelling_is_the_wire_spelling() { + for kind in [ + EdgeKind::Normal, + EdgeKind::Build, + EdgeKind::Dev, + EdgeKind::Test, + EdgeKind::Example, + EdgeKind::Bench, + EdgeKind::ProcMacro, + ] { + assert_eq!( + serde_json::to_string(&kind).unwrap(), + format!("\"{}\"", kind.as_str()) + ); + assert_eq!(EdgeKind::parse(kind.as_str()).unwrap(), kind); + } + assert_eq!(EdgeKind::ProcMacro.as_str(), "proc-macro"); + assert!(EdgeKind::parse("workspace").is_err()); } #[test] From e4277787de5fab6b47aa6bf9de78535d01fad189 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 20:57:51 -0700 Subject: [PATCH 668/726] guest: hold the status sink and test recorders in async locks The Guest family's status capture point and its test-support recorders kept state in parking_lot locks, so the banned lock type leaked into this crate's and d2bd's public signatures and the doubles sat on a blocking lock inside async methods. The capture point is now Arc>>: every write awaits it and no guard is held across another await. The driver's Cloud Hypervisor arm, the daemon's controller-status handler and the effects-service test take it with lock().await, and the crate drops its parking_lot dependency. The recorders use the async lock where only async methods touch them and a blocking lock with the recorded per-site exception where the facet traits' synchronous accessors read them; the driver harness's order log is the toolkit's SharedLog, so no lock appears at its call sites. The async-gate hatch inventory is regenerated for the moved marker sites and the policy inputs for the lock-file change. --- Cargo.lock | 1 - .../w7-07-guest-status-sink-and-recorders.md | 19 +++ packages/d2b-provider-guest/Cargo.toml | 1 - packages/d2b-provider-guest/src/driver.rs | 157 +++++++++++------- .../d2b-provider-guest/src/effects_service.rs | 60 ++++--- .../d2b-provider-guest/src/test_support.rs | 118 +++++++------ packages/d2bd/src/resource_runtime.rs | 5 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 - .../main-product/policy/closure.json | 8 +- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 - .../main-product/production/closure.json | 8 +- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 1 - .../main-product/policy/closure.json | 8 +- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 1 - .../main-product/production/closure.json | 8 +- .../main-product/production/metadata.json | 2 +- packages/xtask/data/async-gate-inventory.json | 93 +---------- 52 files changed, 265 insertions(+), 297 deletions(-) create mode 100644 changelog.d/w7-07-guest-status-sink-and-recorders.md diff --git a/Cargo.lock b/Cargo.lock index 728b558e8..366c35a2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1395,7 +1395,6 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "d2bd-runtime", - "parking_lot", "schemars", "serde", "serde_json", diff --git a/changelog.d/w7-07-guest-status-sink-and-recorders.md b/changelog.d/w7-07-guest-status-sink-and-recorders.md new file mode 100644 index 000000000..2abf7ec1b --- /dev/null +++ b/changelog.d/w7-07-guest-status-sink-and-recorders.md @@ -0,0 +1,19 @@ +### Changed + +- The Guest family's status capture point is now an async lock + (`Arc>>` in place of the banned + `parking_lot` lock): every write awaits it and no guard is held + across another await. The driver's Cloud Hypervisor reconcile arm and + the daemon's controller-status handler take it with `lock().await`, + and `d2b-provider-guest` no longer depends on `parking_lot`. + +### Fixed + +- The Guest test-support recorder doubles and the guest driver's test + harness no longer hold recorder state in `parking_lot` locks. The + scripted effect and facet recorders use the toolkit's `SharedLog` or + the async lock where only async methods touch them, and the blocking + lock with a recorded per-site exception where the facet traits' + synchronous accessors read them; the harness's order log is a + `SharedLog` and its row/view recorders a blocking lock with the same + recorded exception. diff --git a/packages/d2b-provider-guest/Cargo.toml b/packages/d2b-provider-guest/Cargo.toml index 3c54abcb7..edf66d2d0 100644 --- a/packages/d2b-provider-guest/Cargo.toml +++ b/packages/d2b-provider-guest/Cargo.toml @@ -26,7 +26,6 @@ d2b-provider-guest-azure-virtual-machine = { path = "../d2b-provider-guest-azure d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-bootstrap" } d2b-contracts-provider = { path = "../d2b-contracts-provider", version = "0.0.0-bootstrap" } sha2 = { workspace = true } -parking_lot = "0.12" schemars = { workspace = true } serde = { workspace = true } serde_json.workspace = true diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index 9029c3670..fea83208e 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -504,11 +504,14 @@ pub fn view_phase(view: &d2b_resource_runtime::manager::ResourceView) -> &'stati /// controller's status write into: the converted Guest's status is /// actor-local, so the effect call that drives the controller is the only /// place it can be observed (R11: no dual-write into any store). -pub type GuestStatusSink = Arc>>; +/// +/// The capture point is an async lock: every write awaits it and no guard +/// is ever held across another await. +pub type GuestStatusSink = Arc>>; /// A fresh, empty Guest status sink. pub fn guest_status_sink() -> GuestStatusSink { - Arc::new(parking_lot::Mutex::new(None)) + Arc::new(tokio::sync::Mutex::new(None)) } // --------------------------------------------------------------------------- @@ -1515,6 +1518,8 @@ mod tests { use d2b_resource_runtime::resource::ResourceStatus; use d2b_resource_runtime::spec_store::EnsureOutcome; + use d2b_provider_toolkit::testing::SharedLog; + use super::{ GUEST_REGISTRATIONS, GUEST_TYPE_NAME, GuestDriver, GuestDriverArgs, GuestDriverFactory, GuestDriverStatus, GuestEffectError, GuestEffectPhase, GuestFinalizeStage, GuestKind, @@ -1538,9 +1543,9 @@ mod tests { /// (or keeps) the child row and its live view; the child's published /// phase is the `children_ready` switch. struct RecordingManager { - calls: Arc>>, - rows: parking_lot::Mutex>, - views: parking_lot::Mutex>, + calls: SharedLog, + rows: std::sync::Mutex>, + views: std::sync::Mutex>, children_ready: std::sync::atomic::AtomicBool, fail_reads: std::sync::atomic::AtomicBool, } @@ -1548,9 +1553,9 @@ mod tests { impl RecordingManager { fn new() -> Arc { Arc::new(Self { - calls: Arc::new(parking_lot::Mutex::new(Vec::new())), - rows: parking_lot::Mutex::new(Vec::new()), - views: parking_lot::Mutex::new(Vec::new()), + calls: SharedLog::new(), + rows: std::sync::Mutex::new(Vec::new()), + views: std::sync::Mutex::new(Vec::new()), children_ready: std::sync::atomic::AtomicBool::new(false), fail_reads: std::sync::atomic::AtomicBool::new(false), }) @@ -1558,8 +1563,8 @@ mod tests { /// The shared order log: effect calls that were constructed over it /// append to the same sequence. - fn log_handle(&self) -> Arc>> { - Arc::clone(&self.calls) + fn log_handle(&self) -> SharedLog { + self.calls.clone() } fn set_children_ready(&self, ready: bool) { @@ -1585,25 +1590,28 @@ mod tests { status_generation: Some(row.generation), status_projection: None, }; - self.rows.lock().push(row); - self.views.lock().push((view.key.clone(), view)); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.rows.lock().unwrap().push(row); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.views.lock().unwrap().push((view.key.clone(), view)); } fn drop_row(&self, key: &ResourceKey) { - self.rows.lock().retain(|row| row.key != *key); - self.views.lock().retain(|(view_key, _)| view_key != key); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.rows.lock().unwrap().retain(|row| row.key != *key); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.views.lock().unwrap().retain(|(view_key, _)| view_key != key); } fn call_order(&self) -> Vec { - self.calls.lock().clone() + self.calls.entries() } fn ensure_order(&self) -> Vec { self.calls - .lock() - .iter() + .entries() + .into_iter() .filter(|call| call.starts_with("ensure:")) - .cloned() .collect() } } @@ -1616,14 +1624,14 @@ mod tests { child: ChildEnsure, ) -> Result { self.calls - .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held - .push(format!("ensure:{}/{}", child.type_name.as_str(), child.name)); + .record(format!("ensure:{}/{}", child.type_name.as_str(), child.name)); let key = ResourceKey::new( parent.zone.clone(), child.type_name.as_str(), child.name.as_str(), ); - let mut rows = self.rows.lock(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + let mut rows = self.rows.lock().unwrap(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held if let Some(existing) = rows.iter().find(|row| row.key == key).cloned() { if existing.spec == child.spec { return Ok(EnsureOutcome::Unchanged(existing)); @@ -1635,8 +1643,10 @@ mod tests { updated.generation += 1; rows.push(updated.clone()); drop(rows); - self.views.lock().retain(|(view_key, _)| view_key != &key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - self.views.lock().push(( // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.views.lock().unwrap().retain(|(view_key, _)| view_key != &key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.views.lock().unwrap().push(( // async-gate-allow: synchronous lock acquisition, no await while the guard is held key, ResourceView { key: updated.key.clone(), @@ -1671,7 +1681,8 @@ mod tests { }; rows.push(row.clone()); drop(rows); - self.views.lock().push(( // async-gate-allow: synchronous lock acquisition, no await while the guard is held + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.views.lock().unwrap().push(( // async-gate-allow: synchronous lock acquisition, no await while the guard is held key, ResourceView { key: row.key.clone(), @@ -1698,33 +1709,37 @@ mod tests { &self, key: &ResourceKey, ) -> Result, ResourceError> { - self.calls.lock().push(format!("get:{}/{}", key.type_name, key.name)); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.record(format!("get:{}/{}", key.type_name, key.name)); if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] Ok(self .rows .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held + .unwrap() .iter() .find(|row| row.key == *key) .cloned()) } async fn view(&self, key: &ResourceKey) -> Result, ResourceError> { - self.calls.lock().push(format!("view:{}/{}", key.type_name, key.name)); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.record(format!("view:{}/{}", key.type_name, key.name)); if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] Ok(self .views .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held + .unwrap() .iter() .find(|(view_key, _)| view_key == key) .map(|(_, view)| view.clone())) } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { - self.calls.lock().push(format!("delete:{}/{}", key.type_name, key.name)); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.record(format!("delete:{}/{}", key.type_name, key.name)); self.drop_row(key); Ok(()) } @@ -1733,13 +1748,15 @@ mod tests { &self, owner_uid: [u8; 16], ) -> Result, ResourceError> { - self.calls.lock().push("list-owned".to_owned()); + self.calls.record("list-owned".to_owned()); if self.fail_reads.load(std::sync::atomic::Ordering::SeqCst) { return Err(ResourceError::ManagerRejected { reason: "scripted read failure".into() }); } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] Ok(self .rows - .lock() + .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held + .unwrap() .iter() .filter(|row| row.owner_uid == Some(owner_uid)) .cloned() @@ -1751,7 +1768,7 @@ mod tests { _subscriber: &ResourceKey, registration: WatchRegistration, ) -> Result { - self.calls.lock().push(format!( // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.record(format!( "watch:{}/{}", registration.target.type_name, registration.target.name )); @@ -1759,26 +1776,27 @@ mod tests { } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { - self.calls.lock().push("cancel-watch".to_owned()); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.record("cancel-watch".to_owned()); Ok(()) } } struct RecordingRequeue { - scheduled: parking_lot::Mutex>, + scheduled: std::sync::Mutex>, } impl RecordingRequeue { fn new() -> Arc { Arc::new(Self { - scheduled: parking_lot::Mutex::new(Vec::new()), + scheduled: std::sync::Mutex::new(Vec::new()), }) } } impl RequeueScheduler for RecordingRequeue { fn schedule(&self, key: ResourceKey, after: std::time::Duration) -> RequeueId { - self.scheduled.lock().push((key, after)); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + self.scheduled.lock().unwrap().push((key, after)); RequeueId(0) } @@ -1977,28 +1995,34 @@ mod tests { #[tokio::test] async fn driver_recreation_shares_the_factorys_controller_state() { let facets = crate::test_support::ScriptedFacets::new(); - facets.add_row(crate::test_support::row_fixture( - "work", - "Provider", - "runtime-azure-container-apps", - aca_provider_spec(), - ResourceStatus::Ready, - )); - facets.add_row(crate::test_support::row_fixture_with_metadata( - "work", - "Guest", - "gateway", - serde_json::json!({}), - ResourceStatus::Ready, - serde_json::json!({ "zone": "work" }), - )); - facets.add_row(crate::test_support::row_fixture( - "work", - "Credential", - "control", - serde_json::json!({ "scope": { "executionRef": "Guest/gateway" } }), - ResourceStatus::Ready, - )); + facets + .add_row(crate::test_support::row_fixture( + "work", + "Provider", + "runtime-azure-container-apps", + aca_provider_spec(), + ResourceStatus::Ready, + )) + .await; + facets + .add_row(crate::test_support::row_fixture_with_metadata( + "work", + "Guest", + "gateway", + serde_json::json!({}), + ResourceStatus::Ready, + serde_json::json!({ "zone": "work" }), + )) + .await; + facets + .add_row(crate::test_support::row_fixture( + "work", + "Credential", + "control", + serde_json::json!({ "scope": { "executionRef": "Guest/gateway" } }), + ResourceStatus::Ready, + )) + .await; facets.add_committed_provider( ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap(), d2b_contracts_resource::v3::ResourceUid::parse( @@ -2132,7 +2156,7 @@ mod tests { let (mut ctx, effects, manager) = qemu_fixture(); manager.set_children_ready(true); let projection = serde_json::json!({ "phase": "Ready", "runtimeReady": true }); - effects.set_projection(Some(projection.clone())); + effects.set_projection(Some(projection.clone())).await; let mut driver = driver(Arc::clone(&effects)); let outcome = driver.reconcile(&mut ctx).await.expect("reconcile"); @@ -2145,7 +2169,7 @@ mod tests { ], "the qemu child graph is the runtime Volume then the VMM Process", ); - let observation = effects.observations().pop().expect("effect call"); + let observation = effects.observations().await.pop().expect("effect call"); assert_eq!(observation.kind, GuestKind::QemuMedia); assert_eq!(observation.provider_spec, Some(qemu_provider_spec())); assert_eq!( @@ -2285,7 +2309,9 @@ mod tests { #[tokio::test] async fn cloud_hypervisor_guests_commit_no_children_through_the_driver() { let effects = ScriptedEffects::new(); - effects.set_projection(Some(serde_json::json!({ "phase": "Ready" }))); + effects + .set_projection(Some(serde_json::json!({ "phase": "Ready" }))) + .await; let manager = RecordingManager::new(); let mut ctx = context( guest_row( @@ -2299,7 +2325,12 @@ mod tests { driver.reconcile(&mut ctx).await.expect("reconcile"); assert_eq!( - effects.observations().pop().expect("effect call").kind, + effects + .observations() + .await + .pop() + .expect("effect call") + .kind, GuestKind::CloudHypervisor, ); assert!(manager.ensure_order().is_empty()); @@ -2433,7 +2464,7 @@ mod tests { owned_row("Volume", "work-vm-stale", serde_json::json!({})), ResourceStatus::Ready, ); - effects.set_finalize(GuestFinalizeStage::Pending); + effects.set_finalize(GuestFinalizeStage::Pending).await; let mut driver = driver(Arc::clone(&effects)); let failure = driver.delete(&mut ctx).await.expect_err("stage pending"); @@ -2455,12 +2486,12 @@ mod tests { let (mut ctx, effects, manager) = qemu_fixture(); manager.set_children_ready(true); let projection = serde_json::json!({ "phase": "Ready", "runtimeReady": true }); - effects.set_projection(Some(projection.clone())); + effects.set_projection(Some(projection.clone())).await; let mut driver = driver(Arc::clone(&effects)); driver.reconcile(&mut ctx).await.expect("first pass"); assert_eq!(ctx.take_status_projection(), Some(projection.clone())); - effects.set_projection(None); + effects.set_projection(None).await; driver.reconcile(&mut ctx).await.expect("second pass"); assert_eq!(ctx.take_status_projection(), Some(projection.clone())); let status = guest_status(&ctx); diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index 15175616a..95d18724f 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -1438,10 +1438,10 @@ impl GuestEffectsService { ); GuestEffectError::Unavailable })?; - #[allow(clippy::disallowed_methods, reason = "synchronous path")] let published = request .status_sink - .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held + .lock() + .await .clone() .or_else(|| request.status.clone()); let phase = match published.as_ref().and_then(|status| status.get("phase")).and_then(Value::as_str) { @@ -2111,13 +2111,15 @@ mod tests { #[tokio::test] async fn guest_phase_answers_the_live_phase_of_a_held_row() { let facets = ScriptedFacets::new(); - facets.add_row(row_fixture( - "work", - "Guest", - "worker", - json!({ "providerRef": "Provider/runtime-qemu-media" }), - ResourceStatus::Ready, - )); + facets + .add_row(row_fixture( + "work", + "Guest", + "worker", + json!({ "providerRef": "Provider/runtime-qemu-media" }), + ResourceStatus::Ready, + )) + .await; let service = super::GuestEffectsService::new(facets.facet_set()); let payload = guest_phase_payload(); let mut resources = d2b_resource_runtime::context::ServiceResourceContext::fail_closed(); @@ -2170,13 +2172,15 @@ mod tests { #[tokio::test] async fn cloud_hypervisor_reconcile_drives_the_controller_session_facets() { let facets = ScriptedFacets::new(); - facets.add_row(row_fixture( - "work", - "Provider", - "runtime-cloud-hypervisor", - json!({ "config": {} }), - ResourceStatus::Ready, - )); + facets + .add_row(row_fixture( + "work", + "Provider", + "runtime-cloud-hypervisor", + json!({ "config": {} }), + ResourceStatus::Ready, + )) + .await; facets.add_committed_provider( ResourceRef::parse("Provider/runtime-cloud-hypervisor").expect("provider"), ResourceUid::parse("123e4567-e89b-42d3-a456-426614174001").expect("uid"), @@ -2185,14 +2189,14 @@ mod tests { facets.set_session_generation(Some( d2b_contracts_resource::v3::identity::ReconnectGeneration::new(2).expect("generation"), )); - facets.set_cloud_hypervisor_outcome( - crate::facets::GuestCloudHypervisorOutcome::Ready, - ); + facets + .set_cloud_hypervisor_outcome(crate::facets::GuestCloudHypervisorOutcome::Ready) + .await; let service = super::GuestEffectsService::new(facets.facet_set()); let request = cloud_hypervisor_request(); // The controller session's status write is captured into the sink // before the pass, exactly as the driver's effect call observes it. - *request.status_sink.lock() = Some(json!({ "phase": "Ready" })); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + *request.status_sink.lock().await = Some(json!({ "phase": "Ready" })); let outcome = service .reconcile(crate::driver::GuestKind::CloudHypervisor, &request) @@ -2224,13 +2228,15 @@ mod tests { #[tokio::test] async fn cloud_hypervisor_finalize_completes_through_the_controller_session() { let facets = ScriptedFacets::new(); - facets.add_row(row_fixture( - "work", - "Provider", - "runtime-cloud-hypervisor", - json!({ "config": {} }), - ResourceStatus::Ready, - )); + facets + .add_row(row_fixture( + "work", + "Provider", + "runtime-cloud-hypervisor", + json!({ "config": {} }), + ResourceStatus::Ready, + )) + .await; facets.add_committed_provider( ResourceRef::parse("Provider/runtime-cloud-hypervisor").expect("provider"), ResourceUid::parse("123e4567-e89b-42d3-a456-426614174001").expect("uid"), diff --git a/packages/d2b-provider-guest/src/test_support.rs b/packages/d2b-provider-guest/src/test_support.rs index aff169cd7..2a2763b85 100644 --- a/packages/d2b-provider-guest/src/test_support.rs +++ b/packages/d2b-provider-guest/src/test_support.rs @@ -23,6 +23,11 @@ //! The doubles' ordered call recorders are the toolkit's `SharedLog` //! (`d2b_provider_toolkit::testing`), the canonical recorder shape every //! family crate's test-support module shares. +//! +//! Every other recorded field is behind a lock: the async lock +//! (`tokio::sync::Mutex`, awaited) where only async methods touch it, and +//! the blocking lock (`std::sync::Mutex`) with its recorded per-site +//! exception where the facet trait's synchronous accessors read it. use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; @@ -64,11 +69,11 @@ pub struct ScriptedEffects { calls: SharedLog, /// Optional shared order log (the recording manager's), so tests can /// compare the provider stage against the child mutations. - shared: Option>>>, - observations: parking_lot::Mutex>, - phase: parking_lot::Mutex, - projection: parking_lot::Mutex>, - finalize: parking_lot::Mutex, + shared: Option, + observations: tokio::sync::Mutex>, + phase: tokio::sync::Mutex, + projection: tokio::sync::Mutex>, + finalize: tokio::sync::Mutex, } impl ScriptedEffects { @@ -78,17 +83,17 @@ impl ScriptedEffects { Arc::new(Self { calls: SharedLog::new(), shared: None, - observations: parking_lot::Mutex::new(Vec::new()), - phase: parking_lot::Mutex::new(GuestEffectPhase::Ready), - projection: parking_lot::Mutex::new(None), - finalize: parking_lot::Mutex::new(GuestFinalizeStage::Complete), + observations: tokio::sync::Mutex::new(Vec::new()), + phase: tokio::sync::Mutex::new(GuestEffectPhase::Ready), + projection: tokio::sync::Mutex::new(None), + finalize: tokio::sync::Mutex::new(GuestFinalizeStage::Complete), }) } /// Construct a double that appends every recorded call to `log` as well /// as its own call log, so the provider stage can be compared against /// the child mutations of the recording manager that owns the log. - pub fn with_shared_log(log: Arc>>) -> Arc { + pub fn with_shared_log(log: SharedLog) -> Arc { let mut effects = Arc::into_inner(Self::new()).expect("fresh effects"); effects.shared = Some(log); Arc::new(effects) @@ -96,24 +101,24 @@ impl ScriptedEffects { fn record(&self, entry: String) { if let Some(shared) = &self.shared { - shared.lock().push(entry.clone()); + shared.record(entry.clone()); } self.calls.record(entry); } /// Script the phase the next `reconcile` reports. - pub fn set_phase(&self, phase: GuestEffectPhase) { - *self.phase.lock() = phase; + pub async fn set_phase(&self, phase: GuestEffectPhase) { + *self.phase.lock().await = phase; } /// Script the `status.resource` projection the next `reconcile` reports. - pub fn set_projection(&self, projection: Option) { - *self.projection.lock() = projection; + pub async fn set_projection(&self, projection: Option) { + *self.projection.lock().await = projection; } /// Script the finalize stage the next `finalize` reports. - pub fn set_finalize(&self, stage: GuestFinalizeStage) { - *self.finalize.lock() = stage; + pub async fn set_finalize(&self, stage: GuestFinalizeStage) { + *self.finalize.lock().await = stage; } /// The observed call labels in arrival order. @@ -122,8 +127,8 @@ impl ScriptedEffects { } /// The recorded `reconcile` observations in arrival order. - pub fn observations(&self) -> Vec { - self.observations.lock().clone() + pub async fn observations(&self) -> Vec { + self.observations.lock().await.clone() } } @@ -136,7 +141,7 @@ impl GuestDriverEffects for ScriptedEffects { ) -> Result { self.record(format!("reconcile:{}", kind.effect_id())); let children = request.children.owned().await?; - self.observations.lock().push(EffectObservation { // async-gate-allow: test-support recorder lock + self.observations.lock().await.push(EffectObservation { kind, provider_spec: request.provider_spec.clone(), status: request.status.clone(), @@ -152,8 +157,8 @@ impl GuestDriverEffects for ScriptedEffects { .collect(), }); Ok(GuestEffectOutcome { - phase: *self.phase.lock(), // async-gate-allow: test-support recorder lock - resource_projection: self.projection.lock().clone(), // async-gate-allow: test-support recorder lock + phase: *self.phase.lock().await, + resource_projection: self.projection.lock().await.clone(), }) } @@ -163,7 +168,7 @@ impl GuestDriverEffects for ScriptedEffects { _request: &GuestEffectRequest<'_>, ) -> Result { self.record(format!("finalize:{}", kind.effect_id())); - Ok(*self.finalize.lock()) // async-gate-allow: test-support recorder lock + Ok(*self.finalize.lock().await) } } @@ -174,11 +179,11 @@ impl GuestDriverEffects for ScriptedEffects { pub struct ScriptedFacets { zone: ZoneId, controller_generation: ControllerGeneration, - rows: parking_lot::Mutex>, - committed: parking_lot::Mutex>, - session_generation: parking_lot::Mutex>, - cloud_hypervisor_outcome: parking_lot::Mutex, - fail_reads: parking_lot::Mutex, + rows: tokio::sync::Mutex>, + committed: std::sync::Mutex>, + session_generation: std::sync::Mutex>, + cloud_hypervisor_outcome: tokio::sync::Mutex, + fail_reads: std::sync::Mutex, calls: SharedLog, } @@ -190,11 +195,11 @@ impl ScriptedFacets { Arc::new(Self { zone: ZoneId::parse("work").expect("zone"), controller_generation: ControllerGeneration::new(3).expect("generation"), - rows: parking_lot::Mutex::new(HashMap::new()), - committed: parking_lot::Mutex::new(BTreeMap::new()), - session_generation: parking_lot::Mutex::new(None), - cloud_hypervisor_outcome: parking_lot::Mutex::new(GuestCloudHypervisorOutcome::Ready), - fail_reads: parking_lot::Mutex::new(false), + rows: tokio::sync::Mutex::new(HashMap::new()), + committed: std::sync::Mutex::new(BTreeMap::new()), + session_generation: std::sync::Mutex::new(None), + cloud_hypervisor_outcome: tokio::sync::Mutex::new(GuestCloudHypervisorOutcome::Ready), + fail_reads: std::sync::Mutex::new(false), calls: SharedLog::new(), }) } @@ -210,8 +215,8 @@ impl ScriptedFacets { } /// Seed one manager row the effects read. - pub fn add_row(&self, row: ResourceView) { - self.rows.lock().insert(row.key.clone(), row); + pub async fn add_row(&self, row: ResourceView) { + self.rows.lock().await.insert(row.key.clone(), row); } /// Seed one committed Provider identity (KTD7). @@ -221,25 +226,35 @@ impl ScriptedFacets { uid: ResourceUid, generation: ResourceGeneration, ) { - self.committed - .lock() - .insert(provider_ref, (uid, generation)); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + { + self.committed + .lock() + .unwrap() + .insert(provider_ref, (uid, generation)); + } } /// Enroll (or clear) the live controller-session generation. pub fn set_session_generation(&self, generation: Option) { - *self.session_generation.lock() = generation; + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + { + *self.session_generation.lock().unwrap() = generation; + } } /// Script the Cloud Hypervisor reconcile outcome. - pub fn set_cloud_hypervisor_outcome(&self, outcome: GuestCloudHypervisorOutcome) { - *self.cloud_hypervisor_outcome.lock() = outcome; + pub async fn set_cloud_hypervisor_outcome(&self, outcome: GuestCloudHypervisorOutcome) { + *self.cloud_hypervisor_outcome.lock().await = outcome; } /// Script the manager view as unanswerable: every read refuses, the /// same fail-closed surface the effects treat as `Unavailable`. pub fn set_fail_reads(&self, fail: bool) { - *self.fail_reads.lock() = fail; + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + { + *self.fail_reads.lock().unwrap() = fail; + } } /// The observed read labels in arrival order. @@ -252,10 +267,11 @@ impl ScriptedFacets { impl GuestManagerView for ScriptedFacets { async fn row_view(&self, key: &ResourceKey) -> Result, ()> { self.calls.record(format!("row:{key}")); - if *self.fail_reads.lock() { // async-gate-allow: test-support recorder lock + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + if *self.fail_reads.lock().unwrap() { // async-gate-allow: test-support recorder lock return Err(()); } - Ok(self.rows.lock().get(key).cloned()) // async-gate-allow: test-support recorder lock + Ok(self.rows.lock().await.get(key).cloned()) } fn committed_provider_identity( @@ -264,18 +280,22 @@ impl GuestManagerView for ScriptedFacets { ) -> Result, ()> { self.calls .record(format!("committed:{}", provider_ref.to_canonical_string())); - if *self.fail_reads.lock() { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + if *self.fail_reads.lock().unwrap() { return Err(()); } - Ok(self.committed.lock().get(provider_ref).cloned()) + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + Ok(self.committed.lock().unwrap().get(provider_ref).cloned()) } fn controller_session_generation(&self) -> Result, ()> { self.calls.record("session-generation".to_owned()); - if *self.fail_reads.lock() { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + if *self.fail_reads.lock().unwrap() { return Err(()); } - Ok(*self.session_generation.lock()) + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + Ok(*self.session_generation.lock().unwrap()) } } @@ -294,7 +314,7 @@ impl CloudHypervisorGuestRuntime for ScriptedFacets { ) -> Result { self.calls .record(format!("reconcile-ch:{}", guest_ref.to_canonical_string())); - Ok(*self.cloud_hypervisor_outcome.lock()) // async-gate-allow: test-support recorder lock + Ok(*self.cloud_hypervisor_outcome.lock().await) } } diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index 2dd00163f..f4dea943e 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -2478,10 +2478,7 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { // Endpoint drivers' `Ready` is the only publication, and // writing one here as well would be a dual-write. if let Some(sink) = self.status_sink.as_ref() { - #[allow(clippy::disallowed_methods, reason = "synchronous path")] - { - *sink.lock() = Some(desired_status); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - } + *sink.lock().await = Some(desired_status); } else { tracing::debug!( zone = %self.zone.as_str(), diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index b247d5ea0..5d6426471 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index c8448f76d..09fc24831 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index cdcad4818..ad5c5ae60 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index c8448f76d..09fc24831 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 333cf3ec2..f0d0ca295 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 4b58232de..6665fb58d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index 0a2c06cd7..04a6a0b89 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 4b58232de..6665fb58d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 24f7f6382..5a992d736 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index 5616168e7..e20bad39c 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index e6955ce6a..80f6ad823 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index 5616168e7..e20bad39c 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 664051117..88dcf7ebf 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index c8448f76d..09fc24831 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index 14ff57a6c..adc1202e8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index c8448f76d..09fc24831 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index de3987244..5b0c5e97d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1492,7 +1492,6 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "d2bd-runtime", - "parking_lot", "schemars", "serde", "serde_json", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index da970bca0..5bcce1dba 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6611,12 +6611,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-guest@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest@0.0.0-bootstrap#path", "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index 233238cbd..e05733890 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index de3987244..5b0c5e97d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1492,7 +1492,6 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "d2bd-runtime", - "parking_lot", "schemars", "serde", "serde_json", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index 3738aa4fa..a0ffc47d5 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6287,12 +6287,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-guest@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest@0.0.0-bootstrap#path", "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index 233238cbd..e05733890 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 5a98d394c..12ca4723f 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 16b38f73d..b062eab93 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index d965d2f4b..23e7f62ff 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 16b38f73d..b062eab93 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index b12b85a52..adaec41a5 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index c40c80cee..f68be57c9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index edbb4eb1f..7d858b3cc 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index c40c80cee..f68be57c9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 12f9f8854..23b800121 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index a5f02a3fe..b9a0c2f10 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 1d4069e4f..436786c6c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index a5f02a3fe..b9a0c2f10 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index 97a9caddc..b72f361c2 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index 16b38f73d..b062eab93 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 68f9ee328..96fc956e6 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index 16b38f73d..b062eab93 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index de3987244..5b0c5e97d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1492,7 +1492,6 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "d2bd-runtime", - "parking_lot", "schemars", "serde", "serde_json", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index 0544b0d4b..806d76d7c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6649,12 +6649,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-guest@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest@0.0.0-bootstrap#path", "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index 0a750448b..cf9f8c7bd 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index de3987244..5b0c5e97d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1492,7 +1492,6 @@ dependencies = [ "d2b-resource-runtime", "d2b-resource-types", "d2bd-runtime", - "parking_lot", "schemars", "serde", "serde_json", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index 19f356551..467490c7f 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6325,12 +6325,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-guest@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-guest@0.0.0-bootstrap#path", "to": "schemars@0.8.22#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index 0a750448b..cf9f8c7bd 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "29cd3dc9c5817aeb7eafe4a6b5a9b32b2f871994b758215eb9554a480ca375e5", + "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index f823664ce..535200294 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -513,107 +513,37 @@ }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1619, + "line": 1634, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1626, + "line": 1647, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1638, + "line": 1649, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1639, + "line": 1685, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1674, + "line": 1719, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1701, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1707, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1714, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1720, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1727, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1754, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/driver.rs", - "line": 1762, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/effects_service.rs", - "line": 1444, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-guest/src/effects_service.rs", - "line": 2195, + "line": 1734, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 139, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 155, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 156, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 166, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 255, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 258, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-guest/src/test_support.rs", - "line": 297, + "line": 271, "reason": "test-support recorder lock" }, { @@ -1098,17 +1028,12 @@ }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 2483, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2bd/src/resource_runtime.rs", - "line": 7503, + "line": 7500, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/resource_runtime.rs", - "line": 8654, + "line": 8651, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From aee08d1cffb05a7fefe645fa5cee7a47a36e9e17 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:03:43 -0700 Subject: [PATCH 669/726] refactor(d2b-broker): type the storage contract refusal reasons StorageContractError::Refused carried a slug built from literals at each raise site, so a new refusal could misspell the operator-visible reason. Each refusal is now one variant of a closed reason type whose rendered text is unchanged, including the canonicalize failure that still appends its host error detail. --- .../d2b-broker/src/ops/storage_contract.rs | 138 +++++++++++++++--- 1 file changed, 120 insertions(+), 18 deletions(-) diff --git a/packages/d2b-broker/src/ops/storage_contract.rs b/packages/d2b-broker/src/ops/storage_contract.rs index 801a29d42..c350e2481 100644 --- a/packages/d2b-broker/src/ops/storage_contract.rs +++ b/packages/d2b-broker/src/ops/storage_contract.rs @@ -24,11 +24,77 @@ use super::hosts::stable_hash_str; pub enum StorageContractError { UnknownStorage(String), UnknownLock(String), - Refused { subject: String, reason: String }, + Refused { + subject: String, + reason: RefusalReason, + }, Invalid { subject: String, detail: String }, Io { path_hash: String, detail: String }, } +/// The closed refusal-reason set of the broker storage/sync contract. +/// +/// Every refusal this module raises names one variant instead of spelling a +/// slug at the raise site, so a new refusal cannot typo its audit-visible +/// text. The variants are not serialized; [`Display`](std::fmt::Display) +/// renders the slug the operator/audit surface already carries, and the one +/// host-detail failure +/// ([`StoragePathCanonicalizeFailed`](Self::StoragePathCanonicalizeFailed)) +/// renders its fixed slug with the detail appended after a `:`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum RefusalReason { + /// `--apply` on an unexpanded template path the broker would mutate. + StorageCriticalTemplateUnexpanded, + /// `--apply` under `/etc/d2b`, which Nix owns and the broker only checks. + StorageConfigRootIsNixManaged, + /// `--apply` on a storage row whose kind is not a directory. + StorageApplySupportedForDirectoryOnly, + /// A path carrying a `..` component. + StoragePathParentDirRefused, + /// A path outside every broker-owned root. + StoragePathOutsideOwnedRoots, + /// A path whose canonical form escapes its owned root. + StoragePathEscapesOwnedRoot, + /// Canonicalization reached a path component with no leaf name. + StoragePathHasNoLeaf, + /// Canonicalization reached a path component with no parent. + StoragePathHasNoParent, + /// Canonicalizing a path failed for a reason other than `NotFound`; + /// carries the host error detail. + StoragePathCanonicalizeFailed(String), +} + +impl RefusalReason { + /// The fixed refusal slug. `Display` appends the carried detail of + /// [`Self::StoragePathCanonicalizeFailed`]. + pub const fn as_str(&self) -> &'static str { + match self { + Self::StorageCriticalTemplateUnexpanded => "storage-critical-template-unexpanded", + Self::StorageConfigRootIsNixManaged => "storage-config-root-is-nix-managed", + Self::StorageApplySupportedForDirectoryOnly => { + "storage-apply-supported-for-directory-only" + } + Self::StoragePathParentDirRefused => "storage-path-parent-dir-refused", + Self::StoragePathOutsideOwnedRoots => "storage-path-outside-owned-roots", + Self::StoragePathEscapesOwnedRoot => "storage-path-escapes-owned-root", + Self::StoragePathHasNoLeaf => "storage-path-has-no-leaf", + Self::StoragePathHasNoParent => "storage-path-has-no-parent", + Self::StoragePathCanonicalizeFailed(_) => "storage-path-canonicalize-failed", + } + } +} + +impl std::fmt::Display for RefusalReason { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::StoragePathCanonicalizeFailed(detail) => { + write!(f, "{}:{detail}", self.as_str()) + } + fixed => f.write_str(fixed.as_str()), + } + } +} + impl std::fmt::Display for StorageContractError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -59,7 +125,7 @@ pub async fn reconcile_storage_scope( if apply && path.starts_with("/etc/d2b") { return Err(StorageContractError::Refused { subject: storage_ref.as_str().to_owned(), - reason: "storage-critical-template-unexpanded".to_owned(), + reason: RefusalReason::StorageCriticalTemplateUnexpanded, }); } return Ok(ReconcileStorageScopeResponse { @@ -86,7 +152,7 @@ pub async fn reconcile_storage_scope( if apply && apply_is_check_only(&path_buf) { return Err(StorageContractError::Refused { subject: storage_ref.as_str().to_owned(), - reason: "storage-config-root-is-nix-managed".to_owned(), + reason: RefusalReason::StorageConfigRootIsNixManaged, }); } match spec.kind { @@ -139,7 +205,7 @@ pub async fn reconcile_storage_scope( } _ if apply => Err(StorageContractError::Refused { subject: storage_ref.as_str().to_owned(), - reason: "storage-apply-supported-for-directory-only".to_owned(), + reason: RefusalReason::StorageApplySupportedForDirectoryOnly, }), _ => Ok(ReconcileStorageScopeResponse { storage_ref: storage_ref.clone(), @@ -202,7 +268,7 @@ async fn validate_owned_root_against( { return Err(StorageContractError::Refused { subject: subject.to_owned(), - reason: "storage-path-parent-dir-refused".to_owned(), + reason: RefusalReason::StoragePathParentDirRefused, }); } let root = roots @@ -211,14 +277,14 @@ async fn validate_owned_root_against( .find(|root| path.starts_with(root)) .ok_or_else(|| StorageContractError::Refused { subject: subject.to_owned(), - reason: "storage-path-outside-owned-roots".to_owned(), + reason: RefusalReason::StoragePathOutsideOwnedRoots, })?; let canonical_root = canonicalize_existing_or_nearest_ancestor(root, subject).await?; let canonical_target = canonicalize_existing_or_nearest_ancestor(path, subject).await?; if !canonical_target.starts_with(&canonical_root) { return Err(StorageContractError::Refused { subject: subject.to_owned(), - reason: "storage-path-escapes-owned-root".to_owned(), + reason: RefusalReason::StoragePathEscapesOwnedRoot, }); } Ok(()) @@ -244,20 +310,20 @@ async fn canonicalize_existing_or_nearest_ancestor( .file_name() .ok_or_else(|| StorageContractError::Refused { subject: subject.to_owned(), - reason: "storage-path-has-no-leaf".to_owned(), + reason: RefusalReason::StoragePathHasNoLeaf, })?; missing_suffix.push(leaf.to_os_string()); current = current .parent() .ok_or_else(|| StorageContractError::Refused { subject: subject.to_owned(), - reason: "storage-path-has-no-parent".to_owned(), + reason: RefusalReason::StoragePathHasNoParent, })?; } Err(err) => { return Err(StorageContractError::Refused { subject: subject.to_owned(), - reason: format!("storage-path-canonicalize-failed:{err}"), + reason: RefusalReason::StoragePathCanonicalizeFailed(err.to_string()), }); } } @@ -380,15 +446,15 @@ mod tests { assert!(validate_owned_root(Path::new("/run/d2b"), "x").await.is_ok()); assert_refused_reason( validate_owned_root(Path::new("/var/lib/d2b/../../etc/malicious"), "x").await, - "storage-path-parent-dir-refused", + RefusalReason::StoragePathParentDirRefused, ); assert_refused_reason( validate_owned_root(Path::new("/var/lib/d2b/../d2b-escape"), "x").await, - "storage-path-parent-dir-refused", + RefusalReason::StoragePathParentDirRefused, ); assert_refused_reason( validate_owned_root(Path::new("/home/not-d2b"), "x").await, - "storage-path-outside-owned-roots", + RefusalReason::StoragePathOutsideOwnedRoots, ); } @@ -403,7 +469,7 @@ mod tests { std::os::unix::fs::symlink("/etc", root.join("escape")).unwrap(); assert_refused_reason( validate_owned_root_against(&root.join("escape/passwd"), "x", &[&root]).await, - "storage-path-escapes-owned-root", + RefusalReason::StoragePathEscapesOwnedRoot, ); } } @@ -428,7 +494,10 @@ mod tests { let err = reconcile_storage_scope(&resolver, &BundleOpId::new("path:regular-file"), true) .await .expect_err("regular files are check-only in broker reconcile"); - assert_refused_reason(Err(err), "storage-apply-supported-for-directory-only"); + assert_refused_reason( + Err(err), + RefusalReason::StorageApplySupportedForDirectoryOnly, + ); } #[tokio::test] @@ -462,7 +531,7 @@ mod tests { let err = reconcile_storage_scope(&resolver, &BundleOpId::new("path:config-root"), true) .await .expect_err("nix-managed config roots are not broker-mutated"); - assert_refused_reason(Err(err), "storage-config-root-is-nix-managed"); + assert_refused_reason(Err(err), RefusalReason::StorageConfigRootIsNixManaged); } #[tokio::test] @@ -521,16 +590,49 @@ mod tests { fn assert_refused_reason( result: Result<(), StorageContractError>, - expected_reason: &'static str, + expected_reason: RefusalReason, ) { match result { Err(StorageContractError::Refused { reason, .. }) => { assert_eq!(reason, expected_reason); } - other => panic!("expected refused reason {expected_reason}, got {other:?}"), + other => panic!("expected refused reason {expected_reason:?}, got {other:?}"), } } + /// The refusal text is operator/audit-visible: the dispatch caller + /// forwards `StorageContractError::to_string()` into the operation + /// record. The enum must therefore reproduce every pre-enum slug, with + /// the canonicalize failure still appending its host detail. + #[test] + fn refused_display_keeps_the_wire_text() { + let fixed = StorageContractError::Refused { + subject: "path:run-root".to_owned(), + reason: RefusalReason::StoragePathParentDirRefused, + }; + assert_eq!( + fixed.to_string(), + "path:run-root: refused: storage-path-parent-dir-refused" + ); + assert_eq!( + RefusalReason::StoragePathParentDirRefused.as_str(), + "storage-path-parent-dir-refused" + ); + + let detailed = StorageContractError::Refused { + subject: "path:run-root".to_owned(), + reason: RefusalReason::StoragePathCanonicalizeFailed("EACCES".to_owned()), + }; + assert_eq!( + detailed.to_string(), + "path:run-root: refused: storage-path-canonicalize-failed:EACCES" + ); + assert_eq!( + RefusalReason::StoragePathCanonicalizeFailed(String::new()).as_str(), + "storage-path-canonicalize-failed" + ); + } + struct ScratchDir(PathBuf); impl ScratchDir { From 5c95bf879f0b9c193914542f58fbc83130a68c24 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:03:44 -0700 Subject: [PATCH 670/726] refactor(d2b-core): resolve the NetworkManager reload contract to a type reloadBehavior was a raw string re-validated at the apply and remove call sites. It now resolves to a closed enum when the host artifact is parsed and when the broker kernel payload is decoded, so a hand-declared typo fails at resolution instead of reaching a mutation. The wire value is unchanged and the empty no-host-contract sentinel still round-trips. --- .../w7-01-broker-storage-and-reload-types.md | 16 +++++ docs/reference/schemas/v2/host.json | 21 ++++++- packages/d2b-broker/src/kernel_ops.rs | 2 +- packages/d2b-broker/src/live_handlers.rs | 62 ++----------------- packages/d2b-broker/src/ops/nm.rs | 45 +++++++------- packages/d2b-broker/src/ops/tap.rs | 6 +- packages/d2b-broker/src/runtime.rs | 8 +-- .../d2b-core/fuzz/corpus/host/00-valid.json | 2 +- packages/d2b-core/fuzz/src/bin/core.rs | 35 ++++++++++- packages/d2b-core/src/bundle_resolver.rs | 26 +++++--- packages/d2b-core/src/host.rs | 61 +++++++++++++++++- tests/fixtures/deny-unknown/host-valid.json | 2 +- 12 files changed, 179 insertions(+), 107 deletions(-) create mode 100644 changelog.d/w7-01-broker-storage-and-reload-types.md diff --git a/changelog.d/w7-01-broker-storage-and-reload-types.md b/changelog.d/w7-01-broker-storage-and-reload-types.md new file mode 100644 index 000000000..dd364bddd --- /dev/null +++ b/changelog.d/w7-01-broker-storage-and-reload-types.md @@ -0,0 +1,16 @@ +### Changed + +- Broker storage/sync contract refusals carry a closed reason type: + every refusal reason is one variant of that type instead of a slug + spelled at the raise site, so a new refusal cannot misspell what the + operator and the audit record see. The rendered text is unchanged, + including the canonicalize failure that still appends its host error + detail. + +- The NetworkManager unmanaged reload behavior is a parsed contract + value rather than a string re-checked at each call site. + `reloadBehavior` resolves to the closed set `atomic-reload`, `none`, + and the empty no-host-contract sentinel when the host artifact and the + broker kernel payload are read, so a hand-declared typo fails at + resolution instead of reaching the apply and remove paths. The wire + value and its empty sentinel round-trip unchanged. diff --git a/docs/reference/schemas/v2/host.json b/docs/reference/schemas/v2/host.json index cf772bb47..3ce0499ae 100644 --- a/docs/reference/schemas/v2/host.json +++ b/docs/reference/schemas/v2/host.json @@ -882,7 +882,7 @@ "$ref": "#/definitions/OwnershipRule" }, "reloadBehavior": { - "type": "string" + "$ref": "#/definitions/NmReloadBehavior" } }, "additionalProperties": false @@ -958,6 +958,25 @@ }, "additionalProperties": false }, + "NmReloadBehavior": { + "description": "The closed reload contract a NetworkManager unmanaged drop-in declares.\n\n`atomic-reload` reloads NetworkManager after the drop-in write, `none` writes it without reloading, and `unspecified` is the empty-string sentinel a bundle that declares no host contract carries. Every other wire value is a hand-declared bundle defect that fails when the artifact is resolved, so a typo can no longer silently skip the reload while the apply acks success.", + "oneOf": [ + { + "type": "string", + "enum": [ + "atomic-reload", + "none" + ] + }, + { + "description": "The empty-string sentinel; a real wire value that round-trips.", + "type": "string", + "enum": [ + "" + ] + } + ] + }, "OwnershipRule": { "description": "File ownership policy for host materialized files.", "type": "object", diff --git a/packages/d2b-broker/src/kernel_ops.rs b/packages/d2b-broker/src/kernel_ops.rs index b5358531e..5f4df7ca3 100644 --- a/packages/d2b-broker/src/kernel_ops.rs +++ b/packages/d2b-broker/src/kernel_ops.rs @@ -1162,7 +1162,7 @@ async fn apply_nm_unmanaged( mode: field_i64(invocation.payload, "mode")? as u32, owner: field_str(invocation.payload, "owner")?.to_owned(), group: field_str(invocation.payload, "group")?.to_owned(), - reload_behavior: field_str(invocation.payload, "reloadBehavior")?.to_owned(), + reload_behavior: parse_field(invocation.payload, "reloadBehavior")?, }; let exec = crate::ops::exec_reconcile::SystemReconcileExecutor; if destroy { diff --git a/packages/d2b-broker/src/live_handlers.rs b/packages/d2b-broker/src/live_handlers.rs index 891b819ba..6a607bafe 100644 --- a/packages/d2b-broker/src/live_handlers.rs +++ b/packages/d2b-broker/src/live_handlers.rs @@ -37,6 +37,7 @@ use crate::ops::spawn_runner::{ }; use d2b_contracts_resource::v3::{ActivationRunnerInput, MAX_ACTIVATION_RUNNER_INPUT_BYTES}; use d2b_core::bundle_resolver::HostRuntime; +use d2b_core::host::NmReloadBehavior; use d2b_core::sandbox_profile::CgroupPlacement; use rustix::fs::{CWD, Mode, OFlags, ResolveFlags}; @@ -87,10 +88,6 @@ pub enum LiveHandlerError { /// NetworkManager reload failure after writing the unmanaged config /// snippet. NmReload(String), - /// The NetworkManager unmanaged intent declared a reload behavior the - /// contract does not admit. Carries the rejected value so the refusal - /// names exactly what a hand-declared bundle got wrong. - NmReloadBehaviorRefused(String), /// The declared owner/group of the NetworkManager unmanaged file could /// not be resolved or enforced. Carries the failing principal or the /// enforcement detail. @@ -135,10 +132,6 @@ impl std::fmt::Display for LiveHandlerError { Self::KeysRotate(detail) => write!(f, "keys rotate: {detail}"), Self::HostKey(detail) => write!(f, "host key: {detail}"), Self::NmReload(detail) => write!(f, "networkmanager reload: {detail}"), - Self::NmReloadBehaviorRefused(value) => write!( - f, - "NetworkManager reload behavior {value:?} is not supported; expected \"atomic-reload\" or \"none\"" - ), Self::NmFileOwnership(detail) => { write!(f, "NetworkManager unmanaged file ownership: {detail}") } @@ -279,24 +272,6 @@ impl NmReloadMethod { } } -/// The closed reload-behavior set the NetworkManager unmanaged contract -/// admits. `"atomic-reload"` selects the reload branch; `"none"` and the -/// empty no-host-contract sentinel select the write-only path. Any other -/// value is a hand-declared bundle defect: refusing it here (before any -/// mutation) keeps a typo from silently skipping the NetworkManager reload -/// while the apply acks success. -/// -/// Shared with the remove path in `ops/nm.rs`; both arms branch on the -/// same value, so both must apply the same contract check. -pub(crate) fn validate_nm_reload_behavior( - reload_behavior: &str, -) -> Result<(), LiveHandlerError> { - if matches!(reload_behavior, "atomic-reload" | "none" | "") { - return Ok(()); - } - Err(LiveHandlerError::NmReloadBehaviorRefused(reload_behavior.to_owned())) -} - /// Resolve the declared owner/group names of the NetworkManager unmanaged /// drop-in to uid/gid. The declaration is part of the bundle contract and /// is enforced on the written file; an unresolvable principal refuses the @@ -359,7 +334,6 @@ pub(crate) async fn live_apply_nm_unmanaged_with_reload( where F: AsyncFnMut(&[&str]) -> Result<(), String>, { - validate_nm_reload_behavior(&intent.reload_behavior)?; let existing = match crate::sys::path_safe::read_to_string_nofollow(&intent.file_path) { Ok(contents) => contents, Err(error) if error.kind() == io::ErrorKind::NotFound => String::new(), @@ -378,7 +352,7 @@ where ) .await .map_err(LiveHandlerError::ReconcileExec)?; - if intent.reload_behavior == "atomic-reload" { + if matches!(intent.reload_behavior, NmReloadBehavior::AtomicReload) { reload(&["reload", "NetworkManager"]) .await .map_err(LiveHandlerError::NmReload)?; @@ -401,7 +375,6 @@ where D: AsyncFnMut() -> Result<(), String>, F: AsyncFnMut(&[&str]) -> Result<(), String>, { - validate_nm_reload_behavior(&intent.reload_behavior)?; let existing = match crate::sys::path_safe::read_to_string_nofollow(&intent.file_path) { Ok(contents) => contents, Err(error) if error.kind() == io::ErrorKind::NotFound => String::new(), @@ -420,7 +393,7 @@ where ) .await .map_err(LiveHandlerError::ReconcileExec)?; - if intent.reload_behavior != "atomic-reload" { + if !matches!(intent.reload_behavior, NmReloadBehavior::AtomicReload) { return Ok(None); } match dbus_reload().await { @@ -3291,7 +3264,7 @@ mod tests { mode: 0o644, owner: "root".to_owned(), group: "root".to_owned(), - reload_behavior: "atomic-reload".to_owned(), + reload_behavior: NmReloadBehavior::AtomicReload, } } @@ -4009,33 +3982,6 @@ mod tests { assert!(exec.take_log().is_empty()); } - #[tokio::test] - #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - async fn live_apply_nm_unmanaged_refuses_unknown_reload_behavior_before_mutation() { - let exec = FakeReconcileExecutor::new(); - let root = TestDir::new("nm-unmanaged-reload-refused"); - let mut intent = sample_nm_unmanaged_intent(&root); - intent.reload_behavior = "atomic-reloadd".to_owned(); - - let err = live_apply_nm_unmanaged_with_reloaders( - &exec, - &intent, - async || Ok(()), - async |_| Ok(()), - ) - .await - .expect_err("a typo'd reload behavior must refuse the apply"); - - assert!(matches!( - &err, - LiveHandlerError::NmReloadBehaviorRefused(value) if value == "atomic-reloadd" - )); - assert!( - exec.take_log().is_empty(), - "the reload-behavior refusal must precede any file mutation" - ); - } - #[tokio::test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn live_apply_nm_unmanaged_refuses_unresolvable_declared_owner() { diff --git a/packages/d2b-broker/src/ops/nm.rs b/packages/d2b-broker/src/ops/nm.rs index 0d6f8ba26..5591629e7 100644 --- a/packages/d2b-broker/src/ops/nm.rs +++ b/packages/d2b-broker/src/ops/nm.rs @@ -15,6 +15,7 @@ use crate::ops::exec_reconcile::ReconcileExecutor; use crate::sys::path_safe; use d2b_core::bundle_resolver::ResolvedNmUnmanagedIntent; +use d2b_core::host::NmReloadBehavior; use d2b_core::host_w3::NmUnmanagedEntry; use std::io; use std::path::{Path, PathBuf}; @@ -291,10 +292,10 @@ fn rollback(path: &Path, prior: Option<&str>) -> io::Result<()> { /// Runtime entry-point for `ApplyNmUnmanaged`:apply an intent through the /// live executor path. /// -/// The intent's declared reload behavior is verified before any mutation -/// (`atomic-reload`, `none`, and the empty sentinel are the only accepted -/// spellings), and NetworkManager is reloaded after a successful write -/// when the behavior calls for it. +/// The intent's reload behavior is already resolved to the closed +/// [`NmReloadBehavior`] set by the time it reaches here, so NetworkManager +/// is reloaded after a successful write exactly when the intent declares +/// `atomic-reload`. pub async fn apply_with_reload( executor: &dyn ReconcileExecutor, intent: &ResolvedNmUnmanagedIntent, @@ -302,9 +303,8 @@ pub async fn apply_with_reload( crate::live_handlers::live_apply_nm_unmanaged(executor, intent).await } -/// Remove one NetworkManager unmanaged drop-in the intent names, verifying -/// the same reload-behavior contract before mutation and running the -/// `systemctl` reload when the behavior calls for it. +/// Remove one NetworkManager unmanaged drop-in the intent names and run the +/// `systemctl` reload when the resolved behavior calls for it. pub async fn remove_with_reload( intent: &ResolvedNmUnmanagedIntent, ) -> Result<(), crate::live_handlers::LiveHandlerError> { @@ -330,7 +330,6 @@ async fn remove_with_reload_using( where F: for<'a> FnMut(&'a [&'a str]) -> Pin> + Send + 'a>>, { - crate::live_handlers::validate_nm_reload_behavior(&intent.reload_behavior)?; path_safe::refuse_world_writable_parent(&intent.file_path) .map_err(|err| io_to_live_handler(&intent.file_path, err))?; path_safe::refuse_symlink(&intent.file_path) @@ -347,7 +346,7 @@ where Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()), Err(err) => return Err(io_to_live_handler(&intent.file_path, err)), } - if intent.reload_behavior == "atomic-reload" + if matches!(intent.reload_behavior, NmReloadBehavior::AtomicReload) && let Err(err) = reload(&["reload", "NetworkManager"]).await { let _ = rollback(&intent.file_path, prior.as_deref()); @@ -534,7 +533,7 @@ mod tests { mode: 0o644, owner: "root".to_owned(), group: "root".to_owned(), - reload_behavior: "atomic-reload".to_owned(), + reload_behavior: NmReloadBehavior::AtomicReload, }; apply_with_reload_using(&exec, &intent, { @@ -574,12 +573,12 @@ mod tests { #[tokio::test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] - async fn remove_with_reload_refuses_unknown_reload_behavior_before_mutation() { + async fn remove_with_reload_removes_without_reloading_for_the_unspecified_behavior() { let dir = std::env::current_dir() .unwrap() .join("target") .join(format!( - "nm-remove-refused-{}-{}", + "nm-remove-unspecified-{}-{}", std::process::id(), std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -588,19 +587,25 @@ mod tests { )); tokio::fs::create_dir_all(&dir).await.unwrap(); let path = dir.join("00-d2b-unmanaged.conf"); + let d2b_link = derive_from_env_vm("e", None, DerivedRole::Bridge, None).unwrap(); + let prior = render_nm_conf(&[NmUnmanagedEntry { + if_name: d2b_link, + marker_id: "m1".into(), + }]); + tokio::fs::write(&path, &prior).await.unwrap(); let intent = ResolvedNmUnmanagedIntent { intent_id: "nm-unmanaged:host".to_owned(), file_path: path.clone(), - contents: String::new(), + contents: prior, mode: 0o644, owner: "root".to_owned(), group: "root".to_owned(), - reload_behavior: "atomic-reloadd".to_owned(), + reload_behavior: NmReloadBehavior::Unspecified, }; let reloaded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); let reload_flag = std::sync::Arc::clone(&reloaded); - let err = remove_with_reload_using(&intent, move |_| { + remove_with_reload_using(&intent, move |_| { let reload_flag = std::sync::Arc::clone(&reload_flag); Box::pin(async move { reload_flag.store(true, std::sync::atomic::Ordering::Relaxed); @@ -608,17 +613,13 @@ mod tests { }) }) .await - .expect_err("a typo'd reload behavior must refuse the removal"); + .expect("the empty no-host-contract sentinel still removes the drop-in"); - assert!(matches!( - &err, - crate::live_handlers::LiveHandlerError::NmReloadBehaviorRefused(value) - if value == "atomic-reloadd" - )); assert!( !reloaded.load(std::sync::atomic::Ordering::Relaxed), - "the refusal must precede any mutation" + "only the atomic-reload behavior reloads NetworkManager" ); + assert!(!path.exists(), "the drop-in is still removed"); tokio::fs::remove_dir_all(&dir).await.ok(); } } diff --git a/packages/d2b-broker/src/ops/tap.rs b/packages/d2b-broker/src/ops/tap.rs index 34f7f676e..c0282713d 100644 --- a/packages/d2b-broker/src/ops/tap.rs +++ b/packages/d2b-broker/src/ops/tap.rs @@ -1247,8 +1247,8 @@ mod tests { use d2b_core::bundle::{Bundle, BundleGeneration}; use d2b_core::host::{ BridgePortFlags as HostBridgePortFlags, HostJson as BundleHostJson, IfNameMapping, - LanPolicy, NetEnv, NftablesModel, SitePolicy, TapRole, UsbipBusidLock, UsbipLockOwner, - UsbipLockScope, + LanPolicy, NetEnv, NmReloadBehavior, NftablesModel, SitePolicy, TapRole, UsbipBusidLock, + UsbipLockOwner, UsbipLockScope, }; use d2b_core::manifest_v04::ManifestV04; use d2b_core::processes::ProcessesJson; @@ -1379,7 +1379,7 @@ mod tests { mode: "0644".to_owned(), drift_policy: "replace".to_owned(), }, - reload_behavior: "reload".to_owned(), + reload_behavior: NmReloadBehavior::AtomicReload, }, hosts_file: d2b_core::host::HostsFileOwnership { start_marker: "# d2b-managed begin".to_owned(), diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 9bad34dc7..a0e894bee 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -12782,9 +12782,9 @@ mod tests { use d2b_core::host::{ BridgePortFlags, ChNetHandoffMode, CloudHypervisorCapability, FdOwnershipEntry, HostChConfig, HostJson, HostsFileOwnership, IfNameMapping, Ipv6SysctlEntry, - KernelModulesEntry, LanPolicy, NetEnv, NetworkManagerUnmanaged, NftChain, - NftablesModel, OwnershipRule, SitePolicy, TapRole, UsbipBusidLock, UsbipLockOwner, - UsbipLockScope, VendorProductPair, + KernelModulesEntry, LanPolicy, NetEnv, NmReloadBehavior, NetworkManagerUnmanaged, + NftChain, NftablesModel, OwnershipRule, SitePolicy, TapRole, UsbipBusidLock, + UsbipLockOwner, UsbipLockScope, VendorProductPair, }; use d2b_core::manifest_v04::{ ManifestMeta, ManifestV04, ObservabilityMeta, VmEntry, VmLanPolicy, VmObservability, @@ -12875,7 +12875,7 @@ mod tests { network_manager: NetworkManagerUnmanaged { file_path: "/etc/NetworkManager/conf.d/00-d2b-unmanaged.conf".to_owned(), match_criteria: vec!["interface-name:d2b-*".to_owned()], - reload_behavior: "atomic-reload".to_owned(), + reload_behavior: NmReloadBehavior::AtomicReload, ownership: OwnershipRule { owner: "root".to_owned(), group: "root".to_owned(), diff --git a/packages/d2b-core/fuzz/corpus/host/00-valid.json b/packages/d2b-core/fuzz/corpus/host/00-valid.json index 50ba596ee..692e8d58d 100644 --- a/packages/d2b-core/fuzz/corpus/host/00-valid.json +++ b/packages/d2b-core/fuzz/corpus/host/00-valid.json @@ -1 +1 @@ -{"schemaVersion":"v1","site":{"allowUnsafeEastWest":false},"environments":[{"env":"work","bridge":"br-work-lan","mtu":1500,"mssClamp":null,"lan":{"allowEastWest":false,"effectiveEastWest":false},"netVmForwardBlocklist":[],"bridgePortFlags":[{"role":"workload-lan","isolated":true,"neighSuppress":false,"rule":"default"}],"ipv6Sysctls":[{"ifName":"br-work-lan","disableIpv6":1,"acceptRa":0,"autoconf":0,"addrGenMode":1}],"usbipBusidLocks":[]}],"nftables":{"family":"inet","table":"d2b","chains":[]},"networkManager":{"filePath":"/etc/NetworkManager/conf.d/d2b.conf","matchCriteria":[],"reloadBehavior":"reload","ownership":{"owner":"root","group":"root","mode":"0644","driftPolicy":"replace"}},"hostsFile":{"startMarker":"# BEGIN D2B","endMarker":"# END D2B","rule":"replace"},"kernelModules":[],"fdOwnership":[],"cloudHypervisorCapabilities":[]} +{"schemaVersion":"v1","site":{"allowUnsafeEastWest":false},"environments":[{"env":"work","bridge":"br-work-lan","mtu":1500,"mssClamp":null,"lan":{"allowEastWest":false,"effectiveEastWest":false},"netVmForwardBlocklist":[],"bridgePortFlags":[{"role":"workload-lan","isolated":true,"neighSuppress":false,"rule":"default"}],"ipv6Sysctls":[{"ifName":"br-work-lan","disableIpv6":1,"acceptRa":0,"autoconf":0,"addrGenMode":1}],"usbipBusidLocks":[]}],"nftables":{"family":"inet","table":"d2b","chains":[]},"networkManager":{"filePath":"/etc/NetworkManager/conf.d/d2b.conf","matchCriteria":[],"reloadBehavior":"atomic-reload","ownership":{"owner":"root","group":"root","mode":"0644","driftPolicy":"replace"}},"hostsFile":{"startMarker":"# BEGIN D2B","endMarker":"# END D2B","rule":"replace"},"kernelModules":[],"fdOwnership":[],"cloudHypervisorCapabilities":[]} diff --git a/packages/d2b-core/fuzz/src/bin/core.rs b/packages/d2b-core/fuzz/src/bin/core.rs index 8c647060d..3a54047f5 100644 --- a/packages/d2b-core/fuzz/src/bin/core.rs +++ b/packages/d2b-core/fuzz/src/bin/core.rs @@ -15,8 +15,8 @@ use d2b_core::{ }, host::{ BridgePortFlags, HostJson, HostsFileOwnership, Ipv6SysctlEntry, LanPolicy, NetEnv, - NetworkManagerUnmanaged, NftChain, NftablesModel, OwnershipRule, SitePolicy, TapRole, - UsbipBusidLock, UsbipLockOwner, UsbipLockScope, + NmReloadBehavior, NetworkManagerUnmanaged, NftChain, NftablesModel, OwnershipRule, + SitePolicy, TapRole, UsbipBusidLock, UsbipLockOwner, UsbipLockScope, }, manifest_v04::ManifestV04, sandbox_profile::CgroupPlacement, @@ -46,6 +46,10 @@ fn main() { "host_json_denies_unknown_fields", host_json_denies_unknown_fields, ), + ( + "nm_reload_behavior_wire_values_are_closed", + nm_reload_behavior_wire_values_are_closed, + ), ( "usbip_busid_lock_round_trips_bus_ids", usbip_busid_lock_round_trips_bus_ids, @@ -138,6 +142,31 @@ fn host_json_denies_unknown_fields() { assert!(err.to_string().contains("unknown field")); } +fn nm_reload_behavior_wire_values_are_closed() { + for (wire, behavior) in [ + ("atomic-reload", NmReloadBehavior::AtomicReload), + ("none", NmReloadBehavior::None), + ("", NmReloadBehavior::Unspecified), + ] { + let rendered = serde_json::to_string(&behavior).expect("serialize reload behavior"); + assert_eq!(rendered, format!("{wire:?}")); + let parsed: NmReloadBehavior = + serde_json::from_str(&rendered).expect("parse reload behavior"); + assert_eq!(parsed, behavior); + } + + let declared = |reload_behavior: &str| { + format!( + r##"{{"filePath":"/etc/NetworkManager/conf.d/00-d2b.conf","matchCriteria":[],"reloadBehavior":{reload_behavior:?},"ownership":{{"owner":"root","group":"root","mode":"0644","driftPolicy":"replace"}}}}"## + ) + }; + serde_json::from_str::(&declared("atomic-reload")) + .expect("a declared reload behavior resolves"); + let err = serde_json::from_str::(&declared("atomic-reloadd")) + .expect_err("a hand-declared reload behavior typo must fail at resolution"); + assert!(err.to_string().contains("unknown variant"), "{err}"); +} + fn usbip_busid_lock_round_trips_bus_ids() { let lock: UsbipBusidLock = serde_json::from_str( r#"{"vm":"work-vm","lockOwner":"daemon","scope":"per-busid","busIds":["1-1.4","2-3"]}"#, @@ -339,7 +368,7 @@ fn build_synthetic_resolver() -> BundleResolver { network_manager: NetworkManagerUnmanaged { file_path: "/etc/NetworkManager/conf.d/00-d2b.conf".to_owned(), match_criteria: vec!["interface-name:d2b-*".to_owned()], - reload_behavior: "atomic-reload".to_owned(), + reload_behavior: NmReloadBehavior::AtomicReload, ownership: OwnershipRule { owner: "root".to_owned(), group: "root".to_owned(), diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 47c61bfc0..1eb20ee50 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -67,7 +67,7 @@ use crate::allocator_config::AllocatorZoneTopology; use crate::bundle::{Bundle, BundleGeneration}; use d2b_contracts::error::Error; use crate::host::{ - ChNetHandoffMode, HostJson, HostsFileOwnership, ModuleRequirement, NetEnv, + ChNetHandoffMode, HostJson, HostsFileOwnership, ModuleRequirement, NetEnv, NmReloadBehavior, NetworkManagerUnmanaged, NftablesModel, OwnershipRule, QemuMediaSourceIntent, SitePolicy, UsbipBusidLock, VendorProductPair, }; @@ -337,7 +337,7 @@ pub struct ResolvedNmUnmanagedIntent { pub mode: u32, pub owner: String, pub group: String, - pub reload_behavior: String, + pub reload_behavior: NmReloadBehavior, } /// Resolved per-busid USBIP firewall rule body. @@ -1200,7 +1200,7 @@ fn empty_zone_native_host() -> HostJson { network_manager: NetworkManagerUnmanaged { file_path: String::new(), match_criteria: Vec::new(), - reload_behavior: String::new(), + reload_behavior: NmReloadBehavior::Unspecified, ownership: OwnershipRule { owner: String::new(), group: String::new(), @@ -4256,7 +4256,7 @@ fn build_nm_unmanaged_intents(host: &HostJson) -> BTreeMap, - pub reload_behavior: String, + pub reload_behavior: NmReloadBehavior, pub ownership: OwnershipRule, } +/// The closed reload contract a NetworkManager unmanaged drop-in declares. +/// +/// `atomic-reload` reloads NetworkManager after the drop-in write, `none` +/// writes it without reloading, and `unspecified` is the empty-string +/// sentinel a bundle that declares no host contract carries. Every other +/// wire value is a hand-declared bundle defect that fails when the artifact +/// is resolved, so a typo can no longer silently skip the reload while the +/// apply acks success. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum NmReloadBehavior { + AtomicReload, + None, + /// The empty-string sentinel; a real wire value that round-trips. + #[serde(rename = "")] + Unspecified, +} + /// File ownership policy for host materialized files. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -538,8 +556,8 @@ pub enum CapabilityStatus { #[cfg(test)] mod tests { use super::{ - BridgePortFlags, HostJson, IfName, Ipv6SysctlEntry, TapRole, UsbipBusidLock, - UsbipLockOwner, UsbipLockScope, VendorProductPair, + BridgePortFlags, HostJson, IfName, Ipv6SysctlEntry, NmReloadBehavior, TapRole, + UsbipBusidLock, UsbipLockOwner, UsbipLockScope, VendorProductPair, }; use d2b_contracts_resource::v3::IfNameError; @@ -632,4 +650,41 @@ mod tests { assert_eq!(parsed, lock); } + + /// The reload contract's wire vocabulary is closed and every value + /// round-trips, including the empty no-host-contract sentinel. + #[test] + fn nm_reload_behavior_round_trips_its_wire_values() { + for (wire, behavior) in [ + ("atomic-reload", NmReloadBehavior::AtomicReload), + ("none", NmReloadBehavior::None), + ("", NmReloadBehavior::Unspecified), + ] { + let rendered = serde_json::to_string(&behavior).expect("serialize reload behavior"); + assert_eq!(rendered, format!("{wire:?}")); + let parsed: NmReloadBehavior = + serde_json::from_str(&rendered).expect("parse reload behavior"); + assert_eq!(parsed, behavior); + } + } + + /// A hand-declared reload-behavior typo fails where the host artifact is + /// resolved, never as a string that the apply/remove paths must re-check. + #[test] + fn host_json_refuses_unknown_nm_reload_behavior() { + let host = |reload_behavior: &str| { + format!( + r##"{{"schemaVersion":"v2","site":{{"allowUnsafeEastWest":false}},"environments":[],"nftables":{{"family":"inet","table":"d2b","chains":[]}},"networkManager":{{"filePath":"/etc/NetworkManager/conf.d/00-d2b.conf","matchCriteria":[],"reloadBehavior":{reload_behavior:?},"ownership":{{"owner":"root","group":"root","mode":"0644","driftPolicy":"replace"}}}},"hostsFile":{{"startMarker":"# begin","endMarker":"# end","rule":"test"}},"kernelModules":[],"fdOwnership":[],"cloudHypervisorCapabilities":[]}}"## + ) + }; + + for declared in ["atomic-reload", "none", ""] { + serde_json::from_str::(&host(declared)) + .unwrap_or_else(|err| panic!("{declared:?} is a declared value: {err}")); + } + + let err = serde_json::from_str::(&host("atomic-reloadd")) + .expect_err("a hand-declared reload behavior typo must fail at resolution"); + assert!(err.to_string().contains("unknown variant"), "{err}"); + } } diff --git a/tests/fixtures/deny-unknown/host-valid.json b/tests/fixtures/deny-unknown/host-valid.json index 8fae27d3c..849b5e390 100644 --- a/tests/fixtures/deny-unknown/host-valid.json +++ b/tests/fixtures/deny-unknown/host-valid.json @@ -92,7 +92,7 @@ "mode": "0644", "owner": "root" }, - "reloadBehavior": "nmcli general reload" + "reloadBehavior": "atomic-reload" }, "nftables": { "chains": [ From 4fdf13b348f6f026d35357b6a7f02f4da715db3a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:13:39 -0700 Subject: [PATCH 671/726] d2b: emit the mutation-flag envelope for the host mutation verbs `d2b host prepare` and `host destroy` without `--dry-run`/`--apply` exited 2 with a `ref-invalid` zone envelope, and `host reconcile` exited 78 under that same wrong code, while docs/reference/error-codes.md documents `--apply-or-dry-run-required` at exit 78 for these verbs. All three now route through the helper `host validate` already used, so the envelope kind names the offending verb. The `--network` requirement on `host reconcile` keeps its own `ref-invalid` refusal, and the integration test pins both shapes through the real binary. --- packages/d2b/src/host.rs | 18 +++------ packages/d2b/tests/host_validate_verb.rs | 50 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/packages/d2b/src/host.rs b/packages/d2b/src/host.rs index 30d740229..53a717dbb 100644 --- a/packages/d2b/src/host.rs +++ b/packages/d2b/src/host.rs @@ -272,12 +272,8 @@ fn mutation( deadline: RequestDeadline, ) -> Result { if !args.dry_run && !args.apply { - return Err(context.failure( - "ref-invalid", - "host mutation requires --dry-run or --apply", - mode, - 2, - )); + let verb = format!("host {operation}"); + return emit_host_error(&missing_mutation_flag_envelope(&verb), mode.is_json()); } let value = context.invoke( "Reconcile", @@ -301,12 +297,10 @@ fn reconcile( deadline: RequestDeadline, ) -> Result { if !args.dry_run && !args.apply { - return Err(context.failure( - "ref-invalid", - "host reconcile requires --dry-run or --apply", - mode, - 78, - )); + return emit_host_error( + &missing_mutation_flag_envelope("host reconcile"), + mode.is_json(), + ); } if !args.network { return Err(context.failure("ref-invalid", "host reconcile requires --network", mode, 78)); diff --git a/packages/d2b/tests/host_validate_verb.rs b/packages/d2b/tests/host_validate_verb.rs index ad110da50..0659b36bd 100644 --- a/packages/d2b/tests/host_validate_verb.rs +++ b/packages/d2b/tests/host_validate_verb.rs @@ -4,6 +4,10 @@ //! real CLI binary, redirect the validator/evidence directories into a //! per-test scratch tree, and assert the same readiness-wave, evidence-write, //! and exit-code contract as the retired shell gate. +//! +//! The missing-mutation-flag envelope cases also pin the sibling mutating +//! host verbs (`host prepare` / `host destroy` / `host reconcile`), which +//! share `--apply-or-dry-run-required` with `host validate`. use std::collections::BTreeSet; use std::fs; @@ -241,6 +245,52 @@ fn host_validate_without_apply_or_dry_run_exits_78_usage_envelope() { assert_eq!(envelope["exitCode"], 78); } +#[test] +fn host_mutating_verbs_without_apply_or_dry_run_exit_78_usage_envelope() { + let sandbox = Sandbox::new(); + for (verb, args) in [ + ("host prepare", &["host", "prepare", "--json"][..]), + ("host destroy", &["host", "destroy", "--json"][..]), + ("host reconcile", &["host", "reconcile", "--json"][..]), + ] { + let out = sandbox.run(&sandbox.scripts_full, args); + + assert_eq!( + out.status.code(), + Some(78), + "{verb} without a mode should exit 78; stderr:\n{}", + String::from_utf8_lossy(&out.stderr) + ); + let envelope = stdout_json(&out); + assert_eq!(envelope["code"], "--apply-or-dry-run-required", "{verb}"); + assert_eq!(envelope["exitCode"], 78, "{verb}"); + assert_eq!( + envelope["kind"], + format!("{verb} requires either --dry-run or --apply"), + "{verb} should name the offending verb" + ); + } +} + +#[test] +fn host_reconcile_without_network_keeps_its_own_refusal() { + let sandbox = Sandbox::new(); + let out = sandbox.run( + &sandbox.scripts_full, + &["host", "reconcile", "--dry-run", "--json"], + ); + + assert_eq!( + out.status.code(), + Some(78), + "missing --network should exit 78; stderr:\n{}", + String::from_utf8_lossy(&out.stderr) + ); + let envelope = stdout_json(&out); + assert_eq!(envelope["errorClass"], "ref-invalid"); + assert_eq!(envelope["message"], "host reconcile requires --network"); +} + #[test] fn host_validate_dry_run_reports_catalog_waves_and_writes_no_evidence() { let sandbox = Sandbox::new(); From 50be72eeaae6b45553fade15d68cf397f2f658d0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:13:43 -0700 Subject: [PATCH 672/726] d2b-bus: make the route-lease revocation latch lock-free The lease flag was a `Mutex` and `with_active` held its guard across the caller's closure, so a revocation check serialized the operation registration it guards. Revocation is one-way and is only ever read as "is this lease dead yet", so an `AtomicBool` with a release store at revocation and acquire loads at every check is the weakest correct ordering and needs no guard. Method signatures are unchanged, so no caller moves. --- .../w7-10-cli-envelope-and-lease-latch.md | 18 +++++++++ packages/d2b-bus/src/registry.rs | 38 +++++++++---------- 2 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 changelog.d/w7-10-cli-envelope-and-lease-latch.md diff --git a/changelog.d/w7-10-cli-envelope-and-lease-latch.md b/changelog.d/w7-10-cli-envelope-and-lease-latch.md new file mode 100644 index 000000000..29f25a451 --- /dev/null +++ b/changelog.d/w7-10-cli-envelope-and-lease-latch.md @@ -0,0 +1,18 @@ +### Fixed + +- `d2b host prepare`, `d2b host destroy`, and `d2b host reconcile` + invoked without `--dry-run` or `--apply` now exit 78 with the + documented `--apply-or-dry-run-required` envelope, as `d2b host + validate` already did. `host prepare` and `host destroy` previously + exited 2 with `ref-invalid`, and `host reconcile` exited 78 under that + same wrong code. Each envelope names the offending verb. The + `--network` requirement on `host reconcile` keeps its own + `ref-invalid` refusal. + +### Changed + +- The route-lease revocation flag in the bus route registry is an + `AtomicBool` latch rather than a `Mutex`. Revocation is one-way, + so revocation is a release store and every check an acquire load: the + weakest correct ordering, and no guard is held across the caller's + work. The lease API and its revocation semantics are unchanged. diff --git a/packages/d2b-bus/src/registry.rs b/packages/d2b-bus/src/registry.rs index ae6ce743b..d3a06d8ca 100644 --- a/packages/d2b-bus/src/registry.rs +++ b/packages/d2b-bus/src/registry.rs @@ -4,7 +4,10 @@ use std::{ collections::{BTreeMap, BTreeSet}, future::Future, pin::Pin, - sync::{Arc, Mutex}, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + }, }; use async_trait::async_trait; @@ -527,8 +530,17 @@ impl SessionIdentity { } } +/// Route-lease revocation latch. +/// +/// Revocation is one-way and is only ever read as "is this lease dead yet", +/// so the flag needs no mutual exclusion: a `Release` store at revocation and +/// `Acquire` loads at every check are the weakest correct ordering. The +/// acquire-load that observes the revocation also observes everything written +/// before the release-store; a `Relaxed` load would drop that edge, and a +/// `SeqCst` fence would buy nothing because no other memory location is +/// ordered against the latch. struct RouteLeaseState { - revoked: Mutex, + revoked: AtomicBool, } pub(crate) struct RevocableRouteLease { @@ -554,7 +566,7 @@ impl RevocableRouteLease { generation, endpoint, state: Arc::new(RouteLeaseState { - revoked: Mutex::new(false), + revoked: AtomicBool::new(false), }), } } @@ -575,16 +587,8 @@ impl RevocableRouteLease { Arc::clone(&self.endpoint) } - // Route-lease revocation is a brief non-suspending critical section shared - // with synchronous teardown paths;the lease flag has no async form here. - #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub(crate) fn with_active(&self, action: impl FnOnce() -> T) -> Result { - let revoked = self - .state - .revoked - .lock() - .unwrap_or_else(|poisoned| poisoned.into_inner()); - if *revoked { + if self.state.revoked.load(Ordering::Acquire) { return Err(RegistryError::RouteRevoked); } Ok(action()) @@ -738,24 +742,20 @@ impl Registry { routes, endpoint: registration.endpoint, route_lease: Arc::new(RouteLeaseState { - revoked: Mutex::new(false), + revoked: AtomicBool::new(false), }), }, ); } - // Session removal marks the lease revoked in a brief non-suspending critical - // section;the lease flag has no async form (see with_active). - #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub(crate) fn remove(&mut self, session: SessionId) -> bool { let Some(registered) = self.sessions.remove(&session) else { return false; }; - *registered + registered .route_lease .revoked - .lock() - .unwrap_or_else(|poisoned| poisoned.into_inner()) = true; + .store(true, Ordering::Release); for route in registered.routes { self.routes.remove(&route); } From fe7c349ea4009168f90cb66379b134c550e17c1f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:11:23 -0700 Subject: [PATCH 673/726] core: deny unknown fields on the zone index document The index document admits index.json; its three sibling index types already deny unknown fields, so an undeclared top-level key passed the top-level check. Declaring the emitted-but-unread keys keeps the emitter's document admissible, and those declared keys stay optional so a partial index still loads. --- .../w7-14-index-document-deny-unknown.md | 9 + packages/d2b-core/src/bundle_resolver.rs | 157 +++++++++++++++++- 2 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 changelog.d/w7-14-index-document-deny-unknown.md diff --git a/changelog.d/w7-14-index-document-deny-unknown.md b/changelog.d/w7-14-index-document-deny-unknown.md new file mode 100644 index 000000000..0ab72b35b --- /dev/null +++ b/changelog.d/w7-14-index-document-deny-unknown.md @@ -0,0 +1,9 @@ +### Fixed + +- The `index.json` reader now refuses an undeclared top-level key. Like + the sibling index types, the index document denies unknown fields, and + it declares the `schemaVersion`, `executionIndex`, `networkIndex`, and + `closureIndex` keys the emitter writes, so an emitted document still + loads while a body carrying a foreign top-level key is rejected as an + `index.json` parse error. The declared-but-unread keys stay optional, + so a partial index that omits them still loads. diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 1eb20ee50..dedacd392 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -203,11 +203,41 @@ struct ZoneNativeBundleRef { path: String, } +/// The cross-Zone index (`index.json`) emitted by `nixos-modules/index.nix`. +/// +/// The reader consumes `zones` and `topology` only, but every other key the +/// emitter writes is declared here so `deny_unknown_fields` can refuse an +/// undeclared top-level key without refusing the emitted document itself. +/// The declared-but-unread keys tolerate absence: admission rests on the +/// sealed topology, and a partial index that omits them still carries it. #[derive(Deserialize)] -#[serde(rename_all = "camelCase")] +#[serde(rename_all = "camelCase", deny_unknown_fields)] struct ZoneNativeIndexDocument { + /// `schemaVersion` of the emitted index. Declared, not read: the reader + /// trusts the index version the bundle's own `schemaVersion` pins. + #[serde(default)] + #[allow(dead_code)] + schema_version: String, zones: BTreeMap, topology: ZoneNativeTopology, + /// `executionIndex`: Host/Guest ref -> Zone, Provider, and Process refs. + /// Declared, not read: execution facts are resolved from the resource + /// bundles and `processes.json`. + #[serde(default)] + #[allow(dead_code)] + execution_index: BTreeMap, + /// `networkIndex`: Network ref -> Zone, LAN subnet, attached Guests. + /// Declared, not read: network facts are resolved from the resource + /// bundles. + #[serde(default)] + #[allow(dead_code)] + network_index: BTreeMap, + /// `closureIndex`: Guest ref -> Zone, closure artifact, closure path, + /// toplevel, and store view. Declared, not read: closure facts are + /// resolved from the resource bundles. + #[serde(default)] + #[allow(dead_code)] + closure_index: BTreeMap, } #[derive(Deserialize)] @@ -7547,6 +7577,131 @@ mod tests { let _ = fs::remove_dir_all(root); } + /// The `/etc/d2b/index.json` body `nixos-modules/index.nix` emits for a + /// single sealed root Zone, with one entry in each index map. + fn emitted_zone_native_index_document() -> serde_json::Value { + let parent_map = BTreeMap::from([("work".to_owned(), None::)]); + let parent_map_bytes = serde_json::to_vec(&parent_map).expect("serialize parent map"); + serde_json::json!({ + "schemaVersion": "v1", + "zones": { + "work": { + "hosts": ["work-host"], + "guests": ["work-guest"], + "networks": ["work-lan"], + "providers": ["system-core"] + } + }, + "topology": { + "sealed": true, + "parentMap": parent_map, + "parentMapDigest": framed_canonical_digest( + "d2b:v3:parent-topology", + &parent_map_bytes, + ), + "generationByZone": { + "work": format!("sha256:{}", "a".repeat(64)) + } + }, + "executionIndex": { + "Host/work-host": { + "zone": "work", + "providerRef": "Provider/system-core", + "processes": [] + } + }, + "networkIndex": { + "Network/work-lan": { + "zone": "work", + "lanSubnet": null, + "attachedGuests": ["Guest/work-guest"] + } + }, + "closureIndex": { + "Guest/work-guest": { + "zone": "work", + "guest": "work-guest", + "closureArtifact": null, + "closurePath": "/etc/d2b/closures/zones/work/work-guest.json", + "toplevel": null, + "storeView": null + } + } + }) + } + + /// Writes an index body under `root` with the production posture and + /// returns the v3 bundle that hash-pins it. + fn write_zone_native_index(root: &Path, index: &serde_json::Value) -> Bundle { + use std::os::unix::fs::PermissionsExt as _; + + let index_bytes = serde_json::to_vec(index).expect("serialize index"); + let index_path = root.join("index.json"); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fs::write(&index_path, &index_bytes).expect("write index"); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fs::set_permissions(&index_path, fs::Permissions::from_mode(0o640)).expect("chmod index"); + site_test_bundle(Some(BTreeMap::from([( + "index.json".to_owned(), + sha256_hex(&index_bytes), + )]))) + } + + #[test] + fn zone_native_index_admits_the_emitted_keys_and_refuses_a_foreign_one() { + let root = test_root("zone-native-index-unknown-key"); + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fs::create_dir_all(&root).expect("create bundle root"); + let zone_bundles = BTreeMap::from([("work".to_owned(), Vec::new())]); + + // Every emitted key is declared, so the emitted document loads. + let emitted = emitted_zone_native_index_document(); + let bundle = write_zone_native_index(&root, &emitted); + let topology = + load_zone_native_topology(&bundle, &zone_bundles, &root, ¤t_user_bundle_policy()) + .expect("the emitted index shape loads") + .expect("topology present"); + assert_eq!(topology.root.as_str(), "work"); + + // An index that omits the declared-but-unread keys still loads: the + // broker seam pilot writes `zones` and `topology` only. + let mut partial = emitted_zone_native_index_document(); + { + let object = partial.as_object_mut().expect("index body is an object"); + for key in [ + "schemaVersion", + "executionIndex", + "networkIndex", + "closureIndex", + ] { + assert!(object.remove(key).is_some(), "{key} must be emitted"); + } + } + let bundle = write_zone_native_index(&root, &partial); + load_zone_native_topology(&bundle, &zone_bundles, &root, ¤t_user_bundle_policy()) + .expect("a partial index loads") + .expect("topology present"); + + // The emitted document plus one undeclared top-level key is refused; + // that key is the only difference from the admitted document. + let mut foreign = emitted; + foreign + .as_object_mut() + .expect("index body is an object") + .insert( + "topologyDigest".to_owned(), + serde_json::Value::String("sha256:deadbeef".to_owned()), + ); + let bundle = write_zone_native_index(&root, &foreign); + let error = + load_zone_native_topology(&bundle, &zone_bundles, &root, ¤t_user_bundle_policy()) + .expect_err("an undeclared top-level key must refuse the index"); + assert_eq!(error.kind().as_str(), "manifest-parse-error"); + + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + let _ = fs::remove_dir_all(root); + } + #[test] fn host_reconcile_and_store_preflight_emit_executable_vm_start_intents() { let root = test_root("vm-start-intents"); From ca3cde0c501167637b4ceb1ff618c6a5c461fe71 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:17:45 -0700 Subject: [PATCH 674/726] providers: validate relay transport settings on deserialization RelayTransportSettings derived Deserialize directly, so serde_json::from_slice at the composition admission site accepted identifiers the constructor refuses - including the secret-shape exclusion that lived only in Rust. Deserialize now goes through an unvalidated wire form whose only conversion is RelayTransportSettings::new, so the accepted sets cannot diverge, and the pinned settings schema records the same SharedAccessSignature exclusion. The constructor and validator are unchanged, so no value the schema admits is newly refused. --- ...azure-relay-typed-settings-and-material.md | 14 ++++ ...nsport-azure-relay.transport-settings.json | 5 ++ .../ADR-046-provider-transport-azure-relay.md | 21 +++-- .../src/transport_settings.rs | 37 ++++++++- .../tests/transport_settings_schema.rs | 76 +++++++++++++++++++ 5 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 changelog.d/w7-16-azure-relay-typed-settings-and-material.md diff --git a/changelog.d/w7-16-azure-relay-typed-settings-and-material.md b/changelog.d/w7-16-azure-relay-typed-settings-and-material.md new file mode 100644 index 000000000..8236c0c9e --- /dev/null +++ b/changelog.d/w7-16-azure-relay-typed-settings-and-material.md @@ -0,0 +1,14 @@ +### Fixed + +- `d2b-provider-transport-azure-relay`: `RelayTransportSettings` is now + deserialized through the same admission the constructor runs, so a + settings blob can no longer be admitted with an identifier the + constructor refuses, and the pinned settings schema records the + secret-shape exclusion. + +### Changed + +- The gateway credential loader describes the fixed + `relayListen`/`relaySend` envelope shape with typed wire structs + instead of walking JSON paths. The accepted values are unchanged; + unknown keys are now refused rather than ignored. diff --git a/docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json b/docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json index 579dbb092..da6419d43 100644 --- a/docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json +++ b/docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json @@ -8,12 +8,17 @@ "properties": { "relayNamespaceId": { "type": "string", + "description": "Bare Relay namespace identifier: no scheme, no DNS suffix. Non-secret.", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{1,48}[a-zA-Z0-9]$", "maxLength": 50 }, "relayEntityId": { "type": "string", + "description": "Hybrid Connection entity identifier: lowercase kebab. Non-secret, and never a SAS token shape.", "pattern": "^[a-z][a-z0-9-]{1,49}$", + "not": { + "pattern": "SharedAccessSignature" + }, "maxLength": 50 } } diff --git a/docs/specs/providers/ADR-046-provider-transport-azure-relay.md b/docs/specs/providers/ADR-046-provider-transport-azure-relay.md index ade48d673..3f627d1f7 100644 --- a/docs/specs/providers/ADR-046-provider-transport-azure-relay.md +++ b/docs/specs/providers/ADR-046-provider-transport-azure-relay.md @@ -195,10 +195,12 @@ The transport Provider publishes a signed settings schema at: docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json ``` -This schema is committed alongside the crate and kept in sync by -`make test-drift` (via `xtask gen-provider-transport-schemas && git diff --exit-code`). -The Nix build phase validates every `ZoneLink.spec.transportSettings` object -against it before emitting the resource bundle. +This schema is a hand-authored committed artifact: the crate embeds it verbatim +(`RelayTransportSettings::schema_json`) and applies the same admission rules to +every settings object it deserializes, so the published schema and the runtime +validator agree on the accepted set. The Nix zones contract validates every +`ZoneLink.spec.transportSettings` object against the same identifier patterns +before emitting the resource bundle. ### Canonical `spec.transportSettings` object @@ -213,14 +215,17 @@ against it before emitting the resource bundle. "properties": { "relayNamespaceId": { "type": "string", - "description": "Plain Azure Relay namespace identifier (not the FQDN; no scheme or host suffix). Example: 'relns-d2b-prod'. Non-secret; validated against ^[a-zA-Z0-9][a-zA-Z0-9-]{2,48}[a-zA-Z0-9]$.", - "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{2,48}[a-zA-Z0-9]$", + "description": "Bare Relay namespace identifier: no scheme, no DNS suffix. Non-secret.", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{1,48}[a-zA-Z0-9]$", "maxLength": 50 }, "relayEntityId": { "type": "string", - "description": "Hybrid Connection entity name within the namespace. Example: 'hc-d2b-k2'. Non-secret. Validated against ^[a-z][a-z0-9-]{1,49}$.", + "description": "Hybrid Connection entity identifier: lowercase kebab. Non-secret, and never a SAS token shape.", "pattern": "^[a-z][a-z0-9-]{1,49}$", + "not": { + "pattern": "SharedAccessSignature" + }, "maxLength": 50 } } @@ -232,7 +237,7 @@ against it before emitting the resource bundle. | Field | Required | Secret | Rules | | --- | --- | --- | --- | | `relayNamespaceId` | Yes | No | Plain Azure Relay namespace label only; no `.servicebus.windows.net` suffix, no scheme; validated by regex; max 50 chars | -| `relayEntityId` | Yes | No | Hybrid Connection entity name; lowercase kebab; max 50 chars | +| `relayEntityId` | Yes | No | Hybrid Connection entity name; lowercase kebab; max 50 chars; never a `SharedAccessSignature` token shape | The build emitter **rejects** any `spec.transportSettings` field: diff --git a/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs b/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs index 610abf1ca..c8697d073 100644 --- a/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs +++ b/packages/d2b-provider-transport-azure-relay/src/transport_settings.rs @@ -5,8 +5,12 @@ use std::fmt; use serde::{Deserialize, Serialize}; /// Bounded non-secret Relay settings. +/// +/// Deserialization runs the same validation as [`RelayTransportSettings::new`] +/// through [`RelayTransportSettingsWire`], so a value that arrives over the +/// wire cannot be admitted when the constructor would refuse it. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] +#[serde(rename_all = "camelCase", try_from = "RelayTransportSettingsWire")] pub struct RelayTransportSettings { /// Bare namespace identifier, without scheme or DNS suffix. pub relay_namespace_id: String, @@ -14,6 +18,25 @@ pub struct RelayTransportSettings { pub relay_entity_id: String, } +/// Unvalidated wire form of [`RelayTransportSettings`]. +/// +/// The shape is the only thing this type decides; every admitted value is +/// handed to [`RelayTransportSettings::new`] before it becomes settings. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct RelayTransportSettingsWire { + relay_namespace_id: String, + relay_entity_id: String, +} + +impl TryFrom for RelayTransportSettings { + type Error = RelayTransportSettingsError; + + fn try_from(wire: RelayTransportSettingsWire) -> Result { + Self::new(wire.relay_namespace_id, wire.relay_entity_id) + } +} + impl RelayTransportSettings { /// Construct validated settings. /// @@ -71,6 +94,18 @@ pub enum RelayTransportSettingsError { InvalidIdentifier, } +impl fmt::Display for RelayTransportSettingsError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidIdentifier => formatter.write_str( + "relay transport settings must carry a bounded non-secret namespace and entity", + ), + } + } +} + +impl std::error::Error for RelayTransportSettingsError {} + fn valid_namespace(value: &str) -> bool { (3..=50).contains(&value.len()) && value diff --git a/packages/d2b-provider-transport-azure-relay/tests/transport_settings_schema.rs b/packages/d2b-provider-transport-azure-relay/tests/transport_settings_schema.rs index a7456dfc2..76fc365fb 100644 --- a/packages/d2b-provider-transport-azure-relay/tests/transport_settings_schema.rs +++ b/packages/d2b-provider-transport-azure-relay/tests/transport_settings_schema.rs @@ -16,3 +16,79 @@ fn settings_accept_only_bare_non_secret_identifiers() { Err(RelayTransportSettingsError::InvalidIdentifier) )); } + +#[test] +fn deserialization_admits_exactly_what_the_constructor_admits() { + let blob = r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"hc-d2b-k2"}"#; + let settings = + serde_json::from_str::(blob).expect("an admitted settings blob"); + assert_eq!( + settings, + RelayTransportSettings::new("relns-d2b-prod", "hc-d2b-k2").unwrap() + ); + assert_eq!(serde_json::to_string(&settings).unwrap(), blob); + + for refused in [ + // Secret-shaped entity identifiers: refused by the Rust validator and + // recorded as an exclusion in the pinned schema. + r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"SharedAccessSignature sr=x&sig=y"}"#, + r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"hc-SharedAccessSignature-k2"}"#, + // Namespace grammar, bound, and separator exclusions. + r#"{"relayNamespaceId":"ns","relayEntityId":"hc-d2b-k2"}"#, + r#"{"relayNamespaceId":"https://relay.example","relayEntityId":"hc-d2b-k2"}"#, + r#"{"relayNamespaceId":"relns/d2b","relayEntityId":"hc-d2b-k2"}"#, + r#"{"relayNamespaceId":"relns:d2b","relayEntityId":"hc-d2b-k2"}"#, + r#"{"relayNamespaceId":"-relns-d2b-","relayEntityId":"hc-d2b-k2"}"#, + // Entity grammar and bound. + r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"HC-D2B-K2"}"#, + r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"h"}"#, + r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"hc_d2b"}"#, + // Wire-shape failures the derived form owns. + r#"{"relayNamespaceId":"relns-d2b-prod"}"#, + r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"hc-d2b-k2","relayKeyName":"listen"}"#, + r#"{"relayNamespaceId":7,"relayEntityId":"hc-d2b-k2"}"#, + ] { + assert!( + serde_json::from_str::(refused).is_err(), + "{refused} must be refused at deserialization" + ); + } + + let long_namespace = format!( + r#"{{"relayNamespaceId":"{}","relayEntityId":"hc-d2b-k2"}}"#, + "a".repeat(51) + ); + let long_entity = format!( + r#"{{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"{}"}}"#, + "h".repeat(51) + ); + for refused in [long_namespace, long_entity] { + assert!( + serde_json::from_str::(&refused).is_err(), + "{refused} must be refused at deserialization" + ); + } +} + +#[test] +fn refused_settings_surface_the_typed_validation_error() { + let error = serde_json::from_str::( + r#"{"relayNamespaceId":"relns-d2b-prod","relayEntityId":"SharedAccessSignature sr=x&sig=y"}"#, + ) + .expect_err("a secret-shaped entity identifier is refused"); + let typed = RelayTransportSettingsError::InvalidIdentifier; + assert!( + error.to_string().contains(&typed.to_string()), + "deserialization must carry the typed validation error: {error}" + ); +} + +#[test] +fn pinned_schema_records_the_secret_shape_exclusion() { + let schema: serde_json::Value = + serde_json::from_str(RelayTransportSettings::schema_json()).unwrap(); + assert_eq!( + schema["properties"]["relayEntityId"]["not"]["pattern"], + "SharedAccessSignature" + ); +} From 5c3f15511a886537a4101a21c0291f63908111d4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:17:50 -0700 Subject: [PATCH 675/726] providers: type the gateway credential material shape parse_material_json hand-walked serde_json::Value paths for a fixed nested relayListen/relaySend shape. Two derived wire structs now own that shape, and the value pass keeps the invariants the walk enforced: every branch and rule name is required, a JSON string, non-empty, within 16 KiB, and free of ASCII control bytes. Unknown keys are refused instead of silently ignored, which is the one deliberate tightening; every other accepted value is unchanged. --- .../src/guest_credential.rs | 116 +++++++++++++++--- 1 file changed, 99 insertions(+), 17 deletions(-) diff --git a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs index 7e69ecbe1..417d9a446 100644 --- a/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs +++ b/packages/d2b-provider-transport-azure-relay/src/guest_credential.rs @@ -25,7 +25,6 @@ use base64::Engine; use chacha20poly1305::aead::{Aead, KeyInit, Payload}; use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; use serde::{Deserialize, Serialize}; -use serde_json::Value; use sha2::{Digest, Sha256}; use zeroize::{Zeroize, Zeroizing}; @@ -230,13 +229,19 @@ impl GatewayCredential { self.not_after } + /// Parse the plaintext material shape the enrollment flow admits. + /// + /// The nested shape is fixed, so it is described by types: the wire + /// structs decide presence, string typing, and unknown keys, and the + /// validation pass below decides the values. fn parse_material_json(raw: &str) -> Result { - let v: Value = serde_json::from_str(raw).map_err(|_| CredentialError::Malformed)?; + let file: CredentialMaterialFile = + serde_json::from_str(raw).map_err(|_| CredentialError::Malformed)?; let material = GatewayCredentialMaterial { - listen_key_name: required_str(&v, &["relayListen", "keyName"])?, - listen_key: required_str(&v, &["relayListen", "key"])?, - send_key_name: required_str(&v, &["relaySend", "keyName"])?, - send_key: required_str(&v, &["relaySend", "key"])?, + listen_key_name: file.relay_listen.key_name, + listen_key: file.relay_listen.key, + send_key_name: file.relay_send.key_name, + send_key: file.relay_send.key, }; if [ &material.listen_key_name, @@ -495,6 +500,24 @@ impl ScopedCredentialClient for GatewayGuestCredentialPort { } } +/// Plaintext credential material shape the enrollment flow admits. +/// +/// `Debug` is deliberately not derived: both branches carry Relay keys. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct CredentialMaterialFile { + relay_listen: RelayRoleMaterial, + relay_send: RelayRoleMaterial, +} + +/// One Relay role's rule name and key, as the envelope names them. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct RelayRoleMaterial { + key_name: String, + key: String, +} + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct SealedCredentialFile { @@ -636,17 +659,6 @@ fn decode_fixed(encoded: &str) -> Result<[u8; N], CredentialErro .map_err(|_| CredentialError::Malformed) } -fn required_str(v: &Value, path: &[&str]) -> Result { - let mut cur = v; - for key in path { - cur = cur.get(*key).ok_or(CredentialError::Malformed)?; - } - cur.as_str() - .filter(|s| !s.is_empty()) - .map(str::to_owned) - .ok_or(CredentialError::Malformed) -} - fn system_now_unix_ms() -> Result { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -781,6 +793,76 @@ mod tests { } } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn material_file(dir: &Path, contents: &str) -> PathBuf { + let path = dir.join("credential.json"); + fs::write(&path, contents).unwrap(); + fs::set_permissions(&path, fs::Permissions::from_mode(0o600)).unwrap(); + path + } + + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[test] + fn rejects_malformed_material_shapes() { + let dir = tempfile::tempdir().unwrap(); + for (label, contents) in [ + ( + "missing listen key", + r#"{"relayListen":{"keyName":"gateway-listen"},"relaySend":{"keyName":"gateway-send","key":"send-secret"}}"#, + ), + ( + "missing send branch", + r#"{"relayListen":{"keyName":"gateway-listen","key":"listen-secret"}}"#, + ), + ( + "wrong key type", + r#"{"relayListen":{"keyName":5,"key":"listen-secret"},"relaySend":{"keyName":"gateway-send","key":"send-secret"}}"#, + ), + ( + "non-object listen branch", + r#"{"relayListen":"gateway-listen","relaySend":{"keyName":"gateway-send","key":"send-secret"}}"#, + ), + ( + "unknown top-level key", + r#"{"relayListen":{"keyName":"gateway-listen","key":"listen-secret"},"relaySend":{"keyName":"gateway-send","key":"send-secret"},"relayOther":{"keyName":"x","key":"y"}}"#, + ), + ( + "unknown nested key", + r#"{"relayListen":{"keyName":"gateway-listen","key":"listen-secret","audience":"azure-relay-listen"},"relaySend":{"keyName":"gateway-send","key":"send-secret"}}"#, + ), + ( + "empty key name", + r#"{"relayListen":{"keyName":"","key":"listen-secret"},"relaySend":{"keyName":"gateway-send","key":"send-secret"}}"#, + ), + ( + "control character in key", + r#"{"relayListen":{"keyName":"gateway-listen","key":"listen\u0000secret"},"relaySend":{"keyName":"gateway-send","key":"send-secret"}}"#, + ), + ( + "duplicate role key", + r#"{"relayListen":{"keyName":"gateway-listen","key":"listen-secret","key":"listen-secret-two"},"relaySend":{"keyName":"gateway-send","key":"send-secret"}}"#, + ), + ] { + let path = material_file(dir.path(), contents); + assert_eq!( + GatewayCredential::load(&path, &CredentialFilePolicy::default()).unwrap_err(), + CredentialError::Malformed, + "{label} must stay refused" + ); + } + + let oversized = format!( + r#"{{"relayListen":{{"keyName":"gateway-listen","key":"{}"}},"relaySend":{{"keyName":"gateway-send","key":"send-secret"}}}}"#, + "k".repeat(16 * 1024 + 1) + ); + let path = material_file(dir.path(), &oversized); + assert_eq!( + GatewayCredential::load(&path, &CredentialFilePolicy::default()).unwrap_err(), + CredentialError::Malformed, + "an over-long key must stay refused" + ); + } + #[test] fn loads_only_runtime_0600_files_and_redacts_debug() { let dir = tempfile::tempdir().unwrap(); From 369627b7861b01fbe610cc8e31675933ef85fb20 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:21:39 -0700 Subject: [PATCH 676/726] fix(d2bd): validate the host activation marker mode and schema version The persisted activation marker carried `mode` as a free string and `schemaVersion` was never checked, so a marker written by newer activation machinery could parse as current. - Mirror the public activation verbs (`switch`, `boot`, `test`, `rollback`) in a marker mode enum with an `#[serde(other)]` catch-all, keeping an unrecognized future mode parseable and the startup/status log line reporting a recognized label through `Display`. - Route every marker parse through `parse_activation_marker`, which refuses any `schemaVersion` other than the one this daemon understands with a structured warning naming `schema_version`: `read_activation_marker` returns `None` and both startup passes (degraded-metric refresh, configuration staging) skip the marker. --- .../w7-09-activation-marker-typed-mode.md | 19 +++ packages/d2bd/src/composition.rs | 158 +++++++++++++++++- 2 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 changelog.d/w7-09-activation-marker-typed-mode.md diff --git a/changelog.d/w7-09-activation-marker-typed-mode.md b/changelog.d/w7-09-activation-marker-typed-mode.md new file mode 100644 index 000000000..f85d6d547 --- /dev/null +++ b/changelog.d/w7-09-activation-marker-typed-mode.md @@ -0,0 +1,19 @@ +### Changed + +- `d2bd` validates the `mode` recorded in a host activation marker + against the public activation verbs (`switch`, `boot`, `test`, + `rollback`) instead of carrying it as a free string, and the + startup/status log line reports the recognized label. A mode this + daemon does not know still parses into a catch-all variant, so a + marker written by newer activation machinery keeps every other field + readable. + +### Fixed + +- `d2bd` refuses host activation markers whose `schemaVersion` it does + not understand. `status`/`list` no longer report degraded + activation-pending from a future marker version, and neither startup + pass (degraded-metric refresh, configuration staging) adopts one - a + future version with a compatible field set can no longer parse as the + current version. Each refusal is logged with the marker's VM and + version. diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index dcc02d2be..59c8606dc 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -20367,12 +20367,47 @@ enum HostActivationMarkerState { Indeterminate, } +/// The `mode` a host activation marker records. +/// +/// The labels mirror the public activation verbs (`switch`, `boot`, `test`, +/// `rollback`) so a marker's mode is validated instead of accepted as a free +/// string. The marker itself is written by the activation machinery outside +/// this workspace, so an unrecognized future mode still parses into +/// `Unknown` rather than invalidating every other field of the marker. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +enum HostActivationMarkerMode { + Switch, + Boot, + Test, + Rollback, + #[serde(other)] + Unknown, +} + +impl std::fmt::Display for HostActivationMarkerMode { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(match self { + HostActivationMarkerMode::Switch => "switch", + HostActivationMarkerMode::Boot => "boot", + HostActivationMarkerMode::Test => "test", + HostActivationMarkerMode::Rollback => "rollback", + HostActivationMarkerMode::Unknown => "unknown", + }) + } +} + +/// The only activation-marker `schemaVersion` this daemon understands. +/// The version, not the field set, decides whether a marker is adopted: a +/// newer version may add, drop, or repurpose fields while still parsing. +const ACTIVATION_MARKER_SCHEMA_VERSION: u32 = 1; + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct HostActivationPendingMarker { schema_version: u32, vm: String, - mode: String, + mode: HostActivationMarkerMode, generation_number: Option, activation_id: String, switch_script_basename: String, @@ -20487,11 +20522,29 @@ fn activation_marker_path(state: &ServerState, vm: &str) -> PathBuf { activation_marker_dir(state).join(format!("{vm}.json")) } +/// Parse one activation marker body, refusing a `schemaVersion` this daemon +/// does not understand so a future marker version with a compatible field set +/// cannot silently parse as current. Every activation-marker parse site goes +/// through here, so no caller can adopt a marker without the version check. +fn parse_activation_marker(bytes: &[u8]) -> Option { + let marker: HostActivationPendingMarker = serde_json::from_slice(bytes).ok()?; + if marker.schema_version == ACTIVATION_MARKER_SCHEMA_VERSION { + return Some(marker); + } + tracing::warn!( + vm = %marker.vm, + schema_version = marker.schema_version, + supported_schema_version = ACTIVATION_MARKER_SCHEMA_VERSION, + "activation marker refused: unsupported schema_version" + ); + None +} + #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn read_activation_marker(state: &ServerState, vm: &str) -> Option { let path = activation_marker_path(state, vm); let bytes = fs::read(path).ok()?; - serde_json::from_slice(&bytes).ok() + parse_activation_marker(&bytes) } async fn refresh_activation_marker_metrics_on_startup(state: &ServerState) { @@ -20503,7 +20556,7 @@ async fn refresh_activation_marker_metrics_on_startup(state: &ServerState) { let Ok(bytes) = tokio::fs::read(entry.path()).await else { continue; }; - let Ok(marker) = serde_json::from_slice::(&bytes) else { + let Some(marker) = parse_activation_marker(&bytes) else { continue; }; tracing::warn!( @@ -20526,7 +20579,7 @@ async fn restore_configuration_staging_on_startup(state: &ServerState) { let Ok(bytes) = tokio::fs::read(entry.path()).await else { continue; }; - let Ok(marker) = serde_json::from_slice::(&bytes) else { + let Some(marker) = parse_activation_marker(&bytes) else { continue; }; let Some(ordinal) = marker.generation_number else { @@ -22992,6 +23045,103 @@ mod public_status_tests { ); server.join().expect("status server"); } + + /// A marker body shaped exactly as the activation machinery writes it. + fn activation_marker_json(schema_version: u32, mode: &str) -> Value { + json!({ + "schemaVersion": schema_version, + "vm": "vm-a", + "mode": mode, + "generationNumber": 3, + "activationId": "activation-1", + "switchScriptBasename": "switch.sh", + "switchScriptSha256": "sha256:0", + "state": "pending", + "createdUnixSecs": 1, + "updatedUnixSecs": 2, + }) + } + + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn write_activation_marker(state: &ServerState, schema_version: u32, mode: &str) { + let dir = activation_marker_dir(state); + fs::create_dir_all(&dir).expect("activation marker dir"); + fs::write( + activation_marker_path(state, "vm-a"), + serde_json::to_vec(&activation_marker_json(schema_version, mode)) + .expect("serialize activation marker"), + ) + .expect("write activation marker"); + } + + #[test] + fn unknown_activation_marker_mode_parses_into_the_catch_all_variant() { + let marker: HostActivationPendingMarker = + serde_json::from_value(activation_marker_json(1, "warp-drive")) + .expect("marker with an unrecognized mode still parses"); + assert_eq!(marker.mode, HostActivationMarkerMode::Unknown); + assert_eq!(marker.mode.to_string(), "unknown"); + + for (label, mode) in [ + ("switch", HostActivationMarkerMode::Switch), + ("boot", HostActivationMarkerMode::Boot), + ("test", HostActivationMarkerMode::Test), + ("rollback", HostActivationMarkerMode::Rollback), + ] { + let marker: HostActivationPendingMarker = + serde_json::from_value(activation_marker_json(1, label)) + .expect("known mode label parses"); + assert_eq!(marker.mode, mode, "mode label {label}"); + assert_eq!(marker.mode.to_string(), label, "mode label {label}"); + assert_eq!( + serde_json::to_value(mode).expect("mode serializes"), + Value::String(label.to_owned()), + "mode label {label}" + ); + } + } + + #[test] + fn activation_marker_parse_refuses_an_unsupported_schema_version() { + let current = serde_json::to_vec(&activation_marker_json(1, "switch")).expect("marker body"); + assert!(parse_activation_marker(¤t).is_some()); + + // A newer version with a still-compatible field set must not parse as + // the current version. + let future = serde_json::to_vec(&activation_marker_json(2, "switch")).expect("marker body"); + assert!(parse_activation_marker(&future).is_none()); + } + + #[test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn read_activation_marker_refuses_an_unsupported_schema_version() { + let (state, _state_dir) = test_state(); + write_activation_marker(&state, 1, "switch"); + assert!(read_activation_marker(&state, "vm-a").is_some()); + + write_activation_marker(&state, 2, "switch"); + assert!(read_activation_marker(&state, "vm-a").is_none()); + } + + #[test] + fn startup_marker_metric_refresh_ignores_an_unsupported_schema_version() { + let (state, _state_dir) = test_state(); + write_activation_marker(&state, 2, "switch"); + // Driven from this non-async test thread; the adoption path records a + // gauge through `MetricsRegistry`'s blocking seat, so the refusal path + // is the one this runtime-free test can observe. + drive_sync( + &state.runtime_handle, + refresh_activation_marker_metrics_on_startup(&state), + ); + assert!( + !state + .metrics_registry + .render() + .contains("d2b_daemon_vm_degraded{reason=\"activation-pending\"}"), + "an unsupported marker version must not record degraded activation" + ); + } } fn dispatch_audit( From bf8dc0bc293fb1232b0485d853263aefe861b601 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:23:49 -0700 Subject: [PATCH 677/726] fix(d2b-provider-command): publish the command admission in the schema `CommandExec` published `^/[^\u0000]*$` while `CommandExec::parse` refuses every control code point, so a document that satisfied the published schema could still be refused at deserialization. The pattern now excludes what `char::is_control` selects: C0, DEL, and C1. `CommandArgvSlot` published no pattern and no lower bound at all. It now publishes `minLength: 1` plus the slot grammar the parse enforces: literal text carrying no brace and no control code point, or exactly one whole-slot `{placeholder}` whose name is a well-formed payload parameter name. `CommandArgvSlot::parse` refuses a control character in a literal slot so that the two sides admit the same strings, which also matches the control-free rule the executable path already had. `maxLength` counts code points where the parse bounds bytes, so multi-byte text can still be published-legal and parse-refused; an ECMA-262 pattern cannot express a byte bound without excluding parse-legal non-ASCII text. Regenerated with `cargo run -p xtask -- gen-zone-schemas`. --- changelog.d/w7-12-command-schema-admission.md | 15 +++ .../v3/core.d2bus.org_Command.schema.json | 4 +- packages/d2b-provider-command/src/command.rs | 109 +++++++++++++++++- 3 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 changelog.d/w7-12-command-schema-admission.md diff --git a/changelog.d/w7-12-command-schema-admission.md b/changelog.d/w7-12-command-schema-admission.md new file mode 100644 index 000000000..2e3a2104e --- /dev/null +++ b/changelog.d/w7-12-command-schema-admission.md @@ -0,0 +1,15 @@ +### Fixed + +- The published `Command` schema now carries the admission its parse + enforces, so a value that satisfies the schema always deserializes. + `CommandExec` publishes the control-free absolute path pattern (every + `char::is_control` code point: C0, DEL, and C1, not NUL only), and + `CommandArgvSlot` publishes `minLength: 1` plus the slot pattern: a + brace-free, control-free literal, or exactly one whole-slot + `{placeholder}` naming a well-formed payload parameter. + +### Changed + +- `CommandArgvSlot::parse` refuses a control character in a literal + slot, matching the control-free executable rule and the pattern the + published schema carries. diff --git a/docs/reference/schemas/v3/core.d2bus.org_Command.schema.json b/docs/reference/schemas/v3/core.d2bus.org_Command.schema.json index ff507af49..47c838c37 100644 --- a/docs/reference/schemas/v3/core.d2bus.org_Command.schema.json +++ b/docs/reference/schemas/v3/core.d2bus.org_Command.schema.json @@ -16,11 +16,13 @@ "CommandArgvSlot": { "description": "One argument slot: a literal, or a whole-slot {placeholder} naming a declared parameter.", "maxLength": 4096, + "minLength": 1, + "pattern": "^(?:[^{}\\u0000-\\u001f\\u007f-\\u009f]+|\\{[a-z][a-zA-Z0-9]{0,62}\\})$", "type": "string" }, "CommandExec": { "maxLength": 4096, - "pattern": "^/[^\\u0000]*$", + "pattern": "^/[^\\u0000-\\u001f\\u007f-\\u009f]*$", "type": "string" }, "CommandIntent": { diff --git a/packages/d2b-provider-command/src/command.rs b/packages/d2b-provider-command/src/command.rs index 0f88b1dc7..9cb20ab41 100644 --- a/packages/d2b-provider-command/src/command.rs +++ b/packages/d2b-provider-command/src/command.rs @@ -25,9 +25,21 @@ pub const COMMAND_RESOURCE_TYPE: &str = "Command"; pub const MAX_COMMAND_ARGV_SLOTS: usize = 64; /// Maximum bytes of one argument slot. pub const MAX_COMMAND_ARGV_SLOT_BYTES: usize = 4096; -/// Maximum bytes of one executable path. +/// Maximum bytes of an executable path. pub const MAX_COMMAND_EXEC_BYTES: usize = 4096; +/// The published spelling of an executable path, mirroring +/// [`CommandExec::parse`]: absolute, and free of every code point +/// `char::is_control` selects (C0, DEL, and C1). +const EXEC_PATTERN: &str = "^/[^\\u0000-\\u001f\\u007f-\\u009f]*$"; +/// The published spelling of one argument slot, mirroring +/// [`CommandArgvSlot::parse`]: literal text with no brace and no control code +/// point, or one whole-slot `{placeholder}` whose name is a well-formed +/// payload parameter name (`valid_property_name`: a lowercase ASCII letter +/// followed by up to 62 ASCII alphanumerics). +const ARGV_SLOT_PATTERN: &str = + "^(?:[^{}\\u0000-\\u001f\\u007f-\\u009f]+|\\{[a-z][a-zA-Z0-9]{0,62}\\})$"; + /// A validated absolute executable path. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] @@ -78,7 +90,7 @@ impl JsonSchema for CommandExec { ))), ..Default::default() }; - schema.string().pattern = Some("^/[^\\u0000]*$".to_owned()); + schema.string().pattern = Some(EXEC_PATTERN.to_owned()); schema.string().max_length = Some(MAX_COMMAND_EXEC_BYTES as u32); schemars::schema::Schema::Object(schema) } @@ -95,14 +107,14 @@ impl CommandArgvSlot { /// # Errors /// /// Returns `InvalidArgvSlot` when the slot is empty, over bound, - /// contains a NUL byte, or is a brace-carrying slot that is not a - /// single placeholder naming a valid parameter. + /// carries a control character, or is a brace-carrying slot that is not + /// a single placeholder naming a valid parameter. pub fn parse(value: impl Into) -> Result { let value = value.into(); if value.is_empty() || value.len() > MAX_COMMAND_ARGV_SLOT_BYTES { return Err(CommandContractError::InvalidArgvSlot); } - if value.contains('\u{0}') { + if value.chars().any(char::is_control) { return Err(CommandContractError::InvalidArgvSlot); } if value.contains(['{', '}']) { @@ -157,6 +169,8 @@ impl JsonSchema for CommandArgvSlot { "One argument slot: a literal, or a whole-slot {placeholder} naming a declared parameter." .to_owned(), ); + schema.string().min_length = Some(1); + schema.string().pattern = Some(ARGV_SLOT_PATTERN.to_owned()); schema.string().max_length = Some(MAX_COMMAND_ARGV_SLOT_BYTES as u32); schemars::schema::Schema::Object(schema) } @@ -322,6 +336,9 @@ impl From for CommandContractError { #[cfg(test)] mod tests { use super::*; + use d2b_contracts_resource::v3::payload_schema::MAX_PAYLOAD_PROPERTY_NAME_BYTES; + use schemars::r#gen::SchemaGenerator; + use schemars::schema::Schema; use serde_json::json; fn params() -> PayloadSchema { @@ -415,4 +432,86 @@ mod tests { }); assert!(serde_json::from_value::(unknown).is_err()); } + + #[test] + fn the_published_schemas_carry_the_parse_patterns() { + let mut generator = SchemaGenerator::default(); + + let Schema::Object(exec) = CommandExec::json_schema(&mut generator) else { + panic!("CommandExec schema is an object"); + }; + let exec_string = exec.string.expect("CommandExec string validation"); + assert_eq!(exec_string.pattern.as_deref(), Some(EXEC_PATTERN)); + assert_eq!(exec_string.max_length, Some(MAX_COMMAND_EXEC_BYTES as u32)); + + let Schema::Object(slot) = CommandArgvSlot::json_schema(&mut generator) else { + panic!("CommandArgvSlot schema is an object"); + }; + let slot_string = slot.string.expect("CommandArgvSlot string validation"); + assert_eq!(slot_string.pattern.as_deref(), Some(ARGV_SLOT_PATTERN)); + assert_eq!(slot_string.min_length, Some(1)); + assert_eq!( + slot_string.max_length, + Some(MAX_COMMAND_ARGV_SLOT_BYTES as u32) + ); + } + + #[test] + fn argument_slot_admission_covers_the_published_language() { + for slot in [ + "--flag", + "-", + "/run/d2b/vfs/socket", + "caf\u{e9}-dir", + "{socketPath}", + "{aB9}", + ] { + assert!(CommandArgvSlot::parse(slot).is_ok(), "{slot:?}"); + } + let longest_name = format!("a{}", "b".repeat(MAX_PAYLOAD_PROPERTY_NAME_BYTES - 1)); + assert!(CommandArgvSlot::parse(format!("{{{longest_name}}}")).is_ok()); + + for slot in [ + "", + "\u{0}", + "--flag\t", + "--flag\n", + "\u{7f}", + "\u{9f}", + "{", + "}", + "a}b", + "-{socketPath}", + "{socketPath", + "{}", + "{Upper}", + "{a-b}", + "{a_b}", + "{caf\u{e9}}", + ] { + assert!(CommandArgvSlot::parse(slot).is_err(), "{slot:?}"); + } + let over_long_name = format!("a{}", "b".repeat(MAX_PAYLOAD_PROPERTY_NAME_BYTES)); + assert!(CommandArgvSlot::parse(format!("{{{over_long_name}}}")).is_err()); + assert!(CommandArgvSlot::parse("x".repeat(MAX_COMMAND_ARGV_SLOT_BYTES + 1)).is_err()); + } + + #[test] + fn executable_admission_rejects_every_control_code_point() { + for exec in [ + "/bin/true", + "/usr/lib/d2b/libexec/virtiofsd", + "/bin/caf\u{e9}", + ] { + assert!(CommandExec::parse(exec).is_ok(), "{exec:?}"); + } + for exec in [ + "/bin/true\u{0}", + "/bin/true\t", + "/bin/true\u{7f}", + "/bin/true\u{9f}", + ] { + assert!(CommandExec::parse(exec).is_err(), "{exec:?}"); + } + } } From 6e8f344068b57ee2ac24a75b0d54e35d22de4245 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:28:11 -0700 Subject: [PATCH 678/726] refactor(d2bd): scope the interaction and shared-effect locks per Zone The interaction runtime set stored its Zone compositions bare, so every ComponentSession dispatch held the daemon-global set lock across its awaits and a second Zone's dispatch waited behind it, as did the VM-start display reconcile. The set now holds one independently lockable composition per Zone and hands that handle out: the global slot is taken only to clone a handle (install/teardown and the daemon-wide scans), so a dispatch owns just its own Zone. The synchronous driver lookup, the VM-start reconcile, and the daemon-wide finalization take the handles the same way, and their documented rule is preserved: a contended Zone is reported once it is free, never as an absent source. The shared Provider effect adapter resolved its Zone resource runtime by spinning on try_lock, which a reconciler called from an async context burned on an executor worker. The async seat now awaits the plane slot, the two synchronous GPU authority seats use a fail-closed non-blocking seat that reports the runtime unavailable on a collision, and the Network runtime facet's trusted-bundle reload is awaited end to end on the bundle loader worker instead of spinning on the bundle slot. --- ...15-zone-handle-dispatch-and-async-locks.md | 26 + .../src/effects_service.rs | 4 +- .../d2b-provider-network-local/src/facets.rs | 7 +- .../src/test_support.rs | 2 +- packages/d2bd/src/composition.rs | 38 +- packages/d2bd/src/interaction_composition.rs | 554 +++++++++++------- packages/d2bd/src/shared_provider_effects.rs | 110 ++-- packages/xtask/data/async-gate-inventory.json | 60 +- 8 files changed, 486 insertions(+), 315 deletions(-) create mode 100644 changelog.d/w7-15-zone-handle-dispatch-and-async-locks.md diff --git a/changelog.d/w7-15-zone-handle-dispatch-and-async-locks.md b/changelog.d/w7-15-zone-handle-dispatch-and-async-locks.md new file mode 100644 index 000000000..a1c7259b4 --- /dev/null +++ b/changelog.d/w7-15-zone-handle-dispatch-and-async-locks.md @@ -0,0 +1,26 @@ +### Changed + +- The daemon's interaction runtime set holds one independently lockable + composition per Zone and hands that handle out instead of exposing the + compositions themselves. A ComponentSession dispatch holds only its + own Zone for the length of a request, so a second Zone's dispatch and + the VM-start display reconcile no longer wait behind an in-flight + request; the daemon-global slot is an install/teardown handle that is + released before any Zone is locked. +- The synchronous ComponentSession driver lookup and the daemon-wide + finalization take the daemon-global slot only to clone the per-Zone + handles, then lock each Zone in turn, so a contended Zone is reported + once it is free rather than as an absent source. +- The shared Provider effect adapter resolves its Zone resource runtime + by awaiting the plane slot, so concurrent reconcile and attach traffic + serializes on the slot instead of spinning an executor worker. The + synchronous GPU authority seats keep a non-blocking seat and report + the runtime unavailable on a collision instead of spinning. + +### Fixed + +- The Network runtime facet's trusted-bundle reload is awaited end to + end: the `NetworkRuntime::bundle` seat and its callers are async, and + the reload runs on the bundle loader worker, so serving a bundle fact + no longer spins a worker on the bundle slot or on the synchronous + read-and-verify of the on-disk bundle. diff --git a/packages/d2b-provider-network-local/src/effects_service.rs b/packages/d2b-provider-network-local/src/effects_service.rs index 61f87683b..363854933 100644 --- a/packages/d2b-provider-network-local/src/effects_service.rs +++ b/packages/d2b-provider-network-local/src/effects_service.rs @@ -101,7 +101,7 @@ async fn serve_inspect_network( service: NETWORK_EFFECTS_SERVICE.id.to_owned(), reason: reason.to_owned(), }; - let bundle = runtime.bundle(); + let bundle = runtime.bundle().await; let installed = bundle .installed_generation_identity() .ok_or_else(|| declined("inspect-network-installed-generation-unavailable"))?; @@ -203,7 +203,7 @@ mod tests { #[async_trait] impl NetworkRuntime for ScriptedRuntime { - fn bundle(&self) -> std::sync::Arc { + async fn bundle(&self) -> std::sync::Arc { std::sync::Arc::new(self.bundle.clone()) } fn broker_socket_path(&self) -> &std::path::Path { diff --git a/packages/d2b-provider-network-local/src/facets.rs b/packages/d2b-provider-network-local/src/facets.rs index 0a916ffd7..5b9c74f65 100644 --- a/packages/d2b-provider-network-local/src/facets.rs +++ b/packages/d2b-provider-network-local/src/facets.rs @@ -68,9 +68,10 @@ pub trait NetworkRuntime: Send + Sync + 'static { /// The daemon implementation loads a fresh, fully re-verified resolver /// per invocation (the retired adapter's per-call reload), so an /// on-disk bundle replacement is observed without a daemon restart; the - /// owned `Arc` keeps the served resolver valid for the caller's - /// synchronous read. - fn bundle(&self) -> Arc; + /// owned `Arc` keeps the served resolver valid for the caller's read. + /// The seat is async because the reload re-reads and re-verifies the + /// on-disk bundle, which must not park an executor worker. + async fn bundle(&self) -> Arc; /// The authenticated daemon-to-broker origination socket one kernel /// invocation goes over. diff --git a/packages/d2b-provider-network-local/src/test_support.rs b/packages/d2b-provider-network-local/src/test_support.rs index 8ba67a785..69cf0f510 100644 --- a/packages/d2b-provider-network-local/src/test_support.rs +++ b/packages/d2b-provider-network-local/src/test_support.rs @@ -49,7 +49,7 @@ impl RecordingRuntime { #[async_trait] impl NetworkRuntime for RecordingRuntime { - fn bundle(&self) -> Arc { + async fn bundle(&self) -> Arc { Arc::new(FIXTURE_BUNDLE.clone()) } diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index dcc02d2be..cc683682e 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -4937,22 +4937,21 @@ async fn finalize_daemon_interactions(state: &ServerState) -> Result<(), TypedEr { listeners.stop().await; } - let interaction_error = { - let mut runtime = state.interaction_runtime.lock().await; - if let Some(runtime) = runtime.as_mut() - && let Err(error) = runtime - .finalize_async(d2b_provider_display_wayland::GraceState::Expired) - .await - { + let interaction_error = match interaction_composition::finalize_interaction_runtimes( + &state.interaction_runtime, + d2b_provider_display_wayland::GraceState::Expired, + ) + .await + { + Some(error) => { tracing::error!(?error, "interaction Provider finalization failed"); Some(TypedError::InternalIo { context: "interaction Provider finalization".to_owned(), detail: error.to_string(), source: error_source(error), }) - } else { - None } + None => None, }; let runtime = state.interaction_runtime.lock().await.take(); // The interaction composition retains the Resource API client used by @@ -16142,15 +16141,18 @@ fn reconcile_display_before_vm_start( else { return Err("display-session-missing".to_owned()); }; - let result = { - let mut interactions = drive_sync(&state.runtime_handle, state.interaction_runtime.lock()); - let runtime_set = interactions - .as_mut() - .ok_or_else(|| "display-interaction-runtime-unavailable".to_owned())?; - runtime_set - .reconcile_committed_display_for_vm_start(&zone, vm, &session_ref, &session_uid, &spec) - .map_err(|error| error.to_string())? - }; + let result = drive_sync(&state.runtime_handle, async { + interaction_composition::reconcile_committed_display_for_vm_start( + &state.interaction_runtime, + &zone, + vm, + &session_ref, + &session_uid, + &spec, + ) + .await + .map_err(|error| error.to_string()) + })?; if result.status.phase == d2b_provider_display_wayland::Phase::Failed { return Err("display-session-reconcile-failed".to_owned()); } diff --git a/packages/d2bd/src/interaction_composition.rs b/packages/d2bd/src/interaction_composition.rs index d31732eb1..1da2bf2d1 100644 --- a/packages/d2bd/src/interaction_composition.rs +++ b/packages/d2bd/src/interaction_composition.rs @@ -427,11 +427,18 @@ where } /// Daemon-owned collection of independently Zone-bound compositions. +/// +/// Every Zone keeps its own composition behind its own lock, so an +/// in-flight dispatch holds only the Zone it belongs to: a second Zone's +/// dispatch and the VM-start display reconcile never queue behind it. The +/// daemon-global slot that holds this set is an install/teardown handle +/// only - a caller takes it to clone one per-Zone handle and drops it +/// before locking that handle. pub struct InteractionRuntimeSet where S: ProcessLaunchEffectPort + Clone + Send + Sync + 'static, { - runtimes: BTreeMap>, + runtimes: BTreeMap>>>, } impl core::fmt::Debug for InteractionRuntimeSet @@ -459,7 +466,8 @@ where /// Insert one fully Zone-bound runtime. pub fn insert(&mut self, zone: ZoneId, runtime: InteractionComposition) { - self.runtimes.insert(zone.as_str().to_owned(), runtime); + self.runtimes + .insert(zone.as_str().to_owned(), Arc::new(AsyncMutex::new(runtime))); } /// Return whether any Zone runtime is installed. @@ -472,72 +480,123 @@ where self.runtimes.keys().map(String::as_str) } - fn runtime_for(&self, zone: &ZoneId) -> Option<&InteractionComposition> { - self.runtimes.get(zone.as_str()) + /// Clone one Zone's composition handle. The caller locks the handle for + /// as long as it owns that Zone's composition - never the set that + /// handed it out. + pub(crate) fn runtime_handle( + &self, + zone: &ZoneId, + ) -> Option>>> { + self.runtimes.get(zone.as_str()).cloned() } - fn runtime_for_mut(&mut self, zone: &ZoneId) -> Option<&mut InteractionComposition> { - self.runtimes.get_mut(zone.as_str()) + /// Every installed Zone handle, in Zone order. + fn runtime_handles(&self) -> Vec>>> { + self.runtimes.values().cloned().collect() } +} - /// Reconcile the committed WaylandSession for one exact VM before its - /// process DAG waits on the Host proxy socket. - pub(crate) fn reconcile_committed_display_for_vm_start( - &mut self, - zone: &ZoneId, - vm: &str, - session_ref: &ResourceRef, - session_uid: &ResourceUid, - spec: &WaylandSessionSpec, - ) -> Result { - self.runtime_for_mut(zone) - .ok_or(DisplayRuntimeError::SessionUnauthenticated)? - .reconcile_committed_display_for_vm_start(vm, session_ref, session_uid, spec) - } +/// The sole driver of a Zone-by-Zone scan: absent or ambiguous fails closed. +fn sole_driver( + drivers: Vec, +) -> Option { + let mut drivers = drivers.into_iter(); + let driver = drivers.next()?; + drivers.next().is_none().then_some(driver) +} - /// Find the sole authenticated ComponentSession owned by one exact - /// execution target and service across the daemon's Zone compositions. - /// Absent, stale, or ambiguous sources fail closed. - pub fn component_session_driver_for_target( - &self, - service: &str, - target: &ResourceRef, - ) -> Option { - let mut drivers = self - .runtimes - .values() - .filter_map(|runtime| runtime.component_session_driver_for_target(service, target)); - let driver = drivers.next()?; - drivers.next().is_none().then_some(driver) +/// Reconcile the committed WaylandSession of one Zone for one exact VM +/// before its process DAG waits on the Host proxy socket. +/// +/// The set lock is taken only to clone that Zone's handle and is released +/// before the composition is locked, so a VM start in one Zone does not +/// queue behind another Zone's in-flight dispatch. +pub(crate) async fn reconcile_committed_display_for_vm_start( + runtime: &Arc>>>, + zone: &ZoneId, + vm: &str, + session_ref: &ResourceRef, + session_uid: &ResourceUid, + spec: &WaylandSessionSpec, +) -> Result +where + S: ProcessLaunchEffectPort + Clone + Send + Sync + 'static, +{ + let handle = { + let guard = runtime.lock().await; + guard.as_ref().and_then(|set| set.runtime_handle(zone)) } + .ok_or(DisplayRuntimeError::SessionUnauthenticated)?; + handle + .lock() + .await + .reconcile_committed_display_for_vm_start(vm, session_ref, session_uid, spec) +} - async fn remove_session(&mut self, zone: &ZoneId, session_key: &str) -> Result<(), String> { - self.runtime_for_mut(zone) - .ok_or_else(|| "interaction runtime unavailable".to_owned())? - .remove_session(session_key) - .await +/// Finalize every Zone composition of one daemon-owned runtime set, +/// retaining each Zone's failed state for retry. +/// +/// The set lock is taken only to clone the per-Zone handles and is released +/// before any Zone is finalized, so no outer guard is held across a Zone's +/// awaits. The first failure is returned; `None` means no Zone composition +/// is installed or all of them finalized. +pub async fn finalize_interaction_runtimes( + runtime: &Arc>>>, + grace: d2b_provider_display_wayland::GraceState, +) -> Option +where + S: ProcessLaunchEffectPort + Clone + Send + Sync + 'static, +{ + let handles = { + let guard = runtime.lock().await; + guard.as_ref()?.runtime_handles() + }; + let mut failure = None; + for handle in handles { + let mut handle = handle.lock().await; + if let Err(error) = handle.finalize_async(grace).await { + failure.get_or_insert(error); + } } + failure +} - /// Finalize every Zone composition, retaining failed state for retry. - pub async fn finalize_async( - &mut self, - grace: d2b_provider_display_wayland::GraceState, - ) -> Result<(), InteractionFinalizeError> { - let zones = self.runtimes.keys().cloned().collect::>(); - let mut failure = None; - for zone in zones { - if let Some(runtime) = self.runtimes.get_mut(&zone) - && let Err(error) = runtime.finalize_async(grace).await - { - failure.get_or_insert(error); - } - } - failure.map_or(Ok(()), Err) +/// Find the sole authenticated ComponentSession owned by one exact +/// execution target and service across the daemon's Zone compositions. +/// Absent, stale, or ambiguous sources fail closed. +/// +/// The set lock is taken only to clone the per-Zone handles and is released +/// before any of them is locked; the handles are then locked one at a time, +/// so a contended Zone reports its composition once it is free instead of +/// being reported as an absent source. +pub async fn component_session_driver_for_service( + runtime: &Arc>>>, + service: &str, + target: &ResourceRef, +) -> Option +where + S: ProcessLaunchEffectPort + Clone + Send + Sync + 'static, +{ + let handles = { + let guard = runtime.lock().await; + guard.as_ref()?.runtime_handles() + }; + let mut drivers = Vec::new(); + for handle in handles { + let handle = handle.lock().await; + drivers.extend(handle.component_session_driver_for_target(service, target)); } + sole_driver(drivers) } /// Resolve one exact service-owned ComponentSession without converting a /// contended runtime lock into an absent source. +/// +/// Synchronous seat: the set lock is taken only to clone the per-Zone +/// handles and is released before any of them is locked, so a caller parked +/// in a dispatch holds nothing this needs. A contended Zone handle waits +/// rather than reporting the driver as absent - the same fail-closed rule +/// the async seat follows. pub(crate) fn blocking_component_session_driver_for_service( runtime: &Arc>>>, service: &str, @@ -546,10 +605,16 @@ pub(crate) fn blocking_component_session_driver_for_service( where S: ProcessLaunchEffectPort + Clone + Send + Sync + 'static, { - let runtime = runtime.blocking_lock(); - runtime - .as_ref() - .and_then(|runtime| runtime.component_session_driver_for_target(service, target)) + let handles = { + let guard = runtime.blocking_lock(); + guard.as_ref()?.runtime_handles() + }; + let mut drivers = Vec::new(); + for handle in handles { + let handle = handle.blocking_lock(); + drivers.extend(handle.component_session_driver_for_target(service, target)); + } + sole_driver(drivers) } impl Default for InteractionRuntimeSet @@ -5451,12 +5516,17 @@ where .await .map_err(|_| "interaction-handshake-timeout".to_owned())? .map_err(|error| error.to_string())?; - let acceptor = { + // The Zone handle is cloned out of the install/teardown lock and that + // lock is dropped before the composition is taken: this session holds + // only its own Zone for the rest of its life, so a second Zone's session + // and the VM-start display reconcile never wait behind its dispatch. + let zone_runtime = { let guard = runtime.lock().await; - let composition = guard - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .ok_or_else(|| "interaction runtime unavailable".to_owned())?; + guard.as_ref().and_then(|set| set.runtime_handle(&zone)) + } + .ok_or_else(|| "interaction runtime unavailable".to_owned())?; + let acceptor = { + let composition = zone_runtime.lock().await; composition .registrar() .component_session_acceptor(policy, verified_peer) @@ -5470,11 +5540,7 @@ where ), ); let request_receiver = { - let mut guard = runtime.lock().await; - let composition = guard - .as_mut() - .and_then(|set| set.runtime_for_mut(&zone)) - .ok_or_else(|| "interaction runtime unavailable".to_owned())?; + let mut composition = zone_runtime.lock().await; let registered = composition .admit_and_register_for_service(acceptor, engine, evidence, 1, &service) .await @@ -5531,23 +5597,9 @@ where } else { Vec::new() }; - // Residual, recorded rather than half-fixed: this session's request - // dispatch holds the *global* runtime-set lock across its awaits, so - // another Zone's session (and the VM-start display reconcile) waits - // behind it. Removing the hold means the set must hand out a per-Zone - // handle (`BTreeMap>>`) - // so the outer lock is taken only to clone that handle - which also - // moves `reconcile_committed_display_for_vm_start` and - // `component_session_driver_for_target` off their synchronous seats, - // and the latter's documented rule is that a contended lock is never - // reported as an absent source. That is a design change to the - // interaction runtime's ownership, not a seat swap, and it needs its - // own concurrency test. - let mut guard = runtime.lock().await; - let composition = guard - .as_mut() - .and_then(|set| set.runtime_for_mut(&zone)) - .ok_or_else(|| "interaction runtime unavailable".to_owned())?; + // Only this Zone's composition is held across the dispatch, so a + // second Zone's request is dispatched while this one is in flight. + let mut composition = zone_runtime.lock().await; if let Err(error) = composition .dispatch_component_request_for_session(&session_key, frame, attachments) .await @@ -5558,12 +5610,7 @@ where break; } } - let mut guard = runtime.lock().await; - guard - .as_mut() - .ok_or_else(|| "interaction runtime unavailable".to_owned())? - .remove_session(&zone, &session_key) - .await?; + zone_runtime.lock().await.remove_session(&session_key).await?; Ok(()) } @@ -6291,6 +6338,44 @@ mod tests { type TestInteractionRuntime = Arc>>>>; + /// Clone one Zone's composition handle out of the daemon-global slot. + async fn zone_runtime_handle( + runtime: &TestInteractionRuntime, + zone: &ZoneId, + ) -> Arc>>> { + let handle = { + let guard = runtime.lock().await; + guard.as_ref().and_then(|set| set.runtime_handle(zone)) + }; + handle.expect("interaction runtime unavailable") + } + + /// The session count of one Zone's composition, read under that Zone's + /// own handle rather than the daemon-global slot. + async fn zone_session_count(runtime: &TestInteractionRuntime, zone: &ZoneId) -> Option { + let handle = { + let guard = runtime.lock().await; + guard.as_ref().and_then(|set| set.runtime_handle(zone)) + }?; + Some(handle.lock().await.session_count()) + } + + /// Whether one Zone's composition admitted a session for `service`. + async fn zone_has_service_session( + runtime: &TestInteractionRuntime, + zone: &ZoneId, + service: &str, + ) -> bool { + let handle = { + let guard = runtime.lock().await; + guard.as_ref().and_then(|set| set.runtime_handle(zone)) + }; + let Some(handle) = handle else { + return false; + }; + handle.lock().await.has_service_session(service) + } + #[test] fn durable_display_process_payloads_bind_owner_provider_template_and_target() { let supervisor = d2b_provider_supervisor::ProviderSupervisor::new(Backend::default()); @@ -6605,24 +6690,14 @@ mod tests { .expect("client handshake timeout") .expect("client handshake failed"); for _ in 0..100 { - let admitted = runtime - .lock() - .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .is_some_and(|composition| composition.session_count() == 1); - if admitted { + if zone_session_count(&runtime, &zone).await == Some(1) { break; } tokio::time::sleep(Duration::from_millis(10)).await; } - assert!( - runtime - .lock() - .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .is_some_and(|composition| composition.session_count() == 1), + assert_eq!( + zone_session_count(&runtime, &zone).await, + Some(1), "the reactor accept loop admitted the connecting client" ); engine.close( @@ -6668,13 +6743,7 @@ mod tests { ) .await; for _ in 0..50 { - if runtime - .lock() - .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .is_some_and(|composition| composition.session_count() == 2) - { + if zone_session_count(&runtime, &zone).await == Some(2) { break; } tokio::time::sleep(Duration::from_millis(1)).await; @@ -6682,11 +6751,8 @@ mod tests { let target = ResourceRef::parse(&format!("Guest/uid-{uid}")).unwrap(); let display_target = ResourceRef::parse("Host/host-system").unwrap(); let missing = ResourceRef::parse("Guest/missing").unwrap(); - let guard = runtime.lock().await; - let composition = guard - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .expect("runtime"); + let composition = zone_runtime_handle(&runtime, &zone).await; + let composition = composition.lock().await; assert!( composition .component_session_driver_for_target(PROCESS_ATTACH_SERVICE, &target,) @@ -6714,7 +6780,7 @@ mod tests { .is_none(), "an absent target must remain fail-closed" ); - drop(guard); + drop(composition); let stream = d2b_session::StreamId::new(0x101).unwrap(); process_client @@ -6726,13 +6792,10 @@ mod tests { .await .unwrap(); let process_driver = { - let guard = runtime.lock().await; - guard - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .and_then(|composition| { - composition.component_session_driver_for_target(PROCESS_ATTACH_SERVICE, &target) - }) + let composition = zone_runtime_handle(&runtime, &zone).await; + let composition = composition.lock().await; + composition + .component_session_driver_for_target(PROCESS_ATTACH_SERVICE, &target) .expect("Process session driver") }; process_driver @@ -6782,29 +6845,20 @@ mod tests { drop(process_client); for _ in 0..1_000 { - if runtime - .lock() - .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .is_some_and(|composition| composition.session_count() == 1) - { + if zone_session_count(&runtime, &zone).await == Some(1) { break; } tokio::time::sleep(Duration::from_millis(1)).await; } - let guard = runtime.lock().await; - let composition = guard - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .expect("runtime"); + let composition = zone_runtime_handle(&runtime, &zone).await; + let composition = composition.lock().await; assert!( composition .component_session_driver_for_target(PROCESS_ATTACH_SERVICE, &target) .is_none(), "a disconnected Process source must be removed rather than reused" ); - drop(guard); + drop(composition); display_server.abort(); process_server.abort(); drop(display_listener); @@ -6830,39 +6884,34 @@ mod tests { ) .await; for _ in 0..50 { - if runtime - .lock() - .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .is_some_and(|composition| composition.session_count() == 1) - { + if zone_session_count(&runtime, &zone).await == Some(1) { break; } tokio::time::sleep(Duration::from_millis(1)).await; } let target = ResourceRef::parse(&format!("Guest/uid-{uid}")).unwrap(); - let guard = runtime.lock().await; + // An in-flight dispatch of this Zone holds its own composition + // handle: the daemon-wide lookup must wait for it rather than report + // the enrolled source as absent. + let zone_composition = zone_runtime_handle(&runtime, &zone).await; + let zone_guard = zone_composition.lock().await; let lookup_runtime = Arc::clone(&runtime); - // U13: the contended-lookup assertion now drives the async lock - // directly (the sync `blocking_lock` seat stays for the sync - // dispatch caller at composition.rs:3322); the contention semantics - // are unchanged (R13: no timing change). + let lookup_target = target.clone(); let mut lookup = tokio::spawn(async move { - let runtime = lookup_runtime.lock().await; - runtime - .as_ref() - .and_then(|runtime| { - runtime.component_session_driver_for_target(PROCESS_ATTACH_SERVICE, &target) - }) + component_session_driver_for_service( + &lookup_runtime, + PROCESS_ATTACH_SERVICE, + &lookup_target, + ) + .await }); assert!( tokio::time::timeout(Duration::from_millis(20), &mut lookup) .await .is_err(), - "runtime contention must not be reported as an absent source" + "a contended Zone must not be reported as an absent source" ); - drop(guard); + drop(zone_guard); assert!( tokio::time::timeout(Duration::from_secs(1), &mut lookup) .await @@ -7062,6 +7111,27 @@ mod tests { runtimes } + /// One identity-bound (committed) composition for a Zone. + fn committed_test_interaction_composition( + zone: &ZoneId, + transport_uid: u32, + ) -> InteractionComposition> { + test_interaction_composition_with_identity( + zone, + transport_uid, + ResourceRef::parse("Guest/work").unwrap(), + ResourceUid::parse("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa").unwrap(), + ResourceRef::parse("Host/host").unwrap(), + ResourceRef::parse("User/alice").unwrap(), + 7, + Some(11), + Some(13), + 17, + None, + None, + ) + } + fn committed_test_interaction_runtime( zone: &ZoneId, transport_uid: u32, @@ -7069,22 +7139,115 @@ mod tests { let mut runtimes = InteractionRuntimeSet::new(); runtimes.insert( zone.clone(), - test_interaction_composition_with_identity( - zone, - transport_uid, + committed_test_interaction_composition(zone, transport_uid), + ); + runtimes + } + + /// Two Zones' sessions dispatch concurrently instead of serializing. + /// + /// A session loop holds only its own Zone's composition for the whole + /// request, including its awaits, while the daemon-global slot is already + /// released. A second Zone's dispatch therefore reaches its own + /// composition and answers while the first Zone's composition is still + /// held; under the daemon-global lock it waited behind it. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn zone_dispatches_do_not_serialize_behind_another_zone() { + let directory = tempfile::tempdir().unwrap(); + let uid = nix::unistd::getuid().as_raw(); + let zone_a = ZoneId::parse("work").unwrap(); + let zone_b = ZoneId::parse("dev").unwrap(); + let service = d2b_provider_display_wayland::SERVICE_PACKAGE; + let mut runtimes = InteractionRuntimeSet::new(); + runtimes.insert( + zone_a.clone(), + committed_test_interaction_composition(&zone_a, uid), + ); + runtimes.insert( + zone_b.clone(), + committed_test_interaction_composition(&zone_b, uid), + ); + let runtime = Arc::new(AsyncMutex::new(Some(runtimes))); + + let path_a = directory.path().join("work.sock"); + let listener_a = bind_interaction_listener(&path_a, uid).await.unwrap(); + let (zone_a_client, zone_a_server) = + establish_test_client(&listener_a, &runtime, &zone_a, service, uid, &path_a).await; + let path_b = directory.path().join("dev.sock"); + let listener_b = bind_interaction_listener(&path_b, uid).await.unwrap(); + let (zone_b_client, zone_b_server) = + establish_test_client(&listener_b, &runtime, &zone_b, service, uid, &path_b).await; + for zone in [&zone_a, &zone_b] { + for _ in 0..50 { + if zone_has_service_session(&runtime, zone, service).await { + break; + } + tokio::time::sleep(Duration::from_millis(1)).await; + } + assert!( + zone_has_service_session(&runtime, zone, service).await, + "each Zone admits its own display session" + ); + } + + let spec = |name: &str| { + WaylandSessionSpec::new( ResourceRef::parse("Guest/work").unwrap(), - ResourceUid::parse("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa").unwrap(), ResourceRef::parse("Host/host").unwrap(), ResourceRef::parse("User/alice").unwrap(), - 7, - Some(11), - Some(13), - 17, - None, - None, - ), + ResourceRef::parse("display-wayland.d2bus.org.WaylandPolicy/display-wayland") + .unwrap(), + d2b_provider_display_wayland::DisplayIdentity::new( + name, "#112233", "#223344", "#334455", + ) + .unwrap(), + true, + ) + .unwrap() + }; + + // Zone A's in-flight dispatch owns Zone A's composition. + let zone_a_composition = zone_runtime_handle(&runtime, &zone_a).await; + let zone_a_dispatch = zone_a_composition.lock().await; + + let zone_b_reconcile = dispatch_test_request( + &zone_b_client, + service, + 200, + "DisplayService/Reconcile", + serde_json::to_vec(&serde_json::json!({"spec": spec("zone-b")})).unwrap(), + ) + .await; + assert_eq!( + zone_b_reconcile.status().code(), + TtrpcCode::OK, + "Zone B's dispatch must not wait behind Zone A's in-flight dispatch" ); - runtimes + assert!( + zone_a_composition.try_lock().is_err(), + "Zone A's composition is still held by its in-flight dispatch" + ); + + drop(zone_a_dispatch); + assert!( + zone_a_composition.try_lock().is_ok(), + "Zone A's composition frees as soon as its dispatch releases it" + ); + let zone_a_reconcile = dispatch_test_request( + &zone_a_client, + service, + 201, + "DisplayService/Reconcile", + serde_json::to_vec(&serde_json::json!({"spec": spec("zone-a")})).unwrap(), + ) + .await; + assert_eq!(zone_a_reconcile.status().code(), TtrpcCode::OK); + + zone_a_server.abort(); + zone_b_server.abort(); + drop(listener_a); + drop(listener_b); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -7108,14 +7271,8 @@ mod tests { ) .await; for _ in 0..50 { - if runtime - .lock() + if zone_has_service_session(&runtime, &zone, d2b_provider_display_wayland::SERVICE_PACKAGE) .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .is_some_and(|composition| { - composition.has_service_session(d2b_provider_display_wayland::SERVICE_PACKAGE) - }) { break; } @@ -7141,11 +7298,8 @@ mod tests { let session_uid = ResourceUid::parse("33333333-3333-4333-8333-333333333333").expect("session uid"); - let mut guard = runtime.lock().await; - let composition = guard - .as_mut() - .and_then(|set| set.runtime_for_mut(&zone)) - .expect("committed interaction composition"); + let composition = zone_runtime_handle(&runtime, &zone).await; + let mut composition = composition.lock().await; let result = composition .reconcile_committed_display_for_vm_start("work", &session_ref, &session_uid, &spec) .expect("committed display reconciliation"); @@ -7169,7 +7323,7 @@ mod tests { .is_err(), "a VM start for a different Guest must not reuse the committed session" ); - drop(guard); + drop(composition); server.abort(); drop(listener); } @@ -7416,11 +7570,8 @@ mod tests { clients.push((service, path, listener, client, server)); } { - let guard = runtime.lock().await; - let composition = guard - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .expect("committed interaction composition"); + let composition = zone_runtime_handle(&runtime, &zone).await; + let composition = composition.lock().await; let display_route = composition .route_for_service(d2b_provider_display_wayland::SERVICE_PACKAGE) .expect("display route"); @@ -7716,15 +7867,7 @@ mod tests { for (_, _, _, _, server) in clients { assert!(server.await.unwrap().is_ok()); } - assert_eq!( - runtime - .lock() - .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .map_or(0, InteractionComposition::session_count), - 0 - ); + assert_eq!(zone_session_count(&runtime, &zone).await, Some(0)); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -8192,11 +8335,8 @@ mod tests { .await; assert_eq!(reconcile.status().code(), TtrpcCode::OK); { - let guard = runtime.lock().await; - let composition = guard - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .unwrap(); + let composition = zone_runtime_handle(&runtime, &zone).await; + let composition = composition.lock().await; assert!( composition .display @@ -8456,15 +8596,7 @@ mod tests { let finalize = TtrpcResponse::parse_from_bytes(finalize_payload).unwrap(); assert_eq!(finalize.status().code(), TtrpcCode::OK); assert!(server.await.unwrap().is_ok()); - assert_eq!( - runtime - .lock() - .await - .as_ref() - .and_then(|set| set.runtime_for(&zone)) - .map_or(0, InteractionComposition::session_count), - 0 - ); + assert_eq!(zone_session_count(&runtime, &zone).await, Some(0)); let replay_frame = request_frame_for_test( d2b_provider_display_wayland::SERVICE_PACKAGE, diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 8e6a9dc69..c364c7633 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -214,11 +214,12 @@ pub(crate) struct ProductionSharedProviderEffects { /// resolver on every reconcile, finalize, and effect). intents: Arc, /// The last verified trusted bundle the runtime facet serves - /// ([`NetworkRuntime::bundle`]): `bundle()` reloads the on-disk bundle - /// per invocation and falls back to the last verified resolver when - /// the load fails, so an unreadable bundle never mints facts while the - /// reconcile, finalize, and kernel paths refuse closed. Seeded at - /// plane composition, which already verified the same bundle file. + /// ([`NetworkRuntime::bundle`]): `bundle()` re-verifies the on-disk + /// bundle per invocation on the bundle loader worker and falls back to + /// the last verified resolver when the load fails, so an unreadable + /// bundle never mints facts while the reconcile, finalize, and kernel + /// paths refuse closed. Seeded at plane composition, which already + /// verified the same bundle file. bundle: tokio::sync::Mutex>, /// The authenticated daemon-to-broker origination socket (U14). broker_socket: PathBuf, @@ -343,29 +344,41 @@ impl ProductionSharedProviderEffects { let _ = self.gpu_facets.set(gpu_facets); } - fn runtime(&self) -> Result, SharedProviderEffectError> { - // Synchronous caller on a tokio Mutex (plan U10): the slot's - // critical sections are single Assignment/attach operations - // (microseconds) and the pre-conversion std Mutex::lock serialized - // instead of refusing, so a collision spins on try_lock (lock_sync - // pattern, same as the broker rate limiter) rather than failing - // closed - concurrent reconcile/attach traffic must be serialized, - // never refused. - let plane = loop { - match self.state.resource_plane.try_lock() { - Ok(guard) => break guard, - Err(_) => std::hint::spin_loop(), - } - }; + /// Resolve this Zone's live resource runtime. + /// + /// Async seat: the plane slot's critical sections are single + /// Assignment/attach operations (microseconds), so concurrent + /// reconcile/attach traffic is serialized by awaiting the slot rather + /// than by spinning - a worker that spins on the slot stalls every task + /// on it, and refusing a collision would turn ordinary traffic into an + /// unavailable runtime. + async fn runtime(&self) -> Result, SharedProviderEffectError> { + let plane = self.state.resource_plane.lock().await; + plane + .as_ref() + .and_then(|plane| plane.zone(&self.zone).ok()) + .ok_or(SharedProviderEffectError::Unavailable) + } + + /// Resolve this Zone's live resource runtime without waiting for the + /// plane slot. + /// + /// Fail-closed seat for the synchronous trait boundaries that cannot + /// await ([`GpuRuntime::admit_authority`] and `release_authority`): a + /// collision reports the runtime unavailable instead of spinning a lock + /// on a thread the executor shares. + fn try_runtime(&self) -> Result, SharedProviderEffectError> { + let plane = self.state.resource_plane.try_lock().ok(); plane .as_ref() + .and_then(|plane| plane.as_ref()) .and_then(|plane| plane.zone(&self.zone).ok()) .ok_or(SharedProviderEffectError::Unavailable) } /// The published v3 plane (manager-backed live rows and status). - fn plane(&self) -> Result, SharedProviderEffectError> { - let runtime = self.runtime()?; + async fn plane(&self) -> Result, SharedProviderEffectError> { + let runtime = self.runtime().await?; runtime .v3_plane() .map_err(|_| SharedProviderEffectError::Unavailable) @@ -376,7 +389,7 @@ impl ProductionSharedProviderEffects { &self, target: &ResourceRef, ) -> Result, SharedProviderEffectError> { - let plane = self.plane()?; + let plane = self.plane().await?; let key = ResourceKey::new( self.zone.as_str(), target.resource_type().as_str(), @@ -396,7 +409,7 @@ impl ProductionSharedProviderEffects { &self, target: &ResourceRef, ) -> Result, SharedProviderEffectError> { - let plane = self.plane()?; + let plane = self.plane().await?; let key = ResourceKey::new( self.zone.as_str(), target.resource_type().as_str(), @@ -457,7 +470,7 @@ impl ProductionSharedProviderEffects { ) -> Result { let provider_ref = ResourceRef::parse(kind.provider_ref()) .map_err(|_| SharedProviderEffectError::InvalidResource)?; - let plane = self.plane()?; + let plane = self.plane().await?; let key = ResourceKey::new( self.zone.as_str(), provider_ref.resource_type().as_str(), @@ -1382,7 +1395,7 @@ impl ProductionSharedProviderEffects { ), SharedProviderEffectError, > { - let runtime = self.runtime()?; + let runtime = self.runtime().await?; if runtime.authority_zone_uid().is_none() { return Err(SharedProviderEffectError::Unavailable); } @@ -1517,7 +1530,7 @@ impl ProductionSharedProviderEffects { let resolver = crate::load_bundle_resolver_on_worker(&self.state) .await .map_err(|_| SharedProviderEffectError::Unavailable)?; - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let admission = self .network_admission(&runtime, request, &spec, &resolver) .await?; @@ -1595,7 +1608,7 @@ impl ProductionSharedProviderEffects { return Err(SharedProviderEffectError::InvalidResource); } let device_ref = key_ref(&request.target)?; - let runtime = self.runtime().inspect_err(|_| { + let runtime = self.runtime().await.inspect_err(|_| { tracing::warn!( device = %device_ref.to_canonical_string(), "TPM device reconcile refused: the Zone resource runtime is not attached", @@ -1723,7 +1736,7 @@ impl ProductionSharedProviderEffects { SharedProviderEffectPhase::Pending, )); } - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let services = runtime .committed_resources_of_type( d2b_provider_device_usbip::USB_SERVICE_RESOURCE_TYPE, @@ -1777,7 +1790,7 @@ impl ProductionSharedProviderEffects { SharedProviderEffectPhase::Ready, )); } - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let (zone_uid, zone_opted_in, mut port) = self.usbip_service_port(&runtime, request).await?; let mut lifecycle = d2b_provider_device_usbip::ServiceLifecycle::new( @@ -1809,7 +1822,7 @@ impl ProductionSharedProviderEffects { .ok_or(SharedProviderEffectError::InvalidResource)?, ) .map_err(|_| SharedProviderEffectError::InvalidResource)?; - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let zone_uid = runtime .authority_zone_uid() .cloned() @@ -1945,7 +1958,7 @@ impl ProductionSharedProviderEffects { } match component { SecurityKeyComponent::Service => { - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let mode = SharedProviderEffectMode::parse(request)?; if mode == SharedProviderEffectMode::Projection { let endpoint_ref = request @@ -2242,7 +2255,7 @@ impl ProductionSharedProviderEffects { request: &SharedProviderEffectRequest<'_>, ) -> Result { let device_ref = key_ref(&request.target)?.to_canonical_string(); - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let children = runtime .committed_resources_of_type(d2b_provider_device_usbip::USB_SERVICE_RESOURCE_TYPE) .await @@ -2264,7 +2277,7 @@ impl ProductionSharedProviderEffects { &self, request: &SharedProviderEffectRequest<'_>, ) -> Result { - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let service_ref = key_ref(&request.target)?.to_canonical_string(); let bindings = runtime .committed_resources_of_type( @@ -2286,7 +2299,7 @@ impl ProductionSharedProviderEffects { &self, request: &SharedProviderEffectRequest<'_>, ) -> Result { - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let device_ref = key_ref(&request.target)?.to_canonical_string(); let services = runtime .committed_resources_of_type( @@ -2368,7 +2381,7 @@ impl ProductionSharedProviderEffects { let resolver = crate::load_bundle_resolver_on_worker(&self.state) .await .map_err(|_| SharedProviderEffectError::Unavailable)?; - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let admission = self .network_admission(&runtime, request, &spec, &resolver) .await?; @@ -2500,7 +2513,7 @@ impl ProductionSharedProviderEffects { .and_then(Value::as_str) .and_then(|value| ResourceRef::parse(value).ok()) .unwrap_or_else(|| ResourceRef::parse(HOST_REF).expect("Host ref")); - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let vm_id = VmId::new(holder.name().as_str()); let migration_intent = BundleOpId::new(format!( "{}{}", @@ -2571,7 +2584,7 @@ impl ProductionSharedProviderEffects { &self, request: &SharedProviderEffectRequest<'_>, ) -> Result { - let runtime = self.runtime()?; + let runtime = self.runtime().await?; let service_ref = key_ref(&request.target)?.to_canonical_string(); let bindings = runtime .committed_resources_of_type(d2b_provider_device_usbip::USB_BINDING_RESOURCE_TYPE) @@ -2670,22 +2683,17 @@ impl ProductionSharedProviderEffects { // daemon-resolved bundle intents ([`NetworkIntentSource`]). #[async_trait] impl d2b_provider_network_local::NetworkRuntime for ProductionSharedProviderEffects { - fn bundle(&self) -> Arc { + async fn bundle(&self) -> Arc { // Per-invocation freshness, mirroring the retired adapter's per-call // reload: re-verify the on-disk bundle before serving any bundle // fact, so a replaced bundle is observed without a daemon restart. // The owned `Arc` keeps the served resolver valid for the caller's - // synchronous read even when a later invocation refreshes the slot. - // A bundle that fails verification keeps the last verified resolver - // (an unreadable bundle never mints facts), while the reconcile, + // read even when a later invocation refreshes the slot. A bundle + // that fails verification keeps the last verified resolver (an + // unreadable bundle never mints facts), while the reconcile, // finalize, and kernel paths refuse closed. - let mut slot = loop { - match self.bundle.try_lock() { - Ok(guard) => break guard, - Err(_) => std::hint::spin_loop(), - } - }; - if let Ok(resolver) = crate::load_bundle_resolver(&self.state) { + let mut slot = self.bundle.lock().await; + if let Ok(resolver) = crate::load_bundle_resolver_on_worker(&self.state).await { *slot = Arc::new(resolver); } Arc::clone(&slot) @@ -2890,7 +2898,7 @@ impl GpuRuntime for ProductionSharedProviderEffects { ) -> Result { let runtime = self - .runtime() + .try_runtime() .map_err(|_| d2b_provider_device_gpu::GpuEffectError::Transient)?; crate::drive_sync(&tokio::runtime::Handle::current(), async { runtime @@ -2908,7 +2916,7 @@ impl GpuRuntime for ProductionSharedProviderEffects { lease: &d2b_core_controller::authority::AuthorityLease, ) -> Result<(), d2b_provider_device_gpu::GpuEffectError> { let runtime = self - .runtime() + .try_runtime() .map_err(|_| d2b_provider_device_gpu::GpuEffectError::Transient)?; crate::drive_sync(&tokio::runtime::Handle::current(), async { runtime @@ -3019,6 +3027,7 @@ mod tests { let composed = effects .bundle() + .await .installed_generation_identity() .expect("composed bundle generation") .as_str() @@ -3037,6 +3046,7 @@ mod tests { write_v3_native_bundle(&state.config.artifacts.bundle_path, "replaced"); let replaced = effects .bundle() + .await .installed_generation_identity() .expect("replaced bundle generation") .as_str() diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 36de0fcda..5e393ccbf 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -53,12 +53,12 @@ }, { "file": "packages/d2b-broker/src/ops/nm.rs", - "line": 544, + "line": 543, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/ops/nm.rs", - "line": 570, + "line": 569, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1008,17 +1008,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10886, + "line": 10885, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26470, + "line": 26472, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26867, + "line": 26869, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1038,57 +1038,57 @@ }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1630, + "line": 1643, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1678, + "line": 1691, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 1703, + "line": 1716, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2134, + "line": 2147, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2523, + "line": 2536, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2556, + "line": 2569, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/shared_provider_effects.rs", - "line": 2612, + "line": 2625, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/tests/cloud_composition.rs", - "line": 61, + "line": 59, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/cloud_composition.rs", - "line": 80, + "line": 78, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/cloud_composition.rs", - "line": 94, + "line": 92, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/cloud_composition.rs", - "line": 489, + "line": 487, "reason": "test-support recorder lock" }, { @@ -1128,72 +1128,72 @@ }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 725, + "line": 726, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 749, + "line": 750, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 772, + "line": 773, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 800, + "line": 801, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1098, + "line": 1099, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1106, + "line": 1107, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1111, + "line": 1112, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1131, + "line": 1132, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1143, + "line": 1144, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1182, + "line": 1183, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1187, + "line": 1188, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1241, + "line": 1242, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1258, + "line": 1259, "reason": "test-support recorder lock" }, { "file": "packages/d2bd/tests/zone_provider_acceptance.rs", - "line": 1289, + "line": 1290, "reason": "test-support recorder lock" } ] From 814ad86b6a814af69830ceaed6bcd56431fe6837 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:33:35 -0700 Subject: [PATCH 679/726] refactor(d2b-contracts-broker): declare the controller-bootstrap take and the pidfd failure kinds The provider-controller bootstrap take leg hand-built its camelCase payload and read the `taken` verdict loosely, so a malformed broker reply read as "no escrow held" and the daemon replaced a controller whose bootstrap endpoint it had never claimed. The take request and response are now committed wire types, the leg sends the row's payload from the typed request, and the reply is parsed into the typed response: a reply that carries no result, a mistyped verdict, or a field the row does not declare fails the leg with a structured warning, while a `taken: false` verdict stays an absent result. The escrow descriptor is still the reply's sole attachment, taken at index 0. The pidfd failure kinds a broker pidfd dispatch reports are declared once in the broker wire contract, the live handler maps its pidfd variants through that vocabulary, and the open-pidfd refusal detail names the kind the caller classifies the failure by. The daemon-side test that pinned those names by scraping the broker's source now asserts over the shared constant, so a rename can no longer pass unnoticed on one side. --- ...13-typed-bootstrap-and-pidfd-vocabulary.md | 17 + packages/d2b-broker/src/kernel_ops.rs | 60 ++- packages/d2b-broker/src/live_handlers.rs | 69 ++++ .../d2b-contracts-broker/src/broker_wire.rs | 51 +++ .../d2b-provider-supervisor/src/broker.rs | 358 ++++++++++++++++-- 5 files changed, 532 insertions(+), 23 deletions(-) create mode 100644 changelog.d/w7-13-typed-bootstrap-and-pidfd-vocabulary.md diff --git a/changelog.d/w7-13-typed-bootstrap-and-pidfd-vocabulary.md b/changelog.d/w7-13-typed-bootstrap-and-pidfd-vocabulary.md new file mode 100644 index 000000000..5673152a6 --- /dev/null +++ b/changelog.d/w7-13-typed-bootstrap-and-pidfd-vocabulary.md @@ -0,0 +1,17 @@ +### Changed + +- The provider-controller bootstrap take leg sends and reads the + committed `take-controller-bootstrap` row as a typed request/response + pair instead of a hand-built payload and a loose field read, and a + reply that does not carry the committed response is a hard failure + naming the failed broker call. Such a reply previously read as "no + escrow held" and replaced a controller whose bootstrap endpoint the + daemon had not claimed. + +- The pidfd failure kinds a broker pidfd dispatch reports are declared + once, in the broker wire contract, and the live handler maps its pidfd + variants through that vocabulary. The open-pidfd refusal detail now + names the kind instead of leaving it implicit in the display text, and + the daemon side no longer reads the broker's source to learn the + names. + diff --git a/packages/d2b-broker/src/kernel_ops.rs b/packages/d2b-broker/src/kernel_ops.rs index 5f4df7ca3..f3a08d0b4 100644 --- a/packages/d2b-broker/src/kernel_ops.rs +++ b/packages/d2b-broker/src/kernel_ops.rs @@ -233,7 +233,7 @@ async fn open_pidfd( let pid = field_i64(invocation.payload, "pid")? as i32; let expected_start_time_ticks = field_i64(invocation.payload, "expectedStartTimeTicks")? as u64; let outcome = crate::live_handlers::live_open_pidfd(pid, expected_start_time_ticks) - .map_err(|error| errored(format!("open-pidfd: {error}")))?; + .map_err(|error| pidfd_open_failure(&error))?; Ok(DispatchOutcome { result: canonical(serde_json::json!({ "pid": outcome.pid, @@ -243,6 +243,17 @@ async fn open_pidfd( }) } +/// The dispatch failure of one failed pidfd-open kernel step: the handler's +/// shared failure kind, then its own detail text. The kind is the one the +/// daemon-side classifier reads off this leg, so the refusal names it +/// instead of leaving it implicit in the display text. +fn pidfd_open_failure(error: &crate::live_handlers::LiveHandlerError) -> DispatchFailure { + match error.pidfd_dispatch_failure() { + Some(kind) => errored(format!("open-pidfd: {kind}: {error}")), + None => errored(format!("open-pidfd: {error}")), + } +} + /// The peer-pidfd kernel: derive the accepted socket's peer pidfd via /// `SO_PEERPIDFD`, exactly as the retired `OpenPeerPidfdFromAcceptedSocket` /// arm's sys layer ran it. The pidfd travels back over the fd leg. @@ -2608,4 +2619,51 @@ mod tests { ); assert_eq!(parse_proc_state("no close paren"), None); } + + /// An open-pidfd refusal names the failure kind the caller classifies + /// it by, from the shared vocabulary: without it a pidfd-open refusal + /// and a race refusal read as the same unlabelled error in the log. + #[test] + fn open_pidfd_refusals_name_the_shared_failure_kind() { + use crate::live_handlers::LiveHandlerError; + + let [pidfd_race, pidfd_open_failed, proc_stat_read_failed] = + d2b_contracts_broker::broker_wire::PIDFD_DISPATCH_FAILURE_KINDS; + for (kind, error) in [ + ( + pidfd_open_failed, + LiveHandlerError::PidfdOpenFailed { + pid: 7, + detail: "ESRCH".to_owned(), + }, + ), + ( + pidfd_race, + LiveHandlerError::PidfdRace { + pid: 7, + expected_start_time_ticks: 2, + observed_start_time_ticks: Some(3), + }, + ), + ( + proc_stat_read_failed, + LiveHandlerError::ProcStatReadFailed { + pid: 7, + detail: "EIO".to_owned(), + }, + ), + ] { + let failure = pidfd_open_failure(&error); + assert_eq!( + failure.code, + crate::envelope::HANDLER_ERRORED, + "the kernel leg keeps reporting the handler-errored refusal" + ); + let detail = failure.detail.expect("the refusal carries its detail"); + assert!( + detail.starts_with(&format!("open-pidfd: {kind}: ")), + "the refusal must name the shared kind {kind}: {detail}" + ); + } + } } diff --git a/packages/d2b-broker/src/live_handlers.rs b/packages/d2b-broker/src/live_handlers.rs index 6a607bafe..e631ea219 100644 --- a/packages/d2b-broker/src/live_handlers.rs +++ b/packages/d2b-broker/src/live_handlers.rs @@ -146,6 +146,40 @@ impl std::fmt::Display for LiveHandlerError { impl std::error::Error for LiveHandlerError {} +impl LiveHandlerError { + /// The pidfd dispatch failure kind this error reports, when it is one + /// of the pidfd handler failures. + /// + /// The names are the shared vocabulary in + /// [`d2b_contracts_broker::broker_wire::PIDFD_DISPATCH_FAILURE_KINDS`], + /// which is what a pidfd dispatch labels a failure with and what a + /// caller classifying that failure reads: mapping the variants through + /// the shared constant keeps the two spellings one constant, never two + /// literals that can drift. + pub fn pidfd_dispatch_failure(&self) -> Option<&'static str> { + let [pidfd_race, pidfd_open_failed, proc_stat_read_failed] = + d2b_contracts_broker::broker_wire::PIDFD_DISPATCH_FAILURE_KINDS; + match self { + Self::PidfdRace { .. } => Some(pidfd_race), + Self::PidfdOpenFailed { .. } => Some(pidfd_open_failed), + Self::ProcStatReadFailed { .. } => Some(proc_stat_read_failed), + Self::SpawnPreflight(_) + | Self::SpawnFailed { .. } + | Self::ReconcileExec(_) + | Self::UsbipLock(_) + | Self::HostInstall(_) + | Self::Activation(_) + | Self::Gc(_) + | Self::KeysRotate(_) + | Self::HostKey(_) + | Self::NmReload(_) + | Self::NmFileOwnership(_) + | Self::NmOwnershipConflict + | Self::SwtpmDirHardening { .. } => None, + } + } +} + /// Result of [`live_open_pidfd`]. #[derive(Debug)] pub struct OpenPidfdResult { @@ -5615,4 +5649,39 @@ mod tests { "the retry must keep attempting until the deadline" ); } + + /// The pidfd handler failures report the shared vocabulary's kinds, one + /// per variant and in its order: this is the producer half of the + /// contract a caller classifying a failed pidfd dispatch reads, so a + /// reordered or respelled kind here is a silent misclassification + /// there. + #[test] + fn pidfd_handler_failures_report_the_shared_kinds() { + let race = LiveHandlerError::PidfdRace { + pid: 1, + expected_start_time_ticks: 2, + observed_start_time_ticks: Some(3), + }; + let open_failed = LiveHandlerError::PidfdOpenFailed { + pid: 1, + detail: "ESRCH".to_owned(), + }; + let read_failed = LiveHandlerError::ProcStatReadFailed { + pid: 1, + detail: "EIO".to_owned(), + }; + assert_eq!( + [ + race.pidfd_dispatch_failure(), + open_failed.pidfd_dispatch_failure(), + read_failed.pidfd_dispatch_failure(), + ], + d2b_contracts_broker::broker_wire::PIDFD_DISPATCH_FAILURE_KINDS.map(Some), + ); + // A non-pidfd failure is never labelled as a pidfd dispatch failure. + assert_eq!( + LiveHandlerError::NmOwnershipConflict.pidfd_dispatch_failure(), + None + ); + } } diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 756e3c367..e28deec67 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -303,6 +303,17 @@ pub const DEFAULT_CONTEXT_DEADLINE_MS: u64 = 25_000; /// oversized handler grant. pub const MAX_CONTEXT_DEADLINE_MS: u64 = 60_000; +/// The failure kinds a broker pidfd dispatch reports. +/// +/// The live handler mints one of these names for every failure of a +/// pidfd dispatch, and the daemon side reads the same names when it +/// classifies a failed pidfd leg. Declaring the vocabulary once, here, +/// keeps the producer and the classifier from drifting apart on the +/// spelling of a kind neither can derive from the other - a mismatch +/// would make a handled failure look like an unclassified one. +pub const PIDFD_DISPATCH_FAILURE_KINDS: [&str; 3] = + ["PidfdRace", "PidfdOpenFailed", "ProcStatReadFailed"]; + /// The broker-attested context block riding one forwarded request. /// /// The broker is the sole minter. The block names the authenticating value @@ -1686,6 +1697,46 @@ pub struct ObserveRunnerResponse { pub executable_verified: bool, } +/// Take the Provider-controller bootstrap escrow one live runner retained +/// at launch. +/// +/// A daemon adopting a still-running ProviderController after its own +/// restart sends this for the runner it identified: the broker's +/// spawn-process kernel retained the controller's bootstrap endpoint, and +/// the controller's bootstrap sends have been landing in it, so the +/// daemon's bootstrap wait consumes them from here and the session +/// acceptor can establish the controller session. The take is one-time +/// and keyed by the same runner identity every generic Process leg uses. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct TakeControllerBootstrapRequest { + pub vm_id: VmId, + pub role_id: RoleId, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub resource_ref: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub resource_uid: Option, + /// Immutable Zone identity for typed Process adoption. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub zone_uid: Option, + /// Broker-independent commitment to the private runtime scope. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub runtime_scope: Option<[u8; 32]>, +} + +/// Response to [`TakeControllerBootstrapRequest`]. +/// +/// `taken` is `false` when the registry holds no escrow for the named +/// identity: an absent escrow is an absent result, never a refusal. When +/// it is `true`, the escrow itself is the sole SCM_RIGHTS attachment on +/// the same frame. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct TakeControllerBootstrapResponse { + /// Whether this take claimed the retained escrow. + pub taken: bool, +} + /// Audio channel selected by a broker-owned PipeWire effect. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case")] diff --git a/packages/d2b-provider-supervisor/src/broker.rs b/packages/d2b-provider-supervisor/src/broker.rs index a7c25898f..a72b7bbee 100644 --- a/packages/d2b-provider-supervisor/src/broker.rs +++ b/packages/d2b-provider-supervisor/src/broker.rs @@ -13,7 +13,7 @@ use d2b_contracts_broker::broker_wire::{ GuestExecutionBinding as BrokerGuestExecutionBinding, ObserveRunnerRequest, ObserveRunnerResponse, OpenPidfdRequest, OpenPidfdResponse, RunnerLaunchArgs, RunnerRole, RunnerSignal, SandboxLaunchPlan, SignalRunnerRequest, SignalRunnerResponse, SpawnRunnerRequest, - SpawnRunnerResponse, + SpawnRunnerResponse, TakeControllerBootstrapRequest, TakeControllerBootstrapResponse, }; use d2b_contracts_broker::kernel_client::{ KernelInvocation, KernelInvokeError, KernelReply, envelope_invoke_kernel, @@ -1530,14 +1530,16 @@ impl ProcessEffectBackend for BrokerProcessBackend { // restart takes the retained escrow so the controller's bootstrap // sends - which have been landing in it - can be consumed. let intent = &handle.observed.intent; - let payload = serde_json::json!({ - "vmId": intent.vm_id.to_string(), - "roleId": intent.role_id.to_string(), - "resourceRef": intent.resource_ref.to_canonical_string(), - "resourceUid": intent.resource_uid.as_str(), - "zoneUid": intent.zone_uid.as_ref().map(|uid| uid.as_str()), - "runtimeScope": intent.runtime_scope.map(|scope| scope.to_vec()), - }); + let payload = serde_json::to_value(take_controller_bootstrap_request(intent)).map_err( + |error| { + warn!( + provider = "supervisor", + error = %error, + "broker take-controller-bootstrap payload encoding failed" + ); + ProcessEffectError::LaunchFailed + }, + )?; let mut reply = self .envelope_call( "take-controller-bootstrap", @@ -1554,14 +1556,7 @@ impl ProcessEffectBackend for BrokerProcessBackend { ); response_error(&error, BrokerOperation::Other) })?; - let taken = reply - .response - .result - .as_ref() - .and_then(|result| result.get("taken")) - .and_then(serde_json::Value::as_bool) - .unwrap_or(false); - if !taken { + if !take_controller_bootstrap_verdict(&reply)?.taken { return Ok(None); } reply_take_fd(&mut reply, 0).map(Some).inspect_err(|&error| { @@ -1711,6 +1706,55 @@ enum BrokerOperation<'a> { Other, } +/// The committed `take-controller-bootstrap` payload for one runner identity. +/// +/// The identity fields are the row's payload, and the typed request is what +/// keeps their names and their presence in step with the row: the leg used +/// to hand-build the same object, so a rename or a dropped field left a +/// broker refusal that read like an absent runner identity. +fn take_controller_bootstrap_request( + intent: &BrokerLaunchIntent, +) -> TakeControllerBootstrapRequest { + TakeControllerBootstrapRequest { + vm_id: intent.vm_id.clone(), + role_id: intent.role_id.clone(), + resource_ref: Some(intent.resource_ref.clone()), + resource_uid: Some(intent.resource_uid.clone()), + zone_uid: intent.zone_uid.clone(), + runtime_scope: intent.runtime_scope, + } +} + +/// Read the take verdict out of one settled `take-controller-bootstrap` +/// reply. +/// +/// A reply that carries no result, or a result that is not the committed +/// take response, is a hard failure under the error the leg already reports +/// for a failed invocation: reading it as "not taken" would make a broker +/// wire defect indistinguishable from an absent escrow, and the caller +/// would then replace a controller whose bootstrap endpoint it never +/// claimed. `taken == false` is not that case - it is the broker's answer +/// that no escrow is held for the identity, and stays an absent result. +fn take_controller_bootstrap_verdict( + reply: &KernelReply, +) -> Result { + let result = reply.response.result.clone().ok_or_else(|| { + warn!( + provider = "supervisor", + "broker take-controller-bootstrap reply carried no result" + ); + ProcessEffectError::LaunchFailed + })?; + serde_json::from_value(result).map_err(|error| { + warn!( + provider = "supervisor", + error = %error, + "broker take-controller-bootstrap reply is not the typed take response" + ); + ProcessEffectError::LaunchFailed + }) +} + /// Classify the start time observed for a freshly spawned child against the /// value the broker reported for it, and report the adoption refusal when the /// child cannot be adopted. @@ -1836,6 +1880,10 @@ fn response_error(error: &KernelInvokeError, operation: BrokerOperation<'_>) -> mod tests { use std::path::Path; + use d2b_contracts_broker::broker_wire::PIDFD_DISPATCH_FAILURE_KINDS; + use d2b_contracts_broker::broker_wire::{ + BrokerRequest, BrokerRequestEnvelope, BrokerResponse, EnvelopeInvokeResponse, FdKind, + }; use d2b_core::processes::ProcessRole; use crate::observations::MAX_PENDING_OBSERVATIONS; @@ -1935,11 +1983,14 @@ mod tests { /// kernel's own `errored` code (the daemon-side family handler /// propagates the kernel's refusal), which is one of the /// dispatch-failure codes the backend classifies against the observed - /// process state. + /// process state. The detail is the shape the open-pidfd kernel emits: + /// the leg's name, the shared failure kind, then the handler's own text. fn pidfd_open_refusal() -> KernelInvokeError { KernelInvokeError::Refused { code: "errored".to_owned(), - detail: Some("open-pidfd: pidfd_open(123) failed: ESRCH".to_owned()), + detail: Some( + "open-pidfd: PidfdOpenFailed: pidfd_open(123) failed: ESRCH".to_owned(), + ), } } @@ -2009,9 +2060,17 @@ mod tests { #[test] fn open_pidfd_dispatch_failure_is_ambiguous_only_after_identity_drift() { - const LIVE_HANDLER_SOURCE: &str = include_str!("../../d2b-broker/src/live_handlers.rs"); - for producer_error in ["PidfdRace", "PidfdOpenFailed", "ProcStatReadFailed"] { - assert!(LIVE_HANDLER_SOURCE.contains(producer_error)); + // The kinds the broker's pidfd handler reports come from the shared + // vocabulary the handler maps its variants through, so this leg + // never has to scrape the producer's source to know them. What it + // still relies on is their shape: the kind rides the refusal detail + // as a bare token, and the classification below reads the envelope's + // dispatch-failure code, not the token. + for kind in PIDFD_DISPATCH_FAILURE_KINDS { + assert!( + !kind.is_empty() && !kind.contains(char::is_whitespace), + "pidfd dispatch failure kind {kind:?} is not a bare token" + ); } let refusal = pidfd_open_refusal(); @@ -2050,6 +2109,261 @@ mod tests { ); } + /// A fake broker answering exactly one `take-controller-bootstrap` leg: + /// the socket the leg dials (the directory holding it stays alive with + /// the leg) and the thread that served it. + struct TakeBootstrapLeg { + _directory: tempfile::TempDir, + socket: PathBuf, + server: std::thread::JoinHandle<()>, + } + + /// The bytes the answering leg writes into the escrow descriptor, so the + /// caller can prove the descriptor it took is the one the broker sent. + const ESCROW_BYTES: &[u8] = b"controller-bootstrap"; + + /// Serve one `take-controller-bootstrap` leg on a fresh broker socket. + /// + /// The answering leg asserts the request it received is the committed + /// row's: the operation, a root call carrying no request descriptor, and + /// a payload of exactly the row's camelCase identity fields, which the + /// typed request decodes. + /// + /// `result` is the reply's result body (`None` is a resultless reply); + /// `attach_escrow` attaches one descriptor holding [`ESCROW_BYTES`]. + fn serve_take_controller_bootstrap( + result: Option, + attach_escrow: bool, + ) -> TakeBootstrapLeg { + use std::io::{IoSlice, IoSliceMut}; + use std::os::fd::AsFd; + use std::os::unix::net::UnixStream; + + use rustix::net::{ + AddressFamily, RecvAncillaryBuffer, RecvAncillaryMessage, RecvFlags, + SendAncillaryBuffer, SendAncillaryMessage, SendFlags, SocketAddrUnix, SocketFlags, + SocketType, accept, bind_unix, listen, recvmsg, sendmsg, socket_with, + }; + + let directory = tempfile::tempdir().expect("socket directory"); + let socket_path = directory.path().join("broker.sock"); + let listener = socket_with( + AddressFamily::UNIX, + SocketType::SEQPACKET, + SocketFlags::CLOEXEC, + None, + ) + .expect("listener socket"); + let address = SocketAddrUnix::new(&socket_path).expect("socket address"); + bind_unix(&listener, &address).expect("bind"); + listen(&listener, 1).expect("listen"); + + let socket = socket_path.clone(); + let server = std::thread::spawn(move || { + let connection = accept(&listener).expect("the take leg dials"); + let mut buffer = vec![0_u8; d2b_contracts::MAX_FRAME_SIZE + 4]; + let mut iov = [IoSliceMut::new(&mut buffer)]; + let mut ancillary_bytes = [0_u8; rustix::cmsg_space!(ScmRights(1))]; + let mut ancillary = RecvAncillaryBuffer::new(&mut ancillary_bytes); + let received = recvmsg(&connection, &mut iov, &mut ancillary, RecvFlags::CMSG_CLOEXEC) + .expect("request frame"); + let mut request_fds = 0; + for message in ancillary.drain() { + if let RecvAncillaryMessage::ScmRights(fds) = message { + request_fds += fds.len(); + } + } + assert_eq!(request_fds, 0, "the take leg attaches no request descriptor"); + let envelope: BrokerRequestEnvelope = + d2b_contracts::decode_frame("BrokerRequestEnvelope", &buffer[..received.bytes]) + .expect("request envelope"); + let BrokerRequest::EnvelopeInvoke(request) = envelope.request else { + panic!("expected one EnvelopeInvoke leg"); + }; + assert_eq!(request.operation, "take-controller-bootstrap"); + assert_eq!(request.zone, "corp"); + assert_eq!(request.chain_root_invocation_id, None); + assert_eq!(request.chain_identities, None); + assert_eq!( + request.payload, + serde_json::json!({ + "vmId": "corp-vm", + "roleId": "worker", + "resourceRef": "Process/worker", + "resourceUid": "00000000-0000-4000-8000-000000000001", + }), + "the leg carries the committed take-controller-bootstrap payload" + ); + let _: TakeControllerBootstrapRequest = + serde_json::from_value(request.payload.clone()) + .expect("the committed payload decodes into the typed take request"); + + let (fd_indexes, fd_kinds) = if attach_escrow { + (vec![0], vec![FdKind::Any]) + } else { + (Vec::new(), Vec::new()) + }; + let response = BrokerResponse::EnvelopeInvoke(EnvelopeInvokeResponse { + operation: "take-controller-bootstrap".to_owned(), + invocation_id: "invocation-take".to_owned(), + result, + refusal: None, + detail: None, + fd_indexes, + fd_kinds, + }); + let frame = d2b_contracts::encode_frame(&response).expect("response frame"); + let iov = [IoSlice::new(&frame)]; + if attach_escrow { + // The escrow crosses as an SCM_RIGHTS attachment of the same + // frame that carries the verdict, exactly as the kernel's + // reply leg sends it. + let (peer, escrow) = UnixStream::pair().expect("escrow socket pair"); + let mut written = 0; + while written < ESCROW_BYTES.len() { + written += + rustix::io::write(&peer, &ESCROW_BYTES[written..]).expect("escrow bytes"); + } + let escrow: OwnedFd = escrow.into(); + let descriptors = [escrow.as_fd()]; + let mut control_bytes = [0_u8; rustix::cmsg_space!(ScmRights(1))]; + let mut control = SendAncillaryBuffer::new(&mut control_bytes); + assert!(control.push(SendAncillaryMessage::ScmRights(&descriptors))); + assert_eq!( + sendmsg(&connection, &iov, &mut control, SendFlags::empty()) + .expect("escrow reply frame"), + frame.len() + ); + } else { + assert_eq!( + rustix::net::send(&connection, &frame, SendFlags::empty()) + .expect("reply frame"), + frame.len() + ); + } + }); + TakeBootstrapLeg { + _directory: directory, + socket, + server, + } + } + + /// Run one `take-controller-bootstrap` leg through the production + /// backend against a fake broker that answers with `result`. + fn take_controller_bootstrap_against( + result: Option, + attach_escrow: bool, + ) -> (Result, ProcessEffectError>, TakeBootstrapLeg) { + let leg = serve_take_controller_bootstrap(result, attach_escrow); + let backend = BrokerProcessBackend::with_socket_and_role( + Resolver, + &leg.socket, + Duration::from_secs(5), + BrokerCallerRole::AdminUid { uid: 1000 }, + ); + // The leg never touches the handle's own descriptor; only the + // runner intent it was adopted from crosses. + let handle = BrokerPidfdHandle { + pidfd: rustix::event::eventfd(0, rustix::event::EventfdFlags::empty()) + .expect("placeholder descriptor"), + observed: observed(1), + spawn_invocation_id: None, + }; + let outcome = backend.take_controller_bootstrap(&handle); + (outcome, leg) + } + + /// Read the escrow bytes back from the descriptor a take handed over. + fn read_escrow(escrow: OwnedFd) -> Vec { + let mut bytes = vec![0_u8; ESCROW_BYTES.len()]; + let mut read = 0; + while read < bytes.len() { + read += rustix::io::read(&escrow, &mut bytes[read..]).expect("escrow read"); + } + bytes + } + + /// The take-controller-bootstrap leg reads the committed reply: an + /// escrow-less take is an absent result, and a reply that is not the + /// committed response - resultless, mistyped, or carrying a field the + /// row does not declare - fails the leg instead of reading as "not + /// taken", which would replace a controller whose bootstrap endpoint + /// the caller never claimed. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + #[test] + fn take_controller_bootstrap_reads_the_committed_reply() { + let (absent, leg) = + take_controller_bootstrap_against(Some(serde_json::json!({ "taken": false })), false); + assert!( + absent.expect("a not-taken reply is an absent escrow").is_none(), + "a broker holding no escrow takes nothing" + ); + leg.server.join().expect("the answering leg served the take"); + + let (taken, leg) = + take_controller_bootstrap_against(Some(serde_json::json!({ "taken": true })), true); + let escrow = taken + .expect("a taken escrow") + .expect("the escrow descriptor the reply attached"); + assert_eq!( + read_escrow(escrow), + ESCROW_BYTES, + "the take hands over the descriptor the broker attached" + ); + leg.server.join().expect("the answering leg served the take"); + + let malformed = [ + None, + Some(serde_json::json!({ "taken": "yes" })), + Some(serde_json::json!({ "taken": true, "escrow": 1 })), + ]; + for result in malformed { + let (failed, leg) = take_controller_bootstrap_against(result, false); + assert_eq!( + failed.expect_err("a malformed reply fails the take"), + ProcessEffectError::LaunchFailed, + "a reply that is not the committed take response must not read as not-taken" + ); + leg.server.join().expect("the answering leg served the take"); + } + } + + /// The take payload is the committed row's: its camelCase identity + /// fields and nothing else (the row is `additionalProperties: false`), + /// with the runtime scope as the row's 32-byte array and the optional + /// pair omitted when the launch carries none. + #[test] + fn take_controller_bootstrap_payload_carries_the_row_identity_fields() { + let mut intent = observed(1).intent; + assert_eq!( + serde_json::to_value(take_controller_bootstrap_request(&intent)).unwrap(), + serde_json::json!({ + "vmId": "corp-vm", + "roleId": "worker", + "resourceRef": "Process/worker", + "resourceUid": "00000000-0000-4000-8000-000000000001", + }) + ); + + intent.zone_uid = Some( + ResourceUid::parse("00000000-0000-4000-8000-000000000002").expect("zone uid"), + ); + intent.runtime_scope = Some([7; 32]); + let scope = [7_u8; 32]; + assert_eq!( + serde_json::to_value(take_controller_bootstrap_request(&intent)).unwrap(), + serde_json::json!({ + "vmId": "corp-vm", + "roleId": "worker", + "resourceRef": "Process/worker", + "resourceUid": "00000000-0000-4000-8000-000000000001", + "zoneUid": "00000000-0000-4000-8000-000000000002", + "runtimeScope": scope, + }) + ); + } + /// The launch fence classifies the spawned child's observed start time: /// a *different* live process owning the reported pid is a genuine drift /// and stays refused (`adoption-ambiguous`), while a child that is already From 61071463183b111979a0538cd608505a4d02b734 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:34:58 -0700 Subject: [PATCH 680/726] fix(d2bd): poll the Process broker legs for their declared budget The daemon's Process-family broker clients used a flat 10s poll against rows that declare DeadlineTier::Standard, so the client abandoned spawns the broker was still serving. The broker had already created the child and kept its runner registration, so every relaunch was refused as a duplicate and the Process wedged in Pending. Derive the three budgets from DEFAULT_CONTEXT_DEADLINE_MS, the carrier constant the Standard tier returns, so no literal can drift from the row it must outlast. --- changelog.d/fix-host-preflight.md | 19 ++++++++++++ packages/d2bd/src/process_provider_runtime.rs | 31 ++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 changelog.d/fix-host-preflight.md diff --git a/changelog.d/fix-host-preflight.md b/changelog.d/fix-host-preflight.md new file mode 100644 index 000000000..09925fe5b --- /dev/null +++ b/changelog.d/fix-host-preflight.md @@ -0,0 +1,19 @@ +### Fixed + +- The daemon's Process-family broker clients poll their calls for the family's + own declared per-call deadline instead of a hardcoded 10 seconds. The three + budgets in `ProductionProcessProviders::new_for_mode` + (`packages/d2bd/src/process_provider_runtime.rs`: the adoption observation + socket, `BrokerProcessBackend::with_socket_profile_and_role`, and + `BrokerSystemdEffectOwner::with_socket_and_role`) now derive from + `BROKER_IO_TIMEOUT`, which is the carrier's `DEFAULT_CONTEXT_DEADLINE_MS` + (25 s) - the same constant `DeadlineTier::Standard::budget_ms()` returns, so + no literal is restated. Polling shorter than the budget the call is served + under abandoned spawns the broker was still running, and an abandoned spawn + is not inert: the controller child the broker had already created stayed + live holding its runner registration, so every relaunch was refused as a + duplicate (`handler-refused`) and the Process wedged in `Pending` until the + `runtime-cloud-hypervisor-guest-preflight` host-integration wait expired. + The daemon now receives the broker's own verdict on those legs, ordered + under the launch ticket's deadline (30 s at the call sites), whose + late-launch path stops a process that outruns it. diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index 2514ba076..ebaa4d531 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -17,7 +17,7 @@ use std::{ use tokio::sync::Mutex; -use d2b_contracts_broker::broker_wire::BrokerCallerRole; +use d2b_contracts_broker::broker_wire::{BrokerCallerRole, DEFAULT_CONTEXT_DEADLINE_MS}; use d2b_contracts_resource::v3::execution_policy::{BoundedToken, ExecutionDomain}; use d2b_contracts_resource::v3::{ ControllerGeneration, ResourceGeneration, ResourceRef, ResourceSpec, ResourceUid, @@ -858,6 +858,29 @@ impl std::fmt::Debug for ProductionProcessProviders { } } +/// The io budget the daemon's Process clients poll the broker under. +/// +/// It is the Process family's own declared per-call deadline: every +/// Process-family row (`SpawnRunner`, and the `spawn_process` kernel it +/// forwards to) declares `DeadlineTier::Standard`, the carrier mints that +/// budget for the call, and both execution legs serve it as their handler +/// deadline. A client poll shorter than the budget it wraps abandons a call +/// the broker is still entitled to serve, and an abandoned spawn is not +/// inert: the broker has already created the child and holds its runner +/// registration, so `reserve_runner_id_for_spawn` refuses every relaunch as +/// a duplicate and the Process wedges with no recovery. +/// +/// Measured 2026-09-25 (`runtime-cloud-hypervisor-guest-preflight`, gate +/// head `dc995602c`): a flat 10s poll abandoned one volume-local controller +/// spawn at t=16.9s; the controller child the broker had created then looped +/// its session handshake every 5.5s for 145s, the next ten relaunches were +/// refused (`handler-refused`), and the fixture's 180s wait expired with the +/// row still `Pending` at t=202s. Every green run of the same check reports +/// zero `handler-refused` lines and establishes all three controller +/// sessions by t=10s; its `reply timeout`s are all on `observe` legs, which +/// register no runner and are simply re-probed. +const BROKER_IO_TIMEOUT: Duration = Duration::from_millis(DEFAULT_CONTEXT_DEADLINE_MS); + impl ProductionProcessProviders { /// Construct both fixed process Providers over the authenticated broker. pub fn new( @@ -895,13 +918,13 @@ impl ProductionProcessProviders { let daemon_uid = caller_uid(&caller_role); let resolver = BundleBackedLaunchResolver::new(bundle.clone()).with_observation_socket( broker_socket.clone(), - Duration::from_secs(10), + BROKER_IO_TIMEOUT, caller_role.clone(), ); let mut minijail_backend = BrokerProcessBackend::with_socket_profile_and_role( resolver.clone(), broker_socket.clone(), - Duration::from_secs(10), + BROKER_IO_TIMEOUT, mode.broker_profile(), caller_role.clone(), ); @@ -916,7 +939,7 @@ impl ProductionProcessProviders { let systemd_owner = BrokerSystemdEffectOwner::with_socket_and_role( resolver, broker_socket, - Duration::from_secs(10), + BROKER_IO_TIMEOUT, caller_role, ); let fixed_effect = FixedEffectAdapter::for_mode(mode, fixed_socket, daemon_uid); From a822cc8e4a755dd32f2090b7cdf8af37a6f4a02c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:48:38 -0700 Subject: [PATCH 681/726] providers: await the activation and endpoint recorder locks The two crates' test recorders held their seats in parking_lot locks, so every site stayed an unsuppressed hit the census would refuse once the deny list resolved those locks through the lock_api paths, and the async effect methods parked an executor worker on a blocking acquire. The activation recording manager and the endpoint dead manager now hold their rows in tokio::sync::Mutex and await every take. The activation manager's with_row, log, and row readers turn async so the seat keeps one lock type, and ensure_child scopes its row guard so it is released before the spawn notification's await. Neither driver test module holds a blocking lock any more. The three test-support recorders keep their blocking seats: the plain accessors external test crates read cannot await, so each seat carries the recorded per-site exception with reason "cfg(test) helper" rather than a module-level allow. The async-gate hatch inventory is regenerated for the removed and moved marker sites, which also repairs two stale line entries in the daemon composition module. --- .../w7-24-activation-and-endpoint-locks.md | 19 ++++ .../src/driver.rs | 93 +++++++++++-------- .../src/test_support.rs | 4 + packages/d2b-provider-endpoint/src/driver.rs | 20 ++-- .../d2b-provider-endpoint/src/test_support.rs | 3 + packages/xtask/data/async-gate-inventory.json | 65 ++----------- 6 files changed, 99 insertions(+), 105 deletions(-) create mode 100644 changelog.d/w7-24-activation-and-endpoint-locks.md diff --git a/changelog.d/w7-24-activation-and-endpoint-locks.md b/changelog.d/w7-24-activation-and-endpoint-locks.md new file mode 100644 index 000000000..52bbba075 --- /dev/null +++ b/changelog.d/w7-24-activation-and-endpoint-locks.md @@ -0,0 +1,19 @@ +### Changed + +- The activation recording manager and the endpoint dead manager in the + two provider crates' driver test modules hold their recorder state in + `tokio::sync::Mutex` in place of the banned `parking_lot` lock: every + take awaits it, the activation manager's `with_row`, `log`, and `row` + readers turn async for the same reason, and no guard is held across + another await. + +### Fixed + +- The activation and endpoint test-support recorders + (`FakeActivationEffects`, `RecordingBrokerDispatch` and + `FakeSocketEffects`) no longer take an unsuppressed blocking lock + inside the async effect methods their facets call. The seats the + synchronous accessors read keep the blocking lock with the recorded + per-site exception (`clippy::disallowed_methods`, reason `cfg(test) + helper`), so both crates read zero unsuppressed census sites once the + meter resolves the locks through its `lock_api` deny paths. diff --git a/packages/d2b-provider-activation-nixos/src/driver.rs b/packages/d2b-provider-activation-nixos/src/driver.rs index 0eeb37c24..cb5c59fe0 100644 --- a/packages/d2b-provider-activation-nixos/src/driver.rs +++ b/packages/d2b-provider-activation-nixos/src/driver.rs @@ -992,8 +992,8 @@ mod tests { struct RecordingManager { zone: String, owner_uid: [u8; 16], - log: Arc>>, - rows: Arc>>, + log: Arc>>, + rows: Arc>>, next_uid: Arc, } @@ -1002,23 +1002,28 @@ mod tests { Self { zone: "work".to_owned(), owner_uid, - log: Arc::new(parking_lot::Mutex::new(Vec::new())), - rows: Arc::new(parking_lot::Mutex::new(Vec::new())), + log: Arc::new(tokio::sync::Mutex::new(Vec::new())), + rows: Arc::new(tokio::sync::Mutex::new(Vec::new())), next_uid: Arc::new(std::sync::atomic::AtomicU64::new(1)), } } - fn with_row(self, row: StoredDesiredResource) -> Self { - self.rows.lock().push(row); + async fn with_row(self, row: StoredDesiredResource) -> Self { + self.rows.lock().await.push(row); self } - fn log(&self) -> Vec { - self.log.lock().clone() + async fn log(&self) -> Vec { + self.log.lock().await.clone() } - fn row(&self, key: &ResourceKey) -> Option { - self.rows.lock().iter().find(|row| row.key == *key).cloned() + async fn row(&self, key: &ResourceKey) -> Option { + self.rows + .lock() + .await + .iter() + .find(|row| row.key == *key) + .cloned() } } @@ -1030,7 +1035,7 @@ mod tests { child: ChildEnsure, ) -> Result { let id = format!("{}/{}", child.type_name.as_str(), child.name); - self.log.lock().push(format!("ensure:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.log.lock().await.push(format!("ensure:{id}")); let next = self .next_uid .fetch_add(1, std::sync::atomic::Ordering::SeqCst); @@ -1047,20 +1052,26 @@ mod tests { metadata: child.metadata, created_at: 0, }; - let mut rows = self.rows.lock(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - let outcome = match rows.iter_mut().find(|existing| existing.key == row.key) { - Some(existing) if existing.spec == row.spec => EnsureOutcome::Unchanged(existing.clone()), - Some(existing) => { - *existing = row.clone(); - EnsureOutcome::Updated(row.clone()) - } - None => { - rows.push(row.clone()); - EnsureOutcome::Created(row.clone()) + // The row guard is scoped so it is released before the spawn + // notification's await below. + let outcome = { + let mut rows = self.rows.lock().await; + match rows.iter_mut().find(|existing| existing.key == row.key) { + Some(existing) if existing.spec == row.spec => { + EnsureOutcome::Unchanged(existing.clone()) + } + Some(existing) => { + *existing = row.clone(); + EnsureOutcome::Updated(row.clone()) + } + None => { + rows.push(row.clone()); + EnsureOutcome::Created(row.clone()) + } } }; // The spawn notification the manager emits after the commit (F1). - self.log.lock().push(format!("spawned:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.log.lock().await.push(format!("spawned:{id}")); Ok(outcome) } @@ -1068,7 +1079,7 @@ mod tests { &self, key: &ResourceKey, ) -> Result, ResourceError> { - Ok(self.row(key)) + Ok(self.row(key).await) } async fn view( @@ -1081,11 +1092,11 @@ mod tests { } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { - self.log.lock().push(format!( // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.log.lock().await.push(format!( "delete:{}/{}", key.type_name, key.name )); - self.rows.lock().retain(|row| row.key != *key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.rows.lock().await.retain(|row| row.key != *key); Ok(()) } @@ -1096,6 +1107,7 @@ mod tests { Ok(self .rows .lock() + .await .iter() .filter(|row| row.owner_uid.as_ref() == Some(&owner_uid)) .cloned() @@ -1108,7 +1120,7 @@ mod tests { registration: WatchRegistration, ) -> Result { assert_eq!(registration.condition, WatchCondition::Ready); - self.log.lock().push(format!( // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.log.lock().await.push(format!( "watch:{}/{}", registration.target.type_name, registration.target.name )); @@ -1270,7 +1282,7 @@ mod tests { ActivationMode::Switch, None, [0x41; 16], - )); + )).await; let mut f = fixture( generation_row( "gen-2", @@ -1312,7 +1324,7 @@ mod tests { assert_eq!(projected.detail(), ActivationDetail::Applied); assert_eq!(projected.outcome(), Some(ActivationOutcomeCode::Succeeded)); // A Host target realizes through the broker: no runner child. - assert!(f.manager.log().is_empty()); + assert!(f.manager.log().await.is_empty()); } /// The facets -> factory -> driver -> handoff seam the refactor @@ -1347,7 +1359,7 @@ mod tests { ActivationMode::Switch, None, [0x41; 16], - )); + )).await; let mut f = fixture( generation_row( "gen-2", @@ -1401,7 +1413,7 @@ mod tests { ActivationMode::Switch, None, [0x41; 16], - )); + )).await; let mut f = fixture( generation_row( "gen-2", @@ -1451,7 +1463,7 @@ mod tests { projected.outcome(), Some(ActivationOutcomeCode::HelperRefused) ); - assert!(f.manager.log().is_empty()); + assert!(f.manager.log().await.is_empty()); } #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -1491,7 +1503,7 @@ mod tests { ActivationMode::Switch, None, [0x41; 16], - )), + )).await, ); let mut cross_driver = driver(effects.clone(), Arc::new(AllowVerifier)).await; assert!(cross_driver.reconcile(&mut cross.ctx).await.is_err()); @@ -1519,7 +1531,7 @@ mod tests { ActivationMode::Switch, None, [0x41; 16], - )), + )).await, ); let mut d = driver( effects.clone(), @@ -1565,7 +1577,7 @@ mod tests { // KTD13: the launch is a Process-resource mint through the manager, // never a spawn from this controller, and the child row is committed // before its spawn notification (F1). - let log = manager.log(); + let log = manager.log().await; let ensure = log .iter() .position(|entry| entry.starts_with("ensure:EphemeralProcess/")) @@ -1590,7 +1602,7 @@ mod tests { .name() .as_str(), ); - let runner = manager.row(&runner_key).expect("runner row committed"); + let runner = manager.row(&runner_key).await.expect("runner row committed"); assert_eq!(runner.owner_uid, Some(GENERATION_UID)); // The launch parameters travel on the sanctioned typed channel: the @@ -1627,7 +1639,7 @@ mod tests { d.reconcile(&mut f.ctx).await.expect("first reconcile"); d.reconcile(&mut f.ctx).await.expect("rejoin reconcile"); - let log = manager.log(); + let log = manager.log().await; assert_eq!( log.iter().filter(|entry| entry.starts_with("ensure:")).count(), 1, @@ -1663,7 +1675,7 @@ mod tests { f.ctx.status::().is_none(), "no runner to rejoin: recovery projects nothing" ); - assert!(manager.log().is_empty()); + assert!(manager.log().await.is_empty()); // The Host target realizes through the broker authority. let mut host = fixture( @@ -1697,7 +1709,7 @@ mod tests { None, [0x77; 16], ) - }); + }).await; let Fixture { mut ctx, manager } = fixture( generation_row( "gen-1", @@ -1718,7 +1730,7 @@ mod tests { let failure = d.finalize(&mut ctx).await.expect_err("owned runner still live"); assert_eq!(failure.class(), FailureClass::Retryable); assert!( - manager.log().iter().any(|call| call.starts_with("delete:")), + manager.log().await.iter().any(|call| call.starts_with("delete:")), "the owned runner is nudged through its own finalize-before-delete pass" ); @@ -1757,6 +1769,7 @@ mod tests { .to_owned(); let deletions = manager .log() + .await .into_iter() .filter(|entry| entry.starts_with("delete:")) .collect::>(); @@ -1767,7 +1780,7 @@ mod tests { ); let runner_key = ResourceKey::new("work", "EphemeralProcess", &runner_name); assert!( - manager.row(&runner_key).is_none(), + manager.row(&runner_key).await.is_none(), "the runner child retires through the manager" ); } diff --git a/packages/d2b-provider-activation-nixos/src/test_support.rs b/packages/d2b-provider-activation-nixos/src/test_support.rs index 0c95eeb5b..6359431ee 100644 --- a/packages/d2b-provider-activation-nixos/src/test_support.rs +++ b/packages/d2b-provider-activation-nixos/src/test_support.rs @@ -35,12 +35,14 @@ impl FakeActivationEffects { } /// The host-generation handoff dispatches recorded so far, in call order. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn dispatches(&self) -> Vec<(ResourceRef, HostGenerationHandoffIntent)> { self.dispatches.lock().clone() } } #[async_trait::async_trait] +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl ActivationDriverEffects for FakeActivationEffects { async fn apply_host_generation_handoff( &self, @@ -90,11 +92,13 @@ impl RecordingBrokerDispatch { } /// The host-generation handoffs dispatched so far, in call order. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn requests(&self) -> Vec { self.requests.lock().clone() } } +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl ActivationBrokerDispatch for RecordingBrokerDispatch { fn dispatch_handoff( &self, diff --git a/packages/d2b-provider-endpoint/src/driver.rs b/packages/d2b-provider-endpoint/src/driver.rs index 69b076d8d..285f40326 100644 --- a/packages/d2b-provider-endpoint/src/driver.rs +++ b/packages/d2b-provider-endpoint/src/driver.rs @@ -623,22 +623,22 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer /// each child retirement nudge, and every other mutating route still /// fails, so an unexpected flow is caught. struct DeadManager { - owned: parking_lot::Mutex>, - deleted: parking_lot::Mutex>, + owned: tokio::sync::Mutex>, + deleted: tokio::sync::Mutex>, } impl DeadManager { fn new() -> Self { Self { - owned: parking_lot::Mutex::new(Vec::new()), - deleted: parking_lot::Mutex::new(Vec::new()), + owned: tokio::sync::Mutex::new(Vec::new()), + deleted: tokio::sync::Mutex::new(Vec::new()), } } fn with_owned(row: StoredDesiredResource) -> Arc { Arc::new(Self { - owned: parking_lot::Mutex::new(vec![row]), - deleted: parking_lot::Mutex::new(Vec::new()), + owned: tokio::sync::Mutex::new(vec![row]), + deleted: tokio::sync::Mutex::new(Vec::new()), }) } } @@ -668,8 +668,8 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { - self.deleted.lock().push(key.clone()); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - self.owned.lock().retain(|row| row.key != *key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.deleted.lock().await.push(key.clone()); + self.owned.lock().await.retain(|row| row.key != *key); Err(ResourceError::ManagerUnavailable("dead".into())) } @@ -677,7 +677,7 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer &self, _owner_uid: [u8; 16], ) -> Result, ResourceError> { - Ok(self.owned.lock().clone()) + Ok(self.owned.lock().await.clone()) } async fn register_watch( @@ -894,7 +894,7 @@ use crate::endpoint::{ EndpointAttachmentPolicy, EndpointClass, EndpointConsumer let failure = d.finalize(&mut ctx).await.expect_err("owned child still live"); assert_eq!(failure.class(), FailureClass::Retryable); assert_eq!( - manager.deleted.lock().len(), // async-gate-allow: synchronous lock acquisition, no await while the guard is held + manager.deleted.lock().await.len(), 1, "the owned child is nudged through its own finalize-before-delete pass" ); diff --git a/packages/d2b-provider-endpoint/src/test_support.rs b/packages/d2b-provider-endpoint/src/test_support.rs index a337a09b6..ff419e4f5 100644 --- a/packages/d2b-provider-endpoint/src/test_support.rs +++ b/packages/d2b-provider-endpoint/src/test_support.rs @@ -38,6 +38,7 @@ impl FakeSocketEffects { } /// The socket effect calls recorded so far, in order. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn call_order(&self) -> Vec<&'static str> { self.calls.lock().clone() } @@ -66,6 +67,7 @@ impl FakeSocketEffects { struct ScriptedSocketSource(Arc); #[async_trait::async_trait] +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl EndpointSocketSource for ScriptedSocketSource { async fn present(&self, _producer_ref: &ResourceRef, _purpose: &str) -> bool { self.0.calls.lock().push("socket-present"); // async-gate-allow: test-support recorder lock @@ -115,6 +117,7 @@ impl EndpointPurposeVocabulary for FakeSocketEffects { } #[async_trait::async_trait] +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl EndpointDriverEffects for FakeSocketEffects { async fn socket_present(&self, _producer_ref: &ResourceRef, _purpose: &str) -> bool { self.calls.lock().push("socket-present"); // async-gate-allow: test-support recorder lock diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 5e393ccbf..34ed8ffb0 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -141,44 +141,14 @@ "line": 8616, "reason": "synchronous lock acquisition, no await while the guard is held" }, - { - "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1033, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1050, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1063, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1084, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1088, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-activation-nixos/src/driver.rs", - "line": 1111, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, { "file": "packages/d2b-provider-activation-nixos/src/test_support.rs", - "line": 50, + "line": 52, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-activation-nixos/src/test_support.rs", - "line": 52, + "line": 54, "reason": "test-support recorder lock" }, { @@ -466,49 +436,34 @@ "line": 167, "reason": "test-support recorder lock" }, - { - "file": "packages/d2b-provider-endpoint/src/driver.rs", - "line": 671, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-endpoint/src/driver.rs", - "line": 672, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-endpoint/src/driver.rs", - "line": 897, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, { "file": "packages/d2b-provider-endpoint/src/test_support.rs", - "line": 71, + "line": 73, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-endpoint/src/test_support.rs", - "line": 76, + "line": 78, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-endpoint/src/test_support.rs", - "line": 82, + "line": 84, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-endpoint/src/test_support.rs", - "line": 120, + "line": 123, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-endpoint/src/test_support.rs", - "line": 129, + "line": 132, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-endpoint/src/test_support.rs", - "line": 139, + "line": 142, "reason": "test-support recorder lock" }, { @@ -1013,12 +968,12 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 26472, + "line": 26622, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26869, + "line": 27019, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 89961f9d95c6cbe17a25d2407d7c3f8d82a9c039 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:45:34 -0700 Subject: [PATCH 682/726] refactor(d2b-provider-user): run the NSS probe on the bounded seat The bounded local-account probe ran its NSS reads inline on the executor worker: User::from_name, Group::from_gid and Group::from_name have no async form, so a slow or wedged NSS backend (LDAP/NIS) parked a runtime worker for the whole lookup. The whole blocking body now runs on d2b-core's bounded loader probe seat. The closure owns the declared identity and builds the complete discovery on the worker, and an absent or saturated seat maps onto SystemCoreError::DiscoveryUnavailable - the classification a lookup that cannot complete always reported - so the driver's retryable mapping and the hosted inspect-user refusal code are unchanged. spawn_blocking is not used: plan KD2 bans it as the thread-per-call shape, and the seat is the house replacement, the same way the device-tpm prepare-state leg runs its storage-row posture resolution. The test-support recorders and the driver's test fakes leave the banned parking_lot locks for the async-lock shape the host family uses: the async effect methods await the lock and the synchronous accessors take a non-blocking try_lock, so the crate drops its parking_lot dependency and carries no unsuppressed blocking-lock site. The async-gate hatch inventory is regenerated for the removed marker sites and the policy inputs for the dependency change. --- Cargo.lock | 2 +- .../w7-21-user-nss-seat-and-recorders.md | 18 +++++++ packages/d2b-provider-user/BUILD.bazel | 3 ++ packages/d2b-provider-user/Cargo.toml | 3 +- packages/d2b-provider-user/README.md | 16 +++--- packages/d2b-provider-user/src/driver.rs | 40 +++++++-------- packages/d2b-provider-user/src/probe.rs | 28 +++++++++-- .../d2b-provider-user/src/test_support.rs | 29 +++++++---- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 2 +- .../main-product/policy/closure.json | 18 ++++--- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 2 +- .../main-product/production/closure.json | 14 ++++-- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 2 +- .../main-product/policy/closure.json | 18 ++++--- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 2 +- .../main-product/production/closure.json | 14 ++++-- .../main-product/production/metadata.json | 2 +- packages/xtask/data/async-gate-inventory.json | 49 +------------------ 53 files changed, 184 insertions(+), 148 deletions(-) create mode 100644 changelog.d/w7-21-user-nss-seat-and-recorders.md diff --git a/Cargo.lock b/Cargo.lock index 366c35a2d..2a83b1b42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1869,12 +1869,12 @@ version = "0.0.0-bootstrap" dependencies = [ "async-trait", "d2b-contracts-resource", + "d2b-core", "d2b-provider-system-core", "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", "nix 0.29.0", - "parking_lot", "serde_json", "sha2", "tokio", diff --git a/changelog.d/w7-21-user-nss-seat-and-recorders.md b/changelog.d/w7-21-user-nss-seat-and-recorders.md new file mode 100644 index 000000000..11af0bc60 --- /dev/null +++ b/changelog.d/w7-21-user-nss-seat-and-recorders.md @@ -0,0 +1,18 @@ +### Changed + +- The `User` family's bounded local-account probe now runs its NSS reads + on `d2b-core`'s bounded loader probe seat: `getpwnam`/`getgrnam` have + no async form, so the whole blocking body is admitted with + `loader_worker::run_probe` and a saturated or absent seat is reported + as `SystemCoreError::DiscoveryUnavailable` - the same classification + the probe always mapped a failed lookup to - instead of parking an + executor worker for the lookup. + +### Fixed + +- The User test-support recorder doubles and the driver test harness + hold their recorder state in async locks instead of `parking_lot` + locks: the recorders await the lock inside the async effect methods + and take a non-blocking `try_lock` from their synchronous accessors, + so `d2b-provider-user` no longer depends on `parking_lot` and carries + no unsuppressed blocking-lock site. diff --git a/packages/d2b-provider-user/BUILD.bazel b/packages/d2b-provider-user/BUILD.bazel index 56e70d6aa..5d664d8da 100644 --- a/packages/d2b-provider-user/BUILD.bazel +++ b/packages/d2b-provider-user/BUILD.bazel @@ -22,6 +22,7 @@ d2b_rust_library( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", + "//packages/d2b-core:d2b_core", "//packages/d2b-provider-system-core:d2b_provider_system_core", "//packages/d2b-provider-toolkit:d2b_provider_toolkit", "//packages/d2b-resource-runtime:d2b_resource_runtime", @@ -37,6 +38,7 @@ d2b_rust_library( crate_name = "d2b_provider_user", deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", + "//packages/d2b-core:d2b_core_test_support", "//packages/d2b-provider-system-core:d2b_provider_system_core_test_support", "//packages/d2b-provider-toolkit:d2b_provider_toolkit_test_support", "//packages/d2b-resource-runtime:d2b_resource_runtime", @@ -50,6 +52,7 @@ d2b_rust_test( crate = ":d2b_provider_user", deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", + "//packages/d2b-core:d2b_core", "//packages/d2b-provider-system-core:d2b_provider_system_core", "//packages/d2b-provider-toolkit:d2b_provider_toolkit", "//packages/d2b-resource-runtime:d2b_resource_runtime", diff --git a/packages/d2b-provider-user/Cargo.toml b/packages/d2b-provider-user/Cargo.toml index 8200e3326..35d0be3af 100644 --- a/packages/d2b-provider-user/Cargo.toml +++ b/packages/d2b-provider-user/Cargo.toml @@ -16,6 +16,7 @@ await_holding_refcell_ref = "deny" [dependencies] async-trait = "0.1" d2b-contracts-resource = { path = "../d2b-contracts-resource", version = "0.0.0-bootstrap" } +d2b-core = { path = "../d2b-core", version = "0.0.0-bootstrap" } d2b-provider-system-core = { path = "../d2b-provider-system-core", version = "0.0.0-bootstrap" } d2b-provider-toolkit = { path = "../d2b-provider-toolkit", version = "0.0.0-bootstrap" } d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-bootstrap" } @@ -23,8 +24,8 @@ d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstra nix = { version = "0.29", features = ["user"] } serde_json.workspace = true sha2 = { workspace = true } +tokio = { workspace = true, features = ["sync"] } tracing = "0.1" -parking_lot = "0.12" [features] test-support = [] diff --git a/packages/d2b-provider-user/README.md b/packages/d2b-provider-user/README.md index c43435897..4525552e6 100644 --- a/packages/d2b-provider-user/README.md +++ b/packages/d2b-provider-user/README.md @@ -49,12 +49,16 @@ with the decoder, the type's verbs, execution domain, reads, and the local identity it names, so the plane drives it in the Host domain. The crate's own bounded NSS probe (`src/probe.rs`) reads the local account database through `nix`'s `getpwnam`/`getgrnam` surface, behind the -`UserDriverEffects` seam, over the preserved `UserReconciler`. No daemon -adapter implements discovery for this family, and the daemon supplies no -externally built port: the composition root hands the family's effects the -declared facet set, which carries the crate's own probe. - -The crate depends on `d2b-contracts-resource`, `d2b-provider-system-core` +`UserDriverEffects` seam, over the preserved `UserReconciler`. The reads +have no async form, so the probe runs them on `d2b-core`'s bounded loader +probe seat (`loader_worker::run_probe`): a slow or wedged backend refuses +later probes instead of parking an executor worker for the lookup. No +daemon adapter implements discovery for this family, and the daemon +supplies no externally built port: the composition root hands the family's +effects the declared facet set, which carries the crate's own probe. + +The crate depends on `d2b-contracts-resource`, `d2b-core` (the bounded +loader probe seat the account reads run on), `d2b-provider-system-core` (the User reconciler the family's effects drive), `d2b-provider-toolkit`, `d2b-resource-runtime`, `d2b-resource-types`, `nix` (the bounded account reads), `sha2` (the identity digest), `serde_json`, and `tracing`. It diff --git a/packages/d2b-provider-user/src/driver.rs b/packages/d2b-provider-user/src/driver.rs index 1545ae593..02da32dfb 100644 --- a/packages/d2b-provider-user/src/driver.rs +++ b/packages/d2b-provider-user/src/driver.rs @@ -461,21 +461,21 @@ mod tests { /// any unexpected manager call fails the test loudly through the recorded /// call list. struct RecordingManager { - calls: parking_lot::Mutex>, - owned: parking_lot::Mutex>, + calls: tokio::sync::Mutex>, + owned: tokio::sync::Mutex>, } impl RecordingManager { fn new() -> Arc { Arc::new(Self { - calls: parking_lot::Mutex::new(Vec::new()), - owned: parking_lot::Mutex::new(Vec::new()), + calls: tokio::sync::Mutex::new(Vec::new()), + owned: tokio::sync::Mutex::new(Vec::new()), }) } /// Seed one owned child row (the finalize gate's input). fn seed_owned(&self, key: ResourceKey) { - self.owned.lock().push(StoredDesiredResource { + self.owned.try_lock().expect("uncontended test mutex").push(StoredDesiredResource { key, uid: [0x77; 16], generation: 1, @@ -489,7 +489,7 @@ mod tests { } fn call_order(&self) -> Vec<&'static str> { - self.calls.lock().clone() + self.calls.try_lock().expect("uncontended test mutex").clone() } } @@ -500,7 +500,7 @@ mod tests { _parent: &ResourceKey, _child: ChildEnsure, ) -> Result { - self.calls.lock().push("ensure-child"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.lock().await.push("ensure-child"); Err(ResourceError::ManagerRejected { reason: "unexpected ensure_child".into() }) } @@ -508,7 +508,7 @@ mod tests { &self, _key: &ResourceKey, ) -> Result, ResourceError> { - self.calls.lock().push("get"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.lock().await.push("get"); Ok(None) } @@ -516,13 +516,13 @@ mod tests { &self, _key: &ResourceKey, ) -> Result, ResourceError> { - self.calls.lock().push("view"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.lock().await.push("view"); Err(ResourceError::ManagerRejected { reason: "unexpected view".into() }) } async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { - self.calls.lock().push("delete"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - let mut owned = self.owned.lock(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.lock().await.push("delete"); + let mut owned = self.owned.lock().await; if owned.iter().any(|row| row.key == *key) { owned.retain(|row| row.key != *key); Ok(()) @@ -535,8 +535,8 @@ mod tests { &self, _owner_uid: [u8; 16], ) -> Result, ResourceError> { - self.calls.lock().push("list-owned"); - Ok(self.owned.lock().clone()) + self.calls.lock().await.push("list-owned"); + Ok(self.owned.lock().await.clone()) } async fn register_watch( @@ -544,40 +544,40 @@ mod tests { _subscriber: &ResourceKey, _registration: WatchRegistration, ) -> Result { - self.calls.lock().push("register-watch"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.lock().await.push("register-watch"); Ok(WatchId(1)) } async fn cancel_watch(&self, _watch: WatchId) -> Result<(), ResourceError> { - self.calls.lock().push("cancel-watch"); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.calls.lock().await.push("cancel-watch"); Ok(()) } } struct RecordingRequeue { - calls: parking_lot::Mutex>, + calls: tokio::sync::Mutex>, } impl RecordingRequeue { fn new() -> Arc { Arc::new(Self { - calls: parking_lot::Mutex::new(Vec::new()), + calls: tokio::sync::Mutex::new(Vec::new()), }) } fn call_count(&self) -> usize { - self.calls.lock().len() + self.calls.try_lock().expect("uncontended test mutex").len() } /// The scheduled delays in milliseconds, in arrival order. fn calls(&self) -> Vec { - self.calls.lock().clone() + self.calls.try_lock().expect("uncontended test mutex").clone() } } impl RequeueScheduler for RecordingRequeue { fn schedule(&self, _key: ResourceKey, after: std::time::Duration) -> RequeueId { - self.calls.lock().push(after.as_millis() as u64); + self.calls.try_lock().expect("uncontended test mutex").push(after.as_millis() as u64); RequeueId(0) } diff --git a/packages/d2b-provider-user/src/probe.rs b/packages/d2b-provider-user/src/probe.rs index f31fbbb84..24812f9ab 100644 --- a/packages/d2b-provider-user/src/probe.rs +++ b/packages/d2b-provider-user/src/probe.rs @@ -5,8 +5,15 @@ //! effects: every call that touches the account database - the bounded //! `getpwnam` / `getgrnam` record reads and the group-membership checks - //! lives here, so this crate reaches host state through no daemon runtime. +//! +//! The reads have no async form, so the probe runs the whole blocking body +//! on `d2b-core`'s bounded loader probe seat: a slow or wedged backend +//! (LDAP/NIS) refuses later probes rather than parking this executor +//! worker for the lookup (`spawn_blocking` is banned by plan KD2; the seat +//! is the house replacement). use d2b_contracts_resource::v3::{ResourceRef, user::UserSpec}; +use d2b_core::loader_worker; use d2b_provider_system_core::{ DiscoveredUser, SystemCoreError, UserBinding, UserDiscoveryEffectPort, UserIdentityDigest, UserObservation, @@ -25,11 +32,26 @@ impl UserDiscoveryEffectPort for UserProbe { user_ref: &ResourceRef, spec: &UserSpec, ) -> Result, SystemCoreError> { - discover_local_user(user_ref, spec).await + // The seat job owns the declared identity and builds the complete + // discovery on the worker; a seat that refuses is the ordinary + // "cannot complete" classification, so the driver's mapping and the + // hosted service's refusal code are unchanged. + let reference = user_ref.clone(); + let declared = spec.clone(); + loader_worker::run_probe(move || discover_local_user(&reference, &declared)) + .await + .map_err(|refusal| { + tracing::warn!( + user = %user_ref.name().as_str(), + error = %refusal, + "user probe refused: the bounded NSS probe seat is unavailable", + ); + SystemCoreError::DiscoveryUnavailable + })? } } -/// Resolve one declared User locally. +/// Resolve one declared User locally, on the bounded loader probe seat. /// /// `Ok(None)` means the local machine resolves no such identity, which is /// an ordinary state rather than a failure; an NSS lookup that cannot @@ -37,7 +59,7 @@ impl UserDiscoveryEffectPort for UserProbe { /// derived from the immutable identity material: the declared reference and /// username, the resolved numeric ids, and every declared group, in the /// fixed `d2b-system-core-user-v1` domain. -async fn discover_local_user( +fn discover_local_user( user_ref: &ResourceRef, spec: &UserSpec, ) -> Result, SystemCoreError> { diff --git a/packages/d2b-provider-user/src/test_support.rs b/packages/d2b-provider-user/src/test_support.rs index 9997856e0..298dd54bb 100644 --- a/packages/d2b-provider-user/src/test_support.rs +++ b/packages/d2b-provider-user/src/test_support.rs @@ -22,7 +22,12 @@ //! //! The doubles' ordered call recorder is the toolkit's `SharedLog` //! (`d2b_provider_toolkit::testing`), the canonical recorder shape every -//! family crate's test-support module shares. +//! family crate's test-support module shares. The state the doubles keep +//! themselves - the scripted phase and the requested usernames - lives in +//! `tokio::sync::Mutex`: the effect methods that write it await the lock, +//! and the synchronous accessors that read or script it take a +//! non-blocking `try_lock`, so no double parks an executor worker on a +//! lock. use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; @@ -44,7 +49,7 @@ use crate::facets::UserEffectFacets; /// fail discovery. pub struct RecordingEffects { calls: SharedLog, - phase: parking_lot::Mutex, + phase: tokio::sync::Mutex, /// Script whether the next discovery refuses. pub fail: AtomicBool, } @@ -55,7 +60,7 @@ impl RecordingEffects { pub fn new() -> Arc { Arc::new(Self { calls: SharedLog::new(), - phase: parking_lot::Mutex::new(ResourcePhase::Ready), + phase: tokio::sync::Mutex::new(ResourcePhase::Ready), fail: AtomicBool::new(false), }) } @@ -67,7 +72,7 @@ impl RecordingEffects { /// Script the phase the next discovery reports. pub fn set_phase(&self, phase: ResourcePhase) { - *self.phase.lock() = phase; + *self.phase.try_lock().expect("uncontended test mutex") = phase; } } @@ -85,7 +90,7 @@ impl UserDriverEffects for RecordingEffects { Ok(UserStatusReport { user_ref: user_ref.clone(), provider: "system-core", - phase: *self.phase.lock(), // async-gate-allow: test-support recorder lock + phase: *self.phase.lock().await, discovery: UserDiscoveryCondition::Discovered, identity: None, }) @@ -110,7 +115,7 @@ pub struct ScriptedProbe { struct ScriptedCore { /// The usernames discovery was requested for, in arrival order. - calls: parking_lot::Mutex>, + calls: tokio::sync::Mutex>, /// Whether the next discovery resolves no local record. absent: AtomicBool, /// Whether the next discovery refuses. @@ -123,7 +128,7 @@ impl ScriptedProbe { pub fn new() -> Arc { Arc::new(Self { core: Arc::new(ScriptedCore { - calls: parking_lot::Mutex::new(Vec::new()), + calls: tokio::sync::Mutex::new(Vec::new()), absent: AtomicBool::new(false), failing: AtomicBool::new(false), }), @@ -132,7 +137,11 @@ impl ScriptedProbe { /// The usernames discovery was requested for, in arrival order. pub fn discovered_names(&self) -> Vec { - self.core.calls.lock().clone() + self.core + .calls + .try_lock() + .expect("uncontended test mutex") + .clone() } /// Script whether the next discovery resolves no local record. @@ -153,7 +162,7 @@ impl UserDiscoveryEffectPort for ScriptedProbe { user_ref: &ResourceRef, spec: &UserSpec, ) -> Result, SystemCoreError> { - self.core.calls.lock().push(spec.os_username().clone()); // async-gate-allow: test-support recorder lock + self.core.calls.lock().await.push(spec.os_username().clone()); if self.core.failing.load(Ordering::Relaxed) { return Err(SystemCoreError::DiscoveryUnavailable); } @@ -202,4 +211,4 @@ fn scripted_identity(user_ref: &ResourceRef, spec: &UserSpec) -> UserIdentityDig /// [`UserDiscoveryEffectPort`] boundary. pub fn recording_facets(probe: Arc) -> UserEffectFacets { UserEffectFacets { probe } -} \ No newline at end of file +} diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 5d6426471..c6d0f8d68 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 09fc24831..f2abf96ff 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index ad5c5ae60..d22bf9bbd 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 09fc24831..f2abf96ff 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index f0d0ca295..c4f8ba72d 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 6665fb58d..8795ddb46 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index 04a6a0b89..d335c4667 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 6665fb58d..8795ddb46 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 5a992d736..e1b5e77f8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index e20bad39c..daf606525 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 80f6ad823..7b25bf743 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index e20bad39c..daf606525 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 88dcf7ebf..496766575 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index 09fc24831..f2abf96ff 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index adc1202e8..2da4f65f8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index 09fc24831..f2abf96ff 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index 5b0c5e97d..374dfe270 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1998,12 +1998,12 @@ version = "0.0.0-bootstrap" dependencies = [ "async-trait", "d2b-contracts-resource", + "d2b-core", "d2b-provider-system-core", "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", "nix 0.29.0", - "parking_lot", "serde_json", "sha2", "tokio", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index 5bcce1dba..3331808e6 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -8201,6 +8201,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-user@0.0.0-bootstrap#path", + "to": "d2b-core@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", "to": "d2b-provider-system-core@0.0.0-bootstrap#path", @@ -8233,26 +8239,26 @@ }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "dev", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", - "kind": "dev", + "kind": "normal", "target": null }, { diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index e05733890..b78ed36b5 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index 5b0c5e97d..374dfe270 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1998,12 +1998,12 @@ version = "0.0.0-bootstrap" dependencies = [ "async-trait", "d2b-contracts-resource", + "d2b-core", "d2b-provider-system-core", "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", "nix 0.29.0", - "parking_lot", "serde_json", "sha2", "tokio", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index a0ffc47d5..52afafc49 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -7619,6 +7619,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-user@0.0.0-bootstrap#path", + "to": "d2b-core@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", "to": "d2b-provider-system-core@0.0.0-bootstrap#path", @@ -7651,19 +7657,19 @@ }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index e05733890..b78ed36b5 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 12ca4723f..75686594f 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index b062eab93..91226c802 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index 23e7f62ff..17c5987a9 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index b062eab93..91226c802 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index adaec41a5..7aa64e673 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index f68be57c9..045761813 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index 7d858b3cc..017318690 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index f68be57c9..045761813 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 23b800121..7983c991c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index b9a0c2f10..44e3b0fd8 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 436786c6c..e80f09639 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index b9a0c2f10..44e3b0fd8 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index b72f361c2..f2673e8ca 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index b062eab93..91226c802 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 96fc956e6..6b1b39a2d 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index b062eab93..91226c802 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index 5b0c5e97d..374dfe270 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1998,12 +1998,12 @@ version = "0.0.0-bootstrap" dependencies = [ "async-trait", "d2b-contracts-resource", + "d2b-core", "d2b-provider-system-core", "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", "nix 0.29.0", - "parking_lot", "serde_json", "sha2", "tokio", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index 806d76d7c..d4d26bad2 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -8239,6 +8239,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-user@0.0.0-bootstrap#path", + "to": "d2b-core@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", "to": "d2b-provider-system-core@0.0.0-bootstrap#path", @@ -8271,26 +8277,26 @@ }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "dev", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", - "kind": "dev", + "kind": "normal", "target": null }, { diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index cf9f8c7bd..a90093679 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index 5b0c5e97d..374dfe270 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1998,12 +1998,12 @@ version = "0.0.0-bootstrap" dependencies = [ "async-trait", "d2b-contracts-resource", + "d2b-core", "d2b-provider-system-core", "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", "nix 0.29.0", - "parking_lot", "serde_json", "sha2", "tokio", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index 467490c7f..4e0ab787b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -7657,6 +7657,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-user@0.0.0-bootstrap#path", + "to": "d2b-core@0.0.0-bootstrap#path", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", "to": "d2b-provider-system-core@0.0.0-bootstrap#path", @@ -7689,19 +7695,19 @@ }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", + "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", + "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, { "from": "d2b-provider-user@0.0.0-bootstrap#path", - "to": "sha2@0.10.9#registry+https://github.com/rust-lang/crates.io-index", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", "kind": "normal", "target": null }, diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index cf9f8c7bd..a90093679 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "94cd4f67627f960299ec2696f5f0d8c0458fd95e333064219bd718a932c25582", + "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 5e393ccbf..73857abcb 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -761,51 +761,6 @@ "line": 1030, "reason": "test-support recorder lock" }, - { - "file": "packages/d2b-provider-user/src/driver.rs", - "line": 503, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-user/src/driver.rs", - "line": 511, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-user/src/driver.rs", - "line": 519, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-user/src/driver.rs", - "line": 524, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-user/src/driver.rs", - "line": 525, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-user/src/driver.rs", - "line": 547, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-user/src/driver.rs", - "line": 552, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-user/src/test_support.rs", - "line": 88, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-user/src/test_support.rs", - "line": 156, - "reason": "test-support recorder lock" - }, { "file": "packages/d2b-provider-volume-binding/src/driver.rs", "line": 1243, @@ -1013,12 +968,12 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 26472, + "line": 26622, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26869, + "line": 27019, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 7b480f35d1447ccbc1f63b90c0f42c733b048b7f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:49:40 -0700 Subject: [PATCH 683/726] refactor(d2b-resource-runtime): validate the spec fence in place and evict the ledger by sequence The declaration-only metadata driver's spec object fence returned the decoded `serde_json::Value` it had just validated, and its only caller discarded it. The fence now validates in place: the decode and shape refusals are unchanged, and no validate pass clones the whole spec object. The ACA Guest completed-operation ledger evicted its oldest entry by cloning the map key to hand it to `BTreeMap::remove`. It now computes the minimum record sequence once and drops exactly that entry with a single `retain`, so the eviction path clones no `AcaOperationId`. A unit test records three operations at a capacity of two and pins that the oldest is the one evicted, using non-monotonic identifiers so a key-ordered eviction cannot pass it. The runtime's scripted test doubles take per-site banned-API allows with the `cfg(test) helper` reason. Measured against the resolved `lock_api` deny paths, the blocking census for this crate reads zero unsuppressed lock sites, down from five. --- changelog.d/w7-22-eviction-and-spec-fence.md | 17 +++++++ .../src/controller.rs | 51 +++++++++++++++++-- packages/d2b-resource-runtime/src/context.rs | 5 ++ packages/d2b-resource-runtime/src/metadata.rs | 9 ++-- packages/xtask/data/async-gate-inventory.json | 12 ++--- 5 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 changelog.d/w7-22-eviction-and-spec-fence.md diff --git a/changelog.d/w7-22-eviction-and-spec-fence.md b/changelog.d/w7-22-eviction-and-spec-fence.md new file mode 100644 index 000000000..c620fc9a4 --- /dev/null +++ b/changelog.d/w7-22-eviction-and-spec-fence.md @@ -0,0 +1,17 @@ +### Fixed + +- The ACA Guest completed-operation ledger evicts its oldest entry by + record sequence instead of cloning the map key first. Eviction order, + the capacity bound, and operation replay are unchanged; the eviction + now copies no `AcaOperationId`, and a unit test pins that the first + recorded operation is the one dropped at capacity. + +### Changed + +- The declaration-only metadata driver's spec fence validates the + decoded spec without materializing it: it keeps the same decode and + shape refusals and no longer clones the whole spec object on every + validate pass. The lock acquisitions in the runtime's scripted test + doubles are per-site lint allows whose recorded reason names them as + test-only helpers; the test doubles and their lock types are + unchanged. diff --git a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs index 6e244b1fb..9c488fc8b 100644 --- a/packages/d2b-provider-guest-azure-container-apps/src/controller.rs +++ b/packages/d2b-provider-guest-azure-container-apps/src/controller.rs @@ -150,15 +150,18 @@ impl CompletedOperationLedger { self.completed .insert(operation_id, (expires_at_unix_ms, phase, sequence)); while self.completed.len() > capacity { - let Some(oldest) = self + let Some(oldest_sequence) = self .completed - .iter() - .min_by_key(|(_, (_, _, sequence))| *sequence) - .map(|(operation_id, _)| operation_id.clone()) + .values() + .map(|(_, _, sequence)| *sequence) + .min() else { break; }; - self.completed.remove(&oldest); + // `next_sequence` increments per insert, so a sequence identifies + // exactly one entry: this retain evicts exactly the oldest one. + self.completed + .retain(|_, (_, _, sequence)| *sequence != oldest_sequence); } } @@ -962,3 +965,41 @@ where ) } } + +#[cfg(test)] +mod tests { + use super::{AcaPhase, CompletedOperationLedger}; + use crate::AcaOperationId; + + fn operation(name: &str) -> AcaOperationId { + AcaOperationId::parse(name).expect("valid operation identifier") + } + + /// Eviction follows record order, not key order: the alphabetically + /// smallest identifier is recorded before the larger ones, so an + /// eviction that walked the map instead of the sequence would drop the + /// wrong entry. + #[test] + fn ledger_evicts_the_oldest_operation_first() { + let mut ledger = CompletedOperationLedger::default(); + ledger.record(operation("operation-c"), 1_000, AcaPhase::Ready, 2); + ledger.record(operation("operation-a"), 1_000, AcaPhase::Ready, 2); + ledger.record(operation("operation-b"), 1_000, AcaPhase::Ready, 2); + assert_eq!( + ledger.get(&operation("operation-c")), + None, + "the first recorded operation is evicted at capacity" + ); + assert_eq!(ledger.get(&operation("operation-a")), Some(AcaPhase::Ready)); + assert_eq!(ledger.get(&operation("operation-b")), Some(AcaPhase::Ready)); + + ledger.record(operation("operation-d"), 1_000, AcaPhase::Ready, 2); + assert_eq!( + ledger.get(&operation("operation-a")), + None, + "the next eviction takes the oldest survivor" + ); + assert_eq!(ledger.get(&operation("operation-b")), Some(AcaPhase::Ready)); + assert_eq!(ledger.get(&operation("operation-d")), Some(AcaPhase::Ready)); + } +} diff --git a/packages/d2b-resource-runtime/src/context.rs b/packages/d2b-resource-runtime/src/context.rs index a376f0f96..0dc8f33e7 100644 --- a/packages/d2b-resource-runtime/src/context.rs +++ b/packages/d2b-resource-runtime/src/context.rs @@ -891,6 +891,7 @@ pub(crate) mod test_support { } /// Child keys the manager was asked to delete, in order. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub(crate) fn deleted_keys(&self) -> Vec { self.deleted.lock().clone() } @@ -910,6 +911,7 @@ pub(crate) mod test_support { Err(ResourceError::ManagerRejected { reason: "unexpected view".into() }) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { self.deleted.lock().push(key.clone()); // async-gate-allow: synchronous lock acquisition, no await while the guard is held Ok(()) @@ -961,6 +963,7 @@ pub(crate) mod test_support { } } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub(crate) fn take_receiver(&self) -> mpsc::UnboundedReceiver { self.inner .delivered_rx @@ -971,6 +974,7 @@ pub(crate) mod test_support { } impl RequeueScheduler for TokioRequeue { + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn schedule(&self, _key: ResourceKey, after: std::time::Duration) -> RequeueId { let id = self.inner.next.fetch_add(1, Ordering::SeqCst); let tx = self.inner.delivered_tx.clone(); @@ -982,6 +986,7 @@ pub(crate) mod test_support { RequeueId(id) } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn cancel(&self, id: RequeueId) { if let Some(handle) = self.inner.pending.lock().remove(&id.0) { handle.abort(); diff --git a/packages/d2b-resource-runtime/src/metadata.rs b/packages/d2b-resource-runtime/src/metadata.rs index 033e8f62b..88c2b0220 100644 --- a/packages/d2b-resource-runtime/src/metadata.rs +++ b/packages/d2b-resource-runtime/src/metadata.rs @@ -162,9 +162,10 @@ impl ResourceDriver for MetadataDriver { // --------------------------------------------------------------------------- /// The stored spec object fence every declaration-only metadata type shares: -/// the manager's decode hook must have produced a JSON object, which is -/// exactly what the old `validate_spec` required of the canonical row JSON. -fn spec_object(ctx: &ResourceContext, op: DriverOp) -> Result { +/// validates that the manager's decode hook produced a JSON object - exactly +/// what the old `validate_spec` required of the canonical row JSON - without +/// materializing the decoded value. +fn spec_object(ctx: &ResourceContext, op: DriverOp) -> Result<(), DriverFailure> { let spec = ctx.spec::().map_err(|error| { DriverFailure::refused(op, FailureKinds::CORE_SPEC_INVALID) .with_detail(FailureDetail::at("spec/decode").with_note(error.to_string())) @@ -188,7 +189,7 @@ fn spec_object(ctx: &ResourceContext, op: DriverOp) -> Result Date: Fri, 25 Sep 2026 21:55:23 -0700 Subject: [PATCH 684/726] refactor(d2b-broker): publish only the operation arms something outside the crate imports `ops/mod.rs` declared all 31 handler arms `pub` under a public `pub mod ops;`, so every item in every handler was published surface. The census found no crate outside `d2b-broker` importing `d2b_broker::ops`: the only consumers are the broker's own integration tests, which are separate crates and import three arms by path. `network`, `audit_op`, and `pidfd` therefore stay `pub`; the other 28 arms are `pub(crate)`. The rationale beside `pub mod ops;` and the `ops` module doc record the census and the three-arm split, so a new arm cannot reopen the surface silently. --- changelog.d/w7-17-broker-ops-surface.md | 11 ++++ packages/d2b-broker/src/lib.rs | 8 +++ packages/d2b-broker/src/ops/mod.rs | 74 +++++++++++++++---------- 3 files changed, 65 insertions(+), 28 deletions(-) create mode 100644 changelog.d/w7-17-broker-ops-surface.md diff --git a/changelog.d/w7-17-broker-ops-surface.md b/changelog.d/w7-17-broker-ops-surface.md new file mode 100644 index 000000000..59ad1902f --- /dev/null +++ b/changelog.d/w7-17-broker-ops-surface.md @@ -0,0 +1,11 @@ +### Changed + +- The broker's operation-handler arms are published only where a + consumer outside the crate addresses them. `d2b_broker::ops` + declared all 31 handler modules `pub`, so every item in them was + published surface even though no crate outside `d2b-broker` imported + any of them; only `network`, `audit_op`, and `pidfd` stay `pub`, + because the broker's integration tests are separate crates and + import those arms by path. The other 28 arms are `pub(crate)`, and a + new handler arm stays crate-private until something outside the + crate imports it. No item, type, or behavior inside an arm changed. diff --git a/packages/d2b-broker/src/lib.rs b/packages/d2b-broker/src/lib.rs index 67fe6db33..0fcd84f20 100644 --- a/packages/d2b-broker/src/lib.rs +++ b/packages/d2b-broker/src/lib.rs @@ -47,6 +47,14 @@ pub mod forwarding; #[cfg(not(feature = "layer1-bootstrap"))] pub mod kernel_ops; pub mod live_handlers; +// Broker operation handlers. `ops::mod` declares 31 arms and only the +// three the crate's own integration tests address by path stay `pub` - +// `ops::network`, `ops::audit_op`, and `ops::pidfd` - because those +// tests are separate crates and `pub(crate)` would hide the arms from +// them. Every other arm is `pub(crate)`: no crate outside `d2b-broker` +// imports `d2b_broker::ops`, so publishing them offered a surface with +// no consumer. A new arm stays `pub(crate)` unless an out-of-crate +// consumer appears, and then the integration tests are that consumer. pub mod ops; pub mod protocol; pub mod runtime; diff --git a/packages/d2b-broker/src/ops/mod.rs b/packages/d2b-broker/src/ops/mod.rs index 2fec102e7..2c2e8cf5b 100644 --- a/packages/d2b-broker/src/ops/mod.rs +++ b/packages/d2b-broker/src/ops/mod.rs @@ -15,83 +15,101 @@ //! these modules depend on `d2b-host` and `d2b-contracts`, but //! nothing in the runtime depends on them beyond the integrator-managed //! dispatch wiring. +//! +//! Only three of the arms below are `pub` - `network`, `audit_op`, and +//! `pidfd` - because the crate's integration tests are separate crates +//! and address those arms by path (`tests/bridge_lifecycle.rs`, +//! `tests/persistent_tap_lifecycle.rs`, `tests/security_key_broker.rs`, +//! `tests/pidfd_handoff_scm_rights.rs`, `tests/pidfd_real_spawner.rs`); +//! `pub(crate)` would hide them from that oracle. Every other arm is +//! `pub(crate)`: no crate outside `d2b-broker` imports it, so its items +//! were reachable published surface for no consumer. Keep the split - +//! a new handler arm stays `pub(crate)` until something outside this +//! crate imports it, and the integration tests are the only thing that +//! reopens an arm. // Cgroup v2 delegation + pidfd handoff ops. -pub mod cgroup; +pub(crate) mod cgroup; +// Public arm: `tests/pidfd_handoff_scm_rights.rs` and +// `tests/pidfd_real_spawner.rs` import it from outside the crate. pub mod pidfd; // Bridge / TAP / NM / IPv6 / IfName / state-dir ops. -pub mod hosts; -pub mod nm; -pub mod route; -pub mod state_dir; -pub mod storage_contract; +pub(crate) mod hosts; +pub(crate) mod nm; +pub(crate) mod route; +pub(crate) mod state_dir; +pub(crate) mod storage_contract; // Per-VM swtpm state-dir first-run hardening (issue #64). -pub mod swtpm_dir; -pub mod sysctl; -pub mod tap; +pub(crate) mod swtpm_dir; +pub(crate) mod sysctl; +pub(crate) mod tap; // Nftables + USBIP firewall skeleton ops. +// Public arm: `tests/bridge_lifecycle.rs` imports it from outside the +// crate. pub mod network; -pub mod nft; -pub mod usbip_firewall; +pub(crate) mod nft; +pub(crate) mod usbip_firewall; // Per-busid USBIP exclusivity lock helper. -pub mod usbip_lock; +pub(crate) mod usbip_lock; // Broker-side USBIP host inspection and physical-policy enforcement. -pub mod usbip_host; +pub(crate) mod usbip_host; // Kernel-module + device-fd handoff ops. -pub mod device; +pub(crate) mod device; // Trusted scope of one Device-owned worker launch (row -> Device -> Guest // pin, per-Guest socket directory, Device row uid derivation). -pub mod device_worker; +pub(crate) mod device_worker; // GPU-specific role, allowlist, and restart identity preflight. -pub mod gpu; -pub mod modprobe; +pub(crate) mod gpu; +pub(crate) mod modprobe; // Security-key hidraw open op: resolves stable selector → opens // hidraw fd for `d2bd`'s long-lived CTAPHID relay session. -pub mod security_key; +pub(crate) mod security_key; // Broker SpawnRunner preflight + spawn helper. -pub mod spawn_runner; +pub(crate) mod spawn_runner; // Broker reconcile executors (nft / sysctl / hosts / ip route) with // FakeReconcileExecutor for unit tests + the SystemReconcileExecutor // for production shellouts. -pub mod exec_reconcile; +pub(crate) mod exec_reconcile; // Audit-helper introduced by s2; reusable by s1/s3/s4 going forward. +// Public arm: `tests/persistent_tap_lifecycle.rs` and +// `tests/security_key_broker.rs` import it from outside the crate. pub mod audit_op; // Broker-owned source-to-target NixOS generation handoff journal and replay. -pub mod host_generation_handoff; +pub(crate) mod host_generation_handoff; // Typed broker op that hardlink-farms per-VM closures into // `/var/lib/d2b/vms//store/` and atomically swaps the `current` // symlink. Replaces the `d2b--store-sync.service` bash oneshot. -pub mod store_sync; +pub(crate) mod store_sync; // Signed ADR 0027 terminal audit schema for `StoreSync` (enums + // invariant-enforcing constructors + validation). -pub mod store_sync_audit; +pub(crate) mod store_sync_audit; // StoreSync-only observability JSONL export: a positive-allow-list // projection of the host-confidential `StoreSync` terminal audit record // (ADR 0027). Written to the alloy-readable export directory; never // carries caller identity, retained generations, or any host path. -pub mod store_sync_export; +pub(crate) mod store_sync_export; // Single-inode ownership/mode posture for broker-created store-view // metadata paths. Never recursive into the hardlinked live pool. -pub mod store_view_posture; +pub(crate) mod store_view_posture; // Out-of-process, mount-namespace-isolated store-view hardlink farm // build. Used by `store_sync` so the farm hardlinks succeed even when // `/nix/store` is a separate (bind) mount from `/var/lib/d2b`. -pub mod store_view_farm; +pub(crate) mod store_view_farm; // Per-VM writable store overlay disk-image provisioning. Runs before // SpawnRunner when `DiskInit` plan-ops are present. -pub mod disk_init; +pub(crate) mod disk_init; // qemu-media physical USB enrollment/open by opaque ref. Raw device identity // stays in root-only registry/runtime artifacts outside the Nix store. -pub mod media; +pub(crate) mod media; use std::fmt; use std::path::PathBuf; From f30695d3fab21ed2cd741fc1b7d7461cdc8bf69a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 21:59:55 -0700 Subject: [PATCH 685/726] provider-display-wayland: type the launch failure and return the pooled principal The grant and ticket constructors reported their refusals as a bare `&'static str`, so no caller could match the failure, and the principal release receipt had no constructor, leaving the controller's release path as exported surface nothing could reach. Launches now fail with the closed `LaunchError` enum whose rendered codes are byte-identical to the strings they replace, and the runtime keeps the reconciled session key so finalization returns the dynamic principal lease to the bounded pool after both workers are confirmed terminal and deleted. --- ...play-launch-error-and-principal-release.md | 16 +++ .../src/controller.rs | 10 +- .../d2b-provider-display-wayland/src/lib.rs | 6 +- .../src/process.rs | 44 ++++++- .../src/runtime.rs | 109 +++++++++++++++++- 5 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 changelog.d/w7-11-display-launch-error-and-principal-release.md diff --git a/changelog.d/w7-11-display-launch-error-and-principal-release.md b/changelog.d/w7-11-display-launch-error-and-principal-release.md new file mode 100644 index 000000000..caa48cb5d --- /dev/null +++ b/changelog.d/w7-11-display-launch-error-and-principal-release.md @@ -0,0 +1,16 @@ +### Changed + +- The Wayland display launch boundary now reports failures as the + closed `LaunchError` enum (`SessionInvalid`, `TicketInvalid`) + instead of a bare string, so callers match the failure variant. The + observable failure codes `display-grant-session-invalid` and + `display-launch-ticket-invalid` are unchanged. + +### Fixed + +- `DisplayRuntime` now returns the dynamic principal leased during + display reconciliation to the controller's bounded pool when + finalization runs, after both workers are confirmed terminal and + deleted. The release receipt previously had no constructor, so the + lease was never returned and a session that launched workers held a + pool account until the daemon restarted. diff --git a/packages/d2b-provider-display-wayland/src/controller.rs b/packages/d2b-provider-display-wayland/src/controller.rs index 541399801..b975cfda6 100644 --- a/packages/d2b-provider-display-wayland/src/controller.rs +++ b/packages/d2b-provider-display-wayland/src/controller.rs @@ -686,6 +686,14 @@ pub struct PrincipalReleaseReceipt { session_key: String, } +impl PrincipalReleaseReceipt { + /// Bind one release receipt to a session key reconciled by this + /// controller. + pub(crate) fn new(session_key: String) -> Self { + Self { session_key } + } +} + impl core::fmt::Debug for PrincipalReleaseReceipt { fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("PrincipalReleaseReceipt(REDACTED)") @@ -1422,7 +1430,7 @@ impl core::fmt::Debug for DisplayController { } } -fn session_key(spec: &WaylandSessionSpec, controller_generation: u64) -> String { +pub(crate) fn session_key(spec: &WaylandSessionSpec, controller_generation: u64) -> String { format!( "{}|{}|{}|{}|{}", spec.guest_ref().to_canonical_string(), diff --git a/packages/d2b-provider-display-wayland/src/lib.rs b/packages/d2b-provider-display-wayland/src/lib.rs index ad87d81f9..b12465b52 100644 --- a/packages/d2b-provider-display-wayland/src/lib.rs +++ b/packages/d2b-provider-display-wayland/src/lib.rs @@ -26,9 +26,9 @@ pub use policy::{ pub use principal::{PrincipalLease, PrincipalPool, PrincipalPoolError}; pub use process::DisplayLaunchBinding; pub use process::{ - AttachmentGrantHandle, DisplayProcessRole, LaunchGrants, LaunchTicket, ProcessObservation, - VolumeState, WorkerAction, WorkerRestartEvidence, WorkerState, WorkerSupervisor, - WorkerSupervisorError, + AttachmentGrantHandle, DisplayProcessRole, LaunchError, LaunchGrants, LaunchTicket, + ProcessObservation, VolumeState, WorkerAction, WorkerRestartEvidence, WorkerState, + WorkerSupervisor, WorkerSupervisorError, }; pub use runtime::{ DisplayProcessEffectPort, DisplayRuntime, DisplayRuntimeError, FinalizationReport, diff --git a/packages/d2b-provider-display-wayland/src/process.rs b/packages/d2b-provider-display-wayland/src/process.rs index d89a7ffab..4652b43b0 100644 --- a/packages/d2b-provider-display-wayland/src/process.rs +++ b/packages/d2b-provider-display-wayland/src/process.rs @@ -3,6 +3,21 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; +/// Closed failure set of the sealed display launch boundary. +/// +/// The [`Display`](core::fmt::Display) message of each variant is the +/// observable failure code; callers match the variant instead of the code +/// text, so no caller ever depends on a string comparison. +#[derive(Debug, thiserror::Error, PartialEq, Eq)] +pub enum LaunchError { + /// The supplied session evidence cannot issue launch grants. + #[error("display-grant-session-invalid")] + SessionInvalid, + /// The requested role ticket violates the sealed launch contract. + #[error("display-launch-ticket-invalid")] + TicketInvalid, +} + /// Lifecycle evidence for one independently supervised worker. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum WorkerState { @@ -332,18 +347,23 @@ pub struct LaunchGrants { impl LaunchGrants { /// Issue grants bound to the authenticated controller generation. + /// + /// # Errors + /// + /// Returns [`LaunchError::SessionInvalid`] when the session digest or one + /// of the reconnect, controller, and teardown generations is zero. pub fn issue_for_supervisor_with_controller_generation( session_digest: [u8; 32], reconnect_generation: u64, controller_generation: u64, teardown_generation: u64, - ) -> Result { + ) -> Result { if reconnect_generation == 0 || controller_generation == 0 || teardown_generation == 0 || session_digest == [0; 32] { - return Err("display-grant-session-invalid"); + return Err(LaunchError::SessionInvalid); } Ok( Self::from_supervisor_for_session_with_frontend_and_controller( @@ -806,7 +826,7 @@ impl LaunchTicket { policy_generation: u64, identity_label: impl Into, teardown_generation: u64, - ) -> Result { + ) -> Result { Self::new_for_role_with_controller_generation( role, compositor_grant, @@ -820,6 +840,12 @@ impl LaunchTicket { /// Construct one role-specific ticket with an authenticated controller /// generation. + /// + /// # Errors + /// + /// Returns [`LaunchError::TicketInvalid`] when the policy digest is not a + /// sealed digest, the identity label is empty or too long, a generation is + /// zero, or the HostProxy role is missing its compositor grant. pub(crate) fn new_for_role_with_controller_generation( role: DisplayProcessRole, compositor_grant: Option, @@ -828,7 +854,7 @@ impl LaunchTicket { policy_generation: u64, identity_label: impl Into, generations: LaunchGenerations, - ) -> Result { + ) -> Result { let policy_digest = policy_digest.into(); let identity_label = identity_label.into(); if !policy_digest.starts_with("sha256:") @@ -838,7 +864,7 @@ impl LaunchTicket { || generations.teardown == 0 || (role == DisplayProcessRole::HostProxy && compositor_grant.is_none()) { - return Err("display-launch-ticket-invalid"); + return Err(LaunchError::TicketInvalid); } Ok(Self { role, @@ -853,6 +879,12 @@ impl LaunchTicket { } /// Construct an opaque role ticket for daemon conformance tests. + /// + /// # Errors + /// + /// Returns [`LaunchError::TicketInvalid`] for the same contract + /// violations rejected by + /// [`Self::new_for_role_with_controller_generation`]. #[cfg(feature = "test-support")] pub fn new_for_daemon( role: DisplayProcessRole, @@ -862,7 +894,7 @@ impl LaunchTicket { policy_generation: u64, identity_label: impl Into, teardown_generation: u64, - ) -> Result { + ) -> Result { Self::new_for_role( role, compositor_grant, diff --git a/packages/d2b-provider-display-wayland/src/runtime.rs b/packages/d2b-provider-display-wayland/src/runtime.rs index 70af2c74c..d745099e9 100644 --- a/packages/d2b-provider-display-wayland/src/runtime.rs +++ b/packages/d2b-provider-display-wayland/src/runtime.rs @@ -14,8 +14,9 @@ use sha2::{Digest, Sha256}; use crate::{ AuthenticatedDisplaySession, CleanupState, DependencyState, DisplayController, DisplayDependencyProof, DisplayProcessRole, FinalizationDecision, FinalizationInput, - GraceState, LaunchGrants, ProcessObservation, StopRequest, VolumeState, WaylandPolicySnapshot, - WaylandSessionResourceStatus, WaylandSessionSpec, WorkerState, process::WorkerRestartEvidence, + GraceState, LaunchGrants, PrincipalReleaseReceipt, ProcessObservation, StopRequest, VolumeState, + WaylandPolicySnapshot, WaylandSessionResourceStatus, WaylandSessionSpec, WorkerState, + process::WorkerRestartEvidence, }; /// Failure returned by the daemon-owned display effect port. @@ -228,6 +229,7 @@ pub struct DisplayRuntime { observation: ProcessObservation, supervision: WorkerRestartEvidence, issued_grants: BTreeSet<[u8; 32]>, + reconciled_session_key: Option, stop_requested: bool, authority: CleanupState, principal: CleanupState, @@ -254,6 +256,7 @@ where ), supervision: WorkerRestartEvidence::from_supervisor(0, None, None, 1), issued_grants: BTreeSet::new(), + reconciled_session_key: None, stop_requested: false, authority: CleanupState::Pending, principal: CleanupState::Pending, @@ -366,6 +369,7 @@ where ); return Err(DisplayRuntimeError::SessionMismatch); } + self.remember_session_key(spec, &authenticated); self.effects .bind_session( &authenticated, @@ -568,6 +572,7 @@ where ); return Err(DisplayRuntimeError::SessionMismatch); } + self.remember_session_key(spec, &authenticated); self.effects .bind_session( &authenticated, @@ -740,6 +745,19 @@ where Ok(result) } + /// Retain the reconciled session key so finalization can return the + /// dynamic principal lease to the controller's bounded pool. + fn remember_session_key( + &mut self, + spec: &WaylandSessionSpec, + authenticated: &AuthenticatedDisplaySession, + ) { + self.reconciled_session_key = Some(crate::controller::session_key( + spec, + authenticated.controller_generation(), + )); + } + fn observe_receipt(&mut self, receipt: WorkerLaunchReceipt) { let (proxy, frontend) = match receipt.role() { DisplayProcessRole::HostProxy => (receipt.state(), self.observation.frontend), @@ -847,6 +865,19 @@ where tracing::warn!(error = %e, "principal release effect failed during finalization"); DisplayRuntimeError::Effect(e) })?; + // Both workers are terminal and deleted above, so the dynamic + // principal leased by the reconciliation is no longer in use: the + // controller returns it to the bounded pool. + if let Some(session_key) = self.reconciled_session_key.take() + && let Err(error) = self + .controller + .release_session_principal(PrincipalReleaseReceipt::new(session_key)) + { + tracing::debug!( + error = %error, + "controller principal release skipped: no lease for the reconciled session" + ); + } self.authority = self .effects .release_authority() @@ -1161,4 +1192,78 @@ mod tests { assert_eq!(runtime.effects.nonce, 1); assert_eq!(runtime.effects.launches.len(), 2); } + + fn registered_display() -> (WaylandSessionSpec, WaylandPolicySnapshot) { + let spec = WaylandSessionSpec::new( + ResourceRef::parse("Guest/test").unwrap(), + ResourceRef::parse("Host/test").unwrap(), + ResourceRef::parse("User/alice").unwrap(), + ResourceRef::parse("display-wayland.d2bus.org.WaylandPolicy/default").unwrap(), + DisplayIdentity::new("test", "#7fc8ff", "#45475a", "#f38ab8").unwrap(), + true, + ) + .unwrap(); + let policy = WaylandPolicySnapshot::from_test_core( + spec.policy_ref().clone(), + ZoneId::parse("dev").unwrap(), + 1, + FilterInput::default(), + FilterInput::default(), + ) + .unwrap(); + (spec, policy) + } + + fn registered_route(reconnect_generation: u64) -> AuthenticatedSessionRouteBinding { + AuthenticatedSessionRouteBinding::for_test( + Some(ResourceRef::parse(crate::PROVIDER_REF).unwrap()), + crate::SERVICE_PACKAGE, + reconnect_generation, + Some(1), + Some(1), + ) + } + + #[test] + fn finalize_returns_the_reconciled_principal_to_the_bounded_pool() { + let (spec, policy) = registered_display(); + let effects = Effects { + launch_state: Some(WorkerState::Ready { generation: 1 }), + ..Effects::default() + }; + // A single-principal pool makes the release observable: while the + // reconciled session holds its dynamic lease, no later session can + // reach Ready. + let mut runtime = DisplayRuntime::new(DisplayController::new(1).unwrap(), effects); + let supervision = WorkerRestartEvidence::from_supervisor(1, None, None, 1); + let ready = runtime + .reconcile_registered( + ®istered_route(1), + &spec, + DependencyState::ready(), + supervision, + &policy, + ) + .unwrap(); + assert_eq!(ready.status.phase, crate::controller::Phase::Ready); + assert!(ready.status.principal.is_some()); + + runtime.finalize(GraceState::Active).unwrap(); + + let next_spec = spec.with_reconnect_generation(2).unwrap(); + let next = runtime + .reconcile_registered( + ®istered_route(2), + &next_spec, + DependencyState::ready(), + supervision, + &policy, + ) + .unwrap(); + assert_eq!(next.status.phase, crate::controller::Phase::Ready); + assert!( + next.status.principal.is_some(), + "finalize must have returned the first session's principal to the pool" + ); + } } From 1f8e52a5f6fae76b66e97c515ba311772ed21c1e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:01:16 -0700 Subject: [PATCH 686/726] refactor(d2b-provider-audio-pipewire): name the nothing-applied audio status `AudioLastSetApplied::OfflineOnly` read as "applied offline only" while its own documentation said "No setting was applied in the current reconcile", and the wayland-policy projection published that name as the wire-visible `resource.lastSetApplied` label. The variant is now `AudioLastSetApplied::NotApplied` and the projection publishes `NotApplied`, so the label states the outcome instead of naming an application path. The projection, the wayland-policy and daemon test pins, and the provider dossier's enum row move together; a census over the tree finds no other consumer of the string. --- .../w7-23-broker-keyring-and-audio-variant.md | 19 +++++++++++++++++++ .../ADR-046-provider-audio-pipewire.md | 2 +- .../src/controller.rs | 4 ++-- .../src/audio_registry.rs | 8 ++++---- packages/d2bd/src/resource_plane_v3.rs | 2 +- 5 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 changelog.d/w7-23-broker-keyring-and-audio-variant.md diff --git a/changelog.d/w7-23-broker-keyring-and-audio-variant.md b/changelog.d/w7-23-broker-keyring-and-audio-variant.md new file mode 100644 index 000000000..08dd45835 --- /dev/null +++ b/changelog.d/w7-23-broker-keyring-and-audio-variant.md @@ -0,0 +1,19 @@ +### Changed + +- The USB-audit serial HMAC keyring builds as one synchronous job on the + bounded loader probe seat instead of on the caller's executor. The + 0o700 root-owned directory prepare, the `O_NOFOLLOW | O_CLOEXEC` key + reads, the dir-fd `openat` create with its 0o400 stamp, and the file + and directory fsyncs all block, and a USB bind reaches the keyring + from an async handler, so the syscall chain could park a runtime + worker. Every check is unchanged: the same descriptor-level root-only + validation, the same directory posture, and the same create-then-read- + back order. A saturated seat refuses the call instead of growing + threads. +- `AudioLastSetApplied::OfflineOnly` is renamed + `AudioLastSetApplied::NotApplied`, and the wire-visible + `resource.lastSetApplied` label the wayland-policy projection + publishes is `NotApplied` with it. The variant means "no setting was + applied in the current reconcile", which its documentation said and + its old name did not; the projection, the wayland-policy and daemon + test pins, and the provider ADR's enum row all move together. diff --git a/docs/specs/providers/ADR-046-provider-audio-pipewire.md b/docs/specs/providers/ADR-046-provider-audio-pipewire.md index 71ce47f71..80def26e8 100644 --- a/docs/specs/providers/ADR-046-provider-audio-pipewire.md +++ b/docs/specs/providers/ADR-046-provider-audio-pipewire.md @@ -745,7 +745,7 @@ single-flight priority lane. | `resource.channels.mic.liveEnforced` | bool | True when confirmed through the referenced AudioService this reconcile | | `resource.channels.mic.arbitrationState` | enum | `inactive\|queued\|active\|blocked`; `active` is possible for at most one consumer of an owner Service | | `resource.enforcementPosture` | enum | `HostAndGuest\|HostOnly\|GuestOnly\|None` | -| `resource.lastSetApplied` | enum | `HostAndGuest\|HostOnly\|GuestOnly\|OfflineOnly` | +| `resource.lastSetApplied` | enum | `HostAndGuest\|HostOnly\|GuestOnly\|NotApplied` | | `resource.observedServiceRef` | ResourceRef | Last resolved same-Zone AudioService; must equal `spec.serviceRef` | | `resource.realizationRefs` | list[ResourceRef] | At most 32 same-Zone owned `Process`/`Endpoint` refs; no implementation locator or identity | | `outcome.code` | string | Closed enum; see error codes | diff --git a/packages/d2b-provider-audio-pipewire/src/controller.rs b/packages/d2b-provider-audio-pipewire/src/controller.rs index c8f8947b3..37216016c 100644 --- a/packages/d2b-provider-audio-pipewire/src/controller.rs +++ b/packages/d2b-provider-audio-pipewire/src/controller.rs @@ -140,7 +140,7 @@ pub enum AudioLastSetApplied { /// Applied to the guest only. GuestOnly, /// No setting was applied in the current reconcile. - OfflineOnly, + NotApplied, } /// Typed AudioBinding status projection. @@ -591,7 +591,7 @@ impl AudioBindingController { (true, true) => AudioLastSetApplied::HostAndGuest, (true, false) => AudioLastSetApplied::HostOnly, (false, true) => AudioLastSetApplied::GuestOnly, - (false, false) => AudioLastSetApplied::OfflineOnly, + (false, false) => AudioLastSetApplied::NotApplied, }; Ok(AudioReconcileResult { status: AudioBindingStatus { diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index f3df175d0..20bb3010d 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -121,7 +121,7 @@ pub(crate) fn audio_binding_status_value(status: AudioBindingStatus) -> serde_js AudioLastSetApplied::HostAndGuest => "HostAndGuest", AudioLastSetApplied::HostOnly => "HostOnly", AudioLastSetApplied::GuestOnly => "GuestOnly", - AudioLastSetApplied::OfflineOnly => "OfflineOnly", + AudioLastSetApplied::NotApplied => "NotApplied", }, }) } @@ -481,7 +481,7 @@ fn unavailable_status( }, }, enforcement_posture: AudioEnforcementPosture::None, - last_set_applied: AudioLastSetApplied::OfflineOnly, + last_set_applied: AudioLastSetApplied::NotApplied, } } @@ -711,7 +711,7 @@ mod tests { assert_eq!(status["channels"]["mic"]["grant"], "off"); assert_eq!(status["channels"]["mic"]["arbitrationState"], "inactive"); assert_eq!(status["enforcementPosture"], "None"); - assert_eq!(status["lastSetApplied"], "OfflineOnly"); + assert_eq!(status["lastSetApplied"], "NotApplied"); } #[test] @@ -751,7 +751,7 @@ mod tests { assert_eq!(projection["channels"]["speaker"]["grant"], "off"); assert_eq!(projection["channels"]["mic"]["grant"], "off"); assert_eq!(projection["enforcementPosture"], "None"); - assert_eq!(projection["lastSetApplied"], "OfflineOnly"); + assert_eq!(projection["lastSetApplied"], "NotApplied"); } #[test] diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index cc838c83a..c7d3cd86b 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -4603,7 +4603,7 @@ HOST_EFFECTS_SERVICE.id, }, }, "enforcementPosture": "None", - "lastSetApplied": "OfflineOnly", + "lastSetApplied": "NotApplied", }], })) .expect("canonical payload"), From 792ca2002d85222fef3c2db6ffabd7851b1b0070 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:01:19 -0700 Subject: [PATCH 687/726] refactor(d2b-broker): build the USB-audit keyring on the bounded probe seat `usb_audit_serial_hmac_keyring` ran its filesystem work on the caller's executor: two `path_safe::ensure_dir` openat chains, the `O_NOFOLLOW | O_CLOEXEC` key opens, the dir-fd `openat` create with its 0o400 stamp, and the file and directory fsyncs, with only the file bodies on `tokio::fs`. A USB bind reaches the keyring from an async handler, so the chain parked a runtime worker per call. The build is now one synchronous job on `d2b-core`'s bounded probe seat, the shape the repository uses where the kernel path has no async form: the worker body keeps every check exactly as it was - same 0o700 root-owned directories, same descriptor-level root-only validation, same create-then-read-back order, same error text - and the async seat awaits it. A saturated seat refuses the call with a typed error instead of growing threads, and the rotation-window event is emitted from the async seat so it keeps the caller's tracing context. The async-gate hatch inventory is regenerated in the same commit: the keyring body shifts the four broker runtime marker lines by 43, and the same run repairs two `d2bd/src/composition.rs` entries that were already 150 lines stale at the base commit. --- packages/d2b-broker/src/runtime.rs | 113 ++++++++++++------ packages/xtask/data/async-gate-inventory.json | 12 +- 2 files changed, 84 insertions(+), 41 deletions(-) diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index a0e894bee..f037329df 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -7708,27 +7708,51 @@ async fn usb_audit_serial_hmac_keyring( test_mode: bool, ) -> Result { let key_dir = usb_audit_serial_hmac_key_dir(state_dir); - ensure_usb_audit_serial_hmac_key_dir(&key_dir, test_mode)?; + // The build is blocking filesystem work: the `path_safe` directory + // prepare and the dir-fd key create are openat chains with no async + // form, and the descriptor-open `O_NOFOLLOW` reads interleave them. It + // runs as one job on the bounded probe seat, so admission is a + // non-blocking `try_send` and a saturated seat refuses the call instead + // of growing threads or parking an executor worker. + let keyring = d2b_core::loader_worker::run_probe(move || { + build_usb_audit_serial_hmac_keyring(&key_dir, test_mode) + }) + .await + .map_err(|err| { + BrokerError::LiveHandler(format!( + "USB audit serial HMAC keyring worker refused: {err}" + )) + })??; + // Logged from the async seat so the event keeps the caller's span + // context; the built keyring is all this needs. + log_usb_audit_serial_hmac_rotation_window(&keyring); + Ok(keyring) +} + +/// Build the keyring. Blocking-work body: reached only through +/// [`usb_audit_serial_hmac_keyring`], whose job runs it on the bounded probe +/// seat, so the directory ensures, the `O_NOFOLLOW` opens, the dir-fd key +/// create, and the dir-fd fsync never run on an executor worker. +#[cfg(not(feature = "layer1-bootstrap"))] +fn build_usb_audit_serial_hmac_keyring( + key_dir: &Path, + test_mode: bool, +) -> Result { + ensure_usb_audit_serial_hmac_key_dir(key_dir, test_mode)?; let current = match read_usb_audit_serial_hmac_key_file( &key_dir.join(USB_AUDIT_SERIAL_HMAC_CURRENT_KEY_FILE), UsbAuditSerialHmacKeySlot::Current, test_mode, - ) - .await? - { + )? { Some(key) => key, - None => create_usb_audit_serial_hmac_key(&key_dir, test_mode).await?, + None => create_usb_audit_serial_hmac_key(key_dir, test_mode)?, }; let previous = read_usb_audit_serial_hmac_key_file( &key_dir.join(USB_AUDIT_SERIAL_HMAC_PREVIOUS_KEY_FILE), UsbAuditSerialHmacKeySlot::Previous, test_mode, - ) - .await?; - - let keyring = UsbAuditSerialHmacKeyring { current, previous }; - log_usb_audit_serial_hmac_rotation_window(&keyring); - Ok(keyring) + )?; + Ok(UsbAuditSerialHmacKeyring { current, previous }) } #[cfg(not(feature = "layer1-bootstrap"))] @@ -7738,6 +7762,10 @@ fn usb_audit_serial_hmac_key_dir(state_dir: &Path) -> PathBuf { .join(USB_AUDIT_SERIAL_HMAC_KEY_DIR) } +/// Prepare the secrets and key directories at 0o700 with the key directory +/// owned by root outside test mode. Blocking-work body: reached only from +/// [`build_usb_audit_serial_hmac_keyring`] on the bounded probe seat, so the +/// openat walk, the mkdir, and the mode/owner stamp stay off the executor. #[cfg(not(feature = "layer1-bootstrap"))] fn ensure_usb_audit_serial_hmac_key_dir( key_dir: &Path, @@ -7760,12 +7788,17 @@ fn ensure_usb_audit_serial_hmac_key_dir( Ok(()) } +/// Read one key slot. Blocking-work body: reached only from +/// [`build_usb_audit_serial_hmac_keyring`] on the bounded probe seat. The +/// open is `O_NOFOLLOW | O_CLOEXEC`, and the descriptor it returns is +/// validated as a root-only regular file before any byte is read. #[cfg(not(feature = "layer1-bootstrap"))] -async fn read_usb_audit_serial_hmac_key_file( +fn read_usb_audit_serial_hmac_key_file( path: &Path, slot: UsbAuditSerialHmacKeySlot, test_mode: bool, ) -> Result, BrokerError> { + use std::io::Read as _; let fd = match nix::fcntl::open( path, nix::fcntl::OFlag::O_RDONLY | nix::fcntl::OFlag::O_CLOEXEC | nix::fcntl::OFlag::O_NOFOLLOW, @@ -7779,22 +7812,23 @@ async fn read_usb_audit_serial_hmac_key_file( ))); } }; - use tokio::io::AsyncReadExt as _; - let file = tokio::fs::File::from_std(fs::File::from(owned_fd_from_raw(fd))); - validate_usb_audit_serial_hmac_key_metadata(&file, test_mode).await?; + let mut file = fs::File::from(owned_fd_from_raw(fd)); + validate_usb_audit_serial_hmac_key_metadata(&file, test_mode)?; let mut contents = String::new(); - file.take(u64::MAX).read_to_string(&mut contents).await.map_err(|err| { + file.read_to_string(&mut contents).map_err(|err| { BrokerError::LiveHandler(format!("read USB audit serial HMAC key failed: {err}")) })?; parse_usb_audit_serial_hmac_key(&contents, slot).map(Some) } +/// The root-only regular-file check, on the descriptor the caller already +/// holds: no path is re-resolved between the open and the check. #[cfg(not(feature = "layer1-bootstrap"))] -async fn validate_usb_audit_serial_hmac_key_metadata( - file: &tokio::fs::File, +fn validate_usb_audit_serial_hmac_key_metadata( + file: &fs::File, test_mode: bool, ) -> Result<(), BrokerError> { - let metadata = file.metadata().await.map_err(|err| { + let metadata = file.metadata().map_err(|err| { BrokerError::LiveHandler(format!("stat USB audit serial HMAC key failed: {err}")) })?; if !metadata.is_file() || metadata.mode() & 0o077 != 0 || (!test_mode && metadata.uid() != 0) { @@ -7805,18 +7839,20 @@ async fn validate_usb_audit_serial_hmac_key_metadata( Ok(()) } +/// Create the current key through the dir-fd `openat` create, then read it +/// back so the caller uses exactly the bytes that reached the disk. #[cfg(not(feature = "layer1-bootstrap"))] -async fn create_usb_audit_serial_hmac_key( +fn create_usb_audit_serial_hmac_key( key_dir: &Path, test_mode: bool, ) -> Result { - let key = generate_usb_audit_serial_hmac_key().await?; + let key = generate_usb_audit_serial_hmac_key()?; let dir_fd = crate::sys::path_safe::open_dir_path_safe(key_dir).map_err(|err| { BrokerError::LiveHandler(format!( "open USB audit serial HMAC key directory failed: {err}" )) })?; - match write_new_usb_audit_serial_hmac_key_file(&dir_fd, &key).await { + match write_new_usb_audit_serial_hmac_key_file(&dir_fd, &key) { Ok(()) => {} Err(err) if err.kind() == io::ErrorKind::AlreadyExists => {} Err(err) => { @@ -7829,36 +7865,40 @@ async fn create_usb_audit_serial_hmac_key( &key_dir.join(USB_AUDIT_SERIAL_HMAC_CURRENT_KEY_FILE), UsbAuditSerialHmacKeySlot::Current, test_mode, - ) - .await? + )? .ok_or_else(|| { BrokerError::LiveHandler("USB audit serial HMAC key disappeared after creation".to_owned()) }) } +/// Write the current key file. Blocking-work body: reached only from +/// [`build_usb_audit_serial_hmac_keyring`] on the bounded probe seat, so the +/// dir-fd create, the 0o400 stamp, and the file and directory fsyncs stay +/// off the executor. #[cfg(not(feature = "layer1-bootstrap"))] -async fn write_new_usb_audit_serial_hmac_key_file( +#[allow(clippy::disallowed_methods, reason = "dedicated bounded worker per plan R4")] +fn write_new_usb_audit_serial_hmac_key_file( dir_fd: &OwnedFd, key: &UsbAuditSerialHmacKey, ) -> io::Result<()> { - use tokio::io::AsyncWriteExt as _; + use std::io::Write as _; let fd = crate::sys::path_safe::create_file_at_safe( dir_fd, USB_AUDIT_SERIAL_HMAC_CURRENT_KEY_FILE, libc::O_WRONLY | libc::O_CREAT | libc::O_EXCL, 0o400, )?; - let mut file = tokio::fs::File::from_std(fs::File::from(fd)); - file.write_all(render_usb_audit_serial_hmac_key(key).as_bytes()).await?; + let mut file = fs::File::from(fd); + file.write_all(render_usb_audit_serial_hmac_key(key).as_bytes())?; crate::sys::path_safe::fchmod(file.as_fd(), 0o400)?; - file.sync_all().await?; + file.sync_all()?; rustix::fs::fsync(dir_fd).map_err(|err| io::Error::from_raw_os_error(err.raw_os_error()))?; Ok(()) } #[cfg(not(feature = "layer1-bootstrap"))] -async fn generate_usb_audit_serial_hmac_key() -> Result { - let random = read_high_entropy_bytes(USB_AUDIT_SERIAL_HMAC_RANDOM_BYTES).await?; +fn generate_usb_audit_serial_hmac_key() -> Result { + let random = read_high_entropy_bytes(USB_AUDIT_SERIAL_HMAC_RANDOM_BYTES)?; let (key, id_bytes) = random.split_at(USB_AUDIT_SERIAL_HMAC_KEY_BYTES); Ok(UsbAuditSerialHmacKey { slot: UsbAuditSerialHmacKeySlot::Current, @@ -7867,16 +7907,19 @@ async fn generate_usb_audit_serial_hmac_key() -> Result Result, BrokerError> { - use tokio::io::AsyncReadExt as _; - let mut file = tokio::fs::File::open("/dev/urandom").await.map_err(|err| { +#[allow(clippy::disallowed_methods, reason = "dedicated bounded worker per plan R4")] +fn read_high_entropy_bytes(len: usize) -> Result, BrokerError> { + use std::io::Read as _; + let mut file = fs::File::open("/dev/urandom").map_err(|err| { BrokerError::LiveHandler(format!( "open kernel CSPRNG for USB audit key failed: {err}" )) })?; let mut bytes = vec![0u8; len]; - file.read_exact(&mut bytes).await.map_err(|err| { + file.read_exact(&mut bytes).map_err(|err| { BrokerError::LiveHandler(format!( "read kernel CSPRNG for USB audit key failed: {err}" )) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 5e393ccbf..bdc4e9361 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -123,22 +123,22 @@ }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8255, + "line": 8298, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8322, + "line": 8365, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8539, + "line": 8582, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-broker/src/runtime.rs", - "line": 8616, + "line": 8659, "reason": "synchronous lock acquisition, no await while the guard is held" }, { @@ -1013,12 +1013,12 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 26472, + "line": 26622, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26869, + "line": 27019, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 764d87ef9c3070f87c0c50b159bf922f1060b628 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:06:30 -0700 Subject: [PATCH 688/726] refactor(d2b-provider-process): await the one-shot lifecycle clocks The Process/EphemeralProcess driver's runtime-only one-shot memory guarded its launcher clock and its terminal-outcome clock with a parking_lot mutex inside methods every caller reaches from an async driver pass, so a pass could park the executor worker behind another holder of either clock. Both clocks are tokio::sync::Mutex now, every acquisition is awaited, and the two test-only backdating helpers and the assertion helper await with them; the clocks' semantics are unchanged - the launch clock is still set once, and a second terminal observation still keeps the first, so the retention TTL never restarts. The records that remain are test-only state, never an executor worker's path: the shared test-support recorder double, the driver's own manager and requeue doubles, and the committed-identity double in the effects-service tests keep their synchronous locks under per-site "cfg(test) helper" allows, which is why parking_lot stays in the manifest. The crate now reports no unsuppressed use of a denied lock path. The async-gate hatch inventory is regenerated for the shifted marker lines; the marker set itself is unchanged. --- changelog.d/w7-19-process-async-runtime.md | 12 +++ packages/d2b-provider-process/src/driver.rs | 74 ++++++++++--------- .../src/effects_service.rs | 2 + .../d2b-provider-process/src/test_support.rs | 2 + packages/xtask/data/async-gate-inventory.json | 56 +++++++------- 5 files changed, 85 insertions(+), 61 deletions(-) create mode 100644 changelog.d/w7-19-process-async-runtime.md diff --git a/changelog.d/w7-19-process-async-runtime.md b/changelog.d/w7-19-process-async-runtime.md new file mode 100644 index 000000000..75bcedd78 --- /dev/null +++ b/changelog.d/w7-19-process-async-runtime.md @@ -0,0 +1,12 @@ +### Changed + +- The `Process`/`EphemeralProcess` driver's one-shot lifecycle memory + guards its launcher clock and its terminal-outcome clock with + `tokio::sync::Mutex` and awaits every acquisition, so a pass reaching + either clock never parks the executor worker behind another holder. + The clock semantics are unchanged: the launch clock is still set once, + and a second terminal observation still keeps the first (the retention + TTL never restarts). +- Every remaining lock site in the crate is either awaited or carries a + per-site suppression whose reason names why it stays synchronous, so + the crate reports no unsuppressed use of a denied lock path. diff --git a/packages/d2b-provider-process/src/driver.rs b/packages/d2b-provider-process/src/driver.rs index ea906ce61..806d1421c 100644 --- a/packages/d2b-provider-process/src/driver.rs +++ b/packages/d2b-provider-process/src/driver.rs @@ -677,9 +677,9 @@ struct EphemeralRuntime { started: AtomicBool, /// When the process was launched or adopted: the clock for the bounded /// runtime deadline. - started_at: parking_lot::Mutex>, + started_at: tokio::sync::Mutex>, /// The terminal outcome, once observed: the clock for the retention TTL. - completed: parking_lot::Mutex>, + completed: tokio::sync::Mutex>, } /// One one-shot terminal outcome: the TTL class and when it was reached. @@ -695,22 +695,22 @@ impl EphemeralRuntime { self.started.load(Ordering::Relaxed) } - fn mark_started(&self) { - let mut started_at = self.started_at.lock(); + async fn mark_started(&self) { + let mut started_at = self.started_at.lock().await; if started_at.is_none() { *started_at = Some(tokio::time::Instant::now()); } self.started.store(true, Ordering::Relaxed); } - fn started_at(&self) -> Option { - *self.started_at.lock() + async fn started_at(&self) -> Option { + *self.started_at.lock().await } /// Record the one-shot terminal state once; a second observation keeps /// the first (the TTL clock must not restart). - fn finish(&self, failed: bool, code: &'static str) -> EphemeralCompletion { - let mut completed = self.completed.lock(); + async fn finish(&self, failed: bool, code: &'static str) -> EphemeralCompletion { + let mut completed = self.completed.lock().await; *completed.get_or_insert(EphemeralCompletion { failed, code, @@ -718,14 +718,14 @@ impl EphemeralRuntime { }) } - fn completed(&self) -> Option { - *self.completed.lock() + async fn completed(&self) -> Option { + *self.completed.lock().await } /// Test-only: backdate the runtime-deadline clock. #[cfg(test)] - fn backdate_started(&self, elapsed: Duration) { - let mut started_at = self.started_at.lock(); + async fn backdate_started(&self, elapsed: Duration) { + let mut started_at = self.started_at.lock().await; if let Some(at) = started_at.as_mut() { *at -= elapsed; } @@ -734,8 +734,8 @@ impl EphemeralRuntime { /// Test-only: backdate the retention TTL clock. #[cfg(test)] - fn backdate_completed(&self, elapsed: Duration) { - if let Some(completion) = self.completed.lock().as_mut() { + async fn backdate_completed(&self, elapsed: Duration) { + if let Some(completion) = self.completed.lock().await.as_mut() { completion.at -= elapsed; } } @@ -1351,7 +1351,7 @@ impl ProcessDriver { ) -> Result { match self.effects.adopt_ephemeral(identity, spec).await { Ok(ProviderAdoption::Adopted(_)) => { - self.ephemeral.mark_started(); + self.ephemeral.mark_started().await; ctx.set_status(ProcessDriverStatus::Ready { adopted: true }); Ok(RecoveryOutcome::Adopted) } @@ -1603,7 +1603,7 @@ impl ProcessDriver { identity: &ProcessResourceIdentity, spec: &EphemeralProcessSpec, ) -> Result { - if let Some(completion) = self.ephemeral.completed() { + if let Some(completion) = self.ephemeral.completed().await { return self.ephemeral_retention(ctx, spec, completion).await; } @@ -1611,7 +1611,7 @@ impl ProcessDriver { // this actor started outlived its bounded run, so it stops exactly and // the terminal outcome is `Failed`. if self.ephemeral.started() - && let Some(started_at) = self.ephemeral.started_at() + && let Some(started_at) = self.ephemeral.started_at().await && started_at.elapsed() >= Duration::from_millis(spec.runtime_deadline().as_millis()) { if self.effects.has_active( @@ -1629,7 +1629,7 @@ impl ProcessDriver { .await .map_err(|error| map_provider_error(error, DriverOp::Reconcile))?; } - let completion = self.ephemeral.finish(true, "runtime-deadline"); + let completion = self.ephemeral.finish(true, "runtime-deadline").await; Self::publish_ephemeral_outcome(ctx, completion); ctx.set_status(ProcessDriverStatus::Failed { code: "runtime-deadline", @@ -1653,7 +1653,7 @@ impl ProcessDriver { Ok(ReconcileOutcome::Satisfied) } Ok(ProviderLiveness::Exited) => { - let completion = self.ephemeral.finish(false, "process-exited"); + let completion = self.ephemeral.finish(false, "process-exited").await; Self::publish_ephemeral_outcome(ctx, completion); ctx.set_status(ProcessDriverStatus::Succeeded { code: "process-exited", @@ -1661,7 +1661,7 @@ impl ProcessDriver { self.ephemeral_retention(ctx, spec, completion).await } Ok(ProviderLiveness::Unknown) => { - let completion = self.ephemeral.finish(true, "identity-ambiguous"); + let completion = self.ephemeral.finish(true, "identity-ambiguous").await; Self::publish_ephemeral_outcome(ctx, completion); ctx.set_status(ProcessDriverStatus::Failed { code: "identity-ambiguous", @@ -1678,7 +1678,7 @@ impl ProcessDriver { // or a fail-closed refusal. match self.effects.adopt_ephemeral(identity, spec).await { Ok(ProviderAdoption::Adopted(_)) => { - self.ephemeral.mark_started(); + self.ephemeral.mark_started().await; ctx.set_status(ProcessDriverStatus::Ready { adopted: true }); let _ = ctx.requeue_after(PROCESS_RESYNC); Ok(ReconcileOutcome::Satisfied) @@ -1824,7 +1824,7 @@ impl ProcessDriver { .await { Ok(_) => { - ephemeral.mark_started(); + ephemeral.mark_started().await; EffectResult::Completed } Err(error) => { @@ -2407,6 +2407,7 @@ mod tests { deleted: parking_lot::Mutex>, } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl OwnershipManager { /// An owner-scoped manager with no owned rows: the retention delete /// path's double. @@ -2435,6 +2436,7 @@ mod tests { } #[async_trait::async_trait] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl ManagerEndpoint for OwnershipManager { async fn ensure_child( &self, @@ -2502,6 +2504,7 @@ mod tests { delivered_tx: Option>, } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl RecordingRequeue { fn new() -> (Self, mpsc::UnboundedReceiver) { let (tx, rx) = mpsc::unbounded_channel(); @@ -2522,6 +2525,7 @@ mod tests { } } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl RequeueScheduler for RecordingRequeue { fn schedule(&self, key: ResourceKey, after: Duration) -> RequeueId { let mut inner = self.inner.lock(); @@ -2646,17 +2650,17 @@ mod tests { } /// Test-only: backdate the one-shot runtime clock past its deadline. - fn backdate_runtime(&self, elapsed: Duration) { - self.typed.ephemeral.backdate_started(elapsed); + async fn backdate_runtime(&self, elapsed: Duration) { + self.typed.ephemeral.backdate_started(elapsed).await; } /// Test-only: backdate the one-shot retention clock. - fn backdate_completion(&self, elapsed: Duration) { - self.typed.ephemeral.backdate_completed(elapsed); + async fn backdate_completion(&self, elapsed: Duration) { + self.typed.ephemeral.backdate_completed(elapsed).await; } - fn ephemeral_completed(&self) -> bool { - self.typed.ephemeral.completed().is_some() + async fn ephemeral_completed(&self) -> bool { + self.typed.ephemeral.completed().await.is_some() } } @@ -3255,7 +3259,9 @@ mod tests { ); // TTL elapsed: the driver asks the manager to retire its own row. - driver.backdate_completion(Duration::from_secs(3600)); + driver + .backdate_completion(Duration::from_secs(3600)) + .await; assert_eq!( driver.reconcile(&mut f.ctx).await.expect("reconcile"), ReconcileOutcome::Satisfied @@ -3280,7 +3286,7 @@ mod tests { yield_until_effects_settled().await; f.effects.recv().await.expect("launch completion"); - driver.backdate_runtime(Duration::from_secs(300)); + driver.backdate_runtime(Duration::from_secs(300)).await; assert_eq!( driver.reconcile(&mut f.ctx).await.expect("reconcile"), ReconcileOutcome::Satisfied @@ -3339,7 +3345,7 @@ mod tests { yield_until_effects_settled().await; f.effects.recv().await.expect("launch completion"); - driver.backdate_runtime(Duration::from_secs(300)); + driver.backdate_runtime(Duration::from_secs(300)).await; assert_eq!( driver.reconcile(&mut f.ctx).await.expect("reconcile"), ReconcileOutcome::Satisfied @@ -3355,11 +3361,13 @@ mod tests { "no cleanup timer under incident hold" ); assert!( - driver.ephemeral_completed(), + driver.ephemeral_completed().await, "the terminal state is recorded" ); - driver.backdate_completion(Duration::from_secs(365 * 24 * 3600)); + driver + .backdate_completion(Duration::from_secs(365 * 24 * 3600)) + .await; assert_eq!( driver.reconcile(&mut f.ctx).await.expect("reconcile"), ReconcileOutcome::Satisfied diff --git a/packages/d2b-provider-process/src/effects_service.rs b/packages/d2b-provider-process/src/effects_service.rs index 48a67f6ed..a13c7bc11 100644 --- a/packages/d2b-provider-process/src/effects_service.rs +++ b/packages/d2b-provider-process/src/effects_service.rs @@ -608,6 +608,7 @@ mod tests { rows: Mutex>, } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl TestCommittedIdentities { fn publish(&self, provider: &str, uid: &str, generation: u64) { self.rows.lock().insert( @@ -620,6 +621,7 @@ mod tests { } } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl CommittedProviderIdentitySource for TestCommittedIdentities { fn committed_provider_identity( &self, diff --git a/packages/d2b-provider-process/src/test_support.rs b/packages/d2b-provider-process/src/test_support.rs index 8b855d056..25a615a3b 100644 --- a/packages/d2b-provider-process/src/test_support.rs +++ b/packages/d2b-provider-process/src/test_support.rs @@ -110,6 +110,7 @@ pub struct FakeFacets { socket_runtime_dir: std::path::PathBuf, } +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl FakeFacets { /// Build a double from the given scripted configuration. pub fn new(config: FakeFacetsConfig) -> Self { @@ -201,6 +202,7 @@ pub fn recorded_launch( } #[async_trait::async_trait] +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] impl ProcessProviderRuntime for FakeFacets { fn bundle(&self) -> &BundleResolver { &self.bundle diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index f3205f49b..74f89f102 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -548,142 +548,142 @@ }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2451, + "line": 2453, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2462, + "line": 2464, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 2463, + "line": 2465, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3253, + "line": 3257, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3263, + "line": 3269, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3368, + "line": 3376, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/driver.rs", - "line": 3730, + "line": 3738, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 227, + "line": 229, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 229, + "line": 231, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 231, + "line": 233, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 240, + "line": 242, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 246, + "line": 248, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 252, + "line": 254, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 260, + "line": 262, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 261, + "line": 263, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 273, + "line": 275, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 274, + "line": 276, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 286, + "line": 288, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 287, + "line": 289, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 302, + "line": 304, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 303, + "line": 305, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 317, + "line": 319, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 318, + "line": 320, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 333, + "line": 335, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 334, + "line": 336, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 347, + "line": 349, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 355, + "line": 357, "reason": "test-support recorder lock" }, { "file": "packages/d2b-provider-process/src/test_support.rs", - "line": 356, + "line": 358, "reason": "test-support recorder lock" }, { From 14d098fc3639b8f45d1cdc2286ff2209dc4aebed Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:06:51 -0700 Subject: [PATCH 689/726] refactor(d2b-provider-process-systemd): gate the test-only surface behind test-support The library target exported six modules with no production consumer - `controller`, `drain`, `metrics`, `audit`, `launch`, and `sandbox` - because every module was exported so the crate's own conformance tests (separate crates) could reach them. The census is finer-grained than the audit row: those tests exercise `controller`, `drain`, and `metrics`, while `audit`, `launch`, and `sandbox` have no consumer at all, and nothing else in the tree names any of the six. The surface production does compose (`lifecycle` through the root re-exports, `effects_service`, and `operations`) is unchanged. The six modules now compile behind a `test-support` feature, the Bazel `_test_support` library carries that feature so the conformance tests keep running there, and the `boundaries` and `controller` tests declare `required-features`, so their cargo lane is `cargo test -p d2b-provider-process-systemd --features test-support`. The crate doc and the README record which surface is wired and which stays unexported until the daemon reconcile composition lands on it. --- .../d2b-provider-process-systemd/BUILD.bazel | 3 ++- .../d2b-provider-process-systemd/Cargo.toml | 15 +++++++++++++ .../d2b-provider-process-systemd/README.md | 15 +++++++++++++ .../d2b-provider-process-systemd/src/lib.rs | 22 +++++++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/packages/d2b-provider-process-systemd/BUILD.bazel b/packages/d2b-provider-process-systemd/BUILD.bazel index a4b0f44e2..009378f58 100644 --- a/packages/d2b-provider-process-systemd/BUILD.bazel +++ b/packages/d2b-provider-process-systemd/BUILD.bazel @@ -43,6 +43,7 @@ d2b_rust_library( name = "d2b_provider_process_systemd_test_support", srcs = glob(["src/**/*.rs"], allow_empty = True), compile_data = ["Cargo.toml"], + crate_features = ["test-support"], crate_name = "d2b_provider_process_systemd", deps = [ # Mirrors the library target's dependency list: the test-support @@ -98,7 +99,7 @@ d2b_rust_test( compile_data = ["Cargo.toml"], deps = [ "//packages/d2b-contracts-resource:d2b_contracts_resource", - ":d2b_provider_process_systemd", + ":d2b_provider_process_systemd_test_support", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) diff --git a/packages/d2b-provider-process-systemd/Cargo.toml b/packages/d2b-provider-process-systemd/Cargo.toml index 589fa0e81..41bc98d77 100644 --- a/packages/d2b-provider-process-systemd/Cargo.toml +++ b/packages/d2b-provider-process-systemd/Cargo.toml @@ -33,3 +33,18 @@ zbus = "5.16" [dev-dependencies] d2b-process-conformance = { path = "../d2b-process-conformance", version = "0.0.0-bootstrap", features = ["test-support"] } tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync", "test-util", "time"] } + +[features] +test-support = [] + +# The modules `boundaries` and `controller` consume compile only under the +# `test-support` feature, so these tests need it. +[[test]] +name = "boundaries" +path = "tests/boundaries.rs" +required-features = ["test-support"] + +[[test]] +name = "controller" +path = "tests/controller.rs" +required-features = ["test-support"] diff --git a/packages/d2b-provider-process-systemd/README.md b/packages/d2b-provider-process-systemd/README.md index ed144d061..e778f1ec8 100644 --- a/packages/d2b-provider-process-systemd/README.md +++ b/packages/d2b-provider-process-systemd/README.md @@ -30,6 +30,14 @@ One controller, shipped as a library type: `SystemdProcessProvider` and its `ProcessLaunchEffectPort`. Lifecycle, drain, audit, and metric helpers remain typed and path-free. +The library target exports what production composes today: the controller, +the `lifecycle` root re-exports, `effects_service`, and `operations`. The +controller family, drain, metrics, audit, launch, and sandbox helpers have no +production consumer - the conformance tests exercise the controller family, +drain, and metrics, and the daemon reconcile composition has not landed on +any of the six - so they compile behind the `test-support` feature and are +absent from the plain library build. + ## Placement and dependencies Runs under a Host or a Guest whose service manager is systemd. It depends on @@ -74,3 +82,10 @@ closed enumerations only. ```bash bazel test //packages/d2b-provider-process-systemd:all ``` + +The conformance tests that consume the test-only modules run under the +`test-support` feature: + +```bash +cargo test -p d2b-provider-process-systemd --features test-support +``` diff --git a/packages/d2b-provider-process-systemd/src/lib.rs b/packages/d2b-provider-process-systemd/src/lib.rs index e582a8435..6ad5db4e9 100644 --- a/packages/d2b-provider-process-systemd/src/lib.rs +++ b/packages/d2b-provider-process-systemd/src/lib.rs @@ -16,17 +16,39 @@ //! validates the ticket and calls the injected //! [`ProcessLaunchEffectPort`], which the fixed core process effect adapter //! implements. +//! +//! The library target exports the surface production composes today: the +//! Provider controller, the `lifecycle` root re-exports, [`effects_service`], +//! and [`operations`]. The controller family (`controller`), `drain`, +//! `metrics`, `audit`, `launch`, and `sandbox` have no production consumer: +//! this crate's conformance tests exercise the first three, and the daemon +//! reconcile composition has not landed on any of the six, so they compile +//! behind the `test-support` feature instead of being exported by the +//! library. #![deny(missing_docs)] +// The gated surface above has no production consumer: this crate's tests and +// the conformance suites reach it, and consumers opt in through the +// `test-support` feature. Gating on `any(test, feature = "test-support")` +// makes it available automatically to this crate's unit tests; the +// integration tests that consume it declare `required-features`, so run those +// with `--features test-support` (or let the Bazel `*_test_support` target +// compile them). +#[cfg(any(test, feature = "test-support"))] pub mod audit; +#[cfg(any(test, feature = "test-support"))] pub mod controller; +#[cfg(any(test, feature = "test-support"))] pub mod drain; pub mod effects_service; +#[cfg(any(test, feature = "test-support"))] pub mod launch; mod lifecycle; +#[cfg(any(test, feature = "test-support"))] pub mod metrics; pub mod operations; +#[cfg(any(test, feature = "test-support"))] pub mod sandbox; pub use lifecycle::{ From 21a7af4241c246e0a959cf25269275b6d44ad17b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:06:51 -0700 Subject: [PATCH 690/726] refactor(d2b-provider-notification-desktop): type the runner cutover state `NotificationRunnerContract` carried `watched_configuration_is_dependency` and `component_session_only`, two booleans its single constructor always set true. They are one typed `NotificationCutoverState` now, and both accessors read that state, so every existing caller - including the daemon composition assertions - compiles and behaves unchanged. --- ...stemd-surface-and-notification-contract.md | 19 ++++++++++++++++ .../src/controller.rs | 22 ++++++++++++++----- .../src/lib.rs | 2 +- 3 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 changelog.d/w7-18-process-systemd-surface-and-notification-contract.md diff --git a/changelog.d/w7-18-process-systemd-surface-and-notification-contract.md b/changelog.d/w7-18-process-systemd-surface-and-notification-contract.md new file mode 100644 index 000000000..c8514aab5 --- /dev/null +++ b/changelog.d/w7-18-process-systemd-surface-and-notification-contract.md @@ -0,0 +1,19 @@ +### Added + +- `NotificationCutoverState`, the typed cutover state of the + notification-desktop `NotificationRunnerContract`. + +### Changed + +- `d2b-provider-process-systemd` exports only the surface production + composes today: the Provider controller, the `lifecycle` root + re-exports, `effects_service`, and `operations`. The controller + family, `drain`, `metrics`, `audit`, `launch`, and `sandbox` modules + have no production consumer - the conformance tests exercise the first + three - so they compile behind the crate's `test-support` feature and + are gone from the plain library build. The tests consuming them + declare `required-features` and run with `--features test-support`. +- The notification-desktop `NotificationRunnerContract` replaces its two + always-true cutover flags with one `NotificationCutoverState`. + `component_session_only` and `watched_configuration_is_dependency` + remain as reads of that state, so every existing caller is unchanged. diff --git a/packages/d2b-provider-notification-desktop/src/controller.rs b/packages/d2b-provider-notification-desktop/src/controller.rs index a0a61d7e8..1325d8fd9 100644 --- a/packages/d2b-provider-notification-desktop/src/controller.rs +++ b/packages/d2b-provider-notification-desktop/src/controller.rs @@ -17,13 +17,24 @@ use crate::Category; /// The bounded repair interval for the notification ComponentSession runtime. pub const NOTIFICATION_REPAIR_INTERVAL_SECS: u64 = 300; +/// The cutover state of the notification ComponentSession runtime. +/// +/// The two booleans the contract used to carry were both pinned true by its +/// single constructor, so they were one state spelled twice. The state is +/// typed instead: `ServiceOnly` means configuration is dependency-only and +/// notification state stays on typed ComponentSession streams. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum NotificationCutoverState { + /// Only the service package is the notification runtime. + ServiceOnly, +} + /// The cutover contract for the notification service-only runtime. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct NotificationRunnerContract { service_package: &'static str, repair_interval_secs: u64, - watched_configuration_is_dependency: bool, - component_session_only: bool, + cutover: NotificationCutoverState, } impl NotificationRunnerContract { @@ -39,12 +50,12 @@ impl NotificationRunnerContract { /// Whether configuration is dependency-only. pub const fn watched_configuration_is_dependency(self) -> bool { - self.watched_configuration_is_dependency + matches!(self.cutover, NotificationCutoverState::ServiceOnly) } /// Whether notification state remains on typed ComponentSession streams. pub const fn component_session_only(self) -> bool { - self.component_session_only + matches!(self.cutover, NotificationCutoverState::ServiceOnly) } } @@ -53,8 +64,7 @@ pub const fn notification_runner_contract() -> NotificationRunnerContract { NotificationRunnerContract { service_package: crate::SERVICE_PACKAGE, repair_interval_secs: NOTIFICATION_REPAIR_INTERVAL_SECS, - watched_configuration_is_dependency: true, - component_session_only: true, + cutover: NotificationCutoverState::ServiceOnly, } } diff --git a/packages/d2b-provider-notification-desktop/src/lib.rs b/packages/d2b-provider-notification-desktop/src/lib.rs index b119269be..c0d7a2117 100644 --- a/packages/d2b-provider-notification-desktop/src/lib.rs +++ b/packages/d2b-provider-notification-desktop/src/lib.rs @@ -33,7 +33,7 @@ pub use admission::{AdmissionError, AdmissionPurpose, SessionEvidence, Transport pub use audit::{NotificationAuditKind, NotificationAuditRecord}; pub use controller::{ DisplayDependencyEvidence, DisplayDependencyState, GuestSourceConfig, NotificationController, - NotificationProviderConfig, NotificationRunnerContract, ProcessPlan, + NotificationCutoverState, NotificationProviderConfig, NotificationRunnerContract, ProcessPlan, SourceProcessEffectPort, SourceProcessEffectReceipt, SourceReconcileResult, notification_runner_contract, }; From e14ea9c02f37339f4401a35d063d5685f28eb20e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:08:35 -0700 Subject: [PATCH 691/726] fix(d2b-contracts-resource): keep the activation generation vocabulary family-neutral The activation-runner `targetGeneration` field took a new `NixosGenerationOrdinal` newtype declared beside the shared identity primitives, which put provider-family vocabulary into `d2b-contracts` and `d2b-contracts-resource`; the layout ratchet reports that as `shared-crate-family-identifier` for token `nixos` and never accepts a new row. Type the field and its constructor argument with the existing `ConfigurationGeneration` identity instead, delete the newtype and its `IdentityClass` variant, and regenerate the committed EphemeralProcess zone schema. The field keeps its nonzero invariant, its serde-transparent `u64` wire bytes, and its definition-reference rendering in that schema. --- changelog.d/w7-02-activation-generation-types.md | 11 ++++++----- .../w7-27-configuration-generation-vocabulary.md | 9 +++++++++ .../v3/core.d2bus.org_EphemeralProcess.schema.json | 10 +++++----- .../d2b-contracts-resource/src/v3/activation_nixos.rs | 6 +++--- packages/d2b-contracts-resource/src/v3/identity.rs | 2 -- packages/d2b-contracts-resource/src/v3/mod.rs | 6 +++--- packages/d2b-contracts/src/identity.rs | 1 - .../d2b-provider-activation-nixos/src/controller.rs | 8 ++++---- 8 files changed, 30 insertions(+), 23 deletions(-) create mode 100644 changelog.d/w7-27-configuration-generation-vocabulary.md diff --git a/changelog.d/w7-02-activation-generation-types.md b/changelog.d/w7-02-activation-generation-types.md index 305e7a973..56b0adb75 100644 --- a/changelog.d/w7-02-activation-generation-types.md +++ b/changelog.d/w7-02-activation-generation-types.md @@ -1,11 +1,12 @@ ### Changed - The activation-runner `targetGeneration` contract field is typed as - the nonzero `NixosGenerationOrdinal` identity instead of a bare `u64`, - so a zero ordinal is refused when the input decodes rather than by a - manual check in the constructor. The wire bytes are unchanged, and the - committed EphemeralProcess schema now carries the ordinal as a - definition reference instead of an inline minimum-1 integer. + the nonzero `ConfigurationGeneration` identity instead of a bare + `u64`, so a zero ordinal is refused when the input decodes rather + than by a manual check in the constructor. The wire bytes are + unchanged, and the committed EphemeralProcess schema now carries the + ordinal as a definition reference instead of an inline minimum-1 + integer. - The activation-nixos status `observedGeneration` field is typed as `ObservedGeneration` (zero meaning none) instead of a bare `u64`. The transparent newtype renders the same integer schema, and the two diff --git a/changelog.d/w7-27-configuration-generation-vocabulary.md b/changelog.d/w7-27-configuration-generation-vocabulary.md new file mode 100644 index 000000000..d65bd83db --- /dev/null +++ b/changelog.d/w7-27-configuration-generation-vocabulary.md @@ -0,0 +1,9 @@ +### Fixed + +- The shared contract crates carry family-neutral vocabulary again: the + activation-runner `targetGeneration` field and its constructor take + the existing `ConfigurationGeneration` identity instead of a new + activation-nixos-specific ordinal type declared beside it. The field + keeps its nonzero invariant, its serde-transparent u64 wire bytes, + and the same definition-reference rendering in the committed + EphemeralProcess schema. diff --git a/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json b/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json index 81da887dd..d4d74f5e4 100644 --- a/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json +++ b/docs/reference/schemas/v3/core.d2bus.org_EphemeralProcess.schema.json @@ -59,7 +59,7 @@ "targetGeneration": { "allOf": [ { - "$ref": "#/definitions/NixosGenerationOrdinal" + "$ref": "#/definitions/ConfigurationGeneration" } ], "description": "Target generation ordinal bound to the owning `NixosGeneration`." @@ -176,6 +176,10 @@ ], "type": "string" }, + "ConfigurationGeneration": { + "minimum": 1.0, + "type": "integer" + }, "CountBudget": { "additionalProperties": false, "description": "One optional integer ceiling.", @@ -405,10 +409,6 @@ ], "type": "object" }, - "NixosGenerationOrdinal": { - "minimum": 1.0, - "type": "integer" - }, "PortProtocol": { "description": "Transport protocol of one declared port.", "enum": [ diff --git a/packages/d2b-contracts-resource/src/v3/activation_nixos.rs b/packages/d2b-contracts-resource/src/v3/activation_nixos.rs index 8e9f69896..bd0ba8457 100644 --- a/packages/d2b-contracts-resource/src/v3/activation_nixos.rs +++ b/packages/d2b-contracts-resource/src/v3/activation_nixos.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use super::{ - ArtifactId, NixosGenerationOrdinal, ObservedGeneration, ResourceRef, ResourceTypeName, + ArtifactId, ConfigurationGeneration, ObservedGeneration, ResourceRef, ResourceTypeName, execution_policy::require_execution_ref, }; use d2b_contracts::wire_deserialize; @@ -43,7 +43,7 @@ pub struct ActivationRunnerInput { /// Private-catalog artifact identifier. pub system_artifact_id: ArtifactId, /// Target generation ordinal bound to the owning `NixosGeneration`. - pub target_generation: NixosGenerationOrdinal, + pub target_generation: ConfigurationGeneration, /// Closed activation mode. pub activation_mode: ActivationMode, } @@ -52,7 +52,7 @@ impl ActivationRunnerInput { /// Construct one runner input. pub fn new( system_artifact_id: ArtifactId, - target_generation: NixosGenerationOrdinal, + target_generation: ConfigurationGeneration, activation_mode: ActivationMode, ) -> Self { Self { diff --git a/packages/d2b-contracts-resource/src/v3/identity.rs b/packages/d2b-contracts-resource/src/v3/identity.rs index 1b09ecd16..13708fe90 100644 --- a/packages/d2b-contracts-resource/src/v3/identity.rs +++ b/packages/d2b-contracts-resource/src/v3/identity.rs @@ -500,8 +500,6 @@ impl ConfigurationGeneration { } } -nonzero_generation!(NixosGenerationOrdinal, IdentityClass::NixosGenerationOrdinal); - /// The latest generation a controller has observed, with zero meaning none. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, diff --git a/packages/d2b-contracts-resource/src/v3/mod.rs b/packages/d2b-contracts-resource/src/v3/mod.rs index 53a72cef6..36eec833d 100644 --- a/packages/d2b-contracts-resource/src/v3/mod.rs +++ b/packages/d2b-contracts-resource/src/v3/mod.rs @@ -34,9 +34,9 @@ pub use execution_policy::*; pub use host::*; pub use identity::{ ConfigurationGeneration, ControllerGeneration, IdentityClass, IdentityError, - NixosGenerationOrdinal, ObservedGeneration, ResourceBundleGenerationId, ResourceGeneration, - ResourceName, ResourceTypeName, ResourceUid, SchemaFingerprint, Timestamp, - V3_CONVERTED_RESOURCE_TYPES, ZoneId, ZoneResourceIdentity, ZoneRevision, + ObservedGeneration, ResourceBundleGenerationId, ResourceGeneration, ResourceName, + ResourceTypeName, ResourceUid, SchemaFingerprint, Timestamp, V3_CONVERTED_RESOURCE_TYPES, + ZoneId, ZoneResourceIdentity, ZoneRevision, }; pub mod ifname { pub use d2b_contracts::v3::ifname::*; diff --git a/packages/d2b-contracts/src/identity.rs b/packages/d2b-contracts/src/identity.rs index 68ebe2e50..94375c6f8 100644 --- a/packages/d2b-contracts/src/identity.rs +++ b/packages/d2b-contracts/src/identity.rs @@ -248,7 +248,6 @@ pub enum IdentityClass { ReconnectGeneration, ControllerGeneration, ConfigurationGeneration, - NixosGenerationOrdinal, } /// Reason a canonical identity could not be constructed. diff --git a/packages/d2b-provider-activation-nixos/src/controller.rs b/packages/d2b-provider-activation-nixos/src/controller.rs index 161f2dad0..db3a8bf2d 100644 --- a/packages/d2b-provider-activation-nixos/src/controller.rs +++ b/packages/d2b-provider-activation-nixos/src/controller.rs @@ -1,9 +1,9 @@ //! Pure activation-nixos reconciliation policy. use d2b_contracts_resource::v3::{ - ActivationMode, ActivationOutcomeCode, ActivationRunnerInput, ArtifactId, EnvironmentClass, - ExecutionDomain, IdentityError, NixosGenerationOrdinal, NixosGenerationSpec, ResourceName, - ResourcePhase, ResourceRef, + ActivationMode, ActivationOutcomeCode, ActivationRunnerInput, ArtifactId, + ConfigurationGeneration, EnvironmentClass, ExecutionDomain, IdentityError, NixosGenerationSpec, + ResourceName, ResourcePhase, ResourceRef, process::{EphemeralProcessSpec, ExecutionSpec, NamespaceClass, ProcessClass, SandboxSpec}, }; use ring::signature; @@ -387,7 +387,7 @@ pub fn activation_runner_spec(request: &RunnerRequest) -> EphemeralProcessSpec { .expect("static activation runner process"); spec.with_activation_input(ActivationRunnerInput::new( request.system_artifact_id.clone(), - NixosGenerationOrdinal::new(request.target_generation) + ConfigurationGeneration::new(request.target_generation) .expect("activation runner generation is nonzero"), request.activation_mode, )) From dbb04d6c4dec98f5384e84ec013c6d9fdd465b00 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:10:09 -0700 Subject: [PATCH 692/726] refactor(providers): await the volume, device, and network-local recorder locks The Volume, Device, and network-local test-support recorders and the Volume driver's own test harness held their logs, rows, and counters in parking_lot locks and took them from async methods: the guard cannot be held across an await and the acquisition parks a worker, and plan KD3 revokes the parking_lot carve-out outright. The recorders whose every reader and writer is async move to the awaited async lock. The Volume recording manager's ordered log and row store become tokio::sync::Mutex and its order() snapshot awaits them; the network-local recording double awaits its call log and both per-verb counters, and its call_order() snapshot awaits too; the Device double awaits both component recorders and the crate declares tokio with the sync feature. The network-local test requeue recorder counts ids with an atomic instead of a lock. The recorders that a synchronous accessor reads keep a blocking lock but move to std::sync::Mutex behind one acquisition site with the recorded per-site exception: the Volume runtime double's call log, read by the synchronous has_layout probe and by call_order(), and the network-local broker and reconcile fixtures, whose port and harness methods are synchronous. d2b-provider-volume and d2b-provider-network-local drop the parking_lot dependency; the Device driver's GPU authority-lease cache keeps the type the sibling GPU crate's declared construction contract locks on its own synchronous path. The async-gate hatch inventory is regenerated for the removed marker sites and the policy inputs for the dependency change. --- Cargo.lock | 2 - .../w7-25-volume-device-network-locks.md | 26 +++++ packages/d2b-provider-device/Cargo.toml | 1 + .../d2b-provider-device/src/test_support.rs | 12 +- .../tests/device_family.rs | 3 +- .../d2b-provider-network-local/Cargo.toml | 1 - .../d2b-provider-network-local/src/broker.rs | 19 ++- .../d2b-provider-network-local/src/driver.rs | 19 +-- .../src/test_support.rs | 38 +++--- .../tests/network_family.rs | 18 +-- .../tests/reconcile.rs | 56 ++++++--- packages/d2b-provider-volume/Cargo.toml | 1 - packages/d2b-provider-volume/src/driver.rs | 50 ++++---- .../d2b-provider-volume/src/test_support.rs | 33 ++++-- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 2 - .../main-product/policy/closure.json | 20 ++-- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 2 - .../main-product/production/closure.json | 20 ++-- .../main-product/production/metadata.json | 2 +- .../broker-default-tests/policy/closure.json | 2 +- .../broker-default-tests/policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../policy/closure.json | 2 +- .../policy/metadata.json | 2 +- .../production/closure.json | 2 +- .../production/metadata.json | 2 +- .../broker-production/policy/closure.json | 2 +- .../broker-production/policy/metadata.json | 2 +- .../broker-production/production/closure.json | 2 +- .../production/metadata.json | 2 +- .../main-product/policy/Cargo.lock | 2 - .../main-product/policy/closure.json | 20 ++-- .../main-product/policy/metadata.json | 2 +- .../main-product/production/Cargo.lock | 2 - .../main-product/production/closure.json | 20 ++-- .../main-product/production/metadata.json | 2 +- packages/xtask/data/async-gate-inventory.json | 110 ------------------ 59 files changed, 254 insertions(+), 295 deletions(-) create mode 100644 changelog.d/w7-25-volume-device-network-locks.md diff --git a/Cargo.lock b/Cargo.lock index 2a83b1b42..59d0e9806 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1497,7 +1497,6 @@ dependencies = [ "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "rustix 0.38.44", "serde", "serde_json", @@ -1892,7 +1891,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", ] diff --git a/changelog.d/w7-25-volume-device-network-locks.md b/changelog.d/w7-25-volume-device-network-locks.md new file mode 100644 index 000000000..d1af43e7f --- /dev/null +++ b/changelog.d/w7-25-volume-device-network-locks.md @@ -0,0 +1,26 @@ +### Changed + +- The Volume driver's test recording manager holds its ordered log and + its row store in awaited `tokio::sync::Mutex` locks: every endpoint + and the tests' own `order()` snapshot await the lock instead of + taking a `parking_lot` lock inside an async method. + +### Fixed + +- The Volume, Device, and network-local families carry no unsuppressed + blocking-lock site. `d2b-provider-volume` and + `d2b-provider-network-local` drop `parking_lot` outright: the + network-local recorder doubles await their call log and both per-verb + counters, the Device recorder doubles await theirs (the crate now + declares `tokio` with the `sync` feature), and the network-local test + requeue recorder counts ids with an atomic instead of a lock. +- The recorders a synchronous accessor reads keep a blocking lock but + move to `std::sync::Mutex` behind a recorded per-site exception: the + Volume runtime double's call log, read by the synchronous + `has_layout` probe and by `call_order()`, and the network-local + broker and reconcile fixtures, whose port and harness methods are + synchronous. The Device driver's GPU authority-lease cache keeps the + type the GPU port's declared construction contract locks on its own + synchronous path. The async-gate hatch inventory is regenerated for + the removed marker sites and the policy inputs for the dependency + change. diff --git a/packages/d2b-provider-device/Cargo.toml b/packages/d2b-provider-device/Cargo.toml index ba9168121..acebb39fc 100644 --- a/packages/d2b-provider-device/Cargo.toml +++ b/packages/d2b-provider-device/Cargo.toml @@ -29,6 +29,7 @@ d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-boot d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } parking_lot = "0.12" serde_json.workspace = true +tokio = { workspace = true, features = ["sync"] } [[test]] name = "device_family" diff --git a/packages/d2b-provider-device/src/test_support.rs b/packages/d2b-provider-device/src/test_support.rs index 12d0540d4..39376316f 100644 --- a/packages/d2b-provider-device/src/test_support.rs +++ b/packages/d2b-provider-device/src/test_support.rs @@ -18,12 +18,16 @@ use crate::facets::{DeviceEffectFacets, DeviceRuntime}; /// Recording [`DeviceRuntime`] double: answers Pending/Complete for every /// effect call and records the driven components, so `d2bd`'s plane tests /// can build a facet set without a daemon. +/// +/// Both recorders are async locks (`tokio::sync::Mutex`, awaited): every +/// reader and writer here is an async effect method or an async test, so no +/// synchronous accessor forces a blocking lock. #[derive(Default)] pub struct RecordingRuntime { /// Components reconciled, in call order. - pub reconciled: parking_lot::Mutex>, + pub reconciled: tokio::sync::Mutex>, /// Components finalized, in call order. - pub finalized: parking_lot::Mutex>, + pub finalized: tokio::sync::Mutex>, } #[async_trait] @@ -34,7 +38,7 @@ impl DeviceRuntime for RecordingRuntime { _request: &SharedProviderEffectRequest<'_>, _state: &DeviceResourceState, ) -> Result { - self.reconciled.lock().push(component); // async-gate-allow: test-support recorder lock + self.reconciled.lock().await.push(component); Ok(SharedProviderEffectOutcome::phase( SharedProviderEffectPhase::Pending, )) @@ -46,7 +50,7 @@ impl DeviceRuntime for RecordingRuntime { _request: &SharedProviderEffectRequest<'_>, _state: &DeviceResourceState, ) -> Result { - self.finalized.lock().push(component); // async-gate-allow: test-support recorder lock + self.finalized.lock().await.push(component); Ok(SharedProviderFinalize::Complete) } } diff --git a/packages/d2b-provider-device/tests/device_family.rs b/packages/d2b-provider-device/tests/device_family.rs index a31c4ca18..5917a892a 100644 --- a/packages/d2b-provider-device/tests/device_family.rs +++ b/packages/d2b-provider-device/tests/device_family.rs @@ -154,7 +154,6 @@ fn descriptor_declares_the_device_type_over_four_providers() { /// A row is driven by the component its Provider reference selects, and a /// Provider outside the four is terminal. -#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn a_row_runs_the_effect_of_the_provider_its_spec_names() { let runtime = Arc::new(RecordingRuntime::default()); @@ -164,7 +163,7 @@ async fn a_row_runs_the_effect_of_the_provider_its_spec_names() { driver.validate(&mut ctx).await.expect("tpm row validates"); driver.reconcile(&mut ctx).await.expect("tpm row reconciles"); assert_eq!( - *runtime.reconciled.lock(), // async-gate-allow: test-support recorder lock + *runtime.reconciled.lock().await, vec![DeviceComponent::Tpm], "the tpm Provider reference selects the tpm component" ); diff --git a/packages/d2b-provider-network-local/Cargo.toml b/packages/d2b-provider-network-local/Cargo.toml index cd3c99b88..8adc7fed3 100644 --- a/packages/d2b-provider-network-local/Cargo.toml +++ b/packages/d2b-provider-network-local/Cargo.toml @@ -32,7 +32,6 @@ serde.workspace = true tracing = "0.1" serde_json.workspace = true tokio = { workspace = true, features = ["macros", "process", "rt-multi-thread", "sync", "time"] } -parking_lot = "0.12" [dev-dependencies] rustix = { workspace = true, features = ["std", "net", "pipe"] } diff --git a/packages/d2b-provider-network-local/src/broker.rs b/packages/d2b-provider-network-local/src/broker.rs index 99bdf0ef4..7d7bb456e 100644 --- a/packages/d2b-provider-network-local/src/broker.rs +++ b/packages/d2b-provider-network-local/src/broker.rs @@ -1622,17 +1622,30 @@ mod tests { #[derive(Clone, Default)] struct RecordingBroker { - events: Arc>>, + events: Arc>>, } impl RecordingBroker { + /// Take the recorder lock, failing loudly on poisoning. + /// + /// This fake's recording happens from the synchronous + /// [`NetworkBroker`] trait methods, so the log cannot be an awaited + /// async lock; this is its one acquisition site and it carries the + /// recorded exception. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn recorder(&self) -> std::sync::MutexGuard<'_, Vec<&'static str>> { + self.events + .lock() + .expect("a test-support recorder lock is never poisoned") + } + fn record(&self, event: &'static str) { - self.events.lock().push(event); + self.recorder().push(event); } fn events(&self) -> Vec<&'static str> { - self.events.lock().clone() + self.recorder().clone() } } diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index 6b050b497..a190e1e10 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -504,15 +504,16 @@ mod tests { #[derive(Default)] struct RecordingRequeue { - scheduled: parking_lot::Mutex>, + next_id: std::sync::atomic::AtomicU64, } impl RequeueScheduler for RecordingRequeue { fn schedule(&self, _key: ResourceKey, _after: Duration) -> RequeueId { - let mut scheduled = self.scheduled.lock(); - let id = RequeueId(scheduled.len() as u64 + 1); - scheduled.push(id); - id + let id = self + .next_id + .fetch_add(1, std::sync::atomic::Ordering::SeqCst) + + 1; + RequeueId(id) } fn cancel(&self, _id: RequeueId) {} @@ -643,7 +644,7 @@ impl RequeueScheduler for RecordingRequeue { ] { assert!(entries.contains(&expected), "{entries:?}"); } - assert_eq!(*effects.reconciled.lock(), 1); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + assert_eq!(*effects.reconciled.lock().await, 1); } /// The family decoder yields the shared envelope the driver's verbs read. @@ -742,9 +743,9 @@ impl RequeueScheduler for RecordingRequeue { driver.validate(&mut ctx).await.expect("network row validates"); driver.reconcile(&mut ctx).await.expect("network row reconciles"); driver.delete(&mut ctx).await.expect("network row finalizes"); - assert_eq!(effects.call_order(), vec!["reconcile", "finalize"]); - assert_eq!(*effects.reconciled.lock(), 1); // async-gate-allow: synchronous lock acquisition, no await while the guard is held - assert_eq!(*effects.finalized.lock(), 1); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + assert_eq!(effects.call_order().await, vec!["reconcile", "finalize"]); + assert_eq!(*effects.reconciled.lock().await, 1); + assert_eq!(*effects.finalized.lock().await, 1); } } diff --git a/packages/d2b-provider-network-local/src/test_support.rs b/packages/d2b-provider-network-local/src/test_support.rs index 69cf0f510..01406a3db 100644 --- a/packages/d2b-provider-network-local/src/test_support.rs +++ b/packages/d2b-provider-network-local/src/test_support.rs @@ -24,26 +24,34 @@ const INSTALLED_GENERATION: &str = /// Recording [`NetworkRuntime`] double. /// -/// Every effect call is appended to an ordered [`Self::call_order`] log while -/// the per-verb counters (`reconciled`, `finalized`) keep counting, so the -/// plane can assert both event ordering and invocation counts. The double -/// answers the trusted-bundle report from a fixture bundle (the same -/// artifact shapes the daemon's own tests load); the broker facets are -/// unreachable because the driver tests never invoke a kernel. +/// Every effect call is appended to an ordered call log while the per-verb +/// counters (`reconciled`, `finalized`) keep counting, so the plane can +/// assert both event ordering and invocation counts. The log and both +/// counters are async locks (`tokio::sync::Mutex`, awaited): the effect +/// methods write them and the crate's async tests read them, so no +/// synchronous accessor forces a blocking lock. The double answers the +/// trusted-bundle report from a fixture bundle (the same artifact shapes the +/// daemon's own tests load); the broker facets are unreachable because the +/// driver tests never invoke a kernel. #[derive(Default)] pub struct RecordingRuntime { /// Ordered log of every effect call, oldest first. - calls: parking_lot::Mutex>, + calls: tokio::sync::Mutex>, /// Number of [`NetworkRuntime::reconcile_network`] invocations. - pub reconciled: parking_lot::Mutex, + pub reconciled: tokio::sync::Mutex, /// Number of [`NetworkRuntime::finalize_network`] invocations. - pub finalized: parking_lot::Mutex, + pub finalized: tokio::sync::Mutex, } impl RecordingRuntime { /// The ordered effect calls, oldest first. - pub fn call_order(&self) -> Vec<&'static str> { - self.calls.lock().clone() + pub async fn call_order(&self) -> Vec<&'static str> { + self.calls.lock().await.clone() + } + + /// Append one effect call to the ordered log. + async fn record(&self, call: &'static str) { + self.calls.lock().await.push(call); } } @@ -65,8 +73,8 @@ impl NetworkRuntime for RecordingRuntime { &self, _request: &SharedProviderEffectRequest<'_>, ) -> Result { - self.calls.lock().push("reconcile"); // async-gate-allow: test-support recorder lock - *self.reconciled.lock() += 1; // async-gate-allow: test-support recorder lock + self.record("reconcile").await; + *self.reconciled.lock().await += 1; Ok(SharedProviderEffectOutcome::phase( SharedProviderEffectPhase::Ready, )) @@ -76,8 +84,8 @@ impl NetworkRuntime for RecordingRuntime { &self, _request: &SharedProviderEffectRequest<'_>, ) -> Result { - self.calls.lock().push("finalize"); // async-gate-allow: test-support recorder lock - *self.finalized.lock() += 1; // async-gate-allow: test-support recorder lock + self.record("finalize").await; + *self.finalized.lock().await += 1; Ok(SharedProviderFinalize::Complete) } } diff --git a/packages/d2b-provider-network-local/tests/network_family.rs b/packages/d2b-provider-network-local/tests/network_family.rs index 17d40bd2c..21b4115a3 100644 --- a/packages/d2b-provider-network-local/tests/network_family.rs +++ b/packages/d2b-provider-network-local/tests/network_family.rs @@ -14,8 +14,7 @@ use std::collections::BTreeMap; use std::io::IoSlice; use std::os::fd::AsFd; use std::path::PathBuf; -use parking_lot::Mutex; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::thread::JoinHandle; use std::time::Duration; @@ -146,13 +145,15 @@ let handle = std::thread::spawn(move || { } } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn answer(&self, response: BrokerResponse) { - *self.reply.lock() = Some(response); + *self.reply.lock().expect("a fake-socket lock is never poisoned") = Some(response); } + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn answer_with_fds(&self, response: BrokerResponse, fds: Vec) { - *self.reply.lock() = Some(response); - *self.reply_fds.lock() = fds; + *self.reply.lock().expect("a fake-socket lock is never poisoned") = Some(response); + *self.reply_fds.lock().expect("a fake-socket lock is never poisoned") = fds; } // Joining the fake kernel server's thread is the sync test harness's own @@ -167,6 +168,7 @@ let handle = std::thread::spawn(move || { .expect("kernel server completes"); self.captured .lock() + .expect("a fake-socket lock is never poisoned") .clone() .expect("the kernel server captured one frame") } @@ -193,15 +195,15 @@ fn serve_kernel_call( let envelope: BrokerRequestEnvelope = d2b_contracts::decode_frame("BrokerRequestEnvelope", &buf[..read]) .expect("decode kernel frame"); - *captured.lock() = Some(envelope); + *captured.lock().expect("a fake-socket lock is never poisoned") = Some(envelope); let response = loop { - if let Some(response) = reply.lock().take() { + if let Some(response) = reply.lock().expect("a fake-socket lock is never poisoned").take() { break response; } std::thread::sleep(Duration::from_millis(5)); }; let frame = d2b_contracts::encode_frame(&response).expect("encode kernel reply"); - let fds = std::mem::take(&mut *reply_fds.lock()); + let fds = std::mem::take(&mut *reply_fds.lock().expect("a fake-socket lock is never poisoned")); if fds.is_empty() { connection.write_all(&frame).expect("write kernel reply"); } else { diff --git a/packages/d2b-provider-network-local/tests/reconcile.rs b/packages/d2b-provider-network-local/tests/reconcile.rs index 58f3d663c..26854e455 100644 --- a/packages/d2b-provider-network-local/tests/reconcile.rs +++ b/packages/d2b-provider-network-local/tests/reconcile.rs @@ -1,7 +1,6 @@ -use parking_lot::Mutex; use std::{ future::Future, - sync::Arc, + sync::{Arc, Mutex, MutexGuard}, task::{Context, Poll, Waker}, }; @@ -38,9 +37,23 @@ struct FakePortState { } impl FakePorts { + /// Take one recorder lock, failing loudly on poisoning. + /// + /// The recorded fields are `std::sync::Mutex`: the port methods are + /// driven by this file's own `block_on` harness (plain `#[test]` + /// functions, with no runtime) and the test bodies read the records + /// synchronously, so they cannot be awaited async locks. This is the + /// single acquisition site and it carries the recorded exception. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn recorder<'a, T>(&self, recorder: &'a Mutex) -> MutexGuard<'a, T> { + recorder + .lock() + .expect("a test-support recorder lock is never poisoned") + } + fn push(&self, event: &'static str) -> Result<(), NetworkEffectError> { - self.inner.events.lock().push(event); - let mut configured = self.inner.effect_error.lock(); + self.recorder(&self.inner.events).push(event); + let mut configured = self.recorder(&self.inner.effect_error); if configured.is_some_and(|error| { matches!( (event, error), @@ -57,7 +70,22 @@ impl FakePorts { } fn events(&self) -> Vec<&'static str> { - self.inner.events.lock().clone() + self.recorder(&self.inner.events).clone() + } + + /// Script the error the next matching effect reports. + fn script_effect_error(&self, error: Option) { + *self.recorder(&self.inner.effect_error) = error; + } + + /// The captured firewall generation identities, oldest first. + fn firewall_generations(&self) -> Vec { + self.recorder(&self.inner.firewall_generations).clone() + } + + /// The recorded mDNS values, oldest first. + fn mdns_values(&self) -> Vec { + self.recorder(&self.inner.mdns_values).clone() } } @@ -94,9 +122,7 @@ impl NetworkEffectPort for FakePorts { &self, intent: &FirewallIntent, ) -> Result { - self.inner - .firewall_generations - .lock() // async-gate-allow: test-support recorder lock + self.recorder(&self.inner.firewall_generations) .push(intent.expected_generation_id().as_str().to_owned()); self.push("firewall-apply")?; Ok(FirewallDigest::new([1; 32])) @@ -176,7 +202,7 @@ impl NetworkResourcePort for FakePorts { } async fn reconcile_mdns(&self, enabled: bool) -> Result<(), NetworkEffectError> { - self.inner.mdns_values.lock().push(enabled); // async-gate-allow: test-support recorder lock + self.recorder(&self.inner.mdns_values).push(enabled); self.push("mdns") } @@ -311,10 +337,7 @@ fn reconcile_enforces_effect_and_child_readiness_order() { "tap-delete", ] ); - assert_eq!( - *effects.inner.firewall_generations.lock(), - [generation().as_str()] - ); + assert_eq!(effects.firewall_generations(), [generation().as_str()]); assert_eq!( resources.events(), [ @@ -367,8 +390,7 @@ fn guest_and_agent_are_barriered_by_volume_and_attachment_readiness() { #[test] fn stale_configuration_generation_requeues_without_following_effects() { let effects = FakePorts::default(); - *effects.inner.effect_error.lock() = - Some(NetworkEffectError::StaleConfigurationGeneration); + effects.script_effect_error(Some(NetworkEffectError::StaleConfigurationGeneration)); let resources = FakePorts::default(); let controller = NetworkReconciler::new(effects.clone(), resources.clone()); assert!(matches!( @@ -478,7 +500,7 @@ fn user_readiness_and_mdns_toggle_are_explicit() { block_on(controller.reconcile(&enabled)).unwrap(), ReconcileProgress::Ready ); - assert_eq!(*resources.inner.mdns_values.lock(), [true]); + assert_eq!(resources.mdns_values(), [true]); } #[test] @@ -498,7 +520,7 @@ fn east_west_requires_the_site_opt_in_before_any_effect() { #[test] fn transient_tap_delete_retains_finalizer_stage_for_retry() { let effects = FakePorts::default(); - *effects.inner.effect_error.lock() = Some(NetworkEffectError::Transient); + effects.script_effect_error(Some(NetworkEffectError::Transient)); let resources = FakePorts::default(); let controller = NetworkReconciler::new(effects.clone(), resources); assert_eq!( diff --git a/packages/d2b-provider-volume/Cargo.toml b/packages/d2b-provider-volume/Cargo.toml index dba738586..0dd87f3d5 100644 --- a/packages/d2b-provider-volume/Cargo.toml +++ b/packages/d2b-provider-volume/Cargo.toml @@ -24,7 +24,6 @@ d2b-provider-volume-local = { path = "../d2b-provider-volume-local", version = " d2b-provider-volume-virtiofs = { path = "../d2b-provider-volume-virtiofs", version = "0.0.0-bootstrap" } d2b-resource-runtime = { path = "../d2b-resource-runtime", version = "0.0.0-bootstrap" } d2b-resource-types = { path = "../d2b-resource-types", version = "0.0.0-bootstrap" } -parking_lot = "0.12" serde_json.workspace = true tokio = { workspace = true, features = ["macros", "rt-multi-thread", "sync", "time"] } diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index ebaed6c99..47598b728 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -761,12 +761,14 @@ mod tests { /// Recording manager endpoint over one shared ordered log so tests can /// assert commit-before-spawn (F1) and retire/retain behavior. The - /// in-memory row set emulates the manager's store. + /// in-memory row set emulates the manager's store. Both fields are async + /// locks: the endpoint methods and the test bodies that read them are + /// async, so every acquisition can await. #[derive(Clone)] struct RecordingManager { zone: String, - log: Arc>>, - rows: Arc>>, + log: Arc>>, + rows: Arc>>, next_uid: Arc, } @@ -774,14 +776,14 @@ mod tests { fn new() -> Self { Self { zone: "work".to_owned(), - log: Arc::new(parking_lot::Mutex::new(Vec::new())), - rows: Arc::new(parking_lot::Mutex::new(Vec::new())), + log: Arc::new(tokio::sync::Mutex::new(Vec::new())), + rows: Arc::new(tokio::sync::Mutex::new(Vec::new())), next_uid: Arc::new(std::sync::atomic::AtomicU64::new(1)), } } - fn order(&self) -> Vec { - self.log.lock().clone() + async fn order(&self) -> Vec { + self.log.lock().await.clone() } } @@ -796,7 +798,7 @@ mod tests { // Record the ensure request first; the commit (this function's // row write) happens before the reply, and the spawn // notification is recorded only after it. - self.log.lock().push(format!("ensure:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.log.lock().await.push(format!("ensure:{id}")); let next = self .next_uid .fetch_add(1, std::sync::atomic::Ordering::SeqCst); @@ -813,7 +815,7 @@ mod tests { metadata: child.metadata, created_at: 0, }; - let mut rows = self.rows.lock(); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + let mut rows = self.rows.lock().await; let outcome = match rows.iter_mut().find(|existing| existing.key == row.key) { Some(existing) => { if existing.spec == row.spec { @@ -829,7 +831,7 @@ mod tests { } }; drop(rows); - self.log.lock().push(format!("spawned:{id}")); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.log.lock().await.push(format!("spawned:{id}")); Ok(outcome) } @@ -837,7 +839,7 @@ mod tests { &self, key: &ResourceKey, ) -> Result, ResourceError> { - Ok(self.rows.lock().iter().find(|row| row.key == *key).cloned()) // async-gate-allow: synchronous lock acquisition, no await while the guard is held + Ok(self.rows.lock().await.iter().find(|row| row.key == *key).cloned()) } async fn view( @@ -851,9 +853,10 @@ mod tests { async fn delete(&self, key: &ResourceKey) -> Result<(), ResourceError> { self.log - .lock() // async-gate-allow: synchronous lock acquisition, no await while the guard is held + .lock() + .await .push(format!("delete:{}/{}", key.type_name, key.name)); - self.rows.lock().retain(|row| row.key != *key); // async-gate-allow: synchronous lock acquisition, no await while the guard is held + self.rows.lock().await.retain(|row| row.key != *key); Ok(()) } @@ -864,6 +867,7 @@ mod tests { Ok(self .rows .lock() + .await .iter() .filter(|row| row.owner_uid.as_ref() == Some(&owner_uid)) .cloned() @@ -1031,7 +1035,7 @@ mod tests { let outcome = reconcile_to_children(&mut d, &mut f).await; assert_eq!(outcome, ReconcileOutcome::Satisfied); - let order = manager.order(); + let order = manager.order().await; assert_eq!( fake.call_order(), vec!["has-layout", "ensure-layout"], @@ -1115,12 +1119,13 @@ mod tests { ); let binding_ensures = manager .order() + .await .iter() .filter(|entry| entry.starts_with("ensure:VolumeBinding/")) .count(); assert_eq!(binding_ensures, 2, "the adoption pass re-attaches the same binding child"); assert_eq!( - manager.rows.lock().len(), // async-gate-allow: synchronous lock acquisition, no await while the guard is held + manager.rows.lock().await.len(), 1, "re-attaching the deterministic child never mints a duplicate row" ); @@ -1159,6 +1164,7 @@ mod tests { assert!( !manager .order() + .await .iter() .any(|entry| entry.starts_with("ensure:VolumeBinding/")), "a degraded layout derives no binding children" @@ -1193,7 +1199,7 @@ mod tests { let mut d = driver(RecordingRuntime::new()).await; reconcile_to_children(&mut d, &mut f).await; } - let first = manager.order(); + let first = manager.order().await; // Same parent + attachment -> exactly one child key, ensured again // as Unchanged (no duplicate identity, no churn). { @@ -1202,7 +1208,7 @@ mod tests { d.recover(&mut f.ctx).await.expect("recover"); reconcile_to_children(&mut d, &mut f).await; } - let second = manager.order(); + let second = manager.order().await; let ensure_count = first .iter() .filter(|entry| entry.starts_with("ensure:VolumeBinding/")) @@ -1239,6 +1245,7 @@ mod tests { reconcile_to_children(&mut d, &mut f).await; let first_child = manager .order() + .await .iter() .find_map(|entry| entry.strip_prefix("ensure:VolumeBinding/")) .expect("first binding name") @@ -1260,6 +1267,7 @@ mod tests { d.reconcile(&mut ctx2).await.expect("reconcile grown"); let ensured = manager .order() + .await .iter() .filter(|entry| entry.starts_with("ensure:VolumeBinding/")) .count(); @@ -1267,6 +1275,7 @@ mod tests { assert!( !manager .order() + .await .iter() .any(|entry| entry.starts_with("delete:")), "matching child retained, no delete on growth" @@ -1288,6 +1297,7 @@ mod tests { d.reconcile(&mut ctx3).await.expect("reconcile shrunk"); let deletes = manager .order() + .await .iter() .filter(|entry| entry.starts_with("delete:VolumeBinding/")) .cloned() @@ -1296,7 +1306,7 @@ mod tests { assert!( !deletes[0].contains(&first_child), "matching child never retired, order: {:?}", - manager.order() + manager.order().await ); } @@ -1306,7 +1316,7 @@ mod tests { #[tokio::test] async fn finalize_finalizes_owned_children_before_the_layout_teardown() { let manager = RecordingManager::new(); - manager.rows.lock().push(StoredDesiredResource { // async-gate-allow: synchronous lock acquisition, no await while the guard is held + manager.rows.lock().await.push(StoredDesiredResource { key: ResourceKey::new("work", "VolumeBinding", "vol-binding-0"), uid: [0x77; 16], generation: 1, @@ -1326,7 +1336,7 @@ mod tests { let failure = d.finalize(&mut f.ctx).await.expect_err("owned child still live"); assert_eq!(failure.class(), FailureClass::Retryable); assert_eq!( - manager.order(), + manager.order().await, vec!["delete:VolumeBinding/vol-binding-0".to_owned()], "the owned child is nudged through its own finalize-before-delete pass" ); diff --git a/packages/d2b-provider-volume/src/test_support.rs b/packages/d2b-provider-volume/src/test_support.rs index fca41a53c..5618fcf7a 100644 --- a/packages/d2b-provider-volume/src/test_support.rs +++ b/packages/d2b-provider-volume/src/test_support.rs @@ -7,7 +7,7 @@ //! which layout effects the Volume driver ran. use std::sync::atomic::AtomicBool; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use async_trait::async_trait; use d2b_contracts_resource::v3::volume::VolumeSpec; @@ -47,8 +47,14 @@ impl VolumeRuntime for RefusingRuntime { } /// Scripted layout runtime: records every call in order. +/// +/// The call log is the blocking lock: [`VolumeRuntime::has_layout`] is a +/// synchronous trait method and [`RecordingRuntime::call_order`] a +/// synchronous accessor, so neither can await an async lock. Both +/// acquisitions sit behind one sync appender and one sync snapshot, and +/// each carries its own recorded exception. pub struct RecordingRuntime { - calls: parking_lot::Mutex>, + calls: Mutex>, /// Whether the runtime currently reports a Ready layout /// (`has_layout` returns this). pub ready: AtomicBool, @@ -61,7 +67,7 @@ impl RecordingRuntime { /// A fresh runtime: no layout yet, every call recorded. pub fn new() -> Arc { Arc::new(Self { - calls: parking_lot::Mutex::new(Vec::new()), + calls: Mutex::new(Vec::new()), ready: AtomicBool::new(false), degraded: AtomicBool::new(false), }) @@ -75,8 +81,21 @@ impl RecordingRuntime { } /// The ordered log of layout-probe calls made through this runtime. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn call_order(&self) -> Vec<&'static str> { - self.calls.lock().clone() + self.calls + .lock() + .expect("a test-support recorder lock is never poisoned") + .clone() + } + + /// Append one layout-probe call to the ordered log. + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn record(&self, call: &'static str) { + self.calls + .lock() + .expect("a test-support recorder lock is never poisoned") + .push(call); } } @@ -96,7 +115,7 @@ impl VolumeRuntime for RecordingRuntime { _provider: Option<&serde_json::Value>, _owner_ref: Option<&ResourceRef>, ) -> Result { - self.calls.lock().push("ensure-layout"); // async-gate-allow: test-support recorder lock + self.record("ensure-layout"); if self.degraded.load(std::sync::atomic::Ordering::SeqCst) { return Ok(false); } @@ -109,12 +128,12 @@ impl VolumeRuntime for RecordingRuntime { _volume_uid: &ResourceUid, _spec: &VolumeSpec, ) -> Result<(), String> { - self.calls.lock().push("remove-layout"); // async-gate-allow: test-support recorder lock + self.record("remove-layout"); Ok(()) } fn has_layout(&self, _volume_uid: &ResourceUid) -> bool { - self.calls.lock().push("has-layout"); + self.record("has-layout"); self.ready.load(std::sync::atomic::Ordering::SeqCst) } } \ No newline at end of file diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json index c6d0f8d68..f13821353 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index f2abf96ff..1e4003ddc 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json index d22bf9bbd..d9fa7d561 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json index f2abf96ff..1e4003ddc 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index c4f8ba72d..b772efc51 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 8795ddb46..a4e85e5c9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index d335c4667..122c08121 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 8795ddb46..a4e85e5c9 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index e1b5e77f8..320123d08 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index daf606525..539939915 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index 7b25bf743..aafde8015 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index daf606525..539939915 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json index 496766575..fdaf680b4 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json index f2abf96ff..1e4003ddc 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json index 2da4f65f8..ce0ccb33c 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json index f2abf96ff..1e4003ddc 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock index 374dfe270..28f7d946b 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1600,7 +1600,6 @@ dependencies = [ "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "rustix 0.38.44", "serde", "serde_json", @@ -2022,7 +2021,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json index 3331808e6..8703cbe5e 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6089,6 +6089,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-device@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-display-wayland@0.0.0-bootstrap#path", "to": "clap@4.6.6#registry+https://github.com/rust-lang/crates.io-index", @@ -6785,12 +6791,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-network-local@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-network-local@0.0.0-bootstrap#path", "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8483,12 +8483,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json index b78ed36b5..4d23f95a0 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock index 374dfe270..28f7d946b 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1600,7 +1600,6 @@ dependencies = [ "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "rustix 0.38.44", "serde", "serde_json", @@ -2022,7 +2021,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json index 52afafc49..50ca3c48b 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5813,6 +5813,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-device@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-display-wayland@0.0.0-bootstrap#path", "to": "clap@4.6.6#registry+https://github.com/rust-lang/crates.io-index", @@ -6455,12 +6461,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-network-local@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-network-local@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -7877,12 +7877,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json index b78ed36b5..4d23f95a0 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 395, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json index 75686594f..bcf3189a0 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json index 91226c802..474de2195 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json index 17c5987a9..77414fccc 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json index 91226c802..474de2195 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-default-tests/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json index 7aa64e673..35d1ab0d2 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json index 045761813..9a0acdbd1 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json index 017318690..b8421af02 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json index 045761813..9a0acdbd1 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-fake-backends-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "fake-backends" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json index 7983c991c..b90a9d6a4 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json index 44e3b0fd8..373531dde 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/policy/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json index e80f09639..bdeaa7f7a 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/closure.json @@ -12,7 +12,7 @@ ], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json index 44e3b0fd8..373531dde 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-layer1-bootstrap-tests/production/metadata.json @@ -4,7 +4,7 @@ "features": [ "layer1-bootstrap" ], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json index f2673e8ca..1a8321458 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json index 91226c802..474de2195 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json index 6b1b39a2d..d06e25077 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/closure.json @@ -10,7 +10,7 @@ "features": [], "default_features": false, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json index 91226c802..474de2195 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/broker-production/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 80, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock index 374dfe270..28f7d946b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/Cargo.lock @@ -1600,7 +1600,6 @@ dependencies = [ "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "rustix 0.38.44", "serde", "serde_json", @@ -2022,7 +2021,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json index d4d26bad2..dcce170e1 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -6127,6 +6127,12 @@ "kind": "dev", "target": null }, + { + "from": "d2b-provider-device@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-display-wayland@0.0.0-bootstrap#path", "to": "clap@4.6.6#registry+https://github.com/rust-lang/crates.io-index", @@ -6823,12 +6829,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-network-local@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-network-local@0.0.0-bootstrap#path", "to": "rustix@0.38.44#registry+https://github.com/rust-lang/crates.io-index", @@ -8521,12 +8521,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json index a90093679..8a6607ddb 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock index 374dfe270..28f7d946b 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/Cargo.lock @@ -1600,7 +1600,6 @@ dependencies = [ "d2b-provider-toolkit", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "rustix 0.38.44", "serde", "serde_json", @@ -2022,7 +2021,6 @@ dependencies = [ "d2b-provider-volume-virtiofs", "d2b-resource-runtime", "d2b-resource-types", - "parking_lot", "serde_json", "tokio", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json index 4e0ab787b..47683a22c 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/closure.json @@ -99,7 +99,7 @@ "features": [], "default_features": true, "source_authority": "Cargo.lock", - "lock_sha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lock_sha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5851,6 +5851,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-provider-device@0.0.0-bootstrap#path", + "to": "tokio@1.53.1#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-provider-display-wayland@0.0.0-bootstrap#path", "to": "clap@4.6.6#registry+https://github.com/rust-lang/crates.io-index", @@ -6493,12 +6499,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-network-local@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-network-local@0.0.0-bootstrap#path", "to": "serde@1.0.229#registry+https://github.com/rust-lang/crates.io-index", @@ -7915,12 +7915,6 @@ "kind": "normal", "target": null }, - { - "from": "d2b-provider-volume@0.0.0-bootstrap#path", - "to": "parking_lot@0.12.5#registry+https://github.com/rust-lang/crates.io-index", - "kind": "normal", - "target": null - }, { "from": "d2b-provider-volume@0.0.0-bootstrap#path", "to": "serde_json@1.0.151#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json index a90093679..8a6607ddb 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-gnu/main-product/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": true, "features": [], - "lockSha256": "a4260159f8005a1ad118ee1469408cde69c25070afb39a7da000623daadfe0cf", + "lockSha256": "e454a2e441db2592805160bfd0e9de55b4a8537e754127e58c595b6967cdb695", "policyPackageCount": 396, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index f3205f49b..4cf402cc1 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -421,21 +421,6 @@ "line": 98, "reason": "test-support recorder lock" }, - { - "file": "packages/d2b-provider-device/src/test_support.rs", - "line": 37, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-device/src/test_support.rs", - "line": 49, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-device/tests/device_family.rs", - "line": 167, - "reason": "test-support recorder lock" - }, { "file": "packages/d2b-provider-endpoint/src/test_support.rs", "line": 73, @@ -501,51 +486,6 @@ "line": 271, "reason": "test-support recorder lock" }, - { - "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 646, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 746, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-network-local/src/driver.rs", - "line": 747, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-network-local/src/test_support.rs", - "line": 68, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-network-local/src/test_support.rs", - "line": 69, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-network-local/src/test_support.rs", - "line": 79, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-network-local/src/test_support.rs", - "line": 80, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-network-local/tests/reconcile.rs", - "line": 99, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-network-local/tests/reconcile.rs", - "line": 179, - "reason": "test-support recorder lock" - }, { "file": "packages/d2b-provider-process/src/driver.rs", "line": 2451, @@ -751,56 +691,6 @@ "line": 1336, "reason": "synchronous lock acquisition, no await while the guard is held" }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 799, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 816, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 832, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 840, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 854, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 856, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1123, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/driver.rs", - "line": 1309, - "reason": "synchronous lock acquisition, no await while the guard is held" - }, - { - "file": "packages/d2b-provider-volume/src/test_support.rs", - "line": 99, - "reason": "test-support recorder lock" - }, - { - "file": "packages/d2b-provider-volume/src/test_support.rs", - "line": 112, - "reason": "test-support recorder lock" - }, { "file": "packages/d2b-resource-runtime/src/context.rs", "line": 914, From 04cf64c5d5e31ff8be630d1c7bc44aacb78c9c3a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:15:25 -0700 Subject: [PATCH 693/726] refactor(d2bd-runtime): reach the runtime locks through tokio seats The unsafe-local helper registry's four mutexes are `tokio::sync::Mutex` reached through one seat helper: a caller that does not drive a runtime (the helper accept loop, its per-connection handler threads, and the daemon's `d2b-conn` dispatch threads) parks on the blocking seat, while a runtime worker keeps the repository's bounded try-lock spin, because the blocking seats panic inside a runtime and the `--once` serve path dispatches its connection inline on the accept loop's runtime worker. Every critical section is a sub-microsecond map operation and no guard is held across an await. The op-lock manager's four `try_lock` + `spin_loop` loops are gone: the global and per-VM op locks are taken through the same dual seat, so a contended production op parks its dedicated `d2b-conn` handler thread until the holder finishes instead of burning it in a spin, while the inline `--once` path keeps the bounded spin that works on a runtime worker. The acquisition doc records both seats and the single lock ordering, and the stale claim that acquisition spins unconditionally is deleted. The pidfd table's locks stay blocking primitives and each locking function carries a recorded per-site allow. The readiness liveness probe and the startup-adoption pass read the table on runtime workers, where tokio's blocking seats panic, while the lifecycle and dispatch paths lock it from dedicated threads; one lock serves both, so the `parking_lot` dependency is unchanged. The async-gate inventory is regenerated for the composition.rs line shift carried by the integration base, which the gate reported as drift. --- changelog.d/w7-20-d2bd-runtime-locks.md | 22 +++ packages/d2bd-runtime/src/concurrency.rs | 102 +++++++++----- .../src/supervisor/pidfd_table.rs | 31 ++++ .../d2bd-runtime/src/unsafe_local_helper.rs | 132 ++++++++++-------- packages/xtask/data/async-gate-inventory.json | 4 +- 5 files changed, 195 insertions(+), 96 deletions(-) create mode 100644 changelog.d/w7-20-d2bd-runtime-locks.md diff --git a/changelog.d/w7-20-d2bd-runtime-locks.md b/changelog.d/w7-20-d2bd-runtime-locks.md new file mode 100644 index 000000000..814f8a1ac --- /dev/null +++ b/changelog.d/w7-20-d2bd-runtime-locks.md @@ -0,0 +1,22 @@ +### Changed + +- The unsafe-local helper registry's mutexes are `tokio::sync::Mutex`, + reached through one seat helper: a caller that does not drive a + runtime - the helper accept loop, its per-connection handler threads, + and the daemon's `d2b-conn` dispatch threads - parks on the blocking + seat, while a runtime worker keeps the repository's bounded try-lock + spin, because the blocking seats panic inside a runtime and the + `--once` serve path dispatches its connection inline on the accept + loop's runtime worker. +- The op-lock manager no longer spins on four `try_lock` loops: the + global and per-VM op locks are taken through the same dual seat, so a + contended production op parks its dedicated `d2b-conn` handler thread + until the holder finishes, while the inline `--once` path keeps the + bounded spin that works on a runtime worker. The acquisition doc + records both seats and the single lock ordering. +- The pidfd table's locks stay blocking primitives, each locking + function carrying a recorded per-site allow. The readiness liveness + probe and the startup-adoption pass read the table on runtime + workers, where tokio's blocking seats panic, while the lifecycle and + dispatch paths lock it from dedicated threads; one lock serves both, + so the `parking_lot` dependency is unchanged. diff --git a/packages/d2bd-runtime/src/concurrency.rs b/packages/d2bd-runtime/src/concurrency.rs index 9b50658b8..3031eb4a4 100644 --- a/packages/d2bd-runtime/src/concurrency.rs +++ b/packages/d2bd-runtime/src/concurrency.rs @@ -117,12 +117,11 @@ pub enum OpLockClass { /// Per-VM + global in-process op locks. Cheaply [`Clone`]able (all state /// behind `Arc`) so it can live inside the `Clone` `ServerState`. /// -/// The locks are `tokio::sync` primitives (async purity, plan U17). The -/// daemon's dispatch threads are dedicated worker threads - never executor -/// workers - so `acquire` takes the blocking owned-lock seats, which park -/// the calling worker thread exactly like the parking_lot seats they replace -/// (and which panic if ever called from inside a runtime; the daemon's -/// dispatch boundary is a plain thread by construction). +/// The locks are `tokio::sync` primitives (async purity, plan U17). +/// Production dispatch runs on dedicated `d2b-conn` handler threads, so +/// `acquire` parks them on the blocking seats; the `--once` serve path +/// dispatches inline on the accept loop's runtime worker, where those seats +/// panic, so `acquire` keeps the bounded try-lock spin there instead. #[derive(Debug, Clone, Default)] pub struct OpLockManager { /// A global op takes the write side (exclusive with every per-VM op); @@ -154,51 +153,82 @@ impl OpLockManager { } /// Acquire the lock appropriate to `class`. The op lock spans a - /// synchronous critical section (never an await), and callers run both - /// on tokio runtime workers (the async dispatch path) and on dedicated - /// threads; tokio's `blocking_*` primitives panic inside a runtime, so - /// acquisition spins on `try_lock` until the lock is free (the repo's - /// lock_sync pattern). The critical sections are single map ops, so a - /// spin is bounded and there is no deadlock: holders never await. + /// synchronous critical section (never an await) and is held for the + /// whole op, so the wait matters. + /// + /// Off a runtime the acquisition takes the tokio blocking seats, which + /// park the calling thread; that is what production dispatch wants, + /// because every production connection is handled on its own dedicated + /// `d2b-conn` thread. The blocking seats panic on a runtime worker, and + /// the `--once` serve path dispatches its single connection inline on + /// the accept loop's runtime worker, so there the wait keeps the repo's + /// `lock_sync` bounded try-lock spin (`authority_persistence` and the + /// Zone activation guard take the same shape). The critical sections + /// are single map ops, holders never await, and the single lock ordering + /// is acyclic, so the wait is bounded and deadlock-free on either seat. pub fn acquire(&self, class: &OpLockClass) -> OpLockGuard<'_> { + let blocking = tokio::runtime::Handle::try_current().is_err(); match class { OpLockClass::ReadOnly => OpLockGuard::None, OpLockClass::PerVm(vm) => { // Lock ordering: global(read) THEN per-VM. A global op // takes global(write), so it cannot interleave with an // in-flight per-VM op, and the single ordering is acyclic. - let global = loop { - match self.global.try_read() { - Ok(guard) => break guard, - Err(_) => std::hint::spin_loop(), - } - }; + let global = wait_for_op_lock( + blocking, + || self.global.try_read().ok(), + || self.global.blocking_read(), + ); let vm_lock = { - let mut map = loop { - match self.per_vm.try_lock() { - Ok(guard) => break guard, - Err(_) => std::hint::spin_loop(), - } - }; + let mut map = wait_for_op_lock( + blocking, + || self.per_vm.try_lock().ok(), + || self.per_vm.blocking_lock(), + ); Arc::clone( map.entry(vm.clone()) .or_insert_with(|| Arc::new(Mutex::new(()))), ) }; - let vm = loop { - match vm_lock.clone().try_lock_owned() { - Ok(guard) => break guard, - Err(_) => std::hint::spin_loop(), - } - }; + let vm = wait_for_op_lock( + blocking, + || vm_lock.clone().try_lock_owned().ok(), + || vm_lock.clone().blocking_lock_owned(), + ); OpLockGuard::PerVm { global, vm } } - OpLockClass::Global => loop { - match self.global.try_write() { - Ok(guard) => break OpLockGuard::Global(guard), - Err(_) => std::hint::spin_loop(), - } - }, + OpLockClass::Global => OpLockGuard::Global(wait_for_op_lock( + blocking, + || self.global.try_write().ok(), + || self.global.blocking_write(), + )), + } + } +} + +/// Wait for one op-lock seat. +/// +/// `blocking` names the seat `OpLockManager::acquire` chose: the blocking +/// seat parks the calling thread when the caller does not drive a runtime, +/// and the bounded try-lock spin (the `lock_sync` shape, +/// `authority_persistence`) carries the wait on a runtime worker, where +/// tokio's blocking seats panic. The free fast path runs first, so an +/// uncontended lock is taken without either wait. +fn wait_for_op_lock( + blocking: bool, + try_acquire: impl Fn() -> Option, + blocking_acquire: impl FnOnce() -> T, +) -> T { + if let Some(guard) = try_acquire() { + return guard; + } + if blocking { + return blocking_acquire(); + } + loop { + match try_acquire() { + Some(guard) => return guard, + None => std::hint::spin_loop(), } } } diff --git a/packages/d2bd-runtime/src/supervisor/pidfd_table.rs b/packages/d2bd-runtime/src/supervisor/pidfd_table.rs index 317d170b7..f96592809 100644 --- a/packages/d2bd-runtime/src/supervisor/pidfd_table.rs +++ b/packages/d2bd-runtime/src/supervisor/pidfd_table.rs @@ -20,6 +20,18 @@ static SIGNAL_EPERM_TEST_ROLES: OnceLock>, @@ -81,11 +93,13 @@ impl BrokerReapLog { } /// Insert (or overwrite) a ChildReaped event keyed by PID. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn insert(&self, notif: d2b_contracts_broker::broker_wire::ChildReapedNotification) { self.inner.lock().insert(notif.pid, notif); } /// Remove and return the event for `pid`, if any. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn take( &self, pid: i32, @@ -94,6 +108,7 @@ impl BrokerReapLog { } /// Remove and return the event for a `(vm, role)` runner id, if any. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn take_for( &self, vm: &str, @@ -113,6 +128,7 @@ impl BrokerReapLog { /// readiness liveness probe must only observe so the buffered exit /// status remains available to the mutating teardown path /// (`wait_terminated` / rollback) that owns deregistration. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn peek_for( &self, vm: &str, @@ -235,6 +251,7 @@ impl PidfdTable { /// Reserve one in-flight spawn so a concurrent starter cannot launch a /// second writer against the same VM role. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn try_reserve_spawn(&self, vm: &str, role: &str) -> bool { self.spawn_reservations .lock() @@ -242,6 +259,7 @@ impl PidfdTable { } /// Drop an in-flight spawn reservation. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn release_spawn_reservation(&self, vm: &str, role: &str) { self.spawn_reservations .lock() @@ -260,6 +278,7 @@ impl PidfdTable { let _ = self.broker_reap_log.set(log); } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn register( &self, vm: String, @@ -276,6 +295,7 @@ impl PidfdTable { Ok(()) } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn deregister(&self, vm: &str, role: &str) -> Option { let mut entries = self.entries.write(); let removed = entries.remove(&(vm.to_owned(), role.to_owned())); @@ -288,6 +308,7 @@ impl PidfdTable { /// Remove an entry only when it still identifies the supplied process. /// Rollback paths use this to avoid deleting a newer/live registration /// that won a concurrent spawn race. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn deregister_if_matches( &self, vm: &str, @@ -315,6 +336,7 @@ impl PidfdTable { self.generation.fetch_add(1, Ordering::AcqRel); } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn contains(&self, vm: &str, role: &str) -> bool { self.entries .read() @@ -333,6 +355,7 @@ impl PidfdTable { /// /// Returns the number of entries dropped. Snapshot is /// re-persisted to disk if any entries were dropped. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn prune_dead_entries(&self) -> Result { // Serialize the mutate + snapshot sequence against concurrent // register/deregister+snapshot from other VMs (same invariant as @@ -375,6 +398,7 @@ impl PidfdTable { Ok(dropped) } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn list_for_vm(&self, vm: &str) -> Vec { self.entries .read() @@ -389,6 +413,7 @@ impl PidfdTable { .collect() } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn len(&self) -> usize { self.entries.read().len() } @@ -397,6 +422,7 @@ impl PidfdTable { self.len() == 0 } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn signal(&self, vm: &str, role: &str, sig: libc::c_int) -> Result<(), PidfdTableError> { let signal = rustix::process::Signal::from_raw(sig) .ok_or(PidfdTableError::InvalidSignal { signal: sig })?; @@ -546,6 +572,7 @@ impl PidfdTable { } } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn still_alive_same_start_time(&self, vm: &str, role: &str) -> bool { let (pid, start_time_ticks) = { let entries = self.entries.read(); @@ -563,6 +590,7 @@ impl PidfdTable { /// snapshot" sequence hold this guard across BOTH steps so concurrent /// different-VM ops cannot lose an entry on disk (one thread's /// snapshot landing between another thread's register and snapshot). + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn mutation_guard(&self) -> parking_lot::MutexGuard<'_, ()> { self.mutation_lock.lock() } @@ -574,6 +602,7 @@ impl PidfdTable { /// /// This OBSERVES only - it never removes the entry. All /// deregistration stays in the teardown / rollback path. + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn dup_pidfd_for(&self, vm: &str, role: &str) -> Option<(OwnedFd, i32, u64)> { let entries = self.entries.read(); let entry = entries.get(&(vm.to_owned(), role.to_owned()))?; @@ -587,6 +616,7 @@ impl PidfdTable { self.contains(vm, role) } + #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn snapshot(&self) -> Result<(), PidfdTableError> { let persisted = { let entries = self.entries.read(); @@ -660,6 +690,7 @@ impl PidfdTable { } #[cfg(any(test, feature = "test-support"))] +#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] pub fn force_signal_eperm_for_tests(vm: &str, role: &str, enabled: bool) { let mut roles = SIGNAL_EPERM_TEST_ROLES .get_or_init(|| Mutex::new(Default::default())) diff --git a/packages/d2bd-runtime/src/unsafe_local_helper.rs b/packages/d2bd-runtime/src/unsafe_local_helper.rs index 203f2f9de..fab2b56c9 100644 --- a/packages/d2bd-runtime/src/unsafe_local_helper.rs +++ b/packages/d2bd-runtime/src/unsafe_local_helper.rs @@ -23,7 +23,6 @@ use nix::sys::socket::{ sockopt::PeerCredentials, }; use nix::unistd::{self, Gid}; -use parking_lot::Mutex; use serde::Serialize; use sha2::{Digest, Sha256}; use socket2::{Domain, SockAddr, Socket, Type}; @@ -38,6 +37,7 @@ use std::path::Path; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, mpsc}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +use tokio::sync::Mutex; /// How often a healthy helper must send a heartbeat to stay live. pub const HELPER_HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5); @@ -101,6 +101,33 @@ impl fmt::Debug for HelperReply { } } +/// Wait for one registry lock. +/// +/// The registry's own accept loop and per-connection handler threads, and +/// the daemon's `d2b-conn` handler threads, do not drive a runtime, so they +/// take the tokio blocking seat and park until the lock is free. A runtime +/// worker takes the repo's `lock_sync` bounded try-lock spin instead +/// (`authority_persistence`), because the blocking seats panic there: the +/// `--once` serve path dispatches its single connection inline on the +/// accept loop's runtime worker, and the workload status and launcher +/// dispatch read this registry on that path. Every critical section is a +/// sub-microsecond map operation and no guard is held across an await, so +/// the spin is short. +fn lock_registry(mutex: &Mutex) -> tokio::sync::MutexGuard<'_, T> { + if let Ok(guard) = mutex.try_lock() { + return guard; + } + if tokio::runtime::Handle::try_current().is_err() { + return mutex.blocking_lock(); + } + loop { + match mutex.try_lock() { + Ok(guard) => return guard, + Err(_) => std::hint::spin_loop(), + } + } +} + struct PendingRequest { operation_id: String, sender: mpsc::SyncSender>, @@ -147,7 +174,7 @@ impl HelperConnection { return; } let _ = self.socket.shutdown(std::net::Shutdown::Both); - let pending = std::mem::take(&mut *self.pending.lock()); + let pending = std::mem::take(&mut *lock_registry(&self.pending)); for (_, request) in pending { let _ = request.sender.try_send(Err(reason)); } @@ -165,14 +192,14 @@ impl HelperConnection { } fn abandon_pending(&self, request_id: u64, operation_id: &str) { - let Some(pending) = self.pending.lock().remove(&request_id) else { + let Some(pending) = lock_registry(&self.pending).remove(&request_id) else { return; }; if pending.operation_id != operation_id { return; } let now = Instant::now(); - let mut abandoned = self.abandoned.lock(); + let mut abandoned = lock_registry(&self.abandoned); abandoned.retain(|_, request| request.expires_at > now); if abandoned.len() >= MAX_HELPER_QUEUE_DEPTH && let Some(oldest) = abandoned @@ -193,8 +220,7 @@ impl HelperConnection { fn reap_abandoned(&self) { let now = Instant::now(); - self.abandoned - .lock() + lock_registry(&self.abandoned) .retain(|_, request| request.expires_at > now); } } @@ -210,6 +236,13 @@ struct RegistryState { /// /// Tracks per-UID helper generations, snapshots, and operation /// completions; all peer contact flows through [`Self::accept_loop`]. +/// +/// The mutexes are `tokio::sync` primitives (async purity, plan U17) +/// reached through the `lock_registry` helper: the accept loop, its +/// per-connection handler threads, and the daemon's `d2b-conn` dispatch +/// thread park on the blocking seat, while a runtime worker (the `--once` +/// serve path dispatches its connection inline) takes the bounded try-lock +/// spin there, because the blocking seats panic inside a runtime. pub struct HelperRegistry { daemon_uid: u32, allowed_uids: HashSet, @@ -219,7 +252,7 @@ pub struct HelperRegistry { impl fmt::Debug for HelperRegistry { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let state = self.state.lock(); + let state = lock_registry(&self.state); f.debug_struct("HelperRegistry") .field("allowed_uid_count", &self.allowed_uids.len()) .field("active_helper_count", &state.connections.len()) @@ -277,8 +310,7 @@ impl HelperRegistry { /// The generation of the live helper connection for `uid`, or `None`. pub fn active_generation(&self, uid: u32) -> Option { - self.state - .lock() + lock_registry(&self.state) .connections .get(&uid) .filter(|connection| !connection.closed.load(Ordering::Acquire)) @@ -287,12 +319,12 @@ impl HelperRegistry { /// The last helper snapshot the daemon saw for `uid`, if any. pub fn snapshot(&self, uid: u32) -> Option { - self.state.lock().snapshots.get(&uid).cloned() + lock_registry(&self.state).snapshots.get(&uid).cloned() } /// Whether `uid` has a ready, unavailable, or stale helper connection. pub fn availability(&self, uid: u32) -> HelperAvailability { - let state = self.state.lock(); + let state = lock_registry(&self.state); let Some(connection) = state.connections.get(&uid) else { return HelperAvailability::Unavailable; }; @@ -312,8 +344,7 @@ impl HelperRegistry { uid: u32, target: &d2b_contracts::workload_identity::WorkloadTarget, ) -> Option { - self.state - .lock() + lock_registry(&self.state) .last_failures .get(&(uid, target.to_canonical())) .copied() @@ -339,7 +370,7 @@ impl HelperRegistry { let operation_key = request.operation_id.to_string(); let workload_target = request.target.to_canonical(); let request_id = request.request_id; - match self.operations.lock().begin( + match lock_registry(&self.operations).begin( requester_uid, operation_key.clone(), fingerprint, @@ -356,33 +387,29 @@ impl HelperRegistry { LedgerBegin::Started => {} } - let connection = match self.state.lock().connections.get(&requester_uid).cloned() { + let connection = match lock_registry(&self.state).connections.get(&requester_uid).cloned() { Some(connection) => connection, None => { - self.operations - .lock() + lock_registry(&self.operations) .abort_active(requester_uid, &operation_key); return Err(HelperRegistryError::HelperUnavailable); } }; if connection.closed.load(Ordering::Acquire) { - self.operations - .lock() + lock_registry(&self.operations) .abort_active(requester_uid, &operation_key); return Err(HelperRegistryError::HelperUnavailable); } if connection.is_stale() { - self.operations - .lock() + lock_registry(&self.operations) .abort_active(requester_uid, &operation_key); return Err(HelperRegistryError::HelperStale); } let (sender, receiver) = mpsc::sync_channel(1); { - let mut pending = connection.pending.lock(); + let mut pending = lock_registry(&connection.pending); if pending.len() >= MAX_HELPER_QUEUE_DEPTH { - self.operations - .lock() + lock_registry(&self.operations) .abort_active(requester_uid, &operation_key); return Err(HelperRegistryError::QueueFull); } @@ -396,16 +423,14 @@ impl HelperRegistry { ) .is_some() { - self.operations - .lock() + lock_registry(&self.operations) .abort_active(requester_uid, &operation_key); return Err(HelperRegistryError::RequestCorrelationMismatch); } } if let Err(error) = connection.queue_outbound(DaemonToUnsafeLocalHelper::Launch(Box::new(request))) { - connection.pending.lock().remove(&request_id); - self.operations - .lock() + lock_registry(&connection.pending).remove(&request_id); + lock_registry(&self.operations) .abort_active(requester_uid, &operation_key); return Err(error); } @@ -421,35 +446,32 @@ impl HelperRegistry { // `dispatch_request_locked` down to this call, to become async first. match receiver.recv_timeout(HELPER_OPERATION_TIMEOUT) { Ok(Ok(HelperReply::Operation(result))) => { - self.operations.lock().complete( + lock_registry(&self.operations).complete( requester_uid, &operation_key, result.clone(), now_epoch_seconds(), ); - self.state - .lock() + lock_registry(&self.state) .last_failures .remove(&(requester_uid, workload_target)); Ok(result) } Ok(Ok(HelperReply::Rejected(rejected))) => { - self.operations.lock().reject( + lock_registry(&self.operations).reject( requester_uid, &operation_key, rejected.code, now_epoch_seconds(), ); - self.state - .lock() + lock_registry(&self.state) .last_failures .insert((requester_uid, workload_target), rejected.code); Err(HelperRegistryError::OperationRejected(rejected.code)) } Ok(Err(error)) => { - connection.pending.lock().remove(&request_id); - self.operations - .lock() + lock_registry(&connection.pending).remove(&request_id); + lock_registry(&self.operations) .abort_active(requester_uid, &operation_key); Err(error) } @@ -535,7 +557,7 @@ impl HelperRegistry { connection.touch(); let replaced = { - let mut state = self.state.lock(); + let mut state = lock_registry(&self.state); state.snapshots.insert(uid, snapshot.clone()); state.connections.insert(uid, Arc::clone(&connection)) }; @@ -555,8 +577,7 @@ impl HelperRegistry { "unsafe-local helper registered" ); } - self.operations - .lock() + lock_registry(&self.operations) .adopt_snapshot(uid, &snapshot, now_epoch_seconds()); let result = self.connection_loop( @@ -566,7 +587,7 @@ impl HelperRegistry { &outbound_wakeup_read, &mut receive_buffer, ); - let mut state = self.state.lock(); + let mut state = lock_registry(&self.state); if state .connections .get(&uid) @@ -638,8 +659,7 @@ impl HelperRegistry { } fn is_active_generation(&self, uid: u32, connection: &Arc) -> bool { - self.state - .lock() + lock_registry(&self.state) .connections .get(&uid) .is_some_and(|active| Arc::ptr_eq(active, connection)) @@ -670,7 +690,7 @@ let completion = complete_pending( )?; if !completion.delivered { let operation_id = result.operation_id.to_string(); - self.operations.lock().complete( + lock_registry(&self.operations).complete( uid, &operation_id, result, @@ -688,7 +708,7 @@ let completion = complete_pending( HelperReply::Rejected(rejected.clone()), )?; if !completion.delivered { - self.operations.lock().reject( + lock_registry(&self.operations).reject( uid, rejected.operation_id.as_str(), rejected.code, @@ -716,9 +736,9 @@ fn complete_pending( operation_id: &str, reply: HelperReply, ) -> Result { - let pending = connection.pending.lock().remove(&request_id); + let pending = lock_registry(&connection.pending).remove(&request_id); let Some(pending) = pending else { - let abandoned = connection.abandoned.lock().remove(&request_id); + let abandoned = lock_registry(&connection.abandoned).remove(&request_id); return match abandoned { Some(abandoned) if abandoned.operation_id == operation_id => Ok(PendingCompletion { delivered: false, @@ -1435,9 +1455,7 @@ mod tests { let registry = HelperRegistry::new(42, [uid]); let request = launch(7, "late-op", "program"); let fingerprint = launch_fingerprint(&request).unwrap(); - registry - .operations - .lock() + lock_registry(®istry.operations) .begin(uid, "late-op".to_owned(), fingerprint, 1) .unwrap(); let (socket, _peer) = seqpacket_pair(); @@ -1455,7 +1473,7 @@ mod tests { closed: AtomicBool::new(false), }; let (sender, receiver) = mpsc::sync_channel(1); - connection.pending.lock().insert( + lock_registry(&connection.pending).insert( request.request_id, PendingRequest { operation_id: request.operation_id.to_string(), @@ -1474,13 +1492,11 @@ mod tests { ) .unwrap(); assert!(matches!( - registry - .operations - .lock() + lock_registry(®istry.operations) .begin(uid, "late-op".to_owned(), fingerprint, 2), Ok(LedgerBegin::Completed(_)) )); - assert!(connection.abandoned.lock().is_empty()); + assert!(lock_registry(&connection.abandoned).is_empty()); } #[test] @@ -1644,7 +1660,7 @@ mod tests { connected_at: Instant::now(), closed: AtomicBool::new(false), }); - registry.state.lock().connections.insert(uid, connection); + lock_registry(®istry.state).connections.insert(uid, connection); let request = launch(1, "queue-op", "/bin/true"); assert_eq!( registry.dispatch_launch(uid, request.clone()), @@ -1684,7 +1700,7 @@ mod tests { d2b_contracts::workload_identity::WorkloadTarget::parse("browser.host.d2b").unwrap(); let editor = d2b_contracts::workload_identity::WorkloadTarget::parse("editor.host.d2b").unwrap(); - registry.state.lock().last_failures.insert( + lock_registry(®istry.state).last_failures.insert( (1000, browser.to_canonical()), HelperFailureCode::ProxyUnavailable, ); diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 5e393ccbf..af8914f87 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -1013,12 +1013,12 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 26472, + "line": 26622, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26869, + "line": 27019, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From cc5499e8b0bfca5f3b7ee1e97f6fd6f31fd5f9d3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:21:46 -0700 Subject: [PATCH 694/726] fix(d2bd): defer an unanswered lifecycle claim instead of refusing it The Guest lifecycle claim polled consume-cell/complete-cell under the legacy 10s KERNEL_IO_TIMEOUT against rows that declare DeadlineTier::Standard, and flattened every failure - a lost reply included - into EffectRejected, the one spelling the Device Providers read as permanent. A slow broker reply therefore became a permanent refusal the TPM device controller spun on, leaving the one-shot EphemeralProcess/swtpm-flush-tpm0 refused and its outcome wait unsatisfiable. Poll under the rows' declared DEFAULT_CONTEXT_DEADLINE_MS and keep the permanent spelling for a served refusal only, which is the claim's own answer. --- changelog.d/fix-host-preflight.md | 13 +++++++ packages/d2bd/src/composition.rs | 64 ++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/changelog.d/fix-host-preflight.md b/changelog.d/fix-host-preflight.md index 09925fe5b..8ff77da7b 100644 --- a/changelog.d/fix-host-preflight.md +++ b/changelog.d/fix-host-preflight.md @@ -17,3 +17,16 @@ The daemon now receives the broker's own verdict on those legs, ordered under the launch ticket's deadline (30 s at the call sites), whose late-launch path stops a process that outruns it. + +- The Guest lifecycle claim (`consume_lifecycle_lease`) reports an unanswered + broker as `StateUnavailable` rather than `EffectRejected`, and polls the + `consume-cell`/`complete-cell` rows under their declared + `DEFAULT_CONTEXT_DEADLINE_MS` (25 s, `LIFECYCLE_CELL_IO_TIMEOUT`) instead of + the legacy 10 s `KERNEL_IO_TIMEOUT`. A lost claim reply used to arrive as the + permanent spelling the Device Providers refuse to retry, so the TPM device + controller spun on `Effect(EffectRejected)` for the rest of the run (100 to + 855 lines in the failing `device-worker-launch` runs against none in most + passing ones) and the one-shot `EphemeralProcess/swtpm-flush-tpm0` stayed + refused, making the fixture's flush-outcome wait unsatisfiable. The served + replay refusal still carries `EffectRejected`, so a genuinely spent claim + keeps its permanent classification. diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index dcc02d2be..8d83a6308 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -37,6 +37,7 @@ use d2b_contracts_broker::broker_wire::{ BrokerCallerRole, BrokerRequest, BrokerRequestEnvelope, BrokerResponse, ChildExitKind, ChildExitStatus, ChildReapedNotification, + DEFAULT_CONTEXT_DEADLINE_MS, ExportBrokerAuditRequest, QemuMediaBootRequest as BrokerQemuMediaBootRequest, QemuMediaHotplugRequest as BrokerQemuMediaHotplugRequest, @@ -10304,6 +10305,21 @@ pub(crate) fn broker_socket_path(state: &ServerState) -> PathBuf { /// The broker kernel IO budget one legacy kernel invocation may take. pub(crate) const KERNEL_IO_TIMEOUT: Duration = Duration::from_secs(10); +/// The io budget the two lifecycle-cell claims poll the broker under. +/// +/// `consume-cell` and `complete-cell` declare the carrier's +/// `DeadlineTier::Standard`, so the claim polls for `DEFAULT_CONTEXT_DEADLINE_MS` +/// rather than the legacy 10s `KERNEL_IO_TIMEOUT`: a poll shorter than the +/// budget the row is served under abandons a claim the broker is still +/// serving. Measured 2026-09-25: a 10s poll on this leg turned a slow broker +/// reply into `EffectRejected`, the one spelling the Device Providers read as +/// permanent, and the TPM device controller then spun on it for the rest of +/// the run (`device-worker-launch` failing runs carry 100 to 855 +/// `EffectRejected` lines; most passing runs carry none), which left the +/// one-shot `EphemeralProcess/swtpm-flush-tpm0` refused and its outcome wait +/// unsatisfiable. +const LIFECYCLE_CELL_IO_TIMEOUT: Duration = Duration::from_millis(DEFAULT_CONTEXT_DEADLINE_MS); + /// The daemon-side runner lookup the U10 family seam wires: `(vm, role)` to /// the retained `(pid, start_time_ticks)` of the daemon's pidfd table. /// @@ -19057,7 +19073,7 @@ pub(crate) fn consume_lifecycle_lease( for (kernel, result_field) in [("consume-cell", "consumed"), ("complete-cell", "completed")] { let reply = envelope_invoke_kernel( &broker_socket_path(state), - KERNEL_IO_TIMEOUT, + LIFECYCLE_CELL_IO_TIMEOUT, caller_role.clone(), KernelInvocation { operation: kernel, @@ -19068,7 +19084,20 @@ pub(crate) fn consume_lifecycle_lease( chain_identities: None, }, ) - .map_err(|_| provider_effects::ProviderEffectError::EffectRejected)?; + // A served refusal is the claim's own answer - the cell machinery + // refused it, and no retry reverses a spent claim - so it keeps the + // permanent spelling. Everything else (an unanswered broker, a + // malformed reply) says nothing about the claim and keeps the + // retryable spelling the callers defer on; reporting those as + // `EffectRejected` made a merely unanswered claim permanently fatal. + .map_err(|error| match error { + KernelInvokeError::Refused { .. } => { + provider_effects::ProviderEffectError::EffectRejected + } + KernelInvokeError::Transport(_) | KernelInvokeError::Protocol(_) => { + provider_effects::ProviderEffectError::StateUnavailable + } + })?; let granted = reply .response .result @@ -27306,6 +27335,37 @@ mod broker_dispatch_tests { broker.join().expect("broker join"); } + #[test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn an_unanswered_cell_kernel_defers_instead_of_refusing() { + // The other half of the refusal contract: a broker that never + // answered says nothing about the claim, so the caller hands back + // the retryable spelling the Device Providers defer on. Returning + // `EffectRejected` here (the served replay refusal above) would read + // as permanent, and a Guest whose claim was merely unanswered would + // wedge on it. + let state = + test_state_with_broker_socket(unreachable_broker_socket_path("lease-cell-silent")); + let authorization = LifecycleAuthorization::for_test_with_guest( + "Guest/vm-a", + "11111111-1111-4111-8111-111111111111", + "22222222-2222-4222-8222-222222222222", + 4, + 9, + 7, + "lease-caller-silent", + ); + assert_eq!( + super::consume_lifecycle_lease( + &state, + &authorization, + super::provider_effects::GuestLifecycleOperation::Start, + &BrokerCallerRole::AdminUid { uid: 0 }, + ), + Err(super::provider_effects::ProviderEffectError::StateUnavailable) + ); + } + #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn the_lease_caller_applies_the_fence_before_invoking() { From 8c3c48c0c747167099ddc0c2f0caa19d16cbf9c3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:38:00 -0700 Subject: [PATCH 695/726] policy: enforce the parking_lot lock ban through resolved lock_api paths The three parking_lot lock entries named a type alias, not a definition: `parking_lot::Mutex` is `lock_api::Mutex` and `parking_lot::RwLock` is `lock_api::RwLock`, and clippy matches a configured method path against the definition a call resolves to. The `parking_lot::Mutex::lock`, `parking_lot::RwLock::read`, and `parking_lot::RwLock::write` entries therefore never matched a call site: the ban did not fire, and the blocking census read zero for every crate while real lock sites existed (the enforcement gap the audit recorded). The entries now name `lock_api::Mutex::lock`, `lock_api::RwLock::read`, and `lock_api::RwLock::write`. Their reasons say the lock is reached through the parking_lot alias, the replacements and the sanctioned per-site allow vocabulary ("synchronous path", "cfg(test) helper", the R4 worker boundary) are unchanged, and `parking_lot::Condvar::wait` stays as configured because `Condvar` is a real type rather than an alias. The census baseline moves through its own write mode. Every real parking_lot lock site in the workspace already carries a sanctioned per-site allow, so the flipped ban adds no diagnostic: the three deny rows are renamed in all 94 crates and read 0. Two other rows move: `d2b-bus`'s `std::sync::Mutex::lock` shrinks 2 -> 0 (its remaining sites were converted after the last baseline write) and `d2b-provider-device`'s `tokio::runtime::Runtime::block_on` grows 0 -> 1 for `tests/device_family.rs:179`, a test-context site the regeneration records. --- changelog.d/w7-26-parking-lot-ban-enforced.md | 24 + clippy.toml | 13 +- .../xtask/data/blocking-census-baseline.json | 568 +++++++++--------- 3 files changed, 318 insertions(+), 287 deletions(-) create mode 100644 changelog.d/w7-26-parking-lot-ban-enforced.md diff --git a/changelog.d/w7-26-parking-lot-ban-enforced.md b/changelog.d/w7-26-parking-lot-ban-enforced.md new file mode 100644 index 000000000..bd7ff68e7 --- /dev/null +++ b/changelog.d/w7-26-parking-lot-ban-enforced.md @@ -0,0 +1,24 @@ +### Changed + +- The blocking-API deny list names the parking_lot locks through the + paths they actually resolve to: `lock_api::Mutex::lock`, + `lock_api::RwLock::read`, and `lock_api::RwLock::write` replace the + former `parking_lot::*` spellings. `parking_lot::Mutex` and + `parking_lot::RwLock` are type aliases into `lock_api`, and clippy + matches a configured method path against the definition a call + resolves to, so an alias spelling never matched a call site. Reasons + and replacements are unchanged, the sanctioned per-site allow + vocabulary (`synchronous path`, `cfg(test) helper`, R4 worker + boundary) is unchanged, and `parking_lot::Condvar::wait` stays as + configured because `Condvar` is a real type, not an alias. + +### Fixed + +- The parking_lot lock ban is enforced again. The blocking census read + zero for every `parking_lot::Mutex::lock`, `parking_lot::RwLock::read` + and `parking_lot::RwLock::write` row because the configured path did + not resolve, so unsuppressed lock sites demanded no per-site allow and + the census disagreed with the manifest's recorded level. The census + now counts the locks through `lock_api`, the committed baseline + carries the renamed rows for every crate, and each of them reads zero + against it. diff --git a/clippy.toml b/clippy.toml index b29209178..d7a9b23ab 100644 --- a/clippy.toml +++ b/clippy.toml @@ -79,9 +79,16 @@ disallowed-methods = [ { path = "std::sync::Mutex::lock", reason = "Blocks the calling thread until the lock is free, and the guard it returns cannot be held across an await; use the async mutex, or the dedicated bounded-worker channel boundary (plan R4)", replacement = "tokio::sync::Mutex::lock" }, { path = "std::sync::RwLock::read", reason = "Blocks the calling thread until the read lock is free, and the guard it returns cannot be held across an await", replacement = "tokio::sync::RwLock::read" }, { path = "std::sync::RwLock::write", reason = "Blocks the calling thread until the write lock is free, and the guard it returns cannot be held across an await", replacement = "tokio::sync::RwLock::write" }, - { path = "parking_lot::Mutex::lock", reason = "Blocking lock, and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::Mutex::lock" }, - { path = "parking_lot::RwLock::read", reason = "Blocking read lock, and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::RwLock::read" }, - { path = "parking_lot::RwLock::write", reason = "Blocking write lock, and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::RwLock::write" }, + # The parking_lot lock types are aliases into `lock_api` (`parking_lot`'s + # `Mutex` is `lock_api::Mutex`, its `RwLock` is + # `lock_api::RwLock`), and a method entry configured on the + # alias text does not resolve: clippy matches the path against the + # definition the call ends up at, so the three entries below name the + # resolved `lock_api` paths. `parking_lot::Condvar` below is a real type, + # not an alias, and keeps its own name. + { path = "lock_api::Mutex::lock", reason = "Blocking lock reached through the parking_lot alias (`parking_lot::Mutex` is `lock_api::Mutex`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::Mutex::lock" }, + { path = "lock_api::RwLock::read", reason = "Blocking read lock reached through the parking_lot alias (`parking_lot::RwLock` is `lock_api::RwLock`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::RwLock::read" }, + { path = "lock_api::RwLock::write", reason = "Blocking write lock reached through the parking_lot alias (`parking_lot::RwLock` is `lock_api::RwLock`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::RwLock::write" }, # --- Condition variables --------------------------------------------- { path = "std::sync::Condvar::wait", reason = "Parks the caller until another thread notifies; on a single-threaded runtime the notifier is the parked worker itself, so the wait can never be satisfied", replacement = "arm tokio::sync::Notify before the check, then tokio::time::timeout" }, diff --git a/packages/xtask/data/blocking-census-baseline.json b/packages/xtask/data/blocking-census-baseline.json index 1ec8dd9a6..ad2ff257d 100644 --- a/packages/xtask/data/blocking-census-baseline.json +++ b/packages/xtask/data/blocking-census-baseline.json @@ -3,6 +3,9 @@ "packages/d2b": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -10,9 +13,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -70,6 +70,9 @@ "packages/d2b-audit": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -77,9 +80,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -137,6 +137,9 @@ "packages/d2b-broker": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 3, "nix::sys::socket::recv": 0, @@ -144,9 +147,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -204,6 +204,9 @@ "packages/d2b-broker-composition": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -211,9 +214,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -271,6 +271,9 @@ "packages/d2b-broker-fixture-handlers": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -278,9 +281,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -338,6 +338,9 @@ "packages/d2b-broker-fixture-syscall-surface": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -345,9 +348,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -405,6 +405,9 @@ "packages/d2b-bus": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -412,9 +415,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -455,7 +455,7 @@ "std::sync::Condvar::wait_timeout": 0, "std::sync::Condvar::wait_timeout_while": 0, "std::sync::Condvar::wait_while": 0, - "std::sync::Mutex::lock": 2, + "std::sync::Mutex::lock": 0, "std::sync::RwLock::read": 0, "std::sync::RwLock::write": 0, "std::sync::mpsc::Receiver::iter": 0, @@ -472,6 +472,9 @@ "packages/d2b-contracts": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -479,9 +482,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -539,6 +539,9 @@ "packages/d2b-contracts-broker": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -546,9 +549,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -606,6 +606,9 @@ "packages/d2b-contracts-control": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -613,9 +616,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -673,6 +673,9 @@ "packages/d2b-contracts-provider": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -680,9 +683,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -740,6 +740,9 @@ "packages/d2b-contracts-resource": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -747,9 +750,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -807,6 +807,9 @@ "packages/d2b-contracts-zone-session": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -814,9 +817,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -874,6 +874,9 @@ "packages/d2b-controller-toolkit": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -881,9 +884,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -941,6 +941,9 @@ "packages/d2b-core": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -948,9 +951,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1008,6 +1008,9 @@ "packages/d2b-core-controller": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1015,9 +1018,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1075,6 +1075,9 @@ "packages/d2b-host": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1082,9 +1085,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1142,6 +1142,9 @@ "packages/d2b-host-activation-helper": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1149,9 +1152,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1209,6 +1209,9 @@ "packages/d2b-process-conformance": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1216,9 +1219,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1276,6 +1276,9 @@ "packages/d2b-provider": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1283,9 +1286,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1343,6 +1343,9 @@ "packages/d2b-provider-activation-nixos": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1350,9 +1353,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1410,6 +1410,9 @@ "packages/d2b-provider-audio-binding": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1417,9 +1420,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1477,6 +1477,9 @@ "packages/d2b-provider-audio-pipewire": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1484,9 +1487,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1544,6 +1544,9 @@ "packages/d2b-provider-audio-service": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1551,9 +1554,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1611,6 +1611,9 @@ "packages/d2b-provider-clipboard-wayland": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1618,9 +1621,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1678,6 +1678,9 @@ "packages/d2b-provider-command": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1685,9 +1688,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1745,6 +1745,9 @@ "packages/d2b-provider-config-nixos": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1752,9 +1755,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1812,6 +1812,9 @@ "packages/d2b-provider-credential": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1819,9 +1822,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1879,6 +1879,9 @@ "packages/d2b-provider-credential-entra": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1886,9 +1889,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -1946,6 +1946,9 @@ "packages/d2b-provider-credential-managed-identity": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -1953,9 +1956,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2013,6 +2013,9 @@ "packages/d2b-provider-credential-secret-service": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2020,9 +2023,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2080,6 +2080,9 @@ "packages/d2b-provider-device": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2087,9 +2090,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2140,13 +2140,16 @@ "std::thread::JoinHandle::join": 0, "std::thread::sleep": 0, "tokio::runtime::Handle::block_on": 0, - "tokio::runtime::Runtime::block_on": 0, + "tokio::runtime::Runtime::block_on": 1, "tokio::task::block_in_place": 0, "tokio::task::spawn_blocking": 0 }, "packages/d2b-provider-device-gpu": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2154,9 +2157,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2214,6 +2214,9 @@ "packages/d2b-provider-device-security-key": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2221,9 +2224,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2281,6 +2281,9 @@ "packages/d2b-provider-device-tpm": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2288,9 +2291,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2348,6 +2348,9 @@ "packages/d2b-provider-device-usbip": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2355,9 +2358,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2415,6 +2415,9 @@ "packages/d2b-provider-display-wayland": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2422,9 +2425,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2482,6 +2482,9 @@ "packages/d2b-provider-emergency-policy": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2489,9 +2492,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2549,6 +2549,9 @@ "packages/d2b-provider-endpoint": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2556,9 +2559,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2616,6 +2616,9 @@ "packages/d2b-provider-guest": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2623,9 +2626,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2683,6 +2683,9 @@ "packages/d2b-provider-guest-azure-container-apps": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2690,9 +2693,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2750,6 +2750,9 @@ "packages/d2b-provider-guest-azure-virtual-machine": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2757,9 +2760,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2817,6 +2817,9 @@ "packages/d2b-provider-guest-cloud-hypervisor": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2824,9 +2827,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2884,6 +2884,9 @@ "packages/d2b-provider-guest-qemu-media": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2891,9 +2894,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -2951,6 +2951,9 @@ "packages/d2b-provider-host": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -2958,9 +2961,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3018,6 +3018,9 @@ "packages/d2b-provider-network-local": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3025,9 +3028,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3085,6 +3085,9 @@ "packages/d2b-provider-notification-desktop": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3092,9 +3095,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3152,6 +3152,9 @@ "packages/d2b-provider-observability-otel": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3159,9 +3162,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3219,6 +3219,9 @@ "packages/d2b-provider-operation": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3226,9 +3229,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3286,6 +3286,9 @@ "packages/d2b-provider-process": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3293,9 +3296,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3353,6 +3353,9 @@ "packages/d2b-provider-process-minijail": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3360,9 +3363,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3420,6 +3420,9 @@ "packages/d2b-provider-process-systemd": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3427,9 +3430,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3487,6 +3487,9 @@ "packages/d2b-provider-provider": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3494,9 +3497,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3554,6 +3554,9 @@ "packages/d2b-provider-quota": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3561,9 +3564,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3621,6 +3621,9 @@ "packages/d2b-provider-resource-export": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3628,9 +3631,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3688,6 +3688,9 @@ "packages/d2b-provider-resource-import": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3695,9 +3698,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3755,6 +3755,9 @@ "packages/d2b-provider-role": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3762,9 +3765,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3822,6 +3822,9 @@ "packages/d2b-provider-role-binding": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3829,9 +3832,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3889,6 +3889,9 @@ "packages/d2b-provider-seccomp-profile": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3896,9 +3899,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -3956,6 +3956,9 @@ "packages/d2b-provider-shell-pool": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -3963,9 +3966,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4023,6 +4023,9 @@ "packages/d2b-provider-shell-session": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4030,9 +4033,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4090,6 +4090,9 @@ "packages/d2b-provider-shell-terminal": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4097,9 +4100,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4157,6 +4157,9 @@ "packages/d2b-provider-supervisor": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4164,9 +4167,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4224,6 +4224,9 @@ "packages/d2b-provider-system-core": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4231,9 +4234,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4291,6 +4291,9 @@ "packages/d2b-provider-telemetry-binding": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4298,9 +4301,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4358,6 +4358,9 @@ "packages/d2b-provider-telemetry-service": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4365,9 +4368,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4425,6 +4425,9 @@ "packages/d2b-provider-test-controller": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4432,9 +4435,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4492,6 +4492,9 @@ "packages/d2b-provider-toolkit": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4499,9 +4502,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4559,6 +4559,9 @@ "packages/d2b-provider-transport-azure-relay": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4566,9 +4569,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4626,6 +4626,9 @@ "packages/d2b-provider-transport-unix": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4633,9 +4636,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4693,6 +4693,9 @@ "packages/d2b-provider-transport-vsock": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4700,9 +4703,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4760,6 +4760,9 @@ "packages/d2b-provider-user": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4767,9 +4770,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4827,6 +4827,9 @@ "packages/d2b-provider-volume": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4834,9 +4837,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4894,6 +4894,9 @@ "packages/d2b-provider-volume-binding": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4901,9 +4904,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -4961,6 +4961,9 @@ "packages/d2b-provider-volume-local": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -4968,9 +4971,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5028,6 +5028,9 @@ "packages/d2b-provider-volume-virtiofs": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5035,9 +5038,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5095,6 +5095,9 @@ "packages/d2b-provider-wayland-policy": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5102,9 +5105,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5162,6 +5162,9 @@ "packages/d2b-provider-wayland-session": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5169,9 +5172,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5229,6 +5229,9 @@ "packages/d2b-provider-zone": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5236,9 +5239,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5296,6 +5296,9 @@ "packages/d2b-provider-zone-link": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5303,9 +5306,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5363,6 +5363,9 @@ "packages/d2b-resource-api": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5370,9 +5373,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5430,6 +5430,9 @@ "packages/d2b-resource-client": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5437,9 +5440,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5497,6 +5497,9 @@ "packages/d2b-resource-compiler": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5504,9 +5507,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5564,6 +5564,9 @@ "packages/d2b-resource-runtime": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5571,9 +5574,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5631,6 +5631,9 @@ "packages/d2b-resource-types": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5638,9 +5641,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5698,6 +5698,9 @@ "packages/d2b-session": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5705,9 +5708,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5765,6 +5765,9 @@ "packages/d2b-session-unix": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5772,9 +5775,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5832,6 +5832,9 @@ "packages/d2b-sk-frontend": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5839,9 +5842,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5899,6 +5899,9 @@ "packages/d2b-telemetry": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5906,9 +5909,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -5966,6 +5966,9 @@ "packages/d2b-unsafe-local-helper": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -5973,9 +5976,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -6033,6 +6033,9 @@ "packages/d2b-zone-routing": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -6040,9 +6043,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -6100,6 +6100,9 @@ "packages/d2bd": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -6107,9 +6110,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 4, "std::fs::File::sync_all": 0, @@ -6167,6 +6167,9 @@ "packages/d2bd-runtime": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -6174,9 +6177,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, @@ -6234,6 +6234,9 @@ "packages/xtask": { "d2bd_runtime::runtime_util::block_on_future": 0, "d2bd_runtime::runtime_util::block_on_future_with": 0, + "lock_api::Mutex::lock": 0, + "lock_api::RwLock::read": 0, + "lock_api::RwLock::write": 0, "nix::sys::socket::accept4": 0, "nix::sys::socket::connect": 0, "nix::sys::socket::recv": 0, @@ -6241,9 +6244,6 @@ "nix::sys::socket::send": 0, "nix::sys::socket::sendmsg": 0, "parking_lot::Condvar::wait": 0, - "parking_lot::Mutex::lock": 0, - "parking_lot::RwLock::read": 0, - "parking_lot::RwLock::write": 0, "std::fs::File::create": 0, "std::fs::File::open": 0, "std::fs::File::sync_all": 0, From eff7cbb3d44e043afbaf3f040d5c3ec16806d4c0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:42:24 -0700 Subject: [PATCH 696/726] fix(d2b-broker): drop the shared prefix from the storage refusal variants --- .../w7-30-broker-refusal-variant-names.md | 6 ++ .../d2b-broker/src/ops/storage_contract.rs | 80 +++++++++---------- 2 files changed, 46 insertions(+), 40 deletions(-) create mode 100644 changelog.d/w7-30-broker-refusal-variant-names.md diff --git a/changelog.d/w7-30-broker-refusal-variant-names.md b/changelog.d/w7-30-broker-refusal-variant-names.md new file mode 100644 index 000000000..a58895c24 --- /dev/null +++ b/changelog.d/w7-30-broker-refusal-variant-names.md @@ -0,0 +1,6 @@ +### Fixed + +- The broker storage-contract refusal enum no longer trips the shared-prefix + clippy style check: its variants drop the `Storage` prefix while the + operator-visible refusal slugs are unchanged (`Display` still renders the + same `storage-...` text every audit surface carries). diff --git a/packages/d2b-broker/src/ops/storage_contract.rs b/packages/d2b-broker/src/ops/storage_contract.rs index c350e2481..a31e6c4f3 100644 --- a/packages/d2b-broker/src/ops/storage_contract.rs +++ b/packages/d2b-broker/src/ops/storage_contract.rs @@ -39,47 +39,47 @@ pub enum StorageContractError { /// text. The variants are not serialized; [`Display`](std::fmt::Display) /// renders the slug the operator/audit surface already carries, and the one /// host-detail failure -/// ([`StoragePathCanonicalizeFailed`](Self::StoragePathCanonicalizeFailed)) +/// ([`PathCanonicalizeFailed`](Self::PathCanonicalizeFailed)) /// renders its fixed slug with the detail appended after a `:`. #[derive(Debug, Clone, PartialEq, Eq)] pub enum RefusalReason { /// `--apply` on an unexpanded template path the broker would mutate. - StorageCriticalTemplateUnexpanded, + CriticalTemplateUnexpanded, /// `--apply` under `/etc/d2b`, which Nix owns and the broker only checks. - StorageConfigRootIsNixManaged, + ConfigRootIsNixManaged, /// `--apply` on a storage row whose kind is not a directory. - StorageApplySupportedForDirectoryOnly, + ApplySupportedForDirectoryOnly, /// A path carrying a `..` component. - StoragePathParentDirRefused, + PathParentDirRefused, /// A path outside every broker-owned root. - StoragePathOutsideOwnedRoots, + PathOutsideOwnedRoots, /// A path whose canonical form escapes its owned root. - StoragePathEscapesOwnedRoot, + PathEscapesOwnedRoot, /// Canonicalization reached a path component with no leaf name. - StoragePathHasNoLeaf, + PathHasNoLeaf, /// Canonicalization reached a path component with no parent. - StoragePathHasNoParent, + PathHasNoParent, /// Canonicalizing a path failed for a reason other than `NotFound`; /// carries the host error detail. - StoragePathCanonicalizeFailed(String), + PathCanonicalizeFailed(String), } impl RefusalReason { /// The fixed refusal slug. `Display` appends the carried detail of - /// [`Self::StoragePathCanonicalizeFailed`]. + /// [`Self::PathCanonicalizeFailed`]. pub const fn as_str(&self) -> &'static str { match self { - Self::StorageCriticalTemplateUnexpanded => "storage-critical-template-unexpanded", - Self::StorageConfigRootIsNixManaged => "storage-config-root-is-nix-managed", - Self::StorageApplySupportedForDirectoryOnly => { + Self::CriticalTemplateUnexpanded => "storage-critical-template-unexpanded", + Self::ConfigRootIsNixManaged => "storage-config-root-is-nix-managed", + Self::ApplySupportedForDirectoryOnly => { "storage-apply-supported-for-directory-only" } - Self::StoragePathParentDirRefused => "storage-path-parent-dir-refused", - Self::StoragePathOutsideOwnedRoots => "storage-path-outside-owned-roots", - Self::StoragePathEscapesOwnedRoot => "storage-path-escapes-owned-root", - Self::StoragePathHasNoLeaf => "storage-path-has-no-leaf", - Self::StoragePathHasNoParent => "storage-path-has-no-parent", - Self::StoragePathCanonicalizeFailed(_) => "storage-path-canonicalize-failed", + Self::PathParentDirRefused => "storage-path-parent-dir-refused", + Self::PathOutsideOwnedRoots => "storage-path-outside-owned-roots", + Self::PathEscapesOwnedRoot => "storage-path-escapes-owned-root", + Self::PathHasNoLeaf => "storage-path-has-no-leaf", + Self::PathHasNoParent => "storage-path-has-no-parent", + Self::PathCanonicalizeFailed(_) => "storage-path-canonicalize-failed", } } } @@ -87,7 +87,7 @@ impl RefusalReason { impl std::fmt::Display for RefusalReason { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::StoragePathCanonicalizeFailed(detail) => { + Self::PathCanonicalizeFailed(detail) => { write!(f, "{}:{detail}", self.as_str()) } fixed => f.write_str(fixed.as_str()), @@ -125,7 +125,7 @@ pub async fn reconcile_storage_scope( if apply && path.starts_with("/etc/d2b") { return Err(StorageContractError::Refused { subject: storage_ref.as_str().to_owned(), - reason: RefusalReason::StorageCriticalTemplateUnexpanded, + reason: RefusalReason::CriticalTemplateUnexpanded, }); } return Ok(ReconcileStorageScopeResponse { @@ -152,7 +152,7 @@ pub async fn reconcile_storage_scope( if apply && apply_is_check_only(&path_buf) { return Err(StorageContractError::Refused { subject: storage_ref.as_str().to_owned(), - reason: RefusalReason::StorageConfigRootIsNixManaged, + reason: RefusalReason::ConfigRootIsNixManaged, }); } match spec.kind { @@ -205,7 +205,7 @@ pub async fn reconcile_storage_scope( } _ if apply => Err(StorageContractError::Refused { subject: storage_ref.as_str().to_owned(), - reason: RefusalReason::StorageApplySupportedForDirectoryOnly, + reason: RefusalReason::ApplySupportedForDirectoryOnly, }), _ => Ok(ReconcileStorageScopeResponse { storage_ref: storage_ref.clone(), @@ -268,7 +268,7 @@ async fn validate_owned_root_against( { return Err(StorageContractError::Refused { subject: subject.to_owned(), - reason: RefusalReason::StoragePathParentDirRefused, + reason: RefusalReason::PathParentDirRefused, }); } let root = roots @@ -277,14 +277,14 @@ async fn validate_owned_root_against( .find(|root| path.starts_with(root)) .ok_or_else(|| StorageContractError::Refused { subject: subject.to_owned(), - reason: RefusalReason::StoragePathOutsideOwnedRoots, + reason: RefusalReason::PathOutsideOwnedRoots, })?; let canonical_root = canonicalize_existing_or_nearest_ancestor(root, subject).await?; let canonical_target = canonicalize_existing_or_nearest_ancestor(path, subject).await?; if !canonical_target.starts_with(&canonical_root) { return Err(StorageContractError::Refused { subject: subject.to_owned(), - reason: RefusalReason::StoragePathEscapesOwnedRoot, + reason: RefusalReason::PathEscapesOwnedRoot, }); } Ok(()) @@ -310,20 +310,20 @@ async fn canonicalize_existing_or_nearest_ancestor( .file_name() .ok_or_else(|| StorageContractError::Refused { subject: subject.to_owned(), - reason: RefusalReason::StoragePathHasNoLeaf, + reason: RefusalReason::PathHasNoLeaf, })?; missing_suffix.push(leaf.to_os_string()); current = current .parent() .ok_or_else(|| StorageContractError::Refused { subject: subject.to_owned(), - reason: RefusalReason::StoragePathHasNoParent, + reason: RefusalReason::PathHasNoParent, })?; } Err(err) => { return Err(StorageContractError::Refused { subject: subject.to_owned(), - reason: RefusalReason::StoragePathCanonicalizeFailed(err.to_string()), + reason: RefusalReason::PathCanonicalizeFailed(err.to_string()), }); } } @@ -446,15 +446,15 @@ mod tests { assert!(validate_owned_root(Path::new("/run/d2b"), "x").await.is_ok()); assert_refused_reason( validate_owned_root(Path::new("/var/lib/d2b/../../etc/malicious"), "x").await, - RefusalReason::StoragePathParentDirRefused, + RefusalReason::PathParentDirRefused, ); assert_refused_reason( validate_owned_root(Path::new("/var/lib/d2b/../d2b-escape"), "x").await, - RefusalReason::StoragePathParentDirRefused, + RefusalReason::PathParentDirRefused, ); assert_refused_reason( validate_owned_root(Path::new("/home/not-d2b"), "x").await, - RefusalReason::StoragePathOutsideOwnedRoots, + RefusalReason::PathOutsideOwnedRoots, ); } @@ -469,7 +469,7 @@ mod tests { std::os::unix::fs::symlink("/etc", root.join("escape")).unwrap(); assert_refused_reason( validate_owned_root_against(&root.join("escape/passwd"), "x", &[&root]).await, - RefusalReason::StoragePathEscapesOwnedRoot, + RefusalReason::PathEscapesOwnedRoot, ); } } @@ -496,7 +496,7 @@ mod tests { .expect_err("regular files are check-only in broker reconcile"); assert_refused_reason( Err(err), - RefusalReason::StorageApplySupportedForDirectoryOnly, + RefusalReason::ApplySupportedForDirectoryOnly, ); } @@ -531,7 +531,7 @@ mod tests { let err = reconcile_storage_scope(&resolver, &BundleOpId::new("path:config-root"), true) .await .expect_err("nix-managed config roots are not broker-mutated"); - assert_refused_reason(Err(err), RefusalReason::StorageConfigRootIsNixManaged); + assert_refused_reason(Err(err), RefusalReason::ConfigRootIsNixManaged); } #[tokio::test] @@ -608,27 +608,27 @@ mod tests { fn refused_display_keeps_the_wire_text() { let fixed = StorageContractError::Refused { subject: "path:run-root".to_owned(), - reason: RefusalReason::StoragePathParentDirRefused, + reason: RefusalReason::PathParentDirRefused, }; assert_eq!( fixed.to_string(), "path:run-root: refused: storage-path-parent-dir-refused" ); assert_eq!( - RefusalReason::StoragePathParentDirRefused.as_str(), + RefusalReason::PathParentDirRefused.as_str(), "storage-path-parent-dir-refused" ); let detailed = StorageContractError::Refused { subject: "path:run-root".to_owned(), - reason: RefusalReason::StoragePathCanonicalizeFailed("EACCES".to_owned()), + reason: RefusalReason::PathCanonicalizeFailed("EACCES".to_owned()), }; assert_eq!( detailed.to_string(), "path:run-root: refused: storage-path-canonicalize-failed:EACCES" ); assert_eq!( - RefusalReason::StoragePathCanonicalizeFailed(String::new()).as_str(), + RefusalReason::PathCanonicalizeFailed(String::new()).as_str(), "storage-path-canonicalize-failed" ); } From f8799edd53871629fabc7e0f172e4260f137cd38 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:43:26 -0700 Subject: [PATCH 697/726] audit: fold the wave-7 ledger outcomes and point the wave row at the integration head --- .../2026-09-24-rust-skills-audit/ledger.md | 111 +++++++++--------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 7d7552adb..bcb841b7c 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -44,6 +44,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | | W5 | `25b2474f4` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step, not this wave's. | | W6 | `4e47723a1` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Three close repairs: the pre-existing `clone_on_copy` re-linted in `d2b-core/src/privileges.rs`, the stale family-knowledge exemption in `xtask/src/provider_crate_policy.rs`, and the async-gate hatch inventory re-recorded for ten moved marker sites (4e47723a1: four in `d2b-broker/src/runtime.rs` moved with the w6-12 merge, six in `d2bd` were already stale on the handed-over head, so that red was waiting on a head no preflight had measured). The four clipped reason cells were repaired and marked [reconstructed]. The head cell names the code head 4e47723a1 that the five preflight commands measured (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake); this row ships in ledger-only commits on top of it. | +| W7 | `eff7cbb3d` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 48 rows disposed - see the wave-7 close artifact (.scratch/wave7-close.md) for the per-row evidence, the verified anchors, and the co-change lists. | ## Findings (965 rows) @@ -144,7 +145,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | | `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's literal snippet is missing parentheses; the chain shape used is names.difference(...).map(...).chain(declared_names.difference(...).map(...)).collect() preserving bin= then manifest= order | | | `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | derive Default on three unit structs; new() const kept | | -| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | declined | U2 | | `target.rs` | sort_by_key and sort_by_cached_key both rejected by rustc 1.97 (lifetime may not live long enough; closure returns (&str,&str,&str) borrowing the element); kept sort_by | | +| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | 7 | 1fb8eff80 | `packages/d2b-resource-runtime/src/target.rs:737` | both listings sort through one owned identity key with sort_by_cached_key (the borrowed-key forms are lifetime errors); ordering unchanged and the key is cloned once per element instead of twice per comparison. Merged 6f1390556. | | | `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | shared free manager_rpc transport; both endpoints route through it | | | `RS-0098` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | derive Default on TargetDirectory | | | `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | impl FromStr for ResourceProvenance; store parses via str::parse | | @@ -213,7 +214,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs` | the type must propagate to the two child handlers (DmabufFeedbackHandler, DmabufBufferParamsHandler) and five test constructions, which clone the same filters value; sync::Arc import removed from dmab | | | `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied-variant | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/driver.rs` | Applied the row's sort_by comparator, fixing its misplaced-paren typo (teardown_rank().cmp().then_with(name cmp)); drops the per-row name clone. | | | `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/effects_service.rs` | Both ACA candidate lists use state.sandbox.iter().cloned().collect() (and disk_image) instead of clone().into_iter().collect(). | | -| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | declined | U2 | | `src/controller.rs:156-157` | Cannot land as written: BTreeMap::remove(&mut self, &Q) cannot take a key borrowed from the same map (E0502, verified by cargo check); zero-clone claim refuted. Original eviction restored unchanged. | | +| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | 7 | 7b480f35d | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs:152` | eviction computes the minimum record sequence once (a Copy u64; sequences are unique because next_sequence increments per insert) and removes exactly that entry with a single retain, so no AcaOperationId clone remains; the Borrow shape was rejected because it still needs an owned key out of the map borrow. A new test pins oldest-first eviction. Merged 39411da5e. | | | `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | reconcile_observed extracts Copy lifecycle first, moves record into self.observed without clone, matches on the extracted lifecycle. Applied with RS-0166 as one considered change per packet. | | | `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | record.id moved out of the stored record via take().expect(...).id, resolving the partial-move vs whole-record-store conflict. Deviation: on resume failure observed is None (was Some(record)). | | | `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 9730af073 | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | Stop and delete stages clone only the sandbox id (observed.as_ref().ok_or(...)?.id.clone()) and move it into the closures; the delete-stage Stopping check reads observed.as_ref().is_some_and(..). | | @@ -259,10 +260,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | insert_new takes StoredDesiredResource by value; ensure passes by move | | | `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 0e6061c1e | `resource.rs` | pre_start moves row into state; clones only for ResourceContext::new | | | `RS-0210` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | list binds borrowed selector str forms | | -| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | declined | U2 | | `metadata.rs` | ctx.spec::() returns Result<&Value,_>; Ok(spec) is E0308; the clone is required by the API | | +| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | 7 | 7b480f35d | `packages/d2b-resource-runtime/src/metadata.rs:167` | the fence now validates in place and returns Result<(), DriverFailure>; the sole caller discards the value, so the clone is deleted rather than moved; decode and shape refusals stay byte-identical. Merged 39411da5e. | | | `RS-0211` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 1f9423d9a | `target.rs` | assign moves assignment into map and clones once for return | | | `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | json_object moves member values; 17 call sites updated | | -| `RS-0213` | `own` | `d2b-session` | low | actionable | family | | | | `engine.rs:689, admission.rs:593` | | | +| `RS-0213` | `own` | `d2b-session` | low | actionable | family | applied | 7 | 1fb8eff80 | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:1209` | the borrow-based From impl landed earlier in a2cf0e614; this wave deleted the now-unused by-value impl and moved the three owned test sites to borrows. Merged 6f1390556. | | | `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | applied | U2 | 0b8ef8ff5 | `packages/d2b-sk-frontend/src/main.rs` | main destructures Config and calls placement.into_placement() (no clone); config builds "/dev/uhid" via PathBuf::from. | | | `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | applied-variant | U2 | 6a3cf6cff | `packages/d2b-zone-routing/src/engine.rs` | Zone pair moved into the snapshot after destructuring expected; validate_snapshot checks inlined (row's first option) and gated #[cfg(test)] since consume no longer calls it | | | `RS-0221` | `own` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 9441488c0 | `packages/d2bd/src/interaction_composition.rs` | supervisor clone removed as row intended; adoption_ticket clone KEPT because process_ticket used after run_effect (self.tickets.insert); closure uses &adoption_ticket - row's remove-both not implement | | @@ -279,7 +280,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | Borrow implemented; five map lookups/removes resolve without String alloc | | | `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/daemon_audit.rs` | write_event* and enqueue take DaemonEvent by value, drop clone; caller migration in d2bd/src/composition.rs left to W1Daemon/orchestrator (cross-crate} | | | `RS-0231` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | check_members takes &[WorkspaceMember]; caller clones dropped; second caller borrows result | | -| `RS-0236` | `own` | `xtask` | low | actionable | leaf | declined | U2 | | `production_closure.rs` | compute_* take ContextSpec by value today; ComputedContext struct owns spec; changing to &ContextSpec forces internal clones at the struct literals (= no net clone removal; E0308 evidence); reverted | | +| `RS-0236` | `own` | `xtask` | low | actionable | leaf | applied | 7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:425` | ComputedContext<'a> borrows its spec, so both caller clones are deleted without adding callee clones; the declared &ContextSpec shape would have been a 2-for-2 swap. Output byte-identical (gen-package-policy-inputs --check green). Merged 83578063f. | | | `RS-0238` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 16e0b183d | `packages/xtask/src/blocking_census.rs` | CensusBaseline built by consuming each CrateCensus instead of cloning crate_dir/counts; --baseline check driven from the written map via a shared helper. Check passes; 18 census tests pass. | | | `RS-0232` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | family-knowledge exempt set keys &str pairs; probe via as_str | | | `RS-0237` | `own` | `xtask` | low | actionable | leaf | applied | U2 | be3e0744b | `production_closure.rs` | duplicate approval clone binding removed; single clone at with_approval call | | @@ -297,8 +298,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | | `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | applied | W5 | 6b9187e44 | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | EvidenceChain deserializes through an admission gate that rejects an empty identities list, so depth() cannot underflow and the identity accessors cannot panic; the wire shape is unchanged | | | `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | already-fixed | U3 | | `packages/d2b-broker/src/ops/media.rs:889-892` | Re-verified at HEAD: QmpAttachCleanup already models its four-step rollback as an ordered typed step list (steps: Vec with QmpAttachStep enum, media.rs:889-892), not four bools. Already | | -| `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_co` | | | -| `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | | | | `packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362` | | | +| `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | 7 | 5c95bf879 | `packages/d2b-broker/src/ops/storage_contract.rs:27` | Refused.reason is the closed RefusalReason enum (8 fixed slugs plus a canonicalize-failure variant carrying the io error); Display keeps the exact wire text the runtime forwards. Merged 6dc80e258. | | +| `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | 7 | 5c95bf879 | `packages/d2b-broker/src/live_handlers.rs:291` | reloadBehavior parses to a closed NmReloadBehavior (atomic-reload, none, empty-string sentinel) in d2b-core; the broker validator and its typo-refusal error were deleted, both branch sites and the kernel payload parse are typed, and the v2 host schema moved with the generator. Merged 6dc80e258. | | | `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 7a5a7f957,4e20f7674 | packages/d2b-bus/src/session/zone_link.rs | folded admission+liveness into private EstablishedLane; test lane keeps None; all three gate sites migrated; follow-up commit reattaches the doc to ZoneLinkSession | | | `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | ResourceQuery assignment/scope Option pair folded into one Option<(AssignmentIdentity, ScopedResourceScope)>; pub assignment()/scope() accessors keep signatures via const match; validate_scoped now on | | | `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | @@ -310,9 +311,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | | `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | applied | W5 | fa8706320 | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | ComponentDescriptor::new no longer takes declares_state_volume: the parameter could only ever be false (true returned MissingRequiredField), so the illegal state is not expressible and every call site drops the argument; the wire-only declaresStateVolume field and its consistency check against stateNamespaces stay in the Deserialize path | | | `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | -| `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-res` | | | +| `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied | 7 | 1af47c8cf | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:284` | observed_generation is the crate's transparent ObservedGeneration (wire bytes unchanged); the two hand-committed activation-nixos schemas moved with it. Merged ab038d388. | | | `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | -| `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | | | | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-r` | | | +| `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied-variant | 7 | 1af47c8cf + e14ea9c02 | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:47` | target_generation is the existing nonzero ConfigurationGeneration newtype (serde-transparent u64, JsonSchema minimum 1): nonzero_u64_schema, ActivationRunnerInputError and the zero check are deleted, new() is infallible, the now-unreachable zero guards in process-conformance and provider-process are gone, and the EphemeralProcess schema was regenerated. The first landing used a new NixosGenerationOrdinal newtype, which the layout gate refused as shared-crate family vocabulary; the follow-up slice switched to the row's own prescribed ConfigurationGeneration. Merged ab038d388 + 6abcf5cac. | | | `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises - `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | | `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | packages/d2b-provider-transport-azure-relay/contrast-zone-session/src/v3/role_binding.rs | | | | `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | 4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | @@ -323,9 +324,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | 87e8d7654 | packages/d2b-provider-audio-pipewire/src/resource_type.rs | owner()/new() now infallible; validate_audio_* remain the single admission gate (they also check provider_ref/extension/zone the ctors cannot). All call sites updated; check+test+clippy green on 4 cra | | | `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | Shared-vs-owned controller mode carried in the type; mixer speaker path split into grant/revoke so the return contract stops being argument-dependent. Suite 94/94. | | | `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 4404afb72 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Merged picker (args.picker.or(config)) validated once after merge; relative paths rejected from either source. | | -| `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider` | | | -| `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipb` | | | -| `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard` | | | +| `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 6a6a62f2f | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13` | the two boolean fields are gone - ClipboardRunnerContract carries only service_package and repair_interval_secs, and the former flags survive as const-true accessors with two in-repo test consumers; re-verified at 6dc80e258. | | +| `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | d59bb44a3 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:250` | the pipe-joined completion key is a typed CompletionKey struct built by CompletionKey::new and consumed by ClipboardHistory (BTreeMap keys plus purge); no join/split on the separator remains anywhere in the crate, and the literal-key test builds the struct instead of a string; re-verified at 6dc80e258. | | +| `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 5dfe92ec1 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:143` | entry digests are EntryDigest, parsed once at the single construction point (EntryDigest::parse) and carried by PickerReceipt; the receipt-boundary starts_with check the row described no longer exists; re-verified at 6dc80e258. | | | `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/service.rs | Request fields sealed to pub(crate); ConfigSyncRequest::new now calls validate_guest_ref, closing the Guest/ drift; serde derive keeps wire JSON unchanged. | | | `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | applied-variant | U3 | 1ce473a70 | packages/d2b-provider-credential/src/driver.rs | zone: String -> d2b_contracts_resource::v3::ZoneId in CredentialDriverArgs and CredentialDriver; agent_child builds the zone ref with expect on a validated ZoneId (fallible ResourceRef::parse path dro | | | `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | applied | U3 | cd8838c03 | packages/d2b-provider-credential-managed-identity/src/controller.rs | seal `ManagedIdentityTeardownPlan`'s three bool fields behind `pub const fn` accessors so invalid combos (stop_agent && delete_agent, delete_agent && clear_provider_revoke) are unrepresentable; tests | | @@ -336,11 +337,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired - the illegal Consumed/Expired-with-Some(psk) combination is now unco | | | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | e53601c88 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | derive_private_runtime_scope and private_runtime_scope take ChildRole and use role.suffix(); the &str whitelist branch is gone. Callers incl. wayland-policy migrated. | | -| `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | | | | `config.rs:20, config.rs:53` | | | +| `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | applied | 7 | 2ca9a22dd | `packages/d2b-provider-guest-cloud-hypervisor/src/config.rs:20` | default_machine_type is the closed MachineType enum (the closed q35/microvm pair) and the unreachable validate arm is deleted; root-config.schema.json carries the enum and the committed provider-manifest.json digest moved with the schema bytes. Leftover: the committed provider-manifest.json.sig no longer verifies (publisher private key is not in-tree; nix/provider-artifact.nix:135 checks only the 64-byte length and the host-integration lanes re-sign with their own derived key). Merged bdb26e6ef. | | | `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | f1404725d | packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs | vmm_readiness/vmm_lifecycle now take one VmmReadinessSnapshot struct (five named facts, all_ready()); controller readiness() builds it from GuestDependencySnapshot accessors; tests updated. check/test | | | `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | 82f8cac47 | packages/d2b-provider-guest-qemu-media/src/config.rs | 7 gate calls now use BoundedToken::parse(...) .is_err(); local validate_token helper and its pub(crate) re-export deleted; qmp validate_object_id delegates to BoundedToken::parse. Deviation: validate_ | | | `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | b845000ff | packages/d2b-provider-guest-qemu-media/src/config.rs | impl Default for ProviderConfig deleted (it manufactured a config that fails its own validate());the sole consumer test now builds valid-then-mutated configs (controller_execution_ref swapped to a Gue | | -| `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-` | | | +| `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | applied | 7 | 21a7af424 | `packages/d2b-provider-notification-desktop/src/controller.rs:22` | the two hardcoded-true booleans are one typed NotificationCutoverState::ServiceOnly, and both accessors are derived matches! reads so every caller (both tests) compiles unchanged; the refusal ledger row cited only the daemon composition test, so no ADR amendment was needed. Merged 3668d3a6e. | | | `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/agent.rs | ProviderAgentAuditEvent stores parsed BoundedToken values; Serialize renders via as_str(); parse-then-copy-back removed, wire output unchanged. | | | `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U3 | 9fbe75ec2 | packages/d2b-provider-process-minijail/src/launch.rs | validate_launch_ticket renamed to validate_platform_gate and reduced to the gate check (identity checks live only in MinijailProcessProvider::validate); lib.rs:160 literal replaced with crate::PROVIDE | | | `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | @@ -359,7 +360,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0302` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | ShutdownDegradedMarker now stores VmShutdownOutcome enum (derive Serialize/Deserialize, rename_all snake_case) instead of String outcome/severity; construction site passes the enum. Report shape uncha | | | `RS-0300` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ZoneResourceRuntime gate trio (policy_installed/controller_endpoint_registered/watch_admitted) replaced by PlanePublicationStage { BootstrapOnly, Published } set at open and activate_published_bundle; | | | `RS-0301` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ControllerSession teardown trio (ingress_revoked/assignments_revoked/transport_closed) replaced by a TeardownStage enum advanced monotonically (Active -> IngressRevoked -> AssignmentsRevoked -> Transp | | -| `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d` | | | +| `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | applied-variant | 7 | 369627b78 | `packages/d2bd/src/composition.rs:20375` | mode is HostActivationMarkerMode rendering the four documented verbs, with a serde(other) Unknown catch-all so an unknown out-of-tree mode still parses (the catch-all is named Unknown so its serde label and Display agree; the finding suggested no name); the marker log keeps a recognized label via Display. Merged a74fd9b0c. | | | `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | 7e0ec2bce | packages/d2bd-runtime/src/admission.rs | peer admission lookup mode modelled self-describing; check + admission tests green (worker reported the oid as already present after committing its own change; the commit is this branch's) | | | `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W5 | 6dabfe132 | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | DaemonEvent::ApiReadyTimeout.mode is a closed ApiReadyMode enum (Strict / NoWaitApi) with kebab-case serde, so an invalid mode string is rejected on deserialize; the JSONL shape is unchanged | | | `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | 4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | @@ -368,7 +369,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | | `RS-0314` | `type` | `xtask` | medium | actionable | leaf | applied | U3 | 0b767225a | packages/xtask/src/inventory.rs | Deleted the private copy and both call sites plus the test now use crate::delivery::model::validate_repo_relative_path(Path::new(...)); stricter empty check retained. | | | `RS-0313` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 1d692db3d | packages/xtask/src/provider_crate_policy.rs | FamilyKnowledgeSignal gains typed count: Option; ServerState site fills it and drops the serialized-count text; renderer matches class without the parse;the ratchet JSON stays byte-identical (t | | -| `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | | | | `packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660` | | | +| `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | applied | 7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:107` | EdgeRecord.kind is a closed EdgeKind with the wire spelling preserved (proc-macro); a hand-written Ord keeps the historical string order so every committed policy-inputs closure stays byte-identical (write-mode regeneration changed nothing). Merged 83578063f. | | | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option pub(crate) for all 19 gpu.rs items and 7 modprobe.rs items (types, impl methods, free fns, trait). Chose item-level over module-decl narrowing so d2b-core bundle_resolver.rs:4300 and | | -| `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | | | | `src/lib.rs:45, src/ops/mod.rs:20-94` | | | +| `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | applied | 7 | 5a0110bb9 | `packages/d2b-broker/src/ops/mod.rs:20` | 28 of the 31 handler arms are now pub(crate); pidfd, network and audit_op stay pub because five in-crate integration-test crates import them by path. The census (which arms stay public and why) is recorded next to pub mod ops in lib.rs so a new arm cannot silently reopen the surface. Merged 0365535b1. | | | `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | applied | 6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | Dropped the unused _daemon_uid parameter from pub fn acquire_lock; all 12 census call sites plus 9 in-file test sites and the dead daemon_uid forwarding param on live_usbip_bind (6 callers) updated; broker-internal signature, no doc or fixture pins it. | | | `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | 068ddcfc4 | packages/d2b-broker/src/ops/cgroup.rs | CgroupBundleContext::slice_path() now returns &Path (borrows parent_slice, no clone). Call sites: vm_interior_path join works on &Path; AuditFields slice_path and the D2bSlice tuple site keep one to_p | | | `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | @@ -420,8 +421,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | | `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | already-fixed | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | set_grant(lease, on: bool) already split into grant()/revoke() with was-empty/was-last contracts by the RS-0267 commit (c7d7d66c5); callers use is_last_grant first. No change needed. | | | `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c9a141c78 | packages/d2b-provider-audio-pipewire/src/controller.rs | register_service deleted (zero callers; census over packages/nixos-modules/tests/docs/reference/labs = only the definition); daemon and wayland-policy validate specs via validate_audio_service directl | | -| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | needs-contract | U3 | | `src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-` | deferred: needs-contract - AudioLastSetApplied::OfflineOnly naming vs its doc; variant renders to a wire-visible status string pinned in daemon tests; owning wave U3 (contract wave; ledger precedent RS-0955/RS-0957) | | -| `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-cli` | | | +| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | applied | 7 | 792ca2002 | `packages/d2b-provider-audio-pipewire/src/controller.rs:142` | AudioLastSetApplied::OfflineOnly is renamed NotApplied and the wire label moves with every consumer: the wayland-policy projection arm, its fixture and two pins, the daemon status pin in resource_plane_v3.rs, and the provider ADR enum row - the census of the old literal leaves only the historical audit record. Merged d9a91015a. | | +| `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 9024c13d9 | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1282` | host_entry_ttl_secs and the policy() accessor are gone from ClipboardConfig (field, Default value, and accessors); repo-wide grep finds no code hit; re-verified at 6dc80e258. | | | `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | applied | W5 | 4524b7e45 | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | the public decode_document forwarder and its re-export are deleted; the sole caller in d2bd uses ConfigSyncResponse::document() directly, leaving one API path for validating a synced config document | | | `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | | `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | @@ -436,10 +437,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | | `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | c47b8ba63 | packages/d2b-provider-device-usbip/src/lib.rs | pub mod state_machine -> mod state_machine; the lib.rs re-export remains the single surface. Census re-run: no state_machine:: module-path users outside the crate. | | | `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 7c4997d04 | packages/d2b-provider-device-usbip/src/broker.rs | | | -| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | declined | U3 | | `src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20` | pub(crate) narrowing trips the repo dead_code deny (no internal users, no lint allows permitted by wave rules); wiring the daemon cleanup path needs spec/session-key plumbing across runtime+daemon bey | | +| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | 7 | f30695d3f | `packages/d2b-provider-display-wayland/src/controller.rs:685` | PrincipalReleaseReceipt gained a pub(crate) constructor, the runtime captures the reconciled session key through the one canonical derivation, and DisplayRuntime::finalize returns the lease to the bounded pool in the terminal block after worker closure; a crate-local runtime test proves the release. Narrowing was rejected (dead-code deny). Merged (w7-11 branch). | | | `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | c5d8e0cf5 | packages/d2b-provider-display-wayland/src/lib.rs | Module moved into the binary target via #[path]; all crate::wayland_proxy paths rewritten; census of d2b_provider_display_wayland::wayland_proxy over packages/nixos-modules/tests/docs/reference = 0. | | | `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 15d510a76 | packages/d2b-provider-display-wayland/src/controller.rs | WaylandPolicySnapshot::from_authenticated_session deleted (no callers; census over packages/nixos-modules/tests/labs/docs/reference = 0 in the display crate). | | -| `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12` | | | +| `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | already-fixed | 7 | dc1b0b05e | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:1` | the four-item pub use re-export line is deleted; only the submodule arms remain and consumers use wayland_proxy::policy::...; re-verified at 6dc80e258. | | | `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | | `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | applied | W5 | f5672d7c9 | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | trim route: the uncalled Azure-VM update/adopt/complete-enrollment/status/controller-execution-ref surface and its consequential dead state are deleted after a census showing no production caller; the framework-driven reconcile/recovery/finalize surface is retained | | | `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmController::new now takes effect: E by value and stores it; the production call site and the crate's test call sites (18 FakeEffect constructions, incl. the shared-effect recovery test restruct | | @@ -453,10 +454,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | applied-variant | U3 | f17f141c6 | packages/d2b-provider-network-local/src/routes.rs | Both route provenance validators narrowed to #[cfg(test)] pub(crate) and the stale #[allow(dead_code)] removed. Variant: plain pub(crate) alone re-triggers dead_code (both validators have zero product | | | `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied-variant | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Deleted uncalled reconcile_authenticated_display (census: def only, zero callers); reconcile_sources and drain_sources lowered to #[cfg(test)] pub(crate) (test-only). Variant: plain pub(crate) would r | | | `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Stale #[allow(dead_code)] removed from from_route, which is reachable from production via from_authenticated_route. Same commit as RS-0394 (same file). | | -| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | | | | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1-3, packages/d2b-provi` | | | +| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | 7 | 58ac8df53 | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1` | the private shim module is deleted and lib.rs re-exports the four admission items directly; the ADR-046 layout and reuse rows now cite src/admission.rs (dossier-citation gate green). Merged ae531b399. | | | `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | ebeef4024 | packages/d2b-provider-process-systemd/src/lib.rs | lifecycle is now a private module; the root re-export is the single surface. Census: zero consumers of the d2b_provider_process_systemd::lifecycle path anywhere. check + lib tests green; clippy red is | | | `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | -| `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd` | | | +| `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | applied-variant | 7 | 14d098fc3 | `packages/d2b-provider-process-systemd/src/lib.rs:22` | the row's zero-production-consumer claim is partly false (d2bd composes SystemdProcessProvider and effects_service), so lifecycle/effects_service/operations stay exported; the holding part is implemented - the six test-only modules (controller, drain, metrics, audit, launch, sandbox) are gated behind a new test-support feature (Cargo [[test]] required-features + Bazel crate_features on the test-support target), the conformance suites keep running, and the crate doc records the wired vs test-only surface. A throwaway consumer crate proves the plain build no longer resolves the six modules. Merged 3668d3a6e. | | | `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | c61b0e5b5 | packages/d2b-provider-provider/src/driver.rs | ProviderDriverFactory::new() and impl Default deleted (zero callers; crate tests construct via with_effects; FailClosedProviderDriverEffects still used by tests). Census: no new()/default() callers ac | | | `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | 56c460c03 | packages/d2b-provider-provider/src/providers.rs | Completed the in-flight partial edit: deleted plan_external body, Disable/Delete intent variants, Draining phase, TrustOrCompatibilityDenied error, and orphaned test helpers/imports; check/test/clippy | | | `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | same wiring as RS-0959 | | @@ -482,7 +483,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0422` | `api` | `d2b-provider-zone` | medium | actionable | leaf | applied | U3 | c28489ccc | packages/d2b-provider-zone/src/lib.rs | zone_status module private with the four items re-exported by name; the two module-path consumers (d2bd resource_runtime.rs:63-65, tests/zone_status.rs:3-4) re-pointed to the crate root. Census: d2b_p | | | `RS-0423` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied-variant | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zone_links.rs | Fix as written (pub(crate)) not implementable: usage is test-only, and .cargo/config.toml -Dwarnings turns the resulting dead-code into build errors. Minimal correct variant: #[cfg(test)] on ZoneLinkM | | | `RS-0424` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zonelink.rs | Deleted transport_error_is_quarantine (zero callers in or out of crate, including tests; privatizing alone would trip -Dwarnings dead-code). ZoneLinkError import stays used by issue_route_admission. c | | -| `RS-0425` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | skipped-stale | U3 | | `packages/d2b-provider-zone-link/src/zonelink.rs:178` | Lane premise false on census re-run: d2bd/src/composition.rs:1175 and :1541 call controller.cursor_authority() and use the returned ZoneLinkCursorAuthority value, so the accessor's pub return type is | | +| `RS-0425` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | skipped-stale | U3 | | `packages/d2b-provider-zone-link/src/zonelink.rs:178` | Lane premise false on census re-run: d2bd calls `controller.cursor_authority()` and consumes the returned `ZoneLinkCursorAuthority` value (production at packages/d2bd/src/composition.rs:1200, test at :1566), so the accessor's pub return type is part of a live cross-crate contract. [reconstructed: the original cell was truncated mid-sentence.] | | | `RS-0426` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | Census re-run: zero consumers. Deleted ResourceApiReachability enum, RESOURCE_API_REACHABILITY const, lib re-export, and the tautological assertion in the 13-method test. | | | `RS-0427` | `api` | `d2b-resource-api` | low | actionable | leaf | applied-variant | U3 | 0d74a18f2 | packages/d2b-resource-api/src/client.rs | Census re-run: zero callers. pub(crate) alone tripped denied dead_code warnings (crate denies warnings), so the unwired methods were deleted until a caller exists. | | | `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | wire_revision and api_subject narrowed to pub(crate). resource_owner_subject stays pub because its U9/U10 caller has landed at HEAD: d2bd/src/resource_runtime/plane_controller_bridge.rs:369 (subject() | | @@ -510,7 +511,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 26d5c1119 | packages/d2bd-runtime/src/console_session.rs | ConsoleRing/ConsoleSession fields made private; ConsoleRing exposes push_bytes/set_eof (notify internally), read_at, base_offset, notify(); ConsoleSession exposes provider_kind/ring/stdin_tx accessors | | | `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | applied-variant | 6 | 7739ae6f5 + 128a340f0 | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slices w6-15 and w6-13. Applied: d2b-provider-clipboard-wayland PickerIpcError::Frame/String became Frame(#[from] FramingError) + Read(#[source] io::Error) + ClosedMidFrame with every Display byte-identical; d2b-provider-transport-azure-relay CredentialUnavailable/TransportUnavailable carry typed sources through the explicit Error::source impl (applied-variant: the file hand-writes Display/Error, so no #[source] attributes exist there) with code() strings unchanged; d2bd TypedError carries the audio failure classes as typed leaf variants (applied-variant: failure class as variants rather than a source object, because d2bd-runtime cannot name provider-typed sources and std sources are not Clone). Already-fixed at HEAD, each with its commit: d2b-broker ops/usbip_lock.rs (RS-0454 fd5b41b4b), ops/hosts.rs (84d4cb0b9), d2b-resource-runtime (fa4907468), d2bd-runtime vsock (c9addc3aa). Residual not in the row: PickerIpcError::Socketpair/Spawn/FdFlags still flatten their io/FdMappingCollision errors - flagged, not expanded. | | | `RS-0477` | `err` | `d2b` | medium | actionable | leaf | applied-variant | U3 | 7256bc918 | packages/d2b/src/lib.rs | Added structured code field to CliFailure; populated in ZoneContext::failure; can_fallback_to_local_state and reconcile_deadline match on it. Field is String not &'static str because validate_response | | -| `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | | | | `packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, ` | | | +| `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | applied | 7 | 50be72eea | `packages/d2b/src/host.rs:276` | host prepare/destroy/reconcile now route through missing_mutation_flag_envelope: kind --apply-or-dry-run-required and exit 78 for all three (prepare/destroy moved from exit 2 ref-invalid), with a regression test that fails on the old shape; the --network refusal is untouched. Merged 01daff2b1. | | | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | | `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 637d66627 | packages/d2b-audit/src/segment.rs | | | | `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | @@ -543,14 +544,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | bf6f8829f | packages/d2b-provider-audio-pipewire/src/state.rs | AudioStateIoError::source() returns the io::Error/AudioPolicyError payload; AudioControllerError::source() returns the AudioMediatorError payload. Hand-written impls (thiserror not in lockfile). check | | | `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | 1b70ff14a | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | spawn_niri_event_thread returns Result<(), io::Error>; call site logs instead of panicking. | | | `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | da5acd332 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Binary Result<_, String> signatures and format!-built errors migrated to anyhow; typed BridgeReadError/ControlReadError/ReasonCode untouched; control-socket JSON bodies byte-identical. | | -| `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clip` | | | -| `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provide` | | | +| `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | fb67a0526 | `packages/d2b-provider-clipboard-wayland/src/history.rs:137` | ClipboardHistory::new returns Self unconditionally and ClipdHost::new calls it directly with no map_err or warn; re-verified at 6dc80e258. | | +| `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 7739ae6f5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:132` | PickerIpcError carries the typed Frame(FramingError) variant with #[from]; the six to_string collapses are gone and a test pins the typed source; re-verified at 6dc80e258. | | | `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/ttrpc.rs | Encoding-failure branch now maps to ttrpc Code::INTERNAL, matching the config-document-encoding-failed code class. | | | `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | export_checkpoints now rejects an unparseable lease-map key with the crate's typed `InvariantFailure` refusal instead of a `.expect()` panic; shares commit dbec5dde7 with RS-0368 (same lib.rs surface, | | | `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | | `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 2f5c9a692 | packages/d2b-provider-device-usbip/src/state_machine.rs | | | | `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | 263eea211 | packages/d2b-provider-display-wayland/src/controller.rs | DisplayController::new returns Result with # Errors doc; 2 daemon sites use expect/unwrap; all call sites updated. | | -| `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | | | | `src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886` | | | +| `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | 7 | f30695d3f | `packages/d2b-provider-display-wayland/src/process.rs:346` | both constructors return a closed LaunchError whose Display codes are byte-identical to the old &'static str failures; the test-support wrappers take the same type and lib.rs re-exports it. The daemon caller keeps its whole-error map because the constructor's failure set is closed to one variant. Merged (v7-11 branch). | | | `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 64c41ddb5 | packages/d2b-provider-display-wayland/src/spec.rs | WaylandSpecError::NoPrincipalAvailable variant + Display arm deleted; no error-codes.md hit; no other constructors (controller uses PrincipalPoolError/SessionCondition). | | | `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | applied-variant | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | observe_host returns Result<_, ObserveError>; the flattening format! is replaced by a closed error carrying both SystemCoreError legs with Error::source() (fallback is the chain source, probe error re | | | `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | HostDriverError::Display delegates to self.kind.failure_kind().code(); the three registry codes verified identical to the re-spelled literals. | | @@ -561,7 +562,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | applied | U3 | c22876d4f | packages/d2b-provider-process/src/driver.rs | Map VolumeBinding/Volume row parse failures to ProcessDriverErrorKind::SpecInvalid in identity() and serving_worker_launch() (now Result, _>); genuinely absent rows/views/attachments still y | | | `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | | `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | -| `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | skipped-stale | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | +| `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | skipped-stale | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | The wildcard match arm the row wanted removed is mandatory: `ProcessEffectError` is `#[non_exhaustive]` (packages/d2b-provider-process/src/backend.rs:216-217), so a match outside its defining crate cannot be exhaustive without it. [reconstructed: the wave-3 per-slice reports were never persisted, so this cell is reconstructed from the code rather than recovered from the record.] | | | `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServiceDriverError carries source: Option> with Error::source(); the Err(_) swallow in reconcile_service now attaches the store error and classify_error surfaces it as a fa | | | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | | `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | @@ -613,29 +614,29 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | | `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | applied-variant | 4 | a2cf0e614 | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | applied-variant: consolidated 28 Wire-shape Deserialize impls behind the crate-local wire_deserialize! macro in d2b-contracts-zone-session (canonical home; later waves must reuse it, not write a third macro); parsed_deserialize! requires Self::parse(String) (JSON-string wire), which no Wire-struct impl matches - adopting it would change the wire format the row never asked to change (Main ruling 2026-09-25) | | | `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/storage_lifecycle.rs | serde rejects rename_all on struct variants (field attribute); applied the equivalent house pattern #[serde(rename_all_fields = "camelCase")] on the enum container + dropped per-field renames; seriali | | -| `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | | | | `packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175` | | | +| `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | applied | 7 | fe7c349ea | `packages/d2b-core/src/bundle_resolver.rs:207` | ZoneNativeIndexDocument declares all six keys nixos-modules/index.nix emits and now denies undeclared ones (the four unread keys are defaulted so a partial index still loads); a new admission test fails without the deny and the four committed index fixtures still parse. Merged cd2b66149. | | | `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | | `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | applied | W5 | 6ecf465b7 | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | typed serde structs (rename_all camelCase, deny_unknown_fields) replace the Value-walking assignment codec and the child-create json! literal builder; exact keys, version 1, ascending verb arrays, canonical bytes, and the size bounds are pinned by the transport tests | | | `RS-0557` | `serde` | `d2b-host` | low | actionable | family | applied | 4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:229` | | | | `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | | `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | -| `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-` | | | -| `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | | | | `packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/comm` | | | +| `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | 7 | bcdb699ea | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:12` | AuditEvent drops Deserialize (never read back; every site serializes), keeping Serialize and the bounded-MIME adapter, so the audit wire shape is unchanged. Merged ae531b399. | | +| `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | applied | 7 | bf8dc0bc2 | `packages/d2b-provider-command/src/command.rs:48` | both JsonSchema impls publish the exact admission their parse enforces (exec excludes C0/DEL/C1, argv slot gains minLength and the whole-slot brace pattern); CommandArgvSlot::parse refuses control characters in literal slots so schema and parse agree; the generated v3 Command schema moved through its generator, and an ECMA-262 oracle over 1.1M code points found no mismatch. Merged efdd43e7d. | | | `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | d58f183d5 | packages/d2b-provider-device-gpu/src/gpu_argv.rs | deny_unknown_fields added to GpuArgvInput/GpuParams/GpuDisplayConfig (mirroring VideoArgvInput); new rejects_unknown_fields test pins top-level, params-nested, and display-nested rejection. Mutation c | | | `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | applied | W5 | 4cb0daadb | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | the receive path decodes each newline-delimited bridge frame with a typed #[serde(tag = "type", rename_all = "snake_case")] inbound enum mirroring the outbound frame instead of scanning raw bytes for the refresh substring; a frame that fails to decode is rate-limited-diagnosed and dropped, and later frames still refresh (pinned by tests) | | | `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 84b343101 | packages/d2b-provider-display-wayland/src/spec.rs | Inert serde try_from attribute removed; rename_all/deny_unknown_fields and the manual Deserialize + TryFrom kept. | | | `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | -| `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | | | | `src/driver.rs:282-289, src/driver.rs:190` | | | +| `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | already-fixed | 7 | 73e163675 | `packages/d2b-provider-network-local/src/driver.rs:296` | the serde failure is no longer dropped - the map_err closure emits a structured warn with the error field before mapping to the toolkit's SpecInvalid; re-verified at 6dc80e258. | | | `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | U3 | 336a4fd97 | packages/d2b-provider-network-local/src/broker.rs | Four provenance payload builders (resolved_bridge_payload/resolved_route_payload in broker.rs and operations.rs) no longer .ok()-swallow serde_json::to_value(provenance); they now propagate with map_e | | -| `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | | | | `packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generate` | | | -| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | needs-contract | U3 | | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-p` | deferred: needs-contract - RelayTransportSettings derives Deserialize without try_from, bypassing validate() incl. the secret-shape exclusion; owning wave U3 (contract wave) | | -| `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | | | | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264` | | | +| `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | applied | 7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:1533` | the take-controller-bootstrap leg now builds a typed TakeControllerBootstrapRequest and parses the typed response; a missing/mistyped result fails the leg with a structured warning instead of reading as not-taken (an explicit taken=false still returns Ok(None)), and the fd stays index 0 (the reply carries exactly one descriptor). Merged f2b98ccfb. | | +| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | applied | 7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9` | deserialization goes through a wire struct plus TryFrom so the derived path runs new()/validate(), and the pinned (hand-authored) schema now records the secret-shape exclusion; a schema-vs-validate agreement probe over 7.9M adversarial identifier pairs found 0 mismatches. Merged 82d6c395d. | | +| `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | applied | 7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:233` | parse_material_json is replaced by derived relayListen/relaySend structs with deny_unknown_fields plus the same value pass; admission is strictly stronger (unknown and duplicate keys are now refused, and no in-tree producer emits either) and a malformed-shape test pins it. Merged 82d6c395d. | | | `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | applied | W5 | 379eb3b33 | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | VsockTransportSettings deserializes through a private wire mirror with TryFrom validation, so untrusted JSON is rejected at the boundary; fields are private with accessors and the wire names and JSON schema are unchanged - the needs-contract verdict is overridden because no wire surface moved | | | `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | applied | U3 | b00a073f2 | packages/d2b-provider-volume-local/src/content.rs | ContentFile/ContentProjection/NetworkConfigContentProjection decode via serde try_from Raw mirrors running validating constructors; Deserialize dropped from evidence types; wire shape unchanged. | | | `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | 4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | | `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | | `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | applied-variant | U3 | f1bb96854 | packages/d2bd/src/composition.rs | deny_unknown_fields added to both GatewayGuestConfigFile and GatewayGuestRelayConfigFile. The config-typo test landed as direct deserialization tests on both structs (gateway_guest_config_tests mod), | | -| `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | | | | `packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d` | | | +| `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | applied | 7 | 369627b78 | `packages/d2bd/src/composition.rs:20373` | one parse_activation_marker seam refuses any schemaVersion != 1 with a structured warning and all three read sites (read_activation_marker plus both startup loops) go through it, so a future caller cannot adopt a versioned marker without the check. Merged a74fd9b0c. | | | `RS-0577` | `serde` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | declared_fd_kind now matches the seven kebab-case FdKind spellings directly (fifo/socket/char-device/block-device/any/regular/directory) instead of allocating a serde_json::Value::String; behavior ide | | | `RS-0578` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 3e78efe56 | packages/d2bd-runtime/src/wire.rs | parse_request now dispatches the 17 plain verbs (list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio) throug | | | `RS-0579` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | version-file write failures reported through tracing | | @@ -646,7 +647,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | | `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | a94ef37d6 | packages/d2b-provider-activation-nixos/src/controller.rs | all 9 warn! refusal events in ActivationTrust::verify now carry a named refusal field with the exact ActivationVerificationError variant; no correlation identifiers added (ADR 0010/0028 safe). | | | `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 09167b5fa | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | All 62 log:: sites in d2b-clipd.rs converted to tracing:: with named fields; env_logger init replaced by tracing_subscriber::fmt().with_env_filter(...).with_writer(stderr).init() mirroring d2bd; log/e | | -| `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | | | | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provide` | | | +| `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | 7 | e1ab1525f | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:66` | all six interpolated clipd_host log events now emit tracing named fields (quality, mimes, secret, error, pid, protocol). Merged ae531b399. | | | `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | | `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml | #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] on reconcile/adopt/poll_operation/update/finalize; per-event provider literal and redacted resource_group field dro | | | `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | cc01388e6 | packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs | reconcile/finalize now carry a tracing instrument span with resource/provider fields; 23 per-event duplicate pairs dropped. Deviation: the row's literal span syntax (fields inside skip) is rejected by | | @@ -868,23 +869,23 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0805` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:431` | | | | `RS-0806` | `perf` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:582` | | | | `RS-0807` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:972` | | | -| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | policy-confirmed | W3 | | `clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provide` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | applied | 7 | 8c3c48c0c | `clippy.toml:82` | the three lock entries now name the resolved lock_api paths the parking_lot type aliases point at, so clippy finally fires on every real .lock()/.read()/.write() site; the workspace's unsuppressed sites were taken to zero by the burn-down slices (sanctioned per-site allows or tokio conversions) and the census baseline was regenerated through its own write mode (282 key renames, no count growth). blocking-census --check, check-async-gate and check-provider-crate-layout are green on the flip head; a force-warn probe proves the flipped path matches the real sites while the alias spelling matched none. Merged c31e798ce. | | | `RS-0809` | `conc` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/envelope/mod.rs:1146, src/envelope/mod.rs:2144` | | | -| `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | | | | `packages/d2b-bus/src/registry.rs:522-523, packages/d2b-bus/src/registry.rs:573-582` | | | +| `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | applied | 7 | 50be72eea | `packages/d2b-bus/src/registry.rs:530` | RouteLeaseState.revoked is an AtomicBool with a Release store at remove and Acquire loads at with_active (weakest correct ordering; the latch is one-way), and the two synchronous-path allows are gone; the guard that used to span Operations::begin's mutation no longer serializes it. Merged 01daff2b1. | | | `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-p` | | | | `RS-0812` | `conc` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96` | | | -| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | -| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | policy-confirmed | W3 | | `packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-g` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | applied | 7 | 7e194b77c | `packages/d2b-provider-credential/src/test_support.rs:97` | 27 previously unsuppressed recorder/impl lock sites now carry the sanctioned cfg(test) helper allow (19 in test_support.rs, 7 in the driver test module, 1 in session.rs); synchronous accessors stay synchronous. Merged 78db8d04d. | | +| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | applied-variant | 7 | 7e194b77c | `packages/d2b-provider-device-gpu/src/effects_service.rs:310` | the three gpu_authority_leases lock sites take one sanctioned synchronous-path allow on each enclosing port fn rather than one per call; the Arc type is unchanged because the port is genuinely synchronous. Merged 78db8d04d. | | | `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-` | | | -| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | policy-confirmed | W3 | | `test_support.rs:25, test_support.rs:35, Cargo.toml:30` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | -| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | policy-confirmed | W3 | | `packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, ` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | -| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_s` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | -| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | applied | 7 | 7e194b77c | `packages/d2b-provider-device-usbip/src/test_support.rs:46` | five sanctioned cfg(test) helper allows cover the seven recorder lock sites; no field or type changed. Merged 78db8d04d. | | +| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | applied | 7 | e4277787d | `packages/d2b-provider-guest/src/driver.rs:507` | GuestStatusSink is Arc>> and every write (guest effects service, d2bd resource runtime) awaits it; d2bd was the only external consumer. Merged 8c0715d2f. | | +| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | applied | 7 | e4277787d | `packages/d2b-provider-guest/src/test_support.rs:68` | recorders moved to the toolkit SharedLog, tokio locks with async accessors, or std::sync locks with sanctioned cfg(test) helper allows where a sync trait accessor forces it; parking_lot dropped from the crate and the async-gate inventory and policy-input closures regenerated. Merged 8c0715d2f. | | +| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | applied | 7 | 764d87ef9 | `packages/d2b-provider-process/src/driver.rs:680` | EphemeralRuntime's two clocks are tokio::sync::Mutex and all six accessors are async, awaited by every call site; the crate's remaining unsuppressed sites are test-only state under sanctioned cfg(test) helper allows, taking the crate's post-flip census to 0. Merged 849f2974b. | | | `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.` | | | | `RS-0821` | `conc` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:43, src/testing.rs:79` | | | | `RS-0822` | `conc` | `d2b-provider-toolkit` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-toolkit/src/operations/envelope.rs:487` | | | | `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-uni` | | | -| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-user/src/test_support.rs:41-42, packages/d2b-provider-user/src/test_` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | applied | 7 | 89961f9d9 | `packages/d2b-provider-user/src/test_support.rs:47` | the five recorder/fake fields are tokio::sync::Mutex with the host-sibling accessor split (11 awaited locks, 7 sync try_locks), 18 lock sites converted, parking_lot dropped from the crate, and the async-gate inventory entries rewritten through its write mode. Merged 47ba61aec. | | | `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_sup` | | | | `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-bindin` | | | | `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone` | | | @@ -894,15 +895,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src` | | | | `RS-0832` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs` | | | | `RS-0833` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414` | | | -| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | -| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | 7 | 04cf64c5d | `packages/d2bd-runtime/src/unsafe_local_helper.rs:26` | the four registry/connection/ledger fields are tokio::sync::Mutex and all 39 lock sites reach the tokio seat, through a lock_registry dual seat (blocking_lock off-runtime, bounded try-lock spin on the in-runtime --once path where plain blocking_lock panics) - the panic was reproduced in d2bd's bundle_tampered_envelope test with the plain seat. Merged e65d4954e. | | +| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | 7 | 04cf64c5d | `packages/d2bd-runtime/src/concurrency.rs:163` | OpLockManager::acquire's four try_lock+spin_loop loops are replaced by blocking seats for the production d2b-conn handler threads (a contended op parks instead of burning a core), with the bounded spin kept only on the in-runtime --once path where the blocking seats panic; the stale spin doc is deleted and the dual-seat ordering recorded. Merged e65d4954e. | | | `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support` | | | | `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | 9b64eaa27 | packages/d2b-broker/src/runtime.rs (reap fn; kernel_ops.rs callers) | bounded WNOHANG reap poll replaces the blocking waitid; orphaned helpers deleted | | | `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | 25dfa3aee | packages/d2b-broker/src/sys.rs, packages/d2b-broker/src/ops/swtpm_dir.rs | setfacl shellout moved behind an async wrapper on a bounded worker | | | `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | a6d8fb022 | packages/d2b-broker/src/ops/media.rs | nss group lookup hoisted to a LazyLock, off the per-write path | | | `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | f4f09c74c | packages/d2b-broker/src/ops/host_generation_handoff.rs | flock wait moved to a bounded worker (sanctioned allow reason) | | | `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | -| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | policy-confirmed | W3 | | `packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | applied | 7 | 1f8e52a5f | `packages/d2b-broker/src/runtime.rs:7711` | the whole USB-audit serial HMAC keyring body hops onto the d2b-core bounded loader probe seat, so no blocking stat/mkdir/open/create/fchmod/fsync runs on an executor worker; every hardening check is preserved verbatim (0o700 root-owned dir, O_NOFOLLOW plus O_CLOEXEC open, descriptor-level root-only validation, dir-fd openat create with 0o400 and file+dir fsync) and the existing keyring test passes unchanged. The whole-body hop was chosen over tokio::fs legs because path_safe's openat-on-dir_fd chain has no path-based equivalent. Merged d9a91015a. | | | `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | ProcessLaunchEffectPort and ProcessProvider declare their methods as `async fn` (the RPITIT `impl Future + Send` form is retired) under the house `#[allow(async_fn_in_trait)]` that the pinned lint configuration requires; default bodies are plain async blocks, implementors and the single Send-bound caller keep working, and the bazel graphs re-point consumer test targets at the test-support variants so each crate keeps one instance | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | applied | W3 | 7de088b5d | `packages/d2b-provider/src/agent.rs:316-324` | | | | `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-cre` | | | @@ -911,13 +912,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/observe.rs:255-260` | | | | `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:30, src/testing.rs:19` | | | | `RS-0850` | `async` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833` | | | -| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | policy-confirmed | U1 | | `packages/d2b-provider-user/src/probe.rs:48, packages/d2b-provider-user/src/probe.rs:63, pa` | recorded no-op (KTD8/R14): the deliberate bounded NSS probe is the crate's documented contract - packages/d2b-provider-user/README.md:50-55, src/probe.rs:1-5; audit cluster README.md:2806 | | +| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | applied | 7 | 89961f9d9 | `packages/d2b-provider-user/src/probe.rs:48` | the three blocking NSS reads now run on the d2b-core bounded loader probe seat (run_probe: one thread, bounded sync_channel admission, oneshot reply); a seat refusal maps to SystemCoreError::DiscoveryUnavailable with a structured warning, the whole blocking body (identity digest and bindings) is built on the worker, and a throwaway smoke test resolved the real NSS root through the seat. Cargo.toml/BUILD.bazel gained the d2b-core dep and the policy-input closures were regenerated. Merged 47ba61aec. | | | `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | -| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | declined | W3 | f6b8e60e6 | `packages/d2bd/src/interaction_composition.rs:5518-5530` | | | -| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | declined | W3 | f6b8e60e6 | `packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_ef` | | | +| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | applied | 7 | 6e8f34406 | `packages/d2bd/src/interaction_composition.rs:5546` | InteractionRuntimeSet holds per-Zone Arc handles; the daemon-global lock is taken only to clone the handle and released before the Zone lock, so no global guard spans the dispatch await. The residual note is deleted and a named concurrency test proves two Zones' sessions no longer serialize. Merged fffe5afee. | | +| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | applied | 7 | 6e8f34406 | `packages/d2bd/src/shared_provider_effects.rs:354` | runtime()/plane() are async seats awaiting the plane slot (13 call sites) and the two sync GPU authority seats use a fail-closed try_runtime() per the TPM precedent; NetworkRuntime::bundle is async across both impls and the caller, so both try_lock+spin loops are gone; the async-gate inventory was regenerated. Merged fffe5afee. | | | `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | applied-variant | 4 | 87c3172bc | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | applied-variant: drainer tasks spawn on the daemon's own tokio runtime handle instead of a new dedicated runtime (audit-sanctioned) | | | `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 406f13d98 | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broke` | | | -| `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | skipped-stale | W3 | 406f13d98 | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | | | +| `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | skipped-stale | W3 | 406f13d98 | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | The row's premise does not hold at the pinned versions: `pre_exec` is an `unsafe` method on tokio 1.53.1's `Process` (Cargo.lock:4472) and on `std::process::Command`, so the unsafe block at packages/d2b-broker/src/ops/disk_init.rs:674 cannot be removed. [reconstructed: verified from the code and the lockfile; the wave-3 close artifact carries the original reasoning at lines 15 and 92.] | | | `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | applied | W3 | 3886cfd7b | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | | `RS-0859` | `unsafe` | `d2b-host-activation-helper` | medium | actionable | leaf | applied | W3 | 3f4a63bc8 | `packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/sr` | | | | `RS-0860` | `macro` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | W3 | a34843f8e | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420` | | | @@ -969,7 +970,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0904` | `test` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:145, metric_policy.rs:150` | | | | `RS-0905` | `test` | `d2b-provider-provider` | medium | actionable | leaf | applied | W3 | 55b7d20a6 | `src/providers.rs:206, src/driver.rs:1147` | | | | `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied-variant | W3 | 55b7d20a6 | `tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.r` | | | -| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | policy-confirmed | W3 | | `packages/d2b-provider-supervisor/src/broker.rs:2040-2043` | deferred: policy-confirmed - recorded policy (clippy.toml disallowed-methods / blocking-census sanctioned sites, bounded-worker contracts); needs policy/ADR change first (KTD3) | | +| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | applied | 7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:2012` | the source scrape and its literal name list are gone: PIDFD_DISPATCH_FAILURE_KINDS is a shared const in d2b-contracts-broker, LiveHandlerError maps its variants through it, and the supervisor test asserts against the constant with every behavior assertion kept. Merged f2b98ccfb. | | | `RS-0908` | `test` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230` | | | | `RS-0909` | `test` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-transport-vsock/tests/observe.rs:14-15` | | | | `RS-0910` | `test` | `d2b-provider-user` | medium | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs` | | | From 124490db524da08c5e98a1c2d02108e0cf097a89 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:49:23 -0700 Subject: [PATCH 698/726] fix(d2b-broker): gate the sysctl destroy-value re-export on the feature that uses it --- changelog.d/w7-31-layer1-sysctl-reexport.md | 6 ++++++ packages/d2b-broker/src/ops/sysctl.rs | 1 + packages/xtask/data/async-gate-inventory.json | 6 +++--- 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 changelog.d/w7-31-layer1-sysctl-reexport.md diff --git a/changelog.d/w7-31-layer1-sysctl-reexport.md b/changelog.d/w7-31-layer1-sysctl-reexport.md new file mode 100644 index 000000000..9c69a8094 --- /dev/null +++ b/changelog.d/w7-31-layer1-sysctl-reexport.md @@ -0,0 +1,6 @@ +### Fixed + +- The broker's sysctl destroy-value re-export is compiled only where its + user is: the layer-1 bootstrap build no longer fails on the unused + import while the normal build keeps `destroy_sysctl_value` working + unchanged. diff --git a/packages/d2b-broker/src/ops/sysctl.rs b/packages/d2b-broker/src/ops/sysctl.rs index 6090bbaf5..b55702f9e 100644 --- a/packages/d2b-broker/src/ops/sysctl.rs +++ b/packages/d2b-broker/src/ops/sysctl.rs @@ -201,6 +201,7 @@ fn proc_sys_path(key: &str) -> PathBuf { /// key, read from `d2b_host::netlink` (the crate that owns the sysctl /// tables). A key with no destroy value cannot be destroyed; the broker /// fails closed instead of guessing a value. +#[cfg(not(feature = "layer1-bootstrap"))] pub use d2b_host::netlink::destroy_value_for_key; #[cfg(test)] diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 44f532afd..9867fb1e8 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -808,17 +808,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10885, + "line": 10901, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26622, + "line": 26651, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 27019, + "line": 27048, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 26b18d7782cb23b1346208f1591c1dd166500948 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 22:49:38 -0700 Subject: [PATCH 699/726] audit: point the wave-7 row at the final integration head --- docs/audits/2026-09-24-rust-skills-audit/ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index bcb841b7c..7feb3a5f4 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -44,7 +44,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | | W5 | `25b2474f4` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step, not this wave's. | | W6 | `4e47723a1` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Three close repairs: the pre-existing `clone_on_copy` re-linted in `d2b-core/src/privileges.rs`, the stale family-knowledge exemption in `xtask/src/provider_crate_policy.rs`, and the async-gate hatch inventory re-recorded for ten moved marker sites (4e47723a1: four in `d2b-broker/src/runtime.rs` moved with the w6-12 merge, six in `d2bd` were already stale on the handed-over head, so that red was waiting on a head no preflight had measured). The four clipped reason cells were repaired and marked [reconstructed]. The head cell names the code head 4e47723a1 that the five preflight commands measured (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake); this row ships in ledger-only commits on top of it. | -| W7 | `eff7cbb3d` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 48 rows disposed - see the wave-7 close artifact (.scratch/wave7-close.md) for the per-row evidence, the verified anchors, and the co-change lists. | +| W7 | `124490db5` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 48 rows disposed - see the wave-7 close artifact (.scratch/wave7-close.md) for the per-row evidence, the verified anchors, and the co-change lists. | ## Findings (965 rows) From 464ed6240c9c8ef7d15201046c527ae767ff95f2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 23:03:20 -0700 Subject: [PATCH 700/726] generate: refresh the daemon API reference after the wave-7 merge The merged sources shift the generator's line anchors; the regenerated reference is the committed artifact that matches them. --- docs/reference/daemon-api.md | 226 ++++++++++++++++++----------------- 1 file changed, 114 insertions(+), 112 deletions(-) diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 213b2e5b7..0fddbab77 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -83,8 +83,8 @@ compatibility surface. | `HelloOk` | struct | [`HelloOk`](../../packages/d2b-contracts/src/lib.rs#L190) | struct { `server_version`: `Version`; `selected_version`: `Version`; `capabilities`: `Vec` } | | `HelloRejected` | struct | [`HelloRejected`](../../packages/d2b-contracts/src/lib.rs#L198) | struct { `reason`: `HelloRejectedReason` } | | `HelloRejectedReason` | enum | [`HelloRejectedReason`](../../packages/d2b-contracts/src/lib.rs#L204) | `VersionMismatch`; `CapabilityNegotiationFailed`; `InternalError` | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L902) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L996) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L913) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1007) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | | `KnownFeatureFlag` | enum | [`KnownFeatureFlag`](../../packages/d2b-contracts/src/lib.rs#L154) | `TypedErrors`; `ManifestV04`; `StatusCheckBridges`; `ExportBrokerAudit`; `ConfiguredLaunchV1`; `UnsafeLocalProviderV1` | | `SemverRange` | struct | [`SemverRange`](../../packages/d2b-contracts/src/error.rs#L1130) | empty struct | @@ -277,64 +277,65 @@ host reboot. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | | `BrokerRequest` | enum | [`BrokerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L31) | `ApplyHostGenerationHandoff` - (crate::host_generation::ApplyHostGenerationHandoff); `CreateOrReconcileUsersGroups` - (CreateOrReconcileUsersGroupsRequest); `DelegateCgroupV2` - (DelegateCgroupV2Request); `ExportBrokerAudit` - (ExportBrokerAuditRequest); `Hello` - (HelloRequest); `PublishTrustedContext` - (PublishTrustedContextValues); `InjectSecretById` - (SecretByIdRequest); `LaunchMinijailChild` - (LaunchMinijailChildRequest); `ModprobeIfAllowed` - (ModprobeIfAllowedRequest); `OpenCgroupDir` - (OpenCgroupDirRequest); `OpenDevice` - (OpenDeviceRequest); `OpenFuse` - (OpenFuseRequest); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyRequest); `OpenKvm` - (OpenKvmRequest); `QemuMediaEnroll` - (QemuMediaEnrollRequest); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryRequest); `QemuMediaBoot` - (QemuMediaBootRequest); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleRequest); `QemuMediaQueryStatus` - (QemuMediaQueryStatusRequest); `QemuMediaQuit` - (QemuMediaLifecycleRequest); `QemuMediaAttach` - (QemuMediaHotplugRequest); `QemuMediaDetach` - (QemuMediaHotplugRequest); `PipeWireAudio` - (PipeWireAudioRequest); `OpenVhostNet` - (OpenVhostNetRequest); `ReconcileStorageScope` - (ReconcileStorageScopeRequest); `ValidateLockSpec` - (ValidateLockSpecRequest); `StoreSync` - (StoreSyncRequest); `ReadSecretById` - (SecretByIdRequest); `RotateSecretById` - (SecretByIdRequest); `UsbipBind` - (UsbipBindRequest); `UsbipBindFirewallRule` - (UsbipBindFirewallRuleRequest); `UsbipProxyReconcile` - (UsbipProxyReconcileRequest); `UsbipUnbind` - (UsbipUnbindRequest); `UsbipExplicitBind` - (UsbipExplicitBindRequest); `UsbipExplicitFirewallRule` - (UsbipExplicitFirewallRuleRequest); `OwnershipMatrixCheck` - (OwnershipMatrixCheckRequest); `SshHostKeyPreflight` - (SshHostKeyPreflightRequest); `DiskInit` - (DiskInitRequest); `SecurityKeyOpenDevice` - (d2b_contracts::security_key::SecurityKeyOpenDeviceRequest); `SecurityKeyApplyUdevRules` - (d2b_contracts::security_key::SecurityKeyApplyUdevRulesRequest); `EnvelopeInvoke` - (EnvelopeInvokeRequest) | -| `ForwardOperationRequest` | struct | [`ForwardOperationRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L396) | struct { `operation`: `String`; `zone`: `String`; `invocation_id`: `String`; `payload`: `serde_json::Value`; `context`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L486) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L902) | struct { `client_version`: `String`; `supported_features`: `Vec` } | -| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1008) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1039) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | -| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1057) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1068) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1084) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1100) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | -| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1112) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1133) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1152) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1168) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1184) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | -| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1206) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1214) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | -| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1271) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | -| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1283) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1297) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | -| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1307) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1316) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | -| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1325) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1339) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1360) | struct { `tracing_span_id`: `Option` } | -| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1382) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1390) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1398) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | -| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1463) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | -| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1550) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1623) | empty struct | -| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1638) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1712) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | -| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1782) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | -| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1838) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | -| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1849) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | -| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1922) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1930) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1942) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | -| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1985) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | -| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2007) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | -| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2044) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | -| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2058) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2081) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2098) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2106) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | -| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2114) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | -| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2136) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | -| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2154) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | -| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2249) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2306) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | -| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2315) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | -| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2599) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | -| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2932) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | -| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2949) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2960) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | -| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2974) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | -| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3011) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | -| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3045) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `ForwardOperationRequest` | struct | [`ForwardOperationRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L407) | struct { `operation`: `String`; `zone`: `String`; `invocation_id`: `String`; `payload`: `serde_json::Value`; `context`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `EnvelopeInvokeRequest` | struct | [`EnvelopeInvokeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L497) | struct { `operation`: `String`; `zone`: `String`; `payload`: `serde_json::Value`; `chain_root_invocation_id`: `Option`; `chain_identities`: `Option>`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `HelloRequest` | struct | [`HelloRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L913) | struct { `client_version`: `String`; `supported_features`: `Vec` } | +| `ApplyNftablesRequest` | struct | [`ApplyNftablesRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1019) | struct { `bundle_nft_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `desired_hash`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyNftablesProjectionRequest` | struct | [`ApplyNftablesProjectionRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1050) | struct { `bundle_nft_projection_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `action`: `NftablesProjectionAction`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `expected_generation_id`: `ResourceBundleGenerationId`; `desired_hash`: `Option`; `tracing_span_id`: `Option` } | +| `ApplyNmUnmanagedRequest` | struct | [`ApplyNmUnmanagedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1068) | struct { `bundle_nm_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplyRouteRequest` | struct | [`ApplyRouteRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1079) | struct { `bundle_route_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `ApplySysctlRequest` | struct | [`ApplySysctlRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1095) | struct { `bundle_sysctl_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `CreateOrReconcileUsersGroupsRequest` | struct | [`CreateOrReconcileUsersGroupsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1111) | struct { `subject_ids`: `Vec`; `tracing_span_id`: `Option` } | +| `CreatePersistentTapRequest` | struct | [`CreatePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1123) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DeletePersistentTapRequest` | struct | [`DeletePersistentTapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1144) | struct { `attachment_id`: `ResourceUid`; `expected_zone_uid`: `ResourceUid`; `expected_network_uid`: `ResourceUid`; `expected_network_generation`: `ResourceGeneration`; `expected_attachment_generation`: `ResourceGeneration`; `expected_bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateBridgeRequest` | struct | [`CreateBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1163) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `DeleteBridgeRequest` | struct | [`DeleteBridgeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1179) | struct { `bundle_bridge_intent_ref`: `BundleOpId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `CreateTapFdRequest` | struct | [`CreateTapFdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1195) | struct { `role_id`: `RoleId`; `vm_id`: `VmId`; `bundle_tap_intent_ref`: `BundleOpId`; `attachment_id`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `bundle_generation`: `ResourceBundleGenerationId`; `admitted_interface_names`: `Vec`; `tracing_span_id`: `Option` } | +| `DelegateCgroupV2Request` | struct | [`DelegateCgroupV2Request`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1217) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `ExportBrokerAuditRequest` | struct | [`ExportBrokerAuditRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1225) | struct { `filter`: `Option`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | +| `SecretByIdRequest` | struct | [`SecretByIdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1282) | struct { `opaque_id`: `String`; `tracing_span_id`: `Option` } | +| `LaunchMinijailChildRequest` | struct | [`LaunchMinijailChildRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1294) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `ModprobeIfAllowedRequest` | struct | [`ModprobeIfAllowedRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1308) | struct { `module_name`: `String`; `tracing_span_id`: `Option` } | +| `OpenCgroupDirRequest` | struct | [`OpenCgroupDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1318) | struct { `scope_id`: `ScopeId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `OpenDeviceRequest` | struct | [`OpenDeviceRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1327) | struct { `role_id`: `RoleId`; `device_class`: `String`; `tracing_span_id`: `Option` } | +| `OpenKvmRequest` | struct | [`OpenKvmRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1336) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `QemuMediaEnrollRequest` | struct | [`QemuMediaEnrollRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1350) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `QemuMediaRefreshRegistryRequest` | struct | [`QemuMediaRefreshRegistryRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1371) | struct { `tracing_span_id`: `Option` } | +| `QemuMediaBootRequest` | struct | [`QemuMediaBootRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1393) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaLifecycleRequest` | struct | [`QemuMediaLifecycleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1401) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `QemuMediaQueryStatusRequest` | struct | [`QemuMediaQueryStatusRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1409) | struct { `vm_id`: `VmId`; `shutdown_context`: `bool`; `tracing_span_id`: `Option` } | +| `QemuMediaHotplugRequest` | struct | [`QemuMediaHotplugRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1474) | struct { `vm_id`: `VmId`; `bus_id`: `String`; `tracing_span_id`: `Option` } | +| `OpenPidfdRequest` | struct | [`OpenPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1561) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `pid`: `i32`; `expected_start_time_ticks`: `u64`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketRequest` | struct | [`OpenPeerPidfdFromAcceptedSocketRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1634) | empty struct | +| `ObserveRunnerRequest` | struct | [`ObserveRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1649) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `TakeControllerBootstrapRequest` | struct | [`TakeControllerBootstrapRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1712) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `runtime_scope`: `Option<[u8; 32]>` } | +| `PipeWireAudioRequest` | struct | [`PipeWireAudioRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1763) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `BundleOpId`; `channel`: `PipeWireAudioChannel`; `action`: `PipeWireAudioAction`; `tracing_span_id`: `Option` } | +| `UnitRequest` | struct | [`UnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1833) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `bundle_content_identity`: `String`; `provider_identity`: `[u8; 32]`; `template_identity`: `[u8; 32]`; `generation`: `u64`; `domain`: `UnitDomain`; `execution_ref`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `sandbox_plan`: `Option`; `tracing_span_id`: `Option` } | +| `OpenUnitPidfdRequest` | struct | [`OpenUnitPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1889) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity` } | +| `StopUnitRequest` | struct | [`StopUnitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1900) | struct { `unit`: `UnitRequest`; `expected`: `UnitIdentity`; `class`: `UnitStopClass` } | +| `OpenVhostNetRequest` | struct | [`OpenVhostNetRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1973) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenFuseRequest` | struct | [`OpenFuseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1981) | struct { `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `OpenHidrawSecurityKeyRequest` | struct | [`OpenHidrawSecurityKeyRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1993) | struct { `vm_id`: `VmId`; `selector_id`: `String`; `device_ref`: `ResourceRef`; `authority_key`: `String`; `tracing_span_id`: `Option` } | +| `PrepareDirRequest` | struct | [`PrepareDirRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2036) | struct { `vm_id`: `VmId`; `path_class`: `PathClass`; `tracing_span_id`: `Option` } | +| `StoreSyncRequest` | struct | [`StoreSyncRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2058) | struct { `vm_id`: `VmId`; `bundle_closure_ref`: `BundleClosureRef`; `generation_token`: `u32`; `tracing_span_id`: `Option` } | +| `SetBridgePortFlagsRequest` | struct | [`SetBridgePortFlagsRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2095) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `network_tap_context`: `Option`; `tracing_span_id`: `Option` } | +| `UpdateHostsFileRequest` | struct | [`UpdateHostsFileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2109) | struct { `bundle_hosts_intent_ref`: `BundleOpId`; `zone_uid`: `Option`; `network_uid`: `Option`; `network_generation`: `Option`; `attachment_generation`: `Option`; `bundle_generation`: `Option`; `destroy`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipBindRequest` | struct | [`UsbipBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2132) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipBindFirewallRuleRequest` | struct | [`UsbipBindFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2149) | struct { `bundle_usbip_firewall_intent_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `UsbipProxyReconcileRequest` | struct | [`UsbipProxyReconcileRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2157) | struct { `scope_id`: `ScopeId`; `tracing_span_id`: `Option` } | +| `UsbipUnbindRequest` | struct | [`UsbipUnbindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2165) | struct { `bundle_usbip_bind_intent_ref`: `BundleOpId`; `preserve_durable_claim`: `bool`; `tracing_span_id`: `Option` } | +| `UsbipExplicitBindRequest` | struct | [`UsbipExplicitBindRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2187) | struct { `bus_id`: `String`; `vm`: `String`; `env`: `String`; `tracing_span_id`: `Option` } | +| `UsbipExplicitFirewallRuleRequest` | struct | [`UsbipExplicitFirewallRuleRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2205) | struct { `bus_id`: `String`; `env`: `String`; `host_uplink_ip`: `String`; `net_uplink_ip`: `String`; `tracing_span_id`: `Option` } | +| `SignalRunnerRequest` | struct | [`SignalRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2300) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `bundle_runner_intent_ref`: `Option`; `signal`: `RunnerSignal`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `CgroupKillRequest` | struct | [`CgroupKillRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2357) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `tracing_span_id`: `Option` } | +| `DeregisterRunnerPidfdRequest` | struct | [`DeregisterRunnerPidfdRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2366) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `Option`; `expected_start_time_ticks`: `Option`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `provider_ref`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `guest_execution`: `Option`; `tracing_span_id`: `Option` } | +| `SpawnRunnerRequest` | struct | [`SpawnRunnerRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2650) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `owner_uid`: `Option`; `provider_ref`: `Option`; `bundle_content_identity`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `activation_input`: `Option`; `launch_args`: `Option`; `sandbox_plan`: `Option`; `role`: `RunnerRole`; `bundle_runner_intent_ref`: `BundleOpId`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `runtime_allocations`: `Vec`; `tracing_span_id`: `Option`; `workload_identity`: `Option`; `inherited_fd_count`: `u16`; `network_tap_context`: `Option` } | +| `SeedDnsmasqLeaseRequest` | struct | [`SeedDnsmasqLeaseRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2983) | struct { `vm_id`: `VmId`; `scope_id`: `ScopeId`; `zone_uid`: `ResourceUid`; `network_uid`: `ResourceUid`; `network_generation`: `ResourceGeneration`; `attachment_generation`: `ResourceGeneration`; `bundle_generation`: `ResourceBundleGenerationId`; `tracing_span_id`: `Option` } | +| `OwnershipMatrixCheckRequest` | struct | [`OwnershipMatrixCheckRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3000) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `SshHostKeyPreflightRequest` | struct | [`SshHostKeyPreflightRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3011) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | +| `ReconcileStorageScopeRequest` | struct | [`ReconcileStorageScopeRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3025) | struct { `storage_ref`: `BundleOpId`; `apply`: `bool`; `tracing_span_id`: `Option` } | +| `ValidateLockSpecRequest` | struct | [`ValidateLockSpecRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3062) | struct { `lock_ref`: `BundleOpId`; `tracing_span_id`: `Option` } | +| `DiskInitRequest` | struct | [`DiskInitRequest`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3096) | struct { `vm_id`: `VmId`; `tracing_span_id`: `Option` } | ### Console and audio wire types @@ -390,38 +391,39 @@ see the auto-generated tables above for the committed Rust variants. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | | `ApplyHostGenerationHandoffResponse` | struct | [`ApplyHostGenerationHandoffResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L211) | struct { `target`: `d2b_contracts_resource::v3::ResourceRef`; `state`: `crate::host_generation::HandoffState`; `source_generation`: `u64`; `target_generation`: `u64`; `source_remains_usable`: `bool`; `summary`: `String` } | -| `PublishTrustedContextResponse` | struct | [`PublishTrustedContextResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L372) | struct { `broker_epoch`: `u64` } | -| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L464) | struct { `outcome`: `ForwardOperationOutcome` } | -| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L518) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | -| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L910) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L969) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L996) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | -| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1349) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1367) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | -| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1443) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | -| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1450) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | -| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1493) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | -| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1604) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | -| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1628) | struct { `pidfd_index`: `u32` } | -| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1679) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | -| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1731) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | -| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1872) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1884) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | -| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1893) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | -| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1904) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | -| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1914) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | -| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1972) | struct { `selector_resolved`: `String`; `device_class`: `String` } | -| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2028) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | -| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2169) | struct { `accepted`: `bool`; `operation`: `String` } | -| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2176) | struct { `bridge`: `Option`; `tap`: `IfName` } | -| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2183) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2228) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | -| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2298) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | -| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2358) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | -| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2754) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | -| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2995) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | -| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3019) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | -| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3108) | struct { `notifications`: `Vec` } | +| `PublishTrustedContextResponse` | struct | [`PublishTrustedContextResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L383) | struct { `broker_epoch`: `u64` } | +| `ForwardOperationResponse` | struct | [`ForwardOperationResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L475) | struct { `outcome`: `ForwardOperationOutcome` } | +| `EnvelopeInvokeResponse` | struct | [`EnvelopeInvokeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L529) | struct { `operation`: `String`; `invocation_id`: `String`; `result`: `Option`; `refusal`: `Option`; `detail`: `Option`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` } | +| `BrokerResponse` | enum | [`BrokerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L921) | `ApplyHostGenerationHandoff` - (ApplyHostGenerationHandoffResponse); `Ack` - (AckResponse); `Error` - (BrokerErrorResponse); `ExportBrokerAudit` - (ExportBrokerAuditResponse); `Hello` - (HelloResponse); `PublishTrustedContext` - (PublishTrustedContextResponse); `QemuMediaEnroll` - (QemuMediaEnrollResponse); `QemuMediaRefreshRegistry` - (QemuMediaRefreshRegistryResponse); `QemuMediaBoot` - (QemuMediaHotplugResponse); `QemuMediaSystemPowerdown` - (QemuMediaLifecycleResponse); `QemuMediaQueryStatus` - (QemuMediaQueryStatusResponse); `QemuMediaQuit` - (QemuMediaLifecycleResponse); `QemuMediaAttach` - (QemuMediaHotplugResponse); `QemuMediaDetach` - (QemuMediaHotplugResponse); `OpenHidrawSecurityKey` - (OpenHidrawSecurityKeyResponse); `PipeWireAudio` - (PipeWireAudioResponse); `ReconcileStorageScope` - (ReconcileStorageScopeResponse); `StoreSync` - (StoreSyncResponse); `ValidateLockSpec` - (ValidateLockSpecResponse); `EnvelopeInvoke` - (EnvelopeInvokeResponse) | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L980) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `HelloResponse` | struct | [`HelloResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1007) | struct { `server_version`: `String`; `selected_version`: `String`; `capabilities`: `Vec` } | +| `QemuMediaEnrollResponse` | struct | [`QemuMediaEnrollResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1360) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `read_only`: `bool`; `enrolled`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaRefreshRegistryResponse` | struct | [`QemuMediaRefreshRegistryResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1378) | struct { `record_count`: `u32`; `redacted_index_written`: `bool`; `udev_rule_written`: `bool`; `udev_reloaded`: `bool` } | +| `QemuMediaLifecycleResponse` | struct | [`QemuMediaLifecycleResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1454) | struct { `vm_id`: `VmId`; `command`: `QemuMediaLifecycleAction` } | +| `QemuMediaQueryStatusResponse` | struct | [`QemuMediaQueryStatusResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1461) | struct { `vm_id`: `VmId`; `status`: `QemuMediaVmStatus` } | +| `QemuMediaHotplugResponse` | struct | [`QemuMediaHotplugResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1504) | struct { `vm_id`: `VmId`; `media_ref`: `MediaRef`; `slot`: `String`; `read_only`: `bool`; `qmp_commands`: `Vec`; `events`: `Vec` } | +| `OpenPidfdResponse` | struct | [`OpenPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1615) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `pid`: `i32`; `verified_start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option` } | +| `OpenPeerPidfdFromAcceptedSocketResponse` | struct | [`OpenPeerPidfdFromAcceptedSocketResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1639) | struct { `pidfd_index`: `u32` } | +| `ObserveRunnerResponse` | struct | [`ObserveRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1690) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `pid`: `i32`; `start_time_ticks`: `u64`; `cgroup_verified`: `bool`; `executable_verified`: `bool` } | +| `TakeControllerBootstrapResponse` | struct | [`TakeControllerBootstrapResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1735) | struct { `taken`: `bool` } | +| `PipeWireAudioResponse` | struct | [`PipeWireAudioResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1782) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `applied`: `bool`; `host_ready`: `bool`; `node_present`: `bool` } | +| `StartTransientUnitResponse` | struct | [`StartTransientUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1923) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `CheckUserManagerResponse` | struct | [`CheckUserManagerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1935) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `available`: `bool` } | +| `ObserveUnitResponse` | struct | [`ObserveUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1944) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `present`: `bool`; `identity`: `Option` } | +| `OpenUnitPidfdResponse` | struct | [`OpenUnitPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1955) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `identity`: `UnitIdentity`; `pidfd_index`: `u32` } | +| `StopUnitResponse` | struct | [`StopUnitResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1965) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `stopped`: `bool` } | +| `OpenHidrawSecurityKeyResponse` | struct | [`OpenHidrawSecurityKeyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2023) | struct { `selector_resolved`: `String`; `device_class`: `String` } | +| `StoreSyncResponse` | struct | [`StoreSyncResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2079) | struct { `vm`: `String`; `generation_id`: `String`; `generation_token`: `u32`; `hardlink_farm_path`: `String`; `closure_count`: `u32`; `retained_generations`: `Vec`; `swept_count`: `u32`; `cleanup_deferred`: `bool` } | +| `AckResponse` | struct | [`AckResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2220) | struct { `accepted`: `bool`; `operation`: `String` } | +| `TapReadyResponse` | struct | [`TapReadyResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2227) | struct { `bridge`: `Option`; `tap`: `IfName` } | +| `ExportBrokerAuditResponse` | struct | [`ExportBrokerAuditResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2234) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `BridgePortFlagsResponse` | struct | [`BridgePortFlagsResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2279) | struct { `bridge`: `IfName`; `isolated`: `bool`; `neigh_suppress`: `bool`; `port`: `IfName` } | +| `SignalRunnerResponse` | struct | [`SignalRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2349) | struct { `signaled`: `bool`; `vm_id`: `VmId`; `role_id`: `RoleId` } | +| `DeregisterRunnerPidfdResponse` | struct | [`DeregisterRunnerPidfdResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2409) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `removed`: `bool` } | +| `SpawnRunnerResponse` | struct | [`SpawnRunnerResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2805) | struct { `vm_id`: `VmId`; `role_id`: `RoleId`; `role`: `RunnerRole`; `resource_ref`: `Option`; `resource_uid`: `Option`; `zone_uid`: `Option`; `owner_ref`: `Option`; `runtime_scope`: `Option<[u8; 32]>`; `execution_ref`: `Option`; `execution_domain`: `Option`; `user_ref`: `Option`; `guest_execution`: `Option`; `provider_identity`: `Option<[u8; 32]>`; `template_identity`: `Option<[u8; 32]>`; `generation`: `Option`; `bundle_content_identity`: `Option`; `pid`: `i32`; `start_time_ticks`: `u64`; `pidfd_index`: `u32`; `controller_bootstrap_fd_index`: `Option`; `console_fd_index`: `Option` } | +| `ReconcileStorageScopeResponse` | struct | [`ReconcileStorageScopeResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3046) | struct { `storage_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `status`: `StorageReconcileStatus`; `applied`: `bool`; `path_hash`: `String` } | +| `ValidateLockSpecResponse` | struct | [`ValidateLockSpecResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3070) | struct { `lock_ref`: `BundleOpId`; `scope`: `String`; `kind`: `String`; `cloexec_required`: `bool`; `fd_passing_mechanism`: `String`; `order_key`: `String` } | +| `PollChildReapedResponse` | struct | [`PollChildReapedResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3159) | struct { `notifications`: `Vec` } | ## Per-VM lifecycle state @@ -497,24 +499,24 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | | `FdKind` | enum | [`FdKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L252) | `Fifo`; `Socket`; `CharDevice`; `BlockDevice`; `Any`; `Regular`; `Directory` | -| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L439) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | -| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L840) | `Host`; `Guest` | -| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1027) | `Apply`; `Remove` | -| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1258) | `Info`; `Warning`; `Error`; `Denied` | -| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1412) | `SystemPowerdown`; `Quit` | -| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1419) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | -| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1472) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | -| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1692) | `Speaker`; `Microphone` | -| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1702) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | -| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1746) | `System`; `User` | -| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1862) | `Drain`; `Terminate` | -| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2241) | `Term`; `Kill`; `Quit` | -| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2377) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | -| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2732) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | -| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2886) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | -| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2984) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | -| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3058) | `Exited`; `Signaled`; `Killed` | -| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3096) | `ChildReaped` - (ChildReapedNotification); `Unknown` | +| `ForwardOperationOutcome` | enum | [`ForwardOperationOutcome`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L450) | `Result` - struct { `result`: `serde_json::Value`; `fd_indexes`: `Vec`; `fd_kinds`: `Vec` }; `Refused` - struct { `code`: `String` } | +| `BrokerProfile` | enum | [`BrokerProfile`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L851) | `Host`; `Guest` | +| `NftablesProjectionAction` | enum | [`NftablesProjectionAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1038) | `Apply`; `Remove` | +| `BrokerAuditSeverity` | enum | [`BrokerAuditSeverity`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1269) | `Info`; `Warning`; `Error`; `Denied` | +| `QemuMediaLifecycleAction` | enum | [`QemuMediaLifecycleAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1423) | `SystemPowerdown`; `Quit` | +| `QemuMediaVmStatus` | enum | [`QemuMediaVmStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1430) | `Running`; `Paused`; `Shutdown`; `Suspended`; `Watchdog`; `Debug`; `Inmigrate`; `InternalError`; `IoError`; `Postmigrate`; `Prelaunch`; `FinishMigrate`; `RestoreVm`; `SaveVm`; `GuestPanicked`; `Colo`; `Preconfig`; `Unknown`; `ConnectionLostDuringShutdown` | +| `QemuMediaHotplugStatus` | enum | [`QemuMediaHotplugStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1483) | `IdentityResolved`; `QmpConnected`; `QmpCapabilities`; `FdAdded`; `BlockdevAdded`; `DeviceAdded`; `DeviceDeleted`; `BlockdevDeleted`; `FdRemoved`; `VmContinued` | +| `PipeWireAudioChannel` | enum | [`PipeWireAudioChannel`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1743) | `Speaker`; `Microphone` | +| `PipeWireAudioAction` | enum | [`PipeWireAudioAction`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1753) | `SetGrant` - struct { `on`: `bool` }; `SetLevel` - struct { `percent`: `u8` } | +| `UnitDomain` | enum | [`UnitDomain`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1797) | `System`; `User` | +| `UnitStopClass` | enum | [`UnitStopClass`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L1913) | `Drain`; `Terminate` | +| `RunnerSignal` | enum | [`RunnerSignal`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2292) | `Term`; `Kill`; `Quit` | +| `RunnerRole` | enum | [`RunnerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2428) | `ProviderController`; `CloudHypervisor`; `QemuMedia`; `ActivationNixos`; `Virtiofsd`; `Swtpm`; `SwtpmFlush`; `Gpu`; `Audio`; `Video`; `VsockRelay`; `Usbip`; `OtelHostBridge`; `WaylandProxy` | +| `RunnerAllocationKind` | enum | [`RunnerAllocationKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2783) | `VsockCid`; `TapFdSlot`; `ApiSocketPath` | +| `BrokerCallerRole` | enum | [`BrokerCallerRole`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2937) | `AdminUid` - struct { `uid`: `u32` }; `LauncherUid` - struct { `uid`: `u32` }; `RootUid` - struct { `uid`: `u32` }; `HostShutdownUid` - struct { `uid`: `u32` }; `NotAuthorized` | +| `StorageReconcileStatus` | enum | [`StorageReconcileStatus`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3035) | `Clean`; `Created`; `Reused`; `CheckedOnly`; `TemplateUnexpanded`; `Refused` | +| `ChildExitKind` | enum | [`ChildExitKind`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3109) | `Exited`; `Signaled`; `Killed` | +| `BrokerNotification` | enum | [`BrokerNotification`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L3147) | `ChildReaped` - (ChildReapedNotification); `Unknown` | | `HandoffCallerRole` | enum | [`HandoffCallerRole`](../../packages/d2b-contracts-broker/src/host_generation.rs#L141) | `Lifecycle`; `Admin` | | `HandoffState` | enum | [`HandoffState`](../../packages/d2b-contracts-broker/src/host_generation.rs#L179) | `Recorded`; `Validated`; `Mutating`; `Transferred`; `Completed`; `RolledBack`; `Refused` | | `ProxyReadinessStage` | enum | [`ProxyReadinessStage`](../../packages/d2b-contracts-control/src/proxy_readiness.rs#L12) | `Upstream`; `Listener`; `FirstClient` | @@ -651,8 +653,8 @@ the failure class, for example `host check`, `audit`, `status`, or | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L969) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | -| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2537) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | +| `BrokerErrorResponse` | struct | [`BrokerErrorResponse`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L980) | struct { `kind`: `String`; `operation`: `String`; `target_wave`: `Option`; `message`: `String`; `action`: `String` } | +| `RunnerLaunchArgsError` | enum | [`RunnerLaunchArgsError`](../../packages/d2b-contracts-broker/src/broker_wire.rs#L2588) | `Empty`; `TooMany` - struct { `count`: `usize` }; `EmptyArgument` - struct { `index`: `usize` }; `ArgumentWithNul` - struct { `index`: `usize` }; `ArgumentTooLong` - struct { `index`: `usize` }; `TotalTooLong` - struct { `bytes`: `usize` } | | `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L198) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | | `MutationModeError` | struct | [`MutationModeError`](../../packages/d2b-contracts-control/src/public_wire.rs#L333) | empty struct | From 91b93e438582d576f24b776080c76dc58d03e6be Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 23:11:30 -0700 Subject: [PATCH 701/726] fix(d2b-broker): drop redundant Usbip prefix from op variants `W6UsbipOperation` variants now read `Bind`, `Unbind`, and `ProxyReconcile`, so `clippy::enum_variant_names` no longer fires once the module leaves the crate's exported API (clippy's default `avoid-breaking-exported-api` stops suppressing the lint at that point). Each variant pins its serialized label with an explicit `#[serde(rename = "...")]`, so the audit discriminants stay byte-identical (`usbip-bind`, `usbip-unbind`, `usbip-proxy-reconcile`), and a test asserts the labels on the wire. --- changelog.d/fix-usbip-clippy.md | 8 +++++ packages/d2b-broker/src/ops/usbip_firewall.rs | 36 ++++++++++++++----- 2 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 changelog.d/fix-usbip-clippy.md diff --git a/changelog.d/fix-usbip-clippy.md b/changelog.d/fix-usbip-clippy.md new file mode 100644 index 000000000..fa89aad6d --- /dev/null +++ b/changelog.d/fix-usbip-clippy.md @@ -0,0 +1,8 @@ +### Fixed + +- `d2b-broker`'s `W6UsbipOperation` variants no longer repeat the enum's + `Usbip` prefix, clearing `clippy::enum_variant_names` once the module is + no longer part of the crate's exported API; each variant keeps its exact + kebab-case wire label (`usbip-bind`, `usbip-unbind`, + `usbip-proxy-reconcile`) through an explicit `#[serde(rename = "...")]`, + so the audit discriminants are byte-identical. diff --git a/packages/d2b-broker/src/ops/usbip_firewall.rs b/packages/d2b-broker/src/ops/usbip_firewall.rs index bf513e765..05a02d49d 100644 --- a/packages/d2b-broker/src/ops/usbip_firewall.rs +++ b/packages/d2b-broker/src/ops/usbip_firewall.rs @@ -58,17 +58,20 @@ pub fn bind_firewall_rule( #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum W6UsbipOperation { - UsbipBind, - UsbipUnbind, - UsbipProxyReconcile, + #[serde(rename = "usbip-bind")] + Bind, + #[serde(rename = "usbip-unbind")] + Unbind, + #[serde(rename = "usbip-proxy-reconcile")] + ProxyReconcile, } impl W6UsbipOperation { pub const fn as_kebab_case(&self) -> &'static str { match self { - Self::UsbipBind => "usbip-bind", - Self::UsbipUnbind => "usbip-unbind", - Self::UsbipProxyReconcile => "usbip-proxy-reconcile", + Self::Bind => "usbip-bind", + Self::Unbind => "usbip-unbind", + Self::ProxyReconcile => "usbip-proxy-reconcile", } } } @@ -130,13 +133,28 @@ mod tests { #[test] fn w6_ops_refused_with_unknown_operation_audit() { for op in [ - W6UsbipOperation::UsbipBind, - W6UsbipOperation::UsbipUnbind, - W6UsbipOperation::UsbipProxyReconcile, + W6UsbipOperation::Bind, + W6UsbipOperation::Unbind, + W6UsbipOperation::ProxyReconcile, ] { let audit = refuse_w6_operation(op); assert_eq!(audit.reason, "unknown-operation"); assert_eq!(audit.operation, op); } } + + #[test] + fn w6_operation_serialized_labels_are_pinned() { + for (op, label) in [ + (W6UsbipOperation::Bind, "usbip-bind"), + (W6UsbipOperation::Unbind, "usbip-unbind"), + (W6UsbipOperation::ProxyReconcile, "usbip-proxy-reconcile"), + ] { + let encoded = serde_json::to_value(op).expect("serialize operation"); + assert_eq!(encoded, serde_json::json!(label)); + let decoded: W6UsbipOperation = + serde_json::from_value(encoded).expect("deserialize operation"); + assert_eq!(decoded, op); + } + } } From c6e30d8d344e563938b77c78772972c71916b407 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 23:11:30 -0700 Subject: [PATCH 702/726] fix(xtask): resync async-gate inventory line anchors The d2bd lifecycle-claim fix inserted lines above the three marker-honored sites in `packages/d2bd/src/composition.rs`, so `check-async-gate` reported inventory drift and failed the Layer-1 lane. Regenerated with `cargo xtask check-async-gate --write-inventory`; the only change is the three recorded line numbers. --- packages/xtask/data/async-gate-inventory.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index f823664ce..b10e72188 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -1078,17 +1078,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10886, + "line": 10902, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26470, + "line": 26499, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26867, + "line": 26896, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From 32a5ebb07f9a38985fb880e7a69f3728156464c5 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 23:58:44 -0700 Subject: [PATCH 703/726] fix(d2b-broker,xtask): unblock the check lane's two masked build failures `ops::exec_reconcile` became a `pub(crate)` arm, so its `pub use fake::{FakeReconcileExecutor, ReconcileOp}` is no longer an export rustc counts: a `fake-backends` library build compiles the re-export with no reader, and `-D warnings` rejects it as unused. Gate it on `cfg(test)`, where its six in-crate readers live. `xtask`'s `compute_lock_context` passed `&spec` for a `spec` that is already `&ContextSpec`, tripping `clippy::needless_borrow` in the schema-reproducibility target. --- changelog.d/w7-32-check-lane-build-failures.md | 9 +++++++++ packages/d2b-broker/src/ops/exec_reconcile.rs | 9 +++++++-- packages/xtask/src/production_closure.rs | 4 ++-- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 changelog.d/w7-32-check-lane-build-failures.md diff --git a/changelog.d/w7-32-check-lane-build-failures.md b/changelog.d/w7-32-check-lane-build-failures.md new file mode 100644 index 000000000..234923039 --- /dev/null +++ b/changelog.d/w7-32-check-lane-build-failures.md @@ -0,0 +1,9 @@ +### Fixed + +- The broker's fake reconcile re-export is compiled only where its users + are: the fake-backends library build no longer fails on the unused + import while the unit tests that drive `FakeReconcileExecutor` and + `ReconcileOp` keep working unchanged. +- `xtask`'s production-closure context no longer passes a `&ContextSpec` + that is already a reference, so the schema-reproducibility clippy + target builds clean. diff --git a/packages/d2b-broker/src/ops/exec_reconcile.rs b/packages/d2b-broker/src/ops/exec_reconcile.rs index ad96dbc48..3ba84a103 100644 --- a/packages/d2b-broker/src/ops/exec_reconcile.rs +++ b/packages/d2b-broker/src/ops/exec_reconcile.rs @@ -1666,8 +1666,13 @@ mod fake { } } -#[cfg(any(test, feature = "fake-backends"))] -pub use fake::{FakeReconcileExecutor, ReconcileOp}; +// `exec_reconcile` is a `pub(crate)` arm (see `ops::mod`), so every reader +// of this re-export is an in-crate `#[cfg(test)]` module: the five `ops/*` +// test modules that import the pair by path, `live_handlers`, and the one +// below. A `feature = "fake-backends"` library build compiles the re-export +// with no reader at all, which `-D warnings` rejects as an unused import. +#[cfg(test)] +pub(crate) use fake::{FakeReconcileExecutor, ReconcileOp}; #[cfg(test)] mod tests { diff --git a/packages/xtask/src/production_closure.rs b/packages/xtask/src/production_closure.rs index 86c382eaf..4ef1e7b5c 100644 --- a/packages/xtask/src/production_closure.rs +++ b/packages/xtask/src/production_closure.rs @@ -680,10 +680,10 @@ fn compute_lock_context<'a>( } } let lock_sha256 = sha256_file(&root.join(&spec.lock_path))?; - let production = make_lock_closure(&spec, &records, &selected, &edges, &lock_sha256)?; + let production = make_lock_closure(spec, &records, &selected, &edges, &lock_sha256)?; let policy = production.clone(); let metadata = metadata_projection( - &spec, + spec, &production, &policy, &json!({ "resolve": { "nodes": [] } }), From 97714413dcef48d1ae1f0a02c26780d1490e4428 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 00:15:14 -0700 Subject: [PATCH 704/726] docs(audit): record the gated wave rows and normalize the wave column The W4-W7 wave-gate rows still carried their fold heads and an unrun placeholder in all four result cells, so the table read as if those waves closed without a gate. They closed on the same four-lane set as every earlier wave; the rows now name the gated head and carry that run's real results, and the two notes that explained the old fold head in the head cell are corrected to match. The findings table's wave column mixed the W-prefixed form with a bare numeral, so the same wave appeared under two spellings and could not be selected on. All rows now use the W-prefixed form. --- .../2026-09-24-rust-skills-audit/ledger.md | 250 +++++++++--------- 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 7feb3a5f4..81b53c1b1 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -41,10 +41,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | -| W4 | `c0aaef232` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | -| W5 | `25b2474f4` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step, not this wave's. | -| W6 | `4e47723a1` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Three close repairs: the pre-existing `clone_on_copy` re-linted in `d2b-core/src/privileges.rs`, the stale family-knowledge exemption in `xtask/src/provider_crate_policy.rs`, and the async-gate hatch inventory re-recorded for ten moved marker sites (4e47723a1: four in `d2b-broker/src/runtime.rs` moved with the w6-12 merge, six in `d2bd` were already stale on the handed-over head, so that red was waiting on a head no preflight had measured). The four clipped reason cells were repaired and marked [reconstructed]. The head cell names the code head 4e47723a1 that the five preflight commands measured (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake); this row ships in ledger-only commits on top of it. | -| W7 | `124490db5` | not run (Main gates) | not run (Main gates) | not run (Main gates) | not run (Main gates) | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 48 rows disposed - see the wave-7 close artifact (.scratch/wave7-close.md) for the per-row evidence, the verified anchors, and the co-change lists. | +| W4 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | +| W5 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step; the wave closes on the final gated head in the head cell. | +| W6 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Three close repairs: the pre-existing `clone_on_copy` re-linted in `d2b-core/src/privileges.rs`, the stale family-knowledge exemption in `xtask/src/provider_crate_policy.rs`, and the async-gate hatch inventory re-recorded for ten moved marker sites (4e47723a1: four in `d2b-broker/src/runtime.rs` moved with the w6-12 merge, six in `d2bd` were already stale on the handed-over head, so that red was waiting on a head no preflight had measured). The four clipped reason cells were repaired and marked [reconstructed]. The five preflight commands this wave ran (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake) measured code head 4e47723a1; the head cell now names the final gated head, and the row's remaining commits are ledger-only on top of it. | +| W7 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 48 rows disposed - see the wave-7 close artifact (.scratch/wave7-close.md) for the per-row evidence, the verified anchors, and the co-change lists. | ## Findings (965 rows) @@ -135,7 +135,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U2 | fda87abbe | `packages/d2b-provider-transport-vsock/src/auth.rs` | ReadySession::disconnect now drops mut and returns SessionState::Disconnected directly (SessionState is Copy). | | | `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix (envelope.base.get("provider").cloned()) is type-incompatible: base.get yields CanonicalJsonValue not serde_json::Value. Applied minimal variant: dropped the dead unwrap_or fallback via an | | | `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/status.rs` | LayoutPhase::worse now uses derived self.max(other); declaration order already encodes severity. | | -| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | applied | 4 | b062e724d | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | +| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | applied | W4 | b062e724d | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | | `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | f5dd934fc | `packages/d2b-contracts-resource/src/v3/execution_policy.rs` | The redacted_debug macro was extended with a closure-based field-preserving form (two exported helper fns redacted_debug_field_ref and redacted_debug_field_value), and all 17 hand-written redaction De | | | `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | | `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | @@ -145,7 +145,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | | `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's literal snippet is missing parentheses; the chain shape used is names.difference(...).map(...).chain(declared_names.difference(...).map(...)).collect() preserving bin= then manifest= order | | | `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | derive Default on three unit structs; new() const kept | | -| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | 7 | 1fb8eff80 | `packages/d2b-resource-runtime/src/target.rs:737` | both listings sort through one owned identity key with sort_by_cached_key (the borrowed-key forms are lifetime errors); ordering unchanged and the key is cloned once per element instead of twice per comparison. Merged 6f1390556. | | +| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | W7 | 1fb8eff80 | `packages/d2b-resource-runtime/src/target.rs:737` | both listings sort through one owned identity key with sort_by_cached_key (the borrowed-key forms are lifetime errors); ordering unchanged and the key is cloned once per element instead of twice per comparison. Merged 6f1390556. | | | `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | shared free manager_rpc transport; both endpoints route through it | | | `RS-0098` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | derive Default on TargetDirectory | | | `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | impl FromStr for ResourceProvenance; store parses via str::parse | | @@ -195,9 +195,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | dedup sets now BTreeSet<&BoundedToken>/BTreeSet<&ResourceTypeName> in ProviderManifest::new and with_state_namespaces | | | `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/volume_state.rs` | SchemaFingerprint::parse takes the borrowed str instead of cloning | | | `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied-variant | U2 | 862071320 | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs` | Order-preserving contains check (n<=64) instead of sort-in-place: sorting would change serialized bytes of a signed wire message for unsorted inputs | | -| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | 4 | a2cf0e614 | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | +| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | W4 | a2cf0e614 | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | | `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | acffb7466 | `packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs` | Walk iterates CanonicalJsonObject keys directly; no wrapper or clone built | | -| `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | 4 | a2cf0e614 | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | +| `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | W4 | a2cf0e614 | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | | `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | 7be394a88 | `packages/d2b-contracts-zone-session/src/v3/services.rs` | BoundedText::parse takes method.as_str() instead of method.clone() | | | `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | path_bearing_key_violations renders through Cow; string arm borrows instead of cloning | | | `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | parse(value.as_str()) at 3 sites; network_uid compare via as_str; note: row rationale 'no allocation' inaccurate (Into still allocates) but explicit clones removed | | @@ -214,7 +214,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs` | the type must propagate to the two child handlers (DmabufFeedbackHandler, DmabufBufferParamsHandler) and five test constructions, which clone the same filters value; sync::Arc import removed from dmab | | | `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied-variant | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/driver.rs` | Applied the row's sort_by comparator, fixing its misplaced-paren typo (teardown_rank().cmp().then_with(name cmp)); drops the per-row name clone. | | | `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/effects_service.rs` | Both ACA candidate lists use state.sandbox.iter().cloned().collect() (and disk_image) instead of clone().into_iter().collect(). | | -| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | 7 | 7b480f35d | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs:152` | eviction computes the minimum record sequence once (a Copy u64; sequences are unique because next_sequence increments per insert) and removes exactly that entry with a single retain, so no AcaOperationId clone remains; the Borrow shape was rejected because it still needs an owned key out of the map borrow. A new test pins oldest-first eviction. Merged 39411da5e. | | +| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W7 | 7b480f35d | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs:152` | eviction computes the minimum record sequence once (a Copy u64; sequences are unique because next_sequence increments per insert) and removes exactly that entry with a single retain, so no AcaOperationId clone remains; the Borrow shape was rejected because it still needs an owned key out of the map borrow. A new test pins oldest-first eviction. Merged 39411da5e. | | | `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | reconcile_observed extracts Copy lifecycle first, moves record into self.observed without clone, matches on the extracted lifecycle. Applied with RS-0166 as one considered change per packet. | | | `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | record.id moved out of the stored record via take().expect(...).id, resolving the partial-move vs whole-record-store conflict. Deviation: on resume failure observed is None (was Some(record)). | | | `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 9730af073 | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | Stop and delete stages clone only the sandbox id (observed.as_ref().ok_or(...)?.id.clone()) and move it into the closures; the delete-stage Stopping check reads observed.as_ref().is_some_and(..). | | @@ -236,7 +236,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0183` | `own` | `d2b-provider-provider` | low | actionable | leaf | applied-variant | U2 | 46b177892 | `packages/d2b-provider-provider/src/driver.rs` | Stated fix's assumption (last previous read before set_status) fails: dependencies(ctx) needs &mut ctx between the two previous reads. Minimal variant: reordered dependencies() before the status read | | | `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/service/supervisor.rs` | advance_session now scopes the first session_mut borrow in a block and compares supervisor_identity.as_ref() directly; dropped the clone. | | | `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | -| `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | +| `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | | `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | the provider session loop compares the bound controller route inside the route mutex lock scope, dropping the per-frame AuthenticatedSessionRouteBinding clone | | | `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | is_ready_for_route compares through the guard via is_some_and(/ready/ ready.as_ref().is_some_and(/bound/ bound.liveness().is_live() && bound == route)); no clone. | | | `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/shared_provider.rs` | sort_by with teardown_rank cmp then name cmp; no per-row String allocation. | | @@ -260,10 +260,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | insert_new takes StoredDesiredResource by value; ensure passes by move | | | `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 0e6061c1e | `resource.rs` | pre_start moves row into state; clones only for ResourceContext::new | | | `RS-0210` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | list binds borrowed selector str forms | | -| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | 7 | 7b480f35d | `packages/d2b-resource-runtime/src/metadata.rs:167` | the fence now validates in place and returns Result<(), DriverFailure>; the sole caller discards the value, so the clone is deleted rather than moved; decode and shape refusals stay byte-identical. Merged 39411da5e. | | +| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | W7 | 7b480f35d | `packages/d2b-resource-runtime/src/metadata.rs:167` | the fence now validates in place and returns Result<(), DriverFailure>; the sole caller discards the value, so the clone is deleted rather than moved; decode and shape refusals stay byte-identical. Merged 39411da5e. | | | `RS-0211` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 1f9423d9a | `target.rs` | assign moves assignment into map and clones once for return | | | `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | json_object moves member values; 17 call sites updated | | -| `RS-0213` | `own` | `d2b-session` | low | actionable | family | applied | 7 | 1fb8eff80 | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:1209` | the borrow-based From impl landed earlier in a2cf0e614; this wave deleted the now-unused by-value impl and moved the three owned test sites to borrows. Merged 6f1390556. | | +| `RS-0213` | `own` | `d2b-session` | low | actionable | family | applied | W7 | 1fb8eff80 | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:1209` | the borrow-based From impl landed earlier in a2cf0e614; this wave deleted the now-unused by-value impl and moved the three owned test sites to borrows. Merged 6f1390556. | | | `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | applied | U2 | 0b8ef8ff5 | `packages/d2b-sk-frontend/src/main.rs` | main destructures Config and calls placement.into_placement() (no clone); config builds "/dev/uhid" via PathBuf::from. | | | `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | applied-variant | U2 | 6a3cf6cff | `packages/d2b-zone-routing/src/engine.rs` | Zone pair moved into the snapshot after destructuring expected; validate_snapshot checks inlined (row's first option) and gated #[cfg(test)] since consume no longer calls it | | | `RS-0221` | `own` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 9441488c0 | `packages/d2bd/src/interaction_composition.rs` | supervisor clone removed as row intended; adoption_ticket clone KEPT because process_ticket used after run_effect (self.tickets.insert); closure uses &adoption_ticket - row's remove-both not implement | | @@ -280,7 +280,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | Borrow implemented; five map lookups/removes resolve without String alloc | | | `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/daemon_audit.rs` | write_event* and enqueue take DaemonEvent by value, drop clone; caller migration in d2bd/src/composition.rs left to W1Daemon/orchestrator (cross-crate} | | | `RS-0231` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | check_members takes &[WorkspaceMember]; caller clones dropped; second caller borrows result | | -| `RS-0236` | `own` | `xtask` | low | actionable | leaf | applied | 7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:425` | ComputedContext<'a> borrows its spec, so both caller clones are deleted without adding callee clones; the declared &ContextSpec shape would have been a 2-for-2 swap. Output byte-identical (gen-package-policy-inputs --check green). Merged 83578063f. | | +| `RS-0236` | `own` | `xtask` | low | actionable | leaf | applied | W7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:425` | ComputedContext<'a> borrows its spec, so both caller clones are deleted without adding callee clones; the declared &ContextSpec shape would have been a 2-for-2 swap. Output byte-identical (gen-package-policy-inputs --check green). Merged 83578063f. | | | `RS-0238` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 16e0b183d | `packages/xtask/src/blocking_census.rs` | CensusBaseline built by consuming each CrateCensus instead of cloning crate_dir/counts; --baseline check driven from the written map via a shared helper. Check passes; 18 census tests pass. | | | `RS-0232` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | family-knowledge exempt set keys &str pairs; probe via as_str | | | `RS-0237` | `own` | `xtask` | low | actionable | leaf | applied | U2 | be3e0744b | `production_closure.rs` | duplicate approval clone binding removed; single clone at with_approval call | | @@ -289,34 +289,34 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0235` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 02238dbdd | `semantic_service_schemas.rs` | resource_ref_schema takes &str/&[&str]; five call sites pass borrowed forms | | | `RS-0229` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | mem::take on the mut slot before in-place edit | | | `RS-0230` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | two ratchet probes key borrowed strs via signal fields | | -| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | applied-variant | 4 | 0b5c7d292 | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | applied-variant: d2b-core privileges enums (SecretAccess, BrokerRequirement, AuditMode) gained Copy derives - required because BrokerAuthzFacets/BrokerOperationRow derive Copy; additive, non-breaking | | -| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | applied | 6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Closed Disposition enum (CallableReadOnly/PromotedLive/StubbedUnimplemented/CompileTimeOnly, as_str) beside StubTarget in catalog.rs; BrokerOperationRow.disposition typed against it; generator emits via disposition_variant() mapper with a DISPOSITIONS closed-set validation; the five string-match sites migrated to variant matches; policy JSON stays the string vocabulary. | | -| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | applied | 6 | 13101e206 | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | Generator emits a full closed BrokerOperationName enum (98 variants, as_str); HOST/GUEST_OPERATION_CATALOG and the row operation field typed against it; allows_operation keeps the &str spelling via as_str so the wire boundary is unchanged; consumers migrated (broker_wire.rs, catalog.rs, runtime.rs, d2b-broker/tests profiles, envelope/mod.rs, d2b-broker-composition routing/seam). | | -| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | applied | 6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Destructive enum (Serialize/Deserialize/JsonSchema, kebab-case) in privileges.rs; both field types bool -> Destructive; generate_authz emits named-field construction with Destructive::No/Yes; row() helper and its arity allow deleted (PUBLIC_OPERATION_AUTHZ converted in the same change); Nix emitter, v2 schema, and fuzz corpus seeds moved to no/yes; v1 schema frozen. | | +| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | applied-variant | W4 | 0b5c7d292 | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | applied-variant: d2b-core privileges enums (SecretAccess, BrokerRequirement, AuditMode) gained Copy derives - required because BrokerAuthzFacets/BrokerOperationRow derive Copy; additive, non-breaking | | +| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | applied | W6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Closed Disposition enum (CallableReadOnly/PromotedLive/StubbedUnimplemented/CompileTimeOnly, as_str) beside StubTarget in catalog.rs; BrokerOperationRow.disposition typed against it; generator emits via disposition_variant() mapper with a DISPOSITIONS closed-set validation; the five string-match sites migrated to variant matches; policy JSON stays the string vocabulary. | | +| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | applied | W6 | 13101e206 | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | Generator emits a full closed BrokerOperationName enum (98 variants, as_str); HOST/GUEST_OPERATION_CATALOG and the row operation field typed against it; allows_operation keeps the &str spelling via as_str so the wire boundary is unchanged; consumers migrated (broker_wire.rs, catalog.rs, runtime.rs, d2b-broker/tests profiles, envelope/mod.rs, d2b-broker-composition routing/seam). | | +| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | applied | W6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Destructive enum (Serialize/Deserialize/JsonSchema, kebab-case) in privileges.rs; both field types bool -> Destructive; generate_authz emits named-field construction with Destructive::No/Yes; row() helper and its arity allow deleted (PUBLIC_OPERATION_AUTHZ converted in the same change); Nix emitter, v2 schema, and fuzz corpus seeds moved to no/yes; v1 schema frozen. | | | `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | driver-args zone class: the zone is a validated ZoneId through the wayland-policy, volume-binding, guest, and shared-provider driver args, and the daemon boundary parses it once; the per-pass parse-expects are gone, key_ref returns a typed SpecInvalid Result instead of panicking | escalated W2 -> U5 -> W5 (the family wave landed the driver-args class member sites) | `RS-0263` | `type` | `d2b` | low | actionable | leaf | applied | U3 | f98ad4f82 | packages/d2b/src/context.rs | ZoneContext now stores ZoneId; zone_ref/zone_name built from it; validate_zone_name deleted; discover double validation removed; from_socket takes ZoneId directly. | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | | `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | applied | W5 | 6b9187e44 | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | EvidenceChain deserializes through an admission gate that rejects an empty identities list, so depth() cannot underflow and the identity accessors cannot panic; the wire shape is unchanged | | | `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | already-fixed | U3 | | `packages/d2b-broker/src/ops/media.rs:889-892` | Re-verified at HEAD: QmpAttachCleanup already models its four-step rollback as an ordered typed step list (steps: Vec with QmpAttachStep enum, media.rs:889-892), not four bools. Already | | -| `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | 7 | 5c95bf879 | `packages/d2b-broker/src/ops/storage_contract.rs:27` | Refused.reason is the closed RefusalReason enum (8 fixed slugs plus a canonicalize-failure variant carrying the io error); Display keeps the exact wire text the runtime forwards. Merged 6dc80e258. | | -| `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | 7 | 5c95bf879 | `packages/d2b-broker/src/live_handlers.rs:291` | reloadBehavior parses to a closed NmReloadBehavior (atomic-reload, none, empty-string sentinel) in d2b-core; the broker validator and its typo-refusal error were deleted, both branch sites and the kernel payload parse are typed, and the v2 host schema moved with the generator. Merged 6dc80e258. | | +| `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | W7 | 5c95bf879 | `packages/d2b-broker/src/ops/storage_contract.rs:27` | Refused.reason is the closed RefusalReason enum (8 fixed slugs plus a canonicalize-failure variant carrying the io error); Display keeps the exact wire text the runtime forwards. Merged 6dc80e258. | | +| `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | W7 | 5c95bf879 | `packages/d2b-broker/src/live_handlers.rs:291` | reloadBehavior parses to a closed NmReloadBehavior (atomic-reload, none, empty-string sentinel) in d2b-core; the broker validator and its typo-refusal error were deleted, both branch sites and the kernel payload parse are typed, and the v2 host schema moved with the generator. Merged 6dc80e258. | | | `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 7a5a7f957,4e20f7674 | packages/d2b-bus/src/session/zone_link.rs | folded admission+liveness into private EstablishedLane; test lane keeps None; all three gate sites migrated; follow-up commit reattaches the doc to ZoneLinkSession | | | `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | ResourceQuery assignment/scope Option pair folded into one Option<(AssignmentIdentity, ScopedResourceScope)>; pub assignment()/scope() accessors keep signatures via const match; validate_scoped now on | | | `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | | `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/host_generation.rs | HandoffCoordinator.source_remains_usable field dropped; accessor derives from state != Completed; old durable records deserialize (unknown field ignored); wire response field untouched. | | | `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/broker_wire.rs | CanonicalAuditDigest tuple field made private; parse and as_str remain the only construction/read paths; hand-written Deserialize and serde transparent keep wire shape. | | -| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | applied | 6 | caa29e248 | `public_wire.rs:2166, public_wire.rs:2203` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. AuditResponse's complete/next_cursor pair replaced by the closed AuditPageEnd (Complete / More(cursor)); the crate-local validate_audit_page is deleted and from_parts reports the canonical d2b_contracts::audit_wire::AuditPageError classes, so the admission error text is unchanged; AuditResponse keeps byte- and key-order-identical Serialize via the borrowing AuditResponseOut plus a manual JsonSchema; consumers migrated (d2b/src/dispatch.rs pagination, d2bd-runtime/src/wire.rs audit_response, d2bd/src/composition.rs). Gate: cargo check -p d2b-contracts-control -p d2bd-runtime -p d2bd -p d2b --all-targets rc=0 and the slice's schema drift targets. | | -| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied | 6 | e9cb637c3 | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11. Status DTO state vocabularies are closed kebab-case enums: RealmMode/RealmGatewayState (the `not reported by d2bd` sentinel preserved), QemuMediaRunnerState/QemuMediaRegistryState, PublicReadModelKind, VmAutostartMode; the crate-local duplicate kind and the parallel kind_name:&'static str are deleted, d2bd-runtime publishes the contract enum, and a spelling test pins all 21 spellings. Emitted bytes: the CLI goldens are byte-unchanged; the generated CLI schemas and the v2 wire-protocol schema plus the daemon-api enum table were regenerated with the xtask gen commands and proven by gen_cli_schemas_drift + gen_schemas_drift + gen_daemon_api_drift (3 of 3 pass on the committed tree). | | -| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied-variant | 6 | caa29e248 | `public_wire.rs:316, public_wire.rs:311` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. MutationFlags' three booleans became MutationMode { DryRun, Apply } + MutationFlags { mode, json } with from_flags/to_flags; the seven flattened flag fields lost `default` and the three host requests lost Default, so a payload selecting neither mode fails admission. Recorded deviations: (a) the raw-JSON public frame cannot lose its refusal (it never passes typed admission), so the pair is parsed at the boundary in mutation_mode_from_request and keeps the byte-identical mutating-verb invalid-request envelope, while typed frames fail admission; (b) a hand-written frame setting both flags keeps the long-standing dry-run precedence instead of gaining a new refusal class. | | -| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | +| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | applied | W6 | caa29e248 | `public_wire.rs:2166, public_wire.rs:2203` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. AuditResponse's complete/next_cursor pair replaced by the closed AuditPageEnd (Complete / More(cursor)); the crate-local validate_audit_page is deleted and from_parts reports the canonical d2b_contracts::audit_wire::AuditPageError classes, so the admission error text is unchanged; AuditResponse keeps byte- and key-order-identical Serialize via the borrowing AuditResponseOut plus a manual JsonSchema; consumers migrated (d2b/src/dispatch.rs pagination, d2bd-runtime/src/wire.rs audit_response, d2bd/src/composition.rs). Gate: cargo check -p d2b-contracts-control -p d2bd-runtime -p d2bd -p d2b --all-targets rc=0 and the slice's schema drift targets. | | +| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied | W6 | e9cb637c3 | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11. Status DTO state vocabularies are closed kebab-case enums: RealmMode/RealmGatewayState (the `not reported by d2bd` sentinel preserved), QemuMediaRunnerState/QemuMediaRegistryState, PublicReadModelKind, VmAutostartMode; the crate-local duplicate kind and the parallel kind_name:&'static str are deleted, d2bd-runtime publishes the contract enum, and a spelling test pins all 21 spellings. Emitted bytes: the CLI goldens are byte-unchanged; the generated CLI schemas and the v2 wire-protocol schema plus the daemon-api enum table were regenerated with the xtask gen commands and proven by gen_cli_schemas_drift + gen_schemas_drift + gen_daemon_api_drift (3 of 3 pass on the committed tree). | | +| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied-variant | W6 | caa29e248 | `public_wire.rs:316, public_wire.rs:311` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. MutationFlags' three booleans became MutationMode { DryRun, Apply } + MutationFlags { mode, json } with from_flags/to_flags; the seven flattened flag fields lost `default` and the three host requests lost Default, so a payload selecting neither mode fails admission. Recorded deviations: (a) the raw-JSON public frame cannot lose its refusal (it never passes typed admission), so the pair is parsed at the boundary in mutation_mode_from_request and keeps the byte-identical mutating-verb invalid-request envelope, while typed frames fail admission; (b) a hand-written frame setting both flags keeps the long-standing dry-run precedence instead of gaining a new refusal class. | | +| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | | `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | applied | W5 | fa8706320 | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | ComponentDescriptor::new no longer takes declares_state_volume: the parameter could only ever be false (true returned MissingRequiredField), so the illegal state is not expressible and every call site drops the argument; the wire-only declaresStateVolume field and its consistency check against stateNamespaces stay in the Deserialize path | | | `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | -| `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied | 7 | 1af47c8cf | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:284` | observed_generation is the crate's transparent ObservedGeneration (wire bytes unchanged); the two hand-committed activation-nixos schemas moved with it. Merged ab038d388. | | -| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | -| `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied-variant | 7 | 1af47c8cf + e14ea9c02 | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:47` | target_generation is the existing nonzero ConfigurationGeneration newtype (serde-transparent u64, JsonSchema minimum 1): nonzero_u64_schema, ActivationRunnerInputError and the zero check are deleted, new() is infallible, the now-unreachable zero guards in process-conformance and provider-process are gone, and the EphemeralProcess schema was regenerated. The first landing used a new NixosGenerationOrdinal newtype, which the layout gate refused as shared-crate family vocabulary; the follow-up slice switched to the row's own prescribed ConfigurationGeneration. Merged ab038d388 + 6abcf5cac. | | +| `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied | W7 | 1af47c8cf | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:284` | observed_generation is the crate's transparent ObservedGeneration (wire bytes unchanged); the two hand-committed activation-nixos schemas moved with it. Merged ab038d388. | | +| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | +| `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied-variant | W7 | 1af47c8cf + e14ea9c02 | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:47` | target_generation is the existing nonzero ConfigurationGeneration newtype (serde-transparent u64, JsonSchema minimum 1): nonzero_u64_schema, ActivationRunnerInputError and the zero check are deleted, new() is infallible, the now-unreachable zero guards in process-conformance and provider-process are gone, and the EphemeralProcess schema was regenerated. The first landing used a new NixosGenerationOrdinal newtype, which the layout gate refused as shared-crate family vocabulary; the follow-up slice switched to the row's own prescribed ConfigurationGeneration. Merged ab038d388 + 6abcf5cac. | | | `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises - `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | | `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | packages/d2b-provider-transport-azure-relay/contrast-zone-session/src/v3/role_binding.rs | | | -| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | 4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | +| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | W4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | | `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | | `RS-0262` | `type` | `d2b-host` | medium | actionable | family | applied | W5 | d593fa50e | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | BusId keeps its inner string private and validates the USB busid grammar once at the type boundary (BusId::new returns Result, TryFrom<&str> and as_str carry the value); the transparent wire shape is unchanged and the redundant broker qemu-media re-validations plus the daemon attach/detach pre-checks are deleted | | @@ -324,24 +324,24 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | 87e8d7654 | packages/d2b-provider-audio-pipewire/src/resource_type.rs | owner()/new() now infallible; validate_audio_* remain the single admission gate (they also check provider_ref/extension/zone the ctors cannot). All call sites updated; check+test+clippy green on 4 cra | | | `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | Shared-vs-owned controller mode carried in the type; mixer speaker path split into grant/revoke so the return contract stops being argument-dependent. Suite 94/94. | | | `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 4404afb72 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Merged picker (args.picker.or(config)) validated once after merge; relative paths rejected from either source. | | -| `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 6a6a62f2f | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13` | the two boolean fields are gone - ClipboardRunnerContract carries only service_package and repair_interval_secs, and the former flags survive as const-true accessors with two in-repo test consumers; re-verified at 6dc80e258. | | -| `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | d59bb44a3 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:250` | the pipe-joined completion key is a typed CompletionKey struct built by CompletionKey::new and consumed by ClipboardHistory (BTreeMap keys plus purge); no join/split on the separator remains anywhere in the crate, and the literal-key test builds the struct instead of a string; re-verified at 6dc80e258. | | -| `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 5dfe92ec1 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:143` | entry digests are EntryDigest, parsed once at the single construction point (EntryDigest::parse) and carried by PickerReceipt; the receipt-boundary starts_with check the row described no longer exists; re-verified at 6dc80e258. | | +| `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 6a6a62f2f | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13` | the two boolean fields are gone - ClipboardRunnerContract carries only service_package and repair_interval_secs, and the former flags survive as const-true accessors with two in-repo test consumers; re-verified at 6dc80e258. | | +| `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | d59bb44a3 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:250` | the pipe-joined completion key is a typed CompletionKey struct built by CompletionKey::new and consumed by ClipboardHistory (BTreeMap keys plus purge); no join/split on the separator remains anywhere in the crate, and the literal-key test builds the struct instead of a string; re-verified at 6dc80e258. | | +| `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 5dfe92ec1 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:143` | entry digests are EntryDigest, parsed once at the single construction point (EntryDigest::parse) and carried by PickerReceipt; the receipt-boundary starts_with check the row described no longer exists; re-verified at 6dc80e258. | | | `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/service.rs | Request fields sealed to pub(crate); ConfigSyncRequest::new now calls validate_guest_ref, closing the Guest/ drift; serde derive keeps wire JSON unchanged. | | | `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | applied-variant | U3 | 1ce473a70 | packages/d2b-provider-credential/src/driver.rs | zone: String -> d2b_contracts_resource::v3::ZoneId in CredentialDriverArgs and CredentialDriver; agent_child builds the zone ref with expect on a validated ZoneId (fallible ResourceRef::parse path dro | | | `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | applied | U3 | cd8838c03 | packages/d2b-provider-credential-managed-identity/src/controller.rs | seal `ManagedIdentityTeardownPlan`'s three bool fields behind `pub const fn` accessors so invalid combos (stop_agent && delete_agent, delete_agent && clear_provider_revoke) are unrepresentable; tests | | | `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | -| `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | applied | 4 | 9870dc852 | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | +| `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | applied | W4 | 9870dc852 | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | | `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | -| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | 6 | 5d067420c | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery records [reconstructed: must still load after the change, so the sealed-record read path needs a bounded migration (the sealed Volume survives execute_upgrade per ADR-046-provider-runtime-azure-virtual-machine.md:1157)]. Grouped the operation/operation_started_at_unix_ms pair into Option; hand-written Deserialize accepts both the new inFlightOperation shape and the legacy pair (total fold); pair check deleted; legacy-shape deserialize test added; ADR sealed-recovery section notes the accepted legacy shape. | | +| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | W6 | 5d067420c | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery records [reconstructed: must still load after the change, so the sealed-record read path needs a bounded migration (the sealed Volume survives execute_upgrade per ADR-046-provider-runtime-azure-virtual-machine.md:1157)]. Grouped the operation/operation_started_at_unix_ms pair into Option; hand-written Deserialize accepts both the new inFlightOperation shape and the legacy pair (total fold); pair check deleted; legacy-shape deserialize test added; ADR sealed-recovery section notes the accepted legacy shape. | | | `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired - the illegal Consumed/Expired-with-Some(psk) combination is now unco | | | `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | | `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | e53601c88 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | derive_private_runtime_scope and private_runtime_scope take ChildRole and use role.suffix(); the &str whitelist branch is gone. Callers incl. wayland-policy migrated. | | -| `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | applied | 7 | 2ca9a22dd | `packages/d2b-provider-guest-cloud-hypervisor/src/config.rs:20` | default_machine_type is the closed MachineType enum (the closed q35/microvm pair) and the unreachable validate arm is deleted; root-config.schema.json carries the enum and the committed provider-manifest.json digest moved with the schema bytes. Leftover: the committed provider-manifest.json.sig no longer verifies (publisher private key is not in-tree; nix/provider-artifact.nix:135 checks only the 64-byte length and the host-integration lanes re-sign with their own derived key). Merged bdb26e6ef. | | +| `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | applied | W7 | 2ca9a22dd | `packages/d2b-provider-guest-cloud-hypervisor/src/config.rs:20` | default_machine_type is the closed MachineType enum (the closed q35/microvm pair) and the unreachable validate arm is deleted; root-config.schema.json carries the enum and the committed provider-manifest.json digest moved with the schema bytes. Leftover: the committed provider-manifest.json.sig no longer verifies (publisher private key is not in-tree; nix/provider-artifact.nix:135 checks only the 64-byte length and the host-integration lanes re-sign with their own derived key). Merged bdb26e6ef. | | | `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | f1404725d | packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs | vmm_readiness/vmm_lifecycle now take one VmmReadinessSnapshot struct (five named facts, all_ready()); controller readiness() builds it from GuestDependencySnapshot accessors; tests updated. check/test | | | `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | 82f8cac47 | packages/d2b-provider-guest-qemu-media/src/config.rs | 7 gate calls now use BoundedToken::parse(...) .is_err(); local validate_token helper and its pub(crate) re-export deleted; qmp validate_object_id delegates to BoundedToken::parse. Deviation: validate_ | | | `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | b845000ff | packages/d2b-provider-guest-qemu-media/src/config.rs | impl Default for ProviderConfig deleted (it manufactured a config that fails its own validate());the sole consumer test now builds valid-then-mutated configs (controller_execution_ref swapped to a Gue | | -| `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | applied | 7 | 21a7af424 | `packages/d2b-provider-notification-desktop/src/controller.rs:22` | the two hardcoded-true booleans are one typed NotificationCutoverState::ServiceOnly, and both accessors are derived matches! reads so every caller (both tests) compiles unchanged; the refusal ledger row cited only the daemon composition test, so no ADR amendment was needed. Merged 3668d3a6e. | | +| `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | applied | W7 | 21a7af424 | `packages/d2b-provider-notification-desktop/src/controller.rs:22` | the two hardcoded-true booleans are one typed NotificationCutoverState::ServiceOnly, and both accessors are derived matches! reads so every caller (both tests) compiles unchanged; the refusal ledger row cited only the daemon composition test, so no ADR amendment was needed. Merged 3668d3a6e. | | | `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/agent.rs | ProviderAgentAuditEvent stores parsed BoundedToken values; Serialize renders via as_str(); parse-then-copy-back removed, wire output unchanged. | | | `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U3 | 9fbe75ec2 | packages/d2b-provider-process-minijail/src/launch.rs | validate_launch_ticket renamed to validate_platform_gate and reduced to the gate check (identity checks live only in MinijailProcessProvider::validate); lib.rs:160 literal replaced with crate::PROVIDE | | | `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | @@ -360,18 +360,18 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0302` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | ShutdownDegradedMarker now stores VmShutdownOutcome enum (derive Serialize/Deserialize, rename_all snake_case) instead of String outcome/severity; construction site passes the enum. Report shape uncha | | | `RS-0300` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ZoneResourceRuntime gate trio (policy_installed/controller_endpoint_registered/watch_admitted) replaced by PlanePublicationStage { BootstrapOnly, Published } set at open and activate_published_bundle; | | | `RS-0301` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ControllerSession teardown trio (ingress_revoked/assignments_revoked/transport_closed) replaced by a TeardownStage enum advanced monotonically (Active -> IngressRevoked -> AssignmentsRevoked -> Transp | | -| `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | applied-variant | 7 | 369627b78 | `packages/d2bd/src/composition.rs:20375` | mode is HostActivationMarkerMode rendering the four documented verbs, with a serde(other) Unknown catch-all so an unknown out-of-tree mode still parses (the catch-all is named Unknown so its serde label and Display agree; the finding suggested no name); the marker log keeps a recognized label via Display. Merged a74fd9b0c. | | +| `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | applied-variant | W7 | 369627b78 | `packages/d2bd/src/composition.rs:20375` | mode is HostActivationMarkerMode rendering the four documented verbs, with a serde(other) Unknown catch-all so an unknown out-of-tree mode still parses (the catch-all is named Unknown so its serde label and Display agree; the finding suggested no name); the marker log keeps a recognized label via Display. Merged a74fd9b0c. | | | `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | 7e0ec2bce | packages/d2bd-runtime/src/admission.rs | peer admission lookup mode modelled self-describing; check + admission tests green (worker reported the oid as already present after committing its own change; the commit is this branch's) | | | `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W5 | 6dabfe132 | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | DaemonEvent::ApiReadyTimeout.mode is a closed ApiReadyMode enum (Strict / NoWaitApi) with kebab-case serde, so an invalid mode string is rejected on deserialize; the JSONL shape is unchanged | | -| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | 4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | +| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | | `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | d1c5c44d9 | packages/d2bd-runtime/src/typed_shell_targets.rs | typed-shell target key becomes a named struct with a constructor; the three composition.rs cache call sites migrate to it | | | `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | | `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | | `RS-0314` | `type` | `xtask` | medium | actionable | leaf | applied | U3 | 0b767225a | packages/xtask/src/inventory.rs | Deleted the private copy and both call sites plus the test now use crate::delivery::model::validate_repo_relative_path(Path::new(...)); stricter empty check retained. | | | `RS-0313` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 1d692db3d | packages/xtask/src/provider_crate_policy.rs | FamilyKnowledgeSignal gains typed count: Option; ServerState site fills it and drops the serialized-count text; renderer matches class without the parse;the ratchet JSON stays byte-identical (t | | -| `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | applied | 7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:107` | EdgeRecord.kind is a closed EdgeKind with the wire spelling preserved (proc-macro); a hand-written Ord keeps the historical string order so every committed policy-inputs closure stays byte-identical (write-mode regeneration changed nothing). Merged 83578063f. | | +| `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | applied | W7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:107` | EdgeRecord.kind is a closed EdgeKind with the wire spelling preserved (proc-macro); a hand-written Ord keeps the historical string order so every committed policy-inputs closure stays byte-identical (write-mode regeneration changed nothing). Merged 83578063f. | | | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option pub(crate) for all 19 gpu.rs items and 7 modprobe.rs items (types, impl methods, free fns, trait). Chose item-level over module-decl narrowing so d2b-core bundle_resolver.rs:4300 and | | -| `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | applied | 7 | 5a0110bb9 | `packages/d2b-broker/src/ops/mod.rs:20` | 28 of the 31 handler arms are now pub(crate); pidfd, network and audit_op stay pub because five in-crate integration-test crates import them by path. The census (which arms stay public and why) is recorded next to pub mod ops in lib.rs so a new arm cannot silently reopen the surface. Merged 0365535b1. | | -| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | applied | 6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | Dropped the unused _daemon_uid parameter from pub fn acquire_lock; all 12 census call sites plus 9 in-file test sites and the dead daemon_uid forwarding param on live_usbip_bind (6 callers) updated; broker-internal signature, no doc or fixture pins it. | | +| `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | applied | W7 | 5a0110bb9 | `packages/d2b-broker/src/ops/mod.rs:20` | 28 of the 31 handler arms are now pub(crate); pidfd, network and audit_op stay pub because five in-crate integration-test crates import them by path. The census (which arms stay public and why) is recorded next to pub mod ops in lib.rs so a new arm cannot silently reopen the surface. Merged 0365535b1. | | +| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | applied | W6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | Dropped the unused _daemon_uid parameter from pub fn acquire_lock; all 12 census call sites plus 9 in-file test sites and the dead daemon_uid forwarding param on live_usbip_bind (6 callers) updated; broker-internal signature, no doc or fixture pins it. | | | `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | 068ddcfc4 | packages/d2b-broker/src/ops/cgroup.rs | CgroupBundleContext::slice_path() now returns &Path (borrows parent_slice, no clone). Call sites: vm_interior_path join works on &Path; AuditFields slice_path and the D2bSlice tuple site keep one to_p | | | `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | | `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | applied-variant | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | Census re-run:= with_observer/with_observer_and_metrics/with_clock_and_observer have zero ZoneBus callers, deleted; with_clock -> pub(crate) because production new() delegates to it; with_clock_observ | | | `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | | `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | | `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | -| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | applied | 6 | 3c3454697 | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). BrokerRequestEnvelope no longer carries the test-only test_peer_uid member: the harness (the bootstrap probe CLI and the integration tests) sends that override as a testPeerUid member beside the envelope, and only a --test-mode broker unwraps it in front of its strict decode, so the wire contract carries no test seam and every other broker refuses a frame that carries one; production frames stop emitting the "testPeerUid": null member. New d2b_broker::runtime::{TEST_PEER_UID_FIELD, test_peer_uid_frame} name the harness-only override, and the contract test broker_request_envelope_refuses_a_test_only_peer_uid_member pins the refusal. Co-change: the broker runtime and bootstrap call sites and the four broker integration targets (profile_separation, guest_profile, socket_activation, broker_protocol_compatibility). Gate on the merged tree: cargo test -p d2b-contracts-broker rc=0, cargo test -p d2b-broker rc=0 (700 lib tests plus the spawned-broker integration targets, each driving the new frame-member seam against a real broker), cargo check over the seven touched crates --all-targets rc=0, gen_daemon_api_drift green. | | -| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | 4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | -| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | -| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | 6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | -| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | applied | 6 | e9cb637c3 | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11, as a versioned transition (first assessed blocked on the frozen v1 schema; the operator rule that format compatibility is a co-change list applies, and the census found no freeze policy to cite). The dead pub AuditEntry export is deleted; census at HEAD: the definition only (the live public AuditResponse carries AuditExportEntry pages), no golden, no live consumer; the v1 schema stays the byte-identical historical artifact and the generated v2 schema never contained the name (gen_schemas_drift + gen_daemon_api_drift green). Outside-tree observer: none - the v1-era AuditResponse shape has not been emitted since the page moved to AuditExportEntry. | | -| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied-variant | 6 | dc145cf0c | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Caller-migration variant (recorded deviation; the ledger's census was stale): the two live external callers of HelperLaunchRequest::validate_bounds (d2b-unsafe-local-helper protocol.rs:157, runtime.rs:333) migrated to the pub free fn validate_unsafe_local_resource_identity; then both methods narrowed to pub(crate). Wire types and serde admission unchanged. | | -| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | +| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | applied | W6 | 3c3454697 | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). BrokerRequestEnvelope no longer carries the test-only test_peer_uid member: the harness (the bootstrap probe CLI and the integration tests) sends that override as a testPeerUid member beside the envelope, and only a --test-mode broker unwraps it in front of its strict decode, so the wire contract carries no test seam and every other broker refuses a frame that carries one; production frames stop emitting the "testPeerUid": null member. New d2b_broker::runtime::{TEST_PEER_UID_FIELD, test_peer_uid_frame} name the harness-only override, and the contract test broker_request_envelope_refuses_a_test_only_peer_uid_member pins the refusal. Co-change: the broker runtime and bootstrap call sites and the four broker integration targets (profile_separation, guest_profile, socket_activation, broker_protocol_compatibility). Gate on the merged tree: cargo test -p d2b-contracts-broker rc=0, cargo test -p d2b-broker rc=0 (700 lib tests plus the spawned-broker integration targets, each driving the new frame-member seam against a real broker), cargo check over the seven touched crates --all-targets rc=0, gen_daemon_api_drift green. | | +| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | W4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | +| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | W6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | +| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | W6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | +| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | applied | W6 | e9cb637c3 | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11, as a versioned transition (first assessed blocked on the frozen v1 schema; the operator rule that format compatibility is a co-change list applies, and the census found no freeze policy to cite). The dead pub AuditEntry export is deleted; census at HEAD: the definition only (the live public AuditResponse carries AuditExportEntry pages), no golden, no live consumer; the v1 schema stays the byte-identical historical artifact and the generated v2 schema never contained the name (gen_schemas_drift + gen_daemon_api_drift green). Outside-tree observer: none - the v1-era AuditResponse shape has not been emitted since the page moved to AuditExportEntry. | | +| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied-variant | W6 | dc145cf0c | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Caller-migration variant (recorded deviation; the ledger's census was stale): the two live external callers of HelperLaunchRequest::validate_bounds (d2b-unsafe-local-helper protocol.rs:157, runtime.rs:333) migrated to the pub free fn validate_unsafe_local_resource_identity; then both methods narrowed to pub(crate). Wire types and serde admission unchanged. | | +| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | | `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 67393687b13c359ac6b3a96bca469d28e25c7c96 | packages/d2b-contracts-resource/src/v3/identity.rs | Deleted the zero-caller alias and its doc. Census re-run: ValidatedSessionPurpose over worktree = 1 hit (the definition); no re-export arm in v3/mod.rs. cargo check -p d2b-contracts-resource --locked | | | `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | @@ -421,8 +421,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | | `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | already-fixed | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | set_grant(lease, on: bool) already split into grant()/revoke() with was-empty/was-last contracts by the RS-0267 commit (c7d7d66c5); callers use is_last_grant first. No change needed. | | | `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c9a141c78 | packages/d2b-provider-audio-pipewire/src/controller.rs | register_service deleted (zero callers; census over packages/nixos-modules/tests/docs/reference/labs = only the definition); daemon and wayland-policy validate specs via validate_audio_service directl | | -| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | applied | 7 | 792ca2002 | `packages/d2b-provider-audio-pipewire/src/controller.rs:142` | AudioLastSetApplied::OfflineOnly is renamed NotApplied and the wire label moves with every consumer: the wayland-policy projection arm, its fixture and two pins, the daemon status pin in resource_plane_v3.rs, and the provider ADR enum row - the census of the old literal leaves only the historical audit record. Merged d9a91015a. | | -| `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 9024c13d9 | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1282` | host_entry_ttl_secs and the policy() accessor are gone from ClipboardConfig (field, Default value, and accessors); repo-wide grep finds no code hit; re-verified at 6dc80e258. | | +| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | applied | W7 | 792ca2002 | `packages/d2b-provider-audio-pipewire/src/controller.rs:142` | AudioLastSetApplied::OfflineOnly is renamed NotApplied and the wire label moves with every consumer: the wayland-policy projection arm, its fixture and two pins, the daemon status pin in resource_plane_v3.rs, and the provider ADR enum row - the census of the old literal leaves only the historical audit record. Merged d9a91015a. | | +| `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 9024c13d9 | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1282` | host_entry_ttl_secs and the policy() accessor are gone from ClipboardConfig (field, Default value, and accessors); repo-wide grep finds no code hit; re-verified at 6dc80e258. | | | `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | applied | W5 | 4524b7e45 | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | the public decode_document forwarder and its re-export are deleted; the sole caller in d2bd uses ConfigSyncResponse::document() directly, leaving one API path for validating a synced config document | | | `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | | `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | @@ -437,16 +437,16 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | | `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | c47b8ba63 | packages/d2b-provider-device-usbip/src/lib.rs | pub mod state_machine -> mod state_machine; the lib.rs re-export remains the single surface. Census re-run: no state_machine:: module-path users outside the crate. | | | `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 7c4997d04 | packages/d2b-provider-device-usbip/src/broker.rs | | | -| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | 7 | f30695d3f | `packages/d2b-provider-display-wayland/src/controller.rs:685` | PrincipalReleaseReceipt gained a pub(crate) constructor, the runtime captures the reconciled session key through the one canonical derivation, and DisplayRuntime::finalize returns the lease to the bounded pool in the terminal block after worker closure; a crate-local runtime test proves the release. Narrowing was rejected (dead-code deny). Merged (w7-11 branch). | | +| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | W7 | f30695d3f | `packages/d2b-provider-display-wayland/src/controller.rs:685` | PrincipalReleaseReceipt gained a pub(crate) constructor, the runtime captures the reconciled session key through the one canonical derivation, and DisplayRuntime::finalize returns the lease to the bounded pool in the terminal block after worker closure; a crate-local runtime test proves the release. Narrowing was rejected (dead-code deny). Merged (w7-11 branch). | | | `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | c5d8e0cf5 | packages/d2b-provider-display-wayland/src/lib.rs | Module moved into the binary target via #[path]; all crate::wayland_proxy paths rewritten; census of d2b_provider_display_wayland::wayland_proxy over packages/nixos-modules/tests/docs/reference = 0. | | | `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 15d510a76 | packages/d2b-provider-display-wayland/src/controller.rs | WaylandPolicySnapshot::from_authenticated_session deleted (no callers; census over packages/nixos-modules/tests/labs/docs/reference = 0 in the display crate). | | -| `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | already-fixed | 7 | dc1b0b05e | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:1` | the four-item pub use re-export line is deleted; only the submodule arms remain and consumers use wayland_proxy::policy::...; re-verified at 6dc80e258. | | +| `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | already-fixed | W7 | dc1b0b05e | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:1` | the four-item pub use re-export line is deleted; only the submodule arms remain and consumers use wayland_proxy::policy::...; re-verified at 6dc80e258. | | | `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | | `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | applied | W5 | f5672d7c9 | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | trim route: the uncalled Azure-VM update/adopt/complete-enrollment/status/controller-execution-ref surface and its consequential dead state are deleted after a census showing no production caller; the framework-driven reconcile/recovery/finalize surface is retained | | | `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmController::new now takes effect: E by value and stores it; the production call site and the crate's test call sites (18 FakeEffect constructions, incl. the shared-effect recovery test restruct | | | `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | fe17cfa53 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | repair_children no longer takes committed: &BTreeMap (sole caller passed an always-empty map); the unreachable committed.get(target) branch and the empty-map local are deleted. check/test/clippy green | | | `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | 2ba072632 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | assess_update no longer takes children (production adapter discarded it via let _; request carries none); trait default, adapter override, test impl, and the reconcile call site's Vec allocation all u | | -| `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | applied-variant | 4 | 768457562 | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | applied-variant: the two declarations had drifted (GuestLocalError::EndpointMismatch vs ClientError::InvalidTarget/TransportPolicyMismatch; extra unused endpoint_uid()); reconciled to the d2b-resource-client shape and re-exported | | +| `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | applied-variant | W4 | 768457562 | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | applied-variant: the two declarations had drifted (GuestLocalError::EndpointMismatch vs ClientError::InvalidTarget/TransportPolicyMismatch; extra unused endpoint_uid()); reconciled to the d2b-resource-client shape and re-exported | | | `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | 9b56489c4 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | ChildMutation::expected_uid() (constant None on the UID-free batch) deleted along with the three assert-None assertions; census: remaining expected_uid hits are unrelated types. check/test/clippy gree | | | `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | dc09819bf | packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | Deleted constant-true preserve_state() accessor and its tautological assertion (census: only consumer was the assertion). check+finalize_ordering tests (6) + clippy green. | | | `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | @@ -454,28 +454,28 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | applied-variant | U3 | f17f141c6 | packages/d2b-provider-network-local/src/routes.rs | Both route provenance validators narrowed to #[cfg(test)] pub(crate) and the stale #[allow(dead_code)] removed. Variant: plain pub(crate) alone re-triggers dead_code (both validators have zero product | | | `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied-variant | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Deleted uncalled reconcile_authenticated_display (census: def only, zero callers); reconcile_sources and drain_sources lowered to #[cfg(test)] pub(crate) (test-only). Variant: plain pub(crate) would r | | | `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Stale #[allow(dead_code)] removed from from_route, which is reachable from production via from_authenticated_route. Same commit as RS-0394 (same file). | | -| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | 7 | 58ac8df53 | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1` | the private shim module is deleted and lib.rs re-exports the four admission items directly; the ADR-046 layout and reuse rows now cite src/admission.rs (dossier-citation gate green). Merged ae531b399. | | +| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W7 | 58ac8df53 | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1` | the private shim module is deleted and lib.rs re-exports the four admission items directly; the ADR-046 layout and reuse rows now cite src/admission.rs (dossier-citation gate green). Merged ae531b399. | | | `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | ebeef4024 | packages/d2b-provider-process-systemd/src/lib.rs | lifecycle is now a private module; the root re-export is the single surface. Census: zero consumers of the d2b_provider_process_systemd::lifecycle path anywhere. check + lib tests green; clippy red is | | | `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | -| `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | applied-variant | 7 | 14d098fc3 | `packages/d2b-provider-process-systemd/src/lib.rs:22` | the row's zero-production-consumer claim is partly false (d2bd composes SystemdProcessProvider and effects_service), so lifecycle/effects_service/operations stay exported; the holding part is implemented - the six test-only modules (controller, drain, metrics, audit, launch, sandbox) are gated behind a new test-support feature (Cargo [[test]] required-features + Bazel crate_features on the test-support target), the conformance suites keep running, and the crate doc records the wired vs test-only surface. A throwaway consumer crate proves the plain build no longer resolves the six modules. Merged 3668d3a6e. | | +| `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | applied-variant | W7 | 14d098fc3 | `packages/d2b-provider-process-systemd/src/lib.rs:22` | the row's zero-production-consumer claim is partly false (d2bd composes SystemdProcessProvider and effects_service), so lifecycle/effects_service/operations stay exported; the holding part is implemented - the six test-only modules (controller, drain, metrics, audit, launch, sandbox) are gated behind a new test-support feature (Cargo [[test]] required-features + Bazel crate_features on the test-support target), the conformance suites keep running, and the crate doc records the wired vs test-only surface. A throwaway consumer crate proves the plain build no longer resolves the six modules. Merged 3668d3a6e. | | | `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | c61b0e5b5 | packages/d2b-provider-provider/src/driver.rs | ProviderDriverFactory::new() and impl Default deleted (zero callers; crate tests construct via with_effects; FailClosedProviderDriverEffects still used by tests). Census: no new()/default() callers ac | | | `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | 56c460c03 | packages/d2b-provider-provider/src/providers.rs | Completed the in-flight partial edit: deleted plan_external body, Disable/Delete intent variants, Draining phase, TrustOrCompatibilityDenied error, and orphaned test helpers/imports; check/test/clippy | | -| `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | same wiring as RS-0959 | | -| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | same wiring as RS-0959 | | -| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | same wiring as RS-0959 | | +| `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | same wiring as RS-0959 | | +| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | same wiring as RS-0959 | | +| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | same wiring as RS-0959 | | | `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | applied | W5 | f82fa17c8 | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | the empty test-support feature stanza is deleted with the [[test]] registration required-features gate and the bazel variant's crate_features that referenced it; the registration test now runs instead of being silently skipped, rbac stays public product surface | | -| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | applied | 4 | 7dadf9923 | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | +| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | applied | W4 | 7dadf9923 | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | | `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 0cb5d7b68 | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | applied | W5 | 85cfe8bc1 | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | LaunchedSnapshot carries the launched runner (vm, role, pid, start-time ticks, pidfd) as a named struct with a redacting Debug; the in-tree ProcessEffectBackend trait and LaunchedObserver take it instead of five positional parameters and a 5-tuple, and the only call site plus both daemon call sites are re-pointed | | | `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | -| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | applied-variant | 6 | ab90777de | `src/host.rs:389, src/host.rs:13` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-14. HostReconciler::reject_operator_status_fields (zero callers outside its own tests at HEAD) is now enforced at the daemon's operator status admission (public_update_status_request, the public dispatch's UpdateStatus arm): an operator-submitted Host status naming isolationPosture or isolationPostureMessage, in either request spelling and including the explicit null form, is refused before the row is read. Recorded deviations: the site is the daemon admission rather than d2b-resource-api's update_status (that crate cannot depend on d2b-provider-system-core without inverting the layering), and the provider-session dispatch keeps its own admission because the system-core reconciler's own publication legitimately derives those fields (ADR-046-provider-system-core 4.1.4). Co-change: the typed refusal ResourceRuntimeError::HostStatusFieldNotOwned with its error frame, the system-core host module doc, the admission test an_operator_status_naming_a_host_reconciler_owned_field_is_refused. No serialized shape moves. | | +| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | applied-variant | W6 | ab90777de | `src/host.rs:389, src/host.rs:13` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-14. HostReconciler::reject_operator_status_fields (zero callers outside its own tests at HEAD) is now enforced at the daemon's operator status admission (public_update_status_request, the public dispatch's UpdateStatus arm): an operator-submitted Host status naming isolationPosture or isolationPostureMessage, in either request spelling and including the explicit null form, is refused before the row is read. Recorded deviations: the site is the daemon admission rather than d2b-resource-api's update_status (that crate cannot depend on d2b-provider-system-core without inverting the layering), and the provider-session dispatch keeps its own admission because the system-core reconciler's own publication legitimately derives those fields (ADR-046-provider-system-core 4.1.4). Co-change: the typed refusal ResourceRuntimeError::HostStatusFieldNotOwned with its error frame, the system-core host module doc, the admission test an_operator_status_naming_a_host_reconciler_owned_field_is_refused. No serialized shape moves. | | | `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | make the `ownership` module private; the root re-export of the owned/disowned type lists is the single surface. Shares commit 31ff8b396 with RS-0409 (the audit's own census pairs these two module-surf | | | `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | narrow `reconcile_observed`/`HostProbeSnapshot` to `pub(crate)` with the crate-internal-only callers retained; drop the now-private seam from the crate's pub re-export. Shares commit 31ff8b396 with th | | | `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | forward `HostProbeMetadata` from the host re-export while dropping the zero-external-consumer `HostProbeSnapshot` constant from the public surface; the crate's probe seam stays internal until a consum | | | `RS-0414` | `api` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | 0623be33bf4894fc796b0f603508b2570b746b7d | packages/d2b-provider-toolkit/Cargo.toml | Added test-support = [] feature; gated both constructors with #[cfg(any(test, feature = "test-support"))]; required-features on the supervised_runtime test target; added test-support to the Bazel test | | | `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | 81f51276ed7456104a034c40ba5b3c45bba8c790 | packages/d2b-provider-toolkit/src/server/service.rs | Deleted response_request_id and generated_service plus the response_request_id doc; narrowed the now-unused RequestId import; kept generated_services(). Census re-run: both symbols over worktree = 0 c | | -| `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | -| `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | +| `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | +| `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | | `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs | | | | `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | | `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | applied | W5 | 14bf42022 | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | the never-read VolumeDriverArgs zone field is removed; construction sites and fixtures no longer carry it | | @@ -488,13 +488,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0427` | `api` | `d2b-resource-api` | low | actionable | leaf | applied-variant | U3 | 0d74a18f2 | packages/d2b-resource-api/src/client.rs | Census re-run: zero callers. pub(crate) alone tripped denied dead_code warnings (crate denies warnings), so the unwired methods were deleted until a caller exists. | | | `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | wire_revision and api_subject narrowed to pub(crate). resource_owner_subject stays pub because its U9/U10 caller has landed at HEAD: d2bd/src/resource_runtime/plane_controller_bridge.rs:369 (subject() | | | `RS-0429` | `api` | `d2b-resource-client` | medium | actionable | leaf | applied | U3 | 8b53d606e | packages/d2b-resource-client/src/zone_client.rs | | | -| `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | applied | 4 | 98f74a980 | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | +| `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | applied | W4 | 98f74a980 | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | | `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | 0cd7b063d | packages/d2b-resource-runtime/src/target.rs | Removed TargetBinding::directory() accessor. Census re-run: zero callers; the directory field stays read by internal methods (observe/delete/adopt), no dead code. cargo check/test/clippy green for d2b | | | `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | U3 | 3570364e0 | packages/d2b-resource-runtime/src/guest_target.rs | Removal as written orphans GuestTargetInner.reference (dead-code deny) and forces a public constructor signature change across 26 call sites in 5 files incl. d2bd production (published surface -> cont | | | `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | applied | W5 | 96fef8256 | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | assert_metadata_registration and its re-export arm are gated behind test-support; the 11 registration test crates enable the feature in dev-dependencies, gain required-features where it was missing, and their bazel targets use the resource-types `_test_support` variant | | | `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/fragmentation.rs | Fragment.header is now private with a pub header() accessor; the two engine.rs encode call sites (877, 1395) use the accessor. Census: no external field access. | | | `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | -| `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | applied | 4 | 2f034e476 | `packages/d2b-session-unix/src/socket.rs:176` | | | +| `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | applied | W4 | 2f034e476 | `packages/d2b-session-unix/src/socket.rs:176` | | | | `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | applied | U3 | b9fc346fc | packages/d2b-sk-frontend/src/lib.rs | agent/config/link/uhid made private; UhidDevice and UhidEvent re-exported from lib.rs; main.rs:41 uses root re-exports. Census: sk_frontend::(agent/config/link/uhid):: = 0 full-path hits; zone-routing | | | `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | a9902b8e7 | packages/d2b-unsafe-local-helper/src/runtime.rs | Census re-run: zero external consumers. SupervisorSpec, SUPERVISOR_START_TIMEOUT, SNAPSHOT_RECONCILE_TIMEOUT, send_frame, receive_frame, configure_socket_buffers narrowed to module-private; no pub sig | | | `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/composition.rs | process_provider_runtime and provider_effects narrowed to pub(crate) with a cfg(feature=test-support) pub mod seam for tests/resource_operator_activation.rs; test-only items (new_persistent, admit, pe | | @@ -502,38 +502,38 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0439` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | pub surface reduced to pub(crate): trait HostAudioController, PipeWireHostController, from_audio_node, find_audio_node, QemuAudioController. Census re-run: only in-crate callers (audio_dispatch.rs); m | | | `RS-0440` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | vm_name param removed from HostAudioController::enforce_grant/enforce_level, all three impls (PipeWire/Qemu/Fake), and all call sites incl. tests. Checks: cargo check green; cargo test -p d2bd --locke | | | `RS-0443` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 524d06bad06c00ccf05c20c14461400478d70df3 | packages/d2bd/src/provider_registry.rs | Re-export narrowed to MAX_PROVIDER_REGISTRY_ENTRIES only; census re-run at HEAD shows ProviderRegistrySnapshot appears nowhere else in the workspace through d2bd's path (only the re-export line itself | | -| `RS-0444` | `api` | `d2bd-runtime` | medium | actionable | family | applied-variant | 4 | 87c3172bc | `shell_backend.rs:52-53` | applied-variant: delegating best_effort_close/best_effort_cancel take &EstablishedShell (0/2 callers, all in composition.rs) | | +| `RS-0444` | `api` | `d2bd-runtime` | medium | actionable | family | applied-variant | W4 | 87c3172bc | `shell_backend.rs:52-53` | applied-variant: delegating best_effort_close/best_effort_cancel take &EstablishedShell (0/2 callers, all in composition.rs) | | | `RS-0446` | `api` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U3 | 225f36a3a | packages/d2bd-runtime/src/exec_session.rs | Variant of the row's fallback ('gate the module test-support-only'): the exec-session worker machinery (spawn_session_worker, WorkerSpawn, worker_main, WorkerState, TerminalReaper, OwnerReaper, Establ | | | `RS-0445` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e10faa81f | packages/d2bd-runtime/src/ch_api.rs | ch vm.info payload deserialized through a derived raw shape with a round-trip test | | | `RS-0447` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8b3164c4f | packages/d2bd-runtime/src/console_session.rs | ConsoleClientHandle field made private; added validating FromStr (console-<32 hex>) with ConsoleClientHandleParseError; table lookups stay allocation-free via existing Borrow/as_str (the already- | | | `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 1ed0521fa | packages/d2bd-runtime/src/console_session.rs | Dropped unused _vm parameter from spawn_ch_serial_drainer and the hardcoded "ch-console".to_owned() allocation at the create_ch_session call site. | | | `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e8e7a2d51 | packages/d2bd-runtime/src/console_session.rs | Deleted dead pub DrainerSource enum (census re-run: pattern DrainerSource over packages = 1 hit, the definition itself; zero constructions) and its #[allow(dead_code)]. | | | `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 26d5c1119 | packages/d2bd-runtime/src/console_session.rs | ConsoleRing/ConsoleSession fields made private; ConsoleRing exposes push_bytes/set_eof (notify internally), read_at, base_offset, notify(); ConsoleSession exposes provider_kind/ring/stdin_tx accessors | | -| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | applied-variant | 6 | 7739ae6f5 + 128a340f0 | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slices w6-15 and w6-13. Applied: d2b-provider-clipboard-wayland PickerIpcError::Frame/String became Frame(#[from] FramingError) + Read(#[source] io::Error) + ClosedMidFrame with every Display byte-identical; d2b-provider-transport-azure-relay CredentialUnavailable/TransportUnavailable carry typed sources through the explicit Error::source impl (applied-variant: the file hand-writes Display/Error, so no #[source] attributes exist there) with code() strings unchanged; d2bd TypedError carries the audio failure classes as typed leaf variants (applied-variant: failure class as variants rather than a source object, because d2bd-runtime cannot name provider-typed sources and std sources are not Clone). Already-fixed at HEAD, each with its commit: d2b-broker ops/usbip_lock.rs (RS-0454 fd5b41b4b), ops/hosts.rs (84d4cb0b9), d2b-resource-runtime (fa4907468), d2bd-runtime vsock (c9addc3aa). Residual not in the row: PickerIpcError::Socketpair/Spawn/FdFlags still flatten their io/FdMappingCollision errors - flagged, not expanded. | | +| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | applied-variant | W6 | 7739ae6f5 + 128a340f0 | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slices w6-15 and w6-13. Applied: d2b-provider-clipboard-wayland PickerIpcError::Frame/String became Frame(#[from] FramingError) + Read(#[source] io::Error) + ClosedMidFrame with every Display byte-identical; d2b-provider-transport-azure-relay CredentialUnavailable/TransportUnavailable carry typed sources through the explicit Error::source impl (applied-variant: the file hand-writes Display/Error, so no #[source] attributes exist there) with code() strings unchanged; d2bd TypedError carries the audio failure classes as typed leaf variants (applied-variant: failure class as variants rather than a source object, because d2bd-runtime cannot name provider-typed sources and std sources are not Clone). Already-fixed at HEAD, each with its commit: d2b-broker ops/usbip_lock.rs (RS-0454 fd5b41b4b), ops/hosts.rs (84d4cb0b9), d2b-resource-runtime (fa4907468), d2bd-runtime vsock (c9addc3aa). Residual not in the row: PickerIpcError::Socketpair/Spawn/FdFlags still flatten their io/FdMappingCollision errors - flagged, not expanded. | | | `RS-0477` | `err` | `d2b` | medium | actionable | leaf | applied-variant | U3 | 7256bc918 | packages/d2b/src/lib.rs | Added structured code field to CliFailure; populated in ZoneContext::failure; can_fallback_to_local_state and reconcile_deadline match on it. Field is String not &'static str because validate_response | | -| `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | applied | 7 | 50be72eea | `packages/d2b/src/host.rs:276` | host prepare/destroy/reconcile now route through missing_mutation_flag_envelope: kind --apply-or-dry-run-required and exit 78 for all three (prepare/destroy moved from exit 2 ref-invalid), with a regression test that fails on the old shape; the --network refusal is untouched. Merged 01daff2b1. | | +| `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | applied | W7 | 50be72eea | `packages/d2b/src/host.rs:276` | host prepare/destroy/reconcile now route through missing_mutation_flag_envelope: kind --apply-or-dry-run-required and exit 78 for all three (prepare/destroy moved from exit 2 ref-invalid), with a regression test that fails on the old shape; the --network refusal is untouched. Merged 01daff2b1. | | | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | | `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 637d66627 | packages/d2b-audit/src/segment.rs | | | | `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | -| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | applied-variant | 6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source [reconstructed: ]source: io::Error`; the Display text is preserved, so the broker error-envelope strings are unchanged; one format-string site (usbip_lock.rs:111) needs its own variant]. Applied as variant-split deviation: Io { path, source: io::Error } with a manual Error::source() override (no thiserror dep in d2b-broker) and a new PathSafetyViolation { path } variant; Display byte-identical. | | +| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | applied-variant | W6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source [reconstructed: ]source: io::Error`; the Display text is preserved, so the broker error-envelope strings are unchanged; one format-string site (usbip_lock.rs:111) needs its own variant]. Applied as variant-split deviation: Io { path, source: io::Error } with a manual Error::source() override (no thiserror dep in d2b-broker) and a new PathSafetyViolation { path } variant; Display byte-identical. | | | `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | | `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | ce4da285b | packages/d2b-broker/src/state_cells.rs | with_retention now returns Result (test caller updated with expect); in_memory expect names the startup-precondition rationale; check/test/clippy green. | | | `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | -| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | applied | 6 | fd5b41b4b | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | guest_socket_directory now returns a pub(crate) GuestSocketError enum (RuntimeRootNotAnchored/GuestNotAPlainName/DirectoryOutsideRuntimeRoot) whose Display preserves the three static-code substrings byte-for-byte; the two live_handlers.rs consumers updated; substring-asserting tests stay green. | | +| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | applied | W6 | fd5b41b4b | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | guest_socket_directory now returns a pub(crate) GuestSocketError enum (RuntimeRootNotAnchored/GuestNotAPlainName/DirectoryOutsideRuntimeRoot) whose Display preserves the three static-code substrings byte-for-byte; the two live_handlers.rs consumers updated; substring-asserting tests stay green. | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/src/seam.rs | verify_startup_routing returns Result<(), StartupRoutingViolation> (UnadmittedHandler/MissingHandlers, Display preserved for main.rs); audit_crate/run_cargo_metadata/dependency_tree return Result<_, S | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/configured_argv.rs | ConfiguredArgvError, LauncherMetadataError, UnsafeLocalWorkloadsError, MediaRefError, UsbBusIdError, AuditPageError enums with Display+Error replace String/&'static str returns; unwrap-only callers co | | | `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | Added fmt::Display (message "invalid shell name") and std::error::Error impls to ShellNameError; additive, no surface moved. cargo check/test/clippy -p d2b-contracts-control --locked all passed | | | `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | applied | U3 | 58e72374f | packages/d2b-contracts-provider/src/v3/provider_registry.rs | split zero-generation check before mapping-count bound; Defensive-only reachability since ResourceGeneration rejects 0 at new/Deserialize; no consumer pins the code | | -| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | 6 | 1a6ca86e7 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError::AlreadyRunning Display now emits credential-already-running; the lease-ceiling emitters (CredentialAuditOutcome/CredentialTelemetryOutcome as_str) fixed to credential-queue-pressure and the allowed_telemetry_value closed set updated so the ADR-documented code has its real emitter; ADR-046-resources-credential.md Errors table amended in the same commit, plus the two provider ADRs' code tables that enumerate the same set. | | +| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | W6 | 1a6ca86e7 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError::AlreadyRunning Display now emits credential-already-running; the lease-ceiling emitters (CredentialAuditOutcome/CredentialTelemetryOutcome as_str) fixed to credential-queue-pressure and the allowed_telemetry_value closed set updated so the ADR-documented code has its real emitter; ADR-046-resources-credential.md Errors table amended in the same commit, plus the two provider ADRs' code tables that enumerate the same set. | | | `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | | `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | ed46f196b | packages/d2b-contracts-provider/src/v3/provider_registry.rs | added GenerationMismatch variant kebab code provider-registry-generation-mismatch; updated failure-path test to assert the variant; census ProviderRegistryError=12 hits all in-file | | | `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 75e9c238c | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialSingleFlight lock() now recovers poisoned mutexes via unwrap_or_else(poisoned.into_inner()) and returns the guard directly (infallible); guard Drop recovers the same way instead of silently | | -| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | +| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | | `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | | `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_macvtap_intents now returns crate::error::Error via Error::manifest_parse_error (typed, two failure modes distinguishable); broker call site updated to house .map_err(/error/ BrokerError::Live | | -| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | applied | 4 | 5282e9337 | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | -| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | applied | 6 | 8de97517b | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | find_network_spec and build_resource_network_intents return Result; the six resolve_network_*_intent pub methods return Result, Error> with Error::manifest_parse_error("resource-bundle.json", reason); ~20 call sites and the NetworkIntentSource trait updated; regression test pins kind ManifestParseError / code 40; error-codes.md unchanged; behavior note added to manifest-bundle.md. | | +| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | applied | W4 | 5282e9337 | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | +| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | applied | W6 | 8de97517b | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | find_network_spec and build_resource_network_intents return Result; the six resolve_network_*_intent pub methods return Result, Error> with Error::manifest_parse_error("resource-bundle.json", reason); ~20 call sites and the NetworkIntentSource trait updated; regression test pins kind ManifestParseError / code 40; error-codes.md unchanged; behavior note added to manifest-bundle.md. | | | `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/site.rs | SiteJson::validate returns SiteValidationError::InvalidWaylandSocket enum with Display token; caller and tests updated | | | `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | | `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | manifest_parse_reason now matches serde_json::Error::classify() (Category::Data/Syntax/Eof/Io) instead of Display text; all 8 call sites updated to pass &error; slug change not wire-visible per census | | @@ -544,19 +544,19 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | bf6f8829f | packages/d2b-provider-audio-pipewire/src/state.rs | AudioStateIoError::source() returns the io::Error/AudioPolicyError payload; AudioControllerError::source() returns the AudioMediatorError payload. Hand-written impls (thiserror not in lockfile). check | | | `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | 1b70ff14a | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | spawn_niri_event_thread returns Result<(), io::Error>; call site logs instead of panicking. | | | `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | da5acd332 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Binary Result<_, String> signatures and format!-built errors migrated to anyhow; typed BridgeReadError/ControlReadError/ReasonCode untouched; control-socket JSON bodies byte-identical. | | -| `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | fb67a0526 | `packages/d2b-provider-clipboard-wayland/src/history.rs:137` | ClipboardHistory::new returns Self unconditionally and ClipdHost::new calls it directly with no map_err or warn; re-verified at 6dc80e258. | | -| `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | 7 | 7739ae6f5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:132` | PickerIpcError carries the typed Frame(FramingError) variant with #[from]; the six to_string collapses are gone and a test pins the typed source; re-verified at 6dc80e258. | | +| `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | fb67a0526 | `packages/d2b-provider-clipboard-wayland/src/history.rs:137` | ClipboardHistory::new returns Self unconditionally and ClipdHost::new calls it directly with no map_err or warn; re-verified at 6dc80e258. | | +| `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 7739ae6f5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:132` | PickerIpcError carries the typed Frame(FramingError) variant with #[from]; the six to_string collapses are gone and a test pins the typed source; re-verified at 6dc80e258. | | | `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/ttrpc.rs | Encoding-failure branch now maps to ttrpc Code::INTERNAL, matching the config-document-encoding-failed code class. | | | `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | export_checkpoints now rejects an unparseable lease-map key with the crate's typed `InvariantFailure` refusal instead of a `.expect()` panic; shares commit dbec5dde7 with RS-0368 (same lib.rs surface, | | | `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | | `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 2f5c9a692 | packages/d2b-provider-device-usbip/src/state_machine.rs | | | | `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | 263eea211 | packages/d2b-provider-display-wayland/src/controller.rs | DisplayController::new returns Result with # Errors doc; 2 daemon sites use expect/unwrap; all call sites updated. | | -| `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | 7 | f30695d3f | `packages/d2b-provider-display-wayland/src/process.rs:346` | both constructors return a closed LaunchError whose Display codes are byte-identical to the old &'static str failures; the test-support wrappers take the same type and lib.rs re-exports it. The daemon caller keeps its whole-error map because the constructor's failure set is closed to one variant. Merged (v7-11 branch). | | +| `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | W7 | f30695d3f | `packages/d2b-provider-display-wayland/src/process.rs:346` | both constructors return a closed LaunchError whose Display codes are byte-identical to the old &'static str failures; the test-support wrappers take the same type and lib.rs re-exports it. The daemon caller keeps its whole-error map because the constructor's failure set is closed to one variant. Merged (v7-11 branch). | | | `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 64c41ddb5 | packages/d2b-provider-display-wayland/src/spec.rs | WaylandSpecError::NoPrincipalAvailable variant + Display arm deleted; no error-codes.md hit; no other constructors (controller uses PrincipalPoolError/SessionCondition). | | | `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | applied-variant | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | observe_host returns Result<_, ObserveError>; the flattening format! is replaced by a closed error carrying both SystemCoreError legs with Error::source() (fallback is the chain source, probe error re | | | `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | HostDriverError::Display delegates to self.kind.failure_kind().code(); the three registry codes verified identical to the re-spelled literals. | | | `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | applied | U3 | 200aa2bb2 | packages/d2b-provider-network-local/src/nftables.rs | Sole non-test unwrap replaced with try_into().expect naming the statically-known invariant (64-byte chunk yields a 4-byte word slice). check/clippy exit 0; nftables tests pass. | | -| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | applied-variant | 4 | b56a46c1e | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | applied-variant: kept the crate's existing exported ProviderError name (renaming is churn); test-fake slugs mapped to family variants; 4 pre-existing unused ProviderError variants kept as exported API | | +| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | applied-variant | W4 | b56a46c1e | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | applied-variant: kept the crate's existing exported ProviderError name (renaming is churn); test-fake slugs mapped to family variants; 4 pre-existing unused ProviderError variants kept as exported API | | | `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U3 | eba219aa6 | packages/d2b-provider-notification-desktop/src/types.rs | Added NotificationError::Denied (slug notification-denied; not pinned in docs/reference) and mapped the five admission/zone/category rejection sites (host_sink.rs source/observer admission, zone misma | | | `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/ingress_policy.rs | Full connection-table rejection now reports IngressErrorClass::None, consistent with the sibling capacity refusal. | | | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | applied | U3 | c22876d4f | packages/d2b-provider-process/src/driver.rs | Map VolumeBinding/Volume row parse failures to ProcessDriverErrorKind::SpecInvalid in identity() and serving_worker_launch() (now Result, _>); genuinely absent rows/views/attachments still y | | @@ -567,10 +567,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | | `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | | `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | de1a2c493eb2db826cd517128364c759a86240d9 | packages/d2b-provider-toolkit/src/operations/envelope.rs | audit_named falls back to the canonical (lowercase, dash-stripped) spelling when BoundedToken::parse rejects the raw name, so a refused PascalCase forwarded invocation lands its Denied record; already | | -| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | -| `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | -| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | -| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | applied-variant: key_ref returns Result; the cited spec_store.rs:60-63 anchor has no key_ref caller at base (d2b-resource-runtime has no provider-toolkit dependency), nothing to update there | | +| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | +| `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | +| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | +| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | applied-variant: key_ref returns Result; the cited spec_store.rs:60-63 anchor has no key_ref caller at base (d2b-resource-runtime has no provider-toolkit dependency), nothing to update there | | | `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | applied | U3 | 2ab7a1ed2 | packages/d2b-provider-user/src/driver.rs | Display impl now writes self.kind.failure_kind().code(); registered FailureKind codes remain the single source, strings unchanged, no behavior change. | | @@ -585,15 +585,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | | `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | applied | U3 | 6f07391f0 | packages/d2b-telemetry/src/emitter.rs | Added EmitterError::InvalidLimits with Display arm and doc updates; zero-capacity/frame/age/retry guards return it; StatePoisoned kept for lock().map_err sites; check/test/clippy green. | | | `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | applied | U3 | 1453d6b9a | packages/d2b-telemetry/src/session_metrics_sink.rs | Deleted never-constructed SessionMetricsError::Encode variant and its session-metric-encode-failed Display arm; check/test/clippy green. | | -| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | applied | 6 | 0330ae04b | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | await_scope_identity's early-exit Ok(_) arm now maps to ScopeError::CreateFailed; the existing mapping chain carries it to HelperFailureCode::ScopeCreateFailed -> daemon wire code 42; both codes stay documented in error-codes.md (rows untouched, drift gate green); regression test pins the reclassified contract. | | +| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | applied | W6 | 0330ae04b | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | await_scope_identity's early-exit Ok(_) arm now maps to ScopeError::CreateFailed; the existing mapping chain carries it to HelperFailureCode::ScopeCreateFailed -> daemon wire code 42; both codes stay documented in error-codes.md (rows untouched, drift gate green); regression test pins the reclassified contract. | | | `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | | `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | a91ad9bbc | packages/d2bd/src/resource_plane_v3.rs | PlaneError's five String variants retyped: FoundationSeed(#[from] SeedError), ManagerSpawn(#[from] ractor::SpawnErr), Bundle(#[from] ResourceBundleError), Authority/Target(#[source] Box>, every impl and call site migrated; re-dispatched per Main's directive 2026-09-25) | | +| `RS-0527` | `err` | `d2bd` | medium | actionable | family | applied | W4 | ea55636aa | `packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511` | applied in two commits: f3028c0ee (d2bd-side propagation) + ea55636aa (CredentialRuntime::dependency_facts trait signature Result>, every impl and call site migrated; re-dispatched per Main's directive 2026-09-25) | | | `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d4fe83812 | packages/d2bd/src/composition.rs | dispatch_audit's unrecognized severity arm now returns TypedError::WireInvalidFrame { detail: "audit filter has an invalid severity".to_owned() } instead of InternalIo, so caller input errors surface | | | `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d1a472077 | packages/d2bd/src/composition.rs | ActivationLockGuard::drop now logs finish_activation failures via tracing::warn!(zone = %self.zone, error = %error, ...) instead of `let _ =`, mirroring the file's house style for coordinator refusals | | -| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | applied | 6 | dba2d00f2 | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-13. The audio mutation paths report a user-input refusal through the typed kinds TypedError::AudioVmNotFound (audio-vm-not-found, exit 2) and TypedError::AudioNotEnabled (audio-not-enabled, exit 70) instead of flattening both into TypedError::InternalIo { context, detail }; lock/read/write/host failures keep internal-io. Co-change: the two daemon wire kinds with their envelope text/exit codes/hello-rejection arm, the four mutation-site constructors, and hand-written rows in docs/reference/error-codes.md (the generated block is untouched, so gen_error_codes_drift stays the proof). Wire-visible: a public-socket client that matched internal-io on an unknown or audio-less VM sees the new kinds - the needs-contract move this row asked for; no in-tree consumer branches on the old slug. | | +| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | applied | W6 | dba2d00f2 | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-13. The audio mutation paths report a user-input refusal through the typed kinds TypedError::AudioVmNotFound (audio-vm-not-found, exit 2) and TypedError::AudioNotEnabled (audio-not-enabled, exit 70) instead of flattening both into TypedError::InternalIo { context, detail }; lock/read/write/host failures keep internal-io. Co-change: the two daemon wire kinds with their envelope text/exit codes/hello-rejection arm, the four mutation-site constructors, and hand-written rows in docs/reference/error-codes.md (the generated block is untouched, so gen_error_codes_drift stays the proof). Wire-visible: a public-socket client that matched internal-io on an unknown or audio-less VM sees the new kinds - the needs-contract move this row asked for; no in-tree consumer branches on the old slug. | | | `RS-0534` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | 96be9307a | packages/d2bd/src/resource_plane_v3.rs | ConstructionInputs::production now propagates attach_process_providers failures: state.provider_runtime.attach_process_providers(...).map_err(/error/ PlaneError::Authority(error.into()))? instead of ` | | | `RS-0536` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | fd6778735 | packages/d2bd/src/process_provider_runtime.rs | serving_worker_launch_args now warns when the 0700 enforcement on the worker socket parent fails: tracing::warn!(zone = %zone, socket_dir = %parent.display(), error = %error, ...) mirrors the pidfd sn | | | `RS-0528` | `err` | `d2bd` | low | actionable | family | applied | W5 | 2fa4cd475 | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | TypedError's io, config, and broker-unavailable variants carry an `Option` origin (Arc) built by a bounded helper, Display renders the unchanged envelope string, and the raw-detail logging boundary renders a depth-capped source chain; the 34 owned composition.rs sites plus 67 more sites across d2bd-runtime, audio dispatch, forward rendezvous, and the bundle-tampered test are converted (116 sites legitimately pass None where detail is a literal or wire-field rendering), and a test pins byte-identical envelopes | | @@ -604,39 +604,39 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | a09140432 | packages/d2bd-runtime/src/daemon_version.rs | version-file read failures typed (VersionFileReadError); check + tests green | | | `RS-0543` | `err` | `xtask` | medium | actionable | leaf | applied | U3 | 7194d24e9 | packages/xtask/src/delivery/recovery.rs | RecoveryError::Read added for fs open/read failures; Json(String) now carries the bounded serde detail (field names/positions only via error.to_string(), never payload values, keeping the redaction co | | | `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 6467d8d2c | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | the wire_deserialize! macro moves to d2b-contracts with #[macro_export] and 72 hand-written Wire admission Deserialize impls (17 contracts-provider, 55 contracts-resource) become macro invocations; container attributes, field lists, and admission expressions are token-identical, the emitted schemas are byte-identical, and zone-session's 28 invocations re-point at the shared home (one contracts-broker site is out of this slice's scope) | | -| `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | applied | 6 | f25b21e84 | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu [reconstructed: m with `#[serde(rename_all = "lowercase")]`) keeps the serialized shapes "unknown"/"completed" identical, so no DURABLE_VERSION bump is needed]. DurableRecord.outcome typed as CellOutcome with the derive; hand match and re-parse deleted; unknown-outcome fail-closed preserved via serde unknown-variant rejection mapped to CorruptDurable. | | +| `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | applied | W6 | f25b21e84 | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu [reconstructed: m with `#[serde(rename_all = "lowercase")]`) keeps the serialized shapes "unknown"/"completed" identical, so no DURABLE_VERSION bump is needed]. DurableRecord.outcome typed as CellOutcome with the derive; hand match and re-parse deleted; unknown-outcome fail-closed preserved via serde unknown-variant rejection mapped to CorruptDurable. | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | -| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | applied | 6 | 1ab759f13 | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). AuditExportEntry now carries exactly one payload through the closed AuditExportEntryPayload enum (Record { record } or Error { error }) instead of the independent record/error optional pair, so an entry that carries neither or both is unrepresentable and refused at decode; the emitted members are unchanged (sequence plus exactly one of record or error), so the broker audit page and the public daemon audit page keep their JSON and the legacy_export_entry_line renderer keeps its output. Co-change: the d2b-contracts-broker re-export, d2b-broker/src/audit.rs, the d2b entry-mapping closure, the d2bd-runtime wire literal, and the regenerated docs/reference/daemon-api.md plus docs/reference/schemas/v2/wire-protocol.json. Gate on the merged tree: cargo test -p d2b-contracts rc=0 (120 tests plus 1 doctest, including an_entry_emits_and_admits_exactly_one_payload and an_entry_payload_is_admitted_exactly_once), cargo test -p d2b-broker rc=0, cargo check over the seven touched crates --all-targets rc=0, gen_schemas_drift and gen_daemon_api_drift green. | | -| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | skipped-stale | 6 | 8351954a0 | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> re-verified at HEAD in slice w6-12, which merged into phase-w6-integration (merge b07a7e887): the claim does not hold at HEAD, so no admission edit was made. The audited premise has the guard inverted - serde 1.0.229 refuses unknown members through the CONTAINER's deny_unknown_fields, while the FLATTENED type's own deny_unknown_fields is the inert one, and both audited requests (OpenUnitPidfdRequest, StopUnitRequest) carry the container attribute, so a stray member is refused today and there is no silently-accepted state to repair. Raw probe kept at .scratch/rs0547-flatten-probe.txt (w6-12 worktree): container-deny + inner-lax still refuses the stray member (unknown field `unknownMember`), container-lax + inner-deny and container-lax + inner-lax accept it, and serde_json::from_value and from_slice both refuse. The requested admission pin landed anyway as 8351954a0 (flattened_unit_requests_refuse_unknown_members), so the observed contract is pinned rather than repaired; gate: cargo test -p d2b-contracts-broker rc=0. | | +| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | applied | W6 | 1ab759f13 | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). AuditExportEntry now carries exactly one payload through the closed AuditExportEntryPayload enum (Record { record } or Error { error }) instead of the independent record/error optional pair, so an entry that carries neither or both is unrepresentable and refused at decode; the emitted members are unchanged (sequence plus exactly one of record or error), so the broker audit page and the public daemon audit page keep their JSON and the legacy_export_entry_line renderer keeps its output. Co-change: the d2b-contracts-broker re-export, d2b-broker/src/audit.rs, the d2b entry-mapping closure, the d2bd-runtime wire literal, and the regenerated docs/reference/daemon-api.md plus docs/reference/schemas/v2/wire-protocol.json. Gate on the merged tree: cargo test -p d2b-contracts rc=0 (120 tests plus 1 doctest, including an_entry_emits_and_admits_exactly_one_payload and an_entry_payload_is_admitted_exactly_once), cargo test -p d2b-broker rc=0, cargo check over the seven touched crates --all-targets rc=0, gen_schemas_drift and gen_daemon_api_drift green. | | +| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | skipped-stale | W6 | 8351954a0 | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> re-verified at HEAD in slice w6-12, which merged into phase-w6-integration (merge b07a7e887): the claim does not hold at HEAD, so no admission edit was made. The audited premise has the guard inverted - serde 1.0.229 refuses unknown members through the CONTAINER's deny_unknown_fields, while the FLATTENED type's own deny_unknown_fields is the inert one, and both audited requests (OpenUnitPidfdRequest, StopUnitRequest) carry the container attribute, so a stray member is refused today and there is no silently-accepted state to repair. Raw probe kept at .scratch/rs0547-flatten-probe.txt (w6-12 worktree): container-deny + inner-lax still refuses the stray member (unknown field `unknownMember`), container-lax + inner-deny and container-lax + inner-lax accept it, and serde_json::from_value and from_slice both refuse. The requested admission pin landed anyway as 8351954a0 (flattened_unit_requests_refuse_unknown_members), so the observed contract is pinned rather than repaired; gate: cargo test -p d2b-contracts-broker rc=0. | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | | `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | applied | W5 | e77bf4940 | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | ResourceError deserialization routes through the validating constructor, rejecting a revision for a kind that forbids it and inconsistent retry fields; the wire shape is unchanged | | -| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | 4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | -| `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | applied-variant | 4 | a2cf0e614 | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | applied-variant: consolidated 28 Wire-shape Deserialize impls behind the crate-local wire_deserialize! macro in d2b-contracts-zone-session (canonical home; later waves must reuse it, not write a third macro); parsed_deserialize! requires Self::parse(String) (JSON-string wire), which no Wire-struct impl matches - adopting it would change the wire format the row never asked to change (Main ruling 2026-09-25) | | +| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | +| `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | applied-variant | W4 | a2cf0e614 | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | applied-variant: consolidated 28 Wire-shape Deserialize impls behind the crate-local wire_deserialize! macro in d2b-contracts-zone-session (canonical home; later waves must reuse it, not write a third macro); parsed_deserialize! requires Self::parse(String) (JSON-string wire), which no Wire-struct impl matches - adopting it would change the wire format the row never asked to change (Main ruling 2026-09-25) | | | `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/storage_lifecycle.rs | serde rejects rename_all on struct variants (field attribute); applied the equivalent house pattern #[serde(rename_all_fields = "camelCase")] on the enum container + dropped per-field renames; seriali | | -| `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | applied | 7 | fe7c349ea | `packages/d2b-core/src/bundle_resolver.rs:207` | ZoneNativeIndexDocument declares all six keys nixos-modules/index.nix emits and now denies undeclared ones (the four unread keys are defaulted so a partial index still loads); a new admission test fails without the deny and the four committed index fixtures still parse. Merged cd2b66149. | | +| `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | applied | W7 | fe7c349ea | `packages/d2b-core/src/bundle_resolver.rs:207` | ZoneNativeIndexDocument declares all six keys nixos-modules/index.nix emits and now denies undeclared ones (the four unread keys are defaulted so a partial index still loads); a new admission test fails without the deny and the four committed index fixtures still parse. Merged cd2b66149. | | | `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | | `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | applied | W5 | 6ecf465b7 | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | typed serde structs (rename_all camelCase, deny_unknown_fields) replace the Value-walking assignment codec and the child-create json! literal builder; exact keys, version 1, ascending verb arrays, canonical bytes, and the size bounds are pinned by the transport tests | | -| `RS-0557` | `serde` | `d2b-host` | low | actionable | family | applied | 4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:229` | | | +| `RS-0557` | `serde` | `d2b-host` | low | actionable | family | applied | W4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:229` | | | | `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | | `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | -| `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | 7 | bcdb699ea | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:12` | AuditEvent drops Deserialize (never read back; every site serializes), keeping Serialize and the bounded-MIME adapter, so the audit wire shape is unchanged. Merged ae531b399. | | -| `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | applied | 7 | bf8dc0bc2 | `packages/d2b-provider-command/src/command.rs:48` | both JsonSchema impls publish the exact admission their parse enforces (exec excludes C0/DEL/C1, argv slot gains minLength and the whole-slot brace pattern); CommandArgvSlot::parse refuses control characters in literal slots so schema and parse agree; the generated v3 Command schema moved through its generator, and an ECMA-262 oracle over 1.1M code points found no mismatch. Merged efdd43e7d. | | +| `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W7 | bcdb699ea | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:12` | AuditEvent drops Deserialize (never read back; every site serializes), keeping Serialize and the bounded-MIME adapter, so the audit wire shape is unchanged. Merged ae531b399. | | +| `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | applied | W7 | bf8dc0bc2 | `packages/d2b-provider-command/src/command.rs:48` | both JsonSchema impls publish the exact admission their parse enforces (exec excludes C0/DEL/C1, argv slot gains minLength and the whole-slot brace pattern); CommandArgvSlot::parse refuses control characters in literal slots so schema and parse agree; the generated v3 Command schema moved through its generator, and an ECMA-262 oracle over 1.1M code points found no mismatch. Merged efdd43e7d. | | | `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | d58f183d5 | packages/d2b-provider-device-gpu/src/gpu_argv.rs | deny_unknown_fields added to GpuArgvInput/GpuParams/GpuDisplayConfig (mirroring VideoArgvInput); new rejects_unknown_fields test pins top-level, params-nested, and display-nested rejection. Mutation c | | | `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | applied | W5 | 4cb0daadb | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | the receive path decodes each newline-delimited bridge frame with a typed #[serde(tag = "type", rename_all = "snake_case")] inbound enum mirroring the outbound frame instead of scanning raw bytes for the refresh substring; a frame that fails to decode is rate-limited-diagnosed and dropped, and later frames still refresh (pinned by tests) | | | `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 84b343101 | packages/d2b-provider-display-wayland/src/spec.rs | Inert serde try_from attribute removed; rename_all/deny_unknown_fields and the manual Deserialize + TryFrom kept. | | | `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | -| `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | already-fixed | 7 | 73e163675 | `packages/d2b-provider-network-local/src/driver.rs:296` | the serde failure is no longer dropped - the map_err closure emits a structured warn with the error field before mapping to the toolkit's SpecInvalid; re-verified at 6dc80e258. | | +| `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | already-fixed | W7 | 73e163675 | `packages/d2b-provider-network-local/src/driver.rs:296` | the serde failure is no longer dropped - the map_err closure emits a structured warn with the error field before mapping to the toolkit's SpecInvalid; re-verified at 6dc80e258. | | | `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | U3 | 336a4fd97 | packages/d2b-provider-network-local/src/broker.rs | Four provenance payload builders (resolved_bridge_payload/resolved_route_payload in broker.rs and operations.rs) no longer .ok()-swallow serde_json::to_value(provenance); they now propagate with map_e | | -| `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | applied | 7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:1533` | the take-controller-bootstrap leg now builds a typed TakeControllerBootstrapRequest and parses the typed response; a missing/mistyped result fails the leg with a structured warning instead of reading as not-taken (an explicit taken=false still returns Ok(None)), and the fd stays index 0 (the reply carries exactly one descriptor). Merged f2b98ccfb. | | -| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | applied | 7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9` | deserialization goes through a wire struct plus TryFrom so the derived path runs new()/validate(), and the pinned (hand-authored) schema now records the secret-shape exclusion; a schema-vs-validate agreement probe over 7.9M adversarial identifier pairs found 0 mismatches. Merged 82d6c395d. | | -| `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | applied | 7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:233` | parse_material_json is replaced by derived relayListen/relaySend structs with deny_unknown_fields plus the same value pass; admission is strictly stronger (unknown and duplicate keys are now refused, and no in-tree producer emits either) and a malformed-shape test pins it. Merged 82d6c395d. | | +| `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | applied | W7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:1533` | the take-controller-bootstrap leg now builds a typed TakeControllerBootstrapRequest and parses the typed response; a missing/mistyped result fails the leg with a structured warning instead of reading as not-taken (an explicit taken=false still returns Ok(None)), and the fd stays index 0 (the reply carries exactly one descriptor). Merged f2b98ccfb. | | +| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | applied | W7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9` | deserialization goes through a wire struct plus TryFrom so the derived path runs new()/validate(), and the pinned (hand-authored) schema now records the secret-shape exclusion; a schema-vs-validate agreement probe over 7.9M adversarial identifier pairs found 0 mismatches. Merged 82d6c395d. | | +| `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | applied | W7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:233` | parse_material_json is replaced by derived relayListen/relaySend structs with deny_unknown_fields plus the same value pass; admission is strictly stronger (unknown and duplicate keys are now refused, and no in-tree producer emits either) and a malformed-shape test pins it. Merged 82d6c395d. | | | `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | applied | W5 | 379eb3b33 | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | VsockTransportSettings deserializes through a private wire mirror with TryFrom validation, so untrusted JSON is rejected at the boundary; fields are private with accessors and the wire names and JSON schema are unchanged - the needs-contract verdict is overridden because no wire surface moved | | | `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | applied | U3 | b00a073f2 | packages/d2b-provider-volume-local/src/content.rs | ContentFile/ContentProjection/NetworkConfigContentProjection decode via serde try_from Raw mirrors running validating constructors; Deserialize dropped from evidence types; wire shape unchanged. | | -| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | 4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | +| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | W4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | | `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | | `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | applied-variant | U3 | f1bb96854 | packages/d2bd/src/composition.rs | deny_unknown_fields added to both GatewayGuestConfigFile and GatewayGuestRelayConfigFile. The config-typo test landed as direct deserialization tests on both structs (gateway_guest_config_tests mod), | | -| `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | applied | 7 | 369627b78 | `packages/d2bd/src/composition.rs:20373` | one parse_activation_marker seam refuses any schemaVersion != 1 with a structured warning and all three read sites (read_activation_marker plus both startup loops) go through it, so a future caller cannot adopt a versioned marker without the check. Merged a74fd9b0c. | | +| `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | applied | W7 | 369627b78 | `packages/d2bd/src/composition.rs:20373` | one parse_activation_marker seam refuses any schemaVersion != 1 with a structured warning and all three read sites (read_activation_marker plus both startup loops) go through it, so a future caller cannot adopt a versioned marker without the check. Merged a74fd9b0c. | | | `RS-0577` | `serde` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | declared_fd_kind now matches the seven kebab-case FdKind spellings directly (fifo/socket/char-device/block-device/any/regular/directory) instead of allocating a serde_json::Value::String; behavior ide | | | `RS-0578` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 3e78efe56 | packages/d2bd-runtime/src/wire.rs | parse_request now dispatches the 17 plain verbs (list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio) throug | | | `RS-0579` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | version-file write failures reported through tracing | | @@ -647,7 +647,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | | `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | a94ef37d6 | packages/d2b-provider-activation-nixos/src/controller.rs | all 9 warn! refusal events in ActivationTrust::verify now carry a named refusal field with the exact ActivationVerificationError variant; no correlation identifiers added (ADR 0010/0028 safe). | | | `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 09167b5fa | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | All 62 log:: sites in d2b-clipd.rs converted to tracing:: with named fields; env_logger init replaced by tracing_subscriber::fmt().with_env_filter(...).with_writer(stderr).init() mirroring d2bd; log/e | | -| `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | 7 | e1ab1525f | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:66` | all six interpolated clipd_host log events now emit tracing named fields (quality, mimes, secret, error, pid, protocol). Merged ae531b399. | | +| `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W7 | e1ab1525f | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:66` | all six interpolated clipd_host log events now emit tracing named fields (quality, mimes, secret, error, pid, protocol). Merged ae531b399. | | | `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | | `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml | #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] on reconcile/adopt/poll_operation/update/finalize; per-event provider literal and redacted resource_group field dro | | | `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | cc01388e6 | packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs | reconcile/finalize now carry a tracing instrument span with resource/provider fields; 23 per-event duplicate pairs dropped. Deviation: the row's literal span syntax (fields inside skip) is rejected by | | @@ -655,7 +655,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | | `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | | `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | abc324d2a | packages/d2b-provider-toolkit/src/base/guest.rs | serve_enrolled now emits tracing::warn!(frame_bytes, ...) before dropping a frame GuestFrame::new rejects (empty or oversized), keeping the session up. No correlation identifiers in the record. cargo | | -| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | 4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | applied-variant: method field unavailable at all 3 sites (receive failure precedes decode; readiness/loop failures carry no request); zone+provider added from the route binding | | +| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | applied-variant: method field unavailable at all 3 sites (receive failure precedes decode; readiness/loop failures carry no request); zone+provider added from the route binding | | | `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/relay_transport.rs | | | | `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | | `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | @@ -683,7 +683,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0631` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | ba9873712 | `packages/d2b-broker/src/protocol.rs` | MAX_FRAME_SIZE and connect/bind/send_json_frame/recv_json_frame documented | | | `RS-0632` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 6b709ea9a | `packages/d2b-broker/src/ops/state_dir.rs` | DirKind, PrepareDirRequest/fields, PrepareDirAudit, ReplaceOrCreateResult, prepare_dir and live helpers documented with # Errors | | | `RS-0621` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 1643cd532 | `packages/d2b-broker/src/audit.rs` | field docs on AuditDropSummary/AuditEntry; contract docs on AuditLog::open/audit_drop_summary | | -| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | applied | 4 | 27a3de0bd | `packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b` | | | +| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | applied | W4 | 27a3de0bd | `packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b` | | | | `RS-0622` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 7ac3d8cdf | `packages/d2b-broker/src/ops/host_generation_handoff.rs` | doc comments added per row | | | `RS-0623` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 025b075a8 | `packages/d2b-broker/src/ops/route.rs` | doc comments added per row | | | `RS-0615` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 34f355adf | `packages/d2b-broker/src/ops/usbip_lock.rs` | doc comments added per row | | @@ -707,7 +707,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | e12e51dac | `packages/d2b-contracts-control/src/public_wire.rs` | Docs added to the named request/status types plus UsbipProbeEntry field meanings; # Errors added to ShellName::new (RealmAccentColor::new covered by RS-0643) | | | `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | 5c5b2d478 | `packages/d2b-contracts-control/src/unsafe_local_wire.rs` | Constants documented with the daemon-enforced bounds, wire types one-lined, helper fns and RealmAccentColor::new get # Errors | | | `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | applied | U2 | e5b584959 | `packages/d2b-contracts-control/src/terminal_wire.rs` | One-line docs per DTO plus the redacted-Debug note on session-bearing types | | -| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | applied | 4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | +| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | | `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | | `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/artifact.rs` | doc comments on the artifact id bound, error, type, parse, and accessor | | | `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | e7bba788d | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | none (anchor drift only) | | @@ -727,7 +727,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/state.rs` | Documented AudioStateLock guard semantics (holds the OFD lock; drop releases and closes). | | | `RS-0665` | `docs` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/controller.rs` | Documented the 300s cadence rationale, hoisted 64 into pub const AUDIO_QUEUE_BOUND used by new, with_shared_microphone, and the admission bound test (u64 casts at lease sites). | | | `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | f0210347a,48437393c | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | the Policy::new hunk landed in the policy-unification commit f0210347a (same file as RS-0040); the other three hunks in 48437393c | | -| `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | applied | 4 | 64408bc95 | `src/audit.rs:172, src/audit.rs:174` | | | +| `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | applied | W4 | 64408bc95 | `src/audit.rs:172, src/audit.rs:174` | | | | `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 460a05942 | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | none | | | `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,b8724cd15,ac5e33ab1 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | picker.rs hunks shared commit 018c1dad5 with RS-0041/RS-0042 (index race, see RS-0041) | | | `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,ac5e33ab1,08c2e3648 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | picker.rs hunk shared commit 018c1dad5 (index race, see RS-0041) | | @@ -851,7 +851,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | | `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | applied | W3 | 037e23533 | `driver.rs:437-440, driver.rs:614-617` | | | | `RS-0791` | `perf` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:1006` | | | -| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | applied | 4 | 5c7fbf067 | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | | | +| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | applied | W4 | 5c7fbf067 | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | | | | `RS-0793` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458` | | | | `RS-0790` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:495, manager_backend.rs:449-455` | | | | `RS-0794` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/manager.rs:1390` | | | @@ -864,28 +864,28 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0801` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/process_provider_runtime.rs:333` | | | | `RS-0802` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476` | | | | `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.r` | | | -| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | applied | 4 | 87c3172bc | `public_read_model.rs:117-118` | | | +| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | applied | W4 | 87c3172bc | `public_read_model.rs:117-118` | | | | `RS-0808` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packag` | | | | `RS-0805` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:431` | | | | `RS-0806` | `perf` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:582` | | | | `RS-0807` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:972` | | | -| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | applied | 7 | 8c3c48c0c | `clippy.toml:82` | the three lock entries now name the resolved lock_api paths the parking_lot type aliases point at, so clippy finally fires on every real .lock()/.read()/.write() site; the workspace's unsuppressed sites were taken to zero by the burn-down slices (sanctioned per-site allows or tokio conversions) and the census baseline was regenerated through its own write mode (282 key renames, no count growth). blocking-census --check, check-async-gate and check-provider-crate-layout are green on the flip head; a force-warn probe proves the flipped path matches the real sites while the alias spelling matched none. Merged c31e798ce. | | +| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | applied | W7 | 8c3c48c0c | `clippy.toml:82` | the three lock entries now name the resolved lock_api paths the parking_lot type aliases point at, so clippy finally fires on every real .lock()/.read()/.write() site; the workspace's unsuppressed sites were taken to zero by the burn-down slices (sanctioned per-site allows or tokio conversions) and the census baseline was regenerated through its own write mode (282 key renames, no count growth). blocking-census --check, check-async-gate and check-provider-crate-layout are green on the flip head; a force-warn probe proves the flipped path matches the real sites while the alias spelling matched none. Merged c31e798ce. | | | `RS-0809` | `conc` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/envelope/mod.rs:1146, src/envelope/mod.rs:2144` | | | -| `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | applied | 7 | 50be72eea | `packages/d2b-bus/src/registry.rs:530` | RouteLeaseState.revoked is an AtomicBool with a Release store at remove and Acquire loads at with_active (weakest correct ordering; the latch is one-way), and the two synchronous-path allows are gone; the guard that used to span Operations::begin's mutation no longer serializes it. Merged 01daff2b1. | | +| `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | applied | W7 | 50be72eea | `packages/d2b-bus/src/registry.rs:530` | RouteLeaseState.revoked is an AtomicBool with a Release store at remove and Acquire loads at with_active (weakest correct ordering; the latch is one-way), and the two synchronous-path allows are gone; the guard that used to span Operations::begin's mutation no longer serializes it. Merged 01daff2b1. | | | `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-p` | | | | `RS-0812` | `conc` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96` | | | -| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | applied | 7 | 7e194b77c | `packages/d2b-provider-credential/src/test_support.rs:97` | 27 previously unsuppressed recorder/impl lock sites now carry the sanctioned cfg(test) helper allow (19 in test_support.rs, 7 in the driver test module, 1 in session.rs); synchronous accessors stay synchronous. Merged 78db8d04d. | | -| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | applied-variant | 7 | 7e194b77c | `packages/d2b-provider-device-gpu/src/effects_service.rs:310` | the three gpu_authority_leases lock sites take one sanctioned synchronous-path allow on each enclosing port fn rather than one per call; the Arc type is unchanged because the port is genuinely synchronous. Merged 78db8d04d. | | +| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | applied | W7 | 7e194b77c | `packages/d2b-provider-credential/src/test_support.rs:97` | 27 previously unsuppressed recorder/impl lock sites now carry the sanctioned cfg(test) helper allow (19 in test_support.rs, 7 in the driver test module, 1 in session.rs); synchronous accessors stay synchronous. Merged 78db8d04d. | | +| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | applied-variant | W7 | 7e194b77c | `packages/d2b-provider-device-gpu/src/effects_service.rs:310` | the three gpu_authority_leases lock sites take one sanctioned synchronous-path allow on each enclosing port fn rather than one per call; the Arc type is unchanged because the port is genuinely synchronous. Merged 78db8d04d. | | | `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-` | | | -| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | applied | 7 | 7e194b77c | `packages/d2b-provider-device-usbip/src/test_support.rs:46` | five sanctioned cfg(test) helper allows cover the seven recorder lock sites; no field or type changed. Merged 78db8d04d. | | -| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | applied | 7 | e4277787d | `packages/d2b-provider-guest/src/driver.rs:507` | GuestStatusSink is Arc>> and every write (guest effects service, d2bd resource runtime) awaits it; d2bd was the only external consumer. Merged 8c0715d2f. | | -| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | applied | 7 | e4277787d | `packages/d2b-provider-guest/src/test_support.rs:68` | recorders moved to the toolkit SharedLog, tokio locks with async accessors, or std::sync locks with sanctioned cfg(test) helper allows where a sync trait accessor forces it; parking_lot dropped from the crate and the async-gate inventory and policy-input closures regenerated. Merged 8c0715d2f. | | -| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | applied | 7 | 764d87ef9 | `packages/d2b-provider-process/src/driver.rs:680` | EphemeralRuntime's two clocks are tokio::sync::Mutex and all six accessors are async, awaited by every call site; the crate's remaining unsuppressed sites are test-only state under sanctioned cfg(test) helper allows, taking the crate's post-flip census to 0. Merged 849f2974b. | | +| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | applied | W7 | 7e194b77c | `packages/d2b-provider-device-usbip/src/test_support.rs:46` | five sanctioned cfg(test) helper allows cover the seven recorder lock sites; no field or type changed. Merged 78db8d04d. | | +| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | applied | W7 | e4277787d | `packages/d2b-provider-guest/src/driver.rs:507` | GuestStatusSink is Arc>> and every write (guest effects service, d2bd resource runtime) awaits it; d2bd was the only external consumer. Merged 8c0715d2f. | | +| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | applied | W7 | e4277787d | `packages/d2b-provider-guest/src/test_support.rs:68` | recorders moved to the toolkit SharedLog, tokio locks with async accessors, or std::sync locks with sanctioned cfg(test) helper allows where a sync trait accessor forces it; parking_lot dropped from the crate and the async-gate inventory and policy-input closures regenerated. Merged 8c0715d2f. | | +| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | applied | W7 | 764d87ef9 | `packages/d2b-provider-process/src/driver.rs:680` | EphemeralRuntime's two clocks are tokio::sync::Mutex and all six accessors are async, awaited by every call site; the crate's remaining unsuppressed sites are test-only state under sanctioned cfg(test) helper allows, taking the crate's post-flip census to 0. Merged 849f2974b. | | | `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.` | | | | `RS-0821` | `conc` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:43, src/testing.rs:79` | | | | `RS-0822` | `conc` | `d2b-provider-toolkit` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-toolkit/src/operations/envelope.rs:487` | | | | `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-uni` | | | -| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | applied | 7 | 89961f9d9 | `packages/d2b-provider-user/src/test_support.rs:47` | the five recorder/fake fields are tokio::sync::Mutex with the host-sibling accessor split (11 awaited locks, 7 sync try_locks), 18 lock sites converted, parking_lot dropped from the crate, and the async-gate inventory entries rewritten through its write mode. Merged 47ba61aec. | | +| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | applied | W7 | 89961f9d9 | `packages/d2b-provider-user/src/test_support.rs:47` | the five recorder/fake fields are tokio::sync::Mutex with the host-sibling accessor split (11 awaited locks, 7 sync try_locks), 18 lock sites converted, parking_lot dropped from the crate, and the async-gate inventory entries rewritten through its write mode. Merged 47ba61aec. | | | `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_sup` | | | | `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-bindin` | | | | `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone` | | | @@ -895,15 +895,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src` | | | | `RS-0832` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs` | | | | `RS-0833` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414` | | | -| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | 7 | 04cf64c5d | `packages/d2bd-runtime/src/unsafe_local_helper.rs:26` | the four registry/connection/ledger fields are tokio::sync::Mutex and all 39 lock sites reach the tokio seat, through a lock_registry dual seat (blocking_lock off-runtime, bounded try-lock spin on the in-runtime --once path where plain blocking_lock panics) - the panic was reproduced in d2bd's bundle_tampered_envelope test with the plain seat. Merged e65d4954e. | | -| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | 7 | 04cf64c5d | `packages/d2bd-runtime/src/concurrency.rs:163` | OpLockManager::acquire's four try_lock+spin_loop loops are replaced by blocking seats for the production d2b-conn handler threads (a contended op parks instead of burning a core), with the bounded spin kept only on the in-runtime --once path where the blocking seats panic; the stale spin doc is deleted and the dual-seat ordering recorded. Merged e65d4954e. | | +| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | W7 | 04cf64c5d | `packages/d2bd-runtime/src/unsafe_local_helper.rs:26` | the four registry/connection/ledger fields are tokio::sync::Mutex and all 39 lock sites reach the tokio seat, through a lock_registry dual seat (blocking_lock off-runtime, bounded try-lock spin on the in-runtime --once path where plain blocking_lock panics) - the panic was reproduced in d2bd's bundle_tampered_envelope test with the plain seat. Merged e65d4954e. | | +| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | W7 | 04cf64c5d | `packages/d2bd-runtime/src/concurrency.rs:163` | OpLockManager::acquire's four try_lock+spin_loop loops are replaced by blocking seats for the production d2b-conn handler threads (a contended op parks instead of burning a core), with the bounded spin kept only on the in-runtime --once path where the blocking seats panic; the stale spin doc is deleted and the dual-seat ordering recorded. Merged e65d4954e. | | | `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support` | | | | `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | 9b64eaa27 | packages/d2b-broker/src/runtime.rs (reap fn; kernel_ops.rs callers) | bounded WNOHANG reap poll replaces the blocking waitid; orphaned helpers deleted | | | `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | 25dfa3aee | packages/d2b-broker/src/sys.rs, packages/d2b-broker/src/ops/swtpm_dir.rs | setfacl shellout moved behind an async wrapper on a bounded worker | | | `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | a6d8fb022 | packages/d2b-broker/src/ops/media.rs | nss group lookup hoisted to a LazyLock, off the per-write path | | | `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | f4f09c74c | packages/d2b-broker/src/ops/host_generation_handoff.rs | flock wait moved to a bounded worker (sanctioned allow reason) | | | `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | -| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | applied | 7 | 1f8e52a5f | `packages/d2b-broker/src/runtime.rs:7711` | the whole USB-audit serial HMAC keyring body hops onto the d2b-core bounded loader probe seat, so no blocking stat/mkdir/open/create/fchmod/fsync runs on an executor worker; every hardening check is preserved verbatim (0o700 root-owned dir, O_NOFOLLOW plus O_CLOEXEC open, descriptor-level root-only validation, dir-fd openat create with 0o400 and file+dir fsync) and the existing keyring test passes unchanged. The whole-body hop was chosen over tokio::fs legs because path_safe's openat-on-dir_fd chain has no path-based equivalent. Merged d9a91015a. | | +| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | applied | W7 | 1f8e52a5f | `packages/d2b-broker/src/runtime.rs:7711` | the whole USB-audit serial HMAC keyring body hops onto the d2b-core bounded loader probe seat, so no blocking stat/mkdir/open/create/fchmod/fsync runs on an executor worker; every hardening check is preserved verbatim (0o700 root-owned dir, O_NOFOLLOW plus O_CLOEXEC open, descriptor-level root-only validation, dir-fd openat create with 0o400 and file+dir fsync) and the existing keyring test passes unchanged. The whole-body hop was chosen over tokio::fs legs because path_safe's openat-on-dir_fd chain has no path-based equivalent. Merged d9a91015a. | | | `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | ProcessLaunchEffectPort and ProcessProvider declare their methods as `async fn` (the RPITIT `impl Future + Send` form is retired) under the house `#[allow(async_fn_in_trait)]` that the pinned lint configuration requires; default bodies are plain async blocks, implementors and the single Send-bound caller keep working, and the bazel graphs re-point consumer test targets at the test-support variants so each crate keeps one instance | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | applied | W3 | 7de088b5d | `packages/d2b-provider/src/agent.rs:316-324` | | | | `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-cre` | | | @@ -912,11 +912,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/observe.rs:255-260` | | | | `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:30, src/testing.rs:19` | | | | `RS-0850` | `async` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833` | | | -| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | applied | 7 | 89961f9d9 | `packages/d2b-provider-user/src/probe.rs:48` | the three blocking NSS reads now run on the d2b-core bounded loader probe seat (run_probe: one thread, bounded sync_channel admission, oneshot reply); a seat refusal maps to SystemCoreError::DiscoveryUnavailable with a structured warning, the whole blocking body (identity digest and bindings) is built on the worker, and a throwaway smoke test resolved the real NSS root through the seat. Cargo.toml/BUILD.bazel gained the d2b-core dep and the policy-input closures were regenerated. Merged 47ba61aec. | | +| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | applied | W7 | 89961f9d9 | `packages/d2b-provider-user/src/probe.rs:48` | the three blocking NSS reads now run on the d2b-core bounded loader probe seat (run_probe: one thread, bounded sync_channel admission, oneshot reply); a seat refusal maps to SystemCoreError::DiscoveryUnavailable with a structured warning, the whole blocking body (identity digest and bindings) is built on the worker, and a throwaway smoke test resolved the real NSS root through the seat. Cargo.toml/BUILD.bazel gained the d2b-core dep and the policy-input closures were regenerated. Merged 47ba61aec. | | | `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | -| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | applied | 7 | 6e8f34406 | `packages/d2bd/src/interaction_composition.rs:5546` | InteractionRuntimeSet holds per-Zone Arc handles; the daemon-global lock is taken only to clone the handle and released before the Zone lock, so no global guard spans the dispatch await. The residual note is deleted and a named concurrency test proves two Zones' sessions no longer serialize. Merged fffe5afee. | | -| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | applied | 7 | 6e8f34406 | `packages/d2bd/src/shared_provider_effects.rs:354` | runtime()/plane() are async seats awaiting the plane slot (13 call sites) and the two sync GPU authority seats use a fail-closed try_runtime() per the TPM precedent; NetworkRuntime::bundle is async across both impls and the caller, so both try_lock+spin loops are gone; the async-gate inventory was regenerated. Merged fffe5afee. | | -| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | applied-variant | 4 | 87c3172bc | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | applied-variant: drainer tasks spawn on the daemon's own tokio runtime handle instead of a new dedicated runtime (audit-sanctioned) | | +| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | applied | W7 | 6e8f34406 | `packages/d2bd/src/interaction_composition.rs:5546` | InteractionRuntimeSet holds per-Zone Arc handles; the daemon-global lock is taken only to clone the handle and released before the Zone lock, so no global guard spans the dispatch await. The residual note is deleted and a named concurrency test proves two Zones' sessions no longer serialize. Merged fffe5afee. | | +| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | applied | W7 | 6e8f34406 | `packages/d2bd/src/shared_provider_effects.rs:354` | runtime()/plane() are async seats awaiting the plane slot (13 call sites) and the two sync GPU authority seats use a fail-closed try_runtime() per the TPM precedent; NetworkRuntime::bundle is async across both impls and the caller, so both try_lock+spin loops are gone; the async-gate inventory was regenerated. Merged fffe5afee. | | +| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | applied-variant | W4 | 87c3172bc | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | applied-variant: drainer tasks spawn on the daemon's own tokio runtime handle instead of a new dedicated runtime (audit-sanctioned) | | | `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 406f13d98 | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broke` | | | | `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | skipped-stale | W3 | 406f13d98 | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | The row's premise does not hold at the pinned versions: `pre_exec` is an `unsafe` method on tokio 1.53.1's `Process` (Cargo.lock:4472) and on `std::process::Command`, so the unsafe block at packages/d2b-broker/src/ops/disk_init.rs:674 cannot be removed. [reconstructed: verified from the code and the lockfile; the wave-3 close artifact carries the original reasoning at lines 15 and 92.] | | | `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | applied | W3 | 3886cfd7b | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | @@ -925,8 +925,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0861` | `macro` | `d2b-resource-api` | low | actionable | leaf | applied-variant | W3 | 81b2ef867 | `service.rs:2245-2267` | | | | `RS-0862` | `macro` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643` | | | | `RS-0863` | `macro` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/s` | | | -| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | applied | 4 | 776ddb336 | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | | | -| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | applied-variant | 4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | applied-variant: feature wired to the registration integration test via [[test]] required-features (house pattern d2b-provider-host/Cargo.toml:28) instead of a #[cfg(feature)] module - the crates have no test-support module and BUILD.bazel *_test_support targets consume the feature | | +| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W4 | 776ddb336 | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | | | +| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | applied-variant: feature wired to the registration integration test via [[test]] required-features (house pattern d2b-provider-host/Cargo.toml:28) instead of a #[cfg(feature)] module - the crates have no test-support module and BUILD.bazel *_test_support targets consume the feature | | | `RS-0880` | `test` | `d2b` | medium | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:227-239` | | | | `RS-0881` | `test` | `d2b` | low | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:383-397` | | | | `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | applied | W3 | b80491dde | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | @@ -943,7 +943,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0877` | `test` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/tests/bundle_resolver_tamper.rs:149` | | | | `RS-0875` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority.rs:1824, authority.rs:1968, authority.rs:1899` | | | | `RS-0876` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority_persistence.rs:246-320` | | | -| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | applied | 4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:245` | | | +| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | applied | W4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:245` | | | | `RS-0879` | `test` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/bin/d2b-activation-helper.rs:792` | | | | `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activ` | | | | `RS-0883` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/authority.rs:26-31, src/authority.rs:236-241` | | | @@ -970,7 +970,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0904` | `test` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:145, metric_policy.rs:150` | | | | `RS-0905` | `test` | `d2b-provider-provider` | medium | actionable | leaf | applied | W3 | 55b7d20a6 | `src/providers.rs:206, src/driver.rs:1147` | | | | `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied-variant | W3 | 55b7d20a6 | `tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.r` | | | -| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | applied | 7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:2012` | the source scrape and its literal name list are gone: PIDFD_DISPATCH_FAILURE_KINDS is a shared const in d2b-contracts-broker, LiveHandlerError maps its variants through it, and the supervisor test asserts against the constant with every behavior assertion kept. Merged f2b98ccfb. | | +| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | applied | W7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:2012` | the source scrape and its literal name list are gone: PIDFD_DISPATCH_FAILURE_KINDS is a shared const in d2b-contracts-broker, LiveHandlerError maps its variants through it, and the supervisor test asserts against the constant with every behavior assertion kept. Merged f2b98ccfb. | | | `RS-0908` | `test` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230` | | | | `RS-0909` | `test` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-transport-vsock/tests/observe.rs:14-15` | | | | `RS-0910` | `test` | `d2b-provider-user` | medium | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs` | | | From 304fdb3324b7e9499d32506471111bab6ea7f9c0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 01:00:50 -0700 Subject: [PATCH 705/726] fix(audit): repair the review findings the audit remediation carried An independent review of the remediation branch returned a verdict of request-changes. Each finding was re-derived against the committed head before being accepted; one was refuted and is recorded as such on the pull request rather than acted on. The ratchet regression is mine. Two shared-family-knowledge exemptions were added for tokens the target module does not contain, against that file's own rule that the list only shrinks and no row may be added. A row for a signal the tree does not carry is standing pre-authorization for the reintroduction the ratchet exists to catch, so both rows are deleted. Three more are behavior changes the mechanical pass made by accident. A mutating request that selects neither flag lost its `default` while the mode became a closed enum decoded through `try_from`, so the same input moved from a typed `InvalidRequest` envelope with its remediation string to a wire decode failure across seven public verbs; the mode is optional again and the daemon refuses the no-mode case with the envelope. A typed fail-closed check on a persisted Azure VM recovery record became a panic on the decode path. And the live services DTO lost the wire pin that was its only guard. The audit record itself is repaired: 124 findings rows had anchor cells truncated mid-path and now carry the full `path:line`, the W7 row's count matched 48 rows against the table's 52, one row's commit named an object this repository does not have, one row's anchor spliced two crate paths into a path that exists nowhere, and the W7 row pointed its per-row evidence at a gitignored scratch path. Eleven rows gained their closing pipe. The non-ASCII damage is confined to the ideographic full stops and one spliced CJK character the mechanical pass left in doc comments; the deliberate typography the tree already uses is untouched. --- changelog.d/audit-review-remediation.md | 21 ++ changelog.d/fix-wave3-gate-breaks.md | 4 +- .../w3-10-contracts-resource-status-size.md | 2 - changelog.d/w3-12-core-bundle-resolver.md | 2 - changelog.d/w3-15-clipboard-perf-tests.md | 2 - changelog.d/w3-16-config-nixos-parse-tests.md | 2 - changelog.d/w3-33-sk-frontend-uhid.md | 2 - changelog.d/w3-37-d2bd-perf.md | 6 +- .../w4-03-contracts-store-digests-errors.md | 2 - .../w6-13-d2bd-structured-error-kinds.md | 4 +- .../2026-09-24-rust-skills-audit/ledger.md | 268 +++++++++--------- packages/d2b-broker/src/audit.rs | 6 +- packages/d2b-broker/src/envelope/mod.rs | 22 +- packages/d2b-broker/src/forwarding.rs | 8 +- packages/d2b-broker/src/lib.rs | 4 +- packages/d2b-broker/src/live_handlers.rs | 26 +- packages/d2b-broker/src/ops/cgroup.rs | 24 +- packages/d2b-broker/src/ops/device_worker.rs | 14 +- packages/d2b-broker/src/ops/exec_reconcile.rs | 4 +- packages/d2b-broker/src/ops/media.rs | 4 +- packages/d2b-broker/src/ops/nm.rs | 4 +- packages/d2b-broker/src/ops/pidfd.rs | 2 +- packages/d2b-broker/src/ops/spawn_runner.rs | 2 +- packages/d2b-broker/src/ops/state_dir.rs | 6 +- .../d2b-broker/src/ops/store_sync_export.rs | 4 +- .../d2b-broker/src/ops/store_view_posture.rs | 4 +- packages/d2b-broker/src/ops/swtpm_dir.rs | 26 +- packages/d2b-broker/src/ops/sysctl.rs | 2 +- packages/d2b-broker/src/ops/usbip_host.rs | 2 +- packages/d2b-broker/src/ops/usbip_lock.rs | 6 +- packages/d2b-broker/src/runtime.rs | 50 ++-- packages/d2b-broker/src/state_cells.rs | 6 +- packages/d2b-broker/src/sys.rs | 52 ++-- .../tests/pidfd_handoff_scm_rights.rs | 2 +- .../d2b-broker/tests/socket_activation.rs | 6 +- packages/d2b-bus/src/authorization.rs | 4 +- packages/d2b-bus/src/router.rs | 28 +- packages/d2b-bus/src/session/contract.rs | 4 +- packages/d2b-bus/src/streams.rs | 2 +- .../d2b-contracts-broker/src/broker_wire.rs | 22 +- .../d2b-contracts-control/src/cli_output.rs | 64 ++++- .../d2b-contracts-control/src/public_wire.rs | 107 ++++--- .../src/v3/credential.rs | 2 +- .../d2b-contracts-provider/src/v3/provider.rs | 18 +- .../src/v3/semantic_services/audio.rs | 18 +- .../src/v3/semantic_services/mod.rs | 30 +- .../src/v3/semantic_services/security_key.rs | 12 +- .../src/v3/semantic_services/telemetry.rs | 10 +- .../src/v3/semantic_services/usb.rs | 4 +- .../d2b-contracts-resource/src/v3/device.rs | 8 +- .../d2b-contracts-resource/src/v3/host.rs | 8 +- .../d2b-contracts-resource/src/v3/limits.rs | 8 +- .../d2b-contracts-resource/src/v3/network.rs | 4 +- .../src/v3/operations/seal.rs | 6 +- .../src/v3/resource_schema.rs | 12 +- .../d2b-contracts-resource/src/v3/user.rs | 4 +- .../d2b-contracts-resource/src/v3/volume.rs | 2 +- .../src/v3/resource_export.rs | 2 +- .../src/v3/resource_import.rs | 2 +- .../src/v3/zone_session.rs | 12 +- packages/d2b-contracts/src/error.rs | 6 +- packages/d2b-contracts/src/lib.rs | 2 +- packages/d2b-contracts/src/types.rs | 2 +- .../d2b-contracts/src/workload_identity.rs | 12 +- packages/d2b-core/src/bundle_resolver.rs | 28 +- packages/d2b-core/src/host.rs | 6 +- packages/d2b-core/src/manifest_v04.rs | 2 +- packages/d2b-core/src/processes.rs | 8 +- packages/d2b-core/src/site.rs | 6 +- packages/d2b-core/src/static_invariants.rs | 4 +- .../d2b-host/src/bin/d2b-activation-helper.rs | 2 +- packages/d2b-host/src/bridge_port.rs | 8 +- packages/d2b-host/src/cgroup.rs | 66 ++--- packages/d2b-host/src/devices.rs | 4 +- packages/d2b-host/src/hardlink_farm.rs | 18 +- packages/d2b-host/src/host_prep_dag.rs | 14 +- packages/d2b-host/src/modules.rs | 40 +-- packages/d2b-host/src/nftables.rs | 8 +- packages/d2b-host/src/ownership_matrix.rs | 2 +- .../src/driver.rs | 10 +- .../src/clipd_host/wayland.rs | 2 +- .../src/picker.rs | 2 +- .../d2b-provider-config-nixos/src/ttrpc.rs | 24 +- .../src/lib.rs | 2 +- .../d2b-provider-credential/src/driver.rs | 8 +- .../d2b-provider-credential/src/session.rs | 2 +- .../d2b-provider-device-gpu/src/gpu_argv.rs | 8 +- .../d2b-provider-device-gpu/src/video_argv.rs | 18 +- .../src/driver.rs | 10 +- .../src/relay_service.rs | 6 +- .../src/effects_service.rs | 4 +- .../d2b-provider-device-tpm/src/swtpm_argv.rs | 18 +- .../d2b-provider-device-usbip/src/driver.rs | 6 +- .../src/state_machine.rs | 4 +- .../src/bin/d2b-wayland-proxy.rs | 4 +- .../src/controller.rs | 2 +- .../src/session_children.rs | 2 +- .../src/wayland_proxy/bridge.rs | 2 +- .../src/wayland_proxy/filter.rs | 2 +- .../src/wayland_proxy/policy.rs | 4 +- packages/d2b-provider-endpoint/src/driver.rs | 6 +- .../src/controller/mod.rs | 34 ++- .../src/hotplug.rs | 2 +- packages/d2b-provider-guest/src/driver.rs | 16 +- .../d2b-provider-guest/src/effects_service.rs | 4 +- packages/d2b-provider-guest/src/shutdown.rs | 2 +- .../d2b-provider-guest/src/test_support.rs | 6 +- packages/d2b-provider-host/src/driver.rs | 16 +- .../d2b-provider-host/src/test_support.rs | 2 +- .../d2b-provider-network-local/src/driver.rs | 4 +- .../tests/network_family.rs | 4 +- .../src/metrics.rs | 2 +- .../src/launch.rs | 6 +- .../src/effects_service.rs | 8 +- .../src/operations.rs | 10 +- packages/d2b-provider-process/src/driver.rs | 20 +- .../src/effects_service.rs | 2 +- .../src/launch_identity.rs | 2 +- .../d2b-provider-process/src/operations.rs | 4 +- packages/d2b-provider-provider/src/driver.rs | 18 +- packages/d2b-provider-role/src/rbac.rs | 2 +- .../src/resources/pool.rs | 2 +- .../src/resources/session.rs | 2 +- .../d2b-provider-supervisor/src/broker.rs | 2 +- .../d2b-provider-supervisor/src/systemd.rs | 2 +- .../d2b-provider-system-core/src/error.rs | 2 +- packages/d2b-provider-system-core/src/host.rs | 6 +- packages/d2b-provider-system-core/src/lib.rs | 2 +- .../d2b-provider-system-core/src/testing.rs | 4 +- .../src/driver.rs | 8 +- .../d2b-provider-telemetry-binding/src/lib.rs | 2 +- .../src/driver.rs | 14 +- .../d2b-provider-telemetry-service/src/lib.rs | 4 +- .../src/shared_provider.rs | 14 +- .../src/testing/conformance.rs | 4 +- .../src/auth.rs | 6 +- .../src/settings.rs | 2 +- packages/d2b-provider-user/src/driver.rs | 10 +- .../d2b-provider-volume-binding/src/driver.rs | 10 +- .../d2b-provider-volume-local/src/adapter.rs | 4 +- .../d2b-provider-volume-local/src/content.rs | 2 +- .../src/bindings.rs | 2 +- packages/d2b-provider-volume/src/driver.rs | 6 +- .../src/audio_registry.rs | 2 +- .../src/effects_service.rs | 4 +- .../src/interaction.rs | 16 +- .../d2b-provider-zone-link/src/zone_links.rs | 12 +- packages/d2b-provider/src/agent.rs | 2 +- packages/d2b-resource-api/src/admission.rs | 2 +- .../d2b-resource-api/src/manager_backend.rs | 10 +- .../src/manager_backend/tests.rs | 12 +- packages/d2b-resource-api/src/service.rs | 2 +- packages/d2b-resource-compiler/src/lib.rs | 4 +- packages/d2b-resource-runtime/src/context.rs | 18 +- packages/d2b-resource-runtime/src/error.rs | 8 +- packages/d2b-resource-runtime/src/manager.rs | 22 +- packages/d2b-resource-runtime/src/metadata.rs | 2 +- packages/d2b-resource-runtime/src/resource.rs | 6 +- .../d2b-resource-runtime/src/spec_store.rs | 4 +- packages/d2b-resource-runtime/src/target.rs | 4 +- packages/d2b-resource-types/src/metadata.rs | 2 +- packages/d2b-sk-frontend/src/uhid.rs | 2 +- packages/d2b-telemetry/src/emitter.rs | 2 +- packages/d2b-zone-routing/src/enrollment.rs | 2 +- packages/d2b-zone-routing/src/resolver.rs | 10 +- packages/d2b-zone-routing/src/service.rs | 6 +- packages/d2b/src/context.rs | 2 +- packages/d2b/src/dispatch.rs | 2 +- packages/d2b/src/doctor.rs | 12 +- packages/d2b/src/exec_client.rs | 6 +- packages/d2b/src/host_validate.rs | 12 +- packages/d2b/tests/auth_status_contract.rs | 6 +- packages/d2bd-runtime/src/autostart.rs | 14 +- packages/d2bd-runtime/src/ch_api.rs | 18 +- packages/d2bd-runtime/src/console_session.rs | 6 +- packages/d2bd-runtime/src/daemon_audit.rs | 4 +- packages/d2bd-runtime/src/daemon_config.rs | 2 +- packages/d2bd-runtime/src/exec_session.rs | 6 +- .../d2bd-runtime/src/kernel_module_check.rs | 18 +- packages/d2bd-runtime/src/metrics.rs | 2 +- packages/d2bd-runtime/src/pidfs_probe.rs | 2 +- .../d2bd-runtime/src/public_projection.rs | 2 +- packages/d2bd-runtime/src/readiness.rs | 4 +- packages/d2bd-runtime/src/runtime_process.rs | 10 +- .../src/ssh_host_key_preflight.rs | 6 +- .../src/supervisor/pidfd_table.rs | 4 +- packages/d2bd-runtime/src/typed_error.rs | 4 +- packages/d2bd/src/audio_host_controller.rs | 4 +- packages/d2bd/src/composition.rs | 155 +++++----- packages/d2bd/src/forward_rendezvous.rs | 14 +- packages/d2bd/src/process_provider_runtime.rs | 14 +- packages/d2bd/src/provider_lifecycle.rs | 2 +- packages/d2bd/src/resource_plane_v3.rs | 22 +- packages/d2bd/src/resource_runtime.rs | 12 +- packages/d2bd/src/shared_provider_effects.rs | 14 +- packages/xtask/src/blocking_census.rs | 22 +- packages/xtask/src/changelog.rs | 20 +- packages/xtask/src/nix_inventories.rs | 4 +- packages/xtask/src/provider_crate_policy.rs | 20 +- packages/xtask/src/provider_packaging.rs | 2 +- packages/xtask/src/resource_type_authority.rs | 2 +- packages/xtask/src/zone_schema.rs | 6 +- 202 files changed, 1199 insertions(+), 1062 deletions(-) create mode 100644 changelog.d/audit-review-remediation.md diff --git a/changelog.d/audit-review-remediation.md b/changelog.d/audit-review-remediation.md new file mode 100644 index 000000000..cf75c0195 --- /dev/null +++ b/changelog.d/audit-review-remediation.md @@ -0,0 +1,21 @@ +### Fixed + +- A mutating request that sets neither `dryRun` nor `apply` decodes again + instead of failing admission, so the daemon refuses it through the same + structured `InvalidRequest` outcome and remediation string every other + invalid mutating request gets, rather than an opaque frame error. +- A persisted Azure VM recovery record whose legacy operation pair is only + half present now fails its decode with a typed error instead of aborting the + thread, and the restore documentation no longer promises a predicate that + the collapsed pair no longer needs. +- The `StatusServicesOutputV2` wire shape is pinned again, including the + asymmetry where only `qemuMedia` is omitted when absent while the four + sidecar fields serialize an explicit `null`. + +### Changed + +- Two `shared-family-knowledge` ratchet exemptions that named tokens the + target module does not contain are removed; the list only ever shrinks. +- Seven changelog fragments no longer open with a filename title line the + fragment parsers reject, and internal audit identifiers are out of the + release prose. diff --git a/changelog.d/fix-wave3-gate-breaks.md b/changelog.d/fix-wave3-gate-breaks.md index e9f4e4d94..538baa475 100644 --- a/changelog.d/fix-wave3-gate-breaks.md +++ b/changelog.d/fix-wave3-gate-breaks.md @@ -1,5 +1,3 @@ -# `fix-wave3-gate-breaks.md` - ### Fixed -- The wave-3 integration merge left the workspace gate red: the status-size single-pass change dropped the last non-test use of `canonical_json_bytes` in the v3 resource status contract while its import stayed at module scope, the telemetry meter registry kept a module-scope import used only by tests, the test-support runner-intent rebuild hook still read the pre-merge flat guest intent map after the resolver nested it per zone, the CLI receive-buffer slice added a `std::sync::Mutex` critical section without the sanctioned CLI-only allow its sibling sites carry (tripping the blocking census), the nftables/hosts renderers wrote trailing-newline format strings with `write!` where the newline form trips the clippy gate, the clipboard controller's route-shape validators and their tests exceeded the clippy argument and type-complexity limits, and the merged `Cargo.lock` and the async-gate inventory were never regenerated after wave-3 slices changed dependencies and marker sites, leaving the policy-input closures and the inventory stale. The imports now live at their test-module use sites, the hook iterates the nested map, the receive-buffer lock carries the per-site allow, the renderers use `writeln!`, the route-shape checks take a plain-field shape struct, and the lock, policy inputs, and async-gate inventory are regenerated, so `cargo check --workspace --all-targets`, the blocking census, the policy-input check, the async-gate check, the clippy gate, and the Layer-1 gate lanes are green again. \ No newline at end of file +- A cross-slice merge left the workspace gate red: the status-size single-pass change dropped the last non-test use of `canonical_json_bytes` in the v3 resource status contract while its import stayed at module scope, the telemetry meter registry kept a module-scope import used only by tests, the test-support runner-intent rebuild hook still read the pre-merge flat guest intent map after the resolver nested it per zone, the CLI receive-buffer slice added a `std::sync::Mutex` critical section without the sanctioned CLI-only allow its sibling sites carry (tripping the blocking census), the nftables/hosts renderers wrote trailing-newline format strings with `write!` where the newline form trips the clippy gate, the clipboard controller's route-shape validators and their tests exceeded the clippy argument and type-complexity limits, and the merged `Cargo.lock` and the async-gate inventory were never regenerated after wave-3 slices changed dependencies and marker sites, leaving the policy-input closures and the inventory stale. The imports now live at their test-module use sites, the hook iterates the nested map, the receive-buffer lock carries the per-site allow, the renderers use `writeln!`, the route-shape checks take a plain-field shape struct, and the lock, policy inputs, and async-gate inventory are regenerated, so `cargo check --workspace --all-targets`, the blocking census, the policy-input check, the async-gate check, the clippy gate, and the Layer-1 gate lanes are green again. \ No newline at end of file diff --git a/changelog.d/w3-10-contracts-resource-status-size.md b/changelog.d/w3-10-contracts-resource-status-size.md index 79cf59f6f..54fb13ea5 100644 --- a/changelog.d/w3-10-contracts-resource-status-size.md +++ b/changelog.d/w3-10-contracts-resource-status-size.md @@ -1,5 +1,3 @@ -# `w3-10-contracts-resource-status-size.md` - ### Changed - Building a v3 `ResourceStatus` now enforces the 64 KiB status-size bound diff --git a/changelog.d/w3-12-core-bundle-resolver.md b/changelog.d/w3-12-core-bundle-resolver.md index 68adfb5fc..73908d8c1 100644 --- a/changelog.d/w3-12-core-bundle-resolver.md +++ b/changelog.d/w3-12-core-bundle-resolver.md @@ -1,5 +1,3 @@ -# `w3-12-core-bundle-resolver.md` - ### Changed - Zone bundle lookups no longer re-parse resource-bundle JSON or allocate composite keys per call: zone UID presence/identity, network-spec resolution, and guest setup descriptor / VMM intent lookups now read the bundles parsed once at load and borrow (zone, guest) keys from per-zone nested maps, so intent resolution allocates less on bundles with many zones. diff --git a/changelog.d/w3-15-clipboard-perf-tests.md b/changelog.d/w3-15-clipboard-perf-tests.md index 95dcc2b0d..2720e4f1f 100644 --- a/changelog.d/w3-15-clipboard-perf-tests.md +++ b/changelog.d/w3-15-clipboard-perf-tests.md @@ -1,5 +1,3 @@ -# `w3-15-clipboard-perf-tests.md` - ### Changed - d2b-clipd now shares clipboard payload maps by reference instead of diff --git a/changelog.d/w3-16-config-nixos-parse-tests.md b/changelog.d/w3-16-config-nixos-parse-tests.md index b9a09359b..bc6a2a84f 100644 --- a/changelog.d/w3-16-config-nixos-parse-tests.md +++ b/changelog.d/w3-16-config-nixos-parse-tests.md @@ -1,5 +1,3 @@ -# `w3-16-config-nixos-parse-tests.md` - ### Changed - The config-nixos RPC boundary now decodes each request into its typed form once and validates the typed value, removing a redundant JSON parse and the admission-time base64 decode of Stage payloads (up to ~683 KiB); Stage document bounds are still enforced when the staging store applies the document, and the backend hop keeps re-checking the original payload. diff --git a/changelog.d/w3-33-sk-frontend-uhid.md b/changelog.d/w3-33-sk-frontend-uhid.md index b5c800253..dfc6d90e2 100644 --- a/changelog.d/w3-33-sk-frontend-uhid.md +++ b/changelog.d/w3-33-sk-frontend-uhid.md @@ -1,5 +1,3 @@ -# `w3-33-sk-frontend-uhid.md` - ### Changed - d2b-sk-frontend: extract UHID event parsing into a testable `parse_event` diff --git a/changelog.d/w3-37-d2bd-perf.md b/changelog.d/w3-37-d2bd-perf.md index 3189d7b8d..925cbe4b3 100644 --- a/changelog.d/w3-37-d2bd-perf.md +++ b/changelog.d/w3-37-d2bd-perf.md @@ -3,11 +3,11 @@ - `d2bd` no longer computes a discarded SHA-256 operation digest plus a formatted operation id on every Cloud Hypervisor spec/status update and child deletion: the dead canonical-digest chain is gone from the - reconcile hot path (RS-0800). + reconcile hot path. - Resource identity projections are pre-sized to their field count (twelve required+optional identity columns) and audio status queries to their VM set, bounding a refused call's allocations on frequently- - repeated provider relists (RS-0801, RS-0803). + repeated provider relists. - The forward rendezvous sizes frame read buffers from the length-prefixed datagram instead of the one-megabyte ceiling, so a drain of refused - frames no longer allocates the ceiling per read (RS-0802). \ No newline at end of file + frames no longer allocates the ceiling per read. \ No newline at end of file diff --git a/changelog.d/w4-03-contracts-store-digests-errors.md b/changelog.d/w4-03-contracts-store-digests-errors.md index 96b6b2b8a..6e07ed54e 100644 --- a/changelog.d/w4-03-contracts-store-digests-errors.md +++ b/changelog.d/w4-03-contracts-store-digests-errors.md @@ -1,5 +1,3 @@ -# `w4-03-contracts-store-digests-errors.md` - ### Fixed - The store-contract payload digests (`StoredResource.payload_digest`, diff --git a/changelog.d/w6-13-d2bd-structured-error-kinds.md b/changelog.d/w6-13-d2bd-structured-error-kinds.md index d3447dd9e..fb3bde114 100644 --- a/changelog.d/w6-13-d2bd-structured-error-kinds.md +++ b/changelog.d/w6-13-d2bd-structured-error-kinds.md @@ -1,6 +1,6 @@ ### Changed -- `d2bd` audio mutations (RS-0537): a `setVolume` / `mute` request that names a +- `d2bd` audio mutations: a `setVolume` / `mute` request that names a VM absent from the public manifest, or a VM whose manifest entry does not declare audio, is refused with the structured `TypedError::AudioVmNotFound` (`kind` `audio-vm-not-found`, exit `2`) and @@ -14,7 +14,7 @@ ### Fixed -- `d2bd` `TypedError` (RS-0963): the audio mutation refusals no longer collapse +- `d2bd` `TypedError`: the audio mutation refusals no longer collapse their failure class into a `String` detail on the `internal-io` variant - the class travels as a typed variant, the way the status path carries `AudioErrorKind`. Lock, read, write, and host-enforcement failures keep their diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md index 81b53c1b1..adf70e9c2 100644 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ b/docs/audits/2026-09-24-rust-skills-audit/ledger.md @@ -41,10 +41,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | | U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | | W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | -| W4 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant; 2 needs-contract deferred (RS-0363, RS-0569 to U3); 24 anchor-unverified rows excluded (Main to re-scope) | +| W4 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant. The two rows the wave deferred as needs-contract are recorded below as W7 and applied, which is where they landed. | | W5 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step; the wave closes on the final gated head in the head cell. | | W6 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Three close repairs: the pre-existing `clone_on_copy` re-linted in `d2b-core/src/privileges.rs`, the stale family-knowledge exemption in `xtask/src/provider_crate_policy.rs`, and the async-gate hatch inventory re-recorded for ten moved marker sites (4e47723a1: four in `d2b-broker/src/runtime.rs` moved with the w6-12 merge, six in `d2bd` were already stale on the handed-over head, so that red was waiting on a head no preflight had measured). The four clipped reason cells were repaired and marked [reconstructed]. The five preflight commands this wave ran (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake) measured code head 4e47723a1; the head cell now names the final gated head, and the row's remaining commits are ledger-only on top of it. | -| W7 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 48 rows disposed - see the wave-7 close artifact (.scratch/wave7-close.md) for the per-row evidence, the verified anchors, and the co-change lists. | +| W7 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 52 rows disposed - 37 applied, 7 applied-variant, 8 already-fixed. The per-row evidence is the reason and anchor cells of the W7 rows below; the wave-close artifact that held the rest was scratch-only and is not part of this record. | ## Findings (965 rows) @@ -87,14 +87,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | applied-variant | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | row's bare-import removal broke tests using TapRole via use super::*; variant: import dropped, const deleted, 3 test sites qualified crate::host::TapRole (as _ import rejected by -D warnings) | | | `RS-0029` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | resolve_disk_init_ops flattened to vm.nodes.iter().flat_map(...).filter_map(...).collect() | | | `RS-0026` | `idiom` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | Both duplicate-reservation checks are entry.holders.iter().any(...) predicates; let _ = holder; gone. | | -| `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provid` | two deliberate variants: (1) canonical secret-hint list is the union of both previous lists so no secret detection is weakened on either path (host tests pin application/x-secret-service; guest-only h | | +| `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:91-97, packages/d2b-provider-clipboard-wayland/src/policy.rs:3-14, packages/d2b-provider-clipboard-wayland/src/policy.rs:91-93` | two deliberate variants: (1) canonical secret-hint list is the union of both previous lists so no secret detection is weakened on either path (host tests pin application/x-secret-service; guest-only h | | | `RS-0039` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | 9d0eaefff | `src/bin/d2b-clipd.rs:2812, src/policy.rs:12` | none | | -| `RS-0041` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboa` | commit grouping: the picker.rs changes landed in the same commit as fallback.rs (018c1dad5) because two parallel git add/commit calls raced on the shared index and the second committed both staged fil | | +| `RS-0041` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:113-126` | commit grouping: the picker.rs changes landed in the same commit as fallback.rs (018c1dad5) because two parallel git add/commit calls raced on the shared index and the second committed both staged fil | | | `RS-0038` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 9d0eaefff | `src/bin/d2b-clipd.rs:1131` | none (Ok wrapper required by the existing signature) | | -| `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-pro` | none | | -| `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provi` | implemented the inverse of the row's literal suggestion (a const table read by as_str): Serialize delegates to as_str instead, which keeps the match as the single source of truth with a smaller diff, | | +| `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:5-12` | none | | +| `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:45-68` | implemented the inverse of the row's literal suggestion (a const table read by as_str): Serialize delegates to as_str instead, which keeps the match as the single source of truth with a smaller diff, | | | `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 3459dc5a0 | `packages/d2b-provider-config-nixos/src/ttrpc.rs` | Shared path_components helper classifies Path::components; both callers use it | | -| `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | applied | W5 | 1fe37219f | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-e` | the credential-entra in-crate deadline trio is folded onto the toolkit credential helpers, all eight call sites re-pointed, expired-grant and expired-inspection checks compose the toolkit primitives, and deadline bounds compare two operation_deadline instants | | +| `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | applied | W5 | 1fe37219f | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-entra/src/lib.rs:1172, packages/d2b-provider-credential-entra/src/lib.rs:1187, packages/d2b-provider-toolkit/src/credential.rs:111` | the credential-entra in-crate deadline trio is folded onto the toolkit credential helpers, all eight call sites re-pointed, expired-grant and expired-inspection checks compose the toolkit primitives, and deadline bounds compare two operation_deadline instants | | | `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | applied | U2 | 20e8286f8 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | SecretServiceOwner::Userd renamed to User; enum not serialized; census 2 hits in-crate | | | `RS-0047` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | rustfmt drift normalized: enum closing brace, trailing-whitespace line, reindented variant doc comment | | | `RS-0048` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/effects_service.rs` | let _ = binding dropped; Self::declared_row_template(&view, role)?; | | @@ -135,7 +135,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U2 | fda87abbe | `packages/d2b-provider-transport-vsock/src/auth.rs` | ReadySession::disconnect now drops mut and returns SessionState::Disconnected directly (SessionState is Copy). | | | `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix (envelope.base.get("provider").cloned()) is type-incompatible: base.get yields CanonicalJsonValue not serde_json::Value. Applied minimal variant: dropped the dead unwrap_or fallback via an | | | `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/status.rs` | LayoutPhase::worse now uses derived self.max(other); declaration order already encodes severity. | | -| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | applied | W4 | b062e724d | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/` | | | +| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | applied | W4 | b062e724d | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/zone_links.rs:63, packages/d2b-bus/src/session/enrollment.rs:42, packages/d2b-bus/src/session/enrollment.rs:49` | | | | `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | f5dd934fc | `packages/d2b-contracts-resource/src/v3/execution_policy.rs` | The redacted_debug macro was extended with a closure-based field-preserving form (two exported helper fns redacted_debug_field_ref and redacted_debug_field_value), and all 17 hand-written redaction De | | | `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | | `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | @@ -172,7 +172,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 7eef023f9 | `resource_type_authority.rs` | three statements reindented | | | `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | fc0353eb1 | `nix_inventories.rs` | applied-variant: generic S: AsRef + Display standard params (caller with Vec cannot feed &[&str]); call site passes STANDARD_RESOURCE_TYPES.as_slice() | | | `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | a8bc3bb0b | `packages/xtask/src/gen_layer_catalogs.rs` | Ten surface_catalog blocks and the two protobuf redaction templates converted to r## raw strings; all 12 literals verified byte-identical against HEAD; gen-layer-catalogs --check passes. | | -| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | skipped-stale | U2 | bbd40b6fd | packages/xtask/src/main.rs (sanitize_generated_rust) | premise false: the literal matches the ttrpc-compiler 0.8.0 marker exactly, so the strip is live. The wave's deletion was reverted - without it the committed binding file is not reproducible and the bogus attribute fails -D warnings; regeneration is byte-stable again. | | +| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | skipped-stale | U2 | bbd40b6fd | `packages/xtask/src/main.rs:464` (sanitize_generated_rust) | premise false: the literal matches the ttrpc-compiler 0.8.0 marker exactly, so the strip is live. The wave's deletion was reverted - without it the committed binding file is not reproducible and the bogus attribute fails -D warnings; regeneration is byte-stable again. | | | `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | dead close-block reset replaced with scan end at closing brace | | | `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 564cc6d00 | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | public Arc surfaces narrowed at the named sites: the ConsoleRing::notify accessor is deleted, ConsoleSession::ring returns &Mutex, DaemonAuditLog.captured is private behind an accessor, TargetBinding::new takes TargetDirectory by value, and SkAcceptHandle.state is private behind an accessor; all 13 Arc constructor params are kept with per-site reasons (stored and cloned at a spawn boundary, a per-driver factory, an admission offer/engine pair, a split transport half, or a test-held clock) | | | `RS-0150` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | cursor/page_token/reference moved into calls;call-site reassignment unchanged | | @@ -195,7 +195,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | dedup sets now BTreeSet<&BoundedToken>/BTreeSet<&ResourceTypeName> in ProviderManifest::new and with_state_namespaces | | | `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/volume_state.rs` | SchemaFingerprint::parse takes the borrowed str instead of cloning | | | `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied-variant | U2 | 862071320 | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs` | Order-preserving contains check (n<=64) instead of sort-in-place: sorting would change serialized bytes of a signed wire message for unsorted inputs | | -| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | W4 | a2cf0e614 | `src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session` | | | +| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | W4 | a2cf0e614 | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:456, packages/d2b-contracts-zone-session/src/v3/component_session.rs:473` | | | | `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | acffb7466 | `packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs` | Walk iterates CanonicalJsonObject keys directly; no wrapper or clone built | | | `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | W4 | a2cf0e614 | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | | `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | 7be394a88 | `packages/d2b-contracts-zone-session/src/v3/services.rs` | BoundedText::parse takes method.as_str() instead of method.clone() | | @@ -237,14 +237,14 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/service/supervisor.rs` | advance_session now scopes the first session_mut borrow in a block and compares supervisor_identity.as_ref() directly; dropped the clone. | | | `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | | `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | -| `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src` | the provider session loop compares the bound controller route inside the route mutex lock scope, dropping the per-frame AuthenticatedSessionRouteBinding clone | | +| `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src/server/adapter.rs:314-316` | the provider session loop compares the bound controller route inside the route mutex lock scope, dropping the per-frame AuthenticatedSessionRouteBinding clone | | | `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | is_ready_for_route compares through the guard via is_some_and(/ready/ ready.as_ref().is_some_and(/bound/ bound.liveness().is_live() && bound == route)); no clone. | | | `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/shared_provider.rs` | sort_by with teardown_rank cmp then name cmp; no per-row String allocation. | | | `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | with_deadline consumes self and rebuilds with struct-update syntax; sole caller passes owned request | | | `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 72858f537 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs` | GatewayCredential stores material: GatewayCredentialMaterial moved in from_material; Drop impl deleted (material zeroizes); accessors and Debug unchanged | | | `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | applied-variant | U2 | 9ba7acf09 | `packages/d2b-provider-user/src/effects_service.rs` | Destructured InspectUserRequest and moved groups by value; username still cloned because inspect_user_response borrows it after UserSpec::new consumes it (stated fix was not implementable as written). | | | `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix not type-compatible: ctx.spec returns &T so decoded_spec returned an owned clone. Minimal variant: decoded_spec now returns (&VolumeSpecEnvelope, VolumeSpec); callers adapted; removed the p | | -| `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | applied | W5 | eee03f2a9 | `driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.` | desired_binding_intents takes the volume ResourceRef by borrow; the volume driver and the shared runtime no longer clone the reference before every binding-intent derivation | | +| `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | applied | W5 | eee03f2a9 | `packages/d2b-provider-volume-local/src/bindings.rs:80, packages/d2b-provider-volume-local/src/bindings.rs:80-81, packages/d2bd/src/resource_runtime.rs:5882, packages/d2bd/src/resource_runtime.rs:12921` | desired_binding_intents takes the volume ResourceRef by borrow; the volume driver and the shared runtime no longer clone the reference before every binding-intent derivation | | | `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/row_readers.rs` | Bounded the as_object_mut removal borrow in a block and moved spec into serde_json::from_value, dropping the Value::Object(object.clone()). | | | `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | Both plan() route-binding arms (RoutePolicyCommitted, SessionGenerationAdvanced) now borrow record.route_binding.as_mut() and mutate through it; dropped the clone + store-back. | | | `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | EnrolledSessionEstablished arm now takes record.enrollment.as_ref() and compares the fingerprint, ending the borrow before record.link_epoch mutation. | | @@ -289,11 +289,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0235` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 02238dbdd | `semantic_service_schemas.rs` | resource_ref_schema takes &str/&[&str]; five call sites pass borrowed forms | | | `RS-0229` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | mem::take on the mut slot before in-place edit | | | `RS-0230` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | two ratchet probes key borrowed strs via signal fields | | -| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | applied-variant | W4 | 0b5c7d292 | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operati` | applied-variant: d2b-core privileges enums (SecretAccess, BrokerRequirement, AuditMode) gained Copy derives - required because BrokerAuthzFacets/BrokerOperationRow derive Copy; additive, non-breaking | | +| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | applied-variant | W4 | 0b5c7d292 | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19` | applied-variant: d2b-core privileges enums (SecretAccess, BrokerRequirement, AuditMode) gained Copy derives - required because BrokerAuthzFacets/BrokerOperationRow derive Copy; additive, non-breaking | | | `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | applied | W6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Closed Disposition enum (CallableReadOnly/PromotedLive/StubbedUnimplemented/CompileTimeOnly, as_str) beside StubTarget in catalog.rs; BrokerOperationRow.disposition typed against it; generator emits via disposition_variant() mapper with a DISPOSITIONS closed-set validation; the five string-match sites migrated to variant matches; policy JSON stays the string vocabulary. | | -| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | applied | W6 | 13101e206 | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operati` | Generator emits a full closed BrokerOperationName enum (98 variants, as_str); HOST/GUEST_OPERATION_CATALOG and the row operation field typed against it; allows_operation keeps the &str spelling via as_str so the wire boundary is unchanged; consumers migrated (broker_wire.rs, catalog.rs, runtime.rs, d2b-broker/tests profiles, envelope/mod.rs, d2b-broker-composition routing/seam). | | +| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | applied | W6 | 13101e206 | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11` | Generator emits a full closed BrokerOperationName enum (98 variants, as_str); HOST/GUEST_OPERATION_CATALOG and the row operation field typed against it; allows_operation keeps the &str spelling via as_str so the wire boundary is unchanged; consumers migrated (broker_wire.rs, catalog.rs, runtime.rs, d2b-broker/tests profiles, envelope/mod.rs, d2b-broker-composition routing/seam). | | | `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | applied | W6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Destructive enum (Serialize/Deserialize/JsonSchema, kebab-case) in privileges.rs; both field types bool -> Destructive; generate_authz emits named-field construction with Destructive::No/Yes; row() helper and its arity allow deleted (PUBLIC_OPERATION_AUTHZ converted in the same change); Nix emitter, v2 schema, and fuzz corpus seeds moved to no/yes; v1 schema frozen. | | -| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-` | driver-args zone class: the zone is a validated ZoneId through the wayland-policy, volume-binding, guest, and shared-provider driver args, and the daemon boundary parses it once; the per-pass parse-expects are gone, key_ref returns a typed SpecInvalid Result instead of panicking | escalated W2 -> U5 -> W5 (the family wave landed the driver-args class member sites) +| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs` | driver-args zone class: the zone is a validated ZoneId through the wayland-policy, volume-binding, guest, and shared-provider driver args, and the daemon boundary parses it once; the per-pass parse-expects are gone, key_ref returns a typed SpecInvalid Result instead of panicking | escalated W2 -> U5 -> W5 (the family wave landed the driver-args class member sites) | | `RS-0263` | `type` | `d2b` | low | actionable | leaf | applied | U3 | f98ad4f82 | packages/d2b/src/context.rs | ZoneContext now stores ZoneId; zone_ref/zone_name built from it; validate_zone_name deleted; discover double validation removed; from_socket takes ZoneId directly. | | | `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | | `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | applied | W5 | 6b9187e44 | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | EvidenceChain deserializes through an admission gate that rejects an empty identities list, so depth() cannot underflow and the identity accessors cannot panic; the wire shape is unchanged | | @@ -308,15 +308,15 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | applied | W6 | caa29e248 | `public_wire.rs:2166, public_wire.rs:2203` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. AuditResponse's complete/next_cursor pair replaced by the closed AuditPageEnd (Complete / More(cursor)); the crate-local validate_audit_page is deleted and from_parts reports the canonical d2b_contracts::audit_wire::AuditPageError classes, so the admission error text is unchanged; AuditResponse keeps byte- and key-order-identical Serialize via the borrowing AuditResponseOut plus a manual JsonSchema; consumers migrated (d2b/src/dispatch.rs pagination, d2bd-runtime/src/wire.rs audit_response, d2bd/src/composition.rs). Gate: cargo check -p d2b-contracts-control -p d2bd-runtime -p d2bd -p d2b --all-targets rc=0 and the slice's schema drift targets. | | | `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied | W6 | e9cb637c3 | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11. Status DTO state vocabularies are closed kebab-case enums: RealmMode/RealmGatewayState (the `not reported by d2bd` sentinel preserved), QemuMediaRunnerState/QemuMediaRegistryState, PublicReadModelKind, VmAutostartMode; the crate-local duplicate kind and the parallel kind_name:&'static str are deleted, d2bd-runtime publishes the contract enum, and a spelling test pins all 21 spellings. Emitted bytes: the CLI goldens are byte-unchanged; the generated CLI schemas and the v2 wire-protocol schema plus the daemon-api enum table were regenerated with the xtask gen commands and proven by gen_cli_schemas_drift + gen_schemas_drift + gen_daemon_api_drift (3 of 3 pass on the committed tree). | | | `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied-variant | W6 | caa29e248 | `public_wire.rs:316, public_wire.rs:311` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. MutationFlags' three booleans became MutationMode { DryRun, Apply } + MutationFlags { mode, json } with from_flags/to_flags; the seven flattened flag fields lost `default` and the three host requests lost Default, so a payload selecting neither mode fails admission. Recorded deviations: (a) the raw-JSON public frame cannot lose its refusal (it never passes typed admission), so the pair is parsed at the boundary in mutation_mode_from_request and keeps the byte-identical mutating-verb invalid-request envelope, while typed frames fail admission; (b) a hand-written frame setting both flags keeps the long-standing dry-run precedence instead of gaining a new refusal class. | | -| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d` | | | -| `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | applied | W5 | fa8706320 | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/s` | ComponentDescriptor::new no longer takes declares_state_volume: the parameter could only ever be false (true returned MissingRequiredField), so the illegal state is not expressible and every call site drops the argument; the wire-only declaresStateVolume field and its consistency check against stateNamespaces stay in the Deserialize path | | +| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:499, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:502` | | | +| `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | applied | W5 | fa8706320 | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/src/v3/provider.rs:1368, packages/d2b-contracts-provider/src/v3/provider.rs:1720, packages/d2b-contracts-provider/src/v3/provider.rs:3455` | ComponentDescriptor::new no longer takes declares_state_volume: the parameter could only ever be false (true returned MissingRequiredField), so the illegal state is not expressible and every call site drops the argument; the wire-only declaresStateVolume field and its consistency check against stateNamespaces stay in the Deserialize path | | | `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | | `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied | W7 | 1af47c8cf | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:284` | observed_generation is the crate's transparent ObservedGeneration (wire bytes unchanged); the two hand-committed activation-nixos schemas moved with it. Merged ab038d388. | | -| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resour` | | | +| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resource/src/v3/operations/mod.rs:239, packages/d2b-contracts-resource/src/v3/operations/mod.rs:374` | | | | `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied-variant | W7 | 1af47c8cf + e14ea9c02 | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:47` | target_generation is the existing nonzero ConfigurationGeneration newtype (serde-transparent u64, JsonSchema minimum 1): nonzero_u64_schema, ActivationRunnerInputError and the zero check are deleted, new() is infallible, the now-unreachable zero guards in process-conformance and provider-process are gone, and the EphemeralProcess schema was regenerated. The first landing used a new NixosGenerationOrdinal newtype, which the layout gate refused as shared-crate family vocabulary; the follow-up slice switched to the row's own prescribed ConfigurationGeneration. Merged ab038d388 + 6abcf5cac. | | | `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises - `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | -| `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | packages/d2b-provider-transport-azure-relay/contrast-zone-session/src/v3/role_binding.rs | | | -| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | W4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/` | | | +| `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | `packages/d2b-contracts-zone-session/src/v3/role_binding.rs` | | | +| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | W4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/context.rs:61-67` | | | | `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | | `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | | `RS-0262` | `type` | `d2b-host` | medium | actionable | family | applied | W5 | d593fa50e | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | BusId keeps its inner string private and validates the USB busid grammar once at the type boundary (BusId::new returns Result, TryFrom<&str> and as_str carry the value); the transparent wire shape is unchanged and the redundant broker qemu-media re-validations plus the daemon attach/detach pre-checks are deleted | | @@ -363,7 +363,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | applied-variant | W7 | 369627b78 | `packages/d2bd/src/composition.rs:20375` | mode is HostActivationMarkerMode rendering the four documented verbs, with a serde(other) Unknown catch-all so an unknown out-of-tree mode still parses (the catch-all is named Unknown so its serde label and Display agree; the finding suggested no name); the marker log keeps a recognized label via Display. Merged a74fd9b0c. | | | `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | 7e0ec2bce | packages/d2bd-runtime/src/admission.rs | peer admission lookup mode modelled self-describing; check + admission tests green (worker reported the oid as already present after committing its own change; the commit is this branch's) | | | `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W5 | 6dabfe132 | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | DaemonEvent::ApiReadyTimeout.mode is a closed ApiReadyMode enum (Strict / NoWaitApi) with kebab-case serde, so an invalid mode string is rejected on deserialize; the JSONL shape is unchanged | | -| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_resp` | | | +| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_response_helpers.rs:118` | | | | `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | d1c5c44d9 | packages/d2bd-runtime/src/typed_shell_targets.rs | typed-shell target key becomes a named struct with a constructor; the three composition.rs cache call sites migrate to it | | | `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | | `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | @@ -373,7 +373,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | -| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | applied | W6 | 3c3454697 | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtim` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). BrokerRequestEnvelope no longer carries the test-only test_peer_uid member: the harness (the bootstrap probe CLI and the integration tests) sends that override as a testPeerUid member beside the envelope, and only a --test-mode broker unwraps it in front of its strict decode, so the wire contract carries no test seam and every other broker refuses a frame that carries one; production frames stop emitting the "testPeerUid": null member. New d2b_broker::runtime::{TEST_PEER_UID_FIELD, test_peer_uid_frame} name the harness-only override, and the contract test broker_request_envelope_refuses_a_test_only_peer_uid_member pins the refusal. Co-change: the broker runtime and bootstrap call sites and the four broker integration targets (profile_separation, guest_profile, socket_activation, broker_protocol_compatibility). Gate on the merged tree: cargo test -p d2b-contracts-broker rc=0, cargo test -p d2b-broker rc=0 (700 lib tests plus the spawned-broker integration targets, each driving the new frame-member seam against a real broker), cargo check over the seven touched crates --all-targets rc=0, gen_daemon_api_drift green. | | -| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | W4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib` | | | +| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | applied | W6 | 3c3454697 | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtime.rs:1628-1632` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). BrokerRequestEnvelope no longer carries the test-only test_peer_uid member: the harness (the bootstrap probe CLI and the integration tests) sends that override as a testPeerUid member beside the envelope, and only a --test-mode broker unwraps it in front of its strict decode, so the wire contract carries no test seam and every other broker refuses a frame that carries one; production frames stop emitting the "testPeerUid": null member. New d2b_broker::runtime::{TEST_PEER_UID_FIELD, test_peer_uid_frame} name the harness-only override, and the contract test broker_request_envelope_refuses_a_test_only_peer_uid_member pins the refusal. Co-change: the broker runtime and bootstrap call sites and the four broker integration targets (profile_separation, guest_profile, socket_activation, broker_protocol_compatibility). Gate on the merged tree: cargo test -p d2b-contracts-broker rc=0, cargo test -p d2b-broker rc=0 (700 lib tests plus the spawned-broker integration targets, each driving the new frame-member seam against a real broker), cargo check over the seven touched crates --all-targets rc=0, gen_daemon_api_drift green. | | +| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | W4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib.rs:7-11` | | | | `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | W6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | | `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | W6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | | `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | applied | W6 | e9cb637c3 | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11, as a versioned transition (first assessed blocked on the frozen v1 schema; the operator rule that format compatibility is a co-change list applies, and the census found no freeze policy to cite). The dead pub AuditEntry export is deleted; census at HEAD: the definition only (the live public AuditResponse carries AuditExportEntry pages), no golden, no live consumer; the v1 schema stays the byte-identical historical artifact and the generated v2 schema never contained the name (gen_schemas_drift + gen_daemon_api_drift green). Outside-tree observer: none - the v1-era AuditResponse shape has not been emitted since the page moved to AuditExportEntry. | | | `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied-variant | W6 | dc145cf0c | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Caller-migration variant (recorded deviation; the ledger's census was stale): the two live external callers of HelperLaunchRequest::validate_bounds (d2b-unsafe-local-helper protocol.rs:157, runtime.rs:333) migrated to the pub free fn validate_unsafe_local_resource_identity; then both methods narrowed to pub(crate). Wire types and serde admission unchanged. | | -| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/sr` | | | +| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/src/v3/resource_schema.rs:592` | | | | `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | | `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 67393687b13c359ac6b3a96bca469d28e25c7c96 | packages/d2b-contracts-resource/src/v3/identity.rs | Deleted the zero-caller alias and its doc. Census re-run: ValidatedSessionPurpose over worktree = 1 hit (the definition); no re-export arm in v3/mod.rs. cargo check -p d2b-contracts-resource --locked | | | `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | | `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs | Deleted EmergencyPolicySpec::default_values(); Default::default() now constructs directly. Census: the Default impl was the only caller. | | | `RS-0339` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone.rs | Removed ZoneSpec::validate (always-Ok). Census: no callers anywhere in the workspace or in-crate tests; the Deserialize gate remains the invariant. | | -| `RS-0348` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | ac3083316 | `packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-cor` | the six d2b-core compat shim modules are deleted and every import site re-pointed at d2b_contracts; the xtask gen-error-codes generator and the generated docs/reference/error-codes.md anchors follow; the zero-consumer UnsafeLocalWorkloadIdentity alias goes with its module | | +| `RS-0348` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | ac3083316 | `packages/d2b-core/src/error.rs, packages/d2b-core/src/contract_id.rs` (the shim modules this row deleted are gone from the tree) | the six d2b-core compat shim modules are deleted and every import site re-pointed at d2b_contracts; the xtask gen-error-codes generator and the generated docs/reference/error-codes.md anchors follow; the zero-consumer UnsafeLocalWorkloadIdentity alias goes with its module | | | `RS-0345` | `api` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Nine zero-consumer resolved-intent types marked #[doc(hidden)] (kept for planned broker dispatch arms per module doc); census re-run: 0 consumers workspace-wide | | | `RS-0349` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | 8e70d643e | `packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:1` | the four static validators now carry in-module positive/negative unit tests restoring the retired tests/static-invariant-*.sh gate cases, so the module doc claim is true; the stale doc paragraphs are corrected and the public API and constants are unchanged | | | `RS-0346` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | 8abd3c1ba | `packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109` | the seven BundleResolver trusted-bundle fields are private behind typed accessors and a single set_storage setter replaces the broker's direct storage mutation; every consumer in d2bd, d2bd-runtime, d2b-broker, and the provider crates reads through the accessors | | @@ -414,8 +414,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0344` | `api` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 4105103ab | packages/d2b-core-controller/src/owner_reconcile.rs | Deleted six zero-caller public alias accessors: OwnerReconcilePlan::create_order/batch, OwnerChildBatch::resource_refs, OwnerChildIdentity::resource_ref, TeardownPlan::refs/resources; kept canonical n | | | `RS-0351` | `api` | `d2b-host` | low | actionable | leaf | applied | U3 | c44532f1d | packages/d2b-host/src/lib.rs | HostPrepStepId inner string made private with serde-transparent round-trip unchanged; workspace check and clippy green. | | | `RS-0355` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 9ed591eb2 | packages/d2b-process-conformance/src/lib.rs | Dropped the unused BrokerExitClass alias from the terminal re-export; census: only hit was its own re-export. | | -| `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | dbac9940c | packages/d2b-process-conformance/src/process_provider.rs | Deleted the duplicate process_provider re-export module; census: 0 users of that path. | | -| `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testi` | the process-conformance test doubles and fixtures (`testing`) ship behind a `test-support` feature: the feature is declared, the `_test_support` bazel variant gains `crate_features`, the suite helpers that need the doubles are gated, and every in-tree consumer enables the feature through dev-dependencies plus the `_test_support` bazel variants; the shared `suite` stays ungated product surface | | +| `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | dbac9940c | `packages/d2b-process-conformance/src/provider.rs` (the process_provider.rs module this row deleted is gone from the tree) | Deleted the duplicate process_provider re-export module; census: 0 users of that path. | | +| `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testing.rs:1` | the process-conformance test doubles and fixtures (`testing`) ship behind a `test-support` feature: the feature is declared, the `_test_support` bazel variant gains `crate_features`, the suite helpers that need the doubles are gated, and every in-tree consumer enables the feature through dev-dependencies plus the `_test_support` bazel variants; the shared `suite` stays ungated product surface | | | `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | a37c1e0cf | packages/d2b-process-conformance/src/sandbox.rs | Deleted CompiledSandbox::requires_cgroup_kill field, its unconditional true initializer in compile(), and its public accessor; census: `requires_cgroup_kill` over packages/, nixos-modules/, tests/, do | | | `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 6c66b83ea | packages/d2b-provider-activation-nixos/src/driver.rs | ActivationDriver narrowed to pub(crate) and dropped from the lib.rs driver re-export arm. Census re-run:the symbol appears only in driver.rs (7 sites)and lib.rs; no external consumer. Checks shared wi | | | `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | @@ -423,11 +423,11 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c9a141c78 | packages/d2b-provider-audio-pipewire/src/controller.rs | register_service deleted (zero callers; census over packages/nixos-modules/tests/docs/reference/labs = only the definition); daemon and wayland-policy validate specs via validate_audio_service directl | | | `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | applied | W7 | 792ca2002 | `packages/d2b-provider-audio-pipewire/src/controller.rs:142` | AudioLastSetApplied::OfflineOnly is renamed NotApplied and the wire label moves with every consumer: the wayland-policy projection arm, its fixture and two pins, the daemon status pin in resource_plane_v3.rs, and the provider ADR enum row - the census of the old literal leaves only the historical audit record. Merged d9a91015a. | | | `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 9024c13d9 | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1282` | host_entry_ttl_secs and the policy() accessor are gone from ClipboardConfig (field, Default value, and accessors); repo-wide grep finds no code hit; re-verified at 6dc80e258. | | -| `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | applied | W5 | 4524b7e45 | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-ni` | the public decode_document forwarder and its re-export are deleted; the sole caller in d2bd uses ConfigSyncResponse::document() directly, leaving one API path for validating a synced config document | | +| `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | applied | W5 | 4524b7e45 | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-nixos/src/lib.rs:22` | the public decode_document forwarder and its re-export are deleted; the sole caller in d2bd uses ConfigSyncResponse::document() directly, leaving one API path for validating a synced config document | | | `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | | `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | | `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | drop the zero-caller `ManagedIdentityPlacement::in_zone` constructor (exact duplicate of `new`); census over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 consumers outside the definit | | -| `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | applied | W5 | 3c229db55 | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effe` | DeviceResourceState's three provider caches are private behind read-only typed accessors; the daemon's shared provider effects migrate all nine read sites and the GPU authority-lease construction contract stays behind the driver crate | | +| `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | applied | W5 | 3c229db55 | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effects.rs:1584, packages/d2bd/src/shared_provider_effects.rs:2092, packages/d2bd/src/shared_provider_effects.rs:2122` | DeviceResourceState's three provider caches are private behind read-only typed accessors; the daemon's shared provider effects migrate all nine read sites and the GPU authority-lease construction contract stays behind the driver crate | | | `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U3 | 539ca5113 | packages/d2b-provider-device-gpu/src/lib.rs | gpu_argv/video_argv made private; root re-exports keep one reachable path per item. Census re-run: `d2b_provider_device_gpu::(gpu_argv/video_argv)::` over packages/nixos-modules/tests/docs/reference/l | | | `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U3 | 4efbf8ea5 | packages/d2b-provider-device-gpu/src/effects_service.rs | applied-variant: row's second option (single crate-owned sidecar) used: DeclaredWorkerGpuPortDeps sidecar (private fields, pub 4-arg ::new) holds the four dependency types; DeclaredWorkerGpuPortArgs ( | | | `RS-0372` | `api` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U3 | 0867cba1a | packages/d2b-provider-device-security-key/src/lib.rs | pub mod relay made private (relay_service already private at HEAD); lib.rs pub use arms stay the single surface. Census re-run: device_security_key::relay:: = 1 hit (backticked doc comment in d2b-brok | | @@ -454,19 +454,19 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | applied-variant | U3 | f17f141c6 | packages/d2b-provider-network-local/src/routes.rs | Both route provenance validators narrowed to #[cfg(test)] pub(crate) and the stale #[allow(dead_code)] removed. Variant: plain pub(crate) alone re-triggers dead_code (both validators have zero product | | | `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied-variant | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Deleted uncalled reconcile_authenticated_display (census: def only, zero callers); reconcile_sources and drain_sources lowered to #[cfg(test)] pub(crate) (test-only). Variant: plain pub(crate) would r | | | `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Stale #[allow(dead_code)] removed from from_route, which is reachable from production via from_authenticated_route. Same commit as RS-0394 (same file). | | -| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W7 | 58ac8df53 | `packages/d2b-provider-notification-desktop/src/stream_admission.rs:1` | the private shim module is deleted and lib.rs re-exports the four admission items directly; the ADR-046 layout and reuse rows now cite src/admission.rs (dossier-citation gate green). Merged ae531b399. | | +| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W7 | 58ac8df53 | `packages/d2b-provider-notification-desktop/src/lib.rs:29, packages/d2b-provider-notification-desktop/src/lib.rs:59` (the src/stream_admission.rs shim this row deleted is gone from the tree) | the private shim module is deleted and lib.rs re-exports the four admission items directly; the ADR-046 layout and reuse rows now cite src/admission.rs (dossier-citation gate green). Merged ae531b399. | | | `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | ebeef4024 | packages/d2b-provider-process-systemd/src/lib.rs | lifecycle is now a private module; the root re-export is the single surface. Census: zero consumers of the d2b_provider_process_systemd::lifecycle path anywhere. check + lib tests green; clippy red is | | | `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | | `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | applied-variant | W7 | 14d098fc3 | `packages/d2b-provider-process-systemd/src/lib.rs:22` | the row's zero-production-consumer claim is partly false (d2bd composes SystemdProcessProvider and effects_service), so lifecycle/effects_service/operations stay exported; the holding part is implemented - the six test-only modules (controller, drain, metrics, audit, launch, sandbox) are gated behind a new test-support feature (Cargo [[test]] required-features + Bazel crate_features on the test-support target), the conformance suites keep running, and the crate doc records the wired vs test-only surface. A throwaway consumer crate proves the plain build no longer resolves the six modules. Merged 3668d3a6e. | | | `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | c61b0e5b5 | packages/d2b-provider-provider/src/driver.rs | ProviderDriverFactory::new() and impl Default deleted (zero callers; crate tests construct via with_effects; FailClosedProviderDriverEffects still used by tests). Census: no new()/default() callers ac | | | `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | 56c460c03 | packages/d2b-provider-provider/src/providers.rs | Completed the in-flight partial edit: deleted plan_external body, Disable/Delete intent variants, Draining phase, TrustOrCompatibilityDenied error, and orphaned test helpers/imports; check/test/clippy | | | `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | same wiring as RS-0959 | | -| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export` | same wiring as RS-0959 | | -| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import` | same wiring as RS-0959 | | +| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export/src/lib.rs:18` | same wiring as RS-0959 | | +| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import/src/lib.rs:18` | same wiring as RS-0959 | | | `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | applied | W5 | f82fa17c8 | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | the empty test-support feature stanza is deleted with the [[test]] registration required-features gate and the bazel variant's crate_features that referenced it; the registration test now runs instead of being silently skipped, rbac stays public product surface | | -| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | applied | W4 | 7dadf9923 | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile` | | | +| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | applied | W4 | 7dadf9923 | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile/src/lib.rs:22, packages/d2bd/src/foundation_seed.rs:25, packages/d2bd/src/foundation_seed.rs:1091` | | | | `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 0cb5d7b68 | packages/d2b-provider-supervisor/src/adapter.rs | | | -| `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | applied | W5 | 85cfe8bc1 | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/s` | LaunchedSnapshot carries the launched runner (vm, role, pid, start-time ticks, pidfd) as a named struct with a redacting Debug; the in-tree ProcessEffectBackend trait and LaunchedObserver take it instead of five positional parameters and a 5-tuple, and the only call site plus both daemon call sites are re-pointed | | +| `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | applied | W5 | 85cfe8bc1 | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/src/broker.rs:1524-1546, packages/d2b-provider-process/src/backend.rs:315-319` | LaunchedSnapshot carries the launched runner (vm, role, pid, start-time ticks, pidfd) as a named struct with a redacting Debug; the in-tree ProcessEffectBackend trait and LaunchedObserver take it instead of five positional parameters and a 5-tuple, and the only call site plus both daemon call sites are re-pointed | | | `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | | `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | applied-variant | W6 | ab90777de | `src/host.rs:389, src/host.rs:13` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-14. HostReconciler::reject_operator_status_fields (zero callers outside its own tests at HEAD) is now enforced at the daemon's operator status admission (public_update_status_request, the public dispatch's UpdateStatus arm): an operator-submitted Host status naming isolationPosture or isolationPostureMessage, in either request spelling and including the explicit null form, is refused before the row is read. Recorded deviations: the site is the daemon admission rather than d2b-resource-api's update_status (that crate cannot depend on d2b-provider-system-core without inverting the layering), and the provider-session dispatch keeps its own admission because the system-core reconciler's own publication legitimately derives those fields (ADR-046-provider-system-core 4.1.4). Co-change: the typed refusal ResourceRuntimeError::HostStatusFieldNotOwned with its error frame, the system-core host module doc, the admission test an_operator_status_naming_a_host_reconciler_owned_field_is_refused. No serialized shape moves. | | | `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | make the `ownership` module private; the root re-export of the owned/disowned type lists is the single surface. Shares commit 31ff8b396 with RS-0409 (the audit's own census pairs these two module-surf | | @@ -478,7 +478,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | | `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs | | | | `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | -| `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | applied | W5 | 14bf42022 | `driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.r` | the never-read VolumeDriverArgs zone field is removed; construction sites and fixtures no longer carry it | | +| `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | applied | W5 | 14bf42022 | `packages/d2b-provider-volume/src/driver.rs:246-250, packages/d2b-provider-volume/src/driver.rs:282, packages/d2bd/src/resource_plane_v3.rs:2975, packages/d2b-provider-volume/tests/registration.rs:25` | the never-read VolumeDriverArgs zone field is removed; construction sites and fixtures no longer carry it | | | `RS-0421` | `api` | `d2b-provider-volume-local` | medium | actionable | family | applied | W5 | 96fef8256 | `src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1` | the volume-local `testing` module is gated behind test-support (feature declared, the pre-existing `_test_support` bazel variant gains `crate_features`); the four volume-local suites, d2bd's cfg(test) consumer, and the crate's internal cfg(test) uses are re-pointed, with zero product-path consumers | | | `RS-0422` | `api` | `d2b-provider-zone` | medium | actionable | leaf | applied | U3 | c28489ccc | packages/d2b-provider-zone/src/lib.rs | zone_status module private with the four items re-exported by name; the two module-path consumers (d2bd resource_runtime.rs:63-65, tests/zone_status.rs:3-4) re-pointed to the crate root. Census: d2b_p | | | `RS-0423` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied-variant | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zone_links.rs | Fix as written (pub(crate)) not implementable: usage is test-only, and .cargo/config.toml -Dwarnings turns the resulting dead-code into build errors. Minimal correct variant: #[cfg(test)] on ZoneLinkM | | @@ -509,17 +509,17 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 1ed0521fa | packages/d2bd-runtime/src/console_session.rs | Dropped unused _vm parameter from spawn_ch_serial_drainer and the hardcoded "ch-console".to_owned() allocation at the create_ch_session call site. | | | `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e8e7a2d51 | packages/d2bd-runtime/src/console_session.rs | Deleted dead pub DrainerSource enum (census re-run: pattern DrainerSource over packages = 1 hit, the definition itself; zero constructions) and its #[allow(dead_code)]. | | | `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 26d5c1119 | packages/d2bd-runtime/src/console_session.rs | ConsoleRing/ConsoleSession fields made private; ConsoleRing exposes push_bytes/set_eof (notify internally), read_at, base_offset, notify(); ConsoleSession exposes provider_kind/ring/stdin_tx accessors | | -| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | applied-variant | W6 | 7739ae6f5 + 128a340f0 | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, pa` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slices w6-15 and w6-13. Applied: d2b-provider-clipboard-wayland PickerIpcError::Frame/String became Frame(#[from] FramingError) + Read(#[source] io::Error) + ClosedMidFrame with every Display byte-identical; d2b-provider-transport-azure-relay CredentialUnavailable/TransportUnavailable carry typed sources through the explicit Error::source impl (applied-variant: the file hand-writes Display/Error, so no #[source] attributes exist there) with code() strings unchanged; d2bd TypedError carries the audio failure classes as typed leaf variants (applied-variant: failure class as variants rather than a source object, because d2bd-runtime cannot name provider-typed sources and std sources are not Clone). Already-fixed at HEAD, each with its commit: d2b-broker ops/usbip_lock.rs (RS-0454 fd5b41b4b), ops/hosts.rs (84d4cb0b9), d2b-resource-runtime (fa4907468), d2bd-runtime vsock (c9addc3aa). Residual not in the row: PickerIpcError::Socketpair/Spawn/FdFlags still flatten their io/FdMappingCollision errors - flagged, not expanded. | | +| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | applied-variant | W6 | 7739ae6f5 + 128a340f0 | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:132` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slices w6-15 and w6-13. Applied: d2b-provider-clipboard-wayland PickerIpcError::Frame/String became Frame(#[from] FramingError) + Read(#[source] io::Error) + ClosedMidFrame with every Display byte-identical; d2b-provider-transport-azure-relay CredentialUnavailable/TransportUnavailable carry typed sources through the explicit Error::source impl (applied-variant: the file hand-writes Display/Error, so no #[source] attributes exist there) with code() strings unchanged; d2bd TypedError carries the audio failure classes as typed leaf variants (applied-variant: failure class as variants rather than a source object, because d2bd-runtime cannot name provider-typed sources and std sources are not Clone). Already-fixed at HEAD, each with its commit: d2b-broker ops/usbip_lock.rs (RS-0454 fd5b41b4b), ops/hosts.rs (84d4cb0b9), d2b-resource-runtime (fa4907468), d2bd-runtime vsock (c9addc3aa). Residual not in the row: PickerIpcError::Socketpair/Spawn/FdFlags still flatten their io/FdMappingCollision errors - flagged, not expanded. | | | `RS-0477` | `err` | `d2b` | medium | actionable | leaf | applied-variant | U3 | 7256bc918 | packages/d2b/src/lib.rs | Added structured code field to CliFailure; populated in ZoneContext::failure; can_fallback_to_local_state and reconcile_deadline match on it. Field is String not &'static str because validate_response | | | `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | applied | W7 | 50be72eea | `packages/d2b/src/host.rs:276` | host prepare/destroy/reconcile now route through missing_mutation_flag_envelope: kind --apply-or-dry-run-required and exit 78 for all three (prepare/destroy moved from exit 2 ref-invalid), with a regression test that fails on the old shape; the --network refusal is untouched. Merged 01daff2b1. | | | `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | | `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 637d66627 | packages/d2b-audit/src/segment.rs | | | -| `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | packages/d2b-broker/src/runtime.rs (from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | +| `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | `packages/d2b-broker/src/runtime.rs:2534` (DispatchAuditContext::from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | | `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | applied-variant | W6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source [reconstructed: ]source: io::Error`; the Display text is preserved, so the broker error-envelope strings are unchanged; one format-string site (usbip_lock.rs:111) needs its own variant]. Applied as variant-split deviation: Io { path, source: io::Error } with a manual Error::source() override (no thiserror dep in d2b-broker) and a new PathSafetyViolation { path } variant; Display byte-identical. | | | `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | | `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | ce4da285b | packages/d2b-broker/src/state_cells.rs | with_retention now returns Result (test caller updated with expect); in_memory expect names the startup-precondition rationale; check/test/clippy green. | | | `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | -| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | applied | W6 | fd5b41b4b | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2` | guest_socket_directory now returns a pub(crate) GuestSocketError enum (RuntimeRootNotAnchored/GuestNotAPlainName/DirectoryOutsideRuntimeRoot) whose Display preserves the three static-code substrings byte-for-byte; the two live_handlers.rs consumers updated; substring-asserting tests stay green. | | +| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | applied | W6 | fd5b41b4b | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/live_handlers.rs:2452` | guest_socket_directory now returns a pub(crate) GuestSocketError enum (RuntimeRootNotAnchored/GuestNotAPlainName/DirectoryOutsideRuntimeRoot) whose Display preserves the three static-code substrings byte-for-byte; the two live_handlers.rs consumers updated; substring-asserting tests stay green. | | | `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/src/seam.rs | verify_startup_routing returns Result<(), StartupRoutingViolation> (UnadmittedHandler/MissingHandlers, Display preserved for main.rs); audit_crate/run_cargo_metadata/dependency_tree return Result<_, S | | | `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | | `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/configured_argv.rs | ConfiguredArgvError, LauncherMetadataError, UnsafeLocalWorkloadsError, MediaRefError, UsbBusIdError, AuditPageError enums with Display+Error replace String/&'static str returns; unwrap-only callers co | | @@ -529,10 +529,10 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | | `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | ed46f196b | packages/d2b-contracts-provider/src/v3/provider_registry.rs | added GenerationMismatch variant kebab code provider-registry-generation-mismatch; updated failure-path test to assert the variant; census ProviderRegistryError=12 hits all in-file | | | `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 75e9c238c | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialSingleFlight lock() now recovers poisoned mutexes via unwrap_or_else(poisoned.into_inner()) and returns the guard directly (infallible); guard Drop recovers the same way instead of silently | | -| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-reso` | | | +| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-resource/src/v3/operations/error.rs:132, packages/d2b-resource-api/src/error.rs:11` | | | | `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | | `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_macvtap_intents now returns crate::error::Error via Error::manifest_parse_error (typed, two failure modes distinguishable); broker call site updated to house .map_err(/error/ BrokerError::Live | | -| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | applied | W4 | 5282e9337 | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core` | | | +| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | applied | W4 | 5282e9337 | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136` | | | | `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | applied | W6 | 8de97517b | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | find_network_spec and build_resource_network_intents return Result; the six resolve_network_*_intent pub methods return Result, Error> with Error::manifest_parse_error("resource-bundle.json", reason); ~20 call sites and the NetworkIntentSource trait updated; regression test pins kind ManifestParseError / code 40; error-codes.md unchanged; behavior note added to manifest-bundle.md. | | | `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/site.rs | SiteJson::validate returns SiteValidationError::InvalidWaylandSocket enum with Display token; caller and tests updated | | | `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | @@ -556,25 +556,25 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | applied-variant | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | observe_host returns Result<_, ObserveError>; the flattening format! is replaced by a closed error carrying both SystemCoreError legs with Error::source() (fallback is the chain source, probe error re | | | `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | HostDriverError::Display delegates to self.kind.failure_kind().code(); the three registry codes verified identical to the re-spelled literals. | | | `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | applied | U3 | 200aa2bb2 | packages/d2b-provider-network-local/src/nftables.rs | Sole non-test unwrap replaced with try_into().expect naming the statically-known invariant (64-byte chunk yields a 4-byte word slice). check/clippy exit 0; nftables tests pass. | | -| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | applied-variant | W4 | b56a46c1e | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provide` | applied-variant: kept the crate's existing exported ProviderError name (renaming is churn); test-fake slugs mapped to family variants; 4 pre-existing unused ProviderError variants kept as exported API | | +| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | applied-variant | W4 | b56a46c1e | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provider-notification-desktop/src/lifecycle.rs:291-297, packages/d2b-provider-notification-desktop/src/controller.rs:369, packages/d2b-provider-notification-desktop/src/controller.rs:930` | applied-variant: kept the crate's existing exported ProviderError name (renaming is churn); test-fake slugs mapped to family variants; 4 pre-existing unused ProviderError variants kept as exported API | | | `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U3 | eba219aa6 | packages/d2b-provider-notification-desktop/src/types.rs | Added NotificationError::Denied (slug notification-denied; not pinned in docs/reference) and mapped the five admission/zone/category rejection sites (host_sink.rs source/observer admission, zone misma | | | `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/ingress_policy.rs | Full connection-table rejection now reports IngressErrorClass::None, consistent with the sibling capacity refusal. | | | `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | applied | U3 | c22876d4f | packages/d2b-provider-process/src/driver.rs | Map VolumeBinding/Volume row parse failures to ProcessDriverErrorKind::SpecInvalid in identity() and serving_worker_launch() (now Result, _>); genuinely absent rows/views/attachments still y | | -| `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | packages/d2b-provider-process-systemd/src/error.rs (deleted) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | +| `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | `packages/d2b-provider-process-systemd/src/error.rs` (deleted by this row) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | | `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | | `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | skipped-stale | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | The wildcard match arm the row wanted removed is mandatory: `ProcessEffectError` is `#[non_exhaustive]` (packages/d2b-provider-process/src/backend.rs:216-217), so a match outside its defining crate cannot be exhaustive without it. [reconstructed: the wave-3 per-slice reports were never persisted, so this cell is reconstructed from the code rather than recovered from the record.] | | | `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServiceDriverError carries source: Option> with Error::source(); the Err(_) swallow in reconcile_service now attaches the store error and classify_error surfaces it as a fa | | | `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | | `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | | `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | de1a2c493eb2db826cd517128364c759a86240d9 | packages/d2b-provider-toolkit/src/operations/envelope.rs | audit_named falls back to the canonical (lowercase, dash-stripped) spelling when BoundedToken::parse rejects the raw name, so a refused PascalCase forwarded invocation lands its Denied record; already | | -| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/sr` | | | +| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/src/shared_provider.rs:539-546` | | | | `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | -| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/` | | | -| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtim` | applied-variant: key_ref returns Result; the cited spec_store.rs:60-63 anchor has no key_ref caller at base (d2b-resource-runtime has no provider-toolkit dependency), nothing to update there | | +| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/src/testing/fakes.rs:289-291, packages/d2b-provider-toolkit/src/testing/fakes.rs:337-339, packages/d2b-provider-toolkit/src/testing/fakes.rs:391-393` | | | +| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtime/src/spec_store.rs:60-63` | applied-variant: key_ref returns Result; the cited spec_store.rs:60-63 anchor has no key_ref caller at base (d2b-resource-runtime has no provider-toolkit dependency), nothing to update there | | | `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | | `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | applied | U3 | 2ab7a1ed2 | packages/d2b-provider-user/src/driver.rs | Display impl now writes self.kind.failure_kind().code(); registered FailureKind codes remain the single source, strings unchanged, no behavior change. | | -| `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-bindi` | BindingDriverArgs.zone is a ZoneId; BindingDriver derives the socket-identity bounded token once at construction instead of re-parsing the zone with expect on every pass, and the sole production construction in d2bd passes the parsed value | | +| `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-binding/src/driver.rs:426-427, packages/d2bd/src/resource_plane_v3.rs:2954` | BindingDriverArgs.zone is a ZoneId; BindingDriver derives the socket-identity bounded token once at construction instead of re-parsing the zone with expect on every pass, and the sole production construction in d2bd passes the parsed value | | | `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 -> W5 (driver-args class member key_ref; RS-0962; the class remainder landed in W5 at 14bf42022) | | `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | applied | U3 | e783447e2 | packages/d2b-provider-wayland-session/Cargo.toml | Added tracing = 0.1 (already in lockfile; Cargo.lock records one new dep edge) and map_err now logs provider=WAYLAND_SESSION_PROVIDER_REF with reason=%error before mapping to InvalidResource. | | | `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Empty batch now rejected with 'batch mutation count is zero'; MAX_BATCH_MUTATIONS check keeps the bound reason. Reason string unpinned in error-codes.md. | | @@ -585,7 +585,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | | `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | applied | U3 | 6f07391f0 | packages/d2b-telemetry/src/emitter.rs | Added EmitterError::InvalidLimits with Display arm and doc updates; zero-capacity/frame/age/retry guards return it; StatePoisoned kept for lock().map_err sites; check/test/clippy green. | | | `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | applied | U3 | 1453d6b9a | packages/d2b-telemetry/src/session_metrics_sink.rs | Deleted never-constructed SessionMetricsError::Encode variant and its session-metric-encode-failed Display arm; check/test/clippy green. | | -| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | applied | W6 | 0330ae04b | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/` | await_scope_identity's early-exit Ok(_) arm now maps to ScopeError::CreateFailed; the existing mapping chain carries it to HelperFailureCode::ScopeCreateFailed -> daemon wire code 42; both codes stay documented in error-codes.md (rows untouched, drift gate green); regression test pins the reclassified contract. | | +| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | applied | W6 | 0330ae04b | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/systemd.rs:338-346` | await_scope_identity's early-exit Ok(_) arm now maps to ScopeError::CreateFailed; the existing mapping chain carries it to HelperFailureCode::ScopeCreateFailed -> daemon wire code 42; both codes stay documented in error-codes.md (rows untouched, drift gate green); regression test pins the reclassified contract. | | | `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | | `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | | `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | a91ad9bbc | packages/d2bd/src/resource_plane_v3.rs | PlaneError's five String variants retyped: FoundationSeed(#[from] SeedError), ManagerSpawn(#[from] ractor::SpawnErr), Bundle(#[from] ResourceBundleError), Authority/Target(#[source] Box landed in wave 6 as slice w6-13. The audio mutation paths report a user-input refusal through the typed kinds TypedError::AudioVmNotFound (audio-vm-not-found, exit 2) and TypedError::AudioNotEnabled (audio-not-enabled, exit 70) instead of flattening both into TypedError::InternalIo { context, detail }; lock/read/write/host failures keep internal-io. Co-change: the two daemon wire kinds with their envelope text/exit codes/hello-rejection arm, the four mutation-site constructors, and hand-written rows in docs/reference/error-codes.md (the generated block is untouched, so gen_error_codes_drift stays the proof). Wire-visible: a public-socket client that matched internal-io on an unknown or audio-less VM sees the new kinds - the needs-contract move this row asked for; no in-tree consumer branches on the old slug. | | | `RS-0534` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | 96be9307a | packages/d2bd/src/resource_plane_v3.rs | ConstructionInputs::production now propagates attach_process_providers failures: state.provider_runtime.attach_process_providers(...).map_err(/error/ PlaneError::Authority(error.into()))? instead of ` | | | `RS-0536` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | fd6778735 | packages/d2bd/src/process_provider_runtime.rs | serving_worker_launch_args now warns when the 0700 enforcement on the worker socket parent fails: tracing::warn!(zone = %zone, socket_dir = %parent.display(), error = %error, ...) mirrors the pidfd sn | | -| `RS-0528` | `err` | `d2bd` | low | actionable | family | applied | W5 | 2fa4cd475 | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d` | TypedError's io, config, and broker-unavailable variants carry an `Option` origin (Arc) built by a bounded helper, Display renders the unchanged envelope string, and the raw-detail logging boundary renders a depth-capped source chain; the 34 owned composition.rs sites plus 67 more sites across d2bd-runtime, audio dispatch, forward rendezvous, and the bundle-tampered test are converted (116 sites legitimately pass None where detail is a literal or wire-field rendering), and a test pins byte-identical envelopes | | +| `RS-0528` | `err` | `d2bd` | low | actionable | family | applied | W5 | 2fa4cd475 | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d2bd/src/composition.rs:15243, packages/d2bd/src/composition.rs:15247` | TypedError's io, config, and broker-unavailable variants carry an `Option` origin (Arc) built by a bounded helper, Display renders the unchanged envelope string, and the raw-detail logging boundary renders a depth-capped source chain; the 34 owned composition.rs sites plus 67 more sites across d2bd-runtime, audio dispatch, forward rendezvous, and the bundle-tampered test are converted (116 sites legitimately pass None where detail is a literal or wire-field rendering), and a test pins byte-identical envelopes | | | `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | already-fixed | U3 | ebb3831b1 | packages/d2bd-runtime/src/broker_transport.rs | At session-start HEAD, default_audit_join_context maps CanonicalAuditDigest::parse failures to TypedError::WireInvalidFrame;no .expect remains (commit ebb3831b1, ledger wave U1 applied-variant). No ed | | | `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | c14b5d486 | packages/d2bd-runtime/src/wire.rs | map_parse_error classifies structurally: serde_json::Error::classify() gates the frame kind, and the generic WireInvalidFrame detail now carries line/column; the two payload-level wire kinds (unknown- | | | `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | cdfb78d49 | packages/d2bd-runtime/src/exec_session.rs | spawn_session_worker now returns std::io::Result> (Builder::spawn error propagated via Ok(...)?), replacing the expect panic; the two test call sites unwrap with expect. | | | `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 75c49e784 | packages/d2bd-runtime/src/console_session.rs | Deleted panicking impl Default for ConsoleClientHandle (census: no ConsoleClientHandle::default() callers in workspace). | | | `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | a09140432 | packages/d2bd-runtime/src/daemon_version.rs | version-file read failures typed (VersionFileReadError); check + tests green | | | `RS-0543` | `err` | `xtask` | medium | actionable | leaf | applied | U3 | 7194d24e9 | packages/xtask/src/delivery/recovery.rs | RecoveryError::Read added for fs open/read failures; Json(String) now carries the bounded serde detail (field names/positions only via error.to_string(), never payload values, keeping the redaction co | | -| `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 6467d8d2c | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zon` | the wire_deserialize! macro moves to d2b-contracts with #[macro_export] and 72 hand-written Wire admission Deserialize impls (17 contracts-provider, 55 contracts-resource) become macro invocations; container attributes, field lists, and admission expressions are token-identical, the emitted schemas are byte-identical, and zone-session's 28 invocations re-point at the shared home (one contracts-broker site is out of this slice's scope) | | +| `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 6467d8d2c | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558` | the wire_deserialize! macro moves to d2b-contracts with #[macro_export] and 72 hand-written Wire admission Deserialize impls (17 contracts-provider, 55 contracts-resource) become macro invocations; container attributes, field lists, and admission expressions are token-identical, the emitted schemas are byte-identical, and zone-session's 28 invocations re-point at the shared home (one contracts-broker site is out of this slice's scope) | | | `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | applied | W6 | f25b21e84 | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu [reconstructed: m with `#[serde(rename_all = "lowercase")]`) keeps the serialized shapes "unknown"/"completed" identical, so no DURABLE_VERSION bump is needed]. DurableRecord.outcome typed as CellOutcome with the derive; hand match and re-parse deleted; unknown-outcome fail-closed preserved via serde unknown-variant rejection mapped to CorruptDurable. | | | `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | | `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | applied | W6 | 1ab759f13 | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). AuditExportEntry now carries exactly one payload through the closed AuditExportEntryPayload enum (Record { record } or Error { error }) instead of the independent record/error optional pair, so an entry that carries neither or both is unrepresentable and refused at decode; the emitted members are unchanged (sequence plus exactly one of record or error), so the broker audit page and the public daemon audit page keep their JSON and the legacy_export_entry_line renderer keeps its output. Co-change: the d2b-contracts-broker re-export, d2b-broker/src/audit.rs, the d2b entry-mapping closure, the d2bd-runtime wire literal, and the regenerated docs/reference/daemon-api.md plus docs/reference/schemas/v2/wire-protocol.json. Gate on the merged tree: cargo test -p d2b-contracts rc=0 (120 tests plus 1 doctest, including an_entry_emits_and_admits_exactly_one_payload and an_entry_payload_is_admitted_exactly_once), cargo test -p d2b-broker rc=0, cargo check over the seven touched crates --all-targets rc=0, gen_schemas_drift and gen_daemon_api_drift green. | | -| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | skipped-stale | W6 | 8351954a0 | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> re-verified at HEAD in slice w6-12, which merged into phase-w6-integration (merge b07a7e887): the claim does not hold at HEAD, so no admission edit was made. The audited premise has the guard inverted - serde 1.0.229 refuses unknown members through the CONTAINER's deny_unknown_fields, while the FLATTENED type's own deny_unknown_fields is the inert one, and both audited requests (OpenUnitPidfdRequest, StopUnitRequest) carry the container attribute, so a stray member is refused today and there is no silently-accepted state to repair. Raw probe kept at .scratch/rs0547-flatten-probe.txt (w6-12 worktree): container-deny + inner-lax still refuses the stray member (unknown field `unknownMember`), container-lax + inner-deny and container-lax + inner-lax accept it, and serde_json::from_value and from_slice both refuse. The requested admission pin landed anyway as 8351954a0 (flattened_unit_requests_refuse_unknown_members), so the observed contract is pinned rather than repaired; gate: cargo test -p d2b-contracts-broker rc=0. | | +| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | skipped-stale | W6 | 8351954a0 | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/src/broker_wire.rs:1783-1834` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> re-verified at HEAD in slice w6-12, which merged into phase-w6-integration (merge b07a7e887): the claim does not hold at HEAD, so no admission edit was made. The audited premise has the guard inverted - serde 1.0.229 refuses unknown members through the CONTAINER's deny_unknown_fields, while the FLATTENED type's own deny_unknown_fields is the inert one, and both audited requests (OpenUnitPidfdRequest, StopUnitRequest) carry the container attribute, so a stray member is refused today and there is no silently-accepted state to repair. Raw probe kept at .scratch/rs0547-flatten-probe.txt (w6-12 worktree): container-deny + inner-lax still refuses the stray member (unknown field `unknownMember`), container-lax + inner-deny and container-lax + inner-lax accept it, and serde_json::from_value and from_slice both refuse. The requested admission pin landed anyway as 8351954a0 (flattened_unit_requests_refuse_unknown_members), so the observed contract is pinned rather than repaired; gate: cargo test -p d2b-contracts-broker rc=0. | | | `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | | `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | -| `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | applied | W5 | e77bf4940 | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v` | ResourceError deserialization routes through the validating constructor, rejecting a revision for a kind that forbids it and inconsistent retry fields; the wire shape is unchanged | | -| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resour` | | | +| `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | applied | W5 | e77bf4940 | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v3/error.rs:177` | ResourceError deserialization routes through the validating constructor, rejecting a revision for a kind that forbids it and inconsistent retry fields; the wire shape is unchanged | | +| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resource/src/v3/payload_schema.rs:36` | | | | `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | applied-variant | W4 | a2cf0e614 | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | applied-variant: consolidated 28 Wire-shape Deserialize impls behind the crate-local wire_deserialize! macro in d2b-contracts-zone-session (canonical home; later waves must reuse it, not write a third macro); parsed_deserialize! requires Self::parse(String) (JSON-string wire), which no Wire-struct impl matches - adopting it would change the wire format the row never asked to change (Main ruling 2026-09-25) | | | `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/storage_lifecycle.rs | serde rejects rename_all on struct variants (field attribute); applied the equivalent house pattern #[serde(rename_all_fields = "camelCase")] on the enum container + dropped per-field renames; seriali | | | `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | applied | W7 | fe7c349ea | `packages/d2b-core/src/bundle_resolver.rs:207` | ZoneNativeIndexDocument declares all six keys nixos-modules/index.nix emits and now denies undeclared ones (the four unread keys are defaulted so a partial index still loads); a new admission test fails without the deny and the four committed index fixtures still parse. Merged cd2b66149. | | | `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | -| `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | applied | W5 | 6ecf465b7 | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controlle` | typed serde structs (rename_all camelCase, deny_unknown_fields) replace the Value-walking assignment codec and the child-create json! literal builder; exact keys, version 1, ascending verb arrays, canonical bytes, and the size bounds are pinned by the transport tests | | +| `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | applied | W5 | 6ecf465b7 | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controller/src/controller_assignment.rs:735, packages/d2b-core-controller/src/controller_assignment.rs:891, packages/d2b-core-controller/src/controller_assignment.rs:901` | typed serde structs (rename_all camelCase, deny_unknown_fields) replace the Value-walking assignment codec and the child-create json! literal builder; exact keys, version 1, ascending verb arrays, canonical bytes, and the size bounds are pinned by the transport tests | | | `RS-0557` | `serde` | `d2b-host` | low | actionable | family | applied | W4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:229` | | | | `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | | `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | | `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W7 | bcdb699ea | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:12` | AuditEvent drops Deserialize (never read back; every site serializes), keeping Serialize and the bounded-MIME adapter, so the audit wire shape is unchanged. Merged ae531b399. | | | `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | applied | W7 | bf8dc0bc2 | `packages/d2b-provider-command/src/command.rs:48` | both JsonSchema impls publish the exact admission their parse enforces (exec excludes C0/DEL/C1, argv slot gains minLength and the whole-slot brace pattern); CommandArgvSlot::parse refuses control characters in literal slots so schema and parse agree; the generated v3 Command schema moved through its generator, and an ECMA-262 oracle over 1.1M code points found no mismatch. Merged efdd43e7d. | | | `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | d58f183d5 | packages/d2b-provider-device-gpu/src/gpu_argv.rs | deny_unknown_fields added to GpuArgvInput/GpuParams/GpuDisplayConfig (mirroring VideoArgvInput); new rejects_unknown_fields test pins top-level, params-nested, and display-nested rejection. Mutation c | | -| `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | applied | W5 | 4cb0daadb | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provid` | the receive path decodes each newline-delimited bridge frame with a typed #[serde(tag = "type", rename_all = "snake_case")] inbound enum mirroring the outbound frame instead of scanning raw bytes for the refresh substring; a frame that fails to decode is rate-limited-diagnosed and dropped, and later frames still refresh (pinned by tests) | | +| `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | applied | W5 | 4cb0daadb | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:395` | the receive path decodes each newline-delimited bridge frame with a typed #[serde(tag = "type", rename_all = "snake_case")] inbound enum mirroring the outbound frame instead of scanning raw bytes for the refresh substring; a frame that fails to decode is rate-limited-diagnosed and dropped, and later frames still refresh (pinned by tests) | | | `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 84b343101 | packages/d2b-provider-display-wayland/src/spec.rs | Inert serde try_from attribute removed; rename_all/deny_unknown_fields and the manual Deserialize + TryFrom kept. | | | `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | | `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | already-fixed | W7 | 73e163675 | `packages/d2b-provider-network-local/src/driver.rs:296` | the serde failure is no longer dropped - the map_err closure emits a structured warn with the error field before mapping to the toolkit's SpecInvalid; re-verified at 6dc80e258. | | @@ -631,9 +631,9 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | applied | W7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:1533` | the take-controller-bootstrap leg now builds a typed TakeControllerBootstrapRequest and parses the typed response; a missing/mistyped result fails the leg with a structured warning instead of reading as not-taken (an explicit taken=false still returns Ok(None)), and the fd stays index 0 (the reply carries exactly one descriptor). Merged f2b98ccfb. | | | `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | applied | W7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9` | deserialization goes through a wire struct plus TryFrom so the derived path runs new()/validate(), and the pinned (hand-authored) schema now records the secret-shape exclusion; a schema-vs-validate agreement probe over 7.9M adversarial identifier pairs found 0 mismatches. Merged 82d6c395d. | | | `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | applied | W7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:233` | parse_material_json is replaced by derived relayListen/relaySend structs with deny_unknown_fields plus the same value pass; admission is strictly stronger (unknown and duplicate keys are now refused, and no in-tree producer emits either) and a malformed-shape test pins it. Merged 82d6c395d. | | -| `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | applied | W5 | 379eb3b33 | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transpo` | VsockTransportSettings deserializes through a private wire mirror with TryFrom validation, so untrusted JSON is rejected at the boundary; fields are private with accessors and the wire names and JSON schema are unchanged - the needs-contract verdict is overridden because no wire surface moved | | +| `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | applied | W5 | 379eb3b33 | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transport-vsock/src/settings.rs:42-50, packages/d2b-provider-transport-vsock/tests/schema.rs:13-18` | VsockTransportSettings deserializes through a private wire mirror with TryFrom validation, so untrusted JSON is rejected at the boundary; fields are private with accessors and the wire names and JSON schema are unchanged - the needs-contract verdict is overridden because no wire surface moved | | | `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | applied | U3 | b00a073f2 | packages/d2b-provider-volume-local/src/content.rs | ContentFile/ContentProjection/NetworkConfigContentProjection decode via serde try_from Raw mirrors running validating constructors; Deserialize dropped from evidence types; wire shape unchanged. | | -| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | W4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-way` | | | +| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | W4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-wayland-policy/src/effects_service.rs:205-206, packages/d2b-provider-wayland-policy/src/audio_registry.rs:517-534` | | | | `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | | `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | applied-variant | U3 | f1bb96854 | packages/d2bd/src/composition.rs | deny_unknown_fields added to both GatewayGuestConfigFile and GatewayGuestRelayConfigFile. The config-typo test landed as direct deserialization tests on both structs (gateway_guest_config_tests mod), | | | `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | applied | W7 | 369627b78 | `packages/d2bd/src/composition.rs:20373` | one parse_activation_marker seam refuses any schemaVersion != 1 with a structured warning and all three read sites (read_activation_marker plus both startup loops) go through it, so a future caller cannot adopt a versioned marker without the check. Merged a74fd9b0c. | | @@ -655,7 +655,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | | `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | | `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | abc324d2a | packages/d2b-provider-toolkit/src/base/guest.rs | serve_enrolled now emits tracing::warn!(frame_bytes, ...) before dropping a frame GuestFrame::new rejects (empty or oversized), keeping the session up. No correlation identifiers in the record. cargo | | -| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src` | applied-variant: method field unavailable at all 3 sites (receive failure precedes decode; readiness/loop failures carry no request); zone+provider added from the route binding | | +| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src/server/session.rs:255, packages/d2b-provider-toolkit/src/server/session.rs:262` | applied-variant: method field unavailable at all 3 sites (receive failure precedes decode; readiness/loop failures carry no request); zone+provider added from the route binding | | | `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/relay_transport.rs | | | | `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | | `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | @@ -683,7 +683,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0631` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | ba9873712 | `packages/d2b-broker/src/protocol.rs` | MAX_FRAME_SIZE and connect/bind/send_json_frame/recv_json_frame documented | | | `RS-0632` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 6b709ea9a | `packages/d2b-broker/src/ops/state_dir.rs` | DirKind, PrepareDirRequest/fields, PrepareDirAudit, ReplaceOrCreateResult, prepare_dir and live helpers documented with # Errors | | | `RS-0621` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 1643cd532 | `packages/d2b-broker/src/audit.rs` | field docs on AuditDropSummary/AuditEntry; contract docs on AuditLog::open/audit_drop_summary | | -| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | applied | W4 | 27a3de0bd | `packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b` | | | +| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | applied | W4 | 27a3de0bd | `packages/d2b-broker/src/runtime.rs:324, packages/d2b-broker/src/runtime.rs:375, packages/d2b-broker/src/runtime.rs:398` | | | | `RS-0622` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 7ac3d8cdf | `packages/d2b-broker/src/ops/host_generation_handoff.rs` | doc comments added per row | | | `RS-0623` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 025b075a8 | `packages/d2b-broker/src/ops/route.rs` | doc comments added per row | | | `RS-0615` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 34f355adf | `packages/d2b-broker/src/ops/usbip_lock.rs` | doc comments added per row | | @@ -707,13 +707,13 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | e12e51dac | `packages/d2b-contracts-control/src/public_wire.rs` | Docs added to the named request/status types plus UsbipProbeEntry field meanings; # Errors added to ShellName::new (RealmAccentColor::new covered by RS-0643) | | | `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | 5c5b2d478 | `packages/d2b-contracts-control/src/unsafe_local_wire.rs` | Constants documented with the daemon-enforced bounds, wire types one-lined, helper fns and RealmAccentColor::new get # Errors | | | `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | applied | U2 | e5b584959 | `packages/d2b-contracts-control/src/terminal_wire.rs` | One-line docs per DTO plus the redacted-Debug note on session-bearing types | | -| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contract` | | | +| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:478, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:72, packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs:93` | | | | `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | | `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/artifact.rs` | doc comments on the artifact id bound, error, type, parse, and accessor | | -| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | e7bba788d | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-res` | none (anchor drift only) | | +| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | e7bba788d | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-resource/src/v3/execution_policy.rs:944` | none (anchor drift only) | | | `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/limits.rs` | module-level rationale naming the enforcing boundaries | | -| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | 712bb24af | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-reso` | three enumerated sub-claims were already documented at the audit baseline and left unchanged (verified via git show 6ebdd4cec): MutationSealAcceptor::diagnose (seal.rs:176-177), PreparedStoreMutation: | | -| `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | applied | W5 | 0274747fc | `src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.r` | the 37 ComponentSession v3 wire constants carry one-line docs naming their wire role; values, names, and ordering are unchanged | | +| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | 712bb24af | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-resource/src/v3/operations/error.rs:262, packages/d2b-contracts-resource/src/v3/operations/seal.rs:48, packages/d2b-contracts-resource/src/v3/operations/seal.rs:121` | three enumerated sub-claims were already documented at the audit baseline and left unchanged (verified via git show 6ebdd4cec): MutationSealAcceptor::diagnose (seal.rs:176-177), PreparedStoreMutation: | | +| `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | applied | W5 | 0274747fc | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:27, packages/d2b-contracts-zone-session/src/v3/component_session.rs:51` | the 37 ComponentSession v3 wire constants carry one-line docs naming their wire role; values, names, and ordering are unchanged | | | `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/manifest_v04.rs` | module doc plus docs on ManifestV04/ManifestMeta/ObservabilityMeta/VmEntry/VmLifecycle/VmGracefulShutdown/VmLiveActivation/VmLanPolicy/VmObservability/VmShellMetadata/ManifestShellName; # Errors on fr | | | `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | one-line docs naming the exact BundleOpId shape added to all 15 undocumented intent_id_* constructors | | | `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/main.rs` | One-line field docs added to RuntimeReadiness (4), RecoverySnapshot (5), HandlerStatus (9). | | @@ -729,8 +729,8 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | f0210347a,48437393c | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | the Policy::new hunk landed in the policy-unification commit f0210347a (same file as RS-0040); the other three hunks in 48437393c | | | `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | applied | W4 | 64408bc95 | `src/audit.rs:172, src/audit.rs:174` | | | | `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 460a05942 | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | none | | -| `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,b8724cd15,ac5e33ab1 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-` | picker.rs hunks shared commit 018c1dad5 with RS-0041/RS-0042 (index race, see RS-0041) | | -| `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,ac5e33ab1,08c2e3648 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-prov` | picker.rs hunk shared commit 018c1dad5 (index race, see RS-0041) | | +| `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,b8724cd15,ac5e33ab1 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:128, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:162, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:336-337, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:424-427, packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:79-81, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:204-242, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:248-249` | picker.rs hunks shared commit 018c1dad5 with RS-0041/RS-0042 (index race, see RS-0041) | | +| `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,ac5e33ab1,08c2e3648 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:74, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:7` | picker.rs hunk shared commit 018c1dad5 (index race, see RS-0041) | | | `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | applied | U2 | ef3bc5ec9 | `packages/d2b-provider-command/src/command.rs` | Added one-line # Errors naming CommandContractError variants to CommandExec::parse, CommandArgvSlot::parse, CommandSpec::new. | | | `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 7a6ab2d2d | `packages/d2b-provider-config-nixos/src/controller.rs` | # Errors added to all 19 pub Result items naming ConfigError variants | | | `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | applied | U2 | b68a9b55e | `packages/d2b-provider-credential/src/session.rs` | Added # Errors to CredentialRevocationRequest::new (InvalidResource conditions) and CredentialSession::revoke_credential (Revocation). | | @@ -756,7 +756,7 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs` | # Errors sections on GuestSetupDescriptor new/from_canonical_bytes/canonical_bytes/validate_integrity/verify_with, GuestChildBatch::from_descriptor, and the health evidence constructors. | | | `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U2 | 613491144 | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | # Errors added to DeviceAdmission::validate, QemuMediaController::reconcile, LaunchTicket::new, QmpSession::negotiate | | | `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/action_nonce.rs` | # Errors sections on ActionNonceStore::register, NotificationRuntime::new, NotificationSink::deliver_from_guest_source naming exact variants. | | -| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | skipped-stale | U2 | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-not` | All three cited docs are complete standalone first sentences at baseline 6ebdd4cec (verified via git show) and HEAD; the lane quoted tail lines of multi-line docs. | | +| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | skipped-stale | U2 | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-notification-desktop/src/test_support.rs:14, packages/d2b-provider-notification-desktop/src/guest_source.rs:17` | All three cited docs are complete standalone first sentences at baseline 6ebdd4cec (verified via git show) and HEAD; the lane quoted tail lines of multi-line docs. | | | `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/lib.rs` | Added one-line doc comments to PROVIDER_NAME, PROVIDER_REF, PROVIDER_API_MAJOR mirroring OTEL_HOST_BRIDGE_ROLE. | | | `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/agent.rs` | Added # Errors to ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream, EmitterSocket::bin | | | `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | applied | U2 | 4e381161f | `packages/d2b-provider-operation/src/operation.rs` | Added one-line # Errors naming OperationContractError variants to OperationAudit::new, AuditJoin::new, OperationFds::new, OperationBounds::new, OperationSpec::new. | | @@ -819,35 +819,35 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0753` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | doc comments above today_utc_iso8601 and civil_from_days naming the Hinnant algorithm, constants, and epoch fallback | | | `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | applied-variant | W3 | 44cb49a0d | `context.rs:570, context.rs:538` | | | | `RS-0757` | `perf` | `d2b-audit` | low | actionable | leaf | applied | W3 | 10923b65e | `packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970` | | | -| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | applied | W5 | 6488d26a4 | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | the broker protocol receive path peeks the 4-byte length prefix with MSG_PEEK and allocates the declared size plus the prefix; SCM_RIGHTS receipt is size-exact the same way, and sockets without MSG_PEEK keep the fixed allocation | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | applied | W5 | 6488d26a4 | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | the broker protocol receive path peeks the 4-byte length prefix with MSG_PEEK and allocates the declared size plus the prefix; SCM_RIGHTS receipt is size-exact the same way, and sockets without MSG_PEEK keep the fixed allocation | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | | `RS-0759` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/nft.rs:784-790` | | | | `RS-0760` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368` | | | -| `RS-0758` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, pa` | | | -| `RS-0761` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/stor` | | | +| `RS-0758` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, packages/d2b-broker/src/state_cells.rs:524` | | | +| `RS-0761` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/store_view_posture.rs:310-352` | | | | `RS-0763` | `perf` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/router.rs:4228-4235` | | | | `RS-0764` | `perf` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/streams.rs:642-658` | | | -| `RS-0765` | `perf` | `d2b-contracts-resource` | low | actionable | leaf | applied | W3 | 395eba54d | `packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-reso` | | | +| `RS-0765` | `perf` | `d2b-contracts-resource` | low | actionable | leaf | applied | W3 | 395eba54d | `packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-resource/src/v3/resource_status.rs:650` | | | | `RS-0766` | `perf` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | W3 | 5966950aa | `resource_bundle.rs:382` | | | | `RS-0767` | `perf` | `d2b-core` | medium | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:16` | | | | `RS-0768` | `perf` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:37` | | | | `RS-0769` | `perf` | `d2b-core` | low | actionable | leaf | applied-variant | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:16` | | | | `RS-0770` | `perf` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628` | | | -| `RS-0772` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2` | | | +| `RS-0772` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2b-clipd.rs:1838, src/bin/d2b-clipd.rs:2797` | | | | `RS-0773` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159` | | | -| `RS-0774` | `perf` | `d2b-provider-config-nixos` | low | actionable | leaf | applied-variant | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nix` | | | +| `RS-0774` | `perf` | `d2b-provider-config-nixos` | low | actionable | leaf | applied-variant | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/ttrpc.rs:326, packages/d2b-provider-config-nixos/src/ttrpc.rs:81` | | | | `RS-0775` | `perf` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | W3 | a34843f8e | `src/session_children.rs:316, src/session_children.rs:317` | | | | `RS-0776` | `perf` | `d2b-provider-guest` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:8` | | | | `RS-0777` | `perf` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | W3 | 513edf50c | `shutdown.rs:505-513` | | | | `RS-0778` | `perf` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | W3 | e4cbd3054 | `packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239` | | | | `RS-0779` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/nftables.rs:266-268` | | | | `RS-0780` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | W3 | bacc017aa | `src/observe.rs:305` | | | -| `RS-0781` | `perf` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-not` | | | +| `RS-0781` | `perf` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-notification-desktop/src/host_sink.rs:276-291, packages/d2b-provider-notification-desktop/src/host_sink.rs:376, packages/d2b-provider-notification-desktop/src/host_sink.rs:484-493` | | | | `RS-0782` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `emitter_socket.rs:139` | | | | `RS-0783` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `ingress_policy.rs:203, ingress_policy.rs:368` | | | | `RS-0784` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:44` | | | -| `RS-0785` | `perf` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process` | | | -| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/sr` | SharedProviderEffectRequest borrows the row's canonical spec document from the driver's spec envelope instead of cloning it into every reconcile and delete request | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) -| `RS-0787` | `perf` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-p` | | | +| `RS-0785` | `perf` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process-systemd/src/operations.rs:421` | | | +| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/src/shared_provider.rs:1024, packages/d2b-provider-toolkit/src/shared_provider.rs:479-481` | SharedProviderEffectRequest borrows the row's canonical spec document from the driver's spec envelope instead of cloning it into every reconcile and delete request | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | +| `RS-0787` | `perf` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:629-630, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:814, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:844` | | | | `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | | `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | applied | W3 | 037e23533 | `driver.rs:437-440, driver.rs:614-617` | | | | `RS-0791` | `perf` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:1006` | | | @@ -855,59 +855,59 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0793` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458` | | | | `RS-0790` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:495, manager_backend.rs:449-455` | | | | `RS-0794` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/manager.rs:1390` | | | -| `RS-0795` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/g` | | | +| `RS-0795` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/guest_target.rs:1212` | | | | `RS-0796` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `record.rs:125, record.rs:147` | | | | `RS-0797` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `engine.rs:1354, engine.rs:1362, scheduler.rs:72` | | | | `RS-0798` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `record.rs:120, record.rs:146` | | | | `RS-0799` | `perf` | `d2b-session-unix` | low | actionable | leaf | applied | W3 | 774c148eb | `packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, ` | | | -| `RS-0800` | `perf` | `d2bd` | medium | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, pa` | | | +| `RS-0800` | `perf` | `d2bd` | medium | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, packages/d2bd/src/resource_runtime.rs:2505, packages/d2bd/src/resource_runtime.rs:2856` | | | | `RS-0801` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/process_provider_runtime.rs:333` | | | | `RS-0802` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476` | | | -| `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.r` | | | +| `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.rs:392-396` | | | | `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | applied | W4 | 87c3172bc | `public_read_model.rs:117-118` | | | -| `RS-0808` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packag` | | | +| `RS-0808` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packages/xtask/src/bazel_evidence.rs:407` | | | | `RS-0805` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:431` | | | | `RS-0806` | `perf` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:582` | | | | `RS-0807` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:972` | | | | `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | applied | W7 | 8c3c48c0c | `clippy.toml:82` | the three lock entries now name the resolved lock_api paths the parking_lot type aliases point at, so clippy finally fires on every real .lock()/.read()/.write() site; the workspace's unsuppressed sites were taken to zero by the burn-down slices (sanctioned per-site allows or tokio conversions) and the census baseline was regenerated through its own write mode (282 key renames, no count growth). blocking-census --check, check-async-gate and check-provider-crate-layout are green on the flip head; a force-warn probe proves the flipped path matches the real sites while the alias spelling matched none. Merged c31e798ce. | | | `RS-0809` | `conc` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/envelope/mod.rs:1146, src/envelope/mod.rs:2144` | | | | `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | applied | W7 | 50be72eea | `packages/d2b-bus/src/registry.rs:530` | RouteLeaseState.revoked is an AtomicBool with a Release store at remove and Acquire loads at with_active (weakest correct ordering; the latch is one-way), and the two synchronous-path allows are gone; the guard that used to span Operations::begin's mutation no longer serializes it. Merged 01daff2b1. | | -| `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-p` | | | +| `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-provider/src/v3/credential/service.rs:963, packages/d2b-contracts-provider/src/v3/credential/service.rs:977` | | | | `RS-0812` | `conc` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96` | | | | `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | applied | W7 | 7e194b77c | `packages/d2b-provider-credential/src/test_support.rs:97` | 27 previously unsuppressed recorder/impl lock sites now carry the sanctioned cfg(test) helper allow (19 in test_support.rs, 7 in the driver test module, 1 in session.rs); synchronous accessors stay synchronous. Merged 78db8d04d. | | | `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | applied-variant | W7 | 7e194b77c | `packages/d2b-provider-device-gpu/src/effects_service.rs:310` | the three gpu_authority_leases lock sites take one sanctioned synchronous-path allow on each enclosing port fn rather than one per call; the Arc type is unchanged because the port is genuinely synchronous. Merged 78db8d04d. | | -| `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-` | | | +| `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-device-security-key/src/relay_service.rs:281, packages/d2b-provider-device-security-key/src/relay_service.rs:489-599, packages/d2b-provider-device-security-key/src/test_support.rs:32-89` | | | | `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | applied | W7 | 7e194b77c | `packages/d2b-provider-device-usbip/src/test_support.rs:46` | five sanctioned cfg(test) helper allows cover the seven recorder lock sites; no field or type changed. Merged 78db8d04d. | | | `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | applied | W7 | e4277787d | `packages/d2b-provider-guest/src/driver.rs:507` | GuestStatusSink is Arc>> and every write (guest effects service, d2bd resource runtime) awaits it; d2bd was the only external consumer. Merged 8c0715d2f. | | | `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | applied | W7 | e4277787d | `packages/d2b-provider-guest/src/test_support.rs:68` | recorders moved to the toolkit SharedLog, tokio locks with async accessors, or std::sync locks with sanctioned cfg(test) helper allows where a sync trait accessor forces it; parking_lot dropped from the crate and the async-gate inventory and policy-input closures regenerated. Merged 8c0715d2f. | | | `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | applied | W7 | 764d87ef9 | `packages/d2b-provider-process/src/driver.rs:680` | EphemeralRuntime's two clocks are tokio::sync::Mutex and all six accessors are async, awaited by every call site; the crate's remaining unsuppressed sites are test-only state under sanctioned cfg(test) helper allows, taking the crate's post-flip census to 0. Merged 849f2974b. | | -| `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.` | | | +| `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.rs:451, packages/d2b-provider-process/src/driver.rs:458, packages/d2b-provider-process/src/driver.rs:462` | | | | `RS-0821` | `conc` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:43, src/testing.rs:79` | | | | `RS-0822` | `conc` | `d2b-provider-toolkit` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-toolkit/src/operations/envelope.rs:487` | | | -| `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-uni` | | | +| `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-transport-unix/src/portal.rs:18` | | | | `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | applied | W7 | 89961f9d9 | `packages/d2b-provider-user/src/test_support.rs:47` | the five recorder/fake fields are tokio::sync::Mutex with the host-sibling accessor split (11 awaited locks, 7 sync try_locks), 18 lock sites converted, parking_lot dropped from the crate, and the async-gate inventory entries rewritten through its write mode. Merged 47ba61aec. | | -| `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_sup` | | | -| `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-bindin` | | | -| `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone` | | | +| `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_support.rs:135, packages/d2b-provider-user/src/test_support.rs:140, packages/d2b-provider-user/src/test_support.rs:152, packages/d2b-provider-user/src/test_support.rs:155, packages/d2b-provider-user/src/driver.rs:854` | | | +| `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-volume-binding/src/driver.rs:1139-1142, clippy.toml:82` | | | +| `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone_client.rs:512, packages/d2b-resource-client/src/zone_client.rs:513, packages/d2b-resource-client/src/process_attach.rs:409, packages/d2b-resource-client/src/process_attach.rs:412` | | | | `RS-0828` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/resource.rs:247` | | | | `RS-0829` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:` | | | | `RS-0830` | `conc` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `admission.rs:756, admission.rs:1666, driver.rs:33` | | | -| `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src` | | | +| `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src/protocol.rs:167, packages/d2b-unsafe-local-helper/src/protocol.rs:195` | | | | `RS-0832` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs` | | | | `RS-0833` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414` | | | | `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | W7 | 04cf64c5d | `packages/d2bd-runtime/src/unsafe_local_helper.rs:26` | the four registry/connection/ledger fields are tokio::sync::Mutex and all 39 lock sites reach the tokio seat, through a lock_registry dual seat (blocking_lock off-runtime, bounded try-lock spin on the in-runtime --once path where plain blocking_lock panics) - the panic was reproduced in d2bd's bundle_tampered_envelope test with the plain seat. Merged e65d4954e. | | | `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | W7 | 04cf64c5d | `packages/d2bd-runtime/src/concurrency.rs:163` | OpLockManager::acquire's four try_lock+spin_loop loops are replaced by blocking seats for the production d2b-conn handler threads (a contended op parks instead of burning a core), with the bounded spin kept only on the in-runtime --once path where the blocking seats panic; the stale spin doc is deleted and the dual-seat ordering recorded. Merged e65d4954e. | | -| `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support` | | | -| `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | 9b64eaa27 | packages/d2b-broker/src/runtime.rs (reap fn; kernel_ops.rs callers) | bounded WNOHANG reap poll replaces the blocking waitid; orphaned helpers deleted | | +| `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support.rs:166, resource_runtime_support.rs:170, resource_runtime_support.rs:175-178` | | | +| `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | 9b64eaa27 | `packages/d2b-broker/src/runtime.rs:11801` (targeted_reap_runner; called from kernel_ops.rs:916 and :977) | bounded WNOHANG reap poll replaces the blocking waitid; orphaned helpers deleted | | | `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | 25dfa3aee | packages/d2b-broker/src/sys.rs, packages/d2b-broker/src/ops/swtpm_dir.rs | setfacl shellout moved behind an async wrapper on a bounded worker | | | `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | a6d8fb022 | packages/d2b-broker/src/ops/media.rs | nss group lookup hoisted to a LazyLock, off the per-write path | | | `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | f4f09c74c | packages/d2b-broker/src/ops/host_generation_handoff.rs | flock wait moved to a bounded worker (sanctioned allow reason) | | | `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | | `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | applied | W7 | 1f8e52a5f | `packages/d2b-broker/src/runtime.rs:7711` | the whole USB-audit serial HMAC keyring body hops onto the d2b-core bounded loader probe seat, so no blocking stat/mkdir/open/create/fchmod/fsync runs on an executor worker; every hardening check is preserved verbatim (0o700 root-owned dir, O_NOFOLLOW plus O_CLOEXEC open, descriptor-level root-only validation, dir-fd openat create with 0o400 and file+dir fsync) and the existing keyring test passes unchanged. The whole-body hop was chosen over tokio::fs legs because path_safe's openat-on-dir_fd chain has no path-based equivalent. Merged d9a91015a. | | -| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port` | ProcessLaunchEffectPort and ProcessProvider declare their methods as `async fn` (the RPITIT `impl Future + Send` form is retired) under the house `#[allow(async_fn_in_trait)]` that the pinned lint configuration requires; default bodies are plain async blocks, implementors and the single Send-bound caller keep working, and the bazel graphs re-point consumer test targets at the test-support variants so each crate keeps one instance | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port.rs:109` | ProcessLaunchEffectPort and ProcessProvider declare their methods as `async fn` (the RPITIT `impl Future + Send` form is retired) under the house `#[allow(async_fn_in_trait)]` that the pinned lint configuration requires; default bodies are plain async blocks, implementors and the single Send-bound caller keep working, and the bazel graphs re-point consumer test targets at the test-support variants so each crate keeps one instance | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | | `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | applied | W3 | 7de088b5d | `packages/d2b-provider/src/agent.rs:316-324` | | | -| `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-cre` | | | -| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | applied | W5 | 7a971ec0b | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | the TPM prepare-state kernel round trip runs on the bounded kernel seat and the NSS lookups on the bounded loader worker instead of the executor worker; spawn_blocking is deny-listed by clippy.toml and banned by plan KD2 (2026-09-16-001), so the sanctioned bounded seats carry the work, the timeout and error mapping are byte-preserved, and the crate's async-gate inventory entries are refreshed for the line shift | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-credential-secret-service/src/lib.rs:1341, packages/d2b-provider-credential-secret-service/src/lib.rs:1380` | | | +| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | applied | W5 | 7a971ec0b | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | the TPM prepare-state kernel round trip runs on the bounded kernel seat and the NSS lookups on the bounded loader worker instead of the executor worker; spawn_blocking is deny-listed by clippy.toml and banned by plan KD2 (2026-09-16-001), so the sanctioned bounded seats carry the work, the timeout and error mapping are byte-preserved, and the crate's async-gate inventory entries are refreshed for the line shift | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | | `RS-0847` | `async` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | W3 | 7de088b5d | `effects_service.rs:361, effects_service.rs:384, effects_service.rs:698` | | | | `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/observe.rs:255-260` | | | | `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:30, src/testing.rs:19` | | | @@ -916,48 +916,48 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | | `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | applied | W7 | 6e8f34406 | `packages/d2bd/src/interaction_composition.rs:5546` | InteractionRuntimeSet holds per-Zone Arc handles; the daemon-global lock is taken only to clone the handle and released before the Zone lock, so no global guard spans the dispatch await. The residual note is deleted and a named concurrency test proves two Zones' sessions no longer serialize. Merged fffe5afee. | | | `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | applied | W7 | 6e8f34406 | `packages/d2bd/src/shared_provider_effects.rs:354` | runtime()/plane() are async seats awaiting the plane slot (13 call sites) and the two sync GPU authority seats use a fail-closed try_runtime() per the TPM precedent; NetworkRuntime::bundle is async across both impls and the caller, so both try_lock+spin loops are gone; the async-gate inventory was regenerated. Merged fffe5afee. | | -| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | applied-variant | W4 | 87c3172bc | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session` | applied-variant: drainer tasks spawn on the daemon's own tokio runtime handle instead of a new dedicated runtime (audit-sanctioned) | | -| `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 406f13d98 | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broke` | | | +| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | applied-variant | W4 | 87c3172bc | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session.rs:35` | applied-variant: drainer tasks spawn on the daemon's own tokio runtime handle instead of a new dedicated runtime (audit-sanctioned) | | +| `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 406f13d98 | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broker/src/sys.rs:630, packages/d2b-broker/src/sys.rs:653, packages/d2b-broker/src/sys.rs:676, packages/d2b-broker/src/sys.rs:685, packages/d2b-broker/src/sys.rs:697, packages/d2b-broker/src/sys.rs:2109, packages/d2b-broker/src/sys.rs:2591, packages/d2b-broker/src/sys.rs:2630, packages/d2b-broker/src/sys.rs:2670, packages/d2b-broker/src/sys.rs:2694` | | | | `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | skipped-stale | W3 | 406f13d98 | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | The row's premise does not hold at the pinned versions: `pre_exec` is an `unsafe` method on tokio 1.53.1's `Process` (Cargo.lock:4472) and on `std::process::Command`, so the unsafe block at packages/d2b-broker/src/ops/disk_init.rs:674 cannot be removed. [reconstructed: verified from the code and the lockfile; the wave-3 close artifact carries the original reasoning at lines 15 and 92.] | | | `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | applied | W3 | 3886cfd7b | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | -| `RS-0859` | `unsafe` | `d2b-host-activation-helper` | medium | actionable | leaf | applied | W3 | 3f4a63bc8 | `packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/sr` | | | +| `RS-0859` | `unsafe` | `d2b-host-activation-helper` | medium | actionable | leaf | applied | W3 | 3f4a63bc8 | `packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/src/main.rs:129, packages/d2b-host-activation-helper/src/main.rs:140, packages/d2b-host-activation-helper/src/main.rs:194, packages/d2b-host-activation-helper/src/main.rs:213, packages/d2b-host-activation-helper/src/main.rs:271` | | | | `RS-0860` | `macro` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | W3 | a34843f8e | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420` | | | | `RS-0861` | `macro` | `d2b-resource-api` | low | actionable | leaf | applied-variant | W3 | 81b2ef867 | `service.rs:2245-2267` | | | | `RS-0862` | `macro` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643` | | | -| `RS-0863` | `macro` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/s` | | | -| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W4 | 776ddb336 | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/t` | | | -| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.tom` | applied-variant: feature wired to the registration integration test via [[test]] required-features (house pattern d2b-provider-host/Cargo.toml:28) instead of a #[cfg(feature)] module - the crates have no test-support module and BUILD.bazel *_test_support targets consume the feature | | +| `RS-0863` | `macro` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/src/changelog.rs:1019` | | | +| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W4 | 776ddb336 | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs` | | | +| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17` | applied-variant: feature wired to the registration integration test via [[test]] required-features (house pattern d2b-provider-host/Cargo.toml:28) instead of a #[cfg(feature)] module - the crates have no test-support module and BUILD.bazel *_test_support targets consume the feature | | | `RS-0880` | `test` | `d2b` | medium | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:227-239` | | | | `RS-0881` | `test` | `d2b` | low | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:383-397` | | | | `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | applied | W3 | b80491dde | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | | `RS-0864` | `test` | `d2b-broker-composition` | low | actionable | leaf | applied | W3 | fbcf5d1f5 | `packages/d2b-broker-composition/src/seam.rs:523` | | | -| `RS-0865` | `test` | `d2b-broker-composition` | low | actionable | leaf | applied | W3 | fbcf5d1f5 | `packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.` | | | +| `RS-0865` | `test` | `d2b-broker-composition` | low | actionable | leaf | applied | W3 | fbcf5d1f5 | `packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.rs:733` | | | | `RS-0867` | `test` | `d2b-bus` | high | actionable | leaf | applied | U1 | 01e8edab3 | packages/d2b-bus/src/metrics.rs | test now drives BusMetrics::emit over every closed label domain; mutation-verified | | -| `RS-0868` | `test` | `d2b-bus` | medium | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_te` | | | +| `RS-0868` | `test` | `d2b-bus` | medium | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_tests.rs:1808-1810, packages/d2b-bus/src/session_seam_tests.rs:1882-1884, packages/d2b-bus/src/session_seam_tests.rs:1941-1960` | | | | `RS-0869` | `test` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/operations.rs:1057-1060` | | | | `RS-0870` | `test` | `d2b-contracts-control` | medium | actionable | leaf | applied | W3 | 1ff8e6a8c | `public_wire.rs:167, public_wire.rs:175` | | | -| `RS-0871` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-` | | | -| `RS-0872` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contract` | | | -| `RS-0873` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | W3 | 5966950aa | `src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_sessi` | | | +| `RS-0871` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-provider/src/v3/credential/service.rs:1393, packages/d2b-contracts-provider/src/v3/credential/service.rs:1296` | | | +| `RS-0872` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1346, packages/d2b-contracts-provider/src/v3/credential_controller.rs:499, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1084` | | | +| `RS-0873` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | W3 | 5966950aa | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:2445, packages/d2b-contracts-zone-session/src/v3/component_session.rs:1829` | | | | `RS-0874` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | W3 | 5966950aa | `emergency_policy.rs:236, emergency_policy.rs:112` | | | | `RS-0877` | `test` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/tests/bundle_resolver_tamper.rs:149` | | | | `RS-0875` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority.rs:1824, authority.rs:1968, authority.rs:1899` | | | | `RS-0876` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority_persistence.rs:246-320` | | | | `RS-0878` | `test` | `d2b-host` | medium | actionable | family | applied | W4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:245` | | | | `RS-0879` | `test` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/bin/d2b-activation-helper.rs:792` | | | -| `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activ` | | | +| `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activation-nixos/tests/reconcile.rs:447` | | | | `RS-0883` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/authority.rs:26-31, src/authority.rs:236-241` | | | | `RS-0884` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/mediator.rs:13-24` | | | | `RS-0885` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | W3 | d5ab66ec5 | `src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787` | | | -| `RS-0886` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clip` | | | -| `RS-0887` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provide` | | | -| `RS-0888` | `test` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-pro` | | | -| `RS-0889` | `test` | `d2b-provider-config-nixos` | medium | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixo` | | | -| `RS-0890` | `test` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixo` | | | -| `RS-0891` | `test` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-e` | | | +| `RS-0886` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clipboard-wayland/src/history.rs:345-356, packages/d2b-provider-clipboard-wayland/src/history.rs:257-273` | | | +| `RS-0887` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:144-201, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:360-371` | | | +| `RS-0888` | `test` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:378-387, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:394` | | | +| `RS-0889` | `test` | `d2b-provider-config-nixos` | medium | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixos/tests/config_lifecycle.rs:8-18` | | | +| `RS-0890` | `test` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixos/tests/service_contract.rs:41-79` | | | +| `RS-0891` | `test` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-entra/src/lib.rs:1362` | | | | `RS-0892` | `test` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76` | | | -| `RS-0893` | `test` | `d2b-provider-credential-secret-service` | low | actionable | leaf | already-fixed | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-` | | | -| `RS-0894` | `test` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/te` | | | +| `RS-0893` | `test` | `d2b-provider-credential-secret-service` | low | actionable | leaf | already-fixed | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-credential-secret-service/tests/placement.rs:8, packages/d2b-provider-credential-secret-service/src/lib.rs:1966` | | | +| `RS-0894` | `test` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/tests/authority_lifecycle.rs` | | | | `RS-0896` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | W3 | b373f7624 | `tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, ` | | | | `RS-0897` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | W3 | b373f7624 | `src/reconcile_state.rs:51-308, src/state_machine.rs:98-100` | | | | `RS-0895` | `test` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | W3 | b373f7624 | `tests/conformance.rs:63-66` | | | @@ -966,26 +966,26 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0899` | `test` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W3 | 52f5ef660 | `tests/provider_lifecycle.rs:536` | | | | `RS-0901` | `test` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | W3 | 563820766 | `tests/error_redaction.rs:17` | | | | `RS-0902` | `test` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | already-fixed | W3 | 513edf50c | `finalize_ordering_test.rs:286` | | | -| `RS-0903` | `test` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | W3 | e4cbd3054 | `packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest` | | | +| `RS-0903` | `test` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | W3 | e4cbd3054 | `packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | | | | `RS-0904` | `test` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:145, metric_policy.rs:150` | | | | `RS-0905` | `test` | `d2b-provider-provider` | medium | actionable | leaf | applied | W3 | 55b7d20a6 | `src/providers.rs:206, src/driver.rs:1147` | | | -| `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied-variant | W3 | 55b7d20a6 | `tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.r` | | | +| `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied-variant | W3 | 55b7d20a6 | `packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:17, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:81, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:142, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:193, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:255, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:320, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:367` | | | | `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | applied | W7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:2012` | the source scrape and its literal name list are gone: PIDFD_DISPATCH_FAILURE_KINDS is a shared const in d2b-contracts-broker, LiveHandlerError maps its variants through it, and the supervisor test asserts against the constant with every behavior assertion kept. Merged f2b98ccfb. | | | `RS-0908` | `test` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230` | | | | `RS-0909` | `test` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-transport-vsock/tests/observe.rs:14-15` | | | | `RS-0910` | `test` | `d2b-provider-user` | medium | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs` | | | | `RS-0911` | `test` | `d2b-provider-wayland-policy` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-wayland-policy/tests/registration.rs:93` | | | -| `RS-0912` | `test` | `d2b-provider-zone-link` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/sr` | | | -| `RS-0914` | `test` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src` | | | +| `RS-0912` | `test` | `d2b-provider-zone-link` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/src/zone_links.rs:3093, packages/d2b-provider-zone-link/src/zone_links.rs:3162` | | | +| `RS-0914` | `test` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src/manager_backend/tests.rs:1460, packages/d2b-resource-api/src/manager_backend/tests.rs:1461` | | | | `RS-0913` | `test` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `service.rs:3377` | | | -| `RS-0915` | `test` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/p` | | | -| `RS-0916` | `test` | `d2b-resource-runtime` | high | actionable | leaf | applied-variant | U1 | 8b191fe39 | packages/d2b-resource-runtime/src/revision.rs (display test) | claim corrected: the committed line was a tautological bare-epoch assertion (not an assertion that cannot pass); the audit's quoted literal is a tool-output redaction artifact, absent from the file and from git history; the row's own fix text applied by deleting the redundant assertion | | +| `RS-0915` | `test` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/process_attach.rs:541, packages/d2b-resource-client/src/zone_client.rs:567` | | | +| `RS-0916` | `test` | `d2b-resource-runtime` | high | actionable | leaf | applied-variant | U1 | 8b191fe39 | `packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revision.rs:71` | claim corrected: the committed line was a tautological bare-epoch assertion (not an assertion that cannot pass); the audit's quoted literal is a tool-output redaction artifact, absent from the file and from git history; the row's own fix text applied by deleting the redundant assertion | | | `RS-0917` | `test` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/revision.rs:182` | | | | `RS-0918` | `test` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/lib.rs:66` | | | | `RS-0919` | `test` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139` | | | | `RS-0920` | `test` | `d2b-sk-frontend` | medium | actionable | leaf | applied | W3 | a094121e5 | `packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186` | | | -| `RS-0921` | `test` | `d2b-telemetry` | low | actionable | leaf | applied | W3 | c6480efc | `packages/d2b-telemetry/src/meter_registry.rs:176-180` | | | -| `RS-0922` | `test` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helpe` | | | +| `RS-0921` | `test` | `d2b-telemetry` | low | actionable | leaf | applied | W3 | cc1a4dbd9 | `packages/d2b-telemetry/src/meter_registry.rs:176-180` | | | +| `RS-0922` | `test` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helper/src/runtime.rs:505-508` | | | | `RS-0923` | `test` | `d2b-zone-routing` | low | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/engine.rs:3333` | | | | `RS-0924` | `test` | `d2b-zone-routing` | low | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/router.rs:517` | | | | `RS-0925` | `test` | `d2bd-runtime` | high | actionable | leaf | applied | U1 | bea8fa96d | packages/d2bd-runtime/src/runtime_process.rs | sd_notify tests assert observable tracing outcomes; two mutations verified | | @@ -998,20 +998,20 @@ Each wave closes on the same gate set, run on the wave's integrated head in the | `RS-0936` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b-telemetry/Cargo.toml:14` | | | | `RS-0937` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-quota/Cargo.toml:24` | | | | `RS-0938` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b-bus/Cargo.toml:41` | | | -| `RS-0939` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `dependencies` | | | -| `RS-0940` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `dependencies` | | | -| `RS-0941` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `dependencies` | | | +| `RS-0939` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `packages/d2b-provider-activation-nixos/Cargo.toml:35` | | | +| `RS-0940` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `packages/d2b-provider-audio-pipewire/Cargo.toml:25` | | | +| `RS-0941` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21` | | | | `RS-0942` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | -| `RS-0943` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.baz` | | | +| `RS-0943` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39` | | | | `RS-0944` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55` | | | -| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | the nix 0.26.4/0.31.3 transitive legs are recorded as accepted clusters with pullers and a re-check trigger in deny.toml [bans]; the workspace pin stays at 0.29 | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) -| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:202, deny.toml:2` | the rustix 0.38/1.1 legs are recorded as an accepted cluster with a re-check trigger in deny.toml [bans] | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) -| `RS-0948` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport` | | | -| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied-variant | W5 | 78b5c5672 | `packages/Cargo.guest.lock:1, flake.nix:389` | a lock-drift check compares shared-crate versions across Cargo.lock and packages/Cargo.guest.lock and records the 39 lags; deviation: the one-snapshot aligned regen stays at the next dependency refresh, which is where the row's own fix text scopes it (regen needs the container lane) | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) -| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | 13 member decls across 10 crates inherit rustix and sha2 from workspace.dependencies instead of literal pins; the resolved versions and both lockfiles are unchanged | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) -| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2` | the 31 transitive-only duplicate clusters are inventoried in deny.toml [bans] with versions, pullers, and re-check triggers; multiple-versions stays warn because the workspace-direct clusters do not resolve | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) -| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:21` | deny.toml licence confidence-threshold is raised from 0.8 to 0.9 and any failing allow-listed licence moved to a per-crate [licenses.exceptions] entry with its reason | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) +| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | the nix 0.26.4/0.31.3 transitive legs are recorded as accepted clusters with pullers and a re-check trigger in deny.toml [bans]; the workspace pin stays at 0.29 | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | +| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:202, deny.toml:2` | the rustix 0.38/1.1 legs are recorded as an accepted cluster with a re-check trigger in deny.toml [bans] | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | +| `RS-0948` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36` | | | +| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied-variant | W5 | 78b5c5672 | `packages/Cargo.guest.lock:1, flake.nix:389` | a lock-drift check compares shared-crate versions across Cargo.lock and packages/Cargo.guest.lock and records the 39 lags; deviation: the one-snapshot aligned regen stays at the next dependency refresh, which is where the row's own fix text scopes it (regen needs the container lane) | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | +| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | 13 member decls across 10 crates inherit rustix and sha2 from workspace.dependencies instead of literal pins; the resolved versions and both lockfiles are unchanged | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | +| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2` | the 31 transitive-only duplicate clusters are inventoried in deny.toml [bans] with versions, pullers, and re-check triggers; multiple-versions stays warn because the workspace-direct clusters do not resolve | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | +| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:21` | deny.toml licence confidence-threshold is raised from 0.8 to 0.9 and any failing allow-listed licence moved to a per-crate [licenses.exceptions] entry with its reason | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | | `RS-0929` | `supply` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:24, Cargo.toml:25` | | | -| `RS-0930` | `supply` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.tom` | | | +| `RS-0930` | `supply` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | | `RS-0931` | `supply` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:21` | | | -| `RS-0932` | `supply` | `d2b-provider-quota` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `dependencies` | | | +| `RS-0932` | `supply` | `d2b-provider-quota` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-quota/Cargo.toml:24` | | | diff --git a/packages/d2b-broker/src/audit.rs b/packages/d2b-broker/src/audit.rs index 0de8913a0..110c7ada9 100644 --- a/packages/d2b-broker/src/audit.rs +++ b/packages/d2b-broker/src/audit.rs @@ -1688,7 +1688,7 @@ fn prune_expired_daily_files_locked(audit_dir: &Path, retention_days: u32) -> io let age_days = today_unix_days - file_unix_days; if age_days > cutoff_days { // Best-effort: remove failures don't propagate as - // hard errors (e.g. file vanished between readdir + // hard errors (e. g. file vanished between readdir // and remove, permission denied on a stray file). if path_safe::remove_nofollow(&entry.path()).is_ok() { pruned += 1; @@ -2478,7 +2478,7 @@ fn ymd_from_unix(unix: i64) -> (i32, u32, u32) { /// underlying Hinnant algorithm normalizes out-of-range days into the /// next month, producing a different (y, m, d) on decode. We treat any /// normalization as `None` so `prune_expired_daily_files` doesn't trust -/// a filename like `broker-2024-02-30.jsonl` as a real date. +/// a filename like `broker-2024-02-30. jsonl` as a real date. fn unix_days_from_ymd(y: i32, m: u32, d: u32) -> Option { if !(1..=12).contains(&m) || !(1..=31).contains(&d) { return None; @@ -2495,7 +2495,7 @@ fn unix_days_from_ymd(y: i32, m: u32, d: u32) -> Option { let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] let result = era as i64 * 146_097 + doe as i64 - 719_468; // Round-trip guard: rejects impossible calendar dates that the - // Hinnant algorithm would otherwise normalize (e.g. 2024-02-30 + // Hinnant algorithm would otherwise normalize (e. g. 2024-02-30 // becoming 2024-03-01). Pruning trusts the filename only after // this guard agrees. let (yy, mm, dd) = ymd_from_unix(result * 86_400); diff --git a/packages/d2b-broker/src/envelope/mod.rs b/packages/d2b-broker/src/envelope/mod.rs index 34247f5a6..c9a890cdd 100644 --- a/packages/d2b-broker/src/envelope/mod.rs +++ b/packages/d2b-broker/src/envelope/mod.rs @@ -906,11 +906,11 @@ pub struct DispatchOutcome { /// The canonical result payload. pub result: CanonicalJsonObject, /// The descriptors the answering peer minted this invocation, when the - /// operation's result carries any.where + /// operation's result carries any. Wherewhere /// /// Formal fd provenance tracking is the answering peer's job (KTD7):the /// carrier only refuses a descriptor that is one of the call's own attached - /// fds, never a fresh mint. The caller owns the returned descriptors;the + /// fds, never a fresh mint. The caller owns the returned descriptors; the /// forwarder closes them on any refusal. pub fds: Vec, } @@ -980,7 +980,7 @@ pub struct DirectInvocation<'a> { /// sees the same block the forward carrier would carry. pub context: Option<&'a ForwardContext>, /// The descriptors the caller attached to this invocation, when any. - /// The caller owns them;the invocation borrows them for its duration. + /// The caller owns them; the invocation borrows them for its duration. pub fds: &'a [OwnedFd], /// The kernel kind the row's fd facet declares, when it declares one. @@ -1145,7 +1145,7 @@ impl BrokerEnvelope { /// frame's SCM_RIGHTS attachments are the operation's descriptors, validated /// here against the row's declared fd facet before dispatch, so an /// oversized-but-transport-legal set is refused with the fd-leg code - /// rather than truncated by the transport.where + /// rather than truncated by the transport. Wherewhere /// /// # Errors /// @@ -1531,13 +1531,13 @@ impl BrokerEnvelope { } /// Whether one request's attached fd set is admitted by the row's fd - /// facet, before dispatch。 + /// facet, before dispatch. /// - /// A row that declares no fd carriage admits only the empty set;an + /// A row that declares no fd carriage admits only the empty set; an /// oversized-but-transport-legal set (count over the row's declared max, /// kind mismatch, or a row whose facet exceeds the frame ceiling) is /// refused with the fd-leg code rather than let the transport truncate an - /// anonymous oversized frame.where + /// anonymous oversized frame. Wherewhere fn request_fds_admitted(row: &BrokerOperationRow, fds: &[OwnedFd]) -> bool { if fds.len() > usize::from(row.max_fds) { return false; @@ -3101,12 +3101,12 @@ mod tests { let returned_write_end = Arc::clone(&returned_write_end); Box::pin(async move { // Request leg:the descriptor the caller attached crossed the socket - // and reads back what the caller wrote.to + // and reads back what the caller wrote. to let mut echoed = [0_u8; 4]; let n = read(invocation.fds[0].as_raw_fd(), &mut echoed).expect("read request fd"); assert_eq!(&echoed[..n], b"ping"); - // Response leg:answer with a fresh descriptor the peer minted.to + // Response leg:answer with a fresh descriptor the peer minted. to let (answer_read, answer_write) = pipe().expect("answer pipe"); *returned_write_end.lock().expect("slot") = Some(answer_write); Ok(DispatchOutcome { @@ -3141,7 +3141,7 @@ mod tests { // Read back what the peer wrote through the returned descriptor:the // minted write end stays on the peer's side,and the returned read end - // is a working duplicated handle, exactly as w12 asserts.to + // is a working duplicated handle, exactly as w12 asserts. to let write_end = write_slot .lock() .expect("slot") @@ -3283,7 +3283,7 @@ mod tests { .expect("canonical"), // Return the call's own descriptor - a descriptor the peer did // not mint this call. The carrier spoils the theft at the wire - // boundary rather than at the handler.se + // boundary rather than at the handler. se fds: vec![invocation.fds[0].try_clone().expect("dup request fd")], }) }) diff --git a/packages/d2b-broker/src/forwarding.rs b/packages/d2b-broker/src/forwarding.rs index cd4604948..6a8662f91 100644 --- a/packages/d2b-broker/src/forwarding.rs +++ b/packages/d2b-broker/src/forwarding.rs @@ -2,7 +2,7 @@ //! //! The broker holds the committed rows and links no provider crate, so the //! dispatch step of the operation envelope cannot run a family row's -//! `OperationDef.handler` locally. It forwards instead: one validated, +//! `OperationDef. handler` locally. It forwards instead: one validated, //! authorized invocation crosses to the process that declared the handler, //! which answers with the handler's canonical result or its refusal code. //! @@ -82,7 +82,7 @@ pub struct ForwardedOperation<'a> { pub fds: &'a [OwnedFd], /// The kernel kind the row's fd facet declares for those descriptors, - /// when it declares one;the envelope validated every attached descriptor + /// when it declares one; the envelope validated every attached descriptor /// against it before dispatch, so the forwarder can declare it back to /// the peer verbatim. pub fd_kind: Option, @@ -751,7 +751,7 @@ mod tests { fn a_response_whose_fd_count_mismatches_its_declared_indexes_is_refused_not_truncated() { // The peer declares two descriptors but attaches only one:the // carrier must refuse with the fd-leg code rather than succeed with a - // truncated answer.where + // truncated answer. Wherewhere let (read_end, _write_end) = pipe().expect("pipe"); let mut read_end = Some(read_end); let peer = Peer::spawn_raw(move |_request| { @@ -794,7 +794,7 @@ mod tests { fn a_response_whose_fd_declarations_exceed_the_frame_ceiling_is_refused() { // Nine declared descriptors cannot ride an eight-descriptor frame; // the refusal must name the fd leg, never surface as a transport-side - // control-truncation error.where + // control-truncation error. Wherewhere let (read_end, _write_end) = pipe().expect("pipe"); let mut read_end = Some(read_end); let peer = Peer::spawn_raw(move |_request| { diff --git a/packages/d2b-broker/src/lib.rs b/packages/d2b-broker/src/lib.rs index 6153d35ad..b92449f52 100644 --- a/packages/d2b-broker/src/lib.rs +++ b/packages/d2b-broker/src/lib.rs @@ -4,8 +4,8 @@ // otherwise correct and well-tested: // // - `deprecated`: cgroup vm_leaf_path migration is tracked but the deprecated -// path is still referenced in legacy code paths kept for v1.1.x compat. -// - `clippy::dead_code`: helper functions (e.g. apply_mount_actions, apply) +// path is still referenced in legacy code paths kept for v1.1. x compat. +// - `clippy::dead_code`: helper functions (e. g. apply_mount_actions, apply) // are public API of internal modules that downstream callers may use. // - `clippy::large_enum_variant`, `clippy::result_large_err`: TypedError // variants intentionally carry rich context; boxing tracked separately. diff --git a/packages/d2b-broker/src/live_handlers.rs b/packages/d2b-broker/src/live_handlers.rs index e631ea219..5b7decaee 100644 --- a/packages/d2b-broker/src/live_handlers.rs +++ b/packages/d2b-broker/src/live_handlers.rs @@ -934,10 +934,10 @@ fn ensure_runner_cgroup_leaf( }; let leaf_path = cgroup_leaf_path(parent_slice, &segments); // Always materialize the cgroup leaf dir tree even when - // placement.delegated == false. The delegated flag is about + // placement. delegated == false. The delegated flag is about // controller delegation (enabling subtree control), not whether // the directory exists. The broker spawn path always needs the - // Zone/Guest role leaf to write the child pid into cgroup.procs. + // Zone/Guest role leaf to write the child pid into cgroup. procs. let slice = crate::ops::cgroup::create_d2b_slice( backend, unified_hierarchy_root, @@ -1943,7 +1943,7 @@ async fn refresh_spawn_runner_acls( // Derive the expected runtime-dir owner uid from the // declarative path `/run/user/` (from the bundle's // XDG_RUNTIME_DIR value, which originates in - // d2b.site.waylandUser). Do not shell out. + // d2b. site. waylandUser). Do not shell out. let wayland_user_uid = runtime .file_name() .and_then(|s| s.to_str()) @@ -2366,7 +2366,7 @@ fn validate_served_view_root(root: &Path) -> Result<(), String> { /// The worker runs as the trusted intent's principal, never as the daemon: /// the broker's only authentication factor is peer identity /// (`peer_matches_instance` admits exactly the daemon uid/gid on -/// `/run/d2b/priv.sock`), so a worker launched with the daemon identity +/// `/run/d2b/priv. sock`), so a worker launched with the daemon identity /// would be able to call the whole daemon API after a guest -> worker /// compromise. The daemon-provisioned trees the worker legitimately needs /// are therefore opened to its own principal instead: @@ -2785,7 +2785,7 @@ fn grant_component_session_socket_acl_once(socket: &Path) -> Result Result<(), String> { if let Some((dev, ino)) = setfacl_component_session( socket, @@ -2835,7 +2835,7 @@ fn spawn_component_session_vsock_acl_retry(socket: PathBuf) { /// /// Revoke-then-grant: first revoke any stale per-VM daemon grant left on /// the (possibly replaced) socket inode from a prior generation, then -/// (re-)establish the full ancestor traversal chain and grant `rw` on +/// (re-) establish the full ancestor traversal chain and grant `rw` on /// the live socket. The traversal grant is applied synchronously so the /// daemon never loses search on the per-VM state dir (the api-socket /// depends on it too); if the socket is not yet present, a bounded retry @@ -2950,14 +2950,14 @@ pub async fn live_spawn_runner( // spawns (ADR 0021). // // Detection: seccomp_policy_ref == "w1-gpu-render-node" AND - // user_namespace.is_some() (both conditions must hold; the policy + // user_namespace. is_some() (both conditions must hold; the policy // ref is the canonical identifier for the render-node-only profile // and avoids introducing a new SpawnRunnerPlan field). // // The fd is opened here (parent side, before clone3(CLONE_NEWUSER)) // so the DAC permission check runs as the broker UID - the child's // user-NS UID mapping provides no host-side access. The OwnedFd is - // moved into RunnerIsolationSpec.pre_opened_device_fds; the broker + // moved into RunnerIsolationSpec. pre_opened_device_fds; the broker // sys layer dup2's it to RENDER_NODE_INHERITED_FD (10) in the child // closure before execve. The crosvm argv carries // --gpu-device-node /proc/self/fd/10 as the render node path. @@ -3101,9 +3101,9 @@ pub async fn live_spawn_runner( /// /// Two placements exist: /// -/// - a **VM-scoped** placement (`d2b.slice//...`, the legacy VM DAG) is +/// - a **VM-scoped** placement (`d2b. slice//...`, the legacy VM DAG) is /// provisioned and identity-bound here, exactly as before; -/// - a **resource-backed** placement (`d2b.slice/process-<64hex>/...`, +/// - a **resource-backed** placement (`d2b. slice/process-<64hex>/...`, /// `private_cgroup_placement`) carries no VM identity in the cgroup and the /// typed Device-worker intent ships no writable paths, so the identity comes /// from the verified bundle (`resource_backed`) and the launch is fenced @@ -3135,7 +3135,7 @@ async fn maybe_harden_swtpm_dir( // directory for the log and pid file the moment it starts, so a launch // racing the Volume's layout must fail retryably here instead of // burning the row's restart budget on a child that dies on its first - // write. The one-shot flush (`--unix

/ctrl.sock`) only connects + // write. The one-shot flush (`--unix /ctrl. sock`) only connects // to the worker's control socket inside that directory: it is admitted // and waits for the socket, so refusing it would spend the row's one // attempt on a race it can win. Presence is a filesystem fact, so it @@ -4265,7 +4265,7 @@ mod tests { ); assert!(backend.directory_exists(&leaf)); // DEFAULT_DELEGATED_PARENT_SLICE is the top-level - // `/sys/fs/cgroup/d2b.slice` (systemd top-level slice naming + // `/sys/fs/cgroup/d2b. slice` (systemd top-level slice naming // convention). The leaf path lives under that, so the slice MUST // exist for the leaf to exist. assert!(backend.directory_exists(Path::new("/sys/fs/cgroup/d2b.slice"))); @@ -4628,7 +4628,7 @@ mod tests { // behaviour (no setfacl on world-traversable ancestors) is // covered hermetically by `dir_traverse_classification_world_x_vs_private` // without invoking the host setfacl binary on real ancestors - - // which a TestDir rooted under a non-world-x CI path (e.g. + // which a TestDir rooted under a non-world-x CI path (e. g. // `/home/runner`, mode 0750) would otherwise trigger. revoke_component_session_vsock_acl(&socket).expect("revoke of absent socket is a no-op"); } diff --git a/packages/d2b-broker/src/ops/cgroup.rs b/packages/d2b-broker/src/ops/cgroup.rs index 4c753fba0..29dc1018c 100644 --- a/packages/d2b-broker/src/ops/cgroup.rs +++ b/packages/d2b-broker/src/ops/cgroup.rs @@ -7,7 +7,7 @@ //! never from caller input; the wire request only names the //! subject (`subtree`, `vm_id`) and the broker maps that name to //! the canonical delegated subtree (default -//! `/sys/fs/cgroup/d2b.slice`) plus per-VM interiors and +//! `/sys/fs/cgroup/d2b. slice`) plus per-VM interiors and //! per-role leaves beneath it; //! - the 8-step delegation algorithm runs through //! [`d2b_host::cgroup`]; @@ -47,9 +47,9 @@ pub enum CgroupOpError { /// that the broker is allowed to manage. CgroupNotDelegated { expected_parent: PathBuf }, /// `OpenCgroupDir` was asked about a path that does not resolve - /// under the delegated d2b.slice (`path-class = foreign`). + /// under the delegated d2b. slice (`path-class = foreign`). PathClassForeign { requested: PathBuf }, - /// `cgroup.kill` was attempted on a non-leaf path. + /// `cgroup. kill` was attempted on a non-leaf path. KillAncestor { requested: PathBuf }, } @@ -130,15 +130,15 @@ impl CgroupBundleContext { /// v1.1.1 per-VM-interior + per-role-leaf taxonomy per ADR 0011 /// Decision item 1: `vm_interior_path` returns the - /// process-free intermediate directory `d2b.slice//`. - /// Per-role leaf cgroups (`d2b.slice///`) are + /// process-free intermediate directory `d2b. slice//`. + /// Per-role leaf cgroups (`d2b. slice///`) are /// the only entries that carry processes. pub fn vm_interior_path(&self, vm_id: &str) -> PathBuf { self.slice_path().join(vm_id) } /// v1.1.1 per-role leaf cgroup path - /// `d2b.slice///`. Processes for the + /// `d2b. slice///`. Processes for the /// `(vm_id, role_id)` SpawnRunner instance are placed here via /// `clone3(CLONE_INTO_CGROUP)` at spawn time. pub fn vm_role_leaf_path(&self, vm_id: &str, role_id: &str) -> PathBuf { @@ -230,7 +230,7 @@ impl PathClass { /// systemd-managed parent slice that has already been delegated to the /// broker/daemon. The broker never writes `/sys/fs/cgroup` root; the /// operator must pre-create + `Delegate=yes` the parent slice (default -/// `/sys/fs/cgroup/d2b.slice`) and then the broker +/// `/sys/fs/cgroup/d2b. slice`) and then the broker /// enables controllers / chowns only within that subtree. Per the /// broker variant table, `destructive: no`, `secret: no`, audit /// decision `allowed` on success. @@ -316,8 +316,8 @@ where }; // Subject classification: the wire request carries a logical - // subject name (e.g. "d2b-slice" or a vm id). The broker - // maps that to a canonical path under d2b.slice. + // subject name (e. g. "d2b-slice" or a vm id). The broker + // maps that to a canonical path under d2b. slice. let (canonical_path, class) = if requested_subject == D2B_SLICE_NAME || requested_subject == "d2b-slice" { (context.slice_path().to_path_buf(), PathClass::D2bSlice) @@ -431,7 +431,7 @@ pub(crate) fn create_d2b_slice( host_cgroup::probe_unified_hierarchy(backend, unified_hierarchy_root)?; // Systemd must pre-create + delegate this slice. The broker only // enables controllers and changes ownership within that subtree; - // it never writes `/sys/fs/cgroup/cgroup.subtree_control`. + // it never writes `/sys/fs/cgroup/cgroup. subtree_control`. if !backend.exists(parent_slice) { return Err(CgroupOpError::CgroupNotDelegated { expected_parent: parent_slice.to_path_buf(), @@ -684,8 +684,8 @@ fn runner_cgroup_shape(subtree: &str, vm_id: &str) -> Option { /// /// The request carries `(vm_id, role_id)`. The broker resolves the cgroup /// placement from its bundle copy and refuses anything other than a -/// canonical `d2b.slice///` or legacy -/// `d2b.slice//` leaf shape. A same-named Zone-qualified Guest +/// canonical `d2b. slice///` or legacy +/// `d2b. slice//` leaf shape. A same-named Zone-qualified Guest /// collision is refused as ambiguous rather than selecting a cgroup. pub fn live_kill_runner_cgroup( resolver: &BundleResolver, diff --git a/packages/d2b-broker/src/ops/device_worker.rs b/packages/d2b-broker/src/ops/device_worker.rs index 56e8eeab5..a5ab4b15e 100644 --- a/packages/d2b-broker/src/ops/device_worker.rs +++ b/packages/d2b-broker/src/ops/device_worker.rs @@ -37,7 +37,7 @@ pub struct DeviceWorkerScope { /// uid the request carried, now the Zone the bundle row was read from. pub(crate) zone_uid: ResourceUid, /// The `Device` row that owns the launched Process row, per the verified - /// Zone resource bundle (`Process.metadata.ownerRef`, cross-checked with + /// Zone resource bundle (`Process. metadata. ownerRef`, cross-checked with /// the request's claim). pub(crate) device_ref: ResourceRef, /// That Device's durable row uid: the deterministic derivation of its @@ -45,7 +45,7 @@ pub struct DeviceWorkerScope { /// the request must carry. pub(crate) device_uid: ResourceUid, /// The Guest the Device declares as its owner - /// (`Device.metadata.ownerRef == Guest/`): the VM scope every + /// (`Device. metadata. ownerRef == Guest/`): the VM scope every /// runtime path of the worker hangs off. pub(crate) guest: String, } @@ -140,7 +140,7 @@ impl DeviceWorkerScopeError { /// Pin the Device scope of one Device-owned worker launch. /// /// The launched row is resolved from the verified Zone resource bundle the -/// request's `zone_uid` names (`Process.metadata.ownerRef`), that owner must +/// request's `zone_uid` names (`Process. metadata. ownerRef`), that owner must /// be a `Device`, `owner_ref` must be exactly it, and `owner_uid` must be that /// Device row's durable uid. Only then is the Device's declared Guest read. /// @@ -241,8 +241,8 @@ pub(crate) fn unique_tpm_state_dir( /// Whether one Device-owned worker role binds its socket under the broker /// runtime root's per-Guest directory. /// -/// The long-lived swtpm worker (`--server ...path=/vms//tpm.sock`) -/// and both GPU sidecars (`--socket /vms//gpu.sock`) do. The +/// The long-lived swtpm worker (`--server ...path=/vms//tpm. sock`) +/// and both GPU sidecars (`--socket /vms//gpu. sock`) do. The /// one-shot flush binds its ctrl socket inside the Device's state Volume, and /// the video sidecar's socket lives in the video module's own `/run/d2b-video` /// runtime directory: neither is a directory the broker owns or opens. @@ -345,7 +345,7 @@ fn find_resource_row<'a>( .find(pred) } -/// The authored `metadata.ownerRef` of one row of a verified Zone resource +/// The authored `metadata. ownerRef` of one row of a verified Zone resource /// bundle, parsed into a canonical reference. pub(crate) fn row_owner_ref( bundle_bytes: &[u8], @@ -368,7 +368,7 @@ let bundle: serde_json::Value = serde_json::from_slice(bundle_bytes).ok()?; .and_then(|owner| ResourceRef::parse(owner).ok()) } -/// `Device.metadata.ownerRef == Guest/` for one Device row of a +/// `Device. metadata. ownerRef == Guest/` for one Device row of a /// verified Zone resource bundle. /// /// The same derivation the daemon's Device-worker ticket uses to name the diff --git a/packages/d2b-broker/src/ops/exec_reconcile.rs b/packages/d2b-broker/src/ops/exec_reconcile.rs index d91526fc9..d117152b5 100644 --- a/packages/d2b-broker/src/ops/exec_reconcile.rs +++ b/packages/d2b-broker/src/ops/exec_reconcile.rs @@ -253,7 +253,7 @@ pub trait ReconcileExecutor: Send + Sync { } /// Generate a replacement ed25519 keypair and atomically publish it - /// at `key_path` + `key_path.pub`. + /// at `key_path` + `key_path. pub`. fn run_ssh_keygen<'a>( &'a self, key_path: &'a Path, @@ -1683,7 +1683,7 @@ mod tests { static HELPER_COUNTER: AtomicU64 = AtomicU64::new(0); /// Sysctl key validation: the broker callers pass dotted keys - /// (`net.ipv4.ip_forward`); the executor translates dots to + /// (`net. ipv4. ip_forward`); the executor translates dots to /// slashes for the /proc/sys path. Rejects absolute paths, /// traversal, and unsafe characters. #[tokio::test] diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index 56e8e99ef..24640d3f0 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -216,7 +216,7 @@ pub struct HotplugOutcome { } /// The result of a VM boot media attach:the broker wire response plus -/// which registry/udev artifacts were (re)written and whether udev was +/// which registry/udev artifacts were (re) written and whether udev was /// reloaded. pub struct BootOutcome { /// The wire response echoed to the daemon. @@ -325,7 +325,7 @@ pub async fn refresh_registry(resolver: &BundleResolver) -> Result= 1.20) with `systemctl reload //! NetworkManager.service` fallback. Verify via `nmcli -t -f @@ -89,7 +89,7 @@ impl From for ApplyNmError { } } -/// Renders the d2b-owned NM `conf.d` snippet body. +/// Renders the d2b-owned NM `conf. d` snippet body. pub fn render_nm_conf(entries: &[NmUnmanagedEntry]) -> String { let mut out = String::new(); out.push_str("# d2b-managed begin\n"); diff --git a/packages/d2b-broker/src/ops/pidfd.rs b/packages/d2b-broker/src/ops/pidfd.rs index b7413d6a5..4858685ac 100644 --- a/packages/d2b-broker/src/ops/pidfd.rs +++ b/packages/d2b-broker/src/ops/pidfd.rs @@ -6,7 +6,7 @@ //! (preferred), with a `fork + pidfd_open` fallback; //! - the pidfd is `CLOEXEC`; //! - it is transported to `d2bd` via `SCM_RIGHTS` over the -//! private `priv.sock`; +//! private `priv. sock`; //! - the broker itself does NOT set `PR_SET_CHILD_SUBREAPER` (it is //! short-lived per operation); //! - reconciliation paths use `pidfd_open` keyed on pid + start-time diff --git a/packages/d2b-broker/src/ops/spawn_runner.rs b/packages/d2b-broker/src/ops/spawn_runner.rs index 61e909e3c..1ed8b1701 100644 --- a/packages/d2b-broker/src/ops/spawn_runner.rs +++ b/packages/d2b-broker/src/ops/spawn_runner.rs @@ -150,7 +150,7 @@ pub struct SpawnRunnerPlanInput { pub mount_policy: MountPolicy, pub cgroup_placement: CgroupPlacement, /// Set by the broker dispatch when the bundle row's - /// `adr_carve_out` field is non-null (e.g. for the swtpm + /// `adr_carve_out` field is non-null (e. g. for the swtpm /// pre-start flush which legitimately runs as root). pub root_carve_out: bool, /// Set to `true` only by unit tests so the preflight skips diff --git a/packages/d2b-broker/src/ops/state_dir.rs b/packages/d2b-broker/src/ops/state_dir.rs index 7b42c45ae..3b21bf50e 100644 --- a/packages/d2b-broker/src/ops/state_dir.rs +++ b/packages/d2b-broker/src/ops/state_dir.rs @@ -58,11 +58,11 @@ pub enum DirKind { pub struct PrepareDirRequest { /// Whether the op prepares the state or runtime tree. pub kind: DirKind, - /// The tree root under whichthe subdirectories are created. + /// The tree root under which the subdirectories are created. pub base_dir: PathBuf, /// Per-VM or global scope (`global` if `vm_id` is `None`). pub vm_id_or_scope: String, - /// 0o-mode (e.g. 0o750 for state, 0o755 for runtime). + /// 0o-mode (e. g. 0o750 for state, 0o755 for runtime). pub mode: u32, /// The owner uid to apply to created directories. pub owner_uid: u32, @@ -254,7 +254,7 @@ pub struct PreparedStateDir { /// Returns [`super::OpError::InvalidInput`] for a non-VM path class, /// [`super::OpError::UnknownSubject`] / [`super::OpError::Refused`] /// for unresolvable subjects, and the swtpm-hardening refusal as -/// [`PrepareStateDirError::SwtpmDirHardening`].where applicable。 +/// [`PrepareStateDirError::SwtpmDirHardening`]. Where applicable. pub fn live_prepare_state_dir( _exec:&SystemLiveExec, resolver:&BundleResolver, diff --git a/packages/d2b-broker/src/ops/store_sync_export.rs b/packages/d2b-broker/src/ops/store_sync_export.rs index a2ea5275f..443066e35 100644 --- a/packages/d2b-broker/src/ops/store_sync_export.rs +++ b/packages/d2b-broker/src/ops/store_sync_export.rs @@ -185,7 +185,7 @@ impl StoreSyncObservabilityRecord { /// one's ownership/permissions/ACLs. /// /// In production the directory is created by the observability host -/// module's `systemd.tmpfiles` rule (mode `0750` + a focused `alloy` +/// module's `systemd. tmpfiles` rule (mode `0750` + a focused `alloy` /// read/traverse ACL and a default ACL so broker-created `0640` files /// inherit `user:alloy:r`). The broker must NOT chmod/chown/setfacl an /// existing directory - doing so would clobber that grant. We only @@ -235,7 +235,7 @@ fn ensure_export_dir(export_dir: &Path) -> io::Result<()> { /// directory's default ACL grants `alloy` read on new files; the broker /// does not chown to or know about the `alloy` gid. Daily rotation is by /// filename, so a long-lived broker that crosses midnight simply opens -/// the next day's file. The host Alloy `local.file_match` globs the +/// the next day's file. The host Alloy `local. file_match` globs the /// directory and follows new files + truncation. /// /// Call-site contract: this is best-effort observability. The diff --git a/packages/d2b-broker/src/ops/store_view_posture.rs b/packages/d2b-broker/src/ops/store_view_posture.rs index 6986502f7..322c0991f 100644 --- a/packages/d2b-broker/src/ops/store_view_posture.rs +++ b/packages/d2b-broker/src/ops/store_view_posture.rs @@ -374,7 +374,7 @@ async fn posture_store_view_matrix_paths_with( } /// Posture every ancestor strictly above the per-VM state dir (the farm -/// root's parent, i.e. the daemon's ownership-matrix root) up to the first +/// root's parent, i. e. the daemon's ownership-matrix root) up to the first /// world-traversable directory, so the daemon's group can search it. /// /// The daemon reaches `/zones//guests//store-view` @@ -563,7 +563,7 @@ mod tests { /// `/zones/work/guests/acceptance-guest/store-view` and return the /// farm root plus the broker-created levels above the per-VM state dir, /// innermost first. The state dir itself - the daemon's ownership-matrix - /// root - is `farm.parent()`. + /// root - is `farm. parent()`. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn farm_chain(root: &Path) -> (PathBuf, Vec) { let farm = root diff --git a/packages/d2b-broker/src/ops/swtpm_dir.rs b/packages/d2b-broker/src/ops/swtpm_dir.rs index 8f74bb7b8..28bfd3874 100644 --- a/packages/d2b-broker/src/ops/swtpm_dir.rs +++ b/packages/d2b-broker/src/ops/swtpm_dir.rs @@ -21,11 +21,11 @@ //! identity (`st_dev`/`st_ino` + first-provision stamp). On every //! subsequent spawn the marker is verified against the live dir's //! identity; a missing dir after prior provision, or an `st_ino` -//! mismatch (e.g. a fresh correct-owner empty replacement smuggled in +//! mismatch (e. g. a fresh correct-owner empty replacement smuggled in //! under the sticky per-VM root), fails closed. //! //! The runtime socket dir (`/run/d2b/vms/`) posture is left -//! untouched; only a stale `tpm.sock` under it is unlinked. +//! untouched; only a stale `tpm. sock` under it is unlinked. //! //! Every error is PATH-FREE: the [`SwtpmHardenError`] `Display` carries //! only closed-set reason slugs, never a raw path, so the broker can @@ -120,7 +120,7 @@ pub struct SwtpmDirPaths { /// Per-VM root: `/vms/` (the sticky 3770 parent). pub per_vm_root: PathBuf, /// Runtime socket dir: `/run/d2b/vms/`. Posture untouched; - /// only a stale `tpm.sock` under it is unlinked. + /// only a stale `tpm. sock` under it is unlinked. pub runtime_dir: PathBuf, /// Marker tree root (`/var/lib/d2b/swtpm-markers`). pub marker_dir: PathBuf, @@ -227,17 +227,17 @@ fn production_swtpm_path(p: &Path) -> bool { /// The placement identity a spawn plan's cgroup subtree names. /// -/// A legacy VM-scoped placement (`d2b.slice/[/...]`) carries the VM +/// A legacy VM-scoped placement (`d2b. slice/[/...]`) carries the VM /// name in its first segment. A resource-backed (typed) launch is rewritten by -/// `private_cgroup_placement` into `d2b.slice/process-<64hex>[/...]`, a +/// `private_cgroup_placement` into `d2b. slice/process-<64hex>[/...]`, a /// commitment to the private runtime scope that deliberately carries no VM /// identity: for those launches the VM is resolved from the verified bundle, /// never from the cgroup. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum PlacementSegment { - /// `d2b.slice/[/...]` - the segment after `d2b.slice/` is the VM id. + /// `d2b. slice/[/...]` - the segment after `d2b. slice/` is the VM id. Vm(String), - /// `d2b.slice/process-<64hex>[/...]` - a private resource-backed scope. + /// `d2b. slice/process-<64hex>[/...]` - a private resource-backed scope. RuntimeScope(String), } @@ -270,7 +270,7 @@ pub(crate) fn parse_placement_segment(subtree: &str) -> Option #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResourceBackedSwtpm { /// The Guest whose owning Device declares the worker row - /// (`Device.metadata.ownerRef == Guest/`, the same derivation the + /// (`Device. metadata. ownerRef == Guest/`, the same derivation the /// daemon's Device-worker ticket uses). pub guest: String, /// The trusted TPM state policy root the `path:swtpm-state:` row @@ -375,8 +375,8 @@ pub(crate) fn state_volume_name(device_uid: &ResourceUid) -> String { /// `/run/d2b/vms` runtime dir must be exactly the trusted one; /// - the composed argv must name the trusted state volume directory /// (`--tpmstate dir=/` with `--ctrl -/// ...path=/ctrl.sock`) and the trusted per-Guest runtime socket -/// (`--server`/`--unix` `...path=/run/d2b/vms//tpm.sock`). +/// ...path=/ctrl. sock`) and the trusted per-Guest runtime socket +/// (`--server`/`--unix` `...path=/run/d2b/vms//tpm. sock`). /// /// A launch that disagrees fails closed with [`reasons::IDENTITY_MISMATCH`]. pub fn derive_resource_backed_paths( @@ -1021,7 +1021,7 @@ async fn apply_ancestor_traverse_acl( .map_err(|_| reasons::ANCESTOR_ACL_FAILED) } -/// Unlink only the trusted `tpm.sock` under the runtime dir, if present. +/// Unlink only the trusted `tpm. sock` under the runtime dir, if present. /// The runtime dir's own posture (mode / ACL / sibling entries) is left /// untouched. A missing runtime dir is a no-op (not an error). fn unlink_stale_socket(runtime_dir: &Path) -> Result<(), &'static str> { @@ -1507,7 +1507,7 @@ mod tests { s.make_per_vm_root(&paths); let cfg = s.cfg(); // Pre-create runtime dir with a distinctive mode + a sibling - // file + a stale tpm.sock. + // file + a stale tpm. sock. tokio::fs::create_dir_all(&paths.runtime_dir).await.unwrap(); tokio::fs::set_permissions(&paths.runtime_dir, fs::Permissions::from_mode(0o751)).await.unwrap(); let sibling = paths.runtime_dir.join("vsock.sock"); @@ -1721,7 +1721,7 @@ mod tests { }, cgroup_placement: CgroupPlacement { // What `private_cgroup_placement` writes for a typed launch: - // `d2b.slice/process-<64hex>/`. + // `d2b. slice/process-<64hex>/`. subtree: format!( "d2b.slice/{}/swtpm", "process-".to_owned() + &"a".repeat(64) diff --git a/packages/d2b-broker/src/ops/sysctl.rs b/packages/d2b-broker/src/ops/sysctl.rs index f73c8d436..e8dbb07ba 100644 --- a/packages/d2b-broker/src/ops/sysctl.rs +++ b/packages/d2b-broker/src/ops/sysctl.rs @@ -64,7 +64,7 @@ impl From for ApplySysctlError { } } -/// Converts `net.ipv6.conf..disable_ipv6` to +/// Converts `net. ipv6.conf..disable_ipv6` to /// `/net/ipv6/conf//disable_ipv6` for safe per-link /// writes. pub(crate) fn intent_to_proc_path(root: &Path, intent: &SysctlIntent) -> PathBuf { diff --git a/packages/d2b-broker/src/ops/usbip_host.rs b/packages/d2b-broker/src/ops/usbip_host.rs index 190133481..be89fdcb7 100644 --- a/packages/d2b-broker/src/ops/usbip_host.rs +++ b/packages/d2b-broker/src/ops/usbip_host.rs @@ -175,7 +175,7 @@ pub struct UsbipHostDeviceInspection { pub bus_number: u16, /// The physical port chain under the bus, root-first. pub port_chain: Vec, - /// The device node (e.g. `/dev/bus/usb/...`) the device exposes. + /// The device node (e. g. `/dev/bus/usb/...`) the device exposes. pub device_node: PathBuf, /// Which kernel driver currently binds the device's interface. pub driver: UsbipDriverBinding, diff --git a/packages/d2b-broker/src/ops/usbip_lock.rs b/packages/d2b-broker/src/ops/usbip_lock.rs index e7ecab4b3..f5935e362 100644 --- a/packages/d2b-broker/src/ops/usbip_lock.rs +++ b/packages/d2b-broker/src/ops/usbip_lock.rs @@ -43,7 +43,7 @@ pub enum UsbipLockError { expected: String, observed: String, }, - /// Underlying I/O error (e.g. parent dir missing). + /// Underlying I/O error (e. g. parent dir missing). Io { path: PathBuf, source: std::io::Error, @@ -175,7 +175,7 @@ pub fn acquire_lock( Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => { let existing = read_owner(&full_lock_path).unwrap_or_else(|_| "".to_owned()); - // Idempotent: if the same VM already owns the lock (e.g. + // Idempotent: if the same VM already owns the lock (e. g. // after a VM restart without an explicit detach), treat the // acquire as a success rather than refusing. if existing.trim() == owner_vm { @@ -478,7 +478,7 @@ mod tests { let lock = tmp.path().join("6-1"); let gid = nix::unistd::Gid::current().as_raw(); acquire_lock(&lock, "work-aad", gid).unwrap(); - // Re-acquire by the same VM succeeds (e.g. after VM restart). + // Re-acquire by the same VM succeeds (e. g. after VM restart). acquire_lock(&lock, "work-aad", gid).unwrap(); assert_eq!(peek_owner(&lock).unwrap(), "work-aad"); } diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index a01a39bdb..3e6e9bf6c 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -105,7 +105,7 @@ const DEFAULT_GUEST_AUDIT_DIR: &str = "/var/lib/d2b/guest-audit"; /// Default audit retention. Matches the docs claim in /// `docs/reference/daemon-api.md` "Audit" and `AGENTS.md` "Control /// plane". Override via `--audit-retention-days` (broker flag) or the -/// NixOS module's `d2b.site.audit.retentionDays` option. Set to 0 +/// NixOS module's `d2b. site. audit. retentionDays` option. Set to 0 /// to disable pruning. const DEFAULT_AUDIT_RETENTION_DAYS: u32 = 30; const DEFAULT_BUNDLE_PATH: &str = "/var/lib/d2b/current-bundle/manifest.json"; @@ -142,7 +142,7 @@ const MAX_MODULE_NAME_LEN: usize = 64; /// the caller has not moved past. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct RetiredWireVariant { - /// The wire variant name, exactly as the frame's `request.kind` spells + /// The wire variant name, exactly as the frame's `request. kind` spells /// it. pub variant: &'static str, /// The negotiated wire version the variant was retired in: a straggler @@ -268,7 +268,7 @@ pub const RETIRED_WIRE_VARIANTS: &[RetiredWireVariant] = &[ ]; #[cfg(not(feature = "layer1-bootstrap"))] -/// The variant one frame's `request.kind` names, when the envelope's request +/// The variant one frame's `request. kind` names, when the envelope's request /// is shaped the way the closed wire spells it. /// /// The frame is inspected before the typed decode precisely so a variant the @@ -290,7 +290,7 @@ fn request_kind(envelope: &Value) -> Option<&str> { #[cfg(not(feature = "layer1-bootstrap"))] /// The gate's lookup, public so a mixed-version fixture can exercise it the /// way the production accept loop does; the variant name is the frame's -/// `request.kind` ([`request_kind`]). +/// `request. kind` ([`request_kind`]). pub fn retired_wire_variant<'a>( kind: &str, retired: &'a [RetiredWireVariant], @@ -343,7 +343,7 @@ pub struct ServerConfig { /// path. The daemon never names a bundle path on the wire (security: /// prevents path-traversal + symlink-confusion). Defaults to /// `/var/lib/d2b/current-bundle/manifest.json`; the NixOS module's - /// `d2b.site.bundle.currentManifest` option overrides. + /// `d2b. site. bundle. currentManifest` option overrides. pub bundle_path: PathBuf, pub state_dir: PathBuf, /// Trusted target-local activation helper. The daemon never supplies @@ -448,11 +448,11 @@ pub(crate) enum BrokerError { AuditRequiresAdmin, HostShutdownRestricted, /// Broker started without a loadable bundle at - /// `ServerConfig.bundle_path`; bundle-dependent real-wire ops cannot + /// `ServerConfig. bundle_path`; bundle-dependent real-wire ops cannot /// resolve their `BundleOpId` refs and refuse fail-closed. #[cfg_attr(feature = "layer1-bootstrap", allow(dead_code))] BundleResolverUnavailable, - /// Bundle artifact at `ServerConfig.bundle_path` failed the + /// Bundle artifact at `ServerConfig. bundle_path` failed the /// tamper-resistance check (symlink / owner / mode / hash). Every /// incoming operation surfaces this error until the broker is /// restarted with a clean bundle. @@ -515,7 +515,7 @@ pub(crate) enum BrokerError { }, /// `SpawnRunner` was called with `RunnerRole::OtelHostBridge`, but /// the bundle-resolved intent points at a VM whose name does not - /// match `manifest._observability.vmName`. The bridge MUST forward + /// match `manifest._observability. vmName`. The bridge MUST forward /// only into the obs VM declared in the trusted bundle; any other /// target is a closed-set violation and the broker refuses /// fail-closed. @@ -631,7 +631,7 @@ where // --socket-path is optional. Resolution order: // 1. --socket-path flag (explicit override) // 2. D2B_BROKER_SOCKET_PATH env var - // 3. DEFAULT_SOCKET_PATH constant ("/run/d2b/priv.sock") + // 3. DEFAULT_SOCKET_PATH constant ("/run/d2b/priv. sock") // Under SD_LISTEN_FDS=1 (socket activation) the resolved path is // informational only; the broker adopts fd 3 from systemd and // MUST NOT bind, fchmod, or fchown the socket path. @@ -869,7 +869,7 @@ pub fn run(command: BrokerMode) -> Result<(), RunError> { /// or if `LISTEN_FDS` is absent or not `"1"` - not socket-activated. /// - `Some(Ok(fd))` when socket activation is valid and fd 3 has been /// verified as an `AF_UNIX SOCK_SEQPACKET` listen socket. -/// - `Some(Err(_))` if `LISTEN_FDNAMES` is present but is not `"priv.sock"`, +/// - `Some(Err(_))` if `LISTEN_FDNAMES` is present but is not `"priv. sock"`, /// or if the fd-level validation in `sys::adopt_listen_fd_from_fd3` fails. /// /// The `LISTEN_*` vars are NOT unset after adoption. The `sd_listen_fds(3)` @@ -892,7 +892,7 @@ fn adopt_listen_fd() -> Option> { return None; } - // Step 3: If LISTEN_FDNAMES is present it must equal "priv.sock". + // Step 3: If LISTEN_FDNAMES is present it must equal "priv. sock". if let Ok(fdnames) = env::var("LISTEN_FDNAMES") && fdnames != "priv.sock" { @@ -1366,7 +1366,7 @@ pub fn probe_bundle_load_response(bundle_path: &std::path::Path) -> BrokerRespon } /// Like [`probe_bundle_load_response`] but uses an explicit [`BundleVerifyPolicy`]. -/// Tests that need to control uid/gid/mode requirements (e.g. to avoid requiring +/// Tests that need to control uid/gid/mode requirements (e. g. to avoid requiring /// root in CI) pass `current_user_policy()` so the uid check passes and only the /// intended tamper reason fires. #[cfg(not(feature = "layer1-bootstrap"))] @@ -2895,7 +2895,7 @@ fn intent_is_serving_worker_template( /// ([`Self::carries_controller_escrow`]) and the advertised response fd /// indices ([`Self::bootstrap_response_index`] / /// [`Self::console_response_index`]) - instead of re-deriving it from -/// `(req.role, intent)`. +/// `(req. role, intent)`. /// /// The posture deliberately decides NO identity: a launch's executor uid/gid /// and in-namespace root mapping are always the trusted intent's principal @@ -3041,7 +3041,7 @@ impl LaunchPosture { /// This is the single evaluation point for runner identity, and it /// deliberately takes no identity from the posture: the broker's only /// authentication factor is peer identity - `peer_matches_instance` admits -/// exactly `config.d2bd_uid` / `config.d2bd_gid` on the privileged socket, +/// exactly `config. d2bd_uid` / `config. d2bd_gid` on the privileged socket, /// whose mode is `0660 d2bd:d2bd` - so a runner launched with the daemon's /// uid/gid could connect that socket, pass the pre-decode peer check, and use /// the whole daemon API (the pre-PR security review's finding: the @@ -4706,7 +4706,7 @@ async fn dispatch_request_with_backend_and_request_fds( d2b_contracts::usbip::lock_path_for_busid(&req.bus_id), ); - // Same-VM replay: lock is already held by this VM (e.g. daemon restart). + // Same-VM replay: lock is already held by this VM (e. g. daemon restart). let same_vm_replay = match crate::ops::usbip_lock::peek_owner(&lock_path) { Some(owner) if owner == req.vm => true, Some(owner) => { @@ -7393,8 +7393,8 @@ fn usbip_binary_path() -> PathBuf { } /// Best-effort lookup of the human-readable VM name carried in the -/// bundle's `processes.vms[*].vm` list. The wire `VmId` is a transparent -/// opaque string; the bundle index is the `processes.vms[*].vm` field. +/// bundle's `processes. vms[*].vm` list. The wire `VmId` is a transparent +/// opaque string; the bundle index is the `processes. vms[*].vm` field. /// We use the wire value as both the opaque key and the human-readable /// name today - the daemon emits them identically. #[cfg(not(feature = "layer1-bootstrap"))] @@ -8164,7 +8164,7 @@ async fn handle_usbip_acl_revoke_failure_after_unbind( return revoke_error; } - // `backend.usbip_unbind` succeeded before the ACL revoke was attempted. + // `backend. usbip_unbind` succeeded before the ACL revoke was attempted. // Release the host-session claim on revoke failure unless a best-effort // live recheck proves the device is still attached to usbip-host. If the // recheck itself fails, trust the successful unbind result and release to @@ -9292,7 +9292,7 @@ fn validate_typed_process_metadata( serving_worker: bool, intent: &d2b_core::bundle_resolver::ResolvedRunnerIntent, // Owning-Device scope already pinned from the verified bundle (the - // launched row's `metadata.ownerRef`, `device_worker::resolve_launch_scope`). + // launched row's `metadata. ownerRef`, `device_worker::resolve_launch_scope`). // `Some` on the launch path, where that Device anchors every runtime path // the launch derives; `None` for the observe/adopt requests, which carry // no owner uid to pin and derive no Device paths. @@ -9396,7 +9396,7 @@ fn validate_typed_process_metadata( // the intent was resolved through. WHICH Device owns the launched // row is pinned from the verified bundle by the launch arm // (`device_worker::resolve_launch_scope`: the row's - // `metadata.ownerRef`, plus the Device row's durable uid), and the + // `metadata. ownerRef`, plus the Device row's durable uid), and the // request must name exactly that Device - a launch aimed at // another Device would derive another Guest's runtime socket // directory and state Volume. The scope is `None` for the @@ -10031,9 +10031,9 @@ async fn video_socket_path(argv: &[String]) -> Result { )) } -// The OtelHostBridge runner is `socat UNIX-LISTEN:,...`. +// The OtelHostBridge runner is `socat UNIX-LISTEN:,...`. // socat does not unlink a pre-existing socket path before binding, so a -// stale `host-egress.sock` left behind by a prior bridge instance (e.g. +// stale `host-egress. sock` left behind by a prior bridge instance (e. g. // after the obs VM is restarted, draining and respawning the bridge) // makes the fresh socat exit immediately with "address in use". The // readiness probe only checks the socket *file* exists, so the stale @@ -11880,7 +11880,7 @@ fn deliver_targeted_reap( match broker_audit_log_handle().get() { Some(audit_log) => remove_and_notify(runner_id, notif, audit_log.as_ref()), None => { - // No audit handle (e.g. a unit test that didn't start the + // No audit handle (e. g. a unit test that didn't start the // reaper): still reap + notify so the child can't zombie. let removed = remove_runner_registries(runner_id); push_child_reap_notification(notif); @@ -17688,7 +17688,7 @@ mod tests { assert_eq!(export_record.authz_outcome, AuthzOutcome::Allow); // The outer error-audit path must NOT write a second (duplicate) - // record: BrokerError::StoreSyncFailed.audit() is a no-op because + // record: BrokerError::StoreSyncFailed. audit() is a no-op because // the terminal record was already emitted in the dispatch arm. error .audit( @@ -18096,7 +18096,7 @@ mod tests { caller_role: BrokerCallerRole::AdminUid { uid: configured_daemon_uid, }, - // Ignored because config.test_mode=false: the broker must use the + // Ignored because config. test_mode=false: the broker must use the // kernel SO_PEERCRED uid, not the envelope's claimed caller role. audit_join: None, }; diff --git a/packages/d2b-broker/src/state_cells.rs b/packages/d2b-broker/src/state_cells.rs index 0bcb6d6a7..b854bfa7e 100644 --- a/packages/d2b-broker/src/state_cells.rs +++ b/packages/d2b-broker/src/state_cells.rs @@ -163,7 +163,7 @@ impl std::fmt::Display for CellStoreError { /// Retention bounds for replayable non-one-time outcome records. /// /// One-time consumed markers are always exempt; records carrying live -/// in-process payloads (e.g. the runner pidfd registry) are live state, not +/// in-process payloads (e. g. the runner pidfd registry) are live state, not /// outcome history, and are exempt too. #[derive(Debug, Clone, Copy)] pub struct RetentionPolicy { @@ -195,7 +195,7 @@ struct CellRecord { /// into a reconciliation rather than an in-progress refusal. claimed: bool, durability: CellDurability, - /// Non-durable cell value (e.g. a runner's pidfd). Live state, exempt + /// Non-durable cell value (e. g. a runner's pidfd). Live state, exempt /// from retention and never serialized. payload: Option>, consumed_ms: u64, @@ -435,7 +435,7 @@ impl CellStore { reply_rx.recv().map_err(|_| CellStoreError::Poisoned)? } - /// Insert one payload record into an ephemeral cell (e.g. a registered + /// Insert one payload record into an ephemeral cell (e. g. a registered /// runner's pidfd). The cell record is in-process state, never durable; /// the recorded principal is the initiating principal of the write. pub fn insert_payload( diff --git a/packages/d2b-broker/src/sys.rs b/packages/d2b-broker/src/sys.rs index 2fda7b32e..8e47510db 100644 --- a/packages/d2b-broker/src/sys.rs +++ b/packages/d2b-broker/src/sys.rs @@ -255,7 +255,7 @@ pub fn tun_set_group(fd: &OwnedFd, gid: u32) -> io::Result<()> { /// (`RESOLVE_NO_SYMLINKS | RESOLVE_NO_MAGICLINKS | RESOLVE_BENEATH`). /// `RESOLVE_NO_XDEV` is additionally enforced at every component as /// defense-in-depth and is relaxed *only* exactly where a real, -/// pre-existing kernel/framework mount sits (e.g. `/run` tmpfs, `/dev` +/// pre-existing kernel/framework mount sits (e. g. `/run` tmpfs, `/dev` /// devtmpfs), since broker paths legitimately span those mounts - see /// [`open_dir_path_safe`] for the per-component mount-tolerant walk: /// @@ -291,7 +291,7 @@ pub mod path_safe { } /// Reject a world-writable (or symlink) parent directory, the most - /// common path-safety regression.for broker file targets. + /// common path-safety regression. for broker file targets. pub fn refuse_world_writable_parent(path: &Path) -> io::Result<()> { let parent = path.parent().ok_or_else(|| { io::Error::new( @@ -976,7 +976,7 @@ pub mod path_safe { /// `fstatat(AT_SYMLINK_NOFOLLOW)` of a single `name` component /// beneath an already-open safe parent dirfd. Returns `Ok(None)` /// when the entry is absent (`ENOENT`). The caller inspects - /// `st_mode` (e.g. `S_IFLNK` / `S_IFDIR`), `st_uid`/`st_gid`, and + /// `st_mode` (e. g. `S_IFLNK` / `S_IFDIR`), `st_uid`/`st_gid`, and /// `st_dev`/`st_ino` without following a symlink. Used by the /// swtpm-dir hardening step to detect symlink / non-dir / owner /// drift without opening the target. @@ -1006,7 +1006,7 @@ pub mod path_safe { /// Returns whether `fd` carries an extended POSIX ACL xattr. The /// tuple is `(access_present, default_present)` for - /// `system.posix_acl_access` and `system.posix_acl_default`. A + /// `system. posix_acl_access` and `system. posix_acl_default`. A /// directory with only the base owner/group/other entries (a /// "minimal" ACL) has NO xattr, so both `false` means "clean". An /// `ENODATA`/`ENOATTR`/`ENOTSUP` result is treated as absent so @@ -1172,7 +1172,7 @@ pub mod path_safe { /// tmpfs, `/dev` a devtmpfs, `/sys` sysfs, `/proc` procfs, and /// `/var/lib` may be its own mount. A single `/`-anchored `NO_XDEV` /// walk therefore fails with `EXDEV` at the first mount crossing - /// (e.g. `/`→`/run` when preparing `/run/d2b/vms/`, or + /// (e. g. `/`→`/run` when preparing `/run/d2b/vms/`, or /// `/`→`/dev` when opening `/dev/net/tun`). /// /// We resolve **component by component**. Each component is opened @@ -1335,7 +1335,7 @@ pub mod path_safe { // Apply mode + ownership only when WE created the dir, or when // the caller asked to re-assert metadata. The `created == false` // case here is the `mkdirat` EEXIST race: a concurrent actor - // (e.g. host activation) created the per-VM root between our + // (e. g. host activation) created the per-VM root between our // initial open (which returned NotFound) and this `mkdirat`. // Re-stamping it then would defeat `ensure_dir_preserve_existing` // exactly as the always-fchmod path did - clipping the ACL mask @@ -1406,7 +1406,7 @@ pub mod path_safe { /// Like [`mkdir_at`] but FAILS CLOSED on `EEXIST` (surfaced as /// [`io::ErrorKind::AlreadyExists`]) instead of treating a pre-existing /// entry as success. Used where adopting a directory this call did NOT - /// create would be a security bug - e.g. the swtpm NVRAM dir + /// create would be a security bug - e. g. the swtpm NVRAM dir /// fresh-create path (issue #64): a role UID with `rwx` on the sticky /// per-VM root can race-create `swtpm/` between the absence pre-check /// and this `mkdirat`, and the broker must refuse rather than @@ -1582,7 +1582,7 @@ pub mod pidfd_sys { /// `clone_args` per ``. Layout is stable since /// kernel 5.5 (the first `clone3`-with-pidfd release). We pin the /// `size = 88` shape (clone3 v2 / set_tid extension); the kernel - /// `clone3` accepts a smaller `args.size` (88) and rejects bigger + /// `clone3` accepts a smaller `args. size` (88) and rejects bigger /// sizes on older kernels, so we pass the minimal size that /// supports CLONE_PIDFD. #[repr(C)] @@ -1623,16 +1623,16 @@ pub mod pidfd_sys { /// v1.1.1 `into_cgroup_dirfd` parameter (per ADR 0011 /// Decision item 8 + ADR 0018 § "Atomic cgroup placement"): /// when `Some(dirfd)`, the clone3 syscall is invoked with - /// `CLONE_INTO_CGROUP` and `args.cgroup = dirfd as u64`. The + /// `CLONE_INTO_CGROUP` and `args. cgroup = dirfd as u64`. The /// kernel atomically places the new child into the cgroup /// pointed at by `dirfd` (typically the per-role leaf - /// `d2b.slice///`) - eliminating the + /// `d2b. slice///`) - eliminating the /// classical race window where the parent writes the child's - /// PID to `cgroup.procs` AFTER fork (during which the child + /// PID to `cgroup. procs` AFTER fork (during which the child /// is unaccounted in the per-role cgroup). /// /// `CLONE_INTO_CGROUP` is supported on kernel ≥ 5.7; the - /// fork+cgroup.procs fallback retains the v1.0 semantics for + /// fork+cgroup. procs fallback retains the v1.0 semantics for /// any kernel that returns ENOSYS/EINVAL on the new flag. #[allow(unsafe_code)] pub fn clone3_pidfd_or_fork_fallback( @@ -1887,7 +1887,7 @@ pub mod pidfd_sys { /// Run `setfacl /proc/self/fd/` in a forked /// child while keeping the target fd CLOEXEC in the broker parent. /// - /// `op` is the setfacl operation flag, e.g. `-m` to add/modify an + /// `op` is the setfacl operation flag, e. g. `-m` to add/modify an /// entry or `-x` to remove one. See [`run_setfacl_on_fd`] for the /// CLOEXEC rationale. #[allow(unsafe_code)] @@ -2408,7 +2408,7 @@ pub mod pidfd_sys { for path in &policy.writable_paths { by_path.entry(path.path.clone()).or_insert(false); } - // device_binds (e.g. /dev/kvm, /dev/dri/renderD128, + // device_binds (e. g. /dev/kvm, /dev/dri/renderD128, // /dev/nvidia*) are bind-mounted writable into the runner mount // namespace. The host already controls access via the dev-node // mode bits + groups; the bind-mount just ensures the device @@ -2431,7 +2431,7 @@ pub mod pidfd_sys { readonly, }); } - // bind_mounts entries are cross-domain bind mounts (e.g. + // bind_mounts entries are cross-domain bind mounts (e. g. // /run/user//wayland-0 -> /run/d2b-gpu//wayland-0). // The dst is created if missing; the src is bind-mounted at the // dst with MS_BIND|MS_REC. Both src and dst must be absolute. The @@ -3095,10 +3095,10 @@ pub mod pidfd_sys { "SpawnRunner: activation stdin exceeds bounded envelope", )); } - // NamespaceSet.user is ALLOWED when - // RunnerIsolationSpec.user_namespace provides the uid_map/gid_map + // NamespaceSet. user is ALLOWED when + // RunnerIsolationSpec. user_namespace provides the uid_map/gid_map // values. Caller must set both for the child to be fake-root - // inside the new user NS. Setting namespaces.user without + // inside the new user NS. Setting namespaces. user without // user_namespace is rejected because the child would land in the // namespace with overflowuid (65534) and no caps - never useful. let user_ns_spec = isolation.user_namespace; @@ -3491,7 +3491,7 @@ pub mod pidfd_sys { // not mask=---. // // Reject umasks that exceed the POSIX file-mode width (0o777) - // so a config typo (e.g. umask = 9999) is caught explicitly + // so a config typo (e. g. umask = 9999) is caught explicitly // rather than silently truncated by libc::umask. if let Some(mask) = child_umask { if mask > 0o777 { @@ -3541,10 +3541,10 @@ pub mod pidfd_sys { } // Parent-side user-NS map writes. Performed AFTER clone3 returns - // (we have the child's PID) and AFTER any fallback cgroup.procs + // (we have the child's PID) and AFTER any fallback cgroup. procs // attach that the parent must perform with host credentials. Both // complete BEFORE the sync pipe write that unblocks the child. - // Sequencing per `man 7 user_namespaces`: cgroup.procs fallback + // Sequencing per `man 7 user_namespaces`: cgroup. procs fallback // attach → uid_map → setgroups=deny → gid_map → sync byte. The // child has already closed its inherited write_fd, so if the // parent dies BEFORE this point the child gets EOF on read and @@ -3981,7 +3981,7 @@ mod tests { #[test] fn user_namespace_true_requires_spec() { - // namespaces.user=true but user_namespace=None is + // namespaces. user=true but user_namespace=None is // rejected before clone3 - the child would land in the // NS with overflowuid and never be able to setuid(0). let mut iso = isolation_with_user_namespace(None); @@ -3994,7 +3994,7 @@ mod tests { #[test] fn user_namespace_spec_requires_namespace_flag() { - // user_namespace=Some but namespaces.user=false is + // user_namespace=Some but namespaces. user=false is // also rejected - the spec would be silently ignored. let mut iso = isolation_with_user_namespace(Some(UserNamespaceSpec { host_uid_for_zero: 1000, @@ -4236,7 +4236,7 @@ mod tests { /// to mutate mounts owned by the parent user-NS); the call /// returns EPERM and the child exits `CHILD_EXIT_MOUNT` (64). /// - /// Skips cleanly on hosts with `kernel.unprivileged_userns_clone=0` + /// Skips cleanly on hosts with `kernel. unprivileged_userns_clone=0` /// (clone3 returns EPERM before any child runs). #[test] fn apply_mount_actions_skipped_in_user_ns() { @@ -4309,7 +4309,7 @@ mod tests { ) { Ok(o) => o, Err(e) if e.raw_os_error() == Some(nix::libc::EPERM) => { - // kernel.unprivileged_userns_clone=0: user namespaces + // kernel. unprivileged_userns_clone=0: user namespaces // not available on this host - skip rather than fail. println!( "SKIP: unprivileged user NS not available \ @@ -4332,7 +4332,7 @@ mod tests { } // CHILD_EXIT_MOUNT = 64 would mean apply_mount_actions ran and - // got EPERM on the locked /nix/store bind-mount - i.e., the + // got EPERM on the locked /nix/store bind-mount - i. e., the // `if !in_ns_credentials` guard is absent. assert_eq!( wait_status, diff --git a/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs b/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs index 26aef5650..4c3e93fda 100644 --- a/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs +++ b/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs @@ -11,7 +11,7 @@ //! 2. The SCM_RIGHTS transport delivers exactly one fd to the //! receiver. //! 3. The receiver-side fd remains valid after the broker copy is -//! dropped (i.e. it really is a freshly-duplicated kernel handle, +//! dropped (i. e. it really is a freshly-duplicated kernel handle, //! not the broker's own descriptor). //! 4. The `O_CLOEXEC` flag survives the transport (this is a kernel //! invariant for SCM_RIGHTS - we check it on the receiving side). diff --git a/packages/d2b-broker/tests/socket_activation.rs b/packages/d2b-broker/tests/socket_activation.rs index ebee1a318..acc3f5c8f 100644 --- a/packages/d2b-broker/tests/socket_activation.rs +++ b/packages/d2b-broker/tests/socket_activation.rs @@ -1,6 +1,6 @@ //! Socket-activation integration test. //! -//! Spawns the broker binary with `LISTEN_FDS=1 LISTEN_FDNAMES=priv.sock` +//! Spawns the broker binary with `LISTEN_FDS=1 LISTEN_FDNAMES=priv. sock` //! and fd 3 = a bound `AF_UNIX SOCK_SEQPACKET` listen socket, then asserts //! that the broker: //! @@ -14,7 +14,7 @@ //! passed to `execve`. To work around this we launch a POSIX `sh` one-liner: //! //! ```sh -//! LISTEN_PID=$$ LISTEN_FDS=1 LISTEN_FDNAMES=priv.sock exec 3>& broker +//! LISTEN_PID=$$ LISTEN_FDS=1 LISTEN_FDNAMES=priv. sock exec 3>& broker //! ``` //! //! `$$` expands to the shell's PID; after `exec`, the broker runs in the same @@ -146,7 +146,7 @@ fn broker_adopts_socket_activated_fd_and_serves_hello() { // Shell one-liner: // LISTEN_PID=$$ → shell's PID; after `exec`, broker's PID matches. // LISTEN_FDS=1 → one socket fd follows. - // LISTEN_FDNAMES=priv.sock → matches the broker's fd-name expectation. + // LISTEN_FDNAMES=priv. sock → matches the broker's fd-name expectation. // exec 3>& broker → redirect listen socket to fd 3, then exec broker. // // Variable references ($BROKER etc.) protect against path quoting issues. diff --git a/packages/d2b-bus/src/authorization.rs b/packages/d2b-bus/src/authorization.rs index 881057334..89576a9d1 100644 --- a/packages/d2b-bus/src/authorization.rs +++ b/packages/d2b-bus/src/authorization.rs @@ -185,7 +185,7 @@ impl BusAuthorizer { }; if let Some(registry) = &self.assignments { // The assignment registry lock is an externally supplied std Mutex - // (d2bd-runtime's AssignmentRegistry);the validation is a brief + // (d2bd-runtime's AssignmentRegistry); the validation is a brief // non-suspending critical section on the sync authorization surface. #[allow(clippy::disallowed_methods, reason = "synchronous path")] registry @@ -268,7 +268,7 @@ impl BusAuthorizer { // Policy state is evaluated in brief non-suspending critical sections behind // the synchronous SessionAcceptor surface (component_session_acceptor - // closures)and pub sync API consumed by the daemon;the lock has no async + // closures) and pub sync API consumed by the daemon; the lock has no async // form here. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn lock(&self) -> MutexGuard<'_, AuthorizationRuntime> { diff --git a/packages/d2b-bus/src/router.rs b/packages/d2b-bus/src/router.rs index 3b1aa7aa1..9bc2af71b 100644 --- a/packages/d2b-bus/src/router.rs +++ b/packages/d2b-bus/src/router.rs @@ -917,7 +917,7 @@ impl BusCore { // Active-session gauges are updated in a brief non-suspending critical // section fed from async registration/reconnect flows and sync teardown - // accounting;the std lock stays short and never crosses an await. + // accounting; the std lock stays short and never crosses an await. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn record_session_registered(&self, session: SessionId) { let (direction, transport) = self.session_metrics(session); @@ -1108,7 +1108,7 @@ impl BusCore { } // Operation bookkeeping is a brief non-suspending critical sectionshared - // with synchronous teardown (Drop impls of OperationLease/BusStream)and + // with synchronous teardown (Drop impls of OperationLease/BusStream) and // the operation table has no async form here. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn lock_operations(&self) -> MutexGuard<'_, OperationTable> { @@ -1896,7 +1896,7 @@ pub struct CommittedInteractionSubjectInstallBody { /// use d2b_bus::CommittedInteractionSubjectIssuer; /// /// fn clone(value: CommittedInteractionSubjectIssuer) { -/// let _ = value.clone(); +/// let _ = value. clone(); /// } /// ``` /// @@ -1933,7 +1933,7 @@ pub struct CommittedInteractionSubjectIssuer { /// use d2b_bus::CommittedInteractionSubjectInstall; /// /// fn inspect(value: &CommittedInteractionSubjectInstall) { -/// let _ = &value.body; +/// let _ = &value. body; /// } /// ``` /// @@ -1941,7 +1941,7 @@ pub struct CommittedInteractionSubjectIssuer { /// use d2b_bus::CommittedInteractionSubjectInstall; /// /// fn clone(value: CommittedInteractionSubjectInstall) { -/// let _ = value.clone(); +/// let _ = value. clone(); /// } /// ``` /// @@ -2070,7 +2070,7 @@ struct ComponentSessionRegistrar { /// use d2b_bus::ComponentSessionAdmission; /// /// fn inspect(value: &ComponentSessionAdmission) { -/// let _ = &value.identity; +/// let _ = &value. identity; /// } /// ``` /// @@ -2451,7 +2451,7 @@ impl ComponentResponses { } }; let accepted = { - // Brief non-suspending endpoint-state critical section;the + // Brief non-suspending endpoint-state critical section; the // same state is locked by the sync BusEndpoint trait paths // (invalidate_session/terminalize_cancel), so it has no // async form. @@ -2494,7 +2494,7 @@ impl ComponentResponses { } } - // Brief non-suspending response-waiter mutation;state has no async form + // Brief non-suspending response-waiter mutation; state has no async form // because sync BusEndpoint trait paths lock it too. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn deliver(&self, request_id: d2b_session::contract::RequestId, response: ComponentResponse) { @@ -2541,7 +2541,7 @@ impl ComponentResponses { } let stream_id = ttrpc_stream_id(&frame).map_err(|_| EndpointError::Rejected)?; { - // Brief non-suspending critical section;locked by sync trait paths + // Brief non-suspending critical section; locked by sync trait paths // too (invalidate_session/terminalize_cancel), so no async form. #[allow(clippy::disallowed_methods, reason = "synchronous path")] let mut state = self @@ -2726,7 +2726,7 @@ fn publish_component_request( } // Component request publication takes both endpoint locks in one brief - // non-suspending critical section;the same state is locked by the sync + // non-suspending critical section; the same state is locked by the sync // BusEndpoint trait paths (invalidate_session/terminalize_cancel), so // the locks have no async form. #[allow(clippy::disallowed_methods, reason = "synchronous path")] @@ -2789,7 +2789,7 @@ fn publish_component_request( #[async_trait::async_trait] impl crate::registry::BusEndpoint for ComponentEndpoint { - // Sync BusEndpoint trait contract;brief non-suspending activity revocation. + // Sync BusEndpoint trait contract; brief non-suspending activity revocation. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn invalidate_session(&self) -> crate::registry::SessionInvalidation { let writer_fence = self.cancellation.revoke_generation_writes(); @@ -2857,7 +2857,7 @@ impl crate::registry::BusEndpoint for ComponentEndpoint { let caller_stream_id = ttrpc_stream_id(request.payload()).map_err(|_| EndpointError::Rejected)?; let correlation = { - // Brief non-suspending correlation allocation;the same lock is + // Brief non-suspending correlation allocation; the same lock is // used from sync paths, and no await happens while it is held. #[allow(clippy::disallowed_methods, reason = "synchronous path")] let mut correlations = self @@ -3703,8 +3703,8 @@ impl BusIngress { /// # Errors /// Returns `BusError::SessionClosed` when the bus or session is closed; /// `BusError::RouteShape` for a non-method route, an oversized payload, or -/// an oversized response;the session's authorization or registry admission -/// failures otherwise;an endpoint rejection wrapped as `BusError::Endpoint`; +/// an oversized response; the session's authorization or registry admission +/// failures otherwise; an endpoint rejection wrapped as `BusError::Endpoint`; /// `BusError::Cancelled` or /// `BusError::Operation(OperationError::DeadlineExceeded)` when the attempt is /// cancelled or outlives its deadline. diff --git a/packages/d2b-bus/src/session/contract.rs b/packages/d2b-bus/src/session/contract.rs index a8cfc9b47..a30aea96a 100644 --- a/packages/d2b-bus/src/session/contract.rs +++ b/packages/d2b-bus/src/session/contract.rs @@ -765,7 +765,7 @@ impl RuntimeRouteAdmissionAuthority { /// use d2b_bus::session::contract::RouteAdmissionEvidence; /// /// fn forge(mut value: RouteAdmissionEvidence) { -/// value.body = todo!(); +/// value. body = todo!(); /// } /// ``` pub struct RouteAdmissionEvidence { @@ -881,7 +881,7 @@ impl RouteAdmissionIssuer { #[allow(dead_code)] // Route admission authority state is read/updated in brief non-suspending // critical sections behind synchronized admission flows and the sync - // ZoneLinkSession guard surface (admit/is_open/revalidate);no async form. + // ZoneLinkSession guard surface (admit/is_open/revalidate); no async form. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub(crate) fn issue( &self, diff --git a/packages/d2b-bus/src/streams.rs b/packages/d2b-bus/src/streams.rs index e717e7715..26391bacc 100644 --- a/packages/d2b-bus/src/streams.rs +++ b/packages/d2b-bus/src/streams.rs @@ -559,7 +559,7 @@ impl StreamBridge { } } - // Bridge state is mutated in brief non-suspending critical sections;the + // Bridge state is mutated in brief non-suspending critical sections; the // same state is closed synchronously from Drop teardown (OutgoingStream/ // IncomingStream), so the lock has no async form here. #[allow(clippy::disallowed_methods, reason = "synchronous path")] diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index e23925d67..13ee8ac45 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -128,7 +128,7 @@ pub enum BrokerRequest { /// without requiring static bundle firewall/bind intent refs. /// /// The daemon has already validated: (1) the busid is present in sysfs, - /// (2) the target VM has `runtime.capabilities.usbHotplug = true`, (3) no + /// (2) the target VM has `runtime. capabilities. usbHotplug = true`, (3) no /// other active claim holds this busid. The broker validates the busid shape, /// acquires the per-busid OFD lock, and runs the `usbip bind` helper. /// @@ -1210,7 +1210,7 @@ pub struct CreateTapFdRequest { } /// The slice path is pinned by the bundle -/// (`/sys/fs/cgroup/d2b.slice`). It is **not** taken from caller +/// (`/sys/fs/cgroup/d2b. slice`). It is **not** taken from caller /// input - the broker reads it from its own bundle copy via `scope_id`. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -1287,7 +1287,7 @@ pub struct SecretByIdRequest { /// The daemon never passes argv, env, uid/gid, caps, seccomp profile /// path, or any other launch authority across the wire. The broker -/// reads the full launch context from `bundle.vms[vm_id].roles[role_id]` +/// reads the full launch context from `bundle. vms[vm_id].roles[role_id]` /// and constructs the minijail exec line itself. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -2065,7 +2065,7 @@ pub struct StoreSyncRequest { /// Store-sync response. Returned after the broker successfully /// populates the per-VM hardlink farm and swaps the `current` symlink -/// atomically. The `hardlink_farm_path` is the per-VM farm root (i.e. +/// atomically. The `hardlink_farm_path` is the per-VM farm root (i. e. /// `/var/lib/d2b/vms//store-view/`); the active generation /// directory is reachable via the `current` symlink. /// @@ -2137,7 +2137,7 @@ pub struct UsbipBindRequest { /// USBIP firewall-rule skeleton. The rule body and the bus_id are /// derived from the per-busid policy in the trusted bundle -/// (`bundle.usbip.busidLocks[*]`) via the +/// (`bundle. usbip. busidLocks[*]`) via the /// `bundle_usbip_firewall_intent_ref` opaque-ID lookup. The legacy /// caller-supplied `bus_id: String` + `rule_hash: String` fields were /// replaced with this opaque reference because the raw `bus_id` was @@ -2177,7 +2177,7 @@ pub struct UsbipUnbindRequest { /// Explicit-attach: bind a present sysfs busid for a USB-capable VM /// without a bundle intent ref. The daemon has already completed: /// 1. sysfs busid presence check (fail-closed if device absent), -/// 2. USB-capable gate (`runtime.capabilities.usbHotplug`), +/// 2. USB-capable gate (`runtime. capabilities. usbHotplug`), /// 3. active-claim exclusivity check (OFD lock read). /// /// The broker acquires the per-busid OFD lock, runs `usbip bind`, and @@ -2415,7 +2415,7 @@ pub struct DeregisterRunnerPidfdResponse { /// The daemon never names argv, env, uid/gid, caps, /// kernel/initrd/cmdline strings, virtiofs sockets, TAP fds, or any /// other launch authority across the wire. The broker resolves the full -/// role spawn context from `bundle.vms[vm_id].roles[role_id]` anchored +/// role spawn context from `bundle. vms[vm_id].roles[role_id]` anchored /// by the opaque `bundle_runner_intent_ref`. The wire shape follows the /// opaque-only contract for every other mutating variant. /// @@ -2445,7 +2445,7 @@ pub enum RunnerRole { /// persisted record written before the rename still decodes. #[serde(rename = "activation-nixos-runner", alias = "activation-nixos")] ActivationNixos, - /// virtiofsd sidecar; one per `d2b.vms..runner.shares` row. The + /// virtiofsd sidecar; one per `d2b. vms..runner. shares` row. The /// daemon/bundle provides argv from the runner-shape generators. Virtiofsd, /// swtpm sidecar (long-lived `swtpm socket ...` process). @@ -2853,7 +2853,7 @@ pub struct SpawnRunnerResponse { pub start_time_ticks: u64, /// Index into the SCM_RIGHTS fd vector the daemon should treat as /// the spawned process's pidfd. Always `0` today - kept explicit - /// so future multi-fd spawn responses (e.g. CH API socket + pidfd) + /// so future multi-fd spawn responses (e. g. CH API socket + pidfd) /// have an existing wire slot. pub pidfd_index: u32, /// Provider-controller bootstrap endpoint created and retained by the broker. @@ -2936,7 +2936,7 @@ pub struct BrokerRequestEnvelope { } /// Caller role classification derived from `SO_PEERCRED` + the -/// `d2b.site.adminUsers` / `d2b.site.launcherUsers` +/// `d2b. site. adminUsers` / `d2b. site. launcherUsers` /// allowlists. Mirrors the legacy `bootstrap::wire::CallerRole` /// but lives in the production wire crate so the live broker /// dispatch can take it directly. @@ -3088,7 +3088,7 @@ pub struct ValidateLockSpecResponse { /// /// The daemon sends the VM's opaque `vm_id`; the broker resolves /// every `DiskInit` plan-op from the trusted bundle's -/// `ProcessNode.plan_ops` for that VM and creates or validates the +/// `ProcessNode. plan_ops` for that VM and creates or validates the /// disk images before runner spawn. Existing `ifAbsent` images are /// skipped only after fd-bound identity and ext4-superblock validation; /// declared owner/mode posture drift is repaired automatically when the diff --git a/packages/d2b-contracts-control/src/cli_output.rs b/packages/d2b-contracts-control/src/cli_output.rs index 1af958ab3..1350b7e30 100644 --- a/packages/d2b-contracts-control/src/cli_output.rs +++ b/packages/d2b-contracts-control/src/cli_output.rs @@ -38,7 +38,7 @@ pub struct ListItemOutputV2 { pub runner_parity_ok: Option, /// Canonical realm-native workload target address (`..d2b`). /// Present when the daemon has associated this entry with a realm workload - /// identity. Absent for classical `d2b.vms` entries not yet adopted into + /// identity. Absent for classical `d2b. vms` entries not yet adopted into /// a realm. Additive - old CLI consumers must tolerate its absence. #[serde(default, skip_serializing_if = "Option::is_none")] pub canonical_target: Option, @@ -541,5 +541,67 @@ mod tests { .insert("autoUpgrade_commits_lockX".to_owned(), json!(true)); assert!(serde_json::from_value::(drifted).is_err()); } + + /// The live services DTO has no in-tree consumer, so this pin is the only + /// thing standing behind its wire shape. It pins the asymmetry that is + /// easiest to drift silently: only `qemu_media` skips a `None`, while + /// `gpu`, `video`, `snd`, and `swtpm` serialize an explicit `null`. + #[test] + fn status_services_output_v2_pins_its_exact_wire_keys() { + let services = StatusServicesOutputV2 { + d2b: "running".to_owned(), + microvm: "running".to_owned(), + virtiofsd: "running".to_owned(), + qemu_media: Some("stopped".to_owned()), + gpu: Some("stopped".to_owned()), + video: None, + snd: Some("running".to_owned()), + swtpm: None, + }; + + let value = serde_json::to_value(&services).unwrap(); + let object = value.as_object().unwrap(); + + // Populated fields keep their camelCase keys. + for key in ["d2b", "microvm", "virtiofsd", "qemuMedia", "gpu", "snd"] { + assert!(object.contains_key(key), "missing wire key {key}: {value}"); + } + + // Only `qemu_media` may be omitted when absent. + let without_media = serde_json::to_value(StatusServicesOutputV2 { + qemu_media: None, + ..services.clone() + }) + .unwrap(); + assert!( + !without_media + .as_object() + .unwrap() + .contains_key("qemuMedia"), + "qemuMedia must be omitted when None: {without_media}" + ); + + // The four sidecar fields emit an explicit null rather than vanishing. + for key in ["video", "swtpm"] { + assert_eq!( + object.get(key), + Some(&json!(null)), + "{key} must serialize as an explicit null: {value}" + ); + } + + assert_eq!( + serde_json::from_value::(value).unwrap(), + services + ); + + // `deny_unknown_fields`: a drifted sibling key must fail to decode. + let mut drifted = serde_json::to_value(&services).unwrap(); + drifted + .as_object_mut() + .unwrap() + .insert("d2bX".to_owned(), json!("running")); + assert!(serde_json::from_value::(drifted).is_err()); + } } diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index 60b8791cb..849a53db6 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -364,13 +364,17 @@ impl std::error::Error for MutationModeError {} /// Common flags every mutating-verb request carries. /// /// The mode moves with the flags, so a request that selects neither -/// `dryRun` nor `apply` - which the daemon refuses - has no value here. -/// The serialized shape is unchanged: the flat `dryRun`, `apply`, and `json` -/// keys the protocol has always carried. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +/// `dryRun` nor `apply` decodes with no mode rather than failing to decode: +/// the daemon refuses it through the same structured +/// `MutatingVerbOutcome::InvalidRequest` envelope and remediation string every +/// other invalid mutating request gets, which is a contract a client can +/// match on. The serialized shape is unchanged: the flat `dryRun`, `apply`, +/// and `json` keys the protocol has always carried. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] #[serde(try_from = "MutationFlagsWire", into = "MutationFlagsWire")] pub struct MutationFlags { - pub mode: MutationMode, + /// `None` when the request selected neither `dryRun` nor `apply`. + pub mode: Option, /// Ask for the machine-readable (`json`) response body. pub json: bool, } @@ -395,7 +399,7 @@ impl TryFrom for MutationFlags { fn try_from(wire: MutationFlagsWire) -> Result { Ok(Self { - mode: MutationMode::from_flags(wire.dry_run, wire.apply)?, + mode: MutationMode::from_flags(wire.dry_run, wire.apply).ok(), json: wire.json, }) } @@ -403,7 +407,10 @@ impl TryFrom for MutationFlags { impl From for MutationFlagsWire { fn from(flags: MutationFlags) -> Self { - let (dry_run, apply) = flags.mode.to_flags(); + let (dry_run, apply) = flags + .mode + .map(MutationMode::to_flags) + .unwrap_or((false, false)); Self { dry_run, apply, @@ -426,7 +433,7 @@ impl JsonSchema for MutationFlags { #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct VmLifecycleRequest { pub vm: String, - #[serde(flatten)] + #[serde(default, flatten)] pub flags: MutationFlags, /// Bypass provider graceful-shutdown and use the existing forced cleanup path. #[schemars(default)] @@ -449,7 +456,7 @@ pub struct ActivationRequest { #[serde(default, skip_serializing_if = "Option::is_none")] #[schemars(range(min = 1))] pub to_generation: Option, - #[serde(flatten)] + #[serde(default, flatten)] pub flags: MutationFlags, } @@ -458,7 +465,7 @@ pub struct ActivationRequest { pub struct UsbipBindCliRequest { pub vm: String, pub bus_id: String, - #[serde(flatten)] + #[serde(default, flatten)] pub flags: MutationFlags, } @@ -467,13 +474,13 @@ pub struct UsbipBindCliRequest { pub struct UsbipUnbindCliRequest { pub vm: String, pub bus_id: String, - #[serde(flatten)] + #[serde(default, flatten)] pub flags: MutationFlags, } /// Maximum decoded stdin chunk per `WriteStdin` op and decoded output chunk /// per `ReadOutput` op. The base64 envelope of a -/// 64 KiB chunk (~87 KiB) stays well under the 1 MiB public.sock frame, so a +/// 64 KiB chunk (~87 KiB) stays well under the 1 MiB public. sock frame, so a /// single exec op never approaches the frame cap. pub const EXEC_MAX_CHUNK_BYTES: u64 = 64 * 1024; @@ -1994,7 +2001,7 @@ pub enum AudioErrorKind { ProviderMisconfigured, /// The requested VM was not found in the bundle. VmNotFound, - /// Audio enforcement is not available for this VM (e.g. the runtime does + /// Audio enforcement is not available for this VM (e. g. the runtime does /// not support it and no degraded path exists). EnforcementUnavailable, /// The VM exists but audio is not enabled in its manifest entry. @@ -2063,7 +2070,7 @@ pub enum AudioOp { #[serde(rename_all = "camelCase")] pub struct AudioChannelState { /// Current volume/gain level in percent. `None` when the level is unknown - /// (e.g. the provider has not yet synced state). + /// (e. g. the provider has not yet synced state). #[serde(default, skip_serializing_if = "Option::is_none")] pub level: Option, /// Whether the channel is currently muted. @@ -2155,26 +2162,26 @@ pub enum AudioOpResponse { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct HostPrepareRequest { - #[serde(flatten)] + #[serde(default, flatten)] pub flags: MutationFlags, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct HostDestroyRequest { - #[serde(flatten)] + #[serde(default, flatten)] pub flags: MutationFlags, } /// `host reconcile` request payload. Today the only scope is -/// `--network`; future versions may add additional scopes (e.g. +/// `--network`; future versions may add additional scopes (e. g. /// `--ownership`) carved out of `host prepare`. The daemon rejects /// requests with no scope selected with a typed `invalid-request` /// envelope. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct HostReconcileRequest { - #[serde(flatten)] + #[serde(default, flatten)] pub flags: MutationFlags, /// Re-run the per-env nftables / route / sysctl reconcile. #[serde(default)] @@ -2732,7 +2739,7 @@ pub struct ListEntry { pub usbip: bool, pub vm: String, /// Realm-native workload identity. Present for workloads that have been - /// associated with a realm; `None` for classical `d2b.vms` entries that + /// associated with a realm; `None` for classical `d2b. vms` entries that /// have not yet been adopted into a realm. Additive field - old daemons /// omit it; new CLI consumers must tolerate its absence. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -2769,7 +2776,7 @@ pub struct VmStatus { pub usb: Option, pub vm: String, /// Realm-native workload identity. Present for workloads that have been - /// associated with a realm; `None` for classical `d2b.vms` entries that + /// associated with a realm; `None` for classical `d2b. vms` entries that /// have not yet been adopted into a realm. Additive field - old daemons /// omit it; new CLI consumers must tolerate its absence. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -3284,7 +3291,7 @@ mod tests { decoded, PublicRequest::VmStop(VmLifecycleRequest { vm, - flags: MutationFlags { mode: MutationMode::Apply, .. }, + flags: MutationFlags { mode: Some(MutationMode::Apply), .. }, force: false, no_wait_api: false, }) if vm == "corp-vm" @@ -3305,9 +3312,9 @@ mod tests { } #[test] - fn mutating_flags_keeps_the_flat_pair_and_requires_a_mode() { + fn mutating_flags_keep_the_flat_pair_and_admit_a_no_mode_payload() { let apply = MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }; assert_eq!( @@ -3327,23 +3334,59 @@ mod tests { decoded, PublicRequest::VmStop(VmLifecycleRequest { flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, .. }) )); - let error = serde_json::from_value::(serde_json::json!({ + // A payload that selects neither flag decodes with no mode rather + // than failing admission: the daemon refuses it through the same + // structured `MutatingVerbOutcome::InvalidRequest` envelope, with its + // remediation string, that every other invalid mutating request gets. + // A decode failure here would replace that matchable outcome with an + // opaque frame error. + let decoded: PublicRequest = serde_json::from_value(serde_json::json!({ "kind": "vm stop", "payload": { "vm": "corp-vm" } })) - .expect_err("a payload with no mode must fail admission"); - assert!( - error.to_string().contains("neither dryRun nor apply"), - "the refusal should name the flags: {error}" + .expect("a payload that selects no mode still decodes"); + assert!(matches!( + decoded, + PublicRequest::VmStop(VmLifecycleRequest { + flags: MutationFlags { mode: None, json: false }, + .. + }) + )); + + // Both flags set still resolves to the documented precedence. + let decoded: PublicRequest = serde_json::from_value(serde_json::json!({ + "kind": "vm stop", + "payload": { + "vm": "corp-vm", + "dryRun": true, + "apply": true + } + })) + .expect("a payload that sets both flags decodes"); + assert!(matches!( + decoded, + PublicRequest::VmStop(VmLifecycleRequest { + flags: MutationFlags { + mode: Some(MutationMode::DryRun), + .. + }, + .. + }) + )); + + // Round trip: a no-mode value re-serializes to the flat pair unset. + assert_eq!( + serde_json::to_string(&MutationFlags::default()).expect("flags serialize"), + "{\"dryRun\":false,\"apply\":false,\"json\":false}" ); } @@ -3352,7 +3395,7 @@ mod tests { let without_force = serde_json::to_value(PublicRequest::VmStop(VmLifecycleRequest { vm: "corp-vm".to_owned(), flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, force: false, @@ -3364,7 +3407,7 @@ mod tests { serde_json::to_string(&PublicRequest::VmStop(VmLifecycleRequest { vm: "corp-vm".to_owned(), flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, force: false, @@ -3377,7 +3420,7 @@ mod tests { let with_force = serde_json::to_value(PublicRequest::VmRestart(VmLifecycleRequest { vm: "corp-vm".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: true, diff --git a/packages/d2b-contracts-provider/src/v3/credential.rs b/packages/d2b-contracts-provider/src/v3/credential.rs index 5def9c773..76e2e20cf 100644 --- a/packages/d2b-contracts-provider/src/v3/credential.rs +++ b/packages/d2b-contracts-provider/src/v3/credential.rs @@ -4,7 +4,7 @@ //! ResourceType. The scope, audience, consumer, allowed-operation, rotation, //! expiry, revocation, and identity-Guest fields are Layer 2 base fields; //! non-secret implementation-only desired settings belong to the Layer 3 -//! `spec.provider` envelope on the universal `ResourceSpec`. +//! `spec. provider` envelope on the universal `ResourceSpec`. //! //! The base spec is zero-secret by construction: it carries no token, key, //! pre-shared key, cookie, claim, or other credential byte. Sensitive bytes diff --git a/packages/d2b-contracts-provider/src/v3/provider.rs b/packages/d2b-contracts-provider/src/v3/provider.rs index f37e09fd8..36f47ad4c 100644 --- a/packages/d2b-contracts-provider/src/v3/provider.rs +++ b/packages/d2b-contracts-provider/src/v3/provider.rs @@ -896,12 +896,12 @@ impl ComponentStateVolumeProjection { &self.source_execution_ref } - /// Return the Volume `quota.maxBytes` value. + /// Return the Volume `quota. maxBytes` value. pub const fn quota_max_bytes(&self) -> u64 { self.quota_max_bytes } - /// Return the nonzero Volume `quota.maxInodes` value. + /// Return the nonzero Volume `quota. maxInodes` value. pub const fn quota_max_inodes(&self) -> u64 { self.quota_max_inodes } @@ -1086,7 +1086,7 @@ impl ComponentStateNamespace { self.sensitivity_class } - /// Return the byte quota copied to `quota.maxBytes`. + /// Return the byte quota copied to `quota. maxBytes`. pub const fn quota_bytes(&self) -> u64 { self.quota_bytes } @@ -1814,7 +1814,7 @@ impl<'de> Deserialize<'de> for StandardCapabilityMatrix { } } -/// One registered `spec.provider` or `status.provider` extension schema. +/// One registered `spec. provider` or `status. provider` extension schema. /// /// The resource store validates every extension write against the installed /// Provider's registration, rejecting an unregistered or version-mismatched @@ -1838,8 +1838,8 @@ redacted_debug!(ExtensionSchemaRegistration); /// fingerprint it implements, the signed capability matrix, and the strict /// extension schemas it registers. The base itself is never redefined here: /// fields shared across implementations are promoted to the ResourceType -/// base and are never registered under `spec.provider` or -/// `status.provider`. +/// base and are never registered under `spec. provider` or +/// `status. provider`. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct ResourceApiBinding { @@ -1988,12 +1988,12 @@ impl ResourceApiBinding { &self.capability_matrix } - /// The registered `spec.provider` extension schema, if any. + /// The registered `spec. provider` extension schema, if any. pub const fn spec_extension(&self) -> Option<&ExtensionSchemaRegistration> { self.spec_extension.as_ref() } - /// The registered `status.provider` extension schema, if any. + /// The registered `status. provider` extension schema, if any. pub const fn status_extension(&self) -> Option<&ExtensionSchemaRegistration> { self.status_extension.as_ref() } @@ -2208,7 +2208,7 @@ impl ProjectionFactory { /// Decide whether an export may target the supplied stored resource. /// - /// `ResourceExport.resourceRef` must target a locally owned authority + /// `ResourceExport. resourceRef` must target a locally owned authority /// Service. An import-owned projection is never re-exportable. pub fn admits_export_target( &self, diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs index 7a6972703..20eb946b1 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs @@ -1,16 +1,16 @@ //! The shared audio semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen audio pair `audio.d2bus.org.AudioService` and -//! `audio.d2bus.org.AudioBinding`. The field sets below are the top-level +//! frozen audio pair `audio. d2bus. org.AudioService` and +//! `audio. d2bus. org.AudioBinding`. The field sets below are the top-level //! provider-neutral base fields stated by the audio Provider dossier's -//! `AudioService.spec`, `AudioService.status`, `AudioBinding.spec`, and -//! `AudioBinding.status` tables, which are the ResourceType base per D089 and +//! `AudioService. spec`, `AudioService. status`, `AudioBinding. spec`, and +//! `AudioBinding. status` tables, which are the ResourceType base per D089 and //! D088. //! //! PipeWire aliases, node selectors, portal settings, frontend parameters, and //! every other implementation detail are rejected from these bases and belong -//! only in an implementation's strict `spec.provider` and `status.provider` +//! only in an implementation's strict `spec. provider` and `status. provider` //! extensions. //! //! Interiors this catalog does not model. `grants` carries `mic`, `speaker`, @@ -79,7 +79,7 @@ const BINDING_STATUS_ALLOWED: &[&str] = &[ /// A projection Service carries only `providerRef`, its observed role, and its /// local route Endpoints. It never carries the owner authority descriptor and -/// never carries `spec.provider`. +/// never carries `spec. provider`. const PROJECTION_SPEC_ALLOWED: &[&str] = &["providerRef", "serviceRole", "implementationEndpointRefs"]; const PROJECTION_SPEC_REQUIRED: &[&str] = @@ -121,7 +121,7 @@ mod tests { assert_base_is_provider_neutral, assert_minimal_base_round_trips, object, provider_ref, }; - /// Canonical minimal base acceptance without `spec.provider`, plus a + /// Canonical minimal base acceptance without `spec. provider`, plus a /// strict serde and canonical-schema round trip. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { @@ -167,8 +167,8 @@ mod tests { assert!(contract.validate_minimal_base_spec(&spec).is_err()); } - /// Common fields only under `status.resource`; implementation observation - /// only under `status.provider`. + /// Common fields only under `status. resource`; implementation observation + /// only under `status. provider`. #[test] fn a_pipewire_observation_is_not_a_common_status_field() { let status = contract().service().status(); diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs index 3a888c7e9..4d459941c 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs @@ -13,12 +13,12 @@ //! //! Two spellings appear here and are never interchangeable. The API //! ResourceType is the dot-qualified name, for example -//! `audio.d2bus.org.AudioService`, and a ResourceRef appends `/` to it. +//! `audio. d2bus. org.AudioService`, and a ResourceRef appends `/` to it. //! The schema identity is the slash form, `//spec` and //! `//status`. //! //! Scope of the base. A base layer here is the frozen top-level field set of -//! `spec` and of `status.resource` for one ResourceType, plus its schema +//! `spec` and of `status. resource` for one ResourceType, plus its schema //! identity, version, and fingerprint. That is exactly the surface the //! specification freezes as provider-neutral. Where the specification names a //! base field but does not fix that field's interior member names or value @@ -297,7 +297,7 @@ impl SemanticLayer { pub enum SemanticContractError { /// A base spec or status layer failed its frozen field-name schema. SchemaViolation, - /// A projection spec carried a `spec.provider` extension. A Core-generated + /// A projection spec carried a `spec. provider` extension. A Core-generated /// projection permits only `providerRef`, the semantic base and import /// fields, and ResourceImport ownership. ProjectionProviderExtensionForbidden, @@ -574,7 +574,7 @@ impl SemanticTypeContract { &self.spec } - /// Borrow the frozen base `status.resource` layer. + /// Borrow the frozen base `status. resource` layer. pub const fn status(&self) -> &SemanticLayerSchema { &self.status } @@ -583,7 +583,7 @@ impl SemanticTypeContract { /// /// This is exactly the field set the canonical minimal valid base Spec /// supplies, and every conformant implementation must accept it without - /// a `spec.provider` extension. + /// a `spec. provider` extension. pub fn required_spec_fields(&self) -> impl Iterator + '_ { self.spec.required_names() } @@ -621,7 +621,7 @@ impl SemanticTypeContract { } /// Assemble the canonical minimal valid base Spec, without a - /// `spec.provider` extension. + /// `spec. provider` extension. /// /// `base_values` must supply exactly the required base field names other /// than `providerRef`, which the envelope owns. The catalog supplies the @@ -903,13 +903,13 @@ impl SemanticProjectionBinding { /// Admit a Core-generated projection Service spec. /// /// A projection permits only `providerRef`, the semantic base and import - /// fields, and ResourceImport ownership. A `spec.provider` extension is + /// fields, and ResourceImport ownership. A `spec. provider` extension is /// rejected: Core never synthesizes one and never copies a remote one. /// /// # Errors /// /// Returns [`SemanticContractError::ProjectionProviderExtensionForbidden`] - /// when the spec carries a `spec.provider` extension and + /// when the spec carries a `spec. provider` extension and /// [`SemanticContractError::SchemaViolation`] when a field name is outside /// the projection's allowed set or a required name is missing. pub fn validate_projection_spec( @@ -1118,7 +1118,7 @@ impl SemanticPairContract { Ok(()) } - /// Check the ResourceType half of a `ResourceExport.resourceRef`. + /// Check the ResourceType half of a `ResourceExport. resourceRef`. /// /// It must target the owner Service, never a `Device`, an `Endpoint`, or /// a `*Binding`. This type-only helper does not establish resource origin; @@ -1240,7 +1240,7 @@ pub(crate) mod tests_support { } /// Assert that the canonical minimal base Spec is accepted with no - /// `spec.provider`, and that it survives a strict serde and canonical + /// `spec. provider`, and that it survives a strict serde and canonical /// JSON round trip unchanged. pub(crate) fn assert_minimal_base_round_trips(member: &SemanticTypeContract, base: &str) { let contract = member @@ -1292,7 +1292,7 @@ pub(crate) mod tests_support { } /// The Provider-specific settings field each installed implementation - /// registers under `spec.provider`, and a name no implementation + /// registers under `spec. provider`, and a name no implementation /// registers at all. Every observation probes all three, so a base that /// admitted one implementation's detail - or admitted an arbitrary extra /// field for one implementation and not the other - moves a probe. @@ -1470,7 +1470,7 @@ pub(crate) mod tests_support { /// Prove the base is genuinely Provider-neutral. /// /// Two different implementations are installed in turn - each with its - /// own registered `spec.provider` / `status.provider` extension - and the + /// own registered `spec. provider` / `status. provider` extension - and the /// entire Provider-observable base surface is captured under each. The /// two observations must be equal: same schema identities, same versions, /// same frozen field sets, same base and factory fingerprints, and the @@ -1840,7 +1840,7 @@ mod tests { } } - /// Core projection rejection of `spec.provider`. + /// Core projection rejection of `spec. provider`. #[test] fn a_core_projection_rejects_a_provider_extension() { let pair = SemanticFamily::SecurityKey.contract(); @@ -2070,8 +2070,8 @@ mod tests { } } - /// Common fields only under `status.resource`; implementation observation - /// only under `status.provider`. A registered Provider extension may not + /// Common fields only under `status. resource`; implementation observation + /// only under `status. provider`. A registered Provider extension may not /// shadow a common status field. #[test] fn a_provider_status_extension_may_not_shadow_a_common_status_field() { diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs index cf45c4213..604ab8391 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs @@ -1,15 +1,15 @@ //! The shared security-key semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen security-key pair `security-key.d2bus.org.SecurityKeyService` and -//! `security-key.d2bus.org.SecurityKeyBinding`. The field sets below are the +//! frozen security-key pair `security-key. d2bus. org.SecurityKeyService` and +//! `security-key. d2bus. org.SecurityKeyBinding`. The field sets below are the //! top-level provider-neutral base fields stated by the security-key Provider //! dossier's Service and Binding spec/status contract sections. //! //! The Service base is a discriminated `mode` union declaring only semantic //! security-key authority. The physical backing selector is deliberately not a //! base field for this family: the dossier places `deviceRef` and the relay -//! Endpoint inside the implementation's strict `spec.provider` extension. +//! Endpoint inside the implementation's strict `spec. provider` extension. //! //! Consequences of that placement. Because no semantic base field names a //! backing resource, this family's closed `allowedBackingRefTypes` set is @@ -51,7 +51,7 @@ const BINDING_SPEC_REQUIRED: &[&str] = &["providerRef", "serviceRef", "target"]; const BINDING_STATUS_ALLOWED: &[&str] = &["attachment"]; /// The Core-owned projection branch permits only `providerRef` and the -/// observed mode. It rejects `spec.provider`, the physical device selector, +/// observed mode. It rejects `spec. provider`, the physical device selector, /// the authority descriptor, and every physical selector. const PROJECTION_SPEC_ALLOWED: &[&str] = &["providerRef", "mode"]; const PROJECTION_SPEC_REQUIRED: &[&str] = &["providerRef", "mode"]; @@ -91,7 +91,7 @@ mod tests { resource_envelope, }; - /// Canonical minimal base acceptance without `spec.provider`. + /// Canonical minimal base acceptance without `spec. provider`. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { assert_minimal_base_round_trips(contract().service(), r#"{"mode":"authority"}"#); @@ -148,7 +148,7 @@ mod tests { ); } - /// A Core projection rejects `spec.provider` and the authority descriptor. + /// A Core projection rejects `spec. provider` and the authority descriptor. #[test] fn a_projection_rejects_a_provider_extension_and_the_authority_descriptor() { let spec = d2b_contracts_resource::v3::resource::ResourceSpec::new( diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs index 526c61c41..9b879037a 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs @@ -1,13 +1,13 @@ //! The shared telemetry semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen telemetry pair `telemetry.d2bus.org.TelemetryService` and -//! `telemetry.d2bus.org.TelemetryBinding`. The spec field sets below are the +//! frozen telemetry pair `telemetry. d2bus. org.TelemetryService` and +//! `telemetry. d2bus. org.TelemetryBinding`. The spec field sets below are the //! "TelemetryService base spec" and "TelemetryBinding base spec" D089 tables //! of the telemetry Provider dossier. //! //! OTEL, OTLP, and backend-product choices are not base fields. They belong -//! only in an implementation's strict `spec.provider` extension. +//! only in an implementation's strict `spec. provider` extension. //! //! Interiors this catalog does not model. `signals` is the non-empty subset of //! metrics, traces, and logs. `quota` and `policy` are named as required base @@ -15,7 +15,7 @@ //! frozen member table, so this catalog freezes the top-level field only. //! //! Status field names this catalog could not determine. The dossier describes -//! `TelemetryService.status.resource` and `TelemetryBinding.status.resource` +//! `TelemetryService. status. resource` and `TelemetryBinding. status. resource` //! in prose. Only `serviceRole` and `serviceReadiness` are stated as field //! spellings; the effective signal, quota, and policy digests, the ingest and //! import readiness summaries, the producer counts, the queue and drop @@ -122,7 +122,7 @@ mod tests { r#"{"policy":{},"quota":{},"serviceRole":"authority","signals":["metrics"]}"#; const MINIMAL_BINDING: &str = r#"{"policy":{},"producerRef":"Zone/work","quota":{},"serviceRef":"telemetry.d2bus.org.TelemetryService/ingest","signals":["metrics"]}"#; - /// Canonical minimal base acceptance without `spec.provider`. + /// Canonical minimal base acceptance without `spec. provider`. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { assert_minimal_base_round_trips(contract().service(), MINIMAL_SERVICE); diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs index 360dfd947..88ef16327 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs @@ -1,7 +1,7 @@ //! The shared USB semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen USB pair `usb.d2bus.org.UsbService` and `usb.d2bus.org.UsbBinding`. +//! frozen USB pair `usb. d2bus. org.UsbService` and `usb. d2bus. org.UsbBinding`. //! The field sets below are the top-level provider-neutral base fields stated //! by the USBIP Provider dossier's owner authority, projection, and per-Guest //! Binding sections, which describe the base as carrying only generic @@ -118,7 +118,7 @@ mod tests { const MINIMAL_SERVICE: &str = r#"{"accessPolicy":{},"mode":"authority"}"#; const MINIMAL_BINDING: &str = r#"{"accessPolicy":{},"attachmentPolicy":{},"guestRef":"Guest/corp-vm","serviceRef":"usb.d2bus.org.UsbService/work-token"}"#; - /// Canonical minimal base acceptance without `spec.provider`. + /// Canonical minimal base acceptance without `spec. provider`. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { assert_minimal_base_round_trips(contract().service(), MINIMAL_SERVICE); diff --git a/packages/d2b-contracts-resource/src/v3/device.rs b/packages/d2b-contracts-resource/src/v3/device.rs index bd8dc1bc6..576ae945c 100644 --- a/packages/d2b-contracts-resource/src/v3/device.rs +++ b/packages/d2b-contracts-resource/src/v3/device.rs @@ -2,9 +2,9 @@ //! //! `Device` is the inventoried, exclusive-or-shared device arbitration //! ResourceType. `deviceClass`, `arbitration`, `maxConcurrentClaims`, and the -//! `inventory.selector` discriminated union are Layer 2 base fields; +//! `inventory. selector` discriminated union are Layer 2 base fields; //! implementation-only device configuration belongs to the Layer 3 -//! `spec.provider` envelope on the universal `ResourceSpec`. +//! `spec. provider` envelope on the universal `ResourceSpec`. //! //! No raw device path appears in the spec. A physical device is selected by a //! stable operator-defined label plus optional bounded filter fields, and the @@ -669,7 +669,7 @@ wire_deserialize!( /// The common Device-specific status resource layer. /// -/// This object is placed in universal `status.resource`; it deliberately does +/// This object is placed in universal `status. resource`; it deliberately does /// not duplicate `observedGeneration`, `phase`, `conditions`, or `update`. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] @@ -1054,7 +1054,7 @@ impl DeviceMetricOutcome { } /// Fixed Device metric labels. Zone, resource, UID, selector, and backing -/// identity never occur in this struct; `d2b.zone` and `d2b.provider` belong +/// identity never occur in this struct; `d2b. zone` and `d2b. provider` belong /// only to the OTEL resource-attribute set. #[derive(Debug, Clone, Copy, PartialEq, Eq, JsonSchema)] pub struct DeviceMetricLabels { diff --git a/packages/d2b-contracts-resource/src/v3/host.rs b/packages/d2b-contracts-resource/src/v3/host.rs index 6751ca238..299040bb9 100644 --- a/packages/d2b-contracts-resource/src/v3/host.rs +++ b/packages/d2b-contracts-resource/src/v3/host.rs @@ -1,8 +1,8 @@ //! Host primitive ResourceType base spec. //! //! `Host` is the physical or local execution, policy, and budget parent. -//! Layer 2 is this base spec; `spec.providerRef`, `spec.updatePolicy`, and -//! the Layer 3 `spec.provider` extension envelope live on the universal +//! Layer 2 is this base spec; `spec. providerRef`, `spec. updatePolicy`, and +//! the Layer 3 `spec. provider` extension envelope live on the universal //! `ResourceSpec` and are never restated here. use schemars::JsonSchema; @@ -20,13 +20,13 @@ use d2b_contracts::wire_deserialize; /// The canonical ResourceType name for this module. pub const HOST_RESOURCE_TYPE: &str = "Host"; -/// The only Provider admitted by `Host.spec.providerRef`. +/// The only Provider admitted by `Host. spec. providerRef`. pub const HOST_PROVIDER_REF: &str = "Provider/system-core"; /// The explicit no-isolation posture of the user-only Host. /// /// The posture is a promoted Host base field; it is never a -/// `spec.provider.settings` field, and `null` used to evade the +/// `spec. provider. settings` field, and `null` used to evade the /// no-isolation warning is rejected. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, diff --git a/packages/d2b-contracts-resource/src/v3/limits.rs b/packages/d2b-contracts-resource/src/v3/limits.rs index 6d7db7d70..ada48e170 100644 --- a/packages/d2b-contracts-resource/src/v3/limits.rs +++ b/packages/d2b-contracts-resource/src/v3/limits.rs @@ -1,12 +1,12 @@ //! Frozen resource API admission limits. //! //! These ceilings cap resource API admission: request envelope, response, -//! batch, and list bounds size a single admission round-trip;watch bounds cap -//! per-session and per-zone credits, filters, and queue growth;deadline bounds +//! batch, and list bounds size a single admission round-trip; watch bounds cap +//! per-session and per-zone credits, filters, and queue growth; deadline bounds //! cap request admission wait, with separate expedited and per-principal concurrency -//! ceilings;and role bounds cap role rule graphs and bindings. The `DEFAULT_` +//! ceilings; and role bounds cap role rule graphs and bindings. The `DEFAULT_` //! variants name the fallback applied when a caller omits the corresponding field. -//! Byte ceilings are raw bytes;deadline ceilings are raw milliseconds. +//! Byte ceilings are raw bytes; deadline ceilings are raw milliseconds. pub const MAX_REQUEST_CANONICAL_BYTES: usize = 512 * 1024; pub const MAX_RESPONSE_CANONICAL_BYTES: usize = 512 * 1024; diff --git a/packages/d2b-contracts-resource/src/v3/network.rs b/packages/d2b-contracts-resource/src/v3/network.rs index 41e987bbb..e348aec7a 100644 --- a/packages/d2b-contracts-resource/src/v3/network.rs +++ b/packages/d2b-contracts-resource/src/v3/network.rs @@ -4,7 +4,7 @@ //! layer-3, isolation, routing, DHCP and DNS, external-attachment, mDNS, //! net-VM, and per-execution-target attachment fields are all Layer 2 base //! fields; only genuinely implementation-only desired settings belong to the -//! Layer 3 `spec.provider` envelope on the universal `ResourceSpec`. +//! Layer 3 `spec. provider` envelope on the universal `ResourceSpec`. use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -115,7 +115,7 @@ pub const DEFAULT_HOST_BLOCKLIST: [&str; 4] = [ "192.168.0.0/16", "169.254.0.0/16", ]; -/// A validated IPv4 CIDR in `a.b.c.d/prefix` form. +/// A validated IPv4 CIDR in `a. b.c. d/prefix` form. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] pub struct Ipv4Cidr(String); diff --git a/packages/d2b-contracts-resource/src/v3/operations/seal.rs b/packages/d2b-contracts-resource/src/v3/operations/seal.rs index 7659cd083..1a21fde93 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/seal.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/seal.rs @@ -97,7 +97,7 @@ pub struct MutationSealBody { /// use SealedMutation; /// /// fn inspect(sealed: SealedMutation) { -/// let _ = sealed.body; +/// let _ = sealed. body; /// } /// ``` /// @@ -107,7 +107,7 @@ pub struct MutationSealBody { /// use SealedMutation; /// /// fn clone(sealed: SealedMutation) { -/// let _ = sealed.clone(); +/// let _ = sealed. clone(); /// } /// ``` /// @@ -155,7 +155,7 @@ pub struct MutationSealIssuer { /// use operations::seal::MutationSealAcceptor; /// /// fn clone(acceptor: MutationSealAcceptor) { -/// let _ = acceptor.clone(); +/// let _ = acceptor. clone(); /// } /// ``` pub struct MutationSealAcceptor { diff --git a/packages/d2b-contracts-resource/src/v3/resource_schema.rs b/packages/d2b-contracts-resource/src/v3/resource_schema.rs index 368c59ad1..af6595119 100644 --- a/packages/d2b-contracts-resource/src/v3/resource_schema.rs +++ b/packages/d2b-contracts-resource/src/v3/resource_schema.rs @@ -734,7 +734,7 @@ impl JsonSchema for SchemaVersion { /// /// A placement anchor is a contract-owned selector, not a Provider-defined /// field path. `Zone` resolves the containing Zone, while `ExecutionRef` -/// resolves the canonical `spec.executionRef` field to one Host or Guest. +/// resolves the canonical `spec. executionRef` field to one Host or Guest. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] @@ -742,7 +742,7 @@ impl JsonSchema for SchemaVersion { pub enum PlacementAnchor { /// Place the resource at its containing Zone. Zone, - /// Place the resource at its canonical `spec.executionRef` target. + /// Place the resource at its canonical `spec. executionRef` target. ExecutionRef, } @@ -779,7 +779,7 @@ impl PlacementAnchor { /// # Errors /// /// Returns [`ResourceSchemaError::PlacementTargetMissing`] when an - /// `ExecutionRef` anchor finds no `spec.executionRef` field, + /// `ExecutionRef` anchor finds no `spec. executionRef` field, /// [`ResourceSchemaError::PlacementTargetInvalid`] when that field is not a /// string or not a parseable reference, and /// [`ResourceSchemaError::PlacementTargetWrongType`] when it names neither @@ -910,12 +910,12 @@ impl ExtensionSchemaId { } } - /// Parse `.d2bus.org//{spec|status}`. + /// Parse `.d2bus. org//{spec|status}`. /// /// # Errors /// /// Returns [`ResourceSchemaError::InvalidSchemaId`] when the value is not - /// exactly `.d2bus.org//{spec|status}` with valid + /// exactly `.d2bus. org//{spec|status}` with valid /// provider and ResourceType names. pub fn parse(value: &str) -> Result { let (authority, remainder) = value @@ -1277,7 +1277,7 @@ impl ResourceSchemaContract { /// # Errors /// /// Returns [`ResourceSchemaError::ProviderExtensionNotMinimal`] when the - /// spec carries a `spec.provider` extension, and + /// spec carries a `spec. provider` extension, and /// [`ResourceSchemaError::UnknownField`] or /// [`ResourceSchemaError::MissingField`] for a base field-set violation. pub fn validate_minimal_base_spec( diff --git a/packages/d2b-contracts-resource/src/v3/user.rs b/packages/d2b-contracts-resource/src/v3/user.rs index f47266fd5..5fdea2616 100644 --- a/packages/d2b-contracts-resource/src/v3/user.rs +++ b/packages/d2b-contracts-resource/src/v3/user.rs @@ -2,8 +2,8 @@ //! //! `User` is the named identity that ACL principals, Process user domains, //! and Host or Guest `defaultUserRef` fields resolve. The Zone-local resource -//! name and the OS username are separate: `metadata.name` is the canonical -//! Zone-local key, and `spec.osUsername` is the actual username resolved +//! name and the OS username are separate: `metadata. name` is the canonical +//! Zone-local key, and `spec. osUsername` is the actual username resolved //! through NSS. //! //! The User base spec carries no credential material, public key, PAM diff --git a/packages/d2b-contracts-resource/src/v3/volume.rs b/packages/d2b-contracts-resource/src/v3/volume.rs index 2c21e6b02..29c6ed4d2 100644 --- a/packages/d2b-contracts-resource/src/v3/volume.rs +++ b/packages/d2b-contracts-resource/src/v3/volume.rs @@ -5,7 +5,7 @@ //! Host or Guest attachment policy that separate file, directory, ACL, and //! filesystem-view types would otherwise carry. //! -//! `source.settings` never carries a raw host path in the authored spec: the +//! `source. settings` never carries a raw host path in the authored spec: the //! `local-path` and `block-image` source kinds name an opaque bounded //! `sourcePolicyId` that resolves, only inside the Volume Provider's private //! authority, against that Provider's allowlisted root policy. Layout paths diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs index 3c42c2ddc..53fbdab53 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs @@ -591,7 +591,7 @@ wire_deserialize!( .map_err(serde::de::Error::custom) ); -/// ResourceExport lifecycle state projected into `status.resource`. +/// ResourceExport lifecycle state projected into `status. resource`. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs index c1de0e4ad..5afec63c4 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs @@ -107,7 +107,7 @@ pub enum ImportDisconnectPolicy { Teardown, } -/// ResourceImport lifecycle state projected into `status.resource`. +/// ResourceImport lifecycle state projected into `status. resource`. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs index 292555d33..3c70ad27c 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs @@ -54,14 +54,14 @@ //! a v3 peer from silently reading an old tag as a new role. //! //! Two service-package wire strings are stated by the specs and used verbatim: -//! `d2b.resource.v3` and `d2b.zone.v3`. The remaining new wire strings and +//! `d2b. resource. v3` and `d2b. zone. v3`. The remaining new wire strings and //! every new numeric tag are the minimal defensible extension of the frozen //! scheme, not a spec quotation. They are listed in the module's report as //! inferences pending explicit contract confirmation: //! `EndpointPurpose::ZoneLocal` = 14, `EndpointPurpose::ZoneControl` = 15, //! `EndpointRole::ZoneRelay` = 9, `EndpointRole::ZoneBootstrap` = 10, //! `ServicePackage::ZoneV3` = 7, `ServicePackage::ZoneLinkV3` = 8, and the -//! wire string `d2b.zonelink.v3`. +//! wire string `d2b. zonelink. v3`. //! //! # Relationship to the v2-shaped session structs //! @@ -172,7 +172,7 @@ zone_closed_enum!( EndpointPurpose { /// Lifecycle control on a Zone-local endpoint. LocalLifecycle = 1 => "local-lifecycle", - /// The `d2b.resource.v3` resource service. + /// The `d2b. resource. v3` resource service. ResourceService = 2 => "resource-service", /// An enrolled ZoneLink between a parent and a child Zone. ZoneLink = 3 => "zone-link", @@ -199,7 +199,7 @@ zone_closed_enum!( /// A Zone-local endpoint reached over an allocator-issued socket, /// never over a ZoneLink. ZoneLocal = 14 => "zone-local", - /// The `d2b.zone.v3` Zone control service. + /// The `d2b. zone. v3` Zone control service. ZoneControl = 15 => "zone-control", } ); @@ -242,7 +242,7 @@ zone_closed_enum!( /// frozen independently of the v2 assignments and are not restated by /// this module. ServicePackage { - /// `d2b.resource.v3.ResourceService`. + /// `d2b. resource. v3.ResourceService`. ResourceV3 = 1 => "d2b.resource.v3", /// The controller service package. ControllerV3 = 2 => "d2b.controller.v3", @@ -254,7 +254,7 @@ zone_closed_enum!( SupportV3 = 5 => "d2b.support.v3", /// The credential service package. CredentialV3 = 6 => "d2b.credential.v3", - /// `d2b.zone.v3.ZoneService`. + /// `d2b. zone. v3.ZoneService`. ZoneV3 = 7 => "d2b.zone.v3", /// The ZoneLink carriage service package. ZoneLinkV3 = 8 => "d2b.zonelink.v3", diff --git a/packages/d2b-contracts/src/error.rs b/packages/d2b-contracts/src/error.rs index 93c806229..e7ed13739 100644 --- a/packages/d2b-contracts/src/error.rs +++ b/packages/d2b-contracts/src/error.rs @@ -50,7 +50,7 @@ pub enum Kind { #[serde(rename = "bundle-tampered")] BundleTampered, /// A provider required by an audio or console operation is present but - /// not in a state where enforcement can proceed (e.g. expected + /// not in a state where enforcement can proceed (e. g. expected /// target-local Process absent). Operator remediation required. #[serde(rename = "provider-misconfigured")] ProviderMisconfigured, @@ -630,7 +630,7 @@ impl Error { } /// Provider required by an audio or console operation is present but - /// misconfigured (e.g. expected target-local Process absent). + /// misconfigured (e. g. expected target-local Process absent). pub fn provider_misconfigured(vm: impl Into, reason: impl Into) -> Self { Self::Audio(AudioError::ProviderMisconfigured { vm: vm.into(), @@ -755,7 +755,7 @@ impl From for Error { #[derive(Debug, Clone, PartialEq, Eq)] pub enum AudioError { /// Provider required by an audio or console operation is present but - /// misconfigured (e.g. expected target-local Process absent). + /// misconfigured (e. g. expected target-local Process absent). ProviderMisconfigured { vm: String, reason: String }, } diff --git a/packages/d2b-contracts/src/lib.rs b/packages/d2b-contracts/src/lib.rs index 357b347b1..da7f2de41 100644 --- a/packages/d2b-contracts/src/lib.rs +++ b/packages/d2b-contracts/src/lib.rs @@ -378,7 +378,7 @@ mod tests { fn encode_frame_public_sock_cap_boundary_is_exact() { // A JSON string of N chars serializes to N+2 bytes (two quotes), so // drive the encoded body length to exactly cap-1, cap, and cap+1 to - // pin the public.sock frame boundary. Removing the `> MAX_FRAME_SIZE` + // pin the public. sock frame boundary. Removing the `> MAX_FRAME_SIZE` // check would let the cap+1 case through and fail this test. let body_len = |n: usize| serde_json::to_vec(&"x".repeat(n)).expect("serialize").len(); // cap - 1 and cap fit. diff --git a/packages/d2b-contracts/src/types.rs b/packages/d2b-contracts/src/types.rs index 53ebbb10d..fa40ffdc2 100644 --- a/packages/d2b-contracts/src/types.rs +++ b/packages/d2b-contracts/src/types.rs @@ -63,7 +63,7 @@ opaque_id! { opaque_id! { /// Opaque identifier for a per-VM authorization scope. Resolved - /// against `bundle.vms[]`. The VM name string is + /// against `bundle. vms[]`. The VM name string is /// derivation-internal; the daemon should not synthesize one. VmId } diff --git a/packages/d2b-contracts/src/workload_identity.rs b/packages/d2b-contracts/src/workload_identity.rs index 7166ada9b..9594900bf 100644 --- a/packages/d2b-contracts/src/workload_identity.rs +++ b/packages/d2b-contracts/src/workload_identity.rs @@ -48,9 +48,9 @@ use crate::target::RealmTarget; /// ``` /// use d2b_contracts::workload_identity::WorkloadTarget; /// -/// let t = WorkloadTarget::parse("builder.dev.d2b").unwrap(); -/// assert_eq!(t.to_canonical(), "builder.dev.d2b"); -/// assert_eq!(t.workload.as_str(), "builder"); +/// let t = WorkloadTarget::parse("builder.dev. d2b").unwrap(); +/// assert_eq!(t. to_canonical(), "builder.dev. d2b"); +/// assert_eq!(t. workload. as_str(), "builder"); /// ``` pub type WorkloadTarget = RealmTarget; @@ -84,15 +84,15 @@ pub struct WorkloadIdentity { /// Fully-qualified canonical target address, kept pre-rendered to avoid /// repeated formatting and to make it audit-log safe. pub canonical_target: WorkloadTarget, - /// Legacy `d2b.vms.` name for workloads that exist as a classical VM + /// Legacy `d2b. vms.` name for workloads that exist as a classical VM /// entry while the realm-native model is being adopted. `None` for /// workloads declared directly inside a realm without a legacy VM entry. #[serde(default, skip_serializing_if = "Option::is_none")] pub legacy_vm_name: Option, - /// Opaque runtime kind identifier (e.g. `nixos`, `qemu-media`). + /// Opaque runtime kind identifier (e. g. `nixos`, `qemu-media`). #[serde(default, skip_serializing_if = "Option::is_none")] pub runtime_kind: Option, - /// Stable provider identifier within the realm (e.g. + /// Stable provider identifier within the realm (e. g. /// `local-cloud-hypervisor`). #[serde(default, skip_serializing_if = "Option::is_none")] pub provider_id: Option, diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 1ee8fa870..6f43f1f7b 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -424,7 +424,7 @@ pub struct ResolvedDiskInitOp { pub target_path: std::path::PathBuf, /// Pre-allocated file size in bytes. pub size_bytes: u64, - /// Unix permission bits (e.g. `0o600`). + /// Unix permission bits (e. g. `0o600`). pub mode: u32, /// Owner UID - typically the per-VM runner UID. pub owner_uid: u32, @@ -986,9 +986,9 @@ fn lookup_group_gid(name: &str) -> Option { /// on any security check failure: /// - `"symlink"` - `open` returned `ELOOP` (path is a symlink). /// - `"not-regular-file"` - `fstat` shows it is not a regular file. -/// - `"owner"` - `st_uid` ≠ `policy.required_uid` or -/// `st_gid` ≠ `policy.required_gid` (when Some). -/// - `"mode"` - low 9 bits of `st_mode` ≠ `policy.required_mode`. +/// - `"owner"` - `st_uid` ≠ `policy. required_uid` or +/// `st_gid` ≠ `policy. required_gid` (when Some). +/// - `"mode"` - low 9 bits of `st_mode` ≠ `policy. required_mode`. /// /// The read is part of the bundle-read work class the loader seat isolates: /// async consumers reach it only through @@ -1087,7 +1087,7 @@ fn verify_artifact_hash( /// /// The hash is computed over the canonical JSON of the bundle with /// `bundleHash` removed and `artifactHashes` set to null - matching what -/// `nixos-modules/bundle.nix` emits via `builtins.toJSON dataWithoutHash` +/// `nixos-modules/bundle.nix` emits via `builtins. toJSON dataWithoutHash` /// where `dataWithoutHash` has `artifactHashes = null`. /// /// For `schemaVersion "v2"` bundles a missing `bundleHash` is a hard @@ -1164,7 +1164,7 @@ fn verify_bundle_hash(path: &Path, raw_bytes: &[u8]) -> Result<(), Error> { // serde_json without `preserve_order` feature serialises objects with // BTreeMap (sorted keys) - the same lexicographic ordering that - // builtins.toJSON uses on the Nix side. + // builtins. toJSON uses on the Nix side. let canonical = serde_json::to_vec(&value).map_err(|_| Error::internal_io("bundle-hash-canonical"))?; let actual = sha256_hex(&canonical); @@ -2547,7 +2547,7 @@ impl BundleResolver { /// `Guest` is the v3 ResourceType for VMs (there is no separate `Vm` /// type); each yielded pair carries the enclosing `ZoneId` and the /// `BundleResource` whose `spec()` holds the provider identity - /// (`spec.providerRef`) plus the ExecutionPolicy base. Parsing happens + /// (`spec. providerRef`) plus the ExecutionPolicy base. Parsing happens /// on each call over the verified bytes the resolver holds; the /// `ResourceBundle::from_json` parse rejects malformed bytes. pub fn guest_vm_resources(&self) -> impl Iterator { @@ -3016,7 +3016,7 @@ impl BundleResolver { } /// Build the canonical `host-runtime.json` record from the bundle's - /// `host.if_name_mappings` rows. The broker writes this during + /// `host. if_name_mappings` rows. The broker writes this during /// `RunHostInstall` so downstream consumers read ifnames from a /// single source of truth instead of recomputing via the /// SHA-256-vs-FNV-1a dual-algorithm dance. @@ -3540,7 +3540,7 @@ fn cidr_contains_address(cidr: &str, address: &str) -> bool { /// the host-side bridge host octet 1 of the uplink CIDR while the routes' /// gateway host (host octet 2) rides the net-VM side. The derivation /// refuses a malformed uplink CIDR and any uplink whose gateway host would -/// fall outside the bridge's own subnet (e.g. a `/31` or `/32` uplink, or +/// fall outside the bridge's own subnet (e. g. a `/31` or `/32` uplink, or /// a network whose host octet cannot carry both hosts). fn uplink_bridge_cidr(uplink_cidr: &str) -> Option { let bridge = network_cidr_host_address(uplink_cidr, 1)?; @@ -5019,7 +5019,7 @@ type LoadedZoneResourceBundles = (BTreeMap>, Vec, /// TAP role for the bridge-port flag matrix. pub role: TapRole, - /// User-visible interface name as it appears in `d2b.envs.*` - /// and operator docs (e.g. `br-work-lan`). + /// User-visible interface name as it appears in `d2b. envs.*` + /// and operator docs (e. g. `br-work-lan`). pub user_visible_name: String, /// Deterministic hash-derived IFNAMSIZ-safe interface name with - /// `d2b-` prefix (e.g. `d2b-br-a1b2c3d4`). Bundle build refuses any + /// `d2b-` prefix (e. g. `d2b-br-a1b2c3d4`). Bundle build refuses any /// collision. pub derived_ifname: IfName, } diff --git a/packages/d2b-core/src/manifest_v04.rs b/packages/d2b-core/src/manifest_v04.rs index cb0bd6802..7261334a5 100644 --- a/packages/d2b-core/src/manifest_v04.rs +++ b/packages/d2b-core/src/manifest_v04.rs @@ -21,7 +21,7 @@ use std::{collections::BTreeMap, path::Path}; use crate::runtime::RuntimeMetadata; -/// Current emitted `_manifest.manifestVersion`. +/// Current emitted `_manifest. manifestVersion`. /// /// Bumped to `6` for the local runtime/provider contract. Per-VM manifest /// entries now carry runtime/provider metadata and provider capability bits, and diff --git a/packages/d2b-core/src/processes.rs b/packages/d2b-core/src/processes.rs index 4d2bfa4f4..b6e83a22d 100644 --- a/packages/d2b-core/src/processes.rs +++ b/packages/d2b-core/src/processes.rs @@ -25,7 +25,7 @@ pub struct VmProcessDag { /// Additive: present for VMs that are declared as realm workloads; /// absent (`None`) for VMs that predate realm workload declarations. /// Consumers must not treat absence as an error - it simply means the - /// VM is a classical `d2b.vms.` entry without a realm workload row. + /// VM is a classical `d2b. vms.` entry without a realm workload row. /// /// The provider/backend-specific config (vm_id, role, runner argv) is /// carried separately in the per-node `profile` and `argv` fields so @@ -138,7 +138,7 @@ pub enum ProcessNetworkInterfaceType { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ProcessMacvtapInterface { - /// Lower host interface to attach to, e.g. `eno1`. + /// Lower host interface to attach to, e. g. `eno1`. pub link: String, /// macvtap/macvlan mode passed to `ip link ... type macvtap mode`. pub mode: ProcessMacvtapMode, @@ -183,7 +183,7 @@ pub enum SpawnRunnerPlanOp { /// image when present. /// /// Used for d2b-owned raw ext4 volumes and the per-VM writable - /// store overlay disk (`store-overlay.img`). The broker validates + /// store overlay disk (`store-overlay. img`). The broker validates /// `target_path` is under `/var/lib/d2b/vms/`, creates absent /// files with `O_CREAT|O_EXCL`, pre-allocates `size_bytes` via /// `fallocate`, formats them as ext4, and sets mode + ownership. @@ -197,7 +197,7 @@ pub enum SpawnRunnerPlanOp { target_path: PathBuf, /// Pre-allocated size in bytes (broker calls `fallocate`). size_bytes: u64, - /// Unix permission bits in octal (e.g. `0o600` = 384 decimal). + /// Unix permission bits in octal (e. g. `0o600` = 384 decimal). mode: u32, /// Owner UID - typically the per-VM runner UID. owner_uid: u32, diff --git a/packages/d2b-core/src/site.rs b/packages/d2b-core/src/site.rs index a0303f094..8324a0243 100644 --- a/packages/d2b-core/src/site.rs +++ b/packages/d2b-core/src/site.rs @@ -2,7 +2,7 @@ //! //! The NixOS site module resolves the host session facts the daemon must //! never guess - today the host Wayland socket that -//! `d2b.site.waylandUser` + `d2b.site.waylandDisplay` describe - into this +//! `d2b. site. waylandUser` + `d2b. site. waylandDisplay` describe - into this //! artifact, so the trusted bundle and the runtime directory the site //! provisions cannot disagree. The artifact is optional in the bundle index: //! a bundle that predates it, or a site that declares no Wayland session, @@ -20,7 +20,7 @@ pub struct SiteJson { /// Artifact schema version (currently `"v1"`). pub schema_version: String, /// Absolute host Wayland socket (`/run/user//`), or `null` - /// when the site declares no Wayland session (`d2b.site.waylandUser` is + /// when the site declares no Wayland session (`d2b. site. waylandUser` is /// unset). Optional so bundles that predate the field still parse. #[serde(default, skip_serializing_if = "Option::is_none")] pub wayland_socket: Option, @@ -65,7 +65,7 @@ impl std::fmt::Display for SiteValidationError { /// The one accepted shape: exactly `/run/user//` with no parent /// components - the value the Nix emitter resolves from -/// `d2b.site.waylandUser`'s uid and `d2b.site.waylandDisplay`. +/// `d2b. site. waylandUser`'s uid and `d2b. site. waylandDisplay`. fn wayland_socket_ok(socket: &str) -> bool { let mut components = std::path::Path::new(socket).components(); matches!(components.next(), Some(Component::RootDir)) diff --git a/packages/d2b-core/src/static_invariants.rs b/packages/d2b-core/src/static_invariants.rs index 3ab4a02d0..4c490a7ef 100644 --- a/packages/d2b-core/src/static_invariants.rs +++ b/packages/d2b-core/src/static_invariants.rs @@ -50,7 +50,7 @@ pub const PUBLIC_MANIFEST_FIELDS: &[&str] = &[ "usbipdHostIp", "securityKey", "observability", - // `observability.enabled` (public-safe boolean) is nested under the per-VM + // `observability. enabled` (public-safe boolean) is nested under the per-VM // `observability` object in the current manifest; the bash allowlist // predated this field. The path-bearing key/secret invariant separately // guards the observability block against host-path leaks. @@ -264,7 +264,7 @@ mod tests { /// Negative fixture from `tests/static-invariant-opaque-key-ids.sh`: /// path-bearing key suffixes with host-path values must be reported as - /// `dotted.path=value`. + /// `dotted. path=value`. #[test] fn path_bearing_key_rejects_host_paths() { let manifest = json!({ diff --git a/packages/d2b-host/src/bin/d2b-activation-helper.rs b/packages/d2b-host/src/bin/d2b-activation-helper.rs index 7db38f580..56a8a1091 100644 --- a/packages/d2b-host/src/bin/d2b-activation-helper.rs +++ b/packages/d2b-host/src/bin/d2b-activation-helper.rs @@ -514,7 +514,7 @@ fn cmd_enforce_dir_posture(args: &Args) -> ExitCode { /// already holds, so the setxattr cannot be redirected to a /// different path and the target fd is not inherited by setfacl. The /// `--setfacl-bin` flag pins the setfacl binary (typically -/// `${pkgs.acl}/bin/setfacl`) so $PATH is not consulted. +/// `${pkgs. acl}/bin/setfacl`) so $PATH is not consulted. // CLI-only verb: synchronous `setfacl` status wait at the // activation-helper entry point, never on an executor worker shared // with other tasks. diff --git a/packages/d2b-host/src/bridge_port.rs b/packages/d2b-host/src/bridge_port.rs index 6ec7e978a..b9703dca2 100644 --- a/packages/d2b-host/src/bridge_port.rs +++ b/packages/d2b-host/src/bridge_port.rs @@ -2,7 +2,7 @@ //! //! Implements the per-role bridge port flag defaults table plus the //! validators that gate east-west bridges behind the -//! `env.lan.allowEastWest` + `site.allowUnsafeEastWest` double opt-in. +//! `env. lan. allowEastWest` + `site. allowUnsafeEastWest` double opt-in. //! //! The complete flag set this module covers (every flag, every role): //! `isolated`, `hairpin_mode`, `learning`, `unicast_flood`, @@ -167,9 +167,9 @@ pub fn validate_readback( /// Double opt-in policy for east-west bridges. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct EastWestPolicy { - /// Env-level toggle: `d2b.envs..lan.allowEastWest`. + /// Env-level toggle: `d2b. envs..lan. allowEastWest`. pub env_allow_east_west: bool, - /// Site-level toggle: `d2b.site.allowUnsafeEastWest`. + /// Site-level toggle: `d2b. site. allowUnsafeEastWest`. pub site_allow_unsafe_east_west: bool, } @@ -177,7 +177,7 @@ pub struct EastWestPolicy { #[derive(Debug, Clone, PartialEq, Eq)] pub enum BridgePortPolicyError { /// The bundle requested `WorkloadLanEastWest` but the env did not - /// set `lan.allowEastWest = true`. + /// set `lan. allowEastWest = true`. EastWestRequiresEnvOptIn, /// The bundle requested `WorkloadLanEastWest` and the env opted in /// but the site did not set `allowUnsafeEastWest = true`. diff --git a/packages/d2b-host/src/cgroup.rs b/packages/d2b-host/src/cgroup.rs index 9e53a11b8..11432bc87 100644 --- a/packages/d2b-host/src/cgroup.rs +++ b/packages/d2b-host/src/cgroup.rs @@ -6,22 +6,22 @@ //! //! ## Invariants enforced here //! -//! 1. The unified hierarchy must be present (`/sys/fs/cgroup/cgroup.controllers`). +//! 1. The unified hierarchy must be present (`/sys/fs/cgroup/cgroup. controllers`). //! 2. The required controller set `{cpu, memory, io, pids, cpuset}` must be //! advertised on the root before any subtree is created. -//! 3. Before enabling `+cpuset`, an ancestor with an empty `cpuset.cpus` or -//! `cpuset.mems` inherits from `cpuset.cpus.effective` / `cpuset.mems.effective`. -//! 4. `cgroup.subtree_control` is rewritten in the strict order +//! 3. Before enabling `+cpuset`, an ancestor with an empty `cpuset. cpus` or +//! `cpuset. mems` inherits from `cpuset. cpus. effective` / `cpuset. mems. effective`. +//! 4. `cgroup. subtree_control` is rewritten in the strict order //! `+cpu, +memory, +io, +pids, +cpuset` with a re-read verification after //! each individual enable. -//! 5. `cpuset.cpus.partition` STAYS `member`. A debug assertion blows up if +//! 5. `cpuset. cpus. partition` STAYS `member`. A debug assertion blows up if //! any caller passes the partition-root key into the writer; releases //! fail closed by returning [`CgroupError::CgroupPartitionRootForbidden`]. -//! 6. Threaded cgroups are forbidden - `cgroup.type=threaded` is refused. -//! 7. `d2b.slice` and intermediate Zone/Guest cgroup directories must +//! 6. Threaded cgroups are forbidden - `cgroup. type=threaded` is refused. +//! 7. `d2b. slice` and intermediate Zone/Guest cgroup directories must //! be process-free; only leaf role cgroups carry processes. -//! 8. `cgroup.kill` is allowed only on broker/daemon-owned VM or role leaves; -//! ancestor `cgroup.kill` is refused with +//! 8. `cgroup. kill` is allowed only on broker/daemon-owned VM or role leaves; +//! ancestor `cgroup. kill` is refused with //! [`CgroupError::CgroupKillOnAncestorRefused`]. //! 9. The delegation must NOT be performed while running as uid 0; the //! broker is the only root-effective component, and even it walks this @@ -69,7 +69,7 @@ impl Controller { Controller::Cpuset, ]; - /// The cgroup v2 controller name as written in `cgroup.controllers`. + /// The cgroup v2 controller name as written in `cgroup. controllers`. pub fn as_str(&self) -> &'static str { match self { Controller::Cpu => "cpu", @@ -104,7 +104,7 @@ impl fmt::Display for Controller { } } -/// Snapshot of the controllers advertised on a cgroup's `cgroup.controllers` +/// Snapshot of the controllers advertised on a cgroup's `cgroup. controllers` /// file at the moment of probing. #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnabledControllers { @@ -141,24 +141,24 @@ impl EnabledControllers { /// into the broker audit record `error_kind` field. #[derive(Debug, Clone, PartialEq, Eq)] pub enum CgroupError { - /// Unified hierarchy probe failed - `/sys/fs/cgroup/cgroup.controllers` + /// Unified hierarchy probe failed - `/sys/fs/cgroup/cgroup. controllers` /// is missing or unreadable. CLI exit code 1; matches plan-named /// `cgroup-v2-unified-not-present`. CgroupV2UnifiedNotPresent { detail: String }, - /// One or more required controllers are absent from `cgroup.controllers` + /// One or more required controllers are absent from `cgroup. controllers` /// on the delegation root. Matches plan-named `cgroup-controllers-missing`. CgroupControllersMissing { missing: Vec }, /// Delegation was attempted while running as uid 0 (or the host cannot /// support non-root delegation). Matches plan-named /// `cgroup-delegation-refused`. CgroupDelegationRefused { detail: String }, - /// `cgroup.kill` was attempted on an ancestor (e.g. `d2b.slice` + /// `cgroup. kill` was attempted on an ancestor (e. g. `d2b. slice` /// or an intermediate VM cgroup). Matches plan-named /// `cgroup-kill-on-ancestor-refused`. CgroupKillOnAncestorRefused { path: PathBuf }, /// cpuset inheritance could not produce non-empty `.effective` files. CpusetInheritanceFailed { path: PathBuf, detail: String }, - /// `d2b.slice` or an intermediate VM cgroup contained running + /// `d2b. slice` or an intermediate VM cgroup contained running /// processes when the no-internal-process invariant was checked. CgroupInternalProcessesPresent { path: PathBuf, pids: Vec }, /// Subtree-control verification failed after a write - the re-read @@ -169,12 +169,12 @@ pub enum CgroupError { }, /// Threaded cgroup encountered - forbidden. ThreadedCgroupForbidden { path: PathBuf }, - /// Attempt to write `cpuset.cpus.partition` (partition roots are - /// forbidden; ancestors and `d2b.slice` stay `member`). + /// Attempt to write `cpuset. cpus. partition` (partition roots are + /// forbidden; ancestors and `d2b. slice` stay `member`). CgroupPartitionRootForbidden { path: PathBuf }, /// Subtree-control write on `parent` enabled `controller` (the - /// re-read of `parent/cgroup.subtree_control` confirmed it) but the - /// child cgroup's `cgroup.controllers` does not advertise the + /// re-read of `parent/cgroup. subtree_control` confirmed it) but the + /// child cgroup's `cgroup. controllers` does not advertise the /// controller. The delegation must fail closed before chown. CgroupControllerNotExposedToChild { controller: Controller, @@ -286,7 +286,7 @@ impl fmt::Display for CgroupError { impl std::error::Error for CgroupError {} /// Default unified hierarchy mount point. The probe target is -/// `/cgroup.controllers`. +/// `/cgroup. controllers`. pub const UNIFIED_HIERARCHY_ROOT: &str = "/sys/fs/cgroup"; /// Canonical d2b slice name under the unified hierarchy. pub const D2B_SLICE_NAME: &str = "d2b.slice"; @@ -311,7 +311,7 @@ pub trait CgroupBackend { fn mkdir(&self, path: &Path) -> Result<(), CgroupError>; fn fchown(&self, path: &Path, uid: u32, gid: u32) -> Result<(), CgroupError>; - /// Returns the PIDs currently inside `cgroup.procs` for the given + /// Returns the PIDs currently inside `cgroup. procs` for the given /// cgroup directory. fn read_procs(&self, dir: &Path) -> Result, CgroupError>; } @@ -371,8 +371,8 @@ fn read_trimmed(backend: &B, path: &Path) -> Result( backend: &B, path: &Path, @@ -424,11 +424,11 @@ pub fn prepare_cpuset_inheritance( Ok(()) } -/// Step 3: enable controllers in `cgroup.subtree_control` in the strict +/// Step 3: enable controllers in `cgroup. subtree_control` in the strict /// order, verifying re-read after each individual enable. When `child` -/// is `Some`, the child cgroup's `cgroup.controllers` file is also +/// is `Some`, the child cgroup's `cgroup. controllers` file is also /// re-read after each enable ("Each enable is verified by re-reading -/// cgroup.subtree_control AND cgroup.controllers on the child"). +/// cgroup. subtree_control AND cgroup. controllers on the child"). pub fn enable_subtree_controllers( backend: &B, path: &Path, @@ -438,7 +438,7 @@ pub fn enable_subtree_controllers( } /// Variant of [`enable_subtree_controllers`] that additionally verifies -/// the child cgroup's `cgroup.controllers` advertises the just-enabled +/// the child cgroup's `cgroup. controllers` advertises the just-enabled /// controller. Fail-closed with /// [`CgroupError::CgroupControllerNotExposedToChild`]. pub fn enable_subtree_controllers_with_child( @@ -485,7 +485,7 @@ pub fn enable_subtree_controllers_with_child( } /// Step 4 enforcement helper: the algorithm NEVER writes -/// `cpuset.cpus.partition`. Any code path that tries to is treated as a +/// `cpuset. cpus. partition`. Any code path that tries to is treated as a /// programmer bug - a `debug_assert!` blows up in development builds, /// and release builds return [`CgroupError::CgroupPartitionRootForbidden`]. pub fn assert_partition_member_only(path: &Path, key: &str) -> Result<(), CgroupError> { @@ -517,7 +517,7 @@ pub fn assert_not_threaded(backend: &B, path: &Path) -> Result Ok(()) } -/// Step 5: assert `cgroup.procs` is empty on an intermediate (non-leaf) +/// Step 5: assert `cgroup. procs` is empty on an intermediate (non-leaf) /// cgroup. Returns [`CgroupError::CgroupInternalProcessesPresent`] /// listing the offending pids when not. pub fn assert_no_internal_processes( @@ -534,7 +534,7 @@ pub fn assert_no_internal_processes( Ok(()) } -/// Step 7: `cgroup.kill` is allowed only on a leaf. The caller passes +/// Step 7: `cgroup. kill` is allowed only on a leaf. The caller passes /// the cgroup directory and the leaves it is permitted to kill; any /// path not in the leaf set is refused. pub fn cgroup_kill_leaf_only( @@ -581,7 +581,7 @@ pub fn chown_subtree_to_d2bd( } /// v1.1.1 per-VM-interior + per-role-leaf taxonomy. Creates the -/// process-free intermediate directory `d2b.slice//` +/// process-free intermediate directory `d2b. slice//` /// (NOT a leaf). Per-role leaf cgroups are created by /// the per-role leaf helper. Per ADR 0011 Decision item 1. pub fn create_vm_subtree( @@ -932,7 +932,7 @@ pub mod fake { .unwrap_or_default(), )?; let mut inner = self.inner.lock().unwrap(); - // `cgroup.kill` is intercepted separately so the kill scope + // `cgroup. kill` is intercepted separately so the kill scope // can be audited from tests. if path .file_name() @@ -1183,7 +1183,7 @@ mod tests { fn child_controllers_verified_after_subtree_enable() { // Drive the new verifying variant directly to assert the // child-controllers re-read is load-bearing: if the fake - // backend's child `cgroup.controllers` is *blank* the call + // backend's child `cgroup. controllers` is *blank* the call // fail-closes with `cgroup-controller-not-exposed-to-child`. let backend = fresh(d2bd_uid()); let root = Path::new(FAKE_ROOT); diff --git a/packages/d2b-host/src/devices.rs b/packages/d2b-host/src/devices.rs index 4c8646d6b..5ac0d44a4 100644 --- a/packages/d2b-host/src/devices.rs +++ b/packages/d2b-host/src/devices.rs @@ -85,7 +85,7 @@ pub struct DeviceNodeEntry { pub class: DeviceClass, pub path: PathBuf, pub kind: DeviceNodeKind, - /// Required POSIX mode bits (e.g. `0o660`). Validation requires an + /// Required POSIX mode bits (e. g. `0o660`). Validation requires an /// exact `0o7777` match (permission plus special bits). pub mode_required: u32, /// Required POSIX group name (UNIX group ownership), matched via @@ -217,7 +217,7 @@ pub enum DeviceValidation { MissingOptional, /// Required path is absent; broker cannot open the fd. MissingRequired, - /// Path exists but is the wrong kind (e.g. file instead of char + /// Path exists but is the wrong kind (e. g. file instead of char /// device). WrongKind, /// POSIX mode bits do not exactly match the required mask. diff --git a/packages/d2b-host/src/hardlink_farm.rs b/packages/d2b-host/src/hardlink_farm.rs index a2f17af9c..4b19c3497 100644 --- a/packages/d2b-host/src/hardlink_farm.rs +++ b/packages/d2b-host/src/hardlink_farm.rs @@ -27,7 +27,7 @@ //! live/.d2b-marker- # zero-length readiness marker //! meta/ # guest read-only share root //! current -> generations/ -//! generations//{store-paths,db.dump,meta.json} +//! generations//{store-paths,db. dump,meta.json} //! state/ # host-only broker state //! current -> generations/ //! generations//{system,marker.json,meta.json} @@ -100,7 +100,7 @@ pub enum HardlinkFarmError { b_dev: u64, }, /// `link(2)` returned `EXDEV` even though source and destination - /// share the same `st_dev` - i.e. they are on the same underlying + /// share the same `st_dev` - i. e. they are on the same underlying /// filesystem but in different *vfsmounts* (the canonical case is /// NixOS bind-mounting `/nix/store` read-only on top of itself). /// Unlike [`HardlinkFarmError::DifferentFilesystem`] this is RECOVERABLE: building the @@ -728,7 +728,7 @@ pub async fn write_generation_marker( // here (it has no on-disk backing) but ext4 / xfs / btrfs need // this for full crash safety. Best-effort: errors are // non-fatal - the marker file itself is already on disk via - // the f.sync_all() above. + // the f. sync_all() above. if let Ok(dir) = tokio::fs::File::open(generation_dir).await { let _ = dir.sync_all().await; } @@ -853,7 +853,7 @@ pub async fn build_farm( /// Shared by the legacy [`build_farm`] and the split-layout /// [`build_store_view`]. Top-level paths already present in `live/` are /// skipped (the flat pool is shared across retained generations); the -/// rest are hardlinked into a private `live.stage..` sibling +/// rest are hardlinked into a private `live. stage..` sibling /// and atomically renamed into `live/`. `store_root` and `live/` must /// already exist and share one filesystem (the caller asserts this). /// Returns the top-level link/skip accounting. @@ -985,7 +985,7 @@ async fn fsync_tree_bottom_up(path: &Path) -> Result<(), HardlinkFarmError> { /// /// `generation_id` is the collision-free on-disk key (see /// [`generation_id`]). This function does NOT swap the `state/current` or -/// `meta/current` pointers, copy `db.dump`, or plant the live readiness +/// `meta/current` pointers, copy `db. dump`, or plant the live readiness /// marker: those are the in-process "publish" steps the caller performs /// after a successful (possibly cross-mount-retried) materialisation, in /// the ADR-mandated order (state/current, then meta/current, then the @@ -1044,7 +1044,7 @@ pub async fn build_store_view( let counts = link_closures_into_live(store_root, generation_id, closure_paths).await?; // Guest-served metadata (`meta/generations//`): store-paths + - // guest-safe meta.json only. db.dump is copied in by the caller + // guest-safe meta.json only. db. dump is copied in by the caller // before the meta/current swap. let meta_gen = meta_generation_dir(store_root, generation_id); tokio::fs::create_dir_all(&meta_gen) @@ -1121,10 +1121,10 @@ async fn plant_generation_gcroot( Ok(()) } -/// Copy the closure-scoped Nix DB dump into `meta/generations//db.dump`. +/// Copy the closure-scoped Nix DB dump into `meta/generations//db. dump`. /// In-process (a byte copy, cross-mount-safe). tmp+rename for crash /// safety. Must complete before the `meta/current` swap so the guest -/// never observes a current generation without its `db.dump`. +/// never observes a current generation without its `db. dump`. pub async fn write_meta_db_dump( store_root: &Path, generation_id: &str, @@ -1707,7 +1707,7 @@ pub async fn read_meta_current_id(store_root: &Path) -> Option { read_current_pointer_id(&meta_dir(store_root)).await } -/// Remove stale `current.tmp` files left under `state/` and `meta/` by a +/// Remove stale `current. tmp` files left under `state/` and `meta/` by a /// previous publish that crashed between symlink-write and rename. /// Idempotent. pub async fn reconcile_split_current_tmp(store_root: &Path) -> Result<(), HardlinkFarmError> { diff --git a/packages/d2b-host/src/host_prep_dag.rs b/packages/d2b-host/src/host_prep_dag.rs index cd834c555..52272048f 100644 --- a/packages/d2b-host/src/host_prep_dag.rs +++ b/packages/d2b-host/src/host_prep_dag.rs @@ -151,7 +151,7 @@ pub enum HostPrepStepKind { /// tap creation so NetworkManager doesn't race the broker's /// `TUNSETIFF` + immediate `dev set master` and pull the link /// down between create + attach. Replaces the - /// `NetworkManager.conf.d/00-d2b-unmanaged.conf` materializer + /// `NetworkManager.conf. d/00-d2b-unmanaged.conf` materializer /// leaf of `microvm-setup@.service`. ApplyNmUnmanaged, /// Apply the per-VM sysctl set (RP filter, forwarding, MSS clamp @@ -161,7 +161,7 @@ pub enum HostPrepStepKind { /// SetBridgePortFlags. Replaces the sysctl-apply leaf of /// `microvm-setup@.service`. ApplySysctl, - /// Set bridge-port flags on the tap (e.g. `learning off`, + /// Set bridge-port flags on the tap (e. g. `learning off`, /// `flood off`, `mcast_to_unicast off`) after tap attach. /// Replaces the `bridge link set` leaf of /// `microvm-tap-interfaces@.service`. Must run AFTER @@ -227,7 +227,7 @@ impl HostPrepStepKind { #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct BundleStepRef { /// Opaque VM id this step targets (resolved against - /// `bundle.vms[]`). + /// `bundle. vms[]`). pub vm_id: VmId, /// Optional authorization scope (env / VM). Present for steps /// that scope to an env (`ApplyNftablesRules` uses @@ -235,10 +235,10 @@ pub struct BundleStepRef { #[serde(default, skip_serializing_if = "Option::is_none")] pub scope_id: Option, /// Optional opaque intent reference for steps that look up a - /// specific bundle intent row (e.g. `nft:env:` for + /// specific bundle intent row (e. g. `nft:env:` for /// `ApplyNftablesRules`, `runner:vm::role:` for tap /// ownership derivation). `None` for steps whose entire - /// payload is derived from `vm_id` alone (e.g. + /// payload is derived from `vm_id` alone (e. g. /// `SshHostKeyPreflight`). #[serde(default, skip_serializing_if = "Option::is_none")] pub bundle_op_id: Option, @@ -306,7 +306,7 @@ impl std::error::Error for CycleError {} /// `PreOpenVhostNetFd`). /// - `runner_role_id` names the runner intent role for the tap step. /// -/// Net VMs (Guest resource `spec.netVm` flag) additionally emit +/// Net VMs (Guest resource `spec. netVm` flag) additionally emit /// `SeedDnsmasqLease`. /// /// Steps unrelated to the VM's optional sidecars (obs / usbip / @@ -333,7 +333,7 @@ pub fn build_host_prep_dag( return Vec::new(); }; let spec = resource.spec(); - // Best-effort env: top-level `spec.env`, else `spec.executionPolicy.env`. + // Best-effort env: top-level `spec. env`, else `spec. executionPolicy. env`. let env = match spec.get("env") { Some(CanonicalJsonValue::String(env)) => Some(env.as_str()), _ => spec diff --git a/packages/d2b-host/src/modules.rs b/packages/d2b-host/src/modules.rs index 993cf9772..1aa4abe57 100644 --- a/packages/d2b-host/src/modules.rs +++ b/packages/d2b-host/src/modules.rs @@ -6,9 +6,9 @@ //! module that is neither built-in nor loaded forces a closed-fail //! `host-modules-locked` finding. //! 2. `/proc/modules` + `/sys/module//` - loaded-module detection. -//! 3. `/lib/modules/$(uname -r)/modules.builtin` (preferred) or -//! `modules.builtin.bin` - built-in detection. -//! 4. `/boot/config-$(uname -r)` or `/proc/config.gz` - secondary +//! 3. `/lib/modules/$(uname -r)/modules. builtin` (preferred) or +//! `modules. builtin. bin` - built-in detection. +//! 4. `/boot/config-$(uname -r)` or `/proc/config. gz` - secondary //! `CONFIG_*` evidence only. //! //! `br_netfilter` post-step-2 detection drives the @@ -61,9 +61,9 @@ pub struct BuiltinModuleSet { } impl BuiltinModuleSet { - /// Parses `modules.builtin`: one relative path per line; the - /// module name is the basename minus the `.ko` (or `.ko.xz`, - /// `.ko.zst`) suffix. + /// Parses `modules. builtin`: one relative path per line; the + /// module name is the basename minus the `.ko` (or `.ko. xz`, + /// `.ko. zst`) suffix. pub fn parse_modules_builtin(contents: &str) -> Self { let mut names = BTreeSet::new(); for line in contents.lines() { @@ -87,16 +87,16 @@ impl BuiltinModuleSet { Self { names } } - /// Parses the in-kernel `modules.builtin.bin` format (the binary - /// sibling of `modules.builtin`). The file is a concatenation of + /// Parses the in-kernel `modules. builtin. bin` format (the binary + /// sibling of `modules. builtin`). The file is a concatenation of /// null-terminated records `=\0`; per-module records /// share a `.=` shape with the module /// path acting as the prefix before the first `.` in the key. - /// Older kernels (depmod ≤ 5.x without `--symbol-prefix`) store + /// Older kernels (depmod ≤ 5. x without `--symbol-prefix`) store /// just `\0` records; we accept both. /// /// We extract the unique set of module relpaths (anything ending - /// in `.ko`, `.ko.xz`, `.ko.zst`, or `.ko.gz`) and reuse the + /// in `.ko`, `.ko. xz`, `.ko. zst`, or `.ko. gz`) and reuse the /// basename stemming pass from [`Self::parse_modules_builtin`]. pub fn parse_modules_builtin_bin(bytes: &[u8]) -> Self { let mut names = BTreeSet::new(); @@ -114,7 +114,7 @@ impl BuiltinModuleSet { let key = lhs.rsplit('/').next().unwrap_or(lhs); let candidate = key.split('.').next().unwrap_or(key); // Also handle the legacy `` (no `.info`) form by - // running the modules.builtin-style stemming pass on the + // running the modules. builtin-style stemming pass on the // whole record. let stems = [ candidate, @@ -215,9 +215,9 @@ pub fn read_loaded_modules_at(proc_modules: &Path, sys_module_dir: &Path) -> Loa set } -/// Reads `/lib/modules/$(uname -r)/modules.builtin`. Returns an empty +/// Reads `/lib/modules/$(uname -r)/modules. builtin`. Returns an empty /// set on failure; the production probe order falls back to -/// `modules.builtin.bin` via [`read_builtin_modules_with_fallback`] +/// `modules. builtin. bin` via [`read_builtin_modules_with_fallback`] /// in step 3. pub fn read_builtin_modules() -> BuiltinModuleSet { let release = uname_release().unwrap_or_default(); @@ -225,8 +225,8 @@ pub fn read_builtin_modules() -> BuiltinModuleSet { read_builtin_modules_at(&primary) } -/// Two-stage builtin probe: prefers `modules.builtin` (text), falls -/// back to `modules.builtin.bin` (in-kernel format) when the text +/// Two-stage builtin probe: prefers `modules. builtin` (text), falls +/// back to `modules. builtin. bin` (in-kernel format) when the text /// variant is missing or unparseable. Returns the union of both if /// both parse successfully. pub fn read_builtin_modules_with_fallback() -> BuiltinModuleSet { @@ -262,7 +262,7 @@ pub fn read_builtin_modules_with_fallback_at(primary: &Path, fallback: &Path) -> } /// Reads the host kernel config. Tries `/boot/config-$(uname -r)` -/// first; falls back to `/proc/config.gz` in step 4. Kernel config is treated +/// first; falls back to `/proc/config. gz` in step 4. Kernel config is treated /// as **secondary** evidence; failure returns `None` and the /// loaded+builtin path drives the decision. pub fn read_kernel_config() -> Option { @@ -281,7 +281,7 @@ pub fn read_kernel_config_at(path: &Path) -> Option { } /// Two-stage kernel-config probe: prefers `` (uncompressed), -/// falls back to a `` gzip-encoded blob (`/proc/config.gz`). +/// falls back to a `` gzip-encoded blob (`/proc/config. gz`). /// Returns `None` only if neither source yields a parseable config. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn read_kernel_config_with_fallback_at( @@ -298,7 +298,7 @@ pub fn read_kernel_config_with_fallback_at( } /// Minimal RFC 1952 gzip → DEFLATE → text decoder used by the -/// `/proc/config.gz` fallback. Strips the gzip header (magic + +/// `/proc/config. gz` fallback. Strips the gzip header (magic + /// optional FEXTRA / FNAME / FCOMMENT) and the trailing 8-byte /// CRC32 + ISIZE, then hands the raw DEFLATE stream to /// `miniz_oxide`. Pure: callers feed a `&[u8]` so the test path @@ -434,8 +434,8 @@ pub struct ProbeInputs { } /// Real-host wrapper around [`probe_with`]. Reads `/proc` + `/sys` -/// plus the modules.builtin two-stage probe (text first, then -/// `modules.builtin.bin`). +/// plus the modules. builtin two-stage probe (text first, then +/// `modules. builtin. bin`). pub fn probe(kmodules: &[KernelModuleEntry]) -> ModuleProbeResult { probe_with( kmodules, diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index d94ca7b31..e862e0db2 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -206,14 +206,14 @@ pub struct NftChain { pub priority: i32, pub policy: ChainPolicy, /// Rules in order. The reconcile contract requires specific - /// carve-outs (e.g. USBIP per-busid) to be inserted BEFORE the + /// carve-outs (e. g. USBIP per-busid) to be inserted BEFORE the /// generic allow/drop rules - [`NftBatch::add_usbip_carveout`] /// enforces this invariant. pub rules: Vec, } /// A single nft rule. The `expr` field is the rendered nft expression -/// (e.g. `"ip saddr 10.10.0.5 accept"`); `comment` carries the +/// (e. g. `"ip saddr 10.10.0.5 accept"`); `comment` carries the /// mandatory `d2b managed: ` marker. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct NftRule { @@ -858,7 +858,7 @@ pub fn assert_no_forbidden_hooks(batch: &NftBatch) -> Result<(), NftError> { } // The enum has no raw/mangle/nat variant, so a hook that // round-trips through it can never be one of those - but we - // also defend against a buggy chain.name suggesting otherwise. + // also defend against a buggy chain. name suggesting otherwise. let lname = chain.name.to_ascii_lowercase(); if lname == "raw" || lname == "mangle" || lname == "nat" { return Err(NftError::ForeignNftRuleShadowsD2b { @@ -897,7 +897,7 @@ pub mod fake { Self::default() } - /// Seed a foreign rule (e.g. an iptables-nft generated table) + /// Seed a foreign rule (e. g. an iptables-nft generated table) /// the reconcile path MUST preserve. pub fn seed_foreign(&self, rule: impl Into) { self.foreign.borrow_mut().push(rule.into()); diff --git a/packages/d2b-host/src/ownership_matrix.rs b/packages/d2b-host/src/ownership_matrix.rs index 7f784b05e..a790a1c1d 100644 --- a/packages/d2b-host/src/ownership_matrix.rs +++ b/packages/d2b-host/src/ownership_matrix.rs @@ -180,7 +180,7 @@ impl OwnershipMismatch { /// Per-VM hardlink-pool paths the enforcer NEVER recurses into. /// -/// Each string is compared byte-for-byte against `entry.path`. Covers +/// Each string is compared byte-for-byte against `entry. path`. Covers /// the canonical `store-view/live` pool and the legacy `store` farm; /// both share inodes with /nix/store, so recursing would risk /// propagating ownership/ACL changes into the system store. diff --git a/packages/d2b-provider-activation-nixos/src/driver.rs b/packages/d2b-provider-activation-nixos/src/driver.rs index 3b36c9c59..cb0e59012 100644 --- a/packages/d2b-provider-activation-nixos/src/driver.rs +++ b/packages/d2b-provider-activation-nixos/src/driver.rs @@ -20,7 +20,7 @@ //! //! Conversion mapping (spec section 13): //! - `describe` -> [`ActivationDriverFactory`] registration under -//! `activation-nixos.d2bus.org.NixosGeneration`. +//! `activation-nixos. d2bus. org.NixosGeneration`. //! - `validate_spec` -> [`ResourceDriver::validate`]. //! - `observe` -> [`ResourceDriver::recover`] (rejoin the owned runner). //! - `plan`/`reconcile`/`execute_effect` -> [`ResourceDriver::reconcile`]. @@ -28,7 +28,7 @@ //! durable deleting mark is the manager's (R10), so the old finalizer //! dance is not part of the new plane; the owned runner retires first //! (F3). -//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). //! //! Three preserved behaviors do not map onto one resource's context and are //! reported rather than invented: @@ -44,7 +44,7 @@ //! ever fabricated; the projection stays non-terminal until the //! child-status surface exists. //! 3. The typed activation status projection is in-memory (R11); its -//! durable `status.resource.activationDetail` publication belongs to the +//! durable `status. resource. activationDetail` publication belongs to the //! manager view model, not this driver. #![allow(dead_code)] @@ -890,7 +890,7 @@ impl ResourceDriver for ActivationDriver { /// The execution domains the NixosGeneration type can be reconciled in. /// /// Derived from the placement contract: `NixosGeneration` names the canonical -/// `spec.executionRef` anchor (`PlacementAnchor::canonical_for` resolves +/// `spec. executionRef` anchor (`PlacementAnchor::canonical_for` resolves /// `ExecutionRef`), and the spec constructor admits a `Host` or a `Guest` /// there, so a generation row is driven in either domain. const ACTIVATION_EXECUTION_DOMAINS: &[&str] = &["host", "guest"]; @@ -907,7 +907,7 @@ const ACTIVATION_READS: &[WellKnownType] = &[WellKnownType::NIXOS_GENERATION]; /// `NixosGeneration` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane /// cannot serve the activation generations without it, so it must be /// registered before the plane opens. The type is not exportable: -/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a /// generation can never be an export subject. The driver serves no broker /// operations and declares the one child creation it performs - the owned /// activation runner ([`ACTIVATION_RUNNER_CREATION`]) - and the family's diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs index 81cea1165..cd4d77cd3 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs @@ -36,7 +36,7 @@ pub enum HostClipboardEvent { /// the policy allowlist. `has_secret` indicates a password-manager hint. /// Call [`DataControlOffer::receive`] (then flush + drop write end) to get /// the data. `offer` is `None` when the selection has no allowed MIME - /// types (i.e. the content cannot be pasted). + /// types (i. e. the content cannot be pasted). SelectionChanged { offer: Option, allowed_mimes: Vec, diff --git a/packages/d2b-provider-clipboard-wayland/src/picker.rs b/packages/d2b-provider-clipboard-wayland/src/picker.rs index 76f624f0b..0d525c88d 100644 --- a/packages/d2b-provider-clipboard-wayland/src/picker.rs +++ b/packages/d2b-provider-clipboard-wayland/src/picker.rs @@ -154,7 +154,7 @@ impl EntryDigest { } } - /// Wrap a digest freshly minted for an entry;the prefix is guaranteed by construction. + /// Wrap a digest freshly minted for an entry; the prefix is guaranteed by construction. pub(crate) fn from_sha256_hex(value: String) -> Self { Self(value) } diff --git a/packages/d2b-provider-config-nixos/src/ttrpc.rs b/packages/d2b-provider-config-nixos/src/ttrpc.rs index 1089ee86f..79ec67b25 100644 --- a/packages/d2b-provider-config-nixos/src/ttrpc.rs +++ b/packages/d2b-provider-config-nixos/src/ttrpc.rs @@ -222,29 +222,29 @@ impl ConfigNixosClient { } } -/// The bound on admitted-but-unstarted blocking config dispatches, per seat。 +/// The bound on admitted-but-unstarted blocking config dispatches, per seat. /// /// The Guest read walks the working-copy path with `O_NOFOLLOW` and reads the -/// document through `rustix`;that kernel path has no async form, so a +/// document through `rustix`; that kernel path has no async form, so a /// dispatch must not run on the runtime worker that polls this service: a /// blocked worker stalls every other task sharing it. Dispatches run on one /// dedicated bounded worker (plan R4) instead of the runtime's shared /// blocking pool: the worker admits at most this many queued jobs, and a /// full queue refuses the caller (mapped to `Unavailable`) rather than -/// parking an executor worker or growing a thread per call。 +/// parking an executor worker or growing a thread per call. const MAX_DISPATCH_QUEUE_DEPTH: usize = 16; type DispatchJob = Box; -/// One dedicated dispatch worker thread with its own bounded queue。 +/// One dedicated dispatch worker thread with its own bounded queue. struct DispatchWorker { sender: SyncSender, } -/// Start one named worker with its own bounded queue。 +/// Start one named worker with its own bounded queue. /// /// `None` records a worker that could not start, so every later call refuses -/// rather than retrying a failing spawn。 +/// rather than retrying a failing spawn. fn start_dispatch_worker() -> Option { let (sender, receiver) = sync_channel::(MAX_DISPATCH_QUEUE_DEPTH); thread::Builder::new() @@ -262,15 +262,15 @@ fn start_dispatch_worker() -> Option { .map(|_| DispatchWorker { sender }) } -/// The blocking config-dispatch seat, started on first use。 +/// The blocking config-dispatch seat, started on first use. static DISPATCH_WORKER: LazyLock> = LazyLock::new(start_dispatch_worker); -/// Dispatch one operation on the dedicated bounded dispatch worker。 +/// Dispatch one operation on the dedicated bounded dispatch worker. /// /// The backend read is a synchronous kernel path, so it must not run on the /// runtime worker that polls this service: a blocked worker stalls every other /// task sharing it. Admission is a non-blocking `try_send`, so the caller's -/// executor is never parked;the outcome is awaited from the worker。 +/// executor is never parked; the outcome is awaited from the worker. async fn dispatch_on_blocking_worker( backend: Arc, operation: ConfigOperation, @@ -285,7 +285,7 @@ async fn dispatch_on_blocking_worker( let backend = Arc::clone(&backend); move || { // A panicking job drops the reply sender, so the waiter sees - // `Unavailable` instead of hanging on a dead worker。 + // `Unavailable` instead of hanging on a dead worker. let _ = reply.send(backend.dispatch(operation, payload)); } @@ -306,7 +306,7 @@ async fn dispatch_on_blocking_worker( }) } // A saturated queue refuses instead of growing threads or parking the - // caller;the RPC surface maps that refusal to `Unavailable`, matching + // caller; the RPC surface maps that refusal to `Unavailable`, matching // the previous semaphore ceiling's error. Err(TrySendError::Full(_)) | Err(TrySendError::Disconnected(_)) => { @@ -541,7 +541,7 @@ mod tests { // Drive the registered service handler, not the helper behind it. On // the single-threaded runtime below the release can only be delivered // while the backend is parked if the handler left its polling worker - // free: an inline `backend.dispatch` would stall the only worker and + // free: an inline `backend. dispatch` would stall the only worker and // the handler would answer the parked call with an error. let (started, mut started_rx) = tokio::sync::mpsc::unbounded_channel(); let (release, release_rx) = channel(); diff --git a/packages/d2b-provider-credential-secret-service/src/lib.rs b/packages/d2b-provider-credential-secret-service/src/lib.rs index d33e449e0..96df8d63f 100644 --- a/packages/d2b-provider-credential-secret-service/src/lib.rs +++ b/packages/d2b-provider-credential-secret-service/src/lib.rs @@ -1109,7 +1109,7 @@ impl fmt::Debug for SessionKey { /// ```compile_fail /// # use d2b_provider_credential_secret_service::SecretServiceSessionCapability; /// fn cannot_clone(capability: SecretServiceSessionCapability) { -/// let _ = capability.clone(); +/// let _ = capability. clone(); /// } /// ``` pub struct SecretServiceSessionCapability { diff --git a/packages/d2b-provider-credential/src/driver.rs b/packages/d2b-provider-credential/src/driver.rs index 8c14c1649..3038b4af1 100644 --- a/packages/d2b-provider-credential/src/driver.rs +++ b/packages/d2b-provider-credential/src/driver.rs @@ -25,7 +25,7 @@ //! - finalizer enrollment + agent child minting + provider readiness -> //! [`ResourceDriver::reconcile`]. //! - `prepare_finalize`/`execute_finalize`/`finalize` -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). //! //! One input has no durable home in the new runtime below the port: the old //! revocation gate read the lease facts from the Credential's persisted @@ -296,7 +296,7 @@ pub struct CredentialDriverArgs { /// The zone the plane serves. pub zone: ZoneId, /// Zone controller generation folded into every revocation request - /// (old `policy_snapshot.controller_generation`). + /// (old `policy_snapshot. controller_generation`). pub controller_generation: ControllerGeneration, /// The daemon-supplied facet set the family's own effects /// implementation is built from (U8): the construction site holds no @@ -977,7 +977,7 @@ const CREDENTIAL_VERBS: &[&str] = &[ /// The execution domains the Credential type can be reconciled in. /// /// A Credential row names a Host or a Guest execution target -/// (`spec.scope.executionRef`; the old `credential_execution_ref` admitted +/// (`spec. scope. executionRef`; the old `credential_execution_ref` admitted /// exactly those two), so the type spans both domains. const CREDENTIAL_EXECUTION_DOMAINS: &[&str] = &["host", "guest"]; @@ -1011,7 +1011,7 @@ const CREDENTIAL_CREATIONS: &[ChildCreation] = &[ChildCreation { /// `Credential` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot /// serve credential rows without it, so it must be registered before the /// plane opens. The type is not exportable (`ResourceExport` admits only -/// qualified `*.d2bus.org.*Service` types), and it serves no broker +/// qualified `*.d2bus. org.*Service` types), and it serves no broker /// operations. /// /// U8: the driver's effects are this crate's own implementation diff --git a/packages/d2b-provider-credential/src/session.rs b/packages/d2b-provider-credential/src/session.rs index c367d8090..bd7be21f8 100644 --- a/packages/d2b-provider-credential/src/session.rs +++ b/packages/d2b-provider-credential/src/session.rs @@ -72,7 +72,7 @@ pub struct CredentialRevocationInputs { pub controller_generation: ControllerGeneration, /// The live Provider session generation the request binds. pub session_generation: ReconnectGeneration, - /// `credential.rotationGeneration`; a missing or zero value keeps the + /// `credential. rotationGeneration`; a missing or zero value keeps the /// old status read's default of 1. pub rotation_generation: u64, } diff --git a/packages/d2b-provider-device-gpu/src/gpu_argv.rs b/packages/d2b-provider-device-gpu/src/gpu_argv.rs index ac0f21fd0..1b48f1ae2 100644 --- a/packages/d2b-provider-device-gpu/src/gpu_argv.rs +++ b/packages/d2b-provider-device-gpu/src/gpu_argv.rs @@ -11,12 +11,12 @@ //! //! ```text //! crosvm device gpu \ -//! --socket corp-desktop-gpu.sock \ +//! --socket corp-desktop-gpu. sock \ //! --wayland-sock $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY \ //! --params '{"context-types":"virgl:virgl2:cross-domain","displays":[{"hidden":true}],"egl":true,"vulkan":true}' //! ``` //! -//! CH then connects via `--gpu socket=corp-desktop-gpu.sock`. The Process +//! CH then connects via `--gpu socket=corp-desktop-gpu. sock`. The Process //! Provider composes that private CH argument from the sealed launch ticket; //! the Guest controller does not receive or assemble it. //! @@ -85,11 +85,11 @@ pub struct GpuArgvInput { /// not embed the VM name (the socket path does). pub vm_name: String, /// `--socket` value. Audit uses runner-cwd-relative - /// `-gpu.sock`; the daemon uses an absolute path under + /// `-gpu. sock`; the daemon uses an absolute path under /// `/run/d2b/vms//`. Either shape is honoured. pub socket_path: String, /// `--wayland-sock` value. Resolved by the daemon caller to the - /// host's primary Wayland session socket (per `d2b.site.waylandUser`). + /// host's primary Wayland session socket (per `d2b. site. waylandUser`). pub wayland_sock: String, /// `--params` JSON payload. pub params: GpuParams, diff --git a/packages/d2b-provider-device-gpu/src/video_argv.rs b/packages/d2b-provider-device-gpu/src/video_argv.rs index 5a8e062fe..3b40ce1d8 100644 --- a/packages/d2b-provider-device-gpu/src/video_argv.rs +++ b/packages/d2b-provider-device-gpu/src/video_argv.rs @@ -9,7 +9,7 @@ //! //! ```text //! crosvm device video-decoder \ -//! --socket-path /run/d2b-video//video.sock \ +//! --socket-path /run/d2b-video//video. sock \ //! --backend vaapi //! ``` //! @@ -26,19 +26,19 @@ use serde::{Deserialize, Serialize}; // Wire-contract pins // ========================================================================= // -// `pkgs/spectrum-ch/cloud-hypervisor/0003-vhost-user-media-device.patch` +// `pkgs/spectrum-ch/cloud-hypervisor/0003-vhost-user-media-device. patch` // hard-codes the virtio-media wire shape that this sidecar speaks to the // guest through cloud-hypervisor. These constants are NOT user-tunable // argv flags - they live in the CH patch and the crosvm vhost-user-media // backend. We mirror them here so the byte-parity golden -// (`tests/golden/runner-shape/video-argv-minimal.txt`) captures the full +// (`tests/golden/runner-shape/video-argv-minimal. txt`) captures the full // effective wire shape, and any future drift in the CH patch surfaces as // a golden diff in CI even though no argv changed. // // Every constant cites the patch line that pins it. /// virtio device-type id for `vhost-user-media`. Pinned in -/// `0003-vhost-user-media-device.patch` as `const VIRTIO_ID_MEDIA: u32 = 48`. +/// `0003-vhost-user-media-device. patch` as `const VIRTIO_ID_MEDIA: u32 = 48`. pub const VIRTIO_ID_MEDIA: u32 = 48; /// Number of virtqueues exposed by `vhost-user-media` (one command, one @@ -55,7 +55,7 @@ pub const VHOST_USER_MEDIA_QUEUE_SIZE: u16 = 256; pub const VHOST_USER_MEDIA_SHM_REGION_BYTES: u64 = 256 * 1024 * 1024; /// Forced `SET_VRING_BASE` value for every queue. Pinned in the CH patch -/// in `activate()`: `self.vu_common.vring_bases = Some(vec![0; queues.len()])`. +/// in `activate()`: `self. vu_common. vring_bases = Some(vec![0; queues. len()])`. /// The virtio-media guest driver pre-queues event buffers on queue 1 before /// `DRIVER_OK`; the explicit zero override keeps those buffers visible to /// the backend on resume. @@ -68,8 +68,8 @@ pub const VHOST_USER_MEDIA_VRING_BASE: u64 = 0; pub const VHOST_USER_MEDIA_PROTOCOL_FLAGS: &str = "BACKEND_REQ|REPLY_ACK|SHMEM_MAP_CROSVM"; /// PCI MMIO allocator used for the SHM region. Pinned in the CH patch via -/// `self.pci_segments[..].mem64_allocator.lock()...allocate(...)`. The -/// allocator name is part of the wire shape because changing it (e.g. to +/// `self. pci_segments[..].mem64_allocator.lock()...allocate(...)`. The +/// allocator name is part of the wire shape because changing it (e. g. to /// `mem32_allocator`) changes the guest-visible BAR layout. pub const VHOST_USER_MEDIA_MMIO_ALLOCATOR: &str = "pci-mem64"; @@ -114,12 +114,12 @@ impl VideoBackend { pub struct VideoArgvInput { /// Absolute store path to the `crosvm` binary (the video component /// overlays `cargoBuildFeatures += [video-decoder, - /// vaapi, media]` against `pkgs.crosvm`). + /// vaapi, media]` against `pkgs. crosvm`). pub crosvm_binary_path: String, /// VM name; used by the worker launch arg0 only. pub vm_name: String, /// `--socket-path` value. Per host.nix: - /// `/run/d2b-video//video.sock` (the video module uses its + /// `/run/d2b-video//video. sock` (the video module uses its /// own `RuntimeDirectory = d2b-video/` rather /// than sharing `/run/d2b/vms//`). pub socket_path: String, diff --git a/packages/d2b-provider-device-security-key/src/driver.rs b/packages/d2b-provider-device-security-key/src/driver.rs index 768705a64..02eddcfb3 100644 --- a/packages/d2b-provider-device-security-key/src/driver.rs +++ b/packages/d2b-provider-device-security-key/src/driver.rs @@ -2,8 +2,8 @@ //! conversion of the daemon-owned security-key Provider path. //! //! The family serves the two converted security-key ResourceTypes the -//! Provider owns - `security-key.d2bus.org.SecurityKeyService` and -//! `security-key.d2bus.org.SecurityKeyBinding` - and their `Device` rows +//! Provider owns - `security-key. d2bus. org.SecurityKeyService` and +//! `security-key. d2bus. org.SecurityKeyBinding` - and their `Device` rows //! belong to the `d2b-provider-device` family, which owns the `Device` //! ResourceType. //! @@ -77,10 +77,10 @@ const FRONTEND_PROCESS_PROVIDER_REF: &str = d2b_provider_process_systemd::PROVID #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SecurityKeyComponent { /// The security-key authority Service - /// (`security-key.d2bus.org.SecurityKeyService`). + /// (`security-key. d2bus. org.SecurityKeyService`). Service, /// The per-Guest security-key Binding - /// (`security-key.d2bus.org.SecurityKeyBinding`). + /// (`security-key. d2bus. org.SecurityKeyBinding`). Binding, } @@ -624,7 +624,7 @@ mod tests { } /// The relay Endpoint this driver declares carries a closed purpose - /// token: `EndpointSpec.purpose` is a `BoundedToken`, so the dotted + /// token: `EndpointSpec. purpose` is a `BoundedToken`, so the dotted /// pre-wave spelling is an admission refusal. #[test] fn security_key_relay_endpoint_purpose_is_a_closed_token() { diff --git a/packages/d2b-provider-device-security-key/src/relay_service.rs b/packages/d2b-provider-device-security-key/src/relay_service.rs index 57522a78d..84017a417 100644 --- a/packages/d2b-provider-device-security-key/src/relay_service.rs +++ b/packages/d2b-provider-device-security-key/src/relay_service.rs @@ -68,7 +68,7 @@ impl AsyncHidrawDevice { } /// Read a single 64-byte CTAPHID report from the physical token. - // Readiness-gated non-blocking read inside `AsyncFd::try_io`;the std + // Readiness-gated non-blocking read inside `AsyncFd::try_io`; the std // `Read` impl over the raw fd is the sanctioned AsyncFd shape. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub async fn read_report(&self) -> std::io::Result { @@ -94,7 +94,7 @@ impl AsyncHidrawDevice { } /// Write a single 64-byte CTAPHID report to the physical token. - // Readiness-gated non-blocking write inside `AsyncFd::try_io`;the std + // Readiness-gated non-blocking write inside `AsyncFd::try_io`; the std // `Write` impl over the raw fd is the sanctioned AsyncFd shape. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub async fn write_report(&self, report: &CtaphidReport) -> std::io::Result<()> { @@ -239,7 +239,7 @@ pub fn authenticate_peer( /// Bind (and tighten) the per-VM relay socket the accept loop serves. // Short mkdir/unlink/chmod on the socket path at a sync public surface; - // converting to async would ripple the crate's exported API beyond scope。 + // converting to async would ripple the crate's exported API beyond scope. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn bind_accept_socket(path: &Path) -> std::io::Result { if let Some(parent) = path.parent() { diff --git a/packages/d2b-provider-device-tpm/src/effects_service.rs b/packages/d2b-provider-device-tpm/src/effects_service.rs index 1c8dca19d..0ed83b01d 100644 --- a/packages/d2b-provider-device-tpm/src/effects_service.rs +++ b/packages/d2b-provider-device-tpm/src/effects_service.rs @@ -882,7 +882,7 @@ mod tests { } /// Publish one declared row together with the driver-projected - /// `status.resource` layer the Process controller writes for a + /// `status. resource` layer the Process controller writes for a /// one-shot's terminal outcome. fn publish_outcome(&self, reference: &str, status: ResourceStatus, projection: Value) { self.publish(reference, status); @@ -1321,7 +1321,7 @@ async fn deletion_targets_the_declared_rows() { } /// Malformed manager-child documents fail closed before any mutation: a - /// missing type, metadata.name, or spec is rejected, and an + /// missing type, metadata. name, or spec is rejected, and an /// unparseable type/name pair can never name a row. #[test] diff --git a/packages/d2b-provider-device-tpm/src/swtpm_argv.rs b/packages/d2b-provider-device-tpm/src/swtpm_argv.rs index b134dde8d..99316280b 100644 --- a/packages/d2b-provider-device-tpm/src/swtpm_argv.rs +++ b/packages/d2b-provider-device-tpm/src/swtpm_argv.rs @@ -1,20 +1,20 @@ //! swtpm argv generator (UNIX-socket TPM 2.0 backend). //! //! `swtpm` is the per-VM software TPM sidecar d2b spawns for VMs -//! that declare `d2b.vms..tpm.enable = true`. The guest-side +//! that declare `d2b. vms..tpm. enable = true`. The guest-side //! TPM module passes the CH TPM socket via -//! `d2b.vms..runner.hypervisor.extraArgs`, and the sidecar +//! `d2b. vms..runner. hypervisor. extraArgs`, and the sidecar //! process is shaped as a standalone broker-spawned worker: //! //! ```text //! swtpm socket \ //! --tpm2 \ //! --tpmstate dir= \ -//! --ctrl type=unixio,path=/ctrl.sock,mode=0660,uid=,gid= \ -//! --server type=unixio,path=-tpm.sock,mode=0660,uid=,gid= \ +//! --ctrl type=unixio,path=/ctrl. sock,mode=0660,uid=,gid= \ +//! --server type=unixio,path=-tpm. sock,mode=0660,uid=,gid= \ //! --flags startup-clear \ //! --log file=/swtpm.log,level=20 \ -//! --pid file=/swtpm.pid +//! --pid file=/swtpm. pid //! ``` //! //! `swtpm socket` stays in the foreground unless `-d|--daemon` is @@ -29,7 +29,7 @@ //! (`processes::VmProcessInvariants::swtpm_pre_start_flush = true`): //! //! ```text -//! swtpm_ioctl -i --unix /ctrl.sock +//! swtpm_ioctl -i --unix /ctrl. sock //! ``` //! //! …followed by a clean shutdown command (`-s`) before the supervisor @@ -51,7 +51,7 @@ pub struct SwtpmArgvInput { /// VM name; the Provider refuses an empty one. pub vm_name: String, /// Absolute path to the per-VM TPM state directory. swtpm writes - /// `tpm2-00.permall` plus its log/pid in here. + /// `tpm2-00. permall` plus its log/pid in here. pub state_dir: String, /// Absolute path to the swtpm control socket (`--ctrl`). CH never /// connects to this one - the daemon uses it for shutdown/flush. @@ -72,7 +72,7 @@ pub struct SwtpmArgvInput { /// `--log level=` value. swtpm accepts 1..20; d2b defaults /// to 20 (debug) during alpha and clamps in the daemon caller. pub log_level: u8, - /// `--pid file=` value; usually `/swtpm.pid`. + /// `--pid file=` value; usually `/swtpm. pid`. pub pid_path: String, /// `--flags startup-clear` is emitted when this is `true`. On /// startup the supervisor runs `swtpm_ioctl -i` first, so the @@ -299,7 +299,7 @@ mod tests { /// Byte-parity oracle for the long-lived swtpm argv. /// - /// The golden file `tests/golden/runner-shape/swtpm-argv-minimal.txt` + /// The golden file `tests/golden/runner-shape/swtpm-argv-minimal. txt` /// contains a leading comment block (lines starting with `#`) /// followed by the argv vector joined by `'\n'`, one argument per /// line. This test strips the comment block and asserts byte-parity diff --git a/packages/d2b-provider-device-usbip/src/driver.rs b/packages/d2b-provider-device-usbip/src/driver.rs index 0204ea2ba..2c53f4e15 100644 --- a/packages/d2b-provider-device-usbip/src/driver.rs +++ b/packages/d2b-provider-device-usbip/src/driver.rs @@ -2,7 +2,7 @@ //! conversion of the daemon-owned USBIP Provider path. //! //! The family serves the two converted USB ResourceTypes the Provider owns - -//! `usb.d2bus.org.UsbService` and `usb.d2bus.org.UsbBinding` - and their +//! `usb. d2bus. org.UsbService` and `usb. d2bus. org.UsbBinding` - and their //! `Device` rows belong to the `d2b-provider-device` family, which owns the //! `Device` ResourceType. The scope here is the crate's own declaration: the //! rows below name the components this crate serves, and the typed effect @@ -63,9 +63,9 @@ pub const USBIP_RESYNC: Duration = Duration::from_secs(30); /// ResourceTypes it owns. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UsbipComponent { - /// The USB authority Service (`usb.d2bus.org.UsbService`). + /// The USB authority Service (`usb. d2bus. org.UsbService`). Service, - /// The per-Guest USB Binding (`usb.d2bus.org.UsbBinding`). + /// The per-Guest USB Binding (`usb. d2bus. org.UsbBinding`). Binding, } diff --git a/packages/d2b-provider-device-usbip/src/state_machine.rs b/packages/d2b-provider-device-usbip/src/state_machine.rs index 9f3f081a5..e59dc12a5 100644 --- a/packages/d2b-provider-device-usbip/src/state_machine.rs +++ b/packages/d2b-provider-device-usbip/src/state_machine.rs @@ -327,7 +327,7 @@ pub fn build_usbip_plan( /// /// The daemon MUST have already checked, before calling this: /// 1. the busid is present in `/sys/bus/usb/devices//` (sysfs check), -/// 2. the target VM has `runtime.capabilities.usbHotplug = true` (USB-capable gate), +/// 2. the target VM has `runtime. capabilities. usbHotplug = true` (USB-capable gate), /// 3. the per-busid OFD lock at `/run/d2b/locks/usbip/` is NOT held by /// another VM (active-claim exclusivity). /// @@ -682,7 +682,7 @@ mod tests { /// Per-step failure surfaces as a typed error tagged with the /// exact step. Execution halts immediately (no later steps run) - /// and prior steps stay in `report.completed` so the stop-path + /// and prior steps stay in `report. completed` so the stop-path /// reconciler can undo them. #[test] fn each_step_failure_surfaces_typed_error() { diff --git a/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs b/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs index 04551c221..b84e51659 100644 --- a/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs +++ b/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs @@ -53,7 +53,7 @@ struct Args { #[arg(long)] connect: Option, - /// Canonical workload target, e.g. `tools.host.d2b`. + /// Canonical workload target, e. g. `tools. host. d2b`. #[arg(long, value_name = "TARGET")] target: Option, @@ -764,7 +764,7 @@ fn accept_poll_timeout_ms( .min(i32::MAX as u128) as i32 } -/// Renders an error together with its full `source()` chain on one line, e.g. +/// Renders an error together with its full `source()` chain on one line, e. g. /// `could not dispatch server events: receiver object 4278190081 does not exist`. /// `thiserror`'s `Display` only prints the top-level message, so without walking /// the chain the `#[source]` detail that pinpoints the failing message is lost. diff --git a/packages/d2b-provider-display-wayland/src/controller.rs b/packages/d2b-provider-display-wayland/src/controller.rs index 1ee2ed899..e4b374222 100644 --- a/packages/d2b-provider-display-wayland/src/controller.rs +++ b/packages/d2b-provider-display-wayland/src/controller.rs @@ -243,7 +243,7 @@ pub struct WaylandSessionStatus { pub resource: WaylandSessionResourceStatus, } -/// Bounded `WaylandSession.status.resource` projection. +/// Bounded `WaylandSession. status. resource` projection. #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct WaylandSessionResourceStatus { /// Stable Host proxy Process reference. diff --git a/packages/d2b-provider-display-wayland/src/session_children.rs b/packages/d2b-provider-display-wayland/src/session_children.rs index d09ff3022..9060da466 100644 --- a/packages/d2b-provider-display-wayland/src/session_children.rs +++ b/packages/d2b-provider-display-wayland/src/session_children.rs @@ -323,7 +323,7 @@ fn durable_display_suffix(session_uid: &ResourceUid, role: DisplayProcessRole) - suffix } -/// The `status.resource` projection for one display session: the two worker +/// The `status. resource` projection for one display session: the two worker /// Process references and the private Endpoint with its committed /// generation. pub fn wayland_session_resource_projection( diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs index 748f91934..2b8f51181 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs @@ -290,7 +290,7 @@ pub enum BridgeTransferKind { impl BridgeHandoff for UnixStream { // Descriptor-passing sendmsg, MSG_DONTWAIT non-blocking on a poll-driven - // sync bridge surface;no async form fits the trait contract here. + // sync bridge surface; no async form fits the trait contract here. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn handoff_transfer_fd( &mut self, diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs index fe6ec31b0..7daa0238f 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs @@ -371,7 +371,7 @@ impl VirtualClipboardState { .and_then(|vs| vs.borrow().source.upgrade()); self.selection = source.and_then(|source| self.sources.get(&source.unique_id()).cloned()); // Return the old source only when it is being superseded by a different source - // (or cleared), so the caller can send wl_data_source.cancelled. + // (or cleared), so the caller can send wl_data_source. cancelled. old_strong.filter(|old| source.is_none_or(|new| old.unique_id() != new.unique_id())) } diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs index c4e0ec9b5..464c0bab7 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs @@ -137,10 +137,10 @@ impl PolicyWarning { pub struct PolicyInput { /// Typed canonical workload identity. pub identity: ProxyIdentity, - /// Prefix prepended to `xdg_toplevel.set_app_id` values. + /// Prefix prepended to `xdg_toplevel. set_app_id` values. /// Default: the identity's provider-specific prefix. pub app_id_prefix: Option, - /// Prefix prepended to `xdg_toplevel.set_title` values. + /// Prefix prepended to `xdg_toplevel. set_title` values. /// Default: the identity's provider-specific prefix. pub title_prefix: Option, /// Additional explicit deny rules (appended after defaults). diff --git a/packages/d2b-provider-endpoint/src/driver.rs b/packages/d2b-provider-endpoint/src/driver.rs index 53d610085..378fc8bf4 100644 --- a/packages/d2b-provider-endpoint/src/driver.rs +++ b/packages/d2b-provider-endpoint/src/driver.rs @@ -32,7 +32,7 @@ //! - `observe` -> [`ResourceDriver::recover`]. //! - socket realization -> [`ResourceDriver::reconcile`]. //! - socket removal -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx.set_status` (in-memory only). +//! - `UpdateStatus` -> `ctx. set_status` (in-memory only). //! //! Which purposes a declaring provider commits, and on which producer, is //! this crate's own derivation ([`crate::effects_service`]): the closed @@ -540,7 +540,7 @@ impl ResourceDriver for EndpointDriver { /// /// Derived from the placement contract: `Endpoint` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so an Endpoint row never -/// carries the canonical `spec.executionRef` and the plane reconciles it on +/// carries the canonical `spec. executionRef` and the plane reconciles it on /// its own Host domain. A realized producer may live in a Guest; the effects /// reach that row through the manager, not through this row's placement. const ENDPOINT_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -563,7 +563,7 @@ const ENDPOINT_READS: &[WellKnownType] = &[ /// `Endpoint` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve /// the converted endpoint shapes without it, so it must be registered before /// the plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus.org.*Service` types, so an endpoint can never be an +/// qualified `*.d2bus. org.*Service` types, so an endpoint can never be an /// export subject. The driver serves no broker operations and creates no /// children through this declaration; the endpoint children the volume /// binding realizes are created by that family. The declaration carries the diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs index 1f066cd52..2289674e5 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs @@ -192,18 +192,27 @@ impl<'de> Deserialize<'de> for AzureVmRecoveryState { // pending update was set carries the removed reconfiguration // phase, which the phase decode refuses. let _ = shape.pending_update; + // A legacy record carries the operation and its start stamp + // as a pair. The write side emits both or neither, but this + // is decoded data read back off disk, so a half-Some pair is + // a malformed record: it fails the decode with a typed serde + // error instead of aborting the thread. + let in_flight_operation = match (shape.operation, shape.operation_started_at_unix_ms) + { + (Some(operation), Some(started_at)) => { + Some(InFlightOperation { operation, started_at }) + } + (None, None) => None, + (Some(_), None) | (None, Some(_)) => { + return Err(::custom( + "legacy recovery record has a half-Some operation pair", + )); + } + }; Self { phase: shape.phase, finalizer_installed: shape.finalizer_installed, - in_flight_operation: match (shape.operation, shape.operation_started_at_unix_ms) - { - (Some(operation), Some(started_at)) => { - Some(InFlightOperation { operation, started_at }) - } - (None, None) => None, - // Unreachable: the write side keeps the pair together. - _ => unreachable!("legacy recovery record has a half-Some operation pair"), - }, + in_flight_operation, pending_delete_operation_id: shape.pending_delete_operation_id, bootstrap_started_at_unix_ms: shape.bootstrap_started_at_unix_ms, psk_delivery_attempts: shape.psk_delivery_attempts, @@ -306,8 +315,11 @@ where /// # Errors /// /// Returns [`AzureVmError::InvalidConfiguration`] when the recovery - /// record is internally inconsistent (phase/operation pairing, - /// finalizer, or identifier bounds). + /// record is internally inconsistent (an in-flight operation under a + /// phase that allows none, a finalizer that disagrees with the phase, or + /// identifier bounds). The operation/start-stamp pairing is checked when + /// the record is decoded, not here: a half-paired legacy record fails the + /// decode instead of reaching this predicate. pub fn restore_recovery_state( mut self, recovery: AzureVmRecoveryState, diff --git a/packages/d2b-provider-guest-qemu-media/src/hotplug.rs b/packages/d2b-provider-guest-qemu-media/src/hotplug.rs index 0cd74a2ce..cb02091b3 100644 --- a/packages/d2b-provider-guest-qemu-media/src/hotplug.rs +++ b/packages/d2b-provider-guest-qemu-media/src/hotplug.rs @@ -32,7 +32,7 @@ impl QemuMediaHotplugAction { pub struct QemuMediaHotplugScaffold { /// Opaque media ref the transaction targets. pub media_ref: String, - /// Slot the media occupies (e.g. `boot`). + /// Slot the media occupies (e. g. `boot`). pub slot: String, /// QMP block node name. pub blockdev_id: String, diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index 990956f58..2032389cf 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -11,7 +11,7 @@ //! F1), owned children the desired set no longer derives are retired in //! the family's preserved order, the typed Provider effect runs behind //! [`GuestDriverEffects`], and the in-memory status projection is -//! published with `ctx.set_status` + `ctx.set_status_projection` (R11) +//! published with `ctx. set_status` + `ctx. set_status_projection` (R11) //! plus a self-`requeue_after` while the family is not converged; //! - [`ResourceDriver::finalize`] and [`ResourceDriver::delete`]: the kind's //! preserved teardown stage (Cloud Hypervisor's controller-owned finalize, @@ -208,12 +208,12 @@ pub enum GuestEffectPhase { } /// One Provider effect outcome: the phase the old effect returned plus the -/// layered `status.resource` projection the Provider published for the row. +/// layered `status. resource` projection the Provider published for the row. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GuestEffectOutcome { /// The phase the Provider effect reported. pub phase: GuestEffectPhase, - /// The layered `status.resource` projection the Provider published. + /// The layered `status. resource` projection the Provider published. pub resource_projection: Option, } @@ -340,12 +340,12 @@ impl std::error::Error for GuestDriverError {} /// Typed in-memory status projection (R11: never persisted). Carries the /// closed phase the old status candidate published plus the Provider's -/// layered `status.resource` projection. +/// layered `status. resource` projection. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GuestDriverStatus { /// The phase this status publishes. pub phase: GuestEffectPhase, - /// The Provider's sticky `status.resource` projection, when one exists. + /// The Provider's sticky `status. resource` projection, when one exists. pub resource: Option, } @@ -541,7 +541,7 @@ pub struct GuestEffectRequest<'a> { /// The Provider row's spec for this Guest's `providerRef`, when the /// manager holds it (the framework kinds read their `/config` here). pub provider_spec: Option, - /// The driver's last published `status.resource` projection, when one + /// The driver's last published `status. resource` projection, when one /// was published: the Provider status is sticky, exactly as the old /// durable row's was. pub status: Option, @@ -681,12 +681,12 @@ const GUEST_CREATIONS: &[ChildCreation] = &[ /// `Guest` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve a /// guest whose provider controller never registered, so the type must be /// present before the plane opens. The type is not exportable: -/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a /// guest can never be an export subject. The driver serves no broker /// operations and contributes no startup step of its own; every child the /// family's drivers and controller sessions create is declared in /// [`GUEST_CREATIONS`]. The family's declared effects service -/// (`guest.d2bus.org/effects`, U10) rides the declaration, so the daemon +/// (`guest. d2bus. org/effects`, U10) rides the declaration, so the daemon /// hosts it through the registered factory over the composition root's /// facet set. pub fn guest_descriptor(args: GuestDriverArgs) -> DriverDescriptor { diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index 95d18724f..b7ecc4228 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -25,7 +25,7 @@ //! `activeProcessCount`). That status is the row's actor's to own (R11) and //! there is no durable row to write: the session captures the controller's //! write into the effect call's [`GuestStatusSink`] and the driver publishes -//! it as the row's `status.resource` projection. The provider controller's +//! it as the row's `status. resource` projection. The provider controller's //! finalizer requests are acknowledged without a store write for the same //! reason - the manager's deleting-row hold replaces the old durable //! finalizer (F3). @@ -632,7 +632,7 @@ impl GuestEffectsService { } /// The old-shape document of one resource (`spec`, `metadata`, live - /// `status.phase`) from the manager view, answered as one classified read + /// `status. phase`) from the manager view, answered as one classified read /// (issue #511): `Present` carries the document, `Absent` is the honest /// not-created answer, `Unavailable` is a plane that could not answer, /// and `Error` carries the projection detail of a committed row that diff --git a/packages/d2b-provider-guest/src/shutdown.rs b/packages/d2b-provider-guest/src/shutdown.rs index ad3ea6ec0..0afdab9d1 100644 --- a/packages/d2b-provider-guest/src/shutdown.rs +++ b/packages/d2b-provider-guest/src/shutdown.rs @@ -204,7 +204,7 @@ mod tests { let _ = tokio::fs::remove_dir_all(dir).await; } - /// Serve one `vm.info` HTTP-over-unix exchange for the given wire state, + /// Serve one `vm. info` HTTP-over-unix exchange for the given wire state, /// and return the socket path the poll reads, plus the serving dir the /// caller removes when the exchange is complete. async fn serve_vm_info(state: &str) -> (PathBuf, PathBuf) { diff --git a/packages/d2b-provider-guest/src/test_support.rs b/packages/d2b-provider-guest/src/test_support.rs index 2a2763b85..e111087ab 100644 --- a/packages/d2b-provider-guest/src/test_support.rs +++ b/packages/d2b-provider-guest/src/test_support.rs @@ -56,7 +56,7 @@ pub struct EffectObservation { pub kind: GuestKind, /// The Provider row's spec the driver resolved, when the manager held it. pub provider_spec: Option, - /// The driver's last published `status.resource` projection, when one + /// The driver's last published `status. resource` projection, when one /// was published. pub status: Option, /// The owned child rows the call read, with their live phase. @@ -111,7 +111,7 @@ impl ScriptedEffects { *self.phase.lock().await = phase; } - /// Script the `status.resource` projection the next `reconcile` reports. + /// Script the `status. resource` projection the next `reconcile` reports. pub async fn set_projection(&self, projection: Option) { *self.projection.lock().await = projection; } @@ -331,7 +331,7 @@ pub fn row_fixture( } /// A manager row fixture with explicit metadata (the gateway-custody -/// validation reads the gateway Guest's `metadata.zone`). +/// validation reads the gateway Guest's `metadata. zone`). pub fn row_fixture_with_metadata( zone: &str, type_name: &str, diff --git a/packages/d2b-provider-host/src/driver.rs b/packages/d2b-provider-host/src/driver.rs index ccb49f640..8571a3907 100644 --- a/packages/d2b-provider-host/src/driver.rs +++ b/packages/d2b-provider-host/src/driver.rs @@ -12,7 +12,7 @@ //! Conversion mapping (spec section 13): //! - `describe` -> [`host_descriptor`] registration under `Host`. //! - `validate_spec` -> [`ResourceDriver::validate`]: typed spec decode plus -//! the `Host.spec.providerRef` fence (`Provider/system-core` is the only +//! the `Host. spec. providerRef` fence (`Provider/system-core` is the only //! Provider the Host contract admits). //! - `plan` -> the preserved `observedGeneration` short-circuit: a status //! observed at the current generation skips re-observing (the old @@ -23,10 +23,10 @@ //! over the [`HostDriverEffects`] probe port. //! - `finalize` -> [`ResourceDriver::delete`] (old `FinalizeResult` was //! converged: the family owns no children and carries no finalizer). -//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). //! //! Deliberately not carried from the old handler: the durable -//! `status.resource` JSON projection and its `lastReconciledAt` / +//! `status. resource` JSON projection and its `lastReconciledAt` / //! `observedGeneration` writes (status is runtime-only now, R11), and the //! `assess_update` / `plan_upgrade` runner path (no driver equivalent; the //! family never planned an upgrade). The old runner's 5s resync relisted and @@ -42,7 +42,7 @@ //! ([`crate::effects_service::HostEffectsService`]) built from the //! daemon-supplied facet set - the construction site holds no externally //! built port (R2) - and the family's declared effects service -//! (`host.d2bus.org/effects`) rides the declaration, so a zone that cannot +//! (`host. d2bus. org/effects`) rides the declaration, so a zone that cannot //! host it refuses startup by name (R5). //! //! KTD13: the driver has no spawn surface at all. It observes the local host @@ -137,7 +137,7 @@ impl std::error::Error for HostDriverError {} /// Typed in-memory status projection (R11: never persisted). /// /// The observation is kept with the generation it was taken at, which is the -/// runtime-only successor of the old durable `status.observedGeneration` +/// runtime-only successor of the old durable `status. observedGeneration` /// plan short-circuit. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct HostDriverStatus { @@ -301,7 +301,7 @@ impl HostDriver { .map_err(|_| self.error(HostDriverErrorKind::SpecInvalid, op)) } - /// The declared `spec.providerRef` fence plus the typed Host base spec. + /// The declared `spec. providerRef` fence plus the typed Host base spec. fn host_spec( &self, ctx: &ResourceContext, @@ -457,7 +457,7 @@ impl ResourceDriver for HostDriver { /// /// Derived from the placement contract: `Host` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so a Host row never -/// carries the canonical `spec.executionRef` and the plane reconciles it on +/// carries the canonical `spec. executionRef` and the plane reconciles it on /// its own Host domain - which is the row's own subject. const HOST_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -466,7 +466,7 @@ const HOST_EXECUTION_DOMAINS: &[&str] = &["host"]; /// `Host` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve the /// converted bootstrap rows without it, so it must be registered before the /// plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus.org.*Service` types. The driver serves no broker +/// qualified `*.d2bus. org.*Service` types. The driver serves no broker /// operations, creates no children, and reads no other resource: the /// observation reaches the local machine through the family's own probe. /// diff --git a/packages/d2b-provider-host/src/test_support.rs b/packages/d2b-provider-host/src/test_support.rs index d23ab8505..c88909663 100644 --- a/packages/d2b-provider-host/src/test_support.rs +++ b/packages/d2b-provider-host/src/test_support.rs @@ -109,7 +109,7 @@ struct RecordingProbeCore { impl RecordingProbe { /// Construct the double over one scripted capability set, the default - /// Ready gate (6.9 with cgroup.kill), and the default bounded metadata. + /// Ready gate (6.9 with cgroup. kill), and the default bounded metadata. pub fn new(capabilities: Vec) -> Arc { Arc::new(Self { core: Arc::new(RecordingProbeCore { diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index de960790e..c8cb173f6 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -19,7 +19,7 @@ //! [`ResourceDriver::reconcile`]: the desired child set is ensured through //! the manager child API (committed before the child actor exists, F1), the //! typed Provider effect runs behind the port, and the in-memory status -//! projection is published with `ctx.set_status` (R11) plus a self-requeue +//! projection is published with `ctx. set_status` (R11) plus a self-requeue //! while the family is not converged. //! - `prepare_finalize`/`execute_finalize`/`finalize` -> //! [`ResourceDriver::delete`]: the family's staged fabric finalizer runs @@ -241,7 +241,7 @@ const NETWORK_READS: &[WellKnownType] = &[ /// `Network` is `BUILTIN | STARTUP` (no RUNTIME bit): zone networking is /// referenced by every Guest-bearing zone, so the plane must have the driver /// registered before it opens. The type is not exportable: `ResourceExport` -/// admits only qualified `*.d2bus.org.*Service` types, so a network can never +/// admits only qualified `*.d2bus. org.*Service` types, so a network can never /// be an export subject. The driver declares the thirteen network-fds family /// operations (U12): the broker-generic kernels serve each operation's /// privileged core in-broker, while the family operation itself stays diff --git a/packages/d2b-provider-network-local/tests/network_family.rs b/packages/d2b-provider-network-local/tests/network_family.rs index 21b4115a3..1adfb9488 100644 --- a/packages/d2b-provider-network-local/tests/network_family.rs +++ b/packages/d2b-provider-network-local/tests/network_family.rs @@ -157,7 +157,7 @@ let handle = std::thread::spawn(move || { } // Joining the fake kernel server's thread is the sync test harness's own - // blocking wait;the server leg itself runs on a plain test thread. + // blocking wait; the server leg itself runs on a plain test thread. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn captured(&mut self) -> BrokerRequestEnvelope { @@ -177,7 +177,7 @@ let handle = std::thread::spawn(move || { /// Serve one accepted kernel call:capture the EnvelopeInvoke frame and /// sendthe canned reply over the same SEQPACKET connection, exactly as /// the broker's origination socket would. Runs on the test's own blocking -/// thread;the poll-and-sleep wait for the caller's canned answer is part +/// thread; the poll-and-sleep wait for the caller's canned answer is part /// of this sync test harness, so the leg carries the test-helper sanction. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn serve_kernel_call( diff --git a/packages/d2b-provider-notification-desktop/src/metrics.rs b/packages/d2b-provider-notification-desktop/src/metrics.rs index 471227308..2cd3e6044 100644 --- a/packages/d2b-provider-notification-desktop/src/metrics.rs +++ b/packages/d2b-provider-notification-desktop/src/metrics.rs @@ -180,7 +180,7 @@ mod tests { } /// The collector-field injection fence: duplicate keys, newline or - /// oversized values, `d2b.provider` spoofing, and out-of-vocabulary + /// oversized values, `d2b. provider` spoofing, and out-of-vocabulary /// categories are all rejected. #[test] fn collector_field_validation_rejects_injection_and_spoofing() { diff --git a/packages/d2b-provider-process-minijail/src/launch.rs b/packages/d2b-provider-process-minijail/src/launch.rs index 1c419a6ed..ba19de0a6 100644 --- a/packages/d2b-provider-process-minijail/src/launch.rs +++ b/packages/d2b-provider-process-minijail/src/launch.rs @@ -9,7 +9,7 @@ pub struct PlatformGate { pub kernel_major: u16, /// Kernel minor. pub kernel_minor: u16, - /// Whether the runtime cgroup exposes cgroup.kill. + /// Whether the runtime cgroup exposes cgroup. kill. pub cgroup_kill_available: bool, } @@ -27,12 +27,12 @@ impl PlatformGate { } } - /// Check Linux 5.14 and cgroup.kill. + /// Check Linux 5.14 and cgroup. kill. /// /// # Errors /// /// Returns `PlatformGateRejected` when the kernel is older than - /// 5.14 or the runtime cgroup does not expose `cgroup.kill`. + /// 5.14 or the runtime cgroup does not expose `cgroup. kill`. pub const fn validate(self) -> Result<(), ProcessConformanceError> { if self.kernel_major < 5 || (self.kernel_major == 5 && self.kernel_minor < 14) diff --git a/packages/d2b-provider-process-systemd/src/effects_service.rs b/packages/d2b-provider-process-systemd/src/effects_service.rs index 66b592901..5b716bc31 100644 --- a/packages/d2b-provider-process-systemd/src/effects_service.rs +++ b/packages/d2b-provider-process-systemd/src/effects_service.rs @@ -35,7 +35,7 @@ use crate::operations::{ /// to the crate's committed handler table with the invocation's kernel seam - /// the same handler table the provider-operation path serves, over the same /// authority path (U15). The service is hermetic and carries no declared -/// facet;the family's privileged operations reach daemon-structural state +/// facet; the family's privileged operations reach daemon-structural state /// through the per-zone kernel seam of the forwarded invocation, never /// through a daemon handle. pub const PROCESS_SYSTEMD_EFFECTS_SERVICE: ServiceDecl = ServiceDecl { @@ -83,7 +83,7 @@ pub const PROCESS_SYSTEMD_SERVICES: &[ServiceDecl] = &[PROCESS_SYSTEMD_EFFECTS_S /// The provider-owned system-systemd effects service (U15). /// -/// One value per zone serves the declared methods;the factory constructs it +/// One value per zone serves the declared methods; the factory constructs it /// from crate-owned constants alone, so a respawn rebuilds the same surface /// from its durable row (KTD5). #[derive(Default)] @@ -138,7 +138,7 @@ fn inspect_response() -> Result { /// assembled from the invocation:the zone, the caller `Provider/process- /// systemd` the family's registered identity, the invocation id, the /// request-leg descriptors, the invocation's kernel seam, and an empty -/// evidence chain (a root forwarded call carries none;the chain the broker +/// evidence chain (a root forwarded call carries none; the chain the broker /// minted for the forwarded root stays broker-side, exactly as a /// provider-operation-table dispatch's root call does. async fn run_operation( @@ -286,7 +286,7 @@ mod tests { ) .expect("payload object"); let mut resources = ServiceResourceContext::fail_closed(); - // No kernel seam is wired in this hermetic test;the handler que + // No kernel seam is wired in this hermetic test; the handler que // validates the typed request before its kernel read, so an // empty payload refuses with the invalid-request code rather // than reaching the kernel-seam check. Either code is the diff --git a/packages/d2b-provider-process-systemd/src/operations.rs b/packages/d2b-provider-process-systemd/src/operations.rs index 0b8ee3a39..3a8878928 100644 --- a/packages/d2b-provider-process-systemd/src/operations.rs +++ b/packages/d2b-provider-process-systemd/src/operations.rs @@ -118,11 +118,11 @@ const SERVICE_INTERFACE: &str = "org.freedesktop.systemd1.Service"; /// The systemd object interface a unit-identity property is defined on. /// -/// `ControlGroup` and `MainPID` are defined on `org.freedesktop.systemd1.Service` +/// `ControlGroup` and `MainPID` are defined on `org. freedesktop. systemd1.Service` /// (the family's transient service units), not on `Unit`; reading them through /// the Unit proxy fails every read with `UnknownProperty` and the identity can /// never bind (issue #587). `ActiveState` and `InvocationID` are defined on -/// `org.freedesktop.systemd1.Unit`. `read_identity` routes every property read +/// `org. freedesktop. systemd1.Unit`. `read_identity` routes every property read /// through this selection. fn identity_property_interface(property: &str) -> &'static str { match property { @@ -464,7 +464,7 @@ async fn unit_proxy<'a>(manager: &Proxy<'a>, name: &str) -> Result`). +/// declared Guest owner (`Device. metadata. ownerRef == Guest/`). /// /// A Device-owned worker row runs on the Host (`executionRef /// Host/host-system`) and names no Guest target, so the row's own launch @@ -382,12 +382,12 @@ pub fn resource_uid_from_bytes(bytes: &[u8; 16]) -> Option { /// KTD7 Guest-owner identity source: the owning `Guest` row's durable uid for /// one canonical Guest reference. `Guest` has not been converted, so a /// converted Process row owned by a Guest cannot carry the durable owner -/// linkage the pre-v3 store computed (`record.owner_uid` = the resolved owner +/// linkage the pre-v3 store computed (`record. owner_uid` = the resolved owner /// row's uid) - the manager row carries only the authored -/// `metadata.ownerRef`. The old descriptor composer read the linkage first +/// `metadata. ownerRef`. The old descriptor composer read the linkage first /// and the owner identity cache second; a reference this source cannot /// resolve stays unbound, so the Cloud Hypervisor launch stays refused closed -/// (the broker requires the owner uid to bind `d2b.guest_uid=`). +/// (the broker requires the owner uid to bind `d2b. guest_uid=`). /// /// Trait, not a concrete type, because `d2b-provider-process` consumes it /// (`resolve_guest_owner_uid`) and cannot depend on `d2bd`, where the @@ -604,14 +604,14 @@ pub(crate) const PROCESS_FAMILY_READS: &[WellKnownType] = &[ /// `Process` and `EphemeralProcess` are `BUILTIN | STARTUP` (no RUNTIME bit): /// the plane cannot admit workloads without a process launcher, so both must /// be registered before the plane opens. Neither member type is exportable: -/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a /// process can never be an export subject. /// /// The family's declared operations and services ride on the `Process` /// descriptor alone: the registry gives one operation reference exactly one /// owning type (a second declaring driver is refused as foreign), the /// declaration inspection is a family operation, not a per-member one, and -/// the family's effects service (`process.d2bus.org/effects`, U1) is a +/// the family's effects service (`process. d2bus. org/effects`, U1) is a /// family surface its member types share. The family creates no children /// through this declaration today. pub fn process_family_descriptors(args: ProcessDriverArgs) -> [DriverDescriptor; 2] { @@ -1887,7 +1887,7 @@ impl ProcessDriver { Err(self.identity_ambiguous(DriverOp::Delete, &report)) } // A row no host-minted ticket can describe (a Guest-owned one-shot - // outside the guest VMM chain, e.g. the projected + // outside the guest VMM chain, e. g. the projected // `store-preflight-` intent) has no identity this daemon // could ever have realized, so its deletion converges with no // provider effect. The guard's real intent is preserved: nothing @@ -1940,7 +1940,7 @@ fn provider_error_kind(error: &str) -> ProcessDriverErrorKind { ProcessDriverErrorKind::ResolutionRefused } else if error.contains("guest-process-not-vmm") { // The trusted bundle holds no host-minted intent for this row at all - // (a Guest-owned one-shot outside the guest VMM chain, e.g. a + // (a Guest-owned one-shot outside the guest VMM chain, e. g. a // projected preflight intent): no retry can ever mint a ticket, so // the refusal is terminal - never an ambiguous identity to quarantine // (R15 is about observed identity). @@ -2785,7 +2785,7 @@ mod tests { /// A Device-owned worker row names no VM of its own (`executionRef /// Host/host-system`, no Guest target), so the Process controller derives /// the worker's VM scope from the owning Device's declared Guest owner - - /// the same `Device.metadata.ownerRef == Guest/` derivation the TPM + /// the same `Device. metadata. ownerRef == Guest/` derivation the TPM /// admission fence requires and the TPM shared-provider effects mint /// their `VmId` from. A Device with no Guest owner is the genuinely /// unresolvable case and refuses by name; absence and an unanswerable @@ -2934,7 +2934,7 @@ mod tests { /// The Guest-owner resolution reads the pre-v3 plane only for a Guest /// owner whose row carries no linked uid; a linked uid always wins (the - /// old composer's precedence: `record.resource.owner_uid` first, the + /// old composer's precedence: `record. resource. owner_uid` first, the /// owner identity cache second), and a non-Guest owner never reaches the /// Guest plane. Without a wired source the slot stays unbound, so the /// launch still refuses closed. diff --git a/packages/d2b-provider-process/src/effects_service.rs b/packages/d2b-provider-process/src/effects_service.rs index a13c7bc11..81c4e31e2 100644 --- a/packages/d2b-provider-process/src/effects_service.rs +++ b/packages/d2b-provider-process/src/effects_service.rs @@ -483,7 +483,7 @@ pub struct ProcessEffectsServiceFactory { } impl ProcessEffectsServiceFactory { - /// Build the factory from one zone's facet set。 + /// Build the factory from one zone's facet set. pub fn new(facets: ProcessEffectFacets) -> Self { Self { facets } } diff --git a/packages/d2b-provider-process/src/launch_identity.rs b/packages/d2b-provider-process/src/launch_identity.rs index 88b43e6ce..7b4a23f95 100644 --- a/packages/d2b-provider-process/src/launch_identity.rs +++ b/packages/d2b-provider-process/src/launch_identity.rs @@ -24,7 +24,7 @@ const GUEST_RUNTIME_PROCESS_TEMPLATES: &[(&str, &str)] = &[ /// the identity on its own. pub struct LaunchRow<'a> { /// The row's semantic owner (manager owner key, or the authored - /// `metadata.ownerRef` for an owner the manager does not hold). + /// `metadata. ownerRef` for an owner the manager does not hold). pub owner_ref: Option<&'a ResourceRef>, /// The durable owner linkage the row persists. pub owner_uid: Option, diff --git a/packages/d2b-provider-process/src/operations.rs b/packages/d2b-provider-process/src/operations.rs index 80eb1fa5d..eab9bdfc3 100644 --- a/packages/d2b-provider-process/src/operations.rs +++ b/packages/d2b-provider-process/src/operations.rs @@ -1563,7 +1563,7 @@ fn zone_bundle_for_uid<'a>( Some((zone.as_str().to_owned(), bytes)) } -/// The authored `metadata.ownerRef` of one row of a verified Zone resource +/// The authored `metadata. ownerRef` of one row of a verified Zone resource /// bundle, parsed into a canonical reference. fn row_owner_ref(bundle_bytes: &[u8], resource_type: &str, name: &str) -> Option { let bundle: serde_json::Value = serde_json::from_slice(bundle_bytes).ok()?; @@ -1619,7 +1619,7 @@ fn binds_runtime_socket(role: &ProcessRole) -> bool { /// Pin the Device scope of one Device-owned worker launch. /// /// The launched row is resolved from the verified Zone resource bundle the -/// request's `zone_uid` names (`Process.metadata.ownerRef`), that owner must +/// request's `zone_uid` names (`Process. metadata. ownerRef`), that owner must /// be a `Device`, `owner_ref` must be exactly it, and `owner_uid` must be /// that Device row's durable uid. Only then is the Device's declared Guest /// read. Every refusal is fail-closed (the retired broker arm's diff --git a/packages/d2b-provider-provider/src/driver.rs b/packages/d2b-provider-provider/src/driver.rs index 75ecb0ac4..13c922a38 100644 --- a/packages/d2b-provider-provider/src/driver.rs +++ b/packages/d2b-provider-provider/src/driver.rs @@ -96,7 +96,7 @@ const PROVIDER_CONVERGENCE_POLL: Duration = Duration::from_millis(1_000); /// /// Derived from the placement contract: `Provider` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so a Provider row never -/// carries the canonical `spec.executionRef` and the plane reconciles it on +/// carries the canonical `spec. executionRef` and the plane reconciles it on /// its own Host domain. const PROVIDER_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -120,8 +120,8 @@ const PROVIDER_READS: &[WellKnownType] = &[ /// Typed in-memory status projection (R11: never persisted). /// /// The old plane persisted `phase`, `observedGeneration`, the -/// `status.resource.providerReadiness` projection, and the store-derived -/// `status.resource.owned.refs` list. Nothing durable replaces them: the +/// `status. resource. providerReadiness` projection, and the store-derived +/// `status. resource. owned. refs` list. Nothing durable replaces them: the /// generation the old `Enable`/`Update` short-circuit read and the projected /// phase are kept here, the readiness fields stay on the typed /// [`ProviderObservation`], and the last observed owned `Volume` references @@ -131,7 +131,7 @@ const PROVIDER_READS: &[WellKnownType] = &[ #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProviderDriverStatus { /// The desired generation this observation was taken at (the old - /// `status.observedGeneration`). + /// `status. observedGeneration`). pub observed_generation: u64, /// The phase the pure policy projected. pub phase: ProviderPhase, @@ -149,7 +149,7 @@ pub struct ProviderDriverStatus { /// The live evidence the `Provider` observation needs and the manager cannot /// serve: a converted row's status is in-memory only (R11), so the manager's /// view carries the closed [`ResourceStatus`] and never the controller-session -/// evidence the pure core reads as `status.resource.controllerSession`. The +/// evidence the pure core reads as `status. resource. controllerSession`. The /// production implementation is the daemon's live-session seam; every unknown /// fails closed (`None`), so no caller can synthesize an admitted session. pub trait ProviderDriverEffects: Send + Sync + 'static { @@ -348,7 +348,7 @@ impl ProviderDriver { .dependencies(ctx, &provider_ref, &provider_uid, generation) .await?; - // The old `status.observedGeneration` short-circuit selected the + // The old `status. observedGeneration` short-circuit selected the // `Enable` intent; the in-memory status is its runtime-only successor. let previous = ctx.status::(); let intent = match previous { @@ -361,7 +361,7 @@ impl ProviderDriver { // The provider row as the pure observation reads it: spec from the // stored envelope, metadata as authored, and the previous // observation's owned Volume references standing in for the durable - // `status.resource.owned.refs` projection the store used to derive. + // `status. resource. owned. refs` projection the store used to derive. let metadata: Value = serde_json::from_slice(ctx.metadata()) .map_err(|_| spec_invalid(DriverOp::Reconcile, "spec/metadata"))?; let status = match previous { @@ -524,7 +524,7 @@ impl ProviderDriver { // The manager's ownership is authoritative (R8): a row listed as this // Provider's child carries the Provider reference in the synthesized // payload, because the pure core reads ownership from - // `metadata.ownerRef`, not from the manager. + // `metadata. ownerRef`, not from the manager. metadata.as_object_mut()?.insert( "ownerRef".to_owned(), Value::String(provider_ref.to_owned()), @@ -677,7 +677,7 @@ fn resource_uid(bytes: &[u8; 16]) -> Option { /// through this declaration. /// /// The type is not exportable: `ResourceExport` admits only qualified -/// `*.d2bus.org.*Service` types, so a Provider row is never an export subject. +/// `*.d2bus. org.*Service` types, so a Provider row is never an export subject. pub fn provider_descriptor(args: ProviderDriverArgs) -> DriverDescriptor { DriverDescriptor { resource_type: WellKnownType::PROVIDER, diff --git a/packages/d2b-provider-role/src/rbac.rs b/packages/d2b-provider-role/src/rbac.rs index 5ad2eff54..6ce658b06 100644 --- a/packages/d2b-provider-role/src/rbac.rs +++ b/packages/d2b-provider-role/src/rbac.rs @@ -87,7 +87,7 @@ impl core::fmt::Debug for PositiveDecisionCache { } impl PositiveDecisionCache { - /// Construct a bounded positive-only cache.max_entries = 0 + /// Construct a bounded positive-only cache. max_entries = 0 /// disables caching entirely. pub fn new(max_entries: usize) -> Self { Self { diff --git a/packages/d2b-provider-shell-terminal/src/resources/pool.rs b/packages/d2b-provider-shell-terminal/src/resources/pool.rs index 267317c14..e98eaad34 100644 --- a/packages/d2b-provider-shell-terminal/src/resources/pool.rs +++ b/packages/d2b-provider-shell-terminal/src/resources/pool.rs @@ -1,4 +1,4 @@ -//! `shell-terminal.d2bus.org.ShellPool` schema. +//! `shell-terminal. d2bus. org.ShellPool` schema. use super::{ShellTerminalError, validate_name}; diff --git a/packages/d2b-provider-shell-terminal/src/resources/session.rs b/packages/d2b-provider-shell-terminal/src/resources/session.rs index 9b709a4ee..c7f6c1811 100644 --- a/packages/d2b-provider-shell-terminal/src/resources/session.rs +++ b/packages/d2b-provider-shell-terminal/src/resources/session.rs @@ -1,4 +1,4 @@ -//! `shell-terminal.d2bus.org.ShellSession` schema. +//! `shell-terminal. d2bus. org.ShellSession` schema. use super::{ShellPool, ShellTerminalError, validate_name}; use crate::resources::ExecutionTarget; diff --git a/packages/d2b-provider-supervisor/src/broker.rs b/packages/d2b-provider-supervisor/src/broker.rs index f26ab791f..edc0ca360 100644 --- a/packages/d2b-provider-supervisor/src/broker.rs +++ b/packages/d2b-provider-supervisor/src/broker.rs @@ -1172,7 +1172,7 @@ impl BrokerProcessBackend { } } -// Sync by construction:the ledger sits behind the sync trait surface;the +// Sync by construction:the ledger sits behind the sync trait surface; the // shared helper's critical section is short and never held across a suspension // point. fn record(&self, observed: BrokerObservedProcess) -> Result<(), ProcessEffectError> { diff --git a/packages/d2b-provider-supervisor/src/systemd.rs b/packages/d2b-provider-supervisor/src/systemd.rs index 557b3aee5..969d658bd 100644 --- a/packages/d2b-provider-supervisor/src/systemd.rs +++ b/packages/d2b-provider-supervisor/src/systemd.rs @@ -233,7 +233,7 @@ impl SystemdProcessBackend { } } - // Sync by construction:the ledger sits behind the sync trait surface;the + // Sync by construction:the ledger sits behind the sync trait surface; the // shared helper's critical section is short and never held across a suspension // point. fn record(&self, identity: SystemdInvocationIdentity) -> Result<(), ProcessEffectError> { diff --git a/packages/d2b-provider-system-core/src/error.rs b/packages/d2b-provider-system-core/src/error.rs index ad3370263..17eea0eac 100644 --- a/packages/d2b-provider-system-core/src/error.rs +++ b/packages/d2b-provider-system-core/src/error.rs @@ -28,7 +28,7 @@ pub enum SystemCoreError { CapabilityMissing, /// The kernel is below the mandatory system-minijail floor. KernelTooOld, - /// The delegated cgroup leaf has no writable cgroup.kill. + /// The delegated cgroup leaf has no writable cgroup. kill. CgroupKillUnavailable, } diff --git a/packages/d2b-provider-system-core/src/host.rs b/packages/d2b-provider-system-core/src/host.rs index bae66801d..834c415f2 100644 --- a/packages/d2b-provider-system-core/src/host.rs +++ b/packages/d2b-provider-system-core/src/host.rs @@ -100,7 +100,7 @@ pub struct MinijailPlatformGate { pub kernel_major: u16, /// Minor Linux kernel version observed by the probe. pub kernel_minor: u16, - /// Whether the runtime cgroup exposes cgroup.kill. + /// Whether the runtime cgroup exposes cgroup. kill. pub cgroup_kill_available: bool, } @@ -125,7 +125,7 @@ impl MinijailPlatformGate { /// /// Returns [`SystemCoreError::KernelTooOld`] when the kernel is below the /// mandatory floor and [`SystemCoreError::CgroupKillUnavailable`] when - /// the delegated cgroup leaf has no writable `cgroup.kill`. + /// the delegated cgroup leaf has no writable `cgroup. kill`. pub fn validate(self) -> Result<(), SystemCoreError> { if !self.kernel_supported() { return Err(SystemCoreError::KernelTooOld); @@ -320,7 +320,7 @@ impl HostReconciler { /// Reconcile one Host resource into its public status. /// - /// `provider_ref` is the resource's declared `spec.providerRef`. A Host + /// `provider_ref` is the resource's declared `spec. providerRef`. A Host /// naming another Provider is refused rather than reconciled, because /// `Provider/system-core` is the only Provider the Host contract admits /// and reconciling a foreign Host would be exactly the bootstrap diff --git a/packages/d2b-provider-system-core/src/lib.rs b/packages/d2b-provider-system-core/src/lib.rs index 3a28a66d5..7478b1a07 100644 --- a/packages/d2b-provider-system-core/src/lib.rs +++ b/packages/d2b-provider-system-core/src/lib.rs @@ -58,7 +58,7 @@ pub const PROVIDER_NAME: &str = "system-core"; /// The canonical `Provider/system-core` reference. /// -/// This is the only value admitted by `Host.spec.providerRef`, and it is +/// This is the only value admitted by `Host. spec. providerRef`, and it is /// the same constant the Host primitive contract pins. pub const PROVIDER_REF: &str = d2b_contracts_resource::v3::host::HOST_PROVIDER_REF; diff --git a/packages/d2b-provider-system-core/src/testing.rs b/packages/d2b-provider-system-core/src/testing.rs index 544cf84df..fb6e58191 100644 --- a/packages/d2b-provider-system-core/src/testing.rs +++ b/packages/d2b-provider-system-core/src/testing.rs @@ -130,8 +130,8 @@ pub mod fixtures { /// /// It is deliberately different from the `User/alice` resource name, so /// a redaction assertion can tell the two apart. The split is the one - /// the User primitive contract describes: `metadata.name` is the - /// Zone-local key and `spec.osUsername` is what NSS resolves. + /// the User primitive contract describes: `metadata. name` is the + /// Zone-local key and `spec. osUsername` is what NSS resolves. pub const OS_USERNAME: &str = "alice_admin"; /// A User spec declaring no additional groups. diff --git a/packages/d2b-provider-telemetry-binding/src/driver.rs b/packages/d2b-provider-telemetry-binding/src/driver.rs index 49268e894..c56c649ea 100644 --- a/packages/d2b-provider-telemetry-binding/src/driver.rs +++ b/packages/d2b-provider-telemetry-binding/src/driver.rs @@ -9,7 +9,7 @@ //! section 13 mapping): //! //! - `describe` -> [`TelemetryBindingDriverFactory`], registered for -//! `telemetry.d2bus.org.TelemetryBinding` in the plane's provider directory. +//! `telemetry. d2bus. org.TelemetryBinding` in the plane's provider directory. //! - `validate_spec` -> [`ResourceDriver::validate`]: the stored spec envelope //! must decode. A malformed Service/target relationship is fenced in //! reconcile (old `telemetry_binding_owner`), never fatal here. @@ -24,7 +24,7 @@ //! writes). //! - `prepare_finalize` + `execute_finalize` + `finalize` -> //! [`ResourceDriver::delete`]. The old -//! `d2b.d2bus.org/binding-children` finalizer is gone by construction: the +//! `d2b. d2bus. org/binding-children` finalizer is gone by construction: the //! v3 manager already holds a parent row until its owned children retire //! (`ResourceManagerState::remove_internal` cascades the removal to owned //! children and `pending_retirement` keeps the parent's durable deleting @@ -610,7 +610,7 @@ fn teardown_rank(resource_type: &str) -> u8 { /// /// Derived from the placement contract: `TelemetryBinding` names no placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a Binding row -/// never carries the canonical `spec.executionRef` and the plane reconciles it +/// never carries the canonical `spec. executionRef` and the plane reconciles it /// on its own Host domain. The Provider declares every child host-placed, so /// the declared set is realized from that same domain. const TELEMETRY_BINDING_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -633,7 +633,7 @@ const TELEMETRY_BINDING_READS: &[WellKnownType] = &[ /// `TelemetryBinding` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane /// cannot serve the Zone's telemetry producers without it, so it must be /// registered before the plane opens. The type is not exportable: -/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a /// binding can never be an export subject. The driver serves no broker /// operations and declares the two child creations it performs - the /// collector/forwarder Process and its Endpoint. diff --git a/packages/d2b-provider-telemetry-binding/src/lib.rs b/packages/d2b-provider-telemetry-binding/src/lib.rs index c44ef7a94..258dca3e6 100644 --- a/packages/d2b-provider-telemetry-binding/src/lib.rs +++ b/packages/d2b-provider-telemetry-binding/src/lib.rs @@ -1,7 +1,7 @@ //! The TelemetryBinding resource type's driver, its spec decoder, and its //! driver declaration. //! -//! The crate owns the `telemetry.d2bus.org.TelemetryBinding` type's complete +//! The crate owns the `telemetry. d2bus. org.TelemetryBinding` type's complete //! resource knowledge: the relationship admission (the owner must name the //! telemetry Provider and its Service/target rows must exist and not be //! deleting), the provider-declared child set materialized as owned manager diff --git a/packages/d2b-provider-telemetry-service/src/driver.rs b/packages/d2b-provider-telemetry-service/src/driver.rs index 659feb84f..7d3a88fd0 100644 --- a/packages/d2b-provider-telemetry-service/src/driver.rs +++ b/packages/d2b-provider-telemetry-service/src/driver.rs @@ -7,7 +7,7 @@ //! `TelemetryResourceReconciler`'s Service half (spec section 13 mapping): //! //! - `describe` -> [`TelemetryServiceDriverFactory`], registered for -//! `telemetry.d2bus.org.TelemetryService` in the plane's provider directory. +//! `telemetry. d2bus. org.TelemetryService` in the plane's provider directory. //! - `validate_spec` -> [`ResourceDriver::validate`]: the stored spec envelope //! must decode. //! - `observe` -> [`ResourceDriver::recover`]: a Service realizes nothing on a @@ -19,7 +19,7 @@ //! route that is not materialized yet re-schedules the preserved resync. //! - `prepare_finalize` + `execute_finalize` + `finalize` -> //! [`ResourceDriver::delete`]. The old -//! `d2b.d2bus.org/binding-children` finalizer is gone by construction: the +//! `d2b. d2bus. org/binding-children` finalizer is gone by construction: the //! v3 manager already holds a parent row until its owned children retire, //! and a Service owns none. @@ -60,7 +60,7 @@ pub const PHASE_DEGRADED: &str = "Degraded"; /// The readiness term of the preserved phase predicate. /// /// CONTRACT FLAG: the term reads a dependency's observed status (an ingest -/// Endpoint's `status.phase`), which the KTD3 driver surface does not expose. +/// Endpoint's `status. phase`), which the KTD3 driver surface does not expose. /// It evaluates fail-closed until the surface carries observed state, so /// `Ready` is never claimed without evidence. pub const DEPENDENCY_READINESS_PROVEN: bool = false; @@ -379,7 +379,7 @@ impl ResourceDriver for TelemetryServiceDriver { type Error = TelemetryServiceDriverError; fn classify_error(&self, error: &TelemetryServiceDriverError) -> DriverFailure { - // The old reconciler classified every failure retryable;the actor + // The old reconciler classified every failure retryable; the actor // owns retry/backoff from the closed class (R13). match error.source() { Some(source) => DriverFailure::retryable(error.op) @@ -458,7 +458,7 @@ fn ingest_endpoint_refs( /// /// Derived from the placement contract: `TelemetryService` names no placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a Service row -/// never carries the canonical `spec.executionRef` and the plane reconciles it +/// never carries the canonical `spec. executionRef` and the plane reconciles it /// on its own Host domain. const TELEMETRY_SERVICE_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -473,7 +473,7 @@ const TELEMETRY_SERVICE_READS: &[WellKnownType] = &[WellKnownType::ENDPOINT]; /// `TelemetryService` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane /// cannot serve the Zone's telemetry authority without it, so it must be /// registered before the plane opens. The type is exportable: the qualified -/// `telemetry.d2bus.org.TelemetryService` is exactly the shape +/// `telemetry. d2bus. org.TelemetryService` is exactly the shape /// `ResourceExport` admits. The driver serves no broker operations and owns /// no child, so it declares no creation. pub fn telemetry_service_descriptor() -> DriverDescriptor { @@ -687,7 +687,7 @@ mod tests { assert_eq!(status.present_endpoints.len(), 1); assert_eq!(status.projection.as_ref().unwrap().service_role, "authority"); // CONTRACT FLAG: the old predicate also required the ingest - // Endpoint's own `status.phase == "Ready"`, which this surface cannot + // Endpoint's own `status. phase == "Ready"`, which this surface cannot // read; the phase stays fail-closed Pending while the row exists. assert_eq!(status.phase, TelemetryServicePhase::Pending); assert_eq!( diff --git a/packages/d2b-provider-telemetry-service/src/lib.rs b/packages/d2b-provider-telemetry-service/src/lib.rs index 1c69dfcaf..1a5997888 100644 --- a/packages/d2b-provider-telemetry-service/src/lib.rs +++ b/packages/d2b-provider-telemetry-service/src/lib.rs @@ -1,7 +1,7 @@ //! The TelemetryService resource type's driver, its spec decoder, and its //! driver declaration. //! -//! The crate owns the `telemetry.d2bus.org.TelemetryService` type's complete +//! The crate owns the `telemetry. d2bus. org.TelemetryService` type's complete //! resource knowledge: the observed-phase projection the old reconciler //! published, the admission rule over the spec's declared `serviceRole`, the //! driver's validate, recover, reconcile, and delete verbs, and the @@ -12,7 +12,7 @@ //! durable ingest-`Endpoint` rows reconcile re-reads, and it owns no child, so //! the crate declares no effect port and no child creation. The telemetry //! Serving Provider stays the authority for what a Service *means* - the -//! `telemetry.d2bus.org.TelemetryService` contract this crate keys on lives in +//! `telemetry. d2bus. org.TelemetryService` contract this crate keys on lives in //! `d2b-contracts-provider`, beside the sibling Binding type. //! //! # Contract flag (KTD3 fit; preserved from the daemon-side conversion) diff --git a/packages/d2b-provider-toolkit/src/shared_provider.rs b/packages/d2b-provider-toolkit/src/shared_provider.rs index 41aefb475..015342b36 100644 --- a/packages/d2b-provider-toolkit/src/shared_provider.rs +++ b/packages/d2b-provider-toolkit/src/shared_provider.rs @@ -17,7 +17,7 @@ //! actor exists, F1), owned children the desired set no longer derives are //! retired in the family's preserved order, the typed Provider effect runs //! behind the family's port, and the in-memory status projection is -//! published with `ctx.set_status` (R11) plus a self-`requeue_after` while +//! published with `ctx. set_status` (R11) plus a self-`requeue_after` while //! the family is not converged; //! - `prepare_finalize`/`execute_finalize`/`finalize` -> //! [`ResourceDriver::delete`]: the family's teardown stage runs behind the @@ -35,7 +35,7 @@ //! observable from an effect through [`SharedProviderChildSurface::view`], //! which reads the manager plane's live view for a row of the driving //! resource; the driver itself only registers -//! `ctx.watch(.., WatchCondition::Ready)` edges so dependency and child +//! `ctx. watch(.., WatchCondition::Ready)` edges so dependency and child //! readiness wake it, and it never fabricates a readiness it cannot observe. use std::sync::Arc; @@ -180,12 +180,12 @@ pub enum SharedProviderEffectPhase { } /// One Provider effect outcome: the phase the old effect returned plus the -/// `status.resource` projection the old status candidate published. +/// `status. resource` projection the old status candidate published. #[derive(Debug, Clone, PartialEq, Eq)] pub struct SharedProviderEffectOutcome { /// The phase the effect returned. pub phase: SharedProviderEffectPhase, - /// The `status.resource` projection the old status candidate published. + /// The `status. resource` projection the old status candidate published. pub resource_projection: Option, } @@ -198,7 +198,7 @@ impl SharedProviderEffectOutcome { } } - /// A phase outcome carrying one `status.resource` projection. + /// A phase outcome carrying one `status. resource` projection. pub fn projection(phase: SharedProviderEffectPhase, resource_projection: Value) -> Self { Self { phase, @@ -306,12 +306,12 @@ impl std::error::Error for SharedProviderDriverError {} /// Typed in-memory status projection (R11: never persisted). Carries the /// closed phase the old status candidate published plus the Provider's -/// `status.resource` projection. +/// `status. resource` projection. #[derive(Debug, Clone, PartialEq, Eq)] pub struct SharedProviderDriverStatus { /// The phase the effect published. pub phase: SharedProviderEffectPhase, - /// The Provider's `status.resource` projection. + /// The Provider's `status. resource` projection. pub resource: Option, } diff --git a/packages/d2b-provider-toolkit/src/testing/conformance.rs b/packages/d2b-provider-toolkit/src/testing/conformance.rs index 9985dd927..f1ba93abc 100644 --- a/packages/d2b-provider-toolkit/src/testing/conformance.rs +++ b/packages/d2b-provider-toolkit/src/testing/conformance.rs @@ -4,7 +4,7 @@ //! `ResourceApiBinding` to implement the exact base spec and status schema //! version and fingerprint the installed ResourceType contract declares, to //! accept the canonical minimal valid base spec without a -//! `spec.provider` extension, and to refuse an optional base capability +//! `spec. provider` extension, and to refuse an optional base capability //! only through its signed capability matrix and the provider-neutral //! `unsupported-capability` result. //! @@ -296,7 +296,7 @@ pub fn check_descriptor_conformance( /// Live conformance for one binding: the Provider advertises the installed /// base schema identity, and the canonical minimal valid base spec is -/// accepted without any `spec.provider` extension. +/// accepted without any `spec. provider` extension. /// /// # Errors /// diff --git a/packages/d2b-provider-transport-azure-relay/src/auth.rs b/packages/d2b-provider-transport-azure-relay/src/auth.rs index eb144f323..c2e7f02dd 100644 --- a/packages/d2b-provider-transport-azure-relay/src/auth.rs +++ b/packages/d2b-provider-transport-azure-relay/src/auth.rs @@ -56,9 +56,9 @@ impl RelayRole { /// (hybrid connection) name. Non-secret. #[derive(Clone, PartialEq, Eq)] pub struct RelayEndpoint { - /// Namespace FQDN, e.g. `relns-xxxx.servicebus.windows.net`. + /// Namespace FQDN, e. g. `relns-xxxx. servicebus. windows. net`. pub namespace: String, - /// Hybrid connection (entity) name, e.g. `hc-d2b-display`. + /// Hybrid connection (entity) name, e. g. `hc-d2b-display`. pub entity: String, } @@ -80,7 +80,7 @@ pub enum RelayCredential { /// Gateway Guest-side (the Listen rule), and transitionally for non-MI /// senders. Sas { - /// The authorization-rule (key) name, e.g. `gateway-listen`. + /// The authorization-rule (key) name, e. g. `gateway-listen`. key_name: String, /// The rule's key. Secret. key: String, diff --git a/packages/d2b-provider-transport-vsock/src/settings.rs b/packages/d2b-provider-transport-vsock/src/settings.rs index 37c6ec039..5d8e80f25 100644 --- a/packages/d2b-provider-transport-vsock/src/settings.rs +++ b/packages/d2b-provider-transport-vsock/src/settings.rs @@ -1,4 +1,4 @@ -//! Closed `ZoneLink.spec.transportSettings` validation. +//! Closed `ZoneLink. spec. transportSettings` validation. use serde::{Deserialize, Serialize}; use std::fmt; diff --git a/packages/d2b-provider-user/src/driver.rs b/packages/d2b-provider-user/src/driver.rs index ec3df3576..fca2cbafb 100644 --- a/packages/d2b-provider-user/src/driver.rs +++ b/packages/d2b-provider-user/src/driver.rs @@ -20,10 +20,10 @@ //! over the [`UserDriverEffects`] discovery port. //! - `finalize` -> [`ResourceDriver::delete`] (old `FinalizeResult` was //! converged: the family owns no children and carries no finalizer). -//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). //! //! Deliberately not carried from the old handler: the durable -//! `status.resource` JSON projection and its `lastReconciledAt` / +//! `status. resource` JSON projection and its `lastReconciledAt` / //! `observedGeneration` writes (status is runtime-only now, R11), and the //! `assess_update` / `plan_upgrade` runner path (no driver equivalent; the //! family never planned an upgrade). The old runner's 5s resync relisted and @@ -126,7 +126,7 @@ impl std::error::Error for UserDriverError {} /// Typed in-memory status projection (R11: never persisted). /// /// The discovery is kept with the generation it was taken at, which is the -/// runtime-only successor of the old durable `status.observedGeneration` +/// runtime-only successor of the old durable `status. observedGeneration` /// plan short-circuit. #[derive(Debug, Clone, PartialEq, Eq)] pub struct UserDriverStatus { @@ -390,11 +390,11 @@ impl ResourceDriver for UserDriver { /// `User` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve the /// converted bootstrap rows without it, so it must be registered before the /// plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus.org.*Service` types. The driver serves no broker +/// qualified `*.d2bus. org.*Service` types. The driver serves no broker /// operations, creates no children, and reads no other resource: discovery /// reaches the local machine through the family's own probe. `User` names /// no placement anchor, so a User row never carries the canonical -/// `spec.executionRef` and the plane reconciles it on its own Host domain - +/// `spec. executionRef` and the plane reconciles it on its own Host domain - /// the machine whose local identity it names. /// /// U5: the declaration builds the family's own effects implementation from diff --git a/packages/d2b-provider-volume-binding/src/driver.rs b/packages/d2b-provider-volume-binding/src/driver.rs index deff835c1..ca15e8dbc 100644 --- a/packages/d2b-provider-volume-binding/src/driver.rs +++ b/packages/d2b-provider-volume-binding/src/driver.rs @@ -31,7 +31,7 @@ //! - `observe` -> [`ResourceDriver::recover`]. //! - `binding_children` minting + readiness -> [`ResourceDriver::reconcile`]. //! - `finalize_binding` drain + endpoint-first teardown -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx.set_status` (in-memory only). +//! - `UpdateStatus` -> `ctx. set_status` (in-memory only). //! //! Everything the driver needs from outside arrives through the driver //! effect port ([`BindingDriverEffects`]): the serving socket probe, the @@ -736,7 +736,7 @@ impl BindingDriver { // Host/host-system) and as the signed `virtiofsd-worker` template // the launch ticket resolves through binds it: the template's // execution_ref is the volume-virtiofs Provider's - // config.controllerExecutionRef. The attachment's Guest stays the + // config. controllerExecutionRef. The attachment's Guest stays the // ticket's target ref (KTD7), re-derived from the owning VolumeBinding // row by the Process driver's identity path. let process_spec = serde_json::json!({ @@ -957,7 +957,7 @@ impl ResourceDriver for BindingDriver { .expect("the fenced binding projection is always serializable"), ); if mutated || !socket_ready { - // The child rows were (re)committed this pass, or the socket is + // The child rows were (re) committed this pass, or the socket is // not serving yet: re-check on the preserved resync cadence (the // Runner contract's repair interval) - the same shape the Guest // driver uses while its Provider phase is not Ready, so a @@ -1076,7 +1076,7 @@ impl ResourceDriver for BindingDriver { /// /// Derived from the placement contract: `VolumeBinding` names no placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a binding row -/// never carries the canonical `spec.executionRef` and the plane reconciles +/// never carries the canonical `spec. executionRef` and the plane reconciles /// it on its containing Zone's Host. The attachment's `executionRef` selects /// the Guest that consumes the share, never where the binding row itself is /// reconciled. @@ -1094,7 +1094,7 @@ const BINDING_READS: &[WellKnownType] = &[WellKnownType::VOLUME]; /// `VolumeBinding` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot /// serve the converted binding shapes without it, so it must be registered /// before the plane opens. The type is not exportable: `ResourceExport` -/// admits only qualified `*.d2bus.org.*Service` types, so a binding can never +/// admits only qualified `*.d2bus. org.*Service` types, so a binding can never /// be an export subject. The driver serves no broker operations and /// contributes no startup steps; the worker Process and Endpoint children it /// mints are declared in [`BINDING_CREATIONS`], and the declaration carries diff --git a/packages/d2b-provider-volume-local/src/adapter.rs b/packages/d2b-provider-volume-local/src/adapter.rs index 86d759550..747d19de8 100644 --- a/packages/d2b-provider-volume-local/src/adapter.rs +++ b/packages/d2b-provider-volume-local/src/adapter.rs @@ -1266,7 +1266,7 @@ fn apply_metadata( // POSIX ACL application // // The declared grants are real kernel ACLs: the daemon owns the entry it -// creates, so it applies them through the `system.posix_acl_*` xattrs without +// creates, so it applies them through the `system. posix_acl_*` xattrs without // any capability. The encoding is the kernel's `posix_acl_xattr_header` + // `posix_acl_xattr_entry` layout, and the mask carries the group-class // permissions exactly as `setfacl` computes it - the kernel requires the mask @@ -1356,7 +1356,7 @@ fn acl_entries(mode: u32, mut named: Vec) -> Vec { entries } -/// Encode one entry set as the `system.posix_acl_*` xattr value. +/// Encode one entry set as the `system. posix_acl_*` xattr value. fn acl_xattr_bytes(entries: &[AclEntry]) -> Vec { let mut bytes = Vec::with_capacity(4 + entries.len() * 8); bytes.extend_from_slice(&POSIX_ACL_XATTR_VERSION.to_le_bytes()); diff --git a/packages/d2b-provider-volume-local/src/content.rs b/packages/d2b-provider-volume-local/src/content.rs index 4802ae711..3e37805df 100644 --- a/packages/d2b-provider-volume-local/src/content.rs +++ b/packages/d2b-provider-volume-local/src/content.rs @@ -707,7 +707,7 @@ impl NetworkConfigContentProjection { Ok(projection) } - /// Parse and validate a provider `settings.content` object. + /// Parse and validate a provider `settings. content` object. pub fn from_settings(settings: &serde_json::Value) -> Result { let projection: Self = serde_json::from_value(settings.clone()).map_err(|_| VolumeLocalError::InvalidSpec)?; diff --git a/packages/d2b-provider-volume-virtiofs/src/bindings.rs b/packages/d2b-provider-volume-virtiofs/src/bindings.rs index e84cfa5a9..ba02f0e0d 100644 --- a/packages/d2b-provider-volume-virtiofs/src/bindings.rs +++ b/packages/d2b-provider-volume-virtiofs/src/bindings.rs @@ -115,7 +115,7 @@ impl StoredBinding { /// The envelope must be a `VolumeBinding` owned by an existing /// Volume and served by this Provider, and it must be strictly /// neutral: the standard catalog admits no provider extension path - /// for the type, so a `spec.provider` block -- legacy schema id + /// for the type, so a `spec. provider` block -- legacy schema id /// or otherwise -- is rejected, and the envelope never carries /// attachment settings (KTD1). The serving posture is the frozen /// default declared by the worker plan. diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index ef15dcdcf..84f1c3e2d 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -18,7 +18,7 @@ //! - `observe` -> [`ResourceDriver::recover`]. //! - layout effect + `volume_children` ensure -> [`ResourceDriver::reconcile`]. //! - volume-local cleanup -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx.set_status` (in-memory only). +//! - `UpdateStatus` -> `ctx. set_status` (in-memory only). //! //! Everything the driver needs from outside arrives through the driver //! effect port ([`VolumeDriverEffects`]): the layout effect over the @@ -689,7 +689,7 @@ impl ResourceDriver for VolumeDriver { /// /// Derived from the placement contract: `Volume` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so a Volume row never -/// carries the canonical `spec.executionRef` and the plane reconciles it on +/// carries the canonical `spec. executionRef` and the plane reconciles it on /// its containing Zone's Host. A source or attachment reference selects /// where a share is served, never where the row itself is reconciled. const VOLUME_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -705,7 +705,7 @@ const VOLUME_READS: &[WellKnownType] = &[]; /// `Volume` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve /// the converted volume shapes without it, so it must be registered before /// the plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus.org.*Service` types, so a volume can never be an +/// qualified `*.d2bus. org.*Service` types, so a volume can never be an /// export subject. The driver serves no broker operations and contributes no /// startup steps; the `VolumeBinding` children it mints are declared in /// [`VOLUME_CREATIONS`]. diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index d29cac356..d738f5cdb 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -535,7 +535,7 @@ fn decode_spec( .map_err(|error| AudioResourceRuntimeError::InvalidSpec(error.to_string())) } -/// The `status.resource` projection for one AudioBinding (old +/// The `status. resource` projection for one AudioBinding (old /// `audio_binding_status_projection_with_status`): the typed channel status /// plus the realized Process/Endpoint references the driver owns. pub(crate) fn audio_binding_projection( diff --git a/packages/d2b-provider-wayland-policy/src/effects_service.rs b/packages/d2b-provider-wayland-policy/src/effects_service.rs index f0f41111a..51484350b 100644 --- a/packages/d2b-provider-wayland-policy/src/effects_service.rs +++ b/packages/d2b-provider-wayland-policy/src/effects_service.rs @@ -597,7 +597,7 @@ fn envelope_spec_document(value: &Value) -> Value { } } -/// The base spec with `spec.providerRef` re-inserted (the typed audio specs +/// The base spec with `spec. providerRef` re-inserted (the typed audio specs /// carry the field; old `AudioResourceRuntime::decode_spec` re-inserted it /// after the envelope split). fn spec_with_provider_ref( @@ -703,7 +703,7 @@ fn map_audio_effect_error(error: AudioResourceRuntimeError) -> InteractionEffect } } -/// The old `status.resource` projection for a display session (old +/// The old `status. resource` projection for a display session (old /// `display_resource_projection`): the two worker Process references and the /// private Endpoint with its committed generation. fn display_projection( diff --git a/packages/d2b-provider-wayland-policy/src/interaction.rs b/packages/d2b-provider-wayland-policy/src/interaction.rs index e86fb6f6c..5976532ac 100644 --- a/packages/d2b-provider-wayland-policy/src/interaction.rs +++ b/packages/d2b-provider-wayland-policy/src/interaction.rs @@ -84,17 +84,17 @@ pub enum InteractionEffectPhase { } /// One Provider effect outcome: the phase the effect returned plus the -/// `status.resource` projection the effect publishes. +/// `status. resource` projection the effect publishes. #[derive(Debug, Clone, PartialEq, Eq)] pub struct InteractionEffectOutcome { /// The convergence phase of the row. pub phase: InteractionEffectPhase, - /// The optional `status.resource` projection. + /// The optional `status. resource` projection. pub resource: Option, } impl InteractionEffectOutcome { - /// A phase-only outcome with no `status.resource` projection. + /// A phase-only outcome with no `status. resource` projection. pub const fn phase(phase: InteractionEffectPhase) -> Self { Self { phase, @@ -102,7 +102,7 @@ impl InteractionEffectOutcome { } } - /// A phase outcome carrying the row's `status.resource` projection. + /// A phase outcome carrying the row's `status. resource` projection. pub fn projection(phase: InteractionEffectPhase, resource: Value) -> Self { Self { phase, @@ -201,13 +201,13 @@ impl core::fmt::Display for InteractionDriverError { impl std::error::Error for InteractionDriverError {} /// Typed in-memory status projection (never persisted). Carries the closed -/// phase the effect published plus the Provider's `status.resource` +/// phase the effect published plus the Provider's `status. resource` /// projection. #[derive(Debug, Clone, PartialEq, Eq)] pub struct InteractionDriverStatus { /// Whether the Provider realization is current. pub ready: bool, - /// The Provider's `status.resource` projection, when it published one. + /// The Provider's `status. resource` projection, when it published one. pub resource: Option, } @@ -330,7 +330,7 @@ pub struct InteractionEffectRequest<'a> { /// stripped, so every type decodes its typed spec without re-deriving the /// split. pub spec: Value, - /// The row's `spec.providerRef`. + /// The row's `spec. providerRef`. pub provider_ref: Option, /// Owned child rows realizing the current desired child set. pub children: &'a [InteractionChild], @@ -392,7 +392,7 @@ pub trait InteractionType: Clone + Send + Sync + 'static { const RESOURCE_TYPE: &'static str; /// The Provider reference the type's rows select. const PROVIDER_REF: &'static str; - /// Whether a row's spec must carry the typed universal `spec.providerRef`. + /// Whether a row's spec must carry the typed universal `spec. providerRef`. const SPEC_PROVIDER_SELECTOR: bool; /// The preserved reconcile resync cadence of the type: the Provider's diff --git a/packages/d2b-provider-zone-link/src/zone_links.rs b/packages/d2b-provider-zone-link/src/zone_links.rs index a0459256f..fbda037b9 100644 --- a/packages/d2b-provider-zone-link/src/zone_links.rs +++ b/packages/d2b-provider-zone-link/src/zone_links.rs @@ -63,10 +63,10 @@ pub use d2b_contracts_zone_session::v3::zone_session::{ BOOTSTRAP_PSK_TTL_MS_DEFAULT, KK_SESSION_MAX_LIFETIME_MS_DEFAULT, }; -/// Admission ceiling for `spec.limits.maxPendingIntents`. +/// Admission ceiling for `spec. limits. maxPendingIntents`. pub const MAX_PENDING_LOCAL_INTENTS: u32 = 1024; -/// Admission ceiling for `spec.limits.maxActiveStreams`. +/// Admission ceiling for `spec. limits. maxActiveStreams`. pub const MAX_ACTIVE_STREAMS: u32 = 128; /// Maximum committed route-admission operation IDs retained for one immutable @@ -250,7 +250,7 @@ impl core::fmt::Display for ZoneLinkError { impl std::error::Error for ZoneLinkError {} -/// Bounded ZoneLink connection and queue limits from `spec.limits`. +/// Bounded ZoneLink connection and queue limits from `spec. limits`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ZoneLinkLimits { max_pending_intents: u32, @@ -260,7 +260,7 @@ pub struct ZoneLinkLimits { } impl ZoneLinkLimits { - /// Validate one complete `spec.limits` object against its frozen bounds. + /// Validate one complete `spec. limits` object against its frozen bounds. /// /// # Errors /// @@ -995,7 +995,7 @@ impl core::fmt::Debug for ZoneLinkRecord { } } -/// The D088 `status.resource` projection written by the child-local handler. +/// The D088 `status. resource` projection written by the child-local handler. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ZoneLinkStatus { phase: ZoneLinkPhase, @@ -1282,7 +1282,7 @@ impl ZoneLinkHandler { self.key_policy } - /// Project the current D088 `status.resource` observation. + /// Project the current D088 `status. resource` observation. pub fn status(&self) -> ZoneLinkStatus { ZoneLinkStatus { phase: self.phase, diff --git a/packages/d2b-provider/src/agent.rs b/packages/d2b-provider/src/agent.rs index 9319485f9..274c4b97a 100644 --- a/packages/d2b-provider/src/agent.rs +++ b/packages/d2b-provider/src/agent.rs @@ -288,7 +288,7 @@ where /// # Errors /// /// Returns [`ProviderAgentError::UnsupportedService`] when the request - /// names a service other than `d2b.provider.v3`, + /// names a service other than `d2b. provider. v3`, /// [`ProviderAgentError::DispatchSaturated`] when the in-flight budget /// is exhausted, [`ProviderAgentError::DispatchTimeout`] when the /// request exceeds its timeout, and diff --git a/packages/d2b-resource-api/src/admission.rs b/packages/d2b-resource-api/src/admission.rs index 6a13d0379..3adf61bce 100644 --- a/packages/d2b-resource-api/src/admission.rs +++ b/packages/d2b-resource-api/src/admission.rs @@ -264,7 +264,7 @@ impl AdmissionPermit { /// use d2b_resource_api::AdmittedMutation; /// /// fn inspect(value: &AdmittedMutation) { -/// let _ = &value.mutations; +/// let _ = &value. mutations; /// } /// ``` pub struct AdmittedMutation { diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index 3abbd1b27..5a98e2bd8 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -12,8 +12,8 @@ //! remainder exists, and a cursor that cannot be honoured is refused with //! a typed error rather than ignored; //! - the closed list filters keep their durable-plane semantics, including -//! ownership (`owner.resourceUid` matches the row's resolved owner uid, -//! `owner.resourceRef` the owner reference the row renders); +//! ownership (`owner. resourceUid` matches the row's resolved owner uid, +//! `owner. resourceRef` the owner reference the row renders); //! - mutations admit at the manager boundary under the caller's real //! authenticated subject ([`api_subject`]) and persist through //! `Ensure`/`Remove` with commit-before-return (F1/AE1); @@ -334,7 +334,7 @@ fn check_precondition(mutation: &StoreMutation, row: &StoredDesiredResource) -> } /// The owner reference the row renders, when one is rendered: the authored -/// `metadata.ownerRef` wins (exactly as [`render_envelope`] resolves it), and +/// `metadata. ownerRef` wins (exactly as [`render_envelope`] resolves it), and /// a row without one renders the resolved owner key. Evaluating the filter /// here keeps it on the same value the row's readers see. fn rendered_owner_ref(view: &ResourceView) -> Option { @@ -595,7 +595,7 @@ fn stored_of( generation: u64, spec: &[u8], ) -> StoredResource { - // Rows not created through this backend (e.g. Nix-materialized rows whose + // Rows not created through this backend (e. g. Nix-materialized rows whose // spec the compiler owns) keep their bytes verbatim; the digest is // recomputed only when the spec is a complete resource envelope. let payload_digest = CanonicalJsonValue::parse(spec) @@ -938,7 +938,7 @@ fn stamp_deletion_request(stored: &mut StoredResource) -> Result<(), StoreError> /// /// ```text /// let authorizer = Arc::new(NativeAuthorizer::new(catalog, policy)?); -/// let acceptor = authorizer.take_store_seal(manager_seal_identity())?; +/// let acceptor = authorizer. take_store_seal(manager_seal_identity())?; /// let backend = ManagerBackend::new(client, hub, acceptor); /// let service = ResourceService::new_with_zone_uid(Arc::new(backend), authorizer, zone_uid)?; /// ``` diff --git a/packages/d2b-resource-api/src/manager_backend/tests.rs b/packages/d2b-resource-api/src/manager_backend/tests.rs index a50d6b141..795e07874 100644 --- a/packages/d2b-resource-api/src/manager_backend/tests.rs +++ b/packages/d2b-resource-api/src/manager_backend/tests.rs @@ -555,7 +555,7 @@ async fn create_get_update_delete_round_trip_through_the_manager() { /// Nix-ingested rows persist spec-shaped bytes, so their envelope is /// rendered on the read (the fallback path). The manager view must serve the /// row's stable uid there: the public delete precondition resolves the exact -/// uid from `metadata.uid`, and `ResourceUid`'s redacted `Display` is never +/// uid from `metadata. uid`, and `ResourceUid`'s redacted `Display` is never /// data. A round trip through an API-created row cannot catch this - those /// rows persist envelope-shaped bytes and already carry their uid. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -821,7 +821,7 @@ fn rendered_full_envelopes_keep_the_strict_reader_contract() { /// converted type the API can serve renders through the one producer, and /// each rendered row is a complete strict envelope - with and without a live /// status projection - whose status object is exactly the contract's closed -/// shape and whose `status.resource` layer is the driver's own value carried +/// shape and whose `status. resource` layer is the driver's own value carried /// unchanged. /// /// A type whose rendering lost a required member, wrapped the driver's layer, @@ -1026,7 +1026,7 @@ async fn every_converted_type_is_served_by_the_manager_path() { fixture.manager_actor.get_cell().stop(None); } -/// The converted types whose contracts pin a typed `status.resource` layer +/// The converted types whose contracts pin a typed `status. resource` layer /// decode the served layer through exactly that `deny-unknown-fields` /// decoder: the projection cannot wrap, rename, or nest what the type's /// consumers read. The remaining converted types publish free-form evidence @@ -1040,7 +1040,7 @@ fn converted_type_status_layers_round_trip_through_their_typed_decoders() { use d2b_resource_runtime::spec_store::{ResourceKey, ResourceProvenance}; /// One typed status decoder case: the converted type's name, the served - /// wire `status.resource` value, and the type's decoder. + /// wire `status. resource` value, and the type's decoder. type TypedDecoderCase = ( &'static str, serde_json::Value, @@ -1672,8 +1672,8 @@ async fn list_refuses_a_cursor_it_cannot_honour() { } /// An owner-scoped LIST matches the manager's owned children: the row's real -/// ownership is projected into the store shape, so `owner.resourceUid` and -/// `owner.resourceRef` return the owner's rows instead of an empty page. +/// ownership is projected into the store shape, so `owner. resourceUid` and +/// `owner. resourceRef` return the owner's rows instead of an empty page. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn list_owner_filters_match_manager_owned_children() { diff --git a/packages/d2b-resource-api/src/service.rs b/packages/d2b-resource-api/src/service.rs index a692c66ec..a98fd0b8b 100644 --- a/packages/d2b-resource-api/src/service.rs +++ b/packages/d2b-resource-api/src/service.rs @@ -43,7 +43,7 @@ use crate::{ /// use d2b_resource_api::service::TrustedRequest; /// /// fn forge(request: &TrustedRequest) { -/// let _ = &request.subject; +/// let _ = &request. subject; /// } /// ``` #[derive(Clone)] diff --git a/packages/d2b-resource-compiler/src/lib.rs b/packages/d2b-resource-compiler/src/lib.rs index 3d78f5a6c..62ff34c9f 100644 --- a/packages/d2b-resource-compiler/src/lib.rs +++ b/packages/d2b-resource-compiler/src/lib.rs @@ -12,7 +12,7 @@ //! //! ``` //! let digest = d2b_resource_compiler::sha256_digest(b"provider"); -//! assert_eq!(digest.as_str().len(), 71); +//! assert_eq!(digest. as_str().len(), 71); //! ``` use std::{ @@ -970,7 +970,7 @@ fn append_virtiofsd_worker_templates( /// for `device-tpm`, `Process/gpu-` and `Process/video-` for /// `device-gpu` - each carrying the row's `template` and an `ownerRef` to the /// claiming Device. The declared row is the authority this pass reads: the -/// owner Device's declared `spec.providerRef` names the Device Provider, whose +/// owner Device's declared `spec. providerRef` names the Device Provider, whose /// artifact must enumerate the executable the closed posture for /// (`providerRef`, `template`) pins /// ([`d2b_core::bundle_resolver::device_worker_posture`]), and a declared row diff --git a/packages/d2b-resource-runtime/src/context.rs b/packages/d2b-resource-runtime/src/context.rs index 82f5720ed..a21ce2179 100644 --- a/packages/d2b-resource-runtime/src/context.rs +++ b/packages/d2b-resource-runtime/src/context.rs @@ -95,7 +95,7 @@ pub struct WatchSatisfied { /// /// ```text /// if status matches condition { notify(subscriber, Satisfied) } -/// else { watchers.insert(watch_id, ...) } +/// else { watchers. insert(watch_id, ...) } /// ``` /// /// Status transitions evaluate registered watches in the same handler. U3 @@ -347,7 +347,7 @@ pub struct ResourceContext { status: Option>, /// Free-form status projection for the read surfaces (R11: in-memory /// only, never persisted). The erased status slot above is typed and - /// driver-private; this is the closed-JSON `status.resource` layer the + /// driver-private; this is the closed-JSON `status. resource` layer the /// manager renders onto the wire for rows whose consumer contract /// carries one (the Cloud Hypervisor Guest runtime status). status_projection: Option, @@ -463,7 +463,7 @@ impl ResourceContext { self.status = Some(Box::new(status)); } - /// Publish the wire-visible `status.resource` layer of this row (R11: + /// Publish the wire-visible `status. resource` layer of this row (R11: /// in-memory only). The actor takes it after the pass that set it and the /// manager renders it onto the row's status; a driver that publishes no /// projection leaves the layer empty, exactly as today. @@ -518,11 +518,11 @@ impl ResourceContext { /// /// - `Ok(None)`: **absent** - no row for `key` exists in this manager's /// Zone (never created, already retired, or owned by another Zone). - /// - `Ok(Some(view))` with `view.status == None`: the row exists but no + /// - `Ok(Some(view))` with `view. status == None`: the row exists but no /// actor has ever published a status for it (spawn still in flight, /// poisoned spawn, actor restart). **Unknown**, never "not ready". /// - `Ok(Some(view))` with - /// `view.status_generation != Some(view.generation)`: the last + /// `view. status_generation != Some(view. generation)`: the last /// published status describes an older generation, so it is not /// observed state of the current row. /// [`ResourceView::observed_status`] folds both of the last two cases @@ -533,7 +533,7 @@ impl ResourceContext { /// Never reported as absence. /// /// Readiness of a child or dependency is therefore - /// `view.observed_status() == Some(ResourceStatus::Ready)`; when the + /// `view. observed_status() == Some(ResourceStatus::Ready)`; when the /// answer is not-ready, a [`Self::watch`] on [`WatchCondition::Ready`] /// wakes this resource's actor on the transition and the next reconcile /// re-reads here. @@ -596,7 +596,7 @@ impl ResourceContext { /// child that owns it. /// /// Idempotent under retry, and non-blocking (R5): every owned child's - /// deletion is (re)requested - the manager's `Remove` is idempotent and + /// deletion is (re) requested - the manager's `Remove` is idempotent and /// the child's own finalize/delete are retry-idempotent - and the call /// then reports [`ResourceError::ChildrenDraining`] while any owned child /// row is still live. The caller classifies that retryable and requeues, @@ -610,7 +610,7 @@ impl ResourceContext { // The manager already cascaded the deletion when this resource // was marked deleting; requesting it again is the idempotent // nudge that guarantees a child whose actor missed the first - // cascade (e.g. spawned between passes) runs its own + // cascade (e. g. spawned between passes) runs its own // finalize-before-delete pass. let _ = self.manager.delete(&child.key).await; } @@ -1590,7 +1590,7 @@ mod tests { assert!(notify2_rx.try_recv().is_err(), "exactly one immediate notification"); } - /// `ctx.watch()` routes the registration through the manager with this + /// `ctx. watch()` routes the registration through the manager with this /// resource's key as the subscriber, and satisfaction arrives on this /// resource's notify channel. #[tokio::test] diff --git a/packages/d2b-resource-runtime/src/error.rs b/packages/d2b-resource-runtime/src/error.rs index 904132bc0..517192807 100644 --- a/packages/d2b-resource-runtime/src/error.rs +++ b/packages/d2b-resource-runtime/src/error.rs @@ -101,7 +101,7 @@ impl std::fmt::Display for FailureClass { pub const REDACTED: &str = ""; /// Bounded note length a failure may carry (provider-supplied text). The wire -/// `status.resource` layer is bounded, so failure detail is truncated at a +/// `status. resource` layer is bounded, so failure detail is truncated at a /// char boundary before it can render. pub const MAX_FAILURE_NOTE_BYTES: usize = 512; @@ -468,7 +468,7 @@ impl DriverFailure { Self::refused(op, FailureKinds::DRIVER_REFUSED) } - /// Refine the stage beyond the driver operation (e.g. `recover/adopt`). + /// Refine the stage beyond the driver operation (e. g. `recover/adopt`). #[must_use] pub fn at(mut self, stage: &'static str) -> Self { self.stage = stage; @@ -586,7 +586,7 @@ impl DriverFailure { self.report().log_line() } - /// The `status.resource.driverFailure` wire object: the same structured + /// The `status. resource. driverFailure` wire object: the same structured /// detail as [`Self::log_line`]. pub fn wire_layer(&self) -> serde_json::Value { self.report().wire_layer() @@ -686,7 +686,7 @@ impl FailureReport { line } - /// The `status.resource.driverFailure` wire object. `operation` keeps the + /// The `status. resource. driverFailure` wire object. `operation` keeps the /// established PascalCase spelling and `retryable` stays first-class for /// the readers that gate child retries on it. pub fn wire_layer(&self) -> serde_json::Value { diff --git a/packages/d2b-resource-runtime/src/manager.rs b/packages/d2b-resource-runtime/src/manager.rs index c9c6db767..d82ea5071 100644 --- a/packages/d2b-resource-runtime/src/manager.rs +++ b/packages/d2b-resource-runtime/src/manager.rs @@ -13,7 +13,7 @@ //! spawn-or-update the actor -> reply. Identical specs return the current //! actor handle; changed specs persist a new generation and only then send //! `SpecChanged`; absent resources persist before their actor is spawned. A -//! spawn that fails after the commit (e.g. no provider factory for the type) +//! spawn that fails after the commit (e. g. no provider factory for the type) //! leaves the row durable; a later Ensure or manager restart recovers it. //! //! ## Admission boundary (KTD2 review finding; security review finding 3) @@ -187,7 +187,7 @@ pub struct ResourceView { /// notified once per committed generation, so a status published before a /// spec change must not be read as observed state of the newer row. pub status_generation: Option, - /// The driver's wire-visible `status.resource` layer published with that + /// The driver's wire-visible `status. resource` layer published with that /// status (`None` when the driver published none, or when the status is /// not current for the row). pub status_projection: Option, @@ -210,7 +210,7 @@ impl ResourceView { .cloned() } - /// The `status.resource` layer published **for this exact row + /// The `status. resource` layer published **for this exact row /// generation**, mirroring [`Self::observed_status`]: a projection left /// over from an older generation is not observed state of the row. pub fn observed_status_projection(&self) -> Option<&serde_json::Value> { @@ -221,7 +221,7 @@ impl ResourceView { /// The canonical wire `status` object for this row: the closed universal /// shape the resource contract defines, carrying this row's live - /// classification and its driver-published `status.resource` layer. + /// classification and its driver-published `status. resource` layer. /// /// This is the one producer of the status shape (issue #515). Every /// reader - the API's wire view, a store-shaped bridge, an effect gate - @@ -358,7 +358,7 @@ pub enum ResourceManagerMsg { key: ResourceKey, generation: u64, status: ResourceStatus, - /// The actor's wire-visible `status.resource` layer for this pass, + /// The actor's wire-visible `status. resource` layer for this pass, /// when the driver published one (R11: in-memory only, replaced or /// dropped with the next status). projection: Option, @@ -463,7 +463,7 @@ pub struct ResourceManagerState { /// The generation each published status belongs to (see /// [`ResourceView::status_generation`]). status_generations: HashMap, - /// The driver-published `status.resource` layer of each row's current + /// The driver-published `status. resource` layer of each row's current /// status (see [`ResourceView::status_projection`]); in-memory only. status_projections: HashMap, /// Rows whose cleanup completed at their actor while owned children were @@ -873,7 +873,7 @@ pub struct ResourceManagerArgs { /// reference. pub host_target: TargetRef, /// Resolves the execution reference a stored desired spec declares - /// (`spec.executionRef`), supplied by the composition from the resource + /// (`spec. executionRef`), supplied by the composition from the resource /// contracts. pub target_resolver: Arc, /// Fixed reconcile backoff for retryable driver failures (R13). @@ -933,7 +933,7 @@ impl Actor for ResourceManager { // Restart recovery (F2, R15): load durable specs and spawn one actor // per row; each actor reconstructs observed state by discovery and // adoption on its target. Rows without a registered provider factory - // (e.g. a spawn that failed after commit) stay durable and are + // (e. g. a spawn that failed after commit) stay durable and are // picked up by the next Ensure or restart. let rows = state .store @@ -2507,7 +2507,7 @@ mod tests { /// closed universal shape, and only a status published for the row's own /// generation is observed state. A stale published status must never /// leak a `Ready` into the served phase, and a live driver projection is - /// carried as the `status.resource` layer byte-for-byte. + /// carried as the `status. resource` layer byte-for-byte. #[test] fn wire_status_projects_only_current_observed_state() { use crate::identity::{ResourceKey, ResourceProvenance}; @@ -2630,7 +2630,7 @@ mod tests { /// projection publishes it, whatever its outcome. `InProgress` (a long /// effect in flight) keeps the actor's `Reconciling` status but must not /// swallow the evidence the pass just computed - dropping it left rows - /// serving the pre-pass (or no) `status.resource` layer while the driver + /// serving the pre-pass (or no) `status. resource` layer while the driver /// already knew better. Only invalidation (spec change, deletion) clears /// the layer. #[tokio::test] @@ -3462,7 +3462,7 @@ mod tests { } /// The projection channel's failure case: a pass that computed a - /// `status.resource` layer and then failed publishes the failure, not the + /// `status. resource` layer and then failed publishes the failure, not the /// stale success layer. `wire_status` prefers a projection when one is /// present, so a leaked layer would hide the driver failure entirely. #[tokio::test] diff --git a/packages/d2b-resource-runtime/src/metadata.rs b/packages/d2b-resource-runtime/src/metadata.rs index 88c2b0220..a65fa8e1d 100644 --- a/packages/d2b-resource-runtime/src/metadata.rs +++ b/packages/d2b-resource-runtime/src/metadata.rs @@ -60,7 +60,7 @@ use serde_json::Value; /// /// Derived from the placement contract: none of these types names a placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a row never -/// carries the canonical `spec.executionRef` and the plane reconciles it on +/// carries the canonical `spec. executionRef` and the plane reconciles it on /// its own Host domain. pub const METADATA_EXECUTION_DOMAINS: &[&str] = &["host"]; diff --git a/packages/d2b-resource-runtime/src/resource.rs b/packages/d2b-resource-runtime/src/resource.rs index 2ccffde15..66c4d34c0 100644 --- a/packages/d2b-resource-runtime/src/resource.rs +++ b/packages/d2b-resource-runtime/src/resource.rs @@ -115,7 +115,7 @@ impl ResourceStatus { } /// The structured failure classification rendered into the free-form - /// `status.resource` layer, for a row whose driver published no + /// `status. resource` layer, for a row whose driver published no /// projection of its own: the universal status object is closed to /// unknown fields, so a failure classification rides the type's own /// layer. `None` for every non-failed classification. @@ -360,7 +360,7 @@ impl ResourceActorState { self.transition_published(status, None); } - /// [`Self::transition`] with the pass's wire-visible `status.resource` + /// [`Self::transition`] with the pass's wire-visible `status. resource` /// projection attached (R11: in-memory only, dropped with the next /// status). The projection is `None` for transitions no driver pass /// produced. @@ -1419,7 +1419,7 @@ pub(crate) mod test_support { } /// Restart semantics with the caller's factory: restart tests can pin - /// driver behavior (e.g. blocked deletes) on keys before the manager + /// driver behavior (e. g. blocked deletes) on keys before the manager /// loads rows and spawns their actors. pub(crate) async fn harness_over_with_factory( store: Arc, diff --git a/packages/d2b-resource-runtime/src/spec_store.rs b/packages/d2b-resource-runtime/src/spec_store.rs index 1afd04cbb..8160498b6 100644 --- a/packages/d2b-resource-runtime/src/spec_store.rs +++ b/packages/d2b-resource-runtime/src/spec_store.rs @@ -11,7 +11,7 @@ //! variant of the message-passing surface allowed by KTD2: SQLite calls never //! run inside an async context or an actor mailbox (KTD12), writers serialize //! structurally on the single connection, and `busy_timeout` covers the -//! remaining cross-connection case (two stores open on one file, e.g. during +//! remaining cross-connection case (two stores open on one file, e. g. during //! handover). //! //! Admission is refuse-don't-queue (the loader_worker doctrine): a full @@ -435,7 +435,7 @@ fn tighten_file_modes(path: &Path) { // files carry the daemon's private-data mode (0600). SQLite names the // side files by appending `-wal`/`-shm` to the *database file name*, so // the suffix is appended here too - `with_extension` would rewrite the - // real suffix (`spec-store.sqlite3` -> `spec-store.db-wal`) and leave + // real suffix (`spec-store. sqlite3` -> `spec-store. db-wal`) and leave // the files SQLite actually created at their creation mode. Side files // only exist while a connection holds the database open in WAL mode. let tighten = |p: &Path| { diff --git a/packages/d2b-resource-runtime/src/target.rs b/packages/d2b-resource-runtime/src/target.rs index f2864acbb..590adaf9b 100644 --- a/packages/d2b-resource-runtime/src/target.rs +++ b/packages/d2b-resource-runtime/src/target.rs @@ -86,7 +86,7 @@ pub const MAX_TARGET_NAME_BYTES: usize = 128; /// One canonical execution reference: `Host/` or `Guest/`. /// -/// This is the reference a desired spec declares (`spec.executionRef`); it +/// This is the reference a desired spec declares (`spec. executionRef`); it /// names where effects run and never changes a resource's Zone identity. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TargetRef { @@ -463,7 +463,7 @@ impl std::error::Error for TargetError {} /// Resolves the execution target a stored desired spec declares. /// /// One implementation per composition: it reads the same canonical -/// `spec.executionRef` the resource contracts resolve, and returns the +/// `spec. executionRef` the resource contracts resolve, and returns the /// canonical `Host/` or `Guest/` reference. A row whose type has /// no execution anchor, or a legacy row that carries none, returns `None` and /// realizes on the Zone's Host target. diff --git a/packages/d2b-resource-types/src/metadata.rs b/packages/d2b-resource-types/src/metadata.rs index 6373bf36d..43331900d 100644 --- a/packages/d2b-resource-types/src/metadata.rs +++ b/packages/d2b-resource-types/src/metadata.rs @@ -36,7 +36,7 @@ use crate::{AllowedSources, CONVERTED_TYPE_VERBS, DriverDescriptor, WellKnownTyp /// and creates no children through this declaration. /// /// None of the types is exportable: `ResourceExport` admits only qualified -/// `*.d2bus.org.*Service` types, so a row of one of these types is never an +/// `*.d2bus. org.*Service` types, so a row of one of these types is never an /// export subject. pub fn metadata_descriptor(resource_type: WellKnownType) -> DriverDescriptor { DriverDescriptor { diff --git a/packages/d2b-sk-frontend/src/uhid.rs b/packages/d2b-sk-frontend/src/uhid.rs index 272ba06f4..a9410ee02 100644 --- a/packages/d2b-sk-frontend/src/uhid.rs +++ b/packages/d2b-sk-frontend/src/uhid.rs @@ -173,7 +173,7 @@ impl UhidDevice { /// Read and parse one event from /dev/uhid. /// /// Blocks until an event is available. Returns `None` on clean EOF - /// (e.g. the kernel closed the device). + /// (e. g. the kernel closed the device). pub async fn read_event(&mut self) -> io::Result> { let mut buf = [0u8; UHID_EVENT_SIZE]; let n = self.read_nonblocking(&mut buf).await?; diff --git a/packages/d2b-telemetry/src/emitter.rs b/packages/d2b-telemetry/src/emitter.rs index 77a5f3207..10ab8f9b1 100644 --- a/packages/d2b-telemetry/src/emitter.rs +++ b/packages/d2b-telemetry/src/emitter.rs @@ -241,7 +241,7 @@ impl BoundedEmitter { /// /// # Errors /// - /// Returns the same `EmitterError` conditions as [`BoundedEmitter::new`]。 + /// Returns the same `EmitterError` conditions as [`BoundedEmitter::new`]. pub fn with_default_capacity(path: impl Into) -> Result { Self::new(path, DEFAULT_RING_CAPACITY_BYTES) } diff --git a/packages/d2b-zone-routing/src/enrollment.rs b/packages/d2b-zone-routing/src/enrollment.rs index 710e4acb0..b93f6516b 100644 --- a/packages/d2b-zone-routing/src/enrollment.rs +++ b/packages/d2b-zone-routing/src/enrollment.rs @@ -1,6 +1,6 @@ //! The Zone enrollment admission shape (`ADR046-routing-016`). //! -//! `zone-bootstrap` and `zone-enroll` are the two `d2b.zone.v3.ZoneService` +//! `zone-bootstrap` and `zone-enroll` are the two `d2b. zone. v3.ZoneService` //! methods that place a Guest agent: the one-time IKpsk2 bootstrap that //! consumes the allocator-issued single-use PSK, and the enrolled `Noise_KK` //! enrollment that commits the sealed enrollment record and admits the peer. diff --git a/packages/d2b-zone-routing/src/resolver.rs b/packages/d2b-zone-routing/src/resolver.rs index b5987e635..552c3df0c 100644 --- a/packages/d2b-zone-routing/src/resolver.rs +++ b/packages/d2b-zone-routing/src/resolver.rs @@ -607,7 +607,7 @@ mod tests { fn sealing_rejects_a_subtree_attached_outside_the_sealed_scope() { let error = SealedZoneTopology::seal( zone(&["k0"]), - // k9.k0 is never declared as a child, so k1.k9.k0 would attach an + // k9. k0 is never declared as a child, so k1. k9. k0 would attach an // unknown subtree. vec![edge(&["k9", "k0"], &["k1", "k9", "k0"])], ) @@ -629,8 +629,8 @@ mod tests { #[test] fn a_descendant_matches_its_nearest_sealed_ancestor_not_the_root() { let topology = sealed(); - // deep.k2.k1.k0 is not sealed; the longest suffix is k2.k1.k0, and the - // shorter suffixes k1.k0 and k0 must not win. + // deep. k2. k1. k0 is not sealed; the longest suffix is k2. k1. k0, and the + // shorter suffixes k1. k0 and k0 must not win. assert_eq!( topology.longest_suffix_match(&zone(&["deep", "k2", "k1", "k0"])), Some(&zone(&["k2", "k1", "k0"])) @@ -720,8 +720,8 @@ mod tests { fn an_unsealed_descendant_resolves_to_its_sealed_ancestor_entrypoint() { let resolver = ZoneEntrypointResolver::new(sealed()); let engine = seeded_engine(); - // deep.k2.k1.k0 has no sealed row and no projection of its own; the - // sealed k2.k1.k0 owns it and is the entrypoint the engine routes to. + // deep. k2. k1. k0 has no sealed row and no projection of its own; the + // sealed k2. k1. k0 owns it and is the entrypoint the engine routes to. let request = allowed_request(zone(&["deep", "k2", "k1", "k0"])); let ZoneEntrypointResolution::Resolved { entrypoint_zone, diff --git a/packages/d2b-zone-routing/src/service.rs b/packages/d2b-zone-routing/src/service.rs index 8c61e4ad4..2832e8c17 100644 --- a/packages/d2b-zone-routing/src/service.rs +++ b/packages/d2b-zone-routing/src/service.rs @@ -125,7 +125,7 @@ macro_rules! redacted_debug { pub(crate) use redacted_debug; -/// The closed set of `d2b.zone.v3.ZoneService` methods. +/// The closed set of `d2b. zone. v3.ZoneService` methods. /// /// The inventory is frozen here in full. Every method has a landed handler. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -500,7 +500,7 @@ struct AdmittedEnrollment { child: ZonePath, } -/// The `d2b.zone.v3.ZoneService` handler for one Zone. +/// The `d2b. zone. v3.ZoneService` handler for one Zone. /// /// The Zone runtime instantiates exactly one of these per Zone. It composes /// [`ZoneEntrypointResolver`] over the sealed topology with a caller-supplied @@ -1839,7 +1839,7 @@ mod tests { #[test] fn construction_rejects_a_topology_the_seal_rejects() { - // k9.k0 is never declared as a child, so the row would attach a + // k9. k0 is never declared as a child, so the row would attach a // subtree outside the sealed scope. assert_eq!( ZoneServiceServer::new( diff --git a/packages/d2b/src/context.rs b/packages/d2b/src/context.rs index bfc077bf0..9f7388ec4 100644 --- a/packages/d2b/src/context.rs +++ b/packages/d2b/src/context.rs @@ -3594,7 +3594,7 @@ mod tests { // 60s is a 12x headroom over that budget: wide enough that scheduling // delay cannot trip it on any normally-loaded machine, finite enough - // that inflation beyond ~12x (e.g., an ms-misread-as-seconds budget + // that inflation beyond ~12x (e. g., an ms-misread-as-seconds budget // like 5000ms read as 500s) fails on the measurement. Smaller // inflations - a 10x arithmetic error to 50s, or a copy-paste to the // 30s request lifetime - land below the ceiling by design: catching diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index 85e57a7a0..7e63ebd20 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -33,7 +33,7 @@ use serde_json::{Value, json}; /// The Provider projection commands the parser carries as static variants. /// /// A projected command is named by the declaring Provider's own -/// `cliProjection.topLevel` (`d2b provider inspect`), which no compile-time +/// `cliProjection. topLevel` (`d2b provider inspect`), which no compile-time /// table can enumerate, so clap holds one static variant per projection /// Provider and the projection binding admits exactly these names in place of /// a built-in command. They are parser carriers, not resource knowledge: the diff --git a/packages/d2b/src/doctor.rs b/packages/d2b/src/doctor.rs index 3aa1eb853..b757d486b 100644 --- a/packages/d2b/src/doctor.rs +++ b/packages/d2b/src/doctor.rs @@ -1,9 +1,9 @@ //! `d2b host doctor --read-only` checks. //! //! Each check is a passive, read-only probe: -//! - `broker_ready` - connect to `/run/d2b/priv.sock`, or verify the +//! - `broker_ready` - connect to `/run/d2b/priv. sock`, or verify the //! private socket exists and correctly rejects this unprivileged caller. -//! - `daemon_ready` - connect to `/run/d2b/public.sock`. +//! - `daemon_ready` - connect to `/run/d2b/public. sock`. //! - `metrics_endpoint` - `GET /metrics` over the canonical //! operator-configured external Prometheus URL (see //! `docs/reference/daemon-metrics.md`). The scrape endpoint is optional; @@ -11,7 +11,7 @@ //! posture so local host health stays clean until the metrics listener //! is enabled. //! - `signoz-ui-endpoint` - when observability is enabled, read -//! `_observability.signozUrl` from `vms.json` and probe the SigNoz +//! `_observability. signozUrl` from `vms.json` and probe the SigNoz //! health endpoint. //! - `otel_host_bridge_runner` - inspect daemon-persisted //! `pidfd-table.json` for a registration with role @@ -78,12 +78,12 @@ impl DoctorStatus { /// One row in the doctor's `checks[]` array. #[derive(Debug, Clone)] pub(crate) struct DoctorCheck { - /// Stable kebab-case identifier (e.g. `broker-ready`). + /// Stable kebab-case identifier (e. g. `broker-ready`). pub name: &'static str, pub status: DoctorStatus, pub detail: String, /// Optional structured payload that the JSON renderer merges - /// into the per-check object (e.g. runner counts). + /// into the per-check object (e. g. runner counts). pub data: Option, } @@ -1593,7 +1593,7 @@ fn is_d2b_bridge_name(name: &str) -> bool { } /// For each declared d2b bridge, query -/// `net.ipv6.conf..disable_ipv6` via `sysctl`. +/// `net. ipv6.conf..disable_ipv6` via `sysctl`. /// /// - **Fail** if any bridge returns `0` (IPv6 active). /// - **Pass** if all bridges return `1`. diff --git a/packages/d2b/src/exec_client.rs b/packages/d2b/src/exec_client.rs index 52261f639..c4365d895 100644 --- a/packages/d2b/src/exec_client.rs +++ b/packages/d2b/src/exec_client.rs @@ -1,7 +1,7 @@ //! CLI-side `d2b vm exec` owner-connection FSM + host terminal safety. //! //! `d2b vm exec` establishes one Process/EphemeralProcess resource owner over -//! the daemon `public.sock`, then drives the authenticated named stream with +//! the daemon `public. sock`, then drives the authenticated named stream with //! (`WriteStdin`/`ReadOutput`/`Signal`/`Resize`/`Wait`/`Close`) operations. The //! CLI never opens a new connection per op and never allocates a host PTY - //! the guest owns the PTY (helper-exec). This module is the pure FSM + @@ -25,7 +25,7 @@ use serde_json::Value; use crate::terminal_client::{TerminalHostIo, TerminalSignalSource, TerminalTransport}; // Reserved exec CLI exit codes. Guest WIFEXITED 0-255 codes pass through -// and CAN collide with these reserved numbers (e.g. a guest that exits 70 vs. +// and CAN collide with these reserved numbers (e. g. a guest that exits 70 vs. // the old-generation transport class); `--json` disambiguates via // `source`/`reason`/`guestExitCode`/`transportExitCode`. These deliberately // avoid the pre-existing CLI exit codes 2/3/33/78. @@ -209,7 +209,7 @@ pub fn exit_for_kind(kind: &str) -> (i32, ExecFailureSource) { (EXIT_EXEC_AUTH, ExecFailureSource::ComponentSession) } // The daemon's admin gate refused the caller before any guest contact - // (caller not in `d2b.site.adminUsers`). It is an authorization + // (caller not in `d2b. site. adminUsers`). It is an authorization // failure, NOT an internal bug - map it to the AUTH reserved code so // it does not fall through to the internal (42) default. "authz-not-admin" => (EXIT_EXEC_AUTH, ExecFailureSource::ComponentSession), diff --git a/packages/d2b/src/host_validate.rs b/packages/d2b/src/host_validate.rs index 1b226b7bd..e8cfd6ae3 100644 --- a/packages/d2b/src/host_validate.rs +++ b/packages/d2b/src/host_validate.rs @@ -4,7 +4,7 @@ //! This module ships the operator-facing one-command preflight that //! must run after a fresh `nixos-rebuild switch` to record the //! per-wave validation evidence the readiness assertions consume. -//! (`d2b.daemonExperimental.enable` defaults `true` and is no +//! (`d2b. daemonExperimental. enable` defaults `true` and is no //! longer evidence-auto-flipped - there is no default to flip - but it //! still functionally gates the daemon control plane; setting it //! `false` reverts the host to the unsupported pre-daemon legacy @@ -39,7 +39,7 @@ //! and external hardware). Instead, it lets the operator attest that //! the validators were run by issuing the evidence record as a //! single composite operation. Per-wave validators that already write -//! their own evidence records (e.g. `tests/minijail-validator-swtpm.sh` +//! their own evidence records (e. g. `tests/minijail-validator-swtpm.sh` //! → `p1-swtpm.json`) continue to do so; this verb is the umbrella //! preflight that produces the per-wave `.json` records the //! readiness option consumes. @@ -63,7 +63,7 @@ pub(crate) const DEFAULT_EVIDENCE_DIR: &str = "/var/lib/d2b/validated"; /// `tests/host-validate-verb-eval.sh` enforces parity. #[derive(Debug, Clone, Copy)] pub(crate) struct WaveSpec { - /// Wave id, e.g. `"p1"` or `"w5Fu"`. Matches the file basename the + /// Wave id, e. g. `"p1"` or `"w5Fu"`. Matches the file basename the /// readiness option consumes (`/var/lib/d2b/validated/.json`). pub wave: &'static str, /// Short human-readable summary of what the wave covers. @@ -185,7 +185,7 @@ pub(crate) enum WaveStatus { /// At least one declared validator script is missing. Missing, /// No validators are declared for this wave (informational - - /// e.g. `p6`/`p7` whose readiness signal is gate-output, not a + /// e. g. `p6`/`p7` whose readiness signal is gate-output, not a /// per-host script). NoValidators, /// Apply mode only: evidence record was written successfully. @@ -193,7 +193,7 @@ pub(crate) enum WaveStatus { /// Apply mode only: evidence write was skipped because the wave /// is `Missing` or because `--wave ` filtered it out. Skipped, - /// Apply mode only: evidence write failed (e.g. permission + /// Apply mode only: evidence write failed (e. g. permission /// denied). The detail field carries the underlying error. WriteFailed, } @@ -218,7 +218,7 @@ pub(crate) struct WaveReport { pub status: WaveStatus, /// Per-validator presence map: `(basename, present)`. pub validators: Vec<(String, bool)>, - /// Human-readable detail (e.g. evidence path written, error + /// Human-readable detail (e. g. evidence path written, error /// reason). pub detail: String, /// On `Attested`, the absolute evidence path. Otherwise `None`. diff --git a/packages/d2b/tests/auth_status_contract.rs b/packages/d2b/tests/auth_status_contract.rs index 801911e05..64120dc43 100644 --- a/packages/d2b/tests/auth_status_contract.rs +++ b/packages/d2b/tests/auth_status_contract.rs @@ -8,7 +8,7 @@ //! * `auth status --json` deserializes strictly into //! `d2b_contracts_control::cli_output::AuthStatusOutputV2` (`deny_unknown_fields` makes a successful //! typed deserialize equivalent to the schema check the bash gate did via -//! docs/reference/cli-output/auth-status.schema.json); +//! docs/reference/cli-output/auth-status. schema.json); //! * the per-role allowed/denied subcommand authz surface matches the binary's //! contract (launcher gets `up` but keeps `audit` denied; `none` stays //! read-only; admin gains `audit` and denies nothing); @@ -85,7 +85,7 @@ fn parse_json(out: &std::process::Output) -> AuthStatusOutputV2 { ); // Strict schema validation: AuthStatusOutputV2 (and its nested DTOs) are // deny_unknown_fields, so a successful typed deserialize is equivalent to - // validating against docs/reference/cli-output/auth-status.schema.json. + // validating against docs/reference/cli-output/auth-status. schema.json. serde_json::from_slice(&out.stdout).unwrap_or_else(|err| { panic!( "auth status --json did not match the AuthStatusOutputV2 schema: {err}\noutput:\n{}", @@ -101,7 +101,7 @@ fn auth_status_roles_match_schema_and_authz() { let none_fixture = write_fixture(tmp.path(), "auth-none.json", NONE_FIXTURE); let admin_fixture = write_fixture(tmp.path(), "auth-admin.json", ADMIN_FIXTURE); - // Case 1 - launcher: gains launcher-allowed verbs (e.g. `list`) but keeps + // Case 1 - launcher: gains launcher-allowed verbs (e. g. `list`) but keeps // `audit` denied, and no retired v2 verbs are reported as allowed. let launcher = parse_json(&run_auth_status( diff --git a/packages/d2bd-runtime/src/autostart.rs b/packages/d2bd-runtime/src/autostart.rs index 98f7234c0..f0e3cd1c0 100644 --- a/packages/d2bd-runtime/src/autostart.rs +++ b/packages/d2bd-runtime/src/autostart.rs @@ -47,7 +47,7 @@ use tokio::task::JoinSet; /// see meaningful progress in the journal before the next batch /// starts" on the small-fleet desktop deployments d2b targets. /// Operators with bigger fleets override via -/// `d2b.daemon.autostart.parallelism` (NixOS) → +/// `d2b. daemon. autostart. parallelism` (NixOS) → /// `AutostartConfig::parallelism`. pub const DEFAULT_PARALLELISM: usize = 3; @@ -56,7 +56,7 @@ pub const DEFAULT_PARALLELISM: usize = 3; /// can be re-derived without re-loading the world. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct VmAutostartEntry { - /// VM name as it appears in `_manifest.vms`. + /// VM name as it appears in `_manifest. vms`. pub vm: String, /// Env this VM belongs to, if any. Net VMs use the env from /// their `sys--net` name (= `Some("")`); workloads @@ -93,7 +93,7 @@ impl AutostartPlan { } /// Tunables for [`execute_autostart`]. Mirrors the -/// `d2b.daemon.autostart.*` NixOS option set. +/// `d2b. daemon. autostart.*` NixOS option set. #[derive(Debug, Clone, Copy)] pub struct AutostartConfig { /// Concurrency cap N (number of VMs started in parallel within @@ -254,14 +254,14 @@ fn vm_is_autostart_eligible(vm: &d2b_core::manifest_v04::VmEntry) -> bool { } /// Drive a built plan. Net VMs are started first (up to -/// `config.parallelism` in parallel); once that phase settles, any +/// `config. parallelism` in parallel); once that phase settles, any /// env whose net VM ended in a degraded/failed state has its /// workloads marked `Outcome::Degraded` *without dispatch*, and /// the remaining workloads are started (again, up to -/// `config.parallelism` in parallel). +/// `config. parallelism` in parallel). /// /// The function is safe to invoke repeatedly: each VM is gated on -/// `starter.is_running(...)`, so a re-entry on SIGHUP or +/// `starter. is_running(...)`, so a re-entry on SIGHUP or /// bundle-reload short-circuits to `Outcome::AlreadyRunning` for /// every VM that's still supervised. pub async fn execute_autostart( @@ -402,7 +402,7 @@ where let pre_degraded = Arc::clone(&pre_degraded); let request_txs = Arc::clone(&request_txs); join_set.spawn(async move { - // Pre-degraded VMs (e.g. flagged by the kernel-module-check + // Pre-degraded VMs (e. g. flagged by the kernel-module-check // pass) short-circuit before anything else. if pre_degraded.contains(&entry.vm) { return ( diff --git a/packages/d2bd-runtime/src/ch_api.rs b/packages/d2bd-runtime/src/ch_api.rs index d92dda807..50471234f 100644 --- a/packages/d2bd-runtime/src/ch_api.rs +++ b/packages/d2bd-runtime/src/ch_api.rs @@ -21,7 +21,7 @@ pub const MAX_RESPONSE_BYTES: usize = 64 * 1024; #[derive(Debug, Clone, PartialEq, Eq)] pub enum ChApiError { /// The control socket is unreachable or the I/O failed, citing the - /// underlying error kind (not full paths或 payloads). + /// underlying error kind (not full paths or payloads). Unavailable(String), /// The control request exceeded its deadline. Timeout, @@ -31,7 +31,7 @@ pub enum ChApiError { MalformedResponse, /// The API answered a non-2xx status code. Rejected(u16), - /// The `vm.info` payload did not deserialize into the expected shape. + /// The `vm. info` payload did not deserialize into the expected shape. InvalidJson(String), } @@ -47,11 +47,11 @@ impl ChApiError { } } -/// The subset of the Cloud Hypervisor `vm.info` payload this crate +/// The subset of the Cloud Hypervisor `vm. info` payload this crate /// consumes; fields absent from the reply stay `None`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ChVmInfo { - /// The VM run state (e.g. `Running`, `Stopped`) as reported by CH. + /// The VM run state (e. g. `Running`, `Stopped`) as reported by CH. pub state: Option, /// The configured vCPU count, when the reply reports one. pub vcpu_count: Option, @@ -59,7 +59,7 @@ pub struct ChVmInfo { pub memory_mib: Option, } -/// Fetch and parse the Cloud Hypervisor `vm.info` payload over the control +/// Fetch and parse the Cloud Hypervisor `vm. info` payload over the control /// socket. /// /// # Errors @@ -108,7 +108,7 @@ pub fn blocking_get_json( split_http_body(&raw) } -/// Raw Cloud Hypervisor `vm.info` payload shape, deserialized at the +/// Raw Cloud Hypervisor `vm. info` payload shape, deserialized at the /// boundary; fields absent from the reply default to `None`. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRaw { @@ -118,7 +118,7 @@ struct ChVmInfoRaw { config: ChVmInfoRawConfig, } -/// Nested `config` object of the raw `vm.info` payload. +/// Nested `config` object of the raw `vm. info` payload. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRawConfig { #[serde(default)] @@ -127,14 +127,14 @@ struct ChVmInfoRawConfig { memory: ChVmInfoRawMemory, } -/// Nested `config.cpus` object of the raw `vm.info` payload. +/// Nested `config. cpus` object of the raw `vm. info` payload. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRawCpus { #[serde(default)] boot_vcpus: Option, } -/// Nested `config.memory` object of the raw `vm.info` payload. +/// Nested `config. memory` object of the raw `vm. info` payload. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRawMemory { #[serde(default)] diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index f4fd026e9..1cd69fa9b 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -207,7 +207,7 @@ impl ConsoleSessionTable { } impl ConsoleSessionTable { - /// drainer. Replaces any existing session (e.g. after a VM restart). + /// drainer. Replaces any existing session (e. g. after a VM restart). pub fn register_session(&mut self, vm: String, session: ConsoleSession) { // Abort any previous drainer for this VM. if let Some(mut old) = self.sessions.remove(&vm) { @@ -372,7 +372,7 @@ pub struct ConsoleReadOutput { /// Spawn a drainer task for a Cloud Hypervisor serial socket. /// /// The task connects to `socket_path` (CH's `--serial socket=`), reads -/// bytes into the ring, and reconnects if CH closes the connection (e.g. after +/// bytes into the ring, and reconnects if CH closes the connection (e. g. after /// a VM reboot). The ring's `notify` is triggered on each new chunk. The task /// runs on the caller-provided runtime handle (owned by the daemon binary). pub fn spawn_ch_serial_drainer( @@ -408,7 +408,7 @@ pub fn spawn_ch_serial_drainer( }) } -/// Spawn a drainer task for a pre-opened async stream (e.g. the host end of a +/// Spawn a drainer task for a pre-opened async stream (e. g. the host end of a /// qemu-media socketpair, converted to `tokio::net::UnixStream`). /// /// Unlike [`spawn_ch_serial_drainer`], this does not reconnect after EOF: the diff --git a/packages/d2bd-runtime/src/daemon_audit.rs b/packages/d2bd-runtime/src/daemon_audit.rs index b8a0376a4..fdedcbaff 100644 --- a/packages/d2bd-runtime/src/daemon_audit.rs +++ b/packages/d2bd-runtime/src/daemon_audit.rs @@ -274,7 +274,7 @@ pub enum DaemonEvent { }, /// Emitted when a `vm start` long-lived runner node fast-fails because /// the spawned runner terminated (or its PID was reused) BEFORE its - /// readiness signal fired - the `tpm.enable` first-run wedge fix. + /// readiness signal fired - the `tpm. enable` first-run wedge fix. /// /// Bounded by construction: carries ONLY the VM name, the closed /// `role_id` of the failed node, a closed reason kind, the optional @@ -284,7 +284,7 @@ pub enum DaemonEvent { VmStartRunnerExited { /// VM name (matches the `vmStart` request). vm: String, - /// Role id of the runner node that exited (e.g. `swtpm`, + /// Role id of the runner node that exited (e. g. `swtpm`, /// `ch-runner`). role_id: String, /// Closed reason kind: exited vs PID-reused. diff --git a/packages/d2bd-runtime/src/daemon_config.rs b/packages/d2bd-runtime/src/daemon_config.rs index 8d50214f4..8b8788a9e 100644 --- a/packages/d2bd-runtime/src/daemon_config.rs +++ b/packages/d2bd-runtime/src/daemon_config.rs @@ -85,7 +85,7 @@ pub struct DaemonConfig { pub realm_identity_config_path: PathBuf, /// Concurrency cap for the autostart pass that runs on daemon /// startup. Default `3`. - /// Mirrors `d2b.daemon.autostart.parallelism`. + /// Mirrors `d2b. daemon. autostart. parallelism`. #[serde(default = "default_autostart_parallelism")] pub autostart_parallelism: usize, /// Default provider graceful-shutdown wait before forced cleanup. diff --git a/packages/d2bd-runtime/src/exec_session.rs b/packages/d2bd-runtime/src/exec_session.rs index e158b5928..73d23c624 100644 --- a/packages/d2bd-runtime/src/exec_session.rs +++ b/packages/d2bd-runtime/src/exec_session.rs @@ -2,7 +2,7 @@ //! //! The daemon owns a long-lived, authenticated Process named-stream client per //! exec session. The CLI establishes the resource owner through the -//! admin-gated `public.sock` route, then sends one correlated named-stream +//! admin-gated `public. sock` route, then sends one correlated named-stream //! frame per [`ExecOp`]. A dedicated worker thread (current-thread tokio //! runtime) owns the authenticated client, the target-local process resource, //! the authoritative stdin offset, and the monotone control sequence; it is @@ -136,7 +136,7 @@ pub enum ExecEstablishError { Timeout, OldGeneration, Capability, - /// Guest accepted the handshake but rejected the create (e.g. exec + /// Guest accepted the handshake but rejected the create (e. g. exec /// disabled, root denied, unsupported mode). Guest(ProcessOpError), } @@ -831,7 +831,7 @@ pub struct WorkerCommand { pub type EstablishReply = Result; /// Owner-socket teardown seam for the terminal-cleanup reaper. -/// `reap` forces the owner connection's reader to unblock (e.g. by shutting +/// `reap` forces the owner connection's reader to unblock (e. g. by shutting /// down the socket) so the session slot is released after the command has gone /// terminal and the cleanup TTL elapsed. It MUST be idempotent and MUST NOT be /// called while the command is still live. diff --git a/packages/d2bd-runtime/src/kernel_module_check.rs b/packages/d2bd-runtime/src/kernel_module_check.rs index 586ae05d3..eb4335484 100644 --- a/packages/d2bd-runtime/src/kernel_module_check.rs +++ b/packages/d2bd-runtime/src/kernel_module_check.rs @@ -101,14 +101,14 @@ pub const OPTIONAL_TPM: &str = "tpm_vtpm_proxy"; /// One row in [`ModuleCheckReport::optional_missing`]. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct OptionalMissing { - /// Kernel module name (e.g. `nvidia`, `usbip_host`, + /// Kernel module name (e. g. `nvidia`, `usbip_host`, /// `tpm_vtpm_proxy`). pub module: String, /// VMs whose declared features depend on this module. Empty - /// for purely host-wide optionals (e.g. `nvidia` with no + /// for purely host-wide optionals (e. g. `nvidia` with no /// graphics VMs declared). pub affected_vms: BTreeSet, - /// Short human-readable reason (e.g. "graphics VMs may fall + /// Short human-readable reason (e. g. "graphics VMs may fall /// back to software rendering"). Suitable for log + the /// operator reference. pub reason: String, @@ -310,7 +310,7 @@ pub fn check_kernel_modules( } // Optional rows. Each is recorded only when (a) the gate is - // satisfied (e.g. there is at least one graphics VM) and + // satisfied (e. g. there is at least one graphics VM) and // (b) the module is NOT present. let mut optional_missing: Vec = Vec::new(); @@ -388,7 +388,7 @@ pub const PROC_MODULES_PATH: &str = "/proc/modules"; pub const SYS_MODULE_DIR: &str = "/sys/module"; /// Side-effecting wrapper: read `/proc/modules` + `/sys/module` + the -/// `modules.builtin` text file, then dispatch to [`check_kernel_modules`]. +/// `modules. builtin` text file, then dispatch to [`check_kernel_modules`]. /// /// Module detection order (union of all three sources): /// 1. `/proc/modules` - loadable modules currently inserted. @@ -397,10 +397,10 @@ pub const SYS_MODULE_DIR: &str = "/sys/module"; /// not appear in `/proc/modules`. This is the primary fix for /// false-positive "missing" reports on hosts where virtio modules /// are compiled in (`=y`) rather than loadable (`=m`). -/// 3. `/lib/modules/$(uname -r)/modules.builtin` - text list of +/// 3. `/lib/modules/$(uname -r)/modules. builtin` - text list of /// built-in modules for offline/early-boot coverage, merged into /// the `builtin` set. -/// 4. `/boot/config-$(uname -r)` / `/proc/config.gz` - kernel config +/// 4. `/boot/config-$(uname -r)` / `/proc/config. gz` - kernel config /// for `CONFIG_*=y` built-in detection (existing path). /// /// On any read failure we conservatively treat the failed source as @@ -422,7 +422,7 @@ pub fn run_kernel_module_check(resolver: &BundleResolver) -> ModuleCheckReport { } let loaded = read_loaded_modules_at(Path::new(PROC_MODULES_PATH), Path::new(SYS_MODULE_DIR)); - // Step 3: modules.builtin text file (uname handled internally). + // Step 3: modules. builtin text file (uname handled internally). let modules_builtin = read_builtin_modules_with_fallback(); // Step 4: kernel config (existing path). @@ -773,7 +773,7 @@ mod tests { } // ------------------------------------------------------------------ - // /sys/module and modules.builtin detection tests + // /sys/module and modules. builtin detection tests // ------------------------------------------------------------------ /// Virtio modules compiled as =y appear in `/sys/module//` but diff --git a/packages/d2bd-runtime/src/metrics.rs b/packages/d2bd-runtime/src/metrics.rs index 6839e1907..ac7d6d41e 100644 --- a/packages/d2bd-runtime/src/metrics.rs +++ b/packages/d2bd-runtime/src/metrics.rs @@ -6,7 +6,7 @@ //! `docs/reference/daemon-metrics.md`), and avoiding a new transitive //! dependency keeps the supply-chain audit footprint minimal. The //! exposition format we emit is the documented -//! [text-format v0.0.4](https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format) +//! [text-format v0.0.4](https://prometheus. io/docs/instrumenting/exposition_formats/#text-based-format) //! that every Prometheus-compatible scraper accepts. //! //! The module is the canonical source of truth for the metric diff --git a/packages/d2bd-runtime/src/pidfs_probe.rs b/packages/d2bd-runtime/src/pidfs_probe.rs index afbd364d7..7987cab2c 100644 --- a/packages/d2bd-runtime/src/pidfs_probe.rs +++ b/packages/d2bd-runtime/src/pidfs_probe.rs @@ -8,7 +8,7 @@ //! check relies on pidfs (per-pidfd `(st_dev, st_ino)` stability //! across PID reuse). Static eval gates //! (`tests/v1.1-kernel-floor-eval.sh`) catch the easy case (operator -//! flake declares an older kernel via `boot.kernelPackages`); this +//! flake declares an older kernel via `boot. kernelPackages`); this //! runtime probe catches the hard case - a custom-built kernel at //! >= 6.9 that strips pidfs support. //! diff --git a/packages/d2bd-runtime/src/public_projection.rs b/packages/d2bd-runtime/src/public_projection.rs index a42871a79..efa4e8466 100644 --- a/packages/d2bd-runtime/src/public_projection.rs +++ b/packages/d2bd-runtime/src/public_projection.rs @@ -302,7 +302,7 @@ fn public_pidfd_role_prefix_state(pidfd_table: &PidfdTable, vm: &str, prefix: &s /// Liveness of the qemu-media runner role as the public media row reports it. /// /// The pidfd table is the authority for both this projection and the -/// per-service state map, so the typed state and the `services.qemuMedia` +/// per-service state map, so the typed state and the `services. qemuMedia` /// string cannot disagree. pub fn public_qemu_media_runner_state(pidfd_table: &PidfdTable, vm: &str) -> QemuMediaRunnerState { if public_pidfd_role_running(pidfd_table, vm, RunnerRole::QemuMedia.as_str()) { diff --git a/packages/d2bd-runtime/src/readiness.rs b/packages/d2bd-runtime/src/readiness.rs index c8a404ec5..c806bc9b6 100644 --- a/packages/d2bd-runtime/src/readiness.rs +++ b/packages/d2bd-runtime/src/readiness.rs @@ -309,7 +309,7 @@ pub async fn wait_for_readiness_async( /// fail-fast, or treat as terminal. #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ProcState { - /// The process is alive in the given state character (e.g. + /// The process is alive in the given state character (e. g. /// 'S' sleeping, 'R' running, 'D' uninterruptible sleep, /// 'Z' zombie awaiting reap, 'X' dead). Alive(char), @@ -522,7 +522,7 @@ mod unix_socket_readiness_tests { /// No `unsafe` code: child processes are created via /// `std::process::Command`. Rust's `Child` does not call `waitpid` on /// drop, so an exited child stays in 'Z' state until the test calls -/// `child.wait()` for cleanup. +/// `child. wait()` for cleanup. #[cfg(test)] #[cfg(target_os = "linux")] mod wait_for_one_shot_exit_tests { diff --git a/packages/d2bd-runtime/src/runtime_process.rs b/packages/d2bd-runtime/src/runtime_process.rs index 963855561..3e513d21c 100644 --- a/packages/d2bd-runtime/src/runtime_process.rs +++ b/packages/d2bd-runtime/src/runtime_process.rs @@ -162,10 +162,10 @@ pub fn validate_lock_parent( // `root:d2b 1770` (sticky bit, world-closed) with explicit POSIX // ACLs (g::r-x, u:d2bd:rwx, m::rwx) so: // - launcher users (members of `d2b`) traverse via the effective - // group ACL entry (g::r-x) to reach `/run/d2b/public.sock` + // group ACL entry (g::r-x) to reach `/run/d2b/public. sock` // (mode 0660, group d2b); // - d2bd gets rwx via the named-user ACL entry without owning - // the directory, so root-owned subdirs (e.g. /run/d2b/vms) + // the directory, so root-owned subdirs (e. g. /run/d2b/vms) // do not trigger the systemd-tmpfiles unsafe-path-transition guard; // - the sticky bit prevents d2bd from unlinking those root-owned // children. @@ -335,7 +335,7 @@ pub fn bind_public_socket(path: &Path, identity: &RuntimeIdentity) -> Result std::path::PathBuf { } /// Tiny RFC-3339 UTC formatter (`YYYY-MM-DDTHH:MM:SSZ`) so we can -/// stamp `DaemonVersionFile.started_at` without pulling in `chrono` +/// stamp `DaemonVersionFile. started_at` without pulling in `chrono` /// as a new top-level dependency. The daemon's startup is the only /// caller; precision to the second is sufficient. pub fn chrono_like_rfc3339() -> String { @@ -751,7 +751,7 @@ mod runtime_acl_tests { /// `expect_root_owned_parent=true` chgrp actually mutated the /// socket's gid. The caller is a member of every group `getgroups` /// returns, so `chown(None, Some(supp_gid))` is permitted by POSIX. - /// Returns `None` when the runtime has only the primary gid (e.g. + /// Returns `None` when the runtime has only the primary gid (e. g. /// inside minimal CI containers); the caller skips the assertion in /// that case with a visible log line so the gap is documented /// rather than silently passing. diff --git a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs index 9e39ae653..299a796e8 100644 --- a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs +++ b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs @@ -267,14 +267,14 @@ pub fn check_sshd_host_keys(vm: &str, keys_dir: &Path) -> Result<(), SshdHostKey } let mode = meta.permissions().mode() & 0o7777; // Review note: when the file has POSIX ACL named - // entries (e.g. from the activation script's per-keyfile + // entries (e. g. from the activation script's per-keyfile // `u:virtiofsd_uid:r` grant required by ADR 0021 broker- // pre-NS virtiofsd reading the 0400 root:root host key), // Linux stores the mask in the file's group-mode bits. The // group's BASE perm (in the ACL's ACL_GROUP_OBJ entry) is // still ---, but stat() reports 0440 because the mask is r. // Accept either 0400 (no ACL) or 0440 (ACL with mask r--) - // when the file has a system.posix_acl_access xattr; reject + // when the file has a system. posix_acl_access xattr; reject // any other mode. let mode_ok = if mode == EXPECTED_KEY_MODE { true @@ -309,7 +309,7 @@ pub fn check_sshd_host_keys(vm: &str, keys_dir: &Path) -> Result<(), SshdHostKey } /// Returns true when the file has a -/// `system.posix_acl_access` xattr (i.e. the activation script's +/// `system. posix_acl_access` xattr (i. e. the activation script's /// `setfacl -m u:UID:r` grant for ADR 0021 broker-pre-NS /// virtiofsd has been applied). Used by the preflight to /// distinguish 0o0440-with-ACL (legitimate) from 0o0440-without-ACL diff --git a/packages/d2bd-runtime/src/supervisor/pidfd_table.rs b/packages/d2bd-runtime/src/supervisor/pidfd_table.rs index b83572dfa..a1aa6f9f3 100644 --- a/packages/d2bd-runtime/src/supervisor/pidfd_table.rs +++ b/packages/d2bd-runtime/src/supervisor/pidfd_table.rs @@ -272,7 +272,7 @@ impl PidfdTable { self } - /// Set the `BrokerReapLog` on an already-constructed table (e.g. + /// Set the `BrokerReapLog` on an already-constructed table (e. g. /// after `restore_from_disk`). pub fn set_broker_reap_log(&self, log: Arc) { let _ = self.broker_reap_log.set(log); @@ -598,7 +598,7 @@ impl PidfdTable { /// Duplicate the daemon-held pidfd for `(vm, role)` for a read-only /// liveness poll. Returns the dup'd fd plus the registered /// `(pid, start_time_ticks)`, or `None` when no entry is registered - /// (e.g. rollback already removed it) or the dup fails. + /// (e. g. rollback already removed it) or the dup fails. /// /// This OBSERVES only - it never removes the entry. All /// deregistration stays in the teardown / rollback path. diff --git a/packages/d2bd-runtime/src/typed_error.rs b/packages/d2bd-runtime/src/typed_error.rs index 933845388..d8581d070 100644 --- a/packages/d2bd-runtime/src/typed_error.rs +++ b/packages/d2bd-runtime/src/typed_error.rs @@ -583,7 +583,7 @@ pub enum TypedError { /// Refusal raised by the VM-start preflight for `sys--net` VMs /// when the on-disk /// dnsmasq.conf hash diverges from the bundle's expectation. - /// `env` is the env scope (e.g. `corp`, `personal`, `obs`); + /// `env` is the env scope (e. g. `corp`, `personal`, `obs`); /// `expected` and `actual` are 64-char lowercase SHA-256 hex /// digests. The mismatch indicates the bundle was updated but /// the dnsmasq render step did not rerun - rebuild the bundle @@ -697,7 +697,7 @@ pub enum TypedError { ConsoleSessionTableFull { vm: String, }, - /// A realm workload canonical target (`workload.realm.d2b`) was supplied + /// A realm workload canonical target (`workload. realm. d2b`) was supplied /// but is not present in the realm workload index. The caller must use a /// declared workload target or a known legacy VM name. WorkloadTargetNotFound { diff --git a/packages/d2bd/src/audio_host_controller.rs b/packages/d2bd/src/audio_host_controller.rs index a32c8c215..7cc6a3433 100644 --- a/packages/d2bd/src/audio_host_controller.rs +++ b/packages/d2bd/src/audio_host_controller.rs @@ -19,9 +19,9 @@ //! ## PipeWire node targeting //! //! The vhost-user-sound sidecar is launched with -//! `PIPEWIRE_PROPS={ application.name = "d2b-" ... }`. The controller +//! `PIPEWIRE_PROPS={ application. name = "d2b-" ... }`. The controller //! resolves the live PipeWire node id with `pw-dump`, filtering by -//! `application.name` plus `media.class` so speaker and microphone controls do +//! `application. name` plus `media. class` so speaker and microphone controls do //! not target the same ambiguous node name. //! //! ## Credential posture diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index b87dcf6c0..abf4c5c1f 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -550,7 +550,7 @@ struct ServerState { pidfd_table: Arc, broker_reap_log: Arc, metrics_registry: Arc, - /// Daemon-side audit log for supervisor events (e.g. api-ready + /// Daemon-side audit log for supervisor events (e. g. api-ready /// timeout) that are not emitted by the broker. daemon_audit: Arc, /// In-process Process-session table (caps + opaque handles) for @@ -5392,7 +5392,7 @@ impl d2bd_runtime::autostart::VmStarter for BrokerVmStarter { let request = public_wire::VmLifecycleRequest { vm: vm.to_owned(), flags: public_wire::MutationFlags { - mode: public_wire::MutationMode::Apply, + mode: Some(public_wire::MutationMode::Apply), json: true, }, force: false, @@ -5512,7 +5512,7 @@ async fn run_startup_autostart(state: &ServerState, kernel_module_degraded: &BTr let _ = resolver; } -/// Thin wrapper used by the `options.once` test path and by direct +/// Thin wrapper used by the `options. once` test path and by direct /// unit-test callers: authorizes the peer (SO_PEERCRED), then runs the /// authorized connection body. The production accept loop authorizes the /// peer itself (before admission) and calls @@ -6943,7 +6943,7 @@ fn dispatch_guest_lifecycle_resource_request( Ok(mode) => mode, Err(response) => return Ok(response), }; - if let Some(response) = mutating_verb_preflight(&verb, mode, Some(target.name().as_str())) { + if let Some(response) = mutating_verb_preflight(&verb, Some(mode), Some(target.name().as_str())) { return Ok(response); } let caller_role = broker_caller_role_for_peer(peer); @@ -7137,7 +7137,7 @@ fn dispatch_process_lifecycle_resource_request( Ok(mode) => mode, Err(response) => return Ok(response), }; - if let Some(response) = mutating_verb_preflight(&verb, mode, Some(target.name().as_str())) { + if let Some(response) = mutating_verb_preflight(&verb, Some(mode), Some(target.name().as_str())) { return Ok(response); } let base_operation_id = @@ -7295,7 +7295,10 @@ fn dispatch_device_usb_resource_request( Ok(mode) => mode, Err(response) => return Ok(response), }; - let flags = public_wire::MutationFlags { mode, json: false }; + let flags = public_wire::MutationFlags { + mode: Some(mode), + json: false, + }; match method { "DeviceUsbAttach" => dispatch_broker_usbip_bind( state, @@ -10246,21 +10249,39 @@ fn mutation_mode_from_request( }) } -/// One mutating-verb preflight response: the daemon-side plan for a dry run, -/// or `None` for an apply request that proceeds to dispatch. +/// One mutating-verb preflight response: the structured refusal for a request +/// that selected no mode, the daemon-side plan for a dry run, or `None` for an +/// apply request that proceeds to dispatch. /// -/// The mode is closed, so the "neither flag set" refusal the pair used to need -/// has no case here; raw request frames are refused at -/// [`mutation_mode_from_request`]. +/// `mode` is `None` when the request set neither `dryRun` nor `apply`. That +/// case decodes rather than failing, so it is refused here and keeps the +/// typed outcome and remediation string a client can match on. fn mutating_verb_preflight( verb: &str, - mode: d2b_contracts_control::public_wire::MutationMode, + mode: Option, target_vm: Option<&str>, ) -> Option { use d2b_contracts_control::public_wire::{ MutationMode, MutatingVerbOutcome, MutatingVerbResponse, }; + let mode = match mode { + Some(mode) => mode, + None => { + return Some(d2bd_runtime::wire::mutating_verb_response( + MutatingVerbResponse { + verb: verb.to_owned(), + outcome: MutatingVerbOutcome::InvalidRequest, + target_wave: None, + summary: None, + remediation: Some(format!( + "d2b {verb} requires either --dry-run or --apply" + )), + api_ready: None, + }, + )); + } + }; match mode { MutationMode::Apply => None, MutationMode::DryRun => { @@ -10384,7 +10405,7 @@ fn cloud_hypervisor_api_socket(argv: &[String]) -> Option { /// The producer-derived Endpoint generation one guest-control Endpoint /// carries. /// -/// The old daemon publication stage stamped `status.resource.endpointGeneration` +/// The old daemon publication stage stamped `status. resource. endpointGeneration` /// from the Endpoint row's own generation; `Endpoint` is a converted type, so /// a manager row has no durable status to read and the row's committed /// generation is the same value the old stage published. @@ -11366,7 +11387,7 @@ async fn live_cached_guest_session_generation( } /// Re-adopt every assignment the directory holds for one Guest after a -/// (re)connect: the target layer is the only place that re-binds a handle to +/// (re) connect: the target layer is the only place that re-binds a handle to /// the live session generation, and a source the Guest cannot confirm is left /// for its owning actor to realize again (F5). async fn adopt_guest_target_assignments( @@ -14686,7 +14707,7 @@ async fn open_resource_plane( // v3 resource plane (U9/U10): assemble each Zone's manager plane once the // generation publication is committed, and publish the whole table into - // `state.v3_planes` before any runtime activates. The runtime's + // `state. v3_planes` before any runtime activates. The runtime's // manager-backed API service resolves its manager client + watch hub from // that table, so a Zone whose plane is not published yet cannot activate. let mut v3_planes: BTreeMap> = @@ -17018,7 +17039,7 @@ fn request_cgroup_kill_if_populated( // its own processes.json placement (the same derivation the old typed // CgroupKill arm performed broker-side from the bundle) and the // kill-cgroup kernel kills exactly that leaf, refusing any path outside - // the delegated d2b.slice subtree. + // the delegated d2b. slice subtree. let Some(cgroup_path) = role_cgroup_path(state, vm, role_id) else { tracing::warn!(vm = %vm, role = %role_id, "broker CgroupKill request skipped: no cgroup placement"); return; @@ -18129,7 +18150,7 @@ fn host_prep_role_id_from_bundle_ref( /// Dispatch a broker request for one host-prep DAG step where the broker /// may return a typed response -/// (e.g. `CreatePersistentTap`, `SetBridgePortFlags`) rather than +/// (e. g. `CreatePersistentTap`, `SetBridgePortFlags`) rather than /// the canonical `Ack`. Treats any non-`Error` response as success /// and surfaces `Error` responses through the same launcher-side /// redaction path used by `dispatch_broker_ack_request`. Any fd @@ -18298,7 +18319,7 @@ fn execute_host_prep_dag( use d2b_host::host_prep_dag::HostPrepStepKind; const VERB: &str = "vm start"; // Resolve the per-VM state directory once (used by daemon-native - // step handlers that need filesystem context, e.g. the + // step handlers that need filesystem context, e. g. the // ssh-host-key preflight). The v3 zone-native Guest resource carries // no stateDir surface (the v2 manifest is an empty stub), so there is // no clean stateDir source; daemon-native handlers gracefully no-op. @@ -19107,7 +19128,11 @@ fn next_provider_lifecycle_operation_id( operation: &str, request: &public_wire::VmLifecycleRequest, ) -> String { - let (dry_run, apply) = request.flags.mode.to_flags(); + let (dry_run, apply) = request + .flags + .mode + .map(public_wire::MutationMode::to_flags) + .unwrap_or((false, false)); let fingerprint = format!( "force={};no_wait_api={};dry_run={dry_run};apply={apply};json={}", request.force, @@ -21142,7 +21167,7 @@ fn build_public_list( } = load_public_request_artifacts(state, false, true)?; // Resolve the `vm` filter through the workload index so callers can - // use a canonical target (`vm.realm.d2b`) or unambiguous workload id. + // use a canonical target (`vm. realm. d2b`) or unambiguous workload id. let resolved_vm_filter = resolve_vm_filter_target(request.vm.as_deref(), workload_index.as_ref(), &manifest) .map_err(typed_error_from_resolution_error)?; @@ -22987,7 +23012,7 @@ mod public_status_tests { request: public_wire::VmLifecycleRequest { vm: "vm-a".to_owned(), flags: public_wire::MutationFlags { - mode: public_wire::MutationMode::Apply, + mode: Some(public_wire::MutationMode::Apply), json: false, }, force: false, @@ -23786,7 +23811,7 @@ pub(crate) mod detached_exec_routing_tests { } } -/// The public.sock accept loop is serial: it accepts one connection, runs +/// The public. sock accept loop is serial: it accepts one connection, runs /// `handle_connection`, then accepts the next. A Process resource owner /// connection is long-lived, so `handle_connection` MUST hand it off to a /// spawned owner thread and return immediately - otherwise the single accept @@ -24147,7 +24172,7 @@ mod accept_loop_concurrency_tests { handle_a.join().expect("accept-loop thread joins"); // Prove the owner session is STILL HELD OPEN (the body has not torn - // down) at the moment handle_connection has already returned - i.e. the + // down) at the moment handle_connection has already returned - i. e. the // dispatch was genuinely off-loop, concurrent with the accept loop. { let (lock, _cv) = &*shared; @@ -24159,7 +24184,7 @@ mod accept_loop_concurrency_tests { ); } - // --- Connection B: a SECOND public.sock request is accepted and served + // --- Connection B: a SECOND public. sock request is accepted and served // while connection A's owner session is still held open. --- let (server_b, client_b) = seqpacket_pair(); let client_b = std::thread::spawn(move || { @@ -25523,7 +25548,7 @@ mod broker_dispatch_tests { d2bd_runtime::wire::Request::VmStart(VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, force: false, @@ -25535,7 +25560,7 @@ mod broker_dispatch_tests { d2bd_runtime::wire::Request::VmStop(VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, force: false, @@ -25547,7 +25572,7 @@ mod broker_dispatch_tests { d2bd_runtime::wire::Request::VmRestart(VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, force: false, @@ -25560,7 +25585,7 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }), @@ -25571,7 +25596,7 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }), @@ -25582,7 +25607,7 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }), @@ -25593,7 +25618,7 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), to_generation: None, flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }), @@ -25605,7 +25630,7 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), bus_id: "1-1".to_owned(), flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }, @@ -25618,7 +25643,7 @@ mod broker_dispatch_tests { vm: "vm-a".to_owned(), bus_id: "1-1".to_owned(), flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }, @@ -25628,7 +25653,7 @@ mod broker_dispatch_tests { "hostPrepare", d2bd_runtime::wire::Request::HostPrepare(HostPrepareRequest { flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }), @@ -25637,7 +25662,7 @@ mod broker_dispatch_tests { "hostDestroy", d2bd_runtime::wire::Request::HostDestroy(HostDestroyRequest { flags: MutationFlags { - mode: MutationMode::DryRun, + mode: Some(MutationMode::DryRun), json: false, }, }), @@ -25895,7 +25920,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -26101,7 +26126,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -26434,7 +26459,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -26736,7 +26761,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -26782,7 +26807,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -26821,7 +26846,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -27594,7 +27619,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -27639,7 +27664,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -27783,7 +27808,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -27919,7 +27944,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28060,7 +28085,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28167,7 +28192,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28182,7 +28207,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28219,7 +28244,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28273,7 +28298,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28311,7 +28336,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28350,7 +28375,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28401,7 +28426,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28512,7 +28537,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: vm.to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28715,7 +28740,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "vm-a".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, @@ -28741,7 +28766,7 @@ mod broker_dispatch_tests { &state, HostPrepareRequest { flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, }, @@ -28837,7 +28862,7 @@ mod broker_dispatch_tests { &state, HostPrepareRequest { flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, }, @@ -29041,7 +29066,7 @@ mod broker_dispatch_tests { &state, HostDestroyRequest { flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, }, @@ -29085,7 +29110,7 @@ mod broker_dispatch_tests { &state, HostDestroyRequest { flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, }, @@ -29103,7 +29128,7 @@ mod broker_dispatch_tests { ); } - /// Wiring test: verify that `ServerState.daemon_audit` is wired with a + /// Wiring test: verify that `ServerState. daemon_audit` is wired with a /// `DaemonAuditLog` that can capture `DaemonEvent::ApiReadyTimeout` /// events, and that the event serialises with the expected field shape. /// @@ -29593,7 +29618,7 @@ mod broker_dispatch_tests { // HAZARD: the stateless readiness helper treats an EMPTY predicate // slice as TRIVIALLY ready - it returns Ok without running any // probe. `spawn_and_check_process_alive` (the process-alive fast - // path, e.g. `--no-wait-api`) delegates the node to + // path, e. g. `--no-wait-api`) delegates the node to // `spawn_and_wait_ready(vm, node, &[], budget)` with exactly this // empty slice. If a ComponentSessionHealth node ever reached // `wait_for_readiness`, an absent/auth-failing component-session @@ -29610,7 +29635,7 @@ mod broker_dispatch_tests { // `spawn_and_check_process_alive` does NOT take the LongLived // process-alive-only short-circuit (which registers a node as alive // after spawn with no probe at all). It falls through to - // `spawn_and_wait_ready`, whose `node.role == ComponentSessionHealth` + // `spawn_and_wait_ready`, whose `node. role == ComponentSessionHealth` // special case runs `wait_for_component_session_health` BEFORE the empty // readiness slice can reach the trivially-ready `wait_for_readiness`. // Were ComponentSessionHealth ever made LongLived, or the interception @@ -30090,7 +30115,7 @@ mod broker_dispatch_tests { /// Creates bundle artifacts for a minimal obs-enabled VM start test. /// The obs VM has an empty process DAG (no nodes) so the supervisor DAG /// succeeds immediately without a broker connection. The bundle is wired - /// with `_observability.enabled=true` and `vmName="obs"` so + /// with `_observability. enabled=true` and `vmName="obs"` so /// `dispatch_broker_vm_start` reaches the OtelHostBridge readiness gate. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn write_obs_enabled_bundle_artifacts(root: &Path) -> ArtifactPaths { @@ -30234,7 +30259,7 @@ mod broker_dispatch_tests { /// is bypassed entirely and the `degraded` field MUST NOT appear in the /// success envelope. Prevents false-positive `degraded` from leaking into /// VM starts that were explicitly requested without the API-readiness wait - /// (e.g., CLI `--no-wait-api` flag). + /// (e. g., CLI `--no-wait-api` flag). #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn vm_start_non_obs_vm_has_no_degraded_field_in_envelope() { @@ -30304,7 +30329,7 @@ mod broker_dispatch_tests { VmLifecycleRequest { vm: "obs".to_owned(), flags: MutationFlags { - mode: MutationMode::Apply, + mode: Some(MutationMode::Apply), json: false, }, force: false, diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index 83bd9abea..2f2b92f87 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -665,7 +665,7 @@ impl ForwardRendezvous { ), }; // The handler-side legs append the invoking handler's own - // identity;the daemon-side record of a forwarded nested leg + // identity; the daemon-side record of a forwarded nested leg // keys on the root id and the chain's depth exactly as the // broker-side record of the in-broker leg does. @@ -1439,7 +1439,7 @@ impl AsyncSeqpacket { /// /// A frame and its attachments arrive together or not at all, so the /// received descriptor count is exactly what the sender put on the - /// carrier;an oversized cmsg set is capped by the kernel at the receive + /// carrier; an oversized cmsg set is capped by the kernel at the receive /// buffer's ceiling, which is why the caller-side declaration check /// refuses a count over that ceiling rather than let a truncation pass.. async fn read_frame_with_fds(&self, deadline: Duration) -> Result<(Vec, Vec), TypedError> { @@ -1462,7 +1462,7 @@ impl AsyncSeqpacket { deadline: Duration, ) -> Result<(), TypedError> { // The transport writes the length prefix itself,so the body crosses - // as-is;the receiving transport strips the same prefix back off.. + // as-is; the receiving transport strips the same prefix back off.. match tokio::time::timeout(deadline, self.send_datagram_with_fds(body, fds)).await { Ok(Ok(())) => Ok(()), Ok(Err(error)) => Err(send_failure(error.to_string(), error_source(error))), @@ -1967,9 +1967,9 @@ mod tests { /// A handler that reads the descriptor the carrier attached to its /// call. The forwarded request leg carries the caller's descriptor over - /// SCM_RIGHTS;the rendezvous validates it against the wire declarations + /// SCM_RIGHTS; the rendezvous validates it against the wire declarations /// and hands it to the declared handler, so this handler reading it back - /// proves the round trip through the real socket and the provider envelope.to + /// proves the round trip through the real socket and the provider envelope. to struct FdEchoHandler; #[async_trait::async_trait] @@ -2487,7 +2487,7 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") use d2bd_runtime::unix_transport::write_frame_with_fds; /// Forward one invocation with SCM_RIGHTS attachments on the request /// frame, the way the broker's forwarder does once the request leg - /// carries fds.to + /// carries fds. to fn forward_with_fds( socket_path: &Path, operation: &str, @@ -3746,7 +3746,7 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") // one-shot publication dial (started by the test after this returns) // can never race the bind: a dial before the bind would error, the // daemon would never retry, and the accept below would block the - // test's `broker.join()` forever. + // test's `broker. join()` forever. let listener = bind_public_socket(&socket_path, &test_identity()) .expect("bind the test broker socket"); std::thread::spawn(move || { diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index ebaa4d531..7a1c2766b 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -3149,7 +3149,7 @@ pub(crate) async fn resolve_device_worker_launch( // and no Guest target, so the row's own launch identity names no VM // by construction. The coherent VM scope is the owning Device's // Guest owner - the same derivation `tpm_device_targets_vm` requires - // (`Device.metadata.ownerRef == Guest/`) and the TPM + // (`Device. metadata. ownerRef == Guest/`) and the TPM // shared-provider effects mint their `VmId` from. A Device with no // Guest owner is the genuinely unresolvable case. let vm_name = match launch.vm() { @@ -3240,7 +3240,7 @@ pub(crate) async fn resolve_device_worker_launch( let settings = device_gpu_settings(ctx, &owner_key).await?; // The Wayland socket the sidecar renders into is projected by // the trusted bundle from the site's own Wayland session - // (`d2b.site.waylandUser` / `waylandDisplay`, see + // (`d2b. site. waylandUser` / `waylandDisplay`, see // `nixos-modules/site-json.nix`). A bundle without the // artifact, or a headless site, leaves the slot unbound and // the launch refuses with its own code instead of naming a @@ -3561,7 +3561,7 @@ fn device_state_dir( /// /// Only an absent Provider extension decodes to the Provider's bounded /// default. A present settings payload that does not decode as the closed -/// `device-gpu.d2bus.org` extension refuses with its own code instead: folding +/// `device-gpu. d2bus. org` extension refuses with its own code instead: folding /// it into the default made an undecodable declaration indistinguishable from /// a Device that declares nothing, and the default's context classes /// (including `CrossDomain`) are wider than anything the Device declared. @@ -3579,7 +3579,7 @@ fn decode_device_gpu_settings( } /// The owning Device's declared GPU settings (the closed -/// `device-gpu.d2bus.org` Device extension); a Device that declares none +/// `device-gpu. d2bus. org` Device extension); a Device that declares none /// keeps the Provider's own bounded default. async fn device_gpu_settings( ctx: &mut ResourceContext, @@ -3615,7 +3615,7 @@ fn video_nvidia_posture( /// The host Wayland socket the GPU sidecar renders into. /// /// The trusted bundle projects it (`site.json`, emitted from the site's own -/// `d2b.site.waylandUser` / `waylandDisplay`), so the daemon never derives +/// `d2b. site. waylandUser` / `waylandDisplay`), so the daemon never derives /// `/run/user//...` itself: the daemon's own `/run/user` is its runtime /// directory, not the session user's. `None` - a bundle that predates the /// artifact, or a site without a Wayland session - keeps the slot unbound so @@ -3644,7 +3644,7 @@ fn device_runtime_socket( socket_runtime_dir.join("vms").join(vm_name).join(file_name) } -/// The per-VM video-decoder socket (`/run/d2b-video//video.sock`): the +/// The per-VM video-decoder socket (`/run/d2b-video//video. sock`): the /// video module's own `RuntimeDirectory` and the guest's /// `--vhost-user-media socket=` argument name it, so the video runtime root is /// a sibling of the daemon's runtime root. @@ -6050,7 +6050,7 @@ mod tests { // -- Launched-runner pidfd-table registration ----------------------------- // - // A failed launch (e.g. a readiness-probe envelope timeout) stops the + // A failed launch (e. g. a readiness-probe envelope timeout) stops the // spawned child but never clears the daemon's pidfd-table slot for its // (vm, role). The next launch's observer registration would hit the // duplicate guard and be swallowed, leaving the probe and the stop path diff --git a/packages/d2bd/src/provider_lifecycle.rs b/packages/d2bd/src/provider_lifecycle.rs index 2b698dfc2..21813843c 100644 --- a/packages/d2bd/src/provider_lifecycle.rs +++ b/packages/d2bd/src/provider_lifecycle.rs @@ -994,7 +994,7 @@ impl ProviderRuntime { })? } - /// (Re)publish one effect service row on the zone's supervisor, taking + /// (Re) publish one effect service row on the zone's supervisor, taking /// effect at the composition point the plane publishes declared /// services. A republish of a live service bumps the generational /// binding revision and rebuilds the actor from the new row (KTD5). diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 9b168727a..c2f4676e8 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -18,7 +18,7 @@ //! ## Spec store path decision //! //! The store is a plain daemon-owned file under -//! `/zones//spec-store.sqlite3`. It is never opened +//! `/zones//spec-store. sqlite3`. It is never opened //! through a broker fd handover: the broker-provisioned //! `/zones/` directory is owned by the zone-store //! principal, so a spec store placed there fails to open with @@ -1789,7 +1789,7 @@ pub struct ConstructionInputs { pub zone_token: BoundedToken, /// The zone's daemon-owned spec-store directory /// (`/zones/`); the spec store lives at - /// `spec-store.sqlite3` underneath it. + /// `spec-store. sqlite3` underneath it. pub spec_store_dir: PathBuf, pub authority: ZoneAuthorityInputs, /// Committed `Provider` identities (KTD7) keyed by canonical reference, @@ -1867,13 +1867,13 @@ pub user_facets: UserEffectFacets, /// The daemon-supplied facet set the Guest family's effects /// implementation is built from (U10):the zone's manager view (live /// rows, committed Provider identities, and the controller-session - /// generation)andthe Cloud Hypervisor controller session, supplied + /// generation) andthe Cloud Hypervisor controller session, supplied /// through the composition root. The family never receives a /// daemon-built effect port (R2). pub guest_facets: GuestEffectFacets, /// The daemon-supplied facet sets the device families' effects /// implementations are built from (U12): each family's driver never - /// receives a daemon-built effect port (R2);the family crates serve + /// receives a daemon-built effect port (R2); the family crates serve /// their own effects over these facets. pub usbip_facets: d2b_provider_device_usbip::facets::UsbipEffectFacets, pub security_key_facets: d2b_provider_device_security_key::facets::SecurityKeyEffectFacets, @@ -2425,7 +2425,7 @@ impl AudioMediatorSource for DaemonAudioMediatorSource { /// Production `GuestOwnerIdentitySource` (KTD7): the pre-v3 plane owns `Guest`, /// so its durable rows are the authority for a Guest-owned Process launch's -/// owner uid. The old store resolved every row's `metadata.ownerRef` to the +/// owner uid. The old store resolved every row's `metadata. ownerRef` to the /// owner row's uid and the old descriptor composer read that linkage into the /// launch ticket; the converted manager row cannot carry it for an /// unconverted owner, so the Process effects resolve the same durable value @@ -2670,7 +2670,7 @@ pub enum PlaneError { /// (`CORE_CONTROLLER_HOST_REF` in the old plane). const CORE_HOST_TARGET_NAME: &str = "host-system"; -/// The canonical `spec.executionRef` resolver (U13). +/// The canonical `spec. executionRef` resolver (U13). /// /// A stored row's `spec` is the ResourceSpec object, so this reads exactly /// the `executionRef` base field the resource contracts' `PlacementAnchor:: @@ -2716,7 +2716,7 @@ impl core::fmt::Debug for ResourcePlaneV3 { impl ResourcePlaneV3 { /// The per-zone spec store path decision (documented in the module - /// header): `spec-store.sqlite3` under the daemon-owned + /// header): `spec-store. sqlite3` under the daemon-owned /// `/zones/` directory. pub fn spec_store_path(spec_store_dir: &Path) -> PathBuf { spec_store_dir.join("spec-store.sqlite3") @@ -2989,9 +2989,9 @@ impl ResourcePlaneV3 { pub async fn prepare(inputs: ConstructionInputs) -> Result { let readiness = Arc::new(NewPlaneReadinessState::new()); // Stage 1: durable spec store. The directory create is async - // (`tokio::fs`);the SQLite open + migration has no async form and runs + // (`tokio::fs`); the SQLite open + migration has no async form and runs // once on the daemon's reused bounded loader seat (plan KTD2: zero - // new seats;d2bd already drives bundle resolution on the same + // new seats; d2bd already drives bundle resolution on the same // shipped bounded worker). A saturated seat refuses the plane start // with a named Authority error instead of parking the worker. let store_path = Self::spec_store_path(&inputs.spec_store_dir); @@ -3424,7 +3424,7 @@ impl ResourcePlaneV3 { let plan = partition_nix_bundle(&self.zone, bundle, &self.store).await?; let subject = nix_bundle_subject(&bundle.integrity.content_hash); let mut report = BundleIngestReport::default(); - // Owners before owned. A bundle row that declares `metadata.ownerRef` + // Owners before owned. A bundle row that declares `metadata. ownerRef` // is ensured as that owner's child, so the manager links ownership by // uid the way R8 defines it: the Core `Provider` driver reads its // owned controller `Process` rows through that link (an unlinked row @@ -4753,7 +4753,7 @@ HOST_EFFECTS_SERVICE.id, /// U15:the composition root hosts the process-systemd family's /// declared effects service from the family's own factory over the /// registered service identity (U3, R5: the registration table - /// carries the row;the daemon names no family string, only the + /// carries the row; the daemon names no family string, only the /// crate's declared service id), and the hosted service answers /// `inspect-process-systemd` through the real invocation capability /// object carrying the real envelope payload - hermetic, served from diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index f4dea943e..fe0b3e238 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -310,7 +310,7 @@ pub(crate) async fn bridge_manager_row( /// /// Role/RoleBinding/Zone/Provider and the subject rows are manager rows, so /// without them a RoleBinding whose Role row moved returns -/// `AuthorizationUnavailable` and its subjects are dropped - i.e. the Zone's +/// `AuthorizationUnavailable` and its subjects are dropped - i. e. the Zone's /// committed policy would empty out. A miss stays the loud, fail-closed /// compile failure it is today. /// @@ -2471,7 +2471,7 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { // row has no durable status to write - the row's actor owns // status (R11). The controller's layered status is captured // by the effect call that drove this session and published as - // the row's `status.resource` projection; a session with no + // the row's `status. resource` projection; a session with no // capture point (an explicit lifecycle relist) acknowledges // the write without persisting it. Converted children never // never receive a provider-written status either: the Process and @@ -4155,8 +4155,8 @@ impl ZoneResourceRuntime { /// reference. /// /// The pre-v3 store linked every owned row to its owner by uid: it - /// resolved the row's `metadata.ownerRef` to the owner row's uid and - /// carried that value in `record.owner_uid` + /// resolved the row's `metadata. ownerRef` to the owner row's uid and + /// carried that value in `record. owner_uid` /// (`@@REDB-D@@::transaction::resolve_uid_in_read`), and the /// old Process descriptor composer read it as the launch ticket's owner /// identity. `Guest` stays on this plane, so a converted Process row @@ -6079,7 +6079,7 @@ fn child_publication_gate( /// Whether one committed child row's status reports a failure the row's own /// actor will retry: the manager view stamps a failed actor's closed -/// classification under `status.resource.driverFailure` (the converted plane +/// classification under `status. resource. driverFailure` (the converted plane /// has no durable status, R11/AE6), so this is where a reader can tell a /// child's retry in progress from a terminal child failure. fn row_status_failure_is_retryable(resource: &Value) -> bool { @@ -10022,7 +10022,7 @@ where /// R11/AE6 leaves the public Resource API no status write path, so the /// daemon's operator admission is the last layer that sees a submission: both /// spellings a request may use (`status`, or the nested -/// `resource.status`) are read here, and this is the enforcement point for +/// `resource. status`) are read here, and this is the enforcement point for /// `ADR-046-telemetry-audit-and-support`, section "Host resource status". The /// `system-core` reconciler sets `isolationPosture` and /// `isolationPostureMessage` on every user-only Host from the spec alone, and diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index c364c7633..8c4b769e4 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -404,7 +404,7 @@ impl ProductionSharedProviderEffects { } /// The old-shape document of one resource (`spec`, `metadata`, live - /// `status.phase`) from the manager view. + /// `status. phase`) from the manager view. async fn resource_value( &self, target: &ResourceRef, @@ -560,7 +560,7 @@ struct NetworkReadiness { } /// The Network child port over the manager-routed surface: every upsert is a -/// `ctx.ensure_child` (F1) and every read is the live row. +/// `ctx. ensure_child` (F1) and every read is the live row. struct NetworkChildPort<'a> { effects: &'a ProductionSharedProviderEffects, request: &'a SharedProviderEffectRequest<'a>, @@ -696,7 +696,7 @@ fn child_ref(resource_type: &str, name: &str) -> ResourceRef { /// The spec-level content projection check (old /// `network_config_content_projection_ready` without its persisted-status -/// terms: the materialization evidence lived in `status.resource`, which R11 +/// terms: the materialization evidence lived in `status. resource`, which R11 /// deletes; the Volume actor's live Ready phase is the equivalent gate). fn network_config_projection_present(value: &Value, volume_uid: &ResourceUid) -> bool { let Some(provider) = value.pointer("/spec/provider") else { @@ -1080,9 +1080,9 @@ impl ProductionSharedProviderEffects { .ok_or(SharedProviderEffectError::InvalidResource)?; // The attached row's authoritative zone is the zone its key // resolved under (`resource_value` reads the plane for - // `self.zone`); the stored metadata carries no zone, so the old + // `self. zone`); the stored metadata carries no zone, so the old // `/metadata/zone` read was always `None` and refused every - // attachment unconditionally. `request.zone` is external input, + // attachment unconditionally. `request. zone` is external input, // so the fence stays: a request naming a zone the resolved rows // cannot be in is refused. if self.zone.as_str() != request.zone.as_str() { @@ -1133,9 +1133,9 @@ impl ProductionSharedProviderEffects { if !attached { continue; } - // The committed Guest rows were resolved under `self.zone` (the + // The committed Guest rows were resolved under `self. zone` (the // type-scoped manager list selects the plane's own zone), so the - // row's authoritative zone is `self.zone`; the fence compares it + // row's authoritative zone is `self. zone`; the fence compares it // against the request zone instead of a projection-synthesised // field. if self.zone.as_str() != request.zone.as_str() { diff --git a/packages/xtask/src/blocking_census.rs b/packages/xtask/src/blocking_census.rs index aedb44b0b..74b401935 100644 --- a/packages/xtask/src/blocking_census.rs +++ b/packages/xtask/src/blocking_census.rs @@ -69,7 +69,7 @@ pub enum EntryKind { /// clippy matches on (everything after the final `::`), and the counting /// class. pub struct DeniedApi { - /// Fully-qualified API path as configured, e.g. `std::sync::Mutex::lock`. + /// Fully-qualified API path as configured, e. g. `std::sync::Mutex::lock`. pub path: String, /// The bare tail clippy matches on: everything after the final `::`. pub tail: String, @@ -323,7 +323,7 @@ pub struct SuppressionSite { pub blanket: bool, /// `#[expect(...)]` rather than `#[allow(...)]`. pub expect: bool, - /// The banned lint, e.g. `clippy::disallowed_methods`. + /// The banned lint, e. g. `clippy::disallowed_methods`. pub lint: String, /// The attribute's `reason = "..."` value, when present. pub reason: Option, @@ -639,7 +639,7 @@ fn reason_in_args(args: &[String]) -> Option { /// suppression inventory. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct CrateCensus { - /// Crate directory relative to the repo root, e.g. `packages/d2b-broker`. + /// Crate directory relative to the repo root, e. g. `packages/d2b-broker`. pub crate_dir: String, /// Package name from the manifest. pub package_name: String, @@ -672,7 +672,7 @@ struct CensusFile { split: SplitContext, } -/// The workspace member paths the root manifest declares, e.g. +/// The workspace member paths the root manifest declares, e. g. /// `packages/d2b-broker`. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn workspace_member_paths(repo_root: &Path) -> Result, String> { @@ -874,7 +874,7 @@ fn first_diagnostic(stderr: &str) -> Option { /// before any warning is considered; `None` when the stream has no /// error-level record and no warning that carries a primary span (a /// spanless warning is dropped, so a spanless-warning-only stream also -/// yields `None` - e.g. a cargo-level failure that never reached rustc). +/// yields `None` - e. g. a cargo-level failure that never reached rustc). fn first_json_diagnostic(json: &str) -> Option { let mut first_warning: Option = None; let mut first_spanless_error: Option = None; @@ -931,7 +931,7 @@ fn first_json_diagnostic(json: &str) -> Option { /// (run_clippy) consults it before accepting a warning-only JSON pick. fn first_stderr_error(stderr: &str) -> Option { // First error-level header, span or spanless: cargo-level failures - // (e.g. `error: failed to run custom build command`) never carry a + // (e. g. `error: failed to run custom build command`) never carry a // `--> file:line` span, but they are the real cause when the JSON // stream holds only warnings. let lines: Vec<&str> = stderr.lines().collect(); @@ -1112,7 +1112,7 @@ fn collect_crate_files( } /// Whether a clippy hit at `file:line` is test context, by the same split -/// the lexical meter uses。 +/// the lexical meter uses. fn hit_is_test(files: &[CensusFile], file: &str, line: usize) -> bool { files .iter() @@ -1126,7 +1126,7 @@ fn hit_is_test(files: &[CensusFile], file: &str, line: usize) -> bool { }) } -/// Fails when any current per-crate count exceeds its committed baseline。 +/// Fails when any current per-crate count exceeds its committed baseline. fn check_against_baseline<'a>( baseline_path: &Path, crates: impl Iterator)>, @@ -1176,9 +1176,9 @@ fn check_against_baseline<'a>( Ok(()) } -/// Run the census over the repository or the given crate paths。Prints the -/// per-crate tables and the totals;with `json_out` writes the authoritative -/// per-crate counts (the baseline shape);with `baseline` fails when any +/// Run the census over the repository or the given crate paths. Prints the +/// per-crate tables and the totals; with `json_out` writes the authoritative +/// per-crate counts (the baseline shape); with `baseline` fails when any /// covered crate's count exceeds its committed baseline (plan R15). #[allow(clippy::disallowed_methods, reason = "CLI-only path")] pub fn run( diff --git a/packages/xtask/src/changelog.rs b/packages/xtask/src/changelog.rs index 8f9d8c8a7..30a728fa7 100644 --- a/packages/xtask/src/changelog.rs +++ b/packages/xtask/src/changelog.rs @@ -1,6 +1,6 @@ -//! Fragment assembler for the `changelog.d/` directory. +//! Fragment assembler for the `changelog. d/` directory. //! -//! Concurrent branches each drop one fragment file into `changelog.d/` +//! Concurrent branches each drop one fragment file into `changelog. d/` //! instead of appending to the shared `## [Unreleased]` block in //! `CHANGELOG.md`. Every branch then writes a file no other branch touches, //! so the changelog stops being a guaranteed merge conflict whenever more @@ -30,7 +30,7 @@ pub const CHANGELOG_FILE: &str = "CHANGELOG.md"; /// Transaction directory for an in-flight fold, created in the resolved /// repository root - the real directory holding `CHANGELOG.md` and -/// `changelog.d/` - so every rename into and out of it is atomic and stays on +/// `changelog. d/` - so every rename into and out of it is atomic and stays on /// one filesystem. A fixed (non-PID) name lets a later invocation discover an /// interrupted transaction and recover it. const TXN_DIR: &str = ".changelog-fold-txn"; @@ -131,7 +131,7 @@ pub struct FragmentSection { pub entries: Vec, } -/// A parsed `changelog.d/.md` fragment. +/// A parsed `changelog. d/.md` fragment. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Fragment { /// Fragment file name, used for ordering and error messages. @@ -390,7 +390,7 @@ pub struct Outcome { /// /// The Bazel entry point (`bazel run --config=local //packages/xtask:xtask`) /// reaches the checkout through a symlink forest: `CHANGELOG.md` and -/// `changelog.d/` under the execroot are links into the real workspace. Reads +/// `changelog. d/` under the execroot are links into the real workspace. Reads /// follow those links, but renaming the folded changelog *onto* `CHANGELOG.md` /// replaces the link and leaves the real file untouched, so the fold would /// consume every fragment and write nowhere (issue #519). Resolving both paths @@ -454,7 +454,7 @@ impl FoldTree { ))); } // An absent fragment directory is no fragments at all, the same - // no-op a repository without `changelog.d/` has always been. + // no-op a repository without `changelog. d/` has always been. Err(err) if err.kind() == std::io::ErrorKind::NotFound => root.join(FRAGMENT_DIR), Err(err) => { return Err(FoldError::single(format!( @@ -745,7 +745,7 @@ fn read_journal(txn: &Path) -> Option { /// recovery finishes forward by discarding the transaction (the reserved /// fragments are already consumed). Any earlier state - or an unreadable /// journal - means the promotion did not durably happen, so recovery rolls -/// back: reserved fragments return to `changelog.d/` and the original changelog +/// back: reserved fragments return to `changelog. d/` and the original changelog /// is restored from its backup. Either way the tree ends fully folded or fully /// unfolded, never half-consumed. /// @@ -896,7 +896,7 @@ fn finish_forward( } /// Undo an uncommitted transaction: return every reserved fragment to -/// `changelog.d/` and restore the original changelog from its backup, then +/// `changelog. d/` and restore the original changelog from its backup, then /// remove the transaction directory. Restorative steps run before the backup is /// consumed so a crash mid-rollback stays recoverable on the next pass. Errors /// are surfaced, never swallowed. @@ -1762,7 +1762,7 @@ mod tests { #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn fold_repo_consumes_fragments_through_a_symlinked_fragment_directory() { - // The execroot reaches `changelog.d/` through a link too: the fold must + // The execroot reaches `changelog. d/` through a link too: the fold must // reserve the real fragments and leave the link in place. let repo = TempRepo::new("fragment-dir-symlink"); repo.write_changelog(CHANGELOG); @@ -2032,7 +2032,7 @@ mod tests { repo.write_fragment("feature-a.md", "### Added\n\n- from a\n"); crash_at_boundary(&repo, FoldStage::AfterReserve(0)); - // The reserved fragment is out of changelog.d/ and inside the txn. + // The reserved fragment is out of changelog. d/ and inside the txn. assert!( repo.fragment_names().is_empty(), "fragment reserved, not in place" diff --git a/packages/xtask/src/nix_inventories.rs b/packages/xtask/src/nix_inventories.rs index 3caa260c1..bc2c2ca2b 100644 --- a/packages/xtask/src/nix_inventories.rs +++ b/packages/xtask/src/nix_inventories.rs @@ -246,8 +246,8 @@ fn core_schema_file(resource_type: &str) -> String { /// Split one qualified ResourceType into its schema namespace and local name. /// -/// A qualified type is `.d2bus.org.`; the committed artifact -/// is `.d2bus.org_.schema.json`. +/// A qualified type is `.d2bus. org.`; the committed artifact +/// is `.d2bus. org_.schema.json`. fn qualified_schema_parts( resource_type: &str, ) -> Result<(&str, &str), Box> { diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index 4c40f734d..cc7a1955a 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -3528,18 +3528,6 @@ const SHARED_FAMILY_KNOWLEDGE_RATCHET: &[SharedFamilyKnowledgeExemption] = &[ family: "activation-nixos", retires_with: "permanent: v3 contract files are shared wire vocabulary consumed by the bus, broker, daemon, and core crates; relocating them into a provider crate would add a shared-to-provider dependency edge, which the dependency-direction detector at provider_crate_policy.rs:6999 refuses", }, - SharedFamilyKnowledgeExemption { - module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", - token: "network_local", - family: "network-local", - retires_with: "permanent: the unsafe-local workload limits are shared wire vocabulary whose error variants are family-named; no shared crate may depend on a provider crate", - }, - SharedFamilyKnowledgeExemption { - module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", - token: "volume_local", - family: "volume-local", - retires_with: "permanent: the unsafe-local workload limits are shared wire vocabulary whose error variants are family-named; no shared crate may depend on a provider crate", - }, SharedFamilyKnowledgeExemption { module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", token: "nixos", @@ -6437,7 +6425,7 @@ fn check_shared_structural_knowledge(repo_root: &Path) -> Result<(), String> { } /// The named shared-crate-to-provider dependency edges the /// dependency-direction detector lists. A shared crate may depend on -/// a provider crate only through an edge named here;the list is empty +/// a provider crate only through an edge named here; the list is empty /// today and only the owning crates' moves add edges to it./ /// /// U4 re-homed the laneless primitive types into their owning provider @@ -7081,7 +7069,7 @@ fn packages_tokens(line: &str) -> Vec { end += 1; } // A `<...>` immediately after the run marks a naming-template - // placeholder (e.g. `packages/d2b-provider--/`), + // placeholder (e. g. `packages/d2b-provider--/`), // not a resolvable citation; skip it. if bytes.get(end) == Some(&b'<') { search = &rest[end..]; @@ -8836,7 +8824,7 @@ enum CommittedScopeClass { /// stale. A committed-scope check cannot police every file outside these /// classes without encoding the whole plan's touch surface, so it polices /// the crate set and the declared artifact roots, the two surfaces the plan -/// names; every other surface (docs/plans, changelog.d, tests/, Nix +/// names; every other surface (docs/plans, changelog. d, tests/, Nix /// modules, Bazel files, ...) is out of its scope by construction. struct CommittedScopeEntry { crate_name: &'static str, @@ -8845,7 +8833,7 @@ struct CommittedScopeEntry { } /// The committed workspace-crate scope, seeded from the tree the plan -/// refactors. Every workspace member must appear exactly once;every entry +/// refactors. Every workspace member must appear exactly once; every entry /// must stay a live member. The classes are the plan's own naming: the plan /// names provider crates as a class, the shared crates its lanes read /// through, the daemon, the broker, and the tooling its own check lives in. diff --git a/packages/xtask/src/provider_packaging.rs b/packages/xtask/src/provider_packaging.rs index f59d3d52f..475756b42 100644 --- a/packages/xtask/src/provider_packaging.rs +++ b/packages/xtask/src/provider_packaging.rs @@ -9,7 +9,7 @@ //! nine field groups the specification's "Package catalog" section enumerates, //! flattened into the exact field names `nixos-modules/provider-catalog.nix` //! validates every entry against. The catalog itself is compiled in Nix from -//! `d2b.artifacts.` declarations; only its shape is generated here, so that +//! `d2b. artifacts.` declarations; only its shape is generated here, so that //! the module and any later Rust consumer cannot drift apart silently. //! //! Three absences in that section are the design rather than gaps, and the diff --git a/packages/xtask/src/resource_type_authority.rs b/packages/xtask/src/resource_type_authority.rs index 071a4974b..4b6639bd0 100644 --- a/packages/xtask/src/resource_type_authority.rs +++ b/packages/xtask/src/resource_type_authority.rs @@ -339,7 +339,7 @@ fn render_artifacts( /// The declared standard (unqualified) ResourceTypes in committed order, with /// a declared standard type absent from the committed order appended after it -/// in sorted order. A qualified type (`.d2bus.org.`) carries +/// in sorted order. A qualified type (`.d2bus. org.`) carries /// a dot and never enters the standard registry. fn declared_standard_types(registry: &AuthorityRegistry) -> Vec { let mut declared = BTreeSet::new(); diff --git a/packages/xtask/src/zone_schema.rs b/packages/xtask/src/zone_schema.rs index 1cab80c52..45b15382b 100644 --- a/packages/xtask/src/zone_schema.rs +++ b/packages/xtask/src/zone_schema.rs @@ -4,7 +4,7 @@ //! Two generators read this one model: //! //! * `gen-zone-schemas` writes -//! `docs/reference/schemas/v3/core.d2bus.org_.schema.json`, +//! `docs/reference/schemas/v3/core. d2bus. org_.schema.json`, //! the committed JSON Schema for the emitted canonical resource object. //! * `gen-zone-nix-options` writes the committed generated Nix modules under //! `nixos-modules/generated/`. @@ -38,7 +38,7 @@ const CREDENTIAL_REF_PATTERN: &str = "^Credential/[a-z][a-z0-9-]{0,62}$"; /// `ADR-046-resources-zone-control.md` section 3.3: the transport Provider ref /// is required, explicit, and its local name always begins with `transport-`. const TRANSPORT_PROVIDER_REF_PATTERN: &str = "^Provider/transport-[a-z][a-z0-9-]{0,52}$"; -/// Any same-Zone `/` ref, used by `metadata.ownerRef`. +/// Any same-Zone `/` ref, used by `metadata. ownerRef`. const RESOURCE_REF_PATTERN: &str = "^(?:[A-Z][A-Za-z0-9]{0,62}|[a-z][a-z0-9-]{0,62}\\.d2bus\\.org\\.[A-Z][A-Za-z0-9]{0,62})/[a-z][a-z0-9-]{0,62}$"; /// Role posture `principalRef` spelling: the host-account identity the /// committed principal allocation names. It is not a ResourceRef. @@ -75,7 +75,7 @@ enum FieldKind { min: i64, max: i64, }, - /// `types.ints.positive`: the specification states a positive integer with + /// `types. ints. positive`: the specification states a positive integer with /// no declared ceiling, so no ceiling is invented here. PositiveInt, /// Closed object with a fixed, fully-defaulted member list. From c79c9a049ed76343e77718a4d30a453672bf5d4b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 01:38:17 -0700 Subject: [PATCH 706/726] fix(audit): repair the gate damage the review findings left behind An independent review bound to head 304fdb332 returned request-changes with four-lane gate evidence, and the gate itself was red on nine targets. This repairs all of it. The period-space corruption was this repair's own doing. The previous commit replaced a period with a period and a space, and in some places capitalised and duplicated the word that followed, so `e.g.` became `e. g.`, `cgroup.procs.` became `cgroup. procs.`, and `any.where` became `any. Wherewhere`. It reached 744 lines across 178 files under packages/. A text search cannot enumerate it reliably and a doctest is not a comment: 25 of those lines sit inside doctest fences, and the WorkloadTarget example in d2b-contracts now parses "builder.dev. d2b", which no longer parses, so the doctest unwrapped a MissingSuffix. The fix is constructive rather than another sweep. For every line the previous commit changed, the a16f1195e line and the 304fdb332 line were compared directly, and the pair decided the outcome: where the head was the base with spaces inserted after a character that cannot end a word, or with a word capitalised and duplicated, the base line was restored verbatim. Where the head only restored a space the base had lost after a clause separator, or replaced a non-ASCII character with its intended ASCII, the head line was kept. The result against a16f1195e is fifteen intended non-ASCII removals, thirty word-separator spacing restorations, and zero intra-token breaks. That corruption also reached the generated artifacts, because the generators copy source doc comments into the schema descriptions, so six drift targets were red against committed output that had been correct all along. The async-gate inventory had drifted the same way: the inventory keys sites by (file, line), the edit above the marked calls shifted them, and three rows named lines that no longer carried a marker. `check-async-gate --write-inventory` regenerated it, moving three rows and nothing else. The two shared-family-knowledge rows are back, and deleting them was my error. The prior review called them improper on the evidence that d2b-contracts/src/unsafe_local_workloads.rs contains no occurrence of "network" or "volume" in 549 lines, and that is true. The signal is not a literal though: it is an assembled name, so the row is what the bidirectional validator requires once those families exist, and a text search cannot see it. `provider_crate_layout` is the proof - it fails with shared-crate-family-assembled-name at that module for exactly those two tokens while the rows are absent, and passes with them present. This is the same blind spot as the census false positive, inverted: there a text search missed a real macro-expanded call site, here it missed a real runtime-assembled name. The rationales now say so, so the next reader does not repeat the search. --- docs/reference/daemon-api.md | 112 +++++++++--------- packages/d2b-broker/src/audit.rs | 6 +- packages/d2b-broker/src/envelope/mod.rs | 14 +-- packages/d2b-broker/src/forwarding.rs | 6 +- packages/d2b-broker/src/lib.rs | 4 +- packages/d2b-broker/src/live_handlers.rs | 26 ++-- packages/d2b-broker/src/ops/cgroup.rs | 24 ++-- packages/d2b-broker/src/ops/device_worker.rs | 14 +-- packages/d2b-broker/src/ops/exec_reconcile.rs | 4 +- packages/d2b-broker/src/ops/media.rs | 4 +- packages/d2b-broker/src/ops/nm.rs | 4 +- packages/d2b-broker/src/ops/pidfd.rs | 2 +- packages/d2b-broker/src/ops/spawn_runner.rs | 2 +- packages/d2b-broker/src/ops/state_dir.rs | 2 +- .../d2b-broker/src/ops/store_sync_export.rs | 4 +- .../d2b-broker/src/ops/store_view_posture.rs | 4 +- packages/d2b-broker/src/ops/swtpm_dir.rs | 26 ++-- packages/d2b-broker/src/ops/sysctl.rs | 2 +- packages/d2b-broker/src/ops/usbip_host.rs | 2 +- packages/d2b-broker/src/ops/usbip_lock.rs | 6 +- packages/d2b-broker/src/runtime.rs | 50 ++++---- packages/d2b-broker/src/state_cells.rs | 6 +- packages/d2b-broker/src/sys.rs | 52 ++++---- .../tests/pidfd_handoff_scm_rights.rs | 2 +- .../d2b-broker/tests/socket_activation.rs | 6 +- packages/d2b-bus/src/router.rs | 10 +- packages/d2b-bus/src/session/contract.rs | 2 +- .../d2b-contracts-broker/src/broker_wire.rs | 22 ++-- .../d2b-contracts-control/src/cli_output.rs | 2 +- .../d2b-contracts-control/src/public_wire.rs | 12 +- .../src/v3/credential.rs | 2 +- .../d2b-contracts-provider/src/v3/provider.rs | 18 +-- .../src/v3/semantic_services/audio.rs | 18 +-- .../src/v3/semantic_services/mod.rs | 30 ++--- .../src/v3/semantic_services/security_key.rs | 12 +- .../src/v3/semantic_services/telemetry.rs | 10 +- .../src/v3/semantic_services/usb.rs | 4 +- .../d2b-contracts-resource/src/v3/device.rs | 8 +- .../d2b-contracts-resource/src/v3/host.rs | 8 +- .../d2b-contracts-resource/src/v3/network.rs | 4 +- .../src/v3/operations/seal.rs | 6 +- .../src/v3/resource_schema.rs | 12 +- .../d2b-contracts-resource/src/v3/user.rs | 4 +- .../d2b-contracts-resource/src/v3/volume.rs | 2 +- .../src/v3/resource_export.rs | 2 +- .../src/v3/resource_import.rs | 2 +- .../src/v3/zone_session.rs | 12 +- packages/d2b-contracts/src/error.rs | 6 +- packages/d2b-contracts/src/lib.rs | 2 +- packages/d2b-contracts/src/types.rs | 2 +- .../d2b-contracts/src/workload_identity.rs | 12 +- packages/d2b-core/src/bundle_resolver.rs | 28 ++--- packages/d2b-core/src/host.rs | 6 +- packages/d2b-core/src/manifest_v04.rs | 2 +- packages/d2b-core/src/processes.rs | 8 +- packages/d2b-core/src/site.rs | 6 +- packages/d2b-core/src/static_invariants.rs | 4 +- .../d2b-host/src/bin/d2b-activation-helper.rs | 2 +- packages/d2b-host/src/bridge_port.rs | 8 +- packages/d2b-host/src/cgroup.rs | 66 +++++------ packages/d2b-host/src/devices.rs | 4 +- packages/d2b-host/src/hardlink_farm.rs | 18 +-- packages/d2b-host/src/host_prep_dag.rs | 14 +-- packages/d2b-host/src/modules.rs | 40 +++---- packages/d2b-host/src/nftables.rs | 8 +- packages/d2b-host/src/ownership_matrix.rs | 2 +- .../src/driver.rs | 10 +- .../src/clipd_host/wayland.rs | 2 +- .../d2b-provider-config-nixos/src/ttrpc.rs | 2 +- .../src/lib.rs | 2 +- .../d2b-provider-credential/src/driver.rs | 8 +- .../d2b-provider-credential/src/session.rs | 2 +- .../d2b-provider-device-gpu/src/gpu_argv.rs | 8 +- .../d2b-provider-device-gpu/src/video_argv.rs | 18 +-- .../src/driver.rs | 10 +- .../src/effects_service.rs | 4 +- .../d2b-provider-device-tpm/src/swtpm_argv.rs | 18 +-- .../d2b-provider-device-usbip/src/driver.rs | 6 +- .../src/state_machine.rs | 4 +- .../src/bin/d2b-wayland-proxy.rs | 4 +- .../src/controller.rs | 2 +- .../src/session_children.rs | 2 +- .../src/wayland_proxy/filter.rs | 2 +- .../src/wayland_proxy/policy.rs | 4 +- packages/d2b-provider-endpoint/src/driver.rs | 6 +- .../src/hotplug.rs | 2 +- packages/d2b-provider-guest/src/driver.rs | 16 +-- .../d2b-provider-guest/src/effects_service.rs | 4 +- packages/d2b-provider-guest/src/shutdown.rs | 2 +- .../d2b-provider-guest/src/test_support.rs | 6 +- packages/d2b-provider-host/src/driver.rs | 16 +-- .../d2b-provider-host/src/test_support.rs | 2 +- .../d2b-provider-network-local/src/driver.rs | 4 +- .../src/metrics.rs | 2 +- .../src/launch.rs | 6 +- .../src/operations.rs | 10 +- packages/d2b-provider-process/src/driver.rs | 20 ++-- .../src/launch_identity.rs | 2 +- .../d2b-provider-process/src/operations.rs | 4 +- packages/d2b-provider-provider/src/driver.rs | 18 +-- packages/d2b-provider-role/src/rbac.rs | 2 +- .../src/resources/pool.rs | 2 +- .../src/resources/session.rs | 2 +- .../d2b-provider-system-core/src/error.rs | 2 +- packages/d2b-provider-system-core/src/host.rs | 6 +- packages/d2b-provider-system-core/src/lib.rs | 2 +- .../d2b-provider-system-core/src/testing.rs | 4 +- .../src/driver.rs | 8 +- .../d2b-provider-telemetry-binding/src/lib.rs | 2 +- .../src/driver.rs | 12 +- .../d2b-provider-telemetry-service/src/lib.rs | 4 +- .../src/shared_provider.rs | 14 +-- .../src/testing/conformance.rs | 4 +- .../src/auth.rs | 6 +- .../src/settings.rs | 2 +- packages/d2b-provider-user/src/driver.rs | 10 +- .../d2b-provider-volume-binding/src/driver.rs | 10 +- .../d2b-provider-volume-local/src/adapter.rs | 4 +- .../d2b-provider-volume-local/src/content.rs | 2 +- .../src/bindings.rs | 2 +- packages/d2b-provider-volume/src/driver.rs | 6 +- .../src/audio_registry.rs | 2 +- .../src/effects_service.rs | 4 +- .../src/interaction.rs | 16 +-- .../d2b-provider-zone-link/src/zone_links.rs | 12 +- packages/d2b-provider/src/agent.rs | 2 +- packages/d2b-resource-api/src/admission.rs | 2 +- .../d2b-resource-api/src/manager_backend.rs | 10 +- .../src/manager_backend/tests.rs | 12 +- packages/d2b-resource-api/src/service.rs | 2 +- packages/d2b-resource-compiler/src/lib.rs | 4 +- packages/d2b-resource-runtime/src/context.rs | 18 +-- packages/d2b-resource-runtime/src/error.rs | 8 +- packages/d2b-resource-runtime/src/manager.rs | 22 ++-- packages/d2b-resource-runtime/src/metadata.rs | 2 +- packages/d2b-resource-runtime/src/resource.rs | 6 +- .../d2b-resource-runtime/src/spec_store.rs | 4 +- packages/d2b-resource-runtime/src/target.rs | 4 +- packages/d2b-resource-types/src/metadata.rs | 2 +- packages/d2b-sk-frontend/src/uhid.rs | 2 +- packages/d2b-zone-routing/src/enrollment.rs | 2 +- packages/d2b-zone-routing/src/resolver.rs | 10 +- packages/d2b-zone-routing/src/service.rs | 6 +- packages/d2b/src/context.rs | 2 +- packages/d2b/src/dispatch.rs | 2 +- packages/d2b/src/doctor.rs | 12 +- packages/d2b/src/exec_client.rs | 6 +- packages/d2b/src/host_validate.rs | 12 +- packages/d2b/tests/auth_status_contract.rs | 6 +- packages/d2bd-runtime/src/autostart.rs | 14 +-- packages/d2bd-runtime/src/ch_api.rs | 16 +-- packages/d2bd-runtime/src/console_session.rs | 6 +- packages/d2bd-runtime/src/daemon_audit.rs | 4 +- packages/d2bd-runtime/src/daemon_config.rs | 2 +- packages/d2bd-runtime/src/exec_session.rs | 6 +- .../d2bd-runtime/src/kernel_module_check.rs | 18 +-- packages/d2bd-runtime/src/metrics.rs | 2 +- packages/d2bd-runtime/src/pidfs_probe.rs | 2 +- .../d2bd-runtime/src/public_projection.rs | 2 +- packages/d2bd-runtime/src/readiness.rs | 4 +- packages/d2bd-runtime/src/runtime_process.rs | 10 +- .../src/ssh_host_key_preflight.rs | 6 +- .../src/supervisor/pidfd_table.rs | 4 +- packages/d2bd-runtime/src/typed_error.rs | 4 +- packages/d2bd/src/audio_host_controller.rs | 4 +- packages/d2bd/src/composition.rs | 34 +++--- packages/d2bd/src/forward_rendezvous.rs | 6 +- packages/d2bd/src/process_provider_runtime.rs | 14 +-- packages/d2bd/src/provider_lifecycle.rs | 2 +- packages/d2bd/src/resource_plane_v3.rs | 14 +-- packages/d2bd/src/resource_runtime.rs | 12 +- packages/d2bd/src/shared_provider_effects.rs | 14 +-- packages/xtask/data/async-gate-inventory.json | 6 +- packages/xtask/src/blocking_census.rs | 12 +- packages/xtask/src/changelog.rs | 20 ++-- packages/xtask/src/nix_inventories.rs | 4 +- packages/xtask/src/provider_crate_policy.rs | 16 ++- packages/xtask/src/provider_packaging.rs | 2 +- packages/xtask/src/resource_type_authority.rs | 2 +- packages/xtask/src/zone_schema.rs | 6 +- 180 files changed, 815 insertions(+), 803 deletions(-) diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index c74e07278..dbdad9644 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -263,14 +263,14 @@ host reboot. | `ListRequest` | struct | [`ListRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L280) | struct { `env`: `Option`; `vm`: `Option` } | | `StatusRequest` | struct | [`StatusRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L288) | struct { `check_bridges`: `bool`; `vm`: `Option` } | | `AuditRequest` | struct | [`AuditRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L297) | struct { `filter`: `Option`; `format`: `AuditFormat`; `since`: `Option`; `cursor`: `Option`; `limit`: `u32` } | -| `VmLifecycleRequest` | struct | [`VmLifecycleRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L427) | struct { `vm`: `String`; `flags`: `MutationFlags`; `force`: `bool`; `no_wait_api`: `bool` } | -| `ActivationRequest` | struct | [`ActivationRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L447) | struct { `vm`: `String`; `to_generation`: `Option`; `flags`: `MutationFlags` } | -| `UsbipBindCliRequest` | struct | [`UsbipBindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L458) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | -| `UsbipUnbindCliRequest` | struct | [`UsbipUnbindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L467) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | -| `NamedProcessStreamRequest` | enum | [`NamedProcessStreamRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L1137) | `Stdin` - struct { `offset`: `u64`; `chunk_base64`: `String`; `eof`: `bool` }; `Read` - struct { `stream`: `ExecStream`; `offset`: `u64`; `max_len`: `u64`; `wait`: `bool`; `timeout_ms`: `u64` }; `Signal` - struct { `control_seq`: `u64`; `signo`: `u32` }; `Resize` - struct { `control_seq`: `u64`; `rows`: `u32`; `cols`: `u32` }; `CloseStdin` - struct { `offset`: `u64` }; `Cancel`; `Close`; `Wait` - struct { `timeout_ms`: `u64` } | -| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2157) | struct { `flags`: `MutationFlags` } | -| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2164) | struct { `flags`: `MutationFlags` } | -| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2176) | struct { `flags`: `MutationFlags`; `network`: `bool` } | +| `VmLifecycleRequest` | struct | [`VmLifecycleRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L434) | struct { `vm`: `String`; `flags`: `MutationFlags`; `force`: `bool`; `no_wait_api`: `bool` } | +| `ActivationRequest` | struct | [`ActivationRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L454) | struct { `vm`: `String`; `to_generation`: `Option`; `flags`: `MutationFlags` } | +| `UsbipBindCliRequest` | struct | [`UsbipBindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L465) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | +| `UsbipUnbindCliRequest` | struct | [`UsbipUnbindCliRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L474) | struct { `vm`: `String`; `bus_id`: `String`; `flags`: `MutationFlags` } | +| `NamedProcessStreamRequest` | enum | [`NamedProcessStreamRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L1144) | `Stdin` - struct { `offset`: `u64`; `chunk_base64`: `String`; `eof`: `bool` }; `Read` - struct { `stream`: `ExecStream`; `offset`: `u64`; `max_len`: `u64`; `wait`: `bool`; `timeout_ms`: `u64` }; `Signal` - struct { `control_seq`: `u64`; `signo`: `u32` }; `Resize` - struct { `control_seq`: `u64`; `rows`: `u32`; `cols`: `u32` }; `CloseStdin` - struct { `offset`: `u64` }; `Cancel`; `Close`; `Wait` - struct { `timeout_ms`: `u64` } | +| `HostPrepareRequest` | struct | [`HostPrepareRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2164) | struct { `flags`: `MutationFlags` } | +| `HostDestroyRequest` | struct | [`HostDestroyRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2171) | struct { `flags`: `MutationFlags` } | +| `HostReconcileRequest` | struct | [`HostReconcileRequest`](../../packages/d2b-contracts-control/src/public_wire.rs#L2183) | struct { `flags`: `MutationFlags`; `network`: `bool` } | ### Broker socket request types @@ -374,17 +374,17 @@ see the auto-generated tables above for the committed Rust variants. | --- | --- | --- | --- | | `PublicResponse` | enum | [`PublicResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L124) | `Capabilities` - (CapabilitiesResponse); `AuthStatus` - (AuthStatusResponse); `List` - (ListResponse); `Status` - (StatusResponse); `Audit` - (AuditResponse); `UsbipProbe` - (UsbipProbeResponse); `MutatingVerb` - (MutatingVerbResponse); `Exec` - (ExecOpResponse); `Console` - (ConsoleOpResponse); `Audio` - (AudioOpResponse); `Workload` - (WorkloadOpResponse); `UsbSecurityKeyStatus` - (d2b_contracts::security_key::SecurityKeyStatusResponse); `UsbSecurityKeySessions` - (d2b_contracts::security_key::SecurityKeySessionsResponse); `UsbSecurityKeyCancel` - (d2b_contracts::security_key::SecurityKeyCancelResponse); `Error` - (Error) | | `WorkloadOpResponse` | enum | [`WorkloadOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L175) | `List` - (WorkloadListResult); `Status` - (Box); `LauncherExec` - (LauncherExecResult) | -| `ExecOpResponse` | enum | [`ExecOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1110) | `Start` - (ExecStartResult); `DetachedCreate` - (ExecDetachedCreateResult); `WriteStdin` - (ExecWriteStdinResult); `ReadOutput` - (ExecReadOutputResult); `Signal` - (ExecControlResult); `Resize` - (ExecControlResult); `Wait` - (ExecWaitResult); `Close` - (ExecCloseResult); `List` - (ExecDetachedListResult); `Logs` - (ExecDetachedLogsResult); `Status` - (ExecDetachedStatusResult); `Kill` - (ExecDetachedKillResult) | -| `NamedProcessStreamResponse` | enum | [`NamedProcessStreamResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1237) | `Stdin` - (ExecWriteStdinResult); `Output` - (ExecReadOutputResult); `Delivered` - (ExecControlResult); `Wait` - (ExecWaitResult); `Closed` - (ExecCloseResult); `Terminal` - (ExecTerminalStatus); `Error` - (NamedProcessStreamError) | -| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1940) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | -| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2147) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | -| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2209) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | -| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2235) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | -| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2245) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | -| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2254) | struct { `vms`: `Vec`; `read_model`: `Option` } | -| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2262) | struct { `entries`: `Vec`; `read_model`: `Option` } | -| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2342) | struct { `entries`: `Vec`; `page_end`: `AuditPageEnd` } | -| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2657) | struct { `entries`: `Vec` } | +| `ExecOpResponse` | enum | [`ExecOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1117) | `Start` - (ExecStartResult); `DetachedCreate` - (ExecDetachedCreateResult); `WriteStdin` - (ExecWriteStdinResult); `ReadOutput` - (ExecReadOutputResult); `Signal` - (ExecControlResult); `Resize` - (ExecControlResult); `Wait` - (ExecWaitResult); `Close` - (ExecCloseResult); `List` - (ExecDetachedListResult); `Logs` - (ExecDetachedLogsResult); `Status` - (ExecDetachedStatusResult); `Kill` - (ExecDetachedKillResult) | +| `NamedProcessStreamResponse` | enum | [`NamedProcessStreamResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1244) | `Stdin` - (ExecWriteStdinResult); `Output` - (ExecReadOutputResult); `Delivered` - (ExecControlResult); `Wait` - (ExecWaitResult); `Closed` - (ExecCloseResult); `Terminal` - (ExecTerminalStatus); `Error` - (NamedProcessStreamError) | +| `ConsoleOpResponse` | enum | [`ConsoleOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L1947) | `Attach` - (ConsoleAttachResult); `WriteStdin` - (ConsoleControlResult); `ReadOutput` - (ConsoleReadOutputResult); `Resize` - (ConsoleControlResult); `Wait` - (ConsoleWaitResult); `Close` - (ConsoleCloseResult) | +| `AudioOpResponse` | enum | [`AudioOpResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2154) | `Status` - (AudioStatusResult); `SetVolume` - (AudioSetResult); `Mute` - (AudioSetResult) | +| `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2216) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | +| `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2242) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | +| `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2252) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | +| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2261) | struct { `vms`: `Vec`; `read_model`: `Option` } | +| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2269) | struct { `entries`: `Vec`; `read_model`: `Option` } | +| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2349) | struct { `entries`: `Vec`; `page_end`: `AuditPageEnd` } | +| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2664) | struct { `entries`: `Vec` } | ### Broker socket response types @@ -492,7 +492,7 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2823) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | +| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2830) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | ### Other documented enums @@ -528,37 +528,37 @@ running live guest activation. | `GraphicalLaunchPosture` | enum | [`GraphicalLaunchPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L222) | `Proxied`; `NotApplicable`; `GraphicalSessionInactive`; `WaylandUnavailable`; `ProxyUnavailable` | | `LauncherExecDisposition` | enum | [`LauncherExecDisposition`](../../packages/d2b-contracts-control/src/public_wire.rs#L263) | `Committed`; `AlreadyCommitted` | | `MutationMode` | enum | [`MutationMode`](../../packages/d2b-contracts-control/src/public_wire.rs#L324) | `DryRun`; `Apply` | -| `ExecStream` | enum | [`ExecStream`](../../packages/d2b-contracts-control/src/public_wire.rs#L484) | `Stdout`; `Stderr` | -| `ExecOp` | enum | [`ExecOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L775) | `Start` - (ExecStartArgs); `WriteStdin` - (ExecWriteStdinArgs); `ReadOutput` - (ExecReadOutputArgs); `Signal` - (ExecSignalArgs); `Resize` - (ExecResizeArgs); `Wait` - (ExecWaitArgs); `Close` - (ExecCloseArgs); `List` - (ExecDetachedListArgs); `Logs` - (ExecDetachedLogsArgs); `Status` - (ExecDetachedStatusArgs); `Kill` - (ExecDetachedKillArgs) | -| `ExecTerminalStatus` | enum | [`ExecTerminalStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L891) | `Exited` - struct { `code`: `i32` }; `Signaled` - struct { `signal`: `u32` }; `Error` - struct { `slug`: `String` } | -| `ExecDetachedKillOutcome` | enum | [`ExecDetachedKillOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L1082) | `Cancelling`; `AlreadyTerminal` | -| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1544) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | -| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1555) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | -| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1665) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1808) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | -| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1954) | `Speaker`; `Microphone` | -| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1968) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2010) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | -| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L2055) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | -| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2118) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | -| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2224) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | -| `PublicReadModelKind` | enum | [`PublicReadModelKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2288) | `List`; `Status` | -| `AuditPageEnd` | enum | [`AuditPageEnd`](../../packages/d2b-contracts-control/src/public_wire.rs#L2303) | `Complete`; `More` - (AuditExportCursor) | -| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2416) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | -| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2434) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | -| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2459) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | -| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2472) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | -| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2486) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | -| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2509) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | -| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2527) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | -| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2540) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | -| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2559) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | -| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2595) | `Usbip`; `QemuMediaSlot` | -| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2678) | `Human`; `Json` | -| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2686) | `None`; `Launcher`; `Admin` | -| `VmAutostartMode` | enum | [`VmAutostartMode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2866) | `ManualOnly` | -| `QemuMediaRunnerState` | enum | [`QemuMediaRunnerState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2900) | `Running`; `Stopped` | -| `QemuMediaRegistryState` | enum | [`QemuMediaRegistryState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2935) | `DirectConfig`; `Present`; `Stale`; `Missing` | +| `ExecStream` | enum | [`ExecStream`](../../packages/d2b-contracts-control/src/public_wire.rs#L491) | `Stdout`; `Stderr` | +| `ExecOp` | enum | [`ExecOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L782) | `Start` - (ExecStartArgs); `WriteStdin` - (ExecWriteStdinArgs); `ReadOutput` - (ExecReadOutputArgs); `Signal` - (ExecSignalArgs); `Resize` - (ExecResizeArgs); `Wait` - (ExecWaitArgs); `Close` - (ExecCloseArgs); `List` - (ExecDetachedListArgs); `Logs` - (ExecDetachedLogsArgs); `Status` - (ExecDetachedStatusArgs); `Kill` - (ExecDetachedKillArgs) | +| `ExecTerminalStatus` | enum | [`ExecTerminalStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L898) | `Exited` - struct { `code`: `i32` }; `Signaled` - struct { `signal`: `u32` }; `Error` - struct { `slug`: `String` } | +| `ExecDetachedKillOutcome` | enum | [`ExecDetachedKillOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L1089) | `Cancelling`; `AlreadyTerminal` | +| `ShellSessionState` | enum | [`ShellSessionState`](../../packages/d2b-contracts-control/src/public_wire.rs#L1551) | `Attached`; `Detached`; `Killed`; `PoolUnavailable`; `FeatureDisabled`; `OutputGap` | +| `ShellCloseCause` | enum | [`ShellCloseCause`](../../packages/d2b-contracts-control/src/public_wire.rs#L1562) | `ClientDetach`; `EvictedByForce`; `EvictedByAdminDetach`; `KilledByAdmin`; `PoolUnavailable`; `OutputGap` | +| `ConsoleProviderKind` | enum | [`ConsoleProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1672) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `ConsoleOp` | enum | [`ConsoleOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L1815) | `Attach` - (ConsoleAttachArgs); `WriteStdin` - (ConsoleWriteStdinArgs); `ReadOutput` - (ConsoleReadOutputArgs); `Resize` - (ConsoleResizeArgs); `Wait` - (ConsoleWaitArgs); `Close` - (ConsoleCloseArgs) | +| `AudioChannel` | enum | [`AudioChannel`](../../packages/d2b-contracts-control/src/public_wire.rs#L1961) | `Speaker`; `Microphone` | +| `AudioEnforcementPosture` | enum | [`AudioEnforcementPosture`](../../packages/d2b-contracts-control/src/public_wire.rs#L1975) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `AudioProviderKind` | enum | [`AudioProviderKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2017) | `LocalHypervisor`; `QemuMedia`; `AcaSandbox` | +| `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L2062) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | +| `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2125) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | +| `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2231) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | +| `PublicReadModelKind` | enum | [`PublicReadModelKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2295) | `List`; `Status` | +| `AuditPageEnd` | enum | [`AuditPageEnd`](../../packages/d2b-contracts-control/src/public_wire.rs#L2310) | `Complete`; `More` - (AuditExportCursor) | +| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2423) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | +| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2441) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | +| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2466) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | +| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2479) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | +| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2493) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | +| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2516) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | +| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2534) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | +| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2547) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | +| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2566) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | +| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2602) | `Usbip`; `QemuMediaSlot` | +| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2685) | `Human`; `Json` | +| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2693) | `None`; `Launcher`; `Admin` | +| `VmAutostartMode` | enum | [`VmAutostartMode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2873) | `ManualOnly` | +| `QemuMediaRunnerState` | enum | [`QemuMediaRunnerState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2907) | `Running`; `Stopped` | +| `QemuMediaRegistryState` | enum | [`QemuMediaRegistryState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2942) | `DirectConfig`; `Present`; `Stale`; `Missing` | | `TerminalStream` | enum | [`TerminalStream`](../../packages/d2b-contracts-control/src/terminal_wire.rs#L13) | `Stdout`; `Stderr` | | `HelperScopeKind` | enum | [`HelperScopeKind`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L68) | `LauncherApp`; `WaylandProxy` | | `HelperScopeState` | enum | [`HelperScopeState`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L95) | `Starting`; `Active`; `Stopping`; `Exited`; `Degraded` | @@ -658,11 +658,11 @@ the failure class, for example `host check`, `audit`, `status`, or | `HandoffError` | enum | [`HandoffError`](../../packages/d2b-contracts-broker/src/host_generation.rs#L198) | `CompatibilityFloorInvalid`; `GenerationTooOld`; `TargetFingerprintMismatch`; `TargetGenerationMismatch`; `GenerationAncestryInvalid`; `InvalidTransition` | | `KernelInvokeError` | enum | [`KernelInvokeError`](../../packages/d2b-contracts-broker/src/kernel_client.rs#L44) | `Transport` - (String); `Protocol` - (String); `Refused` - struct { `code`: `String`; `detail`: `Option` } | | `MutationModeError` | struct | [`MutationModeError`](../../packages/d2b-contracts-control/src/public_wire.rs#L333) | empty struct | -| `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1304) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | -| `NamedProcessStreamError` | struct | [`NamedProcessStreamError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1324) | struct { `kind`: `NamedProcessStreamErrorKind` } | -| `ShellNameError` | struct | [`ShellNameError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1405) | empty struct | -| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1991) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | -| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L2092) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | +| `NamedProcessStreamErrorKind` | enum | [`NamedProcessStreamErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1311) | `Authorization`; `StaleSession`; `NotFound`; `Backpressure`; `Protocol`; `Timeout`; `Disconnected` | +| `NamedProcessStreamError` | struct | [`NamedProcessStreamError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1331) | struct { `kind`: `NamedProcessStreamErrorKind` } | +| `ShellNameError` | struct | [`ShellNameError`](../../packages/d2b-contracts-control/src/public_wire.rs#L1412) | empty struct | +| `AudioErrorKind` | enum | [`AudioErrorKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L1998) | `ProviderMisconfigured`; `VmNotFound`; `EnforcementUnavailable`; `AudioNotEnabled`; `InternalError` | +| `AudioVmError` | struct | [`AudioVmError`](../../packages/d2b-contracts-control/src/public_wire.rs#L2099) | struct { `vm`: `String`; `kind`: `AudioErrorKind`; `remediation`: `Option` } | | `LevelPercentError` | enum | [`LevelPercentError`](../../packages/d2b-contracts/src/audio.rs#L28) | `OutOfRange` - (u8) | | `AudioPolicyError` | enum | [`AudioPolicyError`](../../packages/d2b-contracts/src/audio.rs#L216) | `InvalidJson` - (String); `InvalidField` - (String); `UnknownSchemaVersion` - (String); `Serialize` - (String) | | `AuditExportErrorCode` | enum | [`AuditExportErrorCode`](../../packages/d2b-contracts/src/audit_wire.rs#L24) | `HashBreak`; `RecordInvalid`; `ReadFailed` | diff --git a/packages/d2b-broker/src/audit.rs b/packages/d2b-broker/src/audit.rs index 110c7ada9..0de8913a0 100644 --- a/packages/d2b-broker/src/audit.rs +++ b/packages/d2b-broker/src/audit.rs @@ -1688,7 +1688,7 @@ fn prune_expired_daily_files_locked(audit_dir: &Path, retention_days: u32) -> io let age_days = today_unix_days - file_unix_days; if age_days > cutoff_days { // Best-effort: remove failures don't propagate as - // hard errors (e. g. file vanished between readdir + // hard errors (e.g. file vanished between readdir // and remove, permission denied on a stray file). if path_safe::remove_nofollow(&entry.path()).is_ok() { pruned += 1; @@ -2478,7 +2478,7 @@ fn ymd_from_unix(unix: i64) -> (i32, u32, u32) { /// underlying Hinnant algorithm normalizes out-of-range days into the /// next month, producing a different (y, m, d) on decode. We treat any /// normalization as `None` so `prune_expired_daily_files` doesn't trust -/// a filename like `broker-2024-02-30. jsonl` as a real date. +/// a filename like `broker-2024-02-30.jsonl` as a real date. fn unix_days_from_ymd(y: i32, m: u32, d: u32) -> Option { if !(1..=12).contains(&m) || !(1..=31).contains(&d) { return None; @@ -2495,7 +2495,7 @@ fn unix_days_from_ymd(y: i32, m: u32, d: u32) -> Option { let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096] let result = era as i64 * 146_097 + doe as i64 - 719_468; // Round-trip guard: rejects impossible calendar dates that the - // Hinnant algorithm would otherwise normalize (e. g. 2024-02-30 + // Hinnant algorithm would otherwise normalize (e.g. 2024-02-30 // becoming 2024-03-01). Pruning trusts the filename only after // this guard agrees. let (yy, mm, dd) = ymd_from_unix(result * 86_400); diff --git a/packages/d2b-broker/src/envelope/mod.rs b/packages/d2b-broker/src/envelope/mod.rs index c9a890cdd..7f802ed7d 100644 --- a/packages/d2b-broker/src/envelope/mod.rs +++ b/packages/d2b-broker/src/envelope/mod.rs @@ -906,7 +906,7 @@ pub struct DispatchOutcome { /// The canonical result payload. pub result: CanonicalJsonObject, /// The descriptors the answering peer minted this invocation, when the - /// operation's result carries any. Wherewhere + /// operation's result carries any.where /// /// Formal fd provenance tracking is the answering peer's job (KTD7):the /// carrier only refuses a descriptor that is one of the call's own attached @@ -1145,7 +1145,7 @@ impl BrokerEnvelope { /// frame's SCM_RIGHTS attachments are the operation's descriptors, validated /// here against the row's declared fd facet before dispatch, so an /// oversized-but-transport-legal set is refused with the fd-leg code - /// rather than truncated by the transport. Wherewhere + /// rather than truncated by the transport.where /// /// # Errors /// @@ -1537,7 +1537,7 @@ impl BrokerEnvelope { /// oversized-but-transport-legal set (count over the row's declared max, /// kind mismatch, or a row whose facet exceeds the frame ceiling) is /// refused with the fd-leg code rather than let the transport truncate an - /// anonymous oversized frame. Wherewhere + /// anonymous oversized frame.where fn request_fds_admitted(row: &BrokerOperationRow, fds: &[OwnedFd]) -> bool { if fds.len() > usize::from(row.max_fds) { return false; @@ -3101,12 +3101,12 @@ mod tests { let returned_write_end = Arc::clone(&returned_write_end); Box::pin(async move { // Request leg:the descriptor the caller attached crossed the socket - // and reads back what the caller wrote. to + // and reads back what the caller wrote.to let mut echoed = [0_u8; 4]; let n = read(invocation.fds[0].as_raw_fd(), &mut echoed).expect("read request fd"); assert_eq!(&echoed[..n], b"ping"); - // Response leg:answer with a fresh descriptor the peer minted. to + // Response leg:answer with a fresh descriptor the peer minted.to let (answer_read, answer_write) = pipe().expect("answer pipe"); *returned_write_end.lock().expect("slot") = Some(answer_write); Ok(DispatchOutcome { @@ -3141,7 +3141,7 @@ mod tests { // Read back what the peer wrote through the returned descriptor:the // minted write end stays on the peer's side,and the returned read end - // is a working duplicated handle, exactly as w12 asserts. to + // is a working duplicated handle, exactly as w12 asserts.to let write_end = write_slot .lock() .expect("slot") @@ -3283,7 +3283,7 @@ mod tests { .expect("canonical"), // Return the call's own descriptor - a descriptor the peer did // not mint this call. The carrier spoils the theft at the wire - // boundary rather than at the handler. se + // boundary rather than at the handler.se fds: vec![invocation.fds[0].try_clone().expect("dup request fd")], }) }) diff --git a/packages/d2b-broker/src/forwarding.rs b/packages/d2b-broker/src/forwarding.rs index 6a8662f91..03e22f799 100644 --- a/packages/d2b-broker/src/forwarding.rs +++ b/packages/d2b-broker/src/forwarding.rs @@ -2,7 +2,7 @@ //! //! The broker holds the committed rows and links no provider crate, so the //! dispatch step of the operation envelope cannot run a family row's -//! `OperationDef. handler` locally. It forwards instead: one validated, +//! `OperationDef.handler` locally. It forwards instead: one validated, //! authorized invocation crosses to the process that declared the handler, //! which answers with the handler's canonical result or its refusal code. //! @@ -751,7 +751,7 @@ mod tests { fn a_response_whose_fd_count_mismatches_its_declared_indexes_is_refused_not_truncated() { // The peer declares two descriptors but attaches only one:the // carrier must refuse with the fd-leg code rather than succeed with a - // truncated answer. Wherewhere + // truncated answer.where let (read_end, _write_end) = pipe().expect("pipe"); let mut read_end = Some(read_end); let peer = Peer::spawn_raw(move |_request| { @@ -794,7 +794,7 @@ mod tests { fn a_response_whose_fd_declarations_exceed_the_frame_ceiling_is_refused() { // Nine declared descriptors cannot ride an eight-descriptor frame; // the refusal must name the fd leg, never surface as a transport-side - // control-truncation error. Wherewhere + // control-truncation error.where let (read_end, _write_end) = pipe().expect("pipe"); let mut read_end = Some(read_end); let peer = Peer::spawn_raw(move |_request| { diff --git a/packages/d2b-broker/src/lib.rs b/packages/d2b-broker/src/lib.rs index b92449f52..6153d35ad 100644 --- a/packages/d2b-broker/src/lib.rs +++ b/packages/d2b-broker/src/lib.rs @@ -4,8 +4,8 @@ // otherwise correct and well-tested: // // - `deprecated`: cgroup vm_leaf_path migration is tracked but the deprecated -// path is still referenced in legacy code paths kept for v1.1. x compat. -// - `clippy::dead_code`: helper functions (e. g. apply_mount_actions, apply) +// path is still referenced in legacy code paths kept for v1.1.x compat. +// - `clippy::dead_code`: helper functions (e.g. apply_mount_actions, apply) // are public API of internal modules that downstream callers may use. // - `clippy::large_enum_variant`, `clippy::result_large_err`: TypedError // variants intentionally carry rich context; boxing tracked separately. diff --git a/packages/d2b-broker/src/live_handlers.rs b/packages/d2b-broker/src/live_handlers.rs index 5b7decaee..e631ea219 100644 --- a/packages/d2b-broker/src/live_handlers.rs +++ b/packages/d2b-broker/src/live_handlers.rs @@ -934,10 +934,10 @@ fn ensure_runner_cgroup_leaf( }; let leaf_path = cgroup_leaf_path(parent_slice, &segments); // Always materialize the cgroup leaf dir tree even when - // placement. delegated == false. The delegated flag is about + // placement.delegated == false. The delegated flag is about // controller delegation (enabling subtree control), not whether // the directory exists. The broker spawn path always needs the - // Zone/Guest role leaf to write the child pid into cgroup. procs. + // Zone/Guest role leaf to write the child pid into cgroup.procs. let slice = crate::ops::cgroup::create_d2b_slice( backend, unified_hierarchy_root, @@ -1943,7 +1943,7 @@ async fn refresh_spawn_runner_acls( // Derive the expected runtime-dir owner uid from the // declarative path `/run/user/` (from the bundle's // XDG_RUNTIME_DIR value, which originates in - // d2b. site. waylandUser). Do not shell out. + // d2b.site.waylandUser). Do not shell out. let wayland_user_uid = runtime .file_name() .and_then(|s| s.to_str()) @@ -2366,7 +2366,7 @@ fn validate_served_view_root(root: &Path) -> Result<(), String> { /// The worker runs as the trusted intent's principal, never as the daemon: /// the broker's only authentication factor is peer identity /// (`peer_matches_instance` admits exactly the daemon uid/gid on -/// `/run/d2b/priv. sock`), so a worker launched with the daemon identity +/// `/run/d2b/priv.sock`), so a worker launched with the daemon identity /// would be able to call the whole daemon API after a guest -> worker /// compromise. The daemon-provisioned trees the worker legitimately needs /// are therefore opened to its own principal instead: @@ -2785,7 +2785,7 @@ fn grant_component_session_socket_acl_once(socket: &Path) -> Result Result<(), String> { if let Some((dev, ino)) = setfacl_component_session( socket, @@ -2835,7 +2835,7 @@ fn spawn_component_session_vsock_acl_retry(socket: PathBuf) { /// /// Revoke-then-grant: first revoke any stale per-VM daemon grant left on /// the (possibly replaced) socket inode from a prior generation, then -/// (re-) establish the full ancestor traversal chain and grant `rw` on +/// (re-)establish the full ancestor traversal chain and grant `rw` on /// the live socket. The traversal grant is applied synchronously so the /// daemon never loses search on the per-VM state dir (the api-socket /// depends on it too); if the socket is not yet present, a bounded retry @@ -2950,14 +2950,14 @@ pub async fn live_spawn_runner( // spawns (ADR 0021). // // Detection: seccomp_policy_ref == "w1-gpu-render-node" AND - // user_namespace. is_some() (both conditions must hold; the policy + // user_namespace.is_some() (both conditions must hold; the policy // ref is the canonical identifier for the render-node-only profile // and avoids introducing a new SpawnRunnerPlan field). // // The fd is opened here (parent side, before clone3(CLONE_NEWUSER)) // so the DAC permission check runs as the broker UID - the child's // user-NS UID mapping provides no host-side access. The OwnedFd is - // moved into RunnerIsolationSpec. pre_opened_device_fds; the broker + // moved into RunnerIsolationSpec.pre_opened_device_fds; the broker // sys layer dup2's it to RENDER_NODE_INHERITED_FD (10) in the child // closure before execve. The crosvm argv carries // --gpu-device-node /proc/self/fd/10 as the render node path. @@ -3101,9 +3101,9 @@ pub async fn live_spawn_runner( /// /// Two placements exist: /// -/// - a **VM-scoped** placement (`d2b. slice//...`, the legacy VM DAG) is +/// - a **VM-scoped** placement (`d2b.slice//...`, the legacy VM DAG) is /// provisioned and identity-bound here, exactly as before; -/// - a **resource-backed** placement (`d2b. slice/process-<64hex>/...`, +/// - a **resource-backed** placement (`d2b.slice/process-<64hex>/...`, /// `private_cgroup_placement`) carries no VM identity in the cgroup and the /// typed Device-worker intent ships no writable paths, so the identity comes /// from the verified bundle (`resource_backed`) and the launch is fenced @@ -3135,7 +3135,7 @@ async fn maybe_harden_swtpm_dir( // directory for the log and pid file the moment it starts, so a launch // racing the Volume's layout must fail retryably here instead of // burning the row's restart budget on a child that dies on its first - // write. The one-shot flush (`--unix /ctrl. sock`) only connects + // write. The one-shot flush (`--unix /ctrl.sock`) only connects // to the worker's control socket inside that directory: it is admitted // and waits for the socket, so refusing it would spend the row's one // attempt on a race it can win. Presence is a filesystem fact, so it @@ -4265,7 +4265,7 @@ mod tests { ); assert!(backend.directory_exists(&leaf)); // DEFAULT_DELEGATED_PARENT_SLICE is the top-level - // `/sys/fs/cgroup/d2b. slice` (systemd top-level slice naming + // `/sys/fs/cgroup/d2b.slice` (systemd top-level slice naming // convention). The leaf path lives under that, so the slice MUST // exist for the leaf to exist. assert!(backend.directory_exists(Path::new("/sys/fs/cgroup/d2b.slice"))); @@ -4628,7 +4628,7 @@ mod tests { // behaviour (no setfacl on world-traversable ancestors) is // covered hermetically by `dir_traverse_classification_world_x_vs_private` // without invoking the host setfacl binary on real ancestors - - // which a TestDir rooted under a non-world-x CI path (e. g. + // which a TestDir rooted under a non-world-x CI path (e.g. // `/home/runner`, mode 0750) would otherwise trigger. revoke_component_session_vsock_acl(&socket).expect("revoke of absent socket is a no-op"); } diff --git a/packages/d2b-broker/src/ops/cgroup.rs b/packages/d2b-broker/src/ops/cgroup.rs index 29dc1018c..4c753fba0 100644 --- a/packages/d2b-broker/src/ops/cgroup.rs +++ b/packages/d2b-broker/src/ops/cgroup.rs @@ -7,7 +7,7 @@ //! never from caller input; the wire request only names the //! subject (`subtree`, `vm_id`) and the broker maps that name to //! the canonical delegated subtree (default -//! `/sys/fs/cgroup/d2b. slice`) plus per-VM interiors and +//! `/sys/fs/cgroup/d2b.slice`) plus per-VM interiors and //! per-role leaves beneath it; //! - the 8-step delegation algorithm runs through //! [`d2b_host::cgroup`]; @@ -47,9 +47,9 @@ pub enum CgroupOpError { /// that the broker is allowed to manage. CgroupNotDelegated { expected_parent: PathBuf }, /// `OpenCgroupDir` was asked about a path that does not resolve - /// under the delegated d2b. slice (`path-class = foreign`). + /// under the delegated d2b.slice (`path-class = foreign`). PathClassForeign { requested: PathBuf }, - /// `cgroup. kill` was attempted on a non-leaf path. + /// `cgroup.kill` was attempted on a non-leaf path. KillAncestor { requested: PathBuf }, } @@ -130,15 +130,15 @@ impl CgroupBundleContext { /// v1.1.1 per-VM-interior + per-role-leaf taxonomy per ADR 0011 /// Decision item 1: `vm_interior_path` returns the - /// process-free intermediate directory `d2b. slice//`. - /// Per-role leaf cgroups (`d2b. slice///`) are + /// process-free intermediate directory `d2b.slice//`. + /// Per-role leaf cgroups (`d2b.slice///`) are /// the only entries that carry processes. pub fn vm_interior_path(&self, vm_id: &str) -> PathBuf { self.slice_path().join(vm_id) } /// v1.1.1 per-role leaf cgroup path - /// `d2b. slice///`. Processes for the + /// `d2b.slice///`. Processes for the /// `(vm_id, role_id)` SpawnRunner instance are placed here via /// `clone3(CLONE_INTO_CGROUP)` at spawn time. pub fn vm_role_leaf_path(&self, vm_id: &str, role_id: &str) -> PathBuf { @@ -230,7 +230,7 @@ impl PathClass { /// systemd-managed parent slice that has already been delegated to the /// broker/daemon. The broker never writes `/sys/fs/cgroup` root; the /// operator must pre-create + `Delegate=yes` the parent slice (default -/// `/sys/fs/cgroup/d2b. slice`) and then the broker +/// `/sys/fs/cgroup/d2b.slice`) and then the broker /// enables controllers / chowns only within that subtree. Per the /// broker variant table, `destructive: no`, `secret: no`, audit /// decision `allowed` on success. @@ -316,8 +316,8 @@ where }; // Subject classification: the wire request carries a logical - // subject name (e. g. "d2b-slice" or a vm id). The broker - // maps that to a canonical path under d2b. slice. + // subject name (e.g. "d2b-slice" or a vm id). The broker + // maps that to a canonical path under d2b.slice. let (canonical_path, class) = if requested_subject == D2B_SLICE_NAME || requested_subject == "d2b-slice" { (context.slice_path().to_path_buf(), PathClass::D2bSlice) @@ -431,7 +431,7 @@ pub(crate) fn create_d2b_slice( host_cgroup::probe_unified_hierarchy(backend, unified_hierarchy_root)?; // Systemd must pre-create + delegate this slice. The broker only // enables controllers and changes ownership within that subtree; - // it never writes `/sys/fs/cgroup/cgroup. subtree_control`. + // it never writes `/sys/fs/cgroup/cgroup.subtree_control`. if !backend.exists(parent_slice) { return Err(CgroupOpError::CgroupNotDelegated { expected_parent: parent_slice.to_path_buf(), @@ -684,8 +684,8 @@ fn runner_cgroup_shape(subtree: &str, vm_id: &str) -> Option { /// /// The request carries `(vm_id, role_id)`. The broker resolves the cgroup /// placement from its bundle copy and refuses anything other than a -/// canonical `d2b. slice///` or legacy -/// `d2b. slice//` leaf shape. A same-named Zone-qualified Guest +/// canonical `d2b.slice///` or legacy +/// `d2b.slice//` leaf shape. A same-named Zone-qualified Guest /// collision is refused as ambiguous rather than selecting a cgroup. pub fn live_kill_runner_cgroup( resolver: &BundleResolver, diff --git a/packages/d2b-broker/src/ops/device_worker.rs b/packages/d2b-broker/src/ops/device_worker.rs index a5ab4b15e..56e8eeab5 100644 --- a/packages/d2b-broker/src/ops/device_worker.rs +++ b/packages/d2b-broker/src/ops/device_worker.rs @@ -37,7 +37,7 @@ pub struct DeviceWorkerScope { /// uid the request carried, now the Zone the bundle row was read from. pub(crate) zone_uid: ResourceUid, /// The `Device` row that owns the launched Process row, per the verified - /// Zone resource bundle (`Process. metadata. ownerRef`, cross-checked with + /// Zone resource bundle (`Process.metadata.ownerRef`, cross-checked with /// the request's claim). pub(crate) device_ref: ResourceRef, /// That Device's durable row uid: the deterministic derivation of its @@ -45,7 +45,7 @@ pub struct DeviceWorkerScope { /// the request must carry. pub(crate) device_uid: ResourceUid, /// The Guest the Device declares as its owner - /// (`Device. metadata. ownerRef == Guest/`): the VM scope every + /// (`Device.metadata.ownerRef == Guest/`): the VM scope every /// runtime path of the worker hangs off. pub(crate) guest: String, } @@ -140,7 +140,7 @@ impl DeviceWorkerScopeError { /// Pin the Device scope of one Device-owned worker launch. /// /// The launched row is resolved from the verified Zone resource bundle the -/// request's `zone_uid` names (`Process. metadata. ownerRef`), that owner must +/// request's `zone_uid` names (`Process.metadata.ownerRef`), that owner must /// be a `Device`, `owner_ref` must be exactly it, and `owner_uid` must be that /// Device row's durable uid. Only then is the Device's declared Guest read. /// @@ -241,8 +241,8 @@ pub(crate) fn unique_tpm_state_dir( /// Whether one Device-owned worker role binds its socket under the broker /// runtime root's per-Guest directory. /// -/// The long-lived swtpm worker (`--server ...path=/vms//tpm. sock`) -/// and both GPU sidecars (`--socket /vms//gpu. sock`) do. The +/// The long-lived swtpm worker (`--server ...path=/vms//tpm.sock`) +/// and both GPU sidecars (`--socket /vms//gpu.sock`) do. The /// one-shot flush binds its ctrl socket inside the Device's state Volume, and /// the video sidecar's socket lives in the video module's own `/run/d2b-video` /// runtime directory: neither is a directory the broker owns or opens. @@ -345,7 +345,7 @@ fn find_resource_row<'a>( .find(pred) } -/// The authored `metadata. ownerRef` of one row of a verified Zone resource +/// The authored `metadata.ownerRef` of one row of a verified Zone resource /// bundle, parsed into a canonical reference. pub(crate) fn row_owner_ref( bundle_bytes: &[u8], @@ -368,7 +368,7 @@ let bundle: serde_json::Value = serde_json::from_slice(bundle_bytes).ok()?; .and_then(|owner| ResourceRef::parse(owner).ok()) } -/// `Device. metadata. ownerRef == Guest/` for one Device row of a +/// `Device.metadata.ownerRef == Guest/` for one Device row of a /// verified Zone resource bundle. /// /// The same derivation the daemon's Device-worker ticket uses to name the diff --git a/packages/d2b-broker/src/ops/exec_reconcile.rs b/packages/d2b-broker/src/ops/exec_reconcile.rs index d117152b5..d91526fc9 100644 --- a/packages/d2b-broker/src/ops/exec_reconcile.rs +++ b/packages/d2b-broker/src/ops/exec_reconcile.rs @@ -253,7 +253,7 @@ pub trait ReconcileExecutor: Send + Sync { } /// Generate a replacement ed25519 keypair and atomically publish it - /// at `key_path` + `key_path. pub`. + /// at `key_path` + `key_path.pub`. fn run_ssh_keygen<'a>( &'a self, key_path: &'a Path, @@ -1683,7 +1683,7 @@ mod tests { static HELPER_COUNTER: AtomicU64 = AtomicU64::new(0); /// Sysctl key validation: the broker callers pass dotted keys - /// (`net. ipv4. ip_forward`); the executor translates dots to + /// (`net.ipv4.ip_forward`); the executor translates dots to /// slashes for the /proc/sys path. Rejects absolute paths, /// traversal, and unsafe characters. #[tokio::test] diff --git a/packages/d2b-broker/src/ops/media.rs b/packages/d2b-broker/src/ops/media.rs index 24640d3f0..56e8e99ef 100644 --- a/packages/d2b-broker/src/ops/media.rs +++ b/packages/d2b-broker/src/ops/media.rs @@ -216,7 +216,7 @@ pub struct HotplugOutcome { } /// The result of a VM boot media attach:the broker wire response plus -/// which registry/udev artifacts were (re) written and whether udev was +/// which registry/udev artifacts were (re)written and whether udev was /// reloaded. pub struct BootOutcome { /// The wire response echoed to the daemon. @@ -325,7 +325,7 @@ pub async fn refresh_registry(resolver: &BundleResolver) -> Result= 1.20) with `systemctl reload //! NetworkManager.service` fallback. Verify via `nmcli -t -f @@ -89,7 +89,7 @@ impl From for ApplyNmError { } } -/// Renders the d2b-owned NM `conf. d` snippet body. +/// Renders the d2b-owned NM `conf.d` snippet body. pub fn render_nm_conf(entries: &[NmUnmanagedEntry]) -> String { let mut out = String::new(); out.push_str("# d2b-managed begin\n"); diff --git a/packages/d2b-broker/src/ops/pidfd.rs b/packages/d2b-broker/src/ops/pidfd.rs index 4858685ac..b7413d6a5 100644 --- a/packages/d2b-broker/src/ops/pidfd.rs +++ b/packages/d2b-broker/src/ops/pidfd.rs @@ -6,7 +6,7 @@ //! (preferred), with a `fork + pidfd_open` fallback; //! - the pidfd is `CLOEXEC`; //! - it is transported to `d2bd` via `SCM_RIGHTS` over the -//! private `priv. sock`; +//! private `priv.sock`; //! - the broker itself does NOT set `PR_SET_CHILD_SUBREAPER` (it is //! short-lived per operation); //! - reconciliation paths use `pidfd_open` keyed on pid + start-time diff --git a/packages/d2b-broker/src/ops/spawn_runner.rs b/packages/d2b-broker/src/ops/spawn_runner.rs index 1ed8b1701..61e909e3c 100644 --- a/packages/d2b-broker/src/ops/spawn_runner.rs +++ b/packages/d2b-broker/src/ops/spawn_runner.rs @@ -150,7 +150,7 @@ pub struct SpawnRunnerPlanInput { pub mount_policy: MountPolicy, pub cgroup_placement: CgroupPlacement, /// Set by the broker dispatch when the bundle row's - /// `adr_carve_out` field is non-null (e. g. for the swtpm + /// `adr_carve_out` field is non-null (e.g. for the swtpm /// pre-start flush which legitimately runs as root). pub root_carve_out: bool, /// Set to `true` only by unit tests so the preflight skips diff --git a/packages/d2b-broker/src/ops/state_dir.rs b/packages/d2b-broker/src/ops/state_dir.rs index 3b21bf50e..3bb8942a0 100644 --- a/packages/d2b-broker/src/ops/state_dir.rs +++ b/packages/d2b-broker/src/ops/state_dir.rs @@ -62,7 +62,7 @@ pub struct PrepareDirRequest { pub base_dir: PathBuf, /// Per-VM or global scope (`global` if `vm_id` is `None`). pub vm_id_or_scope: String, - /// 0o-mode (e. g. 0o750 for state, 0o755 for runtime). + /// 0o-mode (e.g. 0o750 for state, 0o755 for runtime). pub mode: u32, /// The owner uid to apply to created directories. pub owner_uid: u32, diff --git a/packages/d2b-broker/src/ops/store_sync_export.rs b/packages/d2b-broker/src/ops/store_sync_export.rs index 443066e35..a2ea5275f 100644 --- a/packages/d2b-broker/src/ops/store_sync_export.rs +++ b/packages/d2b-broker/src/ops/store_sync_export.rs @@ -185,7 +185,7 @@ impl StoreSyncObservabilityRecord { /// one's ownership/permissions/ACLs. /// /// In production the directory is created by the observability host -/// module's `systemd. tmpfiles` rule (mode `0750` + a focused `alloy` +/// module's `systemd.tmpfiles` rule (mode `0750` + a focused `alloy` /// read/traverse ACL and a default ACL so broker-created `0640` files /// inherit `user:alloy:r`). The broker must NOT chmod/chown/setfacl an /// existing directory - doing so would clobber that grant. We only @@ -235,7 +235,7 @@ fn ensure_export_dir(export_dir: &Path) -> io::Result<()> { /// directory's default ACL grants `alloy` read on new files; the broker /// does not chown to or know about the `alloy` gid. Daily rotation is by /// filename, so a long-lived broker that crosses midnight simply opens -/// the next day's file. The host Alloy `local. file_match` globs the +/// the next day's file. The host Alloy `local.file_match` globs the /// directory and follows new files + truncation. /// /// Call-site contract: this is best-effort observability. The diff --git a/packages/d2b-broker/src/ops/store_view_posture.rs b/packages/d2b-broker/src/ops/store_view_posture.rs index 322c0991f..6986502f7 100644 --- a/packages/d2b-broker/src/ops/store_view_posture.rs +++ b/packages/d2b-broker/src/ops/store_view_posture.rs @@ -374,7 +374,7 @@ async fn posture_store_view_matrix_paths_with( } /// Posture every ancestor strictly above the per-VM state dir (the farm -/// root's parent, i. e. the daemon's ownership-matrix root) up to the first +/// root's parent, i.e. the daemon's ownership-matrix root) up to the first /// world-traversable directory, so the daemon's group can search it. /// /// The daemon reaches `/zones//guests//store-view` @@ -563,7 +563,7 @@ mod tests { /// `/zones/work/guests/acceptance-guest/store-view` and return the /// farm root plus the broker-created levels above the per-VM state dir, /// innermost first. The state dir itself - the daemon's ownership-matrix - /// root - is `farm. parent()`. + /// root - is `farm.parent()`. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn farm_chain(root: &Path) -> (PathBuf, Vec) { let farm = root diff --git a/packages/d2b-broker/src/ops/swtpm_dir.rs b/packages/d2b-broker/src/ops/swtpm_dir.rs index 28bfd3874..8f74bb7b8 100644 --- a/packages/d2b-broker/src/ops/swtpm_dir.rs +++ b/packages/d2b-broker/src/ops/swtpm_dir.rs @@ -21,11 +21,11 @@ //! identity (`st_dev`/`st_ino` + first-provision stamp). On every //! subsequent spawn the marker is verified against the live dir's //! identity; a missing dir after prior provision, or an `st_ino` -//! mismatch (e. g. a fresh correct-owner empty replacement smuggled in +//! mismatch (e.g. a fresh correct-owner empty replacement smuggled in //! under the sticky per-VM root), fails closed. //! //! The runtime socket dir (`/run/d2b/vms/`) posture is left -//! untouched; only a stale `tpm. sock` under it is unlinked. +//! untouched; only a stale `tpm.sock` under it is unlinked. //! //! Every error is PATH-FREE: the [`SwtpmHardenError`] `Display` carries //! only closed-set reason slugs, never a raw path, so the broker can @@ -120,7 +120,7 @@ pub struct SwtpmDirPaths { /// Per-VM root: `/vms/` (the sticky 3770 parent). pub per_vm_root: PathBuf, /// Runtime socket dir: `/run/d2b/vms/`. Posture untouched; - /// only a stale `tpm. sock` under it is unlinked. + /// only a stale `tpm.sock` under it is unlinked. pub runtime_dir: PathBuf, /// Marker tree root (`/var/lib/d2b/swtpm-markers`). pub marker_dir: PathBuf, @@ -227,17 +227,17 @@ fn production_swtpm_path(p: &Path) -> bool { /// The placement identity a spawn plan's cgroup subtree names. /// -/// A legacy VM-scoped placement (`d2b. slice/[/...]`) carries the VM +/// A legacy VM-scoped placement (`d2b.slice/[/...]`) carries the VM /// name in its first segment. A resource-backed (typed) launch is rewritten by -/// `private_cgroup_placement` into `d2b. slice/process-<64hex>[/...]`, a +/// `private_cgroup_placement` into `d2b.slice/process-<64hex>[/...]`, a /// commitment to the private runtime scope that deliberately carries no VM /// identity: for those launches the VM is resolved from the verified bundle, /// never from the cgroup. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum PlacementSegment { - /// `d2b. slice/[/...]` - the segment after `d2b. slice/` is the VM id. + /// `d2b.slice/[/...]` - the segment after `d2b.slice/` is the VM id. Vm(String), - /// `d2b. slice/process-<64hex>[/...]` - a private resource-backed scope. + /// `d2b.slice/process-<64hex>[/...]` - a private resource-backed scope. RuntimeScope(String), } @@ -270,7 +270,7 @@ pub(crate) fn parse_placement_segment(subtree: &str) -> Option #[derive(Debug, Clone, PartialEq, Eq)] pub struct ResourceBackedSwtpm { /// The Guest whose owning Device declares the worker row - /// (`Device. metadata. ownerRef == Guest/`, the same derivation the + /// (`Device.metadata.ownerRef == Guest/`, the same derivation the /// daemon's Device-worker ticket uses). pub guest: String, /// The trusted TPM state policy root the `path:swtpm-state:` row @@ -375,8 +375,8 @@ pub(crate) fn state_volume_name(device_uid: &ResourceUid) -> String { /// `/run/d2b/vms` runtime dir must be exactly the trusted one; /// - the composed argv must name the trusted state volume directory /// (`--tpmstate dir=/` with `--ctrl -/// ...path=/ctrl. sock`) and the trusted per-Guest runtime socket -/// (`--server`/`--unix` `...path=/run/d2b/vms//tpm. sock`). +/// ...path=/ctrl.sock`) and the trusted per-Guest runtime socket +/// (`--server`/`--unix` `...path=/run/d2b/vms//tpm.sock`). /// /// A launch that disagrees fails closed with [`reasons::IDENTITY_MISMATCH`]. pub fn derive_resource_backed_paths( @@ -1021,7 +1021,7 @@ async fn apply_ancestor_traverse_acl( .map_err(|_| reasons::ANCESTOR_ACL_FAILED) } -/// Unlink only the trusted `tpm. sock` under the runtime dir, if present. +/// Unlink only the trusted `tpm.sock` under the runtime dir, if present. /// The runtime dir's own posture (mode / ACL / sibling entries) is left /// untouched. A missing runtime dir is a no-op (not an error). fn unlink_stale_socket(runtime_dir: &Path) -> Result<(), &'static str> { @@ -1507,7 +1507,7 @@ mod tests { s.make_per_vm_root(&paths); let cfg = s.cfg(); // Pre-create runtime dir with a distinctive mode + a sibling - // file + a stale tpm. sock. + // file + a stale tpm.sock. tokio::fs::create_dir_all(&paths.runtime_dir).await.unwrap(); tokio::fs::set_permissions(&paths.runtime_dir, fs::Permissions::from_mode(0o751)).await.unwrap(); let sibling = paths.runtime_dir.join("vsock.sock"); @@ -1721,7 +1721,7 @@ mod tests { }, cgroup_placement: CgroupPlacement { // What `private_cgroup_placement` writes for a typed launch: - // `d2b. slice/process-<64hex>/`. + // `d2b.slice/process-<64hex>/`. subtree: format!( "d2b.slice/{}/swtpm", "process-".to_owned() + &"a".repeat(64) diff --git a/packages/d2b-broker/src/ops/sysctl.rs b/packages/d2b-broker/src/ops/sysctl.rs index e8dbb07ba..f73c8d436 100644 --- a/packages/d2b-broker/src/ops/sysctl.rs +++ b/packages/d2b-broker/src/ops/sysctl.rs @@ -64,7 +64,7 @@ impl From for ApplySysctlError { } } -/// Converts `net. ipv6.conf..disable_ipv6` to +/// Converts `net.ipv6.conf..disable_ipv6` to /// `/net/ipv6/conf//disable_ipv6` for safe per-link /// writes. pub(crate) fn intent_to_proc_path(root: &Path, intent: &SysctlIntent) -> PathBuf { diff --git a/packages/d2b-broker/src/ops/usbip_host.rs b/packages/d2b-broker/src/ops/usbip_host.rs index be89fdcb7..190133481 100644 --- a/packages/d2b-broker/src/ops/usbip_host.rs +++ b/packages/d2b-broker/src/ops/usbip_host.rs @@ -175,7 +175,7 @@ pub struct UsbipHostDeviceInspection { pub bus_number: u16, /// The physical port chain under the bus, root-first. pub port_chain: Vec, - /// The device node (e. g. `/dev/bus/usb/...`) the device exposes. + /// The device node (e.g. `/dev/bus/usb/...`) the device exposes. pub device_node: PathBuf, /// Which kernel driver currently binds the device's interface. pub driver: UsbipDriverBinding, diff --git a/packages/d2b-broker/src/ops/usbip_lock.rs b/packages/d2b-broker/src/ops/usbip_lock.rs index f5935e362..e7ecab4b3 100644 --- a/packages/d2b-broker/src/ops/usbip_lock.rs +++ b/packages/d2b-broker/src/ops/usbip_lock.rs @@ -43,7 +43,7 @@ pub enum UsbipLockError { expected: String, observed: String, }, - /// Underlying I/O error (e. g. parent dir missing). + /// Underlying I/O error (e.g. parent dir missing). Io { path: PathBuf, source: std::io::Error, @@ -175,7 +175,7 @@ pub fn acquire_lock( Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => { let existing = read_owner(&full_lock_path).unwrap_or_else(|_| "".to_owned()); - // Idempotent: if the same VM already owns the lock (e. g. + // Idempotent: if the same VM already owns the lock (e.g. // after a VM restart without an explicit detach), treat the // acquire as a success rather than refusing. if existing.trim() == owner_vm { @@ -478,7 +478,7 @@ mod tests { let lock = tmp.path().join("6-1"); let gid = nix::unistd::Gid::current().as_raw(); acquire_lock(&lock, "work-aad", gid).unwrap(); - // Re-acquire by the same VM succeeds (e. g. after VM restart). + // Re-acquire by the same VM succeeds (e.g. after VM restart). acquire_lock(&lock, "work-aad", gid).unwrap(); assert_eq!(peek_owner(&lock).unwrap(), "work-aad"); } diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index 3e6e9bf6c..a01a39bdb 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -105,7 +105,7 @@ const DEFAULT_GUEST_AUDIT_DIR: &str = "/var/lib/d2b/guest-audit"; /// Default audit retention. Matches the docs claim in /// `docs/reference/daemon-api.md` "Audit" and `AGENTS.md` "Control /// plane". Override via `--audit-retention-days` (broker flag) or the -/// NixOS module's `d2b. site. audit. retentionDays` option. Set to 0 +/// NixOS module's `d2b.site.audit.retentionDays` option. Set to 0 /// to disable pruning. const DEFAULT_AUDIT_RETENTION_DAYS: u32 = 30; const DEFAULT_BUNDLE_PATH: &str = "/var/lib/d2b/current-bundle/manifest.json"; @@ -142,7 +142,7 @@ const MAX_MODULE_NAME_LEN: usize = 64; /// the caller has not moved past. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct RetiredWireVariant { - /// The wire variant name, exactly as the frame's `request. kind` spells + /// The wire variant name, exactly as the frame's `request.kind` spells /// it. pub variant: &'static str, /// The negotiated wire version the variant was retired in: a straggler @@ -268,7 +268,7 @@ pub const RETIRED_WIRE_VARIANTS: &[RetiredWireVariant] = &[ ]; #[cfg(not(feature = "layer1-bootstrap"))] -/// The variant one frame's `request. kind` names, when the envelope's request +/// The variant one frame's `request.kind` names, when the envelope's request /// is shaped the way the closed wire spells it. /// /// The frame is inspected before the typed decode precisely so a variant the @@ -290,7 +290,7 @@ fn request_kind(envelope: &Value) -> Option<&str> { #[cfg(not(feature = "layer1-bootstrap"))] /// The gate's lookup, public so a mixed-version fixture can exercise it the /// way the production accept loop does; the variant name is the frame's -/// `request. kind` ([`request_kind`]). +/// `request.kind` ([`request_kind`]). pub fn retired_wire_variant<'a>( kind: &str, retired: &'a [RetiredWireVariant], @@ -343,7 +343,7 @@ pub struct ServerConfig { /// path. The daemon never names a bundle path on the wire (security: /// prevents path-traversal + symlink-confusion). Defaults to /// `/var/lib/d2b/current-bundle/manifest.json`; the NixOS module's - /// `d2b. site. bundle. currentManifest` option overrides. + /// `d2b.site.bundle.currentManifest` option overrides. pub bundle_path: PathBuf, pub state_dir: PathBuf, /// Trusted target-local activation helper. The daemon never supplies @@ -448,11 +448,11 @@ pub(crate) enum BrokerError { AuditRequiresAdmin, HostShutdownRestricted, /// Broker started without a loadable bundle at - /// `ServerConfig. bundle_path`; bundle-dependent real-wire ops cannot + /// `ServerConfig.bundle_path`; bundle-dependent real-wire ops cannot /// resolve their `BundleOpId` refs and refuse fail-closed. #[cfg_attr(feature = "layer1-bootstrap", allow(dead_code))] BundleResolverUnavailable, - /// Bundle artifact at `ServerConfig. bundle_path` failed the + /// Bundle artifact at `ServerConfig.bundle_path` failed the /// tamper-resistance check (symlink / owner / mode / hash). Every /// incoming operation surfaces this error until the broker is /// restarted with a clean bundle. @@ -515,7 +515,7 @@ pub(crate) enum BrokerError { }, /// `SpawnRunner` was called with `RunnerRole::OtelHostBridge`, but /// the bundle-resolved intent points at a VM whose name does not - /// match `manifest._observability. vmName`. The bridge MUST forward + /// match `manifest._observability.vmName`. The bridge MUST forward /// only into the obs VM declared in the trusted bundle; any other /// target is a closed-set violation and the broker refuses /// fail-closed. @@ -631,7 +631,7 @@ where // --socket-path is optional. Resolution order: // 1. --socket-path flag (explicit override) // 2. D2B_BROKER_SOCKET_PATH env var - // 3. DEFAULT_SOCKET_PATH constant ("/run/d2b/priv. sock") + // 3. DEFAULT_SOCKET_PATH constant ("/run/d2b/priv.sock") // Under SD_LISTEN_FDS=1 (socket activation) the resolved path is // informational only; the broker adopts fd 3 from systemd and // MUST NOT bind, fchmod, or fchown the socket path. @@ -869,7 +869,7 @@ pub fn run(command: BrokerMode) -> Result<(), RunError> { /// or if `LISTEN_FDS` is absent or not `"1"` - not socket-activated. /// - `Some(Ok(fd))` when socket activation is valid and fd 3 has been /// verified as an `AF_UNIX SOCK_SEQPACKET` listen socket. -/// - `Some(Err(_))` if `LISTEN_FDNAMES` is present but is not `"priv. sock"`, +/// - `Some(Err(_))` if `LISTEN_FDNAMES` is present but is not `"priv.sock"`, /// or if the fd-level validation in `sys::adopt_listen_fd_from_fd3` fails. /// /// The `LISTEN_*` vars are NOT unset after adoption. The `sd_listen_fds(3)` @@ -892,7 +892,7 @@ fn adopt_listen_fd() -> Option> { return None; } - // Step 3: If LISTEN_FDNAMES is present it must equal "priv. sock". + // Step 3: If LISTEN_FDNAMES is present it must equal "priv.sock". if let Ok(fdnames) = env::var("LISTEN_FDNAMES") && fdnames != "priv.sock" { @@ -1366,7 +1366,7 @@ pub fn probe_bundle_load_response(bundle_path: &std::path::Path) -> BrokerRespon } /// Like [`probe_bundle_load_response`] but uses an explicit [`BundleVerifyPolicy`]. -/// Tests that need to control uid/gid/mode requirements (e. g. to avoid requiring +/// Tests that need to control uid/gid/mode requirements (e.g. to avoid requiring /// root in CI) pass `current_user_policy()` so the uid check passes and only the /// intended tamper reason fires. #[cfg(not(feature = "layer1-bootstrap"))] @@ -2895,7 +2895,7 @@ fn intent_is_serving_worker_template( /// ([`Self::carries_controller_escrow`]) and the advertised response fd /// indices ([`Self::bootstrap_response_index`] / /// [`Self::console_response_index`]) - instead of re-deriving it from -/// `(req. role, intent)`. +/// `(req.role, intent)`. /// /// The posture deliberately decides NO identity: a launch's executor uid/gid /// and in-namespace root mapping are always the trusted intent's principal @@ -3041,7 +3041,7 @@ impl LaunchPosture { /// This is the single evaluation point for runner identity, and it /// deliberately takes no identity from the posture: the broker's only /// authentication factor is peer identity - `peer_matches_instance` admits -/// exactly `config. d2bd_uid` / `config. d2bd_gid` on the privileged socket, +/// exactly `config.d2bd_uid` / `config.d2bd_gid` on the privileged socket, /// whose mode is `0660 d2bd:d2bd` - so a runner launched with the daemon's /// uid/gid could connect that socket, pass the pre-decode peer check, and use /// the whole daemon API (the pre-PR security review's finding: the @@ -4706,7 +4706,7 @@ async fn dispatch_request_with_backend_and_request_fds( d2b_contracts::usbip::lock_path_for_busid(&req.bus_id), ); - // Same-VM replay: lock is already held by this VM (e. g. daemon restart). + // Same-VM replay: lock is already held by this VM (e.g. daemon restart). let same_vm_replay = match crate::ops::usbip_lock::peek_owner(&lock_path) { Some(owner) if owner == req.vm => true, Some(owner) => { @@ -7393,8 +7393,8 @@ fn usbip_binary_path() -> PathBuf { } /// Best-effort lookup of the human-readable VM name carried in the -/// bundle's `processes. vms[*].vm` list. The wire `VmId` is a transparent -/// opaque string; the bundle index is the `processes. vms[*].vm` field. +/// bundle's `processes.vms[*].vm` list. The wire `VmId` is a transparent +/// opaque string; the bundle index is the `processes.vms[*].vm` field. /// We use the wire value as both the opaque key and the human-readable /// name today - the daemon emits them identically. #[cfg(not(feature = "layer1-bootstrap"))] @@ -8164,7 +8164,7 @@ async fn handle_usbip_acl_revoke_failure_after_unbind( return revoke_error; } - // `backend. usbip_unbind` succeeded before the ACL revoke was attempted. + // `backend.usbip_unbind` succeeded before the ACL revoke was attempted. // Release the host-session claim on revoke failure unless a best-effort // live recheck proves the device is still attached to usbip-host. If the // recheck itself fails, trust the successful unbind result and release to @@ -9292,7 +9292,7 @@ fn validate_typed_process_metadata( serving_worker: bool, intent: &d2b_core::bundle_resolver::ResolvedRunnerIntent, // Owning-Device scope already pinned from the verified bundle (the - // launched row's `metadata. ownerRef`, `device_worker::resolve_launch_scope`). + // launched row's `metadata.ownerRef`, `device_worker::resolve_launch_scope`). // `Some` on the launch path, where that Device anchors every runtime path // the launch derives; `None` for the observe/adopt requests, which carry // no owner uid to pin and derive no Device paths. @@ -9396,7 +9396,7 @@ fn validate_typed_process_metadata( // the intent was resolved through. WHICH Device owns the launched // row is pinned from the verified bundle by the launch arm // (`device_worker::resolve_launch_scope`: the row's - // `metadata. ownerRef`, plus the Device row's durable uid), and the + // `metadata.ownerRef`, plus the Device row's durable uid), and the // request must name exactly that Device - a launch aimed at // another Device would derive another Guest's runtime socket // directory and state Volume. The scope is `None` for the @@ -10031,9 +10031,9 @@ async fn video_socket_path(argv: &[String]) -> Result { )) } -// The OtelHostBridge runner is `socat UNIX-LISTEN:,...`. +// The OtelHostBridge runner is `socat UNIX-LISTEN:,...`. // socat does not unlink a pre-existing socket path before binding, so a -// stale `host-egress. sock` left behind by a prior bridge instance (e. g. +// stale `host-egress.sock` left behind by a prior bridge instance (e.g. // after the obs VM is restarted, draining and respawning the bridge) // makes the fresh socat exit immediately with "address in use". The // readiness probe only checks the socket *file* exists, so the stale @@ -11880,7 +11880,7 @@ fn deliver_targeted_reap( match broker_audit_log_handle().get() { Some(audit_log) => remove_and_notify(runner_id, notif, audit_log.as_ref()), None => { - // No audit handle (e. g. a unit test that didn't start the + // No audit handle (e.g. a unit test that didn't start the // reaper): still reap + notify so the child can't zombie. let removed = remove_runner_registries(runner_id); push_child_reap_notification(notif); @@ -17688,7 +17688,7 @@ mod tests { assert_eq!(export_record.authz_outcome, AuthzOutcome::Allow); // The outer error-audit path must NOT write a second (duplicate) - // record: BrokerError::StoreSyncFailed. audit() is a no-op because + // record: BrokerError::StoreSyncFailed.audit() is a no-op because // the terminal record was already emitted in the dispatch arm. error .audit( @@ -18096,7 +18096,7 @@ mod tests { caller_role: BrokerCallerRole::AdminUid { uid: configured_daemon_uid, }, - // Ignored because config. test_mode=false: the broker must use the + // Ignored because config.test_mode=false: the broker must use the // kernel SO_PEERCRED uid, not the envelope's claimed caller role. audit_join: None, }; diff --git a/packages/d2b-broker/src/state_cells.rs b/packages/d2b-broker/src/state_cells.rs index b854bfa7e..0bcb6d6a7 100644 --- a/packages/d2b-broker/src/state_cells.rs +++ b/packages/d2b-broker/src/state_cells.rs @@ -163,7 +163,7 @@ impl std::fmt::Display for CellStoreError { /// Retention bounds for replayable non-one-time outcome records. /// /// One-time consumed markers are always exempt; records carrying live -/// in-process payloads (e. g. the runner pidfd registry) are live state, not +/// in-process payloads (e.g. the runner pidfd registry) are live state, not /// outcome history, and are exempt too. #[derive(Debug, Clone, Copy)] pub struct RetentionPolicy { @@ -195,7 +195,7 @@ struct CellRecord { /// into a reconciliation rather than an in-progress refusal. claimed: bool, durability: CellDurability, - /// Non-durable cell value (e. g. a runner's pidfd). Live state, exempt + /// Non-durable cell value (e.g. a runner's pidfd). Live state, exempt /// from retention and never serialized. payload: Option>, consumed_ms: u64, @@ -435,7 +435,7 @@ impl CellStore { reply_rx.recv().map_err(|_| CellStoreError::Poisoned)? } - /// Insert one payload record into an ephemeral cell (e. g. a registered + /// Insert one payload record into an ephemeral cell (e.g. a registered /// runner's pidfd). The cell record is in-process state, never durable; /// the recorded principal is the initiating principal of the write. pub fn insert_payload( diff --git a/packages/d2b-broker/src/sys.rs b/packages/d2b-broker/src/sys.rs index 8e47510db..2fda7b32e 100644 --- a/packages/d2b-broker/src/sys.rs +++ b/packages/d2b-broker/src/sys.rs @@ -255,7 +255,7 @@ pub fn tun_set_group(fd: &OwnedFd, gid: u32) -> io::Result<()> { /// (`RESOLVE_NO_SYMLINKS | RESOLVE_NO_MAGICLINKS | RESOLVE_BENEATH`). /// `RESOLVE_NO_XDEV` is additionally enforced at every component as /// defense-in-depth and is relaxed *only* exactly where a real, -/// pre-existing kernel/framework mount sits (e. g. `/run` tmpfs, `/dev` +/// pre-existing kernel/framework mount sits (e.g. `/run` tmpfs, `/dev` /// devtmpfs), since broker paths legitimately span those mounts - see /// [`open_dir_path_safe`] for the per-component mount-tolerant walk: /// @@ -291,7 +291,7 @@ pub mod path_safe { } /// Reject a world-writable (or symlink) parent directory, the most - /// common path-safety regression. for broker file targets. + /// common path-safety regression.for broker file targets. pub fn refuse_world_writable_parent(path: &Path) -> io::Result<()> { let parent = path.parent().ok_or_else(|| { io::Error::new( @@ -976,7 +976,7 @@ pub mod path_safe { /// `fstatat(AT_SYMLINK_NOFOLLOW)` of a single `name` component /// beneath an already-open safe parent dirfd. Returns `Ok(None)` /// when the entry is absent (`ENOENT`). The caller inspects - /// `st_mode` (e. g. `S_IFLNK` / `S_IFDIR`), `st_uid`/`st_gid`, and + /// `st_mode` (e.g. `S_IFLNK` / `S_IFDIR`), `st_uid`/`st_gid`, and /// `st_dev`/`st_ino` without following a symlink. Used by the /// swtpm-dir hardening step to detect symlink / non-dir / owner /// drift without opening the target. @@ -1006,7 +1006,7 @@ pub mod path_safe { /// Returns whether `fd` carries an extended POSIX ACL xattr. The /// tuple is `(access_present, default_present)` for - /// `system. posix_acl_access` and `system. posix_acl_default`. A + /// `system.posix_acl_access` and `system.posix_acl_default`. A /// directory with only the base owner/group/other entries (a /// "minimal" ACL) has NO xattr, so both `false` means "clean". An /// `ENODATA`/`ENOATTR`/`ENOTSUP` result is treated as absent so @@ -1172,7 +1172,7 @@ pub mod path_safe { /// tmpfs, `/dev` a devtmpfs, `/sys` sysfs, `/proc` procfs, and /// `/var/lib` may be its own mount. A single `/`-anchored `NO_XDEV` /// walk therefore fails with `EXDEV` at the first mount crossing - /// (e. g. `/`→`/run` when preparing `/run/d2b/vms/`, or + /// (e.g. `/`→`/run` when preparing `/run/d2b/vms/`, or /// `/`→`/dev` when opening `/dev/net/tun`). /// /// We resolve **component by component**. Each component is opened @@ -1335,7 +1335,7 @@ pub mod path_safe { // Apply mode + ownership only when WE created the dir, or when // the caller asked to re-assert metadata. The `created == false` // case here is the `mkdirat` EEXIST race: a concurrent actor - // (e. g. host activation) created the per-VM root between our + // (e.g. host activation) created the per-VM root between our // initial open (which returned NotFound) and this `mkdirat`. // Re-stamping it then would defeat `ensure_dir_preserve_existing` // exactly as the always-fchmod path did - clipping the ACL mask @@ -1406,7 +1406,7 @@ pub mod path_safe { /// Like [`mkdir_at`] but FAILS CLOSED on `EEXIST` (surfaced as /// [`io::ErrorKind::AlreadyExists`]) instead of treating a pre-existing /// entry as success. Used where adopting a directory this call did NOT - /// create would be a security bug - e. g. the swtpm NVRAM dir + /// create would be a security bug - e.g. the swtpm NVRAM dir /// fresh-create path (issue #64): a role UID with `rwx` on the sticky /// per-VM root can race-create `swtpm/` between the absence pre-check /// and this `mkdirat`, and the broker must refuse rather than @@ -1582,7 +1582,7 @@ pub mod pidfd_sys { /// `clone_args` per ``. Layout is stable since /// kernel 5.5 (the first `clone3`-with-pidfd release). We pin the /// `size = 88` shape (clone3 v2 / set_tid extension); the kernel - /// `clone3` accepts a smaller `args. size` (88) and rejects bigger + /// `clone3` accepts a smaller `args.size` (88) and rejects bigger /// sizes on older kernels, so we pass the minimal size that /// supports CLONE_PIDFD. #[repr(C)] @@ -1623,16 +1623,16 @@ pub mod pidfd_sys { /// v1.1.1 `into_cgroup_dirfd` parameter (per ADR 0011 /// Decision item 8 + ADR 0018 § "Atomic cgroup placement"): /// when `Some(dirfd)`, the clone3 syscall is invoked with - /// `CLONE_INTO_CGROUP` and `args. cgroup = dirfd as u64`. The + /// `CLONE_INTO_CGROUP` and `args.cgroup = dirfd as u64`. The /// kernel atomically places the new child into the cgroup /// pointed at by `dirfd` (typically the per-role leaf - /// `d2b. slice///`) - eliminating the + /// `d2b.slice///`) - eliminating the /// classical race window where the parent writes the child's - /// PID to `cgroup. procs` AFTER fork (during which the child + /// PID to `cgroup.procs` AFTER fork (during which the child /// is unaccounted in the per-role cgroup). /// /// `CLONE_INTO_CGROUP` is supported on kernel ≥ 5.7; the - /// fork+cgroup. procs fallback retains the v1.0 semantics for + /// fork+cgroup.procs fallback retains the v1.0 semantics for /// any kernel that returns ENOSYS/EINVAL on the new flag. #[allow(unsafe_code)] pub fn clone3_pidfd_or_fork_fallback( @@ -1887,7 +1887,7 @@ pub mod pidfd_sys { /// Run `setfacl /proc/self/fd/` in a forked /// child while keeping the target fd CLOEXEC in the broker parent. /// - /// `op` is the setfacl operation flag, e. g. `-m` to add/modify an + /// `op` is the setfacl operation flag, e.g. `-m` to add/modify an /// entry or `-x` to remove one. See [`run_setfacl_on_fd`] for the /// CLOEXEC rationale. #[allow(unsafe_code)] @@ -2408,7 +2408,7 @@ pub mod pidfd_sys { for path in &policy.writable_paths { by_path.entry(path.path.clone()).or_insert(false); } - // device_binds (e. g. /dev/kvm, /dev/dri/renderD128, + // device_binds (e.g. /dev/kvm, /dev/dri/renderD128, // /dev/nvidia*) are bind-mounted writable into the runner mount // namespace. The host already controls access via the dev-node // mode bits + groups; the bind-mount just ensures the device @@ -2431,7 +2431,7 @@ pub mod pidfd_sys { readonly, }); } - // bind_mounts entries are cross-domain bind mounts (e. g. + // bind_mounts entries are cross-domain bind mounts (e.g. // /run/user//wayland-0 -> /run/d2b-gpu//wayland-0). // The dst is created if missing; the src is bind-mounted at the // dst with MS_BIND|MS_REC. Both src and dst must be absolute. The @@ -3095,10 +3095,10 @@ pub mod pidfd_sys { "SpawnRunner: activation stdin exceeds bounded envelope", )); } - // NamespaceSet. user is ALLOWED when - // RunnerIsolationSpec. user_namespace provides the uid_map/gid_map + // NamespaceSet.user is ALLOWED when + // RunnerIsolationSpec.user_namespace provides the uid_map/gid_map // values. Caller must set both for the child to be fake-root - // inside the new user NS. Setting namespaces. user without + // inside the new user NS. Setting namespaces.user without // user_namespace is rejected because the child would land in the // namespace with overflowuid (65534) and no caps - never useful. let user_ns_spec = isolation.user_namespace; @@ -3491,7 +3491,7 @@ pub mod pidfd_sys { // not mask=---. // // Reject umasks that exceed the POSIX file-mode width (0o777) - // so a config typo (e. g. umask = 9999) is caught explicitly + // so a config typo (e.g. umask = 9999) is caught explicitly // rather than silently truncated by libc::umask. if let Some(mask) = child_umask { if mask > 0o777 { @@ -3541,10 +3541,10 @@ pub mod pidfd_sys { } // Parent-side user-NS map writes. Performed AFTER clone3 returns - // (we have the child's PID) and AFTER any fallback cgroup. procs + // (we have the child's PID) and AFTER any fallback cgroup.procs // attach that the parent must perform with host credentials. Both // complete BEFORE the sync pipe write that unblocks the child. - // Sequencing per `man 7 user_namespaces`: cgroup. procs fallback + // Sequencing per `man 7 user_namespaces`: cgroup.procs fallback // attach → uid_map → setgroups=deny → gid_map → sync byte. The // child has already closed its inherited write_fd, so if the // parent dies BEFORE this point the child gets EOF on read and @@ -3981,7 +3981,7 @@ mod tests { #[test] fn user_namespace_true_requires_spec() { - // namespaces. user=true but user_namespace=None is + // namespaces.user=true but user_namespace=None is // rejected before clone3 - the child would land in the // NS with overflowuid and never be able to setuid(0). let mut iso = isolation_with_user_namespace(None); @@ -3994,7 +3994,7 @@ mod tests { #[test] fn user_namespace_spec_requires_namespace_flag() { - // user_namespace=Some but namespaces. user=false is + // user_namespace=Some but namespaces.user=false is // also rejected - the spec would be silently ignored. let mut iso = isolation_with_user_namespace(Some(UserNamespaceSpec { host_uid_for_zero: 1000, @@ -4236,7 +4236,7 @@ mod tests { /// to mutate mounts owned by the parent user-NS); the call /// returns EPERM and the child exits `CHILD_EXIT_MOUNT` (64). /// - /// Skips cleanly on hosts with `kernel. unprivileged_userns_clone=0` + /// Skips cleanly on hosts with `kernel.unprivileged_userns_clone=0` /// (clone3 returns EPERM before any child runs). #[test] fn apply_mount_actions_skipped_in_user_ns() { @@ -4309,7 +4309,7 @@ mod tests { ) { Ok(o) => o, Err(e) if e.raw_os_error() == Some(nix::libc::EPERM) => { - // kernel. unprivileged_userns_clone=0: user namespaces + // kernel.unprivileged_userns_clone=0: user namespaces // not available on this host - skip rather than fail. println!( "SKIP: unprivileged user NS not available \ @@ -4332,7 +4332,7 @@ mod tests { } // CHILD_EXIT_MOUNT = 64 would mean apply_mount_actions ran and - // got EPERM on the locked /nix/store bind-mount - i. e., the + // got EPERM on the locked /nix/store bind-mount - i.e., the // `if !in_ns_credentials` guard is absent. assert_eq!( wait_status, diff --git a/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs b/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs index 4c3e93fda..26aef5650 100644 --- a/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs +++ b/packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs @@ -11,7 +11,7 @@ //! 2. The SCM_RIGHTS transport delivers exactly one fd to the //! receiver. //! 3. The receiver-side fd remains valid after the broker copy is -//! dropped (i. e. it really is a freshly-duplicated kernel handle, +//! dropped (i.e. it really is a freshly-duplicated kernel handle, //! not the broker's own descriptor). //! 4. The `O_CLOEXEC` flag survives the transport (this is a kernel //! invariant for SCM_RIGHTS - we check it on the receiving side). diff --git a/packages/d2b-broker/tests/socket_activation.rs b/packages/d2b-broker/tests/socket_activation.rs index acc3f5c8f..ebee1a318 100644 --- a/packages/d2b-broker/tests/socket_activation.rs +++ b/packages/d2b-broker/tests/socket_activation.rs @@ -1,6 +1,6 @@ //! Socket-activation integration test. //! -//! Spawns the broker binary with `LISTEN_FDS=1 LISTEN_FDNAMES=priv. sock` +//! Spawns the broker binary with `LISTEN_FDS=1 LISTEN_FDNAMES=priv.sock` //! and fd 3 = a bound `AF_UNIX SOCK_SEQPACKET` listen socket, then asserts //! that the broker: //! @@ -14,7 +14,7 @@ //! passed to `execve`. To work around this we launch a POSIX `sh` one-liner: //! //! ```sh -//! LISTEN_PID=$$ LISTEN_FDS=1 LISTEN_FDNAMES=priv. sock exec 3>& broker +//! LISTEN_PID=$$ LISTEN_FDS=1 LISTEN_FDNAMES=priv.sock exec 3>& broker //! ``` //! //! `$$` expands to the shell's PID; after `exec`, the broker runs in the same @@ -146,7 +146,7 @@ fn broker_adopts_socket_activated_fd_and_serves_hello() { // Shell one-liner: // LISTEN_PID=$$ → shell's PID; after `exec`, broker's PID matches. // LISTEN_FDS=1 → one socket fd follows. - // LISTEN_FDNAMES=priv. sock → matches the broker's fd-name expectation. + // LISTEN_FDNAMES=priv.sock → matches the broker's fd-name expectation. // exec 3>& broker → redirect listen socket to fd 3, then exec broker. // // Variable references ($BROKER etc.) protect against path quoting issues. diff --git a/packages/d2b-bus/src/router.rs b/packages/d2b-bus/src/router.rs index 9bc2af71b..e99da6b44 100644 --- a/packages/d2b-bus/src/router.rs +++ b/packages/d2b-bus/src/router.rs @@ -1108,7 +1108,7 @@ impl BusCore { } // Operation bookkeeping is a brief non-suspending critical sectionshared - // with synchronous teardown (Drop impls of OperationLease/BusStream) and + // with synchronous teardown (Drop impls of OperationLease/BusStream)and // the operation table has no async form here. #[allow(clippy::disallowed_methods, reason = "synchronous path")] fn lock_operations(&self) -> MutexGuard<'_, OperationTable> { @@ -1896,7 +1896,7 @@ pub struct CommittedInteractionSubjectInstallBody { /// use d2b_bus::CommittedInteractionSubjectIssuer; /// /// fn clone(value: CommittedInteractionSubjectIssuer) { -/// let _ = value. clone(); +/// let _ = value.clone(); /// } /// ``` /// @@ -1933,7 +1933,7 @@ pub struct CommittedInteractionSubjectIssuer { /// use d2b_bus::CommittedInteractionSubjectInstall; /// /// fn inspect(value: &CommittedInteractionSubjectInstall) { -/// let _ = &value. body; +/// let _ = &value.body; /// } /// ``` /// @@ -1941,7 +1941,7 @@ pub struct CommittedInteractionSubjectIssuer { /// use d2b_bus::CommittedInteractionSubjectInstall; /// /// fn clone(value: CommittedInteractionSubjectInstall) { -/// let _ = value. clone(); +/// let _ = value.clone(); /// } /// ``` /// @@ -2070,7 +2070,7 @@ struct ComponentSessionRegistrar { /// use d2b_bus::ComponentSessionAdmission; /// /// fn inspect(value: &ComponentSessionAdmission) { -/// let _ = &value. identity; +/// let _ = &value.identity; /// } /// ``` /// diff --git a/packages/d2b-bus/src/session/contract.rs b/packages/d2b-bus/src/session/contract.rs index a30aea96a..5a55207da 100644 --- a/packages/d2b-bus/src/session/contract.rs +++ b/packages/d2b-bus/src/session/contract.rs @@ -765,7 +765,7 @@ impl RuntimeRouteAdmissionAuthority { /// use d2b_bus::session::contract::RouteAdmissionEvidence; /// /// fn forge(mut value: RouteAdmissionEvidence) { -/// value. body = todo!(); +/// value.body = todo!(); /// } /// ``` pub struct RouteAdmissionEvidence { diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index 13ee8ac45..e23925d67 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -128,7 +128,7 @@ pub enum BrokerRequest { /// without requiring static bundle firewall/bind intent refs. /// /// The daemon has already validated: (1) the busid is present in sysfs, - /// (2) the target VM has `runtime. capabilities. usbHotplug = true`, (3) no + /// (2) the target VM has `runtime.capabilities.usbHotplug = true`, (3) no /// other active claim holds this busid. The broker validates the busid shape, /// acquires the per-busid OFD lock, and runs the `usbip bind` helper. /// @@ -1210,7 +1210,7 @@ pub struct CreateTapFdRequest { } /// The slice path is pinned by the bundle -/// (`/sys/fs/cgroup/d2b. slice`). It is **not** taken from caller +/// (`/sys/fs/cgroup/d2b.slice`). It is **not** taken from caller /// input - the broker reads it from its own bundle copy via `scope_id`. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -1287,7 +1287,7 @@ pub struct SecretByIdRequest { /// The daemon never passes argv, env, uid/gid, caps, seccomp profile /// path, or any other launch authority across the wire. The broker -/// reads the full launch context from `bundle. vms[vm_id].roles[role_id]` +/// reads the full launch context from `bundle.vms[vm_id].roles[role_id]` /// and constructs the minijail exec line itself. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -2065,7 +2065,7 @@ pub struct StoreSyncRequest { /// Store-sync response. Returned after the broker successfully /// populates the per-VM hardlink farm and swaps the `current` symlink -/// atomically. The `hardlink_farm_path` is the per-VM farm root (i. e. +/// atomically. The `hardlink_farm_path` is the per-VM farm root (i.e. /// `/var/lib/d2b/vms//store-view/`); the active generation /// directory is reachable via the `current` symlink. /// @@ -2137,7 +2137,7 @@ pub struct UsbipBindRequest { /// USBIP firewall-rule skeleton. The rule body and the bus_id are /// derived from the per-busid policy in the trusted bundle -/// (`bundle. usbip. busidLocks[*]`) via the +/// (`bundle.usbip.busidLocks[*]`) via the /// `bundle_usbip_firewall_intent_ref` opaque-ID lookup. The legacy /// caller-supplied `bus_id: String` + `rule_hash: String` fields were /// replaced with this opaque reference because the raw `bus_id` was @@ -2177,7 +2177,7 @@ pub struct UsbipUnbindRequest { /// Explicit-attach: bind a present sysfs busid for a USB-capable VM /// without a bundle intent ref. The daemon has already completed: /// 1. sysfs busid presence check (fail-closed if device absent), -/// 2. USB-capable gate (`runtime. capabilities. usbHotplug`), +/// 2. USB-capable gate (`runtime.capabilities.usbHotplug`), /// 3. active-claim exclusivity check (OFD lock read). /// /// The broker acquires the per-busid OFD lock, runs `usbip bind`, and @@ -2415,7 +2415,7 @@ pub struct DeregisterRunnerPidfdResponse { /// The daemon never names argv, env, uid/gid, caps, /// kernel/initrd/cmdline strings, virtiofs sockets, TAP fds, or any /// other launch authority across the wire. The broker resolves the full -/// role spawn context from `bundle. vms[vm_id].roles[role_id]` anchored +/// role spawn context from `bundle.vms[vm_id].roles[role_id]` anchored /// by the opaque `bundle_runner_intent_ref`. The wire shape follows the /// opaque-only contract for every other mutating variant. /// @@ -2445,7 +2445,7 @@ pub enum RunnerRole { /// persisted record written before the rename still decodes. #[serde(rename = "activation-nixos-runner", alias = "activation-nixos")] ActivationNixos, - /// virtiofsd sidecar; one per `d2b. vms..runner. shares` row. The + /// virtiofsd sidecar; one per `d2b.vms..runner.shares` row. The /// daemon/bundle provides argv from the runner-shape generators. Virtiofsd, /// swtpm sidecar (long-lived `swtpm socket ...` process). @@ -2853,7 +2853,7 @@ pub struct SpawnRunnerResponse { pub start_time_ticks: u64, /// Index into the SCM_RIGHTS fd vector the daemon should treat as /// the spawned process's pidfd. Always `0` today - kept explicit - /// so future multi-fd spawn responses (e. g. CH API socket + pidfd) + /// so future multi-fd spawn responses (e.g. CH API socket + pidfd) /// have an existing wire slot. pub pidfd_index: u32, /// Provider-controller bootstrap endpoint created and retained by the broker. @@ -2936,7 +2936,7 @@ pub struct BrokerRequestEnvelope { } /// Caller role classification derived from `SO_PEERCRED` + the -/// `d2b. site. adminUsers` / `d2b. site. launcherUsers` +/// `d2b.site.adminUsers` / `d2b.site.launcherUsers` /// allowlists. Mirrors the legacy `bootstrap::wire::CallerRole` /// but lives in the production wire crate so the live broker /// dispatch can take it directly. @@ -3088,7 +3088,7 @@ pub struct ValidateLockSpecResponse { /// /// The daemon sends the VM's opaque `vm_id`; the broker resolves /// every `DiskInit` plan-op from the trusted bundle's -/// `ProcessNode. plan_ops` for that VM and creates or validates the +/// `ProcessNode.plan_ops` for that VM and creates or validates the /// disk images before runner spawn. Existing `ifAbsent` images are /// skipped only after fd-bound identity and ext4-superblock validation; /// declared owner/mode posture drift is repaired automatically when the diff --git a/packages/d2b-contracts-control/src/cli_output.rs b/packages/d2b-contracts-control/src/cli_output.rs index 1350b7e30..9b269ef48 100644 --- a/packages/d2b-contracts-control/src/cli_output.rs +++ b/packages/d2b-contracts-control/src/cli_output.rs @@ -38,7 +38,7 @@ pub struct ListItemOutputV2 { pub runner_parity_ok: Option, /// Canonical realm-native workload target address (`..d2b`). /// Present when the daemon has associated this entry with a realm workload - /// identity. Absent for classical `d2b. vms` entries not yet adopted into + /// identity. Absent for classical `d2b.vms` entries not yet adopted into /// a realm. Additive - old CLI consumers must tolerate its absence. #[serde(default, skip_serializing_if = "Option::is_none")] pub canonical_target: Option, diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index 849a53db6..202fa1ccc 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -480,7 +480,7 @@ pub struct UsbipUnbindCliRequest { /// Maximum decoded stdin chunk per `WriteStdin` op and decoded output chunk /// per `ReadOutput` op. The base64 envelope of a -/// 64 KiB chunk (~87 KiB) stays well under the 1 MiB public. sock frame, so a +/// 64 KiB chunk (~87 KiB) stays well under the 1 MiB public.sock frame, so a /// single exec op never approaches the frame cap. pub const EXEC_MAX_CHUNK_BYTES: u64 = 64 * 1024; @@ -2001,7 +2001,7 @@ pub enum AudioErrorKind { ProviderMisconfigured, /// The requested VM was not found in the bundle. VmNotFound, - /// Audio enforcement is not available for this VM (e. g. the runtime does + /// Audio enforcement is not available for this VM (e.g. the runtime does /// not support it and no degraded path exists). EnforcementUnavailable, /// The VM exists but audio is not enabled in its manifest entry. @@ -2070,7 +2070,7 @@ pub enum AudioOp { #[serde(rename_all = "camelCase")] pub struct AudioChannelState { /// Current volume/gain level in percent. `None` when the level is unknown - /// (e. g. the provider has not yet synced state). + /// (e.g. the provider has not yet synced state). #[serde(default, skip_serializing_if = "Option::is_none")] pub level: Option, /// Whether the channel is currently muted. @@ -2174,7 +2174,7 @@ pub struct HostDestroyRequest { } /// `host reconcile` request payload. Today the only scope is -/// `--network`; future versions may add additional scopes (e. g. +/// `--network`; future versions may add additional scopes (e.g. /// `--ownership`) carved out of `host prepare`. The daemon rejects /// requests with no scope selected with a typed `invalid-request` /// envelope. @@ -2739,7 +2739,7 @@ pub struct ListEntry { pub usbip: bool, pub vm: String, /// Realm-native workload identity. Present for workloads that have been - /// associated with a realm; `None` for classical `d2b. vms` entries that + /// associated with a realm; `None` for classical `d2b.vms` entries that /// have not yet been adopted into a realm. Additive field - old daemons /// omit it; new CLI consumers must tolerate its absence. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -2776,7 +2776,7 @@ pub struct VmStatus { pub usb: Option, pub vm: String, /// Realm-native workload identity. Present for workloads that have been - /// associated with a realm; `None` for classical `d2b. vms` entries that + /// associated with a realm; `None` for classical `d2b.vms` entries that /// have not yet been adopted into a realm. Additive field - old daemons /// omit it; new CLI consumers must tolerate its absence. #[serde(default, skip_serializing_if = "Option::is_none")] diff --git a/packages/d2b-contracts-provider/src/v3/credential.rs b/packages/d2b-contracts-provider/src/v3/credential.rs index 76e2e20cf..5def9c773 100644 --- a/packages/d2b-contracts-provider/src/v3/credential.rs +++ b/packages/d2b-contracts-provider/src/v3/credential.rs @@ -4,7 +4,7 @@ //! ResourceType. The scope, audience, consumer, allowed-operation, rotation, //! expiry, revocation, and identity-Guest fields are Layer 2 base fields; //! non-secret implementation-only desired settings belong to the Layer 3 -//! `spec. provider` envelope on the universal `ResourceSpec`. +//! `spec.provider` envelope on the universal `ResourceSpec`. //! //! The base spec is zero-secret by construction: it carries no token, key, //! pre-shared key, cookie, claim, or other credential byte. Sensitive bytes diff --git a/packages/d2b-contracts-provider/src/v3/provider.rs b/packages/d2b-contracts-provider/src/v3/provider.rs index 36f47ad4c..f37e09fd8 100644 --- a/packages/d2b-contracts-provider/src/v3/provider.rs +++ b/packages/d2b-contracts-provider/src/v3/provider.rs @@ -896,12 +896,12 @@ impl ComponentStateVolumeProjection { &self.source_execution_ref } - /// Return the Volume `quota. maxBytes` value. + /// Return the Volume `quota.maxBytes` value. pub const fn quota_max_bytes(&self) -> u64 { self.quota_max_bytes } - /// Return the nonzero Volume `quota. maxInodes` value. + /// Return the nonzero Volume `quota.maxInodes` value. pub const fn quota_max_inodes(&self) -> u64 { self.quota_max_inodes } @@ -1086,7 +1086,7 @@ impl ComponentStateNamespace { self.sensitivity_class } - /// Return the byte quota copied to `quota. maxBytes`. + /// Return the byte quota copied to `quota.maxBytes`. pub const fn quota_bytes(&self) -> u64 { self.quota_bytes } @@ -1814,7 +1814,7 @@ impl<'de> Deserialize<'de> for StandardCapabilityMatrix { } } -/// One registered `spec. provider` or `status. provider` extension schema. +/// One registered `spec.provider` or `status.provider` extension schema. /// /// The resource store validates every extension write against the installed /// Provider's registration, rejecting an unregistered or version-mismatched @@ -1838,8 +1838,8 @@ redacted_debug!(ExtensionSchemaRegistration); /// fingerprint it implements, the signed capability matrix, and the strict /// extension schemas it registers. The base itself is never redefined here: /// fields shared across implementations are promoted to the ResourceType -/// base and are never registered under `spec. provider` or -/// `status. provider`. +/// base and are never registered under `spec.provider` or +/// `status.provider`. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] pub struct ResourceApiBinding { @@ -1988,12 +1988,12 @@ impl ResourceApiBinding { &self.capability_matrix } - /// The registered `spec. provider` extension schema, if any. + /// The registered `spec.provider` extension schema, if any. pub const fn spec_extension(&self) -> Option<&ExtensionSchemaRegistration> { self.spec_extension.as_ref() } - /// The registered `status. provider` extension schema, if any. + /// The registered `status.provider` extension schema, if any. pub const fn status_extension(&self) -> Option<&ExtensionSchemaRegistration> { self.status_extension.as_ref() } @@ -2208,7 +2208,7 @@ impl ProjectionFactory { /// Decide whether an export may target the supplied stored resource. /// - /// `ResourceExport. resourceRef` must target a locally owned authority + /// `ResourceExport.resourceRef` must target a locally owned authority /// Service. An import-owned projection is never re-exportable. pub fn admits_export_target( &self, diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs index 20eb946b1..7a6972703 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/audio.rs @@ -1,16 +1,16 @@ //! The shared audio semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen audio pair `audio. d2bus. org.AudioService` and -//! `audio. d2bus. org.AudioBinding`. The field sets below are the top-level +//! frozen audio pair `audio.d2bus.org.AudioService` and +//! `audio.d2bus.org.AudioBinding`. The field sets below are the top-level //! provider-neutral base fields stated by the audio Provider dossier's -//! `AudioService. spec`, `AudioService. status`, `AudioBinding. spec`, and -//! `AudioBinding. status` tables, which are the ResourceType base per D089 and +//! `AudioService.spec`, `AudioService.status`, `AudioBinding.spec`, and +//! `AudioBinding.status` tables, which are the ResourceType base per D089 and //! D088. //! //! PipeWire aliases, node selectors, portal settings, frontend parameters, and //! every other implementation detail are rejected from these bases and belong -//! only in an implementation's strict `spec. provider` and `status. provider` +//! only in an implementation's strict `spec.provider` and `status.provider` //! extensions. //! //! Interiors this catalog does not model. `grants` carries `mic`, `speaker`, @@ -79,7 +79,7 @@ const BINDING_STATUS_ALLOWED: &[&str] = &[ /// A projection Service carries only `providerRef`, its observed role, and its /// local route Endpoints. It never carries the owner authority descriptor and -/// never carries `spec. provider`. +/// never carries `spec.provider`. const PROJECTION_SPEC_ALLOWED: &[&str] = &["providerRef", "serviceRole", "implementationEndpointRefs"]; const PROJECTION_SPEC_REQUIRED: &[&str] = @@ -121,7 +121,7 @@ mod tests { assert_base_is_provider_neutral, assert_minimal_base_round_trips, object, provider_ref, }; - /// Canonical minimal base acceptance without `spec. provider`, plus a + /// Canonical minimal base acceptance without `spec.provider`, plus a /// strict serde and canonical-schema round trip. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { @@ -167,8 +167,8 @@ mod tests { assert!(contract.validate_minimal_base_spec(&spec).is_err()); } - /// Common fields only under `status. resource`; implementation observation - /// only under `status. provider`. + /// Common fields only under `status.resource`; implementation observation + /// only under `status.provider`. #[test] fn a_pipewire_observation_is_not_a_common_status_field() { let status = contract().service().status(); diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs index 4d459941c..3a888c7e9 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs @@ -13,12 +13,12 @@ //! //! Two spellings appear here and are never interchangeable. The API //! ResourceType is the dot-qualified name, for example -//! `audio. d2bus. org.AudioService`, and a ResourceRef appends `/` to it. +//! `audio.d2bus.org.AudioService`, and a ResourceRef appends `/` to it. //! The schema identity is the slash form, `//spec` and //! `//status`. //! //! Scope of the base. A base layer here is the frozen top-level field set of -//! `spec` and of `status. resource` for one ResourceType, plus its schema +//! `spec` and of `status.resource` for one ResourceType, plus its schema //! identity, version, and fingerprint. That is exactly the surface the //! specification freezes as provider-neutral. Where the specification names a //! base field but does not fix that field's interior member names or value @@ -297,7 +297,7 @@ impl SemanticLayer { pub enum SemanticContractError { /// A base spec or status layer failed its frozen field-name schema. SchemaViolation, - /// A projection spec carried a `spec. provider` extension. A Core-generated + /// A projection spec carried a `spec.provider` extension. A Core-generated /// projection permits only `providerRef`, the semantic base and import /// fields, and ResourceImport ownership. ProjectionProviderExtensionForbidden, @@ -574,7 +574,7 @@ impl SemanticTypeContract { &self.spec } - /// Borrow the frozen base `status. resource` layer. + /// Borrow the frozen base `status.resource` layer. pub const fn status(&self) -> &SemanticLayerSchema { &self.status } @@ -583,7 +583,7 @@ impl SemanticTypeContract { /// /// This is exactly the field set the canonical minimal valid base Spec /// supplies, and every conformant implementation must accept it without - /// a `spec. provider` extension. + /// a `spec.provider` extension. pub fn required_spec_fields(&self) -> impl Iterator + '_ { self.spec.required_names() } @@ -621,7 +621,7 @@ impl SemanticTypeContract { } /// Assemble the canonical minimal valid base Spec, without a - /// `spec. provider` extension. + /// `spec.provider` extension. /// /// `base_values` must supply exactly the required base field names other /// than `providerRef`, which the envelope owns. The catalog supplies the @@ -903,13 +903,13 @@ impl SemanticProjectionBinding { /// Admit a Core-generated projection Service spec. /// /// A projection permits only `providerRef`, the semantic base and import - /// fields, and ResourceImport ownership. A `spec. provider` extension is + /// fields, and ResourceImport ownership. A `spec.provider` extension is /// rejected: Core never synthesizes one and never copies a remote one. /// /// # Errors /// /// Returns [`SemanticContractError::ProjectionProviderExtensionForbidden`] - /// when the spec carries a `spec. provider` extension and + /// when the spec carries a `spec.provider` extension and /// [`SemanticContractError::SchemaViolation`] when a field name is outside /// the projection's allowed set or a required name is missing. pub fn validate_projection_spec( @@ -1118,7 +1118,7 @@ impl SemanticPairContract { Ok(()) } - /// Check the ResourceType half of a `ResourceExport. resourceRef`. + /// Check the ResourceType half of a `ResourceExport.resourceRef`. /// /// It must target the owner Service, never a `Device`, an `Endpoint`, or /// a `*Binding`. This type-only helper does not establish resource origin; @@ -1240,7 +1240,7 @@ pub(crate) mod tests_support { } /// Assert that the canonical minimal base Spec is accepted with no - /// `spec. provider`, and that it survives a strict serde and canonical + /// `spec.provider`, and that it survives a strict serde and canonical /// JSON round trip unchanged. pub(crate) fn assert_minimal_base_round_trips(member: &SemanticTypeContract, base: &str) { let contract = member @@ -1292,7 +1292,7 @@ pub(crate) mod tests_support { } /// The Provider-specific settings field each installed implementation - /// registers under `spec. provider`, and a name no implementation + /// registers under `spec.provider`, and a name no implementation /// registers at all. Every observation probes all three, so a base that /// admitted one implementation's detail - or admitted an arbitrary extra /// field for one implementation and not the other - moves a probe. @@ -1470,7 +1470,7 @@ pub(crate) mod tests_support { /// Prove the base is genuinely Provider-neutral. /// /// Two different implementations are installed in turn - each with its - /// own registered `spec. provider` / `status. provider` extension - and the + /// own registered `spec.provider` / `status.provider` extension - and the /// entire Provider-observable base surface is captured under each. The /// two observations must be equal: same schema identities, same versions, /// same frozen field sets, same base and factory fingerprints, and the @@ -1840,7 +1840,7 @@ mod tests { } } - /// Core projection rejection of `spec. provider`. + /// Core projection rejection of `spec.provider`. #[test] fn a_core_projection_rejects_a_provider_extension() { let pair = SemanticFamily::SecurityKey.contract(); @@ -2070,8 +2070,8 @@ mod tests { } } - /// Common fields only under `status. resource`; implementation observation - /// only under `status. provider`. A registered Provider extension may not + /// Common fields only under `status.resource`; implementation observation + /// only under `status.provider`. A registered Provider extension may not /// shadow a common status field. #[test] fn a_provider_status_extension_may_not_shadow_a_common_status_field() { diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs index 604ab8391..cf45c4213 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/security_key.rs @@ -1,15 +1,15 @@ //! The shared security-key semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen security-key pair `security-key. d2bus. org.SecurityKeyService` and -//! `security-key. d2bus. org.SecurityKeyBinding`. The field sets below are the +//! frozen security-key pair `security-key.d2bus.org.SecurityKeyService` and +//! `security-key.d2bus.org.SecurityKeyBinding`. The field sets below are the //! top-level provider-neutral base fields stated by the security-key Provider //! dossier's Service and Binding spec/status contract sections. //! //! The Service base is a discriminated `mode` union declaring only semantic //! security-key authority. The physical backing selector is deliberately not a //! base field for this family: the dossier places `deviceRef` and the relay -//! Endpoint inside the implementation's strict `spec. provider` extension. +//! Endpoint inside the implementation's strict `spec.provider` extension. //! //! Consequences of that placement. Because no semantic base field names a //! backing resource, this family's closed `allowedBackingRefTypes` set is @@ -51,7 +51,7 @@ const BINDING_SPEC_REQUIRED: &[&str] = &["providerRef", "serviceRef", "target"]; const BINDING_STATUS_ALLOWED: &[&str] = &["attachment"]; /// The Core-owned projection branch permits only `providerRef` and the -/// observed mode. It rejects `spec. provider`, the physical device selector, +/// observed mode. It rejects `spec.provider`, the physical device selector, /// the authority descriptor, and every physical selector. const PROJECTION_SPEC_ALLOWED: &[&str] = &["providerRef", "mode"]; const PROJECTION_SPEC_REQUIRED: &[&str] = &["providerRef", "mode"]; @@ -91,7 +91,7 @@ mod tests { resource_envelope, }; - /// Canonical minimal base acceptance without `spec. provider`. + /// Canonical minimal base acceptance without `spec.provider`. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { assert_minimal_base_round_trips(contract().service(), r#"{"mode":"authority"}"#); @@ -148,7 +148,7 @@ mod tests { ); } - /// A Core projection rejects `spec. provider` and the authority descriptor. + /// A Core projection rejects `spec.provider` and the authority descriptor. #[test] fn a_projection_rejects_a_provider_extension_and_the_authority_descriptor() { let spec = d2b_contracts_resource::v3::resource::ResourceSpec::new( diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs index 9b879037a..526c61c41 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/telemetry.rs @@ -1,13 +1,13 @@ //! The shared telemetry semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen telemetry pair `telemetry. d2bus. org.TelemetryService` and -//! `telemetry. d2bus. org.TelemetryBinding`. The spec field sets below are the +//! frozen telemetry pair `telemetry.d2bus.org.TelemetryService` and +//! `telemetry.d2bus.org.TelemetryBinding`. The spec field sets below are the //! "TelemetryService base spec" and "TelemetryBinding base spec" D089 tables //! of the telemetry Provider dossier. //! //! OTEL, OTLP, and backend-product choices are not base fields. They belong -//! only in an implementation's strict `spec. provider` extension. +//! only in an implementation's strict `spec.provider` extension. //! //! Interiors this catalog does not model. `signals` is the non-empty subset of //! metrics, traces, and logs. `quota` and `policy` are named as required base @@ -15,7 +15,7 @@ //! frozen member table, so this catalog freezes the top-level field only. //! //! Status field names this catalog could not determine. The dossier describes -//! `TelemetryService. status. resource` and `TelemetryBinding. status. resource` +//! `TelemetryService.status.resource` and `TelemetryBinding.status.resource` //! in prose. Only `serviceRole` and `serviceReadiness` are stated as field //! spellings; the effective signal, quota, and policy digests, the ingest and //! import readiness summaries, the producer counts, the queue and drop @@ -122,7 +122,7 @@ mod tests { r#"{"policy":{},"quota":{},"serviceRole":"authority","signals":["metrics"]}"#; const MINIMAL_BINDING: &str = r#"{"policy":{},"producerRef":"Zone/work","quota":{},"serviceRef":"telemetry.d2bus.org.TelemetryService/ingest","signals":["metrics"]}"#; - /// Canonical minimal base acceptance without `spec. provider`. + /// Canonical minimal base acceptance without `spec.provider`. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { assert_minimal_base_round_trips(contract().service(), MINIMAL_SERVICE); diff --git a/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs b/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs index 88ef16327..360dfd947 100644 --- a/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs +++ b/packages/d2b-contracts-provider/src/v3/semantic_services/usb.rs @@ -1,7 +1,7 @@ //! The shared USB semantic Service and Binding base contract. //! //! This module owns the common base spec, status, and schema contract for the -//! frozen USB pair `usb. d2bus. org.UsbService` and `usb. d2bus. org.UsbBinding`. +//! frozen USB pair `usb.d2bus.org.UsbService` and `usb.d2bus.org.UsbBinding`. //! The field sets below are the top-level provider-neutral base fields stated //! by the USBIP Provider dossier's owner authority, projection, and per-Guest //! Binding sections, which describe the base as carrying only generic @@ -118,7 +118,7 @@ mod tests { const MINIMAL_SERVICE: &str = r#"{"accessPolicy":{},"mode":"authority"}"#; const MINIMAL_BINDING: &str = r#"{"accessPolicy":{},"attachmentPolicy":{},"guestRef":"Guest/corp-vm","serviceRef":"usb.d2bus.org.UsbService/work-token"}"#; - /// Canonical minimal base acceptance without `spec. provider`. + /// Canonical minimal base acceptance without `spec.provider`. #[test] fn the_canonical_minimal_base_is_accepted_without_a_provider_extension() { assert_minimal_base_round_trips(contract().service(), MINIMAL_SERVICE); diff --git a/packages/d2b-contracts-resource/src/v3/device.rs b/packages/d2b-contracts-resource/src/v3/device.rs index 576ae945c..bd8dc1bc6 100644 --- a/packages/d2b-contracts-resource/src/v3/device.rs +++ b/packages/d2b-contracts-resource/src/v3/device.rs @@ -2,9 +2,9 @@ //! //! `Device` is the inventoried, exclusive-or-shared device arbitration //! ResourceType. `deviceClass`, `arbitration`, `maxConcurrentClaims`, and the -//! `inventory. selector` discriminated union are Layer 2 base fields; +//! `inventory.selector` discriminated union are Layer 2 base fields; //! implementation-only device configuration belongs to the Layer 3 -//! `spec. provider` envelope on the universal `ResourceSpec`. +//! `spec.provider` envelope on the universal `ResourceSpec`. //! //! No raw device path appears in the spec. A physical device is selected by a //! stable operator-defined label plus optional bounded filter fields, and the @@ -669,7 +669,7 @@ wire_deserialize!( /// The common Device-specific status resource layer. /// -/// This object is placed in universal `status. resource`; it deliberately does +/// This object is placed in universal `status.resource`; it deliberately does /// not duplicate `observedGeneration`, `phase`, `conditions`, or `update`. #[derive(Clone, PartialEq, Eq, Serialize, JsonSchema)] #[serde(rename_all = "camelCase")] @@ -1054,7 +1054,7 @@ impl DeviceMetricOutcome { } /// Fixed Device metric labels. Zone, resource, UID, selector, and backing -/// identity never occur in this struct; `d2b. zone` and `d2b. provider` belong +/// identity never occur in this struct; `d2b.zone` and `d2b.provider` belong /// only to the OTEL resource-attribute set. #[derive(Debug, Clone, Copy, PartialEq, Eq, JsonSchema)] pub struct DeviceMetricLabels { diff --git a/packages/d2b-contracts-resource/src/v3/host.rs b/packages/d2b-contracts-resource/src/v3/host.rs index 299040bb9..6751ca238 100644 --- a/packages/d2b-contracts-resource/src/v3/host.rs +++ b/packages/d2b-contracts-resource/src/v3/host.rs @@ -1,8 +1,8 @@ //! Host primitive ResourceType base spec. //! //! `Host` is the physical or local execution, policy, and budget parent. -//! Layer 2 is this base spec; `spec. providerRef`, `spec. updatePolicy`, and -//! the Layer 3 `spec. provider` extension envelope live on the universal +//! Layer 2 is this base spec; `spec.providerRef`, `spec.updatePolicy`, and +//! the Layer 3 `spec.provider` extension envelope live on the universal //! `ResourceSpec` and are never restated here. use schemars::JsonSchema; @@ -20,13 +20,13 @@ use d2b_contracts::wire_deserialize; /// The canonical ResourceType name for this module. pub const HOST_RESOURCE_TYPE: &str = "Host"; -/// The only Provider admitted by `Host. spec. providerRef`. +/// The only Provider admitted by `Host.spec.providerRef`. pub const HOST_PROVIDER_REF: &str = "Provider/system-core"; /// The explicit no-isolation posture of the user-only Host. /// /// The posture is a promoted Host base field; it is never a -/// `spec. provider. settings` field, and `null` used to evade the +/// `spec.provider.settings` field, and `null` used to evade the /// no-isolation warning is rejected. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, diff --git a/packages/d2b-contracts-resource/src/v3/network.rs b/packages/d2b-contracts-resource/src/v3/network.rs index e348aec7a..41e987bbb 100644 --- a/packages/d2b-contracts-resource/src/v3/network.rs +++ b/packages/d2b-contracts-resource/src/v3/network.rs @@ -4,7 +4,7 @@ //! layer-3, isolation, routing, DHCP and DNS, external-attachment, mDNS, //! net-VM, and per-execution-target attachment fields are all Layer 2 base //! fields; only genuinely implementation-only desired settings belong to the -//! Layer 3 `spec. provider` envelope on the universal `ResourceSpec`. +//! Layer 3 `spec.provider` envelope on the universal `ResourceSpec`. use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -115,7 +115,7 @@ pub const DEFAULT_HOST_BLOCKLIST: [&str; 4] = [ "192.168.0.0/16", "169.254.0.0/16", ]; -/// A validated IPv4 CIDR in `a. b.c. d/prefix` form. +/// A validated IPv4 CIDR in `a.b.c.d/prefix` form. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[serde(transparent)] pub struct Ipv4Cidr(String); diff --git a/packages/d2b-contracts-resource/src/v3/operations/seal.rs b/packages/d2b-contracts-resource/src/v3/operations/seal.rs index 1a21fde93..7659cd083 100644 --- a/packages/d2b-contracts-resource/src/v3/operations/seal.rs +++ b/packages/d2b-contracts-resource/src/v3/operations/seal.rs @@ -97,7 +97,7 @@ pub struct MutationSealBody { /// use SealedMutation; /// /// fn inspect(sealed: SealedMutation) { -/// let _ = sealed. body; +/// let _ = sealed.body; /// } /// ``` /// @@ -107,7 +107,7 @@ pub struct MutationSealBody { /// use SealedMutation; /// /// fn clone(sealed: SealedMutation) { -/// let _ = sealed. clone(); +/// let _ = sealed.clone(); /// } /// ``` /// @@ -155,7 +155,7 @@ pub struct MutationSealIssuer { /// use operations::seal::MutationSealAcceptor; /// /// fn clone(acceptor: MutationSealAcceptor) { -/// let _ = acceptor. clone(); +/// let _ = acceptor.clone(); /// } /// ``` pub struct MutationSealAcceptor { diff --git a/packages/d2b-contracts-resource/src/v3/resource_schema.rs b/packages/d2b-contracts-resource/src/v3/resource_schema.rs index af6595119..368c59ad1 100644 --- a/packages/d2b-contracts-resource/src/v3/resource_schema.rs +++ b/packages/d2b-contracts-resource/src/v3/resource_schema.rs @@ -734,7 +734,7 @@ impl JsonSchema for SchemaVersion { /// /// A placement anchor is a contract-owned selector, not a Provider-defined /// field path. `Zone` resolves the containing Zone, while `ExecutionRef` -/// resolves the canonical `spec. executionRef` field to one Host or Guest. +/// resolves the canonical `spec.executionRef` field to one Host or Guest. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] @@ -742,7 +742,7 @@ impl JsonSchema for SchemaVersion { pub enum PlacementAnchor { /// Place the resource at its containing Zone. Zone, - /// Place the resource at its canonical `spec. executionRef` target. + /// Place the resource at its canonical `spec.executionRef` target. ExecutionRef, } @@ -779,7 +779,7 @@ impl PlacementAnchor { /// # Errors /// /// Returns [`ResourceSchemaError::PlacementTargetMissing`] when an - /// `ExecutionRef` anchor finds no `spec. executionRef` field, + /// `ExecutionRef` anchor finds no `spec.executionRef` field, /// [`ResourceSchemaError::PlacementTargetInvalid`] when that field is not a /// string or not a parseable reference, and /// [`ResourceSchemaError::PlacementTargetWrongType`] when it names neither @@ -910,12 +910,12 @@ impl ExtensionSchemaId { } } - /// Parse `.d2bus. org//{spec|status}`. + /// Parse `.d2bus.org//{spec|status}`. /// /// # Errors /// /// Returns [`ResourceSchemaError::InvalidSchemaId`] when the value is not - /// exactly `.d2bus. org//{spec|status}` with valid + /// exactly `.d2bus.org//{spec|status}` with valid /// provider and ResourceType names. pub fn parse(value: &str) -> Result { let (authority, remainder) = value @@ -1277,7 +1277,7 @@ impl ResourceSchemaContract { /// # Errors /// /// Returns [`ResourceSchemaError::ProviderExtensionNotMinimal`] when the - /// spec carries a `spec. provider` extension, and + /// spec carries a `spec.provider` extension, and /// [`ResourceSchemaError::UnknownField`] or /// [`ResourceSchemaError::MissingField`] for a base field-set violation. pub fn validate_minimal_base_spec( diff --git a/packages/d2b-contracts-resource/src/v3/user.rs b/packages/d2b-contracts-resource/src/v3/user.rs index 5fdea2616..f47266fd5 100644 --- a/packages/d2b-contracts-resource/src/v3/user.rs +++ b/packages/d2b-contracts-resource/src/v3/user.rs @@ -2,8 +2,8 @@ //! //! `User` is the named identity that ACL principals, Process user domains, //! and Host or Guest `defaultUserRef` fields resolve. The Zone-local resource -//! name and the OS username are separate: `metadata. name` is the canonical -//! Zone-local key, and `spec. osUsername` is the actual username resolved +//! name and the OS username are separate: `metadata.name` is the canonical +//! Zone-local key, and `spec.osUsername` is the actual username resolved //! through NSS. //! //! The User base spec carries no credential material, public key, PAM diff --git a/packages/d2b-contracts-resource/src/v3/volume.rs b/packages/d2b-contracts-resource/src/v3/volume.rs index 29c6ed4d2..2c21e6b02 100644 --- a/packages/d2b-contracts-resource/src/v3/volume.rs +++ b/packages/d2b-contracts-resource/src/v3/volume.rs @@ -5,7 +5,7 @@ //! Host or Guest attachment policy that separate file, directory, ACL, and //! filesystem-view types would otherwise carry. //! -//! `source. settings` never carries a raw host path in the authored spec: the +//! `source.settings` never carries a raw host path in the authored spec: the //! `local-path` and `block-image` source kinds name an opaque bounded //! `sourcePolicyId` that resolves, only inside the Volume Provider's private //! authority, against that Provider's allowlisted root policy. Layout paths diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs index 53fbdab53..3c42c2ddc 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_export.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_export.rs @@ -591,7 +591,7 @@ wire_deserialize!( .map_err(serde::de::Error::custom) ); -/// ResourceExport lifecycle state projected into `status. resource`. +/// ResourceExport lifecycle state projected into `status.resource`. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] diff --git a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs index 5afec63c4..c1de0e4ad 100644 --- a/packages/d2b-contracts-zone-session/src/v3/resource_import.rs +++ b/packages/d2b-contracts-zone-session/src/v3/resource_import.rs @@ -107,7 +107,7 @@ pub enum ImportDisconnectPolicy { Teardown, } -/// ResourceImport lifecycle state projected into `status. resource`. +/// ResourceImport lifecycle state projected into `status.resource`. #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema, )] diff --git a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs index 3c70ad27c..292555d33 100644 --- a/packages/d2b-contracts-zone-session/src/v3/zone_session.rs +++ b/packages/d2b-contracts-zone-session/src/v3/zone_session.rs @@ -54,14 +54,14 @@ //! a v3 peer from silently reading an old tag as a new role. //! //! Two service-package wire strings are stated by the specs and used verbatim: -//! `d2b. resource. v3` and `d2b. zone. v3`. The remaining new wire strings and +//! `d2b.resource.v3` and `d2b.zone.v3`. The remaining new wire strings and //! every new numeric tag are the minimal defensible extension of the frozen //! scheme, not a spec quotation. They are listed in the module's report as //! inferences pending explicit contract confirmation: //! `EndpointPurpose::ZoneLocal` = 14, `EndpointPurpose::ZoneControl` = 15, //! `EndpointRole::ZoneRelay` = 9, `EndpointRole::ZoneBootstrap` = 10, //! `ServicePackage::ZoneV3` = 7, `ServicePackage::ZoneLinkV3` = 8, and the -//! wire string `d2b. zonelink. v3`. +//! wire string `d2b.zonelink.v3`. //! //! # Relationship to the v2-shaped session structs //! @@ -172,7 +172,7 @@ zone_closed_enum!( EndpointPurpose { /// Lifecycle control on a Zone-local endpoint. LocalLifecycle = 1 => "local-lifecycle", - /// The `d2b. resource. v3` resource service. + /// The `d2b.resource.v3` resource service. ResourceService = 2 => "resource-service", /// An enrolled ZoneLink between a parent and a child Zone. ZoneLink = 3 => "zone-link", @@ -199,7 +199,7 @@ zone_closed_enum!( /// A Zone-local endpoint reached over an allocator-issued socket, /// never over a ZoneLink. ZoneLocal = 14 => "zone-local", - /// The `d2b. zone. v3` Zone control service. + /// The `d2b.zone.v3` Zone control service. ZoneControl = 15 => "zone-control", } ); @@ -242,7 +242,7 @@ zone_closed_enum!( /// frozen independently of the v2 assignments and are not restated by /// this module. ServicePackage { - /// `d2b. resource. v3.ResourceService`. + /// `d2b.resource.v3.ResourceService`. ResourceV3 = 1 => "d2b.resource.v3", /// The controller service package. ControllerV3 = 2 => "d2b.controller.v3", @@ -254,7 +254,7 @@ zone_closed_enum!( SupportV3 = 5 => "d2b.support.v3", /// The credential service package. CredentialV3 = 6 => "d2b.credential.v3", - /// `d2b. zone. v3.ZoneService`. + /// `d2b.zone.v3.ZoneService`. ZoneV3 = 7 => "d2b.zone.v3", /// The ZoneLink carriage service package. ZoneLinkV3 = 8 => "d2b.zonelink.v3", diff --git a/packages/d2b-contracts/src/error.rs b/packages/d2b-contracts/src/error.rs index e7ed13739..93c806229 100644 --- a/packages/d2b-contracts/src/error.rs +++ b/packages/d2b-contracts/src/error.rs @@ -50,7 +50,7 @@ pub enum Kind { #[serde(rename = "bundle-tampered")] BundleTampered, /// A provider required by an audio or console operation is present but - /// not in a state where enforcement can proceed (e. g. expected + /// not in a state where enforcement can proceed (e.g. expected /// target-local Process absent). Operator remediation required. #[serde(rename = "provider-misconfigured")] ProviderMisconfigured, @@ -630,7 +630,7 @@ impl Error { } /// Provider required by an audio or console operation is present but - /// misconfigured (e. g. expected target-local Process absent). + /// misconfigured (e.g. expected target-local Process absent). pub fn provider_misconfigured(vm: impl Into, reason: impl Into) -> Self { Self::Audio(AudioError::ProviderMisconfigured { vm: vm.into(), @@ -755,7 +755,7 @@ impl From for Error { #[derive(Debug, Clone, PartialEq, Eq)] pub enum AudioError { /// Provider required by an audio or console operation is present but - /// misconfigured (e. g. expected target-local Process absent). + /// misconfigured (e.g. expected target-local Process absent). ProviderMisconfigured { vm: String, reason: String }, } diff --git a/packages/d2b-contracts/src/lib.rs b/packages/d2b-contracts/src/lib.rs index da7f2de41..357b347b1 100644 --- a/packages/d2b-contracts/src/lib.rs +++ b/packages/d2b-contracts/src/lib.rs @@ -378,7 +378,7 @@ mod tests { fn encode_frame_public_sock_cap_boundary_is_exact() { // A JSON string of N chars serializes to N+2 bytes (two quotes), so // drive the encoded body length to exactly cap-1, cap, and cap+1 to - // pin the public. sock frame boundary. Removing the `> MAX_FRAME_SIZE` + // pin the public.sock frame boundary. Removing the `> MAX_FRAME_SIZE` // check would let the cap+1 case through and fail this test. let body_len = |n: usize| serde_json::to_vec(&"x".repeat(n)).expect("serialize").len(); // cap - 1 and cap fit. diff --git a/packages/d2b-contracts/src/types.rs b/packages/d2b-contracts/src/types.rs index fa40ffdc2..53ebbb10d 100644 --- a/packages/d2b-contracts/src/types.rs +++ b/packages/d2b-contracts/src/types.rs @@ -63,7 +63,7 @@ opaque_id! { opaque_id! { /// Opaque identifier for a per-VM authorization scope. Resolved - /// against `bundle. vms[]`. The VM name string is + /// against `bundle.vms[]`. The VM name string is /// derivation-internal; the daemon should not synthesize one. VmId } diff --git a/packages/d2b-contracts/src/workload_identity.rs b/packages/d2b-contracts/src/workload_identity.rs index 9594900bf..7166ada9b 100644 --- a/packages/d2b-contracts/src/workload_identity.rs +++ b/packages/d2b-contracts/src/workload_identity.rs @@ -48,9 +48,9 @@ use crate::target::RealmTarget; /// ``` /// use d2b_contracts::workload_identity::WorkloadTarget; /// -/// let t = WorkloadTarget::parse("builder.dev. d2b").unwrap(); -/// assert_eq!(t. to_canonical(), "builder.dev. d2b"); -/// assert_eq!(t. workload. as_str(), "builder"); +/// let t = WorkloadTarget::parse("builder.dev.d2b").unwrap(); +/// assert_eq!(t.to_canonical(), "builder.dev.d2b"); +/// assert_eq!(t.workload.as_str(), "builder"); /// ``` pub type WorkloadTarget = RealmTarget; @@ -84,15 +84,15 @@ pub struct WorkloadIdentity { /// Fully-qualified canonical target address, kept pre-rendered to avoid /// repeated formatting and to make it audit-log safe. pub canonical_target: WorkloadTarget, - /// Legacy `d2b. vms.` name for workloads that exist as a classical VM + /// Legacy `d2b.vms.` name for workloads that exist as a classical VM /// entry while the realm-native model is being adopted. `None` for /// workloads declared directly inside a realm without a legacy VM entry. #[serde(default, skip_serializing_if = "Option::is_none")] pub legacy_vm_name: Option, - /// Opaque runtime kind identifier (e. g. `nixos`, `qemu-media`). + /// Opaque runtime kind identifier (e.g. `nixos`, `qemu-media`). #[serde(default, skip_serializing_if = "Option::is_none")] pub runtime_kind: Option, - /// Stable provider identifier within the realm (e. g. + /// Stable provider identifier within the realm (e.g. /// `local-cloud-hypervisor`). #[serde(default, skip_serializing_if = "Option::is_none")] pub provider_id: Option, diff --git a/packages/d2b-core/src/bundle_resolver.rs b/packages/d2b-core/src/bundle_resolver.rs index 6f43f1f7b..1ee8fa870 100644 --- a/packages/d2b-core/src/bundle_resolver.rs +++ b/packages/d2b-core/src/bundle_resolver.rs @@ -424,7 +424,7 @@ pub struct ResolvedDiskInitOp { pub target_path: std::path::PathBuf, /// Pre-allocated file size in bytes. pub size_bytes: u64, - /// Unix permission bits (e. g. `0o600`). + /// Unix permission bits (e.g. `0o600`). pub mode: u32, /// Owner UID - typically the per-VM runner UID. pub owner_uid: u32, @@ -986,9 +986,9 @@ fn lookup_group_gid(name: &str) -> Option { /// on any security check failure: /// - `"symlink"` - `open` returned `ELOOP` (path is a symlink). /// - `"not-regular-file"` - `fstat` shows it is not a regular file. -/// - `"owner"` - `st_uid` ≠ `policy. required_uid` or -/// `st_gid` ≠ `policy. required_gid` (when Some). -/// - `"mode"` - low 9 bits of `st_mode` ≠ `policy. required_mode`. +/// - `"owner"` - `st_uid` ≠ `policy.required_uid` or +/// `st_gid` ≠ `policy.required_gid` (when Some). +/// - `"mode"` - low 9 bits of `st_mode` ≠ `policy.required_mode`. /// /// The read is part of the bundle-read work class the loader seat isolates: /// async consumers reach it only through @@ -1087,7 +1087,7 @@ fn verify_artifact_hash( /// /// The hash is computed over the canonical JSON of the bundle with /// `bundleHash` removed and `artifactHashes` set to null - matching what -/// `nixos-modules/bundle.nix` emits via `builtins. toJSON dataWithoutHash` +/// `nixos-modules/bundle.nix` emits via `builtins.toJSON dataWithoutHash` /// where `dataWithoutHash` has `artifactHashes = null`. /// /// For `schemaVersion "v2"` bundles a missing `bundleHash` is a hard @@ -1164,7 +1164,7 @@ fn verify_bundle_hash(path: &Path, raw_bytes: &[u8]) -> Result<(), Error> { // serde_json without `preserve_order` feature serialises objects with // BTreeMap (sorted keys) - the same lexicographic ordering that - // builtins. toJSON uses on the Nix side. + // builtins.toJSON uses on the Nix side. let canonical = serde_json::to_vec(&value).map_err(|_| Error::internal_io("bundle-hash-canonical"))?; let actual = sha256_hex(&canonical); @@ -2547,7 +2547,7 @@ impl BundleResolver { /// `Guest` is the v3 ResourceType for VMs (there is no separate `Vm` /// type); each yielded pair carries the enclosing `ZoneId` and the /// `BundleResource` whose `spec()` holds the provider identity - /// (`spec. providerRef`) plus the ExecutionPolicy base. Parsing happens + /// (`spec.providerRef`) plus the ExecutionPolicy base. Parsing happens /// on each call over the verified bytes the resolver holds; the /// `ResourceBundle::from_json` parse rejects malformed bytes. pub fn guest_vm_resources(&self) -> impl Iterator { @@ -3016,7 +3016,7 @@ impl BundleResolver { } /// Build the canonical `host-runtime.json` record from the bundle's - /// `host. if_name_mappings` rows. The broker writes this during + /// `host.if_name_mappings` rows. The broker writes this during /// `RunHostInstall` so downstream consumers read ifnames from a /// single source of truth instead of recomputing via the /// SHA-256-vs-FNV-1a dual-algorithm dance. @@ -3540,7 +3540,7 @@ fn cidr_contains_address(cidr: &str, address: &str) -> bool { /// the host-side bridge host octet 1 of the uplink CIDR while the routes' /// gateway host (host octet 2) rides the net-VM side. The derivation /// refuses a malformed uplink CIDR and any uplink whose gateway host would -/// fall outside the bridge's own subnet (e. g. a `/31` or `/32` uplink, or +/// fall outside the bridge's own subnet (e.g. a `/31` or `/32` uplink, or /// a network whose host octet cannot carry both hosts). fn uplink_bridge_cidr(uplink_cidr: &str) -> Option { let bridge = network_cidr_host_address(uplink_cidr, 1)?; @@ -5019,7 +5019,7 @@ type LoadedZoneResourceBundles = (BTreeMap>, Vec, /// TAP role for the bridge-port flag matrix. pub role: TapRole, - /// User-visible interface name as it appears in `d2b. envs.*` - /// and operator docs (e. g. `br-work-lan`). + /// User-visible interface name as it appears in `d2b.envs.*` + /// and operator docs (e.g. `br-work-lan`). pub user_visible_name: String, /// Deterministic hash-derived IFNAMSIZ-safe interface name with - /// `d2b-` prefix (e. g. `d2b-br-a1b2c3d4`). Bundle build refuses any + /// `d2b-` prefix (e.g. `d2b-br-a1b2c3d4`). Bundle build refuses any /// collision. pub derived_ifname: IfName, } diff --git a/packages/d2b-core/src/manifest_v04.rs b/packages/d2b-core/src/manifest_v04.rs index 7261334a5..cb0bd6802 100644 --- a/packages/d2b-core/src/manifest_v04.rs +++ b/packages/d2b-core/src/manifest_v04.rs @@ -21,7 +21,7 @@ use std::{collections::BTreeMap, path::Path}; use crate::runtime::RuntimeMetadata; -/// Current emitted `_manifest. manifestVersion`. +/// Current emitted `_manifest.manifestVersion`. /// /// Bumped to `6` for the local runtime/provider contract. Per-VM manifest /// entries now carry runtime/provider metadata and provider capability bits, and diff --git a/packages/d2b-core/src/processes.rs b/packages/d2b-core/src/processes.rs index b6e83a22d..4d2bfa4f4 100644 --- a/packages/d2b-core/src/processes.rs +++ b/packages/d2b-core/src/processes.rs @@ -25,7 +25,7 @@ pub struct VmProcessDag { /// Additive: present for VMs that are declared as realm workloads; /// absent (`None`) for VMs that predate realm workload declarations. /// Consumers must not treat absence as an error - it simply means the - /// VM is a classical `d2b. vms.` entry without a realm workload row. + /// VM is a classical `d2b.vms.` entry without a realm workload row. /// /// The provider/backend-specific config (vm_id, role, runner argv) is /// carried separately in the per-node `profile` and `argv` fields so @@ -138,7 +138,7 @@ pub enum ProcessNetworkInterfaceType { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ProcessMacvtapInterface { - /// Lower host interface to attach to, e. g. `eno1`. + /// Lower host interface to attach to, e.g. `eno1`. pub link: String, /// macvtap/macvlan mode passed to `ip link ... type macvtap mode`. pub mode: ProcessMacvtapMode, @@ -183,7 +183,7 @@ pub enum SpawnRunnerPlanOp { /// image when present. /// /// Used for d2b-owned raw ext4 volumes and the per-VM writable - /// store overlay disk (`store-overlay. img`). The broker validates + /// store overlay disk (`store-overlay.img`). The broker validates /// `target_path` is under `/var/lib/d2b/vms/`, creates absent /// files with `O_CREAT|O_EXCL`, pre-allocates `size_bytes` via /// `fallocate`, formats them as ext4, and sets mode + ownership. @@ -197,7 +197,7 @@ pub enum SpawnRunnerPlanOp { target_path: PathBuf, /// Pre-allocated size in bytes (broker calls `fallocate`). size_bytes: u64, - /// Unix permission bits in octal (e. g. `0o600` = 384 decimal). + /// Unix permission bits in octal (e.g. `0o600` = 384 decimal). mode: u32, /// Owner UID - typically the per-VM runner UID. owner_uid: u32, diff --git a/packages/d2b-core/src/site.rs b/packages/d2b-core/src/site.rs index 8324a0243..a0303f094 100644 --- a/packages/d2b-core/src/site.rs +++ b/packages/d2b-core/src/site.rs @@ -2,7 +2,7 @@ //! //! The NixOS site module resolves the host session facts the daemon must //! never guess - today the host Wayland socket that -//! `d2b. site. waylandUser` + `d2b. site. waylandDisplay` describe - into this +//! `d2b.site.waylandUser` + `d2b.site.waylandDisplay` describe - into this //! artifact, so the trusted bundle and the runtime directory the site //! provisions cannot disagree. The artifact is optional in the bundle index: //! a bundle that predates it, or a site that declares no Wayland session, @@ -20,7 +20,7 @@ pub struct SiteJson { /// Artifact schema version (currently `"v1"`). pub schema_version: String, /// Absolute host Wayland socket (`/run/user//`), or `null` - /// when the site declares no Wayland session (`d2b. site. waylandUser` is + /// when the site declares no Wayland session (`d2b.site.waylandUser` is /// unset). Optional so bundles that predate the field still parse. #[serde(default, skip_serializing_if = "Option::is_none")] pub wayland_socket: Option, @@ -65,7 +65,7 @@ impl std::fmt::Display for SiteValidationError { /// The one accepted shape: exactly `/run/user//` with no parent /// components - the value the Nix emitter resolves from -/// `d2b. site. waylandUser`'s uid and `d2b. site. waylandDisplay`. +/// `d2b.site.waylandUser`'s uid and `d2b.site.waylandDisplay`. fn wayland_socket_ok(socket: &str) -> bool { let mut components = std::path::Path::new(socket).components(); matches!(components.next(), Some(Component::RootDir)) diff --git a/packages/d2b-core/src/static_invariants.rs b/packages/d2b-core/src/static_invariants.rs index 4c490a7ef..3ab4a02d0 100644 --- a/packages/d2b-core/src/static_invariants.rs +++ b/packages/d2b-core/src/static_invariants.rs @@ -50,7 +50,7 @@ pub const PUBLIC_MANIFEST_FIELDS: &[&str] = &[ "usbipdHostIp", "securityKey", "observability", - // `observability. enabled` (public-safe boolean) is nested under the per-VM + // `observability.enabled` (public-safe boolean) is nested under the per-VM // `observability` object in the current manifest; the bash allowlist // predated this field. The path-bearing key/secret invariant separately // guards the observability block against host-path leaks. @@ -264,7 +264,7 @@ mod tests { /// Negative fixture from `tests/static-invariant-opaque-key-ids.sh`: /// path-bearing key suffixes with host-path values must be reported as - /// `dotted. path=value`. + /// `dotted.path=value`. #[test] fn path_bearing_key_rejects_host_paths() { let manifest = json!({ diff --git a/packages/d2b-host/src/bin/d2b-activation-helper.rs b/packages/d2b-host/src/bin/d2b-activation-helper.rs index 56a8a1091..7db38f580 100644 --- a/packages/d2b-host/src/bin/d2b-activation-helper.rs +++ b/packages/d2b-host/src/bin/d2b-activation-helper.rs @@ -514,7 +514,7 @@ fn cmd_enforce_dir_posture(args: &Args) -> ExitCode { /// already holds, so the setxattr cannot be redirected to a /// different path and the target fd is not inherited by setfacl. The /// `--setfacl-bin` flag pins the setfacl binary (typically -/// `${pkgs. acl}/bin/setfacl`) so $PATH is not consulted. +/// `${pkgs.acl}/bin/setfacl`) so $PATH is not consulted. // CLI-only verb: synchronous `setfacl` status wait at the // activation-helper entry point, never on an executor worker shared // with other tasks. diff --git a/packages/d2b-host/src/bridge_port.rs b/packages/d2b-host/src/bridge_port.rs index b9703dca2..6ec7e978a 100644 --- a/packages/d2b-host/src/bridge_port.rs +++ b/packages/d2b-host/src/bridge_port.rs @@ -2,7 +2,7 @@ //! //! Implements the per-role bridge port flag defaults table plus the //! validators that gate east-west bridges behind the -//! `env. lan. allowEastWest` + `site. allowUnsafeEastWest` double opt-in. +//! `env.lan.allowEastWest` + `site.allowUnsafeEastWest` double opt-in. //! //! The complete flag set this module covers (every flag, every role): //! `isolated`, `hairpin_mode`, `learning`, `unicast_flood`, @@ -167,9 +167,9 @@ pub fn validate_readback( /// Double opt-in policy for east-west bridges. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct EastWestPolicy { - /// Env-level toggle: `d2b. envs..lan. allowEastWest`. + /// Env-level toggle: `d2b.envs..lan.allowEastWest`. pub env_allow_east_west: bool, - /// Site-level toggle: `d2b. site. allowUnsafeEastWest`. + /// Site-level toggle: `d2b.site.allowUnsafeEastWest`. pub site_allow_unsafe_east_west: bool, } @@ -177,7 +177,7 @@ pub struct EastWestPolicy { #[derive(Debug, Clone, PartialEq, Eq)] pub enum BridgePortPolicyError { /// The bundle requested `WorkloadLanEastWest` but the env did not - /// set `lan. allowEastWest = true`. + /// set `lan.allowEastWest = true`. EastWestRequiresEnvOptIn, /// The bundle requested `WorkloadLanEastWest` and the env opted in /// but the site did not set `allowUnsafeEastWest = true`. diff --git a/packages/d2b-host/src/cgroup.rs b/packages/d2b-host/src/cgroup.rs index 11432bc87..9e53a11b8 100644 --- a/packages/d2b-host/src/cgroup.rs +++ b/packages/d2b-host/src/cgroup.rs @@ -6,22 +6,22 @@ //! //! ## Invariants enforced here //! -//! 1. The unified hierarchy must be present (`/sys/fs/cgroup/cgroup. controllers`). +//! 1. The unified hierarchy must be present (`/sys/fs/cgroup/cgroup.controllers`). //! 2. The required controller set `{cpu, memory, io, pids, cpuset}` must be //! advertised on the root before any subtree is created. -//! 3. Before enabling `+cpuset`, an ancestor with an empty `cpuset. cpus` or -//! `cpuset. mems` inherits from `cpuset. cpus. effective` / `cpuset. mems. effective`. -//! 4. `cgroup. subtree_control` is rewritten in the strict order +//! 3. Before enabling `+cpuset`, an ancestor with an empty `cpuset.cpus` or +//! `cpuset.mems` inherits from `cpuset.cpus.effective` / `cpuset.mems.effective`. +//! 4. `cgroup.subtree_control` is rewritten in the strict order //! `+cpu, +memory, +io, +pids, +cpuset` with a re-read verification after //! each individual enable. -//! 5. `cpuset. cpus. partition` STAYS `member`. A debug assertion blows up if +//! 5. `cpuset.cpus.partition` STAYS `member`. A debug assertion blows up if //! any caller passes the partition-root key into the writer; releases //! fail closed by returning [`CgroupError::CgroupPartitionRootForbidden`]. -//! 6. Threaded cgroups are forbidden - `cgroup. type=threaded` is refused. -//! 7. `d2b. slice` and intermediate Zone/Guest cgroup directories must +//! 6. Threaded cgroups are forbidden - `cgroup.type=threaded` is refused. +//! 7. `d2b.slice` and intermediate Zone/Guest cgroup directories must //! be process-free; only leaf role cgroups carry processes. -//! 8. `cgroup. kill` is allowed only on broker/daemon-owned VM or role leaves; -//! ancestor `cgroup. kill` is refused with +//! 8. `cgroup.kill` is allowed only on broker/daemon-owned VM or role leaves; +//! ancestor `cgroup.kill` is refused with //! [`CgroupError::CgroupKillOnAncestorRefused`]. //! 9. The delegation must NOT be performed while running as uid 0; the //! broker is the only root-effective component, and even it walks this @@ -69,7 +69,7 @@ impl Controller { Controller::Cpuset, ]; - /// The cgroup v2 controller name as written in `cgroup. controllers`. + /// The cgroup v2 controller name as written in `cgroup.controllers`. pub fn as_str(&self) -> &'static str { match self { Controller::Cpu => "cpu", @@ -104,7 +104,7 @@ impl fmt::Display for Controller { } } -/// Snapshot of the controllers advertised on a cgroup's `cgroup. controllers` +/// Snapshot of the controllers advertised on a cgroup's `cgroup.controllers` /// file at the moment of probing. #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnabledControllers { @@ -141,24 +141,24 @@ impl EnabledControllers { /// into the broker audit record `error_kind` field. #[derive(Debug, Clone, PartialEq, Eq)] pub enum CgroupError { - /// Unified hierarchy probe failed - `/sys/fs/cgroup/cgroup. controllers` + /// Unified hierarchy probe failed - `/sys/fs/cgroup/cgroup.controllers` /// is missing or unreadable. CLI exit code 1; matches plan-named /// `cgroup-v2-unified-not-present`. CgroupV2UnifiedNotPresent { detail: String }, - /// One or more required controllers are absent from `cgroup. controllers` + /// One or more required controllers are absent from `cgroup.controllers` /// on the delegation root. Matches plan-named `cgroup-controllers-missing`. CgroupControllersMissing { missing: Vec }, /// Delegation was attempted while running as uid 0 (or the host cannot /// support non-root delegation). Matches plan-named /// `cgroup-delegation-refused`. CgroupDelegationRefused { detail: String }, - /// `cgroup. kill` was attempted on an ancestor (e. g. `d2b. slice` + /// `cgroup.kill` was attempted on an ancestor (e.g. `d2b.slice` /// or an intermediate VM cgroup). Matches plan-named /// `cgroup-kill-on-ancestor-refused`. CgroupKillOnAncestorRefused { path: PathBuf }, /// cpuset inheritance could not produce non-empty `.effective` files. CpusetInheritanceFailed { path: PathBuf, detail: String }, - /// `d2b. slice` or an intermediate VM cgroup contained running + /// `d2b.slice` or an intermediate VM cgroup contained running /// processes when the no-internal-process invariant was checked. CgroupInternalProcessesPresent { path: PathBuf, pids: Vec }, /// Subtree-control verification failed after a write - the re-read @@ -169,12 +169,12 @@ pub enum CgroupError { }, /// Threaded cgroup encountered - forbidden. ThreadedCgroupForbidden { path: PathBuf }, - /// Attempt to write `cpuset. cpus. partition` (partition roots are - /// forbidden; ancestors and `d2b. slice` stay `member`). + /// Attempt to write `cpuset.cpus.partition` (partition roots are + /// forbidden; ancestors and `d2b.slice` stay `member`). CgroupPartitionRootForbidden { path: PathBuf }, /// Subtree-control write on `parent` enabled `controller` (the - /// re-read of `parent/cgroup. subtree_control` confirmed it) but the - /// child cgroup's `cgroup. controllers` does not advertise the + /// re-read of `parent/cgroup.subtree_control` confirmed it) but the + /// child cgroup's `cgroup.controllers` does not advertise the /// controller. The delegation must fail closed before chown. CgroupControllerNotExposedToChild { controller: Controller, @@ -286,7 +286,7 @@ impl fmt::Display for CgroupError { impl std::error::Error for CgroupError {} /// Default unified hierarchy mount point. The probe target is -/// `/cgroup. controllers`. +/// `/cgroup.controllers`. pub const UNIFIED_HIERARCHY_ROOT: &str = "/sys/fs/cgroup"; /// Canonical d2b slice name under the unified hierarchy. pub const D2B_SLICE_NAME: &str = "d2b.slice"; @@ -311,7 +311,7 @@ pub trait CgroupBackend { fn mkdir(&self, path: &Path) -> Result<(), CgroupError>; fn fchown(&self, path: &Path, uid: u32, gid: u32) -> Result<(), CgroupError>; - /// Returns the PIDs currently inside `cgroup. procs` for the given + /// Returns the PIDs currently inside `cgroup.procs` for the given /// cgroup directory. fn read_procs(&self, dir: &Path) -> Result, CgroupError>; } @@ -371,8 +371,8 @@ fn read_trimmed(backend: &B, path: &Path) -> Result( backend: &B, path: &Path, @@ -424,11 +424,11 @@ pub fn prepare_cpuset_inheritance( Ok(()) } -/// Step 3: enable controllers in `cgroup. subtree_control` in the strict +/// Step 3: enable controllers in `cgroup.subtree_control` in the strict /// order, verifying re-read after each individual enable. When `child` -/// is `Some`, the child cgroup's `cgroup. controllers` file is also +/// is `Some`, the child cgroup's `cgroup.controllers` file is also /// re-read after each enable ("Each enable is verified by re-reading -/// cgroup. subtree_control AND cgroup. controllers on the child"). +/// cgroup.subtree_control AND cgroup.controllers on the child"). pub fn enable_subtree_controllers( backend: &B, path: &Path, @@ -438,7 +438,7 @@ pub fn enable_subtree_controllers( } /// Variant of [`enable_subtree_controllers`] that additionally verifies -/// the child cgroup's `cgroup. controllers` advertises the just-enabled +/// the child cgroup's `cgroup.controllers` advertises the just-enabled /// controller. Fail-closed with /// [`CgroupError::CgroupControllerNotExposedToChild`]. pub fn enable_subtree_controllers_with_child( @@ -485,7 +485,7 @@ pub fn enable_subtree_controllers_with_child( } /// Step 4 enforcement helper: the algorithm NEVER writes -/// `cpuset. cpus. partition`. Any code path that tries to is treated as a +/// `cpuset.cpus.partition`. Any code path that tries to is treated as a /// programmer bug - a `debug_assert!` blows up in development builds, /// and release builds return [`CgroupError::CgroupPartitionRootForbidden`]. pub fn assert_partition_member_only(path: &Path, key: &str) -> Result<(), CgroupError> { @@ -517,7 +517,7 @@ pub fn assert_not_threaded(backend: &B, path: &Path) -> Result Ok(()) } -/// Step 5: assert `cgroup. procs` is empty on an intermediate (non-leaf) +/// Step 5: assert `cgroup.procs` is empty on an intermediate (non-leaf) /// cgroup. Returns [`CgroupError::CgroupInternalProcessesPresent`] /// listing the offending pids when not. pub fn assert_no_internal_processes( @@ -534,7 +534,7 @@ pub fn assert_no_internal_processes( Ok(()) } -/// Step 7: `cgroup. kill` is allowed only on a leaf. The caller passes +/// Step 7: `cgroup.kill` is allowed only on a leaf. The caller passes /// the cgroup directory and the leaves it is permitted to kill; any /// path not in the leaf set is refused. pub fn cgroup_kill_leaf_only( @@ -581,7 +581,7 @@ pub fn chown_subtree_to_d2bd( } /// v1.1.1 per-VM-interior + per-role-leaf taxonomy. Creates the -/// process-free intermediate directory `d2b. slice//` +/// process-free intermediate directory `d2b.slice//` /// (NOT a leaf). Per-role leaf cgroups are created by /// the per-role leaf helper. Per ADR 0011 Decision item 1. pub fn create_vm_subtree( @@ -932,7 +932,7 @@ pub mod fake { .unwrap_or_default(), )?; let mut inner = self.inner.lock().unwrap(); - // `cgroup. kill` is intercepted separately so the kill scope + // `cgroup.kill` is intercepted separately so the kill scope // can be audited from tests. if path .file_name() @@ -1183,7 +1183,7 @@ mod tests { fn child_controllers_verified_after_subtree_enable() { // Drive the new verifying variant directly to assert the // child-controllers re-read is load-bearing: if the fake - // backend's child `cgroup. controllers` is *blank* the call + // backend's child `cgroup.controllers` is *blank* the call // fail-closes with `cgroup-controller-not-exposed-to-child`. let backend = fresh(d2bd_uid()); let root = Path::new(FAKE_ROOT); diff --git a/packages/d2b-host/src/devices.rs b/packages/d2b-host/src/devices.rs index 5ac0d44a4..4c8646d6b 100644 --- a/packages/d2b-host/src/devices.rs +++ b/packages/d2b-host/src/devices.rs @@ -85,7 +85,7 @@ pub struct DeviceNodeEntry { pub class: DeviceClass, pub path: PathBuf, pub kind: DeviceNodeKind, - /// Required POSIX mode bits (e. g. `0o660`). Validation requires an + /// Required POSIX mode bits (e.g. `0o660`). Validation requires an /// exact `0o7777` match (permission plus special bits). pub mode_required: u32, /// Required POSIX group name (UNIX group ownership), matched via @@ -217,7 +217,7 @@ pub enum DeviceValidation { MissingOptional, /// Required path is absent; broker cannot open the fd. MissingRequired, - /// Path exists but is the wrong kind (e. g. file instead of char + /// Path exists but is the wrong kind (e.g. file instead of char /// device). WrongKind, /// POSIX mode bits do not exactly match the required mask. diff --git a/packages/d2b-host/src/hardlink_farm.rs b/packages/d2b-host/src/hardlink_farm.rs index 4b19c3497..a2f17af9c 100644 --- a/packages/d2b-host/src/hardlink_farm.rs +++ b/packages/d2b-host/src/hardlink_farm.rs @@ -27,7 +27,7 @@ //! live/.d2b-marker- # zero-length readiness marker //! meta/ # guest read-only share root //! current -> generations/ -//! generations//{store-paths,db. dump,meta.json} +//! generations//{store-paths,db.dump,meta.json} //! state/ # host-only broker state //! current -> generations/ //! generations//{system,marker.json,meta.json} @@ -100,7 +100,7 @@ pub enum HardlinkFarmError { b_dev: u64, }, /// `link(2)` returned `EXDEV` even though source and destination - /// share the same `st_dev` - i. e. they are on the same underlying + /// share the same `st_dev` - i.e. they are on the same underlying /// filesystem but in different *vfsmounts* (the canonical case is /// NixOS bind-mounting `/nix/store` read-only on top of itself). /// Unlike [`HardlinkFarmError::DifferentFilesystem`] this is RECOVERABLE: building the @@ -728,7 +728,7 @@ pub async fn write_generation_marker( // here (it has no on-disk backing) but ext4 / xfs / btrfs need // this for full crash safety. Best-effort: errors are // non-fatal - the marker file itself is already on disk via - // the f. sync_all() above. + // the f.sync_all() above. if let Ok(dir) = tokio::fs::File::open(generation_dir).await { let _ = dir.sync_all().await; } @@ -853,7 +853,7 @@ pub async fn build_farm( /// Shared by the legacy [`build_farm`] and the split-layout /// [`build_store_view`]. Top-level paths already present in `live/` are /// skipped (the flat pool is shared across retained generations); the -/// rest are hardlinked into a private `live. stage..` sibling +/// rest are hardlinked into a private `live.stage..` sibling /// and atomically renamed into `live/`. `store_root` and `live/` must /// already exist and share one filesystem (the caller asserts this). /// Returns the top-level link/skip accounting. @@ -985,7 +985,7 @@ async fn fsync_tree_bottom_up(path: &Path) -> Result<(), HardlinkFarmError> { /// /// `generation_id` is the collision-free on-disk key (see /// [`generation_id`]). This function does NOT swap the `state/current` or -/// `meta/current` pointers, copy `db. dump`, or plant the live readiness +/// `meta/current` pointers, copy `db.dump`, or plant the live readiness /// marker: those are the in-process "publish" steps the caller performs /// after a successful (possibly cross-mount-retried) materialisation, in /// the ADR-mandated order (state/current, then meta/current, then the @@ -1044,7 +1044,7 @@ pub async fn build_store_view( let counts = link_closures_into_live(store_root, generation_id, closure_paths).await?; // Guest-served metadata (`meta/generations//`): store-paths + - // guest-safe meta.json only. db. dump is copied in by the caller + // guest-safe meta.json only. db.dump is copied in by the caller // before the meta/current swap. let meta_gen = meta_generation_dir(store_root, generation_id); tokio::fs::create_dir_all(&meta_gen) @@ -1121,10 +1121,10 @@ async fn plant_generation_gcroot( Ok(()) } -/// Copy the closure-scoped Nix DB dump into `meta/generations//db. dump`. +/// Copy the closure-scoped Nix DB dump into `meta/generations//db.dump`. /// In-process (a byte copy, cross-mount-safe). tmp+rename for crash /// safety. Must complete before the `meta/current` swap so the guest -/// never observes a current generation without its `db. dump`. +/// never observes a current generation without its `db.dump`. pub async fn write_meta_db_dump( store_root: &Path, generation_id: &str, @@ -1707,7 +1707,7 @@ pub async fn read_meta_current_id(store_root: &Path) -> Option { read_current_pointer_id(&meta_dir(store_root)).await } -/// Remove stale `current. tmp` files left under `state/` and `meta/` by a +/// Remove stale `current.tmp` files left under `state/` and `meta/` by a /// previous publish that crashed between symlink-write and rename. /// Idempotent. pub async fn reconcile_split_current_tmp(store_root: &Path) -> Result<(), HardlinkFarmError> { diff --git a/packages/d2b-host/src/host_prep_dag.rs b/packages/d2b-host/src/host_prep_dag.rs index 52272048f..cd834c555 100644 --- a/packages/d2b-host/src/host_prep_dag.rs +++ b/packages/d2b-host/src/host_prep_dag.rs @@ -151,7 +151,7 @@ pub enum HostPrepStepKind { /// tap creation so NetworkManager doesn't race the broker's /// `TUNSETIFF` + immediate `dev set master` and pull the link /// down between create + attach. Replaces the - /// `NetworkManager.conf. d/00-d2b-unmanaged.conf` materializer + /// `NetworkManager.conf.d/00-d2b-unmanaged.conf` materializer /// leaf of `microvm-setup@.service`. ApplyNmUnmanaged, /// Apply the per-VM sysctl set (RP filter, forwarding, MSS clamp @@ -161,7 +161,7 @@ pub enum HostPrepStepKind { /// SetBridgePortFlags. Replaces the sysctl-apply leaf of /// `microvm-setup@.service`. ApplySysctl, - /// Set bridge-port flags on the tap (e. g. `learning off`, + /// Set bridge-port flags on the tap (e.g. `learning off`, /// `flood off`, `mcast_to_unicast off`) after tap attach. /// Replaces the `bridge link set` leaf of /// `microvm-tap-interfaces@.service`. Must run AFTER @@ -227,7 +227,7 @@ impl HostPrepStepKind { #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct BundleStepRef { /// Opaque VM id this step targets (resolved against - /// `bundle. vms[]`). + /// `bundle.vms[]`). pub vm_id: VmId, /// Optional authorization scope (env / VM). Present for steps /// that scope to an env (`ApplyNftablesRules` uses @@ -235,10 +235,10 @@ pub struct BundleStepRef { #[serde(default, skip_serializing_if = "Option::is_none")] pub scope_id: Option, /// Optional opaque intent reference for steps that look up a - /// specific bundle intent row (e. g. `nft:env:` for + /// specific bundle intent row (e.g. `nft:env:` for /// `ApplyNftablesRules`, `runner:vm::role:` for tap /// ownership derivation). `None` for steps whose entire - /// payload is derived from `vm_id` alone (e. g. + /// payload is derived from `vm_id` alone (e.g. /// `SshHostKeyPreflight`). #[serde(default, skip_serializing_if = "Option::is_none")] pub bundle_op_id: Option, @@ -306,7 +306,7 @@ impl std::error::Error for CycleError {} /// `PreOpenVhostNetFd`). /// - `runner_role_id` names the runner intent role for the tap step. /// -/// Net VMs (Guest resource `spec. netVm` flag) additionally emit +/// Net VMs (Guest resource `spec.netVm` flag) additionally emit /// `SeedDnsmasqLease`. /// /// Steps unrelated to the VM's optional sidecars (obs / usbip / @@ -333,7 +333,7 @@ pub fn build_host_prep_dag( return Vec::new(); }; let spec = resource.spec(); - // Best-effort env: top-level `spec. env`, else `spec. executionPolicy. env`. + // Best-effort env: top-level `spec.env`, else `spec.executionPolicy.env`. let env = match spec.get("env") { Some(CanonicalJsonValue::String(env)) => Some(env.as_str()), _ => spec diff --git a/packages/d2b-host/src/modules.rs b/packages/d2b-host/src/modules.rs index 1aa4abe57..993cf9772 100644 --- a/packages/d2b-host/src/modules.rs +++ b/packages/d2b-host/src/modules.rs @@ -6,9 +6,9 @@ //! module that is neither built-in nor loaded forces a closed-fail //! `host-modules-locked` finding. //! 2. `/proc/modules` + `/sys/module//` - loaded-module detection. -//! 3. `/lib/modules/$(uname -r)/modules. builtin` (preferred) or -//! `modules. builtin. bin` - built-in detection. -//! 4. `/boot/config-$(uname -r)` or `/proc/config. gz` - secondary +//! 3. `/lib/modules/$(uname -r)/modules.builtin` (preferred) or +//! `modules.builtin.bin` - built-in detection. +//! 4. `/boot/config-$(uname -r)` or `/proc/config.gz` - secondary //! `CONFIG_*` evidence only. //! //! `br_netfilter` post-step-2 detection drives the @@ -61,9 +61,9 @@ pub struct BuiltinModuleSet { } impl BuiltinModuleSet { - /// Parses `modules. builtin`: one relative path per line; the - /// module name is the basename minus the `.ko` (or `.ko. xz`, - /// `.ko. zst`) suffix. + /// Parses `modules.builtin`: one relative path per line; the + /// module name is the basename minus the `.ko` (or `.ko.xz`, + /// `.ko.zst`) suffix. pub fn parse_modules_builtin(contents: &str) -> Self { let mut names = BTreeSet::new(); for line in contents.lines() { @@ -87,16 +87,16 @@ impl BuiltinModuleSet { Self { names } } - /// Parses the in-kernel `modules. builtin. bin` format (the binary - /// sibling of `modules. builtin`). The file is a concatenation of + /// Parses the in-kernel `modules.builtin.bin` format (the binary + /// sibling of `modules.builtin`). The file is a concatenation of /// null-terminated records `=\0`; per-module records /// share a `.=` shape with the module /// path acting as the prefix before the first `.` in the key. - /// Older kernels (depmod ≤ 5. x without `--symbol-prefix`) store + /// Older kernels (depmod ≤ 5.x without `--symbol-prefix`) store /// just `\0` records; we accept both. /// /// We extract the unique set of module relpaths (anything ending - /// in `.ko`, `.ko. xz`, `.ko. zst`, or `.ko. gz`) and reuse the + /// in `.ko`, `.ko.xz`, `.ko.zst`, or `.ko.gz`) and reuse the /// basename stemming pass from [`Self::parse_modules_builtin`]. pub fn parse_modules_builtin_bin(bytes: &[u8]) -> Self { let mut names = BTreeSet::new(); @@ -114,7 +114,7 @@ impl BuiltinModuleSet { let key = lhs.rsplit('/').next().unwrap_or(lhs); let candidate = key.split('.').next().unwrap_or(key); // Also handle the legacy `` (no `.info`) form by - // running the modules. builtin-style stemming pass on the + // running the modules.builtin-style stemming pass on the // whole record. let stems = [ candidate, @@ -215,9 +215,9 @@ pub fn read_loaded_modules_at(proc_modules: &Path, sys_module_dir: &Path) -> Loa set } -/// Reads `/lib/modules/$(uname -r)/modules. builtin`. Returns an empty +/// Reads `/lib/modules/$(uname -r)/modules.builtin`. Returns an empty /// set on failure; the production probe order falls back to -/// `modules. builtin. bin` via [`read_builtin_modules_with_fallback`] +/// `modules.builtin.bin` via [`read_builtin_modules_with_fallback`] /// in step 3. pub fn read_builtin_modules() -> BuiltinModuleSet { let release = uname_release().unwrap_or_default(); @@ -225,8 +225,8 @@ pub fn read_builtin_modules() -> BuiltinModuleSet { read_builtin_modules_at(&primary) } -/// Two-stage builtin probe: prefers `modules. builtin` (text), falls -/// back to `modules. builtin. bin` (in-kernel format) when the text +/// Two-stage builtin probe: prefers `modules.builtin` (text), falls +/// back to `modules.builtin.bin` (in-kernel format) when the text /// variant is missing or unparseable. Returns the union of both if /// both parse successfully. pub fn read_builtin_modules_with_fallback() -> BuiltinModuleSet { @@ -262,7 +262,7 @@ pub fn read_builtin_modules_with_fallback_at(primary: &Path, fallback: &Path) -> } /// Reads the host kernel config. Tries `/boot/config-$(uname -r)` -/// first; falls back to `/proc/config. gz` in step 4. Kernel config is treated +/// first; falls back to `/proc/config.gz` in step 4. Kernel config is treated /// as **secondary** evidence; failure returns `None` and the /// loaded+builtin path drives the decision. pub fn read_kernel_config() -> Option { @@ -281,7 +281,7 @@ pub fn read_kernel_config_at(path: &Path) -> Option { } /// Two-stage kernel-config probe: prefers `` (uncompressed), -/// falls back to a `` gzip-encoded blob (`/proc/config. gz`). +/// falls back to a `` gzip-encoded blob (`/proc/config.gz`). /// Returns `None` only if neither source yields a parseable config. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn read_kernel_config_with_fallback_at( @@ -298,7 +298,7 @@ pub fn read_kernel_config_with_fallback_at( } /// Minimal RFC 1952 gzip → DEFLATE → text decoder used by the -/// `/proc/config. gz` fallback. Strips the gzip header (magic + +/// `/proc/config.gz` fallback. Strips the gzip header (magic + /// optional FEXTRA / FNAME / FCOMMENT) and the trailing 8-byte /// CRC32 + ISIZE, then hands the raw DEFLATE stream to /// `miniz_oxide`. Pure: callers feed a `&[u8]` so the test path @@ -434,8 +434,8 @@ pub struct ProbeInputs { } /// Real-host wrapper around [`probe_with`]. Reads `/proc` + `/sys` -/// plus the modules. builtin two-stage probe (text first, then -/// `modules. builtin. bin`). +/// plus the modules.builtin two-stage probe (text first, then +/// `modules.builtin.bin`). pub fn probe(kmodules: &[KernelModuleEntry]) -> ModuleProbeResult { probe_with( kmodules, diff --git a/packages/d2b-host/src/nftables.rs b/packages/d2b-host/src/nftables.rs index e862e0db2..d94ca7b31 100644 --- a/packages/d2b-host/src/nftables.rs +++ b/packages/d2b-host/src/nftables.rs @@ -206,14 +206,14 @@ pub struct NftChain { pub priority: i32, pub policy: ChainPolicy, /// Rules in order. The reconcile contract requires specific - /// carve-outs (e. g. USBIP per-busid) to be inserted BEFORE the + /// carve-outs (e.g. USBIP per-busid) to be inserted BEFORE the /// generic allow/drop rules - [`NftBatch::add_usbip_carveout`] /// enforces this invariant. pub rules: Vec, } /// A single nft rule. The `expr` field is the rendered nft expression -/// (e. g. `"ip saddr 10.10.0.5 accept"`); `comment` carries the +/// (e.g. `"ip saddr 10.10.0.5 accept"`); `comment` carries the /// mandatory `d2b managed: ` marker. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct NftRule { @@ -858,7 +858,7 @@ pub fn assert_no_forbidden_hooks(batch: &NftBatch) -> Result<(), NftError> { } // The enum has no raw/mangle/nat variant, so a hook that // round-trips through it can never be one of those - but we - // also defend against a buggy chain. name suggesting otherwise. + // also defend against a buggy chain.name suggesting otherwise. let lname = chain.name.to_ascii_lowercase(); if lname == "raw" || lname == "mangle" || lname == "nat" { return Err(NftError::ForeignNftRuleShadowsD2b { @@ -897,7 +897,7 @@ pub mod fake { Self::default() } - /// Seed a foreign rule (e. g. an iptables-nft generated table) + /// Seed a foreign rule (e.g. an iptables-nft generated table) /// the reconcile path MUST preserve. pub fn seed_foreign(&self, rule: impl Into) { self.foreign.borrow_mut().push(rule.into()); diff --git a/packages/d2b-host/src/ownership_matrix.rs b/packages/d2b-host/src/ownership_matrix.rs index a790a1c1d..7f784b05e 100644 --- a/packages/d2b-host/src/ownership_matrix.rs +++ b/packages/d2b-host/src/ownership_matrix.rs @@ -180,7 +180,7 @@ impl OwnershipMismatch { /// Per-VM hardlink-pool paths the enforcer NEVER recurses into. /// -/// Each string is compared byte-for-byte against `entry. path`. Covers +/// Each string is compared byte-for-byte against `entry.path`. Covers /// the canonical `store-view/live` pool and the legacy `store` farm; /// both share inodes with /nix/store, so recursing would risk /// propagating ownership/ACL changes into the system store. diff --git a/packages/d2b-provider-activation-nixos/src/driver.rs b/packages/d2b-provider-activation-nixos/src/driver.rs index cb0e59012..3b36c9c59 100644 --- a/packages/d2b-provider-activation-nixos/src/driver.rs +++ b/packages/d2b-provider-activation-nixos/src/driver.rs @@ -20,7 +20,7 @@ //! //! Conversion mapping (spec section 13): //! - `describe` -> [`ActivationDriverFactory`] registration under -//! `activation-nixos. d2bus. org.NixosGeneration`. +//! `activation-nixos.d2bus.org.NixosGeneration`. //! - `validate_spec` -> [`ResourceDriver::validate`]. //! - `observe` -> [`ResourceDriver::recover`] (rejoin the owned runner). //! - `plan`/`reconcile`/`execute_effect` -> [`ResourceDriver::reconcile`]. @@ -28,7 +28,7 @@ //! durable deleting mark is the manager's (R10), so the old finalizer //! dance is not part of the new plane; the owned runner retires first //! (F3). -//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). //! //! Three preserved behaviors do not map onto one resource's context and are //! reported rather than invented: @@ -44,7 +44,7 @@ //! ever fabricated; the projection stays non-terminal until the //! child-status surface exists. //! 3. The typed activation status projection is in-memory (R11); its -//! durable `status. resource. activationDetail` publication belongs to the +//! durable `status.resource.activationDetail` publication belongs to the //! manager view model, not this driver. #![allow(dead_code)] @@ -890,7 +890,7 @@ impl ResourceDriver for ActivationDriver { /// The execution domains the NixosGeneration type can be reconciled in. /// /// Derived from the placement contract: `NixosGeneration` names the canonical -/// `spec. executionRef` anchor (`PlacementAnchor::canonical_for` resolves +/// `spec.executionRef` anchor (`PlacementAnchor::canonical_for` resolves /// `ExecutionRef`), and the spec constructor admits a `Host` or a `Guest` /// there, so a generation row is driven in either domain. const ACTIVATION_EXECUTION_DOMAINS: &[&str] = &["host", "guest"]; @@ -907,7 +907,7 @@ const ACTIVATION_READS: &[WellKnownType] = &[WellKnownType::NIXOS_GENERATION]; /// `NixosGeneration` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane /// cannot serve the activation generations without it, so it must be /// registered before the plane opens. The type is not exportable: -/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a /// generation can never be an export subject. The driver serves no broker /// operations and declares the one child creation it performs - the owned /// activation runner ([`ACTIVATION_RUNNER_CREATION`]) - and the family's diff --git a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs index cd4d77cd3..81cea1165 100644 --- a/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs +++ b/packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs @@ -36,7 +36,7 @@ pub enum HostClipboardEvent { /// the policy allowlist. `has_secret` indicates a password-manager hint. /// Call [`DataControlOffer::receive`] (then flush + drop write end) to get /// the data. `offer` is `None` when the selection has no allowed MIME - /// types (i. e. the content cannot be pasted). + /// types (i.e. the content cannot be pasted). SelectionChanged { offer: Option, allowed_mimes: Vec, diff --git a/packages/d2b-provider-config-nixos/src/ttrpc.rs b/packages/d2b-provider-config-nixos/src/ttrpc.rs index 79ec67b25..af6f2ad63 100644 --- a/packages/d2b-provider-config-nixos/src/ttrpc.rs +++ b/packages/d2b-provider-config-nixos/src/ttrpc.rs @@ -541,7 +541,7 @@ mod tests { // Drive the registered service handler, not the helper behind it. On // the single-threaded runtime below the release can only be delivered // while the backend is parked if the handler left its polling worker - // free: an inline `backend. dispatch` would stall the only worker and + // free: an inline `backend.dispatch` would stall the only worker and // the handler would answer the parked call with an error. let (started, mut started_rx) = tokio::sync::mpsc::unbounded_channel(); let (release, release_rx) = channel(); diff --git a/packages/d2b-provider-credential-secret-service/src/lib.rs b/packages/d2b-provider-credential-secret-service/src/lib.rs index 96df8d63f..d33e449e0 100644 --- a/packages/d2b-provider-credential-secret-service/src/lib.rs +++ b/packages/d2b-provider-credential-secret-service/src/lib.rs @@ -1109,7 +1109,7 @@ impl fmt::Debug for SessionKey { /// ```compile_fail /// # use d2b_provider_credential_secret_service::SecretServiceSessionCapability; /// fn cannot_clone(capability: SecretServiceSessionCapability) { -/// let _ = capability. clone(); +/// let _ = capability.clone(); /// } /// ``` pub struct SecretServiceSessionCapability { diff --git a/packages/d2b-provider-credential/src/driver.rs b/packages/d2b-provider-credential/src/driver.rs index 3038b4af1..8c14c1649 100644 --- a/packages/d2b-provider-credential/src/driver.rs +++ b/packages/d2b-provider-credential/src/driver.rs @@ -25,7 +25,7 @@ //! - finalizer enrollment + agent child minting + provider readiness -> //! [`ResourceDriver::reconcile`]. //! - `prepare_finalize`/`execute_finalize`/`finalize` -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). //! //! One input has no durable home in the new runtime below the port: the old //! revocation gate read the lease facts from the Credential's persisted @@ -296,7 +296,7 @@ pub struct CredentialDriverArgs { /// The zone the plane serves. pub zone: ZoneId, /// Zone controller generation folded into every revocation request - /// (old `policy_snapshot. controller_generation`). + /// (old `policy_snapshot.controller_generation`). pub controller_generation: ControllerGeneration, /// The daemon-supplied facet set the family's own effects /// implementation is built from (U8): the construction site holds no @@ -977,7 +977,7 @@ const CREDENTIAL_VERBS: &[&str] = &[ /// The execution domains the Credential type can be reconciled in. /// /// A Credential row names a Host or a Guest execution target -/// (`spec. scope. executionRef`; the old `credential_execution_ref` admitted +/// (`spec.scope.executionRef`; the old `credential_execution_ref` admitted /// exactly those two), so the type spans both domains. const CREDENTIAL_EXECUTION_DOMAINS: &[&str] = &["host", "guest"]; @@ -1011,7 +1011,7 @@ const CREDENTIAL_CREATIONS: &[ChildCreation] = &[ChildCreation { /// `Credential` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot /// serve credential rows without it, so it must be registered before the /// plane opens. The type is not exportable (`ResourceExport` admits only -/// qualified `*.d2bus. org.*Service` types), and it serves no broker +/// qualified `*.d2bus.org.*Service` types), and it serves no broker /// operations. /// /// U8: the driver's effects are this crate's own implementation diff --git a/packages/d2b-provider-credential/src/session.rs b/packages/d2b-provider-credential/src/session.rs index bd7be21f8..c367d8090 100644 --- a/packages/d2b-provider-credential/src/session.rs +++ b/packages/d2b-provider-credential/src/session.rs @@ -72,7 +72,7 @@ pub struct CredentialRevocationInputs { pub controller_generation: ControllerGeneration, /// The live Provider session generation the request binds. pub session_generation: ReconnectGeneration, - /// `credential. rotationGeneration`; a missing or zero value keeps the + /// `credential.rotationGeneration`; a missing or zero value keeps the /// old status read's default of 1. pub rotation_generation: u64, } diff --git a/packages/d2b-provider-device-gpu/src/gpu_argv.rs b/packages/d2b-provider-device-gpu/src/gpu_argv.rs index 1b48f1ae2..ac0f21fd0 100644 --- a/packages/d2b-provider-device-gpu/src/gpu_argv.rs +++ b/packages/d2b-provider-device-gpu/src/gpu_argv.rs @@ -11,12 +11,12 @@ //! //! ```text //! crosvm device gpu \ -//! --socket corp-desktop-gpu. sock \ +//! --socket corp-desktop-gpu.sock \ //! --wayland-sock $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY \ //! --params '{"context-types":"virgl:virgl2:cross-domain","displays":[{"hidden":true}],"egl":true,"vulkan":true}' //! ``` //! -//! CH then connects via `--gpu socket=corp-desktop-gpu. sock`. The Process +//! CH then connects via `--gpu socket=corp-desktop-gpu.sock`. The Process //! Provider composes that private CH argument from the sealed launch ticket; //! the Guest controller does not receive or assemble it. //! @@ -85,11 +85,11 @@ pub struct GpuArgvInput { /// not embed the VM name (the socket path does). pub vm_name: String, /// `--socket` value. Audit uses runner-cwd-relative - /// `-gpu. sock`; the daemon uses an absolute path under + /// `-gpu.sock`; the daemon uses an absolute path under /// `/run/d2b/vms//`. Either shape is honoured. pub socket_path: String, /// `--wayland-sock` value. Resolved by the daemon caller to the - /// host's primary Wayland session socket (per `d2b. site. waylandUser`). + /// host's primary Wayland session socket (per `d2b.site.waylandUser`). pub wayland_sock: String, /// `--params` JSON payload. pub params: GpuParams, diff --git a/packages/d2b-provider-device-gpu/src/video_argv.rs b/packages/d2b-provider-device-gpu/src/video_argv.rs index 3b40ce1d8..5a8e062fe 100644 --- a/packages/d2b-provider-device-gpu/src/video_argv.rs +++ b/packages/d2b-provider-device-gpu/src/video_argv.rs @@ -9,7 +9,7 @@ //! //! ```text //! crosvm device video-decoder \ -//! --socket-path /run/d2b-video//video. sock \ +//! --socket-path /run/d2b-video//video.sock \ //! --backend vaapi //! ``` //! @@ -26,19 +26,19 @@ use serde::{Deserialize, Serialize}; // Wire-contract pins // ========================================================================= // -// `pkgs/spectrum-ch/cloud-hypervisor/0003-vhost-user-media-device. patch` +// `pkgs/spectrum-ch/cloud-hypervisor/0003-vhost-user-media-device.patch` // hard-codes the virtio-media wire shape that this sidecar speaks to the // guest through cloud-hypervisor. These constants are NOT user-tunable // argv flags - they live in the CH patch and the crosvm vhost-user-media // backend. We mirror them here so the byte-parity golden -// (`tests/golden/runner-shape/video-argv-minimal. txt`) captures the full +// (`tests/golden/runner-shape/video-argv-minimal.txt`) captures the full // effective wire shape, and any future drift in the CH patch surfaces as // a golden diff in CI even though no argv changed. // // Every constant cites the patch line that pins it. /// virtio device-type id for `vhost-user-media`. Pinned in -/// `0003-vhost-user-media-device. patch` as `const VIRTIO_ID_MEDIA: u32 = 48`. +/// `0003-vhost-user-media-device.patch` as `const VIRTIO_ID_MEDIA: u32 = 48`. pub const VIRTIO_ID_MEDIA: u32 = 48; /// Number of virtqueues exposed by `vhost-user-media` (one command, one @@ -55,7 +55,7 @@ pub const VHOST_USER_MEDIA_QUEUE_SIZE: u16 = 256; pub const VHOST_USER_MEDIA_SHM_REGION_BYTES: u64 = 256 * 1024 * 1024; /// Forced `SET_VRING_BASE` value for every queue. Pinned in the CH patch -/// in `activate()`: `self. vu_common. vring_bases = Some(vec![0; queues. len()])`. +/// in `activate()`: `self.vu_common.vring_bases = Some(vec![0; queues.len()])`. /// The virtio-media guest driver pre-queues event buffers on queue 1 before /// `DRIVER_OK`; the explicit zero override keeps those buffers visible to /// the backend on resume. @@ -68,8 +68,8 @@ pub const VHOST_USER_MEDIA_VRING_BASE: u64 = 0; pub const VHOST_USER_MEDIA_PROTOCOL_FLAGS: &str = "BACKEND_REQ|REPLY_ACK|SHMEM_MAP_CROSVM"; /// PCI MMIO allocator used for the SHM region. Pinned in the CH patch via -/// `self. pci_segments[..].mem64_allocator.lock()...allocate(...)`. The -/// allocator name is part of the wire shape because changing it (e. g. to +/// `self.pci_segments[..].mem64_allocator.lock()...allocate(...)`. The +/// allocator name is part of the wire shape because changing it (e.g. to /// `mem32_allocator`) changes the guest-visible BAR layout. pub const VHOST_USER_MEDIA_MMIO_ALLOCATOR: &str = "pci-mem64"; @@ -114,12 +114,12 @@ impl VideoBackend { pub struct VideoArgvInput { /// Absolute store path to the `crosvm` binary (the video component /// overlays `cargoBuildFeatures += [video-decoder, - /// vaapi, media]` against `pkgs. crosvm`). + /// vaapi, media]` against `pkgs.crosvm`). pub crosvm_binary_path: String, /// VM name; used by the worker launch arg0 only. pub vm_name: String, /// `--socket-path` value. Per host.nix: - /// `/run/d2b-video//video. sock` (the video module uses its + /// `/run/d2b-video//video.sock` (the video module uses its /// own `RuntimeDirectory = d2b-video/` rather /// than sharing `/run/d2b/vms//`). pub socket_path: String, diff --git a/packages/d2b-provider-device-security-key/src/driver.rs b/packages/d2b-provider-device-security-key/src/driver.rs index 02eddcfb3..768705a64 100644 --- a/packages/d2b-provider-device-security-key/src/driver.rs +++ b/packages/d2b-provider-device-security-key/src/driver.rs @@ -2,8 +2,8 @@ //! conversion of the daemon-owned security-key Provider path. //! //! The family serves the two converted security-key ResourceTypes the -//! Provider owns - `security-key. d2bus. org.SecurityKeyService` and -//! `security-key. d2bus. org.SecurityKeyBinding` - and their `Device` rows +//! Provider owns - `security-key.d2bus.org.SecurityKeyService` and +//! `security-key.d2bus.org.SecurityKeyBinding` - and their `Device` rows //! belong to the `d2b-provider-device` family, which owns the `Device` //! ResourceType. //! @@ -77,10 +77,10 @@ const FRONTEND_PROCESS_PROVIDER_REF: &str = d2b_provider_process_systemd::PROVID #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SecurityKeyComponent { /// The security-key authority Service - /// (`security-key. d2bus. org.SecurityKeyService`). + /// (`security-key.d2bus.org.SecurityKeyService`). Service, /// The per-Guest security-key Binding - /// (`security-key. d2bus. org.SecurityKeyBinding`). + /// (`security-key.d2bus.org.SecurityKeyBinding`). Binding, } @@ -624,7 +624,7 @@ mod tests { } /// The relay Endpoint this driver declares carries a closed purpose - /// token: `EndpointSpec. purpose` is a `BoundedToken`, so the dotted + /// token: `EndpointSpec.purpose` is a `BoundedToken`, so the dotted /// pre-wave spelling is an admission refusal. #[test] fn security_key_relay_endpoint_purpose_is_a_closed_token() { diff --git a/packages/d2b-provider-device-tpm/src/effects_service.rs b/packages/d2b-provider-device-tpm/src/effects_service.rs index 0ed83b01d..1c8dca19d 100644 --- a/packages/d2b-provider-device-tpm/src/effects_service.rs +++ b/packages/d2b-provider-device-tpm/src/effects_service.rs @@ -882,7 +882,7 @@ mod tests { } /// Publish one declared row together with the driver-projected - /// `status. resource` layer the Process controller writes for a + /// `status.resource` layer the Process controller writes for a /// one-shot's terminal outcome. fn publish_outcome(&self, reference: &str, status: ResourceStatus, projection: Value) { self.publish(reference, status); @@ -1321,7 +1321,7 @@ async fn deletion_targets_the_declared_rows() { } /// Malformed manager-child documents fail closed before any mutation: a - /// missing type, metadata. name, or spec is rejected, and an + /// missing type, metadata.name, or spec is rejected, and an /// unparseable type/name pair can never name a row. #[test] diff --git a/packages/d2b-provider-device-tpm/src/swtpm_argv.rs b/packages/d2b-provider-device-tpm/src/swtpm_argv.rs index 99316280b..b134dde8d 100644 --- a/packages/d2b-provider-device-tpm/src/swtpm_argv.rs +++ b/packages/d2b-provider-device-tpm/src/swtpm_argv.rs @@ -1,20 +1,20 @@ //! swtpm argv generator (UNIX-socket TPM 2.0 backend). //! //! `swtpm` is the per-VM software TPM sidecar d2b spawns for VMs -//! that declare `d2b. vms..tpm. enable = true`. The guest-side +//! that declare `d2b.vms..tpm.enable = true`. The guest-side //! TPM module passes the CH TPM socket via -//! `d2b. vms..runner. hypervisor. extraArgs`, and the sidecar +//! `d2b.vms..runner.hypervisor.extraArgs`, and the sidecar //! process is shaped as a standalone broker-spawned worker: //! //! ```text //! swtpm socket \ //! --tpm2 \ //! --tpmstate dir= \ -//! --ctrl type=unixio,path=/ctrl. sock,mode=0660,uid=,gid= \ -//! --server type=unixio,path=-tpm. sock,mode=0660,uid=,gid= \ +//! --ctrl type=unixio,path=/ctrl.sock,mode=0660,uid=,gid= \ +//! --server type=unixio,path=-tpm.sock,mode=0660,uid=,gid= \ //! --flags startup-clear \ //! --log file=/swtpm.log,level=20 \ -//! --pid file=/swtpm. pid +//! --pid file=/swtpm.pid //! ``` //! //! `swtpm socket` stays in the foreground unless `-d|--daemon` is @@ -29,7 +29,7 @@ //! (`processes::VmProcessInvariants::swtpm_pre_start_flush = true`): //! //! ```text -//! swtpm_ioctl -i --unix /ctrl. sock +//! swtpm_ioctl -i --unix /ctrl.sock //! ``` //! //! …followed by a clean shutdown command (`-s`) before the supervisor @@ -51,7 +51,7 @@ pub struct SwtpmArgvInput { /// VM name; the Provider refuses an empty one. pub vm_name: String, /// Absolute path to the per-VM TPM state directory. swtpm writes - /// `tpm2-00. permall` plus its log/pid in here. + /// `tpm2-00.permall` plus its log/pid in here. pub state_dir: String, /// Absolute path to the swtpm control socket (`--ctrl`). CH never /// connects to this one - the daemon uses it for shutdown/flush. @@ -72,7 +72,7 @@ pub struct SwtpmArgvInput { /// `--log level=` value. swtpm accepts 1..20; d2b defaults /// to 20 (debug) during alpha and clamps in the daemon caller. pub log_level: u8, - /// `--pid file=` value; usually `/swtpm. pid`. + /// `--pid file=` value; usually `/swtpm.pid`. pub pid_path: String, /// `--flags startup-clear` is emitted when this is `true`. On /// startup the supervisor runs `swtpm_ioctl -i` first, so the @@ -299,7 +299,7 @@ mod tests { /// Byte-parity oracle for the long-lived swtpm argv. /// - /// The golden file `tests/golden/runner-shape/swtpm-argv-minimal. txt` + /// The golden file `tests/golden/runner-shape/swtpm-argv-minimal.txt` /// contains a leading comment block (lines starting with `#`) /// followed by the argv vector joined by `'\n'`, one argument per /// line. This test strips the comment block and asserts byte-parity diff --git a/packages/d2b-provider-device-usbip/src/driver.rs b/packages/d2b-provider-device-usbip/src/driver.rs index 2c53f4e15..0204ea2ba 100644 --- a/packages/d2b-provider-device-usbip/src/driver.rs +++ b/packages/d2b-provider-device-usbip/src/driver.rs @@ -2,7 +2,7 @@ //! conversion of the daemon-owned USBIP Provider path. //! //! The family serves the two converted USB ResourceTypes the Provider owns - -//! `usb. d2bus. org.UsbService` and `usb. d2bus. org.UsbBinding` - and their +//! `usb.d2bus.org.UsbService` and `usb.d2bus.org.UsbBinding` - and their //! `Device` rows belong to the `d2b-provider-device` family, which owns the //! `Device` ResourceType. The scope here is the crate's own declaration: the //! rows below name the components this crate serves, and the typed effect @@ -63,9 +63,9 @@ pub const USBIP_RESYNC: Duration = Duration::from_secs(30); /// ResourceTypes it owns. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UsbipComponent { - /// The USB authority Service (`usb. d2bus. org.UsbService`). + /// The USB authority Service (`usb.d2bus.org.UsbService`). Service, - /// The per-Guest USB Binding (`usb. d2bus. org.UsbBinding`). + /// The per-Guest USB Binding (`usb.d2bus.org.UsbBinding`). Binding, } diff --git a/packages/d2b-provider-device-usbip/src/state_machine.rs b/packages/d2b-provider-device-usbip/src/state_machine.rs index e59dc12a5..9f3f081a5 100644 --- a/packages/d2b-provider-device-usbip/src/state_machine.rs +++ b/packages/d2b-provider-device-usbip/src/state_machine.rs @@ -327,7 +327,7 @@ pub fn build_usbip_plan( /// /// The daemon MUST have already checked, before calling this: /// 1. the busid is present in `/sys/bus/usb/devices//` (sysfs check), -/// 2. the target VM has `runtime. capabilities. usbHotplug = true` (USB-capable gate), +/// 2. the target VM has `runtime.capabilities.usbHotplug = true` (USB-capable gate), /// 3. the per-busid OFD lock at `/run/d2b/locks/usbip/` is NOT held by /// another VM (active-claim exclusivity). /// @@ -682,7 +682,7 @@ mod tests { /// Per-step failure surfaces as a typed error tagged with the /// exact step. Execution halts immediately (no later steps run) - /// and prior steps stay in `report. completed` so the stop-path + /// and prior steps stay in `report.completed` so the stop-path /// reconciler can undo them. #[test] fn each_step_failure_surfaces_typed_error() { diff --git a/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs b/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs index b84e51659..04551c221 100644 --- a/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs +++ b/packages/d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs @@ -53,7 +53,7 @@ struct Args { #[arg(long)] connect: Option, - /// Canonical workload target, e. g. `tools. host. d2b`. + /// Canonical workload target, e.g. `tools.host.d2b`. #[arg(long, value_name = "TARGET")] target: Option, @@ -764,7 +764,7 @@ fn accept_poll_timeout_ms( .min(i32::MAX as u128) as i32 } -/// Renders an error together with its full `source()` chain on one line, e. g. +/// Renders an error together with its full `source()` chain on one line, e.g. /// `could not dispatch server events: receiver object 4278190081 does not exist`. /// `thiserror`'s `Display` only prints the top-level message, so without walking /// the chain the `#[source]` detail that pinpoints the failing message is lost. diff --git a/packages/d2b-provider-display-wayland/src/controller.rs b/packages/d2b-provider-display-wayland/src/controller.rs index e4b374222..1ee2ed899 100644 --- a/packages/d2b-provider-display-wayland/src/controller.rs +++ b/packages/d2b-provider-display-wayland/src/controller.rs @@ -243,7 +243,7 @@ pub struct WaylandSessionStatus { pub resource: WaylandSessionResourceStatus, } -/// Bounded `WaylandSession. status. resource` projection. +/// Bounded `WaylandSession.status.resource` projection. #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct WaylandSessionResourceStatus { /// Stable Host proxy Process reference. diff --git a/packages/d2b-provider-display-wayland/src/session_children.rs b/packages/d2b-provider-display-wayland/src/session_children.rs index 9060da466..d09ff3022 100644 --- a/packages/d2b-provider-display-wayland/src/session_children.rs +++ b/packages/d2b-provider-display-wayland/src/session_children.rs @@ -323,7 +323,7 @@ fn durable_display_suffix(session_uid: &ResourceUid, role: DisplayProcessRole) - suffix } -/// The `status. resource` projection for one display session: the two worker +/// The `status.resource` projection for one display session: the two worker /// Process references and the private Endpoint with its committed /// generation. pub fn wayland_session_resource_projection( diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs index 7daa0238f..fe6ec31b0 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs @@ -371,7 +371,7 @@ impl VirtualClipboardState { .and_then(|vs| vs.borrow().source.upgrade()); self.selection = source.and_then(|source| self.sources.get(&source.unique_id()).cloned()); // Return the old source only when it is being superseded by a different source - // (or cleared), so the caller can send wl_data_source. cancelled. + // (or cleared), so the caller can send wl_data_source.cancelled. old_strong.filter(|old| source.is_none_or(|new| old.unique_id() != new.unique_id())) } diff --git a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs index 464c0bab7..c4e0ec9b5 100644 --- a/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs +++ b/packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs @@ -137,10 +137,10 @@ impl PolicyWarning { pub struct PolicyInput { /// Typed canonical workload identity. pub identity: ProxyIdentity, - /// Prefix prepended to `xdg_toplevel. set_app_id` values. + /// Prefix prepended to `xdg_toplevel.set_app_id` values. /// Default: the identity's provider-specific prefix. pub app_id_prefix: Option, - /// Prefix prepended to `xdg_toplevel. set_title` values. + /// Prefix prepended to `xdg_toplevel.set_title` values. /// Default: the identity's provider-specific prefix. pub title_prefix: Option, /// Additional explicit deny rules (appended after defaults). diff --git a/packages/d2b-provider-endpoint/src/driver.rs b/packages/d2b-provider-endpoint/src/driver.rs index 378fc8bf4..53d610085 100644 --- a/packages/d2b-provider-endpoint/src/driver.rs +++ b/packages/d2b-provider-endpoint/src/driver.rs @@ -32,7 +32,7 @@ //! - `observe` -> [`ResourceDriver::recover`]. //! - socket realization -> [`ResourceDriver::reconcile`]. //! - socket removal -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx. set_status` (in-memory only). +//! - `UpdateStatus` -> `ctx.set_status` (in-memory only). //! //! Which purposes a declaring provider commits, and on which producer, is //! this crate's own derivation ([`crate::effects_service`]): the closed @@ -540,7 +540,7 @@ impl ResourceDriver for EndpointDriver { /// /// Derived from the placement contract: `Endpoint` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so an Endpoint row never -/// carries the canonical `spec. executionRef` and the plane reconciles it on +/// carries the canonical `spec.executionRef` and the plane reconciles it on /// its own Host domain. A realized producer may live in a Guest; the effects /// reach that row through the manager, not through this row's placement. const ENDPOINT_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -563,7 +563,7 @@ const ENDPOINT_READS: &[WellKnownType] = &[ /// `Endpoint` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve /// the converted endpoint shapes without it, so it must be registered before /// the plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus. org.*Service` types, so an endpoint can never be an +/// qualified `*.d2bus.org.*Service` types, so an endpoint can never be an /// export subject. The driver serves no broker operations and creates no /// children through this declaration; the endpoint children the volume /// binding realizes are created by that family. The declaration carries the diff --git a/packages/d2b-provider-guest-qemu-media/src/hotplug.rs b/packages/d2b-provider-guest-qemu-media/src/hotplug.rs index cb02091b3..0cd74a2ce 100644 --- a/packages/d2b-provider-guest-qemu-media/src/hotplug.rs +++ b/packages/d2b-provider-guest-qemu-media/src/hotplug.rs @@ -32,7 +32,7 @@ impl QemuMediaHotplugAction { pub struct QemuMediaHotplugScaffold { /// Opaque media ref the transaction targets. pub media_ref: String, - /// Slot the media occupies (e. g. `boot`). + /// Slot the media occupies (e.g. `boot`). pub slot: String, /// QMP block node name. pub blockdev_id: String, diff --git a/packages/d2b-provider-guest/src/driver.rs b/packages/d2b-provider-guest/src/driver.rs index 2032389cf..990956f58 100644 --- a/packages/d2b-provider-guest/src/driver.rs +++ b/packages/d2b-provider-guest/src/driver.rs @@ -11,7 +11,7 @@ //! F1), owned children the desired set no longer derives are retired in //! the family's preserved order, the typed Provider effect runs behind //! [`GuestDriverEffects`], and the in-memory status projection is -//! published with `ctx. set_status` + `ctx. set_status_projection` (R11) +//! published with `ctx.set_status` + `ctx.set_status_projection` (R11) //! plus a self-`requeue_after` while the family is not converged; //! - [`ResourceDriver::finalize`] and [`ResourceDriver::delete`]: the kind's //! preserved teardown stage (Cloud Hypervisor's controller-owned finalize, @@ -208,12 +208,12 @@ pub enum GuestEffectPhase { } /// One Provider effect outcome: the phase the old effect returned plus the -/// layered `status. resource` projection the Provider published for the row. +/// layered `status.resource` projection the Provider published for the row. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GuestEffectOutcome { /// The phase the Provider effect reported. pub phase: GuestEffectPhase, - /// The layered `status. resource` projection the Provider published. + /// The layered `status.resource` projection the Provider published. pub resource_projection: Option, } @@ -340,12 +340,12 @@ impl std::error::Error for GuestDriverError {} /// Typed in-memory status projection (R11: never persisted). Carries the /// closed phase the old status candidate published plus the Provider's -/// layered `status. resource` projection. +/// layered `status.resource` projection. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GuestDriverStatus { /// The phase this status publishes. pub phase: GuestEffectPhase, - /// The Provider's sticky `status. resource` projection, when one exists. + /// The Provider's sticky `status.resource` projection, when one exists. pub resource: Option, } @@ -541,7 +541,7 @@ pub struct GuestEffectRequest<'a> { /// The Provider row's spec for this Guest's `providerRef`, when the /// manager holds it (the framework kinds read their `/config` here). pub provider_spec: Option, - /// The driver's last published `status. resource` projection, when one + /// The driver's last published `status.resource` projection, when one /// was published: the Provider status is sticky, exactly as the old /// durable row's was. pub status: Option, @@ -681,12 +681,12 @@ const GUEST_CREATIONS: &[ChildCreation] = &[ /// `Guest` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve a /// guest whose provider controller never registered, so the type must be /// present before the plane opens. The type is not exportable: -/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a /// guest can never be an export subject. The driver serves no broker /// operations and contributes no startup step of its own; every child the /// family's drivers and controller sessions create is declared in /// [`GUEST_CREATIONS`]. The family's declared effects service -/// (`guest. d2bus. org/effects`, U10) rides the declaration, so the daemon +/// (`guest.d2bus.org/effects`, U10) rides the declaration, so the daemon /// hosts it through the registered factory over the composition root's /// facet set. pub fn guest_descriptor(args: GuestDriverArgs) -> DriverDescriptor { diff --git a/packages/d2b-provider-guest/src/effects_service.rs b/packages/d2b-provider-guest/src/effects_service.rs index b7ecc4228..95d18724f 100644 --- a/packages/d2b-provider-guest/src/effects_service.rs +++ b/packages/d2b-provider-guest/src/effects_service.rs @@ -25,7 +25,7 @@ //! `activeProcessCount`). That status is the row's actor's to own (R11) and //! there is no durable row to write: the session captures the controller's //! write into the effect call's [`GuestStatusSink`] and the driver publishes -//! it as the row's `status. resource` projection. The provider controller's +//! it as the row's `status.resource` projection. The provider controller's //! finalizer requests are acknowledged without a store write for the same //! reason - the manager's deleting-row hold replaces the old durable //! finalizer (F3). @@ -632,7 +632,7 @@ impl GuestEffectsService { } /// The old-shape document of one resource (`spec`, `metadata`, live - /// `status. phase`) from the manager view, answered as one classified read + /// `status.phase`) from the manager view, answered as one classified read /// (issue #511): `Present` carries the document, `Absent` is the honest /// not-created answer, `Unavailable` is a plane that could not answer, /// and `Error` carries the projection detail of a committed row that diff --git a/packages/d2b-provider-guest/src/shutdown.rs b/packages/d2b-provider-guest/src/shutdown.rs index 0afdab9d1..ad3ea6ec0 100644 --- a/packages/d2b-provider-guest/src/shutdown.rs +++ b/packages/d2b-provider-guest/src/shutdown.rs @@ -204,7 +204,7 @@ mod tests { let _ = tokio::fs::remove_dir_all(dir).await; } - /// Serve one `vm. info` HTTP-over-unix exchange for the given wire state, + /// Serve one `vm.info` HTTP-over-unix exchange for the given wire state, /// and return the socket path the poll reads, plus the serving dir the /// caller removes when the exchange is complete. async fn serve_vm_info(state: &str) -> (PathBuf, PathBuf) { diff --git a/packages/d2b-provider-guest/src/test_support.rs b/packages/d2b-provider-guest/src/test_support.rs index e111087ab..2a2763b85 100644 --- a/packages/d2b-provider-guest/src/test_support.rs +++ b/packages/d2b-provider-guest/src/test_support.rs @@ -56,7 +56,7 @@ pub struct EffectObservation { pub kind: GuestKind, /// The Provider row's spec the driver resolved, when the manager held it. pub provider_spec: Option, - /// The driver's last published `status. resource` projection, when one + /// The driver's last published `status.resource` projection, when one /// was published. pub status: Option, /// The owned child rows the call read, with their live phase. @@ -111,7 +111,7 @@ impl ScriptedEffects { *self.phase.lock().await = phase; } - /// Script the `status. resource` projection the next `reconcile` reports. + /// Script the `status.resource` projection the next `reconcile` reports. pub async fn set_projection(&self, projection: Option) { *self.projection.lock().await = projection; } @@ -331,7 +331,7 @@ pub fn row_fixture( } /// A manager row fixture with explicit metadata (the gateway-custody -/// validation reads the gateway Guest's `metadata. zone`). +/// validation reads the gateway Guest's `metadata.zone`). pub fn row_fixture_with_metadata( zone: &str, type_name: &str, diff --git a/packages/d2b-provider-host/src/driver.rs b/packages/d2b-provider-host/src/driver.rs index 8571a3907..ccb49f640 100644 --- a/packages/d2b-provider-host/src/driver.rs +++ b/packages/d2b-provider-host/src/driver.rs @@ -12,7 +12,7 @@ //! Conversion mapping (spec section 13): //! - `describe` -> [`host_descriptor`] registration under `Host`. //! - `validate_spec` -> [`ResourceDriver::validate`]: typed spec decode plus -//! the `Host. spec. providerRef` fence (`Provider/system-core` is the only +//! the `Host.spec.providerRef` fence (`Provider/system-core` is the only //! Provider the Host contract admits). //! - `plan` -> the preserved `observedGeneration` short-circuit: a status //! observed at the current generation skips re-observing (the old @@ -23,10 +23,10 @@ //! over the [`HostDriverEffects`] probe port. //! - `finalize` -> [`ResourceDriver::delete`] (old `FinalizeResult` was //! converged: the family owns no children and carries no finalizer). -//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). //! //! Deliberately not carried from the old handler: the durable -//! `status. resource` JSON projection and its `lastReconciledAt` / +//! `status.resource` JSON projection and its `lastReconciledAt` / //! `observedGeneration` writes (status is runtime-only now, R11), and the //! `assess_update` / `plan_upgrade` runner path (no driver equivalent; the //! family never planned an upgrade). The old runner's 5s resync relisted and @@ -42,7 +42,7 @@ //! ([`crate::effects_service::HostEffectsService`]) built from the //! daemon-supplied facet set - the construction site holds no externally //! built port (R2) - and the family's declared effects service -//! (`host. d2bus. org/effects`) rides the declaration, so a zone that cannot +//! (`host.d2bus.org/effects`) rides the declaration, so a zone that cannot //! host it refuses startup by name (R5). //! //! KTD13: the driver has no spawn surface at all. It observes the local host @@ -137,7 +137,7 @@ impl std::error::Error for HostDriverError {} /// Typed in-memory status projection (R11: never persisted). /// /// The observation is kept with the generation it was taken at, which is the -/// runtime-only successor of the old durable `status. observedGeneration` +/// runtime-only successor of the old durable `status.observedGeneration` /// plan short-circuit. #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct HostDriverStatus { @@ -301,7 +301,7 @@ impl HostDriver { .map_err(|_| self.error(HostDriverErrorKind::SpecInvalid, op)) } - /// The declared `spec. providerRef` fence plus the typed Host base spec. + /// The declared `spec.providerRef` fence plus the typed Host base spec. fn host_spec( &self, ctx: &ResourceContext, @@ -457,7 +457,7 @@ impl ResourceDriver for HostDriver { /// /// Derived from the placement contract: `Host` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so a Host row never -/// carries the canonical `spec. executionRef` and the plane reconciles it on +/// carries the canonical `spec.executionRef` and the plane reconciles it on /// its own Host domain - which is the row's own subject. const HOST_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -466,7 +466,7 @@ const HOST_EXECUTION_DOMAINS: &[&str] = &["host"]; /// `Host` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve the /// converted bootstrap rows without it, so it must be registered before the /// plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus. org.*Service` types. The driver serves no broker +/// qualified `*.d2bus.org.*Service` types. The driver serves no broker /// operations, creates no children, and reads no other resource: the /// observation reaches the local machine through the family's own probe. /// diff --git a/packages/d2b-provider-host/src/test_support.rs b/packages/d2b-provider-host/src/test_support.rs index c88909663..d23ab8505 100644 --- a/packages/d2b-provider-host/src/test_support.rs +++ b/packages/d2b-provider-host/src/test_support.rs @@ -109,7 +109,7 @@ struct RecordingProbeCore { impl RecordingProbe { /// Construct the double over one scripted capability set, the default - /// Ready gate (6.9 with cgroup. kill), and the default bounded metadata. + /// Ready gate (6.9 with cgroup.kill), and the default bounded metadata. pub fn new(capabilities: Vec) -> Arc { Arc::new(Self { core: Arc::new(RecordingProbeCore { diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index c8cb173f6..de960790e 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -19,7 +19,7 @@ //! [`ResourceDriver::reconcile`]: the desired child set is ensured through //! the manager child API (committed before the child actor exists, F1), the //! typed Provider effect runs behind the port, and the in-memory status -//! projection is published with `ctx. set_status` (R11) plus a self-requeue +//! projection is published with `ctx.set_status` (R11) plus a self-requeue //! while the family is not converged. //! - `prepare_finalize`/`execute_finalize`/`finalize` -> //! [`ResourceDriver::delete`]: the family's staged fabric finalizer runs @@ -241,7 +241,7 @@ const NETWORK_READS: &[WellKnownType] = &[ /// `Network` is `BUILTIN | STARTUP` (no RUNTIME bit): zone networking is /// referenced by every Guest-bearing zone, so the plane must have the driver /// registered before it opens. The type is not exportable: `ResourceExport` -/// admits only qualified `*.d2bus. org.*Service` types, so a network can never +/// admits only qualified `*.d2bus.org.*Service` types, so a network can never /// be an export subject. The driver declares the thirteen network-fds family /// operations (U12): the broker-generic kernels serve each operation's /// privileged core in-broker, while the family operation itself stays diff --git a/packages/d2b-provider-notification-desktop/src/metrics.rs b/packages/d2b-provider-notification-desktop/src/metrics.rs index 2cd3e6044..471227308 100644 --- a/packages/d2b-provider-notification-desktop/src/metrics.rs +++ b/packages/d2b-provider-notification-desktop/src/metrics.rs @@ -180,7 +180,7 @@ mod tests { } /// The collector-field injection fence: duplicate keys, newline or - /// oversized values, `d2b. provider` spoofing, and out-of-vocabulary + /// oversized values, `d2b.provider` spoofing, and out-of-vocabulary /// categories are all rejected. #[test] fn collector_field_validation_rejects_injection_and_spoofing() { diff --git a/packages/d2b-provider-process-minijail/src/launch.rs b/packages/d2b-provider-process-minijail/src/launch.rs index ba19de0a6..1c419a6ed 100644 --- a/packages/d2b-provider-process-minijail/src/launch.rs +++ b/packages/d2b-provider-process-minijail/src/launch.rs @@ -9,7 +9,7 @@ pub struct PlatformGate { pub kernel_major: u16, /// Kernel minor. pub kernel_minor: u16, - /// Whether the runtime cgroup exposes cgroup. kill. + /// Whether the runtime cgroup exposes cgroup.kill. pub cgroup_kill_available: bool, } @@ -27,12 +27,12 @@ impl PlatformGate { } } - /// Check Linux 5.14 and cgroup. kill. + /// Check Linux 5.14 and cgroup.kill. /// /// # Errors /// /// Returns `PlatformGateRejected` when the kernel is older than - /// 5.14 or the runtime cgroup does not expose `cgroup. kill`. + /// 5.14 or the runtime cgroup does not expose `cgroup.kill`. pub const fn validate(self) -> Result<(), ProcessConformanceError> { if self.kernel_major < 5 || (self.kernel_major == 5 && self.kernel_minor < 14) diff --git a/packages/d2b-provider-process-systemd/src/operations.rs b/packages/d2b-provider-process-systemd/src/operations.rs index 3a8878928..0b8ee3a39 100644 --- a/packages/d2b-provider-process-systemd/src/operations.rs +++ b/packages/d2b-provider-process-systemd/src/operations.rs @@ -118,11 +118,11 @@ const SERVICE_INTERFACE: &str = "org.freedesktop.systemd1.Service"; /// The systemd object interface a unit-identity property is defined on. /// -/// `ControlGroup` and `MainPID` are defined on `org. freedesktop. systemd1.Service` +/// `ControlGroup` and `MainPID` are defined on `org.freedesktop.systemd1.Service` /// (the family's transient service units), not on `Unit`; reading them through /// the Unit proxy fails every read with `UnknownProperty` and the identity can /// never bind (issue #587). `ActiveState` and `InvocationID` are defined on -/// `org. freedesktop. systemd1.Unit`. `read_identity` routes every property read +/// `org.freedesktop.systemd1.Unit`. `read_identity` routes every property read /// through this selection. fn identity_property_interface(property: &str) -> &'static str { match property { @@ -464,7 +464,7 @@ async fn unit_proxy<'a>(manager: &Proxy<'a>, name: &str) -> Result`). +/// declared Guest owner (`Device.metadata.ownerRef == Guest/`). /// /// A Device-owned worker row runs on the Host (`executionRef /// Host/host-system`) and names no Guest target, so the row's own launch @@ -382,12 +382,12 @@ pub fn resource_uid_from_bytes(bytes: &[u8; 16]) -> Option { /// KTD7 Guest-owner identity source: the owning `Guest` row's durable uid for /// one canonical Guest reference. `Guest` has not been converted, so a /// converted Process row owned by a Guest cannot carry the durable owner -/// linkage the pre-v3 store computed (`record. owner_uid` = the resolved owner +/// linkage the pre-v3 store computed (`record.owner_uid` = the resolved owner /// row's uid) - the manager row carries only the authored -/// `metadata. ownerRef`. The old descriptor composer read the linkage first +/// `metadata.ownerRef`. The old descriptor composer read the linkage first /// and the owner identity cache second; a reference this source cannot /// resolve stays unbound, so the Cloud Hypervisor launch stays refused closed -/// (the broker requires the owner uid to bind `d2b. guest_uid=`). +/// (the broker requires the owner uid to bind `d2b.guest_uid=`). /// /// Trait, not a concrete type, because `d2b-provider-process` consumes it /// (`resolve_guest_owner_uid`) and cannot depend on `d2bd`, where the @@ -604,14 +604,14 @@ pub(crate) const PROCESS_FAMILY_READS: &[WellKnownType] = &[ /// `Process` and `EphemeralProcess` are `BUILTIN | STARTUP` (no RUNTIME bit): /// the plane cannot admit workloads without a process launcher, so both must /// be registered before the plane opens. Neither member type is exportable: -/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a /// process can never be an export subject. /// /// The family's declared operations and services ride on the `Process` /// descriptor alone: the registry gives one operation reference exactly one /// owning type (a second declaring driver is refused as foreign), the /// declaration inspection is a family operation, not a per-member one, and -/// the family's effects service (`process. d2bus. org/effects`, U1) is a +/// the family's effects service (`process.d2bus.org/effects`, U1) is a /// family surface its member types share. The family creates no children /// through this declaration today. pub fn process_family_descriptors(args: ProcessDriverArgs) -> [DriverDescriptor; 2] { @@ -1887,7 +1887,7 @@ impl ProcessDriver { Err(self.identity_ambiguous(DriverOp::Delete, &report)) } // A row no host-minted ticket can describe (a Guest-owned one-shot - // outside the guest VMM chain, e. g. the projected + // outside the guest VMM chain, e.g. the projected // `store-preflight-` intent) has no identity this daemon // could ever have realized, so its deletion converges with no // provider effect. The guard's real intent is preserved: nothing @@ -1940,7 +1940,7 @@ fn provider_error_kind(error: &str) -> ProcessDriverErrorKind { ProcessDriverErrorKind::ResolutionRefused } else if error.contains("guest-process-not-vmm") { // The trusted bundle holds no host-minted intent for this row at all - // (a Guest-owned one-shot outside the guest VMM chain, e. g. a + // (a Guest-owned one-shot outside the guest VMM chain, e.g. a // projected preflight intent): no retry can ever mint a ticket, so // the refusal is terminal - never an ambiguous identity to quarantine // (R15 is about observed identity). @@ -2785,7 +2785,7 @@ mod tests { /// A Device-owned worker row names no VM of its own (`executionRef /// Host/host-system`, no Guest target), so the Process controller derives /// the worker's VM scope from the owning Device's declared Guest owner - - /// the same `Device. metadata. ownerRef == Guest/` derivation the TPM + /// the same `Device.metadata.ownerRef == Guest/` derivation the TPM /// admission fence requires and the TPM shared-provider effects mint /// their `VmId` from. A Device with no Guest owner is the genuinely /// unresolvable case and refuses by name; absence and an unanswerable @@ -2934,7 +2934,7 @@ mod tests { /// The Guest-owner resolution reads the pre-v3 plane only for a Guest /// owner whose row carries no linked uid; a linked uid always wins (the - /// old composer's precedence: `record. resource. owner_uid` first, the + /// old composer's precedence: `record.resource.owner_uid` first, the /// owner identity cache second), and a non-Guest owner never reaches the /// Guest plane. Without a wired source the slot stays unbound, so the /// launch still refuses closed. diff --git a/packages/d2b-provider-process/src/launch_identity.rs b/packages/d2b-provider-process/src/launch_identity.rs index 7b4a23f95..88b43e6ce 100644 --- a/packages/d2b-provider-process/src/launch_identity.rs +++ b/packages/d2b-provider-process/src/launch_identity.rs @@ -24,7 +24,7 @@ const GUEST_RUNTIME_PROCESS_TEMPLATES: &[(&str, &str)] = &[ /// the identity on its own. pub struct LaunchRow<'a> { /// The row's semantic owner (manager owner key, or the authored - /// `metadata. ownerRef` for an owner the manager does not hold). + /// `metadata.ownerRef` for an owner the manager does not hold). pub owner_ref: Option<&'a ResourceRef>, /// The durable owner linkage the row persists. pub owner_uid: Option, diff --git a/packages/d2b-provider-process/src/operations.rs b/packages/d2b-provider-process/src/operations.rs index eab9bdfc3..80eb1fa5d 100644 --- a/packages/d2b-provider-process/src/operations.rs +++ b/packages/d2b-provider-process/src/operations.rs @@ -1563,7 +1563,7 @@ fn zone_bundle_for_uid<'a>( Some((zone.as_str().to_owned(), bytes)) } -/// The authored `metadata. ownerRef` of one row of a verified Zone resource +/// The authored `metadata.ownerRef` of one row of a verified Zone resource /// bundle, parsed into a canonical reference. fn row_owner_ref(bundle_bytes: &[u8], resource_type: &str, name: &str) -> Option { let bundle: serde_json::Value = serde_json::from_slice(bundle_bytes).ok()?; @@ -1619,7 +1619,7 @@ fn binds_runtime_socket(role: &ProcessRole) -> bool { /// Pin the Device scope of one Device-owned worker launch. /// /// The launched row is resolved from the verified Zone resource bundle the -/// request's `zone_uid` names (`Process. metadata. ownerRef`), that owner must +/// request's `zone_uid` names (`Process.metadata.ownerRef`), that owner must /// be a `Device`, `owner_ref` must be exactly it, and `owner_uid` must be /// that Device row's durable uid. Only then is the Device's declared Guest /// read. Every refusal is fail-closed (the retired broker arm's diff --git a/packages/d2b-provider-provider/src/driver.rs b/packages/d2b-provider-provider/src/driver.rs index 13c922a38..75ecb0ac4 100644 --- a/packages/d2b-provider-provider/src/driver.rs +++ b/packages/d2b-provider-provider/src/driver.rs @@ -96,7 +96,7 @@ const PROVIDER_CONVERGENCE_POLL: Duration = Duration::from_millis(1_000); /// /// Derived from the placement contract: `Provider` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so a Provider row never -/// carries the canonical `spec. executionRef` and the plane reconciles it on +/// carries the canonical `spec.executionRef` and the plane reconciles it on /// its own Host domain. const PROVIDER_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -120,8 +120,8 @@ const PROVIDER_READS: &[WellKnownType] = &[ /// Typed in-memory status projection (R11: never persisted). /// /// The old plane persisted `phase`, `observedGeneration`, the -/// `status. resource. providerReadiness` projection, and the store-derived -/// `status. resource. owned. refs` list. Nothing durable replaces them: the +/// `status.resource.providerReadiness` projection, and the store-derived +/// `status.resource.owned.refs` list. Nothing durable replaces them: the /// generation the old `Enable`/`Update` short-circuit read and the projected /// phase are kept here, the readiness fields stay on the typed /// [`ProviderObservation`], and the last observed owned `Volume` references @@ -131,7 +131,7 @@ const PROVIDER_READS: &[WellKnownType] = &[ #[derive(Debug, Clone, PartialEq, Eq)] pub struct ProviderDriverStatus { /// The desired generation this observation was taken at (the old - /// `status. observedGeneration`). + /// `status.observedGeneration`). pub observed_generation: u64, /// The phase the pure policy projected. pub phase: ProviderPhase, @@ -149,7 +149,7 @@ pub struct ProviderDriverStatus { /// The live evidence the `Provider` observation needs and the manager cannot /// serve: a converted row's status is in-memory only (R11), so the manager's /// view carries the closed [`ResourceStatus`] and never the controller-session -/// evidence the pure core reads as `status. resource. controllerSession`. The +/// evidence the pure core reads as `status.resource.controllerSession`. The /// production implementation is the daemon's live-session seam; every unknown /// fails closed (`None`), so no caller can synthesize an admitted session. pub trait ProviderDriverEffects: Send + Sync + 'static { @@ -348,7 +348,7 @@ impl ProviderDriver { .dependencies(ctx, &provider_ref, &provider_uid, generation) .await?; - // The old `status. observedGeneration` short-circuit selected the + // The old `status.observedGeneration` short-circuit selected the // `Enable` intent; the in-memory status is its runtime-only successor. let previous = ctx.status::(); let intent = match previous { @@ -361,7 +361,7 @@ impl ProviderDriver { // The provider row as the pure observation reads it: spec from the // stored envelope, metadata as authored, and the previous // observation's owned Volume references standing in for the durable - // `status. resource. owned. refs` projection the store used to derive. + // `status.resource.owned.refs` projection the store used to derive. let metadata: Value = serde_json::from_slice(ctx.metadata()) .map_err(|_| spec_invalid(DriverOp::Reconcile, "spec/metadata"))?; let status = match previous { @@ -524,7 +524,7 @@ impl ProviderDriver { // The manager's ownership is authoritative (R8): a row listed as this // Provider's child carries the Provider reference in the synthesized // payload, because the pure core reads ownership from - // `metadata. ownerRef`, not from the manager. + // `metadata.ownerRef`, not from the manager. metadata.as_object_mut()?.insert( "ownerRef".to_owned(), Value::String(provider_ref.to_owned()), @@ -677,7 +677,7 @@ fn resource_uid(bytes: &[u8; 16]) -> Option { /// through this declaration. /// /// The type is not exportable: `ResourceExport` admits only qualified -/// `*.d2bus. org.*Service` types, so a Provider row is never an export subject. +/// `*.d2bus.org.*Service` types, so a Provider row is never an export subject. pub fn provider_descriptor(args: ProviderDriverArgs) -> DriverDescriptor { DriverDescriptor { resource_type: WellKnownType::PROVIDER, diff --git a/packages/d2b-provider-role/src/rbac.rs b/packages/d2b-provider-role/src/rbac.rs index 6ce658b06..5ad2eff54 100644 --- a/packages/d2b-provider-role/src/rbac.rs +++ b/packages/d2b-provider-role/src/rbac.rs @@ -87,7 +87,7 @@ impl core::fmt::Debug for PositiveDecisionCache { } impl PositiveDecisionCache { - /// Construct a bounded positive-only cache. max_entries = 0 + /// Construct a bounded positive-only cache.max_entries = 0 /// disables caching entirely. pub fn new(max_entries: usize) -> Self { Self { diff --git a/packages/d2b-provider-shell-terminal/src/resources/pool.rs b/packages/d2b-provider-shell-terminal/src/resources/pool.rs index e98eaad34..267317c14 100644 --- a/packages/d2b-provider-shell-terminal/src/resources/pool.rs +++ b/packages/d2b-provider-shell-terminal/src/resources/pool.rs @@ -1,4 +1,4 @@ -//! `shell-terminal. d2bus. org.ShellPool` schema. +//! `shell-terminal.d2bus.org.ShellPool` schema. use super::{ShellTerminalError, validate_name}; diff --git a/packages/d2b-provider-shell-terminal/src/resources/session.rs b/packages/d2b-provider-shell-terminal/src/resources/session.rs index c7f6c1811..9b709a4ee 100644 --- a/packages/d2b-provider-shell-terminal/src/resources/session.rs +++ b/packages/d2b-provider-shell-terminal/src/resources/session.rs @@ -1,4 +1,4 @@ -//! `shell-terminal. d2bus. org.ShellSession` schema. +//! `shell-terminal.d2bus.org.ShellSession` schema. use super::{ShellPool, ShellTerminalError, validate_name}; use crate::resources::ExecutionTarget; diff --git a/packages/d2b-provider-system-core/src/error.rs b/packages/d2b-provider-system-core/src/error.rs index 17eea0eac..ad3370263 100644 --- a/packages/d2b-provider-system-core/src/error.rs +++ b/packages/d2b-provider-system-core/src/error.rs @@ -28,7 +28,7 @@ pub enum SystemCoreError { CapabilityMissing, /// The kernel is below the mandatory system-minijail floor. KernelTooOld, - /// The delegated cgroup leaf has no writable cgroup. kill. + /// The delegated cgroup leaf has no writable cgroup.kill. CgroupKillUnavailable, } diff --git a/packages/d2b-provider-system-core/src/host.rs b/packages/d2b-provider-system-core/src/host.rs index 834c415f2..bae66801d 100644 --- a/packages/d2b-provider-system-core/src/host.rs +++ b/packages/d2b-provider-system-core/src/host.rs @@ -100,7 +100,7 @@ pub struct MinijailPlatformGate { pub kernel_major: u16, /// Minor Linux kernel version observed by the probe. pub kernel_minor: u16, - /// Whether the runtime cgroup exposes cgroup. kill. + /// Whether the runtime cgroup exposes cgroup.kill. pub cgroup_kill_available: bool, } @@ -125,7 +125,7 @@ impl MinijailPlatformGate { /// /// Returns [`SystemCoreError::KernelTooOld`] when the kernel is below the /// mandatory floor and [`SystemCoreError::CgroupKillUnavailable`] when - /// the delegated cgroup leaf has no writable `cgroup. kill`. + /// the delegated cgroup leaf has no writable `cgroup.kill`. pub fn validate(self) -> Result<(), SystemCoreError> { if !self.kernel_supported() { return Err(SystemCoreError::KernelTooOld); @@ -320,7 +320,7 @@ impl HostReconciler { /// Reconcile one Host resource into its public status. /// - /// `provider_ref` is the resource's declared `spec. providerRef`. A Host + /// `provider_ref` is the resource's declared `spec.providerRef`. A Host /// naming another Provider is refused rather than reconciled, because /// `Provider/system-core` is the only Provider the Host contract admits /// and reconciling a foreign Host would be exactly the bootstrap diff --git a/packages/d2b-provider-system-core/src/lib.rs b/packages/d2b-provider-system-core/src/lib.rs index 7478b1a07..3a28a66d5 100644 --- a/packages/d2b-provider-system-core/src/lib.rs +++ b/packages/d2b-provider-system-core/src/lib.rs @@ -58,7 +58,7 @@ pub const PROVIDER_NAME: &str = "system-core"; /// The canonical `Provider/system-core` reference. /// -/// This is the only value admitted by `Host. spec. providerRef`, and it is +/// This is the only value admitted by `Host.spec.providerRef`, and it is /// the same constant the Host primitive contract pins. pub const PROVIDER_REF: &str = d2b_contracts_resource::v3::host::HOST_PROVIDER_REF; diff --git a/packages/d2b-provider-system-core/src/testing.rs b/packages/d2b-provider-system-core/src/testing.rs index fb6e58191..544cf84df 100644 --- a/packages/d2b-provider-system-core/src/testing.rs +++ b/packages/d2b-provider-system-core/src/testing.rs @@ -130,8 +130,8 @@ pub mod fixtures { /// /// It is deliberately different from the `User/alice` resource name, so /// a redaction assertion can tell the two apart. The split is the one - /// the User primitive contract describes: `metadata. name` is the - /// Zone-local key and `spec. osUsername` is what NSS resolves. + /// the User primitive contract describes: `metadata.name` is the + /// Zone-local key and `spec.osUsername` is what NSS resolves. pub const OS_USERNAME: &str = "alice_admin"; /// A User spec declaring no additional groups. diff --git a/packages/d2b-provider-telemetry-binding/src/driver.rs b/packages/d2b-provider-telemetry-binding/src/driver.rs index c56c649ea..49268e894 100644 --- a/packages/d2b-provider-telemetry-binding/src/driver.rs +++ b/packages/d2b-provider-telemetry-binding/src/driver.rs @@ -9,7 +9,7 @@ //! section 13 mapping): //! //! - `describe` -> [`TelemetryBindingDriverFactory`], registered for -//! `telemetry. d2bus. org.TelemetryBinding` in the plane's provider directory. +//! `telemetry.d2bus.org.TelemetryBinding` in the plane's provider directory. //! - `validate_spec` -> [`ResourceDriver::validate`]: the stored spec envelope //! must decode. A malformed Service/target relationship is fenced in //! reconcile (old `telemetry_binding_owner`), never fatal here. @@ -24,7 +24,7 @@ //! writes). //! - `prepare_finalize` + `execute_finalize` + `finalize` -> //! [`ResourceDriver::delete`]. The old -//! `d2b. d2bus. org/binding-children` finalizer is gone by construction: the +//! `d2b.d2bus.org/binding-children` finalizer is gone by construction: the //! v3 manager already holds a parent row until its owned children retire //! (`ResourceManagerState::remove_internal` cascades the removal to owned //! children and `pending_retirement` keeps the parent's durable deleting @@ -610,7 +610,7 @@ fn teardown_rank(resource_type: &str) -> u8 { /// /// Derived from the placement contract: `TelemetryBinding` names no placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a Binding row -/// never carries the canonical `spec. executionRef` and the plane reconciles it +/// never carries the canonical `spec.executionRef` and the plane reconciles it /// on its own Host domain. The Provider declares every child host-placed, so /// the declared set is realized from that same domain. const TELEMETRY_BINDING_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -633,7 +633,7 @@ const TELEMETRY_BINDING_READS: &[WellKnownType] = &[ /// `TelemetryBinding` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane /// cannot serve the Zone's telemetry producers without it, so it must be /// registered before the plane opens. The type is not exportable: -/// `ResourceExport` admits only qualified `*.d2bus. org.*Service` types, so a +/// `ResourceExport` admits only qualified `*.d2bus.org.*Service` types, so a /// binding can never be an export subject. The driver serves no broker /// operations and declares the two child creations it performs - the /// collector/forwarder Process and its Endpoint. diff --git a/packages/d2b-provider-telemetry-binding/src/lib.rs b/packages/d2b-provider-telemetry-binding/src/lib.rs index 258dca3e6..c44ef7a94 100644 --- a/packages/d2b-provider-telemetry-binding/src/lib.rs +++ b/packages/d2b-provider-telemetry-binding/src/lib.rs @@ -1,7 +1,7 @@ //! The TelemetryBinding resource type's driver, its spec decoder, and its //! driver declaration. //! -//! The crate owns the `telemetry. d2bus. org.TelemetryBinding` type's complete +//! The crate owns the `telemetry.d2bus.org.TelemetryBinding` type's complete //! resource knowledge: the relationship admission (the owner must name the //! telemetry Provider and its Service/target rows must exist and not be //! deleting), the provider-declared child set materialized as owned manager diff --git a/packages/d2b-provider-telemetry-service/src/driver.rs b/packages/d2b-provider-telemetry-service/src/driver.rs index 7d3a88fd0..476ab59a2 100644 --- a/packages/d2b-provider-telemetry-service/src/driver.rs +++ b/packages/d2b-provider-telemetry-service/src/driver.rs @@ -7,7 +7,7 @@ //! `TelemetryResourceReconciler`'s Service half (spec section 13 mapping): //! //! - `describe` -> [`TelemetryServiceDriverFactory`], registered for -//! `telemetry. d2bus. org.TelemetryService` in the plane's provider directory. +//! `telemetry.d2bus.org.TelemetryService` in the plane's provider directory. //! - `validate_spec` -> [`ResourceDriver::validate`]: the stored spec envelope //! must decode. //! - `observe` -> [`ResourceDriver::recover`]: a Service realizes nothing on a @@ -19,7 +19,7 @@ //! route that is not materialized yet re-schedules the preserved resync. //! - `prepare_finalize` + `execute_finalize` + `finalize` -> //! [`ResourceDriver::delete`]. The old -//! `d2b. d2bus. org/binding-children` finalizer is gone by construction: the +//! `d2b.d2bus.org/binding-children` finalizer is gone by construction: the //! v3 manager already holds a parent row until its owned children retire, //! and a Service owns none. @@ -60,7 +60,7 @@ pub const PHASE_DEGRADED: &str = "Degraded"; /// The readiness term of the preserved phase predicate. /// /// CONTRACT FLAG: the term reads a dependency's observed status (an ingest -/// Endpoint's `status. phase`), which the KTD3 driver surface does not expose. +/// Endpoint's `status.phase`), which the KTD3 driver surface does not expose. /// It evaluates fail-closed until the surface carries observed state, so /// `Ready` is never claimed without evidence. pub const DEPENDENCY_READINESS_PROVEN: bool = false; @@ -458,7 +458,7 @@ fn ingest_endpoint_refs( /// /// Derived from the placement contract: `TelemetryService` names no placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a Service row -/// never carries the canonical `spec. executionRef` and the plane reconciles it +/// never carries the canonical `spec.executionRef` and the plane reconciles it /// on its own Host domain. const TELEMETRY_SERVICE_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -473,7 +473,7 @@ const TELEMETRY_SERVICE_READS: &[WellKnownType] = &[WellKnownType::ENDPOINT]; /// `TelemetryService` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane /// cannot serve the Zone's telemetry authority without it, so it must be /// registered before the plane opens. The type is exportable: the qualified -/// `telemetry. d2bus. org.TelemetryService` is exactly the shape +/// `telemetry.d2bus.org.TelemetryService` is exactly the shape /// `ResourceExport` admits. The driver serves no broker operations and owns /// no child, so it declares no creation. pub fn telemetry_service_descriptor() -> DriverDescriptor { @@ -687,7 +687,7 @@ mod tests { assert_eq!(status.present_endpoints.len(), 1); assert_eq!(status.projection.as_ref().unwrap().service_role, "authority"); // CONTRACT FLAG: the old predicate also required the ingest - // Endpoint's own `status. phase == "Ready"`, which this surface cannot + // Endpoint's own `status.phase == "Ready"`, which this surface cannot // read; the phase stays fail-closed Pending while the row exists. assert_eq!(status.phase, TelemetryServicePhase::Pending); assert_eq!( diff --git a/packages/d2b-provider-telemetry-service/src/lib.rs b/packages/d2b-provider-telemetry-service/src/lib.rs index 1a5997888..1c69dfcaf 100644 --- a/packages/d2b-provider-telemetry-service/src/lib.rs +++ b/packages/d2b-provider-telemetry-service/src/lib.rs @@ -1,7 +1,7 @@ //! The TelemetryService resource type's driver, its spec decoder, and its //! driver declaration. //! -//! The crate owns the `telemetry. d2bus. org.TelemetryService` type's complete +//! The crate owns the `telemetry.d2bus.org.TelemetryService` type's complete //! resource knowledge: the observed-phase projection the old reconciler //! published, the admission rule over the spec's declared `serviceRole`, the //! driver's validate, recover, reconcile, and delete verbs, and the @@ -12,7 +12,7 @@ //! durable ingest-`Endpoint` rows reconcile re-reads, and it owns no child, so //! the crate declares no effect port and no child creation. The telemetry //! Serving Provider stays the authority for what a Service *means* - the -//! `telemetry. d2bus. org.TelemetryService` contract this crate keys on lives in +//! `telemetry.d2bus.org.TelemetryService` contract this crate keys on lives in //! `d2b-contracts-provider`, beside the sibling Binding type. //! //! # Contract flag (KTD3 fit; preserved from the daemon-side conversion) diff --git a/packages/d2b-provider-toolkit/src/shared_provider.rs b/packages/d2b-provider-toolkit/src/shared_provider.rs index 015342b36..41aefb475 100644 --- a/packages/d2b-provider-toolkit/src/shared_provider.rs +++ b/packages/d2b-provider-toolkit/src/shared_provider.rs @@ -17,7 +17,7 @@ //! actor exists, F1), owned children the desired set no longer derives are //! retired in the family's preserved order, the typed Provider effect runs //! behind the family's port, and the in-memory status projection is -//! published with `ctx. set_status` (R11) plus a self-`requeue_after` while +//! published with `ctx.set_status` (R11) plus a self-`requeue_after` while //! the family is not converged; //! - `prepare_finalize`/`execute_finalize`/`finalize` -> //! [`ResourceDriver::delete`]: the family's teardown stage runs behind the @@ -35,7 +35,7 @@ //! observable from an effect through [`SharedProviderChildSurface::view`], //! which reads the manager plane's live view for a row of the driving //! resource; the driver itself only registers -//! `ctx. watch(.., WatchCondition::Ready)` edges so dependency and child +//! `ctx.watch(.., WatchCondition::Ready)` edges so dependency and child //! readiness wake it, and it never fabricates a readiness it cannot observe. use std::sync::Arc; @@ -180,12 +180,12 @@ pub enum SharedProviderEffectPhase { } /// One Provider effect outcome: the phase the old effect returned plus the -/// `status. resource` projection the old status candidate published. +/// `status.resource` projection the old status candidate published. #[derive(Debug, Clone, PartialEq, Eq)] pub struct SharedProviderEffectOutcome { /// The phase the effect returned. pub phase: SharedProviderEffectPhase, - /// The `status. resource` projection the old status candidate published. + /// The `status.resource` projection the old status candidate published. pub resource_projection: Option, } @@ -198,7 +198,7 @@ impl SharedProviderEffectOutcome { } } - /// A phase outcome carrying one `status. resource` projection. + /// A phase outcome carrying one `status.resource` projection. pub fn projection(phase: SharedProviderEffectPhase, resource_projection: Value) -> Self { Self { phase, @@ -306,12 +306,12 @@ impl std::error::Error for SharedProviderDriverError {} /// Typed in-memory status projection (R11: never persisted). Carries the /// closed phase the old status candidate published plus the Provider's -/// `status. resource` projection. +/// `status.resource` projection. #[derive(Debug, Clone, PartialEq, Eq)] pub struct SharedProviderDriverStatus { /// The phase the effect published. pub phase: SharedProviderEffectPhase, - /// The Provider's `status. resource` projection. + /// The Provider's `status.resource` projection. pub resource: Option, } diff --git a/packages/d2b-provider-toolkit/src/testing/conformance.rs b/packages/d2b-provider-toolkit/src/testing/conformance.rs index f1ba93abc..9985dd927 100644 --- a/packages/d2b-provider-toolkit/src/testing/conformance.rs +++ b/packages/d2b-provider-toolkit/src/testing/conformance.rs @@ -4,7 +4,7 @@ //! `ResourceApiBinding` to implement the exact base spec and status schema //! version and fingerprint the installed ResourceType contract declares, to //! accept the canonical minimal valid base spec without a -//! `spec. provider` extension, and to refuse an optional base capability +//! `spec.provider` extension, and to refuse an optional base capability //! only through its signed capability matrix and the provider-neutral //! `unsupported-capability` result. //! @@ -296,7 +296,7 @@ pub fn check_descriptor_conformance( /// Live conformance for one binding: the Provider advertises the installed /// base schema identity, and the canonical minimal valid base spec is -/// accepted without any `spec. provider` extension. +/// accepted without any `spec.provider` extension. /// /// # Errors /// diff --git a/packages/d2b-provider-transport-azure-relay/src/auth.rs b/packages/d2b-provider-transport-azure-relay/src/auth.rs index c2e7f02dd..eb144f323 100644 --- a/packages/d2b-provider-transport-azure-relay/src/auth.rs +++ b/packages/d2b-provider-transport-azure-relay/src/auth.rs @@ -56,9 +56,9 @@ impl RelayRole { /// (hybrid connection) name. Non-secret. #[derive(Clone, PartialEq, Eq)] pub struct RelayEndpoint { - /// Namespace FQDN, e. g. `relns-xxxx. servicebus. windows. net`. + /// Namespace FQDN, e.g. `relns-xxxx.servicebus.windows.net`. pub namespace: String, - /// Hybrid connection (entity) name, e. g. `hc-d2b-display`. + /// Hybrid connection (entity) name, e.g. `hc-d2b-display`. pub entity: String, } @@ -80,7 +80,7 @@ pub enum RelayCredential { /// Gateway Guest-side (the Listen rule), and transitionally for non-MI /// senders. Sas { - /// The authorization-rule (key) name, e. g. `gateway-listen`. + /// The authorization-rule (key) name, e.g. `gateway-listen`. key_name: String, /// The rule's key. Secret. key: String, diff --git a/packages/d2b-provider-transport-vsock/src/settings.rs b/packages/d2b-provider-transport-vsock/src/settings.rs index 5d8e80f25..37c6ec039 100644 --- a/packages/d2b-provider-transport-vsock/src/settings.rs +++ b/packages/d2b-provider-transport-vsock/src/settings.rs @@ -1,4 +1,4 @@ -//! Closed `ZoneLink. spec. transportSettings` validation. +//! Closed `ZoneLink.spec.transportSettings` validation. use serde::{Deserialize, Serialize}; use std::fmt; diff --git a/packages/d2b-provider-user/src/driver.rs b/packages/d2b-provider-user/src/driver.rs index fca2cbafb..ec3df3576 100644 --- a/packages/d2b-provider-user/src/driver.rs +++ b/packages/d2b-provider-user/src/driver.rs @@ -20,10 +20,10 @@ //! over the [`UserDriverEffects`] discovery port. //! - `finalize` -> [`ResourceDriver::delete`] (old `FinalizeResult` was //! converged: the family owns no children and carries no finalizer). -//! - `UpdateStatus` -> `ctx. set_status` (in-memory only, R11). +//! - `UpdateStatus` -> `ctx.set_status` (in-memory only, R11). //! //! Deliberately not carried from the old handler: the durable -//! `status. resource` JSON projection and its `lastReconciledAt` / +//! `status.resource` JSON projection and its `lastReconciledAt` / //! `observedGeneration` writes (status is runtime-only now, R11), and the //! `assess_update` / `plan_upgrade` runner path (no driver equivalent; the //! family never planned an upgrade). The old runner's 5s resync relisted and @@ -126,7 +126,7 @@ impl std::error::Error for UserDriverError {} /// Typed in-memory status projection (R11: never persisted). /// /// The discovery is kept with the generation it was taken at, which is the -/// runtime-only successor of the old durable `status. observedGeneration` +/// runtime-only successor of the old durable `status.observedGeneration` /// plan short-circuit. #[derive(Debug, Clone, PartialEq, Eq)] pub struct UserDriverStatus { @@ -390,11 +390,11 @@ impl ResourceDriver for UserDriver { /// `User` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve the /// converted bootstrap rows without it, so it must be registered before the /// plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus. org.*Service` types. The driver serves no broker +/// qualified `*.d2bus.org.*Service` types. The driver serves no broker /// operations, creates no children, and reads no other resource: discovery /// reaches the local machine through the family's own probe. `User` names /// no placement anchor, so a User row never carries the canonical -/// `spec. executionRef` and the plane reconciles it on its own Host domain - +/// `spec.executionRef` and the plane reconciles it on its own Host domain - /// the machine whose local identity it names. /// /// U5: the declaration builds the family's own effects implementation from diff --git a/packages/d2b-provider-volume-binding/src/driver.rs b/packages/d2b-provider-volume-binding/src/driver.rs index ca15e8dbc..deff835c1 100644 --- a/packages/d2b-provider-volume-binding/src/driver.rs +++ b/packages/d2b-provider-volume-binding/src/driver.rs @@ -31,7 +31,7 @@ //! - `observe` -> [`ResourceDriver::recover`]. //! - `binding_children` minting + readiness -> [`ResourceDriver::reconcile`]. //! - `finalize_binding` drain + endpoint-first teardown -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx. set_status` (in-memory only). +//! - `UpdateStatus` -> `ctx.set_status` (in-memory only). //! //! Everything the driver needs from outside arrives through the driver //! effect port ([`BindingDriverEffects`]): the serving socket probe, the @@ -736,7 +736,7 @@ impl BindingDriver { // Host/host-system) and as the signed `virtiofsd-worker` template // the launch ticket resolves through binds it: the template's // execution_ref is the volume-virtiofs Provider's - // config. controllerExecutionRef. The attachment's Guest stays the + // config.controllerExecutionRef. The attachment's Guest stays the // ticket's target ref (KTD7), re-derived from the owning VolumeBinding // row by the Process driver's identity path. let process_spec = serde_json::json!({ @@ -957,7 +957,7 @@ impl ResourceDriver for BindingDriver { .expect("the fenced binding projection is always serializable"), ); if mutated || !socket_ready { - // The child rows were (re) committed this pass, or the socket is + // The child rows were (re)committed this pass, or the socket is // not serving yet: re-check on the preserved resync cadence (the // Runner contract's repair interval) - the same shape the Guest // driver uses while its Provider phase is not Ready, so a @@ -1076,7 +1076,7 @@ impl ResourceDriver for BindingDriver { /// /// Derived from the placement contract: `VolumeBinding` names no placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a binding row -/// never carries the canonical `spec. executionRef` and the plane reconciles +/// never carries the canonical `spec.executionRef` and the plane reconciles /// it on its containing Zone's Host. The attachment's `executionRef` selects /// the Guest that consumes the share, never where the binding row itself is /// reconciled. @@ -1094,7 +1094,7 @@ const BINDING_READS: &[WellKnownType] = &[WellKnownType::VOLUME]; /// `VolumeBinding` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot /// serve the converted binding shapes without it, so it must be registered /// before the plane opens. The type is not exportable: `ResourceExport` -/// admits only qualified `*.d2bus. org.*Service` types, so a binding can never +/// admits only qualified `*.d2bus.org.*Service` types, so a binding can never /// be an export subject. The driver serves no broker operations and /// contributes no startup steps; the worker Process and Endpoint children it /// mints are declared in [`BINDING_CREATIONS`], and the declaration carries diff --git a/packages/d2b-provider-volume-local/src/adapter.rs b/packages/d2b-provider-volume-local/src/adapter.rs index 747d19de8..86d759550 100644 --- a/packages/d2b-provider-volume-local/src/adapter.rs +++ b/packages/d2b-provider-volume-local/src/adapter.rs @@ -1266,7 +1266,7 @@ fn apply_metadata( // POSIX ACL application // // The declared grants are real kernel ACLs: the daemon owns the entry it -// creates, so it applies them through the `system. posix_acl_*` xattrs without +// creates, so it applies them through the `system.posix_acl_*` xattrs without // any capability. The encoding is the kernel's `posix_acl_xattr_header` + // `posix_acl_xattr_entry` layout, and the mask carries the group-class // permissions exactly as `setfacl` computes it - the kernel requires the mask @@ -1356,7 +1356,7 @@ fn acl_entries(mode: u32, mut named: Vec) -> Vec { entries } -/// Encode one entry set as the `system. posix_acl_*` xattr value. +/// Encode one entry set as the `system.posix_acl_*` xattr value. fn acl_xattr_bytes(entries: &[AclEntry]) -> Vec { let mut bytes = Vec::with_capacity(4 + entries.len() * 8); bytes.extend_from_slice(&POSIX_ACL_XATTR_VERSION.to_le_bytes()); diff --git a/packages/d2b-provider-volume-local/src/content.rs b/packages/d2b-provider-volume-local/src/content.rs index 3e37805df..4802ae711 100644 --- a/packages/d2b-provider-volume-local/src/content.rs +++ b/packages/d2b-provider-volume-local/src/content.rs @@ -707,7 +707,7 @@ impl NetworkConfigContentProjection { Ok(projection) } - /// Parse and validate a provider `settings. content` object. + /// Parse and validate a provider `settings.content` object. pub fn from_settings(settings: &serde_json::Value) -> Result { let projection: Self = serde_json::from_value(settings.clone()).map_err(|_| VolumeLocalError::InvalidSpec)?; diff --git a/packages/d2b-provider-volume-virtiofs/src/bindings.rs b/packages/d2b-provider-volume-virtiofs/src/bindings.rs index ba02f0e0d..e84cfa5a9 100644 --- a/packages/d2b-provider-volume-virtiofs/src/bindings.rs +++ b/packages/d2b-provider-volume-virtiofs/src/bindings.rs @@ -115,7 +115,7 @@ impl StoredBinding { /// The envelope must be a `VolumeBinding` owned by an existing /// Volume and served by this Provider, and it must be strictly /// neutral: the standard catalog admits no provider extension path - /// for the type, so a `spec. provider` block -- legacy schema id + /// for the type, so a `spec.provider` block -- legacy schema id /// or otherwise -- is rejected, and the envelope never carries /// attachment settings (KTD1). The serving posture is the frozen /// default declared by the worker plan. diff --git a/packages/d2b-provider-volume/src/driver.rs b/packages/d2b-provider-volume/src/driver.rs index 84f1c3e2d..ef15dcdcf 100644 --- a/packages/d2b-provider-volume/src/driver.rs +++ b/packages/d2b-provider-volume/src/driver.rs @@ -18,7 +18,7 @@ //! - `observe` -> [`ResourceDriver::recover`]. //! - layout effect + `volume_children` ensure -> [`ResourceDriver::reconcile`]. //! - volume-local cleanup -> [`ResourceDriver::delete`]. -//! - `UpdateStatus` -> `ctx. set_status` (in-memory only). +//! - `UpdateStatus` -> `ctx.set_status` (in-memory only). //! //! Everything the driver needs from outside arrives through the driver //! effect port ([`VolumeDriverEffects`]): the layout effect over the @@ -689,7 +689,7 @@ impl ResourceDriver for VolumeDriver { /// /// Derived from the placement contract: `Volume` names no placement anchor /// (`PlacementAnchor::canonical_for` resolves none), so a Volume row never -/// carries the canonical `spec. executionRef` and the plane reconciles it on +/// carries the canonical `spec.executionRef` and the plane reconciles it on /// its containing Zone's Host. A source or attachment reference selects /// where a share is served, never where the row itself is reconciled. const VOLUME_EXECUTION_DOMAINS: &[&str] = &["host"]; @@ -705,7 +705,7 @@ const VOLUME_READS: &[WellKnownType] = &[]; /// `Volume` is `BUILTIN | STARTUP` (no RUNTIME bit): the plane cannot serve /// the converted volume shapes without it, so it must be registered before /// the plane opens. The type is not exportable: `ResourceExport` admits only -/// qualified `*.d2bus. org.*Service` types, so a volume can never be an +/// qualified `*.d2bus.org.*Service` types, so a volume can never be an /// export subject. The driver serves no broker operations and contributes no /// startup steps; the `VolumeBinding` children it mints are declared in /// [`VOLUME_CREATIONS`]. diff --git a/packages/d2b-provider-wayland-policy/src/audio_registry.rs b/packages/d2b-provider-wayland-policy/src/audio_registry.rs index d738f5cdb..d29cac356 100644 --- a/packages/d2b-provider-wayland-policy/src/audio_registry.rs +++ b/packages/d2b-provider-wayland-policy/src/audio_registry.rs @@ -535,7 +535,7 @@ fn decode_spec( .map_err(|error| AudioResourceRuntimeError::InvalidSpec(error.to_string())) } -/// The `status. resource` projection for one AudioBinding (old +/// The `status.resource` projection for one AudioBinding (old /// `audio_binding_status_projection_with_status`): the typed channel status /// plus the realized Process/Endpoint references the driver owns. pub(crate) fn audio_binding_projection( diff --git a/packages/d2b-provider-wayland-policy/src/effects_service.rs b/packages/d2b-provider-wayland-policy/src/effects_service.rs index 51484350b..f0f41111a 100644 --- a/packages/d2b-provider-wayland-policy/src/effects_service.rs +++ b/packages/d2b-provider-wayland-policy/src/effects_service.rs @@ -597,7 +597,7 @@ fn envelope_spec_document(value: &Value) -> Value { } } -/// The base spec with `spec. providerRef` re-inserted (the typed audio specs +/// The base spec with `spec.providerRef` re-inserted (the typed audio specs /// carry the field; old `AudioResourceRuntime::decode_spec` re-inserted it /// after the envelope split). fn spec_with_provider_ref( @@ -703,7 +703,7 @@ fn map_audio_effect_error(error: AudioResourceRuntimeError) -> InteractionEffect } } -/// The old `status. resource` projection for a display session (old +/// The old `status.resource` projection for a display session (old /// `display_resource_projection`): the two worker Process references and the /// private Endpoint with its committed generation. fn display_projection( diff --git a/packages/d2b-provider-wayland-policy/src/interaction.rs b/packages/d2b-provider-wayland-policy/src/interaction.rs index 5976532ac..e86fb6f6c 100644 --- a/packages/d2b-provider-wayland-policy/src/interaction.rs +++ b/packages/d2b-provider-wayland-policy/src/interaction.rs @@ -84,17 +84,17 @@ pub enum InteractionEffectPhase { } /// One Provider effect outcome: the phase the effect returned plus the -/// `status. resource` projection the effect publishes. +/// `status.resource` projection the effect publishes. #[derive(Debug, Clone, PartialEq, Eq)] pub struct InteractionEffectOutcome { /// The convergence phase of the row. pub phase: InteractionEffectPhase, - /// The optional `status. resource` projection. + /// The optional `status.resource` projection. pub resource: Option, } impl InteractionEffectOutcome { - /// A phase-only outcome with no `status. resource` projection. + /// A phase-only outcome with no `status.resource` projection. pub const fn phase(phase: InteractionEffectPhase) -> Self { Self { phase, @@ -102,7 +102,7 @@ impl InteractionEffectOutcome { } } - /// A phase outcome carrying the row's `status. resource` projection. + /// A phase outcome carrying the row's `status.resource` projection. pub fn projection(phase: InteractionEffectPhase, resource: Value) -> Self { Self { phase, @@ -201,13 +201,13 @@ impl core::fmt::Display for InteractionDriverError { impl std::error::Error for InteractionDriverError {} /// Typed in-memory status projection (never persisted). Carries the closed -/// phase the effect published plus the Provider's `status. resource` +/// phase the effect published plus the Provider's `status.resource` /// projection. #[derive(Debug, Clone, PartialEq, Eq)] pub struct InteractionDriverStatus { /// Whether the Provider realization is current. pub ready: bool, - /// The Provider's `status. resource` projection, when it published one. + /// The Provider's `status.resource` projection, when it published one. pub resource: Option, } @@ -330,7 +330,7 @@ pub struct InteractionEffectRequest<'a> { /// stripped, so every type decodes its typed spec without re-deriving the /// split. pub spec: Value, - /// The row's `spec. providerRef`. + /// The row's `spec.providerRef`. pub provider_ref: Option, /// Owned child rows realizing the current desired child set. pub children: &'a [InteractionChild], @@ -392,7 +392,7 @@ pub trait InteractionType: Clone + Send + Sync + 'static { const RESOURCE_TYPE: &'static str; /// The Provider reference the type's rows select. const PROVIDER_REF: &'static str; - /// Whether a row's spec must carry the typed universal `spec. providerRef`. + /// Whether a row's spec must carry the typed universal `spec.providerRef`. const SPEC_PROVIDER_SELECTOR: bool; /// The preserved reconcile resync cadence of the type: the Provider's diff --git a/packages/d2b-provider-zone-link/src/zone_links.rs b/packages/d2b-provider-zone-link/src/zone_links.rs index fbda037b9..a0459256f 100644 --- a/packages/d2b-provider-zone-link/src/zone_links.rs +++ b/packages/d2b-provider-zone-link/src/zone_links.rs @@ -63,10 +63,10 @@ pub use d2b_contracts_zone_session::v3::zone_session::{ BOOTSTRAP_PSK_TTL_MS_DEFAULT, KK_SESSION_MAX_LIFETIME_MS_DEFAULT, }; -/// Admission ceiling for `spec. limits. maxPendingIntents`. +/// Admission ceiling for `spec.limits.maxPendingIntents`. pub const MAX_PENDING_LOCAL_INTENTS: u32 = 1024; -/// Admission ceiling for `spec. limits. maxActiveStreams`. +/// Admission ceiling for `spec.limits.maxActiveStreams`. pub const MAX_ACTIVE_STREAMS: u32 = 128; /// Maximum committed route-admission operation IDs retained for one immutable @@ -250,7 +250,7 @@ impl core::fmt::Display for ZoneLinkError { impl std::error::Error for ZoneLinkError {} -/// Bounded ZoneLink connection and queue limits from `spec. limits`. +/// Bounded ZoneLink connection and queue limits from `spec.limits`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ZoneLinkLimits { max_pending_intents: u32, @@ -260,7 +260,7 @@ pub struct ZoneLinkLimits { } impl ZoneLinkLimits { - /// Validate one complete `spec. limits` object against its frozen bounds. + /// Validate one complete `spec.limits` object against its frozen bounds. /// /// # Errors /// @@ -995,7 +995,7 @@ impl core::fmt::Debug for ZoneLinkRecord { } } -/// The D088 `status. resource` projection written by the child-local handler. +/// The D088 `status.resource` projection written by the child-local handler. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ZoneLinkStatus { phase: ZoneLinkPhase, @@ -1282,7 +1282,7 @@ impl ZoneLinkHandler { self.key_policy } - /// Project the current D088 `status. resource` observation. + /// Project the current D088 `status.resource` observation. pub fn status(&self) -> ZoneLinkStatus { ZoneLinkStatus { phase: self.phase, diff --git a/packages/d2b-provider/src/agent.rs b/packages/d2b-provider/src/agent.rs index 274c4b97a..9319485f9 100644 --- a/packages/d2b-provider/src/agent.rs +++ b/packages/d2b-provider/src/agent.rs @@ -288,7 +288,7 @@ where /// # Errors /// /// Returns [`ProviderAgentError::UnsupportedService`] when the request - /// names a service other than `d2b. provider. v3`, + /// names a service other than `d2b.provider.v3`, /// [`ProviderAgentError::DispatchSaturated`] when the in-flight budget /// is exhausted, [`ProviderAgentError::DispatchTimeout`] when the /// request exceeds its timeout, and diff --git a/packages/d2b-resource-api/src/admission.rs b/packages/d2b-resource-api/src/admission.rs index 3adf61bce..6a13d0379 100644 --- a/packages/d2b-resource-api/src/admission.rs +++ b/packages/d2b-resource-api/src/admission.rs @@ -264,7 +264,7 @@ impl AdmissionPermit { /// use d2b_resource_api::AdmittedMutation; /// /// fn inspect(value: &AdmittedMutation) { -/// let _ = &value. mutations; +/// let _ = &value.mutations; /// } /// ``` pub struct AdmittedMutation { diff --git a/packages/d2b-resource-api/src/manager_backend.rs b/packages/d2b-resource-api/src/manager_backend.rs index 5a98e2bd8..3abbd1b27 100644 --- a/packages/d2b-resource-api/src/manager_backend.rs +++ b/packages/d2b-resource-api/src/manager_backend.rs @@ -12,8 +12,8 @@ //! remainder exists, and a cursor that cannot be honoured is refused with //! a typed error rather than ignored; //! - the closed list filters keep their durable-plane semantics, including -//! ownership (`owner. resourceUid` matches the row's resolved owner uid, -//! `owner. resourceRef` the owner reference the row renders); +//! ownership (`owner.resourceUid` matches the row's resolved owner uid, +//! `owner.resourceRef` the owner reference the row renders); //! - mutations admit at the manager boundary under the caller's real //! authenticated subject ([`api_subject`]) and persist through //! `Ensure`/`Remove` with commit-before-return (F1/AE1); @@ -334,7 +334,7 @@ fn check_precondition(mutation: &StoreMutation, row: &StoredDesiredResource) -> } /// The owner reference the row renders, when one is rendered: the authored -/// `metadata. ownerRef` wins (exactly as [`render_envelope`] resolves it), and +/// `metadata.ownerRef` wins (exactly as [`render_envelope`] resolves it), and /// a row without one renders the resolved owner key. Evaluating the filter /// here keeps it on the same value the row's readers see. fn rendered_owner_ref(view: &ResourceView) -> Option { @@ -595,7 +595,7 @@ fn stored_of( generation: u64, spec: &[u8], ) -> StoredResource { - // Rows not created through this backend (e. g. Nix-materialized rows whose + // Rows not created through this backend (e.g. Nix-materialized rows whose // spec the compiler owns) keep their bytes verbatim; the digest is // recomputed only when the spec is a complete resource envelope. let payload_digest = CanonicalJsonValue::parse(spec) @@ -938,7 +938,7 @@ fn stamp_deletion_request(stored: &mut StoredResource) -> Result<(), StoreError> /// /// ```text /// let authorizer = Arc::new(NativeAuthorizer::new(catalog, policy)?); -/// let acceptor = authorizer. take_store_seal(manager_seal_identity())?; +/// let acceptor = authorizer.take_store_seal(manager_seal_identity())?; /// let backend = ManagerBackend::new(client, hub, acceptor); /// let service = ResourceService::new_with_zone_uid(Arc::new(backend), authorizer, zone_uid)?; /// ``` diff --git a/packages/d2b-resource-api/src/manager_backend/tests.rs b/packages/d2b-resource-api/src/manager_backend/tests.rs index 795e07874..a50d6b141 100644 --- a/packages/d2b-resource-api/src/manager_backend/tests.rs +++ b/packages/d2b-resource-api/src/manager_backend/tests.rs @@ -555,7 +555,7 @@ async fn create_get_update_delete_round_trip_through_the_manager() { /// Nix-ingested rows persist spec-shaped bytes, so their envelope is /// rendered on the read (the fallback path). The manager view must serve the /// row's stable uid there: the public delete precondition resolves the exact -/// uid from `metadata. uid`, and `ResourceUid`'s redacted `Display` is never +/// uid from `metadata.uid`, and `ResourceUid`'s redacted `Display` is never /// data. A round trip through an API-created row cannot catch this - those /// rows persist envelope-shaped bytes and already carry their uid. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] @@ -821,7 +821,7 @@ fn rendered_full_envelopes_keep_the_strict_reader_contract() { /// converted type the API can serve renders through the one producer, and /// each rendered row is a complete strict envelope - with and without a live /// status projection - whose status object is exactly the contract's closed -/// shape and whose `status. resource` layer is the driver's own value carried +/// shape and whose `status.resource` layer is the driver's own value carried /// unchanged. /// /// A type whose rendering lost a required member, wrapped the driver's layer, @@ -1026,7 +1026,7 @@ async fn every_converted_type_is_served_by_the_manager_path() { fixture.manager_actor.get_cell().stop(None); } -/// The converted types whose contracts pin a typed `status. resource` layer +/// The converted types whose contracts pin a typed `status.resource` layer /// decode the served layer through exactly that `deny-unknown-fields` /// decoder: the projection cannot wrap, rename, or nest what the type's /// consumers read. The remaining converted types publish free-form evidence @@ -1040,7 +1040,7 @@ fn converted_type_status_layers_round_trip_through_their_typed_decoders() { use d2b_resource_runtime::spec_store::{ResourceKey, ResourceProvenance}; /// One typed status decoder case: the converted type's name, the served - /// wire `status. resource` value, and the type's decoder. + /// wire `status.resource` value, and the type's decoder. type TypedDecoderCase = ( &'static str, serde_json::Value, @@ -1672,8 +1672,8 @@ async fn list_refuses_a_cursor_it_cannot_honour() { } /// An owner-scoped LIST matches the manager's owned children: the row's real -/// ownership is projected into the store shape, so `owner. resourceUid` and -/// `owner. resourceRef` return the owner's rows instead of an empty page. +/// ownership is projected into the store shape, so `owner.resourceUid` and +/// `owner.resourceRef` return the owner's rows instead of an empty page. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] #[tokio::test] async fn list_owner_filters_match_manager_owned_children() { diff --git a/packages/d2b-resource-api/src/service.rs b/packages/d2b-resource-api/src/service.rs index a98fd0b8b..a692c66ec 100644 --- a/packages/d2b-resource-api/src/service.rs +++ b/packages/d2b-resource-api/src/service.rs @@ -43,7 +43,7 @@ use crate::{ /// use d2b_resource_api::service::TrustedRequest; /// /// fn forge(request: &TrustedRequest) { -/// let _ = &request. subject; +/// let _ = &request.subject; /// } /// ``` #[derive(Clone)] diff --git a/packages/d2b-resource-compiler/src/lib.rs b/packages/d2b-resource-compiler/src/lib.rs index 62ff34c9f..3d78f5a6c 100644 --- a/packages/d2b-resource-compiler/src/lib.rs +++ b/packages/d2b-resource-compiler/src/lib.rs @@ -12,7 +12,7 @@ //! //! ``` //! let digest = d2b_resource_compiler::sha256_digest(b"provider"); -//! assert_eq!(digest. as_str().len(), 71); +//! assert_eq!(digest.as_str().len(), 71); //! ``` use std::{ @@ -970,7 +970,7 @@ fn append_virtiofsd_worker_templates( /// for `device-tpm`, `Process/gpu-` and `Process/video-` for /// `device-gpu` - each carrying the row's `template` and an `ownerRef` to the /// claiming Device. The declared row is the authority this pass reads: the -/// owner Device's declared `spec. providerRef` names the Device Provider, whose +/// owner Device's declared `spec.providerRef` names the Device Provider, whose /// artifact must enumerate the executable the closed posture for /// (`providerRef`, `template`) pins /// ([`d2b_core::bundle_resolver::device_worker_posture`]), and a declared row diff --git a/packages/d2b-resource-runtime/src/context.rs b/packages/d2b-resource-runtime/src/context.rs index a21ce2179..82f5720ed 100644 --- a/packages/d2b-resource-runtime/src/context.rs +++ b/packages/d2b-resource-runtime/src/context.rs @@ -95,7 +95,7 @@ pub struct WatchSatisfied { /// /// ```text /// if status matches condition { notify(subscriber, Satisfied) } -/// else { watchers. insert(watch_id, ...) } +/// else { watchers.insert(watch_id, ...) } /// ``` /// /// Status transitions evaluate registered watches in the same handler. U3 @@ -347,7 +347,7 @@ pub struct ResourceContext { status: Option>, /// Free-form status projection for the read surfaces (R11: in-memory /// only, never persisted). The erased status slot above is typed and - /// driver-private; this is the closed-JSON `status. resource` layer the + /// driver-private; this is the closed-JSON `status.resource` layer the /// manager renders onto the wire for rows whose consumer contract /// carries one (the Cloud Hypervisor Guest runtime status). status_projection: Option, @@ -463,7 +463,7 @@ impl ResourceContext { self.status = Some(Box::new(status)); } - /// Publish the wire-visible `status. resource` layer of this row (R11: + /// Publish the wire-visible `status.resource` layer of this row (R11: /// in-memory only). The actor takes it after the pass that set it and the /// manager renders it onto the row's status; a driver that publishes no /// projection leaves the layer empty, exactly as today. @@ -518,11 +518,11 @@ impl ResourceContext { /// /// - `Ok(None)`: **absent** - no row for `key` exists in this manager's /// Zone (never created, already retired, or owned by another Zone). - /// - `Ok(Some(view))` with `view. status == None`: the row exists but no + /// - `Ok(Some(view))` with `view.status == None`: the row exists but no /// actor has ever published a status for it (spawn still in flight, /// poisoned spawn, actor restart). **Unknown**, never "not ready". /// - `Ok(Some(view))` with - /// `view. status_generation != Some(view. generation)`: the last + /// `view.status_generation != Some(view.generation)`: the last /// published status describes an older generation, so it is not /// observed state of the current row. /// [`ResourceView::observed_status`] folds both of the last two cases @@ -533,7 +533,7 @@ impl ResourceContext { /// Never reported as absence. /// /// Readiness of a child or dependency is therefore - /// `view. observed_status() == Some(ResourceStatus::Ready)`; when the + /// `view.observed_status() == Some(ResourceStatus::Ready)`; when the /// answer is not-ready, a [`Self::watch`] on [`WatchCondition::Ready`] /// wakes this resource's actor on the transition and the next reconcile /// re-reads here. @@ -596,7 +596,7 @@ impl ResourceContext { /// child that owns it. /// /// Idempotent under retry, and non-blocking (R5): every owned child's - /// deletion is (re) requested - the manager's `Remove` is idempotent and + /// deletion is (re)requested - the manager's `Remove` is idempotent and /// the child's own finalize/delete are retry-idempotent - and the call /// then reports [`ResourceError::ChildrenDraining`] while any owned child /// row is still live. The caller classifies that retryable and requeues, @@ -610,7 +610,7 @@ impl ResourceContext { // The manager already cascaded the deletion when this resource // was marked deleting; requesting it again is the idempotent // nudge that guarantees a child whose actor missed the first - // cascade (e. g. spawned between passes) runs its own + // cascade (e.g. spawned between passes) runs its own // finalize-before-delete pass. let _ = self.manager.delete(&child.key).await; } @@ -1590,7 +1590,7 @@ mod tests { assert!(notify2_rx.try_recv().is_err(), "exactly one immediate notification"); } - /// `ctx. watch()` routes the registration through the manager with this + /// `ctx.watch()` routes the registration through the manager with this /// resource's key as the subscriber, and satisfaction arrives on this /// resource's notify channel. #[tokio::test] diff --git a/packages/d2b-resource-runtime/src/error.rs b/packages/d2b-resource-runtime/src/error.rs index 517192807..904132bc0 100644 --- a/packages/d2b-resource-runtime/src/error.rs +++ b/packages/d2b-resource-runtime/src/error.rs @@ -101,7 +101,7 @@ impl std::fmt::Display for FailureClass { pub const REDACTED: &str = ""; /// Bounded note length a failure may carry (provider-supplied text). The wire -/// `status. resource` layer is bounded, so failure detail is truncated at a +/// `status.resource` layer is bounded, so failure detail is truncated at a /// char boundary before it can render. pub const MAX_FAILURE_NOTE_BYTES: usize = 512; @@ -468,7 +468,7 @@ impl DriverFailure { Self::refused(op, FailureKinds::DRIVER_REFUSED) } - /// Refine the stage beyond the driver operation (e. g. `recover/adopt`). + /// Refine the stage beyond the driver operation (e.g. `recover/adopt`). #[must_use] pub fn at(mut self, stage: &'static str) -> Self { self.stage = stage; @@ -586,7 +586,7 @@ impl DriverFailure { self.report().log_line() } - /// The `status. resource. driverFailure` wire object: the same structured + /// The `status.resource.driverFailure` wire object: the same structured /// detail as [`Self::log_line`]. pub fn wire_layer(&self) -> serde_json::Value { self.report().wire_layer() @@ -686,7 +686,7 @@ impl FailureReport { line } - /// The `status. resource. driverFailure` wire object. `operation` keeps the + /// The `status.resource.driverFailure` wire object. `operation` keeps the /// established PascalCase spelling and `retryable` stays first-class for /// the readers that gate child retries on it. pub fn wire_layer(&self) -> serde_json::Value { diff --git a/packages/d2b-resource-runtime/src/manager.rs b/packages/d2b-resource-runtime/src/manager.rs index d82ea5071..c9c6db767 100644 --- a/packages/d2b-resource-runtime/src/manager.rs +++ b/packages/d2b-resource-runtime/src/manager.rs @@ -13,7 +13,7 @@ //! spawn-or-update the actor -> reply. Identical specs return the current //! actor handle; changed specs persist a new generation and only then send //! `SpecChanged`; absent resources persist before their actor is spawned. A -//! spawn that fails after the commit (e. g. no provider factory for the type) +//! spawn that fails after the commit (e.g. no provider factory for the type) //! leaves the row durable; a later Ensure or manager restart recovers it. //! //! ## Admission boundary (KTD2 review finding; security review finding 3) @@ -187,7 +187,7 @@ pub struct ResourceView { /// notified once per committed generation, so a status published before a /// spec change must not be read as observed state of the newer row. pub status_generation: Option, - /// The driver's wire-visible `status. resource` layer published with that + /// The driver's wire-visible `status.resource` layer published with that /// status (`None` when the driver published none, or when the status is /// not current for the row). pub status_projection: Option, @@ -210,7 +210,7 @@ impl ResourceView { .cloned() } - /// The `status. resource` layer published **for this exact row + /// The `status.resource` layer published **for this exact row /// generation**, mirroring [`Self::observed_status`]: a projection left /// over from an older generation is not observed state of the row. pub fn observed_status_projection(&self) -> Option<&serde_json::Value> { @@ -221,7 +221,7 @@ impl ResourceView { /// The canonical wire `status` object for this row: the closed universal /// shape the resource contract defines, carrying this row's live - /// classification and its driver-published `status. resource` layer. + /// classification and its driver-published `status.resource` layer. /// /// This is the one producer of the status shape (issue #515). Every /// reader - the API's wire view, a store-shaped bridge, an effect gate - @@ -358,7 +358,7 @@ pub enum ResourceManagerMsg { key: ResourceKey, generation: u64, status: ResourceStatus, - /// The actor's wire-visible `status. resource` layer for this pass, + /// The actor's wire-visible `status.resource` layer for this pass, /// when the driver published one (R11: in-memory only, replaced or /// dropped with the next status). projection: Option, @@ -463,7 +463,7 @@ pub struct ResourceManagerState { /// The generation each published status belongs to (see /// [`ResourceView::status_generation`]). status_generations: HashMap, - /// The driver-published `status. resource` layer of each row's current + /// The driver-published `status.resource` layer of each row's current /// status (see [`ResourceView::status_projection`]); in-memory only. status_projections: HashMap, /// Rows whose cleanup completed at their actor while owned children were @@ -873,7 +873,7 @@ pub struct ResourceManagerArgs { /// reference. pub host_target: TargetRef, /// Resolves the execution reference a stored desired spec declares - /// (`spec. executionRef`), supplied by the composition from the resource + /// (`spec.executionRef`), supplied by the composition from the resource /// contracts. pub target_resolver: Arc, /// Fixed reconcile backoff for retryable driver failures (R13). @@ -933,7 +933,7 @@ impl Actor for ResourceManager { // Restart recovery (F2, R15): load durable specs and spawn one actor // per row; each actor reconstructs observed state by discovery and // adoption on its target. Rows without a registered provider factory - // (e. g. a spawn that failed after commit) stay durable and are + // (e.g. a spawn that failed after commit) stay durable and are // picked up by the next Ensure or restart. let rows = state .store @@ -2507,7 +2507,7 @@ mod tests { /// closed universal shape, and only a status published for the row's own /// generation is observed state. A stale published status must never /// leak a `Ready` into the served phase, and a live driver projection is - /// carried as the `status. resource` layer byte-for-byte. + /// carried as the `status.resource` layer byte-for-byte. #[test] fn wire_status_projects_only_current_observed_state() { use crate::identity::{ResourceKey, ResourceProvenance}; @@ -2630,7 +2630,7 @@ mod tests { /// projection publishes it, whatever its outcome. `InProgress` (a long /// effect in flight) keeps the actor's `Reconciling` status but must not /// swallow the evidence the pass just computed - dropping it left rows - /// serving the pre-pass (or no) `status. resource` layer while the driver + /// serving the pre-pass (or no) `status.resource` layer while the driver /// already knew better. Only invalidation (spec change, deletion) clears /// the layer. #[tokio::test] @@ -3462,7 +3462,7 @@ mod tests { } /// The projection channel's failure case: a pass that computed a - /// `status. resource` layer and then failed publishes the failure, not the + /// `status.resource` layer and then failed publishes the failure, not the /// stale success layer. `wire_status` prefers a projection when one is /// present, so a leaked layer would hide the driver failure entirely. #[tokio::test] diff --git a/packages/d2b-resource-runtime/src/metadata.rs b/packages/d2b-resource-runtime/src/metadata.rs index a65fa8e1d..88c2b0220 100644 --- a/packages/d2b-resource-runtime/src/metadata.rs +++ b/packages/d2b-resource-runtime/src/metadata.rs @@ -60,7 +60,7 @@ use serde_json::Value; /// /// Derived from the placement contract: none of these types names a placement /// anchor (`PlacementAnchor::canonical_for` resolves none), so a row never -/// carries the canonical `spec. executionRef` and the plane reconciles it on +/// carries the canonical `spec.executionRef` and the plane reconciles it on /// its own Host domain. pub const METADATA_EXECUTION_DOMAINS: &[&str] = &["host"]; diff --git a/packages/d2b-resource-runtime/src/resource.rs b/packages/d2b-resource-runtime/src/resource.rs index 66c4d34c0..2ccffde15 100644 --- a/packages/d2b-resource-runtime/src/resource.rs +++ b/packages/d2b-resource-runtime/src/resource.rs @@ -115,7 +115,7 @@ impl ResourceStatus { } /// The structured failure classification rendered into the free-form - /// `status. resource` layer, for a row whose driver published no + /// `status.resource` layer, for a row whose driver published no /// projection of its own: the universal status object is closed to /// unknown fields, so a failure classification rides the type's own /// layer. `None` for every non-failed classification. @@ -360,7 +360,7 @@ impl ResourceActorState { self.transition_published(status, None); } - /// [`Self::transition`] with the pass's wire-visible `status. resource` + /// [`Self::transition`] with the pass's wire-visible `status.resource` /// projection attached (R11: in-memory only, dropped with the next /// status). The projection is `None` for transitions no driver pass /// produced. @@ -1419,7 +1419,7 @@ pub(crate) mod test_support { } /// Restart semantics with the caller's factory: restart tests can pin - /// driver behavior (e. g. blocked deletes) on keys before the manager + /// driver behavior (e.g. blocked deletes) on keys before the manager /// loads rows and spawns their actors. pub(crate) async fn harness_over_with_factory( store: Arc, diff --git a/packages/d2b-resource-runtime/src/spec_store.rs b/packages/d2b-resource-runtime/src/spec_store.rs index 8160498b6..1afd04cbb 100644 --- a/packages/d2b-resource-runtime/src/spec_store.rs +++ b/packages/d2b-resource-runtime/src/spec_store.rs @@ -11,7 +11,7 @@ //! variant of the message-passing surface allowed by KTD2: SQLite calls never //! run inside an async context or an actor mailbox (KTD12), writers serialize //! structurally on the single connection, and `busy_timeout` covers the -//! remaining cross-connection case (two stores open on one file, e. g. during +//! remaining cross-connection case (two stores open on one file, e.g. during //! handover). //! //! Admission is refuse-don't-queue (the loader_worker doctrine): a full @@ -435,7 +435,7 @@ fn tighten_file_modes(path: &Path) { // files carry the daemon's private-data mode (0600). SQLite names the // side files by appending `-wal`/`-shm` to the *database file name*, so // the suffix is appended here too - `with_extension` would rewrite the - // real suffix (`spec-store. sqlite3` -> `spec-store. db-wal`) and leave + // real suffix (`spec-store.sqlite3` -> `spec-store.db-wal`) and leave // the files SQLite actually created at their creation mode. Side files // only exist while a connection holds the database open in WAL mode. let tighten = |p: &Path| { diff --git a/packages/d2b-resource-runtime/src/target.rs b/packages/d2b-resource-runtime/src/target.rs index 590adaf9b..f2864acbb 100644 --- a/packages/d2b-resource-runtime/src/target.rs +++ b/packages/d2b-resource-runtime/src/target.rs @@ -86,7 +86,7 @@ pub const MAX_TARGET_NAME_BYTES: usize = 128; /// One canonical execution reference: `Host/` or `Guest/`. /// -/// This is the reference a desired spec declares (`spec. executionRef`); it +/// This is the reference a desired spec declares (`spec.executionRef`); it /// names where effects run and never changes a resource's Zone identity. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TargetRef { @@ -463,7 +463,7 @@ impl std::error::Error for TargetError {} /// Resolves the execution target a stored desired spec declares. /// /// One implementation per composition: it reads the same canonical -/// `spec. executionRef` the resource contracts resolve, and returns the +/// `spec.executionRef` the resource contracts resolve, and returns the /// canonical `Host/` or `Guest/` reference. A row whose type has /// no execution anchor, or a legacy row that carries none, returns `None` and /// realizes on the Zone's Host target. diff --git a/packages/d2b-resource-types/src/metadata.rs b/packages/d2b-resource-types/src/metadata.rs index 43331900d..6373bf36d 100644 --- a/packages/d2b-resource-types/src/metadata.rs +++ b/packages/d2b-resource-types/src/metadata.rs @@ -36,7 +36,7 @@ use crate::{AllowedSources, CONVERTED_TYPE_VERBS, DriverDescriptor, WellKnownTyp /// and creates no children through this declaration. /// /// None of the types is exportable: `ResourceExport` admits only qualified -/// `*.d2bus. org.*Service` types, so a row of one of these types is never an +/// `*.d2bus.org.*Service` types, so a row of one of these types is never an /// export subject. pub fn metadata_descriptor(resource_type: WellKnownType) -> DriverDescriptor { DriverDescriptor { diff --git a/packages/d2b-sk-frontend/src/uhid.rs b/packages/d2b-sk-frontend/src/uhid.rs index a9410ee02..272ba06f4 100644 --- a/packages/d2b-sk-frontend/src/uhid.rs +++ b/packages/d2b-sk-frontend/src/uhid.rs @@ -173,7 +173,7 @@ impl UhidDevice { /// Read and parse one event from /dev/uhid. /// /// Blocks until an event is available. Returns `None` on clean EOF - /// (e. g. the kernel closed the device). + /// (e.g. the kernel closed the device). pub async fn read_event(&mut self) -> io::Result> { let mut buf = [0u8; UHID_EVENT_SIZE]; let n = self.read_nonblocking(&mut buf).await?; diff --git a/packages/d2b-zone-routing/src/enrollment.rs b/packages/d2b-zone-routing/src/enrollment.rs index b93f6516b..710e4acb0 100644 --- a/packages/d2b-zone-routing/src/enrollment.rs +++ b/packages/d2b-zone-routing/src/enrollment.rs @@ -1,6 +1,6 @@ //! The Zone enrollment admission shape (`ADR046-routing-016`). //! -//! `zone-bootstrap` and `zone-enroll` are the two `d2b. zone. v3.ZoneService` +//! `zone-bootstrap` and `zone-enroll` are the two `d2b.zone.v3.ZoneService` //! methods that place a Guest agent: the one-time IKpsk2 bootstrap that //! consumes the allocator-issued single-use PSK, and the enrolled `Noise_KK` //! enrollment that commits the sealed enrollment record and admits the peer. diff --git a/packages/d2b-zone-routing/src/resolver.rs b/packages/d2b-zone-routing/src/resolver.rs index 552c3df0c..b5987e635 100644 --- a/packages/d2b-zone-routing/src/resolver.rs +++ b/packages/d2b-zone-routing/src/resolver.rs @@ -607,7 +607,7 @@ mod tests { fn sealing_rejects_a_subtree_attached_outside_the_sealed_scope() { let error = SealedZoneTopology::seal( zone(&["k0"]), - // k9. k0 is never declared as a child, so k1. k9. k0 would attach an + // k9.k0 is never declared as a child, so k1.k9.k0 would attach an // unknown subtree. vec![edge(&["k9", "k0"], &["k1", "k9", "k0"])], ) @@ -629,8 +629,8 @@ mod tests { #[test] fn a_descendant_matches_its_nearest_sealed_ancestor_not_the_root() { let topology = sealed(); - // deep. k2. k1. k0 is not sealed; the longest suffix is k2. k1. k0, and the - // shorter suffixes k1. k0 and k0 must not win. + // deep.k2.k1.k0 is not sealed; the longest suffix is k2.k1.k0, and the + // shorter suffixes k1.k0 and k0 must not win. assert_eq!( topology.longest_suffix_match(&zone(&["deep", "k2", "k1", "k0"])), Some(&zone(&["k2", "k1", "k0"])) @@ -720,8 +720,8 @@ mod tests { fn an_unsealed_descendant_resolves_to_its_sealed_ancestor_entrypoint() { let resolver = ZoneEntrypointResolver::new(sealed()); let engine = seeded_engine(); - // deep. k2. k1. k0 has no sealed row and no projection of its own; the - // sealed k2. k1. k0 owns it and is the entrypoint the engine routes to. + // deep.k2.k1.k0 has no sealed row and no projection of its own; the + // sealed k2.k1.k0 owns it and is the entrypoint the engine routes to. let request = allowed_request(zone(&["deep", "k2", "k1", "k0"])); let ZoneEntrypointResolution::Resolved { entrypoint_zone, diff --git a/packages/d2b-zone-routing/src/service.rs b/packages/d2b-zone-routing/src/service.rs index 2832e8c17..8c61e4ad4 100644 --- a/packages/d2b-zone-routing/src/service.rs +++ b/packages/d2b-zone-routing/src/service.rs @@ -125,7 +125,7 @@ macro_rules! redacted_debug { pub(crate) use redacted_debug; -/// The closed set of `d2b. zone. v3.ZoneService` methods. +/// The closed set of `d2b.zone.v3.ZoneService` methods. /// /// The inventory is frozen here in full. Every method has a landed handler. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -500,7 +500,7 @@ struct AdmittedEnrollment { child: ZonePath, } -/// The `d2b. zone. v3.ZoneService` handler for one Zone. +/// The `d2b.zone.v3.ZoneService` handler for one Zone. /// /// The Zone runtime instantiates exactly one of these per Zone. It composes /// [`ZoneEntrypointResolver`] over the sealed topology with a caller-supplied @@ -1839,7 +1839,7 @@ mod tests { #[test] fn construction_rejects_a_topology_the_seal_rejects() { - // k9. k0 is never declared as a child, so the row would attach a + // k9.k0 is never declared as a child, so the row would attach a // subtree outside the sealed scope. assert_eq!( ZoneServiceServer::new( diff --git a/packages/d2b/src/context.rs b/packages/d2b/src/context.rs index 9f7388ec4..bfc077bf0 100644 --- a/packages/d2b/src/context.rs +++ b/packages/d2b/src/context.rs @@ -3594,7 +3594,7 @@ mod tests { // 60s is a 12x headroom over that budget: wide enough that scheduling // delay cannot trip it on any normally-loaded machine, finite enough - // that inflation beyond ~12x (e. g., an ms-misread-as-seconds budget + // that inflation beyond ~12x (e.g., an ms-misread-as-seconds budget // like 5000ms read as 500s) fails on the measurement. Smaller // inflations - a 10x arithmetic error to 50s, or a copy-paste to the // 30s request lifetime - land below the ceiling by design: catching diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index 7e63ebd20..85e57a7a0 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -33,7 +33,7 @@ use serde_json::{Value, json}; /// The Provider projection commands the parser carries as static variants. /// /// A projected command is named by the declaring Provider's own -/// `cliProjection. topLevel` (`d2b provider inspect`), which no compile-time +/// `cliProjection.topLevel` (`d2b provider inspect`), which no compile-time /// table can enumerate, so clap holds one static variant per projection /// Provider and the projection binding admits exactly these names in place of /// a built-in command. They are parser carriers, not resource knowledge: the diff --git a/packages/d2b/src/doctor.rs b/packages/d2b/src/doctor.rs index b757d486b..3aa1eb853 100644 --- a/packages/d2b/src/doctor.rs +++ b/packages/d2b/src/doctor.rs @@ -1,9 +1,9 @@ //! `d2b host doctor --read-only` checks. //! //! Each check is a passive, read-only probe: -//! - `broker_ready` - connect to `/run/d2b/priv. sock`, or verify the +//! - `broker_ready` - connect to `/run/d2b/priv.sock`, or verify the //! private socket exists and correctly rejects this unprivileged caller. -//! - `daemon_ready` - connect to `/run/d2b/public. sock`. +//! - `daemon_ready` - connect to `/run/d2b/public.sock`. //! - `metrics_endpoint` - `GET /metrics` over the canonical //! operator-configured external Prometheus URL (see //! `docs/reference/daemon-metrics.md`). The scrape endpoint is optional; @@ -11,7 +11,7 @@ //! posture so local host health stays clean until the metrics listener //! is enabled. //! - `signoz-ui-endpoint` - when observability is enabled, read -//! `_observability. signozUrl` from `vms.json` and probe the SigNoz +//! `_observability.signozUrl` from `vms.json` and probe the SigNoz //! health endpoint. //! - `otel_host_bridge_runner` - inspect daemon-persisted //! `pidfd-table.json` for a registration with role @@ -78,12 +78,12 @@ impl DoctorStatus { /// One row in the doctor's `checks[]` array. #[derive(Debug, Clone)] pub(crate) struct DoctorCheck { - /// Stable kebab-case identifier (e. g. `broker-ready`). + /// Stable kebab-case identifier (e.g. `broker-ready`). pub name: &'static str, pub status: DoctorStatus, pub detail: String, /// Optional structured payload that the JSON renderer merges - /// into the per-check object (e. g. runner counts). + /// into the per-check object (e.g. runner counts). pub data: Option, } @@ -1593,7 +1593,7 @@ fn is_d2b_bridge_name(name: &str) -> bool { } /// For each declared d2b bridge, query -/// `net. ipv6.conf..disable_ipv6` via `sysctl`. +/// `net.ipv6.conf..disable_ipv6` via `sysctl`. /// /// - **Fail** if any bridge returns `0` (IPv6 active). /// - **Pass** if all bridges return `1`. diff --git a/packages/d2b/src/exec_client.rs b/packages/d2b/src/exec_client.rs index c4365d895..52261f639 100644 --- a/packages/d2b/src/exec_client.rs +++ b/packages/d2b/src/exec_client.rs @@ -1,7 +1,7 @@ //! CLI-side `d2b vm exec` owner-connection FSM + host terminal safety. //! //! `d2b vm exec` establishes one Process/EphemeralProcess resource owner over -//! the daemon `public. sock`, then drives the authenticated named stream with +//! the daemon `public.sock`, then drives the authenticated named stream with //! (`WriteStdin`/`ReadOutput`/`Signal`/`Resize`/`Wait`/`Close`) operations. The //! CLI never opens a new connection per op and never allocates a host PTY - //! the guest owns the PTY (helper-exec). This module is the pure FSM + @@ -25,7 +25,7 @@ use serde_json::Value; use crate::terminal_client::{TerminalHostIo, TerminalSignalSource, TerminalTransport}; // Reserved exec CLI exit codes. Guest WIFEXITED 0-255 codes pass through -// and CAN collide with these reserved numbers (e. g. a guest that exits 70 vs. +// and CAN collide with these reserved numbers (e.g. a guest that exits 70 vs. // the old-generation transport class); `--json` disambiguates via // `source`/`reason`/`guestExitCode`/`transportExitCode`. These deliberately // avoid the pre-existing CLI exit codes 2/3/33/78. @@ -209,7 +209,7 @@ pub fn exit_for_kind(kind: &str) -> (i32, ExecFailureSource) { (EXIT_EXEC_AUTH, ExecFailureSource::ComponentSession) } // The daemon's admin gate refused the caller before any guest contact - // (caller not in `d2b. site. adminUsers`). It is an authorization + // (caller not in `d2b.site.adminUsers`). It is an authorization // failure, NOT an internal bug - map it to the AUTH reserved code so // it does not fall through to the internal (42) default. "authz-not-admin" => (EXIT_EXEC_AUTH, ExecFailureSource::ComponentSession), diff --git a/packages/d2b/src/host_validate.rs b/packages/d2b/src/host_validate.rs index e8cfd6ae3..1b226b7bd 100644 --- a/packages/d2b/src/host_validate.rs +++ b/packages/d2b/src/host_validate.rs @@ -4,7 +4,7 @@ //! This module ships the operator-facing one-command preflight that //! must run after a fresh `nixos-rebuild switch` to record the //! per-wave validation evidence the readiness assertions consume. -//! (`d2b. daemonExperimental. enable` defaults `true` and is no +//! (`d2b.daemonExperimental.enable` defaults `true` and is no //! longer evidence-auto-flipped - there is no default to flip - but it //! still functionally gates the daemon control plane; setting it //! `false` reverts the host to the unsupported pre-daemon legacy @@ -39,7 +39,7 @@ //! and external hardware). Instead, it lets the operator attest that //! the validators were run by issuing the evidence record as a //! single composite operation. Per-wave validators that already write -//! their own evidence records (e. g. `tests/minijail-validator-swtpm.sh` +//! their own evidence records (e.g. `tests/minijail-validator-swtpm.sh` //! → `p1-swtpm.json`) continue to do so; this verb is the umbrella //! preflight that produces the per-wave `.json` records the //! readiness option consumes. @@ -63,7 +63,7 @@ pub(crate) const DEFAULT_EVIDENCE_DIR: &str = "/var/lib/d2b/validated"; /// `tests/host-validate-verb-eval.sh` enforces parity. #[derive(Debug, Clone, Copy)] pub(crate) struct WaveSpec { - /// Wave id, e. g. `"p1"` or `"w5Fu"`. Matches the file basename the + /// Wave id, e.g. `"p1"` or `"w5Fu"`. Matches the file basename the /// readiness option consumes (`/var/lib/d2b/validated/.json`). pub wave: &'static str, /// Short human-readable summary of what the wave covers. @@ -185,7 +185,7 @@ pub(crate) enum WaveStatus { /// At least one declared validator script is missing. Missing, /// No validators are declared for this wave (informational - - /// e. g. `p6`/`p7` whose readiness signal is gate-output, not a + /// e.g. `p6`/`p7` whose readiness signal is gate-output, not a /// per-host script). NoValidators, /// Apply mode only: evidence record was written successfully. @@ -193,7 +193,7 @@ pub(crate) enum WaveStatus { /// Apply mode only: evidence write was skipped because the wave /// is `Missing` or because `--wave ` filtered it out. Skipped, - /// Apply mode only: evidence write failed (e. g. permission + /// Apply mode only: evidence write failed (e.g. permission /// denied). The detail field carries the underlying error. WriteFailed, } @@ -218,7 +218,7 @@ pub(crate) struct WaveReport { pub status: WaveStatus, /// Per-validator presence map: `(basename, present)`. pub validators: Vec<(String, bool)>, - /// Human-readable detail (e. g. evidence path written, error + /// Human-readable detail (e.g. evidence path written, error /// reason). pub detail: String, /// On `Attested`, the absolute evidence path. Otherwise `None`. diff --git a/packages/d2b/tests/auth_status_contract.rs b/packages/d2b/tests/auth_status_contract.rs index 64120dc43..801911e05 100644 --- a/packages/d2b/tests/auth_status_contract.rs +++ b/packages/d2b/tests/auth_status_contract.rs @@ -8,7 +8,7 @@ //! * `auth status --json` deserializes strictly into //! `d2b_contracts_control::cli_output::AuthStatusOutputV2` (`deny_unknown_fields` makes a successful //! typed deserialize equivalent to the schema check the bash gate did via -//! docs/reference/cli-output/auth-status. schema.json); +//! docs/reference/cli-output/auth-status.schema.json); //! * the per-role allowed/denied subcommand authz surface matches the binary's //! contract (launcher gets `up` but keeps `audit` denied; `none` stays //! read-only; admin gains `audit` and denies nothing); @@ -85,7 +85,7 @@ fn parse_json(out: &std::process::Output) -> AuthStatusOutputV2 { ); // Strict schema validation: AuthStatusOutputV2 (and its nested DTOs) are // deny_unknown_fields, so a successful typed deserialize is equivalent to - // validating against docs/reference/cli-output/auth-status. schema.json. + // validating against docs/reference/cli-output/auth-status.schema.json. serde_json::from_slice(&out.stdout).unwrap_or_else(|err| { panic!( "auth status --json did not match the AuthStatusOutputV2 schema: {err}\noutput:\n{}", @@ -101,7 +101,7 @@ fn auth_status_roles_match_schema_and_authz() { let none_fixture = write_fixture(tmp.path(), "auth-none.json", NONE_FIXTURE); let admin_fixture = write_fixture(tmp.path(), "auth-admin.json", ADMIN_FIXTURE); - // Case 1 - launcher: gains launcher-allowed verbs (e. g. `list`) but keeps + // Case 1 - launcher: gains launcher-allowed verbs (e.g. `list`) but keeps // `audit` denied, and no retired v2 verbs are reported as allowed. let launcher = parse_json(&run_auth_status( diff --git a/packages/d2bd-runtime/src/autostart.rs b/packages/d2bd-runtime/src/autostart.rs index f0e3cd1c0..98f7234c0 100644 --- a/packages/d2bd-runtime/src/autostart.rs +++ b/packages/d2bd-runtime/src/autostart.rs @@ -47,7 +47,7 @@ use tokio::task::JoinSet; /// see meaningful progress in the journal before the next batch /// starts" on the small-fleet desktop deployments d2b targets. /// Operators with bigger fleets override via -/// `d2b. daemon. autostart. parallelism` (NixOS) → +/// `d2b.daemon.autostart.parallelism` (NixOS) → /// `AutostartConfig::parallelism`. pub const DEFAULT_PARALLELISM: usize = 3; @@ -56,7 +56,7 @@ pub const DEFAULT_PARALLELISM: usize = 3; /// can be re-derived without re-loading the world. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct VmAutostartEntry { - /// VM name as it appears in `_manifest. vms`. + /// VM name as it appears in `_manifest.vms`. pub vm: String, /// Env this VM belongs to, if any. Net VMs use the env from /// their `sys--net` name (= `Some("")`); workloads @@ -93,7 +93,7 @@ impl AutostartPlan { } /// Tunables for [`execute_autostart`]. Mirrors the -/// `d2b. daemon. autostart.*` NixOS option set. +/// `d2b.daemon.autostart.*` NixOS option set. #[derive(Debug, Clone, Copy)] pub struct AutostartConfig { /// Concurrency cap N (number of VMs started in parallel within @@ -254,14 +254,14 @@ fn vm_is_autostart_eligible(vm: &d2b_core::manifest_v04::VmEntry) -> bool { } /// Drive a built plan. Net VMs are started first (up to -/// `config. parallelism` in parallel); once that phase settles, any +/// `config.parallelism` in parallel); once that phase settles, any /// env whose net VM ended in a degraded/failed state has its /// workloads marked `Outcome::Degraded` *without dispatch*, and /// the remaining workloads are started (again, up to -/// `config. parallelism` in parallel). +/// `config.parallelism` in parallel). /// /// The function is safe to invoke repeatedly: each VM is gated on -/// `starter. is_running(...)`, so a re-entry on SIGHUP or +/// `starter.is_running(...)`, so a re-entry on SIGHUP or /// bundle-reload short-circuits to `Outcome::AlreadyRunning` for /// every VM that's still supervised. pub async fn execute_autostart( @@ -402,7 +402,7 @@ where let pre_degraded = Arc::clone(&pre_degraded); let request_txs = Arc::clone(&request_txs); join_set.spawn(async move { - // Pre-degraded VMs (e. g. flagged by the kernel-module-check + // Pre-degraded VMs (e.g. flagged by the kernel-module-check // pass) short-circuit before anything else. if pre_degraded.contains(&entry.vm) { return ( diff --git a/packages/d2bd-runtime/src/ch_api.rs b/packages/d2bd-runtime/src/ch_api.rs index 50471234f..70360adf7 100644 --- a/packages/d2bd-runtime/src/ch_api.rs +++ b/packages/d2bd-runtime/src/ch_api.rs @@ -31,7 +31,7 @@ pub enum ChApiError { MalformedResponse, /// The API answered a non-2xx status code. Rejected(u16), - /// The `vm. info` payload did not deserialize into the expected shape. + /// The `vm.info` payload did not deserialize into the expected shape. InvalidJson(String), } @@ -47,11 +47,11 @@ impl ChApiError { } } -/// The subset of the Cloud Hypervisor `vm. info` payload this crate +/// The subset of the Cloud Hypervisor `vm.info` payload this crate /// consumes; fields absent from the reply stay `None`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ChVmInfo { - /// The VM run state (e. g. `Running`, `Stopped`) as reported by CH. + /// The VM run state (e.g. `Running`, `Stopped`) as reported by CH. pub state: Option, /// The configured vCPU count, when the reply reports one. pub vcpu_count: Option, @@ -59,7 +59,7 @@ pub struct ChVmInfo { pub memory_mib: Option, } -/// Fetch and parse the Cloud Hypervisor `vm. info` payload over the control +/// Fetch and parse the Cloud Hypervisor `vm.info` payload over the control /// socket. /// /// # Errors @@ -108,7 +108,7 @@ pub fn blocking_get_json( split_http_body(&raw) } -/// Raw Cloud Hypervisor `vm. info` payload shape, deserialized at the +/// Raw Cloud Hypervisor `vm.info` payload shape, deserialized at the /// boundary; fields absent from the reply default to `None`. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRaw { @@ -118,7 +118,7 @@ struct ChVmInfoRaw { config: ChVmInfoRawConfig, } -/// Nested `config` object of the raw `vm. info` payload. +/// Nested `config` object of the raw `vm.info` payload. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRawConfig { #[serde(default)] @@ -127,14 +127,14 @@ struct ChVmInfoRawConfig { memory: ChVmInfoRawMemory, } -/// Nested `config. cpus` object of the raw `vm. info` payload. +/// Nested `config.cpus` object of the raw `vm.info` payload. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRawCpus { #[serde(default)] boot_vcpus: Option, } -/// Nested `config. memory` object of the raw `vm. info` payload. +/// Nested `config.memory` object of the raw `vm.info` payload. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] struct ChVmInfoRawMemory { #[serde(default)] diff --git a/packages/d2bd-runtime/src/console_session.rs b/packages/d2bd-runtime/src/console_session.rs index 1cd69fa9b..f4fd026e9 100644 --- a/packages/d2bd-runtime/src/console_session.rs +++ b/packages/d2bd-runtime/src/console_session.rs @@ -207,7 +207,7 @@ impl ConsoleSessionTable { } impl ConsoleSessionTable { - /// drainer. Replaces any existing session (e. g. after a VM restart). + /// drainer. Replaces any existing session (e.g. after a VM restart). pub fn register_session(&mut self, vm: String, session: ConsoleSession) { // Abort any previous drainer for this VM. if let Some(mut old) = self.sessions.remove(&vm) { @@ -372,7 +372,7 @@ pub struct ConsoleReadOutput { /// Spawn a drainer task for a Cloud Hypervisor serial socket. /// /// The task connects to `socket_path` (CH's `--serial socket=`), reads -/// bytes into the ring, and reconnects if CH closes the connection (e. g. after +/// bytes into the ring, and reconnects if CH closes the connection (e.g. after /// a VM reboot). The ring's `notify` is triggered on each new chunk. The task /// runs on the caller-provided runtime handle (owned by the daemon binary). pub fn spawn_ch_serial_drainer( @@ -408,7 +408,7 @@ pub fn spawn_ch_serial_drainer( }) } -/// Spawn a drainer task for a pre-opened async stream (e. g. the host end of a +/// Spawn a drainer task for a pre-opened async stream (e.g. the host end of a /// qemu-media socketpair, converted to `tokio::net::UnixStream`). /// /// Unlike [`spawn_ch_serial_drainer`], this does not reconnect after EOF: the diff --git a/packages/d2bd-runtime/src/daemon_audit.rs b/packages/d2bd-runtime/src/daemon_audit.rs index fdedcbaff..b8a0376a4 100644 --- a/packages/d2bd-runtime/src/daemon_audit.rs +++ b/packages/d2bd-runtime/src/daemon_audit.rs @@ -274,7 +274,7 @@ pub enum DaemonEvent { }, /// Emitted when a `vm start` long-lived runner node fast-fails because /// the spawned runner terminated (or its PID was reused) BEFORE its - /// readiness signal fired - the `tpm. enable` first-run wedge fix. + /// readiness signal fired - the `tpm.enable` first-run wedge fix. /// /// Bounded by construction: carries ONLY the VM name, the closed /// `role_id` of the failed node, a closed reason kind, the optional @@ -284,7 +284,7 @@ pub enum DaemonEvent { VmStartRunnerExited { /// VM name (matches the `vmStart` request). vm: String, - /// Role id of the runner node that exited (e. g. `swtpm`, + /// Role id of the runner node that exited (e.g. `swtpm`, /// `ch-runner`). role_id: String, /// Closed reason kind: exited vs PID-reused. diff --git a/packages/d2bd-runtime/src/daemon_config.rs b/packages/d2bd-runtime/src/daemon_config.rs index 8b8788a9e..8d50214f4 100644 --- a/packages/d2bd-runtime/src/daemon_config.rs +++ b/packages/d2bd-runtime/src/daemon_config.rs @@ -85,7 +85,7 @@ pub struct DaemonConfig { pub realm_identity_config_path: PathBuf, /// Concurrency cap for the autostart pass that runs on daemon /// startup. Default `3`. - /// Mirrors `d2b. daemon. autostart. parallelism`. + /// Mirrors `d2b.daemon.autostart.parallelism`. #[serde(default = "default_autostart_parallelism")] pub autostart_parallelism: usize, /// Default provider graceful-shutdown wait before forced cleanup. diff --git a/packages/d2bd-runtime/src/exec_session.rs b/packages/d2bd-runtime/src/exec_session.rs index 73d23c624..e158b5928 100644 --- a/packages/d2bd-runtime/src/exec_session.rs +++ b/packages/d2bd-runtime/src/exec_session.rs @@ -2,7 +2,7 @@ //! //! The daemon owns a long-lived, authenticated Process named-stream client per //! exec session. The CLI establishes the resource owner through the -//! admin-gated `public. sock` route, then sends one correlated named-stream +//! admin-gated `public.sock` route, then sends one correlated named-stream //! frame per [`ExecOp`]. A dedicated worker thread (current-thread tokio //! runtime) owns the authenticated client, the target-local process resource, //! the authoritative stdin offset, and the monotone control sequence; it is @@ -136,7 +136,7 @@ pub enum ExecEstablishError { Timeout, OldGeneration, Capability, - /// Guest accepted the handshake but rejected the create (e. g. exec + /// Guest accepted the handshake but rejected the create (e.g. exec /// disabled, root denied, unsupported mode). Guest(ProcessOpError), } @@ -831,7 +831,7 @@ pub struct WorkerCommand { pub type EstablishReply = Result; /// Owner-socket teardown seam for the terminal-cleanup reaper. -/// `reap` forces the owner connection's reader to unblock (e. g. by shutting +/// `reap` forces the owner connection's reader to unblock (e.g. by shutting /// down the socket) so the session slot is released after the command has gone /// terminal and the cleanup TTL elapsed. It MUST be idempotent and MUST NOT be /// called while the command is still live. diff --git a/packages/d2bd-runtime/src/kernel_module_check.rs b/packages/d2bd-runtime/src/kernel_module_check.rs index eb4335484..586ae05d3 100644 --- a/packages/d2bd-runtime/src/kernel_module_check.rs +++ b/packages/d2bd-runtime/src/kernel_module_check.rs @@ -101,14 +101,14 @@ pub const OPTIONAL_TPM: &str = "tpm_vtpm_proxy"; /// One row in [`ModuleCheckReport::optional_missing`]. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct OptionalMissing { - /// Kernel module name (e. g. `nvidia`, `usbip_host`, + /// Kernel module name (e.g. `nvidia`, `usbip_host`, /// `tpm_vtpm_proxy`). pub module: String, /// VMs whose declared features depend on this module. Empty - /// for purely host-wide optionals (e. g. `nvidia` with no + /// for purely host-wide optionals (e.g. `nvidia` with no /// graphics VMs declared). pub affected_vms: BTreeSet, - /// Short human-readable reason (e. g. "graphics VMs may fall + /// Short human-readable reason (e.g. "graphics VMs may fall /// back to software rendering"). Suitable for log + the /// operator reference. pub reason: String, @@ -310,7 +310,7 @@ pub fn check_kernel_modules( } // Optional rows. Each is recorded only when (a) the gate is - // satisfied (e. g. there is at least one graphics VM) and + // satisfied (e.g. there is at least one graphics VM) and // (b) the module is NOT present. let mut optional_missing: Vec = Vec::new(); @@ -388,7 +388,7 @@ pub const PROC_MODULES_PATH: &str = "/proc/modules"; pub const SYS_MODULE_DIR: &str = "/sys/module"; /// Side-effecting wrapper: read `/proc/modules` + `/sys/module` + the -/// `modules. builtin` text file, then dispatch to [`check_kernel_modules`]. +/// `modules.builtin` text file, then dispatch to [`check_kernel_modules`]. /// /// Module detection order (union of all three sources): /// 1. `/proc/modules` - loadable modules currently inserted. @@ -397,10 +397,10 @@ pub const SYS_MODULE_DIR: &str = "/sys/module"; /// not appear in `/proc/modules`. This is the primary fix for /// false-positive "missing" reports on hosts where virtio modules /// are compiled in (`=y`) rather than loadable (`=m`). -/// 3. `/lib/modules/$(uname -r)/modules. builtin` - text list of +/// 3. `/lib/modules/$(uname -r)/modules.builtin` - text list of /// built-in modules for offline/early-boot coverage, merged into /// the `builtin` set. -/// 4. `/boot/config-$(uname -r)` / `/proc/config. gz` - kernel config +/// 4. `/boot/config-$(uname -r)` / `/proc/config.gz` - kernel config /// for `CONFIG_*=y` built-in detection (existing path). /// /// On any read failure we conservatively treat the failed source as @@ -422,7 +422,7 @@ pub fn run_kernel_module_check(resolver: &BundleResolver) -> ModuleCheckReport { } let loaded = read_loaded_modules_at(Path::new(PROC_MODULES_PATH), Path::new(SYS_MODULE_DIR)); - // Step 3: modules. builtin text file (uname handled internally). + // Step 3: modules.builtin text file (uname handled internally). let modules_builtin = read_builtin_modules_with_fallback(); // Step 4: kernel config (existing path). @@ -773,7 +773,7 @@ mod tests { } // ------------------------------------------------------------------ - // /sys/module and modules. builtin detection tests + // /sys/module and modules.builtin detection tests // ------------------------------------------------------------------ /// Virtio modules compiled as =y appear in `/sys/module//` but diff --git a/packages/d2bd-runtime/src/metrics.rs b/packages/d2bd-runtime/src/metrics.rs index ac7d6d41e..6839e1907 100644 --- a/packages/d2bd-runtime/src/metrics.rs +++ b/packages/d2bd-runtime/src/metrics.rs @@ -6,7 +6,7 @@ //! `docs/reference/daemon-metrics.md`), and avoiding a new transitive //! dependency keeps the supply-chain audit footprint minimal. The //! exposition format we emit is the documented -//! [text-format v0.0.4](https://prometheus. io/docs/instrumenting/exposition_formats/#text-based-format) +//! [text-format v0.0.4](https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format) //! that every Prometheus-compatible scraper accepts. //! //! The module is the canonical source of truth for the metric diff --git a/packages/d2bd-runtime/src/pidfs_probe.rs b/packages/d2bd-runtime/src/pidfs_probe.rs index 7987cab2c..afbd364d7 100644 --- a/packages/d2bd-runtime/src/pidfs_probe.rs +++ b/packages/d2bd-runtime/src/pidfs_probe.rs @@ -8,7 +8,7 @@ //! check relies on pidfs (per-pidfd `(st_dev, st_ino)` stability //! across PID reuse). Static eval gates //! (`tests/v1.1-kernel-floor-eval.sh`) catch the easy case (operator -//! flake declares an older kernel via `boot. kernelPackages`); this +//! flake declares an older kernel via `boot.kernelPackages`); this //! runtime probe catches the hard case - a custom-built kernel at //! >= 6.9 that strips pidfs support. //! diff --git a/packages/d2bd-runtime/src/public_projection.rs b/packages/d2bd-runtime/src/public_projection.rs index efa4e8466..a42871a79 100644 --- a/packages/d2bd-runtime/src/public_projection.rs +++ b/packages/d2bd-runtime/src/public_projection.rs @@ -302,7 +302,7 @@ fn public_pidfd_role_prefix_state(pidfd_table: &PidfdTable, vm: &str, prefix: &s /// Liveness of the qemu-media runner role as the public media row reports it. /// /// The pidfd table is the authority for both this projection and the -/// per-service state map, so the typed state and the `services. qemuMedia` +/// per-service state map, so the typed state and the `services.qemuMedia` /// string cannot disagree. pub fn public_qemu_media_runner_state(pidfd_table: &PidfdTable, vm: &str) -> QemuMediaRunnerState { if public_pidfd_role_running(pidfd_table, vm, RunnerRole::QemuMedia.as_str()) { diff --git a/packages/d2bd-runtime/src/readiness.rs b/packages/d2bd-runtime/src/readiness.rs index c806bc9b6..c8a404ec5 100644 --- a/packages/d2bd-runtime/src/readiness.rs +++ b/packages/d2bd-runtime/src/readiness.rs @@ -309,7 +309,7 @@ pub async fn wait_for_readiness_async( /// fail-fast, or treat as terminal. #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ProcState { - /// The process is alive in the given state character (e. g. + /// The process is alive in the given state character (e.g. /// 'S' sleeping, 'R' running, 'D' uninterruptible sleep, /// 'Z' zombie awaiting reap, 'X' dead). Alive(char), @@ -522,7 +522,7 @@ mod unix_socket_readiness_tests { /// No `unsafe` code: child processes are created via /// `std::process::Command`. Rust's `Child` does not call `waitpid` on /// drop, so an exited child stays in 'Z' state until the test calls -/// `child. wait()` for cleanup. +/// `child.wait()` for cleanup. #[cfg(test)] #[cfg(target_os = "linux")] mod wait_for_one_shot_exit_tests { diff --git a/packages/d2bd-runtime/src/runtime_process.rs b/packages/d2bd-runtime/src/runtime_process.rs index 3e513d21c..963855561 100644 --- a/packages/d2bd-runtime/src/runtime_process.rs +++ b/packages/d2bd-runtime/src/runtime_process.rs @@ -162,10 +162,10 @@ pub fn validate_lock_parent( // `root:d2b 1770` (sticky bit, world-closed) with explicit POSIX // ACLs (g::r-x, u:d2bd:rwx, m::rwx) so: // - launcher users (members of `d2b`) traverse via the effective - // group ACL entry (g::r-x) to reach `/run/d2b/public. sock` + // group ACL entry (g::r-x) to reach `/run/d2b/public.sock` // (mode 0660, group d2b); // - d2bd gets rwx via the named-user ACL entry without owning - // the directory, so root-owned subdirs (e. g. /run/d2b/vms) + // the directory, so root-owned subdirs (e.g. /run/d2b/vms) // do not trigger the systemd-tmpfiles unsafe-path-transition guard; // - the sticky bit prevents d2bd from unlinking those root-owned // children. @@ -335,7 +335,7 @@ pub fn bind_public_socket(path: &Path, identity: &RuntimeIdentity) -> Result std::path::PathBuf { } /// Tiny RFC-3339 UTC formatter (`YYYY-MM-DDTHH:MM:SSZ`) so we can -/// stamp `DaemonVersionFile. started_at` without pulling in `chrono` +/// stamp `DaemonVersionFile.started_at` without pulling in `chrono` /// as a new top-level dependency. The daemon's startup is the only /// caller; precision to the second is sufficient. pub fn chrono_like_rfc3339() -> String { @@ -751,7 +751,7 @@ mod runtime_acl_tests { /// `expect_root_owned_parent=true` chgrp actually mutated the /// socket's gid. The caller is a member of every group `getgroups` /// returns, so `chown(None, Some(supp_gid))` is permitted by POSIX. - /// Returns `None` when the runtime has only the primary gid (e. g. + /// Returns `None` when the runtime has only the primary gid (e.g. /// inside minimal CI containers); the caller skips the assertion in /// that case with a visible log line so the gap is documented /// rather than silently passing. diff --git a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs index 299a796e8..9e39ae653 100644 --- a/packages/d2bd-runtime/src/ssh_host_key_preflight.rs +++ b/packages/d2bd-runtime/src/ssh_host_key_preflight.rs @@ -267,14 +267,14 @@ pub fn check_sshd_host_keys(vm: &str, keys_dir: &Path) -> Result<(), SshdHostKey } let mode = meta.permissions().mode() & 0o7777; // Review note: when the file has POSIX ACL named - // entries (e. g. from the activation script's per-keyfile + // entries (e.g. from the activation script's per-keyfile // `u:virtiofsd_uid:r` grant required by ADR 0021 broker- // pre-NS virtiofsd reading the 0400 root:root host key), // Linux stores the mask in the file's group-mode bits. The // group's BASE perm (in the ACL's ACL_GROUP_OBJ entry) is // still ---, but stat() reports 0440 because the mask is r. // Accept either 0400 (no ACL) or 0440 (ACL with mask r--) - // when the file has a system. posix_acl_access xattr; reject + // when the file has a system.posix_acl_access xattr; reject // any other mode. let mode_ok = if mode == EXPECTED_KEY_MODE { true @@ -309,7 +309,7 @@ pub fn check_sshd_host_keys(vm: &str, keys_dir: &Path) -> Result<(), SshdHostKey } /// Returns true when the file has a -/// `system. posix_acl_access` xattr (i. e. the activation script's +/// `system.posix_acl_access` xattr (i.e. the activation script's /// `setfacl -m u:UID:r` grant for ADR 0021 broker-pre-NS /// virtiofsd has been applied). Used by the preflight to /// distinguish 0o0440-with-ACL (legitimate) from 0o0440-without-ACL diff --git a/packages/d2bd-runtime/src/supervisor/pidfd_table.rs b/packages/d2bd-runtime/src/supervisor/pidfd_table.rs index a1aa6f9f3..b83572dfa 100644 --- a/packages/d2bd-runtime/src/supervisor/pidfd_table.rs +++ b/packages/d2bd-runtime/src/supervisor/pidfd_table.rs @@ -272,7 +272,7 @@ impl PidfdTable { self } - /// Set the `BrokerReapLog` on an already-constructed table (e. g. + /// Set the `BrokerReapLog` on an already-constructed table (e.g. /// after `restore_from_disk`). pub fn set_broker_reap_log(&self, log: Arc) { let _ = self.broker_reap_log.set(log); @@ -598,7 +598,7 @@ impl PidfdTable { /// Duplicate the daemon-held pidfd for `(vm, role)` for a read-only /// liveness poll. Returns the dup'd fd plus the registered /// `(pid, start_time_ticks)`, or `None` when no entry is registered - /// (e. g. rollback already removed it) or the dup fails. + /// (e.g. rollback already removed it) or the dup fails. /// /// This OBSERVES only - it never removes the entry. All /// deregistration stays in the teardown / rollback path. diff --git a/packages/d2bd-runtime/src/typed_error.rs b/packages/d2bd-runtime/src/typed_error.rs index d8581d070..933845388 100644 --- a/packages/d2bd-runtime/src/typed_error.rs +++ b/packages/d2bd-runtime/src/typed_error.rs @@ -583,7 +583,7 @@ pub enum TypedError { /// Refusal raised by the VM-start preflight for `sys--net` VMs /// when the on-disk /// dnsmasq.conf hash diverges from the bundle's expectation. - /// `env` is the env scope (e. g. `corp`, `personal`, `obs`); + /// `env` is the env scope (e.g. `corp`, `personal`, `obs`); /// `expected` and `actual` are 64-char lowercase SHA-256 hex /// digests. The mismatch indicates the bundle was updated but /// the dnsmasq render step did not rerun - rebuild the bundle @@ -697,7 +697,7 @@ pub enum TypedError { ConsoleSessionTableFull { vm: String, }, - /// A realm workload canonical target (`workload. realm. d2b`) was supplied + /// A realm workload canonical target (`workload.realm.d2b`) was supplied /// but is not present in the realm workload index. The caller must use a /// declared workload target or a known legacy VM name. WorkloadTargetNotFound { diff --git a/packages/d2bd/src/audio_host_controller.rs b/packages/d2bd/src/audio_host_controller.rs index 7cc6a3433..a32c8c215 100644 --- a/packages/d2bd/src/audio_host_controller.rs +++ b/packages/d2bd/src/audio_host_controller.rs @@ -19,9 +19,9 @@ //! ## PipeWire node targeting //! //! The vhost-user-sound sidecar is launched with -//! `PIPEWIRE_PROPS={ application. name = "d2b-" ... }`. The controller +//! `PIPEWIRE_PROPS={ application.name = "d2b-" ... }`. The controller //! resolves the live PipeWire node id with `pw-dump`, filtering by -//! `application. name` plus `media. class` so speaker and microphone controls do +//! `application.name` plus `media.class` so speaker and microphone controls do //! not target the same ambiguous node name. //! //! ## Credential posture diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index abf4c5c1f..791bf7e5c 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -550,7 +550,7 @@ struct ServerState { pidfd_table: Arc, broker_reap_log: Arc, metrics_registry: Arc, - /// Daemon-side audit log for supervisor events (e. g. api-ready + /// Daemon-side audit log for supervisor events (e.g. api-ready /// timeout) that are not emitted by the broker. daemon_audit: Arc, /// In-process Process-session table (caps + opaque handles) for @@ -5512,7 +5512,7 @@ async fn run_startup_autostart(state: &ServerState, kernel_module_degraded: &BTr let _ = resolver; } -/// Thin wrapper used by the `options. once` test path and by direct +/// Thin wrapper used by the `options.once` test path and by direct /// unit-test callers: authorizes the peer (SO_PEERCRED), then runs the /// authorized connection body. The production accept loop authorizes the /// peer itself (before admission) and calls @@ -10405,7 +10405,7 @@ fn cloud_hypervisor_api_socket(argv: &[String]) -> Option { /// The producer-derived Endpoint generation one guest-control Endpoint /// carries. /// -/// The old daemon publication stage stamped `status. resource. endpointGeneration` +/// The old daemon publication stage stamped `status.resource.endpointGeneration` /// from the Endpoint row's own generation; `Endpoint` is a converted type, so /// a manager row has no durable status to read and the row's committed /// generation is the same value the old stage published. @@ -11387,7 +11387,7 @@ async fn live_cached_guest_session_generation( } /// Re-adopt every assignment the directory holds for one Guest after a -/// (re) connect: the target layer is the only place that re-binds a handle to +/// (re)connect: the target layer is the only place that re-binds a handle to /// the live session generation, and a source the Guest cannot confirm is left /// for its owning actor to realize again (F5). async fn adopt_guest_target_assignments( @@ -14707,7 +14707,7 @@ async fn open_resource_plane( // v3 resource plane (U9/U10): assemble each Zone's manager plane once the // generation publication is committed, and publish the whole table into - // `state. v3_planes` before any runtime activates. The runtime's + // `state.v3_planes` before any runtime activates. The runtime's // manager-backed API service resolves its manager client + watch hub from // that table, so a Zone whose plane is not published yet cannot activate. let mut v3_planes: BTreeMap> = @@ -17039,7 +17039,7 @@ fn request_cgroup_kill_if_populated( // its own processes.json placement (the same derivation the old typed // CgroupKill arm performed broker-side from the bundle) and the // kill-cgroup kernel kills exactly that leaf, refusing any path outside - // the delegated d2b. slice subtree. + // the delegated d2b.slice subtree. let Some(cgroup_path) = role_cgroup_path(state, vm, role_id) else { tracing::warn!(vm = %vm, role = %role_id, "broker CgroupKill request skipped: no cgroup placement"); return; @@ -18150,7 +18150,7 @@ fn host_prep_role_id_from_bundle_ref( /// Dispatch a broker request for one host-prep DAG step where the broker /// may return a typed response -/// (e. g. `CreatePersistentTap`, `SetBridgePortFlags`) rather than +/// (e.g. `CreatePersistentTap`, `SetBridgePortFlags`) rather than /// the canonical `Ack`. Treats any non-`Error` response as success /// and surfaces `Error` responses through the same launcher-side /// redaction path used by `dispatch_broker_ack_request`. Any fd @@ -18319,7 +18319,7 @@ fn execute_host_prep_dag( use d2b_host::host_prep_dag::HostPrepStepKind; const VERB: &str = "vm start"; // Resolve the per-VM state directory once (used by daemon-native - // step handlers that need filesystem context, e. g. the + // step handlers that need filesystem context, e.g. the // ssh-host-key preflight). The v3 zone-native Guest resource carries // no stateDir surface (the v2 manifest is an empty stub), so there is // no clean stateDir source; daemon-native handlers gracefully no-op. @@ -21167,7 +21167,7 @@ fn build_public_list( } = load_public_request_artifacts(state, false, true)?; // Resolve the `vm` filter through the workload index so callers can - // use a canonical target (`vm. realm. d2b`) or unambiguous workload id. + // use a canonical target (`vm.realm.d2b`) or unambiguous workload id. let resolved_vm_filter = resolve_vm_filter_target(request.vm.as_deref(), workload_index.as_ref(), &manifest) .map_err(typed_error_from_resolution_error)?; @@ -23811,7 +23811,7 @@ pub(crate) mod detached_exec_routing_tests { } } -/// The public. sock accept loop is serial: it accepts one connection, runs +/// The public.sock accept loop is serial: it accepts one connection, runs /// `handle_connection`, then accepts the next. A Process resource owner /// connection is long-lived, so `handle_connection` MUST hand it off to a /// spawned owner thread and return immediately - otherwise the single accept @@ -24172,7 +24172,7 @@ mod accept_loop_concurrency_tests { handle_a.join().expect("accept-loop thread joins"); // Prove the owner session is STILL HELD OPEN (the body has not torn - // down) at the moment handle_connection has already returned - i. e. the + // down) at the moment handle_connection has already returned - i.e. the // dispatch was genuinely off-loop, concurrent with the accept loop. { let (lock, _cv) = &*shared; @@ -24184,7 +24184,7 @@ mod accept_loop_concurrency_tests { ); } - // --- Connection B: a SECOND public. sock request is accepted and served + // --- Connection B: a SECOND public.sock request is accepted and served // while connection A's owner session is still held open. --- let (server_b, client_b) = seqpacket_pair(); let client_b = std::thread::spawn(move || { @@ -29128,7 +29128,7 @@ mod broker_dispatch_tests { ); } - /// Wiring test: verify that `ServerState. daemon_audit` is wired with a + /// Wiring test: verify that `ServerState.daemon_audit` is wired with a /// `DaemonAuditLog` that can capture `DaemonEvent::ApiReadyTimeout` /// events, and that the event serialises with the expected field shape. /// @@ -29618,7 +29618,7 @@ mod broker_dispatch_tests { // HAZARD: the stateless readiness helper treats an EMPTY predicate // slice as TRIVIALLY ready - it returns Ok without running any // probe. `spawn_and_check_process_alive` (the process-alive fast - // path, e. g. `--no-wait-api`) delegates the node to + // path, e.g. `--no-wait-api`) delegates the node to // `spawn_and_wait_ready(vm, node, &[], budget)` with exactly this // empty slice. If a ComponentSessionHealth node ever reached // `wait_for_readiness`, an absent/auth-failing component-session @@ -29635,7 +29635,7 @@ mod broker_dispatch_tests { // `spawn_and_check_process_alive` does NOT take the LongLived // process-alive-only short-circuit (which registers a node as alive // after spawn with no probe at all). It falls through to - // `spawn_and_wait_ready`, whose `node. role == ComponentSessionHealth` + // `spawn_and_wait_ready`, whose `node.role == ComponentSessionHealth` // special case runs `wait_for_component_session_health` BEFORE the empty // readiness slice can reach the trivially-ready `wait_for_readiness`. // Were ComponentSessionHealth ever made LongLived, or the interception @@ -30115,7 +30115,7 @@ mod broker_dispatch_tests { /// Creates bundle artifacts for a minimal obs-enabled VM start test. /// The obs VM has an empty process DAG (no nodes) so the supervisor DAG /// succeeds immediately without a broker connection. The bundle is wired - /// with `_observability. enabled=true` and `vmName="obs"` so + /// with `_observability.enabled=true` and `vmName="obs"` so /// `dispatch_broker_vm_start` reaches the OtelHostBridge readiness gate. #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn write_obs_enabled_bundle_artifacts(root: &Path) -> ArtifactPaths { @@ -30259,7 +30259,7 @@ mod broker_dispatch_tests { /// is bypassed entirely and the `degraded` field MUST NOT appear in the /// success envelope. Prevents false-positive `degraded` from leaking into /// VM starts that were explicitly requested without the API-readiness wait - /// (e. g., CLI `--no-wait-api` flag). + /// (e.g., CLI `--no-wait-api` flag). #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn vm_start_non_obs_vm_has_no_degraded_field_in_envelope() { diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index 2f2b92f87..1e5913ce5 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -1969,7 +1969,7 @@ mod tests { /// call. The forwarded request leg carries the caller's descriptor over /// SCM_RIGHTS; the rendezvous validates it against the wire declarations /// and hands it to the declared handler, so this handler reading it back - /// proves the round trip through the real socket and the provider envelope. to + /// proves the round trip through the real socket and the provider envelope.to struct FdEchoHandler; #[async_trait::async_trait] @@ -2487,7 +2487,7 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") use d2bd_runtime::unix_transport::write_frame_with_fds; /// Forward one invocation with SCM_RIGHTS attachments on the request /// frame, the way the broker's forwarder does once the request leg - /// carries fds. to + /// carries fds.to fn forward_with_fds( socket_path: &Path, operation: &str, @@ -3746,7 +3746,7 @@ serde_json::from_slice(&frame).expect("the reply is a ForwardOperationResponse") // one-shot publication dial (started by the test after this returns) // can never race the bind: a dial before the bind would error, the // daemon would never retry, and the accept below would block the - // test's `broker. join()` forever. + // test's `broker.join()` forever. let listener = bind_public_socket(&socket_path, &test_identity()) .expect("bind the test broker socket"); std::thread::spawn(move || { diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index 7a1c2766b..ebaa4d531 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -3149,7 +3149,7 @@ pub(crate) async fn resolve_device_worker_launch( // and no Guest target, so the row's own launch identity names no VM // by construction. The coherent VM scope is the owning Device's // Guest owner - the same derivation `tpm_device_targets_vm` requires - // (`Device. metadata. ownerRef == Guest/`) and the TPM + // (`Device.metadata.ownerRef == Guest/`) and the TPM // shared-provider effects mint their `VmId` from. A Device with no // Guest owner is the genuinely unresolvable case. let vm_name = match launch.vm() { @@ -3240,7 +3240,7 @@ pub(crate) async fn resolve_device_worker_launch( let settings = device_gpu_settings(ctx, &owner_key).await?; // The Wayland socket the sidecar renders into is projected by // the trusted bundle from the site's own Wayland session - // (`d2b. site. waylandUser` / `waylandDisplay`, see + // (`d2b.site.waylandUser` / `waylandDisplay`, see // `nixos-modules/site-json.nix`). A bundle without the // artifact, or a headless site, leaves the slot unbound and // the launch refuses with its own code instead of naming a @@ -3561,7 +3561,7 @@ fn device_state_dir( /// /// Only an absent Provider extension decodes to the Provider's bounded /// default. A present settings payload that does not decode as the closed -/// `device-gpu. d2bus. org` extension refuses with its own code instead: folding +/// `device-gpu.d2bus.org` extension refuses with its own code instead: folding /// it into the default made an undecodable declaration indistinguishable from /// a Device that declares nothing, and the default's context classes /// (including `CrossDomain`) are wider than anything the Device declared. @@ -3579,7 +3579,7 @@ fn decode_device_gpu_settings( } /// The owning Device's declared GPU settings (the closed -/// `device-gpu. d2bus. org` Device extension); a Device that declares none +/// `device-gpu.d2bus.org` Device extension); a Device that declares none /// keeps the Provider's own bounded default. async fn device_gpu_settings( ctx: &mut ResourceContext, @@ -3615,7 +3615,7 @@ fn video_nvidia_posture( /// The host Wayland socket the GPU sidecar renders into. /// /// The trusted bundle projects it (`site.json`, emitted from the site's own -/// `d2b. site. waylandUser` / `waylandDisplay`), so the daemon never derives +/// `d2b.site.waylandUser` / `waylandDisplay`), so the daemon never derives /// `/run/user//...` itself: the daemon's own `/run/user` is its runtime /// directory, not the session user's. `None` - a bundle that predates the /// artifact, or a site without a Wayland session - keeps the slot unbound so @@ -3644,7 +3644,7 @@ fn device_runtime_socket( socket_runtime_dir.join("vms").join(vm_name).join(file_name) } -/// The per-VM video-decoder socket (`/run/d2b-video//video. sock`): the +/// The per-VM video-decoder socket (`/run/d2b-video//video.sock`): the /// video module's own `RuntimeDirectory` and the guest's /// `--vhost-user-media socket=` argument name it, so the video runtime root is /// a sibling of the daemon's runtime root. @@ -6050,7 +6050,7 @@ mod tests { // -- Launched-runner pidfd-table registration ----------------------------- // - // A failed launch (e. g. a readiness-probe envelope timeout) stops the + // A failed launch (e.g. a readiness-probe envelope timeout) stops the // spawned child but never clears the daemon's pidfd-table slot for its // (vm, role). The next launch's observer registration would hit the // duplicate guard and be swallowed, leaving the probe and the stop path diff --git a/packages/d2bd/src/provider_lifecycle.rs b/packages/d2bd/src/provider_lifecycle.rs index 21813843c..2b698dfc2 100644 --- a/packages/d2bd/src/provider_lifecycle.rs +++ b/packages/d2bd/src/provider_lifecycle.rs @@ -994,7 +994,7 @@ impl ProviderRuntime { })? } - /// (Re) publish one effect service row on the zone's supervisor, taking + /// (Re)publish one effect service row on the zone's supervisor, taking /// effect at the composition point the plane publishes declared /// services. A republish of a live service bumps the generational /// binding revision and rebuilds the actor from the new row (KTD5). diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index c2f4676e8..1f1bd7d3a 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -18,7 +18,7 @@ //! ## Spec store path decision //! //! The store is a plain daemon-owned file under -//! `/zones//spec-store. sqlite3`. It is never opened +//! `/zones//spec-store.sqlite3`. It is never opened //! through a broker fd handover: the broker-provisioned //! `/zones/` directory is owned by the zone-store //! principal, so a spec store placed there fails to open with @@ -1789,7 +1789,7 @@ pub struct ConstructionInputs { pub zone_token: BoundedToken, /// The zone's daemon-owned spec-store directory /// (`/zones/`); the spec store lives at - /// `spec-store. sqlite3` underneath it. + /// `spec-store.sqlite3` underneath it. pub spec_store_dir: PathBuf, pub authority: ZoneAuthorityInputs, /// Committed `Provider` identities (KTD7) keyed by canonical reference, @@ -1867,7 +1867,7 @@ pub user_facets: UserEffectFacets, /// The daemon-supplied facet set the Guest family's effects /// implementation is built from (U10):the zone's manager view (live /// rows, committed Provider identities, and the controller-session - /// generation) andthe Cloud Hypervisor controller session, supplied + /// generation)andthe Cloud Hypervisor controller session, supplied /// through the composition root. The family never receives a /// daemon-built effect port (R2). pub guest_facets: GuestEffectFacets, @@ -2425,7 +2425,7 @@ impl AudioMediatorSource for DaemonAudioMediatorSource { /// Production `GuestOwnerIdentitySource` (KTD7): the pre-v3 plane owns `Guest`, /// so its durable rows are the authority for a Guest-owned Process launch's -/// owner uid. The old store resolved every row's `metadata. ownerRef` to the +/// owner uid. The old store resolved every row's `metadata.ownerRef` to the /// owner row's uid and the old descriptor composer read that linkage into the /// launch ticket; the converted manager row cannot carry it for an /// unconverted owner, so the Process effects resolve the same durable value @@ -2670,7 +2670,7 @@ pub enum PlaneError { /// (`CORE_CONTROLLER_HOST_REF` in the old plane). const CORE_HOST_TARGET_NAME: &str = "host-system"; -/// The canonical `spec. executionRef` resolver (U13). +/// The canonical `spec.executionRef` resolver (U13). /// /// A stored row's `spec` is the ResourceSpec object, so this reads exactly /// the `executionRef` base field the resource contracts' `PlacementAnchor:: @@ -2716,7 +2716,7 @@ impl core::fmt::Debug for ResourcePlaneV3 { impl ResourcePlaneV3 { /// The per-zone spec store path decision (documented in the module - /// header): `spec-store. sqlite3` under the daemon-owned + /// header): `spec-store.sqlite3` under the daemon-owned /// `/zones/` directory. pub fn spec_store_path(spec_store_dir: &Path) -> PathBuf { spec_store_dir.join("spec-store.sqlite3") @@ -3424,7 +3424,7 @@ impl ResourcePlaneV3 { let plan = partition_nix_bundle(&self.zone, bundle, &self.store).await?; let subject = nix_bundle_subject(&bundle.integrity.content_hash); let mut report = BundleIngestReport::default(); - // Owners before owned. A bundle row that declares `metadata. ownerRef` + // Owners before owned. A bundle row that declares `metadata.ownerRef` // is ensured as that owner's child, so the manager links ownership by // uid the way R8 defines it: the Core `Provider` driver reads its // owned controller `Process` rows through that link (an unlinked row diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index fe0b3e238..f4dea943e 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -310,7 +310,7 @@ pub(crate) async fn bridge_manager_row( /// /// Role/RoleBinding/Zone/Provider and the subject rows are manager rows, so /// without them a RoleBinding whose Role row moved returns -/// `AuthorizationUnavailable` and its subjects are dropped - i. e. the Zone's +/// `AuthorizationUnavailable` and its subjects are dropped - i.e. the Zone's /// committed policy would empty out. A miss stays the loud, fail-closed /// compile failure it is today. /// @@ -2471,7 +2471,7 @@ impl AuthenticatedResourceSession for CloudHypervisorResourceSession { // row has no durable status to write - the row's actor owns // status (R11). The controller's layered status is captured // by the effect call that drove this session and published as - // the row's `status. resource` projection; a session with no + // the row's `status.resource` projection; a session with no // capture point (an explicit lifecycle relist) acknowledges // the write without persisting it. Converted children never // never receive a provider-written status either: the Process and @@ -4155,8 +4155,8 @@ impl ZoneResourceRuntime { /// reference. /// /// The pre-v3 store linked every owned row to its owner by uid: it - /// resolved the row's `metadata. ownerRef` to the owner row's uid and - /// carried that value in `record. owner_uid` + /// resolved the row's `metadata.ownerRef` to the owner row's uid and + /// carried that value in `record.owner_uid` /// (`@@REDB-D@@::transaction::resolve_uid_in_read`), and the /// old Process descriptor composer read it as the launch ticket's owner /// identity. `Guest` stays on this plane, so a converted Process row @@ -6079,7 +6079,7 @@ fn child_publication_gate( /// Whether one committed child row's status reports a failure the row's own /// actor will retry: the manager view stamps a failed actor's closed -/// classification under `status. resource. driverFailure` (the converted plane +/// classification under `status.resource.driverFailure` (the converted plane /// has no durable status, R11/AE6), so this is where a reader can tell a /// child's retry in progress from a terminal child failure. fn row_status_failure_is_retryable(resource: &Value) -> bool { @@ -10022,7 +10022,7 @@ where /// R11/AE6 leaves the public Resource API no status write path, so the /// daemon's operator admission is the last layer that sees a submission: both /// spellings a request may use (`status`, or the nested -/// `resource. status`) are read here, and this is the enforcement point for +/// `resource.status`) are read here, and this is the enforcement point for /// `ADR-046-telemetry-audit-and-support`, section "Host resource status". The /// `system-core` reconciler sets `isolationPosture` and /// `isolationPostureMessage` on every user-only Host from the spec alone, and diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 8c4b769e4..c364c7633 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -404,7 +404,7 @@ impl ProductionSharedProviderEffects { } /// The old-shape document of one resource (`spec`, `metadata`, live - /// `status. phase`) from the manager view. + /// `status.phase`) from the manager view. async fn resource_value( &self, target: &ResourceRef, @@ -560,7 +560,7 @@ struct NetworkReadiness { } /// The Network child port over the manager-routed surface: every upsert is a -/// `ctx. ensure_child` (F1) and every read is the live row. +/// `ctx.ensure_child` (F1) and every read is the live row. struct NetworkChildPort<'a> { effects: &'a ProductionSharedProviderEffects, request: &'a SharedProviderEffectRequest<'a>, @@ -696,7 +696,7 @@ fn child_ref(resource_type: &str, name: &str) -> ResourceRef { /// The spec-level content projection check (old /// `network_config_content_projection_ready` without its persisted-status -/// terms: the materialization evidence lived in `status. resource`, which R11 +/// terms: the materialization evidence lived in `status.resource`, which R11 /// deletes; the Volume actor's live Ready phase is the equivalent gate). fn network_config_projection_present(value: &Value, volume_uid: &ResourceUid) -> bool { let Some(provider) = value.pointer("/spec/provider") else { @@ -1080,9 +1080,9 @@ impl ProductionSharedProviderEffects { .ok_or(SharedProviderEffectError::InvalidResource)?; // The attached row's authoritative zone is the zone its key // resolved under (`resource_value` reads the plane for - // `self. zone`); the stored metadata carries no zone, so the old + // `self.zone`); the stored metadata carries no zone, so the old // `/metadata/zone` read was always `None` and refused every - // attachment unconditionally. `request. zone` is external input, + // attachment unconditionally. `request.zone` is external input, // so the fence stays: a request naming a zone the resolved rows // cannot be in is refused. if self.zone.as_str() != request.zone.as_str() { @@ -1133,9 +1133,9 @@ impl ProductionSharedProviderEffects { if !attached { continue; } - // The committed Guest rows were resolved under `self. zone` (the + // The committed Guest rows were resolved under `self.zone` (the // type-scoped manager list selects the plane's own zone), so the - // row's authoritative zone is `self. zone`; the fence compares it + // row's authoritative zone is `self.zone`; the fence compares it // against the request zone instead of a projection-synthesised // field. if self.zone.as_str() != request.zone.as_str() { diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 8a7aa7fbc..23dc77571 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -788,17 +788,17 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 10890, + "line": 10911, "reason": "awaited through tokio::time::timeout" }, { "file": "packages/d2bd/src/composition.rs", - "line": 26624, + "line": 26649, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 27021, + "line": 27046, "reason": "synchronous lock acquisition, no await while the guard is held" }, { diff --git a/packages/xtask/src/blocking_census.rs b/packages/xtask/src/blocking_census.rs index 74b401935..d09a32df7 100644 --- a/packages/xtask/src/blocking_census.rs +++ b/packages/xtask/src/blocking_census.rs @@ -69,7 +69,7 @@ pub enum EntryKind { /// clippy matches on (everything after the final `::`), and the counting /// class. pub struct DeniedApi { - /// Fully-qualified API path as configured, e. g. `std::sync::Mutex::lock`. + /// Fully-qualified API path as configured, e.g. `std::sync::Mutex::lock`. pub path: String, /// The bare tail clippy matches on: everything after the final `::`. pub tail: String, @@ -323,7 +323,7 @@ pub struct SuppressionSite { pub blanket: bool, /// `#[expect(...)]` rather than `#[allow(...)]`. pub expect: bool, - /// The banned lint, e. g. `clippy::disallowed_methods`. + /// The banned lint, e.g. `clippy::disallowed_methods`. pub lint: String, /// The attribute's `reason = "..."` value, when present. pub reason: Option, @@ -639,7 +639,7 @@ fn reason_in_args(args: &[String]) -> Option { /// suppression inventory. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct CrateCensus { - /// Crate directory relative to the repo root, e. g. `packages/d2b-broker`. + /// Crate directory relative to the repo root, e.g. `packages/d2b-broker`. pub crate_dir: String, /// Package name from the manifest. pub package_name: String, @@ -672,7 +672,7 @@ struct CensusFile { split: SplitContext, } -/// The workspace member paths the root manifest declares, e. g. +/// The workspace member paths the root manifest declares, e.g. /// `packages/d2b-broker`. #[allow(clippy::disallowed_methods, reason = "CLI-only path")] fn workspace_member_paths(repo_root: &Path) -> Result, String> { @@ -874,7 +874,7 @@ fn first_diagnostic(stderr: &str) -> Option { /// before any warning is considered; `None` when the stream has no /// error-level record and no warning that carries a primary span (a /// spanless warning is dropped, so a spanless-warning-only stream also -/// yields `None` - e. g. a cargo-level failure that never reached rustc). +/// yields `None` - e.g. a cargo-level failure that never reached rustc). fn first_json_diagnostic(json: &str) -> Option { let mut first_warning: Option = None; let mut first_spanless_error: Option = None; @@ -931,7 +931,7 @@ fn first_json_diagnostic(json: &str) -> Option { /// (run_clippy) consults it before accepting a warning-only JSON pick. fn first_stderr_error(stderr: &str) -> Option { // First error-level header, span or spanless: cargo-level failures - // (e. g. `error: failed to run custom build command`) never carry a + // (e.g. `error: failed to run custom build command`) never carry a // `--> file:line` span, but they are the real cause when the JSON // stream holds only warnings. let lines: Vec<&str> = stderr.lines().collect(); diff --git a/packages/xtask/src/changelog.rs b/packages/xtask/src/changelog.rs index 30a728fa7..8f9d8c8a7 100644 --- a/packages/xtask/src/changelog.rs +++ b/packages/xtask/src/changelog.rs @@ -1,6 +1,6 @@ -//! Fragment assembler for the `changelog. d/` directory. +//! Fragment assembler for the `changelog.d/` directory. //! -//! Concurrent branches each drop one fragment file into `changelog. d/` +//! Concurrent branches each drop one fragment file into `changelog.d/` //! instead of appending to the shared `## [Unreleased]` block in //! `CHANGELOG.md`. Every branch then writes a file no other branch touches, //! so the changelog stops being a guaranteed merge conflict whenever more @@ -30,7 +30,7 @@ pub const CHANGELOG_FILE: &str = "CHANGELOG.md"; /// Transaction directory for an in-flight fold, created in the resolved /// repository root - the real directory holding `CHANGELOG.md` and -/// `changelog. d/` - so every rename into and out of it is atomic and stays on +/// `changelog.d/` - so every rename into and out of it is atomic and stays on /// one filesystem. A fixed (non-PID) name lets a later invocation discover an /// interrupted transaction and recover it. const TXN_DIR: &str = ".changelog-fold-txn"; @@ -131,7 +131,7 @@ pub struct FragmentSection { pub entries: Vec, } -/// A parsed `changelog. d/.md` fragment. +/// A parsed `changelog.d/.md` fragment. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Fragment { /// Fragment file name, used for ordering and error messages. @@ -390,7 +390,7 @@ pub struct Outcome { /// /// The Bazel entry point (`bazel run --config=local //packages/xtask:xtask`) /// reaches the checkout through a symlink forest: `CHANGELOG.md` and -/// `changelog. d/` under the execroot are links into the real workspace. Reads +/// `changelog.d/` under the execroot are links into the real workspace. Reads /// follow those links, but renaming the folded changelog *onto* `CHANGELOG.md` /// replaces the link and leaves the real file untouched, so the fold would /// consume every fragment and write nowhere (issue #519). Resolving both paths @@ -454,7 +454,7 @@ impl FoldTree { ))); } // An absent fragment directory is no fragments at all, the same - // no-op a repository without `changelog. d/` has always been. + // no-op a repository without `changelog.d/` has always been. Err(err) if err.kind() == std::io::ErrorKind::NotFound => root.join(FRAGMENT_DIR), Err(err) => { return Err(FoldError::single(format!( @@ -745,7 +745,7 @@ fn read_journal(txn: &Path) -> Option { /// recovery finishes forward by discarding the transaction (the reserved /// fragments are already consumed). Any earlier state - or an unreadable /// journal - means the promotion did not durably happen, so recovery rolls -/// back: reserved fragments return to `changelog. d/` and the original changelog +/// back: reserved fragments return to `changelog.d/` and the original changelog /// is restored from its backup. Either way the tree ends fully folded or fully /// unfolded, never half-consumed. /// @@ -896,7 +896,7 @@ fn finish_forward( } /// Undo an uncommitted transaction: return every reserved fragment to -/// `changelog. d/` and restore the original changelog from its backup, then +/// `changelog.d/` and restore the original changelog from its backup, then /// remove the transaction directory. Restorative steps run before the backup is /// consumed so a crash mid-rollback stays recoverable on the next pass. Errors /// are surfaced, never swallowed. @@ -1762,7 +1762,7 @@ mod tests { #[test] #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] fn fold_repo_consumes_fragments_through_a_symlinked_fragment_directory() { - // The execroot reaches `changelog. d/` through a link too: the fold must + // The execroot reaches `changelog.d/` through a link too: the fold must // reserve the real fragments and leave the link in place. let repo = TempRepo::new("fragment-dir-symlink"); repo.write_changelog(CHANGELOG); @@ -2032,7 +2032,7 @@ mod tests { repo.write_fragment("feature-a.md", "### Added\n\n- from a\n"); crash_at_boundary(&repo, FoldStage::AfterReserve(0)); - // The reserved fragment is out of changelog. d/ and inside the txn. + // The reserved fragment is out of changelog.d/ and inside the txn. assert!( repo.fragment_names().is_empty(), "fragment reserved, not in place" diff --git a/packages/xtask/src/nix_inventories.rs b/packages/xtask/src/nix_inventories.rs index bc2c2ca2b..3caa260c1 100644 --- a/packages/xtask/src/nix_inventories.rs +++ b/packages/xtask/src/nix_inventories.rs @@ -246,8 +246,8 @@ fn core_schema_file(resource_type: &str) -> String { /// Split one qualified ResourceType into its schema namespace and local name. /// -/// A qualified type is `.d2bus. org.`; the committed artifact -/// is `.d2bus. org_.schema.json`. +/// A qualified type is `.d2bus.org.`; the committed artifact +/// is `.d2bus.org_.schema.json`. fn qualified_schema_parts( resource_type: &str, ) -> Result<(&str, &str), Box> { diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index cc7a1955a..a660d5471 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -3534,6 +3534,18 @@ const SHARED_FAMILY_KNOWLEDGE_RATCHET: &[SharedFamilyKnowledgeExemption] = &[ family: "activation-nixos", retires_with: "permanent: wire vocabulary crossing CLI/daemon/broker boundaries; no shared crate may depend on a provider crate", }, + SharedFamilyKnowledgeExemption { + module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", + token: "network_local", + family: "network-local", + retires_with: "permanent: the local-vm workload limit is family-named shared wire vocabulary and no shared crate may depend on a provider crate. The signal is an assembled name, so it is invisible to a text search for the token: the module contains no occurrence of network_local, which is why this row is required rather than removable", + }, + SharedFamilyKnowledgeExemption { + module: "packages/d2b-contracts/src/unsafe_local_workloads.rs", + token: "volume_local", + family: "volume-local", + retires_with: "permanent: the local-vm workload limit is family-named shared wire vocabulary and no shared crate may depend on a provider crate. The signal is an assembled name, so it is invisible to a text search for the token: the module contains no occurrence of volume_local, which is why this row is required rather than removable", + }, SharedFamilyKnowledgeExemption { module: "packages/d2b-broker/src/live_handlers.rs", token: "activation_nixos", @@ -7069,7 +7081,7 @@ fn packages_tokens(line: &str) -> Vec { end += 1; } // A `<...>` immediately after the run marks a naming-template - // placeholder (e. g. `packages/d2b-provider--/`), + // placeholder (e.g. `packages/d2b-provider--/`), // not a resolvable citation; skip it. if bytes.get(end) == Some(&b'<') { search = &rest[end..]; @@ -8824,7 +8836,7 @@ enum CommittedScopeClass { /// stale. A committed-scope check cannot police every file outside these /// classes without encoding the whole plan's touch surface, so it polices /// the crate set and the declared artifact roots, the two surfaces the plan -/// names; every other surface (docs/plans, changelog. d, tests/, Nix +/// names; every other surface (docs/plans, changelog.d, tests/, Nix /// modules, Bazel files, ...) is out of its scope by construction. struct CommittedScopeEntry { crate_name: &'static str, diff --git a/packages/xtask/src/provider_packaging.rs b/packages/xtask/src/provider_packaging.rs index 475756b42..f59d3d52f 100644 --- a/packages/xtask/src/provider_packaging.rs +++ b/packages/xtask/src/provider_packaging.rs @@ -9,7 +9,7 @@ //! nine field groups the specification's "Package catalog" section enumerates, //! flattened into the exact field names `nixos-modules/provider-catalog.nix` //! validates every entry against. The catalog itself is compiled in Nix from -//! `d2b. artifacts.` declarations; only its shape is generated here, so that +//! `d2b.artifacts.` declarations; only its shape is generated here, so that //! the module and any later Rust consumer cannot drift apart silently. //! //! Three absences in that section are the design rather than gaps, and the diff --git a/packages/xtask/src/resource_type_authority.rs b/packages/xtask/src/resource_type_authority.rs index 4b6639bd0..071a4974b 100644 --- a/packages/xtask/src/resource_type_authority.rs +++ b/packages/xtask/src/resource_type_authority.rs @@ -339,7 +339,7 @@ fn render_artifacts( /// The declared standard (unqualified) ResourceTypes in committed order, with /// a declared standard type absent from the committed order appended after it -/// in sorted order. A qualified type (`.d2bus. org.`) carries +/// in sorted order. A qualified type (`.d2bus.org.`) carries /// a dot and never enters the standard registry. fn declared_standard_types(registry: &AuthorityRegistry) -> Vec { let mut declared = BTreeSet::new(); diff --git a/packages/xtask/src/zone_schema.rs b/packages/xtask/src/zone_schema.rs index 45b15382b..1cab80c52 100644 --- a/packages/xtask/src/zone_schema.rs +++ b/packages/xtask/src/zone_schema.rs @@ -4,7 +4,7 @@ //! Two generators read this one model: //! //! * `gen-zone-schemas` writes -//! `docs/reference/schemas/v3/core. d2bus. org_.schema.json`, +//! `docs/reference/schemas/v3/core.d2bus.org_.schema.json`, //! the committed JSON Schema for the emitted canonical resource object. //! * `gen-zone-nix-options` writes the committed generated Nix modules under //! `nixos-modules/generated/`. @@ -38,7 +38,7 @@ const CREDENTIAL_REF_PATTERN: &str = "^Credential/[a-z][a-z0-9-]{0,62}$"; /// `ADR-046-resources-zone-control.md` section 3.3: the transport Provider ref /// is required, explicit, and its local name always begins with `transport-`. const TRANSPORT_PROVIDER_REF_PATTERN: &str = "^Provider/transport-[a-z][a-z0-9-]{0,52}$"; -/// Any same-Zone `/` ref, used by `metadata. ownerRef`. +/// Any same-Zone `/` ref, used by `metadata.ownerRef`. const RESOURCE_REF_PATTERN: &str = "^(?:[A-Z][A-Za-z0-9]{0,62}|[a-z][a-z0-9-]{0,62}\\.d2bus\\.org\\.[A-Z][A-Za-z0-9]{0,62})/[a-z][a-z0-9-]{0,62}$"; /// Role posture `principalRef` spelling: the host-account identity the /// committed principal allocation names. It is not a ResourceRef. @@ -75,7 +75,7 @@ enum FieldKind { min: i64, max: i64, }, - /// `types. ints. positive`: the specification states a positive integer with + /// `types.ints.positive`: the specification states a positive integer with /// no declared ceiling, so no ceiling is invented here. PositiveInt, /// Closed object with a fixed, fully-defaulted member list. From 564bd616610f87241e9fd8952051f530c2088e2e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 01:58:52 -0700 Subject: [PATCH 707/726] docs(audit): drop the rust-skills audit corpus from the shipped tree The 2026-09-24 rust-skills audit record does not belong in the merged tree. Its own review pass, bound to the previous head, found that the 965-row findings table does not render, that the wave-gate notes contradict the table they summarise, and that a large set of anchors resolves from nowhere - and that its reproduction scripts live in a gitignored directory, so its central claim cannot be checked from the repository at all. That is working material for the remediation, not documentation a reader of d2b needs. This removes the 114 files this branch added under that directory - the report, the lane contract, the 110 lane corpus files, the verification record, and the ledger - and updates the plan that pointed at them, so the committed tree carries no reference to a path it no longer has. The other two audit trees under docs/audits/ predate this branch and are untouched. The remediation itself is unaffected: every finding's outcome was already carried by its changelog fragment and by the code, which is what the gate exercises. The gate set is the record that survives. --- .../2026-09-24-rust-skills-audit/README.md | 2828 ----------------- .../U1-constraints.md | 961 ------ .../VERIFICATION.md | 553 ---- .../lane/X1-supply-chain.md | 69 - .../lane/X2-generated-boundary.md | 45 - .../lane/X3-cross-crate-duplication.md | 44 - .../lane/d2b-audit.md | 88 - .../lane/d2b-broker-composition.md | 84 - .../lane/d2b-broker-p1.md | 75 - .../lane/d2b-broker-p2.md | 100 - .../lane/d2b-broker-p3.md | 83 - .../lane/d2b-broker-p4.md | 95 - .../lane/d2b-broker-p5.md | 82 - .../lane/d2b-broker-p6.md | 101 - .../lane/d2b-broker-p7.md | 87 - .../lane/d2b-bus-p1.md | 83 - .../lane/d2b-bus-p2.md | 87 - .../lane/d2b-contracts-broker.md | 87 - .../lane/d2b-contracts-control.md | 90 - .../lane/d2b-contracts-provider-p1.md | 81 - .../lane/d2b-contracts-provider-p2.md | 85 - .../lane/d2b-contracts-resource-p1.md | 87 - .../lane/d2b-contracts-resource-p2.md | 77 - .../lane/d2b-contracts-zone-session-p1.md | 77 - .../lane/d2b-contracts-zone-session-p2.md | 87 - .../lane/d2b-contracts.md | 81 - .../lane/d2b-core-controller-p1.md | 76 - .../lane/d2b-core-controller-p2.md | 88 - .../lane/d2b-core-p1.md | 96 - .../lane/d2b-core-p2.md | 91 - .../lane/d2b-host.md | 87 - .../lane/d2b-p1.md | 71 - .../lane/d2b-p2.md | 82 - .../lane/d2b-p3.md | 78 - .../lane/d2b-process-conformance.md | 87 - .../lane/d2b-provider-activation-nixos.md | 86 - .../lane/d2b-provider-audio-pipewire.md | 89 - .../lane/d2b-provider-clipboard-wayland-p1.md | 93 - .../lane/d2b-provider-clipboard-wayland-p2.md | 106 - .../lane/d2b-provider-config-nixos.md | 82 - .../lane/d2b-provider-credential-entra.md | 75 - ...2b-provider-credential-managed-identity.md | 88 - .../d2b-provider-credential-secret-service.md | 84 - .../lane/d2b-provider-credential.md | 73 - .../lane/d2b-provider-device-gpu.md | 93 - .../lane/d2b-provider-device-security-key.md | 82 - .../lane/d2b-provider-device-tpm.md | 85 - .../lane/d2b-provider-device-usbip.md | 87 - .../lane/d2b-provider-display-wayland-p1.md | 85 - .../lane/d2b-provider-display-wayland-p2.md | 89 - .../lane/d2b-provider-endpoint.md | 72 - ...d2b-provider-guest-azure-container-apps.md | 89 - ...2b-provider-guest-azure-virtual-machine.md | 97 - .../d2b-provider-guest-cloud-hypervisor.md | 91 - .../lane/d2b-provider-guest-qemu-media.md | 88 - .../lane/d2b-provider-guest.md | 93 - .../lane/d2b-provider-host.md | 77 - .../lane/d2b-provider-network-local.md | 79 - .../lane/d2b-provider-notification-desktop.md | 84 - .../lane/d2b-provider-observability-otel.md | 99 - .../lane/d2b-provider-process-systemd.md | 84 - .../lane/d2b-provider-process.md | 75 - .../lane/d2b-provider-provider.md | 81 - .../lane/d2b-provider-shell-terminal.md | 87 - .../lane/d2b-provider-supervisor.md | 65 - .../lane/d2b-provider-system-core.md | 83 - .../lane/d2b-provider-toolkit-p1.md | 81 - .../lane/d2b-provider-toolkit-p2.md | 85 - .../d2b-provider-transport-azure-relay.md | 97 - .../lane/d2b-provider-transport-vsock.md | 96 - .../lane/d2b-provider-user.md | 77 - .../lane/d2b-provider-volume-binding.md | 73 - .../lane/d2b-provider-volume-local.md | 74 - .../lane/d2b-provider-volume-virtiofs.md | 56 - .../lane/d2b-provider-volume.md | 116 - .../lane/d2b-provider-wayland-policy.md | 103 - .../lane/d2b-provider-zone-link.md | 81 - .../lane/d2b-provider.md | 68 - .../lane/d2b-resource-api-p1.md | 87 - .../lane/d2b-resource-api-p2.md | 72 - .../lane/d2b-resource-client.md | 77 - .../lane/d2b-resource-compiler.md | 83 - .../lane/d2b-resource-runtime-p1.md | 93 - .../lane/d2b-resource-runtime-p2.md | 90 - .../lane/d2b-session-p1.md | 72 - .../lane/d2b-session-p2.md | 89 - .../lane/d2b-session-unix.md | 72 - .../lane/d2b-telemetry.md | 72 - .../lane/d2b-unsafe-local-helper.md | 68 - .../lane/d2b-zone-routing.md | 78 - .../lane/d2bd-p1.md | 78 - .../lane/d2bd-p2.md | 81 - .../lane/d2bd-p3.md | 80 - .../lane/d2bd-p4.md | 86 - .../lane/d2bd-p5.md | 72 - .../lane/d2bd-p6.md | 77 - .../lane/d2bd-p7.md | 83 - .../lane/d2bd-p8.md | 88 - .../lane/d2bd-runtime-p1.md | 86 - .../lane/d2bd-runtime-p2.md | 79 - .../lane/d2bd-runtime-p3.md | 85 - .../lane/d2bd-runtime-p4.md | 112 - .../lane/tail-1.md | 333 -- .../lane/tail-2.md | 331 -- .../lane/tail-3.md | 271 -- .../lane/tail-4.md | 336 -- .../lane/tail-5.md | 337 -- .../lane/tail-6.md | 143 - .../lane/xtask-p1.md | 91 - .../lane/xtask-p2.md | 71 - .../lane/xtask-p3.md | 75 - .../lane/xtask-p4.md | 72 - .../lane/xtask-p5.md | 72 - .../2026-09-24-rust-skills-audit/ledger.md | 1017 ------ ...2-refactor-rust-skills-remediation-plan.md | 4 +- 115 files changed, 1 insertion(+), 15733 deletions(-) delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/README.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p5.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md delete mode 100644 docs/audits/2026-09-24-rust-skills-audit/ledger.md diff --git a/docs/audits/2026-09-24-rust-skills-audit/README.md b/docs/audits/2026-09-24-rust-skills-audit/README.md deleted file mode 100644 index c0f26c5fc..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/README.md +++ /dev/null @@ -1,2828 +0,0 @@ -# Rust skills audit - 16 lenses x 94 crates: consolidated findings, coverage, and remediation input - -**Date:** 2026-09-24 - **Baseline:** `v3` @ `6ebdd4cec` - **Lens revision:** `third_party/agent-skills/rewrite-rs/v0.1.0-alpha.1/skills/`. - -**Method (one paragraph).** A read-only, per-lane audit: 107 crate lanes - 51 part lanes over the 17 largest crates, 50 whole-crate lanes, and 6 tail lanes covering 27 small crates - ran 15 of the 16 rewrite-rs audit lenses over the assigned scope - `src/**` excluding `src/generated/**`, plus `tests/**` for the `test` lens - by running each lens card's seed regexes (U1-constraints.md section c), reading every hit, and recording findings or a `clean` line with seed counts. The `supply` lens is workspace-level (lane X1); the generated boundary is lane X2; cross-crate classes are lane X3. Two lenses-routed lanes judge emitted code rather than crate code: X2 (generated shapes, judged through serde/docs/api/type/err). No code was changed: every finding is a proposal. Anchors are valid at the baseline OID; remediation must re-locate by symbol. - -**Deliverable:** this report, `U1-constraints.md` (the lane contract: protocol, lens cards, constraints ledger, seed matrix, part map), `lane/.md` per lane (the evidence record), `VERIFICATION.md` (independent verification). - -## 1. Executive summary - -| Metric | Value | -| --- | --- | -| Findings total | **965** | -| By severity | high 13 - medium 295 - low 657 | -| By verdict | actionable 923 - needs-contract 25 - policy-confirmed 17 | -| Lane files | 110 (107 crate lanes + X1 supply + X2 generated + X3 cross-crate) | -| Crates with zero findings | 7 of 94 | -| Merge operations (same issue, two lenses/parts) | 57 | - -Findings by lens: - -| lens | findings | lens | findings | -| --- | ---: | --- | ---: | -| `idiom` | 124 | `perf` | 52 | -| `own` | 115 | `conc` | 29 | -| `type` | 82 | `async` | 19 | -| `api` | 138 | `unsafe` | 4 | -| `err` | 94 | `ffi` | 0 | -| `serde` | 40 | `macro` | 4 | -| `obs` | 31 | `test` | 67 | -| `docs` | 143 | `supply` | 23 | - -Top-20 findings (severity, then blast radius; `what` truncated to 160 characters and `|` escaped for the table - sections 2 and 4 carry the full verbatim text): - -| RS id | lens | crate | what | sev | blast | verdict | -| --- | --- | --- | --- | --- | --- | --- | -| RS-0837 | `async` | `d2b-broker` | `cleanup_spawned_runner_after_failure` performs a blocking `waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED)` (no WNOHANG) at runtime.rs:11815, and is called dire | high | wide | actionable | -| RS-0455 | `err` | `d2b-broker` | DispatchAuditContext::from_request panics the broker on a malformed authoritative audit join: both CanonicalAuditDigest::parse(zone_id.expect)...) at runtime.rs | high | wide | actionable | -| RS-0842 | `async` | `d2b-broker` | write_redacted_registry_index_at_path resolves the fixed d2bd group via nss `Group::from_name` synchronously on an executor worker on every registry write (enro | high | wide | actionable | -| RS-0962 | `type` | `X3-cross-crate-duplication` | Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one | high | family | actionable | -| RS-0516 | `err` | `d2b-provider-wayland-policy` | Panic reachable from caller input at the family engine's public boundary: `InteractionDriver::new` parses-and-expects `InteractionDriverArgs.zone: String` (pub | high | family | actionable | -| RS-0840 | `async` | `d2b-broker` | `acquire_handoff_lock` is an `async fn` whose final step is a blocking `nix::fcntl::Flock::lock(file, LockExclusive)` on the executor worker thread; the call is | high | leaf | actionable | -| RS-0841 | `async` | `d2b-broker` | the async `harden()` path (invoked from `live_handlers.rs:3142` on the runtime) calls `apply_ancestor_traverse_acl` -> `run_setfacl_op_on_fd` (sys.rs:1866-1893) | high | leaf | actionable | -| RS-0867 | `test` | `d2b-bus` | emitter_records_only_closed_bus_labels exercises every BusTelemetry method but asserts nothing, and every emit outcome is swallowed by `let _ = self.emit(...)` | high | leaf | actionable | -| RS-0898 | `test` | `d2b-provider-display-wayland` | two registry-handler tests cannot fail on any behavior change: `filtered_globals_preserve_original_global_names` (filter.rs:3213-3224) inserts entries into `adv | high | leaf | actionable | -| RS-0851 | `async` | `d2b-provider-user` | the bounded probe's `discover_local_user` runs blocking NSS lookups (`nix::unistd::User::from_name`, `Group::from_gid`, `Group::from_name`) inside async fns on | high | leaf | policy-confirmed | -| RS-0916 | `test` | `d2b-resource-runtime` | `display_shows_epoch_and_sequence` asserts `rendered.contains("[PHONE]")` on the rendering `e1728000000+42`, an assertion that cannot pass, so the test fails at | high | leaf | actionable | -| RS-0538 | `err` | `d2bd-runtime` | default_audit_join_context panics with `.expect("canonical broker zone digest")` on a wire-supplied digest - a malformed request from the broker client crashes | high | leaf | actionable | -| RS-0925 | `test` | `d2bd-runtime` | `sd_notify_ready_noops_without_notify_socket` (runtime_process.rs:543-546) and `sd_notify_ready_errors_when_socket_is_unreachable` (runtime_process.rs:589-594) | high | leaf | actionable | -| RS-0946 | `supply` | `X1-supply-chain` | nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a sy | medium | wide | actionable | -| RS-0947 | `supply` | `X1-supply-chain` | rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shippe | medium | wide | actionable | -| RS-0950 | `supply` | `X1-supply-chain` | packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2 | medium | wide | actionable | -| RS-0960 | `conc` | `X3-cross-crate-duplication` | parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-ce | medium | wide | policy-confirmed | -| RS-0963 | `err` | `X3-cross-crate-duplication` | Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { | medium | wide | needs-contract | -| RS-0239 | `type` | `d2b-audit` | `EvidenceChain` derives `Deserialize` (evidence_chain.rs:50) while its accessors assume a non-empty identity list: `invoking_identity()` panics via `.last().exp | medium | wide | actionable | -| RS-0838 | `async` | `d2b-broker` | the USB-audit serial HMAC key path runs blocking filesystem syscalls inside async fns on broker executor threads:usb_audit_serial_hmac_keyring calls the sync en | medium | wide | policy-confirmed | - -## 2. Findings by lens - -Row format: `RS-id | sev | crate | what | fix | anchor | verdict | lane`. Every finding appears under its lens, grouped by crate (cross-cutting lanes grouped under their lane id); section 4 lists the cross-cutting lanes by lane instead. Section row counts equal the executive-summary per-lens counts. - -### `idiom` - -Expression shape: iterator pipelines over index loops, derives over hand-written impls, `From`/`TryFrom` over ad-hoc converters, naming discipline. - -**`d2b`** - -- `RS-0037` | medium | `d2b` | `all_known_subcommands` hand-maintains a 22-entry command-name list of which 13 (launch, realm list/inspect/enter/run, up, down, restart, boot, build, switch, test, rollback, generations, usb, console) are retired v2 verbs the ModernCli parser rejects, so `d2b auth status` reports them as known-but-denied commands | fix: derive the list from `ModernCli::command().get_subcommands()` minus `PROJECTION_COMMANDS` the way `BUILTIN_COMMANDS` does, or drop the retired entries; update the pinned expectation in tests/auth_status_contract.rs | [packages/d2b/src/dispatch.rs:688-706, packages/d2b/src/dispatch.rs:1169-1175] | actionable | lane/d2b-p3.md -- `RS-0031` | low | `d2b` | the pidfd-table inspection detail string is re-derived by an identical 3-line match at five check sites | fix: add `PidfdEntries::state_detail() -> String` next to `load_pidfd_entries` and call it from `check_otel_host_bridge_runner`, `check_usbipd_runners`, `check_seccomp_bpf_loaded`, `check_pre_ns_posture_with_reader`, `check_broker_reap_health` | [packages/d2b/src/doctor.rs:529, packages/d2b/src/doctor.rs:579, packages/d2b/src/doctor.rs:1230, packages/d2b/src/doctor.rs:1343] | actionable | lane/d2b-p2.md -- `RS-0036` | low | `d2b` | `summarize` hand-builds a zeroed `DoctorSummary` although the type derives `Default` | fix: `let mut summary = DoctorSummary::default();` | [packages/d2b/src/zone_doctor.rs:598-601] | actionable | lane/d2b-p3.md -- `RS-0032` | low | `d2b` | `typed()` hand-rolls eight field-by-field typed-args to generic-args conversions with ~20 clones instead of `From` impls | fix: implement `From for GenericListArgs` (and the other six pairs) consuming the typed args, and change `typed()`/`typed_noun()` to take `TypedResourceArgs` by value so the conversions stop cloning | [packages/d2b/src/resource.rs:525, packages/d2b/src/resource.rs:546, packages/d2b/src/resource.rs:555, packages/d2b/src/resource.rs:565] | actionable | lane/d2b-p2.md -- `RS-0033` | low | `d2b` | `valid_digest` and `valid_hash` in zone_audit.rs are byte-identical functions | fix: keep one (e.g. `valid_digest`) and delete the other, updating its three call sites | [packages/d2b/src/zone_audit.rs:805, packages/d2b/src/zone_audit.rs:838] | actionable | lane/d2b-p2.md -- `RS-0034` | low | `d2b` | the v1 record path in `validate_record` duplicates the ~22-line chain-verification tail of the nested `validate_v2_record` (hash extraction, expected-previous check, canonical json! build, digest compare) | fix: extract `verify_chain(object, fields_key, expected_previous) -> Result` and call it from both the v1 path and `validate_v2_record` | [packages/d2b/src/zone_audit.rs:349, packages/d2b/src/zone_audit.rs:395] | actionable | lane/d2b-p2.md -- `RS-0035` | low | `d2b` | `validate_public_fields` and `validate_v2_fields` have identical bodies differing only in the per-field validator they call | fix: merge into one `validate_fields(class, fields, validate_field: fn(&str, &str, &Value) -> bool)` and pass `validate_public_field`/`validate_v2_field` | [packages/d2b/src/zone_audit.rs:591, packages/d2b/src/zone_audit.rs:607] | actionable | lane/d2b-p2.md - -**`d2b-audit`** - -- `RS-0001` | medium | `d2b-audit` | `read_bounded_line` is copy-pasted three times with only the error-code strings differing ("audit-export-line-*" / "audit-segment-line-*" / "audit-scan-line-*") | fix: extract one crate-private `read_bounded_line` (canonical home: a shared module or segment.rs) taking the line-limit/truncated error codes as parameters, and delete the two copies | [packages/d2b-audit/src/export.rs:255, packages/d2b-audit/src/segment.rs:980, packages/d2b-audit/src/sink.rs:421] | actionable | lane/d2b-audit.md -- `RS-0002` | low | `d2b-audit` | `paths.retain)...)` in `export_segments_range` re-applies `is_segment_name` to every path the read_dir loop already filtered, a redundant pass over the directory listing | fix: delete the `paths.retain` block (export.rs:103-110); the push guard at export.rs:94-102 is the only filter needed | [packages/d2b-audit/src/export.rs:103] | actionable | lane/d2b-audit.md -- `RS-0003` | low | `d2b-audit` | `scan_chain_state` re-invokes `record.mutation_id()` and `record.zone_operation_key()` inside the block whose outer `if let` already bound them, re-deriving two SHA-256 identities per mutation record during the startup scan | fix: use the outer bindings for the `mutation_predecessors` insert, deleting the inner `if let` (sink.rs:403-410) | [packages/d2b-audit/src/sink.rs:393, packages/d2b-audit/src/sink.rs:403] | actionable | lane/d2b-audit.md - -**`d2b-broker`** - -- `RS-0011` | medium | `d2b-broker` | row_owner_ref, device_guest_owner,and tpm_devices_of_guest hand-roll the same "walk the bundles resources array" loop three times with slightly different match predicates, so bundle-shape drift (new field, renamed key) silently desyncs them. | fix: extract a single `fn find_resource_row<'a>(bundle: &'a Value, pred: impl FnMut(&'a Value) -> bool) -> Option<&'a Value>` and drive all three (and callers of row_owner_ref at src/ops/device_worker.rs:158) from it; keep the three predicates as call-site closures. | [src/ops/device_worker.rs:312-335, src/ops/device_worker.rs:339-369, src/ops/device_worker.rs:371-434] | actionable | lane/d2b-broker-p6.md -- `RS-0006` | low | `d2b-broker` | three near-identical hand-rolled flag parsers `parse_probe_flags`/`parse_stub_flags`/`parse_export_flags` duplicate the same index-loop skeleton and the `--socket-path`/`--test-uid` arms (with `expect_arg` bound-checking) three times | fix: extract one table-driven flag parser (flag spec -> value) that the three wrappers compose, or a shared `parse_common_flags` helper returning `(socket_path, test_uid)` | [packages/d2b-broker/src/runtime.rs:10392, packages/d2b-broker/src/runtime.rs:10418, packages/d2b-broker/src/runtime.rs:10453, packages/d2b-broker/src/runtime.rs:10495] | actionable | lane/d2b-broker-p1.md -- `RS-0007` | low | `d2b-broker` | active_locked_usbip_bind_intents builds out with a let-mut push loop over the resolver's intent-id iterator, where a filter_map().collect() pipeline would carry the same filtering | fix: replace the loop at runtime.rs:10132-10147 with `resolver.usbip_bind_intent_ids().filter_map(|id| resolver.find_usbip_bind_intent(id).map)...))).collect::>()`, keeping the two continue conditions as filter predicates | [packages/d2b-broker/src/runtime.rs:10132] | actionable | lane/d2b-broker-p2.md -- `RS-0008` | low | `d2b-broker` | `format_errno` reverses `tmp` into `buf` by hand with an index loop (`for i in 0..len`), the exact case an iterator form reads as idiomatic | fix: replace the loop with `buf[..len].copy_from_slice(&tmp[..len])` plus `buf[..len].reverse()`, or fill via `buf.iter_mut().zip(tmp[..len].iter().rev())`; both stay allocation- and panic-free so the async-signal-safe contract is preserved | [packages/d2b-broker/src/sys.rs:2816-2820] | actionable | lane/d2b-broker-p5.md -- `RS-0009` | low | `d2b-broker` | the "path must be absolute" check (a `to_str()` + `starts_with('/')` + `InvalidInput` refusal) is hand-copied into seven SystemReconcileExecutor methods, so a wording or error-shape change must touch all seven. | fix: extract a private `fn require_absolute(path: &Path) -> Result<(), ReconcileExecError>` helper and call it from apply_nft_script, write_atomic_file, write_atomic_file_with_ownership, write_path_value, read_path_value, ip_route, run_usbip, run_ssh_keygen. | [src/ops/exec_reconcile.rs:404, src/ops/exec_reconcile.rs:505, src/ops/exec_reconcile.rs:551, src/ops/exec_reconcile.rs:602] | actionable | lane/d2b-broker-p6.md merged: d2b-broker-p6#2 -- `RS-0010` | low | `d2b-broker` | build_farm_via_namespace and build_store_view_via_namespace duplicate the same spawn-process + write-config + read-stdout + split-lines scaffold (about 100 lines each), drifting in error messages and success parsing. | fix: unify behind one private `async fn run_store_helper(verb: StoreViewHelperVerb, request: impl Serialize, success: impl FnOnce(&[u8]) -> ...) -> Result<(), StoreViewFarmError>` with a two-variant `StoreViewHelperVerb` enum, or extract the shared scaffold into a thin helper. | [src/ops/store_view_farm.rs:97-190, src/ops/store_view_farm.rs:228-300] | actionable | lane/d2b-broker-p6.md -- `RS-0012` | low | `d2b-broker` | TrustedContextStore duplicates each worker-handshake entrypoint as a sync twin (`open`/`open_async`, `publish`/`publish_async`) whose sync copies spawn a `block_on`-free worker handshake that only in-crate `#[cfg(test)]` callers exercise;; the justification comment begins "The crate is nearly all async" and does not cover the sync twins' ongoing cost. | fix: gate the sync twins `#[cfg(test)]` (and gate `TrustedContextStore::Drop`'s sync persist path if unused outside tests), or unify over a private `fn with_worker(blocking: bool, f: impl FnOnce...` seam if a production sync caller is restored. | [src/envelope/mod.rs:424-464, src/envelope/mod.rs:466-493, src/envelope/mod.rs:540-565, src/envelope/mod.rs:567-593] | actionable | lane/d2b-broker-p6.md - -**`d2b-broker-composition`** - -- `RS-0004` | low | `d2b-broker-composition` | `workspace_root` walks up to four parent directories with a `for _ in 0..4` index loop and a mutable `current`, where the bounded walk is an iterator chain | fix: replace the loop with `std::iter::successors(Some(current), |c| c.parent()).take(4).find(|c| c.join("Cargo.toml").is_file() && c.join("packages").is_dir())` | [packages/d2b-broker-composition/src/dependency_surface.rs:136] | actionable | lane/d2b-broker-composition.md -- `RS-0005` | low | `d2b-broker-composition` | `state_cell` silences its deliberately unused parameter with `let _ = invocation;` instead of naming it as unused | fix: rename the parameter to `_invocation` and delete the `let _ = invocation;` line (the doc comment's "the invocation's row" is prose, not the parameter name) | [packages/d2b-broker-composition/src/seam.rs:270, packages/d2b-broker-composition/src/seam.rs:274] | actionable | lane/d2b-broker-composition.md - -**`d2b-bus`** - -- `RS-0013` | low | `d2b-bus` | AuthoritativeUnixSubjectResolver::resolve_for_service collects matching subject indices into a Vec and indexes [0], allocating and double-scanning where a take-two iterator would do | fix: replace the collect-then-index with subjects.iter().enumerate().filter_map(...) checked via next() then next().is_some() | [packages/d2b-bus/src/router.rs:1773-1781] | actionable | lane/d2b-bus-p1.md -- `RS-0014` | low | `d2b-bus` | `PendingCancelDeliveries::abort_destination` collects into a `Vec` inside a `retain` closure (statement-style accumulation with a side effect in the predicate) instead of partitioning the entries | fix: `let (aborted, kept): (Vec<_>, Vec<_>) = entries.drain(..).partition(|entry| entry.destination == session); *entries = kept;` and abort the drained handles | [packages/d2b-bus/src/operations.rs:302-310] | actionable | lane/d2b-bus-p2.md - -**`d2b-contracts-broker`** - -- `RS-0015` | low | `d2b-contracts-broker` | `response.refusal.clone().unwrap_or_default()` runs inside an `if response.refusal.is_some()` branch, so the default is unreachable and the value is cloned twice | fix: restructure to `if let Some(code) = response.refusal.clone()` or match on the Option once, returning `KernelInvokeError::Refused` in the Some arm | [packages/d2b-contracts-broker/src/kernel_client.rs:225-227] | actionable | lane/d2b-contracts-broker.md -- `RS-0016` | low | `d2b-contracts-broker` | `ApplyHostGenerationHandoff::validate` carries a caller-role check that can never fire: `HandoffCallerRole` has exactly two variants and the `!matches!(Lifecycle | Admin)` guard is always false, so the `InvalidTransition` arm is dead code in a security-adjacent validation path | fix: delete the branch (or add the missing third role if one was intended) | [packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broker/src/host_generation.rs:131-137] | actionable | lane/d2b-contracts-broker.md -- `RS-0017` | low | `d2b-contracts-broker` | `BrokerCallerRole::for_display()` returns the bare label `"RootUid"` for `RootUid` while every sibling arm returns a stable `d2b-*` audit label, and the value lands in the broker's `peer_role` audit records | fix: align the arm to the scheme, e.g. `"d2b-root"`, and pin it in the existing label test | [packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/src/broker_wire.rs:3149-3163] | actionable | lane/d2b-contracts-broker.md merged: d2b-contracts-broker#10 - -**`d2b-contracts-provider`** - -- `RS-0018` | low | `d2b-contracts-provider` | hand-written `Default` impls on `CredentialRotationPolicy` and `CredentialRevocationPolicy` reproduce the field-wise default a derive would generate | fix: add `#[default]` to `RotationPolicyClass::OnExpiry` and `RevocationAction::Immediate` and replace both impls with `#[derive(Default)]` | [packages/d2b-contracts-provider/src/v3/credential.rs:362, packages/d2b-contracts-provider/src/v3/credential.rs:453] | actionable | lane/d2b-contracts-provider-p1.md -- `RS-0020` | low | `d2b-contracts-provider` | the two `children.push(BindingChildIntent {...})` arms in `explicit_binding_children_with_user` are identical 15-field literals differing only in `producer_ref: None` versus `Some(producer_ref)`, forced apart by a `let ... else { ...; continue; }` | fix: bind `let producer_ref: Option = producer_ref.transpose()?;` before the push and emit one literal with `producer_ref,`, deleting the else-continue arm | [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:595] | actionable | lane/d2b-contracts-provider-p2.md -- `RS-0019` | low | `d2b-contracts-provider` | manual `Debug` impl on `UpgradePolicy` prints exactly the three closed pub fields a derive would print, with nothing to redact | fix: replace `impl core::fmt::Debug for UpgradePolicy` with `#[derive(Debug)]` on the struct | [packages/d2b-contracts-provider/src/v3/provider.rs:2374] | actionable | lane/d2b-contracts-provider-p1.md - -**`d2b-contracts-resource`** - -- `RS-0022` | medium | `d2b-contracts-resource` | the sort-dedup-compare uniqueness check is hand-rolled at three production sites while a private helper already exists | fix: extract `ensure_unique(values: &[T]) -> Result<(), PrimitiveSpecError>` into execution_policy.rs (home of PrimitiveSpecError) and call it from VolumeSpec::new, ExecutionPolicy::new, and process.rs check_unique (which keeps only its max-bound check) | [packages/d2b-contracts-resource/src/v3/volume.rs:1210-1213, packages/d2b-contracts-resource/src/v3/volume.rs:1248-1253, packages/d2b-contracts-resource/src/v3/execution_policy.rs:792-796, packages/d2b-contracts-resource/src/v3/process.rs:1571-1579] | actionable | lane/d2b-contracts-resource-p2.md -- `RS-0021` | low | `d2b-contracts-resource` | `ExternalIpv4Spec::default` (network.rs:597-605) hand-writes exactly the field-wise default (method: Ipv4Method::Dhcp, address: None, gateway: None, dns: Vec::new()) that a derive would produce | fix: add `#[default]` to `Ipv4Method::Dhcp` (network.rs:533) and `#[derive(Default)]` to `ExternalIpv4Spec`, delete the hand-written impl | [packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src/v3/network.rs:533] | actionable | lane/d2b-contracts-resource-p1.md -- `RS-0023` | low | `d2b-contracts-resource` | ResourceSpec::serialize iterates `self.base.keys()` and re-gets each key with an avoidable `expect("key returned by canonical object")` | fix: iterate `for (key, value) in &self.base` and call `map.serialize_entry(key, value)?`, deleting the expect and the double lookup | [packages/d2b-contracts-resource/src/v3/resource.rs:621-626] | actionable | lane/d2b-contracts-resource-p2.md -- `RS-0024` | low | `d2b-contracts-resource` | VolumeSpec::new checks `views.contains_key` and then repeats the lookup with a dead `ok_or(MissingRequiredField)` that can never fire | fix: collapse to one `let view = views.get(attachment.view.as_str()).ok_or(PrimitiveSpecError::MissingRequiredField)?;` | [packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223] | actionable | lane/d2b-contracts-resource-p2.md - -**`d2b-contracts-zone-session`** - -- `RS-0025` | low | `d2b-contracts-zone-session` | hand-written `impl Default for ReceiveSequence` and `SendSequence` duplicate what `#[derive(Default)]` generates field-for-field (u64 plus bool, both zero) | fix: add `Default` to the derive lists of `ReceiveSequence` and `SendSequence` and delete the two hand-written impls; keep `ZoneLinkLimits`' Default (zone_link.rs:126) which preserves the nonzero bounds invariant | [src/v3/component_session.rs:1935, src/v3/component_session.rs:1976] | actionable | lane/d2b-contracts-zone-session-p1.md - -**`d2b-core`** - -- `RS-0027` | low | `d2b-core` | resolve_network_projection_intent and resolve_network_sysctl_intent fetch the Network spec only to discard it via `let _ = spec;`, a workaround for the unused binding | fix: replace `let spec = self.find_network_spec(&parts)?; ... let _ = spec;` with the statement `self.find_network_spec(&parts)?;` (the `?` on Option keeps the admission check and drops the value) | [packages/d2b-core/src/bundle_resolver.rs:1805, packages/d2b-core/src/bundle_resolver.rs:1911] | actionable | lane/d2b-core-p1.md -- `RS-0030` | low | `d2b-core` | allowlist membership checks in static_invariants.rs use `iter().any(|f| f == last)` linear scans where slice `contains` reads cleaner | fix: replace `PUBLIC_MANIFEST_FIELDS.iter().any(|f| f == last)` with `PUBLIC_MANIFEST_FIELDS.contains(&last.as_str())` and `BROAD_CAPABILITIES.iter().any(|broad| broad == cap)` with `BROAD_CAPABILITIES.contains(&cap.as_str())` | [packages/d2b-core/src/static_invariants.rs:162, packages/d2b-core/src/static_invariants.rs:219] | actionable | lane/d2b-core-p2.md -- `RS-0028` | low | `d2b-core` | `_ASSERT_TAPROLE` is a `#[allow(dead_code)]` const that exists only to silence an unused-import warning for `TapRole`, which the module does not actually name | fix: drop the `use crate::host::TapRole` import (the comment says `BridgePortFlags` uses the type internally) or import it as `use crate::host::TapRole as _;`, and delete the const | [packages/d2b-core/src/bundle_resolver.rs:5746] | actionable | lane/d2b-core-p1.md -- `RS-0029` | low | `d2b-core` | resolve_disk_init_ops nests two `for` loops over a single-arm `match` on `SpawnRunnerPlanOp`, which is a one-variant enum, so the match is a no-op wrapper around construction | fix: flatten to `vm.nodes.iter().flat_map(|n| &n.plan_ops).filter_map(|op| match op { SpawnRunnerPlanOp::DiskInit { .. } => Some(ResolvedDiskInitOp { .. }), })` or at least an `if let` for the single variant | [packages/d2b-core/src/bundle_resolver.rs:2434, packages/d2b-core/src/processes.rs:180] | actionable | lane/d2b-core-p1.md - -**`d2b-core-controller`** - -- `RS-0026` | low | `d2b-core-controller` | the duplicate-reservation checks bind a holder only to silence it with `let _ = holder;`, when the check is a pure predicate | fix: replace the `if let Some(holder) = ... { let _ = holder; return Err(...); }` blocks with `if entry.holders.iter().any(|holder| holder.owner_proof == request.owner_proof) { return Err(...); }` in admit_authority_inner_with_operation and admit_with_operation_id | [authority.rs:2189-2192, authority.rs:2542-2545] | actionable | lane/d2b-core-controller-p2.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0040` | medium | `d2b-provider-clipboard-wayland` | MIME policy is duplicated in two modules with divergent semantics: clipd_host/policy.rs normalizes by splitting on ';' and carries a 7-entry secret-hint list, while crate::policy.rs normalizes by trim+lowercase only and carries a 3-entry list, so the same MIME string ("Text/Plain ; Charset=UTF-8") is admitted by the host Wayland path and rejected by the guest history path, and secret hints diverge (application/x-secret-service is a hint on the host side only) | fix: make crate::policy the single canonical MIME module and have clipd_host::policy delegate to it for ALLOWED_MIME_TYPES, SECRET_HINT_MIME_TYPES, and normalize_mime | [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:91-97, packages/d2b-provider-clipboard-wayland/src/policy.rs:3-14, packages/d2b-provider-clipboard-wayland/src/policy.rs:91-93] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0039` | medium | `d2b-provider-clipboard-wayland` | preferred_mime_order hardcodes the four MIME strings that policy.rs ALLOWED_MIME_TYPES already owns, keeping the reported MIME-policy triplication alive (row S79, reported not consolidated) | fix: iterate d2b_provider_clipboard_wayland::ALLOWED_MIME_TYPES in preferred_mime_order instead of the literal list, so allowlist changes propagate to the preference order | [src/bin/d2b-clipd.rs:2812, src/policy.rs:12] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0041` | low | `d2b-provider-clipboard-wayland` | two distinct PickerError enums in one crate (crate::picker::PickerError for receipt minting and crate::clipd_host::picker::PickerError for the subprocess supervisor) share a name, which reads as one type in errors and imports | fix: rename the clipd_host one (e.g. PickerIpcError) or move the supervisor module under a distinct name | [packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:113-126] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0038` | low | `d2b-provider-clipboard-wayland` | install_bridge_listeners builds a Vec with a push loop where the body is a pure Result-producing map | fix: collect the iterator: bridge_peers.into_iter().map(|peer| { ... Ok(BridgeListener { ... }) }).collect::, String>>()? | [src/bin/d2b-clipd.rs:1131] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0042` | low | `d2b-provider-clipboard-wayland` | FallbackArming implements Default by hand for a single-field struct whose only field defaults to FallbackState::Idle; a derive would stay in sync with the enum | fix: `#[derive(Default)]` on FallbackArming plus `#[derive(Default)]` with `#[default]` on FallbackState::Idle, delete the impl | [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:5-12] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0043` | low | `d2b-provider-clipboard-wayland` | ReasonCode::as_str is a hand-written match that duplicates the `#[serde(rename_all = "snake_case")]` label mapping on the same enum, giving two sources of truth for the wire label that can drift | fix: derive the label once (e.g. a const table or serde serialization) and have as_str return it | [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:45-68] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-config-nixos`** - -- `RS-0044` | low | `d2b-provider-config-nixos` | the path-component rejection walk is written twice with identical rules, and the two copies can drift (one checks, one checks and collects) | fix: extract one helper classifying `Path::components()` into `Result, ConfigError>` (reject `CurDir`/`ParentDir`/`Prefix`) and call it from both `validate_reader_path` and `read_bounded_file` | [packages/d2b-provider-config-nixos/src/ttrpc.rs:379-386, packages/d2b-provider-config-nixos/src/ttrpc.rs:414-421] | actionable | lane/d2b-provider-config-nixos.md - -**`d2b-provider-credential-entra`** - -- `RS-0045` | medium | `d2b-provider-credential-entra` | in-crate deadline trio (`operation_deadline`/`time_bound_instant`/`time_bounds_not_after`/`time_bound_instant_at`/`is_expired_unix_ms`) duplicates the toolkit's `credential::operation_deadline` with identical absolute-or-relative semantics; the family finding that folded this trio onto the toolkit was applied to secret-service but not here | fix: fold the trio onto `d2b_provider_toolkit::credential::{operation_deadline, deadline_remaining, now_unix_ms, is_absolute_unix_ms}` (keep the injectable-clock `time_bound_instant_at` only if the tests need it), deleting lib.rs:1164-1220 | [packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-entra/src/lib.rs:1172, packages/d2b-provider-credential-entra/src/lib.rs:1187, packages/d2b-provider-toolkit/src/credential.rs:111] | actionable | lane/d2b-provider-credential-entra.md - -**`d2b-provider-credential-secret-service`** - -- `RS-0046` | low | `d2b-provider-credential-secret-service` | exported enum variant is misspelled `Userd` for `User` in the only supported owner classification, so every consumer must copy the typo | fix: rename `SecretServiceOwner::Userd` to `SecretServiceOwner::User` (and `owner()` return at lib.rs:1233); in-tree census shows no consumers to update | [packages/d2b-provider-credential-secret-service/src/lib.rs:446, packages/d2b-provider-credential-secret-service/src/lib.rs:1233] | actionable | lane/d2b-provider-credential-secret-service.md - -**`d2b-provider-device-gpu`** - -- `RS-0047` | low | `d2b-provider-device-gpu` | rustfmt drift: the GpuAuthorityError enum is closed by an indented brace with a trailing-whitespace line inside code(), and a variant doc comment in GpuEffectError sits at column 0 | fix: normalize the three sites (cargo fmt --check class): authority.rs:401 -> `}`, authority.rs:411 empty, effects.rs:101 reindent `/// A worker closure...` | [packages/d2b-provider-device-gpu/src/authority.rs:401, packages/d2b-provider-device-gpu/src/authority.rs:411, packages/d2b-provider-device-gpu/src/effects.rs:101] | actionable | lane/d2b-provider-device-gpu.md -- `RS-0048` | low | `d2b-provider-device-gpu` | `let _ = Self::declared_row_template)...)?` binds nothing while the `?` already propagates the error | fix: drop the binding: `Self::declared_row_template(&view, role)?;` | [packages/d2b-provider-device-gpu/src/effects_service.rs:193] | actionable | lane/d2b-provider-device-gpu.md -- `RS-0049` | low | `d2b-provider-device-gpu` | six opaque-token newtypes duplicate the same from_core / is_zero / as_bytes / redacting-Debug boilerplate with subtly differing surfaces | fix: extract a shared opaque-bytes shape (const-generic `OpaqueBytes` with per-type markers, or an in-crate `macro_rules! opaque_token`), keeping the deliberate per-type Debug redaction; the repo's `redacted_debug!`-class macro is the resident pattern to lean on | [packages/d2b-provider-device-gpu/src/authority.rs:17, packages/d2b-provider-device-gpu/src/authority.rs:44, packages/d2b-provider-device-gpu/src/authority.rs:66, packages/d2b-provider-device-gpu/src/authority.rs:265] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-device-security-key`** - -- `RS-0050` | low | `d2b-provider-device-security-key` | `declared_dependency_refs` accumulates through a `let mut refs = Vec::new()` plus a push closure instead of an iterator chain, the one statement-style accumulation in the crate | fix: collect the two `Option` probes with an iterator chain (`[a, b].into_iter().flatten().collect()`) and delete the closure | [packages/d2b-provider-device-security-key/src/driver.rs:380-390] | actionable | lane/d2b-provider-device-security-key.md - -**`d2b-provider-device-tpm`** - -- `RS-0051` | low | `d2b-provider-device-tpm` | the swtpm log-level bound is spelled twice: lib.rs exports MIN_SWTPM_LOG_LEVEL/MAX_SWTPM_LOG_LEVEL (1/20) which runner.rs uses, while swtpm_argv.rs:160 hardcodes `1..=20` in generate_swtpm_argv, so a bound change in one place silently drifts from the other | fix: import crate::{MIN_SWTPM_LOG_LEVEL, MAX_SWTPM_LOG_LEVEL} in swtpm_argv.rs and replace the literal range | [swtpm_argv.rs:160, lib.rs:63, lib.rs:65] | actionable | lane/d2b-provider-device-tpm.md - -**`d2b-provider-device-usbip`** - -- `RS-0052` | low | `d2b-provider-device-usbip` | `declared_dependency_refs` accumulates into `let mut refs = Vec::new()` and pushes in match arms where each arm returns a fixed small list | fix: return the match arms as owned `Vec` literals (or `.into_iter().flatten().collect()`) so the shape is an expression | [driver.rs:267-281] | actionable | lane/d2b-provider-device-usbip.md - -**`d2b-provider-display-wayland`** - -- `RS-0059` | medium | `d2b-provider-display-wayland` | the session binding digest is derived twice with byte-identical bodies: free fn `session_digest` (controller.rs:1442) duplicates `WaylandSessionSpec::session_digest` (spec.rs:385), so the two can silently diverge | fix: make the controller free fn delegate to `spec.session_digest(controller_generation)` and keep spec.rs:385 as the canonical home (census: d2bd already consumes the method at interaction_composition.rs:4080,4267) | [src/controller.rs:1442, src/spec.rs:385] | actionable | lane/d2b-provider-display-wayland-p2.md -- `RS-0053` | low | `d2b-provider-display-wayland` | handoff_via_bridge re-wraps the bound `error` into a fresh `HandoffStatus::Failed(error)` and immediately matches it back out with a `_ => unreachable!()` arm that can never fire; the outer match arm already binds the value | fix: delete the `let status = ...` / `let error = match status {...}` round-trip and use the arm-bound `error` directly in filter.rs:620-628 | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:620, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:624] | actionable | lane/d2b-provider-display-wayland-p1.md -- `RS-0058` | low | `d2b-provider-display-wayland` | three stale `#[allow(dead_code)]` markers sit on constructors that production code calls: `FinalizationInput::from_supervisor` (controller.rs:464), `LaunchGrants::from_supervisor_for_session_with_frontend_and_controller` (process.rs:402), `ProcessObservation::from_supervisor` (process.rs:676) | fix: delete the three allows (keep process.rs:380, whose constructor is test/test-support-only) so a future real dead-code warning is not masked | [src/controller.rs:464, src/process.rs:402, src/process.rs:676] | actionable | lane/d2b-provider-display-wayland-p2.md -- `RS-0054` | low | `d2b-provider-display-wayland` | handle_bind dispatches per-interface handler installation through a nested `match try_downcast::() { Some => ..., _ => match try_downcast::() { Some => ..., _ => { if let ... } } }` while the same function already uses edition-2024 if-let chains for viewporter and dmabuf, mixing two dispatch styles in one body | fix: flatten the nested match into `if let Some(wm_base) = ... else if let Some(eglstream) = ... else if let Some(compositor) = ...` chains, keeping the early `return` arms | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1272, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1300] | actionable | lane/d2b-provider-display-wayland-p1.md -- `RS-0055` | low | `d2b-provider-display-wayland` | filter_format_table iterates `for (index, entry) in table.chunks_exact(16).enumerate()` but the index is never used except `let _ = index;` inside the overflow branch, an ignore that exists only to silence the unused variable | fix: drop `.enumerate()` and remove `let _ = index;` | [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:790, packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:801] | actionable | lane/d2b-provider-display-wayland-p1.md -- `RS-0056` | low | `d2b-provider-display-wayland` | sanitize_label calls `out.chars().count()` on every loop iteration, a quadratic re-count of the output string that grows with the label length (bounded at 64 chars, so cheap, but the shape invites the same mistake at a larger bound) | fix: track a `let mut written = 0usize;` counter incremented per pushed char and compare against `MAX_LABEL_CHARS` | [packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:150] | actionable | lane/d2b-provider-display-wayland-p1.md -- `RS-0057` | low | `d2b-provider-display-wayland` | four comment blocks are mangled prose: a non-ASCII full stop (`\u3002`) at dmabuf.rs:820, a stray `**` at filter.rs:769, two `; no` joins missing the space after the semicolon at filter.rs:770 and filter.rs:2801, and misindented two-line comment pairs at decoration.rs:1804-1805, dmabuf.rs:819-820 and filter.rs:2799-2801 where the continuation line sits at 4-space indent inside the fn | fix: rewrite the four comments as plain ASCII with normal spacing and consistent indent | [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:769, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:770, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:2801] | actionable | lane/d2b-provider-display-wayland-p1.md - -**`d2b-provider-endpoint`** - -- `RS-0061` | medium | `d2b-provider-endpoint` | the `inspect-endpoint` payload table hardcodes the four committed purposes and their producer/locality/class strings, duplicating the same-module derivations `guest_control_producer`/`device_worker_endpoint_class` built from the provider constants, so a provider role/purpose rename drifts the report silently | fix: build the table from those fns, or constrain it with a unit test pinning the payload rows to the derivations | [packages/d2b-provider-endpoint/src/effects_service.rs:50-60, packages/d2b-provider-endpoint/src/effects_service.rs:73-84, packages/d2b-provider-endpoint/src/effects_service.rs:128-143] | actionable | lane/d2b-provider-endpoint.md -- `RS-0060` | low | `d2b-provider-endpoint` | hand-written `impl Default for EndpointConsumerPolicy` returns `Self::unrestricted()`, which the field-wise derive would produce identically (empty Vecs) | fix: add `Default` to the derive list on `EndpointConsumerPolicy` and drop the manual impl | [packages/d2b-provider-endpoint/src/endpoint.rs:395-398] | actionable | lane/d2b-provider-endpoint.md - -**`d2b-provider-guest-azure-virtual-machine`** - -- `RS-0062` | low | `d2b-provider-guest-azure-virtual-machine` | hand-written `impl Default for BootstrapService` where a derive with a `#[default]` variant covers it | fix: add `#[derive(Default)]` with `#[default]` on `BootstrapServiceState::Waiting` (bootstrap.rs:124) and `#[derive(Default)]` on `BootstrapService`, delete the manual impl | [src/bootstrap.rs:138, src/bootstrap.rs:124] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md - -**`d2b-provider-guest-cloud-hypervisor`** - -- `RS-0063` | low | `d2b-provider-guest-cloud-hypervisor` | `CloudHypervisorController` stores `_config` (controller.rs:1712) that is never read; only `config.validate()` at 1739 uses the value | fix: drop the `_config` field and its initializer, keeping the validate() call in `from_verified_descriptor` | [controller.rs:1712, controller.rs:1744] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0064` | low | `d2b-provider-guest-cloud-hypervisor` | `observed_process_status` is controller state used only inside one `reconcile` invocation (reset at 1860, set at 2013/2016, read at 2042), a field masquerading as a local | fix: make it a local variable in `reconcile` and delete the struct field | [controller.rs:1722, controller.rs:1860, controller.rs:2042] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0065` | low | `d2b-provider-guest-cloud-hypervisor` | `deletion_rank` (shutdown.rs:487) and `upgrade_rank` (shutdown.rs:666) are byte-identical match arms duplicated across two free functions | fix: one `ChildRole::rank()` method (or single free fn) used by both planners | [shutdown.rs:487-494, shutdown.rs:666-673] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0066` | low | `d2b-provider-guest-cloud-hypervisor` | `BootstrapGraph::readiness()` (bootstrap_graph.rs:131) hardcodes `bindings_ready`/`setup_ready` to true while the `bindings` field doc says fenced binding readiness gates VMM start; only tests call it | fix: delete the wrapper and update the test (bootstrap_graph.rs:417) to call `vmm_readiness` with explicit booleans | [bootstrap_graph.rs:131-139, bootstrap_graph.rs:417-422] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0067` | low | `d2b-provider-guest-qemu-media` | The `impl Default` bodies re-spell the serde `default_*` helper values in a second place (`"qemu-system-x86-64".to_owned()` at packages/d2b-provider-guest-qemu-media/src/config.rs:93 vs `default_qemu_artifact()` at 272; the whole GuestProviderSpecSettings default body at packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182-196 vs the serde default fns at ~440-447); two spellings of one default drift independently | fix: have the Default impls call the serde default fns (`qemu_binary_artifact_id: default_qemu_artifact()`, `vcpu: default_vcpu()`, `boot_media_view: default_boot_media_view()`( ( | [packages/d2b-provider-guest-qemu-media/src/config.rs:93, packages/d2b-provider-guest-qemu-media/src/config.rs:272, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:440] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-host`** - -- `RS-0068` | low | `d2b-provider-host` | stray misindented closing brace at test_support.rs:185 closes `impl RecordingMinijailGate` at 4-space indent (the fn body closes at :183, the impl at :185) | fix: reindent the stray `}` to column 0 (rustfmt would flag it) | [packages/d2b-provider-host/src/test_support.rs:185] | actionable | lane/d2b-provider-host.md - -**`d2b-provider-network-local`** - -- `RS-0069` | low | `d2b-provider-network-local` | octet-to-string conversion collects a Vec of four Strings and joins it, where one format! suffices | fix: destructure the parsed octets (`let [a, b, c, d] = octets; Some(format!("{a}.{b}.{c}.{d}"))`) instead of `.collect::>().join(".")` | [src/controller.rs:298-302] | actionable | lane/d2b-provider-network-local.md -- `RS-0070` | low | `d2b-provider-network-local` | declared_dependency_refs accumulates into `let mut refs = Vec::new()` with a nested if-push, where a filter_map pipeline fits | fix: `spec.pointer("/spec/attachments").and_then(Value::as_array).into_iter().flatten().filter_map(|a| a.get("executionRef").and_then(Value::as_str).and_then(|v| ResourceRef::parse(v.ok()()).collect()` | [src/driver.rs:377-393] | actionable | lane/d2b-provider-network-local.md - -**`d2b-provider-notification-desktop`** - -- `RS-0071` | low | `d2b-provider-notification-desktop` | `expected_acknowledgements` accumulates its two source acknowledgement arms with `Vec::new()` + `extend(iterator)` where the chain could collect the Vec directly | fix: `let mut acknowledgements: Vec<_> = plan.start_endpoints.iter().map)...).chain(plan.stop_endpoints.iter().map)...)).collect();` then keep the two conditional `HostSink` pushes | [packages/d2b-provider-notification-desktop/src/controller.rs:660-675] | actionable | lane/d2b-provider-notification-desktop.md -- `RS-0072` | low | `d2b-provider-notification-desktop` | `NotificationProviderDescriptor::service_package()` hardcodes the wire literal `"d2b.notification.v3"` duplicating the exported `SERVICE_PACKAGE` const | fix: return `crate::SERVICE_PACKAGE` so the literal has one home | [packages/d2b-provider-notification-desktop/src/descriptor.rs:43-44, packages/d2b-provider-notification-desktop/src/lib.rs:70] | actionable | lane/d2b-provider-notification-desktop.md - -**`d2b-provider-process-systemd`** - -- `RS-0073` | low | `d2b-provider-process-systemd` | hand-written `impl Default` on the unit structs `SystemdEffectsService` and `SystemdEffectsServiceFactory` where `#[derive(Default)]` generates the identical impl | fix: replace both `impl Default { fn default() -> Self { Self::new() } }` blocks with `#[derive(Default)]` on the structs | [packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-process-systemd/src/effects_service.rs:218] | actionable | lane/d2b-provider-process-systemd.md - -**`d2b-provider-seccomp-profile`** - -- `RS-0074` | low | `d2b-provider-seccomp-profile` | three impl-block closing braces are indented at 4 spaces instead of column 0 (fmt drift; `cargo fmt --check` would fail) | fix: dedent the closing braces of `impl DeviceNodePath`, `impl DeviceBind`, and `impl SeccompProfileSpec` to column 0 (rustfmt) | [packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:162, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:196] | actionable | lane/tail-4.md - -**`d2b-provider-supervisor`** - -- `RS-0075` | low | `d2b-provider-supervisor` | systemd.rs stop() holds a no-op statement `let _ = &handle.pidfd;` that creates and immediately drops a temporary reference, doing nothing | fix: delete the line (the pidfd field is already used by wait/finalize and the retained handle) | [packages/d2b-provider-supervisor/src/systemd.rs:840] | actionable | lane/d2b-provider-supervisor.md -- `RS-0076` | low | `d2b-provider-supervisor` | the bounded pending-observation ledger is copy-pasted twice: `BrokerProcessBackend::{record,take_observation}` and `SystemdProcessBackend::{record,take_observation}` are the same shape (Mutex, evict-oldest at MAX_PENDING_OBSERVATIONS=1024, poisoned-lock to ObserveFailed) | fix: extract one shared bounded-ledger helper and have both backends use it | [packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor/src/systemd.rs:240-280] | actionable | lane/d2b-provider-supervisor.md - -**`d2b-provider-system-core`** - -- `RS-0077` | low | `d2b-provider-system-core` | `UserIdentityDigest::to_hex` pushes hex nibbles with `char::from_digit)...).unwrap_or('0')`, a fallback that can never fire (from_digit is total for 0-15 at radix 16) | fix: const `HEX: [char; 16]` table lookup, or `write!(out, "{byte:02x}")` via `std::fmt::Write` which pushes without allocating | [src/user.rs:75, src/user.rs:76] | actionable | lane/d2b-provider-system-core.md -- `RS-0078` | low | `d2b-provider-system-core` | `UserReconciler::required_bindings` is an associated fn that never uses `Self`, the shape the naming rule calls a free function | fix: free `required_bindings(spec: &UserSpec)` in user.rs, updating the two test call sites (tests/user_discovery.rs:45, tests/user_discovery.rs:73) | [src/user.rs:232] | actionable | lane/d2b-provider-system-core.md - -**`d2b-provider-toolkit`** - -- `RS-0079` | medium | `d2b-provider-toolkit` | the 15-operation Guest backend allowlist is spelled out twice: `GuestCredentialBackend::request` inlines the same `matches!` that `valid_guest_backend_operation` already implements, so adding one operation to one list and not the other silently diverges the client and responder admission | fix: have `request` call `valid_guest_backend_operation(&operation)` and delete the inline `matches!` arm | [packages/d2b-provider-toolkit/src/base/fd10.rs:926-941, packages/d2b-provider-toolkit/src/base/fd10.rs:1478-1496] | actionable | lane/d2b-provider-toolkit-p1.md -- `RS-0080` | low | `d2b-provider-toolkit` | `GuestCredentialBackendResponse` and `GuestCredentialBackendReply` are two public 7-field structs with the same shape (state, lease_handle, source_version, rotation_generation, expires_at_unix_ms, outcome, bytes) and duplicated accessors, both re-exported at the crate root | fix: collapse into one type carrying the accessors plus `encode`/`with_sensitive_bytes`, keeping the zeroizing bytes field | [packages/d2b-provider-toolkit/src/base/fd10.rs:545-597, packages/d2b-provider-toolkit/src/base/fd10.rs:612-700, packages/d2b-provider-toolkit/src/lib.rs:91-92] | actionable | lane/d2b-provider-toolkit-p1.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0081` | low | `d2b-provider-transport-azure-relay` | `impl Clone for RelaySecret` hand-writes what `#[derive(Clone)]` generates identically (`Zeroizing>` clones into a fresh `Zeroizing` either way), and the manual version can drift from the field | fix: replace the impl block with `#[derive(Clone)]` on `RelaySecret` | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239, packages/d2b-provider-transport-azure-relay/src/credential_client.rs:217] | actionable | lane/d2b-provider-transport-azure-relay.md -- `RS-0082` | low | `d2b-provider-transport-azure-relay` | `build_connect` builds the literal `"Bearer"` by collecting a char array (`['B','e','a','r','e','r']`) into a fresh String on every connect, where a `const`/literal `"Bearer"` reads plainly and allocates nothing | fix: use a `const BEARER: &str = "Bearer"` (or inline literal) in the `ServiceBusAuthorization` header format | [packages/d2b-provider-transport-azure-relay/src/auth.rs:249-253] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-transport-vsock`** - -- `RS-0083` | low | `d2b-provider-transport-vsock` | `ReadySession::disconnect` takes `mut self`, assigns `SessionState::Disconnected` to a by-value copy that is immediately dropped, and then returns the assigned constant - the mutation is dead code and the method contract is fully expressed by returning the constant. | fix: `pub fn disconnect(self) -> SessionState { SessionState::Disconnected }`, dropping `mut` and the state assignment | [packages/d2b-provider-transport-vsock/src/auth.rs:221-224] | actionable | lane/d2b-provider-transport-vsock.md - -**`d2b-provider-volume`** - -- `RS-0084` | low | `d2b-provider-volume` | `reconcile` converts the provider facet via `serde_json::to_value(value).unwrap_or(serde_json::Value::Null)` where the value is already a `serde_json::Value`: a serialization round trip plus dead `unwrap_or` fallback for an infallible conversion | fix: replace with `envelope.base.get("provider").cloned()` | [driver.rs:607-609] | actionable | lane/d2b-provider-volume.md - -**`d2b-provider-volume-local`** - -- `RS-0085` | low | `d2b-provider-volume-local` | LayoutPhase::worse hand-rolls severity comparison with an `as u8` cast although the enum derives PartialOrd/Ord; the cast also silently depends on variant declaration order matching severity order | fix: replace the `if self as u8 >= other as u8` body with `self.max(other)` (derived Ord, declaration order Pending/Ready/Degraded/Failed already encodes severity) | [src/status.rs:33-38] | actionable | lane/d2b-provider-volume-local.md - -**`d2b-provider-zone-link`** - -- `RS-0086` | medium | `d2b-provider-zone-link` | the frozen cryptoperiod defaults `BOOTSTRAP_PSK_TTL_MS_DEFAULT` (300_000) and `KK_SESSION_MAX_LIFETIME_MS_DEFAULT` (86_400_000) are defined identically in two crates with no shared home, so a drift silently desynchronizes the child-local handler from the bus-side enrollment machine | fix: move both constants to `d2b_contracts_zone_session` (the crate both `d2b-provider-zone-link` and `d2b-bus` already depend on) and re-export from both sites; this is not the refused ZoneLink enrollment-machine merge, only the two constants | [packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/zone_links.rs:63, packages/d2b-bus/src/session/enrollment.rs:42, packages/d2b-bus/src/session/enrollment.rs:49] | actionable | lane/d2b-provider-zone-link.md - -**`d2b-resource-api`** - -- `RS-0087` | low | `d2b-resource-api` | A6 not-applied: 17 hand-written redaction Debug impls in authz.rs (15) and admission.rs (2) where the exported `redacted_debug!` macro exists | fix: fold byte-compatible impls to `redacted_debug!` or extend the macro with a count-preserving form, updating the Debug-shape pinning tests in the same change | [packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, packages/d2b-resource-api/src/authz.rs:356, packages/d2b-resource-api/src/authz.rs:377] | actionable | lane/d2b-resource-api-p2.md -- `RS-0088` | low | `d2b-resource-api` | unformatted `use` lines inside a fn body break `cargo fmt --check` | fix: reindent to 4 spaces and drop the inner-brace spacing | [packages/d2b-resource-api/src/manager_backend/tests.rs:1045, packages/d2b-resource-api/src/manager_backend/tests.rs:1046] | actionable | lane/d2b-resource-api-p2.md - -**`d2b-resource-client`** - -- `RS-0089` | low | `d2b-resource-client` | two byte-identical private async helpers each exist twice in this crate: `await_with_cancellation` (zone_client vs process_attach) and `classify_session_error`/`classify_attach_error` | fix: hoist both into one shared pub(crate) module (e.g., call.rs) and have zone_client.rs and process_attach.rs call the single copies | [packages/d2b-resource-client/src/zone_client.rs:914, packages/d2b-resource-client/src/process_attach.rs:764, packages/d2b-resource-client/src/zone_client.rs:936, packages/d2b-resource-client/src/process_attach.rs:785] | actionable | lane/d2b-resource-client.md -- `RS-0090` | low | `d2b-resource-client` | `GuestControlEndpoint::endpoint_uid` is an exact duplicate of `uid()` (same field, same doc sentence; a test pins the equivalence at zone_client.rs:1067) | fix: keep one accessor (e.g., `uid()`) and drop or deprecate the other | [packages/d2b-resource-client/src/zone_client.rs:194, packages/d2b-resource-client/src/zone_client.rs:199, packages/d2b-resource-client/src/zone_client.rs:1067] | actionable | lane/d2b-resource-client.md - -**`d2b-resource-compiler`** - -- `RS-0091` | medium | `d2b-resource-compiler` | main.rs hand-rolls identical output-sanitizer helpers already in lib.rs (safe_token/bound_ascii duplicate sanitize_token/bound_message body-for-body) | fix: expose lib.rs sanitize_token/bound_message as pub(crate) helpers (dropping safe_label indirection if unneeded) and replace main.rs safe_token/bound_ascii with calls to the shared pair | [packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:2438, packages/d2b-resource-compiler/src/main.rs:2531, packages/d2b-resource-compiler/src/main.rs:2545] | actionable | lane/d2b-resource-compiler.md -- `RS-0092` | low | `d2b-resource-compiler` | sanitize_token's char-loop filter is expressible as an iterator pipeline | fix: `value.chars().filter(|character| (character.is_ascii_graphic() && *character != '/' && *character != '\\') || *character == ' ').collect::()` | [packages/d2b-resource-compiler/src/lib.rs:2402] | actionable | lane/d2b-resource-compiler.md -- `RS-0093` | low | `d2b-resource-compiler` | check_metadata_closure's unexpected-layout-entries accumulation could be a filter_map+collect pipeline | fix: `let unexpected: Vec = entries.into_iter().filter_map(|entry_name| match entry_name.to_str() { Some(name) if expected.contains(name) => None, Some(name) => Some(truncate_entry(name)), None => Some("".to_owned()) }).collect();` (kept the trailing sort* | [packages/d2b-resource-compiler/src/lib.rs:1724] | actionable | lane/d2b-resource-compiler.md -- `RS-0094` | low | `d2b-resource-compiler` | executable-set difference builders are two push-loops a chain can express in one collect | fix: `let difference: Vec = names.difference(&declared_names).map(|name| format!("bin={}", truncate_entry(name)).chain(declared_names.difference(&names).map(|name| format!("manifest={}", truncate_entry(name)).collect();` | [packages/d2b-resource-compiler/src/lib.rs:1913] | actionable | lane/d2b-resource-compiler.md - -**`d2b-resource-runtime`** - -- `RS-0095` | low | `d2b-resource-runtime` | hand-written `impl Default` on the unit structs `ResourceManager` and `ResourceActor` delegate to `new()` where `#[derive(Default)]` is equivalent, and neither impl has any caller | fix: derive `Default` on both (or delete the impls; `new()` stays) | [packages/d2b-resource-runtime/src/manager.rs:882, packages/d2b-resource-runtime/src/resource.rs:685] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0097` | low | `d2b-resource-runtime` | two hand-written comparator closures where the sort_by_key form is the idiomatic one | fix: replace sort_by(|l, r| identity_order(l).cmp(&identity_order(r))) with sort_by_key(identity_order) in TargetDirectory::assignments_for and GuestTargetRuntime::instances | [packages/d2b-resource-runtime/src/target.rs:732, packages/d2b-resource-runtime/src/guest_target.rs:514] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0096` | low | `d2b-resource-runtime` | `ManagerActorEndpoint::rpc` and `ResourceManagerClient::rpc` are byte-identical 9-line request/reply helpers duplicated in one file | fix: extract one free `manager_rpc(actor: &ActorRef, build: impl FnOnce(oneshot::Sender>) -> ResourceManagerMsg)` and call it from both impls | [packages/d2b-resource-runtime/src/manager.rs:1419, packages/d2b-resource-runtime/src/manager.rs:1508] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0098` | low | `d2b-resource-runtime` | hand-written impl Default for TargetDirectory where a derive yields the identical value | fix: replace the impl with #[derive(Default)] on TargetDirectory (DirectoryState already derives Default and Arc>: Default) | [packages/d2b-resource-runtime/src/target.rs:581-584] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0099` | low | `d2b-resource-runtime` | inherent ResourceProvenance::from_str shadows the FromStr trait name | fix: implement std::str::FromStr for ResourceProvenance and parse at the single use site in row_from | [packages/d2b-resource-runtime/src/spec_store.rs:83-88, packages/d2b-resource-runtime/src/spec_store.rs:556] | actionable | lane/d2b-resource-runtime-p2.md - -**`d2b-session`** - -- `RS-0100` | low | `d2b-session` | decode_attachment_control walks the descriptor table with an index loop plus manual offset arithmetic where an iterator pipeline fits | fix: replace the `for _ in 0..count` loop with `bytes[3..].chunks_exact(ATTACHMENT_DESCRIPTOR_BYTES).take(usize::from(count)).map(decode_attachment_descriptor).collect::, _>>()` | [engine.rs:1802, engine.rs:1803, engine.rs:1807] | actionable | lane/d2b-session-p2.md -- `RS-0101` | low | `d2b-session` | send_authorized_ttrpc re-implements the exact verb allow-list check that validate_ttrpc_permit already encodes | fix: call `validate_ttrpc_permit(&permit, now_tick)?` instead of re-writing the matches! block | [admission.rs:1593, admission.rs:956, admission.rs:958] | actionable | lane/d2b-session-p2.md - -**`d2b-sk-frontend`** - -- `RS-0102` | low | `d2b-sk-frontend` | `zone_path` accumulates labels with a `let mut Vec` + push loop where an iterator pipeline collects | fix: replace the loop with `value.split('/').map(|label| ZoneLabelId::parse(label).map_err(|_| format!("{name} is not a valid Zone label path"))).collect::, String>>()?` before `ZonePath::new(labels)` | [packages/d2b-sk-frontend/src/config.rs:178] | actionable | lane/tail-6.md - -**`d2b-unsafe-local-helper`** - -- `RS-0103` | low | `d2b-unsafe-local-helper` | terminate_scope and stop_scope normalize a NotFound into Ok via `(error == ScopeError::NotFound).then_some(()).ok_or(error)?`, a boolean-then-Option chain that hides the two-branch control flow at the exact spot a reader asks "what happens on NotFound" | fix: `if error != ScopeError::NotFound { return Err(error); }` in both terminate_scope and stop_scope, then `Ok(())` | [packages/d2b-unsafe-local-helper/src/systemd.rs:260, packages/d2b-unsafe-local-helper/src/systemd.rs:277] | actionable | lane/d2b-unsafe-local-helper.md - -**`d2b-zone-routing`** - -- `RS-0104` | low | `d2b-zone-routing` | `SealedZoneTopology::longest_suffix_match` walks `for start in 0..labels.len()` with an inline `continue`, where the same logic is a `find_map` over the index range | fix: replace the loop with `(0..labels.len()).find_map(|start| { let Ok(suffix) = ZonePath::new(labels[start..].to_vec()) else { return None; }; self.zones.get(&suffix) })` | [packages/d2b-zone-routing/src/resolver.rs:144] | actionable | lane/d2b-zone-routing.md -- `RS-0105` | low | `d2b-zone-routing` | `ZoneTopologyRequest` carries a hand-written `impl Default` that a field-wise derive reproduces exactly | fix: delete the manual impl and add `#[derive(Default)]` to the struct | [packages/d2b-zone-routing/src/service.rs:311] | actionable | lane/d2b-zone-routing.md - -**`d2bd`** - -- `RS-0106` | low | `d2bd` | `current_committed_resource` (9168) is a body-for-body duplicate of `committed_resource` (9153) plus an unused `_operation_id` parameter, and its only caller is `committed_wayland_session_for_vm` (4555) | fix: call `committed_resource` at 4555 and delete `current_committed_resource` | [packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, packages/d2bd/src/resource_runtime.rs:9153] | actionable | lane/d2bd-p1.md -- `RS-0108` | low | `d2bd` | open_resource_plane hardcodes the provider-identity seed window as `for attempt in 0..30` and `Duration::from_secs(2)` although the same-file consts PROVIDER_IDENTITY_SEED_ATTEMPTS (30) and PROVIDER_IDENTITY_SEED_INTERVAL (2s) at composition.rs:14193-14194 document exactly this "30 x 2s" window | fix: use `PROVIDER_IDENTITY_SEED_ATTEMPTS` and `PROVIDER_IDENTITY_SEED_INTERVAL` in the retry loop so the literals cannot drift from the documented window | [packages/d2bd/src/composition.rs:14699, packages/d2bd/src/composition.rs:14710, packages/d2bd/src/composition.rs:14193] | actionable | lane/d2bd-p2.md -- `RS-0109` | low | `d2bd` | dispatch_live_guest_activation_resource builds the identical resource-List json and identical drive_sync dispatch twice (rollback branch and next-ordinal branch), differing only in post-processing | fix: hoist the `list` json and `runtime.dispatch_public_cli_request(&list)` call (with its map_err) above the `if mode == DaemonActivationMode::Rollback` split and branch only the filter/max computation | [packages/d2bd/src/composition.rs:20450-20461, packages/d2bd/src/composition.rs:20486-20498] | actionable | lane/d2bd-p3.md merged: d2bd-p3#10 -- `RS-0111` | low | `d2bd` | `registered_service_decl` (provider_lifecycle) and `registered_service_factories` (resource_plane_v3) are 15-arm `if ... else if` chains over `&'static str` equality where a `match` reads as a table, gets exhaustiveness-free fallthrough by construction, and does not re-test the winner's earlier arms | fix: convert both chains to `match service { PROCESS_EFFECTS_SERVICE.id => ..., ... , _ => None/continue }`, keeping the `as Arc` coercions on the factory arms | [packages/d2bd/src/provider_lifecycle.rs:78, packages/d2bd/src/resource_plane_v3.rs:2226] | actionable | lane/d2bd-p6.md -- `RS-0112` | low | `d2bd` | hand-written `impl Default` on both unit-struct actors (`EffectServiceActor`, `EffectServiceSupervisor`) delegates to `Self::new()` with zero call sites anywhere; a derive emits the same impl and cannot drift | fix: replace both with `#[derive(Default)]` (or delete both; no workspace caller) | [packages/d2bd/src/effect_service_actors.rs:268, packages/d2bd/src/effect_service_actors.rs:411] | actionable | lane/d2bd-p7.md -- `RS-0113` | low | `d2bd` | no-op `let _ =` suppression statements with dead bindings: `let _ = &mut chain;` after the chain re-root (no mutation follows), `let _ = kind;` masking the unused `kind` param of `network_content_fence`, and `let _ = error.code();` masking the unused `error` in the `Refused` arm | fix: delete the statements and bind the now-unused pattern args as `_` / drop the `kind` param | [packages/d2bd/src/forward_rendezvous.rs:672, packages/d2bd/src/shared_provider_effects.rs:1156, packages/d2bd/src/provider_registry.rs:531] | actionable | lane/d2bd-p8.md merged: d2bd-p8#3 -- `RS-0107` | low | `d2bd` | pointless `let setup = setup;` rebind in `reconcile_controller_sessions_locked` shadows the just-bound value to drop a mutability that was never declared | fix: bind once without `mut` and delete the rebind line | [packages/d2bd/src/resource_runtime.rs:6896] | actionable | lane/d2bd-p1.md -- `RS-0110` | low | `d2bd` | qemu_media_registry_state takes `_registry_dir: &str` and never reads it (the probe reads global state), so every caller passes a value into a dead parameter | fix: drop the parameter and the `registry_dir` argument at the sole call site | [packages/d2bd/src/composition.rs:21306-21319, packages/d2bd/src/composition.rs:21291] | actionable | lane/d2bd-p3.md - -**`d2bd-runtime`** - -- `RS-0114` | low | `d2bd-runtime` | build_autostart_plan accumulates two Vecs with side-effect loops then extends a third, where an iterator pipeline partition would express the split | fix: replace the two push loops in build_autostart_plan with a collector pair: `let (net_entries, workload_entries): (Vec<_>, Vec<_>) = resolver.manifest.vms.iter().map(|(name, vm)| { ... }).partition(|e| e.is_net_vm);` then sort each half | [autostart.rs:228-245] | actionable | lane/d2bd-runtime-p1.md -- `RS-0115` | low | `d2bd-runtime` | two fd-extraction loops grow a Vec via `extend` in a `for` over `cmsgs()`, where a filter_map collect would read as one expression | fix: collect `message.cmsgs().map_err)...)?.filter_map(|c| ...).flatten().collect()` into the result Vec in `receive_frame` and `read_frame_with_fds` | [packages/d2bd-runtime/src/unsafe_local_helper.rs:789, packages/d2bd-runtime/src/unix_transport.rs:294] | actionable | lane/d2bd-runtime-p3.md -- `RS-0116` | low | `d2bd-runtime` | `monotonic_tick()` is duplicated verbatim in guest_mode.rs and guest_component_session.rs (identical `OnceLock` elapsed-millis helper, two copies of the same code) | fix: move one `monotonic_tick()` into `crate::runtime_util` and have both modules call it | [packages/d2bd-runtime/src/guest_mode.rs:849, packages/d2bd-runtime/src/guest_component_session.rs:587] | actionable | lane/d2bd-runtime-p4.md -- `RS-0117` | low | `d2bd-runtime` | `impl Default for ConsoleSessionTable` hand-writes what `#[derive(Default)]` produces field-wise (all three HashMap fields are Default) | fix: replace the impl with `#[derive(Default)]` on `ConsoleSessionTable` and delete the manual `default()` | [packages/d2bd-runtime/src/console_session.rs:162] | actionable | lane/d2bd-runtime-p4.md - -**`xtask`** - -- `RS-0118` | medium | `xtask` | gen_layer_catalogs.rs has two byte-identical helpers under different names: `string_slice` and `string_array` share the same signature and body (both emit a `pub const : &[&str]` array), so callers guess which to use and a future shape change drifts only one copy | fix: delete `string_array` and route its 10 call sites (lines 299, 362, 367, 456, 466, 471, 496, 507, 512, 517) through `string_slice`, keeping `string_pair_slice` for the tuple case | [packages/xtask/src/gen_layer_catalogs.rs:147, packages/xtask/src/gen_layer_catalogs.rs:158] | actionable | lane/xtask-p1.md -- `RS-0120` | medium | `xtask` | the daemon-api IPC collector (`parse_rust_items` + `IpcItemCollector`) parses files with `syn`, then slices the original source text back out and re-parses fields and variants with ~150 lines of hand-rolled scanners (`parse_fields`, `parse_variants`, `split_top_level_entries`, `extract_body`, `strip_non_code_lines`, `normalize_ws`, `line_col_to_offset`), duplicating what the `syn` AST already provides and re-implementing angle-bracket depth counting for generics | fix: in `visit_item_struct`/`visit_item_enum`, extract `Field { name, ty }` and variants from `syn::Fields`/`syn::Variant` directly (type text via `quote::ToTokens`), then delete the text parsers and `line_col_to_offset`'s per-span O(n) scan | [packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.rs:1203] | actionable | lane/xtask-p1.md -- `RS-0123` | low | `xtask` | resource_type_authority.rs carries misindented statements (`errors.push(format!(` at column 0, `out.push_str("// @generated\n");` at column 0, `fn drop` under-indented by 4) that rustfmt would reflow; the repo runs no fmt gate, so the drift is committed | fix: reindent the statements at the three sites (or run rustfmt over the file once) | [packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_authority.rs:940, packages/xtask/src/resource_type_authority.rs:1083] | actionable | lane/xtask-p3.md merged: xtask-p3#2 -- `RS-0124` | low | `xtask` | `resource_type.to_string()` in an iterator map over `&[String]` where `.cloned()` is the idiomatic copy | fix: `STANDARD_RESOURCE_TYPES.iter().map(|resource_type| resource_type.to_string()).collect::>()` -> `.iter().cloned().collect::>()` | [packages/xtask/src/nix_inventories.rs:721] | actionable | lane/xtask-p5.md -- `RS-0119` | low | `xtask` | emitted Rust source is embedded as single-line escaped string literals with backslash line continuations (`"... \n \` chains, e.g. the `typed_noun_type` block), making the generator bodies unreadable and brittle to edit; a reviewer cannot diff the embedded code | fix: embed the emitted blocks as raw string literals (the content contains `"` but not `"##`, so `r##"..."##` delimiters work) in `surface_catalog_source` and in `redact_generated_protobuf_formatting`'s `raw_display`/`redacted_formatting` templates | [packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473] | actionable | lane/xtask-p1.md -- `RS-0121` | low | `xtask` | `sanitize_generated_rust` contains a corrupted replacement literal `"#![allow(clipto_camel_casepy)]\n"` that can never match any generator output, so the sanitizer silently keeps whatever attribute the line was meant to strip in the committed generated file | fix: replace the literal with the actual protobuf/ttrpc-emitted marker it targets (or delete the line if the marker is no longer emitted) at main.rs:459 | [packages/xtask/src/main.rs:459] | actionable | lane/xtask-p1.md -- `RS-0122` | low | `xtask` | in `collect_self_binding_scope` the row-close reset block at provider_crate_policy.rs:6662 is dead: a line whose trim equals `}` cannot also contain `SeedSelfBinding`, so the inner reset never fires, its comment describes behavior that never runs, and the inner scan has no exit at the row close (it runs to EOF for every `SeedProvider {`) | fix: drop the dead inner condition, reset `pending_subject`/`pending_role` when `code_text(lines[stop]).trim() == "}"`, and `break` the `while stop < lines.len()` loop there | [packages/xtask/src/provider_crate_policy.rs:6662, packages/xtask/src/provider_crate_policy.rs:6612] | actionable | lane/xtask-p1.md - -### `own` - -Ownership: every clone/to_owned/Rc/RefCell/Arc-Mutex explainable in one sentence; borrows beat copies; cheapest argument types. - -**`X3-cross-crate-duplication`** - -- `RS-0964` | medium | `X3-cross-crate-duplication` | Repeated ownership pattern: public signatures and fields across eight crates leak `Arc`/`&Arc` (accessors returning `&Arc`, constructors taking `Arc` where single ownership suffices, pub fields carrying `Arc>`), forcing callers to see refcount plumbing and blocking signature evolution | fix: return `&T`/owned values and take owned parameters per the ownership-not-clone convention (canonical home is the borrow/owned convention; no shared type involved, so the merge target is per-crate signatures) | [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:491, packages/d2b-provider-toolkit/src/testing/mod.rs:530, packages/d2b-provider-supervisor/src/broker.rs:997] | actionable | lane/X3-cross-crate-duplication.md - -**`d2b`** - -- `RS-0150` | low | `d2b` | redundant clones of paging values that are dead after the call: `cursor.clone()` before `cursor` is overwritten by `next_cursor`, `page_token.clone()` before reassignment from `nextCursor`, and `reference.to_owned()` on a fresh `format!` String | fix: move `cursor` and `page_token` into the calls (reassign afterwards) and move `reference` into the struct literal | [packages/d2b/src/dispatch.rs:548, packages/d2b/src/debug.rs:472, packages/d2b/src/debug.rs:418] | actionable | lane/d2b-p3.md -- `RS-0151` | low | `d2b` | `modern_run` clones the entire argv (`raw_args.clone()`) for `try_parse_from` although `raw_args` is consumed by value from the only caller and never used again | fix: `ModernCli::try_parse_from(raw_args)` | [packages/d2b/src/dispatch.rs:977] | actionable | lane/d2b-p3.md -- `RS-0152` | low | `d2b` | `host_error_envelope` takes seven `&str` parameters and `.to_owned()`s each into the envelope, while callers pass `&format!(...)` results, allocating twice per field | fix: take `impl Into` parameters so `format!` results move in directly | [packages/d2b/src/dispatch.rs:296-313, packages/d2b/src/dispatch.rs:347, packages/d2b/src/dispatch.rs:359, packages/d2b/src/dispatch.rs:371-377] | actionable | lane/d2b-p3.md -- `RS-0149` | low | `d2b` | three `.clone()` calls feed `json!` operands, which serde_json serializes by reference (`to_value(&expr)`), so the clones are dropped immediately | fix: pass `parsed.schema_version`, `issue_kinds`, and `parsed.issues` to `json!` without `.clone()` | [packages/d2b/src/doctor.rs:1062, packages/d2b/src/doctor.rs:1069, packages/d2b/src/doctor.rs:1070] | actionable | lane/d2b-p2.md - -**`d2b-audit`** - -- `RS-0125` | low | `d2b-audit` | `OperationIdentity::parse` calls `AuditHash::parse(value.to_owned())`, allocating a String though `AuditHash::parse` takes `impl Into` and `&str: Into` holds | fix: pass `value` directly (`AuditHash::parse(value)`) | [packages/d2b-audit/src/operation.rs:79] | actionable | lane/d2b-audit.md - -**`d2b-broker`** - -- `RS-0129` | low | `d2b-broker` | `RealPidfdSpawner::spawn` clones the whole payload argv into a never-read `_argv` binding on every spawn | fix: delete `let _argv = payload.argv.clone();` (keep the explanatory comment; the placeholder child needs no argv) | [packages/d2b-broker/src/ops/pidfd.rs:210] | actionable | lane/d2b-broker-p3.md -- `RS-0131` | low | `d2b-broker` | enroll's registry-read fallback clones the just-written record although it is never used again | fix: replace `unwrap_or_else(|_| vec![record.clone()])` with `unwrap_or_else(|_| vec![record])` in `enroll` | [packages/d2b-broker/src/ops/media.rs:220] | actionable | lane/d2b-broker-p7.md -- `RS-0130` | low | `d2b-broker` | in `context_worker_loop` the Bootstrap reply clones the entire persisted state (`let _ = reply.send(Ok(state.state.clone()))`) just to unblock open()/open_async(), which discard the reply value (`?`), so each broker open copies the whole `PersistedTrustedContext` for nothing. | fix: shrink `ContextCommand::Bootstrap`'s oneshot reply to `Sender>` and send `Ok(())` without touching `state`;; delete the `state.state.clone()` site (keep the `let _ =` on the send alone). | [src/envelope/mod.rs:671] | actionable | lane/d2b-broker-p6.md - -**`d2b-broker-composition`** - -- `RS-0126` | low | `d2b-broker-composition` | `audit_crate` iterates `&added` and clones every dependency name into the report fields, though `added` is dead after the loop | fix: consume it with `for name in added { ... report.forbidden_dependencies.push(name); ... report.proc_macro_dependencies.push(name); }` (passing `&name` to `is_proc_macro`), removing both clones | [packages/d2b-broker-composition/src/dependency_surface.rs:251, packages/d2b-broker-composition/src/dependency_surface.rs:255] | actionable | lane/d2b-broker-composition.md -- `RS-0127` | low | `d2b-broker-composition` | the manifest scan checks `report.forbidden_dependencies.contains(&crate_name.to_string())`, allocating a fresh String per forbidden crate name (8 per audit run) for a membership test | fix: use `report.forbidden_dependencies.iter().any(|name| name == crate_name)` | [packages/d2b-broker-composition/src/dependency_surface.rs:272] | actionable | lane/d2b-broker-composition.md -- `RS-0128` | low | `d2b-broker-composition` | `dependency_tree` clones every node id into `queue` and `seen` although all ids borrow from `metadata` for the whole traversal | fix: type the traversal as `Vec<&str>` / `BTreeSet<&str>` (`let mut queue = vec![root_id];`, `seen.insert(id)`), leaving the returned `Vec` untouched | [packages/d2b-broker-composition/src/dependency_surface.rs:340, packages/d2b-broker-composition/src/dependency_surface.rs:343] | actionable | lane/d2b-broker-composition.md - -**`d2b-bus`** - -- `RS-0132` | low | `d2b-bus` | ResourceCall::authorization_request clones the whole AssignmentIdentity and mutation Vec just to learn whether ScopedCommitTransport::new rejects them, and invoke clones the same pair again to build the real transport | fix: add a reference-taking ScopedCommitTransport::validate(&AssignmentIdentity, &[ScopedResourceMutation]) in d2b-core-controller and call it from authorization_request so the validation clone disappears | [packages/d2b-bus/src/router.rs:480, packages/d2b-bus/src/router.rs:2928] | actionable | lane/d2b-bus-p1.md -- `RS-0133` | low | `d2b-bus` | `SubjectContextDigest::of_subject` builds six owned `String`s (four `to_owned()` on `&str`/`&'static str` fields plus two `to_canonical_string()` calls) only to hash length-prefixed bytes | fix: iterate `&[&str]` slices (the label helpers already return `&'static str`, and the subject/service/purpose accessors expose `&str`) and feed `len()` and `as_bytes()` directly, dropping all six allocations per digest | [packages/d2b-bus/src/session/prologue.rs:72-78] | actionable | lane/d2b-bus-p2.md -- `RS-0134` | low | `d2b-bus` | `VerifiedRouteAdmission::revalidate` clones the whole admission body (including the session binding) on every call, and `ZoneLinkSession::admit`/`is_open` invoke it on every forwarded operation | fix: add a by-reference verification path (a `verify_body(&self, body: &RouteAdmissionBody)` helper or a `revalidate` that digests `&self.body` without rebuilding owned evidence) so the re-check allocates nothing | [packages/d2b-bus/src/session/contract.rs:1046-1056, packages/d2b-bus/src/session/zone_link.rs:147] | actionable | lane/d2b-bus-p2.md - -**`d2b-contracts-provider`** - -- `RS-0137` | low | `d2b-contracts-provider` | duplicate-detection set in `validate_descriptor` clones every label key (`seen.insert(label.key.clone())`) where a borrowed `BTreeSet<&str>` suffices | fix: declare `let mut seen: BTreeSet<&str> = BTreeSet::new();` and insert `&label.key` | [packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:497, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:500] | actionable | lane/d2b-contracts-provider-p2.md -- `RS-0135` | low | `d2b-contracts-provider` | `ProviderManifest::validate_runtime_artifacts` takes `impl IntoIterator` by value, forcing `entries.clone()` and `self.runtime_artifacts.clone()` at both call sites that already hold the vec | fix: change the signature to `entries: &[TargetRuntimeArtifacts]` and drop both clones (census shows no external callers, so the pub signature change is contained) | [packages/d2b-contracts-provider/src/v3/provider.rs:2497, packages/d2b-contracts-provider/src/v3/provider.rs:2531, packages/d2b-contracts-provider/src/v3/provider.rs:2580] | actionable | lane/d2b-contracts-provider-p1.md -- `RS-0138` | low | `d2b-contracts-provider` | `allowed_telemetry_value` allocates a fresh String just to test zone validity (`validate_zone(value.to_owned()).is_ok()`) although `validate_zone` only reads the value | fix: give the zone grammar a `&str`-based check (for example `fn is_valid_zone(value: &str) -> bool` used here, keeping the owning `validate_zone` for the three construction call sites that need the validated String back) | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1591, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1549] | actionable | lane/d2b-contracts-provider-p2.md -- `RS-0136` | low | `d2b-contracts-provider` | `ProviderManifest::new` and `ComponentDescriptor::with_state_namespaces` clone identifiers into dedup sets that could borrow | fix: use `BTreeSet<&BoundedToken>` / `BTreeSet<&ResourceTypeName>` for `component_ids`, `owned_types`, `bound_types`, and `ids` | [packages/d2b-contracts-provider/src/v3/provider.rs:2438, packages/d2b-contracts-provider/src/v3/provider.rs:2445, packages/d2b-contracts-provider/src/v3/provider.rs:2455, packages/d2b-contracts-provider/src/v3/provider.rs:1459] | actionable | lane/d2b-contracts-provider-p1.md - -**`d2b-contracts-resource`** - -- `RS-0139` | low | `d2b-contracts-resource` | `StateDigest::parse` clones its String before delegating to `SchemaFingerprint::parse` (volume_state.rs:138), but that function takes `impl Into`, so `value.as_str()` avoids the copy | fix: `SchemaFingerprint::parse(value.as_str())` | [packages/d2b-contracts-resource/src/v3/volume_state.rs:138] | actionable | lane/d2b-contracts-resource-p1.md - -**`d2b-contracts-zone-session`** - -- `RS-0142` | low | `d2b-contracts-zone-session` | ZoneLinkRouteWithdrawal::new clones the entire route-id vec only to detect duplicates | fix: sort the owned vec in place and check windows(2), mirroring the crate's own dedup pattern in RoleBindingSpec::with_facets (role_binding.rs:273-276) | [zone_routing.rs:883] | actionable | lane/d2b-contracts-zone-session-p2.md -- `RS-0140` | low | `d2b-contracts-zone-session` | `HandshakeOffer::from(policy.clone())` at 7 sites across two crates: the by-value `impl From for HandshakeOffer` (component_session.rs:1172) forces a clone at every site that holds `&EndpointPolicy`, and every in-repo caller clones | fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in component_session.rs and switch the 7 sites to borrow; then delete the by-value impl if the census stays clone-only | [src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session.rs:1014, d2b-session/src/admission.rs:593] | actionable | lane/d2b-contracts-zone-session-p1.md -- `RS-0143` | low | `d2b-contracts-zone-session` | reject_runtime_or_private_fields clones the whole spec object (object.clone().into_inner()) just to wrap it for the walk, on every BundleResource::new call | fix: make walk iterate the CanonicalJsonObject map directly (and a sibling fn for arrays) so no CanonicalJsonValue wrapper or clone is built | [resource_bundle.rs:944, resource_bundle.rs:149] | actionable | lane/d2b-contracts-zone-session-p2.md -- `RS-0141` | low | `d2b-contracts-zone-session` | `ResourceExportSpec::validate_target` clones `target.resource_type()` and `target.metadata().name()` out of a borrowed `&ResourceEnvelope` only to rebuild the ref for comparison, because `ResourceRef::new` takes owned parts and the envelope exposes no borrowed accessor | fix: add `impl From<&ResourceEnvelope> for ResourceRef` (or a `resource_ref()` accessor) in d2b-contracts-resource and use it at the comparison site | [src/v3/resource_export.rs:545, src/v3/resource_export.rs:546] | actionable | lane/d2b-contracts-zone-session-p1.md -- `RS-0144` | low | `d2b-contracts-zone-session` | ServiceDescriptor::new clones each method String for BoundedText::parse, which takes impl Into | fix: pass method.as_str() (String: From<&str> satisfies the bound) | [services.rs:216] | actionable | lane/d2b-contracts-zone-session-p2.md - -**`d2b-core`** - -- `RS-0148` | low | `d2b-core` | `path_bearing_key_violations` clones a borrowed `String` (`Value::String(s) => s.clone()`) only to run `.contains('/')` on it | fix: render through `Cow<'_, str>` (`Cow::Borrowed(s.as_str())` for the string arm, `Cow::Owned(other.to_string())` otherwise) so the common string case copies nothing | [packages/d2b-core/src/static_invariants.rs:201] | actionable | lane/d2b-core-p2.md -- `RS-0147` | low | `d2b-core` | `ResourceUid::parse(value.clone())` plus `parts.network_uid.clone()` in find_network_spec and build_resource_network_intents, and `ZoneId::parse(zone.clone())` in zone_resource_bundle_zones, clone to feed parse/compare where `&str` suffices | fix: `ResourceUid::parse(value.as_str())` and compare `parse(...).ok().as_ref().map(ResourceUid::as_str) == Some(parts.network_uid.as_str())`; `ZoneId::parse(zone.as_str())`; the parse signatures are `impl Into` so `&str` converts without allocation | [packages/d2b-core/src/bundle_resolver.rs:1973, packages/d2b-core/src/bundle_resolver.rs:3354, packages/d2b-core/src/bundle_resolver.rs:1629] | actionable | lane/d2b-core-p1.md - -**`d2b-core-controller`** - -- `RS-0145` | low | `d2b-core-controller` | OwnerIndex::plan clones the entire observed child map (`self.children.get(owner).cloned()`) though every later use is a read-only borrow, copying every ObservedChild (digest strings, dependency sets) per reconcile | fix: bind `let observed = self.children.get(owner).ok_or(OwnerReconcileError::OwnerNotRelisted)?;` and pass `&observed` to the existing `.get`, `for ... in &observed`, and `ordered_observed_refs` calls | [owner_reconcile.rs:1072-1075] | actionable | lane/d2b-core-controller-p2.md -- `RS-0146` | low | `d2b-core-controller` | AuthorityReservation::reserve_durable clones the whole request into admit_authority_inner_with_operation and only afterwards builds the durable claim from the same request, when the claim can be computed first and the request moved | fix: compute `let claim = AuthorityStorageClaim::Generic(request.durable_claim());` before the lock block, then pass `request` by value into admit_authority_inner_with_operation, deleting the `.clone()` | [authority.rs:2803, authority.rs:2806] | actionable | lane/d2b-core-controller-p2.md - -**`d2b-process-conformance`** - -- `RS-0153` | low | `d2b-process-conformance` | LaunchTicket's consuming `with_*` builders clone the whole `launch_identity` (two `String` fields plus refs) before delegating to a by-value `LaunchIdentity::with_*`, although moving the field out of the consumed ticket and writing the result back does the same job without the copy | fix: `self.launch_identity = self.launch_identity.with_owner(owner_ref.clone())?;` (same shape at the other three sites: with_owner_uid, with_owner_ref, with_target_ref) | [packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/ticket.rs:610, packages/d2b-process-conformance/src/ticket.rs:631, packages/d2b-process-conformance/src/ticket.rs:664] | actionable | lane/d2b-process-conformance.md - -**`d2b-provider`** - -- `RS-0154` | low | `d2b-provider` | `ProviderAgent::dispatch` clones the full canonical-JSON request per dispatch (agent.rs:290)even though only `request.method` and `request.timeout_ms` are used after the `timeout`, both Copy | fix: extract `let method = request.method;` before the `timeout)...)`, move `request` into `self.service.dispatch)...)` instead of `request.clone()`, and use `method` in the audit record | [packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304] | actionable | lane/d2b-provider.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0155` | low | `d2b-provider-clipboard-wayland` | finalize_selection clones pending.mimes into all_mimes only to compute has_secret before consuming the Vec by into_iter; the borrow of pending.mimes ends before the move, so the clone is avoidable | fix: compute `has_secret_hint(pending.mimes.iter().map(String::as_str))` first, then `pending.mimes.into_iter().filter(...)` | [packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-config-nixos`** - -- `RS-0156` | low | `d2b-provider-config-nixos` | `GuestConfigReader::dispatch` copies the just-validated document bytes (`document.bytes().to_vec()`, up to 512 KiB per guest read on the dedicated worker) only so `read_guest_config` can re-validate the already-valid `GuestConfigDocument` | fix: give `GuestConfigDocument` a consuming accessor (`into_bytes()` or `impl From for Vec`, `bytes` field stays private) and pass it straight into the `impl Into>` parameter | [packages/d2b-provider-config-nixos/src/ttrpc.rs:111, packages/d2b-provider-config-nixos/src/controller.rs:106] | actionable | lane/d2b-provider-config-nixos.md - -**`d2b-provider-credential`** - -- `RS-0157` | low | `d2b-provider-credential` | dead derives: `#[derive(Clone)]` on `CredentialDriver` and `#[derive(Default)]` on `RecordingRuntime` are never used by any call site | fix: drop `Clone` from `CredentialDriver` (driver.rs:342) and `Default` from `RecordingRuntime` (test_support.rs:178), keeping `RecordingRuntime::new` as the only constructor | [packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/test_support.rs:178] | actionable | lane/d2b-provider-credential.md - -**`d2b-provider-device-gpu`** - -- `RS-0158` | low | `d2b-provider-device-gpu` | the started worker identity is cloned solely so validate_started_identity runs after the store | fix: validate `&identity` before `self.gpu_identity = Some(identity)` (same for video), storing on the failure branch first to preserve the test-pinned retain-for-finalize contract | [packages/d2b-provider-device-gpu/src/controller.rs:272, packages/d2b-provider-device-gpu/src/controller.rs:325] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-device-tpm`** - -- `RS-0159` | low | `d2b-provider-device-tpm` | avoidable clones of Option and String where a reborrow suffices: resource_controller.rs:233-234 clones self.volume_ref only to borrow it, resource_controller.rs:247 clones self.process_ref the same way, effects_service.rs:280 clones self.device_ref to pass `&self.device_ref` to key(), and effects_service.rs:450 clones self.zone to call zone.as_str() on a live self | fix: use self.volume_ref.as_ref().ok_or(...)?, self.process_ref.as_ref(), self.key(&self.device_ref), and self.zone.as_str() | [resource_controller.rs:233, resource_controller.rs:247, effects_service.rs:280, effects_service.rs:450] | actionable | lane/d2b-provider-device-tpm.md - -**`d2b-provider-device-usbip`** - -- `RS-0160` | low | `d2b-provider-device-usbip` | lease admission in `KernelUsbipDispatcher` clones each 16-byte lease three times per reservation (`ledger.insert)..., lease.clone())`, `self.x = Some(lease.clone())`, `Ok(lease.clone())`) | fix: move the lease into the field and clone from the field for the map and the return (two clones), or return `self.x.as_ref().unwrap().clone()` after the insert | [broker.rs:194-208, broker.rs:218-232, broker.rs:313-321, broker.rs:333-341] | actionable | lane/d2b-provider-device-usbip.md - -**`d2b-provider-display-wayland`** - -- `RS-0161` | low | `d2b-provider-display-wayland` | FilterPolicy carries `dmabuf_filters: std::sync::Arc` (built at policy.rs:316, cloned into DmabufHandler at filter.rs:1305) while the entire proxy is a single-threaded `Rc` graph - no thread or `'static` boundary justifies Arc, and the conc seeds are all zero | fix: switch the field and `DmabufHandler::new` parameter to `Rc` | [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:316] | actionable | lane/d2b-provider-display-wayland-p1.md - -**`d2b-provider-guest`** - -- `RS-0162` | low | `d2b-provider-guest` | Retiring obsolete children sorts by teardown rank plus row name by cloning every row's name String into the sort-key tuple | fix: sort with a comparator borrowing the name (`sort_by(|a,b| teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name).then_with(|| a.key.name.cmp(&b.key.name)))`), dropping the per-row allocation | [packages/d2b-provider-guest/src/driver.rs:981] | actionable | lane/d2b-provider-guest.md -- `RS-0163` | low | `d2b-provider-guest` | The ACA framework controllers clone each stored candidate list before collect (`state.sandbox.clone().into_iter().collect()`), allocating an intermediate Vec per candidate read | fix: `state.sandbox.iter().cloned().collect()` (same element copies, one fewer allocation | [packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/effects_service.rs:256] | actionable | lane/d2b-provider-guest.md - -**`d2b-provider-guest-azure-container-apps`** - -- `RS-0164` | low | `d2b-provider-guest-azure-container-apps` | CompletedOperationLedger::record evicts the oldest entry by cloning the map key only to hand it to BTreeMap::remove, which accepts a borrowed key | fix: drop the `.map(|(operation_id, _)| operation_id.clone())` and call `self.completed.remove(&oldest)` directly on the `&AcaOperationId` that `iter().min_by_key)...)` yields | [src/controller.rs:156-157] | actionable | lane/d2b-provider-guest-azure-container-apps.md -- `RS-0165` | low | `d2b-provider-guest-azure-container-apps` | reconcile_observed clones the whole owned `record` parameter into `self.observed` and then matches on it, although only the Copy `lifecycle` field is read after the store | fix: `let lifecycle = record.lifecycle; self.observed = Some(record); match lifecycle { ... }` | [src/controller.rs:500-501] | actionable | lane/d2b-provider-guest-azure-container-apps.md -- `RS-0166` | low | `d2b-provider-guest-azure-container-apps` | in the Suspended/Stopped arm of reconcile_observed the owned `record` parameter is dead after the resume closure is built, yet `record.id.clone()` copies the id instead of moving it out | fix: `let id = record.id;` (partial move) before the `move` closure | [src/controller.rs:527] | actionable | lane/d2b-provider-guest-azure-container-apps.md -- `RS-0167` | low | `d2b-provider-guest-azure-container-apps` | the stop and delete stages clone the entire observed `AcaSandboxRecord` (`self.observed.clone().ok_or)...)?`) although the closures consume only `record.id` | fix: clone just the id (`self.observed.as_ref().ok_or)...)?.id.clone()`) and move that into the closure | [src/controller.rs:417-419, src/controller.rs:469-471] | actionable | lane/d2b-provider-guest-azure-container-apps.md -- `RS-0168` | low | `d2b-provider-guest-azure-container-apps` | one_candidate and one_disk_image clone the single match out of a slice pattern although they own the `candidates` parameter and return an owned record | fix: consume with `let mut it = candidates.into_iter(); match (it.next(), it.next()) { (Some(c), None) => Ok(Some(c)), (None, None) => Ok(None), _ => Err)...) }` | [src/controller.rs:892, src/controller.rs:903] | actionable | lane/d2b-provider-guest-azure-container-apps.md -- `RS-0169` | low | `d2b-provider-guest-azure-container-apps` | AcaProviderConfig::validate() re-clones all 11 fields to re-run the constructor checks, when every check is readable from `&self` | fix: extract a private `fn validate_refs(&self) -> Result<(), AcaTypeError>` holding the resource_type() comparisons and call it from both `new` (on the raw args) and `validate` (on self) | [src/effects.rs:450-464] | actionable | lane/d2b-provider-guest-azure-container-apps.md merged: d2b-provider-guest-azure-container-apps#10 - -**`d2b-provider-guest-azure-virtual-machine`** - -- `RS-0170` | medium | `d2b-provider-guest-azure-virtual-machine` | PSK secret copied twice in `start_psk_delivery`: `copy_for_delivery()` already returns an owned `Zeroizing>` and the extra `.to_vec()` produces a plain, non-zeroized `Vec` copy of the secret | fix: `PskExtensionPayload::from_secret(psk.copy_for_delivery().into_inner())` (or pass the `Zeroizing` value directly; zeroize 1.9 implements `From> for T`) | [src/controller/mod.rs:791, src/bootstrap.rs:42] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md -- `RS-0171` | low | `d2b-provider-guest-azure-virtual-machine` | `self.vm_handle.clone().ok_or)...)` clones the handle only to pass it by reference to an effect call | fix: `let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?;` and pass `handle` (no mutable borrow of `vm_handle` is live across the effect await) | [src/controller/mod.rs:640, src/controller/mod.rs:764] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md -- `RS-0172` | low | `d2b-provider-guest-azure-virtual-machine` | `self.pending_delete_operation_id.clone().ok_or)...)` clones a `String` only to borrow it for `start_vm_delete` | fix: `let operation_id = self.pending_delete_operation_id.as_deref().ok_or(AzureVmError::Ambiguous)?;` and pass `operation_id` | [src/controller/mod.rs:852] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md -- `RS-0173` | low | `d2b-provider-guest-azure-virtual-machine` | `base32(&digest.finalize())[..20].to_owned()` allocates the full base32 string and then a second 20-char copy | fix: `let mut id = base32(&digest.finalize()); id.truncate(20); id` (or cap the length inside `base32`) | [src/controller/mod.rs:1046] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0174` | low | `d2b-provider-guest-qemu-media` | `QmpSession::execute` clones every dispatched QmpCommand into the bounded history before executing (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266); per-field borrow splitting makes the clone avoidable: push the owned command into `commands` and execute from `commands.back()` (`let Self { transport, commands, .. } = self;` then `commands.push_back(command); transport.execute(commands.back().expect("just pushed"))`(removes 1-4 String copies per QMP command | fix: destructure the two fields and reorder push/execute (drop `command.clone()` | [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-host`** - -- `RS-0175` | low | `d2b-provider-host` | avoidable clones of the row key strings before parsing into identity newtypes: `ResourceTypeName::parse`/`ResourceName::parse` take `impl Into`, so `&String` converts without cloning | fix: pass `&ctx.key().type_name` / `&ctx.key().name` at driver.rs:263/266 (or `.as_str()`) | [packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266] | actionable | lane/d2b-provider-host.md - -**`d2b-provider-network-local`** - -- `RS-0176` | low | `d2b-provider-network-local` | collision-detection BTreeSet stores owned Strings from borrowed &str keys, though the set never outlives the borrow | fix: `let mut unique_interfaces = BTreeSet::new();` and insert `ifname.as_str()` (a set of `&str` borrowing interface_names for its whole short life)) | [src/controller.rs:416-417] | actionable | lane/d2b-provider-network-local.md - -**`d2b-provider-notification-desktop`** - -- `RS-0177` | low | `d2b-provider-notification-desktop` | `commit_reconciliation` takes `SourceReconcileResult` by value but only reads its fields, forcing `.clone()` at both call sites | fix: take `result: &SourceReconcileResult` and drop the two `.clone()` calls | [packages/d2b-provider-notification-desktop/src/controller.rs:1033, packages/d2b-provider-notification-desktop/src/controller.rs:1058, packages/d2b-provider-notification-desktop/src/controller.rs:1297-1318] | actionable | lane/d2b-provider-notification-desktop.md -- `RS-0178` | low | `d2b-provider-notification-desktop` | `NotificationLifecycleSupervisor` wraps its owned backend in `Arc`, counting one reference that nothing else shares | fix: store `backend: B` directly (drop `Arc`) while keeping the `Send + Sync` bounds | [packages/d2b-provider-notification-desktop/src/lifecycle.rs:338, packages/d2b-provider-notification-desktop/src/lifecycle.rs:346] | actionable | lane/d2b-provider-notification-desktop.md - -**`d2b-provider-observability-otel`** - -- `RS-0179` | low | `d2b-provider-observability-otel` | provider-agent methods clone their input strings only to hand them to a token parser, though parse_closed_token could borrow | fix: change parse_token/parse_closed_token (agent.rs:224-244) to take `value: &str` (BoundedToken::parse takes `impl Into`, so `&str` satisfies it),and drop the five `clone()` calls in session_connect/process_effect | [agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285] | actionable | lane/d2b-provider-observability-otel.md - -**`d2b-provider-process`** - -- `RS-0180` | low | `d2b-provider-process` | `envelope.provider_ref.clone().expect("checked")` clones the `Option` at three call sites where `as_ref().expect("checked")` borrows without copying | fix: replace `.clone().expect("checked")` with `.as_ref().expect("checked")` in the `identity()` call at recover, reconcile, and delete | [packages/d2b-provider-process/src/driver.rs:1988, packages/d2b-provider-process/src/driver.rs:2056, packages/d2b-provider-process/src/driver.rs:2105] | actionable | lane/d2b-provider-process.md -- `RS-0181` | low | `d2b-provider-process` | `bind_cloud_hypervisor_guest_uid` takes `argv: &[String]` and clones the whole argv at both return paths (`Ok(argv.to_vec())` and `let mut bound = argv.to_vec()`), while its sole caller never uses `launch_argv` afterwards | fix: take `argv: Vec` by value and return it (caller passes `launch_argv` directly), removing both copies | [packages/d2b-provider-process/src/operations.rs:1354, packages/d2b-provider-process/src/operations.rs:1362, packages/d2b-provider-process/src/operations.rs:2649] | actionable | lane/d2b-provider-process.md - -**`d2b-provider-provider`** - -- `RS-0182` | low | `d2b-provider-provider` | `let zone = ctx.key().zone.clone()` clones a `String` the callee accepts as `impl Into` in three spots | fix: pass `ctx.key().zone.as_str()` / `view.key.zone.as_str()` directly; drop the `zone` local in the fixed-provider branch | [src/driver.rs:355, src/driver.rs:478, src/driver.rs:522] | actionable | lane/d2b-provider-provider.md -- `RS-0183` | low | `d2b-provider-provider` | `ctx.status::().cloned()` deep-clones the whole in-memory status (incl. the `BTreeSet` volume_refs) on every reconcile pass | fix: hold the `Option<&ProviderDriverStatus>` reference (`ctx.status()` returns `Option<&T>`, d2b-resource-runtime/src/context.rs:459); last read of `previous` precedes `ctx.set_status` | [src/driver.rs:360, src/driver.rs:435] | actionable | lane/d2b-provider-provider.md merged: d2b-provider-provider#7 - -**`d2b-provider-shell-terminal`** - -- `RS-0184` | low | `d2b-provider-shell-terminal` | `advance_session` clones the whole `Option` only to end the first `session_mut` borrow before the retired-identity check; the check can compare the live field inside a scoped block instead. | fix: in `ShellAuthorityLedger::advance_session`, wrap the first `session_mut` borrow in `{ ... }` and compare `entry.supervisor_identity.as_ref() != retired_identity` inside it, dropping `let current_identity` and `.clone()`; keep the second borrow for minting and mutation. | [src/service/supervisor.rs:599, src/service/supervisor.rs:601] | actionable | lane/d2b-provider-shell-terminal.md - -**`d2b-provider-system-core`** - -- `RS-0185` | low | `d2b-provider-system-core` | `reconcile_observed` copies `kernel_release`/`os_name` out of a by-value `HostProbeSnapshot` with `to_owned()` where destructuring the owned snapshot moves the Strings | fix: `let HostProbeSnapshot { capabilities, kernel_release, os_name, user_manager_available, minijail_gate, active_process_count } = snapshot;` at the method top and move fields into the report | [src/host.rs:466, src/host.rs:467] | actionable | lane/d2b-provider-system-core.md - -**`d2b-provider-toolkit`** - -- `RS-0187` | low | `d2b-provider-toolkit` | serve_component_session clones all four fields of the owned decoded request per frame (`request.zone().clone(), request.provider_ref().clone(), request.method().clone(), request.payload().clone()`) instead of moving them out | fix: destructure `let ProviderRequest { request_id, zone, provider_ref, method, payload } = request;`, pass the owned values to `dispatch_for_route`, and call `codec.encode_response(&request_id, &response)` | [packages/d2b-provider-toolkit/src/server/adapter.rs:331-334] | actionable | lane/d2b-provider-toolkit-p2.md -- `RS-0188` | low | `d2b-provider-toolkit` | the session loop clones the bound route out of the async mutex twice per frame (`self.authenticated_route.lock().await.clone()` at loop entry and per iteration) to compare identities | fix: compare inside the lock scope, e.g. `if self.authenticated_route.lock().await.as_ref() != Some(&route)`, avoiding the per-frame `AuthenticatedSessionRouteBinding` clone | [packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src/server/adapter.rs:314-316] | actionable | lane/d2b-provider-toolkit-p2.md -- `RS-0186` | low | `d2b-provider-toolkit` | `is_ready_for_route` clones the retained route binding out of the mutex guard (`and_then(|ready| ready.clone())`) only to compare it, allocating the binding's strings on every route check | fix: compare through the guard, `try_lock().ok().is_some_and(|ready| ready.as_ref().is_some_and(|bound| bound.liveness().is_live() && bound == route))`, no clone | [packages/d2b-provider-toolkit/src/base/runtime.rs:530-537] | actionable | lane/d2b-provider-toolkit-p1.md -- `RS-0189` | low | `d2b-provider-toolkit` | `retire_obsolete_children` sorts obsolete rows with `sort_by_key` over `(teardown_rank, row.key.name.clone())`, allocating a String per owned row per pass | fix: use `sort_by` with a comparator `teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name)).then_with(|| a.key.name.cmp(&b.key.name))` | [packages/d2b-provider-toolkit/src/shared_provider.rs:771] | actionable | lane/d2b-provider-toolkit-p2.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0190` | low | `d2b-provider-transport-azure-relay` | `ScopedCredentialRequest::with_deadline` takes `&self` and clones all four owned fields (zone, credential_ref, execution_ref, binding) only to rebuild the struct, while its single in-tree caller can consume the request | fix: change the signature to `with_deadline(self, deadline_ms)` and rebuild with `Self { deadline_ms, ..request }` plus `validate()` | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:190-198, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:1315-1317] | actionable | lane/d2b-provider-transport-azure-relay.md -- `RS-0191` | low | `d2b-provider-transport-azure-relay` | `GatewayCredential::from_material` clones all four secret Strings out of an owned `GatewayCredentialMaterial` (forced today because the material type implements `Drop`, which forbids partial moves) where storing the material as one field would move it in without copies | fix: give `GatewayCredential` a single private `material: GatewayCredentialMaterial` field and move it in `from_material`; field accessors and the redacting `Debug` stay unchanged | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:267-277, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:271-275] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-user`** - -- `RS-0192` | low | `d2b-provider-user` | `serve_inspect_user` clones `request.groups` into the spec even though the owned `InspectUserRequest` could yield it by move; the username clone at the same site is required (reused in `inspect_user_response`) | fix: destructure `let InspectUserRequest { user_ref, username, groups } = request;` and pass `username`/`groups` by value into `UserSpec::new`, borrowing `user_ref` and `username` afterwards | [packages/d2b-provider-user/src/effects_service.rs:179, packages/d2b-provider-user/src/effects_service.rs:164-187] | actionable | lane/d2b-provider-user.md - -**`d2b-provider-volume`** - -- `RS-0193` | low | `d2b-provider-volume` | `decoded_spec` returns `(envelope.clone(), spec)` though the local `envelope` is never used after the clone:an avoidable `Vec` raw-spec copy on every driver op (validate, recover, reconcile, delete) | fix: return `(envelope, spec)` directly | [driver.rs:337] | actionable | lane/d2b-provider-volume.md -- `RS-0194` | low | `d2b-provider-volume` | `desired_binding_intents` takes `ResourceRef` by value though it only reads it (cloning into each `BindingIntent` internally), so every production caller must clone first: driver.rs:380 and d2bd/src/resource_runtime.rs:5882,12921 | fix: change the signature to `&ResourceRef` in `d2b-provider-volume-local/src/bindings.rs:80`, drop the caller clones (callers pass `&volume_ref`) | [driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.rs:5882, d2bd/src/resource_runtime.rs:12921] | actionable | lane/d2b-provider-volume.md - -**`d2b-provider-volume-binding`** - -- `RS-0195` | low | `d2b-provider-volume-binding` | parsed_binding_spec clones the whole parsed spec object to end the as_object_mut() borrow before from_value (row_readers.rs:44), a clone a scoped block removes by letting `spec` move into the conversion | fix: bound the removal borrow in a block (let o = spec.as_object_mut()?; for f in [..] { o.remove(f); }) then serde_json::from_value::(spec) without Value::Object(object.clone()) | [packages/d2b-provider-volume-binding/src/row_readers.rs:38-44] | actionable | lane/d2b-provider-volume-binding.md - -**`d2b-provider-zone-link`** - -- `RS-0196` | low | `d2b-provider-zone-link` | `plan()` clones `record.route_binding` in the `RoutePolicyCommitted` and `SessionGenerationAdvanced` arms only to mutate it and store it back, where a `route_binding.as_mut()` borrow would work (no other borrow of the record is live in either arm) | fix: replace `let Some(mut binding) = record.route_binding.clone() else ...` with `let Some(binding) = record.route_binding.as_mut() else ...` and mutate through the borrow in both arms | [packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/src/zone_links.rs:1706] | actionable | lane/d2b-provider-zone-link.md -- `RS-0197` | low | `d2b-provider-zone-link` | `plan()` clones `record.enrollment` in the `EnrolledSessionEstablished` arm solely to compare the key fingerprint before mutating disjoint record fields | fix: take `record.enrollment.as_ref()`, compare `enrollment.key_fingerprint() != &peer_key_fingerprint` (fingerprint tokens are Copy), and let the borrow end before the `record.link_epoch += 1` mutation | [packages/d2b-provider-zone-link/src/zone_links.rs:1526] | actionable | lane/d2b-provider-zone-link.md - -**`d2b-resource-api`** - -- `RS-0198` | low | `d2b-resource-api` | every bus scoped commit clones the full assignment-mutation list (`transport.mutations().to_vec()`) even though the whole chain only borrows it | fix: change `ResourceApiClient::scoped_commit_batch` (client.rs:110) and `ResourceService::commit_scoped_batch` (service.rs:852) to take `&[ScopedResourceMutation]` and pass `transport.mutations()` directly at adapter.rs:425 | [adapter.rs:425, client.rs:110, service.rs:852] | actionable | lane/d2b-resource-api-p1.md -- `RS-0199` | low | `d2b-resource-api` | redundant `.cloned()` in `StoreAdmissionBinding::verify`: `mutations` is already owned after the destructure, so the iterator clones every mutation before `prepare_mutation` consumes it | fix: `mutations.into_iter().map(prepare_mutation)` | [packages/d2b-resource-api/src/admission.rs:338, packages/d2b-resource-api/src/admission.rs:344, packages/d2b-resource-api/src/admission.rs:345] | actionable | lane/d2b-resource-api-p2.md - -**`d2b-resource-client`** - -- `RS-0200` | low | `d2b-resource-client` | by-value `resource_ref()` accessors clone a `ResourceRef` (target.rs:155, 279, 407) and `ResolvedTarget::matches_assignment` clones just to compare (`self.resource_ref().as_ref() == Some(reference)`, target.rs:424) | fix: give the in-crate comparison a borrow-returning variant (`Option<&ResourceRef>`) and consider tightening the pub accessors later, migrating about 15 caller files | [packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs:279, packages/d2b-resource-client/src/target.rs:407, packages/d2b-resource-client/src/target.rs:424] | actionable | lane/d2b-resource-client.md - -**`d2b-resource-compiler`** - -- `RS-0202` | medium | `d2b-resource-compiler` | LinuxAnchoredDir's three flag accessors (resolve_flags, readable_flags, executable_flags) are public, return rustix::fs::{ResolveFlags,OFlags} (making rustix part of the public contract), and have zero callers anywhere | fix: delete the accessors (the anchored impl reads the module constants directly unless a real consumer arrives | [packages/d2b-resource-compiler/src/linux.rs:93, packages/d2b-resource-compiler/src/linux.rs:98, packages/d2b-resource-compiler/src/linux.rs:103] | actionable | lane/d2b-resource-compiler.md -- `RS-0201` | low | `d2b-resource-compiler` | SchemaCache uses RefCell for a lazy schema cache though the only two call sites could take `&mut self` | fix: change `fn schema(&self,...)` to `fn schema(&mut self,...)`, drop the RefCell holding the cache in plain `BTreeMap` field, and mark `let mut schema_cache` in validate_resources | [packages/d2b-resource-compiler/src/main.rs:1148, packages/d2b-resource-compiler/src/main.rs:1631, packages/d2b-resource-compiler/src/main.rs:818, packages/d2b-resource-compiler/src/main.rs:846] | actionable | lane/d2b-resource-compiler.md -- `RS-0203` | low | `d2b-resource-compiler` | validate_schema_node_with_budget re-gets additionalProperties/items after an if-let shape check and panics "checked above" where a pattern bind removes the second get | fix: `if let Some(additional @ Value::Object(_)) = object.get("additionalProperties") { ... additional ... }` (same for items | [packages/d2b-resource-compiler/src/main.rs:1467, packages/d2b-resource-compiler/src/main.rs:1468, packages/d2b-resource-compiler/src/main.rs:1477, packages/d2b-resource-compiler/src/main.rs:1478] | actionable | lane/d2b-resource-compiler.md -- `RS-0204` | low | `d2b-resource-compiler` | usage() takes a program param it never uses and silences it with `let _ = program;` | fix: drop the `program` parameter (and its `env::args_os().next()` binding from usage() andits six call sites (main.rs:242,245,254,261,264,265 | [packages/d2b-resource-compiler/src/main.rs:269, packages/d2b-resource-compiler/src/main.rs:270] | actionable | lane/d2b-resource-compiler.md -- `RS-0205` | low | `d2b-resource-compiler` | validate_resources serializes every resource with serde_json::to_vec just to measure its wire size, allocating a fresh buffer per resource | fix: serialize into a counting io::sink-style Write (or walk the Value once for a length to drop the per-resource Vec | [packages/d2b-resource-compiler/src/main.rs:704] | actionable | lane/d2b-resource-compiler.md - -**`d2b-resource-runtime`** - -- `RS-0206` | low | `d2b-resource-runtime` | `ResourceView::observed_status` clones the whole `Option` (which can carry a `DriverFailure` with comparison vectors) before the generation filter, so a stale status is copied and then discarded | fix: `self.status.as_ref().filter(|_| self.status_generation == Some(self.generation)).cloned()` | [packages/d2b-resource-runtime/src/manager.rs:205] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0209` | low | `d2b-resource-runtime` | insert_new clones the entire row (spec and metadata Vecs included) only to stamp generation/deleting/created_at | fix: take row: StoredDesiredResource by value in insert_new and destructure it, dropping `..row.clone()`; the caller at spec_store.rs:346 does not use row afterwards | [packages/d2b-resource-runtime/src/spec_store.rs:520-541] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0207` | low | `d2b-resource-runtime` | `ResourceActor::pre_start` clones `args.row` twice (once into the context, once into `state.row`) where one move and one clone suffice | fix: move `args.row` into `ResourceActorState.row` and clone it only for `ResourceContext::new` | [packages/d2b-resource-runtime/src/resource.rs:714, packages/d2b-resource-runtime/src/resource.rs:732] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0210` | low | `d2b-resource-runtime` | SpecStore::list clones the selector's zone/type_name/owner_uid fields to bind SQL params | fix: bind borrowed forms (selector.zone.as_deref(), selector.type_name.as_deref(), selector.owner_uid.as_deref()), which rusqlite params accept | [packages/d2b-resource-runtime/src/spec_store.rs:596-598] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0208` | low | `d2b-resource-runtime` | `spec_object` returns `Ok(spec.clone())` on an owned `serde_json::Value` where the move `Ok(spec)` is legal (the value is not used after) | fix: drop the `.clone()` | [packages/d2b-resource-runtime/src/metadata.rs:191] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0211` | low | `d2b-resource-runtime` | TargetDirectory::assign clones the assignment twice (once into the map, once for the return value) | fix: insert the owned assignment and clone from the map for the return, halving the copies of the 3-string ResourceKey and the resolved handle | [packages/d2b-resource-runtime/src/target.rs:655, packages/d2b-resource-runtime/src/target.rs:663] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0212` | low | `d2b-resource-runtime` | json_object clones every member Value into the map although every caller constructs the member array inline | fix: take members: impl IntoIterator and move values into the map | [packages/d2b-resource-runtime/src/guest_target.rs:1004-1009] | actionable | lane/d2b-resource-runtime-p2.md - -**`d2b-session`** - -- `RS-0213` | low | `d2b-session` | take_authentication and from_verified_adapter clone the whole EndpointPolicy just to build a comparison HandshakeOffer | fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in d2b-contracts-zone-session and call HandshakeOffer::from(policy) | [engine.rs:689, admission.rs:593] | actionable | lane/d2b-session-p2.md - -**`d2b-sk-frontend`** - -- `RS-0214` | low | `d2b-sk-frontend` | `main` clones the whole `PlacementConfig` (owned `ZoneEnrollmentIdentity` inside) only to keep `config` alive for its other fields, and `config.rs` builds `"/dev/uhid".to_owned()` where `PathBuf::from` suffices | fix: destructure `let Config { vm_id, link, uhid_path, placement } = config;` and call `placement.into_placement()` (drop the clone); write `PathBuf::from("/dev/uhid")` via `optional("D2B_SK_UHID_PATH").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/dev/uhid"))` | [packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83] | actionable | lane/tail-6.md - -**`d2b-zone-routing`** - -- `RS-0215` | low | `d2b-zone-routing` | In `ZoneRouteAdmission::consume`, the snapshot's zone pair is copied from `expected` with two `ZonePath` clones per consumed route admission, though `expected` is already owned by the match arm and only compared afterwards | fix: compare every non-zone field first, then move `expected.source_zone`/`expected.target_zone` intosnapshot (or split `validate_snapshot` into a zone-pair phase taking `expected` by value), removing the two clones | [packages/d2b-zone-routing/src/engine.rs:345, packages/d2b-zone-routing/src/engine.rs:346] | actionable | lane/d2b-zone-routing.md - -**`d2bd`** - -- `RS-0221` | low | `d2bd` | the `run_effect` closure (bound `F: FnOnce`) clones `supervisor` and `process_ticket` a second time inside its body, though the captured values can move straight into the `async move` block (which only borrows them( | fix: remove `let supervisor = supervisor.clone();` and `let process_ticket = adoption_ticket.clone();`, letting the outer captures move into the `async move` | [packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_composition.rs:4344] | actionable | lane/d2bd-p5.md -- `RS-0222` | low | `d2bd` | `match context.owner_uid.clone()` at ticket assembly clones the whole `Option` (a String-backed uid) on every launch, including the `None` arm and the guard-false `Some` arm where the value is never consumed | fix: match on `&context.owner_uid` and clone inside the arm (`Some(owner_uid) if ticket.owner_uid().is_none() => ticket.with_owner_uid(owner_uid.clone())`), so the `_ => ticket` path copies nothing | [packages/d2bd/src/process_provider_runtime.rs:4057] | actionable | lane/d2bd-p7.md -- `RS-0216` | low | `d2bd` | avoidable `row.resource_ref.clone()` in `committed_controller_provider_identities`: the field is only borrowed by `committed_provider_spec` and then moved into the result map | fix: pass `&row.resource_ref` to `committed_provider_spec` and `identities.insert(row.resource_ref, (uid, generation))` after the call | [packages/d2bd/src/resource_runtime.rs:359] | actionable | lane/d2bd-p1.md -- `RS-0218` | low | `d2bd` | `let zone = guard.zone().clone()` clones the ZoneId although `guard` can be borrowed for the whole body (it is only used again by its own Drop at scope end) | fix: bind `let zone = guard.zone();` and pass `&zone` to plane.zone and the json! formatters | [packages/d2bd/src/composition.rs:20404] | actionable | lane/d2bd-p3.md -- `RS-0217` | low | `d2bd` | nine call sites pass `.to_owned()` into parsers that take `impl Into` (d2b-contracts-resource identity.rs:79,155,279,393), where `&str: Into` makes the allocation unnecessary | fix: drop `.to_owned()` at 181, 4625, 9911, 9931, 10096, 10138, 10212, 11078, 11079, 11082 | [packages/d2bd/src/resource_runtime.rs:181, packages/d2bd/src/resource_runtime.rs:4625, packages/d2bd/src/resource_runtime.rs:9931, packages/d2bd/src/resource_runtime.rs:10096] | actionable | lane/d2bd-p1.md -- `RS-0219` | low | `d2bd` | typed_error_from_resolution_error clones `workload_id` while destructuring an owned error; the binding can be moved into TypedError::WorkloadAliasConflict because `candidates` is only joined by reference | fix: bind `workload_id` (no `.clone()`) in the AliasConflict arm | [packages/d2bd/src/composition.rs:21091] | actionable | lane/d2bd-p3.md -- `RS-0223` | low | `d2bd` | avoidable `let zone = request.zone.clone();` in `ForwardRendezvous::invoke`: `zone` is used only as the `BTreeMap::get` key inside the `self.zones.lock().await` block, whose scope does not outlive the `request` borrow, so `zones.get(&request.zone)` compiles without the clone | fix: drop the clone and borrow `&request.zone` | [packages/d2bd/src/forward_rendezvous.rs:456, packages/d2bd/src/forward_rendezvous.rs:458-466] | actionable | lane/d2bd-p8.md -- `RS-0220` | low | `d2bd` | `ResourceName::parse(readable.clone())` clones a just-built String although parse takes `impl Into` and `&readable` converts without allocation | fix: `ResourceName::parse(&readable)` | [packages/d2bd/src/composition.rs:20638] | actionable | lane/d2bd-p3.md -- `RS-0224` | low | `d2bd` | `validate_network_config_volume_spec` clones the whole JSON `spec` document (`let mut base = spec.clone();`) just to strip three fields and re-parse as `VolumeSpec`; on the `upsert_volume_content` path the document is cloned again at the caller, so the same wire document is cloned and re-parsed twice per reconcile/readiness check | fix: take the spec by ownership once at the boundary and parse to `VolumeSpec` directly (drop the clone by passing the already-owned `Value`) | [packages/d2bd/src/shared_provider_effects.rs:690, packages/d2bd/src/shared_provider_effects.rs:854-858, packages/d2bd/src/shared_provider_effects.rs:891-895] | actionable | lane/d2bd-p8.md - -**`d2bd-runtime`** - -- `RS-0225` | low | `d2bd-runtime` | DagExecutor::run_split clones `state` into api_ready then matches the same value by move, when matching `&state` would keep it | fix: `match &state { .. }`, bind `ApiReadyState::Error { reason }` by reference in the format! call, and set `api_ready = Some(state)` after the match | [dag.rs:423-424] | actionable | lane/d2bd-runtime-p1.md -- `RS-0226` | low | `d2bd-runtime` | three `operation_id.to_string()` copies of an already-owned `String` are produced only to be borrowed or passed along (`complete_pending` takes `String` just for one comparison), so each completed/rejected helper op pays a heap alloc | fix: change `complete_pending` to take `operation_id: &str` and pass `&result.operation_id` / `&rejected.operation_id` at the three call sites (the second local `let operation_id = result.operation_id.to_string()` becomes `&result.operation_id` directly) | [packages/d2bd-runtime/src/unsafe_local_helper.rs:625, packages/d2bd-runtime/src/unsafe_local_helper.rs:629, packages/d2bd-runtime/src/unsafe_local_helper.rs:644] | actionable | lane/d2bd-runtime-p3.md -- `RS-0227` | low | `d2bd-runtime` | `ConsoleSessionTable` lookups allocate a `String` on every call (`ConsoleClientHandle(session_handle.to_owned())` in five methods) because the map key newtype does not implement `Borrow` | fix: implement `Borrow` for `ConsoleClientHandle` (or key the two maps by `String`) so `self.clients.get(session_handle)` resolves without allocation | [packages/d2bd-runtime/src/console_session.rs:250, packages/d2bd-runtime/src/console_session.rs:268, packages/d2bd-runtime/src/console_session.rs:293, packages/d2bd-runtime/src/console_session.rs:304] | actionable | lane/d2bd-runtime-p4.md -- `RS-0228` | low | `d2bd-runtime` | every audit write clones the whole `DaemonEvent` (strings included) in `enqueue` because the write API takes `&DaemonEvent`, while every caller (d2bd composition.rs:19356, tests) constructs the event solely to write it | fix: change `write_event`/`write_event_with_authority`/`write_event_async`/`write_event_with_authority_async` to take `DaemonEvent` by value and drop the `event: event.clone()` in `enqueue` | [packages/d2bd-runtime/src/daemon_audit.rs:976, packages/d2bd-runtime/src/daemon_audit.rs:1003] | actionable | lane/d2bd-runtime-p4.md - -**`xtask`** - -- `RS-0231` | low | `xtask` | `check_members(&repo_root, members.clone())` clones the whole workspace-member vec at the check entry point because `check_members` (provider_crate_policy.rs:7916) takes `Vec` by value while its body only reads it (`.iter()`, `.iter().map()`); the signature forces the clone | fix: change `fn check_members(repo_root: &Path, members: &[WorkspaceMember])` and drop the clone at the call site (second caller at 9560 passes `&manifest_workspace_members(&root)?`) | [packages/xtask/src/provider_crate_policy.rs:577, packages/xtask/src/provider_crate_policy.rs:7916] | actionable | lane/xtask-p2.md -- `RS-0236` | low | `xtask` | `compute_context(root, spec)` takes `ContextSpec` by value,so both caller loops clone the spec they still need afterwards | fix: change `fn compute_context(root: &Path, spec: ContextSpec)` (and the `compute_lock_context` recursion at production_closure.rs:431) to take `spec: &ContextSpec`,removing the `.clone()` at both loop call sites | [packages/xtask/src/production_closure.rs:263, packages/xtask/src/production_closure.rs:379] | actionable | lane/xtask-p4.md -- `RS-0238` | low | `xtask` | Baseline map build clones each `CrateCensus`'s `crate_dir` and `counts` twice per crate although the later baseline check only re-borrows them | fix: build `CensusBaseline` from `crates.into_iter().map(|c| (c.crate_dir, c.counts)).collect()` (when `json_out` is set( and drive the `--baseline` check loop from `&baseline.crates` instead of `&crates` | [packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287] | actionable | lane/xtask-p5.md -- `RS-0232` | low | `xtask` | `check_shared_family_knowledge_with` builds `exempt: BTreeSet<(String, &str)>` with `row.module.to_owned()` and probes it with `signal.module.clone()`, when the ratchet rows are `&'static str` and the signal already owns a `String`; both the build-time to_owned and the per-signal clone disappear by keying borrowed strs | fix: `let exempt: BTreeSet<(&str, &str)> = ratchet.iter().map(|row| (row.module, row.token)).collect()` and probe `exempt.contains(&(signal.module.as_str(), signal.token))` | [packages/xtask/src/provider_crate_policy.rs:5200, packages/xtask/src/provider_crate_policy.rs:5206] | actionable | lane/xtask-p2.md -- `RS-0237` | low | `xtask` | `check_outputs` binds `ApprovalProjection` twice in a row,but the first binding is never read after the second clone | fix: replace `let approval = advisory.approval.clone();` followed by `Some(approval.clone())` with one `Some(advisory.approval.clone())` | [packages/xtask/src/production_closure.rs:383, packages/xtask/src/production_closure.rs:386] | actionable | lane/xtask-p4.md -- `RS-0234` | low | `xtask` | `nix_string_list` takes `impl IntoIterator`, forcing every caller to `.to_owned()` its `&'static str` fields at seven call sites only to borrow them again inside `nix_string` | fix: change the signature to `impl IntoIterator` (or `&[&str]`) and delete the `.map(|field| (*field).to_owned())` closures at the call sites | [packages/xtask/src/provider_packaging.rs:163, packages/xtask/src/provider_packaging.rs:206, packages/xtask/src/provider_packaging.rs:222, packages/xtask/src/provider_packaging.rs:230] | actionable | lane/xtask-p3.md -- `RS-0233` | low | `xtask` | `profile_catalog` clones every row's `wire_variant` String (`row.wire_variant.clone()`) only to format it into the generated profile catalog text; the values are never mutated or stored | fix: return `Vec<&str>` via `.filter_map(|row| row.wire_variant.as_deref())` and change `string_list` (gen_broker_operations.rs:772) to take `Item = &str` (its only two call sites are 860-861) | [packages/xtask/src/gen_broker_operations.rs:844, packages/xtask/src/gen_broker_operations.rs:772] | actionable | lane/xtask-p2.md -- `RS-0235` | low | `xtask` | `resource_ref_schema(pattern: String, allowed_types: &[String])` forces `.to_owned()`/`String::from` at every call site, including static regex literals that never need an owned String | fix: change the signature to `pattern: &str` and `allowed_types: &[&str]` (both serialize into `json!` unchanged) and drop the conversions at the call sites | [packages/xtask/src/semantic_service_schemas.rs:32, packages/xtask/src/semantic_service_schemas.rs:44, packages/xtask/src/semantic_service_schemas.rs:55, packages/xtask/src/semantic_service_schemas.rs:61] | actionable | lane/xtask-p3.md -- `RS-0229` | low | `xtask` | `apply_citation_fixes` clones `lines[index]` before mutating it (`let mut line = lines[index].clone();`) although the slot is borrowed `&mut` and then reassigned on the same iteration | fix: `let mut line = std::mem::take(&mut lines[index]);` per the skill's `mem::take` pattern | [packages/xtask/src/provider_crate_policy.rs:7257] | actionable | lane/xtask-p1.md -- `RS-0230` | low | `xtask` | two ratchet lookups build an owned tuple just to call `BTreeSet::contains`, allocating a cloned String per signal during tree-wide scans (`family_exempt.contains(&(signal.module.clone(), token))` and `exempt.contains(&(signal.crate_name.clone(), signal.module.clone(), signal.token))`) | fix: replace `contains` with `family_exempt.iter().any(|(module, token)| *module == signal.module && *token == token)` (and the 3-tuple equivalent), or key both sets on `&str` like the neighboring `structural_exempt` set | [packages/xtask/src/provider_crate_policy.rs:6375, packages/xtask/src/provider_crate_policy.rs:8750] | actionable | lane/xtask-p1.md - -### `type` - -Type-driven design: illegal states representable - flag soup, Option pairs, stringly-typed state, parse-once over validate-everywhere. - -**`X2-generated-boundary`** - -- `RS-0954` | medium | `X2-generated-boundary` | the broker catalog view emits the authz facets as string literals (`secret_access: "None"`, `broker_required: "Yes"`, `audit_mode: "Yes"` at `broker_operation_catalog.rs:25-27` and every row) into the hand-written `BrokerAuthzFacets` struct whose fields are `&'static str` (`catalog.rs:98-102`), while the same generator emits the same declared data as typed enums in the sibling authz view (`SecretAccess::None`, `BrokerRequirement::Yes`, `AuditMode::Yes` at `broker_operation_authz.rs:12-19`); the broker-composition router string-matches the facet (`row.authz.secret_access != "None"` at routing.rs:98) and a hand-written row already drifts case (`audit_mode: "yes"` at `d2b-broker/src/envelope/mod.rs:2277` vs generated "Yes") | fix: change `BrokerAuthzFacets.secret_access/broker_required/audit_mode` to the existing `SecretAccess`/`BrokerRequirement`/`AuditMode` enums (`d2b-core/src/privileges.rs:48,61,83`; d2b-broker already depends on d2b-core per Cargo.toml:48) and make `generate_catalog` emit enum idents exactly as `generate_authz` already does | [packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19] | actionable | lane/X2-generated-boundary.md -- `RS-0955` | medium | `X2-generated-boundary` | `BrokerOperationRow.disposition` is `&'static str` (`catalog.rs:181`) holding a closed 4-value set emitted by the generator (`disposition: "promoted-live"` etc. at `broker_operation_catalog.rs:17` and 97 more rows), string-matched at catalog.rs:590,773,779,791 and runtime.rs:12562, while the same generator already maps every other closed set to enums (`owner_variant`, profile match, `StubTarget`) | fix: add a `Disposition` enum (four variants: callable-read-only, promoted-live, stubbed-unimplemented, compile-time-only) beside `StubTarget` in `d2b-broker/src/catalog.rs:266`, change the struct field, and have `generate_catalog` emit `Disposition::X` like `owner_variant` | [packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_operation_catalog.rs:17, packages/d2b-broker/src/catalog.rs:181, packages/d2b-broker/src/catalog.rs:590] | actionable | lane/X2-generated-boundary.md -- `RS-0956` | low | `X2-generated-boundary` | the operation-name vocabulary is emitted as strings (`HOST_OPERATION_CATALOG`/`GUEST_OPERATION_CATALOG: &[&str]` at `broker_operation_profiles.rs:8-41`, `operation: "Hello"` at `broker_operation_catalog.rs:11`) and admission is a string `contains` (`BrokerProfile::allows_operation` at `d2b-contracts-broker/src/broker_wire.rs:864-889`), while the same generator emits the w3 subset as the typed `W3BrokerOperation` enum (`w3_broker_operations.rs`, re-exported at `d2b-contracts-broker/src/lib.rs:11`) | fix: have `generate_profiles`/`generate_catalog` emit a full closed `BrokerOperationName` enum (all 98 rows, not just the 24 w3 variants) with `as_str`, and type the catalogs and row `operation` field against it; the wire boundary keeps the string spelling via `as_str` | [packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11] | actionable | lane/X2-generated-boundary.md -- `RS-0957` | low | `X2-generated-boundary` | the authz view's positional `row)...)` helper calls carry a bare boolean at argument 5 (`false`/`true` for `destructive` at `broker_operation_authz.rs:12-19` and every row), the boolean-trap shape the type lens names, in a 988-line generated file where the field is the routing-relevant facet (`row.authz.destructive` at routing.rs:98) | fix: emit `Destructive::No`/`Destructive::Yes` (or named-field construction) from `generate_authz` and drop the `#[allow(clippy::too_many_arguments)]` on the hand-written `row()` helper at `d2b-core/src/privileges.rs:687-708` | [packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-core/src/privileges.rs:687-708] | actionable | lane/X2-generated-boundary.md - -**`X3-cross-crate-duplication`** - -- `RS-0962` | high | `X3-cross-crate-duplication` | Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one member, d2b-provider-wayland-policy, panics on caller input at the family engine's public boundary) | fix: type the args field as `d2b_contracts_resource::v3::ZoneId` (or a `BoundedToken`) in each `*DriverArgs` and parse once at the daemon construction boundary, with `SharedProviderDriverArgs` in d2b-provider-toolkit as the shared home the family args mirror | [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-credential/src/driver.rs:295] | actionable | lane/X3-cross-crate-duplication.md - -**`d2b`** - -- `RS-0263` | low | `d2b` | ZoneContext stores the validated Zone name as a bare String and re-validates it at every construction site instead of carrying the invariant in the already-imported ZoneId type | fix: store `ZoneId` in ZoneContext (field at context.rs:713), build `zone_ref()` and `zone_name()` from it, delete `validate_zone_name` (context.rs:2751) and the duplicated double validation in `discover` (context.rs:752 and context.rs:763), and replace the `expect` re-parses in `from_socket` (context.rs:801-803) with direct construction | [context.rs:713, context.rs:2751, context.rs:801] | actionable | lane/d2b-p1.md -- `RS-0264` | low | `d2b` | closed CLI vocabularies carried as `String` and validated at every call site: `ExecKillArgs.signal` checked by `matches!` in `kill`, and `endpoint_class: Option` checked by `validate_endpoint_class` in `list` and `watch` | fix: clap `ValueEnum` on the args fields so an invalid value is a parse error and the runtime checks disappear | [packages/d2b/src/exec.rs:90, packages/d2b/src/exec.rs:345, packages/d2b/src/endpoint.rs:34, packages/d2b/src/endpoint.rs:42] | actionable | lane/d2b-p3.md - -**`d2b-audit`** - -- `RS-0239` | medium | `d2b-audit` | `EvidenceChain` derives `Deserialize` (evidence_chain.rs:50) while its accessors assume a non-empty identity list: `invoking_identity()` panics via `.last().expect)...)`, `initiating_identity()` indexes `&self.identities[0]`, and `depth()` underflows on `len() - 1`; the "identities never empty" invariant is enforced only by the constructors, so a wire payload with `"identities": []` deserializes into the illegal state | fix: hand-write `Deserialize` for `EvidenceChain` rejecting an empty `identities` (the crate's own admission-gate pattern in operation.rs), or make the accessors total | [packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115, packages/d2b-audit/src/evidence_chain.rs:121, packages/d2b-audit/src/evidence_chain.rs:102] | actionable | lane/d2b-audit.md - -**`d2b-broker`** - -- `RS-0242` | medium | `d2b-broker` | QmpAttachCleanup models its four-step rollback as four bools (16 states, ~5 valid)with a fixed teardown order | fix: replace `device_added/raw_added/file_added/fdset_added: bool` with an ordered step list or enum so rollback order cannot drift from the attach order | [packages/d2b-broker/src/ops/media.rs:889-892] | actionable | lane/d2b-broker-p7.md -- `RS-0240` | low | `d2b-broker` | `StorageContractError::Refused { reason: String }` carries a closed set of refusal slugs ("storage-path-parent-dir-refused", "storage-path-outside-owned-roots", "storage-path-escapes-owned-root", ...) that tests string-match (storage_contract.rs:380-403) and audit records emit | fix: introduce a `RefusalReason` enum (serde lowercase) so the slug set is exhaustive and a new refusal cannot typo; wire/audit-visible strings make this needs-contract | [packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_contract.rs:380] | needs-contract | lane/d2b-broker-p3.md -- `RS-0241` | low | `d2b-broker` | `reload_behavior` is a stringly-typed wire value re-validated at every call site (`validate_nm_reload_behavior` here and the remove path in ops/nm.rs, per the doc at live_handlers.rs:288-290) instead of parsed once at the bundle boundary | fix: parse `reloadBehavior` into an enum in the bundle resolver so both arms branch on the parsed type and a hand-declared typo fails at resolution; `reloadBehavior` is pinned in docs/reference/schemas/v1/host.json:409 and v2/host.json:543, so needs-contract | [packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362] | needs-contract | lane/d2b-broker-p3.md - -**`d2b-bus`** - -- `RS-0245` | medium | `d2b-bus` | `ZoneLinkSession` carries `admission: Option` and `liveness: Option` that are always both `Some` or both `None` (the two constructors set them in lockstep), so a half-set lane is representable and would silently skip admission revalidation | fix: fold the pair into one `established: Option` holding both values (the test lane stays the `None` case), making the impossible combination unconstructible | [packages/d2b-bus/src/session/zone_link.rs:111-117] | actionable | lane/d2b-bus-p2.md -- `RS-0243` | low | `d2b-bus` | ResourceQuery carries assignment: Option and scope: Option that are always both Some or both None, with a runtime validate_scoped re-check at every use site to keep the pair in sync | fix: fold the pair into one Option<(AssignmentIdentity, ScopedResourceScope)> or a ScopedQuery struct so the one-Some state is unrepresentable and the re-validation disappears | [packages/d2b-bus/src/router.rs:218-219, packages/d2b-bus/src/router.rs:298-337] | actionable | lane/d2b-bus-p1.md -- `RS-0244` | low | `d2b-bus` | UnixSubjectRecord holds expected_peer: Option and expected_peer_uid: Option where exactly one is always Some, and bind() ORs the two options at match time as if the state were open | fix: replace the pair with an enum (Exact(PeerCredentials) | Uid(u32)) so the exactly-one invariant is structural and the runtime OR branch disappears | [packages/d2b-bus/src/router.rs:1445-1446, packages/d2b-bus/src/router.rs:1667-1674] | actionable | lane/d2b-bus-p1.md - -**`d2b-contracts-broker`** - -- `RS-0246` | medium | `d2b-contracts-broker` | `HandoffCoordinator.source_remains_usable: bool` is fully derivable from `state` (false iff `Completed`, true in every other phase), so the pair `{ state: Completed, source_remains_usable: true }` is an illegal state constructible through durable-record deserialization and the two fields can desync | fix: drop the field, derive the accessor from `self.state != HandoffState::Completed`, keep `#[serde(default)]` for old broker records (the wire `ApplyHostGenerationHandoffResponse.source_remains_usable` field stays as-is) | [packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broker/src/host_generation.rs:294-315] | actionable | lane/d2b-contracts-broker.md -- `RS-0247` | medium | `d2b-contracts-broker` | `CanonicalAuditDigest(pub String)` exposes a public field that bypasses the SHA-256-spelling invariant its `parse` constructor and hand-written `Deserialize` enforce, so a literal construction can mint an invalid digest | fix: make the tuple field private and keep `as_str()` (serde transparent and JsonSchema work with a private field; wire shape unchanged) | [packages/d2b-contracts-broker/src/broker_wire.rs:2805, packages/d2b-contracts-broker/src/broker_wire.rs:2807-2821] | actionable | lane/d2b-contracts-broker.md - -**`d2b-contracts-control`** - -- `RS-0248` | medium | `d2b-contracts-control` | `AuditResponse` pairs `complete: bool` with `next_cursor: Option`, encoding 4 states of which 2 are illegal, guarded only by the runtime `validate_audit_page` at deserialize | fix: replace the pair with an enum (`Complete` / `More(AuditExportCursor)`) so the illegal combos are unrepresentable, deleting `validate_audit_page` | [public_wire.rs:2166, public_wire.rs:2203] | needs-contract | lane/d2b-contracts-control.md -- `RS-0249` | low | `d2b-contracts-control` | status DTOs carry stringly-typed state (`mode`, `state`, `kind`, `status` as `String`) mirroring daemon-side vocabularies instead of closed enums | fix: convert the closed vocabularies (realm mode, gateway state, qemu runner/registry state, read-model kind) to kebab-case enums on both daemon and wire sides | [cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672] | needs-contract | lane/d2b-contracts-control.md -- `RS-0250` | low | `d2b-contracts-control` | `MutationFlags` models dry-run/apply/json as three booleans while the doc comment itself records that "the daemon rejects requests that set neither `dry_run` nor `apply`", i.e. an illegal state the type still represents | fix: encode the mode as an enum variant (e.g. `MutationMode::{DryRun, Apply}` plus a separate json flag) and delete the daemon-side runtime rejection | [public_wire.rs:316, public_wire.rs:311] | needs-contract | lane/d2b-contracts-control.md - -**`d2b-contracts-provider`** - -- `RS-0253` | medium | `d2b-contracts-provider` | `BindingChildRequest::process` and `process_for_user` accept `kind: BindingChildKind` including `Endpoint`, so an Endpoint carrying process fields is constructible and must be rejected at runtime (`InvalidProducer`, child_resources.rs:502-510), and the sibling check `producer_role.is_some() && kind != Endpoint` (child_resources.rs:499) is unreachable because only `endpoint()` sets `producer_role` and it hardcodes `Endpoint` | fix: take a restricted `ProcessChildKind { Process, EphemeralProcess }` in the two process constructors (all seven in-tree call sites pass `BindingChildKind::Process`), then delete both runtime checks | [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:499, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:502] | actionable | lane/d2b-contracts-provider-p2.md -- `RS-0251` | low | `d2b-contracts-provider` | `ComponentDescriptor::new` takes a `declares_state_volume: bool` parameter that can only be `false`: `true` is rejected at the top of the constructor, the Deserialize path passes the literal `false`, and the flag is only ever set through `with_state_namespaces` | fix: remove the parameter from `ComponentDescriptor::new` and update the ~20 call sites (census below), keeping the wire-only `declaresStateVolume` field and its consistency check inside the Deserialize Wire struct | [packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/src/v3/provider.rs:1368, packages/d2b-contracts-provider/src/v3/provider.rs:1720, packages/d2b-contracts-provider/src/v3/provider.rs:3455] | actionable | lane/d2b-contracts-provider-p1.md -- `RS-0252` | low | `d2b-contracts-provider` | `ComponentDescriptor` stores `execution` and `execution_wire` as parallel fields where the wire shape is derived from the enum, so one fact has two representations that only `with_execution` keeps in sync | fix: implement `Serialize` for `ComponentExecution` emitting the flat `binaryRef` key (absent for `InProcessBootstrap`), drop the `execution_wire` field and the private `ComponentExecutionWire` struct | [packages/d2b-contracts-provider/src/v3/provider.rs:1333, packages/d2b-contracts-provider/src/v3/provider.rs:1335, packages/d2b-contracts-provider/src/v3/provider.rs:1418] | actionable | lane/d2b-contracts-provider-p1.md - -**`d2b-contracts-resource`** - -- `RS-0256` | medium | `d2b-contracts-resource` | NixosGenerationStatus.observed_generation is a bare u64 while the crate already models exactly this value (zero meaning none) as ObservedGeneration in identity.rs | fix: replace the field type with `ObservedGeneration` (serde-transparent u64, same wire bytes and schemars shape) and update the accessor call sites | [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-resource/src/v3/identity.rs:595-606] | needs-contract | lane/d2b-contracts-resource-p2.md -- `RS-0255` | medium | `d2b-contracts-resource` | store-contract digests are bare `String` (`StoredResource.payload_digest` mod.rs:71, `StoredSchema.payload_digest` mod.rs:239, `PreparedStoreMutation.payload_digest` mod.rs:374) while every other identity in this crate is a parsed newtype (SchemaFingerprint, StateDigest), so a non-digest string can flow through the store boundary without a type-level guarantee | fix: type the three fields as `SchemaFingerprint` (or `StateDigest`) and parse at the backend boundary where the digest is computed | [packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resource/src/v3/operations/mod.rs:239, packages/d2b-contracts-resource/src/v3/operations/mod.rs:374] | actionable | lane/d2b-contracts-resource-p1.md -- `RS-0257` | medium | `d2b-contracts-resource` | ActivationRunnerInput.target_generation is a bare u64 carrying a manual zero check plus a hand-rolled `nonzero_u64_schema`, duplicating the nonzero-generation newtype the crate already generates | fix: use the `nonzero_generation!` macro output (e.g. ConfigurationGeneration, transparent u64 with JsonSchema minimum 1) for the field, deleting `ActivationRunnerInputError::GenerationInvalid`, the zero check in `new`, and `nonzero_u64_schema` | [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:59-63, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:77-87, packages/d2b-contracts-resource/src/v3/identity.rs:448-472] | needs-contract | lane/d2b-contracts-resource-p2.md -- `RS-0254` | low | `d2b-contracts-resource` | `StoreSealIdentity::with_store_epoch` (seal.rs:57-61) documents "Bind the seal identity to a nonzero store epoch" but accepts 0 without a check, and the fn has no callers, so the promised invariant is unenforced and untested | fix: reject 0 (return `Result` or `debug_assert!` plus a documented contract) or drop the nonzero claim from the doc | [packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resource/src/v3/operations/seal.rs:58] | actionable | lane/d2b-contracts-resource-p1.md - -**`d2b-contracts-zone-session`** - -- `RS-0258` | low | `d2b-contracts-zone-session` | narrowing_set_is_subset takes a bare empty_allowed_is_unrestricted: bool that flips the empty-allowed semantics between call sites | fix: replace the bool with a two-variant enum (or split into named fns) so the three call sites state the policy they mean | [role_binding.rs:179-182, role_binding.rs:149-162] | actionable | lane/d2b-contracts-zone-session-p2.md - -**`d2b-controller-toolkit`** - -- `RS-0259` | low | `d2b-controller-toolkit` | `ResourceSnapshot` carries `owner_uid: Option` and `owner_generation: Option` that are only ever set together, leaving the illegal one-Some/one-None combination constructible | fix: introduce `OwnerIdentity { uid, generation }` and replace the pair with a single `Option` (fields context.rs:17-18, constructor :61-67; the only external setter call passes both Some - packages/d2b-provider-provider/src/driver.rs:559) | [packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/context.rs:61-67] | actionable | lane/tail-1.md - -**`d2b-core`** - -- `RS-0261` | medium | `d2b-core` | `ManifestShellName(pub String)` exposes its inner String publicly, so the shell-name shape invariant enforced in the hand-written `Deserialize` (and in `shell_name_valid`) can be bypassed by literal construction | fix: make the field private and add an `as_str()` accessor, mirroring the `AllocatorRealmPath` newtype pattern in allocator_config.rs; serde(transparent) keeps the wire shape unchanged | [packages/d2b-core/src/manifest_v04.rs:313] | actionable | lane/d2b-core-p2.md - -**`d2b-core-controller`** - -- `RS-0260` | low | `d2b-core-controller` | AuthorityRequest::provider decides ProviderCardinality by string-comparing the rendered ref to "Provider/observability-otel", a stringly-typed special case whose why is not documented | fix: extract a named constant (e.g. `const OPTIONAL_PROVIDER_REF: &str = "Provider/observability-otel";`) beside the other domain constants and add a one-line doc noting the otel Provider is the one optional cardinality (D049 initial-Provider freeze), or move the decision into a `ProviderCardinality::for_provider(&ResourceRef)` helper | [authority.rs:985-988] | actionable | lane/d2b-core-controller-p2.md - -**`d2b-host`** - -- `RS-0262` | medium | `d2b-host` | `BusId(pub String)` carries no lexical invariant: `BusId::new` accepts any string and the field is public, so the busid grammar is re-validated at every consumer instead of once at the type boundary | fix: make the field private, validate in `BusId::new` (reusing `media::validate_usb_busid`'s grammar) or add `TryFrom<&str>`, keep `#[serde(transparent)]`; then delete the three broker re-validation sites | [packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194] | actionable | lane/d2b-host.md - -**`d2b-process-conformance`** - -- `RS-0265` | low | `d2b-process-conformance` | LaunchTicket models the "zone identity + runtime scope" pairing as two independent `Option` fields whose both-or-neither invariant is re-checked at every mutation and again in `validate()` (`self.zone_uid.is_some() != self.runtime_scope.is_some()`), leaving the illegal single-`Some` state representable | fix: introduce one private struct bundling both (e.g. `struct RuntimeScopeBinding { zone_uid: ResourceUid, scope: ConfigurationDigest }` held as `Option`), keeping the two accessors; the XOR check and the per-mutator guards (ticket.rs:546-552) become unrepresentable | [packages/d2b-process-conformance/src/ticket.rs:387, packages/d2b-process-conformance/src/ticket.rs:395, packages/d2b-process-conformance/src/ticket.rs:768] | actionable | lane/d2b-process-conformance.md - -**`d2b-provider-audio-pipewire`** - -- `RS-0266` | low | `d2b-provider-audio-pipewire` | constructors re-validate invariants the admission gate already enforces: `AudioServiceSpec::owner` (endpoint type) and `AudioBindingSpec::new` (service/target ref types) return the same error variants `validate_audio_service`/`validate_audio_binding` produce, so the same invariant is checked at two layers and the constructors' `Result` promises a rejection path that is dead in practice | fix: drop the checks from `owner()`/`new()` (make them infallible) and keep `validate_audio_*` as the single parse-once admission gate, or delete the gate checks and keep the constructor checks | [src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, src/resource_type.rs:233-246] | actionable | lane/d2b-provider-audio-pipewire.md -- `RS-0267` | low | `d2b-provider-audio-pipewire` | the shared-vs-owned controller mode is a private bool `activate_promoted` (controller.rs:210 vs 218-224) and `finalize`/`finalize_shared` are byte-identical delegations to `finalize_inner`, so the two public methods' behavioral difference is invisible in their signatures and a caller can invoke `finalize_shared` on an owned controller and get promotion activation anyway | fix: encode the mode in the type (typestate or a `MicrophoneHandoff::{Enable,Defer}` field set by construction) so the method contract holds by construction, or collapse the two methods into one documented by the constructor | [src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199] | actionable | lane/d2b-provider-audio-pipewire.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0268` | medium | `d2b-provider-clipboard-wayland` | the config-sourced picker path bypasses the absolute-path validation that the --picker CLI flag enforces, because the check runs on args.picker before the merge with the config value | fix: validate the merged picker value (args.picker.clone().or(picker_from_config)) once after the merge, rejecting relative paths from either source | [src/bin/d2b-clipd.rs:140, src/bin/d2b-clipd.rs:142] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0269` | low | `d2b-provider-clipboard-wayland` | ClipboardRunnerContract carries two boolean fields (watched_configuration_is_dependency, component_session_only) that are hardcoded true in the only constructor clipboard_runner_contract(), leaving three unrepresentable-but-constructible states with no consumer | fix: fold the two flags into the contract's consts or delete the fields and their accessors | [packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13-41, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:44-52] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0270` | low | `d2b-provider-clipboard-wayland` | the picker-completion key is a stringly-typed 7-field value joined with '|' in picker.rs and re-parsed by split('|') in history.rs, so a field-order or separator change silently breaks purge semantics | fix: introduce a small CompletionKey struct (or a shared builder/parser pair) with the fields typed, used by both PickerAuthority::complete and ClipboardHistory::purge_guest | [packages/d2b-provider-clipboard-wayland/src/picker.rs:258-264, packages/d2b-provider-clipboard-wayland/src/history.rs:283] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0271` | low | `d2b-provider-clipboard-wayland` | entry digests are bare "sha256:..." Strings whose only invariant is enforced by a starts_with("sha256:") prefix check at the receipt-minting boundary; a Digest newtype with a private field would make the check once at construction | fix: introduce an EntryDigest newtype constructed by ClipboardEntry (and parsed at the picker boundary) and use it in PickerReceipt and PickerResult::Selected | [packages/d2b-provider-clipboard-wayland/src/picker.rs:247, packages/d2b-provider-clipboard-wayland/src/history.rs:77] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-config-nixos`** - -- `RS-0272` | low | `d2b-provider-config-nixos` | stringly-typed request fields (`identifier`, `against`, `destination`) are re-validated at every entry (constructors, store methods, and `validate_operation`), and the duplicated guest-ref checks have already drifted: `ConfigSyncRequest::new` checks only the resource type while `validate_guest_ref` also requires a non-empty name, so "Guest/" passes the constructor yet fails the boundary | fix: parse-once request fields (private fields, `new()`/`try_from` as the only constructors, transparent serde keeps the wire JSON unchanged) so the per-entry `validate_*` calls collapse; align `ConfigSyncRequest::new` with `validate_guest_ref` | [packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixos/src/service.rs:300-306, packages/d2b-provider-config-nixos/src/service.rs:316-323, packages/d2b-provider-config-nixos/src/service.rs:326-336] | actionable | lane/d2b-provider-config-nixos.md - -**`d2b-provider-credential`** - -- `RS-0273` | low | `d2b-provider-credential` | `CredentialDriverArgs.zone: String` (and the mirrored `CredentialDriver.zone: String`) carries a bare string where the daemon already holds a validated `ZoneId`, so the driver re-derives and re-parses the zone at use sites instead of receiving the invariant | fix: change `zone` to `d2b_contracts_resource::v3::ZoneId` in `CredentialDriverArgs` (driver.rs:295) and `CredentialDriver` (driver.rs:344); the daemon construction site drops `inputs.zone.as_str().to_owned()` and passes `inputs.zone` (resource_plane_v3.rs:2969, where `ConstructionInputs.zone: ZoneId` at resource_plane_v3.rs:1784); `agent_child` then builds `format!("Zone/{}", self.zone.as_str())` without the fallible `ResourceRef::parse` failure path (driver.rs:457-461); test fixtures switch to `ZoneId::parse("dev").unwrap()` | [packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-credential/src/driver.rs:457, packages/d2bd/src/resource_plane_v3.rs:2969] | actionable | lane/d2b-provider-credential.md - -**`d2b-provider-credential-managed-identity`** - -- `RS-0274` | medium | `d2b-provider-credential-managed-identity` | `ManagedIdentityTeardownPlan` exposes its three bools as pub fields, letting a caller construct invalid combos (`stop_agent && delete_agent`, `delete_agent && clear_provider_revoke` that `teardown_plan` never emits | fix: make the fields private with `pub const fn` accessors (or replace with an ordered stage enum); update the literal constructions in tests/binding.rs:1214-1234 | [controller.rs:85-89, tests/binding.rs:1214-1234] | actionable | lane/d2b-provider-credential-managed-identity.md - -**`d2b-provider-device-gpu`** - -- `RS-0275` | medium | `d2b-provider-device-gpu` | `video_started: bool` duplicates `video_identity.is_some()` and is read only by the Debug impl, so the pair can drift into an illegal state | fix: delete the field and use `video_identity.is_some()` in the `GpuController` Debug impl | [packages/d2b-provider-device-gpu/src/controller.rs:79, packages/d2b-provider-device-gpu/src/controller.rs:326, packages/d2b-provider-device-gpu/src/controller.rs:442, packages/d2b-provider-device-gpu/src/controller.rs:552] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-guest`** - -- `RS-0276` | medium | `d2b-provider-guest` | GuestDriverArgs.zone is String while every other Guest surface speaks ZoneId (GuestEffectFacets.zone, GuestDriver.zone,,forcing a parse-at-construction expect at GuestDriver::new | fix: type GuestDriverArgs.zone as ZoneId and pass ZoneId directly into GuestDriver::new, dropping the expect and the daemon-side String round-trip | [packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:788, packages/d2bd/src/resource_plane_v3.rs:2926, packages/d2b-provider-guest/tests/registration.rs:15] | actionable | lane/d2b-provider-guest.md - -**`d2b-provider-guest-azure-container-apps`** - -- `RS-0277` | medium | `d2b-provider-guest-azure-container-apps` | AcaProviderConfig exposes all 11 fields `pub` while its sibling validated configs (AcaRuntimeConfig, AcaSandboxProfile, AcaReadinessPolicy) keep fields private behind constructors, so a literal construction bypasses the execution-boundary validation that `new()`/`validate()` enforce | fix: privatize the fields and add accessors (network_ref, sandbox_transport_alias, defaults are read in-crate at controller.rs:940-946; no external field reads exist) | [src/effects.rs:394-406] | actionable | lane/d2b-provider-guest-azure-container-apps.md - -**`d2b-provider-guest-azure-virtual-machine`** - -- `RS-0278` | medium | `d2b-provider-guest-azure-virtual-machine` | `operation: Option` and `operation_started_at_unix_ms: Option` are always Some-together/None-together on the controller (controller/mod.rs:186-187) and in `AzureVmRecoveryState` (controller/mod.rs:110-118), and `restore_recovery_state` line 278 exists only to reject the illegal half-Some combination | fix: group into `Option` in both the controller and the recovery record, and delete the pair check at controller/mod.rs:278 | [src/controller/mod.rs:278, src/controller/mod.rs:186] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md merged: d2b-provider-guest-azure-virtual-machine#15 -- `RS-0279` | medium | `d2b-provider-guest-azure-virtual-machine` | `BootstrapAdmission { psk: Option, state: BootstrapAdmissionState }` (bootstrap.rs:65-68) can represent Consumed/Expired-with-`Some(psk)`; `consume()` manually forces `psk = None` on every transition | fix: `enum BootstrapAdmission { Pending { psk: BootstrapPsk, expires_at_unix_ms: u64 }, Consumed, Expired }` so the illegal combination is unconstructible (the skill's Option-pair smell) | [src/bootstrap.rs:65, src/bootstrap.rs:82] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md merged: d2b-provider-guest-azure-virtual-machine#14 -- `RS-0280` | low | `d2b-provider-guest-azure-virtual-machine` | `AzureVmUpdate::Resize.size: String` is parse-validated at `validate_update` (controller/mod.rs:982) and parsed again at `apply_update` (controller/mod.rs:1008); `OpaqueAzureRef` is a validating, serde-transparent string wire type | fix: carry `size: OpaqueAzureRef` in the wire enum (JSON shape unchanged, a plain string) and drop both re-parses | [src/controller/mod.rs:82, src/controller/mod.rs:982] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md - -**`d2b-provider-guest-cloud-hypervisor`** - -- `RS-0281` | medium | `d2b-provider-guest-cloud-hypervisor` | `derive_private_runtime_scope` (identity.rs:857) and `CloudHypervisorController::private_runtime_scope` (controller.rs:1808) take `role: &str` validated against exactly the four `ChildRole` variants, stringly-typed state where the enum exists | fix: take `ChildRole` and use `role.suffix()` inside; update the test callers (tests/controller.rs:249, tests/redaction_test.rs:62-104, tests/guest_spec_validation_test.rs:107-110) | [identity.rs:857-865, controller.rs:1808-1818] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0282` | medium | `d2b-provider-guest-cloud-hypervisor` | `CloudHypervisorConfig::default_machine_type` reuses the credential vocabulary type `OpaqueAzureRef` (d2b_contracts_provider::v3::credential) for a machine type that `validate()` restricts to "q35"|"microvm" | fix: introduce a `MachineType` enum (serde kebab-case) in place of `OpaqueAzureRef`, updating the committed root-config.schema.json and provider config wire | [config.rs:20, config.rs:53] | needs-contract | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0283` | medium | `d2b-provider-guest-cloud-hypervisor` | `BootstrapGraph::vmm_readiness`/`vmm_lifecycle` take five positional booleans (bootstrap_graph.rs:142-176) where a swapped argument compiles and silently changes VMM start gating | fix: pass one readiness snapshot struct (the five facts already exist as `GuestDependencySnapshot` accessors) instead of five bools | [bootstrap_graph.rs:142-176, controller.rs:662-670] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0284` | medium | `d2b-provider-guest-qemu-media` | `validate_token` (packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417(re-implements exactly the bounds of the in-tree `BoundedToken::parse` (`^[a-z][a-z0-9-]*$`, up to 63 bytes (at packages/d2b-contracts-resource/src/v3/execution_policy.rs:187-191); a second, slightly looser copy lives in `validate_object_id` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:274) | fix: replace the 7 gate calls (config.rs:142, hotplug.rs:62, process_builder.rs:288, volume.rs:121,165, guest.rs:115,213(with `BoundedToken::parse)...).is_ok()` (route qmp's variant through a first-char check plus the helper), delete the local helper | [packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417, packages/d2b-contracts-resource/src/v3/execution_policy.rs:187, packages/d2b-provider-guest-qemu-media/src/config.rs:142] | actionable | lane/d2b-provider-guest-qemu-media.md -- `RS-0285` | medium | `d2b-provider-guest-qemu-media` | Public `impl Default for ProviderConfig` manufactures an invalid config (`controller_execution_ref: ResourceRef::parse("Guest/invalid").expect)...)` at packages/d2b-provider-guest-qemu-media/src/config.rs:92), which fails its own `validate()` ); its only consumer is a test asserting that invalidity | fix: delete the Default impl (and rewrite the test to build valid-then-mutated configs as its sibling test at tests/config_schema_projection.rs:27 already does), or replace with a `#[doc(hidden)]` `for_test()`-style constructor | [packages/d2b-provider-guest-qemu-media/src/config.rs:89, packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs:5] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-notification-desktop`** - -- `RS-0286` | low | `d2b-provider-notification-desktop` | `NotificationRunnerContract` carries two boolean flags (`watched_configuration_is_dependency`, `component_session_only`) where a cutover enum could make the states explicit | fix: after a policy/ADR change, fold them into a `CutoverState` enum; currently kept per the refusal ledger | [packages/d2b-provider-notification-desktop/src/controller.rs:22-27, docs/explanation/over-engineering-audit-record.md:361] | policy-confirmed | lane/d2b-provider-notification-desktop.md - -**`d2b-provider-observability-otel`** - -- `RS-0287` | low | `d2b-provider-observability-otel` | ProviderAgentAuditEvent stores the four closed audit strings as `String`/`Option` and immediately discards the validated `BoundedToken` (parse-then-copy-back at as_str().to_owned()) | fix: store `BoundedToken`/small enums in the event fields (agent.rs:59,66-68),and render through `BoundedToken::as_str` in the Serialize impl (wire output unchanged) | [agent.rs:56, agent.rs:265, agent.rs:297] | actionable | lane/d2b-provider-observability-otel.md - -**`d2b-provider-process-minijail`** - -- `RS-0288` | low | `d2b-provider-process-minijail` | provider-identity validation is duplicated: `MinijailProcessProvider::validate` re-checks selected provider name and provider ref that `launch::validate_launch_ticket` repeats whenever a platform gate is present, so the two can drift apart | fix: drop the two identity checks from `validate_launch_ticket` (keep the gate check; rename it `validate_platform_gate` to disambiguate from the sibling `d2b-provider-process-systemd/src/launch.rs:8` function of the same name with different semantics) and use `crate::PROVIDER_REF` at lib.rs:160 instead of the literal string | [packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minijail/src/lib.rs:160, packages/d2b-provider-process-minijail/src/launch.rs:50, packages/d2b-provider-process-minijail/src/launch.rs:62] | actionable | lane/tail-3.md - -**`d2b-provider-process-systemd`** - -- `RS-0289` | low | `d2b-provider-process-systemd` | `RestartPolicy.restart_on_failure: bool` is invariant state: the only constructor sets it to `true` and nothing ever mutates it, so the field and its guard encode a state the type cannot otherwise represent | fix: drop the field and the `if !self.restart_on_failure` check in `should_restart`, or add a `RestartPolicy::never()` constructor if the never-restart class is real | [packages/d2b-provider-process-systemd/src/lifecycle.rs:78, packages/d2b-provider-process-systemd/src/lifecycle.rs:100] | actionable | lane/d2b-provider-process-systemd.md -- `RS-0290` | low | `d2b-provider-process-systemd` | `metrics::validate_labels` accepts stringly-typed `(String, String)` label pairs checked against the runtime `LABEL_KEYS` allowlist, so a misspelled key is a runtime rejection instead of a type error | fix: introduce `enum MetricLabelKey { Operation, Outcome, Domain }` with an `as_str()` accessor and take the key side typed | [packages/d2b-provider-process-systemd/src/metrics.rs:7, packages/d2b-provider-process-systemd/src/metrics.rs:4] | actionable | lane/d2b-provider-process-systemd.md - -**`d2b-provider-telemetry-binding`** - -- `RS-0291` | low | `d2b-provider-telemetry-binding` | `TelemetryBindingStatus.phase: &'static str` is stringly-typed state with exactly two valid spellings (`PHASE_PENDING`, `PHASE_DEGRADED`), while the sibling otel crate models the same concept as the `TelemetryBindingPhase` enum | fix: introduce a local `TelemetryBindingPhase` enum with `as_str()` preserving the "Pending"/"Degraded" spellings and use it for the `phase` field, deleting the two `PHASE_*` consts | [packages/d2b-provider-telemetry-binding/src/driver.rs:168, packages/d2b-provider-telemetry-binding/src/driver.rs:170, packages/d2b-provider-observability-otel/src/controller.rs:288] | actionable | lane/tail-4.md - -**`d2b-provider-telemetry-service`** - -- `RS-0292` | low | `d2b-provider-telemetry-service` | `TelemetryServiceStatus` carries stringly-typed state: `phase: &'static str` (three spellings via `PHASE_*` consts) and `projection: serde_json::Value` built by hand with `json!` at three sites, so the `{serviceRole, serviceReadiness}` pair is constructed and indexed by string | fix: add a `TelemetryServicePhase` enum with `as_str()` for the three spellings and a two-field `TelemetryServiceProjection` struct that serializes to the same contract-pinned shape (`SERVICE_STATUS_ALLOWED` spellings at d2b-contracts-provider/src/v3/semantic_services/telemetry.rs:55), replacing the `json!` literals at driver.rs:274-290 and 309-315 | [packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telemetry-service/src/driver.rs:309-315] | actionable | lane/tail-5.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0293` | low | `d2b-provider-transport-azure-relay` | `GatewayGuestZoneLinkRuntime` carries `credential_generation: Option` and `credential_send_key_digest: Option<[u8; 32]>` as two independent Options that are always set or unset together (from_sealed sets both, from_scoped sets neither), leaving the half-set state representable and forcing `write_open_observation`'s `let (Some, Some) else` guard | fix: replace the pair with one `Option` struct (or a `Sealed`/`Scoped` enum carrying the marker data) so the impossible half-set combination stops compiling | [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:258-262] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-volume-local`** - -- `RS-0294` | low | `d2b-provider-volume-local` | VolumeRootHandle carries ten Option fields that are valid only all-Some (from_anchored) or all-None (held), so eleven mixed states are representable; construction is internal today so the mixed states are unreachable, but the fail-closed root-identity handle is exactly where a future partial-construction bug would land | fix: split into a two-variant enum (e.g. `enum VolumeRootHandle { Empty, Anchored(AnchoredHandle) }`) or a typestate pair, keeping the non-Clone/non-Serialize property | [src/identity.rs:72-88, src/identity.rs:146-150] | actionable | lane/d2b-provider-volume-local.md - -**`d2b-resource-api`** - -- `RS-0295` | low | `d2b-resource-api` | `attach_scoped_query_frame` takes a bare `watch: bool` mode flag selecting List versus Watch rewriting, a boolean state the type lens names | fix: replace the parameter with `enum ScopedQueryMethod { List, Watch }` and update the d2b-bus call site (packages/d2b-bus/src/router.rs:2914) | [adapter.rs:124] | actionable | lane/d2b-resource-api-p1.md - -**`d2b-resource-client`** - -- `RS-0296` | low | `d2b-resource-client` | `MetadataInput::validate_lifetime` (call.rs:168) is a re-validation of the invariant `MetadataInput::new` already enforces at construction (private fields); `CallDriver::new` re-checks it (dispatch.rs:189) where it cannot fail | fix: drop the `validate_lifetime()?` re-check at CallDriver::new (or convert to a debug_assert) | [packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs:189] | actionable | lane/d2b-resource-client.md - -**`d2b-session`** - -- `RS-0297` | low | `d2b-session` | `OutboundFrame::channel()` silently falls back to `SESSION_CONTROL` for the constructor-prevented NamedStream-without-stream combination, so an invariant break would misroute a frame to the session control channel with no error | fix: encode the stream inside the class (enum variants `SessionControl`/`TtrpcControl`/`AttachmentControl`/`Named(StreamId, ...)`) or make `channel()` return `Result` and drop the `unwrap_or(SESSION_CONTROL)` fallback | [scheduler.rs:18-21, scheduler.rs:66-68] | actionable | lane/d2b-session-p1.md merged: d2b-session-p1#4 -- `RS-0298` | low | `d2b-session` | stream control is decoded as a raw u8 kind inside a (u8, StreamId, u32) tuple and matched against local constants, so an unknown tag stays representable until the runtime match | fix: introduce a closed StreamControlKind enum with tag()/from_tag() beside the existing AttachmentControl enum | [engine.rs:1702, engine.rs:1295, engine.rs:31] | actionable | lane/d2b-session-p2.md - -**`d2b-unsafe-local-helper`** - -- `RS-0299` | low | `d2b-unsafe-local-helper` | RuntimeLedger.reservations is keyed by `operation_id.to_string()` (a String key) while OperationId already derives Ord + Clone + Hash, so every begin/owns/clear round-trips through a per-call allocation and as_str() re-parsing of an id the caller already owns typed | fix: `BTreeMap` and use the OperationId directly in begin (runtime.rs:193, 206, 230), owns (236) and clear (242); delete operation_key | [packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/runtime.rs:193, packages/d2b-unsafe-local-helper/src/runtime.rs:230, packages/d2b-unsafe-local-helper/src/runtime.rs:236] | actionable | lane/d2b-unsafe-local-helper.md - -**`d2bd`** - -- `RS-0303` | medium | `d2bd` | `force` on guest lifecycle requests is parsed from the wire (composition.rs:6794-6797), stored in DaemonGuestLifecycleEffect.force (6837-6848), and never consulted - apply() only reads it via `let _ = self.force;` (18659) - so `d2b guest ... --force` (sent by d2b/src/guest.rs:283) is silently ignored | fix: implement the force semantics in apply() (e.g. skip the graceful wait) or drop the field and the wire parse | [packages/d2bd/src/composition.rs:18659, packages/d2bd/src/composition.rs:18608] | actionable | lane/d2bd-p2.md -- `RS-0305` | medium | `d2bd` | stringly-typed wire mode compared to string literals: `request.spec.pointer("/mode").and_then(Value::as_str) == Some("authority")` (USBIP service) and `mode == "projection"` (security-key service); an unknown or misspelled mode silently takes the non-authority / non-projection branch, flipping the admission posture without an error | fix: parse the mode once into a typed enum (`#[derive(Deserialize, PartialEq)]` with `rename_all = "kebab-case"`) at the effect boundary and refuse unknown values (fail closed) | [packages/d2bd/src/shared_provider_effects.rs:1299, packages/d2bd/src/shared_provider_effects.rs:1903-1908] | actionable | lane/d2bd-p8.md merged: d2bd-p8#2 -- `RS-0302` | low | `d2bd` | ShutdownDegradedMarker stores `outcome: String` and `severity: String` although the same file defines VmShutdownOutcome (composition.rs:16131) whose label()/degraded_severity() (16205-16239) are the only producers of those strings | fix: derive Serialize on VmShutdownOutcome with `#[serde(rename_all = "snake_case")]` and store the enum in the marker so the report shape cannot drift from the enum | [packages/d2bd/src/composition.rs:16152, packages/d2bd/src/composition.rs:16155, packages/d2bd/src/composition.rs:16131] | actionable | lane/d2bd-p2.md -- `RS-0300` | low | `d2bd` | `ZoneResourceRuntime` carries three gate booleans `policy_installed`/`controller_endpoint_registered`/`watch_admitted` (3041-3043) with only two reachable states - (true, false, false) at open (3230-3232) and (true, true, true) after `activate_published_bundle` (3470-3472) - so six impossible combinations are representable | fix: replace the trio with one enum (e.g. `PlanePublicationStage { BootstrapOnly, Published }`) read by `readiness_error` (8104-8116) | [packages/d2bd/src/resource_runtime.rs:3041, packages/d2bd/src/resource_runtime.rs:3230, packages/d2bd/src/resource_runtime.rs:3470, packages/d2bd/src/resource_runtime.rs:8104] | actionable | lane/d2bd-p1.md -- `RS-0301` | low | `d2bd` | `ControllerSession` encodes ordered once-only teardown progress as three independent booleans `ingress_revoked`/`assignments_revoked`/`transport_closed` (1014-1016), so skipping or reordering a step (e.g. closing the transport before revoking assignments) is representable and silently leaks a lease or a revocation frame | fix: replace the three with a `TeardownStage` enum advanced monotonically in `remove_controller_session` (7614-7650) | [packages/d2bd/src/resource_runtime.rs:1014, packages/d2bd/src/resource_runtime.rs:7614] | actionable | lane/d2bd-p1.md -- `RS-0304` | low | `d2bd` | HostActivationPendingMarker.mode is a stringly-typed activation mode on a persisted marker: it is deserialized, logged and rendered but never validated against the known label set, while the in-Rust mode already exists as DaemonActivationMode | fix: replace `mode: String` with a serde-mirrored enum (e.g. `DaemonActivationMode` behind kebab-case serde, or a marker-local enum) and validate on read; the marker file is written by out-of-tree activation machinery, so the serialized label set is a contract | [packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d2bd/src/composition.rs:21135] | needs-contract | lane/d2bd-p3.md - -**`d2bd-runtime`** - -- `RS-0307` | medium | `d2bd-runtime` | `Wave6Dependencies` (resource_operator_activation.rs:129) is a five-public-bool struct whose named constructors `network_ready_for_guest` and `guest_ready_for_adoption` produce byte-identical state (all five fields true), so two semantic progression stages are indistinguishable and 27 illegal field combinations remain constructible through the pub fields | fix: encode the operator-acceptance progression as a typestate carrier (e.g. `Wave6Dependencies` holding a `Wave6DepStage { WaitingForVolume, WaitingForNetwork, ReadyForAdoption }` enum plus only the facts needed by that stage, fields private), guaranteeing the two stages differ and the impossible combos do not compile; at minimum make the bools private and delete/clarify the duplicate constructor | [resource_operator_activation.rs:129-182, resource_operator_activation.rs:163-177] | actionable | lane/d2bd-runtime-p2.md -- `RS-0309` | medium | `d2bd-runtime` | `DaemonEvent::ApiReadyTimeout.mode: String` models a closed two-value state (`"strict"` | `"no-wait-api"`, documented at daemon_audit.rs:193) as an open string, so an invalid mode is representable and would land in the preserved audit record | fix: introduce a two-variant `SplitReadinessMode`-style enum with `#[serde(rename_all = "kebab-case")]` and use it for the field; serialized bytes stay `"strict"`/`"no-wait-api"` so the daemon-events JSONL shape is unchanged | [packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361] | actionable | lane/d2bd-runtime-p4.md -- `RS-0310` | medium | `d2bd-runtime` | `retarget_mutating_response` and `response_outcome` re-derive the wire outcome as strings (`Some("applied")`, `Some("broker-error")`, `Some("api-ready-timeout")`) although the same file already builds responses from the `MutatingVerbOutcome` enum, forcing every caller into string matching (8 sites in d2bd composition.rs) | fix: add a typed accessor that parses `outcome` into `MutatingVerbOutcome` (serde) and match on the enum variants in `retarget_mutating_response`, keeping the `_` pass-through for unknown broker outcomes | [packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_response_helpers.rs:118] | actionable | lane/d2bd-runtime-p4.md merged: d2bd-runtime-p4#16 -- `RS-0308` | low | `d2bd-runtime` | `classify_peer` takes a bare `production_lookup: bool` mode switch whose meaning ("hermetic test injection skips NSS group-name existence lookup") is invisible at the call sites | fix: replace with a two-variant `PeerLookupMode::{Production, Hermetic}` parameter (or document the bool's contract in a doc comment with the behavior difference), so the admission path's mode is self-describing | [admission.rs:107-108, admission.rs:66, admission.rs:83] | actionable | lane/d2bd-runtime-p2.md merged: d2bd-runtime-p2#7 -- `RS-0306` | low | `d2bd-runtime` | ComponentSessionTransportFailure carries `kind: String` in four Io variants, where std::io::ErrorKind would carry the same class as a typed value | fix: replace the `kind: String` fields of PeerCredentialIo/ConnectIo/WriteIo/AckIo with `io::ErrorKind` and map at call sites (component_session_vsock.rs:150,198,381,410), dropping the `.to_string()` round-trips | [component_session_vsock.rs:32-36] | actionable | lane/d2bd-runtime-p1.md -- `RS-0311` | low | `d2bd-runtime` | the typed-shell target key `(u32, String)` (uid + shell name) is a bare tuple repeated across three collections and every public method signature, so uid/name swap is a type error waiting to happen | fix: extract `TypedShellTargetKey { uid: u32, name: String }` (derive Ord) and use it in `entries`/`recency`/`create_reservations` and the `remember`/`cached`/`forget`/`reserve` signatures | [packages/d2bd-runtime/src/typed_shell_targets.rs:13, packages/d2bd-runtime/src/typed_shell_targets.rs:82] | actionable | lane/d2bd-runtime-p4.md - -**`xtask`** - -- `RS-0314` | medium | `xtask` | inventory.rs re-implements the crate's own `delivery::model::validate_repo_relative_path` with the same invariant (minus the empty-path check), so two validators drift apart | fix: delete the private copy at inventory.rs:230,and call `crate::delivery::model::validate_repo_relative_path(Path::new(path))`, keeping the stricter empty check | [packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557] | actionable | lane/xtask-p4.md -- `RS-0313` | low | `xtask` | `FamilyKnowledgeSignal.text: String` (provider_crate_policy.rs:4664-4675) carries two meanings discriminated only by `class`: literal/identifier text for Literal/Assembled/Identifier, and a serialized count for ServerState (`text: format!("{server_state_count}")` at 5104) that the renderer re-parses (`signal.text.parse::().unwrap_or(0)` at 5179), silently defaulting a non-numeric to 0 | fix: add a typed `count: Option` field (or split the struct per class), fill it at 5104, and render by matching `class` without the parse | [packages/xtask/src/provider_crate_policy.rs:5104, packages/xtask/src/provider_crate_policy.rs:5179] | actionable | lane/xtask-p2.md -- `RS-0315` | low | `xtask` | `EdgeRecord.kind: String` carries the closed Cargo dependency-kind vocabulary {"normal","build","dev","proc-macro"} as a free string through traverse/filter/emit | fix: introduce a closed `EdgeKind` enum parsed once at the metadata boundary (dep_kinds reads at :660-676), serde-renamed to preserve the wire spelling "proc-macro",and regenerate the committed packages/policy-inputs/** closures | [packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660, packages/xtask/src/production_closure.rs:724] | needs-contract | lane/xtask-p4.md -- `RS-0312` | low | `xtask` | `process_provider_ids(metric_label: Option)` uses an optional boolean to select among three label domains (all, metric-only, plus an unreachable `Some(false)` state) where the two production call sites only ever pass `None` or `Some(true)` | fix: split into `all_process_provider_ids()` and `metric_process_provider_ids()` (or a two-variant enum), and update the call sites at gen_layer_catalogs.rs:370, 474, 515 | [packages/xtask/src/gen_layer_catalogs.rs:288, packages/xtask/src/gen_layer_catalogs.rs:515] | actionable | lane/xtask-p1.md - -### `api` - -Public surface: deliberate exports, one path per item, no internals or dependency types in signatures, semver breakage classes. - -**`X2-generated-boundary`** - -- `RS-0952` | medium | `X2-generated-boundary` | the hand-maintained registry `d2b-resource-api/src/generated/mod.rs:3-4` glob-re-exports the entire protobuf module (`pub use d2b_contracts_resource::resource_proto::*;`) as public surface of d2b-resource-api, exposing 47 items including reflection internals (`file_descriptor()` at `d2b_resource_v3.rs:7522`, `special_fields: ::protobuf::SpecialFields` on every message) and forcing `pub use protobuf;` at `d2b-resource-api/src/lib.rs:24` - with zero consumers | fix: delete the `d2b_resource_v3` re-export module from the registry (consumers use `d2b_contracts_resource::resource_proto` directly, e.g. `adapter.rs:560,578`); if a consumer ever needs the types through this crate, re-export named arms instead of a glob | [packages/d2b-resource-api/src/generated/mod.rs:3-4, packages/xtask/src/main.rs:355-370, packages/d2b-resource-api/src/lib.rs:24] | actionable | lane/X2-generated-boundary.md -- `RS-0953` | low | `X2-generated-boundary` | `d2b-audit/src/lib.rs:7` declares `pub mod generated;` but every consumer of the emitted catalog is in-crate (`crate::generated::audit_catalog::...` at record_types.rs:1038,1067,1212,1297,1367) | fix: `mod generated;` (private) in lib.rs; the emitted file and its registry need no change | [packages/d2b-audit/src/lib.rs:7, packages/xtask/src/gen_layer_catalogs.rs:725, packages/d2b-audit/src/generated/audit_catalog.rs:6-8] | actionable | lane/X2-generated-boundary.md - -**`X3-cross-crate-duplication`** - -- `RS-0965` | low | `X3-cross-crate-duplication` | Double-path public surface: eleven crates expose every item of a module at two public paths (`pub mod x` plus root `pub use x::*` or item re-exports), deviating from the house single-surface convention and letting future pub items silently widen API | fix: keep one public path per item (either the module or the root re-export, per the house single-surface pattern the d2b-sk-frontend lane names), deleting the duplicate arm in each lib.rs | [packages/d2b-provider-device-usbip/src/lib.rs:24, packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-zone/src/lib.rs:17, packages/d2b-sk-frontend/src/lib.rs:22] | actionable | lane/X3-cross-crate-duplication.md - -**`d2b`** - -- `RS-0352` | medium | `d2b` | `pub mod host_generation` (lib.rs:25) is the crate's only public module and its three exported items have zero consumers anywhere in the workspace | fix: make it `mod host_generation` (private) until a caller exists, or wire `build_request` into the host-generation CLI flow that currently does not call it | [packages/d2b/src/host_generation.rs:7, packages/d2b/src/host_generation.rs:17, packages/d2b/src/host_generation.rs:36] | actionable | lane/d2b-p1.md -- `RS-0353` | low | `d2b` | zone_support_bundle.rs declares 9 `pub` items (6 structs, 3 consts, build_bundle, render_ndjson) inside a private module, a pub-in-private surface no external caller can reach | fix: reduce to `pub(crate)` or plain items, keeping only what the in-file tests and `run` need | [zone_support_bundle.rs:19, zone_support_bundle.rs:28, zone_support_bundle.rs:99, zone_support_bundle.rs:323] | actionable | lane/d2b-p1.md merged: d2b-p1#4 -- `RS-0354` | low | `d2b` | the d2b lib exports a wide pub surface while the only external consumer (xtask) uses just `d2b::cli_command()`; `pub mod host_generation` and `pub const EXIT_API_TIMEOUT` have zero consumers anywhere | fix: narrow `doctor`/`host_validate` pub items and `EXIT_API_TIMEOUT` to `pub(crate)`, make `host_generation` a private `mod`, keeping only `cli_command`/`run` public | [packages/d2b/src/lib.rs:25, packages/d2b/src/lib.rs:41, packages/d2b/src/doctor.rs:62, packages/d2b/src/host_validate.rs:55] | actionable | lane/d2b-p2.md - -**`d2b-audit`** - -- `RS-0316` | medium | `d2b-audit` | the crate re-exports a large surface with zero external consumers: `sink` (AuditSink/AuditSinkError/AuditWriteOutcome), `segment` (SegmentWriter/FailureInjector/FailurePoint/DEFAULT_MAX_SEGMENT_BYTES/DEFAULT_RETENTION_DAYS), `export` (ExportLine/export_segments/export_segments_range/MAX_EXPORT_*), `rate_limit` (AuditRateLimiter/AuditWriteClass/RateDecision/DEFAULT_AUDIT_WRITES_PER_SECOND), `record_types` (AuditRecord/AuditRecordFields/*Fields/AuditRecordError/AUDIT_SCHEMA_VERSION), and `reconcile`'s `reconcile`/`Reconciliation`/`DurabilityOutcome` are all exported from lib.rs:16-46 but no dependent crate references them; consumers (d2b-broker, d2bd, d2bd-runtime, d2b-session) use only evidence_chain, operation, hash_chain, and `evidence_from_decision_result`/`DurabilityEvidence` | fix: either wire the daemon-side audit writer (d2bd-runtime daemon_audit) to the sink/segment/export stack, or reduce the unwired modules to `pub(crate)` until a consumer exists (crate is `publish = false`) | [packages/d2b-audit/src/lib.rs:16, packages/d2b-audit/src/lib.rs:30, packages/d2b-audit/src/lib.rs:33, packages/d2b-audit/src/lib.rs:37] | actionable | lane/d2b-audit.md merged: d2b-audit#7 - -**`d2b-broker`** - -- `RS-0319` | medium | `d2b-broker` | `ops::sysctl` exports a dead pub surface: `apply_sysctl_intents` (sysctl.rs:84), `ApplySysctlRequest` (16), `with_default_root` (23) and `intent_to_proc_path` (76) are referenced only inside sysctl.rs (its own tests at 258/283); the production entry point is `apply_with_readback` | fix: delete the dead trio (or demote to `pub(crate)` and keep only what tests need) | [packages/d2b-broker/src/ops/sysctl.rs:16, packages/d2b-broker/src/ops/sysctl.rs:84] | actionable | lane/d2b-broker-p3.md -- `RS-0320` | medium | `d2b-broker` | `RouteConflictKey` is exported as `d2b_broker::ops::route::RouteConflictKey` (pub struct with all-pub fields) but its only users are private fns in the same file; its companion record type `RouteOwnershipRecord` is private - the visibility is a leak, not a contract with callers | fix: make it `pub(crate)` or plain `struct` (all users are in-file private helpers: `route_conflicts`, `route_matches_record`, `requested_route_conflict_key`)and drop the pub fields to private | [packages/d2b-broker/src/ops/route.rs:19] | actionable | lane/d2b-broker-p4.md -- `RS-0318` | medium | `d2b-broker` | the GPU and modprobe op modules rise to the crate's public surface through pub mod ops + pub mod gpu/pub mod modprobe (ops/mod.rs:47-48), yet the GPU types (GpuBrokerRole, GpuDeviceClass, GpuOpaqueIdentity, GpuLaunchRequest, GpuProcessObservation, GpuBrokerError)and modprobe's(ModprobeAuditRecord, ModprobeDecision, AllowlistRow, ModprobeBackend, RecordingBackend, dispatch, live_modprobe_if_allowed)have zero consumers outside d2b-broker itself:live_handlers uses only the two gpu validate fns and runtime uses only live_modprobe_if_allowed, all same-crate | fix: narrow the module decls to pub(crate)(ops/mod.rs:47-48), or make the item-level pub to pub(crate)in gpu.rs and modprobe.rs; same-crate call sites are unaffected | [packages/d2b-broker/src/ops/gpu.rs:13, packages/d2b-broker/src/ops/gpu.rs:24, packages/d2b-broker/src/ops/gpu.rs:41, packages/d2b-broker/src/ops/gpu.rs:63] | actionable | lane/d2b-broker-p2.md -- `RS-0322` | medium | `d2b-broker` | `lib.rs` declares `pub mod ops` (src/lib.rs:45) with `pub mod` arms for all 27 executor/helper modules in src/ops/mod.rs:20-94, so every item in them becomes part of the crate's public surface - while the recorded design rationale (src/lib.rs:8-11) is "public API of internal modules that downstream callers may use", and a census finds no downstream crate consumer.. | fix: if a deliberate public-surface decision is desired, keep `pub mod` and record the census in a doc comment or dossier;; otherwise narrow the `pub mod` arms to `pub(crate)` for modules with no out-of-crate consumer (ops/exec_reconcile, ops/audit_op, ops/store_view_posture, ops/store_view_farm, ops/device_worker, ops/security_key, ops/usbip_firewall, ops/nm)and re-export only test-consumed items (`OperationFields` for tests/security_key_broker.rs) under a `#[cfg(any(test, feature = "fake-backends")))]`-style gate. | [src/lib.rs:45, src/ops/mod.rs:20-94] | policy-confirmed | lane/d2b-broker-p6.md -- `RS-0317` | low | `d2b-broker` | pub fn `acquire_lock` takes `_daemon_uid: u32` (underscore-prefixed) that the body never uses - the record owner is always `Uid::current()`, so every caller (live_handlers.rs:467 plus 8 test sites) supplies a value the function ignores | fix: drop the parameter and update the call sites | [packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467] | actionable | lane/d2b-broker-p1.md -- `RS-0321` | low | `d2b-broker` | `CgroupBundleContext::slice_path()` returns an owned `PathBuf` (cloning `parent_slice`) when a `&Path` return serves every in-crate call, forcing a clone per call at the `is_under_slice` check and duplicating the value | fix: change the return to `&Path` (`pub fn slice_path(&self) -> &Path`); the builder methods `vm_interior_path`/`vm_leaf_path`/`vm_role_leaf_path` keep their owned joins and `fields.slice_path`/tuple sites keep their one owned conversion | [packages/d2b-broker/src/ops/cgroup.rs:126-129, packages/d2b-broker/src/ops/cgroup.rs:343] | actionable | lane/d2b-broker-p5.md -- `RS-0323` | low | `d2b-broker` | kernel_table clones the whole KernelConfig into an Arc because it takes `&KernelConfig` | fix: take `config: KernelConfig` by value (or `Arc`) so the one-time clone disappears; the per-handler Arc clones stay | [packages/d2b-broker/src/kernel_ops.rs:99-100] | actionable | lane/d2b-broker-p7.md - -**`d2b-bus`** - -- `RS-0324` | medium | `d2b-bus` | ZoneBus exposes eight pub constructors but only new, with_interaction_subject_issuer, and with_clock_observer_and_metrics_and_interaction_subject_issuer have production callers; with_observer, with_observer_and_metrics, with_clock, with_clock_and_observer, and with_clock_observer_and_metrics are internal delegation rungs or test-only | fix: keep the three live constructors pub, move with_clock/with_clock_observer_and_metrics under #[cfg(test)] or pub(crate), and delete or fold with_observer/with_observer_and_metrics/with_clock_and_observer | [packages/d2b-bus/src/router.rs:1208, packages/d2b-bus/src/router.rs:1224, packages/d2b-bus/src/router.rs:1258, packages/d2b-bus/src/router.rs:1267] | actionable | lane/d2b-bus-p1.md -- `RS-0325` | medium | `d2b-bus` | native_authorizer() returns Arc in a pub signature on both BusAuthorizer and ZoneBus and has zero callers anywhere in the workspace, so the shared-authority accessor is dead surface that also leaks the Arc type | fix: remove both accessors or reduce them to pub(crate) until a daemon consumer exists | [packages/d2b-bus/src/authorization.rs:75, packages/d2b-bus/src/router.rs:1415-1416] | actionable | lane/d2b-bus-p1.md -- `RS-0326` | medium | `d2b-bus` | two public types named `Cancellation` are reachable from the crate root: `d2b_bus::Cancellation` (operations) and `d2b_bus::session::Cancellation` (the re-exported `d2b_session::Cancellation`), so a caller importing both modules gets a name collision and can hand the wrong token to a handler | fix: drop `Cancellation` from the `d2b_session` re-export block in session/mod.rs (the bus's own token shadows the need) or rename one of the two | [packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97] | actionable | lane/d2b-bus-p2.md - -**`d2b-contracts`** - -- `RS-0327` | medium | `d2b-contracts` | `pub fn MediaRef::validate_value` (types.rs:114) is dead:the `opaque_id!`-generated `MediaRef::new` accepts any string without calling it, so the public fn advertises a shape check that never runs on the type it names | fix: either delete the fn, or wire it into construction via a `TryFrom<&str>` boundary on MediaRef (the house parse-gate pattern)so calers cannot bypass it | [packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114] | actionable | lane/d2b-contracts.md - -**`d2b-contracts-broker`** - -- `RS-0328` | medium | `d2b-contracts-broker` | `BrokerRequestEnvelope.test_peer_uid: Option` is a test-only peer-uid override carried on the production wire envelope (serialized, schema-visible), honored only under the broker's `config.test_mode` gate | fix: move the override out of the wire type into the broker's test harness (e.g. a test-only envelope wrapper or a `#[cfg(test)]`-visible field) so the production contract carries no test seam | [packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtime.rs:1628-1632] | needs-contract | lane/d2b-contracts-broker.md -- `RS-0329` | low | `d2b-contracts-broker` | `pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}` at broker_wire.rs:13 re-exports another crate's types into this crate's surface, making each item reachable at two paths (`d2b_contracts::audit_wire::*` and `d2b_contracts_broker::broker_wire::*`), off the house single-surface pattern which places re-export arms in lib.rs | fix: move the re-export to lib.rs or drop it and let consumers import from d2b_contracts (sibling d2b-contracts-control/src/public_wire.rs:1 repeats the pattern; X3 may merge the family) | [packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib.rs:7-11] | actionable | lane/d2b-contracts-broker.md - -**`d2b-contracts-control`** - -- `RS-0330` | low | `d2b-contracts-control` | `StatusServicesOutputV3` and its `from_v2` conversion shim are exported but have zero callers in the workspace; the doc comment says "Used so callers... can be migrated incrementally" but no migration landed | fix: delete `StatusServicesOutputV3` and `from_v2` (or wire the intended caller) | [cli_output.rs:241, cli_output.rs:276] | actionable | lane/d2b-contracts-control.md -- `RS-0331` | low | `d2b-contracts-control` | `pub use d2b_contracts::audio::LevelPercent;` in cli_output.rs re-exports a type neither this module nor any external caller uses (public_wire.rs imports LevelPercent from d2b_contracts directly) | fix: delete the re-export | [cli_output.rs:6] | actionable | lane/d2b-contracts-control.md -- `RS-0332` | low | `d2b-contracts-control` | `AuditEntry` (public_wire.rs:2677) is exported but referenced by no wire type in the crate - `AuditResponse` uses `AuditExportEntry` from d2b_contracts - and survives only as a historical schema artifact | fix: remove the struct after confirming docs/reference/schemas/v1/wire-protocol.json:127 no longer needs the definition | [public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127] | needs-contract | lane/d2b-contracts-control.md -- `RS-0333` | low | `d2b-contracts-control` | `HelperSnapshot::validate` and `HelperLaunchRequest::validate_bounds` are `pub` but every caller is an in-crate `Deserialize` impl; external consumers call `validate_unsafe_local_resource_identity` directly instead | fix: make both methods private (or `pub(crate)`) | [unsafe_local_wire.rs:105, unsafe_local_wire.rs:171] | actionable | lane/d2b-contracts-control.md - -**`d2b-contracts-provider`** - -- `RS-0334` | low | `d2b-contracts-provider` | `SchemaVersion` in d2b-contracts-resource exposes no `major()`/`minor()` accessors, so `CompatibilityRange::admits_state` re-parses the canonical string in `schema_version_parts` with three `expect`s and an allocation per call | fix: add `pub const fn major(self) -> u32` and `minor(self) -> u32` to `SchemaVersion` (non-breaking) and delete `schema_version_parts` | [packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/src/v3/resource_schema.rs:592] | actionable | lane/d2b-contracts-provider-p1.md - -**`d2b-contracts-resource`** - -- `RS-0335` | low | `d2b-contracts-resource` | six `pub type` aliases are exported with zero consumers anywhere: `AttachmentSpec` (network.rs:956), `AuthorityDescriptor` (device.rs:129), `OpaqueAuthorityKey` (device.rs:151), `DeviceStatus` (device.rs:760), `DeviceRbacVerb` (device.rs:918), `DeviceTelemetryLabels` (device.rs:1119) | fix: delete the unused aliases (or make them `pub(crate)` if a provider adapter is planned) | [packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src/v3/device.rs:129, packages/d2b-contracts-resource/src/v3/device.rs:151, packages/d2b-contracts-resource/src/v3/device.rs:760] | actionable | lane/d2b-contracts-resource-p1.md -- `RS-0336` | low | `d2b-contracts-resource` | the exported type alias `ValidatedSessionPurpose` has zero callers anywhere in the workspace | fix: delete the alias (identity.rs:270) or document the intended consumer before it accrues surface | [packages/d2b-contracts-resource/src/v3/identity.rs:269-270] | actionable | lane/d2b-contracts-resource-p2.md - -**`d2b-contracts-zone-session`** - -- `RS-0337` | low | `d2b-contracts-zone-session` | four documented "compatibility" aliases give one type a second public path with zero in-repo callers: `ResourceExportError`, `Fairness`, `ResourceImportError`, `ZoneLinkStatus` | fix: delete the aliases (and the "Compatibility alias" doc lines); any future caller names the canonical type | [src/v3/resource_export.rs:97, src/v3/resource_export.rs:156, src/v3/resource_import.rs:86, src/v3/zone_link.rs:444] | actionable | lane/d2b-contracts-zone-session-p1.md -- `RS-0338` | low | `d2b-contracts-zone-session` | EmergencyPolicySpec::default_values is a pub method with zero callers outside its own Default impl | fix: delete it and let Default::default() be the single entry (or make it private) | [emergency_policy.rs:142, emergency_policy.rs:170] | actionable | lane/d2b-contracts-zone-session-p2.md -- `RS-0339` | low | `d2b-contracts-zone-session` | ZoneSpec::validate always returns Ok and has no callers, a dead always-succeeding validation on the exported surface | fix: remove the method (ZoneSpec is the empty spec; its Deserialize gate already enforces the only invariant) | [zone.rs:74] | actionable | lane/d2b-contracts-zone-session-p2.md - -**`d2b-core`** - -- `RS-0348` | medium | `d2b-core` | six one-line compat shim modules (`error`, `contract_id`, `configured_argv`, `privileges_w3`, `workload_identity`, `unsafe_local_workloads`) re-export d2b_contracts items, making every re-exported item public at two paths (`d2b_contracts::error::Error` and `d2b_core::error::Error`); this is the recorded A4 not-applied row | fix: delete the six shim modules and re-point the ~25 import sites at `d2b_contracts::*` (and `d2b_contracts_resource::v3::ZoneResourceIdentity`); the `UnsafeLocalWorkloadIdentity` alias has zero consumers and goes with its module; the xtask gen-error-codes generator and docs/reference/error-codes.md anchors that read `d2b_core::error` must switch to `d2b_contracts::error` | [packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-core/src/configured_argv.rs:1, packages/d2b-core/src/privileges_w3.rs:1] | actionable | lane/d2b-core-p2.md -- `RS-0345` | medium | `d2b-core` | nine exported resolved-intent types have zero consumers anywhere in the workspace: ResolvedInstallerIntent, ResolvedMigrateIntent, ResolvedActivationIntent, ResolvedGcIntent, ResolvedKeysRotateIntent, ResolvedHostKeyTrustIntent, ResolvedRotateKnownHostIntent, ResolvedLegacySwtpmIntent, InstallerArtifact | fix: delete them, or wire them to the broker dispatch arms the module doc says are still `Unimplemented`; if kept for planned arms, mark them `#[doc(hidden)]` or gate them behind a feature | [packages/d2b-core/src/bundle_resolver.rs:620, packages/d2b-core/src/bundle_resolver.rs:641, packages/d2b-core/src/bundle_resolver.rs:656, packages/d2b-core/src/bundle_resolver.rs:698] | actionable | lane/d2b-core-p1.md -- `RS-0349` | medium | `d2b-core` | `pub mod static_invariants` exports four security validators (world-readable-leak, path-bearing-key, broad-caps, writable-paths) with zero callers in the tree, and the bash gates the module doc says it replaced are gone, so the invariants are enforced nowhere; the module doc's claim that the original positive/negative cases were "preserved as unit tests" is false | fix: wire the validators into the contract-test lane (e.g. the d2b-contract-tests static-invariants structure ADR-046-zone-control cites) or the broker's manifest load path, or delete the module with its stale claim | [packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:158, packages/d2b-core/src/static_invariants.rs:189, packages/d2b-core/src/static_invariants.rs:216] | actionable | lane/d2b-core-p2.md merged: d2b-core-p2#12 -- `RS-0346` | medium | `d2b-core` | `BundleResolver` exposes seven `pub` fields (bundle, host, processes, storage, site, realm_workloads_launcher_v2, manifest) on the security-boundary type whose tables are derived from verified artifacts; the broker mutates `resolver.storage` directly, so the trusted model is writable by any consumer and derived state can drift from it | fix: make the fields private, add read accessors (`host()`, `manifest()`, `processes()`, `bundle()`, ...) and a single `set_storage(StorageJson)` setter, then migrate the ~30 read sites in d2bd, d2bd-runtime, and d2b-broker | [packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109, packages/d2b-core/src/bundle_resolver.rs:110, packages/d2b-broker/src/ops/storage_contract.rs:589] | actionable | lane/d2b-core-p1.md -- `RS-0350` | low | `d2b-core` | `PrivilegesJson::w1` is a pub constructor with zero production callers and an opaque name ("w1") unexplained by its doc comment | fix: rename to a descriptive constructor such as `from_const_rows()` or gate it behind cfg(test) | [packages/d2b-core/src/privileges.rs:741] | actionable | lane/d2b-core-p2.md -- `RS-0347` | low | `d2b-core` | three `pub` methods have no out-of-crate callers and are only used inside this module and its tests: resolve_vm_start_intent, find_process_node, find_if_name_mapping_for_vm | fix: narrow to `pub(crate)` | [packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:2417, packages/d2b-core/src/bundle_resolver.rs:2506] | actionable | lane/d2b-core-p1.md merged: d2b-core-p1#16 - -**`d2b-core-controller`** - -- `RS-0340` | medium | `d2b-core-controller` | `observed_child_from_resource` (binding_children.rs:173) is a pub fn re-exported at lib.rs:35 with zero callers anywhere in the repo; the observed-child adapter is dead public surface | fix: delete the fn and its lib.rs re-export arm, or wire it into the owner_reconcile relist path if the digest-from-stored-body adapter is still intended | [packages/d2b-core-controller/src/binding_children.rs:173, packages/d2b-core-controller/src/lib.rs:35] | actionable | lane/d2b-core-controller-p1.md merged: d2b-core-controller-p1#4 -- `RS-0341` | medium | `d2b-core-controller` | eight pub methods on ControllerAssignmentRegistry/ResourceClientLease have zero callers: reserve_epoch_after, rebind_revision, record_child, remove_child, child_uids, validate_writer, observation_is_stale, target_for; because record_child is never called the children set is always empty, so release()'s ChildrenRemain fence, ChildLimit, and MAX_ASSIGNED_CHILDREN are unreachable | fix: delete the eight methods and, if the child index stays in owner_reconcile's OwnerIndex (which already tracks children), the `children` field and MAX_ASSIGNED_CHILDREN const | [packages/d2b-core-controller/src/controller_assignment.rs:2707, packages/d2b-core-controller/src/controller_assignment.rs:2866, packages/d2b-core-controller/src/controller_assignment.rs:2943, packages/d2b-core-controller/src/controller_assignment.rs:2957] | actionable | lane/d2b-core-controller-p1.md merged: d2b-core-controller-p1#6 -- `RS-0342` | medium | `d2b-core-controller` | ten pub ZoneCoordinator methods have zero callers: begin_usbip_reconcile, finish_usbip_reconcile, set_force_shutdown_generation, clear_force_shutdown_generation, stage_configuration, commit_configuration, abort_configuration, commit_configuration_ordinal, abort_configuration_ordinal, zone_count; the daemon uses only the ordinal staging half (d2bd/src/composition.rs:20248), the generation-based family is unwired, and stage_configuration silently overwrites a pending generation where stage_configuration_ordinal rejects a conflict | fix: delete the ten methods and the generation-based staging fields, or wire the usbip reconcile lease into the daemon reconcile flow | [packages/d2b-core-controller/src/coordinator.rs:252, packages/d2b-core-controller/src/coordinator.rs:262, packages/d2b-core-controller/src/coordinator.rs:292, packages/d2b-core-controller/src/coordinator.rs:317] | actionable | lane/d2b-core-controller-p1.md -- `RS-0343` | medium | `d2b-core-controller` | the parallel external physical-NIC machinery (TrustedExternalNicInventory, ExternalNicClaimRequest, ExternalNicLease, ExternalNicEffectGate, ExternalNicAdoption, ExternalNicCloseOutcome, ExternalNicReservation, the external_nics half of the index, and the EXTERNAL_PHYSICAL_NIC_* constants) has zero production callers; the prior audit row C2 names exactly this surface and is recorded not-applied with the site still matching | fix: delete the controller-side NIC request/lease/reservation/inventory types and the external_nics index half with their tests, keeping ExternalNicRecoveryInventory (consumed by d2bd-runtime's provenance fence) and the wire types in d2b-contracts-resource (consumed by d2bd and d2b-provider-network-local); cite record row C2 at docs/explanation/over-engineering-audit-record.md:473 | [authority.rs:80-128, authority.rs:167-211, authority.rs:258-335, authority.rs:1732] | actionable | lane/d2b-core-controller-p2.md merged: d2b-core-controller-p2#10 -- `RS-0344` | low | `d2b-core-controller` | public accessor aliases multiply paths to one item: OwnerReconcilePlan::create_order/batch, OwnerChildBatch::resource_refs, OwnerChildIdentity::resource_ref, TeardownPlan::order/refs/resources all duplicate a canonical accessor with zero external callers | fix: delete the zero-caller aliases and keep the canonical names (creation_order, deletion_order, create_batch, refs, target, order), retaining teardown_order which has live consumers | [owner_reconcile.rs:579, owner_reconcile.rs:600, owner_reconcile.rs:697, owner_reconcile.rs:754] | actionable | lane/d2b-core-controller-p2.md - -**`d2b-host`** - -- `RS-0351` | low | `d2b-host` | `HostPrepStepId(pub String)` exposes the inner `String` on a `#[serde(transparent)]` newtype whose only constructor `new` is private, so literal construction is the only external path and the `{vm}:{kind}` id convention stays unenforced | fix: make the field private (serde transparent round-trips unchanged; `as_str()` already exists) and add a public constructor if integrators need one | [packages/d2b-host/src/host_prep_dag.rs:85] | actionable | lane/d2b-host.md - -**`d2b-process-conformance`** - -- `RS-0355` | low | `d2b-process-conformance` | `terminal::ExitClass` is re-exported under two names and the `BrokerExitClass` alias has zero consumers anywhere in the repo (the only hit is the re-export itself), while `ProcessExitClass` is the name the one real consumer (systemd lifecycle) imports | fix: drop the `ExitClass as BrokerExitClass` arm from lib.rs:54, keep `ExitClass as ProcessExitClass` | [packages/d2b-process-conformance/src/lib.rs:52, packages/d2b-process-conformance/src/lib.rs:54] | actionable | lane/d2b-process-conformance.md -- `RS-0356` | low | `d2b-process-conformance` | `process_provider.rs` re-exports the same root surface under a second public path (`d2b_process_conformance::process_provider::*`) and no caller uses that path (its own doc calls it a "destination-compatible boundary" for a split that is already settled) | fix: delete the module and its lib.rs:36 declaration; every item stays reachable at the root path | [packages/d2b-process-conformance/src/process_provider.rs:6, packages/d2b-process-conformance/src/lib.rs:36] | actionable | lane/d2b-process-conformance.md -- `RS-0357` | low | `d2b-process-conformance` | `pub mod testing` ships the mock `ScriptedEffectPort`, `PortCall`, `block_on` poller, and `TicketBuilder` fixtures unconditionally in the production library surface, while the house pattern (api card false-positive note) is a feature-gated `test-support` export; every in-tree consumer is a test target (provider crates' integration tests, d2bd `#[cfg(test)]`, provider-supervisor tests) | fix: gate `testing` behind a `test-support` feature (`#[cfg(feature = "test-support")] pub mod testing;`) and have consumer test targets enable it via dev-dependencies; `suite` stays ungated (it is the crate's product) | [packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testing.rs:60] | actionable | lane/d2b-process-conformance.md -- `RS-0358` | low | `d2b-process-conformance` | `CompiledSandbox::requires_cgroup_kill()` is public API whose field is set unconditionally to `true` at the only constructor, and no in-tree caller reads it (census inside the crate only); the accessor promises sandbox-dependent variation the compiler can never produce | fix: either thread a real `StopProof`/cgroup decision through `compile()` and its callers, or delete the field and the accessor along with the suite's unused surface | [packages/d2b-process-conformance/src/sandbox.rs:18, packages/d2b-process-conformance/src/sandbox.rs:61, packages/d2b-process-conformance/src/sandbox.rs:98] | actionable | lane/d2b-process-conformance.md - -**`d2b-provider-activation-nixos`** - -- `RS-0359` | low | `d2b-provider-activation-nixos` | `ActivationDriver` is re-exported at lib.rs:38 but no external consumer names it: the factory returns `Box` (driver.rs:410), so the concrete type never escapes the crate | fix: make `ActivationDriver` `pub(crate)` and drop it from the lib.rs re-export arm | [packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation-nixos/src/lib.rs:38] | actionable | lane/d2b-provider-activation-nixos.md -- `RS-0360` | low | `d2b-provider-activation-nixos` | `ACTIVATION_RUNNER_RESOURCE_TYPE` (controller.rs:14) is `pub` inside the exported `controller` module but used only at controller.rs:296 in the same module, so it is reachable as `d2b_provider_activation_nixos::controller::ACTIVATION_RUNNER_RESOURCE_TYPE` with no consumer | fix: make the const private (or `pub(crate)`) | [packages/d2b-provider-activation-nixos/src/controller.rs:14, packages/d2b-provider-activation-nixos/src/controller.rs:296] | actionable | lane/d2b-provider-activation-nixos.md - -**`d2b-provider-audio-pipewire`** - -- `RS-0361` | low | `d2b-provider-audio-pipewire` | `SpeakerMixer::set_grant(lease, on: bool)` takes a boolean command and returns a bool whose meaning flips with the argument (true: was-empty, false: was-last), and the only caller ignores the revoke return (it calls `is_last_grant` first) | fix: split into `grant(lease) -> Result` (was-empty) and `revoke(lease) -> Result` (was-last), or return a named enum, so the return contract stops being argument-dependent | [src/authority.rs:157-171, src/controller.rs:395-403] | actionable | lane/d2b-provider-audio-pipewire.md merged: d2b-provider-audio-pipewire#9 -- `RS-0362` | low | `d2b-provider-audio-pipewire` | `register_service` is exported from lib.rs but has zero callers anywhere (the daemon's audio paths and the wayland-policy audio_registry validate specs directly), leaving a dead registration gate on the surface | fix: consume `register_service` in the daemon's audio Service registration path or drop the export (crate is 0.0.0-bootstrap, no semver gate) | [src/controller.rs:746-748, src/lib.rs:32] | actionable | lane/d2b-provider-audio-pipewire.md -- `RS-0363` | low | `d2b-provider-audio-pipewire` | `AudioLastSetApplied::OfflineOnly` is named as if it meant "applied offline only" while its doc says "No setting was applied in the current reconcile"; the variant is rendered to a wire-visible status string "OfflineOnly" by the wayland-policy projection and pinned in daemon tests | fix: rename the variant (e.g. `NotApplied`) and update the projection string and pinned expectations together | [src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-122, packages/d2bd/src/resource_plane_v3.rs:4626] | needs-contract | lane/d2b-provider-audio-pipewire.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0364` | low | `d2b-provider-clipboard-wayland` | ClipboardConfig exposes host_entry_ttl_secs (field, Default value, and pub accessor) plus a pub policy() accessor with zero consumers anywhere in the repo; the history only ever reads guest_entry_ttl_secs, so the host TTL is dead public surface | fix: remove host_entry_ttl_secs and policy(), or wire host_entry_ttl_secs into ClipboardHistory retention for host-owned entries | [packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1289, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1297, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1313-1316, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1338-1340] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-config-nixos`** - -- `RS-0365` | low | `d2b-provider-config-nixos` | `decode_document` (service.rs:296-298) is a public one-line forwarder duplicating the already-public `ConfigSyncResponse::document()`, giving two API paths for one operation | fix: drop the export and call `.document()` at the one live caller (d2bd/src/composition.rs:11585), or privatize `document()` and keep the named helper | [packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-nixos/src/lib.rs:22] | actionable | lane/d2b-provider-config-nixos.md - -**`d2b-provider-credential-entra`** - -- `RS-0366` | medium | `d2b-provider-credential-entra` | `pub fn controller_binary_entrypoint()` is an exact duplicate of `run_from_fd10()` with zero callers anywhere in the workspace; the sibling credential crate deleted its twin as production-dead | fix: delete controller_binary_entrypoint (lib.rs:102-105) and its doc comment, keeping `run_from_fd10` as the single entrypoint | [packages/d2b-provider-credential-entra/src/lib.rs:102, packages/d2b-provider-credential-entra/src/lib.rs:103] | actionable | lane/d2b-provider-credential-entra.md -- `RS-0367` | low | `d2b-provider-credential-entra` | `EntraCredentialOwner` enum and the `owner()` accessor have no caller inside or outside the crate | fix: delete the enum (lib.rs:445-449) and `owner()` (lib.rs:939-942), or wire them into the toolkit's dispatch/controller surface if the ownership policy is meant to be observable | [packages/d2b-provider-credential-entra/src/lib.rs:446, packages/d2b-provider-credential-entra/src/lib.rs:940] | actionable | lane/d2b-provider-credential-entra.md - -**`d2b-provider-credential-managed-identity`** - -- `RS-0368` | low | `d2b-provider-credential-managed-identity` | `ManagedIdentityPlacement::in_zone` is an exact duplicate constructor of `new` with zero callers anywhere in the repo, doubling the public construction path | fix: delete `in_zone` (and its docs at lib.rs:611-618); `new` already validates and names the behavior | [lib.rs:612-618] | actionable | lane/d2b-provider-credential-managed-identity.md - -**`d2b-provider-device`** - -- `RS-0369` | medium | `d2b-provider-device` | `DeviceResourceState` exposes raw `Arc>>` and `Arc>>` as pub fields, leaking wrapper types and the `parking_lot` dependency into the crate's public API (parking_lot is banned outright by (d) 2 outside the R4 worker boundary; this site is comment-justified only, driver.rs:137-138, matching the GPU crate's cache at d2b-provider-device-gpu/src/effects_service.rs:79) | fix: make the three caches private and expose narrow typed accessor methods on `DeviceResourceState` (or an effects-owned registry handle), keeping the GPU authority-lease construction contract behind the crate, and migrate the nine daemon read sites | [packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effects.rs:1584, packages/d2bd/src/shared_provider_effects.rs:2092, packages/d2bd/src/shared_provider_effects.rs:2122] | actionable | lane/tail-2.md - -**`d2b-provider-device-gpu`** - -- `RS-0370` | low | `d2b-provider-device-gpu` | `pub mod gpu_argv`/`pub mod video_argv` expose a second public path for items already re-exported at the root, and the module paths have zero workspace callers | fix: make both modules private (`mod gpu_argv`/`mod video_argv`), keeping the lib.rs re-export arms so each item stays reachable by one path (the house single-surface pattern) | [packages/d2b-provider-device-gpu/src/lib.rs:12, packages/d2b-provider-device-gpu/src/lib.rs:15] | actionable | lane/d2b-provider-device-gpu.md -- `RS-0371` | low | `d2b-provider-device-gpu` | public `DeclaredWorkerGpuPortArgs` tunnels dependency types in pub fields (`Arc`, `Arc>>` over parking_lot, `tokio::runtime::Handle`, `&dyn SharedProviderChildSurface`) | fix: hide the field types behind crate-private accessors or accept a single crate-owned sidecar struct; publish=false so the semver cost is nil, but the surface leaks three dependency crates | [packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-device-gpu/src/effects_service.rs:467, packages/d2b-provider-device-gpu/src/effects_service.rs:469] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-device-security-key`** - -- `RS-0372` | low | `d2b-provider-device-security-key` | `pub mod relay` and `pub mod relay_service` (lib.rs:16-17) expose a second path for every root-re-exported item, while `facets`/`effects_service`/`test_support` module paths are the ones the daemon actually consumes | fix: make `relay` and `relay_service` private modules, keep the lib.rs `pub use` arms as the single surface (house pattern) | [packages/d2b-provider-device-security-key/src/lib.rs:16-17, packages/d2b-provider-device-security-key/src/lib.rs:45-55] | actionable | lane/d2b-provider-device-security-key.md - -**`d2b-provider-device-tpm`** - -- `RS-0373` | medium | `d2b-provider-device-tpm` | the state.rs token module (StateDirectoryToken, TamperMarkerToken, StateOwnerToken, StateDirIntent, state.rs:6-107, re-exported lib.rs:36-38) has zero consumers repo-wide at HEAD, so the refusal ledger's stated reason for keeping it ("the daemon references them", over-engineering-audit-record.md:386, rows 71/72) is no longer evidenced - the daemon-side uses were deleted by the same applied finding | fix: delete state.rs and its re-export, or wire the daemon side that the record claims exists | [state.rs:6, state.rs:29, state.rs:51, state.rs:73] | actionable | lane/d2b-provider-device-tpm.md -- `RS-0374` | low | `d2b-provider-device-tpm` | the exported inspect-tpm effects service is unwired: TPM_EFFECTS_SERVICE (effects_service.rs:53), TpmEffectsService, and TpmEffectsServiceFactory (effects_service.rs:103-116, whose facets field carries #[allow(dead_code)] for an R5 respawn path "not wired yet") are never registered, while d2bd registers every sibling provider's factory in shared_provider_effects.rs:3434-3493 without the TPM one | fix: register the factory there, or delete the service surface until the respawn path is wired | [effects_service.rs:53, effects_service.rs:103, effects_service.rs:114] | actionable | lane/d2b-provider-device-tpm.md -- `RS-0375` | low | `d2b-provider-device-tpm` | LiveTpmResourceEffectPort is pub (effects_service.rs:341) but is only constructed and consumed inside effects_service.rs (into_port at effects_service.rs:697), never appearing in a public signature or external caller | fix: make it pub(crate) | [effects_service.rs:341] | actionable | lane/d2b-provider-device-tpm.md -- `RS-0376` | low | `d2b-provider-device-tpm` | LegacyMigrationOutcome (migration.rs:5, re-exported lib.rs:24) has zero callers repo-wide: the "closed outcome of the broker-owned one-time legacy state adoption" is consumed by no broker or daemon code at HEAD | fix: delete the enum and its re-export, or wire the broker consumer it documents | [migration.rs:5, lib.rs:24] | actionable | lane/d2b-provider-device-tpm.md - -**`d2b-provider-device-usbip`** - -- `RS-0377` | medium | `d2b-provider-device-usbip` | `pub mod state_machine` (lib.rs:24) plus the root `pub use state_machine::{...}` (lib.rs:61-65) exposes every state-machine item at two public paths, and no external caller uses the module path | fix: make the module private (`mod state_machine`) since lib.rs already re-exports its whole surface | [lib.rs:24, lib.rs:61-65] | actionable | lane/d2b-provider-device-usbip.md -- `RS-0378` | medium | `d2b-provider-device-usbip` | `new_authority_ledger` returns `Arc>`, leaking the concrete lock type into the public signature and making any lock change a breaking change for the caller | fix: introduce an opaque `AuthorityLedgerHandle` newtype wrapping the `Arc>` (or a `pub type` alias) so the handle is the API | [broker.rs:131-133] | actionable | lane/d2b-provider-device-usbip.md - -**`d2b-provider-display-wayland`** - -- `RS-0381` | medium | `d2b-provider-display-wayland` | `PrincipalReleaseReceipt` (controller.rs:702, re-exported at lib.rs:20) is unconstructible: private `session_key` field and no constructor, so `DisplayController::release_session_principal` (controller.rs:1379) can never be called by the daemon; the principal-release path is dead exported surface | fix: add a constructor and wire the daemon cleanup path to call release_session_principal, or make both pub(crate) until the path is wired | [src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20] | actionable | lane/d2b-provider-display-wayland-p2.md merged: d2b-provider-display-wayland-p2#12 -- `RS-0379` | medium | `d2b-provider-display-wayland` | `#[allow(missing_docs)] pub mod wayland_proxy` (lib.rs:14) exposes the whole 9,342-line proxy implementation as public library surface whose only consumer is the crate's own binary target, which cannot reach crate-private items | fix: move the module into the binary target (declare `#[path = "../wayland_proxy/mod.rs"] mod wayland_proxy;` in src/bin/d2b-wayland-proxy.rs and rewrite the `crate::wayland_proxy::` paths to `wayland_proxy::`), keeping the lib surface to the re-exported controller/policy/process/runtime/spec items | [packages/d2b-provider-display-wayland/src/lib.rs:14] | actionable | lane/d2b-provider-display-wayland-p1.md merged: d2b-provider-display-wayland-p1#10 -- `RS-0382` | low | `d2b-provider-display-wayland` | `WaylandPolicySnapshot::from_authenticated_session` (controller.rs:580) has no callers anywhere; the daemon resolves snapshots via `from_authenticated_route` | fix: delete the wrapper or mark it deliberate with a comment naming the route-based entry as canonical | [src/controller.rs:580] | actionable | lane/d2b-provider-display-wayland-p2.md -- `RS-0380` | low | `d2b-provider-display-wayland` | `pub use policy::{FilterPolicy, GlobalAction, PolicyInput, PolicyWarning};` in wayland_proxy/mod.rs re-exports four items at a second path with zero consumers; the bin imports them via `wayland_proxy::policy::...` | fix: delete the re-export line so each item has one path | [packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12] | actionable | lane/d2b-provider-display-wayland-p1.md - -**`d2b-provider-guest-azure-container-apps`** - -- `RS-0383` | low | `d2b-provider-guest-azure-container-apps` | lib.rs re-exports the whole effects module via `pub use effects::*;` (so every future pub item in effects silently becomes public API) and effects.rs re-exports four dependency types (`CredentialLeaseHandle`, `OpaqueAzureRef`, `ResourceRef`, `ResourceUid`) with zero consumers through this crate's path | fix: replace the glob with named arms listing the intended effect surface and drop the uncalled dependency-type re-exports | [src/lib.rs:14, src/effects.rs:8-9] | actionable | lane/d2b-provider-guest-azure-container-apps.md - -**`d2b-provider-guest-azure-virtual-machine`** - -- `RS-0384` | low | `d2b-provider-guest-azure-virtual-machine` | the mutable-update/adoption/enrollment surface has no in-tree production caller: `update()`/`AzureVmUpdate`, `adopt()`, `complete_enrollment`, `status()`/`AzureVmStatus`, `controller_execution_ref()` are exercised only by this crate's tests, while the framework adapter (d2b-provider-guest/src/effects_service.rs) drives only `reconcile` (1303-1308), `poll_operation`/`recovery_state` (1384-1396), `finalize` (1384-1396) and `finalizer_installed` (590) | fix: wire the update path in the framework adapter (it already implements the resize/attach/detach/tags effect methods at effects_service.rs:499-565) or trim the surface | [src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md -- `RS-0385` | low | `d2b-provider-guest-azure-virtual-machine` | `AzureVmController::new` takes `effect: Arc` (controller/mod.rs:211) and stores it, but the only call site constructs a fresh `Arc::new(FrameworkAzureEffect {...})` with no sharing (d2b-provider-guest/src/effects_service.rs:1186-1189) | fix: take `effect: E` by value and store it, removing `Arc` from the public signature | [src/controller/mod.rs:211, packages/d2b-provider-guest/src/effects_service.rs:1186] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md - -**`d2b-provider-guest-cloud-hypervisor`** - -- `RS-0386` | medium | `d2b-provider-guest-cloud-hypervisor` | `repair_children` takes `committed: &BTreeMap` whose only call site passes an always-empty map (`let committed = BTreeMap::new()` at controller.rs:2140), making the `committed.get(target)` branch at 2890 unreachable | fix: drop the parameter and the dead branch, delete the empty-map local | [controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0387` | medium | `d2b-provider-guest-cloud-hypervisor` | `CloudHypervisorResourceApi::assess_update` takes `children` that the production adapter discards (`let _ = children;` at controller.rs:1366, the request carries no children) while `reconcile` allocates a Vec just to drop it | fix: remove the `children` parameter from the trait method, the adapter override, and the call site (controller.rs:1907-1909) | [controller.rs:1361-1376, controller.rs:1907-1909] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0390` | medium | `d2b-provider-guest-cloud-hypervisor` | `GuestControlEndpoint` is declared byte-identically in this crate (guest_local.rs:49) and in d2b-resource-client (zone_client.rs:129), the not-applied ledger row C1 with no refusal reason | fix: keep one declaration (d2b-resource-client is the consumer-facing home; d2bd/src/composition.rs:10723 constructs it) and re-export from the other | [guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md merged: d2b-provider-guest-cloud-hypervisor#13 -- `RS-0388` | low | `d2b-provider-guest-cloud-hypervisor` | `ChildMutation::expected_uid()` (identity.rs:554) always returns `None` because the UID-free batch is structurally UID-free; the only consumers are tests asserting the None (bootstrap_graph.rs:340, tests/controller.rs:206, tests/guest_spec_validation_test.rs:181) | fix: delete the accessor and the assert-None assertions | [identity.rs:554-556, tests/controller.rs:206] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md -- `RS-0389` | low | `d2b-provider-guest-cloud-hypervisor` | `GuestUpgradePlan::preserve_state()` (shutdown.rs:576) returns a literal `true`; its only consumer is the tautological assertion in finding #5 | fix: delete the accessor together with the assertion | [shutdown.rs:576-578] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0391` | low | `d2b-provider-guest-qemu-media` | Test-support exports `ScriptedQmpTransport` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129(and `ProcessIdentity::for_test` (packages/d2b-provider-guest-qemu-media/src/adoption.rs:24(are unconditionally pub+re-exported with no consumer outside this crate's own tests (while the house convention for test-only items is `#[doc(hidden)]` (see `mark_ready_for_test` at packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:327-328( | fix: mark both `#[doc(hidden)]` (or gate behind a `test-support` feature | [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129, packages/d2b-provider-guest-qemu-media/src/lib.rs:32, packages/d2b-provider-guest-qemu-media/src/adoption.rs:24] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-host`** - -- `RS-0392` | low | `d2b-provider-host` | dead `pub` visibility on seven items in the private `mod driver` that are never re-exported: `HostDriver`, `HostDriverError`, `HostDriverStatus`, `HostDriverFactory`, `HostDriverEffects`, `host_spec_decoder`, `HOST_REOBSERVE` | fix: make them `pub(crate)` (the live surface is the lib.rs re-export set: host_descriptor, HOST_EFFECTS_SERVICE, HostEffectsServiceFactory, HostEffectFacets, MinijailPlatformGateSource, production_probe, the three probe constants, MinijailPlatformGate) | [packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111, packages/d2b-provider-host/src/driver.rs:147, packages/d2b-provider-host/src/driver.rs:174] | actionable | lane/d2b-provider-host.md merged: d2b-provider-host#6 - -**`d2b-provider-network-local`** - -- `RS-0393` | medium | `d2b-provider-network-local` | two pub route validators are exported with zero production callers (only crate-internal unit tests), and the wrapper carries a stale `#[allow(dead_code)]` on a pub item | fix: lower both to `pub(crate)` (unit tests still reach them)and remove the dead_code allow, or wire them into BrokerNetworkEffectPort::apply_routes/remove_routes which currently resolve intents without these checks | [src/routes.rs:244-279, src/routes.rs:264-265] | actionable | lane/d2b-provider-network-local.md merged: d2b-provider-network-local#8 - -**`d2b-provider-notification-desktop`** - -- `RS-0394` | medium | `d2b-provider-notification-desktop` | The non-effects controller surface has no production callers: `reconcile_authenticated_display` is uncalled at all, `reconcile_sources` and `drain_sources` serve only in-crate tests | fix: delete `reconcile_authenticated_display` or route its tests through the `_with_effects` twin; make `reconcile_sources`/`drain_sources` `pub(crate)` unless an external caller is planned | [packages/d2b-provider-notification-desktop/src/controller.rs:1019, packages/d2b-provider-notification-desktop/src/controller.rs:1329, packages/d2b-provider-notification-desktop/src/controller.rs:1411] | actionable | lane/d2b-provider-notification-desktop.md -- `RS-0395` | low | `d2b-provider-notification-desktop` | `#[allow(dead_code)]` sits on `from_route`, a function reachable from production via `from_authenticated_route` | fix: delete the stale allow | [packages/d2b-provider-notification-desktop/src/controller.rs:110, packages/d2b-provider-notification-desktop/src/controller.rs:159-160] | actionable | lane/d2b-provider-notification-desktop.md -- `RS-0396` | low | `d2b-provider-notification-desktop` | `stream_admission.rs` is a private three-line re-export shim: `lib.rs` could re-export admission items directly | fix: delete `stream_admission.rs` and change `lib.rs:59` to `pub use admission::{AdmissionError, AdmissionPurpose, SessionEvidence, TransportClass};` | [packages/d2b-provider-notification-desktop/src/stream_admission.rs:1-3, packages/d2b-provider-notification-desktop/src/lib.rs:29, packages/d2b-provider-notification-desktop/src/lib.rs:59] | actionable | lane/d2b-provider-notification-desktop.md - -**`d2b-provider-process-systemd`** - -- `RS-0397` | low | `d2b-provider-process-systemd` | `SystemdProviderConfig`, `RestartPolicy`, `SystemdConfigError`, and `EphemeralProcessController` are each reachable at two paths: `pub mod lifecycle` (src/lib.rs:28) plus the root re-export `pub use lifecycle::{...}` (src/lib.rs:33), violating the one-path-per-item surface rule | fix: make `lifecycle` private (`mod lifecycle;`) and keep the root re-export as the single surface; no external caller imports through the module path (tests use the crate root) | [packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd/src/lib.rs:33] | actionable | lane/d2b-provider-process-systemd.md -- `RS-0398` | low | `d2b-provider-process-systemd` | `SystemdProviderConfig::no_persistent_unit()` is an always-true method with no production caller; the invariant it states already lives in the README security posture and the dossier | fix: delete the method and its test assertion (tests/lifecycle.rs:12), or replace it with a documented `const` if the surface is contract | [packages/d2b-provider-process-systemd/src/lifecycle.rs:55, packages/d2b-provider-process-systemd/tests/lifecycle.rs:12] | actionable | lane/d2b-provider-process-systemd.md -- `RS-0399` | low | `d2b-provider-process-systemd` | the controller/provider/lifecycle/drain/launch/sandbox/audit/metrics/error modules have zero production consumers: the daemon composes only `effects_service` + `operations` (the U15 forward seam), so the declared controller surface is unwired in the tree | fix: none until daemon composition lands; record the drift | [packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd/README.md:28] | policy-confirmed | lane/d2b-provider-process-systemd.md - -**`d2b-provider-provider`** - -- `RS-0400` | low | `d2b-provider-provider` | `ProviderDriverFactory::new()` and its `Default` impl are zero-caller public surface (the doc names "unit fixtures", but the crate's own tests construct via `with_effects`) | fix: delete `new()` and `impl Default` (driver.rs:213-232), or drop them to `pub(crate)` if a fixture wants them | [src/driver.rs:215, src/driver.rs:229] | actionable | lane/d2b-provider-provider.md -- `RS-0401` | low | `d2b-provider-provider` | `ProviderHandler::plan_external` (and the `ProviderError`/`ProviderChildAction`/`Disable`/`Delete` planning surface it serves) is exported through `pub mod providers` with zero production callers | fix: reduce to `pub(crate)` or delete `plan_external` (providers.rs:121-171) and the `ProviderIntent::Disable`/`Delete` arms of `plan_observed` if the external-provider path is not coming back; keep the surface the driver consumes (`plan_observed` Enable/Update, `plan_system_core`, `provider_observation`, `fixed_system_core_handlers_ready`) | [src/providers.rs:121, src/lib.rs:19] | actionable | lane/d2b-provider-provider.md merged: d2b-provider-provider#6 - -**`d2b-provider-quota`** - -- `RS-0402` | low | `d2b-provider-quota` | the `test-support` feature is declared empty and gates nothing: the `quota` module is unconditionally `pub`, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza (or gate the test-consumed exports behind it, matching the house pattern of feature-gated test-support) | [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21] | actionable | lane/tail-3.md - -**`d2b-provider-resource-export`** - -- `RS-0403` | low | `d2b-provider-resource-export` | the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_export_descriptor` unconditionally, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza | [packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export/src/lib.rs:18] | actionable | lane/tail-3.md - -**`d2b-provider-resource-import`** - -- `RS-0404` | low | `d2b-provider-resource-import` | the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_import_descriptor` unconditionally, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza | [packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import/src/lib.rs:18] | actionable | lane/tail-3.md - -**`d2b-provider-role`** - -- `RS-0405` | low | `d2b-provider-role` | the `test-support` feature is declared empty and gates nothing: `rbac` is unconditionally `pub`, and no manifest enables the feature | fix: delete the `[features] test-support = []` stanza | [packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16] | actionable | lane/tail-3.md - -**`d2b-provider-seccomp-profile`** - -- `RS-0406` | low | `d2b-provider-seccomp-profile` | every `seccomp_profile` item is reachable at two paths: `pub mod seccomp_profile` (lib.rs:19) plus the glob `pub use seccomp_profile::*` (lib.rs:22), and d2bd imports via both paths | fix: make the module private (`mod seccomp_profile;`) and replace the glob with the house-style explicit re-export list (as shell-pool/shell-session/telemetry-binding lib.rs do), then update the two d2bd imports at foundation_seed.rs:25 and :1091 to the crate-root paths | [packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile/src/lib.rs:22, packages/d2bd/src/foundation_seed.rs:25, packages/d2bd/src/foundation_seed.rs:1091] | actionable | lane/tail-4.md - -**`d2b-provider-supervisor`** - -- `RS-0407` | medium | `d2b-provider-supervisor` | `BrokerProcessBackend::set_launched_observer` takes `Arc` in a public signature although single ownership suffices: the one caller (d2bd/src/process_provider_runtime.rs:913) hands over a fresh `Arc::new)...)` and retains nothing, so the Arc is a forced refcount, not shared ownership | fix: take `Box` or `impl LaunchedObserver + Send + Sync + 'static`, drop the Arc at the call site | [packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2bd/src/process_provider_runtime.rs:913] | actionable | lane/d2b-provider-supervisor.md -- `RS-0408` | medium | `d2b-provider-supervisor` | `LaunchedObserver::launched` takes five positional parameters (vm, role, pid, start_time_ticks, pidfd) and `BrokerProcessBackend::launched_runner_snapshot` returns `Option<(String, String, i32, u64, OwnedFd)>`, a 5-tuple whose shape is pinned by the upstream `ProcessEffectBackend` trait (which carries its own `#[allow(clippy::type_complexity)]`) | fix: introduce a `LaunchedSnapshot` struct (or a small `LaunchedProcessRef`) and change `launched_runner_snapshot`'s default + the observer method to carry it, updating the implementor in d2bd | [packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/src/broker.rs:1524-1546, packages/d2b-provider-process/src/backend.rs:315-319] | actionable | lane/d2b-provider-supervisor.md - -**`d2b-provider-system-core`** - -- `RS-0409` | medium | `d2b-provider-system-core` | `pub mod testing` (lib.rs:41) ships the hand-rolled `block_on` driver, `ScriptedDiscoveryPort`, and fixture set unconditionally in the library surface although only this crate's own `tests/` consumes them | fix: gate behind a `test-support = []` feature (house pattern: d2b-provider-host/Cargo.toml:28, d2b-provider-user/Cargo.toml:30) with `#[cfg(feature = "test-support")]` and `required-features` on the three [[test]] targets | [src/lib.rs:41, src/testing.rs:23] | actionable | lane/d2b-provider-system-core.md -- `RS-0413` | medium | `d2b-provider-system-core` | `HostReconciler::reject_operator_status_fields` (host.rs:389), documented as the enforcement half of the ADR-046 no-suppression obligation ("both are met here", host.rs:13), has zero callers outside this crate's tests - the "operators can neither suppress nor override" posture rule is test-only today | fix: wire the check into the daemon's status admission path (d2b-resource-api `update_status`, service.rs:735, or the daemon's Host status publication) or document the structural exclusion | [src/host.rs:389, src/host.rs:13] | needs-contract | lane/d2b-provider-system-core.md -- `RS-0410` | low | `d2b-provider-system-core` | `pub mod ownership` (lib.rs:40) makes `OWNED_RESOURCE_TYPES`/`DISOWNED_RESOURCE_TYPES` reachable at two paths (module plus root re-export), the refused two-path shape; its fns `owns`/`require_owned`/`require_resource_type` have no external callers | fix: `mod ownership;` private, keep the root re-export (lib.rs:49) | [src/lib.rs:40, src/ownership.rs:42] | actionable | lane/d2b-provider-system-core.md -- `RS-0411` | low | `d2b-provider-system-core` | `HostReconciler::reconcile_observed` (host.rs:419) and `HostProbeSnapshot` (host.rs:134, root re-export lib.rs:46) are pub with zero external callers; the doc frames reconcile_observed as a conformance/fault-injection seam no consumer uses yet | fix: `pub(crate)` both until a consumer exists, or keep as the documented seam | [src/host.rs:419, src/host.rs:134] | actionable | lane/d2b-provider-system-core.md -- `RS-0412` | low | `d2b-provider-system-core` | `PROVIDER_UID` (lib.rs:70) is a zero-caller pub const whose doc says "the bus keeps its own copy"; d2b-bus consumes the generated `BOOTSTRAP_PROVIDER_UID` (d2b-contracts-zone-session/src/generated/service_provider_catalog.rs:15) with the identical value | fix: have d2b-bus import `d2b_provider_system_core::PROVIDER_UID` (or land the daemon re-home the doc promises) or drop the const until wired | [src/lib.rs:70] | actionable | lane/d2b-provider-system-core.md - -**`d2b-provider-toolkit`** - -- `RS-0414` | medium | `d2b-provider-toolkit` | test-only constructors `GuestCredentialBackend::from_socket_for_test` and `from_socket_for_test_with_route` sit on the public surface (the type is re-exported at the crate root) without the house `test-support` feature gate that `d2b-session` uses for the same class of export | fix: move both behind a `test-support` feature (or `#[doc(hidden)]` + `#[cfg(any(test, feature = "test-support"))]`) so downstream crates cannot rely on them | [packages/d2b-provider-toolkit/src/base/fd10.rs:888, packages/d2b-provider-toolkit/src/base/fd10.rs:901, packages/d2b-provider-toolkit/src/lib.rs:89] | actionable | lane/d2b-provider-toolkit-p1.md -- `RS-0415` | low | `d2b-provider-toolkit` | two dead public methods on `GeneratedProviderServiceServer`: `response_request_id` is a pure identity function (`request_id` in, same reference out) and `generated_service` has no callers anywhere | fix: delete both methods (and the `response_request_id` doc), keeping `generated_services()` which the registration-boundary doc justifies | [packages/d2b-provider-toolkit/src/server/service.rs:297-299, packages/d2b-provider-toolkit/src/server/service.rs:174-176] | actionable | lane/d2b-provider-toolkit-p2.md -- `RS-0416` | low | `d2b-provider-toolkit` | `SharedProviderEffectRequest::envelope()` (the old-shape owner-envelope document) has zero callers and clones the full spec and metadata Values on every call | fix: delete the method; the driver and families read `spec`/`metadata` directly | [packages/d2b-provider-toolkit/src/shared_provider.rs:525-531] | actionable | lane/d2b-provider-toolkit-p2.md -- `RS-0417` | low | `d2b-provider-toolkit` | `TestHarness::clock()` returns `&Arc`, exposing the Arc in the public signature when callers only need the clock | fix: return `&DeterministicClock` (callers at testing/mod.rs:686 and tests/harness.rs:857-909 all deref) | [packages/d2b-provider-toolkit/src/testing/mod.rs:530-532] | actionable | lane/d2b-provider-toolkit-p2.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0418` | low | `d2b-provider-transport-azure-relay` | `RelayCredentialPort::acquire` is a required trait method whose only production implementation (GatewayGuestCredentialPort) returns `Err(BindingRequired)` - the same fail-closed policy the trait already gives `acquire_bound` as a default - so every implementer must write a method that never succeeds | fix: give `acquire` a default body returning `Err(RelayCredentialError::BindingRequired)` and delete the redundant overrides in GatewayGuestCredentialPort and the test fakes | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:491-497, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:387-392] | actionable | lane/d2b-provider-transport-azure-relay.md -- `RS-0419` | low | `d2b-provider-transport-azure-relay` | `set_drop_hook` takes `Arc` in a public signature although the lease is the sole owner of the hook (it is stored once and called on drop), forcing every caller to allocate an Arc for a single-owner value | fix: take `Box` or a generic `F: Fn(u64) + Send + Sync + 'static`; call sites (guest_credential.rs:455, tests) change `Arc::new)...)` to `Box::new)...)` | [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343-347, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:455] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-volume`** - -- `RS-0420` | medium | `d2b-provider-volume` | `VolumeDriverArgs.zone: String` is never read by the factory, descriptor, or driver (`create` clones it into a throwaway args before `VolumeDriver::new` drops it; the derived rows' zone comes from the manager-keyed `ResourceContext`, so the doc's "zone identity every derived row folds in" claim has no code path) | fix: remove the field from `VolumeDriverArgs` (and its `lib.rs` re-export), drop the clone at driver.rs:282, update construction sites `d2bd/src/resource_plane_v3.rs:2975-2977` and `tests/registration.rs:25` (plus this crate's test fixtures)) | [driver.rs:246-250, driver.rs:282, d2bd/src/resource_plane_v3.rs:2975, tests/registration.rs:25] | actionable | lane/d2b-provider-volume.md - -**`d2b-provider-volume-local`** - -- `RS-0421` | medium | `d2b-provider-volume-local` | `pub mod testing` (ScriptedPort with a Mutex, fixtures, hand-rolled block_on) is compiled unconditionally into the production library although it is consumed only by tests: this crate's tests/** and one d2bd test fn; the house pattern for cross-crate test support is a feature gate | fix: gate the module behind a `test-support` feature (`#[cfg(feature = "test-support")]` on `pub mod testing`, add `[features] test-support = []`), and enable the feature from d2bd's dev-dependencies | [src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1] | actionable | lane/d2b-provider-volume-local.md - -**`d2b-provider-zone`** - -- `RS-0422` | medium | `d2b-provider-zone` | `pub mod zone_status;` plus `pub use zone_status::*;` (lib.rs:9-10) exposes every zone_status item at two paths (crate root and module path), violating the house single-surface pattern (named re-export arms with a private module, cf. telemetry-service lib.rs:34-36 and wayland-session lib.rs:11-20) | fix: make the module private and re-export the four items by name (`SystemCoreStatusEmitter`, `ZoneRuntimeMetadata`, `ZoneStatusInput`, `ZoneStatusProjectionError`), updating the module-path call sites | [packages/d2b-provider-zone/src/lib.rs:9-10, packages/d2b-provider-zone/src/zone_status.rs:43] | actionable | lane/tail-5.md - -**`d2b-provider-zone-link`** - -- `RS-0423` | low | `d2b-provider-zone-link` | `ZoneLinkMetricSample` and `ZONE_LINK_METRIC_LABEL_KEYS` are exported pub (and re-exported through `zonelink`) but have zero consumers outside the crate, so the metric vocabulary is promised surface nobody wires | fix: either consume them from `d2bd`'s metrics path or reduce to `pub(crate)` until a consumer exists | [packages/d2b-provider-zone-link/src/zone_links.rs:1783, packages/d2b-provider-zone-link/src/zone_links.rs:89, packages/d2b-provider-zone-link/src/zonelink.rs:13] | actionable | lane/d2b-provider-zone-link.md -- `RS-0424` | low | `d2b-provider-zone-link` | `transport_error_is_quarantine` is a `pub const fn` with zero callers anywhere, including in-crate tests, so it is dead exported surface | fix: make it private or delete it until the quarantine mapping is actually consumed | [packages/d2b-provider-zone-link/src/zonelink.rs:281] | actionable | lane/d2b-provider-zone-link.md -- `RS-0425` | low | `d2b-provider-zone-link` | `ZoneLinkCursorAuthority` is `pub` but is only reached through `ZoneLinkController` in the same module and the module's own tests, so its publicity is wider than its use | fix: reduce to `pub(crate)` | [packages/d2b-provider-zone-link/src/zonelink.rs:178] | actionable | lane/d2b-provider-zone-link.md - -**`d2b-resource-api`** - -- `RS-0426` | low | `d2b-resource-api` | one-variant `ResourceApiReachability` enum plus `RESOURCE_API_REACHABILITY` const have no production consumer; the only assertion compares the const to its own definition and cannot fail | fix: delete both and the assertion in the 13-method test, or wire the const to a real reachability check | [adapter.rs:251-256, adapter.rs:1208-1211] | actionable | lane/d2b-resource-api-p1.md -- `RS-0427` | low | `d2b-resource-api` | `commit_configuration_batch` is pub on both `ResourceApiClient` and `ResourceService` but nothing calls it (declared "internal Core path", unwired) | fix: wire it into d2bd bundle ingestion (packages/d2bd/src/resource_plane_v3.rs:3445 area) or reduce to pub(crate) until a caller exists | [client.rs:98, service.rs:837] | actionable | lane/d2b-resource-api-p1.md -- `RS-0428` | low | `d2b-resource-api` | three `manager_backend` helpers are pub in a pub module with no production caller outside the crate: `wire_revision` (internal-only), `api_subject` (internal-only), `resource_owner_subject` (test-only, doc says U9/U10 wires it) | fix: make `wire_revision` and `api_subject` pub(crate); keep `resource_owner_subject` pub only when the U9/U10 caller lands | [manager_backend.rs:81, manager_backend.rs:208, manager_backend.rs:227] | actionable | lane/d2b-resource-api-p1.md - -**`d2b-resource-client`** - -- `RS-0429` | medium | `d2b-resource-client` | eight zero-caller pub items form dead surface: `ZonePeerIdentity::from_enrolled_peer` (zone_client.rs:83), `ZoneSocketConnector::local_daemon_endpoint_identity` (361), `ZoneClient::scoped_query` (635), `scoped_child_query` (646), `call_resource` (703), `ProcessAttachTarget::from_target` (process_attach.rs:125), `configured_launcher_from_target` (132), `ProcessAttachClient::attach_local` (721) | fix: remove or demote to `pub(crate)` (and, if kept, merge the two from-target constructors into one) | [packages/d2b-resource-client/src/zone_client.rs:83, packages/d2b-resource-client/src/zone_client.rs:361, packages/d2b-resource-client/src/zone_client.rs:635, packages/d2b-resource-client/src/zone_client.rs:646] | actionable | lane/d2b-resource-client.md merged: d2b-resource-client#9 - -**`d2b-resource-runtime`** - -- `RS-0430` | medium | `d2b-resource-runtime` | ResourceContext::new accepts `_target: TargetHandle` and discards it; every caller supplies a value that is silently dropped | fix: remove the parameter and update the 21 call sites (provider family, resource.rs, metadata.rs, context.rs test_support), or store it and expose ResourceContext::target() per U4's "coarse handle a driver context exposes" | [packages/d2b-resource-runtime/src/context.rs:364-366] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0431` | medium | `d2b-resource-runtime` | TargetBinding::directory() returns &Arc (internals leak in a public signature) and has zero callers | fix: remove the accessor, or return &TargetDirectory if a caller appears | [packages/d2b-resource-runtime/src/target.rs:491-493] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0432` | low | `d2b-resource-runtime` | GuestTargetRuntime::reference() returns TargetRef by value (clones the name String) and has zero callers | fix: remove the accessor, or return &TargetRef | [packages/d2b-resource-runtime/src/guest_target.rs:460-462] | actionable | lane/d2b-resource-runtime-p2.md - -**`d2b-resource-types`** - -- `RS-0433` | medium | `d2b-resource-types` | `assert_metadata_registration` is a test-only assertion helper exported unconditionally through the crate root, while the crate already declares a `test-support` feature that no consumer enables | fix: gate the fn and its `pub use` arm behind `#[cfg(feature = "test-support")]` (or `any(test, feature = "test-support")` per the house pattern in d2b-provider-activation-nixos/Cargo.toml:16-23) and enable the feature from the 11 consumer crates' test targets | [packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72, packages/d2b-resource-types/Cargo.toml:9] | actionable | lane/tail-6.md - -**`d2b-session`** - -- `RS-0434` | low | `d2b-session` | `Fragment.header` is a public mutable field on an exported wire-facing struct while `bytes` is private behind `as_bytes()`, so external crates can corrupt the header/bytes pairing (reassembly validates at use, but the surface invites it) | fix: make `header` private and add `pub fn header(&self) -> &FragmentHeader`, keeping construction through `Fragmenter`/`from_parts` | [fragmentation.rs:10-13] | actionable | lane/d2b-session-p1.md -- `RS-0435` | low | `d2b-session` | SessionEngine exposes seven establishment constructors, the metrics-taking variants have no production callers, and a public with_metrics builder already exists | fix: drop establish_initiator_with_generation_discovery_and_metrics and establish_responder_with_metrics, keep one metrics-taking path per role, and give establish_responder_with_generation_floor a metrics twin instead of recording into a fresh NoopMetrics | [engine.rs:166, engine.rs:262, engine.rs:416, engine.rs:356] | actionable | lane/d2b-session-p2.md merged: d2b-session-p2#8 - -**`d2b-session-unix`** - -- `RS-0436` | medium | `d2b-session-unix` | `SentPacket::acknowledge(self) {}` is a public no-op whose name promises an acknowledgment; its only behavior is dropping the packet (releasing the credit bundle via `Drop`), which callers cannot tell from the signature | fix: remove the method and let callers drop the packet, or document the drop-semantics contract on the method | [packages/d2b-session-unix/src/socket.rs:176] | actionable | lane/d2b-session-unix.md - -**`d2b-sk-frontend`** - -- `RS-0437` | low | `d2b-sk-frontend` | `pub mod agent/config/link/uhid` plus root `pub use` re-exports make every item reachable at two paths, deviating from the house single-surface pattern; only the binary needs a module path | fix: make the four modules private (`mod agent; ...`) and re-export `UhidDevice` (and `UhidEvent`) from lib.rs, updating main.rs:41 to `use d2b_sk_frontend::{Config, SecurityKeyFrontend, UhidDevice, VsockAllocatorLink}` | [packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-sk-frontend/src/lib.rs:27, packages/d2b-sk-frontend/src/main.rs:41] | actionable | lane/tail-6.md - -**`d2b-unsafe-local-helper`** - -- `RS-0438` | low | `d2b-unsafe-local-helper` | the exported surface includes SupervisorSpec, send_frame/receive_frame/configure_socket_buffers, and SUPERVISOR_START_TIMEOUT/SNAPSHOT_RECONCILE_TIMEOUT, none consumed by the crate's only external user (the same crate's binary main.rs, which imports only HelperClient, ScopeRuntime, run_scope_supervisor, SystemdUserScopeManager, default_helper_socket_path) | fix: narrow to pub(crate)/private where possible; keep pub only the items main.rs or a pub signature needs | [packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/protocol.rs:310, packages/d2b-unsafe-local-helper/src/protocol.rs:337, packages/d2b-unsafe-local-helper/src/protocol.rs:357] | actionable | lane/d2b-unsafe-local-helper.md merged: d2b-unsafe-local-helper#8,d2b-unsafe-local-helper#7 - -**`d2bd`** - -- `RS-0442` | medium | `d2bd` | `pub mod process_provider_runtime` and `pub mod provider_effects` are root-public, exposing the daemon's internal composition (83 pub items in the two modules, including `ProductionProcessProviders`, `FixedEffectAdapter`, `ProviderLifecycleDispatch`, and the pub `FixedEffectError`/`ProviderEffectError` enums) whose only external consumer is the crate's own `test-support`-gated integration test; the daemon binary reaches neither module | fix: declare both `pub(crate) mod` in composition.rs and keep a `#[cfg(feature = "test-support")]` re-export seam for `tests/resource_operator_activation.rs` (house pattern for test-support surface) | [packages/d2bd/src/composition.rs:398, packages/d2bd/src/composition.rs:400, packages/d2bd/src/provider_effects.rs:34, packages/d2bd/src/process_provider_runtime.rs:836] | actionable | lane/d2bd-p7.md -- `RS-0441` | low | `d2bd` | `ResourcePlaneV3::targets`/`hub`/`store`/`registry` return `&Arc`, exposing refcount plumbing in the accessor surface and forcing the two callers that need the shared handle to clone through the reference | fix: return `&TargetDirectory`/`&SpecStore`/`&PlaneResourceRegistry` from the borrow-only accessors and `Arc`/`Arc` by value from `hub()`/`targets()`, then update `Arc::clone(plane.hub())` at resource_runtime.rs:4423 and `Arc::clone(plane.targets())` at composition.rs:11250 to `plane.hub()`/`plane.targets()` | [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2bd/src/resource_plane_v3.rs:3295, packages/d2bd/src/resource_plane_v3.rs:3301, packages/d2bd/src/resource_plane_v3.rs:3308] | actionable | lane/d2bd-p6.md -- `RS-0439` | low | `d2bd` | the pub surface of audio_host_controller.rs (trait HostAudioController 59, PipeWireHostController 92, from_audio_node 106, find_audio_node 124, QemuAudioController 214) is unreachable outside the crate because `mod audio_host_controller;` (composition.rs:395) is private | fix: reduce these to `pub(crate)` (FakeHostController is already cfg(test)) so the visibility says what the surface is | [packages/d2bd/src/audio_host_controller.rs:59, packages/d2bd/src/audio_host_controller.rs:92, packages/d2bd/src/composition.rs:395] | actionable | lane/d2bd-p2.md -- `RS-0440` | low | `d2bd` | `vm_name: &str` in HostAudioController::enforce_grant/enforce_level is dead trait surface: every implementation (PipeWire, Qemu, Fake) names it `_vm_name` and ignores it, and the only callers (audio_dispatch.rs:160,177) pass it pointlessly | fix: remove the parameter from both trait methods and the call sites | [packages/d2bd/src/audio_host_controller.rs:68, packages/d2bd/src/audio_host_controller.rs:78, packages/d2bd/src/audio_host_controller.rs:173] | actionable | lane/d2bd-p2.md -- `RS-0443` | low | `d2bd` | `pub use d2b_provider::{MAX_PROVIDER_REGISTRY_ENTRIES, ProviderRegistrySnapshot};` re-exports `ProviderRegistrySnapshot`, which nothing in d2bd uses; only `MAX_PROVIDER_REGISTRY_ENTRIES` is consumed (registry bound check) | fix: re-export `MAX_PROVIDER_REGISTRY_ENTRIES` only, removing the second path to `ProviderRegistrySnapshot` | [packages/d2bd/src/provider_registry.rs:48, packages/d2bd/src/provider_registry.rs:288] | actionable | lane/d2bd-p8.md - -**`d2bd-runtime`** - -- `RS-0444` | medium | `d2bd-runtime` | EstablishedShell exposes `pub backend: Arc`, pushing an Arc + trait-object + the whole backend trait into the public field surface, when callers only need the three trait methods | fix: make the field private, add `handle_op`/`close_attachment`/`cancel_attachment` delegating methods on EstablishedShell, and update the d2bd/src/composition.rs call sites (13403,13460,13517,13625,13677)) | [shell_backend.rs:52-53] | actionable | lane/d2bd-runtime-p1.md merged: d2bd-runtime-p1#9 -- `RS-0446` | low | `d2bd-runtime` | `pub fn spawn_session_worker` (with `pub struct WorkerSpawn`, `SessionTable`, `ExecOpDeadlines`, `ExecStartSpec`, etc.) has no production caller in the workspace - only its own crate's tests - so the whole exec-session worker surface is either pending wiring from d2bd composition or dead public API | fix: wire `spawn_session_worker`/`SessionTable` into d2bd's exec composition (or gate the module test-support-only pending that wiring) | [packages/d2bd-runtime/src/exec_session.rs:900] | actionable | lane/d2bd-runtime-p3.md -- `RS-0445` | low | `d2bd-runtime` | CachedPublicFrame is pub with pub fields (including a serde_json::Value dependency field)but only used inside public_read_model; the struct is dead public surface | fix: make CachedPublicFrame (and its fields) module-private or pub(crate, keep the ArcSwapOption slots private | [public_read_model.rs:51-53] | actionable | lane/d2bd-runtime-p1.md -- `RS-0447` | low | `d2bd-runtime` | `ConsoleClientHandle(pub String)` exposes the inner token of a type documented as "Opaque per-client session token", so any caller can fabricate handles and the opacity claim is unenforced | fix: make the field private, add `FromStr`/`as_str`, and route the table's own lookups through them | [packages/d2bd-runtime/src/console_session.rs:118] | actionable | lane/d2bd-runtime-p4.md -- `RS-0448` | low | `d2bd-runtime` | `spawn_ch_serial_drainer(_vm: String, ...)` takes an unused `_vm` parameter, and its only caller allocates a hardcoded `"ch-console".to_owned()` per session to satisfy it | fix: drop the parameter and the call-site allocation in `create_ch_session` | [packages/d2bd-runtime/src/console_session.rs:341, packages/d2bd-runtime/src/console_session.rs:422] | actionable | lane/d2bd-runtime-p4.md -- `RS-0449` | low | `d2bd-runtime` | `DrainerSource` is a dead public enum: never constructed anywhere, with a `#[allow(dead_code)]` `Connected` variant carrying a tokio stream | fix: delete the enum (and the allow) | [packages/d2bd-runtime/src/console_session.rs:54] | actionable | lane/d2bd-runtime-p4.md -- `RS-0450` | low | `d2bd-runtime` | `ConsoleRing` and `ConsoleSession` expose all fields `pub` (`ring: RingBuffer`, `notify`, `drainer`, `stdin_tx`), so the documented invariant "notify fires whenever bytes are pushed or EOF is set" (console_session.rs:68) is convention-only: an external caller can push bytes without notifying and waiters hang | fix: make the fields private and expose `push_bytes`/`set_eof`/`read_at` on `ConsoleRing` and accessors on `ConsoleSession` that notify internally | [packages/d2bd-runtime/src/console_session.rs:66, packages/d2bd-runtime/src/console_session.rs:90] | actionable | lane/d2bd-runtime-p4.md - -### `err` - -Error policy: panic vs Result boundary, taxonomy split by caller action, context survival, wire error codes. - -**`X3-cross-crate-duplication`** - -- `RS-0963` | medium | `X3-cross-crate-duplication` | Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { path, detail: String }`, `Io(String)`, `Frame(String)`, `ManagerRpc(String)`, `TypedError::InternalIo { context, detail }`, five `String` variants of PlaneError, `kind: String` in four Io variants), destroying the source chain so diagnostics and callers cannot distinguish failure classes | fix: carry the source with thiserror `#[from]`/`source()` in each enum (no in-tree helper exists; the std Error source chain is the canonical home); wire-visible members (d2bd TypedError) need contract sign-off before the shape changes, internal members (broker, clipboard, azure-relay, resource-runtime, d2bd-runtime vsock) are actionable first | [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69] | needs-contract | lane/X3-cross-crate-duplication.md - -**`d2b`** - -- `RS-0477` | medium | `d2b` | `CliFailure` flattens the error class into the message (`format!("{error_class}: {message}")`), so callers recover the class by string-matching the message prefix | fix: add a structured `code: &'static str` field to `CliFailure` (lib.rs:44-52), populate it in `ZoneContext::failure` (context.rs:1181-1189), and match on it in `can_fallback_to_local_state` and `reconcile_deadline` instead of `message.split(':').next()` / `strip_prefix("ref-invalid: ")` | [packages/d2b/src/host.rs:200, packages/d2b/src/resource.rs:916, packages/d2b/src/lib.rs:44] | actionable | lane/d2b-p2.md -- `RS-0478` | medium | `d2b` | `d2b host prepare`/`destroy` without flags exit 2 with kind `ref-invalid`, diverging from the documented `--apply-or-dry-run-required` exit-78 envelope; `host reconcile` exits 78 but with the wrong kind | fix: route `mutation()` and `reconcile()` through `missing_mutation_flag_envelope` (dispatch.rs:369-375) like `validate()` already does, or correct docs/reference/error-codes.md:156 | [packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, docs/reference/error-codes.md:156] | needs-contract | lane/d2b-p2.md merged: d2b-p2#7 - -**`d2b-audit`** - -- `RS-0451` | medium | `d2b-audit` | `export_segments_range` classifies a failed `AuditRecord` deserialize by string-matching the serde error's Display (`error.to_string().contains("audit-record-hash-mismatch")`) to pick the "hash-break" export error code; a reworded deserialize message silently reclassifies a chain break as "record-invalid" | fix: split parse from verification (deserialize into a wire shape, then `verify()` to surface `AuditRecordError::HashMismatch`), or have the `Deserialize` impl expose the failure class; the emitted `error_code` strings stay unchanged | [packages/d2b-audit/src/export.rs:230] | actionable | lane/d2b-audit.md -- `RS-0452` | medium | `d2b-audit` | `is_discardable_checkpoint_scratch_error` classifies `io::Error` by matching `error.to_string().as_str()` against three literal codes ("audit-retention-checkpoint-invalid" / "-limit" / "-unverifiable") produced by `io::Error::other` at the checkpoint read/validate sites; a reworded code silently changes the discard decision on restart | fix: introduce a private checkpoint-read error enum (or a sentinel error kind) and match on it, keeping the io::Error strings at the public boundary | [packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b-audit/src/segment.rs:718] | actionable | lane/d2b-audit.md - -**`d2b-broker`** - -- `RS-0455` | high | `d2b-broker` | DispatchAuditContext::from_request panics the broker on a malformed authoritative audit join: both CanonicalAuditDigest::parse(zone_id.expect)...) at runtime.rs:2419-2422 parse data that came straight out the wire (request.authoritative_audit_join() returns the strings unchecked), while the sibling from_request_with_join (runtime.rs:2440-2444) converts the same parse failure to BrokerError::Protocol - a remote caller can crash the daemon | fix: replace both expect("authoritative ... digest") calls with `.map_err(|_| BrokerError::Protocol("audit zone identity invalid".to_owned()))?;`, mirroring runtime.rs:2442-2444, keeping the panic out of the wire path | [packages/d2b-broker/src/runtime.rs:2419, packages/d2b-broker/src/runtime.rs:2422] | actionable | lane/d2b-broker-p2.md -- `RS-0454` | medium | `d2b-broker` | `UsbipLockError::Io { path: PathBuf, detail: String }` flattens the underlying `io::Error` into its Display string at 12 conversion sites, losing the source chain (os error number and context) a `#[source]` field would keep for diagnosis | fix: change the variant to `Io { path: PathBuf, #[source] source: std::io::Error }` and drop the `detail: e.to_string()` maps | [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84, packages/d2b-broker/src/ops/usbip_lock.rs:98, packages/d2b-broker/src/ops/usbip_lock.rs:110] | actionable | lane/d2b-broker-p1.md -- `RS-0457` | medium | `d2b-broker` | `WriteMarkerBlockError::Io(String)` (hosts.rs:122) flattens `io::Error` into a Display-only string at three `map_err` sites, destroying the error kind/source so a caller cannot classify NotFound vs permission vs other without string-matching | fix: switch the variant to `Io(#[source] io::Error)` (thiserror or a hand-written `#[source]` accessor) and render the same "update-hosts marker splice: {err}" prefix so the visible message is unchanged | [packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-broker/src/ops/hosts.rs:149, packages/d2b-broker/src/ops/hosts.rs:153, packages/d2b-broker/src/ops/hosts.rs:180] | actionable | lane/d2b-broker-p5.md -- `RS-0456` | low | `d2b-broker` | `CellStore` panic policy is inconsistent: `in_memory()` (state_cells.rs:348) and `with_retention()` (360) `.expect()` on `spawn_owner` failure while the sibling `open()` (353) propagates `CellStoreError::Io` from the same call | fix: make `with_retention` return `Result` (its callers are tests), and have `in_memory` keep its infallible contract only with an `expect` that names the startup-precondition rationale | [packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360] | actionable | lane/d2b-broker-p3.md -- `RS-0458` | low | `d2b-broker` | usbip_unbind_error_is_transient classifies retryable-vs-fatal usbip failures by case-folded substring matching over `stderr`/`error` text (42-Condition-Not-Satisfied, "program does not support"..., "no matching transport"), so a locale or usbip-version message change silently flips the retry decision and the broker's eventual verdict. | fix: parse the failure once at the stderr boundary into a typed `UsbipUnbindFailure { kind: UsbipUnbindFailureKind, transient: bool, detail: String }` (or a documented constant allowlist),and drive the retry loop (and final error reporting) off the typed kind instead of re-scanning strings. | [src/ops/exec_reconcile.rs:1238-1265] | actionable | lane/d2b-broker-p6.md -- `RS-0459` | low | `d2b-broker` | guest_socket_directory returns `Result<&'static str,...>` with two plain-static-code errors (a "not root-owned" refusal, "no guest" refusal),while the sibling launch-scope pinner uses a typed `DeviceWorkerScopeError` enum - so an internal closed-error str forces callers (live_handlers.rs:2428) to stringly-match an error. | fix: give guest_socket_directory a small `GuestSocketError` enum (or reuse DeviceWorkerScopeError's callers-action split with a `GuestSocket` variant.)and return that instead of a `&'static str`. | [src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2428] | actionable | lane/d2b-broker-p6.md - -**`d2b-broker-composition`** - -- `RS-0453` | low | `d2b-broker-composition` | four public/private error returns are bare `Result<_, String>` (`verify_startup_routing`, `audit_crate`, `run_cargo_metadata`, `dependency_tree`), so a future caller that must distinguish failure classes (environment unavailable vs. cargo failure vs. invariant violation) can only string-match | fix: introduce a small typed error enum per module (the seam already owns `RoutingRefusal`; give `dependency_surface` an audit error enum with variants such as `WorkspaceUnavailable`/`CargoFailed`/`InvalidMetadata`) and return it from the cited functions | [packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/dependency_surface.rs:226, packages/d2b-broker-composition/src/dependency_surface.rs:292, packages/d2b-broker-composition/src/dependency_surface.rs:317] | actionable | lane/d2b-broker-composition.md merged: d2b-broker-composition#8 - -**`d2b-bus`** - -- `RS-0460` | medium | `d2b-bus` | public `ZoneBoundPolicyIdentity::with_provider` returns `Result`, a string a caller must string-match instead of matching on a variant | fix: return a closed error type (reuse `ZonePolicyError` with a new `NotProviderRef` variant, or a small `ZoneBoundPolicyIdentityError` enum) for the single failure condition | [packages/d2b-bus/src/wire.rs:49-56] | actionable | lane/d2b-bus-p2.md - -**`d2b-contracts`** - -- `RS-0461` | medium | `d2b-contracts` | Public constructors/validators return `Result<_, String>` or `&'static str` (ConfiguredArgv::new configured_argv.rs:15, RealmWorkloadsLauncherV2Json::validate launcher.rs:21, UnsafeLocalWorkloadsJson/LocalVmConfiguredWorkload/UnsafeLocalWorkload::validate unsafe_local_workloads.rs:35/81/96, MediaRef::validate_value and validate_usb_bus_id types.rs:114/140, validate_audit_page audit_wire.rs:51) while sibling validators inthe same crate use typed enum errors (BusIdError, IfNameError, IdError, ContractStringError, IdentityError, TokenError), forcing callers to string-match instead of matching variants | fix: introduce typed error enums per surface (e.g. `ConfiguredArgvError`, `UnsafeLocalWorkloadsError`, `LauncherMetadataError`, `MediaRefError`)with thiserror-style Display + std::error::Error impls and return them; call sites that only `.unwrap()` (census: ConfiguredArgv::new used in d2b-contracts-control, d2bd-runtime, d2bd, d2b-unsafe-local-helper) compile unchanged | [packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:21, packages/d2b-contracts/src/unsafe_local_workloads.rs:35, packages/d2b-contracts/src/types.rs:114] | actionable | lane/d2b-contracts.md merged: d2b-contracts#1,d2b-contracts#2,d2b-contracts#7 - -**`d2b-contracts-control`** - -- `RS-0462` | low | `d2b-contracts-control` | `ShellNameError` is a public error type with no `Display` or `std::error::Error` impl, so callers cannot format it or chain it with `?` | fix: add `Display` + `std::error::Error` impls (additive; the type is documented as an empty struct in daemon-api.md:653) | [public_wire.rs:1297] | actionable | lane/d2b-contracts-control.md - -**`d2b-contracts-provider`** - -- `RS-0463` | medium | `d2b-contracts-provider` | `ProviderRegistryPublication::new` maps `generation == 0` to `MappingBoundExceeded` even though the `ZeroGeneration` variant exists and is used by the entry constructor, so a caller distinguishing invalid generation from bound overflow receives the wrong code | fix: split the check into `if generation.get() == 0 { return Err(ZeroGeneration) }` before the mapping-count bound | [packages/d2b-contracts-provider/src/v3/provider_registry.rs:186, packages/d2b-contracts-provider/src/v3/provider_registry.rs:92] | actionable | lane/d2b-contracts-provider-p1.md -- `RS-0465` | low | `d2b-contracts-provider` | `CredentialControllerError::AlreadyRunning` renders the wire label "credential-queue-pressure", which names a different concept (the lease-ceiling outcome `CredentialControllerOutcome::QueuePressure`) than the variant's documented meaning ("the same Credential is already being handled") | fix: emit "credential-already-running" from the Display arm, or rename the variant to match the code | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:90] | actionable | lane/d2b-contracts-provider-p2.md -- `RS-0466` | low | `d2b-contracts-provider` | `CredentialObservabilityError` Display strings are prose sentences ("credential audit record is invalid", "credential telemetry frame is invalid"), breaking the kebab-code diagnostic convention every sibling error type in this crate follows (`CredentialControllerError`, `MetricPolicyError`, `TelemetryFrameError`, `SemanticContractError`, `BindingChildError`) | fix: render "credential-audit-record-invalid" and "credential-telemetry-frame-invalid" | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1508, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1509] | actionable | lane/d2b-contracts-provider-p2.md -- `RS-0464` | low | `d2b-contracts-provider` | an entry-generation mismatch in `ProviderRegistryPublication::new` reports `AxisMismatch`, whose Display code is `provider-registry-axis-mismatch`, although no binding axis is involved | fix: add a `GenerationMismatch` variant with its own kebab code and return it for the `entry.provider_generation != generation` check | [packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-provider/src/v3/provider_registry.rs:193] | actionable | lane/d2b-contracts-provider-p1.md -- `RS-0467` | low | `d2b-contracts-provider` | `CredentialSingleFlight` maps a poisoned mutex to `InvalidInput` (a caller-input error) and its guard `Drop` silently skips the removal on poison, which would leave a stale UID and a permanent `AlreadyRunning`; the skill names recovery via `into_inner()` for exactly this shape | fix: recover with `self.running.lock().unwrap_or_else(|poisoned| poisoned.into_inner())` in both `lock()` and `Drop`, keeping the documented synchronous-path boundary | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:834, packages/d2b-contracts-provider/src/v3/credential_controller.rs:846] | actionable | lane/d2b-contracts-provider-p2.md - -**`d2b-contracts-resource`** - -- `RS-0468` | medium | `d2b-contracts-resource` | `StoreErrorKind` (operations/error.rs:93-129) duplicates all 31 `ResourceErrorKind` variants and their `as_str` spellings verbatim, and d2b-resource-api/src/error.rs:11-56 `map_store_error_kind` re-lists all 31 a third time, so adding one resource-plane kind requires three synchronized edits and no test pins the overlap (each set only pins its own size) | fix: restructure `StoreErrorKind` as `Resource(ResourceErrorKind)` plus the three store-only variants (StoreIntegrityFailure, StoreBackpressure, StoreQuarantined), which collapses the map to one arm plus store arms while keeping `as_str` outputs identical | [packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-resource/src/v3/operations/error.rs:132, packages/d2b-resource-api/src/error.rs:11] | actionable | lane/d2b-contracts-resource-p1.md - -**`d2b-contracts-zone-session`** - -- `RS-0469` | medium | `d2b-contracts-zone-session` | from_component_session on EndpointPurpose and ServicePackage panics via expect("preserved component-session tag") on a wire-derived value, enforcing the cross-taxonomy totality only at runtime | fix: replace the tag lookup with an exhaustive match over base::EndpointPurpose / base::ServicePackage variants so adding a component-session variant becomes a compile error, or return Result like EndpointRole::from_component_session already does (zone_session.rs:314) | [zone_session.rs:297, zone_session.rs:332] | actionable | lane/d2b-contracts-zone-session-p2.md - -**`d2b-core`** - -- `RS-0471` | medium | `d2b-core` | resolve_macvtap_intents returns `Result, String>`, a String error in a library API whose two failure modes (missing process node, missing macvtap metadata) are indistinguishable to the caller; the broker wraps it wholesale into BrokerError::LiveHandler | fix: return `crate::error::Error` via `Error::manifest_parse_error` or a small enum with the two variants, and update the single broker call site | [packages/d2b-core/src/bundle_resolver.rs:2625, packages/d2b-broker/src/runtime.rs:6405] | actionable | lane/d2b-core-p1.md -- `RS-0475` | medium | `d2b-core` | `StorageJson::validate_unique_ids` and `SyncJson::validate_lock_order` return `Result<(), String>` with format!-built messages, and storage_lifecycle.rs re-derives the failure reason and offending id by string-prefix matching (`classify_storage_validation_reason`, `classify_sync_validation_reason`, `*_offending_id`, `bounded_contract_detail`), an error taxonomy that forces string-matching; the whole chain has no production caller | fix: return a typed validation error from both validators whose variants are the existing wire enums (`StorageContractValidationReason`, `SyncContractValidationReason`) with the offending id as payload, and delete the classifier functions | [packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core/src/storage_lifecycle.rs:116, packages/d2b-core/src/storage_lifecycle.rs:140] | actionable | lane/d2b-core-p2.md -- `RS-0472` | medium | `d2b-core` | Network spec parse failures inside the trusted-bundle network path are silently dropped: `let Ok(spec) = serde_json::from_value::(spec_value) else { continue; };` in build_resource_network_intents and `serde_json::from_value(value).ok()` in find_network_spec, so a producer-side spec drift silently vanishes every intent for that network and surfaces only as an opaque "intent not found" at apply time | fix: plumb a `Result` out of build_resource_network_intents and find_network_spec and return `Error::manifest_parse_error("resource-bundle.json", reason)` on parse failure so the drift is diagnosable | [packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:1982] | actionable | lane/d2b-core-p1.md -- `RS-0476` | low | `d2b-core` | `SiteJson::validate` returns `Result<(), &'static str>` with a bare token ("invalid-wayland-socket") that callers must string-match | fix: return a small unit error enum (e.g. `SiteValidationError::InvalidWaylandSocket`) with the token as its Display | [packages/d2b-core/src/site.rs:42] | actionable | lane/d2b-core-p2.md merged: d2b-core-p2#11 -- `RS-0473` | low | `d2b-core` | from_artifacts_with_zone_resource_bundles panics on caller-supplied input via two expects (`bundle serialization for audit hashing must succeed`, `zone resource bundle bytes must be verified`) in a `pub` API whose doc comment states the precondition but cannot enforce it; the fuzz target is one caller that passes arbitrary bytes | fix: return `Result` (map both to `Error::internal_io` / `Error::manifest_parse_error`) or downgrade to `debug_assert!` plus a doc note | [packages/d2b-core/src/bundle_resolver.rs:1405, packages/d2b-core/src/bundle_resolver.rs:1412, packages/d2b-core/fuzz/src/bin/core.rs:1] | actionable | lane/d2b-core-p1.md -- `RS-0474` | low | `d2b-core` | manifest_parse_reason classifies serde failures by substring-matching the Display text (`"missing field"`, `"unknown field"`, `"invalid type"`), which is not a stable API and silently degrades to `"parse-failed"` on any message rewording | fix: match on `serde_json::Error::classify()` (ErrorClass::Syntax / Data / Eof) instead of the message text | [packages/d2b-core/src/bundle_resolver.rs:5730] | actionable | lane/d2b-core-p1.md - -**`d2b-core-controller`** - -- `RS-0470` | low | `d2b-core-controller` | AuthorityError::DuplicateConflict renders the wire code "duplicateConflict", the only non-kebab-case code in the 25-variant enum, and nothing outside this crate matches the string | fix: change the code() arm to "duplicate-conflict" and update the two in-crate assertions that pin the old spelling (authority.rs:3409 and the code table test) | [authority.rs:412] | actionable | lane/d2b-core-controller-p2.md - -**`d2b-process-conformance`** - -- `RS-0479` | low | `d2b-process-conformance` | `LaunchIdentity::new` re-borrows `owner_ref` with `.expect("binding owner is present")` immediately after an `is_some_and` guard on the same value, an input-derived `expect` the skill's audit flags; the guard and the re-borrow are the same condition so the panic is unreachable but the shape is avoidable | fix: use an if-let chain, e.g. `if let Some(owner) = owner_ref.as_ref().filter(|o| o.resource_type().as_str() == "VolumeBinding") && target_ref.is_none() { ... owner.to_canonical_string() ... }`, deleting both the separate guard and the `expect` | [packages/d2b-process-conformance/src/launch_identity.rs:147] | actionable | lane/d2b-process-conformance.md - -**`d2b-provider-activation-nixos`** - -- `RS-0480` | medium | `d2b-provider-activation-nixos` | `GenerationObservation::terminal` (exported via lib.rs:33) panics with `assert!` on a caller-supplied name that is empty, contains '/', or exceeds 128 chars, instead of making the bound a type or a `Result` | fix: take `name: ResourceName` (already bounded: no '/', <=128 chars) and have `new` parse through the same path, or return `Result`; this deletes the runtime check the type makes impossible | [packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activation-nixos/src/controller.rs:121] | actionable | lane/d2b-provider-activation-nixos.md merged: d2b-provider-activation-nixos#6 - -**`d2b-provider-audio-pipewire`** - -- `RS-0481` | medium | `d2b-provider-audio-pipewire` | `MicrophoneArbiter::new(0)` and `SpeakerMixer::new(0)` panic via `assert!` on caller input to a pub constructor; the skill's panic policy says input validation is always a `Result`, and the type-level answer (`NonZeroUsize`) exists | fix: take `NonZeroUsize` (or return `Result`) in both constructors; no current caller passes 0 (daemon uses 64), so the change is mechanical | [src/authority.rs:53-54, src/authority.rs:144-145] | actionable | lane/d2b-provider-audio-pipewire.md -- `RS-0482` | low | `d2b-provider-audio-pipewire` | the crate's error enums never chain sources: `AudioStateIoError`'s seven `io::Error` payloads and `AudioControllerError::Mediator(AudioMediatorError)` leave `Error::source()` returning `None`, flattening the chain into the Display message | fix: implement `std::error::Error::source()` for the payload variants (or move the crate to `thiserror` `#[source]`, which also removes the hand-written Display impls) | [src/state.rs:114-123, src/controller.rs:155-160] | actionable | lane/d2b-provider-audio-pipewire.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0483` | low | `d2b-provider-clipboard-wayland` | spawn_niri_event_thread panics with .expect("niri thread spawn") on thread-spawn failure while the four sibling spawn sites log the error and continue | fix: return Result from spawn_niri_event_thread and log at the call site like the bridge-copy-read, paste-replay, host-copy-read, and published-write spawners | [src/bin/d2b-clipd.rs:3550, src/bin/d2b-clipd.rs:1754, src/bin/d2b-clipd.rs:2863] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0484` | low | `d2b-provider-clipboard-wayland` | the binary propagates errors as Result<_, String> with format!-built messages at 13 signatures, where the skill names anyhow for binaries | fix: introduce anyhow at the binary top level (run and its helpers), keeping the lib error enums unchanged | [src/bin/d2b-clipd.rs:127, src/bin/d2b-clipd.rs:411, src/bin/d2b-clipd.rs:247] | actionable | lane/d2b-provider-clipboard-wayland-p1.md merged: d2b-provider-clipboard-wayland-p1#1,d2b-provider-clipboard-wayland-p1#7 -- `RS-0485` | low | `d2b-provider-clipboard-wayland` | ClipboardHistory::new returns Result but the body is an unconditional Ok, so the error arm and the map_err at ClipdHost::new (with its warn) are dead code that misleads callers into handling an impossible failure | fix: return Self from new and drop the map_err in ClipdHost::new | [packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:575-579] | actionable | lane/d2b-provider-clipboard-wayland-p2.md merged: d2b-provider-clipboard-wayland-p2#15 -- `RS-0486` | low | `d2b-provider-clipboard-wayland` | PickerSupervisor collapses the typed FramingError into PickerError::Frame(String) via to_string() at six sites, so callers cannot distinguish FrameTooLong from Incomplete from a JSON error without string matching | fix: add a `Frame(FramingError)` variant (with #[from] or #[source]) and map the framing errors into it | [packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:274, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:284, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:290] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-config-nixos`** - -- `RS-0487` | low | `d2b-provider-config-nixos` | `invalid_status()` maps client-side request-encoding failures to ttrpc `INVALID_ARGUMENT` plus the `config-document-encoding-failed` code, telling the caller their request was invalid when the client implementation failed to serialize | fix: map that site to `INTERNAL` (or reuse `rpc_error(ConfigError::EncodingFailed)`) so status class matches the code | [packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixos/src/ttrpc.rs:189] | actionable | lane/d2b-provider-config-nixos.md - -**`d2b-provider-credential-managed-identity`** - -- `RS-0488` | low | `d2b-provider-credential-managed-identity` | `export_checkpoints` panics via `.expect("lease map keys are validated Credential refs")` where every sibling invariant failure in the crate map_errs to `CredentialServiceErrorCode::InvariantFailure` | fix: replace with `.map_err(|_| invariant())?` (leveragingthe existing `invariant()` helper at lib.rs:1491) | [lib.rs:1261-1262] | actionable | lane/d2b-provider-credential-managed-identity.md - -**`d2b-provider-device-tpm`** - -- `RS-0489` | medium | `d2b-provider-device-tpm` | two same-named error enums for one domain: runner.rs:43 SwtpmArgvError (one variant, LogLevelOutOfRange with no payload, returned by SwtpmSettings::validate) and swtpm_argv.rs:104 SwtpmArgvError (six variants including LogLevelOutOfRange { level }), both reachable from the crate root (lib.rs:35 re-exports the runner one; pub mod swtpm_argv exposes the other), so callers must disambiguate by module path and the two same-named LogLevelOutOfRange variants differ in shape | fix: make SwtpmSettings::validate return swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level } and delete runner::SwtpmArgvError | [runner.rs:43, swtpm_argv.rs:104, lib.rs:35, tests/conformance.rs:11] | actionable | lane/d2b-provider-device-tpm.md - -**`d2b-provider-device-usbip`** - -- `RS-0490` | medium | `d2b-provider-device-usbip` | `UsbipStepExecutor` returns `Result<(), String>` from every step method, forcing implementers and callers to string-match reasons where the crate's own taxonomy is otherwise typed enums with `code()` accessors | fix: introduce a closed per-step error enum (or reuse `UsbipPlanError` tagged with the step) and map it in `execute_usbip_plan` | [state_machine.rs:378-386] | actionable | lane/d2b-provider-device-usbip.md - -**`d2b-provider-display-wayland`** - -- `RS-0491` | medium | `d2b-provider-display-wayland` | `DisplayController::new(pool_size)` panics via `PrincipalPool::new(pool_size).expect(...)` (controller.rs:740-741) on any caller-supplied pool size outside 1..=32; the pub library API should not panic on input-derived values | fix: return `Result` from `DisplayController::new` (or document `# Panics` naming the bound) and update the two daemon call sites | [src/controller.rs:740, src/controller.rs:741] | actionable | lane/d2b-provider-display-wayland-p2.md -- `RS-0493` | medium | `d2b-provider-display-wayland` | grant and ticket constructors return `Result<_, &'static str>` error codes (`issue_for_supervisor_with_controller_generation` process.rs:335-346, `new_for_role_with_controller_generation` process.rs:825-887), so callers cannot match the failure and the codes are untyped strings | fix: introduce a closed `LaunchError` enum (thiserror) with `SessionInvalid` and `TicketInvalid` variants and return it from both constructors; the daemon caller maps to WorkerEffectError today (d2bd interaction_composition.rs:4283) | [src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886] | actionable | lane/d2b-provider-display-wayland-p2.md -- `RS-0492` | low | `d2b-provider-display-wayland` | `WaylandSpecError::NoPrincipalAvailable` (spec.rs:30) is never constructed: pool exhaustion is mapped to a Failed status with `SessionCondition::NoPrincipalAvailable` instead of the error variant | fix: either construct the variant in the exhaustion path (controller.rs:1089) or delete it and its Display arm | [src/spec.rs:30, src/spec.rs:43] | actionable | lane/d2b-provider-display-wayland-p2.md - -**`d2b-provider-host`** - -- `RS-0494` | low | `d2b-provider-host` | the `HostDriverEffects::observe_host` seam returns `Result`: the production impl flattens the probe error and the fallback reconcile error into one `format!("{probe_error}; {error}")` message, losing the source chain; an internal crate per the skill wants an enum (or thiserror with `#[source]`) | fix: introduce a small closed error enum (e.g. `ObserveError { Probe(SystemCoreError), Reconcile(String) }` with `#[source]`) on the trait and both impls | [packages/d2b-provider-host/src/driver.rs:197, packages/d2b-provider-host/src/effects_service.rs:180] | actionable | lane/d2b-provider-host.md -- `RS-0495` | low | `d2b-provider-host` | `HostDriverError::Display` re-spells the three failure-kind codes ("system-core-spec-invalid", "system-core-host-observation-failed", "system-core-drain-pending") that `HostDriverErrorKind::failure_kind()` already maps to, so a registry-code rename drifts silently | fix: `formatter.write_str(self.kind.failure_kind().code())` using the public `FailureKind::code()` | [packages/d2b-provider-host/src/driver.rs:129, packages/d2b-provider-host/src/driver.rs:99] | actionable | lane/d2b-provider-host.md - -**`d2b-provider-network-local`** - -- `RS-0496` | low | `d2b-provider-network-local` | the sole non-test unwrap (SHA-256 word slice conversion() carries no named invariant, though the 4-byte length is statically known | fix: `u32::from_be_bytes(chunk[offset..offset + 4].try_into().expect("4-byte chunk word"))` or a slice-pattern destructure | [src/nftables.rs:588] | actionable | lane/d2b-provider-network-local.md - -**`d2b-provider-notification-desktop`** - -- `RS-0497` | medium | `d2b-provider-notification-desktop` | Fifty `Result<_, &'static str>` sites (controller, lifecycle, guest_source, runtime) form a stringly error family forcing callers to string-match, while sibling enums (AdmissionError, NotificationError, SinkError)_ are typed | fix: introduce one crate error enum (suggest `NotificationLifecycleError`) for the lifecycle/controller/config family and replace the str returns on pub fns and both effect-port traits; update d2bd's `InteractionNotificationLifecycleBackend` impl | [packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provider-notification-desktop/src/lifecycle.rs:291-297, packages/d2b-provider-notification-desktop/src/controller.rs:369, packages/d2b-provider-notification-desktop/src/controller.rs:930] | actionable | lane/d2b-provider-notification-desktop.md -- `RS-0498` | medium | `d2b-provider-notification-desktop` | Delivery rejection paths collapse every admission/session/category failure into `NotificationError::InvalidOpaqueKey`, misreporting "notification-opaque-key-invalid" for unauthenticated, cross-zone,and category-denied cases | fix: add an `NotificationError::Denied` (or `SessionDenied`) variant and map the five admission/zone/category rejection sites to it; keep `InvalidOpaqueKey` for key-bound violations | [packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-notification-desktop/src/host_sink.rs:195, packages/d2b-provider-notification-desktop/src/host_sink.rs:202, packages/d2b-provider-notification-desktop/src/host_sink.rs:308] | actionable | lane/d2b-provider-notification-desktop.md - -**`d2b-provider-observability-otel`** - -- `RS-0499` | low | `d2b-provider-observability-otel` | when the connection-tracking table is full, reject() reports `IngressErrorClass::Malformed` ("frame could not be decoded") though the frame may be valid, whereas the sibling capacity refusal reports `None` | fix: return `IngressOutcome::Rejected, IngressErrorClass::None)` on that branch(or a distinct class, if one is introduced for wire labeling),consistent with the capacity path at ingress_policy.rs:460 | [ingress_policy.rs:647] | actionable | lane/d2b-provider-observability-otel.md - -**`d2b-provider-process`** - -- `RS-0500` | low | `d2b-provider-process` | `.ok().and_then(...)` swallows the parse of a stored owning-row spec in the launch-identity path: a corrupt `VolumeBinding` or `Volume` row silently degrades to an unbound launch instead of refusing with `SpecInvalid` | fix: map the two `serde_json::from_slice` failures to `ProcessDriverErrorKind::SpecInvalid` (or return `None` only for genuinely absent rows, not for parse failures) in `identity()` and `serving_worker_launch()` | [packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/driver.rs:1124-1130] | actionable | lane/d2b-provider-process.md - -**`d2b-provider-process-systemd`** - -- `RS-0501` | low | `d2b-provider-process-systemd` | `SystemdProviderError` (src/error.rs) is a closed error catalogue with zero consumers while the live handlers refuse through the parallel `&'static str` code constants in src/operations.rs:51-107 - two refusal vocabularies in one crate | fix: delete the unused enum, or route the handler refusals through it (its codes are not pinned in docs/reference/error-codes.md, so no wire contract binds them) | [packages/d2b-provider-process-systemd/src/error.rs:5, packages/d2b-provider-process-systemd/src/operations.rs:51] | actionable | lane/d2b-provider-process-systemd.md - -**`d2b-provider-supervisor`** - -- `RS-0502` | medium | `d2b-provider-supervisor` | `ProviderSupervisor::with_limits` (the public constructor knob) panics with `assert!` on caller-provided `blocking_limit == 0` and zero `default_timeout` instead of returning a `Result` - a library panic on caller input, reachable from any future caller passing a computed bound | fix: return `Result` (or clamp and document) and have the single current construction sites handle it | [packages/d2b-provider-supervisor/src/adapter.rs:419-421] | actionable | lane/d2b-provider-supervisor.md merged: d2b-provider-supervisor#8 -- `RS-0503` | low | `d2b-provider-supervisor` | `map_error` folds any currently-unknown `ProcessEffectError` variant into `LaunchFailed` via a `_` catch-all arm, so a new upstream variant (d2b-provider-process) fails at runtime instead of at compile time | fix: make the match exhaustive over the closed variant set (drop `_`), keeping the current mappings | [packages/d2b-provider-supervisor/src/adapter.rs:888-890] | actionable | lane/d2b-provider-supervisor.md - -**`d2b-provider-telemetry-service`** - -- `RS-0504` | medium | `d2b-provider-telemetry-service` | `reconcile_service` replaces the manager's `ResourceError` with the stable `Reconcile` kind via `Err(_) => return Err(...)`, dropping the source, so the actor sees only the wire code and the underlying store failure is invisible | fix: log the source before converting (the crate has no tracing dependency today) or carry it as a `#[source]` field on `TelemetryServiceDriverError` | [packages/d2b-provider-telemetry-service/src/driver.rs:304] | actionable | lane/tail-5.md -- `RS-0505` | low | `d2b-provider-telemetry-service` | `ingest_endpoint_refs` silently drops unparseable declared refs (`ResourceRef::parse(value).ok()` inside `filter_map`), so a typo'd `ingestEndpointRefs` entry is indistinguishable from an absent list and the row requeues on the 5s resync forever with no signal | fix: log a warning naming the dropped value, or fail the reconcile with `InvalidResource` | [packages/d2b-provider-telemetry-service/src/driver.rs:386] | actionable | lane/tail-5.md - -**`d2b-provider-test-controller`** - -- `RS-0506` | low | `d2b-provider-test-controller` | `send_bootstrap` and `controller_transport` drop every failure reason with `map_err(|_| ())` (AncillaryCapacity, credit scopes, packet build, send burst, transport build), and the caller logs only the generic retry line, while sibling sites log `reason = %e` | fix: log the reason at each drop site with `warn!(reason = %e, ...)` before converting to `()` | [packages/d2b-provider-test-controller/src/main.rs:186-187, packages/d2b-provider-test-controller/src/main.rs:196-199, packages/d2b-provider-test-controller/src/main.rs:221-230] | actionable | lane/tail-5.md - -**`d2b-provider-toolkit`** - -- `RS-0507` | medium | `d2b-provider-toolkit` | the refused-forwarded-invocation audit is silently dropped for the documented U10 wire spelling: `invoke_named_with_fds_under_chain` audits the raw caller string, and `audit_named` returns when `BoundedToken::parse` fails, but the forwarded family names are PascalCase (`OpenPidfd`), which the `^[a-z][a-z0-9-]*$` token grammar rejects, so the Denied record the module contract promises for every refused invocation never lands for the uncommitted forwarded path | fix: audit the canonicalized name (lowercase/dash-strip before `BoundedToken::parse`, or audit the resolved entry's `operation.name()` when an entry exists) and add a harness case asserting the PascalCase forwarded spelling records a Denied event | [packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-toolkit/src/operations/envelope.rs:495-497, packages/d2b-provider-toolkit/src/operations/envelope.rs:341-346] | actionable | lane/d2b-provider-toolkit-p1.md -- `RS-0508` | medium | `d2b-provider-toolkit` | `SharedProviderDriver::new` panics via `ZoneId::parse(args.zone).expect("driver zone was validated at construction")`, but `SharedProviderDriverArgs.zone` is a plain pub `String` with no validation anywhere at the factory boundary, so a family passing an invalid zone crashes the provider process at driver construction | fix: hold `ZoneId` in `SharedProviderDriverArgs` (parse once in `SharedProviderDriverFactory::new` and return a `Result`), or make `create` fallible | [packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/src/shared_provider.rs:539-546] | actionable | lane/d2b-provider-toolkit-p2.md -- `RS-0510` | medium | `d2b-provider-toolkit` | `Fixture::method` maps `SpecifiedProviderMethod` with a `_ => unreachable!("specified Provider method is closed")` arm, but the enum is `#[non_exhaustive]` (d2b-contracts-provider/src/v3/provider.rs:2759), so any future contract variant becomes a runtime panic in every fixture-based test suite | fix: return `Result` and map unknown methods to `WireInvalid`, updating the two call sites (fixture.rs:190 and the `ProviderAgentService` impl) | [packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192] | actionable | lane/d2b-provider-toolkit-p2.md -- `RS-0511` | medium | `d2b-provider-toolkit` | every fake port swallows the recorder-capacity error with `let _ = self.recorder.record(...)`, so `FakePortError::RecorderFull` is never constructed (dead variant in the public closed set `ALL`) and a test exceeding `MAX_RECORDED_CALLS` silently truncates its record, contradicting the variant's own doc "the call is refused rather than dropped silently" | fix: map `ProviderToolkitError::CapacityOutOfRange` to `FakePortError::RecorderFull` and return it from the fake methods (or delete the variant and its `ALL` slot) | [packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/src/testing/fakes.rs:289-291, packages/d2b-provider-toolkit/src/testing/fakes.rs:337-339, packages/d2b-provider-toolkit/src/testing/fakes.rs:391-393] | actionable | lane/d2b-provider-toolkit-p2.md -- `RS-0509` | low | `d2b-provider-toolkit` | `key_ref` panics via `expect("manager keys carry canonical resource references")` on a `ResourceKey` whose fields are pub and unvalidated (`ResourceKey::new` accepts any strings), so the pub helper can panic on a non-canonical key a caller constructs | fix: return `Result` (map to `InvalidResource`) like the sibling `owner_ref`/`resource_uid` helpers | [packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtime/src/spec_store.rs:60-63] | actionable | lane/d2b-provider-toolkit-p2.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0512` | medium | `d2b-provider-transport-azure-relay` | `From` and `From` for `GatewayGuestZoneLinkError` discard the source entirely (`fn from(_: ...)`), collapsing every credential failure (Unreadable, Malformed, Expired, BadMode, BadOwner, Crypto) into one generic variant with no chain, so callers cannot distinguish or log the cause | fix: carry the source (e.g. `CredentialUnavailable { source: CredentialError }` with `#[source]`-style chaining, or keep the collapse but retain `source()`), matching the err skill's context-survival rule | [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69-78, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:181-187] | actionable | lane/d2b-provider-transport-azure-relay.md -- `RS-0513` | medium | `d2b-provider-transport-azure-relay` | clock-before-epoch failures are silently swallowed with `unwrap_or(0)` in `system_now_unix()` (guest_zone_link) and `system_now_unix_ms()` (guest_credential), and a zero `now` makes `load_sealed_inner`'s expiry check fail open (`now >= not_after` is false for any positive `not_after`), accepting an expired envelope - while auth.rs returns `RelayError::Clock` and relay_transport.rs maps the same condition to `CredentialExpired` | fix: propagate a clock error (or reject the load) instead of substituting 0, mirroring `RelayError::Clock` | [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:665-669, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:178-183] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-user`** - -- `RS-0514` | low | `d2b-provider-user` | `UserDriverError`'s `Display` hand-copies the three `system-core-*` failure codes that `d2b-contracts` already registers as `FailureKind` constants, so the strings can silently drift from the registry and its rendered reference | fix: write `self.kind.failure_kind().code()` in the `Display` impl (driver.rs:118-124) instead of the per-arm string match, keeping the registry the single source | [packages/d2b-provider-user/src/driver.rs:118-124, packages/d2b-contracts/src/failure_kinds.rs:342-363] | actionable | lane/d2b-provider-user.md - -**`d2b-provider-volume-binding`** - -- `RS-0515` | medium | `d2b-provider-volume-binding` | BindingDriver re-parses the zone as a BoundedToken with a per-pass .expect (driver.rs:426-427) because BindingDriverArgs.zone: String (driver.rs:344) can represent a non-bounded zone, and the sole production caller already holds a BoundedToken (d2bd resource_plane_v3.rs:2954 inputs.zone.as_str().to_owned()), so the invariant is re-checked on every validate/reconcile/recover/delete pass where a parse-at-the-boundary would check it once | fix: store BoundedToken on BindingDriverArgs/BindingDriver (parse or construct once; ResourceKey::new(&self.zone.as_str(), ...), socket_identity(&self.zone)), deleting zone_bounded and its expect | [packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-binding/src/driver.rs:426-427, packages/d2bd/src/resource_plane_v3.rs:2954] | actionable | lane/d2b-provider-volume-binding.md - -**`d2b-provider-wayland-policy`** - -- `RS-0516` | high | `d2b-provider-wayland-policy` | Panic reachable from caller input at the family engine's public boundary: `InteractionDriver::new` parses-and-expects `InteractionDriverArgs.zone: String` (pub field on pub struct with no validating constructor),and `key_ref` parses-and-expects a `ResourceKey` whose `new` accepts any strings; both invariants claimed in expect messages are not enforced by the types | fix: parse once at the args boundary (change `args.zone` to a parsed `ZoneId`, or make `InteractionDriver::new` return `Result<_, InteractionDriverError>`) and make `key_ref` return `Result` (map to `SpecInvalid`) or enforce name canonicality at `ResourceKey::new` in d2b-resource-runtime | [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-wayland-policy/src/interaction.rs:488, packages/d2b-provider-wayland-policy/src/interaction.rs:836-838, packages/d2b-resource-runtime/src/spec_store.rs:60-63] | actionable | lane/d2b-provider-wayland-policy.md - -**`d2b-provider-wayland-session`** - -- `RS-0517` | low | `d2b-provider-wayland-session` | `SessionChildSource::display_children` maps any `WorkerEffectError` from the display crate's child derivation to `InteractionEffectError::InvalidResource`, dropping the cause, and the crate has no tracing, so the derivation failure detail is invisible at the boundary | fix: log the source before mapping (add a tracing dependency) or preserve the specific variant | [packages/d2b-provider-wayland-session/src/wayland_session.rs:73] | actionable | lane/tail-5.md - -**`d2b-resource-api`** - -- `RS-0518` | low | `d2b-resource-api` | an empty batch is rejected with the reason "batch mutation count exceeds its bound", misstating the failure (empty is not over-bound) | fix: use a distinct reason such as "batch mutation count is zero" for the empty case and keep the bound reason for the `MAX_BATCH_MUTATIONS` check | [service.rs:867-868] | actionable | lane/d2b-resource-api-p1.md - -**`d2b-resource-client`** - -- `RS-0519` | low | `d2b-resource-client` | three reflexive `Mutex::lock().unwrap()` sites in the cancellation waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) handle poisoning by panic instead of an explicit choice | fix: use `expect("waker registry lock is not poisoned: no user code runs under it")` or `into_inner()` with the same written reason | [packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309, packages/d2b-resource-client/src/call.rs:335] | actionable | lane/d2b-resource-client.md - -**`d2b-resource-runtime`** - -- `RS-0520` | medium | `d2b-resource-runtime` | `ResourceError::ManagerRpc(String)` collapses caller-distinct failures into one stringly variant: transport failures ("manager channel closed", "manager dropped the request", retryable) and semantic refusals ("owner not known", "refusing re-parent", zone mismatch, permanent) are indistinguishable without string-matching, and drivers that classify a context error (e.g. `drain_owned_children` maps every non-`ChildrenDraining` error to retryable) cannot tell a dead manager from a permanent refusal | fix: split into `ManagerUnavailable` (transport) and `ManagerRejected { reason }` (semantic), or carry a `ManagerRpcKind` enum the variant stores | [packages/d2b-resource-runtime/src/error.rs:773, packages/d2b-resource-runtime/src/manager.rs:1426, packages/d2b-resource-runtime/src/metadata.rs:200] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0521` | medium | `d2b-resource-runtime` | row_from silently substitutes [0; 16] when a stored uid or owner_uid column is not exactly 16 bytes, giving a corrupt row a zero identity that collides with every other zero-uid row | fix: return a typed error (a new SpecStoreError::CorruptRow { zone, type_name, name } variant) instead of try_into().unwrap_or([0; 16]) | [packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spec_store.rs:555] | actionable | lane/d2b-resource-runtime-p2.md - -**`d2b-session`** - -- `RS-0522` | medium | `d2b-session` | OwnedTransportHandle panics via expect on descriptor, into_owned_transport, and close after the handle is consumed, because the Option> keeps the consumed state representable | fix: return Option or Result from into_owned_transport and close, or split the handle into a typestate so double-consume does not compile | [transport.rs:170, transport.rs:178, transport.rs:185, transport.rs:173] | actionable | lane/d2b-session-p2.md -- `RS-0523` | medium | `d2b-session` | SessionClientBridgeError's Display prints a fixed label and the Error impl has no source(), so the inner SessionError code is lost from the chain when the bridge logs it | fix: implement Error::source() returning Some(&SessionError) for the Session variant, and/or include the code in Display | [client.rs:216, client.rs:224, client.rs:237] | actionable | lane/d2b-session-p2.md - -**`d2b-telemetry`** - -- `RS-0524` | medium | `d2b-telemetry` | `BoundedEmitter::new_with_limits` reports invalid constructor arguments as `EmitterError::StatePoisoned`, conflating a permanent programming error with transient lock poisoning | fix: add a dedicated variant (e.g. `InvalidLimits`) and return it from the zero-capacity / zero-frame / zero-age / zero-retry guard clauses, keeping `StatePoisoned` for the `lock().map_err` sites | [packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93] | actionable | lane/d2b-telemetry.md merged: d2b-telemetry#4 -- `RS-0525` | low | `d2b-telemetry` | `SessionMetricsError::Encode` is never constructed; the `io::Error` from `encode_frame` is folded into `EmitterError::MetricPolicy(DescriptorMalformed)` inside `emit_metric`, so the variant and its Display arm are dead surface | fix: delete the `Encode(std::io::Error)` variant and the `"session-metric-encode-failed"` Display arm | [packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_metrics_sink.rs:82] | actionable | lane/d2b-telemetry.md - -**`d2b-unsafe-local-helper`** - -- `RS-0526` | medium | `d2b-unsafe-local-helper` | await_scope_identity maps every `Ok(_)` whose state is not starting/active (scope exists but the launched process already exited, stopping, or degraded) to ScopeError::IdentityMismatch, so an operational "process died during startup" is reported and handled as a security identity failure; the caller then aborts the supervisor and surfaces ScopeIdentityMismatch to the daemon | fix: return a distinct error for an early-exit scope (e.g. ScopeError::CreateFailed or a new EarlyExit variant), keep IdentityMismatch for identity-check failures only, and map it to RuntimeError::ScopeCreateFailed | [packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/systemd.rs:338-346] | actionable | lane/d2b-unsafe-local-helper.md - -**`d2bd`** - -- `RS-0531` | medium | `d2bd` | `record_workload_availability_metrics` panics via `.expect("bounded workload availability tuple")` when the metric key set drifts from the label fns: `WORKLOAD_AVAILABILITY_STATES` (composition.rs:8097) + `WORKLOAD_PROVIDERS` (composition.rs:8090) live here, while `workload_availability_label`/`workload_provider_label` live in d2bd-runtime's workload_dispatch.rs, so adding a `WorkloadAvailability` variant compiles cleanly (the exhaustive match only forces the label fn update) but makes the daemon panic on the next workload List/Status | fix: seed the `counts` map from a single source of truth exported next to the label fns (e.g. `workload_availability_states()`/`workload_provider_labels()`), or replace the expect with a graceful `entry()`/skip so an unknown label degrades to a missing gauge instead of a panic | [packages/d2bd/src/composition.rs:8140, packages/d2bd-runtime/src/workload_dispatch.rs:104, packages/d2bd/src/composition.rs:8097] | actionable | lane/d2bd-p4.md -- `RS-0532` | medium | `d2bd` | `reap_finished_handlers` joins finished listener handler tasks with `let _ = handlers.swap_remove(index)..await;`, silently discarding the `JoinError`, so a panicked handler (whose `handler_active.fetch_sub` decrement sits after the panic-capable body( neither logs and leaks its bounded 64-slot admission reservation( | fix: log the `JoinError` with `tracing::warn!` at the reap site,and wrap the spawn body so the `fetch_sub` decrement runs in a panic-safe guard, not after the admit body | [packages/d2bd/src/interaction_composition.rs:5365, packages/d2bd/src/interaction_composition.rs:5310] | actionable | lane/d2bd-p5.md -- `RS-0533` | medium | `d2bd` | `PlaneError` carries five `String` variants (`FoundationSeed`, `ManagerSpawn`, `Authority`, `Target`, `Bundle`) that wrap the inner error with `error.to_string()`/`format!` at every production site, dropping the source chain the enum's `#[from]` variants already preserve for `SpecStore`/`ProviderRegistration`/`ManagerRpc` - callers of `ResourcePlaneV3::prepare` cannot distinguish a refused spec-store open from a create failure without string-matching | fix: give each String variant a typed payload or `#[source]` (e.g. `PlaneError::Authority(#[from] d2b_core::loader_worker::Error)` where `SpecStore::open` already yields `SpecStoreError` through `#[from]`, and keep the stage word in the `Display` message, not the variant), deleting the `to_string()` wraps at the cited sites | [packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/resource_plane_v3.rs:3016, packages/d2bd/src/resource_plane_v3.rs:3025, packages/d2bd/src/resource_plane_v3.rs:3346] | actionable | lane/d2bd-p6.md -- `RS-0535` | medium | `d2bd` | a durable service row that fails to (re)spawn is silently dropped: `let _ = state.spawn_service_actor)...)` in both the supervisor's restart-recovery loop and `supervise_exit` leaves a declared effect service unhosted with no trace, contradicting the module's own respawn promise (a crashed or killed service actor is respawned from its durable row; never leaves a service unhosted) | fix: log `tracing::warn!` with service/zone/error on spawn failure at both sites, keeping the non-fatal recovery semantics | [packages/d2bd/src/effect_service_actors.rs:551, packages/d2bd/src/effect_service_actors.rs:610] | actionable | lane/d2bd-p7.md -- `RS-0527` | medium | `d2bd` | `credential_dependency_row` swallows a manager RPC failure into absence (`.ok().flatten()`), contradicting the module's own contract that "a manager RPC failure is an error - never reported as absence" (bridge_manager_row doc, 299-305); the caller `ProductionCredentialRuntime` facts closure (4511) then reports no dependency facts, so a transient manager failure silently degrades credential readiness and revocation decisions | fix: propagate the error (log it with the error field at minimum; change `credential_dependency_facts`/`CredentialRuntime::dependency_facts` to `Result>` so the driver can retry) | [packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511] | actionable | lane/d2bd-p1.md -- `RS-0529` | medium | `d2bd` | dispatch_audit maps any unrecognized severity string from the wire to `TypedError::InternalIo { context: "audit filter", detail: "severity-invalid" }`, surfacing caller input errors as internal I/O failures instead of a request-validation refusal | fix: return a wire-input refusal kind (e.g. a TypedError::Wire* invalid-request variant or the invalid_request_response frame used by mutating dispatch) for the `Some(_) =>` arm | [packages/d2bd/src/composition.rs:22793-22797, packages/d2b-contracts-control/src/public_wire.rs:2453] | actionable | lane/d2bd-p3.md -- `RS-0530` | medium | `d2bd` | ActivationLockGuard::drop silently swallows `finish_activation` failure (`let _ =`), so a coordinator refusal to close an activation is never even logged and the wedge is only discoverable via the deferred activation-pending marker | fix: log the error with tracing::warn! (boundary has no Result channel; the marker alone is not enough) | [packages/d2bd/src/composition.rs:20185-20190] | actionable | lane/d2bd-p3.md -- `RS-0537` | medium | `d2bd` | user-input audio failures are flattened into `TypedError::InternalIo { context, detail }` strings on the mutation paths (VM absent, audio not enabled) in `dispatch_audio_set_volume` / `dispatch_audio_mute`, while the status path reports the same classes as structured `AudioVmError` + `AudioErrorKind::VmNotFound` / `AudioNotEnabled`; a caller of set-volume/mute cannot distinguish VM-not-found from an internal I/O failure except by string-matching the detail | fix: map the mutation paths onto the same structured kinds (extend `TypedError` with the audio kinds used by both paths); this changes the daemon-API wire error surface, so it is needs-contract | [packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, packages/d2bd/src/audio_dispatch.rs:417-438] | needs-contract | lane/d2bd-p8.md -- `RS-0534` | low | `d2bd` | `ConstructionInputs::production` swallows the `attach_process_providers` Result at the compose-once fallback, so a `StateUnavailable` collision (or a future attach failure) silently leaves whichever instance won in the shared slot, and the plane keeps composing with its own instance either way | fix: `state.provider_runtime.attach_process_providers(Arc::clone(&providers)).map_err(|error| PlaneError::Authority(error.to_string()))?` (or a dedicated variant), matching the site's other rejections | [packages/d2bd/src/resource_plane_v3.rs:1956] | actionable | lane/d2bd-p6.md -- `RS-0536` | low | `d2bd` | the 0700 enforcement on a serving worker's socket parent is silently swallowed with `let _ =`; the sibling `create_dir_all` failure just above is a hard error, so a failed `set_permissions` leaves the launched socket dir at default umask perms with no diagnostic | fix: replace `let _ = tokio::fs::set_permissions)...)` with a `tracing::warn!` on Err, mirroring the pidfd snapshot warn at ppr:804-809 | [packages/d2bd/src/process_provider_runtime.rs:3436] | actionable | lane/d2bd-p7.md -- `RS-0528` | low | `d2bd` | `detail: err.to_string()` collapses the source error into a String when building TypedError variants, losing the error chain for diagnostics | fix: carry the source in the variant (e.g. `InternalBrokerUnavailable { path, #[source] source: serde_json::Error }` with the detail rendered in Display) so the chain survives to the logging boundary | [packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d2bd/src/composition.rs:15243, packages/d2bd/src/composition.rs:15247] | actionable | lane/d2bd-p2.md - -**`d2bd-runtime`** - -- `RS-0538` | high | `d2bd-runtime` | default_audit_join_context panics with `.expect("canonical broker zone digest")` on a wire-supplied digest - a malformed request from the broker client crashes the daemon instead of returning a refusal | fix: propagate the parse failure (e.g. `CanonicalAuditDigest::parse(zone_id).ok()?;` or map into TypedError::WireInvalidFrame/InternalConfig),and only attend None when digest missing route review-pass | [broker_transport.rs:63, broker_transport.rs:65] | actionable | lane/d2bd-runtime-p1.md -- `RS-0539` | medium | `d2bd-runtime` | `map_parse_error` (wire.rs:529-536) classifies `serde_json::Error` kinds by substring-matching the Display text ("unknown field", "interface name"), so the wire-visible kinds `wire-unknown-field`/`wire-if-name-invalid` flip silently if serde_json rewords a message | fix: classify structurally instead of lexically - e.g. parse the request envelope against a `#[serde(deny_unknown_fields)]`-tagged shape so "extra field" arrives as a discrete rejection (the manual authStatus/usbipProbe arms already do this), and route the raw serde error through `error.classify()` plus line/column for the generic frame kind | [wire.rs:529-536] | actionable | lane/d2bd-runtime-p2.md -- `RS-0540` | low | `d2bd-runtime` | `spawn_session_worker` panics at `std::thread::Builder::spawn)...).expect("spawn exec session worker thread")` in library code on an environmental failure (thread exhaustion/ENOMEM) with a caller-visible alternative | fix: return `std::io::Result>` (or map to `TypedError`) and have the two test call sites adjust | [packages/d2bd-runtime/src/exec_session.rs:939] | actionable | lane/d2bd-runtime-p3.md -- `RS-0541` | low | `d2bd-runtime` | `impl Default for ConsoleClientHandle` panics via `expect("console handle entropy unavailable")` when entropy fails, and nothing in the workspace calls `ConsoleClientHandle::default()` | fix: delete the Default impl (the type already has a fallible `new()` used at attach) | [packages/d2bd-runtime/src/console_session.rs:132] | actionable | lane/d2bd-runtime-p4.md -- `RS-0542` | low | `d2bd-runtime` | `FilesystemReader` reports failures as `Result<..., String>`, so `compute_restart_status` cannot distinguish "file missing" from "file unreadable" without string inspection and the detail is only embeddable in a banner | fix: introduce a small `VersionFileReadError` enum (e.g. `Missing` vs `Unreadable(String)`) returned by both trait methods | [packages/d2bd-runtime/src/daemon_version.rs:77, packages/d2bd-runtime/src/daemon_version.rs:85] | actionable | lane/d2bd-runtime-p4.md - -**`xtask`** - -- `RS-0543` | medium | `xtask` | `RecoveryError::Json` conflates three failure modes: an unreadable attestation file (`read_attestation` maps open/read errors to Json), canonical-JSON rejection, and a typed-parse failure whose serde detail (missing field, line, column) is discarded, so an operator debugging a rejected attestation sees only "recovery attestation shape rejected" with no way to tell a missing file from a malformed payload | fix: add a `RecoveryError::Read` variant for the fs errors and carry the bounded serde error text (field names and positions only, never payload values, keeping the enum's redaction contract) in a `Json(String)` variant, propagating through the existing `From for DeliveryError` | [packages/xtask/src/delivery/recovery.rs:384, packages/xtask/src/delivery/recovery.rs:1610, packages/xtask/src/delivery/recovery.rs:1715, packages/xtask/src/delivery/recovery.rs:1719] | actionable | lane/xtask-p3.md - -### `serde` - -Serde boundary: try_from validation, rename_all conventions, optionality semantics, enum representations, deny_unknown_fields decisions. - -**`X3-cross-crate-duplication`** - -- `RS-0961` | medium | `X3-cross-crate-duplication` | Parallel serde shims: contract/provider crates hand-write the identical Wire-struct admission shape (private `#[derive(Deserialize)]` Wire with deny_unknown_fields, then new()/TryFrom with validation) in 24+ impls where the in-tree `parsed_deserialize!` macro exists | fix: consolidate behind `parsed_deserialize!` (d2b-contracts-resource/src/v3/execution_policy.rs:33, re-exported at :63) or `#[serde(try_from = "...")]` with the raw Wire shape, keeping every admission gate; this deduplicates boilerplate and is distinct from the refused gate-removal class (over-engineering-audit-record.md rows 25/33 refused replacing gates with derives) | [packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs:101, packages/d2b-contracts-zone-session/src/v3/zone.rs:79, packages/d2b-contracts-zone-session/src/v3/role_binding.rs:192] | actionable | lane/X3-cross-crate-duplication.md - -**`d2b-broker`** - -- `RS-0545` | low | `d2b-broker` | `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in `load()` (state_cells.rs:924-931), while the in-process `CellOutcome` enum already exists | fix: derive Serialize/Deserialize on a wire enum (`#[serde(rename_all = "lowercase")]` over `CellOutcome` or a dedicated `DurableOutcome`) and delete the string match; the serialized shapes "unknown"/"completed" stay identical, so no DURABLE_VERSION bump is needed | [packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924] | actionable | lane/d2b-broker-p3.md - -**`d2b-broker-composition`** - -- `RS-0544` | low | `d2b-broker-composition` | `run_cargo_metadata` parses cargo's output into `serde_json::Value` and every consumer re-walks it with repeated `.get("packages")`/`and_then(as_array)`/`as_str` chains (`dependency_tree`, `package_name_of_id`, `is_proc_macro`), pushing the parse out of the boundary | fix: derive `Deserialize` on minimal `CargoMetadata`/`Package`/`ResolveNode` shapes and parse once in `run_cargo_metadata`, replacing the Value-walking chains with field access | [packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composition/src/dependency_surface.rs:318, packages/d2b-broker-composition/src/dependency_surface.rs:365, packages/d2b-broker-composition/src/dependency_surface.rs:380] | actionable | lane/d2b-broker-composition.md - -**`d2b-contracts`** - -- `RS-0546` | medium | `d2b-contracts` | `AuditExportEntry` carries `record: Option` andi `error: Option` where the doc (audit_wire.rs:27) promises exactly one is always populated,so both-None is a wire-accepted illegal state (the broker's own writers d2b-broker/src/audit.rs:1730-1732 etc always set one,but a literal or foreign producer can emit neither) | fix: replace the pair with an enum payload representation (e.g. `#[serde(tag = "type")] enum AuditExportEntryPayload { Record { record: Value }, Error { error: AuditExportErrorCode } }` or an admission-gate enforcing exactly-one at decode),preserving or explicitly changing the wire shape | [packages/d2b-contracts/src/audit_wire.rs:27-36] | needs-contract | lane/d2b-contracts.md - -**`d2b-contracts-broker`** - -- `RS-0547` | medium | `d2b-contracts-broker` | `OpenUnitPidfdRequest` and `StopUnitRequest` combine `#[serde(flatten)] pub unit: UnitRequest` with `deny_unknown_fields` on the containing struct, and serde ignores `deny_unknown_fields` on any type using flatten, so unknown fields in these two wire requests are silently accepted instead of refused | fix: drop the flatten (duplicate the UnitRequest fields or deserialize into a tagged wrapper) or accept-and-validate unknown fields explicitly; the wire admission change needs contract review | [packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/src/broker_wire.rs:1783-1834] | needs-contract | lane/d2b-contracts-broker.md - -**`d2b-contracts-control`** - -- `RS-0548` | medium | `d2b-contracts-control` | three hand-written `Deserialize` impls plus private `*Wire` shadow structs (HelperSnapshot, HelperLaunchRequest, AuditResponse) re-implement exactly what `#[serde(try_from = "...")]` generates: deserialize raw, validate, map failure to a deserialization error | fix: derive `Deserialize` via `#[serde(try_from = "HelperSnapshotWire")]` (and the two siblings), keeping `deny_unknown_fields` on the wire structs and deleting the manual impls | [unsafe_local_wire.rs:118, unsafe_local_wire.rs:176, public_wire.rs:2228] | actionable | lane/d2b-contracts-control.md - -**`d2b-contracts-provider`** - -- `RS-0549` | low | `d2b-contracts-provider` | `parse_raw_frame` maps every serde failure to `Malformed`, so a top-level unknown field (rejected by `deny_unknown_fields` on `TelemetryFrame`) reports `Malformed` while the same unknown key nested inside `value` reports `UnknownField` from validation - the variant exists but is unreachable for the shape that names it | fix: `map_err(|error| match error.classify() { serde_json::error::Category::UnknownField => TelemetryFrameError::UnknownField, _ => TelemetryFrameError::Malformed })` (serde_json 1.0.151 in Cargo.lock provides `classify`) | [packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:114] | actionable | lane/d2b-contracts-provider-p2.md - -**`d2b-contracts-resource`** - -- `RS-0550` | medium | `d2b-contracts-resource` | `ResourceError` derives Deserialize (error.rs:175-176), bypassing the invariants `ResourceError::new` enforces (current_revision only on ResourceConflict/AuthorizationDenied/RevisionExpired, retry_after_ms only with RetryClass::AfterDelay), so a wire error carrying an inconsistent combination deserializes into an illegal state that the retry decision logic then reads | fix: hand-write `Deserialize` for `ResourceError` through `Self::new`, matching every sibling wire type in this crate | [packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v3/error.rs:177] | actionable | lane/d2b-contracts-resource-p1.md -- `RS-0551` | medium | `d2b-contracts-resource` | `PayloadSchema` derives Deserialize (payload_schema.rs:30-32), bypassing `PayloadSchema::parse`'s closed-object and writeOnly validation, and `CommandSpec::deserialize` (d2b-provider-command/src/command.rs:248-266) feeds the wire value straight in, so a wire Command carrying an open schema or a writeOnly property with a default deserializes as valid | fix: hand-write `Deserialize` for `PayloadSchema` through `Self::parse` (the wire shape is unchanged; producers already use parse) | [packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resource/src/v3/payload_schema.rs:36] | actionable | lane/d2b-contracts-resource-p1.md - -**`d2b-contracts-zone-session`** - -- `RS-0552` | medium | `d2b-contracts-zone-session` | seventeen hand-written Deserialize impls repeat the identical Wire-struct shape (local #[derive(Deserialize)] Wire with deny_unknown_fields, then new() plus map_err(serde::de::Error::custom)) | fix: consolidate behind a shared macro in the style of parsed_deserialize! at d2b_contracts_resource::v3::execution_policy, or #[serde(try_from = "Wire")] with TryFrom, keeping each new() gate as the admission check | [zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932] | actionable | lane/d2b-contracts-zone-session-p2.md - -**`d2b-core`** - -- `RS-0556` | low | `d2b-core` | `StorageLifecycleIssue` struct variants carry per-field `#[serde(rename = "bundleVersion")]`-style renames instead of the house `#[serde(rename_all = "camelCase")]` per variant, scattering the wire convention across fields | fix: add `#[serde(rename_all = "camelCase")]` to each struct variant and drop the per-field rename attributes; the serialized shape is unchanged (pinned by the storage_lifecycle tests) | [packages/d2b-core/src/storage_lifecycle.rs:49, packages/d2b-core/src/storage_lifecycle.rs:61, packages/d2b-core/src/storage_lifecycle.rs:70] | actionable | lane/d2b-core-p2.md -- `RS-0554` | low | `d2b-core` | ZoneNativeIndexDocument derives Deserialize with `rename_all = "camelCase"` but no `deny_unknown_fields`, while the three sibling index types (ZoneNativeBundleIndex, ZoneNativeBundleRef, ZoneNativeTopology) all deny, leaving the top-level index admission inconsistent | fix: add `deny_unknown_fields` to ZoneNativeIndexDocument and keep the Nix emitter (nixos-modules/bundle.nix) in sync so no emitted key is rejected | [packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175, packages/d2b-core/src/bundle_resolver.rs:202, packages/d2b-core/src/bundle_resolver.rs:216] | needs-contract | lane/d2b-core-p1.md -- `RS-0555` | low | `d2b-core` | `#[serde(default)]` on the four Option fields of ZoneNativeBundleIndex (storage_path, site_path, host_path, realm_workloads_launcher_v2_path) is redundant: a missing Option field already deserializes to None, so the attribute adds nothing and reads as a convention violation of the sibling fields | fix: drop the four attributes | [packages/d2b-core/src/bundle_resolver.rs:183, packages/d2b-core/src/bundle_resolver.rs:187, packages/d2b-core/src/bundle_resolver.rs:194, packages/d2b-core/src/bundle_resolver.rs:196] | actionable | lane/d2b-core-p1.md - -**`d2b-core-controller`** - -- `RS-0553` | medium | `d2b-core-controller` | the assignment evidence codec is hand-rolled JSON: encode_assignment/decode_assignment/require_exact_keys/encode_bounded_json/decode_string_set walk serde_json::Value with per-field get() chains and exact-key lists where derive(Deserialize) with deny_unknown_fields plus the existing canonical-ordering checks would give the same admission; refusal-ledger row C3 names this codec and it is still present | fix: replace the Value-walking encode/decode with typed serde structs (rename_all = "camelCase", deny_unknown_fields) preserving the wire shape pinned by the transport tests (exact keys, version 1, sorted verb arrays, canonical bytes, bounded size), and replace the json!-literal payload builder in materialize_child_create_payload with a typed envelope builder | [packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controller/src/controller_assignment.rs:735, packages/d2b-core-controller/src/controller_assignment.rs:891, packages/d2b-core-controller/src/controller_assignment.rs:901] | actionable | lane/d2b-core-controller-p1.md - -**`d2b-host`** - -- `RS-0557` | low | `d2b-host` | `NftBatch` derives `Deserialize` but its `&'static str` fields pin the generated impl to `'de: 'static` (serde's `impl<'de: 'a, 'a> Deserialize<'de> for &'a str`), so the type cannot be deserialized from any runtime input; the derive is dead and misleads (the broker only ever `NftBatch::parse`s text or constructs batches) | fix: drop `Deserialize` from the `NftBatch` derive (keep `Serialize`), or make `table_family`/`table_name` owned `String` if round-trip is ever intended | [packages/d2b-host/src/nftables.rs:229] | actionable | lane/d2b-host.md - -**`d2b-process-conformance`** - -- `RS-0558` | low | `d2b-process-conformance` | `CompiledDigests` serialization is hand-written (`impl Serialize` emitting 7 named fields) where a derive with `rename_all = "camelCase"` plus `#[serde(rename = "fdTable")]` on `fd_table` produces the identical wire shape and stays in sync with the struct | fix: add `#[derive(serde::Serialize)]`/`#[serde(rename_all = "camelCase")]` on `CompiledDigests` (ticket.rs:105) and delete the manual impl at status.rs:125-137 | [packages/d2b-process-conformance/src/status.rs:125, packages/d2b-process-conformance/src/ticket.rs:105] | actionable | lane/d2b-process-conformance.md -- `RS-0559` | low | `d2b-process-conformance` | `ProcessOutcome` derives `Deserialize` on `pub` fields but permits illegal `(exit_class, exit_code)` combinations (e.g. `Crash` with `Some(300)`), so a decoded terminal message is invalid until each consumer re-validates (`ProcessOutcome::validate`, then again inside `from_parent` and `relay`); the skill's boundary rule says the read should fail, not first use | fix: deserialize into a raw shape with `#[serde(try_from = "RawOutcome")]` (or a validating custom `Deserialize`) so illegal combinations become `InvalidTerminalResult` at the boundary, then delete the per-use re-validations or keep only one | [packages/d2b-process-conformance/src/terminal.rs:39, packages/d2b-process-conformance/src/terminal.rs:94, packages/d2b-process-conformance/src/terminal.rs:177] | actionable | lane/d2b-process-conformance.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0560` | low | `d2b-provider-clipboard-wayland` | AuditEvent.mime_type carries `serialize_with = "serialize_bounded_mime"` but no deserialize_with, so the round trip is asymmetric: serialization truncates long MIME values at 64 bytes while deserialization accepts unbounded values, and the type still derives Deserialize | fix: add a matching deserialize_with (or drop Deserialize from AuditEvent if it is never read back) | [packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:43-49] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-command`** - -- `RS-0561` | medium | `d2b-provider-command` | the emitted JsonSchema for `CommandExec` (`pattern: "^/[^\\u0000]*$"`) and `CommandArgvSlot` (no pattern) is weaker than the parse admission (rejects control chars/empty/malformed braces/invalid placeholder names), so a value satisfying the published schema can be refused at serde deserialization | fix: tighten the `CommandExec` pattern to exclude `char::is_control` code points and add a `CommandArgvSlot` pattern (or an explicit `format`/`pattern` encoding the whole-slot brace rule), then regenerate the committed schema | [packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/command.rs:133-152, docs/reference/schemas/v3/core.d2bus.org_Command.schema.json:21] | needs-contract | lane/tail-2.md - -**`d2b-provider-device-gpu`** - -- `RS-0562` | medium | `d2b-provider-device-gpu` | `GpuArgvInput` admits unknown JSON fields while its sibling `VideoArgvInput` denies them (and a test pins the rejection), an inconsistent admission policy for two daemon-side wire inputs | fix: add `deny_unknown_fields` to `GpuArgvInput` (and `GpuParams`/`GpuDisplayConfig` for full nested coverage), mirroring video_argv.rs:112; the only in-tree producer d2bd/src/process_provider_runtime.rs:3707 builds a Rust literal, so no producer sends unknown fields today | [packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/video_argv.rs:112, packages/d2b-provider-device-gpu/src/video_argv.rs:244] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-display-wayland`** - -- `RS-0563` | medium | `d2b-provider-display-wayland` | the bridge receive path detects the clipd refresh frame by scanning raw bytes for the substring `"type":"refresh_selection"` (filter.rs:817-824) instead of deserializing the typed frame the way the send side serializes it (bridge.rs:321-365); the producer emits a hand-written byte literal (d2b-clipd.rs:1690), so any whitespace or key-order change in the shared JSON shape silently disables clipboard refresh with no error | fix: define a `#[serde(tag = "type", rename_all = "snake_case")]` inbound frame enum mirroring `bridge_frame`'s `Frame`, deserialize each newline frame with `serde_json::from_str`, and match the `RefreshSelection` variant; add a test feeding `{"type":"refresh_selection"}` through the drain path | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:819] | actionable | lane/d2b-provider-display-wayland-p1.md -- `RS-0564` | low | `d2b-provider-display-wayland` | `#[serde(try_from = "WaylandSessionSpecWire")]` (spec.rs:233) is inert: WaylandSessionSpec derives only Serialize, and Deserialize is hand-written (spec.rs:263-270) to do exactly what the derive plus try_from would generate | fix: delete the inert attribute (keep rename_all for the Serialize side), or derive Deserialize with try_from and delete the manual impl; pick one mechanism | [src/spec.rs:230, src/spec.rs:233, src/spec.rs:263] | actionable | lane/d2b-provider-display-wayland-p2.md - -**`d2b-provider-endpoint`** - -- `RS-0565` | medium | `d2b-provider-endpoint` | `EndpointAttachmentPolicy`'s derived `Deserialize` admits illegal state (`supported=false, max_attachments>0`,andthe converse), while its sibling `EndpointConsumerPolicy` routes `Deserialize` through `Self::new` as an admission gate,so a standalone deserializer yields a shape the constructor refuses | fix: route `EndpointAttachmentPolicy::deserialize` through `Self::new` (try_from or the sibling hand-written pattern at endpoint.rs:197-216) | [packages/d2b-provider-endpoint/src/endpoint.rs:112-120, packages/d2b-provider-endpoint/src/endpoint.rs:125-131, packages/d2b-provider-endpoint/src/endpoint.rs:197-216, packages/d2b-provider-endpoint/src/endpoint.rs:377-381] | actionable | lane/d2b-provider-endpoint.md - -**`d2b-provider-network-local`** - -- `RS-0566` | medium | `d2b-provider-network-local` | the stored-spec parse maps serde failure to `()` unit, dropping the deserialization reason before the toolkit's SpecInvalid terminal | fix: log the serde error (add a tracing::debug/warn at driver.rs:289 before the map)) or return `Result` and let the driver surface the reason; do not touch the pinned SharedProviderDeclarationError enum | [src/driver.rs:282-289, src/driver.rs:190] | actionable | lane/d2b-provider-network-local.md -- `RS-0567` | low | `d2b-provider-network-local` | provenance serialization failures are silently `.ok()`-swallowed into a missing wire field at four payload builders, while the sibling update-hosts path propagates with map_err | fix: match broker.rs:1368: `.map(serde_json::to_value).transpose().map_err)...)` at all four sites (operations.rs maps to OperationFailure::with_detail(KERNEL_REFUSED, ...)) | [src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429] | actionable | lane/d2b-provider-network-local.md - -**`d2b-provider-supervisor`** - -- `RS-0568` | medium | `d2b-provider-supervisor` | `take_controller_bootstrap` is the one wire leg not using a typed d2b-contracts-broker request/response: it hand-builds the payload with `serde_json::json!` (camelCase string keys), reads the reply via `.get("taken")`/`as_bool` with a silent `unwrap_or(false)` (a malformed reply reads as "not taken" -> `Ok(None)`), and reuses hard-coded fd index 0 | fix: add a typed `TakeControllerBootstrapRequest/Response` to the broker wire contract (the operation row currently carries `wire_variant: None`) and parse/reply through it like every sibling leg | [packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generated/broker_operation_catalog.rs:1289] | needs-contract | lane/d2b-provider-supervisor.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0569` | medium | `d2b-provider-transport-azure-relay` | `RelayTransportSettings` derives `Deserialize` without `try_from`, so `serde_json::from_slice::` at d2bd/src/composition.rs:843 accepts identifiers that `new()`/`validate()` reject - including the secret-shape exclusion (`SharedAccessSignature`) that exists only in Rust and not in the pinned schema `docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json` (whose patterns admit lowercase letters) | fix: add `#[serde(try_from = "...")]` reusing `validate()`, and first encode the secret-shape exclusion in the schema so schema and Rust agree | [packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:31-41, packages/d2bd/src/composition.rs:843-846] | needs-contract | lane/d2b-provider-transport-azure-relay.md -- `RS-0570` | low | `d2b-provider-transport-azure-relay` | `parse_material_json` hand-walks `serde_json::Value` paths for a fixed nested shape (`relayListen`/`relaySend` keyName/key) that a derived `Deserialize` with `rename_all = "camelCase"` plus a validate pass would express - this is the recorded live-admission-gate class, refused in the prior audit | fix: only rework if the admission gate is deliberately replaced (derive + `try_from` validation), citing changed evidence | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264] | policy-confirmed | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-transport-vsock`** - -- `RS-0571` | medium | `d2b-provider-transport-vsock` | `VsockTransportSettings` deserializes untrusted wire JSON with no boundary validation: invalid `guest_ref`/`connect_timeout_seconds` land as ordinary values and are only rejected by later explicit `validate()` calls (in `new()` and `ZoneLinkSpec::validate`), and the all-public fields let any caller build an invalid settings value silently; a parse-once `try_from` type would reject once at the wire. | fix: `#[serde(try_from = "VsockTransportSettingsWire")]` with a private raw wire shape +`TryFrom` validation, plus private fields and accessors; wire field names/schema stay unchanged | [packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transport-vsock/src/settings.rs:42-50, packages/d2b-provider-transport-vsock/tests/schema.rs:13-18] | needs-contract | lane/d2b-provider-transport-vsock.md - -**`d2b-provider-volume-local`** - -- `RS-0572` | medium | `d2b-provider-volume-local` | ContentFile, ContentProjection, NetworkConfigContentProjection and the evidence types derive public Deserialize that bypasses the validating constructors: the crate's parse boundary is `from_value`/`from_settings` (which run validate), but the derived impl admits unvalidated projections directly, so the type the rest of the program trusts is not guaranteed valid on the derive path | fix: route the derive through `#[serde(try_from = "Raw...")]` mirror structs (wire shape unchanged: camelCase + deny_unknown_fields preserved) or drop Deserialize from the derives and parse only via the validating entries | [src/content.rs:38-39, src/content.rs:106-107, src/content.rs:203-204, src/content.rs:239-243] | actionable | lane/d2b-provider-volume-local.md - -**`d2b-provider-wayland-policy`** - -- `RS-0573` | medium | `d2b-provider-wayland-policy` | Every wire-parse failure collapses into a bare `InvalidResource` variant that discards the serde reason, so an operator cannot tell which row or which field is malformed (a third of the enum's refusals are spec-shape checks that reuse the same variant) | fix: add a reason-carrying variant to `InteractionEffectError` and `AudioResourceRuntimeError` (e.g. `InvalidResource { reason: String }` or `Decode(#[source] serde_json::Error)` via thiserror)and thread it through the ~15 `map_err(|_| ...InvalidResource)` sites (the enum Display codes are not pinne in `docs/reference/error-codes.md` - grep "interaction" = 0 hits - so not wire-contract) | [packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-wayland-policy/src/effects_service.rs:205-206, packages/d2b-provider-wayland-policy/src/audio_registry.rs:517-534] | actionable | lane/d2b-provider-wayland-policy.md merged: d2b-provider-wayland-policy#3 - -**`d2b-resource-api`** - -- `RS-0574` | medium | `d2b-resource-api` | `render_envelope` parses the row's metadata with `serde_json::from_slice(metadata).unwrap_or(serde_json::Value::Null)`, silently rendering a degraded envelope (empty annotations, epoch fallback timestamps, provenance-derived managedBy) when the metadata is malformed, while every other parse in the file fails closed with `envelope_invalid()` | fix: map the parse error to `envelope_invalid()` like the sibling parses so a corrupt row surfaces as a schema error instead of an invisible degraded read | [manager_backend.rs:744-745] | actionable | lane/d2b-resource-api-p1.md - -**`d2bd`** - -- `RS-0576` | medium | `d2bd` | `GatewayGuestConfigFile` and `GatewayGuestRelayConfigFile` deserialize user-written guest gateway config with `rename_all = "camelCase"` but no `deny_unknown_fields`, so a typo'd key is silently ignored and surfaces later as "Guest Relay namespace is unavailable" instead of a parse error | fix: add `#[serde(deny_unknown_fields)]` to both types (the `QemuMediaProbeRegistry*` records are daemon-written and may stay permissive); add a config-typo test to `load_gateway_guest_zone_link_options` | [packages/d2bd/src/composition.rs:4196, packages/d2bd/src/composition.rs:4205] | actionable | lane/d2bd-p4.md -- `RS-0575` | low | `d2bd` | HostActivationPendingMarker.schema_version is deserialized but never validated, so a future marker version with a compatible field set would silently parse as current | fix: check `schema_version == 1` on read (refuse with a typed log/error otherwise) or drop the field from the read path if versioning is not enforced; the marker file is written by out-of-tree activation machinery, so its shape is a contract | [packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d2bd/src/composition.rs:20298] | needs-contract | lane/d2bd-p3.md -- `RS-0577` | low | `d2bd` | `declared_fd_kind` allocates a `serde_json::Value::String(kind.to_owned())` heap value just to deserialize the wire `FdKind` enum (the kebab-case `serde` mapping) | fix: use `serde_json::from_str::(kind)` (no intermediate `Value`) or a plain `match` over the kebab-case spellings | [packages/d2bd/src/forward_rendezvous.rs:979-981] | actionable | lane/d2bd-p8.md - -**`d2bd-runtime`** - -- `RS-0578` | low | `d2bd-runtime` | `parse_request` (wire.rs:256-355) hand-rolls the internally-tagged dispatch that serde provides: a 19-arm match on the `type` string then `serde_json::from_value` per arm, where the 15 plain verbs would parse directly from a `#[serde(tag = "type", rename_all = "camelCase")]` tagged enum | fix: split a tagged parse enum for list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio derived with internal tag, keeping the custom authStatus/usbipProbe empty-body checks, console opId removal and resourceRequest passthrough explicit; confirm each payload type's deny_unknown_fields posture is unchanged before shipping | [wire.rs:265-353] | actionable | lane/d2bd-runtime-p2.md merged: d2bd-runtime-p2#9 -- `RS-0579` | low | `d2bd-runtime` | `parse_vm_info` hand-walks `serde_json::Value` with `and_then` chains to extract `state`/`boot_vcpus`/`memory.size` from the Cloud Hypervisor vm.info payload, re-implementing what a derived raw shape does at the boundary | fix: derive `Deserialize` on a raw `ChVmInfoRaw` with `#[serde(default)]` on every field (nested `config.cpus.boot_vcpus` / `config.memory.size`) and convert to `ChVmInfo` | [packages/d2bd-runtime/src/ch_api.rs:79] | actionable | lane/d2bd-runtime-p4.md - -**`xtask`** - -- `RS-0580` | medium | `xtask` | `service_catalog.rs`'s `DeclarationFile` parses the committed per-crate `service-catalog.json` with `#[derive(Deserialize)]` and no `deny_unknown_fields`, while the sibling `RegistrationDeclaration` parsing `registrations.json` denies unknowns (`provider_registration_authority.rs:54`); a typo'd key in a declaration (e.g. `providerUid` misspelled) is silently ignored and the daemon's fixed-UID row silently disappears instead of failing the gate | fix: add `#[serde(deny_unknown_fields)]` to `DeclarationFile` | [packages/xtask/src/service_catalog.rs:22, packages/xtask/src/provider_registration_authority.rs:54] | actionable | lane/xtask-p1.md -- `RS-0582` | low | `xtask` | `SnapshotView` (mod.rs:46-47) lacks `#[serde(deny_unknown_fields)]` while every nested wire type in the same artifact (CandidateMaterial, RepositoryRecord, Fingerprint, DependencyEdge, digest newtypes) denies, so a hand-edited snapshot can carry silently-ignored top-level keys | fix: add `#[serde(deny_unknown_fields)]` to SnapshotView; the `schema_version` gate already handles version drift,so there is no forward-compat cost | [packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111] | actionable | lane/xtask-p4.md -- `RS-0581` | low | `xtask` | `DeclarationFile` and `TypeDeclaration` use per-field `#[serde(rename = ...)]` for their camelCase wire keys while the sibling `RoleDeclaration` in the same file uses `#[serde(rename_all = "camelCase")]`, splitting the boundary-naming convention within one file | fix: add `#[serde(rename_all = "camelCase")]` to `DeclarationFile` and `TypeDeclaration` and delete the two per-field renames | [packages/xtask/src/resource_type_authority.rs:179, packages/xtask/src/resource_type_authority.rs:182, packages/xtask/src/resource_type_authority.rs:190, packages/xtask/src/resource_type_authority.rs:192] | actionable | lane/xtask-p3.md - -### `obs` - -Observability: structured named-field events, tracing over println, spans, error chains logged once, no secret in fields. - -**`d2b-broker`** - -- `RS-0583` | low | `d2b-broker` | `retry_acl_grant` interpolates its `label` into the message instead of a named field: `tracing::debug!(error = %err, "{label} ACL refresh not ready yet")` and `tracing::warn!("{label} ACL refresh timed out")`, with no enclosing span carrying it, so the refresh kind is not queryable | fix: emit `label = %label` as a field and keep the message interpolation-free | [packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:2539] | actionable | lane/d2b-broker-p3.md - -**`d2b-core`** - -- `RS-0584` | medium | `d2b-core` | verify_bundle_hash emits a backward-compatibility warning via `eprintln!` in library code, and d2b-core has no tracing/log channel at all, so the "bundleHash missing, skipping self-hash check" warning never reaches the daemon's structured logs and operators cannot see that hash verification was skipped | fix: add `tracing` (already the workspace-wide logging dependency in sibling crates) and emit `tracing::warn!(path = %path.display(), "bundle artifact has no bundleHash field; skipping self-hash check")`, or route the warning through the crate's audit/error path | [packages/d2b-core/src/bundle_resolver.rs:1097] | actionable | lane/d2b-core-p1.md - -**`d2b-provider-activation-nixos`** - -- `RS-0585` | low | `d2b-provider-activation-nixos` | nine `tracing::warn!` refusal events in `ActivationTrust::verify` are message-only with no named fields and no enclosing span (no `#[instrument]` anywhere in the crate), so the failing fence is queryable only as message text | fix: add a named field carrying the error variant (e.g. `refusal = ?ActivationVerificationError::TrustEpochMismatch`), keeping fields identifier-free so the site stays under the ADR 0010/0028 redaction gate | [packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activation-nixos/src/controller.rs:575, packages/d2b-provider-activation-nixos/src/controller.rs:581, packages/d2b-provider-activation-nixos/src/controller.rs:587] | actionable | lane/d2b-provider-activation-nixos.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0586` | medium | `d2b-provider-clipboard-wayland` | the binary logs through the log facade with interpolated message strings (62 sites) while the crate's lib uses tracing with named fields, giving one crate two facades and unqueryable events | fix: migrate d2b-clipd.rs to tracing (already a dependency, used by runtime.rs) with named fields, e.g. log::info!("d2b-clipd: ready (config={}, ...)") becomes tracing::info!(config = %args.config.display(), bridge_root = %args.bridge_root.display(), "d2b-clipd ready") | [src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0587` | low | `d2b-provider-clipboard-wayland` | clipd_host log events use interpolated messages instead of named fields (attribution, mime count, secret flag, error values are formatted into the message), so the events are not queryable by field | fix: convert to structured fields, e.g. log::debug!(quality = ?attribution.quality, mimes = allowed_mimes.len(), secret = has_secret, "host selection changed") | [packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:489, packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs:24, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:60] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-credential-secret-service`** - -- `RS-0588` | medium | `d2b-provider-credential-secret-service` | session-close failure warn is message-only with no named fields, so a fleet cannot filter which provider/session close left unresolved leases | fix: add `provider = crate::PROVIDER_REF` and the two booleans (`unresolved_leases`, `unresolved_operations`)as fields to the `tracing::warn!` | [packages/d2b-provider-credential-secret-service/src/service.rs:860] | actionable | lane/d2b-provider-credential-secret-service.md - -**`d2b-provider-guest-azure-virtual-machine`** - -- `RS-0589` | low | `d2b-provider-guest-azure-virtual-machine` | the literal `provider = "runtime-azure-virtual-machine"` field is repeated on all 27 events and the `resource_group` field renders `OpaqueAzureRef()` via `Display` (d2b-contracts/src/foundation_effects.rs:181-184), so events that log only resource_group carry no correlation value | fix: add a `#[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))]` span on the controller entry points (reconcile, adopt, poll_operation, update, finalize) and drop the per-event literal; log zone/resource where available instead of the redacted resource_group | [src/controller/mod.rs:346, src/controller/mod.rs:425] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0590` | low | `d2b-provider-guest-qemu-media` | All 21 tracing events repeat the same two context fields (`resource = %self.guest_ref`, `provider = "runtime-qemu-media"`(inline ( ~20 sites in reconcile.rs + qmp/mod.rs:233); a span per reconcile/finalize would carry them once | fix: `#[tracing::instrument(skip(self, effect))]` on `QemuMediaController::reconcile`/`finalize` (or an explicit enter/exit span (dropping the duplicated pairs from the per-event fields | [packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:352, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:380, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:605, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:233] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-process-systemd`** - -- `RS-0591` | low | `d2b-provider-process-systemd` | the `debug!` event on the cancelled-ticket path evaluates `ticket.process_ref().to_canonical_string()` eagerly, allocating the canonical string even when debug is disabled | fix: pass a reference and let the macro format lazily (`resource = %ticket.process_ref()` if Display exists, else `?ticket.process_ref()`), reserving the eager `to_canonical_string()` for the warn/error paths | [packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-systemd/src/lib.rs:141] | actionable | lane/d2b-provider-process-systemd.md - -**`d2b-provider-test-controller`** - -- `RS-0592` | medium | `d2b-provider-test-controller` | the bin emits `tracing` events with structured `reason = %e` fields but never installs a subscriber (main() at main.rs:33-47; Cargo.toml has `tracing` but no tracing-subscriber), so every debug/warn/error event is dropped and the only operator-visible diagnostics are the unstructured `eprintln!` retry lines at main.rs:68/95/99/111/125 - one failure class reported through two channels, one of which is dead | fix: install a subscriber once at process start (e.g. `tracing_subscriber::fmt::init()`), or convert the tracing sites to eprintln | [packages/d2b-provider-test-controller/src/main.rs:33-47, packages/d2b-provider-test-controller/src/main.rs:68] | actionable | lane/tail-5.md -- `RS-0593` | low | `d2b-provider-test-controller` | message-only warn events drop their context: the keepalive error is discarded via `.is_err()` and logged as a bare message, and the unexpected named stream's id is unnamed | fix: bind the error (`warn!(reason = %e, ...)`) and name the stream (`warn!(stream = ?stream, ...)`) | [packages/d2b-provider-test-controller/src/main.rs:164, packages/d2b-provider-test-controller/src/main.rs:173-174] | actionable | lane/tail-5.md - -**`d2b-provider-toolkit`** - -- `RS-0594` | low | `d2b-provider-toolkit` | `serve_enrolled` drops a base-side wire-contract violation with no event: a frame that fails `GuestFrame::new` (empty or oversized, i.e. a peer protocol violation, not an agent refusal) is `continue`d silently, and the module doc only covers agent refusals as "the agent's to record", so the malformed frame is invisible to the operator | fix: emit a `warn!` with the frame length before dropping, keeping the session up | [packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src/base/guest.rs:446-452] | actionable | lane/d2b-provider-toolkit-p1.md -- `RS-0595` | low | `d2b-provider-toolkit` | three message-only `warn!` events in the authenticated session loop carry no named fields even though zone/provider/method are in scope at each site, so the events are not queryable per provider | fix: add fields, e.g. `warn!(zone = ?session.route_binding().zone(), "component session receive failed; closing provider session")` and the analogous provider/method fields at the readiness and loop-failure sites | [packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src/server/session.rs:255, packages/d2b-provider-toolkit/src/server/session.rs:262] | actionable | lane/d2b-provider-toolkit-p2.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0596` | low | `d2b-provider-transport-azure-relay` | five `tracing::warn!` events at the credential-port boundary are message-only (guest_credential.rs:406, 423, 476, 483 - and 438 carries `active_leases` but no role), while sibling events in the same crate carry `role = ?role`, `binding = ?binding`, `reason = %error`; a lease-acquire rejection or revoke mismatch is not attributable to a role or lease without those fields | fix: add `role = ?role` (and `lease_id` where available) to those events so the crate's event schema is uniform | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:423-425, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:476-478, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:483-485] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-transport-unix`** - -- `RS-0597` | low | `d2b-provider-transport-unix` | four message-only `tracing::warn!` events drop the underlying errno (`map_err(|_|)` then warn with only the `provider` field): peer-credential bind failure, monitor-fd duplication, observation poll, and entropy-source failures | fix: capture the errno as `reason = %e` like the admission-rejection site at portal.rs:209-212 already does | [packages/d2b-provider-transport-unix/src/portal.rs:217-220, packages/d2b-provider-transport-unix/src/portal.rs:244-247, packages/d2b-provider-transport-unix/src/portal.rs:301-304, packages/d2b-provider-transport-unix/src/portal.rs:348-351] | actionable | lane/tail-5.md - -**`d2b-provider-transport-vsock`** - -- `RS-0598` | low | `d2b-provider-transport-vsock` | the 9 transport-open rejection warn events log `endpoint`/`binding` fields whose `Display` impls are constants ("opaque-endpoint"/"opaque-binding"), so the named fields cannot correlate any event to a specific transport - an operator debugging repeated opens sees identical values every time. | fix: drop the `endpoint`/`binding` fields from the open-reject warn events, or give `OpaqueEndpointId`/`OpaqueBindingId` a real `Display` over `self.0` while keeping `Debug` redacted | [packages/d2b-provider-transport-vsock/src/service.rs:392, packages/d2b-provider-transport-vsock/src/service.rs:466, packages/d2b-provider-transport-vsock/src/service.rs:65-67, packages/d2b-provider-transport-vsock/src/service.rs:99-101] | actionable | lane/d2b-provider-transport-vsock.md -- `RS-0599` | low | `d2b-provider-transport-vsock` | bridge-drop,and bridge-copy-failure debug events carry no transport identity (no handle, endpoint, or binding field), so with up to `MAX_ACTIVE_TRANSPORTS` concurrent transports an operator cannot tell which one dropped an event or failed a copy - thread a handle/endpoint identity into the open path's spawned bridge task and through `emit_event`. | fix: capture `endpoint_id`/`binding_id` into the `tokio::spawn` block in `open_transport` and pass them to `emit_event`, adding named fields to the three drop events and the `run_bridge` copy-failure site | [packages/d2b-provider-transport-vsock/src/service.rs:735, packages/d2b-provider-transport-vsock/src/service.rs:766, packages/d2b-provider-transport-vsock/src/service.rs:851, packages/d2b-provider-transport-vsock/src/bridge.rs:186] | actionable | lane/d2b-provider-transport-vsock.md - -**`d2b-resource-api`** - -- `RS-0600` | low | `d2b-resource-api` | `parse_create_payload` writes an unstructured `eprintln!` to daemon stderr on every failed create-envelope validation, bypassing the tracing pipeline (no level, no filter, no named fields) from a library crate | fix: replace with `tracing::debug!(error = %error, "create envelope validation failed")` (the failure is already returned to the caller as `ResourceSchemaInvalid`) | [service.rs:1992] | actionable | lane/d2b-resource-api-p1.md - -**`d2b-unsafe-local-helper`** - -- `RS-0601` | low | `d2b-unsafe-local-helper` | the operation-worker failure path logs `unsafe-local launch failed: {error:?}` (protocol.rs:188) with no request_id or operation_id, so a background launch failure cannot be correlated to the request that caused it and carries no stage context | fix: include request_id and operation_id (both in scope at protocol.rs:183-189) in the message or as fields | [packages/d2b-unsafe-local-helper/src/protocol.rs:188] | actionable | lane/d2b-unsafe-local-helper.md - -**`d2bd`** - -- `RS-0605` | medium | `d2bd` | the daemon's accept loop reports runtime errors with `eprintln!` (authorization refusal at 4099/4132, connection-handler failure at 4081/4132-ish, spawn failure at 4138) while the rest of the crate uses tracing and main.rs:146-152 installs a `tracing_subscriber`, so these error events bypass level filtering, structured fields, and the redaction gates; the daemon's stderr goes to the journal as unstructured prose | fix: replace the four `eprintln!` calls with `tracing::error!` events carrying named fields (`error = %error.message()`, `peer_uid`) | [packages/d2bd/src/composition.rs:4081, packages/d2bd/src/composition.rs:4099, packages/d2bd/src/composition.rs:4132, packages/d2bd/src/composition.rs:4138] | actionable | lane/d2bd-p4.md -- `RS-0606` | low | `d2bd` | three lifecycle `tracing::info!` events are message-only with no named fields ("Guest-local ZoneLink transport Provider composed", "Guest target-control service composed", "autostart: nothing to do (empty plan)") and no enclosing span exists (0 `#[instrument]` hits in the lane), so the events cannot be filtered by zone/vm | fix: add named fields (`zone`, `guest_ref`, or `vm`) to the three events, or wrap them in instrumented callers | [packages/d2bd/src/composition.rs:4487, packages/d2bd/src/composition.rs:4538, packages/d2bd/src/composition.rs:5300] | actionable | lane/d2bd-p4.md -- `RS-0607` | low | `d2bd` | `publish_trusted_context`'s failure arm interpolates the error into the message (`"trusted-context publication refused: {error}"`) while the sibling `Ok(_)` arm and every other event in the file carry named fields, so the failure reason is not queryable as a column | fix: move the error into a field (`error = %error, "trusted-context publication refused"`), matching the adjacent arms and the plane's other warn sites | [packages/d2bd/src/provider_lifecycle.rs:1085] | actionable | lane/d2bd-p6.md -- `RS-0602` | low | `d2bd` | eighteen message-only `tracing::warn!` events carry no named fields and the file has no spans at all (`\.instrument\(|#\[instrument` = 0), so the events lose the underlying error: most are inside `map_err` closures that drop the error (2024, 2419, 4846, 5283), and 7169 discards the in-scope `context` (provider/process) when a controller assignment refresh retries | fix: capture the error and log it as a named field (`error = ?...`) in the `map_err` closures, and add `provider`/`process` fields at 7169 | [packages/d2bd/src/resource_runtime.rs:2024, packages/d2bd/src/resource_runtime.rs:2419, packages/d2bd/src/resource_runtime.rs:4846, packages/d2bd/src/resource_runtime.rs:5283] | actionable | lane/d2bd-p1.md -- `RS-0603` | low | `d2bd` | `tracing::error!("Gateway Guest composition refused: root Zone generation unavailable")` is message-only although `topology.root` is in scope | fix: add `zone = %topology.root` (and the generation value if available) so the refusal is queryable per zone | [packages/d2bd/src/composition.rs:14781] | actionable | lane/d2bd-p2.md -- `RS-0604` | low | `d2bd` | two identical message-only `tracing::warn!("resource plane still has live request owners during shutdown")` events in the two LiveRequestOwners branches of shutdown_resource_plane carry no fields, so the operator cannot tell which zones are stuck | fix: add `zones = ?zones` (or a count) to both events | [packages/d2bd/src/composition.rs:15195, packages/d2bd/src/composition.rs:15221] | actionable | lane/d2bd-p2.md -- `RS-0608` | low | `d2bd` | message-only `tracing::warn!("forward rendezvous is at its in-flight cap; refusing the call")` carries no fields and sits in a loop with no enclosing span, so the cap refusal cannot be attributed to a caller or the cap value | fix: add a field (`peer_uid`, `max = posture.max_inflight`) | [packages/d2bd/src/forward_rendezvous.rs:1250] | actionable | lane/d2bd-p8.md - -**`d2bd-runtime`** - -- `RS-0609` | low | `d2bd-runtime` | `write_daemon_version_file` (runtime_process.rs:446-486) reports its five failure paths with `eprintln!` from a library module instead of `tracing`, bypassing level/filter/structure | fix: route them through `tracing::warn!`/`tracing::error!` with the path/context as named fields (module already uses tracing in the sd_notify fns) | [runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs:480] | actionable | lane/d2bd-runtime-p2.md -- `RS-0610` | low | `d2bd-runtime` | event fields allocate eagerly even when the level is filtered: `mode = format!("{mode:o}")` inside a `tracing::debug!` (ssh_host_key_preflight.rs:305, hot on every key entry) and a pre-joined `subjects` string built before a `tracing::warn!` (resource_runtime_support.rs:679-680) | fix: use `tracing::field::debug(format_args!("{mode:o}"))` for the octal mode and `tracing::field::display(subjects.iter().map)...).collect::>().join(","))` (or an `Empty`-then-record) so nothing is formatted when the event is disabled | [ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680] | actionable | lane/d2bd-runtime-p2.md -- `RS-0611` | low | `d2bd-runtime` | the one-shot-exit unparseable-stat warning is message-only with no named fields (`tracing::warn!("wait_for_one_shot_exit: /proc//stat unparseable; ...")`), though `pid` and a `path` string are in scope and sibling warnings carry `%err`/field-style context | fix: emit fields (`pid = %pid`, `path = %path`) with a short message (or wrap the poll loop in a span carrying `pid`) | [packages/d2bd-runtime/src/readiness.rs:327] | actionable | lane/d2bd-runtime-p3.md -- `RS-0612` | low | `d2bd-runtime` | pidfs probe warns/errors interpolate a prebuilt `{msg}` string with embedded `st_dev`/`detail` values instead of named fields, while the sibling `PidfsAvailable` arm already emits `pidfs_st_dev`/`pidfs_st_ino` fields | fix: give `PidfsNotPresent` and `UnexpectedError` arms named `pidfs_st_dev = %st_dev` / `detail = %detail` fields (and keep the long operator-facing sentence as the message template) | [packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132, packages/d2bd-runtime/src/pidfs_probe.rs:144, packages/d2bd-runtime/src/pidfs_probe.rs:147] | actionable | lane/d2bd-runtime-p3.md -- `RS-0613` | low | `d2bd-runtime` | `tracing::warn!("qemu console: failed to convert fd to tokio stream: {e}")` interpolates the error into the message instead of a named field, so the event is not queryable by error | fix: `tracing::warn!(error = %e, "qemu console: failed to convert fd to tokio stream")` | [packages/d2bd-runtime/src/console_session.rs:450] | actionable | lane/d2bd-runtime-p4.md - -### `docs` - -Docs as contract: first-sentence shape, module docs, canonical sections (# Examples/# Errors/# Panics/# Safety), doctests that run. - -**`d2b`** - -- `RS-0659` | low | `d2b` | six `pub fn` response expecters (`expect_start`, `expect_detached_create/list/logs/status/kill`) carry no doc comment in an otherwise fully documented module | fix: one-line docs stating the expected `ExecOpResponse` variant and the protocol error on mismatch | [packages/d2b/src/exec_client.rs:497, packages/d2b/src/exec_client.rs:507, packages/d2b/src/exec_client.rs:519, packages/d2b/src/exec_client.rs:531] | actionable | lane/d2b-p3.md -- `RS-0658` | low | `d2b` | several pub items carry no doc comment and lib.rs has no crate-level `//!` doc | fix: add one-line first-sentence docs to `DoctorReport`, `run_doctor`, `render_summary`, `render_human` (doctor.rs), `ValidateReport`, `ValidateMode`, `exit_code` (host_validate.rs), `cli_command`, `run` (lib.rs), and a `//!` crate doc in lib.rs | [packages/d2b/src/doctor.rs:91, packages/d2b/src/doctor.rs:163, packages/d2b/src/host_validate.rs:229, packages/d2b/src/host_validate.rs:237] | actionable | lane/d2b-p2.md - -**`d2b-audit`** - -- `RS-0614` | low | `d2b-audit` | no canonical `# Errors`/`# Examples` sections exist anywhere in the crate although ~50 `-> Result<` sites include the public API (export_segments_range, AuditRecord::new/verify/zone_operation_key, evidence_from_decision_result, AuditSink::open/append/prune_old, SegmentWriter::open/append, OperationIdentity::derive/parse); failure conditions are described in prose but not under the section a caller scans for | fix: add `# Errors` sections naming the AuditRecordError/AuditSinkError/EvidenceError variants on the Result-returning pub items and `# Examples` on the non-obvious constructors (AuditRecord::new, SegmentWriter::open) | [packages/d2b-audit/src/export.rs:74, packages/d2b-audit/src/record_types.rs:428, packages/d2b-audit/src/reconcile.rs:54, packages/d2b-audit/src/sink.rs:175] | actionable | lane/d2b-audit.md - -**`d2b-broker`** - -- `RS-0624` | medium | `d2b-broker` | the public fd-ownership API in fd_passing.rs is undocumented: `FdPassingError` (13), `FdRegistry::register`/`clear` (37, 41), and the whole `FdLease` surface (`new`/`raw`/`release`, 55-70) have no doc comments even though the load-bearing contract is non-obvious - `FdLease` closes the fd on drop and `release()` disarms that close, which is exactly what ADR 0034 fd-transfer callers must know | fix: add one-line docs to each item stating ownership (who closes, what `release` disarms) and the `recv_*`/`send_fds` error variants | [packages/d2b-broker/src/fd_passing.rs:13, packages/d2b-broker/src/fd_passing.rs:31-70] | actionable | lane/d2b-broker-p5.md -- `RS-0630` | medium | `d2b-broker` | media.rs's public ops surface carries no doc comments | fix: add doc blocks to each: MediaOpError variants, the four outcome structs (esp. BootOutcome's four booleans),and the pub ops fns (`enroll`/`refresh_registry`/`boot`/`system_powerdown`/`query_status`/`quit`/`attach`/`detach`),covering preconditions, outcome semantics,and `# Errors` on the `Result` fns | [packages/d2b-broker/src/ops/media.rs:35, packages/d2b-broker/src/ops/media.rs:167-186, packages/d2b-broker/src/ops/media.rs:188, packages/d2b-broker/src/ops/media.rs:238] | actionable | lane/d2b-broker-p7.md -- `RS-0625` | medium | `d2b-broker` | pub syscall wrappers `peer_credentials` (121) and `tun_set_persist`/`tun_set_owner`/`tun_set_group` (185, 195, 210) carry no doc comments while their twins `peer_uid` and `tun_create_tap_fd` do; the contracts are non-obvious (peer uid/gid/pid triple semantics; TUNSETPERSIST/OWNER/GROUP ioctl semantics and the ifname binding) | fix: add one-line docs plus the `# Errors` conditions (ioctl failure, uid/gid out of `c_int` range) | [packages/d2b-broker/src/sys.rs:120-121, packages/d2b-broker/src/sys.rs:185, packages/d2b-broker/src/sys.rs:195, packages/d2b-broker/src/sys.rs:210] | actionable | lane/d2b-broker-p5.md -- `RS-0631` | medium | `d2b-broker` | protocol.rs's framing surface (cap const + sync framing fns)carries no docs although it is the broker wire contract | fix: doc `MAX_FRAME_SIZE` and the six framing fns (length-prefix format, cap enforcement, `Option::None` on empty socket, fd-ancillary semantics), mirroring the async wrappers' existing docs | [packages/d2b-broker/src/protocol.rs:13, packages/d2b-broker/src/protocol.rs:16, packages/d2b-broker/src/protocol.rs:29, packages/d2b-broker/src/protocol.rs:43] | actionable | lane/d2b-broker-p7.md -- `RS-0632` | medium | `d2b-broker` | state_dir.rs publishes nine undocmented pub items (types + fns)with no `# Errors` on the `io::Result` fns | fix: add item-level doc contracts to `DirKind`, `PrepareDirRequest`, `PrepareDirAudit`, `ReplaceOrCreateResult`, `prepare_dir`, `live_prepare_runtime_dir`, `PreparedStateDir`, `live_prepare_state_dir` (and `# Errors` where Result) | [packages/d2b-broker/src/ops/state_dir.rs:47, packages/d2b-broker/src/ops/state_dir.rs:53, packages/d2b-broker/src/ops/state_dir.rs:70, packages/d2b-broker/src/ops/state_dir.rs:83] | actionable | lane/d2b-broker-p7.md -- `RS-0621` | medium | `d2b-broker` | audit.rs public surface gaps:`AuditEntry` (legacy JSONL record shape consumed by the socket-acl gate), `AuditDropSummary`, `AuditLog::open` (the daemon entry point with bootstrap/poison barrier semantics), and `audit_drop_summary` carry no doc comment, while every sibling method around them is documented | fix: add `///` first-sentence contracts (state what `disposition` vs `outcome` mean, what counters `AuditDropSummary` merges, what `open`'s barrier requires of callers) | [packages/d2b-broker/src/audit.rs:124, packages/d2b-broker/src/audit.rs:84, packages/d2b-broker/src/audit.rs:416, packages/d2b-broker/src/audit.rs:1029] | actionable | lane/d2b-broker-p4.md -- `RS-0616` | medium | `d2b-broker` | the broker's central runtime module has no //! module doc,and its five process-entry public items (ServerConfig, BrokerMode, RunError, parse_command, run)lack any doc comment, even though they form the public API the composition binary (d2b-broker-composition/src/main.rs:3, 47-60)and integration tests (tests/profile_separation.rs:1, 22-33)match on | fix: add a one-line module doc atop runtime.rs(serve/socket/audit contract)and one-line first-sentence doc comments to ServerConfig, BrokerMode, RunError, with # Errors on run/parse_command, which return Result),keeping the comments caller-contracts, not implementation narration | [packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b-broker/src/runtime.rs:375, packages/d2b-broker/src/runtime.rs:398] | actionable | lane/d2b-broker-p2.md -- `RS-0622` | medium | `d2b-broker` | `HandoffOperationError` (pub enum returned from every pub handoff fn) has no top-level doc comment; the failure modes (`JournalMismatch`, `HelperUnavailable`, `ArtifactValidationOutputInvalid`, ...) have descriptive names but no contract sentence says what callers should do per variant | fix: add a `///` doc line listing the variant classes (journal replay vs helper/validation failures) | [packages/d2b-broker/src/ops/host_generation_handoff.rs:35] | actionable | lane/d2b-broker-p4.md -- `RS-0623` | medium | `d2b-broker` | `ApplyWithPreflightError` (pub enum returned from the pub `apply_with_preflight_owned` entry point) has no top-level doc (only one variant carries an inline `///`); callers get no contract sentence distinguishing query failures from foreign-route refusal from reconcile failures | fix: add a one-line enum doc naming what each variant class means (route query vs ownership refusal vs executor failure) | [packages/d2b-broker/src/ops/route.rs:29] | actionable | lane/d2b-broker-p4.md -- `RS-0615` | low | `d2b-broker` | the four Result-returning public fns in ops/usbip_lock.rs (`ensure_lock_root`, `acquire_lock`, `release_lock`, `peek_owner`) document failure conditions only in prose and carry no `# Errors` canonical section, which the docs contract wants on every Result-returning item | fix: add `# Errors` sections naming the returned variants (LockAlreadyHeld, OwnerMismatch, Io) | [packages/d2b-broker/src/ops/usbip_lock.rs:81, packages/d2b-broker/src/ops/usbip_lock.rs:90, packages/d2b-broker/src/ops/usbip_lock.rs:171, packages/d2b-broker/src/ops/usbip_lock.rs:316] | actionable | lane/d2b-broker-p1.md -- `RS-0617` | low | `d2b-broker` | pub types `UsbipHostInspectionError` (usbip_host.rs:17), `UsbipDriverBinding` (153) and `UsbipHostDeviceInspection` (160) carry no doc comment at all on a crate with a lib target | fix: add one-line docs (and field docs for the inspection struct) | [packages/d2b-broker/src/ops/usbip_host.rs:17, packages/d2b-broker/src/ops/usbip_host.rs:153, packages/d2b-broker/src/ops/usbip_host.rs:160] | actionable | lane/d2b-broker-p3.md -- `RS-0626` | low | `d2b-broker` | the `path_safe` module's pub helpers (`refuse_symlink`, `refuse_world_writable_parent`, `refuse_non_root_parent`, `read_to_string_nofollow`, `write_nofollow`, `remove_nofollow`, `ensure_dir`, `ensure_dir_preserve_existing`) lack per-item doc comments; the contract lives only in the module-level doc, so rustdoc item pages are empty and the reader must open the module header for each helper's safety rule | fix: promote each module-doc bullet to a one-line `///` on its item (or add `#[doc = "..."]` links), keeping the module doc as the index | [packages/d2b-broker/src/sys.rs:258, packages/d2b-broker/src/sys.rs:268, packages/d2b-broker/src/sys.rs:329, packages/d2b-broker/src/sys.rs:398] | actionable | lane/d2b-broker-p5.md -- `RS-0618` | low | `d2b-broker` | pub types `ApplySysctlOutcome` (sysctl.rs:32), `ApplySysctlError` (40) and `ApplyWithReadbackError` (113) and the pub method `with_default_root` (23) are undocumented | fix: add one-line docs per item | [packages/d2b-broker/src/ops/sysctl.rs:32, packages/d2b-broker/src/ops/sysctl.rs:40, packages/d2b-broker/src/ops/sysctl.rs:113] | actionable | lane/d2b-broker-p3.md -- `RS-0619` | low | `d2b-broker` | pub enum `StorageContractError` (storage_contract.rs:21) has no doc comment | fix: one-line doc naming the refusal/invalid/Io contract | [packages/d2b-broker/src/ops/storage_contract.rs:21] | actionable | lane/d2b-broker-p3.md -- `RS-0620` | low | `d2b-broker` | pub methods `PidfdMethod::as_str` (pidfd.rs:112), `StartTime::matches` (127), `RealPidfdSpawner::new` (191) and `AuditDecision::as_str` (ops/mod.rs:164) are undocumented | fix: one-line docs per method | [packages/d2b-broker/src/ops/pidfd.rs:112, packages/d2b-broker/src/ops/pidfd.rs:191, packages/d2b-broker/src/ops/mod.rs:164] | actionable | lane/d2b-broker-p3.md -- `RS-0627` | low | `d2b-broker` | the two `pub async fn` store-view farm entrypoints carry the same design-journal sentence "Async form used by the async exec_reconcile and store_sync paths; the sync form was removed with its last sync caller" with a typo (missing space after `paths.`), stating history ("was removed") instead of a contract. | fix: trim to a one-line contract ("Async counterpart used by the async exec_reconcile/store_sync callers.") at both sites, and add `# Errors`-style failure notes where the error enum is non-obvious. | [src/ops/store_view_farm.rs:66-72, src/ops/store_view_farm.rs:191-197] | actionable | lane/d2b-broker-p6.md -- `RS-0628` | low | `d2b-broker` | BrokerEnvelope::call, call_with_fds,and call_nested_with_fds return `Result<_, EnvelopeRefusal>` with no `# Errors` section, so failure modes (14 closed refusal-code consts, e.g. subscriber-only, scope refusals, budget refusals) must be chased around the file to be known. | fix: add an `# Errors` block to each of the three pub methods naming the closed `EnvelopeRefusal` vocabulary and pointing at the refusal constants. | [src/envelope/mod.rs:1118, src/envelope/mod.rs:1136, src/envelope/mod.rs:1187] | actionable | lane/d2b-broker-p6.md -- `RS-0629` | low | `d2b-broker` | apply_with_reload/remove_with_reload doc prose narrates design history ("The dispatcher now lands on ops::nm even though the live path is still a thin wrapper... future coexistence/reload-verification work"), which rots and reads as rendered journal prose on a public item. | fix: rewrite the doc as a plain two-sentence contract (what it does, when reload verification kicks in),and move the rationale to the module doc if it must be preserved. | [src/ops/nm.rs:293-301, src/ops/nm.rs:303-308] | actionable | lane/d2b-broker-p6.md - -**`d2b-bus`** - -- `RS-0633` | medium | `d2b-bus` | The exported observer contract BusEvent, BusFailureReason, BusObserver, and NoopBusObserver carry no doc comments, so the semantics of the 17 failure reasons and when record fires are undocumented for the d2bd consumer | fix: add module-level or item docs stating when each event is recorded and what each BusFailureReason variant means | [packages/d2b-bus/src/router.rs:1126, packages/d2b-bus/src/router.rs:1135, packages/d2b-bus/src/router.rs:1187, packages/d2b-bus/src/router.rs:1192] | actionable | lane/d2b-bus-p1.md -- `RS-0637` | medium | `d2b-bus` | `pub struct Cancellation` (re-exported at the crate root) has no doc comment while every sibling public item does, leaving the opaque token's contract (crate-private construction, one-attempt observation, `is_cancelled`) undocumented | fix: add a `///` doc comment stating the token is minted only by the bus and observes one operation attempt | [packages/d2b-bus/src/operations.rs:124-125] | actionable | lane/d2b-bus-p2.md -- `RS-0634` | low | `d2b-bus` | DEFAULT_MAX_ROUTES_PER_SESSION and DEFAULT_MAX_TOTAL_ROUTES are pub consts without docs while their sibling DEFAULT_MAX_PAYLOAD_BYTES has one | fix: add one-line docs naming the bound each constant sets | [packages/d2b-bus/src/router.rs:67-68] | actionable | lane/d2b-bus-p1.md -- `RS-0635` | low | `d2b-bus` | CommittedInteractionSubjectInstallBody (consumed by d2bd), AuthorizationErrorClass, EndpointSessionFailure::class/code/remediation, and the metrics label accessors are pub items without doc comments | fix: add one-line docs to each, at least on the struct and the class enum | [packages/d2b-bus/src/router.rs:1895, packages/d2b-bus/src/authorization.rs:401, packages/d2b-bus/src/registry.rs:259-267, packages/d2b-bus/src/metrics.rs:110] | actionable | lane/d2b-bus-p1.md -- `RS-0636` | low | `d2b-bus` | No pub Result-returning item carries a canonical # Errors section anywhere in the partition (94 Result-returning pub items, zero sections), so the failure conditions of non-obvious APIs such as BusIngress::invoke and ZoneRegistrar::register_component_session are undocumented | fix: add # Errors sections to the non-obvious Result-returning pub items, starting with the bus entry points | [packages/d2b-bus/src/router.rs:3709, packages/d2b-bus/src/router.rs:3261, packages/d2b-bus/src/registry.rs:366] | actionable | lane/d2b-bus-p1.md -- `RS-0638` | low | `d2b-bus` | public `Result`-returning constructors and accessors (`StreamName::parse`, `OperationId::parse`, `ZoneBoundPolicyIdentity::digest`, `ZoneEndpointPolicy::lower`) carry no `# Errors` section naming which condition produces which failure, even though the failure conditions are closed and enumerated in the error enums | fix: add `# Errors` sections to the public parse/lower/digest items | [packages/d2b-bus/src/streams.rs:39-40, packages/d2b-bus/src/operations.rs:24-25, packages/d2b-bus/src/wire.rs:79-82, packages/d2b-bus/src/session/contract.rs:164-165] | actionable | lane/d2b-bus-p2.md - -**`d2b-contracts-broker`** - -- `RS-0639` | medium | `d2b-contracts-broker` | every Result-returning public fn lacks the canonical `# Errors` section (seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits crate-wide), so the failure conditions of the handoff state machine, the launch-args bounds, and the kernel client are only recoverable from enum docs | fix: add `# Errors` sections naming the `HandoffError`/`RunnerLaunchArgsError`/`KernelInvokeError` conditions to `SourceGenerationCompatibilityFloorV1::new`, `begin_handoff`, the `HandoffCoordinator` transitions, `RunnerLaunchArgs::new`, and `envelope_invoke_kernel` | [packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src/kernel_client.rs:113, packages/d2b-contracts-broker/src/broker_wire.rs:2495] | actionable | lane/d2b-contracts-broker.md -- `RS-0640` | low | `d2b-contracts-broker` | doc-comment polish defects in the FdKind/ForwardOperationRequest contract docs: `present.from` (missing space), CJK full-width periods (the FdKind variant docs end in a CJK period), and comma-adjacent spacing (`positions,in the ... list,of`) | fix: reword those doc lines | [packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/broker_wire.rs:254, packages/d2b-contracts-broker/src/broker_wire.rs:421-430] | actionable | lane/d2b-contracts-broker.md - -**`d2b-contracts-control`** - -- `RS-0641` | medium | `d2b-contracts-control` | cli_output.rs exports 20+ CLI-output DTOs (ListOutputV2, ListItemOutputV2, UsbProbeOutputV1, RealmListOutputV1, RealmInspectOutputV1, OpInspect*, RealmPolicyOutputV1, StatusOutputV2, StatusInventoryOutputV2, ApiReady*, StatusVmOutputV2, LivePoolIntegrityOutputV1, StatusServicesOutputV2, RunnerParityOutputV2, StatusBridgeCheckOutputV2, Audit*OutputV2, Auth*OutputV2) with no doc comments; only StatusServicesOutputV3 and two fields document anything | fix: add one-line doc comments naming the wire shape each DTO renders | [cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130] | actionable | lane/d2b-contracts-control.md -- `RS-0642` | medium | `d2b-contracts-control` | public_wire.rs request/response structs and fields are undocumented where the wire semantics are non-obvious (ListRequest, StatusRequest, AuditRequest, AuditSelector, ListEntry, VmStatus, PublicVmServices, BridgeCheck, VmLifecycle, RuntimeSummary, VmAutostartPosture, QemuMedia*, ShellName, ShellNameError, WorkloadListArgs, UsbipProbeEntry field meanings), and `-> Result<` items (ShellName::new, RealmAccentColor::new) carry no `# Errors` section | fix: add doc comments with `# Errors` on the Result-returning constructors | [public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495] | actionable | lane/d2b-contracts-control.md -- `RS-0643` | medium | `d2b-contracts-control` | unsafe_local_wire.rs exposes undocumented pub constants with unexplained magic values (MAX_HELPER_QUEUE_DEPTH=128, MAX_HELPER_SNAPSHOT_SCOPES=1024, MAX_COMPLETED_OPERATIONS_PER_UID=1024, MAX_COMPLETED_OPERATION_AGE_SECS=24*60*60, UNSAFE_LOCAL_HELPER_PROTOCOL_VERSION), undocumented pub fns (unsafe_local_helper_protocol_supported, validate_unsafe_local_resource_identity, HelperSnapshot::validate, HelperLaunchRequest::validate_bounds), and undocumented wire types (HelperHello, HelperHelloAccepted, HelperHeartbeat, HelperScopeKind, HelperScopeState, HelperScopeSnapshot, HelperSnapshot, HelperOperationResult, HelperOperationRejected, DaemonToUnsafeLocalHelper, UnsafeLocalHelperToDaemon, UnsafeLocalHelperWireSchema) | fix: document each constant with the why (queue/snapshot/age bounds the daemon enforces) and one line per wire type | [unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wire.rs:26] | actionable | lane/d2b-contracts-control.md -- `RS-0644` | low | `d2b-contracts-control` | terminal_wire.rs's seven DTOs (TerminalStream, TerminalSize, TerminalWriteStdin, TerminalReadOutput, TerminalResize, TerminalWriteStdinResult, TerminalReadOutputChunk) have no item docs; only the module-level `//!` explains them | fix: add one-line docs per type (the redacted-Debug note belongs on the session-bearing types) | [terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105] | actionable | lane/d2b-contracts-control.md - -**`d2b-contracts-provider`** - -- `RS-0646` | medium | `d2b-contracts-provider` | none of the 59 Result-returning items in the partition carries an `# Errors` section, so callers cannot learn from the docs which closed-discriminant error each condition produces (for example when `CredentialControllerCall::authorize` yields `DeadlineExceeded` versus `OperationDenied`, or which `validate_*` failure maps to which `MetricPolicyError` variant) | fix: add `# Errors` sections naming the variant per condition to the public Result APIs, starting with the constructor and validate families | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:478, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:72, packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs:93] | actionable | lane/d2b-contracts-provider-p2.md -- `RS-0645` | low | `d2b-contracts-provider` | no canonical `# Errors` sections exist on any Result-returning pub item in the lane even though failure conditions are the load-bearing part of these admission constructors | fix: add `# Errors` sections naming the closed variants (e.g. `ProviderContractError::InvalidPrimitive` for `BinaryRef::parse`, `ProviderContractError::TrustNotEstablished` for `TrustEvidence::admit`) to the pub constructors and admission methods | [packages/d2b-contracts-provider/src/v3/provider.rs:250, packages/d2b-contracts-provider/src/v3/provider.rs:481, packages/d2b-contracts-provider/src/v3/credential.rs:120, packages/d2b-contracts-provider/src/v3/credential/service.rs:1002] | actionable | lane/d2b-contracts-provider-p1.md - -**`d2b-contracts-resource`** - -- `RS-0649` | medium | `d2b-contracts-resource` | artifact.rs is the only module with an undocumented public surface: MAX_ARTIFACT_ID_BYTES, ArtifactIdError::Invalid, ArtifactId, parse, and as_str all lack doc comments while every sibling module documents its pub items | fix: add one-line doc comments mirroring the BoundedToken contract (bounded lower-kebab artifact identifier, never a host path) | [packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/v3/artifact.rs:7-10, packages/d2b-contracts-resource/src/v3/artifact.rs:22, packages/d2b-contracts-resource/src/v3/artifact.rs:25] | actionable | lane/d2b-contracts-resource-p2.md -- `RS-0650` | low | `d2b-contracts-resource` | two pub fns in execution_policy.rs lack doc comments: `ExecutionPolicyWire::into_policy` (pub because Host/Guest crates decode through the wire mirror) and `string_schema_object` (pub only for the exported `string_schema!` macro expansion) | fix: add one-line docs, noting for string_schema_object that it is macro-support surface | [packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-resource/src/v3/execution_policy.rs:944] | actionable | lane/d2b-contracts-resource-p2.md -- `RS-0647` | low | `d2b-contracts-resource` | limits.rs exports 30 `pub const` admission limits (lines 3-33) with no per-item docs and no rationale for the specific values (500, 100, 900000, 30000, 256 KiB, 4 MiB), so a reader cannot tell which bound is load-bearing | fix: add one-line doc comments naming the enforcing boundary (request admission, watch credits, deadline) or a module-level rationale paragraph | [packages/d2b-contracts-resource/src/v3/limits.rs:3, packages/d2b-contracts-resource/src/v3/limits.rs:22] | actionable | lane/d2b-contracts-resource-p1.md -- `RS-0648` | low | `d2b-contracts-resource` | the operations module exports pub accessors with no doc comments: `MutationOrdinal::get` (error.rs:21), `StoreSlot::get` (error.rs:50), the eight `StoreError` accessors (error.rs:262-291), `StoreSealIdentity::new/zone/slot` (seal.rs:48/63/67), `OpenedMutation::body/into_body` (seal.rs:121/125), `MutationSealAcceptor::diagnose/declared_slot` (seal.rs:177/181), and `PreparedStoreMutation::new/mutation/resource_uid/payload_digest` (mod.rs:378-400) | fix: add one-line doc comments, especially for the mutating builder `with_store_slot` and the consume-then-open capability methods | [packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-resource/src/v3/operations/error.rs:262, packages/d2b-contracts-resource/src/v3/operations/seal.rs:48, packages/d2b-contracts-resource/src/v3/operations/seal.rs:121] | actionable | lane/d2b-contracts-resource-p1.md - -**`d2b-contracts-zone-session`** - -- `RS-0651` | medium | `d2b-contracts-zone-session` | the 37 pub wire constants at the top of component_session.rs (canonical lengths, clock skew, queue and deadline bounds) carry no doc comments at all, leaving the "why" of each wire value unrecorded in the contract crate that pins them | fix: add one-line `///` docs naming the wire role of each constant, mirroring the documented constant blocks in role.rs:30-58 | [src/v3/component_session.rs:27, src/v3/component_session.rs:51, src/v3/component_session.rs:61] | actionable | lane/d2b-contracts-zone-session-p1.md - -**`d2b-core`** - -- `RS-0655` | medium | `d2b-core` | manifest_v04.rs has no module doc and no doc comments on its central public wire types (`ManifestV04`, `ManifestMeta`, `ObservabilityMeta`, `VmEntry`, `VmLifecycle`, `VmGracefulShutdown`, `VmLiveActivation`, `VmLanPolicy`, `VmObservability`, `VmShellMetadata`, `ManifestShellName`, `from_slice`, `to_compact_json`), while sibling modules (host.rs, storage.rs, sync.rs, site.rs) document every type | fix: add a `//!` module doc and one-line doc comments with `# Errors` on the parse/serialize entry points, following the sibling-module style | [packages/d2b-core/src/manifest_v04.rs:1, packages/d2b-core/src/manifest_v04.rs:31, packages/d2b-core/src/manifest_v04.rs:158, packages/d2b-core/src/manifest_v04.rs:209] | actionable | lane/d2b-core-p2.md -- `RS-0654` | medium | `d2b-core` | 15 of the 23 public `intent_id_*` constructors carry no doc comment (intent_id_store_view, intent_id_vm_start, intent_id_nft_host, intent_id_nft_env, intent_id_nft_projection_env, intent_id_ownership_marker_env, intent_id_bridge_env, intent_id_route_env, intent_id_sysctl, intent_id_hosts_host, intent_id_nm_unmanaged_host, intent_id_usbip_firewall, intent_id_usbip_bind, intent_id_runner, intent_id_legacy_runner), even though these format strings are the deterministic BundleOpId wire contract the module doc describes and integrators build by hand | fix: give each a one-line doc naming the exact `BundleOpId` shape it produces (the module table is the source) | [packages/d2b-core/src/bundle_resolver.rs:2917, packages/d2b-core/src/bundle_resolver.rs:2935, packages/d2b-core/src/bundle_resolver.rs:3118, packages/d2b-core/src/bundle_resolver.rs:3217] | actionable | lane/d2b-core-p1.md - -**`d2b-core-controller`** - -- `RS-0652` | low | `d2b-core-controller` | pub struct fields without doc comments: RuntimeReadiness (3 of 5 fields), RecoverySnapshot (5 of 7), HandlerStatus (all 8); the undocumented fields (checkpoint_revision, last_reconciled_tick, retry_after_tick, provider_lease_count) are non-obvious | fix: add one-line field docs to RuntimeReadiness, RecoverySnapshot, and HandlerStatus | [packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controllers.rs:198-209] | actionable | lane/d2b-core-controller-p1.md -- `RS-0653` | low | `d2b-core-controller` | migration.rs exposes `requires_migration` and `validates_binding` without doc comments while every other pub item in the file documents its contract | fix: add one-line docs (e.g. "Whether this decision requires the broker migration path" and "Whether the supplied vm/intent bindings match the sealed decision") | [migration.rs:54, migration.rs:58] | actionable | lane/d2b-core-controller-p2.md - -**`d2b-host`** - -- `RS-0656` | low | `d2b-host` | Result-returning pub functions document failure conditions in prose but carry no `# Errors` sections; the crate has only 2 canonical sections total (host_prep_dag.rs:316, seccomp.rs:112) against ~119 `-> Result<` signatures (validate_readback, parse_request, gunzip_inflate, ...) | fix: add `# Errors` sections naming the failure conditions to the pub Result-returning fns, starting with the wire-boundary parsers (host_generation.rs, media.rs, nftables.rs) | [packages/d2b-host/src/bridge_port.rs:127, packages/d2b-host/src/host_generation.rs:103, packages/d2b-host/src/media.rs:41] | actionable | lane/d2b-host.md -- `RS-0657` | low | `d2b-host` | Pub items in impl blocks lack doc comments: `Controller::REQUIRED`, `Controller::as_str`, `Controller::from_token`, `BusId::new`, `HostPrepStepId::as_str` | fix: one-line doc comments, with `from_token` documenting the token grammar it accepts | [packages/d2b-host/src/cgroup.rs:53, packages/d2b-host/src/cgroup.rs:71, packages/d2b-host/src/cgroup.rs:85, packages/d2b-host/src/nftables.rs:612] | actionable | lane/d2b-host.md - -**`d2b-process-conformance`** - -- `RS-0660` | low | `d2b-process-conformance` | Zero canonical `# Errors` sections exist (seed 2 = 0) while 52 `-> Result<` declarations carry non-obvious failure conditions that several docs only imply (e.g. `ProcessOutcome::exited` rejects out-of-range codes, `SandboxCompiler::compile` rejects root-in-user-domain and canonical-JSON failure, `LaunchIdentity::new` names six refusal conditions, `BrokerTerminalResult::from_parent` requires matching evidence) | fix: add an `# Errors` section naming the failing conditions to the Result-returning pub items, notably terminal.rs:51/94/215, sandbox.rs:72, launch_identity.rs:112, ticket.rs:731, port.rs:35/67 | [packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/sandbox.rs:72, packages/d2b-process-conformance/src/launch_identity.rs:112, packages/d2b-process-conformance/src/ticket.rs:731] | actionable | lane/d2b-process-conformance.md - -**`d2b-provider`** - -- `RS-0661` | medium | `d2b-provider` | Public Result-returning APIs carry no `# Errors` sections,naming which conditions produce which error variants | fix: add `# Errors` sections to the ~28 pub Result-returning fns (agent.rs:40,270; context.rs:63; descriptor.rs:55,108,196,232; identity.rs:98,120,142; instance.rs:28; operation_ledger.rs:179,195; registry.rs:64,99,329,412; session.rs:36,94),listing each reachable variant per fn | [packages/d2b-provider/src/agent.rs:270, packages/d2b-provider/src/descriptor.rs:232, packages/d2b-provider/src/registry.rs:412, packages/d2b-provider/src/session.rs:36] | actionable | lane/d2b-provider.md - -**`d2b-provider-activation-nixos`** - -- `RS-0662` | medium | `d2b-provider-activation-nixos` | the pub Result-returning policy API (`verify_application`, `reconcile`, `apply_runner_result`, `refuse_undeclared_runner_step`, `ActivationTrust::verify`) documents no `# Errors` section, leaving 5 `ActivationError` and 9 `ActivationVerificationError` failure conditions unstated in the contract | fix: add `# Errors` sections naming the variants each fn returns | [packages/d2b-provider-activation-nixos/src/controller.rs:711, packages/d2b-provider-activation-nixos/src/controller.rs:735, packages/d2b-provider-activation-nixos/src/controller.rs:808, packages/d2b-provider-activation-nixos/src/controller.rs:726] | actionable | lane/d2b-provider-activation-nixos.md - -**`d2b-provider-audio-binding`** - -- `RS-0663` | low | `d2b-provider-audio-binding` | the four Result-returning trait methods (`binding_children`, `validate`, `dependencies`, `desired_children`) lack `# Errors` sections saying which conditions yield `Unavailable` vs `InvalidResource`, even though the crate denies missing_docs | fix: add `# Errors` sections naming the family's two failure variants | [packages/d2b-provider-audio-binding/src/audio_binding.rs:56, packages/d2b-provider-audio-binding/src/audio_binding.rs:117, packages/d2b-provider-audio-binding/src/audio_binding.rs:125, packages/d2b-provider-audio-binding/src/audio_binding.rs:134] | actionable | lane/tail-1.md - -**`d2b-provider-audio-pipewire`** - -- `RS-0664` | medium | `d2b-provider-audio-pipewire` | `AudioStateLock` is a pub struct with no doc comment at all (its module carries `#[allow(missing_docs)]`, lib.rs:9-10), and it is non-obvious: a caller must know holding the value keeps the OFD lock and dropping it releases it | fix: document the guard semantics (or remove the module-level allow and document the item) | [src/state.rs:81-84, src/lib.rs:9-10] | actionable | lane/d2b-provider-audio-pipewire.md -- `RS-0665` | low | `d2b-provider-audio-pipewire` | magic values lack the why: `AUDIO_REPAIR_INTERVAL_SECS = 300` says it is the repair interval but not why 300s, and the arbiter/mixer bound `64` in `AudioBindingController::new` is undocumented (and hardcoded again in tests/controller.rs:302-308) | fix: document the cadence rationale and hoist the 64 into a named const (e.g. `AUDIO_QUEUE_BOUND`) used by both the controller and the bound test | [src/controller.rs:21, src/controller.rs:209, src/controller.rs:212] | actionable | lane/d2b-provider-audio-pipewire.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0666` | medium | `d2b-provider-clipboard-wayland` | Result-returning public items carry no # Errors sections anywhere in the crate despite deny(missing_docs), so failure contracts (ConcurrentLimitExceeded, InvalidBounds, AuditQueueFull, SessionUnauthenticated) are undocumented | fix: add # Errors sections naming the variants to the public Result-returning items, starting with FdPermitPool::acquire, Policy::new, ClipboardAuditQueue::push, and ClipboardRuntime::admit_route | [src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0667` | medium | `d2b-provider-clipboard-wayland` | ClipboardAuditEvent::to_wire derives wire labels from Debug impls (format!("{:?}", event_type) lowercased and size_bucket via {:?}) instead of stable as_str labels, so a variant rename silently changes the cross-crate audit record consumed by d2bd | fix: add as_str() to ClipboardEventType and SizeBucket returning the exact current renderings ("pasteauthorized", "Lt1K", ...) and use them in to_wire | [src/audit.rs:172, src/audit.rs:174] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0668` | low | `d2b-provider-clipboard-wayland` | ClipboardEntry::bytes is documented as "Return a bounded copy for an already-authorized materialization" but returns &[u8], contradicting the copy claim and the as_/to_/into_ cost convention | fix: reword to "Borrow the payload bytes for an already-authorized materialization" | [packages/d2b-provider-clipboard-wayland/src/history.rs:112-115] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0669` | low | `d2b-provider-clipboard-wayland` | the clipd_host IPC and state surface is largely undocumented: niri.rs (read_bounded_ndjson_line, encode_niri_request, decode_niri_response, NiriStateCache methods, FocusedWindowProvider trait, HostClipboardAttributor methods), wayland.rs (DataControlOffer::destroy, DataControlSource::offer_mime), picker.rs (launch's returned &UnixStream borrow, poll_active's nonblocking contract, reap_expired, reap_terminated), host.rs (refresh_focused_window_snapshot) | fix: add doc comments stating the blocking/ownership contracts (which calls block, who destroys protocol objects, what the returned borrow is) | [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:128, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:162, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:336-337] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0670` | low | `d2b-provider-clipboard-wayland` | magic constants lack the why: ENVELOPE_BYTES/JSON_STRING_ESCAPE_EXPANSION in the frame-budget math, PICKER_TERMINATE_GRACE (250ms), MAX_AUDIT_MIME_BYTES (64), DEFAULT_NIRI_MAX_LINE_BYTES (1 MiB) | fix: document the derivation or the upstream constraint each constant encodes | [packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:74, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:7] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-command`** - -- `RS-0671` | low | `d2b-provider-command` | public `Result`-returning constructors `CommandExec::parse`, `CommandArgvSlot::parse`, and `CommandSpec::new` return `Result<..., CommandContractError>` without an `# Errors` section naming which variants each can produce, though callers match on them (tests assert exact variants) | fix: add a one-line `# Errors` per constructor naming its `CommandContractError` variants | [packages/d2b-provider-command/src/command.rs:38, packages/d2b-provider-command/src/command.rs:89, packages/d2b-provider-command/src/command.rs:192] | actionable | lane/tail-2.md - -**`d2b-provider-config-nixos`** - -- `RS-0672` | low | `d2b-provider-config-nixos` | none of the ~14 public `Result`-returning APIs carry a `# Errors` section, so callers cannot learn which `ConfigError` variants each returns without reading the implementation (lib.rs:6 denies missing_docs but only the one-liners exist) | fix: add `# Errors` to `GuestSessionEvidence::new`, `GuestConfigDocument::new`, `ConfigSyncResponse::document`, `ConfigStageRequest::document`, the five `ConfigStagingStore` methods, `GuestConfigReader::new`, and the two `ConfigService` methods | [packages/d2b-provider-config-nixos/src/controller.rs:45-64, packages/d2b-provider-config-nixos/src/service.rs:359-475, packages/d2b-provider-config-nixos/src/ttrpc.rs:52-72] | actionable | lane/d2b-provider-config-nixos.md - -**`d2b-provider-credential`** - -- `RS-0673` | low | `d2b-provider-credential` | the two Result-returning public items lack the canonical `# Errors` section: `CredentialRevocationRequest::new` states its failure condition only in prose (session.rs:128-131) and `CredentialSession::revoke_credential` documents no failure conditions at all (session.rs:273-274) | fix: add `# Errors` sections naming `CredentialResourceRuntimeError::InvalidResource` (zero/unknown session generation, zero rotation generation, foreign Provider) and the `Revocation` variant respectively | [packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/session.rs:275] | actionable | lane/d2b-provider-credential.md - -**`d2b-provider-credential-entra`** - -- `RS-0674` | low | `d2b-provider-credential-entra` | no public item carries a canonical `# Errors` section although ~30 pub items return `Result` (EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, reject_*); `#![deny(missing_docs)]` guarantees presence, not the failure contract | fix: add `# Errors` sections naming the returned error variant (e.g. InvalidConfig, InvalidPlacement, InvalidEndpoint, InvalidConsumer, DeadlineExceeded) to the Result-returning pub constructors | [packages/d2b-provider-credential-entra/src/controller.rs:47, packages/d2b-provider-credential-entra/src/lib.rs:502, packages/d2b-provider-credential-entra/src/lib.rs:565, packages/d2b-provider-credential-entra/src/lib.rs:1049] | actionable | lane/d2b-provider-credential-entra.md - -**`d2b-provider-credential-managed-identity`** - -- `RS-0675` | low | `d2b-provider-credential-managed-identity` | Public `Result`-returning items document failures only in prose and carry no `# Errors` sections (e.g. `ManagedIdentityClientConfig::new`, `ManagedIdentityPlacement::new`, `ImdsEndpointAlias::parse`, `ManagedIdentityCredentialProviderFactory::new`, controller projections) | fix: add `# Errors` sections naming the specific `ManagedIdentityProviderError`/`CredentialServiceError`/`CredentialObservabilityError` variant each failure returns | [lib.rs:449, lib.rs:514, lib.rs:592, lib.rs:796] | actionable | lane/d2b-provider-credential-managed-identity.md - -**`d2b-provider-credential-secret-service`** - -- `RS-0676` | medium | `d2b-provider-credential-secret-service` | public Result-returning constructors/projections lack `# Errors` sections naming which condition yields which error (despite `#![deny(missing_docs)]` forcing presence, no canonical section exists anywhere in the crate) | fix: add `# Errors` to `SecretServiceConfig::new`, `SecretServicePlacement::new`, `SecretServiceCredentialProviderFactory::new`, `SecretServiceController::reconcile` (and the remaining pub Result items) naming `SecretServiceProviderError`/`CredentialServiceError` failures | [packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-credential-secret-service/src/lib.rs:610, packages/d2b-provider-credential-secret-service/src/lib.rs:1140, packages/d2b-provider-credential-secret-service/src/controller.rs:73] | actionable | lane/d2b-provider-credential-secret-service.md -- `RS-0677` | low | `d2b-provider-credential-secret-service` | the one-second session-close revoke deadline is a bare magic `1_000` triplicated with no why (it bounds revoke of potentially many leases during disconnect/finalize/drain) | fix: extract `const SESSION_CLOSE_REVOKE_DEADLINE_MS: u64 = 1_000;` and document why (one-second cap so a stalled backend cannot hang session teardown foreve) | [packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-credential-secret-service/src/service.rs:674, packages/d2b-provider-credential-secret-service/src/service.rs:684] | actionable | lane/d2b-provider-credential-secret-service.md - -**`d2b-provider-device-gpu`** - -- `RS-0678` | medium | `d2b-provider-device-gpu` | no `# Errors` section on any pub `Result`-returning item despite the crate denying missing_docs, so the failure contract is undocumented | fix: add `# Errors` naming the failure branches to new_authorized/reconcile_lifecycle/adopt_lifecycle/finalize_lifecycle/validate/from_core/generate_gpu_argv/generate_video_argv/GpuWorkerSpec::gpu/VideoWorkerSpec::new/GpuProcessDeclaration::new/select_processes/gpu_process_name/GpuOwnerProof::new/GpuAuthorityAdmission::new/with_video_principal | [packages/d2b-provider-device-gpu/src/controller.rs:172, packages/d2b-provider-device-gpu/src/settings.rs:78, packages/d2b-provider-device-gpu/src/gpu_argv.rs:158] | actionable | lane/d2b-provider-device-gpu.md -- `RS-0679` | low | `d2b-provider-device-gpu` | module-level `#![allow(missing_docs)]` in the two argv modules overrides the crate-wide deny, leaving the pub `as_str` methods undocumented | fix: drop both allows and add doc comments to `GpuContextType::as_str` and `VideoBackend::as_str` | [packages/d2b-provider-device-gpu/src/gpu_argv.rs:24, packages/d2b-provider-device-gpu/src/video_argv.rs:22, packages/d2b-provider-device-gpu/src/gpu_argv.rs:40, packages/d2b-provider-device-gpu/src/video_argv.rs:103] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-device-security-key`** - -- `RS-0681` | medium | `d2b-provider-device-security-key` | no `# Errors` section exists on any of the 24 public `Result`-returning items, and the lease/controller state-machine failures are the non-obvious kind the section exists for (`SessionConflict` vs `InvalidTransition` vs `AuthorizationDenied` vs `Effect`) | fix: add `# Errors` sections naming the returned variants to `SecurityKeyLease::{acquire, acquire_authorized, rebind_authorized, complete, cancel, expire}` and `SecurityKeyController::{new, new_authorized, child_resources, child_resources_for_user, acquire, acquire_authorized, rebind_authorized, complete}` | [packages/d2b-provider-device-security-key/src/lease.rs:150-303, packages/d2b-provider-device-security-key/src/controller.rs:162-186, packages/d2b-provider-device-security-key/src/controller.rs:209-267] | actionable | lane/d2b-provider-device-security-key.md -- `RS-0680` | low | `d2b-provider-device-security-key` | `#![allow(missing_docs)]` at relay.rs:7 defeats the crate-root `#![deny(missing_docs)]` for a pub module re-exported at the root, letting undocumented items ship: `CidTranslator::new` (relay.rs:144), `LeaseId::as_u64` (relay.rs:209), and the pub fields of `CtaphidInitPacket`/`CtaphidContPacket` (relay.rs:54-66) | fix: document the handful of items and drop the module-level allow | [packages/d2b-provider-device-security-key/src/relay.rs:7, packages/d2b-provider-device-security-key/src/relay.rs:144, packages/d2b-provider-device-security-key/src/relay.rs:209] | actionable | lane/d2b-provider-device-security-key.md - -**`d2b-provider-device-tpm`** - -- `RS-0682` | low | `d2b-provider-device-tpm` | Result-returning public items never enumerate their error variants: 47 `-> Result<` items (build_tpm_state_volume_spec, build_swtpm_process_spec, build_swtpm_flush_spec, generate_swtpm_argv, generate_swtpm_ioctl_flush_argv, TpmResourceController::new/reconcile/finalize, SwtpmSettings::validate, reconcile_device_tpm_controller, finalize_device_tpm_controller) carry one-line docs but no `# Errors` section, while the crate's doc standard is otherwise high (#![deny(missing_docs)] plus module docs) | fix: add `# Errors` sections naming the TpmResourceEffectError/TpmResourceControllerError/SwtpmArgvError variants each item can return | [resources.rs:53, swtpm_argv.rs:130, resource_controller.rs:132, resource_controller.rs:190] | actionable | lane/d2b-provider-device-tpm.md -- `RS-0683` | low | `d2b-provider-device-tpm` | swtpm_argv.rs:39 `#![allow(missing_docs)]` is redundant: every pub item in the module is already documented and the crate root denies missing docs, so the opt-out lets a future undocumented pub item pass silently | fix: remove the module-level allow | [swtpm_argv.rs:39] | actionable | lane/d2b-provider-device-tpm.md - -**`d2b-provider-device-usbip`** - -- `RS-0684` | medium | `d2b-provider-device-usbip` | `#![allow(missing_docs)]` in reconcile_state.rs:6 and state_machine.rs:61 contradicts the crate's `#![deny(missing_docs)]` (lib.rs:9), leaving root-re-exported pub items without doc contracts (`UsbipPolicyFailure::telemetry_label`, `UsbipEventSource::vm`/`component`, `UsbipReconcileCorrelationId::new`, `UsbipClaimSource::is_explicit`, `UsbipExecutionReport::is_ok`, `UsbipBusidPlan::stop_order`) | fix: document the pub items and drop the two module-level allows | [reconcile_state.rs:6, state_machine.rs:61, lib.rs:9] | actionable | lane/d2b-provider-device-usbip.md -- `RS-0685` | medium | `d2b-provider-device-usbip` | Result-returning public items have no `# Errors` section anywhere in the crate, so callers cannot learn the closed failure sets from the docs | fix: add `# Errors` sections naming the variants to `UsbipArbitrator::new`, `BusId::parse`, `UsbipBindingContext::new`, `UsbipBindingController::new`, `build_usbip_plan`, `execute_usbip_plan`, `admit_bind_bus_class`, `binding_child_resources` | [arbitration.rs:76, busid.rs:12, broker.rs:61, controller.rs:210] | actionable | lane/d2b-provider-device-usbip.md - -**`d2b-provider-display-wayland`** - -- `RS-0687` | low | `d2b-provider-display-wayland` | `FilterInput::allow_globals` and `FilterInput::deny_globals` doc comments say "Add an allowed global to this layer" / "Add a denied global to this layer" but the methods are getters returning `&[String]` | fix: reword to "Borrow the allowed globals of this layer" / "Borrow the denied globals of this layer" | [src/policy.rs:114, src/policy.rs:119] | actionable | lane/d2b-provider-display-wayland-p2.md -- `RS-0686` | low | `d2b-provider-display-wayland` | public Result-returning items lack `# Errors` sections describing which conditions fail: `BridgeConfig::from_identity_parts`, `path_for_user_identity`, `parse_filter`, and the three `ReadinessReporter` methods | fix: add `# Errors` sections naming `BridgeConfigError` variants, the parse failure modes, and the io errors | [packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:37, packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:73, packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:162, packages/d2b-provider-display-wayland/src/wayland_proxy/readiness.rs:30] | actionable | lane/d2b-provider-display-wayland-p1.md -- `RS-0688` | low | `d2b-provider-display-wayland` | Result-returning pub API has no `# Errors` canonical sections despite `#![deny(missing_docs)]`: constructors and reconcilers document their failure modes only through the error-enum variant docs | fix: add `# Errors` sections naming the variants on the pub Result items, e.g. `DisplayIdentity::new`, `WaylandSessionSpec::new`, `WaylandPolicy::compile`, `DisplayController::reconcile_authenticated_session` | [src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759] | actionable | lane/d2b-provider-display-wayland-p2.md - -**`d2b-provider-guest`** - -- `RS-0689` | low | `d2b-provider-guest` | No public Result-returning item carries a canonical `# Errors` doc section (docs2 seed = 0 hits src), despite #![deny(missing_docs)]]and ~107 Result-returning pub items | fix: add `# Errors` headings naming the refusal conditions on the trait/fn contracts ((facets.rs:63, target_control.rs:95, driver.rs:403, target_service.rs:68 etc.) | [packages/d2b-provider-guest/src/facets.rs:63, packages/d2b-provider-guest/src/target_control.rs:95, packages/d2b-provider-guest/src/driver.rs:403, packages/d2b-provider-guest/src/target_service.rs:68] | actionable | lane/d2b-provider-guest.md - -**`d2b-provider-guest-azure-container-apps`** - -- `RS-0690` | low | `d2b-provider-guest-azure-container-apps` | `#[allow(missing_docs)]` blanket-exempts the effects module whose pub surface (AcaControl and AcaCredentialLeaseClient trait methods, AcaProviderConfig fields, Aca*Error enums, MAX_ACA_* constants) is re-exported at the crate root, undercutting the crate's own `#![deny(missing_docs)]` | fix: document the effect trait methods and validated-config accessors and drop the module-level allow (README.md already carries the prose contract, so this is rustdoc-surface work, not a contract gap) | [src/lib.rs:7, src/effects.rs:813-882] | actionable | lane/d2b-provider-guest-azure-container-apps.md - -**`d2b-provider-guest-azure-virtual-machine`** - -- `RS-0691` | medium | `d2b-provider-guest-azure-virtual-machine` | Result-returning public methods carry no `# Errors` sections, so the framework caller cannot learn from docs which failures are transient/retryable vs fatal: `reconcile`, `adopt`, `poll_operation`, `update`, `finalize`, `complete_enrollment`, `restore_recovery_state` (controller/mod.rs:333-760), `BootstrapPsk::from_bytes`, `BootstrapAdmission::consume` (bootstrap.rs:15,82), `DataDiskSpec::validate`, `AzureVmConfig::validate`, `AzureVmGuestSettings::validate` (config.rs:49,103,177) | fix: add `# Errors` sections naming the `AzureVmError` variants each call returns, especially the `Transient` vs fatal split | [src/controller/mod.rs:333, src/controller/mod.rs:446] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md -- `RS-0692` | low | `d2b-provider-guest-azure-virtual-machine` | `BootstrapPsk::matches` does not document the constant-time comparison guarantee that justifies its index loop over max(len) with zero-padding | fix: document "constant-time in the presented length; never exits early on mismatch" (the security contract of the loop shape) | [src/bootstrap.rs:25] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md - -**`d2b-provider-guest-cloud-hypervisor`** - -- `RS-0693` | low | `d2b-provider-guest-cloud-hypervisor` | no canonical `# Errors`/`# Examples` sections exist anywhere in the crate (seed 2 = 0) although 114 pub items return `Result<`; e.g. `GuestSetupDescriptor::from_canonical_bytes` (descriptor.rs:423) and `GuestChildBatch::from_descriptor` (identity.rs:590) document neither failure conditions nor a usage example | fix: add `# Errors` sections to the wire-boundary constructors first (descriptor.rs, identity.rs, health.rs), then the remaining Result-returning pub items | [descriptor.rs:423-429, identity.rs:590-634] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0694` | medium | `d2b-provider-guest-qemu-media` | None of the 41 `-> Result<` items carry a `# Errors` section (seed2 =0 ( (e.g. `DeviceAdmission::validate` has 6 failure kinds (device_watch.rs:82-90), `QemuMediaController::reconcile` 8 (reconcile.rs:338), `LaunchTicket::new` 3 (process_builder.rs:221) ), `QmpSession::negotiate` 3 (qmp/mod.rs:199) (leaving the caller to read the enum to map conditions | fix: add `# Errors` sections naming which conditions produce which variants on the non-obvious pub Result APIs | [packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs:82, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:338, packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:221, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:199] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-notification-desktop`** - -- `RS-0695` | medium | `d2b-provider-notification-desktop` | No `# Errors` section exists on any Result-returning pub item (112 `-> Result<` sites) even though the crate pins wire-leaning error enums | fix: add `# Errors` sections naming the exact variants (or stable slugs) on pub fns like `ActionNonceStore::register`, `NotificationRuntime::new`, `NotificationSink::deliver_from_guest_source` | [packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provider-notification-desktop/src/runtime.rs:64-67, packages/d2b-provider-notification-desktop/src/host_sink.rs:297-305] | actionable | lane/d2b-provider-notification-desktop.md -- `RS-0696` | low | `d2b-provider-notification-desktop` | Doc first sentences are broken fragments: "/// the daemon." opens `deliver_evidence`,"/// completes every effect immediately." opens `RecordingEffects`,"/// the current authenticated reconnect generation." runs into the `from_config_at_generation` doc | fix: rewrite each as a standalone 15-word summary before the trailing paragraph | [packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-notification-desktop/src/test_support.rs:14, packages/d2b-provider-notification-desktop/src/guest_source.rs:17] | actionable | lane/d2b-provider-notification-desktop.md - -**`d2b-provider-observability-otel`** - -- `RS-0697` | medium | `d2b-provider-observability-otel` | the three crate-identity constants `PROVIDER_NAME`,`PROVIDER_REF`,`PROVIDER_API_MAJOR` in lib.rs lack doc comments while every sibling public item in the crate carries one | fix: add one-line doc comments naming each constant's role (mirroring the documented `OTEL_HOST_BRIDGE_ROLE` on the next line) | [lib.rs:13, lib.rs:14, lib.rs:15] | actionable | lane/d2b-provider-observability-otel.md -- `RS-0698` | medium | `d2b-provider-observability-otel` | Result-returning pub API fns lack `# Errors` doc sections naming their failure conditions, leaving callers to infer variants from code | fix: add `# Errors` sections to at least the five representative fns (ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream,EmitterSocket::bind/drain_once, validate_resource_attributes),enumerating e.g. `ProviderAgentError::{SessionDenied,AuditBackpressure,InvalidInput}` | [agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131] | actionable | lane/d2b-provider-observability-otel.md - -**`d2b-provider-operation`** - -- `RS-0699` | low | `d2b-provider-operation` | public `Result`-returning constructors `OperationAudit::new`, `AuditJoin::new`, `OperationFds::new`, `OperationBounds::new`, and `OperationSpec::new` return `Result<..., OperationContractError>` without `# Errors` sections naming which variants each can produce, though callers match exact variants (tests assert them) | fix: add a one-line `# Errors` per constructor naming its `OperationContractError` variants | [packages/d2b-provider-operation/src/operation.rs:138, packages/d2b-provider-operation/src/operation.rs:194, packages/d2b-provider-operation/src/operation.rs:347, packages/d2b-provider-operation/src/operation.rs:405] | actionable | lane/tail-2.md - -**`d2b-provider-process`** - -- `RS-0700` | low | `d2b-provider-process` | no `# Errors` or `# Panics` canonical sections exist on any of the crate's 142 Result-returning items, so the failure contract of the public surface is prose-only | fix: add `# Errors` sections naming the closed codes to the public Result-returning items, starting with `ProcessEffectBackend::launch` (which closed codes each operation can raise) and `resolve_launch_identity` (which `LaunchIdentityError` variants are possible) | [packages/d2b-provider-process/src/backend.rs:256, packages/d2b-provider-process/src/launch_identity.rs:64] | actionable | lane/d2b-provider-process.md - -**`d2b-provider-process-minijail`** - -- `RS-0701` | low | `d2b-provider-process-minijail` | public Result-returning items carry no `# Errors` section stating which conditions produce which `ProcessConformanceError` variant | fix: add `# Errors` to `PlatformGate::validate`, `validate_launch_ticket`, `launch_with_inherited_fds`, `adopt`, `stop`, and `stop_stale` (the shared catalog is `d2b_process_conformance::ProcessConformanceError`) | [packages/d2b-provider-process-minijail/src/launch.rs:33, packages/d2b-provider-process-minijail/src/launch.rs:46, packages/d2b-provider-process-minijail/src/lib.rs:313, packages/d2b-provider-process-minijail/src/lib.rs:371] | actionable | lane/tail-3.md - -**`d2b-provider-process-systemd`** - -- `RS-0702` | medium | `d2b-provider-process-systemd` | public `Result`-returning items lack `# Errors` sections naming their failure conditions: `SystemdProviderConfig::new` (OutOfRange bounds), `drain::validate` (two refusal variants), `SystemdProcessController::reconcile` (DeadlineExceeded), `validate_launch_ticket`, `SystemdSandboxCompiler::compile` | fix: add `# Errors` sections to each, stating which inputs produce which failure | [packages/d2b-provider-process-systemd/src/lifecycle.rs:33, packages/d2b-provider-process-systemd/src/drain.rs:30, packages/d2b-provider-process-systemd/src/controller.rs:66, packages/d2b-provider-process-systemd/src/launch.rs:8] | actionable | lane/d2b-provider-process-systemd.md - -**`d2b-provider-provider`** - -- `RS-0703` | low | `d2b-provider-provider` | the eight `pub` fields of `ProviderObservation` are undocumented while every other pub item in the crate carries a doc comment | fix: add one-line field docs (or a struct-level contract explaining each gate) at providers.rs:72-79 | [src/providers.rs:72, src/providers.rs:79] | actionable | lane/d2b-provider-provider.md - -**`d2b-provider-role`** - -- `RS-0704` | low | `d2b-provider-role` | role's lib.rs lacks the `#![deny(missing_docs)]` gate that its four sibling declaration crates in this lane all carry (quota lib.rs:16, resource-export lib.rs:14, resource-import lib.rs:14, minijail lib.rs:25), and `PolicyRevisionSet`'s four pub fields are undocumented | fix: add `#![deny(missing_docs)]` to lib.rs and document the `PolicyRevisionSet` fields | [packages/d2b-provider-role/src/lib.rs:1, packages/d2b-provider-role/src/rbac.rs:11] | actionable | lane/tail-3.md - -**`d2b-provider-seccomp-profile`** - -- `RS-0705` | medium | `d2b-provider-seccomp-profile` | the crate's two public Result-returning constructors carry no `# Errors` section, and their failure conditions are non-obvious (byte-length bound, control characters, `/dev` prefix; syscall/device list bounds) | fix: add `# Errors` sections to `DeviceNodePath::parse` and `SeccompProfileSpec::new` naming the three `SeccompProfileContractError` variants each can return | [packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:31, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:176] | actionable | lane/tail-4.md - -**`d2b-provider-shell-terminal`** - -- `RS-0706` | medium | `d2b-provider-shell-terminal` | the ~30 `pub fn` items returning `Result<_, ShellTerminalError>` (e.g. `Authorizer::authorize_request`, `OpenSessionRequest::new`, `PoolSpec::new`, `ShellSession::from_pool`, `restore_pool`, `reconcile_pool_attachments`, `restore_session`, `restart_supervisor`, `open_session`, `finalize_session`, `AttachRequest::new`, `OutputRing::new`, `SupervisorIdentity::new`, `ShellAuthorityLedger::validate_session`) lack an `# Errors` section naming which variants they emit. | fix: add an `# Errors` section to each Result-returning pub item enumerating the `ShellTerminalError` variants that item can return (e.g. `restore_pool`: `# Errors` `CapacityExceeded` when pool name already projected or the authority rejects the restore). | [src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/ring.rs:16] | actionable | lane/d2b-provider-shell-terminal.md - -**`d2b-provider-system-core`** - -- `RS-0707` | medium | `d2b-provider-system-core` | public Result-returning items carry no `# Errors` sections, and some fail non-obviously (`HostProbeSnapshot::new` rejects control characters and >64/128-byte strings with `HostProbeFailed`; `MinijailPlatformGate::validate` maps kernel/cgroup failures to two distinct variants) | fix: add `# Errors` sections to validate, HostProbeSnapshot::new, reject_operator_status_fields, reconcile/reconcile_observed/reconcile_with_probe, UserReconciler::reconcile, and the two effect ports' methods | [src/host.rs:121, src/host.rs:161, src/user.rs:241] | actionable | lane/d2b-provider-system-core.md - -**`d2b-provider-toolkit`** - -- `RS-0708` | low | `d2b-provider-toolkit` | key `Result`-returning public items document no failure conditions: `ProviderEntrypoint::new` (InvalidName), `admit` (NotAccepting), the three `with_*` binders, and `StartupPlan::derive`/`declare` (MissingInput/DuplicateOutput/Cycle) have one-line docs with no `# Errors` section or prose naming the refusal, so callers must read the error enum to learn when construction fails | fix: add `# Errors` sections (or one prose sentence naming the refusal) to the entrypoint constructors and the plan derivation | [packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/src/base/runtime.rs:383-384, packages/d2b-provider-toolkit/src/base/startup.rs:39] | actionable | lane/d2b-provider-toolkit-p1.md -- `RS-0709` | low | `d2b-provider-toolkit` | no public item in the scope carries the canonical `# Errors` section even though many return `Result` with closed, non-obvious failure sets (`check_descriptor_conformance` has ten `ConformanceError` variants; `operation_deadline` fails on exhausted deadlines; `validate_attachment_indexes` fails on non-monotone indexes) | fix: add `# Errors` sections naming the variant per condition to the Result-returning pub items, starting with conformance.rs:267, conformance.rs:291, credential.rs:111, credential.rs:131, adapter.rs:31 | [packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolkit/src/testing/conformance.rs:291, packages/d2b-provider-toolkit/src/credential.rs:111, packages/d2b-provider-toolkit/src/credential.rs:131] | actionable | lane/d2b-provider-toolkit-p2.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0710` | low | `d2b-provider-transport-azure-relay` | none of the 80 Result-returning public items carries a canonical `# Errors` section (docs2 = 0 crate-wide), so failure conditions are discoverable only by reading the error enums; e.g. `mint_sas`, `build_connect`, `CreditWindow::new`, `RelayTransportSettings::new` | fix: add `# Errors` sections naming the conditions (mint_sas: InvalidTtl, TtlTooLong, InvalidEndpoint, InvalidCredential, Key, Clock) on the pub Result items | [packages/d2b-provider-transport-azure-relay/src/auth.rs:229-246, packages/d2b-provider-transport-azure-relay/src/backpressure.rs:31-36, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:18-22] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-transport-unix`** - -- `RS-0711` | low | `d2b-provider-transport-unix` | the three inherent pub methods returning `Result` (`open`, `close`, `observe`) lack `# Errors` sections naming which conditions produce which `PortalError` variant, though the failure conditions are recoverable from the enum docs | fix: add `# Errors` sections to the three doc comments | [packages/d2b-provider-transport-unix/src/portal.rs:197-201, packages/d2b-provider-transport-unix/src/portal.rs:266, packages/d2b-provider-transport-unix/src/portal.rs:286] | actionable | lane/tail-5.md - -**`d2b-provider-transport-vsock`** - -- `RS-0712` | low | `d2b-provider-transport-vsock` | 38 public `Result`-returning items carry no `# Errors` doc sections, so callers must infer from doc prose which condition yields which failure variant - the crate's `#![deny(missing_docs)]` (lib.rs:3) secures only first sentences, not the canonical contract sections. | fix: add `# Errors` bullet lists naming the failure variant per condition to the public Result-returning items (e.g. `GuestIdentity::new`, `SessionAuthority::authenticate`, `VsockTransportSettings::new`, `ZoneLinkSpec::validate`, `open_transport`, `NativeGuestRelay::start`) | [packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsock/src/auth.rs:257, packages/d2b-provider-transport-vsock/src/settings.rs:31, packages/d2b-provider-transport-vsock/src/service.rs:383] | actionable | lane/d2b-provider-transport-vsock.md - -**`d2b-provider-volume-binding`** - -- `RS-0713` | low | `d2b-provider-volume-binding` | the four public Result-returning seam methods state no # Errors section (which conditions fail and how the driver classifies them): facets.rs SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, driver.rs BindingDriverEffects::remove_socket/guest_mount_ready | fix: add # Errors to each naming the daemon-adapter failure conditions and the fail-closed handling | [packages/d2b-provider-volume-binding/src/facets.rs:52, packages/d2b-provider-volume-binding/src/facets.rs:65, packages/d2b-provider-volume-binding/src/driver.rs:307-310, packages/d2b-provider-volume-binding/src/driver.rs:325-330] | actionable | lane/d2b-provider-volume-binding.md - -**`d2b-provider-volume-local`** - -- `RS-0714` | low | `d2b-provider-volume-local` | no canonical doc sections exist anywhere in the crate (seed 2 = 0 hits): public Result-returning items such as ContentFile::new, ContentProjection::new/from_value, EntryRequest::resolve, VolumeLocalController::reconcile, admit_attachments and validate_source_spec carry one-line docs but no `# Errors` section naming which conditions produce which failure | fix: add `# Errors` sections to the admission/parse constructors and the controller entry points, listing the closed VolumeLocalError variants each can return | [src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92] | actionable | lane/d2b-provider-volume-local.md - -**`d2b-provider-zone`** - -- `RS-0715` | low | `d2b-provider-zone` | the inherent pub `SystemCoreStatusEmitter::emit` returns `Result` (zone_status.rs:113-114) without an `# Errors` section naming the contract-rejection condition | fix: add an `# Errors` section stating that duplicate system-core handler records or a rejected `ZoneStatusResource` yield `ZoneStatusProjectionError::Contract` | [packages/d2b-provider-zone/src/zone_status.rs:110-114] | actionable | lane/tail-5.md - -**`d2b-provider-zone-link`** - -- `RS-0716` | low | `d2b-provider-zone-link` | 21 public `Result`-returning items document their failure modes only in prose, with zero `# Errors` sections, so the error contract (which `ZoneLinkError` variant fires) is not in the canonical place a caller reads | fix: add `# Errors` sections naming the `ZoneLinkError`/`ZoneLinkAdoptionError` variants to the public `Result` items, starting with `ZoneLinkLimits::new`, `ZoneLinkHandler::{begin,commit,release_effects,issue_route_admission}`, `ZoneLinkRecord::{with_route_binding,encode_route_admission_dedup,with_route_admission_dedup}`, `ZoneLinkOwnerProof::{new,from_digest}`, `ZoneLinkCursorAuthority::{adopt,cursor}` | [packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src/zone_links.rs:1300, packages/d2b-provider-zone-link/src/zonelink.rs:197] | actionable | lane/d2b-provider-zone-link.md - -**`d2b-resource-api`** - -- `RS-0718` | medium | `d2b-resource-api` | nine pub methods on the evaluator surface are undocumented, including `NativeAuthorizer::authorize` (the security decision entry returning nine AuthorizationDenial variants) and `take_store_seal` (which hands off an ownership-bearing seal acceptor) | fix: add doc comments with `# Errors` sections enumerating the denial variants on authorize, and one-line contracts on the remaining eight | [packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, packages/d2b-resource-api/src/authz.rs:912, packages/d2b-resource-api/src/authz.rs:1093] | actionable | lane/d2b-resource-api-p2.md -- `RS-0717` | medium | `d2b-resource-api` | pub `Result`-returning items carry no `# Errors` sections stating which conditions produce which failure: the `ResourceService` constructors (StoreBindingError cases), `ResourceStoreBackend` methods (StoreError classes), the frame helpers (`attach_scoped_commit_frame`/`attach_scoped_query_frame`/`reject_scoped_commit_frame`), `manager_row_stored`, and `admit_guest_lifecycle` | fix: add `# Errors` sections naming the failure classes (binding already taken, invalid frame, unsupported capability, envelope invalid) | [service.rs:198, store.rs:39, adapter.rs:71, manager_backend.rs:625] | actionable | lane/d2b-resource-api-p1.md merged: d2b-resource-api-p1#10 - -**`d2b-resource-client`** - -- `RS-0719` | low | `d2b-resource-client` | 50 Result-returning pub items carry no `# Errors` section (zero `# Examples|Errors|Panics|Safety` sections anywhere in the crate), so callers must infer failure conditions from prose | fix: add `# Errors` to the public Result-returning entry points (MetadataInput::new, RetryPolicy::new, CallDriver::new, ZoneClient::connect, ZoneClient::call_connected, ZoneClient::scoped_commit_batch, ProcessAttachClient::attach) | [packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:131, packages/d2b-resource-client/src/zone_client.rs:711, packages/d2b-resource-client/src/process_attach.rs:648] | actionable | lane/d2b-resource-client.md - -**`d2b-resource-runtime`** - -- `RS-0720` | medium | `d2b-resource-runtime` | `ResourceManagerClient`, the crate-root re-exported caller-facing facade consumed by d2bd and the resource API, has 14 undocumented pub methods (`new`, `actor`, `apply`, `ensure`, `remove`, `get`, `list`, `watch`, `get_row`, `list_owned`, `ensure_child`, `register_watch`, `cancel_watch`, `reconcile_children`) with non-obvious contracts (watch gap-free-epoch semantics, ensure-child re-parent refusal, watch routing) | fix: add doc comments with `# Errors` sections naming the `ResourceError` variants each call can return | [packages/d2b-resource-runtime/src/manager.rs:1500, packages/d2b-resource-runtime/src/manager.rs:1519, packages/d2b-resource-runtime/src/manager.rs:1597] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0721` | low | `d2b-resource-runtime` | `ResourceManagerArgs` fields `store`, `providers`, and `backoff` are undocumented while the sibling fields all carry doc comments | fix: one line each (the store is the single-writer spec store, providers the per-type registry, backoff the R13 fixed reconcile backoff) | [packages/d2b-resource-runtime/src/manager.rs:850, packages/d2b-resource-runtime/src/manager.rs:851, packages/d2b-resource-runtime/src/manager.rs:870] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0722` | low | `d2b-resource-runtime` | five `MODULE_NAME` consts (`manager`, `resource`, `error`, `provider`, `revision`) are undocumented while `metadata`'s carries a doc line | fix: add the one-line "module declared name, asserted by the crate smoke test" doc (or fold into the A5 decision on the whole const set) | [packages/d2b-resource-runtime/src/manager.rs:51, packages/d2b-resource-runtime/src/resource.rs:36, packages/d2b-resource-runtime/src/error.rs:32, packages/d2b-resource-runtime/src/provider.rs:3] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0723` | low | `d2b-resource-runtime` | TargetControlAssignment's five methods (new, source, source_uid, assignment_generation, session_generation) are the only wire-carried type accessors without doc comments while sibling wire types (TargetResourceInstance, GuestRealizeRequest, TargetControlFrame) document every method | fix: add one-line docs to each | [packages/d2b-resource-runtime/src/guest_target.rs:205-228] | actionable | lane/d2b-resource-runtime-p2.md -- `RS-0724` | low | `d2b-resource-runtime` | constructor and accessor doc gaps on public items | fix: add one-line docs to ResourceTypeName::new/as_str, ResourceKey::new, ResourceProvenance::as_str, GuestTargetRuntime::new, TargetBinding::new, GuestTargetHandle::is_bound, SpecStore::path | [packages/d2b-resource-runtime/src/identity.rs:20, packages/d2b-resource-runtime/src/identity.rs:24, packages/d2b-resource-runtime/src/spec_store.rs:61, packages/d2b-resource-runtime/src/spec_store.rs:75] | actionable | lane/d2b-resource-runtime-p2.md - -**`d2b-resource-types`** - -- `RS-0725` | low | `d2b-resource-types` | doc comment typos in `OperationCtx::fds` ("invocation,when any", "frame,not to the handler; the handler") | fix: restore the missing spaces after the commas in the field docs | [packages/d2b-resource-types/src/operation.rs:64, packages/d2b-resource-types/src/operation.rs:65] | actionable | lane/tail-6.md - -**`d2b-session`** - -- `RS-0726` | medium | `d2b-session` | the security-critical handshake module has zero doc comments on its entire pub surface (23 pub items re-exported from lib.rs): wire functions with magic lengths and closed error codes (`x25519_public_key`, `encode_offer`, `negotiate_offer`, `accept_generation_discovery_request`, `decode_generation_discovery_response`, `NoiseHandshake`, `EstablishedHandshake`, `HandshakeCredentials`, `NegotiatedOffer`) carry no first-sentence contract, no `# Errors`, no `# Panics` | fix: add first-sentence docs plus `# Errors` sections naming the `SessionErrorCode` each function returns, and `# Panics` where a step mismatch panics | [handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239] | actionable | lane/d2b-session-p1.md -- `RS-0728` | medium | `d2b-session` | the whole public surface of lifecycle.rs, record.rs, bootstrap.rs, and deadline.rs is undocumented, including non-obvious state machines such as SessionLifecycle::poll_keepalive and begin_reconnect | fix: add item docs with # Errors sections on the Result-returning methods | [lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62] | actionable | lane/d2b-session-p2.md -- `RS-0727` | low | `d2b-session` | the magic bound `value.len() > 128` in `OperationMember::parse` is undocumented: the reader cannot tell why 128 is the canonical member spelling limit or what happens to longer wire strings | fix: extract `const MAX_MEMBER_SPELLING_LEN: usize = 128;` with a comment naming the bound's purpose (wire-visible admission bound) | [operation.rs:207] | actionable | lane/d2b-session-p1.md -- `RS-0729` | low | `d2b-session` | the route-binding accessors on AuthenticatedSessionRouteBinding, the SessionError accessors, and the TransportPacket methods are undocumented while their siblings carry docs | fix: add one-line docs to the accessors at the anchors | [admission.rs:1182, admission.rs:1186, admission.rs:1190, admission.rs:1194] | actionable | lane/d2b-session-p2.md -- `RS-0730` | low | `d2b-session` | serialized_transport_split's doc claims it exists for engine-only test transports, but production code in d2b-bus and the crate's own driver call it | fix: rewrite the doc to state the serialized-compatibility contract (halves must never be driven concurrently) | [transport.rs:208, transport.rs:212] | actionable | lane/d2b-session-p2.md - -**`d2b-session-unix`** - -- `RS-0731` | medium | `d2b-session-unix` | the exported surface is largely undocumented: the transport, credit, descriptor, pidfd, systemd and vsock types and most of their pub methods carry no doc comment (only `VerifiedUnixPeer`, `ZoneBootstrapIdentity` and a handful of methods do) | fix: add first-sentence contract docs per pub item, starting with `SeqpacketSocket`, `UnixSeqpacketTransport`/`UnixStreamTransport`, `CreditPool`, `PidfdEvidence`, `PeerCredentials`, `ActivatedSeqpacketListener`, `FramedVsockTransport` | [packages/d2b-session-unix/src/socket.rs:190, packages/d2b-session-unix/src/adapter.rs:351, packages/d2b-session-unix/src/credit.rs:22, packages/d2b-session-unix/src/pidfd.rs:9] | actionable | lane/d2b-session-unix.md -- `RS-0732` | low | `d2b-session-unix` | zero canonical `# Errors` sections exist despite roughly 60 pub `Result`-returning fns whose failure conditions are non-obvious (e.g. `SeqpacketSocket::from_owned` vs `from_parent_prearmed` vs `from_inherited_fd` fail differently) | fix: add `# Errors` sections naming the failing conditions to the pub `Result` fns | [packages/d2b-session-unix/src/socket.rs:202, packages/d2b-session-unix/src/socket.rs:210, packages/d2b-session-unix/src/socket.rs:222, packages/d2b-session-unix/src/adapter.rs:378] | actionable | lane/d2b-session-unix.md - -**`d2b-telemetry`** - -- `RS-0733` | low | `d2b-telemetry` | Result-returning public items carry no `# Errors` section stating which conditions produce which failure | fix: add `# Errors` sections to `AuditHash::parse` (audit_hash.rs:23), `AuditChainLink::verify`/`verify_at` (audit_hash.rs:103,126), `BoundedEmitter::new`/`new_with_limits`/`with_default_capacity`/`emit`/`emit_metric`/`drain`/`buffered_frames`/`buffered_bytes` (emitter.rs:183,194,228,236,316,340,385,395), `MetricFamily::new`/`record`, `MeterRegistry::register`/`record`, `RedactionGuard::new`/`validate_span_field`/`span_attributes`, `validate_resource_attributes`, and `SessionMetricsSink::record` | [packages/d2b-telemetry/src/emitter.rs:236, packages/d2b-telemetry/src/audit_hash.rs:23] | actionable | lane/d2b-telemetry.md - -**`d2b-zone-routing`** - -- `RS-0734` | low | `d2b-zone-routing` | The crate's 47 `-> Result<` public signatures document failure modes in prose paragraphs (e.g., `SealedZoneTopology::seal`, `ZoneServiceLimits::new`, `ZoneEnrollmentAuthority::with_lifetime`) but zero canonical `# Errors`/`# Panics` sections exist anywhere, so rustdoc index and IDEs lose a scannable contract | fix: add a `# Errors` section to the public validators/constructors that enforce conditions (seal, the `Limits`/`Expectation`/`Authority` constructors, `with_runtime_admission`), keeping the prose as depth beneath it | [packages/d2b-zone-routing/src/resolver.rs:80, packages/d2b-zone-routing/src/service.rs:208, packages/d2b-zone-routing/src/enrollment.rs:424] | actionable | lane/d2b-zone-routing.md - -**`d2bd`** - -- `RS-0736` | medium | `d2bd` | `pub async fn serve`, the daemon's primary entry point (composition.rs is `include!`d into lib.rs:183),has no doc comment at all, and `pub async fn lock_only` has none either; both return `Result` and carry no `# Errors` contract, so callers cannot learn from the docs what each loads/binds/runs and how it fails | fix: add a doc comment to `serve` (loads config, applies overrides, binds the operator socket, runs the accept loop; `# Errors` for config/IO/authz failures) and to `lock_only` | [packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828] | actionable | lane/d2bd-p4.md -- `RS-0741` | medium | `d2bd` | `pub fn dispatch_audio` is the only `pub` item in the lane without a doc comment; it is the daemon's audio dispatch entry with three op arms and non-obvious error behavior | fix: add a doc comment covering the op arms, the capability resolution, and the `TypedError` error surface | [packages/d2bd/src/audio_dispatch.rs:372] | actionable | lane/d2bd-p8.md -- `RS-0737` | low | `d2bd` | `StaticProviderComposition::new` is a pub constructor returning `Result` with no doc comment and no `# Errors` section, so the mode_separation.rs callers must read the body to learn it fails on `AdmissionError` | fix: one-line doc plus a `# Errors` section naming `AdmissionError` | [packages/d2bd/src/composition.rs:438] | actionable | lane/d2bd-p4.md -- `RS-0738` | low | `d2bd` | four public items in the plane's most-documented file are undocumented while their siblings carry `///` contracts: `PlaneResourceRegistry::new()`, `ZoneAuthorityInputs::controller_generation`, and the three fields of `BundleIngestReport` | fix: add the one-line contract each (constructor convenience, the zone authority's controller generation source, and per-field "the rows this ingestion applied/removed/protected") | [packages/d2bd/src/resource_plane_v3.rs:292, packages/d2bd/src/resource_plane_v3.rs:1770, packages/d2bd/src/resource_plane_v3.rs:3432] | actionable | lane/d2bd-p6.md -- `RS-0739` | low | `d2bd` | the crate root carries no `//!` module doc: lib.rs opens with the lint attribute only, and the included composition.rs begins with a plain `//` comment, so the crate's large public surface (pub mods, dozens of pub use re-exports) renders without any module-level description | fix: add a `//!` crate doc in lib.rs naming the daemon composition facets and pointing at the daemon contract references | [packages/d2bd/src/lib.rs:1, packages/d2bd/src/composition.rs:1] | actionable | lane/d2bd-p7.md -- `RS-0735` | low | `d2bd` | the public-request get deadline literal `meta.deadline_ms = 30_000` appears four times (8294, 8390, 10242, 10280) with no comment naming the why (which peer or operation enforces it) | fix: extract `const PUBLIC_GET_DEADLINE_MS: u64 = 30_000;` with a why-comment and use it at all four sites | [packages/d2bd/src/resource_runtime.rs:8294, packages/d2bd/src/resource_runtime.rs:8390, packages/d2bd/src/resource_runtime.rs:10242, packages/d2bd/src/resource_runtime.rs:10280] | actionable | lane/d2bd-p1.md -- `RS-0740` | low | `d2bd` | no canonical `# Errors`/`# Panics` section exists anywhere in the part (0 hits) while `-> Result<` appears 121 times, including on the pub surface (`FixedEffectAdapter::validate_instance`, `dispatch`, `ProviderLifecycleDispatch::new_persistent`, `admit`, `EffectServiceBinding::call`/`call_expected`, `DaemonGuestTargetSession::request`); prose paragraphs describe the happy path but failure conditions are not structurally stated | fix: add `# Errors` sections naming refusal conditions to the pub Result-returning items of the two pub mods, keeping the existing prose | [packages/d2bd/src/provider_effects.rs:91, packages/d2bd/src/provider_effects.rs:711, packages/d2bd/src/provider_effects.rs:804, packages/d2bd/src/effect_service_actors.rs:201] | actionable | lane/d2bd-p7.md -- `RS-0742` | low | `d2bd` | doc-comment shape drift in forward_rendezvous.rs first sentences: double trailing periods and missing spacing (`The received descriptors,borrowed across the invocation..`, `attached:count equal`, `...kind the carrier vocabulary does not carry..`, `awaited for readiness..`) | fix: normalize punctuation/spacing in the affected comments | [packages/d2bd/src/forward_rendezvous.rs:1046-1049, packages/d2bd/src/forward_rendezvous.rs:1070, packages/d2bd/src/forward_rendezvous.rs:1093, packages/d2bd/src/forward_rendezvous.rs:1431-1432] | actionable | lane/d2bd-p8.md - -**`d2bd-runtime`** - -- `RS-0743` | medium | `d2bd-runtime` | Three public helpers in json_io.rs carry no doc comments, though their semantics are non-obvious (absolute-vs-relative bundle path resolution, manifest-must-be-object) | fix: add one-line-then-detail doc comments (`# Errors` for the Result fns)on resolve_bundle_artifact_path and load_manifest | [json_io.rs:10, json_io.rs:41] | actionable | lane/d2bd-runtime-p1.md -- `RS-0747` | medium | `d2bd-runtime` | unsafe_local_helper.rs has no `//!` module doc and its public surface (consts `HELPER_HEARTBEAT_INTERVAL`/`HELPER_STALE_AFTER`/`HELPER_OPERATION_TIMEOUT`, enums `HelperRegistryError`/`HelperAvailability`/`HelperReply`, struct `HelperRegistry` + its seven pub methods) carries no doc comments, unlike every sibling module in this crate | fix: add a `//!` header (lifecycle, wire protocol, thread model, redaction rules) and one-line `///` docs per pub item | [packages/d2bd-runtime/src/unsafe_local_helper.rs:1, packages/d2bd-runtime/src/unsafe_local_helper.rs:33, packages/d2bd-runtime/src/unsafe_local_helper.rs:42, packages/d2bd-runtime/src/unsafe_local_helper.rs:65] | actionable | lane/d2bd-runtime-p3.md -- `RS-0744` | medium | `d2bd-runtime` | Public fns in vm_start_support.rs lack docs while siblings are documented; role->mode mapping, tracked_role_id, and store-view-intent resolution are contract-relevant for the d2bd composition | fix: add one-line-first-sentence docs (+ `# Errors` for the Result fn)on vm_start_node_mode, tracked_role_id, resolve_store_view_intent_for_guest | [vm_start_support.rs:14, vm_start_support.rs:44, vm_start_support.rs:89] | actionable | lane/d2bd-runtime-p1.md -- `RS-0748` | medium | `d2bd-runtime` | public exec-session DTO fields lack doc comments on a cross-crate contract surface (`ExecStartSpec.vm/argv/tty/detached/env/cwd/term_size`, `ExecSessionInfo.tty/stdout_offset/stderr_offset`, `Established.client/info/control_seq/caps`, `WorkerSpawn.connector/spec/deadlines/establish_tx/control_rx`), while sibling fields (`request_id`, `NegotiatedCaps.*`, `TerminalReaper`/`SessionSlot` fields) are documented | fix: add `///` per field (semantics plus any redaction/derivation promise), especially what `control_seq`/`establish_tx` carry | [packages/d2bd-runtime/src/exec_session.rs:181, packages/d2bd-runtime/src/exec_session.rs:211, packages/d2bd-runtime/src/exec_session.rs:249, packages/d2bd-runtime/src/exec_session.rs:882] | actionable | lane/d2bd-runtime-p3.md -- `RS-0749` | medium | `d2bd-runtime` | readiness.rs exposes seven undocumented pub predicates/functions (`readiness_predicate_ready`, `unix_socket_exists`, `unix_socket_listening`, `tcp_port_ready`, `wait_for_tcp_port`, `command_ready`, `readiness_predicate_ready_async`) whose contracts are non-obvious (e.g. `unix_socket_listening` parses `/proc/net/unix` flags;`command_ready` strips `NOTIFY_SOCKET`), while `api_socket_info_ready`/`wait_for_readiness_async` do carry `///` | fix: add one-line `///` first sentences + `# Errors` notes on the `Result<_, String>` shapes | [packages/d2bd-runtime/src/readiness.rs:15, packages/d2bd-runtime/src/readiness.rs:78, packages/d2bd-runtime/src/readiness.rs:85, packages/d2bd-runtime/src/readiness.rs:103] | actionable | lane/d2bd-runtime-p3.md -- `RS-0745` | medium | `d2bd-runtime` | Five broker_transport helpers (audit-join extraction, deadline arithmetic, kind extraction, two launcher redaction renderers)carry no docs, and two of them format operator-facing remediation strings | fix: add one-line-first-sentence docs naming input contracts and output shapes, with `# Panics` on default_audit_join_context identified | [broker_transport.rs:60, broker_transport.rs:69, broker_transport.rs:116, broker_transport.rs:128] | actionable | lane/d2bd-runtime-p1.md -- `RS-0746` | low | `d2bd-runtime` | the `has_posix_acl` doc first sentence begins with an unexplained `v1.1.2fu25:` audit-workflow token, and a sibling `P2fu1 ...` workflow tag sits inside an enabled trace field comment list | fix: drop/relocate the workflow tokens so the rendered contract reads plain, keeping the "0440-with-ACL legitimate vs drift" why in the body (it is the good part) | [ssh_host_key_preflight.rs:312, ssh_host_key_preflight.rs:298-301] | actionable | lane/d2bd-runtime-p2.md -- `RS-0750` | low | `d2bd-runtime` | `ch_api.rs` leaves its public constants, error enum, info struct, and async entry points undocumented: `DEFAULT_TIMEOUT`/`MAX_RESPONSE_BYTES` are magic values without the why (contrast `CH_HTTP_TIMEOUT` at ch_stats.rs:120 which cites the legacy exporter), and `ChApiError` variants/`ChVmInfo` fields/`get_vm_info`/`shutdown_vm` have no docs | fix: document the consts with their provenance and add one-line docs to the enum, struct, and fns | [packages/d2bd-runtime/src/ch_api.rs:11, packages/d2bd-runtime/src/ch_api.rs:15, packages/d2bd-runtime/src/ch_api.rs:37, packages/d2bd-runtime/src/ch_api.rs:43] | actionable | lane/d2bd-runtime-p4.md -- `RS-0751` | low | `d2bd-runtime` | `target_runtime.rs` documents its domain types thoroughly but leaves a cluster of pub accessors undocumented: `AdmissionBudget::new/limits/active`, `AdmissionPermit::kind/release`, `ProviderDeployment::mode/target_kind/admission` | fix: add one-line docs (at minimum to `AdmissionPermit::release`, whose idempotence is a caller-relevant contract) | [packages/d2bd-runtime/src/target_runtime.rs:256, packages/d2bd-runtime/src/target_runtime.rs:311, packages/d2bd-runtime/src/target_runtime.rs:354, packages/d2bd-runtime/src/target_runtime.rs:1108] | actionable | lane/d2bd-runtime-p4.md - -**`xtask`** - -- `RS-0755` | medium | `xtask` | Pub field groups on the wire and census record types carry no field-level doc contracts, so units and serialization formats are guesswork | fix: add per-field doc comments to `DeniedApi.path/tail/kind`, `CensusBaseline.crates`, `OutputDigest.sha256/bytes`, `EvidenceRecord.*`, `SealedLane.lane/validations`, `SealedValidation.validation/record_sha256`, `SealRecord.*` | [packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packages/xtask/src/delivery/evidence.rs:120, packages/xtask/src/delivery/evidence.rs:128] | actionable | lane/xtask-p5.md -- `RS-0756` | low | `xtask` | Result-returning pub fns describe failure modes in prose rather than the canonical `# Errors` section | fix: add `# Errors` sections to `parse_fragment`, `EvidenceLane::parse`, `EvidenceRecord::validate`, `SealRecord::validate`, and `async_gate::scan_source` naming each rejection condition | [packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/xtask/src/delivery/evidence.rs:162, packages/xtask/src/delivery/seal.rs:77] | actionable | lane/xtask-p5.md -- `RS-0754` | low | `xtask` | several pub items in the delivery modules lack the doc comment the modules' own discipline gives every sibling item: `WaveSnapshot::digests`/`program`/`wave`, `WaveCommand::as_str`/`parse`/`required_options`/`optional_options`, `WorkflowOutput::ok`/`with_digests`, `WorkflowCommandHelp`, and the `CliOptions` accessors | fix: add one-line doc comments naming each contract (mirroring the sibling wording already present) | [packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, packages/xtask/src/delivery/snapshot.rs:99, packages/xtask/src/delivery/command.rs:104] | actionable | lane/xtask-p3.md -- `RS-0752` | low | `xtask` | doc comments across the policy range carry text-corruption artifacts from an earlier automated rewrite: 20 lines end with a stray `/` after the closing period (`/// ... only shrinking from here./`) and 4+ comments have doubled opening parens (`((its Cargo package name).`, `((an edit to a`), plus the typo `whiche is what`; the artifacts render as odd punctuation in rustdoc and rot the file's readability | fix: mechanical doc cleanup over the file: replace `\./$` with `.` and `((`-doubles with single parens on the doc lines (lines 5360-6556 and 8428, 8640, 8648, 9043) | [packages/xtask/src/provider_crate_policy.rs:5360, packages/xtask/src/provider_crate_policy.rs:8428, packages/xtask/src/provider_crate_policy.rs:9043] | actionable | lane/xtask-p1.md -- `RS-0753` | low | `xtask` | `civil_from_days` (a port of the Howard Hinnant civil-calendar conversion) carries magic constants (719_468, 146_097, 146_096, 36_524, 153) with no citation or why, and `today_utc_iso8601` silently maps a before-epoch clock to epoch via `unwrap_or(0)` | fix: add a doc comment naming the algorithm and its constants, and decide the before-epoch behaviour explicitly (return an error or a documented fallback) | [packages/xtask/src/main.rs:1555, packages/xtask/src/main.rs:1544] | actionable | lane/xtask-p1.md - -### `perf` - -Performance (static unless a benchmark exists): allocation out of hot paths, collection choice, codegen flags as the last five percent. - -**`d2b`** - -- `RS-0771` | medium | `d2b` | every received frame allocates and zeroes a fresh 1 MiB buffer and then copies the payload again, on the interactive shell path where the daemon answers each 50 ms poll round trip | fix: keep a reusable receive buffer (e.g. a Vec field on CliSocket reused across read_frame calls, or a thread-local scratch) so the zeroed 1 MiB allocation happens once, and return the truncated buffer instead of `frame[FRAME_PREFIX_BYTES..].to_vec()` | [context.rs:570, context.rs:538] | actionable | lane/d2b-p1.md - -**`d2b-audit`** - -- `RS-0757` | low | `d2b-audit` | `scan_chain_state` converts each line with `String::from_utf8(bytes)` then `serde_json::from_str`, allocating a String per record during the open-time scan, while `segment_tail_hash` parses the same JSONL shape with `serde_json::from_slice(&line)`; use `from_slice` here too | fix: replace the from_utf8/from_str pair with `serde_json::from_slice(&bytes)` at sink.rs:386-388 | [packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970] | actionable | lane/d2b-audit.md - -**`d2b-broker`** - -- `RS-0762` | medium | `d2b-broker` | recv_json_frame allocates and zeroes a 1 MiB buffer (`MAX_FRAME_SIZE + 4`)per received frame on every broker/client envelope path | fix: peek the 4-byte length prefix (`recvmsg` with `MSG_PEEK`)then allocate `declared + 4` exactly,, or thread a reusable buffer through the receive path; apply the same size-exactness to `recv_json_frame_with_fds` | [packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125] | actionable | lane/d2b-broker-p7.md -- `RS-0759` | low | `d2b-broker` | `projection_digest` builds the hex digest with `raw.iter().map(|byte| format!("{byte:02x}")).collect::()`, allocating one `String` per byte (32 hex bytes) before the final collect | fix: `String::with_capacity(70)` and `write!`/`push_str` each byte, or a 16-entry hex lookup | [packages/d2b-broker/src/ops/nft.rs:784-790] | actionable | lane/d2b-broker-p5.md -- `RS-0760` | low | `d2b-broker` | `handle_open_cgroup_dir` renders `canonical_path.display().to_string()` twice (the audit field at 341 and the outcome at 368) in the same call | fix: bind `let cgroup_id = canonical_path.display().to_string();` once and reuse for both the audit record and `OpenCgroupDirOutcome` | [packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368] | actionable | lane/d2b-broker-p5.md -- `RS-0758` | low | `d2b-broker` | `CellStore` partial-key lookups scan the whole record map: `contains` (state_cells.rs:470), `payload` (488), `remove` (506), `keys` (524) and `clear` (541) iterate `records: BTreeMap` filtering on (cell, invocation_id) because the principal is a key component, making every op O(n) where the durable file already uses the nested cell -> invocation layout | fix: mirror the durable layout in memory (cell -> invocation -> record, principal inside the record) so lookups become O(log n); static (unmeasured) | [packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, packages/d2b-broker/src/state_cells.rs:524] | actionable | lane/d2b-broker-p3.md -- `RS-0761` | low | `d2b-broker` | contract_store_view_levels re-parses the embedded `include_str!` JSON contract (STATE_POSTURE_CONTRACT) on every call (down per-VM posture passes; each row also re-parses the contract via contract_store_view_level, so the same ~600-line document is parsed many times per sync pass. | fix: pre-parse once into a `static CONTRACT: LazyLock` (or `OnceLock`|and resolve per-row levels/profiles from the cached parse, deleting per-call `ContractFile::parse` sites. | [src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/store_view_posture.rs:310-352] | actionable | lane/d2b-broker-p6.md - -**`d2b-bus`** - -- `RS-0763` | low | `d2b-bus` | The WatchSink delivery path copies every watch frame payload with frame.payload().to_vec() before send_and_wait_ack, allocating a fresh Vec per frame on the watch-delivery path (the recorded kept-half credit path, B1, docs/explanation/over-engineering-audit-record.md:463) | fix: pass the payload slice through OutgoingStream::send_and_wait_ack (streams.rs:661) or clone once at the bridge so per-frame allocation is avoided | [packages/d2b-bus/src/router.rs:4228-4235] | actionable | lane/d2b-bus-p1.md -- `RS-0764` | low | `d2b-bus` | `OutgoingStream::send_wait` clones the whole payload on every backpressure wakeup because `StreamBridge::send` consumes the `Vec` and drops it on rejection, so a frame up to `max_frame_bytes` (64 KiB) is re-allocated per retry on the bounded-watch delivery path | fix: have `send` return the rejected payload (for example `Result<(), (StreamError, Vec)>`) or split an admit-check from the enqueue so the loop moves the buffer instead of cloning | [packages/d2b-bus/src/streams.rs:642-658] | actionable | lane/d2b-bus-p2.md - -**`d2b-contracts-resource`** - -- `RS-0765` | low | `d2b-contracts-resource` | `ResourceStatus::new` (resource_status.rs:636-658) serializes the complete status with `canonical_json_bytes(&value)` on every construction to enforce MAX_STATUS_BYTES, after `ensure_layer_size` already serialized the resource layer, so each status write pays two full serializations of the same object | fix: enforce the byte bound once at the write boundary (the caller already serializes for storage) or check the bound with a cheaper size pass; at minimum reuse the layer bytes from `ensure_layer_size` | [packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-resource/src/v3/resource_status.rs:650] | actionable | lane/d2b-contracts-resource-p1.md - -**`d2b-contracts-zone-session`** - -- `RS-0766` | low | `d2b-contracts-zone-session` | ProcessTemplateBinding validation builds a fresh String via format!("/bin/{}", ...) on every construction to run an ends_with check | fix: binary_path.strip_suffix(binary_ref.as_str()).is_some_and(|prefix| prefix.ends_with("/bin/")) which is allocation-free | [resource_bundle.rs:382] | actionable | lane/d2b-contracts-zone-session-p2.md - -**`d2b-core`** - -- `RS-0767` | medium | `d2b-core` | has_zone_uid re-parses every zone resource bundle on each call and zone_uid / find_network_spec re-parse bundle JSON per lookup (ResourceBundle::from_json over raw bytes), while parsed_zone_resources (populated once at load, line 1462) already holds the parsed ResourceBundle per zone | fix: have has_zone_uid, zone_uid, and find_network_spec iterate or index parsed_zone_resources instead of re-parsing bytes | [packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:1647, packages/d2b-core/src/bundle_resolver.rs:1959] | actionable | lane/d2b-core-p1.md -- `RS-0768` | low | `d2b-core` | the nft/hosts renderers build text with `buf.push_str(&format!(...))`, allocating a fresh String per line then copying it into the buffer (render_host_nft_script, render_env_nft_subset, render_hosts_managed_block), and sha256_hex collects 32 per-byte `format!("{b:02x}")` Strings | fix: `write!(&mut buf, ...)` into the existing buffer (std::fmt::Write) and hex-encode into a fixed `[u8; 64]` buffer or a single format call | [packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:3793, packages/d2b-core/src/bundle_resolver.rs:3986, packages/d2b-core/src/bundle_resolver.rs:1009] | actionable | lane/d2b-core-p1.md -- `RS-0769` | low | `d2b-core` | six composite-key lookups allocate two Strings per call (`(zone.to_owned(), guest.to_owned())`) against BTreeMap<(String, String), _> maps (guest_setup_descriptors, guest_setup_descriptor_catalog_keys, guest_vmm_intents, guest_vmm_zone_uids) | fix: introduce a `ZoneGuestKey(String, String)` newtype with a `Borrow<(str, str)>` impl so lookups borrow without allocating, or nest the maps per zone | [packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:1617, packages/d2b-core/src/bundle_resolver.rs:2068, packages/d2b-core/src/bundle_resolver.rs:2087] | actionable | lane/d2b-core-p1.md - -**`d2b-host`** - -- `RS-0770` | low | `d2b-host` | Hex digests are built with `format!("{b:02x}")` per byte, allocating a fresh String per byte (32+ allocations per digest) in `Sha256::of` and `generation_id` | fix: write into one preallocated `String::with_capacity(64)` via `write!`/`fmt::Write`, or share a hex helper | [packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628] | actionable | lane/d2b-host.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0772` | low | `d2b-provider-clipboard-wayland` | clipboard payload maps (up to MATERIALIZE_MAX_BYTES = 8 MiB) are cloned wholesale on the host-selection record, history materialization, and bridge-copy publish paths, copying every byte per paste | fix: hold payloads as Arc>> (or Arc<[u8]> per MIME) in ClipboardHistoryEntry, BridgeSelectionState, and PublishedSelectionState so materialization and publish become refcount bumps; the history-retention clones at 757 and 1043 disappear | [src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2b-clipd.rs:1838] | actionable | lane/d2b-provider-clipboard-wayland-p1.md -- `RS-0773` | low | `d2b-provider-clipboard-wayland` | read_bounded_ndjson_line reads one byte per read() syscall in a loop (up to DEFAULT_NIRI_MAX_LINE_BYTES = 1 MiB iterations for a maximal line), an avoidable syscall-per-byte pattern on the niri IPC path | fix: read into a stack chunk buffer (e.g. 4 KiB) with the same max-line accounting, or wrap the stream in a BufReader | [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159] | actionable | lane/d2b-provider-clipboard-wayland-p2.md merged: d2b-provider-clipboard-wayland-p2#3 - -**`d2b-provider-config-nixos`** - -- `RS-0774` | low | `d2b-provider-config-nixos` | the RPC path parses the request JSON up to three times per call: handler `from_slice` (ttrpc.rs:326), `validate_operation` `from_value` plus the full-document base64 decode for Stage (controller.rs:298-331), and the backend dispatch `from_value` again (ttrpc.rs:81); Stage payloads can reach ~683 KiB base64 | fix: decode the typed request once in `ConfigMethod::handler`, validate the typed value, and pass the original `Value` to the backend hop (removes one parse and the admission-time document decode) | [packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/ttrpc.rs:326, packages/d2b-provider-config-nixos/src/ttrpc.rs:81] | actionable | lane/d2b-provider-config-nixos.md merged: d2b-provider-config-nixos#2 - -**`d2b-provider-display-wayland`** - -- `RS-0775` | low | `d2b-provider-display-wayland` | `durable_display_suffix` (session_children.rs:316-318) builds a 40-char hex suffix with one `format!` allocation per byte (20 allocations) instead of writing into the already-preallocated `String::with_capacity(40)` | fix: push two hex digits per byte via a lookup table or a single hex write into `suffix`, keeping the preallocation | [src/session_children.rs:316, src/session_children.rs:317] | actionable | lane/d2b-provider-display-wayland-p2.md - -**`d2b-provider-guest`** - -- `RS-0776` | low | `d2b-provider-guest` | Two hex-ID builders format a fresh String per byte ((driver.rs:863-868 map(|byte| format!("{byte:02x}")) into a String, effects_service.rs:983-988 push_str(&format!)...)) in a loop), allocating ~16 and ~8 Strings per reconcile pass | fix: write! to one with_capacity String per builder (or a crate-local hex helper reusing the buffer | [packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:868, packages/d2b-provider-guest/src/effects_service.rs:983, packages/d2b-provider-guest/src/effects_service.rs:988] | actionable | lane/d2b-provider-guest.md - -**`d2b-provider-guest-cloud-hypervisor`** - -- `RS-0777` | low | `d2b-provider-guest-cloud-hypervisor` | `child_role_for_ref` (shutdown.rs:505) builds `format!("-{}", role.suffix())` inside the per-role loop, four String allocations per call on the per-child planning path (`plan_upgrade` at controller.rs:2340, `project_status` at controller.rs:2940) | fix: use `name.rsplit_once('-')` and compare the suffix, or a static suffix table | [shutdown.rs:505-513] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0778` | low | `d2b-provider-guest-qemu-media` | `LaunchTicket::new` grows `attachments` by push from a fresh `Vec::new()` with an a-priori known upper bound (up to media_refs.len()+3 slots (packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239-274) | fix: `Vec::with_capacity(media_refs.len() + 3)` ( (static (unmeasured. | [packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-network-local`** - -- `RS-0779` | low | `d2b-provider-network-local` | FirewallDigest::to_hex formats each byte into its own String (32 heap allocations per call), though the output size is known | fix: `let mut out = String::with_capacity(64); for byte in &self.0 { use std::fmt::Write; write!(out, "{byte:02x}").expect("writing to String is infallible"); } out` | [src/nftables.rs:266-268] | actionable | lane/d2b-provider-network-local.md -- `RS-0780` | low | `d2b-provider-network-local` | observed-address parse allocatesa fresh String per entry via `format!("{local}/{prefix}")`, inside the host-observation parse path | fix: build the CIDR text into a reused buffer or add a two-part Ipv4Cidr constructor to the contracts crate | [src/observe.rs:305] | actionable | lane/d2b-provider-network-local.md - -**`d2b-provider-notification-desktop`** - -- `RS-0781` | low | `d2b-provider-notification-desktop` | `NotificationSink::deliver` formats "notification-{id}" once (request_id) but re-formats the same string three more times into projection map keys; `close` re-formats from u32 while callers already hold the request_id string | fix: reuse `request_id` (clone it into map keys where needed)and add an internal `close_by_request_id(&str)` to kill the u32-to-String-to-u32 round-trip in `close_session`/`gc_projections` | [packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-notification-desktop/src/host_sink.rs:276-291, packages/d2b-provider-notification-desktop/src/host_sink.rs:376, packages/d2b-provider-notification-desktop/src/host_sink.rs:484-493] | actionable | lane/d2b-provider-notification-desktop.md - -**`d2b-provider-observability-otel`** - -- `RS-0782` | low | `d2b-provider-observability-otel` | drain_once allocates a fresh 64KiB+1 scratch buffer per datagram inside the drain loop ( <= 256 iterations/call),when one buffer reused across recv calls would suffice | fix: hoist `let mut bytes = vec![0_u8; MAX_COMPACT_FRAME_BYTES + 1];` above the while loop,and `bytes.resize(MAX_COMPACT_FRAME_BYTES + 1, 0)` per iteration; the queued redacted frame remains its own owned Vec from redact_parsed_frame | [emitter_socket.rs:139] | actionable | lane/d2b-provider-observability-otel.md -- `RS-0783` | low | `d2b-provider-observability-otel` | admit_for_connection re-measures every frame by re-serializing the whole MetricFrame to JSON(allocating a Value tree plus a String per admission),though the wire-boundary paths already carry `encoded_bytes` | fix: thread the canonical measured size through from the decode boundary (admit_raw/admit_parsed/metric_frame_from_raw) instead of re-calling measured_encoded_bytes in admit_for_connection, preserving the documented trustless measurement at the boundary(ingress_policy.rs:202-203)rather than per admission | [ingress_policy.rs:203, ingress_policy.rs:368] | actionable | lane/d2b-provider-observability-otel.md -- `RS-0784` | low | `d2b-provider-observability-otel` | valid_resource_attribute_value allocates a lowercase copy of each attribute value(`to_ascii_lowercase()`)on the per-frame resource-attribute validation path,only to substring-test six words | fix: replace the allocation with a case-insensitive byte-scan helper(e.g. a local `contains_ignore_ascii_case(value, word)`)over the already-bounded( <= 256-byte)value | [metric_policy.rs:44] | actionable | lane/d2b-provider-observability-otel.md - -**`d2b-provider-process-systemd`** - -- `RS-0785` | low | `d2b-provider-process-systemd` | `unit_name` builds the hex suffix with `format!` inside a 16-iteration loop (16 small String allocations) plus a final `format!`, on every unit operation that names a unit | fix: write the bytes into the preallocated `String::with_capacity(52)` with `write!` per byte, or format once into a fixed buffer | [packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process-systemd/src/operations.rs:421] | actionable | lane/d2b-provider-process-systemd.md - -**`d2b-provider-toolkit`** - -- `RS-0786` | medium | `d2b-provider-toolkit` | every reconcile and delete pass clones the row's full spec document (`spec: envelope.value().clone()` at shared_provider.rs:944 and 1024) into the request even though the envelope outlives the effect call and the request is only read by the family | fix: change `SharedProviderEffectRequest.spec` from `Value` to `&'a Value` (the struct is constructed only in this file; family call sites read via method calls and auto-deref), removing one full-spec allocation per pass | [packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/src/shared_provider.rs:1024, packages/d2b-provider-toolkit/src/shared_provider.rs:479-481] | actionable | lane/d2b-provider-toolkit-p2.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0787` | medium | `d2b-provider-transport-azure-relay` | `generation_key` allocates three Strings (`to_owned` x3) on every `RelayConnection::send`/`receive` via `ensure_current_generation -> is_current`, and the key is invariant for a connection's lifetime (it derives from the binding the connection already owns) | fix: precompute the `(String, String, String)` key once in `RelayConnection` (or key the fence map on a borrowed/hashed form) and pass it to `is_current`, removing three heap allocations from the per-frame I/O path | [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:629-630, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:814, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:844] | actionable | lane/d2b-provider-transport-azure-relay.md -- `RS-0788` | low | `d2b-provider-transport-azure-relay` | `read_policy_file` grows `Zeroizing::new(Vec::new())` via `read_to_end` without a capacity hint although the file size is already known from the earlier `metadata()` call | fix: `Vec::with_capacity(meta.len() as usize)` before reading | [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-volume`** - -- `RS-0789` | low | `d2b-provider-volume` | `reconcile` performs two identical `ctx.children()` manager round-trips per pass:`reconcile_children` already fetched the owned child set after ensures (to retire obsolete),andthen `reconcile` re-fetches the same set to compute `converged` - an extra manager RPC per reconcile pass | fix: have `reconcile_children` return the fetched `Vec` (or compute the converged verdict inside)and consume it there | [driver.rs:437-440, driver.rs:614-617] | actionable | lane/d2b-provider-volume.md - -**`d2b-resource-api`** - -- `RS-0791` | medium | `d2b-resource-api` | `commit_mutation` clones the full canonical resource (up to 256 KiB) on every UpdateSpec/UpdateMetadata before the byte-identical no-op check, so a no-op update pays the whole copy | fix: compare `mutation.canonical_resource.as_deref() == Some(row.spec.as_slice())` first and return the committed view early, cloning only when the bytes actually differ | [manager_backend.rs:1006] | actionable | lane/d2b-resource-api-p1.md -- `RS-0792` | medium | `d2b-resource-api` | `owner_key_for` resolves a mutation's owner by listing the entire Zone row set (`manager.list(ResourceSelector::default())`) and linear-searching for the owner uid, on every Delete and every owner-less UpdateSpec/UpdateMetadata/UpdateFinalizers | fix: expose a manager-side uid-to-key lookup on `ResourceManagerClient` (d2b-resource-runtime) or return the owner key from `get_row`, and call it instead of the full-zone list | [manager_backend.rs:1081-1103, manager_backend.rs:1090] | actionable | lane/d2b-resource-api-p1.md -- `RS-0793` | low | `d2b-resource-api` | `compile_authorization_facts` grows its roles and bindings Vecs by push although the row count is known upfront | fix: `Vec::with_capacity(rows.len())` for both | [packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458] | actionable | lane/d2b-resource-api-p2.md -- `RS-0790` | low | `d2b-resource-api` | `encode_list_cursor` hex-encodes each cursor key byte with a per-byte `format!("{byte:02x}")` allocation, and duplicates the hex encoder already present as the local `hex` closure in `list_selector_digest` | fix: extract one `fn hex(bytes: &[u8]) -> String` (with `String::with_capacity(bytes.len() * 2)` and `write!`/`char::from_digit`) and call it from both sites | [manager_backend.rs:495, manager_backend.rs:449-455] | actionable | lane/d2b-resource-api-p1.md - -**`d2b-resource-runtime`** - -- `RS-0794` | low | `d2b-resource-runtime` | `reconcile_children`'s obsolete scan clones every owned `StoredDesiredResource` row (spec and metadata byte vectors included) into a `Vec` when only the keys are needed to drive `remove_internal` | fix: collect `row.key.clone()` only, or iterate `state.rows` by reference and call `remove_internal(&subject, &child.key)` | [packages/d2b-resource-runtime/src/manager.rs:1390] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0795` | low | `d2b-resource-runtime` | hex rendering allocates a fresh String per byte via format! inside the loop at two sites | fix: write!(&mut rendered, "{byte:02x}") with use std::fmt::Write into the pre-sized String | [packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/guest_target.rs:1212] | actionable | lane/d2b-resource-runtime-p2.md - -**`d2b-session`** - -- `RS-0796` | low | `d2b-session` | unprotect allocates a fresh plaintext buffer sized to the limit and copies the payload out with to_vec on every received record | fix: keep a reusable scratch buffer on RecordProtector and return plaintext.split_off(RECORD_HEADER_LEN) instead of payload.to_vec() | [record.rs:125, record.rs:147] | actionable | lane/d2b-session-p2.md -- `RS-0797` | low | `d2b-session` | flush copies every dequeued logical frame with as_bytes().to_vec() because OutboundFrame only exposes a borrowed view | fix: add OutboundFrame::into_bytes() in scheduler.rs and consume it in flush | [engine.rs:1354, engine.rs:1362, scheduler.rs:72] | actionable | lane/d2b-session-p2.md -- `RS-0798` | low | `d2b-session` | the replay cache is a VecDeque scanned linearly with contains() on every received record | fix: use a bounded HashSet<[u8; 32]> or document why the 1024-entry linear scan is acceptable | [record.rs:120, record.rs:146] | actionable | lane/d2b-session-p2.md - -**`d2b-session-unix`** - -- `RS-0799` | low | `d2b-session-unix` | burst and collector `Vec`s grow from empty with an exact known upper bound, reallocating on the way | fix: `Vec::with_capacity(fairness_budget)` in `recv_burst`/`send_burst` and `Vec::with_capacity(attachments.len())` in `send_packet` | [packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, packages/d2b-session-unix/src/adapter.rs:540] | actionable | lane/d2b-session-unix.md - -**`d2bd`** - -- `RS-0800` | medium | `d2bd` | three arms of `CloudHypervisorResourceSession::call` compute an operation id that is immediately discarded: `UpdateSpec` (2360-2364), `UpdateStatus` (2489-2505, `let _ = &operation_id`), and `DeleteChild` (2856-2859, `let _operation_id`) each build `operation_payload` and run a full SHA-256 `canonical_digest` plus a `format!` allocation that no caller reads - this runs on every provider status/spec update, i.e. every reconcile pass | fix: delete the dead digest/format computation and the `let _` bindings in all three arms | [packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, packages/d2bd/src/resource_runtime.rs:2505, packages/d2bd/src/resource_runtime.rs:2856] | actionable | lane/d2bd-p1.md -- `RS-0801` | low | `d2bd` | `resource_identity_fields` builds a `Vec` with exactly 12 statically-known pushes on every launch/adoption pass but grows from an empty `Vec::new()` | fix: `let mut fields = Vec::with_capacity(12);` (6 required + 6 optional entries) | [packages/d2bd/src/process_provider_runtime.rs:333] | actionable | lane/d2bd-p7.md -- `RS-0802` | low | `d2bd` | `AsyncSeqpacket::read_frame` allocates a fresh `vec![0u8; MAX_FRAME_SIZE + 5]` (1 MiB) per read, and `drain_pending` performs up to four such reads per refused call; the frame is length-prefixed, so the read buffer can be sized from the 4-byte prefix (or drained onto a reused buffer) instead of the full ceiling | fix: read the prefix, then allocate `declared + 5` | [packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476-1481] | actionable | lane/d2bd-p8.md -- `RS-0803` | low | `d2bd` | grow-by-push vectors with known upper bounds: `guest_uids = Vec::new()` (bound `spec.attachments().len()`) and `entries`/`errors = Vec::new()` (bound `vm_names.len()`) | fix: `Vec::with_capacity()` | [packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.rs:392-396] | actionable | lane/d2bd-p8.md merged: d2bd-p8#4 - -**`d2bd-runtime`** - -- `RS-0804` | low | `d2bd-runtime` | load_list/load_status clone the entire cached serde_json::Value frame per call (`then(|| cached.value.clone())`), making every public status/list poll allocate a full copy of the read-model frame | fix: return `Option>` (or `&Value` tied to the Arc swap guard)from load_if_fresh and let the wire renderer borrow the Value; update the d2bd composition call sites | [public_read_model.rs:117-118] | actionable | lane/d2bd-runtime-p1.md - -**`xtask`** - -- `RS-0808` | low | `xtask` | `contains_quoted_field` allocates two `format!`'d quoted literals per field per quote inside the per-line redaction scan, up to 8 small String allocations per log line | fix: frame the four credential field names once per `redact_text` call (or as module `const` literals( and pass `&[&str]` framed forms to `contains_quoted_field` so the per-line scan only does `.contains)...)` | [packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packages/xtask/src/bazel_evidence.rs:407] | actionable | lane/xtask-p5.md -- `RS-0805` | low | `xtask` | `message_only_proto` calls `trimmed.starts_with(&format!("service {service_name} "))` inside the per-line loop, allocating a String on every line of the proto file when the prefix never changes | fix: hoist `let marker = format!("service {service_name} ");` (or compare `trimmed.strip_prefix("service ")` then the name) above the loop | [packages/xtask/src/main.rs:431] | actionable | lane/xtask-p1.md -- `RS-0806` | low | `xtask` | `repo_root()` returns `Ok(Box::leak(path.into_boxed_path()))`, so every successful call leaks a heap allocation and re-scans env vars and parent directories; it is called by nearly every command handler | fix: cache the result once, e.g. `static ROOT: OnceLock<&'static Path>` (std, no dependency) computed on first call | [packages/xtask/src/main.rs:582] | actionable | lane/xtask-p1.md -- `RS-0807` | low | `xtask` | `render_schema(&RootSchema)` clones the entire schema document (large `serde_json::Value` trees for the 19 `schema_for!` documents) only to override `meta_schema` before serializing | fix: have `write_schemas` take ownership of the `Vec<(&str, RootSchema)>` and mutate each schema in place (callers already hold the schemas by value from `schema_documents()`) | [packages/xtask/src/main.rs:972] | actionable | lane/xtask-p1.md - -### `conc` - -Concurrency model from workload shape: data parallelism, scoped threads, channels, shared state last; weakest correct ordering. - -**`X3-cross-crate-duplication`** - -- `RS-0960` | medium | `X3-cross-crate-duplication` | parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-census-baseline.json, `parking_lot::Mutex::lock: 0` for every crate) key on the path `parking_lot::Mutex::lock`, which never resolves because `parking_lot::Mutex` is a type alias (`pub type Mutex = lock_api::Mutex`), so unsuppressed lock sites in 10+ crates record zero hits and no per-site allow is demanded | fix: configure the disallowed entry and the census DeniedApi list on the resolved path (`lock_api::Mutex::lock`, or the def-path clippy reports for the alias), then re-run the census so the unsuppressed sites surface and get per-site allows or conversions per the KD3 ban | [clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-security-key/src/relay_service.rs:129] | policy-confirmed | lane/X3-cross-crate-duplication.md - -**`d2b-broker`** - -- `RS-0809` | low | `d2b-broker` | the invocation-id counter uses `Ordering::AcqRel` (`self.invocations.fetch_add(1, Ordering::AcqRel)`), but no reader of the counter or its derived id synchronizes on it - the returned old value is consumed only by the calling thread/audit record, so Relaxed is the weakest correct ordering. | fix: use `Ordering::Relaxed` at src/envelope/mod.rs:1146 (and at the test double's `observed.fetch_add` at src/envelope/mod.rs:2144). | [src/envelope/mod.rs:1146, src/envelope/mod.rs:2144] | actionable | lane/d2b-broker-p6.md - -**`d2b-bus`** - -- `RS-0810` | low | `d2b-bus` | RouteLeaseState wraps a single bool in Mutex, paying a lock for one flag that an atomic would serve | fix: replace revoked: Mutex with AtomicBool and use Acquire/Release in with_active and remove | [packages/d2b-bus/src/registry.rs:522-523, packages/d2b-bus/src/registry.rs:573-582] | actionable | lane/d2b-bus-p1.md - -**`d2b-contracts-provider`** - -- `RS-0811` | low | `d2b-contracts-provider` | `SensitiveDeliveryRecord` uses `Ordering::SeqCst` for per-byte loads and stores that have no release/acquire pairing with any other atomic, so the strongest ordering buys nothing | fix: use `Ordering::Relaxed` in `copy_to`, `clear`, and `is_zeroized` | [packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-provider/src/v3/credential/service.rs:963, packages/d2b-contracts-provider/src/v3/credential/service.rs:977] | actionable | lane/d2b-contracts-provider-p1.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0812` | low | `d2b-provider-clipboard-wayland` | the two permit counters use Acquire/AcqRel orderings where Relaxed is the weakest correct ordering, since neither counter publishes any data (the permit and descriptor ownership move by value) | fix: switch FdPermitPool.active and HELPER_THREADS to Ordering::Relaxed for load, CAS, and fetch_sub | [src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96] | actionable | lane/d2b-provider-clipboard-wayland-p1.md - -**`d2b-provider-credential`** - -- `RS-0813` | medium | `d2b-provider-credential` | `parking_lot::Mutex` is used throughout the test-support recorder and test fixtures (test_support.rs:18,30,41-46,97-113,159,233-249; driver.rs:1053,1074-1075,1109-1172; session.rs:315,429) despite the recorded outright ban whose only exception is the R4 bounded-worker boundary, and the impl methods holding most `.lock()` calls carry no per-site `#[allow(clippy::disallowed_methods)]` even though the test fns do (`reason = "cfg(test) helper"`, the sanctioned form) | fix: switch the recorder locks to `tokio::sync::Mutex` per the clippy.toml replacement column, or record a test-support exception in the policy and add the sanctioned per-site allows to the impl methods; the `// async-gate-allow: test-support recorder lock` markers (30 sites, async-gate-inventory.json) are recorded exceptions and are not re-flagged | [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/src/test_support.rs:97, packages/d2b-provider-credential/src/driver.rs:1109, clippy.toml:40] | policy-confirmed | lane/d2b-provider-credential.md - -**`d2b-provider-device-gpu`** - -- `RS-0814` | medium | `d2b-provider-device-gpu` | `parking_lot::Mutex::lock` on the shared `gpu_authority_leases` cache is off the KD3 exception list (only the R4 bounded-worker boundary is exempt) and carries no per-site `#[allow(clippy::disallowed_methods)]` unlike the same file's drive_sync | fix: add the sanctioned per-site allow `reason = "synchronous path"` at the three lock sites (or record the site in the provider-crate-policy exception list); the clippy.toml:82 replacement (`tokio::sync::Mutex`) is wrong on this pure-synchronous path | [packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-gpu/src/effects_service.rs:310, packages/d2b-provider-device-gpu/src/effects_service.rs:445, packages/d2b-provider-device-gpu/src/effects_service.rs:454] | policy-confirmed | lane/d2b-provider-device-gpu.md - -**`d2b-provider-device-security-key`** - -- `RS-0815` | medium | `d2b-provider-device-security-key` | 14 `parking_lot::Mutex::lock` sites (8 production-path in relay_service.rs:129,281,489,497,527,532,592,599 and 6 in the test-support-gated test_support.rs:32,43,44,55,78,89) carry no `#[allow(clippy::disallowed_methods, reason = "...")]` attribute, while the committed blocking-census baseline records `parking_lot::Mutex::lock = 0` for this crate and parking_lot is banned outright by clippy.toml (KD3) with only the R4 worker boundary exempt - the census bookkeeping and the manifest's recorded `disallowed_methods = "deny"` level disagree with the source, and the `// async-gate-allow:` markers cover only the async-gate scanner, not the clippy/census side | fix: add the sanctioned per-site allows (`reason = "synchronous path"`) or convert the short critical sections to the clippy.toml-named `tokio::sync::Mutex` replacement, then regenerate the census baseline to match | [packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-device-security-key/src/relay_service.rs:281, packages/d2b-provider-device-security-key/src/relay_service.rs:489-599, packages/d2b-provider-device-security-key/src/test_support.rs:32-89] | actionable | lane/d2b-provider-device-security-key.md merged: d2b-provider-device-security-key#6,d2b-provider-device-security-key#7 - -**`d2b-provider-device-usbip`** - -- `RS-0816` | low | `d2b-provider-device-usbip` | `test_support.rs` recorders use `parking_lot::Mutex` (fields at 25/27/29/70/72, `.lock()` at 35/46-47/58-59/82/93) with no per-site allow, but parking_lot is banned outright with the single R4 bounded-worker exception | fix: replace with `tokio::sync::Mutex` (the clippy.toml-named replacement) or add the sanctioned `cfg(test) helper` per-site allow | [test_support.rs:25, test_support.rs:35, Cargo.toml:30] | policy-confirmed | lane/d2b-provider-device-usbip.md - -**`d2b-provider-guest`** - -- `RS-0817` | medium | `d2b-provider-guest` | GuestStatusSink ((a pub type re-exported at lib.rs:42)is Arc>>, injecting the banned parking_lot lock type into this crate's and d2bd's public signatures; the production write sites carry recorded "synchronous path"/async-gate allows,,but every future sink caller inherits the banned type | fix: replace with Arc>>and convert the write sites to .lock().await per the replacement vocabulary | [packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, packages/d2b-provider-guest/src/effects_service.rs:1443] | policy-confirmed | lane/d2b-provider-guest.md -- `RS-0818` | medium | `d2b-provider-guest` | The test-support recorder doubles and the driver test harnesses hold recorder/queue state in parking_lot::Mutex fields, which the ban covers for tests too (KD4 uniform rule,,and no per-site clippy allow exists at these sites | fix: convert to tokio::sync::Mutex with async accessors (or the documented blocking-seat helpers for worker-thread-only callers),,keeping the recorded async-gate-allow marks until converted | [packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_support.rs:171, packages/d2b-provider-guest/src/driver.rs:1534, packages/d2b-provider-guest/src/driver.rs:1761] | policy-confirmed | lane/d2b-provider-guest.md - -**`d2b-provider-process`** - -- `RS-0819` | medium | `d2b-provider-process` | production `parking_lot::Mutex` fields in `EphemeralRuntime` (`started_at`, `completed`) are a live use of a banned primitive with no per-site allow, and the lock calls run on the actor's executor thread | fix: switch the two fields to `tokio::sync::Mutex` (the already-named replacement) or `std::sync::Mutex` with the same short critical sections; requires the parking_lot ban carve-out to be re-opened otherwise | [packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.rs:682] | policy-confirmed | lane/d2b-provider-process.md -- `RS-0820` | low | `d2b-provider-process` | `RestartBudget`, `EphemeralRuntime.started`, and `DurableRuntime.watching` use `Ordering::SeqCst` for plain counters and flags that publish no other data, so the strongest ordering buys nothing over `Relaxed` | fix: switch the 16 `Ordering::SeqCst` sites in driver.rs to `Ordering::Relaxed` (no paired acquire/release handoff exists; the actor and the spawned launch task only gate on these flags) | [packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.rs:451, packages/d2b-provider-process/src/driver.rs:458, packages/d2b-provider-process/src/driver.rs:462] | actionable | lane/d2b-provider-process.md - -**`d2b-provider-system-core`** - -- `RS-0821` | low | `d2b-provider-system-core` | `ScriptedDiscoveryPort.calls: Mutex` (testing.rs:43) uses a tokio::sync::Mutex for a counter - the crate's only tokio use - and `call_count` (testing.rs:79) silently reports 0 on contention via try_lock | fix: `AtomicU32` with `fetch_add`/`load` (Relaxed) and drop `tokio = { workspace = true, features = ["sync"] }` from Cargo.toml | [src/testing.rs:43, src/testing.rs:79] | actionable | lane/d2b-provider-system-core.md - -**`d2b-provider-toolkit`** - -- `RS-0822` | low | `d2b-provider-toolkit` | `invocations.fetch_add(1, Ordering::AcqRel)` uses release-acquire for a monotonic counter nobody synchronizes on; the identifier only needs uniqueness, so `Ordering::Relaxed` is the weakest correct ordering | fix: `fetch_add(1, Ordering::Relaxed)` | [packages/d2b-provider-toolkit/src/operations/envelope.rs:487] | actionable | lane/d2b-provider-toolkit-p1.md - -**`d2b-provider-transport-unix`** - -- `RS-0823` | low | `d2b-provider-transport-unix` | `tokio::sync::Mutex` (portal.rs:18, 155) in a crate with zero async code - every use is `try_lock()` on a synchronous path, so the tokio `sync` feature dependency exists solely for this one lock | fix: use `std::sync::Mutex` (the crate's own `try_lock`-only pattern never awaits) | [packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-unix/src/portal.rs:155] | actionable | lane/tail-5.md - -**`d2b-provider-user`** - -- `RS-0824` | medium | `d2b-provider-user` | the test-support recorder doubles and the driver's test fakes use `parking_lot::Mutex` (banned outright, KD3) at 20 `lock()` call sites with no `#[allow(clippy::disallowed_methods)]` on the enclosing items, while sibling `d2b-provider-host` uses `tokio::sync::Mutex` for the same recorder shape | fix: swap `parking_lot::Mutex` to `tokio::sync::Mutex` in `RecordingEffects`/`ScriptedProbe`/`RecordingManager`/`RecordingRequeue` (or add the sanctioned inline allow with reason "cfg(test) helper" at each site) so the deny-level flip needs no special case | [packages/d2b-provider-user/src/test_support.rs:41-42, packages/d2b-provider-user/src/test_support.rs:108, packages/d2b-provider-user/src/driver.rs:469-470, packages/d2b-provider-user/src/driver.rs:563] | policy-confirmed | lane/d2b-provider-user.md -- `RS-0825` | low | `d2b-provider-user` | the scripted-double flags (`fail`, `absent`, `failing`) use `Ordering::SeqCst` though they are set and read within one test task on a single-threaded `#[tokio::test]` runtime, so the strongest ordering buys nothing | fix: use `Ordering::Relaxed` for the loads/stores in test_support.rs and driver.rs:854, per the weakest-correct-ordering rule | [packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_support.rs:135, packages/d2b-provider-user/src/test_support.rs:140, packages/d2b-provider-user/src/test_support.rs:152] | actionable | lane/d2b-provider-user.md - -**`d2b-provider-volume-binding`** - -- `RS-0826` | low | `d2b-provider-volume-binding` | the production [dependencies] compiles the KD3-banned parking_lot (clippy.toml:82 disallows its lock outright, revocation recorded) solely for the feature-gated/cfg(test) recording doubles, so every production consumer of this crate carries the banned crate in its lockfile; the per-site #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] permits the lock calls but not the manifest posture | fix: swap parking_lot::Mutex -> std::sync::Mutex in FakeServingEffects/RecordingManager/RecordingRequeue (the guards are already statement-scoped, so the sanctioned allows survive unchanged) and drop the Cargo.toml dependency, or gate it behind test-support as an optional dep | [packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-volume-binding/src/driver.rs:1139-1142, clippy.toml:82] | actionable | lane/d2b-provider-volume-binding.md - -**`d2b-resource-client`** - -- `RS-0827` | low | `d2b-resource-client` | `ResourceWatch` models the open/closing/closed stream state with two `Arc` fields (state, closing; zone_client.rs:510-513) where the sibling `ProcessAttachStream` already uses the single `AtomicU8` three-state machine (STREAM_OPEN/CLOSING/CLOSED, process_attach.rs:409-412) | fix: align ResourceWatch onto the same single-atomic state enum | [packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone_client.rs:512, packages/d2b-resource-client/src/zone_client.rs:513, packages/d2b-resource-client/src/process_attach.rs:409] | actionable | lane/d2b-resource-client.md - -**`d2b-resource-runtime`** - -- `RS-0828` | low | `d2b-resource-runtime` | `ActorTimers.next` is a single-owner counter (ractor serializes the actor's handlers) but increments with `Ordering::SeqCst`, the strongest ordering, where `Relaxed` is the weakest correct one for a counter nobody synchronises on | fix: `self.next.fetch_add(1, Ordering::Relaxed)` | [packages/d2b-resource-runtime/src/resource.rs:247] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0829` | low | `d2b-resource-runtime` | parking_lot (banned outright by clippy.toml:40-43, plan KD3, except the R4 worker boundary) is a [dependencies] entry consumed only by #[cfg(test)] code | fix: move parking_lot to [dev-dependencies] or replace the two test uses with std::sync::Mutex | [packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:800, packages/d2b-resource-runtime/src/context.rs:1044] | actionable | lane/d2b-resource-runtime-p2.md - -**`d2b-session`** - -- `RS-0830` | low | `d2b-session` | AuthenticatedSessionDriver._owner is a std::sync::Mutex that is never locked, serving only as a Sync carrier for the ComponentSessionDriver: Send + Sync bound, with no comment saying so | fix: document the Sync-carrier intent on the field or replace it with a named wrapper type | [admission.rs:756, admission.rs:1666, driver.rs:33] | actionable | lane/d2b-session-p2.md - -**`d2b-unsafe-local-helper`** - -- `RS-0831` | low | `d2b-unsafe-local-helper` | the `active` operation counter is a pure admission counter (it bounds MAX_HELPER_QUEUE_DEPTH worker threads and publishes no value; responses travel over the sync_channel, which carries its own synchronization) yet every fetch_add/fetch_sub uses AcqRel | fix: Ordering::Relaxed, the weakest correct ordering for a counter nobody synchronizes on | [packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src/protocol.rs:167, packages/d2b-unsafe-local-helper/src/protocol.rs:195] | actionable | lane/d2b-unsafe-local-helper.md - -**`d2bd`** - -- `RS-0832` | low | `d2bd` | two standalone monotonic counters use stronger orderings than the weakest correct one: the effect-service binding revision does `load(Ordering::SeqCst)` (esa:174) and `fetch_add(1, Ordering::SeqCst)` (esa:509), and `next_desired_generation` uses `fetch_update(Ordering::AcqRel, Ordering::Acquire, ...)` (provider_effects:1064); the revision is a version tag used only in equality staleness checks and the generation is a unique-value mint, so `Ordering::Relaxed` is correct for both | fix: switch the revision load/fetch_add and the generation fetch_update to `Ordering::Relaxed` | [packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs:509, packages/d2bd/src/provider_effects.rs:1064] | actionable | lane/d2bd-p7.md -- `RS-0833` | low | `d2bd` | `Ordering::SeqCst` on the standalone `broker_epoch` atomic (store and load). The epoch is a self-contained value; the zones map it gates is mutex-guarded, so there is no paired publication needing Acquire/Release - `Ordering::Relaxed` is the weakest correct ordering here | fix: use `Ordering::Relaxed` at both sites | [packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414] | actionable | lane/d2bd-p8.md - -**`d2bd-runtime`** - -- `RS-0835` | medium | `d2bd-runtime` | unsafe_local_helper.rs uses `parking_lot::Mutex` for its registry/connection/ledger state (`use parking_lot::Mutex` + 4 `Mutex<...>` field types + 39 `.lock()` call sites), which the repo bans outright outside the R4 dedicated bounded-worker boundary | fix: replace with `tokio::sync::Mutex` reached through the documented blocking-seat patterns this crate already uses (`metrics::Registry::blocking_lock` for worker-thread-only seats, `authority_persistence::lock_sync` try_lock spin where an ambient runtime may exist) | [packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34] | policy-confirmed | lane/d2bd-runtime-p3.md -- `RS-0836` | medium | `d2bd-runtime` | `OpLockManager::acquire` busy-spins (`try_lock` + `std::hint::spin_loop()`) while the per-VM/global lock is held across a whole lifecycle op (composition.rs:5612 holds the guard across `dispatch_request_locked`, i.e. seconds for a VM start), so a concurrent same-VM or global request burns a full core for the op duration; the doc's "critical sections are single map ops" justification covers only the map-entry lock, not the held op lock | fix: replace the spin with the repo's sanctioned wait-on-condition shape (`tokio::sync::Notify` armed before the check + `tokio::time::timeout`, clippy.toml:37-39) or park/wake on the dedicated dispatch threads; requires a policy/ADR decision first | [packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189, packages/d2bd/src/composition.rs:5612] | policy-confirmed | lane/d2bd-runtime-p4.md -- `RS-0834` | low | `d2bd-runtime` | `NewPlaneReadinessState` (resource_runtime_support.rs:144-180) stores four independent readiness booleans with `Ordering::SeqCst` on every store/load; there is no Release/Acquire paired handoff (each flag is an independent published bit) | fix: `Ordering::Relaxed`, which is the weakest correct ordering for independent flags; the cross-thread visibility the startup path needs is already ordered by the join/actor supervision in the daemon, and SeqCst here does not buy snapshot atomicity across the four flags anyway | [resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support.rs:166, resource_runtime_support.rs:170] | actionable | lane/d2bd-runtime-p2.md - -### `async` - -Async correctness: runtime choice, blocking work in async contexts, guards across await, cancellation safety, Send bounds. - -**`d2b-broker`** - -- `RS-0837` | high | `d2b-broker` | `cleanup_spawned_runner_after_failure` performs a blocking `waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED)` (no WNOHANG) at runtime.rs:11815, and is called directly from async `spawn_process` (kernel_ops.rs:919, 955) on the broker's tokio executor; a child stuck in uninterruptible sleep blocks that worker indefinitely, and every sibling reap path in this file is explicitly WNOHANG | fix: bounded WNOHANG poll loop (or spawn_blocking) that preserves the no-live-process-left-behind guarantee; route review-pass | [packages/d2b-broker/src/runtime.rs:11815, packages/d2b-broker/src/kernel_ops.rs:919, packages/d2b-broker/src/kernel_ops.rs:955] | actionable | lane/d2b-broker-p1.md -- `RS-0841` | high | `d2b-broker` | the async `harden()` path (invoked from `live_handlers.rs:3142` on the runtime) calls `apply_ancestor_traverse_acl` -> `run_setfacl_op_on_fd` (sys.rs:1866-1893), which does a synchronous `fork` + `execv(setfacl)` + blocking `waitpid` loop with no `.await` and no `spawn_blocking`, stalling the executor worker for the duration of a subprocess spawn | fix: wrap the setfacl fork/exec/wait in `tokio::task::spawn_blocking` (moving the fd across as `OwnedFd`) and `.await` the join handle in `harden` | [packages/d2b-broker/src/ops/swtpm_dir.rs:770, packages/d2b-broker/src/sys.rs:1866-1893, packages/d2b-broker/src/live_handlers.rs:3142] | actionable | lane/d2b-broker-p5.md -- `RS-0842` | high | `d2b-broker` | write_redacted_registry_index_at_path resolves the fixed d2bd group via nss `Group::from_name` synchronously on an executor worker on every registry write (enroll/refresh/boot) | fix: resolve the gid once (lazy static or serve-time config injected into the ops context)and return `MediaOpError::Registry` on absence, so the nss lookup leaves the async hot path | [packages/d2b-broker/src/ops/media.rs:2100, packages/d2b-broker/src/ops/media.rs:2126] | actionable | lane/d2b-broker-p7.md -- `RS-0840` | high | `d2b-broker` | `acquire_handoff_lock` is an `async fn` whose final step is a blocking `nix::fcntl::Flock::lock(file, LockExclusive)` on the executor worker thread; the call is not in the clippy.toml disallowed-methods list (no flock entry), not caught by the async-gate scanner) (qualified associated-function calls aren't the method-call shape the scanner flags; the hatch inventory records no marker at this line), and not in the blocking-census baseline - yet the repo's own clippy.toml names this exact class as a rule violation ("a synchronous lock acquired inside an async context ... still parks the executor worker" clippy.toml:55-56) | fix: move the flock to a dedicated bounded worker (house loader_worker shape per clippy.toml:37-40) or convert to non-blocking `LockExclusiveNonblock` plus async retry (`tokio::time::timeout`/sleep as the mkfs ETXTBSY loop does), keeping the critical section bounds off the runtime worker | [packages/d2b-broker/src/ops/host_generation_handoff.rs:246, packages/d2b-broker/src/ops/host_generation_handoff.rs:231] | actionable | lane/d2b-broker-p4.md -- `RS-0839` | medium | `d2b-broker` | the initial ACL-grant attempt runs a blocking setfacl fork/exec on the executor worker: `refresh_spawn_runner_acls` (async, live_handlers.rs:1802) -> `refresh_obs_vsock_acl` -> `grant_obs_vsock_acl_once` (1614) -> `setfacl_fd_safe` -> `setfacl_fd_safe_op_classed` (1416) -> `sys::pidfd_sys::run_setfacl_op_on_fd`, while the retry paths (`spawn_obs_vsock_acl_retry` 1658, `retry_acl_grant` 2519) correctly defer the same shellout to `background.dispatches.run` on the bounded dispatch pool | fix: route the initial attempt through `dispatches.run` too (or make the refresh fns async and use the `setfacl_verified_device` async-shellout shape), matching the documented "kernel-path step on the bounded dispatch pool" design; bounded short shellout per spawn, so medium not high | [packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:1802] | actionable | lane/d2b-broker-p3.md -- `RS-0838` | medium | `d2b-broker` | the USB-audit serial HMAC key path runs blocking filesystem syscalls inside async fns on broker executor threads:usb_audit_serial_hmac_keyring calls the sync ensure_usb_audit_serial_hmac_key_dir (two path_safe::ensure_dir stat/mkdir chains)per call,and every bind op with a device serial loads each key file through a sync nix::fcntl::open plus tokio::fs::File::from_std read,and the create leg performs sync create_file_at_safe/fchmod/rustix::fs::fsync(dir_fd) at runtime.rs:7722-7729; none of these raw calls sits on the disallowed-methods list,so the sync-in-async class escapes the existing gate | fix: extend the already-used tokio::fs::File::from_std)..).sync_all().await pattern(orthe bounded-worker shape per plan R4)to the dir-fd fsync and the key-dir ensure/open legs, per U1 ledger 2,which names tokio::fs asthe sanctioned replacement for these blocking calls,so the verdict is policy-confirmed | [packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages/d2b-broker/src/runtime.rs:7584, packages/d2b-broker/src/runtime.rs:7696] | policy-confirmed | lane/d2b-broker-p2.md - -**`d2b-process-conformance`** - -- `RS-0843` | low | `d2b-process-conformance` | Both traits declare their six async methods as `fn ... -> impl Future + Send` while every in-tree implementor already writes `async fn` (ScriptedEffectPort, ProviderSupervisor, systemd/minijail test ports, d2bd's NonLaunchingProcessEffectPort), and the traits already carry `Send + Sync` supertraits, so the RPITIT `async fn` form (stable, edition 2024) expresses the same Send contract more directly | fix: convert the trait method declarations to `async fn` (port.rs:99-157, provider.rs:96-148), rewriting the two default bodies (`launch_with_inherited_fds`, `probe`) as `async { ... }` and dropping the `ready(Err)...))` wrappers; no implementor changes required | [packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port.rs:129, packages/d2b-process-conformance/src/provider.rs:96, packages/d2b-process-conformance/src/provider.rs:125] | actionable | lane/d2b-process-conformance.md - -**`d2b-provider`** - -- `RS-0844` | medium | `d2b-provider` | `ProviderAgent::serve` awaits each `dispatch` serially (agent.rs:316-324):a slow handler near the 900s timeout bound (`MAX_AGENT_TIMEOUT_MS`)stalls the whole session queue,and the `MAX_AGENT_IN_FLIGHT=64` Semaphore bound can never be exceeded by the serve loop itself | fix: spawn each dispatch (`tokio::spawn(async move { let result = self.dispatch(request).await; let _ = response_tx.send(result.await; })`) with a cloned `response_tx`,letting the already-acquired Semaphore permit cap concurrency; state whether per-session response ordering is a contract) | [packages/d2b-provider/src/agent.rs:316-324] | actionable | lane/d2b-provider.md - -**`d2b-provider-credential-secret-service`** - -- `RS-0845` | medium | `d2b-provider-credential-secret-service` | lock order between `sessions` and`user_sessions` is inverted across two branches of `authorize_session_for_user_locked` (first branch acquires `sessions` then awaits `user_sessions`; cached-key branch acquires `user_sessions` then awaits `sessions`), a latent tokio-Mutex deadlock that the outer `async_mutation_gate`/entry-timing currently masks | fix: acquire in one consistent order in both branches (`sessions` before `user_sessions`, e.g. in the cached-key branch scope the `user_sessions` guard chain and then lock `sessions`, or collapse the dual lookup into one map) | [packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-credential-secret-service/src/lib.rs:1341, packages/d2b-provider-credential-secret-service/src/lib.rs:1380] | actionable | lane/d2b-provider-credential-secret-service.md - -**`d2b-provider-device-tpm`** - -- `RS-0846` | medium | `d2b-provider-device-tpm` | prepare_state_dir (effects_service.rs:412) runs blocking work on the executor worker: a synchronous broker round-trip envelope_invoke_kernel (effects_service.rs:467, blocking connect/poll/recv up to kernel_io_timeout) plus NSS lookups nix::unistd::User::from_name/Group::from_name (effects_service.rs:518,525) in row_posture, none marked async-gate-allow (the crate's inventory lists only the 3 test lock sites) | fix: move the invoke and the NSS resolution off the worker (spawn_blocking or an async broker client); the same pattern exists in d2b-provider-supervisor/process/process-systemd/network-local and d2bd, so consolidation may treat it as one family class | [effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs:525] | actionable | lane/d2b-provider-device-tpm.md -- `RS-0847` | low | `d2b-provider-device-tpm` | lifecycle_lease_consumed: tokio::sync::Mutex (effects_service.rs:361,698) guards a flag owned by exactly one task (into_port builds a fresh port per reconcile/finalize call and uses it once), and consume_lifecycle_lease holds the guard across `.await` (effects_service.rs:384-394); the lock can never contend | fix: replace with AtomicBool (preserves &self + Sync) or restructure the once-gate | [effects_service.rs:361, effects_service.rs:384, effects_service.rs:698] | actionable | lane/d2b-provider-device-tpm.md - -**`d2b-provider-network-local`** - -- `RS-0848` | low | `d2b-provider-network-local` | observe_host_network awaits three independent `ip` observations sequentially, where tokio::join! would run them concurrently | fix: `let (links, addresses, routes)= tokio::join!(run_ip(&["-j", "-d", "link", "show"]), run_ip(&["-j", "-4", "addr", "show"]), run_ip(&["-j", "-4", "route", "show", "table", "all"]));` then parse | [src/observe.rs:255-260] | actionable | lane/d2b-provider-network-local.md - -**`d2b-provider-system-core`** - -- `RS-0849` | low | `d2b-provider-system-core` | `block_on` (testing.rs:23) busy-spins (`std::hint::spin_loop()`, testing.rs:30) on `Poll::Pending`, so any future that genuinely yields - a contended tokio Mutex, a future test with real I/O - hangs the test process at 100% CPU instead of failing; the doc comment asserts hermiticity but nothing enforces it | fix: `debug_assert!` the never-pending invariant or drive these tests with a real runtime | [src/testing.rs:30, src/testing.rs:19] | actionable | lane/d2b-provider-system-core.md - -**`d2b-provider-transport-azure-relay`** - -- `RS-0850` | medium | `d2b-provider-transport-azure-relay` | `RelayConnection::send` is not cancellation-safe: `credits.reserve(size)` is followed by `self.socket.send(frame).await`, and the rollback runs only on `Err` - if the future is cancelled between reserve and completion (e.g. by the session engine's timeout wrapper), the reservation leaks and the connection is permanently starved of up to 64 KiB of credit | fix: wrap the reservation in a small RAII guard that rolls back on drop unless the send committed (or reserve after the await using a pre-checked window) | [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833] | actionable | lane/d2b-provider-transport-azure-relay.md - -**`d2b-provider-user`** - -- `RS-0851` | high | `d2b-provider-user` | the bounded probe's `discover_local_user` runs blocking NSS lookups (`nix::unistd::User::from_name`, `Group::from_gid`, `Group::from_name`) inside async fns on the plane's executor worker (driver reconcile via effects_service.rs:224, and the hosted `inspect-user`), so a slow or hung NSS backend (LDAP/NIS) stalls a runtime worker per call; `spawn_blocking` is itself banned (KD2) | fix: move the NSS reads onto a dedicated bounded worker in the `d2b-core` `loader_worker` shape (one thread, bounded sync_channel, oneshot replies) and have the probe await it | [packages/d2b-provider-user/src/probe.rs:48, packages/d2b-provider-user/src/probe.rs:63, packages/d2b-provider-user/src/probe.rs:72, packages/d2b-provider-user/src/probe.rs:40-79] | policy-confirmed | lane/d2b-provider-user.md - -**`d2b-zone-routing`** - -- `RS-0852` | medium | `d2b-zone-routing` | `ZoneEnrollmentServer::serve` commits the link FSM synchronously (PSK burn, enrollment record seal) inside `serve_bootstrap`/`serve_enroll` and then `.await`s the reply write `transport.send)...)`, so a `serve` future dropped between the mutation and the send leaves the link mid-transition and the peer never sees the reply | fix: make the FSM commit + encoded-reply write one non-cancellable unit (and document that dropping the task mid-send closes the connection as the peer's only signal), or make the operation resumable by deferring the transition until the reply write succeeds where the FSM allows | [packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207] | actionable | lane/d2b-zone-routing.md - -**`d2bd`** - -- `RS-0853` | medium | `d2bd` | `admit_interaction_socket`'s per-request dispatch holds the daemon-global `runtime` lock (the `AsyncMutex>`( across the whole `.await` of `dispatch_component_request_for_session`, serializing every Zone's sessions andthe VM-start display reconcile behind one contended lock; the code itself records this as a residual at 5518-5529 | fix: per the recorded note, hand out a per-Zone handle (`BTreeMap>>`) cloned under the outer lock,and move the sync-seat methods off their global lock, adding the named concurrency test | [packages/d2bd/src/interaction_composition.rs:5518-5530] | actionable | lane/d2bd-p5.md -- `RS-0854` | medium | `d2bd` | `ProductionSharedProviderEffects::runtime()` and `NetworkRuntime::bundle()` busy-wait with `std::hint::spin_loop()` on `tokio::sync::Mutex::try_lock()`; `runtime()` is called from async reconcilers (reconcile_network, reconcile_usbip, reconcile_tpm, ...), so a contended lock spins an executor worker instead of awaiting. The `// async-gate-allow` markers in this file cover the `.lock()` sites (recorded in async-gate-inventory.json:1165-1198) but these `try_lock`+spin sites are not marked or recorded, and the gate scanner matches `.lock()`/`.read()`/`.write()` only, so they are invisible to it. The in-code comment cites plan U10 / the broker rate limiter as the choice | fix: use `.lock().await` where the caller is async (split a sync lock path for the sync trait callers), or record these sites in the async-gate inventory as a deliberate exception | [packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_effects.rs:2633-2639] | actionable | lane/d2bd-p8.md - -**`d2bd-runtime`** - -- `RS-0855` | low | `d2bd-runtime` | `CONSOLE_DRAINER_RUNTIME` is a `static OnceLock` started inside library code (console_session.rs:33-44), giving the daemon a second multi-thread runtime per process that is never shut down, while the binary already owns a `#[tokio::main(flavor = "multi_thread")]` runtime (d2bd/src/main.rs:142) | fix: own the runtime at the binary top and pass a `tokio::runtime::Handle` into `create_ch_session`/`create_qemu_session` (or spawn drainers on the daemon runtime) instead of a crate-static `OnceLock` | [packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session.rs:35] | actionable | lane/d2bd-runtime-p4.md - -### `unsafe` - -Soundness: justification, SAFETY comments, safe wrappers, UB hazards, Miri verification. - -**`d2b-broker`** - -- `RS-0858` | medium | `d2b-broker` | most of `sys.rs`'s 101 `unsafe` blocks carry no `// SAFETY:` comment (only 25 SAFETY comments in the file, concentrated on the risky corner: clone3, fork, pre_exec, pidfd, mount); the raw wrapper layer - `openat2_raw`, `openat_raw`, `renameat2_raw`, `renameat_raw`, `mkdirat_raw`, `unlinkat_raw_with_flags`, `fstatat_raw`, `linkat_empty_path_raw` (593-699), the child-context helpers `mkdir_one`/`mknod_device_bind_target`/`install_pre_opened_fds` (2630, 2670, 2109) and the mount/mask helpers `apply_mount_actions(_debug)`/`apply_device_mask_and_binds` (2591, 2694) - call libc with only `#[allow(unsafe_code)]`, so a reader cannot distinguish audited from un-audited blocks in the sanctioned quarantine | fix: add a one-line SAFETY to each bare block stating the invariant it upholds (CString/pointer liveness and NUL-termination, dirfd validity, errno propagation, freshly-owned return fd), matching the existing clone3/fork comments | [packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broker/src/sys.rs:630, packages/d2b-broker/src/sys.rs:653] | actionable | lane/d2b-broker-p5.md -- `RS-0857` | low | `d2b-broker` | `command_output_inheriting_fd_async` wraps a std )safe) call (`std::process::Command::pre_exec`) in an `unsafe { ... }` block (plus a crate-level-exception `#[allow(unsafe_code)]`), making the block and the allow unnecessary:the pre_exec closure contract (async-signal-safe, error-returning) is already std's own safe-API contract,and the closure body uses only safe nix fcntl wrappers | fix: remove the `unsafe { }` block and the `#[allow(unsafe_code)]` attribute, keeping the async-signal-safety rationale as a regular comment (the site then leaves the enumerated unsafe-exception set in U1 (d)8, shrinking it) | [packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661] | actionable | lane/d2b-broker-p4.md - -**`d2b-broker-fixture-syscall-surface`** - -- `RS-0856` | medium | `d2b-broker-fixture-syscall-surface` | the x86_64 `asm!` block omits the registers the `syscall` instruction clobbers (rcx and r11), so the compiler's no-clobber assumption is violated if the fn is ever executed | fix: add `lateout("rcx") _`, `lateout("r11") _` (or `clobber_abi("C")`) to the asm operands at lib.rs:26-32 | [packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32] | actionable | lane/tail-1.md - -**`d2b-host-activation-helper`** - -- `RS-0859` | medium | `d2b-host-activation-helper` | 22 production `unsafe` blocks (libc calls plus `errno_clear`'s `__errno_location` write) carry no `// SAFETY:` comment, violating the skill's mechanical rule and U1 (d) 8 | fix: add a `// SAFETY:` comment to each block stating the invariant (CString NUL-termination, checked return before use, fd ownership) | [packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/src/main.rs:129, packages/d2b-host-activation-helper/src/main.rs:140, packages/d2b-host-activation-helper/src/main.rs:194] | actionable | lane/tail-1.md merged: tail-1#4 - -### `ffi` - -FFI boundary: thin translation layer, no panic across, explicit pointer ownership, repr contracts, edition-2024 forms. - -- No findings. - -### `macro` - -Macros as last resort: by-example before proc-macro, hygiene and $crate, spanned errors, _private module. - -**`d2b-provider-display-wayland`** - -- `RS-0860` | low | `d2b-provider-display-wayland` | the local `macro_rules! entry!` (policy.rs:420-437) is a two-arm table-filling shorthand whose `max=` arm only omits one field; it is not variadic, does not generate impls per type, and is not a DSL, so a plain function is the cheaper answer | fix: replace the macro with `fn entry(m: &mut HashMap, iface: &str, action: GlobalAction, class: Classification, max: Option)` and update the ~70 call rows; the catalog content stays byte-identical (the hand-written catalog itself is Nix-pinned and refused at docs/explanation/over-engineering-audit-record.md:352, 427-429 - this finding touches only the mechanism) | [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420] | actionable | lane/d2b-provider-display-wayland-p1.md - -**`d2b-resource-api`** - -- `RS-0861` | low | `d2b-resource-api` | `response_error!` generates thirteen identical one-line functions that differ only in the response type, a case a generic function covers without a macro | fix: replace the macro with `fn error_response(error: ResourceError) -> T` (type inferred from each RPC method's return type) and delete the thirteen `response_error!` invocations | [service.rs:2245-2267] | actionable | lane/d2b-resource-api-p1.md - -**`d2b-session`** - -- `RS-0862` | low | `d2b-session` | the local admit_try! macro exists only to fuse an early return with a metric record, which a plain helper function plus ? expresses | fix: replace each invocation with `let result = ; admit_or_record(&mut engine, result)?` where admit_or_record records the failure metric and returns the error | [admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643] | actionable | lane/d2b-session-p2.md - -**`xtask`** - -- `RS-0863` | low | `xtask` | The test-only `crash_if_hooked!` macro is defined textually-identically in three sibling fns, differing only in the message string | fix: hoist to one module-scope `macro_rules! crash_if_hooked { ($stage:expr, $message:expr) => { #[cfg(test)] if let HookOutcome::Crash = hook($stage) { return Err(FoldError::single($message)); } }; }` and call with the stage plus message, or replace with a `#[cfg(test)]` generic helper fn | [packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/src/changelog.rs:1019] | actionable | lane/xtask-p5.md - -### `test` - -Test design: form follows the assertion, behavior over implementation, determinism, a test must be able to fail. - -**`X3-cross-crate-duplication`** - -- `RS-0958` | medium | `X3-cross-crate-duplication` | Provider test-support recorder/harness duplication: each provider crate hand-rolls the same recorder-double family (RecordingEffects/ScriptedProbe/RecordingManager/RecordingRequeue-style recording doubles, ScriptedPort/ScriptedDiscoveryPort/ScriptedEffectPort scripted ports, hand-rolled block_on pollers, TicketBuilder-style fixtures) in its own test_support.rs/testing.rs instead of the toolkit's shipped harness | fix: consolidate the recorder/harness shapes onto `d2b-provider-toolkit/src/testing` (TestHarness at testing/mod.rs:397, fakes.rs, fixture.rs, conformance.rs) and have the family crates reuse it; the toolkit module is the B3-kept base, so this does not re-propose the B3 refusal | [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-volume-binding/src/test_support.rs:17] | actionable | lane/X3-cross-crate-duplication.md -- `RS-0959` | low | `X3-cross-crate-duplication` | Test-support shipping shape: `test-support` features declared empty and gating nothing in four declaration crates while three provider crates ship `pub mod testing` (ScriptedPort/block_on harnesses) unconditionally in the production library and d2b-resource-types exports a test-only helper through the root despite declaring the feature | fix: wire each `test-support = []` feature to its module (`#[cfg(feature = "test-support")]` on `pub mod testing`, `#[cfg(feature = "test-support")]` on `assert_metadata_registration`) or drop the empty features, following the house pattern at d2b-provider-host/Cargo.toml:28 | [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-role/Cargo.toml:17] | actionable | lane/X3-cross-crate-duplication.md - -**`d2b`** - -- `RS-0880` | medium | `d2b` | the `d2b exec wait` guest-exit-code passthrough (`guestExitCode`/`exitCode` lookup, 0-255 filter, `unwrap_or(0)`) has no unit or integration test, so a regression in the CLI exit-code contract would pass silently | fix: extract the extraction into a testable helper or add a mock-daemon integration test asserting the passthrough and the out-of-range fallback | [packages/d2b/src/exec.rs:227-239] | actionable | lane/d2b-p3.md -- `RS-0881` | low | `d2b` | `validate_env` (KEY=VALUE shape, key length and charset bounds) has no test, unlike the sibling `validate_exec_ref` behavior that the attach tests cover | fix: table-driven unit test with human-written expected outcomes (valid, empty key, over-64 key, non-alnum key, missing `=`) | [packages/d2b/src/exec.rs:383-397] | actionable | lane/d2b-p3.md - -**`d2b-broker`** - -- `RS-0866` | low | `d2b-broker` | `reconciliation_refuses_start_time_drift` (tests/pidfd_handoff_scm_rights.rs) asserts the Display string (`msg.contains("start-time drifted")`) instead of the error variant, while the sibling real-spawner test matches `PidfdOpError::ReconciliationStartTimeMismatch` | fix: match the variant like tests/pidfd_real_spawner.rs:66-70 | [packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90] | actionable | lane/d2b-broker-p3.md - -**`d2b-broker-composition`** - -- `RS-0864` | low | `d2b-broker-composition` | `an_effectful_handler_offered_to_the_in_broker_table_is_refused_by_the_routing_rule` asserts `format!("{refusal}").contains("forward carrier")`, pinning the routing refusal's Display wording after the `matches!` variant check already pins the contract | fix: delete the Display-string assertion (the variant match is the contract; a wording change must not fail the suite) | [packages/d2b-broker-composition/src/seam.rs:523] | actionable | lane/d2b-broker-composition.md -- `RS-0865` | low | `d2b-broker-composition` | `an_unregistered_admitted_operation_fails_the_startup_invariant` never exercises an admitted-without-handler operation (the committed catalog admits nothing this pass, and the fixture row is refused by `verify_startup_routing` as uncommitted), so the body only asserts the empty-registration happy path and registers a discarded fixture | fix: rename the test to what it asserts (e.g. `the_admitted_set_stays_empty_with_nothing_registered`) and drop the comment's claim that the admitted-without-handler leg is pinned by the fixture row, or restructure to feed a genuinely admitted row when one exists | [packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.rs:733] | actionable | lane/d2b-broker-composition.md - -**`d2b-bus`** - -- `RS-0867` | high | `d2b-bus` | emitter_records_only_closed_bus_labels exercises every BusTelemetry method but asserts nothing, and every emit outcome is swallowed by `let _ = self.emit(...)` inside BusMetrics, so a label drifting out of the closed set passes silently | fix: make the test assert something observable, for example return EmitOutcome from a test-visible emit path or expose a read-back of the BoundedEmitter queue in d2b-telemetry, and assert Ok per call (route review-pass) | [packages/d2b-bus/src/metrics.rs:612-633, packages/d2b-bus/src/metrics.rs:451-534] | actionable | lane/d2b-bus-p1.md -- `RS-0868` | medium | `d2b-bus` | session_seam_tests.rs waits for service readiness with fixed-count yield and poll loops (`for _ in 0..16 { tokio::task::yield_now().await }` at 1623 and 1808, `for attempt in 0..32` at 1882, `for attempt in 0..8` plus an inner yield loop at 1941-1960), which is machine-dependent and can fail spuriously on a loaded runner | fix: replace with condition-driven waits (oneshot or Notify), the deterministic pattern the same file already uses elsewhere (advance_virtual, dispatched_wait) | [packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_tests.rs:1808-1810, packages/d2b-bus/src/session_seam_tests.rs:1882-1884, packages/d2b-bus/src/session_seam_tests.rs:1941-1960] | actionable | lane/d2b-bus-p2.md -- `RS-0869` | low | `d2b-bus` | `cancel_retry_cannot_reach_a_same_id_replacement_while_tombstone_is_retained` pins the full `Display` sentence of `OperationError::RetainedOperationId`, so a wording change fails the test even though the contract is the variant and its `as_str()` label | fix: assert the variant (the surrounding code already matches on variants) and drop the `to_string()` equality | [packages/d2b-bus/src/operations.rs:1057-1060] | actionable | lane/d2b-bus-p2.md - -**`d2b-contracts-control`** - -- `RS-0870` | medium | `d2b-contracts-control` | the `WorkloadOp`/`WorkloadOpResponse` wire family (feature-negotiated v3 operations, dispatched by d2bd/src/composition.rs:7666) has no round-trip or shape test in this crate, unlike every sibling family (exec, console, audio, shell, named streams, audit all have wire-shape tests) | fix: add a round-trip + tag/rename pin test for WorkloadOp::List/Status/LauncherExec and WorkloadOpResponse, mirroring `audio_public_wire_json_shape_is_stable` | [public_wire.rs:167, public_wire.rs:175] | actionable | lane/d2b-contracts-control.md - -**`d2b-contracts-provider`** - -- `RS-0871` | medium | `d2b-contracts-provider` | `credential/service.rs` (1461 lines) contains zero tests: the strict protobuf codec (the five `CredentialWire` impls at service.rs:1071-1350, `WireReader` at service.rs:1393-1452, `set_once` duplicate-field rejection at service.rs:1296, and the `encode_outer`/`decode_outer` ceilings at service.rs:1002-1028) is entirely unverified, so a malformed-input, truncation, or non-canonical-varint regression passes the suite silently | fix: add round-trip tests per DTO plus malformed/truncated/duplicate-field/non-canonical-varint/oversize tests for `WireReader` and `encode_outer`/`decode_outer` | [packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-provider/src/v3/credential/service.rs:1393, packages/d2b-contracts-provider/src/v3/credential/service.rs:1296] | actionable | lane/d2b-contracts-provider-p1.md -- `RS-0872` | medium | `d2b-contracts-provider` | several public contract behaviors have no test: `observe_credential` (both the degraded and the InspectMetadata branches), the rotation-retry-exhausted branch of `reconcile_credential` (`CredentialRetryState::exhausted` feeding `RotationFailed`/`Failed`), `CredentialLeaseAggregate::from_active_expiries`, `CredentialControllerHealth::derive`, and `CredentialAuditRecord::controller_event` | fix: add table-driven unit tests asserting the outcome/disposition variant per input row, mirroring the existing `rotation_policy_matrix_is_closed` shape | [packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1346, packages/d2b-contracts-provider/src/v3/credential_controller.rs:499, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1084] | actionable | lane/d2b-contracts-provider-p2.md - -**`d2b-contracts-zone-session`** - -- `RS-0873` | medium | `d2b-contracts-zone-session` | the security-relevant codec state machines have no tests: RequestEnvelope::admit deadline/skew/lifetime math, FragmentSequence ordering/duplicate/complete detection, ReceiveSequence replay and nonce exhaustion, SendSequence::take, AttachmentCredits::reserve and process_pool, and the canonical round-trips of RecordHeader/FragmentHeader/HandshakeAccept, while the suite covers only policy validation, redaction, and frozen enum vectors | fix: add unit tests asserting the error variants (InvalidDeadline, Reordered, Duplicate, Replay, NonceExhausted, CreditExceeded) for each state machine, plus encode/decode round-trips for the header types | [src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_session.rs:1916, src/v3/component_session.rs:2732] | actionable | lane/d2b-contracts-zone-session-p1.md merged: d2b-contracts-zone-session-p1#6 -- `RS-0874` | medium | `d2b-contracts-zone-session` | EmergencyPolicySpec's contract branches have no tests: the file holds exactly one test covering only the union behavior | fix: add table tests for new() rejecting deadline 0 and > MAX_EMERGENCY_DRAIN_DEADLINE_SECONDS, reason > MAX_EMERGENCY_REASON_BYTES, and control characters; plus effective_scope returning None when no policy is enabled, and the serde default round-trip | [emergency_policy.rs:236, emergency_policy.rs:112] | actionable | lane/d2b-contracts-zone-session-p2.md merged: d2b-contracts-zone-session-p2#9 - -**`d2b-core`** - -- `RS-0877` | low | `d2b-core` | `tamper_owner_wrong_uid` in tests/bundle_resolver_tamper.rs silently returns (eprintln + return) when not root, so it passes vacuously on non-root CI and a regression in the chown tamper path would go unnoticed there | fix: convert the inline skip to the repo's documented `#[ignore]` root-only pattern (the card's false-positive list endorses documented ignores) so the skip is visible in test output | [packages/d2b-core/tests/bundle_resolver_tamper.rs:149] | actionable | lane/d2b-core-p2.md - -**`d2b-core-controller`** - -- `RS-0875` | medium | `d2b-core-controller` | the restart-recovery receipt path (validate_recovery_operations, recovery_receipt_from_operations_with_prepared_capabilities, rehydrate) has no test anywhere: claim-digest verification, prepared-capability matching, and quarantine-on-mismatch are contract behavior with zero coverage | fix: add tests that build AuthorityStorageOperation rows with a tampered claim_digest, a prepared-capability set that misses an active operation, and a duplicate operation_id, asserting each returns InvalidAuthorityRequest, plus a rehydrate round-trip that admits after rehydration | [authority.rs:1824, authority.rs:1968, authority.rs:1899] | actionable | lane/d2b-core-controller-p2.md -- `RS-0876` | medium | `d2b-core-controller` | AuthorityRecoveryCoordinator has no tests and its resolution methods have no callers at all, so the capability-restore-and-quarantine rollback on a failed record_close/release (authority_persistence.rs:292-311) is untested contract behavior that only a future driver will reach | fix: add coordinator tests with a failing persistence double asserting the capability is restored and the operation quarantined after record_close or release failure, and that resolve_observed_and_adopted clears the unresolved set | [authority_persistence.rs:246-320] | actionable | lane/d2b-core-controller-p2.md merged: d2b-core-controller-p2#8 - -**`d2b-host`** - -- `RS-0878` | medium | `d2b-host` | `NftBatch::parse` (the ~200-line nft script dialect parser with 15+ error paths) has no tests: zero calls to `parse` exist in the crate's test modules, while the broker feeds it live script bodies on its nft apply path | fix: table-driven parse tests (valid script, malformed header, foreign family/table, missing hook priority, unterminated chain, trailing content) asserting `ParseNftScriptError` variants | [packages/d2b-host/src/nftables.rs:245] | actionable | lane/d2b-host.md -- `RS-0879` | low | `d2b-host` | `package_digest_includes_bytes_read_through_store_symlinks` writes fixtures to a CWD-relative `target/` directory (the cargo build dir), polluting build artifacts and failing under a read-only target; every sibling test uses `tempdir()` | fix: use `tempfile::tempdir()` like the sibling tests | [packages/d2b-host/src/bin/d2b-activation-helper.rs:792] | actionable | lane/d2b-host.md - -**`d2b-provider-activation-nixos`** - -- `RS-0882` | low | `d2b-provider-activation-nixos` | the six-case verification-fence table in `activation_verification_requires_all_trust_and_digest_fences` asserts without a per-case message, so a failure in case 3 of 6 reports only a line number and no case identity | fix: add a per-case failure message (e.g. `"case {i}: expected {expected_error:?}"`) to the loop assert | [packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activation-nixos/tests/reconcile.rs:447] | actionable | lane/d2b-provider-activation-nixos.md - -**`d2b-provider-audio-pipewire`** - -- `RS-0883` | low | `d2b-provider-audio-pipewire` | `SpeakerMixer::mix_level`'s saturation cap (sum capped at 100, authority.rs:236-241) has no boundary test: tests/authority.rs:26-31 asserts only 80+20=100, so a regression that removed the `min(100)` would pass | fix: add saturation rows (e.g. 80+80, 60+60+60) asserting the capped result | [tests/authority.rs:26-31, src/authority.rs:236-241] | actionable | lane/d2b-provider-audio-pipewire.md -- `RS-0884` | low | `d2b-provider-audio-pipewire` | tests/mediator.rs:13-24 is named `projection_cannot_open_pipewire_and_failed_set_preserves_state` but asserts only the Err and readiness; the state-preservation half of the claim is unasserted, so a regression that mutated grant/level on failure would pass | fix: assert `mediator.grant()`/`mediator.level()` unchanged after the failed set, or rename the test | [tests/mediator.rs:13-24] | actionable | lane/d2b-provider-audio-pipewire.md - -**`d2b-provider-clipboard-wayland`** - -- `RS-0885` | medium | `d2b-provider-clipboard-wayland` | published_selection_echo_is_always_suppressed_once asserts the identity wrapper should_suppress_published_selection_echo_state, a forwarding pin that fails only if the wrapper's triviality changes | fix: delete the test together with the wrapper (idiom finding #2); the behavior it gestures at is already covered by bridge_selection_echo_suppression_persists_for_source_vm_or_unknown_focus | [src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787] | actionable | lane/d2b-provider-clipboard-wayland-p1.md merged: d2b-provider-clipboard-wayland-p1#2 -- `RS-0886` | medium | `d2b-provider-clipboard-wayland` | the history eviction contract has no test: insert's LRU count bound (max_history_entries via evict_oldest) and byte-quota eviction (max_total_bytes via evict_until) are untested, as are materialize's owner and TTL rejections and entry_expiry | fix: unit tests in history.rs asserting eviction order and quota behavior (e.g. insert max_history_entries+1 entries and assert the oldest is evicted; fill past max_total_bytes and assert eviction down to quota) | [packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clipboard-wayland/src/history.rs:345-356, packages/d2b-provider-clipboard-wayland/src/history.rs:257-273] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0887` | medium | `d2b-provider-clipboard-wayland` | the controller's route-to-evidence admission gates (DisplayDependencyEvidence::from_authenticated_route and from_committed_display_route) have no tests even though from_committed_display_route is consumed by d2bd as the display-dependency authority input; only dependency_status is tested | fix: unit tests in controller/mod.rs exercising valid and each rejected route shape (wrong provider, wrong service, wrong evidence class, zero generations, wrong subject type) | [packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:144-201, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:360-371] | actionable | lane/d2b-provider-clipboard-wayland-p2.md -- `RS-0888` | low | `d2b-provider-clipboard-wayland` | FallbackArming::cancel_picker (the PickerCancelled transition) and NiriStateCache's WindowClosed and WorkspaceActivated event paths have no tests, leaving two state transitions and two event handlers unverified | fix: extend the existing table-style tests in fallback.rs and niri.rs with the missing transitions | [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:378-387, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:394] | actionable | lane/d2b-provider-clipboard-wayland-p2.md - -**`d2b-provider-config-nixos`** - -- `RS-0889` | medium | `d2b-provider-config-nixos` | `ConfigSyncResponse::document()`'s integrity contract (forged `sha256`/`bytes` mismatch must fail `EncodingFailed`, over-bound `content_base64` must fail `InvalidRequest`) is untested, and the daemon depends on this exact decode path (d2bd/src/composition.rs:11585) | fix: add integration tests that literal-construct a `ConfigSyncResponse` (fields are pub) with a wrong digest, a wrong byte count, and an over-`MAX_CONFIG_ENCODED_BYTES` payload and assert the failure codes | [packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixos/tests/config_lifecycle.rs:8-18] | actionable | lane/d2b-provider-config-nixos.md -- `RS-0890` | low | `d2b-provider-config-nixos` | no test exercises the `deny_unknown_fields` admission (an extra JSON key must make `validate_operation` fail `InvalidRequest`) or a payload with wrong field types (serde error path), which is exactly the typo-key case the attribute exists for | fix: extend `operation_validation_enforces_closed_identifiers_and_semantic_bounds` (tests/service_contract.rs:41-79) with an unknown-field payload and a wrong-typed payload | [packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixos/tests/service_contract.rs:41-79] | actionable | lane/d2b-provider-config-nixos.md - -**`d2b-provider-credential-entra`** - -- `RS-0891` | low | `d2b-provider-credential-entra` | `exact_consumer_guard_is_independent_of_request_fields` never exercises the guard its name claims: it only asserts that two `ResourceRef::parse` results differ, which can fail only if parsing collapses distinct inputs | fix: replace the body with an assertion on the actual guard (e.g. `provider.authorizes_consumer(&ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap())` true and a different Provider ref false), or delete the test | [packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-entra/src/lib.rs:1362] | actionable | lane/d2b-provider-credential-entra.md - -**`d2b-provider-credential-managed-identity`** - -- `RS-0892` | low | `d2b-provider-credential-managed-identity` | Table-driven loops assert without per-case failure messages, so the first failing case reports only a shared line number and not which case | fix: append `"method: {method:?}"` / `"binding: {binding:?}"` style messages to the `assert!`/`assert_eq!` calls in the method/route/placement matrices (mirroring the canary loops' messages at canary.rs:229-241) | [tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76] | actionable | lane/d2b-provider-credential-managed-identity.md - -**`d2b-provider-credential-secret-service`** - -- `RS-0893` | low | `d2b-provider-credential-secret-service` | table-driven loops assert without per-case failure messages (`locked_and_unavailable_map_to_provider_unavailable`, `only_user_agent_on_host_or_guest_is_accepted`, `collection_alias_accepts_spaces_and_rejects_unsafe_text`), so a failure reports only the line number and not which case failed | fix: add a `"case: {case:?}"`-style message to each loop assertion | [packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-credential-secret-service/tests/placement.rs:8, packages/d2b-provider-credential-secret-service/src/lib.rs:1966] | actionable | lane/d2b-provider-credential-secret-service.md - -**`d2b-provider-device-gpu`** - -- `RS-0894` | medium | `d2b-provider-device-gpu` | `GpuAuthorityAdmission::new`'s arbitration/render-node/max-holders matrix (`ArbitrationViolation`) and zero-token rejections (`StaleDeviceIdentity`) have no direct test even though they are the authority admission gate | fix: add table-driven rejection vectors over `GpuAuthorityAdmission::new` asserting the typed `GpuAuthorityError` variant for each illegal combination, mirroring the `admission()` fixture shape in tests/authority_lifecycle.rs | [packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/tests/authority_lifecycle.rs:245, packages/d2b-provider-device-gpu/tests/combined_reconcile.rs:238] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-device-usbip`** - -- `RS-0896` | medium | `d2b-provider-device-usbip` | `UsbipArbitrator` branches are untested: only the exclusive second-claim conflict is covered, while the constructor ceiling/ArbitrationViolation validation, `MaxClaimsExceeded`, idempotent re-claim by the same holder, and `release` have no test | fix: add a table-driven unit test over the ceiling, arbitration mode, re-claim, and release paths | [tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, src/arbitration.rs:117-121] | actionable | lane/d2b-provider-device-usbip.md -- `RS-0897` | medium | `d2b-provider-device-usbip` | the crate's declared wire types (`UsbipEventSource`, `UsbipReconcileAttemptContext`, `UsbipPublicDegradedReason`, `UsbipClaimSource`) have no serde round-trip test with a real-shaped payload, so kebab-case/camelCase wire drift would pass | fix: add a round-trip test deserializing a hand-written payload for each serde type and re-serializing | [src/reconcile_state.rs:51-308, src/state_machine.rs:98-100] | actionable | lane/d2b-provider-device-usbip.md -- `RS-0895` | low | `d2b-provider-device-usbip` | conformance.rs:63-66 asserts `AttachmentCommand::Attach(AttachmentActivation::Declared)` equals an identical literal, an assertion that cannot fail | fix: delete the tautological assert_eq (the same test's other asserts already pin the enum shape) | [tests/conformance.rs:63-66] | actionable | lane/d2b-provider-device-usbip.md - -**`d2b-provider-display-wayland`** - -- `RS-0898` | high | `d2b-provider-display-wayland` | two registry-handler tests cannot fail on any behavior change: `filtered_globals_preserve_original_global_names` (filter.rs:3213-3224) inserts entries into `advertised_globals`/`hidden_globals` and asserts their presence - pure setup restatement with no function under test - and `standard_clipboard_global_is_advertised_as_synthetic` (filter.rs:3264-3283) admits in its comment that the real path is untested and then asserts only `interface.name()` plus the map content it just inserted | fix: delete the first test and rewrite the second to exercise `prepare_global(11, ObjectInterface::WlDataDeviceManager, 3)` and assert the synthetic `GlobalAdvertisement` decision, as the neighboring `prepare_global_hides_*` tests already do | [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3213, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3264] | actionable | lane/d2b-provider-display-wayland-p1.md - -**`d2b-provider-guest-azure-container-apps`** - -- `RS-0900` | medium | `d2b-provider-guest-azure-container-apps` | the completed-operation ledger replay path (reconcile with a previously recorded operation id returns Converged without re-running effects, controller.rs:264-266) is contract behavior with no test - every test calls reconcile with a fresh operation id | fix: add a test that reconciles twice with the same id against a Running sandbox and asserts the second pass performs no effect calls (calls list unchanged) | [src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225] | actionable | lane/d2b-provider-guest-azure-container-apps.md -- `RS-0899` | low | `d2b-provider-guest-azure-container-apps` | stable_error_codes_are_bounded ends with a dead `let _ = ResourceRef::parse("Guest/gateway").unwrap();` that asserts nothing the test name claims and duplicates parse coverage exercised everywhere else | fix: delete the line (or fold the parse into an assertion the test actually promises) | [tests/provider_lifecycle.rs:536] | actionable | lane/d2b-provider-guest-azure-container-apps.md - -**`d2b-provider-guest-azure-virtual-machine`** - -- `RS-0901` | low | `d2b-provider-guest-azure-virtual-machine` | `every_controller_error_has_a_documented_stable_code` (tests/error_redaction.rs:17-38) asserts `!code().is_empty()` over a hand-enumerated variant list, but `code()` is a const fn whose exhaustive match makes an empty arm a compile error and the enumeration is not compiler-forced, so the test cannot meaningfully fail | fix: drop the loop and keep exact-code pinning (as `errors_and_handles_do_not_render_remote_values` already does for `arm-credential-denied`), or pin the full code table | [tests/error_redaction.rs:17] | actionable | lane/d2b-provider-guest-azure-virtual-machine.md - -**`d2b-provider-guest-cloud-hypervisor`** - -- `RS-0902` | medium | `d2b-provider-guest-cloud-hypervisor` | `assert!(plan.preserve_state())` (finalize_ordering_test.rs:286) cannot fail because `preserve_state()` returns a literal `true` (shutdown.rs:577), an assertion of implementation rather than behavior | fix: delete the assertion together with the accessor (finding #4) | [finalize_ordering_test.rs:286] | actionable | lane/d2b-provider-guest-cloud-hypervisor.md - -**`d2b-provider-guest-qemu-media`** - -- `RS-0903` | low | `d2b-provider-guest-qemu-media` | tests/lifecycle.rs repeats the same 8-field `DeviceObservation` literal ~8 times (e.g. 132-140,154-163,220-228,292-300,377-385( (each test then mutates a field or two (the fixture setup dominates the test bodies | fix: extract `fn device() -> DeviceObservation` helper (as `fn controller()` at tests/lifecycle.rs:104 already factors the bigger fixture (or build from a small builder | [packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:154, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:220, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:292] | actionable | lane/d2b-provider-guest-qemu-media.md - -**`d2b-provider-observability-otel`** - -- `RS-0904` | medium | `d2b-provider-observability-otel` | the resource-attribute validation test asserts only `is_err()` for both failure shapes,so a regression swapping the two wire-visible variants(`NotAllowlisted` vs `Invalid`)would pass | fix: replace the two `is_err()` assertions in `resource_attributes_have_a_separate_allowlist` with `assert_eq!)..., Err(ResourceAttributeError::NotAllowlisted))` for the unknown-key case,and `assert_eq!)..., Err(ResourceAttributeError::Invalid))` for the credential-canary value case | [metric_policy.rs:145, metric_policy.rs:150] | actionable | lane/d2b-provider-observability-otel.md - -**`d2b-provider-provider`** - -- `RS-0905` | medium | `d2b-provider-provider` | the `Degraded` phase projection (`optional_components_degraded` -> `ProviderPhase::Degraded` in `plan_observed`) is production-reachable through the driver's Enable/Update intents and has no test | fix: add a `#[tokio::test]` (or `#[test]` on `plan_observed` directly) that sets `optional_components_degraded = true` with ready dependencies and asserts `phase == Degraded` and `publish_exports` stays true | [src/providers.rs:206, src/driver.rs:1147] | actionable | lane/d2b-provider-provider.md - -**`d2b-provider-shell-terminal`** - -- `RS-0906` | low | `d2b-provider-shell-terminal` | `tests/supervisor_runtime.rs` repeats the full 14-line `ShellPool::new(PoolSpec::new)...))` fixture in 7 of its tests, while sibling `tests/controller_reconcile.rs:8` already defines a `pool()` helper. | fix: extract a parameterized `fn pool(max_sessions: u32, max_attached: u32) -> ShellPool` helper at the top of `tests/supervisor_runtime.rs` (or a shared `tests/common/mod.rs` used by both files), replacing the 7 inline constructions. | [tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.rs:142, tests/supervisor_runtime.rs:193] | actionable | lane/d2b-provider-shell-terminal.md - -**`d2b-provider-supervisor`** - -- `RS-0907` | low | `d2b-provider-supervisor` | `open_pidfd_dispatch_failure_is_ambiguous_only_after_identity_drift` pins the cross-crate broker error-kind contract by scraping source text (`include_str!("../../d2b-broker/src/live_handlers.rs")` + `LIVE_HANDLER_SOURCE.contains("PidfdRace")`) with the expected names duplicated as literals - brittle against broker renames, but the identical fix (a shared typed error-kind constant) was refused for this exact site because no exported constant exists and d2b-contracts-broker is out of lane | fix: none actionable; keep the scrape | [packages/d2b-provider-supervisor/src/broker.rs:2040-2043] | policy-confirmed | lane/d2b-provider-supervisor.md - -**`d2b-provider-system-core`** - -- `RS-0908` | low | `d2b-provider-system-core` | tests/host_reconciliation.rs repeats the `Probe` struct literal plus a 5-field `HostProbeMetadata` block five times (lines 204, 230, 254, 280, 306), one field differing per case | fix: a `Probe::new(capabilities, user_manager_available, gate, kernel_release)` constructor or default-and-mutate helper | [tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230] | actionable | lane/d2b-provider-system-core.md - -**`d2b-provider-transport-vsock`** - -- `RS-0909` | low | `d2b-provider-transport-vsock` | tests/observe.rs asserts `ServicePhase::Ready == ServicePhase::Ready`, a self-comparison that cannot fail and adds nothing to a test already asserting the observation fields - dead assertion weight with no regression value. | fix: delete line 15 (the test still asserts `observation.phase == TransportPhase::Released`), or replace with a real cross-variant assertion (e.g. `assert_ne!(ServicePhase::Ready, ServicePhase::Serving)` | [packages/d2b-provider-transport-vsock/tests/observe.rs:14-15] | actionable | lane/d2b-provider-transport-vsock.md - -**`d2b-provider-user`** - -- `RS-0910` | medium | `d2b-provider-user` | the "cached unrealized phase re-discovers" contract is tested only for `Pending` (`reconcile_rediscovers_a_cached_unrealized_phase`), so a regression that widened the `observed_ready` short-circuit predicate (driver.rs:283) to accept `Degraded` or `Unknown` would pass every test | fix: extend the phase loop in `reconcile_publishes_the_user_discovery_projection` (driver.rs:789-813) to run a second reconcile per phase and assert the second `observe-user` call for all three unrealized phases | [packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs:281-284] | actionable | lane/d2b-provider-user.md - -**`d2b-provider-wayland-policy`** - -- `RS-0911` | low | `d2b-provider-wayland-policy` | Dead no-op line in `the_policy_envelope_is_the_whole_contract`: `let _ = ResourceRef::parse)...)` asserts nothing and cannot fail | fix: assert the parse succeeds (e.g. `.expect("the policy reference parses")`), or delete the line | [packages/d2b-provider-wayland-policy/tests/registration.rs:93] | actionable | lane/d2b-provider-wayland-policy.md - -**`d2b-provider-zone-link`** - -- `RS-0912` | low | `d2b-provider-zone-link` | three table-driven loops assert without a per-case failure message, so a failing row reports only a line number, not which state/error/key failed | fix: add messages naming the loop variable (`"state: {state:?}"`, `"key: {key}"`, `"error: {error:?}"`) to the loops at zone_links.rs:2513-2519, 3092-3094, and 3133-3167 | [packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/src/zone_links.rs:3093, packages/d2b-provider-zone-link/src/zone_links.rs:3162] | actionable | lane/d2b-provider-zone-link.md - -**`d2b-resource-api`** - -- `RS-0914` | medium | `d2b-resource-api` | `list_returns_snapshot_revision_and_watch_refuses_until_wired` compares the wire snapshot's epoch-seconds half against `SystemTime::now()` taken after the list round-trip, so a second boundary crossing between the two instants flakes the test | fix: assert the mapping with a one-second tolerance or inject the clock | [packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src/manager_backend/tests.rs:1460, packages/d2b-resource-api/src/manager_backend/tests.rs:1461] | actionable | lane/d2b-resource-api-p2.md -- `RS-0913` | low | `d2b-resource-api` | `status_owner_matching_generation_is_representable` asserts only that `ControllerGeneration::new(11)` and `ResourceGeneration::new(11)` succeed on literals, restating the type system rather than a behavior contract | fix: delete it, or convert the representability claim into the wire-compatibility test it is meant to document (asserting the status-owner comparison path with a real mismatch) | [service.rs:3377] | actionable | lane/d2b-resource-api-p1.md - -**`d2b-resource-client`** - -- `RS-0915` | low | `d2b-resource-client` | the close/cancel error-rollback paths are untested: `ProcessAttachStream::close`/`cancel` and `ResourceWatch::close` restore the open state when the transport close errors, but no test injects that failure | fix: add failure-injection tests asserting the state rolls back to open and a second close retries | [packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/process_attach.rs:541, packages/d2b-resource-client/src/zone_client.rs:567] | actionable | lane/d2b-resource-client.md - -**`d2b-resource-runtime`** - -- `RS-0916` | high | `d2b-resource-runtime` | `display_shows_epoch_and_sequence` asserts `rendered.contains("[PHONE]")` on the rendering `e1728000000+42`, an assertion that cannot pass, so the test fails at HEAD (route review-pass; read-only audit) | fix: delete the stray `[PHONE]` assertion (the epoch/sequence assertions on the same line already cover the contract) | [packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revision.rs:71] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0917` | low | `d2b-resource-runtime` | `wire_budget_bounds_sequence_for_u32_low_word` asserts `WIRE_SEQUENCE_BUDGET == 1 << 32`, restating the constant's own definition (revision.rs:41), so it cannot fail meaningfully | fix: delete it or assert a behavioral consequence (e.g. that a sequence at the budget still packs into the u32 low word of the U8 mapping) | [packages/d2b-resource-runtime/src/revision.rs:182] | actionable | lane/d2b-resource-runtime-p1.md -- `RS-0918` | low | `d2b-resource-runtime` | the lib.rs `modules_resolve` smoke test asserts each `MODULE_NAME` const against its own literal, pinning source text with no behavioral value (the A5 not-applied row, docs/explanation/over-engineering-audit-record.md:458, covers the consts and this test; the site still matches the record) | fix: fold into the A5 decision (delete both, or keep only as a compile-resolution check without the value assertions) | [packages/d2b-resource-runtime/src/lib.rs:66] | actionable | lane/d2b-resource-runtime-p1.md - -**`d2b-session`** - -- `RS-0919` | low | `d2b-session` | unpolled_cancellation_on_real_driver_reclaims_request_for_reuse spins up to 64 yield_now iterations waiting for the cancellation task to reclaim the request, while its sibling test waits on a Notify | fix: wait on a Notify (or a tokio::time::timeout around a Notify) instead of the fixed spin cap | [tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139] | actionable | lane/d2b-session-p2.md - -**`d2b-sk-frontend`** - -- `RS-0920` | medium | `d2b-sk-frontend` | the parse side of the byte-exact UHID protocol (`read_event`'s event-type dispatch, the OUTPUT size field at payload[4096], GET_REPORT id, lifecycle mapping, short-header error) has no test while the builders have 12 byte-exact tests, so a regression in the parse offsets passes the suite | fix: extract `parse_event(buf: &[u8]) -> io::Result>` from `read_event` and table-test the dispatch against hand-built buffers (plus a `build_get_report_reply_error` layout test) | [packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186] | actionable | lane/tail-6.md - -**`d2b-telemetry`** - -- `RS-0921` | low | `d2b-telemetry` | `target_buckets_are_present` pins three bucket constants by asserting one member value each, a tautology that fails on refactor and passes on behavior change | fix: delete the test, or replace it with a behavior test (e.g. a `MetricFamily::new` built with `CONTROLLER_HINT_BUCKETS_SECONDS` accepts an in-range histogram value and rejects an out-of-range one) | [packages/d2b-telemetry/src/meter_registry.rs:176-180] | actionable | lane/d2b-telemetry.md - -**`d2b-unsafe-local-helper`** - -- `RS-0922` | low | `d2b-unsafe-local-helper` | adoption_degrades_identity_ambiguity_without_stopping_scope re-derives snapshot's inline identity-mismatch match on a hand-built ScopeInspection (test lines 1567-1576 mirror production lines 505-508), so it still passes if snapshot later reports `state` instead of Degraded for a mismatched scope | fix: extract the `ScopeInspection::observable_state()` decision used by snapshot into a testable function and assert on that extracted behavior | [packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helper/src/runtime.rs:505-508] | actionable | lane/d2b-unsafe-local-helper.md - -**`d2b-zone-routing`** - -- `RS-0923` | low | `d2b-zone-routing` | `every_reason_the_engine_can_produce_is_covered_by_this_suite` checks only that the 16 named closed reasons have distinct `label()`s, not that the suite produces any of them - the name promises a coverage property the row never asserts | fix: rename it to `every_engine_reason_has_a_distinct_wire_label` and, if coverage is actually wanted, record the reasons each vector produced and assert the set at the end | [packages/d2b-zone-routing/src/engine.rs:3333] | actionable | lane/d2b-zone-routing.md -- `RS-0924` | low | `d2b-zone-routing` | `durable_exec_table_is_bounded_to_ephemeral_processes` ends with a dead `let _ = ZoneId::parse("dev").unwrap();` line that exercises nothing and exists only to use an import | fix: delete the line and the now-unused `ZoneId` import from the test module | [packages/d2b-zone-routing/src/router.rs:517] | actionable | lane/d2b-zone-routing.md - -**`d2bd-runtime`** - -- `RS-0925` | high | `d2bd-runtime` | `sd_notify_ready_noops_without_notify_socket` (runtime_process.rs:543-546) and `sd_notify_ready_errors_when_socket_is_unreachable` (runtime_process.rs:589-594) cannot fail: each body only calls `sd_notify_ready)...)` on a path the function returns without panicking (None early-return; Some-to-missing-socket caught and warn-logged), with no assertion anywhere | fix: delete both, or give them an observable assertion modeled on the sibling `sd_notify_ready_sends_pathname_datagram` (bind a datagram listener, send the payload, assert the received bytes / exit-code), so the suite refuses to pass silently when the notification path regresses | [runtime_process.rs:543-546, runtime_process.rs:589-594] | actionable | lane/d2bd-runtime-p2.md -- `RS-0926` | low | `d2bd-runtime` | `no_op_does_not_write_file` cannot fail on the behavior it names: the temp dir is never connected to the log (`DaemonAuditLog::no_op()` has no state dir; the comment at daemon_audit.rs:2368 admits the limitation), so `count == 0` is vacuously true and only the write-does-not-error `expect` is exercised | fix: make the state dir injectable (or test via a log constructed with a read-only/blocked state dir) so the no-file-created claim is actually asserted, or rename the test to what it verifies | [packages/d2bd-runtime/src/daemon_audit.rs:2367] | actionable | lane/d2bd-runtime-p4.md - -**`xtask`** - -- `RS-0928` | low | `xtask` | `workflow_status_all_enumerates_every_variant` and `wave_commands_enumerates_every_stage` assert `ALL.contains(status)` for every status drawn from `ALL` itself, so the runtime assertion is tautological and can never fail; the real guard is the wildcard-free match's compile-time exhaustiveness, which the assert adds nothing to | fix: drop the `assert!` and keep the wildcard-free match (the compile-fail property), or assert a property not derived from the same enumeration | [packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079] | actionable | lane/xtask-p3.md -- `RS-0927` | low | `xtask` | the broker-operation domain test recomputes its expectation with the same filter the function under test applies (`catalog.rows.iter().filter_map(|row| row.wire_variant.clone())` re-derives `broker_operation_values`' own pick), so the `assert_eq!(values, expected)` can never disagree with the projection logic; only the human-written pins (`UsbipBind` present, `SpawnRunner`/`vmStart` absent) carry behaviour | fix: drop the recomputed `expected` and assert the human-written pins only (the vector equality adds nothing the pins do not) | [packages/xtask/src/gen_layer_catalogs.rs:705] | actionable | lane/xtask-p1.md - -### `supply` - -Supply chain (workspace level): advisories, licences, duplicates, tree weight; every finding ends in a decision. - -**`X1-supply-chain`** - -- `RS-0933` | medium | `X1-supply-chain` | d2b-session depends on d2b-audit but the name appears nowhere in its sources; the dep edge is dead weight in both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28] | actionable | lane/X1-supply-chain.md -- `RS-0934` | medium | `X1-supply-chain` | d2b-session depends on d2b-telemetry but no source reference exists; the edge is carried into both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31] | actionable | lane/X1-supply-chain.md -- `RS-0935` | medium | `X1-supply-chain` | d2b-session's dev-dependency serde_json (workspace-inherited) has zero uses in any of its files | fix: remove the dev-dep (the guest lock regenerates without it) | [packages/d2b-session/Cargo.toml:44] | actionable | lane/X1-supply-chain.md -- `RS-0936` | medium | `X1-supply-chain` | d2b-telemetry inherits rustix via workspace=true but no source in the crate references it; the dep is compiled into the telemetry crate for nothing | fix: remove rustix from [dependencies] (the root workspace entry stays, other members use it); regenerate the guest lock, which carries d2b-telemetry | [packages/d2b-telemetry/Cargo.toml:14] | actionable | lane/X1-supply-chain.md -- `RS-0937` | medium | `X1-supply-chain` | d2b-provider-quota inherits serde_json via workspace=true but no source or test references it | fix: remove serde_json from [dependencies] (and from the generated BUILD deps on the next regen) | [packages/d2b-provider-quota/Cargo.toml:24] | actionable | lane/X1-supply-chain.md -- `RS-0938` | medium | `X1-supply-chain` | d2b-bus's dev-dependency tempfile has zero uses across src/tests(including the ui test tree) | fix: remove the dev-dep | [packages/d2b-bus/Cargo.toml:41] | actionable | lane/X1-supply-chain.md -- `RS-0939` | medium | `X1-supply-chain` | d2b-provider-activation-nixos inherits serde via workspace=true but no source or test in the crate names it | fix: remove serde from [dependencies] | [packages/d2b-provider-activation-nixos/Cargo.toml:35] | actionable | lane/X1-supply-chain.md -- `RS-0940` | medium | `X1-supply-chain` | d2b-provider-audio-pipewire inherits schemars via workspace=true but no derive or path in its sources uses it | fix: remove schemars from [dependencies] | [packages/d2b-provider-audio-pipewire/Cargo.toml:25] | actionable | lane/X1-supply-chain.md -- `RS-0941` | medium | `X1-supply-chain` | d2b-provider-guest-azure-container-apps inherits sha2 via workspace=true but no source reference exists | fix: remove sha2 from [dependencies] | [packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21] | actionable | lane/X1-supply-chain.md -- `RS-0942` | medium | `X1-supply-chain` | d2b-provider-device-gpu declares async-trait but no #[async_trait] or use path names it | fix: remove async-trait from [dependencies] (the Bazel proc-macro dep drops with it on regen) | [packages/d2b-provider-device-gpu/Cargo.toml:20] | actionable | lane/X1-supply-chain.md -- `RS-0943` | medium | `X1-supply-chain` | d2b-provider-device-gpu depends on d2b-resource-types but no source or test in the crate uses it; the edge carries into Bazel too | fix: remove d2b-resource-types from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39] | actionable | lane/X1-supply-chain.md -- `RS-0944` | medium | `X1-supply-chain` | d2b depends on d2b-zone-routing but no source or test references it; the edge is carried into Bazel too | fix: remove d2b-zone-routing from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55] | actionable | lane/X1-supply-chain.md -- `RS-0946` | medium | `X1-supply-chain` | nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a syscall-family crate reach shipped binaries | fix: keep the workspace pin at 0.29, and record+accept the 0.26/0.31 legs with expiry in a [bans] comment (name, pullers, re-check trigger, per DENY.md); then consider flipping multiple-versions to `deny` | [deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33] | actionable | lane/X1-supply-chain.md -- `RS-0947` | medium | `X1-supply-chain` | rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shipped binaries | fix: accept with expiry+record in a [bans] comment (re-check at each dep refresh; or plan a dedicated pass migrating the workspace pin to 1.1 and re-verifying the feature surface, which the root comments pin at 0.38 | [Cargo.toml:202, deny.toml:2] | actionable | lane/X1-supply-chain.md -- `RS-0948` | medium | `X1-supply-chain` | d2b-provider-transport-azure-relay pins webpki-roots "0.26" directly while its tokio-tungstenite 0.24 dep pulls 1.0.9 via its rustls-tls-webpki-roots feature, so the crate builds both legs | fix: upgrade the direct pin to "1" and drop the 0.26 leg(verify the TLS_SERVER_ROOTS API at the call site; if 0.26-only items are used, accept+record+expiry instead) | [packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36] | actionable | lane/X1-supply-chain.md -- `RS-0950` | medium | `X1-supply-chain` | packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2.128, uuid 1.26.1, aws-lc-rs 1.18.1, mio 1.2.3, etc), so the advisory and licence postures of the two shipped trees are assessed against different dependency sets at the same date | fix: regenerate both lockfiles from ONE index snapshot on the next dependency refresh (keeping the guest tree's host-only exclusions; add a drift check comparing shared-crate versions across the two locks) | [packages/Cargo.guest.lock:1, flake.nix:389] | actionable | lane/X1-supply-chain.md -- `RS-0945` | low | `X1-supply-chain` | 13 member decls pin literal versions of workspace-declared deps rustix (3) and sha2 (10, two of them in d2b-broker) instead of the house `workspace = true` pattern (429 workspace-inherit decls across the workspace), duplicating the version truth the root table owns | fix: convert them to `rustix = { workspace = true, features = [...] }` and `sha2 = { workspace = true }`, keeping member-side features (verified additive on the pinned toolchain: a workspace entry + member features resolves with the union on cargo 1.97, offline probe) | [Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, packages/d2b-provider-process/Cargo.toml:30] | actionable | lane/X1-supply-chain.md -- `RS-0949` | low | `X1-supply-chain` | the remaining ~31 duplicate clusters(hashbrown,bitflags,heck,indexmap,linux-raw-sys,memoffset,phf family,proc-macro-crate,r-efi,rand,rand_core,syn,thiserror,toml_datetime,toml_edit,winnow,windows-sys family,windows-link,etc) resolve transitively-only at multiple versions,and deny.toml records none of it (multiple-versions = "warn" alone keeps them invisible) | fix: annotate [bans] with the accepted-cluster inventory(name, versions, pullers, re-check trigger, per DENY.md; then flip multiple-versions to `deny` once the workspace-direct clusters (#14-#16) resolve | [deny.toml:2] | actionable | lane/X1-supply-chain.md -- `RS-0951` | low | `X1-supply-chain` | deny.toml's licence confidence-threshold sits at 0.8, below the rust-supply-chain skill's 0.9 floor, so licences the tool is guessing at(~80% confidence) pass the gate silently,and rare allow-listed licences(CDLA-Permissive-2.0, Unicode-DFS-2016) may be the reason the bar was lowered | fix: raise to 0.9 (and move any failing allow-listed licence to a per-crate `[licenses.exceptions]` entry with the reason attached, per DENY.md),verifying against the vendored tree at the next flake check | [deny.toml:21] | actionable | lane/X1-supply-chain.md - -**`d2b-provider-audio-pipewire`** - -- `RS-0929` | low | `d2b-provider-audio-pipewire` | Cargo.toml declares `schemars` as a runtime dependency with zero uses in src or tests, and `serde_json` (tests-only, 12 hits) sits in `[dependencies]` instead of `[dev-dependencies]` | fix: drop the `schemars` entry and move `serde_json` to `[dev-dependencies]` (Cargo.toml:24-25) | [Cargo.toml:24, Cargo.toml:25] | actionable | lane/d2b-provider-audio-pipewire.md - -**`d2b-provider-device-gpu`** - -- `RS-0930` | low | `d2b-provider-device-gpu` | manifest dependencies `async-trait` and `d2b-resource-types` appear nowhere in the crate's src/+tests/ | fix: drop both from Cargo.toml (and the mirrored Bazel deps) or justify their retention in the manifest | [packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.toml:25] | actionable | lane/d2b-provider-device-gpu.md - -**`d2b-provider-guest-azure-container-apps`** - -- `RS-0931` | low | `d2b-provider-guest-azure-container-apps` | the `sha2` dependency is unused: the name appears nowhere in src/ or tests/ (only in Cargo.toml:21 and as the prose word "digests" in README.md:51) | fix: remove `sha2 = { workspace = true }` from the crate manifest (the workspace dep stays for its other consumers) | [Cargo.toml:21] | actionable | lane/d2b-provider-guest-azure-container-apps.md - -**`d2b-provider-quota`** - -- `RS-0932` | low | `d2b-provider-quota` | `serde_json` is a declared dependency but appears nowhere in the crate's src/ or tests/ | fix: drop `serde_json.workspace = true` from [dependencies] | [packages/d2b-provider-quota/Cargo.toml:24] | actionable | lane/tail-3.md - -## 3. Per-crate index - -| crate | high | medium | low | top finding ids | lanes | -| --- | ---: | ---: | ---: | --- | --- | -| `d2b` | 0 | 6 | 17 | RS-0037, RS-0352, RS-0477, RS-0478, RS-0771 | [d2b-p1](lane/d2b-p1.md), [d2b-p2](lane/d2b-p2.md), [d2b-p3](lane/d2b-p3.md) | -| `d2b-audit` | 0 | 5 | 5 | RS-0001, RS-0239, RS-0316, RS-0451, RS-0452 | [d2b-audit](lane/d2b-audit.md) | -| `d2b-broker` | 5 | 21 | 35 | RS-0455, RS-0837, RS-0841, RS-0842, RS-0840 | [d2b-broker-p1](lane/d2b-broker-p1.md), [d2b-broker-p2](lane/d2b-broker-p2.md), [d2b-broker-p3](lane/d2b-broker-p3.md), [d2b-broker-p4](lane/d2b-broker-p4.md), [d2b-broker-p5](lane/d2b-broker-p5.md), [d2b-broker-p6](lane/d2b-broker-p6.md), [d2b-broker-p7](lane/d2b-broker-p7.md) | -| `d2b-broker-composition` | 0 | 0 | 9 | RS-0004, RS-0005, RS-0126, RS-0127, RS-0128 | [d2b-broker-composition](lane/d2b-broker-composition.md) | -| `d2b-broker-fixture-handlers` | 0 | 0 | 0 | - | [tail-1](lane/tail-1.md) | -| `d2b-broker-fixture-syscall-surface` | 0 | 1 | 0 | RS-0856 | [tail-1](lane/tail-1.md) | -| `d2b-bus` | 1 | 8 | 15 | RS-0867, RS-0245, RS-0324, RS-0325, RS-0326 | [d2b-bus-p1](lane/d2b-bus-p1.md), [d2b-bus-p2](lane/d2b-bus-p2.md) | -| `d2b-contracts` | 0 | 3 | 0 | RS-0327, RS-0461, RS-0546 | [d2b-contracts](lane/d2b-contracts.md) | -| `d2b-contracts-broker` | 0 | 5 | 5 | RS-0246, RS-0247, RS-0328, RS-0547, RS-0639 | [d2b-contracts-broker](lane/d2b-contracts-broker.md) | -| `d2b-contracts-control` | 0 | 6 | 8 | RS-0248, RS-0548, RS-0641, RS-0642, RS-0643 | [d2b-contracts-control](lane/d2b-contracts-control.md) | -| `d2b-contracts-provider` | 0 | 5 | 17 | RS-0253, RS-0463, RS-0646, RS-0871, RS-0872 | [d2b-contracts-provider-p1](lane/d2b-contracts-provider-p1.md), [d2b-contracts-provider-p2](lane/d2b-contracts-provider-p2.md) | -| `d2b-contracts-resource` | 0 | 8 | 11 | RS-0022, RS-0256, RS-0255, RS-0257, RS-0468 | [d2b-contracts-resource-p1](lane/d2b-contracts-resource-p1.md), [d2b-contracts-resource-p2](lane/d2b-contracts-resource-p2.md) | -| `d2b-contracts-zone-session` | 0 | 5 | 11 | RS-0469, RS-0552, RS-0651, RS-0873, RS-0874 | [d2b-contracts-zone-session-p1](lane/d2b-contracts-zone-session-p1.md), [d2b-contracts-zone-session-p2](lane/d2b-contracts-zone-session-p2.md) | -| `d2b-controller-toolkit` | 0 | 0 | 1 | RS-0259 | [tail-1](lane/tail-1.md) | -| `d2b-core` | 0 | 12 | 17 | RS-0261, RS-0348, RS-0345, RS-0349, RS-0346 | [d2b-core-p1](lane/d2b-core-p1.md), [d2b-core-p2](lane/d2b-core-p2.md) | -| `d2b-core-controller` | 0 | 7 | 8 | RS-0340, RS-0341, RS-0342, RS-0343, RS-0553 | [d2b-core-controller-p1](lane/d2b-core-controller-p1.md), [d2b-core-controller-p2](lane/d2b-core-controller-p2.md) | -| `d2b-host` | 0 | 2 | 6 | RS-0262, RS-0878, RS-0351, RS-0557, RS-0656 | [d2b-host](lane/d2b-host.md) | -| `d2b-host-activation-helper` | 0 | 1 | 0 | RS-0859 | [tail-1](lane/tail-1.md) | -| `d2b-process-conformance` | 0 | 0 | 11 | RS-0153, RS-0265, RS-0355, RS-0356, RS-0357 | [d2b-process-conformance](lane/d2b-process-conformance.md) | -| `d2b-provider` | 0 | 2 | 1 | RS-0661, RS-0844, RS-0154 | [d2b-provider](lane/d2b-provider.md) | -| `d2b-provider-activation-nixos` | 0 | 2 | 4 | RS-0480, RS-0662, RS-0359, RS-0360, RS-0585 | [d2b-provider-activation-nixos](lane/d2b-provider-activation-nixos.md) | -| `d2b-provider-audio-binding` | 0 | 0 | 1 | RS-0663 | [tail-1](lane/tail-1.md) | -| `d2b-provider-audio-pipewire` | 0 | 2 | 10 | RS-0481, RS-0664, RS-0266, RS-0267, RS-0361 | [d2b-provider-audio-pipewire](lane/d2b-provider-audio-pipewire.md) | -| `d2b-provider-audio-service` | 0 | 0 | 0 | - | [tail-2](lane/tail-2.md) | -| `d2b-provider-clipboard-wayland` | 0 | 9 | 22 | RS-0040, RS-0039, RS-0268, RS-0586, RS-0666 | [d2b-provider-clipboard-wayland-p1](lane/d2b-provider-clipboard-wayland-p1.md), [d2b-provider-clipboard-wayland-p2](lane/d2b-provider-clipboard-wayland-p2.md) | -| `d2b-provider-command` | 0 | 1 | 1 | RS-0561, RS-0671 | [tail-2](lane/tail-2.md) | -| `d2b-provider-config-nixos` | 0 | 1 | 8 | RS-0889, RS-0044, RS-0156, RS-0272, RS-0365 | [d2b-provider-config-nixos](lane/d2b-provider-config-nixos.md) | -| `d2b-provider-credential` | 0 | 1 | 3 | RS-0813, RS-0157, RS-0273, RS-0673 | [d2b-provider-credential](lane/d2b-provider-credential.md) | -| `d2b-provider-credential-entra` | 0 | 2 | 3 | RS-0045, RS-0366, RS-0367, RS-0674, RS-0891 | [d2b-provider-credential-entra](lane/d2b-provider-credential-entra.md) | -| `d2b-provider-credential-managed-identity` | 0 | 1 | 4 | RS-0274, RS-0368, RS-0488, RS-0675, RS-0892 | [d2b-provider-credential-managed-identity](lane/d2b-provider-credential-managed-identity.md) | -| `d2b-provider-credential-secret-service` | 0 | 3 | 3 | RS-0588, RS-0676, RS-0845, RS-0046, RS-0677 | [d2b-provider-credential-secret-service](lane/d2b-provider-credential-secret-service.md) | -| `d2b-provider-device` | 0 | 1 | 0 | RS-0369 | [tail-2](lane/tail-2.md) | -| `d2b-provider-device-gpu` | 0 | 5 | 8 | RS-0275, RS-0562, RS-0678, RS-0814, RS-0894 | [d2b-provider-device-gpu](lane/d2b-provider-device-gpu.md) | -| `d2b-provider-device-security-key` | 0 | 2 | 3 | RS-0681, RS-0815, RS-0050, RS-0372, RS-0680 | [d2b-provider-device-security-key](lane/d2b-provider-device-security-key.md) | -| `d2b-provider-device-tpm` | 0 | 3 | 8 | RS-0373, RS-0489, RS-0846, RS-0051, RS-0159 | [d2b-provider-device-tpm](lane/d2b-provider-device-tpm.md) | -| `d2b-provider-device-usbip` | 0 | 7 | 4 | RS-0377, RS-0378, RS-0490, RS-0684, RS-0685 | [d2b-provider-device-usbip](lane/d2b-provider-device-usbip.md) | -| `d2b-provider-display-wayland` | 1 | 6 | 16 | RS-0898, RS-0059, RS-0381, RS-0379, RS-0491 | [d2b-provider-display-wayland-p1](lane/d2b-provider-display-wayland-p1.md), [d2b-provider-display-wayland-p2](lane/d2b-provider-display-wayland-p2.md) | -| `d2b-provider-emergency-policy` | 0 | 0 | 0 | - | [tail-2](lane/tail-2.md) | -| `d2b-provider-endpoint` | 0 | 2 | 1 | RS-0061, RS-0565, RS-0060 | [d2b-provider-endpoint](lane/d2b-provider-endpoint.md) | -| `d2b-provider-guest` | 0 | 3 | 4 | RS-0276, RS-0817, RS-0818, RS-0162, RS-0163 | [d2b-provider-guest](lane/d2b-provider-guest.md) | -| `d2b-provider-guest-azure-container-apps` | 0 | 2 | 10 | RS-0277, RS-0900, RS-0164, RS-0165, RS-0166 | [d2b-provider-guest-azure-container-apps](lane/d2b-provider-guest-azure-container-apps.md) | -| `d2b-provider-guest-azure-virtual-machine` | 0 | 4 | 10 | RS-0170, RS-0278, RS-0279, RS-0691, RS-0062 | [d2b-provider-guest-azure-virtual-machine](lane/d2b-provider-guest-azure-virtual-machine.md) | -| `d2b-provider-guest-cloud-hypervisor` | 0 | 7 | 8 | RS-0281, RS-0282, RS-0283, RS-0386, RS-0387 | [d2b-provider-guest-cloud-hypervisor](lane/d2b-provider-guest-cloud-hypervisor.md) | -| `d2b-provider-guest-qemu-media` | 0 | 3 | 6 | RS-0284, RS-0285, RS-0694, RS-0067, RS-0174 | [d2b-provider-guest-qemu-media](lane/d2b-provider-guest-qemu-media.md) | -| `d2b-provider-host` | 0 | 0 | 5 | RS-0068, RS-0175, RS-0392, RS-0494, RS-0495 | [d2b-provider-host](lane/d2b-provider-host.md) | -| `d2b-provider-network-local` | 0 | 2 | 8 | RS-0393, RS-0566, RS-0069, RS-0070, RS-0176 | [d2b-provider-network-local](lane/d2b-provider-network-local.md) | -| `d2b-provider-notification-desktop` | 0 | 4 | 9 | RS-0394, RS-0497, RS-0498, RS-0695, RS-0071 | [d2b-provider-notification-desktop](lane/d2b-provider-notification-desktop.md) | -| `d2b-provider-observability-otel` | 0 | 3 | 6 | RS-0697, RS-0698, RS-0904, RS-0179, RS-0287 | [d2b-provider-observability-otel](lane/d2b-provider-observability-otel.md) | -| `d2b-provider-operation` | 0 | 0 | 1 | RS-0699 | [tail-2](lane/tail-2.md) | -| `d2b-provider-process` | 0 | 1 | 5 | RS-0819, RS-0180, RS-0181, RS-0500, RS-0700 | [d2b-provider-process](lane/d2b-provider-process.md) | -| `d2b-provider-process-minijail` | 0 | 0 | 2 | RS-0288, RS-0701 | [tail-3](lane/tail-3.md) | -| `d2b-provider-process-systemd` | 0 | 1 | 9 | RS-0702, RS-0073, RS-0289, RS-0290, RS-0397 | [d2b-provider-process-systemd](lane/d2b-provider-process-systemd.md) | -| `d2b-provider-provider` | 0 | 1 | 5 | RS-0905, RS-0182, RS-0183, RS-0400, RS-0401 | [d2b-provider-provider](lane/d2b-provider-provider.md) | -| `d2b-provider-quota` | 0 | 0 | 2 | RS-0402, RS-0932 | [tail-3](lane/tail-3.md) | -| `d2b-provider-resource-export` | 0 | 0 | 1 | RS-0403 | [tail-3](lane/tail-3.md) | -| `d2b-provider-resource-import` | 0 | 0 | 1 | RS-0404 | [tail-3](lane/tail-3.md) | -| `d2b-provider-role` | 0 | 0 | 2 | RS-0405, RS-0704 | [tail-3](lane/tail-3.md) | -| `d2b-provider-role-binding` | 0 | 0 | 0 | - | [tail-4](lane/tail-4.md) | -| `d2b-provider-seccomp-profile` | 0 | 1 | 2 | RS-0705, RS-0074, RS-0406 | [tail-4](lane/tail-4.md) | -| `d2b-provider-shell-pool` | 0 | 0 | 0 | - | [tail-4](lane/tail-4.md) | -| `d2b-provider-shell-session` | 0 | 0 | 0 | - | [tail-4](lane/tail-4.md) | -| `d2b-provider-shell-terminal` | 0 | 1 | 2 | RS-0706, RS-0184, RS-0906 | [d2b-provider-shell-terminal](lane/d2b-provider-shell-terminal.md) | -| `d2b-provider-supervisor` | 0 | 4 | 4 | RS-0407, RS-0408, RS-0502, RS-0568, RS-0075 | [d2b-provider-supervisor](lane/d2b-provider-supervisor.md) | -| `d2b-provider-system-core` | 0 | 3 | 9 | RS-0409, RS-0413, RS-0707, RS-0077, RS-0078 | [d2b-provider-system-core](lane/d2b-provider-system-core.md) | -| `d2b-provider-telemetry-binding` | 0 | 0 | 1 | RS-0291 | [tail-4](lane/tail-4.md) | -| `d2b-provider-telemetry-service` | 0 | 1 | 2 | RS-0504, RS-0292, RS-0505 | [tail-5](lane/tail-5.md) | -| `d2b-provider-test-controller` | 0 | 1 | 2 | RS-0592, RS-0506, RS-0593 | [tail-5](lane/tail-5.md) | -| `d2b-provider-toolkit` | 0 | 7 | 14 | RS-0079, RS-0414, RS-0507, RS-0508, RS-0510 | [d2b-provider-toolkit-p1](lane/d2b-provider-toolkit-p1.md), [d2b-provider-toolkit-p2](lane/d2b-provider-toolkit-p2.md) | -| `d2b-provider-transport-azure-relay` | 0 | 5 | 11 | RS-0512, RS-0513, RS-0569, RS-0787, RS-0850 | [d2b-provider-transport-azure-relay](lane/d2b-provider-transport-azure-relay.md) | -| `d2b-provider-transport-unix` | 0 | 0 | 3 | RS-0597, RS-0711, RS-0823 | [tail-5](lane/tail-5.md) | -| `d2b-provider-transport-vsock` | 0 | 1 | 5 | RS-0571, RS-0083, RS-0598, RS-0599, RS-0712 | [d2b-provider-transport-vsock](lane/d2b-provider-transport-vsock.md) | -| `d2b-provider-user` | 1 | 2 | 3 | RS-0851, RS-0824, RS-0910, RS-0192, RS-0514 | [d2b-provider-user](lane/d2b-provider-user.md) | -| `d2b-provider-volume` | 0 | 1 | 4 | RS-0420, RS-0084, RS-0193, RS-0194, RS-0789 | [d2b-provider-volume](lane/d2b-provider-volume.md) | -| `d2b-provider-volume-binding` | 0 | 1 | 3 | RS-0515, RS-0195, RS-0713, RS-0826 | [d2b-provider-volume-binding](lane/d2b-provider-volume-binding.md) | -| `d2b-provider-volume-local` | 0 | 2 | 3 | RS-0421, RS-0572, RS-0085, RS-0294, RS-0714 | [d2b-provider-volume-local](lane/d2b-provider-volume-local.md) | -| `d2b-provider-volume-virtiofs` | 0 | 0 | 0 | - | [d2b-provider-volume-virtiofs](lane/d2b-provider-volume-virtiofs.md) | -| `d2b-provider-wayland-policy` | 1 | 1 | 1 | RS-0516, RS-0573, RS-0911 | [d2b-provider-wayland-policy](lane/d2b-provider-wayland-policy.md) | -| `d2b-provider-wayland-session` | 0 | 0 | 1 | RS-0517 | [tail-5](lane/tail-5.md) | -| `d2b-provider-zone` | 0 | 1 | 1 | RS-0422, RS-0715 | [tail-5](lane/tail-5.md) | -| `d2b-provider-zone-link` | 0 | 1 | 7 | RS-0086, RS-0196, RS-0197, RS-0423, RS-0424 | [d2b-provider-zone-link](lane/d2b-provider-zone-link.md) | -| `d2b-resource-api` | 0 | 6 | 14 | RS-0574, RS-0718, RS-0717, RS-0791, RS-0792 | [d2b-resource-api-p1](lane/d2b-resource-api-p1.md), [d2b-resource-api-p2](lane/d2b-resource-api-p2.md) | -| `d2b-resource-client` | 0 | 1 | 8 | RS-0429, RS-0089, RS-0090, RS-0200, RS-0296 | [d2b-resource-client](lane/d2b-resource-client.md) | -| `d2b-resource-compiler` | 0 | 2 | 7 | RS-0091, RS-0202, RS-0092, RS-0093, RS-0094 | [d2b-resource-compiler](lane/d2b-resource-compiler.md) | -| `d2b-resource-runtime` | 1 | 5 | 23 | RS-0916, RS-0430, RS-0520, RS-0431, RS-0521 | [d2b-resource-runtime-p1](lane/d2b-resource-runtime-p1.md), [d2b-resource-runtime-p2](lane/d2b-resource-runtime-p2.md) | -| `d2b-resource-types` | 0 | 1 | 1 | RS-0433, RS-0725 | [tail-6](lane/tail-6.md) | -| `d2b-session` | 0 | 4 | 16 | RS-0522, RS-0523, RS-0726, RS-0728, RS-0100 | [d2b-session-p1](lane/d2b-session-p1.md), [d2b-session-p2](lane/d2b-session-p2.md) | -| `d2b-session-unix` | 0 | 2 | 2 | RS-0436, RS-0731, RS-0732, RS-0799 | [d2b-session-unix](lane/d2b-session-unix.md) | -| `d2b-sk-frontend` | 0 | 1 | 3 | RS-0920, RS-0102, RS-0214, RS-0437 | [tail-6](lane/tail-6.md) | -| `d2b-telemetry` | 0 | 1 | 3 | RS-0524, RS-0525, RS-0733, RS-0921 | [d2b-telemetry](lane/d2b-telemetry.md) | -| `d2b-unsafe-local-helper` | 0 | 1 | 6 | RS-0526, RS-0103, RS-0299, RS-0438, RS-0601 | [d2b-unsafe-local-helper](lane/d2b-unsafe-local-helper.md) | -| `d2b-zone-routing` | 0 | 1 | 6 | RS-0852, RS-0104, RS-0105, RS-0215, RS-0734 | [d2b-zone-routing](lane/d2b-zone-routing.md) | -| `d2bd` | 0 | 18 | 47 | RS-0303, RS-0531, RS-0442, RS-0532, RS-0305 | [d2bd-p1](lane/d2bd-p1.md), [d2bd-p2](lane/d2bd-p2.md), [d2bd-p3](lane/d2bd-p3.md), [d2bd-p4](lane/d2bd-p4.md), [d2bd-p5](lane/d2bd-p5.md), [d2bd-p6](lane/d2bd-p6.md), [d2bd-p7](lane/d2bd-p7.md), [d2bd-p8](lane/d2bd-p8.md) | -| `d2bd-runtime` | 2 | 13 | 34 | RS-0538, RS-0925, RS-0307, RS-0444, RS-0539 | [d2bd-runtime-p1](lane/d2bd-runtime-p1.md), [d2bd-runtime-p2](lane/d2bd-runtime-p2.md), [d2bd-runtime-p3](lane/d2bd-runtime-p3.md), [d2bd-runtime-p4](lane/d2bd-runtime-p4.md) | -| `xtask` | 0 | 6 | 31 | RS-0118, RS-0120, RS-0314, RS-0543, RS-0755 | [xtask-p1](lane/xtask-p1.md), [xtask-p2](lane/xtask-p2.md), [xtask-p3](lane/xtask-p3.md), [xtask-p4](lane/xtask-p4.md), [xtask-p5](lane/xtask-p5.md) | - -## 4. Cross-cutting lanes - -### `X1-supply-chain` - -(Rows also listed under their lens in section 2.) - -- `RS-0933` | medium | `supply` | d2b-session depends on d2b-audit but the name appears nowhere in its sources; the dep edge is dead weight in both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28] | actionable | lane/X1-supply-chain.md -- `RS-0934` | medium | `supply` | d2b-session depends on d2b-telemetry but no source reference exists; the edge is carried into both Cargo and Bazel builds | fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31] | actionable | lane/X1-supply-chain.md -- `RS-0935` | medium | `supply` | d2b-session's dev-dependency serde_json (workspace-inherited) has zero uses in any of its files | fix: remove the dev-dep (the guest lock regenerates without it) | [packages/d2b-session/Cargo.toml:44] | actionable | lane/X1-supply-chain.md -- `RS-0936` | medium | `supply` | d2b-telemetry inherits rustix via workspace=true but no source in the crate references it; the dep is compiled into the telemetry crate for nothing | fix: remove rustix from [dependencies] (the root workspace entry stays, other members use it); regenerate the guest lock, which carries d2b-telemetry | [packages/d2b-telemetry/Cargo.toml:14] | actionable | lane/X1-supply-chain.md -- `RS-0937` | medium | `supply` | d2b-provider-quota inherits serde_json via workspace=true but no source or test references it | fix: remove serde_json from [dependencies] (and from the generated BUILD deps on the next regen) | [packages/d2b-provider-quota/Cargo.toml:24] | actionable | lane/X1-supply-chain.md -- `RS-0938` | medium | `supply` | d2b-bus's dev-dependency tempfile has zero uses across src/tests(including the ui test tree) | fix: remove the dev-dep | [packages/d2b-bus/Cargo.toml:41] | actionable | lane/X1-supply-chain.md -- `RS-0939` | medium | `supply` | d2b-provider-activation-nixos inherits serde via workspace=true but no source or test in the crate names it | fix: remove serde from [dependencies] | [packages/d2b-provider-activation-nixos/Cargo.toml:35] | actionable | lane/X1-supply-chain.md -- `RS-0940` | medium | `supply` | d2b-provider-audio-pipewire inherits schemars via workspace=true but no derive or path in its sources uses it | fix: remove schemars from [dependencies] | [packages/d2b-provider-audio-pipewire/Cargo.toml:25] | actionable | lane/X1-supply-chain.md -- `RS-0941` | medium | `supply` | d2b-provider-guest-azure-container-apps inherits sha2 via workspace=true but no source reference exists | fix: remove sha2 from [dependencies] | [packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21] | actionable | lane/X1-supply-chain.md -- `RS-0942` | medium | `supply` | d2b-provider-device-gpu declares async-trait but no #[async_trait] or use path names it | fix: remove async-trait from [dependencies] (the Bazel proc-macro dep drops with it on regen) | [packages/d2b-provider-device-gpu/Cargo.toml:20] | actionable | lane/X1-supply-chain.md -- `RS-0943` | medium | `supply` | d2b-provider-device-gpu depends on d2b-resource-types but no source or test in the crate uses it; the edge carries into Bazel too | fix: remove d2b-resource-types from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39] | actionable | lane/X1-supply-chain.md -- `RS-0944` | medium | `supply` | d2b depends on d2b-zone-routing but no source or test references it; the edge is carried into Bazel too | fix: remove d2b-zone-routing from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles | [packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55] | actionable | lane/X1-supply-chain.md -- `RS-0946` | medium | `supply` | nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a syscall-family crate reach shipped binaries | fix: keep the workspace pin at 0.29, and record+accept the 0.26/0.31 legs with expiry in a [bans] comment (name, pullers, re-check trigger, per DENY.md); then consider flipping multiple-versions to `deny` | [deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33] | actionable | lane/X1-supply-chain.md -- `RS-0947` | medium | `supply` | rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shipped binaries | fix: accept with expiry+record in a [bans] comment (re-check at each dep refresh; or plan a dedicated pass migrating the workspace pin to 1.1 and re-verifying the feature surface, which the root comments pin at 0.38 | [Cargo.toml:202, deny.toml:2] | actionable | lane/X1-supply-chain.md -- `RS-0948` | medium | `supply` | d2b-provider-transport-azure-relay pins webpki-roots "0.26" directly while its tokio-tungstenite 0.24 dep pulls 1.0.9 via its rustls-tls-webpki-roots feature, so the crate builds both legs | fix: upgrade the direct pin to "1" and drop the 0.26 leg(verify the TLS_SERVER_ROOTS API at the call site; if 0.26-only items are used, accept+record+expiry instead) | [packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36] | actionable | lane/X1-supply-chain.md -- `RS-0950` | medium | `supply` | packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2.128, uuid 1.26.1, aws-lc-rs 1.18.1, mio 1.2.3, etc), so the advisory and licence postures of the two shipped trees are assessed against different dependency sets at the same date | fix: regenerate both lockfiles from ONE index snapshot on the next dependency refresh (keeping the guest tree's host-only exclusions; add a drift check comparing shared-crate versions across the two locks) | [packages/Cargo.guest.lock:1, flake.nix:389] | actionable | lane/X1-supply-chain.md -- `RS-0945` | low | `supply` | 13 member decls pin literal versions of workspace-declared deps rustix (3) and sha2 (10, two of them in d2b-broker) instead of the house `workspace = true` pattern (429 workspace-inherit decls across the workspace), duplicating the version truth the root table owns | fix: convert them to `rustix = { workspace = true, features = [...] }` and `sha2 = { workspace = true }`, keeping member-side features (verified additive on the pinned toolchain: a workspace entry + member features resolves with the union on cargo 1.97, offline probe) | [Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, packages/d2b-provider-process/Cargo.toml:30] | actionable | lane/X1-supply-chain.md -- `RS-0949` | low | `supply` | the remaining ~31 duplicate clusters(hashbrown,bitflags,heck,indexmap,linux-raw-sys,memoffset,phf family,proc-macro-crate,r-efi,rand,rand_core,syn,thiserror,toml_datetime,toml_edit,winnow,windows-sys family,windows-link,etc) resolve transitively-only at multiple versions,and deny.toml records none of it (multiple-versions = "warn" alone keeps them invisible) | fix: annotate [bans] with the accepted-cluster inventory(name, versions, pullers, re-check trigger, per DENY.md; then flip multiple-versions to `deny` once the workspace-direct clusters (#14-#16) resolve | [deny.toml:2] | actionable | lane/X1-supply-chain.md -- `RS-0951` | low | `supply` | deny.toml's licence confidence-threshold sits at 0.8, below the rust-supply-chain skill's 0.9 floor, so licences the tool is guessing at(~80% confidence) pass the gate silently,and rare allow-listed licences(CDLA-Permissive-2.0, Unicode-DFS-2016) may be the reason the bar was lowered | fix: raise to 0.9 (and move any failing allow-listed licence to a per-crate `[licenses.exceptions]` entry with the reason attached, per DENY.md),verifying against the vendored tree at the next flake check | [deny.toml:21] | actionable | lane/X1-supply-chain.md - -### `X2-generated-boundary` - -(Rows also listed under their lens in section 2.) - -- `RS-0952` | medium | `api` | the hand-maintained registry `d2b-resource-api/src/generated/mod.rs:3-4` glob-re-exports the entire protobuf module (`pub use d2b_contracts_resource::resource_proto::*;`) as public surface of d2b-resource-api, exposing 47 items including reflection internals (`file_descriptor()` at `d2b_resource_v3.rs:7522`, `special_fields: ::protobuf::SpecialFields` on every message) and forcing `pub use protobuf;` at `d2b-resource-api/src/lib.rs:24` - with zero consumers | fix: delete the `d2b_resource_v3` re-export module from the registry (consumers use `d2b_contracts_resource::resource_proto` directly, e.g. `adapter.rs:560,578`); if a consumer ever needs the types through this crate, re-export named arms instead of a glob | [packages/d2b-resource-api/src/generated/mod.rs:3-4, packages/xtask/src/main.rs:355-370, packages/d2b-resource-api/src/lib.rs:24] | actionable | lane/X2-generated-boundary.md -- `RS-0954` | medium | `type` | the broker catalog view emits the authz facets as string literals (`secret_access: "None"`, `broker_required: "Yes"`, `audit_mode: "Yes"` at `broker_operation_catalog.rs:25-27` and every row) into the hand-written `BrokerAuthzFacets` struct whose fields are `&'static str` (`catalog.rs:98-102`), while the same generator emits the same declared data as typed enums in the sibling authz view (`SecretAccess::None`, `BrokerRequirement::Yes`, `AuditMode::Yes` at `broker_operation_authz.rs:12-19`); the broker-composition router string-matches the facet (`row.authz.secret_access != "None"` at routing.rs:98) and a hand-written row already drifts case (`audit_mode: "yes"` at `d2b-broker/src/envelope/mod.rs:2277` vs generated "Yes") | fix: change `BrokerAuthzFacets.secret_access/broker_required/audit_mode` to the existing `SecretAccess`/`BrokerRequirement`/`AuditMode` enums (`d2b-core/src/privileges.rs:48,61,83`; d2b-broker already depends on d2b-core per Cargo.toml:48) and make `generate_catalog` emit enum idents exactly as `generate_authz` already does | [packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19] | actionable | lane/X2-generated-boundary.md -- `RS-0955` | medium | `type` | `BrokerOperationRow.disposition` is `&'static str` (`catalog.rs:181`) holding a closed 4-value set emitted by the generator (`disposition: "promoted-live"` etc. at `broker_operation_catalog.rs:17` and 97 more rows), string-matched at catalog.rs:590,773,779,791 and runtime.rs:12562, while the same generator already maps every other closed set to enums (`owner_variant`, profile match, `StubTarget`) | fix: add a `Disposition` enum (four variants: callable-read-only, promoted-live, stubbed-unimplemented, compile-time-only) beside `StubTarget` in `d2b-broker/src/catalog.rs:266`, change the struct field, and have `generate_catalog` emit `Disposition::X` like `owner_variant` | [packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_operation_catalog.rs:17, packages/d2b-broker/src/catalog.rs:181, packages/d2b-broker/src/catalog.rs:590] | actionable | lane/X2-generated-boundary.md -- `RS-0953` | low | `api` | `d2b-audit/src/lib.rs:7` declares `pub mod generated;` but every consumer of the emitted catalog is in-crate (`crate::generated::audit_catalog::...` at record_types.rs:1038,1067,1212,1297,1367) | fix: `mod generated;` (private) in lib.rs; the emitted file and its registry need no change | [packages/d2b-audit/src/lib.rs:7, packages/xtask/src/gen_layer_catalogs.rs:725, packages/d2b-audit/src/generated/audit_catalog.rs:6-8] | actionable | lane/X2-generated-boundary.md -- `RS-0956` | low | `type` | the operation-name vocabulary is emitted as strings (`HOST_OPERATION_CATALOG`/`GUEST_OPERATION_CATALOG: &[&str]` at `broker_operation_profiles.rs:8-41`, `operation: "Hello"` at `broker_operation_catalog.rs:11`) and admission is a string `contains` (`BrokerProfile::allows_operation` at `d2b-contracts-broker/src/broker_wire.rs:864-889`), while the same generator emits the w3 subset as the typed `W3BrokerOperation` enum (`w3_broker_operations.rs`, re-exported at `d2b-contracts-broker/src/lib.rs:11`) | fix: have `generate_profiles`/`generate_catalog` emit a full closed `BrokerOperationName` enum (all 98 rows, not just the 24 w3 variants) with `as_str`, and type the catalogs and row `operation` field against it; the wire boundary keeps the string spelling via `as_str` | [packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11] | actionable | lane/X2-generated-boundary.md -- `RS-0957` | low | `type` | the authz view's positional `row)...)` helper calls carry a bare boolean at argument 5 (`false`/`true` for `destructive` at `broker_operation_authz.rs:12-19` and every row), the boolean-trap shape the type lens names, in a 988-line generated file where the field is the routing-relevant facet (`row.authz.destructive` at routing.rs:98) | fix: emit `Destructive::No`/`Destructive::Yes` (or named-field construction) from `generate_authz` and drop the `#[allow(clippy::too_many_arguments)]` on the hand-written `row()` helper at `d2b-core/src/privileges.rs:687-708` | [packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-core/src/privileges.rs:687-708] | actionable | lane/X2-generated-boundary.md - -### `X3-cross-crate-duplication` - -(Rows also listed under their lens in section 2.) - -- `RS-0962` | high | `type` | Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one member, d2b-provider-wayland-policy, panics on caller input at the family engine's public boundary) | fix: type the args field as `d2b_contracts_resource::v3::ZoneId` (or a `BoundedToken`) in each `*DriverArgs` and parse once at the daemon construction boundary, with `SharedProviderDriverArgs` in d2b-provider-toolkit as the shared home the family args mirror | [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-credential/src/driver.rs:295] | actionable | lane/X3-cross-crate-duplication.md -- `RS-0958` | medium | `test` | Provider test-support recorder/harness duplication: each provider crate hand-rolls the same recorder-double family (RecordingEffects/ScriptedProbe/RecordingManager/RecordingRequeue-style recording doubles, ScriptedPort/ScriptedDiscoveryPort/ScriptedEffectPort scripted ports, hand-rolled block_on pollers, TicketBuilder-style fixtures) in its own test_support.rs/testing.rs instead of the toolkit's shipped harness | fix: consolidate the recorder/harness shapes onto `d2b-provider-toolkit/src/testing` (TestHarness at testing/mod.rs:397, fakes.rs, fixture.rs, conformance.rs) and have the family crates reuse it; the toolkit module is the B3-kept base, so this does not re-propose the B3 refusal | [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-volume-binding/src/test_support.rs:17] | actionable | lane/X3-cross-crate-duplication.md -- `RS-0960` | medium | `conc` | parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-census-baseline.json, `parking_lot::Mutex::lock: 0` for every crate) key on the path `parking_lot::Mutex::lock`, which never resolves because `parking_lot::Mutex` is a type alias (`pub type Mutex = lock_api::Mutex`), so unsuppressed lock sites in 10+ crates record zero hits and no per-site allow is demanded | fix: configure the disallowed entry and the census DeniedApi list on the resolved path (`lock_api::Mutex::lock`, or the def-path clippy reports for the alias), then re-run the census so the unsuppressed sites surface and get per-site allows or conversions per the KD3 ban | [clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-security-key/src/relay_service.rs:129] | policy-confirmed | lane/X3-cross-crate-duplication.md -- `RS-0961` | medium | `serde` | Parallel serde shims: contract/provider crates hand-write the identical Wire-struct admission shape (private `#[derive(Deserialize)]` Wire with deny_unknown_fields, then new()/TryFrom with validation) in 24+ impls where the in-tree `parsed_deserialize!` macro exists | fix: consolidate behind `parsed_deserialize!` (d2b-contracts-resource/src/v3/execution_policy.rs:33, re-exported at :63) or `#[serde(try_from = "...")]` with the raw Wire shape, keeping every admission gate; this deduplicates boilerplate and is distinct from the refused gate-removal class (over-engineering-audit-record.md rows 25/33 refused replacing gates with derives) | [packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs:101, packages/d2b-contracts-zone-session/src/v3/zone.rs:79, packages/d2b-contracts-zone-session/src/v3/role_binding.rs:192] | actionable | lane/X3-cross-crate-duplication.md -- `RS-0963` | medium | `err` | Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { path, detail: String }`, `Io(String)`, `Frame(String)`, `ManagerRpc(String)`, `TypedError::InternalIo { context, detail }`, five `String` variants of PlaneError, `kind: String` in four Io variants), destroying the source chain so diagnostics and callers cannot distinguish failure classes | fix: carry the source with thiserror `#[from]`/`source()` in each enum (no in-tree helper exists; the std Error source chain is the canonical home); wire-visible members (d2bd TypedError) need contract sign-off before the shape changes, internal members (broker, clipboard, azure-relay, resource-runtime, d2bd-runtime vsock) are actionable first | [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69] | needs-contract | lane/X3-cross-crate-duplication.md -- `RS-0964` | medium | `own` | Repeated ownership pattern: public signatures and fields across eight crates leak `Arc`/`&Arc` (accessors returning `&Arc`, constructors taking `Arc` where single ownership suffices, pub fields carrying `Arc>`), forcing callers to see refcount plumbing and blocking signature evolution | fix: return `&T`/owned values and take owned parameters per the ownership-not-clone convention (canonical home is the borrow/owned convention; no shared type involved, so the merge target is per-crate signatures) | [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:491, packages/d2b-provider-toolkit/src/testing/mod.rs:530, packages/d2b-provider-supervisor/src/broker.rs:997] | actionable | lane/X3-cross-crate-duplication.md -- `RS-0959` | low | `test` | Test-support shipping shape: `test-support` features declared empty and gating nothing in four declaration crates while three provider crates ship `pub mod testing` (ScriptedPort/block_on harnesses) unconditionally in the production library and d2b-resource-types exports a test-only helper through the root despite declaring the feature | fix: wire each `test-support = []` feature to its module (`#[cfg(feature = "test-support")]` on `pub mod testing`, `#[cfg(feature = "test-support")]` on `assert_metadata_registration`) or drop the empty features, following the house pattern at d2b-provider-host/Cargo.toml:28 | [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-role/Cargo.toml:17] | actionable | lane/X3-cross-crate-duplication.md -- `RS-0965` | low | `api` | Double-path public surface: eleven crates expose every item of a module at two public paths (`pub mod x` plus root `pub use x::*` or item re-exports), deviating from the house single-surface convention and letting future pub items silently widen API | fix: keep one public path per item (either the module or the root re-export, per the house single-surface pattern the d2b-sk-frontend lane names), deleting the duplicate arm in each lib.rs | [packages/d2b-provider-device-usbip/src/lib.rs:24, packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-zone/src/lib.rs:17, packages/d2b-sk-frontend/src/lib.rs:22] | actionable | lane/X3-cross-crate-duplication.md - -## 5. Coverage matrix (94 crates x 16 lenses) - -Cell = findings count. `clean` = the lane ran the lens with zero findings and nonzero seed mass; `N/A` = all of the lens's seeds returned zero for the crate (U1-constraints.md section (e) row) and the lens card's applicability criteria fail. `supply` is workspace-level (lane X1), shown as `X1` everywhere. Cells are summed over a crate's part lanes. Eight cells show a count where the U1 pre-scan row is zero (the lane's own read found what the single-pass pre-scan did not): d2b-controller-toolkit/type, d2b-provider-credential-entra/idiom, d2b-provider-credential-secret-service/idiom, d2b-provider-guest-azure-container-apps/type, d2b-provider-seccomp-profile/idiom, d2b-provider-system-core/idiom, d2b-provider-volume/idiom, d2b-provider-wayland-session/err; every `N/A` cell satisfies both conditions above. - -| crate | `idiom` | `own` | `type` | `api` | `err` | `serde` | `obs` | `docs` | `perf` | `conc` | `async` | `unsafe` | `ffi` | `macro` | `test` | `supply` | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| `d2b` | 7 | 4 | 2 | 3 | 2 | clean | clean | 2 | 1 | clean | clean | clean | N/A | N/A | 2 | X1 | -| `d2b-audit` | 3 | 1 | 1 | 1 | 2 | clean | clean | 1 | 1 | clean | N/A | clean | N/A | clean | clean | X1 | -| `d2b-broker` | 7 | 3 | 3 | 7 | 6 | 1 | 1 | 18 | 5 | 1 | 6 | 2 | clean | clean | 1 | X1 | -| `d2b-broker-composition` | 2 | 3 | N/A | clean | 1 | 1 | clean | clean | clean | N/A | clean | clean | N/A | clean | 2 | X1 | -| `d2b-broker-fixture-handlers` | N/A | clean | N/A | clean | N/A | N/A | N/A | clean | clean | N/A | clean | clean | N/A | N/A | N/A | X1 | -| `d2b-broker-fixture-syscall-surface` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | 1 | clean | N/A | N/A | X1 | -| `d2b-bus` | 2 | 3 | 3 | 3 | 1 | clean | clean | 6 | 2 | 1 | clean | N/A | N/A | clean | 3 | X1 | -| `d2b-contracts` | clean | clean | clean | 1 | 1 | 1 | N/A | clean | clean | N/A | N/A | N/A | N/A | clean | clean | X1 | -| `d2b-contracts-broker` | 3 | clean | 2 | 2 | clean | 1 | N/A | 2 | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-contracts-control` | N/A | clean | 3 | 4 | 1 | 1 | N/A | 4 | clean | N/A | N/A | N/A | N/A | N/A | 1 | X1 | -| `d2b-contracts-provider` | 3 | 4 | 3 | 1 | 5 | 1 | clean | 2 | clean | 1 | clean | N/A | N/A | clean | 2 | X1 | -| `d2b-contracts-resource` | 4 | 1 | 4 | 2 | 1 | 2 | N/A | 4 | 1 | clean | N/A | N/A | N/A | clean | clean | X1 | -| `d2b-contracts-zone-session` | 1 | 5 | 1 | 3 | 1 | 1 | N/A | 1 | 1 | N/A | N/A | N/A | N/A | clean | 2 | X1 | -| `d2b-controller-toolkit` | N/A | N/A | 1 | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | N/A | X1 | -| `d2b-core` | 4 | 2 | 1 | 6 | 6 | 3 | 1 | 2 | 3 | clean | clean | clean | N/A | clean | 1 | X1 | -| `d2b-core-controller` | 1 | 2 | 1 | 5 | 1 | 1 | N/A | 2 | clean | clean | clean | N/A | N/A | N/A | 2 | X1 | -| `d2b-host` | clean | clean | 1 | 1 | clean | 1 | clean | 2 | 1 | clean | clean | clean | clean | clean | 2 | X1 | -| `d2b-host-activation-helper` | N/A | clean | N/A | N/A | clean | N/A | clean | clean | clean | N/A | N/A | 1 | clean | N/A | clean | X1 | -| `d2b-process-conformance` | N/A | 1 | 1 | 4 | 1 | 2 | N/A | 1 | clean | clean | 1 | N/A | N/A | clean | clean | X1 | -| `d2b-provider` | clean | 1 | N/A | clean | clean | N/A | N/A | 1 | clean | clean | 1 | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-activation-nixos` | N/A | clean | clean | 2 | 1 | clean | 1 | 1 | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | -| `d2b-provider-audio-binding` | clean | clean | N/A | clean | N/A | N/A | N/A | 1 | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-audio-pipewire` | clean | clean | 2 | 3 | 2 | clean | clean | 2 | clean | clean | clean | clean | N/A | N/A | 2 | 1 | -| `d2b-provider-audio-service` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-clipboard-wayland` | 6 | 1 | 4 | 1 | 4 | 1 | 2 | 5 | 2 | 1 | N/A | clean | N/A | N/A | 4 | X1 | -| `d2b-provider-command` | N/A | clean | N/A | clean | clean | 1 | N/A | 1 | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-config-nixos` | 1 | 1 | 1 | 1 | 1 | clean | clean | 1 | 1 | clean | clean | clean | N/A | N/A | 2 | X1 | -| `d2b-provider-credential` | N/A | 1 | 1 | clean | clean | clean | clean | 1 | clean | 1 | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-credential-entra` | 1 | clean | clean | 2 | clean | N/A | clean | 1 | clean | clean | clean | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-credential-managed-identity` | N/A | clean | 1 | 1 | 1 | N/A | clean | 1 | clean | clean | clean | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-credential-secret-service` | 1 | clean | clean | clean | clean | N/A | 1 | 2 | clean | clean | 1 | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-device` | N/A | clean | N/A | 1 | N/A | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-device-gpu` | 3 | 1 | 1 | 2 | clean | 1 | clean | 2 | clean | 1 | N/A | clean | N/A | N/A | 1 | 1 | -| `d2b-provider-device-security-key` | 1 | clean | clean | 1 | clean | clean | clean | 2 | clean | 1 | clean | clean | N/A | N/A | clean | X1 | -| `d2b-provider-device-tpm` | 1 | 1 | clean | 4 | 1 | clean | clean | 2 | clean | clean | 2 | clean | N/A | N/A | clean | X1 | -| `d2b-provider-device-usbip` | 1 | 1 | clean | 2 | 1 | clean | clean | 2 | clean | 1 | clean | N/A | N/A | N/A | 3 | X1 | -| `d2b-provider-display-wayland` | 7 | 1 | clean | 4 | 3 | 2 | clean | 3 | 1 | N/A | N/A | clean | clean | 1 | 1 | X1 | -| `d2b-provider-emergency-policy` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-endpoint` | 2 | clean | clean | clean | clean | 1 | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-guest` | clean | 2 | 1 | clean | clean | clean | clean | 1 | 1 | 2 | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-guest-azure-container-apps` | N/A | 6 | 1 | 1 | clean | clean | clean | 1 | N/A | N/A | clean | clean | N/A | clean | 2 | 1 | -| `d2b-provider-guest-azure-virtual-machine` | 1 | 4 | 3 | 2 | clean | clean | 1 | 2 | N/A | N/A | clean | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-guest-cloud-hypervisor` | 4 | clean | 3 | 5 | clean | clean | clean | 1 | 1 | N/A | clean | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-guest-qemu-media` | 1 | 1 | 2 | 1 | clean | clean | 1 | 1 | 1 | N/A | N/A | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-host` | 1 | 1 | clean | 1 | 2 | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-network-local` | 2 | 1 | clean | 1 | 1 | 2 | clean | clean | 2 | clean | 1 | N/A | N/A | clean | clean | X1 | -| `d2b-provider-notification-desktop` | 2 | 2 | 1 | 3 | 2 | clean | clean | 2 | 1 | clean | N/A | clean | N/A | N/A | clean | X1 | -| `d2b-provider-observability-otel` | clean | 1 | 1 | clean | 1 | clean | clean | 2 | 3 | clean | N/A | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-operation` | clean | clean | N/A | clean | clean | clean | N/A | 1 | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-process` | clean | 2 | clean | clean | 1 | clean | clean | 1 | clean | 2 | clean | clean | N/A | N/A | clean | X1 | -| `d2b-provider-process-minijail` | N/A | clean | 1 | clean | clean | N/A | clean | 1 | clean | N/A | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-process-systemd` | 1 | clean | 2 | 3 | 1 | clean | 1 | 1 | 1 | N/A | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-provider` | clean | 2 | clean | 2 | clean | clean | clean | 1 | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | -| `d2b-provider-quota` | N/A | N/A | N/A | 1 | N/A | clean | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | 1 | -| `d2b-provider-resource-export` | N/A | N/A | N/A | 1 | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-resource-import` | N/A | N/A | N/A | 1 | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-role` | N/A | N/A | N/A | 1 | clean | N/A | N/A | 1 | clean | clean | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-role-binding` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-seccomp-profile` | 1 | clean | N/A | 1 | clean | clean | N/A | 1 | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-shell-pool` | N/A | N/A | N/A | clean | N/A | N/A | N/A | clean | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-shell-session` | N/A | clean | N/A | clean | N/A | clean | N/A | clean | clean | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-shell-terminal` | N/A | 1 | clean | clean | clean | N/A | clean | 1 | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | -| `d2b-provider-supervisor` | 2 | clean | clean | 2 | 2 | 1 | clean | clean | clean | clean | clean | N/A | N/A | clean | 1 | X1 | -| `d2b-provider-system-core` | 2 | 1 | N/A | 5 | clean | clean | clean | 1 | N/A | 1 | 1 | N/A | N/A | N/A | 1 | X1 | -| `d2b-provider-telemetry-binding` | clean | clean | 1 | clean | clean | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-telemetry-service` | clean | clean | 1 | clean | 2 | clean | N/A | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-test-controller` | N/A | clean | N/A | N/A | 1 | N/A | 2 | clean | N/A | N/A | clean | clean | N/A | N/A | clean | X1 | -| `d2b-provider-toolkit` | 2 | 4 | clean | 4 | 5 | clean | 2 | 2 | 1 | 1 | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-transport-azure-relay` | 2 | 2 | 1 | 2 | 2 | 2 | 1 | 1 | 2 | clean | 1 | clean | N/A | N/A | clean | X1 | -| `d2b-provider-transport-unix` | clean | N/A | clean | clean | clean | N/A | 1 | 1 | clean | 1 | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-transport-vsock` | 1 | clean | N/A | clean | clean | 1 | 2 | 1 | clean | clean | clean | clean | N/A | N/A | 1 | X1 | -| `d2b-provider-user` | N/A | 1 | clean | clean | 1 | clean | clean | clean | clean | 2 | 1 | N/A | N/A | N/A | 1 | X1 | -| `d2b-provider-volume` | 1 | 2 | clean | 1 | clean | clean | N/A | clean | 1 | clean | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-volume-binding` | N/A | 1 | N/A | clean | 1 | clean | clean | 1 | clean | 1 | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-volume-local` | 1 | clean | 1 | 1 | clean | 1 | clean | 1 | clean | clean | clean | clean | N/A | N/A | clean | X1 | -| `d2b-provider-volume-virtiofs` | N/A | clean | clean | clean | clean | clean | clean | clean | clean | clean | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-wayland-policy` | N/A | clean | clean | clean | 1 | 1 | N/A | clean | clean | clean | clean | N/A | N/A | N/A | 1 | X1 | -| `d2b-provider-wayland-session` | clean | clean | N/A | clean | 1 | N/A | N/A | clean | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-zone` | N/A | clean | N/A | 1 | clean | N/A | N/A | 1 | N/A | N/A | N/A | N/A | N/A | N/A | clean | X1 | -| `d2b-provider-zone-link` | 1 | 2 | clean | 3 | clean | clean | N/A | 1 | clean | clean | N/A | N/A | N/A | N/A | 1 | X1 | -| `d2b-resource-api` | 2 | 2 | 1 | 3 | 1 | 1 | 1 | 2 | 4 | clean | clean | N/A | N/A | 1 | 2 | X1 | -| `d2b-resource-client` | 2 | 1 | 1 | 1 | 1 | clean | N/A | 1 | clean | 1 | clean | N/A | N/A | N/A | 1 | X1 | -| `d2b-resource-compiler` | 4 | 5 | clean | clean | clean | clean | clean | clean | clean | clean | N/A | clean | clean | N/A | clean | X1 | -| `d2b-resource-runtime` | 5 | 7 | clean | 3 | 2 | clean | clean | 5 | 2 | 2 | clean | N/A | N/A | N/A | 3 | X1 | -| `d2b-resource-types` | N/A | clean | N/A | 1 | clean | N/A | N/A | 1 | clean | N/A | clean | N/A | N/A | N/A | clean | X1 | -| `d2b-session` | 2 | 1 | 2 | 2 | 2 | N/A | clean | 5 | 3 | 1 | clean | clean | N/A | 1 | 1 | X1 | -| `d2b-session-unix` | clean | clean | clean | 1 | clean | N/A | clean | 2 | 1 | clean | clean | clean | N/A | clean | clean | X1 | -| `d2b-sk-frontend` | 1 | 1 | N/A | 1 | clean | N/A | clean | clean | clean | clean | clean | clean | N/A | N/A | 1 | X1 | -| `d2b-telemetry` | N/A | clean | clean | clean | 2 | clean | N/A | 1 | clean | clean | N/A | clean | N/A | N/A | 1 | X1 | -| `d2b-unsafe-local-helper` | 1 | clean | 1 | 1 | 1 | clean | 1 | clean | clean | 1 | N/A | clean | N/A | N/A | 1 | X1 | -| `d2b-zone-routing` | 2 | 1 | clean | clean | clean | N/A | N/A | 1 | clean | clean | 1 | N/A | N/A | clean | 2 | X1 | -| `d2bd` | 8 | 9 | 6 | 5 | 11 | 3 | 7 | 8 | 4 | 2 | 2 | clean | N/A | N/A | clean | X1 | -| `d2bd-runtime` | 4 | 4 | 6 | 7 | 5 | 2 | 5 | 9 | 1 | 3 | 1 | clean | N/A | N/A | 2 | X1 | -| `xtask` | 7 | 10 | 4 | clean | 1 | 3 | clean | 5 | 4 | clean | clean | clean | clean | 1 | 2 | X1 | - -Lane-to-crate completeness: 94 workspace members = 17 crates via 51 part-lane files + 50 whole-crate lane files + 27 crates via 6 tail-lane files; no crate appears in two lanes and none is missing (machine-checked by the renderer and by VERIFICATION.md check 2). - -## 6. Remediation input - -Clusters group findings by lens family, blast radius, and precondition. Suggested order: leaf and `actionable` first; family next; `wide`/`needs-contract` last. Every remediation PR must keep `make check` (Bazel suite incl. per-crate clippy), `make test-unit`, `make generate`, and the `security-scan` job green. - -| cluster (lens / blast / verdict) | n | member RS ids | -| --- | ---: | --- | -| `idiom` / leaf / actionable | 122 | RS-0001, RS-0004, RS-0006, RS-0007, RS-0008, RS-0009, RS-0013, RS-0014, RS-0015, RS-0018, RS-0020, RS-0021, RS-0022, RS-0025, RS-0026, RS-0027, RS-0030, RS-0031, RS-0036, RS-0040, RS-0044, RS-0046, RS-0047, RS-0050, RS-0051, RS-0052, RS-0053, RS-0058, RS-0060, RS-0062, RS-0063, RS-0067, RS-0068, RS-0069, RS-0071, RS-0073, RS-0075, RS-0077, RS-0079, RS-0081, RS-0083, RS-0084, RS-0085, RS-0087, RS-0089, RS-0091, RS-0095, RS-0097, RS-0100, RS-0103, RS-0104, RS-0106, RS-0108, RS-0109, RS-0111, RS-0112, RS-0113, RS-0114, RS-0115, RS-0116, RS-0118, RS-0123, RS-0124, RS-0002, RS-0005, RS-0016, RS-0019, RS-0023, RS-0028, RS-0032, RS-0037, RS-0041, RS-0048, RS-0054, RS-0059, RS-0061, RS-0064, RS-0070, RS-0072, RS-0076, RS-0078, RS-0080, RS-0082, RS-0088, RS-0090, RS-0092, RS-0096, RS-0098, RS-0101, RS-0105, RS-0107, RS-0110, RS-0117, RS-0119, RS-0003, RS-0010, RS-0017, RS-0024, RS-0029, RS-0033, RS-0038, RS-0049, RS-0055, RS-0065, RS-0093, RS-0099, RS-0120, RS-0011, RS-0034, RS-0039, RS-0042, RS-0056, RS-0066, RS-0094, RS-0121, RS-0035, RS-0043, RS-0057, RS-0122, RS-0012, RS-0074, RS-0102 | -| `idiom` / family / actionable | 2 | RS-0045, RS-0086 | -| `own` / leaf / actionable | 107 | RS-0129, RS-0131, RS-0142, RS-0153, RS-0154, RS-0157, RS-0162, RS-0164, RS-0180, RS-0182, RS-0184, RS-0192, RS-0195, RS-0198, RS-0221, RS-0231, RS-0236, RS-0132, RS-0238, RS-0133, RS-0137, RS-0139, RS-0143, RS-0145, RS-0148, RS-0159, RS-0160, RS-0163, RS-0165, RS-0170, RS-0174, RS-0175, RS-0179, RS-0181, RS-0183, RS-0196, RS-0222, RS-0225, RS-0226, RS-0232, RS-0237, RS-0135, RS-0150, RS-0176, RS-0177, RS-0185, RS-0199, RS-0215, RS-0216, RS-0234, RS-0126, RS-0134, RS-0138, RS-0144, RS-0146, RS-0156, RS-0166, RS-0171, RS-0186, RS-0189, RS-0190, RS-0193, RS-0197, RS-0206, RS-0218, RS-0233, RS-0136, RS-0147, RS-0151, RS-0178, RS-0209, RS-0217, RS-0227, RS-0235, RS-0125, RS-0127, RS-0158, RS-0167, RS-0172, RS-0191, RS-0207, RS-0219, RS-0152, RS-0210, RS-0223, RS-0228, RS-0128, RS-0168, RS-0173, RS-0201, RS-0208, RS-0220, RS-0149, RS-0155, RS-0161, RS-0211, RS-0224, RS-0229, RS-0130, RS-0169, RS-0212, RS-0230, RS-0202, RS-0203, RS-0204, RS-0205, RS-0214 | -| `own` / family / actionable | 7 | RS-0187, RS-0140, RS-0188, RS-0200, RS-0213, RS-0141, RS-0964 | -| `own` / wide / actionable | 1 | RS-0194 | -| `type` / leaf / actionable | 59 | RS-0288, RS-0263, RS-0266, RS-0297, RS-0307, RS-0242, RS-0243, RS-0265, RS-0267, RS-0273, RS-0274, RS-0289, RS-0292, RS-0294, RS-0295, RS-0299, RS-0302, RS-0308, RS-0314, RS-0244, RS-0254, RS-0261, RS-0287, RS-0290, RS-0296, RS-0298, RS-0303, RS-0306, RS-0313, RS-0245, RS-0246, RS-0258, RS-0260, RS-0272, RS-0300, RS-0247, RS-0252, RS-0264, RS-0268, RS-0275, RS-0293, RS-0301, RS-0281, RS-0284, RS-0278, RS-0305, RS-0269, RS-0277, RS-0285, RS-0279, RS-0270, RS-0283, RS-0312, RS-0280, RS-0311, RS-0271, RS-0955, RS-0957, RS-0291 | -| `type` / leaf / needs-contract | 7 | RS-0240, RS-0241, RS-0256, RS-0315, RS-0257, RS-0304, RS-0282 | -| `type` / leaf / policy-confirmed | 1 | RS-0286 | -| `type` / family / actionable | 11 | RS-0262, RS-0276, RS-0251, RS-0253, RS-0255, RS-0309, RS-0310, RS-0962, RS-0954, RS-0956, RS-0259 | -| `type` / wide / actionable | 1 | RS-0239 | -| `type` / wide / needs-contract | 3 | RS-0248, RS-0249, RS-0250 | -| `api` / leaf / actionable | 107 | RS-0340, RS-0351, RS-0352, RS-0407, RS-0434, RS-0317, RS-0321, RS-0323, RS-0341, RS-0366, RS-0441, RS-0353, RS-0359, RS-0361, RS-0372, RS-0426, RS-0438, RS-0319, RS-0327, RS-0342, RS-0355, RS-0367, RS-0373, RS-0377, RS-0381, RS-0392, RS-0393, RS-0400, RS-0442, RS-0446, RS-0324, RS-0330, RS-0360, RS-0362, RS-0368, RS-0409, RS-0415, RS-0427, RS-0429, RS-0435, RS-0320, RS-0337, RS-0356, RS-0374, RS-0378, RS-0382, RS-0397, RS-0401, RS-0414, RS-0423, RS-0439, RS-0318, RS-0325, RS-0331, RS-0345, RS-0394, RS-0410, RS-0428, RS-0952, RS-0326, RS-0335, RS-0336, RS-0338, RS-0343, RS-0375, RS-0398, RS-0424, RS-0440, RS-0445, RS-0395, RS-0411, RS-0953, RS-0316, RS-0339, RS-0344, RS-0350, RS-0358, RS-0370, RS-0376, RS-0418, RS-0425, RS-0333, RS-0347, RS-0379, RS-0396, RS-0412, RS-0443, RS-0354, RS-0371, RS-0383, RS-0419, RS-0380, RS-0391, RS-0386, RS-0431, RS-0447, RS-0364, RS-0387, RS-0432, RS-0448, RS-0385, RS-0388, RS-0449, RS-0389, RS-0450, RS-0437, RS-0422 | -| `api` / leaf / policy-confirmed | 2 | RS-0399, RS-0322 | -| `api` / family / actionable | 20 | RS-0436, RS-0433, RS-0408, RS-0421, RS-0444, RS-0416, RS-0357, RS-0334, RS-0417, RS-0329, RS-0430, RS-0384, RS-0390, RS-0965, RS-0402, RS-0406, RS-0403, RS-0369, RS-0404, RS-0405 | -| `api` / family / needs-contract | 1 | RS-0363 | -| `api` / wide / actionable | 5 | RS-0348, RS-0365, RS-0349, RS-0346, RS-0420 | -| `api` / wide / needs-contract | 3 | RS-0332, RS-0328, RS-0413 | -| `err` / leaf / actionable | 79 | RS-0524, RS-0531, RS-0514, RS-0525, RS-0500, RS-0504, RS-0532, RS-0539, RS-0454, RS-0457, RS-0502, RS-0526, RS-0533, RS-0456, RS-0461, RS-0496, RS-0505, RS-0488, RS-0494, RS-0503, RS-0519, RS-0522, RS-0534, RS-0535, RS-0540, RS-0543, RS-0480, RS-0499, RS-0465, RS-0481, RS-0490, RS-0491, RS-0495, RS-0507, RS-0518, RS-0523, RS-0536, RS-0487, RS-0453, RS-0460, RS-0463, RS-0466, RS-0482, RS-0483, RS-0492, RS-0520, RS-0529, RS-0538, RS-0501, RS-0462, RS-0464, RS-0467, RS-0469, RS-0470, RS-0471, RS-0479, RS-0484, RS-0489, RS-0493, RS-0530, RS-0477, RS-0451, RS-0472, RS-0476, RS-0498, RS-0512, RS-0452, RS-0473, RS-0513, RS-0458, RS-0521, RS-0474, RS-0485, RS-0459, RS-0486, RS-0541, RS-0542, RS-0506, RS-0517 | -| `err` / leaf / needs-contract | 1 | RS-0478 | -| `err` / family / actionable | 11 | RS-0515, RS-0516, RS-0527, RS-0468, RS-0508, RS-0528, RS-0475, RS-0497, RS-0509, RS-0510, RS-0511 | -| `err` / wide / actionable | 1 | RS-0455 | -| `err` / wide / needs-contract | 2 | RS-0963, RS-0537 | -| `serde` / leaf / actionable | 23 | RS-0576, RS-0565, RS-0578, RS-0545, RS-0566, RS-0572, RS-0582, RS-0581, RS-0567, RS-0574, RS-0544, RS-0577, RS-0548, RS-0549, RS-0558, RS-0562, RS-0564, RS-0580, RS-0556, RS-0559, RS-0555, RS-0560, RS-0579 | -| `serde` / leaf / needs-contract | 4 | RS-0568, RS-0575, RS-0554, RS-0561 | -| `serde` / leaf / policy-confirmed | 1 | RS-0570 | -| `serde` / family / actionable | 6 | RS-0961, RS-0557, RS-0573, RS-0551, RS-0552, RS-0563 | -| `serde` / family / needs-contract | 1 | RS-0569 | -| `serde` / wide / actionable | 2 | RS-0553, RS-0550 | -| `serde` / wide / needs-contract | 3 | RS-0546, RS-0571, RS-0547 | -| `obs` / leaf / actionable | 30 | RS-0605, RS-0601, RS-0606, RS-0609, RS-0588, RS-0583, RS-0610, RS-0607, RS-0611, RS-0585, RS-0594, RS-0598, RS-0602, RS-0612, RS-0600, RS-0599, RS-0603, RS-0591, RS-0604, RS-0608, RS-0590, RS-0586, RS-0589, RS-0584, RS-0596, RS-0587, RS-0613, RS-0592, RS-0593, RS-0597 | -| `obs` / family / actionable | 1 | RS-0595 | -| `docs` / leaf / actionable | 139 | RS-0701, RS-0661, RS-0726, RS-0731, RS-0755, RS-0733, RS-0673, RS-0713, RS-0718, RS-0725, RS-0732, RS-0756, RS-0624, RS-0630, RS-0700, RS-0615, RS-0674, RS-0727, RS-0625, RS-0631, RS-0656, RS-0680, RS-0719, RS-0736, RS-0617, RS-0633, RS-0676, RS-0703, RS-0706, RS-0714, RS-0734, RS-0754, RS-0626, RS-0632, RS-0649, RS-0657, RS-0659, RS-0681, RS-0737, RS-0618, RS-0634, RS-0652, RS-0677, RS-0684, RS-0738, RS-0739, RS-0746, RS-0650, RS-0664, RS-0672, RS-0728, RS-0735, RS-0619, RS-0635, RS-0637, RS-0662, RS-0685, RS-0689, RS-0708, RS-0716, RS-0717, RS-0720, RS-0740, RS-0743, RS-0747, RS-0621, RS-0645, RS-0675, RS-0690, RS-0729, RS-0620, RS-0636, RS-0638, RS-0682, RS-0697, RS-0707, RS-0721, RS-0744, RS-0748, RS-0665, RS-0695, RS-0702, RS-0712, RS-0730, RS-0741, RS-0639, RS-0641, RS-0647, RS-0653, RS-0658, RS-0678, RS-0683, RS-0687, RS-0698, RS-0722, RS-0749, RS-0752, RS-0622, RS-0686, RS-0694, RS-0696, RS-0742, RS-0614, RS-0642, RS-0648, RS-0655, RS-0660, RS-0666, RS-0679, RS-0688, RS-0709, RS-0745, RS-0753, RS-0623, RS-0723, RS-0640, RS-0643, RS-0627, RS-0724, RS-0644, RS-0691, RS-0654, RS-0693, RS-0628, RS-0692, RS-0710, RS-0629, RS-0668, RS-0669, RS-0670, RS-0750, RS-0751, RS-0671, RS-0705, RS-0711, RS-0704, RS-0699, RS-0663, RS-0715 | -| `docs` / family / actionable | 3 | RS-0646, RS-0616, RS-0667 | -| `docs` / wide / actionable | 1 | RS-0651 | -| `perf` / leaf / actionable | 48 | RS-0771, RS-0793, RS-0799, RS-0808, RS-0759, RS-0770, RS-0779, RS-0760, RS-0774, RS-0780, RS-0800, RS-0801, RS-0758, RS-0763, RS-0790, RS-0764, RS-0776, RS-0796, RS-0785, RS-0791, RS-0766, RS-0781, RS-0782, RS-0794, RS-0797, RS-0802, RS-0778, RS-0805, RS-0757, RS-0765, RS-0775, RS-0783, RS-0798, RS-0803, RS-0806, RS-0772, RS-0784, RS-0795, RS-0807, RS-0777, RS-0767, RS-0787, RS-0761, RS-0768, RS-0788, RS-0769, RS-0789, RS-0773 | -| `perf` / family / actionable | 3 | RS-0786, RS-0792, RS-0804 | -| `perf` / wide / actionable | 1 | RS-0762 | -| `conc` / leaf / actionable | 19 | RS-0831, RS-0825, RS-0826, RS-0827, RS-0820, RS-0815, RS-0834, RS-0811, RS-0822, RS-0821, RS-0810, RS-0832, RS-0828, RS-0830, RS-0833, RS-0829, RS-0812, RS-0809, RS-0823 | -| `conc` / leaf / policy-confirmed | 7 | RS-0824, RS-0813, RS-0819, RS-0816, RS-0835, RS-0818, RS-0836 | -| `conc` / family / policy-confirmed | 2 | RS-0814, RS-0817 | -| `conc` / wide / policy-confirmed | 1 | RS-0960 | -| `async` / leaf / actionable | 12 | RS-0844, RS-0853, RS-0852, RS-0848, RS-0841, RS-0845, RS-0839, RS-0849, RS-0847, RS-0854, RS-0840, RS-0850 | -| `async` / leaf / policy-confirmed | 1 | RS-0851 | -| `async` / family / actionable | 3 | RS-0846, RS-0843, RS-0855 | -| `async` / wide / actionable | 2 | RS-0837, RS-0842 | -| `async` / wide / policy-confirmed | 1 | RS-0838 | -| `unsafe` / leaf / actionable | 4 | RS-0858, RS-0857, RS-0856, RS-0859 | -| `macro` / leaf / actionable | 4 | RS-0863, RS-0860, RS-0861, RS-0862 | -| `test` / leaf / actionable | 63 | RS-0922, RS-0914, RS-0921, RS-0891, RS-0928, RS-0880, RS-0910, RS-0923, RS-0873, RS-0915, RS-0881, RS-0924, RS-0889, RS-0925, RS-0905, RS-0912, RS-0864, RS-0871, RS-0890, RS-0883, RS-0895, RS-0899, RS-0865, RS-0866, RS-0867, RS-0893, RS-0908, RS-0868, RS-0872, RS-0884, RS-0896, RS-0900, RS-0906, RS-0875, RS-0879, RS-0882, RS-0898, RS-0869, RS-0874, RS-0897, RS-0876, RS-0903, RS-0913, RS-0892, RS-0894, RS-0916, RS-0870, RS-0919, RS-0877, RS-0917, RS-0927, RS-0902, RS-0885, RS-0918, RS-0909, RS-0901, RS-0904, RS-0911, RS-0886, RS-0887, RS-0888, RS-0926, RS-0920 | -| `test` / leaf / policy-confirmed | 1 | RS-0907 | -| `test` / family / actionable | 3 | RS-0958, RS-0959, RS-0878 | -| `supply` / leaf / actionable | 17 | RS-0933, RS-0934, RS-0935, RS-0936, RS-0937, RS-0938, RS-0939, RS-0940, RS-0941, RS-0942, RS-0943, RS-0944, RS-0948, RS-0929, RS-0931, RS-0930, RS-0932 | -| `supply` / wide / actionable | 6 | RS-0945, RS-0946, RS-0947, RS-0949, RS-0950, RS-0951 | - -## 7. Method and verification evidence - -- Reconciliation: raw lane finding rows 1022 = report rows 965 + recorded merges 57; the executive-summary totals equal the per-lens section totals; severity split 13 high / 295 medium / 657 low; verdicts 923 actionable / 25 needs-contract / 17 policy-confirmed. -- Severity normalization: every one of the 13 `high` rows was re-judged against the rubric and carries a stated reachability path or a directly reproduced condition (panic reachable from wire or caller input, a blocking call on an executor worker, a test that cannot fail, and RS-0916's assertion that cannot pass on the Display output - red at HEAD). No demotions were recorded. Duplicates were merged under the lens-specificity order (`unsafe` > `err`/`serde`/`async`/`conc`/`perf` > `type`/`api`/`own` > `idiom` > `docs`) and recorded as `merged:` on the kept row. -- Independent verification (`VERIFICATION.md`, separate clean-context agent; every number recomputed): checks 1-8 pass - lane completeness 110/110; crate coverage 94/94 with zero double ownership; schema conformance 1022 rows, 0 violations; coverage matrix 94x16 complete (449 `N/A`, 504 `clean`, 461 numeric, 90 `X1`); anchor existence - 568 anchors checked (all 13 `high` rows plus a deterministic every-5th sample of the 1008 medium/low rows), 0 failures; count reconciliation as above; writes confined to this audit directory; README-faithfulness spot-check of five rows field-for-field. Check 6 initially failed on this report's own defect - four crate-lane `supply` rows (`RS-0929`..`RS-0932`) were missing from section 2 - which was fixed and re-verified; check 9 is informational (the artifact list above matches its recomputation, with denominators within 4). -- Data-quality note: lane prose carries numeral-spelling and parentheses artifacts from the lane-writing path (e.g. `two finding(s)`, a dropped `)` in an inline snippet). The structured fields (lens, severity, blast, effort, verdict, anchors, ids) were parsed and verified independently; a mechanical repair pass normalized semicolon spacing, merged-word splits, zero-width characters, stray `{{` terminators, and one file's space-after-paren form, without touching any path, line number, or count. Files where more than ~25% of finding lines carry parenthesis artifacts (drop/duplication, no fact loss): `d2b-provider-guest-qemu-media.md` (40/49), `d2b-resource-compiler.md` (33/49), `d2b-provider-shell-terminal.md` (17/37), `d2b-provider-guest.md` (20/45), `d2bd-p5.md` (12/34), `d2b-provider-volume.md` (14/41), `d2b-provider-credential-managed-identity.md` (11/36), `d2b-contracts.md` (10/39), `d2b-broker-p6.md` (13/52); the verifier's recomputation also places `xtask-p5.md` (9/35) just over the threshold - see VERIFICATION.md check 9. Renderer note: finding rows in sections 2 and 4 carry lane text verbatim, including `|` inside inline code (only the section-1 summary table escapes it), so closure pipes in fix snippets are shown exactly as the lane recorded them. - -## 8. Drift note - -- Working tree vs baseline `6ebdd4cec`: no source, policy, or gate file changed during the audit; the only writes are under `docs/audits/2026-09-24-rust-skills-audit/` and `.scratch/`. A pre-existing untracked plan file was left untouched. See VERIFICATION.md check 7. - diff --git a/docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md b/docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md deleted file mode 100644 index 8674c1f24..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/U1-constraints.md +++ /dev/null @@ -1,961 +0,0 @@ -# U1 - Rust skills audit constraint packet (priming feed) - -Baseline: branch `v3` @ `6ebdd4cec` (HEAD at audit start; working tree clean except -one pre-existing untracked plan file, not ours) - Date: 2026-09-24 - Lens revision: -`third_party/agent-skills/rewrite-rs/v0.1.0-alpha.1/skills/` (vendored at the same -HEAD) - Plan: `local://rust-skills-audit-plan.md` (durable copy; this packet -implements its Step 1). - -Deliverable: `docs/audits/2026-09-24-rust-skills-audit/` - `README.md` -(consolidated report), `U1-constraints.md` (this packet), `lane/.md` (one file -per lane), `VERIFICATION.md` (Step 5). Nothing else is written; the audit is -READ-ONLY on source, policy, and gates. No `cargo build`/`test`/`clippy`, -formatter, or project-wide command is run by any lane. - -Every lane: read this file fully, then the assigned lens cards (section c), then -run the lane protocol (section b) over the lane's scope from the published -part-partition map (section f). Write only your lane file. - -## (a) Lane map - -Lane ids, crates, planning-time LOC (basis: `src/**` excluding `src/generated/**` -plus `tests/**`, `wc -l`), and part counts: - -|lane id|crate|LOC|parts| -|---|---|---:|---:| -|`d2bd-p1`..`-p8`|`d2bd`|93,768|8| -|`d2b-broker-p1`..`-p7`|`d2b-broker`|79,531|7| -|`xtask-p1`..`-p5`|`xtask`|49,329|5| -|`d2bd-runtime-p1`..`-p4`|`d2bd-runtime`|43,123|4| -|`d2b-p1`..`-p3`|`d2b`|26,481|3| -|`d2b-bus-p1`..`-p2`|`d2b-bus`|20,894|2| -|`d2b-contracts-resource-p1`..`-p2`|`d2b-contracts-resource`|19,571|2| -|`d2b-core-p1`..`-p2`|`d2b-core`|17,644|2| -|`d2b-provider-toolkit-p1`..`-p2`|`d2b-provider-toolkit`|17,414|2| -|`d2b-provider-display-wayland-p1`..`-p2`|`d2b-provider-display-wayland`|16,248|2| -|`d2b-resource-runtime-p1`..`-p2`|`d2b-resource-runtime`|15,515|2| -|`d2b-contracts-provider-p1`..`-p2`|`d2b-contracts-provider`|14,706|2| -|`d2b-session-p1`..`-p2`|`d2b-session`|14,538|2| -|`d2b-resource-api-p1`..`-p2`|`d2b-resource-api`|13,931|2| -|`d2b-core-controller-p1`..`-p2`|`d2b-core-controller`|13,919|2| -|`d2b-provider-clipboard-wayland-p1`..`-p2`|`d2b-provider-clipboard-wayland`|13,710|2| -|`d2b-contracts-zone-session-p1`..`-p2`|`d2b-contracts-zone-session`|12,839|2| -|`d2b-host`|`d2b-host`|11,767|1| -|`d2b-provider-network-local`|`d2b-provider-network-local`|11,256|1| -|`d2b-contracts`|`d2b-contracts`|10,743|1| -|`d2b-provider-process`|`d2b-provider-process`|10,732|1| -|`d2b-provider-guest-cloud-hypervisor`|`d2b-provider-guest-cloud-hypervisor`|10,523|1| -|`d2b-provider-volume-local`|`d2b-provider-volume-local`|10,405|1| -|`d2b-zone-routing`|`d2b-zone-routing`|10,370|1| -|`d2b-resource-compiler`|`d2b-resource-compiler`|7,461|1| -|`d2b-provider-device-usbip`|`d2b-provider-device-usbip`|7,015|1| -|`d2b-provider-credential-secret-service`|`d2b-provider-credential-secret-service`|6,699|1| -|`d2b-session-unix`|`d2b-session-unix`|6,663|1| -|`d2b-provider-guest`|`d2b-provider-guest`|6,436|1| -|`d2b-provider-supervisor`|`d2b-provider-supervisor`|6,162|1| -|`d2b-provider-transport-azure-relay`|`d2b-provider-transport-azure-relay`|5,952|1| -|`d2b-provider-notification-desktop`|`d2b-provider-notification-desktop`|5,712|1| -|`d2b-provider-credential-managed-identity`|`d2b-provider-credential-managed-identity`|5,453|1| -|`d2b-provider-credential-entra`|`d2b-provider-credential-entra`|5,246|1| -|`d2b-audit`|`d2b-audit`|5,221|1| -|`d2b-contracts-broker`|`d2b-contracts-broker`|5,215|1| -|`d2b-contracts-control`|`d2b-contracts-control`|5,019|1| -|`d2b-resource-client`|`d2b-resource-client`|4,839|1| -|`d2b-provider-device-security-key`|`d2b-provider-device-security-key`|4,320|1| -|`d2b-process-conformance`|`d2b-process-conformance`|4,195|1| -|`d2b-provider-shell-terminal`|`d2b-provider-shell-terminal`|4,181|1| -|`d2b-provider-transport-vsock`|`d2b-provider-transport-vsock`|4,146|1| -|`d2b-provider-activation-nixos`|`d2b-provider-activation-nixos`|4,014|1| -|`d2b-provider-wayland-policy`|`d2b-provider-wayland-policy`|3,982|1| -|`d2b-provider-process-systemd`|`d2b-provider-process-systemd`|3,816|1| -|`d2b-provider-zone-link`|`d2b-provider-zone-link`|3,814|1| -|`d2b-provider-observability-otel`|`d2b-provider-observability-otel`|3,809|1| -|`d2b-provider-device-gpu`|`d2b-provider-device-gpu`|3,758|1| -|`d2b-provider-guest-qemu-media`|`d2b-provider-guest-qemu-media`|3,694|1| -|`d2b-provider-device-tpm`|`d2b-provider-device-tpm`|3,338|1| -|`d2b-provider-credential`|`d2b-provider-credential`|3,337|1| -|`d2b-provider`|`d2b-provider`|3,252|1| -|`d2b-unsafe-local-helper`|`d2b-unsafe-local-helper`|3,240|1| -|`d2b-provider-volume-binding`|`d2b-provider-volume-binding`|2,914|1| -|`d2b-provider-guest-azure-virtual-machine`|`d2b-provider-guest-azure-virtual-machine`|2,839|1| -|`d2b-provider-audio-pipewire`|`d2b-provider-audio-pipewire`|2,709|1| -|`d2b-provider-endpoint`|`d2b-provider-endpoint`|2,548|1| -|`d2b-provider-guest-azure-container-apps`|`d2b-provider-guest-azure-container-apps`|2,420|1| -|`d2b-provider-provider`|`d2b-provider-provider`|2,289|1| -|`d2b-provider-volume`|`d2b-provider-volume`|2,150|1| -|`d2b-provider-host`|`d2b-provider-host`|2,108|1| -|`d2b-provider-user`|`d2b-provider-user`|2,099|1| -|`d2b-provider-volume-virtiofs`|`d2b-provider-volume-virtiofs`|2,025|1| -|`d2b-telemetry`|`d2b-telemetry`|1,983|1| -|`d2b-provider-config-nixos`|`d2b-provider-config-nixos`|1,816|1| -|`d2b-provider-system-core`|`d2b-provider-system-core`|1,810|1| -|`d2b-broker-composition`|`d2b-broker-composition`|1,634|1| -|`tail-1`|`d2b-broker-fixture-handlers`, `d2b-broker-fixture-syscall-surface`, `d2b-controller-toolkit`, `d2b-host-activation-helper`, `d2b-provider-audio-binding`|1,121|1| -|`tail-2`|`d2b-provider-audio-service`, `d2b-provider-command`, `d2b-provider-device`, `d2b-provider-emergency-policy`, `d2b-provider-operation`|2,571|1| -|`tail-3`|`d2b-provider-process-minijail`, `d2b-provider-quota`, `d2b-provider-resource-export`, `d2b-provider-resource-import`, `d2b-provider-role`|1,759|1| -|`tail-4`|`d2b-provider-role-binding`, `d2b-provider-seccomp-profile`, `d2b-provider-shell-pool`, `d2b-provider-shell-session`, `d2b-provider-telemetry-binding`|2,549|1| -|`tail-5`|`d2b-provider-telemetry-service`, `d2b-provider-test-controller`, `d2b-provider-transport-unix`, `d2b-provider-wayland-session`, `d2b-provider-zone`|3,144|1| -|`tail-6`|`d2b-resource-types`, `d2b-sk-frontend`|2,173|1| - -Cross-cutting lanes (not in the table): `lane/X1-supply-chain.md`, -`lane/X2-generated-boundary.md`, `lane/X3-cross-crate-duplication.md`. - -Part-partition rule (mechanical, already applied in section f; no -renegotiation): for a crate with k>1 parts, its top-level units under `src/` -(files `src/*.rs`, directories `src/*/`, excluding `generated`) were sorted by -LOC descending and greedily packed (least-loaded-bin) into k groups each -`<= ceil(LOC/k) x 1.2`, keeping units whole; units exceeding the cap were -descended (directories) or split by item ranges (files, boundaries recorded in -section f). Section f publishes the concrete part -> module map; each lane stays -inside its assigned files/ranges. - -## (b) Global rules - -### Lane protocol (run in this order) - -1. Read `U1-constraints.md` fully, then the assigned lens cards. -2. Read each assigned lens's SKILL.md (`skill://`; if that URI does - not resolve, the vendored path in the lens table below). A SKILL.md may point - to sibling reference files in the same directory (`ERROR-TYPES.md`, - `NAMING.md`, `BOILERPLATE.md`, `FLOWS.md`, `CLONE-DECISIONS.md`, - `SHARED-STATE.md`, `NUMERICS.md`, `TYPESTATE.md`, `SURFACE.md`, - `DEPENDENCY-INJECTION.md`, `SEMVER.md`, `ALLOCATION.md`, `CANCELLATION.md`, - `SAFETY-REVIEW.md`, `TEST-DESIGN.md`, `DIFFERENTIAL-TESTING.md`, `DENY.md`) - - read on demand when the SKILL.md defers to them. -3. Enumerate the assigned files (all of `src/**` except `src/generated/**`; - plus `tests/**` for the `test` lens; plus `build.rs` if present). If the lane - is a part (`-p`), stay inside the assigned module partition: for file-split - parts restrict seed runs with `sed -n ',p' ` (or - `awk 'NR>=A && NR<=B'`) and add `` to reported line numbers so anchors - stay absolute. -4. Per lens, in the card order: run the seeds, read every hit with enough - context to judge (whole file for files <400 lines; otherwise the hit - neighborhood, +/-40 lines, plus the file's item list). For `api`/`type`, - additionally read the crate's public surface: `lib.rs`/`mod.rs` re-exports - and all `pub` items. -5. Emit findings into the lane file as you go. Reading budget rule: never dump a - whole large file into the lane; cite `path:line`. -6. Sampling rule: if one lens's seeds exceed 200 hits in the lane, read 50 hits - sampled deterministically (every ceil(n/50)-th hit) and record - `sampled: 50 of hits` in the lens section; never claim exhaustiveness for - that lens. -7. Do not run `cargo build`/`test`/`clippy`, formatters, or any project-wide - command. Read-only audit. Write only your lane file. -8. Caller census rule (mandatory) for any finding that claims something is - unused, redundant, unreachable, or reducible in visibility: search the symbol - across `packages/`, `nixos-modules/`, `tests/`, `docs/reference/`, `labs/`, - and `BUILD.bazel`/`*.bzl` files; record - `census: over = hits`. - -### Lane file format (verbatim contract) - -``` -# - [- part /] -Baseline: | LOC audited: (excl. src/generated/**) | modules: -Lenses: | Partitions: - -## -- # sev= blast= effort= verdict= - - fix: - [path:line, path:line] - evidence: -- clean: - -## Coverage -: = | clean | N/A: -``` - -Schema notes (grammar the verifier keys on): - -- A finding is exactly two lines: the `- # sev=... - ... - fix: ... - - [path:line, ...]` line, then one ` evidence: ...` line. -- Local finding ids: `#`, k increments from 1 per lane. -- Coverage lines use one of: `- : finding(s)` | - `- : clean (seeds ran: //...)` | - `- : N/A (seeds: //... all zero; )`. -- Tail lanes carry a `## ` section per crate, each with the standard lens - sections and its own `### Coverage` block; the lane header lists all crates. -- `LOC audited` is measured by the lane (`wc -l` over its assigned files, - excluding `src/generated/**`). -- Consolidation assigns global `RS-####` ids; local ids stay lane-local. - -### Severity rubric (fixed for all lanes; judge against these definitions) - -- `high` - correctness, soundness, security, or measurable operational cost: - unsound/incorrect code; a panic reachable from untrusted or caller input; a - secret/PII path into logs/errors/metrics; a blocking call on an executor - worker; unbounded allocation/scan in a hot path; a failure silently swallowed - where the caller must know; a test that cannot fail. -- `medium` - API/model/maintainability with real cost: public surface exposing - internals or leaking types; illegal states representable that the skill names - an alternative for; an error taxonomy forcing callers to string-match; missing - validation on wire input where a sibling type has it; hand-rolled duplicate of - an existing in-tree helper (name the canonical home); missing doc contract on - a non-obvious public item; contract behavior with no test. -- `low` - expression, consistency, naming, polish: iterator-vs-index loop; - explainable-but-avoidable clone; naming drift; doc first-sentence shape. - -### Verdict values - -- `actionable` (implementable now), `policy-confirmed` (conflicts with a - recorded deliberate decision - cite the policy file:line; requires a - policy/ADR change first), `needs-contract` (touches wire formats, error codes, - manifest schema, golden fixtures, or generated shapes). - -### Blast radius and effort - -- Blast radius: `leaf` (one crate), `family` (crates in one family - provider - family, contracts family, etc.), `wide` (wire/contracts/daemon/broker/ - cross-cutting). -- Effort: `S` (one file or mechanical), `M` (a handful of files in one crate), - `L` (multi-crate or design change). - -### Evidence rules - -- Every finding's `evidence:` line names the seed regex and its count, the - census result, or `static (unmeasured)` for perf; a finding without evidence - is a schema violation. -- An `api` claim that a change breaks callers, and an ownership claim that a - clone is required, both cite the call site rather than assert it. -- Findings that propose an improvement already named by a gate/policy in - section (d) are `policy-confirmed` with the policy file:line cited. -- Perf findings are static until a benchmark exists; never claim a measured - win. - -### Read-only rules - -- No source edits, no gate runs, no formatter, no `git` state changes. The only - write is the lane's own `lane/.md` file. -- Do not fix anything found; correctness or security defects are kept as - `sev=high verdict=actionable` with route `review-pass` noted in the row text. -- The pre-existing untracked file `docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md` - is not ours; leave it untouched. - -## (c) Lens cards - -Lens table (all 16 audit lenses; paths relative to -`third_party/agent-skills/rewrite-rs/v0.1.0-alpha.1/`): - -|lens|skill name|vendored SKILL.md| -|---|---|---| -|`idiom`|idiomatic-rust|`skills/rust/idiomatic-rust/SKILL.md`| -|`own`|ownership-not-clone|`skills/rust/ownership-not-clone/SKILL.md`| -|`type`|type-driven-design|`skills/rust/type-driven-design/SKILL.md`| -|`api`|rust-api-design|`skills/rust/rust-api-design/SKILL.md`| -|`err`|rust-errors|`skills/rust/rust-errors/SKILL.md`| -|`serde`|rust-serde|`skills/misc/rust-serde/SKILL.md`| -|`obs`|rust-observability|`skills/rust/rust-observability/SKILL.md`| -|`docs`|rust-docs|`skills/rust/rust-docs/SKILL.md`| -|`perf`|rust-performance|`skills/rust/rust-performance/SKILL.md`| -|`conc`|rust-concurrency|`skills/rust/rust-concurrency/SKILL.md`| -|`async`|async-rust|`skills/rust/async-rust/SKILL.md`| -|`unsafe`|unsafe-rust|`skills/rust/unsafe-rust/SKILL.md`| -|`ffi`|rust-ffi|`skills/misc/rust-ffi/SKILL.md`| -|`macro`|rust-macros|`skills/misc/rust-macros/SKILL.md`| -|`test`|rust-testing|`skills/workflow/rust-testing/SKILL.md`| -|`supply`|rust-supply-chain|`skills/misc/rust-supply-chain/SKILL.md`| - -Seed construction note: every card's seed set begins with the patterns named in -that skill's own `## Verification` section. Where the skill names only cargo -subcommands (`cargo clippy`, `cargo doc`, `cargo miri`, `cargo bench`, ...), the -card carries a `verify:` line with those commands and the seed regexes are -proxies for the class those commands report. Every seed below is a single regex -that ran over this repository at `6ebdd4cec`; the per-crate hit counts are in -section (e). - -### idiom (idiomatic-rust) - -Judges: expression shape - iterator pipelines over index loops, `From`/`TryFrom` -over ad-hoc converters, derives over hand-written impls, newtypes over bare -primitives, naming discipline (`as_`/`to_`/`into_`, no `get_`, acronyms, free -functions). This is the lens for "reads like Rust" findings; defer ownership to -`own`, invariants to `type`. -Seeds (run each; record hit count per crate): - 1. `for \w+ in 0\.\.` # index loop where an iterator pipeline is expected - 2. `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` # hand-written impl a derive may replace - 3. `let mut \w+ = (String|Vec)::new\(\)` # statement-style accumulation -verify: `cargo clippy --all-targets`, `cargo fmt --check`, `cargo test` (run by -remediation, not by lanes). -Applicable when: the crate declares `fn` bodies. N/A only when all three seeds -are 0 and the crate declares no `fn`. -Repo false positives: hand-written `Debug` impls that redact secrets (deliberate; -`redacted_debug!` exists and a derive would leak); hand-written `PartialEq` on -wire types with deliberate field exclusions; `Default` impls that preserve an -invariant (forbidden by a field-wise derive); `to_string()` on a type whose -`Display` is the wire rendering; `#[derive]` already present is not a finding. -Gate interaction: `make check` runs per-crate clippy inside the Bazel suite with -`-D warnings` on rustc; `clippy::pedantic` is not enabled, so its class is -proposals only. Naming/derive findings are not gate-enforced. - -### own (ownership-not-clone) - -Judges: whether every clone/`to_owned`/`Rc`/`RefCell`/`Arc` is -explainable in one sentence; borrows beat copies; argument position takes the -cheapest thing (`&str` over `&String`, `&[T]` over `&Vec`); `mem::take` -instead of clone; avoid statics. -Seeds: - 1. `\.clone\(\)` # count per file; inspect each - 2. `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` - 3. `Rc<|RefCell<|Arc>` in the daemon's shared -state where multiple owners genuinely exist (`d2bd/src/composition.rs` -`ServerState`); `.to_string()` at a wire-rendering boundary; test fixtures. -Gate interaction: none denies clones. `clippy::redundant_clone` is not enabled; -its findings are candidates only. - -### type (type-driven-design) - -Judges: illegal states representable - boolean flag soup, `Option` pairs where -exactly one is `Some`, stringly-typed state, validate-at-every-callsite instead -of parse-once types, typestate for protocol order. Stopping rule: encode an -invariant only where violating it is a real bug class. -Seeds: - 1. `fn validate_\w+|fn check_\w+` # runtime validation a parsed type could replace - 2. `is_\w+: bool|\w+_flag: bool` # boolean flags that may be state - 3. `(mode|kind|state): String` # stringly-typed state -verify: `cargo clippy --all-targets`, `cargo test`; after a change, grep that -the now-impossible branch is deleted. -Applicable when: the crate declares a `struct` or `enum`. N/A only when all -seeds are 0 and it declares neither. -Repo false positives: wire types that must mirror a schema (generated shapes, -`deny_unknown_fields` admission gates, docs/reference-pinned fields); the -`debug_logging`-class pinned wire fields; one-variant or two-variant enums that -are declared extension points for a declared provider; `StateDirIntent`-class -tokens kept because the daemon references them; schema-mirroring booleans in -generated code (lane X2 owns those). -Gate interaction: `docs/reference/manifest-schema.md` + `schemars`-generated -schemas + `docs/reference/error-codes.md` pin wire shapes; restructuring a wire -type is `needs-contract`. Generated shapes are X2's. - -### api (rust-api-design) - -Judges: what callers can see and rely on - deliberate exports, one path per -item, no `Arc`/`Rc`/`Box`/`RefCell` or dependency types in public signatures, -trait design (small required surface, sealed where growth is planned), semver -breakage classes. -Seeds: - 1. `\bpub (fn|struct|enum|trait|type|const|mod) ` # exported surface size - 2. `pub .*\b(Arc|Rc|Box|RefCell)<` # internals in a public signature - 3. `^\s*pub use ` # re-export arms -verify: `cargo doc --no-deps`, `cargo clippy --all-targets`, `cargo test`; -`cargo semver-checks check-release` only if already installed (never install). -Applicable when: the crate has a `lib` target with `pub` items. N/A only when -all seeds are 0. -Repo false positives: contract crates intentionally export wide wire -vocabularies (that IS the contract; narrowing is `needs-contract`); `pub use` -re-export arms in `lib.rs` are the house single-surface pattern; `test-support` -feature-gated exports consumed by other crates' tests; `Arc<...>` in a public -signature where the value genuinely shares ownership (evaluate, cite the call -sites); generated `pub` surface (X2's). -Gate interaction: no semver gate in the repo. Exported types of contract crates -are pinned by docs/reference and goldens: a change there is `needs-contract`. - -### err (rust-errors) - -Judges: panic policy vs `Result` boundary, error taxonomy split by caller -action, context survival, wire error codes. -Seeds (seed 1 is the skill's own audit): - 1. `\.unwrap\(\)|\.expect\(` # panic site outside tests - 2. `let _ = |\.ok\(\);` # swallowed `Result` - 3. `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` - 4. `enum \w*Error` # error taxonomy shape -verify: `cargo clippy --all-targets`, `cargo test`; the skill's targeted audit -`rg '\.unwrap\(\)|\.expect\(' --glob '!**/tests/**' --glob '!**/benches/**' src/`. -Applicable when: always (a crate with fns can be read for panic policy); N/A -only when all seeds are 0 and no `fn` exists. -Repo false positives: `unwrap` in `#[cfg(test)]` and in `#[tokio::main]`/`main` -startup preconditions; `expect("fixed ... serializes")` on literally-built -values; `format!`-built error strings that are in fact wire error codes pinned by -`docs/reference/error-codes.md`; generated error tables; `let _ =` on a -deliberately ignored best-effort cleanup (judge per site). -Gate interaction: no lint denies `unwrap`/`expect` today (`unwrap_used`/ -`expect_used` are restriction lints, not enabled - propose, never switch on). -`d2b_core::error::Error::all_kinds()` is the wire error catalog; a finding that -restructures a wire-visible error enum is `needs-contract`. -`docs/reference/error-codes.md` is generated from it. - -### serde (rust-serde) - -Judges: serde as the boundary where untrusted input becomes a domain type - -`try_from` validation, `rename_all` conventions, the three optionality meanings, -the four enum representations, `deny_unknown_fields` as a per-type decision, -`flatten` costs, hand-written `Deserialize` as admission gate. -Seeds: - 1. `derive\([^)]*(De)?[Ss]erialize` - 2. `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` - 3. `impl .*Deserialize.*for` # hand-written deserializers - 4. `serde_json::from_|serde_json::to_` -verify: `cargo test` (round-trip + real-payload tests), `cargo clippy`. -Applicable when: seeds 1-4 hit. N/A when all are 0 (crate crosses no wire). -Repo false positives: hand-written `Deserialize` impls that are live admission -gates (qemu guest/provider spec shapes - recorded refusal; do not re-flag); -generated `Wire` deserialize blocks (76 across contract crates - X2's; cite, -never flag); `deny_unknown_fields` deliberately absent on service-consumed -messages; `try_from` validation already applied. -Gate interaction: `docs/reference/manifest-schema.md` and `tests/golden/**` pin -wire shapes - changes there are `needs-contract`. The contract-crate -macro/boilerplate consolidation row (#C4) is recorded not-applied; re-proposing -it OK but must cite the record row and current sites. - -### obs (rust-observability) - -Judges: structured events with named fields; `tracing` over `println`; spans for -context; error chains logged once at the boundary that handles them; never a -secret in a field; lazy field construction. -Seeds (seed 1 and 2 are the skill's own greps): - 1. `\bprintln!\(|\beprintln!\(` # expect zero in a library - 2. `(info|debug|warn|error|trace)!\("` # interpolated message with no fields = smell - 3. `\.instrument\(|#\[instrument` # span usage (context for judging) - 4. `tracing::|log::` # presence check -verify: `cargo clippy --all-targets`, `cargo test`. -Applicable when: always; N/A only when all seeds are 0 and the crate has no -`tracing`/`log` dependency. -Repo false positives: CLI user-facing stdout in `d2b/src/**` and `bin/**` -(product output, not telemetry - the skill itself carves this out); `xtask` -generators whose stdout IS the artifact; test fixtures printing; message-only -events where the fields live in the enclosing span; `d2b-telemetry`/otel -providers whose payload is the metric, not a log. -Gate interaction: the ADR 0010/0028 identifier-in-log redaction scan -(`security-scan` job in `.github/workflows/pr-l1-static-fast.yml`, implemented -by `packages/xtask/src/diagnostic_redaction.rs`) already gates -identifier-in-log; sites it covers are `policy-confirmed` - cite the gate file. - -### docs (rust-docs) - -Judges: doc comment as API contract - one-line first sentence, module docs, -canonical sections (`# Examples`, `# Errors`, `# Panics`, `# Safety`), doctests -that run (`ignore` = unchecked), intra-doc links, magic values documented with -the why. -Seeds: - 1. `^\s*pub (fn|struct|enum|trait|const|type)` # public items needing docs - 2. `/// # (Examples|Errors|Panics|Safety)` # canonical sections present - 3. `-> Result<` # items that should carry `# Errors` -verify: `cargo doc --no-deps`, `cargo test --doc`, `cargo clippy --all-targets`. -Applicable when: seed 1 hits (public items exist). N/A when all seeds are 0. -Repo false positives: internal crates whose contract is the dossier/README and -whose items are crate-internal (`pub(crate)` correct); bin-only crates (the -skill: never add `missing_docs` to a binary crate); doc comments that narrate -policy deliberately (kept); generated docs. -Gate interaction: `missing_docs` is not enabled anywhere; `cargo doc` is not in -`make check`. A finding proposing the lint is a proposal, never imposed. - -### perf (rust-performance) - -Judges: allocation out of hot paths (`format!` in loops, `with_capacity`, clear -and reuse, `Cow`), collection choice for the access pattern, hashing with -attacker-controlled keys, iterator bounds-check elision, codegen flags as the -last five percent. -Seeds: - 1. `format!\(` # allocation sites - 2. `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` # grow-by-push candidates - 3. `\.to_string\(\)` # copies at boundaries -verify: `cargo bench` against a recorded baseline, `cargo clippy`, -`cargo test --release`. -Applicable when: always; N/A only when all seeds are 0. -Repo false positives: `format!` in error paths, audit rendering, and one-shot -diagnostics (cold); `Vec::new()` where the empty case is common; `to_string()` -inside `Display` impls; deliberate `String` building where the artifact is text -(`xtask` generators, wire rendering); the repo has a perf budget gate -(`make perf`) - a finding that claims a budget regression must name the budget. -Gate interaction: perf findings are `static (unmeasured)` unless a benchmark -exists; never claim a measured win. `#[inline]`/codegen-flag advice is taste and -low severity at most. - -### conc (rust-concurrency) - -Judges: the concurrency model picked from the workload shape (data parallelism, -scoped threads, channels, shared state last), weakest correct atomic ordering, -`Send`/`Sync` claims written down, `thread_local!` over `static mut`. -Seeds: - 1. `std::thread::|thread::spawn|thread::scope` - 2. `\bMutex<|\bRwLock<` - 3. `Atomic\w+|Ordering::` - 4. `thread_local!|unsafe impl (Send|Sync) for` -verify: `cargo test` (incl. ignored stress tests), `cargo clippy`, -`cargo miri test` where unsafe `Send`/`Sync` or atomics are involved. -Applicable when: seeds 1-4 hit. N/A when all are 0. -Repo false positives: `std::sync::Mutex` on genuinely synchronous paths -(`d2b-broker/src/ops/**`, the dedicated bounded worker per plan R4); atomics as -counters; `tokio::sync::*` re-exports; test-only synchronization. -Gate interaction: the async-gate scanner (`make check-async-gate`) and -`disallowed_methods` police the blocking subset; `await_holding_lock`/ -`await_holding_refcell_ref` are denied. `// async-gate-allow: ` markers -(283 sites, inventory `packages/xtask/data/async-gate-inventory.json`) are -deliberate exceptions - cite, never re-flag. - -### async (async-rust) - -Judges: runtime choice at the top; blocking work inside an async context; -guards held across `.await`; cancellation safety (irreversible step in one -non-cancellable piece); shared state across tasks; `Send` bounds; future size. -Seeds: - 1. `async fn|async move|\.await` - 2. `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` - 3. `tokio::sync::(Mutex|RwLock|Notify)` - 4. `#\[tokio::(main|test)\]|Runtime::block_on` -verify: `cargo clippy --all-targets`, `cargo test`; async bugs are -timing-dependent - multi-thread test flavor where the path changed. -Applicable when: seeds 1-4 hit. N/A when all are 0. -Repo false positives: `block_on` at process entry points and plain `#[test]` -harnesses (sanctioned with inline allows); `sync_channel` recv on the dedicated -worker thread (plan R4); `async-gate-allow` markers (deliberate; cite); -`spawn_blocking` sites already in `packages/xtask/data/blocking-census-baseline.json` -(tracked work - merely being present is not a finding; a conversion of one is -already-planned work, and only a site above the baseline is new). -Gate interaction: `make check-async-gate` (source scanner), -`make check-census` (blocking-API census vs committed baseline), -`await_holding_lock`/`await_holding_refcell_ref` deny, -`clippy::disallowed_methods` deny at the workspace lint table (see (d) 1 for the -level discrepancy note). Findings that propose one of the `clippy.toml`-named -replacements are `policy-confirmed` unless the site is on a recorded exception -list. - -### unsafe (unsafe-rust) - -Judges: justification (FFI / named perf win / language-inexpressible primitive), -a `// SAFETY:` comment stating the invariant on every block, safe wrappers that -cannot be misused, `# Safety` on every `pub unsafe fn`, the UB hazard list -(aliasing, uninit, invalid values, transmute, unwinding across FFI, data races), -Miri as the verification. -Seeds: - 1. `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` - 2. `// SAFETY:` - 3. `transmute|from_raw|MaybeUninit|mem::zeroed` - 4. `unsafe_code` # lint setting presence (forbid/deny/allow) -verify: `cargo miri test` (say so explicitly if unavailable; never install -nightly), `cargo clippy --all-targets`, `cargo test`. -Applicable when: seeds 1-3 hit, or an `unsafe_code = "allow"` manifest exists. -N/A when seeds 1-3 are all 0 (seed 4 alone - a `forbid(unsafe_code)` attribute - -does not make the lens applicable). -Repo false positives: `d2b-broker/src/sys.rs` per-site `#[allow(unsafe_code)]` -call wrappers are the sanctioned syscall boundary; `d2b-broker-fixture-syscall-surface` -is `unsafe_code = "allow"` deliberately (fixture); `#[unsafe(link_section = ...)]` -is edition-2024 syntax for an attribute (not an unsafe block); `unsafe` in a -doc comment is prose. -Gate interaction: `unsafe_code = "forbid"` where workspace lints are inherited; -local tables per (d) 8. The enumerated exception set in (d) 8 is exhaustive as of -`6ebdd4cec`; a new site not in it is itself a finding. - -### ffi (rust-ffi) - -Judges: thin translation layer with logic in core crates; nothing panics across -the boundary (`catch_unwind` at entry); every pointer states ownership; -`repr(C)`/`repr(transparent)`; handle over module-level state; library-prefixed -symbols; `CStr`/`CString` and pointer+length for strings/slices; edition-2024 -forms (`unsafe extern`, `#[unsafe(no_mangle)]`). -Seeds: - 1. `extern "C"|no_mangle|unsafe\(link_section` - 2. `catch_unwind` - 3. `repr\(C\)|repr\(transparent\)` - 4. `CStr|CString|c_char` -verify: `cargo test` (core crate), `cargo miri test` for the Rust side, -`cargo clippy`; a foreign-language harness is the boundary check. -Applicable when: seeds 1-4 hit. N/A when all are 0 (most crates). -Repo false positives: `extern "C"`-shaped declarations in `libc`-binding call -sites that never cross a foreign caller; `repr(transparent)` newtypes over -handles (intended); `catch_unwind` used for process supervision without FFI -(judge: is it a boundary?); `c_char` in `nix`/`libc` syscall wrappers. -Gate interaction: none specific. The FFI-carrier set is in (d) 8. - -### macro (rust-macros) - -Judges: macro as a last resort (the three genuine answers: variadic interface, -impl-per-type generation, non-Rust DSL); `macro_rules!` before proc-macro; -hygiene and `$crate`; narrowest fragment specifiers; `_private` module; spanned -errors (`syn::Error::new_spanned` -> `to_compile_error`), never panics; proc-macro -logic in a sibling crate. -Seeds: - 1. `macro_rules!` - 2. `proc_macro|syn::|quote!` - 3. `\$crate` - 4. `to_compile_error|new_spanned` -verify: `cargo expand --lib` (propose if absent, never require), `cargo test` -(trybuild suite if present), `cargo clippy`. -Applicable when: seeds 1-4 hit. N/A when all are 0. -Repo false positives: the exported `redacted_debug!`-class macros (deliberate -API; their contract is `docs`); test-only helper macros; std macros -(`format!`, `vec!`) are not `macro_rules!` definitions. -Gate interaction: repo policy forbids adding new linters/formatters; a `trybuild` -proposal is a proposal. - -### test (rust-testing) - -Judges: the form follows the assertion (unit/integration/doc/property/ -snapshot/golden, differential for ports); behavior not implementation; error -variants not `Display` strings; determinism (seeded generators, injected time, -no network); table-driven with failure messages; a test must be able to fail; -the expected value is human-written or from an independent source. -Seeds (scope: `src/**` + `tests/**`): - 1. `#\[test\]|#\[tokio::test\]` # test mass - 2. `assert_eq!\(|assert_ne!\(|assert!\(` # assertion mass - 3. `proptest!|insta::assert|rstest` # property/snapshot tooling - 4. `#\[ignore\]` # ignored tests -verify: `cargo test --all-features`, `cargo test --doc`, -`cargo clippy --all-targets --all-features`; a new test must be observed failing -first. -Applicable when: seeds 1-4 hit. N/A when all are 0. -Repo false positives: golden/snapshot tests pinned under `tests/golden/**` -(authoritative); policy-required `tests/registration.rs` shims (13-17 lines -calling a shared assertion - documented pattern, do not flag as trivial); -tests deliberately pinning wire shapes; `#[ignore]` where the ignore is -documented (stress/root-only); `test-support` features. -Gate interaction: `make test-unit` is the Layer-1 development umbrella; -`tests/AGENTS.md` governs test placement. "A test that cannot fail" is `high` -severity per the rubric. - -### supply (rust-supply-chain) - -Judges: advisories reached from this repo, unmaintained crates, licence policy, -duplicate versions, tree weight - every finding ends in a decision (upgrade / -replace / vendor / accept with a written reason). -verify: `cargo deny check`, `cargo audit`, `cargo tree -d`, -`cargo update --dry-run`. -Applicable when: NEVER a per-crate lane lens. Lane X1 owns supply at workspace -level. A per-crate lane may note a directly evidenced crate-manifest problem -(unused dependency: dep name appears nowhere in that crate's `src/`+`tests/`) -tagged `supply`, with the census as evidence. - -## (d) Repo constraints ledger - -Lanes MUST consult this before writing any finding. `policy-confirmed` verdicts -must cite the file:line below. - -1. **Workspace lints** (root `Cargo.toml`): `unsafe_code = "forbid"` under - `[workspace.lints.rust]`; `await_holding_lock`/`await_holding_refcell_ref` - `deny`; `disallowed_methods = "deny"` in the `[workspace.lints.clippy]` - table. **Discrepancy recorded**: the `clippy.toml` header says the level - "stands at `allow`" while the manifest table says `deny`; the manifest's - actual text is `deny` (Cargo.toml, `[workspace.lints.clippy]`), and the - Makefile `check-clippy` comment also says "allowed there". Record the - manifest text as authoritative; a finding may not assume the level is - advisory. Only 15 crates inherit the workspace table - (`[lints] workspace = true`); the other 79 carry local `[lints]` tables that - mirror `unsafe_code` + the three clippy lints (verified: every member manifest - carries a lints table or reference; none lacks one). - -2. **`clippy.toml` disallowed-methods list + replacement vocabulary**: tokio - timer/sync/fs/net, `AsyncFd` over non-blocking descriptors, - `d2b-core`'s `loader_worker` bounded-worker shape (one thread, bounded - `sync_channel`, no `try_send` growth), `Notify` armed before check + - `timeout`, `d2b-session-unix`'s `SeqpacketSocket` wrappers, - `d2bd::forward_rendezvous`'s `AsyncFd`. `parking_lot` is banned - outright (KD3) except the R4 worker boundary. A finding that proposes one of - these already-named replacements is `policy-confirmed` unless the site is on - a recorded exception list (per-site allows with sanctioned reasons; see 4). - -3. **Async gate**: `make check-async-gate` -> `cargo xtask check-async-gate` - scanner (`packages/xtask/src/async_gate.rs`); inventory - `packages/xtask/data/async-gate-inventory.json` (1,324 lines, 283 marker - sites at HEAD); source marker `// async-gate-allow: `. Markers are - deliberate exceptions - cite, do not re-flag. Scanner flags a - `lock()`/`read()`/`write()` method call inside an async context not followed - by `.await`. - -4. **Blocking census**: `make check-census` -> `cargo xtask blocking-census - --check packages/xtask/data/blocking-census-baseline.json` (per-crate - baseline; a covered crate above baseline fails). Per-site - `#[allow(clippy::disallowed_methods, reason = "...")]` allows are tracked by - `xtask provider-crate-policy`: sanctioned reasons are exactly - `"dedicated bounded worker per plan R4"`, `"synchronous path"`, - `"CLI-only path"`, `"cfg(test) helper"`; one module-level blanket allow - exemption exists (`packages/d2b-broker-composition/src/dependency_surface.rs`). - -5. **Provider crate policy** (`packages/xtask/src/provider_crate_policy.rs`): - README-only integration ratchet - exactly 18 crates (activation-nixos, - audio-pipewire, clipboard-wayland, credential-entra, - credential-managed-identity, credential-secret-service, device-gpu, - display-wayland, notification-desktop, process-minijail, process-systemd, - guest-azure-container-apps, guest-azure-virtual-machine, - guest-cloud-hypervisor, system-core, transport-azure-relay, transport-unix, - volume-virtiofs) whose `integration/*.rs` is a recorded scaffold rather than - an executable scenario. Required paths per provider crate: `src`, `tests`, - `integration`, `README.md`; nine required README sections. Also closes the - accepted Provider matrix, shared-driver placements, family-knowledge - ratchets, structural-knowledge ratchets, Bazel visibility, committed scope, - and generated provenance. Findings that would remove or rewrite a - ratcheted/policy-required path are `policy-confirmed` (cite - provider_crate_policy.rs line). - -6. **Refusal ledger**: `docs/explanation/over-engineering-audit-record.md` - (the prior 242-finding provider/runtime audit; tree state `515cbf610`). - Refused classes (finding on these is `policy-confirmed` unless it cites - changed evidence): - - policy-required scaffolds (`integration/*.rs` + README paths; finding 9 of - the policy family); - - declared-provider zero-caller artifacts (transport-unix, transport-vsock; - pinned by policy matrix, `nixos-modules/provider-runtime-contracts.nix`, - dossiers, committed schemas); - - pinned wire fields / Nix-pinned catalogs (display Wayland global catalog, - `debug_logging`); - - hand-written `Deserialize` impls that are live admission gates (qemu - guest/provider spec shapes); - - cross-crate refactors refused for ownership (supervisor blocking executor, - ZoneLink enrollment-machine merge, host/user driver merge); - - the toolkit's unconsumed framework half (B3 - declared-but-unwired); - - bus-side watch sink / `d2b-resource-api/src/watch.rs` (B1 kept half); - - `d2b-provider` agent dispatcher half (B2 kept half); - - audio `AudioMediator` defaults / `AudioReadiness` / `FakeAudioMediator`; - - supervisor generic systemd seam; tpm state-intent tokens and - `swtpm_argv` input fields; USBIP dossier-declared surface - (`state_machine.rs`, effect-port tests, `BindingLifecycle`); - - build/packaging consolidation findings (80-88) refused as repo-wide work. - "Not applied" rows (no refusal reason recorded; unchanged code): A4-A8, - B9, C1-C10, and the family gaps the record itself names. A finding on a - not-applied row is actionable but must cite the row id and confirm the site - still matches. - -7. **Wire and contract surfaces**: `docs/reference/error-codes.md` (generated - from `d2b_core::error::Error::all_kinds()`), `docs/reference/cli-contract.md`, - `docs/reference/manifest-schema.md`, `docs/reference/daemon-api.md`, - `tests/golden/**`, and every `src/generated/**` file -> any change here is - `needs-contract`. - -8. **`unsafe` exceptions (enumerated by seed at `6ebdd4cec`; never assume the - set)**: - - Files containing `unsafe` blocks/fns/impls (match counts): - `packages/d2b-broker/src/sys.rs` (103), - `packages/d2b-host-activation-helper/src/main.rs` (24), - `packages/d2b-broker/src/seccomp_compile_tests.rs` (5), - `packages/d2b-broker-fixture-syscall-surface/src/lib.rs` (3), - `packages/d2b-broker/tests/socket_activation.rs` (1), - `packages/d2b-broker/src/ops/disk_init.rs` (1), - `packages/d2b-resource-compiler/src/linux.rs` (1, `execveat` with SAFETY). - (`d2bd-runtime/src/typed_error.rs` matched only a doc-comment word - - false positive.) - - `#[allow(unsafe_code)]` sites: `d2b-broker/src/sys.rs` (52), - `d2b-broker/src/seccomp_compile_tests.rs` (3), - `d2b-broker/src/ops/disk_init.rs` (1), - `d2b-broker/tests/socket_activation.rs` (1). - - Manifest `unsafe_code` settings: `forbid` (most, incl. all provider - crates), `deny` (`d2b-broker`, `d2b-broker-composition`, - `d2b-broker-fixture-handlers`, `d2b-sk-frontend`), `allow` - (`d2b-broker-fixture-syscall-surface`), ABSENT (`d2b-audit`, - `d2b-host-activation-helper`, `d2b-resource-compiler`, `d2b-telemetry`, - `d2b-zone-routing`; of these, only host-activation-helper (24 sites) and - resource-compiler (1) actually contain `unsafe`; the other three contain - none). Crate-level `#![forbid(unsafe_code)]` appears in several `lib.rs`. - - `// SAFETY:` comments: 35 across the workspace. A block without one is a - finding (the skill's mechanical rule). - -9. **Toolchain**: `rust-toolchain.toml` pins channel `1.97.0` (stable, - components rustfmt+clippy); all 94 member manifests are edition 2024 - (verified). Lens advice must be edition-legal (let-chains and if-let chains - are available; `#[unsafe(no_mangle)]`/`unsafe extern` forms required). - -10. **Repo prose rules binding this report**: ASCII `-` only in every document - written (including the ASCII hyphen prohibition list in AGENTS.md); no - tool/model/agent attribution anywhere; finding ids (`RS-####`, and lane-local - `#`) are report-local - remediation later must not copy them into - source comments, changelogs, commit messages, or PR bodies. - -11. **Authoritative context, not audit targets**: `docs/explanation/over-engineering-audit-record.md`, - `docs/adr/**`, `docs/specs/**` dossiers, `docs/residual-review-findings/**`. - They may be cited and must not be flagged for change. - -12. **Security invariants**: the Don'ts list in `AGENTS.md` plus - `docs/contributing/critical-subsystems.md`. A finding that would violate a - Don't is `policy-confirmed` and must cite the Don't (e.g. no per-Guest - systemd units; no host-state mutation outside ownership markers; no broad - chmod/chown/setfacl/`/run/d2b` sweeps; no new storage/ACL/lock ownership - outside ADR 0034's single-repair-owner rule; no d2b cgroup mutation outside - delegation). - -## (e) Per-crate applicability matrix - -Seed-hit counts per crate x lens, measured 2026-09-24 at `6ebdd4cec`. Basis: -matching lines summed across the lens's seeds over `packages//src/**` -excluding `src/generated/**` (the `test` lens adds `tests/**`). Cell `0` = all -seeds zero for that crate (N/A candidate; the card's applicability criteria -decide). Cell `X1`: `supply` is a workspace-level lens owned by lane X1; it is -never applicable per crate. Hit counts are raw match mass, not finding counts; -noisy seeds (`own` `.clone()`, `docs` `-> Result<`) are expected to dominate and -are filtered by lane reading. - -| crate | idiom | own | type | api | err | serde | obs | docs | perf | conc | async | unsafe | ffi | macro | test | supply | -|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| -| d2b | 15 | 500 | 46 | 117 | 240 | 194 | 33 | 335 | 319 | 44 | 77 | 4 | 0 | 0 | 1076 | X1 | -| d2b-audit | 14 | 166 | 6 | 149 | 204 | 84 | 5 | 167 | 58 | 18 | 0 | 1 | 0 | 1 | 206 | X1 | -| d2b-broker | 83 | 2689 | 69 | 625 | 2381 | 332 | 116 | 1162 | 1577 | 144 | 2123 | 283 | 79 | 6 | 2959 | X1 | -| d2b-broker-composition | 2 | 13 | 0 | 24 | 18 | 1 | 16 | 31 | 24 | 0 | 17 | 1 | 0 | 8 | 79 | X1 | -| d2b-broker-fixture-handlers | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | X1 | -| d2b-broker-fixture-syscall-surface | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 4 | 1 | 0 | 0 | X1 | -| d2b-bus | 23 | 522 | 7 | 325 | 1376 | 2 | 15 | 470 | 169 | 127 | 661 | 0 | 0 | 1 | 712 | X1 | -| d2b-contracts | 6 | 146 | 16 | 552 | 209 | 378 | 0 | 636 | 107 | 0 | 0 | 0 | 0 | 7 | 467 | X1 | -| d2b-contracts-broker | 1 | 82 | 5 | 202 | 143 | 476 | 0 | 210 | 80 | 0 | 0 | 0 | 0 | 0 | 178 | X1 | -| d2b-contracts-control | 0 | 94 | 22 | 241 | 92 | 660 | 0 | 244 | 57 | 0 | 0 | 0 | 0 | 0 | 169 | X1 | -| d2b-contracts-provider | 9 | 142 | 29 | 591 | 404 | 213 | 1 | 720 | 75 | 7 | 3 | 0 | 0 | 1 | 475 | X1 | -| d2b-contracts-resource | 15 | 216 | 30 | 1065 | 585 | 774 | 0 | 1277 | 266 | 2 | 0 | 0 | 0 | 8 | 644 | X1 | -| d2b-contracts-zone-session | 5 | 127 | 19 | 673 | 339 | 355 | 0 | 822 | 127 | 0 | 0 | 0 | 0 | 5 | 422 | X1 | -| d2b-controller-toolkit | 0 | 0 | 0 | 22 | 0 | 0 | 0 | 18 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | X1 | -| d2b-core | 19 | 505 | 11 | 507 | 297 | 552 | 1 | 520 | 383 | 4 | 14 | 1 | 0 | 1 | 540 | X1 | -| d2b-core-controller | 5 | 441 | 11 | 512 | 468 | 49 | 0 | 681 | 58 | 36 | 87 | 0 | 0 | 0 | 395 | X1 | -| d2b-host | 18 | 404 | 16 | 306 | 300 | 125 | 28 | 405 | 295 | 2 | 318 | 19 | 3 | 1 | 550 | X1 | -| d2b-host-activation-helper | 0 | 1 | 0 | 0 | 14 | 0 | 7 | 2 | 5 | 0 | 0 | 26 | 7 | 0 | 7 | X1 | -| d2b-process-conformance | 0 | 58 | 4 | 227 | 147 | 24 | 0 | 264 | 14 | 1 | 8 | 0 | 0 | 1 | 158 | X1 | -| d2b-provider | 2 | 26 | 0 | 170 | 16 | 0 | 0 | 198 | 5 | 34 | 41 | 0 | 0 | 0 | 100 | X1 | -| d2b-provider-activation-nixos | 0 | 59 | 1 | 95 | 64 | 9 | 17 | 111 | 35 | 10 | 123 | 0 | 0 | 0 | 198 | X1 | -| d2b-provider-audio-binding | 1 | 1 | 0 | 14 | 0 | 0 | 0 | 16 | 0 | 0 | 0 | 0 | 0 | 0 | 20 | X1 | -| d2b-provider-audio-pipewire | 1 | 8 | 3 | 100 | 7 | 10 | 1 | 124 | 4 | 4 | 2 | 2 | 0 | 0 | 174 | X1 | -| d2b-provider-audio-service | 0 | 0 | 0 | 8 | 0 | 0 | 0 | 9 | 2 | 0 | 0 | 0 | 0 | 0 | 19 | X1 | -| d2b-provider-clipboard-wayland | 28 | 430 | 10 | 391 | 269 | 97 | 178 | 514 | 229 | 30 | 0 | 7 | 0 | 0 | 492 | X1 | -| d2b-provider-command | 0 | 6 | 0 | 27 | 19 | 10 | 0 | 30 | 1 | 0 | 0 | 0 | 0 | 0 | 14 | X1 | -| d2b-provider-config-nixos | 1 | 30 | 6 | 63 | 16 | 38 | 25 | 90 | 11 | 1 | 8 | 2 | 0 | 0 | 45 | X1 | -| d2b-provider-credential | 0 | 61 | 2 | 85 | 62 | 14 | 2 | 102 | 24 | 15 | 137 | 0 | 0 | 0 | 128 | X1 | -| d2b-provider-credential-entra | 0 | 43 | 2 | 73 | 20 | 0 | 35 | 120 | 6 | 5 | 101 | 1 | 0 | 0 | 226 | X1 | -| d2b-provider-credential-managed-identity | 0 | 52 | 1 | 88 | 23 | 0 | 26 | 129 | 7 | 4 | 55 | 1 | 0 | 0 | 213 | X1 | -| d2b-provider-credential-secret-service | 0 | 84 | 2 | 62 | 57 | 0 | 32 | 135 | 18 | 30 | 121 | 1 | 0 | 0 | 196 | X1 | -| d2b-provider-device | 0 | 3 | 0 | 31 | 0 | 1 | 0 | 35 | 1 | 5 | 16 | 0 | 0 | 0 | 9 | X1 | -| d2b-provider-device-gpu | 2 | 51 | 1 | 142 | 22 | 29 | 17 | 166 | 9 | 2 | 0 | 2 | 0 | 0 | 120 | X1 | -| d2b-provider-device-security-key | 1 | 55 | 1 | 187 | 68 | 9 | 21 | 213 | 11 | 16 | 77 | 1 | 0 | 0 | 151 | X1 | -| d2b-provider-device-tpm | 1 | 71 | 2 | 91 | 83 | 24 | 11 | 125 | 29 | 2 | 77 | 1 | 0 | 0 | 155 | X1 | -| d2b-provider-device-usbip | 1 | 104 | 5 | 313 | 22 | 26 | 45 | 424 | 9 | 11 | 22 | 0 | 0 | 0 | 229 | X1 | -| d2b-provider-display-wayland | 27 | 596 | 7 | 423 | 166 | 32 | 91 | 476 | 138 | 0 | 0 | 8 | 4 | 1 | 548 | X1 | -| d2b-provider-emergency-policy | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | -| d2b-provider-endpoint | 3 | 23 | 1 | 78 | 40 | 44 | 0 | 97 | 14 | 13 | 102 | 0 | 0 | 0 | 81 | X1 | -| d2b-provider-guest | 6 | 158 | 6 | 130 | 135 | 55 | 13 | 213 | 54 | 34 | 290 | 0 | 0 | 0 | 152 | X1 | -| d2b-provider-guest-azure-container-apps | 0 | 44 | 0 | 94 | 4 | 31 | 15 | 128 | 0 | 0 | 51 | 1 | 0 | 1 | 53 | X1 | -| d2b-provider-guest-azure-virtual-machine | 2 | 18 | 1 | 77 | 1 | 21 | 27 | 106 | 0 | 0 | 72 | 1 | 0 | 0 | 106 | X1 | -| d2b-provider-guest-cloud-hypervisor | 8 | 158 | 11 | 361 | 121 | 57 | 53 | 453 | 22 | 0 | 127 | 1 | 0 | 0 | 273 | X1 | -| d2b-provider-guest-qemu-media | 5 | 44 | 5 | 140 | 15 | 63 | 24 | 156 | 15 | 0 | 0 | 1 | 0 | 0 | 140 | X1 | -| d2b-provider-host | 1 | 32 | 4 | 47 | 40 | 4 | 0 | 64 | 16 | 18 | 145 | 0 | 0 | 0 | 95 | X1 | -| d2b-provider-network-local | 11 | 206 | 15 | 328 | 171 | 29 | 4 | 453 | 125 | 8 | 134 | 0 | 0 | 1 | 347 | X1 | -| d2b-provider-notification-desktop | 5 | 108 | 5 | 245 | 107 | 19 | 4 | 341 | 45 | 1 | 0 | 1 | 0 | 0 | 172 | X1 | -| d2b-provider-observability-otel | 5 | 52 | 3 | 128 | 66 | 13 | 3 | 131 | 12 | 20 | 0 | 4 | 0 | 0 | 158 | X1 | -| d2b-provider-operation | 1 | 1 | 0 | 68 | 17 | 49 | 0 | 72 | 0 | 0 | 0 | 0 | 0 | 0 | 20 | X1 | -| d2b-provider-process | 2 | 274 | 7 | 135 | 185 | 18 | 8 | 250 | 129 | 36 | 444 | 1 | 0 | 0 | 325 | X1 | -| d2b-provider-process-minijail | 0 | 2 | 1 | 15 | 2 | 0 | 1 | 22 | 1 | 0 | 19 | 0 | 0 | 0 | 74 | X1 | -| d2b-provider-process-systemd | 3 | 51 | 4 | 78 | 34 | 10 | 4 | 100 | 37 | 0 | 90 | 0 | 0 | 0 | 154 | X1 | -| d2b-provider-provider | 2 | 24 | 1 | 42 | 54 | 15 | 5 | 56 | 15 | 11 | 72 | 0 | 0 | 0 | 74 | X1 | -| d2b-provider-quota | 0 | 0 | 0 | 9 | 0 | 2 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | -| d2b-provider-resource-export | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | -| d2b-provider-resource-import | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | -| d2b-provider-role | 0 | 0 | 0 | 11 | 5 | 0 | 0 | 9 | 4 | 1 | 0 | 0 | 0 | 0 | 11 | X1 | -| d2b-provider-role-binding | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | X1 | -| d2b-provider-seccomp-profile | 0 | 2 | 0 | 20 | 10 | 30 | 0 | 21 | 1 | 0 | 0 | 0 | 0 | 0 | 9 | X1 | -| d2b-provider-shell-pool | 0 | 0 | 0 | 10 | 0 | 0 | 0 | 11 | 1 | 0 | 0 | 0 | 0 | 0 | 16 | X1 | -| d2b-provider-shell-session | 0 | 1 | 0 | 10 | 0 | 2 | 0 | 11 | 1 | 0 | 0 | 0 | 0 | 0 | 29 | X1 | -| d2b-provider-shell-terminal | 0 | 40 | 7 | 162 | 5 | 0 | 2 | 229 | 10 | 3 | 2 | 0 | 0 | 0 | 142 | X1 | -| d2b-provider-supervisor | 4 | 138 | 1 | 32 | 144 | 24 | 3 | 130 | 40 | 75 | 42 | 0 | 0 | 1 | 128 | X1 | -| d2b-provider-system-core | 0 | 7 | 0 | 74 | 11 | 11 | 2 | 83 | 0 | 1 | 15 | 0 | 0 | 0 | 83 | X1 | -| d2b-provider-telemetry-binding | 1 | 24 | 2 | 22 | 22 | 7 | 0 | 37 | 11 | 4 | 119 | 0 | 0 | 0 | 70 | X1 | -| d2b-provider-telemetry-service | 1 | 15 | 2 | 18 | 20 | 3 | 0 | 30 | 10 | 4 | 83 | 0 | 0 | 0 | 52 | X1 | -| d2b-provider-test-controller | 0 | 1 | 0 | 0 | 10 | 0 | 10 | 4 | 0 | 0 | 14 | 1 | 0 | 0 | 11 | X1 | -| d2b-provider-toolkit | 12 | 226 | 13 | 565 | 258 | 41 | 14 | 720 | 77 | 81 | 325 | 0 | 0 | 0 | 472 | X1 | -| d2b-provider-transport-azure-relay | 2 | 46 | 3 | 148 | 87 | 9 | 25 | 213 | 24 | 15 | 133 | 1 | 0 | 0 | 199 | X1 | -| d2b-provider-transport-unix | 2 | 0 | 2 | 50 | 3 | 0 | 9 | 48 | 4 | 1 | 1 | 0 | 0 | 0 | 26 | X1 | -| d2b-provider-transport-vsock | 3 | 12 | 0 | 116 | 16 | 6 | 13 | 144 | 3 | 24 | 112 | 2 | 0 | 0 | 135 | X1 | -| d2b-provider-user | 0 | 37 | 2 | 39 | 49 | 5 | 1 | 53 | 11 | 19 | 112 | 0 | 0 | 0 | 113 | X1 | -| d2b-provider-volume | 0 | 63 | 1 | 29 | 44 | 8 | 0 | 55 | 13 | 21 | 114 | 0 | 0 | 0 | 85 | X1 | -| d2b-provider-volume-binding | 0 | 81 | 0 | 36 | 76 | 24 | 1 | 58 | 24 | 24 | 141 | 0 | 0 | 0 | 134 | X1 | -| d2b-provider-volume-local | 8 | 87 | 16 | 319 | 121 | 90 | 23 | 459 | 45 | 111 | 60 | 22 | 0 | 0 | 369 | X1 | -| d2b-provider-volume-virtiofs | 0 | 13 | 1 | 69 | 20 | 12 | 15 | 79 | 12 | 4 | 29 | 0 | 0 | 0 | 128 | X1 | -| d2b-provider-wayland-policy | 0 | 49 | 3 | 81 | 46 | 23 | 0 | 134 | 15 | 11 | 98 | 0 | 0 | 0 | 100 | X1 | -| d2b-provider-wayland-session | 1 | 4 | 0 | 15 | 0 | 0 | 0 | 17 | 0 | 0 | 0 | 0 | 0 | 0 | 26 | X1 | -| d2b-provider-zone | 0 | 2 | 0 | 13 | 1 | 0 | 0 | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 17 | X1 | -| d2b-provider-zone-link | 5 | 53 | 1 | 138 | 115 | 4 | 0 | 152 | 6 | 3 | 0 | 0 | 0 | 0 | 209 | X1 | -| d2b-resource-api | 10 | 408 | 4 | 134 | 685 | 40 | 38 | 232 | 147 | 40 | 340 | 0 | 0 | 4 | 441 | X1 | -| d2b-resource-client | 1 | 76 | 2 | 207 | 99 | 4 | 0 | 244 | 31 | 53 | 101 | 0 | 0 | 0 | 178 | X1 | -| d2b-resource-compiler | 12 | 113 | 14 | 67 | 51 | 27 | 1 | 118 | 157 | 5 | 0 | 8 | 5 | 0 | 148 | X1 | -| d2b-resource-runtime | 22 | 448 | 2 | 401 | 559 | 8 | 1 | 592 | 107 | 209 | 1259 | 0 | 0 | 0 | 707 | X1 | -| d2b-resource-types | 0 | 2 | 0 | 97 | 3 | 0 | 0 | 85 | 1 | 0 | 3 | 0 | 0 | 0 | 46 | X1 | -| d2b-session | 8 | 106 | 11 | 317 | 168 | 0 | 19 | 536 | 35 | 72 | 505 | 1 | 0 | 3 | 383 | X1 | -| d2b-session-unix | 12 | 23 | 10 | 157 | 66 | 0 | 4 | 251 | 25 | 34 | 130 | 5 | 0 | 1 | 214 | X1 | -| d2b-sk-frontend | 1 | 6 | 0 | 25 | 2 | 0 | 2 | 29 | 18 | 2 | 39 | 3 | 0 | 0 | 38 | X1 | -| d2b-telemetry | 0 | 23 | 3 | 94 | 85 | 8 | 0 | 107 | 10 | 11 | 0 | 1 | 0 | 0 | 114 | X1 | -| d2b-unsafe-local-helper | 5 | 77 | 4 | 39 | 120 | 22 | 10 | 103 | 36 | 20 | 0 | 2 | 0 | 0 | 112 | X1 | -| d2b-zone-routing | 11 | 147 | 3 | 208 | 225 | 0 | 0 | 248 | 36 | 38 | 6 | 0 | 0 | 1 | 528 | X1 | -| d2bd | 82 | 3416 | 25 | 316 | 2827 | 471 | 515 | 1160 | 1035 | 400 | 2850 | 22 | 0 | 0 | 2192 | X1 | -| d2bd-runtime | 58 | 1322 | 44 | 1031 | 1261 | 261 | 153 | 1356 | 576 | 317 | 583 | 11 | 0 | 0 | 1543 | X1 | -| xtask | 166 | 1059 | 81 | 457 | 926 | 301 | 75 | 774 | 1157 | 50 | 99 | 4 | 1 | 25 | 1819 | X1 | - -Interpretation rules: - -- A cell is `0` only when every seed returned zero matching lines; the lane then - states N/A (with the criteria note) or clean, per the card. -- A partition lane's share of a crate's counts is its assigned files/ranges; - the sum of parts approximates the crate cell (split files divide their - matches). -- Cells are raw match mass; a lane's own run over its assigned scope is - authoritative for its coverage lines. - -## (f) Lane map + partition rule: published part map - -Partitions below are final (computed mechanically; LPT packing, cap -`ceil(LOC/k) x 1.2`, units whole except the recorded item-range splits). Lanes -follow this map; no renegotiation. Each part lane's header records the part -(`part k/n`), its file list, and - for split files - the line ranges. - -Item-range splits (recorded boundaries; 1-based inclusive): -- `d2bd/src/composition.rs` -> `1-10070` | `10071-20142` | `20143-30213`. -- `d2b-broker/src/runtime.rs` -> `1-10300` | `10301-20603`. -- `xtask/src/provider_crate_policy.rs` -> `1-5353` | `5354-11075`. - -|part id|scope (files / dirs / ranges)| -|---|---| -|`d2bd-p1`|`src/resource_runtime.rs`| -|`d2bd-p2`|`src/composition.rs:10071-20142`, `src/audio_host_controller.rs`| -|`d2bd-p3`|`src/composition.rs:20143-30213`, `src/zone_enrollment.rs`| -|`d2bd-p4`|`src/composition.rs:1-10070`, `src/plane_port.rs`| -|`d2bd-p5`|`src/interaction_composition.rs`, `src/foundation_seed.rs`, `src/principal_allocation.rs`, `src/provider_shutdown.rs`, `src/process_resource_runtime.rs`| -|`d2bd-p6`|`src/resource_plane_v3.rs`, `src/provider_lifecycle.rs`, `src/resource_runtime/**`, `src/credential_resource_runtime.rs`| -|`d2bd-p7`|`src/process_provider_runtime.rs`, `src/provider_effects.rs`, `src/effect_service_actors.rs`, `src/main.rs`, `src/guest_target_session.rs`, `src/lib.rs`| -|`d2bd-p8`|`src/forward_rendezvous.rs`, `src/shared_provider_effects.rs`, `src/provider_registry.rs`, `src/audio_dispatch.rs`| -|`d2b-broker-p1`|`src/runtime.rs:10301-20603`, `src/ops/usbip_lock.rs`, `src/seccomp_compile_tests.rs`| -|`d2b-broker-p2`|`src/runtime.rs:1-10300`, `src/ops/gpu.rs`, `src/ops/modprobe.rs`| -|`d2b-broker-p3`|`src/live_handlers.rs`, `src/state_cells.rs`, `src/ops/store_sync.rs`, `src/ops/usbip_host.rs`, `src/ops/storage_contract.rs`, `src/ops/pidfd.rs`, `src/ops/sysctl.rs`, `src/ops/mod.rs`| -|`d2b-broker-p4`|`src/audit.rs`, `src/ops/tap.rs`, `src/ops/disk_init.rs`, `src/ops/route.rs`, `src/ops/store_sync_audit.rs`, `src/ops/spawn_runner.rs`, `src/ops/host_generation_handoff.rs`, `src/ops/store_sync_export.rs`| -|`d2b-broker-p5`|`src/sys.rs`, `src/ops/swtpm_dir.rs`, `src/ops/nft.rs`, `src/forwarding.rs`, `src/ops/cgroup.rs`, `src/ops/device.rs`, `src/ops/hosts.rs`, `src/fd_passing.rs`, `src/lib.rs`| -|`d2b-broker-p6`|`src/envelope/**`, `src/ops/exec_reconcile.rs`, `src/ops/audit_op.rs`, `src/ops/store_view_posture.rs`, `src/ops/device_worker.rs`, `src/ops/nm.rs`, `src/ops/security_key.rs`, `src/ops/store_view_farm.rs`, `src/ops/usbip_firewall.rs`| -|`d2b-broker-p7`|`src/ops/media.rs`, `src/kernel_ops.rs`, `src/ops/network.rs`, `src/catalog.rs`, `src/ops/state_dir.rs`, `src/ops/state-posture-contract.json`, `src/protocol.rs`, `src/bootstrap.rs`| -|`xtask-p1`|`src/provider_crate_policy.rs:5354-11075`, `src/main.rs`, `src/gen_layer_catalogs.rs`, `src/provider_registration_authority.rs`, `src/service_catalog.rs`| -|`xtask-p2`|`src/provider_crate_policy.rs:1-5353`, `src/gen_broker_operations.rs`, `src/delivery/eligibility.rs`, `src/diagnostic_redaction.rs`, `src/delivery/history_proof.rs`| -|`xtask-p3`|`src/delivery/recovery.rs`, `src/delivery/command.rs`, `src/resource_type_authority.rs`, `src/delivery/snapshot.rs`, `src/provider_packaging.rs`, `src/semantic_service_schemas.rs`, `src/deadcode.rs`, `src/authority_common.rs`, `src/bin/**`| -|`xtask-p4`|`src/delivery/storage.rs`, `src/production_closure.rs`, `src/zone_schema.rs`, `src/delivery/model.rs`, `src/operation_row_authority.rs`, `src/inventory.rs`, `src/delivery/mod.rs`| -|`xtask-p5`|`src/changelog.rs`, `src/async_gate.rs`, `src/blocking_census.rs`, `src/delivery/evidence.rs`, `src/nix_inventories.rs`, `src/bazel_evidence.rs`, `src/delivery/seal.rs`| -|`d2bd-runtime-p1`|`src/supervisor/**`, `src/typed_error.rs`, `src/autostart.rs`, `src/component_session_vsock.rs`, `src/daemon_config.rs`, `src/resource_api.rs`, `src/zone_authority.rs`, `src/shell_backend.rs`, `src/broker_transport.rs`, `src/public_read_model.rs`, `src/vm_start_support.rs`, `src/json_io.rs`| -|`d2bd-runtime-p2`|`src/resource_runtime_support.rs`, `src/guest_resource_runtime.rs`, `src/workload_dispatch.rs`, `src/runtime_process.rs`, `src/workload_target_index.rs`, `src/wire.rs`, `src/ssh_host_key_preflight.rs`, `src/public_projection.rs`, `src/resource_operator_activation.rs`, `src/exec_detached.rs`, `src/admission.rs`, `src/daemon_client.rs`, `src/runtime_capability.rs`| -|`d2bd-runtime-p3`|`src/exec_session.rs`, `src/unsafe_local_helper.rs`, `src/metrics.rs`, `src/authority_persistence.rs`, `src/readiness.rs`, `src/otel_host_bridge_readiness.rs`, `src/ownership_preflight.rs`, `src/unix_transport.rs`, `src/exec_session_real.rs`, `src/terminal_session.rs`, `src/pidfs_probe.rs`, `src/lib.rs`, `src/runtime_util.rs`| -|`d2bd-runtime-p4`|`src/target_runtime.rs`, `src/daemon_audit.rs`, `src/guest_mode.rs`, `src/kernel_module_check.rs`, `src/console_session.rs`, `src/guest_component_session.rs`, `src/ch_stats.rs`, `src/concurrency.rs`, `src/daemon_version.rs`, `src/ch_api.rs`, `src/typed_shell_targets.rs`, `src/wire_response_helpers.rs`, `src/exec_support.rs`| -|`d2b-p1`|`src/context.rs`, `src/activation.rs`, `src/zone_support_bundle.rs`, `src/share.rs`, `src/guest.rs`, `src/zone.rs`, `src/host_generation.rs`, `src/runtime.rs`, `src/main.rs`| -|`d2b-p2`|`src/doctor.rs`, `src/zone_audit.rs`, `src/resource.rs`, `src/host_validate.rs`, `src/shell.rs`, `src/host.rs`, `src/lib.rs`, `src/complete.rs`| -|`d2b-p3`|`src/exec_client.rs`, `src/dispatch.rs`, `src/debug.rs`, `src/zone_doctor.rs`, `src/exec.rs`, `src/endpoint.rs`, `src/provider.rs`, `src/terminal_client.rs`| -|`d2b-bus-p1`|`src/router.rs`, `src/authorization.rs`, `src/registry.rs`, `src/metrics.rs`| -|`d2b-bus-p2`|`src/session/**`, `src/session_seam_tests.rs`, `src/streams.rs`, `src/operations.rs`, `src/wire.rs`, `src/lib.rs`| -|`d2b-contracts-resource-p1`|`src/v3/network.rs`, `src/v3/resource_schema.rs`, `src/v3/operations/**`, `src/v3/device.rs`, `src/v3/resource_status.rs`, `src/v3/volume_state.rs`, `src/v3/payload_schema.rs`, `src/v3/error.rs`, `src/v3/host.rs`, `src/v3/bridge.rs`, `src/v3/limits.rs`| -|`d2b-contracts-resource-p2`|`src/v3/volume.rs`, `src/v3/process.rs`, `src/v3/identity.rs`, `src/v3/execution_policy.rs`, `src/v3/resource.rs`, `src/v3/storage.rs`, `src/v3/volume_binding.rs`, `src/v3/activation_nixos.rs`, `src/v3/user.rs`, `src/v3/mod.rs`, `src/v3/artifact.rs`, `src/lib.rs`| -|`d2b-core-p1`|`src/bundle_resolver.rs`| -|`d2b-core-p2`|`src/privileges.rs`, `src/host.rs`, `src/manifest_v04.rs`, `src/storage.rs`, `src/test_support.rs`, `src/console_ring.rs`, `src/allocator_config.rs`, `src/processes.rs`, `src/storage_lifecycle.rs`, `src/provider_artifact.rs`, `src/host_w3.rs`, `src/static_invariants.rs`, `src/sync.rs`, `src/runtime.rs`, `src/base64_codec.rs`, `src/sandbox_profile.rs`, `src/kernel_seat.rs`, `src/loader_worker.rs`, `src/site.rs`, `src/provider_capabilities.rs`, `src/bundle.rs`, `src/host_generation.rs`, `src/closures.rs`, `src/lib.rs`, `src/unsafe_local_workloads.rs`, `src/configured_argv.rs`, `src/contract_id.rs`, `src/error.rs`, `src/privileges_w3.rs`, `src/workload_identity.rs`| -|`d2b-provider-toolkit-p1`|`src/base/**`, `src/plane/**`, `src/operations/**`, `src/audit/**`, `src/declaration/**`, `src/bin/**`| -|`d2b-provider-toolkit-p2`|`src/testing/**`, `src/server/**`, `src/shared_provider.rs`, `src/credential.rs`, `src/service.rs`, `src/lib.rs`| -|`d2b-provider-display-wayland-p1`|`src/wayland_proxy/**`| -|`d2b-provider-display-wayland-p2`|`src/controller.rs`, `src/runtime.rs`, `src/process.rs`, `src/bin/**`, `src/spec.rs`, `src/policy.rs`, `src/session_children.rs`, `src/principal.rs`, `src/lib.rs`| -|`d2b-resource-runtime-p1`|`src/manager.rs`, `src/resource.rs`, `src/error.rs`, `src/provider.rs`, `src/metadata.rs`, `src/revision.rs`, `src/lib.rs`, `src/schema.rs`| -|`d2b-resource-runtime-p2`|`src/context.rs`, `src/target.rs`, `src/guest_target.rs`, `src/spec_store.rs`, `src/watch.rs`, `src/driver.rs`, `src/identity.rs`| -|`d2b-contracts-provider-p1`|`src/v3/provider.rs`, `src/v3/credential/**`, `src/v3/credential.rs`, `src/v3/provider_registry.rs`, `src/v3/mod.rs`, `src/lib.rs`| -|`d2b-contracts-provider-p2`|`src/v3/semantic_services/**`, `src/v3/credential_controller.rs`, `src/v3/telemetry_policy.rs`, `src/v3/telemetry_frame.rs`| -|`d2b-session-p1`|`src/driver.rs`, `src/server.rs`, `src/handshake.rs`, `src/operation.rs`, `src/streams.rs`, `src/scheduler.rs`, `src/cancellation.rs`, `src/fragmentation.rs`, `src/attachment.rs`, `src/metrics.rs`, `src/typed_stream.rs`| -|`d2b-session-p2`|`src/admission.rs`, `src/engine.rs`, `src/error.rs`, `src/client.rs`, `src/transport.rs`, `src/lifecycle.rs`, `src/record.rs`, `src/bootstrap.rs`, `src/deadline.rs`, `src/lib.rs`| -|`d2b-resource-api-p1`|`src/service.rs`, `src/adapter.rs`, `src/manager_backend.rs`, `src/client.rs`, `src/store.rs`, `src/watch.rs`| -|`d2b-resource-api-p2`|`src/authz.rs`, `src/manager_backend/**`, `src/admission.rs`, `src/error.rs`, `src/identity.rs`, `src/lib.rs`| -|`d2b-core-controller-p1`|`src/controller_assignment.rs`, `src/binding_children.rs`, `src/coordinator.rs`, `src/main.rs`, `src/controllers.rs`, `src/lib.rs`| -|`d2b-core-controller-p2`|`src/authority.rs`, `src/owner_reconcile.rs`, `src/authority_persistence.rs`, `src/migration.rs`| -|`d2b-provider-clipboard-wayland-p1`|`src/bin/**`, `src/fd.rs`, `src/runtime.rs`, `src/audit.rs`, `src/policy.rs`, `src/lib.rs`| -|`d2b-provider-clipboard-wayland-p2`|`src/clipd_host/**`, `src/service/**`, `src/history.rs`, `src/controller/**`, `src/picker.rs`| -|`d2b-contracts-zone-session-p1`|`src/v3/component_session.rs`, `src/v3/role.rs`, `src/v3/resource_export.rs`, `src/v3/zone_link.rs`, `src/v3/resource_import.rs`, `src/v3/mod.rs`, `src/lib.rs`| -|`d2b-contracts-zone-session-p2`|`src/v3/zone_routing.rs`, `src/v3/resource_bundle.rs`, `src/v3/zone_session.rs`, `src/v3/zone.rs`, `src/v3/role_binding.rs`, `src/v3/services.rs`, `src/v3/emergency_policy.rs`| - -Single-part lanes (`d2b-host`, `d2b-provider-*`, ...): audit the whole crate -under `src/**` (excl. `src/generated/**`) plus `tests/**` for the `test` lens. - -Partition notes: `d2bd/src/composition.rs` and `d2b-broker/src/runtime.rs` and -`xtask/src/provider_crate_policy.rs` are item-range splits of single oversized -files; their parts still count as one lane each (no `a`/`b` splits were needed). -Directories named with `/**` mean the whole subtree (e.g. `src/ops/**`), not the -bare file. `d2b-broker-p1`'s `state-posture-contract.json` entry under `d2b-broker-p7` -is a non-Rust data file inside `src/ops/`; skip it for seed runs. diff --git a/docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md b/docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md deleted file mode 100644 index 8fefd67f9..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/VERIFICATION.md +++ /dev/null @@ -1,553 +0,0 @@ -# VERIFICATION - rust skills audit (plan Step 5, independent) - -Baseline: branch `v3` @ `6ebdd4cec` - Date: 2026-09-24 - Verifier: separate -clean-context agent (no consolidation state trusted; every number recomputed). - -**Method.** All mechanical checks run from the repo root with -`python3 .scratch/rust-skills-audit-verify.py` (read-only; imports -`.scratch/parse_lanes.py` and `.scratch/consolidate.py` for parsing and -consolidation, recomputing their outputs rather than trusting the report). -The script parses `U1-constraints.md` sections (a) and (e), the root -`Cargo.toml` member list, all 110 lane files, and `README.md` sections 1, 2, -4, 5, 6; it resolves every anchor against the working tree at the baseline OID -and prints each cited line's content. Anchor plausibility (the cited line -range relates to the claim) was judged by the verifier from the printed line -contents for all 568 checked anchors, with direct reads for every `sev=high` -anchor and for the ambiguous basename resolutions. The check script output -below is abbreviated; the full transcript is reproducible by re-running the -script. - -## check 1: lane completeness - pass - -Command: `python3 .scratch/rust-skills-audit-verify.py` (check 1 section). - -``` -expected lane ids: 110 actual lane files: 110 -missing: [] -extra: [] -check 1: PASS -``` - -The expected set is expanded from the U1 section (a) lane map (`d2bd-p1`..`-p8` -style ranges, single-part rows, `tail-1`..`tail-6`) plus the three cross-cutting -lanes `X1-supply-chain`, `X2-generated-boundary`, `X3-cross-crate-duplication`. -Every mapped lane id has exactly one file in `lane/`; no extra files. 110 = 107 -crate lanes + 3 cross lanes, as the report states. - -## check 2: crate coverage - pass - -``` -members: 94 covered crates: 94 -crates with >1 owner group: [] -uncovered: [] -stray (not members): [] -partition summary: 17 multi-part crates, 50 whole-crate lanes, 27 tail crates (94 = 94 members) -check 2: PASS -``` - -All 94 `packages/*` members of the root `Cargo.toml` appear exactly once across -the lane files (tail lanes counted per `## ` section; part lanes counted -per crate). No member is uncovered, no lane covers a non-member, and no crate is -claimed by two different lane owners. The partition matches the README method -paragraph: 51 part lanes over 17 crates, 50 whole-crate lanes, 6 tail lanes -covering 27 crates (17 + 50 + 27 = 94). - -## check 3: schema conformance - pass - -Command: `python3 .scratch/rust-skills-audit-verify.py` (check 3 section), -which imports `.scratch/parse_lanes.py` and parses all 110 lane files. - -``` -lane files parsed: 110 findings: 1022 -schema violations: 0 -findings missing evidence: [] -findings missing anchors: [] -check 3: PASS -``` - -Zero violations of the lane-file grammar (finding rows matching the exact field -pattern `- # sev=... blast=... effort=... verdict=... - what - fix: ... - [path:line, ...]` -with a following `evidence:` line and >=1 well-formed `[path:line]` anchor; -local id matches lane id; coverage lines well-formed). Every one of the 1022 -raw finding rows carries an evidence line and at least one anchor. - -## check 4: coverage matrix completeness - pass - -``` -matrix rows: 94 (expect 94) cols: 16 -cells: N/A=449 clean=504 numeric=461 X1=90 -bad N/A cells (u1!=0 or findings!=0): [] -bad clean cells (u1==0 or findings!=0): [] -bad numeric cells (count mismatch): [] -zero-u1 numeric set == README-named 8 cells: True -check 4: PASS -``` - -README section 5 has all 94 crate rows x 16 lens columns. Every `N/A` cell -(449 of them) corresponds to a zero seed-hit row for that crate in U1 section -(e) AND zero findings; every `clean` cell has nonzero U1 seed mass and zero -findings; every numeric cell equals the consolidated finding count for that -(crate, lens). The eight numeric cells whose U1 pre-scan row is zero -(`d2b-controller-toolkit`/type, `d2b-provider-credential-entra`/idiom, -`d2b-provider-credential-secret-service`/idiom, -`d2b-provider-guest-azure-container-apps`/type, -`d2b-provider-seccomp-profile`/idiom, `d2b-provider-system-core`/idiom, -`d2b-provider-volume`/idiom, `d2b-provider-wayland-session`/err - lanes read -deeper than the single-pass pre-scan) match exactly the set the README's -coverage note names. Spot-checks against U1 section (e) (10 `N/A` cells: -d2b/ffi=0, d2b/macro=0, d2b-audit/async=0, d2b-audit/ffi=0, -d2b-broker-composition/type=0, d2b-broker-composition/conc=0, -d2b-broker-composition/ffi=0, d2b-broker-fixture-handlers/idiom=0, -d2b-broker-fixture-handlers/type=0, d2b-broker-fixture-handlers/err=0; -10 `clean` cells: d2b/serde=194, d2b/obs=33, d2b/conc=44, d2b/async=77, -d2b/unsafe=4, d2b-audit/serde=84, d2b-audit/obs=5, d2b-audit/conc=18, -d2b-audit/unsafe=1, d2b-audit/macro=1) all agree with the U1 seed matrix. - -## check 5: anchor existence - pass - -``` -high findings: 13 (raw high: 14) -medium/low rows: 1008; every-5th sample: 201 -anchors checked: 568 failures: 0 -check 5 (mechanical): PASS -``` - -All 13 consolidated `sev=high` findings (every anchor) and a deterministic 20% -sample of medium/low rows - every 5th row of the 1008 medium/low raw findings -sorted by (lens, crate, lane-file line) - were resolved and re-read. 568 -anchors total; every anchor resolves to an existing file whose line count is ->= the cited line, and the cited line/range plausibly relates to the claim -(judged from the printed line contents; the 13 high anchors and all ambiguous -basename resolutions were additionally read directly). Resolution followed the -rule: repo-relative first, then crate-relative via `packages//`, then -`packages//src/` and `packages//tests/`, then a basename search -under `packages//` preferring `src/` (e.g. `admission.rs:1182` -> -`packages/d2b-session/src/admission.rs:1182`; `public_wire.rs:167` -> -`packages/d2b-contracts-control/src/public_wire.rs:167`; `controller.rs:1808` --> `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs:1808`). - -The raw corpus carries 14 high rows; the 14th (`tail-1#4`, unsafe, -d2b-host-activation-helper, `walk_dir` fdopendir handle leak) was merged into -`tail-1#3` by consolidation (recorded merge, overlapping anchors) - a merge, -not a demotion, consistent with README section 7's "no demotions" record. Its -anchors (`packages/d2b-host-activation-helper/src/main.rs:194,218,222,260,265`) -all exist and relate to the claim. - -Deterministic sample list (201 rows; every 5th medium/low row in -(lens, crate, line) order; first anchor shown): - -``` -d2b-audit#7 [api] d2b-audit packages/d2b-audit/src/lib.rs:16 -d2b-broker-p5#2 [api] d2b-broker-p5 packages/d2b-broker/src/ops/cgroup.rs:126-129 -d2b-bus-p2#5 [api] d2b-bus-p2 packages/d2b-bus/src/lib.rs:34 -d2b-contracts-control#5 [api] d2b-contracts-control cli_output.rs:6 -d2b-contracts-resource-p2#6 [api] d2b-contracts-resource-p2 packages/d2b-contracts-resource/src/v3/identity.rs:269-270 -d2b-core-controller-p1#2 [api] d2b-core-controller-p1 packages/d2b-core-controller/src/controller_assignment.rs:2707 -d2b-core-p1#5 [api] d2b-core-p1 packages/d2b-core/src/bundle_resolver.rs:620 -d2b-core-p2#6 [api] d2b-core-p2 packages/d2b-core/src/privileges.rs:741 -d2b-process-conformance#3 [api] d2b-process-conformance packages/d2b-process-conformance/src/lib.rs:52 -d2b-provider-activation-nixos#2 [api] d2b-provider-activation-nixos packages/d2b-provider-activation-nixos/src/controller.rs:14 -d2b-provider-config-nixos#5 [api] d2b-provider-config-nixos packages/d2b-provider-config-nixos/src/service.rs:296-298 -d2b-provider-device-gpu#6 [api] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/lib.rs:12 -d2b-provider-device-tpm#5 [api] d2b-provider-device-tpm effects_service.rs:341 -d2b-provider-display-wayland-p1#8 [api] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:12 -d2b-provider-guest-azure-virtual-machine#10 [api] d2b-provider-guest-azure-virtual-machine src/controller/mod.rs:211 -d2b-provider-guest-cloud-hypervisor#14 [api] d2b-provider-guest-cloud-hypervisor guest_local.rs:49-166 -d2b-provider-notification-desktop#7 [api] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/controller.rs:110 -d2b-provider-provider#3 [api] d2b-provider-provider src/driver.rs:215 -tail-3#8 [api] d2b-provider-role packages/d2b-provider-role/Cargo.toml:17 -d2b-provider-system-core#5 [api] d2b-provider-system-core src/lib.rs:40 -d2b-provider-toolkit-p2#4 [api] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/server/service.rs:297-299 -d2b-provider-volume#4 [api] d2b-provider-volume driver.rs:246-250 -d2b-provider-zone-link#6 [api] d2b-provider-zone-link packages/d2b-provider-zone-link/src/zonelink.rs:178 -d2b-resource-runtime-p2#8 [api] d2b-resource-runtime-p2 packages/d2b-resource-runtime/src/context.rs:364-366 -d2b-session-p2#5 [api] d2b-session-p2 engine.rs:166 -d2bd-p2#5 [api] d2bd-p2 packages/d2bd/src/audio_host_controller.rs:68 -d2bd-runtime-p1#5 [api] d2bd-runtime-p1 public_read_model.rs:51-53 -d2bd-runtime-p4#11 [api] d2bd-runtime-p4 packages/d2bd-runtime/src/console_session.rs:66 -d2b-provider-credential-secret-service#5 [async] d2b-provider-credential-secret-service packages/d2b-provider-credential-secret-service/src/lib.rs:1323 -d2b-provider-system-core#11 [async] d2b-provider-system-core src/testing.rs:30 -d2bd-runtime-p4#20 [async] d2bd-runtime-p4 packages/d2bd-runtime/src/console_session.rs:33 -d2b-provider-clipboard-wayland-p1#12 [conc] d2b-provider-clipboard-wayland-p1 src/fd.rs:545 -d2b-provider-guest#2 [conc] d2b-provider-guest packages/d2b-provider-guest/src/driver.rs:502 -d2b-provider-toolkit-p1#8 [conc] d2b-provider-toolkit-p1 packages/d2b-provider-toolkit/src/operations/envelope.rs:487 -d2b-resource-client#8 [conc] d2b-resource-client packages/d2b-resource-client/src/zone_client.rs:510 -d2bd-p7#9 [conc] d2bd-p7 packages/d2bd/src/effect_service_actors.rs:174 -d2b-audit#10 [docs] d2b-audit packages/d2b-audit/src/export.rs:74 -d2b-broker-p3#9 [docs] d2b-broker-p3 packages/d2b-broker/src/ops/sysctl.rs:32 -d2b-broker-p4#5 [docs] d2b-broker-p4 packages/d2b-broker/src/ops/route.rs:29 -d2b-broker-p6#11 [docs] d2b-broker-p6 src/envelope/mod.rs:1118 -d2b-bus-p1#7 [docs] d2b-bus-p1 packages/d2b-bus/src/router.rs:1126 -d2b-bus-p2#8 [docs] d2b-bus-p2 packages/d2b-bus/src/streams.rs:39-40 -d2b-contracts-control#10 [docs] d2b-contracts-control cli_output.rs:10 -d2b-contracts-provider-p2#9 [docs] d2b-contracts-provider-p2 packages/d2b-contracts-provider/src/v3/credential_controller.rs:155 -d2b-contracts-zone-session-p1#5 [docs] d2b-contracts-zone-session-p1 src/v3/component_session.rs:27 -d2b-core-controller-p2#8 [docs] d2b-core-controller-p2 authority_persistence.rs:50 -d2b-core-p2#10 [docs] d2b-core-p2 packages/d2b-core/src/manifest_v04.rs:1 -d2b-p2#11 [docs] d2b-p2 packages/d2b/src/doctor.rs:91 -d2b-provider-activation-nixos#6 [docs] d2b-provider-activation-nixos packages/d2b-provider-activation-nixos/src/controller.rs:118 -d2b-provider-clipboard-wayland-p1#9 [docs] d2b-provider-clipboard-wayland-p1 src/fd.rs:549 -tail-2#2 [docs] d2b-provider-command packages/d2b-provider-command/src/command.rs:38 -d2b-provider-credential-secret-service#3 [docs] d2b-provider-credential-secret-service packages/d2b-provider-credential-secret-service/src/lib.rs:523 -d2b-provider-device-security-key#4 [docs] d2b-provider-device-security-key packages/d2b-provider-device-security-key/src/lease.rs:150-303 -d2b-provider-display-wayland-p1#10 [docs] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/lib.rs:14 -d2b-provider-guest-azure-container-apps#9 [docs] d2b-provider-guest-azure-container-apps src/lib.rs:7 -d2b-provider-guest-cloud-hypervisor#15 [docs] d2b-provider-guest-cloud-hypervisor descriptor.rs:423-429 -d2b-provider-notification-desktop#12 [docs] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/runtime.rs:88-89 -tail-3#2 [docs] d2b-provider-process-minijail packages/d2b-provider-process-minijail/src/launch.rs:33 -tail-3#7 [docs] d2b-provider-role packages/d2b-provider-role/src/lib.rs:1 -d2b-provider-toolkit-p1#7 [docs] d2b-provider-toolkit-p1 packages/d2b-provider-toolkit/src/base/runtime.rs:248-249 -d2b-provider-volume-binding#3 [docs] d2b-provider-volume-binding packages/d2b-provider-volume-binding/src/facets.rs:52 -d2b-resource-api-p1#9 [docs] d2b-resource-api-p1 service.rs:198 -d2b-resource-runtime-p1#8 [docs] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/manager.rs:850 -d2b-session-p1#3 [docs] d2b-session-p1 handshake.rs:25 -d2b-session-p2#10 [docs] d2b-session-p2 admission.rs:1182 -d2b-unsafe-local-helper#7 [docs] d2b-unsafe-local-helper packages/d2b-unsafe-local-helper/src/lib.rs:1-4 -d2bd-p4#6 [docs] d2bd-p4 packages/d2bd/src/composition.rs:438 -d2bd-p8#13 [docs] d2bd-p8 packages/d2bd/src/forward_rendezvous.rs:1046-1049 -d2bd-runtime-p2#7 [docs] d2bd-runtime-p2 runtime_capability.rs:47-64 -d2bd-runtime-p4#16 [docs] d2bd-runtime-p4 packages/d2bd-runtime/src/wire_response_helpers.rs:7 -xtask-p3#6 [docs] xtask-p3 packages/xtask/src/delivery/snapshot.rs:87 -d2b-audit#9 [err] d2b-audit packages/d2b-audit/src/segment.rs:694 -d2b-broker-p6#8 [err] d2b-broker-p6 src/ops/exec_reconcile.rs:1238-1265 -d2b-contracts-provider-p1#8 [err] d2b-contracts-provider-p1 packages/d2b-contracts-provider/src/v3/provider_registry.rs:186 -d2b-contracts-resource-p1#6 [err] d2b-contracts-resource-p1 packages/d2b-contracts-resource/src/v3/operations/error.rs:93 -d2b-core-p1#10 [err] d2b-core-p1 packages/d2b-core/src/bundle_resolver.rs:1405 -d2b-p2#10 [err] d2b-p2 packages/d2b/src/host.rs:274 -d2b-provider-clipboard-wayland-p1#5 [err] d2b-provider-clipboard-wayland-p1 src/bin/d2b-clipd.rs:3550 -d2b-provider-credential-managed-identity#3 [err] d2b-provider-credential-managed-identity lib.rs:1261-1262 -d2b-provider-display-wayland-p2#7 [err] d2b-provider-display-wayland-p2 src/process.rs:335 -d2b-provider-notification-desktop#10 [err] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/host_sink.rs:185 -d2b-provider-supervisor#6 [err] d2b-provider-supervisor packages/d2b-provider-supervisor/src/adapter.rs:888-890 -d2b-provider-toolkit-p2#7 [err] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/shared_provider.rs:615 -d2b-provider-transport-azure-relay#9 [err] d2b-provider-transport-azure-relay packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30 -d2b-resource-client#6 [err] d2b-resource-client packages/d2b-resource-client/src/call.rs:281 -d2b-telemetry#1 [err] d2b-telemetry packages/d2b-telemetry/src/emitter.rs:201-206 -d2bd-p3#1 [err] d2bd-p3 packages/d2bd/src/composition.rs:22793-22797 -d2bd-p6#4 [err] d2bd-p6 packages/d2bd/src/resource_plane_v3.rs:1956 -d2bd-runtime-p3#4 [err] d2bd-runtime-p3 packages/d2bd-runtime/src/exec_session.rs:939 -d2b-audit#2 [idiom] d2b-audit packages/d2b-audit/src/export.rs:103 -d2b-broker-p2#1 [idiom] d2b-broker-p2 packages/d2b-broker/src/runtime.rs:10132 -d2b-broker-p6#4 [idiom] d2b-broker-p6 src/ops/device_worker.rs:312-335 -d2b-contracts-broker#1 [idiom] d2b-contracts-broker packages/d2b-contracts-broker/src/kernel_client.rs:225-227 -d2b-contracts-provider-p2#1 [idiom] d2b-contracts-provider-p2 packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573 -d2b-contracts-zone-session-p1#1 [idiom] d2b-contracts-zone-session-p1 src/v3/component_session.rs:1935 -d2b-core-p2#1 [idiom] d2b-core-p2 packages/d2b-core/src/static_invariants.rs:162 -d2b-p2#5 [idiom] d2b-p2 packages/d2b/src/zone_audit.rs:591 -d2b-provider-clipboard-wayland-p1#3 [idiom] d2b-provider-clipboard-wayland-p1 src/bin/d2b-clipd.rs:1131 -d2b-provider-clipboard-wayland-p2#4 [idiom] d2b-provider-clipboard-wayland-p2 packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46 -d2b-provider-device-gpu#1 [idiom] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/authority.rs:401 -d2b-provider-device-usbip#1 [idiom] d2b-provider-device-usbip driver.rs:267-281 -d2b-provider-display-wayland-p1#5 [idiom] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820 -d2b-provider-guest-azure-virtual-machine#1 [idiom] d2b-provider-guest-azure-virtual-machine src/bootstrap.rs:138 -d2b-provider-guest-cloud-hypervisor#13 [idiom] d2b-provider-guest-cloud-hypervisor guest_local.rs:113-121 -d2b-provider-notification-desktop#1 [idiom] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/controller.rs:660-675 -d2b-provider-supervisor#2 [idiom] d2b-provider-supervisor packages/d2b-provider-supervisor/src/broker.rs:1104-1130 -d2b-provider-transport-azure-relay#1 [idiom] d2b-provider-transport-azure-relay packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239 -d2b-provider-zone-link#1 [idiom] d2b-provider-zone-link packages/d2b-provider-zone-link/src/zone_links.rs:60 -d2b-resource-compiler#1 [idiom] d2b-resource-compiler packages/d2b-resource-compiler/src/lib.rs:2401 -d2b-resource-runtime-p1#2 [idiom] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/manager.rs:1419 -d2b-session-p2#2 [idiom] d2b-session-p2 admission.rs:1593 -d2b-zone-routing#2 [idiom] d2b-zone-routing packages/d2b-zone-routing/src/service.rs:311 -d2bd-p3#9 [idiom] d2bd-p3 packages/d2bd/src/composition.rs:21306-21319 -d2bd-p8#3 [idiom] d2bd-p8 packages/d2bd/src/provider_registry.rs:527-536 -d2bd-runtime-p4#2 [idiom] d2bd-runtime-p4 packages/d2bd-runtime/src/console_session.rs:162 -xtask-p1#5 [idiom] xtask-p1 packages/xtask/src/provider_crate_policy.rs:6662 -d2b-resource-api-p1#14 [macro] d2b-resource-api-p1 service.rs:2245-2267 -d2b-provider-activation-nixos#4 [obs] d2b-provider-activation-nixos packages/d2b-provider-activation-nixos/src/controller.rs:569 -d2b-provider-guest-azure-virtual-machine#11 [obs] d2b-provider-guest-azure-virtual-machine src/controller/mod.rs:346 -d2b-provider-toolkit-p1#6 [obs] d2b-provider-toolkit-p1 packages/d2b-provider-toolkit/src/base/guest.rs:494-498 -d2b-provider-transport-vsock#3 [obs] d2b-provider-transport-vsock packages/d2b-provider-transport-vsock/src/service.rs:735 -d2bd-p2#8 [obs] d2bd-p2 packages/d2bd/src/composition.rs:15195 -d2bd-runtime-p2#5 [obs] d2bd-runtime-p2 runtime_process.rs:450 -X3-cross-crate-duplication#7 [own] X3-cross-crate-duplication packages/d2bd/src/resource_plane_v3.rs:3227 -d2b-broker-p3#1 [own] d2b-broker-p3 packages/d2b-broker/src/ops/pidfd.rs:210 -d2b-bus-p2#3 [own] d2b-bus-p2 packages/d2b-bus/src/session/contract.rs:1046-1056 -d2b-contracts-resource-p1#2 [own] d2b-contracts-resource-p1 packages/d2b-contracts-resource/src/v3/volume_state.rs:138 -d2b-contracts-zone-session-p2#3 [own] d2b-contracts-zone-session-p2 services.rs:216 -d2b-p2#6 [own] d2b-p2 packages/d2b/src/doctor.rs:1062 -d2b-provider#1 [own] d2b-provider packages/d2b-provider/src/agent.rs:290 -d2b-provider-device-gpu#4 [own] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/controller.rs:272 -d2b-provider-guest#5 [own] d2b-provider-guest packages/d2b-provider-guest/src/effects_service.rs:243 -d2b-provider-guest-azure-container-apps#5 [own] d2b-provider-guest-azure-container-apps src/controller.rs:892 -d2b-provider-guest-azure-virtual-machine#5 [own] d2b-provider-guest-azure-virtual-machine src/controller/mod.rs:1046 -d2b-provider-notification-desktop#4 [own] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/lifecycle.rs:338 -d2b-provider-provider#2 [own] d2b-provider-provider src/driver.rs:360 -d2b-provider-toolkit-p2#2 [own] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/server/adapter.rs:305 -d2b-provider-volume#2 [own] d2b-provider-volume driver.rs:337 -d2b-resource-api-p1#1 [own] d2b-resource-api-p1 adapter.rs:425 -d2b-resource-compiler#7 [own] d2b-resource-compiler packages/d2b-resource-compiler/src/main.rs:1467 -d2b-resource-runtime-p1#5 [own] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/metadata.rs:191 -d2b-session-p2#3 [own] d2b-session-p2 engine.rs:689 -d2bd-p3#4 [own] d2bd-p3 packages/d2bd/src/composition.rs:20404 -d2bd-p8#5 [own] d2bd-p8 packages/d2bd/src/forward_rendezvous.rs:456 -d2bd-runtime-p4#4 [own] d2bd-runtime-p4 packages/d2bd-runtime/src/daemon_audit.rs:976 -xtask-p2#3 [own] xtask-p2 packages/xtask/src/gen_broker_operations.rs:844 -xtask-p5#2 [own] xtask-p5 packages/xtask/src/blocking_census.rs:1270 -d2b-broker-p6#13 [perf] d2b-broker-p6 src/ops/store_view_posture.rs:194-271 -d2b-contracts-zone-session-p2#10 [perf] d2b-contracts-zone-session-p2 resource_bundle.rs:382 -d2b-p1#5 [perf] d2b-p1 context.rs:570 -d2b-provider-guest#6 [perf] d2b-provider-guest packages/d2b-provider-guest/src/driver.rs:863 -d2b-provider-notification-desktop#13 [perf] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/host_sink.rs:265 -d2b-provider-toolkit-p2#13 [perf] d2b-provider-toolkit-p2 packages/d2b-provider-toolkit/src/shared_provider.rs:944 -d2b-resource-api-p1#12 [perf] d2b-resource-api-p1 manager_backend.rs:1006 -d2b-session-p2#12 [perf] d2b-session-p2 record.rs:125 -d2bd-p7#8 [perf] d2bd-p7 packages/d2bd/src/process_provider_runtime.rs:333 -xtask-p1#12 [perf] xtask-p1 packages/xtask/src/main.rs:431 -d2b-broker-composition#7 [serde] d2b-broker-composition packages/d2b-broker-composition/src/dependency_surface.rs:308 -d2b-contracts-provider-p2#8 [serde] d2b-contracts-provider-p2 packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76 -d2b-core-p1#12 [serde] d2b-core-p1 packages/d2b-core/src/bundle_resolver.rs:209 -d2b-process-conformance#9 [serde] d2b-process-conformance packages/d2b-process-conformance/src/terminal.rs:39 -d2b-provider-display-wayland-p1#9 [serde] d2b-provider-display-wayland-p1 packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817 -d2b-provider-supervisor#7 [serde] d2b-provider-supervisor packages/d2b-provider-supervisor/src/broker.rs:1563-1603 -d2b-provider-wayland-policy#2 [serde] d2b-provider-wayland-policy packages/d2b-provider-wayland-policy/src/interaction.rs:241-243 -d2bd-runtime-p2#4 [serde] d2bd-runtime-p2 wire.rs:265-353 -X1-supply-chain#1 [supply] X1-supply-chain packages/d2b-session/Cargo.toml:17 -X1-supply-chain#6 [supply] X1-supply-chain packages/d2b-bus/Cargo.toml:41 -X1-supply-chain#11 [supply] X1-supply-chain packages/d2b-provider-device-gpu/Cargo.toml:25 -X1-supply-chain#16 [supply] X1-supply-chain packages/d2b-provider-transport-azure-relay/Cargo.toml:34 -d2b-provider-device-gpu#13 [supply] d2b-provider-device-gpu packages/d2b-provider-device-gpu/Cargo.toml:20 -d2b-broker-composition#9 [test] d2b-broker-composition packages/d2b-broker-composition/src/seam.rs:523 -d2b-contracts-control#14 [test] d2b-contracts-control public_wire.rs:167 -d2b-core-controller-p2#11 [test] d2b-core-controller-p2 authority.rs:1824 -d2b-host#8 [test] d2b-host packages/d2b-host/src/bin/d2b-activation-helper.rs:792 -d2b-provider-audio-pipewire#12 [test] d2b-provider-audio-pipewire tests/mediator.rs:13-24 -d2b-provider-config-nixos#9 [test] d2b-provider-config-nixos packages/d2b-provider-config-nixos/src/service.rs:70-90 -d2b-provider-device-gpu#12 [test] d2b-provider-device-gpu packages/d2b-provider-device-gpu/src/authority.rs:168 -d2b-provider-display-wayland-p2#12 [test] d2b-provider-display-wayland-p2 src/controller.rs:1481 -d2b-provider-guest-cloud-hypervisor#5 [test] d2b-provider-guest-cloud-hypervisor finalize_ordering_test.rs:286 -d2b-provider-supervisor#9 [test] d2b-provider-supervisor packages/d2b-provider-supervisor/src/broker.rs:2040-2043 -d2b-provider-zone-link#8 [test] d2b-provider-zone-link packages/d2b-provider-zone-link/src/zone_links.rs:2519 -d2b-resource-runtime-p1#13 [test] d2b-resource-runtime-p1 packages/d2b-resource-runtime/src/revision.rs:182 -d2b-telemetry#5 [test] d2b-telemetry packages/d2b-telemetry/src/meter_registry.rs:176-180 -xtask-p1#15 [test] xtask-p1 packages/xtask/src/gen_layer_catalogs.rs:705 -X2-generated-boundary#6 [type] X2-generated-boundary packages/xtask/src/gen_broker_operations.rs:891 -d2b-bus-p1#3 [type] d2b-bus-p1 packages/d2b-bus/src/router.rs:218-219 -d2b-contracts-broker#5 [type] d2b-contracts-broker packages/d2b-contracts-broker/src/broker_wire.rs:2805 -d2b-contracts-provider-p1#6 [type] d2b-contracts-provider-p1 packages/d2b-contracts-provider/src/v3/provider.rs:1333 -d2b-contracts-resource-p2#5 [type] d2b-contracts-resource-p2 packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47 -d2b-host#1 [type] d2b-host packages/d2b-host/src/nftables.rs:609 -d2b-provider-audio-pipewire#1 [type] d2b-provider-audio-pipewire src/resource_type.rs:64-70 -d2b-provider-clipboard-wayland-p2#9 [type] d2b-provider-clipboard-wayland-p2 packages/d2b-provider-clipboard-wayland/src/picker.rs:247 -d2b-provider-guest#1 [type] d2b-provider-guest packages/d2b-provider-guest/src/driver.rs:709 -d2b-provider-guest-cloud-hypervisor#10 [type] d2b-provider-guest-cloud-hypervisor identity.rs:857-865 -d2b-provider-notification-desktop#5 [type] d2b-provider-notification-desktop packages/d2b-provider-notification-desktop/src/controller.rs:22-27 -tail-4#4 [type] d2b-provider-telemetry-binding packages/d2b-provider-telemetry-binding/src/driver.rs:168 -d2b-resource-client#4 [type] d2b-resource-client packages/d2b-resource-client/src/call.rs:168 -d2bd-p1#8 [type] d2bd-p1 packages/d2bd/src/resource_runtime.rs:1014 -d2bd-runtime-p1#3 [type] d2bd-runtime-p1 component_session_vsock.rs:32-36 -d2bd-runtime-p4#7 [type] d2bd-runtime-p4 packages/d2bd-runtime/src/typed_shell_targets.rs:13 -tail-1#1 [unsafe] d2b-broker-fixture-syscall-surface packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32 -``` - -## check 6: count reconciliation - pass (after consolidator fix; initial run failed) - -Initial run (before the consolidator's fix): - -``` -raw lane rows: 1022 consolidated rows: 965 merges: 57 -965 + 57 == 1022: True -consolidated by sev: {'medium': 295, 'low': 657, 'high': 13} -consolidated by verdict: {'actionable': 923, 'needs-contract': 25, 'policy-confirmed': 17} -exec summary by sev: {'high': 13, 'medium': 295, 'low': 657} -exec summary by verdict: {'actionable': 923, 'needs-contract': 25, 'policy-confirmed': 17} -exec summary lens table: matches consolidated by_lens for all 16 lenses (idiom 124, own 115, - type 82, api 138, err 94, serde 40, obs 31, docs 143, perf 52, conc 29, async 19, - unsafe 4, ffi 0, macro 4, test 67, supply 23) -section 2 rows per lens: total 947; section 4 rows per lane: total 33 -findings with a full row in section 2 or 4: 961 of 965 -rows displayed in BOTH section 2 and section 4 (X1 overlap): 19 -findings with NO full row in sections 2/4: ['RS-0929', 'RS-0930', 'RS-0931', 'RS-0932'] -check 6: FAIL -``` - -The three headline numbers reconciled exactly (1022 raw = 965 report + 57 -merges), and the executive summary's severity split (13 high / 295 medium / -657 low), verdict split (923 actionable / 25 needs-contract / 17 -policy-confirmed), and all 16 per-lens totals equaled the recomputed -consolidated counts. The initial failure was the per-lens section display: -section 2's `supply` section showed 19 rows while the executive summary counts -23 supply findings. Four crate-lane supply findings - `RS-0929` -(`d2b-provider-audio-pipewire#13`), `RS-0930` (`d2b-provider-device-gpu#13`), -`RS-0931` (`d2b-provider-guest-azure-container-apps#13`), `RS-0932` -(`tail-3#4`) - had no full row (what/fix/anchors) anywhere in README sections -2 or 4; they appeared only in the section 3 per-crate index and the section 6 -remediation clusters. The other 14 rows absent from section 2 were the -cross-cutting findings (RS-0952..RS-0965), which section 4 displays by design; -the 19 X1 rows were displayed in both section 2's supply section and section 4 -(a double display, not a loss). Root cause: the render path restricted the -supply section to X1-supply-chain rows and omitted X2/X3 rows from their lens -sections, dropping crate-lane supply rows. - -Re-run after the consolidator's fix (renderer corrected: section 2 now renders -every finding under its lens, grouped by crate, with cross-cutting lanes -grouped under their lane id; section 4 keeps the lane-oriented list): - -``` -raw lane rows: 1022 consolidated rows: 965 merges: 57 -965 + 57 == 1022: True -exec summary by sev: {'high': 13, 'medium': 295, 'low': 657} (matches consolidated) -exec summary by verdict: {'actionable': 923, 'needs-contract': 25, 'policy-confirmed': 17} (matches) -exec summary lens table: matches consolidated by_lens for all 16 lenses (ffi 0 included) -section 2 rows per lens: idiom 124, own 115, type 82, api 138, err 94, serde 40, obs 31, - docs 143, perf 52, conc 29, async 19, unsafe 4, ffi 0, macro 4, test 67, supply 23 - (total 965; every per-lens count equals the executive-summary count) -section 4 rows per lane: X1 19, X2 6, X3 8 (total 33) -findings with a full row in section 2 or 4: 965 of 965 -rows displayed in BOTH section 2 and section 4 (cross-lane overlap): 33 -findings with NO full row in sections 2/4: [] -check 6: PASS -``` - -`RS-0929`, `RS-0930`, `RS-0931`, `RS-0932` are now present as full rows in the -section 2 `supply` section under their crates (`d2b-provider-audio-pipewire`, -`d2b-provider-device-gpu`, `d2b-provider-guest-azure-container-apps`, -`d2b-provider-quota`), and the X2/X3 findings appear in their lens sections. -All 965 findings now have a full row in sections 2/4, and the per-lens section -counts equal the executive-summary counts for all 16 lens labels. - -## check 7: writes confined - pass - -``` -porcelain entries: 2 - ?? docs/audits/2026-09-24-rust-skills-audit/ - ?? docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md -outside allowed paths: [] -check 7: PASS -``` - -`git status --porcelain` lists only the audit deliverable directory and the -pre-existing untracked plan file `docs/plans/2026-09-22-001-chore-post-plan-cleanup-wave-plan.md` -(not ours, left untouched). No tracked file is modified; `.scratch/` is -gitignored (its contents are audit tooling, allowed by the plan). No source, -policy, or gate file changed during the audit. - -## check 8: README faithfulness spot-check - pass - -Rows 100, 300, 500, 700, 900 of the findings corpus (`RS-0100`, `RS-0300`, -`RS-0500`, `RS-0700`, `RS-0900`) were located in the README and their fields -compared field-by-field with the corresponding lane rows (severity, crate, -what, fix, first-four anchors, verdict, lane reference): - -``` -RS-0100 (d2b-session-p2 d2b-session-p2#1): OK -RS-0300 (d2bd-p1 d2bd-p1#7): OK -RS-0500 (d2b-provider-process d2b-provider-process#3): OK -RS-0700 (d2b-provider-process d2b-provider-process#4): OK -RS-0900 (d2b-provider-guest-azure-container-apps d2b-provider-guest-azure-container-apps#12): OK -check 8: PASS -``` - -## check 9: data quality - parenthesis artifacts (informational) - -Metric (as measured by the consolidator): share of lines with unbalanced -parentheses after stripping regex-escaped parens, over lines containing parens -(after the same strip). Recomputation per lane file: - -``` -unbalanced-line numerators match consolidator's list for all 9 files: True -denominator differences (parent, mine): d2b-provider-guest-qemu-media (49, 50), - d2b-resource-compiler (49, 48), d2b-provider-guest (45, 43), - d2b-provider-volume (41, 37), d2b-provider-credential-managed-identity (36, 37), - d2b-contracts (39, 37), d2b-broker-p6 (52, 51); the other two files match exactly -files >25% artifact share (my recomputation): d2b-broker-p6 (13/51), d2b-contracts - (10/37), d2b-provider-credential-managed-identity (11/37), d2b-provider-guest - (20/43), d2b-provider-guest-qemu-media (40/50), d2b-provider-shell-terminal - (17/37), d2b-provider-volume (14/37), d2b-resource-compiler (33/48), d2bd-p5 - (12/34), xtask-p5 (9/35) -``` - -The unbalanced-line numerators match the consolidator's nine-file list exactly -(40/33/17/20/12/14/11/10/13). The denominators differ by at most 4 lines per -file (attributable to the line-scope definition and/or pre-repair file state); -under my recomputation `xtask-p5` (9/35 = 25.7%) and `d2b-broker-p6` (13/51 = -25.5%) sit just above the 25% threshold while the consolidator's measurement -places broker-p6 at exactly 25% (13/52). This class is prose/punctuation only - -paths, line numbers, and counts are intact - and is not a schema violation. - -## Mismatches - -None. The single mismatch found on the initial run (check 6: four crate-lane -supply findings - `RS-0929`, `RS-0930`, `RS-0931`, `RS-0932` - missing full -rows from README section 2's `supply` section) was reported to the -consolidator, fixed in the renderer, and re-verified: all four rows are now -present and every count reconciles (see check 6 and the re-run section below). - -## Re-run after consolidator fix (checks 3, 5, 6) - -Initial run: check 3 PASS, check 5 PASS, check 6 FAIL (four supply rows missing -from section 2; exact ids `RS-0929`..`RS-0932`). Re-run results after the -consolidator's renderer fix: - -``` -check 3: PASS (110 files, 1022 findings, 0 schema violations) -check 5: PASS (13 high + 201 sampled rows; 568 anchors; 0 failures) -check 6: PASS (1022 = 965 + 57; severity 13/295/657; verdicts 923/25/17; - section 2 total 965; per-lens counts equal the exec summary - for all 16 lenses; no finding without a full row) -``` - -Both passes recorded: checks 3 and 5 were unaffected by the fix (no lane row, -count, or anchor changed) and passed on both runs; check 6 failed on the -initial run and passes after the fix. - -## Pass 3 (final README: verbatim pipe restoration) - -The consolidator made two further README-only changes after pass 2: (1) a -renderer fix - section 2/4 bullet rows previously normalized `|` to `/` in -`what`/`fix` text, corrupting closure pipes inside inline code (e.g. -`map(|resource_type| ...)` rendered as `map(/resource_type/ ...)`); bullet -rows now carry lane text verbatim, and only the section 1 summary table -escapes `|` as `\|` (21 closure snippets restored); (2) README section 7 now -carries the verification summary and the data-quality note gained the -`xtask-p5` (9/35) mention and a renderer note about verbatim pipes. No count, -matrix cell, finding id, or anchor changed. - -Re-run of the full script at the final README: - -``` -check 1: PASS check 2: PASS check 3: PASS check 4: PASS -check 5: PASS check 6: PASS check 7: PASS check 8: PASS -(568 anchors checked, 0 failures; section 2 total 965; per-lens counts equal - the exec summary for all 16 lenses; no finding without a full row) -``` - -Checks 3, 5, 6, 8 all pass at the final README. Additional full-corpus -faithfulness run (beyond check 8's five-row spot check): all 998 finding rows -in README sections 2 and 4 were parsed and compared field-by-field against the -consolidated findings - severity, grouping label, `what` (verbatim), `fix` -(verbatim), first-four anchors, verdict, and lane reference - with zero -mismatches, and all 965 unique RS ids appear in section 2. This confirms the -final README differs from the pass-2 state only in the verbatim row-text -restoration and prose (section 7), with no count, cell, id, or anchor change. -Both earlier passes remain valid: pass 1 (check 6 FAIL, four supply rows -missing) and pass 2 (check 6 PASS after the renderer fix) are recorded above -unchanged. - -## Data-quality note - -Two artifact classes were observed in the lane corpus, both confined to prose -and both verified not to affect any structured field: - -1. **Numeral-spelling and punctuation artifacts** from the lane-writing path - (e.g. `two finding(s)`, `twelve/eleven/zero/zero` coverage phrasing, a - dropped or duplicated `)` in inline snippets). The structured fields - (lens, severity, blast, effort, verdict, anchors, local ids) were parsed - and verified independently of this prose: check 3 found zero schema - violations across all 110 files, and check 8 confirmed the README rows - reproduce the lane rows' structured fields exactly. -2. **Parenthesis imbalance** (drop/duplication, no fact loss): see check 9. - Per-file incidence of unbalanced-paren lines (after stripping regex-escaped - parens) is highest in `d2b-provider-guest-qemu-media` (40/50), `d2b-resource-compiler` - (33/48), `d2b-provider-shell-terminal` (17/37), `d2b-provider-guest` (20/43), - `d2bd-p5` (12/34), `d2b-provider-volume` (14/37), `d2b-provider-credential-managed-identity` - (11/37), `d2b-contracts` (10/37), `d2b-broker-p6` (13/51); the consolidator's - measured list (40/49, 33/49, 17/37, 20/45, 12/34, 14/41, 11/36, 10/39, - 13/52) agrees on every numerator. One mechanical repair was applied to - `d2b-provider-guest-qemu-media.md` only (space-after-paren form); no other - lane file was rewritten for this class. - -The known-and-accepted deviations from the plan's lane-file contract (lane -prose artifacts; non-15-line coverage blocks in five single-crate lanes and -the tail/X lanes; tail lanes carrying one `## ` section per crate) were -observed as documented and do not affect the checks above. \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md b/docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md deleted file mode 100644 index e8183dcaf..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/X1-supply-chain.md +++ /dev/null @@ -1,69 +0,0 @@ -# X1-supply-chain - workspace -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: n/a (workspace manifests and lockfiles) | modules: root Cargo.toml, Cargo.lock, deny.toml, rust-toolchain.toml, packages/Cargo.guest.lock, 94 member Cargo.toml`s -Lenses: supply - -## supply - -Gate posture (what the existing supply-chain lane already covers): `cargo-deny check bans licenses sources` runs on both the main workspace and the guest tree against vendored registries (flake.nix:1287-1345), and `cargo-audit` runs on both checked-in locks plus the per-context policy locks against a pinned RustSec advisory-DB snapshot (flake.nix:1072, rev 831c50f4a4304068f125e603add6a8839f08b3eb; `--no-fetch`). Advisories are therefore fully gated (the absence of a [advisories] section in deny.toml is deliberate, documented at flake.nix:1267-1269). This lane's findings cover tree weight, duplicate clusters, manifest consistency, and licence posture gaps only. - -Checked clean: (a) all 13 workspace.dependencies entries are referenced by at least one member manifest (census over 94 member [dependencies|dev-dependencies|build-dependencies] tables = non-zero each);(b) no over-broad default-features found statically: every tokio/ttrpc decl in the workspace sets default-features = false (the root entries at Cargo.toml:211-212 are the only version sources, and no member re-enables defaults);(c) d2b-core's optional `bolero` dep (line 34) is NOT unused - it wires the `fuzz` feature (Cargo.toml:16) consumed by packages/d2b-core/fuzz/ (harness manifests `fuzz/Cargo.toml`, harness at `fuzz/src/harness.rs`), so it is excluded from the unused list below. - -- X1-supply-chain#1 sev=medium blast=leaf effort=S verdict=actionable - d2b-session depends on d2b-audit but the name appears nowhere in its sources; the dep edge is dead weight in both Cargo and Bazel builds - fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28] - evidence: census: \bd2b_audit\b over packages/d2b-session/src + tests + examples + benches + build.rs = 0 hits; BUILD.bazel carries //packages/d2b-audit:d2b_audit at :28; decision: remove - -- X1-supply-chain#2 sev=medium blast=leaf effort=S verdict=actionable - d2b-session depends on d2b-telemetry but no source reference exists; the edge is carried into both Cargo and Bazel builds - fix: remove the dep from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31] - evidence: census: \bd2b_telemetry\b over packages/d2b-session/src + tests + examples + benches + build.rs = 0 hits; BUILD.bazel carries //packages/d2b-telemetry:d2b_telemetry at :31; decision: remove - -- X1-supply-chain#3 sev=medium blast=leaf effort=S verdict=actionable - d2b-session's dev-dependency serde_json (workspace-inherited) has zero uses in any of its files - fix: remove the dev-dep (the guest lock regenerates without it) - [packages/d2b-session/Cargo.toml:44] - evidence: census: \bserde_json\b over packages/d2b-session/src + tests + examples + benches + build.rs = 0 hits(including doc-comment doctests in src); decision: remove - -- X1-supply-chain#4 sev=medium blast=leaf effort=S verdict=actionable - d2b-telemetry inherits rustix via workspace=true but no source in the crate references it; the dep is compiled into the telemetry crate for nothing - fix: remove rustix from [dependencies] (the root workspace entry stays, other members use it); regenerate the guest lock, which carries d2b-telemetry - [packages/d2b-telemetry/Cargo.toml:14] - evidence: census: \brustix\b over packages/d2b-telemetry/src (+ tests, examples, benches, build.rs if present) = 0 hits; decision: remove - -- X1-supply-chain#5 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-quota inherits serde_json via workspace=true but no source or test references it - fix: remove serde_json from [dependencies] (and from the generated BUILD deps on the next regen) - [packages/d2b-provider-quota/Cargo.toml:24] - evidence: census: \bserde_json\b over packages/d2b-provider-quota/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#6 sev=medium blast=leaf effort=S verdict=actionable - d2b-bus's dev-dependency tempfile has zero uses across src/tests(including the ui test tree) - fix: remove the dev-dep - [packages/d2b-bus/Cargo.toml:41] - evidence: census: \btempfile\b over packages/d2b-bus/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#7 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-activation-nixos inherits serde via workspace=true but no source or test in the crate names it - fix: remove serde from [dependencies] - [packages/d2b-provider-activation-nixos/Cargo.toml:35] - evidence: census: \bserde\b over packages/d2b-provider-activation-nixos/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#8 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-audio-pipewire inherits schemars via workspace=true but no derive or path in its sources uses it - fix: remove schemars from [dependencies] - [packages/d2b-provider-audio-pipewire/Cargo.toml:25] - evidence: census: \bschemars\b over packages/d2b-provider-audio-pipewire/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#9 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-guest-azure-container-apps inherits sha2 via workspace=true but no source reference exists - fix: remove sha2 from [dependencies] - [packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21] - evidence: census: \bsha2\b over packages/d2b-provider-guest-azure-container-apps/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#10 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-device-gpu declares async-trait but no #[async_trait] or use path names it - fix: remove async-trait from [dependencies] (the Bazel proc-macro dep drops with it on regen) - [packages/d2b-provider-device-gpu/Cargo.toml:20] - evidence: census: \basync_trait\b over packages/d2b-provider-device-gpu/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#11 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-device-gpu depends on d2b-resource-types but no source or test in the crate uses it; the edge carries into Bazel too - fix: remove d2b-resource-types from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39] - evidence: census: \bd2b_resource_types\b over packages/d2b-provider-device-gpu/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#12 sev=medium blast=leaf effort=S verdict=actionable - d2b depends on d2b-zone-routing but no source or test references it; the edge is carried into Bazel too - fix: remove d2b-zone-routing from [dependencies] and from deps list in BUILD.bazel; regenerate both lockfiles - [packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55] - evidence: census: \bd2b_zone_routing\b over packages/d2b/src + tests + examples + benches + build.rs = 0 hits; decision: remove - -- X1-supply-chain#13 sev=low blast=wide effort=M verdict=actionable - 13 member decls pin literal versions of workspace-declared deps rustix (3) and sha2 (10, two of them in d2b-broker) instead of the house `workspace = true` pattern (429 workspace-inherit decls across the workspace), duplicating the version truth the root table owns - fix: convert them to `rustix = { workspace = true, features = [...] }` and `sha2 = { workspace = true }`, keeping member-side features (verified additive on the pinned toolchain: a workspace entry + member features resolves with the union on cargo 1.97, offline probe) - [Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, packages/d2b-provider-process/Cargo.toml:30, packages/d2b-provider-network-local/Cargo.toml:38, packages/d2bd/Cargo.toml:100] - evidence: census: literal rustix decls: d2b-broker:60, d2b-provider-process:30, d2b-provider-network-local:38(dev); literal sha2 decls: d2b-unsafe-local-helper:29, d2b-telemetry:13, d2b-provider-guest:28, d2bd-runtime:40, d2b-provider-process-systemd:28, d2b-provider-process:33, d2b-provider-user:25, d2bd:100, d2b-broker:63(normal+dev); all other workspace-declared deps (serde 50, serde_json 88, schemars 20, tokio 87, ttrpc 9, ractor 3, ring 3, base64 4, rusqlite 1, rusqlite_migration 1, unicode-normalization 1) are already 100% workspace=true; decision: convert the 13 to workspace=true - -- X1-supply-chain#14 sev=medium blast=wide effort=M verdict=actionable - nix resolves at three minors in both locks (0.26.4 via ttrpc 0.9.0, 0.29.0 via ~19 workspace members, 0.31.3 via vsock/command-fds), so two extra copies of a syscall-family crate reach shipped binaries - fix: keep the workspace pin at 0.29, and record+accept the 0.26/0.31 legs with expiry in a [bans] comment (name, pullers, re-check trigger, per DENY.md); then consider flipping multiple-versions to `deny` - [deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33] - evidence: cargo tree --offline -d, Cargo.lock parse: nix 0.26.4 pulled by ttrpc@0.9.0;0.29.0 pulled by 19 workspace members incl. d2b-broker, d2bd, d2bd-runtime, xtask;0.31.3 pulled by command-fds@0.3.3 and vsock@0.5.4 (via d2b-provider-transport-vsock); decision: accept with expiry, re-check when ttrpc or vsock bumps its nix pin - -- X1-supply-chain#15 sev=medium blast=wide effort=L verdict=actionable - rustix resolves at two majors (0.38.44 workspace-direct vs 1.1.4 transitive via the async-std/wayland/tempfile/zbus families), so two copies compile into shipped binaries - fix: accept with expiry+record in a [bans] comment (re-check at each dep refresh; or plan a dedicated pass migrating the workspace pin to 1.1 and re-verifying the feature surface, which the root comments pin at 0.38 - [Cargo.toml:202, deny.toml:2] - evidence: cargo tree --offline -d, Cargo.lock parse: rustix 0.38.44 pulled by 33 workspace/transitive dependents(incl. d2b-broker, d2bd, xtask, wayland-client itself zbus);1.1.4 pulled by async-io@2.6.0, async-process, async-signal, polling, wayland-backend, tempfile, zbus, which, etc; decision: accept with expiry, re-check at each dependency refresh or upgrade on a dedicated pass - -- X1-supply-chain#16 sev=medium blast=leaf effort=S verdict=actionable - d2b-provider-transport-azure-relay pins webpki-roots "0.26" directly while its tokio-tungstenite 0.24 dep pulls 1.0.9 via its rustls-tls-webpki-roots feature, so the crate builds both legs - fix: upgrade the direct pin to "1" and drop the 0.26 leg(verify the TLS_SERVER_ROOTS API at the call site; if 0.26-only items are used, accept+record+expiry instead) - [packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36] - evidence: Cargo.lock parse: webpki-roots 1.0.9 dependents include tokio-tungstenite@0.24.0; the 0.26.11 leg is the member's own direct pin; decision: upgrade to "1", fallback accept with expiry+record - -- X1-supply-chain#17 sev=low blast=wide effort=M verdict=actionable - the remaining ~31 duplicate clusters(hashbrown,bitflags,heck,indexmap,linux-raw-sys,memoffset,phf family,proc-macro-crate,r-efi,rand,rand_core,syn,thiserror,toml_datetime,toml_edit,winnow,windows-sys family,windows-link,etc) resolve transitively-only at multiple versions,and deny.toml records none of it (multiple-versions = "warn" alone keeps them invisible) - fix: annotate [bans] with the accepted-cluster inventory(name, versions, pullers, re-check trigger, per DENY.md; then flip multiple-versions to `deny` once the workspace-direct clusters (#14-#16) resolve - [deny.toml:2] - evidence: Cargo.lock parse: 34 duplicate clusters total in the main lock(29 in the guest lock); after #14-#16 the remainder isthen ~31; examples: thiserror 1.0.69/2.0.20(1.x from ttrpc, protobuf 3.7.2, tungstenite 0.24, wl-proxy), vs 2.x workspace decls), syn 1/2/3(build-time macro-stack generations), windows-sys 0.48/0.52/0.59/0.61(platform tiers); decision: accept with expiry, record in deny.toml, re-check at each lock regeneration - -- X1-supply-chain#18 sev=medium blast=wide effort=M verdict=actionable - packages/Cargo.guest.lock lagged the main lock's index snapshot: 39 shared crates resolve to newer patch versions in the guest tree (syn 3.0.5, wasm-bindgen 0.2.128, uuid 1.26.1, aws-lc-rs 1.18.1, mio 1.2.3, etc), so the advisory and licence postures of the two shipped trees are assessed against different dependency sets at the same date - fix: regenerate both lockfiles from ONE index snapshot on the next dependency refresh (keeping the guest tree's host-only exclusions; add a drift check comparing shared-crate versions across the two locks) - [packages/Cargo.guest.lock:1, flake.nix:389] - evidence: lock comparison: 77 crates only in main(host-only: bolero/prost/clap/xtask/ d2b CLI crates etc); 34 only in guest(all newer patch versions of shared crates); 39 same-name version diffs, all guest-newer; decision: regenerate both locks from one snapshot, or accept+record the divergence as deliberate with a review date - -- X1-supply-chain#19 sev=low blast=wide effort=S verdict=actionable - deny.toml's licence confidence-threshold sits at 0.8, below the rust-supply-chain skill's 0.9 floor, so licences the tool is guessing at(~80% confidence) pass the gate silently,and rare allow-listed licences(CDLA-Permissive-2.0, Unicode-DFS-2016) may be the reason the bar was lowered - fix: raise to 0.9 (and move any failing allow-listed licence to a per-crate `[licenses.exceptions]` entry with the reason attached, per DENY.md),verifying against the vendored tree at the next flake check - [deny.toml:21] - evidence: static posture read: deny.toml sets confidence-threshold = 0.8 with no exceptions list; the skill's starter keeps it at>=0.9; decision: raise + exceptions, verify at next flake check - -## Coverage -- supply: 19 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md b/docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md deleted file mode 100644 index 31ae7e42b..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/X2-generated-boundary.md +++ /dev/null @@ -1,45 +0,0 @@ -# X2-generated-boundary - generated boundary -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 19,223 (12,629 generated + 6,594 generator sources) | modules: generated files of d2bd, d2b-broker, d2b, d2b-contracts-resource, d2b-core, d2b-contracts, d2b-contracts-broker, d2b-contracts-zone-session, d2b-resource-api, d2b-audit; generator sources packages/xtask/src/{gen_broker_operations.rs, gen_layer_catalogs.rs, provider_registration_authority.rs, resource_type_authority.rs, service_catalog.rs, authority_common.rs, main.rs (gen-resource-proto/gen-resource-ttrpc), provider_crate_policy.rs (layout-check drift gate)} -Lenses: serde docs api type err - -Generator inventory (provenance headers cross-checked against `packages/xtask/src/provider_crate_policy.rs:6681-6696` GENERATOR_COMMANDS and the emitted-file headers): - -- `gen-broker-operations` (`packages/xtask/src/gen_broker_operations.rs`) emits `d2b-contracts-broker/src/generated/broker_operation_profiles.rs`, `d2b-contracts/src/generated/w3_broker_operations.rs`, `d2b-core/src/generated/broker_operation_authz.rs`, `d2b-broker/src/generated/broker_operation_catalog.rs` (plus `docs/reference/broker-operation-triage.md`, not Rust). -- `gen-layer-catalogs` (`packages/xtask/src/gen_layer_catalogs.rs`) emits `d2b/src/generated/{mod.rs,surface_catalog.rs}`, `d2b-audit/src/generated/{mod.rs,audit_catalog.rs}`, and `d2b-contracts-provider/src/v3/generated/telemetry_catalog.rs` (the last sits under `src/v3/generated/`, outside this lane's 10-crate scope; the per-crate lane owns it). -- `check-provider-crate-layout --fix` (layout authority `packages/xtask/src/provider_crate_policy.rs`; emission in `provider_registration_authority.rs`, `resource_type_authority.rs`, `service_catalog.rs`) emits `d2bd/src/generated/provider_registrations.rs`, `d2b-contracts/src/generated/v3_converted_resource_types.rs`, `d2b-core/src/generated/process_roles.rs`, `d2b-contracts-zone-session/src/generated/service_provider_catalog.rs`. -- `gen-resource-ttrpc` / `gen-resource-proto` (`packages/xtask/src/main.rs:162-166`, codegen at :355-400) invoke ttrpc-compiler 0.8.0 and rust-protobuf 3.7.2 to emit `d2b-resource-api/src/generated/d2b_resource_v3_ttrpc.rs` and `d2b-contracts-resource/src/generated/d2b_resource_v3.rs`; their `mod.rs` registries are hand-maintained (the provenance gate at provider_crate_policy.rs:6737-6738 exempts `mod.rs` from needing a producer). -- `gen-zone-schemas`/`gen-zone-nix-options`/`gen-nix-inventories`/`gen-semantic-service-schemas` emit Nix/JSON/docs only; no committed Rust. - -Include sites (the hand-written side each generated shape compiles into): `d2b-broker/src/catalog.rs:217`, `d2b-contracts-broker/src/broker_wire.rs:894`, `d2b-contracts/src/identity.rs:70` + `privileges_w3.rs:98`, `d2b-core/src/privileges.rs:685` + `processes.rs:217`, `d2bd/src/resource_plane_v3.rs:76`, `d2b-contracts-zone-session/src/v3/mod.rs:64`, `d2b-resource-api/src/generated/mod.rs` (module, not include). - -## serde -- clean: seed 1 (`derive\([^)]*(De)?[Ss]erialize`) over the 16 generated files = 1 hit, the only serde-bearing generated shape: `ProcessRole` in `packages/d2b-core/src/generated/process_roles.rs:11-14`, which follows the skill conventions (`rename_all = "kebab-case"` on the type, CamelCase variants with kebab wire names, `JsonSchema` alongside). The protobuf/ttrpc surfaces (`d2b_resource_v3.rs`, `d2b_resource_v3_ttrpc.rs`) carry `#[derive(PartialEq,Clone,Default)]` only and cross the wire via protobuf encoding - the boundary is the `.proto`, not serde attributes, so no serde finding applies. The generator-side input parse (`gen_layer_catalogs.rs` `BrokerOperationRow` with `#[serde(rename_all = "camelCase")]` reading `docs/reference/policy/broker-operations.json`) is generator-internal and correct. No `deny_unknown_fields`/`try_from`/`flatten`/hand-written `Deserialize` appears in emitted shapes. - -## docs -- clean: seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) over the 16 generated files: every public item emitted by a repo generator carries a contract doc comment with a one-line first sentence (`broker_operation_profiles.rs:7-9`, `broker_operation_catalog.rs:6-8`, `surface_catalog.rs:6-8` and every const/fn, `audit_catalog.rs`, `service_provider_catalog.rs`, `provider_registrations.rs`, `v3_converted_resource_types.rs`, `process_roles.rs` with every variant documented, `w3_broker_operations.rs` being a bare expression fragment included into the documented `all()` at `privileges_w3.rs:97-99`). The ttrpc file carries `#![allow(missing_docs)]` (`d2b_resource_v3_ttrpc.rs:5`); the protobuf file carries no docs - both are external-compiler output, not repo-generator-controlled, and the emitted `mod.rs` registries carry module docs (`//!`). Only cosmetic drift found: two doc lines with trailing whitespace in `process_roles.rs:37,48` (generator emits them from the declaration comments); below finding threshold. - -## api -- X2-generated-boundary#1 sev=medium blast=leaf effort=S verdict=actionable - the hand-maintained registry `d2b-resource-api/src/generated/mod.rs:3-4` glob-re-exports the entire protobuf module (`pub use d2b_contracts_resource::resource_proto::*;`) as public surface of d2b-resource-api, exposing 47 items including reflection internals (`file_descriptor()` at `d2b_resource_v3.rs:7522`, `special_fields: ::protobuf::SpecialFields` on every message) and forcing `pub use protobuf;` at `d2b-resource-api/src/lib.rs:24` - with zero consumers - fix: delete the `d2b_resource_v3` re-export module from the registry (consumers use `d2b_contracts_resource::resource_proto` directly, e.g. `adapter.rs:560,578`); if a consumer ever needs the types through this crate, re-export named arms instead of a glob - [packages/d2b-resource-api/src/generated/mod.rs:3-4, packages/xtask/src/main.rs:355-370, packages/d2b-resource-api/src/lib.rs:24] - evidence: census: `generated::d2b_resource_v3` over packages/ = 0 hits (only `generated::d2b_resource_v3_ttrpc` is consumed: adapter.rs:24, d2bd/src/resource_runtime.rs:10274, d2bd-runtime/src/guest_component_session.rs:456-457); seed 3 (`^\s*pub use `) = 1 glob arm in the registry -- X2-generated-boundary#2 sev=low blast=leaf effort=S verdict=actionable - `d2b-audit/src/lib.rs:7` declares `pub mod generated;` but every consumer of the emitted catalog is in-crate (`crate::generated::audit_catalog::...` at record_types.rs:1038,1067,1212,1297,1367) - fix: `mod generated;` (private) in lib.rs; the emitted file and its registry need no change - [packages/d2b-audit/src/lib.rs:7, packages/xtask/src/gen_layer_catalogs.rs:725, packages/d2b-audit/src/generated/audit_catalog.rs:6-8] - evidence: census: `d2b_audit::generated` over packages/ (excluding d2b-audit itself) = 0 hits; seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) = 1 pub mod arm in lib.rs - -## type -- X2-generated-boundary#3 sev=medium blast=family effort=M verdict=actionable - the broker catalog view emits the authz facets as string literals (`secret_access: "None"`, `broker_required: "Yes"`, `audit_mode: "Yes"` at `broker_operation_catalog.rs:25-27` and every row) into the hand-written `BrokerAuthzFacets` struct whose fields are `&'static str` (`catalog.rs:98-102`), while the same generator emits the same declared data as typed enums in the sibling authz view (`SecretAccess::None`, `BrokerRequirement::Yes`, `AuditMode::Yes` at `broker_operation_authz.rs:12-19`); the broker-composition router string-matches the facet (`row.authz.secret_access != "None"` at routing.rs:98) and a hand-written row already drifts case (`audit_mode: "yes"` at `d2b-broker/src/envelope/mod.rs:2277` vs generated "Yes") - fix: change `BrokerAuthzFacets.secret_access/broker_required/audit_mode` to the existing `SecretAccess`/`BrokerRequirement`/`AuditMode` enums (`d2b-core/src/privileges.rs:48,61,83`; d2b-broker already depends on d2b-core per Cargo.toml:48) and make `generate_catalog` emit enum idents exactly as `generate_authz` already does - [packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-broker/src/catalog.rs:98-102, packages/d2b-broker-composition/src/routing.rs:98, packages/d2b-broker/src/envelope/mod.rs:2277] - evidence: seed 3 (`(mode|kind|state): String`) class: `&'static str` facet fields at catalog.rs:98-102; distinct emitted values: secret_access 4, broker_required 1, audit_mode 2; case drift "yes" vs "Yes" at envelope/mod.rs:2277 -- X2-generated-boundary#4 sev=medium blast=leaf effort=S verdict=actionable - `BrokerOperationRow.disposition` is `&'static str` (`catalog.rs:181`) holding a closed 4-value set emitted by the generator (`disposition: "promoted-live"` etc. at `broker_operation_catalog.rs:17` and 97 more rows), string-matched at catalog.rs:590,773,779,791 and runtime.rs:12562, while the same generator already maps every other closed set to enums (`owner_variant`, profile match, `StubTarget`) - fix: add a `Disposition` enum (four variants: callable-read-only, promoted-live, stubbed-unimplemented, compile-time-only) beside `StubTarget` in `d2b-broker/src/catalog.rs:266`, change the struct field, and have `generate_catalog` emit `Disposition::X` like `owner_variant` - [packages/xtask/src/gen_broker_operations.rs:949, packages/d2b-broker/src/generated/broker_operation_catalog.rs:17, packages/d2b-broker/src/catalog.rs:181, packages/d2b-broker/src/catalog.rs:590, packages/d2b-broker/src/runtime.rs:12562] - evidence: seed 3 class: `disposition: "` = 98 hits in the emitted file; distinct values = 4 (callable-read-only 4, promoted-live 85, stubbed-unimplemented 8, compile-time-only 1) -- X2-generated-boundary#5 sev=low blast=family effort=L verdict=actionable - the operation-name vocabulary is emitted as strings (`HOST_OPERATION_CATALOG`/`GUEST_OPERATION_CATALOG: &[&str]` at `broker_operation_profiles.rs:8-41`, `operation: "Hello"` at `broker_operation_catalog.rs:11`) and admission is a string `contains` (`BrokerProfile::allows_operation` at `d2b-contracts-broker/src/broker_wire.rs:864-889`), while the same generator emits the w3 subset as the typed `W3BrokerOperation` enum (`w3_broker_operations.rs`, re-exported at `d2b-contracts-broker/src/lib.rs:11`) - fix: have `generate_profiles`/`generate_catalog` emit a full closed `BrokerOperationName` enum (all 98 rows, not just the 24 w3 variants) with `as_str`, and type the catalogs and row `operation` field against it; the wire boundary keeps the string spelling via `as_str` - [packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11, packages/d2b-contracts-broker/src/broker_wire.rs:864-889] - evidence: seed 3 class: `&[&str]` catalogs at broker_operation_profiles.rs:8,41; `operation: "` = 98 hits in broker_operation_catalog.rs; typed sibling `W3BrokerOperation::all()` = 24 variants -- X2-generated-boundary#6 sev=low blast=leaf effort=S verdict=actionable - the authz view's positional `row)...)` helper calls carry a bare boolean at argument 5 (`false`/`true` for `destructive` at `broker_operation_authz.rs:12-19` and every row), the boolean-trap shape the type lens names, in a 988-line generated file where the field is the routing-relevant facet (`row.authz.destructive` at routing.rs:98) - fix: emit `Destructive::No`/`Destructive::Yes` (or named-field construction) from `generate_authz` and drop the `#[allow(clippy::too_many_arguments)]` on the hand-written `row()` helper at `d2b-core/src/privileges.rs:687-708` - [packages/xtask/src/gen_broker_operations.rs:891, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19, packages/d2b-core/src/privileges.rs:687-708] - evidence: seed 2 (`is_\w+: bool|\w+_flag: bool`) class: bare `false,`/`true,` positional args = 98 occurrences in the emitted authz file - -## err -- clean: seed 1 (`\.unwrap\(\)|\.expect\(`) over the 16 generated files = 47 hits, all in `d2b-contracts-resource/src/generated/d2b_resource_v3.rs` descriptor accessors (`descriptor.get(|| file_descriptor().message_by_package_relative_name("...").unwrap())`) - rust-protobuf 3.7.2 standard output on literal names that cannot fail, external-compiler-controlled, not a repo-generator shape. No repo generator emits error shapes into code; the only generated error surface is the protobuf `ResourceError`/`ResourceErrorKind` wire taxonomy (`d2b_resource_v3.rs:1512,7088`), a typed 32-kind enum with `from_i32 -> Option` fail-closed conversion - the err lens's ideal wire shape. Generated lookups fail closed (`provider_ref`/`provider_ref_for_service` at `service_provider_catalog.rs:18-42`, `typed_noun_type`/`admits_*` at `surface_catalog.rs`/`audit_catalog.rs` all return `Option`/`bool`, never panic). The string-facet comparisons in X2-generated-boundary#3/#4 are the only error-adjacent risk (a misspelled facet silently changes an admission decision) and are tracked there. - -## Coverage -- serde: clean (seeds ran: 1 serde derive across 16 generated files, process_roles.rs only, follows rename_all/JsonSchema conventions; protobuf/ttrpc surfaces use protobuf encoding, not serde) -- docs: clean (seeds ran: every emitted pub item carries a contract doc; ttrpc/protobuf external output carries allow(missing_docs)/no docs by compiler design; only trailing-whitespace drift in process_roles.rs:37,48) -- api: 2 finding(s) -- type: 4 finding(s) -- err: clean (seeds ran: 47 unwrap hits, all rust-protobuf descriptor accessors on literal names, external-compiler output; no repo-generator error shapes; generated lookups fail closed) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md b/docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md deleted file mode 100644 index 45d4ae18b..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/X3-cross-crate-duplication.md +++ /dev/null @@ -1,44 +0,0 @@ -# X3-cross-crate-duplication - cross-cutting duplication -Baseline: 6ebdd4cec | LOC audited: n/a (consumes lane files) | modules: lane corpus -Lenses: cross-crate classes (consumes crate-lane findings) - -## test - -- X3-cross-crate-duplication#1 sev=medium blast=family effort=L verdict=actionable - Provider test-support recorder/harness duplication: each provider crate hand-rolls the same recorder-double family (RecordingEffects/ScriptedProbe/RecordingManager/RecordingRequeue-style recording doubles, ScriptedPort/ScriptedDiscoveryPort/ScriptedEffectPort scripted ports, hand-rolled block_on pollers, TicketBuilder-style fixtures) in its own test_support.rs/testing.rs instead of the toolkit's shipped harness - fix: consolidate the recorder/harness shapes onto `d2b-provider-toolkit/src/testing` (TestHarness at testing/mod.rs:397, fakes.rs, fixture.rs, conformance.rs) and have the family crates reuse it; the toolkit module is the B3-kept base, so this does not re-propose the B3 refusal - [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-device-security-key/src/test_support.rs:32, packages/d2b-provider-device-usbip/src/test_support.rs:25, packages/d2b-provider-volume-local/src/testing.rs:1, packages/d2b-provider-system-core/src/testing.rs:23, packages/d2b-process-conformance/src/testing.rs:60, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129] - evidence: contributing lanes: d2b-provider-credential#4 (its evidence names the family-wide pattern across d2b-provider-device/-endpoint/-guest/-network-local/-process/-usbip/-activation-nixos test_support modules, "X3 candidate"), d2b-provider-guest#3, d2b-provider-user#3, d2b-provider-volume-binding#4, d2b-provider-device-security-key#5, d2b-provider-device-usbip#8, d2b-provider-volume-local#3, d2b-provider-system-core#4, d2b-process-conformance#5, d2b-provider-guest-qemu-media#5; parser over 109 lane files (1014 findings); source re-check: toolkit testing module exists (mod.rs:397 TestHarness, clock at 530), member anchors verified at the cited lines -- X3-cross-crate-duplication#2 sev=low blast=family effort=S verdict=actionable - Test-support shipping shape: `test-support` features declared empty and gating nothing in four declaration crates while three provider crates ship `pub mod testing` (ScriptedPort/block_on harnesses) unconditionally in the production library and d2b-resource-types exports a test-only helper through the root despite declaring the feature - fix: wire each `test-support = []` feature to its module (`#[cfg(feature = "test-support")]` on `pub mod testing`, `#[cfg(feature = "test-support")]` on `assert_metadata_registration`) or drop the empty features, following the house pattern at d2b-provider-host/Cargo.toml:28 - [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-volume-local/src/lib.rs:46, packages/d2b-provider-system-core/src/lib.rs:41, packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-resource-types/src/lib.rs:30] - evidence: contributing lanes: tail-3#3/#5/#6/#8 (census: declared empty in 4 tail-lane crates, enabled by no manifest), d2b-provider-volume-local#3, d2b-provider-system-core#4, d2b-process-conformance#5, tail-6#3; prior audit deferred the class at docs/explanation/over-engineering-audit-record.md:916; source re-check: quota Cargo.toml:17 `test-support = []`, volume-local/system-core/process-conformance `pub mod testing` at lib.rs:46/41/38, host feature at Cargo.toml:28 - -## conc - -- X3-cross-crate-duplication#3 sev=medium blast=wide effort=S verdict=policy-confirmed - parking_lot::Mutex::lock enforcement gap: the clippy disallowed-methods entry (clippy.toml:82) and the blocking-census baseline (packages/xtask/data/blocking-census-baseline.json, `parking_lot::Mutex::lock: 0` for every crate) key on the path `parking_lot::Mutex::lock`, which never resolves because `parking_lot::Mutex` is a type alias (`pub type Mutex = lock_api::Mutex`), so unsuppressed lock sites in 10+ crates record zero hits and no per-site allow is demanded - fix: configure the disallowed entry and the census DeniedApi list on the resolved path (`lock_api::Mutex::lock`, or the def-path clippy reports for the alias), then re-run the census so the unsuppressed sites surface and get per-site allows or conversions per the KD3 ban - [clippy.toml:82, packages/xtask/data/blocking-census-baseline.json:13, packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-user/src/test_support.rs:41, packages/d2b-provider-process/src/driver.rs:680, packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2b-resource-runtime/src/context.rs:800] - evidence: contributing lanes (each independently found the 0-vs-source mismatch): d2b-provider-credential#4, d2b-provider-device-gpu#11, d2b-provider-device-security-key#5, d2b-provider-device-usbip#8, d2b-provider-guest#3, d2b-provider-process#5, d2b-provider-user#3, d2b-provider-volume-binding#4, d2b-resource-runtime-p2#15, d2bd-runtime-p3#10, tail-2#3; parser over 109 lane files; source re-check: clippy.toml:82 entry present, parking_lot-0.12.5/src/mutex.rs:86 alias, baseline rows all 0 for crates with 14+ lock sites; verdict policy-confirmed because the fix changes gate configuration (KD3 ban policy at clippy.toml:40-43 stays) - -## serde - -- X3-cross-crate-duplication#4 sev=medium blast=family effort=L verdict=actionable - Parallel serde shims: contract/provider crates hand-write the identical Wire-struct admission shape (private `#[derive(Deserialize)]` Wire with deny_unknown_fields, then new()/TryFrom with validation) in 24+ impls where the in-tree `parsed_deserialize!` macro exists - fix: consolidate behind `parsed_deserialize!` (d2b-contracts-resource/src/v3/execution_policy.rs:33, re-exported at :63) or `#[serde(try_from = "...")]` with the raw Wire shape, keeping every admission gate; this deduplicates boilerplate and is distinct from the refused gate-removal class (over-engineering-audit-record.md rows 25/33 refused replacing gates with derives) - [packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558, packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs:101, packages/d2b-contracts-zone-session/src/v3/zone.rs:79, packages/d2b-contracts-zone-session/src/v3/role_binding.rs:192, packages/d2b-contracts-zone-session/src/v3/services.rs:265, packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs:176, packages/d2b-contracts-control/src/unsafe_local_wire.rs:118, packages/d2b-contracts-control/src/public_wire.rs:2228, packages/d2b-provider-display-wayland/src/spec.rs:263, packages/d2b-provider-display-wayland/src/policy.rs:194, packages/d2b-provider-endpoint/src/endpoint.rs:197] - evidence: contributing lanes: d2b-contracts-zone-session-p2#8 (17 impls, names parsed_deserialize! as the canonical home), d2b-contracts-control#9 (3 impls + Wire shadow structs), d2b-provider-display-wayland-p2#8 (3 impls), d2b-provider-endpoint#3 (sibling hand-written gate); ledger C4 "Contract-crate macro/boilerplate consolidation" is not-applied with no refusal reason (over-engineering-audit-record.md C-tier); parser over 109 lane files; source re-check: execution_policy.rs:33 macro exists, zone_routing.rs:558 `impl<'de> Deserialize<'de> for ZoneTreeEdge`, endpoint.rs:197-216 hand-written gate - -## type - -- X3-cross-crate-duplication#5 sev=high blast=family effort=M verdict=actionable - Driver-args zone class: six provider-family crates carry `zone: String` on their public driver args and re-parse it with a per-pass expect at construction (one member, d2b-provider-wayland-policy, panics on caller input at the family engine's public boundary) - fix: type the args field as `d2b_contracts_resource::v3::ZoneId` (or a `BoundedToken`) in each `*DriverArgs` and parse once at the daemon construction boundary, with `SharedProviderDriverArgs` in d2b-provider-toolkit as the shared home the family args mirror - [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-volume/src/driver.rs:246] - evidence: contributing lanes: d2b-provider-wayland-policy#1 (sev=high: `ZoneId::parse(args.zone).expect` on pub constructor), d2b-provider-volume-binding#1 (per-pass `BoundedToken::parse(...).expect` at driver.rs:426-427), d2b-provider-toolkit-p2#7 (`ZoneId::parse(args.zone).expect("driver zone was validated at construction")`), d2b-provider-credential#2, d2b-provider-guest#1, d2b-provider-volume#4 (zone never read); parser over 109 lane files; source re-check: all six `pub zone: String` fields and the three expect sites verified at the cited lines - -## err - -- X3-cross-crate-duplication#6 sev=medium blast=wide effort=M verdict=needs-contract - Parallel error enums flattening sources into String payloads: six crates declare error variants that collapse the underlying error into a Display string (`Io { path, detail: String }`, `Io(String)`, `Frame(String)`, `ManagerRpc(String)`, `TypedError::InternalIo { context, detail }`, five `String` variants of PlaneError, `kind: String` in four Io variants), destroying the source chain so diagnostics and callers cannot distinguish failure classes - fix: carry the source with thiserror `#[from]`/`source()` in each enum (no in-tree helper exists; the std Error source chain is the canonical home); wire-visible members (d2bd TypedError) need contract sign-off before the shape changes, internal members (broker, clipboard, azure-relay, resource-runtime, d2bd-runtime vsock) are actionable first - [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69, packages/d2b-resource-runtime/src/error.rs:773, packages/d2bd/src/composition.rs:13894, packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/audio_dispatch.rs:487, packages/d2bd-runtime/src/component_session_vsock.rs:32] - evidence: contributing lanes: d2b-broker-p1#2 (12 conversion sites), d2b-broker-p5#3 (3 map_err sites), d2b-provider-clipboard-wayland-p2#12 (6 to_string() sites), d2b-provider-transport-azure-relay#8 (From impls discard source), d2b-resource-runtime-p1#6, d2bd-p2#6, d2bd-p6#3, d2bd-p8#9 (verdict needs-contract on TypedError), d2bd-runtime-p1#3; parser over 109 lane files; source re-check: all nine variant declarations verified at the cited lines - -## own - -- X3-cross-crate-duplication#7 sev=medium blast=family effort=M verdict=actionable - Repeated ownership pattern: public signatures and fields across eight crates leak `Arc`/`&Arc` (accessors returning `&Arc`, constructors taking `Arc` where single ownership suffices, pub fields carrying `Arc>`), forcing callers to see refcount plumbing and blocking signature evolution - fix: return `&T`/owned values and take owned parameters per the ownership-not-clone convention (canonical home is the borrow/owned convention; no shared type involved, so the merge target is per-crate signatures) - [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:491, packages/d2b-provider-toolkit/src/testing/mod.rs:530, packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343, packages/d2b-provider-device-usbip/src/broker.rs:131, packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs:211, packages/d2bd-runtime/src/shell_backend.rs:52, packages/d2b-provider-device/src/driver.rs:128] - evidence: contributing lanes: d2bd-p6#2 (four `&Arc` accessors), d2b-resource-runtime-p2#9 (`&Arc`), d2b-provider-toolkit-p2#6 (`&Arc`), d2b-provider-supervisor#3 (`Arc`), d2b-provider-transport-azure-relay#7 (`Arc`), d2b-provider-device-usbip#4 (returns `Arc>`), d2b-provider-device-gpu#7 (pub Arc fields), d2b-provider-guest-azure-virtual-machine#10 (`Arc` param), d2bd-runtime-p1#4 (`pub backend: Arc`), tail-2#3 (pub `Arc>` fields); parser over 109 lane files; source re-check: all ten signatures verified at the cited lines - -## api - -- X3-cross-crate-duplication#8 sev=low blast=family effort=S verdict=actionable - Double-path public surface: eleven crates expose every item of a module at two public paths (`pub mod x` plus root `pub use x::*` or item re-exports), deviating from the house single-surface convention and letting future pub items silently widen API - fix: keep one public path per item (either the module or the root re-export, per the house single-surface pattern the d2b-sk-frontend lane names), deleting the duplicate arm in each lib.rs - [packages/d2b-provider-device-usbip/src/lib.rs:24, packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-zone/src/lib.rs:17, packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-process-conformance/src/process_provider.rs:9, packages/d2b-provider-device-gpu/src/lib.rs:14, packages/d2b-provider-device-security-key/src/lib.rs:16, packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:13, packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-system-core/src/lib.rs:40, packages/d2b-provider-guest-azure-container-apps/src/lib.rs:14] - evidence: contributing lanes: d2b-provider-device-usbip#3, tail-4#2, tail-5#11, tail-6#4, d2b-process-conformance#4, d2b-provider-device-gpu#6, d2b-provider-device-security-key#2, d2b-provider-display-wayland-p1#8, d2b-provider-process-systemd#4, d2b-provider-system-core#5, d2b-provider-guest-azure-container-apps#8; parser over 109 lane files; source re-check: `pub mod` + root `pub use` pairs verified at the cited lib.rs lines (zone lib.rs:17+21, seccomp lib.rs:19+22, sk-frontend lib.rs:22-29) - -## Coverage -- classes: 8 finding(s) -- corpus: 109 lane files consumed (107 crate lanes + X1-supply-chain + X2-generated-boundary), enumerated via .scratch/parse_lanes.py (1014 findings extracted; 3 pre-existing anchor-shape violations in d2b-core-p1/d2b-provider-volume-local/tail-2 belong to the lane corpus, not this lane); member anchors re-verified in source at baseline 6ebdd4cec; no crate code re-audited from scratch \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md deleted file mode 100644 index 1df8ec86d..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-audit.md +++ /dev/null @@ -1,88 +0,0 @@ -# d2b-audit - d2b-audit -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5221 (excl. src/generated/**) | modules: evidence_chain, export, hash_chain, lib, operation, rate_limit, reconcile, record_types, segment, sink -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-audit#1 sev=medium blast=leaf effort=S verdict=actionable - `read_bounded_line` is copy-pasted three times with only the error-code strings differing ("audit-export-line-*" / "audit-segment-line-*" / "audit-scan-line-*") - fix: extract one crate-private `read_bounded_line` (canonical home: a shared module or segment.rs) taking the line-limit/truncated error codes as parameters, and delete the two copies - [packages/d2b-audit/src/export.rs:255, packages/d2b-audit/src/segment.rs:980, packages/d2b-audit/src/sink.rs:421] - evidence: idiom seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 9 hits; manual read found 3 verbatim ~30-line copies of the same bounded reader differing only in error strings -- d2b-audit#2 sev=low blast=leaf effort=S verdict=actionable - `paths.retain)...)` in `export_segments_range` re-applies `is_segment_name` to every path the read_dir loop already filtered, a redundant pass over the directory listing - fix: delete the `paths.retain` block (export.rs:103-110); the push guard at export.rs:94-102 is the only filter needed - [packages/d2b-audit/src/export.rs:103] - evidence: manual read of export_segments_range; both the loop guard (export.rs:94-102) and the retain (export.rs:103-110) apply the same `is_segment_name` predicate -- d2b-audit#3 sev=low blast=leaf effort=S verdict=actionable - `scan_chain_state` re-invokes `record.mutation_id()` and `record.zone_operation_key()` inside the block whose outer `if let` already bound them, re-deriving two SHA-256 identities per mutation record during the startup scan - fix: use the outer bindings for the `mutation_predecessors` insert, deleting the inner `if let` (sink.rs:403-410) - [packages/d2b-audit/src/sink.rs:393, packages/d2b-audit/src/sink.rs:403] - evidence: manual read of scan_chain_state; inner if-let at sink.rs:403-410 shadows `mutation_id`/`key` bound at sink.rs:393-394, recomputing `zone_operation_key()` (two digest derivations) -- clean: seeds ran: 5/0/9; the 5 index loops are all test loops (evidence_chain.rs:282, rate_limit.rs:87, segment.rs:1250/1528, sink.rs:503), seed 2 is 0 (no hand-written Default/From/PartialEq/Eq/Clone/Hash impls; the redacting Debug impls use `core::fmt::Debug` paths), and the 9 `Vec::new()` sites are bounded readers/collectors of unknown size - -## own -- d2b-audit#4 sev=low blast=leaf effort=S verdict=actionable - `OperationIdentity::parse` calls `AuditHash::parse(value.to_owned())`, allocating a String though `AuditHash::parse` takes `impl Into` and `&str: Into` holds - fix: pass `value` directly (`AuditHash::parse(value)`) - [packages/d2b-audit/src/operation.rs:79] - evidence: own seed 2 `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = ~100 hits (mostly test fixtures); `AuditHash::parse(value: impl Into)` at packages/d2b-telemetry/src/audit_hash.rs:23 accepts `&str` without allocation -- clean: seeds ran: 55/~100/0/0; every production `.clone()` is explainable (AuditHash is a `String`-wrapped newtype, not Copy - owned values require clone; `EvidenceChain::nested` clones to build the appended chain; sink/segment map and index clones are required by the owned key shapes), seeds 3-4 are 0 real hits (the 8 `Rc<` substring matches are `Arc` fields of the test-only `FailureInjector`) - -## type -- d2b-audit#5 sev=medium blast=wide effort=S verdict=actionable - `EvidenceChain` derives `Deserialize` (evidence_chain.rs:50) while its accessors assume a non-empty identity list: `invoking_identity()` panics via `.last().expect)...)`, `initiating_identity()` indexes `&self.identities[0]`, and `depth()` underflows on `len() - 1`; the "identities never empty" invariant is enforced only by the constructors, so a wire payload with `"identities": []` deserializes into the illegal state - fix: hand-write `Deserialize` for `EvidenceChain` rejecting an empty `identities` (the crate's own admission-gate pattern in operation.rs), or make the accessors total - [packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115, packages/d2b-audit/src/evidence_chain.rs:121, packages/d2b-audit/src/evidence_chain.rs:102] - evidence: manual read; census: `EvidenceChain` over packages/d2b-broker, packages/d2bd, packages/d2bd-runtime = 30 hits, all `root()`/`nested()` construction (e.g. d2b-broker/src/envelope/mod.rs:1152, d2bd/src/forward_rendezvous.rs:650), zero deserialize sites; panic is not reachable from current callers but the parse boundary admits the state -- clean: seeds ran: 7/0/0; the `validate_*` hits are filesystem-metadata and closed-domain checks at the wire boundary (validate_fields record_types.rs:1036 is the parse-once admission gate over the generated audit_catalog vocabulary; segment.rs validate_* are inode/ownership checks), `update_state`/`disruption` strings mirror the pinned wire schema, and `evidence_from_decision_result` string-matching is the wire-boundary parse into typed `DurabilityOutcome` - -## api -- d2b-audit#6 sev=medium blast=leaf effort=M verdict=actionable - the crate re-exports a large surface with zero external consumers: `sink` (AuditSink/AuditSinkError/AuditWriteOutcome), `segment` (SegmentWriter/FailureInjector/FailurePoint/DEFAULT_MAX_SEGMENT_BYTES/DEFAULT_RETENTION_DAYS), `export` (ExportLine/export_segments/export_segments_range/MAX_EXPORT_*), `rate_limit` (AuditRateLimiter/AuditWriteClass/RateDecision/DEFAULT_AUDIT_WRITES_PER_SECOND), `record_types` (AuditRecord/AuditRecordFields/*Fields/AuditRecordError/AUDIT_SCHEMA_VERSION), and `reconcile`'s `reconcile`/`Reconciliation`/`DurabilityOutcome` are all exported from lib.rs:16-46 but no dependent crate references them; consumers (d2b-broker, d2bd, d2bd-runtime, d2b-session) use only evidence_chain, operation, hash_chain, and `evidence_from_decision_result`/`DurabilityEvidence` - fix: either wire the daemon-side audit writer (d2bd-runtime daemon_audit) to the sink/segment/export stack, or reduce the unwired modules to `pub(crate)` until a consumer exists (crate is `publish = false`) - [packages/d2b-audit/src/lib.rs:16, packages/d2b-audit/src/lib.rs:30, packages/d2b-audit/src/lib.rs:33, packages/d2b-audit/src/lib.rs:37, packages/d2b-audit/src/lib.rs:43] - evidence: census: `d2b_audit::(AuditRecord|record_types|sink|segment|export|rate_limit|reconcile_durability|Reconciliation|DurabilityOutcome|AuditSink|SegmentWriter|FailureInjector|AuditRateLimiter|export_segments|MAX_EXPORT_*)` over the 4 dependent crates (packages/d2b-broker, packages/d2bd, packages/d2bd-runtime, packages/d2b-session) = 0 hits; consumed surface is d2b-broker/src/audit.rs:27, runtime.rs:7122, ops/audit_op.rs:10, d2bd/src/forward_rendezvous.rs:78 -- d2b-audit#7 sev=low blast=leaf effort=S verdict=actionable - `pub use d2b_telemetry::TraceContext;` (lib.rs:16) re-exports a foreign type that nothing in the crate or any dependent references - fix: drop the re-export (or adopt TraceContext in the record envelope if it is meant to be the trace carrier) - [packages/d2b-audit/src/lib.rs:16] - evidence: census: `d2b_audit::TraceContext` over packages/ = 0 hits; `TraceContext` appears nowhere in src/ except the re-export line (record_types uses `d2b_telemetry::canonical_export_id` directly) -- clean: seeds ran: ~145/0/12; every pub item carries a doc comment, no Arc/Rc/Box/RefCell appears in a public signature, and the `pub use` arms in lib.rs:16-46 are the house single-surface pattern (all consumed except the two findings above) - -## err -- d2b-audit#8 sev=medium blast=leaf effort=S verdict=actionable - `export_segments_range` classifies a failed `AuditRecord` deserialize by string-matching the serde error's Display (`error.to_string().contains("audit-record-hash-mismatch")`) to pick the "hash-break" export error code; a reworded deserialize message silently reclassifies a chain break as "record-invalid" - fix: split parse from verification (deserialize into a wire shape, then `verify()` to surface `AuditRecordError::HashMismatch`), or have the `Deserialize` impl expose the failure class; the emitted `error_code` strings stay unchanged - [packages/d2b-audit/src/export.rs:230] - evidence: err seed 1 `\.unwrap\(\)|\.expect\(` = 3 production hits (all invariant expects: evidence_chain.rs:121, record_types.rs:367/922) plus test unwraps; `AuditRecordError::HashMismatch` variant exists at record_types.rs:887 and is the type the string names -- d2b-audit#9 sev=medium blast=leaf effort=S verdict=actionable - `is_discardable_checkpoint_scratch_error` classifies `io::Error` by matching `error.to_string().as_str()` against three literal codes ("audit-retention-checkpoint-invalid" / "-limit" / "-unverifiable") produced by `io::Error::other` at the checkpoint read/validate sites; a reworded code silently changes the discard decision on restart - fix: introduce a private checkpoint-read error enum (or a sentinel error kind) and match on it, keeping the io::Error strings at the public boundary - [packages/d2b-audit/src/segment.rs:694, packages/d2b-audit/src/segment.rs:628, packages/d2b-audit/src/segment.rs:718] - evidence: manual read; the three literal strings are created at segment.rs:628-630 and segment.rs:718-747 and matched verbatim at segment.rs:694-699 -- clean: seeds ran: 3 production/40 test, 5 production `let _ =`, 1 test-only `unreachable!`, 4 error enums; the production expects name invariants (identities never empty, bounded identity, literally-built serde values), the `let _ =` sites are deliberate best-effort cleanups (rollback_append segment.rs:273, prune_old segment.rs:302, rotate cleanup segment.rs:470-471, checkpoint repair segment.rs:817), and the four error enums (OperationIdentityError, EvidenceError, AuditRecordError, AuditSinkError) are closed with stable Display codes - -## serde -- clean: seeds ran: 18/26/4/11; all wire structs use `rename_all = "snake_case"` + `deny_unknown_fields`, optionality is correct (`#[serde(default, skip_serializing_if = "Option::is_none")]` on mutation_id/mutation_ordinal, `#[serde(default)]` on backward-compat checkpoint fields), and the four hand-written `Deserialize` impls (OperationIdentity, ZoneId, ZoneOperationKey, AuditRecord) are live admission gates - the recorded-refusal class (docs/explanation/over-engineering-audit-record.md, hand-written Deserialize admission gates); the AuditRecord gate re-verifies the record hash on every read - -## obs -- clean: seeds ran: 0/0/0/5; the 5 `tracing::|log::` hits are `audit_catalog::` substrings (e.g. record_types.rs:1038, 1067), not telemetry; the crate has no println, no tracing/log macros, and no logging dependency - the crate is a library that returns errors instead of logging - -## docs -- d2b-audit#10 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors`/`# Examples` sections exist anywhere in the crate although ~50 `-> Result<` sites include the public API (export_segments_range, AuditRecord::new/verify/zone_operation_key, evidence_from_decision_result, AuditSink::open/append/prune_old, SegmentWriter::open/append, OperationIdentity::derive/parse); failure conditions are described in prose but not under the section a caller scans for - fix: add `# Errors` sections naming the AuditRecordError/AuditSinkError/EvidenceError variants on the Result-returning pub items and `# Examples` on the non-obvious constructors (AuditRecord::new, SegmentWriter::open) - [packages/d2b-audit/src/export.rs:74, packages/d2b-audit/src/record_types.rs:428, packages/d2b-audit/src/reconcile.rs:54, packages/d2b-audit/src/sink.rs:175] - evidence: docs seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; docs seed 3 `-> Result<` = 50 hits; every pub item has a first-sentence doc comment (seed 1 ~145 hits, none undocumented) -- clean: seeds ran: ~145/0/50; module docs present everywhere, every pub item documented with a strong first sentence, no `ignore`d doctests (none exist) - -## perf -- d2b-audit#11 sev=low blast=leaf effort=S verdict=actionable - `scan_chain_state` converts each line with `String::from_utf8(bytes)` then `serde_json::from_str`, allocating a String per record during the open-time scan, while `segment_tail_hash` parses the same JSONL shape with `serde_json::from_slice(&line)`; use `from_slice` here too - fix: replace the from_utf8/from_str pair with `serde_json::from_slice(&bytes)` at sink.rs:386-388 - [packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970] - evidence: perf seed 1/3; static (unmeasured); cold path (startup scan) but a per-record allocation the sibling function already avoids -- clean: seeds ran: 13 format!/9 Vec::new()/~20 to_string(); the production `format!` sites are cold segment-naming and error paths (segment.rs:1007/1028/1039, export.rs:57), the `Vec::new()` sites are bounded readers of unknown size, and the `to_string()` hits are test fixtures and wire rendering; no format! in any loop - -## conc -- clean: seeds ran: 0/1/15/1; the single `Mutex` (sink.rs:66) guards a genuinely synchronous surface with policy-tracked `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` allows, the `AtomicBool` retention_degraded uses the correct Acquire/Release pair (segment.rs:334/343), the `Arc` slots are the test-only FailureInjector, and the `thread_local!` (record_types.rs:658) is the test-support serialization counter; no threads, no unsafe Send/Sync - -## async -- N/A (seeds: 0/0/0/0; no async fn, await, tokio, or spawn in the crate - the whole surface is synchronous by design) - -## unsafe -- N/A (seeds: 0/0/0/1; seeds 1-3 are all zero and the single seed-4 hit is `#![forbid(unsafe_code)]` at lib.rs:3, which per the card does not make the lens applicable; manifest has no unsafe_code setting but the crate-level forbid covers it) - -## ffi -- N/A (seeds: 0/0/0/0; no extern "C", no_mangle, repr(C), catch_unwind, or CStr anywhere; the libc/rustix uses are syscall wrappers inside the crate) - -## macro -- clean: seeds ran: 1/0/0/0; the single `macro_rules!` (impl_redacted_debug, record_types.rs:286) is legitimate impl-per-type generation for the 9 redacting Debug impls (a derive would leak record fields), uses the narrowest fragment specifier `$type:ty`, references no crate paths (no hygiene issue), and is not a proc-macro - -## test -- clean: seeds ran: 50/~200/0/0; no tests/ directory - all 50 tests are in-module `#[cfg(test)]` units covering behavior, not implementation: failure-injection loops over every FailurePoint (segment.rs:1265, sink.rs:561/605), restart/repair/rollback scenarios, idempotent replay, single-writer locking, wire-vector pins (operation.rs:325), redaction assertions (record_types.rs:1275), and a serialization-count behavior probe (sink.rs:516); deterministic timestamps, no network, no `#[ignore]`, no tautological assertions, and no property/snapshot tooling needed for this domain - -## Coverage -- idiom: 3 finding(s) -- own: 1 finding(s) -- type: 1 finding(s) -- api: 2 finding(s) -- err: 2 finding(s) -- serde: clean (seeds ran: 18/26/4/11; admission-gate Deserialize impls are the recorded-refusal class) -- obs: clean (seeds ran: 0/0/0/5; the 5 hits are `audit_catalog::` substrings of `log::`) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 0/1/15/1; synchronous-path Mutex with policy-tracked allows, correct atomic pair) -- async: N/A (seeds: 0/0/0/0; no async surface in the crate) -- unsafe: N/A (seeds: 0/0/0/1; seed 4 alone - `#![forbid(unsafe_code)]` lib.rs:3 - does not make the lens applicable) -- ffi: N/A (seeds: 0/0/0/0; no FFI surface) -- macro: clean (seeds ran: 1/0/0/0; impl_redacted_debug is legitimate impl-per-type generation) -- test: clean (seeds ran: 50/~200/0/0; no tests/ dir, behavior-focused unit mass, no ignored tests) -- supply-note: d2b-session declares `d2b-audit` (packages/d2b-session/Cargo.toml:17, BUILD.bazel:28) but no src/ or tests/ file references `d2b_audit` - directly evidenced unused dependency for lane X1 (census: `d2b_audit|d2b-audit` over packages/d2b-session = 4 hits, all in Cargo.toml/BUILD.bazel) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md deleted file mode 100644 index f5f74c017..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-composition.md +++ /dev/null @@ -1,84 +0,0 @@ -# d2b-broker-composition - d2b-broker-composition -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1634 (excl. src/generated/**; no tests/ dir exists, test lens covers inline #[cfg(test)] modules) | modules: whole crate (lib.rs, main.rs, routing.rs, seam.rs, dependency_surface.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- d2b-broker-composition#1 sev=low blast=leaf effort=S verdict=actionable - `workspace_root` walks up to four parent directories with a `for _ in 0..4` index loop and a mutable `current`, where the bounded walk is an iterator chain - fix: replace the loop with `std::iter::successors(Some(current), |c| c.parent()).take(4).find(|c| c.join("Cargo.toml").is_file() && c.join("packages").is_dir())` - [packages/d2b-broker-composition/src/dependency_surface.rs:136] - evidence: seed `for \w+ in 0\.\.` = 1 hit (dependency_surface.rs:136); the other idiom seed hits are `let mut violations = Vec::new()` (line 165), a side-effect accumulation with early continues where an iterator would obscure the dedup/sort tail - not a finding -- d2b-broker-composition#2 sev=low blast=leaf effort=S verdict=actionable - `state_cell` silences its deliberately unused parameter with `let _ = invocation;` instead of naming it as unused - fix: rename the parameter to `_invocation` and delete the `let _ = invocation;` line (the doc comment's "the invocation's row" is prose, not the parameter name) - [packages/d2b-broker-composition/src/seam.rs:270, packages/d2b-broker-composition/src/seam.rs:274] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1, seed `for \w+ in 0\.\.` = 1; `let _ =` site read at seam.rs:274 -- clean: seeds ran (1/0/1); no hand-written Default/From/PartialEq/Eq/Debug/Clone/Hash impls (all derives), no index loops over collections, naming discipline holds (`as_str` const fn, `is_clean`, no `get_`, free function `report_error` in main.rs) - -## own -- d2b-broker-composition#3 sev=low blast=leaf effort=S verdict=actionable - `audit_crate` iterates `&added` and clones every dependency name into the report fields, though `added` is dead after the loop - fix: consume it with `for name in added { ... report.forbidden_dependencies.push(name); ... report.proc_macro_dependencies.push(name); }` (passing `&name` to `is_proc_macro`), removing both clones - [packages/d2b-broker-composition/src/dependency_surface.rs:251, packages/d2b-broker-composition/src/dependency_surface.rs:255] - evidence: seed `\.clone\(\)` = 12 hits over src (10 dependency_surface.rs, 2 seam.rs test fixtures); sites read in full, `added` has no use after the loop -- d2b-broker-composition#4 sev=low blast=leaf effort=S verdict=actionable - the manifest scan checks `report.forbidden_dependencies.contains(&crate_name.to_string())`, allocating a fresh String per forbidden crate name (8 per audit run) for a membership test - fix: use `report.forbidden_dependencies.iter().any(|name| name == crate_name)` - [packages/d2b-broker-composition/src/dependency_surface.rs:272] - evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 8 hits; the other hits (report construction at 244, error messages at 321/332, `(*crate_name).to_owned()` at 274, `owner_name.to_owned()` at 351) are explainable owned values -- d2b-broker-composition#5 sev=low blast=leaf effort=M verdict=actionable - `dependency_tree` clones every node id into `queue` and `seen` although all ids borrow from `metadata` for the whole traversal - fix: type the traversal as `Vec<&str>` / `BTreeSet<&str>` (`let mut queue = vec![root_id];`, `seen.insert(id)`), leaving the returned `Vec` untouched - [packages/d2b-broker-composition/src/dependency_surface.rs:340, packages/d2b-broker-composition/src/dependency_surface.rs:343] - evidence: seed `\.clone\(\)` = 12 hits; queue/seen sites read; `reachable` keeps `to_owned()` because it is the return value -- clean: no Rc/RefCell/Arc/Arc/Cow (seeds 3-4 = 0); the two seam.rs `invocation.payload.clone()` sites are test-fixture handlers echoing the payload and are explainable - -## type -- clean: seeds ran (0/0/0); the crate declares structs and enums so the lens is applicable, but the refusal taxonomy is already enum-modeled (`RefusalClass`, `RoutingVerdict`, `RoutingRefusal`), `PureTransformClaim` is a private-field newtype with a constructor, and there are no boolean-flag or stringly-typed state fields to collapse - -## api -- clean: seeds ran (24/0/0); all 24 pub items audited - the surface is deliberate and single-path (lib.rs `pub mod` arms with doc comments, the house pattern), no Arc/Rc/Box/RefCell in any public signature, `PureTransformClaim`/`HandlerDeclaration`/`SurfaceReport` are documented data types, and the d2b-broker types in `HandlerDeclaration.handler` are the crate's reason to exist (composition root, publish = false), not a leak - -## err -- d2b-broker-composition#6 sev=low blast=leaf effort=S verdict=actionable - four public/private error returns are bare `Result<_, String>` (`verify_startup_routing`, `audit_crate`, `run_cargo_metadata`, `dependency_tree`), so a future caller that must distinguish failure classes (environment unavailable vs. cargo failure vs. invariant violation) can only string-match - fix: introduce a small typed error enum per module (the seam already owns `RoutingRefusal`; give `dependency_surface` an audit error enum with variants such as `WorkspaceUnavailable`/`CargoFailed`/`InvalidMetadata`) and return it from the cited functions - [packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/dependency_surface.rs:226, packages/d2b-broker-composition/src/dependency_surface.rs:292, packages/d2b-broker-composition/src/dependency_surface.rs:317] - evidence: seed `\.unwrap\(\)|\.expect\(` = 17 hits (13 inside #[cfg(test)] modules - repo false positive; 3 are `expect("static pattern compiles")` on literally-built regexes and 1 is the post-`route_row` invariant expect at seam.rs:238 - all justified); seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0; seed `enum \w*Error` = 0; the String-error shapes were read at the cited sites -- clean: no swallowed Results (`let _ = invocation;` at seam.rs:274 is a deliberately ignored parameter, not a dropped Result); panic policy is sound - the only non-test expect names the invariant the mechanical rule just established - -## serde -- d2b-broker-composition#7 sev=low blast=leaf effort=M verdict=actionable - `run_cargo_metadata` parses cargo's output into `serde_json::Value` and every consumer re-walks it with repeated `.get("packages")`/`and_then(as_array)`/`as_str` chains (`dependency_tree`, `package_name_of_id`, `is_proc_macro`), pushing the parse out of the boundary - fix: derive `Deserialize` on minimal `CargoMetadata`/`Package`/`ResolveNode` shapes and parse once in `run_cargo_metadata`, replacing the Value-walking chains with field access - [packages/d2b-broker-composition/src/dependency_surface.rs:308, packages/d2b-broker-composition/src/dependency_surface.rs:318, packages/d2b-broker-composition/src/dependency_surface.rs:365, packages/d2b-broker-composition/src/dependency_surface.rs:380] - evidence: seed `serde_json::from_|serde_json::to_` = 1 hit (dependency_surface.rs:308); no serde derives or wire types exist in the crate (seeds 1-3 = 0), and cargo metadata is cargo's contract, not repo wire, so the change is actionable -- clean: no derive(Serialize/Deserialize), no serde attributes, no hand-written Deserialize impls; the single serde_json use is the metadata parse above - -## obs -- clean: seeds ran (6/0/0/9); the 6 `eprintln!` hits are CLI product output (main.rs:34, 50, 54, 58 - operator-facing startup/exit diagnostics, the skill's own carve-out) and test skip notices (dependency_surface.rs:423, seam.rs:625); the 9 remaining hits are `log::` false-matching inside `d2b_broker::catalog::` paths; the lib emits no telemetry and the binary installs the subscriber exactly once at main.rs:24-32 (the sanctioned place); no interpolated message-only events, no secrets in fields - -## docs -- d2b-broker-composition#8 sev=low blast=leaf effort=S verdict=actionable - the five Result-returning public items document their failure conditions in prose but carry no canonical `# Errors` section, so the failure contract is not machine-checkable at a glance - fix: add `# Errors` sections to `register_declared_handlers`, `register_production_handlers`, `verify_startup_routing`, `probe_crate_sources`, and `audit_crate` naming which conditions produce which refusal/error - [packages/d2b-broker-composition/src/seam.rs:157, packages/d2b-broker-composition/src/seam.rs:173, packages/d2b-broker-composition/src/seam.rs:198, packages/d2b-broker-composition/src/dependency_surface.rs:151, packages/d2b-broker-composition/src/dependency_surface.rs:226] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed `-> Result<` = 9 hits (7 public items plus 2 test helpers); every pub item already has a one-line first sentence and every module has `//!` docs, so only the canonical-section shape is missing - -## perf -- clean: seeds ran (5/4/1); all `format!` hits are cold error construction (seam.rs:205/210 invariant messages, dependency_surface.rs:228/267/269/309 audit diagnostics) and all `Vec::new()` hits are audit tooling with unknown sizes - repo false positives per the card; the single `to_string()` hit (dependency_surface.rs:272) is flagged under own; nothing here is on a hot path and no benchmark exists, so all observations are static (unmeasured) - -## conc -- N/A: seeds (0/0/0/0) all zero; the crate spawns no threads, holds no Mutex/RwLock, uses no atomics or thread_local, and declares no manual Send/Sync - -## async -- clean: seeds ran (17/0/0/4); every hit is inside `#[cfg(test)]` - four `#[tokio::test]` harnesses, two async fixture helpers, and their `.await` calls; the library declares no `async fn` (handlers are `fn` pointers returning d2b-broker's boxed `HandlerFuture`), and `dependency_surface`'s synchronous document/process reads carry the one sanctioned module-level blanket allow (`#![allow(clippy::disallowed_methods)]` at dependency_surface.rs:8, the U1 (d)4 exemption - cited, not re-flagged) - -## unsafe -- N/A: seeds 1-3 (0/0/0) all zero; seed 4 alone hits - `#![deny(unsafe_code)]` at lib.rs:13 and `unsafe_code = "deny"` in the manifest lints table; the crate is on the U1 (d)8 deny list with zero unsafe blocks, consistent with the ledger - -## ffi -- N/A: seeds (0/0/0/0) all zero; no extern "C", no no_mangle, no repr(C)/repr(transparent), no CStr/CString/c_char anywhere in the crate - -## macro -- clean: seeds ran (0/8/0/0); all 8 hits are the `proc_macro` identifier in the dependency-surface audit vocabulary (field `proc_macro_dependencies`, fn `is_proc_macro`), not macro usage - no `macro_rules!`, `syn`/`quote`, `$crate`, or `to_compile_error`/`new_spanned` anywhere; the crate defines and uses no macros beyond std - -## test -- d2b-broker-composition#9 sev=low blast=leaf effort=S verdict=actionable - `an_effectful_handler_offered_to_the_in_broker_table_is_refused_by_the_routing_rule` asserts `format!("{refusal}").contains("forward carrier")`, pinning the routing refusal's Display wording after the `matches!` variant check already pins the contract - fix: delete the Display-string assertion (the variant match is the contract; a wording change must not fail the suite) - [packages/d2b-broker-composition/src/seam.rs:523] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 51 lines; the assertion was read in context - the preceding `matches!` on `RoutingRefusal::Forwarded { class: RefusalClass::Effectful, .. }` is the behavioral check -- d2b-broker-composition#10 sev=low blast=leaf effort=S verdict=actionable - `an_unregistered_admitted_operation_fails_the_startup_invariant` never exercises an admitted-without-handler operation (the committed catalog admits nothing this pass, and the fixture row is refused by `verify_startup_routing` as uncommitted), so the body only asserts the empty-registration happy path and registers a discarded fixture - fix: rename the test to what it asserts (e.g. `the_admitted_set_stays_empty_with_nothing_registered`) and drop the comment's claim that the admitted-without-handler leg is pinned by the fixture row, or restructure to feed a genuinely admitted row when one exists - [packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.rs:733] - evidence: seed `#\[test\]|#\[tokio::test\]` = 31 hits (5 dependency_surface.rs, 11 routing.rs, 15 seam.rs); test body read in full - no assertion involves an admitted row -- clean: 31 tests, all in the right form (unit tests in `#[cfg(test)]` needing private access), expectations human-written literals, deterministic (no network/clock/randomness), no `#[ignore]`, no proptest/insta/rstest (not needed); the environment-dependent `skip_without` early returns are documented skips, and every remaining test can fail on a real regression - -## Coverage -- idiom: 2 finding(s) -- own: 3 finding(s) -- type: clean (seeds ran: 0/0/0; structs and enums declared so the lens is applicable; refusal taxonomy already enum-modeled) -- api: clean (seeds ran: 24/0/0; deliberate single-path surface, no Arc/Rc/Box/RefCell in signatures) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: clean (seeds ran: 6/0/0/9; eprintln hits are CLI output and test skips, remaining hits are `log::`-in-`catalog::` false matches) -- docs: 1 finding(s) -- perf: clean (seeds ran: 5/4/1; all hits cold-path error/audit code, static (unmeasured)) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads, locks, or atomics) -- async: clean (seeds ran: 17/0/0/4; all hits are #[tokio::test] harnesses and helpers; dependency_surface sync reads are the sanctioned blanket allow, U1 (d)4) -- unsafe: N/A (seeds 1-3: 0/0/0; seed 4 only - #![deny(unsafe_code)] lib.rs:13, manifest deny; on the U1 (d)8 deny list, zero blocks) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: clean (seeds ran: 0/8/0/0; all 8 hits are the audit's proc_macro identifier, no macro definitions) -- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md deleted file mode 100644 index 08dbb6a5e..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p1.md +++ /dev/null @@ -1,75 +0,0 @@ -# d2b-broker-p1 - d2b-broker - part 1/7 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11016 (excl. src/generated/**) | modules: runtime.rs:10301-20603 (item-range split; probe/parse helpers, BrokerError audit+response, SIGCHLD reaper, targeted reap, spawn-rollback cleanup, mod tests 11840-20603), ops/usbip_lock.rs, seccomp_compile_tests.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: runtime.rs:10301-20603, ops/usbip_lock.rs, seccomp_compile_tests.rs - -## idiom -- d2b-broker-p1#4 sev=low blast=leaf effort=S verdict=actionable - three near-identical hand-rolled flag parsers `parse_probe_flags`/`parse_stub_flags`/`parse_export_flags` duplicate the same index-loop skeleton and the `--socket-path`/`--test-uid` arms (with `expect_arg` bound-checking) three times - fix: extract one table-driven flag parser (flag spec -> value) that the three wrappers compose, or a shared `parse_common_flags` helper returning `(socket_path, test_uid)` - [packages/d2b-broker/src/runtime.rs:10392, packages/d2b-broker/src/runtime.rs:10418, packages/d2b-broker/src/runtime.rs:10453, packages/d2b-broker/src/runtime.rs:10495] - evidence: seeds `for \w+ in 0\.\.` = 2, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 4; the two index loops (20235, 20457) and the accumulations (13341, 17867, 20234, usbip_lock.rs:302) are side-effectful test loops / required read buffers, not iterator candidates -- clean: seeds ran 2/0/4; checked every hit - index loops and Vec/String accumulation sites are test fixtures with side-effectful bodies or required read buffers, no derive-able hand-written impls in scope - -## own -- clean: seeds ran 137/282/0/0 (clone, to_owned/to_vec/to_string, Rc/RefCell/Arc/Arc, Cow) - sampled: 47 of 419 hits (every 9th); every sampled clone/to_owned is a test-fixture literal, an audit-record snapshot (`audit_context.request_fields.clone()` at 10934), a wire-boundary owned string (11452), or an error-context path capture in usbip_lock.rs; no Rc/RefCell/Arc/Cow anywhere in scope - -## type -- clean: seeds ran 1/0/0; the single `fn validate_` hit is `validate_socket_parent` (runtime.rs:10321), a one-shot CLI startup preflight rather than a parse-once candidate; no boolean-flag soup, no stringly-typed state, no Option-pair smells in scope (TargetedReapOutcome and UsbipLockError are well-shaped enums) - -## api -- d2b-broker-p1#3 sev=low blast=leaf effort=S verdict=actionable - pub fn `acquire_lock` takes `_daemon_uid: u32` (underscore-prefixed) that the body never uses - the record owner is always `Uid::current()`, so every caller (live_handlers.rs:467 plus 8 test sites) supplies a value the function ignores - fix: drop the parameter and update the call sites - [packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467] - evidence: census `acquire_lock(` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 24 hits; seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 5 (all usbip_lock.rs), `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 0 -- clean: seeds ran 5/0/0; the 5 public items are confined to ops/usbip_lock.rs (UsbipLockError, ensure_lock_root, acquire_lock, release_lock, peek_owner) - no Arc/Rc/Box/RefCell or dependency types in public signatures, no re-export arms, runtime.rs range exposes only pub(crate) items - -## err -- d2b-broker-p1#2 sev=medium blast=leaf effort=S verdict=actionable - `UsbipLockError::Io { path: PathBuf, detail: String }` flattens the underlying `io::Error` into its Display string at 12 conversion sites, losing the source chain (os error number and context) a `#[source]` field would keep for diagnosis - fix: change the variant to `Io { path: PathBuf, #[source] source: std::io::Error }` and drop the `detail: e.to_string()` maps - [packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84, packages/d2b-broker/src/ops/usbip_lock.rs:98, packages/d2b-broker/src/ops/usbip_lock.rs:110, packages/d2b-broker/src/ops/usbip_lock.rs:122, packages/d2b-broker/src/ops/usbip_lock.rs:128, packages/d2b-broker/src/ops/usbip_lock.rs:134, packages/d2b-broker/src/ops/usbip_lock.rs:138, packages/d2b-broker/src/ops/usbip_lock.rs:142, packages/d2b-broker/src/ops/usbip_lock.rs:162, packages/d2b-broker/src/ops/usbip_lock.rs:174, packages/d2b-broker/src/ops/usbip_lock.rs:179, packages/d2b-broker/src/ops/usbip_lock.rs:187] - evidence: seed `enum \w*Error` = 1 (UsbipLockError); `\.unwrap\(\)|\.expect\(` = 518 - sampled: 48 of 518 hits (every 11th), all test-code expects with meaningful messages; production band 10301-11840 has 0 unwrap/expect; `let _ = |\.ok\(\);` = 62 (3 production sites at 10540/11491/11587 are deliberate: cfg-gated param, OnceLock set, best-effort cleanup); `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 50 (all tests plus the justified unix-only `Component::Prefix` unreachable at usbip_lock.rs:284) -- clean: seeds ran 518/62/50/1 - panic policy is sound in production code (zero unwrap/expect/panic in 10301-11840); the only taxonomy issue is the Io-variant source-chain loss recorded above - -## serde -- clean: seeds ran 0/0/0/13; no serde derives or hand-written Deserialize impls in scope - the 13 serde_json hits are test round-trips and redaction assertions (serialObserved present, raw serial/busid/key_hex absent) plus the probe CLI's stdout rendering at 10377; no wire type crosses a boundary in this part - -## obs -- clean: seeds ran 5/0/0/35; the two println!/eprintln! hits in runtime.rs are the layer1-bootstrap probe CLI's product output (10375) and a test skip message (15893), the three seccomp_compile_tests eprintln! sites are test skip notices; all 12 production tracing events (10822-11818) carry named fields (operation, error_kind, detail, runner_id, error, pid, exit_status) with no interpolated-message events and no secrets - -## docs -- d2b-broker-p1#5 sev=low blast=leaf effort=S verdict=actionable - the four Result-returning public fns in ops/usbip_lock.rs (`ensure_lock_root`, `acquire_lock`, `release_lock`, `peek_owner`) document failure conditions only in prose and carry no `# Errors` canonical section, which the docs contract wants on every Result-returning item - fix: add `# Errors` sections naming the returned variants (LockAlreadyHeld, OwnerMismatch, Io) - [packages/d2b-broker/src/ops/usbip_lock.rs:81, packages/d2b-broker/src/ops/usbip_lock.rs:90, packages/d2b-broker/src/ops/usbip_lock.rs:171, packages/d2b-broker/src/ops/usbip_lock.rs:316] - evidence: seed `-> Result<` = 17 (14 runtime + 3 usbip), `/// # (Examples|Errors|Panics|Safety)` = 0, `^\s*pub (fn|struct|enum|trait|const|type)` = 5; all 5 public items have one-line doc summaries; runtime.rs range items are pub(crate) with adequate docs -- clean: seeds ran 5/0/17 - every public item in scope has a one-line doc comment; the only gap is the missing `# Errors` sections recorded above - -## perf -- clean: seeds ran 89/57/29 - all format!/Vec::new/to_string hits are cold error-message construction (RunError/BrokerError/UsbipLockError detail strings), test fixtures, or wire-boundary owned strings; production band 10301-11840 has zero Vec::new() and zero hot-loop allocation; static (unmeasured) - -## conc -- clean: seeds ran 10/4/0/0; all 14 hits are test-only - std::thread::spawn in harnesses, test Mutexes (FakeDispatchBackend, RegistryTestGuard's LazyLock with `poisoned.into_inner()`), and std::thread::sleep polling loops with documented convergence; no atomics, no unsafe Send/Sync impls, no shared-state design issues in production code - -## async -- d2b-broker-p1#1 sev=high blast=wide effort=S verdict=actionable - `cleanup_spawned_runner_after_failure` performs a blocking `waitid(Id::PIDFd(pidfd), WaitPidFlag::WEXITED)` (no WNOHANG) at runtime.rs:11815, and is called directly from async `spawn_process` (kernel_ops.rs:919, 955) on the broker's tokio executor; a child stuck in uninterruptible sleep blocks that worker indefinitely, and every sibling reap path in this file is explicitly WNOHANG - fix: bounded WNOHANG poll loop (or spawn_blocking) that preserves the no-live-process-left-behind guarantee; route review-pass - [packages/d2b-broker/src/runtime.rs:11815, packages/d2b-broker/src/kernel_ops.rs:919, packages/d2b-broker/src/kernel_ops.rs:955] - evidence: seeds `async fn|async move|\.await` = 60, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 1, `tokio::sync::(Mutex|RwLock|Notify)` = 5, `#\[tokio::(main|test)\]|Runtime::block_on` = 4; the WNOHANG discipline is documented at runtime.rs:11486-11529 and applied at 11549/11656; no async-gate-allow marker covers this site; kernel_ops.rs:741 `async fn spawn_process` is the enclosing caller -- clean: seeds ran 60/1/5/4 - reaper loop, targeted reap, and notification paths hold no guard across .await and use non-blocking probes; the single blocking-waitid rollback path is the finding above; the block_on at 11498 is startup signal registration (sanctioned) - -## unsafe -- clean: seeds ran 5/5/16 - all 5 unsafe blocks live in seccomp_compile_tests.rs (can_set_no_new_privs, two forks, two child closures) and each carries a `// SAFETY:` comment stating the invariant; the 3 `#[allow(unsafe_code)]` sites are on the recorded exception list (U1 d8); the 16 transmute/from_raw/MaybeUninit/zeroed hits are safe nix `Pid::from_raw` constructors, not unsafe operations - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no extern "C"/no_mangle/catch_unwind/repr(C)/CStr surface in this part) - -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!/proc-macro/$crate/to_compile_error definitions in this part) - -## test -- clean: seeds ran 123/560/0/0 (#[test]/#[tokio::test], assert_eq!/assert_ne!/assert!, proptest!/insta::assert/rstest, #[ignore]) - sampled: 56 of 123 test fns (every 3rd); the suite asserts observable behavior (wire codes, audit records, redaction, rollback semantics, restart-replay refusal, rate-limiter fail-closed caps) with human-written expectations, table-driven cases with failure messages, injected time (`check_at(now)`), and progress-based waits with documented convergence instead of fixed sleeps; no test that cannot fail, no network, no #[ignore] - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: 137/282/0/0; sampled 47 of 419) -- type: clean (seeds ran: 1/0/0) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 0/0/0/13) -- obs: clean (seeds ran: 5/0/0/35) -- docs: 1 finding(s) -- perf: clean (seeds ran: 89/57/29) -- conc: clean (seeds ran: 10/4/0/0) -- async: 1 finding(s) -- unsafe: clean (seeds ran: 5/5/16) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary surface in this part) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions in this part) -- test: clean (seeds ran: 123/560/0/0; sampled 56 of 123 test fns) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md deleted file mode 100644 index d28b5bd13..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p2.md +++ /dev/null @@ -1,100 +0,0 @@ -# d2b-broker-p2 - d2b-broker - part 2/7 -Baseline: 6ebdd4cec | LOC audited: 11074 (runtime.rs:1-10300; 10300 lines; src/ops/gpu.rs (463); src/ops/modprobe.rs (311); none carries src/generated/**). | modules: runtime (part 1/2 of the item split), ops::gpu, ops::modprobe -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: runtime.rs:1-10300, src/ops/gpu.rs, src/ops/modprobe.rs - -## idiom -- d2b-broker-p2#1 sev=low blast=leaf effort=S verdict=actionable - active_locked_usbip_bind_intents builds out with a let-mut push loop over the resolver's intent-id iterator, where a filter_map().collect() pipeline would carry the same filtering - fix: replace the loop at runtime.rs:10132-10147 with `resolver.usbip_bind_intent_ids().filter_map(|id| resolver.find_usbip_bind_intent(id).map)...))).collect::>()`, keeping the two continue conditions as filter predicates - [packages/d2b-broker/src/runtime.rs:10132] - evidence: seeds: `for w+ in 0..` = 2;`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0;`let mut w+ = (String|Vec)::new()` = 5. The other index-loop hit (runtime.rs:1004) has a per-iteration thread-spawn side effect, so the plain-for rule is the right shape; the while-let async fs-entry loops (5663, 8529, 10113) collect over a fallible async stream, not an iterator-pipeline cleanup. - - - - -## own -- clean: seeds ran: 144/320/0/0. clone seed: 144 hits (142 runtime + 2 modprobe). to_owned/to_vec/to_string seed: 320 hits (311 runtime + 2 gpu + 7 modprobe). Rc/RefCell/Arc/Arc seed: 0; Cow seed: 0. Read all 144 clone hits plus a deterministic sample of the to_* hits (every 7th =45 of 320). Every clone/to_owned inspected constructs an owned wire response, audit record, registration, or intent struct whose value must outlive a borrow, or is an accepted Arc at a spawn/static boundary; the two gpu/modprobe to_owned hits are test-fixture argv lists; no explainable-but-avoidable copy found. - - -## type -- clean: seeds ran: 22/0/0 (`fn validate_w+|fn check_w+` = 22 hits: 18 runtime + 4 gpu;`is_w+: bool|w+_flag: bool` = 0;`(mode|kind|state): String` = 0). The validate fns are wire-admission and-domain-shape gates over contract-pinned &str ids and SpawnRunnerPlan/GpuLaunchRequest values; no boolean-flag soup, Option-pair smell, or string-typed state exists in the three files; a parsed-newtype alternative would be a wire/contract change, not a lane-local refactor. - - - -## api -- d2b-broker-p2#2 sev=medium blast=leaf effort=M verdict=actionable - the GPU and modprobe op modules rise to the crate's public surface through pub mod ops + pub mod gpu/pub mod modprobe (ops/mod.rs:47-48), yet the GPU types (GpuBrokerRole, GpuDeviceClass, GpuOpaqueIdentity, GpuLaunchRequest, GpuProcessObservation, GpuBrokerError)and modprobe's(ModprobeAuditRecord, ModprobeDecision, AllowlistRow, ModprobeBackend, RecordingBackend, dispatch, live_modprobe_if_allowed)have zero consumers outside d2b-broker itself:live_handlers uses only the two gpu validate fns and runtime uses only live_modprobe_if_allowed, all same-crate - fix: narrow the module decls to pub(crate)(ops/mod.rs:47-48), or make the item-level pub to pub(crate)in gpu.rs and modprobe.rs; same-crate call sites are unaffected - [packages/d2b-broker/src/ops/gpu.rs:13, packages/d2b-broker/src/ops/gpu.rs:24, packages/d2b-broker/src/ops/gpu.rs:41, packages/d2b-broker/src/ops/gpu.rs:63, packages/d2b-broker/src/ops/gpu.rs:177, packages/d2b-broker/src/ops/gpu.rs:190, packages/d2b-broker/src/ops/modprobe.rs:32, packages/d2b-broker/src/ops/modprobe.rs:42, packages/d2b-broker/src/ops/modprobe.rs:61, packages/d2b-broker/src/ops/modprobe.rs:67, packages/d2b-broker/src/ops/modprobe.rs:76, packages/d2b-broker/src/ops/modprobe.rs:99, packages/d2b-broker/src/ops/modprobe.rs:165, packages/d2b-broker/src/ops/mod.rs:47, packages/d2b-broker/src/ops/mod.rs:48] - evidence: census:`GpuLaunchRequest|GpuBrokerError|GpuOpaqueIdentity|GpuDeviceClass|GpuBrokerRole|GpuProcessObservation|ModprobeBackend|ModprobeAuditRecord|ModprobeDecision|AllowlistRow|RecordingBackend|ops::gpu|ops::modprobe` over packages, tests, nixos-modules, docs/reference, labs:code hits outside the defining files = 3 (live_handlers.rs:2903, live_handlers.rs:2957, runtime.rs:3722), all inside the same crate; cross-crate code users = 0; d2b-core's/d2b-host's/docs-references are prose only. - - - -## err -- d2b-broker-p2#3 sev=high blast=wide effort=S verdict=actionable - DispatchAuditContext::from_request panics the broker on a malformed authoritative audit join: both CanonicalAuditDigest::parse(zone_id.expect)...) at runtime.rs:2419-2422 parse data that came straight out the wire (request.authoritative_audit_join() returns the strings unchecked), while the sibling from_request_with_join (runtime.rs:2440-2444) converts the same parse failure to BrokerError::Protocol - a remote caller can crash the daemon - fix: replace both expect("authoritative ... digest") calls with `.map_err(|_| BrokerError::Protocol("audit zone identity invalid".to_owned()))?;`, mirroring runtime.rs:2442-2444, keeping the panic out of the wire path - [packages/d2b-broker/src/runtime.rs:2419, packages/d2b-broker/src/runtime.rs:2422] - evidence: seed `\.unwrap\(\)|\.expect\(` = 13 over the lane (11 runtime + 2 gpu; both gpu hits are in mod tests), of which 2419/2422 are the only inputs crossing a caller-controlled boundary; the other unwrap/expect hits are startup/runtime-build/catalog invariants (runtime.rs:1023, 3169, 5112-5118, 7073, 7093, 7173) or best-effort ignores (`let _ =` at runtime.rs:1038, 1200,1421,1461,1579,1613,1641,6432-6434)and the 16 `let _ = |\.ok\(\);` seed hits are all deliberate best-effort audit/cleanup/param sites; gpu's unreachable! at gpu.rs:321 is a closed-enum invariant panic, correct per the panic policy;`enum w*Error` = 3 (RunError, GpuBrokerError; BrokerError is pub(crate) - - -## serde -- clean: seeds ran: 3/2/0/8. The modprobe wire shapes (ModprobeAuditRecord, ModprobeDecision, AllowlistRow)use serde(rename_all = "camelCase") or "kebab-case" on the type, not per field; no hand-written Deserialize impl exists; the 8 serde_json::from_/to_ sites either surface errors as typed BrokerErrors (runtime.rs:1481, 2551, 4976, 9752)or are best-effort optional audit fields that explicitly fall back (to_value().ok() at runtime.rs:3334, 3364, 3725; from_slice::().ok() at 3563 for a qemu dump probe), none silently swallowing wire input the caller must know about. - - - -## obs -- d2b-broker-p2#4 sev=low blast=leaf effort=M verdict=actionable - three message-only tracing events carry no named fields:the child-reap buffer-busy warnings at runtime.rs:6023 and runtime.rs:6036 (a dropped notification / an abandoned drain), and the dispatch-pool panic error at runtime.rs:1016 (request body panicked), each has dynamic identity it could expose (the dropped ChildReapedNotification, or which operation the panicking job covered)- fix: convert to events with named fields:tracing::warn!(dropped = ?notif, "child_reap_buffer busy"), include buffer = "child_reap_buffer" on the empty-drain warn,and propagate an operation span or captured job context into the pool's tracing::error! - [packages/d2b-broker/src/runtime.rs:6023, packages/d2b-broker/src/runtime.rs:6036, packages/d2b-broker/src/runtime.rs:1016] - evidence: seed `(info|debug|warn|error|trace)!\("` = 2 hits (runtime.rs:6023, 6036); the no-fields multiline tracing::error! at runtime.rs:1016 sits inside the tracing::|log:: count = 33; all other tracing events in the lane carry named fields(error, notify_result, load_outcome, runner_id, etc.); the `//!`-documented use tracing::info/warn at 45-46 undermines neither finding. - - - -## docs -- d2b-broker-p2#5 sev=medium blast=family effort=S verdict=actionable - the broker's central runtime module has no //! module doc,and its five process-entry public items (ServerConfig, BrokerMode, RunError, parse_command, run)lack any doc comment, even though they form the public API the composition binary (d2b-broker-composition/src/main.rs:3, 47-60)and integration tests (tests/profile_separation.rs:1, 22-33)match on - fix: add a one-line module doc atop runtime.rs(serve/socket/audit contract)and one-line first-sentence doc comments to ServerConfig, BrokerMode, RunError, with # Errors on run/parse_command, which return Result),keeping the comments caller-contracts, not implementation narration - [packages/d2b-broker/src/runtime.rs:1, packages/d2b-broker/src/runtime.rs:324, packages/d2b-broker/src/runtime.rs:375, packages/d2b-broker/src/runtime.rs:398, packages/d2b-broker/src/runtime.rs:565, packages/d2b-broker/src/runtime.rs:799] - evidence: docs seeds:`^\s*pub (fn|struct|enum|trait|const|type)` = 34 (10 runtime + 19 gpu + 5 modprobe), documentation state checked per hit;`/// # (Examples|Errors|Panics|Safety)` = 0;`-> Result<` = 104. The gpu/modprobe public items largely do carry docs; the runtime entry set listed is the documented-by-fields-only surface (ServerConfig's fields each have ///,but the struct/enum and the four entry fns none) - - - -## perf -- clean: seeds ran: 124/33/91, plus gpu/modprobe 3 sites (2/0/1)=total 251 hits. Sampled: read 42 of 251 hits (every 6th). Every sampled format!/to_string/Vec::new site is an error path (BrokerError::LiveHandler(format!)...)), an audit-record/rendering field (requested:/resolved: rows, display().to_string(), serde_json fallbacks), a one-shot process/startup diagnostic (sd_notify msg, nft table render),or an empty-case/common struct allocation(Vec::new(), HashMap::new()in registries, response_fds)-none sits in a per-request hot loop exceeding a single small allocation; no perf-budget claim is made (static, unmeasured. - - - -## conc -- clean: seeds ran: 2/12/3/0. The two std::thread hits (runtime.rs:1008, 1069)are the sanctioned dedicated bounded-worker DispatchPool (threads spawned once at startup, blocking_recv on the worker's own thread per plan R4)and available_parallelism() sizing; the 12 Mutex< hits are all tokio::sync::Mutex registries/limiters with the documented try_lock-on-sync-worker posture(`// Non-blocking try-lock (plan U8)` at 7540/7556/6022/6035,orthe rate-limiter lock_sync comment at 1663-1666); the 3 Atomic/Ordering hitsform one AtomicUsize round-robin counter with Ordering::Relaxed(a counter nobody synchronises on),the weakest correct ordering; no thread_local!,no unsafe impl Send/Sync. - - - -## async -- d2b-broker-p2#6 sev=medium blast=wide effort=S verdict=policy-confirmed - the USB-audit serial HMAC key path runs blocking filesystem syscalls inside async fns on broker executor threads:usb_audit_serial_hmac_keyring calls the sync ensure_usb_audit_serial_hmac_key_dir (two path_safe::ensure_dir stat/mkdir chains)per call,and every bind op with a device serial loads each key file through a sync nix::fcntl::open plus tokio::fs::File::from_std read,and the create leg performs sync create_file_at_safe/fchmod/rustix::fs::fsync(dir_fd) at runtime.rs:7722-7729; none of these raw calls sits on the disallowed-methods list,so the sync-in-async class escapes the existing gate - fix: extend the already-used tokio::fs::File::from_std)..).sync_all().await pattern(orthe bounded-worker shape per plan R4)to the dir-fd fsync and the key-dir ensure/open legs, per U1 ledger 2,which names tokio::fs asthe sanctioned replacement for these blocking calls,so the verdict is policy-confirmed - [packages/d2b-broker/src/runtime.rs:7729, packages/d2b-broker/src/runtime.rs:7654, packages/d2b-broker/src/runtime.rs:7584, packages/d2b-broker/src/runtime.rs:7696, packages/d2b-broker/src/runtime.rs:7722] - evidence: async seeds:`async fn|async move|\.await` = 286 (runtime 267 + modprobe 19);`tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 1 (tokio::spawn at runtime.rs:1398,a spawn-bound connection task);`tokio::sync::(Mutex|RwLock|Notify)` = 20,all with the documented plan-U8 try_lock/Notify usage;`#\[tokio::(main|test)\]|Runtime::block_on` = 12 (gpu/modprobe test fns; runtime's Runtime::block_on sites at 1221, 1528, 1541 carry inline allows with sanctioned reasons, not re-flagged - - - -## unsafe -- clean: seeds ran: 0/0/5/0 (`unsafe \{|unsafe fn|unsafe impl|unsafe extern` = 0;`// SAFETY:` = 0;`transmute|from_raw|MaybeUninit|mem::zeroed` = 5;`unsafe_code` = 0). The five from_raw-pattern hits (runtime.rs:31, 5141, 6045, 7657, 7729)all name crate::sys::owned_fd_from_raw (the sanctioned syscall-boundary helper in ledger (d) 8)or io::Error::from_raw_os_error (safe std); no unsafe block, fn, impl, or extern exists anywhere inthe three files,consistent with the enumerated exception set (p5's sys.rs/p4's disk_init.rs hold the crate's unsafe sites, not here). - - - -## ffi -- clean: seeds ran: 0/1/0/0. The single catch_unwind hit (runtime.rs:1015)isthe dispatch-pool's process-supervision panic boundary, not an FFI surface:each pool job is caught so a panicking handler costs its own connection andthe worker keeps serving (documented at runtime.rs:1012-1018),the card's "is it a boundary?" question resolves to yes for that purpose; no extern "C", no repr(C)/transparent, no CStr/c_char in the lane. - - - -## macro -- clean: seeds ran: 2/0/0/0. The two macro_rules! definitions (runtime.rs:3087, 3092)are write_decision_op_record! and write_success_op_record!,variadic arg-forwarders that append the contextual audit_context tothe impl fns for dozens of callsites; the genuine variadic-interface case the skill names; the $($args:tt)* fragment isthe narrowest that can forward arbitrary trailing argument lists tothe *_impl fns; no proc-macro, no $crate, no to_compile_error/new_spanned machinery exists inthe lane. - - - -## test -- clean: seeds ran: 67/240/0/0 (`#\[test\]|#\[tokio::test\]` = 67:gpu 3 + modprobe 6 + tests 58; runtime's 1 hit is a comment mention;`assert_eq!\(|assert_ne!\(|assert!\(` = 240:runtime/gpu/modprobe 1/8/12 + tests 219;`proptest!|insta::assert|rstest` = 0;`#\[ignore\]` = 0). Sampled: read 44 of 219 assert rows in tests/** (every 5th) plus both in-file test modules in full. The gpu/modprobe tests assert on error variants (GpuBrokerError::WrongPrincipal,ModprobeDecision::*)and recorded backend effects, not Display strings/implementation; the sampled tests/** asserts target wire payloads (json["kind"], PROTOCOL_VERSION, retired-variant lookup),cross-process state(host.pid() != guest.pid(),reconciler taps/pidfds),and error kinds(STALE_WIRE_VERSION,error_kind,w3-pending-typed-wire)-behavior-level assertions,mostly with failure-message context where tables loop; no test-that-cannot-fail observed. - - - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: 144/320/0/0; sampled: all 144 clone hits + 45 of 320 to_* hits) -- type: clean (seeds ran: 22/0/0) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: clean(seeds ran: 3/2/0/8) -- obs: 1 finding(s) -- docs: 1 finding(s) -- perf: clean(seeds ran: 124/33/91; sampled: read 42 of 251 hits) -- conc: clean(seeds ran: 2/12/3/0) -- async: 1 finding(s) -- unsafe: clean(seeds ran: 0/0/5/0) -- ffi: clean(seeds ran: 0/1/0/0) -- macro: clean(seeds ran: 2/0/0/0) -- test: clean(seeds ran: 67/240/0/0; sampled: read 44 of 219 tests/** asserts) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md deleted file mode 100644 index 22b269c18..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p3.md +++ /dev/null @@ -1,83 +0,0 @@ -# d2b-broker-p3 - d2b-broker - part 3/7 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11019 (excl. src/generated/**) | modules: live_handlers, state_cells, ops::{store_sync, usbip_host, storage_contract, pidfd, sysctl, mod} -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 3/7 (whole files; no range splits) - -## idiom -- clean: seeds `for \w+ in 0\.\.`=2 / `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=3 / `let mut \w+ = (String|Vec)::new\(\)`=6; every hit is justified - the two index loops are test-only (state_cells.rs:1511, store_sync.rs:737), the hand-written impls are required (io::Error has no PartialEq; RetentionPolicy/FakePidfdSpawner Defaults carry magic values a derive would lose), and the Vec::new accumulation loops (live_handlers.rs:607,2156,2299; storage_contract.rs:229) are early-exit/error-return ancestor walks where iterator pipelines do not fit. - -## own -- d2b-broker-p3#1 sev=low blast=leaf effort=S verdict=actionable - `RealPidfdSpawner::spawn` clones the whole payload argv into a never-read `_argv` binding on every spawn - fix: delete `let _argv = payload.argv.clone();` (keep the explanatory comment; the placeholder child needs no argv) - [packages/d2b-broker/src/ops/pidfd.rs:210] - evidence: seed `\.clone\(\)` = 53 hits; site read shows the binding is never read after the clone. - -## type -- d2b-broker-p3#2 sev=low blast=leaf effort=M verdict=needs-contract - `StorageContractError::Refused { reason: String }` carries a closed set of refusal slugs ("storage-path-parent-dir-refused", "storage-path-outside-owned-roots", "storage-path-escapes-owned-root", ...) that tests string-match (storage_contract.rs:380-403) and audit records emit - fix: introduce a `RefusalReason` enum (serde lowercase) so the slug set is exhaustive and a new refusal cannot typo; wire/audit-visible strings make this needs-contract - [packages/d2b-broker/src/ops/storage_contract.rs:24, packages/d2b-broker/src/ops/storage_contract.rs:380] - evidence: type seeds `fn validate_\w+|fn check_\w+`=8 / `is_\w+: bool|\w+_flag: bool`=0 / `(mode|kind|state): String`=0; slug literals cross-referenced in the module's own tests. -- d2b-broker-p3#3 sev=low blast=leaf effort=M verdict=needs-contract - `reload_behavior` is a stringly-typed wire value re-validated at every call site (`validate_nm_reload_behavior` here and the remove path in ops/nm.rs, per the doc at live_handlers.rs:288-290) instead of parsed once at the bundle boundary - fix: parse `reloadBehavior` into an enum in the bundle resolver so both arms branch on the parsed type and a hand-declared typo fails at resolution; `reloadBehavior` is pinned in docs/reference/schemas/v1/host.json:409 and v2/host.json:543, so needs-contract - [packages/d2b-broker/src/live_handlers.rs:291, packages/d2b-broker/src/live_handlers.rs:362] - evidence: type seed `fn validate_\w+` = 8 hits; site read of the validator and its two call sites. - -## api -- d2b-broker-p3#4 sev=medium blast=leaf effort=S verdict=actionable - `ops::sysctl` exports a dead pub surface: `apply_sysctl_intents` (sysctl.rs:84), `ApplySysctlRequest` (16), `with_default_root` (23) and `intent_to_proc_path` (76) are referenced only inside sysctl.rs (its own tests at 258/283); the production entry point is `apply_with_readback` - fix: delete the dead trio (or demote to `pub(crate)` and keep only what tests need) - [packages/d2b-broker/src/ops/sysctl.rs:16, packages/d2b-broker/src/ops/sysctl.rs:84] - evidence: census: `apply_sysctl_intents` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file (the defining file only); `with_default_root` = 1 file; `intent_to_proc_path` = 1 file. - -## err -- d2b-broker-p3#5 sev=low blast=leaf effort=S verdict=actionable - `CellStore` panic policy is inconsistent: `in_memory()` (state_cells.rs:348) and `with_retention()` (360) `.expect()` on `spawn_owner` failure while the sibling `open()` (353) propagates `CellStoreError::Io` from the same call - fix: make `with_retention` return `Result` (its callers are tests), and have `in_memory` keep its infallible contract only with an `expect` that names the startup-precondition rationale - [packages/d2b-broker/src/state_cells.rs:348, packages/d2b-broker/src/state_cells.rs:360] - evidence: seed `\.unwrap\(\)|\.expect\(` = 274 hits (5 in production zones; the rest are cfg(test)); site read of spawn_owner and its three callers. - -## serde -- d2b-broker-p3#6 sev=low blast=leaf effort=S verdict=actionable - `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in `load()` (state_cells.rs:924-931), while the in-process `CellOutcome` enum already exists - fix: derive Serialize/Deserialize on a wire enum (`#[serde(rename_all = "lowercase")]` over `CellOutcome` or a dedicated `DurableOutcome`) and delete the string match; the serialized shapes "unknown"/"completed" stay identical, so no DURABLE_VERSION bump is needed - [packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924] - evidence: seeds `derive\([^)]*(De)?[Ss]erialize`=2 / `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=4 / `impl .*Deserialize.*for`=0 / `serde_json::from_|serde_json::to_`=9. - -## obs -- d2b-broker-p3#7 sev=low blast=leaf effort=S verdict=actionable - `retry_acl_grant` interpolates its `label` into the message instead of a named field: `tracing::debug!(error = %err, "{label} ACL refresh not ready yet")` and `tracing::warn!("{label} ACL refresh timed out")`, with no enclosing span carrying it, so the refresh kind is not queryable - fix: emit `label = %label` as a field and keep the message interpolation-free - [packages/d2b-broker/src/live_handlers.rs:2532, packages/d2b-broker/src/live_handlers.rs:2539] - evidence: seed `(info|debug|warn|error|trace)!\("` = 1 hit (plus the sibling debug! at 2532 read in context); obs1 `\bprintln!\(|\beprintln!\(` = 3 (all cfg(test) skip notices). - -## docs -- d2b-broker-p3#8 sev=low blast=leaf effort=S verdict=actionable - pub types `UsbipHostInspectionError` (usbip_host.rs:17), `UsbipDriverBinding` (153) and `UsbipHostDeviceInspection` (160) carry no doc comment at all on a crate with a lib target - fix: add one-line docs (and field docs for the inspection struct) - [packages/d2b-broker/src/ops/usbip_host.rs:17, packages/d2b-broker/src/ops/usbip_host.rs:153, packages/d2b-broker/src/ops/usbip_host.rs:160] - evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)`=59 / `/// # (Examples|Errors|Panics|Safety)`=0 / `-> Result<`=116; site read of the three items. -- d2b-broker-p3#9 sev=low blast=leaf effort=S verdict=actionable - pub types `ApplySysctlOutcome` (sysctl.rs:32), `ApplySysctlError` (40) and `ApplyWithReadbackError` (113) and the pub method `with_default_root` (23) are undocumented - fix: add one-line docs per item - [packages/d2b-broker/src/ops/sysctl.rs:32, packages/d2b-broker/src/ops/sysctl.rs:40, packages/d2b-broker/src/ops/sysctl.rs:113] - evidence: docs seeds 59/0/116; site read of the items. -- d2b-broker-p3#10 sev=low blast=leaf effort=S verdict=actionable - pub enum `StorageContractError` (storage_contract.rs:21) has no doc comment - fix: one-line doc naming the refusal/invalid/Io contract - [packages/d2b-broker/src/ops/storage_contract.rs:21] - evidence: docs seeds 59/0/116; site read. -- d2b-broker-p3#11 sev=low blast=leaf effort=S verdict=actionable - pub methods `PidfdMethod::as_str` (pidfd.rs:112), `StartTime::matches` (127), `RealPidfdSpawner::new` (191) and `AuditDecision::as_str` (ops/mod.rs:164) are undocumented - fix: one-line docs per method - [packages/d2b-broker/src/ops/pidfd.rs:112, packages/d2b-broker/src/ops/pidfd.rs:191, packages/d2b-broker/src/ops/mod.rs:164] - evidence: docs seeds 59/0/116; site read of the items. - -## perf -- d2b-broker-p3#12 sev=low blast=leaf effort=M verdict=actionable - `CellStore` partial-key lookups scan the whole record map: `contains` (state_cells.rs:470), `payload` (488), `remove` (506), `keys` (524) and `clear` (541) iterate `records: BTreeMap` filtering on (cell, invocation_id) because the principal is a key component, making every op O(n) where the durable file already uses the nested cell -> invocation layout - fix: mirror the durable layout in memory (cell -> invocation -> record, principal inside the record) so lookups become O(log n); static (unmeasured) - [packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, packages/d2b-broker/src/state_cells.rs:524] - evidence: static (unmeasured); perf seeds `format!\(`=185 (production hits are error paths) / `Vec::new\(\)|...`=31 / `\.to_string\(\)`=53. - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope`=2 / `\bMutex<|\bRwLock<`=3 / `Atomic\w+|Ordering::`=16 / `thread_local!|unsafe impl (Send|Sync) for`=0; all concurrency is the sanctioned R4 dedicated bounded worker (state_cells.rs:343,583,606,901 `#[allow)..., reason = "dedicated bounded worker per plan R4")]` sync_channel + owner thread with the documented poison latch), and the remaining hits are cfg(test) scopes/atomics (state_cells.rs:1509, usbip_host.rs:489-551, live_handlers.rs:5605). - -## async -- d2b-broker-p3#13 sev=medium blast=leaf effort=M verdict=actionable - the initial ACL-grant attempt runs a blocking setfacl fork/exec on the executor worker: `refresh_spawn_runner_acls` (async, live_handlers.rs:1802) -> `refresh_obs_vsock_acl` -> `grant_obs_vsock_acl_once` (1614) -> `setfacl_fd_safe` -> `setfacl_fd_safe_op_classed` (1416) -> `sys::pidfd_sys::run_setfacl_op_on_fd`, while the retry paths (`spawn_obs_vsock_acl_retry` 1658, `retry_acl_grant` 2519) correctly defer the same shellout to `background.dispatches.run` on the bounded dispatch pool - fix: route the initial attempt through `dispatches.run` too (or make the refresh fns async and use the `setfacl_verified_device` async-shellout shape), matching the documented "kernel-path step on the bounded dispatch pool" design; bounded short shellout per spawn, so medium not high - [packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:1802] - evidence: async seeds `async fn|async move|\.await`=367 / `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(`=0 / `tokio::sync::(Mutex|RwLock|Notify)`=2 / `#\[tokio::(main|test)\]|Runtime::block_on`=60; call-chain read; the store_sync.rs:666 flock site is a sanctioned per-site allow ("synchronous path", U1 ledger 4) and the state_cells worker is the sanctioned R4 boundary, both left unflagged. - -## unsafe -- clean: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0 / `// SAFETY:`=0 / `transmute|from_raw|MaybeUninit|mem::zeroed`=3 / `unsafe_code`=3; the three `from_raw` hits are safe nix constructors (`Uid::from_raw`/`Gid::from_raw` at storage_contract.rs:279,307, `Pid::from_raw` in a test at live_handlers.rs:5387) and the `unsafe_code` hits are doc prose (pidfd.rs:20,176,208); no unsafe block exists in this partition - all unsafe lives in sys.rs (d2b-broker-p5's scope). - -## ffi -- clean: seeds `extern "C"|no_mangle|unsafe\(link_section`=0 / `catch_unwind`=1 / `repr\(C\)|repr\(transparent\)`=0 / `CStr|CString|c_char`=1; the `catch_unwind` at state_cells.rs:635 is the documented panic-isolation boundary of the cell-store poison latch, not a foreign-caller boundary, and the `CString` hit is doc prose (live_handlers.rs:2857); no FFI surface exists in this partition. - -## macro -- N/A (seeds: `macro_rules!`=0 / `proc_macro|syn::|quote!`=0 / `\$crate`=0 / `to_compile_error|new_spanned`=0 all zero; no macro definitions or proc-macro machinery in the lane files). - -## test -- d2b-broker-p3#14 sev=low blast=leaf effort=S verdict=actionable - `reconciliation_refuses_start_time_drift` (tests/pidfd_handoff_scm_rights.rs) asserts the Display string (`msg.contains("start-time drifted")`) instead of the error variant, while the sibling real-spawner test matches `PidfdOpError::ReconciliationStartTimeMismatch` - fix: match the variant like tests/pidfd_real_spawner.rs:66-70 - [packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90] - evidence: test seeds over lane src: `#\[test\]|#\[tokio::test\]`=114 / `assert_eq!\(|assert_ne!\(|assert!\(`=351 / `proptest!|insta::assert|rstest`=0 / `#\[ignore\]`=0; over tests/: 58/219/0/0; the in-module suites (state_cells, store_sync, usbip_host, storage_contract, sysctl) are invariant-focused and fail-closed, no other findings. - -## Coverage -- idiom: clean (seeds ran: 2/3/6) -- own: 1 finding(s) -- type: 2 finding(s) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: 1 finding(s) -- docs: 4 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 2/3/16/0) -- async: 1 finding(s) -- unsafe: clean (seeds ran: 0/0/3/3) -- ffi: clean (seeds ran: 0/1/0/1) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions in lane files) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md deleted file mode 100644 index 1f59f6aa1..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p4.md +++ /dev/null @@ -1,95 +0,0 @@ -# d2b-broker-p4 - d2b-broker - part 4/7 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10,906 (excl. src/generated/)) | modules: audit; ops::{tap, disk_init, route, store_sync_audit, spawn_runner, host_generation_handoff, store_sync_export} -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: full-file scope for these 8 modules (U1 section f part 4/7 of d2b-broker) - -## idiom -- clean: seeds ran: 10/0/7 - every hit checked: the 10 `for i in 0..` hits are retry loops (quarantine-name, mkfs, udev-wait, test churn)and the 7 `let mut String/Vec::new()` hits are accumulation loops with early bounds/limit checks (legacy-export cap, bounded-line reader, scan cap, test fixtures), where an iterator pipeline would obscure the early exits; no hand-written derive-eligible impls in lane. - - - -## own -- clean: seeds ran: 83/288/6/0 - all 83 `.clone()` hits read in full (owned-construction into `RouteConflictKey`/`SpawnRunnerPlan`/`JournalEntry`/export records, cfg(test) `Arc` capture plumbing, test-fixture spec cloning)and the 294 `to_owned`/`to_vec`/`to_string`/`Arc` hits sampled every-8th (37 rows read) - all owned-string construction at wire/error boundaries, test fixtures, or the cfg(test) capture channel; no borrow-checker-silencing clone found; parsers taking `impl Into` (route.rs:413/418) require the owned String by callee contract, so those clones are not avoidable at the call site. - - - -## type -- clean: seeds ran: 13/0/0 - all 13 `validate_*`/`check_*` hits (mkfs binary path, existing image type/size/identity/posture, route state, artifact-with-helper, target path) validate external filesystem/leader state that a parsed type cannot carry, and each runs once at its boundary or on mutable kernel state - no illegal constructible state to encode; no bool flag fields nor stringly-typed state in lane. - - - -## api -- d2b-broker-p4#1 sev=medium blast=leaf effort=S verdict=actionable - `RouteConflictKey` is exported as `d2b_broker::ops::route::RouteConflictKey` (pub struct with all-pub fields) but its only users are private fns in the same file; its companion record type `RouteOwnershipRecord` is private - the visibility is a leak, not a contract with callers - fix: make it `pub(crate)` or plain `struct` (all users are in-file private helpers: `route_conflicts`, `route_matches_record`, `requested_route_conflict_key`)and drop the pub fields to private - [packages/d2b-broker/src/ops/route.rs:19] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 77 hits; census: `\bRouteConflictKey\b` over packages/ = 1 file (only its defining file) - -## err -- clean: seeds ran: 334/89/9/7 - combined 426 hits, sampled every-9th (48 rows read) plus all 9 panic-family hits and all 7 error enums read in full; the sampled hits are cfg(test) asserts/fixtures, deliberate best-effort `let _ = send/remove` cleanup, and invariant panics (`unreachable!` on limiter-stall/non-ext4 classification, `expect("ETXTBSY error recorded")` on a loop invariant, `expect("typed handoff serializes")` on derive-Serialize wire types) - all inside the acceptable panic-policy classes; the 7 error enums have Display/Error impls and are matched by variant, not by string; `DiskInitError` deliberately converts to `io::Error` with kind mapping (InvalidData/Other) plus actionable Display guidance - a sound coarse boundary for the `io::Result` op signature. - - - -## serde -- clean: seeds ran: 11/10/0/47 - all derive/attr hits checked (route record `rename_all="camelCase",deny_unknown_fields`, store_sync_audit enums `snake_case` pinned by the signed-schema test, `deny_unknown_fields` on broker-written round-trip records)and the 47 `serde_json` sites are boundary parses with `map_err` to `io::Error`/`OpError::InvalidInput` or deliberate corruption surfacing (`serde_json::from_str::)...).ok()` at audit.rs:1830 becomes a typed `AuditExportEntry { error: Some)...) }`), so failures are never silently swallowed. - - - -## obs -- clean: seeds ran: 0/0/0/2 - the only telemetry sites are two `tracing::warn!` calls in audit.rs (queue-full drop accounting, rate-limiter warning), both with named fields (`audit_drop_reason`, `audit_class`, `operation`, counters) - structured events as the skill requires; zero `println!`/`eprintln!` and no interpolated message-only events in lane. - - - -## docs -- d2b-broker-p4#2 sev=medium blast=leaf effort=S verdict=actionable - audit.rs public surface gaps:`AuditEntry` (legacy JSONL record shape consumed by the socket-acl gate), `AuditDropSummary`, `AuditLog::open` (the daemon entry point with bootstrap/poison barrier semantics), and `audit_drop_summary` carry no doc comment, while every sibling method around them is documented - fix: add `///` first-sentence contracts (state what `disposition` vs `outcome` mean, what counters `AuditDropSummary` merges, what `open`'s barrier requires of callers) - [packages/d2b-broker/src/audit.rs:124, packages/d2b-broker/src/audit.rs:84, packages/d2b-broker/src/audit.rs:416, packages/d2b-broker/src/audit.rs:1029] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct reads of lines 78-135/405-425/1025-1035 show no preceding doc comment on these four items -- d2b-broker-p4#3 sev=low blast=leaf effort=S verdict=actionable - tap.rs pub test-support surface lacks item docs:`SetBridgePortFlagsRequest`, `SetBridgePortFlagsAudit`, `set_bridge_port_flags`, `LiveCreateTapOutcome`, `LiveSetBridgePortFlagsError` have no `///` comments (the module-top doc explains the op family, but these exported shapes are the L1c canary-test contract)and should carry one-line first-sentence docs (error enum: list what each variant means to a caller) - [packages/d2b-broker/src/ops/tap.rs:157, packages/d2b-broker/src/ops/tap.rs:163, packages/d2b-broker/src/ops/tap.rs:169, packages/d2b-broker/src/ops/tap.rs:184, packages/d2b-broker/src/ops/tap.rs:828] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct reads of tap.rs lines 94-190 and 819-865 show no doc comments on these five items -- d2b-broker-p4#4 sev=medium blast=leaf effort=S verdict=actionable - `HandoffOperationError` (pub enum returned from every pub handoff fn) has no top-level doc comment; the failure modes (`JournalMismatch`, `HelperUnavailable`, `ArtifactValidationOutputInvalid`, ...) have descriptive names but no contract sentence says what callers should do per variant - fix: add a `///` doc line listing the variant classes (journal replay vs helper/validation failures) - [packages/d2b-broker/src/ops/host_generation_handoff.rs:35] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct read of handoff.rs lines 27-47 shows no doc comment above the enum -- d2b-broker-p4#5 sev=medium blast=leaf effort=S verdict=actionable - `ApplyWithPreflightError` (pub enum returned from the pub `apply_with_preflight_owned` entry point) has no top-level doc (only one variant carries an inline `///`); callers get no contract sentence distinguishing query failures from foreign-route refusal from reconcile failures - fix: add a one-line enum doc naming what each variant class means (route query vs ownership refusal vs executor failure) - [packages/d2b-broker/src/ops/route.rs:29] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits; direct read of route.rs lines 18-46 shows no doc comment above the enum - -## perf -- clean: seeds ran: 124/20/79 - combined 223 hits sampled every-5th (45 rows read) - all sampled format!/to_string/Vec::new sites are error-path messages, audit-JSONL rendering, one-shot op-arg construction (ip link args, macvtap device paths), test fixtures, or empty-case-common buffers (`read_bounded_line`)) - all inside the card's recorded false-positive classes; no hot-loop allocation site found (lanes are one-shot broker ops, not per-packet paths). - - - -## conc -- clean: seeds ran: 2/6/11/0 - the 2 thread sites are the dedicated audit worker spawn (std::thread::Builder at audit.rs:446, bounded sync_channel receiver per plan R4 - sanctioned) and a test thread-name read; the 6 `Arc/Arc/Cow` = 0 throughout; `to_owned/to_vec/to_string` mass is dominated by error-detail and audit rendering, not clone-to-please-the-borrow-checker. - -## type -- clean: seeds ran 5/0/0; the five `validate_*`/`check_*` helpers (sys.rs:526 `validate_target_name`, swtpm_dir.rs:482 `check_resource_backed_state_dir`, nft.rs:534 `validate_projection_marker`, device.rs:335 `validate_opened_device`, hosts.rs:197 `validate_marker_ownership`) are single-boundary validators over genuinely untrusted fs/wire input with real check classes - parse-once newtypes would not remove a bug class here (stopping rule); no boolean-flag soup and no stringly-typed state (`is_/flag: bool` 0, `(mode|kind|state): String` 0). - -## api -- d2b-broker-p5#2 sev=low blast=leaf effort=S verdict=actionable - `CgroupBundleContext::slice_path()` returns an owned `PathBuf` (cloning `parent_slice`) when a `&Path` return serves every in-crate call, forcing a clone per call at the `is_under_slice` check and duplicating the value - fix: change the return to `&Path` (`pub fn slice_path(&self) -> &Path`); the builder methods `vm_interior_path`/`vm_leaf_path`/`vm_role_leaf_path` keep their owned joins and `fields.slice_path`/tuple sites keep their one owned conversion - [packages/d2b-broker/src/ops/cgroup.rs:126-129, packages/d2b-broker/src/ops/cgroup.rs:343] - evidence: census `slice_path\(` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 9 hits (8 in-crate, 1 unrelated `d2b_host::cgroup::d2b_slice_path`); call sites that would stop cloning: cgroup.rs:249 (owns once), 323, 343 (read-only). -- clean remainder: seeds ran 181/0/4; the wide `pub` surface is deliberate for a daemon-internal crate (all 4 `pub use` arms are the house single-surface pattern: lib.rs:56, forwarding.rs:42); the one smart-pointer-in-signature (`ForwardFuture` = `Pin>`, forwarding.rs:114) is a documented trait-object seam for `dyn OperationForwarder` - not a hidden internals leak. - -## err -- d2b-broker-p5#3 sev=medium blast=leaf effort=S verdict=actionable - `WriteMarkerBlockError::Io(String)` (hosts.rs:122) flattens `io::Error` into a Display-only string at three `map_err` sites, destroying the error kind/source so a caller cannot classify NotFound vs permission vs other without string-matching - fix: switch the variant to `Io(#[source] io::Error)` (thiserror or a hand-written `#[source]` accessor) and render the same "update-hosts marker splice: {err}" prefix so the visible message is unchanged - [packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-broker/src/ops/hosts.rs:149, packages/d2b-broker/src/ops/hosts.rs:153, packages/d2b-broker/src/ops/hosts.rs:180] - evidence: seed `enum \w*Error` = 7; the siblings `CgroupOpError`, `ApplyWithCoexistenceError`, `ProjectionMutationError`, `FdPassingError`, `SwtpmHardenError` already carry typed fields, so `Io(String)` is the outlier; `\.unwrap\(\)|\.expect\(` = 260 hits, every non-test survivor is an `expect` on a literally-built C string (sys.rs:695, 714, 746, 974, 1860, 1928) or an unreachable-invariant expect (nft.rs:563 - the `"}"` line with `current.is_none()` is continued earlier, so `current.take()` cannot fail); `let _ =` = 34, all best-effort cleanup (fd close, child SIGKILL/reap, temp-dir removal); `panic!` = 10, all in `#[cfg(test)]`. - -## serde -- clean: seeds ran 7/6/0/18; the derive set (swtpm_dir.rs `MarkerData`/`MarkerOrigin`, nft.rs `ApplyNftablesAudit`/`NftHashSidecar`, device.rs `PreOpenDecision`/`OpenAuditRecord`/`RoleDeviceClaim`) is consistently `rename_all`-conventioned, `MarkerData` correctly carries `deny_unknown_fields` as the one tamper-sensitive payload, no hand-written `Deserialize` (0), and no `try_from` is missing - every shape is an emit/parse pair of the broker's own audit/marker payloads, not untrusted service input; `deny_unknown_fields` absence on service-consumed audit messages is the recorded deliberate posture. - -## obs -- clean: seeds ran 6/0/0/0; the six `println!`/`eprintln!` hits (sys.rs:1417, 1421, 3893, 4201, 4217; swtpm_dir.rs:1557) are all `#[cfg(test)]` skip messages, no interpolated-message events (0), no `instrument` spans (0), and no `tracing`/`log` use in this lane's files (0) - the lane's observability surface is the typed audit records (SwtpmDirAudit, OpenAuditRecord, ApplyNftablesAudit), which are data, not log lines. - -## docs -- d2b-broker-p5#4 sev=medium blast=leaf effort=S verdict=actionable - the public fd-ownership API in fd_passing.rs is undocumented: `FdPassingError` (13), `FdRegistry::register`/`clear` (37, 41), and the whole `FdLease` surface (`new`/`raw`/`release`, 55-70) have no doc comments even though the load-bearing contract is non-obvious - `FdLease` closes the fd on drop and `release()` disarms that close, which is exactly what ADR 0034 fd-transfer callers must know - fix: add one-line docs to each item stating ownership (who closes, what `release` disarms) and the `recv_*`/`send_fds` error variants - [packages/d2b-broker/src/fd_passing.rs:13, packages/d2b-broker/src/fd_passing.rs:31-70] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164; the documented peers in the same module (recv_fds, recv_fds_with_capacity, recv_one_fd, close_received_fds) show the house expectation, making the bare FdLease/FdRegistry group the gap. -- d2b-broker-p5#5 sev=medium blast=leaf effort=S verdict=actionable - pub syscall wrappers `peer_credentials` (121) and `tun_set_persist`/`tun_set_owner`/`tun_set_group` (185, 195, 210) carry no doc comments while their twins `peer_uid` and `tun_create_tap_fd` do; the contracts are non-obvious (peer uid/gid/pid triple semantics; TUNSETPERSIST/OWNER/GROUP ioctl semantics and the ifname binding) - fix: add one-line docs plus the `# Errors` conditions (ioctl failure, uid/gid out of `c_int` range) - [packages/d2b-broker/src/sys.rs:120-121, packages/d2b-broker/src/sys.rs:185, packages/d2b-broker/src/sys.rs:195, packages/d2b-broker/src/sys.rs:210] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 overall, these four are the undocumented pub items in the module's leading wrapper group (rest documented). -- d2b-broker-p5#6 sev=low blast=leaf effort=M verdict=actionable - the `path_safe` module's pub helpers (`refuse_symlink`, `refuse_world_writable_parent`, `refuse_non_root_parent`, `read_to_string_nofollow`, `write_nofollow`, `remove_nofollow`, `ensure_dir`, `ensure_dir_preserve_existing`) lack per-item doc comments; the contract lives only in the module-level doc, so rustdoc item pages are empty and the reader must open the module header for each helper's safety rule - fix: promote each module-doc bullet to a one-line `///` on its item (or add `#[doc = "..."]` links), keeping the module doc as the index - [packages/d2b-broker/src/sys.rs:258, packages/d2b-broker/src/sys.rs:268, packages/d2b-broker/src/sys.rs:329, packages/d2b-broker/src/sys.rs:398] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164; the module doc at sys.rs:205-249 names every helper, confirming intent, and `/// # (Examples|Errors|Panics|Safety)` = 1 (only `getsockopt_int`'s `# Safety`), so the canonical-section convention is otherwise absent here. - -## perf -- d2b-broker-p5#7 sev=low blast=leaf effort=S verdict=actionable - `projection_digest` builds the hex digest with `raw.iter().map(|byte| format!("{byte:02x}")).collect::()`, allocating one `String` per byte (32 hex bytes) before the final collect - fix: `String::with_capacity(70)` and `write!`/`push_str` each byte, or a 16-entry hex lookup - [packages/d2b-broker/src/ops/nft.rs:784-790] - evidence: seed `format!\(` = 108; this is the one site allocating inside a per-element `map` closure, all other `format!` are error/audit/text-artifact sites (cold per repo false positives). -- d2b-broker-p5#8 sev=low blast=leaf effort=S verdict=actionable - `handle_open_cgroup_dir` renders `canonical_path.display().to_string()` twice (the audit field at 341 and the outcome at 368) in the same call - fix: bind `let cgroup_id = canonical_path.display().to_string();` once and reuse for both the audit record and `OpenCgroupDirOutcome` - [packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368] - evidence: seed `\.to_string\(\)` = 33; the duplicate is the same expression on the same value in one function body. -- clean remainder: seeds ran 108/27/33; all other `format!`/`Vec::new`/`to_string` sites are in error paths, audit rendering, nft-script text building, or fixture/test code (deliberate per card false positives); nothing else is a hot path with growth-by-push. - -## conc -- clean: seeds ran 23; production concurrency use is a single `static TMP_NAME_COUNTER: AtomicU64` with `Ordering::Relaxed` (sys.rs:474, 541) - the weakest correct ordering for a globally-unique counter, exactly what the skill prescribes; every `Mutex`/`thread::spawn`/`Arc` hit is test-only (forwarding.rs test peers, fd_passing.rs `fd_test_lock`, swtpm_dir.rs test thread, cgroup.rs `RecordingAuditSink` under `fake-backends`); no `unsafe impl Send/Sync` and no `thread_local!`/`static mut`. - -## async -- d2b-broker-p5#9 sev=high blast=leaf effort=S verdict=actionable - the async `harden()` path (invoked from `live_handlers.rs:3142` on the runtime) calls `apply_ancestor_traverse_acl` -> `run_setfacl_op_on_fd` (sys.rs:1866-1893), which does a synchronous `fork` + `execv(setfacl)` + blocking `waitpid` loop with no `.await` and no `spawn_blocking`, stalling the executor worker for the duration of a subprocess spawn - fix: wrap the setfacl fork/exec/wait in `tokio::task::spawn_blocking` (moving the fd across as `OwnedFd`) and `.await` the join handle in `harden` - [packages/d2b-broker/src/ops/swtpm_dir.rs:770, packages/d2b-broker/src/sys.rs:1866-1893, packages/d2b-broker/src/live_handlers.rs:3142] - evidence: seed `async fn|async move|\.await` = 134, `tokio::spawn|...|#\[tokio::(main|test)\]|Runtime::block_on` = 26; call chain shows the sync `waitpid` loop sits inside an async function with no yield point between entry and the blocking wait; no async-gate-allow marker or blocking-census entry covers this site (the scanner and disallowed-methods list target tokio sync forms and lock acquisition, not fork/exec/waitpid). -- clean remainder: the lane's other async sites follow the house patterns - `acquire_projection_lock` (nft.rs:809-832) polls non-blocking `F_OFD_SETLK` with 25ms async sleeps (R13, documented), `read_live_table_json_optional` uses `tokio::process::Command` (nft.rs:866-881), swtpm marker reads/writes use `tokio::fs` with a single quick `rustix::fs::fsync`; none block a worker and none keep a guard across `.await`. - -## unsafe -- d2b-broker-p5#10 sev=medium blast=leaf effort=M verdict=actionable - most of `sys.rs`'s 101 `unsafe` blocks carry no `// SAFETY:` comment (only 25 SAFETY comments in the file, concentrated on the risky corner: clone3, fork, pre_exec, pidfd, mount); the raw wrapper layer - `openat2_raw`, `openat_raw`, `renameat2_raw`, `renameat_raw`, `mkdirat_raw`, `unlinkat_raw_with_flags`, `fstatat_raw`, `linkat_empty_path_raw` (593-699), the child-context helpers `mkdir_one`/`mknod_device_bind_target`/`install_pre_opened_fds` (2630, 2670, 2109) and the mount/mask helpers `apply_mount_actions(_debug)`/`apply_device_mask_and_binds` (2591, 2694) - call libc with only `#[allow(unsafe_code)]`, so a reader cannot distinguish audited from un-audited blocks in the sanctioned quarantine - fix: add a one-line SAFETY to each bare block stating the invariant it upholds (CString/pointer liveness and NUL-termination, dirfd validity, errno propagation, freshly-owned return fd), matching the existing clone3/fork comments - [packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broker/src/sys.rs:630, packages/d2b-broker/src/sys.rs:653, packages/d2b-broker/src/sys.rs:676, packages/d2b-broker/src/sys.rs:685, packages/d2b-broker/src/sys.rs:697, packages/d2b-broker/src/sys.rs:2109, packages/d2b-broker/src/sys.rs:2591, packages/d2b-broker/src/sys.rs:2630, packages/d2b-broker/src/sys.rs:2670, packages/d2b-broker/src/sys.rs:2694] - evidence: seed `\bunsafe \{|\bunsafe fn|...` = 103 hits; `// SAFETY:` = 25; `transmute|from_raw|MaybeUninit|mem::zeroed` = 39 (the `mem::zeroed` sites are int/struct-value kernels like `libc::stat`/`ifreq`/`clone_args` where zero is a valid bit pattern - sound, but the same bare-block comment gap applies). The allow pattern itself is the sanctioned boundary (U1 d8) and is not re-flagged; this finding targets only missing per-block justification on sound code. - -## ffi -- clean: seeds ran 66; every hit is within the sanctioned libc syscall-wrapper surface and matches the card's repo false positives - `CString`/`c_char` in the `nix`-replacing raw syscall layer (sys.rs), one `#[repr(C)] OpenHow` kernel uapi shape (sys.rs:497), no `extern "C"` function, no `no_mangle`, no `catch_unwind`, and no foreign caller exists anywhere in the lane scope; nothing here crosses a non-Rust calling convention. - -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, proc-macro, syn/quote, `$crate`, or compile-error machinery in any assigned file) - -## test -- clean: seeds ran 109/91/0/0; the in-file `#[cfg(test)]` modules (sys.rs, swtpm_dir.rs, nft.rs, forwarding.rs, cgroup.rs, device.rs, hosts.rs, fd_passing.rs) assert behavior and error variants rather than Display strings - fd tests serialize via `fd_test_lock`, the forwarder tests cover refusal/fd-count-mismatch/budget-bound paths, swtpm tests assert fail-closed reasons and contents-preservation, and the sys.rs tests document skip conditions for privileged/unprivileged-userns cases; no `#[ignore]`, no proptest/insta/rstest (unit tests fit these pure-ish functions), and no test that cannot fail was observed. (Crate-level `tests/**` is shared across the broker's seven parts; this lane's `test` judgement covers its own modules.) - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: 38/156/0) -- type: clean (seeds ran: 5/0/0) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 7/6/0/18) -- obs: clean (seeds ran: 6/0/0/0) -- docs: 3 finding(s) -- perf: 2 finding(s) -- conc: clean (seeds ran: 23) -- async: 1 finding(s) -- unsafe: 1 finding(s) -- ffi: clean (seeds ran: 66) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions in assigned files) -- test: clean (seeds ran: 109/91/0/0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md deleted file mode 100644 index b9e9c84dd..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p6.md +++ /dev/null @@ -1,101 +0,0 @@ -# d2b-broker-p6 - d2b-broker - part 6/7 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10,986 (excl. src/generated/**) | modules: envelope, ops/exec_reconcile, ops/audit_op, ops/store_view_posture, ops/device_worker, ops/nm, ops/security_key, ops/store_view_farm, ops/usbip_firewall -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 6/7 of d2b-broker per U1 section f: src/envelope/**, src/ops/exec_reconcile.rs, src/ops/audit_op.rs, src/ops/store_view_posture.rs, src/ops/device_worker.rs, src/ops/nm.rs, src/ops/security_key.rs, src/ops/store_view_farm.rs, src/ops/usbip_firewall.rs - -## idiom -- d2b-broker-p6#1 sev=low blast=leaf effort=S verdict=actionable - the "path must be absolute" check (a `to_str()` + `starts_with('/')` + `InvalidInput` refusal) is hand-copied into seven SystemReconcileExecutor methods, so a wording or error-shape change must touch all seven. - fix: extract a private `fn require_absolute(path: &Path) -> Result<(), ReconcileExecError>` helper and call it from apply_nft_script, write_atomic_file, write_atomic_file_with_ownership, write_path_value, read_path_value, ip_route, run_usbip, run_ssh_keygen. - [src/ops/exec_reconcile.rs:404, src/ops/exec_reconcile.rs:505, src/ops/exec_reconcile.rs:551, src/ops/exec_reconcile.rs:602, src/ops/exec_reconcile.rs:622, src/ops/exec_reconcile.rs:642, src/ops/exec_reconcile.rs:697, src/ops/exec_reconcile.rs:811] - evidence: idiom seeds over src/ops/exec_reconcile.rs = 1/0/0 (static read of the executor methods 392-926). -- d2b-broker-p6#2 sev=low blast=leaf effort=S verdict=actionable - write_atomic_file and write_atomic_file_with_ownership duplicate the parent-check + basename-extract + open_dir_path_safe preamble, differing only in the optional (u32, u32) ownership argument. - fix: fold into one `fn write_atomic_file(path: &Path, content: &[u8], owner: Option<(u32, u32)>) -> Result<(), ReconcileExecError>` and fold the `_with_ownership` twin into it (keeping a thin wrapper only if a caller outside the executor needs it) - [src/ops/exec_reconcile.rs:500-541, src/ops/exec_reconcile.rs:542-591] - evidence: idiom seeds over src/ops/exec_reconcile.rs = 1/0/0 (static read of the two file-writing helpers). -- d2b-broker-p6#3 sev=low blast=leaf effort=M verdict=actionable - build_farm_via_namespace and build_store_view_via_namespace duplicate the same spawn-process + write-config + read-stdout + split-lines scaffold (about 100 lines each), drifting in error messages and success parsing. - fix: unify behind one private `async fn run_store_helper(verb: StoreViewHelperVerb, request: impl Serialize, success: impl FnOnce(&[u8]) -> ...) -> Result<(), StoreViewFarmError>` with a two-variant `StoreViewHelperVerb` enum, or extract the shared scaffold into a thin helper. - [src/ops/store_view_farm.rs:97-190, src/ops/store_view_farm.rs:228-300] - evidence: idiom seeds over src/ops/store_view_farm.rs = 0/0/0 (static read of the two helper fns). -- d2b-broker-p6#4 sev=medium blast=leaf effort=M verdict=actionable - row_owner_ref, device_guest_owner,and tpm_devices_of_guest hand-roll the same "walk the bundles resources array" loop three times with slightly different match predicates, so bundle-shape drift (new field, renamed key) silently desyncs them. - fix: extract a single `fn find_resource_row<'a>(bundle: &'a Value, pred: impl FnMut(&'a Value) -> bool) -> Option<&'a Value>` and drive all three (and callers of row_owner_ref at src/ops/device_worker.rs:158) from it; keep the three predicates as call-site closures. - [src/ops/device_worker.rs:312-335, src/ops/device_worker.rs:339-369, src/ops/device_worker.rs:371-434] - evidence: idiom seeds over src/ops/device_worker.rs = 0/0/1 (static read of the three bundle-walk fns. -. -- d2b-broker-p6#5 sev=low blast=leaf effort=M verdict=actionable - TrustedContextStore duplicates each worker-handshake entrypoint as a sync twin (`open`/`open_async`, `publish`/`publish_async`) whose sync copies spawn a `block_on`-free worker handshake that only in-crate `#[cfg(test)]` callers exercise;; the justification comment begins "The crate is nearly all async" and does not cover the sync twins' ongoing cost. - fix: gate the sync twins `#[cfg(test)]` (and gate `TrustedContextStore::Drop`'s sync persist path if unused outside tests), or unify over a private `fn with_worker(blocking: bool, f: impl FnOnce...` seam if a production sync caller is restored. - [src/envelope/mod.rs:424-464, src/envelope/mod.rs:466-493, src/envelope/mod.rs:540-565, src/envelope/mod.rs:567-593] - evidence: idiom seeds over src/envelope/mod.rs = 4/3/3 (static read of the four entrypoints 424-593. - -## own -- d2b-broker-p6#6 sev=low blast=leaf effort=S verdict=actionable - in `context_worker_loop` the Bootstrap reply clones the entire persisted state (`let _ = reply.send(Ok(state.state.clone()))`) just to unblock open()/open_async(), which discard the reply value (`?`), so each broker open copies the whole `PersistedTrustedContext` for nothing. - fix: shrink `ContextCommand::Bootstrap`'s oneshot reply to `Sender>` and send `Ok(())` without touching `state`;; delete the `state.state.clone()` site (keep the `let _ =` on the send alone). - [src/envelope/mod.rs:671] - evidence: own seed `\.clone\(\)` over src/envelope/mod.rs = 24 hits; site 671 matched. - -## type -- clean: deterministic-validators and stringly-state seeds checked;; the two `fn validate_*` sites (src/ops/nm.rs:151, src/ops/security_key.rs:82) are boundary cross-checks against existing config/authority state, not per-callsite re-validation;; the 10 `(mode|kind|state): String` occurrences are all audit-record or embedded-contract wire fields (state-posture-contract.json) pinned by the JSON drift gate, so no illegal-state combination is representable at the lens's bar. - -. - -## api - -- d2b-broker-p6#7 sev=medium blast=leaf effort=L verdict=policy-confirmed - `lib.rs` declares `pub mod ops` (src/lib.rs:45) with `pub mod` arms for all 27 executor/helper modules in src/ops/mod.rs:20-94, so every item in them becomes part of the crate's public surface - while the recorded design rationale (src/lib.rs:8-11) is "public API of internal modules that downstream callers may use", and a census finds no downstream crate consumer.. - fix: if a deliberate public-surface decision is desired, keep `pub mod` and record the census in a doc comment or dossier;; otherwise narrow the `pub mod` arms to `pub(crate)` for modules with no out-of-crate consumer (ops/exec_reconcile, ops/audit_op, ops/store_view_posture, ops/store_view_farm, ops/device_worker, ops/security_key, ops/usbip_firewall, ops/nm)and re-export only test-consumed items (`OperationFields` for tests/security_key_broker.rs) under a `#[cfg(any(test, feature = "fake-backends")))]`-style gate. - [src/lib.rs:45, src/ops/mod.rs:20-94] - evidence: census: `d2b_broker::ops` over packages/*/src, packages/*/tests, tests/, docs/reference/, labs/, nixos-modules/ = 10 hits (8 code imports in d2b-broker/tests/{bridge_lifecycle.rs:3, persistent_tap_lifecycle.rs:3, pidfd_handoff_scm_rights.rs:24,:25,:85, pidfd_real_spawner.rs:17, security_key_broker.rs:9};2 doc-comment mentions in d2b-host/src/{modules.rs:19, devices.rs:6}). - - - -## err -- d2b-broker-p6#8 sev=low blast=leaf effort=M verdict=actionable - usbip_unbind_error_is_transient classifies retryable-vs-fatal usbip failures by case-folded substring matching over `stderr`/`error` text (42-Condition-Not-Satisfied, "program does not support"..., "no matching transport"), so a locale or usbip-version message change silently flips the retry decision and the broker's eventual verdict. - fix: parse the failure once at the stderr boundary into a typed `UsbipUnbindFailure { kind: UsbipUnbindFailureKind, transient: bool, detail: String }` (or a documented constant allowlist),and drive the retry loop (and final error reporting) off the typed kind instead of re-scanning strings. - [src/ops/exec_reconcile.rs:1238-1265] - evidence: err seeds over src/ops/exec_reconcile.rs = 56/16/4/1 (static read of usbip_unbind_error_is_transient and its retry call sites 990-1070. -. -- d2b-broker-p6#9 sev=low blast=leaf effort=S verdict=actionable - guest_socket_directory returns `Result<&'static str,...>` with two plain-static-code errors (a "not root-owned" refusal, "no guest" refusal),while the sibling launch-scope pinner uses a typed `DeviceWorkerScopeError` enum - so an internal closed-error str forces callers (live_handlers.rs:2428) to stringly-match an error. - fix: give guest_socket_directory a small `GuestSocketError` enum (or reuse DeviceWorkerScopeError's callers-action split with a `GuestSocket` variant.)and return that instead of a `&'static str`. - [src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/ops/live_handlers.rs:2428] - evidence: err seed4 over src/ops/device_worker.rs = 1 (DeviceWorkerScopeError enum exists; guest_socket_directory uses the bare `&'static str` instead; static read of lines 262-284. - -## serde -- clean: derive-counts, serde-attribute seeds, hand `Deserialize` impls,and serde_json calls checked;; wire-shaped structs in the lane carry `rename_all`, `deny_unknown_fields` (audit identity records, OpAuditRecord via parse_fields!), `skip_serializing_if`/`default` for optional fields, and legacy-compat tests pin optionality meaning;; the untagged `OperationFields` decomposition is deliberate (the JSON drift gate reads back fields per variant),and no missing-validation site warrants a `try_from` row.. - -## obs -- clean: println!/eprintln!/dbg! seeds zero;; tracing events (9 hits) all use named fields (`usbip_subcommand = %subcommand`, `path = %path.display()`, `error = %error`) with no msg-interpolation formatting;; no secrets in fields (audit paths are hashed/redacted at the wrapper boundaries by design). - -## docs -- d2b-broker-p6#10 sev=low blast=leaf effort=S verdict=actionable - the two `pub async fn` store-view farm entrypoints carry the same design-journal sentence "Async form used by the async exec_reconcile and store_sync paths; the sync form was removed with its last sync caller" with a typo (missing space after `paths.`), stating history ("was removed") instead of a contract. - fix: trim to a one-line contract ("Async counterpart used by the async exec_reconcile/store_sync callers.") at both sites, and add `# Errors`-style failure notes where the error enum is non-obvious. - [src/ops/store_view_farm.rs:66-72, src/ops/store_view_farm.rs:191-197] - evidence: docs seeds over src/ops/store_view_farm.rs = 0/0/5 (the two pub async fns are within the `-> Result<` hitset; static read of both docs. -. -- d2b-broker-p6#11 sev=low blast=leaf effort=S verdict=actionable - BrokerEnvelope::call, call_with_fds,and call_nested_with_fds return `Result<_, EnvelopeRefusal>` with no `# Errors` section, so failure modes (14 closed refusal-code consts, e.g. subscriber-only, scope refusals, budget refusals) must be chased around the file to be known. - fix: add an `# Errors` block to each of the three pub methods naming the closed `EnvelopeRefusal` vocabulary and pointing at the refusal constants. - [src/envelope/mod.rs:1118, src/envelope/mod.rs:1136, src/envelope/mod.rs:1187] - evidence: docs seeds over src/envelope/mod.rs = 67/0/18 (canonical section hits zero amid 18 public `-> Result<` items; static read of the call trio. -. -- d2b-broker-p6#12 sev=low blast=leaf effort=S verdict=actionable - apply_with_reload/remove_with_reload doc prose narrates design history ("The dispatcher now lands on ops::nm even though the live path is still a thin wrapper... future coexistence/reload-verification work"), which rots and reads as rendered journal prose on a public item. - fix: rewrite the doc as a plain two-sentence contract (what it does, when reload verification kicks in),and move the rationale to the module doc if it must be preserved. - [src/ops/nm.rs:293-301, src/ops/nm.rs:303-308] - evidence: docs seeds over src/ops/nm.rs = 12/0/9 (static read of the two wrapper docs 288-308. - -## perf -- d2b-broker-p6#13 sev=low blast=leaf effort=S verdict=actionable - contract_store_view_levels re-parses the embedded `include_str!` JSON contract (STATE_POSTURE_CONTRACT) on every call (down per-VM posture passes; each row also re-parses the contract via contract_store_view_level, so the same ~600-line document is parsed many times per sync pass. - fix: pre-parse once into a `static CONTRACT: LazyLock` (or `OnceLock`|and resolve per-row levels/profiles from the cached parse, deleting per-call `ContractFile::parse` sites. - [src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/store_view_posture.rs:310-352] - evidence: static (unmeasured); hot-enough path only with many VMs; read of contract_store_view_levels 194-271 and its row sink 310-352). - -## conc -- d2b-broker-p6#14 sev=low blast=leaf effort=S verdict=actionable - the invocation-id counter uses `Ordering::AcqRel` (`self.invocations.fetch_add(1, Ordering::AcqRel)`), but no reader of the counter or its derived id synchronizes on it - the returned old value is consumed only by the calling thread/audit record, so Relaxed is the weakest correct ordering. - fix: use `Ordering::Relaxed` at src/envelope/mod.rs:1146 (and at the test double's `observed.fetch_add` at src/envelope/mod.rs:2144). - [src/envelope/mod.rs:1146, src/envelope/mod.rs:2144] - evidence: conc seeds over src/envelope/mod.rs = 5/7/10/0 (atomic hits include the AcqRel counter; static read of the counter's only use 1140-1160. - -## async -- clean: async seeds (319 async/await, 3 tokio::spawn writer/stderr-drain tasks, 0 tokio::sync, 39 tokio main/test+block_on) checked;; the trusted-context store's worker uses the sanctioned bounded-worker pattern (async-gate-allow markers "dedicated bounded worker per plan R4" at src/envelope/mod.rs:699,725,798),the sync store twins (`open`/`epoch`/`holds_zone`/`publish`and Drop)run off the R4 worker thread by design,and no production path blocks an executor worker;; no guard is held across `.await`, no cancellation-safety hazard found (handler task abort at budget expiry is deliberate, KTD4; stdin-writer `tokio::spawn` at store_view_farm.rs:135,:247 is dropped after write, fine. - -## unsafe -- clean: unsafe seeds over the lane = 0/0/6/0;; the six `from_raw` hits are all safe std/nix constructors (`io::Error::from_raw_os_error`, `Pid::from_raw`, `Gid::from_raw`),no `unsafe` block, unsafe fn, or unsafe impl exists in these files. - - - -## ffi -- N/A: all four ffi seeds zero in these files; no FFI boundary lives in the lane - the crate's extern surface sits in src/sys.rs etc. (out of this part's scope).. - - - -## macro -- clean: macro_rules! hits = 2 (src/ops/audit_op.rs:475 parse_fields!, src/ops/audit_op.rs:981 roundtrip_test!) - both are the legitimate "generate an impl per type from a small list" use (the parse_fields! macro generates serde impls for 40+ OperationFields variants with a single local pattern;,roundtrip_test! is test-only); no proc-macro, no `$crate`, no hygiene escape hatch.. - -## test -- clean: 109 #[test]/#[tokio::test] + 331 assert seeds, zero proptest/insta/rstest, zero #[ignore];; suite assertions target behavior (refusal codes, legacy-compat parses, fd-leg round-trips, causality-back timeouts),tests are deterministic (tempdir scratch roots, derived/seed paths,,no network, injected time),and no test that cannot fail was found in the lane's tests/**. - - - -## Coverage -- idiom: 5 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 2/0/10) -- api: 1 finding(s) -- err: 2 finding(s) -- serde: clean (seeds ran: 24/34/0/39) -- obs: clean (seeds ran: 0/0/0/9) -- docs: 3 finding(s) -- perf: 1 finding(s) -- conc: 1 finding(s) -- async: clean (seeds ran: 319/3/0/39) -- unsafe: clean (seeds ran: 0/0/6/0) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface in the lane - the crate's extern boundary lives in src/sys.rs (out of this part's scope)) -- macro: clean (seeds ran: 2/0/0/0) -- test: clean (seeds ran: 109/331/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md deleted file mode 100644 index 35242b534..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-broker-p7.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-broker-p7 - d2b-broker - part 7/7 -Baseline: 6ebdd4cec | LOC audited: 10265 (excl. src/generated/**, non-Rust src/ops/state-posture-contract.json) | modules: ops::media, kernel_ops, ops::network, catalog, ops::state_dir, protocol, bootstrap -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 7/7 (src/ops/media.rs, src/kernel_ops.rs, src/ops/network.rs, src/catalog.rs, src/ops/state_dir.rs, src/protocol.rs, src/bootstrap.rs; src/ops/state-posture-contract.json excluded, non-Rust wire contract) - -## idiom -- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=14; all 14 accumulation sites are async `read_dir`/`fill_buf` loops with early returns, test line readers, and hash-input string building - no iterator-pipeline conversions warranted. - -## own -- d2b-broker-p7#1 sev=low blast=leaf effort=S verdict=actionable - enroll's registry-read fallback clones the just-written record although it is never used again - fix: replace `unwrap_or_else(|_| vec![record.clone()])` with `unwrap_or_else(|_| vec![record])` in `enroll` - [packages/d2b-broker/src/ops/media.rs:220] - evidence: `\.clone\(\)` seed = 85 hits; site read confirms `record` is only borrowed (`write_registry_record(resolver,&record)`) and then moved into the fallback `vec!` - no use after line 220; combined own seed mass 358 (>200): sampled: 50 of 358 hits (all seed-1 hit lines read in full; seed-2 hits are owned-build string materialization and wire-render clones - none avoidable; the sole `RefCell<` (network.rs:984)is a `#[cfg(test)]` fake). - -## type -- d2b-broker-p7#2 sev=medium blast=leaf effort=S verdict=actionable - QmpAttachCleanup models its four-step rollback as four bools (16 states, ~5 valid)with a fixed teardown order - fix: replace `device_added/raw_added/file_added/fdset_added: bool` with an ordered step list or enum so rollback order cannot drift from the attach order - [packages/d2b-broker/src/ops/media.rs:889-892] - evidence: `is_\w+: bool|\w+_flag: bool` seed = 1 hit (the four fields at media.rs:889-892; rollback order fixed at 898-943(`device_del`->`blockdev-del` raw->file->`remove-fd`); the valid step set lives only in the attach flow - a future fifth step would silently bypass teardown). - -## api -- d2b-broker-p7#3 sev=low blast=leaf effort=S verdict=actionable - kernel_table clones the whole KernelConfig into an Arc because it takes `&KernelConfig` - fix: take `config: KernelConfig` by value (or `Arc`) so the one-time clone disappears; the per-handler Arc clones stay - [packages/d2b-broker/src/kernel_ops.rs:99-100] - evidence: `pub .*\b(Arc|Rc|Box|RefCell)<` seed = 0 hits (no managed types in signatures; the Arc appears only in the fn body); census: `kernel_table` over packages/,nixos-modules/,tests/,docs/reference/,labs/ = 7 hits (kernel_ops.rs:99 + 6 in-crate call sites in runtime.rs:7145,14485,14798,15227,15545,17597, all passing a locally-built `&KernelConfig`). - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(`=289, `let _ = |\.ok\(\);`=28, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`=1, `enum \w*Error`=3 (sampled: 50 of 321 hits; every production unwrap/expect site read: all are invariant expects (`BrokerOperationRow` committed rows at kernel_ops.rs:667,670,673,699,702,705; validated fdset id at media.rs:705;`[u8;4]` prefix try_into at protocol.rs:98,144 - the rest are in-file `#[cfg(test)]` assertions; the 28 `let _ =`/`.ok();` sites are best-effort rollback/server patterns; the three error enums (`MediaOpError`, `NetworkOpError`, `PrepareStateDirError`) carry stable wire codes - no panic-policy breach found) - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize`=13, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=46, `impl .*Deserialize.*for`=0, `serde_json::from_|serde_json::to_`=36; all wire types (bootstrap.rs wire module, media registry records, network.rs `PersistentTapRealization`, protocol framing values)use `rename_all`/`deny_unknown_fields`/internal enum tags, deliberate `#[serde(default)]` on optional fields; no hand-written deserializers, no parse-validation gap found. - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(`=0, `(info|debug|warn|error|trace)!\(`=1, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=4 (1 real: media.rs:431 structured `tracing::warn!` with named fields `vm_id`/`media_ref`/`slot`; 3 false positives: `catalog::` x2 and `Backlog::` match the `log::` alternation); no secret/PII-in-log paths found. - - - -## docs -- d2b-broker-p7#4 sev=medium blast=leaf effort=M verdict=actionable - media.rs's public ops surface carries no doc comments - fix: add doc blocks to each: MediaOpError variants, the four outcome structs (esp. BootOutcome's four booleans),and the pub ops fns (`enroll`/`refresh_registry`/`boot`/`system_powerdown`/`query_status`/`quit`/`attach`/`detach`),covering preconditions, outcome semantics,and `# Errors` on the `Result` fns - [packages/d2b-broker/src/ops/media.rs:35, packages/d2b-broker/src/ops/media.rs:167-186, packages/d2b-broker/src/ops/media.rs:188, packages/d2b-broker/src/ops/media.rs:238, packages/d2b-broker/src/ops/media.rs:254, packages/d2b-broker/src/ops/media.rs:270, packages/d2b-broker/src/ops/media.rs:281, packages/d2b-broker/src/ops/media.rs:322, packages/d2b-broker/src/ops/media.rs:331, packages/d2b-broker/src/ops/media.rs:339] - evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)`=102, `/// # (Examples|Errors|Panics|Safety)`=0; item-by-item read of media.rs:35-56,167-186,188-339 confirms no preceding `///` blocks on any pub item in this module. -- d2b-broker-p7#5 sev=medium blast=leaf effort=S verdict=actionable - protocol.rs's framing surface (cap const + sync framing fns)carries no docs although it is the broker wire contract - fix: doc `MAX_FRAME_SIZE` and the six framing fns (length-prefix format, cap enforcement, `Option::None` on empty socket, fd-ancillary semantics), mirroring the async wrappers' existing docs - [packages/d2b-broker/src/protocol.rs:13, packages/d2b-broker/src/protocol.rs:16, packages/d2b-broker/src/protocol.rs:29, packages/d2b-broker/src/protocol.rs:43, packages/d2b-broker/src/protocol.rs:52, packages/d2b-broker/src/protocol.rs:85, packages/d2b-broker/src/protocol.rs:121] - evidence: docs seeds 102/0 as above; the async twins (`AsyncSeqpacket`, `AsyncSeqpacketListener`, `connect_seqpacket_bounded`)do carry docs, so the gap is confined to the sync framing path; census: `connect_seqpacket|bind_seqpacket|send_json_frame|recv_json_frame|MAX_FRAME_SIZE` over packages/,nixos-modules/,tests/,docs/reference/,labs/ = heavy use (runtime.rs, forwarding.rs, envelope/, d2bd-runtime/, d2b-contracts/, tests/, docs/reference/tap-dag-contract.md). -- d2b-broker-p7#6 sev=medium blast=leaf effort=S verdict=actionable - state_dir.rs publishes nine undocmented pub items (types + fns)with no `# Errors` on the `io::Result` fns - fix: add item-level doc contracts to `DirKind`, `PrepareDirRequest`, `PrepareDirAudit`, `ReplaceOrCreateResult`, `prepare_dir`, `live_prepare_runtime_dir`, `PreparedStateDir`, `live_prepare_state_dir` (and `# Errors` where Result) - [packages/d2b-broker/src/ops/state_dir.rs:47, packages/d2b-broker/src/ops/state_dir.rs:53, packages/d2b-broker/src/ops/state_dir.rs:70, packages/d2b-broker/src/ops/state_dir.rs:83, packages/d2b-broker/src/ops/state_dir.rs:89, packages/d2b-broker/src/ops/state_dir.rs:161, packages/d2b-broker/src/ops/state_dir.rs:204, packages/d2b-broker/src/ops/state_dir.rs:211] - evidence: docs seeds 102/0 as above; field-level `///` comments exist (e.g. mode units, vm_id_or_scope)but no item-level contract on any of the nine pub items, and `prepare_dir`'s root-ownership refusal guard is explained only in code comments. - -## perf -- d2b-broker-p7#7 sev=medium blast=wide effort=M verdict=actionable - recv_json_frame allocates and zeroes a 1 MiB buffer (`MAX_FRAME_SIZE + 4`)per received frame on every broker/client envelope path - fix: peek the 4-byte length prefix (`recvmsg` with `MSG_PEEK`)then allocate `declared + 4` exactly,, or thread a reusable buffer through the receive path; apply the same size-exactness to `recv_json_frame_with_fds` - [packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125] - evidence: targeted grep `vec!\[0_u8; MAX_FRAME_SIZE` = 1 hit (protocol.rs:86; the fd variant passes the same 1 MiB ceiling at 125);`Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` seed = 44 hits; the same 1 MiB per-receive pattern appears at sibling sites d2bd-runtime/src/unix_transport.rs:207,280 and d2b-contracts-broker/src/kernel_client.rs:202 (candidate for cross-crate consolidation); static (unmeasured) - no benchmark exists. - - - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope`=9 (all 9 are `std::thread::spawn` sites in `#[cfg(test)]` fake QMP servers), `\bMutex<|\bRwLock<`=0, `Atomic\w+|Ordering::`=0, `thread_local!|unsafe impl (Send|Sync) for`=0; no production threads,locks, or atomics in scope. - - - -## async -- d2b-broker-p7#8 sev=high blast=wide effort=S verdict=actionable - write_redacted_registry_index_at_path resolves the fixed d2bd group via nss `Group::from_name` synchronously on an executor worker on every registry write (enroll/refresh/boot) - fix: resolve the gid once (lazy static or serve-time config injected into the ops context)and return `MediaOpError::Registry` on absence, so the nss lookup leaves the async hot path - [packages/d2b-broker/src/ops/media.rs:2100, packages/d2b-broker/src/ops/media.rs:2126] - evidence: `Group::from_name` over the assigned files = 1 hit (media.rs:2126; nss lookup is not a clippy::disallowed_method (absent from clippy.toml's disallowed list, so not tracked by the blocking census - actionable per U1 (d) 2/4); static (unmeasured)per-write latency``` - -## unsafe -- clean: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=7 (all 7 are safe std constructors `io::Error::from_raw_os_error` at protocol.rs:383/kernel_ops.rs:2073-2074 and `FileType::from_raw_mode` at media.rs:1798,1838), `unsafe_code`=0; no `unsafe` blocks in scope (consistent with U1 (d) 8's exception set). - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0 all zero; no foreign-caller boundary in this part) - -## macro -- clean: seeds `macro_rules!`=2, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; the two catalog macros (`wire_variants!` at catalog.rs:301,and `audit_fields!` at catalog.rs:373)are deliberate impl-per-enum generators with narrowest fragment specifiers and a documented completeness-gate purpose - not findings. - - - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]`=74 (src) + 58 (tests/), asserts=206 (src) + 219 (tests/), `#\[ignore\]`=0 (src+tests); reviewed suites are behavioral gates (catalog audit gates, QMP fake-server command-sequence tests, state_dir fs/posture regressions, broker protocol fd round-trips, profile/separation/retirement integration matrix) - no cannot-fail tests found. - - - - - -## Coverage -- idiom: clean (seeds ran: 0/0/14) -- own: 1 finding(s) -- type: 1 finding(s) -- api: 1 finding(s) -- err: clean (seeds ran: 289/28/1/3; sampled: 50 of 321) -- serde: clean (seeds ran: 13/46/0/36) -- obs: clean (seeds ran: 0/1/0/4) -- docs: 3 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 9/0/0/0) -- async: 1 finding(s) -- unsafe: clean (seeds ran: 0/0/7/0) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign-caller boundary in this part) -- macro: clean (seeds ran: 2/0/0/0) -- test: clean (seeds ran: 74+58/206+219/0+0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md deleted file mode 100644 index 45e15a433..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p1.md +++ /dev/null @@ -1,83 +0,0 @@ -# d2b-bus-p1 - d2b-bus - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10547 (excl. src/generated/**) | modules: router, authorization, registry, metrics -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/router.rs, src/authorization.rs, src/registry.rs, src/metrics.rs - -## idiom -- d2b-bus-p1#1 sev=low blast=leaf effort=S verdict=actionable - AuthoritativeUnixSubjectResolver::resolve_for_service collects matching subject indices into a Vec and indexes [0], allocating and double-scanning where a take-two iterator would do - fix: replace the collect-then-index with subjects.iter().enumerate().filter_map(...) checked via next() then next().is_some() - [packages/d2b-bus/src/router.rs:1773-1781] - evidence: seeds `for \w+ in 0\.\.` = 4 (3 test loops, 1 fixed-round Feistel loop at router.rs:2641), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 (invariant-preserving Default at router.rs:148, cfg-macro test impls at 2164-2171), `let mut \w+ = (String|Vec)::new\(\)` = 0; the collect-then-index shape is the only production accumulation - -## own -- d2b-bus-p1#2 sev=low blast=leaf effort=S verdict=actionable - ResourceCall::authorization_request clones the whole AssignmentIdentity and mutation Vec just to learn whether ScopedCommitTransport::new rejects them, and invoke clones the same pair again to build the real transport - fix: add a reference-taking ScopedCommitTransport::validate(&AssignmentIdentity, &[ScopedResourceMutation]) in d2b-core-controller and call it from authorization_request so the validation clone disappears - [packages/d2b-bus/src/router.rs:480, packages/d2b-bus/src/router.rs:2928] - evidence: seeds `\.clone\(\)` = 316 (260 router + 41 authorization + 15 registry; production sites are owned-value constructions for RouteKey/SessionAuthorizationRequest/Arc handles), `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 44, `Rc<|RefCell<|Arc and scope: Option that are always both Some or both None, with a runtime validate_scoped re-check at every use site to keep the pair in sync - fix: fold the pair into one Option<(AssignmentIdentity, ScopedResourceScope)> or a ScopedQuery struct so the one-Some state is unrepresentable and the re-validation disappears - [packages/d2b-bus/src/router.rs:218-219, packages/d2b-bus/src/router.rs:298-337] - evidence: seeds `fn validate_\w+|fn check_\w+` = 7 (boundary validators), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the Option pair is the named skill smell, enforced only by construction plus runtime checks -- d2b-bus-p1#4 sev=low blast=leaf effort=M verdict=actionable - UnixSubjectRecord holds expected_peer: Option and expected_peer_uid: Option where exactly one is always Some, and bind() ORs the two options at match time as if the state were open - fix: replace the pair with an enum (Exact(PeerCredentials) | Uid(u32)) so the exactly-one invariant is structural and the runtime OR branch disappears - [packages/d2b-bus/src/router.rs:1445-1446, packages/d2b-bus/src/router.rs:1667-1674] - evidence: seeds `fn validate_\w+|fn check_\w+` = 7, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the pair is enforced by the two constructor families (new vs guest_for_uid/provider_for_uid) and branched on at bind and resolve_for_service - -## api -- d2b-bus-p1#5 sev=medium blast=leaf effort=S verdict=actionable - ZoneBus exposes eight pub constructors but only new, with_interaction_subject_issuer, and with_clock_observer_and_metrics_and_interaction_subject_issuer have production callers; with_observer, with_observer_and_metrics, with_clock, with_clock_and_observer, and with_clock_observer_and_metrics are internal delegation rungs or test-only - fix: keep the three live constructors pub, move with_clock/with_clock_observer_and_metrics under #[cfg(test)] or pub(crate), and delete or fold with_observer/with_observer_and_metrics/with_clock_and_observer - [packages/d2b-bus/src/router.rs:1208, packages/d2b-bus/src/router.rs:1224, packages/d2b-bus/src/router.rs:1258, packages/d2b-bus/src/router.rs:1267, packages/d2b-bus/src/router.rs:1287] - evidence: census: `ZoneBus::` over packages/ = 4 files; external ctor calls = new (d2bd/src/resource_runtime.rs:3426, d2bd-runtime/src/resource_runtime_support.rs:3432), with_interaction_subject_issuer (d2bd/src/interaction_composition.rs:4879), with_clock_observer_and_metrics_and_interaction_subject_issuer (d2bd/src/interaction_composition.rs:6976); with_clock/with_clock_observer_and_metrics = test-only (router.rs:4946, 5422, session_seam_tests.rs:578); the remaining three = 0 callers anywhere; prior relay-island surface cut U12 applied (docs/explanation/over-engineering-audit-record.md:830) and its cross-crate ownership refusal (docs/audits/2026-09-23-ponytail-audit/README.md:153) consulted, not re-proposed -- d2b-bus-p1#6 sev=medium blast=leaf effort=S verdict=actionable - native_authorizer() returns Arc in a pub signature on both BusAuthorizer and ZoneBus and has zero callers anywhere in the workspace, so the shared-authority accessor is dead surface that also leaks the Arc type - fix: remove both accessors or reduce them to pub(crate) until a daemon consumer exists - [packages/d2b-bus/src/authorization.rs:75, packages/d2b-bus/src/router.rs:1415-1416] - evidence: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits, both this accessor pair; census: `native_authorizer` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both inside d2b-bus (definition plus the ZoneBus delegation) - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(` = 459 (318 router + 133 authorization + 2 registry + 6 metrics; production sites are only router.rs:90 and 4158 named-invariant expects plus the fixed-ref expects at 2219-2222 and 3119-3230, all card false positives), `let _ = |\.ok\(\);` = 31 (oneshot best-effort sends and deliberate metric-emit swallows), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 8 (7 test panics, 1 unreachable! on the impossible AssignmentVerb::CommitBatch variant at router.rs:712), `enum \w*Error` = 5 (closed taxonomies with class accessors, no string-matching callers) - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 2 (metrics.rs:427 production frame construction following d2b-telemetry's emit_metric pattern, authorization.rs:933 test helper); no derives, no deserialization, no untrusted input crossing in this partition - -## obs -- N/A: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\(\"` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0 real (the 13 raw matches are ApiCatalog:: false positives); the crate declares no tracing/log dependency in packages/d2b-bus/Cargo.toml - -## docs -- d2b-bus-p1#7 sev=medium blast=leaf effort=S verdict=actionable - The exported observer contract BusEvent, BusFailureReason, BusObserver, and NoopBusObserver carry no doc comments, so the semantics of the 17 failure reasons and when record fires are undocumented for the d2bd consumer - fix: add module-level or item docs stating when each event is recorded and what each BusFailureReason variant means - [packages/d2b-bus/src/router.rs:1126, packages/d2b-bus/src/router.rs:1135, packages/d2b-bus/src/router.rs:1187, packages/d2b-bus/src/router.rs:1192] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158; these four items have no preceding /// line while every neighboring item does; NoopBusObserver is consumed by d2bd/src/interaction_composition.rs:6981 -- d2b-bus-p1#8 sev=low blast=leaf effort=S verdict=actionable - DEFAULT_MAX_ROUTES_PER_SESSION and DEFAULT_MAX_TOTAL_ROUTES are pub consts without docs while their sibling DEFAULT_MAX_PAYLOAD_BYTES has one - fix: add one-line docs naming the bound each constant sets - [packages/d2b-bus/src/router.rs:67-68] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158; lines 67-68 have no preceding /// comment -- d2b-bus-p1#9 sev=low blast=leaf effort=S verdict=actionable - CommittedInteractionSubjectInstallBody (consumed by d2bd), AuthorizationErrorClass, EndpointSessionFailure::class/code/remediation, and the metrics label accessors are pub items without doc comments - fix: add one-line docs to each, at least on the struct and the class enum - [packages/d2b-bus/src/router.rs:1895, packages/d2b-bus/src/authorization.rs:401, packages/d2b-bus/src/registry.rs:259-267, packages/d2b-bus/src/metrics.rs:110] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158; these items have no preceding /// line; CommittedInteractionSubjectInstallBody is constructed by d2bd/src/resource_runtime.rs:591 -- d2b-bus-p1#10 sev=low blast=leaf effort=S verdict=actionable - No pub Result-returning item carries a canonical # Errors section anywhere in the partition (94 Result-returning pub items, zero sections), so the failure conditions of non-obvious APIs such as BusIngress::invoke and ZoneRegistrar::register_component_session are undocumented - fix: add # Errors sections to the non-obvious Result-returning pub items, starting with the bus entry points - [packages/d2b-bus/src/router.rs:3709, packages/d2b-bus/src/router.rs:3261, packages/d2b-bus/src/registry.rs:366] - evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 158, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 94 - -## perf -- d2b-bus-p1#11 sev=low blast=leaf effort=S verdict=actionable - The WatchSink delivery path copies every watch frame payload with frame.payload().to_vec() before send_and_wait_ack, allocating a fresh Vec per frame on the watch-delivery path (the recorded kept-half credit path, B1, docs/explanation/over-engineering-audit-record.md:463) - fix: pass the payload slice through OutgoingStream::send_and_wait_ack (streams.rs:661) or clone once at the bridge so per-frame allocation is avoided - [packages/d2b-bus/src/router.rs:4228-4235] - evidence: `format!\(` = 13 (12 doc/test, 1 cold bootstrap path at router.rs:2221), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 87 (mostly tests), `\.to_string\(\)` = 5 (test helpers); static (unmeasured), no benchmark exists - -## conc -- d2b-bus-p1#12 sev=low blast=leaf effort=S verdict=actionable - RouteLeaseState wraps a single bool in Mutex, paying a lock for one flag that an atomic would serve - fix: replace revoked: Mutex with AtomicBool and use Acquire/Release in with_active and remove - [packages/d2b-bus/src/registry.rs:522-523, packages/d2b-bus/src/registry.rs:573-582] - evidence: seeds `std::thread::|thread::spawn|thread::scope` = 1 (test-only thread::scope at router.rs:4791), `\bMutex<|\bRwLock<` = 25 (all std Mutex with into_inner poisoning recovery, brief critical sections, none across await), `Atomic\w+|Ordering::` = 49 (ManualClock AcqRel/Acquire pair, ComponentActivity Release/Acquire valid flags, test counters), `thread_local!|unsafe impl (Send|Sync) for` = 0 - -## async -- clean: seeds `async fn|async move|\.await` = 203 (198 router + 1 authorization + 4 registry), `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 11 (1 production tokio::spawn at router.rs:2426 for the response dispatcher, 10 test join! sites), `tokio::sync::(Mutex|RwLock|Notify)` = 2 (Notify in the cfg(test) hook struct at 837-838 plus one test import), `#\[tokio::(main|test)\]|Runtime::block_on` = 24; checked: no std lock held across await (all std Mutex critical sections are brief with sanctioned disallowed-method allows and comments), AsyncMutex only for session and inbound receivers, select! biased with cancellation first, lease Drop aborts on cancellation and deadline paths - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; crate lints table forbids unsafe_code (packages/d2b-bus/Cargo.toml:9), so the lens is not applicable - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the partition crosses no foreign boundary - -## macro -- clean: seeds `macro_rules!` = 1 (router.rs:2162 mutate_component_session_admission_trait!, a cfg-gated compile-assertion harness with narrow ident fragment specifiers and unreachable! bodies, deliberate), `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 - -## test -- d2b-bus-p1#13 sev=high blast=leaf effort=S verdict=actionable - emitter_records_only_closed_bus_labels exercises every BusTelemetry method but asserts nothing, and every emit outcome is swallowed by `let _ = self.emit(...)` inside BusMetrics, so a label drifting out of the closed set passes silently - fix: make the test assert something observable, for example return EmitOutcome from a test-visible emit path or expose a read-back of the BoundedEmitter queue in d2b-telemetry, and assert Ok per call (route review-pass) - [packages/d2b-bus/src/metrics.rs:612-633, packages/d2b-bus/src/metrics.rs:451-534] - evidence: seeds `#\[test\]|#\[tokio::test\]` = 62 (40 router + 19 authorization + 3 metrics), `assert_eq!\(|assert_ne!\(|assert!\(` = heavy across the suite, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the named test contains zero assertion calls and no panic path, so it cannot fail on the property it names; the remaining 61 tests assert observable behavior (delivery counts, error variants, revocation races with Notify hooks, start_paused timeouts, redaction of Debug output); the tests/ui compile-fail fixtures (4 files) belong to the session_seam_tests macro surface in part 2 - -## Coverage -- idiom: 1 finding -- own: 1 finding -- type: 2 findings -- api: 2 findings -- err: clean (seeds ran: 459/31/8/5; production unwrap/expect sites are fixed-ref expects and named-invariant expects per card false positives) -- serde: clean (seeds ran: 0/0/0/2; the 2 s4 hits are frame construction following the d2b-telemetry pattern and a test helper) -- obs: N/A (seeds: 0/0/0/0 real; no tracing/log dependency in the crate manifest) -- docs: 4 findings -- perf: 1 finding -- conc: 1 finding -- async: clean (seeds ran: 203/11/2/24; no lock held across await, biased select with cancellation first, lease Drop aborts) -- unsafe: N/A (seeds: 0/0/0; unsafe_code = "forbid" in the crate lints table) -- ffi: N/A (seeds: 0/0/0/0; no foreign boundary in the partition) -- macro: clean (seeds ran: 1/0/0/0; single cfg-gated compile-assertion harness macro) -- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md deleted file mode 100644 index dc68257ca..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-bus-p2.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-bus-p2 - d2b-bus - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10327 (excl. src/generated/**) | modules: session/ (contract, enrollment, mod, noise_vectors, prologue, zone_link), session_seam_tests, streams, operations, wire, lib -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: src/session/**, src/session_seam_tests.rs, src/streams.rs, src/operations.rs, src/wire.rs, src/lib.rs - -## idiom -- d2b-bus-p2#1 sev=low blast=leaf effort=S verdict=actionable - `PendingCancelDeliveries::abort_destination` collects into a `Vec` inside a `retain` closure (statement-style accumulation with a side effect in the predicate) instead of partitioning the entries - fix: `let (aborted, kept): (Vec<_>, Vec<_>) = entries.drain(..).partition(|entry| entry.destination == session); *entries = kept;` and abort the drained handles - [packages/d2b-bus/src/operations.rs:302-310] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 3 hits; the other two hits are test task vectors (streams.rs:1221, 1283) where a collect would obscure the spawn loop, and the hand-written `impl Default for StreamLimits` (streams.rs:77) and `impl PartialEq/Eq for OperationAttempt` (operations.rs:77-83) are deliberate (nonzero defaults; identity semantics) and are not findings -- clean: seeds `for \w+ in 0\.\.` = 10 hits, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits, `let mut \w+ = (String|Vec)::new\(\)` = 3 hits; the index loops are bounded retry loops over queues being mutated (streams.rs:368-402) or test spawn loops, so plain loops are the right shape; one finding above - -## own -- d2b-bus-p2#2 sev=low blast=leaf effort=S verdict=actionable - `SubjectContextDigest::of_subject` builds six owned `String`s (four `to_owned()` on `&str`/`&'static str` fields plus two `to_canonical_string()` calls) only to hash length-prefixed bytes - fix: iterate `&[&str]` slices (the label helpers already return `&'static str`, and the subject/service/purpose accessors expose `&str`) and feed `len()` and `as_bytes()` directly, dropping all six allocations per digest - [packages/d2b-bus/src/session/prologue.rs:72-78] - evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 26 hits; the four avoidable `to_owned()` calls are at prologue.rs:74-77; the remaining hits are test fixtures and wire-rendering boundaries -- d2b-bus-p2#3 sev=low blast=leaf effort=M verdict=actionable - `VerifiedRouteAdmission::revalidate` clones the whole admission body (including the session binding) on every call, and `ZoneLinkSession::admit`/`is_open` invoke it on every forwarded operation - fix: add a by-reference verification path (a `verify_body(&self, body: &RouteAdmissionBody)` helper or a `revalidate` that digests `&self.body` without rebuilding owned evidence) so the re-check allocates nothing - [packages/d2b-bus/src/session/contract.rs:1046-1056, packages/d2b-bus/src/session/zone_link.rs:147] - evidence: seed `\.clone\(\)` = 132 hits; census: `\.revalidate\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 5 sites (contract.rs:1046 definition plus zone_link.rs:147, 218, 256, 358); the clone at contract.rs:1054 exists only to feed the consuming `verify` signature -- clean: seeds `Rc<|RefCell<|Arc` and `liveness: Option` that are always both `Some` or both `None` (the two constructors set them in lockstep), so a half-set lane is representable and would silently skip admission revalidation - fix: fold the pair into one `established: Option` holding both values (the test lane stays the `None` case), making the impossible combination unconstructible - [packages/d2b-bus/src/session/zone_link.rs:111-117] - evidence: type seeds (`fn validate_\w+|fn check_\w+`, `is_\w+: bool|\w+_flag: bool`, `(mode|kind|state): String`) = 0/0/0 hits; lens applicable because the part declares structs and enums; the lockstep invariant is read from the only two constructors at zone_link.rs:141-195 -- clean: no boolean-flag soup or stringly-typed state found; the enrollment machine already models its five states as an enum with checked transitions, and the `revoked` marker with a persisted record is a documented crash-window state (enrollment.rs:392-396), not a flag finding - -## api -- d2b-bus-p2#5 sev=medium blast=leaf effort=S verdict=actionable - two public types named `Cancellation` are reachable from the crate root: `d2b_bus::Cancellation` (operations) and `d2b_bus::session::Cancellation` (the re-exported `d2b_session::Cancellation`), so a caller importing both modules gets a name collision and can hand the wrong token to a handler - fix: drop `Cancellation` from the `d2b_session` re-export block in session/mod.rs (the bus's own token shadows the need) or rename one of the two - [packages/d2b-bus/src/lib.rs:34, packages/d2b-bus/src/session/mod.rs:89-97] - evidence: seed `^\s*pub use ` = 15 hits; census: `d2b_bus::session::Cancellation` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 qualified uses today, but the in-crate distinction is already live at router.rs:2663-2664 where `Cancellation` and `d2b_session::Cancellation` sit in one struct -- clean: no `Arc`/`Rc`/`Box`/`RefCell` in a public signature beyond the deliberate `Arc`/`Arc` observer injection (streams.rs:149-150) and the `Arc`-shared `ZoneLinkSession` driver owner, both with private fields; the lib.rs re-export arms are the house single-surface pattern - -## err -- d2b-bus-p2#6 sev=medium blast=leaf effort=S verdict=actionable - public `ZoneBoundPolicyIdentity::with_provider` returns `Result`, a string a caller must string-match instead of matching on a variant - fix: return a closed error type (reuse `ZonePolicyError` with a new `NotProviderRef` variant, or a small `ZoneBoundPolicyIdentityError` enum) for the single failure condition - [packages/d2b-bus/src/wire.rs:49-56] - evidence: seed `-> Result<` = 56 hits; census: `ZoneBoundPolicyIdentity::with_provider` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both in wire.rs tests (wire.rs:171, 179), so the fix carries no external call-site churn -- clean: seeds `\.unwrap\(\)|\.expect\(` = 827 hits (the overwhelming majority inside `#[cfg(test)]` modules and test fixtures, which the card exempts), `let _ = ` = 7 hits (the one in production is the deliberate fence compare_exchange at zone_link.rs:232, documented as keeping the stronger fence), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 31 hits (test assertions and the `unimplemented` test-driver helper), `enum \w*Error` = 6 hits; production `expect`s are internal-invariant assertions with named reasons (streams.rs:372-408, operations.rs:487) and every std Mutex poison is recovered via `into_inner()`; one finding above - -## serde -- N/A: seeds `derive\([^)]*(De)?[Ss]erialize`, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`, `impl .*Deserialize.*for`, `serde_json::from_|serde_json::to_` = 0/0/0/0 hits over the part; the crate's serde_json dependency is consumed in part 1 (router.rs), so this part crosses no serde boundary - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 2 (both false positives: `ApiCatalog::standard()` in session_seam_tests.rs:582 and 1289 matches `log::` inside the word "catalog"); the part emits no telemetry at all and the crate declares no tracing/log dependency, so there is nothing to judge beyond absence - -## docs -- d2b-bus-p2#7 sev=medium blast=leaf effort=S verdict=actionable - `pub struct Cancellation` (re-exported at the crate root) has no doc comment while every sibling public item does, leaving the opaque token's contract (crate-private construction, one-attempt observation, `is_cancelled`) undocumented - fix: add a `///` doc comment stating the token is minted only by the bus and observes one operation attempt - [packages/d2b-bus/src/operations.rs:124-125] - evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 137 hits, `/// # (Examples|Errors|Panics|Safety)` = 0; the struct at operations.rs:125 is the only root-re-exported item without a doc comment -- d2b-bus-p2#8 sev=low blast=leaf effort=M verdict=actionable - public `Result`-returning constructors and accessors (`StreamName::parse`, `OperationId::parse`, `ZoneBoundPolicyIdentity::digest`, `ZoneEndpointPolicy::lower`) carry no `# Errors` section naming which condition produces which failure, even though the failure conditions are closed and enumerated in the error enums - fix: add `# Errors` sections to the public parse/lower/digest items - [packages/d2b-bus/src/streams.rs:39-40, packages/d2b-bus/src/operations.rs:24-25, packages/d2b-bus/src/wire.rs:79-82, packages/d2b-bus/src/session/contract.rs:164-165] - evidence: docs seeds: `-> Result<` = 56 hits, `/// # (Examples|Errors|Panics|Safety)` = 0; the repo style is one-line prose docs without canonical sections, so this is a consistency proposal rather than a coverage gap -- clean: module docs are present and substantive (session/mod.rs, prologue.rs, contract.rs, enrollment.rs, zone_link.rs), the redacted `Debug` impls are deliberate and tested, and the compile_fail doctests at contract.rs:312-315 and 760-763 run under `cargo test --doc` - -## perf -- d2b-bus-p2#9 sev=low blast=leaf effort=M verdict=actionable - `OutgoingStream::send_wait` clones the whole payload on every backpressure wakeup because `StreamBridge::send` consumes the `Vec` and drops it on rejection, so a frame up to `max_frame_bytes` (64 KiB) is re-allocated per retry on the bounded-watch delivery path - fix: have `send` return the rejected payload (for example `Result<(), (StreamError, Vec)>`) or split an admit-check from the enqueue so the loop moves the buffer instead of cloning - [packages/d2b-bus/src/streams.rs:642-658] - evidence: static (unmeasured); seed `\.clone\(\)` = 132 hits; census: `send_wait|send_and_wait_ack` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 4 hits, with the production caller at router.rs:4188 -- clean: seeds `format!\(` = 32 hits (all in error paths, digest construction, and test fixtures, which the card exempts), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 31 hits (mostly empty-case collection construction where the empty case is common, plus test fixtures), `\.to_string\(\)` = 1 hit (a test assertion); the BTreeMap choices are for deterministic iteration, and `direction_gauges` already uses saturating accumulation - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 10, `Atomic\w+|Ordering::` = 23, `thread_local!|unsafe impl (Send|Sync) for` = 0; every Mutex and atomic use is a brief non-suspending critical section with a sanctioned `synchronous path` allow (contract.rs:1009-1054, operations.rs:295, streams.rs:562) or a cfg(test) helper, poison is recovered via `into_inner()` rather than `unwrap`, and the fence/attempt/cancellation atomics use correct Acquire/Release pairs with written ordering arguments - -## async -- clean: seeds `async fn|async move|\.await` = 346, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 29, `tokio::sync::(Mutex|RwLock|Notify)` = 2 (the two `use tokio::sync::Notify;` imports), `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the Notify waiters are created before the condition check with the future pinned and `enable()`d (streams.rs:642-676, operations.rs:150-158), which is the correct tokio pattern, no guard is held across an `.await`, and all std-Mutex touches are brief critical sections with sanctioned allows - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0/0/0 hits; seed 4 alone (`unsafe_code = "forbid"` in the manifest) does not make the lens applicable - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char` = 0/0/0/0 hits; the part crosses no foreign-language boundary - -## macro -- N/A: seeds `macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned` = 0/0/0/0 hits over the part (the crate's single macro hit is in part 1); no macro definitions or proc-macro surface - -## test -- d2b-bus-p2#10 sev=medium blast=leaf effort=M verdict=actionable - session_seam_tests.rs waits for service readiness with fixed-count yield and poll loops (`for _ in 0..16 { tokio::task::yield_now().await }` at 1623 and 1808, `for attempt in 0..32` at 1882, `for attempt in 0..8` plus an inner yield loop at 1941-1960), which is machine-dependent and can fail spuriously on a loaded runner - fix: replace with condition-driven waits (oneshot or Notify), the deterministic pattern the same file already uses elsewhere (advance_virtual, dispatched_wait) - [packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_tests.rs:1808-1810, packages/d2b-bus/src/session_seam_tests.rs:1882-1884, packages/d2b-bus/src/session_seam_tests.rs:1941-1960] - evidence: seed `for \w+ in 0\.\.` = 10 hits; the four readiness loops are the only machine-dependent waits in the part, and the file's own comment blocks document the deterministic counterpart pattern -- d2b-bus-p2#11 sev=low blast=leaf effort=S verdict=actionable - `cancel_retry_cannot_reach_a_same_id_replacement_while_tombstone_is_retained` pins the full `Display` sentence of `OperationError::RetainedOperationId`, so a wording change fails the test even though the contract is the variant and its `as_str()` label - fix: assert the variant (the surrounding code already matches on variants) and drop the `to_string()` equality - [packages/d2b-bus/src/operations.rs:1057-1060] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 328 hits; this is the only assertion in the part that pins a `Display` string rather than a variant or label -- clean: seeds `#\[test\]|#\[tokio::test\]` = 113, `assert_eq!\(|assert_ne!\(|assert!\(` = 328, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the suite is strong overall - frozen Noise golden vectors (noise_vectors.rs), deterministic concurrency tests with Barriers and start_paused virtual time (streams.rs:984-1062), error-variant assertions throughout, and the child-process peer test is a documented subprocess pattern; two findings above - -## Coverage -- idiom: 1 finding (seeds 10/3/3) -- own: 2 findings (seeds 132/26/0/0) -- type: 1 finding (seeds 0/0/0; applicable via struct/enum presence) -- api: 1 finding (seeds 137/0/15) -- err: 1 finding (seeds 827/7/31/6) -- serde: N/A (seeds 0/0/0/0 all zero; no serde boundary in this part) -- obs: clean (seeds 0/0/0/2; both hits are `log::` false positives inside `ApiCatalog::`) -- docs: 2 findings (seeds 137/0/56) -- perf: 1 finding (seeds 32/31/1) -- conc: clean (seeds 0/10/23/0) -- async: clean (seeds 346/29/2/0) -- unsafe: N/A (seeds 0/0/0; manifest forbids unsafe_code) -- ffi: N/A (seeds 0/0/0/0 all zero) -- macro: N/A (seeds 0/0/0/0 all zero) -- test: 2 findings (seeds 113/328/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md deleted file mode 100644 index 5cb869590..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-broker.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-contracts-broker - d2b-contracts-broker -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5215 (excl. src/generated/**) | modules: whole crate (broker_wire, host_generation, kernel_client, lib, tests/wire.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) - -## idiom -- d2b-contracts-broker#1 sev=low blast=leaf effort=S verdict=actionable - `response.refusal.clone().unwrap_or_default()` runs inside an `if response.refusal.is_some()` branch, so the default is unreachable and the value is cloned twice - fix: restructure to `if let Some(code) = response.refusal.clone()` or match on the Option once, returning `KernelInvokeError::Refused` in the Some arm - [packages/d2b-contracts-broker/src/kernel_client.rs:225-227] - evidence: seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 1 hit; the is_some/unwrap_or_default pair read at kernel_client.rs:225-227 -- d2b-contracts-broker#2 sev=low blast=leaf effort=S verdict=actionable - `ApplyHostGenerationHandoff::validate` carries a caller-role check that can never fire: `HandoffCallerRole` has exactly two variants and the `!matches!(Lifecycle | Admin)` guard is always false, so the `InvalidTransition` arm is dead code in a security-adjacent validation path - fix: delete the branch (or add the missing third role if one was intended) - [packages/d2b-contracts-broker/src/host_generation.rs:162-167, packages/d2b-contracts-broker/src/host_generation.rs:131-137] - evidence: seed 3 = 1 hit; dead branch confirmed by reading the two-variant enum at host_generation.rs:131-137 -- d2b-contracts-broker#3 sev=low blast=leaf effort=S verdict=actionable - `BrokerCallerRole::for_display()` returns the bare label `"RootUid"` for `RootUid` while every sibling arm returns a stable `d2b-*` audit label, and the value lands in the broker's `peer_role` audit records - fix: align the arm to the scheme, e.g. `"d2b-root"`, and pin it in the existing label test - [packages/d2b-contracts-broker/src/broker_wire.rs:2904-2912, packages/d2b-contracts-broker/src/broker_wire.rs:3149-3163] - evidence: seed 3 = 1 hit; census: `for_display` over packages/ = 12 hits, consumed as `peer_role` audit field at packages/d2b-broker/src/runtime.rs:1654,1731,2456 -- clean: seeds ran (0/0/1); the single `let mut received = Vec::new()` accumulation loop is a side-effect fd-collection drain where the plain loop is the skill's own preference; no index loops, no hand-written derives over derivable ones - -## own -- clean: seeds ran (13/71/0/0); every clone/to_owned is explainable - audit-join string materialization (broker_wire.rs:643,651,698), request-field moves into the envelope (kernel_client.rs:139-145), and the refusal clone before the response is moved (kernel_client.rs:226-227); no Rc/RefCell/Arc/Cow anywhere - -## type -- d2b-contracts-broker#4 sev=medium blast=leaf effort=S verdict=actionable - `HandoffCoordinator.source_remains_usable: bool` is fully derivable from `state` (false iff `Completed`, true in every other phase), so the pair `{ state: Completed, source_remains_usable: true }` is an illegal state constructible through durable-record deserialization and the two fields can desync - fix: drop the field, derive the accessor from `self.state != HandoffState::Completed`, keep `#[serde(default)]` for old broker records (the wire `ApplyHostGenerationHandoffResponse.source_remains_usable` field stays as-is) - [packages/d2b-contracts-broker/src/host_generation.rs:226-232, packages/d2b-contracts-broker/src/host_generation.rs:294-315] - evidence: seed 1 `fn validate_\w+|fn check_\w+` = 2 hits (host_generation.rs:76,256); field/accessor/mutations read at host_generation.rs:226-316; census: `source_remains_usable` over packages/ = 11 hits, consumers use the accessor (d2b-broker/src/ops/host_generation_handoff.rs:390) or the response's own wire field (d2b-provider-activation-nixos driver.rs:1331) -- d2b-contracts-broker#5 sev=medium blast=leaf effort=S verdict=actionable - `CanonicalAuditDigest(pub String)` exposes a public field that bypasses the SHA-256-spelling invariant its `parse` constructor and hand-written `Deserialize` enforce, so a literal construction can mint an invalid digest - fix: make the tuple field private and keep `as_str()` (serde transparent and JsonSchema work with a private field; wire shape unchanged) - [packages/d2b-contracts-broker/src/broker_wire.rs:2805, packages/d2b-contracts-broker/src/broker_wire.rs:2807-2821] - evidence: seed 3 `(mode|kind|state): String` = 3 hits, all wire `kind` code strings (broker_wire.rs:971,2994,3018) that are schema-pinned false positives; census: `CanonicalAuditDigest` over packages/ = 13 hits, every production construction goes through `parse` (d2b-broker/src/runtime.rs:2419,2442; d2bd-runtime/src/broker_transport.rs:63) -- clean: seeds ran (2/0/3); the three `kind: String` fields are wire code strings mirroring the pinned schema (false positive per card); the handoff state machine's runtime phase checks are the deliberate replay-safe design, not a typestate candidate under the stopping rule - -## api -- d2b-contracts-broker#6 sev=medium blast=wide effort=S verdict=needs-contract - `BrokerRequestEnvelope.test_peer_uid: Option` is a test-only peer-uid override carried on the production wire envelope (serialized, schema-visible), honored only under the broker's `config.test_mode` gate - fix: move the override out of the wire type into the broker's test harness (e.g. a test-only envelope wrapper or a `#[cfg(test)]`-visible field) so the production contract carries no test seam - [packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtime.rs:1628-1632] - evidence: seed 1 = 198 pub items (contract-crate wide vocabulary is the card's false positive), seed 2 = 0; census: `test_peer_uid` over packages/ = 26 hits across d2b-broker bootstrap probe helpers, five broker test files, d2bd, d2bd-runtime and kernel_client -- d2b-contracts-broker#7 sev=low blast=family effort=S verdict=actionable - `pub use d2b_contracts::audit_wire::{AuditExportCursor, AuditExportEntry, AuditExportErrorCode}` at broker_wire.rs:13 re-exports another crate's types into this crate's surface, making each item reachable at two paths (`d2b_contracts::audit_wire::*` and `d2b_contracts_broker::broker_wire::*`), off the house single-surface pattern which places re-export arms in lib.rs - fix: move the re-export to lib.rs or drop it and let consumers import from d2b_contracts (sibling d2b-contracts-control/src/public_wire.rs:1 repeats the pattern; X3 may merge the family) - [packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib.rs:7-11] - evidence: seed 3 `^\s*pub use ` = 4 hits; census: `AuditExportEntry|AuditExportCursor|AuditExportErrorCode` over packages/ = 40 hits, consumers import via the broker_wire path (d2b-broker/src/audit.rs:29, d2b/src/dispatch.rs:22, d2bd-runtime/src/wire.rs:544) -- clean: seeds ran (198/0/4); the 198-item pub surface is the deliberate contract-crate wire vocabulary (card false positive); no Arc/Rc/Box/RefCell in signatures; `RunnerLaunchArgs` and `CanonicalAuditDigest` show the private-field-plus-accessor shape; lib.rs re-export arms follow the house pattern - -## err -- clean: seeds ran (114/0/26/3); every unwrap/expect/panic/unreachable site (114 unwrap/expect, 26 panic/unreachable, all listed 3223-4282) sits inside `#[cfg(test)]` (broker_wire.rs tests module, tests/wire.rs) - no panic site reachable from caller input; the three error enums (HandoffError, RunnerLaunchArgsError, KernelInvokeError) are split by caller action with stable Display codes; no swallowed Results (`let _ =` = 0) - -## serde -- d2b-contracts-broker#8 sev=medium blast=wide effort=S verdict=needs-contract - `OpenUnitPidfdRequest` and `StopUnitRequest` combine `#[serde(flatten)] pub unit: UnitRequest` with `deny_unknown_fields` on the containing struct, and serde ignores `deny_unknown_fields` on any type using flatten, so unknown fields in these two wire requests are silently accepted instead of refused - fix: drop the flatten (duplicate the UnitRequest fields or deserialize into a tagged wrapper) or accept-and-validate unknown fields explicitly; the wire admission change needs contract review - [packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/src/broker_wire.rs:1783-1834] - evidence: seed 2 `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 307 hits; the two flatten sites read at broker_wire.rs:1841,1852 with the outer deny_unknown_fields at 1838,1849 -- clean: seeds ran (134/307/0/35); hand-written Deserialize impls (ExportBrokerAuditResponse:2200, RunnerLaunchArgs:2575, CanonicalAuditDigest:2831) are live admission gates in the recorded refusal class (over-engineering-audit-record.md) and validate real invariants; enum representations (adjacent on BrokerRequest/BrokerResponse, internal on ForwardOperationOutcome/BrokerNotification with `#[serde(other)]`) and the pervasive deny_unknown_fields are deliberate pinned wire shapes - -## obs -- N/A: seeds 0/0/0/0 (case-sensitive run; the only case-insensitive `log::` match is the doc-prose word `AuditLog::write_entry` at broker_wire.rs:547) and the crate has no tracing/log dependency (packages/d2b-contracts-broker/Cargo.toml) - -## docs -- d2b-contracts-broker#9 sev=medium blast=leaf effort=S verdict=actionable - every Result-returning public fn lacks the canonical `# Errors` section (seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits crate-wide), so the failure conditions of the handoff state machine, the launch-args bounds, and the kernel client are only recoverable from enum docs - fix: add `# Errors` sections naming the `HandoffError`/`RunnerLaunchArgsError`/`KernelInvokeError` conditions to `SourceGenerationCompatibilityFloorV1::new`, `begin_handoff`, the `HandoffCoordinator` transitions, `RunnerLaunchArgs::new`, and `envelope_invoke_kernel` - [packages/d2b-contracts-broker/src/host_generation.rs:47, packages/d2b-contracts-broker/src/kernel_client.rs:113, packages/d2b-contracts-broker/src/broker_wire.rs:2495] - evidence: seed 3 `-> Result<` = 15 hits (12 public fns: host_generation.rs:50,80,95,153,260,277,286,295,305; kernel_client.rs:118; broker_wire.rs:2495,2809; the other 3 are Deserialize trait impls), seed 2 = 0 hits -- d2b-contracts-broker#10 sev=low blast=leaf effort=S verdict=actionable - four public fns have no doc comment at all: `BrokerCapabilities::w3`, `RunnerRole::as_str`, `BrokerCallerRole::is_admin_uid`, `BrokerCallerRole::for_display` - fix: one-line contract docs (for_display should document the stable audit-label promise) - [packages/d2b-contracts-broker/src/lib.rs:28, packages/d2b-contracts-broker/src/broker_wire.rs:2444, packages/d2b-contracts-broker/src/broker_wire.rs:2900-2904] - evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 195 hits; the four undocumented items confirmed by reading their neighborhoods -- d2b-contracts-broker#11 sev=low blast=leaf effort=S verdict=actionable - doc-comment polish defects in the FdKind/ForwardOperationRequest contract docs: `present.from` (missing space), CJK full-width periods (the FdKind variant docs end in a CJK period), and comma-adjacent spacing (`positions,in the ... list,of`) - fix: reword those doc lines - [packages/d2b-contracts-broker/src/broker_wire.rs:246, packages/d2b-contracts-broker/src/broker_wire.rs:254, packages/d2b-contracts-broker/src/broker_wire.rs:421-430] - evidence: seed 1 = 195 hits; typos read at the cited lines -- clean: seeds ran (195/0/15); the crate's doc discipline is otherwise strong - nearly every pub item carries a contract doc with a load-bearing first sentence, module docs exist in all four modules, and magic values (MAX_FRAME_FDS, DEFAULT_CONTEXT_DEADLINE_MS, MAX_CONTEXT_DEADLINE_MS) document the why - -## perf -- clean: seeds ran (48/2/30); all format!/to_string sites are audit-join rendering (broker_wire.rs:634-730, the card's audit-rendering false positive) or cold error paths (kernel_client.rs:125-223); the two Vec::new() sites are one-shot recvmsg fd collection and test scaffolding; no hot-loop allocation, no attacker-keyed hashing; static (unmeasured) per the card - -## conc -- N/A: seeds 0/0/0/0 (case-sensitive run; the case-insensitive `Atomic\w+` matches were the prose word "atomically" in doc comments at broker_wire.rs:114,2018); no threads, locks, atomics, or unsafe Send/Sync in the crate - -## async -- N/A: seeds 0/0/0/0; no async fn, no .await, no tokio usage anywhere in the crate (kernel_client is a synchronous rustix/socket2 client) - -## unsafe -- N/A: seeds 0/0/0/0; the crate inherits `[lints] workspace = true` with `unsafe_code = "forbid"` (packages/d2b-contracts-broker/Cargo.toml), and no unsafe block, SAFETY comment, or transmute exists - -## ffi -- N/A: seeds 0/0/0/0; no extern "C", no_mangle, repr(C), CStr/CString, or catch_unwind anywhere; the crate crosses no foreign boundary - -## macro -- N/A: seeds 0/0/0/0; no macro_rules!, proc-macro, syn/quote, or $crate usage; the only include is the generated `broker_operation_profiles.rs` (X2's lane) - -## test -- clean: seeds ran (51/127/0/0); 51 `#[test]` (49 in broker_wire.rs tests module, 2 in tests/wire.rs) and ~127 assertions cover wire round-trips, per-field legacy-authority rejection loops with failure messages naming the field, closed-enum matrices, and deliberate wire-constant pins (FD_LEG, STALE_CONTEXT, PROTOCOL_VERSION); no `#[ignore]`, no proptest/insta/rstest; every test can fail on a real regression (the constant pins carry `#[allow(clippy::assertions_on_constants)]` with written reasons) - -## Coverage -- idiom: 3 finding(s) -- own: clean (seeds ran: 13/71/0/0) -- type: 2 finding(s) -- api: 2 finding(s) -- err: clean (seeds ran: 114/0/26/3) -- serde: 1 finding(s) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 3 finding(s) -- perf: clean (seeds ran: 48/2/30) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) -- async: N/A (seeds: 0/0/0/0 all zero; no async code) -- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace `unsafe_code = "forbid"` inherited) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test: clean (seeds ran: 51/127/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md deleted file mode 100644 index d71913112..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-control.md +++ /dev/null @@ -1,90 +0,0 @@ -# d2b-contracts-control - d2b-contracts-control -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5019 (excl. src/generated/**) | modules: whole crate (cli_output, proxy_readiness, public_wire, terminal_wire, unsafe_local_wire) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- clean: seeds `for \w+ in 0\.\.` / `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` / `let mut \w+ = (String|Vec)::new\(\)` ran at 0/0/0; manual check confirms every hand-written `Debug` impl (TerminalWriteStdin, ExecStartArgs, NamedProcessStreamRequest, ScopeIdentity, ShellName, ...) is a deliberate secret-redaction impl per the idiom card's repo false positives, and all other traits are derived. - -## own -- clean: seeds `\.clone\(\)` / `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` / `Rc<|RefCell<|Arc`, encoding 4 states of which 2 are illegal, guarded only by the runtime `validate_audit_page` at deserialize - fix: replace the pair with an enum (`Complete` / `More(AuditExportCursor)`) so the illegal combos are unrepresentable, deleting `validate_audit_page` - [public_wire.rs:2166, public_wire.rs:2203] - evidence: seed `(mode|kind|state): String` + `fn validate_\w+|fn check_\w+` = 22 hits; the complete/next_cursor invariant is the one Option-pair smell in the crate; wire change so needs-contract. -- d2b-contracts-control#2 sev=low blast=wide effort=L verdict=needs-contract - status DTOs carry stringly-typed state (`mode`, `state`, `kind`, `status` as `String`) mirroring daemon-side vocabularies instead of closed enums - fix: convert the closed vocabularies (realm mode, gateway state, qemu runner/registry state, read-model kind) to kebab-case enums on both daemon and wire sides - [cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672, public_wire.rs:2156] - evidence: seed `(mode|kind|state): String` = 22 hits across cli_output.rs and public_wire.rs; shapes are pinned by docs/reference/cli-output schemas and daemon-api.md, so needs-contract. -- d2b-contracts-control#3 sev=low blast=wide effort=M verdict=needs-contract - `MutationFlags` models dry-run/apply/json as three booleans while the doc comment itself records that "the daemon rejects requests that set neither `dry_run` nor `apply`", i.e. an illegal state the type still represents - fix: encode the mode as an enum variant (e.g. `MutationMode::{DryRun, Apply}` plus a separate json flag) and delete the daemon-side runtime rejection - [public_wire.rs:316, public_wire.rs:311] - evidence: seed `is_\w+: bool|\w+_flag: bool` = 22 hits; the neither-set rejection is documented at public_wire.rs:310-313; wire change so needs-contract. - -## api -- d2b-contracts-control#4 sev=low blast=leaf effort=S verdict=actionable - `StatusServicesOutputV3` and its `from_v2` conversion shim are exported but have zero callers in the workspace; the doc comment says "Used so callers... can be migrated incrementally" but no migration landed - fix: delete `StatusServicesOutputV3` and `from_v2` (or wire the intended caller) - [cli_output.rs:241, cli_output.rs:276] - evidence: census `StatusServicesOutputV3|from_v2` over packages/, nixos-modules/, tests/, docs/reference/, labs = 1 hit (the definition itself); not in the generated v2 wire-protocol.json (xtask WireProtocolSchema imports only AuditOutputV2/AuthStatusOutputV2/ListOutputV2/OpInspectOutputV1/StatusOutputV2/UsbProbeOutputV1, xtask/src/main.rs:19-22). -- d2b-contracts-control#5 sev=low blast=leaf effort=S verdict=actionable - `pub use d2b_contracts::audio::LevelPercent;` in cli_output.rs re-exports a type neither this module nor any external caller uses (public_wire.rs imports LevelPercent from d2b_contracts directly) - fix: delete the re-export - [cli_output.rs:6] - evidence: census `cli_output::LevelPercent` over packages/, nixos-modules/, tests/, docs/reference/, labs = 0 hits; in-crate use is only the re-export line itself. -- d2b-contracts-control#6 sev=low blast=wide effort=S verdict=needs-contract - `AuditEntry` (public_wire.rs:2677) is exported but referenced by no wire type in the crate - `AuditResponse` uses `AuditExportEntry` from d2b_contracts - and survives only as a historical schema artifact - fix: remove the struct after confirming docs/reference/schemas/v1/wire-protocol.json:127 no longer needs the definition - [public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127] - evidence: census `AuditEntry` over packages/ = definition plus an unrelated distinct type in d2b-broker/src/audit.rs:124; the only doc pin is the v1 wire-protocol.json definition, so needs-contract. -- d2b-contracts-control#7 sev=low blast=leaf effort=S verdict=actionable - `HelperSnapshot::validate` and `HelperLaunchRequest::validate_bounds` are `pub` but every caller is an in-crate `Deserialize` impl; external consumers call `validate_unsafe_local_resource_identity` directly instead - fix: make both methods private (or `pub(crate)`) - [unsafe_local_wire.rs:105, unsafe_local_wire.rs:171] - evidence: census `\.validate_bounds\(|snapshot\.validate\(` over packages/ = in-crate calls only (unsafe_local_wire.rs:136, unsafe_local_wire.rs:206); external `validate()` hits are other crates' distinct types. - -## err -- d2b-contracts-control#8 sev=low blast=leaf effort=S verdict=actionable - `ShellNameError` is a public error type with no `Display` or `std::error::Error` impl, so callers cannot format it or chain it with `?` - fix: add `Display` + `std::error::Error` impls (additive; the type is documented as an empty struct in daemon-api.md:653) - [public_wire.rs:1297] - evidence: seed `enum \w*Error` = 92 hits; `ShellNameError` is the only error type in the crate without Display/Error; all `\.unwrap\(\)|\.expect\(` hits (92) sit in `#[cfg(test)]` mods or tests/ and `panic!` hits are test assertions, so panic policy is otherwise clean. -- clean: seeds `\.unwrap\(\)|\.expect\(` / `let _ = |\.ok\(\);` / `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` / `enum \w*Error` ran at 92 hits; every panic site is in `#[cfg(test)]` or tests/, wire error vocabularies (NamedProcessStreamErrorKind, AudioErrorKind, HelperFailureCode) are closed kebab-case enums, and the sole `let _ =` is a test line. - -## serde -- d2b-contracts-control#9 sev=medium blast=leaf effort=M verdict=actionable - three hand-written `Deserialize` impls plus private `*Wire` shadow structs (HelperSnapshot, HelperLaunchRequest, AuditResponse) re-implement exactly what `#[serde(try_from = "...")]` generates: deserialize raw, validate, map failure to a deserialization error - fix: derive `Deserialize` via `#[serde(try_from = "HelperSnapshotWire")]` (and the two siblings), keeping `deny_unknown_fields` on the wire structs and deleting the manual impls - [unsafe_local_wire.rs:118, unsafe_local_wire.rs:176, public_wire.rs:2228] - evidence: seed `impl .*Deserialize.*for` = 5 hits (the three Wire-struct pairs plus the two single-field newtypes ShellName/RealmAccentColor, whose custom error strings are fine to keep); same admission semantics, no wire change; the refusal-ledger class covers qemu guest/provider shapes only, not these sites. -- clean: seeds `derive\([^)]*(De)?[Ss]erialize` / `serde\()...)` / `impl .*Deserialize.*for` / `serde_json::from_|serde_json::to_` ran at 660 hits; rename_all/deny_unknown_fields/skip_serializing_if discipline is consistent, `#[serde(other)]` Unknown fallbacks on probe-state enums are the right forward-compat choice, and untagged enums (StatusOutputV2, ApiReadyStatusV1) are output-only. - -## obs -- N/A: seeds `\bprintln!\(|\beprintln!\(` / `(info|debug|warn|error|trace)!\("` / `\.instrument\(|#\[instrument` / `tracing::|log::` all 0 hits and the manifest (packages/d2b-contracts-control/Cargo.toml) declares no tracing/log dependency; pure DTO crate with no telemetry surface. - -## docs -- d2b-contracts-control#10 sev=medium blast=leaf effort=M verdict=actionable - cli_output.rs exports 20+ CLI-output DTOs (ListOutputV2, ListItemOutputV2, UsbProbeOutputV1, RealmListOutputV1, RealmInspectOutputV1, OpInspect*, RealmPolicyOutputV1, StatusOutputV2, StatusInventoryOutputV2, ApiReady*, StatusVmOutputV2, LivePoolIntegrityOutputV1, StatusServicesOutputV2, RunnerParityOutputV2, StatusBridgeCheckOutputV2, Audit*OutputV2, Auth*OutputV2) with no doc comments; only StatusServicesOutputV3 and two fields document anything - fix: add one-line doc comments naming the wire shape each DTO renders - [cli_output.rs:10, cli_output.rs:14, cli_output.rs:49, cli_output.rs:130, cli_output.rs:168, cli_output.rs:222] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits; zero `/// # (Examples|Errors|Panics|Safety)` sections anywhere in the crate. -- d2b-contracts-control#11 sev=medium blast=leaf effort=M verdict=actionable - public_wire.rs request/response structs and fields are undocumented where the wire semantics are non-obvious (ListRequest, StatusRequest, AuditRequest, AuditSelector, ListEntry, VmStatus, PublicVmServices, BridgeCheck, VmLifecycle, RuntimeSummary, VmAutostartPosture, QemuMedia*, ShellName, ShellNameError, WorkloadListArgs, UsbipProbeEntry field meanings), and `-> Result<` items (ShellName::new, RealmAccentColor::new) carry no `# Errors` section - fix: add doc comments with `# Errors` on the Result-returning constructors - [public_wire.rs:278, public_wire.rs:293, public_wire.rs:2451, public_wire.rs:2495, public_wire.rs:2588, public_wire.rs:2633, public_wire.rs:1279, public_wire.rs:1282] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits and seed `-> Result<` = 57 hits; no canonical doc sections exist in the crate. -- d2b-contracts-control#12 sev=medium blast=leaf effort=M verdict=actionable - unsafe_local_wire.rs exposes undocumented pub constants with unexplained magic values (MAX_HELPER_QUEUE_DEPTH=128, MAX_HELPER_SNAPSHOT_SCOPES=1024, MAX_COMPLETED_OPERATIONS_PER_UID=1024, MAX_COMPLETED_OPERATION_AGE_SECS=24*60*60, UNSAFE_LOCAL_HELPER_PROTOCOL_VERSION), undocumented pub fns (unsafe_local_helper_protocol_supported, validate_unsafe_local_resource_identity, HelperSnapshot::validate, HelperLaunchRequest::validate_bounds), and undocumented wire types (HelperHello, HelperHelloAccepted, HelperHeartbeat, HelperScopeKind, HelperScopeState, HelperScopeSnapshot, HelperSnapshot, HelperOperationResult, HelperOperationRejected, DaemonToUnsafeLocalHelper, UnsafeLocalHelperToDaemon, UnsafeLocalHelperWireSchema) - fix: document each constant with the why (queue/snapshot/age bounds the daemon enforces) and one line per wire type - [unsafe_local_wire.rs:15, unsafe_local_wire.rs:21, unsafe_local_wire.rs:24, unsafe_local_wire.rs:26, unsafe_local_wire.rs:250, unsafe_local_wire.rs:32, unsafe_local_wire.rs:308] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits; the constants are consumed by d2bd-runtime and d2b-unsafe-local-helper (census over packages/), so their bounds are cross-crate contracts. -- d2b-contracts-control#13 sev=low blast=leaf effort=S verdict=actionable - terminal_wire.rs's seven DTOs (TerminalStream, TerminalSize, TerminalWriteStdin, TerminalReadOutput, TerminalResize, TerminalWriteStdinResult, TerminalReadOutputChunk) have no item docs; only the module-level `//!` explains them - fix: add one-line docs per type (the redacted-Debug note belongs on the session-bearing types) - [terminal_wire.rs:12, terminal_wire.rs:19, terminal_wire.rs:26, terminal_wire.rs:105] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 244 hits; terminal_wire.rs is the only module whose types are entirely undocumented. - -## perf -- clean: seeds `format!\(` / `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` / `\.to_string\(\)` ran at 57 hits, every one in `#[cfg(test)]` redaction assertions or cold paths (BTreeMap::new in the from_v2 conversion shim, to_owned in the JsonSchema impl); the crate is DTO definitions with no hot loop, so all sites are `static (unmeasured)` and non-issues. - -## conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` / `\bMutex<|\bRwLock<` / `Atomic\w+|Ordering::` / `thread_local!|unsafe impl (Send|Sync) for` all 0 hits; pure data-definition crate with no threads, locks, or atomics. - -## async -- N/A: seeds `async fn|async move|\.await` / `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` / `tokio::sync::(Mutex|RwLock|Notify)` / `#\[tokio::(main|test)\]|Runtime::block_on` all 0 hits and the manifest has no tokio dependency. - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` / `// SAFETY:` / `transmute|from_raw|MaybeUninit|mem::zeroed` all 0 hits; the manifest inherits `[workspace.lints]` (`unsafe_code = "forbid"`, Cargo.toml root) and seed 4 alone does not make the lens applicable. - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` / `catch_unwind` / `repr\(C\)|repr\(transparent\)` / `CStr|CString|c_char` all 0 hits (the only textual matches are `cStr` inside the identifier `ExecStream`, a case-insensitive false positive); no FFI surface in this crate. - -## macro -- N/A: seeds `macro_rules!` / `proc_macro|syn::|quote!` / `\$crate` / `to_compile_error|new_spanned` all 0 hits; no macros defined or used beyond std derives. - -## test -- d2b-contracts-control#14 sev=medium blast=leaf effort=M verdict=actionable - the `WorkloadOp`/`WorkloadOpResponse` wire family (feature-negotiated v3 operations, dispatched by d2bd/src/composition.rs:7666) has no round-trip or shape test in this crate, unlike every sibling family (exec, console, audio, shell, named streams, audit all have wire-shape tests) - fix: add a round-trip + tag/rename pin test for WorkloadOp::List/Status/LauncherExec and WorkloadOpResponse, mirroring `audio_public_wire_json_shape_is_stable` - [public_wire.rs:167, public_wire.rs:175] - evidence: seed `#\[test\]|#\[tokio::test\]` = 35 tests and `assert_eq!\(|assert_ne!\(|assert!\(` = 134 asserts in src+tests; none reference WorkloadOp (census over the crate's tests), so the contract behavior has no test. -- clean: seeds `#\[test\]|#\[tokio::test\]` / `assert_eq!\(|assert_ne!\(|assert!\(` / `proptest!|insta::assert|rstest` / `#\[ignore\]` ran at 35 tests / 134 asserts / 0 / 0; the suite is table-driven with failure messages (shell_name_enforces_adr_shape), pins wire shapes deliberately, and asserts fail-closed behavior (unknown fields, invalid audit pages, redaction sentinels); no ignored or tautological tests found. - -## Coverage -- idiom: clean (seeds ran: 0/0/0; hand-written Debug impls are deliberate redaction) -- own: clean (seeds ran: 94 hits; all clones/to_owned explainable wire-building or test fixtures) -- type: 3 finding(s) -- api: 4 finding(s) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in manifest) -- docs: 4 finding(s) -- perf: clean (seeds ran: 57 hits; all cold/test sites) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn or tokio dependency) -- unsafe: N/A (seeds: 0/0/0 all zero for seeds 1-3; manifest inherits workspace `unsafe_code = "forbid"`) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros defined) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md deleted file mode 100644 index abb6eba91..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p1.md +++ /dev/null @@ -1,81 +0,0 @@ -# d2b-contracts-provider-p1 - d2b-contracts-provider - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 7304 (excl. src/generated/**) | modules: v3/provider.rs, v3/credential.rs, v3/credential/service.rs, v3/provider_registry.rs, v3/mod.rs, lib.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f): src/v3/provider.rs, src/v3/credential/**, src/v3/credential.rs, src/v3/provider_registry.rs, src/v3/mod.rs, src/lib.rs - -## idiom -- d2b-contracts-provider-p1#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `Default` impls on `CredentialRotationPolicy` and `CredentialRevocationPolicy` reproduce the field-wise default a derive would generate - fix: add `#[default]` to `RotationPolicyClass::OnExpiry` and `RevocationAction::Immediate` and replace both impls with `#[derive(Default)]` - [packages/d2b-contracts-provider/src/v3/credential.rs:362, packages/d2b-contracts-provider/src/v3/credential.rs:453] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 hits in lane; 2 are derive-replaceable Defaults (the Clone/PartialEq/Eq on CredentialAuthorization at service.rs:661-687 are required because of the `Arc` field and are not findings) -- d2b-contracts-provider-p1#2 sev=low blast=leaf effort=S verdict=actionable - manual `Debug` impl on `UpgradePolicy` prints exactly the three closed pub fields a derive would print, with nothing to redact - fix: replace `impl core::fmt::Debug for UpgradePolicy` with `#[derive(Debug)]` on the struct - [packages/d2b-contracts-provider/src/v3/provider.rs:2374] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 hits; the other manual Debug impls in the lane redact caller-supplied values (module rule at provider.rs:12-22, deliberate) and are not findings - -## own -- d2b-contracts-provider-p1#3 sev=low blast=leaf effort=S verdict=actionable - `ProviderManifest::validate_runtime_artifacts` takes `impl IntoIterator` by value, forcing `entries.clone()` and `self.runtime_artifacts.clone()` at both call sites that already hold the vec - fix: change the signature to `entries: &[TargetRuntimeArtifacts]` and drop both clones (census shows no external callers, so the pub signature change is contained) - [packages/d2b-contracts-provider/src/v3/provider.rs:2497, packages/d2b-contracts-provider/src/v3/provider.rs:2531, packages/d2b-contracts-provider/src/v3/provider.rs:2580] - evidence: seed `.clone()` = 26 hits in lane; census: `validate_runtime_artifacts` over packages/ + nixos-modules/ + tests/ + docs/reference/ + labs/ = 4 hits, all inside provider.rs (2497, 2531, 2580, 3224 test) -- d2b-contracts-provider-p1#4 sev=low blast=leaf effort=S verdict=actionable - `ProviderManifest::new` and `ComponentDescriptor::with_state_namespaces` clone identifiers into dedup sets that could borrow - fix: use `BTreeSet<&BoundedToken>` / `BTreeSet<&ResourceTypeName>` for `component_ids`, `owned_types`, `bound_types`, and `ids` - [packages/d2b-contracts-provider/src/v3/provider.rs:2438, packages/d2b-contracts-provider/src/v3/provider.rs:2445, packages/d2b-contracts-provider/src/v3/provider.rs:2455, packages/d2b-contracts-provider/src/v3/provider.rs:1459] - evidence: seed `.clone()` = 26 hits in lane; the remaining clones are required (owned projection return at provider.rs:1169-1182, `Arc` proof clone at service.rs:664-668, test fixtures) and are not findings - -## type -- d2b-contracts-provider-p1#5 sev=low blast=family effort=M verdict=actionable - `ComponentDescriptor::new` takes a `declares_state_volume: bool` parameter that can only be `false`: `true` is rejected at the top of the constructor, the Deserialize path passes the literal `false`, and the flag is only ever set through `with_state_namespaces` - fix: remove the parameter from `ComponentDescriptor::new` and update the ~20 call sites (census below), keeping the wire-only `declaresStateVolume` field and its consistency check inside the Deserialize Wire struct - [packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/src/v3/provider.rs:1368, packages/d2b-contracts-provider/src/v3/provider.rs:1720, packages/d2b-contracts-provider/src/v3/provider.rs:3455] - evidence: seed `fn validate_\w+|fn check_\w+` = 8 hits; census: `ComponentDescriptor::new` over packages/ + tests/ = ~20 hits across 7 crates (d2b-bus, d2b-core-controller, d2b-provider-provider, d2b-provider-toolkit, d2bd-runtime, d2bd, d2b-resource-compiler), all passing `false` or relying on the default path -- d2b-contracts-provider-p1#6 sev=low blast=leaf effort=M verdict=actionable - `ComponentDescriptor` stores `execution` and `execution_wire` as parallel fields where the wire shape is derived from the enum, so one fact has two representations that only `with_execution` keeps in sync - fix: implement `Serialize` for `ComponentExecution` emitting the flat `binaryRef` key (absent for `InProcessBootstrap`), drop the `execution_wire` field and the private `ComponentExecutionWire` struct - [packages/d2b-contracts-provider/src/v3/provider.rs:1333, packages/d2b-contracts-provider/src/v3/provider.rs:1335, packages/d2b-contracts-provider/src/v3/provider.rs:1418] - evidence: seed `fn validate_\w+|fn check_\w+` = 8 hits; the redundant pair is visible in the struct literal at provider.rs:1418-1419 and the From bridge at provider.rs:1300-1307 - -## api -- d2b-contracts-provider-p1#7 sev=low blast=family effort=S verdict=actionable - `SchemaVersion` in d2b-contracts-resource exposes no `major()`/`minor()` accessors, so `CompatibilityRange::admits_state` re-parses the canonical string in `schema_version_parts` with three `expect`s and an allocation per call - fix: add `pub const fn major(self) -> u32` and `minor(self) -> u32` to `SchemaVersion` (non-breaking) and delete `schema_version_parts` - [packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/src/v3/resource_schema.rs:592] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~120 hits; the expects are invariant-justified (U1 (c) err false-positive class), so the finding is the missing accessor, not the panics - -## err -- d2b-contracts-provider-p1#8 sev=medium blast=leaf effort=S verdict=actionable - `ProviderRegistryPublication::new` maps `generation == 0` to `MappingBoundExceeded` even though the `ZeroGeneration` variant exists and is used by the entry constructor, so a caller distinguishing invalid generation from bound overflow receives the wrong code - fix: split the check into `if generation.get() == 0 { return Err(ZeroGeneration) }` before the mapping-count bound - [packages/d2b-contracts-provider/src/v3/provider_registry.rs:186, packages/d2b-contracts-provider/src/v3/provider_registry.rs:92] - evidence: seed `enum \w*Error` = 2 hits in lane; the variant pair is visible at provider_registry.rs:40 (ZeroGeneration) and provider_registry.rs:48 (MappingBoundExceeded); no external matchers exist (census below in #9) -- d2b-contracts-provider-p1#9 sev=low blast=leaf effort=S verdict=actionable - an entry-generation mismatch in `ProviderRegistryPublication::new` reports `AxisMismatch`, whose Display code is `provider-registry-axis-mismatch`, although no binding axis is involved - fix: add a `GenerationMismatch` variant with its own kebab code and return it for the `entry.provider_generation != generation` check - [packages/d2b-contracts-provider/src/v3/provider_registry.rs:189, packages/d2b-contracts-provider/src/v3/provider_registry.rs:193] - evidence: seed `enum \w*Error` = 2 hits; census: `ProviderRegistryError` over packages/ + nixos-modules/ + tests/ + docs/reference/ + labs/ = 12 hits, all inside provider_registry.rs, so adding a variant breaks no external exhaustive match - -## serde -- clean: seeds ran: derive Serialize/Deserialize ~41 hits, serde attrs ~30 hits, hand-written `impl Deserialize` 18 hits, serde_json 0 production hits; the hand-written Deserialize impls are live admission gates (recorded refusal class per U1 (d)6, not re-flagged), `rename_all` conventions are consistent, and every Wire admission shape carries `deny_unknown_fields`; the PascalCase wire spellings of `CredentialLeaseState`, `CredentialConditionType`, and `CredentialInteractionState` are pinned by the golden vector at credential.rs:1106 and are deliberate - -## obs -- clean: seeds ran: println!/eprintln! 0, event-macro pattern 17 hits (all `redacted_debug!` macro-name false positives), `.instrument`/`#[instrument]` 0, tracing::/log:: 0; the crate emits no telemetry and every Debug/Display surface redacts caller-supplied values (module rule provider.rs:12-22), which the ADR 0010/0028 redaction gate covers - -## docs -- d2b-contracts-provider-p1#10 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors` sections exist on any Result-returning pub item in the lane even though failure conditions are the load-bearing part of these admission constructors - fix: add `# Errors` sections naming the closed variants (e.g. `ProviderContractError::InvalidPrimitive` for `BinaryRef::parse`, `ProviderContractError::TrustNotEstablished` for `TrustEvidence::admit`) to the pub constructors and admission methods - [packages/d2b-contracts-provider/src/v3/provider.rs:250, packages/d2b-contracts-provider/src/v3/provider.rs:481, packages/d2b-contracts-provider/src/v3/credential.rs:120, packages/d2b-contracts-provider/src/v3/credential/service.rs:1002] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits vs seed `-> Result<` = ~80 hits in lane; every pub item is otherwise documented (first sentences are contract-shaped), so this is a section-shape gap, not missing docs - -## perf -- clean: seeds ran: format! 13 hits (11 in tests, 2 cold: opaque_digest credential.rs:80 and the test-adjacent fingerprint helper), Vec::new 5 hits (encode_outer service.rs:1003 and write_message service.rs:1386 are cold per-operation paths; constructor empties are the common case), to_string 5 hits (all tests); no hot loop allocates, and all findings here would be static (unmeasured) per the perf gate - -## conc -- d2b-contracts-provider-p1#11 sev=low blast=leaf effort=S verdict=actionable - `SensitiveDeliveryRecord` uses `Ordering::SeqCst` for per-byte loads and stores that have no release/acquire pairing with any other atomic, so the strongest ordering buys nothing - fix: use `Ordering::Relaxed` in `copy_to`, `clear`, and `is_zeroized` - [packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-provider/src/v3/credential/service.rs:963, packages/d2b-contracts-provider/src/v3/credential/service.rs:977] - evidence: seed `Atomic\w+|Ordering::` = 7 hits in lane, all on this one record type (import at service.rs:6 plus 6 uses); the `Arc` proof in `CredentialAuthorization` is genuine shared ownership (U1 (c) api false-positive class) and is not a finding - -## async -- clean: seeds ran: async fn/async move/.await 3 hits (dispatch_async service.rs:867, dispatch_authorized_provider_async service.rs:896, .await service.rs:904), tokio::spawn/spawn_blocking/JoinSet/select!/join! 0, tokio::sync 0, #[tokio::main/test] 0; the `#[async_trait]` trait has one required sync method plus a default async wrapper that does no blocking work, holds no locks across `.await`, and is runtime-agnostic - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0, `// SAFETY:` 0, `transmute|from_raw|MaybeUninit|mem::zeroed` 0, `unsafe_code` 0 in lane; workspace lints forbid unsafe (U1 (d)1) and the crate is not on the (d)8 exception list - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` 0, `catch_unwind` 0, `repr\(C\)|repr\(transparent\)` 0, `CStr|CString|c_char` 0; the crate crosses no foreign boundary - -## macro -- clean: seeds ran: macro_rules! 1 hit (opaque_credential_value! credential.rs:111), proc_macro/syn/quote 0, $crate 0, to_compile_error/new_spanned 0; the single macro is a genuine impl-per-type generator with narrow fragment specifiers ($name:ident, $max:expr, $domain:literal, $doc:literal) and is module-local, so no `$crate` path is needed; no proc-macro and no trybuild suite are warranted at this size - -## test -- d2b-contracts-provider-p1#12 sev=medium blast=leaf effort=M verdict=actionable - `credential/service.rs` (1461 lines) contains zero tests: the strict protobuf codec (the five `CredentialWire` impls at service.rs:1071-1350, `WireReader` at service.rs:1393-1452, `set_once` duplicate-field rejection at service.rs:1296, and the `encode_outer`/`decode_outer` ceilings at service.rs:1002-1028) is entirely unverified, so a malformed-input, truncation, or non-canonical-varint regression passes the suite silently - fix: add round-trip tests per DTO plus malformed/truncated/duplicate-field/non-canonical-varint/oversize tests for `WireReader` and `encode_outer`/`decode_outer` - [packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-provider/src/v3/credential/service.rs:1393, packages/d2b-contracts-provider/src/v3/credential/service.rs:1296] - evidence: seed `#\[test\]|#\[tokio::test\]` = 54 hits in lane, 0 of them in service.rs (43 in provider.rs, 9 in credential.rs, 2 in provider_registry.rs); the sibling files' tests are behavior-focused (schema vectors, fail-closed checks, redaction canaries) and no `#[ignore]` or tautological tests were found - -## Coverage -- idiom: 2 finding(s) -- own: 2 finding(s) -- type: 2 finding(s) -- api: 1 finding(s) -- err: 2 finding(s) -- serde: clean (seeds ran: 41/30/18/0; hand-written Deserialize = recorded admission-gate class, U1 (d)6) -- obs: clean (seeds ran: 0/17/0/0; the 17 event-macro hits are `redacted_debug!` name matches) -- docs: 1 finding(s) -- perf: clean (seeds ran: 13/5/5; all hits cold or test-only) -- conc: 1 finding(s) -- async: clean (seeds ran: 3/0/0/0) -- unsafe: N/A (seeds: 0/0/0/0 all zero; unsafe_code forbid per workspace lints, U1 (d)1) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: clean (seeds ran: 1/0/0/0) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md deleted file mode 100644 index d8f3c8ef3..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-provider-p2.md +++ /dev/null @@ -1,85 +0,0 @@ -# d2b-contracts-provider-p2 - d2b-contracts-provider - part 2/2 -Baseline: 6ebdd4cec | LOC audited: 7395 (excl. src/generated/**) | modules: v3/semantic_services (mod, audio, child_resources, security_key, telemetry, usb), v3/credential_controller, v3/telemetry_policy, v3/telemetry_frame -Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: src/v3/semantic_services/**, src/v3/credential_controller.rs, src/v3/telemetry_policy.rs, src/v3/telemetry_frame.rs - -## idiom -- d2b-contracts-provider-p2#1 sev=low blast=leaf effort=S verdict=actionable - the two `children.push(BindingChildIntent {...})` arms in `explicit_binding_children_with_user` are identical 15-field literals differing only in `producer_ref: None` versus `Some(producer_ref)`, forced apart by a `let ... else { ...; continue; }` - fix: bind `let producer_ref: Option = producer_ref.transpose()?;` before the push and emit one literal with `producer_ref,`, deleting the else-continue arm - [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:573, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:595] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (test-support, mod.rs:1276); the duplication is a read finding at child_resources.rs:574-616; seeds 1 and 2 = 1 and 0 hits -- clean: seeds ran: 1/0/1 - no index loops outside one test fixture (telemetry_frame.rs:555), no hand-written Default/From/PartialEq/Debug/Clone/Hash impls matched (the redacting `Debug` impls are `impl core::fmt::Debug` and are the deliberate redaction pattern), one statement-style accumulation in cfg(test) support code - -## own -- d2b-contracts-provider-p2#2 sev=low blast=leaf effort=S verdict=actionable - duplicate-detection set in `validate_descriptor` clones every label key (`seen.insert(label.key.clone())`) where a borrowed `BTreeSet<&str>` suffices - fix: declare `let mut seen: BTreeSet<&str> = BTreeSet::new();` and insert `&label.key` - [packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:497, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:500] - evidence: seed `\.clone\(\)` = 30 hits, of which this is one of two non-test, non-construction clones; the other clones are multi-owner construction copies (frame field values, child intents, single-flight set insert) that pass the one-sentence test -- d2b-contracts-provider-p2#3 sev=low blast=leaf effort=S verdict=actionable - `allowed_telemetry_value` allocates a fresh String just to test zone validity (`validate_zone(value.to_owned()).is_ok()`) although `validate_zone` only reads the value - fix: give the zone grammar a `&str`-based check (for example `fn is_valid_zone(value: &str) -> bool` used here, keeping the owning `validate_zone` for the three construction call sites that need the validated String back) - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1591, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1549] - evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 25 hits; this is the only hit where the owned value is immediately discarded (`.is_ok()`), the rest are genuine owned returns or test fixtures -- clean: seeds ran: 30/25/0/0 - no Rc/RefCell/Arc/Arc and no Cow in the partition; every remaining clone is a multi-owner copy (child intents share binding/provider refs, telemetry frame fields appear in three label sets, single-flight set insert) or a `to_canonical_string` owned return - -## type -- d2b-contracts-provider-p2#4 sev=medium blast=family effort=M verdict=actionable - `BindingChildRequest::process` and `process_for_user` accept `kind: BindingChildKind` including `Endpoint`, so an Endpoint carrying process fields is constructible and must be rejected at runtime (`InvalidProducer`, child_resources.rs:502-510), and the sibling check `producer_role.is_some() && kind != Endpoint` (child_resources.rs:499) is unreachable because only `endpoint()` sets `producer_role` and it hardcodes `Endpoint` - fix: take a restricted `ProcessChildKind { Process, EphemeralProcess }` in the two process constructors (all seven in-tree call sites pass `BindingChildKind::Process`), then delete both runtime checks - [packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:499, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:502] - evidence: seed `fn validate_\w+|fn check_\w+` = 20 hits, all boundary validators on wire input or constructor invariants; census: `BindingChildRequest::process` over packages/nixos-modules/tests/docs/reference/labs = 7 hits in 4 crates (audio-pipewire, device-security-key, device-usbip, observability-otel), all passing `BindingChildKind::Process`; the illegal Endpoint-with-process-fields combination is exercised only by the runtime check, not by any caller -- clean: seeds ran: 20/0/0 - no boolean flag soup (`is_\w+: bool` = 0), no stringly-typed state (`(mode|kind|state): String` = 0); the remaining `validate_*` functions are parse-once admission checks on wire input, which is the skill's sanctioned boundary placement - -## api -- clean: seeds ran: 231/0/1 - the exported surface is the deliberate wide contract vocabulary of a contract crate (U1 (c) api false positive applies), no Arc/Rc/Box/RefCell appears in any public signature, and the single `pub use` arm (telemetry_policy.rs:9) re-exports generated catalog constants as the house single-surface pattern; `SemanticPairDeclaration`, `NonEmpty`, and `SemanticBackingDeclaration` are correctly `pub(crate)` - -## err -- d2b-contracts-provider-p2#5 sev=low blast=leaf effort=S verdict=actionable - `CredentialControllerError::AlreadyRunning` renders the wire label "credential-queue-pressure", which names a different concept (the lease-ceiling outcome `CredentialControllerOutcome::QueuePressure`) than the variant's documented meaning ("the same Credential is already being handled") - fix: emit "credential-already-running" from the Display arm, or rename the variant to match the code - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:90] - evidence: seed `enum \w*Error` = 6 error enums read; census: `credential-queue-pressure` over packages/nixos-modules/tests/docs/reference/labs = 1 hit (the definition itself), so the label is not pinned by docs/reference/error-codes.md or any consumer -- d2b-contracts-provider-p2#6 sev=low blast=leaf effort=S verdict=actionable - `CredentialObservabilityError` Display strings are prose sentences ("credential audit record is invalid", "credential telemetry frame is invalid"), breaking the kebab-code diagnostic convention every sibling error type in this crate follows (`CredentialControllerError`, `MetricPolicyError`, `TelemetryFrameError`, `SemanticContractError`, `BindingChildError`) - fix: render "credential-audit-record-invalid" and "credential-telemetry-frame-invalid" - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:1508, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1509] - evidence: seed `enum \w*Error` = 6 enums; census: both prose strings over packages/nixos-modules/tests/docs/reference/labs = 1 hit each (the definitions), no consumer or doc pins them -- d2b-contracts-provider-p2#7 sev=low blast=leaf effort=S verdict=actionable - `CredentialSingleFlight` maps a poisoned mutex to `InvalidInput` (a caller-input error) and its guard `Drop` silently skips the removal on poison, which would leave a stale UID and a permanent `AlreadyRunning`; the skill names recovery via `into_inner()` for exactly this shape - fix: recover with `self.running.lock().unwrap_or_else(|poisoned| poisoned.into_inner())` in both `lock()` and `Drop`, keeping the documented synchronous-path boundary - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:834, packages/d2b-contracts-provider/src/v3/credential_controller.rs:846] - evidence: seed `\.unwrap\(\)|\.expect\(` = 40 hits, all in tests or on literally-built values (write! to String, canonical constants) per the U1 false-positive list; the poison mapping is a read finding at the two lock sites, both carrying the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` -- clean: seeds ran: 40/1/1/6 - no panic!/unreachable!/todo!/unimplemented! outside one test helper (telemetry_policy.rs:990), the single `let _ =` hit is a compile_fail doctest, and every unwrap/expect outside tests is the U1 false-positive class (write! to String, literally-built catalog constants); error taxonomy is otherwise split by caller action with closed discriminants - -## serde -- d2b-contracts-provider-p2#8 sev=low blast=leaf effort=S verdict=actionable - `parse_raw_frame` maps every serde failure to `Malformed`, so a top-level unknown field (rejected by `deny_unknown_fields` on `TelemetryFrame`) reports `Malformed` while the same unknown key nested inside `value` reports `UnknownField` from validation - the variant exists but is unreachable for the shape that names it - fix: `map_err(|error| match error.classify() { serde_json::error::Category::UnknownField => TelemetryFrameError::UnknownField, _ => TelemetryFrameError::Malformed })` (serde_json 1.0.151 in Cargo.lock provides `classify`) - [packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:76, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:114] - evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 2 hits, seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 3 hits, seed `serde_json::from_|serde_json::to_` = 4 hits; the UnknownField-vs-Malformed asymmetry is a read finding across parse (line 76) and validate (lines 114-121) -- clean: `rename_all = "lowercase"` on `TelemetrySignal` and per-type `deny_unknown_fields` on `TelemetryFrame` follow the card's naming and decision guidance; the hand-written `Deserialize` for `SemanticProjectionProtocolVersion` is a live admission gate (grammar parse), the sanctioned pattern; no `flatten`, no `try_from`, no untagged - -## obs -- clean: seeds ran: 0/0/0/0 - no println/eprintln, no interpolated log macros, no tracing or log usage anywhere in the partition; the telemetry frame and policy modules are the redaction and closed-domain policy data themselves, and `CredentialTelemetryFrame` builds structured field lists rather than log lines, so there is nothing to instrument - -## docs -- d2b-contracts-provider-p2#9 sev=medium blast=family effort=M verdict=actionable - none of the 59 Result-returning items in the partition carries an `# Errors` section, so callers cannot learn from the docs which closed-discriminant error each condition produces (for example when `CredentialControllerCall::authorize` yields `DeadlineExceeded` versus `OperationDenied`, or which `validate_*` failure maps to which `MetricPolicyError` variant) - fix: add `# Errors` sections naming the variant per condition to the public Result APIs, starting with the constructor and validate families - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:478, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:72, packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs:93] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits against seed `-> Result<` = 59 hits; every public item carries a one-line doc (no undocumented pub items found), so this is the missing canonical-section class, not missing docs -- clean: every pub item in the partition has a doc comment with a load-bearing first sentence; module docs (`//!`) exist on all six modules; the redacting Debug/Display impls are documented policy - -## perf -- clean: seeds ran: 11/6/25 - every `format!` site is a cold path (child-name construction, audit wire record rendering, error labels, test fixtures), every `Vec::new()` is an empty-case-common or cfg(test) site, and the `to_string`/`to_owned` sites are owned returns or the two `own` findings above; no hot loop, no attacker-keyed hashing, no grow-by-push in a measured path; static (unmeasured) - -## conc -- clean: seeds ran: 0/1/0/0 - the only synchronization is `CredentialSingleFlight`'s `Mutex>`, a documented synchronous-path boundary with the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` per U1 (d) 4, held only across single insert/remove operations; no threads, no atomics, no thread_local, no unsafe Send/Sync claims - -## async -- N/A (seeds: 0/0/0/0 all zero; no `async fn`, no `.await`, no tokio usage anywhere in the partition - the controller contract is synchronous by design, documented at credential_controller.rs:800-806) - -## unsafe -- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, fns, impls, or SAFETY comments in the partition, and the crate inherits `unsafe_code = "forbid"` through `[lints] workspace = true`) - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no extern "C", no no_mangle, no repr(C)/repr(transparent), no CStr/CString in the partition) - -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro or syn/quote usage, no $crate, no to_compile_error in the partition) - -## test -- d2b-contracts-provider-p2#10 sev=medium blast=leaf effort=M verdict=actionable - several public contract behaviors have no test: `observe_credential` (both the degraded and the InspectMetadata branches), the rotation-retry-exhausted branch of `reconcile_credential` (`CredentialRetryState::exhausted` feeding `RotationFailed`/`Failed`), `CredentialLeaseAggregate::from_active_expiries`, `CredentialControllerHealth::derive`, and `CredentialAuditRecord::controller_event` - fix: add table-driven unit tests asserting the outcome/disposition variant per input row, mirroring the existing `rotation_policy_matrix_is_closed` shape - [packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1346, packages/d2b-contracts-provider/src/v3/credential_controller.rs:499, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1084] - evidence: seed `#\[test\]|#\[tokio::test\]` = 40 tests read across the partition; the named functions appear zero times inside `#[cfg(test)]` bodies (census over the crate's tests: `observe_credential` 0 test hits, `from_active_expiries` 0, `CredentialControllerHealth::derive` 0, `controller_event` 0, `CredentialRetryState` 0), while `reconcile_credential` and `revoke_credential` are exercised -- clean: seeds ran: 40/150/0/0 - no proptest/insta/rstest, no `#[ignore]`; the existing tests are behavior-asserting with negative controls (fingerprint re-derivation, provider-neutrality probes, redaction idempotence) and table-driven cases with messages; no test found that cannot fail - -## Coverage -- idiom: 1 finding -- own: 2 findings -- type: 1 finding -- api: clean (seeds ran: 231/0/1; deliberate contract vocabulary, no internals in signatures, one house-pattern pub use) -- err: 3 findings -- serde: 1 finding -- obs: clean (seeds ran: 0/0/0/0; no logging surface in the partition) -- docs: 1 finding -- perf: clean (seeds ran: 11/6/25; all sites cold or test) -- conc: clean (seeds ran: 0/1/0/0; one documented synchronous-path Mutex with sanctioned allow) -- async: N/A (seeds: 0/0/0/0 all zero; synchronous contract by design) -- unsafe: N/A (seeds: 0/0/0/0 all zero; unsafe_code forbid inherited) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md deleted file mode 100644 index 0dd01cf98..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p1.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-contracts-resource-p1 - d2b-contracts-resource - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9718 (excl. src/generated/**) | modules: v3/network.rs, v3/resource_schema.rs, v3/operations/** (mod.rs, error.rs, seal.rs), v3/device.rs, v3/resource_status.rs, v3/volume_state.rs, v3/payload_schema.rs, v3/error.rs, v3/host.rs, v3/bridge.rs, v3/limits.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f); part 2 owns v3/volume.rs, v3/process.rs, v3/identity.rs, v3/execution_policy.rs, v3/resource.rs, v3/storage.rs, v3/volume_binding.rs, v3/activation_nixos.rs, v3/user.rs, v3/mod.rs, v3/artifact.rs, src/lib.rs - -## idiom -- d2b-contracts-resource-p1#1 sev=low blast=leaf effort=S verdict=actionable - `ExternalIpv4Spec::default` (network.rs:597-605) hand-writes exactly the field-wise default (method: Ipv4Method::Dhcp, address: None, gateway: None, dns: Vec::new()) that a derive would produce - fix: add `#[default]` to `Ipv4Method::Dhcp` (network.rs:533) and `#[derive(Default)]` to `ExternalIpv4Spec`, delete the hand-written impl - [packages/d2b-contracts-resource/src/v3/network.rs:597, packages/d2b-contracts-resource/src/v3/network.rs:533] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 6 hits; the other five Default impls (RoutingSpec, DhcpSpec, DnsSpec, MdnsSpec, EgressSpec) preserve non-derivable defaults (mandatory host blocklist, ignoreClientNames=true, cacheSize=1000, reflector=true, masquerade=true) and are deliberate, so this is the only derive-equivalent one -- clean: seeds 1-3 = 1/6/1 hits; the index loop (payload_schema.rs:383) is a bounded depth test, the `let mut values = Vec::new()` (resource_schema.rs:298) is a serde visitor collect, and no naming or conversion drift was found across the part - -## own -- d2b-contracts-resource-p1#2 sev=low blast=leaf effort=S verdict=actionable - `StateDigest::parse` clones its String before delegating to `SchemaFingerprint::parse` (volume_state.rs:138), but that function takes `impl Into`, so `value.as_str()` avoids the copy - fix: `SchemaFingerprint::parse(value.as_str())` - [packages/d2b-contracts-resource/src/v3/volume_state.rs:138] - evidence: seed `\.clone\(\)` = 92 hits; real-code clones reviewed: resource_schema.rs:729/1010/1094/1212/1231 own error-payload strings (required), resource_status.rs:693 `base_projection` needs an owned copy, seal.rs:157-169 `Arc::clone` at the capability boundary (required); the remainder are test fixtures -- clean: seeds 2-4 = 54/0/0 hits; `to_owned`/`to_string` hits are schemars `schema_name()` returns, wire-rendering boundaries, and test sentinels; no Rc/RefCell/Arc/Cow anywhere in the part - -## type -- d2b-contracts-resource-p1#3 sev=low blast=leaf effort=S verdict=actionable - `StoreSealIdentity::with_store_epoch` (seal.rs:57-61) documents "Bind the seal identity to a nonzero store epoch" but accepts 0 without a check, and the fn has no callers, so the promised invariant is unenforced and untested - fix: reject 0 (return `Result` or `debug_assert!` plus a documented contract) or drop the nonzero claim from the doc - [packages/d2b-contracts-resource/src/v3/operations/seal.rs:57, packages/d2b-contracts-resource/src/v3/operations/seal.rs:58] - evidence: census `with_store_epoch` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (the definition itself); seed 1 `fn validate_\w+|fn check_\w+` = 15 hits (all in tests and validators of sibling types) -- d2b-contracts-resource-p1#4 sev=medium blast=family effort=M verdict=actionable - store-contract digests are bare `String` (`StoredResource.payload_digest` mod.rs:71, `StoredSchema.payload_digest` mod.rs:239, `PreparedStoreMutation.payload_digest` mod.rs:374) while every other identity in this crate is a parsed newtype (SchemaFingerprint, StateDigest), so a non-digest string can flow through the store boundary without a type-level guarantee - fix: type the three fields as `SchemaFingerprint` (or `StateDigest`) and parse at the backend boundary where the digest is computed - [packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resource/src/v3/operations/mod.rs:239, packages/d2b-contracts-resource/src/v3/operations/mod.rs:374] - evidence: static read of the three pub fields; consumers that construct or match them: d2b-resource-api/src/store.rs, d2b-resource-api/src/manager_backend.rs, d2b-bus/src/session_seam_tests.rs; seed 3 `(mode|kind|state): String` = 0 hits, so this is the only stringly-typed identity in the part -- clean: seeds 2 = 0 hits (no boolean flag soup); the Option pairs checked (ResourceError optional fields, ResourceStatus timestamps) are genuinely independent - -## api -- d2b-contracts-resource-p1#5 sev=low blast=leaf effort=S verdict=actionable - six `pub type` aliases are exported with zero consumers anywhere: `AttachmentSpec` (network.rs:956), `AuthorityDescriptor` (device.rs:129), `OpaqueAuthorityKey` (device.rs:151), `DeviceStatus` (device.rs:760), `DeviceRbacVerb` (device.rs:918), `DeviceTelemetryLabels` (device.rs:1119) - fix: delete the unused aliases (or make them `pub(crate)` if a provider adapter is planned) - [packages/d2b-contracts-resource/src/v3/network.rs:956, packages/d2b-contracts-resource/src/v3/device.rs:129, packages/d2b-contracts-resource/src/v3/device.rs:151, packages/d2b-contracts-resource/src/v3/device.rs:760, packages/d2b-contracts-resource/src/v3/device.rs:918, packages/d2b-contracts-resource/src/v3/device.rs:1119] - evidence: census `AttachmentSpec|AuthorityDescriptor|OpaqueAuthorityKey|DeviceStatus|DeviceRbacVerb|DeviceTelemetryLabels` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 6 hits, all the definitions themselves -- clean: seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 hits (the Arc fields in seal.rs are private); seed 3 `pub use` arms in operations/mod.rs are the house single-surface pattern; the wide wire export is the contract-crate norm (U1 (c) api false positive) - -## err -- d2b-contracts-resource-p1#6 sev=medium blast=family effort=M verdict=actionable - `StoreErrorKind` (operations/error.rs:93-129) duplicates all 31 `ResourceErrorKind` variants and their `as_str` spellings verbatim, and d2b-resource-api/src/error.rs:11-56 `map_store_error_kind` re-lists all 31 a third time, so adding one resource-plane kind requires three synchronized edits and no test pins the overlap (each set only pins its own size) - fix: restructure `StoreErrorKind` as `Resource(ResourceErrorKind)` plus the three store-only variants (StoreIntegrityFailure, StoreBackpressure, StoreQuarantined), which collapses the map to one arm plus store arms while keeping `as_str` outputs identical - [packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-resource/src/v3/operations/error.rs:132, packages/d2b-resource-api/src/error.rs:11] - evidence: seed 4 `enum \w*Error` = 10 hits; census `StoreErrorKind` over packages/ = matches in d2b-resource-api (error.rs map, manager_backend.rs, service.rs), d2bd-runtime/src/guest_resource_runtime.rs, d2b-bus/src/session_seam_tests.rs; StoreError carries no serde derives, so the reshape is internal -- clean: seeds 1-3 = 271/9/0 hits; the 14 real-code expect sites are invariant-justified (validated CIDR internals network.rs:151-155, literal defaults network.rs:260/286/289, canonical-JSON serialization of validated values resource_schema.rs:189/396/562, static reason strings error.rs:230-232, fixed constructors device.rs:519 and host.rs:74); the 4 real `let _ =` sites are the compile-time capability assertions in seal.rs:218-224; no panic!/unreachable!/todo!/unimplemented! anywhere - -## serde -- d2b-contracts-resource-p1#7 sev=medium blast=wide effort=S verdict=actionable - `ResourceError` derives Deserialize (error.rs:175-176), bypassing the invariants `ResourceError::new` enforces (current_revision only on ResourceConflict/AuthorizationDenied/RevisionExpired, retry_after_ms only with RetryClass::AfterDelay), so a wire error carrying an inconsistent combination deserializes into an illegal state that the retry decision logic then reads - fix: hand-write `Deserialize` for `ResourceError` through `Self::new`, matching every sibling wire type in this crate - [packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v3/error.rs:177] - evidence: seed 1 `derive\([^)]*(De)?[Ss]erialize` = 85 hits; static read of error.rs:175-259; the retry fields are consumed by d2b-resource-client/src/dispatch.rs:270-273 (record_remote_error matches retry_class then retry_after_ms); census: no production JSON decode site for ResourceError exists today (the wire envelope is built by hand in d2bd-runtime/src/resource_runtime_support.rs:1627), so the bypass is latent on a public wire type -- d2b-contracts-resource-p1#8 sev=medium blast=family effort=S verdict=actionable - `PayloadSchema` derives Deserialize (payload_schema.rs:30-32), bypassing `PayloadSchema::parse`'s closed-object and writeOnly validation, and `CommandSpec::deserialize` (d2b-provider-command/src/command.rs:248-266) feeds the wire value straight in, so a wire Command carrying an open schema or a writeOnly property with a default deserializes as valid - fix: hand-write `Deserialize` for `PayloadSchema` through `Self::parse` (the wire shape is unchanged; producers already use parse) - [packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resource/src/v3/payload_schema.rs:36] - evidence: seed 1 = 85 hits; census `PayloadSchema` over packages/ = consumers d2b-provider-command/src/command.rs:185, d2b-provider-operation/src/operation.rs:458, d2bd/src/foundation_seed.rs:859-860 (which re-parses via parse, showing validation is expected); both spec types are wire shapes pinned in docs/reference/schemas/v3/ -- clean: seeds 2-4 = 163/0/33 hits; the hand-written Deserialize impls (space-anchored seed misses the `impl<'de>` form; ~30 judged manually) are all Wire-struct admission gates calling the validated constructors, which is the recorded house pattern; optionality distinctions (skip_serializing_if vs RequiredNullable) are deliberate and golden-pinned - -## obs -- N/A: seeds 1-4 = 0/0/0/0 hits (println, interpolated event macros, instrument, tracing/log all zero); Cargo.toml carries no tracing or log dependency, so the crate emits no telemetry - -## docs -- d2b-contracts-resource-p1#9 sev=low blast=leaf effort=S verdict=actionable - limits.rs exports 30 `pub const` admission limits (lines 3-33) with no per-item docs and no rationale for the specific values (500, 100, 900000, 30000, 256 KiB, 4 MiB), so a reader cannot tell which bound is load-bearing - fix: add one-line doc comments naming the enforcing boundary (request admission, watch credits, deadline) or a module-level rationale paragraph - [packages/d2b-contracts-resource/src/v3/limits.rs:3, packages/d2b-contracts-resource/src/v3/limits.rs:22] - evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 523 hits; limits.rs has 30/30 pub consts undocumented apart from the one-line module doc -- d2b-contracts-resource-p1#10 sev=low blast=leaf effort=S verdict=actionable - the operations module exports pub accessors with no doc comments: `MutationOrdinal::get` (error.rs:21), `StoreSlot::get` (error.rs:50), the eight `StoreError` accessors (error.rs:262-291), `StoreSealIdentity::new/zone/slot` (seal.rs:48/63/67), `OpenedMutation::body/into_body` (seal.rs:121/125), `MutationSealAcceptor::diagnose/declared_slot` (seal.rs:177/181), and `PreparedStoreMutation::new/mutation/resource_uid/payload_digest` (mod.rs:378-400) - fix: add one-line doc comments, especially for the mutating builder `with_store_slot` and the consume-then-open capability methods - [packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-resource/src/v3/operations/error.rs:262, packages/d2b-contracts-resource/src/v3/operations/seal.rs:48, packages/d2b-contracts-resource/src/v3/operations/seal.rs:121, packages/d2b-contracts-resource/src/v3/operations/mod.rs:378] - evidence: seed 1 = 523 hits; these items carry no `///` at all while the surrounding contract types are otherwise documented to a high standard -- clean: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits, but every Result-returning item documents its failure conditions in prose (the house style); seed 3 `-> Result<` = 127 hits; doc first sentences are strong and redaction behavior is documented on every redacted type - -## perf -- d2b-contracts-resource-p1#11 sev=low blast=leaf effort=M verdict=actionable - `ResourceStatus::new` (resource_status.rs:636-658) serializes the complete status with `canonical_json_bytes(&value)` on every construction to enforce MAX_STATUS_BYTES, after `ensure_layer_size` already serialized the resource layer, so each status write pays two full serializations of the same object - fix: enforce the byte bound once at the write boundary (the caller already serializes for storage) or check the bound with a cheaper size pass; at minimum reuse the layer bytes from `ensure_layer_size` - [packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-resource/src/v3/resource_status.rs:650] - evidence: static (unmeasured); seed 1 `format!\(` = 75 hits (mostly tests and cold error paths), seed 2 collection-new = 35 hits (empty-case defaults), seed 3 `.to_string()` = 5 hits (all tests) -- clean: no format! or allocation in a loop in the part; digest rendering (resource_schema.rs:586-598) pre-sizes its String with with_capacity - -## conc -- N/A: seeds 1-4 = 0/0/0/0 hits (no threads, Mutex/RwLock, atomics, or thread_local in the part) - -## async -- N/A: seeds 1-4 = 0/0/0/0 hits (no async fn, spawn, tokio sync, or tokio attribute in the part) - -## unsafe -- N/A: seeds 1-4 = 0/0/0/0 hits (no unsafe block, fn, impl, transmute, or raw-pointer construct in the part; `unsafe_code = "forbid"` via the workspace lints table) - -## ffi -- N/A: seeds 1-4 = 0/0/0/0 hits (no extern "C", no_mangle, repr(C), or CStr/CString in the part) - -## macro -- N/A: seeds 1-4 = 0/0/0/0 hits (no macro_rules! definitions in the part; the `redacted_debug!`/`parsed_deserialize!`/`string_schema!` invocations here are defined in v3/execution_policy.rs, part 2's scope) - -## test -- clean: seeds 1-4 = 70/232/0/0 hits (test mass, assertion mass, no property/snapshot tooling, no ignored tests); the suite is golden-vector pinned (literal wire bytes in network.rs:1682, resource_schema.rs:1576-1587, volume_state.rs:590-591, host.rs:150-161), redaction-verified with process-id markers, table-driven with per-case failure messages, and the seal capability negative is enforced at compile time (seal.rs:214-225); tests/schema.rs exercises the public surface as a consumer would; no test that cannot fail was found - -## Coverage -- idiom: 1 finding -- own: 1 finding -- type: 2 findings -- api: 1 finding -- err: 1 finding -- serde: 2 findings -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 2 findings -- perf: 1 finding -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 70/232/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md deleted file mode 100644 index c8b57ff3a..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-resource-p2.md +++ /dev/null @@ -1,77 +0,0 @@ -# d2b-contracts-resource-p2 - d2b-contracts-resource - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9703 (excl. src/generated/**) | modules: v3/volume.rs, v3/process.rs, v3/identity.rs, v3/execution_policy.rs, v3/resource.rs, v3/storage.rs, v3/volume_binding.rs, v3/activation_nixos.rs, v3/user.rs, v3/mod.rs, v3/artifact.rs, lib.rs (plus tests/schema.rs for the test lens) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 section f (file list above) - -## idiom -- d2b-contracts-resource-p2#1 sev=medium blast=leaf effort=S verdict=actionable - the sort-dedup-compare uniqueness check is hand-rolled at three production sites while a private helper already exists - fix: extract `ensure_unique(values: &[T]) -> Result<(), PrimitiveSpecError>` into execution_policy.rs (home of PrimitiveSpecError) and call it from VolumeSpec::new, ExecutionPolicy::new, and process.rs check_unique (which keeps only its max-bound check) - [packages/d2b-contracts-resource/src/v3/volume.rs:1210-1213, packages/d2b-contracts-resource/src/v3/volume.rs:1248-1253, packages/d2b-contracts-resource/src/v3/execution_policy.rs:792-796, packages/d2b-contracts-resource/src/v3/process.rs:1571-1579] - evidence: static reading of the three sites plus the existing helper; seeds: `for \w+ in 0\.\.` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 7 (all Default impls preserving frozen defaults, deliberate) -- d2b-contracts-resource-p2#2 sev=low blast=leaf effort=S verdict=actionable - ResourceSpec::serialize iterates `self.base.keys()` and re-gets each key with an avoidable `expect("key returned by canonical object")` - fix: iterate `for (key, value) in &self.base` and call `map.serialize_entry(key, value)?`, deleting the expect and the double lookup - [packages/d2b-contracts-resource/src/v3/resource.rs:621-626] - evidence: static reading; the map is a BTreeMap wrapper so pair iteration is a drop-in; seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 7 -- d2b-contracts-resource-p2#3 sev=low blast=leaf effort=S verdict=actionable - VolumeSpec::new checks `views.contains_key` and then repeats the lookup with a dead `ok_or(MissingRequiredField)` that can never fire - fix: collapse to one `let view = views.get(attachment.view.as_str()).ok_or(PrimitiveSpecError::MissingRequiredField)?;` - [packages/d2b-contracts-resource/src/v3/volume.rs:1218-1223] - evidence: static reading; the second `.ok_or` is unreachable after the `contains_key` early return; seeds: `for \w+ in 0\.\.` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0 - -## own -- clean: seeds ran: `\.clone\(\)` = 28, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 42, `Rc<|RefCell<|Arc)` signature, and the rest are test fixtures; no Rc/RefCell/Arc/Cow anywhere. - -## type -- d2b-contracts-resource-p2#4 sev=medium blast=leaf effort=S verdict=needs-contract - NixosGenerationStatus.observed_generation is a bare u64 while the crate already models exactly this value (zero meaning none) as ObservedGeneration in identity.rs - fix: replace the field type with `ObservedGeneration` (serde-transparent u64, same wire bytes and schemars shape) and update the accessor call sites - [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:285, packages/d2b-contracts-resource/src/v3/identity.rs:595-606] - evidence: static comparison with identity.rs ObservedGeneration whose doc states "zero meaning none", matching the field doc "Store generation revision observed by the controller"; seeds: `fn validate_\w+|fn check_\w+` = 13, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 2 (both are validated-at-construction octal/path strings, not state) -- d2b-contracts-resource-p2#5 sev=medium blast=leaf effort=S verdict=needs-contract - ActivationRunnerInput.target_generation is a bare u64 carrying a manual zero check plus a hand-rolled `nonzero_u64_schema`, duplicating the nonzero-generation newtype the crate already generates - fix: use the `nonzero_generation!` macro output (e.g. ConfigurationGeneration, transparent u64 with JsonSchema minimum 1) for the field, deleting `ActivationRunnerInputError::GenerationInvalid`, the zero check in `new`, and `nonzero_u64_schema` - [packages/d2b-contracts-resource/src/v3/activation_nixos.rs:46-47, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:59-63, packages/d2b-contracts-resource/src/v3/activation_nixos.rs:77-87, packages/d2b-contracts-resource/src/v3/identity.rs:448-472] - evidence: static reading; the invariant (nonzero) is already enforced by the existing macro-generated types in identity.rs; wire bytes unchanged under serde-transparent; seeds: `fn validate_\w+|fn check_\w+` = 13, `(mode|kind|state): String` = 2 - -## api -- d2b-contracts-resource-p2#6 sev=low blast=leaf effort=S verdict=actionable - the exported type alias `ValidatedSessionPurpose` has zero callers anywhere in the workspace - fix: delete the alias (identity.rs:270) or document the intended consumer before it accrues surface - [packages/d2b-contracts-resource/src/v3/identity.rs:269-270] - evidence: census: `ValidatedSessionPurpose` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (the definition itself); seeds: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 485, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 31 (house single-surface re-export arms, deliberate) - -## err -- clean: seeds ran: `\.unwrap\(\)|\.expect\(|\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 288, `let _ = |\.ok\(\);` = 1, `enum \w*Error` = 6. Every unwrap/expect outside `#[cfg(test)]` sits on a frozen literal with a named invariant (`expect("strict is a valid token")` process.rs:237, `duration()` process.rs:1636, `system_default()` execution_policy.rs:844, `resource_type()` activation_nixos.rs:245, `UserSpec::minimal` user.rs:127, `ResourceSpec::empty()` resource.rs:543) or after a compiler-invisible byte check (`is_valid_timestamp` identity.rs:207); the single `let _ =` is the deliberate `$clear` flag in the `digest_identity!` redaction macro; the six error enums are field-free so rejection diagnostics never echo caller text. - -## serde -- clean: seeds ran: `derive\([^)]*(De)?[Ss]erialize|serde\(...\)|impl .*Deserialize.*for|serde_json::from_|serde_json::to_` = 493. The hand-written `Deserialize` impls are all Wire-mirror admission gates (private-field struct, `deny_unknown_fields` Wire struct, `Self::new` validation mapped through `serde::de::Error::custom`) - the recorded house pattern per the refusal ledger (docs/explanation/over-engineering-audit-record.md, hand-written Deserialize admission-gate class); `#[serde(flatten)]` on ProcessSpec/EphemeralProcessSpec is serialization-only composition with the Wire mirror re-enabling `deny_unknown_fields`; enum representations are consistently external kebab-case/lowercase; optionality semantics (default vs Option vs skip_serializing_if) are consistent between the Serialize side and the Wire mirror on every checked type. - -## obs -- clean: seeds ran: `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0. The crate emits no telemetry at all; diagnostics are the redacted Debug/Display impls, which the tests pin. - -## docs -- d2b-contracts-resource-p2#7 sev=medium blast=leaf effort=S verdict=actionable - artifact.rs is the only module with an undocumented public surface: MAX_ARTIFACT_ID_BYTES, ArtifactIdError::Invalid, ArtifactId, parse, and as_str all lack doc comments while every sibling module documents its pub items - fix: add one-line doc comments mirroring the BoundedToken contract (bounded lower-kebab artifact identifier, never a host path) - [packages/d2b-contracts-resource/src/v3/artifact.rs:5, packages/d2b-contracts-resource/src/v3/artifact.rs:7-10, packages/d2b-contracts-resource/src/v3/artifact.rs:22, packages/d2b-contracts-resource/src/v3/artifact.rs:25, packages/d2b-contracts-resource/src/v3/artifact.rs:35] - evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 485, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 142; static comparison shows every other module documents its pub items (e.g. BoundedToken execution_policy.rs:186-191) -- d2b-contracts-resource-p2#8 sev=low blast=leaf effort=S verdict=actionable - two pub fns in execution_policy.rs lack doc comments: `ExecutionPolicyWire::into_policy` (pub because Host/Guest crates decode through the wire mirror) and `string_schema_object` (pub only for the exported `string_schema!` macro expansion) - fix: add one-line docs, noting for string_schema_object that it is macro-support surface - [packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-resource/src/v3/execution_policy.rs:944] - evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 485, `/// # (Examples|Errors|Panics|Safety)` = 0; static reading of the two items - -## perf -- clean: seeds ran: `format!\(` = 84, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 59, `\.to_string\(\)` = 8. The only non-test `format!` is `MilliCpu::to_canonical_string` (execution_policy.rs:363), a cold wire-rendering boundary; `TranscriptHash::to_hex` (identity.rs:660-668) pre-sizes with `String::with_capacity(64)`; `Vec::new()` hits are Default impls and test fixtures where the empty case is the common one; no hot path, no loop allocation, no attacker-keyed hashing (BTreeMap throughout). - -## conc -- N/A (seeds: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; all zero - the crate declares no threads, locks, atomics, or manual Send/Sync) - -## async -- N/A (seeds: `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; all zero - the crate is synchronous contract types only) - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; all zero - no unsafe blocks, fns, impls, or lint settings in the assigned files) - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; all zero - no foreign-language boundary) - -## macro -- clean: seeds ran: `macro_rules!` = 7, `proc_macro|syn::|quote!` = 0, `\$crate` = 1, `to_compile_error|new_spanned` = 0. All seven macro_rules! definitions (label_identity, digest_identity, nonzero_generation in identity.rs; redacted_debug, parsed_deserialize, string_schema in execution_policy.rs; opaque_storage_id in storage.rs) are the genuine impl-per-type generation answer; the exported macros use fully-qualified paths and `$crate::v3::execution_policy::string_schema_object`, so hygiene holds; no proc macros exist. - -## test -- clean: seeds ran: `#\[test\]|#\[tokio::test\]` = 75 (71 unit + 4 integration in tests/schema.rs), `assert_eq!\(|assert_ne!\(|assert!\(` = 299, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0. The suite is behavior-focused: golden byte vectors (MINIMAL_VOLUME_SPEC, MINIMAL_PROCESS_SPEC, GOLDEN_ENVELOPE, canonical base objects), round-trip tests, table-driven rejection tests with per-case messages, redaction tests with process-id markers, and schema-bound preservation tests; no test restates implementation and none is ignored. - -## Coverage -- idiom: 3 finding(s) -- own: clean (seeds ran: 28/42/0) -- type: 2 finding(s) -- api: 1 finding(s) -- err: clean (seeds ran: 288/1/6) -- serde: clean (seeds ran: 493) -- obs: clean (seeds ran: 0/0/0/0) -- docs: 2 finding(s) -- perf: clean (seeds ran: 84/59/8) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn, await, tokio, or block_on) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks/fns/impls or lint settings) -- ffi: N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, repr(C), or CStr) -- macro: clean (seeds ran: 7/0/1/0) -- test: clean (seeds ran: 75/299/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md deleted file mode 100644 index 1658e6ba8..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p1.md +++ /dev/null @@ -1,77 +0,0 @@ -# d2b-contracts-zone-session-p1 - d2b-contracts-zone-session - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6284 (excl. src/generated/**) | modules: v3::component_session, v3::role, v3::resource_export, v3::zone_link, v3::resource_import, v3::mod, lib -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/v3/component_session.rs, src/v3/role.rs, src/v3/resource_export.rs, src/v3/zone_link.rs, src/v3/resource_import.rs, src/v3/mod.rs, src/lib.rs (part 1/2; wire-contract crate, U1 (d) 6-7 apply) - -## idiom -- d2b-contracts-zone-session-p1#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default for ReceiveSequence` and `SendSequence` duplicate what `#[derive(Default)]` generates field-for-field (u64 plus bool, both zero) - fix: add `Default` to the derive lists of `ReceiveSequence` and `SendSequence` and delete the two hand-written impls; keep `ZoneLinkLimits`' Default (zone_link.rs:126) which preserves the nonzero bounds invariant - [src/v3/component_session.rs:1935, src/v3/component_session.rs:1976] - evidence: seed2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 3 hits; the two Default bodies call `Self::new()` whose field values equal the derived zeros, so the derive is behavior-identical; ZoneLinkLimits::default() calls `default_values()` (256/32/10/300) and is correctly hand-written -- clean: seeds 1/2/3 = 0/3/0 (`for \w+ in 0..` / hand-written impls / `let mut x = String|Vec::new()`); no index loops, no statement-style accumulation, and the only hand-written impls are the two derivable Defaults above plus the invariant-preserving ZoneLinkLimits one - -## own -- d2b-contracts-zone-session-p1#2 sev=low blast=family effort=S verdict=actionable - `HandshakeOffer::from(policy.clone())` at 7 sites across two crates: the by-value `impl From for HandshakeOffer` (component_session.rs:1172) forces a clone at every site that holds `&EndpointPolicy`, and every in-repo caller clones - fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in component_session.rs and switch the 7 sites to borrow; then delete the by-value impl if the census stays clone-only - [src/v3/component_session.rs:456, src/v3/component_session.rs:473, src/v3/component_session.rs:1014, d2b-session/src/admission.rs:593, d2b-session/src/engine.rs:689, d2b-session/src/handshake.rs:112, d2b-session/src/handshake.rs:171] - evidence: seed1 (`.clone()`) = 14 hits; census: `HandshakeOffer::from` over packages/ = 7 sites, every one passes a clone; the fix is additive so no caller breaks -- d2b-contracts-zone-session-p1#3 sev=low blast=family effort=S verdict=actionable - `ResourceExportSpec::validate_target` clones `target.resource_type()` and `target.metadata().name()` out of a borrowed `&ResourceEnvelope` only to rebuild the ref for comparison, because `ResourceRef::new` takes owned parts and the envelope exposes no borrowed accessor - fix: add `impl From<&ResourceEnvelope> for ResourceRef` (or a `resource_ref()` accessor) in d2b-contracts-resource and use it at the comparison site - [src/v3/resource_export.rs:545, src/v3/resource_export.rs:546] - evidence: seed1 (`.clone()`) = 14 hits; `ResourceRef::new(resource_type: ResourceTypeName, metadata: ResourceMetadata, ...)` takes owned values (d2b-contracts-resource/src/v3/resource.rs:712) and no `resource_ref()` accessor exists on the envelope; the clones are cold-path but signature-forced -- clean: seeds 1/2/3/4 = 14/21/0/0 (`.clone()` / `.to_owned()|.to_vec()|.to_string()` / `Rc<|RefCell<|Arc Result<`) = 102 hits; the listed methods verified doc-less while the role.rs/resource_export.rs/zone_link.rs/resource_import.rs constructors are documented, so the gap is specific to the component_session codec - -## perf -- clean: seeds 1/2/3 = 20/24/3 (`format!(` / collection `::new()` / `.to_string()`); format! is confined to cold `JsonSchema::schema_name` and #[cfg(test)] fixtures, collection news are test vectors, BinaryWriter is pre-sized with `with_capacity`, and the encode/decode paths are single-pass with no hot-loop allocation; static (unmeasured) - -## conc -- N/A: seeds 0/0/0/0 all zero (`std::thread::|thread::spawn|thread::scope` / `Mutex<|RwLock<` / `Atomic\w+|Ordering::` / `thread_local!|unsafe impl (Send|Sync) for`); no threads, locks, or atomics in a pure wire contract - -## async -- N/A: seeds 0/0/0/0 all zero (`async fn|async move|.await` / `tokio::spawn|spawn_blocking|JoinSet|select!|join!` / `tokio::sync::(Mutex|RwLock|Notify)` / `#[tokio::(main|test)]|Runtime::block_on`); no async code in the contract layer - -## unsafe -- N/A: seeds 0/0/0 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` / `// SAFETY:` / `transmute|from_raw|MaybeUninit|mem::zeroed`); seed 4 `unsafe_code` = forbid inherited through `[lints] workspace = true` (Cargo.toml), no local exceptions - -## ffi -- N/A: seeds 0/0/0/0 all zero (`extern "C"|no_mangle|unsafe(link_section` / `catch_unwind` / `repr(C)|repr(transparent)` / `CStr|CString|c_char`); no FFI surface - -## macro -- clean: seeds 1/2/3/4 = 3/0/0/0 (`macro_rules!` / `proc_macro|syn::|quote!` / `$crate` / `to_compile_error|new_spanned`); `closed_enum`, `wire_enum_values`, and `bounded_bytes` are impl-per-type generation (a genuine macro answer) with narrow ident/literal fragment specifiers, invoked only in the defining module where their unqualified `BinaryError` reference resolves, and no proc-macro machinery - -## test -- d2b-contracts-zone-session-p1#7 sev=medium blast=leaf effort=M verdict=actionable - the security-relevant codec state machines have no tests: RequestEnvelope::admit deadline/skew/lifetime math, FragmentSequence ordering/duplicate/complete detection, ReceiveSequence replay and nonce exhaustion, SendSequence::take, AttachmentCredits::reserve and process_pool, and the canonical round-trips of RecordHeader/FragmentHeader/HandshakeAccept, while the suite covers only policy validation, redaction, and frozen enum vectors - fix: add unit tests asserting the error variants (InvalidDeadline, Reordered, Duplicate, Replay, NonceExhausted, CreditExceeded) for each state machine, plus encode/decode round-trips for the header types - [src/v3/component_session.rs:2445, src/v3/component_session.rs:1829, src/v3/component_session.rs:1916, src/v3/component_session.rs:2732] - evidence: test seeds = 25 `#[test]` / 110 asserts / 0 proptest/insta/rstest / 0 `#[ignore]`; grep `FragmentSequence|ReceiveSequence|SendSequence|\.admit\(|process_pool` over tests/ = 0 hits, and no header round-trip test exists outside the enum-vector golden tests - -## Coverage -- idiom: 1 finding(s) -- own: 2 finding(s) -- type: clean (seeds ran: 14/0/0) -- api: 1 finding(s) -- err: clean (seeds ran: 96/0/0/10) -- serde: clean (seeds ran: 52/105/0/11) -- obs: clean (seeds ran: 0/0/0/0) -- docs: 2 finding(s) -- perf: clean (seeds ran: 20/24/3) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) -- async: N/A (seeds: 0/0/0/0 all zero; no async fns) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest inherits unsafe_code = "forbid") -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: clean (seeds ran: 3/0/0/0) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md deleted file mode 100644 index 399a5e4e9..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts-zone-session-p2.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-contracts-zone-session-p2 - d2b-contracts-zone-session - part 2/2 -Baseline: 6ebdd4cec | LOC audited: 6403 (excl. src/generated/**) | modules: v3/zone_routing.rs, v3/resource_bundle.rs, v3/zone_session.rs, v3/zone.rs, v3/role_binding.rs, v3/services.rs, v3/emergency_policy.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 section f (7 files, no item-range splits) - -## idiom -- clean: seeds 0/1/1 - the single hand-written Default (emergency_policy.rs:170) preserves the drain-deadline invariant a field-wise derive would break (card false positive), and the one Vec::new accumulation (zone_routing.rs:1554) is test code whose loop body asserts per item, where a plain loop is the right shape. - -## own -- d2b-contracts-zone-session-p2#1 sev=low blast=leaf effort=S verdict=actionable - ZoneLinkRouteWithdrawal::new clones the entire route-id vec only to detect duplicates - fix: sort the owned vec in place and check windows(2), mirroring the crate's own dedup pattern in RoleBindingSpec::with_facets (role_binding.rs:273-276) - [zone_routing.rs:883] - evidence: seed \.clone\(\) = 81 hits; this is the only non-test clone in a validation path, and the in-crate sort-plus-windows pattern at role_binding.rs:273-276 proves the clone is avoidable. -- d2b-contracts-zone-session-p2#2 sev=low blast=leaf effort=S verdict=actionable - reject_runtime_or_private_fields clones the whole spec object (object.clone().into_inner()) just to wrap it for the walk, on every BundleResource::new call - fix: make walk iterate the CanonicalJsonObject map directly (and a sibling fn for arrays) so no CanonicalJsonValue wrapper or clone is built - [resource_bundle.rs:944, resource_bundle.rs:149] - evidence: seed \.clone\(\) = 81 hits; the clone is on the success path of every BundleResource::new (call site resource_bundle.rs:149), and walk only needs Object and Array cases it can take by reference. -- d2b-contracts-zone-session-p2#3 sev=low blast=leaf effort=S verdict=actionable - ServiceDescriptor::new clones each method String for BoundedText::parse, which takes impl Into - fix: pass method.as_str() (String: From<&str> satisfies the bound) - [services.rs:216] - evidence: seed \.clone\(\) = 81 hits; the clone is required only by the argument position, and as_str() removes it without changing the parse allocation. -- clean: seeds 81/11/0/0 - remaining clones are test fixtures, wire-rendering to_owned on literals (schema_name, protocol constants), and the ResourceRef::new pair at resource_bundle.rs:689-690 which is required by the owned signature (same shape at d2b-contracts-resource/src/v3/resource.rs:718); no Rc/RefCell/Arc/Cow anywhere. - -## type -- d2b-contracts-zone-session-p2#4 sev=low blast=leaf effort=S verdict=actionable - narrowing_set_is_subset takes a bare empty_allowed_is_unrestricted: bool that flips the empty-allowed semantics between call sites - fix: replace the bool with a two-variant enum (or split into named fns) so the three call sites state the policy they mean - [role_binding.rs:179-182, role_binding.rs:149-162] - evidence: seed is_\w+: bool = 5 hits; the bool is passed both true (subresources, execution_refs) and false (zones) at role_binding.rs:149-162, so it is a real semantic switch, not a constant. -- clean: the remaining seed hits are cross-value validators (validate_self_resource, validate_finalizer, validate_scope_against_role, validate_zone, ZoneEnrollmentIdentity::validate) that check identity/ownership relations no parsed type can carry, and ZoneEnrollmentIdentity::validate is enforced at both decode boundaries (zone_session.rs:448, 502); no stringly-typed state and no flag-soup structs (EmergencyScope's four booleans are independent actions with all combinations valid). - -## api -- d2b-contracts-zone-session-p2#5 sev=low blast=leaf effort=S verdict=actionable - EmergencyPolicySpec::default_values is a pub method with zero callers outside its own Default impl - fix: delete it and let Default::default() be the single entry (or make it private) - [emergency_policy.rs:142, emergency_policy.rs:170] - evidence: census: default_values over packages/ = 4 hits (zone_link.rs:96, 128; emergency_policy.rs:142, 172), all within the two definitions and their Default delegation; no external caller. -- d2b-contracts-zone-session-p2#6 sev=low blast=leaf effort=S verdict=actionable - ZoneSpec::validate always returns Ok and has no callers, a dead always-succeeding validation on the exported surface - fix: remove the method (ZoneSpec is the empty spec; its Deserialize gate already enforces the only invariant) - [zone.rs:74] - evidence: census: ZoneSpec over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file (src/v3/zone.rs); the method is never invoked, only defined. -- clean: seeds 292/0/2 - the pub surface is the deliberate wide wire vocabulary of a contract crate (needs-contract to narrow); the two pub use arms (zone_session.rs:89, 104) are the documented house re-export pattern for the component-session taxonomy; no Arc/Rc/Box/RefCell in any public signature. - -## err -- d2b-contracts-zone-session-p2#7 sev=medium blast=leaf effort=S verdict=actionable - from_component_session on EndpointPurpose and ServicePackage panics via expect("preserved component-session tag") on a wire-derived value, enforcing the cross-taxonomy totality only at runtime - fix: replace the tag lookup with an exhaustive match over base::EndpointPurpose / base::ServicePackage variants so adding a component-session variant becomes a compile error, or return Result like EndpointRole::from_component_session already does (zone_session.rs:314) - [zone_session.rs:297, zone_session.rs:332] - evidence: seed \.unwrap\(\)|\.expect\( = 227 hits; 225 are in #[cfg(test)] or on literally-built values (card false positives), and these two are the only non-test expects on input-derived values in the lane. -- clean: seeds 227/1/0/5 - no panic!/unreachable!/todo!/unimplemented! anywhere; the single let _ = (zone.rs:84) discards a Wire value while propagating via ?; the five error enums are Copy unit-variant taxonomies with prose-documented Display, and wire refusal codes (ZoneEnrollmentRefusal) are returned, not panicked. - -## serde -- d2b-contracts-zone-session-p2#8 sev=medium blast=family effort=M verdict=actionable - seventeen hand-written Deserialize impls repeat the identical Wire-struct shape (local #[derive(Deserialize)] Wire with deny_unknown_fields, then new() plus map_err(serde::de::Error::custom)) - fix: consolidate behind a shared macro in the style of parsed_deserialize! at d2b_contracts_resource::v3::execution_policy, or #[serde(try_from = "Wire")] with TryFrom, keeping each new() gate as the admission check - [zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932, zone_routing.rs:1043, zone_routing.rs:1142, zone_routing.rs:1246, resource_bundle.rs:101, resource_bundle.rs:185, resource_bundle.rs:457, zone.rs:79, zone.rs:172, zone.rs:327, role_binding.rs:192, role_binding.rs:382, services.rs:265, emergency_policy.rs:176] - evidence: seed impl .*Deserialize.*for = 0 hits (the card regex misses impl<'de> forms); dedicated search impl<'de> Deserialize<'de> for = 20 blocks in the lane, 17 of them the Wire-struct shape; this is the recorded not-applied row C4 (docs/explanation/over-engineering-audit-record.md:475), so re-proposing is actionable with this citation. -- clean: seeds 52/90/0/45 - deny_unknown_fields is applied per type on every Wire gate, rename_all conventions are consistent (camelCase structs, kebab-case enums, PascalCase method vocabularies), optionality is deliberate (skip_serializing_if on BundleResourceMetadata and ProcessTemplateBinding, pinned null spellings on RoleBindingSpec round-trip goldens), and no live admission gate is bypassed by a direct derive. - -## obs -- N/A: seeds 0/0/0/0 all zero; the crate declares no tracing/log dependency (Cargo.toml), so there is no telemetry surface to judge. - -## docs -- d2b-contracts-zone-session-p2#9 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub constructors and the two panicking lifts document failure modes in prose but carry no canonical # Errors or # Panics sections anywhere in the lane - fix: add # Errors to the wire constructors (ZonePath::new, ZoneLinkRouteAdvertisement::new, RoleBindingSpec::with_facets, EmergencyPolicySpec::new, ServiceDescriptor::new) listing their PrimitiveSpecError/ContractError variants, and # Panics to from_component_session noting the totality invariant - [zone_routing.rs:210, zone_routing.rs:685, role_binding.rs:254, emergency_policy.rs:112, services.rs:200, zone_session.rs:296] - evidence: seed /// # (Examples|Errors|Panics|Safety) = 0 hits while -> Result< = 73 hits; every pub item carries a prose doc comment (checked all 40 candidates flagged by the lookback scan), so the gap is the canonical-section shape, not missing docs. -- clean: all pub items documented with one-line first sentences; module-level docs present (zone_routing.rs:1-16); magic values carry the why (MAX_ZONE_ADVERTISEMENT_LIFETIME_SECONDS, ZONE_ROUTE_INITIAL_HOP_BUDGET); no doctests exist and none are needed for pure contract types. - -## perf -- d2b-contracts-zone-session-p2#10 sev=low blast=leaf effort=S verdict=actionable - ProcessTemplateBinding validation builds a fresh String via format!("/bin/{}", ...) on every construction to run an ends_with check - fix: binary_path.strip_suffix(binary_ref.as_str()).is_some_and(|prefix| prefix.ends_with("/bin/")) which is allocation-free - [resource_bundle.rs:382] - evidence: seed format!\( = 38 hits; 37 are tests or the one-shot fingerprint renderer (services.rs:297); this is the only success-path allocation in the lane. static (unmeasured). -- clean: seeds 38/42/0 - the Vec::new/BTreeMap::new hits are the empty-case constructor (resource_bundle.rs:592) and test fixtures; no to_string() sites; no loops with per-iteration allocation. - -## conc -- N/A: seeds 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync in the lane. - -## async -- N/A: seeds 0/0/0/0 all zero; no async fn, await, tokio, or block_on in the lane. - -## unsafe -- N/A: seeds 0/0/0/0 all zero; no unsafe blocks, fns, impls, or SAFETY comments; the crate inherits unsafe_code = "forbid" via [lints] workspace = true (Cargo.toml). - -## ffi -- N/A: seeds 0/0/0/0 all zero; no extern "C", no_mangle, repr(C), catch_unwind, or CStr/CString in the lane. - -## macro -- clean: seeds 2/0/0/0 - opaque_routing_token! (zone_routing.rs:117) and zone_closed_enum! (zone_session.rs:121) are by-example impl-per-type generators (a genuine macro case), use narrow fragment specifiers (meta/ident/literal), are invoked only in their defining modules so hygiene holds, and zone_closed_enum!'s local redeclaration is documented as deliberately cheaper than exporting the component_session macro (zone_session.rs:114-120). - -## test -- d2b-contracts-zone-session-p2#11 sev=medium blast=leaf effort=S verdict=actionable - EmergencyPolicySpec's contract branches have no tests: the file holds exactly one test covering only the union behavior - fix: add table tests for new() rejecting deadline 0 and > MAX_EMERGENCY_DRAIN_DEADLINE_SECONDS, reason > MAX_EMERGENCY_REASON_BYTES, and control characters; plus effective_scope returning None when no policy is enabled, and the serde default round-trip - [emergency_policy.rs:236, emergency_policy.rs:112] - evidence: seeds #[test] = 50, assert = 255, proptest/insta/rstest = 0, #[ignore] = 0; emergency_policy.rs has 1 test for 4 validation branches plus the effective_scope all-disabled case, the widest untested contract surface in the lane. -- clean: seeds 50/255/0/0 - the other six modules carry strong in-module tests: golden canonical wire vectors with hand-written expectations (zone_routing.rs:1450-1462, zone_session.rs:787-908), tamper rejection (resource_bundle.rs:1110-1124), bounds at every MAX constant, secret-marker echo checks (zone_routing.rs:2052), and integration coverage of the re-exported session surface in tests/contracts.rs; no test restates implementation, no ignored tests. - -## Coverage -- idiom: clean (seeds ran: 0/1/1) -- own: 3 finding(s) -- type: 1 finding(s) -- api: 2 finding(s) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks and no unsafe_code = "allow" manifest) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: clean (seeds ran: 2/0/0/0) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md deleted file mode 100644 index c15b05766..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-contracts.md +++ /dev/null @@ -1,81 +0,0 @@ -# d2b-contracts - d2b-contracts -Baseline: 6ebdd4cec | LOC audited: 10,743 (excl. src/generated/**; no tests/** Rust files - only tests/fixtures/workload-execution-posture-v1.json fixture) | modules: whole crate (lib.rs + 26 public modules + src/v3/{mod,ifname}.rs; generated/ excluded) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-contracts#1 sev=medium blast=family effort=S verdict=actionable - d2b-contracts-control::public_wire re-declares a private copy of `validate_audit_page` instead of reusing the public export in d2b-contracts::audit_wire (the canonical home), so the two copies can drift - fix: import `validate_audit_page` from d2b_contracts::audit_wire in d2b-contracts-control/src/public_wire.rs (alongside the AExisting AuditExportCursor/Entry import at public_wire.rs:1)and delete the pub(crate) copy at public_wire.rs:2203 - [packages/d2b-contracts/src/audit_wire.rs:51, packages/d2b-contracts-control/src/public_wire.rs:2203] - evidence: census: `validate_audit_page` over packages/tests/docs = 5 hits: 2 definitions + 2 call sites (broker_wire.rs:2206, public_wire.rs:2193) + 1 import; the private copy duplicates the canonical home. - -## own -- clean: seeds ran: ~100/~46/0/0 ).clone(), .to_owned/.to_vec/.to_string, Rc/RefCell/Arc/Arc, Cow<); every production clone has a one-sentence ownership justification (negotiation-record ownership capability.rs:218, error-context ownership controller_config.rs:158 and identity_config.rs:149, owned-String accessors error.rs:674,691, wire-rendering string surfaces identity.rs:368/473/598, RealmTarget construction from a borrow target.rs:261/430/440, duplicate-target error message unsafe_local_workloads.rs:60/67and realm.rs:194-195); remaining clones sit in unit tests, and there are no Rc/RefCell/Arc/Cow sites. - -## type -- d2b-contracts#2 sev=medium blast=wide effort=M verdict=needs-contract - `complete: bool` + `next_cursor: Option<&AuditExportCursor>` in the audit-page surface encode exactly-two-valid-of-four states and both invalid combos are type-expressible; an enum would make them unrepresentable - fix: replace the pair with `enum AuditPageEnd { Complete, More(AuditExportCursor) }` and drive the wire structs/validators from it (callers: d2b-contracts-broker/src/broker_wire.rs:2206,and d2b-contracts-control/src/public_wire.rs:2193), keeping the existing admission behaviour - [packages/d2b-contracts/src/audit_wire.rs:51-59, packages/d2b-contracts-broker/src/broker_wire.rs:2184-2187, packages/d2b-contracts-control/src/public_wire.rs:2167-2173] - evidence: seed `fn validate_\w+|fn check_\w+|is_\w+: bool|\w+_flag: bool|(mode|kind|state): String` = 16 hits; the `complete`/`next_cursor` pair is the Option-pair smell the skill names; wire shape pinned by docs/reference/daemon-api.md:385,417 and schemas/v2/wire-protocol.json (AuditExportEntry/response definitions. - -## api -- d2b-contracts#3 sev=medium blast=leaf effort=S verdict=actionable - `pub fn validate_usb_bus_id` (types.rs:140) is never called in production and re-implements usbip.rs::validate_bus_id with a divergent contract (64-byte cap vs SYSFS_BUS_ID_MAX=31, requires a `-` separator whereusbip accepts bare `B`, plain String error vs typed `BusIdError`)- fix: delete types.rs::validate_usb_bus_id and move its covariance cases (types.rs:202-203into the usbip.rs test table so one canonical bus-id checker survives - [packages/d2b-contracts/src/types.rs:140, packages/d2b-contracts/src/usbip.rs:44] - evidence: census: `validate_usb_bus_id` over packages/tests/docs = 3 hits: 1 definition + 2 test assertions, 0 production callers; the canonical sibling is usbip.rs::validate_bus_id`. -- d2b-contracts#4 sev=medium blast=leaf effort=S verdict=actionable - `pub fn MediaRef::validate_value` (types.rs:114) is dead:the `opaque_id!`-generated `MediaRef::new` accepts any string without calling it, so the public fn advertises a shape check that never runs on the type it names - fix: either delete the fn, or wire it into construction via a `TryFrom<&str>` boundary on MediaRef (the house parse-gate pattern)so calers cannot bypass it - [packages/d2b-contracts/src/types.rs:96-113, packages/d2b-contracts/src/types.rs:114] - evidence: census: `MediaRef::validate_value` over packages/tests/docs = 3 hits: 1 definition + 2 test assertions (types.rs:200-201), 0 production callers (the generated macro body at types.rs:14-25 calls no validator. - -## err -- d2b-contracts#5 sev=medium blast=leaf effort=L verdict=actionable - Public constructors/validators return `Result<_, String>` or `&'static str` (ConfiguredArgv::new configured_argv.rs:15, RealmWorkloadsLauncherV2Json::validate launcher.rs:21, UnsafeLocalWorkloadsJson/LocalVmConfiguredWorkload/UnsafeLocalWorkload::validate unsafe_local_workloads.rs:35/81/96, MediaRef::validate_value and validate_usb_bus_id types.rs:114/140, validate_audit_page audit_wire.rs:51) while sibling validators inthe same crate use typed enum errors (BusIdError, IfNameError, IdError, ContractStringError, IdentityError, TokenError), forcing callers to string-match instead of matching variants - fix: introduce typed error enums per surface (e.g. `ConfiguredArgvError`, `UnsafeLocalWorkloadsError`, `LauncherMetadataError`, `MediaRefError`)with thiserror-style Display + std::error::Error impls and return them; call sites that only `.unwrap()` (census: ConfiguredArgv::new used in d2b-contracts-control, d2bd-runtime, d2bd, d2b-unsafe-local-helper) compile unchanged - [packages/d2b-contracts/src/configured_argv.rs:15, packages/d2b-contracts/src/launcher.rs:21, packages/d2b-contracts/src/unsafe_local_workloads.rs:35, packages/d2b-contracts/src/types.rs:114, packages/d2b-contracts/src/audit_wire.rs:51] - evidence: seed `\.unwrap\(\)|\.expect\(|let _ = |\.ok\(\);|\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 209 hits,mostly test-local; the 6 production String-error surfaces are named above;`enum \w*Error` =the typed-error sibling taxonomy the change would match. - -## serde -- d2b-contracts#6 sev=medium blast=wide effort=M verdict=needs-contract - `AuditExportEntry` carries `record: Option` andi `error: Option` where the doc (audit_wire.rs:27) promises exactly one is always populated,so both-None is a wire-accepted illegal state (the broker's own writers d2b-broker/src/audit.rs:1730-1732 etc always set one,but a literal or foreign producer can emit neither) - fix: replace the pair with an enum payload representation (e.g. `#[serde(tag = "type")] enum AuditExportEntryPayload { Record { record: Value }, Error { error: AuditExportErrorCode } }` or an admission-gate enforcing exactly-one at decode),preserving or explicitly changing the wire shape - [packages/d2b-contracts/src/audit_wire.rs:27-36] - evidence: seed `derive\([^)]*(De)?[Ss]erialize` = ~240 hits,`serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = ~80,`impl .*Deserialize.*for` = ~30,`serde_json::from_|to_` = ~28; the crate's serde discipline is otherwise uniform (rename_all/deny_unknown_fields/skip_serializing_if defaults everywhere); wire shape pinned by docs/reference/daemon-api.md:385,417 and schemas/v2/wire-protocol.json (AuditExportEntry definition. - -## obs -- N/A (seeds: 0/0/0/0 all zero; crate declares no println/log call and Cargo.toml carries no tracing/log dependency - only semver, serde, serde_json, schemars, sha2. - -## docs -- d2b-contracts#7 sev=low blast=leaf effort=M verdict=actionable - Public Result-returning parse/validate fns carry failure conditions only in prose (e.g. ids.rs:138-139, usbip.rs:44-46, contract_id.rs:99, realm.rs:88-90)and only one canonical doc section exists crate-wide,so`cargo doc` readers get no uniform `# Errors` contract - fix: add canonical `# Errors` sections to the public `-> Result<` fns (keeping the existing prose as the section bodies),matching the one existing `# Examples` pattern at workload_identity.rs:46 - [packages/d2b-contracts/src/ids.rs:138, packages/d2b-contracts/src/usbip.rs:44, packages/d2b-contracts/src/contract_id.rs:99, packages/d2b-contracts/src/audit_wire.rs:51] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~520 hits,`/// # (Examples|Errors|Panics|Safety)` = 1 hit (workload_identity.rs:46),`-> Result<` = ~115; pub items themselves are uniformly documented(no missing-docs class found),so the finding is section-shape,not coverage. - -## perf -- clean: seeds ran: ~70/~10/~27 (format!, Vec/VecDeque/HashMap/BTreeMap::new, .to_string()); all format! sites are error paths, one-shot render/schema builders, deserialize gates, or tests (e.g. error.rs:691-692, configured_argv.rs:53-74, ifname.rs:292,306,324-335),the Vec::new sites are empty-constructor/deserialize-gate/test builders, and no hot-path allocation class was found; static (unmeasured). - - - -## conc -- N/A (seeds: 0/0/0/0 all zero; no threads, mutexes, atomics, or unsafe Send/Sync claims in the crate. - -## async -- N/A (seeds: 0/0/0/0 all zero; no async fns, awaits, spawns, otokio runtime usage in the crate. - -## unsafe -- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks/fns/impls, SAFETY comments, transmute/from_raw/MaybeUninit, or unsafe_code text; crate inherits workspace `unsafe_code = "forbid"` via [lints] workspace=true in Cargo.toml. - - - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, catch_unwind, repr(C)/repr(transparent), CStr/CString/c_char sites (serde(transparent) is not an FFI repr. - -## macro -- clean: seeds ran: 7/0/0/0 (macro_rules! = the 7 definitions: contract_string!, realm_controller_string!, opaque_credential_value!, label_identity!, digest_identity!, id_newtype!, opaque_id!; proc_macro/syn/quote/$crate/to_compile_error = 0); all 7 are impl-per-type wire-newtype generators with concrete fragment specifiers (`ident`, `expr`, edition-2024 `expr_2021`, `meta`) and module-scoped textual scope (no #[macro_export], so no $crate path-shadowing hazard; no procedural macros. - - - -## test -- clean: seeds ran: ~70/~397/0/0 (#[test]/#[tokio::test], assert_eq!/assert_ne!/assert!, proptest/insta/rstest, #[ignore]); the crate's unit suites are table-driven round-trip/round-trip-fixture tests with real `tests/fixtures/workload-execution-posture-v1.json` consumption (workload.rs:222-249), fail-closed decode tests, schema-shape assertions,and redaction assertions; no #[ignore]d, flaky, or assert-nothing tests were found; there is no tests/** Rust integration surface (only the JSON fixture), which matches the crate's contract-module shape. - - - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: 146 total, all production clones explainable; no Rc/RefCell/Arc/Cow) -- type: 1 finding(s) -- api: 2 finding(s) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: 1 finding(s) -- perf: clean (seeds ran: ~70/~10/~27; allocation sites are cold/error/test paths) -- conc: N/A (seeds: 0/0/0/0 all zero; no threading/locks/atomics) -- async: N/A (seeds: 0/0/0/0 all zero; no async surface) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks; workspace forbids) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: clean (seeds ran: 7/0/0/0; 7 module-scoped impl-generating macros, no proc macros) -- test: clean (seeds ran: ~70/~397/0/0; no #[ignore]d or vacuous tests found) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md deleted file mode 100644 index a9d58a2b8..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p1.md +++ /dev/null @@ -1,76 +0,0 @@ -# d2b-core-controller-p1 - d2b-core-controller - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6805 (excl. src/generated/**) | modules: controller_assignment.rs, binding_children.rs, coordinator.rs, main.rs, controllers.rs, lib.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f): src/controller_assignment.rs, src/binding_children.rs, src/coordinator.rs, src/main.rs, src/controllers.rs, src/lib.rs (part 2: authority.rs, owner_reconcile.rs, authority_persistence.rs, migration.rs) - -## idiom -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 0; the single hand-written Default (controllers.rs:266) preserves the all-eleven-kinds registry invariant a field-wise derive would break, and every hand-written Debug impl is a partial redaction (the A6 class from docs/explanation/over-engineering-audit-record.md:459) that the all-redact `redacted_debug!` macro cannot express; no index loops, no statement-style accumulation. - -## own -- clean: seeds `\.clone\(\)` = 163, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 61, `Rc<|RefCell<|Arc Result<` items); failure conditions live only in the error-enum variant docs, so a caller must read the enum to learn which errors a fence method returns - fix: add `# Errors` sections naming the returned variants to the pub Result-returning methods, starting with the fence methods (validate_for, validate_writer, query, admit, publish_readiness, bind_vm) - [packages/d2b-core-controller/src/controller_assignment.rs:1793, 3054, 2501, 2720, packages/d2b-core-controller/src/main.rs:188, packages/d2b-core-controller/src/coordinator.rs:206] - evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 242, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 83 -- d2b-core-controller-p1#7 sev=low blast=leaf effort=S verdict=actionable - pub struct fields without doc comments: RuntimeReadiness (3 of 5 fields), RecoverySnapshot (5 of 7), HandlerStatus (all 8); the undocumented fields (checkpoint_revision, last_reconciled_tick, retry_after_tick, provider_lease_count) are non-obvious - fix: add one-line field docs to RuntimeReadiness, RecoverySnapshot, and HandlerStatus - [packages/d2b-core-controller/src/main.rs:33-56, packages/d2b-core-controller/src/controllers.rs:198-209] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 242 with the three structs' field blocks read in full - -## perf -- clean: seeds `format!\(` = 2 (both inside #[cfg(test)]), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 20 (cold admission, snapshot, and digest paths), `\.to_string\(\)` = 1 (wire rendering); no allocation site sits in a loop over unbounded input (mutation arrays capped at 128, verb sets at 64, status collections at MAX_STATUS_COLLECTION_ENTRIES); static (unmeasured) - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 13, `thread_local!|unsafe impl (Send|Sync) for` = 0; the atomics (AssignmentLeaseState phase/stale_observation at controller_assignment.rs:2661-2685, authority_epoch at main.rs:99) use correct Acquire/Release store/load pairs and AcqRel on an epoch counter; no lock, thread, or manual Send/Sync claim in the part. - -## async -- N/A: seeds `async fn|async move|\.await|tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(|tokio::sync::(Mutex|RwLock|Notify)|#\[tokio::(main|test)\]|Runtime::block_on` = 0 over the part's six files; all tokio usage in this crate lives in part 2 (authority.rs, authority_persistence.rs) - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern|// SAFETY:|transmute|from_raw|MaybeUninit|mem::zeroed|unsafe_code` = 0; no unsafe blocks, SAFETY comments, or lint overrides in the part - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section|catch_unwind|repr\(C\)|repr\(transparent\)|CStr|CString|c_char` = 0 - -## macro -- N/A: seeds `macro_rules!|proc_macro|syn::|quote!|\$crate|to_compile_error|new_spanned` = 0; redacted_debug! is invoked (controller_assignment.rs:68), not defined, in this part - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 50 in src plus 3 in tests/owned_children.rs, `assert_eq!\(|assert_ne!\(|assert!\(` = 183 plus 21, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; tests assert behavior (phase transitions, fence rejections, canonical round-trips, zone isolation, transport tamper rejection) with human-written expectations, no network or clock dependence, and the integration test consumes the public owner-reconcile API as a real caller. - -## Coverage -- idiom: clean (seeds: 0/1/0) -- own: clean (seeds: 163/61/0/0) -- type: clean (seeds: 5/0/0) -- api: 4 finding(s) -- err: clean (seeds: 285/0/0/7) -- serde: 1 finding(s) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in manifest) -- docs: 2 finding(s) -- perf: clean (seeds: 2/20/1) -- conc: clean (seeds: 0/0/13/0) -- async: N/A (seeds: 0 all zero; all tokio usage in part 2) -- unsafe: N/A (seeds: 0 all zero) -- ffi: N/A (seeds: 0 all zero) -- macro: N/A (seeds: 0 all zero) -- test: clean (seeds: 53/204/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md deleted file mode 100644 index 042ae2e6e..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-controller-p2.md +++ /dev/null @@ -1,88 +0,0 @@ -# d2b-core-controller-p2 - d2b-core-controller - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6748 (excl. src/generated/**) | modules: authority, owner_reconcile, authority_persistence, migration -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: src/authority.rs, src/owner_reconcile.rs, src/authority_persistence.rs, src/migration.rs (U1 section f) - -## idiom -- d2b-core-controller-p2#1 sev=low blast=leaf effort=S verdict=actionable - the duplicate-reservation checks bind a holder only to silence it with `let _ = holder;`, when the check is a pure predicate - fix: replace the `if let Some(holder) = ... { let _ = holder; return Err(...); }` blocks with `if entry.holders.iter().any(|holder| holder.owner_proof == request.owner_proof) { return Err(...); }` in admit_authority_inner_with_operation and admit_with_operation_id - [authority.rs:2189-2192, authority.rs:2542-2545] - evidence: seeds ran: `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 (the hand-written `Default for HostGlobalAuthorityIndex` at authority.rs:1745 preserves the per-instance nonce invariant, so a derive is correctly refused), `let mut \w+ = (String|Vec)::new\(\)` = 3 (statement accumulation in side-effectful plan/propagate loops, where the plain loop is the right shape); the two `let _ = holder;` sites were found by reading admit paths -- clean: no index loops, no replaceable derives, no statement-style accumulation that an iterator pipeline would improve; the three Vec::new accumulations carry real side effects and early exits - -## own -- d2b-core-controller-p2#2 sev=low blast=leaf effort=S verdict=actionable - OwnerIndex::plan clones the entire observed child map (`self.children.get(owner).cloned()`) though every later use is a read-only borrow, copying every ObservedChild (digest strings, dependency sets) per reconcile - fix: bind `let observed = self.children.get(owner).ok_or(OwnerReconcileError::OwnerNotRelisted)?;` and pass `&observed` to the existing `.get`, `for ... in &observed`, and `ordered_observed_refs` calls - [owner_reconcile.rs:1072-1075] - evidence: seed `\.clone\(\)` = 202 hits (authority.rs 126, owner_reconcile.rs 76); the other 201 are required ownership transfers (keys and proofs moved into index entries and leases, snapshots for durable handoff); this site is the only whole-map copy found by reading -- d2b-core-controller-p2#3 sev=low blast=leaf effort=S verdict=actionable - AuthorityReservation::reserve_durable clones the whole request into admit_authority_inner_with_operation and only afterwards builds the durable claim from the same request, when the claim can be computed first and the request moved - fix: compute `let claim = AuthorityStorageClaim::Generic(request.durable_claim());` before the lock block, then pass `request` by value into admit_authority_inner_with_operation, deleting the `.clone()` - [authority.rs:2803, authority.rs:2806] - evidence: seed `\.clone\(\)` = 202 hits; site read shows the clone at 2803 and the borrow-taking `durable_claim(&self)` at 2806, so the reorder is ownership-clean -- clean: no `to_owned`/`to_vec`/`to_string` beyond wire-rendering boundaries (15 hits, all `.to_owned()` on operation ids and digests at storage boundaries), no `Rc`/`RefCell`/`Arc` (0 hits), no `Cow` (0 hits); the Arc index sharing is the genuine multi-owner case (d2bd holds the same Arc, authority.rs:2636) - -## type -- d2b-core-controller-p2#4 sev=low blast=leaf effort=S verdict=actionable - AuthorityRequest::provider decides ProviderCardinality by string-comparing the rendered ref to "Provider/observability-otel", a stringly-typed special case whose why is not documented - fix: extract a named constant (e.g. `const OPTIONAL_PROVIDER_REF: &str = "Provider/observability-otel";`) beside the other domain constants and add a one-line doc noting the otel Provider is the one optional cardinality (D049 initial-Provider freeze), or move the decision into a `ProviderCardinality::for_provider(&ResourceRef)` helper - [authority.rs:985-988] - evidence: seeds ran: `fn validate_\w+|fn check_\w+` = 6 (all boundary admission validators called once from constructors, the parse-once shape the skill wants), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the otel string compare was found by reading the AuthorityRequest constructor family -- clean: no boolean-flag soup (deletion_requested/deletion_ready are fenced at construction, owner identity Options are set together and checked by validate_observed_owner), no stringly-typed state fields; validate_authority_combination is the single parse-once gate over class/scope/arbitration/cardinality combinations, which is the boundary shape the skill endorses - -## api -- d2b-core-controller-p2#5 sev=medium blast=leaf effort=M verdict=actionable - the parallel external physical-NIC machinery (TrustedExternalNicInventory, ExternalNicClaimRequest, ExternalNicLease, ExternalNicEffectGate, ExternalNicAdoption, ExternalNicCloseOutcome, ExternalNicReservation, the external_nics half of the index, and the EXTERNAL_PHYSICAL_NIC_* constants) has zero production callers; the prior audit row C2 names exactly this surface and is recorded not-applied with the site still matching - fix: delete the controller-side NIC request/lease/reservation/inventory types and the external_nics index half with their tests, keeping ExternalNicRecoveryInventory (consumed by d2bd-runtime's provenance fence) and the wire types in d2b-contracts-resource (consumed by d2bd and d2b-provider-network-local); cite record row C2 at docs/explanation/over-engineering-audit-record.md:473 - [authority.rs:80-128, authority.rs:167-211, authority.rs:258-335, authority.rs:1732, authority.rs:2645-2770] - evidence: census `ExternalNicClaimRequest|ExternalNicReservation|admit_before_effect|TrustedExternalNicInventory|ExternalNicLease|ExternalNicAdoption|ExternalNicEffectGate|ExternalNicCloseOutcome|durable_external_nic_claims|EXTERNAL_PHYSICAL_NIC` over packages/, nixos-modules/, tests/, labs/ = 0 hits outside authority.rs itself; the wire side (ExternalNicClaim, admit_external_nic_claims) has live callers at d2bd/src/resource_runtime.rs:10821-10850 and d2b-provider-network-local; C2 row confirmed still present -- d2b-core-controller-p2#6 sev=low blast=leaf effort=S verdict=actionable - public accessor aliases multiply paths to one item: OwnerReconcilePlan::create_order/batch, OwnerChildBatch::resource_refs, OwnerChildIdentity::resource_ref, TeardownPlan::order/refs/resources all duplicate a canonical accessor with zero external callers - fix: delete the zero-caller aliases and keep the canonical names (creation_order, deletion_order, create_batch, refs, target, order), retaining teardown_order which has live consumers - [owner_reconcile.rs:579, owner_reconcile.rs:600, owner_reconcile.rs:697, owner_reconcile.rs:754, owner_reconcile.rs:933-945] - evidence: census `create_order\(\)|teardown_order\(\)|\.batch\(\)|resource_refs\(\)|\.refs\(\)|\.resources\(\)` over packages/, nixos-modules/, tests/, labs/ = teardown_order 4 sites in 3 crates (d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:775, d2b-provider-audio-pipewire/tests/controller.rs:438, d2b-provider-device-security-key/tests/guest_frontend_process.rs:36, d2b-provider-device-usbip/tests/service_binding_lifecycle.rs:27) and refs 2 test sites; create_order, batch, resource_refs, resource_ref, order, resources = 0 external hits -- clean: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 1 hit, the `pub type AuthorityFuture` boxed-future alias (authority_persistence.rs:20-22) which is the required dyn-compatible shape for the object-safe AuthorityPersistence/AuthorityRecoveryProvenance traits; `pub use` = 0 (module paths are the house single-surface pattern via lib.rs `pub mod`); #[doc(hidden)] accessors and the feature-gated new_for_tests_ready are deliberate - -## err -- d2b-core-controller-p2#7 sev=low blast=leaf effort=S verdict=actionable - AuthorityError::DuplicateConflict renders the wire code "duplicateConflict", the only non-kebab-case code in the 25-variant enum, and nothing outside this crate matches the string - fix: change the code() arm to "duplicate-conflict" and update the two in-crate assertions that pin the old spelling (authority.rs:3409 and the code table test) - [authority.rs:412] - evidence: seed `\.unwrap\(\)|\.expect\(` = 160 hits, all inside #[cfg(test)] modules or doc examples (authority_persistence.rs:138 is a compile_fail doctest); `let _ = ` = 10 hits (authority.rs 8, authority_persistence.rs 2), every one a deliberate best-effort rollback or retryable-state recording on an error path already being returned; `panic!` = 1 hit, inside a test; census `duplicateConflict` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits outside authority.rs, and docs/reference/error-codes.md contains no authority code (grep for duplicateConflict|authority- = 0), so the spelling is not pinned -- clean: panic policy is clean outside tests (zero unwrap/expect in production code, zero panic macros); the error taxonomy is split by caller action (AuthorityError, OwnerReconcileError, OwnerGraphError, AuthorityPersistenceError, AuthorityReservationError) with Display equal to the stable code, so no caller string-matches a message; the `let _ =` rollback sites are the sanctioned best-effort-cleanup class - -## serde -- clean: seeds ran: derive = 10, serde attrs = 11, hand-written Deserialize = 0, serde_json = 2; durable rows use camelCase + deny_unknown_fields consistently (DurableAuthorityOwnerProof, DurableAuthorityClaim, DurableExternalNicClaim, AuthorityStorageClaim, AuthorityStorageOperation), enums use kebab-case, claim_digest canonicalizes through CanonicalJsonValue before hashing, and AuthorityOperationCapability proves non-deserializability with three compile_fail doctests (authority_persistence.rs:113-141); no hand-written admission-gate deserializers, no flatten, no untagged - -## obs -- N/A: seeds: 0/0/0/0 all zero; the crate has no tracing/log dependency (Cargo.toml lists only contracts, serde, serde_json, sha2, tokio), so there is no telemetry surface to judge - -## docs -- d2b-core-controller-p2#8 sev=medium blast=leaf effort=S verdict=actionable - the restart-recovery owner AuthorityRecoveryCoordinator and its data types expose eight pub items with no doc comment (PreparedAuthorityOperation::new, AuthorityRecoveryData::new, recover_with_provenance, index, is_ready_for_readiness, resolve_observed_and_adopted, resolve_observed_closed, quarantine), and this is the security-relevant path that decides whether recovered rows become readiness - fix: add one-line doc comments naming each method's contract, with `# Errors` on the Result-returning resolution methods (RowInvalid vs StateInvalid vs the persistence error) - [authority_persistence.rs:50, authority_persistence.rs:92, authority_persistence.rs:247, authority_persistence.rs:260, authority_persistence.rs:264, authority_persistence.rs:268, authority_persistence.rs:282, authority_persistence.rs:314] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 255 hits (authority.rs 112, owner_reconcile.rs 122, authority_persistence.rs 15, migration.rs 6); reading authority_persistence.rs found the eight bare pub fns while every sibling item carries a one-liner -- d2b-core-controller-p2#9 sev=low blast=leaf effort=S verdict=actionable - migration.rs exposes `requires_migration` and `validates_binding` without doc comments while every other pub item in the file documents its contract - fix: add one-line docs (e.g. "Whether this decision requires the broker migration path" and "Whether the supplied vm/intent bindings match the sealed decision") - [migration.rs:54, migration.rs:58] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 255 hits; reading migration.rs (124 lines) found exactly these two bare pub fns -- d2b-core-controller-p2#10 sev=low blast=leaf effort=M verdict=actionable - no Result-returning pub item carries an `# Errors` section (zero canonical sections in the lane), so failure conditions must be inferred from the code, most notably on the admission and reservation API (admit_authority, admit_before_effect, reserve, close_then_release) - fix: add `# Errors` sections naming the AuthorityError variants to the representative public admission/reservation fns (HostGlobalAuthorityIndex::admit_authority at authority.rs:2160, AuthorityReservation::reserve/close_then_release at authority.rs:2773/2855, ExternalNicReservation::close_then_release at authority.rs:2745) and adopt the section as the house shape for new Result fns - [authority.rs:2160, authority.rs:2773, authority.rs:2745] - evidence: seed `-> Result<` = 101 hits (authority.rs 57, owner_reconcile.rs 36, authority_persistence.rs 8, migration.rs 0); seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits across the lane - -## perf -- clean: seeds ran: format! = 12 (authority.rs 2, owner_reconcile.rs 8, migration.rs 2), collection-new = 23, to_string = 0; every format! hit sits inside a #[cfg(test)] module, and the four non-test Vec::new sites (owner_reconcile.rs:1077-1078, 1256, 1723) are the empty-case or side-effectful-accumulation shapes the card exempts; framed_digest already sizes its buffer with with_capacity (authority.rs:938-946); no hot-path allocation or attacker-keyed hashing found (static reading, unmeasured) - -## conc -- clean: seeds ran: threads = 0, Mutex/RwLock = 8 (all tokio::sync::Mutex in async contexts), atomics = 15, thread_local/unsafe impl = 0; the AtomicU64 orderings are correct for their use (Relaxed for the monotonic nonce counters, AcqRel fetch_add plus Acquire load for the paired runtime-epoch handoff at authority.rs:1789-1791 and 1964), std Mutex appears only in the cfg(test) RecordingPersistence helper with the sanctioned per-site allows, and no manual Send/Sync claims exist - -## async -- clean: seeds ran: async fn/await = 70, spawn/JoinSet/select = 0, tokio::sync = 11, tokio::main/test/block_on = 6 (all #[tokio::test]); no guard is held across an await (every lock().await completes within its statement or block, e.g. the reserve_durable lease block at authority.rs:2665-2672 and the coordinator's take-then-await sequence at authority_persistence.rs:286-292), no blocking calls appear inside async fns, and cancellation is covered by the durable operation rows plus the #[must_use] reservation contract (authority.rs:2634-2635), so a dropped reservation cannot silently release an unobserved effect - -## unsafe -- N/A: seeds: 0/0/0 all zero (no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed); the crate inherits the workspace `unsafe_code = "forbid"` via `[lints] workspace = true`, and no local unsafe_code attribute exists - -## ffi -- N/A: seeds: 0/0/0/0 all zero (no extern "C", no catch_unwind, no repr(C)/repr(transparent), no CStr/CString/c_char) in the lane scope - -## macro -- N/A: seeds: 0/0/0/0 all zero (no macro_rules!, no proc_macro/syn/quote, no $crate, no to_compile_error/new_spanned) in the lane scope - -## test -- d2b-core-controller-p2#11 sev=medium blast=leaf effort=M verdict=actionable - the restart-recovery receipt path (validate_recovery_operations, recovery_receipt_from_operations_with_prepared_capabilities, rehydrate) has no test anywhere: claim-digest verification, prepared-capability matching, and quarantine-on-mismatch are contract behavior with zero coverage - fix: add tests that build AuthorityStorageOperation rows with a tampered claim_digest, a prepared-capability set that misses an active operation, and a duplicate operation_id, asserting each returns InvalidAuthorityRequest, plus a rehydrate round-trip that admits after rehydration - [authority.rs:1824, authority.rs:1968, authority.rs:1899] - evidence: seed `#[test]|#[tokio::test]` = 36 hits (authority.rs 19, owner_reconcile.rs 14, migration.rs 3) and asserts = 102; census `rehydrate|recovery_receipt_from|validate_recovery_operations` over packages/ = definitions and production calls only (d2bd-runtime/src/authority_persistence.rs:399-462 exercises the ledger's own prepare/recover, not the controller's receipt validation), zero test call sites -- d2b-core-controller-p2#12 sev=medium blast=leaf effort=M verdict=actionable - AuthorityRecoveryCoordinator has no tests and its resolution methods have no callers at all, so the capability-restore-and-quarantine rollback on a failed record_close/release (authority_persistence.rs:292-311) is untested contract behavior that only a future driver will reach - fix: add coordinator tests with a failing persistence double asserting the capability is restored and the operation quarantined after record_close or release failure, and that resolve_observed_and_adopted clears the unresolved set - [authority_persistence.rs:246-320] - evidence: seed `#[test]|#[tokio::test]` = 36 hits, zero in authority_persistence.rs; census `recover_with_provenance|resolve_observed_closed|resolve_observed_and_adopted` over packages/, tests/, labs/ = 1 production call (d2bd/src/resource_runtime.rs:3149, recover_with_provenance only); the resolution methods appear nowhere else -- clean: the 36 tests that exist assert error variants and redaction contracts rather than Display strings (e.g. cross_zone_bridge_rejection_is_distinct_and_runs_no_effect asserts the exact AuthorityError and that zero effects ran), the integration suite tests/owned_children.rs covers the committed and uncertain batch-recovery paths with human-written expectations, and no #[ignore] or property-tooling gaps were found - -## Coverage -- idiom: 1 finding -- own: 2 findings -- type: 1 finding -- api: 2 findings -- err: 1 finding -- serde: clean (seeds ran: 10/11/0/2) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 3 findings -- perf: clean (seeds ran: 12/23/0; all format! hits inside test modules) -- conc: clean (seeds ran: 0/8/15/0) -- async: clean (seeds ran: 70/0/11/6) -- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe sites; workspace unsafe_code = "forbid" inherited) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 2 findings \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md deleted file mode 100644 index f1432acfb..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p1.md +++ /dev/null @@ -1,96 +0,0 @@ -# d2b-core-p1 - d2b-core - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8734 (excl. src/generated/**) | modules: bundle_resolver -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/bundle_resolver.rs (whole file) - -## idiom -- d2b-core-p1#1 sev=low blast=leaf effort=S verdict=actionable - resolve_network_projection_intent and resolve_network_sysctl_intent fetch the Network spec only to discard it via `let _ = spec;`, a workaround for the unused binding - fix: replace `let spec = self.find_network_spec(&parts)?; ... let _ = spec;` with the statement `self.find_network_spec(&parts)?;` (the `?` on Option keeps the admission check and drops the value) - [packages/d2b-core/src/bundle_resolver.rs:1805, packages/d2b-core/src/bundle_resolver.rs:1911] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 11 hits; `let _ = ` = 17 hits; the two discarded-spec sites read in full; the intent body never consults `spec` -- d2b-core-p1#2 sev=low blast=leaf effort=S verdict=actionable - `_ASSERT_TAPROLE` is a `#[allow(dead_code)]` const that exists only to silence an unused-import warning for `TapRole`, which the module does not actually name - fix: drop the `use crate::host::TapRole` import (the comment says `BridgePortFlags` uses the type internally) or import it as `use crate::host::TapRole as _;`, and delete the const - [packages/d2b-core/src/bundle_resolver.rs:5746] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 11 hits; the const and its explanatory comment read at 5743-5747; `TapRole` appears nowhere else in the file outside the import and the const -- d2b-core-p1#3 sev=low blast=leaf effort=S verdict=actionable - resolve_disk_init_ops nests two `for` loops over a single-arm `match` on `SpawnRunnerPlanOp`, which is a one-variant enum, so the match is a no-op wrapper around construction - fix: flatten to `vm.nodes.iter().flat_map(|n| &n.plan_ops).filter_map(|op| match op { SpawnRunnerPlanOp::DiskInit { .. } => Some(ResolvedDiskInitOp { .. }), })` or at least an `if let` for the single variant - [packages/d2b-core/src/bundle_resolver.rs:2434, packages/d2b-core/src/processes.rs:180] - evidence: seed `for \w+ in 0\.\.` = 0 hits, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0 hits, `let mut \w+ = (String|Vec)::new\(\)` = 11 hits; `SpawnRunnerPlanOp` enum read at processes.rs:180-211 has exactly one variant `DiskInit` - -## own -- d2b-core-p1#4 sev=low blast=leaf effort=S verdict=actionable - `ResourceUid::parse(value.clone())` plus `parts.network_uid.clone()` in find_network_spec and build_resource_network_intents, and `ZoneId::parse(zone.clone())` in zone_resource_bundle_zones, clone to feed parse/compare where `&str` suffices - fix: `ResourceUid::parse(value.as_str())` and compare `parse(...).ok().as_ref().map(ResourceUid::as_str) == Some(parts.network_uid.as_str())`; `ZoneId::parse(zone.as_str())`; the parse signatures are `impl Into` so `&str` converts without allocation - [packages/d2b-core/src/bundle_resolver.rs:1973, packages/d2b-core/src/bundle_resolver.rs:3354, packages/d2b-core/src/bundle_resolver.rs:1629] - evidence: seed `\.clone\(\)` = 116 hits, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 306 hits, `Rc<|RefCell<|Arc`) -- clean: the remaining clone/to_owned mass is intent-table construction from borrowed bundle data (owned struct fields), `Arc` clones at spawn boundaries are absent, and test-support injection clones are cfg-gated; no Rc/RefCell/Arc/Cow anywhere in the file - -## type -- clean: seeds `fn validate_\w+|fn check_\w+` = 0, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 1; the single hit (line 1194 `mode: String::new()`) is the deliberate fail-closed empty host model in `empty_zone_native_host` whose empty strings are the documented fail-closed contract, not a flag soup; boolean intent fields (`owned`, `stp_disabled`, `dynamic_bus_id`, `accepts_launch_args`) are constant at construction here but read or re-constructed by the broker/provider consumers, so they carry the closed policy rather than dead flexibility - -## api -- d2b-core-p1#5 sev=medium blast=leaf effort=S verdict=actionable - nine exported resolved-intent types have zero consumers anywhere in the workspace: ResolvedInstallerIntent, ResolvedMigrateIntent, ResolvedActivationIntent, ResolvedGcIntent, ResolvedKeysRotateIntent, ResolvedHostKeyTrustIntent, ResolvedRotateKnownHostIntent, ResolvedLegacySwtpmIntent, InstallerArtifact - fix: delete them, or wire them to the broker dispatch arms the module doc says are still `Unimplemented`; if kept for planned arms, mark them `#[doc(hidden)]` or gate them behind a feature - [packages/d2b-core/src/bundle_resolver.rs:620, packages/d2b-core/src/bundle_resolver.rs:641, packages/d2b-core/src/bundle_resolver.rs:656, packages/d2b-core/src/bundle_resolver.rs:698, packages/d2b-core/src/bundle_resolver.rs:705, packages/d2b-core/src/bundle_resolver.rs:713, packages/d2b-core/src/bundle_resolver.rs:723, packages/d2b-core/src/bundle_resolver.rs:778, packages/d2b-core/src/bundle_resolver.rs:633] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 158 hits; census: each of the nine names over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file hit (the definition in bundle_resolver.rs), zero construction or consumption sites -- d2b-core-p1#6 sev=medium blast=wide effort=M verdict=actionable - `BundleResolver` exposes seven `pub` fields (bundle, host, processes, storage, site, realm_workloads_launcher_v2, manifest) on the security-boundary type whose tables are derived from verified artifacts; the broker mutates `resolver.storage` directly, so the trusted model is writable by any consumer and derived state can drift from it - fix: make the fields private, add read accessors (`host()`, `manifest()`, `processes()`, `bundle()`, ...) and a single `set_storage(StorageJson)` setter, then migrate the ~30 read sites in d2bd, d2bd-runtime, and d2b-broker - [packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109, packages/d2b-core/src/bundle_resolver.rs:110, packages/d2b-broker/src/ops/storage_contract.rs:589, packages/d2b-broker/src/ops/state_dir.rs:440] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 158 hits; census: `resolver\.(bundle|host|processes|manifest|site|storage)` over packages/d2bd, packages/d2b-broker, packages/d2bd-runtime = 30+ read sites and 2 write sites (storage_contract.rs:589, state_dir.rs:440) -- d2b-core-p1#7 sev=low blast=leaf effort=S verdict=actionable - three `pub` methods have no out-of-crate callers and are only used inside this module and its tests: resolve_vm_start_intent, find_process_node, find_if_name_mapping_for_vm - fix: narrow to `pub(crate)` - [packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:2417, packages/d2b-core/src/bundle_resolver.rs:2506] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 158 hits; census: each method name over packages/ and tests/ = 1 file hit (bundle_resolver.rs itself, including its test module) - -## err -- d2b-core-p1#8 sev=medium blast=leaf effort=M verdict=actionable - resolve_macvtap_intents returns `Result, String>`, a String error in a library API whose two failure modes (missing process node, missing macvtap metadata) are indistinguishable to the caller; the broker wraps it wholesale into BrokerError::LiveHandler - fix: return `crate::error::Error` via `Error::manifest_parse_error` or a small enum with the two variants, and update the single broker call site - [packages/d2b-core/src/bundle_resolver.rs:2625, packages/d2b-broker/src/runtime.rs:6405] - evidence: seed `enum \w*Error` = 0 hits, `\.unwrap\(\)|\.expect\(` = 210 hits; the signature and both `ok_or_else(|| format!(...))` arms read at 2625-2648; broker call site read at runtime.rs:6405-6406 -- d2b-core-p1#9 sev=medium blast=leaf effort=M verdict=actionable - Network spec parse failures inside the trusted-bundle network path are silently dropped: `let Ok(spec) = serde_json::from_value::(spec_value) else { continue; };` in build_resource_network_intents and `serde_json::from_value(value).ok()` in find_network_spec, so a producer-side spec drift silently vanishes every intent for that network and surfaces only as an opaque "intent not found" at apply time - fix: plumb a `Result` out of build_resource_network_intents and find_network_spec and return `Error::manifest_parse_error("resource-bundle.json", reason)` on parse failure so the drift is diagnosable - [packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:1982] - evidence: seed `\.ok\(\);` = 1 hit, `let _ = ` = 17 hits; both sites read in full at 3355-3370 and 1959-1983; the bundle is hash-verified at load, so a parse failure is producer/consumer contract drift, not adversarial input -- d2b-core-p1#10 sev=low blast=leaf effort=M verdict=actionable - from_artifacts_with_zone_resource_bundles panics on caller-supplied input via two expects (`bundle serialization for audit hashing must succeed`, `zone resource bundle bytes must be verified`) in a `pub` API whose doc comment states the precondition but cannot enforce it; the fuzz target is one caller that passes arbitrary bytes - fix: return `Result` (map both to `Error::internal_io` / `Error::manifest_parse_error`) or downgrade to `debug_assert!` plus a doc note - [packages/d2b-core/src/bundle_resolver.rs:1405, packages/d2b-core/src/bundle_resolver.rs:1412, packages/d2b-core/fuzz/src/bin/core.rs:1] - evidence: seed `\.unwrap\(\)|\.expect\(` = 210 hits, of which 207 are inside `#[cfg(test)] mod tests` (lines 5724-8734) and 3 in library code (1405, 1412, 4469); the 4469 expect (`SHA-256 always has four-byte prefixes`) is a compiler-invisible invariant and is not flagged; sampled: 50 of 228 hits -- d2b-core-p1#11 sev=low blast=leaf effort=S verdict=actionable - manifest_parse_reason classifies serde failures by substring-matching the Display text (`"missing field"`, `"unknown field"`, `"invalid type"`), which is not a stable API and silently degrades to `"parse-failed"` on any message rewording - fix: match on `serde_json::Error::classify()` (ErrorClass::Syntax / Data / Eof) instead of the message text - [packages/d2b-core/src/bundle_resolver.rs:5730] - evidence: seed `enum \w*Error` = 0 hits; the function and its 9 call sites read at 5729-5740; the produced slug feeds the opaque reason of the wire code `manifest-parse-error` (docs/reference/error-codes.md:51), so the classification change is not wire-visible - -## serde -- d2b-core-p1#12 sev=low blast=leaf effort=S verdict=needs-contract - ZoneNativeIndexDocument derives Deserialize with `rename_all = "camelCase"` but no `deny_unknown_fields`, while the three sibling index types (ZoneNativeBundleIndex, ZoneNativeBundleRef, ZoneNativeTopology) all deny, leaving the top-level index admission inconsistent - fix: add `deny_unknown_fields` to ZoneNativeIndexDocument and keep the Nix emitter (nixos-modules/bundle.nix) in sync so no emitted key is rejected - [packages/d2b-core/src/bundle_resolver.rs:209, packages/d2b-core/src/bundle_resolver.rs:175, packages/d2b-core/src/bundle_resolver.rs:202, packages/d2b-core/src/bundle_resolver.rs:216] - evidence: seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 12 hits; the four index types read at 174-220; index.json is a bundle wire artifact emitted by nixos-modules/bundle.nix, hence needs-contract -- d2b-core-p1#13 sev=low blast=leaf effort=S verdict=actionable - `#[serde(default)]` on the four Option fields of ZoneNativeBundleIndex (storage_path, site_path, host_path, realm_workloads_launcher_v2_path) is redundant: a missing Option field already deserializes to None, so the attribute adds nothing and reads as a convention violation of the sibling fields - fix: drop the four attributes - [packages/d2b-core/src/bundle_resolver.rs:183, packages/d2b-core/src/bundle_resolver.rs:187, packages/d2b-core/src/bundle_resolver.rs:194, packages/d2b-core/src/bundle_resolver.rs:196] - evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 6 hits, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 12 hits, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 50; the round-trip test at 8718-8731 pins the optional-field behavior the attribute claims - -## obs -- d2b-core-p1#14 sev=medium blast=leaf effort=S verdict=actionable - verify_bundle_hash emits a backward-compatibility warning via `eprintln!` in library code, and d2b-core has no tracing/log channel at all, so the "bundleHash missing, skipping self-hash check" warning never reaches the daemon's structured logs and operators cannot see that hash verification was skipped - fix: add `tracing` (already the workspace-wide logging dependency in sibling crates) and emit `tracing::warn!(path = %path.display(), "bundle artifact has no bundleHash field; skipping self-hash check")`, or route the warning through the crate's audit/error path - [packages/d2b-core/src/bundle_resolver.rs:1097] - evidence: seed `\bprintln!\(|\beprintln!\(` = 1 hit, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0; d2b-core Cargo.toml carries no tracing dependency; the site is a library warn-and-continue path for pre-v2 bundles, not CLI product output - -## docs -- d2b-core-p1#15 sev=medium blast=leaf effort=S verdict=actionable - 15 of the 23 public `intent_id_*` constructors carry no doc comment (intent_id_store_view, intent_id_vm_start, intent_id_nft_host, intent_id_nft_env, intent_id_nft_projection_env, intent_id_ownership_marker_env, intent_id_bridge_env, intent_id_route_env, intent_id_sysctl, intent_id_hosts_host, intent_id_nm_unmanaged_host, intent_id_usbip_firewall, intent_id_usbip_bind, intent_id_runner, intent_id_legacy_runner), even though these format strings are the deterministic BundleOpId wire contract the module doc describes and integrators build by hand - fix: give each a one-line doc naming the exact `BundleOpId` shape it produces (the module table is the source) - [packages/d2b-core/src/bundle_resolver.rs:2917, packages/d2b-core/src/bundle_resolver.rs:2935, packages/d2b-core/src/bundle_resolver.rs:3118, packages/d2b-core/src/bundle_resolver.rs:3217, packages/d2b-core/src/bundle_resolver.rs:3130] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 23; the 23 intent-id functions enumerated at 2917-3223, 8 of them documented (the network_*_uids family and network_name_token) -- d2b-core-p1#16 sev=low blast=leaf effort=M verdict=actionable - a batch of public resolver items is undocumented (find_nft_intent and sibling find_* getters, resolve_vm_start_intent, resolve_vm_start_prerequisites, resolve_macvtap_intents, resolve_prepare_dir_intent, resolve_kernel_module_intent, resolve_role_device_claim, find_process_vm, find_process_node, find_host_env, find_if_name_mapping_for_vm, audit_bundle_version, audit_bundle_hash, the *_intent_ids iterators), and none of the 23 `-> Result<` items carries an `# Errors` section - fix: one-line docs on the batch and an `# Errors` paragraph on the Result-returning items (load_with_policy, render_json, resolve_macvtap_intents, zone_resource_bundle_zones) - [packages/d2b-core/src/bundle_resolver.rs:1663, packages/d2b-core/src/bundle_resolver.rs:2461, packages/d2b-core/src/bundle_resolver.rs:2621, packages/d2b-core/src/bundle_resolver.rs:1659, packages/d2b-core/src/bundle_resolver.rs:2816] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 158 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 23; the undocumented items were enumerated from the pub-surface listing at 1583-2843 - -## perf -- d2b-core-p1#17 sev=medium blast=leaf effort=S verdict=actionable - has_zone_uid re-parses every zone resource bundle on each call and zone_uid / find_network_spec re-parse bundle JSON per lookup (ResourceBundle::from_json over raw bytes), while parsed_zone_resources (populated once at load, line 1462) already holds the parsed ResourceBundle per zone - fix: have has_zone_uid, zone_uid, and find_network_spec iterate or index parsed_zone_resources instead of re-parsing bytes - [packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:1647, packages/d2b-core/src/bundle_resolver.rs:1959] - evidence: static (unmeasured); seed `format!\(` = 141 hits, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 197, `\.to_string\(\)` = 11; sampled: 50 of 349 hits; callers of has_zone_uid: d2bd/src/provider_effects.rs and d2b-broker/src/ops/tap.rs; find_network_spec runs on every resolve_network_*_intent call -- d2b-core-p1#18 sev=low blast=leaf effort=S verdict=actionable - the nft/hosts renderers build text with `buf.push_str(&format!(...))`, allocating a fresh String per line then copying it into the buffer (render_host_nft_script, render_env_nft_subset, render_hosts_managed_block), and sha256_hex collects 32 per-byte `format!("{b:02x}")` Strings - fix: `write!(&mut buf, ...)` into the existing buffer (std::fmt::Write) and hex-encode into a fixed `[u8; 64]` buffer or a single format call - [packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:3793, packages/d2b-core/src/bundle_resolver.rs:3986, packages/d2b-core/src/bundle_resolver.rs:1009] - evidence: static (unmeasured); seed `format!\(` = 141 hits; the render loops at 3717-3777, 3793-3802, and 3986-3989 each push_str a fresh format! result; these are cold bundle-load paths, hence low -- d2b-core-p1#19 sev=low blast=leaf effort=M verdict=actionable - six composite-key lookups allocate two Strings per call (`(zone.to_owned(), guest.to_owned())`) against BTreeMap<(String, String), _> maps (guest_setup_descriptors, guest_setup_descriptor_catalog_keys, guest_vmm_intents, guest_vmm_zone_uids) - fix: introduce a `ZoneGuestKey(String, String)` newtype with a `Borrow<(str, str)>` impl so lookups borrow without allocating, or nest the maps per zone - [packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:1617, packages/d2b-core/src/bundle_resolver.rs:2068, packages/d2b-core/src/bundle_resolver.rs:2087, packages/d2b-core/src/bundle_resolver.rs:5141, packages/d2b-core/src/bundle_resolver.rs:5355] - evidence: static (unmeasured); seed `\.to_string\(\)` = 11 hits and `\.to_owned\(\)` = 306 hits; the six lookup sites enumerated from the own-seed output; each is a read-only lookup in resolver hot paths (guest VMM intent resolution per request) - -## conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; bundle_resolver.rs declares no threads, locks, atomics, or manual Send/Sync (the crate's concurrency lives in loader_worker.rs, part 2's scope) - -## async -- clean: seeds `async fn|async move|\.await` = 4 hits, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the only async surface is load_on_loader_worker and load_with_policy_on_loader_worker, which delegate the blocking bundle read to `crate::loader_worker::run` - the dedicated bounded worker named in clippy.toml's replacement vocabulary (policy-confirmed good), with no guards held across await and no spawn/select sites - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 1, `unsafe_code` = 0; the single hit is `FileType::from_raw_mode` at line 977, a rustix API name, not an unsafe block; the workspace forbids unsafe_code and the file contains no unsafe - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the file crosses no FFI boundary - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros are defined or expanded in this file (only std macros like format! and vec!) - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 44 hits, `assert_eq!\(|assert_ne!\(|assert!\(` = 208 hits, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; sampled: 50 of 252 hits; the in-module suite (lines 5724-8734) is fixture-driven with failure-path coverage (tamper refusal, malformed CIDR refusal, fail-closed empty-host model, cross-crate serving-worker agreement pinned by a case table), asserts behavior rather than Display strings, and uses no ignored or network-dependent tests - -## Coverage -- idiom: 3 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 0/0/1; the single hit is the deliberate fail-closed empty host model) -- api: 3 finding(s) -- err: 4 finding(s) -- serde: 2 finding(s) -- obs: 1 finding(s) -- docs: 2 finding(s) -- perf: 3 finding(s) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics in bundle_resolver.rs) -- async: clean (seeds ran: 4/0/0/0; the two async fns delegate to the loader_worker bounded worker) -- unsafe: N/A (seeds: 0/0/1/0; the lone hit is the rustix from_raw_mode API name, not an unsafe block) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) -- test: clean (seeds ran: 44/208/0/0; fixture-driven behavior suite with failure-path coverage) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md deleted file mode 100644 index ad891b6aa..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-core-p2.md +++ /dev/null @@ -1,91 +0,0 @@ -# d2b-core-p2 - d2b-core - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6471 (excl. src/generated/**) | modules: privileges, host, manifest_v04, storage, test_support, console_ring, allocator_config, processes, storage_lifecycle, provider_artifact, host_w3, static_invariants, sync, runtime, base64_codec, sandbox_profile, kernel_seat, loader_worker, site, provider_capabilities, bundle, host_generation, closures, lib, unsafe_local_workloads, configured_argv, contract_id, error, privileges_w3, workload_identity -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: every src/*.rs except bundle_resolver.rs (part 1) and src/generated/**; tests/** added for the test lens - -## idiom -- d2b-core-p2#1 sev=low blast=leaf effort=S verdict=actionable - allowlist membership checks in static_invariants.rs use `iter().any(|f| f == last)` linear scans where slice `contains` reads cleaner - fix: replace `PUBLIC_MANIFEST_FIELDS.iter().any(|f| f == last)` with `PUBLIC_MANIFEST_FIELDS.contains(&last.as_str())` and `BROAD_CAPABILITIES.iter().any(|broad| broad == cap)` with `BROAD_CAPABILITIES.contains(&cap.as_str())` - [packages/d2b-core/src/static_invariants.rs:162, packages/d2b-core/src/static_invariants.rs:219] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits (all justified: VmGracefulShutdown Default preserves enable=true, builder Defaults delegate to new()); seed `for \w+ in 0\.\.` = 2 hits (kernel_seat round-robin and worker-start loops, justified); seed `let mut \w+ = (String|Vec)::new\(\)` = 3 hits (static_invariants accumulation, inherent to the recursive walker); the two `any` scans above are the remaining polish. -- clean: seeds 2/3/3 hits; the two index loops are deliberate fixed-count round-robins, the three hand-written Default impls preserve invariants a derive would break, and the Vec::new accumulation feeds a recursive walker; only the two `contains`-shaped scans are findings. - -## own -- d2b-core-p2#2 sev=low blast=leaf effort=S verdict=actionable - `path_bearing_key_violations` clones a borrowed `String` (`Value::String(s) => s.clone()`) only to run `.contains('/')` on it - fix: render through `Cow<'_, str>` (`Cow::Borrowed(s.as_str())` for the string arm, `Cow::Owned(other.to_string())` otherwise) so the common string case copies nothing - [packages/d2b-core/src/static_invariants.rs:201] - evidence: seed `\.clone\(\)` = 6 hits; of these only static_invariants.rs:201 copies a borrowed value needlessly (privileges.rs:722-726 clones non-Copy enums in a From conversion, static_invariants.rs:137/150 clone into a reused prefix buffer, storage.rs:432 is a test fixture); seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = ~45 hits, all test fixtures, wire-rendering boundaries, or thread-name construction; seeds `Rc<|RefCell<|Arc anywhere in the part; every to_owned/to_string site is a fixture, a rendering boundary, or a required owned argument. - -## type -- d2b-core-p2#3 sev=medium blast=leaf effort=S verdict=actionable - `ManifestShellName(pub String)` exposes its inner String publicly, so the shell-name shape invariant enforced in the hand-written `Deserialize` (and in `shell_name_valid`) can be bypassed by literal construction - fix: make the field private and add an `as_str()` accessor, mirroring the `AllocatorRealmPath` newtype pattern in allocator_config.rs; serde(transparent) keeps the wire shape unchanged - [packages/d2b-core/src/manifest_v04.rs:313] - evidence: seed `fn validate_\w+|fn check_\w+` = 4 hits; the allocator_config validate_* fns feed private-field parse-once newtypes (the correct pattern), while storage.rs:357 and sync.rs:136 are cross-field uniqueness checks a type cannot carry; seed `is_\w+: bool|\w+_flag: bool` = 3 hits (schema-mirroring fields, pinned wire shapes); seed `(mode|kind|state): String` = 3 hits (pinned wire fields); census: `ManifestShellName` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 3 hits, all in manifest_v04.rs plus the generated schema doc, so no external literal construction exists to break. -- clean: the only representable-illegal-state gap is the public tuple field on ManifestShellName; the boolean and String fields that the seeds hit are schema-mirroring wire fields pinned by docs/reference/manifest-schema.md and the schemars output. - -## api -- d2b-core-p2#4 sev=medium blast=wide effort=M verdict=actionable - six one-line compat shim modules (`error`, `contract_id`, `configured_argv`, `privileges_w3`, `workload_identity`, `unsafe_local_workloads`) re-export d2b_contracts items, making every re-exported item public at two paths (`d2b_contracts::error::Error` and `d2b_core::error::Error`); this is the recorded A4 not-applied row - fix: delete the six shim modules and re-point the ~25 import sites at `d2b_contracts::*` (and `d2b_contracts_resource::v3::ZoneResourceIdentity`); the `UnsafeLocalWorkloadIdentity` alias has zero consumers and goes with its module; the xtask gen-error-codes generator and docs/reference/error-codes.md anchors that read `d2b_core::error` must switch to `d2b_contracts::error` - [packages/d2b-core/src/error.rs:1, packages/d2b-core/src/contract_id.rs:1, packages/d2b-core/src/configured_argv.rs:1, packages/d2b-core/src/privileges_w3.rs:1, packages/d2b-core/src/workload_identity.rs:1, packages/d2b-core/src/unsafe_local_workloads.rs:1] - evidence: row A4 of docs/explanation/over-engineering-audit-record.md:457 records the six shims as not applied and the sites still match at HEAD; census: `d2b_core::(error|contract_id|configured_argv|privileges_w3|workload_identity|unsafe_local_workloads)::` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = ~25 hits in d2b-broker (runtime.rs:1278, ops/state_dir.rs:327, ops/storage_contract.rs:347), d2b (lib.rs:9), d2bd (composition.rs:77, 9503, 14122, 7840), d2bd-runtime (unsafe_local_helper.rs:1133, workload_dispatch.rs:923), labs/window-chrome/proxy (6 files), d2b-core tests, and the error-codes generator docs; `privileges_w3` has zero consumers. -- d2b-core-p2#5 sev=medium blast=wide effort=M verdict=actionable - `pub mod static_invariants` exports four security validators (world-readable-leak, path-bearing-key, broad-caps, writable-paths) with zero callers in the tree, and the bash gates the module doc says it replaced are gone, so the invariants are enforced nowhere; the module doc's claim that the original positive/negative cases were "preserved as unit tests" is false - fix: wire the validators into the contract-test lane (e.g. the d2b-contract-tests static-invariants structure ADR-046-zone-control cites) or the broker's manifest load path, or delete the module with its stale claim - [packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:158, packages/d2b-core/src/static_invariants.rs:189, packages/d2b-core/src/static_invariants.rs:216, packages/d2b-core/src/static_invariants.rs:230] - evidence: census: `world_readable_field_leaks|path_bearing_key_violations|is_broad_cap_violation|undeclared_writable_paths` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 4 hits, all the definitions themselves; glob `tests/static-invariant*` = no files (the bash gates are gone); the module is policy-known only via xtask SharedFamilyKnowledgeExemption rows (packages/xtask/src/provider_crate_policy.rs:3637-3641, 3661-3665, 4015-4019), which are token ratchets, not callers. -- d2b-core-p2#6 sev=low blast=leaf effort=S verdict=actionable - `PrivilegesJson::w1` is a pub constructor with zero production callers and an opaque name ("w1") unexplained by its doc comment - fix: rename to a descriptive constructor such as `from_const_rows()` or gate it behind cfg(test) - [packages/d2b-core/src/privileges.rs:741] - evidence: census: `PrivilegesJson::w1|::w1\(` over packages/, nixos-modules/, tests/, labs/ = 2 hits, both tests (privileges.rs:762 and packages/d2b-core/fuzz/src/bin/core.rs:160); seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 hits; seed `^\s*pub use ` = 8 hits, of which the six A4 shims are finding #4 and the runtime.rs re-export of eight d2b_contracts names is the applied-A3 house pattern (docs/explanation/over-engineering-audit-record.md:456). -- clean: no Arc/Rc/Box/RefCell in any public signature; the re-export surface is the six A4 shims (finding #4) plus the sanctioned runtime.rs arms; the remaining pub surface is wire DTOs whose width is the contract. - -## err -- d2b-core-p2#7 sev=medium blast=family effort=M verdict=actionable - `StorageJson::validate_unique_ids` and `SyncJson::validate_lock_order` return `Result<(), String>` with format!-built messages, and storage_lifecycle.rs re-derives the failure reason and offending id by string-prefix matching (`classify_storage_validation_reason`, `classify_sync_validation_reason`, `*_offending_id`, `bounded_contract_detail`), an error taxonomy that forces string-matching; the whole chain has no production caller - fix: return a typed validation error from both validators whose variants are the existing wire enums (`StorageContractValidationReason`, `SyncContractValidationReason`) with the offending id as payload, and delete the classifier functions - [packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136, packages/d2b-core/src/storage_lifecycle.rs:116, packages/d2b-core/src/storage_lifecycle.rs:140] - evidence: seed `enum \w*Error` = 3 hits (LayoutError, LaunchError, HostGenerationError, all closed token enums with Display and Error impls, fine); census: `validate_lock_order|validate_unique_ids|classify_sync_validation_reason|classify_storage_validation_reason` over packages/, nixos-modules/, tests/, labs/ = only in-crate definitions, in-crate tests, and a d2b-provider-volume-local import (packages/d2b-provider-volume-local/src/diagnostics/storage_lifecycle.rs:18) used solely by its test at 348-362; the String messages never cross the wire (the report persists the enum), so the change is not needs-contract. -- d2b-core-p2#8 sev=low blast=leaf effort=S verdict=actionable - `SiteJson::validate` returns `Result<(), &'static str>` with a bare token ("invalid-wayland-socket") that callers must string-match - fix: return a small unit error enum (e.g. `SiteValidationError::InvalidWaylandSocket`) with the token as its Display - [packages/d2b-core/src/site.rs:42] - evidence: seed `\.unwrap\(\)|\.expect\(` = 66 hits, every one inside #[cfg(test)] modules (verified per file); seed `let _ = |\.ok\(\);` = 2 hits, both `let _ = reply.send(job());` best-effort oneshot sends on a dead worker (kernel_seat.rs:160, loader_worker.rs:130), deliberate; seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0 hits; the only taxonomy smell is the string-token error above. -- clean: panic policy is clean (no unwrap/expect in production code, no panic macros); the two `let _ =` sites are documented best-effort sends; error enums are small and closed; the two findings above are the taxonomy shape. - -## serde -- d2b-core-p2#9 sev=low blast=leaf effort=S verdict=actionable - `StorageLifecycleIssue` struct variants carry per-field `#[serde(rename = "bundleVersion")]`-style renames instead of the house `#[serde(rename_all = "camelCase")]` per variant, scattering the wire convention across fields - fix: add `#[serde(rename_all = "camelCase")]` to each struct variant and drop the per-field rename attributes; the serialized shape is unchanged (pinned by the storage_lifecycle tests) - [packages/d2b-core/src/storage_lifecycle.rs:49, packages/d2b-core/src/storage_lifecycle.rs:61, packages/d2b-core/src/storage_lifecycle.rs:70] - evidence: seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = ~60 hits; seed `derive\([^)]*(De)?[Ss]erialize` = ~90 hits; seed `impl .*Deserialize.*for` = 2 hits (ManifestV04 and ManifestShellName, both live admission gates with per-key validation a derive cannot express, and the allocator_string! macro generates the third via expansion); seed `serde_json::from_|serde_json::to_` = ~25 hits, mostly tests plus ManifestV04::from_slice; the StorageLifecycleReport deliberately lacks deny_unknown_fields (forward-compat test at storage_lifecycle.rs:256). -- clean: the hand-written Deserialize impls are justified admission gates (manifest VM-key shape, shell-name shape) and the flatten+deny_unknown_fields combination on ManifestV04 is re-implemented correctly in the manual impl; the only convention drift is the per-field rename set above. - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0; the crate carries no telemetry at all, which is appropriate for a DTO/worker crate whose only I/O is the bounded worker seats. - -## docs -- d2b-core-p2#10 sev=medium blast=leaf effort=M verdict=actionable - manifest_v04.rs has no module doc and no doc comments on its central public wire types (`ManifestV04`, `ManifestMeta`, `ObservabilityMeta`, `VmEntry`, `VmLifecycle`, `VmGracefulShutdown`, `VmLiveActivation`, `VmLanPolicy`, `VmObservability`, `VmShellMetadata`, `ManifestShellName`, `from_slice`, `to_compact_json`), while sibling modules (host.rs, storage.rs, sync.rs, site.rs) document every type - fix: add a `//!` module doc and one-line doc comments with `# Errors` on the parse/serialize entry points, following the sibling-module style - [packages/d2b-core/src/manifest_v04.rs:1, packages/d2b-core/src/manifest_v04.rs:31, packages/d2b-core/src/manifest_v04.rs:158, packages/d2b-core/src/manifest_v04.rs:209, packages/d2b-core/src/manifest_v04.rs:41, packages/d2b-core/src/manifest_v04.rs:67] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~140 hits across 25 files; seed `/// # (Examples|Errors|Panics|Safety)` = 1 hit (console_ring.rs:48, the only canonical section in the part); direct read of manifest_v04.rs:1-123 confirms the module opens with `use` statements and the struct at line 31 carries no doc comment; host.rs:6-9, storage.rs:8-10, sync.rs:9-11 show the sibling convention. -- d2b-core-p2#11 sev=low blast=leaf effort=M verdict=actionable - the crate's Result-returning public API has no `# Errors` sections anywhere (only console_ring documents `# Panics`), so callers of `decode`, `validate`, `from_slice`/`from_path`/`to_compact_json`, `validate_unique_ids`, `validate_lock_order`, `parse`, `SourceGenerationCompatibilityFloorV1::new`, `kernel_seat::run`, and `loader_worker::run`/`run_probe` must read the body to learn the failure modes - fix: add `# Errors` sections naming the failure conditions (e.g. decode: non-alphabet byte, misplaced padding, non-multiple-of-four length) - [packages/d2b-core/src/base64_codec.rs:62, packages/d2b-core/src/site.rs:42, packages/d2b-core/src/manifest_v04.rs:41, packages/d2b-core/src/host_generation.rs:15, packages/d2b-core/src/kernel_seat.rs:150, packages/d2b-core/src/loader_worker.rs:92] - evidence: seed `-> Result<` = 17 hits across the part; zero of the public Result-returning items carry `# Errors` (seed 2 = 1 hit total); missing_docs is not enabled anywhere, so this is a proposal-class polish finding. -- clean: the one canonical section that exists (RingBuffer::new `# Panics`) is correct and the doc first sentences that exist are strong; the gaps are the two findings above. - -## perf -- clean: seeds `format!\(` = 10 hits (error-path messages, one-shot thread names at kernel_seat.rs:84, and a violation-rendering loop on a cold invariant path), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 14 hits (empty-case ring reads, bounded manifest walks, test fixtures), `\.to_string\(\)` = 8 hits (tests and error paths); the hot paths that exist (base64 encode/decode, ring buffer) already use with_capacity and sized buffers; all findings would be static (unmeasured) and none clears the bar. - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0 (threads exist via `thread::Builder` in kernel_seat.rs:83 and loader_worker.rs:63), `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 4 hits, `thread_local!|unsafe impl (Send|Sync) for` = 0; the single atomic (kernel_seat.rs:72, 102, 112) is a round-robin cursor with Relaxed ordering, exactly the counter-nobody-synchronizes-on case, and the worker seats are the sanctioned R4 sync_channel boundary with per-site allows (kernel_seat.rs:86-89, loader_worker.rs:66-69). - -## async -- clean: seeds `async fn|async move|\.await` = 8 hits, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0 (spawn_blocking appears only in module docs explaining why it is not used), `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the four async entry points (kernel_seat.rs:150, loader_worker.rs:92, 106, 114) admit via non-blocking try_send and await a oneshot, holding no lock across await and never blocking the executor; cancellation drops the waiter while the already-admitted job runs to completion, which the module docs state. - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; the crate inherits the workspace `unsafe_code = "forbid"` and contains no unsafe blocks, so the lens has nothing to judge. - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the part crosses no FFI boundary (serde(transparent) newtypes are not repr(transparent) FFI carriers). - -## macro -- clean: seed `macro_rules!` = 1 hit (allocator_config.rs:66 `allocator_string!`), seeds `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the single macro is impl-per-type generation (one of the three genuine macro answers), uses narrow ident/expr fragment specifiers, and references only items local to its expansion site, so no $crate or _private module is needed. - -## test -- d2b-core-p2#12 sev=medium blast=leaf effort=S verdict=actionable - the static_invariants.rs module doc claims the bash-gate cases were "preserved as unit tests", but the file contains no `#[cfg(test)]` module, so the four security invariant validators have zero test coverage (and zero callers, per finding #5) - fix: add the unit tests the doc promises (positive and negative fixtures for each validator, matching the old bash-gate cases) or correct the doc if the module is retired - [packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:158] - evidence: seed `#\[test\]|#\[tokio::test\]` = 0 hits in static_invariants.rs (grep over the file: no cfg(test), no #[test]); the seed totals for the part are ~42 in-module tests plus ~29 in tests/, all with real assertions; seed `proptest!|insta::assert|rstest` = 0 and seed `#\[ignore\]` = 0. -- d2b-core-p2#13 sev=low blast=leaf effort=S verdict=actionable - `tamper_owner_wrong_uid` in tests/bundle_resolver_tamper.rs silently returns (eprintln + return) when not root, so it passes vacuously on non-root CI and a regression in the chown tamper path would go unnoticed there - fix: convert the inline skip to the repo's documented `#[ignore]` root-only pattern (the card's false-positive list endorses documented ignores) so the skip is visible in test output - [packages/d2b-core/tests/bundle_resolver_tamper.rs:149] - evidence: seed `#\[ignore\]` = 0 hits, so the repo's documented-ignore convention is not applied here; the test body at lines 148-151 shows the silent-return shape; the remaining ~71 tests in the part are behavior-asserting (golden round-trips via include_str!, RFC 4648 vectors, bounded-queue refusal semantics, deny-unknown-fields closures) and can fail. -- clean: the suite is otherwise strong: golden fixtures from tests/golden, RFC 4648 vectors, corpus-driven bounded-input tests (tests/manifest_bounded_property.rs), worker panic/refusal semantics (tests/loader_worker.rs, tests/loader_worker_panic.rs), and error-kind assertions rather than Display strings in manifest_v04 tests; the two findings above are the only gaps. - -## Coverage -- idiom: 1 finding | clean otherwise (seeds: 2/3/3) -- own: 1 finding | clean otherwise (seeds: 6/~45/0/0) -- type: 1 finding | clean otherwise (seeds: 4/3/3) -- api: 3 finding(s) (seeds: ~140 pub items across 25 files, 0, 8) -- err: 2 finding(s) (seeds: 66 all in tests, 2, 0, 3) -- serde: 1 finding | clean otherwise (seeds: ~90/~60/2/~25) -- obs: clean (seeds: 0/0/0/0; crate has no telemetry) -- docs: 2 finding(s) (seeds: ~140, 1, 17) -- perf: clean (seeds: 10/14/8; all cold-path or sized) -- conc: clean (seeds: 0/0/4/0; Relaxed round-robin cursor correct) -- async: clean (seeds: 8/0/0/0; try_send admission + oneshot await, no blocking) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, workspace unsafe_code = "forbid") -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary in the part) -- macro: clean (seeds: 1/0/0/0; single justified impl-per-type macro) -- test: 2 finding(s) (seeds: ~71, ~150, 0, 0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md deleted file mode 100644 index 755ea3802..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-host.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-host - d2b-host -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11,767 (excl. src/generated/**; src 11,316 + tests 451) | modules: bridge_port, cgroup, devices, hardlink_farm, host_generation, host_prep_dag, ifname, ioctl_policy, media, modules, netlink, nftables, ownership_matrix, routes, seccomp, bin/ -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- clean: seeds ran: 1/0/18. The single `for \w+ in 0..` hit is a test-fixture side-effect loop (tests/activation_helper_build_farm.rs:23; plain `for` is right per the skill); all 18 `let mut X::new()` sites are legitimate accumulation into owned buffers or error vectors with real side effects; zero hand-written `Default|From|Debug|Clone|Hash|Eq|PartialEq` impls; no `fn get_` names found. - -## own -- clean: seeds ran: 66/335/3. Every `.clone()` (66) and `.to_owned()|.to_string()` (335) inspected: each is an explainable error-record payload, a multiple-step construction from one borrowed value (host_prep_dag bundle refs, devices rows, ownership_matrix drift records), a test fake (RefCell-backed ops logs, drift simulators), or a wire/serde boundary; the 3 shared-ownership hits are 2 test-fake `RefCell>` fields (netlink.rs:357, nftables.rs:891,894) and 1 test-fake `Mutex` (cgroup.rs:796); no Rc/Arc/Cow in production code. - -## type -- d2b-host#1 sev=medium blast=family effort=M verdict=actionable - `BusId(pub String)` carries no lexical invariant: `BusId::new` accepts any string and the field is public, so the busid grammar is re-validated at every consumer instead of once at the type boundary - fix: make the field private, validate in `BusId::new` (reusing `media::validate_usb_busid`'s grammar) or add `TryFrom<&str>`, keep `#[serde(transparent)]`; then delete the three broker re-validation sites - [packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194] - evidence: seed `fn validate_\w+|fn check_\w+` = 10 hits; census: `validate_usb_busid` over `packages/` = 4 hits (3 broker call sites + defined here); `BusId(` literal construction over `packages/` = 0 external hits. - -## api -- d2b-host#2 sev=low blast=leaf effort=S verdict=actionable - `HostPrepStepId(pub String)` exposes the inner `String` on a `#[serde(transparent)]` newtype whose only constructor `new` is private, so literal construction is the only external path and the `{vm}:{kind}` id convention stays unenforced - fix: make the field private (serde transparent round-trips unchanged; `as_str()` already exists) and add a public constructor if integrators need one - [packages/d2b-host/src/host_prep_dag.rs:85] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 311 hits; census: `HostPrepStepId(` over `packages/` = 0 external literal constructions (in-crate tests only). - -## err -- clean: seeds ran: 290/23/15/14. All 290 unwrap/expect hits are in `#[cfg(test)]` modules or two justified non-test sites (`media.rs:322` after an explicit `len() != 1` guard; `host_prep_dag.rs:503` on a statically-built DAG with a named invariant); the 23 `let _ =` sites are deliberate best-effort fsync/cleanup shrugs; alla 15 panic! hits are test-arm `panic!("expected ...")` plus the documented invariant `assert!` at seccomp.rs:132 (with `# Panics` contract, and the ioctl matrix is bounded below 251 by construction); the 14 error enums are closed and wire-coded (`code()`, `as_kebab_case()`, serde-tagged`, no string-matching taxonomy. - - - -## serde -- d2b-host#3 sev=low blast=family effort=S verdict=actionable - `NftBatch` derives `Deserialize` but its `&'static str` fields pin the generated impl to `'de: 'static` (serde's `impl<'de: 'a, 'a> Deserialize<'de> for &'a str`), so the type cannot be deserialized from any runtime input; the derive is dead and misleads (the broker only ever `NftBatch::parse`s text or constructs batches) - fix: drop `Deserialize` from the `NftBatch` derive (keep `Serialize`), or make `table_family`/`table_name` owned `String` if round-trip is ever intended - [packages/d2b-host/src/nftables.rs:229] - evidence: seed `derive\([^)]*(De)?[Ss]erialize|serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)|impl .*Deserialize.*for|serde_json::(from|to)_` = 125 hits; census: no `serde_json::from_*` on `NftBatch` over `packages/` = 0 hits; `NftBatch::parse` call sites in d2b-broker = 4. - - - -## obs -- clean: seeds ran: 28/0/0/0. Every println!/eprintln! hit lives in `bin/d2b-activation-helper.rs` and is CLI product output or the helper's JSON wire protocol on stdout (card false positive for `bin/**`); zero tracing/log, zero instrument spans, zero interpolated telemetry events (this crate deliberately carries no telemetry dependency). - -## docs -- d2b-host#4 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub functions document failure conditions in prose but carry no `# Errors` sections; the crate has only 2 canonical sections total (host_prep_dag.rs:316, seccomp.rs:112) against ~119 `-> Result<` signatures (validate_readback, parse_request, gunzip_inflate, ...) - fix: add `# Errors` sections naming the failure conditions to the pub Result-returning fns, starting with the wire-boundary parsers (host_generation.rs, media.rs, nftables.rs) - [packages/d2b-host/src/bridge_port.rs:127, packages/d2b-host/src/host_generation.rs:103, packages/d2b-host/src/media.rs:41] - evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 284, `/// # (Examples|Errors|Panics|Safety)` = 2, `-> Result<` = 119. -- d2b-host#5 sev=low blast=leaf effort=S verdict=actionable - Pub items in impl blocks lack doc comments: `Controller::REQUIRED`, `Controller::as_str`, `Controller::from_token`, `BusId::new`, `HostPrepStepId::as_str` - fix: one-line doc comments, with `from_token` documenting the token grammar it accepts - [packages/d2b-host/src/cgroup.rs:53, packages/d2b-host/src/cgroup.rs:71, packages/d2b-host/src/cgroup.rs:85, packages/d2b-host/src/nftables.rs:612, packages/d2b-host/src/host_prep_dag.rs:92] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 284 hits; the five anchors carry no preceding `///` line (verified by neighborhood read). - -## perf -- d2b-host#6 sev=low blast=leaf effort=S verdict=actionable - Hex digests are built with `format!("{b:02x}")` per byte, allocating a fresh String per byte (32+ allocations per digest) in `Sha256::of` and `generation_id` - fix: write into one preallocated `String::with_capacity(64)` via `write!`/`fmt::Write`, or share a hex helper - [packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628] - evidence: static (unmeasured); seed `format!\(` = 116 hits, of which these two are per-byte loops (cold paths: per batch apply / per generation build). - -## conc -- clean: seeds ran:: 0/1/0/0. The single `Mutex<` hit is the test-only `FakeCgroupBackend.inner` (cgroup.rs:796); no threads, no atomics/Ordering, no thread_local, no manual Send/Sync claims in the crate (the fake's `Mutex` is exercised from single-thread tests and needs no ordering story). - -## async -- clean: seeds ran:: 318/1/0/18. The crate's async surface (hardlink_farm + bin)drove entirely by `tokio::fs` I/O with the runtime created once at the binary entry (`#[tokio::main(flavor = "current_thread")]`); the single spawn-family hit is a policy comment (hardlink_farm.rs:1554, "async-purity policy bans spawn_blocking"), zero `tokio::sync::*`, zero guards held across awaits; sync helpers (`current_boot_id`, `process_identity`, `safe_usb_block_candidates`, `mirror_metadata`'s chown(syscall) carry per-site `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` sanctions tracked by the blocking census (baseline lists all d2b-host blocking APIs at 0) - policy-confirmed, not re-flagged. - - - -## unsafe -- clean: seeds ran: 0/0/9/5. Zero actual `unsafe` blocks/fns/impls in the crate (crate-root `#![forbid(unsafe_code)]` at lib.rs:20); alla 9 `from_raw` hits are safe constructors (`rustix::fs::FileType::from_raw_mode`, `Uid::from_raw`, `Gid::from_raw`, `std::io::Error::from_raw_os_error`), the 5 `unsafe_code` hits are the forbid declaration and its rationale comments; the manifest-level `forbid` explains why `nix`'s safe fchown wrapper is used over rustix's unsafe one (Cargo.toml comment). - -## ffi -- clean: seeds ran: 0/1/1/0. The `repr(C)` hit is the deliberate `BpfInstruction` layout matching `libc::sock_filter` for the broker's quarantined sys.rs (card false positive); the `catch_unwind` hit is a test-only `debug_assert!` exercise (cgroup.rs:1137); no extern "C", no no_mangle, no CStr/CString/c_char cross any boundary in this crate. - - - -## macro -- clean: seeds ran: 1/0/0/0. The single `macro_rules!` (bridge_port.rs:133 `check!`) is a local impl-per-field generator over 5 bool fields of a Copy wire struct with the narrowest fragment specifier (`$field:ident`), defined and consumed inside one function - a genuine last-resort use, not a finding. - - - -## test -- d2b-host#7 sev=medium blast=family effort=M verdict=actionable - `NftBatch::parse` (the ~200-line nft script dialect parser with 15+ error paths) has no tests: zero calls to `parse` exist in the crate's test modules, while the broker feeds it live script bodies on its nft apply path - fix: table-driven parse tests (valid script, malformed header, foreign family/table, missing hook priority, unterminated chain, trailing content) asserting `ParseNftScriptError` variants - [packages/d2b-host/src/nftables.rs:245] - evidence: seeds `#\[test\]|#\[tokio::test\]` = 163, `assert_eq!\(|assert_ne!\(|assert!\(` = 387 hits over src+tests; census: `NftBatch::parse` over `packages/` = 5 hits (1 definition, 4 broker call sites at ops/nft.rs:302,356 and runtime.rs:8598,10007, 0 tests). -- d2b-host#8 sev=low blast=leaf effort=S verdict=actionable - `package_digest_includes_bytes_read_through_store_symlinks` writes fixtures to a CWD-relative `target/` directory (the cargo build dir), polluting build artifacts and failing under a read-only target; every sibling test uses `tempdir()` - fix: use `tempfile::tempdir()` like the sibling tests - [packages/d2b-host/src/bin/d2b-activation-helper.rs:792] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 387 hits; the anchor is the only test in the crate using a CWD-relative path (`PathBuf::from("target")`, bin/d2b-activation-helper.rs:792-793) instead of a tempdir. - - - -## Coverage -- idiom: clean (seeds ran: 1/0/18) -- own: clean (seeds ran: 66/335/3) -- type: 1 finding(s) -- api: 1 finding(s) -- err: clean (seeds ran: 290/23/15/14) -- serde: 1 finding(s) -- obs: clean (seeds ran: 28/0/0/0) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 0/1/0/0) -- async: clean (seeds ran: 318/1/0/18) -- unsafe: clean (seeds ran: 0/0/9/5) -- ffi: clean (seeds ran: 0/1/1/0) -- macro: clean (seeds ran: 1/0/0/0) -- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md deleted file mode 100644 index 1066c2762..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p1.md +++ /dev/null @@ -1,71 +0,0 @@ -# d2b-p1 - d2b - part 1/3 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6520 (excl. src/generated/**) | modules: context, activation, zone_support_bundle, share, guest, zone, host_generation, runtime, main -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/context.rs, src/activation.rs, src/zone_support_bundle.rs, src/share.rs, src/guest.rs, src/zone.rs, src/host_generation.rs, src/runtime.rs, src/main.rs - -## idiom -- clean: seeds ran: 0 index loops / 0 hand-written impls / 4 statement-accumulations; the 4 hits (context.rs:2708, context.rs:2727, context.rs:2738, activation.rs:246) are bounded reads and a byte-budget string fold where an iterator pipeline would obscure the early-exit condition; no derive-replaceable impls and no index loops exist. - -## own -- clean: seeds ran: 77 clones / 121 to_owned-to_vec-to_string / 1 Rc-RefCell-Arc-Mutex / 0 Cow; every clone inspected is explainable (owned constructor parameters such as CliZoneConnector::new and ProcessAttachTarget::shell_session, post-move reuse of resource_ref and guest_ref, serde_json::from_value ownership, clap arg fields); the single RefCell is the cfg(test) TEST_STAGING_BASE thread_local (activation.rs:114-117), a test fixture. - -## type -- d2b-p1#1 sev=low blast=leaf effort=M verdict=actionable - ZoneContext stores the validated Zone name as a bare String and re-validates it at every construction site instead of carrying the invariant in the already-imported ZoneId type - fix: store `ZoneId` in ZoneContext (field at context.rs:713), build `zone_ref()` and `zone_name()` from it, delete `validate_zone_name` (context.rs:2751) and the duplicated double validation in `discover` (context.rs:752 and context.rs:763), and replace the `expect` re-parses in `from_socket` (context.rs:801-803) with direct construction - [context.rs:713, context.rs:2751, context.rs:801] - evidence: seeds `fn validate_\w+|fn check_\w+` = 5 hits, `is_\w+: bool|\w+_flag: bool` = 2, `(mode|kind|state): String` = 3; the other 4 validate hits and all bool/String hits are wire-mirror types (ManifestVm.is_net_vm, ManifestRuntime.kind, BridgeHealthFixture.state, DaemonErrorEnvelope.kind) or boundary admission checks on untrusted daemon JSON (validate_response, validate_share_spec, validate_share_type_filter, validate_operation), which the card exempts. - -## api -- d2b-p1#2 sev=medium blast=leaf effort=S verdict=actionable - `pub mod host_generation` (lib.rs:25) is the crate's only public module and its three exported items have zero consumers anywhere in the workspace - fix: make it `mod host_generation` (private) until a caller exists, or wire `build_request` into the host-generation CLI flow that currently does not call it - [packages/d2b/src/host_generation.rs:7, packages/d2b/src/host_generation.rs:17, packages/d2b/src/host_generation.rs:36] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 14 hits; census: `HostGenerationRequest|build_request` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 1 hit (the defining file itself); the error-code strings host-generation-target-invalid and host-generation-artifact-invalid appear in no docs/reference/error-codes.md or cli-contract.md entry, so no wire pin exists. -- d2b-p1#3 sev=low blast=leaf effort=S verdict=actionable - zone_support_bundle.rs declares 9 `pub` items (6 structs, 3 consts, build_bundle, render_ndjson) inside a private module, a pub-in-private surface no external caller can reach - fix: reduce to `pub(crate)` or plain items, keeping only what the in-file tests and `run` need - [zone_support_bundle.rs:19, zone_support_bundle.rs:28, zone_support_bundle.rs:99, zone_support_bundle.rs:323, zone_support_bundle.rs:395] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 14 hits; census: `build_bundle|render_ndjson|ResourceStatusSnapshot` over packages/ and tests/ = 0 hits outside the defining file; the d2b integration test drives the CLI binary (tests/zone_support_bundle_contract.rs), not the library surface. - -## err -- clean: seeds ran: 84 unwrap-expect / 13 let-underscore-or-ok / 10 panic-unreachable-todo-unimplemented / 2 error enums; the only non-test unwrap/expect sites are invariant panics with named reasons (context.rs:529 fixed-width prefix conversion after an explicit length check, context.rs:801-803 validated-name construction, runtime.rs:28 startup precondition) which the card exempts; every `let _ =` site is deliberate best-effort teardown (socket shutdown, stream cancel/close on signal paths, temp-file cleanup); the 3 unreachable! sites (share.rs:203, share.rs:233, guest.rs:277) sit on closed local constructions; HostGenerationRequestError is a closed two-variant enum with Display, fine for a CLI-internal type. - -## serde -- clean: seeds ran: 16 derives / 18 serde attributes / 0 hand-written Deserialize / 52 serde_json calls; all types are wire mirrors with deliberate rename_all camelCase, deny_unknown_fields on operator-facing fixtures, and `default` on support-bundle projections; the flatten on ManifestDocument.entries (context.rs:137) is a deliberate schema mirror consuming unknown top-level keys; no try_from gap, no untagged enum, no hand-written admission gate. - -## obs -- clean: seeds ran: 2 println-eprintln / 0 interpolated event macros / 0 instrument / 7 tracing-log; the 2 eprintln sites (activation.rs:234, activation.rs:258) are CLI user-facing pending-config notes, product output the card exempts; the 7 tracing/log hits are substring false positives (`surface_catalog::` contains "log::") in guest.rs and host_generation.rs; the crate emits no telemetry from this partition. - -## docs -- d2b-p1#4 sev=low blast=leaf effort=S verdict=actionable - two Result-returning public functions lack the canonical `# Errors` section naming their failure conditions - fix: add `# Errors` to `build_request` (TargetInvalid vs ArtifactInvalid) at host_generation.rs:17 and to `render_ndjson` (serialization failure only) at zone_support_bundle.rs:395 - [host_generation.rs:17, zone_support_bundle.rs:395] - evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 14, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 106; all 14 public items carry first-sentence doc comments and all modules carry `//!` docs, so the only gap is the missing Errors sections on the 2 Result-returning pub fns. - -## perf -- d2b-p1#5 sev=medium blast=leaf effort=M verdict=actionable - every received frame allocates and zeroes a fresh 1 MiB buffer and then copies the payload again, on the interactive shell path where the daemon answers each 50 ms poll round trip - fix: keep a reusable receive buffer (e.g. a Vec field on CliSocket reused across read_frame calls, or a thread-local scratch) so the zeroed 1 MiB allocation happens once, and return the truncated buffer instead of `frame[FRAME_PREFIX_BYTES..].to_vec()` - [context.rs:570, context.rs:538] - evidence: static (unmeasured); seeds `format!\(` = 67, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 11, `\.to_string\(\)` = 12; the remaining format!/Vec::new hits are cold error paths, bounded stdin reads, and output rendering, which the card exempts. - -## conc -- clean: seeds ran: 6 std-thread / 1 Mutex / 29 atomics / 1 thread_local; the atomics in CliAttachStream and call_options use paired Acquire/Release/AcqRel handoffs and a Relaxed counter, all correct for their shape; the Mutex is the cfg(test) MockClient recorder and the thread_local is the cfg(test) staging override; no manual Send/Sync impls exist. - -## async -- clean: seeds ran: 67 async fn-await / 0 spawn / 1 tokio sync / 0 tokio main; the transport is readiness-driven throughout (AsyncFd, non-blocking seqpacket syscalls, bounded retry loops); the two tokio::sync::Mutex guards (round_trip_guard, stdin_offset) legitimately span awaits; the Drop-time block_on in CliAttachStream::drop is guarded by inside_runtime(); the select! loop documents its cancellation safety; all disallowed-method sites carry the sanctioned "CLI-only path" reason. - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; seed 4 alone (workspace `unsafe_code = "forbid"` inherited via `[lints] workspace = true`, Cargo.toml:8-9) does not make the lens applicable. - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no foreign-caller boundary exists in this partition. - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macro definitions in this partition. - -## test -- clean: seeds ran: 32 test attributes / 119 assertions / 0 proptest-insta-rstest / 0 ignore; 32 tests across the six in-file test modules (context.rs, activation.rs, zone_support_bundle.rs, share.rs, guest.rs, zone.rs) all assert observable behavior (frame formats, bounded deadlines, redaction, envelope fields) with human-written expectations; no test is structurally unable to fail; the crate-level tests/ directory is outside this partition and was not audited here. - -## Coverage -- idiom: clean (seeds ran: 0/0/4) -- own: clean (seeds ran: 77/121/1/0) -- type: 1 finding(s) -- api: 2 finding(s) -- err: clean (seeds ran: 84/13/10/2) -- serde: clean (seeds ran: 16/18/0/52) -- obs: clean (seeds ran: 2/0/0/7) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 6/1/29/1) -- async: clean (seeds ran: 67/0/1/0) -- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe blocks, fns, or SAFETY comments; workspace forbid alone does not apply) -- ffi: N/A (seeds: 0/0/0/0 all zero; no extern boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) -- test: clean (seeds ran: 32/119/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md deleted file mode 100644 index 10500510c..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p2.md +++ /dev/null @@ -1,82 +0,0 @@ -# d2b-p2 - d2b - part 2/3 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6600 (excl. src/generated/**) | modules: doctor.rs, zone_audit.rs, resource.rs, host_validate.rs, shell.rs, host.rs, lib.rs, complete.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: d2b-p2 per U1 (f): src/doctor.rs, src/zone_audit.rs, src/resource.rs, src/host_validate.rs, src/shell.rs, src/host.rs, src/lib.rs, src/complete.rs - -## idiom -- d2b-p2#1 sev=low blast=leaf effort=S verdict=actionable - the pidfd-table inspection detail string is re-derived by an identical 3-line match at five check sites - fix: add `PidfdEntries::state_detail() -> String` next to `load_pidfd_entries` and call it from `check_otel_host_bridge_runner`, `check_usbipd_runners`, `check_seccomp_bpf_loaded`, `check_pre_ns_posture_with_reader`, `check_broker_reap_health` - [packages/d2b/src/doctor.rs:529, packages/d2b/src/doctor.rs:579, packages/d2b/src/doctor.rs:1230, packages/d2b/src/doctor.rs:1343, packages/d2b/src/doctor.rs:1449] - evidence: seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) = 3 hits, all deliberate text building; the repeated `match &entries.state { PidfdState::ParseError(d) => d.clone(), _ => "daemon state dir unreadable".to_owned() }` block read at 5 sites -- d2b-p2#2 sev=low blast=leaf effort=M verdict=actionable - `typed()` hand-rolls eight field-by-field typed-args to generic-args conversions with ~20 clones instead of `From` impls - fix: implement `From for GenericListArgs` (and the other six pairs) consuming the typed args, and change `typed()`/`typed_noun()` to take `TypedResourceArgs` by value so the conversions stop cloning - [packages/d2b/src/resource.rs:525, packages/d2b/src/resource.rs:546, packages/d2b/src/resource.rs:555, packages/d2b/src/resource.rs:565, packages/d2b/src/resource.rs:592, packages/d2b/src/resource.rs:608, packages/d2b/src/resource.rs:617] - evidence: own seed 1 (`\.clone\(\)`) = 52 hits, ~20 of them inside `typed()` at resource.rs:533-621; the generic structs (GenericListArgs etc.) are the same fields as the typed structs, so `From` applies -- d2b-p2#3 sev=low blast=leaf effort=S verdict=actionable - `valid_digest` and `valid_hash` in zone_audit.rs are byte-identical functions - fix: keep one (e.g. `valid_digest`) and delete the other, updating its three call sites - [packages/d2b/src/zone_audit.rs:805, packages/d2b/src/zone_audit.rs:838] - evidence: reading both bodies: identical `strip_prefix("sha256:")` + 64-hex check; `valid_hash` is called at zone_audit.rs:376 and 410, `valid_digest` at 670, 806, 816, 822 -- d2b-p2#4 sev=low blast=leaf effort=M verdict=actionable - the v1 record path in `validate_record` duplicates the ~22-line chain-verification tail of the nested `validate_v2_record` (hash extraction, expected-previous check, canonical json! build, digest compare) - fix: extract `verify_chain(object, fields_key, expected_previous) -> Result` and call it from both the v1 path and `validate_v2_record` - [packages/d2b/src/zone_audit.rs:349, packages/d2b/src/zone_audit.rs:395] - evidence: reading zone_audit.rs:349-429: the nested fn body and the outer v1 tail are identical line-for-line except the envelope/fields validation that precedes them -- d2b-p2#5 sev=low blast=leaf effort=S verdict=actionable - `validate_public_fields` and `validate_v2_fields` have identical bodies differing only in the per-field validator they call - fix: merge into one `validate_fields(class, fields, validate_field: fn(&str, &str, &Value) -> bool)` and pass `validate_public_field`/`validate_v2_field` - [packages/d2b/src/zone_audit.rs:591, packages/d2b/src/zone_audit.rs:607] - evidence: reading both bodies: same expected-count, contains-key, posture-field, key-subset, and per-field iteration logic; only the validator reference differs - -## own -- d2b-p2#6 sev=low blast=leaf effort=S verdict=actionable - three `.clone()` calls feed `json!` operands, which serde_json serializes by reference (`to_value(&expr)`), so the clones are dropped immediately - fix: pass `parsed.schema_version`, `issue_kinds`, and `parsed.issues` to `json!` without `.clone()` - [packages/d2b/src/doctor.rs:1062, packages/d2b/src/doctor.rs:1069, packages/d2b/src/doctor.rs:1070] - evidence: seed 1 (`\.clone\(\)`) = 52 hits; the three sites sit inside one `json!({...})` literal at doctor.rs:1061-1071 where the macro borrows each operand, making each clone redundant -- clean: seeds 1/2/3 = 52/116/2 hits; the remaining clones are explainable (report rows owning their detail strings, typed-args to generic-request struct conversion at dispatch, `Option` unwrap_or_else ownership, test fixtures); the two `RefCell`/`Mutex` hits are the `#[cfg(test)]` stdout-capture statics in lib.rs:74-82 - -## type -- d2b-p2#7 sev=low blast=leaf effort=M verdict=actionable - the "exactly one of --dry-run / --apply" invariant lives as a bool pair in six clap arg structs and is hand-rechecked at four call sites with diverging exit codes - fix: introduce `enum MutationMode { DryRun, Apply }` with a single `MutationMode::from_flags(dry_run, apply) -> Result` constructor and a shared missing-flag error, then use it in `require_mutation_flags`, `mutation`, `reconcile`, and `validate` - [packages/d2b/src/resource.rs:880, packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332] - evidence: seed 2 (`is_\w+: bool|\w+_flag: bool`) = 2 hits (AuditStreamValidator state bools, judged fine); the dry_run/apply pairs were found by reading: DeviceUsbAttachArgs, DeviceUsbDetachArgs, DeviceSecurityKeyCancelArgs (resource.rs), HostMutationArgs, HostValidateArgs, HostReconcileArgs (host.rs) - -## api -- d2b-p2#8 sev=low blast=leaf effort=S verdict=actionable - the d2b lib exports a wide pub surface while the only external consumer (xtask) uses just `d2b::cli_command()`; `pub mod host_generation` and `pub const EXIT_API_TIMEOUT` have zero consumers anywhere - fix: narrow `doctor`/`host_validate` pub items and `EXIT_API_TIMEOUT` to `pub(crate)`, make `host_generation` a private `mod`, keeping only `cli_command`/`run` public - [packages/d2b/src/lib.rs:25, packages/d2b/src/lib.rs:41, packages/d2b/src/doctor.rs:62, packages/d2b/src/host_validate.rs:55] - evidence: census: `use d2b::` over packages/, nixos-modules/, tests/, labs/ = 5 hits, all `d2b::cli_command()` in packages/xtask/src/main.rs:841-922; `host_generation` over packages/d2b = 1 hit (the lib.rs:25 declaration itself); `EXIT_API_TIMEOUT` over packages/d2b = 1 hit (the lib.rs:41 declaration); `#![allow(dead_code)]` at lib.rs:1 hides the zero-consumer items from the compiler - -## err -- d2b-p2#9 sev=medium blast=leaf effort=S verdict=actionable - `CliFailure` flattens the error class into the message (`format!("{error_class}: {message}")`), so callers recover the class by string-matching the message prefix - fix: add a structured `code: &'static str` field to `CliFailure` (lib.rs:44-52), populate it in `ZoneContext::failure` (context.rs:1181-1189), and match on it in `can_fallback_to_local_state` and `reconcile_deadline` instead of `message.split(':').next()` / `strip_prefix("ref-invalid: ")` - [packages/d2b/src/host.rs:200, packages/d2b/src/resource.rs:916, packages/d2b/src/lib.rs:44] - evidence: seed 1 (`\.unwrap\(\)|\.expect\(`) = 51 hits, all in `#[cfg(test)]` or after an adjacent compiler-invisible check (zone_audit.rs:99); the string-match recovery was read at host.rs:200-204 and resource.rs:916-918 -- d2b-p2#10 sev=medium blast=leaf effort=S verdict=needs-contract - `d2b host prepare`/`destroy` without flags exit 2 with kind `ref-invalid`, diverging from the documented `--apply-or-dry-run-required` exit-78 envelope; `host reconcile` exits 78 but with the wrong kind - fix: route `mutation()` and `reconcile()` through `missing_mutation_flag_envelope` (dispatch.rs:369-375) like `validate()` already does, or correct docs/reference/error-codes.md:156 - [packages/d2b/src/host.rs:274, packages/d2b/src/host.rs:303, packages/d2b/src/host.rs:332, docs/reference/error-codes.md:156] - evidence: seed 3 (`\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`) = 1 hit (test-only); error-codes.md:156 pins `--apply-or-dry-run-required` exit 78 for host prepare/destroy/install flags while host.rs:274-278 emits `ref-invalid` exit 2; `missing_mutation_flag_envelope` (dispatch.rs:369) already emits the documented shape and `validate()` uses it - -## serde -- clean: seeds 1-2/3/4 = 42/0/26 hits; all Deserialize derives are loose forward-compatible shapes for daemon-persisted state files (`serde(default)` on every field, `#[allow(dead_code)]` on unused fields), DoctorStatus/WaveStatus serialize kebab-case for the CLI wire, and no hand-written Deserialize exists; `deny_unknown_fields` absence is deliberate for service-consumed messages - -## obs -- N/A: seeds 1/2/3/4 = 0/0/0/19 all effectively zero (the 19 seed-4 hits are the `surface_catalog::` substring false positive, verified: 19 of 19 match `surface_catalog`); packages/d2b/Cargo.toml declares no tracing/log dependency, so the lens's N/A criteria hold - -## docs -- d2b-p2#11 sev=low blast=leaf effort=S verdict=actionable - several pub items carry no doc comment and lib.rs has no crate-level `//!` doc - fix: add one-line first-sentence docs to `DoctorReport`, `run_doctor`, `render_summary`, `render_human` (doctor.rs), `ValidateReport`, `ValidateMode`, `exit_code` (host_validate.rs), `cli_command`, `run` (lib.rs), and a `//!` crate doc in lib.rs - [packages/d2b/src/doctor.rs:91, packages/d2b/src/doctor.rs:163, packages/d2b/src/host_validate.rs:229, packages/d2b/src/host_validate.rs:237, packages/d2b/src/host_validate.rs:625, packages/d2b/src/lib.rs:215, packages/d2b/src/lib.rs:221] - evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 30 hits, seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits, seed 3 (`-> Result<`) = 47 hits with no `# Errors` sections anywhere; the nine undocumented items were read directly - -## perf -- clean: seeds 1/2/3 = 117/23/13 hits; every `format!` is in a cold CLI error, report-rendering, or one-shot diagnostic path (doctor probes, evidence payloads, completion scripts), the `Vec::new()` hits are empty-case returns or test capture buffers, and `.to_string()` sits at wire-rendering boundaries; no hot loop or per-item allocation exists in this CLI partition, so all perf observations are static (unmeasured) - -## conc -- clean: seeds 1/2/3/4 = 2/2/0/1 hits, every one `#[cfg(test)]` (doctor.rs:2433 test sleep, shell.rs:343 test Mutex, lib.rs:74-82 test stdout-capture thread_local + Mutex); production code in the partition uses no threads, locks, atomics, or manual Send/Sync impls - -## async -- N/A: seeds 1-4 = 0 hits combined; no `async fn`, `.await`, tokio spawn, sync primitives, or `#[tokio::]` attribute in the partition (the async transport lives in context.rs/exec_client.rs, other parts); the shell watch loop is deliberately synchronous CLI polling with `std::thread::sleep` under a deadline (shell.rs:265) - -## unsafe -- N/A: seeds 1/2/3 = 0/0/0 hits; no unsafe blocks, fns, impls, SAFETY comments, or transmute/raw-pointer patterns in the partition; the crate inherits the workspace `unsafe_code = "forbid"` lint table - -## ffi -- N/A: seeds 1-4 = 0 hits combined; no extern "C", no_mangle, catch_unwind, repr(C)/repr(transparent), or CStr/CString usage in the partition - -## macro -- N/A: seeds 1-4 = 0 hits combined; no macro_rules!, proc-macro, syn/quote, `$crate`, or to_compile_error usage in the partition - -## test -- clean: seeds 1/3/4 = 153/0/0 hits (62 unit tests in the partition's src files, 91 in tests/); the suite is behavioral and independently grounded: FIPS 180-4 SHA-256 vectors (host_validate.rs:657-672), wave-catalog parity vs nixos-modules/options-daemon.nix (host_validate.rs:687, tests/host_validate_verb.rs:209), golden CLI output pins, redaction assertions (zone_audit.rs:973-995), and fail-closed envelope checks; no proptest/insta/rstest, no `#[ignore]`; the D2B_FIXTURES-gated tests in tests/cli_json_contract.rs print an explicit SKIP line and are documented gating, not silent passes - -## Coverage -- idiom: 5 finding(s) -- own: 1 finding(s) -- type: 1 finding(s) -- api: 1 finding(s) -- err: 2 finding(s) -- serde: clean (seeds ran: 42/0/26; loose daemon-state shapes deliberate, no hand-written Deserialize) -- obs: N/A (seeds: 0/0/0/19 all zero or surface_catalog substring false positives; no tracing/log dependency in Cargo.toml) -- docs: 1 finding(s) -- perf: clean (seeds ran: 117/23/13; all cold CLI paths, static unmeasured) -- conc: clean (seeds ran: 2/2/0/1; all cfg(test) hits) -- async: N/A (seeds: 0/0/0/0 all zero; no async code in the partition) -- unsafe: N/A (seeds: 0/0/0 all zero; workspace forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 153/0/0; behavioral, golden-pinned, parity-checked suite) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md deleted file mode 100644 index 71c2f71f3..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-p3.md +++ /dev/null @@ -1,78 +0,0 @@ -# d2b-p3 - d2b - part 3/3 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6525 (excl. src/generated/**) | modules: exec_client.rs, dispatch.rs, debug.rs, zone_doctor.rs, exec.rs, endpoint.rs, provider.rs, terminal_client.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: d2b-p3 = src/exec_client.rs, src/dispatch.rs, src/debug.rs, src/zone_doctor.rs, src/exec.rs, src/endpoint.rs, src/provider.rs, src/terminal_client.rs per U1 (f); the test lens additionally reads tests/** - -## idiom -- d2b-p3#1 sev=low blast=leaf effort=S verdict=actionable - `summarize` hand-builds a zeroed `DoctorSummary` although the type derives `Default` - fix: `let mut summary = DoctorSummary::default();` - [packages/d2b/src/zone_doctor.rs:598-601] - evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 1 hit; `DoctorSummary` derives `Default` at zone_doctor.rs:122-123 -- d2b-p3#2 sev=medium blast=leaf effort=M verdict=actionable - `all_known_subcommands` hand-maintains a 22-entry command-name list of which 13 (launch, realm list/inspect/enter/run, up, down, restart, boot, build, switch, test, rollback, generations, usb, console) are retired v2 verbs the ModernCli parser rejects, so `d2b auth status` reports them as known-but-denied commands - fix: derive the list from `ModernCli::command().get_subcommands()` minus `PROJECTION_COMMANDS` the way `BUILTIN_COMMANDS` does, or drop the retired entries; update the pinned expectation in tests/auth_status_contract.rs - [packages/d2b/src/dispatch.rs:688-706, packages/d2b/src/dispatch.rs:1169-1175] - evidence: idiom seeds 1/2/3 = 1/1/6; census: the `ModernCommand` variants dispatched at dispatch.rs:794-929 contain none of launch/realm/up/down/restart/boot/build/switch/test/rollback/generations/usb/console, and the parser test `modern_parser_has_no_v2_alias_or_realm_dispatch` asserts those parse as errors; tests/auth_status_contract.rs pins the current allowed list, so the fix updates that test - -## own -- d2b-p3#3 sev=low blast=leaf effort=S verdict=actionable - redundant clones of paging values that are dead after the call: `cursor.clone()` before `cursor` is overwritten by `next_cursor`, `page_token.clone()` before reassignment from `nextCursor`, and `reference.to_owned()` on a fresh `format!` String - fix: move `cursor` and `page_token` into the calls (reassign afterwards) and move `reference` into the struct literal - [packages/d2b/src/dispatch.rs:548, packages/d2b/src/debug.rs:472, packages/d2b/src/debug.rs:418] - evidence: own seeds 1/2/3/4 = 19/109/3/0; each cited value is unused after the call (loop bodies reassign from the response); `AuditExportCursor` is a non-Copy struct (d2b-contracts/src/audit_wire.rs:8-15) -- d2b-p3#4 sev=low blast=leaf effort=S verdict=actionable - `modern_run` clones the entire argv (`raw_args.clone()`) for `try_parse_from` although `raw_args` is consumed by value from the only caller and never used again - fix: `ModernCli::try_parse_from(raw_args)` - [packages/d2b/src/dispatch.rs:977] - evidence: own seed 1 = 19 hits; census: `dispatch::modern_run(raw_args)` at packages/d2b/src/lib.rs:236 passes ownership and no later use of `raw_args` exists in `modern_run` -- d2b-p3#5 sev=low blast=leaf effort=S verdict=actionable - `host_error_envelope` takes seven `&str` parameters and `.to_owned()`s each into the envelope, while callers pass `&format!(...)` results, allocating twice per field - fix: take `impl Into` parameters so `format!` results move in directly - [packages/d2b/src/dispatch.rs:296-313, packages/d2b/src/dispatch.rs:347, packages/d2b/src/dispatch.rs:359, packages/d2b/src/dispatch.rs:371-377] - evidence: own seed 2 = 109 hits; callers at dispatch.rs:346-378 (and host.rs:144,367) pass `&format!(...)` into the `&str` parameters - -## type -- d2b-p3#6 sev=low blast=leaf effort=S verdict=actionable - closed CLI vocabularies carried as `String` and validated at every call site: `ExecKillArgs.signal` checked by `matches!` in `kill`, and `endpoint_class: Option` checked by `validate_endpoint_class` in `list` and `watch` - fix: clap `ValueEnum` on the args fields so an invalid value is a parse error and the runtime checks disappear - [packages/d2b/src/exec.rs:90, packages/d2b/src/exec.rs:345, packages/d2b/src/endpoint.rs:34, packages/d2b/src/endpoint.rs:42, packages/d2b/src/endpoint.rs:203-216] - evidence: type seeds 1/2/3 = 6/0/3; both vocabularies are closed five-value sets validated only at CLI entry; the wire value stays a string so no contract change - -## api -- clean: seeds 72/0/0 run; every `pub` item in the part sits inside a private module (`mod exec_client;` etc., lib.rs:13-36), so the items are unreachable crate-external surface; the d2b lib's only outside consumer is xtask via `d2b::cli_command()` (census: 6 hits in packages/xtask/src/main.rs); no `Arc`/`Rc`/`Box`/`RefCell` in any public signature (`FdStateGuard`'s `Box` is a private field) - -## err -- clean: seeds 33/10/5/0 run; all 33 `unwrap`/`expect` and all 5 `panic!` sit in `#[cfg(test)]`; the 10 `let _ =` sites are deliberate best-effort cleanup or discarding an `Ok` value (`round_trip(&close_op(...))?`, `fcntl_setfl`, `writeln!`, `error.print()`); `ExecClientError` is a documented struct (not an enum) carrying the redaction-safe wire `kind` slug, and `exit_for_kind` owns the exit-code mapping with a tested table - -## serde -- clean: seeds 13/11/0/16 run; `HostErrorEnvelope` and `AuditResponseFrame` use `rename_all = "camelCase"` plus `deny_unknown_fields`; zone_doctor projections use type-level `#[serde(default)]`; no hand-written `Deserialize` impls; wire decode failures map to typed `ExecClientError` instead of stringified messages - -## obs -- N/A: seeds 0/0/0/0 all zero (the 5 `tracing::|log::` grep hits are `surface_catalog::` substring false positives); d2b has no tracing/log dependency (packages/d2b/Cargo.toml), and CLI output goes through the `print_stdout`/`print_stderr` product-output helpers, not telemetry - -## docs -- d2b-p3#7 sev=low blast=leaf effort=S verdict=actionable - six `pub fn` response expecters (`expect_start`, `expect_detached_create/list/logs/status/kill`) carry no doc comment in an otherwise fully documented module - fix: one-line docs stating the expected `ExecOpResponse` variant and the protocol error on mismatch - [packages/d2b/src/exec_client.rs:497, packages/d2b/src/exec_client.rs:507, packages/d2b/src/exec_client.rs:519, packages/d2b/src/exec_client.rs:531, packages/d2b/src/exec_client.rs:543, packages/d2b/src/exec_client.rs:555] - evidence: docs seeds 1/2/3 = 72/0/66; the six fns are the only undocumented `pub` items in the module (bin crate, so this is a proposal, never the `missing_docs` lint) - -## perf -- clean: seeds 54/16/109 run; all `format!` sites are error paths, one-shot CLI rendering, or test fixtures (cold per the card); the FSM's per-op `session.to_owned()` is one small String per socket round trip, not a hot-loop allocation; `pending_stdin` and the capture buffers grow by push with natural capacity reuse - -## conc -- clean: seeds 1/1/0/0 run; one dedicated sigwait thread (`d2b-exec-sig`) is the right channel model for signal forwarding; the single `Arc>>` has genuine two owners (sigwait thread + FSM) with a briefly held guard; the `tokio::sync::Notify` waiter documents its permit semantics; no atomics and no unsafe `Send`/`Sync` impls - -## async -- clean: seeds 7/0/2/0 run; `audit_via_socket` is a bounded-budget async fn awaiting only socket send/recv; `InstalledSignals::waiter` uses the documented Notify permit pattern; `block_on` appears only at the CLI entry (`try_audit_via_socket`, dispatch.rs:514-517), a sanctioned process entry point; no guard is held across an `.await` - -## unsafe -- N/A: seeds 0/0/3/0 all zero (the 3 `from_raw` hits are `io::Error::from_raw_os_error`, std functions, not unsafe blocks); no `unsafe` block/fn/impl and no `unsafe_code` attribute in the part; the crate inherits `unsafe_code = "forbid"` via `[lints] workspace = true` (packages/d2b/Cargo.toml:8-9) - -## ffi -- N/A: seeds 0/0/0/0 all zero - -## macro -- N/A: seeds 0/0/0/0 all zero - -## test -- d2b-p3#8 sev=medium blast=leaf effort=S verdict=actionable - the `d2b exec wait` guest-exit-code passthrough (`guestExitCode`/`exitCode` lookup, 0-255 filter, `unwrap_or(0)`) has no unit or integration test, so a regression in the CLI exit-code contract would pass silently - fix: extract the extraction into a testable helper or add a mock-daemon integration test asserting the passthrough and the out-of-range fallback - [packages/d2b/src/exec.rs:227-239] - evidence: test seeds over src+tests = 145/571/0/0; census: `exec.*wait|guestExitCode` over packages/d2b/tests = 0 hits; the exec.rs unit tests cover only attach -- d2b-p3#9 sev=low blast=leaf effort=S verdict=actionable - `validate_env` (KEY=VALUE shape, key length and charset bounds) has no test, unlike the sibling `validate_exec_ref` behavior that the attach tests cover - fix: table-driven unit test with human-written expected outcomes (valid, empty key, over-64 key, non-alnum key, missing `=`) - [packages/d2b/src/exec.rs:383-397] - evidence: test seeds over src+tests = 145/571/0/0; census: `validate_env` appears only at exec.rs:125 (one call site, no test) - -## Coverage -- idiom: 2 finding(s) -- own: 3 finding(s) -- type: 1 finding(s) -- api: clean (seeds ran: 72/0/0) -- err: clean (seeds ran: 33/10/5/0) -- serde: clean (seeds ran: 13/11/0/16) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: 1 finding(s) -- perf: clean (seeds ran: 54/16/109) -- conc: clean (seeds ran: 1/1/0/0) -- async: clean (seeds ran: 7/0/2/0) -- unsafe: N/A (seeds: 0/0/3/0 all zero; `from_raw` hits are `from_raw_os_error` false positives) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md deleted file mode 100644 index ac45aeae6..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-process-conformance.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-process-conformance - d2b-process-conformance -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4195 (excl. src/generated/**, none present; no tests/ dir exists) | modules: whole crate (13 src files: error, identity, launch_identity, lib, port, process_provider, provider, sandbox, status, suite, terminal, testing, ticket) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (1 part) - -## idiom -- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0; applicable (crate declares many `fn` bodies) but all three seeds are zero - no index loops, no hand-written derives (the hand-written `Debug`/`Serialize` impls redact secret bytes and render wire hex, both deliberate), no statement-style accumulation. - -## own -- d2b-process-conformance#1 sev=low blast=leaf effort=S verdict=actionable - LaunchTicket's consuming `with_*` builders clone the whole `launch_identity` (two `String` fields plus refs) before delegating to a by-value `LaunchIdentity::with_*`, although moving the field out of the consumed ticket and writing the result back does the same job without the copy - fix: `self.launch_identity = self.launch_identity.with_owner(owner_ref.clone())?;` (same shape at the other three sites: with_owner_uid, with_owner_ref, with_target_ref) - [packages/d2b-process-conformance/src/ticket.rs:557, packages/d2b-process-conformance/src/ticket.rs:610, packages/d2b-process-conformance/src/ticket.rs:631, packages/d2b-process-conformance/src/ticket.rs:664] - evidence: seed `\.clone\(\)` = 45 hits; the 4 sites cited are the only non-fixture `launch_identity.clone()` builder calls (remaining hits are test fixtures or genuine multi-use copies such as `owner_ref.clone()` stored alongside the moved value) -- clean: seeds `\.clone\(\)`=45, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=13, `Rc<|RefCell<|Arc`), keeping the two accessors; the XOR check and the per-mutator guards (ticket.rs:546-552) become unrepresentable - [packages/d2b-process-conformance/src/ticket.rs:387, packages/d2b-process-conformance/src/ticket.rs:395, packages/d2b-process-conformance/src/ticket.rs:768] - evidence: seed `fn validate_\w+|fn check_\w+` = 4 hits (LaunchTicket::validate, validate_controller_launch, validate_assignment, validate_process_identity), read with full context; the cited pair is the one coupled-Option invariant in the crate (other `Option` fields are genuinely independent) -- clean: seeds `fn validate_\w+|fn check_\w+`=4, `is_\w+: bool|\w+_flag: bool`=0, `(mode|kind|state): String`=0; the four `validate_*` functions are deliberate conformance gates over private-field tickets (the crate's contract is re-validating decoded tickets), `binding_worker`/`reaped` are private booleans set only through checked constructors. - -## api -- d2b-process-conformance#3 sev=low blast=leaf effort=S verdict=actionable - `terminal::ExitClass` is re-exported under two names and the `BrokerExitClass` alias has zero consumers anywhere in the repo (the only hit is the re-export itself), while `ProcessExitClass` is the name the one real consumer (systemd lifecycle) imports - fix: drop the `ExitClass as BrokerExitClass` arm from lib.rs:54, keep `ExitClass as ProcessExitClass` - [packages/d2b-process-conformance/src/lib.rs:52, packages/d2b-process-conformance/src/lib.rs:54] - evidence: census `BrokerExitClass` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (its own re-export), vs `ProcessExitClass` = 6 hits incl. d2b-provider-process-systemd/src/lifecycle.rs:5 -- d2b-process-conformance#4 sev=low blast=leaf effort=S verdict=actionable - `process_provider.rs` re-exports the same root surface under a second public path (`d2b_process_conformance::process_provider::*`) and no caller uses that path (its own doc calls it a "destination-compatible boundary" for a split that is already settled) - fix: delete the module and its lib.rs:36 declaration; every item stays reachable at the root path - [packages/d2b-process-conformance/src/process_provider.rs:6, packages/d2b-process-conformance/src/lib.rs:36] - evidence: census `conformance::process_provider` over packages/, nixos-modules/, tests/, labs/ = 0 hits; seed `^\s*pub use ` = 11 hits (9 root arms in lib.rs, 1 in process_provider.rs, 1 multi-line status arm) -- d2b-process-conformance#5 sev=low blast=family effort=M verdict=actionable - `pub mod testing` ships the mock `ScriptedEffectPort`, `PortCall`, `block_on` poller, and `TicketBuilder` fixtures unconditionally in the production library surface, while the house pattern (api card false-positive note) is a feature-gated `test-support` export; every in-tree consumer is a test target (provider crates' integration tests, d2bd `#[cfg(test)]`, provider-supervisor tests) - fix: gate `testing` behind a `test-support` feature (`#[cfg(feature = "test-support")] pub mod testing;`) and have consumer test targets enable it via dev-dependencies; `suite` stays ungated (it is the crate's product) - [packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testing.rs:60] - evidence: census `d2b_process_conformance::testing` over packages/ = 11 call sites, all under tests/ or `#[cfg(test)]` (d2b-provider-process-systemd/tests/conformance.rs:7, d2b-provider-process-minijail/tests/conformance.rs:8, d2b-provider-supervisor/src/adapter.rs:921, d2bd/src/provider_effects.rs:1484, d2b-provider-process/src/backend.rs:355) -- d2b-process-conformance#6 sev=low blast=leaf effort=S verdict=actionable - `CompiledSandbox::requires_cgroup_kill()` is public API whose field is set unconditionally to `true` at the only constructor, and no in-tree caller reads it (census inside the crate only); the accessor promises sandbox-dependent variation the compiler can never produce - fix: either thread a real `StopProof`/cgroup decision through `compile()` and its callers, or delete the field and the accessor along with the suite's unused surface - [packages/d2b-process-conformance/src/sandbox.rs:18, packages/d2b-process-conformance/src/sandbox.rs:61, packages/d2b-process-conformance/src/sandbox.rs:98] - evidence: census `requires_cgroup_kill` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 4 hits, all inside sandbox.rs (field, accessor body, constructor); seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 216 hits, all pub items read whole-file (no sampling needed) -- clean: seeds 216/0/11 (pub items / `pub .*\b(Arc|Rc|Box|RefCell)<` / `pub use`); every pub item and trait read; no smart-pointer or dependency types in public signatures; traits are generic over the injected port with small required surfaces and documented defaulted methods; exported wire-facing enums are the conformance vocabulary (deliberate closed sets with `#[non_exhaustive]`). - -## err -- d2b-process-conformance#7 sev=low blast=leaf effort=S verdict=actionable - `LaunchIdentity::new` re-borrows `owner_ref` with `.expect("binding owner is present")` immediately after an `is_some_and` guard on the same value, an input-derived `expect` the skill's audit flags; the guard and the re-borrow are the same condition so the panic is unreachable but the shape is avoidable - fix: use an if-let chain, e.g. `if let Some(owner) = owner_ref.as_ref().filter(|o| o.resource_type().as_str() == "VolumeBinding") && target_ref.is_none() { ... owner.to_canonical_string() ... }`, deleting both the separate guard and the `expect` - [packages/d2b-process-conformance/src/launch_identity.rs:147] - evidence: seed `\.unwrap\(\)|\.expect\(` = 141 hits; every other hit sits in `#[cfg(test)]` modules or fixture helpers that parse literal constants (sanctioned classes), and no `let _ =`/`.ok();` swallow (seed 2 = 0) or panic macro outside tests (seed 3 = 4, all suite test-code failure panics) -- clean: seeds `\.unwrap\(\)|\.expect\(`=141, `let _ = |\.ok\(\);`=0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`=4 (suite test-match arms), `enum \w*Error`=2; the two error enums are closed `#[non_exhaustive]` vocabularies with stable `code()` strings (the wire rendering, deliberate) and caller-actionable variants; error payloads echo the rejected input for diagnosability as documented. - -## serde -- d2b-process-conformance#8 sev=low blast=leaf effort=S verdict=actionable - `CompiledDigests` serialization is hand-written (`impl Serialize` emitting 7 named fields) where a derive with `rename_all = "camelCase"` plus `#[serde(rename = "fdTable")]` on `fd_table` produces the identical wire shape and stays in sync with the struct - fix: add `#[derive(serde::Serialize)]`/`#[serde(rename_all = "camelCase")]` on `CompiledDigests` (ticket.rs:105) and delete the manual impl at status.rs:125-137 - [packages/d2b-process-conformance/src/status.rs:125, packages/d2b-process-conformance/src/ticket.rs:105] - evidence: seed `impl .*Serialize.*for` (serde seed-3 variant) = 2 hits; the other hit (identity.rs:140, the digest hex renderer) is deliberate wire hex output; no field names change so `process_status_uses_the_v3_common_field_names` (status.rs:162) stays green -- d2b-process-conformance#9 sev=low blast=leaf effort=S verdict=actionable - `ProcessOutcome` derives `Deserialize` on `pub` fields but permits illegal `(exit_class, exit_code)` combinations (e.g. `Crash` with `Some(300)`), so a decoded terminal message is invalid until each consumer re-validates (`ProcessOutcome::validate`, then again inside `from_parent` and `relay`); the skill's boundary rule says the read should fail, not first use - fix: deserialize into a raw shape with `#[serde(try_from = "RawOutcome")]` (or a validating custom `Deserialize`) so illegal combinations become `InvalidTerminalResult` at the boundary, then delete the per-use re-validations or keep only one - [packages/d2b-process-conformance/src/terminal.rs:39, packages/d2b-process-conformance/src/terminal.rs:94, packages/d2b-process-conformance/src/terminal.rs:177] - evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 8 hits (the only Deserialize pair is terminal.rs:39); seed `impl .*Deserialize.*for` = 0; the wire key names are unchanged by the try_from fix, so no contract revision -- clean: seeds 8/13/0/3 (derives / serde attrs / hand-written Deserialize / serde_json calls); rename_all and skip_serializing_if usage is consistent, enum representations are external with documented vocabularies, `providerImplementation`/`processIdentityDigest` renames are deliberate v3 common-field names pinned by the crate's own wire test (status.rs:162-183); no round-trip-only trap since the only Deserialize type is validated on use today. - -## obs -- N/A: seeds `\bprintln!\(|\beprintln!\(`=0, `(info|debug|warn|error|trace)!\(`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=0 all zero; the crate declares no `tracing`/`log` dependency in Cargo.toml and contains no telemetry at all (library crate whose output is typed values, not events). - -## docs -- d2b-process-conformance#10 sev=low blast=leaf effort=S verdict=actionable - Zero canonical `# Errors` sections exist (seed 2 = 0) while 52 `-> Result<` declarations carry non-obvious failure conditions that several docs only imply (e.g. `ProcessOutcome::exited` rejects out-of-range codes, `SandboxCompiler::compile` rejects root-in-user-domain and canonical-JSON failure, `LaunchIdentity::new` names six refusal conditions, `BrokerTerminalResult::from_parent` requires matching evidence) - fix: add an `# Errors` section naming the failing conditions to the Result-returning pub items, notably terminal.rs:51/94/215, sandbox.rs:72, launch_identity.rs:112, ticket.rs:731, port.rs:35/67 - [packages/d2b-process-conformance/src/terminal.rs:51, packages/d2b-process-conformance/src/sandbox.rs:72, packages/d2b-process-conformance/src/launch_identity.rs:112, packages/d2b-process-conformance/src/ticket.rs:731] - evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)`=212, `/// # (Examples|Errors|Panics|Safety)`=0, `-> Result<`=52; `#![deny(missing_docs)]` (lib.rs:22) already guarantees presence, so the gap is section shape, not coverage; first sentences are consistently strong and magic constants carry their why (ticket.rs:27-30) -- clean: seeds 212/0/52 with all pub items read; every module carries `//!` docs, every pub item is documented (deny(missing_docs) enforced), redaction Debug impls are deliberate, and no doc comment narrates implementation. - -## perf -- clean: seeds `format!\(`=9 (7 in tests plus ticket.rs:472 one-time `Provider/{}` build and identity.rs hex rendering, all cold), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=5 (launch_args default, test doubles), `\.to_string\(\)`=0; `to_hex` pre-sizes with `String::with_capacity(64)` and pushes per byte; no loops allocate, no collection choice issues (BTreeSet is the declared sorted-identity set), findings would be static (unmeasured) and none rose to that bar. - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=1, `Atomic\w+|Ordering::`=0, `thread_local!|unsafe impl (Send|Sync) for`=0; the single `Mutex>` in `ScriptedEffectPort` (testing.rs:67) is a test double whose `try_lock` + fail-closed `unwrap_or_default` policy is documented (testing.rs:116-121) and the crate's hand-rolled poller drives everything single-threaded. - -## async -- d2b-process-conformance#11 sev=low blast=family effort=S verdict=actionable - Both traits declare their six async methods as `fn ... -> impl Future + Send` while every in-tree implementor already writes `async fn` (ScriptedEffectPort, ProviderSupervisor, systemd/minijail test ports, d2bd's NonLaunchingProcessEffectPort), and the traits already carry `Send + Sync` supertraits, so the RPITIT `async fn` form (stable, edition 2024) expresses the same Send contract more directly - fix: convert the trait method declarations to `async fn` (port.rs:99-157, provider.rs:96-148), rewriting the two default bodies (`launch_with_inherited_fds`, `probe`) as `async { ... }` and dropping the `ready(Err)...))` wrappers; no implementor changes required - [packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port.rs:129, packages/d2b-process-conformance/src/provider.rs:96, packages/d2b-process-conformance/src/provider.rs:125] - evidence: seed `async fn|async move|\.await` = 8 hits (the 6 declare/default sites plus impl-side; every impl method is already `async fn`), seeds 2-4 (spawn/JoinSet/select/tokio-sync/tokio-main) = 0; the crate owns a runtime-free `block_on` noop-waker poller (testing.rs:33) documented as hermetic, matching the sanctioned plain-test-harness class -- clean: seeds 8/0/0/0; no `tokio::spawn`, no runtime created in the library, no guard held across `.await`, no cancellation-sensitive section (all futures are immediate), block_on is a deliberate runtime-free test driver. - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern|transmute|from_raw|MaybeUninit|mem::zeroed`=0 and `// SAFETY:`=0; the crate's manifest sets `unsafe_code = "forbid"` in its local `[lints.rust]` table (Cargo.toml), so seed 4 alone does not make the lens applicable per the card. - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section|catch_unwind|repr\(C\)|repr\(transparent\)|CStr|CString|c_char`=0 all zero; the crate crosses no foreign boundary. - -## macro -- clean: seeds `macro_rules!`=1, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; the single macro `opaque_digest!` (identity.rs:105) is the sanctioned impl-per-type generation (duplicating from_bytes/as_bytes/to_hex/is_zero plus redacted Debug and hex Serialize for two digest newtypes) with narrow `ident`/`literal` fragment specifiers, invoked immediately at definition site, and no proc-macro machinery. - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]`=30, `assert_eq!\(|assert_ne!\(|assert!\(`=128, `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0; every test read: named behaviors (not implementations), assert error variants not Display strings, expected values are hand-written or fixture literals, no network/no clock (deadline fixtures are fixed constants), the suite is table-shaped over the two execution domains, redaction and wire-name pins are deliberate contracts (status.rs:162, suite.rs:312), and the fail-closed paths each have a named negative case; no test restates a getter or cannot fail; the crate has no `tests/` dir, which is right for a library whose integration surface (the shared suite) is exercised by the two provider crates' own test targets. - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: 1 finding (seeds ran: 45/13/0/0) -- type: 1 finding (seeds ran: 4/0/0) -- api: 4 findings (seeds ran: 216/0/11) -- err: 1 finding (seeds ran: 141/0/4/2) -- serde: 2 findings (seeds ran: 8/13/0/3) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 1 finding (seeds ran: 212/0/52) -- perf: clean (seeds ran: 9/5/0; all hits are cold paths, static (unmeasured)) -- conc: clean (seeds ran: 0/1/0/0) -- async: 1 finding (seeds ran: 8/0/0/0) -- unsafe: N/A (seeds: 0/0 all zero; crate manifest forbids unsafe_code) -- ffi: N/A (seeds: 0 all zero; no foreign boundary) -- macro: clean (seeds ran: 1/0/0/0) -- test: clean (seeds ran: 30/128/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md deleted file mode 100644 index 5ae012926..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-activation-nixos.md +++ /dev/null @@ -1,86 +0,0 @@ -# d2b-provider-activation-nixos - d2b-provider-activation-nixos -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4014 (src 3368 + tests 646, excl. src/generated/**, no generated dir present) | modules: whole crate (controller, driver, effects_service, facets, lib, test_support, vocabulary; tests/reconcile.rs, tests/registration.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- clean: seeds 1/2/3 = 0/0/0 over src; no index loops, no hand-written derive-replaceable impls, no statement-style accumulation. The three hand-written `Debug` impls (controller.rs:217, 439, 508) are deliberate redaction of key/signature bytes (card false-positive class; a derive would leak). -- clean: checked expression shape, conversion impls, naming (`as_`/`to_`/`into_` discipline holds; no `get_` accessors), and newtype usage across all seven src files. - -## own -- clean: seeds 1/2/3/4 = 41/2/0 (the card's `Rc<` alternative also matches inside every `Arc<`, inflating raw counts; real seed-3 hits are the two `Arc>` in test_support). Every clone read: Arc clones at the factory/facet boundaries are genuine shared ownership (call sites driver.rs:414, effects_service.rs:188 - the daemon composition root builds one dispatch source, the factory and each built service share it); spec-field clones build owned `RunnerRequest`/`HandoffIntent` values (controller.rs:354, 384, 789-790; driver.rs:630, 636, 806); `observed.clone()` at driver.rs:809 is required because the observation is consumed again by `execute_host_runner`/`apply_runner_result`; the rest are test doubles. No `&String`/`&Vec` parameters, no `Rc`/`RefCell`, no `Cow`, no mutable statics. -- clean: all 41 clone-family sites judged explainable in one sentence; no `mem::take` opportunity and no borrow-splitting conflict found. - -## type -- clean: seeds 1/2/3 = 1/0/0; the single hit is the test fn name `validate_rejects_a_spec_outside_the_closed_generation_contract` (driver.rs:1229), not a validation fn. State is enum-typed throughout (`CallerRole`, `GenerationPhase`, `TrustStatus`, `ActivationMode`); `start_root`/`source_generation_preserved` are single semantic booleans, not flag pairs; `ActivationRunnerStep.label` is a deliberate wire label. -- clean: no boolean-flag soup, no `Option` pairs, no stringly-typed state, no validate-at-every-callsite pattern (the spec constructor is the single admission fence, driver.rs:220). - -## api -- d2b-provider-activation-nixos#1 sev=low blast=leaf effort=S verdict=actionable - `ActivationDriver` is re-exported at lib.rs:38 but no external consumer names it: the factory returns `Box` (driver.rs:410), so the concrete type never escapes the crate - fix: make `ActivationDriver` `pub(crate)` and drop it from the lib.rs re-export arm - [packages/d2b-provider-activation-nixos/src/driver.rs:426, packages/d2b-provider-activation-nixos/src/lib.rs:38] - evidence: census: `ActivationDriver\b` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 8 hits, all inside this crate (driver.rs:411,426,436,715,964,1205; lib.rs:38); seed 1 (pub items) = 95 hits -- d2b-provider-activation-nixos#2 sev=low blast=leaf effort=S verdict=actionable - `ACTIVATION_RUNNER_RESOURCE_TYPE` (controller.rs:14) is `pub` inside the exported `controller` module but used only at controller.rs:296 in the same module, so it is reachable as `d2b_provider_activation_nixos::controller::ACTIVATION_RUNNER_RESOURCE_TYPE` with no consumer - fix: make the const private (or `pub(crate)`) - [packages/d2b-provider-activation-nixos/src/controller.rs:14, packages/d2b-provider-activation-nixos/src/controller.rs:296] - evidence: census: `ACTIVATION_RUNNER_RESOURCE_TYPE` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both in controller.rs -- clean: seeds 1/2/3 = 95/5/6; the lib.rs re-export arms are the house single-surface pattern (card false positive); the `Arc` pub field in `ActivationEffectFacets` (facets.rs:34) genuinely shares one daemon-supplied dispatch source across the factory and per-zone services (d2bd implements the trait at resource_plane_v3.rs:2316; clones at driver.rs:414, effects_service.rs:188); `ActivationDriverError` is the skill's struct-with-private-kind public error; every pub item carries a doc comment (`#![deny(missing_docs)]`, lib.rs:8). - -## err -- d2b-provider-activation-nixos#3 sev=medium blast=leaf effort=S verdict=actionable - `GenerationObservation::terminal` (exported via lib.rs:33) panics with `assert!` on a caller-supplied name that is empty, contains '/', or exceeds 128 chars, instead of making the bound a type or a `Result` - fix: take `name: ResourceName` (already bounded: no '/', <=128 chars) and have `new` parse through the same path, or return `Result`; this deletes the runtime check the type makes impossible - [packages/d2b-provider-activation-nixos/src/controller.rs:119, packages/d2b-provider-activation-nixos/src/controller.rs:121] - evidence: seed 1 (unwrap/expect) = 48 in src, of which 18 production expects are on literally-built static values in `activation_runner_spec`/name derivation (card false-positive class) and 30 sit in `#[cfg(test)]`; seed 3 (panic!/unreachable!/todo!/unimplemented!) = 0; the assert! at controller.rs:121 is the only library panic on caller input (assert! is not a card seed) -- clean: seeds 1/2/3/4 = 48/0/0/4; error taxonomy is closed and caller-action-split: `ActivationError` (5 Copy variants, controller.rs:395), `ActivationVerificationError` (9 variants, controller.rs:497), `ActivationDriverError` (struct with private `kind` + `op`, driver.rs:133); no swallowed Results, no `let _ =`, no panic macros; every driver failure maps through `map_err` to the typed error. - -## serde -- clean: seeds 1/2/3/4 = 0/0/0/9; the 9 hits are `from_slice`/`to_value`/`from_value` at the decode hook (driver.rs:220, 549, 651, 664) and the effects payload (effects_service.rs:69). Deserialization lands directly in the closed `NixosGenerationSpec` contract type whose constructor is the validation fence; no derive/`rename_all`/`deny_unknown_fields`/`try_from` decisions live in this crate (the contract crates own them); the `providerRef` JSON insert in `ensure_runner` (driver.rs:656-659) is a deliberate wire-shape accommodation for the manager's child row, not a boundary parse. -- clean: no hand-written `Deserialize`, no enum-representation choices, no `flatten`; round-trip behavior is covered by the runner-spec assertions in tests/reconcile.rs:97-119. - -## obs -- d2b-provider-activation-nixos#4 sev=low blast=leaf effort=S verdict=actionable - nine `tracing::warn!` refusal events in `ActivationTrust::verify` are message-only with no named fields and no enclosing span (no `#[instrument]` anywhere in the crate), so the failing fence is queryable only as message text - fix: add a named field carrying the error variant (e.g. `refusal = ?ActivationVerificationError::TrustEpochMismatch`), keeping fields identifier-free so the site stays under the ADR 0010/0028 redaction gate - [packages/d2b-provider-activation-nixos/src/controller.rs:569, packages/d2b-provider-activation-nixos/src/controller.rs:575, packages/d2b-provider-activation-nixos/src/controller.rs:581, packages/d2b-provider-activation-nixos/src/controller.rs:587, packages/d2b-provider-activation-nixos/src/controller.rs:593, packages/d2b-provider-activation-nixos/src/controller.rs:602, packages/d2b-provider-activation-nixos/src/controller.rs:609, packages/d2b-provider-activation-nixos/src/controller.rs:615, packages/d2b-provider-activation-nixos/src/controller.rs:623] - evidence: seed 2 ((info|debug|warn|error|trace)!(") = 9 hits, all message-only without fields; seed 3 ).instrument|#[instrument) = 0; seed 1 (println!/eprintln!) = 0 -- clean: the other 8 tracing sites (controller.rs:49, 57, 748, 756, 763, 815, 822, 833) carry named fields (`target`, `role`, `generation`, `prior`, `outcome`); no secret or identifier reaches a field; no library-installed subscriber. - -## docs -- d2b-provider-activation-nixos#5 sev=medium blast=leaf effort=S verdict=actionable - the pub Result-returning policy API (`verify_application`, `reconcile`, `apply_runner_result`, `refuse_undeclared_runner_step`, `ActivationTrust::verify`) documents no `# Errors` section, leaving 5 `ActivationError` and 9 `ActivationVerificationError` failure conditions unstated in the contract - fix: add `# Errors` sections naming the variants each fn returns - [packages/d2b-provider-activation-nixos/src/controller.rs:711, packages/d2b-provider-activation-nixos/src/controller.rs:735, packages/d2b-provider-activation-nixos/src/controller.rs:808, packages/d2b-provider-activation-nixos/src/controller.rs:726, packages/d2b-provider-activation-nixos/src/controller.rs:562] - evidence: seed 2 (/// # (Examples|Errors|Panics|Safety)) = 0 across the crate; seed 3 (-> Result<) = 111 hits total; seed 1 (pub items) = 95 hits -- d2b-provider-activation-nixos#6 sev=low blast=leaf effort=S verdict=actionable - `GenerationObservation::terminal` can panic (assert at controller.rs:121) but its doc comment carries no `# Panics` section, so the bound is unstated in the contract - fix: add `# Panics` naming the empty/'/'/length bound (or drop the section once finding #3's type change removes the panic) - [packages/d2b-provider-activation-nixos/src/controller.rs:118, packages/d2b-provider-activation-nixos/src/controller.rs:121] - evidence: seed 2 (canonical sections) = 0 hits; terminal is the only panic-capable pub item (assert at controller.rs:121) -- clean: every pub item is documented (`#![deny(missing_docs)]`); first sentences are single-line contract statements (e.g. "Stable controller failures.", "One declared activation runner step."); all seven modules carry `//!` docs; no doctests and no `ignore`d examples exist (nothing to rot). - -## perf -- clean: seeds 1/2/3 = 16/19/0; every `format!`/`Vec::new` site is cold: reconcile-time runner-name derivation (controller.rs:276-289), error paths, one-shot diagnostics, and test fixtures. The per-byte `format!("{byte:02x}")` digest loop (controller.rs:287) runs once per reconcile at most; no hot loop, no grow-by-push collection in a loop, no `to_string()` at a boundary. -- clean: static (unmeasured) - no benchmark exists for this crate; nothing here would move a perf budget. - -## conc -- clean: seeds 1/2/3/4 = 0/6/4/0; production uses one `tokio::sync::Mutex>` (driver.rs:433) whose guards are scoped to single statements (no guard across an await; `await_holding_lock` is denied at the workspace table), and the parking_lot `Mutex` + `AtomicU64` pairs live only in test-support doubles and the test `RecordingManager`, each with an `async-gate-allow` marker (sanctioned test-support reason; inventory `packages/xtask/data/async-gate-inventory.json`). No `std::thread`, no `thread_local!`, no manual `Send`/`Sync` claims. -- clean: the test-only `Ordering::SeqCst` uid counter (driver.rs:1033) is a fixture, not a synchronization argument worth weakening. - -## async -- clean: seeds 1/2/3/4 = 45/0/2/19; no `tokio::spawn`/`spawn_blocking`/`JoinSet`/`select!`/`join!` anywhere in production. The sync `dispatch_handoff` facet call inside async `apply_host_generation_handoff` (effects_service.rs:137) is the daemon-supplied boundary (R2): the implementation lives in d2bd's composition root (resource_plane_v3.rs:2316), outside this crate, and no blocking evidence exists here. `watched_runner` lock is never held across an await; `ensure_runner` commits the child through the manager before the spawn notification (F1), so the irreversible step is the manager's single non-cancellable commit; the 19 `#[tokio::test]` hits are test harnesses. -- clean: no runtime started inside the library; no future-size or `Send`-bound hazards found; the `async-gate-allow` markers in test_support.rs:50-52 are deliberate recorded exceptions (cited, not re-flagged). - -## unsafe -- N/A (seeds: 1/2/3 = 0/0/0 all zero; seed 4 = 1, `unsafe_code = "forbid"` in Cargo.toml [lints.rust] - a forbid setting alone does not make the lens applicable per the card) - -## ffi -- N/A (seeds: 1/2/3/4 = 0/0/0/0 all zero; no extern "C", no repr(C)/repr(transparent), no CStr/CString, no catch_unwind) - -## macro -- N/A (seeds: 1/2/3/4 = 0/0/0/0 all zero; no macro_rules! definitions, no proc-macro/syn/quote, no $crate, no to_compile_error/new_spanned) - -## test -- d2b-provider-activation-nixos#7 sev=low blast=leaf effort=S verdict=actionable - the six-case verification-fence table in `activation_verification_requires_all_trust_and_digest_fences` asserts without a per-case message, so a failure in case 3 of 6 reports only a line number and no case identity - fix: add a per-case failure message (e.g. `"case {i}: expected {expected_error:?}"`) to the loop assert - [packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activation-nixos/tests/reconcile.rs:447] - evidence: seed 2 (assert_eq!/assert_ne!/assert!) = 160 hits over src+tests; the loop at tests/reconcile.rs:439-450 is the only table without a failure message -- clean: seeds 1/2/3/4 = 38/160/0/0; 38 test fns (13 driver, 6 effects_service, 2 vocabulary, 14 reconcile, 3 registration), no `#[ignore]`, no proptest/insta/rstest. Assertions target error variants, not `Display` strings (`assert_eq!(result.unwrap_err(), ActivationError::OutcomeMismatch)`); the KTD13 argv-free fence (`assert_no_launch_argv`, driver.rs:1821) is a genuine can-fail recursive check; the F1 persist-before-spawn ordering and one-watch-per-child invariants are asserted on the recorded manager log; trust fixtures generate a fresh key per run, keeping assertions deterministic. - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 41/2/0) -- type: clean (seeds ran: 1/0/0) -- api: 2 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 0/0/0/9) -- obs: 1 finding(s) -- docs: 2 finding(s) -- perf: clean (seeds ran: 16/19/0) -- conc: clean (seeds ran: 0/6/4/0) -- async: clean (seeds ran: 45/0/2/19) -- unsafe: N/A (seeds: 0/0/0 all zero; forbid-only, per card criteria) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md deleted file mode 100644 index e7425215b..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-audio-pipewire.md +++ /dev/null @@ -1,89 +0,0 @@ -# d2b-provider-audio-pipewire - d2b-provider-audio-pipewire -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2709 (excl. src/generated/**, none present) | modules: whole crate (src: authority, controller, lib, mediator, resource_type, state; tests: audio_policy, authority, controller, mediator, resource_type, state) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test (+ supply per-crate note) | Partitions: whole crate (single-part lane; on the README-only integration ratchet, provider_crate_policy.rs:331-332) - -## idiom -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 0; the single hit is the hand-written `Default for AudioGrants` (resource_type.rs:161), which preserves the grants/policy-state invariant by seeding from `AudioPolicyState::default_v2()` - a listed repo false-positive class; no index loops, no statement-style accumulation, derives already present everywhere else - -## own -- clean: seeds `.clone()` = 6 (src 3: controller.rs:250-252, tests 3), `.to_owned()|.to_vec()|.to_string()` = 7 (src 5, tests 2), `Rc<|RefCell<|Arc` arbiter is the documented multi-controller shared authority (authority.rs:44), `to_owned()` copies a `&'static str` const, test clones share one arbiter across two controllers; no borrow-fight clones, no `mem::take` candidates - -## type -- d2b-provider-audio-pipewire#1 sev=low blast=leaf effort=S verdict=actionable - constructors re-validate invariants the admission gate already enforces: `AudioServiceSpec::owner` (endpoint type) and `AudioBindingSpec::new` (service/target ref types) return the same error variants `validate_audio_service`/`validate_audio_binding` produce, so the same invariant is checked at two layers and the constructors' `Result` promises a rejection path that is dead in practice - fix: drop the checks from `owner()`/`new()` (make them infallible) and keep `validate_audio_*` as the single parse-once admission gate, or delete the gate checks and keep the constructor checks - [src/resource_type.rs:64-70, src/resource_type.rs:117-125, src/resource_type.rs:206-231, src/resource_type.rs:233-246] - evidence: seed `fn validate_\w+|fn check_\w+` = 3 hits (resource_type.rs:206,233,249); constructor checks at resource_type.rs:68-70 and 122-124 duplicate gate invariants with identical error variants (EndpointType, ReferenceType) -- d2b-provider-audio-pipewire#2 sev=low blast=leaf effort=S verdict=actionable - the shared-vs-owned controller mode is a private bool `activate_promoted` (controller.rs:210 vs 218-224) and `finalize`/`finalize_shared` are byte-identical delegations to `finalize_inner`, so the two public methods' behavioral difference is invisible in their signatures and a caller can invoke `finalize_shared` on an owned controller and get promotion activation anyway - fix: encode the mode in the type (typestate or a `MicrophoneHandoff::{Enable,Defer}` field set by construction) so the method contract holds by construction, or collapse the two methods into one documented by the constructor - [src/controller.rs:589-598, src/controller.rs:602-608, src/controller.rs:199] - evidence: static read (seed `is_\w+: bool|\w+_flag: bool` = 0, manual catch); `finalize` and `finalize_shared` both body `self.finalize_inner(lease)`; `activate_promoted` true from `new()`, false from `with_shared_microphone` - -## api -- d2b-provider-audio-pipewire#3 sev=low blast=leaf effort=S verdict=actionable - `SpeakerMixer::set_grant(lease, on: bool)` takes a boolean command and returns a bool whose meaning flips with the argument (true: was-empty, false: was-last), and the only caller ignores the revoke return (it calls `is_last_grant` first) - fix: split into `grant(lease) -> Result` (was-empty) and `revoke(lease) -> Result` (was-last), or return a named enum, so the return contract stops being argument-dependent - [src/authority.rs:157-171, src/controller.rs:395-403] - evidence: static read; seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 1 (authority.rs:44, unrelated shared-ownership alias); controller.rs:395-403 discards the `set_grant(lease, false)` return after `is_last_grant` -- d2b-provider-audio-pipewire#4 sev=low blast=leaf effort=S verdict=actionable - `register_service` is exported from lib.rs but has zero callers anywhere (the daemon's audio paths and the wayland-policy audio_registry validate specs directly), leaving a dead registration gate on the surface - fix: consume `register_service` in the daemon's audio Service registration path or drop the export (crate is 0.0.0-bootstrap, no semver gate) - [src/controller.rs:746-748, src/lib.rs:32] - evidence: census `register_service` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits (definition + lib.rs re-export), 0 callers -- d2b-provider-audio-pipewire#5 sev=low blast=family effort=S verdict=needs-contract - `AudioLastSetApplied::OfflineOnly` is named as if it meant "applied offline only" while its doc says "No setting was applied in the current reconcile"; the variant is rendered to a wire-visible status string "OfflineOnly" by the wayland-policy projection and pinned in daemon tests - fix: rename the variant (e.g. `NotApplied`) and update the projection string and pinned expectations together - [src/controller.rs:124-133, packages/d2b-provider-wayland-policy/src/audio_registry.rs:117-122, packages/d2bd/src/resource_plane_v3.rs:4626] - evidence: census `AudioLastSetApplied|OfflineOnly` over packages/ = 9 hits; wire rendering at audio_registry.rs:121 and pinned at resource_plane_v3.rs:4626 and audio_registry.rs:704,745 - -## err -- d2b-provider-audio-pipewire#6 sev=medium blast=leaf effort=S verdict=actionable - `MicrophoneArbiter::new(0)` and `SpeakerMixer::new(0)` panic via `assert!` on caller input to a pub constructor; the skill's panic policy says input validation is always a `Result`, and the type-level answer (`NonZeroUsize`) exists - fix: take `NonZeroUsize` (or return `Result`) in both constructors; no current caller passes 0 (daemon uses 64), so the change is mechanical - [src/authority.rs:53-54, src/authority.rs:144-145] - evidence: seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0; `assert!(max_queue > 0)` / `assert!(max_consumers > 0)` at authority.rs:54,145 (manual catch; pub constructor input) -- d2b-provider-audio-pipewire#7 sev=low blast=leaf effort=S verdict=actionable - the crate's error enums never chain sources: `AudioStateIoError`'s seven `io::Error` payloads and `AudioControllerError::Mediator(AudioMediatorError)` leave `Error::source()` returning `None`, flattening the chain into the Display message - fix: implement `std::error::Error::source()` for the payload variants (or move the crate to `thiserror` `#[source]`, which also removes the hand-written Display impls) - [src/state.rs:114-123, src/controller.rs:155-160] - evidence: seed `enum \w*Error` = 5 (all wire-code Display impls, no source()); AudioStateIoError variants hold io::Error without #[source]-equivalent, AudioControllerError::Mediator wraps AudioMediatorError without chaining - -## serde -- clean: seeds `derive)...Serialize` = 4, `serde)...)` = 6, `impl .*Deserialize.*for` = 0, `serde_json::from_|to_` = 0 in src (12 in tests); wire shapes are camelCase + deny_unknown_fields with `#[serde(skip)]` on `zone` (metadata, not spec) and `provider_extension` (signed-envelope only), all pinned by tests/resource_type.rs and tests/audio_policy.rs round-trips; no hand-written deserializers, no try_from needed (post-parse validate gates are the deliberate admission pattern) - -## obs -- clean: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 1 (the `use tracing::{debug, warn};` import at controller.rs:16, a seed false positive), `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 1; every event in controller.rs uses named fields (`zone`, `lease`, `channel`, `error`) with static messages, no interpolated messages, no secrets in fields, errors logged once at the mediation boundary - -## docs -- d2b-provider-audio-pipewire#8 sev=medium blast=leaf effort=S verdict=actionable - `AudioStateLock` is a pub struct with no doc comment at all (its module carries `#[allow(missing_docs)]`, lib.rs:9-10), and it is non-obvious: a caller must know holding the value keeps the OFD lock and dropping it releases it - fix: document the guard semantics (or remove the module-level allow and document the item) - [src/state.rs:81-84, src/lib.rs:9-10] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 85 hits; AudioStateLock (state.rs:81) is the only pub item with no doc comment -- d2b-provider-audio-pipewire#9 sev=medium blast=leaf effort=M verdict=actionable - none of the ~23 Result-returning public functions carries a `# Errors` section, and the failure conditions are non-obvious (LockOpen vs TempWrite vs AtomicRename on the state-I/O path; Admission vs Mediator on reconcile) - fix: add `# Errors` sections to `acquire/read/write_audio_state_*`, `child_resources`, `reconcile*`, `SpeakerMixer::set_grant/set_level`, `validate_audio_*` naming each failure variant - [src/state.rs:91, src/state.rs:148, src/state.rs:181, src/controller.rs:236, src/controller.rs:303, src/authority.rs:157] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 of 85 pub items; `-> Result<` = 23 hits, none documented with an Errors section -- d2b-provider-audio-pipewire#10 sev=low blast=leaf effort=S verdict=actionable - magic values lack the why: `AUDIO_REPAIR_INTERVAL_SECS = 300` says it is the repair interval but not why 300s, and the arbiter/mixer bound `64` in `AudioBindingController::new` is undocumented (and hardcoded again in tests/controller.rs:302-308) - fix: document the cadence rationale and hoist the 64 into a named const (e.g. `AUDIO_QUEUE_BOUND`) used by both the controller and the bound test - [src/controller.rs:21, src/controller.rs:209, src/controller.rs:212] - evidence: static read; no doc text explains either constant's derivation - -## perf -- clean: seeds `format!\(` = 1 src (state.rs:17 lock-path build, cold), `Vec::new\(\)|VecDeque::new\(\)|BTreeMap::new\(\)` = 3 src (empty-case constructors), `\.to_string\(\)` = 0 src; all hits are cold one-shot paths (state I/O, constructors), no allocation in any loop or reconcile hot path; static (unmeasured), no benchmark exists - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 1, `Atomic\w+|Ordering::` = 3 (all `AtomicRename` error-variant false positives), `thread_local!|unsafe impl (Send|Sync) for` = 0; the single shared-state site (Arc arbiter, authority.rs:44) is the justified multi-owner Service authority, reached only through non-blocking `try_lock` (U4 fail-closed), never held across awaits; no threads, no atomics, no manual Send/Sync claims - -## async -- clean: seeds `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 2 (the arbiter alias, authority.rs:44,48), `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the crate is fully synchronous; the tokio Mutex is deliberate (documented: no executor worker ever parks on it, authority.rs:40-44) and used only via try_lock; no guards across awaits, no spawned tasks, no cancellation surface - -## unsafe -- N/A (seeds: 0/0/2/0; the 2 seed-3 hits are `io::Error::from_raw_os_error` at state.rs:49,67 - a safe std function, not an unsafe block; no `unsafe` blocks/fns/impls, no SAFETY comments needed, manifest `unsafe_code = "forbid"` at Cargo.toml:14) - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface - libc/nix calls in state.rs are safe syscall wrappers, not a foreign boundary) - -## macro -- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros defined anywhere in the crate) - -## test -- d2b-provider-audio-pipewire#11 sev=low blast=leaf effort=S verdict=actionable - `SpeakerMixer::mix_level`'s saturation cap (sum capped at 100, authority.rs:236-241) has no boundary test: tests/authority.rs:26-31 asserts only 80+20=100, so a regression that removed the `min(100)` would pass - fix: add saturation rows (e.g. 80+80, 60+60+60) asserting the capped result - [tests/authority.rs:26-31, src/authority.rs:236-241] - evidence: seed `#\[test\]|#\[tokio::test\]` = 40 tests, assert mass = 174 seed hits; mix_level boundary rows absent from the only mixer test -- d2b-provider-audio-pipewire#12 sev=low blast=leaf effort=S verdict=actionable - tests/mediator.rs:13-24 is named `projection_cannot_open_pipewire_and_failed_set_preserves_state` but asserts only the Err and readiness; the state-preservation half of the claim is unasserted, so a regression that mutated grant/level on failure would pass - fix: assert `mediator.grant()`/`mediator.level()` unchanged after the failed set, or rename the test - [tests/mediator.rs:13-24] - evidence: test body asserts two `assert_eq!)... Err)...))` and one readiness check; no grant/level state assertions - -## supply -- d2b-provider-audio-pipewire#13 sev=low blast=leaf effort=S verdict=actionable - Cargo.toml declares `schemars` as a runtime dependency with zero uses in src or tests, and `serde_json` (tests-only, 12 hits) sits in `[dependencies]` instead of `[dev-dependencies]` - fix: drop the `schemars` entry and move `serde_json` to `[dev-dependencies]` (Cargo.toml:24-25) - [Cargo.toml:24, Cargo.toml:25] - evidence: census `schemars` over src/ + tests/ = 0 hits (manifest only); `serde_json` over src/ = 0, tests/ = 12 hits; per-crate supply note, lens owned by lane X1 - -## Coverage -- idiom: clean (seeds: 0/1/0; single deliberate Default) -- own: clean (seeds: 9/7/1/0 over src+tests; all clones explainable) -- type: 2 finding(s) -- api: 3 finding(s) -- err: 2 finding(s) -- serde: clean (seeds: 4/6/0/0; wire shapes pinned) -- obs: clean (seeds: 0/1/0/1; named-field events only) -- docs: 3 finding(s) -- perf: clean (seeds: 1/3/0; cold paths only) -- conc: clean (seeds: 0/1/3/0; 3 false positives, 1 justified shared arbiter) -- async: clean (seeds: 0/0/2/0; synchronous crate, try_lock-only) -- unsafe: N/A (seeds: 0/0/2/0; both hits are from_raw_os_error safe calls; manifest forbid) -- ffi: N/A (seeds: 0/0/0/0) -- macro: N/A (seeds: 0/0/0/0) -- test: 2 finding(s) -- supply: 1 finding(s) (directly evidenced manifest note; lens owned by X1) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md deleted file mode 100644 index 54d174826..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p1.md +++ /dev/null @@ -1,93 +0,0 @@ -# d2b-provider-clipboard-wayland-p1 - d2b-provider-clipboard-wayland - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6771 (excl. src/generated/**) | modules: bin/d2b-clipd.rs, fd.rs, runtime.rs, audit.rs, policy.rs, lib.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/bin/**, src/fd.rs, src/runtime.rs, src/audit.rs, src/policy.rs, src/lib.rs - -## idiom -- d2b-provider-clipboard-wayland-p1#1 sev=medium blast=leaf effort=S verdict=actionable - d2b-clipd hand-rolls CLI flag parsing with a manual loop while every other binary in the repo uses clap derive - fix: replace parse_args with a clap::Parser derive on Args (clap is the house pattern in d2bd/src/main.rs, d2b/src/dispatch.rs, d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs), which also fixes --help exiting 2 via Err - [src/bin/d2b-clipd.rs:3815, src/bin/d2b-clipd.rs:127] - evidence: census: clap::{Parser,Args} over packages = 3+ binaries (d2bd/src/main.rs:3, d2b/src/dispatch.rs:21, d2b-provider-display-wayland/src/bin/d2b-wayland-proxy.rs:23); seed `let mut \w+ = (String|Vec)::new\(\)` 12 hits, all legitimate byte/bounded loops -- d2b-provider-clipboard-wayland-p1#2 sev=low blast=leaf effort=S verdict=actionable - should_suppress_published_selection_echo takes two unused parameters and delegates to an identity wrapper that returns its argument unchanged - fix: return selection.suppress_selection_echo directly, drop the _window and _bridge_selection parameters and the two arguments at the call site, delete should_suppress_published_selection_echo_state - [src/bin/d2b-clipd.rs:3776, src/bin/d2b-clipd.rs:3787, src/bin/d2b-clipd.rs:2113] - evidence: static: wrapper body is `suppress_selection_echo` returned verbatim; census: both functions in-file only (def 3776/3787, call 2113, test 4022) = 4 hits over packages/ -- d2b-provider-clipboard-wayland-p1#3 sev=low blast=leaf effort=S verdict=actionable - install_bridge_listeners builds a Vec with a push loop where the body is a pure Result-producing map - fix: collect the iterator: bridge_peers.into_iter().map(|peer| { ... Ok(BridgeListener { ... }) }).collect::, String>>()? - [src/bin/d2b-clipd.rs:1131] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` 12 hits; site matches the statement-accumulation shape the seed names -- d2b-provider-clipboard-wayland-p1#14 sev=medium blast=leaf effort=S verdict=actionable - preferred_mime_order hardcodes the four MIME strings that policy.rs ALLOWED_MIME_TYPES already owns, keeping the reported MIME-policy triplication alive (row S79, reported not consolidated) - fix: iterate d2b_provider_clipboard_wayland::ALLOWED_MIME_TYPES in preferred_mime_order instead of the literal list, so allowlist changes propagate to the preference order - [src/bin/d2b-clipd.rs:2812, src/policy.rs:12] - evidence: census: the four MIME literals appear at policy.rs:12-17 (ALLOWED_MIME_TYPES), d2b-clipd.rs:2812-2816 (preferred_mime_order), and clipd_host policy (part 2 scope); row S79 at docs/explanation/over-engineering-audit-record.md:394 records the triplication as reported-not-consolidated, and the site still matches -- clean: seeds ran: `for \w+ in 0\.\.` 3 (bounded drain and tests), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` 1 (Policy Default preserves constructor invariants, deliberate), `let mut \w+ = (String|Vec)::new\(\)` 12 (byte reads and bounded loops); no other hand-written impls, naming drift, or conversion smells found - -## own -- clean: seeds ran: `\.clone\(\)` 75, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` 165, `Rc<|RefCell<|Arc with format!-built messages at 13 signatures, where the skill names anyhow for binaries - fix: introduce anyhow at the binary top level (run and its helpers), keeping the lib error enums unchanged - [src/bin/d2b-clipd.rs:127, src/bin/d2b-clipd.rs:411, src/bin/d2b-clipd.rs:247] - evidence: seed `enum \w*Error` 6 hits (lib enums ClipboardRuntimeError, FdSafetyError, FdReadError, ClipboardPolicyError are well-shaped); static: 13 `Result<..., String>` signatures in the binary; no caller string-matches these errors today, hence low -- clean: seeds ran: `\.unwrap\(\)|\.expect\(` 78 (77 test/startup, 1 finding above), `let _ = |\.ok\(\);` 32 (best-effort cleanups: cancel_picker, cancel_active, tx.send, remove_file; judged per site), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` 4 (all in tests), `enum \w*Error` 6 (lib enums split by caller action, Display is the pinned wire code) - -## serde -- d2b-provider-clipboard-wayland-p1#7 sev=medium blast=leaf effort=M verdict=actionable - the daemon config is parsed as serde_json::Value and read through hand-rolled .pointer() lookups with per-field error strings, instead of a typed Deserialize struct that validates at the boundary - fix: define a typed ClipdConfig with #[serde(deny_unknown_fields)] (picker.executable, runtime.bridgeEndpoints with try_from for WorkloadTarget::parse) and deserialize once in run(); the JSON shape is unchanged, so the Nix producer keeps working - [src/bin/d2b-clipd.rs:132, src/bin/d2b-clipd.rs:247] - evidence: seed `serde_json::from_|serde_json::to_` 8 hits; census: config shape produced by nixos-modules nix/site.nix:69-136 (bridgeEndpoints, picker.executable) and pinned by tests at d2b-clipd.rs:4346; the pointer plumbing spans 70+ lines (247-316) that a derive replaces -- clean: seeds ran: `derive\([^)]*(De)?[Ss]erialize` 3, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` 3, `impl .*Deserialize.*for` 0, `serde_json::from_|serde_json::to_` 8; BridgeFrame, BridgeAttribution, and ControlFrame are tagged enums with deny_unknown_fields and rename_all, and parse_bridge_frame validates identity and attribution after the parse (the correct admission-gate shape); no hand-written deserializers - -## obs -- d2b-provider-clipboard-wayland-p1#8 sev=medium blast=leaf effort=M verdict=actionable - the binary logs through the log facade with interpolated message strings (62 sites) while the crate's lib uses tracing with named fields, giving one crate two facades and unqueryable events - fix: migrate d2b-clipd.rs to tracing (already a dependency, used by runtime.rs) with named fields, e.g. log::info!("d2b-clipd: ready (config={}, ...)") becomes tracing::info!(config = %args.config.display(), bridge_root = %args.bridge_root.display(), "d2b-clipd ready") - [src/bin/d2b-clipd.rs:206, src/bin/d2b-clipd.rs:1627, src/runtime.rs:100] - evidence: seed `(info|debug|warn|error|trace)!\("` 40 hits (35 in the binary, 5 in runtime.rs); `tracing::|log::` 76 hits split 62 log:: in the binary vs 14 tracing:: in runtime.rs; `\.instrument\(|#\[instrument` 0, so no span carries the context the interpolated messages duplicate -- clean: seeds ran: `\bprintln!\(|\beprintln!\(` 2 (main's user-facing error path and check-config output, product output per the card), `(info|debug|warn|error|trace)!\("` 40 (runtime.rs events carry named fields, e.g. error = %e; the binary's 35 are the finding above), `\.instrument\(|#\[instrument` 0, `tracing::|log::` 76; no secret or clipboard payload is logged (module doc at d2b-clipd.rs:7 and redaction tests confirm), and AcceptDiagnostics::warn builds messages lazily in a closure - -## docs -- d2b-provider-clipboard-wayland-p1#9 sev=medium blast=leaf effort=M verdict=actionable - Result-returning public items carry no # Errors sections anywhere in the crate despite deny(missing_docs), so failure contracts (ConcurrentLimitExceeded, InvalidBounds, AuditQueueFull, SessionUnauthenticated) are undocumented - fix: add # Errors sections naming the variants to the public Result-returning items, starting with FdPermitPool::acquire, Policy::new, ClipboardAuditQueue::push, and ClipboardRuntime::admit_route - [src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97] - evidence: seed `-> Result<` 69 hits (31 bin, 13 fd, 19 runtime, 4 audit, 2 policy); `/// # (Examples|Errors|Panics|Safety)` 0 hits; first sentences are otherwise one-line and contract-shaped -- d2b-provider-clipboard-wayland-p1#10 sev=medium blast=family effort=S verdict=actionable - ClipboardAuditEvent::to_wire derives wire labels from Debug impls (format!("{:?}", event_type) lowercased and size_bucket via {:?}) instead of stable as_str labels, so a variant rename silently changes the cross-crate audit record consumed by d2bd - fix: add as_str() to ClipboardEventType and SizeBucket returning the exact current renderings ("pasteauthorized", "Lt1K", ...) and use them in to_wire - [src/audit.rs:172, src/audit.rs:174] - evidence: seed `format!\(` 77 hits; static: event_type and size_bucket render via Debug at audit.rs:174-178 while reason uses ClipboardReason::as_str; census: the wire record is consumed by d2bd/src/interaction_composition.rs:4701 and asserted in tests/provider_behavior.rs:88 and tests/redaction.rs:23 -- clean: seeds ran: `^\s*pub (fn|struct|enum|trait|const|type)` 99 (all documented, missing_docs denied at lib.rs:3), `/// # (Examples|Errors|Panics|Safety)` 0 (finding above), `-> Result<` 69 (finding above); module docs present in all five modules; no doctests marked ignore - -## perf -- d2b-provider-clipboard-wayland-p1#11 sev=low blast=leaf effort=M verdict=actionable - clipboard payload maps (up to MATERIALIZE_MAX_BYTES = 8 MiB) are cloned wholesale on the host-selection record, history materialization, and bridge-copy publish paths, copying every byte per paste - fix: hold payloads as Arc>> (or Arc<[u8]> per MIME) in ClipboardHistoryEntry, BridgeSelectionState, and PublishedSelectionState so materialization and publish become refcount bumps; the history-retention clones at 757 and 1043 disappear - [src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2b-clipd.rs:1838, src/bin/d2b-clipd.rs:2797] - evidence: static (unmeasured); seed `\.clone\(\)` 75 hits; the six full-map clones (757, 1043, 1833, 1838, 2797, 2803) copy the entire payload, bounded at 8 MiB per item by policy.rs:114 -- clean: seeds ran: `format!\(` 77 (error paths, one-shot diagnostics, and wire rendering, all cold), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 49 (bounded reads and empty-case collections), `\.to_string\(\)` 14 (boundary copies and Display-free labels); no format! in a loop over payload data, no attacker-controlled hashing, no collection-choice problems found - -## conc -- d2b-provider-clipboard-wayland-p1#12 sev=low blast=leaf effort=S verdict=actionable - the two permit counters use Acquire/AcqRel orderings where Relaxed is the weakest correct ordering, since neither counter publishes any data (the permit and descriptor ownership move by value) - fix: switch FdPermitPool.active and HELPER_THREADS to Ordering::Relaxed for load, CAS, and fetch_sub - [src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96] - evidence: seed `Atomic\w+|Ordering::` 24 hits (fd.rs 10, bin 14); static: no paired handoff through either counter, so the acquire/release pairs synchronize nothing -- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` 5 (named worker threads with mpsc handoff, the channel model the skill prefers), `\bMutex<|\bRwLock<` 2 (test-only serialization locks with documented reasons), `Atomic\w+|Ordering::` 24 (counters, finding above), `thread_local!|unsafe impl (Send|Sync) for` 0; no shared-state deadlock surface, no static mut - -## async -- N/A: seeds `async fn|async move|\.await` 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` 0, `tokio::sync::(Mutex|RwLock|Notify)` 0, `#\[tokio::(main|test)\]|Runtime::block_on` 0 over the scope; the binary is deliberately synchronous (poll loop plus worker threads, documented at d2b-clipd.rs:120-122) and the lib has no async fn, so the lens criteria fail - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0, `// SAFETY:` 0, `transmute|from_raw|MaybeUninit|mem::zeroed` 6 raw matches all false positives (from_raw_os_error at d2b-clipd.rs:2534 and FileType::from_raw_mode at fd.rs:242), `unsafe_code` 1 (the `#![forbid(unsafe_code)]` attribute at lib.rs:4, which per the card does not make the lens applicable); no unsafe blocks or unsafe_code allow manifests in the scope - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` 0, `catch_unwind` 0, `repr\(C\)|repr\(transparent\)` 0, `CStr|CString|c_char` 0 over the scope; the crate crosses no foreign boundary (rustix/nix syscall wrappers stay in their own crates) - -## macro -- N/A: seeds `macro_rules!` 0, `proc_macro|syn::|quote!` 0, `\$crate` 0, `to_compile_error|new_spanned` 0 over the scope; the crate defines no macros - -## test -- d2b-provider-clipboard-wayland-p1#13 sev=medium blast=leaf effort=S verdict=actionable - published_selection_echo_is_always_suppressed_once asserts the identity wrapper should_suppress_published_selection_echo_state, a forwarding pin that fails only if the wrapper's triviality changes - fix: delete the test together with the wrapper (idiom finding #2); the behavior it gestures at is already covered by bridge_selection_echo_suppression_persists_for_source_vm_or_unknown_focus - [src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787] - evidence: seed `#\[test\]|#\[tokio::test\]` 61 hits; `#\[ignore\]` 0; the test body asserts `should_suppress_published_selection_echo_state(true)` and `(false)`, i.e. the wrapper's forwarding, not observable behavior -- clean: seeds ran: `#\[test\]|#\[tokio::test\]` 61, `assert_eq!\(|assert_ne!\(|assert!\(` 139, `proptest!|insta::assert|rstest` 0, `#\[ignore\]` 0; the sampled tests assert observable behavior (frame parsing, fd queue limits, echo suppression, timeout and size-exceeded errors, umask restoration) with human-written expectations; error-code Display assertions in fd.rs:681 pin the wire codes recorded in docs/specs/providers/ADR-046-provider-clipboard-wayland.md:1091-1095, so they are contract pins, not implementation pins; tests/ is outside this part's partition (part 2 covers the remaining src modules) - -## Coverage -- idiom: 4 finding(s) -- own: clean (seeds ran: 75/165/0/0) -- type: 1 finding(s) -- api: clean (seeds ran: 99/0/8) -- err: 2 finding(s) -- serde: 1 finding(s) -- obs: 1 finding(s) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: 1 finding(s) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn, await, spawn, or tokio sync types in scope; binary is a sync poll loop by design) -- unsafe: N/A (seeds: 0/0/6-false-positive/1-forbid-attribute; no unsafe blocks, SAFETY comments, or unsafe_code allow manifests in scope) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros defined) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md deleted file mode 100644 index 61d6c5945..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-clipboard-wayland-p2.md +++ /dev/null @@ -1,106 +0,0 @@ -# d2b-provider-clipboard-wayland-p2 - d2b-provider-clipboard-wayland - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6716 (excl. src/generated/**) | modules: clipd_host/**, service/mod.rs, history.rs, controller/mod.rs, picker.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f) - -## idiom -- d2b-provider-clipboard-wayland-p2#1 sev=medium blast=leaf effort=M verdict=actionable - MIME policy is duplicated in two modules with divergent semantics: clipd_host/policy.rs normalizes by splitting on ';' and carries a 7-entry secret-hint list, while crate::policy.rs normalizes by trim+lowercase only and carries a 3-entry list, so the same MIME string ("Text/Plain ; Charset=UTF-8") is admitted by the host Wayland path and rejected by the guest history path, and secret hints diverge (application/x-secret-service is a hint on the host side only) - fix: make crate::policy the single canonical MIME module and have clipd_host::policy delegate to it for ALLOWED_MIME_TYPES, SECRET_HINT_MIME_TYPES, and normalize_mime - [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:91-97, packages/d2b-provider-clipboard-wayland/src/policy.rs:3-14, packages/d2b-provider-clipboard-wayland/src/policy.rs:91-93] - evidence: manual cross-module read; both modules define ALLOWED_MIME_TYPES/SECRET_HINT_MIME_TYPES/normalize_mime; clipd_host/policy.rs:107 test pins "Text/Plain ; Charset=UTF-8" as allowed while crate::policy::normalize_mime keeps the space and rejects it; secret lists differ (7 vs 3 entries) -- d2b-provider-clipboard-wayland-p2#2 sev=low blast=leaf effort=S verdict=actionable - two distinct PickerError enums in one crate (crate::picker::PickerError for receipt minting and crate::clipd_host::picker::PickerError for the subprocess supervisor) share a name, which reads as one type in errors and imports - fix: rename the clipd_host one (e.g. PickerIpcError) or move the supervisor module under a distinct name - [packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:113-126] - evidence: seed `enum \w*Error` = 8 hits; two PickerError definitions at src/picker.rs:11 and src/clipd_host/picker.rs:113 -- d2b-provider-clipboard-wayland-p2#3 sev=low blast=leaf effort=S verdict=actionable - read_bounded_ndjson_line has two adjacent match arms with identical behavior (`Ok(0) if line.is_empty()` and `Ok(0)` both return NiriIpcError::Incomplete), a redundant guard that suggests a distinction that does not exist - fix: collapse to a single `Ok(0) => return Err(NiriIpcError::Incomplete)` arm - [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:144-146] - evidence: seed `for \w+ in 0\.\.` = 0; manual read of the match at niri.rs:143-158 -- d2b-provider-clipboard-wayland-p2#4 sev=low blast=leaf effort=S verdict=actionable - FallbackArming implements Default by hand for a single-field struct whose only field defaults to FallbackState::Idle; a derive would stay in sync with the enum - fix: `#[derive(Default)]` on FallbackArming plus `#[derive(Default)]` with `#[default]` on FallbackState::Idle, delete the impl - [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:5-12] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits (fallback.rs:40, framing.rs:15, service/mod.rs:1293); the other two are justified (nonzero defaults) -- d2b-provider-clipboard-wayland-p2#5 sev=low blast=leaf effort=S verdict=actionable - ReasonCode::as_str is a hand-written match that duplicates the `#[serde(rename_all = "snake_case")]` label mapping on the same enum, giving two sources of truth for the wire label that can drift - fix: derive the label once (e.g. a const table or serde serialization) and have as_str return it - [packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:45-68] - evidence: seed `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 6 hits; as_str match at policy.rs:45-68 mirrors the rename_all at policy.rs:21 - -## own -- d2b-provider-clipboard-wayland-p2#6 sev=low blast=leaf effort=S verdict=actionable - finalize_selection clones pending.mimes into all_mimes only to compute has_secret before consuming the Vec by into_iter; the borrow of pending.mimes ends before the move, so the clone is avoidable - fix: compute `has_secret_hint(pending.mimes.iter().map(String::as_str))` first, then `pending.mimes.into_iter().filter(...)` - [packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263] - evidence: seed `\.clone\(\)` = 56 hits over the lane; wayland.rs:257 clone is followed by into_iter at wayland.rs:260 with no intervening mutation -- clean: seeds `\.clone\(\)` = 56, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 118, `Rc<|RefCell<|Arc but the body is an unconditional Ok, so the error arm and the map_err at ClipdHost::new (with its warn) are dead code that misleads callers into handling an impossible failure - fix: return Self from new and drop the map_err in ClipdHost::new - [packages/d2b-provider-clipboard-wayland/src/history.rs:137-147, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:575-579] - evidence: seed `\.unwrap\(\)|\.expect\(` = 44 hits (40 in cfg(test), 4 justified production invariants); manual read of new body -- d2b-provider-clipboard-wayland-p2#12 sev=low blast=leaf effort=S verdict=actionable - PickerSupervisor collapses the typed FramingError into PickerError::Frame(String) via to_string() at six sites, so callers cannot distinguish FrameTooLong from Incomplete from a JSON error without string matching - fix: add a `Frame(FramingError)` variant (with #[from] or #[source]) and map the framing errors into it - [packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:262, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:274, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:284, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:290, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:320, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:325] - evidence: seed `let _ = |\.ok\(\);` = 4 hits (all deliberate: write! to a String, best-effort flush, best-effort audit push); manual read of the six Frame(String) construction sites -- clean: `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0; production unwrap/expect sites (service/mod.rs:138,171 after is_none_or checks; clipd_host/picker.rs:242,332 after explicit option checks) are justified invariants - -## serde -- d2b-provider-clipboard-wayland-p2#13 sev=low blast=leaf effort=S verdict=actionable - AuditEvent.mime_type carries `serialize_with = "serialize_bounded_mime"` but no deserialize_with, so the round trip is asymmetric: serialization truncates long MIME values at 64 bytes while deserialization accepts unbounded values, and the type still derives Deserialize - fix: add a matching deserialize_with (or drop Deserialize from AuditEvent if it is never read back) - [packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:13, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:43-49] - evidence: seed `derive\([^)]*(De)?[Ss]erialize` = 29 hits; census: AuditEvent is only ever serialized (bin/d2b-clipd.rs:2030-2033), never deserialized -- clean: internal-tag enums with rename_all (protocol.rs:88-101) and deny_unknown_fields on client-to-daemon messages with deliberate tolerance on daemon-to-picker messages (pinned by tests protocol.rs:257-262, 264-295) match the card's per-type decision; NiriEvent's hand-written Deserialize is a live tolerant admission gate for niri's evolving JSON, not a finding - -## obs -- d2b-provider-clipboard-wayland-p2#14 sev=low blast=leaf effort=M verdict=actionable - clipd_host log events use interpolated messages instead of named fields (attribution, mime count, secret flag, error values are formatted into the message), so the events are not queryable by field - fix: convert to structured fields, e.g. log::debug!(quality = ?attribution.quality, mimes = allowed_mimes.len(), secret = has_secret, "host selection changed") - [packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:64-68, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:489, packages/d2b-provider-clipboard-wayland/src/clipd_host/notifications.rs:24, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:60, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:66, packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:552] - evidence: seed `(info|debug|warn|error|trace)!\("` = 7 hits, all interpolated with no named fields -- d2b-provider-clipboard-wayland-p2#15 sev=low blast=leaf effort=M verdict=actionable - the package mixes two logging facades: clipd_host (and the bin) emit via log:: while service/mod.rs emits via tracing::, so events from the two halves do not share spans or filters - fix: pick tracing for the whole package (tracing has a log bridge) and convert the clipd_host log:: calls - [packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:81, packages/d2b-provider-clipboard-wayland/src/service/mod.rs:577] - evidence: seed `tracing::|log::` = 30 hits split across both facades; no #[instrument] or .instrument anywhere (seed 3 = 0) -- clean: `\bprintln!\(|\beprintln!\(` = 0 in the lane scope; no secret values are logged (host.rs:64-68 logs attribution quality and counts only); the ADR 0010/0028 redaction gate is not implicated - -## docs -- d2b-provider-clipboard-wayland-p2#16 sev=low blast=leaf effort=S verdict=actionable - ClipboardEntry::bytes is documented as "Return a bounded copy for an already-authorized materialization" but returns &[u8], contradicting the copy claim and the as_/to_/into_ cost convention - fix: reword to "Borrow the payload bytes for an already-authorized materialization" - [packages/d2b-provider-clipboard-wayland/src/history.rs:112-115] - evidence: seed `-> Result<` = 62 hits; manual read of the doc line -- d2b-provider-clipboard-wayland-p2#17 sev=low blast=leaf effort=M verdict=actionable - the clipd_host IPC and state surface is largely undocumented: niri.rs (read_bounded_ndjson_line, encode_niri_request, decode_niri_response, NiriStateCache methods, FocusedWindowProvider trait, HostClipboardAttributor methods), wayland.rs (DataControlOffer::destroy, DataControlSource::offer_mime), picker.rs (launch's returned &UnixStream borrow, poll_active's nonblocking contract, reap_expired, reap_terminated), host.rs (refresh_focused_window_snapshot) - fix: add doc comments stating the blocking/ownership contracts (which calls block, who destroys protocol objects, what the returned borrow is) - [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:128, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:162, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:336-337, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:424-427, packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:79-81, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:204-242, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:248-249] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 150 hits; `/// # (Examples|Errors|Panics|Safety)` = 0 hits; missing_docs is not enabled for the bin target that compiles clipd_host -- d2b-provider-clipboard-wayland-p2#18 sev=low blast=leaf effort=S verdict=actionable - magic constants lack the why: ENVELOPE_BYTES/JSON_STRING_ESCAPE_EXPANSION in the frame-budget math, PICKER_TERMINATE_GRACE (250ms), MAX_AUDIT_MIME_BYTES (64), DEFAULT_NIRI_MAX_LINE_BYTES (1 MiB) - fix: document the derivation or the upstream constraint each constant encodes - [packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:74, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:7] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 150 hits; manual read of the four constants - -## perf -- d2b-provider-clipboard-wayland-p2#19 sev=low blast=leaf effort=M verdict=actionable - read_bounded_ndjson_line reads one byte per read() syscall in a loop (up to DEFAULT_NIRI_MAX_LINE_BYTES = 1 MiB iterations for a maximal line), an avoidable syscall-per-byte pattern on the niri IPC path - fix: read into a stack chunk buffer (e.g. 4 KiB) with the same max-line accounting, or wrap the stream in a BufReader - [packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159] - evidence: static (unmeasured); seed `format!\(` = 13 hits, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 21 hits; the loop at niri.rs:142-158 issues one read per byte -- clean: remaining format!/to_string sites are cold (error paths, per-operation digests, notification text, one-shot picker argv), and collection news are bounded structures or empty-case defaults - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 5, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; the thread hits are cfg(test) socketpair harnesses (niri.rs:602,632,663) and the sanctioned CLI-only paste-replay sleeps (virtual_keyboard.rs:83,89, each with a disallowed-methods allow, reason "CLI-only path"); no production locks, atomics, or manual Send/Sync claims exist in the lane - -## async -- N/A (seeds: `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the lane is entirely synchronous, per the crate's CLI-daemon design documented at clipd_host/picker.rs:88-90 and niri.rs:48-51) - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 1, `unsafe_code` = 0; the single hit is a safe rustix Pid::from_raw constructor at clipd_host/picker.rs:57, not an unsafe block; the crate lib.rs carries #![forbid(unsafe_code)] and no unsafe exceptions exist in this lane) - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface in the lane) - -## macro -- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the only macros in the lane are wayland_client's delegate_noop!/event_created_child! invocations, which are generated-protocol helpers, not local definitions) - -## test -- d2b-provider-clipboard-wayland-p2#20 sev=medium blast=leaf effort=M verdict=actionable - the history eviction contract has no test: insert's LRU count bound (max_history_entries via evict_oldest) and byte-quota eviction (max_total_bytes via evict_until) are untested, as are materialize's owner and TTL rejections and entry_expiry - fix: unit tests in history.rs asserting eviction order and quota behavior (e.g. insert max_history_entries+1 entries and assert the oldest is evicted; fill past max_total_bytes and assert eviction down to quota) - [packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clipboard-wayland/src/history.rs:345-356, packages/d2b-provider-clipboard-wayland/src/history.rs:257-273] - evidence: seed `#\[test\]|#\[tokio::test\]` = 73 hits (64 in src, 9 in tests/); tests/provider_behavior.rs:46-61 covers TTL expiry and purge but not eviction; insert/evict_until/evict_oldest have no test that exercises them -- d2b-provider-clipboard-wayland-p2#21 sev=medium blast=leaf effort=M verdict=actionable - the controller's route-to-evidence admission gates (DisplayDependencyEvidence::from_authenticated_route and from_committed_display_route) have no tests even though from_committed_display_route is consumed by d2bd as the display-dependency authority input; only dependency_status is tested - fix: unit tests in controller/mod.rs exercising valid and each rejected route shape (wrong provider, wrong service, wrong evidence class, zero generations, wrong subject type) - [packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:144-201, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:360-371] - evidence: seed `#\[test\]|#\[tokio::test\]` = 73 hits; census: from_committed_display_route consumed at packages/d2bd/src/interaction_composition.rs:2041; no test constructs or rejects DisplayDependencyEvidence from a route -- d2b-provider-clipboard-wayland-p2#22 sev=low blast=leaf effort=S verdict=actionable - FallbackArming::cancel_picker (the PickerCancelled transition) and NiriStateCache's WindowClosed and WorkspaceActivated event paths have no tests, leaving two state transitions and two event handlers unverified - fix: extend the existing table-style tests in fallback.rs and niri.rs with the missing transitions - [packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:378-387, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:394] - evidence: seed `#\[test\]|#\[tokio::test\]` = 73 hits; fallback.rs tests cover capture/arm/focus/timeout/native-selection but not cancel_picker; niri.rs tests cover focus/window/workspaces but not WindowClosed or WorkspaceActivated -- clean: `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; assertions target behavior and error variants, not Display strings; the tests/ suite (223 LOC, 9 tests) covers config validation, redaction canaries, MIME policy, fd validation, and controller projections - -## Coverage -- idiom: 5 finding(s) -- own: 1 finding(s) -- type: 3 finding(s) -- api: 1 finding(s) -- err: 2 finding(s) -- serde: 1 finding(s) -- obs: 2 finding(s) -- docs: 3 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 5/0/0/0; threads only in cfg(test) harnesses plus the sanctioned CLI-only paste-replay sleeps with disallowed-methods allows) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn, .await, tokio, or spawn in the lane) -- unsafe: N/A (seeds: 0/0/1/0; the single hit is a safe rustix Pid::from_raw constructor, not an unsafe block; lib.rs forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero; only generated wayland_client helper invocations) -- test: 3 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md deleted file mode 100644 index c54b6f0fb..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-config-nixos.md +++ /dev/null @@ -1,82 +0,0 @@ -# d2b-provider-config-nixos - d2b-provider-config-nixos -Baseline: 6ebdd4cec | LOC audited: 1816 (src/ 1427, tests/ 389; excl. src/generated/**, none present) | modules: whole crate (lib, controller, service, ttrpc) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (whole crate) - -## idiom -- d2b-provider-config-nixos#1 sev=low blast=leaf effort=S verdict=actionable - the path-component rejection walk is written twice with identical rules, and the two copies can drift (one checks, one checks and collects) - fix: extract one helper classifying `Path::components()` into `Result, ConfigError>` (reject `CurDir`/`ParentDir`/`Prefix`) and call it from both `validate_reader_path` and `read_bounded_file` - [packages/d2b-provider-config-nixos/src/ttrpc.rs:379-386, packages/d2b-provider-config-nixos/src/ttrpc.rs:414-421] - evidence: seeds 0/0/1 (`let mut components = Vec::new()` at ttrpc.rs:414 plus the loop); both walks read in full -- clean: hand-written `Debug` impls (controller.rs:99-119, 120-131, ttrpc.rs:40-49, 160-164) redact secret fields and are the deliberate-derive-exclusion class; naming (`as_str`, `ALL`, no `get_`) is consistent; no index loops over `0..n` - -## own -- d2b-provider-config-nixos#2 sev=low blast=leaf effort=S verdict=actionable - `ConfigService::validate_operation` clones the whole JSON payload per request (`serde_json::from_value::(payload.clone())`, 6 arms) - up to `MAX_CONFIG_ENCODED_BYTES` (~683 KiB base64 limit) per Stage/ReadGuestConfig admission on the async polling worker, when `serde` can deserialize borrowed: `T::deserialize(payload)` works on `&serde_json::Value` - fix: replace the 6 `from_value(payload.clone())` calls with `T::deserialize(payload)` (or change the signature to take `Value` by value and clone once at the single call site) - [packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/controller.rs:304, packages/d2b-provider-config-nixos/src/controller.rs:311, packages/d2b-provider-config-nixos/src/controller.rs:318, packages/d2b-provider-config-nixos/src/controller.rs:325, packages/d2b-provider-config-nixos/src/controller.rs:331] - evidence: seed `\.clone\(\)` = 19 hits in src (6 here; the rest are guest_ref copies into owned responses and test fixtures, each explainable); `Arc` sharing (ttrpc.rs:126, 267, 315) is genuine multi-handler/worker ownership with the daemon caller at d2bd/src/composition.rs:4718 -- d2b-provider-config-nixos#3 sev=low blast=leaf effort=S verdict=actionable - `GuestConfigReader::dispatch` copies the just-validated document bytes (`document.bytes().to_vec()`, up to 512 KiB per guest read on the dedicated worker) only so `read_guest_config` can re-validate the already-valid `GuestConfigDocument` - fix: give `GuestConfigDocument` a consuming accessor (`into_bytes()` or `impl From for Vec`, `bytes` field stays private) and pass it straight into the `impl Into>` parameter - [packages/d2b-provider-config-nixos/src/ttrpc.rs:111, packages/d2b-provider-config-nixos/src/controller.rs:106] - evidence: seed `\.to_vec\(\)` = 1 prod hit; copy bound is static (MAX_CONFIG_BYTES = 512 KiB, service.rs:15) -- clean: `GUEST_CONFIG_IDENTIFIER.to_owned()` in 7 constructors, `guest_ref.clone()` into owned responses, `sha256.clone()` into the approval receipt, and the test fixture clones are each the cheapest correct ownership move; no `Rc`/`RefCell`/`Cow`/`Arc` in production code - -## type -- d2b-provider-config-nixos#4 sev=low blast=leaf effort=M verdict=actionable - stringly-typed request fields (`identifier`, `against`, `destination`) are re-validated at every entry (constructors, store methods, and `validate_operation`), and the duplicated guest-ref checks have already drifted: `ConfigSyncRequest::new` checks only the resource type while `validate_guest_ref` also requires a non-empty name, so "Guest/" passes the constructor yet fails the boundary - fix: parse-once request fields (private fields, `new()`/`try_from` as the only constructors, transparent serde keeps the wire JSON unchanged) so the per-entry `validate_*` calls collapse; align `ConfigSyncRequest::new` with `validate_guest_ref` - [packages/d2b-provider-config-nixos/src/service.rs:31-34, packages/d2b-provider-config-nixos/src/service.rs:300-306, packages/d2b-provider-config-nixos/src/service.rs:316-323, packages/d2b-provider-config-nixos/src/service.rs:326-336] - evidence: seed `fn validate_\w+` = 6 hits (validate_operation, validate_guest_ref, validate_identifier, validate_view_identifier, validate_destination, validate_reader_path), each with 2-3 call sites; `is_\w+: bool` and `(mode|kind|state): String` = 0; identifier stays a wire field (forward-compat token), no `needs-contract` claim - -## api -- d2b-provider-config-nixos#5 sev=low blast=wide effort=S verdict=actionable - `decode_document` (service.rs:296-298) is a public one-line forwarder duplicating the already-public `ConfigSyncResponse::document()`, giving two API paths for one operation - fix: drop the export and call `.document()` at the one live caller (d2bd/src/composition.rs:11585), or privatize `document()` and keep the named helper - [packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-nixos/src/lib.rs:22] - evidence: census: `decode_document` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 3 hits (lib.rs:22 re-export, service.rs:296 definition, composition.rs:11585 caller); `ConfigNixosClient` (composition.rs:11571), `GuestConfigReader` + `create_ttrpc_services` (composition.rs:4711-4720) and `ConfigStagingStore` (composition.rs:578, 29824) all have live daemon callers - per assignment, do not re-flag the policy status (provider_crate_policy.rs:21 lists config-nixos as non-provider-prefixed; finding 6 elsewhere owns it) -- clean: `Arc` in `create_ttrpc_services` is genuine shared ownership (6 method handlers + one dispatch worker share the backend; caller wraps `Arc::new` at composition.rs:4718); single-path re-export of the whole surface from lib.rs; no dependency types leak; `ConfigServiceBackend` is a one-required-method trait - -## err -- d2b-provider-config-nixos#6 sev=low blast=leaf effort=S verdict=actionable - `invalid_status()` maps client-side request-encoding failures to ttrpc `INVALID_ARGUMENT` plus the `config-document-encoding-failed` code, telling the caller their request was invalid when the client implementation failed to serialize - fix: map that site to `INTERNAL` (or reuse `rpc_error(ConfigError::EncodingFailed)`) so status class matches the code - [packages/d2b-provider-config-nixos/src/ttrpc.rs:372-376, packages/d2b-provider-config-nixos/src/ttrpc.rs:189] - evidence: seed `\.unwrap\(\)|\.expect\(` = 16 hits: 2 in production (ttrpc.rs:133, 194), both `expect("canonical config operation prefix")` on constant `ConfigOperation::as_str()` output (false-positive class); the rest are `#[cfg(test)]`; 1 `panic!` (ttrpc.rs:548, test); 2 `let _ =` (ttrpc.rs:282 deliberate panic-safe send documented inline, ttrpc.rs:493 test) -- clean: `ConfigError` is a 12-variant taxonomy split by caller action with stable `code()` strings, `Display` = code, and a clean `rpc_error` mapping (ttrpc.rs:360-376); codes are provider-local (no hits in docs/reference/error-codes.md or tests/golden/), so no wire contract is pinned - -## serde -- clean: seeds 10/20/0/11 (10 `derive)...Serialize...JsonSchema)` types, 20 `serde(rename_all/deny_unknown_fields)` attributes, 0 hand-written `Deserialize`, 11 `serde_json::from_/to_` sites). Every DTO is `rename_all = "camelCase"` + `deny_unknown_fields`, the derive-based admission gate at the RPC boundary is the deliberate pattern, bounds are re-applied after decode (`ConfigSyncResponse::document`, `ConfigStageRequest::document`), and round-trips are exercised via `validate_operation` in tests/service_contract.rs - -## obs -- clean: seeds 0/22/0/22 (0 `println!`/`eprintln!`, 22 tracing events, 0 `.instrument`, 22 `tracing::` uses). Every event uses named fields (`resource`, `operation`, `error`) under the consistent `config-nixos ...` scheme; the message-only `debug!` rejection events in `read_bounded_file` (ttrpc.rs:444-466) sit under the boundary `warn!` that carries `resource` (ttrpc.rs:99-102); no secret or path text reaches a field (redaction tested in tests/redaction.rs); errors are logged once at the handling boundary - -## docs -- d2b-provider-config-nixos#7 sev=low blast=leaf effort=S verdict=actionable - none of the ~14 public `Result`-returning APIs carry a `# Errors` section, so callers cannot learn which `ConfigError` variants each returns without reading the implementation (lib.rs:6 denies missing_docs but only the one-liners exist) - fix: add `# Errors` to `GuestSessionEvidence::new`, `GuestConfigDocument::new`, `ConfigSyncResponse::document`, `ConfigStageRequest::document`, the five `ConfigStagingStore` methods, `GuestConfigReader::new`, and the two `ConfigService` methods - [packages/d2b-provider-config-nixos/src/controller.rs:45-64, packages/d2b-provider-config-nixos/src/service.rs:359-475, packages/d2b-provider-config-nixos/src/ttrpc.rs:52-72] - evidence: seeds 63/0/14 (63 public items, 0 canonical `# Examples`/`# Errors`/`# Panics`/`# Safety` sections, 14 `-> Result<` items); all first sentences are one-line and strong, docs otherwise exemplary - -## perf -- d2b-provider-config-nixos#8 sev=low blast=leaf effort=M verdict=actionable - the RPC path parses the request JSON up to three times per call: handler `from_slice` (ttrpc.rs:326), `validate_operation` `from_value` plus the full-document base64 decode for Stage (controller.rs:298-331), and the backend dispatch `from_value` again (ttrpc.rs:81); Stage payloads can reach ~683 KiB base64 - fix: decode the typed request once in `ConfigMethod::handler`, validate the typed value, and pass the original `Value` to the backend hop (removes one parse and the admission-time document decode) - [packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/ttrpc.rs:326, packages/d2b-provider-config-nixos/src/ttrpc.rs:81] - evidence: static (unmeasured); seeds: `format!\(` = 4 prod sites (crate-constant service strings and the sha256 prefix, all required), `Vec::new()` = 1 (cold path), `.to_string()` = 0; `read_bounded_file` already uses `with_capacity` (ttrpc.rs:452) - -## conc -- clean: seeds 0/1/0/0 (1 `Mutex<` - the `std::sync::Mutex>>` inside the `#[cfg(test)]` `ParkingBackend` at ttrpc.rs:483, a sanctioned `cfg(test) helper` with the recorded allow; 0 atomics, 0 `thread_local!`). The one production thread (`thread::Builder` at ttrpc.rs:241-248) is the R4 dedicated bounded worker with the `disallowed_methods` allow citing "dedicated bounded worker per plan R4" and a bounded `sync_channel` queue - cited, not re-flagged (U1 constraint d.2/d.4) - -## async -- clean: seeds 7/1/0/1 (3 `async fn`, 4 `.await`, 1 `select!`, 1 `#[tokio::test]`). The blocking guest-config read is correctly hoisted off the polling worker: `try_send` admission, `oneshot` reply, full queue maps to `Unavailable` (never parks the executor, never grows threads), the dropped-sender path is `map_err`-handled (ttrpc.rs:266-312) - the sanctioned R4 pattern; the `current_thread` parked-dispatch test (ttrpc.rs:509-558) proves the actual hazard; no lock held across `.await` - -## unsafe -- clean: seeds 0/0/1/1 - no `unsafe` blocks, fns, impls, or `extern`; crate-level `#![forbid(unsafe_code)]` (lib.rs:8) and manifest `unsafe_code = "forbid"`; the single seed-3 hit is `rustix::fs::FileType::from_raw_mode` (ttrpc.rs:442), a safe constructor whose name merely contains "from_raw" - false positive; crate is not in the U1 (d) 8 exception list, consistent - -## ffi -- clean: N/A (seeds 0/0/0/0 - no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString`/`c_char`; the ttrpc service registration is in-process proto dispatch, not a C ABI boundary) - -## macro -- clean: N/A (seeds 0/0/0/0 - no `macro_rules!`, proc-macro machinery, `$crate`, or `to_compile_error`/`new_spanned`; no macro use that a function cannot serve) - -## test -- d2b-provider-config-nixos#9 sev=medium blast=leaf effort=S verdict=actionable - `ConfigSyncResponse::document()`'s integrity contract (forged `sha256`/`bytes` mismatch must fail `EncodingFailed`, over-bound `content_base64` must fail `InvalidRequest`) is untested, and the daemon depends on this exact decode path (d2bd/src/composition.rs:11585) - fix: add integration tests that literal-construct a `ConfigSyncResponse` (fields are pub) with a wrong digest, a wrong byte count, and an over-`MAX_CONFIG_ENCODED_BYTES` payload and assert the failure codes - [packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixos/tests/config_lifecycle.rs:8-18] - evidence: seeds `#\[test\]|#\[tokio::test\]` = 9 tests, `assert*` = 43; none touch the integrity branch of `document()` (read via full scan of tests/) -- d2b-provider-config-nixos#10 sev=low blast=leaf effort=S verdict=actionable - no test exercises the `deny_unknown_fields` admission (an extra JSON key must make `validate_operation` fail `InvalidRequest`) or a payload with wrong field types (serde error path), which is exactly the typo-key case the attribute exists for - fix: extend `operation_validation_enforces_closed_identifiers_and_semantic_bounds` (tests/service_contract.rs:41-79) with an unknown-field payload and a wrong-typed payload - [packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixos/tests/service_contract.rs:41-79] - evidence: seeds `assert*` = 43, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the existing rejection tests cover semantic values only (wrong guest type, wrong identifier, non-digest view) -- clean: the 9 tests cover happy read, stale-session fail-closed, staging lifecycle, idempotent approval retry, zone isolation, unauthorized callers, path rejection, hardlink rejection, redaction, bounds, and the closed method surface; the parked-dispatch test (ttrpc.rs:509-558) asserts the real executor hazard; expectations are human-written, no network, no clock, seeded determinism holds - -## Coverage -- idiom: 1 finding -- own: 2 findings -- type: 1 finding -- api: 1 finding -- err: 1 finding -- serde: clean (seeds ran: 10/20/0/11) -- obs: clean (seeds ran: 0/22/0/22) -- docs: 1 finding -- perf: 1 finding -- conc: clean (seeds ran: 0/1/0/0) -- async: clean (seeds ran: 7/1/0/1) -- unsafe: clean (seeds ran: 0/0/1-false-positive/1; only `from_raw_mode` name collision and the `forbid` attribute) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary exists - ttrpc registration is in-process) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions or proc-macro machinery) -- test: 2 findings \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md deleted file mode 100644 index f66e062a5..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-entra.md +++ /dev/null @@ -1,75 +0,0 @@ -# d2b-provider-credential-entra - d2b-provider-credential-entra -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5,246 (src 2,655 + tests 2,591, excl. src/generated/**, none present) | modules: whole crate (lib.rs, controller.rs [audit.rs, telemetry.rs via #[path]], service.rs, main.rs; tests: common, canary, conformance, controller, delivery, entrypoint, faults, lifecycle, placement) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: single-part lane - -## idiom -- d2b-provider-credential-entra#1 sev=medium blast=family effort=M verdict=actionable - in-crate deadline trio (`operation_deadline`/`time_bound_instant`/`time_bounds_not_after`/`time_bound_instant_at`/`is_expired_unix_ms`) duplicates the toolkit's `credential::operation_deadline` with identical absolute-or-relative semantics; the family finding that folded this trio onto the toolkit was applied to secret-service but not here - fix: fold the trio onto `d2b_provider_toolkit::credential::{operation_deadline, deadline_remaining, now_unix_ms, is_absolute_unix_ms}` (keep the injectable-clock `time_bound_instant_at` only if the tests need it), deleting lib.rs:1164-1220 - [packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-entra/src/lib.rs:1172, packages/d2b-provider-credential-entra/src/lib.rs:1187, packages/d2b-provider-toolkit/src/credential.rs:111, docs/explanation/over-engineering-audit-record.md:872] - evidence: seeds 0/0/0; direct duplicate read at lib.rs:1164-1220 vs toolkit credential.rs:111-130; not-applied row U54 (over-engineering-audit-record.md:872) - site confirmed present at baseline -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the six hand-written `Debug` impls are secret-redacting (``) and deliberate, the hand-written `Display`/`Error` impls carry wire codes, and no index loops or statement-style accumulation exist - -## own -- clean: seeds `\.clone\(\)` = 31, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 11, `Rc<|RefCell<|Arc in Factory::new - genuine shared ownership; Pin> in the EntraFuture alias - required for the object-safe dyn client trait), seed 3 `pub use` = 1 (lib.rs:33, the house single-surface arm); all other pub items are consumed by main.rs, tests, or the toolkit runtime - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(` = 16 (every hit inside a `#[cfg(test)]` module - audit.rs:51, controller.rs:320-343, lib.rs:1363-1386, service.rs:786, telemetry.rs:50), `let _ = |\.ok\(\);` = 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 2 (EntraClientError, EntraProviderError - closed variants, Display strings are stable wire codes, mapped to CredentialServiceErrorCode in map_client_error); no panic site is reachable from caller input in src - -## serde -- N/A: seeds `derive\([^)]*(De)?[Ss]erialize` = 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 0; the crate crosses the wire only through `serde_json::json!` payload construction in GuestEntraClient (lib.rs:200-360) with no derives or deserializers of its own - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 35; every event uses named fields (`provider =`, `resource =`, `%error`, `operation =`) with lazy field expressions, errors are logged once at the mapping boundary (map_client_error lib.rs:1224), and no secret or identifier reaches a field (canary tests pin this) - -## docs -- d2b-provider-credential-entra#4 sev=low blast=leaf effort=S verdict=actionable - no public item carries a canonical `# Errors` section although ~30 pub items return `Result` (EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, reject_*); `#![deny(missing_docs)]` guarantees presence, not the failure contract - fix: add `# Errors` sections naming the returned error variant (e.g. InvalidConfig, InvalidPlacement, InvalidEndpoint, InvalidConsumer, DeadlineExceeded) to the Result-returning pub constructors - [packages/d2b-provider-credential-entra/src/controller.rs:47, packages/d2b-provider-credential-entra/src/lib.rs:502, packages/d2b-provider-credential-entra/src/lib.rs:565, packages/d2b-provider-credential-entra/src/lib.rs:1049] - evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 73 hits, seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits, seed 3 `-> Result<` = 30 hits; missing_docs is denied at lib.rs:7 so every pub item is documented, but zero canonical sections exist -- clean: module docs present on lib.rs, controller.rs, service.rs, audit.rs, telemetry.rs; pub-item docs are one-line contract sentences (no implementation narration, no design journals) - -## perf -- clean: seeds `format!\(` = 2 (both in `#[cfg(test)]` canary tests), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 3 (BTreeMap::new in construct lib.rs:875-877 - empty-case-common, bounded by MAX_LOCAL_LEASES), `\.to_string\(\)` = 0; no allocation site sits on a hot path; `to_canonical_string()` key computation is per-operation and bounded (static, unmeasured) - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 5 (four tokio::sync::Mutex maps + one std::sync::Mutex<()> mutation_gate), `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; the std Mutex is touched only via `try_lock` on the synchronous dispatch path (mutation_guard lib.rs:1152, no await), the tokio mutexes are async-aware, and the mutation-gate serialization is deliberate and test-pinned (concurrent_acquires_issue_once) - -## async -- clean: seeds `async fn|async move|\.await` = 101, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 4, `#\[tokio::(main|test)\]|Runtime::block_on` = 1 (tests/entrypoint.rs, with sanctioned allow); every client await is bounded by `tokio::time::timeout` via await_client (service.rs:742) or ensure_client_ready_async (service.rs:648), no guard is held across an await (statement-scoped locks), no blocking call sits in an async context, and cancellation ambiguity (uncommitted grants, Draining lifecycle) is deliberately designed and covered by faults.rs/lifecycle.rs - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; seed 4 `unsafe_code` = 1 is the `#![forbid(unsafe_code)]` attribute (lib.rs:8) which per the card does not make the lens applicable - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface exists in this crate - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros defined or used beyond std macros - -## test -- d2b-provider-credential-entra#5 sev=low blast=leaf effort=S verdict=actionable - `exact_consumer_guard_is_independent_of_request_fields` never exercises the guard its name claims: it only asserts that two `ResourceRef::parse` results differ, which can fail only if parsing collapses distinct inputs - fix: replace the body with an assertion on the actual guard (e.g. `provider.authorizes_consumer(&ResourceRef::parse("Provider/runtime-azure-container-apps").unwrap())` true and a different Provider ref false), or delete the test - [packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-entra/src/lib.rs:1362] - evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 50 hits, seed 2 `assert_eq!\(|assert_ne!\(|assert!\(` = 176 hits, seed 3 `proptest!|insta::assert|rstest` = 0, seed 4 `#\[ignore\]` = 0; body read at lib.rs:1361-1366 -- clean: the remaining suite asserts behavior and error codes (never Display strings), is deterministic (FakeEntraClient with injected state, no network, real-thread concurrency test with wakers, deadline test with a never-completing client and recv_timeout), and includes canary tests pinning that secrets never reach any rendered surface - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: 31/11/0/0) -- type: clean (seeds ran: 2/0/0) -- api: 2 finding(s) -- err: clean (seeds ran: 16 all cfg(test)/0/0/2) -- serde: N/A (seeds: 0/0/0/0 all zero; no serde derives or deserializers, json! payload construction only) -- obs: clean (seeds ran: 0/0/0/35) -- docs: 1 finding(s) -- perf: clean (seeds ran: 2/3/0) -- conc: clean (seeds ran: 0/5/0/0) -- async: clean (seeds ran: 101/0/4/1) -- unsafe: N/A (seeds: 0/0/0 all zero; only the forbid(unsafe_code) attribute, which does not make the lens applicable) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md deleted file mode 100644 index 04ad8c095..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-managed-identity.md +++ /dev/null @@ -1,88 +0,0 @@ -# d2b-provider-credential-managed-identity - d2b-provider-credential-managed-identity -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5439 (excl. src/generated/**: none) | modules: whole crate (agent, audit, controller, lib, service, telemetry; tests/*) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- clean: seeds ran: 0/0/0 (index loops, hand-written impl a derive may replace, statement-style accumulation); no hits; expression shapes all idiomatic. - -## own -- clean: seeds ran: 37/8/8/0; every clone/to_owned site read: Arcs clone only at `async move` boundaries to avoid borrowing self (lib.rs:210, lib.rs:251, lib.rs:280, lib.rs:309, lib.rs:338); owned constructs (checkpoint/lease/record building) genuinely need owned fields; restore_checkpoints clones the lease map wholesale to keep the original intact on early error (lib.rs:1344); no Cow; all explainable. - - - -## type -- d2b-provider-credential-managed-identity#1 sev=medium blast=leaf effort=S verdict=actionable - `ManagedIdentityTeardownPlan` exposes its three bools as pub fields, letting a caller construct invalid combos (`stop_agent && delete_agent`, `delete_agent && clear_provider_revoke` that `teardown_plan` never emits - fix: make the fields private with `pub const fn` accessors (or replace with an ordered stage enum); update the literal constructions in tests/binding.rs:1214-1234 - [controller.rs:85-89, tests/binding.rs:1214-1234] - evidence: static: seed 2 (`is_\w+: bool|\w+_flag: bool`) =0 but the pub bool triad at controller.rs:85-89 admits invalid states; literal constructions in tests/binding.rs:1214-1234 prove the surface constructible;`teardown_plan` (controller.rs:158-166)is the only in-crate producer and never emits them. - - - -## api -- d2b-provider-credential-managed-identity#2 sev=low blast=leaf effort=S verdict=actionable - `ManagedIdentityPlacement::in_zone` is an exact duplicate constructor of `new` with zero callers anywhere in the repo, doubling the public construction path - fix: delete `in_zone` (and its docs at lib.rs:611-618); `new` already validates and names the behavior - [lib.rs:612-618] - evidence: census: `in_zone\\(` over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel/*.bzl = definition-only (lib.rs:612); no caller; api seeds 86/0/2 (pub items/pub-internals-in-signatures/pub use; the pub use re-exports are the house single-surface pattern (lib.rs:40-45)). - -## err -- d2b-provider-credential-managed-identity#3 sev=low blast=leaf effort=S verdict=actionable - `export_checkpoints` panics via `.expect("lease map keys are validated Credential refs")` where every sibling invariant failure in the crate map_errs to `CredentialServiceErrorCode::InvariantFailure` - fix: replace with `.map_err(|_| invariant())?` (leveragingthe existing `invariant()` helper at lib.rs:1491) - [lib.rs:1261-1262] - evidence: err seed 1 (`\.unwrap\(\)|\.expect\(`) = 20 hits; 19 sit in `#[cfg(test)]`; 1 non-test hit: lib.rs:1262. - - - -## serde -- N/A (seeds: 0/0/0/0 all zero; the crate crosses the guest backend only by building `serde_json::json!` values, no serde-derived type, hand-written deserializer, or from_/to_ boundary sits here). - -## obs -- clean: seeds ran: 0/0/0/26 (tracing-presence); every tracing event carries named fields (`provider`, `resource`, `operation`, `state`, `%error`); no println, interpolated message-only event, or instrument site; library installs no subscriber. - - - - - -## docs -- d2b-provider-credential-managed-identity#4 sev=low blast=leaf effort=M verdict=actionable - Public `Result`-returning items document failures only in prose and carry no `# Errors` sections (e.g. `ManagedIdentityClientConfig::new`, `ManagedIdentityPlacement::new`, `ImdsEndpointAlias::parse`, `ManagedIdentityCredentialProviderFactory::new`, controller projections) - fix: add `# Errors` sections naming the specific `ManagedIdentityProviderError`/`CredentialServiceError`/`CredentialObservabilityError` variant each failure returns - [lib.rs:449, lib.rs:514, lib.rs:592, lib.rs:796, controller.rs:137, controller.rs:171, controller.rs:203, controller.rs:227] - evidence: docs seeds 86/0/43; seed 2 (`/// # (Examples|Errors|Panics|Safety)`)=0 while 43 pub items return `Result<`;`#![deny(missing_docs)]` (lib.rs:7) forces doc presence but not canonical sections. - -## perf -- clean: seeds ran: 3/2/0; all `format!` sites are test canaries (audit.rs:39, lib.rs:1531, telemetry.rs:34); `Vec::new` at construction and at the restore buffer (lib.rs:819, lib.rs:1283, both cold/empty-case-true); no to_string copies; no allocation in a hot path. - - - -## conc -- clean: seeds ran: 1/3/0/0; the sole thread hit is the `use std::thread` import for `poll_client_sync`'s park/unpark waker ( lib.rs:22); std `Mutex` is try_lock-only on synchronous surfaces (lib.rs:902, lib.rs:1094-1103)andthe `tokio::sync::Mutex` pairs guard state across awaits( lib.rs:901, lib.rs:903); no atomics, scoped/spawned threads,or manual Send/Sync. - - - -## async -- clean: seeds ran: ~50/0/4/0; all awaits occur with tokio-aware locks, no guard is held across an await (acquire/refresh/inspect re-acquire per section);`await_client` bounds every injected-client future with `tokio::time::timeout`( service.rs:566-577);`poll_client_sync` is the deliberate synchronous surface documented at lib.rs:1238-1245 (try_lock + park_timeout per plan U4; no spawn/select/runtime-in-library). - - - - - -## unsafe -- N/A (seeds: 0/0/0; seed4=1 only the `#![forbid(unsafe_code)]` attribute at lib.rs:8, which per the lens card doe not make the lens applicable). - -## ffi -- N/A (seeds: 0/0/0/0 all zero; nothing crosses a foreign caller). - -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules, proc-macro usage, or `$crate` paths). - -## test -- d2b-provider-credential-managed-identity#5 sev=low blast=leaf effort=S verdict=actionable - Table-driven loops assert without per-case failure messages, so the first failing case reports only a shared line number and not which case - fix: append `"method: {method:?}"` / `"binding: {binding:?}"` style messages to the `assert!`/`assert_eq!` calls in the method/route/placement matrices (mirroring the canary loops' messages at canary.rs:229-241) - [tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76] - evidence: test seeds ~52/~180/0/0; the three named loops are the only assertion-loops without per-case messages; the suite otherwise asserts behavior (binding subject matrices, canary redaction scans, fault-injection fakes, conformance fixtures) and has no proptest/insta/rstest or `#[ignore]` tests. - -## Coverage -- idiom: clean (seeds ran: 0/0/0 -- own: clean (seeds ran: 37/8/8/0 -- type: 1 finding(s) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: N/A (seeds: 0/0/0/0 all zero; no serde type boundary -- obs: clean (seeds ran: 0/0/0/26 -- docs: 1 finding(s) -- perf: clean (seeds ran: 3/2/0 -- conc: clean (seeds ran: 1/3/0/0 -- async: clean (seeds ran: ~50/0/4/0 -- unsafe: N/A (seeds: 0/0/0; seed4=1 only the forbid attribute -- ffi: N/A (seeds: 0/0/0/0 -- macro: N/A (seeds: 0/0/0/0 -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md deleted file mode 100644 index 2526570ca..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential-secret-service.md +++ /dev/null @@ -1,84 +0,0 @@ -# d2b-provider-credential-secret-service - d2b-provider-credential-secret-service -Baseline: 6ebdd4cec | LOC audited: 6,699 (excl. src/generated/**, none present) | modules: lib.rs, service.rs, controller.rs, audit.rs, telemetry.rs, main.rs; tests: session.rs, lifecycle.rs, faults.rs, canary.rs, delivery.rs, conformance.rs, entrypoint.rs, placement.rs, common/mod.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-credential-secret-service#1 sev=low blast=leaf effort=S verdict=actionable - exported enum variant is misspelled `Userd` for `User` in the only supported owner classification, so every consumer must copy the typo - fix: rename `SecretServiceOwner::Userd` to `SecretServiceOwner::User` (and `owner()` return at lib.rs:1233); in-tree census shows no consumers to update - [packages/d2b-provider-credential-secret-service/src/lib.rs:446, packages/d2b-provider-credential-secret-service/src/lib.rs:1233] - evidence: census: `Userd` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 2 hits (definition + owner() return, both in-crate) -- clean: seeds ran: 0/0/0; no index loops (`for i in 0..`),no hand-written Default/From/PartialEq/Eq/Clone/Hash impls (the hand-written `Debug` impls deliberately redact via ``/`write_str`, where a derive would leak),no statement-style `let mut String/Vec::new()` accumulation; the only naming defect is the typo above - -## own -- clean: seeds ran: ~80/~4/0/0; every clone/is explainable one sentence: `Arc` clones feed `'static` port futures and shared port ownership (GuestCredentialBackend, `SessionAuthority` self-clone for capability ownership),owned field moves build injected port requests and Mutex/BTreeMap keys (`lease_key`, `user_ref`, `credential_ref`, idempotency),cfg(test) fixtures clone canary markers;`to_owned()` sites (`lib.rs:170,406,1618`) feed owned struct fields/opaque handles; no Rc/RefCell/Cow; the deadline-helper and env-scan triplication classes arerecorded refusals (refusal ledger U53: folded onto toolkit) and are not re-flagged -- evidence: seeds ran: ~80 (`.clone()` mostly cfg(test) module in lib.rs and test suites)/~4 (`.to_owned()/to_vec()/to_string()`)/0 (`Rc<|RefCell<|Arc` on the factory, where the value genuinely shares ownership (provider keeps it, tests and runtime construct different ports; call sites: lib.rs:171-178 factory construction, tests/common/mod.rs:187-188)`; no Arc/Rc/Box/RefCell leaks beyond it -- evidence: seeds: `\bpub (fn|struct|enum|trait|type|const|mod) ` ~62 hits, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 (Arc appears in fn args not `pub .* <` form), `^\s*pub use ` = 1 - -## err -- clean: seeds ran: ~50/~2/0/4; all unwrap/expect sites are in `#[cfg(test)]` module/tests (incl. `expect("plain-test admission runtime")` at lib.rs:1296); the four `*Error` enums split by caller action (port errors closed and mapped to wire codes, provider construction errors, crate-private SessionAuthorityError, crate-private SecretServicePollError)and are not wire-visible (wire error codes come from `d2b_core` via toolkit); no non-test panics in src; the deadline/env-scan helper structure already folded onto `d2b-provider-toolkit` (refusal ledger U53) - this crate delegates via `operation_deadline`/`deadline_remaining` and`reject_process_environment_credential_chain`, not re-flagged -- evidence: seeds: `\.unwrap\(\)|\.expect\(` ~50 (all test code), `let _ = |\.ok\(\);` ~2, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0 in src, `enum \w*Error` = 4 - -## serde -- N/A (seeds: 0/0/0/0; no serde derives/attrs/hand-written Deserialize impls and no `serde_json::from_/to_` in src; this crate crosses no serde boundary itself - wire shapes live in d2b-contracts-provider/toolkit, and the port only shapes `serde_json::json!` request payloads for `GuestCredentialBackend`; serde_json appears only in tests (canary.rs:150)) - -## obs -- d2b-provider-credential-secret-service#2 sev=medium blast=leaf effort=S verdict=actionable - session-close failure warn is message-only with no named fields, so a fleet cannot filter which provider/session close left unresolved leases - fix: add `provider = crate::PROVIDER_REF` and the two booleans (`unresolved_leases`, `unresolved_operations`)as fields to the `tracing::warn!` - [packages/d2b-provider-credential-secret-service/src/service.rs:860] - evidence: obs seed 2 (`(info|debug|warn|error|trace)!\(\("`): ~33 warn/error events, of which exactly 1 has no fields (service.rs:860; the other events carry provider/operation/user/resource/%error fields); seed1 `println!/eprintln!` = 0, seed3 instrument = 0, seed4 tracing:: =~33 -- clean: every other event uses named fields (`provider`, `operation`, `user`, `resource`, `state`, `%error`), never a secret (Debug impls redact, telemetry frames pass `validate_collector_fields` canary gate, redaction already gated by ADR 0010/0028 scanner `packages/xtask/src/diagnostic_redaction.rs`) - -## docs -- d2b-provider-credential-secret-service#3 sev=medium blast=leaf effort=M verdict=actionable - public Result-returning constructors/projections lack `# Errors` sections naming which condition yields which error (despite `#![deny(missing_docs)]` forcing presence, no canonical section exists anywhere in the crate) - fix: add `# Errors` to `SecretServiceConfig::new`, `SecretServicePlacement::new`, `SecretServiceCredentialProviderFactory::new`, `SecretServiceController::reconcile` (and the remaining pub Result items) naming `SecretServiceProviderError`/`CredentialServiceError` failures - [packages/d2b-provider-credential-secret-service/src/lib.rs:523, packages/d2b-provider-credential-secret-service/src/lib.rs:610, packages/d2b-provider-credential-secret-service/src/lib.rs:1140, packages/d2b-provider-credential-secret-service/src/controller.rs:73] - evidence: docs seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 across src (no canonical sections),seed 3 (`-> Result<`) ~135 hits covering most pub methods/constructors returning Result -- d2b-provider-credential-secret-service#4 sev=low blast=leaf effort=S verdict=actionable - the one-second session-close revoke deadline is a bare magic `1_000` triplicated with no why (it bounds revoke of potentially many leases during disconnect/finalize/drain) - fix: extract `const SESSION_CLOSE_REVOKE_DEADLINE_MS: u64 = 1_000;` and document why (one-second cap so a stalled backend cannot hang session teardown foreve) - [packages/d2b-provider-credential-secret-service/src/service.rs:660, packages/d2b-provider-credential-secret-service/src/service.rs:674, packages/d2b-provider-credential-secret-service/src/service.rs:684] - evidence: census: `operation_deadline(1_000)` over src = 3 hits (service.rs:660,674,684; all three sync close paths) -- clean: `#![deny(missing_docs)]` is enabled and pub items carry doc'd first sentences; module docs present on lib/controller/service/audit/telemetry; the capability carries a `compile_fail` doctest (lib.rs:1088-1094), no `ignore`d doctests; the gaps flagged above are the canonical-section and magic-value state - -## perf -- clean: seeds ran: ~3/~9/~6;`format!` appears only in cfg(test) canary markers and test rendering (audit.rs:39, telemetry.rs:33, lib.rs:1999,2008),`Vec::new()` only in test double ports (lifecycle.rs:610,705) and cold one-time `BTreeMap::new()`/`BTreeSet::new()` in provider construction (lib.rs:1179-1187),`to_string()` at wire-rendering/test boundaries (canary.rs:146,148); no `format!` or grow-by-push allocation in any hot path; nothing further (static (unmeasured), no benchmark exists for these cold provider paths) -- evidence: seeds: `format!\(` ~3 non-test src (0), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` ~9 (all cold/test), `\.to_string\(\)` ~6 (wire-rendering boundaries/test fixtures) - -## conc -- clean: seeds ran: ~2/~8/~6/0; concurrency model is deliberate and workload-shaped: per-provider entry gates (`std::sync::Mutex` `mutation_gate` for sync surface, `tokio::sync::Mutex` `async_mutation_gate` for async dispatch),tokio::sync::Mutex-guarded BTreeMap/BTreeSet state for shared maps, atomics for counters (`next_counter` with Relaxed load + AcqRel CAS, `finalized` Acquire/Release pair;`NEXT_AUTHORITY_ID` process-unique static counter is a deliberate singleton - not flagged); no thread_local/static-mut/unsafe Send-Sync claims; sync-path `blocking_lock()` sites are documented sync-only (never executor workers), with inline reasons -- evidence: seeds: `std::thread::|thread::spawn|thread::scope` ~2 (src: thread::current/park_timeout poll loop, tests spawn), `\bMutex<|\bRwLock<` ~8 (src fields; RwLock 0), `Atomic\w+|Ordering::` ~6, `thread_local!|unsafe impl (Send|Sync) for` = 0 - -## async -- d2b-provider-credential-secret-service#5 sev=medium blast=leaf effort=S verdict=actionable - lock order between `sessions` and`user_sessions` is inverted across two branches of `authorize_session_for_user_locked` (first branch acquires `sessions` then awaits `user_sessions`; cached-key branch acquires `user_sessions` then awaits `sessions`), a latent tokio-Mutex deadlock that the outer `async_mutation_gate`/entry-timing currently masks - fix: acquire in one consistent order in both branches (`sessions` before `user_sessions`, e.g. in the cached-key branch scope the `user_sessions` guard chain and then lock `sessions`, or collapse the dual lookup into one map) - [packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-credential-secret-service/src/lib.rs:1341, packages/d2b-provider-credential-secret-service/src/lib.rs:1380] - evidence: async seed 2 (`tokio::sync::(Mutex|RwLock|Notify)`) ~9 hits; the two conflicting order edges are lib.rs:1323-1327 (sessions held across user_sessions await) and lib.rs:1341-1351 (user_sessions held across sessions await) -- clean: production async paths use `tokio::time::timeout` + deadline checks (`ensure_unlocked_async`, `await_port`), await-aware locks, and the port futures are cancellation-bookkept (CompletionUnknown/Deadline arms remember ambiguous operations before returning);`blocking_lock()` sites are sync-only with written reasons (cfg(test) helper, sync public surface, never executor workers);`Runtime::block_on` appears only in cfg(test) helper (lib.rs:1290-1297) with inline allow; no async-gate-allow markers needed -- evidence: seeds: `async fn|async move|\.await` ~100 hits, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0 in src, `tokio::sync::(Mutex|RwLock|Notify)` ~9,, `#\[tokio::(main|test)\]|Runtime::block_on` ~3 (cfg-test/current-thread test harness only) - -## unsafe -- N/A (seeds: 0/0/0/1; sole hit is the `#![forbid(unsafe_code)]` attribute at lib.rs:8; no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/mem::zeroed; safelens non-applicable per U1 card rule) - -## ffi -- N/A (seeds: 0/0/0/0; no extern "C"/no_mangle/link_section, catch_unwind, repr(C)/repr(transparent), or CStr/CString/c_char in src; no FFI boundary) - -## macro -- N/A (seeds: 0/0/0/0; no macro_rules! definitions, proc-macro/syn/quote, $crate, or to_compile_error/new_spanned uses; all macros used are std/tracing/serde_json built-ins) - -## test -- d2b-provider-credential-secret-service#6 sev=low blast=leaf effort=S verdict=actionable - table-driven loops assert without per-case failure messages (`locked_and_unavailable_map_to_provider_unavailable`, `only_user_agent_on_host_or_guest_is_accepted`, `collection_alias_accepts_spaces_and_rejects_unsafe_text`), so a failure reports only the line number and not which case failed - fix: add a `"case: {case:?}"`-style message to each loop assertion - [packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-credential-secret-service/tests/placement.rs:8, packages/d2b-provider-credential-secret-service/src/lib.rs:1966] - evidence: test seeds: `#\[test\]|#\[tokio::test\]` ~45, `assert_eq!\(|assert_ne!\(|assert!\(` ~130, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0;; three loops lack per-case messages -- clean: seeds ran: ~45/~130/0/0; suite covers lifecycle, idempotency, faults/mapping, deadlines (NeverPort, DelayedUnlockPort), concurrent admission/close fencing, redaction canaries (audit, telemetry, every rendered surface), entrypoint refusal, dynamic two-user scope, generation/binding/consumer refusal; no ignored tests, no network, seeded nonces via `std::process::id()` keep tests process-unique but deterministic; the per-case-message gap above is the only polish defect - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: ~80/~4/0/0; clones explained above; deadline/env-scan helpers are recorded refusals (U53), not re-flagged) -- type: clean (seeds ran: 2/0/0) -- api: clean(seeds ran: ~62/0/1) -- err: clean(seeds ran: ~50/~2/0/4; all panic sites test-only; error taxonomy split by caller action) -- serde: N/A(seeds: 0/0/0/0; no serde boundary in this crate itself) -- obs: 1 finding(s) -- docs: 2 finding(s) -- perf: clean(seeds ran: ~3/~9/~6; allocation sites cold/test-only) -- conc: clean(seeds ran: ~2/~8/~6/0) -- async: 1 finding(s) -- unsafe: N/A(seeds: 0/0/0/1; forbid attribute only) -- ffi: N/A(seeds: 0/0/0/0) -- macro: N/A(seeds: 0/0/0/0) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md deleted file mode 100644 index 7bbf1f2a8..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-credential.md +++ /dev/null @@ -1,73 +0,0 @@ -# d2b-provider-credential - d2b-provider-credential -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3322 (excl. src/generated/**, none present) | modules: whole crate (driver.rs, session.rs, effects_service.rs, facets.rs, test_support.rs, lib.rs; tests/registration.rs for the test lens) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- clean: seeds 1-3 (`for \w+ in 0\.\.`, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`, `let mut \w+ = (String|Vec)::new\(\)`) all 0 hits over src/; no index loops, no hand-written derives (the only manual impls are Debug redaction impls on CredentialRevocationRequest/Evidence and Display/Error impls, all deliberate), no statement-style accumulation. - -## own -- d2b-provider-credential#1 sev=low blast=leaf effort=S verdict=actionable - dead derives: `#[derive(Clone)]` on `CredentialDriver` and `#[derive(Default)]` on `RecordingRuntime` are never used by any call site - fix: drop `Clone` from `CredentialDriver` (driver.rs:342) and `Default` from `RecordingRuntime` (test_support.rs:178), keeping `RecordingRuntime::new` as the only constructor - [packages/d2b-provider-credential/src/driver.rs:342, packages/d2b-provider-credential/src/test_support.rs:178] - evidence: seed `\.clone\(\)` = 61 hits, all explainable (owned returns, Arc clones at factory/effects boundaries, test-support recorders); census: `CredentialDriver` with `.clone()` over packages/ = 0 hits (d2bd uses only `CredentialDriverArgs`/`credential_descriptor`, resource_plane_v3.rs:2968); census: `RecordingRuntime::default` over packages/ = 0 hits (d2bd calls `RecordingRuntime::new`, resource_plane_v3.rs:3812, shared_provider_effects.rs:3361) -- clean: seeds 1-4 (`.clone\(\)` 61, `.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` 31, `Rc<|RefCell<|Arc`/`Arc` share genuine ownership across the composition root and factory); remaining Arc sites are test-support/test fixtures only. - -## type -- d2b-provider-credential#2 sev=low blast=leaf effort=M verdict=actionable - `CredentialDriverArgs.zone: String` (and the mirrored `CredentialDriver.zone: String`) carries a bare string where the daemon already holds a validated `ZoneId`, so the driver re-derives and re-parses the zone at use sites instead of receiving the invariant - fix: change `zone` to `d2b_contracts_resource::v3::ZoneId` in `CredentialDriverArgs` (driver.rs:295) and `CredentialDriver` (driver.rs:344); the daemon construction site drops `inputs.zone.as_str().to_owned()` and passes `inputs.zone` (resource_plane_v3.rs:2969, where `ConstructionInputs.zone: ZoneId` at resource_plane_v3.rs:1784); `agent_child` then builds `format!("Zone/{}", self.zone.as_str())` without the fallible `ResourceRef::parse` failure path (driver.rs:457-461); test fixtures switch to `ZoneId::parse("dev").unwrap()` - [packages/d2b-provider-credential/src/driver.rs:295, packages/d2b-provider-credential/src/driver.rs:457, packages/d2bd/src/resource_plane_v3.rs:2969] - evidence: seed `(mode|kind|state): String` = 0 hits (seed 2 `fn validate_\w+` matched only two test fn names, driver.rs:1314,1334); the zone string is validated nowhere until `agent_child`'s `ResourceRef::parse` (driver.rs:461), and never for the non-managed-identity providers whose rows skip that path; sibling family args structs (BindingDriverArgs/EndpointDriverArgs/VolumeDriverArgs, resource_plane_v3.rs:2956-2975) share the same String pattern (X3 candidate) -- clean: seeds 1-3 ran (2 hits total, both test fn names); no boolean flag soup, no Option-pair states, no stringly-typed state; `CredentialDriverStatus`/`CredentialRevocationOutcome`/`CredentialDriverErrorKind` are proper enums and `CredentialRevocationRequest` keeps its derived identity fields private behind accessors (session.rs:84-181). - -## api -- clean: seeds 1-3 (`\bpub (fn|struct|enum|trait|type|const|mod) ` 85, `pub .*\b(Arc|Rc|Box|RefCell)<` 5, `^\s*pub use ` 2) read against the full public surface; lib.rs re-exports are the single house surface (lib.rs:36-53), modules stay private, `CredentialDriverError` is a struct with a private kind (driver.rs:141), `Arc` in `CredentialEffectFacets.runtime` (facets.rs:54) and `Arc` from `credential_spec_decoder` (driver.rs:215) are deliberate shared-ownership/registry patterns with cited call sites (composition root resource_plane_v3.rs:3812, factory effects_service.rs:164, test doubles), and the test-support exports are feature-gated (lib.rs:33-34). - -## err -- clean: seeds 1-4 ran (`.unwrap\(\)|\.expect\(` 33, `let _ = |\.ok\(\);` 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` 4, `enum \w*Error` 1); every unwrap/expect/unreachable sits in `#[cfg(test)]` modules or the `test-support`-gated recorder (test_support.rs:140), no production panic site; `CredentialDriverError` is the struct-with-private-kind shape (driver.rs:141-170) with a `class()` split by caller action (Terminal vs Retryable, driver.rs:112-120), `CredentialResourceRuntimeError` has two variants callers match on (session.rs:29-47), and the Display strings are the documented old durable codes, not asserted as the contract anywhere outside deliberate tests. - -## serde -- clean: seeds 1-4 ran (derive 0, serde-attr 0, hand-written Deserialize 0, `serde_json::from_|serde_json::to_` 14); the crate derives no wire types (CredentialSpec/ResourceSpec come from the contracts crates), the spec decoder parses through the canonical `typed_spec_decoder` path (driver.rs:215-223), the inspect-credential payload is built through the canonical JSON object path (effects_service.rs:66-80), and `canonical_bytes` round-trips through `CanonicalJsonValue` (driver.rs:718-723). - -## obs -- clean: seeds 1-4 ran (`\bprintln!\(|\beprintln!\(` 0, interpolated `(info|debug|warn|error|trace)!\("` 0, `\.instrument\(|#\[instrument` 0, `tracing::` 2); the two production events (driver.rs:682, 692) are structured with named fields (`credential`, `outcome`, `session_generation`), carry no interpolated secrets (the redacted `operation_id` is deliberately not logged; Debug impls redact at session.rs:108-126, 253-265), and the error path logs once at the handling boundary. - -## docs -- d2b-provider-credential#3 sev=low blast=leaf effort=S verdict=actionable - the two Result-returning public items lack the canonical `# Errors` section: `CredentialRevocationRequest::new` states its failure condition only in prose (session.rs:128-131) and `CredentialSession::revoke_credential` documents no failure conditions at all (session.rs:273-274) - fix: add `# Errors` sections naming `CredentialResourceRuntimeError::InvalidResource` (zero/unknown session generation, zero rotation generation, foreign Provider) and the `Revocation` variant respectively - [packages/d2b-provider-credential/src/session.rs:132, packages/d2b-provider-credential/src/session.rs:275] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits across src/ while `-> Result<` = 9 hits; `#![deny(missing_docs)]` (lib.rs:29) keeps every pub item documented, so this is the canonical-section shape only -- clean: seeds 1-3 ran (pub items 102, canonical sections 0, `-> Result<` 9); module docs present in all six files, first sentences carry the contract, no `ignore`d doctests exist, and the crate is `#![deny(missing_docs)]` (lib.rs:29). - -## perf -- clean: seeds 1-3 ran (`format!\(` 12, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 8, `\.to_string\(\)` 31); all format!/Vec::new sites are cold paths (per-pass agent/credential ref derivation driver.rs:420,431,457, the durable operation-id preimage session.rs:188-200, error-path and test-recorder strings) with no loop bodies, and no collection is grown in a hot path; static (unmeasured). - -## conc -- d2b-provider-credential#4 sev=medium blast=leaf effort=S verdict=policy-confirmed - `parking_lot::Mutex` is used throughout the test-support recorder and test fixtures (test_support.rs:18,30,41-46,97-113,159,233-249; driver.rs:1053,1074-1075,1109-1172; session.rs:315,429) despite the recorded outright ban whose only exception is the R4 bounded-worker boundary, and the impl methods holding most `.lock()` calls carry no per-site `#[allow(clippy::disallowed_methods)]` even though the test fns do (`reason = "cfg(test) helper"`, the sanctioned form) - fix: switch the recorder locks to `tokio::sync::Mutex` per the clippy.toml replacement column, or record a test-support exception in the policy and add the sanctioned per-site allows to the impl methods; the `// async-gate-allow: test-support recorder lock` markers (30 sites, async-gate-inventory.json) are recorded exceptions and are not re-flagged - [packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-credential/src/test_support.rs:97, packages/d2b-provider-credential/src/driver.rs:1109, clippy.toml:40, clippy.toml:82] - evidence: seed `\bMutex<|\bRwLock<` = 12 hits, all in test-support/test context (production code holds no lock); census: blocking-census-baseline.json counts `parking_lot::Mutex::lock` = 0 for this crate (test context is excluded from the production ratchet); the same family-wide test-support pattern appears in d2b-provider-device, -endpoint, -guest, -network-local, -process, -usbip, -activation-nixos test_support modules (X3 candidate) -- clean: seeds 1-4 ran (`std::thread::|thread::spawn|thread::scope` 0, `\bMutex<|\bRwLock<` 12, `Atomic\w+|Ordering::` 2, `thread_local!|unsafe impl (Send|Sync) for` 0); production code uses no threads, locks, or atomics; the only atomics are a Relaxed test counter (session.rs:430,444) and all synchronization is test-only (card false positive), with the parking_lot choice flagged above. - -## async -- clean: seeds 1-4 ran (`async fn|async move|\.await` 137, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` 0, `tokio::sync::(Mutex|RwLock|Notify)` 0, `#\[tokio::(main|test)\]|Runtime::block_on` 21); no spawn/select/join in the crate, no guard held across an `.await` (the driver's revoke/reconcile awaits at driver.rs:647,669,860,887 hold no lock), no blocking call inside an async context, and every test-support recorder lock carries its recorded `// async-gate-allow` marker (30 sites in async-gate-inventory.json) - cited, not re-flagged. - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0, `// SAFETY:` 0, `transmute|from_raw|MaybeUninit|mem::zeroed` 0, `unsafe_code` 0; manifest `unsafe_code = "forbid"` with no exception sites - the (d)8 exception set does not include this crate). - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` 0, `catch_unwind` 0, `repr\(C\)|repr\(transparent\)` 0, `CStr|CString|c_char` 0; the crate crosses no foreign boundary). - -## macro -- N/A (seeds: `macro_rules!` 0, `proc_macro|syn::|quote!` 0, `\$crate` 0, `to_compile_error|new_spanned` 0; no macros defined). - -## test -- clean: seeds 1-4 ran over src/ + tests/ (`#\[test\]|#\[tokio::test\]` 29, `assert_eq!\(|assert_ne!\(|assert!\(` 128, `proptest!|insta::assert|rstest` 0, `#\[ignore\]` 0); the suite is behavior-focused (revocation-before-child-deletion ordering, fail-closed session binding, durable operation-id dedup, drift deletion, registration boundary), asserts error classes and status variants rather than implementation, is deterministic with no network/time dependence, and every test can fail (no tautologies, no `#[ignore]`, no golden pinning). - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: 1 finding(s) -- type: 1 finding(s) -- api: clean (seeds ran: 85/5/2) -- err: clean (seeds ran: 33/0/4/1) -- serde: clean (seeds ran: 0/0/0/14) -- obs: clean (seeds ran: 0/0/0/2) -- docs: 1 finding(s) -- perf: clean (seeds ran: 12/8/31) -- conc: 1 finding(s) -- async: clean (seeds ran: 137/0/0/21) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, manifest forbids) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test: clean (seeds ran: 29/128/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md deleted file mode 100644 index 902d9296f..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-gpu.md +++ /dev/null @@ -1,93 +0,0 @@ -# d2b-provider-device-gpu - d2b-provider-device-gpu -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3758 (excl. src/generated/**; src/ = 3037, tests/ = 721) | modules: whole crate (authority, controller, effects, effects_service, facets, gpu_argv, process, settings, test_support, video_argv, vocabulary, workers) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) - -## idiom -- d2b-provider-device-gpu#1 sev=low blast=leaf effort=S verdict=actionable - rustfmt drift: the GpuAuthorityError enum is closed by an indented brace with a trailing-whitespace line inside code(), and a variant doc comment in GpuEffectError sits at column 0 - fix: normalize the three sites (cargo fmt --check class): authority.rs:401 -> `}`, authority.rs:411 empty, effects.rs:101 reindent `/// A worker closure...` - [packages/d2b-provider-device-gpu/src/authority.rs:401, packages/d2b-provider-device-gpu/src/authority.rs:411, packages/d2b-provider-device-gpu/src/effects.rs:101] - evidence: read of the three sites; seeds ran: `for \w+ in 0\.\.` = 0, `impl (Default|From|...) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 1; the repository `cargo fmt --check` class (card verify) flags these shapes. -- d2b-provider-device-gpu#2 sev=low blast=leaf effort=S verdict=actionable - `let _ = Self::declared_row_template)...)?` binds nothing while the `?` already propagates the error - fix: drop the binding: `Self::declared_row_template(&view, role)?;` - [packages/d2b-provider-device-gpu/src/effects_service.rs:193] - evidence: read; `let _ =` seed = 1 (effects_service.rs:193); the Ok value is unused and the `?` carries the Err, so the `let _ =` is redundant expression shape. -- d2b-provider-device-gpu#3 sev=low blast=leaf effort=M verdict=actionable - six opaque-token newtypes duplicate the same from_core / is_zero / as_bytes / redacting-Debug boilerplate with subtly differing surfaces - fix: extract a shared opaque-bytes shape (const-generic `OpaqueBytes` with per-type markers, or an in-crate `macro_rules! opaque_token`), keeping the deliberate per-type Debug redaction; the repo's `redacted_debug!`-class macro is the resident pattern to lean on - [packages/d2b-provider-device-gpu/src/authority.rs:17, packages/d2b-provider-device-gpu/src/authority.rs:44, packages/d2b-provider-device-gpu/src/authority.rs:66, packages/d2b-provider-device-gpu/src/authority.rs:265, packages/d2b-provider-device-gpu/src/effects.rs:14, packages/d2b-provider-device-gpu/src/effects.rs:66] - evidence: read; GpuBackingToken/PlatformToken/PrincipalToken (is_zero + from_core), GpuAuthorityLease (from_core + as_bytes), GpuEffectToken/LaunchTicket (from_core) plus a hand-written "" Debug each; U1 idiom card notes hand-written redacting Debug impls are deliberate (not flagged), the construction-boilerplate halves are not. -- clean: seeds ran (s1=0 index loops, s2=1 hand-written Default which is the invariant-preserving case at settings.rs:56, s3=1); no iterator-vs-index loop; naming discipline and From/derive conventions clean. - -## own -- d2b-provider-device-gpu#4 sev=low blast=leaf effort=S verdict=actionable - the started worker identity is cloned solely so validate_started_identity runs after the store - fix: validate `&identity` before `self.gpu_identity = Some(identity)` (same for video), storing on the failure branch first to preserve the test-pinned retain-for-finalize contract - [packages/d2b-provider-device-gpu/src/controller.rs:272, packages/d2b-provider-device-gpu/src/controller.rs:325] - evidence: `.clone()` seed = 22; both clones at controller.rs:272/325 exist to keep the value for the post-store validation; tests/authority_lifecycle.rs:198 (`lifecycle_rejects_worker_identity_and_finalizes_owned_process`) pins that the identity is retained on the WrongPrincipal failure path, so the reorder must keep that behavior; the rest of the clones (wire-rendering argv building, owned-token transfer into effect calls, lease restore-on-error at controller.rs:506) are each explainable in one sentence. -- clean: seeds ran (s1 .clone() = 22, s2 to_owned/to_vec/to_string = 23, s3 Arc share one genuine two-owner lease cache (driver + port). - -## type -- d2b-provider-device-gpu#5 sev=medium blast=leaf effort=S verdict=actionable - `video_started: bool` duplicates `video_identity.is_some()` and is read only by the Debug impl, so the pair can drift into an illegal state - fix: delete the field and use `video_identity.is_some()` in the `GpuController` Debug impl - [packages/d2b-provider-device-gpu/src/controller.rs:79, packages/d2b-provider-device-gpu/src/controller.rs:326, packages/d2b-provider-device-gpu/src/controller.rs:442, packages/d2b-provider-device-gpu/src/controller.rs:552] - evidence: census `video_started` over the crate = 6 sites (decl 79, init 113, writes 326/442, reset 515, read only at 552 in Debug); no behavioral read exists and the gpu side has no `gpu_started` twin, confirming the redundancy; found by full-file read (seed 2 `is_\w+: bool|\w+_flag: bool` = 0). -- clean: seeds ran (s1 validate_/check_ = 1 `validate_started_identity` at controller.rs:524 which is a parse-once-at-boundary check, s2 boolean flags = 0, s3 stringly-state = 0); `GpuSettings::validate` is arbitration-dependent runtime validation of a schema-mirroring wire type (U1 false-positive class, not flagged); `GpuPhase`/`GpuProcessRole`/`GpuProcessObservation`/`GpuReconcileOutcome` are well-modelled closed enums. - -## api -- d2b-provider-device-gpu#6 sev=low blast=leaf effort=S verdict=actionable - `pub mod gpu_argv`/`pub mod video_argv` expose a second public path for items already re-exported at the root, and the module paths have zero workspace callers - fix: make both modules private (`mod gpu_argv`/`mod video_argv`), keeping the lib.rs re-export arms so each item stays reachable by one path (the house single-surface pattern) - [packages/d2b-provider-device-gpu/src/lib.rs:12, packages/d2b-provider-device-gpu/src/lib.rs:15] - evidence: census `d2b_provider_device_gpu::(gpu_argv|video_argv)::` over packages/; nixos-modules/; tests/; docs/reference/; labs/; BUILD.bazel = 0 hits; the sibling `facets`/`vocabulary`/`effects_service` module paths ARE consumed (d2bd/src/resource_plane_v3.rs:2033, d2bd/src/shared_provider_effects.rs:2119, d2bd/src/shared_provider_effects.rs:1423) so those stay `pub`. -- d2b-provider-device-gpu#7 sev=low blast=leaf effort=M verdict=actionable - public `DeclaredWorkerGpuPortArgs` tunnels dependency types in pub fields (`Arc`, `Arc>>` over parking_lot, `tokio::runtime::Handle`, `&dyn SharedProviderChildSurface`) - fix: hide the field types behind crate-private accessors or accept a single crate-owned sidecar struct; publish=false so the semver cost is nil, but the surface leaks three dependency crates - [packages/d2b-provider-device-gpu/src/effects_service.rs:465, packages/d2b-provider-device-gpu/src/effects_service.rs:467, packages/d2b-provider-device-gpu/src/effects_service.rs:469] - evidence: api seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 (facets.rs:29 runtime facet, effects_service.rs:465/467 args fields); the args struct is constructed at d2bd/src/shared_provider_effects.rs:2120 - the dependency-injection ladder rung for an internal provider crate. -- clean: seeds ran (s1 pub items = 124, s2 pub-arc = 2, s3 pub use arms = 11); the lib.rs re-export list is the house surface (U1 accepted pattern); `GpuController`/`GpuOwnerProof`/`GpuProcessIdentity` keep private fields with const accessors; `GpuLifecycleEffectPort`/`GpuRuntime` are small required surfaces; `adopt_lifecycle` has no production caller (census over packages/; nixos-modules/; tests/; docs/reference/; labs/ = 0, only tests/combined_reconcile.rs) but is a recorded kept item per U1 (d) 6 (policy-pinned test) - noted, not flagged. - -## err -- clean: seeds ran (s1 unwrap/expect = 14, s2 let _ = / .ok() = 1, s3 panic/unreachable/todo = 1, s4 enum Error = 7); every unwrap/expect is in tests or on a literally-built fixed-length conversion (effects_service.rs:206/337 `try_into().expect("fixed ...")` - the recorded false-positive class); the single `unreachable!` (workers.rs:28) is a sanctioned invariant panic (the role is derived from settings, Video unreachable by construction); `GpuEffectError::Transient` is genuinely retry-distinguishable; the error taxonomy is split by caller action with stable `code()` strings. - -## serde -- d2b-provider-device-gpu#8 sev=medium blast=leaf effort=S verdict=actionable - `GpuArgvInput` admits unknown JSON fields while its sibling `VideoArgvInput` denies them (and a test pins the rejection), an inconsistent admission policy for two daemon-side wire inputs - fix: add `deny_unknown_fields` to `GpuArgvInput` (and `GpuParams`/`GpuDisplayConfig` for full nested coverage), mirroring video_argv.rs:112; the only in-tree producer d2bd/src/process_provider_runtime.rs:3707 builds a Rust literal, so no producer sends unknown fields today - [packages/d2b-provider-device-gpu/src/gpu_argv.rs:77, packages/d2b-provider-device-gpu/src/video_argv.rs:112, packages/d2b-provider-device-gpu/src/video_argv.rs:244] - evidence: serde seeds - s1 derive = 20, s2 serde attrs = 14, s3 impl Deserialize = 0, s4 serde_json = 4; GpuArgvInput carries only `rename_all = "camelCase"` while VideoArgvInput carries `deny_unknown_fields`; video's `rejects_unknown_extra_args_field` (video_argv.rs:244-253) pins rejection, the gpu side has no such gate or test. -- clean: seeds ran (s1=20, s2=14, s3=0, s4=4); `GpuSettings`/`DisplayConfig` deny unknown fields and `GpuSettings` uses struct-level `#[serde(default)]` (deliberate manifest defaults); the error enums use internal `tag = "kind"` representations; `serde_json::from_slice` on the declared row spec at effects_service.rs:129 is a boundary parse mapped to `SpawnRejected`; no hand-written `Deserialize` (no admission-gate refusal row implicated). - -## obs -- clean: seeds ran (s1 println/eprintln = 2 both in #[cfg(test)] snapshot helpers, s2 interpolated-message-with-no-fields = 0, s3 instrument = 0, s4 tracing = 14); every tracing event in controller.rs and effects_service.rs uses named fields (`device`, `role`, `error`, `reason`) with the device-uid not a secret; no secret/PII is ever rendered (all tokens carry redacting Debug and are never logged); error chains are logged once at the controller boundary that maps each failure. - -## docs -- d2b-provider-device-gpu#9 sev=medium blast=leaf effort=M verdict=actionable - no `# Errors` section on any pub `Result`-returning item despite the crate denying missing_docs, so the failure contract is undocumented - fix: add `# Errors` naming the failure branches to new_authorized/reconcile_lifecycle/adopt_lifecycle/finalize_lifecycle/validate/from_core/generate_gpu_argv/generate_video_argv/GpuWorkerSpec::gpu/VideoWorkerSpec::new/GpuProcessDeclaration::new/select_processes/gpu_process_name/GpuOwnerProof::new/GpuAuthorityAdmission::new/with_video_principal - [packages/d2b-provider-device-gpu/src/controller.rs:172, packages/d2b-provider-device-gpu/src/settings.rs:78, packages/d2b-provider-device-gpu/src/gpu_argv.rs:158] - evidence: docs seeds - s1 pub items = 124, s2 canonical sections (`/// # (Examples|Errors|Panics|Safety)`) = 0, s3 `-> Result<` = 27; the failure conditions are non-obvious (e.g. the arbitration/render-node/max-holders matrix in GpuSettings::validate and the arbitration-dependent GpuAuthorityAdmission::new rejections); first sentences and module docs are otherwise strong. -- d2b-provider-device-gpu#10 sev=low blast=leaf effort=S verdict=actionable - module-level `#![allow(missing_docs)]` in the two argv modules overrides the crate-wide deny, leaving the pub `as_str` methods undocumented - fix: drop both allows and add doc comments to `GpuContextType::as_str` and `VideoBackend::as_str` - [packages/d2b-provider-device-gpu/src/gpu_argv.rs:24, packages/d2b-provider-device-gpu/src/video_argv.rs:22, packages/d2b-provider-device-gpu/src/gpu_argv.rs:40, packages/d2b-provider-device-gpu/src/video_argv.rs:103] - evidence: read; `#![deny(missing_docs)]` at lib.rs:5 vs `#![allow(missing_docs)]` at gpu_argv.rs:24 and video_argv.rs:22; the only undocumented pub items in those modules are the two `as_str` methods (all fields/structs/enums are otherwise documented). -- clean: seeds ran (s1=124, s2=0, s3=27); every module carries a `//!` doc; the wire-contract pin constants in video_argv.rs document the magic values with the patch citation (the skill's magic-value rule is followed). - -## perf -- clean: seeds ran (s1 format! = 6, s2 Vec/VecDeque/HashMap/BTreeMap::new = 3, s3 to_string = 23); all `format!` sites are cold one-shot paths (argv render gpu_argv.rs:151, process-name derive process.rs:121, worker-ref build effects_service.rs:149, wire snapshot video_argv.rs:81) and each has a written rationale (byte-stable JSON order, closed injection surface); `Vec::new()` at controller.rs:376 is a cold adoption loop; no loop-internal allocation, no attacker-keyed hashing; static (unmeasured) - no benchmarks exist for this crate. - -## conc -- d2b-provider-device-gpu#11 sev=medium blast=family effort=S verdict=policy-confirmed - `parking_lot::Mutex::lock` on the shared `gpu_authority_leases` cache is off the KD3 exception list (only the R4 bounded-worker boundary is exempt) and carries no per-site `#[allow(clippy::disallowed_methods)]` unlike the same file's drive_sync - fix: add the sanctioned per-site allow `reason = "synchronous path"` at the three lock sites (or record the site in the provider-crate-policy exception list); the clippy.toml:82 replacement (`tokio::sync::Mutex`) is wrong on this pure-synchronous path - [packages/d2b-provider-device-gpu/src/effects_service.rs:79, packages/d2b-provider-device-gpu/src/effects_service.rs:310, packages/d2b-provider-device-gpu/src/effects_service.rs:445, packages/d2b-provider-device-gpu/src/effects_service.rs:454] - evidence: conc seed 2 `\bMutex<` = 2 (effects_service.rs:79 field, 467 args field) with `.lock()` calls at 310/445/454; the crate's blocking-census baseline records `parking_lot::Mutex::lock: 0` (packages/xtask/data/blocking-census-baseline.json) so the site is above the recorded baseline and off the per-site allow ledger; clippy.toml:40-43 (KD3: banned except R4) and clippy.toml:82 list the ban and the tokio replacement; the same cache type is declared by d2b-provider-device/src/driver.rs:139-143 (family-shared construction contract), so the fix must be coordinated family-wide. -- clean: seeds ran (s1 threads = 0, s2 Mutex/RwLock = 2, s3 atomics/Ordering = 0, s4 thread_local/unsafe Send+Sync = 0); the single lock is a short critical section, never held across an await, and the shared-ownership justification is written in the port doc (operations are the family's sole cross-owner state). - -## async -- clean: N/A - seeds ran (s1 async fn/.await = 0, s2 tokio::spawn/JoinSet/select/join = 0, s3 tokio::sync::{Mutex,RwLock,Notify} = 0, s4 #[tokio::(main,test)]/block_on = 0, all zero); the crate's sync `GpuLifecycleEffectPort` boundary deliberately drives its async child-surface work through `drive_sync` (block_in_place + block_on on the daemon-captured handle, effects_service.rs:44-46) under the sanctioned `reason = "synchronous path"` allow - noted, not flagged per U1 (d) 4. - -## unsafe -- clean: N/A - seeds ran (s1 unsafe blocks/fns/impls = 0, s2 `// SAFETY:` = 0, s3 transmute/from_raw/MaybeUninit/zeroed = 0, s4 `unsafe_code` = 2); both seed-4 hits are the word `unsafe_code` in module doc prose (gpu_argv.rs:23, video_argv.rs:21) - the card's doc-comment-prose false-positive class; the manifest carries `[lints.rust] unsafe_code = "forbid"` (Cargo.toml:9), so the lens is not applicable. - -## ffi -- clean: N/A - seeds ran (s1 extern "C"/no_mangle/link_section = 0, s2 catch_unwind = 0, s3 repr(C)/repr(transparent) = 0, s4 CStr/CString/c_char = 0, all zero); no foreign-calling surface, no `unsafe extern` declarations, no edition-2024 FFI forms in this crate. - -## macro -- clean: N/A - seeds ran (s1 macro_rules! = 0, s2 proc_macro/syn/quote = 0, s3 $crate = 0, s4 to_compile_error/new_spanned = 0, all zero); no user macros or proc-macro surface in this crate (the six-token boilerplate at idiom#3 could adopt a macro, but no macro exists today). - -## test -- d2b-provider-device-gpu#12 sev=medium blast=leaf effort=S verdict=actionable - `GpuAuthorityAdmission::new`'s arbitration/render-node/max-holders matrix (`ArbitrationViolation`) and zero-token rejections (`StaleDeviceIdentity`) have no direct test even though they are the authority admission gate - fix: add table-driven rejection vectors over `GpuAuthorityAdmission::new` asserting the typed `GpuAuthorityError` variant for each illegal combination, mirroring the `admission()` fixture shape in tests/authority_lifecycle.rs - [packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/tests/authority_lifecycle.rs:245, packages/d2b-provider-device-gpu/tests/combined_reconcile.rs:238] - evidence: test seeds - s1 `#\[test\]` = 33 (17 in src, 16 in tests/), s2 asserts = 120, s3 proptest/insta/rstest = 0, s4 `#\[ignore\]` = 0; `GpuAuthorityError::` appears in tests only as `PrincipalNotSeparated` (authority_lifecycle.rs:246) and the effect-level `StaleDeviceIdentity` path (combined_reconcile.rs:239); no test constructs an invalid `GpuAuthorityAdmission` to exercise `new()`'s own gate branches - contract behavior with no test. -- clean: seeds ran (s1=33, s2=120, s3=0, s4=0); the suite is behavior-focused: tests assert typed error variants, never `Display` strings; golden byte-compares pin the argv/wire shapes (`include_str!` goldens under tests/golden/runner-shape/); rejection vectors are table-driven with per-case failure messages; lifecycle and adoption transitions, phase gating, and the config validation matrix are all covered; deterministic (no clock/network/randomness); the observed `expect`/`unwrap` in tests are fixture-construction asserts. - -## Coverage -- idiom: 3 finding(s) -- own: 1 finding(s) -- type: 1 finding(s) -- api: 2 finding(s) -- err: clean (seeds ran: 14/1/1/7) -- serde: 1 finding(s) -- obs: clean (seeds ran: 2/0/0/14) -- docs: 2 finding(s) -- perf: clean (seeds ran: 6/3/23) -- conc: 1 finding(s) -- async: N/A (seeds 0/0/0/0 all zero; no async fn/.await/tokio spawn; the sync-port drive_sync boundary is a sanctioned "synchronous path" allow) -- unsafe: N/A (seeds 1-3 0/0/0; seed 4 `unsafe_code` = 2 doc-prose words only; manifest forbids) -- ffi: N/A (seeds 0/0/0/0 all zero) -- macro: N/A (seeds 0/0/0/0 all zero) -- test: 1 finding(s) - -## Supply note (workspace lens X1 owns the full audit; U1 (e) directly-evidenced crate-manifest note) -- d2b-provider-device-gpu#13 sev=low blast=leaf effort=S verdict=actionable - manifest dependencies `async-trait` and `d2b-resource-types` appear nowhere in the crate's src/+tests/ - fix: drop both from Cargo.toml (and the mirrored Bazel deps) or justify their retention in the manifest - [packages/d2b-provider-device-gpu/Cargo.toml:20, packages/d2b-provider-device-gpu/Cargo.toml:25] - evidence: census `async_trait|d2b_resource_types` over src/+tests/ = 0 matches (the BUILD.bazel references at :39/:55 merely mirror the manifest deps); tagged supply per U1 (e) directly-evidenced unused-dependency note; the workspace-level supply audit is lane X1's. diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md deleted file mode 100644 index 5e291df36..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-security-key.md +++ /dev/null @@ -1,82 +0,0 @@ -# d2b-provider-device-security-key - d2b-provider-device-security-key -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4232 (excl. src/generated/**; src 3853 + tests 379) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- d2b-provider-device-security-key#1 sev=low blast=leaf effort=S verdict=actionable - `declared_dependency_refs` accumulates through a `let mut refs = Vec::new()` plus a push closure instead of an iterator chain, the one statement-style accumulation in the crate - fix: collect the two `Option` probes with an iterator chain (`[a, b].into_iter().flatten().collect()`) and delete the closure - [packages/d2b-provider-device-security-key/src/driver.rs:380-390] - evidence: seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (driver.rs:380); seeds 1-2 = 0 -- clean: seeds ran: 0/0/1 - no index loops, no hand-written derive-replaceable impls (all Debug impls redact secrets, deliberate per repo false-positive list), one accumulation site flagged above - -## own -- clean: seeds ran: 37/30/0/0 - every clone inspected: owned-arg clones into the contracts `explicit_binding_children` helper (controller.rs:224-266), `metadata.clone()` reuse for the second ChildEnsure (driver.rs:494), thread-boundary `vm_id`/Arc clones (relay_service.rs:402,440-442), lease holder/admission clones that must outlive the borrow (lease.rs:121-122,171,194,276-277), test-fixture clones; no Rc/RefCell/Arc/Cow anywhere -- clean: `test_support.rs:32` `self.calls.lock().clone()` returns a snapshot from a Mutex guard - the standard pattern for a recording double, not a borrow-checker workaround - -## type -- clean: seeds ran: 0/1/0 - the single hit `watched_configuration_is_dependency: bool` (controller.rs:83) is one runner-contract knob mirroring the shared-Runner cutover, not flag soup; lease state is a closed `LeaseState` enum with transition checks, and `backing`/`authorized_*` Option pairs are enforced by the state machine at every use site (`.ok_or(AuthorizationDenied)`), so typestate would not buy a real bug class - -## api -- d2b-provider-device-security-key#2 sev=low blast=leaf effort=S verdict=actionable - `pub mod relay` and `pub mod relay_service` (lib.rs:16-17) expose a second path for every root-re-exported item, while `facets`/`effects_service`/`test_support` module paths are the ones the daemon actually consumes - fix: make `relay` and `relay_service` private modules, keep the lib.rs `pub use` arms as the single surface (house pattern) - [packages/d2b-provider-device-security-key/src/lib.rs:16-17, packages/d2b-provider-device-security-key/src/lib.rs:45-55] - evidence: census `device_security_key::relay::` over packages/nixos-modules/tests/docs/reference/labs = 1 hit (a doc comment in d2b-broker/src/ops/security_key.rs:8); `device_security_key::relay_service::` = 0; `::facets::`/`::effects_service::`/`::test_support::` = 16 hits in d2bd (resource_plane_v3.rs:1875,2019,2263,3786,3948; shared_provider_effects.rs:2704,3500) -- clean: seed 2 `pub .*Arc<` = 2 hits, both genuine shared ownership with cited consumers: `SecurityKeyEffectFacets.runtime: Arc` (facets.rs:34) is constructed field-by-field by d2bd (resource_plane_v3.rs:2019-2023) and `SkAcceptHandle.state: Arc>` (relay_service.rs:297) is shared across the accept thread and connection tasks; the relay hosting exports have no external callers but are dossier-pinned (ADR-046 D046, docs/specs/ADR-046-decision-register.md:68; prior audit row U60 "No dead surface beyond dossier-pinned relay") - not flagged -- clean: seed 3 `pub use` = 8 arms, the house single-surface pattern; the crate root `#![deny(missing_docs)]` (lib.rs:6) plus per-item docs give a deliberate, documented surface - -## err -- clean: seeds ran: 70/5/6/5 - production unwrap/expect reduced to the canonical-const class (controller.rs:228,265 `ResourceRef::parse)...).expect("... is canonical")` on a literal; repo false positive); all other hits are `#[cfg(test)]`/`tests/` fixtures; `let _ =` sites are deliberate best-effort (oneshot notify relay_service.rs:282, aborted-task awaits 587/589, cancel packet 596); panics only in test doubles (exact_authority.rs:22, mutual_exclusion.rs:22); the five error enums are closed, split by caller action, and carry stable `code()` wire strings with per-variant docs -- clean: error context survives via the boundary that handles it: `SecurityKeyControllerError::Admission` (controller.rs:123) collapses binding-child detail into a stable code, but the inner error is logged with named fields at the same site (controller.rs:232-235) - deliberate closed-code design, not a swallowed failure - -## serde -- clean: seeds ran: 0/0/0/9 - no derive/attribute/manual-impl surface; all JSON crossing is untyped `serde_json::Value`/`to_vec` with `map_err(|_| invalid())` mapped to `SharedProviderDeclarationError::SpecInvalid` (driver.rs:437-528, effects_service.rs:59); the `binding_child_ensure` Value round-trip (driver.rs:514-517) extracts a known shape from an in-tree trusted payload, not untrusted wire input - no typed boundary to judge - -## obs -- clean: seeds ran: 0/0/0/31 - zero println/eprintln, zero interpolated-message events, zero instrument spans; all 31 tracing events carry named fields (device, error, reason, vm, selector) with the message as the final literal; no secret material in any field (device UIDs and VM ids are identity, not secrets; selector_label is a stable label); redaction is enforced structurally by hand-written Debug impls and pinned by tests/redaction.rs - -## docs -- d2b-provider-device-security-key#3 sev=low blast=leaf effort=S verdict=actionable - `#![allow(missing_docs)]` at relay.rs:7 defeats the crate-root `#![deny(missing_docs)]` for a pub module re-exported at the root, letting undocumented items ship: `CidTranslator::new` (relay.rs:144), `LeaseId::as_u64` (relay.rs:209), and the pub fields of `CtaphidInitPacket`/`CtaphidContPacket` (relay.rs:54-66) - fix: document the handful of items and drop the module-level allow - [packages/d2b-provider-device-security-key/src/relay.rs:7, packages/d2b-provider-device-security-key/src/relay.rs:144, packages/d2b-provider-device-security-key/src/relay.rs:209] - evidence: seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 120 hits; the allow attribute at relay.rs:7 is the only missing_docs suppression in the crate -- d2b-provider-device-security-key#4 sev=medium blast=leaf effort=S verdict=actionable - no `# Errors` section exists on any of the 24 public `Result`-returning items, and the lease/controller state-machine failures are the non-obvious kind the section exists for (`SessionConflict` vs `InvalidTransition` vs `AuthorizationDenied` vs `Effect`) - fix: add `# Errors` sections naming the returned variants to `SecurityKeyLease::{acquire, acquire_authorized, rebind_authorized, complete, cancel, expire}` and `SecurityKeyController::{new, new_authorized, child_resources, child_resources_for_user, acquire, acquire_authorized, rebind_authorized, complete}` - [packages/d2b-provider-device-security-key/src/lease.rs:150-303, packages/d2b-provider-device-security-key/src/controller.rs:162-186, packages/d2b-provider-device-security-key/src/controller.rs:209-267] - evidence: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed 3 `-> Result<` = 24 hits -- clean: first sentences are one-line and load-bearing, module docs (`//!`) present in every module, error enums carry per-variant docs, magic values documented with the why (CEREMONY_TIMEOUT relay.rs:37-39, ring bounds lib.rs:67-72) - -## perf -- clean: seeds ran: 6/3/2 - every allocation site is cold: error construction (relay_service.rs:85,158), thread names (relay_service.rs:404), one-shot dependency collection (driver.rs:380-390), process-name derivation (process.rs:167), test helpers; `Vec::new` sites are the empty-case-common shape; no format!/to_string in any loop or hot path - static (unmeasured) per lens rules - -## conc -- d2b-provider-device-security-key#5 sev=medium blast=leaf effort=M verdict=actionable - 14 `parking_lot::Mutex::lock` sites (8 production-path in relay_service.rs:129,281,489,497,527,532,592,599 and 6 in the test-support-gated test_support.rs:32,43,44,55,78,89) carry no `#[allow(clippy::disallowed_methods, reason = "...")]` attribute, while the committed blocking-census baseline records `parking_lot::Mutex::lock = 0` for this crate and parking_lot is banned outright by clippy.toml (KD3) with only the R4 worker boundary exempt - the census bookkeeping and the manifest's recorded `disallowed_methods = "deny"` level disagree with the source, and the `// async-gate-allow:` markers cover only the async-gate scanner, not the clippy/census side - fix: add the sanctioned per-site allows (`reason = "synchronous path"`) or convert the short critical sections to the clippy.toml-named `tokio::sync::Mutex` replacement, then regenerate the census baseline to match - [packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-device-security-key/src/relay_service.rs:281, packages/d2b-provider-device-security-key/src/relay_service.rs:489-599, packages/d2b-provider-device-security-key/src/test_support.rs:32-89] - evidence: seed `\.lock\(\)` = 16 hits - 14 outside any `#[allow(clippy::disallowed_methods)]` fn (relay_service.rs:129,281,489,497,527,532,592,599; test_support.rs:32,43,44,55,78,89), 2 inside cfg(test) fns with the sanctioned "cfg(test) helper" allow (relay_service.rs:1031,1087); packages/xtask/data/blocking-census-baseline.json `packages/d2b-provider-device-security-key` -> `parking_lot::Mutex::lock: 0`; the census's prod/test split (blocking_census.rs `split_contexts`/`is_test_dir`) counts non-cfg(test) lines as production, so the test_support.rs sites count too; gate state not run (read-only lane) - the row asserts the baseline-vs-source mismatch, not a gate failure; clippy.toml disallowed-methods entry `parking_lot::Mutex::lock` with KD3 reason -- clean: the concurrency model fits the workload - one dedicated accept thread owning its own current-thread runtime (relay_service.rs:403-416, sanctioned "synchronous path" allow), shared `SecurityKeyState` behind a mutex with guards never held across an await, `AtomicU64` counters with Relaxed ordering (relay.rs:205-206, relay_service.rs:620-626) are the repo-sanctioned counter shape; no `unsafe impl Send/Sync`, no `thread_local!`, no `static mut` - -## async -- d2b-provider-device-security-key#6 sev=medium blast=leaf effort=S verdict=actionable - `run_connection` releases the ceremony lease only in its final statement (relay_service.rs:599), so an aborted task leaks the lease: `SkSessionTable::stop_vm`/`register`-replacement or accept-loop abort drops the accept thread's runtime and aborts every in-flight connection task mid-await, leaving `SecurityKeyState` `Leased` until `CEREMONY_TIMEOUT` (120s) expiry evicts it - other VMs are rejected (15s queue wait) for that whole window - fix: release the lease from a Drop guard (a small struct owning `Arc>` + vm_id + lease_id, dropped on task abort) so cancellation is resumable - [packages/d2b-provider-device-security-key/src/relay_service.rs:470-600, packages/d2b-provider-device-security-key/src/relay_service.rs:380-383, packages/d2b-provider-device-security-key/src/relay_service.rs:366-371] - evidence: seed 1 `async fn|async move|\.await` = 60+ hits; seed 2 `tokio::spawn|select!` = 8 hits; static trace: abort path (SkAcceptAbort::abort -> accept-loop break -> runtime drop -> spawned task abort) skips the release statement at relay_service.rs:599 -- clean: no guard is held across an await (all `parking_lot` guards are temporaries dropped before any suspension point - verified at relay_service.rs:489,497,527,532,592,599); `runtime.block_on` at relay_service.rs:416 is the sanctioned dedicated-thread boundary with an inline allow; `tokio::spawn` closures are `Send + 'static` via Arc; the select-then-await-other shape (587-590) correctly awaits the aborted task; all lock sites carry `// async-gate-allow:` markers recorded in the inventory - cited, not re-flagged - -## unsafe -- N/A: seeds 1-3 (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) all zero; the single seed-4 hit is a doc-comment mention of the workspace `forbid(unsafe_code)` lint (relay_service.rs:34), not a site; manifest `[lints.rust] unsafe_code = "forbid"` (Cargo.toml) - -## ffi -- N/A: seeds 1-4 (`extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char`) all zero - no foreign boundary in this crate; fd crossing is safe `File::from(OwnedFd)` under the workspace forbid - -## macro -- N/A: seeds 1-4 (`macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned`) all zero - no macro definitions or proc-macro surface - -## test -- d2b-provider-device-security-key#7 sev=medium blast=leaf effort=M verdict=actionable - no test exercises the relay's core forwarding path: `run_connection`'s guest->hidraw and hidraw->guest loops, CID translation inside the loop, and cancel-on-close are untested while every component (framing, hidraw wrapper, lease, reject paths) has its own unit test - contract behavior with no test; `test_hidraw()` already provides a socket-pair hidraw double, so a full-loop test is feasible - fix: add a `#[tokio::test(flavor = "current_thread")]` that runs `run_connection` with a socket-pair hidraw and a connected guest stream, asserts report forwarding in both directions and a `CTAPHID_CANCEL` packet on peer close - [packages/d2b-provider-device-security-key/src/relay_service.rs:470-600, packages/d2b-provider-device-security-key/src/relay_service.rs:642-648] - evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 50 hits; seed 2 `assert_eq!\(|assert_ne!\(|assert!\(` = 90+ hits; the 33 relay_service tests cover parsing/CID/lease/framing/hidraw/auth/reject paths but none drives the forwarding loop -- clean: seeds ran: 50/90+/0/0 - no `#[ignore]`, no proptest/insta/rstest; assertions target behavior and error variants, not Display strings (lease_state_machine.rs:91-97 asserts `Err(SecurityKeyLeaseError::Effect(Transient))`); redaction is pinned by tests/redaction.rs; tests are deterministic (socket pairs, current-process peer creds, no network/clock injection); integration/provider_lifecycle.rs is a real executable scenario, not a scaffold (this crate is not on the 18-crate policy-scaffold list) - -## Coverage -- idiom: 1 finding -- own: clean (seeds ran: 37/30/0/0) -- type: clean (seeds ran: 0/1/0) -- api: 1 finding -- err: clean (seeds ran: 70/5/6/5) -- serde: clean (seeds ran: 0/0/0/9) -- obs: clean (seeds ran: 0/0/0/31) -- docs: 2 findings -- perf: clean (seeds ran: 6/3/2) -- conc: 1 finding -- async: 1 finding -- unsafe: N/A (seeds: 0/0/0/1 - seeds 1-3 all zero; single seed-4 hit is a doc-comment mention; manifest forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md deleted file mode 100644 index 4b6adefec..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-tpm.md +++ /dev/null @@ -1,85 +0,0 @@ -# d2b-provider-device-tpm - d2b-provider-device-tpm -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3333 (excl. src/generated/**, none present) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- d2b-provider-device-tpm#1 sev=low blast=leaf effort=S verdict=actionable - the swtpm log-level bound is spelled twice: lib.rs exports MIN_SWTPM_LOG_LEVEL/MAX_SWTPM_LOG_LEVEL (1/20) which runner.rs uses, while swtpm_argv.rs:160 hardcodes `1..=20` in generate_swtpm_argv, so a bound change in one place silently drifts from the other - fix: import crate::{MIN_SWTPM_LOG_LEVEL, MAX_SWTPM_LOG_LEVEL} in swtpm_argv.rs and replace the literal range - [swtpm_argv.rs:160, lib.rs:63, lib.rs:65] - evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 1 hit (runner.rs:18, deliberate invariant-preserving Default, not a finding); the bound duplication was read directly at the two sites -- clean: idiom seeds ran: 0/1/0; no index loops, no statement-style accumulation; the one hand-written Default preserves the 20 default a derive cannot express; argv building uses Vec::with_capacity(20) push pipelines - -## own -- d2b-provider-device-tpm#2 sev=low blast=leaf effort=S verdict=actionable - avoidable clones of Option and String where a reborrow suffices: resource_controller.rs:233-234 clones self.volume_ref only to borrow it, resource_controller.rs:247 clones self.process_ref the same way, effects_service.rs:280 clones self.device_ref to pass `&self.device_ref` to key(), and effects_service.rs:450 clones self.zone to call zone.as_str() on a live self - fix: use self.volume_ref.as_ref().ok_or(...)?, self.process_ref.as_ref(), self.key(&self.device_ref), and self.zone.as_str() - [resource_controller.rs:233, resource_controller.rs:247, effects_service.rs:280, effects_service.rs:450] - evidence: own seed 1 (`.clone()`) = 26 hits, seed 2 (`.to_owned()|.to_vec()|.to_string()`) = 46 hits, all sites read; the remaining clones are required (dual ownership into DeclaredTpmRows + port at effects_service.rs:684-692, borrowed-input error paths in swtpm_argv.rs, test fixtures) -- clean: own seed 3 (`Rc<|RefCell<|Arc shared state outside the tokio Mutex covered under async; the Arc facet clone is genuine shared ownership - -## type -- clean: type seeds ran: 1/1/0; validate_absolute (swtpm_argv.rs:119) is a single-boundary validator on a wire-shaped input type (a newtype would rewrite the refused SwtpmArgvInput fields), and watched_configuration_is_dependency (resource_controller.rs:18) is a cutover-contract constant with one constructor - both judged deliberate, no illegal-state finding - -## api -- d2b-provider-device-tpm#3 sev=medium blast=leaf effort=S verdict=actionable - the state.rs token module (StateDirectoryToken, TamperMarkerToken, StateOwnerToken, StateDirIntent, state.rs:6-107, re-exported lib.rs:36-38) has zero consumers repo-wide at HEAD, so the refusal ledger's stated reason for keeping it ("the daemon references them", over-engineering-audit-record.md:386, rows 71/72) is no longer evidenced - the daemon-side uses were deleted by the same applied finding - fix: delete state.rs and its re-export, or wire the daemon side that the record claims exists - [state.rs:6, state.rs:29, state.rs:51, state.rs:73, lib.rs:36] - evidence: census: `StateDirIntent|StateDirectoryToken|StateOwnerToken|TamperMarkerToken` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits outside packages/d2b-provider-device-tpm (only state.rs + lib.rs:36-38); changed evidence vs the record row -- d2b-provider-device-tpm#4 sev=low blast=leaf effort=S verdict=actionable - the exported inspect-tpm effects service is unwired: TPM_EFFECTS_SERVICE (effects_service.rs:53), TpmEffectsService, and TpmEffectsServiceFactory (effects_service.rs:103-116, whose facets field carries #[allow(dead_code)] for an R5 respawn path "not wired yet") are never registered, while d2bd registers every sibling provider's factory in shared_provider_effects.rs:3434-3493 without the TPM one - fix: register the factory there, or delete the service surface until the respawn path is wired - [effects_service.rs:53, effects_service.rs:103, effects_service.rs:114] - evidence: census: `TpmEffectsServiceFactory|TPM_EFFECTS_SERVICE` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits outside the crate -- d2b-provider-device-tpm#5 sev=low blast=leaf effort=S verdict=actionable - LiveTpmResourceEffectPort is pub (effects_service.rs:341) but is only constructed and consumed inside effects_service.rs (into_port at effects_service.rs:697), never appearing in a public signature or external caller - fix: make it pub(crate) - [effects_service.rs:341] - evidence: census: `LiveTpmResourceEffectPort` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits outside the crate -- d2b-provider-device-tpm#6 sev=low blast=leaf effort=S verdict=actionable - LegacyMigrationOutcome (migration.rs:5, re-exported lib.rs:24) has zero callers repo-wide: the "closed outcome of the broker-owned one-time legacy state adoption" is consumed by no broker or daemon code at HEAD - fix: delete the enum and its re-export, or wire the broker consumer it documents - [migration.rs:5, lib.rs:24] - evidence: census: `LegacyMigrationOutcome` over packages/ nixos-modules/ tests/ docs/reference/ labs/ = 0 hits -- clean: api seed 1 = 91 pub items, seed 2 = 1 hit (facets.rs:35 pub runtime: Arc - genuine shared ownership across facet clones, not a leak), seed 3 = 7 pub use arms (house single-surface pattern); the remaining exports (builders, controller, reconcile/finalize entry points, vocabulary) are consumed by d2bd or by this crate's integration tests - -## err -- d2b-provider-device-tpm#7 sev=medium blast=leaf effort=S verdict=actionable - two same-named error enums for one domain: runner.rs:43 SwtpmArgvError (one variant, LogLevelOutOfRange with no payload, returned by SwtpmSettings::validate) and swtpm_argv.rs:104 SwtpmArgvError (six variants including LogLevelOutOfRange { level }), both reachable from the crate root (lib.rs:35 re-exports the runner one; pub mod swtpm_argv exposes the other), so callers must disambiguate by module path and the two same-named LogLevelOutOfRange variants differ in shape - fix: make SwtpmSettings::validate return swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level } and delete runner::SwtpmArgvError - [runner.rs:43, swtpm_argv.rs:104, lib.rs:35, tests/conformance.rs:11] - evidence: err seed 4 (`enum \w*Error`) = 4 hits (resource_controller.rs:98, resource_effect.rs:10, runner.rs:43, swtpm_argv.rs:104); the two SwtpmArgvError definitions read in full -- clean: err seeds ran: 143/0/0/4; all 143 unwrap/expect hits are in #[cfg(test)] modules or on literally-built DurationMs::parse values in the production builders (resources.rs:215-270, fixed literals with fixed bounds - card false-positive class); no panic!/unreachable!/todo!/unimplemented!; no swallowed Results; TpmResourceControllerError wraps TpmResourceEffectError without leaking path/broker detail - -## serde -- clean: serde seeds ran: 5/7/0/14; SwtpmSettings carries deny_unknown_fields + serde default + a validate() admission gate (the conformance test pins the unknown-field refusal); no hand-written Deserialize; serde_json use is boundary rendering (declared child documents) and tests; TpmResourcePhase is Serialize-only for status rendering - -## obs -- clean: obs seeds ran: 0/0/0/11; all 11 tracing events use named fields (device=, error=, phase=, reason=) with %/? formatting; zero println/eprintln, zero interpolated messages, no instrument spans needed on these short paths - -## docs -- d2b-provider-device-tpm#8 sev=low blast=leaf effort=M verdict=actionable - Result-returning public items never enumerate their error variants: 47 `-> Result<` items (build_tpm_state_volume_spec, build_swtpm_process_spec, build_swtpm_flush_spec, generate_swtpm_argv, generate_swtpm_ioctl_flush_argv, TpmResourceController::new/reconcile/finalize, SwtpmSettings::validate, reconcile_device_tpm_controller, finalize_device_tpm_controller) carry one-line docs but no `# Errors` section, while the crate's doc standard is otherwise high (#![deny(missing_docs)] plus module docs) - fix: add `# Errors` sections naming the TpmResourceEffectError/TpmResourceControllerError/SwtpmArgvError variants each item can return - [resources.rs:53, swtpm_argv.rs:130, resource_controller.rs:132, resource_controller.rs:190] - evidence: docs seed 3 (`-> Result<`) = 47 hits, seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits -- d2b-provider-device-tpm#9 sev=low blast=leaf effort=S verdict=actionable - swtpm_argv.rs:39 `#![allow(missing_docs)]` is redundant: every pub item in the module is already documented and the crate root denies missing docs, so the opt-out lets a future undocumented pub item pass silently - fix: remove the module-level allow - [swtpm_argv.rs:39] - evidence: docs seed 1 = 78 pub items, all with doc comments; swtpm_argv.rs read in full - -## perf -- clean: perf seeds ran: 20/8/1; format! sites are swtpm argv rendering (the artifact text), one-shot inspect/JSON payloads, and error paths (cold); Vec::new() sites are empty-case metadata; the single to_string is a cold payload render; the argv builder pre-sizes with with_capacity(20) - no hot-loop allocation - -## conc -- clean: conc seeds ran: 0/3/20/0; the only production synchronization is tokio::sync::Mutex (covered under async); the AtomicBool/AtomicUsize/Ordering hits are test-only SeqCst counters in tests/resource_controller.rs; no threads, no thread_local, no unsafe Send/Sync impls - -## async -- d2b-provider-device-tpm#10 sev=medium blast=family effort=M verdict=actionable - prepare_state_dir (effects_service.rs:412) runs blocking work on the executor worker: a synchronous broker round-trip envelope_invoke_kernel (effects_service.rs:467, blocking connect/poll/recv up to kernel_io_timeout) plus NSS lookups nix::unistd::User::from_name/Group::from_name (effects_service.rs:518,525) in row_posture, none marked async-gate-allow (the crate's inventory lists only the 3 test lock sites) - fix: move the invoke and the NSS resolution off the worker (spawn_blocking or an async broker client); the same pattern exists in d2b-provider-supervisor/process/process-systemd/network-local and d2bd, so consolidation may treat it as one family class - [effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs:525] - evidence: async seed 1 (`async fn|async move|\.await`) = 76 hits; static (unmeasured); async-gate inventory for this crate = 3 sites, all test locks (effects_service.rs:865,874,887) -- d2b-provider-device-tpm#11 sev=low blast=leaf effort=S verdict=actionable - lifecycle_lease_consumed: tokio::sync::Mutex (effects_service.rs:361,698) guards a flag owned by exactly one task (into_port builds a fresh port per reconcile/finalize call and uses it once), and consume_lifecycle_lease holds the guard across `.await` (effects_service.rs:384-394); the lock can never contend - fix: replace with AtomicBool (preserves &self + Sync) or restructure the once-gate - [effects_service.rs:361, effects_service.rs:384, effects_service.rs:698] - evidence: async seed 3 (`tokio::sync::(Mutex|RwLock|Notify)`) = 2 hits (effects_service.rs:361,698); port construction read at effects_service.rs:697-700 - -## unsafe -- N/A: seeds 1-3 all zero (no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed); seed 4 alone = `unsafe_code = "forbid"` in Cargo.toml:9 plus a doc-comment mention (swtpm_argv.rs:38) - a forbid attribute does not make the lens applicable; the crate contains no unsafe code - -## ffi -- N/A: seeds 1-4 all zero (no extern "C"/no_mangle/link_section, no catch_unwind, no repr(C)/repr(transparent), no CStr/CString/c_char) - -## macro -- N/A: seeds 1-4 all zero (no macro_rules!, no proc_macro/syn/quote!, no $crate, no to_compile_error/new_spanned) - -## test -- clean: test seeds ran: 36/119/0/0; behavior-focused suite with no ignored tests: golden byte-parity against tests/golden/runner-shape/swtpm-argv-minimal.txt (swtpm_argv.rs:275), round-trips through the real v3 contract types (resources.rs:362), typed error variants via matches!/assert_eq, phase transitions, the owner fence, and the flush one-shot-outcome gate; deterministic (no network, no clock injection needed); the custom block_on harness (tests/resource_controller.rs:230-242) busy-polls with a noop waker but every scripted effect completes synchronously, so no test can hang today - -## Coverage -- idiom: 1 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 1/1/0) -- api: 4 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 5/7/0/14) -- obs: clean (seeds ran: 0/0/0/11) -- docs: 2 finding(s) -- perf: clean (seeds ran: 20/8/1) -- conc: clean (seeds ran: 0/3/20/0) -- async: 2 finding(s) -- unsafe: N/A (seeds: 0/0/0/1 - seeds 1-3 all zero; manifest `unsafe_code = "forbid"` at Cargo.toml:9) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 36/119/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md deleted file mode 100644 index dd0a0b9da..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-device-usbip.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-provider-device-usbip - d2b-provider-device-usbip -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 7015 (excl. src/generated/**; src 5863 + tests 1143 + integration 9) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (1 part) - -## idiom -- d2b-provider-device-usbip#1 sev=low blast=leaf effort=S verdict=actionable - `declared_dependency_refs` accumulates into `let mut refs = Vec::new()` and pushes in match arms where each arm returns a fixed small list - fix: return the match arms as owned `Vec` literals (or `.into_iter().flatten().collect()`) so the shape is an expression - [driver.rs:267-281] - evidence: seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (driver.rs:267); seeds 1-2 (`for \w+ in 0\.\.`, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 0 -- clean: all three seeds ran (0/0/1); the crate's hand-written `Debug` impls redact (busid.rs:25, process.rs:47, firewall.rs:39) and are the deliberate redaction pattern, not derive candidates - -## own -- d2b-provider-device-usbip#2 sev=low blast=leaf effort=S verdict=actionable - lease admission in `KernelUsbipDispatcher` clones each 16-byte lease three times per reservation (`ledger.insert)..., lease.clone())`, `self.x = Some(lease.clone())`, `Ok(lease.clone())`) - fix: move the lease into the field and clone from the field for the map and the return (two clones), or return `self.x.as_ref().unwrap().clone()` after the insert - [broker.rs:194-208, broker.rs:218-232, broker.rs:313-321, broker.rs:333-341] - evidence: seed 1 `\.clone\(\)` = 104 hits crate-wide (matrix); the triple-clone shape at broker.rs:197+205+207 (and the relay/slot/proxy twins); all other clones in the crate are explainable (owned struct fields, report snapshots, test doubles) -- clean: seeds ran (104/14/0/0 per matrix); `Arc>` sharing is genuine (one ledger per zone, handed to every dispatcher; caller d2bd/src/shared_provider_effects.rs:267); no `Rc`/`RefCell`/`Cow` - -## type -- clean: seeds ran (4/1/0): `validate_zone`/`validate_provider_class`/`validate_admission`/`validate_network` are boundary admission gates on wire strings (recorded refused class, U1 (d) 6), `watched_configuration_is_dependency: bool` is a pinned cutover contract field (controller.rs:28); `BusId`/`PhysicalUsbBackingToken`/leases are already parsed/opaque newtypes; no Option-pair or stringly-state smells - -## api -- d2b-provider-device-usbip#3 sev=medium blast=leaf effort=S verdict=actionable - `pub mod state_machine` (lib.rs:24) plus the root `pub use state_machine::{...}` (lib.rs:61-65) exposes every state-machine item at two public paths, and no external caller uses the module path - fix: make the module private (`mod state_machine`) since lib.rs already re-exports its whole surface - [lib.rs:24, lib.rs:61-65] - evidence: seed 3 `^\s*pub use ` = 9 arms; census `device_usbip::state_machine` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits outside lib.rs (docs/reference/usbip-state-machine.md:110 imports from the root) -- d2b-provider-device-usbip#4 sev=medium blast=leaf effort=S verdict=actionable - `new_authority_ledger` returns `Arc>`, leaking the concrete lock type into the public signature and making any lock change a breaking change for the caller - fix: introduce an opaque `AuthorityLedgerHandle` newtype wrapping the `Arc>` (or a `pub type` alias) so the handle is the API - [broker.rs:131-133] - evidence: seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 4 hits (broker.rs:131, facets.rs:50+65, test_support.rs:101); the facets `Arc` fields are justified shared daemon-supplied facets (built at d2bd/src/resource_plane_v3.rs:2009-2015); census `new_authority_ledger` = 1 caller (d2bd/src/shared_provider_effects.rs:267); the Arc sharing itself is genuine, only the lock-type leak is the finding -- clean: 313 pub items (matrix) are the deliberate declared-provider surface; `pub use` re-export arms in lib.rs are the house single-surface pattern; the other `pub mod`s (broker, core_adapter, effects_service, facets, reconcile_state, vocabulary) each have external module-path consumers (d2bd/src/composition.rs:9557, resource_plane_v3.rs:1874, shared_provider_effects.rs:60) - -## err -- d2b-provider-device-usbip#5 sev=medium blast=leaf effort=M verdict=actionable - `UsbipStepExecutor` returns `Result<(), String>` from every step method, forcing implementers and callers to string-match reasons where the crate's own taxonomy is otherwise typed enums with `code()` accessors - fix: introduce a closed per-step error enum (or reuse `UsbipPlanError` tagged with the step) and map it in `execute_usbip_plan` - [state_machine.rs:378-386] - evidence: seed 4 `enum \w*Error` = 8 typed enums, all with stable `code()` accessors; the trait is the crate's only `Result<(), String>` surface; census `UsbipStepExecutor` = 1 impl (state_machine.rs:510, test fixture only) and docs/reference/usbip-state-machine.md:126 records "no production adapter currently implements this trait" -- clean: seed 1 `.unwrap\(\)|\.expect\(` = 12 hits, all inside `#[cfg(test)]` or the literal-constant `expect` at lifecycle.rs:56 (recorded false-positive class); seed 2 `let _ = |\.ok\(\);` = 0; seed 3 `panic!` = 2, both in tests; error enums carry no caller-controlled identity - -## serde -- clean: seeds ran (8/12/1/3): 8 derives with `rename_all`/`deny_unknown_fields`/`tag` conventions, 1 hand-written `Deserialize` (`UsbipReconcileCorrelationId`, reconcile_state.rs:293) plus the `deserialize_with` VM-shape gate (reconcile_state.rs:37) - both are live admission gates in the recorded refused class (U1 (d) 6, do not re-flag); `serde_json` calls are error-mapped boundary conversions (driver.rs:305-316); optionality meanings (`default` + `skip_serializing_if` + `Option`) are used deliberately on `UsbipEventSource.vm` (reconcile_state.rs:220-224) - -## obs -- clean: seeds ran (0/0/0/45): zero `println!`/`eprintln!`; zero interpolated-first-argument events - every tracing site uses named fields with a trailing message (e.g. lifecycle.rs:251-256); no secret in fields (resource refs are the crate's canonical identities, and wrong_zone_and_redaction.rs:77-98 pins identity-free Debug/metric labels); no spans needed since the crate has no async orchestration of its own - -## docs -- d2b-provider-device-usbip#6 sev=medium blast=leaf effort=M verdict=actionable - `#![allow(missing_docs)]` in reconcile_state.rs:6 and state_machine.rs:61 contradicts the crate's `#![deny(missing_docs)]` (lib.rs:9), leaving root-re-exported pub items without doc contracts (`UsbipPolicyFailure::telemetry_label`, `UsbipEventSource::vm`/`component`, `UsbipReconcileCorrelationId::new`, `UsbipClaimSource::is_explicit`, `UsbipExecutionReport::is_ok`, `UsbipBusidPlan::stop_order`) - fix: document the pub items and drop the two module-level allows - [reconcile_state.rs:6, state_machine.rs:61, lib.rs:9] - evidence: docs seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0; lib.rs:9 `#![deny(missing_docs)]` vs the two module allows; the affected items are re-exported at the crate root (lib.rs:61-65) -- d2b-provider-device-usbip#7 sev=medium blast=leaf effort=M verdict=actionable - Result-returning public items have no `# Errors` section anywhere in the crate, so callers cannot learn the closed failure sets from the docs - fix: add `# Errors` sections naming the variants to `UsbipArbitrator::new`, `BusId::parse`, `UsbipBindingContext::new`, `UsbipBindingController::new`, `build_usbip_plan`, `execute_usbip_plan`, `admit_bind_bus_class`, `binding_child_resources` - [arbitration.rs:76, busid.rs:12, broker.rs:61, controller.rs:210, state_machine.rs:254, state_machine.rs:429, vocabulary.rs:70, lifecycle.rs:43] - evidence: seed 3 `-> Result<` = 111 hits (matrix docs total 424 = 313 pub items + 111 Result returns); seed 2 canonical sections = 0 hits -- clean: first sentences are one-line contract statements throughout; magic values carry the why (USBIP_DEVICE_MAJOR vocabulary.rs:33, USBIP_REPAIR_INTERVAL_SECS controller.rs:14) - -## perf -- clean: seeds ran (4/5/12): `format!` only in plan-error paths (state_machine.rs:287,298,345) and a test (741) - cold per the card; `Vec::new()` at empty-case-common or fixture sites (arbitration.rs:90, lifecycle.rs:904, state_machine.rs:489+495) plus driver.rs:267 (covered by idiom#1); `to_string`/`to_owned` at wire-rendering and owned-projection boundaries; no hot loops; all findings static (unmeasured) - -## conc -- d2b-provider-device-usbip#8 sev=low blast=leaf effort=S verdict=policy-confirmed - `test_support.rs` recorders use `parking_lot::Mutex` (fields at 25/27/29/70/72, `.lock()` at 35/46-47/58-59/82/93) with no per-site allow, but parking_lot is banned outright with the single R4 bounded-worker exception - fix: replace with `tokio::sync::Mutex` (the clippy.toml-named replacement) or add the sanctioned `cfg(test) helper` per-site allow - [test_support.rs:25, test_support.rs:35, Cargo.toml:30] - evidence: seed 2 `\bMutex<` = 9 hits (broker.rs:131-157 tokio::sync::Mutex x4, test_support.rs parking_lot::Mutex x5); zero `#[allow(clippy::disallowed_methods)]` sites in the crate; policy: clippy.toml:40 "parking_lot is banned outright (plan KD3)"; the site is not on the recorded exception list (U1 (d) 2) -- clean: `AtomicU64` + `Ordering::Relaxed` token counter (broker.rs:123) is the weakest-correct ordering for a nobody-synchronizes-on counter; the shared `tokio::sync::Mutex` ledger is used via `try_lock` in synchronous dispatcher methods, never held across an await; no threads, no `thread_local!`, no manual `Send`/`Sync` - -## async -- clean: seeds ran (18/0/4/0): all `async fn`s are thin delegations to the daemon-supplied facets (`UsbipRuntime`/`UsbipBrokerDispatch`) with no spawn/select/join/block_on; the ledger mutex is never held across `.await` (try_lock in sync methods); `#[async_trait]` is the pragmatic object-safe choice; no runtime is started inside the library - -## unsafe -- N/A: seeds 0/0/0 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`); manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) and no `unsafe_code` text in src - -## ffi -- N/A: seeds 0/0/0/0 all zero (`extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char`); the crate crosses no foreign boundary - -## macro -- N/A: seeds 0/0/0/0 all zero (`macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned`); no macros defined or used beyond std - -## test -- d2b-provider-device-usbip#9 sev=low blast=leaf effort=S verdict=actionable - conformance.rs:63-66 asserts `AttachmentCommand::Attach(AttachmentActivation::Declared)` equals an identical literal, an assertion that cannot fail - fix: delete the tautological assert_eq (the same test's other asserts already pin the enum shape) - [tests/conformance.rs:63-66] - evidence: seed 2 `assert_eq!\(|assert_ne!\(|assert!\(` = 229 hits (matrix); the two compared expressions are the same literal construction -- d2b-provider-device-usbip#10 sev=medium blast=leaf effort=S verdict=actionable - `UsbipArbitrator` branches are untested: only the exclusive second-claim conflict is covered, while the constructor ceiling/ArbitrationViolation validation, `MaxClaimsExceeded`, idempotent re-claim by the same holder, and `release` have no test - fix: add a table-driven unit test over the ceiling, arbitration mode, re-claim, and release paths - [tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, src/arbitration.rs:117-121] - evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 40 hits across src+tests; arbitration_conflict.rs:8 is the only arbiter test and exercises one of the four claim branches -- d2b-provider-device-usbip#11 sev=medium blast=leaf effort=S verdict=actionable - the crate's declared wire types (`UsbipEventSource`, `UsbipReconcileAttemptContext`, `UsbipPublicDegradedReason`, `UsbipClaimSource`) have no serde round-trip test with a real-shaped payload, so kebab-case/camelCase wire drift would pass - fix: add a round-trip test deserializing a hand-written payload for each serde type and re-serializing - [src/reconcile_state.rs:51-308, src/state_machine.rs:98-100] - evidence: serde seeds = 25 hits in src but tests/ contains zero `serde_json`/`from_value`/`to_value`/`to_vec` hits; the daemon consumes the vocabulary via `to_public_reason` (d2bd/src/composition.rs:9556-9798), so the wire shapes are live contract -- clean: the suite is behavior-focused (call-order arrays, phase transitions, error variants not Display strings, redaction canaries at wrong_zone_and_redaction.rs:77-98); table-driven loops carry failure messages (state_machine.rs:730-754, vocabulary.rs:88-96); no `#[ignore]`, no network/time dependence; `integration/attach_detach_lifecycle.rs` is a declaration-only policy-required scaffold (recorded class, U1 (d) 5-6, not flagged) - -## Coverage -- idiom: 1 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 4/1/0) -- api: 2 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 8/12/1/3) -- obs: clean (seeds ran: 0/0/0/45) -- docs: 2 finding(s) -- perf: clean (seeds ran: 4/5/12) -- conc: 1 finding(s) -- async: clean (seeds ran: 18/0/4/0) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) -- test: 3 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md deleted file mode 100644 index 72c2640d4..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p1.md +++ /dev/null @@ -1,85 +0,0 @@ -# d2b-provider-display-wayland-p1 - d2b-provider-display-wayland - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9342 (excl. src/generated/**) | modules: wayland_proxy/{bridge,clipboard,decoration,diag,dmabuf,filter,identity,mod,policy,readiness} -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 = src/wayland_proxy/** (part 2 = src/controller.rs, src/runtime.rs, src/process.rs, src/bin/**, src/spec.rs, src/policy.rs, src/session_children.rs, src/principal.rs, src/lib.rs) - -## idiom -- d2b-provider-display-wayland-p1#1 sev=low blast=leaf effort=S verdict=actionable - handoff_via_bridge re-wraps the bound `error` into a fresh `HandoffStatus::Failed(error)` and immediately matches it back out with a `_ => unreachable!()` arm that can never fire; the outer match arm already binds the value - fix: delete the `let status = ...` / `let error = match status {...}` round-trip and use the arm-bound `error` directly in filter.rs:620-628 - [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:620, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:624] - evidence: err seed 3 `panic!\(|unreachable!\(|todo!\(|unimplemented!\(` = 2; static read of filter.rs:606-631 shows the re-match is on a value constructed two lines earlier -- d2b-provider-display-wayland-p1#2 sev=low blast=leaf effort=S verdict=actionable - handle_bind dispatches per-interface handler installation through a nested `match try_downcast::() { Some => ..., _ => match try_downcast::() { Some => ..., _ => { if let ... } } }` while the same function already uses edition-2024 if-let chains for viewporter and dmabuf, mixing two dispatch styles in one body - fix: flatten the nested match into `if let Some(wm_base) = ... else if let Some(eglstream) = ... else if let Some(compositor) = ...` chains, keeping the early `return` arms - [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1272, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:1300] - evidence: idiom seed 1 `for \w+ in 0\.\.` = 12; static read of filter.rs:1191-1332 (the fn mixes nested match with `if let ... && let ...` chains at filter.rs:1296-1304) -- d2b-provider-display-wayland-p1#3 sev=low blast=leaf effort=S verdict=actionable - filter_format_table iterates `for (index, entry) in table.chunks_exact(16).enumerate()` but the index is never used except `let _ = index;` inside the overflow branch, an ignore that exists only to silence the unused variable - fix: drop `.enumerate()` and remove `let _ = index;` - [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:790, packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:801] - evidence: idiom seed 1 `for \w+ in 0\.\.` = 12; static read of dmabuf.rs:790-806 (the `Ok` branch derives `new_index` from `filtered.len() / 16`, never from `index`) -- d2b-provider-display-wayland-p1#4 sev=low blast=leaf effort=S verdict=actionable - sanitize_label calls `out.chars().count()` on every loop iteration, a quadratic re-count of the output string that grows with the label length (bounded at 64 chars, so cheap, but the shape invites the same mistake at a larger bound) - fix: track a `let mut written = 0usize;` counter incremented per pushed char and compare against `MAX_LABEL_CHARS` - [packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:150] - evidence: idiom seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 8; static read of decoration.rs:146-171 -- d2b-provider-display-wayland-p1#5 sev=low blast=leaf effort=S verdict=actionable - four comment blocks are mangled prose: a non-ASCII full stop (`\u3002`) at dmabuf.rs:820, a stray `**` at filter.rs:769, two `; no` joins missing the space after the semicolon at filter.rs:770 and filter.rs:2801, and misindented two-line comment pairs at decoration.rs:1804-1805, dmabuf.rs:819-820 and filter.rs:2799-2801 where the continuation line sits at 4-space indent inside the fn - fix: rewrite the four comments as plain ASCII with normal spacing and consistent indent - [packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs:820, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:769, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:770, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:2801, packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs:1804] - evidence: static (grep for `\u3002|\uff1b` and `\*\*|; no` over the module = 1 and 3 hits respectively; all four sites read) - -## own -- d2b-provider-display-wayland-p1#6 sev=low blast=leaf effort=S verdict=actionable - FilterPolicy carries `dmabuf_filters: std::sync::Arc` (built at policy.rs:316, cloned into DmabufHandler at filter.rs:1305) while the entire proxy is a single-threaded `Rc` graph - no thread or `'static` boundary justifies Arc, and the conc seeds are all zero - fix: switch the field and `DmabufHandler::new` parameter to `Rc` - [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:186, packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:316] - evidence: own seed 3 `Rc<|RefCell<|Arc Result<` = 9; docs seed 2 = 0 (no canonical sections anywhere in the module) - -## perf -- clean: perf seeds 1-3 ran (53 / 31 / 11); every `format!` site is a cold path (lazy diag closures, error details, startup policy messages, identity labels built once per instance); no `format!` or allocation sits in a per-message hot loop; the rail pixel buffer is cached behind `FrameKey` (decoration.rs:1011) and only rebuilt when the key changes; the one bounded-quadratic `chars().count()` is covered by idiom#4; all findings here are static (unmeasured) - -## conc -- N/A (seeds: 0/0/0/0 all zero; the module declares no threads, mutexes, atomics, or thread_local - it is a single-threaded `Rc`/`RefCell` handler graph, so the lens has nothing to judge) - -## async -- N/A (seeds: 0/0/0/0 all zero; no async fn, await, spawn, or tokio sync primitive in the module - the proxy is a synchronous poll-driven loop and every blocking call site carries the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` marker: readiness.rs:29, filter.rs:771, filter.rs:2880, bridge.rs:280, dmabuf.rs:822, decoration.rs:1806) - -## unsafe -- N/A (seeds: 1-3 zero after false positives; the 2 `from_raw` hits are the safe `std::io::Error::from_raw_os_error` at filter.rs:991 and filter.rs:2824, not raw-pointer conversion; no `unsafe` block, fn, or impl exists in the module and the crate forbids unsafe_code at lib.rs:5) - -## ffi -- N/A (seeds: 0/0/0/4; the four `CString` hits are memfd name arguments at libc call sites (memfd_create at dmabuf.rs:823 and decoration.rs:1808), which never cross a foreign caller - the U1 ffi false-positive class) - -## macro -- d2b-provider-display-wayland-p1#12 sev=low blast=leaf effort=S verdict=actionable - the local `macro_rules! entry!` (policy.rs:420-437) is a two-arm table-filling shorthand whose `max=` arm only omits one field; it is not variadic, does not generate impls per type, and is not a DSL, so a plain function is the cheaper answer - fix: replace the macro with `fn entry(m: &mut HashMap, iface: &str, action: GlobalAction, class: Classification, max: Option)` and update the ~70 call rows; the catalog content stays byte-identical (the hand-written catalog itself is Nix-pinned and refused at docs/explanation/over-engineering-audit-record.md:352, 427-429 - this finding touches only the mechanism) - [packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420] - evidence: macro seed 1 `macro_rules!` = 1 (sole definition in the module); static read of policy.rs:417-465 - -## test -- d2b-provider-display-wayland-p1#13 sev=high blast=leaf effort=S verdict=actionable - two registry-handler tests cannot fail on any behavior change: `filtered_globals_preserve_original_global_names` (filter.rs:3213-3224) inserts entries into `advertised_globals`/`hidden_globals` and asserts their presence - pure setup restatement with no function under test - and `standard_clipboard_global_is_advertised_as_synthetic` (filter.rs:3264-3283) admits in its comment that the real path is untested and then asserts only `interface.name()` plus the map content it just inserted - fix: delete the first test and rewrite the second to exercise `prepare_global(11, ObjectInterface::WlDataDeviceManager, 3)` and assert the synthetic `GlobalAdvertisement` decision, as the neighboring `prepare_global_hides_*` tests already do - [packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3213, packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:3264] - evidence: test seeds over src/wayland_proxy + tests/: `#\[test\]` = 130, `assert_*` = 301, proptest/insta/rstest = 0, `#\[ignore\]` = 0; static read of filter.rs:3213-3224 and filter.rs:3264-3283 (assertions restate the inserted state) - -## Coverage -- idiom: 5 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 2/0/0; boundary validation already parse-once at the single construction path) -- api: 2 finding(s) -- err: clean (seeds ran: 63/10/2/1; every production panic site is an invariant-named expect or a U1 false-positive class) -- serde: 1 finding(s) -- obs: clean (seeds ran: 0/1/0/20; no println, consistent key=value event scheme with lazy closures, bounded-metadata policy documented) -- docs: 2 finding(s) -- perf: clean (seeds ran: 53/31/11; format!/allocation sites are cold or lazy, rail redraw cached by FrameKey) -- conc: N/A (seeds: 0/0/0/0 all zero; single-threaded Rc/RefCell handler graph) -- async: N/A (seeds: 0/0/0/0 all zero; synchronous poll-driven proxy with sanctioned synchronous-path allows) -- unsafe: N/A (seeds: 0/0/2/0 with the 2 from_raw hits being safe from_raw_os_error; no unsafe blocks; crate forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/4; CString hits are memfd name args at libc call sites, not a foreign-caller boundary) -- macro: 1 finding(s) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md deleted file mode 100644 index 935d47e3e..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-display-wayland-p2.md +++ /dev/null @@ -1,89 +0,0 @@ -# d2b-provider-display-wayland-p2 - d2b-provider-display-wayland - part 2/2 -Baseline: 6ebdd4cec | LOC audited: 6464 (excl. src/generated/**) | modules: controller, runtime, process, bin (d2b-wayland-proxy), spec, policy, session_children, principal, lib -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f): src/controller.rs, src/runtime.rs, src/process.rs, src/bin/**, src/spec.rs, src/policy.rs, src/session_children.rs, src/principal.rs, src/lib.rs - -## idiom -- d2b-provider-display-wayland-p2#1 sev=low blast=leaf effort=S verdict=actionable - three stale `#[allow(dead_code)]` markers sit on constructors that production code calls: `FinalizationInput::from_supervisor` (controller.rs:464), `LaunchGrants::from_supervisor_for_session_with_frontend_and_controller` (process.rs:402), `ProcessObservation::from_supervisor` (process.rs:676) - fix: delete the three allows (keep process.rs:380, whose constructor is test/test-support-only) so a future real dead-code warning is not masked - [src/controller.rs:464, src/process.rs:402, src/process.rs:676] - evidence: idiom seeds: 0 index loops / 3 hand-written impls / 2 statement accumulations; allows judged stale by reading call sites: runtime.rs:247,748,811,858 and process.rs:349 all reach production paths -- d2b-provider-display-wayland-p2#2 sev=medium blast=leaf effort=S verdict=actionable - the session binding digest is derived twice with byte-identical bodies: free fn `session_digest` (controller.rs:1442) duplicates `WaylandSessionSpec::session_digest` (spec.rs:385), so the two can silently diverge - fix: make the controller free fn delegate to `spec.session_digest(controller_generation)` and keep spec.rs:385 as the canonical home (census: d2bd already consumes the method at interaction_composition.rs:4080,4267) - [src/controller.rs:1442, src/spec.rs:385] - evidence: session_digest census over packages/ = 2 definitions with identical bodies (controller.rs:1442, spec.rs:385); both hash guest/host/user refs, reconnect generation, controller generation with [0] separators -- clean: index-loop seed 0 hits; the 3 hand-written Default impls (controller.rs:221, process.rs:154, process.rs:641) are invariant-preserving or test-support, not derive candidates; the 2 `Vec::new()` accumulations (process.rs:219, policy.rs:272) are conditional-push loops where an iterator would obscure - -## own -- clean: seeds ran 66 clone / 37 to_owned-family / 0 Rc-RefCell-Arc-Mutex / 0 Cow; every clone inspected is explainable (multi-pass reconcile clones at runtime.rs:397,451,599,654; lease principal copies at controller.rs:1085,1112; set-ownership clones in policy.rs:281-354; durable-name clones in session_children.rs:65-143; CLI startup clones in bin); no Rc/RefCell in library code, only in the single-threaded bin accept loop where shared mutable handler state genuinely has multiple owners - -## type -- clean: seeds ran 4 validate/check fns / 1 bool flag / 0 stringly state; the validate fns are parse-once boundary checks inside constructors (validate_label/validate_color in DisplayIdentity::new, validate_bounds in FilterInput::new, validate_layer in WaylandPolicy::compile) exactly per the skill; the one bool (DisplayRunnerContract.watched_configuration_is_dependency, controller.rs:30) is a contract flag; wire-mirroring booleans (cross_domain_trusted, virgl_video, debug_logging, border_enabled) are schema-pinned and not flagged - -## api -- d2b-provider-display-wayland-p2#3 sev=medium blast=leaf effort=S verdict=actionable - `PrincipalReleaseReceipt` (controller.rs:702, re-exported at lib.rs:20) is unconstructible: private `session_key` field and no constructor, so `DisplayController::release_session_principal` (controller.rs:1379) can never be called by the daemon; the principal-release path is dead exported surface - fix: add a constructor and wire the daemon cleanup path to call release_session_principal, or make both pub(crate) until the path is wired - [src/controller.rs:702, src/controller.rs:1379, src/lib.rs:20] - evidence: census: PrincipalReleaseReceipt|release_session_principal over packages/; nixos-modules/; tests/; docs/reference/; labs = 4 hits, all in-crate (controller.rs:702,706,1381; lib.rs:20); release_session_principal has zero callers -- d2b-provider-display-wayland-p2#4 sev=low blast=leaf effort=S verdict=actionable - `WaylandPolicySnapshot::from_authenticated_session` (controller.rs:580) has no callers anywhere; the daemon resolves snapshots via `from_authenticated_route` - fix: delete the wrapper or mark it deliberate with a comment naming the route-based entry as canonical - [src/controller.rs:580] - evidence: census: from_authenticated_session over packages/ = 1 hit (the definition); daemon uses from_authenticated_route (d2bd interaction_composition.rs:2279) -- clean: api seed 2 (Arc/Rc/Box/RefCell in pub signatures) = 0 hits; seed 3 re-export arms in lib.rs are the house single-surface pattern; pub surface is otherwise deliberate (opaque grant/lease types with redacted Debug, pub(crate) fields on ProcessObservation and WorkerRestartEvidence, test-support-gated constructors) - -## err -- d2b-provider-display-wayland-p2#5 sev=medium blast=leaf effort=S verdict=actionable - `DisplayController::new(pool_size)` panics via `PrincipalPool::new(pool_size).expect(...)` (controller.rs:740-741) on any caller-supplied pool size outside 1..=32; the pub library API should not panic on input-derived values - fix: return `Result` from `DisplayController::new` (or document `# Panics` naming the bound) and update the two daemon call sites - [src/controller.rs:740, src/controller.rs:741] - evidence: err seed 1 = 75 hits, 3 outside tests (controller.rs:741,746,1048); the 1048 expect is justified (grants checked non-None two branches earlier); current DisplayController::new callers pass constants (d2bd interaction_composition.rs:2294,7164), so no live trigger -- d2b-provider-display-wayland-p2#6 sev=low blast=leaf effort=S verdict=actionable - `WaylandSpecError::NoPrincipalAvailable` (spec.rs:30) is never constructed: pool exhaustion is mapped to a Failed status with `SessionCondition::NoPrincipalAvailable` instead of the error variant - fix: either construct the variant in the exhaustion path (controller.rs:1089) or delete it and its Display arm - [src/spec.rs:30, src/spec.rs:43] - evidence: census: WaylandSpecError::NoPrincipalAvailable over packages/ = 2 hits (spec.rs:30,43); controller.rs:1089-1101 returns a Failed status rather than the error -- d2b-provider-display-wayland-p2#7 sev=medium blast=leaf effort=M verdict=actionable - grant and ticket constructors return `Result<_, &'static str>` error codes (`issue_for_supervisor_with_controller_generation` process.rs:335-346, `new_for_role_with_controller_generation` process.rs:825-887), so callers cannot match the failure and the codes are untyped strings - fix: introduce a closed `LaunchError` enum (thiserror) with `SessionInvalid` and `TicketInvalid` variants and return it from both constructors; the daemon caller maps to WorkerEffectError today (d2bd interaction_composition.rs:4283) - [src/process.rs:335, src/process.rs:346, src/process.rs:825, src/process.rs:886] - evidence: err seed 4 = 6 error enums in lane scope, all closed and well-split; the two &'static str returns are the only untyped error paths -- clean: err seeds 75 unwrap/expect (72 in tests) / 8 let _ (7 best-effort readiness reports before exit in bin, 1 test artifact) / 0 panic-unreachable-todo / 6 error enums; error taxonomy is otherwise exemplary (WorkerEffectError split by caller action, DisplayRuntimeError forwards effect codes, PolicyCompileError carries the offending interface) - -## serde -- d2b-provider-display-wayland-p2#8 sev=low blast=leaf effort=S verdict=actionable - `#[serde(try_from = "WaylandSessionSpecWire")]` (spec.rs:233) is inert: WaylandSessionSpec derives only Serialize, and Deserialize is hand-written (spec.rs:263-270) to do exactly what the derive plus try_from would generate - fix: delete the inert attribute (keep rename_all for the Serialize side), or derive Deserialize with try_from and delete the manual impl; pick one mechanism - [src/spec.rs:230, src/spec.rs:233, src/spec.rs:263] - evidence: serde seeds 10 derives / 12 serde attrs / 3 hand-written Deserialize impls (spec.rs:105,263; policy.rs:194); the other two manual impls are live admission gates (recorded refusal, not re-flagged); deny_unknown_fields is enforced through the Wire structs so the attribute block adds nothing -- clean: wire admission gates (DisplayIdentityWire, WaylandSessionSpecWire, FilterInputWire) all deny_unknown_fields and validate through TryFrom; CompiledWaylandPolicy round-trips with private fields; DisplayProcessRole and DisplayLabelPosition use kebab-case per house convention - -## obs -- clean: seeds ran 17 println/eprintln (all in bin, CLI product output carved out by the card) / 51 interpolated log macros (all in bin, same carve-out) / 0 instrument / 44 tracing uses; library tracing is exemplary: named fields (zone, guest, session, error) on every event, lazy format! closures in the bin's DiagRateLimiter, no secret material in any field, error chains logged once at the boundary that handles them - -## docs -- d2b-provider-display-wayland-p2#9 sev=low blast=leaf effort=S verdict=actionable - `FilterInput::allow_globals` and `FilterInput::deny_globals` doc comments say "Add an allowed global to this layer" / "Add a denied global to this layer" but the methods are getters returning `&[String]` - fix: reword to "Borrow the allowed globals of this layer" / "Borrow the denied globals of this layer" - [src/policy.rs:114, src/policy.rs:119] - evidence: docs seed 1 = 226 pub items, all read in full; policy.rs:114-122 doc text contradicts the getter shape (copy-paste from the builder intent) -- d2b-provider-display-wayland-p2#10 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub API has no `# Errors` canonical sections despite `#![deny(missing_docs)]`: constructors and reconcilers document their failure modes only through the error-enum variant docs - fix: add `# Errors` sections naming the variants on the pub Result items, e.g. `DisplayIdentity::new`, `WaylandSessionSpec::new`, `WaylandPolicy::compile`, `DisplayController::reconcile_authenticated_session` - [src/spec.rs:117, src/spec.rs:286, src/policy.rs:247, src/controller.rs:759] - evidence: docs seed 2 (canonical sections) = 0 hits; seed 3 = 81 `-> Result<` items; first sentences are otherwise strong and every pub item is documented -- clean: docs seed 1 = 226 pub items (all read), seed 2 = 0, seed 3 = 81; doc quality is high (one-line first sentences, module docs on every module, redacted Debug documented as deliberate); the two findings above are the only shape gaps - -## perf -- d2b-provider-display-wayland-p2#11 sev=low blast=leaf effort=S verdict=actionable - `durable_display_suffix` (session_children.rs:316-318) builds a 40-char hex suffix with one `format!` allocation per byte (20 allocations) instead of writing into the already-preallocated `String::with_capacity(40)` - fix: push two hex digits per byte via a lookup table or a single hex write into `suffix`, keeping the preallocation - [src/session_children.rs:316, src/session_children.rs:317] - evidence: perf seed 1 = 16 format! sites; this is the only format! in a loop; cold durable-naming path, static (unmeasured) -- clean: perf seeds 16 format! (rest are cold error/diagnostic paths or single-shot renders) / 20 collection news (empty-case-common or bounded) / 37 to_string (wire rendering and CLI); no hot-path allocation or collection-choice issue found - -## conc -- N/A: seeds 0/0/0/0 all zero; no threads, locks, atomics, or thread_local in part 2 (Rc/RefCell in the bin is single-threaded shared state, not a concurrency model) - -## async -- N/A: seeds 0/0/0/0 all zero; no async fn, spawn, tokio sync, or runtime entry in part 2; the crate is a synchronous reconciler plus a poll-loop binary - -## unsafe -- N/A: seeds 1-3 zero real hits (the 4 `from_raw` matches are the safe std `io::Error::from_raw_os_error` in bin tests); lib.rs:4 `#![forbid(unsafe_code)]` alone does not make the lens applicable - -## ffi -- N/A: seeds 0/0/0/0 all zero; no extern, no_mangle, repr(C), or CStr in part 2 - -## macro -- N/A: seeds 0/0/0/0 all zero; no macro_rules!, proc macro, or $crate in part 2 - -## test -- d2b-provider-display-wayland-p2#12 sev=medium blast=leaf effort=S verdict=actionable - the principal-release contract has no test and the test named `core_policy_snapshot_and_principal_receipt_are_consumed_by_controller` (controller.rs:1481) never touches `PrincipalReleaseReceipt` or `release_session_principal`; the name overclaims and the release path (acquire, release, re-acquire, UnknownLease on foreign receipt) is unverified - fix: rename the test to what it asserts (snapshot consumption) and add a release-path test exercising `release_session_principal` with a constructed receipt, asserting pool re-acquisition and UnknownLease for a foreign receipt - [src/controller.rs:1481, src/controller.rs:1379] - evidence: test seed 1 = 48 #[test] in lane scope (6 controller, 3 runtime, 6 process, 16 bin, 1 src/policy.rs, 1 session_children, 13 provider_behavior, 1 tests/policy.rs, 1 lifecycle); controller.rs:1481-1505 body reconciles and asserts Phase::Ready only -- clean: test seeds 48 #[test] / ~120 asserts / 0 proptest-insta-rstest / 0 #[ignore]; tests assert behavior (phase transitions, error variants via matches!, cleanup order, wire validation reuse, digest fencing), expectations are human-written, and the bin tests cover accept-error classification and poll-timeout bounds; no test that cannot fail found - -## Coverage -- idiom: 2 finding(s) -- own: clean (seeds ran: 66/37/0/0) -- type: clean (seeds ran: 4/1/0) -- api: 2 finding(s) -- err: 3 finding(s) -- serde: 1 finding(s) -- obs: clean (seeds ran: 17/51/0/44) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics in part 2) -- async: N/A (seeds: 0/0/0/0 all zero; no async code in part 2) -- unsafe: N/A (seeds: 0/0/0 real; only lib.rs:4 forbid(unsafe_code); from_raw_os_error is a safe std fn) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md deleted file mode 100644 index fe910b188..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-endpoint.md +++ /dev/null @@ -1,72 +0,0 @@ -# d2b-provider-endpoint - d2b-provider-endpoint -Baseline: 6ebdd4cec | LOC audited: 2534 (excl. src/generated/**; incl. tests/**) | modules: whole crate (`src/lib.rs`, `src/driver.rs`, `src/endpoint.rs`, `src/effects_service.rs`, `src/facets.rs`, `src/test_support.rs`, `tests/registration.rs`) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none - -## idiom -- d2b-provider-endpoint#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default for EndpointConsumerPolicy` returns `Self::unrestricted()`, which the field-wise derive would produce identically (empty Vecs) - fix: add `Default` to the derive list on `EndpointConsumerPolicy` and drop the manual impl - [packages/d2b-provider-endpoint/src/endpoint.rs:395-398] - evidence: idiom seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit (endpoint.rs:395) -- d2b-provider-endpoint#2 sev=medium blast=leaf effort=S verdict=actionable - the `inspect-endpoint` payload table hardcodes the four committed purposes and their producer/locality/class strings, duplicating the same-module derivations `guest_control_producer`/`device_worker_endpoint_class` built from the provider constants, so a provider role/purpose rename drifts the report silently - fix: build the table from those fns, or constrain it with a unit test pinning the payload rows to the derivations - [packages/d2b-provider-endpoint/src/effects_service.rs:50-60,73-84,128-143] - evidence: static cross-read: payload rows at effects_service.rs:132-137 repeat the values the fns at 50-60,73-84 produce,and no test exercises `inspect_endpoint_response()` -- clean: idiom seeds ran: two/one/zero hits; the two index-loop hits are deliberate `yield_now()` nudge loops in tests,and no statement-style accumulation exists - -## own -- clean: own seeds ran: fourteen/eleven/zero/zero hits; every clone/`to_owned` is explainable: `Arc` clones at factory/spawn fences (driver.rs:338,273,57-58), `ResourceRef`/`String` copies riding into `tokio::spawn` (driver.rs:463-464), `error.detail.clone()` inside the borrowed `classify_error`, test-fixture rows, wire-rendering `to_owned` strings in the service payload - -## type -- clean: type seeds ran: one/zero/zero hits; the one `check_shape` hit classifies a closed realization set that depends on a dynamic vocabulary trait,not an invariant a parsed type can carry; no boolean-flag soup or stringly-typed state exists - -## api -- clean: api seeds ran: sixty-eight/seven/three hits over three seeds; the public surface is the deliberate contract vocabulary (`pub mod endpoint` + `pub use` arms are loaded by d2bd,display-wayland,volume-binding - census: `provider_endpoint::endpoint::` over packages = more than ten hits),andthe only `Arc<...>` in public positions are the composition-supplied facet seams whose ownership is genuinely shared (factory clones `EndpointEffectFacets` per driver at driver.rs:338; daemon builds once at d2bd/resource_plane_v3.rs:2125) - -## err -- clean: err seeds ran: about forty hits over four seeds; every `unwrap`/`expect`/`panic!` sits in `#[cfg(test)]` fixtures over literal-built values; the one production `let _ =` (driver.rs:484) drops the effect-completion `send` as best-effort at resource teardown (the receiver dies with the context,so the report has no consumer); the two `String`-returning effect seams are report-only,re-wrapped into `FailureDetail` notes - -## serde -- d2b-provider-endpoint#3 sev=medium blast=leaf effort=S verdict=actionable - `EndpointAttachmentPolicy`'s derived `Deserialize` admits illegal state (`supported=false, max_attachments>0`,andthe converse), while its sibling `EndpointConsumerPolicy` routes `Deserialize` through `Self::new` as an admission gate,so a standalone deserializer yields a shape the constructor refuses - fix: route `EndpointAttachmentPolicy::deserialize` through `Self::new` (try_from or the sibling hand-written pattern at endpoint.rs:197-216) - [packages/d2b-provider-endpoint/src/endpoint.rs:112-120,125-131,197-216,377-381] - evidence: serde seeds one-two=about forty-four hits; the derive at endpoint.rs:112-113 andthe sibling hand-written gate at endpoint.rs:197-216 - -## obs -- N/A: obs seeds ran: zero/zero/zero/zero all zero; the crate has no `tracing`/`log` dependency and no stdout telemetry - -## docs -- d2b-provider-endpoint#4 sev=low blast=leaf effort=S verdict=actionable -the pub Result-returning constructors lack the canonical `# Errors` section naming which condition produces which `EndpointSpecError` variant - fix: add `# Errors` blocks to `EndpointAttachmentPolicy::new`, `EndpointConsumerPolicy::new`,and `EndpointSpec::new`,each enumerated briefly - [packages/d2b-provider-endpoint/src/endpoint.rs:124-125,152-153,254-255] - evidence: docs seed two (`/// # (Examples|Errors|Panics|Safety))`) = zero hits while seed three (`-> Result<`) about six hits in pub items - -## perf -- clean: perf seeds ran: about fourteen hits over three seeds; all `format!` sites are one-shot error reports (driver.rs:385,effects_service.rs:219) or test fixtures;`Vec::new()` sites are test rows andthe `unrestricted()` policy;`to_string()` sites are test fixtures - no hot-path allocation identified (static, unmeasured) - -## conc -- clean: conc seeds ran: about thirteen hits over four seeds; the only locks/atomics are the `cfg(test)`/test-support recording doubles (`parking_lot::Mutex` + `AtomicBool`),with `SeqCst` on scripted flags - repo recorded false positive (test-only synchronization; atomics as counters),and every lock site carries the recorded `async-gate-allow` marker - -## async -- clean: async seeds ran: about one hundred two hits over four seeds; no guard held across an `.await`, no blocking work inside async contexts (the two `parking_lot` locks in test-support are marker-allowed synchronous acquisitions with no await while held),the spawned long-effect task captures `Send` values and reports through an unbounded mpsc,andthe evidence-wait loop uses async `sleep` inside a `tokio::time::Instant` deadline - cancellation-safe (the wait is resumable on retry) - -## unsafe -- N/A: unsafe seeds ran: zero/zero/zero/zero all zero; no `unsafe` block/fn/impl and no `unsafe_code` manifest allowance (local lints table: `unsafe_code = "forbid"`) - -## ffi -- N/A: ffi seeds ran: zero/zero/zero/zero all zero; no extern/C/repr/CStr surface exists - -## macro -- N/A: macro seeds ran: zero/zero/zero/zero all zero; no `macro_rules!`,proc-macro,or `$crate` use occurs - -## test -- d2b-provider-endpoint#5 sev=low blast=leaf effort=S verdict=actionable -the two long-effect tests wait a fixed sixteen-`yield_now()` budget for the spawned task to report through the double,instead of polling the observable recorded call - fix: replace each fixed loop with a bounded poll over `fake.call_order().contains("ensure-socket")` (async yield or small sleep until it appears,then assert) - [packages/d2b-provider-endpoint/src/driver.rs:824-827,1248-1251] - evidence: test seed two (`assert_eq!|assert_ne!|assert!`) about sixty of the eighty-one test-seed hits; rows at driver.rs:825,1249 are the fixed-budget waits - -## Coverage -- idiom: two finding(s) -- own: clean (seeds ran: fourteen/eleven/zero/zero; clones/to_owned all explainable: Arcs at fences,spawn copies,test rows,wire-rendering strings) -- type: clean(seeds ran: one/zero/zero; check_shape classifies a dynamic closed set,not a typestate-invariant) -- api: clean(seeds ran: sixty-eight/seven/three; public surface is deliberate contract vocabulary with loaded `endpoint::` consumers; Arc seams share ownership at the composition root; no leaking internals found) -- err: clean(seeds ran: about forty hits over four seeds; panics are test-only; the one swallowed send is best-effort at teardown; String effect errors are report-only notes) -- serde: one finding(s) -- obs: N/A (seeds: zero/zero/zero/zero; no tracing/log dep in Cargo.toml) -- docs: one finding(s) -- perf: clean(seeds ran: about fourteen hits over three seeds; all allocation sites are error paths,fixtures,andthe unrestricted policy; static inspection only) -- conc: clean(seeds ran: about thirteen hits over four seeds; only test-support/cfg(test) locks+atomics with async-gate-allow markers - recorded repo false positives) -- async: clean(seeds ran:about one hundred two hits over four seeds; no guard-across-await,blocking work,or unbounded growth; spawned effect path is Send and marker-allowed) -- unsafe: N/A (seeds: zero/zero/zero/zero; no unsafe blocks or allow manifests; local lints: unsafe_code=forbid) -- ffi: N/A (seeds: zero/zero/zero/zero; no extern/C/repr/CStr surface) -- macro: N/A (seeds: zero/zero/zero/zero; no macro_rules!,proc-macro,or $crate use) -- test: one finding(s) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md deleted file mode 100644 index 0e70a2f33..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-container-apps.md +++ /dev/null @@ -1,89 +0,0 @@ -# d2b-provider-guest-azure-container-apps - d2b-provider-guest-azure-container-apps -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2420 (excl. src/generated/**) | modules: whole crate (lib.rs, controller.rs, effects.rs; tests/provider_lifecycle.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test, supply | Partitions: none (single-part lane) - -## idiom -- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0 over src; no index loops, no hand-written derives (the TryFrom impls delegate to validated constructors), no statement-style accumulation; the one `for index in 0..2` loop lives in tests and is a bounded retry driver, not an index idiom. - -## own -- d2b-provider-guest-azure-container-apps#1 sev=low blast=leaf effort=S verdict=actionable - CompletedOperationLedger::record evicts the oldest entry by cloning the map key only to hand it to BTreeMap::remove, which accepts a borrowed key - fix: drop the `.map(|(operation_id, _)| operation_id.clone())` and call `self.completed.remove(&oldest)` directly on the `&AcaOperationId` that `iter().min_by_key)...)` yields - [src/controller.rs:156-157] - evidence: seed `\.clone\(\)` = 44 hits over src; BTreeMap::remove takes `&Q where K: Borrow`, so the eviction path needs zero clones. -- d2b-provider-guest-azure-container-apps#2 sev=low blast=leaf effort=S verdict=actionable - reconcile_observed clones the whole owned `record` parameter into `self.observed` and then matches on it, although only the Copy `lifecycle` field is read after the store - fix: `let lifecycle = record.lifecycle; self.observed = Some(record); match lifecycle { ... }` - [src/controller.rs:500-501] - evidence: seed `\.clone\(\)` = 44 hits over src; the match arms read only `record.lifecycle` (Copy), so moving the record and extracting the field first removes the clone. -- d2b-provider-guest-azure-container-apps#3 sev=low blast=leaf effort=S verdict=actionable - in the Suspended/Stopped arm of reconcile_observed the owned `record` parameter is dead after the resume closure is built, yet `record.id.clone()` copies the id instead of moving it out - fix: `let id = record.id;` (partial move) before the `move` closure - [src/controller.rs:527] - evidence: seed `\.clone\(\)` = 44 hits over src; `record` is not referenced after line 527 in that arm (later reads go through `self.observed`/`resumed`), so the move compiles. -- d2b-provider-guest-azure-container-apps#4 sev=low blast=leaf effort=S verdict=actionable - the stop and delete stages clone the entire observed `AcaSandboxRecord` (`self.observed.clone().ok_or)...)?`) although the closures consume only `record.id` - fix: clone just the id (`self.observed.as_ref().ok_or)...)?.id.clone()`) and move that into the closure - [src/controller.rs:417-419, src/controller.rs:469-471] - evidence: seed `\.clone\(\)` = 44 hits over src; both closures call `stop_sandbox`/`delete_sandbox` with `&record.id` only, so the record-level clone copies the id String plus Copy fields needlessly. -- d2b-provider-guest-azure-container-apps#5 sev=low blast=leaf effort=S verdict=actionable - one_candidate and one_disk_image clone the single match out of a slice pattern although they own the `candidates` parameter and return an owned record - fix: consume with `let mut it = candidates.into_iter(); match (it.next(), it.next()) { (Some(c), None) => Ok(Some(c)), (None, None) => Ok(None), _ => Err)...) }` - [src/controller.rs:892, src/controller.rs:903] - evidence: seed `\.clone\(\)` = 44 hits over src; both helpers take `AcaSandboxCandidates`/`AcaDiskImageCandidates` by value and every caller passes a freshly returned value, so an into_iter consumption removes both clones. -- d2b-provider-guest-azure-container-apps#6 sev=low blast=leaf effort=S verdict=actionable - AcaProviderConfig::validate() re-clones all 11 fields to re-run the constructor checks, when every check is readable from `&self` - fix: extract a private `fn validate_refs(&self) -> Result<(), AcaTypeError>` holding the resource_type() comparisons and call it from both `new` (on the raw args) and `validate` (on self) - [src/effects.rs:450-464] - evidence: seed `\.clone\(\)` = 44 hits over src; lines 451-462 clone gateway_execution_ref, tenant_id, client_id, subscription_id, control_credential_ref, pull_credential_ref, environment_id, resource_group_id, network_ref, sandbox_transport_alias, defaults solely to rebuild the struct the admission boundary already validated. - -## type -- d2b-provider-guest-azure-container-apps#7 sev=medium blast=leaf effort=M verdict=actionable - AcaProviderConfig exposes all 11 fields `pub` while its sibling validated configs (AcaRuntimeConfig, AcaSandboxProfile, AcaReadinessPolicy) keep fields private behind constructors, so a literal construction bypasses the execution-boundary validation that `new()`/`validate()` enforce - fix: privatize the fields and add accessors (network_ref, sandbox_transport_alias, defaults are read in-crate at controller.rs:940-946; no external field reads exist) - [src/effects.rs:394-406] - evidence: census: `AcaProviderConfig` over packages+tests+docs/reference+labs+nixos-modules = 20 hits, all constructions via `::new()` (packages/d2b-provider-guest/src/driver.rs:1942, packages/d2b-provider-guest/src/effects_service.rs:1807) or `serde_json::from_value` (effects_service.rs:1145); literal `AcaProviderConfig {` constructions = 0 real sites (the two regex matches are the struct definition and an accessor brace); field reads only in-crate. - -## api -- d2b-provider-guest-azure-container-apps#8 sev=low blast=leaf effort=S verdict=actionable - lib.rs re-exports the whole effects module via `pub use effects::*;` (so every future pub item in effects silently becomes public API) and effects.rs re-exports four dependency types (`CredentialLeaseHandle`, `OpaqueAzureRef`, `ResourceRef`, `ResourceUid`) with zero consumers through this crate's path - fix: replace the glob with named arms listing the intended effect surface and drop the uncalled dependency-type re-exports - [src/lib.rs:14, src/effects.rs:8-9] - evidence: census: `guest_azure_container_apps::(CredentialLeaseHandle|OpaqueAzureRef|ResourceRef|ResourceUid)` over packages+tests+labs+nixos-modules+docs/reference = 0 hits; callers import the contracts-crate paths directly (packages/d2b-provider-guest/src/driver.rs:1944), so the re-exports are surface without consumers. - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(`=1 (controller.rs:539 `expect("stored above")` asserts the invariant just stored on the previous line - acceptable per the skill's invariant-panic channel), `let _ = |\.ok\(\);`=0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`=0, `enum \w*Error`=3 (AcaControllerError, AcaTypeError, AcaControlErrorKind); the taxonomies split by caller action with stable `code()` strings, AcaControlError wraps a private kind per the struct pattern, and no wire-visible error enum is restructured. - -## serde -- clean: seeds ran: 31 combined hits (derive Serialize/Deserialize, serde attributes, hand-written Deserialize, serde_json calls); every wire type validates through `try_from` (RawAca* shapes and numeric bounds via TryFrom delegating to the validated constructors), `deny_unknown_fields` is applied to all config raws, `rename_all = "camelCase"` everywhere, and the only hand-written Deserialize impls are the opaque_id admission gates (recorded refusal class per U1 (d) 6 - not re-flagged); a real-payload round-trip test exists at effects.rs:886. - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(`=0, interpolated message-only events=0, `\.instrument\(|#\[instrument`=0, `tracing::`=15; all 15 warn!/debug! events carry named fields (resource, provider, code, purpose, lifecycle, attempt), messages are static literals, and the hand-written Debug impls (opaque_id, AcaProviderConfig, AcaSandboxRecord) redact identity material so no secret reaches a field. - -## docs -- d2b-provider-guest-azure-container-apps#9 sev=low blast=leaf effort=M verdict=actionable - `#[allow(missing_docs)]` blanket-exempts the effects module whose pub surface (AcaControl and AcaCredentialLeaseClient trait methods, AcaProviderConfig fields, Aca*Error enums, MAX_ACA_* constants) is re-exported at the crate root, undercutting the crate's own `#![deny(missing_docs)]` - fix: document the effect trait methods and validated-config accessors and drop the module-level allow (README.md already carries the prose contract, so this is rustdoc-surface work, not a contract gap) - [src/lib.rs:7, src/effects.rs:813-882] - evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 87 hits over src, the large majority inside the allow-exempted effects module; seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0. -- d2b-provider-guest-azure-container-apps#10 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub items carry no `# Errors` section naming their failure conditions (AcaController::reconcile and finalize, AzureContainerAppsRuntimeProvider::new, the validated constructors AcaProviderConfig::new/validate, AcaCpuMillis::new, AcaMemoryMib::new, the opaque_id parse) - fix: add `# Errors` sections listing the AcaTypeError/AcaControllerError conditions each returns - [src/controller.rs:257, src/controller.rs:308, src/controller.rs:924, src/effects.rs:61, src/effects.rs:106, src/effects.rs:128, src/effects.rs:410, src/effects.rs:450] - evidence: docs seed 3 (`-> Result<`) = 40 hits over src; seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 canonical sections anywhere in the crate. - -## perf -- clean: seeds `format!\(`=0, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=0, `\.to_string\(\)`=0 over src; no allocation sites in the reconcile path beyond the required owned-effect payloads, and the clone-heavy spots are cold (per-interval reconcile, admission boundary) - static (unmeasured). - -## conc -- N/A (seeds: `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=0, `Atomic\w+|Ordering::`=0, `thread_local!|unsafe impl (Send|Sync) for`=0 all zero; no threads, locks, atomics, or manual Send/Sync in src - the crate is single-task async). - -## async -- clean: seeds ran: 51 combined hits (async fn/async move/.await, async_trait effect ports); every provider call is wrapped in `timeout_at(deadline, ...)` with a deadline derived once from `deadline_remaining_ms` (controller.rs:676-677), no blocking work sits inside an async context, no guard is held across an await (no Mutex in src), no spawn/spawn_blocking exists, and shared state is limited to Arc effect ports with genuine multi-controller ownership (AzureContainerAppsRuntimeProvider::controller shares Arc/Arc across per-Guest controllers). - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=0; seed 4 alone - `#![forbid(unsafe_code)]` at src/lib.rs:4 plus the manifest's local `unsafe_code = "forbid"` - does not make the lens applicable per the card). - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0 all zero; the crate crosses no foreign boundary). - -## macro -- clean: seeds `macro_rules!`=1 (effects.rs:54), `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; the single `opaque_id!` macro is the genuine impl-per-type case (8 ID newtypes with identical parse/as_str/Deserialize/Debug shapes), uses narrow fragment specifiers (ident, expr), needs no `$crate` (it references only std macros and its own parameters), and is by-example, not procedural. - -## test -- d2b-provider-guest-azure-container-apps#11 sev=low blast=leaf effort=S verdict=actionable - stable_error_codes_are_bounded ends with a dead `let _ = ResourceRef::parse("Guest/gateway").unwrap();` that asserts nothing the test name claims and duplicates parse coverage exercised everywhere else - fix: delete the line (or fold the parse into an assertion the test actually promises) - [tests/provider_lifecycle.rs:536] - evidence: test seeds: `#\[test\]|#\[tokio::test\]`=14, `assert_eq!\(|assert_ne!\(|assert!\(`=28, `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0; the stray line is the only statement in the suite whose result is discarded. -- d2b-provider-guest-azure-container-apps#12 sev=medium blast=leaf effort=S verdict=actionable - the completed-operation ledger replay path (reconcile with a previously recorded operation id returns Converged without re-running effects, controller.rs:264-266) is contract behavior with no test - every test calls reconcile with a fresh operation id - fix: add a test that reconciles twice with the same id against a Running sandbox and asserts the second pass performs no effect calls (calls list unchanged) - [src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225] - evidence: test seeds: 14 tests, 0 reuse an operation id across reconcile calls (all ids are unique per test, including the loop in readiness_attempts_are_bounded which formats fresh ids); the ledger replay branch is therefore never exercised. - -## supply -- d2b-provider-guest-azure-container-apps#13 sev=low blast=leaf effort=S verdict=actionable - the `sha2` dependency is unused: the name appears nowhere in src/ or tests/ (only in Cargo.toml:21 and as the prose word "digests" in README.md:51) - fix: remove `sha2 = { workspace = true }` from the crate manifest (the workspace dep stays for its other consumers) - [Cargo.toml:21] - evidence: census: `sha2|Sha2|Sha256|digest` over packages/d2b-provider-guest-azure-container-apps/src + tests = 0 hits; the only manifest mention is Cargo.toml:21. - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: 6 finding(s) -- type: 1 finding(s) -- api: 1 finding(s) -- err: clean (seeds ran: 1/0/0/3) -- serde: clean (seeds ran: 31 combined) -- obs: clean (seeds ran: 0/0/0/15) -- docs: 2 finding(s) -- perf: clean (seeds ran: 0/0/0) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync in src) -- async: clean (seeds ran: 51 combined; all effect calls bounded by timeout_at deadlines, no blocking work, no guards across awaits, no spawn sites) -- unsafe: N/A (seeds: 0/0/0; seed 4 alone - `#![forbid(unsafe_code)]` at src/lib.rs:4 - does not make the lens applicable) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: clean (seeds ran: 1/0/0/0) -- test: 2 finding(s) -- supply: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md deleted file mode 100644 index 92c46840f..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-azure-virtual-machine.md +++ /dev/null @@ -1,97 +0,0 @@ -# d2b-provider-guest-azure-virtual-machine - d2b-provider-guest-azure-virtual-machine -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2839 (src 1882 + tests 957, excl. src/generated/**) | modules: whole crate (bootstrap.rs, config.rs, error.rs, lib.rs, controller/mod.rs, effect/mod.rs + tests/) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-guest-azure-virtual-machine#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default for BootstrapService` where a derive with a `#[default]` variant covers it - fix: add `#[derive(Default)]` with `#[default]` on `BootstrapServiceState::Waiting` (bootstrap.rs:124) and `#[derive(Default)]` on `BootstrapService`, delete the manual impl - [src/bootstrap.rs:138, src/bootstrap.rs:124] - evidence: seed 2 `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit (bootstrap.rs:138); seed 1 `for \w+ in 0\.\.` = 1 hit, seed 3 `let mut \w+ = (String|Vec)::new\(\)` = 0 -- clean: the single index loop (bootstrap.rs:28, `BootstrapPsk::matches`) is a deliberate constant-time comparison over max(len) with no early exit; an iterator chain would obscure the timing property; the hand-written `Debug` impls (BootstrapPsk, DataDiskSpec, AzureVmConfig, AzureVmGuestSettings, AzureVmStatus, AzureVmHandle, AzureOperationHandle, TagDigest) are deliberate secret redaction (derive would leak) - per-card false positive. - -## own -- d2b-provider-guest-azure-virtual-machine#2 sev=medium blast=leaf effort=S verdict=actionable - PSK secret copied twice in `start_psk_delivery`: `copy_for_delivery()` already returns an owned `Zeroizing>` and the extra `.to_vec()` produces a plain, non-zeroized `Vec` copy of the secret - fix: `PskExtensionPayload::from_secret(psk.copy_for_delivery().into_inner())` (or pass the `Zeroizing` value directly; zeroize 1.9 implements `From> for T`) - [src/controller/mod.rs:791, src/bootstrap.rs:42] - evidence: seed 1 `\.clone\(\)` + seed 2 `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 18 hits; site read in full -- d2b-provider-guest-azure-virtual-machine#3 sev=low blast=leaf effort=S verdict=actionable - `self.vm_handle.clone().ok_or)...)` clones the handle only to pass it by reference to an effect call - fix: `let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?;` and pass `handle` (no mutable borrow of `vm_handle` is live across the effect await) - [src/controller/mod.rs:640, src/controller/mod.rs:764] - evidence: seed 1 = 18 hits; both sites read with borrow analysis -- d2b-provider-guest-azure-virtual-machine#4 sev=low blast=leaf effort=S verdict=actionable - `self.pending_delete_operation_id.clone().ok_or)...)` clones a `String` only to borrow it for `start_vm_delete` - fix: `let operation_id = self.pending_delete_operation_id.as_deref().ok_or(AzureVmError::Ambiguous)?;` and pass `operation_id` - [src/controller/mod.rs:852] - evidence: seed 1 = 18 hits; site read -- d2b-provider-guest-azure-virtual-machine#5 sev=low blast=leaf effort=S verdict=actionable - `base32(&digest.finalize())[..20].to_owned()` allocates the full base32 string and then a second 20-char copy - fix: `let mut id = base32(&digest.finalize()); id.truncate(20); id` (or cap the length inside `base32`) - [src/controller/mod.rs:1046] - evidence: seed 2 `.to_owned()` = 1 hit (controller/mod.rs:1046); `base32` already pre-sizes with `String::with_capacity` (controller/mod.rs:1051) -- clean: the remaining clones are explainable - `recovery_state()` export clones (controller/mod.rs:260-265) build an owned sealed record from `&self`; `finalize`'s `get_or_insert_with)...).clone()` (controller/mod.rs:687) re-owns the id it may have just inserted; `verify_owned_vm` stores and returns the same handle (controller/mod.rs:959); `validate_update` clones `settings` (controller/mod.rs:986-997) to validate a prospective state without mutating `self`; `TagDigest::from_tags` copies the tag slice to sort it (effect/mod.rs:101); no `Rc`/`RefCell`/`Arc`/`Cow` in src (seeds 3-4 = 0). - -## type -- d2b-provider-guest-azure-virtual-machine#6 sev=medium blast=leaf effort=M verdict=actionable - `operation: Option` and `operation_started_at_unix_ms: Option` are always Some-together/None-together on the controller (controller/mod.rs:186-187) and in `AzureVmRecoveryState` (controller/mod.rs:110-118), and `restore_recovery_state` line 278 exists only to reject the illegal half-Some combination - fix: group into `Option` in both the controller and the recovery record, and delete the pair check at controller/mod.rs:278 - [src/controller/mod.rs:278, src/controller/mod.rs:186] - evidence: seed 1 `fn validate_\w+|fn check_\w+` = 1 hit (validate_update, controller/mod.rs:979); the Option-pair invariant read at set_operation/clear_operation (controller/mod.rs:963-970) and restore_recovery_state (controller/mod.rs:278) -- d2b-provider-guest-azure-virtual-machine#7 sev=medium blast=leaf effort=S verdict=actionable - `BootstrapAdmission { psk: Option, state: BootstrapAdmissionState }` (bootstrap.rs:65-68) can represent Consumed/Expired-with-`Some(psk)`; `consume()` manually forces `psk = None` on every transition - fix: `enum BootstrapAdmission { Pending { psk: BootstrapPsk, expires_at_unix_ms: u64 }, Consumed, Expired }` so the illegal combination is unconstructible (the skill's Option-pair smell) - [src/bootstrap.rs:65, src/bootstrap.rs:82] - evidence: seed 2 `is_\w+: bool|\w+_flag: bool` = 0, seed 3 `(mode|kind|state): String` = 0; struct and all transition sites read -- d2b-provider-guest-azure-virtual-machine#8 sev=low blast=leaf effort=S verdict=actionable - `AzureVmUpdate::Resize.size: String` is parse-validated at `validate_update` (controller/mod.rs:982) and parsed again at `apply_update` (controller/mod.rs:1008); `OpaqueAzureRef` is a validating, serde-transparent string wire type - fix: carry `size: OpaqueAzureRef` in the wire enum (JSON shape unchanged, a plain string) and drop both re-parses - [src/controller/mod.rs:82, src/controller/mod.rs:982] - evidence: seed 1 = 1 hit; `OpaqueAzureRef::parse` signature and validating `Deserialize` read at d2b-contracts/src/foundation_effects.rs:163,187 -- clean: `AzureVmRecoveryState.finalizer_installed` + `phase` invariant (finalizer false only when Finalized) is enforced once at the restore boundary (controller/mod.rs:286), which is the correct placement for a serialized record; no boolean flag soup or stringly-typed state found. - -## api -- d2b-provider-guest-azure-virtual-machine#9 sev=low blast=family effort=M verdict=actionable - the mutable-update/adoption/enrollment surface has no in-tree production caller: `update()`/`AzureVmUpdate`, `adopt()`, `complete_enrollment`, `status()`/`AzureVmStatus`, `controller_execution_ref()` are exercised only by this crate's tests, while the framework adapter (d2b-provider-guest/src/effects_service.rs) drives only `reconcile` (1303-1308), `poll_operation`/`recovery_state` (1384-1396), `finalize` (1384-1396) and `finalizer_installed` (590) - fix: wire the update path in the framework adapter (it already implements the resize/attach/detach/tags effect methods at effects_service.rs:499-565) or trim the surface - [src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748] - evidence: census: `AzureVmUpdate|complete_enrollment|controller\.adopt` over packages/ = this crate's definitions + its tests only (0 hits in d2b-provider-guest, d2bd, and all other crates) -- d2b-provider-guest-azure-virtual-machine#10 sev=low blast=leaf effort=S verdict=actionable - `AzureVmController::new` takes `effect: Arc` (controller/mod.rs:211) and stores it, but the only call site constructs a fresh `Arc::new(FrameworkAzureEffect {...})` with no sharing (d2b-provider-guest/src/effects_service.rs:1186-1189) - fix: take `effect: E` by value and store it, removing `Arc` from the public signature - [src/controller/mod.rs:211, packages/d2b-provider-guest/src/effects_service.rs:1186] - evidence: seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits (controller/mod.rs:211, 250, 183); call site read; `Arc` (with_clock) and `Arc` are the deliberate #G100 clock seam and the trait-object credential port, not flagged -- clean: seed 1 = 77 pub items, seed 3 = 8 `pub use` arms; lib.rs re-exports are the house single-surface pattern (sibling guest crates use the same `pub mod` + `pub use` shape); `AzureVmStatus` keeps private fields with accessors; `PskExtensionPayload::{len,is_empty}` are kept per refusal-ledger row #G77 (they are the inner field's only readers); `BootstrapPskDelivery` one-variant enum is a kept refusal (#G78, live construction at d2b-provider-guest/src/effects_service.rs:1892); `AzureVmConfig.tenant_id/client_id` are kept refusal #G83 (deny_unknown_fields wire fields). - -## err -- clean: skill audit `\.unwrap\(\)|\.expect\(` over src/ = 0 (all unwraps live in tests/); `let _ =`/`.ok();` = 0; `panic!|unreachable!|todo!|unimplemented!` = 0; seed 4 `enum \w*Error` = 1 hit (error.rs:7). `AzureVmError` is a closed 17-variant wire-code enum with stable `code()` strings and `Display` = code; 7 variants (ArmQuotaExceeded, ArmNetworkUnavailable, ArmCredentialDenied, ArmThrottled, CredentialUnavailable, Cancelled, DeadlineExpired) have no in-tree constructor - reserved vocabulary for the out-of-tree ARM adapter, not flagged; `Transient` is the retry signal the framework maps on. No panic-policy or taxonomy finding. - -## serde -- clean: seeds 1-4 = 21 hits; every wire type (`DiskSku`, `DataDiskSpec`, `BootstrapPskDelivery`, `AzureVmConfig`, `AzureVmGuestSettings`, `AzureVmUpdate`, `AzureVmRecoveryState`, `BootstrapServiceState`) uses `rename_all = "camelCase"` + `deny_unknown_fields`; `AzureVmHandle` is `serde(transparent)`; `AzureOperationHandle` has a hand-written base64 `Serialize`/`Deserialize` (deliberate opaque-bytes wire encoding with bounds re-checked in `from_core`); the three recovery-record bools carry `#[serde(default)]` (forward-compatible sealed records); secrets (`BootstrapPsk`, `PskExtensionPayload`, `AzureAccessToken`) never serialize; wire-value pinning and recovery round-trip tests exist (tests/lifecycle_hermetic.rs:251, 390). No finding. - -## obs -- d2b-provider-guest-azure-virtual-machine#11 sev=low blast=leaf effort=M verdict=actionable - the literal `provider = "runtime-azure-virtual-machine"` field is repeated on all 27 events and the `resource_group` field renders `OpaqueAzureRef()` via `Display` (d2b-contracts/src/foundation_effects.rs:181-184), so events that log only resource_group carry no correlation value - fix: add a `#[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))]` span on the controller entry points (reconcile, adopt, poll_operation, update, finalize) and drop the per-event literal; log zone/resource where available instead of the redacted resource_group - [src/controller/mod.rs:346, src/controller/mod.rs:425] - evidence: seed 4 `tracing::|log::` = 27 hits (bootstrap.rs 4, controller/mod.rs 23); every event read; seed 1 `println!|eprintln!` = 0, seed 2 interpolated-message-without-fields = 0, seed 3 `.instrument|#[instrument]` = 0 -- clean: all events use named fields (`zone`, `resource`, `state`, `code`, `attempts`, `stage`); no secret in any field; message-only events carry their context in fields; the ADR 0010/0028 redaction posture is respected (opaque refs pre-redacted at Display). - -## docs -- d2b-provider-guest-azure-virtual-machine#12 sev=medium blast=leaf effort=M verdict=actionable - Result-returning public methods carry no `# Errors` sections, so the framework caller cannot learn from docs which failures are transient/retryable vs fatal: `reconcile`, `adopt`, `poll_operation`, `update`, `finalize`, `complete_enrollment`, `restore_recovery_state` (controller/mod.rs:333-760), `BootstrapPsk::from_bytes`, `BootstrapAdmission::consume` (bootstrap.rs:15,82), `DataDiskSpec::validate`, `AzureVmConfig::validate`, `AzureVmGuestSettings::validate` (config.rs:49,103,177) - fix: add `# Errors` sections naming the `AzureVmError` variants each call returns, especially the `Transient` vs fatal split - [src/controller/mod.rs:333, src/controller/mod.rs:446] - evidence: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed 3 `-> Result<` = 27 hits; seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 77 hits -- d2b-provider-guest-azure-virtual-machine#13 sev=low blast=leaf effort=S verdict=actionable - `BootstrapPsk::matches` does not document the constant-time comparison guarantee that justifies its index loop over max(len) with zero-padding - fix: document "constant-time in the presented length; never exits early on mismatch" (the security contract of the loop shape) - [src/bootstrap.rs:25] - evidence: seed 1 = 77 hits; site read -- d2b-provider-guest-azure-virtual-machine#14 sev=low blast=leaf effort=S verdict=actionable - `BootstrapAdmission::consume` doc says "if the nonce is fresh" but there is no nonce; the parameter is the presented PSK bytes - fix: reword to "Consume the PSK when the presented bytes match and the deadline is valid" - [src/bootstrap.rs:82] - evidence: static read of the doc comment and the signature -- clean: `#![deny(missing_docs)]` (lib.rs:3) - every pub item has a one-line first sentence; all five modules carry `//!` docs; magic values are named (`AZURE_VM_REPAIR_INTERVAL_SECS`, `MAX_AZURE_TAGS`, `MAX_DATA_DISKS`, `MAX_LRO_AGE_MS`); no doctests exist (no `# Examples` anywhere - the crate's contract is the hermetic suite, acceptable). - -## perf -- clean: seeds `format!\(` / `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` / `\.to_string\(\)` = 0/0/0; `base32` pre-sizes with `String::with_capacity` (controller/mod.rs:1051); no hot-path allocation observed; no benchmark exists, so any perf claim would be static - none made. - -## conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` / `\bMutex<|\bRwLock<` / `Atomic\w+|Ordering::` / `thread_local!|unsafe impl (Send|Sync) for` = 0/0/0/0 in src/ (the only locks are `tokio::sync::Mutex` in tests/lifecycle_hermetic.rs, test-only synchronization); no threads, atomics, or manual Send/Sync claims exist. - -## async -- clean: seeds = 72/0/0/0 (async fns + awaits only; no `tokio::spawn`/`spawn_blocking`/`JoinSet`/`select!`/`join!` in src - the framework owns task spawning); no std lock held across an `.await` (`await_holding_lock` denied at the manifest, Cargo.toml `[lints.clippy]`); the only awaits are non-blocking `AzureEffectPort`/`AzureCredentialPort` calls; cancellation safety is structural - every state transition is re-observable via `get_vm_state` and the sealed `AzureVmRecoveryState`, so a future dropped at any await leaves a resumable state; `#[async_trait]` on both ports is justified by the `dyn AzureCredentialPort` usage; the double `arm_token()` acquisition in the Absent branch (controller/mod.rs:362,368) is deliberate token freshness across the observation await - not flagged. - -## unsafe -- N/A: seeds 1-3 (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` / `// SAFETY:` / `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; the single hit is seed 4 `unsafe_code` = `#![forbid(unsafe_code)]` (lib.rs:4), backed by `unsafe_code = "forbid"` in the manifest lints - a forbid attribute alone does not apply the lens per the card. - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` / `catch_unwind` / `repr\(C\)|repr\(transparent\)` / `CStr|CString|c_char` = 0/0/0/0; no FFI surface exists. - -## macro -- N/A: seeds `macro_rules!` / `proc_macro|syn::|quote!` / `\$crate` / `to_compile_error|new_spanned` = 0/0/0/0; no macros defined. - -## test -- d2b-provider-guest-azure-virtual-machine#15 sev=medium blast=leaf effort=M verdict=actionable - the config/PSK/handle validation contract has no rejection test: nothing constructs an invalid `AzureVmGuestSettings`/`DataDiskSpec`/`AzureVmConfig`/`BootstrapPsk`/`AzureVmHandle` and asserts `InvalidConfiguration`/`InvalidOperationHandle` (os_disk_size_gb outside 30..=4095, admin_user charset, LUN duplicates or >= 64, azure_tags > 50 or `d2b:` prefix, size_gb 0 or > 32767, label rules, empty or > 8192 PSK, handle chars), and `restore_recovery_state` rejection branches (controller/mod.rs:278-296) are untested - all tests restore valid records - fix: add a table-driven rejection test per `validate()` boundary and one invalid-record restore test - [src/config.rs:177, src/config.rs:49, src/controller/mod.rs:278] - evidence: seed 2 `assert_eq!\(|assert_ne!\(|assert!\(|matches!` = 106 hits across tests/; no test asserting `AzureVmError::InvalidConfiguration` or `InvalidOperationHandle` found in any of the 3 test files -- d2b-provider-guest-azure-virtual-machine#16 sev=low blast=leaf effort=S verdict=actionable - `every_controller_error_has_a_documented_stable_code` (tests/error_redaction.rs:17-38) asserts `!code().is_empty()` over a hand-enumerated variant list, but `code()` is a const fn whose exhaustive match makes an empty arm a compile error and the enumeration is not compiler-forced, so the test cannot meaningfully fail - fix: drop the loop and keep exact-code pinning (as `errors_and_handles_do_not_render_remote_values` already does for `arm-credential-denied`), or pin the full code table - [tests/error_redaction.rs:17] - evidence: seed 1 `#\[test\]|#\[tokio::test\]` = 25 tests (3 bootstrap_hermetic + 2 error_redaction + 20 lifecycle_hermetic); site read -- clean: the suite asserts error variants via `matches!`/`assert_eq` on enums, never `Display` strings; deterministic (injected `FixedClock`, no sleeps, no network, scripted LRO poll queues); redaction canaries present (tests/error_redaction.rs:6-13, tests/lifecycle_hermetic.rs:390-396 assert no secret material in Debug/serialized recovery output); wire-value pinning (tests/lifecycle_hermetic.rs:251-265); `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]` on the tokio tests is the sanctioned (d)4 reason; no `#[ignore]` tests; no proptest/insta/rstest (seed 3 = 0 - the scripted-fake form fits the state machine). - -## Coverage -- idiom: 1 finding | clean (seeds: 1/1/0; index loop checked, deliberate constant-time) -- own: 4 findings | clean (seeds: 18; remaining clones explainable) -- type: 3 findings | clean (seeds: 1/0/0) -- api: 2 findings | clean (seeds: 77/3/8; refusals #G77/#G78/#G83 honored) -- err: clean (seeds: 0/0/0/1; closed wire-code taxonomy, no panic sites in src) -- serde: clean (seeds: 21; consistent camelCase + deny_unknown_fields, opaque base64 handle, forward-compatible recovery defaults) -- obs: 1 finding | clean (seeds: 0/0/0/27; named fields everywhere, no secrets) -- docs: 3 findings | clean (seeds: 77/0/27; deny(missing_docs) satisfied) -- perf: clean (seeds: 0/0/0) -- conc: N/A (seeds: 0/0/0/0 in src; only test-only tokio::sync::Mutex) -- async: clean (seeds: 72/0/0/0; no spawn/blocking/guard-across-await; resumable state machine) -- unsafe: N/A (seeds: 0/0/0/1; forbid attribute only) -- ffi: N/A (seeds: 0/0/0/0) -- macro: N/A (seeds: 0/0/0/0) -- test: 2 findings | clean (seeds: 25/106/0/0; deterministic, variant-matched, redaction canaries) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md deleted file mode 100644 index d63354546..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-cloud-hypervisor.md +++ /dev/null @@ -1,91 +0,0 @@ -# d2b-provider-guest-cloud-hypervisor - d2b-provider-guest-cloud-hypervisor -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10440 (excl. src/generated/**) | modules: adoption, bootstrap_graph, config, controller, controller_session, descriptor, guest_local, health, identity, lib, shutdown, state -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-guest-cloud-hypervisor#6 sev=low blast=leaf effort=S verdict=actionable - `CloudHypervisorController` stores `_config` (controller.rs:1712) that is never read; only `config.validate()` at 1739 uses the value - fix: drop the `_config` field and its initializer, keeping the validate() call in `from_verified_descriptor` - [controller.rs:1712, controller.rs:1744] - evidence: census `_config` over packages/ = 2 hits (field declaration + initializer), zero reads -- d2b-provider-guest-cloud-hypervisor#7 sev=low blast=leaf effort=S verdict=actionable - `observed_process_status` is controller state used only inside one `reconcile` invocation (reset at 1860, set at 2013/2016, read at 2042), a field masquerading as a local - fix: make it a local variable in `reconcile` and delete the struct field - [controller.rs:1722, controller.rs:1860, controller.rs:2042] - evidence: census `observed_process_status` over the crate = 5 hits, all inside one reconcile() body -- d2b-provider-guest-cloud-hypervisor#8 sev=low blast=leaf effort=S verdict=actionable - `deletion_rank` (shutdown.rs:487) and `upgrade_rank` (shutdown.rs:666) are byte-identical match arms duplicated across two free functions - fix: one `ChildRole::rank()` method (or single free fn) used by both planners - [shutdown.rs:487-494, shutdown.rs:666-673] - evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 0 hits; the two fn bodies are identical by static comparison -- d2b-provider-guest-cloud-hypervisor#9 sev=low blast=leaf effort=S verdict=actionable - `BootstrapGraph::readiness()` (bootstrap_graph.rs:131) hardcodes `bindings_ready`/`setup_ready` to true while the `bindings` field doc says fenced binding readiness gates VMM start; only tests call it - fix: delete the wrapper and update the test (bootstrap_graph.rs:417) to call `vmm_readiness` with explicit booleans - [bootstrap_graph.rs:131-139, bootstrap_graph.rs:417-422] - evidence: census `\.readiness\(|vmm_readiness|vmm_lifecycle` over packages/ = production call at controller.rs:662 uses vmm_lifecycle with real values, all other calls are in bootstrap_graph.rs tests -- d2b-provider-guest-cloud-hypervisor#13 sev=low blast=leaf effort=S verdict=actionable - `GuestControlEndpoint::uid()` and `endpoint_uid()` (guest_local.rs:113-121) are identical accessors with identical doc text, and `endpoint_uid()` has no caller in this crate - fix: keep one accessor and drop the other (mirror the choice in the sibling copy under finding #14) - [guest_local.rs:113-121] - evidence: census `endpoint_uid` over packages/ = 2 hits (this definition and the sibling copy's own test in d2b-resource-client/src/zone_client.rs:1067) - -## own -- clean: seeds ran `\.clone\(\)` = 127, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 31, `Rc<|RefCell<|Arc` whose only call site passes an always-empty map (`let committed = BTreeMap::new()` at controller.rs:2140), making the `committed.get(target)` branch at 2890 unreachable - fix: drop the parameter and the dead branch, delete the empty-map local - [controller.rs:2140, controller.rs:2148-2151, controller.rs:2876-2895] - evidence: census `repair_children` over packages/,nixos-modules/,tests/,docs/reference/,labs/ = 2 hits (definition + the single call site with the empty map) -- d2b-provider-guest-cloud-hypervisor#2 sev=medium blast=leaf effort=S verdict=actionable - `CloudHypervisorResourceApi::assess_update` takes `children` that the production adapter discards (`let _ = children;` at controller.rs:1366, the request carries no children) while `reconcile` allocates a Vec just to drop it - fix: remove the `children` parameter from the trait method, the adapter override, and the call site (controller.rs:1907-1909) - [controller.rs:1361-1376, controller.rs:1907-1909] - evidence: err seed 2 (`let _ = |\.ok\(\);`) hit at controller.rs:1366; census of `assess_update` call sites = 1 production call plus test fakes -- d2b-provider-guest-cloud-hypervisor#3 sev=low blast=leaf effort=S verdict=actionable - `ChildMutation::expected_uid()` (identity.rs:554) always returns `None` because the UID-free batch is structurally UID-free; the only consumers are tests asserting the None (bootstrap_graph.rs:340, tests/controller.rs:206, tests/guest_spec_validation_test.rs:181) - fix: delete the accessor and the assert-None assertions - [identity.rs:554-556, tests/controller.rs:206] - evidence: census `expected_uid\(\)` over packages/ = 8 hits; the 4 ChildMutation hits are all assert-None, the rest are `ChildSpecUpdate::expected_uid` in d2bd (a different type with a real value) -- d2b-provider-guest-cloud-hypervisor#4 sev=low blast=leaf effort=S verdict=actionable - `GuestUpgradePlan::preserve_state()` (shutdown.rs:576) returns a literal `true`; its only consumer is the tautological assertion in finding #5 - fix: delete the accessor together with the assertion - [shutdown.rs:576-578] - evidence: census `preserve_state\(\)` over packages/ = 1 hit (the test assertion at finalize_ordering_test.rs:286) -- d2b-provider-guest-cloud-hypervisor#14 sev=medium blast=family effort=M verdict=actionable - `GuestControlEndpoint` is declared byte-identically in this crate (guest_local.rs:49) and in d2b-resource-client (zone_client.rs:129), the not-applied ledger row C1 with no refusal reason - fix: keep one declaration (d2b-resource-client is the consumer-facing home; d2bd/src/composition.rs:10723 constructs it) and re-export from the other - [guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256] - evidence: census `GuestControlEndpoint` over packages/ = 2 struct declarations plus consumers; ledger row C1 at docs/explanation/over-engineering-audit-record.md:472 (not applied, no refusal); both sites confirmed byte-identical at this baseline - -## err -- clean: seeds ran `\.unwrap\(\)|\.expect\(` = 108, `let _ = |\.ok\(\);` = 2, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 1, `enum \w*Error` = 10; every unwrap/expect hit is inside `#[cfg(test)]` modules or the sanctioned "fixed ..." class (`role.purpose().expect("fixed Endpoint purpose")` identity.rs:610, `expect("fixed child plan role")` controller.rs:2949, `expect("fixed owner limits")` controller.rs:2869), the two `let _ =` sites are the dropped `assess_update` parameter (finding #2) and a test abort-await, and the error taxonomy (CloudHypervisorError wrapping Descriptor/ResourceApi/LifecyclePlan via From) needs no string matching by callers. - -## serde -- clean: seeds ran `derive\([^)]*(De)?[Ss]erialize|serde\(...` = 51, `impl .*Deserialize.*for|serde_json::from_|serde_json::to_` = 6; the hand-written `Deserialize` impls (descriptor.rs, identity.rs) are live admission gates for the signed setup descriptor and child bodies, the recorded-refusal class (over-engineering-audit-record.md, refused Deserialize gates) so not re-flagged; `deny_unknown_fields` is applied on config, status, and every Wire admission struct, and the enum representations (internal tag on ChildCreateBody, transparent on OpaqueDescriptorSignature/ChildRoleSet) are deliberate wire pins covered by guest_spec_validation_test.rs. - -## obs -- clean: seeds ran `\bprintln!\(|\beprintln!\(|(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument|tracing::|log::` = 53; every tracing event uses named fields (zone/resource/error/stage), errors are logged once at the boundary that handles them via `inspect_err`, no secrets reach fields (identity-bearing Debug impls redact), and no subscriber is installed by the library. - -## docs -- d2b-provider-guest-cloud-hypervisor#15 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors`/`# Examples` sections exist anywhere in the crate (seed 2 = 0) although 114 pub items return `Result<`; e.g. `GuestSetupDescriptor::from_canonical_bytes` (descriptor.rs:423) and `GuestChildBatch::from_descriptor` (identity.rs:590) document neither failure conditions nor a usage example - fix: add `# Errors` sections to the wire-boundary constructors first (descriptor.rs, identity.rs, health.rs), then the remaining Result-returning pub items - [descriptor.rs:423-429, identity.rs:590-634] - evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 339, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 114; the crate denies missing_docs (lib.rs:3) so every item has a first sentence, but failure contracts are absent - -## perf -- d2b-provider-guest-cloud-hypervisor#16 sev=low blast=leaf effort=S verdict=actionable - `child_role_for_ref` (shutdown.rs:505) builds `format!("-{}", role.suffix())` inside the per-role loop, four String allocations per call on the per-child planning path (`plan_upgrade` at controller.rs:2340, `project_status` at controller.rs:2940) - fix: use `name.rsplit_once('-')` and compare the suffix, or a static suffix table - [shutdown.rs:505-513] - evidence: perf seed 1 `format!\(` = 6 hits, this is the only non-test production hit; static (unmeasured) - -## conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0 (one doc-comment word "atomically" is a false positive), `thread_local!|unsafe impl (Send|Sync) for` = 0; the crate declares no threads, locks, atomics, or manual Send/Sync. - -## async -- clean: seeds ran `async fn|async move|\.await` = 125, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(|tokio::sync::(Mutex|RwLock|Notify)|#\[tokio::(main|test)\]|Runtime::block_on` = 2, `tokio::sync::(Mutex|RwLock|Notify)` = 0; the fd10 bootstrap handshake and assignment-stream loop in controller_session.rs are the refused row 7 (over-engineering-audit-record.md:125, G7) so not re-flagged; `Runtime::block_on` at the process entry is the sanctioned CLI-only path with `#[allow(clippy::disallowed_methods, reason = "CLI-only path")]` (controller_session.rs:58), tokio::spawn appears only in tests, no guard is held across `.await` in src, and no blocking call sits inside an async fn. - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; the single `unsafe_code` hit is `#![forbid(unsafe_code)]` at lib.rs:4, which alone does not make the lens applicable. - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign boundary. - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the crate defines no macros. - -## test -- d2b-provider-guest-cloud-hypervisor#5 sev=medium blast=leaf effort=S verdict=actionable - `assert!(plan.preserve_state())` (finalize_ordering_test.rs:286) cannot fail because `preserve_state()` returns a literal `true` (shutdown.rs:577), an assertion of implementation rather than behavior - fix: delete the assertion together with the accessor (finding #4) - [finalize_ordering_test.rs:286] - evidence: test seeds: `#\[test\]|#\[tokio::test\]` = 52, `assert_eq!\(|assert_ne!\(|assert!\(` = 221, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the asserted accessor body is a constant - -## Coverage -- idiom: 5 findings -- own: clean (seeds ran: 127/31/0) -- type: 3 findings -- api: 5 findings -- err: clean (seeds ran: 108/2/1/10; all hits tests or sanctioned "fixed" expects) -- serde: clean (seeds ran: 51/6; admission-gate Deserialize impls are recorded-refusal class) -- obs: clean (seeds ran: 0/53) -- docs: 1 finding -- perf: 1 finding -- conc: N/A (seeds: 0/0/0/0; no threads, locks, atomics, or TLS) -- async: clean (seeds ran: 125/2/0/0; G7-refused handshake not re-flagged) -- unsafe: N/A (seeds: 0/0/0/1; only the forbid(unsafe_code) attribute) -- ffi: N/A (seeds: 0/0/0/0) -- macro: N/A (seeds: 0/0/0/0) -- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md deleted file mode 100644 index 4e6990948..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest-qemu-media.md +++ /dev/null @@ -1,88 +0,0 @@ -# d2b-provider-guest-qemu-media - d2b-provider-guest-qemu-media -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3,632 (src 2,688 + tests 944 (excl. src/generated (none) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) - -## idiom -- d2b-provider-guest-qemu-media#1 sev=low blast=leaf effort=S verdict=actionable - The `impl Default` bodies re-spell the serde `default_*` helper values in a second place (`"qemu-system-x86-64".to_owned()` at packages/d2b-provider-guest-qemu-media/src/config.rs:93 vs `default_qemu_artifact()` at 272; the whole GuestProviderSpecSettings default body at packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182-196 vs the serde default fns at ~440-447); two spellings of one default drift independently - fix: have the Default impls call the serde default fns (`qemu_binary_artifact_id: default_qemu_artifact()`, `vcpu: default_vcpu()`, `boot_media_view: default_boot_media_view()`( ( - [packages/d2b-provider-guest-qemu-media/src/config.rs:93, packages/d2b-provider-guest-qemu-media/src/config.rs:272, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:182, packages/d2b-provider-guest-qemu-media/src/types/guest.rs:440] - evidence: seed2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`= 4 hits;(2 of the 4 hand-written Default impls duplicate the deserialization defaults (the other 2 are deliberate non-derivable (reconcile.rs:146 display_ready=true (qmp/mod.rs:164 delegates to `new()`. -- clean: seeds ran: 0/4/1;0 index loops;(4 hand-written Default impls (2 flagged as #1;(1 `let mut ... = Vec::new()` accumulation (flagged as perf#1; nothing else found. - -## own -- d2b-provider-guest-qemu-media#2 sev=low blast=leaf effort=S verdict=actionable - `QmpSession::execute` clones every dispatched QmpCommand into the bounded history before executing (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266); per-field borrow splitting makes the clone avoidable: push the owned command into `commands` and execute from `commands.back()` (`let Self { transport, commands, .. } = self;` then `commands.push_back(command); transport.execute(commands.back().expect("just pushed"))`(removes 1-4 String copies per QMP command - fix: destructure the two fields and reorder push/execute (drop `command.clone()` - [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:266] - evidence: seed1 (`.clone()`= 9 hits;(8 of the 9 clones are required ownership moves (projections at config.rs:157, ticket slots at process_builder.rs:244,255, recovery state at reconcile.rs:297, launch-ticket process at 447-448, expected-identity persistence at 495, feature dedup at types/guest.rs:228 (this history-copy is the only avoidable one (the skill's borrow-splitting pattern. - - - -- clean: seeds ran: 9/30/0/0;(the 30 to_owned/to_vec/to_string sites are wire-string construction and owned conversions for wire fields (fine;(no Rc/RefCell/Arc/Cow. - - - -## type -- d2b-provider-guest-qemu-media#3 sev=medium blast=leaf effort=M verdict=actionable - `validate_token` (packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417(re-implements exactly the bounds of the in-tree `BoundedToken::parse` (`^[a-z][a-z0-9-]*$`, up to 63 bytes (at packages/d2b-contracts-resource/src/v3/execution_policy.rs:187-191); a second, slightly looser copy lives in `validate_object_id` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:274) - fix: replace the 7 gate calls (config.rs:142, hotplug.rs:62, process_builder.rs:288, volume.rs:121,165, guest.rs:115,213(with `BoundedToken::parse)...).is_ok()` (route qmp's variant through a first-char check plus the helper), delete the local helper - [packages/d2b-provider-guest-qemu-media/src/types/guest.rs:417, packages/d2b-contracts-resource/src/v3/execution_policy.rs:187, packages/d2b-provider-guest-qemu-media/src/config.rs:142] - evidence: seed1 (`fn validate_\w+|fn check_\w+`= 3 hits;(validate_token definition + 7 call sites =8 matches over src/; exact bound match with the BoundedToken doc (execution_policy.rs:190-191. -- d2b-provider-guest-qemu-media#4 sev=medium blast=leaf effort=S verdict=actionable - Public `impl Default for ProviderConfig` manufactures an invalid config (`controller_execution_ref: ResourceRef::parse("Guest/invalid").expect)...)` at packages/d2b-provider-guest-qemu-media/src/config.rs:92), which fails its own `validate()` ); its only consumer is a test asserting that invalidity - fix: delete the Default impl (and rewrite the test to build valid-then-mutated configs as its sibling test at tests/config_schema_projection.rs:27 already does), or replace with a `#[doc(hidden)]` `for_test()`-style constructor - [packages/d2b-provider-guest-qemu-media/src/config.rs:89, packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs:5] - evidence: census: `ProviderConfig::default` over packages/,nixos-modules/,tests/,docs/reference/,labs/=1 hit (src: 0 (tests: 1 (packages/d2b-provider-guest-qemu-media/tests/config_schema_projection.rs:5);(seed2 (`impl Default for`= 4 hits;(this is the sole Default violating its own validate). -- clean: seeds ran: 3/0/2;2 stringly-typed state String fields (volume.rs:31,75 (are mirror images of the v3 Volume wire-contract String fields (false positive (not flags (no boolean-flag soup (otherwise clean. - -## api -- d2b-provider-guest-qemu-media#5 sev=low blast=leaf effort=S verdict=actionable - Test-support exports `ScriptedQmpTransport` (packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129(and `ProcessIdentity::for_test` (packages/d2b-provider-guest-qemu-media/src/adoption.rs:24(are unconditionally pub+re-exported with no consumer outside this crate's own tests (while the house convention for test-only items is `#[doc(hidden)]` (see `mark_ready_for_test` at packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:327-328( - fix: mark both `#[doc(hidden)]` (or gate behind a `test-support` feature - [packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:129, packages/d2b-provider-guest-qemu-media/src/lib.rs:32, packages/d2b-provider-guest-qemu-media/src/adoption.rs:24] - evidence: census: `ScriptedQmpTransport` over packages/,nixos-modules/,tests/,docs/reference/,labs/,BUILD.bazel/=3 hits (`src/qmp/mod.rs:129` def + `src/lib.rs:32` re-export + `tests/qmp_protocol.rs:2`); `for_test` over the same roots = 6 hits (1 definition + 5 test uses (no external crate references either. -- clean: seeds ran: 127/0/15;(the 15 `pub use` arms in lib.rs are the house single-surface re-export pattern (false positive;(no Arc/Rc/Box/RefCell in public signatures;(nothing else found. - -## err -- clean: seeds ran: 5/1/0/9;5 unwrap/expect (4 on parsed literal constants inside Default/new (config.rs:92,99,101, volume.rs:99 (exempt (1 in #[cfg(test] (hotplug.rs:96 (exempt ( (1 swallowed Result (qmp/mod.rs:238 (deliberate best-effort rollback (logged at 233 (original error propagates ( (0 panic-family macros;(9 error enums all carry stable `code()` Display strings (closed taxonomy split by caller action (fine. - -## serde -- clean: seeds ran: 18/38/0/4; all 38 serde attr sites obey rename_all + deny_unknown_fields + default/skip_serializing_if conventions (the 3 hand-written Deserialize impls (config.rs:45, guest.rs:122,238 (are the recorded live admission gates (refused class per docs/explanation/over-engineering-audit-record.md (do not re-flag ( (the boundary is covered by real-payload and round-trip tests (tests/config_schema_projection.rs:43, tests/guest_schema_roundtrip.rs:5 (fine. - -## obs -- d2b-provider-guest-qemu-media#6 sev=low blast=leaf effort=M verdict=actionable - All 21 tracing events repeat the same two context fields (`resource = %self.guest_ref`, `provider = "runtime-qemu-media"`(inline ( ~20 sites in reconcile.rs + qmp/mod.rs:233); a span per reconcile/finalize would carry them once - fix: `#[tracing::instrument(skip(self, effect))]` on `QemuMediaController::reconcile`/`finalize` (or an explicit enter/exit span (dropping the duplicated pairs from the per-event fields - [packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:352, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:380, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:605, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:233] - evidence: seed2 (`(info|debug|warn|error|trace)!\(`= 21 hits;(all use named fields but the resource/provider pair is repeated at every event;(seed3 (`\.instrument\(|#\[instrument`= 0 spans (none to inherit them. -- clean: seeds ran: 0/21/0/21;0 println!/eprintln! in src (library isolates from stdout;(the gated fixture test prints SKIP to stderr (test-only (fine;(all 21 events carry named fields (no interpolated message-only events (no spans (finding #6 ( (21 `tracing::` sites (same set. - -## docs -- d2b-provider-guest-qemu-media#7 sev=medium blast=leaf effort=M verdict=actionable - None of the 41 `-> Result<` items carry a `# Errors` section (seed2 =0 ( (e.g. `DeviceAdmission::validate` has 6 failure kinds (device_watch.rs:82-90), `QemuMediaController::reconcile` 8 (reconcile.rs:338), `LaunchTicket::new` 3 (process_builder.rs:221) ), `QmpSession::negotiate` 3 (qmp/mod.rs:199) (leaving the caller to read the enum to map conditions - fix: add `# Errors` sections naming which conditions produce which variants on the non-obvious pub Result APIs - [packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs:82, packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs:338, packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:221, packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs:199] - evidence: seed3 (`-> Result<`= 41 hits; seed2 (`/// # (Examples|Errors|Panics|Safety)`= 0 (no canonical sections anywhere. -- clean: seeds ran: 115/0/41;`#![deny(missing_docs)]` (lib.rs:3(keeps all 115 pub items documented (the 41 Result-returning items are the # Errors gap (finding #7 ( (module docs present at every module head (fine. - -## perf -- d2b-provider-guest-qemu-media#8 sev=low blast=leaf effort=S verdict=actionable - `LaunchTicket::new` grows `attachments` by push from a fresh `Vec::new()` with an a-priori known upper bound (up to media_refs.len()+3 slots (packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239-274) - fix: `Vec::with_capacity(media_refs.len() + 3)` ( (static (unmeasured. - [packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239] - evidence: seed2 (`Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`= 10 hits;(this is the only grow-by-push site with an a priori bound (the rest are legit empty-case defaults (static (unmeasured. -- clean: seeds ran: 5/10/0;5 format! sites all one-shot cold paths (scaffold/id construction, short-key hex rendering (fine;(0 to_string copies in src (nothing else found. - -## conc -- clean: N/A (seeds: 0/0/0/0 all zero; no threads, mutexes/rwlocks, atomics/orderings, or thread_locals in src (and no tokio::sync re-exports (lens inapplicable. - -## async -- clean: N/A (seeds: 0/0/0/0 all zero; no async fn, .await, tokio::spawn/select/join, tokio::sync types, or block_on in src (this Provider's effect and QMP seams are deliberately synchronous (lens inapplicable. - -## unsafe -- clean: N/A (seeds 1-3: 0/0/0 all zero; seed4 (`unsafe_code`= 2 (manifest `forbid` (Cargo.toml:9 (and crate-level `#![forbid(unsafe_code)]` (lib.rs:4) (per U1 card seed4 alone does not make the lens applicable (no unsafe sites. - -## ffi -- clean: N/A (seeds: 0/0/0/0 all zero; no extern "C"/no_mangle, catch_unwind, repr(C/transparent, or C string types in src (the crate has no FFI surface. - -## macro -- clean: N/A (seeds: 0/0/0/0 all zero; no macro_rules!/proc-macro/syn/quote machinery in src (lens inapplicable. - -## test -- d2b-provider-guest-qemu-media#9 sev=low blast=leaf effort=S verdict=actionable - tests/lifecycle.rs repeats the same 8-field `DeviceObservation` literal ~8 times (e.g. 132-140,154-163,220-228,292-300,377-385( (each test then mutates a field or two (the fixture setup dominates the test bodies - fix: extract `fn device() -> DeviceObservation` helper (as `fn controller()` at tests/lifecycle.rs:104 already factors the bigger fixture (or build from a small builder - [packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:154, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:220, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:292, packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:377] - evidence: seed1 (`#\[test\]`= 33 hits over src+tests (the 8-field literal recurs at ~8 test sites in tests/lifecycle.rs (same file already uses `fn controller()` to factor the bigger fixture (so the pattern exists. -- clean: seeds ran: 33/96/0/0 over src+tests;33 #[test] (all behavioral (effect-order events, real-payload round-trips, stable error codes( (the 96 assertions use human-written expected values (no assertion restates the implementation ( (no property/snapshot tooling (closed bound tables suffice (0 #[ignore] (the gated fixture scan (tests/fixture_projection.rs:19-22(prints SKIP when D2B_FIXTURES unset (documented gate (not an ignore. - -## Coverage -- idiom: 1 finding(s) -- own: 1 finding(s) -- type: 2 finding(s -- api: 1 finding(s -- err: clean (seeds ran: 5/1/0/9) -- serde: clean (seeds ran: 18/38/0/4) -- obs: 1 finding(s -- docs:1 finding(s -- perf:1 finding(s -- conc: N/A (seeds: 0/0/0/0 all zero; no concurrency usage) -- async: N/A (seeds: 0/0/0/0 all zero; no async code) -- unsafe: N/A (seeds 1-3: 0/0/0 all zero; seed4 = forbid manifest/lint settings only) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test:1 finding(s \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md deleted file mode 100644 index 1ab7d549c..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-guest.md +++ /dev/null @@ -1,93 +0,0 @@ -# d2b-provider-guest - d2b-provider-guest -Baseline: 6ebdd4cec | LOC audited: 6,423 (src 6,192 + tests 231; excl. src/generated/**: none present) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- clean: seeds: idiom1=2 (both in test loops, effects_service.rs:1916,1926), idiom2=1 (shutdown.rs hand-written Default preserving ch_api::DEFAULT_TIMEOUT - the U1 false-positive class: a field-wise derive would not preserve the invariant), idiom3=3 (justified accumulators: recursive walk (driver.rs:1348), sequential-await filter (effects_service.rs:1000), conditional push+extend (effects_service.rs:1035);; checked expression shape across src/**: no production index loops, no hand-written replaceable derives, no statement-style accumulation the skill names a pipeline for. - -## own -- d2b-provider-guest#4 sev=low blast=leaf effort=S verdict=actionable - Retiring obsolete children sorts by teardown rank plus row name by cloning every row's name String into the sort-key tuple - fix: sort with a comparator borrowing the name (`sort_by(|a,b| teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name).then_with(|| a.key.name.cmp(&b.key.name)))`), dropping the per-row allocation - [packages/d2b-provider-guest/src/driver.rs:981] - evidence: seed `\.clone\(\)` = 91 hits src; driver.rs:981 is the only clone whose purpose is the owned-key bound of sort_by_key; the name String is otherwise borrowed throughout -- d2b-provider-guest#5 sev=low blast=leaf effort=S verdict=actionable - The ACA framework controllers clone each stored candidate list before collect (`state.sandbox.clone().into_iter().collect()`), allocating an intermediate Vec per candidate read - fix: `state.sandbox.iter().cloned().collect()` (same element copies, one fewer allocation - [packages/d2b-provider-guest/src/effects_service.rs:243, packages/d2b-provider-guest/src/effects_service.rs:256] - evidence: seed `\.clone\(\)` = 91 hits src; both sites clone an Option held behind tokio::sync::Mutex only to iterate it into the candidate-set newtype -- clean: remaining clones (69 further hits incl. .to_owned/.to_vec/.to_string) are ownership copies into typed request structs and dyn ports (GuestEffectRequest field copies, Arc::clone at effects-service/factory boundaries), status.resource clones into the R11 status sink/projection;, and fixture seeds - each explainable in one sentence; no Rc fields (facets.rs:59,65,and GuestTargetEffects Arc map (target_service.rs:91)are declared shared-ownership values the daemon composition root supplies (documented, not caller-derived;; test-support feature-gated doubles are the recorded test-consumed surface;; the dependency types (ResourceRef, ResourceKey, GuestTargetError etc) in signatures are in-tree workspace contract crates (publish=false paths,,not published semver surfaces. - -. - -## err -- clean: seeds 128/3/1/3; production unwrap/expect sites are 3 invariant-naming expects (driver.rs:788 "driver zone was validated at construction", driver.rs:1304 "manager keys carry canonical resource references", driver.rs:1361 "child metadata renders"), all on compiler-invisible invariants, and the remaining 125 hits live in #[cfg(test)];; the let _ sites are a ?-propagating kind-classification call (driver.rs:1041, an deliberately unused request param (effects_service.rs:941,and a test-scope drop (effects_service.rs:1934 - none swallow a Result a caller must see;; the single panic!/unreachable! is a test-only match arm (effects_service.rs:1838;; error enums are closed, context-carrying variants with static code() labels used in logs only, no wire error-code surface touched. - -. - -## serde -- clean: seeds 2/13/0/40; GuestSpec's wire gate uses rename_all camelCase, deny_unknown_fields on the Wire admission struct, flatten+skip_serializing_if+default(fns)) for the three optionality meanings, and serde_json boundary sites map errors to closed kinds; the hand-written Deserialize at guest_spec.rs:81 is the recorded live admission-gate class (over-engineering-audit-refusal, not reflagged;; the canonical-bytes test pins the exact wire shape and a hand-written JsonSchema derive covers the schema surface. - - - -## obs -- clean: seeds 0/0/0/13; all 13 tracing sites are structured events with named fields ((code=, source=, plane=?, detail=, guest=, dependency=, reason=, error=, field=, resource=; no println!/eprintln! in src (CLI product output lives elsewhere);; no secrets enter fields (tokens ride redacted types or as bounded labels;; no #[instrument] spans needed for these short per-pass contexts;; the status-sink lock sites carry recorded async-gate-allow marks (not reflagged). - -## docs -- d2b-provider-guest#7 sev=low blast=leaf effort=M verdict=actionable - No public Result-returning item carries a canonical `# Errors` doc section (docs2 seed = 0 hits src), despite #![deny(missing_docs)]]and ~107 Result-returning pub items - fix: add `# Errors` headings naming the refusal conditions on the trait/fn contracts ((facets.rs:63, target_control.rs:95, driver.rs:403, target_service.rs:68 etc.) - [packages/d2b-provider-guest/src/facets.rs:63, packages/d2b-provider-guest/src/target_control.rs:95, packages/d2b-provider-guest/src/driver.rs:403, packages/d2b-provider-guest/src/target_service.rs:68] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits src; seed `-> Result<` = 107 hits src - every Result-returning pub item is undocumented for its error contract under the rust-docs canonical-section rule -- clean: #![deny(missing_docs)] ((lib.rs:17) makes every public item carry a doc comment, and first sentences are contract-shaped across the sampled surface;; no doctests area present to rot;; magic values ((TARGET_CONTROL_TIMEOUT, GUEST_RESYNC, DEFAULT_TIMEOUT(are documented with their why. - -. - -## perf -- d2b-provider-guest#6 sev=low blast=leaf effort=S verdict=actionable - Two hex-ID builders format a fresh String per byte ((driver.rs:863-868 map(|byte| format!("{byte:02x}")) into a String, effects_service.rs:983-988 push_str(&format!)...)) in a loop), allocating ~16 and ~8 Strings per reconcile pass - fix: write! to one with_capacity String per builder (or a crate-local hex helper reusing the buffer - [packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:868, packages/d2b-provider-guest/src/effects_service.rs:983, packages/d2b-provider-guest/src/effects_service.rs:988] - evidence: static (unmeasured); seed `format!\(` = 30 hits src; the remaining format! sites are error-path/one-shot spec-name Strings ((U1 false-positive class); -- clean: seeds 30/19/5; Vec::new() sites are empty-case-common field inits ((driver.rs:791,952)or push/filter accumulators with sequential awaits/no known capacity ((effects_service.rs:630,1000,1035;; to_string() sites are error-detail conversions into failure details ((effects_service.rs:664,676,908,1000;; no hot-path collections, attacker-controlled hashing, or unbounded scans identified in production code. - - - -## conc -- d2b-provider-guest#2 sev=medium blast=family effort=M verdict=policy-confirmed - GuestStatusSink ((a pub type re-exported at lib.rs:42)is Arc>>, injecting the banned parking_lot lock type into this crate's and d2bd's public signatures; the production write sites carry recorded "synchronous path"/async-gate allows,,but every future sink caller inherits the banned type - fix: replace with Arc>>and convert the write sites to .lock().await per the replacement vocabulary - [packages/d2b-provider-guest/src/driver.rs:502, packages/d2b-provider-guest/Cargo.toml:29, packages/d2b-provider-guest/src/effects_service.rs:1443] - evidence: seed `\bMutex<|\bRwLock<` = 23 hits src (production tokio::sync::Mutex uses at driver.rs:449,effects_service.rs:181,400,618 are the sanctioned async vocabulary; policy: clippy.toml:40-43 bans parking_lot outright (KD3; U33 carve-out revoked)and clippy.toml:82-84 names tokio::sync::Mutex::lock as the replacement;; the per-site "synchronous path" allows at the daemon write sites are the U1 (d)4 recorded-exception list, not the public type -- d2b-provider-guest#3 sev=medium blast=leaf effort=M verdict=policy-confirmed - The test-support recorder doubles and the driver test harnesses hold recorder/queue state in parking_lot::Mutex fields, which the ban covers for tests too (KD4 uniform rule,,and no per-site clippy allow exists at these sites - fix: convert to tokio::sync::Mutex with async accessors (or the documented blocking-seat helpers for worker-thread-only callers),,keeping the recorded async-gate-allow marks until converted - [packages/d2b-provider-guest/src/test_support.rs:59, packages/d2b-provider-guest/src/test_support.rs:171, packages/d2b-provider-guest/src/driver.rs:1534, packages/d2b-provider-guest/src/driver.rs:1761] - evidence: seed `\bMutex<|\bRwLock<` = 23 hits src (the four harness members above carry the banned type; policy: clippy.toml:40-43 (KD3, clippy.toml:82-84;; the 2026-09-16 async-purity plan KD4 includes tests in the ban;; U1 (d)2 names the R4 dedicated bounded-worker boundary as the only exception -- clean: seeds 0/23/11/0; production locks are all tokio::sync::Mutex, held briefly and never across an await ((driver.rs:449,effects_service.rs:181,400,618;; the test-only atomics order SeqCst on single-threaded doubles ((fine;,and no std::thread spawn/scope or unsafe Send/Sync claims exist in production code. - -## async -- clean: seeds 252/0/10/28; no tokio::spawn/spawn_blocking/JoinSet/select!/join! in src;; production shared state is tokio::sync::Mutex held briefly, never across an await;; the sink lock calls at effects_service.rs:1443 (and the daemon-side equivalents)carry "async-gate-allow: synchronous lock acquisition" marks and "synchronous path" clippy allows - recorded exceptions, not reflagged;; test-support recorder locks carry "async-gate-allow: test-support recorder lock" marks - recorded;; the parking_lot policy class behind those locks is recorded under conc#2/#3; no std::thread::sleep, blocking I/O,,or CPU stretches without awaits inside async fns identified in production code. - - - -## unsafe -- N/A: seeds 0/0/0; no unsafe blocks/fns/impls, no // SAFETY: or transmute/from_raw/MaybeUninit sites in src/**;; the crate manifest's [lints.rust] unsafe_code="forbid" (seed4 alone does not make the lens applicable. - -## ffi -- N/A: seeds 0/0/0/0; no extern "C"/no_mangle/link_section, catch_unwind, repr(C)/repr(transparent), or CStr/CString/c_char sites;; the crate crosses no FFI boundary (all I/O rides tokio/ttrpc/d2b-session-unix wrappers. - - - -## macro -- N/A: seeds 0/0/0/0; no macro_rules! definitions, proc_macro/syn::/quote!, $crate, or to_compile_error/new_spanned sites;; std macros ((format!, vec!, json!)) are not definitions; no DSL or impl-per-type macro need identified - -## test -- clean: seeds 42/87/0/0; tests pin the descriptor declaration and registry behavior (tests/registration.rs), the canonical spec bytes and schema vector ((guest_spec.rs),,the qemu/aca/azure reconcile+finalize+adopt+delete+status-projection semantics ((driver.rs and effects_service.rs #[cfg(test)] modules),,and the Cloud Hypervisor fail-closed shutdown (shutdown.rs;; expected values are literal or pinned constants or hand-asserted enumerations, no test restates its own implementation or computes its expectation with the logic under test;; no #[ignore], no network dependence, no property/snapshot tooling needed for the current surface;; the test-harness parking_lot policy class is recorded under conc#3. - -## Coverage -- idiom: clean (seeds ran: 2/1/3) -- own: 2 finding(s) -- type: 1 finding(s) -- api: clean (seeds ran: 114/9/7) -- err: clean (seeds ran: 128/3/1/3) -- serde: clean (seeds ran: 2/13/0/40) -- obs: clean (seeds ran: 0/0/0/13) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: 2 finding(s) -- async: clean (seeds ran: 252/0/10/28) -- unsafe: N/A (seeds: 0/0/0; no unsafe blocks; manifest forbids (seed4 alone does not make it applicable)) -- ffi: N/A (seeds: 0/0/0/0; no FFI surface) -- macro: N/A (seeds: 0/0/0/0; no macro definitions) -- test: clean (seeds ran: 42/87/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md deleted file mode 100644 index 536cba39a..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-host.md +++ /dev/null @@ -1,77 +0,0 @@ -# d2b-provider-host - d2b-provider-host -Baseline: 6ebdd4cec | LOC audited: 2092 (src 1942 excl. src/generated/**, tests 150) | modules: whole crate (driver.rs, effects_service.rs, facets.rs, lib.rs, probe.rs, test_support.rs; tests/registration.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-host#1 sev=low blast=leaf effort=S verdict=actionable - stray misindented closing brace at test_support.rs:185 closes `impl RecordingMinijailGate` at 4-space indent (the fn body closes at :183, the impl at :185) - fix: reindent the stray `}` to column 0 (rustfmt would flag it) - [packages/d2b-provider-host/src/test_support.rs:185] - evidence: idiom seeds = 1 hit (seed 3 `let mut \w+ = (String|Vec)::new()` at effects_service.rs:109, a push-loop the skill's plain-for carve-out covers: side-effecting `.await` probe calls plus an early `?` return); stray brace confirmed by awk line dump, not a seed hit -- clean: seeds ran: 0/0/1; no index loops, no hand-written derives (all impls are deliberate: Debug/Display redaction via label_identity macros, Display as wire kind names), no statement-style accumulation outside the one carve-out loop - -## own -- d2b-provider-host#2 sev=low blast=leaf effort=S verdict=actionable - avoidable clones of the row key strings before parsing into identity newtypes: `ResourceTypeName::parse`/`ResourceName::parse` take `impl Into`, so `&String` converts without cloning - fix: pass `&ctx.key().type_name` / `&ctx.key().name` at driver.rs:263/266 (or `.as_str()`) - [packages/d2b-provider-host/src/driver.rs:263, packages/d2b-provider-host/src/driver.rs:266] - evidence: own seed 1 (`.clone()`) = 10 hits; the only production-code clones are these two (the rest are test fakes, test-support doubles, Arc refcount bumps, and error/status construction); parse signature at packages/d2b-contracts-resource/src/v3/identity.rs:79 -- clean: seeds ran: 10/22/0/0; remaining clones are explainable: `error.detail.clone()` (driver.rs:334, trait passes `&HostDriverError`), `self.facets.clone()` (effects_service.rs:225, one Arc refcount bump per zone respawn), `Arc::clone` at spawn-free factory create, `to_owned()` at wire/error boundaries; no Rc/RefCell/Arc/Cow in production code - -## type -- clean: seeds ran: 4/0/0; the 4 hits are `#[tokio::test] async fn validate_*` test names, not runtime validation helpers; no boolean flags, no stringly-typed state; `HostDriverErrorKind` is a closed enum splitting by caller action (refused/not-yet/retryable); the providerRef fence is the typed admission check at the decode boundary, not validate-at-every-callsite - -## api -- d2b-provider-host#3 sev=low blast=leaf effort=S verdict=actionable - dead `pub` visibility on seven items in the private `mod driver` that are never re-exported: `HostDriver`, `HostDriverError`, `HostDriverStatus`, `HostDriverFactory`, `HostDriverEffects`, `host_spec_decoder`, `HOST_REOBSERVE` - fix: make them `pub(crate)` (the live surface is the lib.rs re-export set: host_descriptor, HOST_EFFECTS_SERVICE, HostEffectsServiceFactory, HostEffectFacets, MinijailPlatformGateSource, production_probe, the three probe constants, MinijailPlatformGate) - [packages/d2b-provider-host/src/driver.rs:84, packages/d2b-provider-host/src/driver.rs:111, packages/d2b-provider-host/src/driver.rs:147, packages/d2b-provider-host/src/driver.rs:174, packages/d2b-provider-host/src/driver.rs:189, packages/d2b-provider-host/src/driver.rs:206, packages/d2b-provider-host/src/driver.rs:239] - evidence: api seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) = 35 hits; census: `HostDriverError|HostDriverStatus|HostDriverFactory|HostDriverEffects|host_spec_decoder|HOST_REOBSERVE` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 code hits outside the crate (2 README.md prose mentions only); `HostDriver::new` is already `pub(crate)` while its type is `pub`, marking the visibility as accidental -- clean: seeds ran: 35/7/5; the `Arc` in public signatures (facets.rs:34, probe.rs:82-83, driver.rs:208/240) is genuine shared ownership - the same probe Arc is handed to the driver factory, the effects service, and the daemon composition root (d2bd/src/process_provider_runtime.rs:192-196, d2bd/src/shared_provider_effects.rs:3444); lib.rs `pub use` arms are the house single-surface pattern and every re-export has an external consumer (d2bd/src/resource_plane_v3.rs:64, provider_lifecycle.rs:43) - -## err -- d2b-provider-host#4 sev=low blast=leaf effort=S verdict=actionable - the `HostDriverEffects::observe_host` seam returns `Result`: the production impl flattens the probe error and the fallback reconcile error into one `format!("{probe_error}; {error}")` message, losing the source chain; an internal crate per the skill wants an enum (or thiserror with `#[source]`) - fix: introduce a small closed error enum (e.g. `ObserveError { Probe(SystemCoreError), Reconcile(String) }` with `#[source]`) on the trait and both impls - [packages/d2b-provider-host/src/driver.rs:197, packages/d2b-provider-host/src/effects_service.rs:180] - evidence: err seed 1 (`.unwrap()|.expect()`) = 39 hits, all in `#[cfg(test)]` modules or test-support; seed 4 (`enum \w*Error`) = 1 hit; the String seam is the only untyped error in the crate (caller maps it to a FailureDetail note, no string-matching today, so low not medium) -- d2b-provider-host#5 sev=low blast=leaf effort=S verdict=actionable - `HostDriverError::Display` re-spells the three failure-kind codes ("system-core-spec-invalid", "system-core-host-observation-failed", "system-core-drain-pending") that `HostDriverErrorKind::failure_kind()` already maps to, so a registry-code rename drifts silently - fix: `formatter.write_str(self.kind.failure_kind().code())` using the public `FailureKind::code()` - [packages/d2b-provider-host/src/driver.rs:129, packages/d2b-provider-host/src/driver.rs:99] - evidence: err seed 4 = 1 hit; `FailureKind::code()` is public and registry-backed (packages/d2b-resource-runtime/src/error.rs:980, docs/reference/resource-runtime-failure-kinds.md generated from it) -- clean: seeds ran: 39/0/0/1; production code has zero unwrap/expect/panic sites; the 39 unwrap/expect hits are all in `#[cfg(test)]` and test-support doubles with named invariants ("uncontended test mutex"); `HostDriverErrorKind` splits by caller action and maps onto the registered failure kinds - -## serde -- clean: seeds ran: 0/0/0/4; the four `serde_json::from_`/`to_` hits are boundary decodes with error mapping: the spec decoder (driver.rs:175), the HostSpec admission decode of the canonical base (driver.rs:292), and the `inspect-host` payload built through the canonical JSON object path (effects_service.rs:75, from_value over json! - the documented escape-safe route); no hand-written Deserialize, no wire type defined in this crate - -## obs -- N/A: seeds 0/0/0/0; the crate carries no tracing/log dependency (Cargo.toml [dependencies] has none) and emits no telemetry of its own - the effects service returns structured payloads instead - -## docs -- d2b-provider-host#6 sev=low blast=leaf effort=S verdict=actionable - `HostDriverEffects::observe_host` is the one pub Result-returning item whose doc contract lacks an `# Errors` section: "or report why the observation could not be taken" does not enumerate the failure conditions (probe failure -> retryable HostObservation; spec decode -> SpecInvalid) - fix: add `# Errors` listing the two failure conditions and their classification - [packages/d2b-provider-host/src/driver.rs:189] - evidence: docs seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits across 34 pub items; the crate is `#![deny(missing_docs)]` (lib.rs:25) and every pub item carries a first-sentence doc, so this is the remaining contract gap -- clean: seeds ran: 34/0/30; module docs present in all six modules; magic values documented with the why (HOST_REOBSERVE echoes the old 5s resync, the probe constants pin cross-family agreements); no `ignore`d doctests (no doctests at all) - -## perf -- clean: seeds ran: 2/13/1; all hits are cold-path or test code: `format!("/sys/module/{}")` in the per-reconcile Usbip probe (probe.rs:174), the error-path `format!` (effects_service.rs:180), `Vec::new()` in test fakes and the fixed 11-class capability loop (one probe per reconcile); `to_string()` once in runtime_path building; no hot loop allocates; static (unmeasured) - -## conc -- clean: seeds ran: 0/7/11/0; every Mutex/atomic hit lives in test-support doubles and unit-test fakes (tokio::sync::Mutex + try_lock with "uncontended test mutex" expects, SeqCst script flags) - appropriate for test doubles; production code holds no shared state, spawns no threads, and declares no manual Send/Sync - -## async -- clean: seeds ran: 112/0/14/19; production async code uses the sanctioned vocabulary: `tokio::fs::read_dir` for /proc and /dev/dri enumeration (probe.rs:112/129); the two synchronous-path sites (`read_bounded` std::fs::File::open + read_to_end, `is_socket` std::fs::metadata) carry per-site `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` - a sanctioned reason tracked by the blocking census (baseline packages/xtask/data/blocking-census-baseline.json lists the crate all-zero because the allows exempt the sites); no guard held across `.await`; no spawn/select!/join!; no cancellation-sensitive irreversible step (probes are read-only); no async-gate-allow markers in the crate - -## unsafe -- N/A: seeds 0/0/0/0; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) alone does not make the lens applicable - -## ffi -- N/A: seeds 0/0/0/0; no extern "C", no repr(C), no CStr/CString anywhere in the crate - -## macro -- N/A: seeds 0/0/0/0; no macro_rules!, no proc-macro/syn/quote usage in the crate - -## test -- clean: seeds ran: 23/71/0/0; 23 test fns (19 `#[tokio::test]` in src, 3 `#[tokio::test]` + 1 `#[test]` in tests/registration.rs) assert observable behavior: report fields, failure classes (not Display strings), error variants, call orders, requeue counts, and the one-observation-per-generation invariant; the live-host probe test documents its non-degenerate guard (probe.rs:251-256); no `#[ignore]`, no flaky clock/network dependence; registration.rs is the policy-required registration boundary test (provider crate policy) - -## Coverage -- idiom=1 | clean | N/A: - -- own=1 | clean | N/A: - -- type: clean (seeds ran: 4/0/0) -- api=1 | clean | N/A: - -- err=2 | clean | N/A: - -- serde: clean (seeds ran: 0/0/0/4) -- obs: N/A (seeds: 0/0/0/0; no tracing/log dependency in Cargo.toml) -- docs=1 | clean | N/A: - -- perf: clean (seeds ran: 2/13/1) -- conc: clean (seeds ran: 0/7/11/0) -- async: clean (seeds ran: 112/0/14/19) -- unsafe: N/A (seeds: 0/0/0/0; manifest `unsafe_code = "forbid"` alone does not make the lens applicable) -- ffi: N/A (seeds: 0/0/0/0) -- macro: N/A (seeds: 0/0/0/0) -- test: clean (seeds ran: 23/71/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md deleted file mode 100644 index 11485f475..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-network-local.md +++ /dev/null @@ -1,79 +0,0 @@ -# d2b-provider-network-local - d2b-provider-network-local -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 11234 (excl. src/generated/**, src 9346 + tests 1888) | modules: whole crate (artifact, bridge_port, broker, controller, diagnostics, driver, effects_service, facets, ifname, netlink, nftables, observe, operations, plan, routes, test_support) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: n/a (single lane) - -## idiom -- d2b-provider-network-local#1 sev=low blast=leaf effort=S verdict=actionable - octet-to-string conversion collects a Vec of four Strings and joins it, where one format! suffices - fix: destructure the parsed octets (`let [a, b, c, d] = octets; Some(format!("{a}.{b}.{c}.{d}"))`) instead of `.collect::>().join(".")` - [src/controller.rs:298-302] - evidence: idiom seed `let mut \w+ = (String|Vec)::new\(\)` count 10; the site is the collect-then-convert shape the skill names (reviewed statically) -- d2b-provider-network-local#2 sev=low blast=leaf effort=S verdict=actionable - declared_dependency_refs accumulates into `let mut refs = Vec::new()` with a nested if-push, where a filter_map pipeline fits - fix: `spec.pointer("/spec/attachments").and_then(Value::as_array).into_iter().flatten().filter_map(|a| a.get("executionRef").and_then(Value::as_str).and_then(|v| ResourceRef::parse(v.ok()()).collect()` - [src/driver.rs:377-393] - evidence: idiom seed `let mut \w+ = (String|Vec)::new\(\)` count 10 (direct hit at driver.rs:378) - -## own -- d2b-provider-network-local#3 sev=low blast=leaf effort=S verdict=actionable - collision-detection BTreeSet stores owned Strings from borrowed &str keys, though the set never outlives the borrow - fix: `let mut unique_interfaces = BTreeSet::new();` and insert `ifname.as_str()` (a set of `&str` borrowing interface_names for its whole short life)) - [src/controller.rs:416-417] - evidence: own seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` count 85; sampled: 50 of 206 own hits (every 5th; the borrow lives only inside the fn, no caller census needed) - -## type -- clean: seeds: `fn validate_\w+|fn check_\w+` 14, `is_\w+: bool|\w+_flag: bool` 1), `(mode|kind|state): String` 0; every validator takes already-parsed types (TapRole, BridgePortFlagSet, DefaultRouteState, ReconcileInput)...) and the one bool is a single config flag, not flag soup; no illegal-state combos found - -## api -- d2b-provider-network-local#4 sev=medium blast=leaf effort=S verdict=actionable - two pub route validators are exported with zero production callers (only crate-internal unit tests), and the wrapper carries a stale `#[allow(dead_code)]` on a pub item - fix: lower both to `pub(crate)` (unit tests still reach them)and remove the dead_code allow, or wire them into BrokerNetworkEffectPort::apply_routes/remove_routes which currently resolve intents without these checks - [src/routes.rs:244-279, src/routes.rs:264-265] - evidence: census: `validate_network_route_intent` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 7 hits (all in src/routes.rs: def 245, wrapper call 276, tests 525/534, wrapper def 265, wrapper tests 568/579); `validate_network_route_intent_with_provenance` = 3 hits (all in src/routes.rs; sampled: 50 of 328 api hits - -## err -- d2b-provider-network-local#5 sev=low blast=leaf effort=S verdict=actionable - the sole non-test unwrap (SHA-256 word slice conversion() carries no named invariant, though the 4-byte length is statically known - fix: `u32::from_be_bytes(chunk[offset..offset + 4].try_into().expect("4-byte chunk word"))` or a slice-pattern destructure - [src/nftables.rs:588] - evidence: err seed `\.unwrap\(\)|\.expect\(` count 155 (154 are cfg(test) fixtures or literal canonical-ref expects at operations.rs:139-202; this singleton is production code) - -## serde -- d2b-provider-network-local#6 sev=medium blast=leaf effort=M verdict=actionable - the stored-spec parse maps serde failure to `()` unit, dropping the deserialization reason before the toolkit's SpecInvalid terminal - fix: log the serde error (add a tracing::debug/warn at driver.rs:289 before the map)) or return `Result` and let the driver surface the reason; do not touch the pinned SharedProviderDeclarationError enum - [src/driver.rs:282-289, src/driver.rs:190] - evidence: serde seed `serde_json::from_|serde_json::to_` count 29 (this site maps from_value failure to ()); `derive)...Serialize...)` 0 -- d2b-provider-network-local#7 sev=low blast=leaf effort=S verdict=actionable - provenance serialization failures are silently `.ok()`-swallowed into a missing wire field at four payload builders, while the sibling update-hosts path propagates with map_err - fix: match broker.rs:1368: `.map(serde_json::to_value).transpose().map_err)...)` at all four sites (operations.rs maps to OperationFailure::with_detail(KERNEL_REFUSED, ...)) - [src/broker.rs:1432, src/broker.rs:1453, src/operations.rs:408, src/operations.rs:429] - evidence: serde seed `serde_json::to_` count 29 (4 of which are `.ok()`-swallowed; sibling at broker.rs:1368 uses map_err) - -## obs -- clean: seeds: `\bprintln!\(|\beprintln!\(` 0,, `(info|debug|warn|error|trace)!\("` 0,, `\.instrument\(|#\[instrument` 0,, `tracing::|log::` 4; all four tracing events carry named fields (`broker_kind = %code`, `provider = "network-local"`, `network_uid = ...`) and no secret or interpolated message - -## docs -- d2b-provider-network-local#8 sev=low blast=leaf effort=M verdict=actionable - Result-returning pub items (~151 sites() carry no `# Errors` section naming their failure conditions, despite `#![deny(missing_docs)]` giving every item a first sentence - fix: add canonical `# Errors` sections to the boundary-facing Result fns (at least: resolve_net_vm_system_artifact, validate_readback, validate_network_route_intent, observe_host_network, NetworkReconciler::reconcile/finalize,and the broker kernel adapters)) - [src/artifact.rs:67, src/bridge_port.rs:151, src/routes.rs:245, src/observe.rs:255, src/controller.rs:1096] - evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` 302,, `/// # (Examples|Errors|Panics|Safety)` 0,, `-> Result<` 151; sampled: 50 of 453 docs hits (every 10th; first-sentence quality checked across all modules - mostly strong, no magic values left unexplained) - -## perf -- d2b-provider-network-local#9 sev=low blast=leaf effort=S verdict=actionable - FirewallDigest::to_hex formats each byte into its own String (32 heap allocations per call), though the output size is known - fix: `let mut out = String::with_capacity(64); for byte in &self.0 { use std::fmt::Write; write!(out, "{byte:02x}").expect("writing to String is infallible"); } out` - [src/nftables.rs:266-268] - evidence: static (unmeasured); perf seed `format!\(` count 54; to_hex is cross-crate used (d2bd resource_plane_v3.rs:322/533 socket identity keys, process_provider_runtime.rs:3041 log field)) -- d2b-provider-network-local#10 sev=low blast=leaf effort=S verdict=actionable - observed-address parse allocatesa fresh String per entry via `format!("{local}/{prefix}")`, inside the host-observation parse path - fix: build the CIDR text into a reused buffer or add a two-part Ipv4Cidr constructor to the contracts crate - [src/observe.rs:305] - evidence: static (unmeasured); perf seeds: `format!\(` 54,, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 61,, `\.to_string\(\)` 10 - -## conc -- clean: seeds: `std::thread::|thread::spawn|thread::scope` 1 (broker.rs:1662 test poll-loop yield_now), `\bMutex<|\bRwLock<` 7 (all test fixtures; the parking_lot sites carry async-gate-allow markers - recorded exceptions, clippy.toml:40-43,82-84), atomics/Ordering 0,, thread_local/unsafe-Send-Sync 0; no shared-state or atomic-ordering claims in production code - -## async -- d2b-provider-network-local#11 sev=low blast=leaf effort=S verdict=actionable - observe_host_network awaits three independent `ip` observations sequentially, where tokio::join! would run them concurrently - fix: `let (links, addresses, routes)= tokio::join!(run_ip(&["-j", "-d", "link", "show"]), run_ip(&["-j", "-4", "addr", "show"]), run_ip(&["-j", "-4", "route", "show", "table", "all"]));` then parse - [src/observe.rs:255-260] - evidence: async seed `async fn|async move|\.await` count 123 (the three sequential process awaits at observe.rs:256-258 are independent - no data dependency); spawn/JoinSet 0; tokio::sync::* 6 (test fixtures); tokio::test 5; block_on 0 in src; elsewhere kernel invocations run through async kernel_seat::run (operations.rs:249-264) and process calls carry timeouts (observe.rs:420-437); no lock is held across an await in production code, and test-support parking_lot locks carry async-gate-allow markers (test_support.rs:68-80) - deliberate exceptions - -## unsafe -- clean: seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0,, `// SAFETY:` 0,, `transmute|from_raw|MaybeUninit|mem::zeroed` 0,, `unsafe_code` 0 in src; lens N/A (no unsafe code; manifest forbids - Cargo.toml:5)) - -## ffi -- clean: seeds: `extern "C"|no_mangle|unsafe\(link_section` 0,, `catch_unwind` 0,, `repr\(C\)|repr\(transparent\)` 0,, `CStr|CString|c_char` 0; lens N/A (no FFI surface in the crate) - -## macro -- clean: seeds: `macro_rules!` 1 (bridge_port.rs:157 local field-check macro - acceptable impl-per-field generation for nine flags, hygiene trivial), `proc_macro|syn::|quote!` 0,, `\$crate` 0,, `to_compile_error|new_spanned` 0; no macro needs rework - -## test -- clean: seeds: `#\[test\]|#\[tokio::test\]` 95,, `assert_eq!\(|assert_ne!\(|assert!\(` 252 (over src+tests), `proptest!|insta::assert|rstest` 0,, `#\[ignore\]` 0;; sampled: 50 of 347 test hits; all 6 test files read - table-driven cases (broker.rs:1844), error variants asserted not Display strings (netlink.rs:437, observe.rs:730), deterministic, no network; fd-passing test exercisesa real socketpair with rustix ScmRights (network_family.rs:200-220); block_onin plain #[test] harnesses is the sanctioned pattern - -## Coverage -- idiom: 2 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 14/1/0) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: 2 finding(s) -- obs: clean (seeds ran: 0/0/0/4) -- docs: 1 finding(s) -- perf: 2 finding(s) -- conc: clean (seeds ran: 1/7/0/0) -- async: 1 finding(s) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe code, manifest forbids) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: clean (seeds ran: 1/0/0/0) -- test: clean (seeds ran: 95/252/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md deleted file mode 100644 index 0f9bd1722..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-notification-desktop.md +++ /dev/null @@ -1,84 +0,0 @@ -# d2b-provider-notification-desktop - d2b-provider-notification-desktop -Baseline: 6ebdd4cec | LOC audited: 5712 (excl. src/generated/**; none present) | modules: whole crate (17 src files, 5 tests files) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- d2b-provider-notification-desktop#1 sev=low blast=leaf effort=S verdict=actionable - `expected_acknowledgements` accumulates its two source acknowledgement arms with `Vec::new()` + `extend(iterator)` where the chain could collect the Vec directly - fix: `let mut acknowledgements: Vec<_> = plan.start_endpoints.iter().map)...).chain(plan.stop_endpoints.iter().map)...)).collect();` then keep the two conditional `HostSink` pushes - [packages/d2b-provider-notification-desktop/src/controller.rs:660-675] - evidence: seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) = 4 hits; this site is the actionable one (lifecycle.rs:403-405 accumulations track side-effecting plan application and are not collect-able) -- d2b-provider-notification-desktop#2 sev=low blast=leaf effort=S verdict=actionable - `NotificationProviderDescriptor::service_package()` hardcodes the wire literal `"d2b.notification.v3"` duplicating the exported `SERVICE_PACKAGE` const - fix: return `crate::SERVICE_PACKAGE` so the literal has one home - [packages/d2b-provider-notification-desktop/src/descriptor.rs:43-44, packages/d2b-provider-notification-desktop/src/lib.rs:70] - evidence: seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 1 hit (descriptor.rs:32 manual `Default` preserving the `schema_version=1` invariant - false positive); static read: literal duplicated from the exported const - -## own -- d2b-provider-notification-desktop#3 sev=low blast=leaf effort=S verdict=actionable - `commit_reconciliation` takes `SourceReconcileResult` by value but only reads its fields, forcing `.clone()` at both call sites - fix: take `result: &SourceReconcileResult` and drop the two `.clone()` calls - [packages/d2b-provider-notification-desktop/src/controller.rs:1033, packages/d2b-provider-notification-desktop/src/controller.rs:1058, packages/d2b-provider-notification-desktop/src/controller.rs:1297-1318] - evidence: seed 1 (`\.clone\(\)`) = 91 hits; these two are avoidable because `commit_reconciliation` reads only `result.stop/start_endpoints/start_host_sink/stop_host_sink/host_sink_fingerprint` -- d2b-provider-notification-desktop#4 sev=low blast=leaf effort=S verdict=actionable - `NotificationLifecycleSupervisor` wraps its owned backend in `Arc`, counting one reference that nothing else shares - fix: store `backend: B` directly (drop `Arc`) while keeping the `Send + Sync` bounds - [packages/d2b-provider-notification-desktop/src/lifecycle.rs:338, packages/d2b-provider-notification-desktop/src/lifecycle.rs:346] - evidence: seed 3-4 (`Rc<|RefCell<|Arc` sites (controller, lifecycle, guest_source, runtime) form a stringly error family forcing callers to string-match, while sibling enums (AdmissionError, NotificationError, SinkError)_ are typed - fix: introduce one crate error enum (suggest `NotificationLifecycleError`) for the lifecycle/controller/config family and replace the str returns on pub fns and both effect-port traits; update d2bd's `InteractionNotificationLifecycleBackend` impl - [packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provider-notification-desktop/src/lifecycle.rs:291-297, packages/d2b-provider-notification-desktop/src/controller.rs:369, packages/d2b-provider-notification-desktop/src/controller.rs:930] - evidence: seed 4 (`enum \w*Error`) = 7; grep `Result<[^>]*, &'static str>` over src/*.rs = 50 hits; tests match on the strings (guest_source.rs:100-115), so callers string-match -- d2b-provider-notification-desktop#10 sev=medium blast=leaf effort=S verdict=actionable - Delivery rejection paths collapse every admission/session/category failure into `NotificationError::InvalidOpaqueKey`, misreporting "notification-opaque-key-invalid" for unauthenticated, cross-zone,and category-denied cases - fix: add an `NotificationError::Denied` (or `SessionDenied`) variant and map the five admission/zone/category rejection sites to it; keep `InvalidOpaqueKey` for key-bound violations - [packages/d2b-provider-notification-desktop/src/host_sink.rs:185, packages/d2b-provider-notification-desktop/src/host_sink.rs:195, packages/d2b-provider-notification-desktop/src/host_sink.rs:202, packages/d2b-provider-notification-desktop/src/host_sink.rs:308, packages/d2b-provider-notification-desktop/src/runtime.rs:103] - evidence: seed 2 (`let _ = |\.ok\(\);`) = 0; static read: `InvalidOpaqueKey` used as catch-all at 9 sites (host_sink.rs:185-308, runtime.rs:103-129); slug not pinned by docs/reference (grep "notification-" = 0 hits) - -## serde -- clean: seeds ran: 6/13/2/0 - derive(Serialize/Deserialize)=6; serde attrs=13; hand-written Deserialize=2 (live admission gates for the wire twins at types.rs:232/307, sanctioned per record rows 143/151); serde_json=0 in src. Wire shapes land through deny_unknown_fields gates + TryFrom validation - clean - -## obs -- clean: seeds ran: 0/24/0/4 - println!/eprintln!=0; tracing event macros=24, all with named fields (provider, zone, reason, action) + static messages; interpolated-message-with-no-fields events=0; instrument/spans=0 (sync provider path, no async context to carry); `use tracing` lines=4. All events carry the provider/zone/reason context as fields - clean - -## docs -- d2b-provider-notification-desktop#11 sev=medium blast=leaf effort=M verdict=actionable - No `# Errors` section exists on any Result-returning pub item (112 `-> Result<` sites) even though the crate pins wire-leaning error enums - fix: add `# Errors` sections naming the exact variants (or stable slugs) on pub fns like `ActionNonceStore::register`, `NotificationRuntime::new`, `NotificationSink::deliver_from_guest_source` - [packages/d2b-provider-notification-desktop/src/action_nonce.rs:84-89, packages/d2b-provider-notification-desktop/src/runtime.rs:64-67, packages/d2b-provider-notification-desktop/src/host_sink.rs:297-305] - evidence: seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 across 229 pub items (seed 1 = 229, seed 3 `-> Result<` = 112) -- d2b-provider-notification-desktop#12 sev=low blast=leaf effort=S verdict=actionable - Doc first sentences are broken fragments: "/// the daemon." opens `deliver_evidence`,"/// completes every effect immediately." opens `RecordingEffects`,"/// the current authenticated reconnect generation." runs into the `from_config_at_generation` doc - fix: rewrite each as a standalone 15-word summary before the trailing paragraph - [packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-notification-desktop/src/test_support.rs:14, packages/d2b-provider-notification-desktop/src/guest_source.rs:17] - evidence: static read: first-sentence shape at the three anchors ("the daemon."/"completes every effect immediately."/"the current authenticated...") - -## perf -- d2b-provider-notification-desktop#13 sev=low blast=leaf effort=S verdict=actionable - `NotificationSink::deliver` formats "notification-{id}" once (request_id) but re-formats the same string three more times into projection map keys; `close` re-formats from u32 while callers already hold the request_id string - fix: reuse `request_id` (clone it into map keys where needed)and add an internal `close_by_request_id(&str)` to kill the u32-to-String-to-u32 round-trip in `close_session`/`gc_projections` - [packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-notification-desktop/src/host_sink.rs:276-291, packages/d2b-provider-notification-desktop/src/host_sink.rs:376, packages/d2b-provider-notification-desktop/src/host_sink.rs:484-493] - evidence: seed 1 (`format!\(`) = 16 hits; four-plus of them re-format a string the caller already owns (host_sink.rs:265 vs 276/278/288/291; close at 376 vs callers holding request_id); static (unmeasured) - -## conc -- clean: seeds ran: 0/1/0/0 - std::thread/spawn/scope=0; Mutex/RwLock=1 (lifecycle.rs:339 `state: Mutex` on sanitary synchronous path, guarded by tracked allows at lifecycle.rs:355/394/538 with reason "synchronous path"); Atomics/Ordering=0; thread_local!/unsafe impl Send/Sync=0 - clean - -## async -- N/A (seeds: 0/0/0/0 all zero; the crate declares no async fn, await, spawn, or tokio runtime usage) - -## unsafe -- N/A (seeds: 0/0/0/1; seeds 1-3 all zero; the lone seed 4 hit is `#![forbid(unsafe_code)]` at lib.rs:4, which per the lens card does not make the lens applicable) - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, repr(C/transparent), CStr/CString, or catch_unwind in src) - -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, proc-macro, or syn/quote usage) - -## test -- clean: seeds ran: 41/131/0/0 - #[test]=41 (25 src + 16 tests); asserts=131 (86 src + 45 tests); proptest!/insta/rstest=0; #[ignore]=0; tests are behavioral (wire defaults, redaction canary, receipt matching, partial-effect rollback, nonce single-use/bounds, closed telemetry labels)and deterministic (injected now_secs, no network or clock reads)- clean - -## Coverage -- idiom: 2 finding(s) -- own: 2 finding(s) -- type: 1 finding(s) -- api: 3 finding(s) -- err: 2 finding(s) -- serde: clean (seeds ran: 6/13/2/0) -- obs: clean (seeds ran: 0/24/0/4) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 0/1/0/0) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn/await/spawn/runtime) -- unsafe: N/A (seeds: 0/0/0/1; seeds 1-3 zero; seed 4 alone is the forbid attribute) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 41/131/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md deleted file mode 100644 index ffe9f1bf9..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-observability-otel.md +++ /dev/null @@ -1,99 +0,0 @@ -# d2b-provider-observability-otel - d2b-provider-observability-otel -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3766 (excl. src/generated/**) | modules: whole crate (agent, config, controller, emitter_socket, ingress_policy, lib, metric_policy, metrics; tests: binding_controller, ingress_metric_policy) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none - -## idiom -- clean: seeds ran: 2/3/0; two `for _ in 0..` loops are test harnesses (ingress_policy.rs:905,1080),and the three hand-written `Default` impls preserve invariants the field-wise derive would break (config.rs:137, controller.rs:364, ingress_policy.rs:268), per U1 lens-card false-positive class. - - - -## own -- d2b-provider-observability-otel#1 sev=low blast=leaf effort=S verdict=actionable - provider-agent methods clone their input strings only to hand them to a token parser, though parse_closed_token could borrow - fix: change parse_token/parse_closed_token (agent.rs:224-244) to take `value: &str` (BoundedToken::parse takes `impl Into`, so `&str` satisfies it),and drop the five `clone()` calls in session_connect/process_effect - [agent.rs:255, agent.rs:256, agent.rs:283, agent.rs:285, agent.rs:288] - evidence: seed `\.clone\(\)` over src = 17 hits (7 in agent.rs;5 avoidable via the borrow-taking parse;2 at agent.rs:332-333 required for ownership transfer into `ToolkitAuditEvent::new`) - - -## type -- d2b-provider-observability-otel#2 sev=low blast=leaf effort=S verdict=actionable - ProviderAgentAuditEvent stores the four closed audit strings as `String`/`Option` and immediately discards the validated `BoundedToken` (parse-then-copy-back at as_str().to_owned()) - fix: store `BoundedToken`/small enums in the event fields (agent.rs:59,66-68),and render through `BoundedToken::as_str` in the Serialize impl (wire output unchanged) - [agent.rs:56, agent.rs:265, agent.rs:297] - evidence: seeds ran: `fn validate_|fn check_` = 3 hits (all boundary validators), `is_: bool|flag: bool` = 0, `(mode|kind|state): String` = 0; reading: event/authz_decision/provider/domain are parsed into `BoundedToken` (agent.rs:230-298) then converted back to String for storage - - -## api -- clean: seeds ran: 121 pub items/1 Arc-in-signature/6 re-export arms; `pub use` re-export arms in lib.rs are the house single-surface pattern (U1 lens-card FP),and the sole `Arc` signature (ingress_policy.rs:331)is justified shared ownership - tests create one ManualClock and clone the Arc into multiple gates (ingress_policy.rs:902,1208,1286) - - -## err -- d2b-provider-observability-otel#3 sev=low blast=leaf effort=S verdict=actionable - when the connection-tracking table is full, reject() reports `IngressErrorClass::Malformed` ("frame could not be decoded") though the frame may be valid, whereas the sibling capacity refusal reports `None` - fix: return `IngressOutcome::Rejected, IngressErrorClass::None)` on that branch(or a distinct class, if one is introduced for wire labeling),consistent with the capacity path at ingress_policy.rs:460 - [ingress_policy.rs:647] - evidence: reading of reject() full-table branch; seed `let _ = |\.ok\(\);` = 7 hits (all deliberate best-effort cleanups or test drills),and wire-visible error classes are the `as_str` labels of IngressErrorClass (ingress_policy.rs:87-91) - - -## serde -- clean: seeds ran: 1/0/1/10; the hand-written `Deserialize` for ProviderConfig (config.rs:127)is a live strict admission gate over untrusted config (the recorded refusal class: hand-written Deserialize admission gates - do not re-flag),the hand-written `Serialize` for ProviderAgentAuditEvent (agent.rs:68)and ProviderConfig (config.rs:118) render redacted/canonical shapes deliberately,and all serde_json sites are round-trip tests or the deliberate canonical-size measurement - - -## obs -- clean: seeds ran: 0/0/0/3; zero println/format-interpolated events(only message-only events with named fields: provider, binding, ingress, outcome, error_class, connection),all diagnostic events carry `provider = "observability-otel"` as a field,andzone/source redaction lives in the Debug/Serialize overrides (deliberate; agent.rs:72-86,88-99) rather than in log calls - - - - - -## docs -- d2b-provider-observability-otel#4 sev=medium blast=leaf effort=S verdict=actionable - the three crate-identity constants `PROVIDER_NAME`,`PROVIDER_REF`,`PROVIDER_API_MAJOR` in lib.rs lack doc comments while every sibling public item in the crate carries one - fix: add one-line doc comments naming each constant's role (mirroring the documented `OTEL_HOST_BRIDGE_ROLE` on the next line) - [lib.rs:13, lib.rs:14, lib.rs:15] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 121 hits over src; the three constants are the only bare undocumented pub items found by reading lib.rs -- d2b-provider-observability-otel#5 sev=medium blast=leaf effort=M verdict=actionable - Result-returning pub API fns lack `# Errors` doc sections naming their failure conditions, leaving callers to infer variants from code - fix: add `# Errors` sections to at least the five representative fns (ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream,EmitterSocket::bind/drain_once, validate_resource_attributes),enumerating e.g. `ProviderAgentError::{SessionDenied,AuditBackpressure,InvalidInput}` - [agent.rs:216, config.rs:147, controller.rs:100, emitter_socket.rs:131, metric_policy.rs:21] - evidence: seed `-> Result<` = 22 hits (11 of them pub fn signatures across 6 modules); none of the pub Result fns' doc comments contain a `# Errors` section (seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits over src) - - -## perf -- d2b-provider-observability-otel#6 sev=low blast=leaf effort=S verdict=actionable - drain_once allocates a fresh 64KiB+1 scratch buffer per datagram inside the drain loop ( <= 256 iterations/call),when one buffer reused across recv calls would suffice - fix: hoist `let mut bytes = vec![0_u8; MAX_COMPACT_FRAME_BYTES + 1];` above the while loop,and `bytes.resize(MAX_COMPACT_FRAME_BYTES + 1, 0)` per iteration; the queued redacted frame remains its own owned Vec from redact_parsed_frame - [emitter_socket.rs:139] - evidence: static (unmeasured); seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 6 hits; he deep read of drain_once found the per-iteration allocation -- d2b-provider-observability-otel#7 sev=low blast=leaf effort=M verdict=actionable - admit_for_connection re-measures every frame by re-serializing the whole MetricFrame to JSON(allocating a Value tree plus a String per admission),though the wire-boundary paths already carry `encoded_bytes` - fix: thread the canonical measured size through from the decode boundary (admit_raw/admit_parsed/metric_frame_from_raw) instead of re-calling measured_encoded_bytes in admit_for_connection, preserving the documented trustless measurement at the boundary(ingress_policy.rs:202-203)rather than per admission - [ingress_policy.rs:203, ingress_policy.rs:368] - evidence: static(unmeasured; seed `format!\(` = 1 hit(cold construction path))and `serde_json::to_` = 10 hits; reread of admit_for_connection (line 395+) shows measured_encoded_bytes called for every frame before policy evaluation -- d2b-provider-observability-otel#8 sev=low blast=leaf effort=S verdict=actionable - valid_resource_attribute_value allocates a lowercase copy of each attribute value(`to_ascii_lowercase()`)on the per-frame resource-attribute validation path,only to substring-test six words - fix: replace the allocation with a case-insensitive byte-scan helper(e.g. a local `contains_ignore_ascii_case(value, word)`)over the already-bounded( <= 256-byte)value - [metric_policy.rs:44] - evidence: static(unmeasured; seed `\.to_string\(\)` = 20 hits(most are wire-map construction); the identified site allocates per attribute value per admission frame(validate_resource_attributes is called from admit_for_connection at ingress_policy.rs:411)) - - -## conc -- clean: seeds ran: 0/0/20/0; zeroproduction threads/locks/atomics; all `AtomicU64`/`AtomicUsize` + `Ordering` hits are in `#[cfg(test)]` harnesses (ManualClock in ingress_policy.rs:769-775,and SOCKET_SEQUENCE in emitter_socket.rs:380-383),test-only synchronization per U1 lens-card FP; production shared state is the single `Arc` trait-object ownership already judged under api - - -## async -- N/A: seeds ran: 0/0/0/0; no async fn/.await/tokio::spawn/tokio::sync anywhere in src,andthe crate declares no tokio dependency - the whole crate is a synchronous library - - -## unsafe -- N/A: seeds ran: 0/0/0/1; seeds1-3 all zero(no unsafe blocks/fns/impls,no SAFETY comments,no transmute/from_raw/MaybeUninit/zeroed),and seed4 alone - the `#![forbid(unsafe_code)]` attribute(lib.rs:3)- does not make the lens applicable per U1 lens-card - - - -## ffi -- N/A: seeds ran: 0/0/0/0; no extern "C"/no_mangle/link_section/catch_unwind/repr(C)/repr(transparent)/CStr/CString/c_char anywhere; the rustix fchmod/fstat call sites(emitter_socket.rs:86,282)are safe-wrapper syscall call sites that never cross a foreign caller(U1 lens-card FP) - - - -## macro -- N/A: seeds ran: 0/0/0/0; no macro_rules!/proc_macro/syn/quote/$crate/to_compile_error/new_spanned anywhere; only std macros and derives exist,which are not definitions per U1 lens-card FP - - - -## test -- d2b-provider-observability-otel#9 sev=medium blast=leaf effort=S verdict=actionable - the resource-attribute validation test asserts only `is_err()` for both failure shapes,so a regression swapping the two wire-visible variants(`NotAllowlisted` vs `Invalid`)would pass - fix: replace the two `is_err()` assertions in `resource_attributes_have_a_separate_allowlist` with `assert_eq!)..., Err(ResourceAttributeError::NotAllowlisted))` for the unknown-key case,and `assert_eq!)..., Err(ResourceAttributeError::Invalid))` for the credential-canary value case - [metric_policy.rs:145, metric_policy.rs:150] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` over src+tests = 158 hits(assert! mass incl.the two variant-blind is_err sites at metric_policy.rs:145,150); the variants' Display codes differ("otel-resource-attribute-not-allowlisted" vs "otel-resource-attribute-invalid", metric_policy.rs:83-91),so a caller can match on them - - -## Coverage -- idiom: clean(seeds ran: 2/3/0; index loops in test harnesses; Default impls deliberate) -- own: 1 finding(s) -- type: 1 finding(s) -- api: clean(seeds ran: 121/1/6; re-exports house pattern; Arc sharing justified by tests) -- err: 1 finding(s) -- serde: clean(seeds ran: 1/0/1/10; hand-written gates deliberate per refusal class) -- obs: clean(seeds ran: 0/0/0/3; no println; named-field events only) -- docs: 2 finding(s) -- perf: 3 finding(s) -- conc: clean(seeds ran: 0/0/20/0; all atomic hits test-only) -- async: N/A(seeds:0/0/0/0; no async fn or tokio dep) -- unsafe: N/A(seeds:0/0/0/1; forbid(unsafe_code) attribute alone does not apply per U1) -- ffi: N/A(seeds:0/0/0/0; no FFI surface; rustix wrappers are not crossings) -- macro: N/A(seeds:0/0/0/0; no macro definitions) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md deleted file mode 100644 index e1f7675c1..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process-systemd.md +++ /dev/null @@ -1,84 +0,0 @@ -# d2b-provider-process-systemd - d2b-provider-process-systemd -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3816 (excl. src/generated/**, incl. tests/**) | modules: whole crate (src: audit, controller, drain, effects_service, error, launch, lib, lifecycle, metrics, operations, sandbox; tests: boundaries, conformance, controller, execution_parents, lifecycle) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-process-systemd#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default` on the unit structs `SystemdEffectsService` and `SystemdEffectsServiceFactory` where `#[derive(Default)]` generates the identical impl - fix: replace both `impl Default { fn default() -> Self { Self::new() } }` blocks with `#[derive(Default)]` on the structs - [packages/d2b-provider-process-systemd/src/effects_service.rs:98, packages/d2b-provider-process-systemd/src/effects_service.rs:218] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 3 hits; the third (`SystemdProviderConfig`, src/lifecycle.rs:20) is a legitimate hand-written Default preserving nonzero bounded defaults (a field-wise derive would yield zeros) -- clean: seeds ran: 0/3/0 - no index loops (`for \w+ in 0\.\.` = 0), no statement-style accumulation (`let mut \w+ = (String|Vec)::new\(\)` = 0); the only hand-written impls are the two unit-struct Defaults above plus the invariant-preserving config Default - -## own -- clean: seeds ran: 14/29/0/0 - every `.clone()` is explainable: move-closure captures into `kernel_seat::run` (src/operations.rs:649-653), owned `ProcessStatusReport`/`UnitIdentity` fields (src/lib.rs:238-243, src/operations.rs:596-597), the payload clone into `ValidatedPayload` (src/effects_service.rs:184), and cfg(test) fixtures; `.to_owned()/.to_string()` sites are uid/path formatting, closure captures, and error-detail strings; no Rc/RefCell/Arc/Arc/Cow - -## type -- d2b-provider-process-systemd#2 sev=low blast=leaf effort=S verdict=actionable - `RestartPolicy.restart_on_failure: bool` is invariant state: the only constructor sets it to `true` and nothing ever mutates it, so the field and its guard encode a state the type cannot otherwise represent - fix: drop the field and the `if !self.restart_on_failure` check in `should_restart`, or add a `RestartPolicy::never()` constructor if the never-restart class is real - [packages/d2b-provider-process-systemd/src/lifecycle.rs:78, packages/d2b-provider-process-systemd/src/lifecycle.rs:100] - evidence: seed `is_\w+: bool|\w+_flag: bool` = 0; full-file read found the invariant field (single constructor `on_failure` at lifecycle.rs:87 sets it true; no other assignment) -- d2b-provider-process-systemd#3 sev=low blast=leaf effort=S verdict=actionable - `metrics::validate_labels` accepts stringly-typed `(String, String)` label pairs checked against the runtime `LABEL_KEYS` allowlist, so a misspelled key is a runtime rejection instead of a type error - fix: introduce `enum MetricLabelKey { Operation, Outcome, Domain }` with an `as_str()` accessor and take the key side typed - [packages/d2b-provider-process-systemd/src/metrics.rs:7, packages/d2b-provider-process-systemd/src/metrics.rs:4] - evidence: seed `fn validate_\w+|fn check_\w+` = 3 hits (`validate_request` is a boundary admission gate cross-checking untrusted wire fields against the trusted bundle - not a parse-once candidate; `validate_launch_ticket` is a two-line provider-binding check); the label-key case is the stringly-typed one -- clean: seeds ran: 3/0/1 - the one `(mode|kind|state): String` hit is the external systemd `ActiveState` property read (src/operations.rs:565), a wire-boundary value, not crate state - -## api -- d2b-provider-process-systemd#4 sev=low blast=leaf effort=S verdict=actionable - `SystemdProviderConfig`, `RestartPolicy`, `SystemdConfigError`, and `EphemeralProcessController` are each reachable at two paths: `pub mod lifecycle` (src/lib.rs:28) plus the root re-export `pub use lifecycle::{...}` (src/lib.rs:33), violating the one-path-per-item surface rule - fix: make `lifecycle` private (`mod lifecycle;`) and keep the root re-export as the single surface; no external caller imports through the module path (tests use the crate root) - [packages/d2b-provider-process-systemd/src/lib.rs:28, packages/d2b-provider-process-systemd/src/lib.rs:33] - evidence: seed `^\s*pub use ` = 1 hit; seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 77 hits; the four re-exported items are the only two-path items (other modules are single-path) -- d2b-provider-process-systemd#5 sev=low blast=leaf effort=S verdict=actionable - `SystemdProviderConfig::no_persistent_unit()` is an always-true method with no production caller; the invariant it states already lives in the README security posture and the dossier - fix: delete the method and its test assertion (tests/lifecycle.rs:12), or replace it with a documented `const` if the surface is contract - [packages/d2b-provider-process-systemd/src/lifecycle.rs:55, packages/d2b-provider-process-systemd/tests/lifecycle.rs:12] - evidence: census: `no_persistent_unit` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel, *.bzl = 2 hits (definition + its own test) -- d2b-provider-process-systemd#6 sev=low blast=leaf effort=S verdict=policy-confirmed - the controller/provider/lifecycle/drain/launch/sandbox/audit/metrics/error modules have zero production consumers: the daemon composes only `effects_service` + `operations` (the U15 forward seam), so the declared controller surface is unwired in the tree - fix: none until daemon composition lands; record the drift - [packages/d2b-provider-process-systemd/src/lib.rs:22, packages/d2b-provider-process-systemd/README.md:28] - evidence: census: `SystemdProcessController|SystemdProcessProvider|SystemdReconcileAction|SystemdReconcileResult|EphemeralProcessController|RestartPolicy|SystemdProviderConfig|DrainProof|DrainStage|DrainError` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel, *.bzl = all hits in-crate (src + tests + README); d2bd consumes only `PROCESS_SYSTEMD_EFFECTS_SERVICE` + `SystemdEffectsServiceFactory` (d2bd/src/resource_plane_v3.rs:2282-2288, d2bd/src/forward_rendezvous.rs:2063-2065); policy: prior audit kept the dossier-named modules (docs/explanation/over-engineering-audit-record.md:262, row 4) and the dossier required layout names them (docs/specs/providers/ADR-046-provider-system-systemd.md:1348-1357); README declares the controller as the shipped library type (README.md:28-31) - -## err -- d2b-provider-process-systemd#7 sev=low blast=leaf effort=S verdict=actionable - `SystemdProviderError` (src/error.rs) is a closed error catalogue with zero consumers while the live handlers refuse through the parallel `&'static str` code constants in src/operations.rs:51-107 - two refusal vocabularies in one crate - fix: delete the unused enum, or route the handler refusals through it (its codes are not pinned in docs/reference/error-codes.md, so no wire contract binds them) - [packages/d2b-provider-process-systemd/src/error.rs:5, packages/d2b-provider-process-systemd/src/operations.rs:51] - evidence: census: `SystemdProviderError` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel, *.bzl = 4 hits, all in src/error.rs (enum, impl, Display, Error); seed `enum \w*Error` = 3 hits (SystemdProviderError, SystemdConfigError, DrainError) -- clean: seeds ran: 24/0/0 - every `.unwrap()/.expect()` is in `#[cfg(test)]` or on frozen literal construction (`BoundedToken::parse(PROVIDER_NAME)` and the profile build in `SystemdProcessProvider::new`, src/lib.rs:68-80; the `LazyLock` operation-table parses, src/operations.rs:161-181); no swallowed Results, no panic macros - -## serde -- clean: seeds ran: 2/2/0/6 - Serialize-only audit projection (`SystemdAuditOperation` kebab-case, `SystemdProcessAudit` camelCase) with no raw unit name/PID/path fields; no hand-written Deserialize; the `serde_json::to_value/from_value` conversions at the operation boundary map failures to the closed refusal codes (UNIT_INVALID_REQUEST/UNIT_QUERY_FAILED) instead of stringified messages - -## obs -- d2b-provider-process-systemd#8 sev=low blast=leaf effort=S verdict=actionable - the `debug!` event on the cancelled-ticket path evaluates `ticket.process_ref().to_canonical_string()` eagerly, allocating the canonical string even when debug is disabled - fix: pass a reference and let the macro format lazily (`resource = %ticket.process_ref()` if Display exists, else `?ticket.process_ref()`), reserving the eager `to_canonical_string()` for the warn/error paths - [packages/d2b-provider-process-systemd/src/lib.rs:139, packages/d2b-provider-process-systemd/src/lib.rs:141] - evidence: seed `(info|debug|warn|error|trace)!\("` = 0 (every event uses named fields); full-file read found the eager field expression on the debug! site -- clean: seeds ran: 0/0/0/4 - no println/eprintln in the library; all tracing events carry named fields (provider, resource, identity, error, timeout_sec); no spans, which is consistent with one-shot handler operations - -## docs -- d2b-provider-process-systemd#9 sev=medium blast=leaf effort=M verdict=actionable - public `Result`-returning items lack `# Errors` sections naming their failure conditions: `SystemdProviderConfig::new` (OutOfRange bounds), `drain::validate` (two refusal variants), `SystemdProcessController::reconcile` (DeadlineExceeded), `validate_launch_ticket`, `SystemdSandboxCompiler::compile` - fix: add `# Errors` sections to each, stating which inputs produce which failure - [packages/d2b-provider-process-systemd/src/lifecycle.rs:33, packages/d2b-provider-process-systemd/src/drain.rs:30, packages/d2b-provider-process-systemd/src/controller.rs:66, packages/d2b-provider-process-systemd/src/launch.rs:8, packages/d2b-provider-process-systemd/src/sandbox.rs:14] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed `-> Result<` = 31 hits; seed `^\s*pub (fn|struct|enum|trait|const|type)` = 67 hits, all documented (the crate opts into `#![deny(missing_docs)]` at src/lib.rs:16) -- clean: seeds ran: 67/0/31 - every public item carries a doc comment with a one-line first sentence and every module has a `//!` doc; the gap is the canonical-section depth, not presence - -## perf -- d2b-provider-process-systemd#10 sev=low blast=leaf effort=S verdict=actionable - `unit_name` builds the hex suffix with `format!` inside a 16-iteration loop (16 small String allocations) plus a final `format!`, on every unit operation that names a unit - fix: write the bytes into the preallocated `String::with_capacity(52)` with `write!` per byte, or format once into a fixed buffer - [packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process-systemd/src/operations.rs:421] - evidence: seed `format!\(` = 20 hits, of which 18 are cold error/detail paths and one is the loop site; static (unmeasured) -- clean: seeds ran: 20/13/10 - `Vec::new()` sites are empty fixtures and the deliberately empty `auxiliary` argument to StartTransientUnit; `.to_string()` sites are uid/path and error-detail strings on cold paths - -## conc -- N/A: seeds: 0/0/0/0 all zero - no threads, locks, atomics, or channels; the only shared state is `tokio::sync::Semaphore` (async-side, judged under async) - -## async -- clean: seeds ran: 53/0/0/3 - no blocking work on the executor (the sync `/proc/sys/kernel/random/boot_id` read in `validate_request` carries the sanctioned per-site allow `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` at src/operations.rs:208); zbus and `/proc//stat` reads are async (tokio::fs); the kernel leg runs through `kernel_seat::run` with 'static captures; the semaphore permit held across `.await` in `reconcile` is the bounded-slot design (try_acquire_owned, never blocking); the timeout-drop of a mid-launch future is recoverable through the designed adoption path; the `tokio::runtime::Handle::try_current()` gate in reconcile is deliberate for the crate's single-poll test driver - -## unsafe -- N/A: seeds: 0/0/0 all zero - no unsafe blocks/fns/impls, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed; manifest sets `unsafe_code = "forbid"` (packages/d2b-provider-process-systemd/Cargo.toml, [lints.rust]) - -## ffi -- N/A: seeds: 0/0/0/0 all zero - no extern "C", no_mangle, catch_unwind, repr(C)/repr(transparent), or CStr/CString/c_char anywhere in the crate (zbus D-Bus calls are Rust-side, not FFI) - -## macro -- N/A: seeds: 0/0/0/0 all zero - no macro_rules!, proc-macro, $crate, or spanned-error machinery; the crate defines no macros - -## test -- clean: seeds ran: 43/102/0/0 - 43 tests (12 in src, 31 in tests/) assert observable behavior with human-written expectations and error-variant matching (`ProcessConformanceError::*`, `EffectServiceError::Declined`), never Display strings; deterministic (no network, explicit current-thread runtimes, 0-second timeouts for the timeout tests); the three runtime-driving tests carry the sanctioned `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]`; no `#[ignore]`, no property/snapshot tooling (not required for this surface); the guest-binding gate test reads the real kernel boot id, which is stable within a boot - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: 14/29/0/0 - every clone explainable; no Rc/RefCell/Arc/Arc/Cow) -- type: 2 finding(s) -- api: 3 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 2/2/0/6 - Serialize-only redacted audit projection; wire conversions map to closed refusal codes) -- obs: 1 finding(s) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics/channels; the only shared state is tokio::sync::Semaphore, async-side) -- async: clean (seeds ran: 53/0/0/3 - no blocking on executor, sanctioned per-site allow cited, bounded-slot permit design, adoption-recoverable timeout) -- unsafe: N/A (seeds: 0/0/0 all zero; unsafe_code = "forbid" in Cargo.toml [lints.rust]) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 43/102/0/0 - behavior-based, error-variant assertions, deterministic, no ignored tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md deleted file mode 100644 index aa28a8083..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-process.md +++ /dev/null @@ -1,75 +0,0 @@ -# d2b-provider-process - d2b-provider-process -Baseline: 6ebdd4cec | LOC audited: 10721 (src 10469, tests 252, excl. src/generated/**) | modules: backend, driver, effects, effects_service, execution, facets, identity, launch_identity, operations, test_support (cfg-gated), worker_launch -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- clean: seeds ran (1/1/0): one `for _ in 0..16` yield helper in a test (driver.rs:2657, a fixed-count yield loop where an iterator pipeline has no meaning) and one hand-written `Default for FakeFacetsConfig` (test_support.rs:88) whose scripted values (`VecDeque::from([ProviderAdoption::Absent])`, `Ok(ProcessIdentityDigest::from_bytes([0x51; 32]))`) a derive cannot express. No index loops, no statement-style accumulation, no replaceable hand-written impls. - -## own -- d2b-provider-process#1 sev=low blast=leaf effort=S verdict=actionable - `envelope.provider_ref.clone().expect("checked")` clones the `Option` at three call sites where `as_ref().expect("checked")` borrows without copying - fix: replace `.clone().expect("checked")` with `.as_ref().expect("checked")` in the `identity()` call at recover, reconcile, and delete - [packages/d2b-provider-process/src/driver.rs:1988, packages/d2b-provider-process/src/driver.rs:2056, packages/d2b-provider-process/src/driver.rs:2105] - evidence: `\.clone\(\)` seed, 3 of 72 driver.rs clone hits; `check_provider` ran immediately before each site so the invariant is already named by the expect, and the clone buys nothing. -- d2b-provider-process#2 sev=low blast=leaf effort=S verdict=actionable - `bind_cloud_hypervisor_guest_uid` takes `argv: &[String]` and clones the whole argv at both return paths (`Ok(argv.to_vec())` and `let mut bound = argv.to_vec()`), while its sole caller never uses `launch_argv` afterwards - fix: take `argv: Vec` by value and return it (caller passes `launch_argv` directly), removing both copies - [packages/d2b-provider-process/src/operations.rs:1354, packages/d2b-provider-process/src/operations.rs:1362, packages/d2b-provider-process/src/operations.rs:2649] - evidence: `\.to_vec\(\)` seed, 2 of 86 operations.rs to_owned/to_vec hits; census: `bind_cloud_hypervisor_guest_uid` over packages/ = 1 call site (operations.rs:2649), which reads `launch_argv` only through this call. - -## type -- clean: seeds ran (5/0/0): the five `validate_*`/`check_*` functions (driver.rs:919 `check_provider`, operations.rs:576 `validate_request_fds`, 756 `validate_typed_process_metadata`, 987 `validate_sandbox_launch_plan`, 1208 `validate_spawn_runner_request_matches_intent`) are boundary fences on wire input, which is where validation belongs; the `typed: bool` parameter is an input-mode flag for one fence, not state. No boolean-flag fields, no stringly-typed state, no validate-at-every-callsite repetition. - -## api -- clean: seeds ran (135/3/15): the pub surface is deliberate and single-path (lib.rs re-export arms are the house pattern); `Arc` in public signatures is genuine shared ownership with visible call sites (`process_spec_decoder() -> Arc` is Arc-cloned into every descriptor, driver.rs:291/619; `ProcessEffectFacets` Arc fields are shared between the driver and the effects service, facets.rs:409-413); `ProcessEffectError` is a closed `#[non_exhaustive]` enum with stable codes (backend.rs:190). No dependency types leak into signatures beyond the deliberate `d2b_process_conformance` re-export, which is the family-home contract. - -## err -- d2b-provider-process#3 sev=low blast=leaf effort=S verdict=actionable - `.ok().and_then(...)` swallows the parse of a stored owning-row spec in the launch-identity path: a corrupt `VolumeBinding` or `Volume` row silently degrades to an unbound launch instead of refusing with `SpecInvalid` - fix: map the two `serde_json::from_slice` failures to `ProcessDriverErrorKind::SpecInvalid` (or return `None` only for genuinely absent rows, not for parse failures) in `identity()` and `serving_worker_launch()` - [packages/d2b-provider-process/src/driver.rs:1018-1030, packages/d2b-provider-process/src/driver.rs:1124-1130] - evidence: `\.ok\(\);`/`.ok()` seed, 2 of 10 driver.rs `.ok()` sites; the downstream ticket fence (`provider-ticket:template-not-found`) still refuses closed, so severity stays low. -- clean: seeds ran (185/14/8/2): all `unwrap`/`expect` outside tests sit on literally-built constants (operations.rs:159-213, 278-280, 1549, 2174, 2205) or after a check the compiler cannot see (`expect("checked")`, driver.rs:1988/2056/2105); every `panic!`/`unreachable!` hit is in `#[cfg(test)]`; `let _ =` sites are deliberate best-effort sends and requeues (RequeueId, not Result, driver.rs:1391-1722) and a payload-shape validation (`let _request`, operations.rs:2093); both error enums (ProcessEffectError, ProcessDriverErrorKind) are closed with stable codes and no caller string-matching. - -## serde -- clean: seeds ran (18 total): the crate derives no Serialize/Deserialize types of its own; all serde use is boundary deserialization of wire specs (`ResourceSpec`, `ProcessSpec`, `EphemeralProcessSpec`, `VolumeBindingSpec`, `VolumeSpec`) with errors mapped to typed failures (driver.rs:884-911, operations.rs:425-459), plus best-effort metadata reads. No hand-written `Deserialize` impls, no `rename_all`/`deny_unknown_fields`/`flatten` decisions to judge on crate-owned types. - -## obs -- clean: seeds ran (8/0/0/8): all eight `tracing::warn!` events carry named fields (`resource`, `provider`, `operation`, `error`, `restart_count`) with static messages (driver.rs:1046, 1183, 1248, 1552, 1759, 1809, 1871, 1894); zero `println!`/`eprintln!`; no interpolated-message-only events; error chains logged once at the handling boundary (`map_provider_error`, driver.rs:1893-1898). - -## docs -- d2b-provider-process#4 sev=low blast=leaf effort=L verdict=actionable - no `# Errors` or `# Panics` canonical sections exist on any of the crate's 142 Result-returning items, so the failure contract of the public surface is prose-only - fix: add `# Errors` sections naming the closed codes to the public Result-returning items, starting with `ProcessEffectBackend::launch` (which closed codes each operation can raise) and `resolve_launch_identity` (which `LaunchIdentityError` variants are possible) - [packages/d2b-provider-process/src/backend.rs:256, packages/d2b-provider-process/src/launch_identity.rs:64] - evidence: seed 2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed 3 `-> Result<` = 142 hits; `#![deny(missing_docs)]` (lib.rs) means every item is documented, the gap is section shape only. -- clean: seeds ran (119/0/142): module docs present in all 12 modules, first sentences carry the load, magic values documented with the why (e.g. `PROCESS_RESYNC` 5s cadence, driver.rs:99-102); no doctests exist and none are marked `ignore`. - -## perf -- clean: seeds ran (78/24/27): every `format!` hit is an error-detail string, a one-shot diagnostic, or a per-operation path construction (cold; the recorded false-positive class); every `Vec::new()` is an empty-case struct field, an empty fd vector, or a test fixture; `to_string()` sits at wire-rendering and Display boundaries. No `format!` in any loop, no grow-by-push collection, no attacker-keyed hashing. static (unmeasured). - -## conc -- d2b-provider-process#5 sev=medium blast=leaf effort=S verdict=policy-confirmed - production `parking_lot::Mutex` fields in `EphemeralRuntime` (`started_at`, `completed`) are a live use of a banned primitive with no per-site allow, and the lock calls run on the actor's executor thread - fix: switch the two fields to `tokio::sync::Mutex` (the already-named replacement) or `std::sync::Mutex` with the same short critical sections; requires the parking_lot ban carve-out to be re-opened otherwise - [packages/d2b-provider-process/src/driver.rs:680, packages/d2b-provider-process/src/driver.rs:682] - evidence: seed 2 `\bMutex<` = 2 production hits (of 36 conc hits; the rest are test doubles and test-support); policy: clippy.toml:40-43 ("parking_lot is banned outright (plan KD3); the U33 short-lock carve-out is revoked") and clippy.toml:82 (replacement `tokio::sync::Mutex::lock`); no `#[allow(clippy::disallowed_methods)]` at the site, and the sanctioned-reason list (U1 d.4) does not cover it. -- d2b-provider-process#6 sev=low blast=leaf effort=S verdict=actionable - `RestartBudget`, `EphemeralRuntime.started`, and `DurableRuntime.watching` use `Ordering::SeqCst` for plain counters and flags that publish no other data, so the strongest ordering buys nothing over `Relaxed` - fix: switch the 16 `Ordering::SeqCst` sites in driver.rs to `Ordering::Relaxed` (no paired acquire/release handoff exists; the actor and the spawned launch task only gate on these flags) - [packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.rs:451, packages/d2b-provider-process/src/driver.rs:458, packages/d2b-provider-process/src/driver.rs:462, packages/d2b-provider-process/src/driver.rs:466, packages/d2b-provider-process/src/driver.rs:470, packages/d2b-provider-process/src/driver.rs:695, packages/d2b-provider-process/src/driver.rs:703, packages/d2b-provider-process/src/driver.rs:732, packages/d2b-provider-process/src/driver.rs:761, packages/d2b-provider-process/src/driver.rs:765, packages/d2b-provider-process/src/driver.rs:772] - evidence: seed 3 `Atomic\w+|Ordering::` = 16 SeqCst sites in driver.rs (of 36 conc hits); no `unsafe impl Send/Sync`, no `thread_local!`, no `std::thread` usage in the crate. - -## async -- clean: seeds ran (444/3/0/25): the three `tokio::spawn` sites (driver.rs:1232, 1795, 2507) pre-capture everything (`spec.clone()`, `identity.clone()`, `Arc::clone`) before the `'static` move and complete through a oneshot whose failed send is harmless when the actor is gone; no blocking call sits in an async context (the async-gate markers on test-support recorder locks are deliberate exceptions, driver.rs:2426-2437, test_support.rs:227-355); no guard is held across an `.await`; tests use `start_paused = true` for deterministic time. No `spawn_blocking`, `JoinSet`, `select!`, or `tokio::sync::Mutex` in the crate. - -## unsafe -- N/A (seeds: 0/0/0/0 - the single `from_raw` match is rustix's safe `Pid::from_raw` constructor, a seed false positive; no `unsafe` blocks, fns, impls, or `// SAFETY:` comments; the manifest forbids `unsafe_code`) - -## ffi -- N/A (seeds: 0/0/0/0 - no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString` anywhere in the crate) - -## macro -- N/A (seeds: 0/0/0/0 - no `macro_rules!`, proc-macro, `$crate`, or `to_compile_error` usage) - -## test -- clean: seeds ran (42/283/0/0): 42 tests (25 driver, 9 effects_service, 3 backend, 2 launch_identity, 3 integration) assert behavior with `start_paused` determinism, table-driven cases with per-case failure messages (launch_identity.rs:213-395), error-code assertions that pin the stable wire codes rather than incidental Display text (driver.rs:2936, 3051-3061), and integration tests through the public registry surface (tests/process_family.rs). No `#[ignore]`, no property/snapshot tooling (no rule-shaped surface needs it), no network or clock reads, no test that cannot fail. - -## Coverage -- idiom: clean (seeds ran: 1/1/0) -- own: 2 findings (seeds: 123/150/1/0; all 273 hits inspected) -- type: clean (seeds ran: 5/0/0) -- api: clean (seeds ran: 135/3/15) -- err: 1 finding (seeds: 185/14/8/2) -- serde: clean (seeds ran: 18 total) -- obs: clean (seeds ran: 8/0/0/8) -- docs: 1 finding (seeds: 119/0/142) -- perf: clean (seeds ran: 78/24/27) -- conc: 2 findings (seeds: 0/4/16/0) -- async: clean (seeds ran: 444/3/0/25) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe blocks or unsafe_code allow) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 42/283/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md deleted file mode 100644 index c1c1432cb..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-provider.md +++ /dev/null @@ -1,81 +0,0 @@ -# d2b-provider-provider - d2b-provider-provider -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2280 (excl. src/generated/**) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- clean: seeds ran 0/1/1 - the hand-written `Default for ProviderDriverFactory` (driver.rs:229) is not derivable (fields carry no `Default`) and the `Vec::new()` accumulation loop (driver.rs:485) has early exits and `?` the skill's plain-for exception covers; no index loops, no ad-hoc converters (clone sites are judged under `own`) - -## own -- d2b-provider-provider#1 sev=low blast=leaf effort=S verdict=actionable - `let zone = ctx.key().zone.clone()` clones a `String` the callee accepts as `impl Into` in three spots - fix: pass `ctx.key().zone.as_str()` / `view.key.zone.as_str()` directly; drop the `zone` local in the fixed-provider branch - [src/driver.rs:355, src/driver.rs:478, src/driver.rs:522] - evidence: own seed 1 `\.clone\(\)` = 15 lines; `ZoneId::parse` takes `impl Into` (d2b-contracts-resource/src/v3/identity.rs:79) and `ResourceKey::new` takes `impl Into` (d2b-resource-runtime/src/spec_store.rs:61), so `&str` compiles without the clone -- d2b-provider-provider#2 sev=low blast=leaf effort=S verdict=actionable - `ctx.status::().cloned()` deep-clones the whole in-memory status (incl. the `BTreeSet` volume_refs) on every reconcile pass - fix: hold the `Option<&ProviderDriverStatus>` reference (`ctx.status()` returns `Option<&T>`, d2b-resource-runtime/src/context.rs:459); last read of `previous` precedes `ctx.set_status` - [src/driver.rs:360, src/driver.rs:435] - evidence: own seed 1 `\.clone\(\)` = 15 lines; the test helper's clone (driver.rs:1066) is required, this site is not -- clean: seeds ran 15/9/0/0 - remaining clones are required by signatures (`classify_error` trait shape, `CoreResourceKey::new`/`with_owner_identity` owned args, `metadata.insert` owned keys, `spec_object` returning owned `Value` from a `&Value` decode) or are test fixtures; no `Rc`/`RefCell`/`Arc`/`Cow` in production code - -## type -- clean: seeds ran 1/0/0 - the single hit (`fn validate_refuses_a_spec_that_is_not_an_object`, driver.rs:1074) is a test fn name, not a runtime validation fn; `ProviderObservation`'s eight booleans are independent observed facts feeding one projection (not flag soup), `ProviderIntent`/`ProviderPhase`/`ProviderChildAction` are enums, no stringly-typed state - -## api -- d2b-provider-provider#3 sev=low blast=leaf effort=S verdict=actionable - `ProviderDriverFactory::new()` and its `Default` impl are zero-caller public surface (the doc names "unit fixtures", but the crate's own tests construct via `with_effects`) - fix: delete `new()` and `impl Default` (driver.rs:213-232), or drop them to `pub(crate)` if a fixture wants them - [src/driver.rs:215, src/driver.rs:229] - evidence: census `ProviderDriverFactory` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 0 callers of `new()`/`default()`; d2bd reaches the factory only through `provider_descriptor` (d2bd/src/resource_plane_v3.rs:144) -- d2b-provider-provider#4 sev=low blast=leaf effort=S verdict=actionable - `ProviderHandler::plan_external` (and the `ProviderError`/`ProviderChildAction`/`Disable`/`Delete` planning surface it serves) is exported through `pub mod providers` with zero production callers - fix: reduce to `pub(crate)` or delete `plan_external` (providers.rs:121-171) and the `ProviderIntent::Disable`/`Delete` arms of `plan_observed` if the external-provider path is not coming back; keep the surface the driver consumes (`plan_observed` Enable/Update, `plan_system_core`, `provider_observation`, `fixed_system_core_handlers_ready`) - [src/providers.rs:121, src/lib.rs:19] - evidence: census `ProviderHandler|plan_external` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 0 production callers; only the crate's own tests exercise it (providers.rs:688, 710, 728); the driver passes only Enable/Update intents (driver.rs:361-365) -- clean: seeds ran 35/3/1 - the `Arc` in `ProviderDriverArgs`/factory/driver is genuine shared ownership (factory clones the Arc per created driver, driver.rs:243); `pub use` re-export arms in lib.rs:31 are the house single-surface pattern; `test_support` is feature-gated; `ProviderPlan` keeps private fields with accessors - -## err -- clean: seeds ran 42/1/0/1 - every `unwrap`/`expect` sits in `#[cfg(test)]` or the `test-support`-gated `RecordingEffects`; the one production `expect` (driver.rs:481) is on a literal const in the same file; `let _ = ctx.requeue_after)...)` (driver.rs:449) is a deliberate fire-and-forget requeue; `ProviderError` is a closed taxonomy with a `code()` accessor and `Display` = code; `CoreReconcileError` is logged at its site before being mapped to `spec_invalid` - -## serde -- clean: seeds ran 0/0/0/15 - no derives, no serde attributes, no hand-written `Deserialize`; all 15 hits are `serde_json::from_/to_` on untyped `Value` (the core types' deliberate spec-envelope shape), and the object fence runs at both validate and reconcile (`spec_object`, driver.rs:575-601) - -## obs -- clean: seeds ran 0/0/0/5 - all five events (`tracing::debug!`/`tracing::warn!`, providers.rs:281/348/370/412/463) carry named fields (`resource = ...`, `reason = %error`) with a plain message, no interpolation, no secrets, no `println!`; levels match handled-vs-attention semantics - -## docs -- d2b-provider-provider#5 sev=low blast=leaf effort=S verdict=actionable - the eight `pub` fields of `ProviderObservation` are undocumented while every other pub item in the crate carries a doc comment - fix: add one-line field docs (or a struct-level contract explaining each gate) at providers.rs:72-79 - [src/providers.rs:72, src/providers.rs:79] - evidence: docs seed 1 `^\s*pub (fn|struct|enum|trait|const|type)` = 34 hits; ProviderObservation is the only pub struct whose pub fields lack `///` -- d2b-provider-provider#6 sev=low blast=leaf effort=S verdict=actionable - the three pub `Result`-returning functions (`plan_external`, `plan_observed`, `provider_observation`) have no `# Errors` section naming which condition produces which failure - fix: add `# Errors` sections enumerating the `ProviderError`/`CoreReconcileError` variants each fn returns - [src/providers.rs:121, src/providers.rs:179, src/providers.rs:406] - evidence: docs seed 3 `-> Result<` = 10 hits; the three pub fns are the ones the skill's `# Errors` trigger names -- d2b-provider-provider#7 sev=low blast=leaf effort=S verdict=actionable - README "State and telemetry" claims "the driver keeps no in-memory status either", but `reconcile_provider` publishes `ProviderDriverStatus` via `ctx.set_status` every pass - fix: correct README.md:72-74 to say the status is in-memory only (R11, never persisted) - [README.md:72, src/driver.rs:435] - evidence: static; README.md:72-74 vs driver.rs:435-441 (`ctx.set_status(ProviderDriverStatus { ... })`); README is a policy-required path (packages/xtask/src/provider_crate_policy.rs) so the text must be fixed, not the path removed -- clean: seeds ran 34/0/10 - module docs present in all four files; every other pub item has a one-line first sentence; no `ignore`d doctests, no magic values without the why - -## perf -- clean: seeds ran 3/8/4 - `format!` at driver.rs:521/606 is per-reconcile on a cold path (static, unmeasured); `to_string()` hits are error-path notes; `Vec::new()` sites are small per-pass collections; no hot loop, no attacker-keyed hashing, no benchmark exists to claim anything stronger - -## conc -- clean: seeds ran 0/5/6/0 - all `Mutex`/`AtomicBool`/`Ordering::SeqCst` hits are the `RecordingManager`/`RecordingEffects` test fakes (test-only synchronization); no threads, no `thread_local!`, no manual `Send`/`Sync`; the test-fake lock sites carry `async-gate-allow` markers (deliberate, cited not re-flagged) - -## async -- clean: seeds ran 62/0/0/10 - production async (validate/recover/reconcile/finalize/delete/dependencies/drain_owned_children) has no `tokio::spawn`, no `spawn_blocking`, no blocking calls on the executor, no guard held across `.await`; `#[async_trait]` is the skill-sanctioned object-safe choice; the 10 `#[tokio::test]` harnesses are deterministic fakes (scripted manager, no sleeps) - -## unsafe -- N/A (seeds: 0/0/0/0 all zero; manifest `unsafe_code = "forbid"`, no blocks/fns/impls, no `SAFETY:` sites) - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no extern surface, no repr, no CStr) - -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro surface) - -## test -- d2b-provider-provider#8 sev=medium blast=leaf effort=S verdict=actionable - the `Degraded` phase projection (`optional_components_degraded` -> `ProviderPhase::Degraded` in `plan_observed`) is production-reachable through the driver's Enable/Update intents and has no test - fix: add a `#[tokio::test]` (or `#[test]` on `plan_observed` directly) that sets `optional_components_degraded = true` with ready dependencies and asserts `phase == Degraded` and `publish_exports` stays true - [src/providers.rs:206, src/driver.rs:1147] - evidence: test seeds = 74 hits (17 test fns, 57 assertions); no test sets `optional_components_degraded = true` - the existing observation assertions pin it `false` (driver.rs:1151) and the plan tests cover Ready/Pending/TrustOrCompatibilityDenied only -- clean: seeds ran 17/57/0/0 - tests assert behavior (phase transitions, call order, error variants via `matches!`, wire codes via `kind().code()`), not implementation; no `#[ignore]`, no network, no sleeps, no proptest/insta/rstest; the registration suite pins the declaration contract through the real `ProviderDirectory` - -## Coverage -- idiom: clean (seeds: 0/1/1) -- own: 2 finding(s) -- type: clean (seeds: 1/0/0; single hit is a test fn name) -- api: 2 finding(s) -- err: clean (seeds: 42/1/0/1) -- serde: clean (seeds: 0/0/0/15) -- obs: clean (seeds: 0/0/0/5) -- docs: 3 finding(s) -- perf: clean (seeds: 3/8/4) -- conc: clean (seeds: 0/5/6/0) -- async: clean (seeds: 62/0/0/10) -- unsafe: N/A (seeds: 0/0/0/0 all zero; manifest `unsafe_code = "forbid"`) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md deleted file mode 100644 index 625762058..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-shell-terminal.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-provider-shell-terminal - d2b-provider-shell-terminal -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4176 (excl. src/generated/**; none present) | modules: whole crate (src: lib, authz, guest_rules, host_rules, migration, observability, resources/{mod,pool,session}, service/{mod,controller,supervisor}, session/{mod,ring,adopt}; tests: 10 files) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: one (whole crate) - -## idiom -- clean: seeds `for \w+ in 0\.\.` 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` 0, `let mut \w+ = (String|Vec)::new\(\)` 0 (all zero; no index loops, no hand-written derive-replaceable impls (the redacted Debug impls are deliberate and not matcheable by the seed), no statement-style accumulation). - -## own -- d2b-provider-shell-terminal#1 sev=low blast=leaf effort=S verdict=actionable - `advance_session` clones the whole `Option` only to end the first `session_mut` borrow before the retired-identity check; the check can compare the live field inside a scoped block instead. - fix: in `ShellAuthorityLedger::advance_session`, wrap the first `session_mut` borrow in `{ ... }` and compare `entry.supervisor_identity.as_ref() != retired_identity` inside it, dropping `let current_identity` and `.clone()`; keep the second borrow for minting and mutation. - [src/service/supervisor.rs:599, src/service/supervisor.rs:601] - evidence: `\.clone\(\)` ~20 hits checked (fingerprint snapshots, capability/attachment accessor hand-offs, Arc clones at the genuinely-shared authority port, resource-map key copies, pool-entry inserts - all own required state except this one) -- clean: seeds `\.clone\(\)` ~20 hits, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` ~16 hits, `Rc<|RefCell<|Arc` signature (`ShellTerminalController::new`, src/service/controller.rs:124, is genuinely shared ownership: the controller stores it, hands clones to every `OpenSessionResult`/`SessionSupervisor` (src/service/controller.rs:99, src/service/controller.rs:426, src/service/supervisor.rs:1104);`pub use` arms in `lib.rs:20-37` are the house single-surface pattern under private module trees;`InMemoryShellAuthority` is kept per the refusal ledger (docs/explanation/over-engineering-audit-record.md:354) - real behavior with live coverage, not re-flagged. - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(` 4, `let _ = |\.ok\(\);` 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` 0, `enum \w*Error` 1; the 4 expects are on validated/static values naming the invariant (`ResourceRef::parse` on a `validate_name`-checked session name, src/service/supervisor.rs:228;`BoundedToken::parse("shell-supervisor-main")` literal, :234; re-checked `ExecutionSpec::new`,:244; ring capacity re-checked against the same bounds `PoolSpec::new` enforces, :1101);`ShellTerminalError` is a closed 14-variant enum split by caller action with wire-style Display codes; no panics, no swallowed Results in src. - - - -## serde -- N/A (seeds: `derive\([^)]*(De)?[Ss]erialize` 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` 0, `impl .*Deserialize.*for` 0,, `serde_json::from_|serde_json::to_` 0; no serde dependency in Cargo.toml and no wire format crosses this crate). - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` 0, `(info|debug|warn|error|trace)!\("` 0,, `\.instrument\(|#\[instrument` 0,, `tracing::|log::` 2; every `warn!`/`debug!` event (in src/service/controller.rs and src/service/supervisor.rs) carries named fields (`provider`, `pool`, `session`, `error`, `decision`, `expected`, `actual`) with template messages and no secrets in fields (the redacting `Debug` impls keep session/canary values out of renders); no `println!` in this library. - - - -## docs -- d2b-provider-shell-terminal#2 sev=medium blast=leaf effort=M verdict=actionable - the ~30 `pub fn` items returning `Result<_, ShellTerminalError>` (e.g. `Authorizer::authorize_request`, `OpenSessionRequest::new`, `PoolSpec::new`, `ShellSession::from_pool`, `restore_pool`, `reconcile_pool_attachments`, `restore_session`, `restart_supervisor`, `open_session`, `finalize_session`, `AttachRequest::new`, `OutputRing::new`, `SupervisorIdentity::new`, `ShellAuthorityLedger::validate_session`) lack an `# Errors` section naming which variants they emit. - fix: add an `# Errors` section to each Result-returning pub item enumerating the `ShellTerminalError` variants that item can return (e.g. `restore_pool`: `# Errors` `CapacityExceeded` when pool name already projected or the authority rejects the restore). - [src/authz.rs:76, src/service/controller.rs:134, src/service/supervisor.rs:88, src/session/ring.rs:16] - evidence: docs seeds: `^\s*pub (fn|struct|enum|trait|const|type)` ~100 hits (every item carries a contract-shaped first sentence; `#![deny(missing_docs)]` at src/lib.rs:9), `/// # (Examples|Errors|Panics|Safety)` 0, `-> Result<` ~30 hits -- clean: seeds pub items ~100 (fully documented first sentences; all 8 modules carry `//!` docs;, first sentences are contract-shaped ), not implementation narration), no `ignore`d doctests exist to rot;; magic values (`SHELL_REPAIR_INTERVAL_SECS`, capacity bounds) carry meaning-comments; the only systematic gap is the missing `# Errors` class above. - -## perf -- clean: seeds `format!\(` 5, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` 5, `\.to_string\(\)` 0; the format sites are one-shot resource-ref/name builders in cold construction paths (`src/resources/session.rs:89-93`, `src/service/controller.rs:380`, `src/service/supervisor.rs:227`), the empty `Vec::new`/`BTreeMap::new` are fresh collection initializers where the empty case is common; no hot-loop allocation sites, no benchmark exists - static (unmeasured) reading only (`OutputRing::append` per-byte push is O(1) amortized and bounded by the 1 MiB ring). - - - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` 0,, `\bMutex<|\bRwLock<` 2, `Atomic\w+|Ordering::` 1 (the word "Atomically" in a doc comment - false positive), `thread_local!|unsafe impl (Send|Sync) for` 0; both `tokio::sync::Mutex` holders (`ShellAuthorityLedger.state` src/service/supervisor.rs:401, `InMemoryShellAuthority.supervisor_processes`, :866) are synchronous surfaces used with `try_lock` fail-closed per a written design comment (src/service/supervisor.rs:410-413); no threads, no atomics, no manual `Send`/`Sync` claims in this crate. - - - -## async -- clean: seeds `async fn|async move|\.await` 0,, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` 0,, `tokio::sync::(Mutex|RwLock|Notify)` 2 (the two synchronous try_lock Mutexes noted under conc;, `#\[tokio::(main|test)\]|Runtime::block_on` 0; no async fn exists anywhere in src - no `.await`, no spawns, no guards across await points (tokio dep is sync-feature-only). - - - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` 0,, `// SAFETY:` 0,, `transmute|from_raw|MaybeUninit|mem::zeroed` 0; manifest `[lints.rust]` sets `unsafe_code = "forbid"` - no blocks, no exception sites). - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` 0,, `catch_unwind` 0,, `repr\(C\)|repr\(transparent\)` 0,, `CStr|CString|c_char` 0; no foreign boundary in this crate). - - - -## macro -- N/A (seeds: `macro_rules!` 0,, `proc_macro|syn::|quote!` 0,, `\$crate` 0,, `to_compile_error|new_spanned` 0; no macro definitions, no proc-macro machinery). - -## test -- d2b-provider-shell-terminal#3 sev=low blast=leaf effort=S verdict=actionable - `tests/supervisor_runtime.rs` repeats the full 14-line `ShellPool::new(PoolSpec::new)...))` fixture in 7 of its tests, while sibling `tests/controller_reconcile.rs:8` already defines a `pool()` helper. - fix: extract a parameterized `fn pool(max_sessions: u32, max_attached: u32) -> ShellPool` helper at the top of `tests/supervisor_runtime.rs` (or a shared `tests/common/mod.rs` used by both files), replacing the 7 inline constructions. - [tests/supervisor_runtime.rs:17, tests/supervisor_runtime.rs:81, tests/supervisor_runtime.rs:142, tests/supervisor_runtime.rs:193, tests/supervisor_runtime.rs:255, tests/supervisor_runtime.rs:320, tests/supervisor_runtime.rs:367] - evidence: test seeds over tests/: `#\[test\]|#\[tokio::test\]` 34, `assert_eq!\(|assert_ne!\(|assert!\(` ~108 hitting lines (matrix cell 142 = 34 + ~108);`proptest!|insta::assert|rstest` 0,, `#\[ignore\]` 0; over src/: 0/0/0/0 (no unit tests in src); the inline fixture repeats 7 times. -- clean: seeds 34 integration tests + ~108 assertions; all deterministic (no network, no clock, no ignored stress tests), error variants asserted via `matches!`/`assert_eq!` against enum variants and never Display strings, redaction tests assert distinct canaries are absent from every `Debug` render, capacity, capability-reuse, recovery-adoption,, attachment-slot edges are covered by named behavior tests; the two large files use local fixture helpers except for the copy-paste class above. - - - -## Coverage -- idiom: clean (seeds 0/0/0 -- own: 1 finding(s) -- type: clean (seeds 7/0/0 -- api: clean (seeds ~160/1/14; Arc-in-signature shared-ownership judged explainable -- err: clean (seeds 4/0/0/1; all 4 expects are invariant-naming on validated values -- serde: N/A (seeds 0/0/0/0; no serde dep -- obs: clean (seeds 0/0/0/2; all events carry named fields -- docs: 1 finding(s) -- perf: clean (seeds 5/5/0; cold paths only -- conc: clean (seeds 0/2/1/0;2 Mutexes deliberate try_lock, 1 doc-word false positive -- async: clean (seeds 0/0/2/0; sync-only Mutex use -- unsafe: N/A (seeds 0/0/0; manifest forbid -- ffi: N/A (seeds 0/0/0/0 -- macro: N/A (seeds 0/0/0/0 -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md deleted file mode 100644 index 5e43f4fda..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-supervisor.md +++ /dev/null @@ -1,65 +0,0 @@ -# d2b-provider-supervisor - d2b-provider-supervisor -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6140 (src 5098 + tests 1042, excl. src/generated/**, none present) | modules: whole crate (adapter, broker, systemd) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-supervisor#1 sev=low blast=leaf effort=S verdict=actionable - systemd.rs stop() holds a no-op statement `let _ = &handle.pidfd;` that creates and immediately drops a temporary reference, doing nothing - fix: delete the line (the pidfd field is already used by wait/finalize and the retained handle) - [packages/d2b-provider-supervisor/src/systemd.rs:840] - evidence: seed `for \w+ in 0\.\.` = 4 (all test loops), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; dead statement found while reading the own seed-2 hits -- d2b-provider-supervisor#2 sev=low blast=leaf effort=S verdict=actionable - the bounded pending-observation ledger is copy-pasted twice: `BrokerProcessBackend::{record,take_observation}` and `SystemdProcessBackend::{record,take_observation}` are the same shape (Mutex, evict-oldest at MAX_PENDING_OBSERVATIONS=1024, poisoned-lock to ObserveFailed) - fix: extract one shared bounded-ledger helper and have both backends use it - [packages/d2b-provider-supervisor/src/broker.rs:1104-1130, packages/d2b-provider-supervisor/src/systemd.rs:240-280] - evidence: refusals ledger row 62 (`deferred for a single writer`, not-applied); both ledgers still present at 6ebdd4cec, site matches the row; seed `let mut \w+ = (String|Vec)::new\(\)` = 0 -- clean: idiom seeds ran (4/0/0); index loops only in test loops, no hand-written derives, no statement-style accumulation; hand-written redacting `Debug` impls (BrokerLaunchIntent adapter/provider surfaces, adapter.rs:424-428) are deliberate and pinned by redaction tests -## own -- clean: own seeds ran (clones 21/64/24, to_owned/to_vec/to_string 2/22/4, Rc/RefCell/Arc/Arc/Cow 1/0/0 per file); every clone inspected is explainable - Waker clone at JobFuture::poll (own the waker, adapter.rs:350), Arc clones at thread-spawn boundaries (worker/deadline worker), wire-payload clones building new per-request values (typed_identity_request! projections), test fixtures; the single Arc>> is the R4 bounded-worker admission queue (sanctioned, per-site allow at adapter.rs:219) -## type -- clean: type seeds ran (1/0/0); the sole hit `BrokerObservedProcess::{validate,validate_launch}` (broker.rs:225-233) is boundary validation of freshly broker-observed values, not repeated validate-at-callsite of one value; `typed_identity`/`cgroup_verified`/`executable_verified`/`multi_instance`/`accepts_launch_args` booleans each mirror distinct wire/source truth and are consumed independently, not flag soup -## api -- d2b-provider-supervisor#3 sev=medium blast=leaf effort=S verdict=actionable - `BrokerProcessBackend::set_launched_observer` takes `Arc` in a public signature although single ownership suffices: the one caller (d2bd/src/process_provider_runtime.rs:913) hands over a fresh `Arc::new)...)` and retains nothing, so the Arc is a forced refcount, not shared ownership - fix: take `Box` or `impl LaunchedObserver + Send + Sync + 'static`, drop the Arc at the call site - [packages/d2b-provider-supervisor/src/broker.rs:997, packages/d2bd/src/process_provider_runtime.rs:913] - evidence: census `set_launched_observer` over packages/ = 2 hits (definition + single call site); the observer only ever lives in `Option>` inside the backend -- d2b-provider-supervisor#4 sev=medium blast=family effort=M verdict=actionable - `LaunchedObserver::launched` takes five positional parameters (vm, role, pid, start_time_ticks, pidfd) and `BrokerProcessBackend::launched_runner_snapshot` returns `Option<(String, String, i32, u64, OwnedFd)>`, a 5-tuple whose shape is pinned by the upstream `ProcessEffectBackend` trait (which carries its own `#[allow(clippy::type_complexity)]`) - fix: introduce a `LaunchedSnapshot` struct (or a small `LaunchedProcessRef`) and change `launched_runner_snapshot`'s default + the observer method to carry it, updating the implementor in d2bd - [packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/src/broker.rs:1524-1546, packages/d2b-provider-process/src/backend.rs:315-319] - evidence: census `LaunchedObserver|set_launched_observer` over packages/ = 9 hits (trait def, backend impl, d2bd implementor + call sites); the tuple is the trait-level wire-in-process shape, not a wire format, so the change is actionable across the provider family -- clean: api seeds ran (pub fn/struct/enum/trait/const/type 29, Arc/Rc/Box/RefCell in pub sig 1 [flagged #3], `pub use` arms 8); lib.rs re-export arms are the house single-surface pattern; `BrokerLaunchIntent`/`BrokerObservedProcess`/`SystemdInvocationIdentity`/`SystemdEffectLaunch` pub structs with documented pub fields are data carriers of the resolver/owner contract (not flagged) -## err -- d2b-provider-supervisor#5 sev=medium blast=leaf effort=S verdict=actionable - `ProviderSupervisor::with_limits` (the public constructor knob) panics with `assert!` on caller-provided `blocking_limit == 0` and zero `default_timeout` instead of returning a `Result` - a library panic on caller input, reachable from any future caller passing a computed bound - fix: return `Result` (or clamp and document) and have the single current construction sites handle it - [packages/d2b-provider-supervisor/src/adapter.rs:419-421] - evidence: err seed 1 `.unwrap\(\)|.expect\(` = 131 (non-test only adapter.rs:58/74/102/177, all startup/invariant expects); the `assert!` pair is the only panic-on-caller-input site in src -- d2b-provider-supervisor#6 sev=low blast=leaf effort=S verdict=actionable - `map_error` folds any currently-unknown `ProcessEffectError` variant into `LaunchFailed` via a `_` catch-all arm, so a new upstream variant (d2b-provider-process) fails at runtime instead of at compile time - fix: make the match exhaustive over the closed variant set (drop `_`), keeping the current mappings - [packages/d2b-provider-supervisor/src/adapter.rs:888-890] - evidence: err seed 3 `panic!\(|unreachable!\(|todo!\(|unimplemented!\(` = 4 (three test-backend `unreachable!` at adapter.rs:1344/1367/1375 + one invariant panic on a `matches!`-guarded `else` at broker.rs:1832, all legitimate); seed 4 `enum \w*Error` = 0 (errors come from d2b-provider-process) -## serde -- d2b-provider-supervisor#7 sev=medium blast=leaf effort=L verdict=needs-contract - `take_controller_bootstrap` is the one wire leg not using a typed d2b-contracts-broker request/response: it hand-builds the payload with `serde_json::json!` (camelCase string keys), reads the reply via `.get("taken")`/`as_bool` with a silent `unwrap_or(false)` (a malformed reply reads as "not taken" -> `Ok(None)`), and reuses hard-coded fd index 0 - fix: add a typed `TakeControllerBootstrapRequest/Response` to the broker wire contract (the operation row currently carries `wire_variant: None`) and parse/reply through it like every sibling leg - [packages/d2b-provider-supervisor/src/broker.rs:1563-1603, packages/d2b-broker/src/generated/broker_operation_catalog.rs:1289] - evidence: serde seeds = 24, all `serde_json::{to_value,from_value}` at the envelope boundary; seeds 1/3 (derive / hand-written Deserialize) = 0; every other leg uses `typed_identity_request!` with typed request/response types - the loose leg is the exception -## obs -- clean: obs seeds ran (3/0/0/3); the 3 hits are `use tracing::{debug,error,warn}` imports only - no `println!`/`eprintln!` in src, no interpolated-field events, no `.instrument`; every traced event carries the `provider = "supervisor"` field (or `error = ?e`/`pid`/`identity` named fields) and message-only warnings are span-backed; no secret or identifier reaches a log field (identity digest values are hex digests, never raw proc/identity material; redaction is structurally enforced by the redacting Debug impls) -## docs -- d2b-provider-supervisor#8 sev=medium blast=leaf effort=M verdict=actionable - despite `#![deny(missing_docs)]`, no public `-> Result` item states its failure conditions in a `# Errors` section and no panicking item carries `# Panics` - `SystemdInvocationIdentity::new`, `ProviderSupervisor::{launch,observe,probe,open_pidfd,stop,finalize_identity,matches_peer_process}`, `BundleBackedLaunchResolver::{new,with_observation_socket}` document conditions only in prose, and `with_limits` panics without a `# Panics` note - fix: add `# Errors` (and `# Panics` on with_limits) sections to the public Result/panicking items - [packages/d2b-provider-supervisor/src/lib.rs:5, packages/d2b-provider-supervisor/src/adapter.rs:419-421, packages/d2b-provider-supervisor/src/systemd.rs:55-70] - evidence: docs seeds ran (pub items 29, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 101); deny(missing_docs) forces prose but the canonical sections are absent crate-wide -## perf -- clean: perf seeds ran (format! 17 / Vec::new 18 / to_string 5); every hit is a cold path - `format!` in error/wire-rendering and test fixture helpers, `Vec::new()` for empty one-shot wire fields (`runtime_allocations`, `inherited_fds`) and test setup, `to_string()` at snapshot/wire boundaries (`launched_runner_snapshot`, `take_controller_bootstrap` payload); no allocation in a hot loop (the deadline worker's `Vec` sort is bounded by the queue cap of 2x limit); perf evidence static (unmeasured) - no benchmark exists -## conc -- clean: conc seeds ran (std::thread 16 / Mutex 10 / Atomic 49 / thread_local+unsafe impl 0); the threads + `Arc>` workers + `AtomicBool` completion flags are the hand-rolled blocking executor recorded as a refused policy item (docs/explanation/over-engineering-audit-record.md row 53 - "src/adapter.rs keeps the executor"), so no executor finding is re-filed; no new evidence at 6ebdd4cec - atomic orderings are correct publish/observe pairs (`AcqRel`/`Acquire` on JobState), the mutex guards are short and never cross a suspension, and the test PoolTestGuard serialization is documented -## async -- clean: async seeds ran (async fn/await 41 / tokio::spawn+JoinSet+select 0 / tokio::sync 1 / tokio::main+block_on 0); the AsyncMutex state is taken with `.lock().await` and never held across the blocking submit; blocking work runs on the dedicated R4 workers with `blocking_lock()` inside the sanctioned worker-only boundary (per-site allows cited reason "dedicated bounded worker per plan R4" / "synchronous path"); the executor itself is the refused policy item (row 53), no new evidence; the only async-gate markers are two test-support recorder locks in tests/production_adapter.rs (inventory lines 840/845) -## unsafe -- N/A: unsafe seeds 1-3 all zero over src (unsafe/SAFETY/transmute/from_raw/MaybeUninit/zeroed = 0); manifest carries `unsafe_code = "forbid"` (Cargo.toml), lens not applicable -## ffi -- N/A: ffi seeds all zero (extern "C"/no_mangle/link_section, catch_unwind, repr(C)/repr(transparent), CStr/CString/c_char = 0); pidfd + SCM_RIGHTS usage (envelope fds, reply_take_fd, poll-based pidfd wait) is fd passing, not a foreign-language boundary -## macro -- clean: macro seeds ran (1/0/0/0); the single hit `typed_identity_request!` (broker.rs:151-168) is a justified impl-per-type boilerplate eliminator over the 9-field typed-identity projection injected into six wire request structs - `tt` fragment is the right specifier for struct-literal injection, the projection accessors stay single-sourced, and the macro carries a doc comment; no proc-macro, no `$crate` need (same crate), no hygiene hazard (the `let wire_intent` local collides with no field) -## test -- d2b-provider-supervisor#9 sev=low blast=leaf effort=S verdict=policy-confirmed - `open_pidfd_dispatch_failure_is_ambiguous_only_after_identity_drift` pins the cross-crate broker error-kind contract by scraping source text (`include_str!("../../d2b-broker/src/live_handlers.rs")` + `LIVE_HANDLER_SOURCE.contains("PidfdRace")`) with the expected names duplicated as literals - brittle against broker renames, but the identical fix (a shared typed error-kind constant) was refused for this exact site because no exported constant exists and d2b-contracts-broker is out of lane - fix: none actionable; keep the scrape - [packages/d2b-provider-supervisor/src/broker.rs:2040-2043] - evidence: refusals ledger row 60 refused ("the include_str scrape and cross-crate compile_data stay"); no changed evidence at 6ebdd4cec (live_handlers.rs still emits the three producer-error strings; no exported constant exists) -- clean: test seeds ran over src + tests (#[test]/#[tokio::test] 29, assert 99, proptest/insta/rstest 0, #[ignore] 0); coverage is mechanism-based and behavior-pinning - a real SCM_RIGHTS/SEQPACKET broker loopback (tests/production_adapter.rs:438-718), a heartbeat-cadence proof that blocking never reaches the executor (tests/production_adapter.rs:736-868), fault/reused/wrong-owner matrix, redaction-pin tests, and bounded-ledger tests; no test that cannot fail found; no `#[ignore]` (no documented stress/root-only skips needed) -## Coverage -- idiom: 2 finding(s) -- own: clean (seeds: 109 clones / 28 to_owned+to_vec+to_string / 1 Arc; all explainable) -- type: clean (seeds: 1/0/0; validate() is boundary validation of freshly observed broker data) -- api: 2 finding(s) -- err: 2 finding(s) -- serde: 1 finding(s) -- obs: clean (seeds: 0 println / 0 interpolated events / 0 instrument / 3 tracing imports; structured events, no secret in fields) -- docs: 1 finding(s) -- perf: clean (seeds: 17 format! / 18 collection new / 5 to_string; all cold paths, static (unmeasured)) -- conc: clean (seeds: 16/10/49/0; the executor is the refused policy item row 53, no new evidence) -- async: clean (seeds: 41/0/1/0; AsyncMutex across await is tokio sync, blocking confined to sanctioned R4 workers; executor refused row 53, no new evidence) -- unsafe: N/A (seeds: 0/0/0; `unsafe_code = "forbid"` in manifest) -- ffi: N/A (seeds: 0/0/0/0; fd passing only, no foreign boundary) -- macro: clean (seeds: 1/0/0/0; typed_identity_request! is a justified impl-per-type eliminator) -- test: 1 finding(s) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md deleted file mode 100644 index c86423d7b..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-system-core.md +++ /dev/null @@ -1,83 +0,0 @@ -# d2b-provider-system-core - d2b-provider-system-core -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1810 (excl. src/generated/**, src 1229 + tests 581) | modules: whole crate (error, host, lib, ownership, testing, user) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-system-core#1 sev=low blast=leaf effort=S verdict=actionable - `UserIdentityDigest::to_hex` pushes hex nibbles with `char::from_digit)...).unwrap_or('0')`, a fallback that can never fire (from_digit is total for 0-15 at radix 16) - fix: const `HEX: [char; 16]` table lookup, or `write!(out, "{byte:02x}")` via `std::fmt::Write` which pushes without allocating - [src/user.rs:75, src/user.rs:76] - evidence: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; dead fallback read in to_hex body -- d2b-provider-system-core#2 sev=low blast=leaf effort=S verdict=actionable - `UserReconciler::required_bindings` is an associated fn that never uses `Self`, the shape the naming rule calls a free function - fix: free `required_bindings(spec: &UserSpec)` in user.rs, updating the two test call sites (tests/user_discovery.rs:45, tests/user_discovery.rs:73) - [src/user.rs:232] - evidence: seeds 0/0/0; impl block user.rs:214-298 read, no Self use - -## own -- d2b-provider-system-core#3 sev=low blast=leaf effort=S verdict=actionable - `reconcile_observed` copies `kernel_release`/`os_name` out of a by-value `HostProbeSnapshot` with `to_owned()` where destructuring the owned snapshot moves the Strings - fix: `let HostProbeSnapshot { capabilities, kernel_release, os_name, user_manager_available, minijail_gate, active_process_count } = snapshot;` at the method top and move fields into the report - [src/host.rs:466, src/host.rs:467] - evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 3 (host.rs:378 to_vec is status-owned, fine; 466/467 are the copies) -- clean: seeds `\.clone\(\)` = 4, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 3, `Rc<|RefCell<|Arc64/128-byte strings with `HostProbeFailed`; `MinijailPlatformGate::validate` maps kernel/cgroup failures to two distinct variants) - fix: add `# Errors` sections to validate, HostProbeSnapshot::new, reject_operator_status_fields, reconcile/reconcile_observed/reconcile_with_probe, UserReconciler::reconcile, and the two effect ports' methods - [src/host.rs:121, src/host.rs:161, src/user.rs:241] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 across 74 pub items; seed `-> Result<` = 9 - -## perf -- clean: seeds `format!\(` = 0, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 0, `\.to_string\(\)` = 0; the only allocation site (to_hex, 64-byte String) is a cold serialization path - -## conc -- d2b-provider-system-core#10 sev=low blast=leaf effort=S verdict=actionable - `ScriptedDiscoveryPort.calls: Mutex` (testing.rs:43) uses a tokio::sync::Mutex for a counter - the crate's only tokio use - and `call_count` (testing.rs:79) silently reports 0 on contention via try_lock - fix: `AtomicU32` with `fetch_add`/`load` (Relaxed) and drop `tokio = { workspace = true, features = ["sync"] }` from Cargo.toml - [src/testing.rs:43, src/testing.rs:79] - evidence: seed `\bMutex<|\bRwLock<` = 1 (testing.rs:43); `tokio::` appears only at testing.rs:9 in src/ - -## async -- d2b-provider-system-core#11 sev=low blast=leaf effort=S verdict=actionable - `block_on` (testing.rs:23) busy-spins (`std::hint::spin_loop()`, testing.rs:30) on `Poll::Pending`, so any future that genuinely yields - a contended tokio Mutex, a future test with real I/O - hangs the test process at 100% CPU instead of failing; the doc comment asserts hermiticity but nothing enforces it - fix: `debug_assert!` the never-pending invariant or drive these tests with a real runtime - [src/testing.rs:30, src/testing.rs:19] - evidence: seed `async fn|async move|\.await` = 15 hits; block_on body read (Waker::noop + spin_loop) - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; manifest carries `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 - -## test -- d2b-provider-system-core#12 sev=low blast=leaf effort=S verdict=actionable - tests/host_reconciliation.rs repeats the `Probe` struct literal plus a 5-field `HostProbeMetadata` block five times (lines 204, 230, 254, 280, 306), one field differing per case - fix: a `Probe::new(capabilities, user_manager_available, gate, kernel_release)` constructor or default-and-mutate helper - [tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230] - evidence: seed `#\[test\]|#\[tokio::test\]` = 23 (22 integration + 1 unit), `assert_eq!\(|assert_ne!\(|assert!\(` = 49, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; five Probe constructions read - -## Coverage -- idiom: 2 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 0/0/0) -- api: 5 finding(s) -- err: clean (seeds ran: 10/0/0/1) -- serde: clean (seeds ran: 11) -- obs: clean (seeds ran: 0/0/0/2) -- docs: 1 finding(s) -- perf: clean (seeds ran: 0/0/0) -- conc: 1 finding(s) -- async: 1 finding(s) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md deleted file mode 100644 index 45d3d8f68..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p1.md +++ /dev/null @@ -1,81 +0,0 @@ -# d2b-provider-toolkit-p1 - d2b-provider-toolkit - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6919 (excl. src/generated/**) | modules: base (bootstrap, error, fd10, guest, mod, runtime, startup), plane (creations, handle, mod, reconcile), operations (envelope, mod), audit (mod, redaction), declaration (manifest, mod, schema), bin (d2b-provider-toolkit) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/base/**, src/plane/**, src/operations/**, src/audit/**, src/declaration/**, src/bin/** - -## idiom -- d2b-provider-toolkit-p1#1 sev=medium blast=leaf effort=S verdict=actionable - the 15-operation Guest backend allowlist is spelled out twice: `GuestCredentialBackend::request` inlines the same `matches!` that `valid_guest_backend_operation` already implements, so adding one operation to one list and not the other silently diverges the client and responder admission - fix: have `request` call `valid_guest_backend_operation(&operation)` and delete the inline `matches!` arm - [packages/d2b-provider-toolkit/src/base/fd10.rs:926-941, packages/d2b-provider-toolkit/src/base/fd10.rs:1478-1496] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit; the duplicate list verified by `grep -n 'secret-service.state'` = 2 sites (fd10.rs:928, fd10.rs:1481) with identical 15-entry bodies -- d2b-provider-toolkit-p1#2 sev=low blast=leaf effort=S verdict=actionable - `GuestCredentialBackendResponse` and `GuestCredentialBackendReply` are two public 7-field structs with the same shape (state, lease_handle, source_version, rotation_generation, expires_at_unix_ms, outcome, bytes) and duplicated accessors, both re-exported at the crate root - fix: collapse into one type carrying the accessors plus `encode`/`with_sensitive_bytes`, keeping the zeroizing bytes field - [packages/d2b-provider-toolkit/src/base/fd10.rs:545-597, packages/d2b-provider-toolkit/src/base/fd10.rs:612-700, packages/d2b-provider-toolkit/src/lib.rs:91-92] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 hit; both structs and their accessor blocks read in full (fd10.rs:545-700), field lists identical -- clean: seeds `for \w+ in 0\.\.` = 2 (a bounded reconnect loop and a test loop, both index-appropriate), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1 (manual `Default` for `ProviderAgentAuditLog` preserving the frozen capacity invariant, deliberate), `let mut \w+ = (String|Vec)::new\(\)` = 7 (all cold build/collect loops); hand-written `Debug` impls that redact are the deliberate house pattern - -## own -- d2b-provider-toolkit-p1#3 sev=low blast=leaf effort=S verdict=actionable - `is_ready_for_route` clones the retained route binding out of the mutex guard (`and_then(|ready| ready.clone())`) only to compare it, allocating the binding's strings on every route check - fix: compare through the guard, `try_lock().ok().is_some_and(|ready| ready.as_ref().is_some_and(|bound| bound.liveness().is_live() && bound == route))`, no clone - [packages/d2b-provider-toolkit/src/base/runtime.rs:530-537] - evidence: seed `\.clone\(\)` = 64 hits; this is the only clone in the sync route-query path that borrows instead of owning (the sibling `ready_route()` clone is required to return an owned value) -- clean: 64 clones, 37 `to_owned`/`to_vec`/`to_string`, 4 `Arc>` (the envelope's shared audit ring and the backend state, genuine multi-owner runtime state), 0 `Rc`/`RefCell`/`Cow`; remaining clones are route-metadata snapshots, per-invocation audit records, and test fixtures, each explainable - -## type -- clean: seeds `fn validate_\w+|fn check_\w+` = 5 (all boundary admission checks: route validation, facet validation, manifest installation validation - parse-once at the boundary, correct), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the `ProviderEntrypoint` builder's seven `Option` fields are guarded against double-binding by each `with_*` method and validated at use, within the stopping rule - -## api -- d2b-provider-toolkit-p1#4 sev=medium blast=leaf effort=S verdict=actionable - test-only constructors `GuestCredentialBackend::from_socket_for_test` and `from_socket_for_test_with_route` sit on the public surface (the type is re-exported at the crate root) without the house `test-support` feature gate that `d2b-session` uses for the same class of export - fix: move both behind a `test-support` feature (or `#[doc(hidden)]` + `#[cfg(any(test, feature = "test-support"))]`) so downstream crates cannot rely on them - [packages/d2b-provider-toolkit/src/base/fd10.rs:888, packages/d2b-provider-toolkit/src/base/fd10.rs:901, packages/d2b-provider-toolkit/src/lib.rs:89] - evidence: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits (this site and the deliberate `SharedClock = Arc` alias); census: `from_socket_for_test` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 5 hits, all in test code (d2b-provider-toolkit/tests/supervised_runtime.rs:94,550,642, d2b-provider-credential-secret-service/tests/session.rs:677, d2b-provider-credential-secret-service/src/lib.rs:1942,1958) -- clean: 262 pub items, 2 `Arc`-in-signature hits (one test constructor, one deliberate clock-seam alias), 14 `pub use` re-export arms matching the house single-surface pattern; no dependency types leak into signatures beyond the declared vocabulary re-exports - -## err -- d2b-provider-toolkit-p1#5 sev=medium blast=leaf effort=S verdict=actionable - the refused-forwarded-invocation audit is silently dropped for the documented U10 wire spelling: `invoke_named_with_fds_under_chain` audits the raw caller string, and `audit_named` returns when `BoundedToken::parse` fails, but the forwarded family names are PascalCase (`OpenPidfd`), which the `^[a-z][a-z0-9-]*$` token grammar rejects, so the Denied record the module contract promises for every refused invocation never lands for the uncommitted forwarded path - fix: audit the canonicalized name (lowercase/dash-strip before `BoundedToken::parse`, or audit the resolved entry's `operation.name()` when an entry exists) and add a harness case asserting the PascalCase forwarded spelling records a Denied event - [packages/d2b-provider-toolkit/src/operations/envelope.rs:429-433, packages/d2b-provider-toolkit/src/operations/envelope.rs:495-497, packages/d2b-provider-toolkit/src/operations/envelope.rs:341-346] - evidence: seed `\.unwrap\(\)|\.expect\(` = 105 (all remaining sites are `#[cfg(test)]` or invariant expects on literally-built values); `BoundedToken::parse` grammar at packages/d2b-contracts-resource/src/v3/execution_policy.rs:191; forwarded wire spelling "OpenPidfd" pinned by the envelope's own U10 doc and the committed catalog row at packages/d2b-broker/src/generated/broker_operation_catalog.rs:2632; the harness covers only the lowercase spelling (tests/harness.rs:501-522), so no test exercises the dropped path -- clean: `let _ = |\.ok\(\);` = 4 (deliberate best-effort watch cancels and the cfg(not) discard), `panic!|unreachable!|todo!|unimplemented!` = 0, `enum \w*Error` = 11 (closed code-carrying sets with `code()` + Display, split by caller action); `commit_grant`'s fail-closed `try_write` drop is the documented U4 pattern, not a finding - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 5, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 20, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 13; every wire type carries `deny_unknown_fields` + `rename_all = "camelCase"`, optionality uses `#[serde(default)]` deliberately, `skip_serializing_if = "Option::is_none"` on the reply wire, decode sites validate protocol markers and route binding, and all parse failures map to closed error codes; the hand-written `Drop` zeroizing `CredentialDeliveryKeyWire` is deliberate - -## obs -- d2b-provider-toolkit-p1#6 sev=low blast=leaf effort=S verdict=actionable - `serve_enrolled` drops a base-side wire-contract violation with no event: a frame that fails `GuestFrame::new` (empty or oversized, i.e. a peer protocol violation, not an agent refusal) is `continue`d silently, and the module doc only covers agent refusals as "the agent's to record", so the malformed frame is invisible to the operator - fix: emit a `warn!` with the frame length before dropping, keeping the session up - [packages/d2b-provider-toolkit/src/base/guest.rs:494-498, packages/d2b-provider-toolkit/src/base/guest.rs:446-452] - evidence: seed `\bprintln!\(|\beprintln!\(` = 5 (all process-entrypoint product output, `CLI-only path` allows), interpolated-message seed = 0, `tracing::` = 3; the drop sites read in full at guest.rs:490-499 -- clean: all tracing events use named fields (`warn!(name, provider, expected_zone, ...)`, `debug!(generation, ...)`); the five `println`/`eprintln` sites are CLI/process-entrypoint output, not telemetry - -## docs -- d2b-provider-toolkit-p1#7 sev=low blast=leaf effort=S verdict=actionable - key `Result`-returning public items document no failure conditions: `ProviderEntrypoint::new` (InvalidName), `admit` (NotAccepting), the three `with_*` binders, and `StartupPlan::derive`/`declare` (MissingInput/DuplicateOutput/Cycle) have one-line docs with no `# Errors` section or prose naming the refusal, so callers must read the error enum to learn when construction fails - fix: add `# Errors` sections (or one prose sentence naming the refusal) to the entrypoint constructors and the plan derivation - [packages/d2b-provider-toolkit/src/base/runtime.rs:248-249, packages/d2b-provider-toolkit/src/base/runtime.rs:383-384, packages/d2b-provider-toolkit/src/base/startup.rs:39] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 254, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 105; `#![deny(missing_docs)]` is on (lib.rs:46), so every item has a comment but failure conditions are prose-absent on the named items -- clean: first sentences are strong throughout (no `get_` accessors, no name-echoing openers), module docs present in every module, redaction and non-authorization contracts documented; the zero canonical-section count is house style, only the failure-condition gap is flagged - -## perf -- clean: seeds `format!\(` = 13 (error diagnostics, startup `Provider/{}` refs, invocation-id minting, tests - all cold), `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 13 (bounded build/collect loops; the two receive loops cap at 64 KiB and 4 KiB), `\.to_string\(\)` = 4 (per-request ttrpc metadata values, cold); all sites static (unmeasured), no allocation in a per-packet or per-frame loop - -## conc -- d2b-provider-toolkit-p1#8 sev=low blast=leaf effort=S verdict=actionable - `invocations.fetch_add(1, Ordering::AcqRel)` uses release-acquire for a monotonic counter nobody synchronizes on; the identifier only needs uniqueness, so `Ordering::Relaxed` is the weakest correct ordering - fix: `fetch_add(1, Ordering::Relaxed)` - [packages/d2b-provider-toolkit/src/operations/envelope.rs:487] - evidence: seed `Atomic\w+|Ordering::` = 23; the counter's only reader is the minted id itself (envelope.rs:485-488), no paired load; contrast the load-bearing `admitted`/`lifecycle` atomics in base/runtime.rs, whose AcqRel/Acquire pairing is documented and deliberate -- clean: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 7 (tokio Mutex/RwLock held across awaits, correct choice; the std `Mutex` on the audit ring is documented as the frozen constructor contract), `thread_local!|unsafe impl (Send|Sync) for` = 0; the `admitted` counter, `lifecycle` state machine, and `bound` bind-once flag carry written ordering arguments - -## async -- clean: seeds `async fn|async move|\.await` = 120, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 2 (the credential-backend responder task, cancel-safe via watch channels, and one test spawn), `tokio::sync::(Mutex|RwLock|Notify)` = 5, `#\[tokio::(main|test)\]|Runtime::block_on` = 2 (tests); the drain wait arms the `Notify` before checking the count and bounds with `tokio::time::timeout` (the sanctioned shape), the backend state lock is a tokio Mutex across awaits, `serve_enrolled` uses a biased `select!`, and the three process entrypoints `block_on` on the calling thread with `CLI-only path` allows - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; the manifest sets `unsafe_code = "forbid"` (packages/d2b-provider-toolkit/Cargo.toml:13), and no `unsafe_code` allow exists in the part - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign boundary - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 - -## test -- clean: seeds over src = `#\[test\]|#\[tokio::test\]` = 22, asserts = 65, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; over tests/ = 46 test attrs, 185 asserts, 0 property/snapshot tooling, 0 ignored; the suites assert behavior (exact closed refusals, byte-identical canonical emission against a committed digest vector, offset parity between CLI and library verification, drain/readiness lifecycle, zeroizing round trips) rather than implementation, and no test computes its expectation with the code under test - -## Coverage -- idiom: 2 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 5/0/0; all five validation fns are boundary admission checks) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 5/20/0/13; wire types deny unknown fields, camelCase, closed-code failures) -- obs: 1 finding(s) -- docs: 1 finding(s) -- perf: clean (seeds ran: 13/13/4; all cold paths, static) -- conc: 1 finding(s) -- async: clean (seeds ran: 120/2/5/2; sanctioned Notify/timeout drain shape, tokio Mutex across awaits, cancel-safe responder) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 22/65/0/0 src + 46/185/0/0 tests/; behavioral boundary and round-trip suites) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md deleted file mode 100644 index 3ecd52e85..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-toolkit-p2.md +++ /dev/null @@ -1,85 +0,0 @@ -# d2b-provider-toolkit-p2 - d2b-provider-toolkit - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10495 (excl. src/generated/**; src 6937 + tests 3558) | modules: testing/**, server/**, shared_provider.rs, credential.rs, service.rs, lib.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f): src/testing/**, src/server/**, src/shared_provider.rs, src/credential.rs, src/service.rs, src/lib.rs - -## idiom -- clean: seeds ran: 0/1/1 (`for \w+ in 0\.\.` = 0; `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1; `let mut \w+ = (String|Vec)::new\(\)` = 1). The one hand-written `impl Default for DispatchLimiter` (server/adapter.rs:448) is justified: `Arc` is not derivable and the manual impl preserves the frozen-ceiling invariant; the one `Vec::new()` accumulation (testing/mod.rs:900) is a recursive reference collector where an iterator pipeline would obscure the recursion. - -## own -- d2b-provider-toolkit-p2#1 sev=low blast=family effort=S verdict=actionable - serve_component_session clones all four fields of the owned decoded request per frame (`request.zone().clone(), request.provider_ref().clone(), request.method().clone(), request.payload().clone()`) instead of moving them out - fix: destructure `let ProviderRequest { request_id, zone, provider_ref, method, payload } = request;`, pass the owned values to `dispatch_for_route`, and call `codec.encode_response(&request_id, &response)` - [packages/d2b-provider-toolkit/src/server/adapter.rs:331-334] - evidence: seed `\.clone\(\)` = 76 hits in scope; the four clones at adapter.rs:331-334 are the only ones on an owned request that could be moves (the request is decoded into an owned value at adapter.rs:325 and used only through the loop). -- d2b-provider-toolkit-p2#2 sev=low blast=family effort=S verdict=actionable - the session loop clones the bound route out of the async mutex twice per frame (`self.authenticated_route.lock().await.clone()` at loop entry and per iteration) to compare identities - fix: compare inside the lock scope, e.g. `if self.authenticated_route.lock().await.as_ref() != Some(&route)`, avoiding the per-frame `AuthenticatedSessionRouteBinding` clone - [packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src/server/adapter.rs:314-316] - evidence: seed `\.clone\(\)` = 76 hits in scope; the route binding carries context and provider identity, so the two per-frame clones are the largest per-frame copies in the hot loop. -- d2b-provider-toolkit-p2#3 sev=low blast=leaf effort=S verdict=actionable - `retire_obsolete_children` sorts obsolete rows with `sort_by_key` over `(teardown_rank, row.key.name.clone())`, allocating a String per owned row per pass - fix: use `sort_by` with a comparator `teardown_rank(&a.key.type_name).cmp(&teardown_rank(&b.key.type_name)).then_with(|| a.key.name.cmp(&b.key.name))` - [packages/d2b-provider-toolkit/src/shared_provider.rs:771] - evidence: seed `\.clone\(\)` = 76 hits in scope; this is the only sort-key clone (all other clone sites are Arc clones, snapshot reads, or owned-argument passes required by the async APIs). - -## type -- clean: seeds ran: 7 (`fn validate_\w+|fn check_\w+` = 7; `is_\w+: bool|\w+_flag: bool` = 0; `(mode|kind|state): String` = 0). Every hit is a boundary validation over already-parsed types (`check_closed_code_set`, `check_descriptor_conformance`, `check_provider_conformance`, `validate_attachment_indexes`, `validate_bound_request`, `validate_authenticated_provider_request`, `validate_provider_route`); no boolean-flag soup, no stringly-typed state, no Option-pair invariants in the scope. - -## api -- d2b-provider-toolkit-p2#4 sev=low blast=leaf effort=S verdict=actionable - two dead public methods on `GeneratedProviderServiceServer`: `response_request_id` is a pure identity function (`request_id` in, same reference out) and `generated_service` has no callers anywhere - fix: delete both methods (and the `response_request_id` doc), keeping `generated_services()` which the registration-boundary doc justifies - [packages/d2b-provider-toolkit/src/server/service.rs:297-299, packages/d2b-provider-toolkit/src/server/service.rs:174-176] - evidence: census: `response_request_id` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (the definition); `generated_service\(\)` = 0 hits; `generated_services\(\)` = 1 hit (toolkit's own test). -- d2b-provider-toolkit-p2#5 sev=low blast=family effort=S verdict=actionable - `SharedProviderEffectRequest::envelope()` (the old-shape owner-envelope document) has zero callers and clones the full spec and metadata Values on every call - fix: delete the method; the driver and families read `spec`/`metadata` directly - [packages/d2b-provider-toolkit/src/shared_provider.rs:525-531] - evidence: census: `request\.envelope\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits; the method is not in the lib.rs re-export list but is pub on a pub struct. -- d2b-provider-toolkit-p2#6 sev=low blast=family effort=S verdict=actionable - `TestHarness::clock()` returns `&Arc`, exposing the Arc in the public signature when callers only need the clock - fix: return `&DeterministicClock` (callers at testing/mod.rs:686 and tests/harness.rs:857-909 all deref) - [packages/d2b-provider-toolkit/src/testing/mod.rs:530-532] - evidence: seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 4 hits in scope; the other three (spec decoder return, `family` field, `created_children`) genuinely share ownership, this one does not. - -## err -- d2b-provider-toolkit-p2#7 sev=medium blast=family effort=M verdict=actionable - `SharedProviderDriver::new` panics via `ZoneId::parse(args.zone).expect("driver zone was validated at construction")`, but `SharedProviderDriverArgs.zone` is a plain pub `String` with no validation anywhere at the factory boundary, so a family passing an invalid zone crashes the provider process at driver construction - fix: hold `ZoneId` in `SharedProviderDriverArgs` (parse once in `SharedProviderDriverFactory::new` and return a `Result`), or make `create` fallible - [packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/src/shared_provider.rs:539-546] - evidence: seed `\.unwrap\(\)|\.expect\(` = 90 hits in scope (about 70 in `#[cfg(test)]`/tests); census: `SharedProviderDriverArgs` is constructed at d2b-provider-device-security-key/src/driver.rs:327, d2b-provider-device-usbip/src/driver.rs:217, d2b-provider-device/src/driver.rs:296, d2b-provider-network-local/src/driver.rs:270, all passing a caller-supplied zone String; the expect's claimed invariant is not enforced by the type. -- d2b-provider-toolkit-p2#8 sev=low blast=family effort=S verdict=actionable - `key_ref` panics via `expect("manager keys carry canonical resource references")` on a `ResourceKey` whose fields are pub and unvalidated (`ResourceKey::new` accepts any strings), so the pub helper can panic on a non-canonical key a caller constructs - fix: return `Result` (map to `InvalidResource`) like the sibling `owner_ref`/`resource_uid` helpers - [packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtime/src/spec_store.rs:60-63] - evidence: seed `\.unwrap\(\)|\.expect\(` = 90 hits in scope; census: `key_ref\(` = 20 call sites across packages (manager-derived keys today, so the invariant holds in practice, but the type does not enforce it). -- d2b-provider-toolkit-p2#9 sev=medium blast=family effort=S verdict=actionable - `Fixture::method` maps `SpecifiedProviderMethod` with a `_ => unreachable!("specified Provider method is closed")` arm, but the enum is `#[non_exhaustive]` (d2b-contracts-provider/src/v3/provider.rs:2759), so any future contract variant becomes a runtime panic in every fixture-based test suite - fix: return `Result` and map unknown methods to `WireInvalid`, updating the two call sites (fixture.rs:190 and the `ProviderAgentService` impl) - [packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192] - evidence: seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 1 hit in scope (this site); the enum it matches is declared `#[non_exhaustive]`, which forces the `_` arm and makes the panic reachable from a contract extension. -- d2b-provider-toolkit-p2#10 sev=medium blast=family effort=S verdict=actionable - every fake port swallows the recorder-capacity error with `let _ = self.recorder.record(...)`, so `FakePortError::RecorderFull` is never constructed (dead variant in the public closed set `ALL`) and a test exceeding `MAX_RECORDED_CALLS` silently truncates its record, contradicting the variant's own doc "the call is refused rather than dropped silently" - fix: map `ProviderToolkitError::CapacityOutOfRange` to `FakePortError::RecorderFull` and return it from the fake methods (or delete the variant and its `ALL` slot) - [packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/src/testing/fakes.rs:289-291, packages/d2b-provider-toolkit/src/testing/fakes.rs:337-339, packages/d2b-provider-toolkit/src/testing/fakes.rs:391-393, packages/d2b-provider-toolkit/src/testing/fakes.rs:430, packages/d2b-provider-toolkit/src/testing/fakes.rs:464] - evidence: seed `let _ = |\.ok\(\);` = 10 hits in scope; six are these swallowed `record` results (`FakePortError::RecorderFull` appears only in the enum, its `code()` match, and `ALL`); the recorder's own error path (fakes.rs:194-198) is unreachable from any fake port. - -## serde -- clean: seeds ran: 0/0/0/4 (`derive(...Serialize/Deserialize)` = 0; `serde(...)` attributes = 0; hand-written Deserialize = 0; `serde_json::from_|to_` = 4). The four sites are Value-level decodes with explicit object validation at the boundary (shared_provider.rs:369-372, 385); no typed wire types are defined in this scope, so there is no deserialization-into-domain-type surface to judge. - -## obs -- d2b-provider-toolkit-p2#11 sev=low blast=family effort=S verdict=actionable - three message-only `warn!` events in the authenticated session loop carry no named fields even though zone/provider/method are in scope at each site, so the events are not queryable per provider - fix: add fields, e.g. `warn!(zone = ?session.route_binding().zone(), "component session receive failed; closing provider session")` and the analogous provider/method fields at the readiness and loop-failure sites - [packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src/server/session.rs:255, packages/d2b-provider-toolkit/src/server/session.rs:262] - evidence: seeds: `\bprintln!\(|\beprintln!\(` = 0; `(info|debug|warn|error|trace)!\(` = 36 hits, of which 33 already carry named fields and 3 are message-only with no enclosing span to inherit fields from (`\.instrument\(|#\[instrument` = 0 in scope). - -## docs -- d2b-provider-toolkit-p2#12 sev=low blast=leaf effort=S verdict=actionable - no public item in the scope carries the canonical `# Errors` section even though many return `Result` with closed, non-obvious failure sets (`check_descriptor_conformance` has ten `ConformanceError` variants; `operation_deadline` fails on exhausted deadlines; `validate_attachment_indexes` fails on non-monotone indexes) - fix: add `# Errors` sections naming the variant per condition to the Result-returning pub items, starting with conformance.rs:267, conformance.rs:291, credential.rs:111, credential.rs:131, adapter.rs:31 - [packages/d2b-provider-toolkit/src/testing/conformance.rs:267, packages/d2b-provider-toolkit/src/testing/conformance.rs:291, packages/d2b-provider-toolkit/src/credential.rs:111, packages/d2b-provider-toolkit/src/credential.rs:131, packages/d2b-provider-toolkit/src/server/adapter.rs:31] - evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 150 hits (all documented; `#![deny(missing_docs)]` is on); `/// # (Examples|Errors|Panics|Safety)` = 0 hits; `-> Result<` = 30 hits. - -## perf -- d2b-provider-toolkit-p2#13 sev=medium blast=family effort=M verdict=actionable - every reconcile and delete pass clones the row's full spec document (`spec: envelope.value().clone()` at shared_provider.rs:944 and 1024) into the request even though the envelope outlives the effect call and the request is only read by the family - fix: change `SharedProviderEffectRequest.spec` from `Value` to `&'a Value` (the struct is constructed only in this file; family call sites read via method calls and auto-deref), removing one full-spec allocation per pass - [packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/src/shared_provider.rs:1024, packages/d2b-provider-toolkit/src/shared_provider.rs:479-481] - evidence: static (unmeasured); seed `format!\(` = 20 hits and `Vec::new\(\)` = 15 hits in scope, but the spec clone is the only per-pass allocation proportional to spec size (the pass runs on every resync cadence and every change); the `operation_id` format! per pass is small and not flagged. - -## conc -- clean: seeds ran: 40 (`std::thread::|thread::spawn|thread::scope` = 0; `\bMutex<|\bRwLock<` = 4; `Atomic\w+|Ordering::` = 36; `thread_local!|unsafe impl (Send|Sync) for` = 1). Atomics use correct orderings (Acquire/Release pairs on the limiter and server state, Relaxed on the delivery-sequence counter, AcqRel in `DeterministicClock::advance`); `shutdown` arms the `Notify` before checking in-flight (the clippy.toml-sanctioned pattern); the `thread_local!` runtime in credential.rs is the sanctioned synchronous-path allow. - -## async -- clean: seeds ran: many (`async fn|async move|\.await` throughout; `tokio::spawn` = 1 at server/mod.rs:68; `tokio::sync::(Mutex|RwLock|Notify)` = 3; `#\[tokio::(main|test)\]|Runtime::block_on` = 0). No blocking work inside async contexts (the one `block_on` is the documented synchronous dispatch half with the sanctioned `reason = "synchronous path"` allow); `ContextChildSurface` holds a `tokio::sync::Mutex` guard across the context's own awaits (async-aware, never across another effect call); both session loops are cancellation-aware; the spawn/yield/is_finished immediate-failure check in `serve_authenticated_route` aborts cleanly on error paths. - -## unsafe -- N/A: seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0; `// SAFETY:` = 0; `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; `unsafe_code` = 0 (manifest carries `unsafe_code = "forbid"` under `[lints.rust]`). - -## ffi -- N/A: seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0; `catch_unwind` = 0; `repr\(C\)|repr\(transparent\)` = 0; `CStr|CString|c_char` = 0. No foreign boundary in this scope. - -## macro -- N/A: seeds: `macro_rules!` = 0; `proc_macro|syn::|quote!` = 0; `\$crate` = 0; `to_compile_error|new_spanned` = 0. No macro definitions in this scope. - -## test -- clean: seeds ran: 55 in src + 90 in tests (`#\[test\]|#\[tokio::test\]` = 20 src + 14 tests; `assert_eq!\(|assert_ne!\(|assert!\(` = 35 src + 76 tests; `proptest!|insta::assert|rstest` = 0; `#\[ignore\]` = 0). Tests assert behavior and error variants rather than Display strings, expectations are human-written or independent (`br#"..."#` literals, closed-code sets), the shared statics (`SEEN_INVOCATIONS`, `TEMP_FILE_SEQUENCE`) are cleared or unique per test so runs stay deterministic, and the `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]` sites use the sanctioned reason. - -## Coverage -- idiom: clean (seeds ran: 0/1/1; hand-written Default justified, no index loops) -- own: 3 finding(s) -- type: clean (seeds ran: 7/0/0; all hits are boundary validations over parsed types) -- api: 3 finding(s) -- err: 4 finding(s) -- serde: clean (seeds ran: 0/0/0/4; Value-level decode with explicit object validation) -- obs: 1 finding(s) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 0/4/36/1; correct atomic orderings, sanctioned Notify pattern) -- async: clean (seeds ran: many/2/3/0; no blocking in async contexts, cancellation-aware loops) -- unsafe: N/A (seeds: 0/0/0/0; manifest forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 34 tests + 111 assertions; behavior and error-variant assertions, deterministic) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md deleted file mode 100644 index 4e3e967e6..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-azure-relay.md +++ /dev/null @@ -1,97 +0,0 @@ -# d2b-provider-transport-azure-relay - d2b-provider-transport-azure-relay -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5952 (excl. src/generated/**, none present) | modules: whole crate (auth, backpressure, credential_client, guest_credential, guest_zone_link, lib, relay_transport, transport_settings; tests: backpressure_credit, fake_relay_transport, listener_sender_conformance, transport_credentials, transport_settings_schema) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) - -## idiom -- d2b-provider-transport-azure-relay#1 sev=low blast=leaf effort=S verdict=actionable - `impl Clone for RelaySecret` hand-writes what `#[derive(Clone)]` generates identically (`Zeroizing>` clones into a fresh `Zeroizing` either way), and the manual version can drift from the field - fix: replace the impl block with `#[derive(Clone)]` on `RelaySecret` - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:236-239, packages/d2b-provider-transport-azure-relay/src/credential_client.rs:217] - evidence: idiom2 `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits in src; the other hit (Default for AzureRelaySocketConnector, relay_transport.rs:249) is deliberate because a field-wise derive would set `sas_ttl_secs: 0` -- d2b-provider-transport-azure-relay#2 sev=low blast=leaf effort=S verdict=actionable - `build_connect` builds the literal `"Bearer"` by collecting a char array (`['B','e','a','r','e','r']`) into a fresh String on every connect, where a `const`/literal `"Bearer"` reads plainly and allocates nothing - fix: use a `const BEARER: &str = "Bearer"` (or inline literal) in the `ServiceBusAuthorization` header format - [packages/d2b-provider-transport-azure-relay/src/auth.rs:249-253] - evidence: idiom1 `for \w+ in 0\.\.` = 1 hit (test loop in fake_relay_transport.rs), idiom3 `let mut \w+ = (String|Vec)::new\(\)` = 0; the char-array collect is a statement-style construction the skill's expression lens names -- clean: idiom1 = 1 (test-only `for _ in 0..=MAX_RELAY_GENERATION_FENCES` loop), idiom2 = 2 (both judged above), idiom3 = 0; naming (`as_`/`to_`/`into_`, no `get_`) and derive discipline otherwise consistent across the crate - -## own -- d2b-provider-transport-azure-relay#3 sev=low blast=leaf effort=S verdict=actionable - `ScopedCredentialRequest::with_deadline` takes `&self` and clones all four owned fields (zone, credential_ref, execution_ref, binding) only to rebuild the struct, while its single in-tree caller can consume the request - fix: change the signature to `with_deadline(self, deadline_ms)` and rebuild with `Self { deadline_ms, ..request }` plus `validate()` - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:190-198, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:1315-1317] - evidence: own1 `\.clone\(\)` = 18 hits in src (12 production, 6 in cfg(test)); census: `with_deadline` over packages = 1 call site (relay_transport.rs:1316), so consuming `self` breaks no caller -- d2b-provider-transport-azure-relay#4 sev=low blast=leaf effort=S verdict=actionable - `GatewayCredential::from_material` clones all four secret Strings out of an owned `GatewayCredentialMaterial` (forced today because the material type implements `Drop`, which forbids partial moves) where storing the material as one field would move it in without copies - fix: give `GatewayCredential` a single private `material: GatewayCredentialMaterial` field and move it in `from_material`; field accessors and the redacting `Debug` stay unchanged - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:267-277, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:271-275] - evidence: own1/own2 counts in guest_credential.rs = 6 clone + 6 to_owned/to_vec/to_string hits; the four clones at 272-275 are the only ones not required by a sharing boundary -- clean: own1 = 18 (src), own2 = 28 (src), own3 = 1 (`Arc>` active-lease table in GatewayGuestCredentialPort, genuinely shared across port clones/tasks), own4 = 0; remaining clones are Arc clones at spawn/`Arc::clone` boundaries, `binding.clone()` into the lease/active table, and wire-boundary `to_vec`/`to_owned` conversions - all explainable in one sentence - -## type -- d2b-provider-transport-azure-relay#5 sev=low blast=leaf effort=S verdict=actionable - `GatewayGuestZoneLinkRuntime` carries `credential_generation: Option` and `credential_send_key_digest: Option<[u8; 32]>` as two independent Options that are always set or unset together (from_sealed sets both, from_scoped sets neither), leaving the half-set state representable and forcing `write_open_observation`'s `let (Some, Some) else` guard - fix: replace the pair with one `Option` struct (or a `Sealed`/`Scoped` enum carrying the marker data) so the impossible half-set combination stops compiling - [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:149-150, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:258-262] - evidence: type1 `fn validate_\w+|fn check_\w+` = 3 hits (auth.rs validate_endpoint/validate_credential_text/validate_credential - boundary validation on a pub API, kept), type2 = 0, type3 = 0; the correlated-Option pair is the only representable-illegal-state candidate -- clean: type1 = 3 (auth.rs boundary validators, correct parse-at-boundary placement), type2 = 0, type3 = 0; no boolean-flag soup or stringly-typed state; the `RelaySessionPhase` enum and `RelayGenerationFence` state machine already encode their transitions in types - -## api -- d2b-provider-transport-azure-relay#6 sev=low blast=leaf effort=S verdict=actionable - `RelayCredentialPort::acquire` is a required trait method whose only production implementation (GatewayGuestCredentialPort) returns `Err(BindingRequired)` - the same fail-closed policy the trait already gives `acquire_bound` as a default - so every implementer must write a method that never succeeds - fix: give `acquire` a default body returning `Err(RelayCredentialError::BindingRequired)` and delete the redundant overrides in GatewayGuestCredentialPort and the test fakes - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:491-497, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:387-392] - evidence: api1 `\bpub (fn|struct|enum|trait|type|const|mod) ` = 140 hits in src; census: `RelayCredentialPort` over packages = 22 hits, `acquire` overrides = 9 sites (1 production + 8 test fakes), none callable to success -- d2b-provider-transport-azure-relay#7 sev=low blast=leaf effort=S verdict=actionable - `set_drop_hook` takes `Arc` in a public signature although the lease is the sole owner of the hook (it is stored once and called on drop), forcing every caller to allocate an Arc for a single-owner value - fix: take `Box` or a generic `F: Fn(u64) + Send + Sync + 'static`; call sites (guest_credential.rs:455, tests) change `Arc::new)...)` to `Box::new)...)` - [packages/d2b-provider-transport-azure-relay/src/credential_client.rs:343-347, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:455] - evidence: api2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits in src (this signature and `GatewayGuestCredentialPort::with_clock`; the latter genuinely shares the credential and clock across port clones and is kept); api3 `^\s*pub use ` = 0 (lib.rs re-export arms are the house single-surface pattern, judged clean) -- clean: api1 = 140, api2 = 2 (both judged), api3 = 0; the lib.rs `pub use` arms are the house single-surface pattern; no dependency types leak into signatures beyond the two judged sites; `AzureRelaySocketConnector` is a builder with `const fn new()` and no `Default`-shape traps - -## err -- d2b-provider-transport-azure-relay#8 sev=medium blast=leaf effort=S verdict=actionable - `From` and `From` for `GatewayGuestZoneLinkError` discard the source entirely (`fn from(_: ...)`), collapsing every credential failure (Unreadable, Malformed, Expired, BadMode, BadOwner, Crypto) into one generic variant with no chain, so callers cannot distinguish or log the cause - fix: carry the source (e.g. `CredentialUnavailable { source: CredentialError }` with `#[source]`-style chaining, or keep the collapse but retain `source()`), matching the err skill's context-survival rule - [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:69-78, packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:181-187] - evidence: err4 `enum \w*Error` = 7 error enums in src; the two `From` impls at guest_zone_link.rs:69-78 are the only source-discarding conversions in the crate (the crate's own Display codes are not pinned in docs/reference/error-codes.md - checked - so the enum shape is not wire-visible) -- d2b-provider-transport-azure-relay#9 sev=medium blast=leaf effort=S verdict=actionable - clock-before-epoch failures are silently swallowed with `unwrap_or(0)` in `system_now_unix()` (guest_zone_link) and `system_now_unix_ms()` (guest_credential), and a zero `now` makes `load_sealed_inner`'s expiry check fail open (`now >= not_after` is false for any positive `not_after`), accepting an expired envelope - while auth.rs returns `RelayError::Clock` and relay_transport.rs maps the same condition to `CredentialExpired` - fix: propagate a clock error (or reject the load) instead of substituting 0, mirroring `RelayError::Clock` - [packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs:26-30, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:665-669, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:178-183] - evidence: err1 `\.unwrap\(\)|\.expect\(` = 72 hits in src, 70 inside `#[cfg(test)]`; the 2 production sites (relay_transport.rs:568 `expect("inserted generation state")`, relay_transport.rs:1129 `expect("credential lease guard must own a lease")`) are invariant expects the panic policy permits; err3 `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0 in src -- clean: err2 `let _ = |\.ok\(\);` = 8 hits, all deliberate best-effort cleanup (`let _ = socket.close().await` on already-failing paths, `let _ = fs::remove_file` of a temp marker) - judged per site and kept; panic policy otherwise consistent: Result all the way to the transport boundary, `revoke_or` preserves the more specific error - -## serde -- d2b-provider-transport-azure-relay#10 sev=medium blast=family effort=M verdict=needs-contract - `RelayTransportSettings` derives `Deserialize` without `try_from`, so `serde_json::from_slice::` at d2bd/src/composition.rs:843 accepts identifiers that `new()`/`validate()` reject - including the secret-shape exclusion (`SharedAccessSignature`) that exists only in Rust and not in the pinned schema `docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json` (whose patterns admit lowercase letters) - fix: add `#[serde(try_from = "...")]` reusing `validate()`, and first encode the secret-shape exclusion in the schema so schema and Rust agree - [packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9-15, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:31-41, packages/d2bd/src/composition.rs:843-846] - evidence: serde1 `derive\([^)]*(De)?[Ss]erialize` = 2, serde2 `serde\((rename_all|deny_unknown_fields|try_from|...)` = 3, serde4 `serde_json::from_|serde_json::to_` = 4 over src+tests; census: `RelayTransportSettings` over packages = 22 hits including the d2bd `from_slice`; the schema pattern-vs-Rust divergence (secret-shape exclusion) makes the tightening needs-contract per U1 (d) 7 -- d2b-provider-transport-azure-relay#11 sev=low blast=leaf effort=S verdict=policy-confirmed - `parse_material_json` hand-walks `serde_json::Value` paths for a fixed nested shape (`relayListen`/`relaySend` keyName/key) that a derived `Deserialize` with `rename_all = "camelCase"` plus a validate pass would express - this is the recorded live-admission-gate class, refused in the prior audit - fix: only rework if the admission gate is deliberately replaced (derive + `try_from` validation), citing changed evidence - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:245-264] - evidence: serde3 `impl .*Deserialize.*for` = 0; the Value-walk is the same class as the refused qemu guest/provider-spec admission gates - docs/explanation/over-engineering-audit-record.md:229-231 ("hand-written deserializers ... kept as the live admission gate") - so the verdict is policy-confirmed per U1 (d) 6 -- clean: serde1 = 2 (SealedCredentialFile, RelayTransportSettings), serde2 = 3 (rename_all camelCase + deny_unknown_fields on both wire types, `#[serde(default)]` on `not_after`), serde3 = 0, serde4 = 4; the sealed-envelope type is a model serde boundary (deny_unknown_fields, version field checked by hand, AAD-bound plaintext parsed after decrypt) - -## obs -- d2b-provider-transport-azure-relay#12 sev=low blast=leaf effort=S verdict=actionable - five `tracing::warn!` events at the credential-port boundary are message-only (guest_credential.rs:406, 423, 476, 483 - and 438 carries `active_leases` but no role), while sibling events in the same crate carry `role = ?role`, `binding = ?binding`, `reason = %error`; a lease-acquire rejection or revoke mismatch is not attributable to a role or lease without those fields - fix: add `role = ?role` (and `lease_id` where available) to those events so the crate's event schema is uniform - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:406-408, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:423-425, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:476-478, packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:483-485] - evidence: obs2 `(info|debug|warn|error|trace)!\("` = 25 hits in src (guest_credential 5, guest_zone_link 4, relay_transport 16); obs1 `\bprintln!\(|\beprintln!\(` = 0; obs3 `\.instrument\(|#\[instrument` = 0; no secret reaches any event (all Debug/Display paths redact, verified per site) -- clean: obs1 = 0 (no println in the library), obs3 = 0, obs4 = 25 (tracing only, no `log` facade); relay_transport's 16 events consistently carry `provider` + `role` + `binding` + `reason`; the three drop-hook cleanup warnings (relay_transport.rs:1155-1190) are best-effort edges with no lease data in scope - -## docs -- d2b-provider-transport-azure-relay#13 sev=low blast=leaf effort=M verdict=actionable - none of the 80 Result-returning public items carries a canonical `# Errors` section (docs2 = 0 crate-wide), so failure conditions are discoverable only by reading the error enums; e.g. `mint_sas`, `build_connect`, `CreditWindow::new`, `RelayTransportSettings::new` - fix: add `# Errors` sections naming the conditions (mint_sas: InvalidTtl, TtlTooLong, InvalidEndpoint, InvalidCredential, Key, Clock) on the pub Result items - [packages/d2b-provider-transport-azure-relay/src/auth.rs:229-246, packages/d2b-provider-transport-azure-relay/src/backpressure.rs:31-36, packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:18-22] - evidence: docs1 `^\s*pub (fn|struct|enum|trait|const|type)` = 133 hits (MULTILINE count), docs2 `/// # (Examples|Errors|Panics|Safety)` = 0, docs3 `-> Result<` = 80; `#![deny(missing_docs)]` at lib.rs:4 means every pub item is otherwise documented - the gap is canonical sections only -- clean: module docs (`//!`) on all 8 modules, first-sentence discipline consistent, all pub items documented (missing_docs denied), redaction rationale documented on every secret-bearing Debug; no doctests present (docs2 = 0), which is consistent with the crate's integration-test style - -## perf -- d2b-provider-transport-azure-relay#14 sev=medium blast=leaf effort=S verdict=actionable - `generation_key` allocates three Strings (`to_owned` x3) on every `RelayConnection::send`/`receive` via `ensure_current_generation -> is_current`, and the key is invariant for a connection's lifetime (it derives from the binding the connection already owns) - fix: precompute the `(String, String, String)` key once in `RelayConnection` (or key the fence map on a borrowed/hashed form) and pass it to `is_current`, removing three heap allocations from the per-frame I/O path - [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:629-630, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:814, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:844] - evidence: static (unmeasured) - no benchmark exists in this crate; perf1 `format!\(` = 22 in src, perf2 `Vec::new\(\)|...` = 2, perf3 `\.to_string\(\)` = 0; the allocation site is on the frame I/O path (send/receive call is_current every call) -- d2b-provider-transport-azure-relay#15 sev=low blast=leaf effort=S verdict=actionable - `read_policy_file` grows `Zeroizing::new(Vec::new())` via `read_to_end` without a capacity hint although the file size is already known from the earlier `metadata()` call - fix: `Vec::with_capacity(meta.len() as usize)` before reading - [packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618] - evidence: static (unmeasured); perf2 = 2 hits - the other (credential_aad's `Vec::with_capacity`) already sizes correctly, so this is the only grow-by-read site -- clean: the remaining format! sites are cold (SAS minting, connect URL building, the one-shot observation marker, digest_hex at 32 x format! for a one-time 64-char hex) and the frame copy in `RelayWebSocketSocket::send` (`as_bytes().to_vec()`) is inherent to the tungstenite `Message::Binary(Vec)` API; no attacker-controlled hashing, no unbounded collections - -## conc -- clean: conc1 `std::thread::|thread::spawn|thread::scope` = 0, conc2 `\bMutex<|\bRwLock<` = 8 in src (5 tokio::sync::Mutex on RelayConnection + 1 tokio::sync::Mutex active-lease table + 1 StdMutex generation fence + 1 StdMutex in tests), conc3 `Atomic\w+|Ordering::` = 9 (lease-id and challenge counters, `Ordering::Relaxed` - the weakest correct ordering for counters), conc4 = 0; the StdMutex fence is a sanctioned `synchronous path` allow (relay_transport.rs:535-541, needed for noexcept Drop cleanup) with a written reason and `into_inner` poison recovery; lock ordering across the five tokio Mutexes is acyclic (write_lock -> credits -> phase -> session_permit -> generation_lease -> socket, each guard dropped before the next acquisition) - -## async -- d2b-provider-transport-azure-relay#16 sev=medium blast=leaf effort=S verdict=actionable - `RelayConnection::send` is not cancellation-safe: `credits.reserve(size)` is followed by `self.socket.send(frame).await`, and the rollback runs only on `Err` - if the future is cancelled between reserve and completion (e.g. by the session engine's timeout wrapper), the reservation leaks and the connection is permanently starved of up to 64 KiB of credit - fix: wrap the reservation in a small RAII guard that rolls back on drop unless the send committed (or reserve after the await using a pre-checked window) - [packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833] - evidence: async1 `async fn|async move|\.await` = 93 hits in relay_transport.rs (134 in src total); cancellation-path analysis is static; the leak is bounded per event but unbounded over repeated cancellations on a live connection -- clean: async2 `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0 in src, async3 `tokio::sync::(Mutex|RwLock|Notify)` = 2 (active-lease table, RelayConnection state - guards never held across foreign awaits beyond the socket call), async4 `#\[tokio::(main|test)\]|Runtime::block_on` = 4 (all `#[tokio::test]`); `spawn_bounded_revoke` uses `Handle::try_current()` so a runtime-less Drop degrades to a warn, not a panic; cancellation of `open_inner` is covered by Drop-based cleanup (generation attempt abort, lease-guard best-effort revoke); no blocking calls on executor workers (the sync file I/O is confined to the sanctioned `synchronous path` composition boundary) - -## unsafe -- N/A: seeds 1-3 (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0) all zero; seed 4 `unsafe_code` = 1 (`#![forbid(unsafe_code)]` at lib.rs:4 plus `unsafe_code = "forbid"` in the manifest) - the forbid attribute alone does not make the lens applicable per the card - -## ffi -- N/A: seeds 1-4 (`extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0) all zero over src; the crate crosses no foreign-language boundary (libc is used only for `O_NOFOLLOW` in the file policy check) - -## macro -- N/A: seeds 1-4 (`macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0) all zero in src; the single `macro_rules!` in tests (fake_relay_transport.rs, `legacy_scoped_adapter!`) is a test-only helper macro, which the card exempts - -## test -- clean: test1 `#\[test\]|#\[tokio::test\]` = 58, test2 `assert_eq!\(|assert_ne!\(|assert!\(` = 141, test3 `proptest!|insta::assert|rstest` = 0, test4 `#\[ignore\]` = 0; assertions target behavior and error variants (never Display strings), the fake harness is deterministic (injected clock, no network; `valid_expiry()` uses the real clock only as a far-future bound), and the cancellation/timeout tests use bounded `timeout` + `yield_now` polling; the only weak assertion is `helper_surface_does_not_reintroduce_unbounded_window` (fake_relay_transport.rs:1407-1409), a bound pin that can still fail if the constant moves - tolerable, not a cannot-fail test - -## Coverage -- idiom: 2 finding(s) -- own: 2 finding(s) -- type: 1 finding(s) -- api: 2 finding(s) -- err: 2 finding(s) -- serde: 2 finding(s) -- obs: 1 finding(s) -- docs: 1 finding(s) -- perf: 2 finding(s) -- conc: clean (seeds ran: 0/8/9/0; tokio Mutex state on RelayConnection is acyclic and StdMutex fence is a sanctioned synchronous-path allow) -- async: 1 finding(s) -- unsafe: N/A (seeds: 0/0/0 all zero; `unsafe_code = "forbid"` in manifest and lib.rs, no unsafe sites) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign-language boundary) -- macro: N/A (seeds: 0/0/0/0 all zero in src; one test-only helper macro in tests/) -- test: clean (seeds ran: 58/141/0/0; behavior- and variant-level assertions, deterministic harness, no ignored tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md deleted file mode 100644 index b37d59b2a..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-transport-vsock.md +++ /dev/null @@ -1,96 +0,0 @@ -# d2b-provider-transport-vsock - d2b-provider-transport-vsock -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 4128 (excl. src/generated/**) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (whole crate) - -## idiom -- d2b-provider-transport-vsock#1 sev=low blast=leaf effort=S verdict=actionable - `ReadySession::disconnect` takes `mut self`, assigns `SessionState::Disconnected` to a by-value copy that is immediately dropped, and then returns the assigned constant - the mutation is dead code and the method contract is fully expressed by returning the constant. - fix: `pub fn disconnect(self) -> SessionState { SessionState::Disconnected }`, dropping `mut` and the state assignment - [packages/d2b-provider-transport-vsock/src/auth.rs:221-224] - evidence: idiom seeds ran:0/3/0; site found by full-file read of auth.rs. - -## own -- clean: all 12 hits (seeds ran:5/0/7/0) are explainable:the five `.clone()` sites share `BridgeControl`/`ReadySession`/`GuestIdentity` values where the clone is the ownership transfer the spanned bridge task or session object needs; the seven `Arc>` fields back genuinely multi-owner service state (active/completed maps, per-entry history/phase/exit, subscriber list) shared between the service and its spawned bridge tasks, matching the U1 shared-state false-positive note. - - - -## type -- clean: seeds all zero (0/0/0) but lens is applicable (the crate declares many structs/enums): no `validate_`/`check_` fns, boolean flag soup, or stringly state;`VsockTransportSettings`'s validate-at-callsite shape (pub fields + later `validate()`) is reported under serde as a wire-boundary validation gap rather than here. - - - -## api -- clean: seeds 106/0/10; the pub surface is the deliberate single-path `lib.rs` re-export pattern(10 arms), every exported item documented under `#![deny(missing_docs)]`; no `Arc`/`Rc`/`Box`/`RefCell` or dependency types appear in public signatures, and the three effect-port traits keep small required surfaces with associated types for the per-implementer stream/handle types. - - - -## err -- clean: seeds 8/1/0/7; the 6 relay.rs `.expect("reservation")`/`.expect("listener")` sites are invariant assertions after an explicit `Some)...)` assignment in the same function (accepted by the skill's "expect names the invariant" rule),the 2 service.rs unwraps live under `#[cfg(test)]` mod tests, and the single `let _ =` is a deliberately ignored best-effort watch send in `BridgeControl::stop`. - - - -## serde -- d2b-provider-transport-vsock#4 sev=medium blast=wide effort=M verdict=needs-contract - `VsockTransportSettings` deserializes untrusted wire JSON with no boundary validation: invalid `guest_ref`/`connect_timeout_seconds` land as ordinary values and are only rejected by later explicit `validate()` calls (in `new()` and `ZoneLinkSpec::validate`), and the all-public fields let any caller build an invalid settings value silently; a parse-once `try_from` type would reject once at the wire. - fix: `#[serde(try_from = "VsockTransportSettingsWire")]` with a private raw wire shape +`TryFrom` validation, plus private fields and accessors; wire field names/schema stay unchanged - [packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transport-vsock/src/settings.rs:42-50, packages/d2b-provider-transport-vsock/tests/schema.rs:13-18] - evidence: serde seeds ran:2/4/0/0; census: `VsockTransportSettings` over packages/, tests/, nixos-modules/, labs/, docs/reference/ = 17 hits, all within this crate + its tests; wire shape pinned by the committed schema at docs/reference/schemas/v3/providers/transport-vsock.transport-binding.json (referenced from settings.rs:56). - -## obs -- d2b-provider-transport-vsock#2 sev=low blast=leaf effort=S verdict=actionable - the 9 transport-open rejection warn events log `endpoint`/`binding` fields whose `Display` impls are constants ("opaque-endpoint"/"opaque-binding"), so the named fields cannot correlate any event to a specific transport - an operator debugging repeated opens sees identical values every time. - fix: drop the `endpoint`/`binding` fields from the open-reject warn events, or give `OpaqueEndpointId`/`OpaqueBindingId` a real `Display` over `self.0` while keeping `Debug` redacted - [packages/d2b-provider-transport-vsock/src/service.rs:392, packages/d2b-provider-transport-vsock/src/service.rs:466, packages/d2b-provider-transport-vsock/src/service.rs:65-67, packages/d2b-provider-transport-vsock/src/service.rs:99-101] - evidence: obs seeds ran:0/0/0/13; static read of the 9 warn-field sites. -- d2b-provider-transport-vsock#3 sev=low blast=leaf effort=M verdict=actionable - bridge-drop,and bridge-copy-failure debug events carry no transport identity (no handle, endpoint, or binding field), so with up to `MAX_ACTIVE_TRANSPORTS` concurrent transports an operator cannot tell which one dropped an event or failed a copy - thread a handle/endpoint identity into the open path's spawned bridge task and through `emit_event`. - fix: capture `endpoint_id`/`binding_id` into the `tokio::spawn` block in `open_transport` and pass them to `emit_event`, adding named fields to the three drop events and the `run_bridge` copy-failure site - [packages/d2b-provider-transport-vsock/src/service.rs:735, packages/d2b-provider-transport-vsock/src/service.rs:766, packages/d2b-provider-transport-vsock/src/service.rs:851, packages/d2b-provider-transport-vsock/src/bridge.rs:186] - evidence: obs seeds ran:0/0/0/13; static read of the emit_event/drop sites. - - - -## docs -- d2b-provider-transport-vsock#5 sev=low blast=leaf effort=M verdict=actionable - 38 public `Result`-returning items carry no `# Errors` doc sections, so callers must infer from doc prose which condition yields which failure variant - the crate's `#![deny(missing_docs)]` (lib.rs:3) secures only first sentences, not the canonical contract sections. - fix: add `# Errors` bullet lists naming the failure variant per condition to the public Result-returning items (e.g. `GuestIdentity::new`, `SessionAuthority::authenticate`, `VsockTransportSettings::new`, `ZoneLinkSpec::validate`, `open_transport`, `NativeGuestRelay::start`) - [packages/d2b-provider-transport-vsock/src/auth.rs:59, packages/d2b-provider-transport-vsock/src/auth.rs:257, packages/d2b-provider-transport-vsock/src/settings.rs:31, packages/d2b-provider-transport-vsock/src/service.rs:383, packages/d2b-provider-transport-vsock/src/relay.rs:201] - evidence: docs seeds ran:106/0/38; the canonical-sections seed (`/// # (Examples|Errors|Panics|Safety)`) returned zero hits. - - - -## perf -- clean: seeds ran:0/3/0; the 3 collection-init hits (two `HashMap::new()` for the active/completed tables, one `Mutex::new(Vec::new())` for subscribers) are genuinely dynamic bounded maps or an empty-case-common vector, and no `format!` or `to_string()` appears in src - no allocation hot path to flag (static, unmeasured). - -## conc -- clean: seeds ran: 0/7/17/0; the atomics match the skill's model: `BridgeStats` counters use `Relaxed` (pure counters), `next_handle.fetch_add(Relaxed` (uniqueness-only handle generation), the `done` `AtomicBool` uses the paired Release-store/Acquire-load handoff with re-check after arming `Notify`,and the seven `Arc>` fields are tokio async mutexes genuinely shared between service and per-transport bridge tasks. - - - -## async -- clean: seeds ran:111/1/0/0; no lock guard crosses an `.await`, every effect open/close and named-stream open are wrapped in `timeout`(with the tokio-clock deadline rationale documented in open_transport),the spawned bridge task uses only async I/O (`copy_bidirectional`, AsyncWriteExt/AsyncReadExt),and the tokio `Mutex`/`Notify`/`watch` selection matches the workload - no blocking call on an executor worker found. - - - -## unsafe -- N/A (seeds:0/0/0 all zero; no unsafe blocks/fns/impls or `// SAFETY:` comments; seed4 (`unsafe_code`=2) is only the `#![forbid(unsafe_code)]` at lib.rs:4 plus the crate manifest's mirror table, which do not make the lens applicable. - - - -## ffi -- N/A (seeds:0/0/0/0 all zero; no `extern "C"`/`no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString`/`c_char` surface exists in the crate). - - - -## macro -- N/A (seeds:0/0/0/0 all zero; no `macro_rules!`, proc-macro trees (`proc_macro`/`syn::`/`quote!`/`$crate`/`to_compile_error`/`new_spanned`) exist in the crate). - - - -## test -- d2b-provider-transport-vsock#6 sev=low blast=leaf effort=S verdict=actionable - tests/observe.rs asserts `ServicePhase::Ready == ServicePhase::Ready`, a self-comparison that cannot fail and adds nothing to a test already asserting the observation fields - dead assertion weight with no regression value. - fix: delete line 15 (the test still asserts `observation.phase == TransportPhase::Released`), or replace with a real cross-variant assertion (e.g. `assert_ne!(ServicePhase::Ready, ServicePhase::Serving)` - [packages/d2b-provider-transport-vsock/tests/observe.rs:14-15] - evidence: test seeds ran:38/84/0/0; the tautology found by full-file read of tests/observe.rs; rest of the suite asserts error variants, uses table-driven virtual-clock deadlines (`drive_until_settled`), redaction canaries, and bounded eviction behavior - no `#[ignore]`, flaky, or implementation-restating tests found. - - - -## Coverage -- idiom: 1 finding (seeds:0/3/0) -- own: clean (seeds ran:5/0/7/0) -- type: clean (seeds ran:0/0/0) -- api: clean (seeds ran:106/0/10) -- err: clean (seeds ran:8/1/0/7) -- serde:1 finding (seeds:2/4/0/0) -- obs:2 findings (seeds:0/0/0/13) -- docs:1 finding (seeds:106/0/38) -- perf: clean (seeds ran:0/3/0) -- conc: clean (seeds ran:0/7/17/0) -- async: clean (seeds ran:111/1/0/0) -- unsafe: N/A (seeds:0/0/0 all zero; no unsafe blocks/fns/impls or SAFETY comments) -- ffi: N/A (seeds:0/0/0/0 all zero; no extern/"C", catch_unwind, repr(C)/transparent, or CStr surface) -- macro: N/A (seeds:0/0/0/0 all zero; no macro_rules! or proc-macro machinery) -- test:1 finding (seeds:38/84/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md deleted file mode 100644 index f91a4415e..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-user.md +++ /dev/null @@ -1,77 +0,0 @@ -# d2b-provider-user - d2b-provider-user -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2079 (excl. src/generated/**; src 1934 + tests 145) | modules: whole crate (driver.rs, effects_service.rs, facets.rs, probe.rs, test_support.rs, lib.rs; tests/registration.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: n/a (single-part lane) - -## idiom -- clean: seeds 0/0/0 - no index loops, no hand-written derive-able impls (all derives are `#[derive]`), no statement-style accumulation; the crate reads as expressions (payload-value iterator in `InspectUserRequest::parse`, let-else, `is_some_and`). - -## own -- d2b-provider-user#1 sev=low blast=leaf effort=S verdict=actionable - `serve_inspect_user` clones `request.groups` into the spec even though the owned `InspectUserRequest` could yield it by move; the username clone at the same site is required (reused in `inspect_user_response`) - fix: destructure `let InspectUserRequest { user_ref, username, groups } = request;` and pass `username`/`groups` by value into `UserSpec::new`, borrowing `user_ref` and `username` afterwards - [packages/d2b-provider-user/src/effects_service.rs:179, packages/d2b-provider-user/src/effects_service.rs:164-187] - evidence: `\.clone\(\)` = 16 hits; the 15 other clones are test doubles (driver.rs:497,544,579; test_support.rs:60,81,130,151), Arc refcount bumps (effects_service.rs:258,302,605; driver.rs:217), required ownership transfers (driver.rs:246,249,305; effects_service.rs:177,386), or test fixtures - only this pair has an owned local as source -- clean: seeds 16/21/0/0 - every clone/to_owned inspected; no Rc/RefCell/Arc/Cow anywhere; argument positions take `&str`/`&ResourceRef`/`&UserSpec` throughout. - -## type -- clean: seeds 2/0/0 - the two `fn validate_` hits are test names (`validate_accepts_the_bootstrap_user_row`, `validate_rejects_a_malformed_user_spec`), not runtime validation; domain state is parsed once into closed contract types (`InspectUserRequest`, `OsUsername`, `OsGroupName`, `ResourceRef`, `UserSpec`), no boolean-flag soup or stringly-typed state in production code. - -## api -- clean: seeds 30/6/3 - the 3 `pub use` arms in lib.rs:42-44 are the house single-path pattern; `UserEffectFacets.probe: Arc` (facets.rs:33) is genuine shared ownership across the driver factory (driver.rs:202-205) and the service factory (effects_service.rs:258), with external consumers in d2bd (resource_plane_v3.rs, provider_lifecycle.rs, shared_provider_effects.rs; census over packages/ = 8 files); `UserDriverError`/`UserDriverStatus`/`UserDriverEffects` are pub-in-private-module and unreachable outside the crate; the test_support surface is feature-gated and consumed by d2bd plane tests. - -## err -- d2b-provider-user#2 sev=low blast=leaf effort=S verdict=actionable - `UserDriverError`'s `Display` hand-copies the three `system-core-*` failure codes that `d2b-contracts` already registers as `FailureKind` constants, so the strings can silently drift from the registry and its rendered reference - fix: write `self.kind.failure_kind().code()` in the `Display` impl (driver.rs:118-124) instead of the per-arm string match, keeping the registry the single source - [packages/d2b-provider-user/src/driver.rs:118-124, packages/d2b-contracts/src/failure_kinds.rs:342-363] - evidence: `enum \w*Error` = 1; census `SYSTEM_CORE_SPEC_INVALID|SYSTEM_CORE_USER_DISCOVERY_FAILED|SYSTEM_CORE_DRAIN_PENDING` over packages/ = 3 sites (registry, provider-host, provider-user); the codes are rendered to docs/reference/resource-runtime-failure-kinds.md -- clean: seeds 46/0/2/1 - 45 of 46 unwrap/expect hits are in `#[cfg(test)]` code; the one production expect (effects_service.rs:178) is a literally-built value (`BoundedText::parse(String::new())`) whose invariant the message names (per-card false-positive class); the 2 panics are test-helper failure messages with context; no swallowed Results (`let _ =`/`.ok();` = 0); the private `UserDriverErrorKind` enum is a closed, correctly-split taxonomy (refused/not-yet/retryable mapped in `classify_error`). - -## serde -- clean: seeds 0/0/0/5 - no serde derives or attributes in this crate; the 5 serde_json sites are the wire boundaries (spec decode hooks driver.rs:164,263; the inspect-user payload round-trip effects_service.rs:83,90; one test helper); `InspectUserRequest::parse` is the hand-written admission gate over the canonical payload into closed contract types (per-card false-positive class), validating before any probe runs. - -## obs -- clean: seeds 0/1/0/1 - no println/eprintln/dbg; the single tracing event (probe.rs:76) is well-formed (`tracing::debug!` with named fields `user`/`group` and a literal message, not interpolation); no spans needed on the short async paths; no secret-shaped fields anywhere. - -## docs -- clean: seeds 29/0/24 - all 29 public items carry doc comments; the crate-level `#![deny(missing_docs)]` (lib.rs:5) enforces it, so the U1 card's "missing_docs not enabled anywhere" gate note does not hold for this crate; first sentences are one-line and non-narrative; the Result-returning surface (seed 3 = 24) is trait impls and private helpers whose contracts are documented at the seam (`UserDriverEffects::observe_user`, `UserDiscoveryEffectPort::discover`); no canonical-section gaps on user-facing items. - -## perf -- clean: seeds 1/8/2 - the 1 `format!` (effects_service.rs:483) is test-data construction; the 8 `Vec::new` sites are empty-by-construction fixtures and recorders (empty case is the common case); the 2 `to_string` are one-shot error stringification at the seam (effects_service.rs:225) and a test assertion; no hot-path allocation, no attacker-controlled hashing, no grow-by-push loops in production code. - -## conc -- d2b-provider-user#3 sev=medium blast=leaf effort=M verdict=policy-confirmed - the test-support recorder doubles and the driver's test fakes use `parking_lot::Mutex` (banned outright, KD3) at 20 `lock()` call sites with no `#[allow(clippy::disallowed_methods)]` on the enclosing items, while sibling `d2b-provider-host` uses `tokio::sync::Mutex` for the same recorder shape - fix: swap `parking_lot::Mutex` to `tokio::sync::Mutex` in `RecordingEffects`/`ScriptedProbe`/`RecordingManager`/`RecordingRequeue` (or add the sanctioned inline allow with reason "cfg(test) helper" at each site) so the deny-level flip needs no special case - [packages/d2b-provider-user/src/test_support.rs:41-42,108, packages/d2b-provider-user/src/driver.rs:469-470,563] - evidence: `\bMutex<|\bRwLock<` = 6 hits (all parking_lot, all test-support/test-fake); lock call sites: test_support.rs:60,65,76,83,130,151 and driver.rs:483,497,508,516,524,529,530,543,544,552,557,574,579,585; policy: clippy.toml:40 (KD3 ban), clippy.toml:82 (replacement tokio::sync::Mutex), U1 (d)4 sanctioned reason "cfg(test) helper"; the 9 async-gate-allow markers record the sites as deliberate async exceptions (cite, not re-flagged), but the clippy allow is absent -- d2b-provider-user#4 sev=low blast=leaf effort=S verdict=actionable - the scripted-double flags (`fail`, `absent`, `failing`) use `Ordering::SeqCst` though they are set and read within one test task on a single-threaded `#[tokio::test]` runtime, so the strongest ordering buys nothing - fix: use `Ordering::Relaxed` for the loads/stores in test_support.rs and driver.rs:854, per the weakest-correct-ordering rule - [packages/d2b-provider-user/src/test_support.rs:77,135,140,152,155, packages/d2b-provider-user/src/driver.rs:854] - evidence: `Atomic\w+|Ordering::` = 13 hits; 6 ordering uses, all `SeqCst`, all in test doubles; no cross-thread publish exists (flags are set and read in the same test task) -- clean: seeds 0/6/13/0 - no threads, no thread_local, no unsafe Send/Sync; production code holds no locks and shares no mutable state; the only shared state in the crate is the test-support recorders judged above. - -## async -- d2b-provider-user#5 sev=high blast=leaf effort=L verdict=policy-confirmed - the bounded probe's `discover_local_user` runs blocking NSS lookups (`nix::unistd::User::from_name`, `Group::from_gid`, `Group::from_name`) inside async fns on the plane's executor worker (driver reconcile via effects_service.rs:224, and the hosted `inspect-user`), so a slow or hung NSS backend (LDAP/NIS) stalls a runtime worker per call; `spawn_blocking` is itself banned (KD2) - fix: move the NSS reads onto a dedicated bounded worker in the `d2b-core` `loader_worker` shape (one thread, bounded sync_channel, oneshot replies) and have the probe await it - [packages/d2b-provider-user/src/probe.rs:48,63,72, packages/d2b-provider-user/src/probe.rs:40-79] - evidence: `async fn|async move|\.await` = 91 hits; reachability path is static and complete: driver.rs:342 -> effects_service.rs:224 -> probe.rs:28 -> probe.rs:48,63,72; `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0; policy: clippy.toml:112 (spawn_blocking banned, bounded-worker shape named as the replacement); the blocking-census baseline lists no NSS class for this crate, so the site is above any tracked set -- clean: seeds 91/0/0/21 - no spawn/JoinSet/select!/tokio::sync types; no guard held across an await (the recorder locks drop before every suspension point, per the async-gate-allow markers, which are deliberate exceptions cited in finding #3); the 21 `#[tokio::test]` harnesses are single-threaded and deterministic; cancellation-safety surface is minimal (no irreversible step between awaits in `reconcile`/`serve_inspect_user`). - -## unsafe -- N/A: seeds 0/0/0 all zero; no unsafe blocks/fns/impls and no `unsafe_code = "allow"` manifest (packages/d2b-provider-user/Cargo.toml sets `unsafe_code = "forbid"` under `[lints.rust]`). - -## ffi -- N/A: seeds 0/0/0/0 all zero; no extern boundary, no repr(C)/transparent, no CStr/CString - the crate crosses no foreign caller. - -## macro -- N/A: seeds 0/0/0/0 all zero; no macro_rules!/proc-macro definitions, no `$crate` uses (the crate only invokes std macros). - -## test -- d2b-provider-user#6 sev=medium blast=leaf effort=S verdict=actionable - the "cached unrealized phase re-discovers" contract is tested only for `Pending` (`reconcile_rediscovers_a_cached_unrealized_phase`), so a regression that widened the `observed_ready` short-circuit predicate (driver.rs:283) to accept `Degraded` or `Unknown` would pass every test - fix: extend the phase loop in `reconcile_publishes_the_user_discovery_projection` (driver.rs:789-813) to run a second reconcile per phase and assert the second `observe-user` call for all three unrealized phases - [packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs:281-284] - evidence: `#\[test\]|#\[tokio::test\]` = 25 (src+tests), `assert_eq!\(|assert_ne!\(|assert!\(` = 88; the `phase == ResourcePhase::Ready` predicate is pinned by no test for the non-Pending unrealized phases (the existing cached-phase test covers Pending only, and the phase-loop test stops after the first reconcile) -- clean: seeds 25/88/0/0 - 25 tests (12 driver, 9 effects-service, 4 registration) assert observable behavior (recorded call orders, status fields, failure classes, registry outcomes, wire payload fields) with human-written expectations; table-driven loops carry per-case failure messages; no `#[ignore]`, no property/snapshot tooling, no network or clock dependence; the registration boundary suite pins the descriptor contract (allowed sources, verbs, services, decoder, duplicate/late registration refusals). - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: 1 finding (seeds ran: 16/21/0/0) -- type: clean (seeds ran: 2/0/0) -- api: clean (seeds ran: 30/6/3) -- err: 1 finding (seeds ran: 46/0/2/1) -- serde: clean (seeds ran: 0/0/0/5) -- obs: clean (seeds ran: 0/1/0/1) -- docs: clean (seeds ran: 29/0/24) -- perf: clean (seeds ran: 1/8/2) -- conc: 2 findings (seeds ran: 0/6/13/0) -- async: 1 finding (seeds ran: 91/0/0/21) -- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe blocks and no unsafe_code = "allow" manifest - Cargo.toml sets forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero; no extern boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) -- test: 1 finding (seeds ran: 25/88/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md deleted file mode 100644 index be23d396f..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-binding.md +++ /dev/null @@ -1,73 +0,0 @@ -# d2b-provider-volume-binding - d2b-provider-volume-binding -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2900 (src 2739 + tests 161; no src/generated/**) | modules: driver, effects_service, facets, lib, row_readers, test_support; tests/registration.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single part) - -## idiom -- clean: seeds ran: for-index-0 | impl-manual-derive-0 | let-mut-accumulate-0 (all zero); the crate reads Rust throughout - iterator chains (row_readers projections, uid_hex byte fold, sort_by_key teardown ordering), edition-2024 let-chains (delete, parent_volume), derives on every plain value type, and BoundedToken newtypes at the wire boundary. - -## own -- d2b-provider-volume-binding#2 sev=low blast=leaf effort=S verdict=actionable - parsed_binding_spec clones the whole parsed spec object to end the as_object_mut() borrow before from_value (row_readers.rs:44), a clone a scoped block removes by letting `spec` move into the conversion - fix: bound the removal borrow in a block (let o = spec.as_object_mut()?; for f in [..] { o.remove(f); }) then serde_json::from_value::(spec) without Value::Object(object.clone()) - [packages/d2b-provider-volume-binding/src/row_readers.rs:38-44] - evidence: seed `\.clone\(\)` own=81 hits (per-file clone sites: row_readers 39/44, driver 286/288/378/382/449/657, rest in test-support and cfg(test) fixtures); of the non-test clones, only row_readers.rs:44 is avoidable - the rest are required (envelope raw copy, factory arg per create, error-detail string, sort key materialization). -- clean: seeds ran: clone (78 in src, most test-support/fixtures) | to_owned/to_vec/to_string | Arc appears only where ownership is genuinely shared (decoder factory return, facet set held by the driver), and the sole dependency type in a signature (Arc) is the shared decoder-factory convention used by every driver crate. - -## err -- d2b-provider-volume-binding#1 sev=medium blast=family effort=S verdict=actionable - BindingDriver re-parses the zone as a BoundedToken with a per-pass .expect (driver.rs:426-427) because BindingDriverArgs.zone: String (driver.rs:344) can represent a non-bounded zone, and the sole production caller already holds a BoundedToken (d2bd resource_plane_v3.rs:2954 inputs.zone.as_str().to_owned()), so the invariant is re-checked on every validate/reconcile/recover/delete pass where a parse-at-the-boundary would check it once - fix: store BoundedToken on BindingDriverArgs/BindingDriver (parse or construct once; ResourceKey::new(&self.zone.as_str(), ...), socket_identity(&self.zone)), deleting zone_bounded and its expect - [packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-binding/src/driver.rs:426-427, packages/d2bd/src/resource_plane_v3.rs:2954] - evidence: seed `\.unwrap\(\)|\.expect\(` err=76 hits, of which exactly one expect is production code reachable per verb (driver.rs:427; driver.rs:937 is the literally-built projection false-positive class); seed `let _ = ` = 1 site (driver.rs:1038, the deliberately ignored retirement bool, errors still propagated via ?); panic!/unreachable! only in cfg(test) match arms; census: BindingDriverArgs over packages/ = 1 production construction site (resource_plane_v3.rs:2954) plus tests/registration.rs and the driver test module. -- clean: seeds ran: unwrap/expect | let _ =/ok() | panic/unreachable/todo/unimplemented | enum Error = 0; the taxonomy (BindingDriverErrorKind with class() + failure_kind() mapping to the FailureKinds wire catalog) is a clean enum split by caller action, details carry FailureComparison context, no swallowed errors outside the documented fail-closed reads (row_readers .ok()?, reconcile guest_mount_ready unwrap_or(false)). - -## serde -- clean: seeds ran: derive-0 | serde-attr-0 | impl-Deserialize-0 | from_/to_-24 hits; the crate declares no serde derive of its own and crosses the wire only by consuming contract types (VolumeBindingSpec, VolumeBindingStatusResource) through serde_json from_slice/from_value/to_vec with explicit map_err into the typed error kinds; the two read-side projections fail closed on unparseable rows by design (documented), and parsed_binding_spec's reserved-envelope-field strip is covered by a dedicated test. No round-trip hazard: this crate holds no serde wire shape. - -## obs -- clean: seeds ran: println/eprintln-0 | interpolated-no-fields-0 | instrument-0 | tracing/log-1 hit; the single telemetry site is a structured tracing::warn!(plane = ?plane, key = %key, detail = %error_detail, ..) with named fields over a diagnostic detail, and no macro interpolates a message without fields; no secret-bearing field is logged. - -## docs -- d2b-provider-volume-binding#3 sev=low blast=leaf effort=S verdict=actionable - the four public Result-returning seam methods state no # Errors section (which conditions fail and how the driver classifies them): facets.rs SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, driver.rs BindingDriverEffects::remove_socket/guest_mount_ready - fix: add # Errors to each naming the daemon-adapter failure conditions and the fail-closed handling - [packages/d2b-provider-volume-binding/src/facets.rs:52, packages/d2b-provider-volume-binding/src/facets.rs:65, packages/d2b-provider-volume-binding/src/driver.rs:307-310, packages/d2b-provider-volume-binding/src/driver.rs:325-330] - evidence: docs seed `-> Result<` docs=58 hits; the four pub trait-method Result returns above are the only pub Result items whose doc comment lacks a canonical # Errors section (the crate runs #![deny(missing_docs)], which covers item presence, not section completeness); every other pub item has a one-line first sentence and the item list checks out. -- clean: seeds ran: pub-items-36 | canonical-sections-0 | -> Result< -58 hits; module docs (//!) present in all six modules, first sentences carry the load, deny(missing_docs) keeps every pub item documented, the BindingDriverError/Status internals stay pub(crate) so their detailed docs are not surface. - -## perf -- clean: seeds ran: format!-6 | Vec::new-7 | to_string-11 (raw match lines over src; most in cfg(test) fixtures); production format! sites are cold (uid_hex hex-spelling in error comparisons, status-projection paths), the Vec::new()s are construction-time/mandatory metadata buffers, and the only per-pass allocations (zone re-parse in zone_bounded, worker/endpoint child-spec rebuild in worker_child_specs) are static (unmeasured) and small - no hot-loop format!/to_string, no with_capacity opportunity named by any benchmark. - -## conc -- d2b-provider-volume-binding#4 sev=low blast=leaf effort=S verdict=actionable - the production [dependencies] compiles the KD3-banned parking_lot (clippy.toml:82 disallows its lock outright, revocation recorded) solely for the feature-gated/cfg(test) recording doubles, so every production consumer of this crate carries the banned crate in its lockfile; the per-site #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] permits the lock calls but not the manifest posture - fix: swap parking_lot::Mutex -> std::sync::Mutex in FakeServingEffects/RecordingManager/RecordingRequeue (the guards are already statement-scoped, so the sanctioned allows survive unchanged) and drop the Cargo.toml dependency, or gate it behind test-support as an optional dep - [packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-volume-binding/src/driver.rs:1139-1142, clippy.toml:82] - evidence: conc seed `\bMutex<` conc=24 hits, every one in test-support/cfg(test) recorders carrying async-gate-allow markers; census: zero locks, threads, or atomics in the non-test src files (driver.rs/effects_service.rs/facets.rs/row_readers.rs/lib.rs) - all synchronization is the recording doubles. parking_lot appears nowhere else in production scope (grep over packages/ for parking_lot in this crate lists only the manifest + test-support sites); the atomics use SeqCst on single-threaded scripted bools, which is harmless but not a finding class here. -- clean: seeds ran: thread-0 | Mutex-10 | Atomic/Ordering-14 | thread_local/unsafe-SendSync-0; the concurrency model is the simplest correct one for a stateless driver - no shared production state beyond the purchased Arc seam, the test doubles' locks are never held across an await (async-gate-allow recorded), and no ordering argument needs defending in two sentences. - -## async -- clean: seeds ran: async-141 hits | spawn/JoinSet/select-0 | tokio-sync-0 | tokio-main/test-13; no blocking work inside async contexts (all waits await trait seams; child-spec JSON builds are small and synchronous but not blocking I/O), no guard held across an await (the recorder locks are statement-scoped with async-gate-allow markers, and clippy deny await_holding_lock is on), the delete/finalize paths are documented idempotent under retry so cancellation mid-teardown converges, and the driver's only shared state (watched Vec, effects Arc) is never contended across tasks. - -## unsafe -- N/A: seeds ran: unsafe-block-0 | SAFETY-comment-0 | transmute/from_raw/MaybeUninit-0; the manifest sets unsafe_code = "forbid" and no block, fn, impl, or extern exists, so the lens never applies. - -## ffi -- N/A: seeds ran: extern/no_mangle/link_section-0 | catch_unwind-0 | repr(C)/transparent-0 | CStr/CString/c_char-0 all zero; the crate crosses no foreign boundary. - -## macro -- N/A: seeds ran: macro_rules-0 | proc_macro/syn/quote-0 | $crate-0 | to_compile_error/new_spanned-0 all zero; the crate defines no macros. - -## test -- clean: seeds ran: test-attr-13 | assert-120 | proptest/insta/rstest-0 | ignore-0; the suite is regression-targeted - F1 persist-before-spawn ordering, endpoint-first/process-last teardown, the fenced-projection currency rules (stale/foreign/ahead revisions), owner guard, absent-parent retry vs owner-mismatch terminal, argv-free worker child - asserted on error variants and FailureClass, never on Display strings; deterministic (scripted manager, no clock/network), and registration.rs is the policy-required declaration boundary shim. No #[ignore], no snapshot/property tooling, and no test that cannot fail was found. - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: 1 finding(s) -- type: clean (seeds ran: 0/0/0); the one stringly-typed field (driver.rs:344) is anchored under err#1 -- api: clean (seeds ran: 36/0/7 hits; single-path pub use surface, deliberate contract exports) -- err: 1 finding(s) -- serde: clean (seeds ran: 0/0/0/24 hits; no crate-local serde derives, contract types consumed at the boundary) -- obs: clean (seeds ran: 0/0/0/1 hits; one structured tracing::warn!, zero println) -- docs: 1 finding(s) -- perf: clean (seeds ran: 24 hits; format!/to_string sites test- or error/cold-path, static (unmeasured)) -- conc: 1 finding(s) -- async: clean (seeds ran: 141/0/0/13 hits; no blocking in async, no await-held guard, cancellation-safe teardown) -- unsafe: N/A (seeds: 0/0/0 all zero; unsafe_code = "forbid" manifest, no blocks/fns/impls) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) -- test: clean (seeds ran: 134 hits; behavior/ordering/variant assertions, no #[ignore]/proptest/insta/rstest) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md deleted file mode 100644 index f34b78b7b..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-local.md +++ /dev/null @@ -1,74 +0,0 @@ -# d2b-provider-volume-local - d2b-provider-volume-local -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10328 (excl. src/generated/**; src 8056 + tests 2272) | modules: whole crate (adapter, acl, atomic, bindings, content, controller, diagnostics, effect_port, error, finalization, identity, layout, lock, marker, port, quota, source, status, store_view, testing, views, lib) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- d2b-provider-volume-local#1 sev=low blast=leaf effort=S verdict=actionable - LayoutPhase::worse hand-rolls severity comparison with an `as u8` cast although the enum derives PartialOrd/Ord; the cast also silently depends on variant declaration order matching severity order - fix: replace the `if self as u8 >= other as u8` body with `self.max(other)` (derived Ord, declaration order Pending/Ready/Degraded/Failed already encodes severity) - [src/status.rs:33-38] - evidence: seeds: `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 8 (all legitimate accumulation loops with side-effect bodies or Read::read_to_end targets; no index loops exist); finding from full-file read of src/status.rs -- clean: the 8 `let mut ... Vec::new()` sites (adapter.rs:1539,1677,1803; content.rs:505,754; controller.rs:215,370; diagnostics/storage_lifecycle.rs:48) are the canonical read-to-end or side-effecting accumulation shapes the skill itself prefers over combinator chains; no hand-written derive candidates and no index loops found - -## own -- clean: seeds: `.clone\(\)` = 87, `.to_owned\(\)|.to_vec\(\)|.to_string\(\)` = 26, `Rc<|RefCell<|Arc delegation impl and adapter.rs:209 Arc in FdRootResolver, both required for the Send+Sync resolver seam), or test-fixture state (testing.rs:81 Mutex>); no borrow-checker-silencing clones found - -## type -- d2b-provider-volume-local#2 sev=low blast=leaf effort=M verdict=actionable - VolumeRootHandle carries ten Option fields that are valid only all-Some (from_anchored) or all-None (held), so eleven mixed states are representable; construction is internal today so the mixed states are unreachable, but the fail-closed root-identity handle is exactly where a future partial-construction bug would land - fix: split into a two-variant enum (e.g. `enum VolumeRootHandle { Empty, Anchored(AnchoredHandle) }`) or a typestate pair, keeping the non-Clone/non-Serialize property - [src/identity.rs:72-88, src/identity.rs:146-150] - evidence: seeds: `fn validate_\w+|fn check_\w+` = 10, `is_\w+: bool|\w+_flag: bool` = 1, `(mode|kind|state): String` = 5; the single bool (controller.rs:41 watched_configuration_is_dependency) and the five `mode: String` fields (content.rs:112,315,382,545,699) are not findings: the bool is a lone flag and the mode strings are schema-mirroring fields validated at construction (ContentFile::validate, content.rs:142-153) - the only illegal-state candidate is the handle -- clean: validate-at-callsite is confined to the wire boundary (validate_source_spec, controller validate_spec, EntryRequest::resolve) where the VolumeSpec contract type gives no guarantees, which is the parse-once pattern rather than a violation - -## api -- d2b-provider-volume-local#3 sev=medium blast=family effort=S verdict=actionable - `pub mod testing` (ScriptedPort with a Mutex, fixtures, hand-rolled block_on) is compiled unconditionally into the production library although it is consumed only by tests: this crate's tests/** and one d2bd test fn; the house pattern for cross-crate test support is a feature gate - fix: gate the module behind a `test-support` feature (`#[cfg(feature = "test-support")]` on `pub mod testing`, add `[features] test-support = []`), and enable the feature from d2bd's dev-dependencies - [src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1] - evidence: census: `volume_local::testing|ScriptedPort` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 26 hits, all in this crate's tests/** (layout_conformance.rs:9, store_view_and_swtpm.rs:3, views_and_sharing.rs:5, volume_effect_adapter.rs:122-493) and d2bd/src/resource_runtime.rs:12917 (inside a #[test] fn); no production code path imports it -- clean: api seed 2 (`pub .*\b(Arc|Rc|Box|RefCell)<`) = 0; the lib.rs `pub use` arms are the house single-surface pattern; public signatures carry only std types (BorrowedFd/OwnedFd in VolumeRootHandleView/AnchoredRoot, identity.rs:90-117) or contract-crate types; the adapter module double-path (pub mod adapter + root re-export) is referenced by cross-crate intra-doc links (d2b-provider-volume/src/facets.rs:18,50) and is covered by the re-export-arm false-positive note, so not flagged - -## err -- clean: seeds: `\.unwrap\(\)|\.expect\(` = 121 (every hit outside #[cfg(test)] is controller.rs:88 `BoundedToken::parse("volume-local").expect("frozen provider name")` on a literally-built value, the sanctioned class), `let _ = |\.ok\(\);` = 4 (adapter.rs:313 stub arg ignore, adapter.rs:1546 unused-arg ignore, adapter.rs:1778 best-effort unlinkat in remove_temp, diagnostics/storage_lifecycle.rs:110 drop cleanup - all deliberate), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 5; the five error enums (VolumeLocalError, AtomicWriteError, LockError, MarkerError, VolumeEffectError) are closed sets with stable lower-kebab `code()` accessors and Display rendering the code, matching the wire-code discipline; VolumeLocalError::ALL (29) matches the code() match arms - -## serde -- d2b-provider-volume-local#4 sev=medium blast=leaf effort=M verdict=actionable - ContentFile, ContentProjection, NetworkConfigContentProjection and the evidence types derive public Deserialize that bypasses the validating constructors: the crate's parse boundary is `from_value`/`from_settings` (which run validate), but the derived impl admits unvalidated projections directly, so the type the rest of the program trusts is not guaranteed valid on the derive path - fix: route the derive through `#[serde(try_from = "Raw...")]` mirror structs (wire shape unchanged: camelCase + deny_unknown_fields preserved) or drop Deserialize from the derives and parse only via the validating entries - [src/content.rs:38-39, 106-107, 203-204, 239-243, 536-537, 590-594] - evidence: seeds: `derive\([^)]*(De)?[Ss]erialize` = 24, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 19 (no try_from anywhere), `impl .*Deserialize.* for` = 0, `serde_json::from_|serde_json::to_` = 66; in-repo consumers all use the validating entries (d2bd/src/shared_provider_effects.rs:676,732 from_settings; d2bd/src/resource_plane_v3.rs:1507-1509 constructors), so the gap is the public derive itself -- clean: rename_all camelCase/kebab-case conventions are consistent per type family; deny_unknown_fields is present on every wire-mirroring struct; skip_serializing_if used correctly (status.rs:87); no hand-written Deserialize impls (the recorded-refusal admission-gate class does not appear here) - -## obs -- clean: seeds: `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::` = 23; every tracing event carries named fields (volume, path, error, reason, drift, entry, provider) with message-only text, e.g. adapter.rs:332-335, 740-743, controller.rs:232-245, lock.rs:250-253; redacted Debug impls (ContentFile, EntryDigest, VolumeRootHandle, SourcePolicyCatalog, VolumeRootIdentity, LockId) keep identifiers out of any field rendering; no secrets in fields - -## docs -- d2b-provider-volume-local#5 sev=low blast=leaf effort=M verdict=actionable - no canonical doc sections exist anywhere in the crate (seed 2 = 0 hits): public Result-returning items such as ContentFile::new, ContentProjection::new/from_value, EntryRequest::resolve, VolumeLocalController::reconcile, admit_attachments and validate_source_spec carry one-line docs but no `# Errors` section naming which conditions produce which failure - fix: add `# Errors` sections to the admission/parse constructors and the controller entry points, listing the closed VolumeLocalError variants each can return - [src/content.rs:118-125, src/controller.rs:148-154, src/layout.rs:54-57, src/views.rs:88-92, src/source.rs:130-131] - evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 319, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 104; `#![deny(missing_docs)]` (src/lib.rs:18) is already enforced so every public item has a first sentence; the gap is the canonical-sections shape only - -## perf -- clean: seeds: `format!\(` = 19, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 9, `\.to_string\(\)` = 26; every hit is a cold path (lock-id/temp-name/mode rendering at adapter.rs:1054,1706,1814; digest hex at content.rs:495-501,773; mount options at source.rs:253; test fixtures), a canonical read_to_end target, or wire-rendering; no format!/allocation inside any loop that runs per-entry on a hot reconcile path beyond the bounded digest preimage builders (content.rs:505,754, bounded by MAX_CONTENT_BYTES); static (unmeasured) - -## conc -- clean: seeds: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 1, `Atomic\w+|Ordering::` = 3, `thread_local!|unsafe impl (Send|Sync) for` = 0; the only production primitive is `static NEXT_TEMP: AtomicU64` with `fetch_add(1, Ordering::Relaxed)` (adapter.rs:1705,1710) - a counter nobody synchronizes on, so Relaxed is the weakest correct ordering and the static is justified for cross-instance temp-name uniqueness; the single Mutex (testing.rs:81) is test-fixture state - -## async -- clean: seeds: `async fn|async move|\.await` = 60, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0; the adapter's synchronous filesystem work runs at future-construction inside the async port methods (adapter.rs:327-369 `let result = self.observe_sync(...); async move { result }`), but every such site carries the sanctioned per-site allow `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` (adapter.rs:1666, 1520) and the crate is in the blocking census baseline (packages/xtask/data/blocking-census-baseline.json, all-zero counts), so the sync-in-async shape is recorded policy, not a new finding; the crate owns no runtime (testing.rs:29-33 hand-rolled block_on is the deliberate no-runtime design); controller awaits only port calls - -## unsafe -- clean: seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 22, `unsafe_code` = 1; the seed-3 hits are all false positives: `Mode::from_raw_mode`/`FileType::from_raw_mode` are rustix safe constructors (adapter.rs:673,696,932,1048,1107,1115,1235,1253,1530,1566,1571,1716,1743) and `MaybeUninit` appears only as a stack buffer handed to rustix RawDir without any unsafe access (adapter.rs:16,1468); the manifest forbids unsafe_code (Cargo.toml `[lints.rust]`) and no `unsafe_code = "allow"` exists, so the crate is outside the U1 (d)8 exception set - -## ffi -- N/A: seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign-language boundary (libc::flock struct literals at adapter.rs:1604-1610,1623-1629 are data passed to rustix's fcntl wrapper, not extern declarations) - -## macro -- N/A: seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macros are defined or used beyond std ones; the crate's repetition is handled by traits and generics - -## test -- clean: seeds (src + tests): `#\[test\]|#\[tokio::test\]` = 59, `assert_eq!\(|assert_ne!\(|assert!\(` = 300, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the suite asserts behavior and error variants rather than Display strings (e.g. tests/layout_conformance.rs asserts `Err(VolumeLocalError::EntryDrift)` and ConditionSeverity; tests/volume_effect_adapter.rs pins foreign-marker preservation and quarantine non-mutation with readback assertions), is table-driven with per-case messages (adapter.rs:1856-1860, tests/layout_conformance.rs:140-153), and is deterministic (tempdirs under CARGO_TARGET_TMPDIR, no network, no wall-clock dependence); no test computes its expectation with the code under test (the bindings.rs reordering test compares forward vs reordered-spec output, which is the determinism property itself); no ignored or unfailable tests found - -## Coverage -- idiom: 1 finding -- own: clean (seeds ran: 87/26/3/0) -- type: 1 finding -- api: 1 finding -- err: clean (seeds ran: 121/4/0/5) -- serde: 1 finding -- obs: clean (seeds ran: 0/0/0/23) -- docs: 1 finding -- perf: clean (seeds ran: 19/9/26) -- conc: clean (seeds ran: 0/1/3/0) -- async: clean (seeds ran: 60/0/0/0) -- unsafe: clean (seeds ran: 0/0/22/1; all seed-3 hits are from_raw_mode/MaybeUninit false positives, manifest forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) -- test: clean (seeds ran: 59/300/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md deleted file mode 100644 index e1851cf63..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume-virtiofs.md +++ /dev/null @@ -1,56 +0,0 @@ -# d2b-provider-volume-virtiofs - d2b-provider-volume-virtiofs -Baseline: 6ebdd4cec | LOC audited: 2,025 (excl. src/generated/**) | modules: whole crate (bindings, controller, error, lib, port, socket_path, testing, worker; tests/lifecycle.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) -## idiom -- clean: seeds all zero (for-loop index 0/0, hand-written derive-able impls 0/0, let-mut accumulation 0/0); hand-written Debug on SocketIdentity/StoredBinding redact deliberately and hand-written Serialize on SocketIdentity is the hex wire rendering; none are findings. -## own -- clean: seeds ran: 13/0/0/0; all 13 .clone() sites are explainable value copies (spec.clone() before mutating the envelope, uid.clone() into an owned fence, BoundedToken clone() into owned status reports, test-double snapshot clones after try_lock, plan/projection clones pushed into recorded history); no to_owned/Rc/RefCell/Arc/Arc/Cow. -## type -- clean: seeds ran: 0/0/1; the one hit (worker.rs:100 sandbox_mode: String) judges clean: WorkerSandbox::declared() is a one-shot admission gate over an adapter-reported posture,and assert_conformant() validates it once against the ADR 0021 frozen singleton before launch; an enum would make the misbehaving report unrepresentable instead of rejected, which is exactly the fail-closed check the controller must keep. -## api -- d2b-provider-volume-virtiofs#1 sev=low blast=leaf effort=S verdict=actionable - dead pub visibility on crate-internal items: resolve_view (controller.rs:23), SANDBOX_MODE (worker.rs:18), USER_NAMESPACE_MAPPING_CLASS (worker.rs:23), and WorkerSandbox plus its 3 pub fns (worker.rs:97,106,121,126) are declared pub in private modules,and never re-exported at lib.rs, so the pub is unreachable surface - fix: reduce to pub(crate)/private on those items, keeping the lib.rs re-export list as the single surface- - [packages/d2b-provider-volume-virtiofs/src/controller.rs:23, packages/d2b-provider-volume-virtiofs/src/worker.rs:97] - evidence: census: (resolve_view|WorkerSandbox|SANDBOX_MODE|USER_NAMESPACE_MAPPING_CLASS) over (packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel+*.bzl) =0 external hits (only in-crate uses; d2b-provider-volume-local resolve_view in views.rs:18 is a distinct symbol). -- d2b-provider-volume-virtiofs#2 sev=low blast=leaf effort=S verdict=actionable - pub mod testing exports 323 LOC of test doubles (ScriptedPort, PortCall, block_on, fixtures) unconditionally in the production lib with no feature gate, so tokio (sync) stays a runtime dependency purely for test support - fix: gate pub mod testing behind a test-support feature (with dep:tokio resolved for the feature), so the lib ships no test doubles and tokio goes conditional; keep testing.rs itself (lifecycle test uses the fixtures).- - [packages/d2b-provider-volume-virtiofs/src/lib.rs:42, packages/d2b-provider-volume-virtiofs/Cargo.toml:25] - evidence: census; (volume_virtiofs::testing) over (packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel+*.bzl) =0 external hits; sole consumer isthe crate own tests/lifecycle.rs:5; Cargo.toml has no [features] section, and tokio= { workspace = true, features = ["sync"] } under [dependencies].. -## err -- clean: seeds ran: 20/0/0/1; non-test unwrap/expect =2, both on literally-built invariants (BoundedToken::parse("volume-virtiofs").expect at controller.rs:44, StatusCode::parse(reason.code().expect at bindings.rs:237, whose grammar is asserted by the every_code test in error.rs); VirtiofsBindingError is a closed #[non_exhaustive] enum with code() plus ALL - clean shape; no swallowed Results, no panics. -## serde -- clean: seeds ran:3/7/0/3; Serialize-only wire outputs (BindingPhase kebab-case, BindingStatusReport camelCase with skip_serializing_if plus serialize_with, VirtiofsdWorkerPlan camelCase); the hand-written envelope parse is a live admission gate over serde_json::Value (per refusal ledger class), not a Deserialize impl; tests lifecycle.rs round-trips the report into JSON,and asserts the forbidden-fragment privacy pin. -## obs -- clean: seeds ran:0/15/0/15; all 15 events are tracing::warn!/debug! with named fields (binding, provider, reason, worker), % lazy forms, static messages; warn for handled failures,and debug for documented recurring steady states (cardinality comments); no println/eprintln, no secrets, no subscriber install. -## docs -- d2b-provider-volume-virtiofs#3 sev=low blast=leaf effort=S verdict=actionable - public Result-returning fns lack the canonical # Errors section even though rejection conditions are described in prose; from_resource_spec, worker_principal, worker_process_ref, endpoint_ref, resolve_view, reconcile, drain, for_binding, assert_conformant - fix; add a # Errors doc section to each listing the VirtiofsBindingError variant(s) it can return- - [packages/d2b-provider-volume-virtiofs/src/bindings.rs:122, packages/d2b-provider-volume-virtiofs/src/controller.rs:66, packages/d2b-provider-volume-virtiofs/src/worker.rs:64] - evidence: docs seed 3 (-> Result<) =14 hits across those fns; seed 2 (canonical sections) =0 hits -- d2b-provider-volume-virtiofs#4 sev=low blast=leaf effort=S verdict=actionable - VIRTIOFS_REPAIR_INTERVAL_SECS =30 documents what but not why; no rationale for the 30-second bound, while an external consumer (d2b-provider-volume-binding/src/driver.rs:112 BINDING_RESYNC) relies on it as its resync cadence - fix; extend the doc with one sentence naming the bound (e.g., matching the family repair cadence,or the socket-readiness deadline budget)- - [packages/d2b-provider-volume-virtiofs/src/controller.rs:19-20] - evidence: docs seed 3 (-> Result<) =14 hits; the const doc ends at "for virtiofs workers." with no why -## perf -- d2b-provider-volume-virtiofs#5 sev=low blast=leaf effort=S verdict=actionable - derive_child_ref builds the hex suffix with 10 per-byte format! allocations (digest[..10].iter().map(|byte| format!("{byte:02x}").collect::() onthe async reconcile path (twice per binding pass; worker_process_ref plus endpoint_ref), instead of one with_capacity String plus write!- fix; replace the per-byte format! chain with a String::with_capacity(20) plus write!/push_str hex loop (mirroring SocketIdentity::to_hex)- - [packages/d2b-provider-volume-virtiofs/src/bindings.rs:294-296] - evidence: static (unmeasured); perf seed 1 (format!() =4 hits of which 2 are this loop, 1 is worker_principal (cold), 1 is a test fixture -## conc -- clean: seeds ran:0/4/0/0; the 4 Mutex< hits are tokio::sync::Mutex inthe test double ScriptedPort (documented plan-U4 try_lock surface for sync consumers plus lock().await for async methods); no threads, atomsics, or manual Send/Sync inthe crate. -## async -- clean: seeds ran:27/0/0/0; async surface is controll controller.compute_report/reconcile/drain awaiting only injected effect-port futures (no locks held across awaits in production, no spawn/JoinSet/select, no blocking work, no runtime started in lib); testing.rs busypoll block_on is a documented plain-#[test] driver; the trait -> impl Future plus Send (over async fn) deliberately keeps the Send promise. -## unsafe -- N/A (seeds: 0/0/0/1 (seed 4 = unsafe_code = "forbid" in Cargo.toml:9; no unsafe_code="allow" manifest); seeds 1-3 all zero; card; seed 4 alone does not make lens applicable. -## ffi -- N/A (seeds: 0/0/0/0 all zero; no extern/no_mangle/CStr/repr boundary in this crate. -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!/proc-macro/$crate in this crate. -## test -- clean: seeds ran:27/~/0/0 (#[test] =27 (bindings 4, error 1, worker 4, lifecycle 18), assertions throughout (assert_eq!/assert!/assert_ne), proptest/insta/rstest =0, #[ignore] =0); the suite is hermetic (ScriptedPort doubles, block_on driver, no virtiofsd binary/socket/network), deterministic, behavior-focused (call ordering, phases, fence validity, delete-before-confirm, privacy fragments, ownership pins), asserts error variants not Display strings,and hangs meaningful failure messages; no test restates implementation. -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 13/0/0/0) -- type: clean (seeds ran: 0/0/1; judged admission gate, not a finding) -- api: 2 finding(s) -- err: clean (seeds ran: 20/0/0/1; non-test unwrap/expect both literally-built invariants) -- serde: clean (seeds ran: 3/7/0/3) -- obs: clean (seeds ran: 0/15/0/15) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 0/4/0/0; test-only tokio::sync::Mutex) -- async: clean (seeds ran: 27/0/0/0) -- unsafe: N/A (seeds: 0/0/0/1; seeds 1-3 all zero; unsafe_code=forbid, no allow manifest) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 27/assert-mass/0/0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md deleted file mode 100644 index a3f664c31..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-volume.md +++ /dev/null @@ -1,116 +0,0 @@ -# d2b-provider-volume - d2b-provider-volume -Baseline: 6ebdd4cec | LOC audited: 2,135 (excl. src/generated - none present) | modules: whole crate (driver, effects_service, facets, lib, test_support) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-provider-volume#1 sev=low blast=leaf effort=S verdict=actionable - `reconcile` converts the provider facet via `serde_json::to_value(value).unwrap_or(serde_json::Value::Null)` where the value is already a `serde_json::Value`: a serialization round trip plus dead `unwrap_or` fallback for an infallible conversion - fix: replace with `envelope.base.get("provider").cloned()` - [driver.rs:607-609] - evidence: idiom seeds 0/0/0 (index loops, hand impls, statement accumulation absent) + static read of the site;`to_value::` on a `&Value` is a deep copy the value's own `Clone` already performs, so the serialization path adds only a dead `Result`. -- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0; the crate's loops iterate (reconcile_children over `desired`, tests over rows), no hand-written derive-replaceable impls, no statement-style accumulators. - - - -## own -- d2b-provider-volume#2 sev=low blast=leaf effort=S verdict=actionable - `decoded_spec` returns `(envelope.clone(), spec)` though the local `envelope` is never used after the clone:an avoidable `Vec` raw-spec copy on every driver op (validate, recover, reconcile, delete) - fix: return `(envelope, spec)` directly - [driver.rs:337] - evidence: own seed `\.clone\(\)` = 35 over src; this site is the only redundant clone outside cfg(test)/test-support (redundant_clone-class; the envelope's later borrow (building `spec`) ends before the return, so ownership can move). -- d2b-provider-volume#3 sev=low blast=wide effort=M verdict=actionable - `desired_binding_intents` takes `ResourceRef` by value though it only reads it (cloning into each `BindingIntent` internally), so every production caller must clone first: driver.rs:380 and d2bd/src/resource_runtime.rs:5882,12921 - fix: change the signature to `&ResourceRef` in `d2b-provider-volume-local/src/bindings.rs:80`, drop the caller clones (callers pass `&volume_ref`) - [driver.rs:380, d2b-provider-volume-local/src/bindings.rs:80-81, d2bd/src/resource_runtime.rs:5882,12921] - evidence: own seed `\.clone\(\)` = 35 over src + census `desired_binding_intents` over packages/ = 11 hits (3 production call sites + 8 volume-local test sites); the callee stores owned refs into each intent, so taking the arg by value buys nothing over a borrow. - -- clean: seeds `\.clone\(\)`=35, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=28, `Rc<|RefCell<|Arc` return matches sibling decoders in process/host/user/guest crates,and `VolumeEffectFacets.runtime` is the daemon-supplied facet set shared by the driver effects and the hosted service (U7); no leaked dependency types in public signatures. - - - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(`=35, `let _ = |\.ok\(\);`=4, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\\(`=4, `enum \w*Error`=1; all unwrap/expect hits are in cfg(test) modules or test-support doubles(`RefusingRuntime` panics loudly by design); the only non-test `let _ =` is driver.rs:516 on a fire-and-forget completion send (an unbounded-channel send to a possibly-dropped actor mailbox, no caller remains to notify);`VolumeDriverErrorKind` is a private 6-variant taxonomy split by caller action with `class()`/`failure_kind()` mappings (R13, issue #508). - - - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize`=0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=0, `impl .*Deserialize.*for`=0, `serde_json::from_|serde_json::to_`=8; the 8 hits are boundary reads/writes over contract-crate types (`ResourceSpec`, `VolumeSpec`, fixtures), no serde attrs or hand-written deserializers in this crate, validation lives in the typed decoder plus `check_provider` (runtime gate). - - - - - -## obs -- N/A: seeds `\bprintln!\(|\beprintln!\\(`=0, `(info|debug|warn|error|trace)!\(`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=0; crate has no tracing/log dependency, so there is no telemetry to judge. - - - -## docs -- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)`=20, `^\s*/// # (Examples|Errors|Panics|Safety)`=0, `-> Result<`=35;`#![deny(missing_docs)]` is active in lib.rs:5, all 20 pub items carry first-sentence docs, VOLUME_RESYNC's 30-second magic is documented with the why (driver.rs:65-77), the 4 Result-returning pub trait methods document what the bool/unit contract reports (the `String` error is an opaque note the caller passes through, not a match surface, so `# Errors` would narrate nothing); no `# Examples` needs (`VolumeRuntime` has no doctests andits use is composition-root wiring, documented therein). - - - -## perf -- d2b-provider-volume#5 sev=low blast=leaf effort=S verdict=actionable - `reconcile` performs two identical `ctx.children()` manager round-trips per pass:`reconcile_children` already fetched the owned child set after ensures (to retire obsolete),andthen `reconcile` re-fetches the same set to compute `converged` - an extra manager RPC per reconcile pass - fix: have `reconcile_children` return the fetched `Vec` (or compute the converged verdict inside)and consume it there - [driver.rs:437-440,614-617] - evidence: static (unmeasured);`ctx.children()` routes to `self.ager.list_owned)...).await` (d2b-resource-runtime/src/context.rs:586-588), a per-call manager RPC; between the two calls no other actor can mutate this owner's rows (driver-owned children only, row actor is single-threaded), so the second fetch returns identical data. - - - -- clean: seeds `format!\\(`=5, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=7, `\.to_string\(\)`=1; all hits are cfg(test) helpers (`format!` recording keys in RecordingManager, malformed-spec fixture bytes) or required empty field defaults (`ChildEnsure.metadata`), no hot-path allocation sites. - - - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=3, `Atomic\w+|Ordering::`=18, `thread_local!|unsafe impl (Send|Sync) for`=0; the 3 Mutex hits are test-support recorders (`RecordingRuntime.calls`, `RecordingManager.log/rows`) sanctioned with `async-gate-allow: test-support recorder lock` markers and cfg(test)-helper allows; the AtomicBool flags use SeqCst deliberately (they publish a layout state read once per 30-s-cadence pass,and the cost is negligible per the skill's "SeqCst when unsure"), no threads are spawned by this crate (task concurrency belongs to async lens). - - - - - -## async -- clean: seeds `async fn|async move|\.await`=100, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\\(`=1, `tokio::sync::(Mutex|RwLock|Notify)`=0, `#\[tokio::(main|test)\]|Runtime::block_on`=13; the single `tokio::spawn` (driver.rs:512-535) is the documented layout-effect spawn (R5/KTD12: mailbox never blocks; completion arrives as `EffectCompleted` and a degraded report flows into the actor's retryable requeue), no guards are held across awaits in src (`tokio::sync` unused), the trait bounds `Send + Sync + 'static` make the spawned future Send-safe, the send on the unbounded channel is non-blocking so the irreversible step cannot be lost to cancellation. - - - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=0, `unsafe_code`=0 (over src\); crate manifest forbids `unsafe_code`, so no unsafe sites exist. - - - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0; the crate crosses no foreign boundary. - - - -## macro -- N/A: seeds `macro_rules!`=0, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; no macro definitions or proc-macro usage (std macros only). - - - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]`=18 (14 src + 4 tests/registration.rs), `assert_eq!\(|assert_ne!\(|assert!\\(`=67, `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0; tests are behavioral throughout: effect-order and commit-before-spawn (F1), deterministic child identity with no churn, adoption re-validates layout idempotently, degraded layout reports exactly one retryable failure per pass, finalize-before-delete drain ordering, idempotent delete retryarry, wire-pinned canonical payload bytes (`the_has_layout_wire_payloads_are_canonical`), error variants asserted via `matches!`/eq on the enum not Display strings, registration tests pin the declaration's verbs/creations/services against human-written expectations; no property/snapshot tooling is needed for this scale (unit + integration coverage is complete for the flows named), no ignored tests. - - - -## Coverage -- idiom: 1 finding -- own: 2 finding(s) -- type: clean (seeds ran: 1/0/0; the one gate is deliberate to keep the two wire error codes distinct) -- api: 1 finding -- err: clean)(seeds ran: 35/4/4/1; all panics are in tests/test-support; the alone `let _ =` is a fire-and-forget completion send) -- serde: clean)(seeds ran: 0/0/0/8; boundary reads over contract-crate types only) -- obs: N/A)(seeds ran: 0/0/0/0; no tracing/log dep) -- docs: clean)(seeds ran: 20/0/35;`deny(missing_docs)` active and pub items documented) -- perf: 1 finding -- conc: clean)(seeds ran: 0/3/18/0; test-support recorders + deliberate SeqCst flags) -- async: clean)(seeds ran: 100/1/0/13; single documented effect spawn; no guards across awaits) -- unsafe: N/A)(seeds ran: 0/0/0; no unsafe sites;`forbid` in manifest) -- ffi: N/A)(seeds ran: 0/0/0/0) -- macro: N/A)(seeds ran: 0/0/0/0) -- test: clean)(seeds ran: 18/67/0/0 incl. tests/; behavioral unit+registration suite, no ignored/property tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md deleted file mode 100644 index 949b3b784..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-wayland-policy.md +++ /dev/null @@ -1,103 +0,0 @@ -# d2b-provider-wayland-policy - d2b-provider-wayland-policy -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3974 (src 3247 + tests 727; excl. src/generated/**, none present) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- clean: seeds ran: 0/0/0; no index loops over `0..`, no hand-written `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`, no `let mut ... = String/Vec::new()` accumulation. One hand-written `Debug` for `AudioResourceRuntime` (audio_registry.rs:142) was read and judged a deliberate state-summary (counts only, not the mediator handle/map bodies), acceptable for the internal state-holding type. - - - -## own -- clean: seeds ran: 32/17/0/0; every one of the 32 `.clone()` lines is explainable: struct/field construction into owned values, `serde_json` Value edits from borrowed refs (`from_value` takes ownership), Arc clones at the genuine shared-ownership boundaries (factory `create` per driver, six drivers' shared effects port, per-zone audio registry handle),test fixtures; the 17 to_owned/to_vec/to_string lines are string/byte construction and test data; no `Rc`/`RefCell`/`Arc` sites are genuine shared ownership or sanctioned exports: `spec_decoder`/`wayland_policy_spec_decoder` return the manager-held `Arc` (call sites: wayland_policy.rs:86, tests/engine.rs:304, tests/registration.rs:62),`InteractionDriverArgs.effects` is the six drivers' shared effects port (effects_service.rs:85-87; factory clones it per create at interaction.rs:471),feature-gated `test_support::Log` is consumed by tests (repo false-positive class),and the `pub(crate) fn *() -> &Arc<...>` facet accessors are crate-internal. The `pub use` re-export arms (lib.rs:47-70) form the house single-surface pattern;`#![deny(missing_docs)]` (lib.rs:28) forces doc presence on every public item. - - - -## err -- d2b-provider-wayland-policy#1 sev=high blast=family effort=M verdict=actionable - Panic reachable from caller input at the family engine's public boundary: `InteractionDriver::new` parses-and-expects `InteractionDriverArgs.zone: String` (pub field on pub struct with no validating constructor),and `key_ref` parses-and-expects a `ResourceKey` whose `new` accepts any strings; both invariants claimed in expect messages are not enforced by the types - fix: parse once at the args boundary (change `args.zone` to a parsed `ZoneId`, or make `InteractionDriver::new` return `Result<_, InteractionDriverError>`) and make `key_ref` return `Result` (map to `SpecInvalid`) or enforce name canonicality at `ResourceKey::new` in d2b-resource-runtime - [packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-wayland-policy/src/interaction.rs:488, packages/d2b-provider-wayland-policy/src/interaction.rs:836-838, packages/d2b-resource-runtime/src/spec_store.rs:60-63] - evidence: seed `\.unwrap\(\)|\.expect\(` = 43 lines over src (most in `#[cfg(test)]`/`test-support`; the two production sites above are the panics); census: `ResourceKey::new` (spec_store.rs:60-63) builds the three String fields unvalidated; route: review-pass - -- clean: seeds ran: 43/0/0/3 after removing the test-module noise; the other production expects are infallible (`expect("fixed digest width")` on a literal 8-byte slice, test-support fixed refs`, and enums are the error taxonomy (AudioResourceRuntimeError, InteractionEffectError, InteractionDriverError),closed and split by caller action (retryable vs terminal classes at interaction.rs:160-174`. - - - -## serde -- d2b-provider-wayland-policy#2 sev=medium blast=family effort=M verdict=actionable - Every wire-parse failure collapses into a bare `InvalidResource` variant that discards the serde reason, so an operator cannot tell which row or which field is malformed (a third of the enum's refusals are spec-shape checks that reuse the same variant) - fix: add a reason-carrying variant to `InteractionEffectError` and `AudioResourceRuntimeError` (e.g. `InvalidResource { reason: String }` or `Decode(#[source] serde_json::Error)` via thiserror)and thread it through the ~15 `map_err(|_| ...InvalidResource)` sites (the enum Display codes are not pinne in `docs/reference/error-codes.md` - grep "interaction" = 0 hits - so not wire-contract) - [packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-wayland-policy/src/effects_service.rs:205-206, packages/d2b-provider-wayland-policy/src/audio_registry.rs:517-534] - evidence: seed `serde_json::from_|serde_json::to_` = 23 lines; every parse failure maps to a bare InvalidResource (or the empty `InteractionSpecDecodeError` at interaction.rs:269-270; serde derive/attribute/impl seeds are 0/0/0 - parse-only boundary, so the serde reason loss is the boundary flaw. - - - -## obs -- obs: N/A (seeds: 0/0/0/0 all zero; no `tracing`/`log` dependency in Cargo.toml - the crate cross neither logging surface) - - - -## docs -- d2b-provider-wayland-policy#3 sev=low blast=leaf effort=S verdict=actionable - Result-returning public items lack `# Errors` canonical sections, so callers must infer which conditions produce `InvalidResource` vs `Unavailable` (the terminal-vs-retryable mapping at interaction.rs:632-636 is non-obvious) - fix: add `# Errors` sections to `base_spec`, `spec_with_provider_ref`, `shell_pool_spec`, `shell_session_execution`, `shell_session_pool_ref`, `owned_child_ensure`, `binding_child_ensure`, and the two `InteractionDriverEffects` methods - [packages/d2b-provider-wayland-policy/src/interaction.rs:241, packages/d2b-provider-wayland-policy/src/vocabulary.rs:35, packages/d2b-provider-wayland-policy/src/interaction.rs:342] - evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)` = 66;`/// # (Examples|Errors|Panics|Safety)` = 0;`-> Result<` = 68 lines; the crate opted in to `#![deny(missing_docs)]` (lib.rs:28),so canonical sections are the next consistency step (the missing-docs lint is per-crate, contrary to the blanket "not enabled anywhere" note in U1) - - - -## perf -- clean: seeds ran: 3/12/0; the three `format!` sites are test-support log pushes (test_support.rs:172,190)and the cold `key_ref` string build (interaction.rs:837);`Vec::new()`/`BTreeMap::new()` are empty-start constructors of long-lived registries and test data; no allocation in a reconcile/effect hot path (per-reconcile serde Value clones at interaction.rs:242,252 are cold, one per row pass); static (unmeasured) - - - -## conc -- clean: seeds ran: 0/2/9/0; the two `Mutex<` lines are `tokio::sync::Mutex` guards for the per-zone audio registry (audio_registry.rs:413)and the test log (test_support.rs:127) - async-appropriate (guard spans a sync registry call, dropped at statement end; no std::thread/spawn/scope anywhere; the 9 atomic/Ordering lines are test-double flags (`AtomicBool`/`AtomicUsize`, SeqCst on plain scripted booleans - harmless and test-only) - - - -## async -- clean: seeds ran: 94/0/4/0; all awaits are facet/plane/manager trait reads and the two tokio Mutex guards; no `tokio::spawn`/`spawn_blocking`/`JoinSet`/`select!`/`join!` hits (this engine's design: no spawn surface, documented at interaction.rs:20-23); no blocking std call in an async body; the reconcile/delete/watch loops mutate through idempotent manager verbs with await-per-step ; cancellation-safe (no lock held across `.await` beyond the statement); no `#[tokio::main(test]`/`Runtime::block_on` in src - - - -## unsafe -- unsafe: N/A (seeds: 0/0/0/0; local `[lints.rust]` `unsafe_code = "forbid"` in Cargo.toml - the crate is fully safe) - - - -## ffi -- ffi: N/A (seeds: 0/0/0/0; no extern/repr/CStr surface in the crate) - - - -## macro -- macro: N/A (seeds: 0/0/0/0; no macros defined, no proc-macro/syn/quote usage) - - - -## test -- d2b-provider-wayland-policy#4 sev=low blast=leaf effort=S verdict=actionable - Dead no-op line in `the_policy_envelope_is_the_whole_contract`: `let _ = ResourceRef::parse)...)` asserts nothing and cannot fail - fix: assert the parse succeeds (e.g. `.expect("the policy reference parses")`), or delete the line - [packages/d2b-provider-wayland-policy/tests/registration.rs:93] - evidence: static read; `Result` is discarded with no assertion; the surrounding test already covers the decoder refusal paths at registration.rs:92 - -- clean: seeds ran: 25/75/0/0; the suite is behavior-focused: assertions carry messages and cite regressions (e.g. "Regression (P2)" at effects_service.rs:746-752),the recording-manager harness makes ordering assertions on log entries with context,no proptest/insta/rstest and no `#[ignore]` (deterministic fixtures, injected time, no network/clock); the `#[allow(clippy::disallowed_methods, reason = "cfg(test helper")]` sites use the sanctioned reason - - - -## Coverage -- idiom: clean (0/0/0) -- own: clean (32/17/0/0) -- type: clean (3/0/0) -- api: clean (70/6/5) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: N/A (0/0/0/0; no tracing/log dep) -- docs: 1 finding(s) -- perf: clean (3/12/0) -- conc: clean (0/2/9/0) -- async: clean (94/0/4/0) -- unsafe: N/A (0/0/0/0; forbid) -- ffi: N/A (0/0/0/0) -- macro: N/A (0/0/0/0) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md deleted file mode 100644 index 394f69029..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider-zone-link.md +++ /dev/null @@ -1,81 +0,0 @@ -# d2b-provider-zone-link - d2b-provider-zone-link -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3805 (excl. src/generated/**) | modules: whole crate (lib.rs, driver.rs, zone_links.rs, zonelink.rs; tests/registration.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- d2b-provider-zone-link#1 sev=medium blast=family effort=S verdict=actionable - the frozen cryptoperiod defaults `BOOTSTRAP_PSK_TTL_MS_DEFAULT` (300_000) and `KK_SESSION_MAX_LIFETIME_MS_DEFAULT` (86_400_000) are defined identically in two crates with no shared home, so a drift silently desynchronizes the child-local handler from the bus-side enrollment machine - fix: move both constants to `d2b_contracts_zone_session` (the crate both `d2b-provider-zone-link` and `d2b-bus` already depend on) and re-export from both sites; this is not the refused ZoneLink enrollment-machine merge, only the two constants - [packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/zone_links.rs:63, packages/d2b-bus/src/session/enrollment.rs:42, packages/d2b-bus/src/session/enrollment.rs:49] - evidence: census: `BOOTSTRAP_PSK_TTL_MS_DEFAULT|KK_SESSION_MAX_LIFETIME_MS_DEFAULT` over packages/nixos-modules/tests/docs/reference/labs = 2 defining sites with identical values (zone_links.rs:60,63 and d2b-bus/src/session/enrollment.rs:42,49); the refused class in docs/explanation/over-engineering-audit-record.md is the enrollment-machine merge, not these constants -- clean: seeds ran 2/2/1; the two `impl Default` hits (zone_links.rs:305,338) deliberately preserve frozen nonzero defaults a field-wise derive would break; the `Vec::new()` accumulation (zone_links.rs:1422) is the match-arms planner pattern; the two `for .. in 0..` loops (zone_links.rs:2012,2828) are test drivers - -## own -- d2b-provider-zone-link#2 sev=low blast=leaf effort=S verdict=actionable - `plan()` clones `record.route_binding` in the `RoutePolicyCommitted` and `SessionGenerationAdvanced` arms only to mutate it and store it back, where a `route_binding.as_mut()` borrow would work (no other borrow of the record is live in either arm) - fix: replace `let Some(mut binding) = record.route_binding.clone() else ...` with `let Some(binding) = record.route_binding.as_mut() else ...` and mutate through the borrow in both arms - [packages/d2b-provider-zone-link/src/zone_links.rs:1692, packages/d2b-provider-zone-link/src/zone_links.rs:1706] - evidence: seed `\.clone\(\)` = 50 hits; the 1663/1682 clones are required (binding moves into `ZoneLinkRouteAdmissionContext`, operation id is re-inserted after comparison), the 1418 record clone is the deliberate copy-on-write pass design, the 815-820 clones feed an owned wire struct, 1269 feeds an owned status projection; only 1692/1706 are avoidable -- d2b-provider-zone-link#3 sev=low blast=leaf effort=S verdict=actionable - `plan()` clones `record.enrollment` in the `EnrolledSessionEstablished` arm solely to compare the key fingerprint before mutating disjoint record fields - fix: take `record.enrollment.as_ref()`, compare `enrollment.key_fingerprint() != &peer_key_fingerprint` (fingerprint tokens are Copy), and let the borrow end before the `record.link_epoch += 1` mutation - [packages/d2b-provider-zone-link/src/zone_links.rs:1526] - evidence: seed `\.clone\(\)` = 50 hits; the arm mutates only `link_epoch`/`connected`/`child_authorized`/`reconnect_attempts`/`advertised_routes`, all disjoint from `enrollment`, so the clone buys nothing -- clean: seeds ran 50/3/0; the three `to_*` hits and the remaining clones are test fixtures (zonelink.rs:350,367,401,429-523; zone_links.rs:1948-2135); no `Rc`/`RefCell`/`Arc`/`Cow` anywhere; the `AtomicU64` owner-token static is a process-wide counter with no single owner - -## type -- clean: seeds ran 1/0/0; the single `fn validate_` hit (`validate_commit_proof`, zone_links.rs:1402) is an internal invariant check on an opaque token with no public constructor, not input validation a parsed type could replace; no boolean-flag soup or stringly-typed state (the record's `disabled`/`connected`/`child_authorized` booleans mirror pinned spec fields - schema-mirroring false positive); the commit-before-effect protocol is already typestate-enforced via `ZoneLinkPass` (no Clone/Copy) and `ZoneLinkCommitProof` (no public constructor) - -## api -- d2b-provider-zone-link#4 sev=low blast=leaf effort=S verdict=actionable - `ZoneLinkMetricSample` and `ZONE_LINK_METRIC_LABEL_KEYS` are exported pub (and re-exported through `zonelink`) but have zero consumers outside the crate, so the metric vocabulary is promised surface nobody wires - fix: either consume them from `d2bd`'s metrics path or reduce to `pub(crate)` until a consumer exists - [packages/d2b-provider-zone-link/src/zone_links.rs:1783, packages/d2b-provider-zone-link/src/zone_links.rs:89, packages/d2b-provider-zone-link/src/zonelink.rs:13] - evidence: census: `ZoneLinkMetricSample|ZONE_LINK_METRIC_LABEL_KEYS` over packages/nixos-modules/tests/docs/reference/labs = 0 hits outside the crate (only in-crate tests at zone_links.rs:3092-3107 and the re-export) -- d2b-provider-zone-link#5 sev=low blast=leaf effort=S verdict=actionable - `transport_error_is_quarantine` is a `pub const fn` with zero callers anywhere, including in-crate tests, so it is dead exported surface - fix: make it private or delete it until the quarantine mapping is actually consumed - [packages/d2b-provider-zone-link/src/zonelink.rs:281] - evidence: census: `transport_error_is_quarantine` over packages/nixos-modules/tests/docs/reference/labs = 0 hits outside its definition -- d2b-provider-zone-link#6 sev=low blast=leaf effort=S verdict=actionable - `ZoneLinkCursorAuthority` is `pub` but is only reached through `ZoneLinkController` in the same module and the module's own tests, so its publicity is wider than its use - fix: reduce to `pub(crate)` - [packages/d2b-provider-zone-link/src/zonelink.rs:178] - evidence: census: `ZoneLinkCursorAuthority` over packages/nixos-modules/tests/docs/reference/labs = 0 hits outside the crate; `d2bd/src/composition.rs:770,891` consumes `ZoneLinkController` only -- clean: seeds ran 133/0/5; no `Arc`/`Rc`/`Box`/`RefCell` in any public signature; the lib.rs `pub use ...::*` arms are the house single-surface pattern; the `pub(crate)` + `#[cfg(test)]` accessors on `ZoneLinkRouteAdmissionContext` and `ZoneLinkHandler::route_admission_context` are correctly scoped; the crate root surface is consumed by `d2bd/src/composition.rs` (86-896, 1118-1172) and `d2bd/src/resource_plane_v3.rs:153` - -## err -- clean: seeds ran 115/0/0/2; all 115 `unwrap`/`expect` hits sit in `#[cfg(test)] mod tests` helpers (zone_links.rs:1817-1945, zonelink.rs:350-527) - the card's test-code false positive; zero panic macros, zero swallowed `Result`s, zero production unwraps; the two error enums (`ZoneLinkError` 26 variants, `ZoneLinkAdoptionError` 4 variants) are closed, Copy, and carry stable kebab-case `label()` tokens asserted bounded by `every_error_label_is_a_bounded_lowercase_token` (zone_links.rs:3131); the cross-crate label reuse via `ZoneRouteFailClosedReason` (zone_links.rs:224,232) avoids duplicated wire tokens - -## serde -- clean: seeds ran 1/1/0/2; the only serde surface is the private durable envelope `ZoneLinkRouteAdmissionDedupWire` (zone_links.rs:697-704) with `rename_all = "camelCase"` + `deny_unknown_fields`, a version field checked on recovery, canonical-bytes enforcement (zone_links.rs:822-826, 845-847), and identity binding; round-trip, version-mismatch, and identity-mismatch paths are covered by `multiple_committed_route_ids_survive_versioned_restart_recovery` (zone_links.rs:2036) and `aborted_route_ids_are_reusable_but_recreated_identity_is_isolated` (zone_links.rs:2097); no hand-written `Deserialize`, no `flatten`, no untagged - -## obs -- N/A: seeds 0/0/0/0 all zero; the crate has no `tracing`/`log` dependency (Cargo.toml deps: d2b-contracts-resource, d2b-resource-types, serde, d2b-contracts-zone-session, serde_json; tokio is dev-only), and the module is a pure planner with no telemetry surface - -## docs -- d2b-provider-zone-link#7 sev=low blast=leaf effort=M verdict=actionable - 21 public `Result`-returning items document their failure modes only in prose, with zero `# Errors` sections, so the error contract (which `ZoneLinkError` variant fires) is not in the canonical place a caller reads - fix: add `# Errors` sections naming the `ZoneLinkError`/`ZoneLinkAdoptionError` variants to the public `Result` items, starting with `ZoneLinkLimits::new`, `ZoneLinkHandler::{begin,commit,release_effects,issue_route_admission}`, `ZoneLinkRecord::{with_route_binding,encode_route_admission_dedup,with_route_admission_dedup}`, `ZoneLinkOwnerProof::{new,from_digest}`, `ZoneLinkCursorAuthority::{adopt,cursor}` - [packages/d2b-provider-zone-link/src/zone_links.rs:267, packages/d2b-provider-zone-link/src/zone_links.rs:1300, packages/d2b-provider-zone-link/src/zonelink.rs:197] - evidence: seeds ran 131/0/21 (131 public items, 0 canonical sections, 21 `-> Result<`); every public item carries a first-sentence doc comment, module docs exist in all four files, and the redaction `Debug` impls are deliberate (tested at zone_links.rs:3115) -- clean: seeds ran 131/0/21; no undocumented public item found; the `ZoneLinkKeyPolicy` "locked six-field schema" doc (zone_links.rs:335-337) is accurate - the ZoneLink spec has exactly six fields (childZoneName, disabled, limits, transportCredentials, transportProviderRef, transportSettings per docs/reference/schemas/v3/core.d2b.org_ZoneLink.schema.json) - -## perf -- clean: seeds ran 3/1/2; all six hits are test-only (`format!` at zone_links.rs:1963,3119 and zonelink.rs:350; `to_string` at zone_links.rs:1977,3168 and zonelink.rs:350; `Vec::new` at zone_links.rs:1422); production has no `format!`/`to_string` and the only allocation in the reconcile path is the deliberate copy-on-write record clone in `plan()` (cold per-event path); `static (unmeasured)` - no benchmark exists for this crate - -## conc -- clean: seeds ran 0/0/3/0; the three hits are the `AtomicU64` owner-token generator (zone_links.rs:35,48,52) using `Ordering::Relaxed` on a counter nobody synchronizes on - the weakest correct ordering per the skill; no `Mutex`/`RwLock`, no threads, no `thread_local!`, no manual `Send`/`Sync` impls - -## async -- N/A: seeds 0/0/0/0 all zero over src/; the crate is a synchronous planner - no `async fn`, no `tokio::spawn`, no `tokio::sync` in src; tokio appears only as a dev-dependency for the single `#[tokio::test]` registration shim (tests/registration.rs:11), which is the test lens's territory - -## unsafe -- N/A: seeds 0/0/0/0 all zero; no `unsafe` blocks/fns/impls, no `transmute`/`from_raw`/`MaybeUninit`, no `// SAFETY:` sites; the manifest sets `[lints.rust] unsafe_code = "forbid"` (Cargo.toml:7), and the crate is not on the (d) 8 exception list - -## ffi -- N/A: seeds 0/0/0/0 all zero; no `extern "C"`, no `no_mangle`, no `repr(C)`/`repr(transparent)`, no `CStr`/`CString` - the crate crosses no foreign boundary - -## macro -- N/A: seeds 0/0/0/0 all zero; no `macro_rules!`, no proc-macro/syn/quote, no `$crate`, no `to_compile_error` - the crate defines no macros - -## test -- d2b-provider-zone-link#8 sev=low blast=leaf effort=S verdict=actionable - three table-driven loops assert without a per-case failure message, so a failing row reports only a line number, not which state/error/key failed - fix: add messages naming the loop variable (`"state: {state:?}"`, `"key: {key}"`, `"error: {error:?}"`) to the loops at zone_links.rs:2513-2519, 3092-3094, and 3133-3167 - [packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/src/zone_links.rs:3093, packages/d2b-provider-zone-link/src/zone_links.rs:3162] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 166 hits; the three loops are the only table-driven asserts without messages (the metric-label loops at 3093/3109 do carry messages) -- clean: seeds ran 43/166/0/0 (209 hits); 42 `#[test]` + 1 `#[tokio::test]` (tests/registration.rs:11, the policy-required registration shim - documented pattern, not flagged); assertions target error variants and durable state, not `Display` strings (the only `to_string` assertions pin the label contract at zone_links.rs:3168); the suite is deterministic (explicit `now_ms`, no clock/network), covers restart replay, capacity ceilings, redaction, and identity isolation; no `#[ignore]`, no proptest/insta/rstest - none needed for this state machine; no test found that cannot fail - -## Coverage -- idiom: 1 finding(s) -- own: 2 finding(s) -- type: clean (seeds ran: 1/0/0) -- api: 3 finding(s) -- err: clean (seeds ran: 115/0/0/2) -- serde: clean (seeds ran: 1/1/0/2) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 1 finding(s) -- perf: clean (seeds ran: 3/1/2) -- conc: clean (seeds ran: 0/0/3/0) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn or tokio in src; tokio is dev-dep only) -- unsafe: N/A (seeds: 0/0/0/0 all zero; manifest unsafe_code = "forbid") -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md deleted file mode 100644 index 77fed7130..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-provider.md +++ /dev/null @@ -1,68 +0,0 @@ -# d2b-provider - d2b-provider -Baseline: 6ebdd4cec | LOC audited: 3,252 (incl. tests/runtime.rs 667; no src/generated/**) | modules: whole crate (agent, context, descriptor, error, identity, instance, lib, operation_ledger, registry, session; tests/runtime.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- clean: seeds ran: 0/2/0;; the two hand-written `Default` impls (operation_ledger.rs:152, registry.rs:76)preserve invariantsa field-wise derive would break (ledger capacity=MAX_OPERATION_LEDGER_ROWS; registry caps=256/32) - the U1-listed deliberate class;; no index loops,no statement-style accumulation in src/** - -## own -- d2b-provider#1 sev=low blast=leaf effort=S verdict=actionable - `ProviderAgent::dispatch` clones the full canonical-JSON request per dispatch (agent.rs:290)even though only `request.method` and `request.timeout_ms` are used after the `timeout`, both Copy - fix: extract `let method = request.method;` before the `timeout)...)`, move `request` into `self.service.dispatch)...)` instead of `request.clone()`, and use `method` in the audit record - [packages/d2b-provider/src/agent.rs:290, packages/d2b-provider/src/agent.rs:299-304] - evidence: `\.clone\(\)` = 26 hits over src/**,all other 25 reviewed as required shared-ownership or owned-wrapper clones (Arc, Arc, watch Sender, cancellation tokens, instance/descriptor/subject clones into owned values);`SpecifiedProviderMethod` derives Copy (d2b-contracts-provider/src/v3/provider.rs:2758-2763),so the partial move compiles - -## type -- clean: seeds ran: 0/0/0;; no `validate_`/`check_` fns,no bool flags,no string-typed state;;`RegistryLimits::validate`/`RegistryDrainPolicy::validate` run at their consuming boundaries (builder.limits, shutdown/publish),so there is no validate-at-every-callsite spread to encode away - -## api -- clean: seeds ran: ~163/1/6;; single-surface `pub use` house pattern (lib.rs:40-65),private module tree;; the one `Arc>` return (registry.rs:618 `current()`)is justified shared ownership:callers hold the generation Arc across awaits while `ProviderRegistryManager::publish` swaps it (registry.rs:626-648; U1-listed evaluation class); no `Rc`/`Box`/`RefCell` in pub signatures - -## err -- clean: seeds ran: 12/0/0/4;; all 12 `.unwrap()`/`.expect(` sites are inside `#[cfg(test)]` modules (agent.rs:349-403,registry.rs:726-727,U1-listed acceptable class); no swallowed Results,no panic macros;; the four error enums are closed Copy code-book types printing kebab wire codes (ProviderAgentError, RegistryBuildError, ProviderRuntimeError, OperationLedgerError);; agent's HandlerFailed/DispatchTimeout mapping is a deliberate wire-boundary conversion,not a swallowed chain - -## serde -- N/A: seeds ran: 0/0/0/0 all zero;; crate crosses no wire - no serde dependency in Cargo.toml,no serde attributes,no serde_json anywhere in src/** - -## obs -- N/A: seeds ran: 0/0/0/0 all zero;; no `println!`/`eprintln!`,,no tracing/log macros,no instrument,no tracing/log dependency in Cargo.toml - the card's N/A criterion (all seeds zero and no tracing/log dep)holds - -## docs -- d2b-provider#2 sev=medium blast=leaf effort=M verdict=actionable - Public Result-returning APIs carry no `# Errors` sections,naming which conditions produce which error variants - fix: add `# Errors` sections to the ~28 pub Result-returning fns (agent.rs:40,270; context.rs:63; descriptor.rs:55,108,196,232; identity.rs:98,120,142; instance.rs:28; operation_ledger.rs:179,195; registry.rs:64,99,329,412; session.rs:36,94),listing each reachable variant per fn - [packages/d2b-provider/src/agent.rs:270, packages/d2b-provider/src/descriptor.rs:232, packages/d2b-provider/src/registry.rs:412, packages/d2b-provider/src/session.rs:36] - evidence: docs seed2 `/// # (Examples|Errors|Panics|Safety)` = 0 hits over src/**,while seed3 `-> Result<` = 33 hit sites;; surface doc coverage itself is enforced (`#![deny(missing_docs)]` at lib.rs:5),so the gap is doc-contract shape (canonical sections),not absence of docs - -## perf -- clean: seeds ran: 0/3/0;; the 3 `BTreeMap::new()` sites are cold one-shot builders (operation_ledger.rs:172,184; registry.rs:261); the agent audit deque preallocates with `with_capacity` (agent.rs:226); no `format!`/`to_string` in src/**;; no hot-path allocation site identified statically - -## conc -- clean: seeds ran: 0/1/~33/0;; the tokio `Mutex>` (agent.rs:213)is held across no `.await` (agent.rs:257-262); Acquire/Release atomics with compare_exchange loops and documented lock-free rationale (registry.rs:446-448,546-560); the Notify drain handoff has a lost-wakeup regression test (registry.rs:698-727); no `std::thread`,no manual `Send`/`Sync` claims - -## async -- d2b-provider#3 sev=medium blast=leaf effort=S verdict=actionable - `ProviderAgent::serve` awaits each `dispatch` serially (agent.rs:316-324):a slow handler near the 900s timeout bound (`MAX_AGENT_TIMEOUT_MS`)stalls the whole session queue,and the `MAX_AGENT_IN_FLIGHT=64` Semaphore bound can never be exceeded by the serve loop itself - fix: spawn each dispatch (`tokio::spawn(async move { let result = self.dispatch(request).await; let _ = response_tx.send(result.await; })`) with a cloned `response_tx`,letting the already-acquired Semaphore permit cap concurrency; state whether per-session response ordering is a contract) - [packages/d2b-provider/src/agent.rs:316-324] - evidence: async seeds = 36/1/0/4 (seed2 hit: registry.rs:709 test `tokio::spawn`; seed4: 4 `#[tokio::test]` in src/**);`census: ProviderAgent over packages/; nixos-modules/; tests/; docs/reference/; labs/; BUILD.bazel = lib.rs re-export + toolkit `FakeProvider` impl (d2b-provider-toolkit/src/testing/fixture.rs:380)+ own tests,so the serialization defect is latent until a session wires the kept B2 dispatcher (not a removal proposal) - -## unsafe -- N/A: seeds ran: 0/0/0 all zero;; no `unsafe` block/fn/impl/SAFETY site in src/**;;`unsafe_code` appears only as the inherited workspace `forbid` (Cargo.toml [lints] workspace = true),which is not a site per the card - -## ffi -- N/A: seeds ran: 0/0/0/0 all zero;; no extern "C",no no_mangle,no repr(C)/repr(transparent),,no CStr/CString/c_char anywhere in src/** - -## macro -- N/A: seeds ran: 0/0/0/0 all zero;; no `macro_rules!`,no proc-macro/syn/quote,no `$crate`,no compile-error machinery anywhere in src/** - -## test -- clean: seeds ran: 26/75+/0/0;;26 tests (18 `#[test]` + 8 `#[tokio::test]`:4 in-agent/registry src tests,22 in tests/runtime.rs)assert behavior and error variants (never Display strings),pin the redaction contract (tests/runtime.rs:480-488),use hermetic fixed-value helpers (no network,no clock reads; drain tests await only the in-process Notify path); no `#[ignore]`,no proptest/insta/rstest - -## Coverage -- idiom: clean (seeds ran: 0/2/0) -- own: 1 finding(s) (seeds ran: 26/0/0/0) -- type: clean (seeds ran: 0/0/0) -- api: clean (seeds ran: ~163/1/6) -- err: clean (seeds ran: 12/0/0/4) -- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no wire) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) -- docs: 1 finding(s) (seeds ran: ~165/0/33) -- perf: clean (seeds ran: 0/3/0) -- conc: clean (seeds ran: 0/1/~33/0) -- async: 1 finding(s) (seeds ran: 36/1/0/4) -- unsafe: N/A (seeds: 0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 26/75+/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md deleted file mode 100644 index 0a56ecbbf..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p1.md +++ /dev/null @@ -1,87 +0,0 @@ -# d2b-resource-api-p1 - d2b-resource-api - part 1/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6971 (excl. src/generated/**) | modules: service.rs, adapter.rs, manager_backend.rs, client.rs, store.rs, watch.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2: src/service.rs, src/adapter.rs, src/manager_backend.rs, src/client.rs, src/store.rs, src/watch.rs (part 2 owns src/authz.rs, src/manager_backend/**, src/admission.rs, src/error.rs, src/identity.rs, src/lib.rs) - -## idiom -- clean: seeds `for \w+ in 0\.\.` = 1 (test-only case-index loop, service.rs:2834), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 2 (manager_backend.rs:490 cursor key build, covered by perf finding 11; manager_backend.rs:1243 bounded batch loop, MAX_BATCH_MUTATIONS = 32). Hand-written `Clone` on `CheckedResourceStore` (store.rs:85) avoids an unwanted `S: Clone` derive bound and the hand-written `Debug` impls redact secrets - both deliberate per the idiom card's false-positive list. - -## own -- d2b-resource-api-p1#1 sev=low blast=leaf effort=S verdict=actionable - every bus scoped commit clones the full assignment-mutation list (`transport.mutations().to_vec()`) even though the whole chain only borrows it - fix: change `ResourceApiClient::scoped_commit_batch` (client.rs:110) and `ResourceService::commit_scoped_batch` (service.rs:852) to take `&[ScopedResourceMutation]` and pass `transport.mutations()` directly at adapter.rs:425 - [adapter.rs:425, client.rs:110, service.rs:852] - evidence: seed `\.clone\(\)` = 50 hits, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 52; census: `scoped_commit_batch` over packages = no production caller outside d2b-resource-api, so the signature change breaks no caller; the remaining clones are explainable (Arc clones of shared service, cursor/claims ownership transfers). -- clean: seeds `Rc<|RefCell<|Arc Result<` = 45; none of the pub Result-returning items in the lane has a `# Errors` section (seed `/// # (Examples|Errors|Panics|Safety)` = 0 in the lane). -- d2b-resource-api-p1#10 sev=low blast=leaf effort=M verdict=actionable - several pub items have no doc comment at all: `TrustedRequest::request`, `ResourceService::new`, the thirteen RPC forwarding methods on `ResourceApiClient` (client.rs:45-135) and `ResourceService` (service.rs:503-1115), and the `ScopedCommitFrameError`/`ScopedQueryFrameError` variants - fix: add one-line first sentences, linking docs/reference/daemon-api.md where the wire contract lives - [service.rs:70, service.rs:198, client.rs:45, adapter.rs:32-56] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 42; the undocumented items above are the gap; the RPC contract is documented in docs/reference/daemon-api.md, so a link suffices and no missing_docs lint is proposed. - -## perf -- d2b-resource-api-p1#11 sev=low blast=leaf effort=S verdict=actionable - `encode_list_cursor` hex-encodes each cursor key byte with a per-byte `format!("{byte:02x}")` allocation, and duplicates the hex encoder already present as the local `hex` closure in `list_selector_digest` - fix: extract one `fn hex(bytes: &[u8]) -> String` (with `String::with_capacity(bytes.len() * 2)` and `write!`/`char::from_digit`) and call it from both sites - [manager_backend.rs:495, manager_backend.rs:449-455] - evidence: static (unmeasured); seed `format!\(` = 20, the per-byte loop at manager_backend.rs:495 is the only format-in-loop site in the lane (cursor encoding runs on every truncated LIST page). -- d2b-resource-api-p1#12 sev=medium blast=leaf effort=S verdict=actionable - `commit_mutation` clones the full canonical resource (up to 256 KiB) on every UpdateSpec/UpdateMetadata before the byte-identical no-op check, so a no-op update pays the whole copy - fix: compare `mutation.canonical_resource.as_deref() == Some(row.spec.as_slice())` first and return the committed view early, cloning only when the bytes actually differ - [manager_backend.rs:1006] - evidence: static (unmeasured); `MAX_RESOURCE_ENVELOPE_BYTES = 256 * 1024` (packages/d2b-contracts-resource/src/v3/limits.rs:5); the clone at manager_backend.rs:1006 runs on the per-mutation hot path before the documented no-op short-circuit at manager_backend.rs:1008-1014. -- d2b-resource-api-p1#13 sev=medium blast=family effort=M verdict=actionable - `owner_key_for` resolves a mutation's owner by listing the entire Zone row set (`manager.list(ResourceSelector::default())`) and linear-searching for the owner uid, on every Delete and every owner-less UpdateSpec/UpdateMetadata/UpdateFinalizers - fix: expose a manager-side uid-to-key lookup on `ResourceManagerClient` (d2b-resource-runtime) or return the owner key from `get_row`, and call it instead of the full-zone list - [manager_backend.rs:1081-1103, manager_backend.rs:1090] - evidence: static (unmeasured); the full-zone list at manager_backend.rs:1090 is called from `owner_for_update` (manager_backend.rs:1065) and the Delete arm (manager_backend.rs:1046) on every mutation that does not carry an explicit owner; the doc comment claims the manager's uid index resolves the owner, but the implementation re-derives it by scanning all rows. - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 15, `Atomic\w+|Ordering::` = 12, `thread_local!|unsafe impl (Send|Sync) for` = 0; every Mutex and atomic hit is test-only (`tokio::sync::Mutex` fakes, SeqCst counters in `FakeStore`/`RecordingStore`), production code in the lane has no locks, threads, or atomics. - -## async -- clean: seeds `async fn|async move|\.await` = ~130, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 15 (all test fakes), `#\[tokio::(main|test)\]|Runtime::block_on` = 14 (all `#[tokio::test]`); no blocking calls in async context, no guards held across `.await` in production code, and both async traits (`ResourceStoreBackend`, `UpgradeDispatcher`) use RPITIT with `+ Send` bounds. - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; the crate manifest forbids unsafe (`unsafe_code = "forbid"` at packages/d2b-resource-api/Cargo.toml:7), so the lens is not applicable. - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; no FFI surface in the lane. - -## macro -- d2b-resource-api-p1#14 sev=low blast=leaf effort=S verdict=actionable - `response_error!` generates thirteen identical one-line functions that differ only in the response type, a case a generic function covers without a macro - fix: replace the macro with `fn error_response(error: ResourceError) -> T` (type inferred from each RPC method's return type) and delete the thirteen `response_error!` invocations - [service.rs:2245-2267] - evidence: seed `macro_rules!` = 3 (service.rs:1262, service.rs:1322, service.rs:2245); `impl_mutation_request!` and `impl_strict_mutation_request!` are genuine impl-per-type generation (one of the skill's three legitimate answers) and are not flagged; seed `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0. - -## test -- d2b-resource-api-p1#15 sev=low blast=leaf effort=S verdict=actionable - `status_owner_matching_generation_is_representable` asserts only that `ControllerGeneration::new(11)` and `ResourceGeneration::new(11)` succeed on literals, restating the type system rather than a behavior contract - fix: delete it, or convert the representability claim into the wire-compatibility test it is meant to document (asserting the status-owner comparison path with a real mismatch) - [service.rs:3377] - evidence: seed `#\[test\]|#\[tokio::test\]` = 23, `assert_eq!\(|assert_ne!\(|assert!\(` = ~90; the test body (service.rs:3377-3384) contains no behavior under test; the suite is otherwise behavioral (dispatch sentinels, redaction markers, authorization-before-validation ordering, byte-bound enforcement). - -## Coverage -- idiom: clean (seeds: 1/0/2; only non-test hit is the cursor build covered by perf finding 11; hand-written Clone/Debug impls deliberate) -- own: 1 finding(s) -- type: 1 finding(s) -- api: 3 finding(s); watch.rs kept-half (B1) refusal cited per U1 (d) 6, not re-flagged -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: 1 finding(s) -- docs: 2 finding(s) -- perf: 3 finding(s) -- conc: clean (seeds: 0/15/12/0; all hits test-only fakes and counters) -- async: clean (seeds: ~130/0/15/14; no blocking, no guards across await, Send bounds on both async traits) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: 1 finding(s) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md deleted file mode 100644 index 6153ce8a0..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-api-p2.md +++ /dev/null @@ -1,72 +0,0 @@ -# d2b-resource-api-p2 - d2b-resource-api - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 6960 (excl. src/generated/**) | modules: authz, admission, error, identity, manager_backend (tests), lib -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/authz.rs, src/manager_backend/**, src/admission.rs, src/error.rs, src/identity.rs, src/lib.rs - -## idiom -- d2b-resource-api-p2#1 sev=low blast=leaf effort=M verdict=actionable - A6 not-applied: 17 hand-written redaction Debug impls in authz.rs (15) and admission.rs (2) where the exported `redacted_debug!` macro exists - fix: fold byte-compatible impls to `redacted_debug!` or extend the macro with a count-preserving form, updating the Debug-shape pinning tests in the same change - [packages/d2b-resource-api/src/authz.rs:106, packages/d2b-resource-api/src/authz.rs:300, packages/d2b-resource-api/src/authz.rs:356, packages/d2b-resource-api/src/authz.rs:377, packages/d2b-resource-api/src/authz.rs:530, packages/d2b-resource-api/src/authz.rs:546, packages/d2b-resource-api/src/authz.rs:560, packages/d2b-resource-api/src/authz.rs:575, packages/d2b-resource-api/src/authz.rs:594, packages/d2b-resource-api/src/authz.rs:604, packages/d2b-resource-api/src/authz.rs:770, packages/d2b-resource-api/src/authz.rs:800, packages/d2b-resource-api/src/authz.rs:1090, packages/d2b-resource-api/src/authz.rs:1120, packages/d2b-resource-api/src/authz.rs:1270, packages/d2b-resource-api/src/admission.rs:60, packages/d2b-resource-api/src/admission.rs:300, packages/d2b-resource-api/src/authz.rs:3328, packages/d2b-resource-api/src/admission.rs:695] - evidence: idiom seeds = 1/1/4 hits; A6 row at docs/explanation/over-engineering-audit-record.md:459 (not applied, no refusal reason; sites still match at 6ebdd4cec); the macro prints only `Type()` (packages/d2b-contracts-resource/src/v3/execution_policy.rs:22-28), so the count/presence fields these impls keep are not byte-compatible without a macro extension, and the shapes are pinned by the two Debug tests -- d2b-resource-api-p2#2 sev=low blast=leaf effort=S verdict=actionable - unformatted `use` lines inside a fn body break `cargo fmt --check` - fix: reindent to 4 spaces and drop the inner-brace spacing - [packages/d2b-resource-api/src/manager_backend/tests.rs:1045, packages/d2b-resource-api/src/manager_backend/tests.rs:1046] - evidence: idiom seeds = 1/1/4 hits; the two `use` lines sit at mixed columns inside `converted_type_status_layers_round_trip_through_their_typed_decoders` (no rustfmt.toml in the repo, default rules apply) - -## own -- d2b-resource-api-p2#3 sev=low blast=leaf effort=S verdict=actionable - redundant `.cloned()` in `StoreAdmissionBinding::verify`: `mutations` is already owned after the destructure, so the iterator clones every mutation before `prepare_mutation` consumes it - fix: `mutations.into_iter().map(prepare_mutation)` - [packages/d2b-resource-api/src/admission.rs:338, packages/d2b-resource-api/src/admission.rs:344, packages/d2b-resource-api/src/admission.rs:345] - evidence: seed `\.clone\(\)` = 133 hits in scope (74 authz.rs, 53 tests.rs, 6 admission.rs); `prepare_mutation` takes `StoreMutation` by value (admission.rs:417), so `into_iter()` compiles without the clone; all other clones in this part are explainable (owned outputs, Arc clones, test fixtures) - -## type -- clean: seeds `fn validate_\w+|fn check_\w+` = 2 (admission.rs:456,483), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the two validate hits are boundary admission gates on untrusted wire bytes (the card's parse-once-at-boundary shape), and no boolean-flag or stringly-typed state fields exist in this part - -## api -- clean: seeds `pub (fn|struct|enum|trait|type|const|mod)` = 81, `pub .*Arc|Rc|Box|RefCell<` = 0, `pub use` = 13; the surface is deliberate: private fields plus compile_fail doctests on AuthorizationLease/AdmittedMutation/AuthenticatedSubjectContext, the lib.rs re-export arms are the house single-surface pattern, and no internals or dependency types appear in public signatures - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(` = 379, `let _ = |\.ok\(\);` = 7, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 17, `enum \w*Error` = 3; every production hit falls in the card's false-positive classes: one expect on a literal catalog (authz.rs:88), two invariant-named expects on bounded batch ordinals (admission.rs:206,208), fail-closed `unwrap_or_else` fallbacks (error.rs:74-78); panics and unwraps are otherwise confined to tests, and the three error enums (StoreSealHandoffError, AdmissionError, AuthorizationPolicyError) all carry Display plus Error - -## serde -- clean: seeds `derive(...Serialize` = 0, `serde(...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|to_` = 30; the two production `from_slice` parses (authz.rs:409,420) are the typed admission boundary where canonical JSON becomes RoleSpec/RoleBindingSpec with error collapse to RoleSchema/BindingShape, and the remaining hits are test payloads - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0 real hits (the seed only matched `catalog::` substrings; tracing is used only in part 1's manager_backend.rs:194) - -## docs -- d2b-resource-api-p2#4 sev=medium blast=leaf effort=S verdict=actionable - nine pub methods on the evaluator surface are undocumented, including `NativeAuthorizer::authorize` (the security decision entry returning nine AuthorizationDenial variants) and `take_store_seal` (which hands off an ownership-bearing seal acceptor) - fix: add doc comments with `# Errors` sections enumerating the denial variants on authorize, and one-line contracts on the remaining eight - [packages/d2b-resource-api/src/authz.rs:630, packages/d2b-resource-api/src/authz.rs:864, packages/d2b-resource-api/src/authz.rs:912, packages/d2b-resource-api/src/authz.rs:1093, packages/d2b-resource-api/src/authz.rs:1479, packages/d2b-resource-api/src/authz.rs:1505, packages/d2b-resource-api/src/authz.rs:1522, packages/d2b-resource-api/src/authz.rs:1550, packages/d2b-resource-api/src/authz.rs:1615] - evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 81 hits, seed 2 (`/// # ...`) = 0, seed 3 (`-> Result<`) = 48; the `///` scan over authz.rs shows no doc comment above these nine lines, and `missing_docs` is not enabled anywhere (proposal only) - -## perf -- d2b-resource-api-p2#5 sev=low blast=leaf effort=S verdict=actionable - `compile_authorization_facts` grows its roles and bindings Vecs by push although the row count is known upfront - fix: `Vec::with_capacity(rows.len())` for both - [packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458] - evidence: static (unmeasured); seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 22 hits in scope, and the loop over `rows` at authz.rs:461 bounds both collections - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 2, `\bMutex<|\bRwLock<` = 5, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; every Mutex/RwLock site (authz.rs:1401,1404,1407, admission.rs:52,393) carries the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` allow, and the two thread::spawn hits are the sanctioned cfg(test) linearization test (authz.rs:2686,2707) - -## async -- clean: seeds `async fn|async move|\.await` = 77, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 13; every hit is the test harness in manager_backend/tests.rs under the sanctioned `#[allow(clippy::disallowed_methods, reason = "cfg(test) helper")]` allow, and the production surface in this part is deliberately synchronous (admission.rs:356-359) - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 all zero; the manifest sets `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero - -## macro -- clean: seeds `macro_rules!` = 1, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the single hit is the test-only `impl_has_error!` helper (tests.rs:463), the card-listed test-helper false positive - -## test -- d2b-resource-api-p2#6 sev=medium blast=leaf effort=S verdict=actionable - `list_returns_snapshot_revision_and_watch_refuses_until_wired` compares the wire snapshot's epoch-seconds half against `SystemTime::now()` taken after the list round-trip, so a second boundary crossing between the two instants flakes the test - fix: assert the mapping with a one-second tolerance or inject the clock - [packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src/manager_backend/tests.rs:1460, packages/d2b-resource-api/src/manager_backend/tests.rs:1461] - evidence: seed `#\[test\]|#\[tokio::test\]` = 57 hits, `assert_eq!\(|assert_ne!\(|assert!\(` = 242, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the compared values are read at different instants (the manager computes `snapshot_revision` before the awaits that precede the assertion), violating the determinism rule - -## Coverage -- idiom: 2 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 2/0/0; the two validate_* hits are boundary admission gates on untrusted wire bytes, admission.rs:456,483) -- api: clean (seeds ran: 81/0/13; deliberate private-field surface with compile_fail doctests, lib.rs re-export arms are the house pattern, no Arc/Rc/Box/RefCell in pub signatures) -- err: clean (seeds ran: 379/7/17/3; production hits are all card-listed false-positive classes, panics confined to tests, error enums carry Display plus Error) -- serde: clean (seeds ran: 0/0/0/30; the two production from_slice parses are the typed admission boundary, the rest is test payloads) -- obs: clean (seeds ran: 0/0/0/0; the log:: seed only matched catalog:: substrings, tracing lives in part 1's manager_backend.rs:194) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 2/5/0/0; all Mutex/RwLock sites carry the sanctioned synchronous-path allow, thread::spawn confined to the sanctioned cfg(test) linearization test) -- async: clean (seeds ran: 77/0/0/13; every hit is the sanctioned test harness in manager_backend/tests.rs, production here is deliberately synchronous) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest sets unsafe_code = "forbid") -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: clean (seeds ran: 1/0/0/0; the single hit is the test-only impl_has_error! helper, a card-listed false positive) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md deleted file mode 100644 index 84565497c..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-client.md +++ /dev/null @@ -1,77 +0,0 @@ -# d2b-resource-client - d2b-resource-client -Baseline: 6ebdd4cec | LOC audited: 4839 (excl. src/generated/**, no tests/ dir, no build.rs) | modules: whole crate (call, client, dispatch, error, lib, process_attach, target, zone_client) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (whole crate) - -## idiom -- d2b-resource-client#1 sev=low blast=leaf effort=S verdict=actionable - two byte-identical private async helpers each exist twice in this crate: `await_with_cancellation` (zone_client vs process_attach) and `classify_session_error`/`classify_attach_error` - fix: hoist both into one shared pub(crate) module (e.g., call.rs) and have zone_client.rs and process_attach.rs call the single copies - [packages/d2b-resource-client/src/zone_client.rs:914, packages/d2b-resource-client/src/process_attach.rs:764, packages/d2b-resource-client/src/zone_client.rs:936, packages/d2b-resource-client/src/process_attach.rs:785] - evidence: census: `async fn await_with_cancellation` over src = 2 hits; `fn classify_\w+_error` over src = 2 hits -- d2b-resource-client#2 sev=low blast=leaf effort=S verdict=actionable - `GuestControlEndpoint::endpoint_uid` is an exact duplicate of `uid()` (same field, same doc sentence; a test pins the equivalence at zone_client.rs:1067) - fix: keep one accessor (e.g., `uid()`) and drop or deprecate the other - [packages/d2b-resource-client/src/zone_client.rs:194, packages/d2b-resource-client/src/zone_client.rs:199, packages/d2b-resource-client/src/zone_client.rs:1067] - evidence: static read: both return `&self.uid`; census: `endpoint_uid` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 22 hits (live, so removal touches callers) - -## own -- d2b-resource-client#3 sev=low blast=family effort=S verdict=actionable - by-value `resource_ref()` accessors clone a `ResourceRef` (target.rs:155, 279, 407) and `ResolvedTarget::matches_assignment` clones just to compare (`self.resource_ref().as_ref() == Some(reference)`, target.rs:424) - fix: give the in-crate comparison a borrow-returning variant (`Option<&ResourceRef>`) and consider tightening the pub accessors later, migrating about 15 caller files - [packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs:279, packages/d2b-resource-client/src/target.rs:407, packages/d2b-resource-client/src/target.rs:424] - evidence: census: `\.resource_ref\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 21 hits across 15 files; seed `\.clone\(\)` = 74 (remaining clones explainable: waker registry, per-attempt payload, by-value trait seams) - -## type -- d2b-resource-client#4 sev=low blast=leaf effort=S verdict=actionable - `MetadataInput::validate_lifetime` (call.rs:168) is a re-validation of the invariant `MetadataInput::new` already enforces at construction (private fields); `CallDriver::new` re-checks it (dispatch.rs:189) where it cannot fail - fix: drop the `validate_lifetime()?` re-check at CallDriver::new (or convert to a debug_assert) - [packages/d2b-resource-client/src/call.rs:168, packages/d2b-resource-client/src/dispatch.rs:189] - evidence: seed `fn validate_\w+|fn check_\w+` = 2 (validate_lifetime, validate_for); census: `validate_lifetime` over packages = 3 hits (definition plus the two calls: call.rs:103, dispatch.rs:189) - -## api -- d2b-resource-client#5 sev=medium blast=leaf effort=M verdict=actionable - eight zero-caller pub items form dead surface: `ZonePeerIdentity::from_enrolled_peer` (zone_client.rs:83), `ZoneSocketConnector::local_daemon_endpoint_identity` (361), `ZoneClient::scoped_query` (635), `scoped_child_query` (646), `call_resource` (703), `ProcessAttachTarget::from_target` (process_attach.rs:125), `configured_launcher_from_target` (132), `ProcessAttachClient::attach_local` (721) - fix: remove or demote to `pub(crate)` (and, if kept, merge the two from-target constructors into one) - [packages/d2b-resource-client/src/zone_client.rs:83, packages/d2b-resource-client/src/zone_client.rs:361, packages/d2b-resource-client/src/zone_client.rs:635, packages/d2b-resource-client/src/zone_client.rs:646, packages/d2b-resource-client/src/zone_client.rs:703, packages/d2b-resource-client/src/process_attach.rs:125, packages/d2b-resource-client/src/process_attach.rs:132, packages/d2b-resource-client/src/process_attach.rs:721] - evidence: census: each name over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 hit (its own definition); the only seam consumer of the call path is `d2b/src/context.rs` via `call_connected`, not `call_resource` - -## err -- d2b-resource-client#6 sev=low blast=leaf effort=S verdict=actionable - three reflexive `Mutex::lock().unwrap()` sites in the cancellation waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) handle poisoning by panic instead of an explicit choice - fix: use `expect("waker registry lock is not poisoned: no user code runs under it")` or `into_inner()` with the same written reason - [packages/d2b-resource-client/src/call.rs:281, packages/d2b-resource-client/src/call.rs:309, packages/d2b-resource-client/src/call.rs:335] - evidence: seed `\.unwrap\(\)|\.expect\(` = 92 (89 in #[cfg(test)]; non-test hits are exactly call.rs:281, 309, 335, all carrying the sanctioned synchronous-path allows); `let _ = |\.ok\(\);` = 6 (all deliberate best-effort cancel/close forwards on the cancellation path) - -## serde -- clean: seeds ran: 0/0/0/4 (`serde_json::from_|serde_json::to_` hits are the frame codecs at process_attach.rs:489, 497 plus 2 test sites); checked: frames are contract-owned (`d2b-contracts-control`) and codec errors map to `ClientError::ContractViolation`; no serde attributes live in this crate - -## obs -- N/A: (seeds: 0/0/0/0 all zero; Cargo.toml declares no `tracing`/`log` dependency, so the lens's applicability condition fails) - -## docs -- d2b-resource-client#7 sev=low blast=leaf effort=L verdict=actionable - 50 Result-returning pub items carry no `# Errors` section (zero `# Examples|Errors|Panics|Safety` sections anywhere in the crate), so callers must infer failure conditions from prose - fix: add `# Errors` to the public Result-returning entry points (MetadataInput::new, RetryPolicy::new, CallDriver::new, ZoneClient::connect, ZoneClient::call_connected, ZoneClient::scoped_commit_batch, ProcessAttachClient::attach) - [packages/d2b-resource-client/src/call.rs:87, packages/d2b-resource-client/src/dispatch.rs:131, packages/d2b-resource-client/src/zone_client.rs:711, packages/d2b-resource-client/src/process_attach.rs:648] - evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type) ` = 194; `/// # (Examples|Errors|Panics|Safety)` = 0; `-> Result<` = 50 - -## perf -- clean: seeds ran: 19/12/0 (`format!(`, `Vec::new(|VecDeque::new(|HashMap::new(|BTreeMap::new(`, `\.to_string(`); all 19 format! sites and all 12 Vec::new sites are in #[cfg(test)] fixtures or diagnostic asserts; no allocation sits in a non-test loop (`payload.clone()` per bounded retry attempt is an explainable by-value-trait cost); static (unmeasured) - -## conc -- d2b-resource-client#8 sev=low blast=leaf effort=S verdict=actionable - `ResourceWatch` models the open/closing/closed stream state with two `Arc` fields (state, closing; zone_client.rs:510-513) where the sibling `ProcessAttachStream` already uses the single `AtomicU8` three-state machine (STREAM_OPEN/CLOSING/CLOSED, process_attach.rs:409-412) - fix: align ResourceWatch onto the same single-atomic state enum - [packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone_client.rs:512, packages/d2b-resource-client/src/zone_client.rs:513, packages/d2b-resource-client/src/process_attach.rs:409, packages/d2b-resource-client/src/process_attach.rs:412] - evidence: seeds: `Atomic\w+|Ordering::` = 47; `\bMutex<|\bRwLock<` = 6 (1 non-test waker registry lock, 5 test fakes); ordering pairs are correct (Relaxed counter, Acquire/Release/AcqRel flags), no ordering misfit found - -## async -- clean: seeds ran: 80/1/20/0 (`async fn|\.await` = 80; `tokio::spawn` family = 1, a test at process_attach.rs:1118; `tokio::sync::(Mutex|RwLock|Notify)` = 20, all #[cfg(test)] fakes; `Runtime::block_on` = 0); checked: `retry_backoff` refuses without a caller runtime rather than panicking, and cancel-forward-on-cancel is best-effort with no swallowed failures beyond intended cleanup - -## unsafe -- N/A: (seeds: 0/0/0 all zero; manifest `unsafe_code = "forbid"`, so seed 4 alone does not make the lens applicable) - -## ffi -- N/A: (seeds: 0/0/0/0 all zero) - -## macro -- N/A: (seeds: 0/0/0/0 all zero) - -## test -- d2b-resource-client#9 sev=medium blast=leaf effort=M verdict=actionable - the core resource-call execution path has no test: no test drives `call_connected`/`call_resource`/`scoped_commit_batch`, so the `execute_resource_call` retry loop, its retry-after-delay backoff branch, scoped-commit admission, and cancel-forward are only exercised indirectly by attach tests - fix: add a fake `ConnectedZoneSession` test covering `call_with_timeout` success, retry-after-delay, cancel-forward, and a scoped commit path - [packages/d2b-resource-client/src/zone_client.rs:703, packages/d2b-resource-client/src/zone_client.rs:711, packages/d2b-resource-client/src/zone_client.rs:755, packages/d2b-resource-client/src/zone_client.rs:858] - evidence: seeds: `#\[test\]|#\[tokio::test\]` = 34; `assert_eq!\(|assert_ne!\(|assert!\(` = 144; census: `call_connected` over tests/ = 0 hits (the only external caller is d2b/src/context.rs:1622, not a test) -- d2b-resource-client#10 sev=low blast=leaf effort=S verdict=actionable - the close/cancel error-rollback paths are untested: `ProcessAttachStream::close`/`cancel` and `ResourceWatch::close` restore the open state when the transport close errors, but no test injects that failure - fix: add failure-injection tests asserting the state rolls back to open and a second close retries - [packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/process_attach.rs:541, packages/d2b-resource-client/src/zone_client.rs:567] - evidence: static read: close()/cancel() error arms at process_attach.rs:534 and zone_client.rs:580 restore state; seed `#\[test\]` = 34 sites, none names a close/cancel failure injection - -## Coverage -- idiom: 2 findings -- own: 1 finding -- type: 1 finding -- api: 1 finding -- err: 1 finding -- serde: clean (seeds ran: 0/0/0/4) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: 1 finding -- perf: clean (seeds ran: 19/12/0) -- conc: 1 finding -- async: clean (seeds ran: 80/1/20/0) -- unsafe: N/A (seeds: 0/0/0 all zero; forbid manifest) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 2 findings \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md deleted file mode 100644 index 057e5e608..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-compiler.md +++ /dev/null @@ -1,83 +0,0 @@ -# d2b-resource-compiler - d2b-resource-compiler -Baseline: 6ebdd4cec | LOC audited: 7461 (excl. src/generated/, which is absent; src 5514 + tests 1947) | modules: whole crate (src/lib.rs, src/linux.rs, src/main.rs, tests/cli.rs, tests/phase2.rs) -Lenses: idiom,own,type,api,err,serde,obs,docs,perf,conc,async,unsafe,ffi,macro,test | Partitions: n/a (single-part lane) - -## idiom -- d2b-resource-compiler#1 sev=medium blast=leaf effort=S verdict=actionable - main.rs hand-rolls identical output-sanitizer helpers already in lib.rs (safe_token/bound_ascii duplicate sanitize_token/bound_message body-for-body) - fix: expose lib.rs sanitize_token/bound_message as pub(crate) helpers (dropping safe_label indirection if unneeded) and replace main.rs safe_token/bound_ascii with calls to the shared pair - [packages/d2b-resource-compiler/src/lib.rs:2401, packages/d2b-resource-compiler/src/lib.rs:2438, packages/d2b-resource-compiler/src/main.rs:2531, packages/d2b-resource-compiler/src/main.rs:2545] - evidence: idiom seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) = 11 hits; both helper pairs rebuild strings char-by-char with the identical filter/ASCII-bound rules -- d2b-resource-compiler#2 sev=low blast=leaf effort=S verdict=actionable - sanitize_token's char-loop filter is expressible as an iterator pipeline - fix: `value.chars().filter(|character| (character.is_ascii_graphic() && *character != '/' && *character != '\\') || *character == ' ').collect::()` - [packages/d2b-resource-compiler/src/lib.rs:2402] - evidence: idiom seed 3 hit at lib.rs:2402 (the canonical copy named by #1) -- d2b-resource-compiler#3 sev=low blast=leaf effort=S verdict=actionable - check_metadata_closure's unexpected-layout-entries accumulation could be a filter_map+collect pipeline - fix: `let unexpected: Vec = entries.into_iter().filter_map(|entry_name| match entry_name.to_str() { Some(name) if expected.contains(name) => None, Some(name) => Some(truncate_entry(name)), None => Some("".to_owned()) }).collect();` (kept the trailing sort* - [packages/d2b-resource-compiler/src/lib.rs:1724] - evidence: idiom seed 3 hit at lib.rs:1724 -- d2b-resource-compiler#4 sev=low blast=leaf effort=S verdict=actionable - executable-set difference builders are two push-loops a chain can express in one collect - fix: `let difference: Vec = names.difference(&declared_names).map(|name| format!("bin={}", truncate_entry(name)).chain(declared_names.difference(&names).map(|name| format!("manifest={}", truncate_entry(name)).collect();` - [packages/d2b-resource-compiler/src/lib.rs:1913] - evidence: idiom seed 3 hit at lib.rs:1913 -- clean: seeds ran: 2/0/11; the two index-loop hits are test-only depth builders (main.rs:2335, a phase2.rs fixture; no hand-written derive-class impls; the remaining accumulation sites are loops with side effects or early exits where the skill's own guidance prefers a plain for loop - -## own -- d2b-resource-compiler#5 sev=low blast=leaf effort=S verdict=actionable - SchemaCache uses RefCell for a lazy schema cache though the only two call sites could take `&mut self` - fix: change `fn schema(&self,...)` to `fn schema(&mut self,...)`, drop the RefCell holding the cache in plain `BTreeMap` field, and mark `let mut schema_cache` in validate_resources - [packages/d2b-resource-compiler/src/main.rs:1148, packages/d2b-resource-compiler/src/main.rs:1631, packages/d2b-resource-compiler/src/main.rs:818, packages/d2b-resource-compiler/src/main.rs:846] - evidence: own seed 3 (`Rc<|RefCell<|Arc, build: impl FnOnce(oneshot::Sender>) -> ResourceManagerMsg)` and call it from both impls - [packages/d2b-resource-runtime/src/manager.rs:1419, packages/d2b-resource-runtime/src/manager.rs:1508] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (test helper, not a finding); the two rpc bodies read identical at the cited lines -- clean: seeds ran: 9 (`for \w+ in 0\.\.`, all in test polling loops), 2 (hand-written impls, both flagged), 1 (`let mut ... = Vec::new()`, test helper); no index loops or statement-style accumulation in production code - -## own -- d2b-resource-runtime-p1#3 sev=low blast=leaf effort=S verdict=actionable - `ResourceView::observed_status` clones the whole `Option` (which can carry a `DriverFailure` with comparison vectors) before the generation filter, so a stale status is copied and then discarded - fix: `self.status.as_ref().filter(|_| self.status_generation == Some(self.generation)).cloned()` - [packages/d2b-resource-runtime/src/manager.rs:205] - evidence: seed `\.clone\(\)` = 232 hits (174 in manager.rs); this site clones only to filter by reference -- d2b-resource-runtime-p1#4 sev=low blast=leaf effort=S verdict=actionable - `ResourceActor::pre_start` clones `args.row` twice (once into the context, once into `state.row`) where one move and one clone suffice - fix: move `args.row` into `ResourceActorState.row` and clone it only for `ResourceContext::new` - [packages/d2b-resource-runtime/src/resource.rs:714, packages/d2b-resource-runtime/src/resource.rs:732] - evidence: seed `\.clone\(\)` = 232 hits; both cited clones are of the same `StoredDesiredResource` in one function -- d2b-resource-runtime-p1#5 sev=low blast=leaf effort=S verdict=actionable - `spec_object` returns `Ok(spec.clone())` on an owned `serde_json::Value` where the move `Ok(spec)` is legal (the value is not used after) - fix: drop the `.clone()` - [packages/d2b-resource-runtime/src/metadata.rs:191] - evidence: seed `\.clone\(\)` = 232 hits; the cited clone copies the whole decoded spec JSON on every metadata validate pass -- clean: seeds ran: 232 (`\.clone\(\)`), 57 (`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`), 0 (`Rc<|RefCell<|Arc Result<`); module docs exist for all eight modules, and every public type, enum variant, and constant except the flagged items carries a first-sentence doc - -## perf -- d2b-resource-runtime-p1#10 sev=low blast=leaf effort=S verdict=actionable - `reconcile_children`'s obsolete scan clones every owned `StoredDesiredResource` row (spec and metadata byte vectors included) into a `Vec` when only the keys are needed to drive `remove_internal` - fix: collect `row.key.clone()` only, or iterate `state.rows` by reference and call `remove_internal(&subject, &child.key)` - [packages/d2b-resource-runtime/src/manager.rs:1390] - evidence: static (unmeasured); seed `Vec::new\(\)|HashMap::new\(\)` = 33 hits; the cited `.cloned().collect()` copies full rows per reconcile pass over a parent's owned set -- clean: seeds ran: 13 (`format!`), 33 (`Vec::new\(\)|HashMap::new\(\)`), 25 (`\.to_string\(\)`); the `format!` sites are error paths and the log-line/wire renderers (cold), the collection literals are one-shot state construction, and no allocation sits in a measured hot path - -## conc -- d2b-resource-runtime-p1#11 sev=low blast=leaf effort=S verdict=actionable - `ActorTimers.next` is a single-owner counter (ractor serializes the actor's handlers) but increments with `Ordering::SeqCst`, the strongest ordering, where `Relaxed` is the weakest correct one for a counter nobody synchronises on - fix: `self.next.fetch_add(1, Ordering::Relaxed)` - [packages/d2b-resource-runtime/src/resource.rs:247] - evidence: seed `Atomic\w+|Ordering::` = 151 hits (the rest are test atomics and the correct Acquire/Release gate pair in test_support); the cited counter is only touched by the actor thread -- clean: seeds ran: 0 (`std::thread::|thread::spawn|thread::scope`), 10 (`\bMutex<|\bRwLock<`), 151 (`Atomic\w+|Ordering::`), 0 (`thread_local!|unsafe impl (Send|Sync) for`); the production `Mutex` is the documented plan-U4 `tokio::sync::Mutex` reached via non-blocking `try_lock` from the sync trait surface (resource.rs:249-252), and `ManualClock` uses `Relaxed` correctly - -## async -- clean: seeds ran: 642 (`async fn|async move|\.await`), 5 (`tokio::spawn|spawn_blocking|JoinSet|select!|join!`), 5 (`tokio::sync::(Mutex|RwLock|Notify)`), 44 (`#[tokio::(main|test)]|Runtime::block_on`); no blocking call sits in an async context (the store and target calls are async, the only `std::fs` use is in tests), no guard is held across `.await`, the `Box::pin` recursion in `remove_internal`/`retire_row` is depth-bounded by the ownership chain with crash-resume covered by tests, the unbounded effect/watch channels are the documented KTD12 mailbox-freeing design, and the two production `.expect` receiver takes name held-in-state invariants - -## unsafe -- N/A: seeds: 0/0/0/0 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`, `unsafe_code`); the crate inherits workspace lints with `unsafe_code = "forbid"` (root Cargo.toml `[workspace.lints.rust]`), matching U1 (d) 8's enumerated set - -## ffi -- N/A: seeds: 0 all zero (`extern "C"|no_mangle|unsafe\(link_section`, `catch_unwind`, `repr\(C\)|repr\(transparent\)`, `CStr|CString|c_char`); no foreign boundary exists in this crate - -## macro -- N/A: seeds: 0 all zero (`macro_rules!`, `proc_macro|syn::|quote!`, `\$crate`, `to_compile_error|new_spanned`); no macros defined or consumed beyond std - -## test -- d2b-resource-runtime-p1#12 sev=high blast=leaf effort=S verdict=actionable - `display_shows_epoch_and_sequence` asserts `rendered.contains("[PHONE]")` on the rendering `e1728000000+42`, an assertion that cannot pass, so the test fails at HEAD (route review-pass; read-only audit) - fix: delete the stray `[PHONE]` assertion (the epoch/sequence assertions on the same line already cover the contract) - [packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revision.rs:71] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 281 hits; the Display impl at revision.rs:71-75 renders `e{}+{}` with no redaction, and `[PHONE]` appears nowhere else in packages/ (grep over packages/ = 0 hits) -- d2b-resource-runtime-p1#13 sev=low blast=leaf effort=S verdict=actionable - `wire_budget_bounds_sequence_for_u32_low_word` asserts `WIRE_SEQUENCE_BUDGET == 1 << 32`, restating the constant's own definition (revision.rs:41), so it cannot fail meaningfully - fix: delete it or assert a behavioral consequence (e.g. that a sequence at the budget still packs into the u32 low word of the U8 mapping) - [packages/d2b-resource-runtime/src/revision.rs:182] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 281 hits; the expected value is the same literal the const is defined from (revision.rs:41), the skill's same-logic expectation rule -- d2b-resource-runtime-p1#14 sev=low blast=leaf effort=S verdict=actionable - the lib.rs `modules_resolve` smoke test asserts each `MODULE_NAME` const against its own literal, pinning source text with no behavioral value (the A5 not-applied row, docs/explanation/over-engineering-audit-record.md:458, covers the consts and this test; the site still matches the record) - fix: fold into the A5 decision (delete both, or keep only as a compile-resolution check without the value assertions) - [packages/d2b-resource-runtime/src/lib.rs:66] - evidence: seed `#\[test\]|#\[tokio::test\]` = 64 hits; the test asserts 13 const-vs-literal pairs that cannot diverge from the same-file definitions -- clean: seeds ran: 64 (`#\[test\]|#\[tokio::test\]`), 281 (`assert_eq!|assert_ne!|assert!`), 0 (`proptest!|insta::assert|rstest`), 1 (`#\[ignore`); the manager/actor/metadata/provider suites are behavior-asserting and deterministic (paused clocks, causal barriers instead of sleeps, documented ignores for the reference-doc regenerator at error.rs:1009), and the three flagged tests are the exceptions - -## Coverage -- idiom: 2 finding(s) -- own: 3 finding(s) -- type: clean (seeds ran: 2/0/0) -- api: clean (seeds ran: 145 pub items inspected; Arc fields are shared-ownership with cited call sites) -- err: 1 finding(s) -- serde: clean (seeds ran: 4) -- obs: clean (seeds ran: 0/2) -- docs: 3 finding(s) -- perf: 1 finding(s) -- conc: 1 finding(s) -- async: clean (seeds ran: 642/5/5/44) -- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace `unsafe_code = "forbid"` inherited) -- ffi: N/A (seeds: 0 all zero; no foreign boundary) -- macro: N/A (seeds: 0 all zero; no macros) -- test: 3 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md deleted file mode 100644 index 806b6b8af..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-resource-runtime-p2.md +++ /dev/null @@ -1,90 +0,0 @@ -# d2b-resource-runtime-p2 - d2b-resource-runtime - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 7756 (excl. src/generated/**) | modules: context, target, guest_target, spec_store, watch, driver, identity -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2: src/context.rs, src/target.rs, src/guest_target.rs, src/spec_store.rs, src/watch.rs, src/driver.rs, src/identity.rs - -## idiom -- d2b-resource-runtime-p2#1 sev=low blast=leaf effort=S verdict=actionable - two hand-written comparator closures where the sort_by_key form is the idiomatic one - fix: replace sort_by(|l, r| identity_order(l).cmp(&identity_order(r))) with sort_by_key(identity_order) in TargetDirectory::assignments_for and GuestTargetRuntime::instances - [packages/d2b-resource-runtime/src/target.rs:732, packages/d2b-resource-runtime/src/guest_target.rs:514] - evidence: seed `for \w+ in 0\.\.` = 7 hits (6 in test modules); static read of both sort sites. -- d2b-resource-runtime-p2#2 sev=low blast=leaf effort=S verdict=actionable - hand-written impl Default for TargetDirectory where a derive yields the identical value - fix: replace the impl with #[derive(Default)] on TargetDirectory (DirectoryState already derives Default and Arc>: Default) - [packages/d2b-resource-runtime/src/target.rs:581-584] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits (target.rs:581, watch.rs:147); the watch.rs:147 Default is not derivable (constant defaults), target.rs:581 is. -- d2b-resource-runtime-p2#3 sev=low blast=leaf effort=S verdict=actionable - inherent ResourceProvenance::from_str shadows the FromStr trait name - fix: implement std::str::FromStr for ResourceProvenance and parse at the single use site in row_from - [packages/d2b-resource-runtime/src/spec_store.rs:83-88, packages/d2b-resource-runtime/src/spec_store.rs:556] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits; static read of spec_store.rs:83-88. - -## own -- d2b-resource-runtime-p2#4 sev=low blast=leaf effort=S verdict=actionable - insert_new clones the entire row (spec and metadata Vecs included) only to stamp generation/deleting/created_at - fix: take row: StoredDesiredResource by value in insert_new and destructure it, dropping `..row.clone()`; the caller at spec_store.rs:346 does not use row afterwards - [packages/d2b-resource-runtime/src/spec_store.rs:520-541] - evidence: seed `\.clone\(\)` = 86 hits in lane; this site copies both envelope byte vectors on every ensure-create. -- d2b-resource-runtime-p2#5 sev=low blast=leaf effort=S verdict=actionable - SpecStore::list clones the selector's zone/type_name/owner_uid fields to bind SQL params - fix: bind borrowed forms (selector.zone.as_deref(), selector.type_name.as_deref(), selector.owner_uid.as_deref()), which rusqlite params accept - [packages/d2b-resource-runtime/src/spec_store.rs:596-598] - evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 36 hits in lane; the three clones at spec_store.rs:596-598 are avoidable. -- d2b-resource-runtime-p2#6 sev=low blast=leaf effort=S verdict=actionable - TargetDirectory::assign clones the assignment twice (once into the map, once for the return value) - fix: insert the owned assignment and clone from the map for the return, halving the copies of the 3-string ResourceKey and the resolved handle - [packages/d2b-resource-runtime/src/target.rs:655, packages/d2b-resource-runtime/src/target.rs:663] - evidence: seed `\.clone\(\)` = 86 hits in lane; assign() runs on the daemon spawn path (per resource spawn). -- d2b-resource-runtime-p2#7 sev=low blast=leaf effort=S verdict=actionable - json_object clones every member Value into the map although every caller constructs the member array inline - fix: take members: impl IntoIterator and move values into the map - [packages/d2b-resource-runtime/src/guest_target.rs:1004-1009] - evidence: seed `\.clone\(\)` = 86 hits in lane; this clone runs on every target-control frame encode (guest_target.rs:820-863). - -## type -- clean: seeds `fn validate_\w+|fn check_\w+`, `is_\w+: bool|\w+_flag: bool`, `(mode|kind|state): String` = 0/0/0 hits; structs and enums audited by read; WatchCondition::Custom is a documented not-implemented extension point (the recorded false-positive class), and the wire rows (StoredDesiredResource, ResourceKey) are schema-mirroring shapes. - -## api -- d2b-resource-runtime-p2#8 sev=medium blast=family effort=M verdict=actionable - ResourceContext::new accepts `_target: TargetHandle` and discards it; every caller supplies a value that is silently dropped - fix: remove the parameter and update the 21 call sites (provider family, resource.rs, metadata.rs, context.rs test_support), or store it and expose ResourceContext::target() per U4's "coarse handle a driver context exposes" - [packages/d2b-resource-runtime/src/context.rs:364-366] - evidence: census: `ResourceContext::new` over packages/ = 22 hits (definition plus 21 call sites, all passing TargetHandle::Host except resource.rs:558). -- d2b-resource-runtime-p2#9 sev=medium blast=leaf effort=S verdict=actionable - TargetBinding::directory() returns &Arc (internals leak in a public signature) and has zero callers - fix: remove the accessor, or return &TargetDirectory if a caller appears - [packages/d2b-resource-runtime/src/target.rs:491-493] - evidence: census: `\.directory\(\)` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 2 hits, both d2b-audit's own writer.directory() (a different type); 0 hits for TargetBinding. -- d2b-resource-runtime-p2#10 sev=low blast=leaf effort=S verdict=actionable - GuestTargetRuntime::reference() returns TargetRef by value (clones the name String) and has zero callers - fix: remove the accessor, or return &TargetRef - [packages/d2b-resource-runtime/src/guest_target.rs:460-462] - evidence: census: `\.reference\(\)` over the workspace = hits only on GuestTargetHandle::reference (target.rs) and d2bd row.reference() (foundation_seed.rs); 0 hits for GuestTargetRuntime::reference. - -## err -- d2b-resource-runtime-p2#11 sev=medium blast=leaf effort=S verdict=actionable - row_from silently substitutes [0; 16] when a stored uid or owner_uid column is not exactly 16 bytes, giving a corrupt row a zero identity that collides with every other zero-uid row - fix: return a typed error (a new SpecStoreError::CorruptRow { zone, type_name, name } variant) instead of try_into().unwrap_or([0; 16]) - [packages/d2b-resource-runtime/src/spec_store.rs:553, packages/d2b-resource-runtime/src/spec_store.rs:555] - evidence: seed `\.unwrap\(\)|\.expect\(` = 96 hits in lane, 8 non-test, all named invariants (OnceCell cache, in-transaction row presence, literally-built JSON, u64 sequence overflow); the row_from substitution is not seed-caught (unwrap_or) and was found by static read. -- clean: seed `let _ = |\.ok\(\);` = 23 hits, all deliberate best-effort cleanup or test stubs (reply.send to a dropped caller, ROLLBACK on error, permission tightening, join); seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 21 hits, all in test modules; seed `enum \w*Error` = 3 (TargetError, SpecStoreError, GuestTargetError), each a closed internal taxonomy with a stable Display code. - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 0, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 8 hits, all the target-control frame encode/decode (guest_target.rs:823, 829, 863, 869); the hand-rolled Value walking is a live protocol admission gate mapping every failure to ProtocolMismatch, the recorded refusal class for hand-written admission gates, and the frame shape is pinned by the guest/host contract; the two expects on literally-built JSON are the recorded false-positive class. - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0 in this partition; the crate's tracing use lives in the part 1 files (manager.rs, resource.rs). - -## docs -- d2b-resource-runtime-p2#12 sev=low blast=leaf effort=S verdict=actionable - TargetControlAssignment's five methods (new, source, source_uid, assignment_generation, session_generation) are the only wire-carried type accessors without doc comments while sibling wire types (TargetResourceInstance, GuestRealizeRequest, TargetControlFrame) document every method - fix: add one-line docs to each - [packages/d2b-resource-runtime/src/guest_target.rs:205-228] - evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 148 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 45; static read of guest_target.rs:204-229. -- d2b-resource-runtime-p2#13 sev=low blast=leaf effort=S verdict=actionable - constructor and accessor doc gaps on public items - fix: add one-line docs to ResourceTypeName::new/as_str, ResourceKey::new, ResourceProvenance::as_str, GuestTargetRuntime::new, TargetBinding::new, GuestTargetHandle::is_bound, SpecStore::path - [packages/d2b-resource-runtime/src/identity.rs:20, packages/d2b-resource-runtime/src/identity.rs:24, packages/d2b-resource-runtime/src/spec_store.rs:61, packages/d2b-resource-runtime/src/spec_store.rs:75, packages/d2b-resource-runtime/src/spec_store.rs:761, packages/d2b-resource-runtime/src/guest_target.rs:449, packages/d2b-resource-runtime/src/target.rs:486, packages/d2b-resource-runtime/src/target.rs:196] - evidence: docs seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 148 hits; static read of each cited site confirms no doc comment; the crate otherwise documents its public surface thoroughly (no missing_docs lint is enabled anywhere). - -## perf -- d2b-resource-runtime-p2#14 sev=low blast=leaf effort=S verdict=actionable - hex rendering allocates a fresh String per byte via format! inside the loop at two sites - fix: write!(&mut rendered, "{byte:02x}") with use std::fmt::Write into the pre-sized String - [packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/guest_target.rs:1212] - evidence: seed `format!\(` = 15 hits in lane; the two loop sites are the only per-iteration allocations (target_local_spec_digest and hex_encode, both on the realize/frame wire path); static (unmeasured). - -## conc -- d2b-resource-runtime-p2#15 sev=low blast=leaf effort=S verdict=actionable - parking_lot (banned outright by clippy.toml:40-43, plan KD3, except the R4 worker boundary) is a [dependencies] entry consumed only by #[cfg(test)] code - fix: move parking_lot to [dev-dependencies] or replace the two test uses with std::sync::Mutex - [packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:800, packages/d2b-resource-runtime/src/context.rs:1044] - evidence: census: `parking_lot` over packages/d2b-resource-runtime = 3 hits (manifest plus 2 cfg(test) sites); supply-tagged manifest posture (the workspace-level supply lens is lane X1). -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 1 (the spec-store writer thread, the sanctioned R4 bounded worker with its documented allow), `\bMutex<|\bRwLock<` = 8, `Atomic\w+|Ordering::` = 33, `thread_local!|unsafe impl (Send|Sync) for` = 0; the atomics are Relaxed counters or the documented AcqRel/acquire generation fence in bind_session, and the tokio Mutex + non-blocking try_lock sync surfaces are the documented plan U4 shape. - -## async -- clean: seeds `async fn|async move|\.await` = 150+ hits (tool-truncated), `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 6+ (tool-truncated), `tokio::sync::(Mutex|RwLock|Notify)` = 8, `#\[tokio::(main|test)\]|Runtime::block_on` = 21 (all #[tokio::test]); SpecStore::call is try_send refuse-don't-queue with a documented unbounded reply await (loader_worker doctrine), WatchStream::recv is cancellation-safe (the missed AtomicBool is checked before the biased notify select and re-checked at loop top), no guard is held across an await anywhere (locks are scoped per iteration in adopt/session_authority), and every sync surface uses the documented plan U4 non-blocking try_lock. - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; the crate inherits workspace `unsafe_code = "forbid"` via `[lints] workspace = true` (Cargo.toml:170). - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the crate crosses no foreign boundary. - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0. - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 30+ hits (tool-truncated), `assert_eq!\(|assert_ne!\(|assert!\(` = 60+ hits (tool-truncated), `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the sampled tests assert real contracts with failure messages (watch gap-free LIST->WATCH replay and Missed frontier, spec-store commit-before-return durability and crash survival, driver classification at the erased boundary, target-control generation fencing) and none restates the implementation; no test that cannot fail was found. - -## Coverage -- idiom: 3 finding(s) -- own: 4 finding(s) -- type: clean (seeds ran: 0/0/0) -- api: 3 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 0/0/0/8) -- obs: clean (seeds ran: 0/0/0/0) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: 1 finding(s) -- async: clean (seeds ran: 150+/6+/8/21) -- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace unsafe_code = "forbid") -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 30+/60+/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md deleted file mode 100644 index cab55279a..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p1.md +++ /dev/null @@ -1,72 +0,0 @@ -# d2b-session-p1 - d2b-session - part 1/2 -Baseline: 6ebdd4cec | LOC audited: 5296 (excl. src/generated/**) | modules: driver, server, handshake, operation, streams, scheduler, cancellation, fragmentation, attachment, metrics, typed_stream -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/2 per U1 (f): src/driver.rs, src/server.rs, src/handshake.rs, src/operation.rs, src/streams.rs, src/scheduler.rs, src/cancellation.rs, src/fragmentation.rs, src/attachment.rs, src/metrics.rs, src/typed_stream.rs - -## idiom -- clean: seeds ran: 5/0/0. The five `for ... in 0..` hits are bounded rotate scans (`pump_named_stream` driver.rs:1626, `FairScheduler::dequeue` scheduler.rs:222) and test loops (driver.rs:2208, 2261, streams.rs:308); no hand-written `Default`/`From`/`PartialEq`/`Eq`/`Debug`/`Clone`/`Hash` impls, no statement-style `String`/`Vec` accumulation. Hand-written `Debug` impls all redact secrets (repo-sanctioned pattern). - -## own -- clean: seeds ran: 30/14/1. Every clone is explainable: `Cancellation`/`Arc` clones at task and command boundaries (driver.rs:124, 347-350, 501-502, 1539, 1611, 2149; server.rs:45, 70, 254, 317, 527; cancellation.rs:71, 184), `RequestId` clones for registry-plus-command pairs (server.rs:245, 259), `policy.clone()` at the handshake encoding boundary (handshake.rs:112, 171), `offer_bytes.to_vec()` for owned canonical bytes (handshake.rs:134), fragment `bytes.to_vec()` for per-fragment ownership (fragmentation.rs:92); the single `Arc>` is a test fixture (driver.rs:1735). No `Rc`/`RefCell`/`Cow`. - -## type -- d2b-session-p1#1 sev=low blast=leaf effort=S verdict=actionable - `OutboundFrame::channel()` silently falls back to `SESSION_CONTROL` for the constructor-prevented NamedStream-without-stream combination, so an invariant break would misroute a frame to the session control channel with no error - fix: encode the stream inside the class (enum variants `SessionControl`/`TtrpcControl`/`AttachmentControl`/`Named(StreamId, ...)`) or make `channel()` return `Result` and drop the `unwrap_or(SESSION_CONTROL)` fallback - [scheduler.rs:18-21, scheduler.rs:66-68] - evidence: type seeds: validate/check fns 4 hits (all boundary validators - `validate_frame` server.rs:360, `validate_credentials` handshake.rs:365, attachment descriptor validation - not findings); `(mode|kind|state): String` 0 hits; bool-flag 0 hits. The class/stream pairing is the one representable-but-guarded combination; constructors `control()`/`named()` (scheduler.rs:25, 36) already reject the bad pair, making the fallback a silent-wrong-value hazard rather than a live illegal state. - -## api -- d2b-session-p1#2 sev=low blast=leaf effort=S verdict=actionable - `Fragment.header` is a public mutable field on an exported wire-facing struct while `bytes` is private behind `as_bytes()`, so external crates can corrupt the header/bytes pairing (reassembly validates at use, but the surface invites it) - fix: make `header` private and add `pub fn header(&self) -> &FragmentHeader`, keeping construction through `Fragmenter`/`from_parts` - [fragmentation.rs:10-13] - evidence: api seeds: pub items 129 (surface re-exported single-path from lib.rs, house pattern); `pub ... Arc|Rc|Box|RefCell<` 0 hits in signatures except evaluated `Arc` at server.rs:202-206 (call sites d2bd/src/composition.rs:7940, d2b-provider-toolkit/src/server/mod.rs:68 - shared ownership across server task and caller, justified); `pub use` arms only in lib.rs. Census: `Fragment` consumed by engine.rs and d2b-bus/src/session/mod.rs:106 - reads header fields only, so an accessor suffices. - -## err -- clean: seeds ran: 88/40/6/2. All 88 unwrap/expect hits are inside `#[cfg(test)]` modules except `resource_operation`'s `expect("every ApiMethod has one unary ResourceService member")` (operation.rs:182) on the generated catalog invariant (compile-time-known closed `ApiMethod` set - acceptable per card). All 40 `let _ =` sites are deliberate best-effort `reply.send`/`writer.close()` on error paths where the receiver may be gone (driver.rs:567, 596, 862, 872, 992, 1264-1346; server.rs:269, 354; cancellation.rs:103). All 6 panics are test assertions. Error enums `SessionServerError` (server.rs:182) and `AttachmentValidationError` (attachment.rs:23) are small and caller-action-split. - -## serde -- N/A: seeds: 0/0/0/0 all zero; crate crosses no serde wire boundary (canonical binary encodings and protobuf framing instead). - -## obs -- clean: seeds ran: 0/0/0/7. Zero `println!`/`eprintln!`; zero interpolated-message events; all 7 `tracing::` sites use named fields (`error = %error`, `stream_id = ...`, `count = ...` - driver.rs:167, 526, 538; server.rs:270, 324, 331, 348). No secrets in fields; no subscriber installed (library). - -## docs -- d2b-session-p1#3 sev=medium blast=leaf effort=M verdict=actionable - the security-critical handshake module has zero doc comments on its entire pub surface (23 pub items re-exported from lib.rs): wire functions with magic lengths and closed error codes (`x25519_public_key`, `encode_offer`, `negotiate_offer`, `accept_generation_discovery_request`, `decode_generation_discovery_response`, `NoiseHandshake`, `EstablishedHandshake`, `HandshakeCredentials`, `NegotiatedOffer`) carry no first-sentence contract, no `# Errors`, no `# Panics` - fix: add first-sentence docs plus `# Errors` sections naming the `SessionErrorCode` each function returns, and `# Panics` where a step mismatch panics - [handshake.rs:25, handshake.rs:111, handshake.rs:155, handshake.rs:239, handshake.rs:441] - evidence: docs seeds: pub items 129, `/// # (Examples|Errors|Panics|Safety)` 0 hits, `-> Result<` 124 hits; per-file doc scan: handshake.rs 0 `///` on 23 pub items (worst in lane; driver.rs 20 on 4, typed_stream.rs 11 on 8 show the house pattern exists). Consumers: engine.rs, d2b-bus/src/session/mod.rs:102-156, d2bd, d2bd-runtime, d2b-provider-toolkit - all rely on these functions. -- d2b-session-p1#4 sev=medium blast=leaf effort=M verdict=actionable - the flow-critical state machines `NamedStreamMux`, `FairScheduler`, `Fragmenter`/`Reassembler`, `StreamId`/`StreamPhase`/`StreamEvent`, `OutboundFrame`, `QueueClass` have zero doc comments on 46 pub items (credit accounting, phase transitions, and error codes are non-obvious) - fix: first-sentence docs on each type and pub method, `# Errors` on the Result-returning mutators, and a module doc in each file - [streams.rs:10, streams.rs:77, streams.rs:165, scheduler.rs:18, scheduler.rs:95, fragmentation.rs:38, fragmentation.rs:99] - evidence: docs seeds: pub items 129, `/// # (Examples|Errors|Panics|Safety)` 0 hits; per-file doc scan: streams.rs 0 `///` on 20 pub items, scheduler.rs 0 on 16, fragmentation.rs 0 on 10. These types are the multiplexing/flow-control core consumed by engine.rs and d2b-bus. -- d2b-session-p1#5 sev=low blast=leaf effort=S verdict=actionable - the magic bound `value.len() > 128` in `OperationMember::parse` is undocumented: the reader cannot tell why 128 is the canonical member spelling limit or what happens to longer wire strings - fix: extract `const MAX_MEMBER_SPELLING_LEN: usize = 128;` with a comment naming the bound's purpose (wire-visible admission bound) - [operation.rs:207] - evidence: docs seeds: `/// # (Examples|Errors|Panics|Safety)` 0 hits; the 128 literal is the only undocumented magic value in the lane's validation paths (checked against `valid_identifier` at operation.rs:210). - -## perf -- clean: seeds ran: 0/16/14. Zero `format!` sites; all 16 `Vec::new`/`VecDeque::new`/`BTreeMap::new` are struct constructors or test fixtures (cold); all 14 `to_string`/`to_vec` are error-path logging (driver.rs:524), wire-boundary ownership copies (handshake.rs:134, server.rs:295), or tests. Hot paths are already shaped: `Vec::with_capacity` in `Fragmenter::fragment` (fragmentation.rs:70), `Reassembler::accept` (fragmentation.rs:135), `ttrpc_request_id` (server.rs:381), `NegotiatedOffer::prologue` (handshake.rs:100); `NamedStreamEventQueue::receive_for`'s O(n) scan is bounded by DRIVER_EVENT_CAPACITY 128. static (unmeasured). - -## conc -- clean: seeds ran: 0/0/57/0. No `std::thread` usage; no `unsafe impl Send/Sync`; the 57 atomics/Mutex/Ordering hits are the documented lock-free admission counter (cancellation.rs:18-30, plan U19 comment; Release/Acquire/AcqRel pairs with a written ordering argument), the generation counter `Arc` (driver.rs:109, 189), and test fixtures. `ActiveInboundCalls` (server.rs:30, 224) is a tokio Mutex held per-statement, never across an await. - -## async -- clean: seeds ran: 21. Two dedicated worker tasks (`tokio::spawn(run_writer)` driver.rs:354, `tokio::spawn(run_driver)` driver.rs:361) with bounded channels and `Notify`-armed-before-check waits (cancellation.rs:74-80, matches the clippy.toml replacement vocabulary); no guard held across `.await` (server.rs lock scopes are per-statement); no blocking work inside async contexts; `cancel_and_wait` returns `impl Future + Send + 'static`; `abort_writer_and_wait` cannot hang (oneshot send failure skips the wait, driver.rs:1540-1548); the remaining hits are `#[tokio::test]` and test spawns. - -## unsafe -- N/A: seeds: 0/0/0 all zero; crate declares `#![forbid(unsafe_code)]` (lib.rs:5), no unsafe blocks, fns, or impls in the lane. - -## ffi -- N/A: seeds: 0 all zero; no extern "C", no_mangle, repr(C), CStr/CString, or catch_unwind in the lane. - -## macro -- N/A: seeds: 0 all zero; no macro_rules!, proc-macro, syn/quote, or $crate usage in the lane. - -## test -- clean: seeds ran: 23/53/0/0. Six of the eleven files carry `#[cfg(test)]` modules (driver.rs 11 tests, server.rs 4, operation.rs 3, streams.rs 1, cancellation.rs 1, metrics.rs 1); all are deterministic (Notify-based, `tokio::time::timeout` only for liveness bounds), assert observable behavior (error codes, ordering, capacity semantics, redaction), use table-driven cases with per-case messages (metrics.rs:97-123, operation.rs:339-347), and can fail (e.g. driver.rs:2166-2169 asserts the full-queue rejection path). No `#[ignore]`, no proptest/insta/rstest. tests/noise_vectors.rs and tests/component_session.rs (out of the published partition) differentially exercise handshake.rs against snow's own implementation. - -## Coverage -- idiom: clean (seeds ran: 5/0/0; index loops are bounded rotate/drain patterns) -- own: clean (seeds ran: 30/14/1; every clone/to_owned explainable at a boundary) -- type: 1 finding(s) -- api: 1 finding(s) -- err: clean (seeds ran: 88/40/6/2; only non-test unwrap/expect is the generated-catalog invariant expect at operation.rs:182) -- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no serde wire boundary) -- obs: clean (seeds ran: 0/0/0/7; all tracing events use named fields) -- docs: 3 finding(s) -- perf: clean (seeds ran: 0/16/14; no format!, hot paths pre-sized, static (unmeasured)) -- conc: clean (seeds ran: 0/0/57/0; atomics documented with a written ordering argument) -- async: clean (seeds ran: 21; two worker tasks, no guard across await, no blocking) -- unsafe: N/A (seeds: 0/0/0 all zero; #![forbid(unsafe_code)] at lib.rs:5) -- ffi: N/A (seeds: 0 all zero) -- macro: N/A (seeds: 0 all zero) -- test: clean (seeds ran: 23/53/0/0; deterministic, behavior-asserting, table-driven) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md deleted file mode 100644 index 212d25def..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-p2.md +++ /dev/null @@ -1,89 +0,0 @@ -# d2b-session-p2 - d2b-session - part 2/2 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 5364 (excl. src/generated/**) | modules: admission.rs, engine.rs, error.rs, client.rs, transport.rs, lifecycle.rs, record.rs, bootstrap.rs, deadline.rs, lib.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 2/2 per U1 (f); test lens adds tests/** - -## idiom -- d2b-session-p2#1 sev=low blast=leaf effort=S verdict=actionable - decode_attachment_control walks the descriptor table with an index loop plus manual offset arithmetic where an iterator pipeline fits - fix: replace the `for _ in 0..count` loop with `bytes[3..].chunks_exact(ATTACHMENT_DESCRIPTOR_BYTES).take(usize::from(count)).map(decode_attachment_descriptor).collect::, _>>()` - [engine.rs:1802, engine.rs:1803, engine.rs:1807] - evidence: seed `for \w+ in 0\.\.` = 1 hit; the loop at engine.rs:1803 is the only index loop in the part -- d2b-session-p2#2 sev=low blast=leaf effort=S verdict=actionable - send_authorized_ttrpc re-implements the exact verb allow-list check that validate_ttrpc_permit already encodes - fix: call `validate_ttrpc_permit(&permit, now_tick)?` instead of re-writing the matches! block - [admission.rs:1593, admission.rs:956, admission.rs:958] - evidence: seed `fn validate_\w+` = 7 hits; the Invoke|AuditExport|SupportBundle matches! block appears verbatim at admission.rs:958-962 and admission.rs:1597-1601 - -## own -- d2b-session-p2#3 sev=low blast=family effort=S verdict=actionable - take_authentication and from_verified_adapter clone the whole EndpointPolicy just to build a comparison HandshakeOffer - fix: add `impl From<&EndpointPolicy> for HandshakeOffer` in d2b-contracts-zone-session and call HandshakeOffer::from(policy) - [engine.rs:689, admission.rs:593] - evidence: seed `\.clone\(\)` = 51 hits; both sites are one-shot admission-path clones of a struct holding LimitProfile, TransportBinding, and AttachmentPolicy; all other clones in the part are explainable (spawn boundaries, snapshot copies, Arc clones) - -## type -- d2b-session-p2#4 sev=low blast=leaf effort=S verdict=actionable - stream control is decoded as a raw u8 kind inside a (u8, StreamId, u32) tuple and matched against local constants, so an unknown tag stays representable until the runtime match - fix: introduce a closed StreamControlKind enum with tag()/from_tag() beside the existing AttachmentControl enum - [engine.rs:1702, engine.rs:1295, engine.rs:31] - evidence: seed `fn validate_\w+|fn check_\w+` = 7 hits; STREAM_CLOSE/STREAM_CREDIT/STREAM_RESET constants at engine.rs:31-33 are matched in receive_stream_control at engine.rs:1297-1308; the validate_* hits are boundary checks on wire-derived values, not repeated validation - -## api -- d2b-session-p2#5 sev=low blast=leaf effort=M verdict=actionable - SessionEngine exposes seven establishment constructors, the metrics-taking variants have no production callers, and a public with_metrics builder already exists - fix: drop establish_initiator_with_generation_discovery_and_metrics and establish_responder_with_metrics, keep one metrics-taking path per role, and give establish_responder_with_generation_floor a metrics twin instead of recording into a fresh NoopMetrics - [engine.rs:166, engine.rs:262, engine.rs:416, engine.rs:356, engine.rs:584] - evidence: census: `establish_initiator_with_metrics` over packages/tests/labs = 1 hit (tests/component_session.rs:1243); `establish_responder_with_metrics` = 0 external hits; `establish_initiator_with_generation_discovery_and_metrics` = 0 external hits; seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 155 hits; the generation-floor variant records with Arc::new(NoopMetrics) at engine.rs:406 - -## err -- d2b-session-p2#6 sev=medium blast=leaf effort=S verdict=actionable - OwnedTransportHandle panics via expect on descriptor, into_owned_transport, and close after the handle is consumed, because the Option> keeps the consumed state representable - fix: return Option or Result from into_owned_transport and close, or split the handle into a typestate so double-consume does not compile - [transport.rs:170, transport.rs:178, transport.rs:185, transport.rs:173] - evidence: seed `\.unwrap\(\)|\.expect\(` = 23 hits; the three expects at transport.rs:173,181,188 are the only non-test panic sites on a public API in the part (the other hits are cfg(test-support) helpers and test code) -- d2b-session-p2#7 sev=medium blast=leaf effort=S verdict=actionable - SessionClientBridgeError's Display prints a fixed label and the Error impl has no source(), so the inner SessionError code is lost from the chain when the bridge logs it - fix: implement Error::source() returning Some(&SessionError) for the Session variant, and/or include the code in Display - [client.rs:216, client.rs:224, client.rs:237] - evidence: seed `enum \w*Error` = 3 hits; bridge termination logs at client.rs:60-70 print only the fixed label via %error, so an operator cannot see the underlying SessionErrorCode - -## serde -- N/A: seeds `derive(...Serialize|Deserialize)` / `serde(...)` / `impl .*Deserialize` / `serde_json::from_|to_` all 0 hits; this part crosses no serde boundary (crate-level matrix cell is 0) - -## obs -- clean: seeds ran: 0/0/0/12 - no println/eprintln, no interpolated message-only events, no instrument spans; all tracing::warn!/debug! calls use named fields (error = %error, purpose, service, timeout_ms, minimum_generation), and the redacting Debug impls keep secrets out of fields - -## docs -- d2b-session-p2#8 sev=medium blast=leaf effort=M verdict=actionable - SessionEngine and SessionEvent plus 24 of the engine's pub methods carry no doc comments, leaving the crate's central data plane undocumented - fix: add one-line docs, with # Errors on the Result-returning methods and # Panics where applicable - [engine.rs:38, engine.rs:84, engine.rs:584, engine.rs:677, engine.rs:681, engine.rs:702, engine.rs:722, engine.rs:737, engine.rs:763, engine.rs:772, engine.rs:776, engine.rs:780, engine.rs:784, engine.rs:788, engine.rs:803, engine.rs:812, engine.rs:941, engine.rs:956, engine.rs:971, engine.rs:1037, engine.rs:1056, engine.rs:1448] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 155 hits; awk scan of engine.rs counts 24 pub methods with no preceding /// (missing_docs is not enabled; this is a proposal only) -- d2b-session-p2#9 sev=medium blast=leaf effort=S verdict=actionable - the whole public surface of lifecycle.rs, record.rs, bootstrap.rs, and deadline.rs is undocumented, including non-obvious state machines such as SessionLifecycle::poll_keepalive and begin_reconnect - fix: add item docs with # Errors sections on the Result-returning methods - [lifecycle.rs:38, lifecycle.rs:81, lifecycle.rs:147, record.rs:62, record.rs:107, bootstrap.rs:87, deadline.rs:14] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 155 hits; awk scan counts 10 undocumented pub methods in lifecycle.rs, 5 in record.rs, 5 in bootstrap.rs, 5 in deadline.rs -- d2b-session-p2#10 sev=low blast=leaf effort=S verdict=actionable - the route-binding accessors on AuthenticatedSessionRouteBinding, the SessionError accessors, and the TransportPacket methods are undocumented while their siblings carry docs - fix: add one-line docs to the accessors at the anchors - [admission.rs:1182, admission.rs:1186, admission.rs:1190, admission.rs:1194, admission.rs:1198, admission.rs:1237, admission.rs:1241, admission.rs:1245, admission.rs:1249, admission.rs:1253, admission.rs:1257, error.rs:31, error.rs:47, error.rs:51, error.rs:55, error.rs:116, transport.rs:23, transport.rs:30, transport.rs:34, transport.rs:38, transport.rs:42] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 155 hits; awk scan confirms 11 admission.rs, 5 error.rs, and 5 transport.rs pub items without a preceding /// -- d2b-session-p2#11 sev=low blast=leaf effort=S verdict=actionable - serialized_transport_split's doc claims it exists for engine-only test transports, but production code in d2b-bus and the crate's own driver call it - fix: rewrite the doc to state the serialized-compatibility contract (halves must never be driven concurrently) - [transport.rs:208, transport.rs:212] - evidence: census: `serialized_transport_split` over packages = 6 hits, including d2b-bus/src/session/zone_link.rs:634 and d2b-session/src/driver.rs:456 - -## perf -- d2b-session-p2#12 sev=low blast=leaf effort=S verdict=actionable - unprotect allocates a fresh plaintext buffer sized to the limit and copies the payload out with to_vec on every received record - fix: keep a reusable scratch buffer on RecordProtector and return plaintext.split_off(RECORD_HEADER_LEN) instead of payload.to_vec() - [record.rs:125, record.rs:147] - evidence: static (unmeasured); seed `Vec::new\(\)` = 11 hits; unprotect runs once per protected record on the receive hot path -- d2b-session-p2#13 sev=low blast=leaf effort=S verdict=actionable - flush copies every dequeued logical frame with as_bytes().to_vec() because OutboundFrame only exposes a borrowed view - fix: add OutboundFrame::into_bytes() in scheduler.rs and consume it in flush - [engine.rs:1354, engine.rs:1362, scheduler.rs:72] - evidence: static (unmeasured); seed `Vec::new\(\)` = 11 hits; one copy per logical frame on the send path before fragmentation and encryption -- d2b-session-p2#14 sev=low blast=leaf effort=S verdict=actionable - the replay cache is a VecDeque scanned linearly with contains() on every received record - fix: use a bounded HashSet<[u8; 32]> or document why the 1024-entry linear scan is acceptable - [record.rs:120, record.rs:146] - evidence: static (unmeasured); REPLAY_CACHE_ENTRIES = 1024 at record.rs:12; contains() runs per record before sequence acceptance - -## conc -- d2b-session-p2#15 sev=low blast=leaf effort=S verdict=actionable - AuthenticatedSessionDriver._owner is a std::sync::Mutex that is never locked, serving only as a Sync carrier for the ComponentSessionDriver: Send + Sync bound, with no comment saying so - fix: document the Sync-carrier intent on the field or replace it with a named wrapper type - [admission.rs:756, admission.rs:1666, driver.rs:33] - evidence: seed `\bMutex<` = 3 hits; grep `_owner` over admission.rs = 2 hits (declaration and construction), no lock() or get_mut() call anywhere; the SessionLiveness AtomicBool uses the correct Acquire/Release pair and the transport split uses tokio::sync::Mutex - -## async -- clean: seeds ran: 201/1/1/3 - all handshake and packet-send I/O is wrapped in tokio::time::timeout, the serialized split uses tokio::sync::Mutex (no std guard across awaits), the client bridge uses tokio::spawn plus select! with cancellation, and no blocking call or lock guard crosses an await point in the part - -## unsafe -- N/A: seeds 1-3 all zero (no unsafe blocks, fns, impls, transmute, from_raw, MaybeUninit, or mem::zeroed); seed 4 = 1 hit, the `#![forbid(unsafe_code)]` attribute at lib.rs:6, which alone does not make the lens applicable - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` / `catch_unwind` / `repr\(C\)|repr\(transparent\)` / `CStr|CString|c_char` all 0 hits; no FFI surface in the part - -## macro -- d2b-session-p2#16 sev=low blast=leaf effort=S verdict=actionable - the local admit_try! macro exists only to fuse an early return with a metric record, which a plain helper function plus ? expresses - fix: replace each invocation with `let result = ; admit_or_record(&mut engine, result)?` where admit_or_record records the failure metric and returns the error - [admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643, admission.rs:648, admission.rs:661] - evidence: seed `macro_rules!` = 3 hits; the macro is invoked 5 times inside admit; the other two macro_rules! sites (mutate_session_acceptor_trait!, mutate_authenticated_session_trait!) are cfg-gated impl-generation scaffolding for compile-fail verification and are justified - -## test -- d2b-session-p2#17 sev=low blast=leaf effort=S verdict=actionable - unpolled_cancellation_on_real_driver_reclaims_request_for_reuse spins up to 64 yield_now iterations waiting for the cancellation task to reclaim the request, while its sibling test waits on a Notify - fix: wait on a Notify (or a tokio::time::timeout around a Notify) instead of the fixed spin cap - [tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139] - evidence: seed `#\[test\]|#\[tokio::test\]` = 5 hits in src plus 40 test fns across tests/; the sibling failed_cancellation_delivery test uses send_failure.entered.notified() with a 1s timeout at tests/admission.rs:139-142; no proptest/insta/rstest and no #[ignore] anywhere - -## Coverage -- idiom: 2 finding(s) -- own: 1 finding(s) -- type: 1 finding(s) -- api: 1 finding(s) -- err: 2 finding(s) -- serde: N/A (seeds: 0/0/0/0 all zero; no serde derives, attributes, hand-written Deserialize, or json crossing in this part) -- obs: clean (seeds ran: 0/0/0/12; no println, no interpolated message-only events, all events carry named fields) -- docs: 4 finding(s) -- perf: 3 finding(s) -- conc: 1 finding(s) -- async: clean (seeds ran: 201/1/1/3; timeouts wrap handshake and send I/O, tokio Mutex for the serialized split, no blocking calls or guards across awaits) -- unsafe: N/A (seeds: 0/0/0/1 all zero except the forbid attribute at lib.rs:6; no unsafe code in the part) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: 1 finding(s) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md deleted file mode 100644 index 48882cdb2..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-session-unix.md +++ /dev/null @@ -1,72 +0,0 @@ -# d2b-session-unix - d2b-session-unix -Baseline: 6ebdd4cec | LOC audited: 6663 (excl. src/generated/**) | modules: whole crate -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: none (single-part lane) - -## idiom -- clean: seeds ran (3/1/8): the index loops at socket.rs:561 (fairness budget) and systemd.rs:176/194 (index needed for `take_custom`/`take_raw_fd`) are legitimate; the hand-written `Clone`/`Default`/`From` impls in subject.rs:61-80 are cfg-gated capability-mutation machinery whose `unreachable!()` bodies are the point (declared in the manifest check-cfg list); the `Vec::new()` accumulation loops are statement-style with per-item error handling and multiple outputs. - -## own -- clean: seeds ran (14/9/14/0): every clone is explainable - Arc clones at split/spawn boundaries (adapter.rs:523/524/627, credit.rs:69/88), cache stores (adapter.rs:234), owned returns (adapter.rs:209/281), CreditBundle copies for split reader/writer (adapter.rs:511/622), test fixtures (adapter.rs:1188, vsock.rs:547/553); the `same_descriptor_binding` clone (adapter.rs:997) is the chosen normalization for a two-field compare and the field-wise alternative is worse; `to_owned`/`to_string` hits are env-string conversions and test payloads; no `Rc`/`RefCell`/`Arc`/`Cow` in production. - -## type -- clean: seeds ran (8/0/0): all `validate_*` hits are boundary parsers the skill endorses - `validate_socket` at construction (socket.rs:637), `validate_descriptor`/`validate_value` as the once-per-attachment admission with a cached result (adapter.rs:258/942), `validate_owned_file*` on received fds (descriptor.rs:569/577), `validate_environment_values` at the env boundary (systemd.rs:201); `VerifiedUnixPeer::validate_transport` (subject.rs:126) is a cheap cross-transport guard on a value that crosses into d2b-session; no boolean-flag soup or stringly-typed state (seeds 2/3 zero). - -## api -- d2b-session-unix#1 sev=medium blast=family effort=S verdict=actionable - `SentPacket::acknowledge(self) {}` is a public no-op whose name promises an acknowledgment; its only behavior is dropping the packet (releasing the credit bundle via `Drop`), which callers cannot tell from the signature - fix: remove the method and let callers drop the packet, or document the drop-semantics contract on the method - [packages/d2b-session-unix/src/socket.rs:176] - evidence: seed `\bpub (fn|struct|enum|trait|type|const|mod)` = 140 hits; census: `\.acknowledge\(\)` over packages/ = 6 hits (adapter.rs:595, d2b-provider-guest-cloud-hypervisor/src/controller_session.rs:145, d2b-provider-test-controller/src/main.rs:208, d2b-provider-toolkit/src/base/fd10.rs:1001/1725, tests/unix_session.rs:819) -- clean: the rest of the surface is deliberate - `pub use` re-export arms in lib.rs (house single-surface pattern), `Arc` callback aliases and `with_observer(Arc)` genuinely shared across split transports (adapter.rs:432/718, cited call sites adapter.rs:627), private fields on all transport/socket types, `UnixTransportObserver` with one required method plus a defaulted `record_errno`. - -## err -- clean: seeds ran (22/5/3/4): production `expect` sites are invariants on internal state (`outbound was initialized`, adapter.rs:888, vsock.rs:158/272) or literally-built values (`compiled bootstrap Provider ref is valid`, zone_admission.rs:35 - the recorded false-positive class); `let _ =` sites are deliberate best-effort closes during shutdown/drain (adapter.rs:900, systemd.rs:196); `unreachable!()` in subject.rs is cfg-gated capability-mutation machinery; the four error enums are family-split with stable kebab-case wire renderings and caller-action mapping fns (`map_transport_error`, `map_validation_error`, `unix_failure_reason`). - -## serde -- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire - no serde dependency in the manifest and no `Deserialize`/`serde_json` anywhere in src. - -## obs -- clean: seeds ran (0/0/0/2): zero `println!`/`eprintln!` in the library; the only two `tracing` events (zone_admission.rs:80/89) are `warn!` with named fields (`provider`, `expected_uid`, `observed_uid`) and no interpolation; no secrets in fields (identity types carry redacting `Debug` impls, e.g. subject.rs:135, pidfd.rs:31); no spans, which is not required at this granularity. - -## docs -- d2b-session-unix#2 sev=medium blast=leaf effort=M verdict=actionable - the exported surface is largely undocumented: the transport, credit, descriptor, pidfd, systemd and vsock types and most of their pub methods carry no doc comment (only `VerifiedUnixPeer`, `ZoneBootstrapIdentity` and a handful of methods do) - fix: add first-sentence contract docs per pub item, starting with `SeqpacketSocket`, `UnixSeqpacketTransport`/`UnixStreamTransport`, `CreditPool`, `PidfdEvidence`, `PeerCredentials`, `ActivatedSeqpacketListener`, `FramedVsockTransport` - [packages/d2b-session-unix/src/socket.rs:190, packages/d2b-session-unix/src/adapter.rs:351, packages/d2b-session-unix/src/credit.rs:22, packages/d2b-session-unix/src/pidfd.rs:9, packages/d2b-session-unix/src/descriptor.rs:23, packages/d2b-session-unix/src/systemd.rs:44, packages/d2b-session-unix/src/vsock.rs:22] - evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 140 hits; seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits; `missing_docs` is not enabled - this is a proposal, not a gate failure -- d2b-session-unix#3 sev=low blast=leaf effort=S verdict=actionable - zero canonical `# Errors` sections exist despite roughly 60 pub `Result`-returning fns whose failure conditions are non-obvious (e.g. `SeqpacketSocket::from_owned` vs `from_parent_prearmed` vs `from_inherited_fd` fail differently) - fix: add `# Errors` sections naming the failing conditions to the pub `Result` fns - [packages/d2b-session-unix/src/socket.rs:202, packages/d2b-session-unix/src/socket.rs:210, packages/d2b-session-unix/src/socket.rs:222, packages/d2b-session-unix/src/adapter.rs:378] - evidence: docs seed 2 = 0 hits vs seed 3 (`-> Result<`) = 60 hits - -## perf -- d2b-session-unix#4 sev=low blast=leaf effort=S verdict=actionable - burst and collector `Vec`s grow from empty with an exact known upper bound, reallocating on the way - fix: `Vec::with_capacity(fairness_budget)` in `recv_burst`/`send_burst` and `Vec::with_capacity(attachments.len())` in `send_packet` - [packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, packages/d2b-session-unix/src/adapter.rs:540] - evidence: static (unmeasured); seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 15 hits; the remaining hits are empty-case defaults (receive_body, outbound None) or test fixtures -- clean: `format!` sites are cold (pidfd.rs:65 /proc path, zone_admission.rs:34 compiled ref) or tests; `to_string` sites are env-string conversions on cold paths; no hashing with attacker-controlled keys; no codegen-flag advice warranted. - -## conc -- clean: seeds ran (0/3/20/0): the two production `std::sync::Mutex` sites (adapter.rs:158 `validation`, adapter.rs:297 `ReceivedPacketState.inner`) carry `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` - sanctioned synchronous paths per the provider-crate-policy allow list, short critical sections with no suspension point; atomics are counters/flags with correct weakest orderings (CreditPool CAS AcqRel, `received_any` swap, `ACTIVATION_CONSUMED` compare_exchange); no threads, no `thread_local!`, no manual `Send`/`Sync`. - -## async -- clean: seeds ran (130/2/1/9): all socket I/O goes through the `AsyncFd` wrappers named in clippy.toml's replacement vocabulary (`SeqpacketSocket::recv_burst`/`send_burst`, `StreamSocket::read_available`/`write_all`, systemd accept loop); no blocking calls on executor workers (the only std fs call is the sanctioned sync pidfd surface with an allow, pidfd.rs:71); no guards held across `.await` (`await_holding_lock` deny is clean); framing is cancellation-safe via persistent buffers + `mem::take` (adapter.rs:813, vsock.rs:127) with dedicated cancellation tests; `tokio::spawn`/`join!` appear only in tests. - -## unsafe -- N/A: seeds 1-3 all zero (`\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 - the `from_raw` matches are `FileType::from_raw_mode`/`Pid::from_raw`/`io::Error::from_raw_os_error`, not pointer casts); manifest declares `unsafe_code = "forbid"`; the crate is not on the enumerated exception set in U1 (d) 8, consistent with zero blocks. - -## ffi -- N/A: seeds 0/0/0/0 all zero (`extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`, `CStr`/`CString`/`c_char` absent); the crate has no C boundary - libc/rustix calls are in-crate syscall wrappers. - -## macro -- clean: seed 1 = 1 hit (`macro_rules!` at subject.rs:59, the cfg-gated `mutate_verified_unix_peer_trait!` capability-mutation machinery whose generated impls must never be reachable - declared in the manifest check-cfg list, the test-only-helper-macro false-positive class); seeds 2-4 zero; no proc-macro or `$crate` usage. - -## test -- clean: seeds ran (32/75/0/0): the suite is behavior-asserting and deterministic - real kernel objects (pipes, pidfds, socketpairs), fd tests serialized through a global `LazyLock>` (unix_session.rs:21), error variants asserted rather than Display strings, adversarial sequences (recycled pidfd info, fd reuse, stale readiness, cancellation mid-frame), credit accounting verified at every scope, and `#[tokio::test(flavor = "current_thread")]` where fd state is shared; no `proptest`/`insta`/`rstest` and no `#[ignore]` (seeds 3/4 zero), which is appropriate for this kernel-surface suite. - -## Coverage -- idiom: clean (seeds ran: 3/1/8) -- own: clean (seeds ran: 14/9/14/0) -- type: clean (seeds ran: 8/0/0) -- api: 1 finding(s) -- err: clean (seeds ran: 22/5/3/4) -- serde: N/A (seeds: 0/0/0/0 all zero; no serde dependency, crate crosses no wire) -- obs: clean (seeds ran: 0/0/0/2) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 0/3/20/0) -- async: clean (seeds ran: 130/2/1/9) -- unsafe: N/A (seeds: 0/0/0/0 for seeds 1-3; manifest `unsafe_code = "forbid"`) -- ffi: N/A (seeds: 0/0/0/0 all zero; no C boundary) -- macro: clean (seeds ran: 1/0/0/0; cfg-gated test-only macro) -- test: clean (seeds ran: 32/75/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md deleted file mode 100644 index 55bdb490e..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-telemetry.md +++ /dev/null @@ -1,72 +0,0 @@ -# d2b-telemetry - d2b-telemetry -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1,983 (excl. src/generated/**) | modules: whole crate (audit_hash, emitter, meter_registry, metric_label_policy, redaction_guard, session_metrics_sink, trace_context) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate (single-part lane) - -## idiom -- clean: seeds `for \w+ in 0\.\.`=0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0, `let mut \w+ = (String|Vec)::new\(\)`=0; crate declares fns so the lens applies, and no index loops, no hand-written derive-replaceable impls, no statement-style accumulation were found (the hand-written Debug impls on AuditHash, TraceContext, and BoundedEmitter are the deliberate redaction class, and the hand-written Serialize/Deserialize impls are deliberate admission gates). - -## own -- clean: seeds `\.clone\(\)`=4, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=18, `Rc<|RefCell<|Arc>` plus `Arc` are the shared-ownership handles behind `BoundedEmitter`'s `Clone` (emitter.rs:167-168), the key/value clones build owned `BTreeMap`s at the admission boundary (emitter.rs:541, meter_registry.rs:107), the `child_span` trace_id clone is required by the Self-owned fields (trace_context.rs:63), and the rest are test fixtures; no `Rc`/`RefCell`/`Cow` anywhere. - -## type -- clean: seeds `fn validate_\w+|fn check_\w+`=3, `is_\w+: bool|\w+_flag: bool`=0, `(mode|kind|state): String`=0; the three validators (`validate_metric_frame` emitter.rs:502, `validate_resource_attributes` metric_label_policy.rs:14, `validate_span_field` redaction_guard.rs:95) are parse-once admission checks on untrusted wire input at the boundary, not validate-at-every-callsite smells, and no boolean-flag soup, stringly-typed state, or `Option`-pair states exist. - -## api -- clean: seeds `\bpub (fn|struct|enum|trait|type|const|mod) `=94, `pub .*\b(Arc|Rc|Box|RefCell)<`=0, `^\s*pub use `=9; the surface is deliberate - every pub item is documented, the `Arc` fields on `BoundedEmitter` are private (`socket_path()` returns `&Path`), the `pub mod` + `pub use` shape in lib.rs is the house single-surface pattern (d2b-audit/src/hash_chain.rs:3-6 and d2b-bus/src/metrics.rs:10-13 consume both paths; census: `d2b_telemetry::` over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 16 hits), and the `meter_registry::label` re-export is a live cross-crate API consumed by d2b-bus/src/metrics.rs:12. - -## err -- d2b-telemetry#1 sev=medium blast=leaf effort=S verdict=actionable - `BoundedEmitter::new_with_limits` reports invalid constructor arguments as `EmitterError::StatePoisoned`, conflating a permanent programming error with transient lock poisoning - fix: add a dedicated variant (e.g. `InvalidLimits`) and return it from the zero-capacity / zero-frame / zero-age / zero-retry guard clauses, keeping `StatePoisoned` for the `lock().map_err` sites - [packages/d2b-telemetry/src/emitter.rs:201-206, packages/d2b-telemetry/src/emitter.rs:93] - evidence: seed `enum \w*Error` = 5; the guard clauses at emitter.rs:201-206 return `StatePoisoned`, whose doc comment says "The emitter lock was poisoned" (emitter.rs:92-93); the Display strings are unpinned - census: `telemetry-emitter-state-poisoned` over packages/nixos-modules/tests/docs/labs/BUILD.bazel = 1 hit (its own Display arm) and no telemetry code appears in docs/reference/error-codes.md -- d2b-telemetry#2 sev=low blast=leaf effort=S verdict=actionable - `SessionMetricsError::Encode` is never constructed; the `io::Error` from `encode_frame` is folded into `EmitterError::MetricPolicy(DescriptorMalformed)` inside `emit_metric`, so the variant and its Display arm are dead surface - fix: delete the `Encode(std::io::Error)` variant and the `"session-metric-encode-failed"` Display arm - [packages/d2b-telemetry/src/session_metrics_sink.rs:73, packages/d2b-telemetry/src/session_metrics_sink.rs:82] - evidence: census: `SessionMetricsError::Encode|Encode\(` over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 2 hits, both self-referential (definition + Display arm); the only encode failure path maps to `EmitterError::MetricPolicy` at emitter.rs:328, so no construction path exists - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize`=3, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`=2, `impl .*Deserialize.*for`=2, `serde_json::from_|serde_json::to_`=5; the hand-written `Deserialize` impls on `AuditHash` (audit_hash.rs:48-56) and `TraceContext` (trace_context.rs:73-87) are live admission gates over private fields (the skill's parse-once pattern), `AuditChainLink` carries `rename_all = "camelCase"` + `deny_unknown_fields`, and `TraceContext`'s hand-written `Serialize` deliberately emits digested identities; no optionality or representation mistakes found. - -## obs -- N/A: seeds `\bprintln!\(|\beprintln!\(`=0, `(info|debug|warn|error|trace)!\("`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`=0, and Cargo.toml declares no tracing/log dependency; the crate is a synchronous library with no telemetry-emitting surface of its own. - -## docs -- d2b-telemetry#3 sev=low blast=leaf effort=M verdict=actionable - Result-returning public items carry no `# Errors` section stating which conditions produce which failure - fix: add `# Errors` sections to `AuditHash::parse` (audit_hash.rs:23), `AuditChainLink::verify`/`verify_at` (audit_hash.rs:103,126), `BoundedEmitter::new`/`new_with_limits`/`with_default_capacity`/`emit`/`emit_metric`/`drain`/`buffered_frames`/`buffered_bytes` (emitter.rs:183,194,228,236,316,340,385,395), `MetricFamily::new`/`record`, `MeterRegistry::register`/`record`, `RedactionGuard::new`/`validate_span_field`/`span_attributes`, `validate_resource_attributes`, and `SessionMetricsSink::record` - [packages/d2b-telemetry/src/emitter.rs:236, packages/d2b-telemetry/src/audit_hash.rs:23] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits against `-> Result<` = 20 hits; repo-wide `/// # Errors` over packages/ = 0 hits, so this is a proposal, not a house deviation; all pub items themselves are documented and every module carries a `//!` doc - -## perf -- clean: seeds `format!\(`=5, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`=4, `\.to_string\(\)`=0; the two production `format!` sites render hash strings in `AuditHash::from_bytes`/`record_hash` (cold construction paths), `hex_lower` pre-sizes with `with_capacity`, and the collection constructors are one-shot constructor-time allocations where the empty case is common; all static (unmeasured), no hot-loop allocation found. - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope`=1, `\bMutex<|\bRwLock<`=1, `Atomic\w+|Ordering::`=6, `thread_local!|unsafe impl (Send|Sync) for`=1; `Arc>` is a `std::sync::Mutex` on a genuinely synchronous path (the sanctioned class), the drop counters use `Relaxed` orderings (the weakest correct ordering for counters nobody synchronizes on), the `thread_local!` and `thread::sleep` are cfg(test) only, and no unsafe `Send`/`Sync` claims or `static mut` exist. - -## async -- N/A: seeds `async fn|async move|\.await`=0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(`=0, `tokio::sync::(Mutex|RwLock|Notify)`=0, `#\[tokio::(main|test)\]|Runtime::block_on`=0; the crate is a synchronous library surface (its own Cargo.toml comment records the frozen no-async-form posture). - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=0; seed 4 (`unsafe_code`) = 1 hit, the `#![forbid(unsafe_code)]` attribute at lib.rs:6, which per the lens card does not make the lens applicable; the crate manifest carries no `unsafe_code` setting (U1 (d) 8 lists it as ABSENT with no sites). - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0; no foreign boundary exists in the crate. - -## macro -- N/A: seeds `macro_rules!`=0, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0; no macros are defined or expanded beyond std/derive macros. - -## test -- d2b-telemetry#4 sev=medium blast=leaf effort=S verdict=actionable - contract rejection paths have no tests: `BoundedEmitter::new`/`new_with_limits` argument rejections (zero capacity -> StatePoisoned, relative path -> SocketPathInvalid), `AuditChainLink::verify` mismatch variants, `MeterRegistry::register` duplicate-name rejection, `MetricFamily::record` kind/value mismatch rejection, and `RedactionGuard::new` duplicate-key rejection are all untested, so a change that breaks any admission check passes the suite - fix: add unit tests asserting the exact variants, e.g. `assert_eq!(BoundedEmitter::new("relative", 128).unwrap_err(), EmitterError::SocketPathInvalid)`, `link.verify(&other, &payload, &record) == Err(ChainVerificationError::PreviousHashMismatch)`, and `registry.register(duplicate).unwrap_err() == MetricPolicyError::DescriptorMalformed` - [packages/d2b-telemetry/src/emitter.rs:201-210, packages/d2b-telemetry/src/audit_hash.rs:103-116, packages/d2b-telemetry/src/meter_registry.rs:88-96, packages/d2b-telemetry/src/meter_registry.rs:127-133, packages/d2b-telemetry/src/redaction_guard.rs:63-64] - evidence: seed `#\[test\]|#\[tokio::test\]` = 31 tests, all read; none exercise the listed rejection paths - the suite covers redaction, FIFO order, ring bounds, label policy, and success paths only -- d2b-telemetry#5 sev=low blast=leaf effort=S verdict=actionable - `target_buckets_are_present` pins three bucket constants by asserting one member value each, a tautology that fails on refactor and passes on behavior change - fix: delete the test, or replace it with a behavior test (e.g. a `MetricFamily::new` built with `CONTROLLER_HINT_BUCKETS_SECONDS` accepts an in-range histogram value and rejects an out-of-range one) - [packages/d2b-telemetry/src/meter_registry.rs:176-180] - evidence: seed `assert_eq!\(|assert_ne!\(|assert!\(` = 77 hits; the test's expected values are the constants themselves (`CONTROLLER_HINT_BUCKETS_SECONDS.contains(&0.005)`), not derived from an independent source - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 4/18/1/0) -- type: clean (seeds ran: 3/0/0) -- api: clean (seeds ran: 94/0/9) -- err: 2 finding(s) -- serde: clean (seeds ran: 3/2/2/5) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 1 finding(s) -- perf: clean (seeds ran: 5/4/0) -- conc: clean (seeds ran: 1/1/6/1) -- async: N/A (seeds: 0/0/0/0 all zero; synchronous library surface) -- unsafe: N/A (seeds: 0/0/0 all zero for the block/fn/impl seeds; seed 4 = 1 hit, the `#![forbid(unsafe_code)]` attribute at lib.rs:6, which does not make the lens applicable) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros defined) -- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md deleted file mode 100644 index 043d22706..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-unsafe-local-helper.md +++ /dev/null @@ -1,68 +0,0 @@ -# d2b-unsafe-local-helper - d2b-unsafe-local-helper -Baseline: 6ebdd4cec | LOC audited: 3240 (excl. src/generated/**) | modules: whole crate (environment.rs, lib.rs, main.rs, protocol.rs, runtime.rs, systemd.rs) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-unsafe-local-helper#6 sev=low blast=leaf effort=S verdict=actionable - terminate_scope and stop_scope normalize a NotFound into Ok via `(error == ScopeError::NotFound).then_some(()).ok_or(error)?`, a boolean-then-Option chain that hides the two-branch control flow at the exact spot a reader asks "what happens on NotFound" - fix: `if error != ScopeError::NotFound { return Err(error); }` in both terminate_scope and stop_scope, then `Ok(())` - [packages/d2b-unsafe-local-helper/src/systemd.rs:260, packages/d2b-unsafe-local-helper/src/systemd.rs:277] - evidence: idiom seed 2 `impl (Default|From|...) for` = 1 hit + manual read; the then_some/ok_or construct appears twice (systemd.rs:260, 277); ScopeError is Copy so it compiles, but the control flow is obscured -- d2b-unsafe-local-helper#8 sev=medium blast=family effort=L verdict=actionable - the seqpacket framing codec (u32 length prefix + JSON body + socket buffer tuning to the frozen MIN_EFFECTIVE floor) is maintained as two independent implementations, one on each side of the same wire: protocol.rs and d2bd-runtime/src/unsafe_local_helper.rs - fix: extract a shared frame codec module as the canonical home for send_frame/receive_frame/configure_socket_buffers and consume it from both processes; keep the daemon-side fd-capturing receive_frame as a thin extension over the shared framing - [packages/d2b-unsafe-local-helper/src/protocol.rs:310, packages/d2b-unsafe-local-helper/src/protocol.rs:337, packages/d2b-unsafe-local-helper/src/protocol.rs:357, packages/d2bd-runtime/src/unsafe_local_helper.rs:727, packages/d2bd-runtime/src/unsafe_local_helper.rs:752, packages/d2bd-runtime/src/unsafe_local_helper.rs:770] - evidence: grep `configure_socket_buffers|send_frame|receive_frame` over packages/ = the helper's own copies at protocol.rs and a second, near-identical set at d2bd-runtime/src/unsafe_local_helper.rs:727/752/770; the two sides already drift (daemon returns captured fds, helper rejects frames carrying fds), and the framing rules and buffer floor must not be re-derived per side -- clean: idiom seeds ran (for `0..` = 1, impl-for = 1, let-mut-Vec/String::new = 2); the only index loop is a test barrier spawn; the hand-written Default for RuntimeLedger preserves the schema_version invariant a derive would break and is justified -## own -- clean: own seeds ran (clone/to_owned/to_vec/to_string ~48 lines; Rc/RefCell/Arc/Arc/Cow = 0); every clone is explainable - Arc clones at thread spawn boundaries (protocol.rs:176-179, required for 'static), wire-identity clones into PersistedScope/SupervisorSpec owned fields, ledger.persisted.clone for commit-rollback and snapshot clones to release the lock before manager calls, and test fixtures; no unneeded copies found -## type -- d2b-unsafe-local-helper#2 sev=low blast=leaf effort=S verdict=actionable - RuntimeLedger.reservations is keyed by `operation_id.to_string()` (a String key) while OperationId already derives Ord + Clone + Hash, so every begin/owns/clear round-trips through a per-call allocation and as_str() re-parsing of an id the caller already owns typed - fix: `BTreeMap` and use the OperationId directly in begin (runtime.rs:193, 206, 230), owns (236) and clear (242); delete operation_key - [packages/d2b-unsafe-local-helper/src/runtime.rs:155, packages/d2b-unsafe-local-helper/src/runtime.rs:193, packages/d2b-unsafe-local-helper/src/runtime.rs:230, packages/d2b-unsafe-local-helper/src/runtime.rs:236, packages/d2b-unsafe-local-helper/src/runtime.rs:242] - evidence: census: OperationId derives PartialOrd, Ord, Clone, Hash at packages/d2b-contracts/src/ids.rs:131-133; runtime.rs uses to_string + as_str at five sites; string keys map one-to-one to OperationId, so this is type-consistency (stringly-keyed state), not a correctness fix -- clean: type seeds ran (validate_/check_ = 3, is_/flag bool = 0, mode/kind/state String = 1); the three validate_* fns are one-shot boundary checks of external inputs (fs paths, wire events) with no same-input re-validation elsewhere, so parse-once types would not remove a bug class; the single String hit is a local `let active_state: String`, not stringly-typed state -## api -- d2b-unsafe-local-helper#1 sev=low blast=leaf effort=S verdict=actionable - the exported surface includes SupervisorSpec, send_frame/receive_frame/configure_socket_buffers, and SUPERVISOR_START_TIMEOUT/SNAPSHOT_RECONCILE_TIMEOUT, none consumed by the crate's only external user (the same crate's binary main.rs, which imports only HelperClient, ScopeRuntime, run_scope_supervisor, SystemdUserScopeManager, default_helper_socket_path) - fix: narrow to pub(crate)/private where possible; keep pub only the items main.rs or a pub signature needs - [packages/d2b-unsafe-local-helper/src/runtime.rs:573, packages/d2b-unsafe-local-helper/src/protocol.rs:310, packages/d2b-unsafe-local-helper/src/protocol.rs:337, packages/d2b-unsafe-local-helper/src/protocol.rs:357, packages/d2b-unsafe-local-helper/src/runtime.rs:35, packages/d2b-unsafe-local-helper/src/runtime.rs:36] - evidence: census: `SupervisorSpec|SUPERVISOR_START_TIMEOUT|SNAPSHOT_RECONCILE_TIMEOUT` over packages/ + nixos-modules/ + tests/ + docs/reference/ + labs/ = 0 external hits (only in-crate uses); the send_frame/receive_frame/configure_socket_buffers hits elsewhere (d2b/src, d2bd-runtime, d2b-resource-client) are unrelated same-named items, so the crate's own trio also has no external consumer -- clean: api seed 3 (`pub use`) = 0; seed 2 (Arc/Rc/Box/RefCell in signatures) matched only pub(crate) fields, no exported signature leaks a heap type -## err -- d2b-unsafe-local-helper#3 sev=medium blast=leaf effort=S verdict=actionable - await_scope_identity maps every `Ok(_)` whose state is not starting/active (scope exists but the launched process already exited, stopping, or degraded) to ScopeError::IdentityMismatch, so an operational "process died during startup" is reported and handled as a security identity failure; the caller then aborts the supervisor and surfaces ScopeIdentityMismatch to the daemon - fix: return a distinct error for an early-exit scope (e.g. ScopeError::CreateFailed or a new EarlyExit variant), keep IdentityMismatch for identity-check failures only, and map it to RuntimeError::ScopeCreateFailed - [packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/systemd.rs:338-346] - evidence: err seeds (unwrap/expect ~non-test, let-_ ~14, panic! 1 test-only, enum Error = 4); read of await_scope_identity shows query_scope (systemd.rs:160-167) maps active/activating/reloading and never produces HelperScopeState::Starting, so the guard's Starting arm is dead and `Ok(_)` is the exited-process path, which is a caller-action distinct from a mismatched identity -- clean: err seed 1 non-test unwrap/expect reduced to one invariant-holding `expect("supervisor child present")` at runtime.rs:713 (child is always Some at id()'s only call site, protocol.rs:408); all other unwrap/expect live in #[cfg(test)]; the `let _ =` sites are deliberate best-effort cleanup (close fd, kill/wait, remove_dir_all); the four error enums (EnvironmentError, ProtocolError, RuntimeError, ScopeError) are exhaustive across From and failure_code mappings, split by caller action -## serde -- clean: serde seeds ran (derive = 4 structs, serde attrs = several, hand-written Deserialize = 0, serde_json from/to = 22); PersistedScope, PersistedScopeLedger, SupervisorSpec, GraphicalSupervisorSpec all use rename_all=camelCase + deny_unknown_fields; fingerprint and graphical are Option with serde(default)/skip_serializing_if; no hand-written deserializer; the child-side re-validation after deserialize (GraphicalSupervisorSpec::validate) is a deliberate admission gate per the refusal ledger -## obs -- d2b-unsafe-local-helper#5 sev=low blast=leaf effort=S verdict=actionable - the operation-worker failure path logs `unsafe-local launch failed: {error:?}` (protocol.rs:188) with no request_id or operation_id, so a background launch failure cannot be correlated to the request that caused it and carries no stage context - fix: include request_id and operation_id (both in scope at protocol.rs:183-189) in the message or as fields - [packages/d2b-unsafe-local-helper/src/protocol.rs:188] - evidence: obs seed 1 (println|eprintln) = 10 hits; main.rs:30/47 are CLI-entry diagnostics and the seven launch_setup eprintlns (runtime.rs:356-399) carry distinct stage labels, but the worker-thread site is the only failure signal for a backgrounded operation and it drops the two identifiers that exist right there -- clean: obs seeds 2-4 (tracing macros, instrument, tracing::) = 0; the crate deliberately has no tracing dependency (synchronous subprocess, U18), so stderr is the log channel and the remaining sites are acceptable one-shot diagnostics -## docs -- d2b-unsafe-local-helper#7 sev=medium blast=leaf effort=M verdict=actionable - the entire pub surface is undocumented: the only /// comment in the crate is on the private validate_runtime_directory, so run/launch/snapshot, the UserScopeManager trait, HelperClient, send_frame/receive_frame, and the public getters carry no one-line contract, no # Errors, and receive_frame's `encoded.len() >= MAX_HELPER_FRAME_SIZE + 5` buffer invariant is discoverable only from the body - fix: add /// first-sentence plus # Errors sections to every pub fn returning Result, document the UserScopeManager trait contract and the frame-buffer invariant - [packages/d2b-unsafe-local-helper/src/lib.rs:1-4, packages/d2b-unsafe-local-helper/src/environment.rs:38, packages/d2b-unsafe-local-helper/src/protocol.rs:92, packages/d2b-unsafe-local-helper/src/protocol.rs:357, packages/d2b-unsafe-local-helper/src/runtime.rs:315, packages/d2b-unsafe-local-helper/src/systemd.rs:72] - evidence: docs seed 2 (`/// # (Examples|Errors|Panics|Safety)`) = 0 hits; `///` grep across src = 1 hit total (a private fn); seed 1 (pub items) and seed 3 (`-> Result<`) dominate the 103 seed matches yet none is documented -## perf -- clean: perf seeds ran (format! 11, *::new 9, to_string 10); all format! sites are cold (error paths, one-shot display generation, ledger/scratch filenames); Vec::new/BTreeMap::new sites are empty-common cases; receive_frame reuses one receive_buffer across the run loop (good pattern), hex and proxy_arguments size with with_capacity; a single win exists in the type lens (#2) which also removes a per-launch to_string allocation, but no allocation sits in a measured loop and no benchmark exists, so nothing else rises above static taste -## conc -- d2b-unsafe-local-helper#4 sev=low blast=leaf effort=S verdict=actionable - the `active` operation counter is a pure admission counter (it bounds MAX_HELPER_QUEUE_DEPTH worker threads and publishes no value; responses travel over the sync_channel, which carries its own synchronization) yet every fetch_add/fetch_sub uses AcqRel - fix: Ordering::Relaxed, the weakest correct ordering for a counter nobody synchronizes on - [packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src/protocol.rs:167, packages/d2b-unsafe-local-helper/src/protocol.rs:195] - evidence: conc seed 3 (Atomic|Ordering) = 4 hits; the counter is read only through fetch_add's returned value and decremented after the response send, with no paired publication, so AcqRel is stronger than the weakest correct ordering -- clean: conc seeds (thread spawn ~12, Mutex/RwLock 3, unsafe impl Send/Sync 0); the ledger and zbus connection Mutexes are std Mutex on genuine synchronous paths (repo-class allowed), the channels are bounded sync_channel (backpressure, no unbounded growth), the UserScopeManager trait states `Send + Sync + 'static` supertraits explicitly, and all worker/reader/reaper threads are named; one long-lived reaper thread per committed launch is inherent to the mini-init design and bounded by MAX_HELPER_SNAPSHOT_SCOPES -## async -- clean: N/A (async seeds all zero: no async fn/await/tokio/block_on anywhere; seed 2/3/4 = 0) -## unsafe -- clean: unsafe seeds ran (seed 3 `transmute|from_raw|MaybeUninit|mem::zeroed` = 2 hits); both hits are nix safe constructors (`nix::unistd::Pid::from_raw` at runtime.rs:954-955 feeding waitpid), not unsafe code; there are zero unsafe blocks, unsafe fns, unsafe impls, or SAFETY comments in the crate, and the manifest lints.rust sets `unsafe_code = "forbid"` (Cargo.toml) - the (d) 8 exception enumeration adds no site in this crate, so nothing to cite or re-flag -## ffi -- clean: N/A (ffi seeds all zero: no extern "C", no_mangle, catch_unwind, repr(C), CStr/CString/c_char anywhere; the crate never crosses a foreign caller) -## macro -- clean: N/A (macro seeds all zero: no macro_rules!, proc macro, syn/quote, $crate, or to_compile_error in the crate) -## test -- d2b-unsafe-local-helper#9 sev=low blast=leaf effort=S verdict=actionable - adoption_degrades_identity_ambiguity_without_stopping_scope re-derives snapshot's inline identity-mismatch match on a hand-built ScopeInspection (test lines 1567-1576 mirror production lines 505-508), so it still passes if snapshot later reports `state` instead of Degraded for a mismatched scope - fix: extract the `ScopeInspection::observable_state()` decision used by snapshot into a testable function and assert on that extracted behavior - [packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helper/src/runtime.rs:505-508] - evidence: test seed 1 (#[test]) = 25 tests, seed 2 (asserts) ~90; this test asserts a copy of the prod match, the skill's same-logic-computes-the-expectation test that cannot catch the plausible regression -- clean: the suite otherwise follows the form the assertion needs - typed error variants (assert_eq against Err(EnvironmentError::X) / Err(RuntimeError::Y)) not Display strings, table-driven cases with `"{invalid:?}"` failure messages, a Barrier/thread concurrency test for reservations, and real child-process keyword tests for supervisor teardown; determinism holds (no clock reads except injected deadlines, no network, scratch dirs are uid-random under /proc/self/cwd); no #[ignore], no proptest/insta/rstest - property/snapshot tooling would not add a covered behavior - -## Coverage -- idiom: 2 finding(s) | clean for the remaining seed mass -- own: clean (seeds: ~48 clone/to_owned/to_string lines; Rc/RefCell/Cow/Arc = 0) -- type: 1 finding(s) | clean for validate_* boundary checks -- api: 1 finding(s) | pub surface wider than the binary consumer needs -- err: 1 finding(s) | panic policy otherwise invariant-only -- serde: clean (seeds: derive 4, serde attrs several, hand Deserialize 0, json from/to 22) -- obs: 1 finding(s) | stderr-only observability as designed -- docs: 1 finding(s) | 0 canonical sections across ~39 pub items -- perf: clean (seeds: format! 11, *::new 9, to_string 10; all cold) -- conc: 1 finding(s) | model otherwise thread-boundary correct -- async: N/A (seeds: async fn/await 0, tokio 0, sync mutex 0; deliberate synchronous subprocess per Cargo.toml U18) -- unsafe: clean (seeds: from_raw 2, both nix safe wrappers; manifest forbids unsafe_code) -- ffi: N/A (seeds: 0/0/0/0; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0; no macros defined) -- test: 1 finding(s) | otherwise behavior-first typed-error tests diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md deleted file mode 100644 index 7a77732ba..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2b-zone-routing.md +++ /dev/null @@ -1,78 +0,0 @@ -# d2b-zone-routing - d2b-zone-routing -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10120 (excl. src/generated/**; src 8214 + tests 1906) | modules: engine, enrollment, resolver, router, service, serving -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crate - -## idiom -- d2b-zone-routing#1 sev=low blast=leaf effort=S verdict=actionable - `SealedZoneTopology::longest_suffix_match` walks `for start in 0..labels.len()` with an inline `continue`, where the same logic is a `find_map` over the index range - fix: replace the loop with `(0..labels.len()).find_map(|start| { let Ok(suffix) = ZonePath::new(labels[start..].to_vec()) else { return None; }; self.zones.get(&suffix) })` - [packages/d2b-zone-routing/src/resolver.rs:144] - evidence: seed `for \w+ in 0\.\.` = 2 hits; only this site is in production code (service.rs:1793 is a fixed-count test loop). -- d2b-zone-routing#2 sev=low blast=leaf effort=S verdict=actionable - `ZoneTopologyRequest` carries a hand-written `impl Default` that a field-wise derive reproduces exactly - fix: delete the manual impl and add `#[derive(Default)]` to the struct - [packages/d2b-zone-routing/src/service.rs:311] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 hits; only this site's derive would be field-wise identical (the other four Default impls preserve non-zero frozen bounds and must stay manual). - -## own -- d2b-zone-routing#3 sev=low blast=leaf effort=M verdict=actionable - In `ZoneRouteAdmission::consume`, the snapshot's zone pair is copied from `expected` with two `ZonePath` clones per consumed route admission, though `expected` is already owned by the match arm and only compared afterwards - fix: compare every non-zone field first, then move `expected.source_zone`/`expected.target_zone` intosnapshot (or split `validate_snapshot` into a zone-pair phase taking `expected` by value), removing the two clones - [packages/d2b-zone-routing/src/engine.rs:345, packages/d2b-zone-routing/src/engine.rs:346] - evidence: seed `\.clone\(\)` = 141 hits; this site is the only production clone of a value already owned by the enclosing scope (all other clones buy a second owner or test fixture state). - -## type -- clean: seeds ran: `fn validate_\w+|fn check_\w+` = 3 (`validate_snapshot`, `validate_session_binding`, `check_current`), `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; all three hits are runtime comparisons against sealed admission evidence (target substitution, session binding, daemon time), not parse-once type candidates, and there is no flag soup or stringly-typed state. - - - -## api -- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod)` = 207, `pub .*\b(Arc|Rc|Box|RefCell)<` = 1, `^\s*pub use` = 0; every public item has exactly one path and a doc comment; the single `Arc` signature hit is the deliberate clock/placements seam (`pub type ZoneEnrollmentPlacements` and `ZoneEnrollmentAuthority::new`), no `Box`/`Rc`/`RefCell` appears in any signature, and `test-support`-gated `for_test` constructors are consumed cross-crate by the vector suites as intended. - - - -## err -- clean: seeds ran: `\.unwrap\(\)|\.expect\(` = 207, `let _ = |\.ok\(\);` = 1, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 15, `enum \w*Error` = 2; every unwrap/expect/panic hit sits in `#[cfg(test)]` or `#[cfg(any(test, feature = "test-support")))]` code or test helpers, the one `let _` is a stray test line (flagged under `test`),and the two error enums (`RouterError`, `ZoneEnrollmentServeError`) are closed with stable kebab labels and `std::error::Error` impls - -## serde -- N/A (seeds: 0/0/0/0 all zero; no serde derives, serde attributes, hand-written `Deserialize` impls, or `serde_json` anywhere - this crate crosses no wire boundary; wire call types live in `d2b-contracts-zone-session`) - -## obs -- N/A (seeds: 0/0/0/0 all zero; the crate has no `tracing`/`log` dependency in Cargo.toml - there is no telemetry surface to judge; zero `println!` in src) - -## docs -- d2b-zone-routing#4 sev=low blast=leaf effort=M verdict=actionable - The crate's 47 `-> Result<` public signatures document failure modes in prose paragraphs (e.g., `SealedZoneTopology::seal`, `ZoneServiceLimits::new`, `ZoneEnrollmentAuthority::with_lifetime`) but zero canonical `# Errors`/`# Panics` sections exist anywhere, so rustdoc index and IDEs lose a scannable contract - fix: add a `# Errors` section to the public validators/constructors that enforce conditions (seal, the `Limits`/`Expectation`/`Authority` constructors, `with_runtime_admission`), keeping the prose as depth beneath it - [packages/d2b-zone-routing/src/resolver.rs:80, packages/d2b-zone-routing/src/service.rs:208, packages/d2b-zone-routing/src/enrollment.rs:424] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 201, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 47 - -## perf -- clean: seeds ran: `format!\(` = 15, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 21, `\.to_string\(\)` = 0; all 15 `format!` hits are `cfg(test)` debug-render assertions and synthetic fingerprint builders (engine.rs:1959, resolver.rs:526, service.rs:1242), and the 21 collection initializers are bounded staging tables with ceilings (`MAX_ZONE_PARENT_ENTRIES`, `MAX_ZONE_ROUTE_ENTRIES`, `MAX_IDEMPOTENCY_ROWS`) - no measured hot path exists to name - -## conc -- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 4, `Atomic\w+|Ordering::` = 34, `thread_local!|unsafe impl (Send|Sync) for` = 0; the four `Mutex` sites are the single-use admission states and the router/exec tables, each `std::sync::Mutex` locked with per-site `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` (no suspension point), atomics are `AtomicBool` revoke flags loaded Acquire/stored Release plus test clocks; no manual `Send`/`Sync` claims or `thread_local!` in production - -## async -- d2b-zone-routing#5 sev=medium blast=leaf effort=M verdict=actionable - `ZoneEnrollmentServer::serve` commits the link FSM synchronously (PSK burn, enrollment record seal) inside `serve_bootstrap`/`serve_enroll` and then `.await`s the reply write `transport.send)...)`, so a `serve` future dropped between the mutation and the send leaves the link mid-transition and the peer never sees the reply - fix: make the FSM commit + encoded-reply write one non-cancellable unit (and document that dropping the task mid-send closes the connection as the peer's only signal), or make the operation resumable by deferring the transition until the reply write succeeds where the FSM allows - [packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207] - evidence: seed `async fn|async move|\.await` = 6 hits (all in serving.rs:180-319); no tokio spawn/spawn_blocking/select!/join! or tokio sync types in src - -## unsafe -- N/A (seeds: 0/0/0/0 all zero; no `unsafe` blocks/fns/impls, no `// SAFETY:` comments, and the manifest carries no `unsafe_code` setting - U1 ledger (d) 8 records it ABSENT here, so there is no unsafe surface to judge) - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)`, or `CStr`/`CString` anywhere - no foreign-calling boundary exists) - -## macro -- clean: seeds ran: `macro_rules!` = 1, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; the single `macro_rules!` (`redacted_debug!`, service.rs:116) is impl-per-type `Debug` generation - a genuine macro answer - with the narrow `ident` fragment, a fully-qualified `::core::fmt` expansion, and no crate-path or error machinery to judge - -## test -- d2b-zone-routing#6 sev=low blast=leaf effort=S verdict=actionable - `every_reason_the_engine_can_produce_is_covered_by_this_suite` checks only that the 16 named closed reasons have distinct `label()`s, not that the suite produces any of them - the name promises a coverage property the row never asserts - fix: rename it to `every_engine_reason_has_a_distinct_wire_label` and, if coverage is actually wanted, record the reasons each vector produced and assert the set at the end - [packages/d2b-zone-routing/src/engine.rs:3333] - evidence: test seed `#\[test\]|#\[tokio::test\]` = 143; this test's body only sorts and dedups `label()` values, with no produced-reason tracking -- d2b-zone-routing#7 sev=low blast=leaf effort=S verdict=actionable - `durable_exec_table_is_bounded_to_ephemeral_processes` ends with a dead `let _ = ZoneId::parse("dev").unwrap();` line that exercises nothing and exists only to use an import - fix: delete the line and the now-unused `ZoneId` import from the test module - [packages/d2b-zone-routing/src/router.rs:517] - evidence: err seed `let _ =` = 1 hit; the single hit is this stray test line - -## Coverage -- idiom: 2 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 3/0/0; all hits are runtime comparisons against sealed evidence, not type-model candidates) -- api: clean (seeds ran: 207/1/0; single-signature `Arc` is a deliberate seam; no internals or second paths exposed) -- err: clean (seeds ran: 207/1/15/2; no production panic or swallowed Result; error enums closed with stable labels) -- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no wire boundary) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency - no telemetry surface) -- docs: 1 finding(s) -- perf: clean (seeds ran: 15/21/0; all format! hits are test paths; collection sites bounded, unmeasured) -- conc: clean (seeds ran: 0/4/34/0; Mutex sites are sanctioned synchronous surfaces; atomics are Acquire/Release pairs) -- async: 1 finding(s) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe surface - manifest setting absent per U1 d8) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign-calling boundary) -- macro: clean (seeds ran: 1/0/0/0; single macro is justified impl-per-type generation) -- test: 2 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md deleted file mode 100644 index e02be9d3a..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p1.md +++ /dev/null @@ -1,78 +0,0 @@ -# d2bd-p1 - d2bd - part 1/8 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 13238 (excl. src/generated/**) | modules: src/resource_runtime.rs (whole file) -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/8: src/resource_runtime.rs (whole file, 13,238 lines) - -## idiom -- d2bd-p1#3 sev=low blast=leaf effort=S verdict=actionable - `current_committed_resource` (9168) is a body-for-body duplicate of `committed_resource` (9153) plus an unused `_operation_id` parameter, and its only caller is `committed_wayland_session_for_vm` (4555) - fix: call `committed_resource` at 4555 and delete `current_committed_resource` - [packages/d2bd/src/resource_runtime.rs:9168, packages/d2bd/src/resource_runtime.rs:4555, packages/d2bd/src/resource_runtime.rs:9153] - evidence: seeds `for \w+ in 0\.\.` = 1, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2, `let mut \w+ = (String|Vec)::new\(\)` = 17; duplicate bodies read at 9153-9210 vs 9168-9210; census: `current_committed_resource` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 1 file -- d2bd-p1#4 sev=low blast=leaf effort=S verdict=actionable - pointless `let setup = setup;` rebind in `reconcile_controller_sessions_locked` shadows the just-bound value to drop a mutability that was never declared - fix: bind once without `mut` and delete the rebind line - [packages/d2bd/src/resource_runtime.rs:6896] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 17 hits; the rebind read at 6896 with the comment block 6893-6895 explaining the ordering that the rebind does not serve; remaining seed mass (1 index-loop hit at 6271, 2 hand-written Defaults at 839/867, 17 accumulators) is deliberate - the loop is a bounded retry, the Defaults preserve pinned wire defaults, and the accumulators have early exits or await-driven extends - -## own -- d2bd-p1#5 sev=low blast=leaf effort=S verdict=actionable - avoidable `row.resource_ref.clone()` in `committed_controller_provider_identities`: the field is only borrowed by `committed_provider_spec` and then moved into the result map - fix: pass `&row.resource_ref` to `committed_provider_spec` and `identities.insert(row.resource_ref, (uid, generation))` after the call - [packages/d2bd/src/resource_runtime.rs:359] - evidence: seed `\.clone\(\)` = 262 hits (sampled: 44 of 262 hits, every 6th); the sampled clone at 359 is the only one whose value survives only as a borrow target and can be moved instead -- d2bd-p1#6 sev=low blast=leaf effort=S verdict=actionable - nine call sites pass `.to_owned()` into parsers that take `impl Into` (d2b-contracts-resource identity.rs:79,155,279,393), where `&str: Into` makes the allocation unnecessary - fix: drop `.to_owned()` at 181, 4625, 9911, 9931, 10096, 10138, 10212, 11078, 11079, 11082 - [packages/d2bd/src/resource_runtime.rs:181, packages/d2bd/src/resource_runtime.rs:4625, packages/d2bd/src/resource_runtime.rs:9931, packages/d2bd/src/resource_runtime.rs:10096, packages/d2bd/src/resource_runtime.rs:11078] - evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 102 hits; parser signatures read at packages/d2b-contracts-resource/src/v3/identity.rs:79 (`pub fn parse(value: impl Into)`); all nine sites pass a `&str` that `Into` accepts directly; the remaining sampled clone mass (44 of 262 hits, every 6th) is explainable - lock-guard escapes (1192), constructor inputs (2059, 6975), Arc clones at spawn/shared-state boundaries (5984, 11236), map-key/return copies (2220, 7231) - -## type -- d2bd-p1#7 sev=low blast=leaf effort=S verdict=actionable - `ZoneResourceRuntime` carries three gate booleans `policy_installed`/`controller_endpoint_registered`/`watch_admitted` (3041-3043) with only two reachable states - (true, false, false) at open (3230-3232) and (true, true, true) after `activate_published_bundle` (3470-3472) - so six impossible combinations are representable - fix: replace the trio with one enum (e.g. `PlanePublicationStage { BootstrapOnly, Published }`) read by `readiness_error` (8104-8116) - [packages/d2bd/src/resource_runtime.rs:3041, packages/d2bd/src/resource_runtime.rs:3230, packages/d2bd/src/resource_runtime.rs:3470, packages/d2bd/src/resource_runtime.rs:8104] - evidence: seeds `fn validate_\w+|fn check_\w+` = 3, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the flag trio and its two write sites read at 3041-3043, 3230-3232, 3470-3472 -- d2bd-p1#8 sev=low blast=leaf effort=S verdict=actionable - `ControllerSession` encodes ordered once-only teardown progress as three independent booleans `ingress_revoked`/`assignments_revoked`/`transport_closed` (1014-1016), so skipping or reordering a step (e.g. closing the transport before revoking assignments) is representable and silently leaks a lease or a revocation frame - fix: replace the three with a `TeardownStage` enum advanced monotonically in `remove_controller_session` (7614-7650) - [packages/d2bd/src/resource_runtime.rs:1014, packages/d2bd/src/resource_runtime.rs:7614] - evidence: seeds `fn validate_\w+|fn check_\w+` = 3, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; flag fields read at 1013-1016 and their only writer `remove_controller_session` at 7614-7650; the three validate fns are wire-boundary checks on manager-served rows (the parse-once point), and the runtime's `Option` pairs are deliberately handled by `derive_interaction_state` (9271-9281) - -## api -- clean: seeds `\bpub (fn|struct|enum|trait|type|const|mod) ` = 30, `pub .*\b(Arc|Rc|Box|RefCell)<` = 2, `^\s*pub use ` = 2; the two `Arc>`/`Arc<...>` returns (11161, 11200) are justified shared ownership - census: `network_admission_index` callers at shared_provider_effects.rs:1132, shared_provider_effects.rs:2436, composition.rs:15350, and `ResourcePlane::zone` hands out the plane's own Arc - and the `pub use` arms (115, 126) are the house re-export pattern; all `pub` items are deliberate (ZoneResourceRuntime, ResourcePlane, HostNetworkAdmissionIndex) with private fields. - -## err -- d2bd-p1#1 sev=medium blast=family effort=M verdict=actionable - `credential_dependency_row` swallows a manager RPC failure into absence (`.ok().flatten()`), contradicting the module's own contract that "a manager RPC failure is an error - never reported as absence" (bridge_manager_row doc, 299-305); the caller `ProductionCredentialRuntime` facts closure (4511) then reports no dependency facts, so a transient manager failure silently degrades credential readiness and revocation decisions - fix: propagate the error (log it with the error field at minimum; change `credential_dependency_facts`/`CredentialRuntime::dependency_facts` to `Result>` so the driver can retry) - [packages/d2bd/src/resource_runtime.rs:381, packages/d2bd/src/resource_runtime.rs:4511] - evidence: seed `let _ = |\.ok\(\);` = 35 hits; the `.ok().flatten()` read at 381-383 versus the never-absence contract documented at 299-305; the remaining seed mass is clean - unwrap/expect = 223 (sampled: 45 of 223 hits, every 5th) with every non-test hit an invariant expect naming its reason (6003, 6992, 4993/5399/5741), the two `unreachable!` sites (3402, 6288) statically guaranteed, and the `let _ =` sites deliberate best-effort cleanup or fenced operations whose error propagates via `?` - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 7, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 27, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 44; all seven wire types (802-916) use `rename_all = "camelCase"` + `deny_unknown_fields` with pinned `default = "..."` functions, the hand-written `Default` impls preserve those pinned defaults, and every parsed config is validated before use (`parse_committed_clipboard_configuration` 9718, `parse_committed_notification_configuration` 9780) - the serde boundary is the admission gate it should be. - -## obs -- d2bd-p1#9 sev=low blast=leaf effort=M verdict=actionable - eighteen message-only `tracing::warn!` events carry no named fields and the file has no spans at all (`\.instrument\(|#\[instrument` = 0), so the events lose the underlying error: most are inside `map_err` closures that drop the error (2024, 2419, 4846, 5283), and 7169 discards the in-scope `context` (provider/process) when a controller assignment refresh retries - fix: capture the error and log it as a named field (`error = ?...`) in the `map_err` closures, and add `provider`/`process` fields at 7169 - [packages/d2bd/src/resource_runtime.rs:2024, packages/d2bd/src/resource_runtime.rs:2419, packages/d2bd/src/resource_runtime.rs:4846, packages/d2bd/src/resource_runtime.rs:5283, packages/d2bd/src/resource_runtime.rs:7169] - evidence: seed `(info|debug|warn|error|trace)!\("` = 18 hits; seed `\.instrument\(|#\[instrument` = 0 (no enclosing span anywhere in the file); the field-less sites read at 2024-2071, 2419-2467, 4846-5364, 7169; the other seeds are clean - `\bprintln!\(|\beprintln!\(` = 0, `tracing::|log::` = 134 with the field-carrying events well-formed (7134, 7719), and no secret or identifier in any field - -## docs -- d2bd-p1#10 sev=low blast=leaf effort=S verdict=actionable - the public-request get deadline literal `meta.deadline_ms = 30_000` appears four times (8294, 8390, 10242, 10280) with no comment naming the why (which peer or operation enforces it) - fix: extract `const PUBLIC_GET_DEADLINE_MS: u64 = 30_000;` with a why-comment and use it at all four sites - [packages/d2bd/src/resource_runtime.rs:8294, packages/d2bd/src/resource_runtime.rs:8390, packages/d2bd/src/resource_runtime.rs:10242, packages/d2bd/src/resource_runtime.rs:10280] - evidence: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 30, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 182; the four deadline literals read at 8294, 8390, 10242, 10280 with no surrounding comment; the rest of the surface is clean - all 30 public items carry prose doc contracts with one-line first sentences (3006, 3777, 10709, 11125), the module has a `//!` doc (1-9), and failure conditions are documented in prose (4725-4734, 3777-3788) - the absent `# Errors` sections are a style choice in a bin crate where `missing_docs` is not appropriate - -## perf -- d2bd-p1#2 sev=medium blast=leaf effort=S verdict=actionable - three arms of `CloudHypervisorResourceSession::call` compute an operation id that is immediately discarded: `UpdateSpec` (2360-2364), `UpdateStatus` (2489-2505, `let _ = &operation_id`), and `DeleteChild` (2856-2859, `let _operation_id`) each build `operation_payload` and run a full SHA-256 `canonical_digest` plus a `format!` allocation that no caller reads - this runs on every provider status/spec update, i.e. every reconcile pass - fix: delete the dead digest/format computation and the `let _` bindings in all three arms - [packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, packages/d2bd/src/resource_runtime.rs:2505, packages/d2bd/src/resource_runtime.rs:2856] - evidence: static (unmeasured); seed `format!\(` = 21 hits; the dead bindings read at 2505 (`let _ = &operation_id;`) and 2856 (`let _operation_id = format!)...)`) with no later use of `operation_id` in the UpdateSpec arm (only `let _ = (&owner_ref, &payload, &operation_id)` at 2414); the remaining seed mass is clean - other `format!` sites are cold paths (960, error rendering), and the `Vec::new()` sites (72 hits) are page-capped list builders or empty-case-common accumulators - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 42, `Atomic\w+|Ordering::` = 26, `thread_local!|unsafe impl (Send|Sync) for` = 0; all 42 mutex hits are `tokio::sync::Mutex` fields whose guards are held across `.await` (the correct choice, e.g. 1052-1117, 3010-3067), the atomics are `AtomicBool` flags with paired Acquire/Release (`system_core_rebind_pending` 14/8637, `finalizer_clear_requested` 11522, reconcile shutdown 6121-6131), and there are no manual `Send`/`Sync` claims or `thread_local!`. - -## async -- clean: seeds `async fn|async move|\.await` = 537 (sampled: 49 of 537 hits, every 11th), `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 6, `tokio::sync::(Mutex|RwLock|Notify)` = 80, `#\[tokio::(main|test)\]|Runtime::block_on` = 1; no blocking work sits on an executor worker (the bundle reload is routed to the bounded loader worker at 5338-5341), the reconcile waker arms `Notify` before the check (6129-6160), guards are dropped before re-locking (`close_guest_session` 1942-1955) or are `tokio::sync` guards held deliberately under a documented lock order (3898-3900), cancellation paths abort and await their tasks (7644-7650), and the only `#[tokio::test]` (12714) is a current-thread harness. - -## unsafe -- unsafe: N/A (seeds: 0/0/0/0 all zero; no `unsafe` blocks/fns/impls, no `// SAFETY:` comments, no transmute/raw-pointer/MaybeUninit sites, and no `unsafe_code` attribute in the file) - -## ffi -- ffi: N/A (seeds: 0/0/0/0 all zero; no `extern "C"`/`no_mangle`, no `catch_unwind`, no `repr(C)`/`repr(transparent)`, no `CStr`/`CString`/`c_char` in the file) - -## macro -- macro: N/A (seeds: 0/0/0/0 all zero; no `macro_rules!`, no proc-macro/syn/quote, no `$crate`, no `to_compile_error`/`new_spanned` in the file) - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 38, `assert_eq!\(|assert_ne!\(|assert!\(` = 128, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the tests are behavior-focused with regression documentation (reconnect fence 11313, endpoint gate 11887, policy digest 11931, manager merge 12206, owner fence 12269), table-driven loops carry failure messages (11936-11968), error assertions match variants not Display strings (11587-11666), and no test restates implementation or computes its expectation with the code under test. - -## Coverage -- idiom: 2 finding(s) -- own: 2 finding(s) -- type: 2 finding(s) -- api: clean (seeds ran: 30/2/2) -- err: 1 finding(s) -- serde: clean (seeds ran: 7/27/0/44) -- obs: 1 finding(s) -- docs: 1 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: 0/42/26/0) -- async: clean (seeds ran: 537/6/80/1) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe sites in the file) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface in the file) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros in the file) -- test: clean (seeds ran: 38/128/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md deleted file mode 100644 index 512b971bc..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p2.md +++ /dev/null @@ -1,81 +0,0 @@ -# d2bd-p2 - d2bd - part 2/8 -Baseline: 6ebdd4cec | LOC audited: 10672 (excl. src/generated/**) | modules: composition.rs (10071-20142), audio_host_controller.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: composition.rs:10071-20142 + audio_host_controller.rs (U1 section f) - -## idiom -- d2bd-p2#1 sev=low blast=leaf effort=S verdict=actionable - open_resource_plane hardcodes the provider-identity seed window as `for attempt in 0..30` and `Duration::from_secs(2)` although the same-file consts PROVIDER_IDENTITY_SEED_ATTEMPTS (30) and PROVIDER_IDENTITY_SEED_INTERVAL (2s) at composition.rs:14193-14194 document exactly this "30 x 2s" window - fix: use `PROVIDER_IDENTITY_SEED_ATTEMPTS` and `PROVIDER_IDENTITY_SEED_INTERVAL` in the retry loop so the literals cannot drift from the documented window - [packages/d2bd/src/composition.rs:14699, packages/d2bd/src/composition.rs:14710, packages/d2bd/src/composition.rs:14193] - evidence: seed `for \w+ in 0\.\.` = 2 hits (14227 parameterized retry is fine; 14699 is the literal); consts at 14193-14194 define the same window -- clean: seeds ran 2/0/4; the other index loop (14227) is a parameterized retry, the `let mut Vec::new()` sites (14967, 19761) are plain loops with early exits and side effects where the idiom skill itself prefers the loop, and no hand-written derive-class impls exist in the range - -## own -- clean: seeds ran 189/286/0/0 (sampled: 50 of 475 hits, every 10th); every sampled clone is explainable - `caller_role.clone()` into spawned owner threads, `Arc` clones at spawn/effect boundaries, `.to_owned()` on wire error codes and JSON payload strings, test-fixture clones; no Rc/RefCell/Arc/Cow in the range - -## type -- d2bd-p2#2 sev=low blast=leaf effort=S verdict=actionable - ShutdownDegradedMarker stores `outcome: String` and `severity: String` although the same file defines VmShutdownOutcome (composition.rs:16131) whose label()/degraded_severity() (16205-16239) are the only producers of those strings - fix: derive Serialize on VmShutdownOutcome with `#[serde(rename_all = "snake_case")]` and store the enum in the marker so the report shape cannot drift from the enum - [packages/d2bd/src/composition.rs:16152, packages/d2bd/src/composition.rs:16155, packages/d2bd/src/composition.rs:16131] - evidence: type seeds 0/0/0 (model reading); the marker strings are produced from the enum at 16233-16239 and 16364 -- d2bd-p2#3 sev=medium blast=leaf effort=S verdict=actionable - `force` on guest lifecycle requests is parsed from the wire (composition.rs:6794-6797), stored in DaemonGuestLifecycleEffect.force (6837-6848), and never consulted - apply() only reads it via `let _ = self.force;` (18659) - so `d2b guest ... --force` (sent by d2b/src/guest.rs:283) is silently ignored - fix: implement the force semantics in apply() (e.g. skip the graceful wait) or drop the field and the wire parse - [packages/d2bd/src/composition.rs:18659, packages/d2bd/src/composition.rs:18608] - evidence: type seeds 0/0/0; census: `DaemonGuestLifecycleEffect|self.force` over packages/ = struct def 18603, construction 6837, single read 18659; CLI sends the flag (d2b/src/guest.rs:283) -- clean: seeds ran 0/0/0; the enums in the range (GuestComponentSessionCacheMode, VmRunnerLaunch, VmShutdownOutcome, HostActivationMarkerState) are well-formed, and no boolean-flag soup or stringly-typed state beyond the two findings exists - -## api -- d2bd-p2#4 sev=low blast=leaf effort=S verdict=actionable - the pub surface of audio_host_controller.rs (trait HostAudioController 59, PipeWireHostController 92, from_audio_node 106, find_audio_node 124, QemuAudioController 214) is unreachable outside the crate because `mod audio_host_controller;` (composition.rs:395) is private - fix: reduce these to `pub(crate)` (FakeHostController is already cfg(test)) so the visibility says what the surface is - [packages/d2bd/src/audio_host_controller.rs:59, packages/d2bd/src/audio_host_controller.rs:92, packages/d2bd/src/composition.rs:395] - evidence: api seeds 9/0/1; census: `HostAudioController|find_audio_node|enforce_grant|enforce_level` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 hits outside packages/d2bd -- d2bd-p2#5 sev=low blast=leaf effort=S verdict=actionable - `vm_name: &str` in HostAudioController::enforce_grant/enforce_level is dead trait surface: every implementation (PipeWire, Qemu, Fake) names it `_vm_name` and ignores it, and the only callers (audio_dispatch.rs:160,177) pass it pointlessly - fix: remove the parameter from both trait methods and the call sites - [packages/d2bd/src/audio_host_controller.rs:68, packages/d2bd/src/audio_host_controller.rs:78, packages/d2bd/src/audio_host_controller.rs:173] - evidence: api seeds 9/0/1; census: `enforce_grant|enforce_level` over packages/ = call sites audio_dispatch.rs:160,177 only; all three impls ignore the parameter (173, 183, 219, 230, 287, 297) -- clean: no Arc/Rc/Box/RefCell in any public signature, the re-export `pub use crate::audio_dispatch::HostEnforcementResult` follows the house single-surface pattern, and the trait is dyn-safe as its docs claim - -## err -- d2bd-p2#6 sev=low blast=family effort=M verdict=actionable - `detail: err.to_string()` collapses the source error into a String when building TypedError variants, losing the error chain for diagnostics - fix: carry the source in the variant (e.g. `InternalBrokerUnavailable { path, #[source] source: serde_json::Error }` with the detail rendered in Display) so the chain survives to the logging boundary - [packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d2bd/src/composition.rs:15243, packages/d2bd/src/composition.rs:15247, packages/d2bd/src/composition.rs:16777, packages/d2bd/src/composition.rs:16785, packages/d2bd/src/composition.rs:16790, packages/d2bd/src/composition.rs:17015, packages/d2bd/src/composition.rs:17023] - evidence: seed `let _ = |\.ok\(\);` = 53 hits; the 9 `detail: err.to_string()` sites are the chain-collapsing class, the rest are deliberate best-effort frame writes and shutdowns -- clean: seeds ran 41/53/1/0; all unwrap/expect hits are cfg(test) code, literal-built values (ShellName::new("primary"), own-constructed response objects), or startup invariants; the single unreachable!() (13622) is guarded by the Close/Cancel pre-check at 13510-13518 so it is not reachable from wire input; `let _ =` sites are deliberate best-effort writes/shutdowns - -## serde -- clean: seeds ran 4/4/0/34; the derives (ShutdownDegradedReport/Marker camelCase, HostActivationMarkerState kebab-case) are consistent, no hand-written Deserialize impls, and all serde_json boundary calls map errors to wire codes or fall back explicitly - -## obs -- d2bd-p2#7 sev=low blast=leaf effort=S verdict=actionable - `tracing::error!("Gateway Guest composition refused: root Zone generation unavailable")` is message-only although `topology.root` is in scope - fix: add `zone = %topology.root` (and the generation value if available) so the refusal is queryable per zone - [packages/d2bd/src/composition.rs:14781] - evidence: seed `(info|debug|warn|error|trace)!\("` = 3 hits; this site has no fields and no enclosing span with the zone -- d2bd-p2#8 sev=low blast=leaf effort=S verdict=actionable - two identical message-only `tracing::warn!("resource plane still has live request owners during shutdown")` events in the two LiveRequestOwners branches of shutdown_resource_plane carry no fields, so the operator cannot tell which zones are stuck - fix: add `zones = ?zones` (or a count) to both events - [packages/d2bd/src/composition.rs:15195, packages/d2bd/src/composition.rs:15221] - evidence: seed `(info|debug|warn|error|trace)!\("` = 3 hits; both warn sites are the duplicated message-only pair -- clean: seeds ran 0/3/0/158 (sampled: 40 of 158 tracing:: lines); the sampled events use named fields consistently (e.g. log_vm_start_report 17845-17874, log_host_prep_dag 17877-17893), no println/eprintln in the range, no secrets in fields, and the async-gate-allow marker at 10701 is a recorded deliberate exception - -## docs -- clean: seeds ran 9/0/96 (sampled: 32 of 96 `-> Result<` lines); all 9 pub items in audio_host_controller.rs carry contract docs with one-line first sentences, the pub(crate) composition items in the range are documented, and no canonical-section or doctest gaps were found - -## perf -- clean: seeds ran 90/18/18 (sampled: 30 of 90 format! lines); the format!/to_string sites are error paths, wire responses, and JSON payload building (cold by the card's own false-positive list), the Vec::new/BTreeMap::new sites are empty-case-common or plain-loop accumulations, and no hot-loop allocation was found - -## conc -- clean: seeds ran 5/1/2/0; the AtomicU64 request-id counter uses Relaxed correctly (13804-13806), the std::thread spawns (12856) are dedicated daemon owner threads with names, the sleeps (16861, 17582) are on sanctioned synchronous paths, and the only Mutex is a cfg(test) journal buffer - -## async -- clean: seeds ran 187/0/2/1 (sampled: 48 of 190 hits); the await chains are in async fns with proper error mapping, tokio::sync::Mutex guards (10884, 11064) are scoped and never held across await, the per-VM mutex map (10869, 10958) is lock striping, the single tokio::test is cfg(test), and the async-gate-allow marker at 10701 is a recorded deliberate exception - -## unsafe -- clean: seeds ran 0/0/2/0; the two seed-3 hits are safe `io::Error::from_raw_os_error` constructors, not unsafe code - no `unsafe` blocks, fns, impls, or SAFETY comments exist in the scope - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no extern "C", no_mangle, catch_unwind, repr(C), or CStr/CString in the scope) - -## macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, proc-macro, $crate, or to_compile_error in the scope) - -## test -- clean: seeds ran 86/301/0/0 (sampled: 50 of 387 hits, every 8th); the in-range unit tests (guest_session_target_admission_tests, guest_target_session_tests, guest_component_session_cache_tests, audio_host_controller tests) and the tests/ suite assert behavior with messages (e.g. "the assignment survives the target loss"), no #[ignore] tests, no property/snapshot tooling, and no assertion that restates its implementation was found in the sample - -## Coverage -- idiom: 1 finding(s) -- own: clean (seeds ran: 189/286/0/0; sampled 50 of 475) -- type: 2 finding(s) -- api: 2 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 4/4/0/34) -- obs: 2 finding(s) -- docs: clean (seeds ran: 9/0/96) -- perf: clean (seeds ran: 90/18/18) -- conc: clean (seeds ran: 5/1/2/0) -- async: clean (seeds ran: 187/0/2/1) -- unsafe: clean (seeds ran: 0/0/2/0; the two seed-3 hits are safe from_raw_os_error constructors, no unsafe code in scope) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 86/301/0/0; sampled 50 of 387) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md deleted file mode 100644 index 242e1e9bb..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p3.md +++ /dev/null @@ -1,80 +0,0 @@ -# d2bd-p3 - d2bd - part 3/8 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10801 (excl. src/generated/**) | modules: composition.rs (20143-30213), zone_enrollment.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/composition.rs:20143-30213, src/zone_enrollment.rs - -## idiom -- d2bd-p3#8 sev=low blast=leaf effort=S verdict=actionable - dispatch_live_guest_activation_resource builds the identical resource-List json and identical drive_sync dispatch twice (rollback branch and next-ordinal branch), differing only in post-processing - fix: hoist the `list` json and `runtime.dispatch_public_cli_request(&list)` call (with its map_err) above the `if mode == DaemonActivationMode::Rollback` split and branch only the filter/max computation - [packages/d2bd/src/composition.rs:20450-20461, packages/d2bd/src/composition.rs:20486-20498] - evidence: static comparison of the two blocks (same "zoneRef"/"service"/"method"/"resourceType"/"executionRef"/"limit": 256 payload, same drive_sync + map_err shape); seed `for \w+ in 0\.\.` = 10 (all test accept loops), `let mut \w+ = (String|Vec)::new\(\)` = 2 (test helpers), `impl (Default|From|...) for` = 0 -- d2bd-p3#9 sev=low blast=leaf effort=S verdict=actionable - qemu_media_registry_state takes `_registry_dir: &str` and never reads it (the probe reads global state), so every caller passes a value into a dead parameter - fix: drop the parameter and the `registry_dir` argument at the sole call site - [packages/d2bd/src/composition.rs:21306-21319, packages/d2bd/src/composition.rs:21291] - evidence: `_registry_dir` appears only in the signature (fn body 21313 calls the zero-arg `qemu_media_probe_registry_records()` at composition.rs:10000); census: `qemu_media_registry_state` over packages/ = 1 call site -- clean: seeds 1-3 ran (10/0/2); the 10 index loops are accept-loop test harvesters and the two Vec::new accumulators are test broker helpers; no hand-written Default/From/Debug/Clone impls, no statement-style production accumulation found - -## own -- d2bd-p3#4 sev=low blast=leaf effort=S verdict=actionable - `let zone = guard.zone().clone()` clones the ZoneId although `guard` can be borrowed for the whole body (it is only used again by its own Drop at scope end) - fix: bind `let zone = guard.zone();` and pass `&zone` to plane.zone and the json! formatters - [packages/d2bd/src/composition.rs:20404] - evidence: seed `\.clone\(\)` = 82 lane hits; non-test hits (35) read in full, this is the only borrow-replaceable clone in non-test code; sampled: 50 of 394 test-mass hits (every 8th), all fixture-owned or required -- d2bd-p3#5 sev=low blast=leaf effort=S verdict=actionable - typed_error_from_resolution_error clones `workload_id` while destructuring an owned error; the binding can be moved into TypedError::WorkloadAliasConflict because `candidates` is only joined by reference - fix: bind `workload_id` (no `.clone()`) in the AliasConflict arm - [packages/d2bd/src/composition.rs:21091] - evidence: seed `\.clone\(\)` = 82 lane hits; err is passed by value and neither field is used after construction of the TypedError -- d2bd-p3#6 sev=low blast=leaf effort=S verdict=actionable - `ResourceName::parse(readable.clone())` clones a just-built String although parse takes `impl Into` and `&readable` converts without allocation - fix: `ResourceName::parse(&readable)` - [packages/d2bd/src/composition.rs:20638] - evidence: `d2b_contracts_resource::v3::ResourceName::parse(value: impl Into)` (packages/d2b-contracts-resource/src/v3/resource.rs:44); seed `\.clone\(\)` = 82 lane hits - -## type -- d2bd-p3#2 sev=low blast=leaf effort=S verdict=needs-contract - HostActivationPendingMarker.mode is a stringly-typed activation mode on a persisted marker: it is deserialized, logged and rendered but never validated against the known label set, while the in-Rust mode already exists as DaemonActivationMode - fix: replace `mode: String` with a serde-mirrored enum (e.g. `DaemonActivationMode` behind kebab-case serde, or a marker-local enum) and validate on read; the marker file is written by out-of-tree activation machinery, so the serialized label set is a contract - [packages/d2bd/src/composition.rs:20146, packages/d2bd/src/composition.rs:20280, packages/d2bd/src/composition.rs:21135] - evidence: seed `(mode|kind|state): String` = 1 hit (composition.rs:20146); marker read boundary at 20260-20277; census: `HostActivationPendingMarker` over packages/ + nixos-modules/ = 3 files (composition.rs, d2bd-runtime/metrics.rs via metric label, docs/reference/daemon-api.md), no Rust writer in-tree - -## api -- N/A: seeds all zero in this partition (pub items 0, `pub .*\b(Arc|Rc|Box|RefCell)<` 0, `pub use ` 0); part 3 contains no exported surface - `pub(crate)` items in zone_enrollment.rs (ZONE_ENROLLMENT_PORT, GuestEnrollmentEndpoint)are crate-internal by design - -## err -- d2bd-p3#1 sev=medium blast=leaf effort=S verdict=actionable - dispatch_audit maps any unrecognized severity string from the wire to `TypedError::InternalIo { context: "audit filter", detail: "severity-invalid" }`, surfacing caller input errors as internal I/O failures instead of a request-validation refusal - fix: return a wire-input refusal kind (e.g. a TypedError::Wire* invalid-request variant or the invalid_request_response frame used by mutating dispatch) for the `Some(_) =>` arm - [packages/d2bd/src/composition.rs:22793-22797, packages/d2b-contracts-control/src/public_wire.rs:2453] - evidence: seed `\.unwrap\(\)|\.expect\(` = 537 lane hits (non-test sites read in full: 8, all documented invariants); the arm's kind is TypedError::InternalIo (packages/d2bd-runtime/src/typed_error.rs:490-493), an internal category for a user-typable field -- d2bd-p3#7 sev=medium blast=leaf effort=S verdict=actionable - ActivationLockGuard::drop silently swallows `finish_activation` failure (`let _ =`), so a coordinator refusal to close an activation is never even logged and the wedge is only discoverable via the deferred activation-pending marker - fix: log the error with tracing::warn! (boundary has no Result channel; the marker alone is not enough) - [packages/d2bd/src/composition.rs:20185-20190] - evidence: seed `let _ = |\.ok\(\);` = 63 lane hits; this is the only non-test `let _ =` on a fallible call (20188) outside cfg(test) cleanup sites - -## serde -- d2bd-p3#3 sev=low blast=leaf effort=S verdict=needs-contract - HostActivationPendingMarker.schema_version is deserialized but never validated, so a future marker version with a compatible field set would silently parse as current - fix: check `schema_version == 1` on read (refuse with a typed log/error otherwise) or drop the field from the read path if versioning is not enforced; the marker file is written by out-of-tree activation machinery, so its shape is a contract - [packages/d2bd/src/composition.rs:20144, packages/d2bd/src/composition.rs:20275, packages/d2bd/src/composition.rs:20298] - evidence: census: `schema_version` over packages/d2bd/src = 7 hits, 1 for this type (20144) and no read site anywhere (the other hits are unrelated types: 3669/8497/16146/28121); seed `serde_json::from_|serde_json::to_` = 56 lane hits - -## obs -- clean: seeds 1-4 ran (println 0, interpolated no-field events 0, instrument 0, tracing refs 18); every tracing event in the part uses named fields (vm = %marker.vm, endpoint = %path.display(), error = %error, activation_id, state = ?) and no event interpolates a message; no secret-bearing field spotted in the 18 sites (mode/activation_id are non-secret opaque identifiers); no subscriber installed (library/binary split respected) - -## docs -- d2bd-p3#10 sev=low blast=leaf effort=S verdict=actionable - the activation generations List limit `"limit": 256` is duplicated as an undocumented magic literal in both branches of dispatch_live_guest_activation_resource - fix: hoist to a named constant (e.g. `const ACTIVATION_GENERATIONS_LIST_LIMIT: u64`) with a comment naming why 256 (bounded retained NixosGeneration scan) - [packages/d2bd/src/composition.rs:20451, packages/d2bd/src/composition.rs:20495] - evidence: seed `^\s*pub (fn|struct|...)` = 0, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 18 (all private binary-crate fns); the two literals are textually identical with no comment - -## perf -- clean: seeds 1-3 ran (format! 55, collection news 54, to_string 28); every format!/to_string hit outside tests is cold (error detail strings, activation marker path names, one-shot generation names, per-poll response envelopes in a network-wait loop); the per-VM scoped workers in build_public_list/build_public_status are justified because provider probes can block up to PUBLIC_STATUS_PROVIDER_PROBE_TIMEOUT; no hot-path allocation pattern found; static (unmeasured) throughout - -## conc -- clean: seeds 1-4 ran (thread 21, Mutex/RwLock 9, Atomic 8, thread_local 0); non-test concurrency is the documented shape: scoped-thread data parallelism for list/status builds, `Arc>`/`Arc>` shared state with multiple owners, atomics only in tests (NEXT_TEST_ID); no manual Send/Sync impls, no static mut; the deliberate serialization of one zone's enrollments through one mutex is documented at zone_enrollment.rs:220-225 - -## async -- clean: seeds 1-4 ran (async fn/.await 78, spawn/JoinSet/select 2, tokio::sync refs 94, tokio main/test 10); no guard held across .await except the tokio::sync::Mutex held across serve() in spawn_accept_loop, which is the documented per-link serialization (zone_enrollment.rs:297-308); blocking work in async contexts is absent (the 250 ms sleep poll in dispatch_live_guest_activation_resource runs on the sync worker-thread dispatch path, marked `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` at 20385); 2 async-gate-allow markers at 26155/26552 are sanctioned cfg(test) sites; startup marker scans use tokio::fs with let-else skipping (no panics, no blocking) - -## unsafe -- clean: seeds 1-4 ran (unsafe blocks/fns/impls 0, `// SAFETY:` 0, transmute/from_raw/MaybeUninit/zeroed 12, unsafe_code 0 in scope); all 12 from_raw hits are safe constructors (`io::Error::from_raw_os_error`, `nix::unistd::Pid::from_raw`) inside test helpers, not unsafe blocks; no unsafe code exists in this partition, so no SAFETY-comment obligations arise (workspace `unsafe_code = "forbid"` is inherited as recorded in U1 (d) 1) - -## ffi -- N/A: seeds all zero (extern "C"/no_mangle 0, catch_unwind 0, repr(C)/repr(transparent) 0, CStr/CString 0); the part crosses no foreign-language boundary - -## macro -- N/A: seeds all zero (macro_rules! 0, proc_macro/syn/quote 0, $crate 0, to_compile_error 0); no macros defined or consumed beyond std macros - -## test -- clean: seeds 1-4 ran in partition scope (test attrs 139, asserts 457, proptest/insta/rstest 0, #[ignore] 2); the two `#[ignore]` tests are documented flakes ("flaky on shared hosts; Unix socket reuse races", composition.rs:25679-25680) which U1 (c) test lists as acceptable; sampled 50 of 596 hits (attrs every 3rd, asserts every 10th) and read test neighborhoods 21355-21463, 24537-24567, 26078-26167, zone_enrollment.rs:595-683: tests assert typed error kinds (error.kind()/assert_eq!(error, "bundle-intent-missing:store-view")), real wire round-trips through FramedVsockTransport with human-written expected values, fail-closed behavior and ordering, with per-case messages; no self-fulfilling expectation or assert-less test spotted; tests/ directory corpus is shared across d2bd parts and outside this partition's module scope - -## Coverage -- idiom: 2 finding(s) -- own: 3 finding(s) -- type: 1 finding(s) -- api: N/A (seeds: 0/0/0 all zero; no pub items in this partition, pub(crate) only) -- err: 2 finding(s) -- serde: 1 finding(s) -- obs: clean (seeds ran: 0/0/0/18) -- docs: 1 finding(s) -- perf: clean (seeds ran: 55/54/28) -- conc: clean (seeds ran: 21/9/8/0) -- async: clean (seeds ran: 78/2/94/10) -- unsafe: clean (seeds ran: 0/0/12/0; all 12 from_raw hits are safe constructors) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions) -- test: clean (seeds ran: 139/457/0/2) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md deleted file mode 100644 index 647be4d75..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p4.md +++ /dev/null @@ -1,86 +0,0 @@ -# d2bd-p4 - d2bd - part 4/8 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10850 (excl. src/generated/**) | modules: composition.rs (lines 1-10070), plane_port.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: composition.rs:1-10070, plane_port.rs (whole file) - -## idiom -- clean: seeds ran: `for \w+ in 0\.\.` = 2, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 4; both index loops are test loops (8889, 8910) and all four `Vec::new()` accumulations are conditional-push loops in complex functions where an iterator pipeline would obscure early exits; no hand-written derive-replaceable impls and no `get_` field accessors. - -## own -- clean: seeds ran: `\.clone\(\)` = 196, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 313, `Rc<|RefCell<|Arc>` shared state in `ServerState` and `ZoneLinkGatewayComposition` is the U10-sanctioned concurrent-state pattern (composition.rs:19, composition.rs:522). - -## type -- clean: seeds ran: `fn validate_\w+|fn check_\w+` = 4, `is_\w+: bool|\w+_flag: bool` = 1, `(mode|kind|state): String` = 2; the four validate/check fns are one-shot boundary checks on wire/config input (correct per the skill), the bool is a parameter not a field flag, and the two `source_kind: String` fields are daemon-written registry records whose string values come from a closed enum match, not user state. - -## api -- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 16, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 11; the pub surface (composition.rs:397-403, 414, 419, 431, 4156, 4184) is consumed by main.rs and d2bd's own integration tests (tests/mode_separation.rs, tests/core_composition.rs, tests/resource_operator_activation.rs), the `pub use` arms (composition.rs:120-230) are the house single-surface pattern, and no public signature carries Arc/Rc/Box/RefCell. - -## err -- d2bd-p4#1 sev=medium blast=leaf effort=S verdict=actionable - `record_workload_availability_metrics` panics via `.expect("bounded workload availability tuple")` when the metric key set drifts from the label fns: `WORKLOAD_AVAILABILITY_STATES` (composition.rs:8097) + `WORKLOAD_PROVIDERS` (composition.rs:8090) live here, while `workload_availability_label`/`workload_provider_label` live in d2bd-runtime's workload_dispatch.rs, so adding a `WorkloadAvailability` variant compiles cleanly (the exhaustive match only forces the label fn update) but makes the daemon panic on the next workload List/Status - fix: seed the `counts` map from a single source of truth exported next to the label fns (e.g. `workload_availability_states()`/`workload_provider_labels()`), or replace the expect with a graceful `entry()`/skip so an unknown label degrades to a missing gauge instead of a panic - [packages/d2bd/src/composition.rs:8140, packages/d2bd-runtime/src/workload_dispatch.rs:104, packages/d2bd/src/composition.rs:8097] - evidence: `\.unwrap\(\)|\.expect\(` seed = 154 hits across the lane; only four production expect sites exist (7574, 8140, 9214, 9256) and the other three name compiler-invisible invariants that the guards literally enforce (mutating_verb_preflight at 10071; ShellName literal at 7574); this one's invariant is maintained across a crate boundary. - -## serde -- d2bd-p4#2 sev=medium blast=leaf effort=S verdict=actionable - `GatewayGuestConfigFile` and `GatewayGuestRelayConfigFile` deserialize user-written guest gateway config with `rename_all = "camelCase"` but no `deny_unknown_fields`, so a typo'd key is silently ignored and surfaces later as "Guest Relay namespace is unavailable" instead of a parse error - fix: add `#[serde(deny_unknown_fields)]` to both types (the `QemuMediaProbeRegistry*` records are daemon-written and may stay permissive); add a config-typo test to `load_gateway_guest_zone_link_options` - [packages/d2bd/src/composition.rs:4196, packages/d2bd/src/composition.rs:4205] - evidence: `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` seed = 4 hits (both pairs of types); no `deny_unknown_fields` anywhere in the lane; the repo's manifest-schema types use it as the admission-gate pattern. - - -## obs -- d2bd-p4#3 sev=medium blast=leaf effort=S verdict=actionable - the daemon's accept loop reports runtime errors with `eprintln!` (authorization refusal at 4099/4132, connection-handler failure at 4081/4132-ish, spawn failure at 4138) while the rest of the crate uses tracing and main.rs:146-152 installs a `tracing_subscriber`, so these error events bypass level filtering, structured fields, and the redaction gates; the daemon's stderr goes to the journal as unstructured prose - fix: replace the four `eprintln!` calls with `tracing::error!` events carrying named fields (`error = %error.message()`, `peer_uid`) - [packages/d2bd/src/composition.rs:4081, packages/d2bd/src/composition.rs:4099, packages/d2bd/src/composition.rs:4132, packages/d2bd/src/composition.rs:4138] - evidence: `\bprintln!\(|\beprintln!\(` seed = 4 hits, all in serve()'s sync connection paths;`tracing::|log::` seed = 92 hits in the same lane, so eprintln is the exception not the norm. -- d2bd-p4#4 sev=low blast=leaf effort=S verdict=actionable - three lifecycle `tracing::info!` events are message-only with no named fields ("Guest-local ZoneLink transport Provider composed", "Guest target-control service composed", "autostart: nothing to do (empty plan)") and no enclosing span exists (0 `#[instrument]` hits in the lane), so the events cannot be filtered by zone/vm - fix: add named fields (`zone`, `guest_ref`, or `vm`) to the three events, or wrap them in instrumented callers - [packages/d2bd/src/composition.rs:4487, packages/d2bd/src/composition.rs:4538, packages/d2bd/src/composition.rs:5300] - evidence: `(info|debug|warn|error|trace)!\("` seed = 3 hits (all three are the message-only events);`\.instrument\(|#\[instrument` = 0, so no span context carries those fields. - - -## docs -- d2bd-p4#5 sev=medium blast=leaf effort=S verdict=actionable - `pub async fn serve`, the daemon's primary entry point (composition.rs is `include!`d into lib.rs:183),has no doc comment at all, and `pub async fn lock_only` has none either; both return `Result` and carry no `# Errors` contract, so callers cannot learn from the docs what each loads/binds/runs and how it fails - fix: add a doc comment to `serve` (loads config, applies overrides, binds the operator socket, runs the accept loop; `# Errors` for config/IO/authz failures) and to `lock_only` - [packages/d2bd/src/composition.rs:3455, packages/d2bd/src/composition.rs:4828] - evidence: `^\s*pub (fn|struct|enum|trait|const|type)` seed = 10 pub items;`/// # (Examples|Errors|Panics|Safety)` = 0 hits in the lane;`-> Result<` = 128 hits; ly the two undocumented pub entry points return Result without an Errors section. -- d2bd-p4#6 sev=low blast=leaf effort=S verdict=actionable - `StaticProviderComposition::new` is a pub constructor returning `Result` with no doc comment and no `# Errors` section, so the mode_separation.rs callers must read the body to learn it fails on `AdmissionError` - fix: one-line doc plus a `# Errors` section naming `AdmissionError` - [packages/d2bd/src/composition.rs:438] - evidence: static (unmeasured); pub-item seed = 10 hits and `-> Result<` = 128 hits; `new` is the only pub constructor without docs among the crate's public surface in this lane. - - -## perf -- clean: seeds ran: `format!\(` = 83, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 19, `\.to_string\(\)` = 33; all format!/to_string sites are error-detail strings, operation-id/ref construction, one-shot probe/registry reads, or test fixtures - none sits in a loop over a hot request path; static (unmeasured), no benchmark exists in the crate. - - -## conc -- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` = 4, `\bMutex<|\bRwLock<` = 23, `Atomic\w+|Ordering::` = 4, `thread_local!|unsafe impl (Send|Sync) for` = 0; the named threads are deliberate per-connection/dedicated worker threads (composition.rs:3650, 4124, 5546),the AtomicU64 stream-id counter uses Relaxed correctly (3437-3440),the Arc stop flag is clear shared state (3805),and all 23 Mutex/RwLock sites are `tokio::sync::Mutex` in the U10-sanctioned production state tables (composition.rs:19) or test fakes. - - - -## async -- clean: seeds ran: `async fn|async move|\.await` = 155, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 3, `tokio::sync::(Mutex|RwLock|Notify)` = 50, `#\[tokio::(main|test)\]|Runtime::block_on` = 0 (the bare seed misses the attribute-carrying `#[tokio::test(flavor = "multi_thread")]` forms, which appear 10 times in plane_port.rs tests);`drive_sync` (composition.rs:210) has the sanctioned "synchronous path" inline allow and `block_in_place` is a documented no-op on dededicated threads (composition.rs:200-213),the select! cancellation in serve_guest (4559-4580) aborts serving then awaits it - the correct shutdown shape,and no guard is held across an .await beyond the async-gate scanner's covered set. - - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0 - all zero; the d2bd crate's unsafe sites (22 crate-wide per U1 (e))) live in other parts of composition.rs and sibling files, not in this part). - - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 - all zero; no FFI-boundary code exists in this part). - - -## macro -- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 - all zero; no macro definitions or proc-macro usage in this part). - - -## test -- clean: seeds ran: `#\[test\]|#\[tokio::test\]` = 21 (plus 10 `#[tokio::test(flavor = "multi_thread")]` in plane_port.rs that the bare seed does not match), `assert_eq!\(|assert_ne!\(|assert!\(` = 87, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the 21 tests assert behavior (topology resolution, gateway session establishment/refusal, cursor adoption, fencing, metric availability counts, workload dispatch denial, plane claim refusal/ordering/release) with hand-written expected values, deterministic (no network, no sleeps), and the async tests use multi_thread flavor per the async skill; no test restates implementation or cannot fail. - - -## Coverage -- idiom: clean (seeds ran: 2/0/4; both index loops are test loops and all four Vec::new accumulations are conditional-push loops with early exits; no derive-replaceable hand-written impls) - -- own: clean (seeds ran: 196/313/0/0; sampled: 46 of 509 hits; every sampled clone/to_owned is an Arc clone at a spawn/thread boundary, error-detail construction, request building, or test fixture; Rc/RefCell/Cow absent; Arc shared state is the U10-sanctioned pattern) -- type: clean (seeds ran: 4/1/2; all four validate/check fns are one-shot boundary checks, the bool is a parameter not a flag, the String fields are daemon-written registry records) -- api: clean (seeds ran: 16/0/11; pub surface consumed by main.rs and d2bd tests, pub use arms are the house single-surface pattern, no internals leak into signatures) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: 2 finding(s) -- docs: 2 finding(s) -- perf: clean (seeds ran: 83/19/33; no format!/allocation sits in a hot request loop; static (unmeasured)) -- conc: clean(seeds ran: 4/23/4/0; dedicated handler threads, Relaxed counter, clear stop flag, U10-sanctioned tokio mutexes) - -- async: clean (seeds ran: 155/3/50/0; drive_sync sanctioned inline allow, select! shutdown shape correct, no guards across .await beyond gate coverage; the 0 for seed 4 is a seed-regex artifact (attribute-carrying tokio::test forms missed)) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe constructs in this part - crate-level sites live elsewhere) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI-boundary code in this part) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros in this part) -- test: clean(seeds ran: 21/87/0/0; behavior-focused, deterministic, multi_thread-flavored async tests; no property/snapshot tooling needed for a daemon composition surface) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md deleted file mode 100644 index ed529208a..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p5.md +++ /dev/null @@ -1,72 +0,0 @@ -# d2bd-p5 - d2bd - part 5/8 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10,670 (excl. src/generated/**) | modules: interaction_composition, foundation_seed, principal_allocation, provider_shutdown, process_resource_runtime -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/interaction_composition.rs, src/foundation_seed.rs, src/principal_allocation.rs, src/provider_shutdown.rs, src/process_resource_runtime.rs - -## idiom -- clean: seeds run: `for \w+ in 0\.\.` = 7, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 7; the 7 index-loop hits are fixed-count poll/retry loops (`for _ in 0..N`) inside the tests module,and the 7 accumulator hits are mixed-effect builders (store rows, materialized specs, client lists( where the equivalent collect chain would be longer than the loop. - -## own -- d2bd-p5#1 sev=low blast=leaf effort=S verdict=actionable - the `run_effect` closure (bound `F: FnOnce`) clones `supervisor` and `process_ticket` a second time inside its body, though the captured values can move straight into the `async move` block (which only borrows them( - fix: remove `let supervisor = supervisor.clone();` and `let process_ticket = adoption_ticket.clone();`, letting the outer captures move into the `async move` - [packages/d2bd/src/interaction_composition.rs:4343, packages/d2bd/src/interaction_composition.rs:4344] - evidence: seed `\.clone\(\)` = 228 hits (sampled: 47 of 228); the sampled pair at 4343-4344 sits inside a `FnOnce` closure (signature at 6150), so the duplicates cannot be required; every other sampled clone is explainable (tokio::spawn capture boundaries, owned-struct assembly, error-path copies) - -## type -- clean: seeds run: `fn validate_\w+|fn check_\w+` = 4, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0; the four validator functions check cross-field compositions of daemon-owned or wire-derived compound state with no parse-once replacement candidate - - - -## api -- clean: seeds run: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 97, `pub .*\b(Arc|Rc|Box|RefCell)<` = 1, `^\s*pub use` = 1; the one `Arc` in a public signature (`stop_token` -> `Arc`, 5109( shares a genuinely multi-owner shutdown token, and the `pub use` re-export block (provider_shutdown.rs:8( is the house single-surface pattern; the rest of the exported surface exposes fields privately, and no dependency types leak - -## err -- d2bd-p5#2 sev=medium blast=leaf effort=S verdict=actionable - `reap_finished_handlers` joins finished listener handler tasks with `let _ = handlers.swap_remove(index)..await;`, silently discarding the `JoinError`, so a panicked handler (whose `handler_active.fetch_sub` decrement sits after the panic-capable body( neither logs and leaks its bounded 64-slot admission reservation( - fix: log the `JoinError` with `tracing::warn!` at the reap site,and wrap the spawn body so the `fetch_sub` decrement runs in a panic-safe guard, not after the admit body - [packages/d2bd/src/interaction_composition.rs:5365, packages/d2bd/src/interaction_composition.rs:5310] - evidence: seed `\.unwrap\(\)|\.expect\(` = 408 hits (sampled: 47 of 408);`let _ = |\.ok\(\);` = 9 (the other eight are deliberate best-effort cleanup with follow-up polls or shutdown joins);`\bpanic!\)...` = 4 (all in the tests module);`enum \w*Error` = 6 - -## serde -- clean: seeds run: `derive\([^)]*(De)?[Ss]erialize` = 5, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 10, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 71; the five `#[derive(Deserialize)]` request structs use `#[serde(default)]` Option fields for service-consumed messages (absent/null conflation acceptable there),and no hand-written deserializer exists. - -## obs -- clean: seeds run: `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 13 (one hit is the substring `log::` inside `ApiCatalog::`, not a log site); all real events use named fields (e.g. 929-931, 1067-1069, 5268-5325), no interpolated messages,and no secrets in fields. - -## docs -- clean: seeds run: `^\s*pub (fn|struct|enum|trait|const|type)` = 97, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 107; spot reads of the pub surface (RegisteredInteractionSession methods, CoreDisplayResourceEvidence::from_committed_policy, InteractionListenerSet methods, the Seed*PrincipalAllocation/HostAccounts APIs( all carry one-line first-sentence docs; no canonical-section-needing item surfaced in the sample - - - -## perf -- clean: seeds run: `format!\(` = 48, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 53, `\.to_string\(\)` = 15; all allocation sites are error paths, one-shot diagnostics, listener-path/key building,and daemon-owned string boundaries (cold per static read),no hot-loop `format!` or grow-by-push pattern found (static (unmeasured() - -## conc -- clean: seeds run: `std::thread::|thread::spawn|thread::scope` = 3 (one is the sanctioned `synchronous path` `#[allow]` std::thread::sleep at 6194, two are test-loop yields), `\bMutex<|\bRwLock<` = 1 (a test Backend fixture), `Atomic\w+|Ordering::` = 32 (stop flag stores Release/loads Acquire,reservation counter uses AcqRel; no weak ordering misuse found), `thread_local!|unsafe impl (Send|Sync) for` = 0 - -## async -- d2bd-p5#3 sev=medium blast=leaf effort=M verdict=actionable - `admit_interaction_socket`'s per-request dispatch holds the daemon-global `runtime` lock (the `AsyncMutex>`( across the whole `.await` of `dispatch_component_request_for_session`, serializing every Zone's sessions andthe VM-start display reconcile behind one contended lock; the code itself records this as a residual at 5518-5529 - fix: per the recorded note, hand out a per-Zone handle (`BTreeMap>>`) cloned under the outer lock,and move the sync-seat methods off their global lock, adding the named concurrency test - [packages/d2bd/src/interaction_composition.rs:5518-5530] - evidence: seed `async fn|async move|\.await` = 302 hits (sampled: 44 of 302);`tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 7, `tokio::sync::(Mutex|RwLock|Notify)` = 1 (the `AsyncMutex` alias at 93), `#\[tokio::(main|test)\]|Runtime::block_on` = 10; the guard-hold across `.await` is observed at 5530 onward, documented as deliberate-but-unfixed at 5518-5529 - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; all zero; the partition declares no unsafe blocks/fns/impls, so the lens criteria fail. - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; all zero; no FFI surface in this partition. - -## macro -- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; all zero; no macro definitions or expansions in these files. - -## test -- clean: seeds run: `#\[test\]|#\[tokio::test\]` = 95, `assert_eq!\(|assert_ne!\(|assert!\(` = 430 (sampled: 48 of 430), `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the sampled assertions (src test modules and tests/** integration files( assert behavior, error variants, statuses,and outcomes with human-written expected values and contextual failure messages; tests use tempdirs and fixed poll counts, no network dependency,and every sampled test can fail on a real behavior change - -## Coverage -- idiom: clean (seeds ran: 7/0/7) -- own: 1 finding(s) -- type: clean (seeds ran: 4/0/0) -- api: clean (seeds ran: 97/1/1) -- err: 1 finding(s) -- serde: clean (seeds ran: 5/10/0/71) -- obs: clean (seeds ran: 0/0/0/13) -- docs: clean (seeds ran: 97/0/107) -- perf: clean (seeds ran: 48/53/15) -- conc: clean (seeds ran: 3/1/32/0) -- async: 1 finding(s) -- unsafe: N/A (seeds: 0/0/0 all zero; no unsafe blocks) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test: clean (seeds ran: 95/430/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md deleted file mode 100644 index fc614dc83..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p6.md +++ /dev/null @@ -1,77 +0,0 @@ -# d2bd-p6 - d2bd - part 6/8 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10772 (excl. src/generated/**) | modules: resource_plane_v3, provider_lifecycle, credential_resource_runtime, resource_runtime/plane_controller_bridge -Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: src/resource_plane_v3.rs, src/provider_lifecycle.rs, src/resource_runtime/**, src/credential_resource_runtime.rs - -## idiom -- d2bd-p6#1 sev=low blast=leaf effort=S verdict=actionable - `registered_service_decl` (provider_lifecycle) and `registered_service_factories` (resource_plane_v3) are 15-arm `if ... else if` chains over `&'static str` equality where a `match` reads as a table, gets exhaustiveness-free fallthrough by construction, and does not re-test the winner's earlier arms - fix: convert both chains to `match service { PROCESS_EFFECTS_SERVICE.id => ..., ... , _ => None/continue }`, keeping the `as Arc` coercions on the factory arms - [packages/d2bd/src/provider_lifecycle.rs:78, packages/d2bd/src/resource_plane_v3.rs:2226] - evidence: idiom seeds `for \w+ in 0\.\.`/`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`/`let mut \w+ = (String|Vec)::new\(\)` = 6/1/8 hits (the three index-loop hits and all eight `Vec::new` accumulators are bounded wait loops and topped-up listings with early exits that an iterator pipeline would obscure; the only hand-impl hit is a test `Default`); the two if-else chains were read whole at the cited lines, not seed-caught -- clean: none of the flagged classes otherwise - the `for _ in 0..N` hits are bounded poll waits (tests), the `Vec::new` hits are partition/plan listings with early returns. - -## own -- clean: seeds `\.clone\(\)`/`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`/`Rc<|RefCell<|Arc>` (ProviderAgentAuditLog, provider_lifecycle.rs:439) is a genuinely shared sync-only sink fed through the envelope. - -## type -- clean: seeds `fn validate_\w+|fn check_\w+`/`is_\w+: bool|\w+_flag: bool`/`(mode|kind|state): String` = 2/0/0 hits - both validation fns are boundary gates (`validate_request_scope` on a test-only wire reader, `check_registry_catalog` as a startup invariant), no flag-soup fields or stringly-typed state in the four files. - -## api -- d2bd-p6#2 sev=low blast=leaf effort=S verdict=actionable - `ResourcePlaneV3::targets`/`hub`/`store`/`registry` return `&Arc`, exposing refcount plumbing in the accessor surface and forcing the two callers that need the shared handle to clone through the reference - fix: return `&TargetDirectory`/`&SpecStore`/`&PlaneResourceRegistry` from the borrow-only accessors and `Arc`/`Arc` by value from `hub()`/`targets()`, then update `Arc::clone(plane.hub())` at resource_runtime.rs:4423 and `Arc::clone(plane.targets())` at composition.rs:11250 to `plane.hub()`/`plane.targets()` - [packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2bd/src/resource_plane_v3.rs:3295, packages/d2bd/src/resource_plane_v3.rs:3301, packages/d2bd/src/resource_plane_v3.rs:3308] - evidence: api seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 8 hits; census: `\.hub\(\)` over packages/ (excl. generated) = 1 hit (resource_runtime.rs:4423), `\.targets\(\)` = 4 hits (composition.rs:11121,11143,11158,11250), `\.store\(\)` in-lane = 3 test hits - the two `Arc::clone)..)` call sites cited are the load-bearing ones -- clean: no internals leak beyond the `&Arc` accessors - `client()` returns `&ResourceManagerClient`, `pub use` seed = 0, module surface is `pub(crate)` per lib.rs:16-17, and the `Arc` fields of `ConstructionInputs` are genuine shared facet ownership with documented callers. - -## err -- d2bd-p6#3 sev=medium blast=leaf effort=M verdict=actionable - `PlaneError` carries five `String` variants (`FoundationSeed`, `ManagerSpawn`, `Authority`, `Target`, `Bundle`) that wrap the inner error with `error.to_string()`/`format!` at every production site, dropping the source chain the enum's `#[from]` variants already preserve for `SpecStore`/`ProviderRegistration`/`ManagerRpc` - callers of `ResourcePlaneV3::prepare` cannot distinguish a refused spec-store open from a create failure without string-matching - fix: give each String variant a typed payload or `#[source]` (e.g. `PlaneError::Authority(#[from] d2b_core::loader_worker::Error)` where `SpecStore::open` already yields `SpecStoreError` through `#[from]`, and keep the stage word in the `Display` message, not the variant), deleting the `to_string()` wraps at the cited sites - [packages/d2bd/src/resource_plane_v3.rs:2646, packages/d2bd/src/resource_plane_v3.rs:3016, packages/d2bd/src/resource_plane_v3.rs:3025, packages/d2bd/src/resource_plane_v3.rs:3346, packages/d2bd/src/resource_plane_v3.rs:3081] - evidence: err seed `enum \w*Error` = 2 hits (PlaneError, ProviderStartupError); err seed `\.unwrap\(\)|\.expect\(` = 390 hits, sampled: 49 of 390 (every 8th) - zero production hits below the test-mod boundaries; the String wraps were read at the cited lines (map_err to_string cluster: 2568, 3081, 3109, 3131, 3244-3275, 3346) -- d2bd-p6#4 sev=low blast=leaf effort=S verdict=actionable - `ConstructionInputs::production` swallows the `attach_process_providers` Result at the compose-once fallback, so a `StateUnavailable` collision (or a future attach failure) silently leaves whichever instance won in the shared slot, and the plane keeps composing with its own instance either way - fix: `state.provider_runtime.attach_process_providers(Arc::clone(&providers)).map_err(|error| PlaneError::Authority(error.to_string()))?` (or a dedicated variant), matching the site's other rejections - [packages/d2bd/src/resource_plane_v3.rs:1956] - evidence: err seed `let _ = |\.ok\(\);` = 3 hits (339 is the documented idempotent store attach; 5324 is test code); the swallowed call is the only production `let _ =` on a fallible Result - read against attach_process_providers' sole `StateUnavailable` error at provider_registry.rs:471-484 -- clean: panic policy is sound in production - `\bpanic!\(|...` = 26 hits, all inside the `#[cfg(test)]` modules (canonical-builder helpers and bounded wait loops); err4 both enums are typed with documented variants, and `ProviderStartupError::code()` keeps stable refusal names. - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize`/`serde\((rename_all|...)\)`/`impl .*Deserialize.*for`/`serde_json::from_|serde_json::to_` = 0/0/0/63 hits - the 63 decode/encode sites are canonical-JSON boundary reads and test fixtures: production sites decode store-derived or bundle-verified bytes with `.ok()?`/`map_err` guards (no untrusted-input deserialization in this scope), and no hand-written `Deserialize` impls live here; the ~40 `from_value(json!({...}))` hits are literal test payloads. - -## obs -- d2bd-p6#5 sev=low blast=leaf effort=S verdict=actionable - `publish_trusted_context`'s failure arm interpolates the error into the message (`"trusted-context publication refused: {error}"`) while the sibling `Ok(_)` arm and every other event in the file carry named fields, so the failure reason is not queryable as a column - fix: move the error into a field (`error = %error, "trusted-context publication refused"`), matching the adjacent arms and the plane's other warn sites - [packages/d2bd/src/provider_lifecycle.rs:1085] - evidence: obs seed `(info|debug|warn|error|trace)!\("[^"]*\{` = 0 hits (the macro call opens on the next line, so the seed misses it); obs seed `tracing::|log::` = 25 hits, all 25 read - this is the only message-interpolation site in the scope -- clean: zero `println!`/`eprintln!` hits; no `#[instrument]` spans but every event carries named fields (`zone`, `revision`, `operation`, `error = %error`), and errors are logged only at the boundary that resolves them. - -## docs -- d2bd-p6#6 sev=low blast=leaf effort=S verdict=actionable - four public items in the plane's most-documented file are undocumented while their siblings carry `///` contracts: `PlaneResourceRegistry::new()`, `ZoneAuthorityInputs::controller_generation`, and the three fields of `BundleIngestReport` - fix: add the one-line contract each (constructor convenience, the zone authority's controller generation source, and per-field "the rows this ingestion applied/removed/protected") - [packages/d2bd/src/resource_plane_v3.rs:292, packages/d2bd/src/resource_plane_v3.rs:1770, packages/d2bd/src/resource_plane_v3.rs:3432] - evidence: docs seed `^\s*pub (fn|struct|enum|trait|const|type)` = 22 hits, all read - 18 carry doc comments; the four gaps are the cited lines; `/// # (Examples|Errors|Panics|Safety)` = 0 and `-> Result<` = 0 (line-broken signatures), and canonical sections are not required for this `pub(crate)` module surface per the card's internal-crate carve-out -- clean: no other public item in the scope lacks a first-sentence contract; module docs exist in all four files. - -## perf -- clean: seeds `format!\(`/`Vec::new\(\)|...`/`\.to_string\(\)` = 40/89/21 hits, all read - the `format!` hits are error paths, refusal-reason rendering, and test literals; the `Vec::new`/`BTreeMap::new` hits are startup planning listings, bounded drain windows, and test fixtures; the `to_string` hits are `map_err` conversions (the err finding #3's subject) - nothing sits on a hot path, and every loop here is bounded (drain windows, budget polls); static (unmeasured). - -## conc -- clean: seeds `std::thread::|...`/`\bMutex<|\bRwLock<`/`Atomic\w+|Ordering::`/`thread_local!|unsafe impl (Send|Sync) for` = 0/17/45/0 hits - the 17 `Mutex` sites are `tokio::sync::Mutex` over shared maps and gates with brief guards (never held across a fallible await), the 45 atomic hits are `Relaxed` counters/flag in `AnchorSubscriptionState` (the weakest correct ordering for test-observable counters) plus test counters, and `SeqCst` appears only in test assertions; no `unsafe impl Send/Sync`, no threads spawned in this scope; the `drain_order` `try_lock` fail-closed view is documented at provider_lifecycle.rs:1042-1044. - -## async -- clean: seeds `async fn|async move|\.await`/`tokio::spawn|...`/`tokio::sync::(Mutex|RwLock|Notify)`/`#\[tokio::(main|test)\]|Runtime::block_on` = 564/4/22/3 hits; sampled: 47 of 564 (every 12th) plus full reads of the 4 spawn sites, 22 tokio-sync sites and 3 test attributes - no blocking work inside async context (SQLite open and store migration run on the sanctioned `d2b_core::loader_worker` bounded seat per the KTD2 comment at `prepare`), no std-sync guard spans an await (the single-flight `tokio::sync::Mutex` gate in `ComponentCredentialSession` is the correct shape), `tokio::spawn` is limited to the one long-lived subscription task, and waits are bounded (`timeout_at` windows, budget polls). - -## unsafe -- clean: seeds `\bunsafe \{|...`/`// SAFETY:`/`transmute|from_raw|MaybeUninit|mem::zeroed`/`unsafe_code` = 0/0/4/0 hits - all four `from_raw` hits are safe functions (`Mode::from_raw_mode`, `std::io::Error::from_raw_os_error`), so the scope contains no `unsafe` block, no `unsafe fn`, and no unsafe-code lint exception; the ledger's enumeration (U1 section d 8) needs no new entry from this lane. - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, `no_mangle`, `catch_unwind`, `repr(C)`/`repr(transparent)` or `CStr`/`CString`/`c_char` anywhere in the scope - the anchored-fd API is exercised through `rustix` safe facades only). - -## macro -- N/A (seeds: 0/0/0/0 all zero; no `macro_rules!` definitions, no proc-macro or `$crate` usage - the only macros are `include!`d generated registrations and std macros). - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]`/`assert_eq!\(|assert_ne!\(|assert!\(`/`proptest!|insta::assert|rstest`/`#\[ignore\]` = 13/202/0/0 hits; sampled: 41 of 202 (every 5th) plus all 13 test attributes - assertions target behavior with messages (refusal codes, applied/removed counts, revisions, projection state), use `matches!` on variants before any Display check, and wait on deterministic poll loops with bounded budgets; no ignored tests, no property/snapshot tooling, no network or wall-clock dependence beyond bounded sleeps. - -## Coverage -- idiom: 1 finding -- own: clean (seeds ran: 220/171/1/0) -- type: clean (seeds ran: 2/0/0) -- api: 1 finding -- err: 2 findings -- serde: clean (seeds ran: 0/0/0/63) -- obs: 1 finding -- docs: 1 finding -- perf: clean (seeds ran: 40/89/21) -- conc: clean (seeds ran: 0/17/45/0) -- async: clean (seeds ran: 564/4/22/3) -- unsafe: clean (seeds ran: 0/0/4/0; all four hits are safe `from_raw*` functions, no unsafe code in scope) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface in the assigned files) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions or proc-macro usage) -- test: clean (seeds ran: 13/202/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md deleted file mode 100644 index 782629897..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p7.md +++ /dev/null @@ -1,83 +0,0 @@ -# d2bd-p7 - d2bd - part 7/8 -Baseline: 6ebdd4cec | LOC audited: 10662 (excl. src/generated/**) | modules: process_provider_runtime, provider_effects, effect_service_actors, main, guest_target_session, lib -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/process_provider_runtime.rs, src/provider_effects.rs, src/effect_service_actors.rs, src/main.rs, src/guest_target_session.rs, src/lib.rs - -## idiom -- d2bd-p7#1 sev=low blast=leaf effort=S verdict=actionable - hand-written `impl Default` on both unit-struct actors (`EffectServiceActor`, `EffectServiceSupervisor`) delegates to `Self::new()` with zero call sites anywhere; a derive emits the same impl and cannot drift - fix: replace both with `#[derive(Default)]` (or delete both; no workspace caller) - [packages/d2bd/src/effect_service_actors.rs:268, packages/d2bd/src/effect_service_actors.rs:411] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 2 hits (both Defaults); census: `EffectServiceActor::default|EffectServiceSupervisor::default` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 0 hits -- clean: seeds `for \w+ in 0\.\.` = 1 (test poll loop, esa:768), hand-written impls = 2, `let mut \w+ = (String|Vec)::new\(\)` = 1 (ppr:333, ordered required/optional field list with helper closures; pipeline not applicable); hand-written Debug impls at ppr:244/485/852 are deliberate redactions (ManagedResource/ControllerBootstrapContext/ProductionProcessProviders hide identities) - checked. - -## own -- d2bd-p7#2 sev=low blast=leaf effort=S verdict=actionable - `match context.owner_uid.clone()` at ticket assembly clones the whole `Option` (a String-backed uid) on every launch, including the `None` arm and the guard-false `Some` arm where the value is never consumed - fix: match on `&context.owner_uid` and clone inside the arm (`Some(owner_uid) if ticket.owner_uid().is_none() => ticket.with_owner_uid(owner_uid.clone())`), so the `_ => ticket` path copies nothing - [packages/d2bd/src/process_provider_runtime.rs:4057] - evidence: sampled: 50 of 276 `.clone()` hits (seeds 2-4: 178/1/0); remaining clones are struct construction from borrowed contexts, Arc clones at spawn boundaries, error-payload clones, and two bounded rollback snapshots (provider_effects.rs:973,1016, map capped by MAX_TRACKED_LIFECYCLE_MUTATIONS = 256) -- clean: `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 178 hits, `Rc<|RefCell<|Arc` - shared factory across respawns, genuinely shared, kept) -- clean: `^\s*pub use ` = 0 hits; re-exports live in composition.rs (outside this partition); the effect-service surface (`EffectServiceRow`, `EffectServiceBinding`, `EffectServiceSupervisorMsg`) sits in a `pub(crate)` module; `ProviderLifecycleEffectPort` has a small required surface (1 required + 1 defaulted method) - checked. - -## err -- d2bd-p7#4 sev=medium blast=leaf effort=S verdict=actionable - a durable service row that fails to (re)spawn is silently dropped: `let _ = state.spawn_service_actor)...)` in both the supervisor's restart-recovery loop and `supervise_exit` leaves a declared effect service unhosted with no trace, contradicting the module's own respawn promise (a crashed or killed service actor is respawned from its durable row; never leaves a service unhosted) - fix: log `tracing::warn!` with service/zone/error on spawn failure at both sites, keeping the non-fatal recovery semantics - [packages/d2bd/src/effect_service_actors.rs:551, packages/d2bd/src/effect_service_actors.rs:610] - evidence: seed `let _ = |\.ok\(\);` = 57 hits; sites 551/610 judged per the per-site rule (the esa:564-570 oneshot `reply.send)...).ok()` sites are deliberate requester-gone ignores, kept); sibling pattern at ppr:804-809 shows the house rule is to warn on best-effort failures that matter -- d2bd-p7#5 sev=low blast=leaf effort=S verdict=actionable - the 0700 enforcement on a serving worker's socket parent is silently swallowed with `let _ =`; the sibling `create_dir_all` failure just above is a hard error, so a failed `set_permissions` leaves the launched socket dir at default umask perms with no diagnostic - fix: replace `let _ = tokio::fs::set_permissions)...)` with a `tracing::warn!` on Err, mirroring the pidfd snapshot warn at ppr:804-809 - [packages/d2bd/src/process_provider_runtime.rs:3436] - evidence: seed `let _ = |\.ok\(\);` = 57 hits; site 3436 judged; house best-effort-warn pattern at ppr:804-809 -- clean: seed `\.unwrap\(\)|\.expect\(` = 435 hits, of which 433 are inside cfg(test) or test-support constructors (exempt); the two production sites (ppr:4310, ppr:4326) are invariant expects the compiler cannot see (`[u8; 32]` hash prefix slicing and `ResourceUid::from_bytes`, which forces version/variant bits before parsing - parse cannot fail), acceptable per the panel policy; `panic!`/`unreachable!`/`todo!`/`unimplemented!` = 4, all in test modules; no error-taxonomy defect in the part's three error enums - checked. - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 2, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 14, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 49; the only serde types are `LifecycleMutationStatus` (lowercase) and `PersistedLifecycleMutation` (camelCase + `deny_unknown_fields` + `#[serde(default)]`/`alias` for rollback-compatible migration of legacy rows, provider_effects.rs:651-690) - the persisted schema choices are deliberate and documented; spec serialization is stable field-order `to_vec` for ticket digests - checked. - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 6 (all in main.rs: banner, error reporting, and the principal-allocation CLI diagnostic - product output per the carve-out), interpolated-message events `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::` = 10; all tracing events carry named fields (vm, role, zone, error, mismatches, resource, identity); the binary installs the subscriber exactly once (main.rs:146-152) with EnvFilter; no secret material reaches any field (`identity` fields are hex digests; `ResourceUid` prints redacted by its own Display) - checked. - -## docs -- d2bd-p7#6 sev=low blast=leaf effort=S verdict=actionable - the crate root carries no `//!` module doc: lib.rs opens with the lint attribute only, and the included composition.rs begins with a plain `//` comment, so the crate's large public surface (pub mods, dozens of pub use re-exports) renders without any module-level description - fix: add a `//!` crate doc in lib.rs naming the daemon composition facets and pointing at the daemon contract references - [packages/d2bd/src/lib.rs:1, packages/d2bd/src/composition.rs:1] - evidence: static (no `//!` line in lib.rs:1-19 or composition.rs:1-40) -- d2bd-p7#7 sev=low blast=leaf effort=M verdict=actionable - no canonical `# Errors`/`# Panics` section exists anywhere in the part (0 hits) while `-> Result<` appears 121 times, including on the pub surface (`FixedEffectAdapter::validate_instance`, `dispatch`, `ProviderLifecycleDispatch::new_persistent`, `admit`, `EffectServiceBinding::call`/`call_expected`, `DaemonGuestTargetSession::request`); prose paragraphs describe the happy path but failure conditions are not structurally stated - fix: add `# Errors` sections naming refusal conditions to the pub Result-returning items of the two pub mods, keeping the existing prose - [packages/d2bd/src/provider_effects.rs:91, packages/d2bd/src/provider_effects.rs:711, packages/d2bd/src/provider_effects.rs:804, packages/d2bd/src/effect_service_actors.rs:201, packages/d2bd/src/guest_target_session.rs:37] - evidence: seed `/// # (Examples|Errors|Panics|Safety)` = 0 hits; seed `-> Result<` = 121 hits -- clean: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 83 hits; every top-level pub item in the part carries a doc comment with a first-sentence contract (spot-checked the full public surface, including the flagged-method set at ppr:1024-1064); `FIXED_PROCESS_PROVIDER_NAMES`, `MAX_TRACKED_LIFECYCLE_MUTATIONS`, `EffectServiceRow`, and both actor types are documented with their why - checked. - -## perf -- d2bd-p7#8 sev=low blast=leaf effort=S verdict=actionable - `resource_identity_fields` builds a `Vec` with exactly 12 statically-known pushes on every launch/adoption pass but grows from an empty `Vec::new()` - fix: `let mut fields = Vec::with_capacity(12);` (6 required + 6 optional entries) - [packages/d2bd/src/process_provider_runtime.rs:333] - evidence: static (unmeasured); seed `Vec::new\(\)` = 56 hits, of which this is the one grow-by-push candidate with a fixed bound -- clean: seeds `format!\(` = 87, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 56, `\.to_string\(\)` = 16; remaining format! sites are error strings, ticket-digest contexts, and launch-argv assembly (cold paths); no format! inside a loop, no attacker-keyed hashing, no grow-in-loop collections besides the finding - checked. - -## conc -- d2bd-p7#9 sev=low blast=leaf effort=S verdict=actionable - two standalone monotonic counters use stronger orderings than the weakest correct one: the effect-service binding revision does `load(Ordering::SeqCst)` (esa:174) and `fetch_add(1, Ordering::SeqCst)` (esa:509), and `next_desired_generation` uses `fetch_update(Ordering::AcqRel, Ordering::Acquire, ...)` (provider_effects:1064); the revision is a version tag used only in equality staleness checks and the generation is a unique-value mint, so `Ordering::Relaxed` is correct for both - fix: switch the revision load/fetch_add and the generation fetch_update to `Ordering::Relaxed` - [packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs:509, packages/d2bd/src/provider_effects.rs:1064] - evidence: seed `Atomic\w+|Ordering::` = 120 matching lines in lane (9 production sites examined; remaining mass is test-mod recorders); no unsafe Send/Sync impls, no thread_local, no std threads in the part (seed 4 = 0, seed 1 = 0) -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 6 (all tokio::sync::Mutex state tables; `await_holding_lock`/`await_holding_refcell_ref` denied workspace-wide), `thread_local!|unsafe impl (Send|Sync)` = 0; the only shared state is the tokio Mutex tables and atomics above - checked. - -## async -- clean: seeds `async fn|async move|\.await` = 231, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 4 (actor spawns), `tokio::sync::(Mutex|RwLock|Notify)` = 5, `#\[tokio::(main|test)\]|Runtime::block_on` = 7; production state tables are `tokio::sync::Mutex` (ppr:18,937-940); the controller-bootstrap wait uses the sanctioned AsyncFd + `tokio::time::timeout` shape (ppr:95-100); the sync `LivenessProbe::probe` seat drives its future via `crate::drive_sync` (`block_in_place` + `handle.block_on`, inline `#[allow(clippy::disallowed_methods, reason = "synchronous path")]`, composition.rs:210-215) and is documented as the U13/R11 sync caller - no guard held across await, no blocking call on an executor worker, no cancellation-loss site found in the part; `EffectServiceBinding::send` awaits the reply oneshot without a deadline, but the production caller (forward_rendezvous) wraps dispatch in `tokio::time::timeout(handler_deadline, ...)` so a hung service surfaces as `forward-timeout`, and in-flight actor death closes the oneshot - checked. - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0, `unsafe_code` = 0; no unsafe blocks/fns/impls and no unsafe_code attribute in the six files; d2bd inherits workspace `unsafe_code = "forbid"`) - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0; the part declares no foreign boundary) - -## macro -- N/A (seeds: `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0; no macro definitions or proc-macro surface in the part) - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 66, `assert_eq!\(|assert_ne!\(|assert!\(` = 255, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0 (scope: in-file tests in the six assigned files; `tests/**` integration targets are shared crate-wide and outside this partition); the in-file suites assert behavior - dedup counting (provider_effects:1783-1791), TTL and persist-failure release, restart/migration determinism with hand-worked expectations, supervision respawn with revision bumps, GPU/TPM argv pinning - with no same-logic expected values or Display-string error asserts found in the sampled assertions, and the only poll helper is bounded (200 iterations, esa:768) - checked. - -## Coverage -- idiom: 1 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 6/0/0; admission/policy checks with caller-actionable failures, no parse-once candidate) -- api: 1 finding(s) -- err: 2 finding(s) -- serde: clean (seeds ran: 2/14/0/49; deliberate migration-aware persisted schema) -- obs: clean (seeds ran: 6/0/0/10; named-field events, CLI output carve-out) -- docs: 2 finding(s) -- perf: 1 finding(s) -- conc: 1 finding(s) -- async: clean (seeds ran: 231/4/5/7; sanctioned sync seats, tokio state tables, deadline at the rendezvous caller) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe constructs in the part) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test: clean (seeds ran: 66/255/0/0; behavior-focused in-file suites, no non-failable assertions found) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md deleted file mode 100644 index 9de720645..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-p8.md +++ /dev/null @@ -1,88 +0,0 @@ -# d2bd-p8 - d2bd - part 8/8 -Baseline: 6ebdd4cec | LOC audited: 10828 (excl. src/generated/**) | modules: forward_rendezvous, shared_provider_effects, provider_registry, audio_dispatch -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: file-split part (forward_rendezvous.rs, shared_provider_effects.rs, provider_registry.rs, audio_dispatch.rs) - -## idiom -- d2bd-p8#1 sev=low blast=leaf effort=S verdict=actionable - no-op `let _ =` suppression statements with dead bindings: `let _ = &mut chain;` after the chain re-root (no mutation follows), `let _ = kind;` masking the unused `kind` param of `network_content_fence`, and `let _ = error.code();` masking the unused `error` in the `Refused` arm - fix: delete the statements and bind the now-unused pattern args as `_` / drop the `kind` param - [packages/d2bd/src/forward_rendezvous.rs:672, packages/d2bd/src/shared_provider_effects.rs:1156, packages/d2bd/src/provider_registry.rs:531] - evidence: seed `let _ = |\.ok\(\);` = 9 hits (3 are these no-ops; the rest are deliberate ignores of `OnceLock::set` results and test channel sends); production parts of all four files read in full -- d2bd-p8#2 sev=medium blast=leaf effort=S verdict=actionable - `reconcile_security_key` (SecurityKeyComponent::Service) acquires the Zone runtime with `let runtime = self.runtime()?;` that no branch uses; `let _ = runtime;` masks it, and `runtime()` (a try_lock spin, see d2bd-p8#17) returns `Unavailable` when the plane is absent, so a Service reconcile that never reads the plane fails spuriously - fix: delete the `let runtime = ...` and `let _ = runtime;` lines - [packages/d2bd/src/shared_provider_effects.rs:1903, packages/d2bd/src/shared_provider_effects.rs:1997] - evidence: seed `let _ = |\.ok\(\);` = 9 hits (1997 is a no-op masking an unused value); read of the Service branch body confirms `runtime` is used in no path -- d2bd-p8#3 sev=low blast=leaf effort=S verdict=actionable - redundant let-else plus a provably-dead second match and `unreachable!` in `ProviderRuntime::dispatch_lifecycle`: the `else` of `let ProviderRuntimeState::Active(active) = ...` re-matches `&*state` and its `Active(_) => unreachable!)...)` arm can never fire - fix: collapse the else to `return Err(ProviderEffectError::RegistryUnavailable)` - [packages/d2bd/src/provider_registry.rs:527-536] - evidence: seed `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 24 hits (this is the only production `unreachable!`; the rest are test fixtures) -- d2bd-p8#4 sev=low blast=leaf effort=M verdict=actionable - statement-style `Vec::new()` + push loops that are iterator shapes: `deploy_target_local_controllers` filters on component type / instance scope / target kind then pushes, and `dispatch_audio_status` partitions `Result` into `entries` and `errors` - fix: `manifest.components().iter().filter)...).map)...).collect::, _>>()?` and `vm_names.iter().map)...).partition(Result::is_ok)` - [packages/d2bd/src/provider_registry.rs:359-390, packages/d2bd/src/audio_dispatch.rs:392-411] - evidence: seed `for \w+ in 0\.\.` = 3, seed `let mut \w+ = (String|Vec)::new\(\)` = 2 - -## own -- d2bd-p8#5 sev=low blast=leaf effort=S verdict=actionable - avoidable `let zone = request.zone.clone();` in `ForwardRendezvous::invoke`: `zone` is used only as the `BTreeMap::get` key inside the `self.zones.lock().await` block, whose scope does not outlive the `request` borrow, so `zones.get(&request.zone)` compiles without the clone - fix: drop the clone and borrow `&request.zone` - [packages/d2bd/src/forward_rendezvous.rs:456, packages/d2bd/src/forward_rendezvous.rs:458-466] - evidence: seed `\.clone\(\)` = 217 hits (sampled: 50 of 217; production parts read in full, this is the one avoidable production clone found); read confirms `zone` is unused after the lock block -- d2bd-p8#6 sev=low blast=leaf effort=S verdict=actionable - `validate_network_config_volume_spec` clones the whole JSON `spec` document (`let mut base = spec.clone();`) just to strip three fields and re-parse as `VolumeSpec`; on the `upsert_volume_content` path the document is cloned again at the caller, so the same wire document is cloned and re-parsed twice per reconcile/readiness check - fix: take the spec by ownership once at the boundary and parse to `VolumeSpec` directly (drop the clone by passing the already-owned `Value`) - [packages/d2bd/src/shared_provider_effects.rs:690, packages/d2bd/src/shared_provider_effects.rs:854-858, packages/d2bd/src/shared_provider_effects.rs:891-895] - evidence: seed `\.clone\(\)` = 217 (shared_provider_effects.rs = 109 hits; production part read in full); callers of `validate_network_config_volume_spec` read at 850-897 - -## type -- d2bd-p8#7 sev=medium blast=leaf effort=S verdict=actionable - stringly-typed wire mode compared to string literals: `request.spec.pointer("/mode").and_then(Value::as_str) == Some("authority")` (USBIP service) and `mode == "projection"` (security-key service); an unknown or misspelled mode silently takes the non-authority / non-projection branch, flipping the admission posture without an error - fix: parse the mode once into a typed enum (`#[derive(Deserialize, PartialEq)]` with `rename_all = "kebab-case"`) at the effect boundary and refuse unknown values (fail closed) - [packages/d2bd/src/shared_provider_effects.rs:1299, packages/d2bd/src/shared_provider_effects.rs:1903-1908] - evidence: seed `fn validate_\w+|fn check_\w+` = 2; the mode state is reached via `/mode` JSON pointers (the direct-field spelling `(mode|kind|state): String` = 0 in this lane); both comparison sites read in full - -## api -- d2bd-p8#8 sev=low blast=leaf effort=S verdict=actionable - `pub use d2b_provider::{MAX_PROVIDER_REGISTRY_ENTRIES, ProviderRegistrySnapshot};` re-exports `ProviderRegistrySnapshot`, which nothing in d2bd uses; only `MAX_PROVIDER_REGISTRY_ENTRIES` is consumed (registry bound check) - fix: re-export `MAX_PROVIDER_REGISTRY_ENTRIES` only, removing the second path to `ProviderRegistrySnapshot` - [packages/d2bd/src/provider_registry.rs:48, packages/d2bd/src/provider_registry.rs:288] - evidence: census `ProviderRegistrySnapshot` over `packages/`, `nixos-modules/`, `tests/`, `docs/reference/`, `labs/`, `BUILD.bazel` = 6 hits, all in `d2b-provider` and this re-export itself; no consumer of the `d2bd::provider_registry::ProviderRegistrySnapshot` path - -## err -- d2bd-p8#9 sev=medium blast=wide effort=M verdict=needs-contract - user-input audio failures are flattened into `TypedError::InternalIo { context, detail }` strings on the mutation paths (VM absent, audio not enabled) in `dispatch_audio_set_volume` / `dispatch_audio_mute`, while the status path reports the same classes as structured `AudioVmError` + `AudioErrorKind::VmNotFound` / `AudioNotEnabled`; a caller of set-volume/mute cannot distinguish VM-not-found from an internal I/O failure except by string-matching the detail - fix: map the mutation paths onto the same structured kinds (extend `TypedError` with the audio kinds used by both paths); this changes the daemon-API wire error surface, so it is needs-contract - [packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, packages/d2bd/src/audio_dispatch.rs:417-438] - evidence: seed `\.unwrap\(\)|\.expect\(` = 269; read of both error paths; `TypedError` is the daemon-API wire error type (typed_error.rs:460+ `kind()`/`message()`) - -## serde -- d2bd-p8#10 sev=low blast=leaf effort=S verdict=actionable - `declared_fd_kind` allocates a `serde_json::Value::String(kind.to_owned())` heap value just to deserialize the wire `FdKind` enum (the kebab-case `serde` mapping) - fix: use `serde_json::from_str::(kind)` (no intermediate `Value`) or a plain `match` over the kebab-case spellings - [packages/d2bd/src/forward_rendezvous.rs:979-981] - evidence: seed `serde_json::from_|serde_json::to_` = 41 hits; site read in full - -## obs -- d2bd-p8#11 sev=low blast=leaf effort=S verdict=actionable - message-only `tracing::warn!("forward rendezvous is at its in-flight cap; refusing the call")` carries no fields and sits in a loop with no enclosing span, so the cap refusal cannot be attributed to a caller or the cap value - fix: add a field (`peer_uid`, `max = posture.max_inflight`) - [packages/d2bd/src/forward_rendezvous.rs:1250] - evidence: seed `(info|debug|warn|error|trace)!\("` = 1 hit (the only message-only event); `\bprintln!\(|\beprintln!\(` = 1 hit, a test `eprintln!` at forward_rendezvous.rs:4973 (out of scope) - -## docs -- d2bd-p8#12 sev=medium blast=leaf effort=S verdict=actionable - `pub fn dispatch_audio` is the only `pub` item in the lane without a doc comment; it is the daemon's audio dispatch entry with three op arms and non-obvious error behavior - fix: add a doc comment covering the op arms, the capability resolution, and the `TypedError` error surface - [packages/d2bd/src/audio_dispatch.rs:372] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 30 pub items over the four files; read of the pub-item list confirms every other one carries a doc contract -- d2bd-p8#13 sev=low blast=leaf effort=S verdict=actionable - doc-comment shape drift in forward_rendezvous.rs first sentences: double trailing periods and missing spacing (`The received descriptors,borrowed across the invocation..`, `attached:count equal`, `...kind the carrier vocabulary does not carry..`, `awaited for readiness..`) - fix: normalize punctuation/spacing in the affected comments - [packages/d2bd/src/forward_rendezvous.rs:1046-1049, packages/d2bd/src/forward_rendezvous.rs:1070, packages/d2bd/src/forward_rendezvous.rs:1093, packages/d2bd/src/forward_rendezvous.rs:1431-1432] - evidence: read of the doc comments at forward_rendezvous.rs:1040-1095, 1421-1432; `-> Result<` seed = 136 hits (all items with Result return either carry `# Errors`-style prose or are `pub(crate)` with documented contracts) - -## perf -- d2bd-p8#14 sev=low blast=leaf effort=M verdict=actionable - `AsyncSeqpacket::read_frame` allocates a fresh `vec![0u8; MAX_FRAME_SIZE + 5]` (1 MiB) per read, and `drain_pending` performs up to four such reads per refused call; the frame is length-prefixed, so the read buffer can be sized from the 4-byte prefix (or drained onto a reused buffer) instead of the full ceiling - fix: read the prefix, then allocate `declared + 5` - [packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476-1481] - evidence: seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 57; `MAX_FRAME_SIZE = 1024 * 1024` (d2b-contracts/src/lib.rs:63); static (unmeasured) -- d2bd-p8#15 sev=low blast=leaf effort=S verdict=actionable - grow-by-push vectors with known upper bounds: `guest_uids = Vec::new()` (bound `spec.attachments().len()`) and `entries`/`errors = Vec::new()` (bound `vm_names.len()`) - fix: `Vec::with_capacity()` - [packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.rs:392-396] - evidence: seed `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 57 hits; both sites read in full; static (unmeasured) - -## conc -- d2bd-p8#16 sev=low blast=leaf effort=S verdict=actionable - `Ordering::SeqCst` on the standalone `broker_epoch` atomic (store and load). The epoch is a self-contained value; the zones map it gates is mutex-guarded, so there is no paired publication needing Acquire/Release - `Ordering::Relaxed` is the weakest correct ordering here - fix: use `Ordering::Relaxed` at both sites - [packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414] - evidence: seed `Atomic\w+|Ordering::` = 13 hits; the two SeqCst sites and their ordering argument read in full (production atomics are otherwise Relaxed counters, and test atomics use Acquire/Release pairs for explicit handoff) - -## async -- d2bd-p8#17 sev=medium blast=leaf effort=M verdict=actionable - `ProductionSharedProviderEffects::runtime()` and `NetworkRuntime::bundle()` busy-wait with `std::hint::spin_loop()` on `tokio::sync::Mutex::try_lock()`; `runtime()` is called from async reconcilers (reconcile_network, reconcile_usbip, reconcile_tpm, ...), so a contended lock spins an executor worker instead of awaiting. The `// async-gate-allow` markers in this file cover the `.lock()` sites (recorded in async-gate-inventory.json:1165-1198) but these `try_lock`+spin sites are not marked or recorded, and the gate scanner matches `.lock()`/`.read()`/`.write()` only, so they are invisible to it. The in-code comment cites plan U10 / the broker rate limiter as the choice - fix: use `.lock().await` where the caller is async (split a sync lock path for the sync trait callers), or record these sites in the async-gate inventory as a deliberate exception - [packages/d2bd/src/shared_provider_effects.rs:316-324, packages/d2bd/src/shared_provider_effects.rs:2633-2639] - evidence: seed `async fn|async move|\.await` = 452, seed `tokio::sync::(Mutex|RwLock|Notify)` = 24; read of runtime()/bundle() and their callers; async-gate-inventory.json:1165-1198 covers the `.lock()` sites only - -## unsafe -- N/A: seeds `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 4 (all safe `io::Error::from_raw_os_error` constructors, not unsafe `from_raw` calls), `unsafe_code` = 0 - no unsafe blocks/fns/impls and no unsafe_code settings in the lane - -## ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 - no FFI boundary in the lane - -## macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 - no macro definitions or proc-macro machinery in the lane - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 21, `assert_eq!\(|assert_ne!\(|assert!\(` = 180, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; checked the unit and `#[tokio::test(flavor = "multi_thread")]` suites in all four files - the rendezvous suite drives real seqpacket sockets across stalls, handler crashes, deadlines, in-flight caps, fd legs, attestation freshness/epoch invalidation, effect-service respawn and chain-recording, with multi_thread flavor on timing paths and generous bounds; the registry/audio suites assert behavior and error variants (never Display strings), and no test is unable to fail; no ignored or property tests exist (absence noted, not a finding) - -## Coverage -- idiom: 4 finding(s) -- own: 2 finding(s) -- type: 1 finding(s) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: 1 finding(s) -- docs: 2 finding(s) -- perf: 2 finding(s) -- conc: 1 finding(s) -- async: 1 finding(s) -- unsafe: N/A (seeds: 0/0/4/0 - the 4 `from_raw` hits are safe `from_raw_os_error` constructors; no unsafe blocks/fns/impls or unsafe_code settings) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test: clean (seeds ran: 21/180/0/0; no findings) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md deleted file mode 100644 index 7998d966d..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p1.md +++ /dev/null @@ -1,86 +0,0 @@ -# d2bd-runtime-p1 - d2bd-runtime - part 1/4 -Baseline: 6ebdd4cec | LOC audited: 10715 (excl. src/generated/**) | modules: supervisor (dag, pidfd_table, readiness_liveness, state), typed_error, autostart, component_session_vsock, daemon_config, resource_api, zone_authority, shell_backend, broker_transport, public_read_model, vm_start_support, json_io -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 1/4: src/supervisor/**, src/typed_error.rs, src/autostart.rs, src/component_session_vsock.rs, src/daemon_config.rs, src/resource_api.rs, src/zone_authority.rs, src/shell_backend.rs, src/broker_transport.rs, src/public_read_model.rs, src/vm_start_support.rs, src/json_io.rs - -## idiom -- d2bd-runtime-p1#1 sev=low blast=leaf effort=S verdict=actionable - build_autostart_plan accumulates two Vecs with side-effect loops then extends a third, where an iterator pipeline partition would express the split - fix: replace the two push loops in build_autostart_plan with a collector pair: `let (net_entries, workload_entries): (Vec<_>, Vec<_>) = resolver.manifest.vms.iter().map(|(name, vm)| { ... }).partition(|e| e.is_net_vm);` then sort each half - [autostart.rs:228-245] - evidence: seed3 `let mut \w+ = (String|Vec)::new\(\)` = 10 hits; hit sites 228-229 are the statement-style split being judged (other hits are test fixtures or map-key builders) -- clean: seeds 1 `for \w+ in 0\.\.` = 4 (all fixed-count test loops in pidfd_table.rs:990-1015,1412-1415 - deliberate retry bounds), seed2 `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 5 (hand-written Default impls for AutostartConfig, ArtifactPaths, DaemonConfig, NodeBudget preserve fixed-path/invariant defaults a derive would break - justified), seed3 = 10 (one suspect site above, all other hits are owned map keys or test fixtures). - -## own -- d2bd-runtime-p1#2 sev=low blast=leaf effort=S verdict=actionable - DagExecutor::run_split clones `state` into api_ready then matches the same value by move, when matching `&state` would keep it - fix: `match &state { .. }`, bind `ApiReadyState::Error { reason }` by reference in the format! call, and set `api_ready = Some(state)` after the match - [dag.rs:423-424] - evidence: seed1 `\.clone\(\)` = ~75 hits; this clone is the only avoidable one (api_ready then match by move; the enclosing value is not used afterwards in the match arms other than the cloned copy) -- clean: seed2 `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = ~110 hits (map keys, Display/remediation strings, test fixtures - all explainable one-liners), seed3 `Rc<|RefCell<|Arc`, pushing an Arc + trait-object + the whole backend trait into the public field surface, when callers only need the three trait methods - fix: make the field private, add `handle_op`/`close_attachment`/`cancel_attachment` delegating methods on EstablishedShell, and update the d2bd/src/composition.rs call sites (13403,13460,13517,13625,13677)) - [shell_backend.rs:52-53] - evidence: seed2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits; census: `EstablishedShell` over packages/nixos-modules/tests/docs/reference/labs = 9 hits (5 cross-crate field reads in d2bd/src/composition.rs - the field is genuinely consumed, so the fix is delegation, not deletion) -- d2bd-runtime-p1#5 sev=low blast=leaf effort=S verdict=actionable - CachedPublicFrame is pub with pub fields (including a serde_json::Value dependency field)but only used inside public_read_model; the struct is dead public surface - fix: make CachedPublicFrame (and its fields) module-private or pub(crate, keep the ArcSwapOption slots private - [public_read_model.rs:51-53] - evidence: seed1 `^\s*pub (fn|struct|enum|trait|const|mod) ` = ~110 hits; census: `CachedPublicFrame` over packages/nixos-modules/tests/docs/reference/labs = 5 hits, all inside public_read_model.rs (lines 52,60,61,115,139) - no consumer outside the module -- clean: seed2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits (zone_authority.rs:181 new_coordinator Arc> - documented U17 shared handle with awaitable entry points; shell_backend.rs:53 - flagged above), seed3 `^\s*pub use ` = 1 (supervisor/pidfd.rs:3 re-export of the pidfd_table surface - house single-surface pattern) - -## err -- d2bd-runtime-p1#6 sev=high blast=leaf effort=S verdict=actionable - default_audit_join_context panics with `.expect("canonical broker zone digest")` on a wire-supplied digest - a malformed request from the broker client crashes the daemon instead of returning a refusal - fix: propagate the parse failure (e.g. `CanonicalAuditDigest::parse(zone_id).ok()?;` or map into TypedError::WireInvalidFrame/InternalConfig),and only attend None when digest missing route review-pass - [broker_transport.rs:63,65] - evidence: seed1 `\.unwrap\(\)|\.expect\(` = ~60 hits; production hits are only these 2 (both with wire-derived values via request.authoritative_audit_join()); every other hit sits in #[cfg(test)] modules or asserts a construction invariant (dag.rs:344,406, state.rs:403,411, pidfd_table.rs:496, typed_error.rs:1266) -- clean: seed2 `let _ = |\.ok\(\);` = ~30 (reply.send best-efforts in autostart.rs:394, test fixture joins, OnceLock::set one-shot setters, parent-dir sync best-effort - deliberate per site); seed3 `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = ~12 (all in #[cfg(test)] modules - test assertion style); seed4 `enum \w*Error` = ~10 (TypedError + four closed kind enums + ResourceRuntimeError, ZoneAuthorityError, ModeBoundBrokerError, DagError, PidfdTableError, ProcStatError, SnapshotStoreError - taxonomy split by caller action with wire_kind()/code()/label() accessors, no string-matching callers) - -## serde -- clean: seeds 1 `derive\([^)]*(De)?[Ss]erialize` = ~25, seed2 `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = ~30, seed3 `impl .*Deserialize.*for` = 1, seed4 `serde_json::from_|serde_json::to_` = ~20; config/snapshot types carry rename_all + deny_unknown_fields + per-field serde(default) with default_* fns consistent with hand-written Default; the only hand-written deserializer (ApiReadyState in dag.rs:89-108)is a deliberate wire admission gate over an untagged Helper enum for the `"yes"|"pending"|"timeout"|{"error": str}` shapes, round-trip tested at dag.rs:1058-1113 - not flagged - -## obs -- clean: seeds 1 `\bprintln!\(|\beprintln!\(` = 0, seed2 `(info|debug|warn|error|trace)!\("` = 0, seed3 `\.instrument\(|#\[instrument` = 0, seed4 `tracing::|log::` = ~25; every tracing event carries named fields (kind, path, detail, busid, vm, role, error, generation),the TypedError::log_raw_detail boundary logs the chain once with the unredacted detail deliberately kept out of the public envelope, and no secret/identifier-only fields beyond the ADR 0010/0028 redaction gate scope were found - -## docs -- d2bd-runtime-p1#7 sev=medium blast=leaf effort=S verdict=actionable - Three public helpers in json_io.rs carry no doc comments, though their semantics are non-obvious (absolute-vs-relative bundle path resolution, manifest-must-be-object) - fix: add one-line-then-detail doc comments (`# Errors` for the Result fns)on resolve_bundle_artifact_path and load_manifest - [json_io.rs:10,41] - evidence: seed1 `^\s*pub (fn|struct|enum|trait|const|type) ` = ~110 hits; spot-check of the file (65 LOC) found 2 undocumented pub items -- d2bd-runtime-p1#8 sev=medium blast=leaf effort=S verdict=actionable - Public fns in vm_start_support.rs lack docs while siblings are documented; role->mode mapping, tracked_role_id, and store-view-intent resolution are contract-relevant for the d2bd composition - fix: add one-line-first-sentence docs (+ `# Errors` for the Result fn)on vm_start_node_mode, tracked_role_id, resolve_store_view_intent_for_guest - [vm_start_support.rs:14,44,89] - evidence: seed1 = ~110 hits; full-file read (186 LOC) found 3 undocumented pub items (neighboring items have docs - inconsistent coverage) -- d2bd-runtime-p1#9 sev=medium blast=leaf effort=S verdict=actionable - ShellTerminalOp, ShellTerminalResponse,and EstablishedShell (a cross-crate contract type) carry no doc comments - fix: add doc comments naming each op/response variant's wire twin and the EstablishedShell lifetime/ownership contract - [shell_backend.rs:14,21,52] - evidence: seed1 = ~110 hits; item-list read of shell_backend.rs found 3 undocumented pub items (EstablishedShell is consumed by d2bd/src/composition.rs:13703) -- d2bd-runtime-p1#10 sev=medium blast=leaf effort=S verdict=actionable - Five broker_transport helpers (audit-join extraction, deadline arithmetic, kind extraction, two launcher redaction renderers)carry no docs, and two of them format operator-facing remediation strings - fix: add one-line-first-sentence docs naming input contracts and output shapes, with `# Panics` on default_audit_join_context identified - [broker_transport.rs:60,69,116,128,187] - evidence: seed1 = ~110 hits; targeted raw reads of broker_transport.rs found 5 undocumented pub fns (the file's other fns carry /// docs (e.g. dispatch_broker_request_to_socket, ModeBoundBrokerAdapter)) -- clean: seed2 `/// # (Examples|Errors|Panics|Safety)` = 0, seed3 `-> Result<` = ~55; Result-returning items mostly carry #-style contract prose in prose form; no doctests exist in this lane (acceptable: no pure example-worthy boundary items in the lane scope) - -## perf -- d2bd-runtime-p1#11 sev=low blast=family effort=M verdict=actionable - load_list/load_status clone the entire cached serde_json::Value frame per call (`then(|| cached.value.clone())`), making every public status/list poll allocate a full copy of the read-model frame - fix: return `Option>` (or `&Value` tied to the Arc swap guard)from load_if_fresh and let the wire renderer borrow the Value; update the d2bd composition call sites - [public_read_model.rs:117-118] - evidence: static (unmeasured) - no benchmark exists for the public-read path; seed1 `format!\(` = ~70 (all in error strings, remediation rendering, and test fixtures - cold paths), seed2 `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = ~15 (empty-case-common collection builds and test fixtures), seed3 `\.to_string\(\)` = ~110 (Display/error/remediation strings - the artifact is the text) - -## conc -- clean: seeds 1 `std::thread::|thread::spawn|thread::scope` = ~9 (autostart run_phase dedicated bounded worker threads per plan R4 (documented at autostart.rs:352-356)and test threads in pidfd_table/component_session_vsock), seed2 `\bMutex<|\bRwLock<` = ~9 (PidfdTable RwLock+mutation_lock Mutex serializing register/snapshot sequences, BrokerReapLog Mutex, InMemorySnapshotStore Mutex (test-only), FakeStarter/FakeRunner Mutexes (cfg(test))), seed3 `Atomic\w+|Ordering::` = ~25 (SNAPSHOT_TMP_COUNTER/next-id Relaxed counters, PidfdTable generation AcqRel/Acquire pairs, PublicStatusReadModel AcqRel/Acquire CAS publish loop - weakest correct orderings for the handoff each guards), seed4 `thread_local!|unsafe impl (Send|Sync) for` = 0; no manual Send/Sync claims, no shared-state-among-threads mis-model found - -## async -- clean: seeds 1 `async fn|async move|\.await` = ~90, seed2 `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = ~12 (JoinSet spawns in autostart run_phase and dag executor tests; `spawn_blocking` = 0 - dedicated threads per R4 replace it), seed3 `tokio::sync::(Mutex|RwLock|Notify)` = ~3 (zone_authority coordinator Mutex - guard held only across synchronous calls, documented U17), seed4 `#\[tokio::(main|test)\]|Runtime::block_on` = ~16 (tokio::test marks; block_on sites in shell_backend.rs:112,224,241 carry `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` - sanctioned blocking-census entries); no guard held across an await, no blocking call on an executor worker,and no cancellation-unsafe irreversible step found - -## unsafe -- clean: seeds 1 `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, seed2 `// SAFETY:` = 0, seed3 `transmute|from_raw|MaybeUninit|mem::zeroed` = 4 (all `rustix::process::Pid::from_raw` / `rustix::process::Signal::from_raw` safe constructors in pidfd_table.rs:401,744,808and state.rs:321 doc prose - no actual unsafe blocks/UB hazards), seed4 `unsafe_code` = 2 (documentation: state.rs:322and the daemon workspace lint inherit - no allow); the lane contains no unsafe code, so no SAFETY comments are owed - -## ffi -- N/A: seeds 1-4 all zero; no FFI surface exists in the assigned files (libc::c_int signal numbers are syscall-adjacent but never cross a foreign caller) - -## macro -- N/A: seeds 1 `macro_rules!` = 0, seed2 `proc_macro|syn::|quote!` = 0, seed3 `\$crate` = 0, seed4 `to_compile_error|new_spanned` = 0 all zero; no macro definitions or proc-macro machinery in the lane - -## test -- clean: seeds 1 `#\[test\]|#\[tokio::test\]` = ~120 (unit tests per module + 2 boundary tests in tests/runtime_boundary.rs), seed2 `assert_eq!\(|assert_ne!\(|assert!\(` = ~320 (behavioral assertions with per-case messages, error-variant matches not Display strings), seed3 `proptest!|insta::assert|rstest` = 0 (no property/snapshot tooling; hand-built case tables with failure messages cover the parser/classifier edges adequately for the closed input classes), seed4 `#\[ignore\]` = 0 (no ignored tests); tests are deterministic (fixed `/proc/stat` fixtures, injected fakes, no network, tempdir-scoped state),and the boundary test suite locks the provider-implementation-free contract - -## Coverage -- idiom: 1 finding(s) -- own: 1 finding(s) -- type: 1 finding(s) -- api: 2 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: ~25/~30/1/~20; all shapes deliberate; one hand-written admission gate with round-trip test) -- obs: clean (seeds ran: 0/0/0/~25; named-field events only, no println, no interpolated message-only logs, no secret fields) -- docs: 4 finding(s) -- perf: 1 finding(s) -- conc: clean (seeds ran: ~9/~9/~25/0; worker-thread model and lock/atomic orderings match the workload shapes) -- async: clean (seeds ran: ~90/~12/~3/~16; dedicated R4 workers, no awaits-under-lock, no executor blocking) -- unsafe: clean (seeds ran: 0/0/4/2; only safe rustix::process::Pid::from_raw constructors; no unsafe blocks to justify) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: N/A (seeds: 0/0/0/0 all zero; no macros) -- test: clean (seeds ran: ~120/~320/0/0; deterministic behavior-focused unit+boundary suite, error variants asserted, no ignored/property tests needed for the closed input classes) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md deleted file mode 100644 index 5fe6d86a0..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p2.md +++ /dev/null @@ -1,79 +0,0 @@ -# d2bd-runtime-p2 - d2bd-runtime - part 2/4 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10744 (excl. src/generated/**) | modules: resource_runtime_support, guest_resource_runtime, workload_dispatch, runtime_process, workload_target_index, wire, ssh_host_key_preflight, public_projection, resource_operator_activation, exec_detached, admission, daemon_client, runtime_capability -Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: part 2/4 (whole-file modules; none split) - -## idiom -- clean: seeds `for \w+ in 0\.\.`=2 (workload_dispatch.rs:786,797, test id-name builders only), `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`=0 (plus 3 generic-shaped hand-written `impl ... Debug for` not matched by the seed: exec_detached.rs ResourceDetachedClient, guest_resource_runtime.rs GuestResourceRuntime/GuestResourceStore - all deliberate redaction/format impls, not derive-replaceable), `let mut \w+ = (String|Vec)::new\(\)`=5 (resource_runtime_support.rs:438 rule builder with `?` short-circuit, :1231 zone-user filter loop with early Err, guest_resource_runtime.rs:665 mutation-loop, :1117/:1568 byte key-material buffers). Every hit is an explainable loop shape (side-effecting, error-propagation, byte concat); no iterator-pipeline regression worth changing. - -## own -- clean: seeds `\.clone\(\)`=100, `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`=128, `Rc<|RefCell<|Arc Arc` (guest_resource_runtime.rs:418) hands out the shared store clone by design; lib.rs exports modules directly (single path per item, no duplicate re-export arms); traits `DetachedProcessResourcePort`, `Wave6ProviderBoundary` keep a small required surface. No semver-concerning export found in this part. - -## err -- d2bd-runtime-p2#3 sev=medium blast=leaf effort=M verdict=actionable - `map_parse_error` (wire.rs:529-536) classifies `serde_json::Error` kinds by substring-matching the Display text ("unknown field", "interface name"), so the wire-visible kinds `wire-unknown-field`/`wire-if-name-invalid` flip silently if serde_json rewords a message - fix: classify structurally instead of lexically - e.g. parse the request envelope against a `#[serde(deny_unknown_fields)]`-tagged shape so "extra field" arrives as a discrete rejection (the manual authStatus/usbipProbe arms already do this), and route the raw serde error through `error.classify()` plus line/column for the generic frame kind - [wire.rs:529-536] - evidence: seeds: `\.unwrap\(\)|\.expect\(`~185 (prod sites 10 - all fixed-literal-valued expects of the card's false-positive family, e.g. resource_runtime_support.rs:1123/1311/1565/1737/1833, guest_resource_runtime.rs:997; rest test-only), `let _ = |\.ok\(\);`=8 (test cleanup removes + deliberate `read_link)...).ok()`), `\bpanic!\(|unreachable!\(|todo!\(|unimplemented!\(`=12 (all tests), `enum \w*Error`=5 (GuestResourceRuntimeError, ShellTargetError, CatalogError, TargetResolutionError, Wave6BoundaryError - shown well-shaped by caller action) - -## serde -- d2bd-runtime-p2#4 sev=low blast=leaf effort=M verdict=actionable - `parse_request` (wire.rs:256-355) hand-rolls the internally-tagged dispatch that serde provides: a 19-arm match on the `type` string then `serde_json::from_value` per arm, where the 15 plain verbs would parse directly from a `#[serde(tag = "type", rename_all = "camelCase")]` tagged enum - fix: split a tagged parse enum for list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio derived with internal tag, keeping the custom authStatus/usbipProbe empty-body checks, console opId removal and resourceRequest passthrough explicit; confirm each payload type's deny_unknown_fields posture is unchanged before shipping - [wire.rs:265-353] - evidence: seeds: `derive\([^)]*(De)?[Ss]erialize`=5 (Serialize-only response frames, deliberate), `serde\((rename_all|deny_unknown_fields|try_from|flatten|...)\)`=8, `impl .*Deserialize.*for`=0, `serde_json::from_|to_`~70; manual read of the parse boundary and its round-trip + rejection tests (wire.rs:548-660) verifies behavior is covered - -## obs -- d2bd-runtime-p2#5 sev=low blast=leaf effort=S verdict=actionable - `write_daemon_version_file` (runtime_process.rs:446-486) reports its five failure paths with `eprintln!` from a library module instead of `tracing`, bypassing level/filter/structure - fix: route them through `tracing::warn!`/`tracing::error!` with the path/context as named fields (module already uses tracing in the sd_notify fns) - [runtime_process.rs:450, runtime_process.rs:464, runtime_process.rs:472, runtime_process.rs:480, runtime_process.rs:484] - evidence: seeds: `\bprintln!\(|\beprintln!\(`=9 (5 prod here, 3 test-fixture, 1 daemon_client.rs:17 test-client stdout = product output), `(info|debug|warn|error|trace)!\("`=0, `\.instrument\(|#\[instrument`=0, `tracing::|log::`~30 -- d2bd-runtime-p2#6 sev=low blast=leaf effort=S verdict=actionable - event fields allocate eagerly even when the level is filtered: `mode = format!("{mode:o}")` inside a `tracing::debug!` (ssh_host_key_preflight.rs:305, hot on every key entry) and a pre-joined `subjects` string built before a `tracing::warn!` (resource_runtime_support.rs:679-680) - fix: use `tracing::field::debug(format_args!("{mode:o}"))` for the octal mode and `tracing::field::display(subjects.iter().map)...).collect::>().join(","))` (or an `Empty`-then-record) so nothing is formatted when the event is disabled - [ssh_host_key_preflight.rs:305, resource_runtime_support.rs:679-680] - evidence: seeds: println/eprintln=9, `)...)!\("`=0, instrument=0, tracing::~30; manual read of the two event sites confirms eager construction - -## docs -- d2bd-runtime-p2#7 sev=medium blast=leaf effort=M verdict=actionable - several publicly-reachable items in this part carry no doc contract: `ensure_manifest_entry_runtime_capability` (runtime_capability.rs:47-64, returns `Result` with a capability-specific error), the security-admission `authorize_peer`/`classify_peer` (admission.rs:61-159, including the non-obvious `production_lookup` mode), and `run_test_client`/`apply_overrides` (daemon_client.rs:12-43) - fix: add one-line first sentences plus `# Errors` naming `TypedError::RuntimeCapabilityUnsupported`/`AuthzNotALauncher` and vertical workspace for the mode semantics; link the daemon-dispatch callers as intra-doc links - [runtime_capability.rs:47-64, admission.rs:61-159, daemon_client.rs:12-43] - evidence: seeds: `^\s*pub (fn|struct|enum|trait|const|type)`~170, `/// # (Examples|Errors|Panics|Safety)`=0, `-> Result<`~80; read: the listed items have no doc comments, and none of the Result-returning items in the part carry a canonical `# Errors` section -- d2bd-runtime-p2#8 sev=low blast=leaf effort=S verdict=actionable - the `has_posix_acl` doc first sentence begins with an unexplained `v1.1.2fu25:` audit-workflow token, and a sibling `P2fu1 ...` workflow tag sits inside an enabled trace field comment list - fix: drop/relocate the workflow tokens so the rendered contract reads plain, keeping the "0440-with-ACL legitimate vs drift" why in the body (it is the good part) - [ssh_host_key_preflight.rs:312, ssh_host_key_preflight.rs:298-301] - evidence: seeds: `/// # ...`=0, `-> Result<`~80; doc-token grep `fu\d+` over the part = 2 (ssh_host_key_preflight.rs:298 comment, :312 doc) - -## perf -- d2bd-runtime-p2#9 sev=medium blast=leaf effort=S verdict=actionable - every daemon wire request is deep-cloned before parsing: the 17 `serde_json::from_value(Value::Object(object.clone()))` arms and the `object.clone().into_iter().collect()` resourceRequest arm (wire.rs:274-352) copy the entire frame Value, then the copy is dropped - fix: `Value::Object(std::mem::take(object))` in each arm and `std::mem::take(object).into_iter().collect()` for resourceRequest (object is a `&mut Map` dead after the exclusive arm bodies); removes a whole-payload clone per request on the CLI/daemon socket path - [wire.rs:275-346, wire.rs:350-351] - evidence: static (unmeasured; no benchmark exists); seeds: `format!\(`~60 (all cold: error paths, diagnostics, test helpers), `Vec::new\(\)|VecDeque|HashMap|BTreeMap::new`~17, `\.to_string\(\)`~20 (error-detail serialization only); manual read of wire.rs:256-353 - -## conc -- d2bd-runtime-p2#10 sev=low blast=leaf effort=S verdict=actionable - `NewPlaneReadinessState` (resource_runtime_support.rs:144-180) stores four independent readiness booleans with `Ordering::SeqCst` on every store/load; there is no Release/Acquire paired handoff (each flag is an independent published bit) - fix: `Ordering::Relaxed`, which is the weakest correct ordering for independent flags; the cross-thread visibility the startup path needs is already ordered by the join/actor supervision in the daemon, and SeqCst here does not buy snapshot atomicity across the four flags anyway - [resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support.rs:166, resource_runtime_support.rs:170, resource_runtime_support.rs:175-178] - evidence: static (unmeasured); seeds: `std::thread::|thread::spawn|thread::scope`=0, `\bMutex<|\bRwLock<`=8 (tokio mutexes in the guest store + sync ledger Mutex on the sanctioned synchronous path + cfg(test) statics), `Atomic\w+|Ordering::`~14, `thread_local!|unsafe impl (Send|Sync) for`=0 - -## async -- clean: seeds `async fn|async move|\.await`~100, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(`=5, `tokio::sync::(Mutex|RwLock|Notify)`=6, `#\[tokio::(main|test)\]|Runtime::block_on`=5. Checked: the guest store uses `tokio::sync::Mutex` for state genuinely locked across await points (guest_resource_runtime.rs:643-738) with the guard not spanning extra awaits beyond the lock scope; `launch_ledger()`'s `std::sync::Mutex` is confined to the sanctioned synchronous path with `#[allow(clippy::disallowed_methods, reason = "synchronous path")]`; `register_system_core_session` handshake uses `tokio::join!` and a detached (deliberate) ttrpc service spawn; no `// async-gate-allow:` markers and no blocking work found inside async contexts in this part. - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern`=0, `// SAFETY:`=0, `transmute|from_raw|MaybeUninit|mem::zeroed`=2 - both false positives of the seed: `Uid::from_raw)...)` in runtime_process.rs:211/236 and chown-guard arithmetic, safe nix constructors). U1 (d)8 records no d2bd-runtime unsafe blocks at this HEAD (only the typed_error.rs doc-word false positive, which is in part 1's scope). - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section`=0, `catch_unwind`=0, `repr\(C\)|repr\(transparent\)`=0, `CStr|CString|c_char`=0). No foreign-caller boundary in this part; the nix socket/seqpacket wrappers are in-crate safe bindings. - -## macro -- N/A (seeds: `macro_rules!`=0, `proc_macro|syn::|quote!`=0, `\$crate`=0, `to_compile_error|new_spanned`=0). No macro definitions in this part. - -## test -- d2bd-runtime-p2#11 sev=high blast=leaf effort=S verdict=actionable - `sd_notify_ready_noops_without_notify_socket` (runtime_process.rs:543-546) and `sd_notify_ready_errors_when_socket_is_unreachable` (runtime_process.rs:589-594) cannot fail: each body only calls `sd_notify_ready)...)` on a path the function returns without panicking (None early-return; Some-to-missing-socket caught and warn-logged), with no assertion anywhere - fix: delete both, or give them an observable assertion modeled on the sibling `sd_notify_ready_sends_pathname_datagram` (bind a datagram listener, send the payload, assert the received bytes / exit-code), so the suite refuses to pass silently when the notification path regresses - [runtime_process.rs:543-546, runtime_process.rs:589-594] - evidence: seeds: `#\[test\]|#\[tokio::test\]|assert_eq!\(|assert_ne!\(|assert!\(`~355 (deterministic sample of 50 read: every other sampled test asserts behavior or error variants - including `error.kind()`/`StoreErrorKind` variant asserts, restart-simulation round-trips with failure messages, and wire rejection kind asserts; these two were the only assertions-free bodies in the sample); `proptest!|insta::assert|rstest`=0, `#\[ignore\]`=0 - -## Coverage -- idiom: clean (seeds ran: 2/0(+3 generic-shaped manual Debug impls inspected)/5; all explainable) -- own: clean (seeds ran: 100/128/1/0; sampled 50 of 229; one avoidable clone family -> perf#9) -- type: 2 finding(s) -- api: clean (seeds ran: ~164/2/3; the 2 Arc-in-signature sites evaluated and legitimately shared) -- err: 1 finding (seeds ran: ~185/8/12/5) -- serde: 1 finding (seeds ran: 5/8/0/~70) -- obs: 2 finding(s) -- docs: 2 finding(s) -- perf: 1 finding (seeds ran: ~60/~17/~20; static unmeasured) -- conc: 1 finding (seeds ran: 0/8/~14/0) -- async: clean (seeds ran: ~100/5/6/5) -- unsafe: N/A (seeds: 0/0/2(false positives: Uid::from_raw)/-) -- ffi: N/A (seeds: 0/0/0/0) -- macro: N/A (seeds: 0/0/0/0) -- test: 1 finding (sampled 50 of 355 hit mass; proptest/insta/rstest=0, #[ignore]=0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md deleted file mode 100644 index 6eeea3651..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p3.md +++ /dev/null @@ -1,85 +0,0 @@ -# d2bd-runtime-p3 - d2bd-runtime - part 3/4 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10718 (excl. src/generated/**) | modules: exec_session, unsafe_local_helper, metrics, authority_persistence, readiness, otel_host_bridge_readiness, ownership_preflight, unix_transport, exec_session_real, terminal_session, pidfs_probe, lib, runtime_util -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: part 3/4 of d2bd-runtime (whole-file lane; no range splits) - -## idiom -- d2bd-runtime-p3#1 sev=low blast=leaf effort=S verdict=actionable - two fd-extraction loops grow a Vec via `extend` in a `for` over `cmsgs()`, where a filter_map collect would read as one expression - fix: collect `message.cmsgs().map_err)...)?.filter_map(|c| ...).flatten().collect()` into the result Vec in `receive_frame` and `read_frame_with_fds` - [packages/d2bd-runtime/src/unsafe_local_helper.rs:789, packages/d2bd-runtime/src/unix_transport.rs:294] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 4 hits; the two allocate-then-extend fd loops are the replaceable pair (the other two hits build String/axes buffers, deliberate accumulation) -- clean: additional seeds for this lens: `for \w+ in 0\.\.` = 6, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 4; index loops are all `for _ in 0..N` bounded retry/drain loops (no element indexing), hand-written `Default` impls set non-zero invariants (`ExecOpDeadlines`, `ExecSessionCaps`, `ReadinessWaitConfig`) or wrap non-Default fields (`Registry::new` -> `Self::new`), so none is derive-replaceable - -## own -- d2bd-runtime-p3#2 sev=low blast=leaf effort=S verdict=actionable - three `operation_id.to_string()` copies of an already-owned `String` are produced only to be borrowed or passed along (`complete_pending` takes `String` just for one comparison), so each completed/rejected helper op pays a heap alloc - fix: change `complete_pending` to take `operation_id: &str` and pass `&result.operation_id` / `&rejected.operation_id` at the three call sites (the second local `let operation_id = result.operation_id.to_string()` becomes `&result.operation_id` directly) - [packages/d2bd-runtime/src/unsafe_local_helper.rs:625, packages/d2bd-runtime/src/unsafe_local_helper.rs:629, packages/d2bd-runtime/src/unsafe_local_helper.rs:644] - evidence: seed `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 157 hits; the three sites are the only String-to-String copies made solely for borrowing -- clean: all own seeds (58 `.clone()`, 157 `.to_owned`/`.to_vec`/`.to_string`, 1 `Arc>` hit is `authority_persistence.rs:77` type alias `Rows`, part of a documented multi-thread shared ledger; every other clone/copy is a map-correlated stored value, a test fixture, an error-context `to_owned`, or an Arc clone at a spawn/thread boundary (required for `'static`) - -## type -- clean: seeds ran: 1/0/0; the single hit is a `#[test]` fn name (`validate_rejects_wrong_kind` in metrics.rs:1139), not a runtime validation predicate; pub struct/enum surfaces were surveyed via the api-runs for flag soup, Option-pair smells, stringly-typed state (none;`ReadinessProbe`'s two booleans fold into the terminal `OtelHostBridgeReadiness` verdict enum, `NegotiatedCaps`'s booleans are independently real capability gates) - -## api -- d2bd-runtime-p3#3 sev=low blast=leaf effort=M verdict=actionable - `pub fn spawn_session_worker` (with `pub struct WorkerSpawn`, `SessionTable`, `ExecOpDeadlines`, `ExecStartSpec`, etc.) has no production caller in the workspace - only its own crate's tests - so the whole exec-session worker surface is either pending wiring from d2bd composition or dead public API - fix: wire `spawn_session_worker`/`SessionTable` into d2bd's exec composition (or gate the module test-support-only pending that wiring) - [packages/d2bd-runtime/src/exec_session.rs:900] - evidence: census: `spawn_session_worker` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel = 4 hits (pub fn def at :900, doc cross-ref at :880, two test call sites at :2486 and :3624); api seed counts: 214/9/0 -- clean: the 9 `pub .*(Arc|Rc|Box|RefCell)<` hits are all genuine shared-ownership tokens (`Established.client`, `WorkerSpawn.connector/clock/owner_reaper`, `HelperRegistry::accept_loop(Arc)`, `ZoneAuthorityLedger::install_*`) whose shared ownership is exercised at spawn/thread boundaries;`pub use` absent, every item reachable via exactly one path (lib.rs `pub mod` arms are the house single-surface pattern) - -## err -- d2bd-runtime-p3#4 sev=low blast=leaf effort=S verdict=actionable - `spawn_session_worker` panics at `std::thread::Builder::spawn)...).expect("spawn exec session worker thread")` in library code on an environmental failure (thread exhaustion/ENOMEM) with a caller-visible alternative - fix: return `std::io::Result>` (or map to `TypedError`) and have the two test call sites adjust - [packages/d2bd-runtime/src/exec_session.rs:939] - evidence: seed `\.unwrap\(\)|\.expect\(` = 254 hits; the only non-test hit besides :939 is metrics.rs:352 `descriptor)...).expect("validated above")`, a post-check invariant; census: spawn_session_worker = 4 hits (no prod caller, so the panic is test-reachable only today) -- clean: remaining err seeds: `let _ = |\.ok\(\);` = 41 hits (every site is deliberate best-effort teardown/oneshot/`write!` onto a `String`, or test cleanup), `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 24 (all test code or internal-invariant `unreachable!`s in non-test code at exec_session.rs:1203,:1256), `enum \w*Error` = 7 (closed enums with `slug()` accessors, fine taxonomy shapes) - -## serde -- clean: seeds ran: 1/0/0/13; the lone derive hit is `OtelHostBridgeReadiness` (internal-tag `status` + `kebab-case` enum, pinned by envelope-shape tests at otel_host_bridge_readiness.rs:601-623); all `serde_json` boundary calls map failures into typed errors (`ExecOpError::Protocol`, `HelperRegistryError::InvalidFrame`, `AuthorityPersistenceError::RowInvalid`, `TypedError::InternalIo`) rather than unwrapping - -## obs -- d2bd-runtime-p3#5 sev=low blast=leaf effort=S verdict=actionable - the one-shot-exit unparseable-stat warning is message-only with no named fields (`tracing::warn!("wait_for_one_shot_exit: /proc//stat unparseable; ...")`), though `pid` and a `path` string are in scope and sibling warnings carry `%err`/field-style context - fix: emit fields (`pid = %pid`, `path = %path`) with a short message (or wrap the poll loop in a span carrying `pid`) - [packages/d2bd-runtime/src/readiness.rs:327] - evidence: seed `(info|debug|warn|error|trace)!\("` = 23 hits; all other hit sites carry named fields (or `%err` field); no instrument span envelopes this helper (seed `\.instrument\(|#\[instrument` = 0) -- d2bd-runtime-p3#6 sev=low blast=leaf effort=S verdict=actionable - pidfs probe warns/errors interpolate a prebuilt `{msg}` string with embedded `st_dev`/`detail` values instead of named fields, while the sibling `PidfsAvailable` arm already emits `pidfs_st_dev`/`pidfs_st_ino` fields - fix: give `PidfsNotPresent` and `UnexpectedError` arms named `pidfs_st_dev = %st_dev` / `detail = %detail` fields (and keep the long operator-facing sentence as the message template) - [packages/d2bd-runtime/src/pidfs_probe.rs:129, packages/d2bd-runtime/src/pidfs_probe.rs:132, packages/d2bd-runtime/src/pidfs_probe.rs:144, packages/d2bd-runtime/src/pidfs_probe.rs:147, packages/d2bd-runtime/src/pidfs_probe.rs:158] - evidence: seed `(info|debug|warn|error|trace)!\("` = 23 hits; the cited five are the only `{msg}`-interpolated events in this lane (readiness.rs:327 is finding d2bd-runtime-p3#5) -- clean: `\bprintln!\(|\beprintln!\(` = 0;`tracing::|log::` = 23 (all `tracing`, structured, prefixed `provider`/`event_kind`/`result` scheme in unsafe_local_helper, `vm`/`path`/`reason` fields elsewhere); no secret material in any field (Debug impls redact terminal bytes, argv/env, and unguessable handles) - -## docs -- d2bd-runtime-p3#7 sev=medium blast=leaf effort=M verdict=actionable - unsafe_local_helper.rs has no `//!` module doc and its public surface (consts `HELPER_HEARTBEAT_INTERVAL`/`HELPER_STALE_AFTER`/`HELPER_OPERATION_TIMEOUT`, enums `HelperRegistryError`/`HelperAvailability`/`HelperReply`, struct `HelperRegistry` + its seven pub methods) carries no doc comments, unlike every sibling module in this crate - fix: add a `//!` header (lifecycle, wire protocol, thread model, redaction rules) and one-line `///` docs per pub item - [packages/d2bd-runtime/src/unsafe_local_helper.rs:1, packages/d2bd-runtime/src/unsafe_local_helper.rs:33, packages/d2bd-runtime/src/unsafe_local_helper.rs:42, packages/d2bd-runtime/src/unsafe_local_helper.rs:65, packages/d2bd-runtime/src/unsafe_local_helper.rs:71, packages/d2bd-runtime/src/unsafe_local_helper.rs:190] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 hits in lane; the cited items have zero `///` lines (verified by contiguous read) -- d2bd-runtime-p3#8 sev=medium blast=leaf effort=S verdict=actionable - public exec-session DTO fields lack doc comments on a cross-crate contract surface (`ExecStartSpec.vm/argv/tty/detached/env/cwd/term_size`, `ExecSessionInfo.tty/stdout_offset/stderr_offset`, `Established.client/info/control_seq/caps`, `WorkerSpawn.connector/spec/deadlines/establish_tx/control_rx`), while sibling fields (`request_id`, `NegotiatedCaps.*`, `TerminalReaper`/`SessionSlot` fields) are documented - fix: add `///` per field (semantics plus any redaction/derivation promise), especially what `control_seq`/`establish_tx` carry - [packages/d2bd-runtime/src/exec_session.rs:181, packages/d2bd-runtime/src/exec_session.rs:211, packages/d2bd-runtime/src/exec_session.rs:249, packages/d2bd-runtime/src/exec_session.rs:882] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 hits; the cited field blocks were read contiguously and have no per-field `///` -- d2bd-runtime-p3#9 sev=medium blast=leaf effort=S verdict=actionable - readiness.rs exposes seven undocumented pub predicates/functions (`readiness_predicate_ready`, `unix_socket_exists`, `unix_socket_listening`, `tcp_port_ready`, `wait_for_tcp_port`, `command_ready`, `readiness_predicate_ready_async`) whose contracts are non-obvious (e.g. `unix_socket_listening` parses `/proc/net/unix` flags;`command_ready` strips `NOTIFY_SOCKET`), while `api_socket_info_ready`/`wait_for_readiness_async` do carry `///` - fix: add one-line `///` first sentences + `# Errors` notes on the `Result<_, String>` shapes - [packages/d2bd-runtime/src/readiness.rs:15, packages/d2bd-runtime/src/readiness.rs:78, packages/d2bd-runtime/src/readiness.rs:85, packages/d2bd-runtime/src/readiness.rs:103, packages/d2bd-runtime/src/readiness.rs:112, packages/d2bd-runtime/src/readiness.rs:125, packages/d2bd-runtime/src/readiness.rs:145] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 164 hits; the seven cited fns were read contiguously and have no `///`; seed `-> Result<` = 113 (the String-typed error returns are message-shaped wire slugs, not enum-typed, so `# Errors` sections can name their slugs) -- clean: seed `/// # (Examples|Errors|Panics|Safety)` = 0 in lane; no pub item needs a doctest/canonical section beyond the `# Errors`-naming noted above (this crate's contract docs live in module/dossier prose, consistent with repo convention) - -## perf -- clean: seeds ran: 59/52/27; the `format!` hits are error-path diagnostics (cold), the metrics renderer's `push_str(&format!)...))`-built exposition, and test fixtures (per U1 the wire-artifact/String-building class is excluded);`Vec::new()`/`BTreeMap::new()` hits are empty-value constructors or test fakes (empty case common);`to_string()` hits duplicate the own-lens borrow finding (d2bd-runtime-p3#2) or are error-context copies; no hot path with an unbounded allocation was identified (static (unmeasured) assessment only) - -## conc -- d2bd-runtime-p3#10 sev=medium blast=leaf effort=M verdict=policy-confirmed - unsafe_local_helper.rs uses `parking_lot::Mutex` for its registry/connection/ledger state (`use parking_lot::Mutex` + 4 `Mutex<...>` field types + 39 `.lock()` call sites), which the repo bans outright outside the R4 dedicated bounded-worker boundary - fix: replace with `tokio::sync::Mutex` reached through the documented blocking-seat patterns this crate already uses (`metrics::Registry::blocking_lock` for worker-thread-only seats, `authority_persistence::lock_sync` try_lock spin where an ambient runtime may exist) - [packages/d2bd-runtime/src/unsafe_local_helper.rs:17, packages/d2bd-runtime/Cargo.toml:34] - evidence: seed `\bMutex<|\bRwLock<` = 27 hits; parking_lot import at unsafe_local_helper.rs:17 and dep at Cargo.toml:34; policy: clippy.toml:40-43 bans parking_lot outright (KD3; single R4 exception, not this site)and clippy.toml:82-84 names `tokio::sync::Mutex::lock` as the replacement -- clean: remaining conc seeds: `std::thread::` = 13 (dedicated daemon/helper handler threads with documented ownership, plus test threads), `Atomic\w+|Ordering::` = 97 (paired Acquire/Release, AcqRel idempotency guards, Relaxed counters - weakest-correct orderings), `thread_local!|unsafe impl (Send|Sync) for` = 0 - -## async -- clean: seeds ran: 260/10/27/14; the async code is well-disciplined:dedicated current-thread runtime per session worker (documented concurrency contract), long-polls spawned onto it so fast control ops never head-of-line block, `tokio::sync::Mutex` guards are scoped or lazily-dropped before awaiting (`prove_claim` clones the Arc out of the guard first), blocking seats are the sanctioned `blocking_lock`/`try_lock`-spin patterns renamed in code comments (plan U17), and the sync-only readiness fns carry `#[allow)..., reason = "synchronous path")]` and are pinned for d2bd's worker-thread callers - -## unsafe -- clean: seeds ran: 0/0/2/0; the two `from_raw` hits are `rustix::process::Pid::from_raw`, a safe constructor, not a UB hazard; no `unsafe` block/fn/impl, no `// SAFETY:` comment, and no raw-pointer `from_raw`/`transmute`/`MaybeUninit` exists in this lane's scope - nothing to justify or doc-inspect (the crate inherits the workspace `unsafe_code = "forbid"` posture) - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, no `catch_unwind`, no `repr(C)`/`repr(transparent)`, no C string/char types - this part crosses no foreign-caller boundary;`nip`/`rustix` syscall wrappers only) - -## macro -- N/A (seeds: 0 all zero; no `macro_rules!` definitions or proc-macro/syn/quote usage in the lane scope; std invariants like `cmsg_space!` are external-crate macros, not this crate's) - -## test -- clean: seeds ran: 125/293/0/0; the suite is hermetic and behavior-focused:all fakes/fixtures injected (fake clock, fake driver, fake connector, fake source), no network/no real timeouts beyond bounded local sleeps, error behavior asserted via `matches!)...Error::Variant)` not Display strings; `runtime_boundary.rs` pins the crate's dependency discipline, `#[should_panic]` on an internal-invariant check, and no `#[ignore]`/flaky gates exist - -## Coverage -- idiom: 1 finding(s) -- own: 1 finding(s) -- type: clean (seeds ran: 1/0/0; single hit is a test fn name, not a validation predicate; no flag-soup/Option-pair/string-state invariant class) -- api: 1 finding(s) -- err: 1 finding(s) -- serde: clean (seeds ran: 1/0/0/13; single serde type is an internal-tag Status enum pinned by envelope tests; all serde_json boundary errors mapped to typed errors) -- obs: 2 finding(s) -- docs: 3 finding(s) -- perf: clean (seeds ran: 59/52/27; format!/collection/to_string hits are error paths, bounded renderers, wire artifact builders, or test fixtures - no hot-path allocation) -- conc: 1 finding(s) -- async: clean (seeds ran: 260/10/27/14; spawn/await/lock discipline matches the documented concurrency contract; blocking seats sanctioned with `"synchronous path"` allows and plan U17 comments) -- unsafe: clean (seeds ran: 0/0/2/0; the 2 hits are safe `rustix::process::Pid::from_raw` constructors - no unsafe code in scope) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI boundary in this part) -- macro: N/A (seeds: 0 all zero; no macro definitions in this part) -- test: clean (seeds ran: 125/293/0/0; hermetic, injected, variant-asserting suite with no ignored tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md deleted file mode 100644 index 0929ddfe4..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/d2bd-runtime-p4.md +++ /dev/null @@ -1,112 +0,0 @@ -# d2bd-runtime-p4 - d2bd-runtime - part 4/4 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 10729 (excl. src/generated/**) | modules: target_runtime, daemon_audit, guest_mode, kernel_module_check, console_session, guest_component_session, ch_stats, concurrency, daemon_version, ch_api, typed_shell_targets, wire_response_helpers, exec_support -Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: part 4/4 - the 13 whole-file units listed in U1 section (f); no item-range splits - -## idiom -- d2bd-runtime-p4#1 sev=low blast=leaf effort=S verdict=actionable - `monotonic_tick()` is duplicated verbatim in guest_mode.rs and guest_component_session.rs (identical `OnceLock` elapsed-millis helper, two copies of the same code) - fix: move one `monotonic_tick()` into `crate::runtime_util` and have both modules call it - [packages/d2bd-runtime/src/guest_mode.rs:849, packages/d2bd-runtime/src/guest_component_session.rs:587] - evidence: census: pattern `fn monotonic_tick` over packages/d2bd-runtime/src = 2 hits (both definitions, same body) -- d2bd-runtime-p4#2 sev=low blast=leaf effort=S verdict=actionable - `impl Default for ConsoleSessionTable` hand-writes what `#[derive(Default)]` produces field-wise (all three HashMap fields are Default) - fix: replace the impl with `#[derive(Default)]` on `ConsoleSessionTable` and delete the manual `default()` - [packages/d2bd-runtime/src/console_session.rs:162] - evidence: idiom seed 2 (`impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for`) = 3 hits; the other two Defaults (ConsoleRing:82, ConsoleClientHandle:132) are invariant-preserving/panicking and correctly hand-written -- clean: idiom seeds 1/2/3 = 4/3/12 hits; seed 1 loops are side-effecting test fills, seed 3 accumulations all have early returns or byte-buffer shapes where a collect would obscure control flow - sampled: 50 of 19 hits (all 19 read in full context) - -## own -- d2bd-runtime-p4#3 sev=low blast=leaf effort=S verdict=actionable - `ConsoleSessionTable` lookups allocate a `String` on every call (`ConsoleClientHandle(session_handle.to_owned())` in five methods) because the map key newtype does not implement `Borrow` - fix: implement `Borrow` for `ConsoleClientHandle` (or key the two maps by `String`) so `self.clients.get(session_handle)` resolves without allocation - [packages/d2bd-runtime/src/console_session.rs:250, packages/d2bd-runtime/src/console_session.rs:268, packages/d2bd-runtime/src/console_session.rs:293, packages/d2bd-runtime/src/console_session.rs:304, packages/d2bd-runtime/src/console_session.rs:318] - evidence: own seed 2 (`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`) = 188 hits; the 5 named sites are the only per-call handle-construction allocations outside tests -- d2bd-runtime-p4#4 sev=low blast=leaf effort=S verdict=actionable - every audit write clones the whole `DaemonEvent` (strings included) in `enqueue` because the write API takes `&DaemonEvent`, while every caller (d2bd composition.rs:19356, tests) constructs the event solely to write it - fix: change `write_event`/`write_event_with_authority`/`write_event_async`/`write_event_with_authority_async` to take `DaemonEvent` by value and drop the `event: event.clone()` in `enqueue` - [packages/d2bd-runtime/src/daemon_audit.rs:976, packages/d2bd-runtime/src/daemon_audit.rs:1003] - evidence: own seed 1 (`\.clone\(\)`) = 124 hits; site-specific (the only per-write event clone; all other clones inspected are required by map keys, closure `'static` bounds, or shared ownership) -- clean: own seeds 1/2/3/4 = 124/188/17/0 hits; Arc clones sit at spawn/closure boundaries, key clones are required by BTreeMap/HashMap ownership, `Arc` state is genuinely shared (ServerState, ring, op locks) - sampled: 50 of 329 hits (deterministic every-7th; all files read in full or in hit neighborhoods) - -## type -- d2bd-runtime-p4#5 sev=medium blast=family effort=S verdict=actionable - `DaemonEvent::ApiReadyTimeout.mode: String` models a closed two-value state (`"strict"` | `"no-wait-api"`, documented at daemon_audit.rs:193) as an open string, so an invalid mode is representable and would land in the preserved audit record - fix: introduce a two-variant `SplitReadinessMode`-style enum with `#[serde(rename_all = "kebab-case")]` and use it for the field; serialized bytes stay `"strict"`/`"no-wait-api"` so the daemon-events JSONL shape is unchanged - [packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361] - evidence: type seed 3 (`(mode|kind|state): String`) = 14 hits; the other hits are wire-mirroring fields (daemon_audit.rs:734-744 bounded error-kind tokens, ch_stats.rs:58 CH-API state) that are deliberate -- d2bd-runtime-p4#6 sev=medium blast=family effort=S verdict=actionable - `retarget_mutating_response` and `response_outcome` re-derive the wire outcome as strings (`Some("applied")`, `Some("broker-error")`, `Some("api-ready-timeout")`) although the same file already builds responses from the `MutatingVerbOutcome` enum, forcing every caller into string matching (8 sites in d2bd composition.rs) - fix: add a typed accessor that parses `outcome` into `MutatingVerbOutcome` (serde) and match on the enum variants in `retarget_mutating_response`, keeping the `_` pass-through for unknown broker outcomes - [packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_response_helpers.rs:118] - evidence: type seed 3 = 14 hits; census: pattern `response_outcome` over packages = 8 hits (5 string-comparison call sites in packages/d2bd/src/composition.rs:6879,6918,19883,19891,19918) -- d2bd-runtime-p4#7 sev=low blast=leaf effort=S verdict=actionable - the typed-shell target key `(u32, String)` (uid + shell name) is a bare tuple repeated across three collections and every public method signature, so uid/name swap is a type error waiting to happen - fix: extract `TypedShellTargetKey { uid: u32, name: String }` (derive Ord) and use it in `entries`/`recency`/`create_reservations` and the `remember`/`cached`/`forget`/`reserve` signatures - [packages/d2bd-runtime/src/typed_shell_targets.rs:13, packages/d2bd-runtime/src/typed_shell_targets.rs:82] - evidence: census: pattern `(u32, String)` over packages/d2bd-runtime/src/typed_shell_targets.rs = 21 hits (field types, signatures, test literals) - -## api -- d2bd-runtime-p4#8 sev=low blast=leaf effort=S verdict=actionable - `ConsoleClientHandle(pub String)` exposes the inner token of a type documented as "Opaque per-client session token", so any caller can fabricate handles and the opacity claim is unenforced - fix: make the field private, add `FromStr`/`as_str`, and route the table's own lookups through them - [packages/d2bd-runtime/src/console_session.rs:118] - evidence: api seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) = 333 hits (surface enumerated via structural summaries); site-specific -- d2bd-runtime-p4#9 sev=low blast=leaf effort=S verdict=actionable - `spawn_ch_serial_drainer(_vm: String, ...)` takes an unused `_vm` parameter, and its only caller allocates a hardcoded `"ch-console".to_owned()` per session to satisfy it - fix: drop the parameter and the call-site allocation in `create_ch_session` - [packages/d2bd-runtime/src/console_session.rs:341, packages/d2bd-runtime/src/console_session.rs:422] - evidence: census: pattern `spawn_ch_serial_drainer` over packages = 2 hits (definition + the single call at console_session.rs:422) -- d2bd-runtime-p4#10 sev=low blast=leaf effort=S verdict=actionable - `DrainerSource` is a dead public enum: never constructed anywhere, with a `#[allow(dead_code)]` `Connected` variant carrying a tokio stream - fix: delete the enum (and the allow) - [packages/d2bd-runtime/src/console_session.rs:54] - evidence: census: pattern `DrainerSource` over packages = 1 hit (the definition itself; zero constructions or matches) -- d2bd-runtime-p4#11 sev=low blast=leaf effort=M verdict=actionable - `ConsoleRing` and `ConsoleSession` expose all fields `pub` (`ring: RingBuffer`, `notify`, `drainer`, `stdin_tx`), so the documented invariant "notify fires whenever bytes are pushed or EOF is set" (console_session.rs:68) is convention-only: an external caller can push bytes without notifying and waiters hang - fix: make the fields private and expose `push_bytes`/`set_eof`/`read_at` on `ConsoleRing` and accessors on `ConsoleSession` that notify internally - [packages/d2bd-runtime/src/console_session.rs:66, packages/d2bd-runtime/src/console_session.rs:90] - evidence: api seed 1 = 333 hits; site-specific (the two structs' field lists read in full) -- clean: api seeds 1/2/3 = 333/0/0 hits; the wide `pub mod` surface is the crate's internal-daemon contract (d2bd and d2b-provider-guest are the only consumers); no `Arc`/`Rc`/`Box`/`RefCell` in public signatures beyond the genuine shared-ownership `driver()` handle - sampled: 50 of 333 hits (surface enumerated via lib.rs re-export list + per-file structural summaries) - -## err -- d2bd-runtime-p4#12 sev=low blast=leaf effort=S verdict=actionable - `impl Default for ConsoleClientHandle` panics via `expect("console handle entropy unavailable")` when entropy fails, and nothing in the workspace calls `ConsoleClientHandle::default()` - fix: delete the Default impl (the type already has a fallible `new()` used at attach) - [packages/d2bd-runtime/src/console_session.rs:132] - evidence: err seed 1 (`\.unwrap\(\)|\.expect\(`) = 295 hits; census: pattern `ConsoleClientHandle::default` over packages = 0 hits; every other non-test unwrap/expect site in the lane is on a literally-built constant, a validated fingerprint, or a startup runtime build (card false-positive classes) -- d2bd-runtime-p4#13 sev=low blast=leaf effort=S verdict=actionable - `FilesystemReader` reports failures as `Result<..., String>`, so `compute_restart_status` cannot distinguish "file missing" from "file unreadable" without string inspection and the detail is only embeddable in a banner - fix: introduce a small `VersionFileReadError` enum (e.g. `Missing` vs `Unreadable(String)`) returned by both trait methods - [packages/d2bd-runtime/src/daemon_version.rs:77, packages/d2bd-runtime/src/daemon_version.rs:85] - evidence: err seed 4 (`enum \w*Error`) = 14 hits (all other error enums in the lane are closed, Display-bearing, wire-label taxonomies) -- clean: err seeds 1/2/3/4 = 295/14/0/14 hits; panic policy is sound outside tests - every remaining expect is a justified invariant (validated fingerprints, literal constants, map keys collected from the same map, runtime startup); swallowed results are deliberate best-effort cleanup or oneshot replies whose failure is the refusal signal - sampled: 50 of 295 hits (all non-test unwrap/expect sites read in context) - -## serde -- d2bd-runtime-p4#14 sev=low blast=leaf effort=S verdict=actionable - `parse_vm_info` hand-walks `serde_json::Value` with `and_then` chains to extract `state`/`boot_vcpus`/`memory.size` from the Cloud Hypervisor vm.info payload, re-implementing what a derived raw shape does at the boundary - fix: derive `Deserialize` on a raw `ChVmInfoRaw` with `#[serde(default)]` on every field (nested `config.cpus.boot_vcpus` / `config.memory.size`) and convert to `ChVmInfo` - [packages/d2bd-runtime/src/ch_api.rs:79] - evidence: serde seeds 1/2/3/4 = 22/13/0/46 hits; site-specific (the only Value-walking parse in the lane) -- clean: serde seeds 1/2/3/4 = 22/13/0/46 hits; `DaemonVersionFile`/`DaemonRestartStatus`/`GuestComponentSessionDescriptor` use `deny_unknown_fields` + `rename_all` + internal tagging correctly; the hand-written `Serialize for DaemonEvent` is a deliberate redaction admission gate (sanitize_daemon_event), not a derive candidate - -## obs -- d2bd-runtime-p4#15 sev=low blast=leaf effort=S verdict=actionable - `tracing::warn!("qemu console: failed to convert fd to tokio stream: {e}")` interpolates the error into the message instead of a named field, so the event is not queryable by error - fix: `tracing::warn!(error = %e, "qemu console: failed to convert fd to tokio stream")` - [packages/d2bd-runtime/src/console_session.rs:450] - evidence: obs seed 2 (`(info|debug|warn|error|trace)!\("`) = 7 hits; the other 6 events use named fields (daemon_audit.rs:892, kernel_module_check.rs:417, console_session.rs:402, guest_component_session.rs:322,342) or are doc prose -- clean: obs seeds 1/2/3/4 = 0/7/0/5 hits; zero println/eprintln, zero `instrument` spans (context comes from enclosing daemon spans), no secret-bearing fields found in any event - -## docs -- d2bd-runtime-p4#16 sev=low blast=leaf effort=S verdict=actionable - `wire_response_helpers.rs` ships 11 undocumented `pub fn`s (the module doc is the only prose), including `retarget_mutating_response` whose pass-through-on-unknown-outcome behavior is load-bearing for broker-forwarded responses - fix: add one-line contract docs per fn, naming the pass-through semantics and the wire fields projected - [packages/d2bd-runtime/src/wire_response_helpers.rs:7, packages/d2bd-runtime/src/wire_response_helpers.rs:118] - evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) = 393 hits; the file's pub surface enumerated in full (11 fns, zero doc comments) -- d2bd-runtime-p4#17 sev=low blast=leaf effort=S verdict=actionable - `ch_api.rs` leaves its public constants, error enum, info struct, and async entry points undocumented: `DEFAULT_TIMEOUT`/`MAX_RESPONSE_BYTES` are magic values without the why (contrast `CH_HTTP_TIMEOUT` at ch_stats.rs:120 which cites the legacy exporter), and `ChApiError` variants/`ChVmInfo` fields/`get_vm_info`/`shutdown_vm` have no docs - fix: document the consts with their provenance and add one-line docs to the enum, struct, and fns - [packages/d2bd-runtime/src/ch_api.rs:11, packages/d2bd-runtime/src/ch_api.rs:15, packages/d2bd-runtime/src/ch_api.rs:37, packages/d2bd-runtime/src/ch_api.rs:43] - evidence: docs seed 1 = 393 hits; site enumerated in full (ch_api.rs read whole) -- d2bd-runtime-p4#18 sev=low blast=leaf effort=S verdict=actionable - `target_runtime.rs` documents its domain types thoroughly but leaves a cluster of pub accessors undocumented: `AdmissionBudget::new/limits/active`, `AdmissionPermit::kind/release`, `ProviderDeployment::mode/target_kind/admission` - fix: add one-line docs (at minimum to `AdmissionPermit::release`, whose idempotence is a caller-relevant contract) - [packages/d2bd-runtime/src/target_runtime.rs:256, packages/d2bd-runtime/src/target_runtime.rs:311, packages/d2bd-runtime/src/target_runtime.rs:354, packages/d2bd-runtime/src/target_runtime.rs:1108] - evidence: docs seed 1 = 393 hits; sites verified by direct read (no `///` on the named methods) -- clean: docs seeds 1/2/3 = 393/0/393 hits; the lane's domain types (DaemonEvent, GuestIdentity, ModuleCheckReport, DaemonVersionFile, OpLockManager, leases) carry contract-grade docs with first-sentence shape; `# Errors`/`# Examples` sections are absent crate-wide (consistent prose style, not a per-item gap) - sampled: 50 of 393 hits (pub surface enumerated via structural summaries of all 13 files) - -## perf -- clean: perf seeds 1/2/3 = 61/27/2 hits; every `format!` site is cold (error diagnostics, audit rendering, one-shot startup) or the artifact IS text (ch_stats Prometheus block, daemon_version banner); `Vec::new()` sites are empty-case-common or bounded buffers; `read_async_capped`/`read_blocking_capped` already use `with_capacity`; no hot-path allocation or bounds-check class found - -## conc -- d2bd-runtime-p4#19 sev=medium blast=leaf effort=M verdict=policy-confirmed - `OpLockManager::acquire` busy-spins (`try_lock` + `std::hint::spin_loop()`) while the per-VM/global lock is held across a whole lifecycle op (composition.rs:5612 holds the guard across `dispatch_request_locked`, i.e. seconds for a VM start), so a concurrent same-VM or global request burns a full core for the op duration; the doc's "critical sections are single map ops" justification covers only the map-entry lock, not the held op lock - fix: replace the spin with the repo's sanctioned wait-on-condition shape (`tokio::sync::Notify` armed before the check + `tokio::time::timeout`, clippy.toml:37-39) or park/wake on the dedicated dispatch threads; requires a policy/ADR decision first - [packages/d2bd-runtime/src/concurrency.rs:163, packages/d2bd-runtime/src/concurrency.rs:189, packages/d2bd/src/composition.rs:5612] - evidence: conc seeds 1/2/3/4 = 26/28/45/0 hits; site read in full; static (unmeasured) - no benchmark exists for contended op throughput -- clean: conc seeds 1/2/3/4 = 26/28/45/0 hits; `ConnSemaphore` CAS uses the weakest correct orderings (Acquire/AcqRel), `HEALTHCHECK_COUNTER` is a Relaxed counter, the audit appender and connect-probe worker are dedicated bounded threads (R4 shape), no `unsafe impl Send/Sync`, no `thread_local!`/`static mut` - -## async -- d2bd-runtime-p4#20 sev=low blast=family effort=M verdict=actionable - `CONSOLE_DRAINER_RUNTIME` is a `static OnceLock` started inside library code (console_session.rs:33-44), giving the daemon a second multi-thread runtime per process that is never shut down, while the binary already owns a `#[tokio::main(flavor = "multi_thread")]` runtime (d2bd/src/main.rs:142) - fix: own the runtime at the binary top and pass a `tokio::runtime::Handle` into `create_ch_session`/`create_qemu_session` (or spawn drainers on the daemon runtime) instead of a crate-static `OnceLock` - [packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session.rs:35] - evidence: async seed 4 (`#\[tokio::(main|test)\]|Runtime::block_on`) = 4 hits; census: pattern `tokio::main` over packages/d2bd/src/main.rs = 1 hit (line 142); no async-gate-allow marker covers the drainer runtime (grep over packages/xtask/data/async-gate-inventory.json = 0 hits) -- clean: async seeds 1/2/3/4 = 47/8/22/4 hits; no guard is held across an await (ring guards are dropped before `notify_waiters()`), the async audit seat awaits a oneshot reply, `run_connect_probe` never parks the caller's executor, and the `#[tokio::test]` sites are plain harnesses - -## unsafe -- clean: unsafe seeds 1/2/3/4 = 0/0/1/0 hits; the single hit is doc prose (`from_raw_fd` mentioned in the `create_qemu_session` doc at console_session.rs:435, same false-positive class recorded in U1 (d)8 for typed_error.rs); zero unsafe blocks/fns/impls, zero SAFETY comments, zero transmute/MaybeUninit/zeroed in the lane - -## ffi -- N/A: ffi seeds 1/2/3/4 = 0/0/0/0 all zero; the lane crosses no foreign-language boundary (no extern, no repr(C), no CStr/CString, no catch_unwind) - -## macro -- N/A: macro seeds 1/2/3/4 = 0/0/0/0 all zero; no macro_rules!, no proc-macro/syn/quote, no $crate, no trybuild machinery in the lane - -## test -- d2bd-runtime-p4#21 sev=low blast=leaf effort=S verdict=actionable - `no_op_does_not_write_file` cannot fail on the behavior it names: the temp dir is never connected to the log (`DaemonAuditLog::no_op()` has no state dir; the comment at daemon_audit.rs:2368 admits the limitation), so `count == 0` is vacuously true and only the write-does-not-error `expect` is exercised - fix: make the state dir injectable (or test via a log constructed with a read-only/blocked state dir) so the no-file-created claim is actually asserted, or rename the test to what it verifies - [packages/d2bd-runtime/src/daemon_audit.rs:2367] - evidence: test seeds 1/2/3/4 = 75/317/0/0 hits (src + tests/runtime_boundary.rs); site read in full -- clean: test seeds 1/2/3/4 = 75/317/0/0 hits; the suite is behavior-asserting and deterministic - leak-safety sentinels with closed key-set assertions (daemon_audit), timing-free concurrency tests via barriers/channels (concurrency), table-driven parse cases (ch_api, kernel_module_check), zero `#[ignore]`, zero proptest/insta/rstest (plain unit + integration tests fit the assertions) - sampled: 50 of 392 hits (test bodies read via full-file reads of the smaller modules and hit neighborhoods of the two large files) - -## Coverage -- idiom: 2 finding(s) -- own: 2 finding(s) -- type: 3 finding(s) -- api: 4 finding(s) -- err: 2 finding(s) -- serde: 1 finding(s) -- obs: 1 finding(s) -- docs: 3 finding(s) -- perf: clean (seeds ran: 61/27/2) -- conc: 1 finding(s) -- async: 1 finding(s) -- unsafe: clean (seeds ran: 0/0/1/0) -- ffi: N/A (seeds: 0/0/0/0 all zero; no foreign boundary in the lane) -- macro: N/A (seeds: 0/0/0/0 all zero; no macro definitions or proc-macro machinery) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md deleted file mode 100644 index a46968443..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-1.md +++ /dev/null @@ -1,333 +0,0 @@ -# tail-1 - tail lane -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1113 (src + tests, excl. src/generated/** and integration/) | modules: d2b-broker-fixture-handlers, d2b-broker-fixture-syscall-surface, d2b-controller-toolkit, d2b-host-activation-helper, d2b-provider-audio-binding -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates - -## d2b-broker-fixture-handlers - -### idiom -- clean: seeds 0/0/0 (no index loops, no hand-written impls, no statement-style accumulation); the crate is one pure echo fn and reads idiomatic. - -### own -- clean: seeds 1/0/0/0; the single `.clone()` at lib.rs:21 copies the borrowed `payload: &CanonicalJsonObject` into the owned `DispatchOutcome.result` - the echo must own its result, so the clone is required (census: payload type at packages/d2b-broker/src/envelope/mod.rs:974; result type at :904). - -### type -- N/A: seeds 0/0/0 all zero; the crate declares no struct or enum (card criterion). - -### api -- clean: seeds 1/0/0; one pub fn (`echo`) documented and deliberately exported for the composition seam (census: registered as handler at packages/d2b-broker-composition/src/seam.rs:339, 538). - -### err -- clean: seeds 0/0/0/0; no panic sites, no swallowed Results; the fn returns the seam's `Result`. - -### serde -- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire. - -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). - -### docs -- clean: seeds 1/0/0; the single pub fn carries a one-line contract doc and the module has `//!` docs. - -### perf -- clean: seeds 0/1/0; the one `Vec::new()` (lib.rs:22) builds the empty fds list - the empty case is common, false-positive class. - -### conc -- N/A: seeds 0/0/0/0 all zero. - -### async -- clean: seeds 1/0/0/0; one `Box::pin(async move ...)` with no `.await`, no spawn, no shared state, no blocking - a single immediate future. - -### unsafe -- N/A: seeds 0/0/0/2; seeds 1-3 all zero - the two `unsafe_code` hits are the `#![deny(unsafe_code)]` attribute (lib.rs:13) and the manifest `deny` (Cargo.toml:9); no unsafe code exists. - -### ffi -- N/A: seeds 0/0/0/0 all zero. - -### macro -- N/A: seeds 0/0/0/0 all zero. - -### test -- N/A: seeds 0/0/0/0 all zero; the crate ships no tests (the seam exercises it from d2b-broker-composition). - -### Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 1/0/0/0) -- type: N/A (seeds: 0/0/0 all zero; no struct/enum declared) -- api: clean (seeds ran: 1/0/0) -- err: clean (seeds ran: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds ran: 1/0/0) -- perf: clean (seeds ran: 0/1/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: clean (seeds ran: 1/0/0/0) -- unsafe: N/A (seeds: 0/0/0/2; seeds 1-3 all zero, only the deny attribute/manifest text) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: N/A (seeds: 0/0/0/0 all zero; no tests) - -## d2b-broker-fixture-syscall-surface - -### idiom -- clean: seeds 0/0/0; two small fns and a static, no expression-shape issues. - -### own -- clean: seeds 0/0/0/0; no clones or shared-ownership types. - -### type -- N/A: seeds 0/0/0 all zero; the crate declares no struct or enum (card criterion). - -### api -- clean: seeds 3/0/0; three pub fns are the deliberate hostile surface the dependency-surface audit scans (census: audit probes at packages/d2b-broker-composition/src/dependency_surface.rs:436-471; refusal tests at seam.rs:612-638); the `FIXTURE_MARKER` static is private. - -### err -- clean: seeds 0/0/0/0; no panic sites; `install_isolation_silencer`'s panic-hook set is the deliberate audit target, not a panic policy issue. - -### serde -- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire. - -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). - -### docs -- clean: seeds 3/0/0; all three pub fns carry contract docs including the fixture rationale. - -### perf -- N/A: seeds 0/0/0 all zero. - -### conc -- N/A: seeds 0/0/0/0 all zero. - -### async -- N/A: seeds 0/0/0/0 all zero. - -### unsafe -- tail-1#1 sev=medium blast=leaf effort=S verdict=actionable - the x86_64 `asm!` block omits the registers the `syscall` instruction clobbers (rcx and r11), so the compiler's no-clobber assumption is violated if the fn is ever executed - fix: add `lateout("rcx") _`, `lateout("r11") _` (or `clobber_abi("C")`) to the asm operands at lib.rs:26-32 - [packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32] - evidence: seed `\bunsafe \{` = 2 hits, `// SAFETY:` = 2; static read of the asm block (no reachability path: the crate is a dev-dependency of the composition root only, never linked into the broker binary - packages/d2b-broker-composition/Cargo.toml:16-18, and none of the fns are ever called) -- clean: both unsafe blocks carry `// SAFETY:` comments (lib.rs:23-24, 40); the `#[unsafe(link_section)]` attribute and panic-hook registration are the deliberate fixture surface the audit must reject (U1 card false-positive class), not re-flagged. - -### ffi -- clean: seeds 1/0/0/0; the single hit is the `#[unsafe(link_section)]` marker - a link-time attribute, not a foreign-caller boundary (no extern "C", no repr, no CStr); deliberately hostile fixture surface. - -### macro -- N/A: seeds 0/0/0/0 all zero. - -### test -- N/A: seeds 0/0/0/0 all zero; no tests (the audit probes it from d2b-broker-composition). - -### Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 0/0/0/0) -- type: N/A (seeds: 0/0/0 all zero; no struct/enum declared) -- api: clean (seeds ran: 3/0/0) -- err: clean (seeds ran: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds ran: 3/0/0) -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: 1 finding -- ffi: clean (seeds ran: 1/0/0/0) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: N/A (seeds: 0/0/0/0 all zero; no tests) - -## d2b-controller-toolkit - -### idiom -- clean: seeds 0/3/0; the three hand-written `Debug` impls (context.rs:92, 125, contract.rs:35) are the deliberate-redaction class (canonical_json shown as byte count, ResourceKey prints structural constants) - a derive would leak, recorded false-positive class. - -### own -- clean: seeds 0/0/0/0; no clones, no refcounts, no Cow; accessors borrow. - -### type -- tail-1#2 sev=low blast=family effort=S verdict=actionable - `ResourceSnapshot` carries `owner_uid: Option` and `owner_generation: Option` that are only ever set together, leaving the illegal one-Some/one-None combination constructible - fix: introduce `OwnerIdentity { uid, generation }` and replace the pair with a single `Option` (fields context.rs:17-18, constructor :61-67; the only external setter call passes both Some - packages/d2b-provider-provider/src/driver.rs:559) - [packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/context.rs:61-67] - evidence: seeds 0/0/0 (lens applicable via the declared structs); census: `with_owner_identity` over packages/ = 1 call site (d2b-provider-provider/src/driver.rs:559, both Some) + definition; owner_generation() has no external consumers -- clean: no validate/check fns, no boolean-flag fields, no stringly-typed state; the single `deleting: bool` is a lone flag with no soup. - -### api -- clean: seeds 18/0/2; the `pub use` re-export arms (lib.rs:11-12) are the house single-surface pattern; no Arc/Rc/Box/RefCell in signatures; all three exported types are consumed (census: d2b-core-controller/src/lib.rs:52 re-exports them; d2b-provider-provider/src/driver.rs:52-53, providers.rs:8 use them). - -### err -- clean: seeds 0/0/0/0; no panic sites, no swallowed Results, no error enum (the crate's constructors cannot fail). - -### serde -- N/A: seeds 0/0/0/0 all zero; the snapshots are in-memory types (no serde derives), no wire. - -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). - -### docs -- clean: seeds 18/0/0; every pub item carries a one-line contract doc; no Result returns so no `# Errors` sections are owed. - -### perf -- N/A: seeds 0/0/0 all zero. - -### conc -- N/A: seeds 0/0/0/0 all zero. - -### async -- N/A: seeds 0/0/0/0 all zero. - -### unsafe -- N/A: seeds 0/0/0/0 all zero; the manifest's `[lints] workspace = true` reference carries no `unsafe_code` text (seed 4 zero too). - -### ffi -- N/A: seeds 0/0/0/0 all zero. - -### macro -- N/A: seeds 0/0/0/0 all zero. - -### test -- N/A: seeds 0/0/0/0 all zero; no tests and an empty dev-dependencies table (Cargo.toml:16). - -### Coverage -- idiom: clean (seeds ran: 0/3/0) -- own: clean (seeds ran: 0/0/0/0) -- type: 1 finding -- api: clean (seeds ran: 18/0/2) -- err: clean (seeds ran: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds ran: 18/0/0) -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero; workspace lints reference) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: N/A (seeds: 0/0/0/0 all zero; no tests) - -## d2b-host-activation-helper - -### idiom -- clean: seeds 0/0/0; no index loops, no hand-written impls, no statement-style accumulation; the arg-parsing match is idiomatic. - -### own -- clean: seeds 0/1/0/0; the single `.to_string()` (main.rs:69) builds a cold error string; no clones or refcounts anywhere. - -### type -- clean: seeds 0/0/0; the `Config` struct's lone `fail_closed: bool` is a single flag with no soup; gid parsing is checked at the boundary (`parse_gid` returns Result). - -### api -- N/A: seeds 0/0/0 all zero; bin-only crate with no lib target and no pub items (card criterion). - -### err -- clean: seeds 0/0/0/0 in production code; `main` uses `unwrap_or_else` (main.rs:341) and exits with codes; the only `.expect()` hits are in `#[cfg(test)]` (false-positive class). - -### serde -- N/A: seeds 0/0/0/0 all zero; the crate crosses no wire. - -### obs -- clean: seeds 7/0/0/0; all seven `eprintln!` sites are CLI product output (usage, error reporting, migration audit lines) per the card's CLI false-positive class; no tracing/log dependency. - -### docs -- N/A: seeds 0/0/11; seed 1 zero - no public items exist in the bin crate (card: never add missing_docs to a binary crate); the 11 `-> Result<` hits are internal fns. - -### perf -- clean: seeds 5/0/1; all `format!` sites are cold paths (usage text, arg errors, one log line per migrated entry); no hot-loop allocation. - -### conc -- N/A: seeds 0/0/0/0 all zero; single-threaded walk. - -### async -- N/A: seeds 0/0/0/0 all zero. - -### unsafe -- tail-1#3 sev=medium blast=leaf effort=S verdict=actionable - 22 production `unsafe` blocks (libc calls plus `errno_clear`'s `__errno_location` write) carry no `// SAFETY:` comment, violating the skill's mechanical rule and U1 (d) 8 - fix: add a `// SAFETY:` comment to each block stating the invariant (CString NUL-termination, checked return before use, fd ownership) - [packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/src/main.rs:129, packages/d2b-host-activation-helper/src/main.rs:140, packages/d2b-host-activation-helper/src/main.rs:194, packages/d2b-host-activation-helper/src/main.rs:213, packages/d2b-host-activation-helper/src/main.rs:271] - evidence: seed `\bunsafe \{` = 24 hits (22 production + 2 cfg(test)), `// SAFETY:` = 0, `MaybeUninit` = 2; U1 (d) 8 mechanical rule (a block without a SAFETY comment is a finding) -- tail-1#4 sev=high blast=leaf effort=S verdict=actionable - `walk_dir` leaks the `fdopendir` DIR* handle on every error-path early return: `closedir` runs only on the readdir-null path (main.rs:206), so the `?` at :218, the `return Err` at :222 and :260, and `result?` at :265 all leak the directory stream (route review-pass) - fix: restructure so `closedir` runs on every exit (closure + close after, or an RAII guard) - [packages/d2b-host-activation-helper/src/main.rs:194, packages/d2b-host-activation-helper/src/main.rs:218, packages/d2b-host-activation-helper/src/main.rs:222, packages/d2b-host-activation-helper/src/main.rs:260, packages/d2b-host-activation-helper/src/main.rs:265] - evidence: static read of walk_dir (main.rs:186-268); closedir appears once on the success/end-of-stream path; the four early returns after fdopendir succeed skip it (correctness defect, not UB) -- clean: the libc calls themselves (open/fcntl/fstat/fstatat/dup/fdopendir/readdir/closedir/fchownat/openat/fchown/close) are standard usage with checked returns, `CString` NUL handling, and correct `MaybeUninit` (assume_init only after rc == 0); the two cfg(test) unsafe sites carry policy-tracked sanctioned allows. - -### ffi -- clean: seeds 0/0/0/5; the CStr/CString usage at the libc boundary is correct (NUL-termination via `CString::new` with InvalidInput errors, `CStr::from_ptr` on readdir's NUL-terminated d_name); these are libc-binding call sites that never cross a foreign caller (card false-positive class). - -### macro -- N/A: seeds 0/0/0/0 all zero. - -### test -- clean: seeds 2/5/0/0; two behavioral tests (migration walk + fail-closed rescan, held-lock fail-closed exit) with real tempdir filesystems, deterministic, no `#[ignore]`; each assertion can fail. - -### Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 0/1/0/0) -- type: clean (seeds ran: 0/0/0) -- api: N/A (seeds: 0/0/0 all zero; bin-only crate, no pub items) -- err: clean (seeds ran: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire) -- obs: clean (seeds ran: 7/0/0/0) -- docs: N/A (seeds: 0/0/11; seed 1 zero - no public items; bin-only crate) -- perf: clean (seeds ran: 5/0/1) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: 2 findings -- ffi: clean (seeds ran: 0/0/0/5) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 2/5/0/0) - -## d2b-provider-audio-binding - -### idiom -- clean: seeds 0/1/0; the hand-written `impl Default for AudioBinding` (audio_binding.rs:98) is justified - `Arc` has no field-wise default, and the impl wires the crate's own `BindingChildSource`. - -### own -- clean: seeds 2/1/0/0; the two `.clone()` calls (audio_binding.rs:130) copy `ResourceRef` values into the owned dependencies Vec the trait contract returns; the `to_owned` hit is a test fixture string; `Arc` is genuine shared ownership (behavior shared by driver and factory). - -### type -- clean: seeds 0/0/0; no validate/check fns, no boolean flags, no stringly-typed state; the child-request struct is three plain borrows. - -### api -- clean: seeds 11/2/1; the two `Arc` in public signatures (`AudioBinding::new` at :93, `audio_binding_spec_decoder` at :158) are the interaction-family pattern with genuine shared ownership (call sites: tests/registration.rs:72, descriptor construction at :163-180); the `pub use` arm (lib.rs:16-19) is the house single-surface pattern; the trait has one required method. - -### err -- clean: seeds 0/0/0/0 in src; no unwrap/expect/panic in production code; the `map_err(|_| InteractionEffectError::InvalidResource)` translation is the family port's coarse two-variant vocabulary (interaction.rs:125-130), the same translation the whole family applies - restructuring it is a family-contract change, not a binding-crate defect. - -### serde -- N/A: seeds 0/0/0/0 all zero; src crosses no wire (spec decoding happens through the family's `spec_decoder`); serde_json appears only in tests. - -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency (card criterion). - -### docs -- tail-1#5 sev=low blast=leaf effort=S verdict=actionable - the four Result-returning trait methods (`binding_children`, `validate`, `dependencies`, `desired_children`) lack `# Errors` sections saying which conditions yield `Unavailable` vs `InvalidResource`, even though the crate denies missing_docs - fix: add `# Errors` sections naming the family's two failure variants - [packages/d2b-provider-audio-binding/src/audio_binding.rs:56, packages/d2b-provider-audio-binding/src/audio_binding.rs:117, packages/d2b-provider-audio-binding/src/audio_binding.rs:125, packages/d2b-provider-audio-binding/src/audio_binding.rs:134] - evidence: docs seeds 11/0/4; all four `-> Result<` hits are pub trait methods without `# Errors` sections (the variants are documented only on the family enum, packages/d2b-provider-wayland-policy/src/interaction.rs:124-130) -- clean: every pub item carries a one-line contract doc (missing_docs denied in lib.rs:13); no `# Examples` sections owed where signatures are self-evident. - -### perf -- N/A: seeds 0/0/0 all zero. - -### conc -- N/A: seeds 0/0/0/0 all zero. - -### async -- N/A: seeds 0/0/0/0 all zero in src; the only async fns are the test harness's `async_trait` effect-port stubs (tests/registration.rs:33, 41). - -### unsafe -- N/A: seeds 0/0/0/1; seeds 1-3 all zero - the single `unsafe_code` hit is the manifest `forbid` (Cargo.toml:9), which does not make the lens applicable (card rule). - -### ffi -- N/A: seeds 0/0/0/0 all zero. - -### macro -- N/A: seeds 0/0/0/0 all zero. - -### test -- clean: seeds 5/14/0/0; five behavioral tests (declaration row, registry duplicate refusal, service/target reads, child-row materialization, foreign-row refusal) asserting observable contracts with real assertions; deterministic, no `#[ignore]`, no network. - -### Coverage -- idiom: clean (seeds ran: 0/1/0) -- own: clean (seeds ran: 2/1/0/0) -- type: clean (seeds ran: 0/0/0) -- api: clean (seeds ran: 11/2/1) -- err: clean (seeds ran: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire in src) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: 1 finding -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero in src) -- unsafe: N/A (seeds: 0/0/0/1; seed 4 = manifest forbid only) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 5/14/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md deleted file mode 100644 index 4d6926ce7..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-2.md +++ /dev/null @@ -1,331 +0,0 @@ -# tail-2 - tail lane -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 2457 (excl. src/generated/**) | modules: d2b-provider-audio-service, d2b-provider-command, d2b-provider-device, d2b-provider-emergency-policy, d2b-provider-operation -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates - -## d2b-provider-audio-service - -### idiom -- clean: seeds s1 index loop = 0, s2 `impl (Default|From|...) for` = 0, s3 `let mut ... = String/Vec::new()` = 0; one declaration struct + thin descriptor fns, no hand-written derives, no statement-style accumulation. - -### own -- clean: seeds 1-4 all zero (clone/to_owned/to_vec/to_string, Rc/RefCell/Arc` in `audio_service_spec_decoder` is the required trait-object return. - -### type -- clean: seeds 1-3 all zero (`fn validate_/check_`, `is_x: bool`/`x_flag: bool`, stringly `mode/kind/state`); unit struct `AudioService` carries no state, validation is delegated to the typed spec decode in the family engine. - -### api -- clean: seed 1 pub surface = 8 hits (AUDIO_SERVICE_PROVIDER_REF, AUDIO_SERVICE_RESYNC, AudioService, AudioServiceFactory, audio_service_spec_decoder, audio_service_descriptor, lib.rs re-export arms) - single re-export path, every item documented, no Arc/Rc/Box/RefCell/dependency types in signatures beyond the shared `InteractionDriverArgs` family-engine args (house interaction pattern, `d2b-provider-wayland-policy`). - -### err -- clean: seeds 1-4 all zero outside tests (no unwrap/expect, no panic!/unreachable!/todo!/unimplemented!, no error enum); `validate` returns `Result` and never panics on row input. - -### serde -- N/A: seeds 1-4 all zero (no serde derives, no serde attributes, no hand-written Deserialize, no serde_json calls); the crate crosses no wire of its own - `AudioServiceSpec` decode lives in `d2b-provider-wayland-policy@interaction::spec_decoder`. - -### obs -- N/A: seeds 1-4 all zero (no println!/eprintln!, no no-field message events, no instrument spans, no tracing/log) and Cargo.toml carries no tracing/log dependency. - -### docs -- clean: seed 1 pub items (six) + seed 3 `-> Result<` (three trait methods) = 9 hits, all public items documented under `#![deny(missing_docs)]` in lib.rs; module header explains the family split. - -### perf -- clean: seeds 1-3 = 2 hits (`Ok(Vec::new())` in `dependencies`/`desired_children`) - both are the deliberate empty desired-child set, empty case is the only case. - -### conc -- N/A: seeds 1-4 all zero (no threads, no Mutex/RwLock, no atomics, no thread_local/unsafe Send-Sync). - -### async -- N/A: seeds 1-4 all zero (no async fn, no spawn/select/join, no tokio sync types, no tokio main/test) over src; the registration test is plain `#[test]`. - -### unsafe -- N/A: seeds 1-4 all zero (no unsafe blocks/fns, no SAFETY comments, no transmute/from_raw/MaybeUninit/zeroed) and manifest declares `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds 1-4 all zero (no extern "C"/no_mangle, no catch_unwind, no repr(C)/repr(transparent), no CStr/CString/c_char). - -### macro -- N/A: seeds 1-4 all zero (no macro_rules!, no proc_macro/syn/quote, no `$crate`, no to_compile_error/new_spanned). - -### test -- clean: seeds over src+tests = 17 hits (4 `#[test]`, 13 `assert*`); registration tests pin the declaration, the required Provider selector, duplicate-type refusal, spec decode, and foreign-row refusal - each fails on a concrete regression. - -### Coverage -- idiom: clean (0/0/0) -- own: clean (0/0/0/0) -- type: clean (0/0/0) -- api: clean (8 hits) -- err: clean (0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; crate crosses no wire) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) -- docs: clean (9 hits) -- perf: clean (2 hits; deliberate empty returns) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (17 hits: 4 #[test], 13 asserts) - -## d2b-provider-command - -### idiom -- clean: seeds 1-3 all zero; constructor-style parsing with `if let`/`else` and `strip_prefix`/`strip_suffix` chains reads idiomatic; `format!("{{{name}}}")` is the canonical-brace normalization. - -### own -- clean: seeds 1-4 = 6 hits (3 `.to_owned()` in `JsonSchema::schema_name`/`pattern` at the schemars trait boundary which demands owned values, 2 `.clone()` in `#[cfg(test)]` fixtures, 1 `.to_owned()` in JsonSchema metadata) - every hit is a required ownership transfer at a trait boundary or test fixture, none avoids a borrow. - -### type -- clean: seeds 1-3 all zero; `CommandExec`/`CommandArgvSlot` are parse-once private-field newtypes and `CommandSpec::new` validates cross-field invariants once at construction - the pattern this lens names as the goal. - -### api -- clean: seed 1 pub surface = 27 hits (constants, four newtypes, CommandIntent, CommandSpec, CommandContractError, command_descriptor, `pub use` arms); single re-export path (`pub mod command` + `pub use command::*` is the house spec-vocabulary pattern), fields private with accessors, no Arc/Rc/Box/RefCell or dependency types in signatures. - -### err -- clean: seeds 1-3 = 0 outside tests (all unwrap/expect live in `#[cfg(test)]`), seed 4 error enum = 1 (`CommandContractError`); the four variants split by caller action (exec vs argv vs role vs placeholder), each documented, deserialize failures surface as serde errors, never panics. - -### serde -- tail-2#1 sev=medium blast=leaf effort=S verdict=needs-contract - the emitted JsonSchema for `CommandExec` (`pattern: "^/[^\\u0000]*$"`) and `CommandArgvSlot` (no pattern) is weaker than the parse admission (rejects control chars/empty/malformed braces/invalid placeholder names), so a value satisfying the published schema can be refused at serde deserialization - fix: tighten the `CommandExec` pattern to exclude `char::is_control` code points and add a `CommandArgvSlot` pattern (or an explicit `format`/`pattern` encoding the whole-slot brace rule), then regenerate the committed schema - [packages/d2b-provider-command/src/command.rs:64-80, packages/d2b-provider-command/src/command.rs:133-152, docs/reference/schemas/v3/core.d2bus.org_Command.schema.json:21] - evidence: serde seed 2 `serde\((rename_all|...|pattern...)` = 0 but seed 3 `impl .*Deserialize.*for` = 2 plus seed 1 derive = 2; divergence verified against the emitted, committed schema `docs/reference/schemas/v3/core.d2bus.org_Command.schema.json` definitions.CommandExec (`pattern "^/[^\\u0000]*$"`) and definitions.CommandArgvSlot (no pattern), generated from these impls; generated-schema text is a wire contract surface. -- clean: other than tail-2#1 - hand-written `Deserialize` for CommandExec/CommandArgvSlot/CommandSpec are live admission gates on a wire shape (recorded refusal class (d) 6), `deny_unknown_fields` on the `Wire` shape and `CommandIntent`, `#[serde(transparent)]` round-trips; seed counts: seed1 = 2, seed2 = 5, seed3 = 3, seed4 = 0. - -### obs -- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency. - -### docs -- tail-2#2 sev=low blast=leaf effort=S verdict=actionable - public `Result`-returning constructors `CommandExec::parse`, `CommandArgvSlot::parse`, and `CommandSpec::new` return `Result<..., CommandContractError>` without an `# Errors` section naming which variants each can produce, though callers match on them (tests assert exact variants) - fix: add a one-line `# Errors` per constructor naming its `CommandContractError` variants - [packages/d2b-provider-command/src/command.rs:38, packages/d2b-provider-command/src/command.rs:89, packages/d2b-provider-command/src/command.rs:192] - evidence: docs seed 3 `-> Result<` = 6 hits over the three public constructors plus validation methods; seed 1 public items = 27 hits, all documented (missing_docs denied) except the canonical-section gap. -- clean: otherwise all public items carry one-line first sentences and module header explains the launch-shape contract. - -### perf -- clean: seeds 1-3 = 1 hit (`format!("{{{name}}}")` in `CommandArgvSlot::parse`) - argument-slot canonicalization runs at declaration admission once, not in a loop or hot path; no other allocation sites. - -### conc -- N/A: seeds 1-4 all zero (no threads, no Mutex/RwLock, no atomics, no thread_local/unsafe Send-Sync) over src. - -### async -- N/A: seeds 1-4 all zero over src (no async fn, no tokio spawn/select/join, no tokio sync, no tokio main/test); the only async surface is the `#[tokio::test]` registration scaffold in tests, which owns no state. - -### unsafe -- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds 1-4 all zero. - -### macro -- N/A: seeds 1-4 all zero; the `redacted_debug!` uses are imported macros from `d2b-contracts-resource` (deliberate exported-API macros, not definitions here). - -### test -- clean: seeds over src+tests = 14 hits (4 `#[test]`, 1 `#[tokio::test]` registration, 9 `assert*`); unit tests pin placeholder resolution, undeclared-placeholder refusal, brace/exec malformation refusal, role-type refusal, and a canonical round trip with unknown-field refusal - each fails on a real regression; the registration test is the documented 13-17-line shared-assertion pattern (do not flag). - -### Coverage -- idiom: clean (0/0/0) -- own: clean (6 hits; all trait-boundary/fixture) -- type: clean (0/0/0) -- api: clean (27 hits) -- err: clean (0/0/0 outside tests; 1 error enum) -- serde: 1 finding (10 hits) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) -- docs: 1 finding (30 hits) -- perf: clean (1 hit; cold admission path) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero over src) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (14 hits: 4 #[test], 1 #[tokio::test], 9 asserts) - -## d2b-provider-device - -### idiom -- clean: seeds 1-3 all zero; match-based `declared_dependency_refs`, const-fn descriptor building, and async-trait delegation read idiomatic; no index loops, hand-written derives, or statement accumulation. - -### own -- clean: seeds 1-4 = 3 hits (2 `.to_owned()` in the `inspect-device-response-invalid` error path, 1 `Arc>` in `DeviceResourceState`); the to_owned builds a cold error message, and the Arc-guarded caches are genuine shared ownership between the driver family and the daemon runtime - the four-question test passes; the `parking_lot::Mutex` choice is contract-justified (see api tail-2#3). - -### type -- clean: seeds 1-3 all zero; `DeviceComponent` is a closed four-variant vocab for the declared family, `DeviceResourceState` is a plain state bag, no boolean flags or stringly state. - -### api -- tail-2#3 sev=medium blast=family effort=L verdict=actionable - `DeviceResourceState` exposes raw `Arc>>` and `Arc>>` as pub fields, leaking wrapper types and the `parking_lot` dependency into the crate's public API (parking_lot is banned outright by (d) 2 outside the R4 worker boundary; this site is comment-justified only, driver.rs:137-138, matching the GPU crate's cache at d2b-provider-device-gpu/src/effects_service.rs:79) - fix: make the three caches private and expose narrow typed accessor methods on `DeviceResourceState` (or an effects-owned registry handle), keeping the GPU authority-lease construction contract behind the crate, and migrate the nine daemon read sites - [packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effects.rs:1584, packages/d2bd/src/shared_provider_effects.rs:2092, packages/d2bd/src/shared_provider_effects.rs:2122] - evidence: api seed 2 `pub .*\b(Arc|Rc|Box|RefCell)<` = 3 hits (tpm_controllers, gpu_controllers, gpu_authority_leases); census: `tpm_controllers|gpu_controllers|gpu_authority_leases` over packages = 9 read sites in packages/d2bd/src/shared_provider_effects.rs (1584, 1632, 1657, 2092, 2122, 2479, 2512, 2568, 2586) - the field access is genuinely needed across the crate boundary; parking_lot (d) 2 ban context cited. -- clean: otherwise seed 1 pub surface = 31 hits, single re-export path (lib.rs `pub use driver::{...}` + `pub use effects_service::DEVICE_EFFECTS_SERVICE`), documented under `#![deny(missing_docs)]`, `DeviceComponents`/trait seams carry no other wrapper or dependency types. - -### err -- clean: seeds 1-4 all zero outside tests (no unwrap/expect, no panic!/unreachable!/todo!, no error enum); `inspect_device_response` maps the trusted-static-json refusal to a named `EffectServiceError::Declined` reason instead of swallowing, and the error `map_err` names its own code. - -### serde -- clean: seeds 1-4 = 1 hit (`serde_json::from_value` in `inspect_device_response`) - a static literal payload rendered through the canonical JSON path, not an untrusted-input admission gate; no wire types deserialize in this crate. - -### obs -- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency; all daemon-side telemetry lives behind the facet trait in d2bd. - -### docs -- clean: seed 1 pub items + seed 3 = 35 hits; every pub item, pub field, and trait method documented under `#![deny(missing_docs)]`; the dead-code `facets` carry in `DeviceEffectsServiceFactory` is documented as the unwired R5 respawn contract (refused scaffolding class (d) 6 - cited, not re-flagged). - -### perf -- clean: seeds 1-3 = 1 hit (`Vec::new()` in `declared_dependency_refs` for the Usbip/SecurityKey arms) - the deliberate empty dependency set; no format!/string copies in cold or hot paths. - -### conc -- clean: seeds 1-3 = 3 hits (two `Arc>`, one `parking_lot::Mutex` scope) - the shared-state model is the documented daemon/driver seam over per-resource caches; guards are std/sync, held briefly, never across an `.await` (`await_holding_lock` is denied at the workspace); the `async-gate-allow: test-support recorder lock` markers in test_support.rs:37,49 are recorded exceptions (d) 3 - cited, not re-flagged; the parking_lot dependency leak is carried by api tail-2#3. - -### async -- clean: seeds 1-4 = 16 hits over src (async fn trait methods + `.await` delegation) - the effects delegate to the `DeviceRuntime` facet trait, no blocking work runs in src async bodies, no tokio sync guard spans an await, and `#[async_trait]` bounds the Send/Sync claims on `DeviceDriverEffects`/`DeviceRuntime`; test recorder locks carry their (d) 3 markers. - -### unsafe -- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds 1-4 all zero. - -### macro -- N/A: seeds 1-4 all zero. - -### test -- clean: seeds over src+tests = 9 hits (1 `#[test]`, 1 `#[tokio::test]`, 7 `assert*`; the `integration/device_family.rs` scaffold is policy-required (d) 5 and out of the test lane's src+tests scope); tests pin the four realizer provider identities, per-row resync, component-dispatch dispatch, and foreign-provider terminal failure - each fails on a real regression; `test-support` feature gating is the house pattern. - -### Coverage -- idiom: clean (0/0/0) -- own: clean (3 hits; shared-state seam + cold error paths) -- type: clean (0/0/0) -- api: 1 finding (31 hits) -- err: clean (0/0/0/0) -- serde: clean (1 hit; static payload only) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) -- docs: clean (35 hits) -- perf: clean (1 hit; deliberate empty set) -- conc: clean (3 hits; documented seam, no guard across await) -- async: clean (16 hits) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (9 hits: 1 #[test], 1 #[tokio::test], 7 asserts) - -## d2b-provider-emergency-policy - -### idiom -- clean: seeds 1-3 all zero; the single descriptor fn is a one-liner delegating to `metadata_descriptor`. - -### own -- N/A: seeds 1-4 all zero and no fn takes parameters (`emergency_policy_descriptor()`). - -### type -- N/A: seeds 1-3 all zero and the crate declares no struct or enum (driver fn only). - -### api -- clean: seed 1 pub surface = 2 hits (`emergency_policy_descriptor` + lib.rs re-export arm) - one documented pub fn, single re-export path, no wrappers or dependency types. - -### err -- clean: seeds 1-4 all zero; the only fn builds a descriptor and cannot panic on input. - -### serde -- N/A: seeds 1-4 all zero (crate crosses no wire; the metadata conversion owns no spec shape). - -### obs -- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency. - -### docs -- clean: seed 1 = 1 hit (`pub fn emergency_policy_descriptor`, documented under `#![deny(missing_docs)]`); module header explains the metadata-only conversion. - -### perf -- N/A: seeds 1-3 all zero. - -### conc -- N/A: seeds 1-4 all zero. - -### async -- N/A: seeds 1-4 all zero. - -### unsafe -- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds 1-4 all zero. - -### macro -- N/A: seeds 1-4 all zero. - -### test -- clean: seeds over src+tests = 1 hit (`#[tokio::test]` registration calling the shared `assert_metadata_registration` - the documented 13-17-line pattern, do not flag as trivial). - -### Coverage -- idiom: clean (0/0/0) -- own: N/A (seeds: 0/0/0/0 all zero; no fn parameters) -- type: N/A (seeds: 0/0/0 all zero; declares no struct/enum) -- api: clean (2 hits) -- err: clean (0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) -- docs: clean (1 hit) -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (1 hit: 1 #[tokio::test] registration) - -## d2b-provider-operation - -### idiom -- clean: seeds 1-3 = 1 hit (`impl Default for OperationBounds`) - the hand-written Default is the sanctioned invariant-preserving case (a field-wise derive would produce 0/0/0, which `OperationBounds::new` rejects), and it shares its value source with the serde `default =` fns; no index loops or statement accumulation. - -### own -- clean: seeds 1-4 = 1 hit (`.to_owned()` in a `#[cfg(test)]` assertion's expected string) - cold test-only, no production clones or refcounts. - -### type -- clean: seeds 1-3 all zero; every facet is a private-field struct with a validating constructor, `owner_ref`/`wire_tag` mutual exclusion (a two-Option pair the lens warns about) is enforced in `OperationSpec::new` and the type is a wire-pinned manifest shape - restructuring it is needs-contract with no new bug class covered, so left as validated state. - -### api -- clean: seed 1 pub surface = 68 hits (six facet structs, seven closed enums, OperationSpec, OperationContractError, eight bounds consts) - the deliberate wide wire vocabulary that IS the contract (api card false positive), single re-export path (`pub mod operation` + `pub use operation::*` house pattern), fields private with accessors, `Copy` where the enum has no payload; `OperationSpec::new`'s 11 arguments are `#[allow(clippy::too_many_arguments)]`-recorded and constructed once from admission, a builder would be over-engineering. - -### err -- clean: seeds 1-3 = 0 outside tests (all unwrap/expect in `#[cfg(test)]`), seed 4 = 1 (`OperationContractError`, eight variants); each variant is a distinct caller-action rejection of a declaration, all documented, constructors return `Result` and never panic on input, `unwrap_or_default` on `.split(':').next()` is infallible by construction. - -### serde -- clean: seeds 1-4 = 49 hits; the hand-written `Deserialize for OperationSpec` over a `deny_unknown_fields` `Wire` shape calling `Self::new` is the recorded live admission-gate pattern ((d) 6, recorded refusal class - cited, not re-flagged); kebab-case external enums are consistent, `deny_unknown_fields` on every facet, `skip_serializing_if = "Option::is_none"` round-trips (test asserts `wireTag` is absent), `serde(default = ...)` backs `OperationBounds`. - -### obs -- N/A: seeds 1-4 all zero and Cargo.toml carries no tracing/log dependency. - -### docs -- tail-2#4 sev=low blast=leaf effort=S verdict=actionable - public `Result`-returning constructors `OperationAudit::new`, `AuditJoin::new`, `OperationFds::new`, `OperationBounds::new`, and `OperationSpec::new` return `Result<..., OperationContractError>` without `# Errors` sections naming which variants each can produce, though callers match exact variants (tests assert them) - fix: add a one-line `# Errors` per constructor naming its `OperationContractError` variants - [packages/d2b-provider-operation/src/operation.rs:138, packages/d2b-provider-operation/src/operation.rs:194, packages/d2b-provider-operation/src/operation.rs:347, packages/d2b-provider-operation/src/operation.rs:405, packages/d2b-provider-operation/src/operation.rs:475] - evidence: docs seed 3 `-> Result<` = 8 hits across the five public constructors plus accessor returns; seed 1 public items = 72 hits, all documented (missing_docs denied) except the canonical-section gap. -- clean: otherwise every pub item, const, and enum variant carries a one-line doc; module header explains the materialized-vs-inherited split and the facet set. - -### perf -- N/A: seeds 1-3 all zero (no format!, no grow-by-push collections, no to_string copies in src). - -### conc -- N/A: seeds 1-4 all zero. - -### async -- N/A: seeds 1-4 all zero over src (no async fn, no tokio surface); the only async is the `#[tokio::test]` registration scaffold. - -### unsafe -- N/A: seeds 1-4 all zero and manifest declares `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds 1-4 all zero. - -### macro -- N/A: seeds 1-4 all zero. - -### test -- clean: seeds over src+tests = 19 hits (5 `#[test]`, 1 `#[tokio::test]` registration, 13 `assert*`); tests pin materialized-command owner, wire-tag exclusivity, secret-access ceiling, a table-driven audit-join rejection loop with per-case messages, bounds ceiling rejections, and a closed round trip - each fails on a real regression. - -### Coverage -- idiom: clean (1 hit; sanctioned invariant-preserving Default) -- own: clean (1 hit; test-only) -- type: clean (0/0/0) -- api: clean (68 hits) -- err: clean (0/0/0 outside tests; 1 error enum) -- serde: clean (49 hits) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dep) -- docs: 1 finding (72 hits) -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (19 hits: 5 #[test], 1 #[tokio::test], 13 asserts) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md deleted file mode 100644 index 09f41c1cd..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-3.md +++ /dev/null @@ -1,271 +0,0 @@ -# tail-3 - tail lane -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 1723 (excl. src/generated/**) | modules: d2b-provider-process-minijail, d2b-provider-quota, d2b-provider-resource-export, d2b-provider-resource-import, d2b-provider-role -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test, supply | Partitions: whole crates (tail lane) - -## d2b-provider-process-minijail -### idiom -- clean: seeds ran 0/0/0; no index loops, no hand-written impls (the only impls are the required `ProcessProvider` trait impl and derives), no statement-style accumulation; let-chains used throughout (edition 2024). -### own -- clean: seeds ran 2/0/0/0; the two `.clone()` sites build the owned `ProcessStatusReport` in `report()` (`self.profile.provider().clone()`, `ticket.execution_ref().clone()`) and are explainable owned-report construction; no Rc/RefCell/Arc/Cow. -### type -- tail-3#1 sev=low blast=leaf effort=S verdict=actionable - provider-identity validation is duplicated: `MinijailProcessProvider::validate` re-checks selected provider name and provider ref that `launch::validate_launch_ticket` repeats whenever a platform gate is present, so the two can drift apart - fix: drop the two identity checks from `validate_launch_ticket` (keep the gate check; rename it `validate_platform_gate` to disambiguate from the sibling `d2b-provider-process-systemd/src/launch.rs:8` function of the same name with different semantics) and use `crate::PROVIDER_REF` at lib.rs:160 instead of the literal string - [packages/d2b-provider-process-minijail/src/lib.rs:151, packages/d2b-provider-process-minijail/src/lib.rs:160, packages/d2b-provider-process-minijail/src/launch.rs:50, packages/d2b-provider-process-minijail/src/launch.rs:62] - evidence: seed `fn validate_\w+|fn check_\w+` = 1 hit (`validate_launch_ticket`, launch.rs:46); census: `validate_launch_ticket` over packages/nixos-modules/tests/docs/reference/labs = 3 hits (definition, the single call at lib.rs:193, and the sibling systemd definition) -### api -- clean: seeds ran 15/0/0; surface is the two `PROVIDER_NAME`/`PROVIDER_REF` consts, `MinijailProcessProvider` over the injected effect port (the house provider-controller seam), and the `launch`/`adoption` modules; no Arc/Rc/Box/RefCell in signatures; no `pub use` arms. -### err -- clean: seeds ran 2/0/0/0; the two `expect` sites (lib.rs:94, 106) assert frozen compile-time constants ("the frozen provider name is a valid token", "the frozen system-minijail profile is well formed") - the recorded literally-built-value false-positive class; no panics, no swallowed Results, no crate-local error enum (shared `ProcessConformanceError`). -### serde -- N/A: seeds 0/0/0/0 all zero; crate crosses no wire (no serde derives, no serde_json). -### obs -- clean: seeds ran 0/0/0/1; all telemetry is `tracing::warn!`/`debug!` with named fields (`provider`, `resource`, `error`, `identity`), message-only events carry no interpolated data, no println, no secrets in fields (identity digests only). -### docs -- tail-3#2 sev=low blast=leaf effort=S verdict=actionable - public Result-returning items carry no `# Errors` section stating which conditions produce which `ProcessConformanceError` variant - fix: add `# Errors` to `PlatformGate::validate`, `validate_launch_ticket`, `launch_with_inherited_fds`, `adopt`, `stop`, and `stop_stale` (the shared catalog is `d2b_process_conformance::ProcessConformanceError`) - [packages/d2b-provider-process-minijail/src/launch.rs:33, packages/d2b-provider-process-minijail/src/launch.rs:46, packages/d2b-provider-process-minijail/src/lib.rs:313, packages/d2b-provider-process-minijail/src/lib.rs:371, packages/d2b-provider-process-minijail/src/lib.rs:453, packages/d2b-provider-process-minijail/src/lib.rs:475] - evidence: docs seeds: pub items 13, `/// # (Examples|Errors|Panics|Safety)` 0, `-> Result<` 9 (2 in launch.rs, 7 in lib.rs; 6 of the 9 are public) -### perf -- clean: seeds ran 0/1/0; the single `Vec::new()` is the cold default in `launch()` delegating to `launch_with_inherited_fds` (lib.rs:306); no format! or to_string() in src; static (unmeasured). -### conc -- N/A: seeds 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync. -### async -- clean: seeds ran 19/0/0/0; `launch`/`adopt`/`stop`/`stop_stale` hold no locks across `.await`, spawn nothing, and do no blocking work; tests use the sanctioned plain `#[test]` + `d2b_process_conformance::testing::block_on` harness. -### unsafe -- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. -### ffi -- N/A: seeds 0/0/0/0 all zero. -### macro -- N/A: seeds 0/0/0/0 all zero. -### test -- clean: seeds ran 22/52/0/0; conformance.rs, execution_parents.rs, and platform_gate.rs assert behavior through `ScriptedEffectPort` call sequences (`PortCall::Observe`/`OpenPidfd`/`Stop`) and outcome variants, not implementation; deterministic, no network, no ignored tests; the shared `suite::` assertions plus minijail-specific pidfd/wait-ownership cells cover the fail-closed paths. -### supply -- clean: deps d2b-contracts-resource, d2b-process-conformance, tracing all appear in src/; no unused deps (X1 owns workspace-level supply). - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 2/0/0/0) -- type: 1 finding(s) -- api: clean (seeds ran: 15/0/0) -- err: clean (seeds ran: 2/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) -- obs: clean (seeds ran: 0/0/0/1) -- docs: 1 finding(s) -- perf: clean (seeds ran: 0/1/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: clean (seeds ran: 19/0/0/0) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 22/52/0/0) -- supply: clean (per-crate dep check; X1 owns workspace level) - -## d2b-provider-quota -### idiom -- clean: seeds ran 0/0/0; no index loops, hand-written impls, or statement-style accumulation; derives carry the value type. -### own -- clean: seeds ran 0/0/0/0; no clones, no shared ownership; applicable because the accessors take `&self`. -### type -- clean: seeds ran 0/0/0; `QuotaStatusResource` is a read-only status shape with private fields and const accessors; no boolean-flag or stringly-typed state; applicable because the crate declares a struct. -### api -- tail-3#3 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: the `quota` module is unconditionally `pub`, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza (or gate the test-consumed exports behind it, matching the house pattern of feature-gated test-support) - [packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21] - evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates (quota/role/resource-export/resource-import Cargo.toml:17), enabled by no manifest (d2bd enables it for 20+ provider crates, not these); prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 -### err -- clean: seeds ran 0/0/0/0; no unwrap/expect/panic, no swallowed Results; applicable because fns exist, and the panic policy is trivially clean. -### serde -- clean: seeds ran 1/1/0/0; `QuotaStatusResource` derives Serialize/Deserialize/JsonSchema with `rename_all = "camelCase"` + `deny_unknown_fields`; it is daemon output (status), so no try_from validation is owed; the shape is exercised by d2b-resource-api manager_backend tests (census: 2 hits there). -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. -### docs -- clean: seeds ran 6/0/0; every pub item (struct, three accessors, `QuotaStatus` alias, `quota_descriptor`) documented under `#![deny(missing_docs)]`; module docs present in lib.rs, driver.rs, quota.rs. -### perf -- N/A: seeds 0/0/0 all zero. -### conc -- N/A: seeds 0/0/0/0 all zero. -### async -- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. -### unsafe -- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. -### ffi -- N/A: seeds 0/0/0/0 all zero. -### macro -- N/A: seeds 0/0/0/0 all zero. -### test -- clean: seeds ran 1/0/0/0; the single test is the policy-required registration-test pattern calling the shared `assert_metadata_registration` (recorded refusal class; not flagged). -### supply -- tail-3#4 sev=low blast=leaf effort=S verdict=actionable - `serde_json` is a declared dependency but appears nowhere in the crate's src/ or tests/ - fix: drop `serde_json.workspace = true` from [dependencies] - [packages/d2b-provider-quota/Cargo.toml:24] - evidence: census: `serde_json` over packages/d2b-provider-quota = 1 hit, the manifest line itself; zero hits in src/ and tests/ (the resource-api consumer test uses its own serde_json) - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 0/0/0/0) -- type: clean (seeds ran: 0/0/0) -- api: 1 finding(s) -- err: clean (seeds ran: 0/0/0/0) -- serde: clean (seeds ran: 1/1/0/0) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds ran: 6/0/0) -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 1/0/0/0) -- supply: 1 finding(s) - -## d2b-provider-resource-export -### idiom -- clean: seeds ran 0/0/0; single descriptor fn, no loops or accumulation. -### own -- N/A: seeds 0/0/0/0 all zero; no fn takes parameters. -### type -- N/A: seeds 0/0/0 all zero; no struct or enum declared. -### api -- tail-3#5 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_export_descriptor` unconditionally, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza - [packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export/src/lib.rs:18] - evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates, enabled by no manifest; prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 -### err -- clean: seeds ran 0/0/0/0; no panic sites, no swallowed Results; applicable because `resource_export_descriptor` exists. -### serde -- N/A: seeds 0/0/0/0 all zero; crate crosses no wire. -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. -### docs -- clean: seeds ran 1/0/0; `resource_export_descriptor` documented, module docs in lib.rs and driver.rs, `#![deny(missing_docs)]` active. -### perf -- N/A: seeds 0/0/0 all zero. -### conc -- N/A: seeds 0/0/0/0 all zero. -### async -- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. -### unsafe -- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. -### ffi -- N/A: seeds 0/0/0/0 all zero. -### macro -- N/A: seeds 0/0/0/0 all zero. -### test -- clean: seeds ran 1/0/0/0; the single test is the policy-required registration-test pattern calling the shared `assert_metadata_registration` (recorded refusal class; not flagged). -### supply -- clean: the only dep, d2b-resource-types, appears in src/; no unused deps. - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: N/A (seeds: 0/0/0/0 all zero; no fn takes parameters) -- type: N/A (seeds: 0/0/0 all zero; no struct or enum declared) -- api: 1 finding(s) -- err: clean (seeds ran: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds ran: 1/0/0) -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 1/0/0/0) -- supply: clean (per-crate dep check; X1 owns workspace level) - -## d2b-provider-resource-import -### idiom -- clean: seeds ran 0/0/0; single descriptor fn, no loops or accumulation. -### own -- N/A: seeds 0/0/0/0 all zero; no fn takes parameters. -### type -- N/A: seeds 0/0/0 all zero; no struct or enum declared. -### api -- tail-3#6 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: the crate exports only `resource_import_descriptor` unconditionally, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza - [packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import/src/lib.rs:18] - evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates, enabled by no manifest; prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 -### err -- clean: seeds ran 0/0/0/0; no panic sites, no swallowed Results; applicable because `resource_import_descriptor` exists. -### serde -- N/A: seeds 0/0/0/0 all zero; crate crosses no wire. -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. -### docs -- clean: seeds ran 1/0/0; `resource_import_descriptor` documented, module docs in lib.rs and driver.rs, `#![deny(missing_docs)]` active. -### perf -- N/A: seeds 0/0/0 all zero. -### conc -- N/A: seeds 0/0/0/0 all zero. -### async -- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. -### unsafe -- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. -### ffi -- N/A: seeds 0/0/0/0 all zero. -### macro -- N/A: seeds 0/0/0/0 all zero. -### test -- clean: seeds ran 1/0/0/0; the single test is the policy-required registration-test pattern calling the shared `assert_metadata_registration` (recorded refusal class; not flagged). -### supply -- clean: the only dep, d2b-resource-types, appears in src/; no unused deps. - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: N/A (seeds: 0/0/0/0 all zero; no fn takes parameters) -- type: N/A (seeds: 0/0/0 all zero; no struct or enum declared) -- api: 1 finding(s) -- err: clean (seeds ran: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds ran: 1/0/0) -- perf: N/A (seeds: 0/0/0 all zero) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 1/0/0/0) -- supply: clean (per-crate dep check; X1 owns workspace level) - -## d2b-provider-role -### idiom -- clean: seeds ran 0/0/0; no index loops, no hand-written impls beyond the deliberate `Debug` for `PositiveDecisionCache` (lock-free diagnostics, documented and tested), no statement-style accumulation. -### own -- clean: seeds ran 0/0/0/0; no clones, no shared ownership; applicable because the cache fns take `&self`/`&key`. -### type -- clean: seeds ran 0/0/0; `PolicyRevisionSet`/`AuthorizationCacheKey`/`PositiveEntry`/`PositiveDecisionCache` model the revision-bound positive-only cache with no boolean-flag or stringly-typed state; applicable because the crate declares structs. -### api -- tail-3#8 sev=low blast=family effort=S verdict=actionable - the `test-support` feature is declared empty and gates nothing: `rbac` is unconditionally `pub`, and no manifest enables the feature - fix: delete the `[features] test-support = []` stanza - [packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16] - evidence: census: `test-support` over packages manifests = declared empty in 4 tail-lane crates, enabled by no manifest; prior audit deferred the class: docs/explanation/over-engineering-audit-record.md:916 -### err -- clean: seeds ran 5/0/0/0; all five unwrap hits sit inside `#[cfg(test)] mod tests` in rbac.rs (fixture refs and generations), the recorded test false-positive class; the production lock path handles poison explicitly (`unwrap_or_else` clearing the entries). -### serde -- N/A: seeds 0/0/0/0 all zero; crate crosses no wire. -### obs -- N/A: seeds 0/0/0/0 all zero; no tracing/log dependency. -### docs -- tail-3#7 sev=low blast=leaf effort=S verdict=actionable - role's lib.rs lacks the `#![deny(missing_docs)]` gate that its four sibling declaration crates in this lane all carry (quota lib.rs:16, resource-export lib.rs:14, resource-import lib.rs:14, minijail lib.rs:25), and `PolicyRevisionSet`'s four pub fields are undocumented - fix: add `#![deny(missing_docs)]` to lib.rs and document the `PolicyRevisionSet` fields - [packages/d2b-provider-role/src/lib.rs:1, packages/d2b-provider-role/src/rbac.rs:11] - evidence: docs seeds: pub items 9, `/// # (Examples|Errors|Panics|Safety)` 0, `-> Result<` 0; grep `deny\(missing_docs\)` = 0 hits in role vs 1 each in the four sibling crates -### perf -- clean: seeds ran 3/1/0; the format! hits are test-only (redaction sentinel checks), the single `BTreeMap::new()` is the cache constructor; bounded cache with retain-on-access, no hot-path allocation; static (unmeasured). -### conc -- clean: seeds ran 0/1/0/0; the `std::sync::Mutex` behind `PositiveDecisionCache` carries the sanctioned `#[allow(clippy::disallowed_methods, reason = "synchronous path")]` (U1 (d)4 sanctioned reason), and the `Debug` impl deliberately uses `try_lock` so diagnostics never block; no atomics, no unsafe Send/Sync. -### async -- N/A: seeds 0/0/0/0 all zero; the only async is the dev-dependency `#[tokio::test]` registration test, out of crate scope. -### unsafe -- N/A: seeds 0/0/0/0; manifest forbids `unsafe_code`. -### ffi -- N/A: seeds 0/0/0/0 all zero. -### macro -- N/A: seeds 0/0/0/0 all zero; `redacted_debug!` is an invocation of the contracts-crate macro, not a definition. -### test -- clean: seeds ran 3/8/0/0; rbac unit tests assert the redaction contract (sentinel absence, exact Debug string) and expiry/revision-invalidation behavior with hand-written expectations; registration test is the policy-required pattern; deterministic, no ignored tests. -### supply -- clean: deps d2b-contracts-resource and d2b-resource-types both appear in src/; no unused deps. - -## Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 0/0/0/0) -- type: clean (seeds ran: 0/0/0) -- api: 1 finding(s) -- err: clean (seeds ran: 5/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: 1 finding(s) -- perf: clean (seeds ran: 3/1/0) -- conc: clean (seeds ran: 0/1/0/0) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0/0 all zero) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 3/8/0/0) -- supply: clean (per-crate dep check; X1 owns workspace level) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md deleted file mode 100644 index 1d9262fe4..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-4.md +++ /dev/null @@ -1,336 +0,0 @@ -# tail-4 - tail lane -Baseline: 6ebdd4cec | LOC audited: 2515 (excl. src/generated/**) | modules: d2b-provider-role-binding, d2b-provider-seccomp-profile, d2b-provider-shell-pool, d2b-provider-shell-session, d2b-provider-telemetry-binding -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test, supply | Partitions: whole crates - -## d2b-provider-role-binding - -### idiom -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the only fn body is the one-line descriptor declaration, nothing to judge. - -### own -- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 0, `Rc<|RefCell<|Arc Result<` = 0; the one pub item carries a doc comment and `#![deny(missing_docs)]` is on (lib.rs:14). - -### perf -- clean: seeds `format!(` = 0, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 0, `.to_string()` = 0; no allocation sites at all. - -### conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero; no threads, locks, or atomics. - -### async -- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; the only async code is the `#[tokio::test]` registration shim in tests/, which the test lens owns. - -### unsafe -- N/A: seeds `\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 all zero; manifest sets `unsafe_code = "forbid"` and no `unsafe_code = "allow"` exists. - -### ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero; no foreign boundary. - -### macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero; no macro definitions. - -### test -- clean: seeds `#[test]|#[tokio::test]` = 1, `assert_eq!|assert_ne!|assert!` = 6, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; the single registration test is the documented shared `assert_metadata_registration` shim (tests/registration.rs:11-17, recorded pattern, not flagged). - -### Coverage -- idiom: clean (seeds: 0/0/0) -- own: clean (seeds: 0/0/0/0) -- type: N/A (seeds: 0/0/0 all zero; no struct or enum declared) -- api: clean (seeds: 1/0/1) -- err: clean (seeds: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire crossing) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds: 1/0/0) -- perf: clean (seeds: 0/0/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero in src) -- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds: 1/6/0/0) -- supply: clean (X1 owns the lens; per-crate manifest check: d2b-resource-types used in driver.rs, tokio dev-dep used in tests/registration.rs) - -## d2b-provider-seccomp-profile - -### idiom -- tail-4#1 sev=low blast=leaf effort=S verdict=actionable - three impl-block closing braces are indented at 4 spaces instead of column 0 (fmt drift; `cargo fmt --check` would fail) - fix: dedent the closing braces of `impl DeviceNodePath`, `impl DeviceBind`, and `impl SeccompProfileSpec` to column 0 (rustfmt) - [packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:43, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:162, packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs:196] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `for \w+ in 0\.\.` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; finding from read: lines 43/162/196 are ` }` closing impl blocks opened at column 0. -- clean: seeds 0/0/0; the only expression-shape items are the validated newtype and constructor, which already follow the parse-once pattern. - -### own -- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 2, `Rc<|RefCell<|Arc Result<` = 2; the two Result returns are the public parse/new constructors; every other pub item is documented under `#![deny(missing_docs)]`. -- clean: module docs (`//!`) present in all three files; every public item has a doc comment and the crate denies missing_docs (lib.rs:14). - -### perf -- clean: seeds `format!(` = 0, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 1, `.to_string()` = 0; the single `Vec::new()` (seccomp_profile.rs:297) is a test argument where the empty case is the point. - -### conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero. - -### async -- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; the only async code is the `#[tokio::test]` registration shim in tests/. - -### unsafe -- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. - -### macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero; `redacted_debug!` appears only as an invocation of the deliberately exported macro (recorded false positive). - -### test -- clean: seeds `#[test]|#[tokio::test]` = 4, `assert_eq!|assert_ne!|assert!` = 7, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; three unit tests (table-driven path rejection with `{path:?}` messages, fail-closed list bounds, wire round-trip plus unknown-field refusal) plus the documented registration shim; no test that cannot fail. - -### Coverage -- idiom: 1 finding(s) -- own: clean (seeds: 0/2/0/0) -- type: clean (seeds: 0/0/0) -- api: 1 finding(s) -- err: clean (seeds: 10/0/0/1, all unwrap in cfg(test)) -- serde: clean (seeds: 8/16/2/2) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: 1 finding(s) -- perf: clean (seeds: 0/1/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero in src) -- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds: 4/7/0/0) -- supply: clean (X1 owns the lens; per-crate manifest check: d2b-contracts-resource, d2b-resource-types, schemars, serde all used in src; tokio + serde_json dev-deps used in tests) - -## d2b-provider-shell-pool - -### idiom -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the crate is one trait impl plus declarations, all in expression shape. - -### own -- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 0, `Rc<|RefCell<|Arc` return (shell_pool.rs:93) is required by the `DriverDescriptor.decoder` field type, and the re-export list is the explicit house pattern. - -### err -- clean: seeds `.unwrap()|.expect()` = 0, `let _ = |.ok();` = 0, `panic!|unreachable!|todo!|unimplemented!` = 0, `enum \w*Error` = 0; failures are the family's `InteractionEffectError`, propagated with `?`; no panic sites. - -### serde -- N/A: seeds `derive)...Serialize` = 0, `serde)...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 0 all zero; the spec is authored as the Provider's reference document and decoded by the family decoder (`spec_decoder()`), so this crate crosses no wire of its own. - -### obs -- N/A: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 0, `.instrument(|#[instrument` = 0, `tracing::|log::` = 0 all zero and the manifest lists no tracing/log dependency. - -### docs -- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 8, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 3; every pub item carries a doc comment under `#![deny(missing_docs)]` (lib.rs:13); the Result-returning `InteractionType` impls (shell_pool.rs:62, 70, 81) carry prose docs and their contract lives on the family trait in d2b-provider-wayland-policy. - -### perf -- clean: seeds `format!(` = 0, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 1, `.to_string()` = 0; the single `Vec::new()` (shell_pool.rs:82) is the empty desired-children return, the common case. - -### conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero. - -### async -- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; all async code lives in tests/. - -### unsafe -- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. - -### macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero. - -### test -- clean: seeds `#[test]|#[tokio::test]` = 4, `assert_eq!|assert_ne!|assert!` = 12, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; four tests with doc comments - declaration surface, duplicate-registration refusal, dependency reads, and table-driven malformed-reference refusal with `{spec}` failure messages; no test that cannot fail. - -### Coverage -- idiom: clean (seeds: 0/0/0) -- own: clean (seeds: 0/0/0/0) -- type: clean (seeds: 0/0/0) -- api: clean (seeds: 8/1/1) -- err: clean (seeds: 0/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; family decoder owns the spec decode) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds: 8/0/3) -- perf: clean (seeds: 0/1/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero in src) -- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds: 4/12/0/0) -- supply: clean (X1 owns the lens; per-crate manifest check: all five deps used in src; async-trait + serde_json dev-deps used in tests) - -## d2b-provider-shell-session - -### idiom -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0; the `dependencies()` accumulation (shell_session.rs:76-80) is a conditional push the iterator form would obscure, so the plain form is right. - -### own -- clean: seeds `.clone()` = 0, `.to_owned()|.to_vec()|.to_string()` = 1, `Rc<|RefCell<|Arc` return (shell_session.rs:137) is required by the `DriverDescriptor.decoder` field; explicit house re-export list; private consts (`SHELL_SUPERVISOR_PROVIDER_REF`, `SHELL_SUPERVISOR_TEMPLATE`) stay private. - -### err -- clean: seeds `.unwrap()|.expect()` = 0, `let _ = |.ok();` = 0, `panic!|unreachable!|todo!|unimplemented!` = 0, `enum \w*Error` = 0; failures are the family's `InteractionEffectError` propagated with `?`; the `invalid()` closure (shell_session.rs:94) maps impossible construction failures to `InvalidResource` without panicking. - -### serde -- clean: seeds `derive)...Serialize` = 0, `serde)...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 2; the two `serde_json::to_vec` calls (shell_session.rs:119-120) render the supervisor child's spec and metadata at the wire boundary; no derives needed because the spec is `json!`-built. - -### obs -- N/A: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 0, `.instrument(|#[instrument` = 0, `tracing::|log::` = 0 all zero and the manifest lists no tracing/log dependency. - -### docs -- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 8, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 3; every pub item documented under `#![deny(missing_docs)]` (lib.rs:13); the Result-returning `InteractionType` impls carry prose docs, contract on the family trait. - -### perf -- clean: seeds `format!(` = 1, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 0, `.to_string()` = 0; the single `format!` (shell_session.rs:99) builds the supervisor child reference once per reconcile pass - cold, static (unmeasured). - -### conc -- N/A: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0 all zero. - -### async -- N/A: seeds `async fn|async move|.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#[tokio::(main|test)]|Runtime::block_on` = 0 all zero in src; all async code lives in tests/. - -### unsafe -- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. - -### macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero. - -### test -- clean: seeds `#[test]|#[tokio::test]` = 5, `assert_eq!|assert_ne!|assert!` = 16, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; five tests with doc comments - declaration surface, duplicate refusal, dependency reads, supervisor-child spec asserted field by field (providerRef/template/processClass/executionRef/userRef/dependencies/ownerRef), and table-driven malformed-ref refusal; no test that cannot fail. - -### Coverage -- idiom: clean (seeds: 0/0/0) -- own: clean (seeds: 0/1/0/0) -- type: clean (seeds: 0/0/0) -- api: clean (seeds: 8/1/1) -- err: clean (seeds: 0/0/0/0) -- serde: clean (seeds: 0/0/0/2) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds: 8/0/3) -- perf: clean (seeds: 1/0/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero in src) -- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds: 5/16/0/0) -- supply: clean (X1 owns the lens; per-crate manifest check: all six deps used in src; async-trait dev-dep used in tests) - -## d2b-provider-telemetry-binding - -### idiom -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 1, `let mut \w+ = (String|Vec)::new\(\)` = 0; the one hand-written `impl Default for TelemetryBindingDriverFactory` (driver.rs:234) is required - `[ResourceTypeName; 1]` has no field-wise `Default` and `ResourceTypeName` does not implement it, so a derive is impossible. - -### own -- clean: seeds `.clone()` = 20, `.to_owned()|.to_vec()|.to_string()` = 4, `Rc<|RefCell<|Arc` return (driver.rs:205) is required by the `DriverDescriptor.decoder` field; the re-export list is explicit (lib.rs:35-41); `TelemetryBindingSpecEnvelope` stays un-exported (pub in a private module), and `TelemetryBindingDriver` is an opaque pub type with a private constructor - deliberate. - -### err -- clean: seeds `.unwrap()|.expect()` = 17, `let _ = |.ok();` = 1, `panic!|unreachable!|todo!|unimplemented!` = 3, `enum \w*Error` = 1; all 17 unwrap/expect and all 3 `panic!` sit in `#[cfg(test)]`; the one `let _ =` (driver.rs:509) is the deliberate validate-the-envelope-decodes pattern that still propagates errors with `?`; `TelemetryBindingDriverErrorKind` splits by caller action with stable wire codes via `as_str()` (driver.rs:130-136) - the taxonomy this lens recommends. - -### serde -- clean: seeds `derive)...Serialize` = 0, `serde)...)` = 0, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 7; the wire boundary is the `ResourceSpec` decode inside `telemetry_binding_spec_decoder` (driver.rs:205-211) and canonical-JSON round-trips of child payloads (199, 374, 388-390); no derives needed because the envelope wraps `CanonicalJsonObject`; every parse failure maps to a typed error kind. - -### obs -- N/A: seeds `println!|eprintln!` = 0, `(info|debug|warn|error|trace)!\("` = 0, `.instrument(|#[instrument` = 0, `tracing::|log::` = 0 all zero and the manifest lists no tracing/log dependency. - -### docs -- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 20, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 17; every pub item carries a doc comment under `#![deny(missing_docs)]` (lib.rs:14), including the contract-flag note on the Degraded projection (driver.rs:473-476); the Result-returning `ResourceDriver` impls (validate/recover/reconcile/delete) carry prose docs and their error contract lives on the trait in d2b-resource-runtime. - -### perf -- clean: seeds `format!(` = 5, `Vec::new()|VecDeque::new()|HashMap::new()|BTreeMap::new()` = 5, `.to_string()` = 0; all 5 `format!` (driver.rs:764, 796, 1027, 1166, 1173) and 3 of the `Vec::new()` (684-686) are `#[cfg(test)]` fixtures; the production `Vec::new()` sites (270, 404, 909) are the empty-common case; static (unmeasured). - -### conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 4, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0; all 4 `Mutex` hits (driver.rs:675-677, 839) are `tokio::sync::Mutex` inside `#[cfg(test)]` fixture doubles - test-only synchronization, no production shared state. - -### async -- clean: seeds `async fn|async move|.await` = 20, `tokio::spawn|spawn_blocking|JoinSet|select!|join!` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 1 (cfg(test) import), `#[tokio::(main|test)]|Runtime::block_on` = 10 (cfg(test)); the production async surface is the `ResourceDriver` trait impls - no blocking calls, no guards held across `.await`, no spawn/select, and each pass is idempotent so cancellation at any await leaves a re-runnable state; `watch_once` (driver.rs:317-323) is documented best-effort with the requeue schedule as the recovery path. - -### unsafe -- N/A: seeds 1-3 (`\bunsafe {|\bunsafe fn|\bunsafe impl|\bunsafe extern`, `// SAFETY:`, `transmute|from_raw|MaybeUninit|mem::zeroed`) = 0/0/0; manifest sets `unsafe_code = "forbid"`. - -### ffi -- N/A: seeds `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 all zero. - -### macro -- N/A: seeds `macro_rules!` = 0, `proc_macro|syn::|quote!` = 0, `\$crate` = 0, `to_compile_error|new_spanned` = 0 all zero. - -### test -- clean: seeds `#[test]|#[tokio::test]` = 13, `assert_eq!|assert_ne!|assert!` = 40, `proptest!|insta::assert|rstest` = 0, `#[ignore]` = 0; ten unit tests over a recording manager endpoint assert the observable contracts - child ensure order (collector Process before ingest Endpoint), second-pass convergence with no resync, fence on dangling dependency and foreign Provider, endpoint-first/process-last teardown order, one watch registration per target, recover adopt only on a current child set, and delete performing no effect past the manager cascade - plus the three documented registration tests; no test that cannot fail. - -### Coverage -- idiom: clean (seeds: 0/1/0) -- own: clean (seeds: 20/4/0/0, all clones explainable) -- type: 1 finding(s) -- api: clean (seeds: 20/1/1) -- err: clean (seeds: 17/1/3/1, all panic sites in cfg(test)) -- serde: clean (seeds: 0/0/0/7) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency) -- docs: clean (seeds: 20/0/17) -- perf: clean (seeds: 5/5/0) -- conc: clean (seeds: 0/4/0/0, test-only) -- async: clean (seeds: 20/0/1/10, production surface sound) -- unsafe: N/A (seeds 1-3: 0/0/0; manifest forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds: 13/40/0/0) -- supply: clean (X1 owns the lens; per-crate manifest check: all eight deps used in src; tokio dev-dep used in tests) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md deleted file mode 100644 index cf7c3dfb2..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-5.md +++ /dev/null @@ -1,337 +0,0 @@ -# tail-5 - tail lane -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 3127 (excl. src/generated/**) | modules: d2b-provider-telemetry-service, d2b-provider-test-controller, d2b-provider-transport-unix, d2b-provider-wayland-session, d2b-provider-zone -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates - -## d2b-provider-telemetry-service - -### idiom -- clean: seeds ran 0/1/0 - the one hand-written impl is `Default for TelemetryServiceDriverFactory` delegating to `new()` (driver.rs:90-94), the idiomatic shape; no index loops, no statement-style accumulation. - -### own -- clean: seeds ran 13/2/0/0 - every clone is explainable: `key.clone()` into the driver's own key (driver.rs:159), `spec.base().clone()` into the owned envelope (driver.rs:151), `endpoint_ref.clone()` into `present_endpoints` (driver.rs:299), plus test-fixture clones; no Rc/RefCell/Arc/Cow. - -### type -- tail-5#1 sev=low blast=leaf effort=S verdict=actionable - `TelemetryServiceStatus` carries stringly-typed state: `phase: &'static str` (three spellings via `PHASE_*` consts) and `projection: serde_json::Value` built by hand with `json!` at three sites, so the `{serviceRole, serviceReadiness}` pair is constructed and indexed by string - fix: add a `TelemetryServicePhase` enum with `as_str()` for the three spellings and a two-field `TelemetryServiceProjection` struct that serializes to the same contract-pinned shape (`SERVICE_STATUS_ALLOWED` spellings at d2b-contracts-provider/src/v3/semantic_services/telemetry.rs:55), replacing the `json!` literals at driver.rs:274-290 and 309-315 - [packages/d2b-provider-telemetry-service/src/driver.rs:119-125, packages/d2b-provider-telemetry-service/src/driver.rs:309-315] - evidence: type seeds s1=2 (the trait-required `validate` and a test fn - not findings), s2=0, s3=0; public-surface read of the exported status struct - -### api -- clean: seeds ran 16/1/1 - the single `Arc` in a public signature (driver.rs:147) is the house decoder contract required by `typed_spec_decoder`; `pub use` re-export arms in lib.rs:34-36 are the house single-surface pattern; every exported item is deliberate (driver, factory, descriptor, decoder, status, error). - -### err -- tail-5#2 sev=medium blast=leaf effort=S verdict=actionable - `reconcile_service` replaces the manager's `ResourceError` with the stable `Reconcile` kind via `Err(_) => return Err(...)`, dropping the source, so the actor sees only the wire code and the underlying store failure is invisible - fix: log the source before converting (the crate has no tracing dependency today) or carry it as a `#[source]` field on `TelemetryServiceDriverError` - [packages/d2b-provider-telemetry-service/src/driver.rs:304] - evidence: err seeds s1=13 (all inside `#[cfg(test)] mod tests`, lines 601-879), s2=2 (both `let _ = self.envelope(...)?` - propagated, not swallowed), s3=4 (test panics), s4=1 -- tail-5#3 sev=low blast=leaf effort=S verdict=actionable - `ingest_endpoint_refs` silently drops unparseable declared refs (`ResourceRef::parse(value).ok()` inside `filter_map`), so a typo'd `ingestEndpointRefs` entry is indistinguishable from an absent list and the row requeues on the 5s resync forever with no signal - fix: log a warning naming the dropped value, or fail the reconcile with `InvalidResource` - [packages/d2b-provider-telemetry-service/src/driver.rs:386] - evidence: err s2=2; the `.ok()` swallow is outside the seed's `\.ok\(\);` shape (no trailing semicolon) - read-based - -### serde -- clean: seeds ran 0/0/0/3 - the crate crosses no wire with derives; serde_json use is the preserved envelope decode (`from_slice::`, `to_canonical_bytes` round-trip, driver.rs:141-151), and `validate` is the decode admission gate; the canonical-bytes round-trip in `value()` is preserved old-reconciler behavior (driver.rs:141-144, documented). - -### obs -- N/A: seeds 0/0/0/0 all zero; Cargo.toml carries no tracing/log dependency (the crate reports through its typed error codes only) - -### docs -- clean: seeds ran 16/0/14 - `#![deny(missing_docs)]` (lib.rs:8) and every pub item carries a contract doc; the Result-returning items are `ResourceDriver` trait impls whose failure contract lives in the trait; no canonical-section gaps on inherent pub items. - -### perf -- clean: seeds ran 3/7/0 - all `format!` hits are test-fixture log strings; the `Vec::new()` sites are cold paths or empty-case-common collections (`watched`, empty `present_endpoints`); no hot-loop allocation. - -### conc -- clean: seeds ran 0/4/0/0 - all four `Mutex<` hits are `tokio::sync::Mutex` in the `#[cfg(test)]` recording fakes; no threads, atomics, or manual Send/Sync in the crate. - -### async -- clean: seeds ran 73/0/1/9 - the 73 await hits are the driver verbs (validate/recover/reconcile/delete/watch_once) over the runtime's async `ResourceContext`; no spawn, no spawn_blocking, no blocking call in an async context, no guard held across await; the 9 `#[tokio::test]` sites are tests; the one `tokio::sync::Mutex` is test-only. - -### unsafe -- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) - -### ffi -- N/A: seeds 0/0/0/0 all zero - -### macro -- N/A: seeds 0/0/0/0 all zero - -### test -- clean: seeds ran 13/39/0/0 - 13 tests (9 driver-level over a recording manager endpoint + requeue recorder, 4 registration-boundary) assert behavior and error variants (`matches!` on `ProviderDirectoryError::DuplicateType`/`RequiredBeforeOpen`, `FailureClass::Retryable`), cover all four reconcile branches (degraded/projection/pending/fail-closed), and use deterministic fakes; no `#[ignore]`, no property tooling needed at this size. - -### Coverage -- idiom: clean (seeds ran: 0/1/0) -- own: clean (seeds ran: 13/2/0/0) -- type: 1 finding(s) -- api: clean (seeds ran: 16/1/1) -- err: 2 finding(s) -- serde: clean (seeds ran: 0/0/0/3) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: clean (seeds ran: 16/0/14) -- perf: clean (seeds ran: 3/7/0) -- conc: clean (seeds ran: 0/4/0/0) -- async: clean (seeds ran: 73/0/1/9) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 13/39/0/0) - -## d2b-provider-test-controller - -### idiom -- clean: seeds ran 0/0/0 - bin-only crate with plain sequential code; no index loops, no hand-written impls, no accumulation statements. - -### own -- clean: seeds ran 0/1/0/0 - the single `.to_vec()` (main.rs:194) copies the bootstrap protocol marker into the owned packet payload, the one ownership-transfer boundary; no clones, no shared-state types. - -### type -- clean: seeds ran 0/0/0 - `SessionDisposition` is a proper two-variant enum; no boolean/string state; the `Result<(), ()>` retry signal is deliberate for the fixture loop. - -### api -- N/A: seeds 0/0/0 all zero; the crate is bin-only ([[bin]] Cargo.toml:24-26) with no lib target and no pub items - -### err -- tail-5#4 sev=low blast=leaf effort=S verdict=actionable - `send_bootstrap` and `controller_transport` drop every failure reason with `map_err(|_| ())` (AncillaryCapacity, credit scopes, packet build, send burst, transport build), and the caller logs only the generic retry line, while sibling sites log `reason = %e` - fix: log the reason at each drop site with `warn!(reason = %e, ...)` before converting to `()` - [packages/d2b-provider-test-controller/src/main.rs:186-187, packages/d2b-provider-test-controller/src/main.rs:196-199, packages/d2b-provider-test-controller/src/main.rs:221-230] - evidence: err seeds s1=9 (all inside `#[cfg(test)] mod tests`), s2=0, s3=1 (test-only panic), s4=0 - -### serde -- N/A: seeds 0/0/0/0 all zero (no wire crossing in the bin) - -### obs -- tail-5#5 sev=medium blast=leaf effort=S verdict=actionable - the bin emits `tracing` events with structured `reason = %e` fields but never installs a subscriber (main() at main.rs:33-47; Cargo.toml has `tracing` but no tracing-subscriber), so every debug/warn/error event is dropped and the only operator-visible diagnostics are the unstructured `eprintln!` retry lines at main.rs:68/95/99/111/125 - one failure class reported through two channels, one of which is dead - fix: install a subscriber once at process start (e.g. `tracing_subscriber::fmt::init()`), or convert the tracing sites to eprintln - [packages/d2b-provider-test-controller/src/main.rs:33-47, packages/d2b-provider-test-controller/src/main.rs:68] - evidence: obs seeds s1=5 (eprintln), s2=4, s3=0, s4=1; Cargo.toml dependency read shows no subscriber crate -- tail-5#6 sev=low blast=leaf effort=S verdict=actionable - message-only warn events drop their context: the keepalive error is discarded via `.is_err()` and logged as a bare message, and the unexpected named stream's id is unnamed - fix: bind the error (`warn!(reason = %e, ...)`) and name the stream (`warn!(stream = ?stream, ...)`) - [packages/d2b-provider-test-controller/src/main.rs:164, packages/d2b-provider-test-controller/src/main.rs:173-174] - evidence: obs s2=4 (message-only `warn!`/`error!`/`debug!` sites; the other two are startup messages without a field to attach) - -### docs -- N/A: seeds 0/0/4 - seed 1 (pub items) is zero; bin-only crate, and the skill never adds missing_docs to a binary - -### perf -- clean: seeds ran 0/0/0 - no format!, no grow-by-push collections, no copies; the retry sleeps are the only pacing. - -### conc -- N/A: seeds 0/0/0/0 all zero (no threads, locks, atomics, or thread_local in the crate) - -### async -- clean: seeds ran 14/0/0/0 - the 14 await hits are the session loop, bootstrap send, and retry sleeps, all on the current-thread runtime built at process entry (`block_on` at main.rs:45 is the sanctioned entry-point pattern); no spawn, no blocking call in an async context, no guard across await. - -### unsafe -- N/A: seeds 0/0/0 all zero; `#![forbid(unsafe_code)]` (main.rs:3) and manifest forbid - -### ffi -- N/A: seeds 0/0/0/0 all zero - -### macro -- N/A: seeds 0/0/0/0 all zero - -### test -- clean: seeds ran 3/8/0/0 - three meaningful tests: a `should_reconnect` disposition table, a behavioral handshake-terminality test over a real socketpair with `select!`/`timeout` proving one-shot bootstrap delivery, and a fail-closed spawn of the bin without fd10; error variants asserted, deterministic, no `#[ignore]`. - -### Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 0/1/0/0) -- type: clean (seeds ran: 0/0/0) -- api: N/A (seeds: 0/0/0 all zero; bin-only crate, no lib target) -- err: 1 finding(s) -- serde: N/A (seeds: 0/0/0/0 all zero) -- obs: 2 finding(s) -- docs: N/A (seeds: 0/0/4; seed 1 zero - no pub items in a bin-only crate) -- perf: clean (seeds ran: 0/0/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: clean (seeds ran: 14/0/0/0) -- unsafe: N/A (seeds: 0/0/0 all zero; forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 3/8/0/0) - -## d2b-provider-transport-unix - -### idiom -- clean: seeds ran 1/1/0 - the single index loop is the bounded 8-attempt handle-collision retry with early return (portal.rs:345), where a plain `for` is right; the hand-written `Default for TransportPortal` delegates to `new()` (portal.rs:147-150), the idiomatic shape. - -### own -- clean: seeds ran 0/0/0/0 - no clones, no to_owned, no shared-state types; ownership is moved end to end (`OwnedFd` transfers, `into_parts`, `into_transport_fd`). - -### type -- clean: seeds ran 2/0/0 - the two `validate_*` fns are the boundary admission checks (`validate_route_class`, `validate_and_prepare`), exactly where parse-once validation belongs; `attachments_enabled: bool` is a single flag whose illegal combination is rejected at the same boundary, below the skill's stopping rule. - -### api -- clean: seeds ran 47/0/3 - deliberate closed surface: opaque redacted `TransportHandle`, private-field `OpenedTransport`/`TransportDescriptor` with accessors, `pub use` named re-export arms (lib.rs:17-23), no Arc/Rc/Box/RefCell in signatures; the zero in-tree callers are the documented declared-provider class (provider-crate-policy ratchet, refusal ledger), not a surface defect. - -### err -- clean: seeds ran 1/0/0/2 - the single `expect("finalized order is populated")` (portal.rs:141) sits behind a `len() > MAX_OPEN_TRANSPORTS` check the compiler cannot see and names the invariant; both error enums are closed stable-code surfaces with `From` mapping between them; no swallowed errors. - -### serde -- N/A: seeds 0/0/0/0 all zero (the crate crosses no wire; descriptors are kernel-observed, not serialized) - -### obs -- tail-5#7 sev=low blast=leaf effort=S verdict=actionable - four message-only `tracing::warn!` events drop the underlying errno (`map_err(|_|)` then warn with only the `provider` field): peer-credential bind failure, monitor-fd duplication, observation poll, and entropy-source failures - fix: capture the errno as `reason = %e` like the admission-rejection site at portal.rs:209-212 already does - [packages/d2b-provider-transport-unix/src/portal.rs:217-220, packages/d2b-provider-transport-unix/src/portal.rs:244-247, packages/d2b-provider-transport-unix/src/portal.rs:301-304, packages/d2b-provider-transport-unix/src/portal.rs:348-351] - evidence: obs seeds s1=0, s2=0 (the `tracing::warn!(` form does not match the interpolated-message seed), s3=0, s4=9; read-based - -### docs -- tail-5#8 sev=low blast=leaf effort=S verdict=actionable - the three inherent pub methods returning `Result` (`open`, `close`, `observe`) lack `# Errors` sections naming which conditions produce which `PortalError` variant, though the failure conditions are recoverable from the enum docs - fix: add `# Errors` sections to the three doc comments - [packages/d2b-provider-transport-unix/src/portal.rs:197-201, packages/d2b-provider-transport-unix/src/portal.rs:266, packages/d2b-provider-transport-unix/src/portal.rs:286] - evidence: docs seeds s1=41, s2=0, s3=7; `#![deny(missing_docs)]` (lib.rs:3) is satisfied but the canonical-section rule is not - -### perf -- clean: seeds ran 0/4/0 - the `Vec::new`/`HashMap::new`/`HashSet::new`/`VecDeque::new` hits are the empty portal's initial state (portal.rs:60-66) and a test fixture; no format! in the crate; handle generation is bounded at 8 attempts. - -### conc -- tail-5#9 sev=low blast=leaf effort=S verdict=actionable - `tokio::sync::Mutex` (portal.rs:18, 155) in a crate with zero async code - every use is `try_lock()` on a synchronous path, so the tokio `sync` feature dependency exists solely for this one lock - fix: use `std::sync::Mutex` (the crate's own `try_lock`-only pattern never awaits) - [packages/d2b-provider-transport-unix/src/portal.rs:18, packages/d2b-provider-transport-unix/src/portal.rs:155] - evidence: conc seeds s1=0, s2=1, s3=0, s4=0; async seeds s1=0, s2=0, s3=1 (this same Mutex import), s4=0 - -### async -- clean: seeds ran 0/0/1/0 - the crate has no async fn, no await, no spawn; the single `tokio::sync::Mutex` hit is judged under conc (tail-5#9); nothing here blocks an executor because there is no executor. - -### unsafe -- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) - -### ffi -- N/A: seeds 0/0/0/0 all zero (rustix syscall wrappers are not a foreign-caller boundary) - -### macro -- N/A: seeds 0/0/0/0 all zero - -### test -- clean: seeds ran 7/19/0/0 - six integration tests over real socketpairs assert error variants (`PortalError::PeerCredentials`/`SocketKindMismatch`/`AttachmentPolicyConflict`/`HandleTableFull`/`UnknownHandle`), kernel-bound peer credentials, fd-substitution refusal, idempotent close, foreign-handle refusal, disconnect observation, and full-table recovery; one unit test covers handle-reissue; deterministic, no `#[ignore]`. - -### Coverage -- idiom: clean (seeds ran: 1/1/0) -- own: clean (seeds ran: 0/0/0/0) -- type: clean (seeds ran: 2/0/0) -- api: clean (seeds ran: 47/0/3) -- err: clean (seeds ran: 1/0/0/2) -- serde: N/A (seeds: 0/0/0/0 all zero) -- obs: 1 finding(s) -- docs: 1 finding(s) -- perf: clean (seeds ran: 0/4/0) -- conc: 1 finding(s) -- async: clean (seeds ran: 0/0/1/0) -- unsafe: N/A (seeds: 0/0/0 all zero; forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 7/19/0/0) - -## d2b-provider-wayland-session - -### idiom -- clean: seeds ran 0/1/0 - the hand-written `Default for WaylandSession` (wayland_session.rs:96-98) builds the `Arc` the derive cannot, delegating through `new()`; `desired_children` already uses the iterator pipeline (`intents.iter().map(owned_child_ensure).collect()`). - -### own -- clean: seeds ran 4/0/0/0 - the four clones (wayland_session.rs:116-119) copy the spec's domain refs into the owned dependencies Vec, the required ownership transfer; `Arc` is genuine shared ownership (see api). - -### type -- clean: seeds ran 0/0/0 - `InteractionKind`/`InteractionType` typestate comes from the shared wayland-policy engine; no boolean/string state in this crate; `DisplayChildSource` is a one-required-method trait. - -### api -- clean: seeds ran 12/2/1 - the two `Arc` signature hits (wayland_session.rs:84, 97) are genuine shared ownership: `WaylandSession` derives `Clone` and clones share the source, with `Default` supplying `SessionChildSource`; `pub use` named re-export arms (lib.rs:11-20) are the house single-surface pattern; `WaylandSessionDriver`/`WaylandSessionFactory` aliases follow the family convention. - -### err -- tail-5#10 sev=low blast=leaf effort=S verdict=actionable - `SessionChildSource::display_children` maps any `WorkerEffectError` from the display crate's child derivation to `InteractionEffectError::InvalidResource`, dropping the cause, and the crate has no tracing, so the derivation failure detail is invisible at the boundary - fix: log the source before mapping (add a tracing dependency) or preserve the specific variant - [packages/d2b-provider-wayland-session/src/wayland_session.rs:73] - evidence: err seeds s1=0, s2=0, s3=0, s4=0; read-based (the `map_err(|_| ...)` at wayland_session.rs:73 drops `WorkerEffectError` from `display_owned_child_intents`, session_children.rs:42-46) - -### serde -- N/A: seeds 0/0/0/0 all zero (spec decoding is delegated to the family's `spec_decoder` in wayland-policy; this crate defines no wire types) - -### obs -- N/A: seeds 0/0/0/0 all zero; Cargo.toml carries no tracing/log dependency (failures travel as typed error codes only) - -### docs -- clean: seeds ran 12/0/4 - `#![deny(missing_docs)]` (lib.rs:7) and every pub item carries a contract doc; the Result-returning items are `InteractionType` trait impls whose failure contract lives in the trait. - -### perf -- clean: seeds ran 0/0/0 - no format!, no grow-by-push collections, no copies; the crate is a thin declaration layer over the shared engine. - -### conc -- N/A: seeds 0/0/0/0 all zero - -### async -- N/A: seeds 0/0/0/0 all zero (no async code in this crate; the engine's async verbs live in wayland-policy) - -### unsafe -- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) - -### ffi -- N/A: seeds 0/0/0/0 all zero - -### macro -- N/A: seeds 0/0/0/0 all zero - -### test -- clean: seeds ran 6/20/0/0 - six integration tests assert the declaration surface, registry duplicate refusal (`matches!` on `ProviderDirectoryError::DuplicateType`), the four-dependency read order, foreign-row refusal (error variant), the two child rows' materialized spec/metadata content, and a refusing child source; deterministic, no `#[ignore]`. - -### Coverage -- idiom: clean (seeds ran: 0/1/0) -- own: clean (seeds ran: 4/0/0/0) -- type: clean (seeds ran: 0/0/0) -- api: clean (seeds ran: 12/2/1) -- err: 1 finding(s) -- serde: N/A (seeds: 0/0/0/0 all zero) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: clean (seeds ran: 12/0/4) -- perf: clean (seeds ran: 0/0/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0 all zero; forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 6/20/0/0) - -## d2b-provider-zone - -### idiom -- clean: seeds ran 0/0/0 - no index loops, no hand-written impls (all derives), no accumulation statements; the emitter's `match`/`Option::replace` flow is expression-shaped. - -### own -- clean: seeds ran 2/0/0/0 - the two `last_reconciled_at.clone()` hits (zone_status.rs:19, 131) are the first-borrow-then-move pattern in `emit_handler_status`/`emit`, the required copy for the two handler records; no shared-state types. - -### type -- clean: seeds ran 0/0/0 - `ZoneStatusInput` is a builder with private fields, `ZoneRuntimeMetadata` is a flat counter struct, `generation_cleanup_pending: bool` is a single flag below the stopping rule; `ZoneStatusProjectionError` is a one-variant enum carrying the stable wire code, not a flag. - -### api -- tail-5#11 sev=medium blast=leaf effort=M verdict=actionable - `pub mod zone_status;` plus `pub use zone_status::*;` (lib.rs:9-10) exposes every zone_status item at two paths (crate root and module path), violating the house single-surface pattern (named re-export arms with a private module, cf. telemetry-service lib.rs:34-36 and wayland-session lib.rs:11-20) - fix: make the module private and re-export the four items by name (`SystemCoreStatusEmitter`, `ZoneRuntimeMetadata`, `ZoneStatusInput`, `ZoneStatusProjectionError`), updating the module-path call sites - [packages/d2b-provider-zone/src/lib.rs:9-10, packages/d2b-provider-zone/src/zone_status.rs:43] - evidence: api seeds s1=11, s2=0, s3=2; census: `d2b_provider_zone::zone_status` over packages/ = 3 hits (d2bd/src/resource_runtime.rs:63-65, tests/zone_status.rs:3-4) - -### err -- clean: seeds ran 0/0/0/1 - the single error enum is a closed stable-code surface (`zone-status-projection-invalid`); no unwrap/expect/panic outside tests; the `map_err(|_| Contract)` at zone_status.rs:139 converts a caller-constructed input violation, where the stable code is the contract. - -### serde -- N/A: seeds 0/0/0/0 all zero (no wire types defined in this crate; status projection consumes contract types) - -### obs -- N/A: seeds 0/0/0/0 all zero; Cargo.toml carries no tracing/log dependency - -### docs -- tail-5#12 sev=low blast=leaf effort=S verdict=actionable - the inherent pub `SystemCoreStatusEmitter::emit` returns `Result` (zone_status.rs:113-114) without an `# Errors` section naming the contract-rejection condition - fix: add an `# Errors` section stating that duplicate system-core handler records or a rejected `ZoneStatusResource` yield `ZoneStatusProjectionError::Contract` - [packages/d2b-provider-zone/src/zone_status.rs:110-114] - evidence: docs seeds s1=10, s2=0, s3=1; `#![deny(missing_docs)]` (lib.rs:7) is satisfied but the canonical-section rule is not - -### perf -- clean: seeds ran 0/0/0 - no format!, no grow-by-push collections, no copies; `Vec::with_capacity(input_handlers.len() + 2)` (zone_status.rs:120) sizes the only allocation. - -### conc -- N/A: seeds 0/0/0/0 all zero - -### async -- N/A: seeds 0/0/0/0 all zero (the emitter is a synchronous projection; async verbs live in the runtime) - -### unsafe -- N/A: seeds 0/0/0 all zero; manifest `unsafe_code = "forbid"` (Cargo.toml [lints.rust]) - -### ffi -- N/A: seeds 0/0/0/0 all zero - -### macro -- N/A: seeds 0/0/0/0 all zero - -### test -- clean: seeds ran 5/12/0/0 - four emitter tests (exact mandatory system-core pair, malformed input cannot publish Ready, duplicate handler records rejected, metadata/timestamp projection) plus the policy-required registration shim calling the shared `assert_metadata_registration`; behavior and error assertions, deterministic, no `#[ignore]`. - -### Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (seeds ran: 2/0/0/0) -- type: clean (seeds ran: 0/0/0) -- api: 1 finding(s) -- err: clean (seeds ran: 0/0/0/1) -- serde: N/A (seeds: 0/0/0/0 all zero) -- obs: N/A (seeds: 0/0/0/0 all zero; no tracing/log dependency in Cargo.toml) -- docs: 1 finding(s) -- perf: clean (seeds ran: 0/0/0) -- conc: N/A (seeds: 0/0/0/0 all zero) -- async: N/A (seeds: 0/0/0/0 all zero) -- unsafe: N/A (seeds: 0/0/0 all zero; forbid) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (seeds ran: 5/12/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md b/docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md deleted file mode 100644 index f780d07b4..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/tail-6.md +++ /dev/null @@ -1,143 +0,0 @@ -# tail-6 - tail lane -Baseline: 6ebdd4cec | LOC audited: 2173 (excl. src/generated/**) | modules: d2b-resource-types, d2b-sk-frontend -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: whole crates - -## d2b-resource-types - -### idiom -- clean: seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 0. No index loops, no statement-style accumulation; the only hand-written impls are `Debug` (redaction, deliberate) and trait impls, which the seed shape does not match. The `while` loop in the `ALL_TYPES` const block (resource_type.rs:36-44) is const-context-required and documented. - -### own -- clean: seeds `\.clone\(\)` = 1, `\.to_owned\(\)` = 1, `Rc<|RefCell<|Arc Vec` trait signature. `Arc` handles in `DriverDescriptor`/`KernelCaller` are shared registry/seam ownership, not clones. - -### type -- clean: seeds `fn validate_\w+|fn check_\w+` = 0, `is_\w+: bool|\w+_flag: bool` = 0, `(mode|kind|state): String` = 0. State is already modelled as enums/bitflags (`AllowedSources`, `ChildCustody`, `Cardinality`, `IsolationPosture`); no boolean flag soup or stringly-typed state. - -### api -- tail-6#3 sev=medium blast=family effort=M verdict=actionable - `assert_metadata_registration` is a test-only assertion helper exported unconditionally through the crate root, while the crate already declares a `test-support` feature that no consumer enables - fix: gate the fn and its `pub use` arm behind `#[cfg(feature = "test-support")]` (or `any(test, feature = "test-support")` per the house pattern in d2b-provider-activation-nixos/Cargo.toml:16-23) and enable the feature from the 11 consumer crates' test targets - [packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72, packages/d2b-resource-types/Cargo.toml:9] - evidence: census: `assert_metadata_registration` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 13 hits; all 11 external callers are `tests/registration.rs` in d2b-provider-{command,emergency-policy,operation,quota,resource-export,resource-import,role,role-binding,seccomp-profile,zone,zone-link}; `d2b-resource-types = {` in 38 manifests, 0 with `features = ["test-support"]` -- clean: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 97 hits, seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 2 hits (descriptor.rs:76,78; operation.rs:105,108), seed `^\s*pub use ` = 11 arms. The `Arc` fields are genuine shared registry ownership (cloned by the `DriverRegistration` impl, descriptor.rs:110-113); `pub use` arms are the house single-surface pattern; remaining surface is the deliberate declaration vocabulary. - -### err -- clean: seeds `\.unwrap\(\)|\.expect\(` = 5, `let _ = |\.ok\(\);` = 0, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 0. All 5 `expect` sites sit inside `assert_metadata_registration` (metadata.rs:100-121), a test-support assertion helper; no panic sites in library paths. `OperationFailure` carries a closed `&'static str` code mirroring the repo's wire error-code convention. - -### serde -- N/A (seeds: 0/0/0/0 all zero; no serde derives, no hand-written deserializers, no JSON calls - the crate crosses no wire boundary) - -### obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 0, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0. Declaration crate emits no telemetry. - -### docs -- tail-6#5 sev=low blast=leaf effort=S verdict=actionable - doc comment typos in `OperationCtx::fds` ("invocation,when any", "frame,not to the handler; the handler") - fix: restore the missing spaces after the commas in the field docs - [packages/d2b-resource-types/src/operation.rs:64, packages/d2b-resource-types/src/operation.rs:65] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 97 hits, read all; seed `/// # (Examples|Errors|Panics|Safety)` = 0; seed `-> Result<` = 1. `#![deny(missing_docs)]` (lib.rs:6) is active; every public item is documented; the two typo lines are the only defects found. -- clean: seeds run as above; all 97 public items documented with first-sentence-shaped docs under `#![deny(missing_docs)]` (lib.rs:6); no canonical-section or magic-value gaps found beyond the typo finding. - -### perf -- clean: seeds `format!\(` = 0, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 1, `\.to_string\(\)` = 0. The single `Vec::new()` (operation.rs:179) is a cold result-construction path; no hot-path allocation. static (unmeasured). - -### conc -- N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or orderings in the crate) - -### async -- clean: seeds `async fn|async move|\.await` = 3, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0. The three hits are the `#[async_trait] OperationHandler::execute` (operation.rs:49) and the async test-support helper (metadata.rs:72,113); no runtime, spawn, or blocking work. - -### unsafe -- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks/fns/impls, no SAFETY comments, no transmute/raw-pointer use, no `unsafe_code` allow manifest) - -### ffi -- N/A (seeds: 0/0/0/0 all zero; no extern declarations, no repr(C), no CStr/CString) - -### macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro machinery) - -### test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 7, `assert_eq!\(|assert_ne!\(|assert!\(` = 39 (incl. 17 asserts in the shared test-support helper), `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0. Seven unit tests in three modules (allowed_sources.rs, child_creation.rs, resource_type.rs) assert behavior with messages; the shared `assert_metadata_registration` helper centralizes the per-type registration coverage for 11 consumer crates. - -### Coverage -- idiom: clean (seeds ran: 0/0/0) -- own: clean (1/1/0/0) -- type: clean (0/0/0) -- api: 1 finding -- err: clean (5/0/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no wire boundary) -- obs: clean (0/0/0/0) -- docs: 1 finding -- perf: clean (0/1/0) -- conc: N/A (seeds: 0/0/0/0 all zero; no threads/locks/atomics) -- async: clean (3/0/0/0) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe constructs) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: clean (7/39/0/0) - -## d2b-sk-frontend - -### idiom -- tail-6#1 sev=low blast=leaf effort=S verdict=actionable - `zone_path` accumulates labels with a `let mut Vec` + push loop where an iterator pipeline collects - fix: replace the loop with `value.split('/').map(|label| ZoneLabelId::parse(label).map_err(|_| format!("{name} is not a valid Zone label path"))).collect::, String>>()?` before `ZonePath::new(labels)` - [packages/d2b-sk-frontend/src/config.rs:178] - evidence: seed `let mut \w+ = (String|Vec)::new\(\)` = 1 hit (config.rs:178); seeds `for \w+ in 0\.\.` = 0, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0 -- clean: seeds run as above; the one hit is the finding; hand-written `Debug` impls (agent.rs:145-148, uhid.rs:77-105) are deliberate redaction. - -### own -- tail-6#2 sev=low blast=leaf effort=S verdict=actionable - `main` clones the whole `PlacementConfig` (owned `ZoneEnrollmentIdentity` inside) only to keep `config` alive for its other fields, and `config.rs` builds `"/dev/uhid".to_owned()` where `PathBuf::from` suffices - fix: destructure `let Config { vm_id, link, uhid_path, placement } = config;` and call `placement.into_placement()` (drop the clone); write `PathBuf::from("/dev/uhid")` via `optional("D2B_SK_UHID_PATH").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/dev/uhid"))` - [packages/d2b-sk-frontend/src/main.rs:55, packages/d2b-sk-frontend/src/config.rs:83] - evidence: seed `\.clone\(\)|\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 6 hits; 2 avoidable (main.rs:55, config.rs:83); the rest are required conversions (agent.rs:178 `to_vec` for `GuestFrame::new`, config.rs:88/91/108 owned error strings) -- clean: seeds run as above; no `Rc<|RefCell<|Arc>` device lifecycle is a deliberate once-init shape. - -### api -- tail-6#4 sev=low blast=leaf effort=S verdict=actionable - `pub mod agent/config/link/uhid` plus root `pub use` re-exports make every item reachable at two paths, deviating from the house single-surface pattern; only the binary needs a module path - fix: make the four modules private (`mod agent; ...`) and re-export `UhidDevice` (and `UhidEvent`) from lib.rs, updating main.rs:41 to `use d2b_sk_frontend::{Config, SecurityKeyFrontend, UhidDevice, VsockAllocatorLink}` - [packages/d2b-sk-frontend/src/lib.rs:22, packages/d2b-sk-frontend/src/lib.rs:27, packages/d2b-sk-frontend/src/main.rs:41] - evidence: seed `^\s*pub use ` = 3 arms (lib.rs:27-29) alongside `pub mod` x4 (lib.rs:22-25); census: `d2b_sk_frontend::(agent|config|link|uhid)::` over packages/, nixos-modules/, tests/, docs/reference/, labs/, BUILD.bazel/*.bzl = 0 full-path hits, and the zone-routing test consumer uses the root re-exports (tests/guest_enrollment.rs:210,422), so only main.rs:41's group-import form needs the module path -- clean: seed `\bpub (fn|struct|enum|trait|type|const|mod) ` = 25 hits, seed `pub .*\b(Arc|Rc|Box|RefCell)<` = 0. No internals leak into signatures beyond the double-path shape above. - -### err -- clean: seeds `\.unwrap\(\)|\.expect\(` = 1, `let _ = |\.ok\(\);` = 1, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 0, `enum \w*Error` = 0. The expect is in a `#[cfg(test)]` test (config.rs:213); the `let _ = event_type;` (uhid.rs:203) silences an unused binding, not a `Result`. `Config::from_env` returns `String` errors consumed once by the binary's `exit_on_error` print - acceptable binary-boundary shape. - -### serde -- N/A (seeds: 0/0/0/0 all zero; no serde derives or JSON crossing - the crate's wire surface is the toolkit's session framing, not serde) - -### obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 2, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0. Both `eprintln!` sites are the binary's own startup banner and fatal-error output (main.rs:47,57) - product output, not telemetry; the library half emits nothing. - -### docs -- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 29 hits, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 5. `#![deny(missing_docs)]` (lib.rs:6) is active; all 29 public items and the `Result`-returning fns (from_env, into_placement, create, read_event, send_input_report) carry first-sentence-shaped prose docs; the UHID constants document their kernel-header provenance. - -### perf -- clean: seeds `format!\(` = 16, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 2, `\.to_string\(\)` = 0. All `format!` sites are error paths (config.rs), one-shot device creation (uhid.rs:275), or tests (uhid.rs:481); the event builders pre-size with `with_capacity` and read into a stack buffer. static (unmeasured). - -### conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 2, `Atomic\w+|Ordering::` = 0, `thread_local!|unsafe impl (Send|Sync) for` = 0. The two `Mutex<` hits are `tokio::sync::Mutex` (agent.rs:105,133) - async-aware primitives judged under the async lens; no threads, atomics, or manual Send/Sync claims. - -### async -- clean: seeds `async fn|async move|\.await` = 39, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 1, `#\[tokio::(main|test)\]|Runtime::block_on` = 0. The device I/O uses the sanctioned `AsyncFd` + `try_io` readiness loops over `rustix::io` (uhid.rs:233-259, the clippy.toml replacement vocabulary), `tokio::fs` open with `into_std().await` (uhid.rs:156-163), and `tokio::sync::Mutex`/`OnceCell` guards held across awaits (agent.rs:133-141,166-177) - all async-aware; no std guards across `.await`, no executor blocking, no runtime started in the library. - -### unsafe -- N/A (seeds: 0/0/0/1; the only hits are `#![forbid(unsafe_code)]` (lib.rs:20) and two `io::Error::from_raw_os_error` std-safe calls (uhid.rs:238,251) matching seed 3's `from_raw` substring - no unsafe blocks/fns/impls exist, and the manifest is `deny`, not `allow`) - -### ffi -- N/A (seeds: 0/0/0/0 all zero; no extern declarations, no repr(C), no CStr/CString - `libc::O_NONBLOCK` and `rustix::io` are syscall bindings, not an FFI surface) - -### macro -- N/A (seeds: 0/0/0/0 all zero; no macro_rules!, no proc-macro machinery) - -### test -- tail-6#6 sev=medium blast=leaf effort=S verdict=actionable - the parse side of the byte-exact UHID protocol (`read_event`'s event-type dispatch, the OUTPUT size field at payload[4096], GET_REPORT id, lifecycle mapping, short-header error) has no test while the builders have 12 byte-exact tests, so a regression in the parse offsets passes the suite - fix: extract `parse_event(buf: &[u8]) -> io::Result>` from `read_event` and table-test the dispatch against hand-built buffers (plus a `build_get_report_reply_error` layout test) - [packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186] - evidence: seed `#\[test\]|#\[tokio::test\]` = 14 hits (12 in uhid.rs, 2 in config.rs); seed `assert_eq!\(|assert_ne!\(|assert!\(` = 24; none of the uhid.rs tests exercise `read_event` or `build_get_report_reply_error` (uhid.rs:283-299) -- clean: seeds run as above; the 14 tests are behavior-focused with messages, deterministic, and byte-exact for the builders; no `#[ignore]` (0), no property/snapshot tooling (0). - -### Coverage -- idiom: 1 finding -- own: 1 finding -- type: clean (0/0/0) -- api: 1 finding -- err: clean (1/1/0/0) -- serde: N/A (seeds: 0/0/0/0 all zero; no serde wire crossing) -- obs: clean (2/0/0/0) -- docs: clean (29/0/5) -- perf: clean (16/2/0) -- conc: clean (0/2/0/0) -- async: clean (39/0/1/0) -- unsafe: N/A (seeds: 0/0/0/1; no real unsafe constructs, forbid is seed 4 only) -- ffi: N/A (seeds: 0/0/0/0 all zero) -- macro: N/A (seeds: 0/0/0/0 all zero) -- test: 1 finding \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md deleted file mode 100644 index f85679079..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p1.md +++ /dev/null @@ -1,91 +0,0 @@ -# xtask-p1 - xtask - part 1/5 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8903 (excl. src/generated/**; policy range 5354-11075 of provider_crate_policy.rs) | modules: provider_crate_policy.rs (5354-11075), main.rs, gen_layer_catalogs.rs, provider_registration_authority.rs, service_catalog.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: provider_crate_policy.rs:5354-11075 (item-range split; sed line + 5353 = absolute) - -## idiom -- xtask-p1#1 sev=medium blast=leaf effort=S verdict=actionable - gen_layer_catalogs.rs has two byte-identical helpers under different names: `string_slice` and `string_array` share the same signature and body (both emit a `pub const : &[&str]` array), so callers guess which to use and a future shape change drifts only one copy - fix: delete `string_array` and route its 10 call sites (lines 299, 362, 367, 456, 466, 471, 496, 507, 512, 517) through `string_slice`, keeping `string_pair_slice` for the tuple case - [packages/xtask/src/gen_layer_catalogs.rs:147, packages/xtask/src/gen_layer_catalogs.rs:158] - evidence: seed `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0; static comparison of the two function bodies; census: `string_(slice|array)\(` over packages/xtask/src = 14 hits -- xtask-p1#2 sev=low blast=leaf effort=M verdict=actionable - emitted Rust source is embedded as single-line escaped string literals with backslash line continuations (`"... \n \` chains, e.g. the `typed_noun_type` block), making the generator bodies unreadable and brittle to edit; a reviewer cannot diff the embedded code - fix: embed the emitted blocks as raw string literals (the content contains `"` but not `"##`, so `r##"..."##` delimiters work) in `surface_catalog_source` and in `redact_generated_protobuf_formatting`'s `raw_display`/`redacted_formatting` templates - [packages/xtask/src/gen_layer_catalogs.rs:377, packages/xtask/src/main.rs:473] - evidence: seed `format!\(` = 115 in lane; static (unmeasured) - the escaped-string sites read at gen_layer_catalogs.rs:297-453 and main.rs:473-528 -- xtask-p1#3 sev=medium blast=leaf effort=M verdict=actionable - the daemon-api IPC collector (`parse_rust_items` + `IpcItemCollector`) parses files with `syn`, then slices the original source text back out and re-parses fields and variants with ~150 lines of hand-rolled scanners (`parse_fields`, `parse_variants`, `split_top_level_entries`, `extract_body`, `strip_non_code_lines`, `normalize_ws`, `line_col_to_offset`), duplicating what the `syn` AST already provides and re-implementing angle-bracket depth counting for generics - fix: in `visit_item_struct`/`visit_item_enum`, extract `Field { name, ty }` and variants from `syn::Fields`/`syn::Variant` directly (type text via `quote::ToTokens`), then delete the text parsers and `line_col_to_offset`'s per-span O(n) scan - [packages/xtask/src/main.rs:1031, packages/xtask/src/main.rs:1142, packages/xtask/src/main.rs:1203] - evidence: seed `for \w+ in 0\.\.` = 1 (main.rs:530, a bounded retry loop, not an index loop); the parse chain read at main.rs:1112-1245 -- xtask-p1#4 sev=low blast=leaf effort=S verdict=actionable - `sanitize_generated_rust` contains a corrupted replacement literal `"#![allow(clipto_camel_casepy)]\n"` that can never match any generator output, so the sanitizer silently keeps whatever attribute the line was meant to strip in the committed generated file - fix: replace the literal with the actual protobuf/ttrpc-emitted marker it targets (or delete the line if the marker is no longer emitted) at main.rs:459 - [packages/xtask/src/main.rs:459] - evidence: seed `generated\.replace` (static); `clipto_camel_casepy` occurs once in the workspace (packages/xtask/src/main.rs:459); the surrounding replace chain read at main.rs:454-472 -- xtask-p1#5 sev=low blast=leaf effort=S verdict=actionable - in `collect_self_binding_scope` the row-close reset block at provider_crate_policy.rs:6662 is dead: a line whose trim equals `}` cannot also contain `SeedSelfBinding`, so the inner reset never fires, its comment describes behavior that never runs, and the inner scan has no exit at the row close (it runs to EOF for every `SeedProvider {`) - fix: drop the dead inner condition, reset `pending_subject`/`pending_role` when `code_text(lines[stop]).trim() == "}"`, and `break` the `while stop < lines.len()` loop there - [packages/xtask/src/provider_crate_policy.rs:6662, packages/xtask/src/provider_crate_policy.rs:6612] - evidence: seed `fn validate_\w+|fn check_\w+` = 17 (the `check_*` family this scanner belongs to); static reading of the block at provider_crate_policy.rs:6608-6672 - -## own -- xtask-p1#6 sev=low blast=leaf effort=S verdict=actionable - `apply_citation_fixes` clones `lines[index]` before mutating it (`let mut line = lines[index].clone();`) although the slot is borrowed `&mut` and then reassigned on the same iteration - fix: `let mut line = std::mem::take(&mut lines[index]);` per the skill's `mem::take` pattern - [packages/xtask/src/provider_crate_policy.rs:7257] - evidence: seed `\.clone\(\)` = 21 in lane (non-test policy range: 16); the site is the mutate-then-reassign shape at provider_crate_policy.rs:7255-7262 -- xtask-p1#7 sev=low blast=leaf effort=S verdict=actionable - two ratchet lookups build an owned tuple just to call `BTreeSet::contains`, allocating a cloned String per signal during tree-wide scans (`family_exempt.contains(&(signal.module.clone(), token))` and `exempt.contains(&(signal.crate_name.clone(), signal.module.clone(), signal.token))`) - fix: replace `contains` with `family_exempt.iter().any(|(module, token)| *module == signal.module && *token == token)` (and the 3-tuple equivalent), or key both sets on `&str` like the neighboring `structural_exempt` set - [packages/xtask/src/provider_crate_policy.rs:6375, packages/xtask/src/provider_crate_policy.rs:8750] - evidence: seed `\.clone\(\)` = 21 in lane; both sites read in context (provider_crate_policy.rs:6369-6378 and 8746-8753); no Rc/RefCell/Arc/Cow hits (0/0) -The remaining 17 clones and the sampled `to_owned`/`to_string` hits (every 8th of 128) all move borrowed scanner values into owned outputs or clone to descend clap subcommands (main.rs:902) - each explainable. - -## type -- xtask-p1#8 sev=low blast=leaf effort=S verdict=actionable - `process_provider_ids(metric_label: Option)` uses an optional boolean to select among three label domains (all, metric-only, plus an unreachable `Some(false)` state) where the two production call sites only ever pass `None` or `Some(true)` - fix: split into `all_process_provider_ids()` and `metric_process_provider_ids()` (or a two-variant enum), and update the call sites at gen_layer_catalogs.rs:370, 474, 515 - [packages/xtask/src/gen_layer_catalogs.rs:288, packages/xtask/src/gen_layer_catalogs.rs:515] - evidence: seed `(mode|kind|state): String` = 0; seed bool-flag = 0; the Option parameter shape read at gen_layer_catalogs.rs:288-295 and its call sites - -## api -- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod) ` = 42 (9 real items, the rest template strings and doc mentions), `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 0. The part's surface is `pub fn check`/`pub fn regenerate` in service_catalog.rs:46,78 and provider_registration_authority.rs:65,84, `pub fn run_cli` in gen_layer_catalogs.rs:584, `pub fn fix` in provider_crate_policy.rs:7181, plus `pub(crate) const GENERATED_ARTIFACT` in two modules - every item is doc-commented, nothing leaks Arc/Rc or dependency types, and the crate is a binary (bin-only crates get no missing_docs). - -## err -- clean: seeds ran: `\.unwrap\(\)|\.expect\(` = 159 (main 4, gen_layer_catalogs 6, provider_registration_authority 24, policy range 125 - all 125 policy hits and the other 34 sit inside `#[cfg(test)]` modules), `let _ = |\.ok\(\);` = 14 (test helpers plus the deliberate best-effort `let _ = fs::remove_dir_all` at main.rs:409), `panic!\(|unreachable!\(|todo!\(|unimplemented!\(` = 3 (main.rs:901 startup invariant, main.rs:1597 cfg(test) helper, one in policy tests), `enum \w*Error` = 0. No production-code unwrap/expect or swallowed Result in the lane; error reporting is `Result<_, String>` with canonical JSON diagnostics, which suites this CLI-policy context. - -## serde -- xtask-p1#9 sev=medium blast=leaf effort=S verdict=actionable - `service_catalog.rs`'s `DeclarationFile` parses the committed per-crate `service-catalog.json` with `#[derive(Deserialize)]` and no `deny_unknown_fields`, while the sibling `RegistrationDeclaration` parsing `registrations.json` denies unknowns (`provider_registration_authority.rs:54`); a typo'd key in a declaration (e.g. `providerUid` misspelled) is silently ignored and the daemon's fixed-UID row silently disappears instead of failing the gate - fix: add `#[serde(deny_unknown_fields)]` to `DeclarationFile` - [packages/xtask/src/service_catalog.rs:22, packages/xtask/src/provider_registration_authority.rs:54] - evidence: seeds ran: `derive\([^)]*(De)?[Ss]erialize` = 4, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 5; the sibling-type comparison is direct line reading of the two declaration structs -The other serde shapes (camelCase rename on `RegistrationDeclaration`, `#[serde(default)]` optionality on provider_uid/services/wire_variant, `BrokerOperations` projecting only two of a row's many committed fields - deliberate, documented) are all sound; no hand-written Deserialize impls and no wire round-trips in the lane. - -## obs -- clean: seeds ran: `\bprintln!\(|\beprintln!\(` = 16 (all in main.rs; those lines are the CLI's product output - artifact paths, usage, failures - and one in policy tests), `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 3 (false positives: `changelog::` subcommand paths). No telemetry exists in this crate; user-facing stdout is the output, per the skill's CLI carve-out. - -## docs -- xtask-p1#10 sev=low blast=leaf effort=S verdict=actionable - doc comments across the policy range carry text-corruption artifacts from an earlier automated rewrite: 20 lines end with a stray `/` after the closing period (`/// ... only shrinking from here./`) and 4+ comments have doubled opening parens (`((its Cargo package name).`, `((an edit to a`), plus the typo `whiche is what`; the artifacts render as odd punctuation in rustdoc and rot the file's readability - fix: mechanical doc cleanup over the file: replace `\./$` with `.` and `((`-doubles with single parens on the doc lines (lines 5360-6556 and 8428, 8640, 8648, 9043) - [packages/xtask/src/provider_crate_policy.rs:5360, packages/xtask/src/provider_crate_policy.rs:8428, packages/xtask/src/provider_crate_policy.rs:9043] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 9; the artifact pattern `^\s*//[/!] .*\./$` = 20 and `^\s*//[/!].*\(\(` = 4 within the policy range 5354-9438 -- xtask-p1#11 sev=low blast=leaf effort=S verdict=actionable - `civil_from_days` (a port of the Howard Hinnant civil-calendar conversion) carries magic constants (719_468, 146_097, 146_096, 36_524, 153) with no citation or why, and `today_utc_iso8601` silently maps a before-epoch clock to epoch via `unwrap_or(0)` - fix: add a doc comment naming the algorithm and its constants, and decide the before-epoch behaviour explicitly (return an error or a documented fallback) - [packages/xtask/src/main.rs:1555, packages/xtask/src/main.rs:1544] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = 9; the magic-number block read at main.rs:1544-1568 - -## perf -- xtask-p1#12 sev=low blast=leaf effort=S verdict=actionable - `message_only_proto` calls `trimmed.starts_with(&format!("service {service_name} "))` inside the per-line loop, allocating a String on every line of the proto file when the prefix never changes - fix: hoist `let marker = format!("service {service_name} ");` (or compare `trimmed.strip_prefix("service ")` then the name) above the loop - [packages/xtask/src/main.rs:431] - evidence: seed `format!\(` = 115 in lane; site is a loop-body allocation, cold CLI path - static (unmeasured) -- xtask-p1#13 sev=low blast=leaf effort=S verdict=actionable - `repo_root()` returns `Ok(Box::leak(path.into_boxed_path()))`, so every successful call leaks a heap allocation and re-scans env vars and parent directories; it is called by nearly every command handler - fix: cache the result once, e.g. `static ROOT: OnceLock<&'static Path>` (std, no dependency) computed on first call - [packages/xtask/src/main.rs:582] - evidence: seed `\.to_string\(\)` = 35 and `Vec::new\(\)` family = 68 in lane; the leak site read at main.rs:558-590 - static (unmeasured) -- xtask-p1#14 sev=low blast=leaf effort=S verdict=actionable - `render_schema(&RootSchema)` clones the entire schema document (large `serde_json::Value` trees for the 19 `schema_for!` documents) only to override `meta_schema` before serializing - fix: have `write_schemas` take ownership of the `Vec<(&str, RootSchema)>` and mutate each schema in place (callers already hold the schemas by value from `schema_documents()`) - [packages/xtask/src/main.rs:972] - evidence: seed `format!\(` = 115 in lane; the clone-then-mutate shape read at main.rs:958-978, called from gen_schemas/gen_cli_schemas/gen_zone_storage_schema - static (unmeasured) - -## conc -- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 3, `thread_local!|unsafe impl (Send|Sync) for` = 0. The only concurrency in the lane is a test-fixture `AtomicU32` counter plus `Ordering::Relaxed` in the policy tests module (provider_crate_policy.rs:9440-9455); production code has no threads, locks, or atomics. - -## async -- N/A (seeds: `async fn|async move|\.await` = 0, `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` = 0, `tokio::sync::(Mutex|RwLock|Notify)` = 0, `#\[tokio::(main|test)\]|Runtime::block_on` = 0 - all zero; the lane declares no async fn and no runtime usage) - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0, `// SAFETY:` = 0, `transmute|from_raw|MaybeUninit|mem::zeroed` = 0 - all zero; the crate manifest sets `unsafe_code = "forbid"` and the single `unsafe_code` string in main.rs:456 is the sanitizer's removal literal, not code; per the card, seed 4 alone does not make the lens applicable) - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0, `catch_unwind` = 0, `repr\(C\)|repr\(transparent\)` = 0, `CStr|CString|c_char` = 0 - all zero; the lane crosses no FFI boundary) - -## macro -- clean: seeds ran: `macro_rules!` = 3, `proc_macro|syn::|quote!` = 15, `\$crate` = 0, `to_compile_error|new_spanned` = 0. No macro definitions exist in the lane: the `macro_rules!` hits are a doc-comment mention (main.rs:1054) and the citation scanner's `item_binding` matcher (provider_crate_policy.rs:7721), and the `syn::` hits are the IPC visitor using `syn` as a parsing library, not a proc macro; `proc_macro_deps` hits are BUILD-attribute strings in docs and scanner constants. - -## test -- xtask-p1#15 sev=low blast=leaf effort=S verdict=actionable - the broker-operation domain test recomputes its expectation with the same filter the function under test applies (`catalog.rows.iter().filter_map(|row| row.wire_variant.clone())` re-derives `broker_operation_values`' own pick), so the `assert_eq!(values, expected)` can never disagree with the projection logic; only the human-written pins (`UsbipBind` present, `SpawnRunner`/`vmStart` absent) carry behaviour - fix: drop the recomputed `expected` and assert the human-written pins only (the vector equality adds nothing the pins do not) - [packages/xtask/src/gen_layer_catalogs.rs:705] - evidence: seeds ran: `#\[test\]|#\[tokio::test\]` = 155 (61 in the policy tests module, 79 in xtask/tests/**), `assert_eq!\(|assert_ne!\(|assert!\(` = 471, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the same-logic expectation read at gen_layer_catalogs.rs:694-720 -The remaining suite is behavior-first (fixture trees exercising both gate directions, committed-tree ratchet pins, drift and idempotence tests in provider_registration_authority.rs and main.rs; all policy unwraps live in `#[cfg(test)]`); no `#[ignore]`, no property/snapshot tooling (snapshot pins instead live in `xtask/tests/**` and the policy ratchet tests). - -## Coverage -- idiom: 5 finding(s) -- own: 2 finding(s) -- type: 1 finding(s) -- api: clean (seeds ran: 42/0/0) -- err: clean (seeds ran: 159/14/3/0) -- serde: 1 finding(s) -- obs: clean (seeds ran: 16/0/0/3) -- docs: 2 finding(s) -- perf: 3 finding(s) -- conc: clean (seeds ran: 0/0/3/0) -- async: N/A (seeds: 0/0/0/0 all zero; no async fn, spawn, or runtime in the lane) -- unsafe: N/A (seeds: 0/0/0 all zero; manifest forbids; seed 4 alone not applicable) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: clean (seeds ran: 3/15/0/0) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md deleted file mode 100644 index 8ae6a1357..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p2.md +++ /dev/null @@ -1,71 +0,0 @@ -# xtask-p2 - xtask - part 2/5 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8954 (excl. src/generated/**) | modules: provider_crate_policy.rs:1-5353, gen_broker_operations.rs, delivery/eligibility.rs, diagnostic_redaction.rs, delivery/history_proof.rs -Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: provider_crate_policy.rs:1-5353 (item-range split; absolute line = sed line) - -## idiom -- clean: seeds `for \w+ in 0\.\.` = 1, `impl (Default|From|PartialEq|Eq|Debug|Clone|Hash) for` = 0, `let mut \w+ = (String|Vec)::new\(\)` = 18; the one index loop (diagnostic_redaction.rs:284 `for _ in 0..overflow`) is the idiomatic repeat-n form, the hand-rolled scanners (identifier_words, string_literal_spans, driver_declarations, normalize_ansi_escape_sequences) are byte/indent state machines with no stdlib equivalent, and the `let mut rows = String::new()` accumulators are generator text builders whose artifact is the emitted file. - -## own -- xtask-p2#1 sev=low blast=leaf effort=S verdict=actionable - `check_members(&repo_root, members.clone())` clones the whole workspace-member vec at the check entry point because `check_members` (provider_crate_policy.rs:7916) takes `Vec` by value while its body only reads it (`.iter()`, `.iter().map()`); the signature forces the clone - fix: change `fn check_members(repo_root: &Path, members: &[WorkspaceMember])` and drop the clone at the call site (second caller at 9560 passes `&manifest_workspace_members(&root)?`) - [packages/xtask/src/provider_crate_policy.rs:577, packages/xtask/src/provider_crate_policy.rs:7916] - evidence: seed `\.clone\(\)` = 47 hits in lane; signature read at 7916-7918 shows read-only use -- xtask-p2#2 sev=low blast=leaf effort=S verdict=actionable - `check_shared_family_knowledge_with` builds `exempt: BTreeSet<(String, &str)>` with `row.module.to_owned()` and probes it with `signal.module.clone()`, when the ratchet rows are `&'static str` and the signal already owns a `String`; both the build-time to_owned and the per-signal clone disappear by keying borrowed strs - fix: `let exempt: BTreeSet<(&str, &str)> = ratchet.iter().map(|row| (row.module, row.token)).collect()` and probe `exempt.contains(&(signal.module.as_str(), signal.token))` - [packages/xtask/src/provider_crate_policy.rs:5200, packages/xtask/src/provider_crate_policy.rs:5206] - evidence: seeds `\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)` = 135, `\.clone\(\)` = 47; sites 5200/5206 read -- xtask-p2#3 sev=low blast=leaf effort=S verdict=actionable - `profile_catalog` clones every row's `wire_variant` String (`row.wire_variant.clone()`) only to format it into the generated profile catalog text; the values are never mutated or stored - fix: return `Vec<&str>` via `.filter_map(|row| row.wire_variant.as_deref())` and change `string_list` (gen_broker_operations.rs:772) to take `Item = &str` (its only two call sites are 860-861) - [packages/xtask/src/gen_broker_operations.rs:844, packages/xtask/src/gen_broker_operations.rs:772] - evidence: seed `\.clone\(\)` = 47 hits in lane; string_list call sites verified at 860-861 - -## type -- xtask-p2#4 sev=low blast=leaf effort=S verdict=actionable - `FamilyKnowledgeSignal.text: String` (provider_crate_policy.rs:4664-4675) carries two meanings discriminated only by `class`: literal/identifier text for Literal/Assembled/Identifier, and a serialized count for ServerState (`text: format!("{server_state_count}")` at 5104) that the renderer re-parses (`signal.text.parse::().unwrap_or(0)` at 5179), silently defaulting a non-numeric to 0 - fix: add a typed `count: Option` field (or split the struct per class), fill it at 5104, and render by matching `class` without the parse - [packages/xtask/src/provider_crate_policy.rs:5104, packages/xtask/src/provider_crate_policy.rs:5179] - evidence: seeds `fn validate_\w+|fn check_\w+` = 12, `(mode|kind|state): String` = 5 (3 are `artifact_kind` false positives); sites 5104/5179 read - -## api -- clean: seeds `\bpub (fn|struct|enum|trait|type|const|mod) ` = 27, `pub .*\b(Arc|Rc|Box|RefCell)<` = 0, `^\s*pub use ` = 0; xtask is a bin-only crate (no lib target, publish = false, packages/xtask/Cargo.toml), so the pub items are crate-internal surface with no external callers to break; no internals-in-signature shapes and no re-export arms exist. - -## err -- clean: seeds `\.unwrap\(\)|\.expect\(` = 94, `let _ = |\.ok\(\);` = 2, `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 4, `enum \w*Error` = 0; 90 of the 94 unwrap/expect hits sit in `#[cfg(test)]`; the four production hits are invariant-named expects on literally-built values (provider_crate_policy.rs:446, gen_broker_operations.rs:1155), an expect after a check the compiler cannot see (gen_broker_operations.rs:423, guarded by the pair check at 404), and `unreachable!` arms after closed-set validation (530, 913, 926, 1037); the two `let _ =` sites (diagnostic_redaction.rs:412, 421) are deliberate best-effort temp-dir cleanup. - -## serde -- clean: seeds `derive\([^)]*(De)?[Ss]erialize` = 22, `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 42, `impl .*Deserialize.*for` = 0, `serde_json::from_|serde_json::to_` = 11; every wire shape uses `rename_all` plus `deny_unknown_fields` with closed-set validation in `validate_row`/`parse_text`, the three optionality meanings are used correctly (`#[serde(default)]` vs `Option` vs `skip_serializing_if`), and `CheckConclusion`/`HistoryVerdict` fail closed on unknown conclusions; no hand-written deserializers. - -## obs -- clean: seeds `\bprintln!\(|\beprintln!\(` = 1, `(info|debug|warn|error|trace)!\("` = 0, `\.instrument\(|#\[instrument` = 0, `tracing::|log::` = 0; the single eprintln! (diagnostic_redaction.rs:379) is the operator-facing failure line of a CLI filter whose stderr is the product output, not telemetry; no tracing/log dependency in the lane. - -## docs -- clean: seeds `^\s*pub (fn|struct|enum|trait|const|type)` = 25, `/// # (Examples|Errors|Panics|Safety)` = 0, `-> Result<` = 40; bin-only crate, so per the card's false-positive note undocumented pub items are not findings; all five files carry a `//!` module doc and every public entry point (run, run_capture, evaluate, open_sealed_candidate, prove, gen_broker_operations, check) has a doc comment whose first sentence carries the contract. - -## perf -- clean: seeds `format!\(` = 143, `Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)` = 21, `\.to_string\(\)` = 17; every hit is an error path, a one-shot policy diagnostic, or a generator text builder whose artifact is the emitted file (card false positive); the only bounded-buffer code (read_diagnostic_tail, VecDeque::with_capacity at the 4 MiB cap) is deliberate; all findings would be static (unmeasured) and none rises to a proposal. - -## conc -- clean: seeds `std::thread::|thread::spawn|thread::scope` = 0, `\bMutex<|\bRwLock<` = 0, `Atomic\w+|Ordering::` = 3, `thread_local!|unsafe impl (Send|Sync) for` = 0; the only atomic is the test-only `SCRATCH_SEQUENCE: AtomicU32` (diagnostic_redaction.rs:393-408) used with Relaxed ordering, the weakest correct ordering for a scratch-dir uniquifier. - -## async -- N/A (seeds: 0/0/0/0 all zero; no async fn, no .await, no spawn, no runtime in the lane) - -## unsafe -- N/A (seeds: 0/0/0 all zero; packages/xtask/Cargo.toml sets `unsafe_code = "forbid"`) - -## ffi -- N/A (seeds: 0 all zero; no extern surface, no repr(C)/repr(transparent), no CStr/CString in the lane) - -## macro -- N/A (seeds: 0 all zero; no macro_rules!, no proc-macro, no $crate in the lane) - -## test -- clean: seeds `#\[test\]|#\[tokio::test\]` = 138 (59 in-module across the five files, 79 in tests/), `assert_eq!\(|assert_ne!\(|assert!\(` = 382, `proptest!|insta::assert|rstest` = 0, `#\[ignore\]` = 0; the in-module tests for all five files are behavior assertions with failure messages and table-driven cases (eligibility.rs:717-734 loops over every non-success conclusion; gen_broker_operations.rs:1327-1334 proves the triage view moves byte-for-byte with a row edit; diagnostic_redaction.rs:520-586 exercises truncation, multibyte splits, and malformed bytes); no test that cannot fail was found. - -## Coverage -- idiom: clean (seeds ran: 1/0/18) -- own: 3 finding(s) -- type: 1 finding(s) -- api: clean (seeds ran: 27/0/0) -- err: clean (seeds ran: 94/2/4/0) -- serde: clean (seeds ran: 22/42/0/11) -- obs: clean (seeds ran: 1/0/0/0) -- docs: clean (seeds ran: 25/0/40) -- perf: clean (seeds ran: 143/21/17) -- conc: clean (seeds ran: 0/0/3/0) -- async: N/A (seeds: 0/0/0/0 all zero; no async code in lane) -- unsafe: N/A (seeds: 0/0/0 all zero; unsafe_code = "forbid" in packages/xtask/Cargo.toml) -- ffi: N/A (seeds: 0 all zero; no FFI surface) -- macro: N/A (seeds: 0 all zero; no macros) -- test: clean (seeds ran: 138/382/0/0) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md deleted file mode 100644 index 5e543e777..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p3.md +++ /dev/null @@ -1,75 +0,0 @@ -# xtask-p3 - xtask - part 3/5 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 8936 (excl. src/generated/**) | modules: delivery/recovery, delivery/command, delivery/snapshot, resource_type_authority, provider_packaging, semantic_service_schemas, deadcode, authority_common, bin/manifest_v04_check -Lenses: idiom own type api err serde obs docs perf conc async unsafe ffi macro test | Partitions: part 3/5 (U1 section f: the nine files above) - -## idiom -- xtask-p3#1 sev=low blast=leaf effort=S verdict=actionable - resource_type_authority.rs carries misindented statements (`errors.push(format!(` at column 0, `out.push_str("// @generated\n");` at column 0, `fn drop` under-indented by 4) that rustfmt would reflow; the repo runs no fmt gate, so the drift is committed - fix: reindent the statements at the three sites (or run rustfmt over the file once) - [packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_authority.rs:940, packages/xtask/src/resource_type_authority.rs:1083] - evidence: idiom seed 3 (`let mut \w+ = (String|Vec)::new\(\)`) 15 hits, each hit neighborhood read; the misindented statements were found while reading the seed-3 hits -- xtask-p3#2 sev=low blast=family effort=S verdict=needs-contract - generator string literals in resource_type_authority.rs drop spaces, so the committed generated artifact header reads "Provenance:emitted", "; the layout check's" and "byte-for-byte,and", and the type-declared-twice diagnostic reads "declared by both {}and {}" - fix: restore the spaces in the four push_str literals and the format string, then regenerate the artifact via `cargo xtask check-provider-crate-layout --fix` so the drift gate and the committed `v3_converted_resource_types.rs` move together - [packages/xtask/src/resource_type_authority.rs:704, packages/xtask/src/resource_type_authority.rs:940, packages/xtask/src/resource_type_authority.rs:941, packages/xtask/src/resource_type_authority.rs:942, packages/d2b-contracts/src/generated/v3_converted_resource_types.rs:2] - evidence: idiom seed 3 15 hits; the emitted strings were confirmed byte-identical in the committed generated artifact (the drift gate would reject a mismatch), so the fix touches src/generated/** and is needs-contract per U1 section d.7 - -## own -- xtask-p3#3 sev=low blast=leaf effort=S verdict=actionable - `nix_string_list` takes `impl IntoIterator`, forcing every caller to `.to_owned()` its `&'static str` fields at seven call sites only to borrow them again inside `nix_string` - fix: change the signature to `impl IntoIterator` (or `&[&str]`) and delete the `.map(|field| (*field).to_owned())` closures at the call sites - [packages/xtask/src/provider_packaging.rs:163, packages/xtask/src/provider_packaging.rs:206, packages/xtask/src/provider_packaging.rs:222, packages/xtask/src/provider_packaging.rs:230, packages/xtask/src/provider_packaging.rs:242, packages/xtask/src/provider_packaging.rs:252, packages/xtask/src/provider_packaging.rs:263, packages/xtask/src/provider_packaging.rs:278] - evidence: own seed 2 (`\.to_owned\(\)|\.to_vec\(\)|\.to_string\(\)`) 168 hits lane-wide; 7 of the provider_packaging.rs hits are nix_string_list call sites (signature read in full) -- xtask-p3#4 sev=low blast=leaf effort=S verdict=actionable - `resource_ref_schema(pattern: String, allowed_types: &[String])` forces `.to_owned()`/`String::from` at every call site, including static regex literals that never need an owned String - fix: change the signature to `pattern: &str` and `allowed_types: &[&str]` (both serialize into `json!` unchanged) and drop the conversions at the call sites - [packages/xtask/src/semantic_service_schemas.rs:32, packages/xtask/src/semantic_service_schemas.rs:44, packages/xtask/src/semantic_service_schemas.rs:55, packages/xtask/src/semantic_service_schemas.rs:61, packages/xtask/src/semantic_service_schemas.rs:74, packages/xtask/src/semantic_service_schemas.rs:155, packages/xtask/src/semantic_service_schemas.rs:203] - evidence: own seed 2 168 hits lane-wide; 7 hits in semantic_service_schemas.rs are signature-forced allocations (function and call sites read in full) - -## type -- clean: type seeds 11/0/9 - seed 1 (`fn validate_\w+|fn check_\w+`) 11 hits are the recovery attestation admission gate (`validate_shape`/`validate_binding`/`validate_at` family, each a parse-once check at the decode/consumption boundary of a deny_unknown_fields wire type) plus the CLI gate `check()`; seed 3 (`(mode|kind|state): String`) 9 hits are all `artifact_kind: String` wire-record fields mirroring the pinned recovery schema; both classes are the card's recorded wire-type false positives. No boolean-flag soup, stringly-typed state, or validate-at-every-callsite duplication beyond the deliberate wire admission. - -## api -- clean: api seeds 171/0/0 - seed 1 (`\bpub (fn|struct|enum|trait|type|const|mod) `) 171 hits, seed 2 (`pub .*\b(Arc|Rc|Box|RefCell)<`) 0, seed 3 (`^\s*pub use `) 0. xtask is a bin-only crate (no `[lib]` target in packages/xtask/Cargo.toml), so the `pub` items are internal wiring consumed by `main.rs`, not an exported surface; over-broad `pub` visibility is already policed by the crate's own dead-code gate (`deadcode.rs` runs `cargo hawk check` for `pub` -> `pub(crate)` reductions). - -## err -- xtask-p3#5 sev=medium blast=leaf effort=S verdict=actionable - `RecoveryError::Json` conflates three failure modes: an unreadable attestation file (`read_attestation` maps open/read errors to Json), canonical-JSON rejection, and a typed-parse failure whose serde detail (missing field, line, column) is discarded, so an operator debugging a rejected attestation sees only "recovery attestation shape rejected" with no way to tell a missing file from a malformed payload - fix: add a `RecoveryError::Read` variant for the fs errors and carry the bounded serde error text (field names and positions only, never payload values, keeping the enum's redaction contract) in a `Json(String)` variant, propagating through the existing `From for DeliveryError` - [packages/xtask/src/delivery/recovery.rs:384, packages/xtask/src/delivery/recovery.rs:1610, packages/xtask/src/delivery/recovery.rs:1715, packages/xtask/src/delivery/recovery.rs:1719] - evidence: err seed 1 (`\.unwrap\(\)|\.expect\(`) 239 hits, sampled: 50 of 239 (every sampled hit is cfg(test) code or a named-invariant expect on internal catalog data); seed 2 (`let _ = |\.ok\(\);`) 4 hits (all deliberate: Drop cleanup, infallible `write!` to String, test cleanup); seed 3 (`\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(`) 3 hits (test helpers and the fail-closed golden arm); seed 4 (`enum \w*Error`) 1 hit (`RecoveryError`, read in full) - -## serde -- xtask-p3#7 sev=low blast=leaf effort=S verdict=actionable - `DeclarationFile` and `TypeDeclaration` use per-field `#[serde(rename = ...)]` for their camelCase wire keys while the sibling `RoleDeclaration` in the same file uses `#[serde(rename_all = "camelCase")]`, splitting the boundary-naming convention within one file - fix: add `#[serde(rename_all = "camelCase")]` to `DeclarationFile` and `TypeDeclaration` and delete the two per-field renames - [packages/xtask/src/resource_type_authority.rs:179, packages/xtask/src/resource_type_authority.rs:182, packages/xtask/src/resource_type_authority.rs:190, packages/xtask/src/resource_type_authority.rs:192, packages/xtask/src/resource_type_authority.rs:204] - evidence: serde seed 2 (`serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)`) 37 hits; the three declaration structs read in full (seeds 1/3/4: 26/0/32 hits, all derived wire types and boundary calls) - -## obs -- clean: obs seeds 15/0/0/0 - seed 1 (`\bprintln!\(|\beprintln!\(`) 15 hits are CLI product output and gate diagnostics (`deadcode.rs` eprintln report lines, `bin/manifest_v04_check.rs` usage/error lines), the card's recorded carve-out; seeds 2-4 0 hits (no interpolated events, no spans, no tracing/log dependency). No telemetry surface exists in this scope to judge. - -## docs -- xtask-p3#6 sev=low blast=leaf effort=S verdict=actionable - several pub items in the delivery modules lack the doc comment the modules' own discipline gives every sibling item: `WaveSnapshot::digests`/`program`/`wave`, `WaveCommand::as_str`/`parse`/`required_options`/`optional_options`, `WorkflowOutput::ok`/`with_digests`, `WorkflowCommandHelp`, and the `CliOptions` accessors - fix: add one-line doc comments naming each contract (mirroring the sibling wording already present) - [packages/xtask/src/delivery/snapshot.rs:87, packages/xtask/src/delivery/snapshot.rs:95, packages/xtask/src/delivery/snapshot.rs:99, packages/xtask/src/delivery/command.rs:104, packages/xtask/src/delivery/command.rs:116, packages/xtask/src/delivery/command.rs:205, packages/xtask/src/delivery/command.rs:234, packages/xtask/src/delivery/command.rs:425, packages/xtask/src/delivery/command.rs:440, packages/xtask/src/delivery/command.rs:465] - evidence: docs seed 1 (`^\s*pub (fn|struct|enum|trait|const|type)`) 153 hits; the listed items were confirmed doc-less while reading each module's pub surface (seed 2 `/// # (Examples|Errors|Panics|Safety)` 0 hits; seed 3 `-> Result<` 73 hits) - -## perf -- clean: perf seeds 138/37/5 - seed 1 (`format!\(`) 138 hits, seed 2 (`Vec::new\(\)|VecDeque::new\(\)|HashMap::new\(\)|BTreeMap::new\(\)`) 37 hits, seed 3 (`\.to_string\(\)`) 5 hits; every hit is a generator building a text artifact (the card's recorded xtask carve-out), a cold error/diagnostic path, a bounded artifact read, or a test. No hot loop allocates; no collection choice is wrong for its access pattern; no attacker-controlled hashing. Perf claims are static (unmeasured) per the card. - -## conc -- N/A (seeds: 0/0/0/0 all zero; no threads, locks, atomics, or manual Send/Sync anywhere in the assigned files - the lane is single-threaded CLI/generator code) - -## async -- N/A (seeds: 0 all zero; no async fn, await, tokio, or block_on in the assigned files - the lane is synchronous CLI/generator code) - -## unsafe -- N/A (seeds: 0/0/0/0 all zero; no unsafe blocks, fns, impls, SAFETY comments, or transmute/from_raw/MaybeUninit sites; the crate manifest carries `unsafe_code = "forbid"`, and seed 4 alone does not make the lens applicable per the card) - -## ffi -- clean: ffi seeds 0/1/0/0 - seed 2 (`catch_unwind`) 1 hit at command.rs:1792, a `#[test]` asserting `golden_fingerprint` fails closed for an unpinned schema version; it is a panic-behavior assertion, not a foreign boundary, so no FFI surface exists to judge (seeds 1/3/4 are 0). - -## macro -- clean: macro seeds 1/0/0/0 - seed 1 (`macro_rules!`) 1 hit: `workflow_status!` (command.rs:317), a list-driven enum/wire-string/ALL-domain generator - the skill's genuine "impl-per-type generation from a list" answer; it uses the narrow `$meta:meta` fragment, needs no `$crate` (no crate paths in the expansion), and its doc comment states the drift rationale. Seeds 2-4 are 0 (no proc macros). - -## test -- xtask-p3#8 sev=low blast=leaf effort=S verdict=actionable - `workflow_status_all_enumerates_every_variant` and `wave_commands_enumerates_every_stage` assert `ALL.contains(status)` for every status drawn from `ALL` itself, so the runtime assertion is tautological and can never fail; the real guard is the wildcard-free match's compile-time exhaustiveness, which the assert adds nothing to - fix: drop the `assert!` and keep the wildcard-free match (the compile-fail property), or assert a property not derived from the same enumeration - [packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079] - evidence: test seed 1 (`#\[test\]|#\[tokio::test\]`) 174 hits, seed 2 (`assert_eq!\(|assert_ne!\(|assert!\(`) 501 hits; both tests read in full (their own comments document the compile-time intent) - -## Coverage -- idiom: 2 finding(s) -- own: 2 finding(s) -- type: clean (seeds ran: 11/0/9; all hits are wire admission gates, the CLI gate, and schema-mirroring artifact_kind fields per the card's false positives) -- api: clean (seeds ran: 171/0/0; bin-only crate with no lib target, pub items are internal wiring, cargo-hawk gate polices visibility) -- err: 1 finding(s) -- serde: 1 finding(s) -- obs: clean (seeds ran: 15/0/0/0; all eprintln/print hits are CLI product output and gate diagnostics per the card's carve-out) -- docs: 1 finding(s) -- perf: clean (seeds ran: 138/37/5; all hits are generator text building, cold error paths, bounded reads, or tests per the card's carve-outs) -- conc: N/A (seeds: 0/0/0/0 all zero; no threading primitives in scope) -- async: N/A (seeds: 0/0/0/0 all zero; no async code in scope) -- unsafe: N/A (seeds: 0/0/0/0 all zero; no unsafe sites; manifest `unsafe_code = "forbid"` only) -- ffi: clean (seeds ran: 0/1/0/0; the single catch_unwind is a test assertion, not a foreign boundary) -- macro: clean (seeds ran: 1/0/0/0; the one macro is the list-driven workflow_status! generator, a genuine macro use) -- test: 1 finding(s) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md deleted file mode 100644 index 3a9bb9682..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p4.md +++ /dev/null @@ -1,72 +0,0 @@ -# xtask-p4 - xtask - part 4/5 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9015 (excl. src/generated/**) | modules: delivery/storage, delivery/model, delivery/mod, production_closure, zone_schema, operation_row_authority, inventory -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: packages/xtask/src/delivery/storage.rs, packages/xtask/src/production_closure.rs, packages/xtask/src/zone_schema.rs, packages/xtask/src/delivery/model.rs, packages/xtask/src/operation_row_authority.rs, packages/xtask/src/inventory.rs, packages/xtask/src/delivery/mod.rs - -## idiom -- clean: seeds ran: 0/0/39; every `let mut ... = String|Vec::new()` hit is a state-machine parser, an error collector, an fd-walk chain,a bounded read buffer, or a Nix/JSON text builder where an iterator collect would not be clearer or would split a single multi-output pass. - -## own -- xtask-p4#1 sev=low blast=leaf effort=S verdict=actionable - `compute_context(root, spec)` takes `ContextSpec` by value,so both caller loops clone the spec they still need afterwards - fix: change `fn compute_context(root: &Path, spec: ContextSpec)` (and the `compute_lock_context` recursion at production_closure.rs:431) to take `spec: &ContextSpec`,removing the `.clone()` at both loop call sites - [packages/xtask/src/production_closure.rs:263, packages/xtask/src/production_closure.rs:379] - evidence: own seed 1 `\.clone()` = ~47 hits; sites 263/379 are loop-boundary clones where the caller reads spec again after the call (spec.key(), spec.system, spec.target, spec.name, or the surviving `&contexts` for `write_advisory_skeleton`). -- xtask-p4#2 sev=low blast=leaf effort=S verdict=actionable - `check_outputs` binds `ApprovalProjection` twice in a row,but the first binding is never read after the second clone - fix: replace `let approval = advisory.approval.clone();` followed by `Some(approval.clone())` with one `Some(advisory.approval.clone())` - [packages/xtask/src/production_closure.rs:383, packages/xtask/src/production_closure.rs:386] - evidence: own seed 1 `\.clone()` = ~47 hits; the clone at :383 is consumed only by the clone at :386,and nothing else in the loop body reads `approval`. - -## type -- xtask-p4#3 sev=medium blast=leaf effort=S verdict=actionable - inventory.rs re-implements the crate's own `delivery::model::validate_repo_relative_path` with the same invariant (minus the empty-path check), so two validators drift apart - fix: delete the private copy at inventory.rs:230,and call `crate::delivery::model::validate_repo_relative_path(Path::new(path))`, keeping the stricter empty check - [packages/xtask/src/inventory.rs:230, packages/xtask/src/delivery/model.rs:557] - evidence: type seed 1 `fn validate_\w+|fn check_\w+` = 14 hits; census: `validate_repo_relative_path` over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 14 hits (model's pub helper already serves delivery/snapshot.rs; inventory carries its own private copy). -- xtask-p4#4 sev=low blast=leaf effort=M verdict=needs-contract - `EdgeRecord.kind: String` carries the closed Cargo dependency-kind vocabulary {"normal","build","dev","proc-macro"} as a free string through traverse/filter/emit - fix: introduce a closed `EdgeKind` enum parsed once at the metadata boundary (dep_kinds reads at :660-676), serde-renamed to preserve the wire spelling "proc-macro",and regenerate the committed packages/policy-inputs/** closures - [packages/xtask/src/production_closure.rs:107, packages/xtask/src/production_closure.rs:660, packages/xtask/src/production_closure.rs:724] - evidence: type seed 3 `(mode|kind|state): String` is 1 site (EdgeRecord.kind); the vocabulary is closed per `production_kinds()`/`policy_kinds()` sets (lines 74-82),and `package_is_proc_macro()`; the emitted closure.json projections are committed generated shapes,so the change is needs-contract. - -## api -- clean: seeds ran: 45/0/4; xtask is bin-only (no `src/lib.rs`, no `[lib]` target, `default-run = "xtask"`), so pub and re-exported items are crate-internal and no external API contract exists to judge or break. - -## err -- clean: seeds ran: ~80/7/2/1; every surviving unwrap/expect site is cfg(test), an invariant expect on an already-checked map lookup,a literally-built JSON value, or `write!` to String; the `let _ =` sites are documented best-effort Drop cleanups; the two panic sites are tests; the one enum hit is `DeliveryErrorKind` (the kind half of the already-correct struct-with-private-kind pattern). - -## serde -- xtask-p4#5 sev=low blast=leaf effort=S verdict=actionable - `SnapshotView` (mod.rs:46-47) lacks `#[serde(deny_unknown_fields)]` while every nested wire type in the same artifact (CandidateMaterial, RepositoryRecord, Fingerprint, DependencyEdge, digest newtypes) denies, so a hand-edited snapshot can carry silently-ignored top-level keys - fix: add `#[serde(deny_unknown_fields)]` to SnapshotView; the `schema_version` gate already handles version drift,so there is no forward-compat cost - [packages/xtask/src/delivery/mod.rs:46, packages/xtask/src/delivery/model.rs:111] - evidence: serde seed 2 `#[serde(...)]` attr scan = ~30 attr sites; SnapshotView is the only Deserialize-wire type in the lane without an attr (every sibling denies at model.rs:111-112, 144-145, 234-235, 244-245, 269-270, 305-307). - -## obs -- clean: seeds ran: 4/0/0/0; all four println!/eprintln! sites are CLI product output per the cli-contract (result JSON on stdout, diagnostics on stderr); no tracing/log, instrument, or interpolated log macros exist in these modules. - -## docs -- clean: seeds ran: 45/0/60; xtask is bin-only per the skill's own carve-out,and every public contract-bearing item (StateRoot, CandidateDir, model wire types, SnapshotView, DeliveryError/DeliveryErrorKind) carries full API docs;# Errors sections are N/A on crate-internal Result fns. - -## perf -- clean: seeds ran: ~38/~40/4; every site is a cold one-shot CLI path, an error diagnostic, or a deliberate Nix/JSON artifact text builder (recorded false-positive classes); no hot loop allocates,and no benchmark exists (static, unmeasured). - -## conc -- clean: seeds ran: 1/2/7/2; the only production sync site is the `Relaxed` atomic temp-suffix counter (recorded atomics-as-counters class); all other sync sites are cfg(test) race-hook/override machinery (test-only synchronization class). - -## async -- N/A (seeds: 0/0/0/0 all zero; no async fns, awaits, spawns, runtimes, or tokio sync guards exist in these files). - -## unsafe -- N/A (seeds: 0/0/2-false-positive/0; the two `from_raw` hits are safe `rustix::fs::FileType::from_raw_mode` conversions, not unsafe ops; no unsafe block/fn/impl or `// SAFETY:` comment exists in scope,and the crate's `unsafe_code = "forbid"` lint setting is untouched). - -## ffi -- N/A (seeds: 0/0/0/0 all zero; no `extern "C"`, `no_mangle`, `catch_unwind`, `reprC()`/`repr(transparent)`, or CStr/CString/c_char surface exists; rustix/nix syscall wrappers never cross a foreign caller). - -## macro -- clean: seeds ran: 1/1/0; the sole `digest_identifier!` macro is impl-per-type generation for the three digest newtypes (one of the skill's three genuine macro uses), with ident/literal fragment specifiersand no external paths to shadow; the one proc_macro/syn hit is the fn name `package_is_proc_macro` (false positive). - -## test -- clean: seeds ran: 50/~150/0/0; tests are behavioral fixture-driven unit tests (parity/drift gates, digest identity matrix, path-safety matrix, exit-code contract), table-driven where apt; no ignored or tautological tests found. - -## Coverage -- idiom: clean(seeds ran: 0/0/39) -- own: 2 finding(s) -- type: 2 finding(s) -- api: clean(seeds ran: 45/0/4) -- err: clean(seeds ran: ~80/7/2/1) -- serde: 1 finding(s) -- obs: clean(seeds ran: 4/0/0/0) -- docs: clean(seeds ran: 45/0/60) -- perf: clean(seeds ran: ~38/~40/4) -- conc: clean(seeds ran: 1/2/7/2) -- async: N/A (seeds: 0/0/0/0 all zero; no async code) -- unsafe: N/A (seeds: 0/0/2-false-positive/0; no real unsafe sites) -- ffi: N/A (seeds: 0/0/0/0 all zero; no FFI surface) -- macro: clean(seeds ran: 1/1/0) -- test: clean(seeds ran: 50/~150/0/0) diff --git a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md b/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md deleted file mode 100644 index c87bfcd1e..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/lane/xtask-p5.md +++ /dev/null @@ -1,72 +0,0 @@ -# xtask-p5 - xtask - part 5/5 -Baseline: 6ebdd4cec22e6537d1376e83ff7a82b00a8492c0 | LOC audited: 9009 (excl. src/generated/**) | modules: changelog.rs, async_gate.rs, blocking_census.rs, delivery/evidence.rs, nix_inventories.rs, bazel_evidence.rs, delivery/seal.rs -Lenses: idiom, own, type, api, err, serde, obs, docs, perf, conc, async, unsafe, ffi, macro, test | Partitions: src/changelog.rs, src/async_gate.rs, src/blocking_census.rs, src/delivery/evidence.rs, src/nix_inventories.rs, src/bazel_evidence.rs, src/delivery/seal.rs - -## idiom -- xtask-p5#1 sev=low blast=leaf effort=S verdict=actionable - `resource_type.to_string()` in an iterator map over `&[String]` where `.cloned()` is the idiomatic copy - fix: `STANDARD_RESOURCE_TYPES.iter().map(|resource_type| resource_type.to_string()).collect::>()` -> `.iter().cloned().collect::>()` - [packages/xtask/src/nix_inventories.rs:721] - evidence: seed `\.to_string\(\)|\.to_owned\(\)|\.to_vec\(\)` = ~96 hits (lane); the cited site is the only production iterator-map copy in this part; the rest are tests and error-path strings - -## own -- xtask-p5#2 sev=low blast=leaf effort=M verdict=actionable - Baseline map build clones each `CrateCensus`'s `crate_dir` and `counts` twice per crate although the later baseline check only re-borrows them - fix: build `CensusBaseline` from `crates.into_iter().map(|c| (c.crate_dir, c.counts)).collect()` (when `json_out` is set( and drive the `--baseline` check loop from `&baseline.crates` instead of `&crates` - [packages/xtask/src/blocking_census.rs:1270, packages/xtask/src/blocking_census.rs:1287] - evidence: seed `\.clone\(\)` = ~32 hits; at blocking_census.rs:1270-1272 the pair clone fires twice per crate into the committed-baseline map; every other clone in this part buys an owned value whose borrower stays live - -## type -- clean: seeds ran: `fn validate_\w+|fn check_\w+` = 3 / `is_\w+: bool|\w+_flag: bool` = 0 / `(mode|kind|state): String` = 0; the three hits (`validate_inventory`, `check_security`, `validate_single_line`) are boundary validators in a CLI/gate context where parse-once newtypes would be over-engineering per the stopping rule - -## api -- clean: seeds ran: `\bpub (fn|struct|enum|trait|type|const|mod) ` = ~66 / `pub .*\b(Arc|Rc|Box|RefCell)<` = 0 / `^\s*pub use ` = 0; all pub items checked; xtask is a bin-only crate (no `lib` target, `publish = false`), so every `pub` item is crate-internal surface, and the pub fields on delivery records serve sibling-module construction - -## err -- clean: seeds ran: `\.unwrap\(\)|\.expect\(` ~95 (production hits ~12, every one an invariant assert on a compiler-verified or pre-checked value - `String::from_utf8(out).expect)...)` async_gate.rs:824, `serde_json::to_string_pretty(&value).expect)...)` bazel_evidence.rs:41, allocation `.get)...).expect("...checked against the allocation")` nix_inventories.rs:620,641; the rest are `#[cfg(test)]`( / `let _ = |\.ok\(\);` ~16 (test fixture strings and deliberate best-effort `Drop` cleanup in changelog tests( / `\bpanic!\(|\bunreachable!\(|\btodo!\(|\bunimplemented!\(` = 1 (test( / `enum \w*Error` = 0; panic policy is sound; no swallowed Results in production paths - -## serde -- clean: seeds ran: `derive\([^)]*(De)?[Ss]erialize` = 13 / `serde\((rename_all|deny_unknown_fields|try_from|untagged|flatten|default|skip_serializing_if)` = 9 / `impl .*Deserialize.*for` = 0 / `serde_json::from_|serde_json::to_` ~18; wire record types (`HatchInventory`, `CensusBaseline`, `EvidenceRecord`, `OutputDigest`, `SealedLane`, `SealedValidation`, `SealRecord`) usa `rename_all = "kebab-case"` for the lane enum, `deny_unknown_fields` on the committed record shapes, and `#[serde(default, skip_serializing_if = "Option::is_none")]` on optional record fields; no hand-written deserializers and no missing-boundary validation identified - -## obs -- clean: seeds ran: `\bprintln!\(|\beprintln!\(` ~31 (all CLI product output of changelog-fold, check-async-gate, blocking-census, and bazel-evidence subcommands - the card's sanctioned xtask case( / `(info|debug|warn|error|trace)!\("` = 0 / `\.instrument\(|#\[instrument` = 0 / `tracing::|log::` = 0; no telemetry or event logging in this part - -## docs -- xtask-p5#3 sev=medium blast=leaf effort=M verdict=actionable - Pub field groups on the wire and census record types carry no field-level doc contracts, so units and serialization formats are guesswork - fix: add per-field doc comments to `DeniedApi.path/tail/kind`, `CensusBaseline.crates`, `OutputDigest.sha256/bytes`, `EvidenceRecord.*`, `SealedLane.lane/validations`, `SealedValidation.validation/record_sha256`, `SealRecord.*` - [packages/xtask/src/blocking_census.rs:71, packages/xtask/src/blocking_census.rs:658, packages/xtask/src/delivery/evidence.rs:120, packages/xtask/src/delivery/evidence.rs:128, packages/xtask/src/delivery/seal.rs:35, packages/xtask/src/delivery/seal.rs:48, packages/xtask/src/delivery/seal.rs:61] - evidence: seed `^\s*pub (fn|struct|enum|trait|const|type)` = ~66 hits; at the cited records the pub fields lack docs for `sha256` (hex? base64?), `imported_at_unix` (seconds?), `schema_version` semantics,and map-key forms -- xtask-p5#4 sev=low blast=leaf effort=S verdict=actionable - Result-returning pub fns describe failure modes in prose rather than the canonical `# Errors` section - fix: add `# Errors` sections to `parse_fragment`, `EvidenceLane::parse`, `EvidenceRecord::validate`, `SealRecord::validate`, and `async_gate::scan_source` naming each rejection condition - [packages/xtask/src/changelog.rs:149, packages/xtask/src/delivery/evidence.rs:97, packages/xtask/src/delivery/evidence.rs:162, packages/xtask/src/delivery/seal.rs:77, packages/xtask/src/async_gate.rs:265] - evidence: seed `-> Result<` ~68 hits; the cited pub fns carry prose rejection lists (e.g. "Rejected: an empty fragment, an unknown...") where the skill's canonical-section shape is absent - -## perf -- xtask-p5#5 sev=low blast=leaf effort=S verdict=actionable - `contains_quoted_field` allocates two `format!`'d quoted literals per field per quote inside the per-line redaction scan, up to 8 small String allocations per log line - fix: frame the four credential field names once per `redact_text` call (or as module `const` literals( and pass `&[&str]` framed forms to `contains_quoted_field` so the per-line scan only does `.contains)...)` - [packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packages/xtask/src/bazel_evidence.rs:407] - evidence: static (unmeasured); seed `format!\(` ~45 hits over the lane;(the other format sites are error paths or deliberate artifact-text generation, which the card exempts; the cited site allocates inside a per-line loop over a potentially large build log - -## conc -- clean: seeds ran: `std::thread::|thread::spawn|thread::scope` ~8 / `\bMutex<|\bRwLock<` ~13 / `Atomic\w+|Ordering::` = 0 / `thread_local!|unsafe impl (Send|Sync) for` = 0; every hit is doc prose or a test-fixture source string inside scanner/gate modules; no threads, locks, atomics, or manual Send/Sync claims exist in real code of this part - -## async -- clean: seeds ran: `async fn|async move|\.await` ~40 / `tokio::spawn|spawn_blocking|JoinSet|select!\(|join!\(` ~8 / `tokio::sync::(Mutex|RwLock|Notify)` ~3 / `#\[tokio::(main|test)\]|Runtime::block_on` ~2; every hit is doc prose or a test-fixture source string; the gate implementations themselves are synchronous, so no async context, spawn, or await exists in this part's real code - -## unsafe -- N/A (seeds: `\bunsafe \{|\bunsafe fn|\bunsafe impl|\bunsafe extern` = 0 / `// SAFETY:` = 0 / `transmute|from_raw|MaybeUninit|mem::zeroed` = 0; seed 4 `unsafe_code` = 1,the sole hit is `#![forbid(unsafe_code)]` at bazel_evidence.rs:1,which does not make the lens applicable) - -## ffi -- N/A (seeds: `extern "C"|no_mangle|unsafe\(link_section` = 0 / `catch_unwind` = 0 / `repr\(C\)|repr\(transparent\)` = 0 / `CStr|CString|c_char` = 0; no FFI boundary exists in these files) - -## macro -- xtask-p5#6 sev=low blast=leaf effort=S verdict=actionable - The test-only `crash_if_hooked!` macro is defined textually-identically in three sibling fns, differing only in the message string - fix: hoist to one module-scope `macro_rules! crash_if_hooked { ($stage:expr, $message:expr) => { #[cfg(test)] if let HookOutcome::Crash = hook($stage) { return Err(FoldError::single($message)); } }; }` and call with the stage plus message, or replace with a `#[cfg(test)]` generic helper fn - [packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/src/changelog.rs:1019] - evidence: seed `macro_rules!` = 3 hits; all three definitions are identical except the embedded message (and the stage enum type, which the `$stage:expr` fragment never names); no proc-macro/syn usage exists in this part - -## test -- clean: seeds ran: `#\[test\]|#\[tokio::test\]` ~70 / `assert_eq!\(|assert_ne!\(|assert!\(` ~500 / `proptest!|insta::assert|rstest` = 0 / `#\[ignore\]` = 0; sampled: 50 of ~500 assertion hits across the seven files' test modules;(the test-lens scope for this part is the `#[cfg(test)]` blocks inside the assigned files, since `tests/` belongs to no part partition); sampled assertions are table-driven with per-case failure messages, the fold-recovery crash-injection tests drive every journal boundary, and the evidence/seal tests assert binding and tamper rejection; no ignored, tautological, or network-touching tests spotted - -## Coverage -- idiom: 1 finding(s -- own: 1 finding(s -- type: clean (seeds ran: 3/0/0; the three validators are boundary checks where parsed types would be over-engineering) -- api: clean (seeds ran: ~66/0/0; bin-only crate with no lib target, so pub surface is crate-internal) -- err: clean (seeds ran: ~95/~16/1/0; production panics are invariant asserts only) -- serde: clean (seeds ran: 13/9/0/~18; record shapes usa the right optionality and field-rejection attributes) -- obs: clean (seeds ran: ~31/0/0/0; all println sites are CLI product output) -- docs: 2 finding(s -- perf: 1 finding(s -- conc: clean (seeds ran: ~8/~13/0/0; all hits are doc prose or test-fixture strings) -- async: clean (seeds ran: ~40/~8/~3/~2; all hits are doc prose or test-fixture strings) -- unsafe: N/A (seeds: 0/0/0; unsafe_code = 1,only a forbid attribute) -- ffi: N/A (seeds: 0/0/0/0; no FFI surface) -- macro: 1 finding(s -- test: clean (seeds ran: ~70/~500/0/0; sampled: 50 of ~500 assertion hits; see section) \ No newline at end of file diff --git a/docs/audits/2026-09-24-rust-skills-audit/ledger.md b/docs/audits/2026-09-24-rust-skills-audit/ledger.md deleted file mode 100644 index adf70e9c2..000000000 --- a/docs/audits/2026-09-24-rust-skills-audit/ledger.md +++ /dev/null @@ -1,1017 +0,0 @@ -# Rust skills remediation ledger - -Baseline: branch `refactor-rust-skills-remediation`, base commit `147a536a0` (the audit baseline `v3` @ `6ebdd4cec` plus the audit corpus commit). Authority: `docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md` (R1-R14, KTD1-KTD11). Corpus: `README.md` and `lane/`. - -One row per finding id. `outcome` is filled by the owning wave when it disposes of the row: `applied`, `applied-variant` (the claim or the stated fix needed a minimal correction or a recorded deviation), `skipped-stale` (the claim does not hold at HEAD; no change made), `already-fixed` (the stated fix is already present in the tree), `escalated` (moved to the owning wave named in `escalation`), `policy-confirmed` (recorded no-op citing its policy), `needs-contract` (deferred to the contract-adjacent wave), `reclassified` (severity or verdict changed on re-verification, reason recorded), `declined` (the claim holds but no correct minimal change lands - the pinned toolchain rejects the rewrite, or the fix would break a contract; the evidence is recorded and the code stays as it is), and `not-started` (the batch's budget ended before the row; it is carried into a follow-up dispatch, never counted as done). - -Corpus caveat: the audit read its sources through a tool path that rewrites long digit runs, so at least one row (RS-0916) quotes a literal that exists nowhere in the tree or in git history. Every row's true state is re-verified at apply time (R3) and the ledger records the corrected finding; the corpus row text is left as the audit wrote it. `anchor` is the apply-time anchor when the wave re-located it; the seed anchor comes from the corpus row. Empty cells mean the row is not yet disposed. - -Every id must appear exactly once and end `applied`, `already-fixed`, `policy-confirmed`, or `needs-contract` at close-out; `escalated` rows carry the escalation history and their final outcome (R1, KTD1). - -## Baseline record (gate set at the untouched head) - -Measured at `147a536a0` in a dedicated gates worktree before any wave-0 fix landed. The whole gate set is green at the baseline, so a wave's bar is to stay green rather than to improve a red gate; any red a wave introduces is its own. - -| gate | command | result at baseline | attribution | -| --- | --- | --- | --- | -| security scan | `D2B_SCAN_BASE_SHA=6ebdd4cec tests/tools/security-scan.sh` | pass (clean) | none | -| blocking census | `make check-census` | pass (no crate above its committed baseline) | none | -| Layer-1 aggregate | `make check` | pass (988 of 988 tests) | none | -| host integration | `make test-host-integration` | pass (11 of 11 vmChecks) | Attic closure-upload warning only, non-fatal | - -### Pre-existing findings observed at apply time - -Defects the audited surfaces carry at HEAD that no corpus row claims and no wave fixes. They are recorded here so a later reader does not mistake them for wave regressions, and they route to an ordinary review pass or the owning package owner rather than to a leaf row. - -- `cargo clippy -p d2b-broker --locked --all-targets` trips the disallowed `nix::sys::socket::connect` in `packages/d2b-broker/tests/common/mod.rs` with no inline allow, so the broker's integration test binaries fail the clippy lint gate under plain cargo while the Bazel clippy action stays green. Reproduced at the audit base `147a536a0`: one clippy error on a pristine checkout. A test-only allow is the broker package owner's policy call. -- (wave-1 regression, fixed on the integration branch) `cargo clippy -p d2b-bus --locked --all-targets` stopped at `use of a disallowed method std::sync::Mutex::lock` in `packages/d2b-bus/src/session/contract.rs`. The missing inline allow arrived with the wave-1 batch commit `fbf92683a`, which extracted `verify_body` out of the already-sanctioned `verify`; wave 1's Bazel clippy action did not flag the extraction, so the wave gate stayed green while plain-cargo clippy went red for `d2b-bus` and every crate depending on it. Fixed with the same sanctioned reason its four sibling functions use (`synchronous path`); `xtask check-provider-crate-layout` validates allow reasons against its sanctioned set rather than a per-site list, so no list changed and the site is not an ad-hoc allow. The broker test-helper entries below stay pre-existing and unfixed. -- `cargo check -p d2b-provider-display-wayland --locked --all-targets` fails to compile the lib test with `E0599` on `AuthenticatedSessionRouteBinding::for_test` (a `test-support` cfg mismatch). Reproduced at the audit base `147a536a0` in a detached worktree, so this one is genuinely pre-existing rather than a wave regression - unlike the bus entry above, which the same check proved to be mine. -- `cargo clippy -p d2b-provider-process-systemd --locked --all-targets` reports three errors from the `#[tokio::test]` functions in `src/effects_service.rs`, whose expansion calls the denied `tokio::runtime::Runtime::block_on`. Reproduced at the audit base `147a536a0`: three errors on a pristine checkout. The owning slice also proved it independently by reverting its own change and re-running. - -Pattern across these entries: plain-cargo clippy and check go red in four places where the Bazel gate stays green, because the gate's actions do not compile the same target set - expanded `#[tokio::test]` bodies, `test-support` cfg paths, and test helpers are linted by cargo and not by the action. One of the four was a wave-1 regression and is fixed; the rest reproduce at the audit base. A worker's acceptance signal for such a crate is its lib target plus its own tests, never a new inline allow. -- `cargo check -p d2b-broker --locked --all-targets --features layer1-bootstrap` fails at the same base: `packages/d2b-broker/src/lib.rs` cfg-excludes `kernel_ops` for that feature while the lib test and `tests/broker_protocol_compatibility.rs` reference it. Reproduced at the audit base `147a536a0`: thirty-nine check errors on a pristine checkout. - -## Wave gates - -Each wave closes on the same gate set, run on the wave's integrated head in the gates worktree. `base` is the commit the scan measures changed lines against. - -| wave | head | security scan | census | Layer-1 aggregate | host integration | notes | -| --- | --- | --- | --- | --- | --- | --- | -| U1 | `11bbfe41a` | pass | pass | pass (988 of 988 tests) | pass (11 of 11 vmChecks) | First attempt flaked on the load-sensitive `daemon_state_persistence` kill-during-startup race (passes standalone, not an audit row); the retry is green. The head carries the refreshed async-gate inventory for the broker line shifts. | -| U2 | `76153aa44` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 368 wave rows carry an outcome: 336 applied, 37 applied-variant with recorded deviations, 4 declined on compiler or API evidence, 1 skipped-stale that overrode a false audit premise, 1 escalated to U5, 1 policy-confirmed no-op. Seven gate attempts got here, each finding something real: the cross-slice signature change (the daemon runtime began consuming audit events while the daemon still borrowed them in nine places), the lint class `cargo check` cannot see (blank lines after doc blocks in default and feature-variant code, nested if-lets, a single-arm `filter_map`, redundant closures, needless borrows, a useless conversion, a too-complex callback type), a census ratchet move recorded with its context, the daemon API reference the scanner rewrite re-rendered, and one deliberate consumer-visible change: the operator's allowed-subcommand list now comes from the parser, so retired realm-era commands no longer appear, and both output goldens moved with it. Host-lane timeouts tracked the runs that did concurrent heavy work on this host and passed in every idle run. | -| U3 | `b81222ba1` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | All 286 wave rows carry an outcome: 240 applied, 25 applied-variant with recorded deviations, 14 needs-contract with anchors recorded, 4 already-fixed, 2 skipped-stale that overrode a false audit premise, 1 declined on compiler or API evidence. Six gate attempts got here, each finding something real: the cross-slice signature change (the azure ref moved to its contracts path while the guest effects service still resolved it through `aca_runtime`), the test-support feature gap (`host_reconciliation`'s unresolved `d2b_provider_system_core::testing` import), the ratchet reconciliation (`tier0_first_pass`, `check-async-gate`, `provider_crate_layout`, `d2bd_lib_test`, and `xtask_test` - the ascii-dash, async-gate inventory, and family-knowledge ratchet), the nix flake-eval runfile resolution (`flake-eval-x86-outputs` and the realized guest-static and provider-catalog evals), and the forward-rendezvous per-test thread bound plus the EPIPE refusal race. Two load-sensitive tests (`detached_exec_routing_tests` in `packages/d2bd/src/composition.rs` and an interaction_composition socket test in `packages/d2bd/src/interaction_composition.rs`) flaked only under an aggressive synthetic 12-core load generator, never in a gate run; they are recorded, not fixed. | -| W3 | `d68d0dbcb` | pass | pass | pass (988 of 988) | pass (11 of 11 vmChecks) | Wave 3 (perf/conc/async/unsafe/macro/test/supply lenses) closed on `phase-w3-integration`: 53 slices, all merged; the merged head then took one repair commit (`d68d0dbcb`, the gated head) for the nine cross-slice break classes the first gate run found, all invisible to per-slice verification in isolated worktrees: two module-scope imports used only by tests, a test-support hook missed by a nesting change, an unsanctioned mutex row in `d2b`'s CLI path, a stale `Cargo.lock` with sixty stale policy-input files (the closure digest, not the census lane, caught that one), twelve `write_with_newline`, `manual_inspect`/`collapsible_if`, a route-shape struct replacing two nine-argument validators, a handler-table type alias, and async-gate inventory drift over 108 sites. 188 rows disposed: 146 applied, 9 applied-variant with recorded deviations, 2 declined (RS-0853, RS-0854 - residuals require design-level ownership change), 1 skipped-stale (RS-0857 - pre_exec is unsafe in tokio and std, compiler-proven), 2 already-fixed (RS-0893, RS-0902), 12 policy-confirmed rows recorded deferred citing their policy, 16 family/wide rows recorded deferred to waves 4-5. Slices W3-37 and W3-38 dispatched at base `b81222ba1` (the forward-rendezvous fix head) per the freeze/unfreeze directive; their rows RS-0802 and RS-0833 anchor `packages/d2bd/src/forward_rendezvous.rs` production symbols. The wave-3 branch merged onto `0c76962ef` (the wave-2 close); the repair was merged fast-forward from there, so this row's head is the gated commit. | -| W4 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 4 (family-blast consolidations): 44 rows disposed - 32 applied, 12 applied-variant. The two rows the wave deferred as needs-contract are recorded below as W7 and applied, which is where they landed. | -| W5 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 5 (wide-blast cross-crate slices), resumed after the harness crash killed the in-flight agents mid-wave: 31 of 31 slices landed (17 already merged at resume, 4 dirty worktrees salvaged, 10 re-dispatched), 0 blocked. Every wave-5 row carries an outcome below; the 10 needs-contract rows this plan routes to the contract wave are folded as needs-contract/W6 with their citation. Preflight and the gate set are the Main gates' step; the wave closes on the final gated head in the head cell. | -| W6 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 6 (the contract-adjacent rows U3 deferred, plus the ten wide rows wave 5 deferred): 25 rows disposed - 18 applied, 6 applied-variant with recorded deviations (RS-0250, RS-0333, RS-0413, RS-0454, RS-0952, RS-0963), 1 skipped-stale that overrode a false audit premise (RS-0547: the audited flatten defect is not reproducible at HEAD - serde refuses unknown members through the container's deny_unknown_fields, which both audited requests carry, so the flattened type's own deny is the inert one - and its requested pin test landed as 8351954a0). The 15 originally dispatched rows landed in the nine w6-01..w6-09 slices; the ten wave-5 deferrals routed to W6 in `.scratch/wave5-slices.md` section 3 landed in slices w6-10..w6-15, the last of them phase-w6-12 (RS-0328 applied, RS-0546 applied, RS-0547 skipped-stale) merged as b07a7e887 with its fourth commit 3d0b38bf0 keeping the layer1-bootstrap build warning-clean. Integration-direct commits: the broker-composition operation-vocabulary fix, the w6-06 changelog fragment title fix, the async-gate inventory refresh. Three close repairs: the pre-existing `clone_on_copy` re-linted in `d2b-core/src/privileges.rs`, the stale family-knowledge exemption in `xtask/src/provider_crate_policy.rs`, and the async-gate hatch inventory re-recorded for ten moved marker sites (4e47723a1: four in `d2b-broker/src/runtime.rs` moved with the w6-12 merge, six in `d2bd` were already stale on the handed-over head, so that red was waiting on a head no preflight had measured). The four clipped reason cells were repaired and marked [reconstructed]. The five preflight commands this wave ran (commands 1-4 rc=0; the bazel checks lane green apart from the pre-existing wave-4 supply-chain red and the documented `daemon_state_persistence` flake) measured code head 4e47723a1; the head cell now names the final gated head, and the row's remaining commits are ledger-only on top of it. | -| W7 | `32a5ebb07` | pass | pass | pass (990 of 990 tests) | pass | Wave 7 (the unfunded remainder, re-opened under the operator rule that compatibility, policy, and ADR clauses are co-changes or amendments and never stops): 52 rows disposed - 37 applied, 7 applied-variant, 8 already-fixed. The per-row evidence is the reason and anchor cells of the W7 rows below; the wave-close artifact that held the rest was scratch-only and is not part of this record. | - -## Findings (965 rows) - -| id | lens | cluster | sev | audit verdict | blast/effort | outcome | wave | commit | anchor | reason or policy citation | escalation | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| `RS-0037` | `idiom` | `d2b` | medium | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | all_known_subcommands derived from parser via modern_cli_subcommands minus PROJECTION_COMMANDS; test updated; mutation (re-add up) fails updated assertion | | -| `RS-0031` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/doctor.rs` | PidfdEntries::state_detail() added; five detail matches replaced | | -| `RS-0036` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_doctor.rs` | summarize uses DoctorSummary::default() | | -| `RS-0032` | `idiom` | `d2b` | low | actionable | leaf | applied-variant | U2 | 0a4f73a1f | `packages/d2b/src/resource.rs` | typed/typed_noun consume TypedResourceArgs by value; 7 dispatch sites pass args.clone() because match binds by reference (deviation recorded | | -| `RS-0033` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | valid_hash deleted; call sites now use valid_digest | | -| `RS-0034` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | nested verify_chain() shared by v1/v2 validation paths | | -| `RS-0035` | `idiom` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/zone_audit.rs` | validate_fields(class, fields, fn) merged; thin wrappers keep both validators | | -| `RS-0001` | `idiom` | `d2b-audit` | medium | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/segment.rs` | One crate-private read_bounded_line(reader, truncated_code, limit_code) in segment.rs; both copies deleted; per-site codes kept. Deviation: truncated kind unified on InvalidData (segment was Other). | | -| `RS-0002` | `idiom` | `d2b-audit` | low | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/export.rs` | Redundant paths.retain block deleted; the push guard is the only is_segment_name filter. | | -| `RS-0003` | `idiom` | `d2b-audit` | low | actionable | leaf | applied-variant | U2 | fc707d752 | `packages/d2b-audit/src/sink.rs` | Inner if-let deleted; outer bindings used. Variant: tuple key cloned once for the durable_mutations insert (key is shadowed and moved); same allocation count, one fewer zone_operation_key derivation. | | -| `RS-0011` | `idiom` | `d2b-broker` | medium | actionable | leaf | applied | U2 | c155578ca | `packages/d2b-broker/src/ops/device_worker.rs` | find_resource_row helper drives row_owner_ref/device_guest_owner/tpm_devices_of_guest | | -| `RS-0006` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 99d7247ee | `packages/d2b-broker/src/runtime.rs` | parse_common_flags helper extracted; parse_probe_flags now takes Vec; error strings preserved | | -| `RS-0007` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 99d7247ee | `packages/d2b-broker/src/runtime.rs` | push loop replaced with filter_map; foreign lock Err early return preserved; merged with RS-0006 in same commit | | -| `RS-0008` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | d2096735c | `packages/d2b-broker/src/sys.rs` | format_errno reversal now iter_mut/zip without intermediate allocation | | -| `RS-0009` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 4234afe18 | `packages/d2b-broker/src/ops/exec_reconcile.rs` | seven hand-copied absolute-path checks factored into require_absolute; error wording normalized; no test asserts old strings | | -| `RS-0010` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | 5a2fa07c7 | `packages/d2b-broker/src/ops/store_view_farm.rs` | run_store_helper and store_helper_failure extracted; both namespaced builders share them | | -| `RS-0012` | `idiom` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | open/publish/init_trusted_context_store gated #[cfg(test)]; only in-crate test callers existed; Drop persist path left ungated | | -| `RS-0004` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | applied-variant | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | successors().take(4).find() chain. Variant: closure needs .map(Path::to_path_buf) since parent() returns Option<&Path>; the row's literal closure would not compile. | | -| `RS-0005` | `idiom` | `d2b-broker-composition` | low | actionable | leaf | applied | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/seam.rs` | Parameter renamed _invocation; let _ = invocation; deleted. | | -| `RS-0013` | `idiom` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | resolve_for_service uses filter_map+next() over collect-then-index; bus check+tests passed | | -| `RS-0014` | `idiom` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/operations.rs` | abort_destination uses drain(..).partition and aborts drained handles; tests passed | | -| `RS-0015` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/kernel_client.rs` | if let Some(code) = response.refusal.clone() with Refused { code, detail }; one clone retained because response is moved into KernelReply afterwards. | | -| `RS-0016` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/host_generation.rs` | Never-firing !matches!(Lifecycle/Admin) guard deleted; InvalidTransition still used by the resource-type check. | | -| `RS-0017` | `idiom` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/broker_wire.rs` | for_display RootUid arm now d2b-root; pinned in the label test. Method label, not a serialized field; no committed JsonSchema carries it. Sibling d2b-broker bootstrap.rs twin out of packet scope. | | -| `RS-0018` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential.rs` | derive(Default) with #[default] on RotationPolicyClass::OnExpiry and RevocationAction::Immediate; manual Default impls deleted | | -| `RS-0020` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs` | producer_ref.transpose()? bound once; duplicate 15-field BindingChildIntent literal collapsed to one push, else-continue arm deleted | | -| `RS-0019` | `idiom` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | manual Debug impl on UpgradePolicy replaced by #[derive(Debug)] | | -| `RS-0022` | `idiom` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/execution_policy.rs` | crate-private ensure_unique helper shared by the volume, process, and execution-plan uniqueness checks | | -| `RS-0021` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/network.rs` | derive Default with #[default] on Ipv4Method::Dhcp; hand-written impl deleted | | -| `RS-0023` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | applied-variant | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/resource.rs` | stated fix not implementable: &CanonicalJsonObject is not IntoIterator, so a borrowed iter() was added to the type and the base is iterated through it | | -| `RS-0024` | `idiom` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/volume.rs` | contains_key plus re-get collapsed into one get with ok_or | | -| `RS-0025` | `idiom` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | f547324ca | `packages/d2b-contracts-zone-session/src/v3/component_session.rs` | Default derived on ReceiveSequence/SendSequence; hand-written impls deleted; ZoneLinkLimits Default kept | | -| `RS-0027` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | let spec = find_network_spec(&parts)?; let _ = spec; replaced by bare self.find_network_spec(&parts)?; in projection and sysctl intents | | -| `RS-0030` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | iter().any(f == last) replaced with slice contains for PUBLIC_MANIFEST_FIELDS and BROAD_CAPABILITIES | | -| `RS-0028` | `idiom` | `d2b-core` | low | actionable | leaf | applied-variant | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | row's bare-import removal broke tests using TapRole via use super::*; variant: import dropped, const deleted, 3 test sites qualified crate::host::TapRole (as _ import rejected by -D warnings) | | -| `RS-0029` | `idiom` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | resolve_disk_init_ops flattened to vm.nodes.iter().flat_map(...).filter_map(...).collect() | | -| `RS-0026` | `idiom` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | Both duplicate-reservation checks are entry.holders.iter().any(...) predicates; let _ = holder; gone. | | -| `RS-0040` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:3-16, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:91-97, packages/d2b-provider-clipboard-wayland/src/policy.rs:3-14, packages/d2b-provider-clipboard-wayland/src/policy.rs:91-93` | two deliberate variants: (1) canonical secret-hint list is the union of both previous lists so no secret detection is weakened on either path (host tests pin application/x-secret-service; guest-only h | | -| `RS-0039` | `idiom` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | 9d0eaefff | `src/bin/d2b-clipd.rs:2812, src/policy.rs:12` | none | | -| `RS-0041` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:11-18, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:113-126` | commit grouping: the picker.rs changes landed in the same commit as fallback.rs (018c1dad5) because two parallel git add/commit calls raced on the shared index and the second committed both staged fil | | -| `RS-0038` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 9d0eaefff | `src/bin/d2b-clipd.rs:1131` | none (Ok wrapper required by the existing signature) | | -| `RS-0042` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:40-46, packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:5-12` | none | | -| `RS-0043` | `idiom` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied-variant | U2 | f0210347a | `packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:22-42, packages/d2b-provider-clipboard-wayland/src/clipd_host/policy.rs:45-68` | implemented the inverse of the row's literal suggestion (a const table read by as_str): Serialize delegates to as_str instead, which keeps the match as the single source of truth with a smaller diff, | | -| `RS-0044` | `idiom` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 3459dc5a0 | `packages/d2b-provider-config-nixos/src/ttrpc.rs` | Shared path_components helper classifies Path::components; both callers use it | | -| `RS-0045` | `idiom` | `d2b-provider-credential-entra` | medium | actionable | family | applied | W5 | 1fe37219f | `packages/d2b-provider-credential-entra/src/lib.rs:1164, packages/d2b-provider-credential-entra/src/lib.rs:1172, packages/d2b-provider-credential-entra/src/lib.rs:1187, packages/d2b-provider-toolkit/src/credential.rs:111` | the credential-entra in-crate deadline trio is folded onto the toolkit credential helpers, all eight call sites re-pointed, expired-grant and expired-inspection checks compose the toolkit primitives, and deadline bounds compare two operation_deadline instants | | -| `RS-0046` | `idiom` | `d2b-provider-credential-secret-service` | low | actionable | leaf | applied | U2 | 20e8286f8 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | SecretServiceOwner::Userd renamed to User; enum not serialized; census 2 hits in-crate | | -| `RS-0047` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | rustfmt drift normalized: enum closing brace, trailing-whitespace line, reindented variant doc comment | | -| `RS-0048` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/effects_service.rs` | let _ = binding dropped; Self::declared_row_template(&view, role)?; | | -| `RS-0049` | `idiom` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/authority.rs` | in-crate macro_rules! opaque_token (derive list + is_zero/as_bytes feature arms, stringify redacting Debug); all 6 newtypes migrated with exact surfaces preserved | | -| `RS-0050` | `idiom` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U2 | db396585b | `packages/d2b-provider-device-security-key/src/driver.rs` | declared_dependency_refs arms are iterator-chain expressions; push closure deleted | | -| `RS-0051` | `idiom` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | swtpm_argv.rs imports and uses MIN/MAX_SWTPM_LOG_LEVEL instead of literal 1..=20 | | -| `RS-0052` | `idiom` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | 9e7388e34 | `packages/d2b-provider-device-usbip/src/driver.rs` | declared_dependency_refs match arms return flatten().collect() expressions | | -| `RS-0059` | `idiom` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | Applied with this commit: display-wayland: drop stale dead-code allows and delegate session digest | | -| `RS-0053` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | Applied with this commit: display-wayland: simplify bridge handoff error binding and bind dispatch | | -| `RS-0058` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 107f8775b | `packages/d2b-provider-display-wayland/src/controller.rs` | Applied with this commit: display-wayland: drop stale dead-code allows and delegate session digest | | -| `RS-0054` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs` | row fix text names chains for wm_base/eglstream/compositor; the remaining shm/subcompositor/seat/viewporter/dmabuf/drm if-lets stay in the final else block, matching the row's 'keeping the early retur | | -| `RS-0055` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | Applied with this commit: display-wayland: tidy dmabuf table loop and share filter list by Rc | | -| `RS-0056` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/decoration.rs` | Applied with this commit: display-wayland: track written label chars and document bridge and readiness errors | | -| `RS-0057` | `idiom` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | f7f3f2708 | `packages/d2b-provider-display-wayland/src/wayland_proxy/dmabuf.rs` | row says 'four comment blocks' while citing 7 sites; all 7 sites fixed | | -| `RS-0061` | `idiom` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/effects_service.rs` | Added the unit-test option: pinned inspect-endpoint payload rows to guest_control_producer/device_worker_endpoint_class (set + per-row class/producer/locality). Mutation (locality drift) fails the tes | | -| `RS-0060` | `idiom` | `d2b-provider-endpoint` | low | actionable | leaf | applied | U2 | 7d49c455d | `packages/d2b-provider-endpoint/src/endpoint.rs` | Derive Default on EndpointConsumerPolicy (field-wise empty-Vec default identical to unrestricted()); dropped the manual impl. | | -| `RS-0062` | `idiom` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | derive(Default) with #[default] on BootstrapServiceState::Waiting; manual BootstrapService Default impl deleted | | -| `RS-0063` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs` | _config field and initializer deleted; config.validate() kept in from_verified_descriptor. | | -| `RS-0064` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied-variant | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs` | Field deleted. Variant: its only read fed a write nobody read, so as a local it tripped -D warnings unused-assignments; dead tail and set sites deleted as dead state. | | -| `RS-0065` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs` | ChildRole::rank() added; deletion_rank/upgrade_rank free fns deleted; both sort sites call role.rank(). | | -| `RS-0066` | `idiom` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs` | readiness() wrapper deleted; test calls vmm_readiness with explicit booleans. Census confirmed only the two test assertions called it. | | -| `RS-0067` | `idiom` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 7cb57d2fe | `packages/d2b-provider-guest-qemu-media/src/config.rs` | Default impls call default_qemu_artifact/default_vcpu/default_memory_mib/default_boot_media_view | | -| `RS-0068` | `idiom` | `d2b-provider-host` | low | actionable | leaf | applied | U2 | 3d165efc4 | `packages/d2b-provider-host/src/test_support.rs` | Dedented the stray impl-closing brace (RecordingMinijailGate) to column 0. | | -| `RS-0069` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Octets destructured via try_into and rendered with one format! | | -| `RS-0070` | `idiom` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/driver.rs` | declared_dependency_refs is a filter_map pipeline over attachments | | -| `RS-0071` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/controller.rs` | expected_acknowledgements collects the chained start/stop endpoint maps directly; conditional HostSink pushes kept. | | -| `RS-0072` | `idiom` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/descriptor.rs` | service_package() returns crate::SERVICE_PACKAGE; literal has one home. | | -| `RS-0073` | `idiom` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U2 | 8fcd947b2 | `packages/d2b-provider-process-systemd/src/effects_service.rs` | Replaced both hand-written impl Default blocks with #[derive(Default)] on SystemdEffectsService and SystemdEffectsServiceFactory. | | -| `RS-0074` | `idiom` | `d2b-provider-seccomp-profile` | low | actionable | leaf | applied | U2 | 4d49437db | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs` | Dedented three impl-block closing braces (DeviceNodePath, DeviceBind, SeccompProfileSpec) to column 0. | | -| `RS-0075` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | applied | U2 | 4065c7032 | `packages/d2b-provider-supervisor/src/systemd.rs` | Deleted the no-op `let _ = &handle.pidfd;` in BrokerSystemdEffectOwner::stop. | | -| `RS-0076` | `idiom` | `d2b-provider-supervisor` | low | actionable | leaf | applied | U2 | 4065c7032 | `packages/d2b-provider-supervisor/src/observations.rs` | Extracted one shared bounded pending-observation ledger (observations.rs record/take) used by both Broker and Systemd backends. | | -| `RS-0077` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | to_hex uses a const HEX table; dead unwrap_or fallback removed | | -| `RS-0078` | `idiom` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/user.rs` | required_bindings is a free pub fn re-exported at root; Self:: call and two test sites updated | | -| `RS-0079` | `idiom` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/fd10.rs` | request() calls valid_guest_backend_operation(&operation); the inline 15-entry matches! deleted; single allowlist remains. | | -| `RS-0080` | `idiom` | `d2b-provider-toolkit` | low | actionable | leaf | applied-variant | U2 | c496e2214 | `packages/d2b-provider-toolkit/src/base/fd10.rs` | One struct carries the accessors plus new/with_sensitive_bytes/encode, keeping the zeroizing bytes field. Variant: GuestCredentialBackendReply kept as a type alias so consumers compile unchanged. | | -| `RS-0081` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | RelaySecret derives Clone; hand-written impl deleted | | -| `RS-0082` | `idiom` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 6fe6615af | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | Bearer header built from a literal instead of a collected char array | | -| `RS-0083` | `idiom` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U2 | fda87abbe | `packages/d2b-provider-transport-vsock/src/auth.rs` | ReadySession::disconnect now drops mut and returns SessionState::Disconnected directly (SessionState is Copy). | | -| `RS-0084` | `idiom` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix (envelope.base.get("provider").cloned()) is type-incompatible: base.get yields CanonicalJsonValue not serde_json::Value. Applied minimal variant: dropped the dead unwrap_or fallback via an | | -| `RS-0085` | `idiom` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/status.rs` | LayoutPhase::worse now uses derived self.max(other); declaration order already encodes severity. | | -| `RS-0086` | `idiom` | `d2b-provider-zone-link` | medium | actionable | family | applied | W4 | b062e724d | `packages/d2b-provider-zone-link/src/zone_links.rs:60, packages/d2b-provider-zone-link/src/zone_links.rs:63, packages/d2b-bus/src/session/enrollment.rs:42, packages/d2b-bus/src/session/enrollment.rs:49` | | | -| `RS-0087` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | f5dd934fc | `packages/d2b-contracts-resource/src/v3/execution_policy.rs` | The redacted_debug macro was extended with a closure-based field-preserving form (two exported helper fns redacted_debug_field_ref and redacted_debug_field_value), and all 17 hand-written redaction De | | -| `RS-0088` | `idiom` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/manager_backend/tests.rs` | Unformatted use lines reindented to 4 spaces with inner-brace spacing dropped. | | -| `RS-0089` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Hoisted await_with_cancellation and classify_session_error into call.rs; both clients call the single copies (process_attach's classify_attach_error renamed to the shared classify_session_error). | | -| `RS-0090` | `idiom` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/zone_client.rs` | Dropped the duplicate GuestControlEndpoint::endpoint_uid accessor (kept uid()); removed the now-obsolete equivalence assertion. Census: no external caller. | | -| `RS-0091` | `idiom` | `d2b-resource-compiler` | medium | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | stated fix not implementable as written: pub(crate) items in the lib are not importable from the bin target (cargo E0603), so sanitize_token/bound_message became pub with doc first sentences; safe_lab | | -| `RS-0092` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's stated filter pipeline would drop replaced characters; the behavior-preserving variant uses map with the same condition, keeping the '?' substitution (user-visible CLI error text) | | -| `RS-0093` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | -| `RS-0094` | `idiom` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/lib.rs` | the row's literal snippet is missing parentheses; the chain shape used is names.difference(...).map(...).chain(declared_names.difference(...).map(...)).collect() preserving bin= then manifest= order | | -| `RS-0095` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | derive Default on three unit structs; new() const kept | | -| `RS-0097` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | W7 | 1fb8eff80 | `packages/d2b-resource-runtime/src/target.rs:737` | both listings sort through one owned identity key with sort_by_cached_key (the borrowed-key forms are lifetime errors); ordering unchanged and the key is cloned once per element instead of twice per comparison. Merged 6f1390556. | | -| `RS-0096` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | shared free manager_rpc transport; both endpoints route through it | | -| `RS-0098` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | derive Default on TargetDirectory | | -| `RS-0099` | `idiom` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | impl FromStr for ResourceProvenance; store parses via str::parse | | -| `RS-0100` | `idiom` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/engine.rs` | index loop replaced with chunks_exact().take(count).map(decode_attachment_descriptor).collect::>>() | | -| `RS-0101` | `idiom` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/admission.rs` | send_authorized_ttrpc now calls validate_ttrpc_permit(&permit, now_tick)? instead of re-writing the matches! block | | -| `RS-0102` | `idiom` | `d2b-sk-frontend` | low | actionable | leaf | applied | U2 | 0b8ef8ff5 | `packages/d2b-sk-frontend/src/config.rs` | zone_path now collects labels with an iterator pipeline (split/map/collect) instead of a push loop. | | -| `RS-0103` | `idiom` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U2 | f3a847c72 | `packages/d2b-unsafe-local-helper/src/systemd.rs` | Replaced the then_some/ok_or NotFound normalization with an explicit if-let/if-error branch in terminate_scope and stop_scope; cargo check and test green. | | -| `RS-0104` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | 932616e19 | `packages/d2b-zone-routing/src/resolver.rs` | longest_suffix_match is a find_map over the index range | | -| `RS-0105` | `idiom` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | c8defa1f4 | `packages/d2b-zone-routing/src/service.rs` | ZoneTopologyRequest derives Default; manual impl deleted | | -| `RS-0106` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | caller at 4555 now calls committed_resource(3 args); deleted current_committed_resource fn | | -| `RS-0108` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | retry loop uses PROVIDER_IDENTITY_SEED_ATTEMPTS/INTERVAL consts; 30x2s rationale comment kept | | -| `RS-0109` | `idiom` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | hoisted list+dispatch above rollback split; both branches share 'activation generations unavailable' (was 'rollback generations unavailable'); no test pins strings | | -| `RS-0111` | `idiom` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 970d1dcd5,14efca7ef | `packages/d2bd/src/provider_lifecycle.rs` | if/else chains converted to match; X.id field-access is invalid in patterns so arms use guards `x if x == X.id`; factory match scrutinee wrapped in parens for let-else | | -| `RS-0112` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 6389b6473 | `packages/d2bd/src/effect_service_actors.rs` | hand-written impl Default replaced by #[derive(Default)] on EffectServiceActor and EffectServiceSupervisor | | -| `RS-0113` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 3220fd1ce,457373d5b,955abf009 | `packages/d2bd/src/forward_rendezvous.rs` | deleted dead `let _ = &mut chain;` and `let _ = error.code();`; `kind` param kept because used by assignment_fence (no dead binding existed) | | -| `RS-0107` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | deleted redundant `let setup = setup;` rebind | | -| `RS-0110` | `idiom` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | dropped _registry_dir/registry_dir params from qemu_media_registry_state/qemu_media_source_status; all 4 call sites updated | | -| `RS-0114` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/autostart.rs` | build_autostart_plan uses iterator partition into the two sorted Vec halves | | -| `RS-0115` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | fd extraction loops are filter_map+flatten collects | | -| `RS-0116` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/guest_mode.rs` | monotonic_tick deduped into runtime_util (LazyLock per repo std; lazy init preserved} | | -| `RS-0117` | `idiom` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | ConsoleSessionTable derives Default; manual impl deleted | | -| `RS-0118` | `idiom` | `xtask` | medium | actionable | leaf | applied | U2 | 80037234d | `gen_layer_catalogs.rs` | string_array deleted; ten call sites rerouted through string_slice | | -| `RS-0120` | `idiom` | `xtask` | medium | actionable | leaf | applied-variant | U2 | e5f3b7f25 | `packages/xtask/src/main.rs` | AST extraction replaces the hand-rolled scanners; type text span-sliced via a once-per-file line index (ToTokens unusable: not a direct dep). gen-daemon-api output byte-identical. | | -| `RS-0123` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 7eef023f9 | `resource_type_authority.rs` | three statements reindented | | -| `RS-0124` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | fc0353eb1 | `nix_inventories.rs` | applied-variant: generic S: AsRef + Display standard params (caller with Vec cannot feed &[&str]); call site passes STANDARD_RESOURCE_TYPES.as_slice() | | -| `RS-0119` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | a8bc3bb0b | `packages/xtask/src/gen_layer_catalogs.rs` | Ten surface_catalog blocks and the two protobuf redaction templates converted to r## raw strings; all 12 literals verified byte-identical against HEAD; gen-layer-catalogs --check passes. | | -| `RS-0121` | `idiom` | `xtask` | low | actionable | leaf | skipped-stale | U2 | bbd40b6fd | `packages/xtask/src/main.rs:464` (sanitize_generated_rust) | premise false: the literal matches the ttrpc-compiler 0.8.0 marker exactly, so the strip is live. The wave's deletion was reverted - without it the committed binding file is not reproducible and the bogus attribute fails -D warnings; regeneration is byte-stable again. | | -| `RS-0122` | `idiom` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | dead close-block reset replaced with scan end at closing brace | | -| `RS-0964` | `own` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 564cc6d00 | `packages/d2bd/src/resource_plane_v3.rs:3227, packages/d2b-resource-runtime/src/target.rs:4` | public Arc surfaces narrowed at the named sites: the ConsoleRing::notify accessor is deleted, ConsoleSession::ring returns &Mutex, DaemonAuditLog.captured is private behind an accessor, TargetBinding::new takes TargetDirectory by value, and SkAcceptHandle.state is private behind an accessor; all 13 Arc constructor params are kept with per-site reasons (stored and cloned at a spawn boundary, a per-driver factory, an admission offer/engine pair, a split transport half, or a test-held clock) | | -| `RS-0150` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | cursor/page_token/reference moved into calls;call-site reassignment unchanged | | -| `RS-0151` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | try_parse_from consumes raw_args by value (sole caller, never reused) | | -| `RS-0152` | `own` | `d2b` | low | actionable | leaf | applied | U2 | d4e4604e4 | `packages/d2b/src/dispatch.rs` | host_error_envelope takes impl Into;;&format! results move in directly | | -| `RS-0149` | `own` | `d2b` | low | actionable | leaf | applied | U2 | 0a4f73a1f | `packages/d2b/src/doctor.rs` | json! literal clones dropped (schema_version, issue_kinds, issues) | | -| `RS-0125` | `own` | `d2b-audit` | low | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/operation.rs` | AuditHash::parse(value) without to_owned; &str: Into holds. | | -| `RS-0129` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | c3ac2bb59 | `packages/d2b-broker/src/ops/pidfd.rs` | redundant payload.argv.clone removed; impl param renamed _payload | | -| `RS-0131` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | b09261be0 | `packages/d2b-broker/src/ops/media.rs` | unwrap_or_else(/_/ vec![record]) in enroll; merged with RS-0630 docs in same commit | | -| `RS-0130` | `own` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | Bootstrap reply shrunk to Result<(),>; state.clone removal; merged with RS-0012/RS-0628 in same commit | | -| `RS-0126` | `own` | `d2b-broker-composition` | low | actionable | leaf | applied-variant | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | added consumed by value. Variant: a name in both lists still needs one clone, so a match on (forbidden, proc_macro) moves into one list and clones only in the both-true case. | | -| `RS-0127` | `own` | `d2b-broker-composition` | low | actionable | leaf | applied | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | contains(&crate_name.to_string()) replaced with iter().any(/name/ name == crate_name). | | -| `RS-0128` | `own` | `d2b-broker-composition` | low | actionable | leaf | applied | U2 | cf91a0aa7 | `packages/d2b-broker-composition/src/dependency_surface.rs` | queue: Vec<&str> and seen: BTreeSet<&str>; ids borrowed from metadata; returned Vec untouched. | | -| `RS-0132` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | ScopedCommitTransport::validate added; authorization_request validates borrowed data instead of cloning | | -| `RS-0133` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/prologue.rs` | of_subject hashes &str slices via hash_resource_ref; digest byte-identical (full bus suite passed | | -| `RS-0134` | `own` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/session/contract.rs` | private verify_body() shared by verify()/revalidate(); clone removed | | -| `RS-0137` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/telemetry_policy.rs` | duplicate-detection set now BTreeSet<&str> inserting &label.key | | -| `RS-0135` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | validate_runtime_artifacts takes &[TargetRuntimeArtifacts]; entries.clone() and self.runtime_artifacts.clone() dropped; test call site updated | | -| `RS-0138` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs` | is_valid_zone(&str) extracted; validate_zone delegates to it; allowed_telemetry_value no longer allocates | | -| `RS-0136` | `own` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | dedup sets now BTreeSet<&BoundedToken>/BTreeSet<&ResourceTypeName> in ProviderManifest::new and with_state_namespaces | | -| `RS-0139` | `own` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/volume_state.rs` | SchemaFingerprint::parse takes the borrowed str instead of cloning | | -| `RS-0142` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied-variant | U2 | 862071320 | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs` | Order-preserving contains check (n<=64) instead of sort-in-place: sorting would change serialized bytes of a signed wire message for unsorted inputs | | -| `RS-0140` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | W4 | a2cf0e614 | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:456, packages/d2b-contracts-zone-session/src/v3/component_session.rs:473` | | | -| `RS-0143` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | acffb7466 | `packages/d2b-contracts-zone-session/src/v3/resource_bundle.rs` | Walk iterates CanonicalJsonObject keys directly; no wrapper or clone built | | -| `RS-0141` | `own` | `d2b-contracts-zone-session` | low | actionable | family | applied | W4 | a2cf0e614 | `src/v3/resource_export.rs:545, src/v3/resource_export.rs:546` | | | -| `RS-0144` | `own` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U2 | 7be394a88 | `packages/d2b-contracts-zone-session/src/v3/services.rs` | BoundedText::parse takes method.as_str() instead of method.clone() | | -| `RS-0148` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/static_invariants.rs` | path_bearing_key_violations renders through Cow; string arm borrows instead of cloning | | -| `RS-0147` | `own` | `d2b-core` | low | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | parse(value.as_str()) at 3 sites; network_uid compare via as_str; note: row rationale 'no allocation' inaccurate (Into still allocates) but explicit clones removed | | -| `RS-0145` | `own` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/owner_reconcile.rs` | observed bound as &BTreeMap via ok_or(OwnerNotRelisted); .get/for-in/ordered_observed_refs/mutation_sort_parts take the borrow; whole-map clone removed. | | -| `RS-0146` | `own` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/authority.rs` | claim computed from request.durable_claim() before the lock block; request moved into admit_authority_inner_with_operation; .clone() deleted. | | -| `RS-0153` | `own` | `d2b-process-conformance` | low | actionable | leaf | applied | U2 | e47020297 | `packages/d2b-process-conformance/src/ticket.rs` | All four with_* builders (with_runtime_identity, with_owner_uid, with_owner_ref, with_target_ref) now move launch_identity instead of cloning it. | | -| `RS-0154` | `own` | `d2b-provider` | low | actionable | leaf | applied | U2 | d6adc6a8e | `packages/d2b-provider/src/agent.rs` | ProviderAgent::dispatch extracts Copy method, moves request into service.dispatch(request) instead of cloning, and uses the local method in the audit record. | | -| `RS-0155` | `own` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | b8724cd15 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:257-263` | none | | -| `RS-0156` | `own` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | b17a8c271 | `packages/d2b-provider-config-nixos/src/controller.rs` | GuestConfigDocument::into_bytes() consuming accessor; dispatch passes it without copying | | -| `RS-0157` | `own` | `d2b-provider-credential` | low | actionable | leaf | applied | U2 | b68a9b55e | `packages/d2b-provider-credential/src/driver.rs` | Dropped dead derives: Clone on CredentialDriver and Default on RecordingRuntime (no call sites; RecordingRuntime::new kept as the only constructor). | | -| `RS-0158` | `own` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | validate &identity before store; identity stored on failure branch preserving test-pinned retain-for-finalize contract | | -| `RS-0159` | `own` | `d2b-provider-device-tpm` | low | actionable | leaf | applied-variant | U2 | 3c3a82817 | `packages/d2b-provider-device-tpm/src/resource_controller.rs` | if/else arms cannot mix owned and borrowed; restructured to ensure-then-borrow from the fields (zero clones), plus the two effects_service reborrows | | -| `RS-0160` | `own` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | U2 | d674e47e9 | `packages/d2b-provider-device-usbip/src/broker.rs` | Lease moved into the field first; map and return clone from the field (3 clones down to 2 per admission) | | -| `RS-0161` | `own` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 309cded8c | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs` | the type must propagate to the two child handlers (DmabufFeedbackHandler, DmabufBufferParamsHandler) and five test constructions, which clone the same filters value; sync::Arc import removed from dmab | | -| `RS-0162` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied-variant | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/driver.rs` | Applied the row's sort_by comparator, fixing its misplaced-paren typo (teardown_rank().cmp().then_with(name cmp)); drops the per-row name clone. | | -| `RS-0163` | `own` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/effects_service.rs` | Both ACA candidate lists use state.sandbox.iter().cloned().collect() (and disk_image) instead of clone().into_iter().collect(). | | -| `RS-0164` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W7 | 7b480f35d | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs:152` | eviction computes the minimum record sequence once (a Copy u64; sequences are unique because next_sequence increments per insert) and removes exactly that entry with a single retain, so no AcaOperationId clone remains; the Borrow shape was rejected because it still needs an owned key out of the map borrow. A new test pins oldest-first eviction. Merged 39411da5e. | | -| `RS-0165` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | reconcile_observed extracts Copy lifecycle first, moves record into self.observed without clone, matches on the extracted lifecycle. Applied with RS-0166 as one considered change per packet. | | -| `RS-0166` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | e5524be9c | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | record.id moved out of the stored record via take().expect(...).id, resolving the partial-move vs whole-record-store conflict. Deviation: on resume failure observed is None (was Some(record)). | | -| `RS-0167` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 9730af073 | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | Stop and delete stages clone only the sandbox id (observed.as_ref().ok_or(...)?.id.clone()) and move it into the closures; the delete-stage Stopping check reads observed.as_ref().is_some_and(..). | | -| `RS-0168` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 35da01dbd | `packages/d2b-provider-guest-azure-container-apps/src/controller.rs` | one_candidate and one_disk_image consume their owned candidates via into_iter + (next(), next()) match, removing both clones; IntoIterator impls added for both candidate types in effects.rs. | | -| `RS-0169` | `own` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 48072a121 | `packages/d2b-provider-guest-azure-container-apps/src/effects.rs` | Extracted validate_refs() with the resource_type() checks, called from new() on raw args and validate() on self; validate() re-clones nothing. Deviation: helper takes the four refs, not &self. | | -| `RS-0170` | `own` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied-variant | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | zeroize here lacks into_inner and From> for T; variant: std::mem::take(&mut *delivery) moves buffer out, no plain Vec copy | | -| `RS-0171` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | both vm_handle sites borrow via as_ref().ok_or(AzureVmError::Ambiguous) instead of cloning | | -| `RS-0172` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | pending_delete_operation_id borrowed via as_deref() instead of clone | | -| `RS-0173` | `own` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | base32 output truncated in place (id.truncate(20)) instead of a second 20-char copy | | -| `RS-0174` | `own` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U2 | 2e56bfa23 | `packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs` | execute destructures transport/commands, pushes the owned command, executes from commands.back() | | -| `RS-0175` | `own` | `d2b-provider-host` | low | actionable | leaf | applied | U2 | 3d165efc4 | `packages/d2b-provider-host/src/driver.rs` | resource_ref now passes &ctx.key().type_name / &ctx.key().name to ResourceTypeName::parse / ResourceName::parse (impl Into), dropping both clones. | | -| `RS-0176` | `own` | `d2b-provider-network-local` | low | actionable | leaf | applied | U2 | 21e8948b2 | `packages/d2b-provider-network-local/src/controller.rs` | Collision set stores &str borrowed from interface_names | | -| `RS-0177` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied-variant | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/controller.rs` | commit_reconciliation takes &SourceReconcileResult; both call-site .clone()s dropped. Variant: body iterates &result.stop and clones only endpoints inserted into active_sources. | | -| `RS-0178` | `own` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/lifecycle.rs` | backend: B stored directly; Arc import dropped; Send+Sync bounds kept via the trait bound. | | -| `RS-0179` | `own` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/agent.rs` | parse_token/parse_closed_token now take &str (BoundedToken::parse accepts it); dropped the five clone() calls in session_connect/process_effect. | | -| `RS-0180` | `own` | `d2b-provider-process` | low | actionable | leaf | applied | U2 | ada188a9c | `packages/d2b-provider-process/src/driver.rs` | Three identity() sites now use envelope.provider_ref.as_ref().expect("checked") instead of .clone().expect. | | -| `RS-0181` | `own` | `d2b-provider-process` | low | actionable | leaf | applied | U2 | ada188a9c | `packages/d2b-provider-process/src/operations.rs` | bind_cloud_hypervisor_guest_uid now takes argv: Vec by value and returns it; sole caller passes launch_argv directly; removed both to_vec copies. | | -| `RS-0182` | `own` | `d2b-provider-provider` | low | actionable | leaf | applied | U2 | 46b177892 | `packages/d2b-provider-provider/src/driver.rs` | Three zone clones now pass ctx.key().zone.as_str() / view.key.zone.as_str() to ZoneId::parse; the system-core branch uses a &str local. | | -| `RS-0183` | `own` | `d2b-provider-provider` | low | actionable | leaf | applied-variant | U2 | 46b177892 | `packages/d2b-provider-provider/src/driver.rs` | Stated fix's assumption (last previous read before set_status) fails: dependencies(ctx) needs &mut ctx between the two previous reads. Minimal variant: reordered dependencies() before the status read | | -| `RS-0184` | `own` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/service/supervisor.rs` | advance_session now scopes the first session_mut borrow in a block and compares supervisor_identity.as_ref() directly; dropped the clone. | | -| `RS-0185` | `own` | `d2b-provider-system-core` | low | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | reconcile_observed destructures the owned snapshot and moves kernel_release/os_name | | -| `RS-0187` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/adapter.rs:331-334` | | | -| `RS-0188` | `own` | `d2b-provider-toolkit` | low | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/server/adapter.rs:305, packages/d2b-provider-toolkit/src/server/adapter.rs:314-316` | the provider session loop compares the bound controller route inside the route mutex lock scope, dropping the per-frame AuthenticatedSessionRouteBinding clone | | -| `RS-0186` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | is_ready_for_route compares through the guard via is_some_and(/ready/ ready.as_ref().is_some_and(/bound/ bound.liveness().is_live() && bound == route)); no clone. | | -| `RS-0189` | `own` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/shared_provider.rs` | sort_by with teardown_rank cmp then name cmp; no per-row String allocation. | | -| `RS-0190` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | f66537394 | `packages/d2b-provider-transport-azure-relay/src/credential_client.rs` | with_deadline consumes self and rebuilds with struct-update syntax; sole caller passes owned request | | -| `RS-0191` | `own` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 72858f537 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs` | GatewayCredential stores material: GatewayCredentialMaterial moved in from_material; Drop impl deleted (material zeroizes); accessors and Debug unchanged | | -| `RS-0192` | `own` | `d2b-provider-user` | low | actionable | leaf | applied-variant | U2 | 9ba7acf09 | `packages/d2b-provider-user/src/effects_service.rs` | Destructured InspectUserRequest and moved groups by value; username still cloned because inspect_user_response borrows it after UserSpec::new consumes it (stated fix was not implementable as written). | | -| `RS-0193` | `own` | `d2b-provider-volume` | low | actionable | leaf | applied-variant | U2 | 1f682b049 | `packages/d2b-provider-volume/src/driver.rs` | Stated fix not type-compatible: ctx.spec returns &T so decoded_spec returned an owned clone. Minimal variant: decoded_spec now returns (&VolumeSpecEnvelope, VolumeSpec); callers adapted; removed the p | | -| `RS-0194` | `own` | `d2b-provider-volume` | low | actionable | wide | applied | W5 | eee03f2a9 | `packages/d2b-provider-volume-local/src/bindings.rs:80, packages/d2b-provider-volume-local/src/bindings.rs:80-81, packages/d2bd/src/resource_runtime.rs:5882, packages/d2bd/src/resource_runtime.rs:12921` | desired_binding_intents takes the volume ResourceRef by borrow; the volume driver and the shared runtime no longer clone the reference before every binding-intent derivation | | -| `RS-0195` | `own` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/row_readers.rs` | Bounded the as_object_mut removal borrow in a block and moved spec into serde_json::from_value, dropping the Value::Object(object.clone()). | | -| `RS-0196` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | Both plan() route-binding arms (RoutePolicyCommitted, SessionGenerationAdvanced) now borrow record.route_binding.as_mut() and mutate through it; dropped the clone + store-back. | | -| `RS-0197` | `own` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | EnrolledSessionEstablished arm now takes record.enrollment.as_ref() and compares the fingerprint, ending the borrow before record.link_epoch mutation. | | -| `RS-0198` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/client.rs` | scoped_commit_batch and commit_scoped_batch take &[ScopedResourceMutation]; commit_batch_with_scope takes Option<&[..]>; adapter passes transport.mutations() directly. | | -| `RS-0199` | `own` | `d2b-resource-api` | low | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/admission.rs` | mutations.into_iter().map(prepare_mutation); the redundant .cloned() removed. | | -| `RS-0200` | `own` | `d2b-resource-client` | low | actionable | family | applied-variant | W5 | 707ad428e | `packages/d2b-resource-client/src/target.rs:155, packages/d2b-resource-client/src/target.rs` | ResolvedTarget::matches_assignment compares the Execution assignment reference by borrow (stored reference for a Resource owner; resource type and name for Guest/Provider/Host) instead of materializing and cloning a ResourceRef; deviation: the public by-value resource_ref() accessors stay by-value, which is the deferral the row itself records for its ~15 external callers | | -| `RS-0202` | `own` | `d2b-resource-compiler` | medium | actionable | leaf | applied | U2 | 628c96492 | `packages/d2b-resource-compiler/src/linux.rs` | Applied with this commit: resource-compiler: drop the unused anchored flag accessors | | -| `RS-0201` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | -| `RS-0203` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | -| `RS-0204` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied-variant | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | row's stated fix (drop the argv[0] binding) is functionally broken; minimal correct variant keeps the skip via args.nth(1) | | -| `RS-0205` | `own` | `d2b-resource-compiler` | low | actionable | leaf | applied | U2 | b2fef5145 | `packages/d2b-resource-compiler/src/main.rs` | Applied with this commit: resource-compiler: share the sanitizers and simplify schema and CLI checks | | -| `RS-0206` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | observed_status filters before clone | | -| `RS-0209` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | insert_new takes StoredDesiredResource by value; ensure passes by move | | -| `RS-0207` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 0e6061c1e | `resource.rs` | pre_start moves row into state; clones only for ResourceContext::new | | -| `RS-0210` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | fb5ed9466 | `spec_store.rs` | list binds borrowed selector str forms | | -| `RS-0208` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | W7 | 7b480f35d | `packages/d2b-resource-runtime/src/metadata.rs:167` | the fence now validates in place and returns Result<(), DriverFailure>; the sole caller discards the value, so the clone is deleted rather than moved; decode and shape refusals stay byte-identical. Merged 39411da5e. | | -| `RS-0211` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 1f9423d9a | `target.rs` | assign moves assignment into map and clones once for return | | -| `RS-0212` | `own` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | json_object moves member values; 17 call sites updated | | -| `RS-0213` | `own` | `d2b-session` | low | actionable | family | applied | W7 | 1fb8eff80 | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:1209` | the borrow-based From impl landed earlier in a2cf0e614; this wave deleted the now-unused by-value impl and moved the three owned test sites to borrows. Merged 6f1390556. | | -| `RS-0214` | `own` | `d2b-sk-frontend` | low | actionable | leaf | applied | U2 | 0b8ef8ff5 | `packages/d2b-sk-frontend/src/main.rs` | main destructures Config and calls placement.into_placement() (no clone); config builds "/dev/uhid" via PathBuf::from. | | -| `RS-0215` | `own` | `d2b-zone-routing` | low | actionable | leaf | applied-variant | U2 | 6a3cf6cff | `packages/d2b-zone-routing/src/engine.rs` | Zone pair moved into the snapshot after destructuring expected; validate_snapshot checks inlined (row's first option) and gated #[cfg(test)] since consume no longer calls it | | -| `RS-0221` | `own` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 9441488c0 | `packages/d2bd/src/interaction_composition.rs` | supervisor clone removed as row intended; adoption_ticket clone KEPT because process_ticket used after run_effect (self.tickets.insert); closure uses &adoption_ticket - row's remove-both not implement | | -| `RS-0222` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 274cfb3c5 | `packages/d2bd/src/process_provider_runtime.rs` | match context.owner_uid.as_ref() with Some(owner_uid) guard => with_owner_uid(owner_uid.clone()), _ => ticket | | -| `RS-0216` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | committed_provider_spec borrows row; identities.insert(row.resource_ref, ...) without clone | | -| `RS-0218` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | let zone = guard.zone() borrow; plane.zone(&zone) and format use &ZoneId | | -| `RS-0217` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | dropped .to_owned() at 9 sites; all targets impl Into parsers (verified contracts-resource identity.rs) | | -| `RS-0219` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | workload_id moved into TypedError::WorkloadAliasConflict (no clone) | | -| `RS-0223` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 3220fd1ce | `packages/d2bd/src/forward_rendezvous.rs` | dropped let zone = request.zone.clone(); zones.get(&request.zone) | | -| `RS-0220` | `own` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | ResourceName::parse(&readable) | | -| `RS-0224` | `own` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 457373d5b | `packages/d2bd/src/shared_provider_effects.rs` | validator rewritten as in-place strip/restore on &mut Value (no clone on upsert path; Option::take fixed via std::mem::take;double-validation removed; clone remains only on read-only projection path) | | -| `RS-0225` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/supervisor/dag.rs` | run_split matches &state, binds reason by ref,and moves state into api_ready afterwards | | -| `RS-0226` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | complete_pending takes &str; two call sites pass as_str; third kept to_string because E0505 forbids borrow+move of result in one call (deviation) | | -| `RS-0227` | `own` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/console_session.rs` | Borrow implemented; five map lookups/removes resolve without String alloc | | -| `RS-0228` | `own` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U2 | c44ccbd0b | `packages/d2bd-runtime/src/daemon_audit.rs` | write_event* and enqueue take DaemonEvent by value, drop clone; caller migration in d2bd/src/composition.rs left to W1Daemon/orchestrator (cross-crate} | | -| `RS-0231` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | check_members takes &[WorkspaceMember]; caller clones dropped; second caller borrows result | | -| `RS-0236` | `own` | `xtask` | low | actionable | leaf | applied | W7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:425` | ComputedContext<'a> borrows its spec, so both caller clones are deleted without adding callee clones; the declared &ContextSpec shape would have been a 2-for-2 swap. Output byte-identical (gen-package-policy-inputs --check green). Merged 83578063f. | | -| `RS-0238` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 16e0b183d | `packages/xtask/src/blocking_census.rs` | CensusBaseline built by consuming each CrateCensus instead of cloning crate_dir/counts; --baseline check driven from the written map via a shared helper. Check passes; 18 census tests pass. | | -| `RS-0232` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | family-knowledge exempt set keys &str pairs; probe via as_str | | -| `RS-0237` | `own` | `xtask` | low | actionable | leaf | applied | U2 | be3e0744b | `production_closure.rs` | duplicate approval clone binding removed; single clone at with_approval call | | -| `RS-0234` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 44a90ab5e | `provider_packaging.rs` | nix_string_list generic over AsRef; eight to_owned closures deleted | | -| `RS-0233` | `own` | `xtask` | low | actionable | leaf | applied | U2 | f01a683c7 | `gen_broker_operations.rs` | profile_catalog returns Vec<&str> via as_deref; string_list items are &str | | -| `RS-0235` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 02238dbdd | `semantic_service_schemas.rs` | resource_ref_schema takes &str/&[&str]; five call sites pass borrowed forms | | -| `RS-0229` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | mem::take on the mut slot before in-place edit | | -| `RS-0230` | `own` | `xtask` | low | actionable | leaf | applied | U2 | 5f04f2119 | `provider_crate_policy.rs` | two ratchet probes key borrowed strs via signal fields | | -| `RS-0954` | `type` | `X2-generated-boundary` | medium | actionable | family | applied-variant | W4 | 0b5c7d292 | `packages/xtask/src/gen_broker_operations.rs:979-987, packages/xtask/src/gen_broker_operations.rs:891-897, packages/d2b-broker/src/generated/broker_operation_catalog.rs:25-27, packages/d2b-core/src/generated/broker_operation_authz.rs:12-19` | applied-variant: d2b-core privileges enums (SecretAccess, BrokerRequirement, AuditMode) gained Copy derives - required because BrokerAuthzFacets/BrokerOperationRow derive Copy; additive, non-breaking | | -| `RS-0955` | `type` | `X2-generated-boundary` | medium | actionable | leaf | applied | W6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Closed Disposition enum (CallableReadOnly/PromotedLive/StubbedUnimplemented/CompileTimeOnly, as_str) beside StubTarget in catalog.rs; BrokerOperationRow.disposition typed against it; generator emits via disposition_variant() mapper with a DISPOSITIONS closed-set validation; the five string-match sites migrated to variant matches; policy JSON stays the string vocabulary. | | -| `RS-0956` | `type` | `X2-generated-boundary` | low | actionable | family | applied | W6 | 13101e206 | `packages/xtask/src/gen_broker_operations.rs:853-858, packages/xtask/src/gen_broker_operations.rs:930, packages/d2b-contracts-broker/src/generated/broker_operation_profiles.rs:8-41, packages/d2b-broker/src/generated/broker_operation_catalog.rs:11` | Generator emits a full closed BrokerOperationName enum (98 variants, as_str); HOST/GUEST_OPERATION_CATALOG and the row operation field typed against it; allows_operation keeps the &str spelling via as_str so the wire boundary is unchanged; consumers migrated (broker_wire.rs, catalog.rs, runtime.rs, d2b-broker/tests profiles, envelope/mod.rs, d2b-broker-composition routing/seam). | | -| `RS-0957` | `type` | `X2-generated-boundary` | low | actionable | leaf | applied | W6 | 13101e206 | packages/d2b-broker/src/catalog.rs | Destructive enum (Serialize/Deserialize/JsonSchema, kebab-case) in privileges.rs; both field types bool -> Destructive; generate_authz emits named-field construction with Destructive::No/Yes; row() helper and its arity allow deleted (PUBLIC_OPERATION_AUTHZ converted in the same change); Nix emitter, v2 schema, and fuzz corpus seeds moved to no/yes; v1 schema frozen. | | -| `RS-0962` | `type` | `X3-cross-crate-duplication` | high | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-wayland-policy/src/interaction.rs:428, packages/d2b-provider-volume-binding/src/driver.rs` | driver-args zone class: the zone is a validated ZoneId through the wayland-policy, volume-binding, guest, and shared-provider driver args, and the daemon boundary parses it once; the per-pass parse-expects are gone, key_ref returns a typed SpecInvalid Result instead of panicking | escalated W2 -> U5 -> W5 (the family wave landed the driver-args class member sites) | -| `RS-0263` | `type` | `d2b` | low | actionable | leaf | applied | U3 | f98ad4f82 | packages/d2b/src/context.rs | ZoneContext now stores ZoneId; zone_ref/zone_name built from it; validate_zone_name deleted; discover double validation removed; from_socket takes ZoneId directly. | | -| `RS-0264` | `type` | `d2b` | low | actionable | leaf | applied | U3 | 913f462f9 | packages/d2b/src/exec.rs | ExecKillSignal and EndpointClass clap ValueEnums replace the runtime matches!/validate_endpoint_class checks (deleted); wire spellings unchanged via as_wire_str + Display; one parser probe in cli_cont | | -| `RS-0239` | `type` | `d2b-audit` | medium | actionable | wide | applied | W5 | 6b9187e44 | `packages/d2b-audit/src/evidence_chain.rs:50, packages/d2b-audit/src/evidence_chain.rs:115,` | EvidenceChain deserializes through an admission gate that rejects an empty identities list, so depth() cannot underflow and the identity accessors cannot panic; the wire shape is unchanged | | -| `RS-0242` | `type` | `d2b-broker` | medium | actionable | leaf | already-fixed | U3 | | `packages/d2b-broker/src/ops/media.rs:889-892` | Re-verified at HEAD: QmpAttachCleanup already models its four-step rollback as an ordered typed step list (steps: Vec with QmpAttachStep enum, media.rs:889-892), not four bools. Already | | -| `RS-0240` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | W7 | 5c95bf879 | `packages/d2b-broker/src/ops/storage_contract.rs:27` | Refused.reason is the closed RefusalReason enum (8 fixed slugs plus a canonicalize-failure variant carrying the io error); Display keeps the exact wire text the runtime forwards. Merged 6dc80e258. | | -| `RS-0241` | `type` | `d2b-broker` | low | needs-contract | leaf | applied | W7 | 5c95bf879 | `packages/d2b-broker/src/live_handlers.rs:291` | reloadBehavior parses to a closed NmReloadBehavior (atomic-reload, none, empty-string sentinel) in d2b-core; the broker validator and its typo-refusal error were deleted, both branch sites and the kernel payload parse are typed, and the v2 host schema moved with the generator. Merged 6dc80e258. | | -| `RS-0245` | `type` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 7a5a7f957,4e20f7674 | packages/d2b-bus/src/session/zone_link.rs | folded admission+liveness into private EstablishedLane; test lane keeps None; all three gate sites migrated; follow-up commit reattaches the doc to ZoneLinkSession | | -| `RS-0243` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | ResourceQuery assignment/scope Option pair folded into one Option<(AssignmentIdentity, ScopedResourceScope)>; pub assignment()/scope() accessors keep signatures via const match; validate_scoped now on | | -| `RS-0244` | `type` | `d2b-bus` | low | actionable | leaf | applied | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | UnixSubjectRecord expected_peer/expected_peer_uid pair replaced by ExpectedPeer enum (Exact(PeerCredentials) / Uid(u32)); bind() and resolve_for_service() match the enum preserving the d2b.resource.v3 | | -| `RS-0246` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/host_generation.rs | HandoffCoordinator.source_remains_usable field dropped; accessor derives from state != Completed; old durable records deserialize (unknown field ignored); wire response field untouched. | | -| `RS-0247` | `type` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U3 | 03d42c7ba | packages/d2b-contracts-broker/src/broker_wire.rs | CanonicalAuditDigest tuple field made private; parse and as_str remain the only construction/read paths; hand-written Deserialize and serde transparent keep wire shape. | | -| `RS-0248` | `type` | `d2b-contracts-control` | medium | needs-contract | wide | applied | W6 | caa29e248 | `public_wire.rs:2166, public_wire.rs:2203` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. AuditResponse's complete/next_cursor pair replaced by the closed AuditPageEnd (Complete / More(cursor)); the crate-local validate_audit_page is deleted and from_parts reports the canonical d2b_contracts::audit_wire::AuditPageError classes, so the admission error text is unchanged; AuditResponse keeps byte- and key-order-identical Serialize via the borrowing AuditResponseOut plus a manual JsonSchema; consumers migrated (d2b/src/dispatch.rs pagination, d2bd-runtime/src/wire.rs audit_response, d2bd/src/composition.rs). Gate: cargo check -p d2b-contracts-control -p d2bd-runtime -p d2bd -p d2b --all-targets rc=0 and the slice's schema drift targets. | | -| `RS-0249` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied | W6 | e9cb637c3 | `cli_output.rs:99, cli_output.rs:123, public_wire.rs:2634, public_wire.rs:2672` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11. Status DTO state vocabularies are closed kebab-case enums: RealmMode/RealmGatewayState (the `not reported by d2bd` sentinel preserved), QemuMediaRunnerState/QemuMediaRegistryState, PublicReadModelKind, VmAutostartMode; the crate-local duplicate kind and the parallel kind_name:&'static str are deleted, d2bd-runtime publishes the contract enum, and a spelling test pins all 21 spellings. Emitted bytes: the CLI goldens are byte-unchanged; the generated CLI schemas and the v2 wire-protocol schema plus the daemon-api enum table were regenerated with the xtask gen commands and proven by gen_cli_schemas_drift + gen_schemas_drift + gen_daemon_api_drift (3 of 3 pass on the committed tree). | | -| `RS-0250` | `type` | `d2b-contracts-control` | low | needs-contract | wide | applied-variant | W6 | caa29e248 | `public_wire.rs:316, public_wire.rs:311` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-10. MutationFlags' three booleans became MutationMode { DryRun, Apply } + MutationFlags { mode, json } with from_flags/to_flags; the seven flattened flag fields lost `default` and the three host requests lost Default, so a payload selecting neither mode fails admission. Recorded deviations: (a) the raw-JSON public frame cannot lose its refusal (it never passes typed admission), so the pair is parsed at the boundary in mutation_mode_from_request and keeps the byte-identical mutating-verb invalid-request envelope, while typed frames fail admission; (b) a hand-written frame setting both flags keeps the long-standing dry-run precedence instead of gaining a new refusal class. | | -| `RS-0253` | `type` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:92, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:499, packages/d2b-contracts-provider/src/v3/semantic_services/child_resources.rs:502` | | | -| `RS-0251` | `type` | `d2b-contracts-provider` | low | actionable | family | applied | W5 | fa8706320 | `packages/d2b-contracts-provider/src/v3/provider.rs:1366, packages/d2b-contracts-provider/src/v3/provider.rs:1368, packages/d2b-contracts-provider/src/v3/provider.rs:1720, packages/d2b-contracts-provider/src/v3/provider.rs:3455` | ComponentDescriptor::new no longer takes declares_state_volume: the parameter could only ever be false (true returned MissingRequiredField), so the illegal state is not expressible and every call site drops the argument; the wire-only declaresStateVolume field and its consistency check against stateNamespaces stay in the Deserialize path | | -| `RS-0252` | `type` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 5f45eb697 | packages/d2b-contracts-provider/src/v3/provider.rs | custom Serialize+JsonSchema for ComponentExecution emitting flat binaryRef; dropped ComponentExecutionWire; descriptor wire JSON and schema byte-identical before/after (probe); added round-trip test | | -| `RS-0256` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied | W7 | 1af47c8cf | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:284` | observed_generation is the crate's transparent ObservedGeneration (wire bytes unchanged); the two hand-committed activation-nixos schemas moved with it. Merged ab038d388. | | -| `RS-0255` | `type` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/mod.rs:71, packages/d2b-contracts-resource/src/v3/operations/mod.rs:239, packages/d2b-contracts-resource/src/v3/operations/mod.rs:374` | | | -| `RS-0257` | `type` | `d2b-contracts-resource` | medium | needs-contract | leaf | applied-variant | W7 | 1af47c8cf + e14ea9c02 | `packages/d2b-contracts-resource/src/v3/activation_nixos.rs:47` | target_generation is the existing nonzero ConfigurationGeneration newtype (serde-transparent u64, JsonSchema minimum 1): nonzero_u64_schema, ActivationRunnerInputError and the zero check are deleted, new() is infallible, the now-unreachable zero guards in process-conformance and provider-process are gone, and the EphemeralProcess schema was regenerated. The first landing used a new NixosGenerationOrdinal newtype, which the layout gate refused as shared-crate family vocabulary; the follow-up slice switched to the row's own prescribed ConfigurationGeneration. Merged ab038d388 + 6abcf5cac. | | -| `RS-0254` | `type` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 29a900c5a | packages/d2b-contracts-resource/src/v3/operations/seal.rs | `StoreSealIdentity`/seal acceptor: enforce the nonzero head-identifier claim the doc promises - `with_store_epoch` (and the seal identity constructor) now reject a zero epoch in debug builds via a doc | | -| `RS-0258` | `type` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 669ec10a2 | `packages/d2b-contracts-zone-session/src/v3/role_binding.rs` | | | -| `RS-0259` | `type` | `d2b-controller-toolkit` | low | actionable | family | applied | W4 | b872981b2 | `packages/d2b-controller-toolkit/src/context.rs:17-18, packages/d2b-controller-toolkit/src/context.rs:61-67` | | | -| `RS-0261` | `type` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/manifest_v04.rs | ManifestShellName field made private + as_str() accessor; serde(transparent) keeps wire shape; census re-run: no out-of-module literal construction | | -| `RS-0260` | `type` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | dfe70fe8f | packages/d2b-core-controller/src/authority.rs | Named the optional otel Provider cardinality by a private const OPTIONAL_PROVIDER_REF beside the domain constants; AuthorityRequest::provider compares against it. | | -| `RS-0262` | `type` | `d2b-host` | medium | actionable | family | applied | W5 | d593fa50e | `packages/d2b-host/src/nftables.rs:609, packages/d2b-broker/src/ops/media.rs:194` | BusId keeps its inner string private and validates the USB busid grammar once at the type boundary (BusId::new returns Result, TryFrom<&str> and as_str carry the value); the transparent wire shape is unchanged and the redundant broker qemu-media re-validations plus the daemon attach/detach pre-checks are deleted | | -| `RS-0265` | `type` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 81d0ff057 | packages/d2b-process-conformance/src/ticket.rs | Bundled zone_uid+runtime_scope into one private Option pairing; const-compatible match accessors keep the public API byte-identical. | | -| `RS-0266` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | 87e8d7654 | packages/d2b-provider-audio-pipewire/src/resource_type.rs | owner()/new() now infallible; validate_audio_* remain the single admission gate (they also check provider_ref/extension/zone the ctors cannot). All call sites updated; check+test+clippy green on 4 cra | | -| `RS-0267` | `type` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | Shared-vs-owned controller mode carried in the type; mixer speaker path split into grant/revoke so the return contract stops being argument-dependent. Suite 94/94. | | -| `RS-0268` | `type` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 4404afb72 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Merged picker (args.picker.or(config)) validated once after merge; relative paths rejected from either source. | | -| `RS-0269` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 6a6a62f2f | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:13` | the two boolean fields are gone - ClipboardRunnerContract carries only service_package and repair_interval_secs, and the former flags survive as const-true accessors with two in-repo test consumers; re-verified at 6dc80e258. | | -| `RS-0270` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | d59bb44a3 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:250` | the pipe-joined completion key is a typed CompletionKey struct built by CompletionKey::new and consumed by ClipboardHistory (BTreeMap keys plus purge); no join/split on the separator remains anywhere in the crate, and the literal-key test builds the struct instead of a string; re-verified at 6dc80e258. | | -| `RS-0271` | `type` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 5dfe92ec1 | `packages/d2b-provider-clipboard-wayland/src/picker.rs:143` | entry digests are EntryDigest, parsed once at the single construction point (EntryDigest::parse) and carried by PickerReceipt; the receipt-boundary starts_with check the row described no longer exists; re-verified at 6dc80e258. | | -| `RS-0272` | `type` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/service.rs | Request fields sealed to pub(crate); ConfigSyncRequest::new now calls validate_guest_ref, closing the Guest/ drift; serde derive keeps wire JSON unchanged. | | -| `RS-0273` | `type` | `d2b-provider-credential` | low | actionable | leaf | applied-variant | U3 | 1ce473a70 | packages/d2b-provider-credential/src/driver.rs | zone: String -> d2b_contracts_resource::v3::ZoneId in CredentialDriverArgs and CredentialDriver; agent_child builds the zone ref with expect on a validated ZoneId (fallible ResourceRef::parse path dro | | -| `RS-0274` | `type` | `d2b-provider-credential-managed-identity` | medium | actionable | leaf | applied | U3 | cd8838c03 | packages/d2b-provider-credential-managed-identity/src/controller.rs | seal `ManagedIdentityTeardownPlan`'s three bool fields behind `pub const fn` accessors so invalid combos (stop_agent && delete_agent, delete_agent && clear_provider_revoke) are unrepresentable; tests | | -| `RS-0275` | `type` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | 7ef81ed6b | packages/d2b-provider-device-gpu/src/controller.rs | video_started bool field deleted (decl 79, init, writes at 341/470, reset at 548); Debug impl now reads `video_identity.is_some()`; no behavioral read remained. | | -| `RS-0276` | `type` | `d2b-provider-guest` | medium | actionable | family | applied | W4 | 9870dc852 | `packages/d2b-provider-guest/src/driver.rs:709, packages/d2b-provider-guest/src/driver.rs:7` | | | -| `RS-0277` | `type` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | U3 | 9e1f1052a | packages/d2b-provider-guest-azure-container-apps/src/effects.rs | Privatized all 11 AcaProviderConfig fields; added 11 borrowed accessors mirroring sibling AcaRuntimeConfig; controller.rs reads now go through defaults()/network_ref()/sandbox_transport_alias(). Censu | | -| `RS-0278` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | W6 | 5d067420c | `src/controller/mod.rs:278, src/controller/mod.rs:186` | AzureVmRecoveryState is a pub serde record (Serialize+Deserialize, deny_unknown_fields, re-exported at lib.rs:20) whose JSON shape this row would restructure; previously written restart-recovery records [reconstructed: must still load after the change, so the sealed-record read path needs a bounded migration (the sealed Volume survives execute_upgrade per ADR-046-provider-runtime-azure-virtual-machine.md:1157)]. Grouped the operation/operation_started_at_unix_ms pair into Option; hand-written Deserialize accepts both the new inFlightOperation shape and the legacy pair (total fold); pair check deleted; legacy-shape deserialize test added; ADR sealed-recovery section notes the accepted legacy shape. | | -| `RS-0279` | `type` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U3 | 5fede0237 | packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs | BootstrapAdmission converted from struct{pub-invalid Option-pair} to enum Pending { psk, expires_at_unix_ms } / Consumed / Expired - the illegal Consumed/Expired-with-Some(psk) combination is now unco | | -| `RS-0280` | `type` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmUpdate::Resize.size is now an OpaqueAzureRef (serde-transparent, JSON unchanged); both re-parses in validate_update/apply_update deleted; resize effect call passes size.as_str(); 18 test constr | | -| `RS-0281` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | e53601c88 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | derive_private_runtime_scope and private_runtime_scope take ChildRole and use role.suffix(); the &str whitelist branch is gone. Callers incl. wayland-policy migrated. | | -| `RS-0282` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | needs-contract | leaf | applied | W7 | 2ca9a22dd | `packages/d2b-provider-guest-cloud-hypervisor/src/config.rs:20` | default_machine_type is the closed MachineType enum (the closed q35/microvm pair) and the unreachable validate arm is deleted; root-config.schema.json carries the enum and the committed provider-manifest.json digest moved with the schema bytes. Leftover: the committed provider-manifest.json.sig no longer verifies (publisher private key is not in-tree; nix/provider-artifact.nix:135 checks only the 64-byte length and the host-integration lanes re-sign with their own derived key). Merged bdb26e6ef. | | -| `RS-0283` | `type` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | f1404725d | packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs | vmm_readiness/vmm_lifecycle now take one VmmReadinessSnapshot struct (five named facts, all_ready()); controller readiness() builds it from GuestDependencySnapshot accessors; tests updated. check/test | | -| `RS-0284` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | 82f8cac47 | packages/d2b-provider-guest-qemu-media/src/config.rs | 7 gate calls now use BoundedToken::parse(...) .is_err(); local validate_token helper and its pub(crate) re-export deleted; qmp validate_object_id delegates to BoundedToken::parse. Deviation: validate_ | | -| `RS-0285` | `type` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U3 | b845000ff | packages/d2b-provider-guest-qemu-media/src/config.rs | impl Default for ProviderConfig deleted (it manufactured a config that fails its own validate());the sole consumer test now builds valid-then-mutated configs (controller_execution_ref swapped to a Gue | | -| `RS-0286` | `type` | `d2b-provider-notification-desktop` | low | policy-confirmed | leaf | applied | W7 | 21a7af424 | `packages/d2b-provider-notification-desktop/src/controller.rs:22` | the two hardcoded-true booleans are one typed NotificationCutoverState::ServiceOnly, and both accessors are derived matches! reads so every caller (both tests) compiles unchanged; the refusal ledger row cited only the daemon composition test, so no ADR amendment was needed. Merged 3668d3a6e. | | -| `RS-0287` | `type` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/agent.rs | ProviderAgentAuditEvent stores parsed BoundedToken values; Serialize renders via as_str(); parse-then-copy-back removed, wire output unchanged. | | -| `RS-0288` | `type` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U3 | 9fbe75ec2 | packages/d2b-provider-process-minijail/src/launch.rs | validate_launch_ticket renamed to validate_platform_gate and reduced to the gate check (identity checks live only in MinijailProcessProvider::validate); lib.rs:160 literal replaced with crate::PROVIDE | | -| `RS-0289` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 7cf83bcaf | packages/d2b-provider-process-systemd/src/lifecycle.rs | Dropped invariant restart_on_failure field and its guard in should_restart. cargo check and restart-policy test pass; clippy base-red pre-existing: tokio::test expansions trigger disallowed Runtime::b | | -| `RS-0290` | `type` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | aee724326 | packages/d2b-provider-process-systemd/src/metrics.rs | Added MetricLabelKey enum with as_str(); validate_labels takes typed keys; dropped LABEL_KEYS const (census: only in-crate definition, zero users). Unknown-key rejection now type-level; test updated. | | -| `RS-0291` | `type` | `d2b-provider-telemetry-binding` | low | actionable | leaf | applied | U3 | c4ea8fb10 | packages/d2b-provider-telemetry-binding/src/lib.rs | PHASE_PENDING/PHASE_DEGRADED constants became a TelemetryBindingPhase enum with matching as_str spellings; driver suite green. | | -| `RS-0292` | `type` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServicePhase enum (as_str for the three spellings) and TelemetryServiceProjection struct (serde camelCase, contract-pinned {serviceRole, serviceReadiness} shape) replace the json! literals; n | | -| `RS-0293` | `type` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | -| `RS-0294` | `type` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U3 | d52b7052c | packages/d2b-provider-volume-local/src/identity.rs | VolumeRootHandle split into Empty / Anchored(Box); mixed Option states unrepresentable; boxed payload per denied large_enum_variant lint; non-Clone/non-Serialize kept. | | -| `RS-0295` | `type` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | watch: bool replaced with pub enum ScopedQueryMethod { List, Watch }; bus router call site and adapter test updated. | | -| `RS-0296` | `type` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | f7b48c947 | packages/d2b-resource-client/src/dispatch.rs | Dropped the unreachable validate_lifetime()? re-check at CallDriver::new (MetadataInput::new enforces the invariant at construction; builder methods cannot change the lifetime fields) and removed the | | -| `RS-0297` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/scheduler.rs | channel() now returns Result; the constructor-prevented NamedStream-without-stream combination yields InvalidChannel instead of a silent SESSION_CONTROL misroute. Census re-run: only caller | | -| `RS-0298` | `type` | `d2b-session` | low | actionable | leaf | applied | U3 | bd25f4ce9 | packages/d2b-session/src/engine.rs | | | -| `RS-0299` | `type` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | fde0a0440 | packages/d2b-unsafe-local-helper/src/runtime.rs | RuntimeLedger.reservations re-keyed from String to BTreeMap; operation_key deleted; begin/owns/clear use the typed id directly (clone on insert). OperationId derives Or | | -| `RS-0303` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | force semantics implemented in apply(): dropped `let _ = self.force;` and gated the graceful wait on `wait_for_ready && !force`. Checks: cargo check -p d2bd --locked --all-targets green. | | -| `RS-0305` | `type` | `d2bd` | medium | actionable | leaf | applied | U3 | b310cab7bdafa68156e88ee513f3083bbe3d25a2 | packages/d2bd/src/shared_provider_effects.rs | Added crate-private SharedProviderEffectMode enum (Deserialize, rename_all kebab-case) with a fail-closed parse; both stringly-compare sites (usbip_service_port opted_in, reconcile_security_key projec | | -| `RS-0302` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | d0f8b5918 | packages/d2bd/src/composition.rs | ShutdownDegradedMarker now stores VmShutdownOutcome enum (derive Serialize/Deserialize, rename_all snake_case) instead of String outcome/severity; construction site passes the enum. Report shape uncha | | -| `RS-0300` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ZoneResourceRuntime gate trio (policy_installed/controller_endpoint_registered/watch_admitted) replaced by PlanePublicationStage { BootstrapOnly, Published } set at open and activate_published_bundle; | | -| `RS-0301` | `type` | `d2bd` | low | actionable | leaf | applied | U3 | a25efea28a12ba81bde8b3d8ebdd88551491f7de | packages/d2bd/src/resource_runtime.rs | ControllerSession teardown trio (ingress_revoked/assignments_revoked/transport_closed) replaced by a TeardownStage enum advanced monotonically (Active -> IngressRevoked -> AssignmentsRevoked -> Transp | | -| `RS-0304` | `type` | `d2bd` | low | needs-contract | leaf | applied-variant | W7 | 369627b78 | `packages/d2bd/src/composition.rs:20375` | mode is HostActivationMarkerMode rendering the four documented verbs, with a serde(other) Unknown catch-all so an unknown out-of-tree mode still parses (the catch-all is named Unknown so its serde label and Display agree; the finding suggested no name); the marker log keeps a recognized label via Display. Merged a74fd9b0c. | | -| `RS-0307` | `type` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | 7e0ec2bce | packages/d2bd-runtime/src/admission.rs | peer admission lookup mode modelled self-describing; check + admission tests green (worker reported the oid as already present after committing its own change; the commit is this branch's) | | -| `RS-0309` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W5 | 6dabfe132 | `packages/d2bd-runtime/src/daemon_audit.rs:194, packages/d2bd/src/composition.rs:19361` | DaemonEvent::ApiReadyTimeout.mode is a closed ApiReadyMode enum (Strict / NoWaitApi) with kebab-case serde, so an invalid mode string is rejected on deserialize; the JSONL shape is unchanged | | -| `RS-0310` | `type` | `d2bd-runtime` | medium | actionable | family | applied | W4 | 87c3172bc | `packages/d2bd-runtime/src/wire_response_helpers.rs:99, packages/d2bd-runtime/src/wire_response_helpers.rs:118` | | | -| `RS-0308` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | d1c5c44d9 | packages/d2bd-runtime/src/typed_shell_targets.rs | typed-shell target key becomes a named struct with a constructor; the three composition.rs cache call sites migrate to it | | -| `RS-0306` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | c9addc3aa | packages/d2bd-runtime/src/component_session_vsock.rs | PeerCredentialIo/ConnectIo/WriteIo/AckIo now carry std::io::ErrorKind instead of String; io_failure helper passes error.kind(); nix Errno mapped via std::io::Error::from(error).kind(); dropped all .to | | -| `RS-0311` | `type` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8cb61bb16 | packages/d2bd-runtime/src/public_read_model.rs | cached public read-model frame type hidden; check + tests green | | -| `RS-0314` | `type` | `xtask` | medium | actionable | leaf | applied | U3 | 0b767225a | packages/xtask/src/inventory.rs | Deleted the private copy and both call sites plus the test now use crate::delivery::model::validate_repo_relative_path(Path::new(...)); stricter empty check retained. | | -| `RS-0313` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 1d692db3d | packages/xtask/src/provider_crate_policy.rs | FamilyKnowledgeSignal gains typed count: Option; ServerState site fills it and drops the serialized-count text; renderer matches class without the parse;the ratchet JSON stays byte-identical (t | | -| `RS-0315` | `type` | `xtask` | low | needs-contract | leaf | applied | W7 | f75fbf3e8 | `packages/xtask/src/production_closure.rs:107` | EdgeRecord.kind is a closed EdgeKind with the wire spelling preserved (proc-macro); a hand-written Ord keeps the historical string order so every committed policy-inputs closure stays byte-identical (write-mode regeneration changed nothing). Merged 83578063f. | | -| `RS-0312` | `type` | `xtask` | low | actionable | leaf | applied | U3 | 5f6132bb2 | packages/xtask/src/gen_layer_catalogs.rs | process_provider_ids(Option pub(crate) for all 19 gpu.rs items and 7 modprobe.rs items (types, impl methods, free fns, trait). Chose item-level over module-decl narrowing so d2b-core bundle_resolver.rs:4300 and | | -| `RS-0322` | `api` | `d2b-broker` | medium | policy-confirmed | leaf | applied | W7 | 5a0110bb9 | `packages/d2b-broker/src/ops/mod.rs:20` | 28 of the 31 handler arms are now pub(crate); pidfd, network and audit_op stay pub because five in-crate integration-test crates import them by path. The census (which arms stay public and why) is recorded next to pub mod ops in lib.rs so a new arm cannot silently reopen the surface. Merged 0365535b1. | | -| `RS-0317` | `api` | `d2b-broker` | low | actionable | leaf | applied | W6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:93, packages/d2b-broker/src/live_handlers.rs:467` | Dropped the unused _daemon_uid parameter from pub fn acquire_lock; all 12 census call sites plus 9 in-file test sites and the dead daemon_uid forwarding param on live_usbip_bind (6 callers) updated; broker-internal signature, no doc or fixture pins it. | | -| `RS-0321` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | 068ddcfc4 | packages/d2b-broker/src/ops/cgroup.rs | CgroupBundleContext::slice_path() now returns &Path (borrows parent_slice, no clone). Call sites: vm_interior_path join works on &Path; AuditFields slice_path and the D2bSlice tuple site keep one to_p | | -| `RS-0323` | `api` | `d2b-broker` | low | actionable | leaf | applied | U3 | e8d9c370f | packages/d2b-broker/src/kernel_ops.rs | kernel_table now takes KernelConfig by value (Arc::new(config), no clone); the 6 call sites (runtime.rs:7143 production + 5 tests) updated to drop the borrow. Per-handler Arc clones unchanged. cargo c | | -| `RS-0324` | `api` | `d2b-bus` | medium | actionable | leaf | applied-variant | U3 | 886a26df3 | packages/d2b-bus/src/router.rs | Census re-run:= with_observer/with_observer_and_metrics/with_clock_and_observer have zero ZoneBus callers, deleted; with_clock -> pub(crate) because production new() delegates to it; with_clock_observ | | -| `RS-0325` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | 886a26df3 a5a619151 | packages/d2b-bus/src/authorization.rs | Removed both native_authorizer() accessors; census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 3 hits (the two definitions plus the in-crate delegation), zero callers. r | | -| `RS-0326` | `api` | `d2b-bus` | medium | actionable | leaf | applied | U3 | d91b738d8 | packages/d2b-bus/src/session/mod.rs | dropped Cancellation from d2b_session re-export block; census re-run: 0 uses of d2b_bus::session::Cancellation repo-wide; in-crate users import d2b_session::Cancellation directly | | -| `RS-0327` | `api` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/types.rs | MediaRef::validate_value wired into construction via TryFrom<&str> parse-gate; validate_value no longer dead, callers cannot bypass the shape check. | | -| `RS-0328` | `api` | `d2b-contracts-broker` | medium | needs-contract | wide | applied | W6 | 3c3454697 | `packages/d2b-contracts-broker/src/broker_wire.rs:2862-2869, packages/d2b-broker/src/runtime.rs:1628-1632` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). BrokerRequestEnvelope no longer carries the test-only test_peer_uid member: the harness (the bootstrap probe CLI and the integration tests) sends that override as a testPeerUid member beside the envelope, and only a --test-mode broker unwraps it in front of its strict decode, so the wire contract carries no test seam and every other broker refuses a frame that carries one; production frames stop emitting the "testPeerUid": null member. New d2b_broker::runtime::{TEST_PEER_UID_FIELD, test_peer_uid_frame} name the harness-only override, and the contract test broker_request_envelope_refuses_a_test_only_peer_uid_member pins the refusal. Co-change: the broker runtime and bootstrap call sites and the four broker integration targets (profile_separation, guest_profile, socket_activation, broker_protocol_compatibility). Gate on the merged tree: cargo test -p d2b-contracts-broker rc=0, cargo test -p d2b-broker rc=0 (700 lib tests plus the spawned-broker integration targets, each driving the new frame-member seam against a real broker), cargo check over the seven touched crates --all-targets rc=0, gen_daemon_api_drift green. | | -| `RS-0329` | `api` | `d2b-contracts-broker` | low | actionable | family | applied | W4 | 068eebb17 | `packages/d2b-contracts-broker/src/broker_wire.rs:13, packages/d2b-contracts-broker/src/lib.rs:7-11` | | | -| `RS-0330` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | W6 | dc145cf0c | `cli_output.rs:241, cli_output.rs:276` | Deleting pub StatusServicesOutputV3 + from_v2 from the published d2b-contracts-control moves the published surface; census re-run at HEAD: 1 hit (the definition itself), not in wire-protocol.json, but [reconstructed: the migration shape is documented at docs/how-to/migrate-d2b-v1-0-to-v1-1.md:212-224, which the change must amend in the same commit]. Deleted both; the migration doc's v1.1.1 shim promise amended in the same commit (V2 stays the emitted shape until the emit-side flip); status.schema.json and status-json.golden byte-unchanged; gen_cli_schemas_drift green. | | -| `RS-0331` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied | W6 | dc145cf0c | `cli_output.rs:6` | Deleted the zero-consumer pub re-export of LevelPercent from cli_output.rs; the type remains reachable through d2b_contracts, the canonical path docs pin. | | -| `RS-0332` | `api` | `d2b-contracts-control` | low | needs-contract | wide | applied | W6 | e9cb637c3 | `public_wire.rs:2677, docs/reference/schemas/v1/wire-protocol.json:127` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-11, as a versioned transition (first assessed blocked on the frozen v1 schema; the operator rule that format compatibility is a co-change list applies, and the census found no freeze policy to cite). The dead pub AuditEntry export is deleted; census at HEAD: the definition only (the live public AuditResponse carries AuditExportEntry pages), no golden, no live consumer; the v1 schema stays the byte-identical historical artifact and the generated v2 schema never contained the name (gen_schemas_drift + gen_daemon_api_drift green). Outside-tree observer: none - the v1-era AuditResponse shape has not been emitted since the page moved to AuditExportEntry. | | -| `RS-0333` | `api` | `d2b-contracts-control` | low | actionable | leaf | applied-variant | W6 | dc145cf0c | `unsafe_local_wire.rs:105, unsafe_local_wire.rs:171` | Caller-migration variant (recorded deviation; the ledger's census was stale): the two live external callers of HelperLaunchRequest::validate_bounds (d2b-unsafe-local-helper protocol.rs:157, runtime.rs:333) migrated to the pub free fn validate_unsafe_local_resource_identity; then both methods narrowed to pub(crate). Wire types and serde admission unchanged. | | -| `RS-0334` | `api` | `d2b-contracts-provider` | low | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/provider.rs:568, packages/d2b-contracts-resource/src/v3/resource_schema.rs:592` | | | -| `RS-0335` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 928dc7755 | packages/d2b-contracts-resource/src/v3/network.rs | drop the six zero-consumer pub type aliases (DeviceStatus, DeviceRbacVerb, DeviceTelemetryLabels, DeviceAttachmentSpec, AuthorityDescriptor, OpaqueAuthorityKey); census over packages/, nixos-modules/, | | -| `RS-0336` | `api` | `d2b-contracts-resource` | low | actionable | leaf | applied | U3 | 67393687b13c359ac6b3a96bca469d28e25c7c96 | packages/d2b-contracts-resource/src/v3/identity.rs | Deleted the zero-caller alias and its doc. Census re-run: ValidatedSessionPurpose over worktree = 1 hit (the definition); no re-export arm in v3/mod.rs. cargo check -p d2b-contracts-resource --locked | | -| `RS-0337` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/resource_export.rs | Deleted the four compatibility aliases (ResourceExportError, Fairness, ResourceImportError, ZoneLinkStatus) and their doc lines. Census re-run over packages/, nixos-modules/, tests/, labs/, docs/refer | | -| `RS-0338` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/emergency_policy.rs | Deleted EmergencyPolicySpec::default_values(); Default::default() now constructs directly. Census: the Default impl was the only caller. | | -| `RS-0339` | `api` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone.rs | Removed ZoneSpec::validate (always-Ok). Census: no callers anywhere in the workspace or in-crate tests; the Deserialize gate remains the invariant. | | -| `RS-0348` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | ac3083316 | `packages/d2b-core/src/error.rs, packages/d2b-core/src/contract_id.rs` (the shim modules this row deleted are gone from the tree) | the six d2b-core compat shim modules are deleted and every import site re-pointed at d2b_contracts; the xtask gen-error-codes generator and the generated docs/reference/error-codes.md anchors follow; the zero-consumer UnsafeLocalWorkloadIdentity alias goes with its module | | -| `RS-0345` | `api` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Nine zero-consumer resolved-intent types marked #[doc(hidden)] (kept for planned broker dispatch arms per module doc); census re-run: 0 consumers workspace-wide | | -| `RS-0349` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | 8e70d643e | `packages/d2b-core/src/static_invariants.rs:3, packages/d2b-core/src/static_invariants.rs:1` | the four static validators now carry in-module positive/negative unit tests restoring the retired tests/static-invariant-*.sh gate cases, so the module doc claim is true; the stale doc paragraphs are corrected and the public API and constants are unchanged | | -| `RS-0346` | `api` | `d2b-core` | medium | actionable | wide | applied | W5 | 8abd3c1ba | `packages/d2b-core/src/bundle_resolver.rs:107, packages/d2b-core/src/bundle_resolver.rs:109` | the seven BundleResolver trusted-bundle fields are private behind typed accessors and a single set_storage setter replaces the broker's direct storage mutation; every consumer in d2bd, d2bd-runtime, d2b-broker, and the provider crates reads through the accessors | | -| `RS-0350` | `api` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/privileges.rs | PrivilegesJson::w1 renamed to from_const_rows(); both test call sites updated; census re-run: only test callers exist | | -| `RS-0347` | `api` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_vm_start_intent and find_process_node narrowed to pub(crate) as stated; find_if_name_mapping_for_vm had ZERO callers anywhere (census re-run: only the definition), so pub(crate) tripped the de | | -| `RS-0340` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | fd2d8eb30 | packages/d2b-core-controller/src/binding_children.rs | Removed the uncalled observed_child_from_resource envelope adapter and its lib re-export; census: 0 callers anywhere. | | -| `RS-0341` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | e95cfb6c5 | packages/d2b-core-controller/src/controller_assignment.rs | Deleted eight zero-caller pub methods (reserve_epoch_after, rebind_revision, record_child, remove_child, child_uids, validate_writer, observation_is_stale, target_for), the children field, MAX_ASSIGNE | | -| `RS-0342` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied | U3 | 442b4cb31 | packages/d2b-core-controller/src/coordinator.rs | Deleted ten zero-caller pub methods (begin/finish_usbip_reconcile, set/clear_force_shutdown_generation, stage/commit/abort_configuration, commit/abort_configuration_ordinal, zone_count), the generatio | | -| `RS-0343` | `api` | `d2b-core-controller` | medium | actionable | leaf | applied-variant | U3 | 7760f4d1a | packages/d2b-core-controller/src/authority.rs | Dropped the unused external physical-NIC admission/inventory/lease machinery (-1185 lines, 7 tests). Kept the DurableExternalNicClaim wires and ExternalNicRecoveryInventory + storage claim variant con | | -| `RS-0344` | `api` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 4105103ab | packages/d2b-core-controller/src/owner_reconcile.rs | Deleted six zero-caller public alias accessors: OwnerReconcilePlan::create_order/batch, OwnerChildBatch::resource_refs, OwnerChildIdentity::resource_ref, TeardownPlan::refs/resources; kept canonical n | | -| `RS-0351` | `api` | `d2b-host` | low | actionable | leaf | applied | U3 | c44532f1d | packages/d2b-host/src/lib.rs | HostPrepStepId inner string made private with serde-transparent round-trip unchanged; workspace check and clippy green. | | -| `RS-0355` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 9ed591eb2 | packages/d2b-process-conformance/src/lib.rs | Dropped the unused BrokerExitClass alias from the terminal re-export; census: only hit was its own re-export. | | -| `RS-0356` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | dbac9940c | `packages/d2b-process-conformance/src/provider.rs` (the process_provider.rs module this row deleted is gone from the tree) | Deleted the duplicate process_provider re-export module; census: 0 users of that path. | | -| `RS-0357` | `api` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/lib.rs:38, packages/d2b-process-conformance/src/testing.rs:1` | the process-conformance test doubles and fixtures (`testing`) ship behind a `test-support` feature: the feature is declared, the `_test_support` bazel variant gains `crate_features`, the suite helpers that need the doubles are gated, and every in-tree consumer enables the feature through dev-dependencies plus the `_test_support` bazel variants; the shared `suite` stays ungated product surface | | -| `RS-0358` | `api` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | a37c1e0cf | packages/d2b-process-conformance/src/sandbox.rs | Deleted CompiledSandbox::requires_cgroup_kill field, its unconditional true initializer in compile(), and its public accessor; census: `requires_cgroup_kill` over packages/, nixos-modules/, tests/, do | | -| `RS-0359` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 6c66b83ea | packages/d2b-provider-activation-nixos/src/driver.rs | ActivationDriver narrowed to pub(crate) and dropped from the lib.rs driver re-export arm. Census re-run:the symbol appears only in driver.rs (7 sites)and lib.rs; no external consumer. Checks shared wi | | -| `RS-0360` | `api` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | 4cccad187 | packages/d2b-provider-activation-nixos/src/controller.rs | ACTIVATION_RUNNER_RESOURCE_TYPE made private const (used only at controller.rs:296, same module). Census re-run: 2 hits both in controller.rs. Checks shared with RS-0359. | | -| `RS-0361` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | already-fixed | U3 | c7d7d66c5 | packages/d2b-provider-audio-pipewire/src/authority.rs | set_grant(lease, on: bool) already split into grant()/revoke() with was-empty/was-last contracts by the RS-0267 commit (c7d7d66c5); callers use is_last_grant first. No change needed. | | -| `RS-0362` | `api` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | c9a141c78 | packages/d2b-provider-audio-pipewire/src/controller.rs | register_service deleted (zero callers; census over packages/nixos-modules/tests/docs/reference/labs = only the definition); daemon and wayland-policy validate specs via validate_audio_service directl | | -| `RS-0363` | `api` | `d2b-provider-audio-pipewire` | low | needs-contract | family | applied | W7 | 792ca2002 | `packages/d2b-provider-audio-pipewire/src/controller.rs:142` | AudioLastSetApplied::OfflineOnly is renamed NotApplied and the wire label moves with every consumer: the wayland-policy projection arm, its fixture and two pins, the daemon status pin in resource_plane_v3.rs, and the provider ADR enum row - the census of the old literal leaves only the historical audit record. Merged d9a91015a. | | -| `RS-0364` | `api` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 9024c13d9 | `packages/d2b-provider-clipboard-wayland/src/service/mod.rs:1282` | host_entry_ttl_secs and the policy() accessor are gone from ClipboardConfig (field, Default value, and accessors); repo-wide grep finds no code hit; re-verified at 6dc80e258. | | -| `RS-0365` | `api` | `d2b-provider-config-nixos` | low | actionable | wide | applied | W5 | 4524b7e45 | `packages/d2b-provider-config-nixos/src/service.rs:296-298, packages/d2b-provider-config-nixos/src/lib.rs:22` | the public decode_document forwarder and its re-export are deleted; the sole caller in d2bd uses ConfigSyncResponse::document() directly, leaving one API path for validating a synced config document | | -| `RS-0366` | `api` | `d2b-provider-credential-entra` | medium | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted controller_binary_entrypoint + doc comment; run_from_fd10 remains the single entrypoint. Census re-run: 0 callers outside the definition (cloud-hypervisor and managed-identity have their own, | | -| `RS-0367` | `api` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U3 | 8af1a1833 | packages/d2b-provider-credential-entra/src/lib.rs | Deleted EntraCredentialOwner enum and owner() accessor. Census re-run: names appear only in the two definitions; ADR-046 mentions the policy concept in prose only. check/test (11 ok)/clippy green. | | -| `RS-0368` | `api` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | drop the zero-caller `ManagedIdentityPlacement::in_zone` constructor (exact duplicate of `new`); census over packages/, nixos-modules/, tests/, docs/reference/, labs/ = 0 consumers outside the definit | | -| `RS-0369` | `api` | `d2b-provider-device` | medium | actionable | family | applied | W5 | 3c229db55 | `packages/d2b-provider-device/src/driver.rs:128-143, packages/d2bd/src/shared_provider_effects.rs:1584, packages/d2bd/src/shared_provider_effects.rs:2092, packages/d2bd/src/shared_provider_effects.rs:2122` | DeviceResourceState's three provider caches are private behind read-only typed accessors; the daemon's shared provider effects migrate all nine read sites and the GPU authority-lease construction contract stays behind the driver crate | | -| `RS-0370` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | U3 | 539ca5113 | packages/d2b-provider-device-gpu/src/lib.rs | gpu_argv/video_argv made private; root re-exports keep one reachable path per item. Census re-run: `d2b_provider_device_gpu::(gpu_argv/video_argv)::` over packages/nixos-modules/tests/docs/reference/l | | -| `RS-0371` | `api` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U3 | 4efbf8ea5 | packages/d2b-provider-device-gpu/src/effects_service.rs | applied-variant: row's second option (single crate-owned sidecar) used: DeclaredWorkerGpuPortDeps sidecar (private fields, pub 4-arg ::new) holds the four dependency types; DeclaredWorkerGpuPortArgs ( | | -| `RS-0372` | `api` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U3 | 0867cba1a | packages/d2b-provider-device-security-key/src/lib.rs | pub mod relay made private (relay_service already private at HEAD); lib.rs pub use arms stay the single surface. Census re-run: device_security_key::relay:: = 1 hit (backticked doc comment in d2b-brok | | -| `RS-0373` | `api` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | state.rs (StateDirectoryToken/TamperMarkerToken/StateOwnerToken/StateDirIntent) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.b | | -| `RS-0374` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 4de51c1b5 | packages/d2bd/src/shared_provider_effects.rs | Registered TpmEffectsServiceFactory for TPM_EFFECTS_SERVICE in the plane test inputs factory map (shared_provider_effects.rs), built from d2b_provider_device_tpm::test_support::recording_facets() - th | | -| `RS-0375` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 205e888b9 | packages/d2b-provider-device-tpm/src/effects_service.rs | LiveTpmResourceEffectPort made pub(crate); census re-run at HEAD: only effects_service.rs:341/364/535/679-680 reference it, 0 external hits | | -| `RS-0376` | `api` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U3 | 5f7c5aae5, 524b8696c | packages/d2b-provider-device-tpm/src/lib.rs | migration.rs (LegacyMigrationOutcome) deleted; re-export arm and mod decl removed. Census re-run over packages/nixos-modules/tests/docs/reference/labs/BUILD.bazel = 0 hits;-crate sweep = 0 uses outsid | | -| `RS-0377` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | c47b8ba63 | packages/d2b-provider-device-usbip/src/lib.rs | pub mod state_machine -> mod state_machine; the lib.rs re-export remains the single surface. Census re-run: no state_machine:: module-path users outside the crate. | | -| `RS-0378` | `api` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 7c4997d04 | packages/d2b-provider-device-usbip/src/broker.rs | | | -| `RS-0381` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | W7 | f30695d3f | `packages/d2b-provider-display-wayland/src/controller.rs:685` | PrincipalReleaseReceipt gained a pub(crate) constructor, the runtime captures the reconciled session key through the one canonical derivation, and DisplayRuntime::finalize returns the lease to the bounded pool in the terminal block after worker closure; a crate-local runtime test proves the release. Narrowing was rejected (dead-code deny). Merged (w7-11 branch). | | -| `RS-0379` | `api` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | c5d8e0cf5 | packages/d2b-provider-display-wayland/src/lib.rs | Module moved into the binary target via #[path]; all crate::wayland_proxy paths rewritten; census of d2b_provider_display_wayland::wayland_proxy over packages/nixos-modules/tests/docs/reference = 0. | | -| `RS-0382` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 15d510a76 | packages/d2b-provider-display-wayland/src/controller.rs | WaylandPolicySnapshot::from_authenticated_session deleted (no callers; census over packages/nixos-modules/tests/labs/docs/reference = 0 in the display crate). | | -| `RS-0380` | `api` | `d2b-provider-display-wayland` | low | actionable | leaf | already-fixed | W7 | dc1b0b05e | `packages/d2b-provider-display-wayland/src/wayland_proxy/mod.rs:1` | the four-item pub use re-export line is deleted; only the submodule arms remain and consumers use wayland_proxy::policy::...; re-verified at 6dc80e258. | | -| `RS-0383` | `api` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U3 | 49c490794 | packages/d2b-provider-guest-azure-container-apps/src/lib.rs | Replaced `pub use effects::*` with a named arm list of all 38 effects-owned items (checked against the two external consumers' import lists: d2bd/tests/cloud_composition.rs, d2b-provider-guest driver/ | | -| `RS-0384` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | family | applied | W5 | f5672d7c9 | `src/controller/mod.rs:608, src/controller/mod.rs:418, src/controller/mod.rs:748` | trim route: the uncalled Azure-VM update/adopt/complete-enrollment/status/controller-execution-ref surface and its consequential dead state are deleted after a census showing no production caller; the framework-driven reconcile/recovery/finalize surface is retained | | -| `RS-0385` | `api` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs | AzureVmController::new now takes effect: E by value and stores it; the production call site and the crate's test call sites (18 FakeEffect constructions, incl. the shared-effect recovery test restruct | | -| `RS-0386` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | fe17cfa53 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | repair_children no longer takes committed: &BTreeMap (sole caller passed an always-empty map); the unreachable committed.get(target) branch and the empty-map local are deleted. check/test/clippy green | | -| `RS-0387` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | applied | U3 | 2ba072632 | packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs | assess_update no longer takes children (production adapter discarded it via let _; request carries none); trait default, adapter override, test impl, and the reconcile call site's Vec allocation all u | | -| `RS-0390` | `api` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | family | applied-variant | W4 | 768457562 | `guest_local.rs:49-166, packages/d2b-resource-client/src/zone_client.rs:129-256` | applied-variant: the two declarations had drifted (GuestLocalError::EndpointMismatch vs ClientError::InvalidTarget/TransportPolicyMismatch; extra unused endpoint_uid()); reconciled to the d2b-resource-client shape and re-exported | | -| `RS-0388` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | 9b56489c4 | packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs | ChildMutation::expected_uid() (constant None on the UID-free batch) deleted along with the three assert-None assertions; census: remaining expected_uid hits are unrelated types. check/test/clippy gree | | -| `RS-0389` | `api` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U3 | dc09819bf | packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs | Deleted constant-true preserve_state() accessor and its tautological assertion (census: only consumer was the assertion). check+finalize_ordering tests (6) + clippy green. | | -| `RS-0391` | `api` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | da9369cef | packages/d2b-provider-guest-qemu-media/src/qmp/mod.rs | ScriptedQmpTransport struct and ProcessIdentity::for_test marked #[doc(hidden)] per the house convention (cf. mark_ready_for_test); re-exports kept; census: only in-crate tests name them. | | -| `RS-0392` | `api` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | Seven dead-pub items in the private mod driver narrowed to pub(crate): HostDriver, HostDriverError, HostDriverStatus, HostDriverFactory, HostDriverEffects, host_spec_decoder, HOST_REOBSERVE. Census re | | -| `RS-0393` | `api` | `d2b-provider-network-local` | medium | actionable | leaf | applied-variant | U3 | f17f141c6 | packages/d2b-provider-network-local/src/routes.rs | Both route provenance validators narrowed to #[cfg(test)] pub(crate) and the stale #[allow(dead_code)] removed. Variant: plain pub(crate) alone re-triggers dead_code (both validators have zero product | | -| `RS-0394` | `api` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied-variant | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Deleted uncalled reconcile_authenticated_display (census: def only, zero callers); reconcile_sources and drain_sources lowered to #[cfg(test)] pub(crate) (test-only). Variant: plain pub(crate) would r | | -| `RS-0395` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | U3 | cd1055487 | packages/d2b-provider-notification-desktop/src/controller.rs | Stale #[allow(dead_code)] removed from from_route, which is reachable from production via from_authenticated_route. Same commit as RS-0394 (same file). | | -| `RS-0396` | `api` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W7 | 58ac8df53 | `packages/d2b-provider-notification-desktop/src/lib.rs:29, packages/d2b-provider-notification-desktop/src/lib.rs:59` (the src/stream_admission.rs shim this row deleted is gone from the tree) | the private shim module is deleted and lib.rs re-exports the four admission items directly; the ADR-046 layout and reuse rows now cite src/admission.rs (dossier-citation gate green). Merged ae531b399. | | -| `RS-0397` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | ebeef4024 | packages/d2b-provider-process-systemd/src/lib.rs | lifecycle is now a private module; the root re-export is the single surface. Census: zero consumers of the d2b_provider_process_systemd::lifecycle path anywhere. check + lib tests green; clippy red is | | -| `RS-0398` | `api` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 6a4c9b7c6 | packages/d2b-provider-process-systemd/src/lifecycle.rs | Deleted always-true no_persistent_unit() and its test assertion; census: definition+test only. cargo check and provider_config test pass. | | -| `RS-0399` | `api` | `d2b-provider-process-systemd` | low | policy-confirmed | leaf | applied-variant | W7 | 14d098fc3 | `packages/d2b-provider-process-systemd/src/lib.rs:22` | the row's zero-production-consumer claim is partly false (d2bd composes SystemdProcessProvider and effects_service), so lifecycle/effects_service/operations stay exported; the holding part is implemented - the six test-only modules (controller, drain, metrics, audit, launch, sandbox) are gated behind a new test-support feature (Cargo [[test]] required-features + Bazel crate_features on the test-support target), the conformance suites keep running, and the crate doc records the wired vs test-only surface. A throwaway consumer crate proves the plain build no longer resolves the six modules. Merged 3668d3a6e. | | -| `RS-0400` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | c61b0e5b5 | packages/d2b-provider-provider/src/driver.rs | ProviderDriverFactory::new() and impl Default deleted (zero callers; crate tests construct via with_effects; FailClosedProviderDriverEffects still used by tests). Census: no new()/default() callers ac | | -| `RS-0401` | `api` | `d2b-provider-provider` | low | actionable | leaf | applied | U3 | 56c460c03 | packages/d2b-provider-provider/src/providers.rs | Completed the in-flight partial edit: deleted plan_external body, Disable/Delete intent variants, Draining phase, TrustOrCompatibilityDenied error, and orphaned test helpers/imports; check/test/clippy | | -| `RS-0402` | `api` | `d2b-provider-quota` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-quota/src/lib.rs:21` | same wiring as RS-0959 | | -| `RS-0403` | `api` | `d2b-provider-resource-export` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-export/Cargo.toml:17, packages/d2b-provider-resource-export/src/lib.rs:18` | same wiring as RS-0959 | | -| `RS-0404` | `api` | `d2b-provider-resource-import` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-resource-import/Cargo.toml:17, packages/d2b-provider-resource-import/src/lib.rs:18` | same wiring as RS-0959 | | -| `RS-0405` | `api` | `d2b-provider-role` | low | actionable | family | applied | W5 | f82fa17c8 | `packages/d2b-provider-role/Cargo.toml:17, packages/d2b-provider-role/src/lib.rs:16` | the empty test-support feature stanza is deleted with the [[test]] registration required-features gate and the bazel variant's crate_features that referenced it; the registration test now runs instead of being silently skipped, rbac stays public product surface | | -| `RS-0406` | `api` | `d2b-provider-seccomp-profile` | low | actionable | family | applied | W4 | 7dadf9923 | `packages/d2b-provider-seccomp-profile/src/lib.rs:19, packages/d2b-provider-seccomp-profile/src/lib.rs:22, packages/d2bd/src/foundation_seed.rs:25, packages/d2bd/src/foundation_seed.rs:1091` | | | -| `RS-0407` | `api` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 0cb5d7b68 | packages/d2b-provider-supervisor/src/adapter.rs | | | -| `RS-0408` | `api` | `d2b-provider-supervisor` | medium | actionable | family | applied | W5 | 85cfe8bc1 | `packages/d2b-provider-supervisor/src/broker.rs:951-955, packages/d2b-provider-supervisor/src/broker.rs:1524-1546, packages/d2b-provider-process/src/backend.rs:315-319` | LaunchedSnapshot carries the launched runner (vm, role, pid, start-time ticks, pidfd) as a named struct with a redacting Debug; the in-tree ProcessEffectBackend trait and LaunchedObserver take it instead of five positional parameters and a 5-tuple, and the only call site plus both daemon call sites are re-pointed | | -| `RS-0409` | `api` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | gate the crate's test-support module behind a `test-support` feature (house pattern: test `required-features`), keeping the hermetic doubles out of the default library surface | | -| `RS-0413` | `api` | `d2b-provider-system-core` | medium | needs-contract | wide | applied-variant | W6 | ab90777de | `src/host.rs:389, src/host.rs:13` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-14. HostReconciler::reject_operator_status_fields (zero callers outside its own tests at HEAD) is now enforced at the daemon's operator status admission (public_update_status_request, the public dispatch's UpdateStatus arm): an operator-submitted Host status naming isolationPosture or isolationPostureMessage, in either request spelling and including the explicit null form, is refused before the row is read. Recorded deviations: the site is the daemon admission rather than d2b-resource-api's update_status (that crate cannot depend on d2b-provider-system-core without inverting the layering), and the provider-session dispatch keeps its own admission because the system-core reconciler's own publication legitimately derives those fields (ADR-046-provider-system-core 4.1.4). Co-change: the typed refusal ResourceRuntimeError::HostStatusFieldNotOwned with its error frame, the system-core host module doc, the admission test an_operator_status_naming_a_host_reconciler_owned_field_is_refused. No serialized shape moves. | | -| `RS-0410` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | make the `ownership` module private; the root re-export of the owned/disowned type lists is the single surface. Shares commit 31ff8b396 with RS-0409 (the audit's own census pairs these two module-surf | | -| `RS-0411` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | narrow `reconcile_observed`/`HostProbeSnapshot` to `pub(crate)` with the crate-internal-only callers retained; drop the now-private seam from the crate's pub re-export. Shares commit 31ff8b396 with th | | -| `RS-0412` | `api` | `d2b-provider-system-core` | low | actionable | leaf | applied | U3 | 31ff8b396 | packages/d2b-provider-system-core/src/lib.rs | forward `HostProbeMetadata` from the host re-export while dropping the zero-external-consumer `HostProbeSnapshot` constant from the public surface; the crate's probe seam stays internal until a consum | | -| `RS-0414` | `api` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | 0623be33bf4894fc796b0f603508b2570b746b7d | packages/d2b-provider-toolkit/Cargo.toml | Added test-support = [] feature; gated both constructors with #[cfg(any(test, feature = "test-support"))]; required-features on the supervised_runtime test target; added test-support to the Bazel test | | -| `RS-0415` | `api` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | 81f51276ed7456104a034c40ba5b3c45bba8c790 | packages/d2b-provider-toolkit/src/server/service.rs | Deleted response_request_id and generated_service plus the response_request_id doc; narrowed the now-unused RequestId import; kept generated_services(). Census re-run: both symbols over worktree = 0 c | | -| `RS-0416` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:525-531` | | | -| `RS-0417` | `api` | `d2b-provider-toolkit` | low | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/mod.rs:530-532` | | | -| `RS-0418` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_zone_link.rs | | | -| `RS-0419` | `api` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/credential_client.rs | | | -| `RS-0420` | `api` | `d2b-provider-volume` | medium | actionable | wide | applied | W5 | 14bf42022 | `packages/d2b-provider-volume/src/driver.rs:246-250, packages/d2b-provider-volume/src/driver.rs:282, packages/d2bd/src/resource_plane_v3.rs:2975, packages/d2b-provider-volume/tests/registration.rs:25` | the never-read VolumeDriverArgs zone field is removed; construction sites and fixtures no longer carry it | | -| `RS-0421` | `api` | `d2b-provider-volume-local` | medium | actionable | family | applied | W5 | 96fef8256 | `src/lib.rs:82, src/testing.rs:1-402, packages/d2b-provider-volume-local/Cargo.toml:1` | the volume-local `testing` module is gated behind test-support (feature declared, the pre-existing `_test_support` bazel variant gains `crate_features`); the four volume-local suites, d2bd's cfg(test) consumer, and the crate's internal cfg(test) uses are re-pointed, with zero product-path consumers | | -| `RS-0422` | `api` | `d2b-provider-zone` | medium | actionable | leaf | applied | U3 | c28489ccc | packages/d2b-provider-zone/src/lib.rs | zone_status module private with the four items re-exported by name; the two module-path consumers (d2bd resource_runtime.rs:63-65, tests/zone_status.rs:3-4) re-pointed to the crate root. Census: d2b_p | | -| `RS-0423` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied-variant | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zone_links.rs | Fix as written (pub(crate)) not implementable: usage is test-only, and .cargo/config.toml -Dwarnings turns the resulting dead-code into build errors. Minimal correct variant: #[cfg(test)] on ZoneLinkM | | -| `RS-0424` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U3 | 0e51b3ad9 | packages/d2b-provider-zone-link/src/zonelink.rs | Deleted transport_error_is_quarantine (zero callers in or out of crate, including tests; privatizing alone would trip -Dwarnings dead-code). ZoneLinkError import stays used by issue_route_admission. c | | -| `RS-0425` | `api` | `d2b-provider-zone-link` | low | actionable | leaf | skipped-stale | U3 | | `packages/d2b-provider-zone-link/src/zonelink.rs:178` | Lane premise false on census re-run: d2bd calls `controller.cursor_authority()` and consumes the returned `ZoneLinkCursorAuthority` value (production at packages/d2bd/src/composition.rs:1200, test at :1566), so the accessor's pub return type is part of a live cross-crate contract. [reconstructed: the original cell was truncated mid-sentence.] | | -| `RS-0426` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 749bbdc34 | packages/d2b-resource-api/src/adapter.rs | Census re-run: zero consumers. Deleted ResourceApiReachability enum, RESOURCE_API_REACHABILITY const, lib re-export, and the tautological assertion in the 13-method test. | | -| `RS-0427` | `api` | `d2b-resource-api` | low | actionable | leaf | applied-variant | U3 | 0d74a18f2 | packages/d2b-resource-api/src/client.rs | Census re-run: zero callers. pub(crate) alone tripped denied dead_code warnings (crate denies warnings), so the unwired methods were deleted until a caller exists. | | -| `RS-0428` | `api` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | wire_revision and api_subject narrowed to pub(crate). resource_owner_subject stays pub because its U9/U10 caller has landed at HEAD: d2bd/src/resource_runtime/plane_controller_bridge.rs:369 (subject() | | -| `RS-0429` | `api` | `d2b-resource-client` | medium | actionable | leaf | applied | U3 | 8b53d606e | packages/d2b-resource-client/src/zone_client.rs | | | -| `RS-0430` | `api` | `d2b-resource-runtime` | medium | actionable | family | applied | W4 | 98f74a980 | `packages/d2b-resource-runtime/src/context.rs:364-366` | | | -| `RS-0431` | `api` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | 0cd7b063d | packages/d2b-resource-runtime/src/target.rs | Removed TargetBinding::directory() accessor. Census re-run: zero callers; the directory field stays read by internal methods (observe/delete/adopt), no dead code. cargo check/test/clippy green for d2b | | -| `RS-0432` | `api` | `d2b-resource-runtime` | low | actionable | leaf | applied-variant | U3 | 3570364e0 | packages/d2b-resource-runtime/src/guest_target.rs | Removal as written orphans GuestTargetInner.reference (dead-code deny) and forces a public constructor signature change across 26 call sites in 5 files incl. d2bd production (published surface -> cont | | -| `RS-0433` | `api` | `d2b-resource-types` | medium | actionable | family | applied | W5 | 96fef8256 | `packages/d2b-resource-types/src/lib.rs:30, packages/d2b-resource-types/src/metadata.rs:72,` | assert_metadata_registration and its re-export arm are gated behind test-support; the 11 registration test crates enable the feature in dev-dependencies, gain required-features where it was missing, and their bazel targets use the resource-types `_test_support` variant | | -| `RS-0434` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/fragmentation.rs | Fragment.header is now private with a pub header() accessor; the two engine.rs encode call sites (877, 1395) use the accessor. Census: no external field access. | | -| `RS-0435` | `api` | `d2b-session` | low | actionable | leaf | applied | U3 | 0b3b6b645 | packages/d2b-session/src/engine.rs | | | -| `RS-0436` | `api` | `d2b-session-unix` | medium | actionable | family | applied | W4 | 2f034e476 | `packages/d2b-session-unix/src/socket.rs:176` | | | -| `RS-0437` | `api` | `d2b-sk-frontend` | low | actionable | leaf | applied | U3 | b9fc346fc | packages/d2b-sk-frontend/src/lib.rs | agent/config/link/uhid made private; UhidDevice and UhidEvent re-exported from lib.rs; main.rs:41 uses root re-exports. Census: sk_frontend::(agent/config/link/uhid):: = 0 full-path hits; zone-routing | | -| `RS-0438` | `api` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | a9902b8e7 | packages/d2b-unsafe-local-helper/src/runtime.rs | Census re-run: zero external consumers. SupervisorSpec, SUPERVISOR_START_TIMEOUT, SNAPSHOT_RECONCILE_TIMEOUT, send_frame, receive_frame, configure_socket_buffers narrowed to module-private; no pub sig | | -| `RS-0442` | `api` | `d2bd` | medium | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/composition.rs | process_provider_runtime and provider_effects narrowed to pub(crate) with a cfg(feature=test-support) pub mod seam for tests/resource_operator_activation.rs; test-only items (new_persistent, admit, pe | | -| `RS-0441` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/resource_plane_v3.rs | ResourcePlaneV3 accessors: targets()/hub() return Arc by value, store()/registry() return plain refs; Arc::clone(plane.hub()/targets()) sites updated to plane.hub()/plane.targets(); adopt_guest_target | | -| `RS-0439` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | pub surface reduced to pub(crate): trait HostAudioController, PipeWireHostController, from_audio_node, find_audio_node, QemuAudioController. Census re-run: only in-crate callers (audio_dispatch.rs); m | | -| `RS-0440` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 2e92e177c | packages/d2bd/src/audio_host_controller.rs | vm_name param removed from HostAudioController::enforce_grant/enforce_level, all three impls (PipeWire/Qemu/Fake), and all call sites incl. tests. Checks: cargo check green; cargo test -p d2bd --locke | | -| `RS-0443` | `api` | `d2bd` | low | actionable | leaf | applied | U3 | 524d06bad06c00ccf05c20c14461400478d70df3 | packages/d2bd/src/provider_registry.rs | Re-export narrowed to MAX_PROVIDER_REGISTRY_ENTRIES only; census re-run at HEAD shows ProviderRegistrySnapshot appears nowhere else in the workspace through d2bd's path (only the re-export line itself | | -| `RS-0444` | `api` | `d2bd-runtime` | medium | actionable | family | applied-variant | W4 | 87c3172bc | `shell_backend.rs:52-53` | applied-variant: delegating best_effort_close/best_effort_cancel take &EstablishedShell (0/2 callers, all in composition.rs) | | -| `RS-0446` | `api` | `d2bd-runtime` | low | actionable | leaf | applied-variant | U3 | 225f36a3a | packages/d2bd-runtime/src/exec_session.rs | Variant of the row's fallback ('gate the module test-support-only'): the exec-session worker machinery (spawn_session_worker, WorkerSpawn, worker_main, WorkerState, TerminalReaper, OwnerReaper, Establ | | -| `RS-0445` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e10faa81f | packages/d2bd-runtime/src/ch_api.rs | ch vm.info payload deserialized through a derived raw shape with a round-trip test | | -| `RS-0447` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 8b3164c4f | packages/d2bd-runtime/src/console_session.rs | ConsoleClientHandle field made private; added validating FromStr (console-<32 hex>) with ConsoleClientHandleParseError; table lookups stay allocation-free via existing Borrow/as_str (the already- | | -| `RS-0448` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 1ed0521fa | packages/d2bd-runtime/src/console_session.rs | Dropped unused _vm parameter from spawn_ch_serial_drainer and the hardcoded "ch-console".to_owned() allocation at the create_ch_session call site. | | -| `RS-0449` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | e8e7a2d51 | packages/d2bd-runtime/src/console_session.rs | Deleted dead pub DrainerSource enum (census re-run: pattern DrainerSource over packages = 1 hit, the definition itself; zero constructions) and its #[allow(dead_code)]. | | -| `RS-0450` | `api` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 26d5c1119 | packages/d2bd-runtime/src/console_session.rs | ConsoleRing/ConsoleSession fields made private; ConsoleRing exposes push_bytes/set_eof (notify internally), read_at, base_offset, notify(); ConsoleSession exposes provider_kind/ring/stdin_tx accessors | | -| `RS-0963` | `err` | `X3-cross-crate-duplication` | medium | needs-contract | wide | applied-variant | W6 | 7739ae6f5 + 128a340f0 | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/hosts.rs:122, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:132` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slices w6-15 and w6-13. Applied: d2b-provider-clipboard-wayland PickerIpcError::Frame/String became Frame(#[from] FramingError) + Read(#[source] io::Error) + ClosedMidFrame with every Display byte-identical; d2b-provider-transport-azure-relay CredentialUnavailable/TransportUnavailable carry typed sources through the explicit Error::source impl (applied-variant: the file hand-writes Display/Error, so no #[source] attributes exist there) with code() strings unchanged; d2bd TypedError carries the audio failure classes as typed leaf variants (applied-variant: failure class as variants rather than a source object, because d2bd-runtime cannot name provider-typed sources and std sources are not Clone). Already-fixed at HEAD, each with its commit: d2b-broker ops/usbip_lock.rs (RS-0454 fd5b41b4b), ops/hosts.rs (84d4cb0b9), d2b-resource-runtime (fa4907468), d2bd-runtime vsock (c9addc3aa). Residual not in the row: PickerIpcError::Socketpair/Spawn/FdFlags still flatten their io/FdMappingCollision errors - flagged, not expanded. | | -| `RS-0477` | `err` | `d2b` | medium | actionable | leaf | applied-variant | U3 | 7256bc918 | packages/d2b/src/lib.rs | Added structured code field to CliFailure; populated in ZoneContext::failure; can_fallback_to_local_state and reconcile_deadline match on it. Field is String not &'static str because validate_response | | -| `RS-0478` | `err` | `d2b` | medium | needs-contract | leaf | applied | W7 | 50be72eea | `packages/d2b/src/host.rs:276` | host prepare/destroy/reconcile now route through missing_mutation_flag_envelope: kind --apply-or-dry-run-required and exit 78 for all three (prepare/destroy moved from exit 2 ref-invalid), with a regression test that fails on the old shape; the --network refusal is untouched. Merged 01daff2b1. | | -| `RS-0451` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 7917598f6 | packages/d2b-audit/src/record_types.rs | | | -| `RS-0452` | `err` | `d2b-audit` | medium | actionable | leaf | applied | U3 | 637d66627 | packages/d2b-audit/src/segment.rs | | | -| `RS-0455` | `err` | `d2b-broker` | high | actionable | wide | applied-variant | U1 | 092b0f3d3 | `packages/d2b-broker/src/runtime.rs:2534` (DispatchAuditContext::from_request) | claim re-verified unreachable at HEAD (join digests are computed before parse); applied anyway so the broker yields the typed protocol refusal like the daemon and the sibling from_request_with_join - mutation-verified with the join returning raw strings, no wire change | | -| `RS-0454` | `err` | `d2b-broker` | medium | actionable | leaf | applied-variant | W6 | fd5b41b4b | `packages/d2b-broker/src/ops/usbip_lock.rs:47, packages/d2b-broker/src/ops/usbip_lock.rs:84` | Claim re-verified at HEAD: `UsbipLockError::Io { path, detail: String }` (ops/usbip_lock.rs:47) flattens io::Error at 12 conversion sites. Fix changes an error-variant's field from String to `#[source [reconstructed: ]source: io::Error`; the Display text is preserved, so the broker error-envelope strings are unchanged; one format-string site (usbip_lock.rs:111) needs its own variant]. Applied as variant-split deviation: Io { path, source: io::Error } with a manual Error::source() override (no thiserror dep in d2b-broker) and a new PathSafetyViolation { path } variant; Display byte-identical. | | -| `RS-0457` | `err` | `d2b-broker` | medium | actionable | leaf | applied | U3 | 84d4cb0b9 | packages/d2b-broker/src/ops/hosts.rs | WriteMarkerBlockError::Io(String) -> Io(io::Error) with a hand-written Error::source() accessor (no thiserror dep). Display unchanged ('update-hosts marker splice: {err}' renders identically). Dropped | | -| `RS-0456` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | ce4da285b | packages/d2b-broker/src/state_cells.rs | with_retention now returns Result (test caller updated with expect); in_memory expect names the startup-precondition rationale; check/test/clippy green. | | -| `RS-0458` | `err` | `d2b-broker` | low | actionable | leaf | applied | U3 | 7ce599eeb | packages/d2b-broker/src/ops/exec_reconcile.rs | Replaced usbip_unbind_error_is_transient with typed UsbipUnbindFailure { kind: UsbipUnbindFailureKind (Busy/Interrupted/TextFileBusy/Fatal), transient, detail } classified once per error via UsbipUnbi | | -| `RS-0459` | `err` | `d2b-broker` | low | actionable | leaf | applied | W6 | fd5b41b4b | `src/ops/device_worker.rs:262-284, src/ops/device_worker.rs:149, src/live_handlers.rs:2452` | guest_socket_directory now returns a pub(crate) GuestSocketError enum (RuntimeRootNotAnchored/GuestNotAPlainName/DirectoryOutsideRuntimeRoot) whose Display preserves the three static-code substrings byte-for-byte; the two live_handlers.rs consumers updated; substring-asserting tests stay green. | | -| `RS-0453` | `err` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/src/seam.rs | verify_startup_routing returns Result<(), StartupRoutingViolation> (UnadmittedHandler/MissingHandlers, Display preserved for main.rs); audit_crate/run_cargo_metadata/dependency_tree return Result<_, S | | -| `RS-0460` | `err` | `d2b-bus` | medium | actionable | leaf | applied | U3 | ad70ac37c | packages/d2b-bus/src/wire.rs | added closed ZoneBoundPolicyIdentityError::NotProviderRef (label zone-bound-policy-identity-provider-ref-invalid); census: only wire.rs tests call with_provider; updated the failure assertion | | -| `RS-0461` | `err` | `d2b-contracts` | medium | actionable | leaf | applied | U3 | 6a3ac39da | packages/d2b-contracts/src/configured_argv.rs | ConfiguredArgvError, LauncherMetadataError, UnsafeLocalWorkloadsError, MediaRefError, UsbBusIdError, AuditPageError enums with Display+Error replace String/&'static str returns; unwrap-only callers co | | -| `RS-0462` | `err` | `d2b-contracts-control` | low | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | Added fmt::Display (message "invalid shell name") and std::error::Error impls to ShellNameError; additive, no surface moved. cargo check/test/clippy -p d2b-contracts-control --locked all passed | | -| `RS-0463` | `err` | `d2b-contracts-provider` | medium | actionable | leaf | applied | U3 | 58e72374f | packages/d2b-contracts-provider/src/v3/provider_registry.rs | split zero-generation check before mapping-count bound; Defensive-only reachability since ResourceGeneration rejects 0 at new/Deserialize; no consumer pins the code | | -| `RS-0465` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | W6 | 1a6ca86e7 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:90` | CredentialControllerError::AlreadyRunning Display now emits credential-already-running; the lease-ceiling emitters (CredentialAuditOutcome/CredentialTelemetryOutcome as_str) fixed to credential-queue-pressure and the allowed_telemetry_value closed set updated so the ADR-documented code has its real emitter; ADR-046-resources-credential.md Errors table amended in the same commit, plus the two provider ADRs' code tables that enumerate the same set. | | -| `RS-0466` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | d9440dfae | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialObservabilityError Display now renders kebab codes (credential-audit-record-invalid, credential-telemetry-frame-invalid); census re-run over packages/nixos-modules/tests/docs/reference/labs/ | | -| `RS-0464` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | ed46f196b | packages/d2b-contracts-provider/src/v3/provider_registry.rs | added GenerationMismatch variant kebab code provider-registry-generation-mismatch; updated failure-path test to assert the variant; census ProviderRegistryError=12 hits all in-file | | -| `RS-0467` | `err` | `d2b-contracts-provider` | low | actionable | leaf | applied | U3 | 75e9c238c | packages/d2b-contracts-provider/src/v3/credential_controller.rs | CredentialSingleFlight lock() now recovers poisoned mutexes via unwrap_or_else(poisoned.into_inner()) and returns the guard directly (infallible); guard Drop recovers the same way instead of silently | | -| `RS-0468` | `err` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/operations/error.rs:93, packages/d2b-contracts-resource/src/v3/operations/error.rs:132, packages/d2b-resource-api/src/error.rs:11` | | | -| `RS-0469` | `err` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | U3 | 8993f39e5 | packages/d2b-contracts-zone-session/src/v3/zone_session.rs | from_component_session on EndpointPurpose and ServicePackage now uses exhaustive matches over the 13/12 base variants; a new component-session variant is a compile error rather than an expect panic. S | | -| `RS-0471` | `err` | `d2b-core` | medium | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | resolve_macvtap_intents now returns crate::error::Error via Error::manifest_parse_error (typed, two failure modes distinguishable); broker call site updated to house .map_err(/error/ BrokerError::Live | | -| `RS-0475` | `err` | `d2b-core` | medium | actionable | family | applied | W4 | 5282e9337 | `packages/d2b-core/src/storage.rs:357, packages/d2b-core/src/sync.rs:136` | | | -| `RS-0472` | `err` | `d2b-core` | medium | actionable | leaf | applied | W6 | 8de97517b | `packages/d2b-core/src/bundle_resolver.rs:3368, packages/d2b-core/src/bundle_resolver.rs:19` | find_network_spec and build_resource_network_intents return Result; the six resolve_network_*_intent pub methods return Result, Error> with Error::manifest_parse_error("resource-bundle.json", reason); ~20 call sites and the NetworkIntentSource trait updated; regression test pins kind ManifestParseError / code 40; error-codes.md unchanged; behavior note added to manifest-bundle.md. | | -| `RS-0476` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/site.rs | SiteJson::validate returns SiteValidationError::InvalidWaylandSocket enum with Display token; caller and tests updated | | -| `RS-0473` | `err` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Primary fix (return Result) is a public-signature change on a pub API with 22 call sites across 6 crates (d2b-broker, d2b-provider-network-local, tests, fuzz) - wider than audited leaf bl | | -| `RS-0474` | `err` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | manifest_parse_reason now matches serde_json::Error::classify() (Category::Data/Syntax/Eof/Io) instead of Display text; all 8 call sites updated to pass &error; slug change not wire-visible per census | | -| `RS-0470` | `err` | `d2b-core-controller` | low | actionable | leaf | applied | U3 | 96cc7e5bb | packages/d2b-core-controller/src/authority.rs | DuplicateConflict code arm rendered as kebab-case duplicate-conflict; in-crate assertion pinning the old spelling updated; census showed 0 hits outside authority.rs. | | -| `RS-0479` | `err` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | bf9832779 | packages/d2b-process-conformance/src/launch_identity.rs | Replaced the is_some_and guard + unreachable .expect with an if-let chain binding owner via .filter(), deleting the panic site and using the bound owner for the error payload; behavior unchanged (same | | -| `RS-0480` | `err` | `d2b-provider-activation-nixos` | medium | actionable | leaf | applied | U3 | 69153d93f | packages/d2b-provider-activation-nixos/src/controller.rs | terminal now takes ResourceName (63-byte lowercase label, no slash); new parses via ResourceName::parse and returns Result<_, IdentityError>; two driver call sites map parse failure to driver Policy e | | -| `RS-0481` | `err` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U3 | f7378bae2 | packages/d2b-provider-audio-pipewire/src/authority.rs | MicrophoneArbiter::new, SpeakerMixer::new, and shared_microphone_arbiter take NonZeroUsize; AUDIO_QUEUE_BOUND is now a NonZeroUsize const; all call sites (incl. wayland-policy) updated. check/test/cli | | -| `RS-0482` | `err` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U3 | bf6f8829f | packages/d2b-provider-audio-pipewire/src/state.rs | AudioStateIoError::source() returns the io::Error/AudioPolicyError payload; AudioControllerError::source() returns the AudioMediatorError payload. Hand-written impls (thiserror not in lockfile). check | | -| `RS-0483` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | 1b70ff14a | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | spawn_niri_event_thread returns Result<(), io::Error>; call site logs instead of panicking. | | -| `RS-0484` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U3 | da5acd332 | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | Binary Result<_, String> signatures and format!-built errors migrated to anyhow; typed BridgeReadError/ControlReadError/ReasonCode untouched; control-socket JSON bodies byte-identical. | | -| `RS-0485` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | fb67a0526 | `packages/d2b-provider-clipboard-wayland/src/history.rs:137` | ClipboardHistory::new returns Self unconditionally and ClipdHost::new calls it directly with no map_err or warn; re-verified at 6dc80e258. | | -| `RS-0486` | `err` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | already-fixed | W7 | 7739ae6f5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:132` | PickerIpcError carries the typed Frame(FramingError) variant with #[from]; the six to_string collapses are gone and a test pins the typed source; re-verified at 6dc80e258. | | -| `RS-0487` | `err` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U3 | 3d19a8ea6 | packages/d2b-provider-config-nixos/src/ttrpc.rs | Encoding-failure branch now maps to ttrpc Code::INTERNAL, matching the config-document-encoding-failed code class. | | -| `RS-0488` | `err` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U3 | dbec5dde7 | packages/d2b-provider-credential-managed-identity/src/lib.rs | export_checkpoints now rejects an unparseable lease-map key with the crate's typed `InvariantFailure` refusal instead of a `.expect()` panic; shares commit dbec5dde7 with RS-0368 (same lib.rs surface, | | -| `RS-0489` | `err` | `d2b-provider-device-tpm` | medium | actionable | leaf | applied | U3 | 5f7c5aae5 | packages/d2b-provider-device-tpm/src/runner.rs | runner::SwtpmArgvError deleted (единый one-variant enum + its Display/Error impls); SwtpmSettings::validate now returns swtpm_argv::SwtpmArgvError::LogLevelOutOfRange { level }; lib.rs re-exports swtp | | -| `RS-0490` | `err` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U3 | 2f5c9a692 | packages/d2b-provider-device-usbip/src/state_machine.rs | | | -| `RS-0491` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | U3 | 263eea211 | packages/d2b-provider-display-wayland/src/controller.rs | DisplayController::new returns Result with # Errors doc; 2 daemon sites use expect/unwrap; all call sites updated. | | -| `RS-0493` | `err` | `d2b-provider-display-wayland` | medium | actionable | leaf | applied | W7 | f30695d3f | `packages/d2b-provider-display-wayland/src/process.rs:346` | both constructors return a closed LaunchError whose Display codes are byte-identical to the old &'static str failures; the test-support wrappers take the same type and lib.rs re-exports it. The daemon caller keeps its whole-error map because the constructor's failure set is closed to one variant. Merged (v7-11 branch). | | -| `RS-0492` | `err` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 64c41ddb5 | packages/d2b-provider-display-wayland/src/spec.rs | WaylandSpecError::NoPrincipalAvailable variant + Display arm deleted; no error-codes.md hit; no other constructors (controller uses PrincipalPoolError/SessionCondition). | | -| `RS-0494` | `err` | `d2b-provider-host` | low | actionable | leaf | applied-variant | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | observe_host returns Result<_, ObserveError>; the flattening format! is replaced by a closed error carrying both SystemCoreError legs with Error::source() (fallback is the chain source, probe error re | | -| `RS-0495` | `err` | `d2b-provider-host` | low | actionable | leaf | applied | U3 | 97ca730c8 | packages/d2b-provider-host/src/driver.rs | HostDriverError::Display delegates to self.kind.failure_kind().code(); the three registry codes verified identical to the re-spelled literals. | | -| `RS-0496` | `err` | `d2b-provider-network-local` | low | actionable | leaf | applied | U3 | 200aa2bb2 | packages/d2b-provider-network-local/src/nftables.rs | Sole non-test unwrap replaced with try_into().expect naming the statically-known invariant (64-byte chunk yields a 4-byte word slice). check/clippy exit 0; nftables tests pass. | | -| `RS-0497` | `err` | `d2b-provider-notification-desktop` | medium | actionable | family | applied-variant | W4 | b56a46c1e | `packages/d2b-provider-notification-desktop/src/guest_source.rs:18-21, packages/d2b-provider-notification-desktop/src/lifecycle.rs:291-297, packages/d2b-provider-notification-desktop/src/controller.rs:369, packages/d2b-provider-notification-desktop/src/controller.rs:930` | applied-variant: kept the crate's existing exported ProviderError name (renaming is churn); test-fake slugs mapped to family variants; 4 pre-existing unused ProviderError variants kept as exported API | | -| `RS-0498` | `err` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U3 | eba219aa6 | packages/d2b-provider-notification-desktop/src/types.rs | Added NotificationError::Denied (slug notification-denied; not pinned in docs/reference) and mapped the five admission/zone/category rejection sites (host_sink.rs source/observer admission, zone misma | | -| `RS-0499` | `err` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | U3 | a625c020b | packages/d2b-provider-observability-otel/src/ingress_policy.rs | Full connection-table rejection now reports IngressErrorClass::None, consistent with the sibling capacity refusal. | | -| `RS-0500` | `err` | `d2b-provider-process` | low | actionable | leaf | applied | U3 | c22876d4f | packages/d2b-provider-process/src/driver.rs | Map VolumeBinding/Volume row parse failures to ProcessDriverErrorKind::SpecInvalid in identity() and serving_worker_launch() (now Result, _>); genuinely absent rows/views/attachments still y | | -| `RS-0501` | `err` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | 159a84f30 e2f9719ac | `packages/d2b-provider-process-systemd/src/error.rs` (deleted by this row) | Deleted the zero-consumer SystemdProviderError enum, its file, and pub mod error; (census: 4 hits all in error.rs). Handlers keep their closed &'static str codes. check + full suite 43 passed; clippy: | | -| `RS-0502` | `err` | `d2b-provider-supervisor` | medium | actionable | leaf | applied | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | | | -| `RS-0503` | `err` | `d2b-provider-supervisor` | low | actionable | leaf | skipped-stale | U3 | 62f4be4ff | packages/d2b-provider-supervisor/src/adapter.rs | The wildcard match arm the row wanted removed is mandatory: `ProcessEffectError` is `#[non_exhaustive]` (packages/d2b-provider-process/src/backend.rs:216-217), so a match outside its defining crate cannot be exhaustive without it. [reconstructed: the wave-3 per-slice reports were never persisted, so this cell is reconstructed from the code rather than recovered from the record.] | | -| `RS-0504` | `err` | `d2b-provider-telemetry-service` | medium | actionable | leaf | applied-variant | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | TelemetryServiceDriverError carries source: Option> with Error::source(); the Err(_) swallow in reconcile_service now attaches the store error and classify_error surfaces it as a fa | | -| `RS-0505` | `err` | `d2b-provider-telemetry-service` | low | actionable | leaf | applied | U3 | 24cca337b | packages/d2b-provider-telemetry-service/src/driver.rs | ingest_endpoint_refs now returns Result and the reconcile fails with InvalidResource on an unparseable or non-array ingestEndpointRefs entry; an absent list still yields an empty set, so a typo is no | | -| `RS-0506` | `err` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | All five map_err(/_/ ()) drop sites in send_bootstrap (capacity, credit scopes, packet build, timeout, burst) and the two in controller_transport (credit scopes, construction) now log warn!(reason = . | | -| `RS-0507` | `err` | `d2b-provider-toolkit` | medium | actionable | leaf | applied | U3 | de1a2c493eb2db826cd517128364c759a86240d9 | packages/d2b-provider-toolkit/src/operations/envelope.rs | audit_named falls back to the canonical (lowercase, dash-stripped) spelling when BoundedToken::parse rejects the raw name, so a refused PascalCase forwarded invocation lands its Denied record; already | | -| `RS-0508` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:615, packages/d2b-provider-toolkit/src/shared_provider.rs:539-546` | | | -| `RS-0510` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fixture.rs:181-192` | | | -| `RS-0511` | `err` | `d2b-provider-toolkit` | medium | actionable | family | applied | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/testing/fakes.rs:275-277, packages/d2b-provider-toolkit/src/testing/fakes.rs:289-291, packages/d2b-provider-toolkit/src/testing/fakes.rs:337-339, packages/d2b-provider-toolkit/src/testing/fakes.rs:391-393` | | | -| `RS-0509` | `err` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/shared_provider.rs:405-408, packages/d2b-resource-runtime/src/spec_store.rs:60-63` | applied-variant: key_ref returns Result; the cited spec_store.rs:60-63 anchor has no key_ref caller at base (d2b-resource-runtime has no provider-toolkit dependency), nothing to update there | | -| `RS-0512` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | -| `RS-0513` | `err` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/guest_credential.rs | | | -| `RS-0514` | `err` | `d2b-provider-user` | low | actionable | leaf | applied | U3 | 2ab7a1ed2 | packages/d2b-provider-user/src/driver.rs | Display impl now writes self.kind.failure_kind().code(); registered FailureKind codes remain the single source, strings unchanged, no behavior change. | | -| `RS-0515` | `err` | `d2b-provider-volume-binding` | medium | actionable | family | applied | W5 | 14bf42022 | `packages/d2b-provider-volume-binding/src/driver.rs:344, packages/d2b-provider-volume-binding/src/driver.rs:426-427, packages/d2bd/src/resource_plane_v3.rs:2954` | BindingDriverArgs.zone is a ZoneId; BindingDriver derives the socket-identity bounded token once at construction instead of re-parsing the zone with expect on every pass, and the sole production construction in d2bd passes the parsed value | | -| `RS-0516` | `err` | `d2b-provider-wayland-policy` | high | actionable | family | applied | U1 | 5776b3cc5 | packages/d2b-provider-wayland-policy/src/interaction.rs, tests/engine.rs | driver constructor returns a typed SpecInvalid refusal; the class's remaining member sites stay with the family wave | U5 -> W5 (driver-args class member key_ref; RS-0962; the class remainder landed in W5 at 14bf42022) | -| `RS-0517` | `err` | `d2b-provider-wayland-session` | low | actionable | leaf | applied | U3 | e783447e2 | packages/d2b-provider-wayland-session/Cargo.toml | Added tracing = 0.1 (already in lockfile; Cargo.lock records one new dep edge) and map_err now logs provider=WAYLAND_SESSION_PROVIDER_REF with reason=%error before mapping to InvalidResource. | | -| `RS-0518` | `err` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Empty batch now rejected with 'batch mutation count is zero'; MAX_BATCH_MUTATIONS check keeps the bound reason. Reason string unpinned in error-codes.md. | | -| `RS-0519` | `err` | `d2b-resource-client` | low | actionable | leaf | applied | U3 | 854ba06a5 | packages/d2b-resource-client/src/call.rs | The three Mutex::lock().unwrap() sites in the waker registry (CancellationFuture::poll, CancellationFuture::drop, CancellationToken::cancel) now use expect with the written reason: no user code runs u | | -| `RS-0520` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | fa4907468 | packages/d2b-resource-runtime/src/error.rs | Split ManagerRpc(String) into ManagerUnavailable(String) (transport: channel closed, dropped request, dead-manager test doubles) and ManagerRejected { reason } (semantic: zone mismatch, unknown owner, | | -| `RS-0521` | `err` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U3 | adb285984 | packages/d2b-resource-runtime/src/spec_store.rs | Added SpecStoreError::CorruptRow { zone, type_name, name }; row_from returns it instead of try_into().unwrap_or([0; 16]) for uid and owner_uid; load_row/list switched from query_row/query_map closures | | -| `RS-0522` | `err` | `d2b-session` | medium | actionable | leaf | applied-variant | U3 | afb1fa59c | packages/d2b-session/src/transport.rs | Applied the typestate option minimally: the Option> wrapper is gone (plain Box), so the consumed state is unrepresentable and all three expects disappeared; public signatures a | | -| `RS-0523` | `err` | `d2b-session` | medium | actionable | leaf | applied | U3 | afb1fa59c | packages/d2b-session/src/client.rs | Error::source() returns Some(&SessionError) for the Session variant and Display writes code= (SessionError::code().as_str()), so the inner code survives both the bridge's %error tracing record a | | -| `RS-0524` | `err` | `d2b-telemetry` | medium | actionable | leaf | applied | U3 | 6f07391f0 | packages/d2b-telemetry/src/emitter.rs | Added EmitterError::InvalidLimits with Display arm and doc updates; zero-capacity/frame/age/retry guards return it; StatePoisoned kept for lock().map_err sites; check/test/clippy green. | | -| `RS-0525` | `err` | `d2b-telemetry` | low | actionable | leaf | applied | U3 | 1453d6b9a | packages/d2b-telemetry/src/session_metrics_sink.rs | Deleted never-constructed SessionMetricsError::Encode variant and its session-metric-encode-failed Display arm; check/test/clippy green. | | -| `RS-0526` | `err` | `d2b-unsafe-local-helper` | medium | actionable | leaf | applied | W6 | 0330ae04b | `packages/d2b-unsafe-local-helper/src/systemd.rs:350, packages/d2b-unsafe-local-helper/src/systemd.rs:338-346` | await_scope_identity's early-exit Ok(_) arm now maps to ScopeError::CreateFailed; the existing mapping chain carries it to HelperFailureCode::ScopeCreateFailed -> daemon wire code 42; both codes stay documented in error-codes.md (rows untouched, drift gate green); regression test pins the reclassified contract. | | -| `RS-0531` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 2c566cfdc | packages/d2bd/src/composition.rs | record_workload_availability_metrics increments through counts.entry((...)).or_insert(0) instead of get_mut().expect("bounded workload availability tuple"), so a label fn drift degrades to a new gauge | | -| `RS-0532` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | 8589377baf86162029f5a6c21ed85d50ec836b04 | packages/d2bd/src/interaction_composition.rs | reap_finished_handlers now logs the JoinError (tracing::warn! %error) instead of discarding it; the spawn body binds an InteractionHandlerAdmissionGuard (Drop runs fetch_sub) so a panicked handler can | | -| `RS-0533` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | a91ad9bbc | packages/d2bd/src/resource_plane_v3.rs | PlaneError's five String variants retyped: FoundationSeed(#[from] SeedError), ManagerSpawn(#[from] ractor::SpawnErr), Bundle(#[from] ResourceBundleError), Authority/Target(#[source] Box>, every impl and call site migrated; re-dispatched per Main's directive 2026-09-25) | | -| `RS-0529` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d4fe83812 | packages/d2bd/src/composition.rs | dispatch_audit's unrecognized severity arm now returns TypedError::WireInvalidFrame { detail: "audit filter has an invalid severity".to_owned() } instead of InternalIo, so caller input errors surface | | -| `RS-0530` | `err` | `d2bd` | medium | actionable | leaf | applied | U3 | d1a472077 | packages/d2bd/src/composition.rs | ActivationLockGuard::drop now logs finish_activation failures via tracing::warn!(zone = %self.zone, error = %error, ...) instead of `let _ =`, mirroring the file's house style for coordinator refusals | | -| `RS-0537` | `err` | `d2bd` | medium | needs-contract | wide | applied | W6 | dba2d00f2 | `packages/d2bd/src/audio_dispatch.rs:487-495, packages/d2bd/src/audio_dispatch.rs:594-602, ` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-13. The audio mutation paths report a user-input refusal through the typed kinds TypedError::AudioVmNotFound (audio-vm-not-found, exit 2) and TypedError::AudioNotEnabled (audio-not-enabled, exit 70) instead of flattening both into TypedError::InternalIo { context, detail }; lock/read/write/host failures keep internal-io. Co-change: the two daemon wire kinds with their envelope text/exit codes/hello-rejection arm, the four mutation-site constructors, and hand-written rows in docs/reference/error-codes.md (the generated block is untouched, so gen_error_codes_drift stays the proof). Wire-visible: a public-socket client that matched internal-io on an unknown or audio-less VM sees the new kinds - the needs-contract move this row asked for; no in-tree consumer branches on the old slug. | | -| `RS-0534` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | 96be9307a | packages/d2bd/src/resource_plane_v3.rs | ConstructionInputs::production now propagates attach_process_providers failures: state.provider_runtime.attach_process_providers(...).map_err(/error/ PlaneError::Authority(error.into()))? instead of ` | | -| `RS-0536` | `err` | `d2bd` | low | actionable | leaf | applied | U3 | fd6778735 | packages/d2bd/src/process_provider_runtime.rs | serving_worker_launch_args now warns when the 0700 enforcement on the worker socket parent fails: tracing::warn!(zone = %zone, socket_dir = %parent.display(), error = %error, ...) mirrors the pidfd sn | | -| `RS-0528` | `err` | `d2bd` | low | actionable | family | applied | W5 | 2fa4cd475 | `packages/d2bd/src/composition.rs:13894, packages/d2bd/src/composition.rs:14127, packages/d2bd/src/composition.rs:15243, packages/d2bd/src/composition.rs:15247` | TypedError's io, config, and broker-unavailable variants carry an `Option` origin (Arc) built by a bounded helper, Display renders the unchanged envelope string, and the raw-detail logging boundary renders a depth-capped source chain; the 34 owned composition.rs sites plus 67 more sites across d2bd-runtime, audio dispatch, forward rendezvous, and the bundle-tampered test are converted (116 sites legitimately pass None where detail is a literal or wire-field rendering), and a test pins byte-identical envelopes | | -| `RS-0538` | `err` | `d2bd-runtime` | high | actionable | leaf | already-fixed | U3 | ebb3831b1 | packages/d2bd-runtime/src/broker_transport.rs | At session-start HEAD, default_audit_join_context maps CanonicalAuditDigest::parse failures to TypedError::WireInvalidFrame;no .expect remains (commit ebb3831b1, ledger wave U1 applied-variant). No ed | | -| `RS-0539` | `err` | `d2bd-runtime` | medium | actionable | leaf | applied | U3 | c14b5d486 | packages/d2bd-runtime/src/wire.rs | map_parse_error classifies structurally: serde_json::Error::classify() gates the frame kind, and the generic WireInvalidFrame detail now carries line/column; the two payload-level wire kinds (unknown- | | -| `RS-0540` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | cdfb78d49 | packages/d2bd-runtime/src/exec_session.rs | spawn_session_worker now returns std::io::Result> (Builder::spawn error propagated via Ok(...)?), replacing the expect panic; the two test call sites unwrap with expect. | | -| `RS-0541` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 75c49e784 | packages/d2bd-runtime/src/console_session.rs | Deleted panicking impl Default for ConsoleClientHandle (census: no ConsoleClientHandle::default() callers in workspace). | | -| `RS-0542` | `err` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | a09140432 | packages/d2bd-runtime/src/daemon_version.rs | version-file read failures typed (VersionFileReadError); check + tests green | | -| `RS-0543` | `err` | `xtask` | medium | actionable | leaf | applied | U3 | 7194d24e9 | packages/xtask/src/delivery/recovery.rs | RecoveryError::Read added for fs open/read failures; Json(String) now carries the bounded serde detail (field names/positions only via error.to_string(), never payload values, keeping the redaction co | | -| `RS-0961` | `serde` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W5 | 6467d8d2c | `packages/d2b-contracts-zone-session/src/v3/zone_routing.rs:558` | the wire_deserialize! macro moves to d2b-contracts with #[macro_export] and 72 hand-written Wire admission Deserialize impls (17 contracts-provider, 55 contracts-resource) become macro invocations; container attributes, field lists, and admission expressions are token-identical, the emitted schemas are byte-identical, and zone-session's 28 invocations re-point at the shared home (one contracts-broker site is out of this slice's scope) | | -| `RS-0545` | `serde` | `d2b-broker` | low | actionable | leaf | applied | W6 | f25b21e84 | `packages/d2b-broker/src/state_cells.rs:337, packages/d2b-broker/src/state_cells.rs:924` | Claim re-verified at HEAD: `DurableRecord.outcome` is a String on the durable wire format, re-parsed by hand in load() (state_cells.rs:924-931), while in-process CellOutcome enum exists. Fix (wire enu [reconstructed: m with `#[serde(rename_all = "lowercase")]`) keeps the serialized shapes "unknown"/"completed" identical, so no DURABLE_VERSION bump is needed]. DurableRecord.outcome typed as CellOutcome with the derive; hand match and re-parse deleted; unknown-outcome fail-closed preserved via serde unknown-variant rejection mapped to CorruptDurable. | | -| `RS-0544` | `serde` | `d2b-broker-composition` | low | actionable | leaf | applied | U3 | 9e035c04f | packages/d2b-broker-composition/Cargo.toml | Minimal CargoMetadata/Package/Resolve/ResolveNode/ResolveDep/DepKind shapes derive Deserialize; run_cargo_metadata parses once; dependency_tree/package_name_of_id/is_proc_macro read fields instead of | | -| `RS-0546` | `serde` | `d2b-contracts` | medium | needs-contract | wide | applied | W6 | 1ab759f13 | `packages/d2b-contracts/src/audit_wire.rs:27-36` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> landed in wave 6 as slice w6-12 and merged into phase-w6-integration (merge b07a7e887). AuditExportEntry now carries exactly one payload through the closed AuditExportEntryPayload enum (Record { record } or Error { error }) instead of the independent record/error optional pair, so an entry that carries neither or both is unrepresentable and refused at decode; the emitted members are unchanged (sequence plus exactly one of record or error), so the broker audit page and the public daemon audit page keep their JSON and the legacy_export_entry_line renderer keeps its output. Co-change: the d2b-contracts-broker re-export, d2b-broker/src/audit.rs, the d2b entry-mapping closure, the d2bd-runtime wire literal, and the regenerated docs/reference/daemon-api.md plus docs/reference/schemas/v2/wire-protocol.json. Gate on the merged tree: cargo test -p d2b-contracts rc=0 (120 tests plus 1 doctest, including an_entry_emits_and_admits_exactly_one_payload and an_entry_payload_is_admitted_exactly_once), cargo test -p d2b-broker rc=0, cargo check over the seven touched crates --all-targets rc=0, gen_schemas_drift and gen_daemon_api_drift green. | | -| `RS-0547` | `serde` | `d2b-contracts-broker` | medium | needs-contract | wide | skipped-stale | W6 | 8351954a0 | `packages/d2b-contracts-broker/src/broker_wire.rs:1836-1861, packages/d2b-contracts-broker/src/broker_wire.rs:1783-1834` | wave-5 deferral: needs-contract routed to W6 (.scratch/wave5-slices.md section 3) -> re-verified at HEAD in slice w6-12, which merged into phase-w6-integration (merge b07a7e887): the claim does not hold at HEAD, so no admission edit was made. The audited premise has the guard inverted - serde 1.0.229 refuses unknown members through the CONTAINER's deny_unknown_fields, while the FLATTENED type's own deny_unknown_fields is the inert one, and both audited requests (OpenUnitPidfdRequest, StopUnitRequest) carry the container attribute, so a stray member is refused today and there is no silently-accepted state to repair. Raw probe kept at .scratch/rs0547-flatten-probe.txt (w6-12 worktree): container-deny + inner-lax still refuses the stray member (unknown field `unknownMember`), container-lax + inner-deny and container-lax + inner-lax accept it, and serde_json::from_value and from_slice both refuse. The requested admission pin landed anyway as 8351954a0 (flattened_unit_requests_refuse_unknown_members), so the observed contract is pinned rather than repaired; gate: cargo test -p d2b-contracts-broker rc=0. | | -| `RS-0548` | `serde` | `d2b-contracts-control` | medium | actionable | leaf | applied | U3 | d72f7c1e6 | packages/d2b-contracts-control/src/public_wire.rs | HelperSnapshot/HelperLaunchRequest/AuditResponse now derive Deserialize via #[serde(try_from = Wire)] with TryFrom impls preserving the exact admission error strings; wire structs keep deny_unknown_fi | | -| `RS-0549` | `serde` | `d2b-contracts-provider` | low | actionable | leaf | applied-variant | U3 | 62324d94a | packages/d2b-contracts-provider/src/v3/telemetry_frame.rs | stated fix uses serde_json::error::Category::UnknownField which 1.0.151 (lockfile) lacks; variant matches the stable 'unknown field' message instead; new test added and mutation-proven (fails pre-fix) | | -| `RS-0550` | `serde` | `d2b-contracts-resource` | medium | actionable | wide | applied | W5 | e77bf4940 | `packages/d2b-contracts-resource/src/v3/error.rs:175, packages/d2b-contracts-resource/src/v3/error.rs:177` | ResourceError deserialization routes through the validating constructor, rejecting a revision for a kind that forbids it and inconsistent retry fields; the wire shape is unchanged | | -| `RS-0551` | `serde` | `d2b-contracts-resource` | medium | actionable | family | applied | W4 | cf58549f7 | `packages/d2b-contracts-resource/src/v3/payload_schema.rs:30, packages/d2b-contracts-resource/src/v3/payload_schema.rs:36` | | | -| `RS-0552` | `serde` | `d2b-contracts-zone-session` | medium | actionable | family | applied-variant | W4 | a2cf0e614 | `zone_routing.rs:558, zone_routing.rs:624, zone_routing.rs:818, zone_routing.rs:932` | applied-variant: consolidated 28 Wire-shape Deserialize impls behind the crate-local wire_deserialize! macro in d2b-contracts-zone-session (canonical home; later waves must reuse it, not write a third macro); parsed_deserialize! requires Self::parse(String) (JSON-string wire), which no Wire-struct impl matches - adopting it would change the wire format the row never asked to change (Main ruling 2026-09-25) | | -| `RS-0556` | `serde` | `d2b-core` | low | actionable | leaf | applied-variant | U3 | 9b3549b58 | packages/d2b-core/src/storage_lifecycle.rs | serde rejects rename_all on struct variants (field attribute); applied the equivalent house pattern #[serde(rename_all_fields = "camelCase")] on the enum container + dropped per-field renames; seriali | | -| `RS-0554` | `serde` | `d2b-core` | low | needs-contract | leaf | applied | W7 | fe7c349ea | `packages/d2b-core/src/bundle_resolver.rs:207` | ZoneNativeIndexDocument declares all six keys nixos-modules/index.nix emits and now denies undeclared ones (the four unread keys are defaulted so a partial index still loads); a new admission test fails without the deny and the four committed index fixtures still parse. Merged cd2b66149. | | -| `RS-0555` | `serde` | `d2b-core` | low | actionable | leaf | applied | U3 | 9b3549b58 | packages/d2b-core/src/bundle_resolver.rs | Dropped four redundant #[serde(default)] on Option fields of ZoneNativeBundleIndex; round-trip test at bundle_resolver.rs:8727 still passes | | -| `RS-0553` | `serde` | `d2b-core-controller` | medium | actionable | wide | applied | W5 | 6ecf465b7 | `packages/d2b-core-controller/src/controller_assignment.rs:596, packages/d2b-core-controller/src/controller_assignment.rs:735, packages/d2b-core-controller/src/controller_assignment.rs:891, packages/d2b-core-controller/src/controller_assignment.rs:901` | typed serde structs (rename_all camelCase, deny_unknown_fields) replace the Value-walking assignment codec and the child-create json! literal builder; exact keys, version 1, ascending verb arrays, canonical bytes, and the size bounds are pinned by the transport tests | | -| `RS-0557` | `serde` | `d2b-host` | low | actionable | family | applied | W4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:229` | | | -| `RS-0558` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 4a72b96f6 | packages/d2b-process-conformance/src/ticket.rs | CompiledDigests now derives Serialize with camelCase rename_all, replacing the 7-field manual impl; wire shape identical (fdTable key pinned by a new round-trip test; explicit fdTable attr found redun | | -| `RS-0559` | `serde` | `d2b-process-conformance` | low | actionable | leaf | applied | U3 | 7f6b1e4da | packages/d2b-process-conformance/src/terminal.rs | ProcessOutcome deserialization now validates at the boundary via #[serde(try_from = "RawProcessOutcome")] with a TryFrom that rejects illegal (exit_class, exit_code) pairs as InvalidTerminalResult; th | | -| `RS-0560` | `serde` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W7 | bcdb699ea | `packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:12` | AuditEvent drops Deserialize (never read back; every site serializes), keeping Serialize and the bounded-MIME adapter, so the audit wire shape is unchanged. Merged ae531b399. | | -| `RS-0561` | `serde` | `d2b-provider-command` | medium | needs-contract | leaf | applied | W7 | bf8dc0bc2 | `packages/d2b-provider-command/src/command.rs:48` | both JsonSchema impls publish the exact admission their parse enforces (exec excludes C0/DEL/C1, argv slot gains minLength and the whole-slot brace pattern); CommandArgvSlot::parse refuses control characters in literal slots so schema and parse agree; the generated v3 Command schema moved through its generator, and an ECMA-262 oracle over 1.1M code points found no mismatch. Merged efdd43e7d. | | -| `RS-0562` | `serde` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U3 | d58f183d5 | packages/d2b-provider-device-gpu/src/gpu_argv.rs | deny_unknown_fields added to GpuArgvInput/GpuParams/GpuDisplayConfig (mirroring VideoArgvInput); new rejects_unknown_fields test pins top-level, params-nested, and display-nested rejection. Mutation c | | -| `RS-0563` | `serde` | `d2b-provider-display-wayland` | medium | actionable | family | applied | W5 | 4cb0daadb | `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs:817, packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs:395` | the receive path decodes each newline-delimited bridge frame with a typed #[serde(tag = "type", rename_all = "snake_case")] inbound enum mirroring the outbound frame instead of scanning raw bytes for the refresh substring; a frame that fails to decode is rate-limited-diagnosed and dropped, and later frames still refresh (pinned by tests) | | -| `RS-0564` | `serde` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U3 | 84b343101 | packages/d2b-provider-display-wayland/src/spec.rs | Inert serde try_from attribute removed; rename_all/deny_unknown_fields and the manual Deserialize + TryFrom kept. | | -| `RS-0565` | `serde` | `d2b-provider-endpoint` | medium | actionable | leaf | applied | U3 | e3ae48716 | packages/d2b-provider-endpoint/src/endpoint.rs | Dropped derived Deserialize; manual impl routes through Self::new following the EndpointConsumerPolicy sibling pattern, plus a round-trip/admission test; wire shape unchanged. | | -| `RS-0566` | `serde` | `d2b-provider-network-local` | medium | actionable | leaf | already-fixed | W7 | 73e163675 | `packages/d2b-provider-network-local/src/driver.rs:296` | the serde failure is no longer dropped - the map_err closure emits a structured warn with the error field before mapping to the toolkit's SpecInvalid; re-verified at 6dc80e258. | | -| `RS-0567` | `serde` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | U3 | 336a4fd97 | packages/d2b-provider-network-local/src/broker.rs | Four provenance payload builders (resolved_bridge_payload/resolved_route_payload in broker.rs and operations.rs) no longer .ok()-swallow serde_json::to_value(provenance); they now propagate with map_e | | -| `RS-0568` | `serde` | `d2b-provider-supervisor` | medium | needs-contract | leaf | applied | W7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:1533` | the take-controller-bootstrap leg now builds a typed TakeControllerBootstrapRequest and parses the typed response; a missing/mistyped result fails the leg with a structured warning instead of reading as not-taken (an explicit taken=false still returns Ok(None)), and the fd stays index 0 (the reply carries exactly one descriptor). Merged f2b98ccfb. | | -| `RS-0569` | `serde` | `d2b-provider-transport-azure-relay` | medium | needs-contract | family | applied | W7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs:9` | deserialization goes through a wire struct plus TryFrom so the derived path runs new()/validate(), and the pinned (hand-authored) schema now records the secret-shape exclusion; a schema-vs-validate agreement probe over 7.9M adversarial identifier pairs found 0 mismatches. Merged 82d6c395d. | | -| `RS-0570` | `serde` | `d2b-provider-transport-azure-relay` | low | policy-confirmed | leaf | applied | W7 | 5c3f15511 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:233` | parse_material_json is replaced by derived relayListen/relaySend structs with deny_unknown_fields plus the same value pass; admission is strictly stronger (unknown and duplicate keys are now refused, and no in-tree producer emits either) and a malformed-shape test pins it. Merged 82d6c395d. | | -| `RS-0571` | `serde` | `d2b-provider-transport-vsock` | medium | needs-contract | wide | applied | W5 | 379eb3b33 | `packages/d2b-provider-transport-vsock/src/settings.rs:16-27, packages/d2b-provider-transport-vsock/src/settings.rs:42-50, packages/d2b-provider-transport-vsock/tests/schema.rs:13-18` | VsockTransportSettings deserializes through a private wire mirror with TryFrom validation, so untrusted JSON is rejected at the boundary; fields are private with accessors and the wire names and JSON schema are unchanged - the needs-contract verdict is overridden because no wire surface moved | | -| `RS-0572` | `serde` | `d2b-provider-volume-local` | medium | actionable | leaf | applied | U3 | b00a073f2 | packages/d2b-provider-volume-local/src/content.rs | ContentFile/ContentProjection/NetworkConfigContentProjection decode via serde try_from Raw mirrors running validating constructors; Deserialize dropped from evidence types; wire shape unchanged. | | -| `RS-0573` | `serde` | `d2b-provider-wayland-policy` | medium | actionable | family | applied | W4 | fc85a4e59 | `packages/d2b-provider-wayland-policy/src/interaction.rs:241-243, packages/d2b-provider-wayland-policy/src/effects_service.rs:205-206, packages/d2b-provider-wayland-policy/src/audio_registry.rs:517-534` | | | -| `RS-0574` | `serde` | `d2b-resource-api` | medium | actionable | leaf | applied | U3 | cc06ec37d | packages/d2b-resource-api/src/manager_backend.rs | render_envelope maps metadata parse failures to envelope_invalid() instead of serde_json::from_slice(...).unwrap_or(Value::Null); sibling parses in the file already fail closed | | -| `RS-0576` | `serde` | `d2bd` | medium | actionable | leaf | applied-variant | U3 | f1bb96854 | packages/d2bd/src/composition.rs | deny_unknown_fields added to both GatewayGuestConfigFile and GatewayGuestRelayConfigFile. The config-typo test landed as direct deserialization tests on both structs (gateway_guest_config_tests mod), | | -| `RS-0575` | `serde` | `d2bd` | low | needs-contract | leaf | applied | W7 | 369627b78 | `packages/d2bd/src/composition.rs:20373` | one parse_activation_marker seam refuses any schemaVersion != 1 with a structured warning and all three read sites (read_activation_marker plus both startup loops) go through it, so a future caller cannot adopt a versioned marker without the check. Merged a74fd9b0c. | | -| `RS-0577` | `serde` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | declared_fd_kind now matches the seven kebab-case FdKind spellings directly (fifo/socket/char-device/block-device/any/regular/directory) instead of allocating a serde_json::Value::String; behavior ide | | -| `RS-0578` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 3e78efe56 | packages/d2bd-runtime/src/wire.rs | parse_request now dispatches the 17 plain verbs (list/status/audit/vmStart/vmStop/vmRestart/switch/boot/test/rollback/usbipBind/usbipUnbind/hostPrepare/hostDestroy/hostReconcile/workload/audio) throug | | -| `RS-0579` | `serde` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | version-file write failures reported through tracing | | -| `RS-0580` | `serde` | `xtask` | medium | actionable | leaf | applied | U3 | 9ccb9c694 | packages/xtask/src/service_catalog.rs | deny_unknown_fields added to DeclarationFile; all six committed service-catalog.json files verified to carry only the declared keys (provider/providerRef/providerUid/services); new test an_unknown_dec | | -| `RS-0582` | `serde` | `xtask` | low | actionable | leaf | applied | U3 | 45160a4e1 | packages/xtask/src/delivery/mod.rs | Added #[serde(deny_unknown_fields)] to SnapshotView; existing prebinding_snapshot_refresh_remains_allowed round-trip test covers the shape. | | -| `RS-0581` | `serde` | `xtask` | low | actionable | leaf | applied-variant | U3 | 341c4fb5e | packages/xtask/src/resource_type_authority.rs | rename_all = camelCase added to DeclarationFile and TypeDeclaration; per-field resourceType rename deleted;the crate per-field rename must stay because the wire key 'crate' is a Rust keyword that rena | | -| `RS-0583` | `obs` | `d2b-broker` | low | actionable | leaf | applied | U3 | 48c6dde54 | packages/d2b-broker/src/live_handlers.rs | retry_acl_grant emits label = %label as a named field on both records with interpolation-free messages; label is not a pinned scan identifier; security-scan clean. | | -| `RS-0584` | `obs` | `d2b-core` | medium | actionable | leaf | applied | U3 | fc7dfcc52 | packages/d2b-core/src/bundle_resolver.rs | verify_bundle_hash warning now tracing::warn! with structured path field (no pinned correlation identifiers; security scan clean); added tracing = "0.1" (house logging dep already in lockfile via sibl | | -| `RS-0585` | `obs` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | U3 | a94ef37d6 | packages/d2b-provider-activation-nixos/src/controller.rs | all 9 warn! refusal events in ActivationTrust::verify now carry a named refusal field with the exact ActivationVerificationError variant; no correlation identifiers added (ADR 0010/0028 safe). | | -| `RS-0586` | `obs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U3 | 09167b5fa | packages/d2b-provider-clipboard-wayland/src/bin/d2b-clipd.rs | All 62 log:: sites in d2b-clipd.rs converted to tracing:: with named fields; env_logger init replaced by tracing_subscriber::fmt().with_env_filter(...).with_writer(stderr).init() mirroring d2bd; log/e | | -| `RS-0587` | `obs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W7 | e1ab1525f | `packages/d2b-provider-clipboard-wayland/src/clipd_host/host.rs:66` | all six interpolated clipd_host log events now emit tracing named fields (quality, mimes, secret, error, pid, protocol). Merged ae531b399. | | -| `RS-0588` | `obs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U3 | a085f811d | packages/d2b-provider-credential-secret-service/src/service.rs | Session-close warn now carries provider=crate::PROVIDER_REF plus unresolved_leases and unresolved_operations named fields. | | -| `RS-0589` | `obs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U3 | 77cf1c434 | packages/d2b-provider-guest-azure-virtual-machine/Cargo.toml | #[tracing::instrument(skip_all, fields(provider = "runtime-azure-virtual-machine"))] on reconcile/adopt/poll_operation/update/finalize; per-event provider literal and redacted resource_group field dro | | -| `RS-0590` | `obs` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | U3 | cc01388e6 | packages/d2b-provider-guest-qemu-media/src/controller/reconcile.rs | reconcile/finalize now carry a tracing instrument span with resource/provider fields; 23 per-event duplicate pairs dropped. Deviation: the row's literal span syntax (fields inside skip) is rejected by | | -| `RS-0591` | `obs` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | U3 | dafc28ca1 | packages/d2b-provider-process-systemd/src/lib.rs | cancelled-ticket debug! now passes resource = %ticket.process_ref() (lazy, redacted Display) instead of eager to_canonical_string(); warn/error paths keep the canonical string. check + lib tests green | | -| `RS-0592` | `obs` | `d2b-provider-test-controller` | medium | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/Cargo.toml | tracing_subscriber::fmt::init() installed at the top of main(); added tracing-subscriber = { version = "0.3", features = ["fmt"] } to Cargo.toml (already in the lockfile at 0.3.23; Cargo.lock delta is | | -| `RS-0593` | `obs` | `d2b-provider-test-controller` | low | actionable | leaf | applied | U3 | c897fbaa7 | packages/d2b-provider-test-controller/src/main.rs | Keepalive failure now bound as warn!(reason = %e, ...) via if let Err; unexpected named-stream arm binds the StreamEvent and logs warn!(stream = ?event.stream(), ...) using the existing const stream() | | -| `RS-0594` | `obs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U3 | abc324d2a | packages/d2b-provider-toolkit/src/base/guest.rs | serve_enrolled now emits tracing::warn!(frame_bytes, ...) before dropping a frame GuestFrame::new rejects (empty or oversized), keeping the session up. No correlation identifiers in the record. cargo | | -| `RS-0595` | `obs` | `d2b-provider-toolkit` | low | actionable | family | applied-variant | W4 | 6a8eed6cb | `packages/d2b-provider-toolkit/src/server/session.rs:135, packages/d2b-provider-toolkit/src/server/session.rs:255, packages/d2b-provider-toolkit/src/server/session.rs:262` | applied-variant: method field unavailable at all 3 sites (receive failure precedes decode; readiness/loop failures carry no request); zone+provider added from the route binding | | -| `RS-0596` | `obs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U3 | 7d2724dba | packages/d2b-provider-transport-azure-relay/src/relay_transport.rs | | | -| `RS-0597` | `obs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U3 | e7b30fbf0 | packages/d2b-provider-transport-unix/src/portal.rs | Four map_err(/_/) warns (peer-credential bind, monitor fd dup, observation poll, entropy source) now capture the errno as reason=%error, mirroring the admission-rejection site. | | -| `RS-0598` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | OpaqueEndpointId/OpaqueBindingId Display now renders self.0 (Debug stays redacted), so the 9 open-reject warn fields correlate a transport. Security scan clean on the changed lines (these ids are not | | -| `RS-0599` | `obs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied-variant | U3 | e97b2b71d | packages/d2b-provider-transport-vsock/src/service.rs | TransportEntry carries endpoint/binding ids; the spawn block captures clones and threads them through run_bridge (copy-failure event gets fields) and emit_event (subscriber-drop event gets fields); th | | -| `RS-0600` | `obs` | `d2b-resource-api` | low | actionable | leaf | applied | U3 | 0d74a18f2 | packages/d2b-resource-api/src/service.rs | Replaced eprintln with tracing::debug!(error = %error, "create envelope validation failed"); tracing already a dependency and used in the crate. | | -| `RS-0601` | `obs` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | U3 | 9d5d2cfc9 | packages/d2b-unsafe-local-helper/Cargo.toml | Failure path now emits tracing::warn! with error/request_id/operation named fields; operation field neutral-named (local renamed operation_id -> operation), no pinned identifier in record; security sc | | -| `RS-0605` | `obs` | `d2bd` | medium | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Accept loop's four eprintln! calls replaced with tracing::error! events: connection-handler failures carry error = %error.message() (and peer_uid = peer.uid, captured before the move into the handler; | | -| `RS-0606` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Three lifecycle info events gained named fields: Guest-local ZoneLink transport Provider composed and Guest target-control service composed carry zone = %identity.zone() and guest_ref = %identity.gues | | -| `RS-0607` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 31248998b093d92fef1e41eb07ecb49e3b79d33c | packages/d2bd/src/provider_lifecycle.rs | publish_trusted_context failure arm now carries error = %error as a named field, matching the sibling Ok(_) arm and the plane's other warn sites. cargo check green; clippy green for d2bd. | | -| `RS-0602` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | 73f90a27e93a9d36942287072f2f8a9c398aee53 | packages/d2bd/src/resource_runtime.rs | The eight named map_err closures (envelope/spec/construction/current-resource/status-serialization/descriptor-decode/descriptor-verify/controller-construction) now capture the error and log it as erro | | -| `RS-0603` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | The root Zone generation unavailable refusal in compose_gateway_zone_links now carries zone = %topology.root, so the refusal is queryable per zone. Checks: cargo check green. | | -| `RS-0604` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | f1bb96854 | packages/d2bd/src/composition.rs | Both LiveRequestOwners warn events in shutdown_resource_plane now carry zones = ?zones, so the operator can tell welche Zones are stuck. Checks: cargo check green. | | -| `RS-0608` | `obs` | `d2bd` | low | actionable | leaf | applied | U3 | ac53b04480ff741f030852d69f5bd9bfcaf466e7 | packages/d2bd/src/forward_rendezvous.rs | In-flight-cap refusal warn now carries peer_uid and max = posture.max_inflight fields, matching the sibling peer-not-broker warn style. Committed together with RS-0577 (same file, same commit). cargo | | -| `RS-0609` | `obs` | `d2bd-runtime` | low | actionable | leaf | already-fixed | U3 | 97df1b826 | packages/d2bd-runtime/src/runtime_process.rs | At session-start HEAD, write_daemon_version_file already routes all five failure paths through tracing::warn! with error/path named fields (commit 97df1b826). No edit made. | | -| `RS-0610` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 918539524 | packages/d2bd-runtime/src/ssh_host_key_preflight.rs | Octal mode field is now tracing::field::debug(format_args!(...)));the pre-joined subjects string was inlined as tracing::field::display(join-expr) inside the warn! so it is built only when the event i | | -| `RS-0611` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | ead7c7956 | packages/d2bd-runtime/src/readiness.rs | Unparseable-stat warning now emits pid = %pid and path = %format_args!(/proc/{pid}/stat) named fields with a shorter message;no correlation-identifier references. | | -| `RS-0612` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 3b86c38b6 | packages/d2bd-runtime/src/pidfs_probe.rs | PidfsNotPresent arm emits pidfs_st_dev = %st_dev (both warn and error), UnexpectedError arm emits detail = %detail;operator-facing sentence kept as message template with interpolated tails removed. | | -| `RS-0613` | `obs` | `d2bd-runtime` | low | actionable | leaf | applied | U3 | 785aebb20 | packages/d2bd-runtime/src/console_session.rs | qemu console fd-conversion warn now carries error = %e as a named field; no correlation identifiers in the record. | | -| `RS-0659` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/exec_client.rs` | one-line docs for expect_start/expect_detached_create/list/logs/status/kill | | -| `RS-0658` | `docs` | `d2b` | low | actionable | leaf | applied | U2 | 4784e6cda | `packages/d2b/src/doctor.rs` | docs for doctor/validate/CLI surface incl. crate-level doc | | -| `RS-0614` | `docs` | `d2b-audit` | low | actionable | leaf | applied | U2 | fc707d752 | `packages/d2b-audit/src/export.rs` | # Errors sections on 11 pub Result items; # Examples doctests on AuditRecord::new and SegmentWriter::open, both passing (cargo test --doc 2/2). | | -| `RS-0624` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 93ced15b2 | `packages/d2b-broker/src/fd_passing.rs` | doc comments added per row | | -| `RS-0630` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | b09261be0 | `packages/d2b-broker/src/ops/media.rs` | MediaOpError variants, outcome structs/fields, eight pub ops fns documented with # Errors | | -| `RS-0625` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | d2096735c | `packages/d2b-broker/src/sys.rs` | doc comments added; merged with RS-0008/RS-0626 in same commit | | -| `RS-0631` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | ba9873712 | `packages/d2b-broker/src/protocol.rs` | MAX_FRAME_SIZE and connect/bind/send_json_frame/recv_json_frame documented | | -| `RS-0632` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 6b709ea9a | `packages/d2b-broker/src/ops/state_dir.rs` | DirKind, PrepareDirRequest/fields, PrepareDirAudit, ReplaceOrCreateResult, prepare_dir and live helpers documented with # Errors | | -| `RS-0621` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 1643cd532 | `packages/d2b-broker/src/audit.rs` | field docs on AuditDropSummary/AuditEntry; contract docs on AuditLog::open/audit_drop_summary | | -| `RS-0616` | `docs` | `d2b-broker` | medium | actionable | family | applied | W4 | 27a3de0bd | `packages/d2b-broker/src/runtime.rs:324, packages/d2b-broker/src/runtime.rs:375, packages/d2b-broker/src/runtime.rs:398` | | | -| `RS-0622` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 7ac3d8cdf | `packages/d2b-broker/src/ops/host_generation_handoff.rs` | doc comments added per row | | -| `RS-0623` | `docs` | `d2b-broker` | medium | actionable | leaf | applied | U2 | 025b075a8 | `packages/d2b-broker/src/ops/route.rs` | doc comments added per row | | -| `RS-0615` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 34f355adf | `packages/d2b-broker/src/ops/usbip_lock.rs` | doc comments added per row | | -| `RS-0617` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 4bfa5fd51 | `packages/d2b-broker/src/ops/usbip_host.rs` | doc comments added per row | | -| `RS-0626` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | d2096735c | `packages/d2b-broker/src/sys.rs` | doc comments added; merged with RS-0008/RS-0625 in same commit | | -| `RS-0618` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 7cf9b6478 | `packages/d2b-broker/src/ops/sysctl.rs` | doc comments added per row | | -| `RS-0619` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 380e073d5 | `packages/d2b-broker/src/ops/storage_contract.rs` | doc comments added per row | | -| `RS-0620` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | e507a1e71 | `packages/d2b-broker/src/ops/mod.rs` | doc comments added per row | | -| `RS-0627` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 5a2fa07c7 | `packages/d2b-broker/src/ops/store_view_farm.rs` | journal sentence trimmed and # Errors block added; merged with RS-0010 in same commit | | -| `RS-0628` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | ac44605b7 | `packages/d2b-broker/src/envelope/mod.rs` | # Errors blocks on call/call_with_fds/call_nested_with_fds naming ENVELOPE_REFUSALS vocabulary; merged | | -| `RS-0629` | `docs` | `d2b-broker` | low | actionable | leaf | applied | U2 | 098cdc0e5 | `packages/d2b-broker/src/ops/nm.rs` | apply_with_reload/remove_with_reload docs rewritten as plain contracts | | -| `RS-0633` | `docs` | `d2b-bus` | medium | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | docs for BusEvent/BusFailureReason variants,and BusObserver methods | | -| `RS-0637` | `docs` | `d2b-bus` | medium | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/operations.rs` | Cancellation docs: minted by bus, one attempt, is_cancelled | | -| `RS-0634` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a | `packages/d2b-bus/src/router.rs` | one-line docs for DEFAULT_MAX_ROUTES_PER_SESSION,and DEFAULT_MAX_TOTAL_ROUTES | | -| `RS-0635` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/router.rs` | docs for install body, authz error class, session-failure accessors, as_str wire labels | | -| `RS-0636` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/router.rs` | # Errors on BusIngress::invoke, ZoneRegistrar::register_component_session,and BusEndpoint::invoke | | -| `RS-0638` | `docs` | `d2b-bus` | low | actionable | leaf | applied | U2 | fbf92683a,6355caebb | `packages/d2b-bus/src/streams.rs` | # Errors on StreamName::parse, OperationId::parse, ZoneBoundPolicyIdentity::digest,and ZoneEndpointPolicy::lower | | -| `RS-0639` | `docs` | `d2b-contracts-broker` | medium | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/host_generation.rs` | # Errors sections on SourceGenerationCompatibilityFloorV1::new, begin_handoff, all five HandoffCoordinator transitions, RunnerLaunchArgs::new, envelope_invoke_kernel naming exact variants. | | -| `RS-0640` | `docs` | `d2b-contracts-broker` | low | actionable | leaf | applied | U2 | 7338e4b5c | `packages/d2b-contracts-broker/src/broker_wire.rs` | FdKind/ForwardOperationRequest doc polish: missing space, CJK full-width periods, and comma-adjacent spacing fixed. | | -| `RS-0641` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | 2329f6aa2 | `packages/d2b-contracts-control/src/cli_output.rs` | One-line docs added to all 32 CLI-output DTOs/enums; StatusServicesOutputV3 already documented | | -| `RS-0642` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | e12e51dac | `packages/d2b-contracts-control/src/public_wire.rs` | Docs added to the named request/status types plus UsbipProbeEntry field meanings; # Errors added to ShellName::new (RealmAccentColor::new covered by RS-0643) | | -| `RS-0643` | `docs` | `d2b-contracts-control` | medium | actionable | leaf | applied | U2 | 5c5b2d478 | `packages/d2b-contracts-control/src/unsafe_local_wire.rs` | Constants documented with the daemon-enforced bounds, wire types one-lined, helper fns and RealmAccentColor::new get # Errors | | -| `RS-0644` | `docs` | `d2b-contracts-control` | low | actionable | leaf | applied | U2 | e5b584959 | `packages/d2b-contracts-control/src/terminal_wire.rs` | One-line docs per DTO plus the redacted-Debug note on session-bearing types | | -| `RS-0646` | `docs` | `d2b-contracts-provider` | medium | actionable | family | applied | W4 | a4de30484 | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:155, packages/d2b-contracts-provider/src/v3/telemetry_policy.rs:478, packages/d2b-contracts-provider/src/v3/telemetry_frame.rs:72, packages/d2b-contracts-provider/src/v3/semantic_services/mod.rs:93` | | | -| `RS-0645` | `docs` | `d2b-contracts-provider` | low | actionable | leaf | applied | U2 | 6fa152aa1 | `packages/d2b-contracts-provider/src/v3/provider.rs` | # Errors sections added to BinaryRef::parse, TrustEvidence::admit, macro-generated parse/from_opaque_digest, CredentialWire::decode_wire | | -| `RS-0649` | `docs` | `d2b-contracts-resource` | medium | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/artifact.rs` | doc comments on the artifact id bound, error, type, parse, and accessor | | -| `RS-0650` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | e7bba788d | `packages/d2b-contracts-resource/src/v3/execution_policy.rs:923, packages/d2b-contracts-resource/src/v3/execution_policy.rs:944` | none (anchor drift only) | | -| `RS-0647` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | c6de84588 | `packages/d2b-contracts-resource/src/v3/limits.rs` | module-level rationale naming the enforcing boundaries | | -| `RS-0648` | `docs` | `d2b-contracts-resource` | low | actionable | leaf | applied | U2 | 712bb24af | `packages/d2b-contracts-resource/src/v3/operations/error.rs:21, packages/d2b-contracts-resource/src/v3/operations/error.rs:262, packages/d2b-contracts-resource/src/v3/operations/seal.rs:48, packages/d2b-contracts-resource/src/v3/operations/seal.rs:121` | three enumerated sub-claims were already documented at the audit baseline and left unchanged (verified via git show 6ebdd4cec): MutationSealAcceptor::diagnose (seal.rs:176-177), PreparedStoreMutation: | | -| `RS-0651` | `docs` | `d2b-contracts-zone-session` | medium | actionable | wide | applied | W5 | 0274747fc | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:27, packages/d2b-contracts-zone-session/src/v3/component_session.rs:51` | the 37 ComponentSession v3 wire constants carry one-line docs naming their wire role; values, names, and ordering are unchanged | | -| `RS-0655` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/manifest_v04.rs` | module doc plus docs on ManifestV04/ManifestMeta/ObservabilityMeta/VmEntry/VmLifecycle/VmGracefulShutdown/VmLiveActivation/VmLanPolicy/VmObservability/VmShellMetadata/ManifestShellName; # Errors on fr | | -| `RS-0654` | `docs` | `d2b-core` | medium | actionable | leaf | applied | U2 | f3da9fd31 | `packages/d2b-core/src/bundle_resolver.rs` | one-line docs naming the exact BundleOpId shape added to all 15 undocumented intent_id_* constructors | | -| `RS-0652` | `docs` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/main.rs` | One-line field docs added to RuntimeReadiness (4), RecoverySnapshot (5), HandlerStatus (9). | | -| `RS-0653` | `docs` | `d2b-core-controller` | low | actionable | leaf | applied | U2 | c89bfcbe0 | `packages/d2b-core-controller/src/migration.rs` | requires_migration and validates_binding documented. | | -| `RS-0656` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/bridge_port.rs` | Added # Errors to validate_readback, parse_request, parse_validation_request, validate_media_ref, validate_usb_busid, and NftBatch::parse (the wire-boundary parsers the row names). | | -| `RS-0657` | `docs` | `d2b-host` | low | actionable | leaf | applied | U2 | f7e032f8f | `packages/d2b-host/src/cgroup.rs` | One-line docs added to Controller::REQUIRED, Controller::as_str, Controller::from_token (token grammar noted), BusId::new, HostPrepStepId::as_str. | | -| `RS-0660` | `docs` | `d2b-process-conformance` | low | actionable | leaf | applied | U2 | e47020297 | `packages/d2b-process-conformance/src/terminal.rs` | Added # Errors to the named Result items: ProcessOutcome::exited/validate, BrokerTerminalResult::relay, SandboxCompiler::compile, LaunchIdentity::new (six variants), LaunchTicket::validate, LaunchedPr | | -| `RS-0661` | `docs` | `d2b-provider` | medium | actionable | leaf | applied | U2 | d6adc6a8e | `packages/d2b-provider/src/agent.rs` | Added # Errors to all 17 anchors: ProviderAgentRequest::new/dispatch, new_linked, RepairPolicy::bounded/validate, ProviderDescriptor::new/validate, three identity parses, ProviderInstance::new, with_c | | -| `RS-0662` | `docs` | `d2b-provider-activation-nixos` | medium | actionable | leaf | applied | U2 | 6acd5ada6 | `packages/d2b-provider-activation-nixos/src/controller.rs` | Added # Errors naming the exact ActivationError/ActivationVerificationError variants to verify, verify_application, refuse_undeclared_runner_step, reconcile, apply_runner_result. | | -| `RS-0663` | `docs` | `d2b-provider-audio-binding` | low | actionable | leaf | applied | U2 | ca450e9d5 | `packages/d2b-provider-audio-binding/src/audio_binding.rs` | Added # Errors to binding_children, validate, dependencies, desired_children naming Unavailable vs InvalidResource conditions. | | -| `RS-0664` | `docs` | `d2b-provider-audio-pipewire` | medium | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/state.rs` | Documented AudioStateLock guard semantics (holds the OFD lock; drop releases and closes). | | -| `RS-0665` | `docs` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | U2 | fc6c6e7da | `packages/d2b-provider-audio-pipewire/src/controller.rs` | Documented the 300s cadence rationale, hoisted 64 into pub const AUDIO_QUEUE_BOUND used by new, with_shared_microphone, and the admission bound test (u64 casts at lease sites). | | -| `RS-0666` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | U2 | f0210347a,48437393c | `src/fd.rs:549, src/policy.rs:81, src/audit.rs:200, src/runtime.rs:97` | the Policy::new hunk landed in the policy-unification commit f0210347a (same file as RS-0040); the other three hunks in 48437393c | | -| `RS-0667` | `docs` | `d2b-provider-clipboard-wayland` | medium | actionable | family | applied | W4 | 64408bc95 | `src/audit.rs:172, src/audit.rs:174` | | | -| `RS-0668` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 460a05942 | `packages/d2b-provider-clipboard-wayland/src/history.rs:112-115` | none | | -| `RS-0669` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,b8724cd15,ac5e33ab1 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:136, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:128, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:162, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:336-337, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:424-427, packages/d2b-provider-clipboard-wayland/src/clipd_host/wayland.rs:79-81, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:204-242, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:248-249` | picker.rs hunks shared commit 018c1dad5 with RS-0041/RS-0042 (index race, see RS-0041) | | -| `RS-0670` | `docs` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | U2 | 018c1dad5,ac5e33ab1,08c2e3648 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/framing.rs:28-29, packages/d2b-provider-clipboard-wayland/src/clipd_host/picker.rs:74, packages/d2b-provider-clipboard-wayland/src/clipd_host/audit.rs:7` | picker.rs hunk shared commit 018c1dad5 (index race, see RS-0041) | | -| `RS-0671` | `docs` | `d2b-provider-command` | low | actionable | leaf | applied | U2 | ef3bc5ec9 | `packages/d2b-provider-command/src/command.rs` | Added one-line # Errors naming CommandContractError variants to CommandExec::parse, CommandArgvSlot::parse, CommandSpec::new. | | -| `RS-0672` | `docs` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | U2 | 7a6ab2d2d | `packages/d2b-provider-config-nixos/src/controller.rs` | # Errors added to all 19 pub Result items naming ConfigError variants | | -| `RS-0673` | `docs` | `d2b-provider-credential` | low | actionable | leaf | applied | U2 | b68a9b55e | `packages/d2b-provider-credential/src/session.rs` | Added # Errors to CredentialRevocationRequest::new (InvalidResource conditions) and CredentialSession::revoke_credential (Revocation). | | -| `RS-0674` | `docs` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | U2 | b29c0b8d2 | `packages/d2b-provider-credential-entra/src/controller.rs` | Added # Errors naming returned variants to EntraEndpointPolicy::new, EntraConfig::new, EntraPlacement::new/new_in_zone/new_runtime_in_zone, EntraCredentialProviderFactory::new, revoke_owned_handles, r | | -| `RS-0675` | `docs` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | U2 | e86206bab | `packages/d2b-provider-credential-managed-identity/src/lib.rs` | Added # Errors naming ManagedIdentityProviderError/CredentialServiceError/CredentialObservabilityError variants to the named constructors and controller projections. | | -| `RS-0676` | `docs` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | U2 | d5869f583 | `packages/d2b-provider-credential-secret-service/src/lib.rs` | # Errors added to SecretServiceConfig/Placement/Factory/Controller items and drain | | -| `RS-0677` | `docs` | `d2b-provider-credential-secret-service` | low | actionable | leaf | applied | U2 | c6aa0e3d6 | `packages/d2b-provider-credential-secret-service/src/service.rs` | SESSION_CLOSE_REVOKE_DEADLINE_MS const with why-doc replaces triplicated 1_000 | | -| `RS-0678` | `docs` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/controller.rs` | # Errors sections added to all 16 named Result-returning items with exact error variants | | -| `RS-0679` | `docs` | `d2b-provider-device-gpu` | low | actionable | leaf | applied-variant | U2 | 8d910bf9c | `packages/d2b-provider-device-gpu/src/gpu_argv.rs` | dropping the allows exposed 15 more undocumented variants/fields under deny(missing_docs); documented GpuContextType variants, GpuArgvError/VideoArgvError variants+path fields, VideoBackend::Vaapi, pl | | -| `RS-0681` | `docs` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | U2 | a895e8c62 | `packages/d2b-provider-device-security-key/src/lease.rs` | # Errors naming SecurityKeyLeaseError/SecurityKeyControllerError variants on all named items | | -| `RS-0680` | `docs` | `d2b-provider-device-security-key` | low | actionable | leaf | applied | U2 | e5ec67524 | `packages/d2b-provider-device-security-key/src/relay.rs` | All pub items documented (incl. Leased variant fields found by compiler); module allow dropped | | -| `RS-0682` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae,8ac4f8535 | `packages/d2b-provider-device-tpm/src/resources.rs` | # Errors added to all 12 pub Result items naming TpmResourceEffectError/TpmResourceControllerError/SwtpmArgvError variants | | -| `RS-0683` | `docs` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | U2 | c4543b5ae | `packages/d2b-provider-device-tpm/src/swtpm_argv.rs` | Module allow dropped; SwtpmArgvError variant fields documented to satisfy deny(missing_docs) | | -| `RS-0684` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | 59c6a4e3a | `packages/d2b-provider-device-usbip/src/reconcile_state.rs` | All pub items documented (compiler-enumerated, incl. trait methods and variant fields); both module allows dropped | | -| `RS-0685` | `docs` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | U2 | a1d9832ec | `packages/d2b-provider-device-usbip/src/arbitration.rs` | # Errors added to the eight named pub Result items | | -| `RS-0687` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/policy.rs` | Applied with this commit: display-wayland: correct policy getter docs and add error sections | | -| `RS-0686` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | 99e27d5b6 | `packages/d2b-provider-display-wayland/src/wayland_proxy/bridge.rs` | from_identity_parts, path_for_user_identity, parse_filter, and the three ReadinessReporter methods had no doc comment at all; each received a first sentence plus the # Errors section (the readiness co | | -| `RS-0688` | `docs` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | U2 | c4242f7f0 | `packages/d2b-provider-display-wayland/src/spec.rs` | Applied with this commit: display-wayland: correct policy getter docs and add error sections | | -| `RS-0689` | `docs` | `d2b-provider-guest` | low | actionable | leaf | applied | U2 | f0a67ccd5 | `packages/d2b-provider-guest/src/facets.rs` | Added # Errors to row_view, session_target_control, resource_uid, and the GuestTargetEffect trait's realize/delete/adopt. | | -| `RS-0690` | `docs` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | U2 | 8a45d2d37 | `packages/d2b-provider-guest-azure-container-apps/src/effects.rs` | Documented effects pub surface (consts, enums, opaque_id! expansion, configs, records, candidates, both effect traits) and dropped the module-level allow; crate builds under deny. | | -| `RS-0691` | `docs` | `d2b-provider-guest-azure-virtual-machine` | medium | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs` | # Errors naming AzureVmError variants incl. Transient-vs-fatal split on reconcile/adopt/poll_operation/update/finalize/complete_enrollment/restore_recovery_state/from_bytes/consume/3 validates | | -| `RS-0692` | `docs` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | U2 | 8b6efd32a | `packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs` | matches() doc states the constant-time-in-presented-length guarantee | | -| `RS-0693` | `docs` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | U2 | cd1a144af | `packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs` | # Errors sections on GuestSetupDescriptor new/from_canonical_bytes/canonical_bytes/validate_integrity/verify_with, GuestChildBatch::from_descriptor, and the health evidence constructors. | | -| `RS-0694` | `docs` | `d2b-provider-guest-qemu-media` | medium | actionable | leaf | applied | U2 | 613491144 | `packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | # Errors added to DeviceAdmission::validate, QemuMediaController::reconcile, LaunchTicket::new, QmpSession::negotiate | | -| `RS-0695` | `docs` | `d2b-provider-notification-desktop` | medium | actionable | leaf | applied | U2 | 18f028fda | `packages/d2b-provider-notification-desktop/src/action_nonce.rs` | # Errors sections on ActionNonceStore::register, NotificationRuntime::new, NotificationSink::deliver_from_guest_source naming exact variants. | | -| `RS-0696` | `docs` | `d2b-provider-notification-desktop` | low | actionable | leaf | skipped-stale | U2 | | `packages/d2b-provider-notification-desktop/src/runtime.rs:88-89, packages/d2b-provider-notification-desktop/src/test_support.rs:14, packages/d2b-provider-notification-desktop/src/guest_source.rs:17` | All three cited docs are complete standalone first sentences at baseline 6ebdd4cec (verified via git show) and HEAD; the lane quoted tail lines of multi-line docs. | | -| `RS-0697` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/lib.rs` | Added one-line doc comments to PROVIDER_NAME, PROVIDER_REF, PROVIDER_API_MAJOR mirroring OTEL_HOST_BRIDGE_ROLE. | | -| `RS-0698` | `docs` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | U2 | 11083ae48 | `packages/d2b-provider-observability-otel/src/agent.rs` | Added # Errors to ProviderAgentProcess::new/session_connect/process_effect, ProviderConfig::from_json, TelemetryServiceController::reconcile, TelemetryComponentSession::open_stream, EmitterSocket::bin | | -| `RS-0699` | `docs` | `d2b-provider-operation` | low | actionable | leaf | applied | U2 | 4e381161f | `packages/d2b-provider-operation/src/operation.rs` | Added one-line # Errors naming OperationContractError variants to OperationAudit::new, AuditJoin::new, OperationFds::new, OperationBounds::new, OperationSpec::new. | | -| `RS-0700` | `docs` | `d2b-provider-process` | low | actionable | leaf | applied | U2 | ada188a9c | `packages/d2b-provider-process/src/backend.rs` | Added # Errors to ProcessEffectBackend::launch (closed-code classes) and resolve_launch_identity (LaunchIdentityError). | | -| `RS-0701` | `docs` | `d2b-provider-process-minijail` | low | actionable | leaf | applied | U2 | 85d30ec37 | `packages/d2b-provider-process-minijail/src/launch.rs` | Added # Errors naming ProcessConformanceError conditions to PlatformGate::validate, validate_launch_ticket, and the launch/adopt/stop/stop_stale impl methods. | | -| `RS-0702` | `docs` | `d2b-provider-process-systemd` | medium | actionable | leaf | applied | U2 | 8fcd947b2 | `packages/d2b-provider-process-systemd/src/lifecycle.rs` | Added # Errors to SystemdProviderConfig::new (OutOfRange), drain::validate (two variants), SystemdProcessController::reconcile (DeadlineExceeded + wrapped), validate_launch_ticket (ProviderMismatch), | | -| `RS-0703` | `docs` | `d2b-provider-provider` | low | actionable | leaf | applied | U2 | 46b177892 | `packages/d2b-provider-provider/src/providers.rs` | Documented all eight ProviderObservation fields. | | -| `RS-0704` | `docs` | `d2b-provider-role` | low | actionable | leaf | applied-variant | U2 | e36441105 | `packages/d2b-provider-role/src/lib.rs` | Added #![deny(missing_docs)] and documented PolicyRevisionSet fields; the gate forced one-line docs on AuthorizationCacheKey::new and the four PositiveDecisionCache methods to keep the build green. | | -| `RS-0705` | `docs` | `d2b-provider-seccomp-profile` | medium | actionable | leaf | applied | U2 | 4d49437db | `packages/d2b-provider-seccomp-profile/src/seccomp_profile.rs` | Added # Errors to DeviceNodePath::parse (InvalidDevicePath) and SeccompProfileSpec::new (TooManySyscalls/TooManyDeviceBinds). | | -| `RS-0706` | `docs` | `d2b-provider-shell-terminal` | medium | actionable | leaf | applied | U2 | 54462da35 | `packages/d2b-provider-shell-terminal/src/authz.rs` | Added # Errors to 14 named Result-returning items enumerating the ShellTerminalError variants each emits (authorize_request, OpenSessionRequest::new, PoolSpec::new, ShellSession::from_pool, restore_po | | -| `RS-0707` | `docs` | `d2b-provider-system-core` | medium | actionable | leaf | applied | U2 | 7b621ee10 | `packages/d2b-provider-system-core/src/host.rs` | # Errors added to validate, HostProbeSnapshot::new, reconcile family, reject_operator_status_fields, UserReconciler::reconcile and both port methods | | -| `RS-0708` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/base/runtime.rs` | # Errors sections on ProviderEntrypoint::new, admit, the three with_* binders, StartupPlan::derive/declare naming their refusal variants. | | -| `RS-0709` | `docs` | `d2b-provider-toolkit` | low | actionable | leaf | applied | U2 | 0208e33d4 | `packages/d2b-provider-toolkit/src/testing/conformance.rs` | # Errors sections on check_descriptor_conformance, check_provider_conformance, operation_deadline, deadline_remaining, validate_attachment_indexes. | | -| `RS-0710` | `docs` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | U2 | 33a84349d | `packages/d2b-provider-transport-azure-relay/src/auth.rs` | # Errors added to mint_sas, build_connect, CreditWindow::new, RelayTransportSettings::new | | -| `RS-0711` | `docs` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | U2 | 721c96f38 | `packages/d2b-provider-transport-unix/src/portal.rs` | Added # Errors naming PortalError variants to open, close, and observe. | | -| `RS-0712` | `docs` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | U2 | fda87abbe | `packages/d2b-provider-transport-vsock/src/auth.rs` | Added # Errors bullet lists to all 30 public Result-returning items (incl. all RelayEffectPort/VsockEffectPort/NamedStreamPort trait methods). The audit's 38 count included private impl helpers, not p | | -| `RS-0713` | `docs` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | U2 | 275c581bf | `packages/d2b-provider-volume-binding/src/facets.rs` | Added # Errors to SocketRemoveSource::remove, GuestMountSource::guest_mount_ready, BindingDriverEffects::remove_socket, and guest_mount_ready naming the daemon-adapter failures and fail-closed handlin | | -| `RS-0714` | `docs` | `d2b-provider-volume-local` | low | actionable | leaf | applied | U2 | 40dc98ca3 | `packages/d2b-provider-volume-local/src/content.rs` | Added # Errors to ContentFile::new, ContentProjection::new/from_value, EntryRequest::resolve, VolumeLocalController::reconcile, admit_attachments, validate_source_spec. | | -| `RS-0715` | `docs` | `d2b-provider-zone` | low | actionable | leaf | applied | U2 | 2170c0cac | `packages/d2b-provider-zone/src/zone_status.rs` | Added # Errors to SystemCoreStatusEmitter::emit naming the duplicate-handler and rejected-resource Contract conditions. | | -| `RS-0716` | `docs` | `d2b-provider-zone-link` | low | actionable | leaf | applied | U2 | a0af15b8c | `packages/d2b-provider-zone-link/src/zone_links.rs` | Added # Errors to ZoneLinkLimits::new, ZoneLinkHandler::{begin,commit,release_effects,issue_route_admission}, ZoneLinkRecord::{with_route_binding,encode_route_admission_dedup,with_route_admission_dedu | | -| `RS-0718` | `docs` | `d2b-resource-api` | medium | actionable | leaf | applied | U2 | 1f9a83aee | `packages/d2b-resource-api/src/authz.rs` | authorize documented with # Errors enumerating the nine AuthorizationDenial variants; one-line contracts on take_store_seal (with Errors), CompiledRole::new, CompiledRoleBinding::new, PolicySet::new. | | -| `RS-0717` | `docs` | `d2b-resource-api` | medium | actionable | leaf | applied | U2 | 855642a90 | `packages/d2b-resource-api/src/service.rs` | # Errors sections on ResourceService::new/new_session_bound, the three frame helpers, manager_row_stored, admit_guest_lifecycle naming the failure classes. | | -| `RS-0719` | `docs` | `d2b-resource-client` | low | actionable | leaf | applied | U2 | 3c9cdc406 | `packages/d2b-resource-client/src/call.rs` | Added # Errors to MetadataInput::new, RetryPolicy::new, CallDriver::new, ZoneClient::{connect,call_connected,scoped_commit_batch}, ProcessAttachClient::attach. | | -| `RS-0720` | `docs` | `d2b-resource-runtime` | medium | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | # Errors on all 14 ResourceManagerClient pub methods | | -| `RS-0721` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | ResourceManagerArgs.store/providers documented | | -| `RS-0722` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 4cbf82851 | `manager.rs` | MODULE_NAME docs on five modules | | -| `RS-0723` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 75d64d039 | `guest_target.rs` | TargetControlAssignment five methods documented | | -| `RS-0724` | `docs` | `d2b-resource-runtime` | low | actionable | leaf | applied | U2 | 69d4b615f | `target.rs` | doc contracts on target/spec/identity accessors | | -| `RS-0725` | `docs` | `d2b-resource-types` | low | actionable | leaf | applied | U2 | 61c64bf0f | `packages/d2b-resource-types/src/operation.rs` | Restored the missing spaces after commas in the OperationCtx::fds field docs. | | -| `RS-0726` | `docs` | `d2b-session` | medium | actionable | leaf | applied | U2 | 6970c9d9e | `packages/d2b-session/src/handshake.rs` | first-sentence docs plus # Errors naming SessionErrorCode added to x25519_public_key, constants, HandshakeRole, HandshakeCredentials, NegotiatedOffer+accessors, encode_offer, negotiate_offer, generati | | -| `RS-0728` | `docs` | `d2b-session` | medium | actionable | leaf | applied | U2 | 060d34e18 | `packages/d2b-session/src/lifecycle.rs` | Added item docs with # Errors sections to the pub surface of lifecycle.rs, record.rs, bootstrap.rs, and deadline.rs (structs, enums, and all methods incl. poll_keepalive/begin_reconnect). | | -| `RS-0727` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/operation.rs` | MAX_MEMBER_SPELLING_LEN const extracted with wire-bound comment; parse uses it | | -| `RS-0729` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 217c0c66c | `packages/d2b-session/src/admission.rs` | one-line docs on route-binding accessors, SessionErrorClass::as_str, SessionError accessors, TransportPacket methods | | -| `RS-0730` | `docs` | `d2b-session` | low | actionable | leaf | applied | U2 | 6970c9d9e | `packages/d2b-session/src/transport.rs` | serialized_transport_split doc rewritten to the serialized-compatibility contract (halves must never be driven concurrently) | | -| `RS-0731` | `docs` | `d2b-session-unix` | medium | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added first-sentence contract docs to SeqpacketSocket, UnixSeqpacketTransport, UnixStreamTransport, CreditPool, PidfdEvidence, PeerCredentials, ActivatedSeqpacketListener(s), FramedVsockTransport and | | -| `RS-0732` | `docs` | `d2b-session-unix` | low | actionable | leaf | applied | U2 | 83f133d3e | `packages/d2b-session-unix/src/socket.rs` | Added # Errors to the anchor Result fns (SeqpacketSocket::from_owned/from_parent_prearmed/from_inherited_fd, UnixSeqpacketTransport::new, CreditPool::new, PidfdEvidence::new) naming their distinct fai | | -| `RS-0733` | `docs` | `d2b-telemetry` | low | actionable | leaf | applied | U2 | e1fab0e9b | `packages/d2b-telemetry/src/audit_hash.rs` | Added # Errors naming the returned variants to every named item: AuditHash::parse, AuditChainLink::verify/verify_at, all eight BoundedEmitter fns, MetricFamily/MeterRegistry, RedactionGuard, validate_ | | -| `RS-0734` | `docs` | `d2b-zone-routing` | low | actionable | leaf | applied | U2 | 20855634d | `packages/d2b-zone-routing/src/resolver.rs` | # Errors added to seal, ZoneServiceLimits::new, both with_runtime_admission sites, ZoneEnrollmentExpectation::new, ZoneEnrollmentAuthority::new/with_lifetime | | -| `RS-0736` | `docs` | `d2bd` | medium | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | serve and lock_only docs with # Errors sections; prose typos fixed | | -| `RS-0741` | `docs` | `d2bd` | medium | actionable | leaf | applied | U2 | 5bf7419ca | `packages/d2bd/src/audio_dispatch.rs` | dispatch_audio doc covering Status/SetVolume/Mute arms and TypedError::InternalIo surface | | -| `RS-0737` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 1fcaf44ee | `packages/d2bd/src/composition.rs` | StaticProviderComposition::new doc + # Errors; 'first.so' typo fixed | | -| `RS-0738` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 14efca7ef | `packages/d2bd/src/resource_plane_v3.rs` | docs on PlaneResourceRegistry::new, controller_generation field, BundleIngestReport fields | | -| `RS-0739` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 154d9e775 | `packages/d2bd/src/lib.rs` | crate-level //! doc added; comma spacing typos fixed | | -| `RS-0735` | `docs` | `d2bd` | low | actionable | leaf | applied-variant | U2 | 40237eea0 | `packages/d2bd/src/resource_runtime.rs` | reused canonical d2b_contracts_resource::v3::DEFAULT_REQUEST_DEADLINE_MS (30_000) instead of new local const; why-comment added | | -| `RS-0740` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 6389b6473,4ce0faaf8,5bf7419ca | `packages/d2bd/src/effect_service_actors.rs` | # Errors sections on call, call_expected, validate_instance, dispatch, new_persistent, admit, DaemonGuestTargetSession::request | | -| `RS-0742` | `docs` | `d2bd` | low | actionable | leaf | applied | U2 | 3220fd1ce | `packages/d2bd/src/forward_rendezvous.rs` | comment punctuation fixed (descriptors, attached, presents, attachments sentences) | | -| `RS-0743` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/json_io.rs` | resolve_bundle_artifact_path and load_manifest documented (+# Errors) | | -| `RS-0747` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c44ccbd0b | `packages/d2bd-runtime/src/unsafe_local_helper.rs` | module doc plus consts, enums, HelperRegistry struct,and its 7 pub methods documented | | -| `RS-0744` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/vm_start_support.rs` | VmStartNodeMode enum, vm_start_node_mode, tracked_role_id,and store-view resolver documented | | -| `RS-0748` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/exec_session.rs` | exec-session DTO fields documented (ExecStartSpec, ExecSessionInfo, Established, WorkerSpawn) | | -| `RS-0749` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/readiness.rs` | six readiness predicates/functions documented (+# Errors);async twin was already documented | | -| `RS-0745` | `docs` | `d2bd-runtime` | medium | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/broker_transport.rs` | 5 broker-transport helpers documented;default_audit_join_context has no panic post-wave0 (re-verified) | | -| `RS-0746` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ssh_host_key_preflight.rs` | workflow tokens dropped from doc and trace comment; 0440-with-ACL why kept | | -| `RS-0750` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/ch_api.rs` | consts with provenance, ChApiError variants, ChVmInfo fields,and both entry fns documented | | -| `RS-0751` | `docs` | `d2bd-runtime` | low | actionable | leaf | applied | U2 | c4b29ded7 | `packages/d2bd-runtime/src/target_runtime.rs` | AdmissionBudget/AdmissionPermit/ProviderDeployment accessors documented incl. release idempotence | | -| `RS-0755` | `docs` | `xtask` | medium | actionable | leaf | applied | U2 | a18cc6eb1 | `packages/xtask/src/blocking_census.rs` | Per-field doc comments added to DeniedApi, CensusBaseline.crates, OutputDigest, EvidenceRecord, SealedLane, SealedValidation, and SealRecord, naming units and serialization formats. | | -| `RS-0756` | `docs` | `xtask` | low | actionable | leaf | applied-variant | U2 | a18cc6eb1 | `packages/xtask/src/changelog.rs` | # Errors sections added to parse_fragment, EvidenceLane::parse, EvidenceRecord::validate, SealRecord::validate. scan_source returns ScanOutcome, not Result, so no Errors section applies there. | | -| `RS-0754` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | a18cc6eb1 | `packages/xtask/src/delivery/snapshot.rs` | One-line docs added to WaveSnapshot digests/program/wave, WaveCommand as_str/parse/required_options/optional_options, WorkflowOutput ok/with_digests, WorkflowCommandHelp, CliOptions accessors. | | -| `RS-0752` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | 6668d84dd | `provider_crate_policy.rs` | four doubled parens and whiche typo fixed; the audit's trailing \. doc lines do not exist at HEAD (grep zero), so that component is stale | | -| `RS-0753` | `docs` | `xtask` | low | actionable | leaf | applied | U2 | bbd40b6fd | `main.rs` | doc comments above today_utc_iso8601 and civil_from_days naming the Hinnant algorithm, constants, and epoch fallback | | -| `RS-0771` | `perf` | `d2b` | medium | actionable | leaf | applied-variant | W3 | 44cb49a0d | `context.rs:570, context.rs:538` | | | -| `RS-0757` | `perf` | `d2b-audit` | low | actionable | leaf | applied | W3 | 10923b65e | `packages/d2b-audit/src/sink.rs:386, packages/d2b-audit/src/segment.rs:970` | | | -| `RS-0762` | `perf` | `d2b-broker` | medium | actionable | wide | applied | W5 | 6488d26a4 | `packages/d2b-broker/src/protocol.rs:86, packages/d2b-broker/src/protocol.rs:125` | the broker protocol receive path peeks the 4-byte length prefix with MSG_PEEK and allocates the declared size plus the prefix; SCM_RIGHTS receipt is size-exact the same way, and sockets without MSG_PEEK keep the fixed allocation | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0759` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/nft.rs:784-790` | | | -| `RS-0760` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/ops/cgroup.rs:341, packages/d2b-broker/src/ops/cgroup.rs:368` | | | -| `RS-0758` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/state_cells.rs:470, packages/d2b-broker/src/state_cells.rs:488, packages/d2b-broker/src/state_cells.rs:524` | | | -| `RS-0761` | `perf` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/ops/store_view_posture.rs:194-271, src/ops/store_view_posture.rs:110-120, src/ops/store_view_posture.rs:310-352` | | | -| `RS-0763` | `perf` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/router.rs:4228-4235` | | | -| `RS-0764` | `perf` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/streams.rs:642-658` | | | -| `RS-0765` | `perf` | `d2b-contracts-resource` | low | actionable | leaf | applied | W3 | 395eba54d | `packages/d2b-contracts-resource/src/v3/resource_status.rs:636, packages/d2b-contracts-resource/src/v3/resource_status.rs:650` | | | -| `RS-0766` | `perf` | `d2b-contracts-zone-session` | low | actionable | leaf | applied | W3 | 5966950aa | `resource_bundle.rs:382` | | | -| `RS-0767` | `perf` | `d2b-core` | medium | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:1636, packages/d2b-core/src/bundle_resolver.rs:16` | | | -| `RS-0768` | `perf` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:3717, packages/d2b-core/src/bundle_resolver.rs:37` | | | -| `RS-0769` | `perf` | `d2b-core` | low | actionable | leaf | applied-variant | W3 | 26538ea75 | `packages/d2b-core/src/bundle_resolver.rs:1609, packages/d2b-core/src/bundle_resolver.rs:16` | | | -| `RS-0770` | `perf` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/nftables.rs:46, packages/d2b-host/src/hardlink_farm.rs:628` | | | -| `RS-0772` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/bin/d2b-clipd.rs:757, src/bin/d2b-clipd.rs:1043, src/bin/d2b-clipd.rs:1833, src/bin/d2b-clipd.rs:1838, src/bin/d2b-clipd.rs:2797` | | | -| `RS-0773` | `perf` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:140-159` | | | -| `RS-0774` | `perf` | `d2b-provider-config-nixos` | low | actionable | leaf | applied-variant | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/controller.rs:298, packages/d2b-provider-config-nixos/src/ttrpc.rs:326, packages/d2b-provider-config-nixos/src/ttrpc.rs:81` | | | -| `RS-0775` | `perf` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | W3 | a34843f8e | `src/session_children.rs:316, src/session_children.rs:317` | | | -| `RS-0776` | `perf` | `d2b-provider-guest` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-guest/src/driver.rs:863, packages/d2b-provider-guest/src/driver.rs:8` | | | -| `RS-0777` | `perf` | `d2b-provider-guest-cloud-hypervisor` | low | actionable | leaf | applied | W3 | 513edf50c | `shutdown.rs:505-513` | | | -| `RS-0778` | `perf` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | W3 | e4cbd3054 | `packages/d2b-provider-guest-qemu-media/src/controller/process_builder.rs:239` | | | -| `RS-0779` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/nftables.rs:266-268` | | | -| `RS-0780` | `perf` | `d2b-provider-network-local` | low | actionable | leaf | applied-variant | W3 | bacc017aa | `src/observe.rs:305` | | | -| `RS-0781` | `perf` | `d2b-provider-notification-desktop` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-notification-desktop/src/host_sink.rs:265, packages/d2b-provider-notification-desktop/src/host_sink.rs:276-291, packages/d2b-provider-notification-desktop/src/host_sink.rs:376, packages/d2b-provider-notification-desktop/src/host_sink.rs:484-493` | | | -| `RS-0782` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `emitter_socket.rs:139` | | | -| `RS-0783` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `ingress_policy.rs:203, ingress_policy.rs:368` | | | -| `RS-0784` | `perf` | `d2b-provider-observability-otel` | low | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:44` | | | -| `RS-0785` | `perf` | `d2b-provider-process-systemd` | low | actionable | leaf | applied | W3 | 037e23533 | `packages/d2b-provider-process-systemd/src/operations.rs:417, packages/d2b-provider-process-systemd/src/operations.rs:421` | | | -| `RS-0786` | `perf` | `d2b-provider-toolkit` | medium | actionable | family | applied | W5 | 079e80ef6 | `packages/d2b-provider-toolkit/src/shared_provider.rs:944, packages/d2b-provider-toolkit/src/shared_provider.rs:1024, packages/d2b-provider-toolkit/src/shared_provider.rs:479-481` | SharedProviderEffectRequest borrows the row's canonical spec document from the driver's spec envelope instead of cloning it into every reconcile and delete request | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0787` | `perf` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:706-714, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:629-630, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:814, packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:844` | | | -| `RS-0788` | `perf` | `d2b-provider-transport-azure-relay` | low | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/guest_credential.rs:617-618` | | | -| `RS-0789` | `perf` | `d2b-provider-volume` | low | actionable | leaf | applied | W3 | 037e23533 | `driver.rs:437-440, driver.rs:614-617` | | | -| `RS-0791` | `perf` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:1006` | | | -| `RS-0792` | `perf` | `d2b-resource-api` | medium | actionable | family | applied | W4 | 5c7fbf067 | `manager_backend.rs:1081-1103, manager_backend.rs:1090` | | | -| `RS-0793` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/authz.rs:457, packages/d2b-resource-api/src/authz.rs:458` | | | -| `RS-0790` | `perf` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `manager_backend.rs:495, manager_backend.rs:449-455` | | | -| `RS-0794` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/manager.rs:1390` | | | -| `RS-0795` | `perf` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/guest_target.rs:178, packages/d2b-resource-runtime/src/guest_target.rs:1212` | | | -| `RS-0796` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `record.rs:125, record.rs:147` | | | -| `RS-0797` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `engine.rs:1354, engine.rs:1362, scheduler.rs:72` | | | -| `RS-0798` | `perf` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `record.rs:120, record.rs:146` | | | -| `RS-0799` | `perf` | `d2b-session-unix` | low | actionable | leaf | applied | W3 | 774c148eb | `packages/d2b-session-unix/src/socket.rs:256, packages/d2b-session-unix/src/socket.rs:306, ` | | | -| `RS-0800` | `perf` | `d2bd` | medium | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/resource_runtime.rs:2360, packages/d2bd/src/resource_runtime.rs:2489, packages/d2bd/src/resource_runtime.rs:2505, packages/d2bd/src/resource_runtime.rs:2856` | | | -| `RS-0801` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/process_provider_runtime.rs:333` | | | -| `RS-0802` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/forward_rendezvous.rs:1356, packages/d2bd/src/forward_rendezvous.rs:1476` | | | -| `RS-0803` | `perf` | `d2bd` | low | actionable | leaf | applied | W3 | 9a8caf31c | `packages/d2bd/src/shared_provider_effects.rs:1014-1016, packages/d2bd/src/audio_dispatch.rs:392-396` | | | -| `RS-0804` | `perf` | `d2bd-runtime` | low | actionable | family | applied | W4 | 87c3172bc | `public_read_model.rs:117-118` | | | -| `RS-0808` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/bazel_evidence.rs:397, packages/xtask/src/bazel_evidence.rs:399, packages/xtask/src/bazel_evidence.rs:407` | | | -| `RS-0805` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:431` | | | -| `RS-0806` | `perf` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:582` | | | -| `RS-0807` | `perf` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/main.rs:972` | | | -| `RS-0960` | `conc` | `X3-cross-crate-duplication` | medium | policy-confirmed | wide | applied | W7 | 8c3c48c0c | `clippy.toml:82` | the three lock entries now name the resolved lock_api paths the parking_lot type aliases point at, so clippy finally fires on every real .lock()/.read()/.write() site; the workspace's unsuppressed sites were taken to zero by the burn-down slices (sanctioned per-site allows or tokio conversions) and the census baseline was regenerated through its own write mode (282 key renames, no count growth). blocking-census --check, check-async-gate and check-provider-crate-layout are green on the flip head; a force-warn probe proves the flipped path matches the real sites while the alias spelling matched none. Merged c31e798ce. | | -| `RS-0809` | `conc` | `d2b-broker` | low | actionable | leaf | applied | W3 | 944012b14 | `src/envelope/mod.rs:1146, src/envelope/mod.rs:2144` | | | -| `RS-0810` | `conc` | `d2b-bus` | low | actionable | leaf | applied | W7 | 50be72eea | `packages/d2b-bus/src/registry.rs:530` | RouteLeaseState.revoked is an AtomicBool with a Release store at remove and Acquire loads at with_active (weakest correct ordering; the latch is one-way), and the two synchronous-path allows are gone; the guard that used to span Operations::begin's mutation no longer serializes it. Merged 01daff2b1. | | -| `RS-0811` | `conc` | `d2b-contracts-provider` | low | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:955, packages/d2b-contracts-provider/src/v3/credential/service.rs:963, packages/d2b-contracts-provider/src/v3/credential/service.rs:977` | | | -| `RS-0812` | `conc` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `src/fd.rs:545, src/fd.rs:600, src/bin/d2b-clipd.rs:74, src/bin/d2b-clipd.rs:96` | | | -| `RS-0813` | `conc` | `d2b-provider-credential` | medium | policy-confirmed | leaf | applied | W7 | 7e194b77c | `packages/d2b-provider-credential/src/test_support.rs:97` | 27 previously unsuppressed recorder/impl lock sites now carry the sanctioned cfg(test) helper allow (19 in test_support.rs, 7 in the driver test module, 1 in session.rs); synchronous accessors stay synchronous. Merged 78db8d04d. | | -| `RS-0814` | `conc` | `d2b-provider-device-gpu` | medium | policy-confirmed | family | applied-variant | W7 | 7e194b77c | `packages/d2b-provider-device-gpu/src/effects_service.rs:310` | the three gpu_authority_leases lock sites take one sanctioned synchronous-path allow on each enclosing port fn rather than one per call; the Arc type is unchanged because the port is genuinely synchronous. Merged 78db8d04d. | | -| `RS-0815` | `conc` | `d2b-provider-device-security-key` | medium | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-device-security-key/src/relay_service.rs:129, packages/d2b-provider-device-security-key/src/relay_service.rs:281, packages/d2b-provider-device-security-key/src/relay_service.rs:489-599, packages/d2b-provider-device-security-key/src/test_support.rs:32-89` | | | -| `RS-0816` | `conc` | `d2b-provider-device-usbip` | low | policy-confirmed | leaf | applied | W7 | 7e194b77c | `packages/d2b-provider-device-usbip/src/test_support.rs:46` | five sanctioned cfg(test) helper allows cover the seven recorder lock sites; no field or type changed. Merged 78db8d04d. | | -| `RS-0817` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | family | applied | W7 | e4277787d | `packages/d2b-provider-guest/src/driver.rs:507` | GuestStatusSink is Arc>> and every write (guest effects service, d2bd resource runtime) awaits it; d2bd was the only external consumer. Merged 8c0715d2f. | | -| `RS-0818` | `conc` | `d2b-provider-guest` | medium | policy-confirmed | leaf | applied | W7 | e4277787d | `packages/d2b-provider-guest/src/test_support.rs:68` | recorders moved to the toolkit SharedLog, tokio locks with async accessors, or std::sync locks with sanctioned cfg(test) helper allows where a sync trait accessor forces it; parking_lot dropped from the crate and the async-gate inventory and policy-input closures regenerated. Merged 8c0715d2f. | | -| `RS-0819` | `conc` | `d2b-provider-process` | medium | policy-confirmed | leaf | applied | W7 | 764d87ef9 | `packages/d2b-provider-process/src/driver.rs:680` | EphemeralRuntime's two clocks are tokio::sync::Mutex and all six accessors are async, awaited by every call site; the crate's remaining unsuppressed sites are test-only state under sanctioned cfg(test) helper allows, taking the crate's post-flip census to 0. Merged 849f2974b. | | -| `RS-0820` | `conc` | `d2b-provider-process` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-process/src/driver.rs:438, packages/d2b-provider-process/src/driver.rs:451, packages/d2b-provider-process/src/driver.rs:458, packages/d2b-provider-process/src/driver.rs:462` | | | -| `RS-0821` | `conc` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:43, src/testing.rs:79` | | | -| `RS-0822` | `conc` | `d2b-provider-toolkit` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-toolkit/src/operations/envelope.rs:487` | | | -| `RS-0823` | `conc` | `d2b-provider-transport-unix` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-transport-unix/src/portal.rs:18` | | | -| `RS-0824` | `conc` | `d2b-provider-user` | medium | policy-confirmed | leaf | applied | W7 | 89961f9d9 | `packages/d2b-provider-user/src/test_support.rs:47` | the five recorder/fake fields are tokio::sync::Mutex with the host-sibling accessor split (11 awaited locks, 7 sync try_locks), 18 lock sites converted, parking_lot dropped from the crate, and the async-gate inventory entries rewritten through its write mode. Merged 47ba61aec. | | -| `RS-0825` | `conc` | `d2b-provider-user` | low | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/test_support.rs:77, packages/d2b-provider-user/src/test_support.rs:135, packages/d2b-provider-user/src/test_support.rs:140, packages/d2b-provider-user/src/test_support.rs:152, packages/d2b-provider-user/src/test_support.rs:155, packages/d2b-provider-user/src/driver.rs:854` | | | -| `RS-0826` | `conc` | `d2b-provider-volume-binding` | low | actionable | leaf | applied | W3 | 06d6376af | `packages/d2b-provider-volume-binding/Cargo.toml:29-31, packages/d2b-provider-volume-binding/src/test_support.rs:17, packages/d2b-provider-volume-binding/src/driver.rs:1139-1142, clippy.toml:82` | | | -| `RS-0827` | `conc` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/zone_client.rs:510, packages/d2b-resource-client/src/zone_client.rs:512, packages/d2b-resource-client/src/zone_client.rs:513, packages/d2b-resource-client/src/process_attach.rs:409, packages/d2b-resource-client/src/process_attach.rs:412` | | | -| `RS-0828` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/resource.rs:247` | | | -| `RS-0829` | `conc` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/Cargo.toml:33, packages/d2b-resource-runtime/src/context.rs:` | | | -| `RS-0830` | `conc` | `d2b-session` | low | actionable | leaf | applied | W3 | a11baf0f9 | `admission.rs:756, admission.rs:1666, driver.rs:33` | | | -| `RS-0831` | `conc` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/protocol.rs:166, packages/d2b-unsafe-local-helper/src/protocol.rs:167, packages/d2b-unsafe-local-helper/src/protocol.rs:195` | | | -| `RS-0832` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/effect_service_actors.rs:174, packages/d2bd/src/effect_service_actors.rs` | | | -| `RS-0833` | `conc` | `d2bd` | low | actionable | leaf | applied | W3 | f6b8e60e6 | `packages/d2bd/src/forward_rendezvous.rs:332, packages/d2bd/src/forward_rendezvous.rs:414` | | | -| `RS-0835` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | W7 | 04cf64c5d | `packages/d2bd-runtime/src/unsafe_local_helper.rs:26` | the four registry/connection/ledger fields are tokio::sync::Mutex and all 39 lock sites reach the tokio seat, through a lock_registry dual seat (blocking_lock off-runtime, bounded try-lock spin on the in-runtime --once path where plain blocking_lock panics) - the panic was reproduced in d2bd's bundle_tampered_envelope test with the plain seat. Merged e65d4954e. | | -| `RS-0836` | `conc` | `d2bd-runtime` | medium | policy-confirmed | leaf | applied-variant | W7 | 04cf64c5d | `packages/d2bd-runtime/src/concurrency.rs:163` | OpLockManager::acquire's four try_lock+spin_loop loops are replaced by blocking seats for the production d2b-conn handler threads (a contended op parks instead of burning a core), with the bounded spin kept only on the in-runtime --once path where the blocking seats panic; the stale spin doc is deleted and the dual-seat ordering recorded. Merged e65d4954e. | | -| `RS-0834` | `conc` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `resource_runtime_support.rs:158, resource_runtime_support.rs:162, resource_runtime_support.rs:166, resource_runtime_support.rs:170, resource_runtime_support.rs:175-178` | | | -| `RS-0837` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | 9b64eaa27 | `packages/d2b-broker/src/runtime.rs:11801` (targeted_reap_runner; called from kernel_ops.rs:916 and :977) | bounded WNOHANG reap poll replaces the blocking waitid; orphaned helpers deleted | | -| `RS-0841` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | 25dfa3aee | packages/d2b-broker/src/sys.rs, packages/d2b-broker/src/ops/swtpm_dir.rs | setfacl shellout moved behind an async wrapper on a bounded worker | | -| `RS-0842` | `async` | `d2b-broker` | high | actionable | wide | applied | U1 | a6d8fb022 | packages/d2b-broker/src/ops/media.rs | nss group lookup hoisted to a LazyLock, off the per-write path | | -| `RS-0840` | `async` | `d2b-broker` | high | actionable | leaf | applied | U1 | f4f09c74c | packages/d2b-broker/src/ops/host_generation_handoff.rs | flock wait moved to a bounded worker (sanctioned allow reason) | | -| `RS-0839` | `async` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 944012b14 | `packages/d2b-broker/src/live_handlers.rs:1614, packages/d2b-broker/src/live_handlers.rs:18` | | | -| `RS-0838` | `async` | `d2b-broker` | medium | policy-confirmed | wide | applied | W7 | 1f8e52a5f | `packages/d2b-broker/src/runtime.rs:7711` | the whole USB-audit serial HMAC keyring body hops onto the d2b-core bounded loader probe seat, so no blocking stat/mkdir/open/create/fchmod/fsync runs on an executor worker; every hardening check is preserved verbatim (0o700 root-owned dir, O_NOFOLLOW plus O_CLOEXEC open, descriptor-level root-only validation, dir-fd openat create with 0o400 and file+dir fsync) and the existing keyring test passes unchanged. The whole-body hop was chosen over tokio::fs legs because path_safe's openat-on-dir_fd chain has no path-based equivalent. Merged d9a91015a. | | -| `RS-0843` | `async` | `d2b-process-conformance` | low | actionable | family | applied | W5 | 78a4df5be | `packages/d2b-process-conformance/src/port.rs:99, packages/d2b-process-conformance/src/port.rs:109` | ProcessLaunchEffectPort and ProcessProvider declare their methods as `async fn` (the RPITIT `impl Future + Send` form is retired) under the house `#[allow(async_fn_in_trait)]` that the pinned lint configuration requires; default bodies are plain async blocks, implementors and the single Send-bound caller keep working, and the bazel graphs re-point consumer test targets at the test-support variants so each crate keeps one instance | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0844` | `async` | `d2b-provider` | medium | actionable | leaf | applied | W3 | 7de088b5d | `packages/d2b-provider/src/agent.rs:316-324` | | | -| `RS-0845` | `async` | `d2b-provider-credential-secret-service` | medium | actionable | leaf | applied | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/src/lib.rs:1323, packages/d2b-provider-credential-secret-service/src/lib.rs:1341, packages/d2b-provider-credential-secret-service/src/lib.rs:1380` | | | -| `RS-0846` | `async` | `d2b-provider-device-tpm` | medium | actionable | family | applied | W5 | 7a971ec0b | `effects_service.rs:412, effects_service.rs:467, effects_service.rs:518, effects_service.rs` | the TPM prepare-state kernel round trip runs on the bounded kernel seat and the NSS lookups on the bounded loader worker instead of the executor worker; spawn_blocking is deny-listed by clippy.toml and banned by plan KD2 (2026-09-16-001), so the sanctioned bounded seats carry the work, the timeout and error mapping are byte-preserved, and the crate's async-gate inventory entries are refreshed for the line shift | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0847` | `async` | `d2b-provider-device-tpm` | low | actionable | leaf | applied | W3 | 7de088b5d | `effects_service.rs:361, effects_service.rs:384, effects_service.rs:698` | | | -| `RS-0848` | `async` | `d2b-provider-network-local` | low | actionable | leaf | applied | W3 | bacc017aa | `src/observe.rs:255-260` | | | -| `RS-0849` | `async` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `src/testing.rs:30, src/testing.rs:19` | | | -| `RS-0850` | `async` | `d2b-provider-transport-azure-relay` | medium | actionable | leaf | applied | W3 | 652dc86a7 | `packages/d2b-provider-transport-azure-relay/src/relay_transport.rs:823-833` | | | -| `RS-0851` | `async` | `d2b-provider-user` | high | policy-confirmed | leaf | applied | W7 | 89961f9d9 | `packages/d2b-provider-user/src/probe.rs:48` | the three blocking NSS reads now run on the d2b-core bounded loader probe seat (run_probe: one thread, bounded sync_channel admission, oneshot reply); a seat refusal maps to SystemCoreError::DiscoveryUnavailable with a structured warning, the whole blocking body (identity digest and bindings) is built on the worker, and a throwaway smoke test resolved the real NSS root through the seat. Cargo.toml/BUILD.bazel gained the d2b-core dep and the policy-input closures were regenerated. Merged 47ba61aec. | | -| `RS-0852` | `async` | `d2b-zone-routing` | medium | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/serving.rs:195, packages/d2b-zone-routing/src/serving.rs:207` | | | -| `RS-0853` | `async` | `d2bd` | medium | actionable | leaf | applied | W7 | 6e8f34406 | `packages/d2bd/src/interaction_composition.rs:5546` | InteractionRuntimeSet holds per-Zone Arc handles; the daemon-global lock is taken only to clone the handle and released before the Zone lock, so no global guard spans the dispatch await. The residual note is deleted and a named concurrency test proves two Zones' sessions no longer serialize. Merged fffe5afee. | | -| `RS-0854` | `async` | `d2bd` | medium | actionable | leaf | applied | W7 | 6e8f34406 | `packages/d2bd/src/shared_provider_effects.rs:354` | runtime()/plane() are async seats awaiting the plane slot (13 call sites) and the two sync GPU authority seats use a fail-closed try_runtime() per the TPM precedent; NetworkRuntime::bundle is async across both impls and the caller, so both try_lock+spin loops are gone; the async-gate inventory was regenerated. Merged fffe5afee. | | -| `RS-0855` | `async` | `d2bd-runtime` | low | actionable | family | applied-variant | W4 | 87c3172bc | `packages/d2bd-runtime/src/console_session.rs:33, packages/d2bd-runtime/src/console_session.rs:35` | applied-variant: drainer tasks spawn on the daemon's own tokio runtime handle instead of a new dedicated runtime (audit-sanctioned) | | -| `RS-0858` | `unsafe` | `d2b-broker` | medium | actionable | leaf | applied | W3 | 406f13d98 | `packages/d2b-broker/src/sys.rs:593, packages/d2b-broker/src/sys.rs:615, packages/d2b-broker/src/sys.rs:630, packages/d2b-broker/src/sys.rs:653, packages/d2b-broker/src/sys.rs:676, packages/d2b-broker/src/sys.rs:685, packages/d2b-broker/src/sys.rs:697, packages/d2b-broker/src/sys.rs:2109, packages/d2b-broker/src/sys.rs:2591, packages/d2b-broker/src/sys.rs:2630, packages/d2b-broker/src/sys.rs:2670, packages/d2b-broker/src/sys.rs:2694` | | | -| `RS-0857` | `unsafe` | `d2b-broker` | low | actionable | leaf | skipped-stale | W3 | 406f13d98 | `packages/d2b-broker/src/ops/disk_init.rs:673, packages/d2b-broker/src/ops/disk_init.rs:661` | The row's premise does not hold at the pinned versions: `pre_exec` is an `unsafe` method on tokio 1.53.1's `Process` (Cargo.lock:4472) and on `std::process::Command`, so the unsafe block at packages/d2b-broker/src/ops/disk_init.rs:674 cannot be removed. [reconstructed: verified from the code and the lockfile; the wave-3 close artifact carries the original reasoning at lines 15 and 92.] | | -| `RS-0856` | `unsafe` | `d2b-broker-fixture-syscall-surface` | medium | actionable | leaf | applied | W3 | 3886cfd7b | `packages/d2b-broker-fixture-syscall-surface/src/lib.rs:25-32` | | | -| `RS-0859` | `unsafe` | `d2b-host-activation-helper` | medium | actionable | leaf | applied | W3 | 3f4a63bc8 | `packages/d2b-host-activation-helper/src/main.rs:96, packages/d2b-host-activation-helper/src/main.rs:129, packages/d2b-host-activation-helper/src/main.rs:140, packages/d2b-host-activation-helper/src/main.rs:194, packages/d2b-host-activation-helper/src/main.rs:213, packages/d2b-host-activation-helper/src/main.rs:271` | | | -| `RS-0860` | `macro` | `d2b-provider-display-wayland` | low | actionable | leaf | applied | W3 | a34843f8e | `packages/d2b-provider-display-wayland/src/wayland_proxy/policy.rs:420` | | | -| `RS-0861` | `macro` | `d2b-resource-api` | low | actionable | leaf | applied-variant | W3 | 81b2ef867 | `service.rs:2245-2267` | | | -| `RS-0862` | `macro` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `admission.rs:625, admission.rs:641, admission.rs:642, admission.rs:643` | | | -| `RS-0863` | `macro` | `xtask` | low | actionable | leaf | applied-variant | W3 | 4d6f66bbb | `packages/xtask/src/changelog.rs:812, packages/xtask/src/changelog.rs:886, packages/xtask/src/changelog.rs:1019` | | | -| `RS-0958` | `test` | `X3-cross-crate-duplication` | medium | actionable | family | applied | W4 | 776ddb336 | `packages/d2b-provider-credential/src/test_support.rs:18, packages/d2b-provider-guest/src/test_support.rs` | | | -| `RS-0959` | `test` | `X3-cross-crate-duplication` | low | actionable | family | applied-variant | W4 | 6b9084957 | `packages/d2b-provider-quota/Cargo.toml:17, packages/d2b-provider-resource-export/Cargo.toml:17` | applied-variant: feature wired to the registration integration test via [[test]] required-features (house pattern d2b-provider-host/Cargo.toml:28) instead of a #[cfg(feature)] module - the crates have no test-support module and BUILD.bazel *_test_support targets consume the feature | | -| `RS-0880` | `test` | `d2b` | medium | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:227-239` | | | -| `RS-0881` | `test` | `d2b` | low | actionable | leaf | applied | W3 | 44cb49a0d | `packages/d2b/src/exec.rs:383-397` | | | -| `RS-0866` | `test` | `d2b-broker` | low | actionable | leaf | applied | W3 | b80491dde | `packages/d2b-broker/tests/pidfd_handoff_scm_rights.rs:90` | | | -| `RS-0864` | `test` | `d2b-broker-composition` | low | actionable | leaf | applied | W3 | fbcf5d1f5 | `packages/d2b-broker-composition/src/seam.rs:523` | | | -| `RS-0865` | `test` | `d2b-broker-composition` | low | actionable | leaf | applied | W3 | fbcf5d1f5 | `packages/d2b-broker-composition/src/seam.rs:731, packages/d2b-broker-composition/src/seam.rs:733` | | | -| `RS-0867` | `test` | `d2b-bus` | high | actionable | leaf | applied | U1 | 01e8edab3 | packages/d2b-bus/src/metrics.rs | test now drives BusMetrics::emit over every closed label domain; mutation-verified | | -| `RS-0868` | `test` | `d2b-bus` | medium | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/session_seam_tests.rs:1623-1625, packages/d2b-bus/src/session_seam_tests.rs:1808-1810, packages/d2b-bus/src/session_seam_tests.rs:1882-1884, packages/d2b-bus/src/session_seam_tests.rs:1941-1960` | | | -| `RS-0869` | `test` | `d2b-bus` | low | actionable | leaf | applied | W3 | 5f1fcd6f1 | `packages/d2b-bus/src/operations.rs:1057-1060` | | | -| `RS-0870` | `test` | `d2b-contracts-control` | medium | actionable | leaf | applied | W3 | 1ff8e6a8c | `public_wire.rs:167, public_wire.rs:175` | | | -| `RS-0871` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential/service.rs:1071, packages/d2b-contracts-provider/src/v3/credential/service.rs:1393, packages/d2b-contracts-provider/src/v3/credential/service.rs:1296` | | | -| `RS-0872` | `test` | `d2b-contracts-provider` | medium | actionable | leaf | applied | W3 | 3b2c1416b | `packages/d2b-contracts-provider/src/v3/credential_controller.rs:691, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1346, packages/d2b-contracts-provider/src/v3/credential_controller.rs:499, packages/d2b-contracts-provider/src/v3/credential_controller.rs:1084` | | | -| `RS-0873` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | W3 | 5966950aa | `packages/d2b-contracts-zone-session/src/v3/component_session.rs:2445, packages/d2b-contracts-zone-session/src/v3/component_session.rs:1829` | | | -| `RS-0874` | `test` | `d2b-contracts-zone-session` | medium | actionable | leaf | applied | W3 | 5966950aa | `emergency_policy.rs:236, emergency_policy.rs:112` | | | -| `RS-0877` | `test` | `d2b-core` | low | actionable | leaf | applied | W3 | 26538ea75 | `packages/d2b-core/tests/bundle_resolver_tamper.rs:149` | | | -| `RS-0875` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority.rs:1824, authority.rs:1968, authority.rs:1899` | | | -| `RS-0876` | `test` | `d2b-core-controller` | medium | actionable | leaf | applied | W3 | 716eaef89 | `authority_persistence.rs:246-320` | | | -| `RS-0878` | `test` | `d2b-host` | medium | actionable | family | applied | W4 | 00aa87923 | `packages/d2b-host/src/nftables.rs:245` | | | -| `RS-0879` | `test` | `d2b-host` | low | actionable | leaf | applied | W3 | 1abe4f9b3 | `packages/d2b-host/src/bin/d2b-activation-helper.rs:792` | | | -| `RS-0882` | `test` | `d2b-provider-activation-nixos` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-activation-nixos/tests/reconcile.rs:439, packages/d2b-provider-activation-nixos/tests/reconcile.rs:447` | | | -| `RS-0883` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/authority.rs:26-31, src/authority.rs:236-241` | | | -| `RS-0884` | `test` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/mediator.rs:13-24` | | | -| `RS-0885` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | W3 | d5ab66ec5 | `src/bin/d2b-clipd.rs:4021, src/bin/d2b-clipd.rs:3787` | | | -| `RS-0886` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/history.rs:150-172, packages/d2b-provider-clipboard-wayland/src/history.rs:345-356, packages/d2b-provider-clipboard-wayland/src/history.rs:257-273` | | | -| `RS-0887` | `test` | `d2b-provider-clipboard-wayland` | medium | actionable | leaf | applied-variant | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:85-141, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:144-201, packages/d2b-provider-clipboard-wayland/src/controller/mod.rs:360-371` | | | -| `RS-0888` | `test` | `d2b-provider-clipboard-wayland` | low | actionable | leaf | applied | W3 | d5ab66ec5 | `packages/d2b-provider-clipboard-wayland/src/clipd_host/fallback.rs:78-83, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:378-387, packages/d2b-provider-clipboard-wayland/src/clipd_host/niri.rs:394` | | | -| `RS-0889` | `test` | `d2b-provider-config-nixos` | medium | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:70-90, packages/d2b-provider-config-nixos/tests/config_lifecycle.rs:8-18` | | | -| `RS-0890` | `test` | `d2b-provider-config-nixos` | low | actionable | leaf | applied | W3 | 1da992306 | `packages/d2b-provider-config-nixos/src/service.rs:20-21, packages/d2b-provider-config-nixos/tests/service_contract.rs:41-79` | | | -| `RS-0891` | `test` | `d2b-provider-credential-entra` | low | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-credential-entra/src/lib.rs:1361, packages/d2b-provider-credential-entra/src/lib.rs:1362` | | | -| `RS-0892` | `test` | `d2b-provider-credential-managed-identity` | low | actionable | leaf | applied | W3 | a4dd46ddc | `tests/conformance.rs:77-82, tests/topology.rs:33-38, tests/topology.rs:68-76` | | | -| `RS-0893` | `test` | `d2b-provider-credential-secret-service` | low | actionable | leaf | already-fixed | W3 | 868fbdbf8 | `packages/d2b-provider-credential-secret-service/tests/faults.rs:25, packages/d2b-provider-credential-secret-service/tests/placement.rs:8, packages/d2b-provider-credential-secret-service/src/lib.rs:1966` | | | -| `RS-0894` | `test` | `d2b-provider-device-gpu` | medium | actionable | leaf | applied | W3 | 563820766 | `packages/d2b-provider-device-gpu/src/authority.rs:168, packages/d2b-provider-device-gpu/tests/authority_lifecycle.rs` | | | -| `RS-0896` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | W3 | b373f7624 | `tests/arbitration_conflict.rs:8-19, src/arbitration.rs:81-84, src/arbitration.rs:113-115, ` | | | -| `RS-0897` | `test` | `d2b-provider-device-usbip` | medium | actionable | leaf | applied | W3 | b373f7624 | `src/reconcile_state.rs:51-308, src/state_machine.rs:98-100` | | | -| `RS-0895` | `test` | `d2b-provider-device-usbip` | low | actionable | leaf | applied | W3 | b373f7624 | `tests/conformance.rs:63-66` | | | -| `RS-0898` | `test` | `d2b-provider-display-wayland` | high | actionable | leaf | applied | U1 | 3b964169f | packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs | registry-handler tests assert advertised-global outcomes; mutation-verified | | -| `RS-0900` | `test` | `d2b-provider-guest-azure-container-apps` | medium | actionable | leaf | applied | W3 | 52f5ef660 | `src/controller.rs:264-266, tests/provider_lifecycle.rs:210-225` | | | -| `RS-0899` | `test` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W3 | 52f5ef660 | `tests/provider_lifecycle.rs:536` | | | -| `RS-0901` | `test` | `d2b-provider-guest-azure-virtual-machine` | low | actionable | leaf | applied | W3 | 563820766 | `tests/error_redaction.rs:17` | | | -| `RS-0902` | `test` | `d2b-provider-guest-cloud-hypervisor` | medium | actionable | leaf | already-fixed | W3 | 513edf50c | `finalize_ordering_test.rs:286` | | | -| `RS-0903` | `test` | `d2b-provider-guest-qemu-media` | low | actionable | leaf | applied | W3 | e4cbd3054 | `packages/d2b-provider-guest-qemu-media/tests/lifecycle.rs:132, packages/d2b-provider-guest-qemu-media/src/controller/device_watch.rs` | | | -| `RS-0904` | `test` | `d2b-provider-observability-otel` | medium | actionable | leaf | applied | W3 | 1200b480d | `metric_policy.rs:145, metric_policy.rs:150` | | | -| `RS-0905` | `test` | `d2b-provider-provider` | medium | actionable | leaf | applied | W3 | 55b7d20a6 | `src/providers.rs:206, src/driver.rs:1147` | | | -| `RS-0906` | `test` | `d2b-provider-shell-terminal` | low | actionable | leaf | applied-variant | W3 | 55b7d20a6 | `packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:17, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:81, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:142, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:193, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:255, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:320, packages/d2b-provider-shell-terminal/tests/supervisor_runtime.rs:367` | | | -| `RS-0907` | `test` | `d2b-provider-supervisor` | low | policy-confirmed | leaf | applied | W7 | 814ad86b6 | `packages/d2b-provider-supervisor/src/broker.rs:2012` | the source scrape and its literal name list are gone: PIDFD_DISPATCH_FAILURE_KINDS is a shared const in d2b-contracts-broker, LiveHandlerError maps its variants through it, and the supervisor test asserts against the constant with every behavior assertion kept. Merged f2b98ccfb. | | -| `RS-0908` | `test` | `d2b-provider-system-core` | low | actionable | leaf | applied | W3 | e807e4596 | `tests/host_reconciliation.rs:204, tests/host_reconciliation.rs:230` | | | -| `RS-0909` | `test` | `d2b-provider-transport-vsock` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-transport-vsock/tests/observe.rs:14-15` | | | -| `RS-0910` | `test` | `d2b-provider-user` | medium | actionable | leaf | applied | W3 | 928b982ce | `packages/d2b-provider-user/src/driver.rs:789-848, packages/d2b-provider-user/src/driver.rs` | | | -| `RS-0911` | `test` | `d2b-provider-wayland-policy` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-wayland-policy/tests/registration.rs:93` | | | -| `RS-0912` | `test` | `d2b-provider-zone-link` | low | actionable | leaf | applied | W3 | 55b7d20a6 | `packages/d2b-provider-zone-link/src/zone_links.rs:2519, packages/d2b-provider-zone-link/src/zone_links.rs:3093, packages/d2b-provider-zone-link/src/zone_links.rs:3162` | | | -| `RS-0914` | `test` | `d2b-resource-api` | medium | actionable | leaf | applied | W3 | 81b2ef867 | `packages/d2b-resource-api/src/manager_backend/tests.rs:1459, packages/d2b-resource-api/src/manager_backend/tests.rs:1460, packages/d2b-resource-api/src/manager_backend/tests.rs:1461` | | | -| `RS-0913` | `test` | `d2b-resource-api` | low | actionable | leaf | applied | W3 | 81b2ef867 | `service.rs:3377` | | | -| `RS-0915` | `test` | `d2b-resource-client` | low | actionable | leaf | applied | W3 | 5a334adb2 | `packages/d2b-resource-client/src/process_attach.rs:515, packages/d2b-resource-client/src/process_attach.rs:541, packages/d2b-resource-client/src/zone_client.rs:567` | | | -| `RS-0916` | `test` | `d2b-resource-runtime` | high | actionable | leaf | applied-variant | U1 | 8b191fe39 | `packages/d2b-resource-runtime/src/revision.rs:157, packages/d2b-resource-runtime/src/revision.rs:71` | claim corrected: the committed line was a tautological bare-epoch assertion (not an assertion that cannot pass); the audit's quoted literal is a tool-output redaction artifact, absent from the file and from git history; the row's own fix text applied by deleting the redundant assertion | | -| `RS-0917` | `test` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/revision.rs:182` | | | -| `RS-0918` | `test` | `d2b-resource-runtime` | low | actionable | leaf | applied | W3 | a8b710719 | `packages/d2b-resource-runtime/src/lib.rs:66` | | | -| `RS-0919` | `test` | `d2b-session` | low | actionable | leaf | applied | W3 | d38e32fc6 | `tests/admission.rs:78, tests/admission.rs:96, tests/admission.rs:139` | | | -| `RS-0920` | `test` | `d2b-sk-frontend` | medium | actionable | leaf | applied | W3 | a094121e5 | `packages/d2b-sk-frontend/src/uhid.rs:175, packages/d2b-sk-frontend/src/uhid.rs:186` | | | -| `RS-0921` | `test` | `d2b-telemetry` | low | actionable | leaf | applied | W3 | cc1a4dbd9 | `packages/d2b-telemetry/src/meter_registry.rs:176-180` | | | -| `RS-0922` | `test` | `d2b-unsafe-local-helper` | low | actionable | leaf | applied | W3 | 840c1edbe | `packages/d2b-unsafe-local-helper/src/runtime.rs:1566-1576, packages/d2b-unsafe-local-helper/src/runtime.rs:505-508` | | | -| `RS-0923` | `test` | `d2b-zone-routing` | low | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/engine.rs:3333` | | | -| `RS-0924` | `test` | `d2b-zone-routing` | low | actionable | leaf | applied | W3 | 113fdf93d | `packages/d2b-zone-routing/src/router.rs:517` | | | -| `RS-0925` | `test` | `d2bd-runtime` | high | actionable | leaf | applied | U1 | bea8fa96d | packages/d2bd-runtime/src/runtime_process.rs | sd_notify tests assert observable tracing outcomes; two mutations verified | | -| `RS-0926` | `test` | `d2bd-runtime` | low | actionable | leaf | applied | W3 | a9a44bfdd | `packages/d2bd-runtime/src/daemon_audit.rs:2367` | | | -| `RS-0928` | `test` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/delivery/command.rs:1059, packages/xtask/src/delivery/command.rs:1079` | | | -| `RS-0927` | `test` | `xtask` | low | actionable | leaf | applied | W3 | 4d6f66bbb | `packages/xtask/src/gen_layer_catalogs.rs:705` | | | -| `RS-0933` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 0b5f937fe | `packages/d2b-session/Cargo.toml:17, packages/d2b-session/BUILD.bazel:28` | | | -| `RS-0934` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 0b5f937fe | `packages/d2b-session/Cargo.toml:19, packages/d2b-session/BUILD.bazel:31` | | | -| `RS-0935` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 0b5f937fe | `packages/d2b-session/Cargo.toml:44` | | | -| `RS-0936` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b-telemetry/Cargo.toml:14` | | | -| `RS-0937` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-quota/Cargo.toml:24` | | | -| `RS-0938` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b-bus/Cargo.toml:41` | | | -| `RS-0939` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `packages/d2b-provider-activation-nixos/Cargo.toml:35` | | | -| `RS-0940` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `packages/d2b-provider-audio-pipewire/Cargo.toml:25` | | | -| `RS-0941` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 1e9b43ee6 | `packages/d2b-provider-guest-azure-container-apps/Cargo.toml:21` | | | -| `RS-0942` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | -| `RS-0943` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:25, packages/d2b-provider-device-gpu/BUILD.bazel:39` | | | -| `RS-0944` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | aacd4defb | `packages/d2b/Cargo.toml:23, packages/d2b/BUILD.bazel:55` | | | -| `RS-0946` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2, packages/d2b-broker/Cargo.toml:53, packages/d2bd-runtime/Cargo.toml:33` | the nix 0.26.4/0.31.3 transitive legs are recorded as accepted clusters with pullers and a re-check trigger in deny.toml [bans]; the workspace pin stays at 0.29 | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0947` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:202, deny.toml:2` | the rustix 0.38/1.1 legs are recorded as an accepted cluster with a re-check trigger in deny.toml [bans] | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0948` | `supply` | `X1-supply-chain` | medium | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-transport-azure-relay/Cargo.toml:34, packages/d2b-provider-transport-azure-relay/Cargo.toml:36` | | | -| `RS-0950` | `supply` | `X1-supply-chain` | medium | actionable | wide | applied-variant | W5 | 78b5c5672 | `packages/Cargo.guest.lock:1, flake.nix:389` | a lock-drift check compares shared-crate versions across Cargo.lock and packages/Cargo.guest.lock and records the 39 lags; deviation: the one-snapshot aligned regen stays at the next dependency refresh, which is where the row's own fix text scopes it (regen needs the container lane) | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0945` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `Cargo.toml:184-229, packages/d2b-broker/Cargo.toml:60, packages/d2b-broker/Cargo.toml:63, ` | 13 member decls across 10 crates inherit rustix and sha2 from workspace.dependencies instead of literal pins; the resolved versions and both lockfiles are unchanged | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0949` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:2` | the 31 transitive-only duplicate clusters are inventoried in deny.toml [bans] with versions, pullers, and re-check triggers; multiple-versions stays warn because the workspace-direct clusters do not resolve | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0951` | `supply` | `X1-supply-chain` | low | actionable | wide | applied | W5 | 78b5c5672 | `deny.toml:21` | deny.toml licence confidence-threshold is raised from 0.8 to 0.9 and any failing allow-listed licence moved to a per-crate [licenses.exceptions] entry with its reason | escalated W3 -> W5 (deferred to waves 4-5 by blast radius) | -| `RS-0929` | `supply` | `d2b-provider-audio-pipewire` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:24, Cargo.toml:25` | | | -| `RS-0930` | `supply` | `d2b-provider-device-gpu` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-device-gpu/Cargo.toml:20` | | | -| `RS-0931` | `supply` | `d2b-provider-guest-azure-container-apps` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `Cargo.toml:21` | | | -| `RS-0932` | `supply` | `d2b-provider-quota` | low | actionable | leaf | applied | W3 | 9c20c2cdf | `packages/d2b-provider-quota/Cargo.toml:24` | | | diff --git a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md index b86584fe7..2fbc9e22a 100644 --- a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md +++ b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md @@ -5,7 +5,6 @@ execution: code title: Rust skills audit remediation - Plan type: refactor date: 2026-09-24 -origin: docs/audits/2026-09-24-rust-skills-audit/README.md --- # Rust skills audit remediation - Plan @@ -149,7 +148,7 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha - **Goal:** the unit of record is tracked, the gate baseline is recorded, and the correctness-first rows are fixed (or, for the one policy-confirmed row, recorded) so the first wave gate reads as evidence. - **Requirements:** R2, R3, R5, R10; KTD4. - **Dependencies:** none. -- **Files:** `docs/audits/2026-09-24-rust-skills-audit/` (report, `U1-constraints.md`, `lane/`, `VERIFICATION.md`, plus the new ledger), `changelog.d/`, and the finding sites - `packages/d2b-resource-runtime/src/revision.rs`, `packages/d2bd-runtime/src/runtime_process.rs`, `packages/d2b-broker/src/runtime.rs`, `packages/d2b-broker/src/ops/kernel_ops.rs`, `packages/d2b-broker/src/ops/sys.rs`, `packages/d2b-bus/src/` (telemetry test), `packages/d2b-provider-display-wayland/src/filter.rs`, `packages/d2b-provider-wayland-policy/src/` (applied), `packages/d2b-provider-user/src/` (record-only, no code change). +- **Files:** `changelog.d/`, and the finding sites - `packages/d2b-resource-runtime/src/revision.rs`, `packages/d2bd-runtime/src/runtime_process.rs`, `packages/d2b-broker/src/runtime.rs`, `packages/d2b-broker/src/ops/kernel_ops.rs`, `packages/d2b-broker/src/ops/sys.rs`, `packages/d2b-bus/src/` (telemetry test), `packages/d2b-provider-display-wayland/src/filter.rs`, `packages/d2b-provider-wayland-policy/src/` (applied), `packages/d2b-provider-user/src/` (record-only, no code change). - **Approach:** 1. Commit the audit corpus and create the ledger with this row schema: finding id, lens, cluster, audit verdict, outcome, apply-time anchor, wave, commit, reason or policy citation, escalation history, and - for an escalated row - the final outcome recorded when the owning wave applies it (KTD1, R8). 2. Record the baseline: run the KTD3 gate set at the untouched head and write the result - pass or fail per gate, with every pre-existing failure attributed. Any additional pre-existing failure inside the audit's crates is fixed here when it blocks the gate and otherwise recorded as baseline-attributed and deferred. @@ -346,7 +345,6 @@ Counts are the audit's own cluster membership (`README.md` section 6); each wave ### Sources -- Audit report, lane files, lane contract, and independent verification: `docs/audits/2026-09-24-rust-skills-audit/` (report sections 2, 6, 7 are the finding corpus, the cluster map, and the verification record). - Gate authority: `Makefile`, `docs/contributing/gates-and-lints.md`, `tests/AGENTS.md`, `.github/workflows/pr-l1-static-fast.yml`. - Policy surfaces that fail closed: `Cargo.toml` (`disallowed_methods` is live `deny`; the `clippy.toml` comment claiming `allow` is stale), `clippy.toml`, `packages/xtask/data/async-gate-inventory.json`, `packages/xtask/data/blocking-census-baseline.json`, `packages/xtask/src/provider_crate_policy.rs`, `docs/explanation/over-engineering-audit-record.md`. - Landing lifecycle: `docs/contributing/workflow.md` (worktrees, reviewed-head lifecycle, security scan gate), `docs/contributing/changelog-and-commits.md`, `changelog.d/README.md`. From 1e7f9e8fa1de27a270afec486e2df800c4674bc0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 02:09:22 -0700 Subject: [PATCH 708/726] docs: correct the plan and prose the audit-record removal invalidated The removal of the rust-skills audit record left four sentences in the repository asserting a record that is no longer there, and the review bound to that removal's head named them. The plan's R8 and R9 and two of its Definition-of-Done lines still said the audit report, the lane files, and the ledger ship in the tree, and that finding identifiers live "only inside the audit directory". They do not ship. The plan now says the record is working material for the remediation, that the gate set and the changelog fragments are the record that does, and that no finding identifier reached the shipped tree - which is the property the original rule was protecting, stated over the tree that actually exists. Two released-prose defects the same review named are fixed here. The migration guide promised a v1.1.2 wire schema by naming a type this branch deleted, so it now describes the V3 shape as the rename map applied to V2 rather than naming something a reader cannot find. A changelog fragment carried a one-space continuation line and a column-0 orphan that the fold copies verbatim, and misspelled the crate it edits; its two entries are now two well-formed bullets. That same fragment still named an internal wave in text bound for the release notes, which the contributing guide forbids, and the earlier repair had already edited the first clause of that line and missed the second. The changelog gate is green on the repaired fragments. --- changelog.d/fix-wave3-gate-breaks.md | 2 +- changelog.d/w3-50-session-supply.md | 6 +++--- docs/how-to/migrate-d2b-v1-0-to-v1-1.md | 4 ++-- ...026-09-24-002-refactor-rust-skills-remediation-plan.md | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/changelog.d/fix-wave3-gate-breaks.md b/changelog.d/fix-wave3-gate-breaks.md index 538baa475..752a007b8 100644 --- a/changelog.d/fix-wave3-gate-breaks.md +++ b/changelog.d/fix-wave3-gate-breaks.md @@ -1,3 +1,3 @@ ### Fixed -- A cross-slice merge left the workspace gate red: the status-size single-pass change dropped the last non-test use of `canonical_json_bytes` in the v3 resource status contract while its import stayed at module scope, the telemetry meter registry kept a module-scope import used only by tests, the test-support runner-intent rebuild hook still read the pre-merge flat guest intent map after the resolver nested it per zone, the CLI receive-buffer slice added a `std::sync::Mutex` critical section without the sanctioned CLI-only allow its sibling sites carry (tripping the blocking census), the nftables/hosts renderers wrote trailing-newline format strings with `write!` where the newline form trips the clippy gate, the clipboard controller's route-shape validators and their tests exceeded the clippy argument and type-complexity limits, and the merged `Cargo.lock` and the async-gate inventory were never regenerated after wave-3 slices changed dependencies and marker sites, leaving the policy-input closures and the inventory stale. The imports now live at their test-module use sites, the hook iterates the nested map, the receive-buffer lock carries the per-site allow, the renderers use `writeln!`, the route-shape checks take a plain-field shape struct, and the lock, policy inputs, and async-gate inventory are regenerated, so `cargo check --workspace --all-targets`, the blocking census, the policy-input check, the async-gate check, the clippy gate, and the Layer-1 gate lanes are green again. \ No newline at end of file +- A cross-slice merge left the workspace gate red: the status-size single-pass change dropped the last non-test use of `canonical_json_bytes` in the v3 resource status contract while its import stayed at module scope, the telemetry meter registry kept a module-scope import used only by tests, the test-support runner-intent rebuild hook still read the pre-merge flat guest intent map after the resolver nested it per zone, the CLI receive-buffer slice added a `std::sync::Mutex` critical section without the sanctioned CLI-only allow its sibling sites carry (tripping the blocking census), the nftables/hosts renderers wrote trailing-newline format strings with `write!` where the newline form trips the clippy gate, the clipboard controller's route-shape validators and their tests exceeded the clippy argument and type-complexity limits, and the merged `Cargo.lock` and the async-gate inventory were never regenerated after the parallel remediation slices changed dependencies and marker sites, leaving the policy-input closures and the inventory stale. The imports now live at their test-module use sites, the hook iterates the nested map, the receive-buffer lock carries the per-site allow, the renderers use `writeln!`, the route-shape checks take a plain-field shape struct, and the lock, policy inputs, and async-gate inventory are regenerated, so `cargo check --workspace --all-targets`, the blocking census, the policy-input check, the async-gate check, the clippy gate, and the Layer-1 gate lanes are green again. \ No newline at end of file diff --git a/changelog.d/w3-50-session-supply.md b/changelog.d/w3-50-session-supply.md index af1998b4a..8ad70c879 100644 --- a/changelog.d/w3-50-session-supply.md +++ b/changelog.d/w3-50-session-supply.md @@ -1,5 +1,5 @@ ### Fixed -- d2b-session no longer depends on the unused d2b-audit and d2b-telemetry crates; - its bazel targets drop the matching explicit deps. -The unused serde_json dev-dependency is removed from d2b-sessions manifest. \ No newline at end of file +- d2b-session no longer depends on the unused d2b-audit and d2b-telemetry crates; its + bazel targets drop the matching explicit deps. +- The unused serde_json dev-dependency is removed from the d2b-session manifest. \ No newline at end of file diff --git a/docs/how-to/migrate-d2b-v1-0-to-v1-1.md b/docs/how-to/migrate-d2b-v1-0-to-v1-1.md index a7f32b8f3..5186dc18b 100644 --- a/docs/how-to/migrate-d2b-v1-0-to-v1-1.md +++ b/docs/how-to/migrate-d2b-v1-0-to-v1-1.md @@ -211,8 +211,8 @@ tagline sweep (drop "on microvm.nix" from `flake.nix` / > **v1.1.1 status note**: v1.1.1 keeps emitting the v1.0/v1.1 > `StatusServicesOutputV2` shape. The V3 wire schema -> (`StatusServicesOutputV3`) ships with the emit-side flip, -> scheduled for v1.1.2, per the rename map below. +> ships with the emit-side flip, scheduled for v1.1.2. The V3 shape is the +> rename map below applied to V2; it is not a type you can name today. > > Tooling authors that consume the JSON output should: > - At v1.1.1, continue parsing V2 (`microvm`/`snd`/`virtiofsd`). diff --git a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md index 2fbc9e22a..010bd11d2 100644 --- a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md +++ b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md @@ -47,8 +47,8 @@ The audit (16 craft lenses over every workspace crate, independently verified) p **Recording** -- R8. The audit report and lane files stay unedited; the remediation ledger lives beside them and is updated in the same pull request as the fixes it describes. -- R9. Finding identifiers appear only inside the audit directory and its ledger - never in source, doc comments, commit messages, changelog fragments, or the pull request body. +- R8. The audit report and lane files stay unedited while the remediation runs, and the ledger is updated in the same pull request as the fixes it describes. The audit record is working material for the remediation and does not ship; the gate set and the changelog fragments are the record that does. +- R9. Finding identifiers appear only inside the audit record while it is being built - never in source, doc comments, commit messages, changelog fragments, or the pull request body. **Gates** @@ -318,9 +318,9 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha - Every one of the audit's findings is applied, or recorded with evidence as skipped-stale, already-fixed, escalated, reclassified, or policy-confirmed; no finding is silently dropped and none is applied without re-verification. - Each wave's gate set (R10) is green before the next wave starts; residual failures are attributed to the wave-0 baseline with recorded evidence, and any baseline-attributed failure that later blocks close-out has an owner recorded in the ledger. - Ratchet surfaces moved by the fixes were moved in the same commits, and the contract-surface changes shipped with their schema, emitter, prose, version, and pins together. -- The audit report and lane files are byte-unchanged; the ledger is complete and lives in the audit directory. +- The audit report and lane files stayed byte-unchanged and the ledger was complete for the whole remediation. The record itself is not part of the shipped tree: each finding's outcome is carried by its changelog fragment and by the code the gate exercises. - Final acceptance ran both integration lanes on the reviewed head, and the pull request carries review evidence for that head. -- No finding identifier leaked outside the audit directory: not into source, doc comments, commits, changelog fragments, or the pull request body. +- No finding identifier reached the shipped tree: not into source, doc comments, commits, changelog fragments, or the pull request body. --- From 44169400c2dabf812f320af55ea2e09528e9a70f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 02:10:42 -0700 Subject: [PATCH 709/726] docs(changelog): align the surface-removal fragment with the corrected migration guide The fragment announced that the migration guide "now promises the V3 type only at the emit-side flip". The guide no longer promises a type at all: it describes the V3 shape as its rename map applied to V2, because the type was deleted. Left as it was, the release note and the guide it points at contradict each other. --- changelog.d/w6-02-contracts-control-surface.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/changelog.d/w6-02-contracts-control-surface.md b/changelog.d/w6-02-contracts-control-surface.md index 6c9bc60d6..8b1cf93fd 100644 --- a/changelog.d/w6-02-contracts-control-surface.md +++ b/changelog.d/w6-02-contracts-control-surface.md @@ -2,8 +2,9 @@ - The unpublished `StatusServicesOutputV3` type and its `from_v2` conversion shim are removed from the d2b-contracts-control crate. The CLI still emits - the V2 status shape; the migration guide now promises the V3 type only at - the emit-side flip, so tooling keeps parsing V2 until then. + the V2 status shape; the migration guide now describes the V3 shape as its + rename map applied to V2 rather than naming a type, so tooling keeps parsing + V2 until the emit-side flip. - `LevelPercent` is no longer re-exported from the CLI-output module; the type remains available through `d2b_contracts`, the path the API docs pin. - The helper wire types' `HelperSnapshot::validate` and From ce91ea72e6080ccdefeed05b2ba46859fb83adc2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 02:17:46 -0700 Subject: [PATCH 710/726] docs: strip internal audit-row citations from shipped source Nine internal audit-corpus row identifiers survived in files the merged tree ships: eight in doc and line comments across d2b-broker, d2b-contracts, d2b-contracts-broker, d2bd-runtime and d2bd, and one in the committed dependency-policy file. The contributing guide forbids internal planning identifiers in released prose, and a comment in a published crate is released prose: it is rendered into rustdoc and read by every consumer of the API. Each citation is removed and nothing else changes. The reasoning every one of those lines carries stands on its own without the row id - a reader needs to know that the test-only peer-uid override is no longer a wire member, that an audio mutation must not report a user-input refusal as the internal-io class, that an audit export entry carrying both payloads is refused at decode - and none of that depends on a number from a corpus the reader cannot open. The rationale for the accepted duplicate clusters stays, without the row ids. The one non-ASCII count reported over these files is pre-existing typography in comment lines this change does not touch. --- deny.toml | 6 +++--- packages/d2b-broker/src/runtime.rs | 2 +- packages/d2b-contracts-broker/src/broker_wire.rs | 2 +- packages/d2b-contracts/src/audit_wire.rs | 2 +- packages/d2bd-runtime/src/typed_error.rs | 6 +++--- packages/d2bd/src/audio_dispatch.rs | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/deny.toml b/deny.toml index 5e319fad2..45c708dd6 100644 --- a/deny.toml +++ b/deny.toml @@ -1,9 +1,9 @@ [bans] multiple-versions = "warn" wildcards = "deny" -# Accepted duplicate clusters (rust-skills audit RS-0946/RS-0947/RS-0949, -# reviewed 2026-09-25). cargo-deny reports these on every run; each entry -# names the versions, the pullers, and the re-check trigger. The clusters +# Accepted duplicate clusters (rust-skills audit, reviewed 2026-09-25). cargo-deny +# reports these on every run; each entry names the versions, the pullers, and +# the re-check trigger. The clusters # below are accepted because the pullers' version ranges genuinely do not # unify (no lower-bound raise reaches both legs). multiple-versions stays # "warn" until the workspace-direct clusters resolve; a warn-to-deny flip diff --git a/packages/d2b-broker/src/runtime.rs b/packages/d2b-broker/src/runtime.rs index a01a39bdb..635cc3cdf 100644 --- a/packages/d2b-broker/src/runtime.rs +++ b/packages/d2b-broker/src/runtime.rs @@ -1397,7 +1397,7 @@ fn peer_matches_instance(config: &ServerConfig, peer_uid: u32, peer_gid: u32) -> || (config.profile == BrokerProfile::Host && peer_uid == 0) } -/// The harness-only peer-uid override's frame member (RS-0328). +/// The harness-only peer-uid override's frame member. /// /// The broker's own harness - the bootstrap probe CLI and the integration /// tests - asks a `--test-mode` broker to treat one connection as a peer other diff --git a/packages/d2b-contracts-broker/src/broker_wire.rs b/packages/d2b-contracts-broker/src/broker_wire.rs index e23925d67..22ea01f35 100644 --- a/packages/d2b-contracts-broker/src/broker_wire.rs +++ b/packages/d2b-contracts-broker/src/broker_wire.rs @@ -3242,7 +3242,7 @@ mod tests { #[test] fn broker_request_envelope_refuses_a_test_only_peer_uid_member() { - // RS-0328: the test-only peer-uid override is no longer a member of + // The test-only peer-uid override is no longer a member of // the wire contract. The harness frames a `--test-mode` broker // unwraps it from; every other broker refuses it here. let env = BrokerRequestEnvelope { diff --git a/packages/d2b-contracts/src/audit_wire.rs b/packages/d2b-contracts/src/audit_wire.rs index d9a358bc6..03aae43f4 100644 --- a/packages/d2b-contracts/src/audit_wire.rs +++ b/packages/d2b-contracts/src/audit_wire.rs @@ -30,7 +30,7 @@ pub enum AuditExportErrorCode { /// One typed audit export entry. Its payload is exactly one of an audit record /// or a closed export failure class, so the state the retired `record` / /// `error` pair left representable - neither populated - cannot be built, and -/// an entry that carries both is refused at decode (RS-0546). +/// an entry that carries both is refused at decode. #[derive(Clone, PartialEq, Serialize, Deserialize)] #[serde(try_from = "AuditExportEntryWire", into = "AuditExportEntryWire")] pub struct AuditExportEntry { diff --git a/packages/d2bd-runtime/src/typed_error.rs b/packages/d2bd-runtime/src/typed_error.rs index 933845388..a93ee898d 100644 --- a/packages/d2bd-runtime/src/typed_error.rs +++ b/packages/d2bd-runtime/src/typed_error.rs @@ -713,13 +713,13 @@ pub enum TypedError { /// declared in the public manifest. The status path reports the same class /// per VM as `AudioErrorKind::VmNotFound`, so a mutation caller /// distinguishes a bad target from an internal I/O failure by `kind` / - /// exit code instead of by matching the message text (RS-0537). + /// exit code instead of by matching the message text. AudioVmNotFound { vm: String, }, /// An audio mutation (`set-volume` / `mute`) named a VM whose manifest /// entry does not declare audio. The status path reports the same class - /// per VM as `AudioErrorKind::AudioNotEnabled` (RS-0537). + /// per VM as `AudioErrorKind::AudioNotEnabled`. AudioNotEnabled { vm: String, }, @@ -1812,7 +1812,7 @@ mod tests { #[test] fn audio_mutation_refusals_are_structured_and_leak_free() { - // RS-0537: an audio mutation must not report a user-input refusal as + // An audio mutation must not report a user-input refusal as // the `internal-io` class, so a caller can tell the two apart without // matching the message text. let not_found = TypedError::AudioVmNotFound { diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index 1b876d6bd..5bbe8ca69 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -379,8 +379,8 @@ pub(crate) fn combined_audio_applied( /// A mutation refuses a target that is not declared in the public manifest /// through [`TypedError::AudioVmNotFound`], and a target whose manifest /// entry does not declare audio through [`TypedError::AudioNotEnabled`] - - /// the same classes the status path reports per VM through `AudioVmError` - /// (RS-0537). Lock, read, write, and enforcement failures keep returning + /// the same classes the status path reports per VM through `AudioVmError`. + /// Lock, read, write, and enforcement failures keep returning /// [`TypedError::InternalIo`]. pub fn dispatch_audio( state: &ServerState, @@ -405,7 +405,7 @@ fn dispatch_audio_status( // Collect the set of VMs to query before sizing the result buffers: the // only lower bound on admission of that set, so both grow-by-push lists - // below are pre-sized to it instead of starting empty (RS-0803). + // below are pre-sized to it instead of starting empty. let vm_names: Vec = if args.vms.is_empty() { manifest .vms From e9ba71d5a5efdb5e75ab3b0b621c0f24a619ee93 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 02:24:37 -0700 Subject: [PATCH 711/726] fix(azure-vm): correct the recovery decode comment to match its rejection arm The leading comment on the custom Deserialize for AzureVmRecoveryState claimed the legacy fold is total because the write side always sets or clears both values together. Seventy lines below, in the same match, the branch-introduced comment and the Err arm it describes refuse a half-Some pair with a typed serde error. Two comments in one function stated opposite contracts for the same arm, both added by this branch. The claim is also false as written: the total-fold sentence reads as a property of the decode, but the write side is only one of the two ways a record reaches it. The other is a record read back off disk, which the fold is now explicitly told can be malformed. A reader reasoning from the header alone concludes the Err arm is unreachable, treats a decode failure there as an impossible state, and widens the arm back to the total fold this branch removed a panic to break. The sentence is rescoped to the write side, which does hold, and the refusal is stated where the reader will meet it. Only comment text changes; no code, no schema, no generated artifact, no test. --- .../src/controller/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs index 2289674e5..bb6fd0a22 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs @@ -120,9 +120,10 @@ impl<'de> Deserialize<'de> for AzureVmRecoveryState { // serde. The in-flight operation is one grouped object today, but // records written before the grouping carry the legacy // `operation` + `operationStartedAtUnixMs` pair; both shapes load - // and the pair folds into the grouped shape. The fold is total - // because the write side always sets or clears both values - // together. + // and the pair folds into the grouped shape when both members + // are present. The write side always sets or clears both values + // together, but a record read back with a half-Some pair is + // malformed, and the decode refuses it below. #[derive(Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct NewShape { From 529751a7651d70be357179128c12a0fa3a6312a0 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 03:24:56 -0700 Subject: [PATCH 712/726] d2b: refuse a host mutation verb with no mode before Zone resolution `modern_run` resolves the Zone before it dispatches a command, and `ZoneContext::discover` refuses a command whose public socket does not answer. `host validate`, `host reconcile` and `host doctor` are built with a local-only context and skip that probe; `host prepare` and `host destroy` do not, so their missing-mode refusal - a property of the invocation - was reported as `zone-unavailable` at exit 1 instead of the documented `--apply-or-dry-run-required` envelope at exit 78 whenever d2bd was not listening. The verbs that carry a mode keep their transport refusal, and an explicit `--zone` keeps its routing. The rule now lives in one place, `host::missing_mutation_mode`, which `modern_run` consults before it builds a context; the per-verb copies in `mutation`, `reconcile` and `validate` are gone. --- .../fix-host-mutation-flag-refusal-order.md | 8 ++++ packages/d2b/src/dispatch.rs | 17 +++++++++ packages/d2b/src/host.rs | 37 ++++++++++--------- 3 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 changelog.d/fix-host-mutation-flag-refusal-order.md diff --git a/changelog.d/fix-host-mutation-flag-refusal-order.md b/changelog.d/fix-host-mutation-flag-refusal-order.md new file mode 100644 index 000000000..1b0fb19ce --- /dev/null +++ b/changelog.d/fix-host-mutation-flag-refusal-order.md @@ -0,0 +1,8 @@ +### Fixed + +- `d2b host prepare` and `d2b host destroy` without `--dry-run`/`--apply` are + refused with the documented `--apply-or-dry-run-required` envelope at exit 78 + even when the public socket is unreachable. The missing-mode refusal is a + property of the invocation, so it is now emitted before the Zone is resolved + rather than after; previously the daemon reachability check ran first and the + same invocation reported `zone-unavailable` at exit 1. diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index 85e57a7a0..3527cbeb1 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -980,6 +980,23 @@ pub(crate) fn modern_run(raw_args: Vec) -> i32 { Err(error) => report_dispatch_failure(None, &cli, mode, error), }; } + // A mutating `host` verb that selected no mode is a usage error the + // operator is owed before any connection. Refusing it here keeps + // `--apply-or-dry-run-required` at exit 78 whether or not the public + // socket answers: resolved after the Zone, a missing `--dry-run`/ + // `--apply` would be reported as a transport failure instead. + if let ModernCommand::Host(host::HostArgs { command }) = &cli.command + && let Some(verb) = host::missing_mutation_mode(command) + { + let mode = match output_mode(cli.json, cli.human) { + Ok(mode) => mode, + Err(error) => return crate::report_failure(error), + }; + return match emit_host_error(&missing_mutation_flag_envelope(verb), mode.is_json()) { + Ok(code) => code, + Err(error) => crate::report_failure(error), + }; + } let local_host_command = matches!( &cli.command, ModernCommand::Host(host::HostArgs { diff --git a/packages/d2b/src/host.rs b/packages/d2b/src/host.rs index 53a717dbb..828e63185 100644 --- a/packages/d2b/src/host.rs +++ b/packages/d2b/src/host.rs @@ -7,7 +7,7 @@ use crate::{ CliFailure, context::{CliContext, OutputMode, RequestDeadline, ZoneContext}, dispatch::{GenericGetArgs, GenericListArgs}, - dispatch::{emit_host_error, host_error_envelope, missing_mutation_flag_envelope}, + dispatch::{emit_host_error, host_error_envelope}, doctor, host_validate, print_json, print_stdout, resource, }; @@ -70,6 +70,25 @@ pub(crate) struct HostReconcileArgs { pub(crate) apply: bool, } +/// The `host` verb a mutation-mode refusal names, for a subcommand that +/// mutates state and selected neither `--dry-run` nor `--apply`. +/// +/// The rule belongs to the invocation rather than to the runtime, so +/// [`crate::dispatch::modern_run`] asks this before it resolves a Zone: a +/// missing mode is owed the `--apply-or-dry-run-required` envelope even when +/// the public socket cannot be reached. +pub(crate) fn missing_mutation_mode(command: &HostCommand) -> Option<&'static str> { + let (verb, dry_run, apply) = match command { + HostCommand::Prepare(args) => ("host prepare", args.dry_run, args.apply), + HostCommand::Destroy(args) => ("host destroy", args.dry_run, args.apply), + HostCommand::Reconcile(args) => ("host reconcile", args.dry_run, args.apply), + HostCommand::Validate(args) => ("host validate", args.dry_run, args.apply), + HostCommand::Get(_) | HostCommand::List(_) | HostCommand::Status(_) => return None, + HostCommand::Doctor(_) => return None, + }; + (!dry_run && !apply).then_some(verb) +} + pub(crate) fn run( context: &ZoneContext, args: &HostArgs, @@ -271,10 +290,6 @@ fn mutation( mode: OutputMode, deadline: RequestDeadline, ) -> Result { - if !args.dry_run && !args.apply { - let verb = format!("host {operation}"); - return emit_host_error(&missing_mutation_flag_envelope(&verb), mode.is_json()); - } let value = context.invoke( "Reconcile", json!({ @@ -296,12 +311,6 @@ fn reconcile( mode: OutputMode, deadline: RequestDeadline, ) -> Result { - if !args.dry_run && !args.apply { - return emit_host_error( - &missing_mutation_flag_envelope("host reconcile"), - mode.is_json(), - ); - } if !args.network { return Err(context.failure("ref-invalid", "host reconcile requires --network", mode, 78)); } @@ -323,12 +332,6 @@ fn reconcile( } fn validate(args: &HostValidateArgs, mode: OutputMode) -> Result { - if !args.dry_run && !args.apply { - return emit_host_error( - &missing_mutation_flag_envelope("host validate"), - mode.is_json(), - ); - } let validation_mode = if args.apply { host_validate::ValidateMode::Apply } else { From ec67a9eed2dfd6fd2a6732e42dfcc93a511785a6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 03:59:57 -0700 Subject: [PATCH 713/726] test(azure-vm): pin the half-paired legacy recovery decode refusal The legacy decode arm refuses a record whose operation and start stamp are only half present, and nothing exercised it. The paired and unpaired records of the same shape decode, so the two controls tie the refusal to the half pair rather than to the record. The enclosing `Repr` is untagged, so the refusal is asserted on the error itself. --- .../BUILD.bazel | 11 ++++ .../tests/recovery_decode.rs | 56 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 packages/d2b-provider-guest-azure-virtual-machine/tests/recovery_decode.rs diff --git a/packages/d2b-provider-guest-azure-virtual-machine/BUILD.bazel b/packages/d2b-provider-guest-azure-virtual-machine/BUILD.bazel index 60fb3bb68..c10597b80 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/BUILD.bazel +++ b/packages/d2b-provider-guest-azure-virtual-machine/BUILD.bazel @@ -65,6 +65,17 @@ d2b_rust_test( ":d2b_provider_guest_azure_virtual_machine", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) +d2b_rust_test( + name = "recovery_decode", + srcs = [ + "tests/recovery_decode.rs", + ], + compile_data = ["Cargo.toml"], + deps = [ + ":d2b_provider_guest_azure_virtual_machine", + ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), +) + d2b_rust_test( name = "lifecycle_hermetic", diff --git a/packages/d2b-provider-guest-azure-virtual-machine/tests/recovery_decode.rs b/packages/d2b-provider-guest-azure-virtual-machine/tests/recovery_decode.rs new file mode 100644 index 000000000..45900ddc0 --- /dev/null +++ b/packages/d2b-provider-guest-azure-virtual-machine/tests/recovery_decode.rs @@ -0,0 +1,56 @@ +//! Decode contract for the sealed Azure VM recovery record. + +use d2b_provider_guest_azure_virtual_machine::{AzureOperationHandle, AzureVmRecoveryState}; +use serde_json::Value; + +/// A record written before the in-flight operation was grouped: the +/// `operation` and `operationStartedAtUnixMs` pair, with the caller +/// choosing which side of the pair carries a value. +fn legacy_record(operation: Option, started_at: Option) -> String { + serde_json::json!({ + "phase": "deleting", + "finalizerInstalled": true, + "operation": operation.unwrap_or(Value::Null), + "operationStartedAtUnixMs": started_at.map_or(Value::Null, Value::from), + "pendingDeleteOperationId": null, + "bootstrapStartedAtUnixMs": null, + "pskDeliveryAttempts": 1, + "bootstrapServiceState": "Waiting", + }) + .to_string() +} + +#[test] +fn a_legacy_record_with_a_half_paired_operation_refuses_the_decode() { + let handle = serde_json::to_value( + AzureOperationHandle::from_core(b"opaque-operation").expect("a bounded operation handle"), + ) + .expect("an operation handle serializes"); + + // The write side emits both members or neither, and both load: the + // pair folds into the grouped in-flight operation. + let paired: AzureVmRecoveryState = + serde_json::from_str(&legacy_record(Some(handle.clone()), Some(1_700_000_000_000))) + .expect("a legacy record with both members present folds into the grouped shape"); + assert!(paired.in_flight_operation.is_some()); + + let empty: AzureVmRecoveryState = serde_json::from_str(&legacy_record(None, None)) + .expect("a legacy record with neither member present carries no in-flight operation"); + assert!(empty.in_flight_operation.is_none()); + + // A half-paired record is malformed and the decode refuses it rather + // than folding one member away. The enclosing `Repr` is untagged, so + // the refusal is observed on the error itself and not through the + // inner message; the two controls above are what tie it to the half + // pair instead of to some other property of the record. + let operation_only = legacy_record(Some(handle), None); + assert!( + serde_json::from_str::(&operation_only).is_err(), + "an operation without its start stamp is refused, not folded" + ); + let started_only = legacy_record(None, Some(1_700_000_000_000)); + assert!( + serde_json::from_str::(&started_only).is_err(), + "a start stamp without its operation is refused, not folded" + ); +} From 248a6c720a747ea57239b9d21ba3943430fdcdd1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 03:59:57 -0700 Subject: [PATCH 714/726] test(core-controller): cover the admission startup barrier refusal `admit_authority` refuses with `StartupRehydrationRequired` until the startup barrier completes, and no test reached that guard. Its only former coverage went with the external-NIC authority surface, while the guard itself stayed on the generic admission path the controller shares the index into, so a caller outside the startup path reached it untested. Distinct from the process-level stage barrier in `main`. --- packages/d2b-core-controller/src/authority.rs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/packages/d2b-core-controller/src/authority.rs b/packages/d2b-core-controller/src/authority.rs index 5b41dd020..c3fcc3935 100644 --- a/packages/d2b-core-controller/src/authority.rs +++ b/packages/d2b-core-controller/src/authority.rs @@ -2302,6 +2302,61 @@ fn authority_proof(value: &str, generation: u64) -> AuthorityOwnerProof { index.admit_authority(other_zone).unwrap(); } + /// The index refuses an admission before any effect runs until the + /// startup barrier completes. This is the index's own guard, distinct + /// from the process-level stage barrier in `main`: the index is shared + /// into the controller admission surface, so a caller outside the + /// startup path reaches this refusal too, and a claim on a host + /// resource whose pre-restart owner set was never loaded must not + /// succeed. + #[test] + fn admission_waits_for_the_same_startup_barrier_before_any_effect() { + let host = uid("623e4567-e89b-42d3-a456-426614174005"); + let claim = || { + AuthorityRequest::gpu_full_device( + host.clone(), + digest(1), + authority_proof("723e4567-e89b-42d3-a456-426614174006", 1), + ) + .unwrap() + }; + + let mut unrehydrated = HostGlobalAuthorityIndex::new_unrehydrated(); + assert!(!unrehydrated.is_ready_for_readiness()); + let mut effects = 0; + assert_eq!( + unrehydrated + .admit_authority_before_effect(claim(), |_| { + effects += 1; + AuthorityEffectOutcome::Confirmed + }) + .unwrap_err(), + AuthorityError::StartupRehydrationRequired + ); + assert_eq!(effects, 0); + assert_eq!( + AuthorityError::StartupRehydrationRequired.code(), + "authority-startup-rehydration-required" + ); + + // A restart relist invalidates an index that has already + // admitted claims, and the same barrier refuses again until + // rehydration loads the durable owner proofs. + let mut live = HostGlobalAuthorityIndex::new_for_tests_ready(); + live.admit_authority(claim()).unwrap(); + live.invalidate_for_restart(); + let mut effects = 0; + assert_eq!( + live.admit_authority_before_effect(claim(), |_| { + effects += 1; + AuthorityEffectOutcome::Confirmed + }) + .unwrap_err(), + AuthorityError::StartupRehydrationRequired + ); + assert_eq!(effects, 0); + } + #[test] fn host_global_hardware_matrix_cannot_be_bypassed_by_zone_or_private_class() { let host = uid("623e4567-e89b-42d3-a456-426614174005"); From 7b611cbc665cb045b9b741d81b51cb975b8bd5b9 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 03:59:58 -0700 Subject: [PATCH 715/726] test(xtask): pin the self-binding scan window at the declaring provider The escape scan ends at the closing brace of the declaring `SeedProvider` block instead of running to the end of the file, and nothing distinguished the two windows. A row written after the block belongs to no provider of its own and is no longer attributed to the preceding one, while a later block is still scanned in its own right. --- packages/xtask/src/provider_crate_policy.rs | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/xtask/src/provider_crate_policy.rs b/packages/xtask/src/provider_crate_policy.rs index a660d5471..db22adbbf 100644 --- a/packages/xtask/src/provider_crate_policy.rs +++ b/packages/xtask/src/provider_crate_policy.rs @@ -10796,6 +10796,51 @@ mod tests { assert_eq!(check_self_binding_scope(&fixture.root), Ok(())); } + /// The escape scan window is the declaring `SeedProvider` block: it + /// ends at the block's closing brace, not at the end of the file. + #[test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn the_self_binding_scan_window_ends_at_the_declaring_provider() { + let fixture = Fixture::new("self-binding-window"); + let d2bd = fixture.root.join("packages/d2bd/src"); + fs::create_dir_all(&d2bd).unwrap(); + let seed = d2bd.join("seed.rs"); + // A self-binding row that follows the declaring block belongs to + // no provider of its own, so it is not attributed to the + // provider that precedes it. An open-ended window would carry + // that provider's name and role list into the trailing row and + // report a second provider's row as that provider's escape. + fs::write( + &seed, + "SeedProvider {\n provider_ref: ResourceRef::parse(\"Provider/system-minijail\"),\n roles: vec![ResourceRef::parse(\"Role/worker\")],\n}\nSeedSelfBinding {\n subject_ref: ResourceRef::parse(\"Provider/other\"),\n role_ref: ResourceRef::parse(\"Role/other\"),\n}\n", + ) + .unwrap(); + assert_eq!( + check_self_binding_scope(&fixture.root), + Ok(()), + "the window ends at the block's closing brace" + ); + // Narrowing one block's window does not blind the file to a + // later block, which is scanned in its own right and reports + // its escape against its own declaring provider. + fs::write( + &seed, + "SeedProvider {\n provider_ref: ResourceRef::parse(\"Provider/system-minijail\"),\n roles: vec![ResourceRef::parse(\"Role/worker\")],\n}\nSeedProvider {\n provider_ref: ResourceRef::parse(\"Provider/other\"),\n roles: vec![ResourceRef::parse(\"Role/other\")],\n self_bindings: vec![SeedSelfBinding {\n subject_ref: ResourceRef::parse(\"Provider/third\"),\n role_ref: ResourceRef::parse(\"Role/third\"),\n }],\n}\n", + ) + .unwrap(); + let error = check_self_binding_scope(&fixture.root) + .expect_err("a later provider block is scanned in its own window"); + assert!(error.contains("self-binding-subject-escape"), "{error}"); + assert!(error.contains("self-binding-role-escape"), "{error}"); + assert!(error.contains("third"), "{error}"); + assert!( + !error.contains("system-minijail"), + "the earlier clean block does not inherit the later escape: {error}" + ); + fs::remove_file(&seed).unwrap(); + assert_eq!(check_self_binding_scope(&fixture.root), Ok(())); + } + #[test] fn the_structural_ratchet_matches_the_committed_tree() { let root = repo_root().expect("resolve repository root"); From 6cbcf185b78ff3ef00241ac4c8f13d059126441d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 04:52:12 -0700 Subject: [PATCH 716/726] fix(d2b-core): publish the storage lifecycle schema in the wire's casing `StorageLifecycleIssue` named its variant fields with serde's container-level `rename_all_fields = "camelCase"`. schemars 0.8.22 reads `rename_all` on a variant, where it renames that variant's fields, but not `rename_all_fields`, so the generated schema required snake_case keys: `bundle_version`, `contract_id`, `offending_id`, and `role_id`. A consumer validating a real report against the committed schema rejected five of the eight issue variants, and the drift gate could not see it because the committed file equalled fresh generator output. Every struct variant now repeats the field casing as a `schemars` attribute, leaving serde's wire bytes untouched, and the schema is regenerated through `make generate`. A new contract test serializes one report carrying every issue variant and validates the bytes against the committed schema instead of against a fresh generator run, so the artifact and the bytes are compared to each other. It refuses a keyword it does not interpret, so a schema that grows one fails rather than passing unvalidated. Against the pre-fix schema the test fails on the first variant that carries a renamed field. --- .../refactor-rust-skills-remediation.md | 1 + .../schemas/v2/storage-lifecycle-report.json | 24 +-- packages/d2b-core/BUILD.bazel | 15 ++ packages/d2b-core/src/storage_lifecycle.rs | 12 ++ .../tests/storage_lifecycle_schema.rs | 194 ++++++++++++++++++ 5 files changed, 234 insertions(+), 12 deletions(-) create mode 100644 packages/d2b-core/tests/storage_lifecycle_schema.rs diff --git a/changelog.d/refactor-rust-skills-remediation.md b/changelog.d/refactor-rust-skills-remediation.md index 3ec5f54dd..4feb5960f 100644 --- a/changelog.d/refactor-rust-skills-remediation.md +++ b/changelog.d/refactor-rust-skills-remediation.md @@ -3,6 +3,7 @@ - Repaired three tests that could not fail - the daemon readiness pair, the bus telemetry closed-label check, and the Wayland display registry handlers - so each one now fails when the behaviour it names breaks, and dropped a redundant revision-display assertion that could never fail either way. - Malformed wire input no longer panics the broker, the daemon runtime, or the Wayland policy engine: a malformed authoritative audit join, a malformed broker zone digest, and a malformed driver zone token now return typed refusals at those boundaries. - Moved blocking reaping, file locking, ACL application, and NSS group lookup off the broker's async executor workers, so a busy executor no longer stalls on host syscalls. +- The published v2 storage lifecycle report schema now names each issue field the way the daemon writes it, so a consumer validating a real report no longer rejects the five issue variants that carry a renamed field. ### Changed diff --git a/docs/reference/schemas/v2/storage-lifecycle-report.json b/docs/reference/schemas/v2/storage-lifecycle-report.json index 8a8289daa..e9c2b7ec6 100644 --- a/docs/reference/schemas/v2/storage-lifecycle-report.json +++ b/docs/reference/schemas/v2/storage-lifecycle-report.json @@ -87,11 +87,11 @@ { "type": "object", "required": [ - "bundle_version", + "bundleVersion", "kind" ], "properties": { - "bundle_version": { + "bundleVersion": { "type": "integer", "format": "uint32", "minimum": 0.0 @@ -121,12 +121,12 @@ { "type": "object", "required": [ - "contract_id", + "contractId", "kind", "reason" ], "properties": { - "contract_id": { + "contractId": { "type": "string" }, "kind": { @@ -135,7 +135,7 @@ "storage-contract-invalid" ] }, - "offending_id": { + "offendingId": { "type": [ "string", "null" @@ -149,12 +149,12 @@ { "type": "object", "required": [ - "contract_id", + "contractId", "kind", "reason" ], "properties": { - "contract_id": { + "contractId": { "type": "string" }, "kind": { @@ -163,7 +163,7 @@ "sync-contract-invalid" ] }, - "offending_id": { + "offendingId": { "type": [ "string", "null" @@ -178,7 +178,7 @@ "type": "object", "required": [ "kind", - "role_id", + "roleId", "vm" ], "properties": { @@ -188,7 +188,7 @@ "missing-restart-policy" ] }, - "role_id": { + "roleId": { "type": "string" }, "vm": { @@ -200,7 +200,7 @@ "type": "object", "required": [ "kind", - "role_id", + "roleId", "vm" ], "properties": { @@ -210,7 +210,7 @@ "adoptable-missing-cgroup-leaf" ] }, - "role_id": { + "roleId": { "type": "string" }, "vm": { diff --git a/packages/d2b-core/BUILD.bazel b/packages/d2b-core/BUILD.bazel index 415ce6d17..0c775ec79 100644 --- a/packages/d2b-core/BUILD.bazel +++ b/packages/d2b-core/BUILD.bazel @@ -276,6 +276,21 @@ d2b_rust_test( ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), ) +d2b_rust_test( + name = "storage_lifecycle_schema", + srcs = ["tests/storage_lifecycle_schema.rs"], + compile_data = [ + "Cargo.toml", + "//:docs/reference/schemas/v2/storage-lifecycle-report.json", # keep + ], + visibility = ["//visibility:public"], + deps = [ + "//packages/d2b-contracts-resource:d2b_contracts_resource", + "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", + ":d2b_core", + ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), +) + # keep filegroup( name = "cargo_workspace_sources", diff --git a/packages/d2b-core/src/storage_lifecycle.rs b/packages/d2b-core/src/storage_lifecycle.rs index bc53e270a..95299e776 100644 --- a/packages/d2b-core/src/storage_lifecycle.rs +++ b/packages/d2b-core/src/storage_lifecycle.rs @@ -42,15 +42,24 @@ impl StorageLifecycleReport { } } +// The published schema must name these fields the way `serde` writes them. +// schemars 0.8 reads `rename_all` on a variant, where it renames that +// variant's fields, but not the container-level `rename_all_fields`, so every +// struct variant repeats the field casing as a `schemars` attribute. Dropping +// one of them leaves the published schema requiring a key the daemon never +// writes; the schema-vs-bytes test in `tests/storage_lifecycle_schema.rs` is +// what makes that loss fail loudly. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "kebab-case", rename_all_fields = "camelCase", tag = "kind")] pub enum StorageLifecycleIssue { MissingStorageContract, MissingSyncContract, + #[schemars(rename_all = "camelCase")] LegacyBundleContractsUnavailable { bundle_version: u32, }, BundleResolverUnavailable, + #[schemars(rename_all = "camelCase")] StorageContractInvalid { contract_id: String, reason: StorageContractValidationReason, @@ -58,6 +67,7 @@ pub enum StorageLifecycleIssue { #[serde(default)] offending_id: Option, }, + #[schemars(rename_all = "camelCase")] SyncContractInvalid { contract_id: String, reason: SyncContractValidationReason, @@ -65,10 +75,12 @@ pub enum StorageLifecycleIssue { #[serde(default)] offending_id: Option, }, + #[schemars(rename_all = "camelCase")] MissingRestartPolicy { vm: String, role_id: String, }, + #[schemars(rename_all = "camelCase")] AdoptableMissingCgroupLeaf { vm: String, role_id: String, diff --git a/packages/d2b-core/tests/storage_lifecycle_schema.rs b/packages/d2b-core/tests/storage_lifecycle_schema.rs new file mode 100644 index 000000000..9c9ecc57b --- /dev/null +++ b/packages/d2b-core/tests/storage_lifecycle_schema.rs @@ -0,0 +1,194 @@ +//! The published storage lifecycle schema must accept the bytes the daemon +//! actually writes. +//! +//! The schema is generated from the same types `serde` serializes, so it can +//! only disagree with the wire where the two derive from different attribute +//! sets. `StorageLifecycleIssue` names its variant fields with serde's +//! container-level `rename_all_fields`, which schemars 0.8 does not read, so +//! the committed schema once required snake_case keys the daemon never wrote. +//! A drift gate cannot see that: the committed file equalled fresh generator +//! output. This test validates the serialized bytes against the committed +//! schema, so the two are compared to each other rather than to the generator. + +use d2b_core::storage_lifecycle::{ + StorageContractValidationReason, StorageLifecycleIssue, StorageLifecycleReport, + SyncContractValidationReason, +}; +use serde_json::Value; + +/// The committed consumer-facing schema, not a fresh generator run. +const PUBLISHED_SCHEMA: &str = + include_str!("../../../docs/reference/schemas/v2/storage-lifecycle-report.json"); + +/// Keywords this validator interprets. A schema that grows a keyword outside +/// `INTERPRETED` and `NON_ASSERTING` fails the test instead of passing +/// unvalidated. +const INTERPRETED: [&str; 8] = [ + "$ref", + "enum", + "items", + "minimum", + "oneOf", + "properties", + "required", + "type", +]; + +/// Keywords that assert nothing about the instance: annotation text, and the +/// definition table a `$ref` looks up. +const NON_ASSERTING: [&str; 5] = ["$schema", "definitions", "description", "format", "title"]; + +#[test] +fn every_issue_variant_satisfies_the_published_schema() { + let schema: Value = + serde_json::from_str(PUBLISHED_SCHEMA).expect("published schema parses"); + let report = StorageLifecycleReport { + schema_version: "v2".to_owned(), + storage_contract_present: true, + sync_contract_present: true, + path_count: 2, + restart_policy_count: 1, + lock_count: 1, + issues: vec![ + StorageLifecycleIssue::MissingStorageContract, + StorageLifecycleIssue::MissingSyncContract, + StorageLifecycleIssue::LegacyBundleContractsUnavailable { bundle_version: 5 }, + StorageLifecycleIssue::BundleResolverUnavailable, + StorageLifecycleIssue::StorageContractInvalid { + contract_id: "storage.json".to_owned(), + reason: StorageContractValidationReason::DuplicateStoragePathId, + offending_id: Some("path:run-root".to_owned()), + }, + StorageLifecycleIssue::SyncContractInvalid { + contract_id: "sync.json".to_owned(), + reason: SyncContractValidationReason::OfdLockMissingCloexec, + offending_id: None, + }, + StorageLifecycleIssue::MissingRestartPolicy { + vm: "corp-vm".to_owned(), + role_id: "cloud-hypervisor".to_owned(), + }, + StorageLifecycleIssue::AdoptableMissingCgroupLeaf { + vm: "corp-vm".to_owned(), + role_id: "vhost-device-sound".to_owned(), + }, + ], + }; + let bytes = serde_json::to_value(&report).expect("report serializes"); + + let variants = report + .issues + .iter() + .map(StorageLifecycleIssue::kind_name) + .collect::>(); + assert_eq!( + variants.len(), + 8, + "one serialized issue per declared variant, so a new variant cannot skip the schema" + ); + + validate(&schema, &schema, &bytes).expect("serialized report satisfies the published schema"); +} + +/// Validate `instance` against `schema`, both borrowed from the published +/// document, returning the first disagreement. +fn validate(root: &Value, schema: &Value, instance: &Value) -> Result<(), String> { + let object = schema + .as_object() + .ok_or_else(|| format!("{instance} is checked against a non-object schema"))?; + for keyword in object.keys() { + if !INTERPRETED.contains(&keyword.as_str()) && !NON_ASSERTING.contains(&keyword.as_str()) { + return Err(format!("{instance} is checked against unimplemented {keyword}")); + } + } + if let Some(declared) = object.get("type") + && !matches_type(declared, instance) + { + return Err(format!("{instance} is not of type {declared}")); + } + if let Some(allowed) = object.get("enum").and_then(Value::as_array) + && !allowed.contains(instance) + { + return Err(format!("{instance} is outside the declared enum {allowed:?}")); + } + if let Some(floor) = object.get("minimum").and_then(Value::as_f64) + && instance.as_f64().is_some_and(|number| number < floor) + { + return Err(format!("{instance} is below the declared minimum {floor}")); + } + if let Some(definition) = object.get("$ref").and_then(Value::as_str) { + return validate(root, resolve(root, definition)?, instance); + } + if let Some(branches) = object.get("oneOf").and_then(Value::as_array) { + let matched = branches + .iter() + .filter(|branch| validate(root, branch, instance).is_ok()) + .count(); + if matched != 1 { + return Err(format!("{instance} satisfies {matched} oneOf branches, not one")); + } + } + if let Some(properties) = object.get("properties").and_then(Value::as_object) + && let Some(members) = instance.as_object() + { + for required in object + .get("required") + .and_then(Value::as_array) + .into_iter() + .flatten() + .filter_map(Value::as_str) + { + if !members.contains_key(required) { + return Err(format!("{instance} is missing the required key {required}")); + } + } + for (key, value) in members { + if let Some(property) = properties.get(key) { + validate(root, property, value).map_err(|error| format!("{error} at {key}"))?; + } + } + } + if let Some(item) = object.get("items") + && let Some(elements) = instance.as_array() + { + for (index, element) in elements.iter().enumerate() { + validate(root, item, element).map_err(|error| format!("{error} at {index}"))?; + } + } + Ok(()) +} + +/// A `type` keyword is either one name or a list of acceptable names. +fn matches_type(declared: &Value, instance: &Value) -> bool { + match declared { + Value::String(name) => matches_name(name, instance), + Value::Array(names) => names + .iter() + .filter_map(Value::as_str) + .any(|name| matches_name(name, instance)), + _ => false, + } +} + +fn matches_name(name: &str, instance: &Value) -> bool { + match name { + "object" => instance.is_object(), + "array" => instance.is_array(), + "string" => instance.is_string(), + "boolean" => instance.is_boolean(), + "null" => instance.is_null(), + "integer" => instance.is_i64() || instance.is_u64(), + "number" => instance.is_number(), + _ => false, + } +} + +/// Resolve a local `#/definitions/` reference. +fn resolve<'a>(root: &'a Value, reference: &str) -> Result<&'a Value, String> { + let name = reference + .strip_prefix("#/definitions/") + .ok_or_else(|| format!("{reference} is not a local definition reference"))?; + root.get("definitions") + .and_then(|definitions| definitions.get(name)) + .ok_or_else(|| format!("{reference} names no definition")) +} From c8a4188943a978813c3b10a3441666b787b0155a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 04:52:17 -0700 Subject: [PATCH 717/726] fix(xtask): document the audit response page as the wire carries it `AuditResponse` holds `entries` and a `page_end`, and its hand-written `Serialize` projects that into the flat `entries`, `nextCursor`, and `complete` keys the protocol has always carried. The response tables read the struct's in-memory fields, so the published row documented a `page_end: AuditPageEnd` member no consumer ever receives. The row now follows the type's hand-written `JsonSchema`, which delegates to the wire struct that publishes the same three keys. A type whose schema delegates is documented from the shape it publishes; every other row still renders its own fields, and the regenerated table differs on that row alone. --- .../refactor-rust-skills-remediation.md | 1 + docs/reference/daemon-api.md | 2 +- packages/xtask/src/main.rs | 110 ++++++++++++++++-- 3 files changed, 105 insertions(+), 8 deletions(-) diff --git a/changelog.d/refactor-rust-skills-remediation.md b/changelog.d/refactor-rust-skills-remediation.md index 4feb5960f..6b22ba219 100644 --- a/changelog.d/refactor-rust-skills-remediation.md +++ b/changelog.d/refactor-rust-skills-remediation.md @@ -4,6 +4,7 @@ - Malformed wire input no longer panics the broker, the daemon runtime, or the Wayland policy engine: a malformed authoritative audit join, a malformed broker zone digest, and a malformed driver zone token now return typed refusals at those boundaries. - Moved blocking reaping, file locking, ACL application, and NSS group lookup off the broker's async executor workers, so a busy executor no longer stalls on host syscalls. - The published v2 storage lifecycle report schema now names each issue field the way the daemon writes it, so a consumer validating a real report no longer rejects the five issue variants that carry a renamed field. +- The daemon API reference now documents an audit response page as the wire carries it - entries, the continuing cursor, and completion - rather than as the daemon holds it in memory. ### Changed diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index dbdad9644..1c37dfa32 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -383,7 +383,7 @@ see the auto-generated tables above for the committed Rust variants. | `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2252) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | | `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2261) | struct { `vms`: `Vec`; `read_model`: `Option` } | | `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2269) | struct { `entries`: `Vec`; `read_model`: `Option` } | -| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2349) | struct { `entries`: `Vec`; `page_end`: `AuditPageEnd` } | +| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2349) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | | `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2664) | struct { `entries`: `Vec` } | ### Broker socket response types diff --git a/packages/xtask/src/main.rs b/packages/xtask/src/main.rs index e99a4842f..dc0044343 100644 --- a/packages/xtask/src/main.rs +++ b/packages/xtask/src/main.rs @@ -1,6 +1,7 @@ #![recursion_limit = "256"] use std::{ + collections::BTreeMap, env, fs, path::{Path, PathBuf}, sync::LazyLock, @@ -108,6 +109,11 @@ struct RustItem { line: usize, fields: Vec, variants: Vec, + /// The fields of the struct this type's hand-written `JsonSchema` + /// publishes, when it delegates to one. The table documents the wire, + /// so a type that serializes to a different shape than it holds in + /// memory is documented from its published schema instead. + published_fields: Option>, } fn main() -> std::process::ExitCode { @@ -1140,8 +1146,11 @@ fn parse_rust_items( offsets: &offsets, file_rel: &file_rel, items: &mut items, + struct_fields: BTreeMap::new(), + schema_delegates: Vec::new(), }; - syn::visit::Visit::visit_file(&mut collector, &syntax); + syn::visit::visit_file(&mut collector, &syntax); + collector.resolve_published_shapes(); Ok(items) } @@ -1155,27 +1164,88 @@ struct IpcItemCollector<'a> { offsets: &'a LineOffsets, file_rel: &'a str, items: &'a mut Vec, + /// The named fields of every struct in the file, public or private, so + /// a `JsonSchema` delegate resolves to the shape it publishes. + struct_fields: BTreeMap>, + /// `(owner, candidate)` pairs named by a hand-written `JsonSchema` + /// impl, resolved against `struct_fields` after the file is walked. + schema_delegates: Vec<(String, String)>, +} + +impl IpcItemCollector<'_> { + /// Point every collected type at the fields its hand-written + /// `JsonSchema` publishes. Resolved after the walk so a delegate + /// declared below its impl still counts. + fn resolve_published_shapes(&mut self) { + for (owner, candidate) in std::mem::take(&mut self.schema_delegates) { + let Some(published) = self.struct_fields.get(&candidate).cloned() else { + continue; + }; + for item in self.items.iter_mut() { + if item.name == owner { + item.published_fields = Some(published.clone()); + } + } + } + } } impl<'ast> syn::visit::Visit<'ast> for IpcItemCollector<'_> { fn visit_item_struct(&mut self, item: &'ast syn::ItemStruct) { - if !matches!(item.vis, syn::Visibility::Public(_)) { - return; - } let fields = match &item.fields { syn::Fields::Named(fields) => collect_named_fields(self.text, self.offsets, fields), _ => Vec::new(), }; + let name = item.ident.to_string(); + if !fields.is_empty() { + self.struct_fields.insert(name.clone(), fields.clone()); + } + if !matches!(item.vis, syn::Visibility::Public(_)) { + return; + } self.items.push(RustItem { - name: item.ident.to_string(), + name, kind: ItemKind::Struct, file_rel: self.file_rel.to_owned(), line: item.struct_token.span.start().line, fields, variants: Vec::new(), + published_fields: None, }); } + /// A type that hand-writes `JsonSchema` publishes another type's shape. + /// Record the pair so the response tables document the published wire + /// rather than the in-memory struct a hand-written `Serialize` reads + /// from. + fn visit_item_impl(&mut self, item: &'ast syn::ItemImpl) { + if !item.trait_.as_ref().is_some_and(|(_, path, _)| { + path.segments + .last() + .is_some_and(|last| last.ident == "JsonSchema") + }) + { + return; + } + let syn::Type::Path(owner) = &*item.self_ty else { + return; + }; + if owner.qself.is_some() || owner.path.segments.len() != 1 { + return; + } + let owner = owner.path.segments[0].ident.to_string(); + let mut delegate = None; + syn::visit::visit_item_impl(self, item); + let mut finder = SchemaDelegateFinder { + owner: &owner, + delegate: &mut delegate, + }; + syn::visit::visit_item_impl(&mut finder, item); + if let Some(delegate) = delegate { + self.schema_delegates.push((owner, delegate)); + } + } + fn visit_item_enum(&mut self, item: &'ast syn::ItemEnum) { if !matches!(item.vis, syn::Visibility::Public(_)) { return; @@ -1216,10 +1286,35 @@ impl<'ast> syn::visit::Visit<'ast> for IpcItemCollector<'_> { line: item.enum_token.span.start().line, fields: Vec::new(), variants, + published_fields: None, }); } } +/// Finds the type a hand-written `JsonSchema` impl names first in its body, +/// so the response tables can document the published wire rather than the +/// in-memory struct a hand-written `Serialize` reads from. Whether the name +/// is a struct of this file is decided after the walk, so a delegate +/// declared below its impl still resolves. +struct SchemaDelegateFinder<'a, 'b> { + owner: &'a str, + delegate: &'b mut Option, +} + +impl<'ast> syn::visit::Visit<'ast> for SchemaDelegateFinder<'_, '_> { + fn visit_expr_path(&mut self, expr: &'ast syn::ExprPath) { + if self.delegate.is_none() + && let Some(first) = expr.path.segments.first() + { + let candidate = first.ident.to_string(); + if candidate != *self.owner { + *self.delegate = Some(candidate); + } + } + syn::visit::visit_expr_path(self, expr); + } +} + /// Line start offsets, so a span position resolves to a byte offset in O(1) /// instead of a per-span scan of the whole file. struct LineOffsets { @@ -1285,10 +1380,11 @@ fn render_fields(fields: &[Field]) -> String { fn render_shape(item: &RustItem) -> String { match item.kind { ItemKind::Struct => { - if item.fields.is_empty() { + let fields = item.published_fields.as_deref().unwrap_or(&item.fields); + if fields.is_empty() { "empty struct".to_string() } else { - format!("struct {{ {} }}", render_fields(&item.fields)) + format!("struct {{ {} }}", render_fields(fields)) } } ItemKind::Enum => { From 2317e1980d0c35d6469f544e30599ab10440dea2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 04:52:22 -0700 Subject: [PATCH 718/726] docs(census): correct the recorded call site behind the device block_on row The baseline raises `tokio::runtime::Runtime::block_on` from 0 to 1 for `packages/d2b-provider-device`, and a text search of that crate finds no `block_on` at all: a source grep cannot see a `#[tokio::test]` expansion. The census decides the question. Run in its write mode on a clean tree it still reports 1 for that crate, and the crate holds exactly one `#[tokio::test]`, at `tests/device_family.rs:157`. The row is therefore a real counted site, not stale headroom, and it stays. Only the recorded site was wrong: it named `tests/device_family.rs:179`, the closing line of an assertion inside the test and not the attribute the expansion comes from. --- changelog.d/refactor-rust-skills-remediation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.d/refactor-rust-skills-remediation.md b/changelog.d/refactor-rust-skills-remediation.md index 6b22ba219..49ad70a32 100644 --- a/changelog.d/refactor-rust-skills-remediation.md +++ b/changelog.d/refactor-rust-skills-remediation.md @@ -5,6 +5,7 @@ - Moved blocking reaping, file locking, ACL application, and NSS group lookup off the broker's async executor workers, so a busy executor no longer stalls on host syscalls. - The published v2 storage lifecycle report schema now names each issue field the way the daemon writes it, so a consumer validating a real report no longer rejects the five issue variants that carry a renamed field. - The daemon API reference now documents an audit response page as the wire carries it - entries, the continuing cursor, and completion - rather than as the daemon holds it in memory. +- The blocking-API baseline row for the device Provider's `block_on` count is real and stays; its recorded call site named a line inside the test, and the census counts the async test attribute that expands to the call. ### Changed From 30033948e9f899995093a96ffcac27697500c657 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 05:56:02 -0700 Subject: [PATCH 719/726] docs: drop planning markers and stale pointers from shipped files Internal planning identifiers had leaked into shipped source, config and changelog fragments, and one plan appendix still pointed at a corpus directory that commit 564bd6166 removed, so its counts could not be checked from the tree at all. The markers carry no information a reader needs: each reason's technical content stays and only the unit label goes. The plan's appendix now records its own counts instead of citing a path the tree no longer has, and the census fragment states why the device Provider's `block_on` cap is 1 - the single async test expands to that call and the base's suppressive allow is gone - rather than claiming to correct a call-site record the baseline never held. The async-gate doc comment now names the `lock_api` deny-list entries this branch put in place of the `parking_lot` aliases, and deny.toml keeps its duplicate-cluster inventory without naming the audit corpus or carrying a review date. --- changelog.d/refactor-rust-skills-remediation.md | 2 +- changelog.d/w3-38-d2bd-conc-async.md | 2 +- clippy.toml | 6 +++--- deny.toml | 5 ++--- .../2026-09-24-002-refactor-rust-skills-remediation-plan.md | 4 +++- packages/d2b-broker/src/ops/host_generation_handoff.rs | 4 ++-- packages/d2b-broker/src/sys.rs | 6 +++--- packages/d2b-provider-device-tpm/src/effects_service.rs | 4 ++-- packages/d2b-provider-user/src/probe.rs | 2 +- packages/d2bd-runtime/src/concurrency.rs | 2 +- packages/d2bd-runtime/src/unsafe_local_helper.rs | 2 +- packages/xtask/src/async_gate.rs | 2 +- 12 files changed, 21 insertions(+), 20 deletions(-) diff --git a/changelog.d/refactor-rust-skills-remediation.md b/changelog.d/refactor-rust-skills-remediation.md index 49ad70a32..7bb89601d 100644 --- a/changelog.d/refactor-rust-skills-remediation.md +++ b/changelog.d/refactor-rust-skills-remediation.md @@ -5,7 +5,7 @@ - Moved blocking reaping, file locking, ACL application, and NSS group lookup off the broker's async executor workers, so a busy executor no longer stalls on host syscalls. - The published v2 storage lifecycle report schema now names each issue field the way the daemon writes it, so a consumer validating a real report no longer rejects the five issue variants that carry a renamed field. - The daemon API reference now documents an audit response page as the wire carries it - entries, the continuing cursor, and completion - rather than as the daemon holds it in memory. -- The blocking-API baseline row for the device Provider's `block_on` count is real and stays; its recorded call site named a line inside the test, and the census counts the async test attribute that expands to the call. +- The device Provider's blocking-API `block_on` cap moved from 0 to 1: its one async test expands to that call, and the suppressive `allow` the base carried on that test is gone, so the census now counts it. ### Changed diff --git a/changelog.d/w3-38-d2bd-conc-async.md b/changelog.d/w3-38-d2bd-conc-async.md index 3291880d3..ce7a20905 100644 --- a/changelog.d/w3-38-d2bd-conc-async.md +++ b/changelog.d/w3-38-d2bd-conc-async.md @@ -1,3 +1,3 @@ ### Fixed -- The effect-service binding revision counters and the broker-epoch generation mint now use the weakest correct orderings (`Relaxed` loads/stores/fetch_updates) instead of `SeqCst`: the revision is a version tag read only for staleness equality and the generation is a unique-value mint, so the standalone atomics carry no paired publication needing acquisition/release (plan U23 ordering-seat relaxations). +- The effect-service binding revision counters and the broker-epoch generation mint now use the weakest correct orderings (`Relaxed` loads/stores/fetch_updates) instead of `SeqCst`: the revision is a version tag read only for staleness equality and the generation is a unique-value mint, so the standalone atomics carry no paired publication needing acquisition/release. diff --git a/clippy.toml b/clippy.toml index d7a9b23ab..a189feb30 100644 --- a/clippy.toml +++ b/clippy.toml @@ -86,9 +86,9 @@ disallowed-methods = [ # definition the call ends up at, so the three entries below name the # resolved `lock_api` paths. `parking_lot::Condvar` below is a real type, # not an alias, and keeps its own name. - { path = "lock_api::Mutex::lock", reason = "Blocking lock reached through the parking_lot alias (`parking_lot::Mutex` is `lock_api::Mutex`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::Mutex::lock" }, - { path = "lock_api::RwLock::read", reason = "Blocking read lock reached through the parking_lot alias (`parking_lot::RwLock` is `lock_api::RwLock`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::RwLock::read" }, - { path = "lock_api::RwLock::write", reason = "Blocking write lock reached through the parking_lot alias (`parking_lot::RwLock` is `lock_api::RwLock`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked (plan KD3)", replacement = "tokio::sync::RwLock::write" }, + { path = "lock_api::Mutex::lock", reason = "Blocking lock reached through the parking_lot alias (`parking_lot::Mutex` is `lock_api::Mutex`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked", replacement = "tokio::sync::Mutex::lock" }, + { path = "lock_api::RwLock::read", reason = "Blocking read lock reached through the parking_lot alias (`parking_lot::RwLock` is `lock_api::RwLock`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked", replacement = "tokio::sync::RwLock::read" }, + { path = "lock_api::RwLock::write", reason = "Blocking write lock reached through the parking_lot alias (`parking_lot::RwLock` is `lock_api::RwLock`), and the guard it returns cannot be held across an await; the parking_lot carve-out is revoked", replacement = "tokio::sync::RwLock::write" }, # --- Condition variables --------------------------------------------- { path = "std::sync::Condvar::wait", reason = "Parks the caller until another thread notifies; on a single-threaded runtime the notifier is the parked worker itself, so the wait can never be satisfied", replacement = "arm tokio::sync::Notify before the check, then tokio::time::timeout" }, diff --git a/deny.toml b/deny.toml index 45c708dd6..ce5d79aee 100644 --- a/deny.toml +++ b/deny.toml @@ -1,9 +1,8 @@ [bans] multiple-versions = "warn" wildcards = "deny" -# Accepted duplicate clusters (rust-skills audit, reviewed 2026-09-25). cargo-deny -# reports these on every run; each entry names the versions, the pullers, and -# the re-check trigger. The clusters +# Accepted duplicate clusters. cargo-deny reports these on every run; each +# entry names the versions, the pullers, and the re-check trigger. The clusters # below are accepted because the pullers' version ranges genuinely do not # unify (no lower-bound raise reaches both legs). multiple-versions stays # "warn" until the workspace-direct clusters resolve; a warn-to-deny flip diff --git a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md index 010bd11d2..68b03d840 100644 --- a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md +++ b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md @@ -328,7 +328,9 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha ### Wave to cluster map -Counts are the audit's own cluster membership (`README.md` section 6); each wave executes the lane files behind them. +Counts are the per-lens cluster membership this plan applied, recorded here +because the audit record itself is not part of the shipped tree; each wave +executes the rows behind them. | wave | lenses and clusters | findings | | --- | --- | ---: | diff --git a/packages/d2b-broker/src/ops/host_generation_handoff.rs b/packages/d2b-broker/src/ops/host_generation_handoff.rs index 1e6aaf15e..7c498b531 100644 --- a/packages/d2b-broker/src/ops/host_generation_handoff.rs +++ b/packages/d2b-broker/src/ops/host_generation_handoff.rs @@ -276,8 +276,8 @@ struct HandoffLockJob { } /// The bounded worker that owns the blocking `flock(2)` wait for the -/// per-state-dir handoff lock (plan R4: a blocking `sync_channel` recv on -/// the worker's own dedicated thread, with `tokio::sync::oneshot` replies). +/// per-state-dir handoff lock: a blocking `sync_channel` recv on +/// the worker's own dedicated thread, with `tokio::sync::oneshot` replies. /// The wait can be long - the lock is held for the whole apply/replay /// critical section of the previous holder - so it must not park an /// executor worker; the dedicated thread blocks instead, and the caller diff --git a/packages/d2b-broker/src/sys.rs b/packages/d2b-broker/src/sys.rs index 2fda7b32e..ad67b8d78 100644 --- a/packages/d2b-broker/src/sys.rs +++ b/packages/d2b-broker/src/sys.rs @@ -1964,9 +1964,9 @@ pub mod pidfd_sys { reply: tokio::sync::oneshot::Sender>, } - /// The bounded worker that owns the blocking `setfacl` fork/exec/wait - /// (plan R4: a blocking `sync_channel` recv on the worker's own - /// dedicated thread, with `tokio::sync::oneshot` replies). The shellout + /// The bounded worker that owns the blocking `setfacl` fork/exec/wait: + /// a blocking `sync_channel` recv on the worker's own + /// dedicated thread, with `tokio::sync::oneshot` replies. The shellout /// has no async form and can take arbitrarily long (a wedged host can /// stall the child), so it must not run on an executor worker; the /// dedicated thread blocks instead, and the caller awaits the outcome. diff --git a/packages/d2b-provider-device-tpm/src/effects_service.rs b/packages/d2b-provider-device-tpm/src/effects_service.rs index 1c8dca19d..498400b4e 100644 --- a/packages/d2b-provider-device-tpm/src/effects_service.rs +++ b/packages/d2b-provider-device-tpm/src/effects_service.rs @@ -443,7 +443,7 @@ impl LiveTpmResourceEffectPort<'_> { // resolution runs on the bounded probe seat: a slow or wedged // backend (LDAP/NIS) refuses later probes rather than parking // this executor worker for the lookup (`spawn_blocking` is - // banned by plan KD2; the seat is the house replacement). + // banned; the seat is the house replacement). let (owner_uid, owner_gid, mode) = { let spec = spec.clone(); loader_worker::run_probe(move || row_posture(&spec)) @@ -479,7 +479,7 @@ impl LiveTpmResourceEffectPort<'_> { // write, reply poll, frame read) with no async form in the tree, so // it runs on the bounded kernel seat under the same io budget: the // executor worker is never parked for the leg (`spawn_blocking` is - // banned by plan KD2; the seat is the house replacement). + // banned; the seat is the house replacement). let socket_path = self.facets.runtime.broker_socket_path().to_path_buf(); let io_timeout = self.facets.runtime.kernel_io_timeout(); let caller_role = self.facets.runtime.caller_role(); diff --git a/packages/d2b-provider-user/src/probe.rs b/packages/d2b-provider-user/src/probe.rs index 130669359..09543ed3a 100644 --- a/packages/d2b-provider-user/src/probe.rs +++ b/packages/d2b-provider-user/src/probe.rs @@ -9,7 +9,7 @@ //! The reads have no async form, so the probe runs the whole blocking body //! on `d2b-core`'s bounded loader probe seat: a slow or wedged backend //! (LDAP/NIS) refuses later probes rather than parking this executor -//! worker for the lookup (`spawn_blocking` is banned by plan KD2; the seat +//! worker for the lookup (`spawn_blocking` is banned; the seat //! is the house replacement). use d2b_contracts_resource::v3::{ResourceRef, user::UserSpec}; diff --git a/packages/d2bd-runtime/src/concurrency.rs b/packages/d2bd-runtime/src/concurrency.rs index 3031eb4a4..7e7ae082a 100644 --- a/packages/d2bd-runtime/src/concurrency.rs +++ b/packages/d2bd-runtime/src/concurrency.rs @@ -117,7 +117,7 @@ pub enum OpLockClass { /// Per-VM + global in-process op locks. Cheaply [`Clone`]able (all state /// behind `Arc`) so it can live inside the `Clone` `ServerState`. /// -/// The locks are `tokio::sync` primitives (async purity, plan U17). +/// The locks are `tokio::sync` primitives (kept off async contexts). /// Production dispatch runs on dedicated `d2b-conn` handler threads, so /// `acquire` parks them on the blocking seats; the `--once` serve path /// dispatches inline on the accept loop's runtime worker, where those seats diff --git a/packages/d2bd-runtime/src/unsafe_local_helper.rs b/packages/d2bd-runtime/src/unsafe_local_helper.rs index fab2b56c9..6b218731b 100644 --- a/packages/d2bd-runtime/src/unsafe_local_helper.rs +++ b/packages/d2bd-runtime/src/unsafe_local_helper.rs @@ -237,7 +237,7 @@ struct RegistryState { /// Tracks per-UID helper generations, snapshots, and operation /// completions; all peer contact flows through [`Self::accept_loop`]. /// -/// The mutexes are `tokio::sync` primitives (async purity, plan U17) +/// The mutexes are `tokio::sync` primitives (kept off async contexts) /// reached through the `lock_registry` helper: the accept loop, its /// per-connection handler threads, and the daemon's `d2b-conn` dispatch /// thread park on the blocking seat, while a runtime worker (the `--once` diff --git a/packages/xtask/src/async_gate.rs b/packages/xtask/src/async_gate.rs index 7f3e7f7ee..e96944989 100644 --- a/packages/xtask/src/async_gate.rs +++ b/packages/xtask/src/async_gate.rs @@ -295,7 +295,7 @@ pub fn scan_source( } /// The method names of the mutex/rwlock lock-acquisition entries on the deny -/// list (`std::sync`/`parking_lot` `Mutex::lock`, `RwLock::read`, +/// list (`std::sync`/`lock_api` `Mutex::lock`, `RwLock::read`, /// `RwLock::write`): the conservative method-call shape the scanner flags /// inside async contexts. Derived from the deny list so the list stays the /// single source of truth - a new lock entry arms the gate automatically. From 5001d7b269eade9fc6e29a271f5ba2200b40f93d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 05:56:08 -0700 Subject: [PATCH 720/726] cli: report only parser-known commands in auth status The `none` role's allowed list was a hand-typed literal naming `realm list` and `realm inspect`, which this branch's parser no longer accepts - the same response told a caller with no role that two retired verbs were allowed while telling a launcher they were not. The daemon half reported those verbs plus `realm enter`, `realm run` and `host check`, none of which the parser declares either, and nothing covered either list, so the drift could not be caught. Both halves now read one shared read-only list of command paths, and a test walks the parser's own command tree to prove every name each half reports resolves to a declared subcommand. A retired verb reintroduced on either side fails that test. The daemon API reference and the async-gate inventory are regenerated through their owning tools, so their line anchors follow the moved types and marker sites. --- .../refactor-rust-skills-remediation.md | 1 + docs/reference/daemon-api.md | 44 ++++++++-------- .../d2b-contracts-control/src/public_wire.rs | 10 ++++ packages/d2b/src/dispatch.rs | 50 +++++++++++++++---- packages/d2b/tests/auth_status_contract.rs | 11 +--- packages/d2bd/src/composition.rs | 42 +++++++--------- packages/xtask/data/async-gate-inventory.json | 4 +- 7 files changed, 93 insertions(+), 69 deletions(-) diff --git a/changelog.d/refactor-rust-skills-remediation.md b/changelog.d/refactor-rust-skills-remediation.md index 7bb89601d..4f135b432 100644 --- a/changelog.d/refactor-rust-skills-remediation.md +++ b/changelog.d/refactor-rust-skills-remediation.md @@ -6,6 +6,7 @@ - The published v2 storage lifecycle report schema now names each issue field the way the daemon writes it, so a consumer validating a real report no longer rejects the five issue variants that carry a renamed field. - The daemon API reference now documents an audit response page as the wire carries it - entries, the continuing cursor, and completion - rather than as the daemon holds it in memory. - The device Provider's blocking-API `block_on` cap moved from 0 to 1: its one async test expands to that call, and the suppressive `allow` the base carried on that test is gone, so the census now counts it. +- `d2b auth status` no longer reports retired commands as allowed: the read-only surface for a caller with no role, and the launcher and admin surfaces the daemon reports, now name only commands the CLI parser accepts, and both halves of the response read one shared list so they cannot disagree. ### Changed diff --git a/docs/reference/daemon-api.md b/docs/reference/daemon-api.md index 1c37dfa32..03e994a34 100644 --- a/docs/reference/daemon-api.md +++ b/docs/reference/daemon-api.md @@ -381,10 +381,10 @@ see the auto-generated tables above for the committed Rust variants. | `MutatingVerbResponse` | struct | [`MutatingVerbResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2216) | struct { `verb`: `String`; `outcome`: `MutatingVerbOutcome`; `target_wave`: `Option`; `summary`: `Option`; `remediation`: `Option`; `api_ready`: `Option` } | | `CapabilitiesResponse` | struct | [`CapabilitiesResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2242) | struct { `broker_socket`: `String`; `capabilities`: `Vec`; `public_socket`: `String`; `server_version`: `Version`; `selected_version`: `Version` } | | `AuthStatusResponse` | struct | [`AuthStatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2252) | struct { `allowed_subcommands`: `Vec`; `denied_subcommands`: `Vec`; `role`: `AuthRole`; `sockets`: `Vec` } | -| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2261) | struct { `vms`: `Vec`; `read_model`: `Option` } | -| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2269) | struct { `entries`: `Vec`; `read_model`: `Option` } | -| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2349) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | -| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2664) | struct { `entries`: `Vec` } | +| `ListResponse` | struct | [`ListResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2271) | struct { `vms`: `Vec`; `read_model`: `Option` } | +| `StatusResponse` | struct | [`StatusResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2279) | struct { `entries`: `Vec`; `read_model`: `Option` } | +| `AuditResponse` | struct | [`AuditResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2359) | struct { `entries`: `Vec`; `next_cursor`: `Option`; `complete`: `bool` } | +| `UsbipProbeResponse` | struct | [`UsbipProbeResponse`](../../packages/d2b-contracts-control/src/public_wire.rs#L2674) | struct { `entries`: `Vec` } | ### Broker socket response types @@ -492,7 +492,7 @@ running live guest activation. | Type | Kind | Rust definition | Shape | | --- | --- | --- | --- | -| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2830) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | +| `VmLifecycleState` | enum | [`VmLifecycleState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2840) | `Stopped`; `Starting`; `Booted`; `Running`; `Stopping`; `Restarting`; `Failed`; `Unknown` | ### Other documented enums @@ -542,23 +542,23 @@ running live guest activation. | `AudioOp` | enum | [`AudioOp`](../../packages/d2b-contracts-control/src/public_wire.rs#L2062) | `Status` - (AudioStatusArgs); `SetVolume` - (AudioSetVolumeArgs); `Mute` - (AudioMuteArgs) | | `AudioSetApplied` | enum | [`AudioSetApplied`](../../packages/d2b-contracts-control/src/public_wire.rs#L2125) | `HostAndGuest`; `HostOnly`; `GuestOnly`; `Unsupported` | | `MutatingVerbOutcome` | enum | [`MutatingVerbOutcome`](../../packages/d2b-contracts-control/src/public_wire.rs#L2231) | `DryRunPlanned`; `Applied`; `ApiReadyTimeout`; `NotYetImplemented`; `BrokerError`; `InvalidRequest` | -| `PublicReadModelKind` | enum | [`PublicReadModelKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2295) | `List`; `Status` | -| `AuditPageEnd` | enum | [`AuditPageEnd`](../../packages/d2b-contracts-control/src/public_wire.rs#L2310) | `Complete`; `More` - (AuditExportCursor) | -| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2423) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | -| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2441) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | -| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2466) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | -| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2479) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | -| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2493) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | -| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2516) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | -| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2534) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | -| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2547) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | -| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2566) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | -| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2602) | `Usbip`; `QemuMediaSlot` | -| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2685) | `Human`; `Json` | -| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2693) | `None`; `Launcher`; `Admin` | -| `VmAutostartMode` | enum | [`VmAutostartMode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2873) | `ManualOnly` | -| `QemuMediaRunnerState` | enum | [`QemuMediaRunnerState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2907) | `Running`; `Stopped` | -| `QemuMediaRegistryState` | enum | [`QemuMediaRegistryState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2942) | `DirectConfig`; `Present`; `Stale`; `Missing` | +| `PublicReadModelKind` | enum | [`PublicReadModelKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2305) | `List`; `Status` | +| `AuditPageEnd` | enum | [`AuditPageEnd`](../../packages/d2b-contracts-control/src/public_wire.rs#L2320) | `Complete`; `More` - (AuditExportCursor) | +| `UsbipProbeStatus` | enum | [`UsbipProbeStatus`](../../packages/d2b-contracts-control/src/public_wire.rs#L2433) | `Bound`; `Unbound`; `Degraded`; `Enrollable`; `Enrolled`; `Stale`; `DirectConfig`; `Unknown` | +| `UsbipDurableClaimState` | enum | [`UsbipDurableClaimState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2451) | `Missing`; `HeldByDesiredOwner`; `HeldByOtherOwner`; `StaleOwner`; `Corrupt`; `NotApplicable`; `Unknown` | +| `UsbipHostBindState` | enum | [`UsbipHostBindState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2476) | `Unbound`; `BoundToUsbipHost`; `BoundToUnexpectedDriver`; `DeviceMissing`; `NotApplicable`; `Unknown` | +| `UsbipHostCarrierState` | enum | [`UsbipHostCarrierState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2489) | `Absent`; `Unavailable`; `WithheldForOwner`; `Ready`; `DepartedDuringProbe`; `NotApplicable`; `Unknown` | +| `UsbipProxyState` | enum | [`UsbipProxyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2503) | `NotDeclared`; `Stopped`; `Starting`; `Listening`; `Stale`; `Failed`; `NotApplicable`; `Unknown` | +| `UsbipGuestImportState` | enum | [`UsbipGuestImportState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2526) | `Detached`; `Imported`; `Unavailable`; `NotApplicable`; `Unknown` | +| `UsbipTopologyState` | enum | [`UsbipTopologyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2544) | `Match`; `Mismatch`; `Incomplete`; `NotObserved`; `NotApplicable`; `Unknown` | +| `UsbipPolicyState` | enum | [`UsbipPolicyState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2557) | `Allowed`; `Denied`; `Missing`; `NotApplicable`; `Unknown` | +| `UsbipProbeDegradedReasonCode` | enum | [`UsbipProbeDegradedReasonCode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2576) | `PolicyFailed`; `DeviceDepartedBeforeClaim`; `DeviceDepartedAfterLock`; `DeviceDepartedDuringMutation`; `DeviceReappearedWithDifferentTopology`; `LockHeldByOtherOwner`; `InvalidPersistedLockClaim`; `CarrierUnavailable`; `HostBindUnavailable`; `ProxyUnavailable`; `GuestImportUnavailable`; `StaleHostState`; `StaleGuestState`; `ProbeIncomplete`; `Unknown` | +| `UsbProbeEntryKind` | enum | [`UsbProbeEntryKind`](../../packages/d2b-contracts-control/src/public_wire.rs#L2612) | `Usbip`; `QemuMediaSlot` | +| `AuditFormat` | enum | [`AuditFormat`](../../packages/d2b-contracts-control/src/public_wire.rs#L2695) | `Human`; `Json` | +| `AuthRole` | enum | [`AuthRole`](../../packages/d2b-contracts-control/src/public_wire.rs#L2703) | `None`; `Launcher`; `Admin` | +| `VmAutostartMode` | enum | [`VmAutostartMode`](../../packages/d2b-contracts-control/src/public_wire.rs#L2883) | `ManualOnly` | +| `QemuMediaRunnerState` | enum | [`QemuMediaRunnerState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2917) | `Running`; `Stopped` | +| `QemuMediaRegistryState` | enum | [`QemuMediaRegistryState`](../../packages/d2b-contracts-control/src/public_wire.rs#L2952) | `DirectConfig`; `Present`; `Stale`; `Missing` | | `TerminalStream` | enum | [`TerminalStream`](../../packages/d2b-contracts-control/src/terminal_wire.rs#L13) | `Stdout`; `Stderr` | | `HelperScopeKind` | enum | [`HelperScopeKind`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L68) | `LauncherApp`; `WaylandProxy` | | `HelperScopeState` | enum | [`HelperScopeState`](../../packages/d2b-contracts-control/src/unsafe_local_wire.rs#L95) | `Starting`; `Active`; `Stopping`; `Exited`; `Degraded` | diff --git a/packages/d2b-contracts-control/src/public_wire.rs b/packages/d2b-contracts-control/src/public_wire.rs index 202fa1ccc..d2c386396 100644 --- a/packages/d2b-contracts-control/src/public_wire.rs +++ b/packages/d2b-contracts-control/src/public_wire.rs @@ -2256,6 +2256,16 @@ pub struct AuthStatusResponse { pub sockets: Vec, } +/// The read-only `d2b` command paths a peer may run, spelled the way the CLI +/// parser names them (`` or ` `). +/// +/// Both halves of the `auth status` response draw their read-only surface from +/// this one list - the CLI's `none` role and the daemon's launcher report are +/// the same set - so the two halves cannot name different surfaces. The CLI +/// is the only side that owns the parser, so its own test parses every entry +/// here: a retired verb cannot be added without that test failing. +pub const READ_ONLY_CLI_COMMANDS: &[&str] = &["list", "status", "auth status", "op inspect"]; + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ListResponse { diff --git a/packages/d2b/src/dispatch.rs b/packages/d2b/src/dispatch.rs index 3527cbeb1..b64dc37f3 100644 --- a/packages/d2b/src/dispatch.rs +++ b/packages/d2b/src/dispatch.rs @@ -702,17 +702,10 @@ pub(crate) fn allowed_subcommands(role: AuthRoleV2) -> BTreeSet { .into_iter() .filter(|command| command != "audit") .collect(), - AuthRoleV2::None => [ - "list", - "status", - "auth status", - "op inspect", - "realm list", - "realm inspect", - ] - .into_iter() - .map(str::to_owned) - .collect(), + AuthRoleV2::None => public_wire::READ_ONLY_CLI_COMMANDS + .iter() + .map(|command| (*command).to_owned()) + .collect(), } } @@ -1171,6 +1164,41 @@ mod tests { assert!(ModernCli::try_parse_from(["d2b", "unknown-provider-command"]).is_err()); } + /// Whether the parser declares `path` as a chain of subcommand names. + /// Arguments are deliberately not supplied: a verb whose positional is + /// required (`list`, `status`) is still a command the parser declares, + /// and what this proves is that the name resolves at all. + fn parser_declares_command_path(path: &str) -> bool { + let mut command = ModernCli::command(); + for name in path.split(' ') { + let Some(subcommand) = command.find_subcommand(name).cloned() else { + return false; + }; + command = subcommand; + } + true + } + + #[test] + fn every_reported_allowed_subcommand_is_a_command_the_parser_declares() { + for role in [AuthRoleV2::None, AuthRoleV2::Launcher, AuthRoleV2::Admin] { + for command in allowed_subcommands(role) { + assert!( + parser_declares_command_path(&command), + "role {role:?} reports `{command}` as allowed, but the parser declares no such command" + ); + } + } + // The daemon half of the response reports the shared read-only list + // and does not own a parser, so its names are proved here instead. + for command in public_wire::READ_ONLY_CLI_COMMANDS { + assert!( + parser_declares_command_path(command), + "the daemon reports `{command}` as allowed, but the parser declares no such command" + ); + } + } + #[test] fn modern_parser_covers_manifest_owned_command_surfaces() { for args in [ diff --git a/packages/d2b/tests/auth_status_contract.rs b/packages/d2b/tests/auth_status_contract.rs index 801911e05..40d322289 100644 --- a/packages/d2b/tests/auth_status_contract.rs +++ b/packages/d2b/tests/auth_status_contract.rs @@ -141,15 +141,8 @@ fn auth_status_roles_match_schema_and_authz() { none_allowed.sort(); assert_eq!( none_allowed, - vec![ - "auth status", - "list", - "op inspect", - "realm inspect", - "realm list", - "status", - ], - "none role stays read-only" + vec!["auth status", "list", "op inspect", "status"], + "none role stays read-only, naming only commands the parser accepts" ); // Case 3 - admin: gains `audit`, denies nothing. diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 791bf7e5c..e26974877 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -50,7 +50,7 @@ use d2b_contracts_broker::kernel_client::{ use d2b_resource_types::{KernelCaller, RunnerLookup}; use d2b_contracts_control::public_wire::{ self, AuthRole, AuthStatusResponse, DeniedCommandHint, PublicReadModelKind, - QemuMediaRegistryState, QemuMediaRunnerState, SocketReachability, + QemuMediaRegistryState, QemuMediaRunnerState, READ_ONLY_CLI_COMMANDS, SocketReachability, }; use d2b_contracts_resource::resource_proto as resource_wire; use d2b_contracts_resource::v3::identity::ReconnectGeneration; @@ -23260,38 +23260,30 @@ fn dispatch_audit( } } +/// The read-only command names the CLI parser accepts. The daemon reports the +/// same surface the CLI's `none` role does, so both halves of `auth status` +/// name one list. +fn read_only_command_names() -> Vec { + READ_ONLY_CLI_COMMANDS + .iter() + .map(|command| (*command).to_owned()) + .collect() +} + fn dispatch_auth_status(state: &ServerState, peer: &PeerIdentity) -> Value { let (role, allowed_subcommands, denied_subcommands) = if peer.role == PeerRole::Admin { ( AuthRole::Admin, - vec![ - "list", - "status", - "audit", - "host check", - "auth status", - "op inspect", - "realm list", - "realm inspect", - "realm enter", - "realm run", - ], + read_only_command_names() + .into_iter() + .chain(std::iter::once("audit".to_owned())) + .collect(), Vec::new(), ) } else { ( AuthRole::Launcher, - vec![ - "list", - "status", - "host check", - "auth status", - "op inspect", - "realm list", - "realm inspect", - "realm enter", - "realm run", - ], + read_only_command_names(), vec![DeniedCommandHint { command: "audit".to_owned(), reason: "audit requires admin role in d2b.site.adminUsers".to_owned(), @@ -23300,7 +23292,7 @@ fn dispatch_auth_status(state: &ServerState, peer: &PeerIdentity) -> Value { }; serde_json::to_value(d2bd_runtime::wire::auth_status_response( AuthStatusResponse { - allowed_subcommands: allowed_subcommands.into_iter().map(str::to_owned).collect(), + allowed_subcommands, denied_subcommands, role, sockets: vec![ diff --git a/packages/xtask/data/async-gate-inventory.json b/packages/xtask/data/async-gate-inventory.json index 23dc77571..da6cafec1 100644 --- a/packages/xtask/data/async-gate-inventory.json +++ b/packages/xtask/data/async-gate-inventory.json @@ -793,12 +793,12 @@ }, { "file": "packages/d2bd/src/composition.rs", - "line": 26649, + "line": 26641, "reason": "synchronous lock acquisition, no await while the guard is held" }, { "file": "packages/d2bd/src/composition.rs", - "line": 27046, + "line": 27038, "reason": "synchronous lock acquisition, no await while the guard is held" }, { From e1c7e85d576301e4e84cdcaf784555fd9b0ca043 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 07:09:33 -0700 Subject: [PATCH 721/726] provider: re-sign the cloud hypervisor artifact and gate the pair The committed Provider signature verified at 88f13fc1e, d3e58b328, and 0d2a5bc17 and broke at 2ca9a22dd, which moved root-config.schema.json and updated the manifest configDigest without re-signing. The old private key is not recoverable, so rotate the publisher keypair rather than re-derive the old one: publisher-public-key.pem carries the new SPKI public key and provider-manifest.json.sig is a fresh raw 64-byte Ed25519 signature over the current manifest bytes. The manifest is byte-for-byte unchanged; only the signature and the public key move. The operator holds the private half outside the repository. Nothing caught the staleness because the Nix build only asserts that the sidecar is 64 bytes long. Add a hermetic test in the resource compiler that loads the committed manifest, sidecar, and public key and asserts the signature verifies over the manifest, with a probe for each half moving alone, so a later manifest or schema change that forgets to re-sign fails the check lane instead of shipping. The test reads the trio from the runfiles tree, and the trio is declared as test data so Bazel re-runs it when any of the three files changes. --- .../fix-provider-artifact-signature.md | 26 ++++++ .../provider-manifest.json.sig | 2 +- .../publisher-public-key.pem | 2 +- packages/d2b-resource-compiler/BUILD.bazel | 15 +++- packages/d2b-resource-compiler/src/lib.rs | 90 +++++++++++++++++++ 5 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 changelog.d/fix-provider-artifact-signature.md diff --git a/changelog.d/fix-provider-artifact-signature.md b/changelog.d/fix-provider-artifact-signature.md new file mode 100644 index 000000000..e35b73040 --- /dev/null +++ b/changelog.d/fix-provider-artifact-signature.md @@ -0,0 +1,26 @@ +### Fixed + +- The committed cloud hypervisor Provider artifact ships a signature that + verifies again. `packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json.sig` + was signed over an earlier manifest, so the commit that moved + `root-config.schema.json` and updated the manifest `configDigest` without + re-signing left the compiler refusing the artifact with + `provider-signature-verification-failed`. The publisher keypair is rotated: + `publisher-public-key.pem` now carries the new SPKI public key and + `provider-manifest.json.sig` is a fresh raw 64-byte Ed25519 signature over + the current manifest bytes. The manifest itself is byte-for-byte unchanged. + The previous private key is not recoverable, so the publisher key changes + rather than being re-derived; the operator holds the new private half + outside the repository, and only its location and public fingerprint are + recorded here. Consumers that pinned the old publisher key must trust the + new public key before building a Zone that installs this artifact. + +### Added + +- A hermetic test in `packages/d2b-resource-compiler` loads the committed + manifest, signature sidecar, and publisher key and asserts the signature + verifies over the manifest, with a probe for each half moving alone. It runs + in the Layer-1 `make check` aggregate, so a future manifest or schema change + that forgets to re-sign fails the gate instead of shipping. The Nix build + only asserted that the sidecar was 64 bytes long, so nothing caught the + staleness before. diff --git a/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json.sig b/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json.sig index 38d778803..9de4d03a0 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json.sig +++ b/packages/d2b-provider-guest-cloud-hypervisor/provider-manifest.json.sig @@ -1 +1 @@ -L˗óÞlïBŒ*e}ýLRܐ­¯фËZ Ћ¹^˜Ë*GÍVèí¯~R€9¶Y-}ùª™¦åfJ’]»Ú¸“bÙ \ No newline at end of file +@ެ+¹anüܭyšWÚYÇ—X«ép3…çx]_dNjª´üÒïT¸ïlÇytx($¶¶sHÔÅN¶R¥‡þ diff --git a/packages/d2b-provider-guest-cloud-hypervisor/publisher-public-key.pem b/packages/d2b-provider-guest-cloud-hypervisor/publisher-public-key.pem index 832614491..80b1758aa 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/publisher-public-key.pem +++ b/packages/d2b-provider-guest-cloud-hypervisor/publisher-public-key.pem @@ -1,3 +1,3 @@ -----BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEAj1WEGxEqg+v6kj43ai6GChZRU8spFROiOaH/4UHoCNs= +MCowBQYDK2VwAyEA8t2y3JtHJ7SVcYOmgtd/YPoB3OGERUZfwewLGLchzcA= -----END PUBLIC KEY----- diff --git a/packages/d2b-resource-compiler/BUILD.bazel b/packages/d2b-resource-compiler/BUILD.bazel index 78d1aa1ca..565568766 100644 --- a/packages/d2b-resource-compiler/BUILD.bazel +++ b/packages/d2b-resource-compiler/BUILD.bazel @@ -86,8 +86,15 @@ d2b_rust_test( name = "d2b_resource_compiler_test", compile_data = ["Cargo.toml"], crate = ":d2b_resource_compiler", - data = [":d2b-resource-compiler"], - env = {"CARGO_BIN_EXE_d2b-resource-compiler": "$(rootpath :d2b-resource-compiler)"}, + data = [ + ":d2b-resource-compiler", + # The committed Publisher artifact trio the signature test reads. + # Declaring it as data both stages the files into the runfiles tree + # and makes Bazel re-run this test when any of them changes. + "//packages/d2b-provider-guest-cloud-hypervisor:provider-manifest.json", + "//packages/d2b-provider-guest-cloud-hypervisor:provider-manifest.json.sig", + "//packages/d2b-provider-guest-cloud-hypervisor:publisher-public-key.pem", + ], rustc_env = {"CARGO_BIN_EXE_d2b-resource-compiler": "$(rootpath :d2b-resource-compiler)"}, deps = ["//packages/d2b-contracts-resource:d2b_contracts_resource", "//packages/d2b-contracts-zone-session:d2b_contracts_zone_session", ] + all_crate_deps(normal = True, normal_dev = True, cargo_only = True), @@ -101,6 +108,10 @@ d2b_rust_test( ":d2b-resource-compiler", "//:d2b_resource_schemas_v3", "//:docs/reference/schemas/v3/audio.d2bus.org_AudioBinding.schema.json", + # The committed Publisher artifact trio the signature test reads. + "//packages/d2b-provider-guest-cloud-hypervisor:provider-manifest.json", + "//packages/d2b-provider-guest-cloud-hypervisor:provider-manifest.json.sig", + "//packages/d2b-provider-guest-cloud-hypervisor:publisher-public-key.pem", ], env = { "CARGO_BIN_EXE_d2b-resource-compiler": "$(rootpath :d2b-resource-compiler)", diff --git a/packages/d2b-resource-compiler/src/lib.rs b/packages/d2b-resource-compiler/src/lib.rs index 3d78f5a6c..a492ea551 100644 --- a/packages/d2b-resource-compiler/src/lib.rs +++ b/packages/d2b-resource-compiler/src/lib.rs @@ -2545,4 +2545,94 @@ mod tests { assert!(decode_ed25519_spki(spki_pem(truncated).as_bytes()).is_none()); } + /// The committed cloud-hypervisor Provider artifact trio, relative to the + /// repository root. `flake.nix` pairs these three files into + /// `providerArtifact`, so they are one reviewable unit. + const COMMITTED_ARTIFACT: [&str; 3] = [ + "provider-manifest.json", + "provider-manifest.json.sig", + "publisher-public-key.pem", + ]; + const COMMITTED_ARTIFACT_DIR: &str = "packages/d2b-provider-guest-cloud-hypervisor"; + + /// The repository root, from the Bazel runfiles tree, the gate's + /// `D2B_REPO_ROOT`, or the cargo manifest directory. The first candidate + /// that carries the artifact directory wins, so the same test runs under + /// `make check` and under `cargo test`. + fn repository_root() -> std::path::PathBuf { + let mut candidates = Vec::new(); + if let (Some(runfiles), Some(workspace)) = ( + std::env::var_os("RUNFILES_DIR"), + std::env::var_os("TEST_WORKSPACE"), + ) { + candidates.push(std::path::PathBuf::from(runfiles).join(workspace)); + } + candidates.extend(std::env::var_os("D2B_REPO_ROOT").map(std::path::PathBuf::from)); + if let Some(manifest_dir) = std::env::var_os("CARGO_MANIFEST_DIR") { + candidates.extend( + std::path::PathBuf::from(manifest_dir) + .parent() + .and_then(std::path::Path::parent) + .map(std::path::Path::to_path_buf), + ); + } + candidates + .into_iter() + .find(|root| { + COMMITTED_ARTIFACT + .iter() + .all(|name| root.join(COMMITTED_ARTIFACT_DIR).join(name).is_file()) + }) + .unwrap_or_else(|| { + panic!( + "{COMMITTED_ARTIFACT_DIR} is not discoverable from the runfiles tree, \ + D2B_REPO_ROOT, or CARGO_MANIFEST_DIR" + ) + }) + } + + /// The committed signature must verify over the committed manifest under + /// the committed publisher key. Nothing in the Nix build re-signs the + /// manifest, so an edit that changes the manifest or its schema without + /// re-signing used to ship a Provider whose signature no longer verified. + #[test] + #[allow(clippy::disallowed_methods, reason = "cfg(test) helper")] + fn committed_artifact_signature_verifies_over_the_committed_manifest() { + let root = repository_root().join(COMMITTED_ARTIFACT_DIR); + let read = |name: &str| { + std::fs::read(root.join(name)) + .unwrap_or_else(|error| panic!("committed {name} is unreadable: {error}")) + }; + let (manifest, signature, public_key) = ( + read(COMMITTED_ARTIFACT[0]), + read(COMMITTED_ARTIFACT[1]), + read(COMMITTED_ARTIFACT[2]), + ); + assert_eq!( + signature.len(), + 64, + "the committed provider-manifest.json.sig is a raw 64-byte Ed25519 signature" + ); + assert!( + verify_ed25519(&public_key, &manifest, &signature), + "the committed publisher-public-key.pem does not verify the committed \ + provider-manifest.json.sig over provider-manifest.json; re-sign the manifest \ + whenever it changes" + ); + + // Neither half may move alone. These two probes keep the assertion + // above from passing on a verifier that accepts everything. + let mut moved_manifest = manifest.clone(); + moved_manifest[0] ^= 0x01; + assert!( + !verify_ed25519(&public_key, &moved_manifest, &signature), + "a manifest that moves without a matching re-signature must not verify" + ); + let mut moved_signature = signature.clone(); + moved_signature[0] ^= 0x01; + assert!( + !verify_ed25519(&public_key, &manifest, &moved_signature), + "a signature that moves without a matching manifest must not verify" + ); + } } From 05092a694da3680c805f8080fd734bec3956e1fa Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 07:49:48 -0700 Subject: [PATCH 722/726] docs: correct the relay schema, plan, and publisher-key citations The Azure Relay ADR named an `xtask gen-provider-transport-schemas` subcommand in three places and a `make test-drift` gate built on it. No such subcommand exists and the suite that target resolves to does not cover this file; the same ADR already states the schema is hand-authored and embedded verbatim, so the file contradicted itself. Cite the embed and the crate test that pins the schema instead, and use the real type name `RelayTransportSettings`, which the same ADR already uses elsewhere. The remediation plan listed three finding sites under paths that do not resolve, and described the `labs/` tree as retired while the head carries 171 tracked files under it, its own governing `AGENTS.md`, and a live prototype. Correct the paths and describe the tree as live. The signature fragment promised a location and a public fingerprint and recorded neither, and the fold copies the line into released prose. Drop the location claim and record the public fingerprint with the convention that produces it, so a reader can recompute it and pin the key. --- changelog.d/fix-provider-artifact-signature.md | 9 ++++++--- ...09-24-002-refactor-rust-skills-remediation-plan.md | 4 ++-- .../ADR-046-provider-transport-azure-relay.md | 11 ++++++----- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/changelog.d/fix-provider-artifact-signature.md b/changelog.d/fix-provider-artifact-signature.md index e35b73040..0d01b01b9 100644 --- a/changelog.d/fix-provider-artifact-signature.md +++ b/changelog.d/fix-provider-artifact-signature.md @@ -11,9 +11,12 @@ the current manifest bytes. The manifest itself is byte-for-byte unchanged. The previous private key is not recoverable, so the publisher key changes rather than being re-derived; the operator holds the new private half - outside the repository, and only its location and public fingerprint are - recorded here. Consumers that pinned the old publisher key must trust the - new public key before building a Zone that installs this artifact. + outside the repository. The new public key is the committed + `packages/d2b-provider-guest-cloud-hypervisor/publisher-public-key.pem`, + whose `sha256` over the DER `SubjectPublicKeyInfo` is + `d798fa9f94f64015d5711c0484b5b30cef1b6c9bb918cb46bf43338e0d817b57`. + Consumers that pinned the old publisher key must trust the new public key + before building a Zone that installs this artifact. ### Added diff --git a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md index 68b03d840..889292922 100644 --- a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md +++ b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md @@ -68,7 +68,7 @@ The audit (16 craft lenses over every workspace crate, independently verified) p **Deferred to Follow-Up Work** - Findings reclassified at apply time into a surface this plan excludes (recorded in the ledger, then planned separately). -- The retired `labs/` tree and any pre-existing failure the baseline attributes to work outside the audit's crates. +- The `labs/` tree, which is live at this head rather than retired: it is tracked, carries its own `AGENTS.md` and live prototypes such as ADR 0047's `labs/window-chrome/`, so its disposition stays with those owners and this plan does not retire it. Also any pre-existing failure the baseline attributes to work outside the audit's crates. - New benchmark coverage for the perf lens: the audit's perf rows are static, and this plan applies only their structural wins (KTD10). ### Open Questions @@ -148,7 +148,7 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha - **Goal:** the unit of record is tracked, the gate baseline is recorded, and the correctness-first rows are fixed (or, for the one policy-confirmed row, recorded) so the first wave gate reads as evidence. - **Requirements:** R2, R3, R5, R10; KTD4. - **Dependencies:** none. -- **Files:** `changelog.d/`, and the finding sites - `packages/d2b-resource-runtime/src/revision.rs`, `packages/d2bd-runtime/src/runtime_process.rs`, `packages/d2b-broker/src/runtime.rs`, `packages/d2b-broker/src/ops/kernel_ops.rs`, `packages/d2b-broker/src/ops/sys.rs`, `packages/d2b-bus/src/` (telemetry test), `packages/d2b-provider-display-wayland/src/filter.rs`, `packages/d2b-provider-wayland-policy/src/` (applied), `packages/d2b-provider-user/src/` (record-only, no code change). +- **Files:** `changelog.d/`, and the finding sites - `packages/d2b-resource-runtime/src/revision.rs`, `packages/d2bd-runtime/src/runtime_process.rs`, `packages/d2b-broker/src/runtime.rs`, `packages/d2b-broker/src/kernel_ops.rs`, `packages/d2b-broker/src/sys.rs`, `packages/d2b-bus/src/` (telemetry test), `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs`, `packages/d2b-provider-wayland-policy/src/` (applied), `packages/d2b-provider-user/src/` (record-only, no code change). - **Approach:** 1. Commit the audit corpus and create the ledger with this row schema: finding id, lens, cluster, audit verdict, outcome, apply-time anchor, wave, commit, reason or policy citation, escalation history, and - for an escalated row - the final outcome recorded when the owning wave applies it (KTD1, R8). 2. Record the baseline: run the KTD3 gate set at the untouched head and write the result - pass or fail per gate, with every pre-existing failure attributed. Any additional pre-existing failure inside the audit's crates is fixed here when it blocks the gate and otherwise recorded as baseline-attributed and deferred. diff --git a/docs/specs/providers/ADR-046-provider-transport-azure-relay.md b/docs/specs/providers/ADR-046-provider-transport-azure-relay.md index 3f627d1f7..619c1f1ee 100644 --- a/docs/specs/providers/ADR-046-provider-transport-azure-relay.md +++ b/docs/specs/providers/ADR-046-provider-transport-azure-relay.md @@ -1366,9 +1366,10 @@ The settings schema file at: docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json ``` -is committed, version-controlled, and kept in sync with the Rust -`AzureRelayTransportSettings` type by `make test-drift` (via -`xtask gen-provider-transport-schemas && git diff --exit-code`). +is committed and hand-authored: the crate embeds it verbatim through +`RelayTransportSettings::schema_json` and re-runs the same admission rules on +every settings object it deserializes, so the committed file is the review +surface rather than a derived copy. The committed settings schema remains the review surface. The derivation copy at `share/d2b/provider/config-schema.json` is the copy the resource compiler @@ -1461,8 +1462,8 @@ download, or PATH scan. | Current source | `docs/specs/ADR-046-zone-routing.md` transport settings Nix example | | Reuse action | create | | Destination | `packages/d2b-provider-transport-azure-relay/src/transport_settings.rs`; `docs/reference/schemas/v3/providers/transport-azure-relay.transport-settings.json` | -| Detailed design | `AzureRelayTransportSettings` Rust struct with serde for only `relayNamespaceId` and `relayEntityId`; validation against committed JSON Schema; reject secret-shaped fields/values; generate and admit the exact six-field ZoneLink base; reject legacy provider envelopes and allocator-private fingerprint/capability fields; resolve `spec.transportProviderRef` before schema validation; validate exactly two same-Zone `spec.transportCredentials` refs with one `azure-relay-listen` and one `azure-relay-send` audience; enforce `disabled`/`limits` in child core; xtask `gen-provider-transport-schemas` integration | -| Integration | `make test-drift` gate: `xtask gen-provider-transport-schemas && git diff --exit-code` | +| Detailed design | `RelayTransportSettings` Rust struct with serde for only `relayNamespaceId` and `relayEntityId`; validation against committed JSON Schema; reject secret-shaped fields/values; generate and admit the exact six-field ZoneLink base; reject legacy provider envelopes and allocator-private fingerprint/capability fields; resolve `spec.transportProviderRef` before schema validation; validate exactly two same-Zone `spec.transportCredentials` refs with one `azure-relay-listen` and one `azure-relay-send` audience; enforce `disabled`/`limits` in child core; the committed schema is hand-authored and embedded verbatim through `RelayTransportSettings::schema_json` | +| Integration | No generator owns the file: `RelayTransportSettings::schema_json` embeds it verbatim and `tests/transport_settings_schema.rs` parses and pins it | | Data migration | None - full d2b 3.0 reset; no prior state to migrate | | Validation | `tests/transport_settings_schema.rs`: valid/invalid schema vectors; `tests/transport_credentials.rs`: exact canonical ZoneLink field set, same-Zone ref/count/audience/scope checks, and rejection of credential refs inside `transportSettings`; eval-time Nix assertion coverage from `nix-unit: transport-settings-secret-key` test (see zone-routing spec) | | Removal proof | N/A; new contract | From bf6ee0ec57a90a2de1e185f8b05af9f8a8238376 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 09:30:10 -0700 Subject: [PATCH 723/726] test(core-controller): generate the recovery fixture nonces at test time The persistence fixtures passed a literal 7 as the prepared nonce, which the code-scanning rule reads as a hard-coded cryptographic value. Both fixtures now derive the nonce through the crate's existing test_nonce_for_operation helper, widened to the crate for reuse from the persistence tests. The rejection test keeps its literal inputs: zero and a valid control are the values under test there. --- packages/d2b-core-controller/src/authority.rs | 2 +- .../src/authority_persistence.rs | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/d2b-core-controller/src/authority.rs b/packages/d2b-core-controller/src/authority.rs index c3fcc3935..7758e24cd 100644 --- a/packages/d2b-core-controller/src/authority.rs +++ b/packages/d2b-core-controller/src/authority.rs @@ -37,7 +37,7 @@ const OPTIONAL_PROVIDER_REF: &str = "Provider/observability-otel"; static NEXT_AUTHORITY_INDEX_NONCE: AtomicU64 = AtomicU64::new(1); #[cfg(test)] -fn test_nonce_for_operation(operation_id: &str) -> u64 { +pub(crate) fn test_nonce_for_operation(operation_id: &str) -> u64 { loop { let nonce = RandomState::new().hash_one(operation_id); if nonce != 0 { diff --git a/packages/d2b-core-controller/src/authority_persistence.rs b/packages/d2b-core-controller/src/authority_persistence.rs index 885664d28..1e8e2f107 100644 --- a/packages/d2b-core-controller/src/authority_persistence.rs +++ b/packages/d2b-core-controller/src/authority_persistence.rs @@ -337,7 +337,9 @@ async fn validated_recovery_receipt( #[cfg(test)] mod tests { use super::*; - use crate::authority::{AuthorityOwnerProof, AuthorityRequest, claim_digest}; + use crate::authority::{ + AuthorityOwnerProof, AuthorityRequest, claim_digest, test_nonce_for_operation, + }; use d2b_contracts_resource::v3::{ResourceGeneration, ResourceUid}; const OP_ID: &str = "recovered-helper-operation"; @@ -371,9 +373,12 @@ mod tests { claim_digest, store_binding_digest: store_binding_digest.clone(), }; - let prepared = - PreparedAuthorityOperation::new(operation_id.to_owned(), store_binding_digest, 7) - .unwrap(); + let prepared = PreparedAuthorityOperation::new( + operation_id.to_owned(), + store_binding_digest, + test_nonce_for_operation(operation_id), + ) + .unwrap(); (operation, prepared, request) } @@ -400,7 +405,7 @@ mod tests { let prepared = PreparedAuthorityOperation::new( OP_ID.to_owned(), STORE_BINDING_DIGEST.to_owned(), - 7, + test_nonce_for_operation(OP_ID), ) .expect("prepared operation"); AuthorityRecoveryData::new( From abfe912eceef6361c4780d184a204338c4568dc2 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 10:13:19 -0700 Subject: [PATCH 724/726] fix(audit): repair the guest static build and the review findings The Guest workspace mirror did not declare the `tracing` dependency the bundle resolver uses, so the static Guest build and the container lane failed compiling `d2b-core`; the fixture override and the Guest lock now carry it, and `tests/tools/guest-workspace-drift.py` is clean again. Applies the fresh review's findings as well: the seccomp-profile re-export list regains the four public items it dropped (the error type its public methods return and the three enforcement bounds), the eight documents that still cite the deleted `d2b-core` compat shim modules are re-pointed at `d2b-contracts`, the plan accounts for all thirteen `high` rows in its wave-0 disposition, and the broker transport's audit-join refusal describes itself accurately with its tautological test and now-unused helper removed. --- ...2-refactor-rust-skills-remediation-plan.md | 2 +- docs/reference/tracing-contract.md | 2 +- docs/specs/ADR-046-cli-and-operations.md | 2 +- .../ADR-046-current-code-migration-map.md | 2 +- docs/specs/ADR-046-nix-configuration.md | 6 +-- docs/specs/ADR-046-resources-device.md | 8 ++-- ...R-046-resources-host-guest-process-user.md | 10 ++--- docs/specs/ADR-046-resources-zone-control.md | 10 ++--- .../ADR-046-telemetry-audit-and-support.md | 8 ++-- packages/Cargo.guest.lock | 1 + .../d2b-provider-seccomp-profile/src/lib.rs | 5 ++- packages/d2bd-runtime/src/broker_transport.rs | 42 +++++++------------ .../guest-rust-workspace/d2b-core.Cargo.toml | 1 + 13 files changed, 46 insertions(+), 53 deletions(-) diff --git a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md index 889292922..9160d97d4 100644 --- a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md +++ b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md @@ -152,7 +152,7 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha - **Approach:** 1. Commit the audit corpus and create the ledger with this row schema: finding id, lens, cluster, audit verdict, outcome, apply-time anchor, wave, commit, reason or policy citation, escalation history, and - for an escalated row - the final outcome recorded when the owning wave applies it (KTD1, R8). 2. Record the baseline: run the KTD3 gate set at the untouched head and write the result - pass or fail per gate, with every pre-existing failure attributed. Any additional pre-existing failure inside the audit's crates is fixed here when it blocks the gate and otherwise recorded as baseline-attributed and deferred. - 3. Dispose of the 13 `high` rows, re-verified per R3: apply the four test rows, the two wire-digest panic rows, the provider-wayland-policy caller-input panic at its driver-args boundary, and the four executor-blocking rows (each with the replacement the lint vocabulary names rather than a new allowance); record the provider-user blocking-NSS row as a policy-confirmed no-op citing its policy (R14, KTD8); escalate the remaining member sites of the shared driver-args class to U5, with the escalation recorded. + 3. Dispose of the 13 `high` rows, re-verified per R3: apply the four test rows, the two wire-digest panic rows, the provider-wayland-policy caller-input panic at its driver-args boundary, and the four executor-blocking rows (each with the replacement the lint vocabulary names rather than a new allowance); record the provider-user blocking-NSS row as a policy-confirmed no-op citing its policy (R14, KTD8); escalate the remaining member sites of the shared driver-args class to U5, with the escalation recorded. Those groups account for all thirteen: the eight `leaf` rows (the four test rows, the daemon audit-join digest row, two of the four executor-blocking rows, and the provider-user row recorded as a no-op), both `family` rows (the driver-args class - one applied here, one escalated), and the three `wide` rows (the broker dispatch digest row inside the wire-digest pair, and the broker reap-poll and NSS-lookup rows inside the executor-blocking four). 4. Reconcile the ratchets these rows touch, then run the gate; the wave only closes with a red-to-green delta on the baseline record. - **Patterns to follow:** the sibling `from_request_with_join` path already converts the same parse failure into a typed protocol error; the sibling `sd_notify_ready` test already asserts an observable outcome; the bounded-worker shape named in `clippy.toml` is the house replacement for blocking work on the executor. - **Test scenarios:** diff --git a/docs/reference/tracing-contract.md b/docs/reference/tracing-contract.md index 28a077335..4f84922e6 100644 --- a/docs/reference/tracing-contract.md +++ b/docs/reference/tracing-contract.md @@ -148,7 +148,7 @@ for the per-VM key drift event. The `drift_kind` is a typed working directory, provider endpoint, provider credential, provider resource id, or child output: route it through the typed error envelope - (`packages/d2b-core/src/error.rs`) and the broker audit log, + (`packages/d2b-contracts/src/error.rs`) and the broker audit log, not the span. 3. Run `D2B_ENABLE_FIXTURE_BUILD=1 make test-fixture-contracts` locally before pushing a tracing-contract change. diff --git a/docs/specs/ADR-046-cli-and-operations.md b/docs/specs/ADR-046-cli-and-operations.md index 78d34109d..c78c47417 100644 --- a/docs/specs/ADR-046-cli-and-operations.md +++ b/docs/specs/ADR-046-cli-and-operations.md @@ -65,7 +65,7 @@ the "target:" annotation. | `RealmPolicyOutputV1 { realm, mode, gateway_vm, gateway_target, gateway_state, cross_realm_policy, credential_boundary }` | `d2b-contracts/src/cli_output.rs:345` | Retired; successor rows expose compiler topology plus authenticated route/projection status, never child-local ZoneLink spec or status | | `RealmListOutputV1 { realms: Vec }` | `d2b-contracts/src/cli_output.rs:285` | Target: `d2b zone list` topology-projection response | | `RealmInspectOutputV1 { realm: RealmPolicyOutputV1 }` | `d2b-contracts/src/cli_output.rs:292` | Target: `d2b zone get ` topology/route projection response | -| `WorkloadId`, `WorkloadTarget` (`= RealmTarget`) | `d2b-realm-core/src/ids.rs`, `d2b-core/src/workload_identity.rs` | `Guest/` ResourceRef for VM/sandbox/cloud/remote; `Host/` for unsafe-local (NEVER `Guest`) | +| `WorkloadId`, `WorkloadTarget` (`= RealmTarget`) | `d2b-realm-core/src/ids.rs`, `d2b-contracts/src/workload_identity.rs` | `Guest/` ResourceRef for VM/sandbox/cloud/remote; `Host/` for unsafe-local (NEVER `Guest`) | | `WorkloadProviderKind::LocalVm` | `d2b-realm-core/src/workload.rs:16` | `Guest` under `Provider/runtime-cloud-hypervisor` | | `WorkloadProviderKind::QemuMedia` | `d2b-realm-core/src/workload.rs:19` | `Guest` under `Provider/runtime-qemu-media` | | `WorkloadProviderKind::UnsafeLocal` | `d2b-realm-core/src/workload.rs:22`; Nix option `kind = "unsafe-local"` in `nixos-modules/options-realms-workloads.nix:221`; Nix emitter `nixos-modules/unsafe-local-workloads-json.nix`; helper crate `packages/d2b-unsafe-local-helper/`; wire protocol `packages/d2b-contracts/src/unsafe_local_wire.rs` | Target: `Host/` resource with `defaultDomain=user`, `allowedDomains=[user]`, `defaultUserRef=User/`; reconciled by `Provider/system-core` (NOT itself a Provider and NOT a Guest); child processes use normal Process Providers; no-isolation posture (`IsolationPosture::UnsafeLocal`) MUST be preserved as explicit warnings in Host status, CLI output, UI, and audit/telemetry | diff --git a/docs/specs/ADR-046-current-code-migration-map.md b/docs/specs/ADR-046-current-code-migration-map.md index a5d310c49..bec3f6e44 100644 --- a/docs/specs/ADR-046-current-code-migration-map.md +++ b/docs/specs/ADR-046-current-code-migration-map.md @@ -776,7 +776,7 @@ Source: `packages/d2b/src/` `NativeCommand` enum + subcommand handlers. | `tests/unit/nix/cases/` (nix-unit) | Nix option eval cases; includes `niri-vm-borders.nix`, assertions | ADAPT | Update realm→zone in all cases; `make nix-unit-pin` after changes | | `tests/unit/smoke/` (smoke evals) | Flake-check smoke evals including `smoke-eval-tpm.nix` | ADAPT | Update option names | | `packages/d2b-realm-core/src/**` (`#[cfg(test)]`) | `RealmId`, `WorkloadId`, `AllocatorLease`, `HostResourceKind` unit tests | ADAPT | Update names to `ZoneId`, `ResourceName` | -| `packages/d2b-core/src/workload_identity.rs` (tests) | `WorkloadTarget::parse`, `WorkloadIdentity` serde | ADAPT | Update to `ResourceRef` format | +| `packages/d2b-contracts/src/workload_identity.rs` (tests) | `WorkloadTarget::parse`, `WorkloadIdentity` serde | ADAPT | Update to `ResourceRef` format | | `packages/d2bd/src/` (hermetic exec tests) | `exec_session` / `exec_client` matrices | RETAIN | Keep; update transport to ComponentSession | | `packages/d2b-contracts/` (tests) | Wire type serde | ADAPT | Update `WorkloadOp` → `ResourceOp`; add handler wire test | | `packages/d2b-contract-tests/tests/` | Rendered-artifact contract tests; drift checks | ADAPT | Update for renamed/split artifacts per §4.2 | diff --git a/docs/specs/ADR-046-nix-configuration.md b/docs/specs/ADR-046-nix-configuration.md index dd8654e29..ff7047a86 100644 --- a/docs/specs/ADR-046-nix-configuration.md +++ b/docs/specs/ADR-046-nix-configuration.md @@ -856,7 +856,7 @@ The current `d2b.realms..workloads..kind = "unsafe-local"` workload `IsolationPosture::UnsafeLocal`, current files: `nixos-modules/unsafe-local-workloads-json.nix`, `nixos-modules/unsafe-local-helper.nix`, -`packages/d2b-core/src/unsafe_local_workloads.rs`) maps to a user-only `Host` +`packages/d2b-contracts/src/unsafe_local_workloads.rs`) maps to a user-only `Host` resource in v3. It is never a `Guest` and is not a v3 Provider. The target shape is a `Host` resource reconciled by `Provider/system-core` with @@ -2491,7 +2491,7 @@ marked compile-only. | `WorkloadId` | `d2b-realm-core/src/ids.rs` | Live | `ResourceName` + `ResourceRef` for `Guest/` or `Process/` | ADR046-identities-001 | | `NodeId`, `NodeSummary`, `NodeKind` | `d2b-realm-core/src/node.rs` | Live in metadata | `Host` / `Guest` ResourceType (see NodeKind table) | ADR046-identities-001 | | `ProviderId` | `d2b-realm-core/src/ids.rs` | Live | `ResourceName` for `Provider/` | ADR046-identities-001 | -| `RealmTarget` / `WorkloadTarget` (`..d2b`) | `d2b-realm-core/src/target.rs`, `d2b-core/src/workload_identity.rs` | Live in resolver | `Zone/` + `Guest/` ResourceRef | ADR046-identities-001 | +| `RealmTarget` / `WorkloadTarget` (`..d2b`) | `d2b-realm-core/src/target.rs`, `d2b-contracts/src/workload_identity.rs` | Live in resolver | `Zone/` + `Guest/` ResourceRef | ADR046-identities-001 | | `RealmControllerPlacement` (`HostLocal`, `GatewayVm`, `CloudFullHost`, `ProviderController`, `ProviderAgent`) | `d2b-realm-core/src/realm.rs` | Metadata only | `Host.providerRef` + `Guest.providerRef` per NodeKind table | ADR046-nix-001 | | `EntrypointMode` (`HostResident`, `GatewayBacked`) | `d2b-realm-core/src/realm.rs` | Metadata only | `Host` vs `Guest` ExecutionPolicy distinction | ADR046-nix-001 | | `VmProcessDag`, `ProcessNode`, `ProcessRole` | `d2b-core/src/processes.rs` | Live (processes.json consumed by broker) | `Process`/`EphemeralProcess` per disposition table | ADR046-nix-006 | @@ -2790,7 +2790,7 @@ contract work item (ADR046-nix-034/ADR046-nix-035). Cross-reference: | Field | Value | | --- | --- | | Dependency/owner | ADR046-nix-001; unsafe-local migration | -| Current source | `nixos-modules/unsafe-local-workloads-json.nix` (`WorkloadProviderKind::UnsafeLocal`/`IsolationPosture::UnsafeLocal`; current `unsafe-local-workloads.json` artifact); `nixos-modules/unsafe-local-helper.nix` (user-domain process/helper definitions); `packages/d2b-core/src/unsafe_local_workloads.rs` | +| Current source | `nixos-modules/unsafe-local-workloads-json.nix` (`WorkloadProviderKind::UnsafeLocal`/`IsolationPosture::UnsafeLocal`; current `unsafe-local-workloads.json` artifact); `nixos-modules/unsafe-local-helper.nix` (user-domain process/helper definitions); `packages/d2b-contracts/src/unsafe_local_workloads.rs` | | Reuse action | adapt | | Destination | User-only `Host` resource in `zones//resource-bundle.json` (`spec.isolationPosture: "none"`, `defaultDomain: user`, `allowedDomains: [user]`, `defaultUserRef: User/`); child `Process` resources in `zones//resource-bundle.json` using normal Process Providers; shell session supervisor -> `Process` under `Provider/shell-terminal`; never a `Guest`; not a v3 Provider | | Detailed design | `isolationPosture: "none"` is a promoted Host base field declared at top-level `spec.isolationPosture` in the Host schema; enforced at eval time; user-only Host rejects system-domain Process refs; `NoIsolation` condition in Host status; `status.isolationPosture: none`; every `ProcessEffect` audit event under this Host carries `no_isolation=true`; OTEL telemetry never carries an isolation label; CLI/UI warning non-suppressible | diff --git a/docs/specs/ADR-046-resources-device.md b/docs/specs/ADR-046-resources-device.md index 22c318ef0..b08b7a4f7 100644 --- a/docs/specs/ADR-046-resources-device.md +++ b/docs/specs/ADR-046-resources-device.md @@ -1043,7 +1043,7 @@ mutually exclusive. This is enforced: - `packages/d2b-contract-tests/tests/usb_sk_contract.rs`: DTO serde, unknown-field denial, broker capability set. -- `packages/d2b-core/src/privileges_w3.rs` unit tests: W3BrokerOperation flags. +- `packages/d2b-contracts/src/privileges_w3.rs` unit tests: W3BrokerOperation flags. - New: Lease acquire/release state machine (Idle → AwaitingLease → Active → Completed). - New: Second-claim conflict rejection. - New: Session ring bounded overflow (oldest session evicted). @@ -2012,7 +2012,7 @@ integration is live and all current tests pass against the new resource model. | Item | Treatment | | --- | --- | -| Current anchor | **Process/DAG**: `packages/d2b-core/src/processes.rs` (ProcessRole enum: Swtpm, SwtpmPreStartFlush, Usbip, SecurityKeyFrontend, Gpu, GpuRenderNode, Video; VmProcessDag/VmProcessInvariants structs - old Workload DAG names); `packages/d2b-core/src/bundle_resolver.rs` (process exec names, device token sets, USBIP intents); `packages/d2b-host/src/swtpm_argv.rs`, `gpu_argv.rs`, `video_argv.rs`; **swtpm state**: `packages/d2b-broker/src/ops/swtpm_dir.rs`; **Contracts/broker ops**: `packages/d2b-contracts/src/security_key.rs`, `usbip.rs`, `broker_wire.rs`; `packages/d2b-core/src/privileges_w3.rs` (W3BrokerOperation enum: SecurityKeyOpenDevice, SecurityKeyApplyUdevRules, UsbipBindFirewallRule); **Security-key relay (daemon-internal)**: `packages/d2bd/src/security_key.rs` (CTAPHID relay: CID translation, SO_PEERCRED auth, hidraw async fd, accept loop, lease; lives inside d2bd, NOT a separate spawned process); `packages/d2bd/src/lib.rs:10456` (`start_sk_accept_loop` - ProcessRole::SecurityKeyFrontend is handled as a daemon-internal coroutine: broker fetches hidraw fd, daemon binds vsock-proxy socket, spawns async accept loop); **Guest binary**: `packages/d2b-sk-frontend/src/` (static binary for in-guest UHID virtual HID device; connects over AF_VSOCK to the daemon accept loop; NOT related to the ProcessRole name); **USBIP state machine**: `packages/d2bd/src/usbip_state_machine.rs` (typed per-busid bring-up plan and executor; canonical step order: modprobe→lock→withhold→firewall→backend→bind→proxy); `packages/d2bd/src/usbip_reconcile_state.rs` (restart-safe reconciler state model; internal to daemon, not yet wired to reconciler); the d2bd-runtime per-env usbipd daemon autostart (broker `SpawnRunner` backend/proxy seams, retiring legacy systemd units in `nixos-modules/network.nix`) is already deleted after the manager-plane cutover; **Workload/Realm capability surface (old names)**: `packages/d2b-realm-core/src/capability.rs` (old Realm Capability enum: GpuAccel, Usb, Hid, Hotplug - current inter-Realm device capability assertion, target maps to Device ResourceType claims); `packages/d2b-realm-core/src/stream.rs` (StreamKind::DeviceHid → Capability::Hid, StreamKind::DeviceUsb → Capability::Usb); `packages/d2bd/src/realm_access_resolver.rs` (maps old Workload ops: `ops.media.usb_hotplug` → Capability::Usb + Capability::Hotplug, `ops.display.graphics` → Capability::GpuAccel); **Workload manifest (old name)**: `packages/d2b-core/src/manifest_v04.rs` VmEntry fields: `tpm: bool`, `usbip_yubikey: bool`, `security_key: bool`, `graphics: bool`, `gpu_socket: Option` (per-Workload device-enable flags in the v04 manifest; these are the current per-VM device declarations); **Runtime capability surface**: `packages/d2b-core/src/runtime.rs` (RuntimeServiceRole enum maps ProcessRoles to public roles: Tpm←Swtpm/SwtpmPreStartFlush, Display←Gpu/GpuRenderNode, Video←Video, Usb←Usbip+SecurityKeyFrontend; RuntimeMediaCapabilities: `usb_hotplug`; RuntimeDisplayCapabilities: `graphics`/`video`); **Nix options (old Workload namespace)**: `nixos-modules/options-realms-workloads.nix` (`d2b.vms..tpm.enable`, `d2b.vms..graphics.enable` - current Nix Workload device options; v3 target is `d2b.zones..resources. = { type = "Device"; ... }`); `nixos-modules/components/tpm.nix`, `usbip.nix`, `security-key-guest.nix`, `video/guest.nix`, `graphics.nix` | +| Current anchor | **Process/DAG**: `packages/d2b-core/src/processes.rs` (ProcessRole enum: Swtpm, SwtpmPreStartFlush, Usbip, SecurityKeyFrontend, Gpu, GpuRenderNode, Video; VmProcessDag/VmProcessInvariants structs - old Workload DAG names); `packages/d2b-core/src/bundle_resolver.rs` (process exec names, device token sets, USBIP intents); `packages/d2b-host/src/swtpm_argv.rs`, `gpu_argv.rs`, `video_argv.rs`; **swtpm state**: `packages/d2b-broker/src/ops/swtpm_dir.rs`; **Contracts/broker ops**: `packages/d2b-contracts/src/security_key.rs`, `usbip.rs`, `broker_wire.rs`; `packages/d2b-contracts/src/privileges_w3.rs` (W3BrokerOperation enum: SecurityKeyOpenDevice, SecurityKeyApplyUdevRules, UsbipBindFirewallRule); **Security-key relay (daemon-internal)**: `packages/d2bd/src/security_key.rs` (CTAPHID relay: CID translation, SO_PEERCRED auth, hidraw async fd, accept loop, lease; lives inside d2bd, NOT a separate spawned process); `packages/d2bd/src/lib.rs:10456` (`start_sk_accept_loop` - ProcessRole::SecurityKeyFrontend is handled as a daemon-internal coroutine: broker fetches hidraw fd, daemon binds vsock-proxy socket, spawns async accept loop); **Guest binary**: `packages/d2b-sk-frontend/src/` (static binary for in-guest UHID virtual HID device; connects over AF_VSOCK to the daemon accept loop; NOT related to the ProcessRole name); **USBIP state machine**: `packages/d2bd/src/usbip_state_machine.rs` (typed per-busid bring-up plan and executor; canonical step order: modprobe→lock→withhold→firewall→backend→bind→proxy); `packages/d2bd/src/usbip_reconcile_state.rs` (restart-safe reconciler state model; internal to daemon, not yet wired to reconciler); the d2bd-runtime per-env usbipd daemon autostart (broker `SpawnRunner` backend/proxy seams, retiring legacy systemd units in `nixos-modules/network.nix`) is already deleted after the manager-plane cutover; **Workload/Realm capability surface (old names)**: `packages/d2b-realm-core/src/capability.rs` (old Realm Capability enum: GpuAccel, Usb, Hid, Hotplug - current inter-Realm device capability assertion, target maps to Device ResourceType claims); `packages/d2b-realm-core/src/stream.rs` (StreamKind::DeviceHid → Capability::Hid, StreamKind::DeviceUsb → Capability::Usb); `packages/d2bd/src/realm_access_resolver.rs` (maps old Workload ops: `ops.media.usb_hotplug` → Capability::Usb + Capability::Hotplug, `ops.display.graphics` → Capability::GpuAccel); **Workload manifest (old name)**: `packages/d2b-core/src/manifest_v04.rs` VmEntry fields: `tpm: bool`, `usbip_yubikey: bool`, `security_key: bool`, `graphics: bool`, `gpu_socket: Option` (per-Workload device-enable flags in the v04 manifest; these are the current per-VM device declarations); **Runtime capability surface**: `packages/d2b-core/src/runtime.rs` (RuntimeServiceRole enum maps ProcessRoles to public roles: Tpm←Swtpm/SwtpmPreStartFlush, Display←Gpu/GpuRenderNode, Video←Video, Usb←Usbip+SecurityKeyFrontend; RuntimeMediaCapabilities: `usb_hotplug`; RuntimeDisplayCapabilities: `graphics`/`video`); **Nix options (old Workload namespace)**: `nixos-modules/options-realms-workloads.nix` (`d2b.vms..tpm.enable`, `d2b.vms..graphics.enable` - current Nix Workload device options; v3 target is `d2b.zones..resources. = { type = "Device"; ... }`); `nixos-modules/components/tpm.nix`, `usbip.nix`, `security-key-guest.nix`, `video/guest.nix`, `graphics.nix` | | Evidence class | ProcessRole enum (ProcessRole, VmProcessDag): **implemented-and-reachable**. swtpm/gpu/video argv generators: **implemented-and-reachable**. swtpm_dir hardening and tamper marker: **implemented-and-reachable**. Security-key broker ops DTOs (`security_key.rs`, `broker_wire.rs` W3BrokerOperation): **implemented-and-reachable** (NOT unwired stubs - the full CTAPHID relay runs in `packages/d2bd/src/security_key.rs` and `packages/d2bd/src/lib.rs:start_sk_accept_loop`). USBIP state machine (`usbip_state_machine.rs`): **implemented-and-reachable**. USBIP reconcile state model (`usbip_reconcile_state.rs`): **implemented-but-unwired** (future restart-safe reconciler, internal state model). USBIP per-env autostart (broker `SpawnRunner` backend/proxy seams): **deleted after the manager-plane cutover**. Realm Capability enum (GpuAccel/Usb/Hid/Hotplug): **implemented-and-reachable** (old Workload/Realm names; in-process capability assertion). StreamKind::DeviceHid/DeviceUsb: **implemented-and-reachable**. realm_access_resolver.rs (Workload ops → Capabilities): **implemented-and-reachable**. manifest_v04.rs VmEntry device fields: **generated-or-eval-contract** (bundle/manifest-driven per-Workload flags). runtime.rs RuntimeServiceRole/RuntimeCapabilities: **implemented-and-reachable** (current public service role and capability surface). d2b-sk-frontend guest binary: **implemented-and-reachable** (guest static binary, not a Zone Process). Nix options-realms-workloads.nix device options: **generated-or-eval-contract**. Device ResourceType schema: **ADR-only**. Provider crates (d2b-provider-device-*): **ADR-only**. | | Behavior retained | Swtpm user-namespace/zero-host-caps (ADR 0021), tamper-marker/fail-closed, umask=7 socket ACL; core-resolved GPU broker token set (kvm/dri/udmabuf/nvidia*); video wire-contract constants frozen; USBIP bus ID validation; broker-opened security-key hidraw fd supplied only through the relay LaunchTicket; eval-time mutual-exclusion assertions | | Required delta | Device ResourceType schema, four Provider crates, controller reconcile loops, RBAC roles, hot-plug observe interval, Guest frontend Process resolution, consolidated process name templates | @@ -2082,7 +2082,7 @@ error listing the missing paths. There is no opt-out mechanism. | Field | Value | | --- | --- | | Dependency/owner | W0 shared contract root; `d2b-contracts` | -| Current source | `packages/d2b-contracts/src/security_key.rs` (SecurityKeyStatusResponse, SecurityKeySession, SecurityKeyLeaseState, SecurityKeyVmSessionState DTOs; implemented-and-reachable), `usbip.rs`, `broker_wire.rs`; `packages/d2b-core/src/privileges_w3.rs` (W3BrokerOperation: SecurityKeyOpenDevice, SecurityKeyApplyUdevRules, UsbipBindFirewallRule - implemented-and-reachable); `packages/d2b-core/src/manifest_v04.rs` VmEntry device fields (tpm, usbip_yubikey, security_key, graphics - old Workload manifest, generated-or-eval-contract) | +| Current source | `packages/d2b-contracts/src/security_key.rs` (SecurityKeyStatusResponse, SecurityKeySession, SecurityKeyLeaseState, SecurityKeyVmSessionState DTOs; implemented-and-reachable), `usbip.rs`, `broker_wire.rs`; `packages/d2b-contracts/src/privileges_w3.rs` (W3BrokerOperation: SecurityKeyOpenDevice, SecurityKeyApplyUdevRules, UsbipBindFirewallRule - implemented-and-reachable); `packages/d2b-core/src/manifest_v04.rs` VmEntry device fields (tpm, usbip_yubikey, security_key, graphics - old Workload manifest, generated-or-eval-contract) | | Reuse action | adapt | | Destination | `packages/d2b-contracts/` | | Detailed design | Device ResourceType schema (spec/status/conditions/claims/inventory); closed-set error codes; Device RBAC verbs; broker operation effect-limit constants; shared Device telemetry contract requires fixed semantic metric labels with no Zone/resource-name-derived identity and retains `d2b.zone`/`d2b.provider` only as OTEL resource attributes. Primary reuse disposition: `adapt`. Preserved source-plan detail: extract and adapt. | @@ -2130,7 +2130,7 @@ error listing the missing paths. There is no opt-out mechanism. | Field | Value | | --- | --- | | Dependency/owner | ADR046-device-001; device-security-key provider owner | -| Current source | `packages/d2b-contracts/src/security_key.rs` (DTOs - implemented-and-reachable); `packages/d2b-core/src/privileges_w3.rs` (W3BrokerOperation - implemented-and-reachable); **KEY: relay is in d2bd** - `packages/d2bd/src/security_key.rs` (CTAPHID relay: CID translation, SO_PEERCRED, hidraw async fd, accept loop - implemented-and-reachable) and `packages/d2bd/src/lib.rs:start_sk_accept_loop` (ProcessRole::SecurityKeyFrontend dispatch - implemented-and-reachable); **guest binary**: `packages/d2b-sk-frontend/src/` (static UHID frontend - implemented-and-reachable); old Workload Nix option: `nixos-modules/options-realms-workloads.nix` `d2b.vms..security_key.*`; `nixos-modules/components/security-key-guest.nix` | +| Current source | `packages/d2b-contracts/src/security_key.rs` (DTOs - implemented-and-reachable); `packages/d2b-contracts/src/privileges_w3.rs` (W3BrokerOperation - implemented-and-reachable); **KEY: relay is in d2bd** - `packages/d2bd/src/security_key.rs` (CTAPHID relay: CID translation, SO_PEERCRED, hidraw async fd, accept loop - implemented-and-reachable) and `packages/d2bd/src/lib.rs:start_sk_accept_loop` (ProcessRole::SecurityKeyFrontend dispatch - implemented-and-reachable); **guest binary**: `packages/d2b-sk-frontend/src/` (static UHID frontend - implemented-and-reachable); old Workload Nix option: `nixos-modules/options-realms-workloads.nix` `d2b.vms..security_key.*`; `nixos-modules/components/security-key-guest.nix` | | Reuse action | adapt | | Destination | `packages/d2b-provider-device-security-key/src/` (controller, relay Process, guest frontend Process, lease/session ring); `packages/d2b-provider-device-security-key/tests/` (hermetic Cargo integration); `packages/d2b-provider-device-security-key/integration/` (container/Host/Guest scenarios); `packages/d2b-provider-device-security-key/README.md` | | Detailed design | Device spec/status; unprivileged relay Process (`device--sk-relay`); guest frontend Process (`device--sk-frontend`, `executionRef: Guest/`); ceremony/CID/lease/session ring (max 1 session per Device); opaque hidraw effect request through DeviceEffectPort, with the core adapter placing the broker-returned fd only in the relay LaunchTicket; mandatory Core-derived `(Host, physical-usb-backing, opaqueKeyDigest)` claim shared with every USB Provider before effects; Nix emitter; all four required crate paths present (see "Provider crate layout") Primary reuse disposition: `adapt`. Preserved source-plan detail: extract and adapt. | diff --git a/docs/specs/ADR-046-resources-host-guest-process-user.md b/docs/specs/ADR-046-resources-host-guest-process-user.md index cedf678c8..ceb6fab5a 100644 --- a/docs/specs/ADR-046-resources-host-guest-process-user.md +++ b/docs/specs/ADR-046-resources-host-guest-process-user.md @@ -2316,13 +2316,13 @@ The zone configuration controller retains the N most recently activated, cleanup | --- | --- | | Current anchor (Host) | `packages/d2b-core/src/host_check.rs`: `HostCheckReport`, `HostCheckSummary`, `HostCheckFinding`, `HostCheckSeverity`; `packages/d2bd/src/kernel_module_check.rs`, `pidfs_probe.rs`; `nixos-modules/options-host.nix`; `packages/d2b-core/src/provider_capabilities.rs`; `packages/d2b-realm-core/src/ids.rs`: `HostResourceId`, `NodeId`; `packages/d2b-realm-core/src/node.rs`: `NodeKind` (`FullHost`/`Gateway`/`ProviderManaged`), `NodeSummary` (id/realm/kind/capabilities) - `NodeKind::FullHost` is the closest current analog for a v3 Host execution node | | Host evidence class | `HostCheckReport`/`HostCheckSummary` implemented-and-reachable; `NodeSummary`/`NodeKind::FullHost` implemented-and-reachable (current node inventory concept); Host ResourceType is ADR-only | -| Current anchor (Guest) | `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind` (`LocalVm` → runtime-cloud-hypervisor Provider, `QemuMedia` → runtime-qemu-media Provider, `ProviderManaged` → ACA/relay Providers; `UnsafeLocal` → user-only **Host**, not Guest - this variant is cited here only for enum completeness; its evidence and target mapping are owned by the unsafe-local anchor row), `IsolationPosture` (`VirtualMachine` → Guest, `ProviderManaged` → Guest; `UnsafeLocal` → Host `isolationPosture="none"`, not Guest), `WorkloadExecutionPosture`, `WorkloadSummary`, `WorkloadState` (`Stopped`/`Starting`/`Running`/`Degraded`/`Failed`), `WorkloadSelector`; `packages/d2b-realm-core/src/ids.rs`: `RealmId`, `WorkloadId`, `NodeId`, `ProviderId`, `ExecutionId`, `GatewayId`; `packages/d2b-realm-core/src/realm.rs`: `RealmPath`, `RealmControllerPlacement`, `EntrypointMode`; `packages/d2b-realm-core/src/target.rs`: `RealmTarget`, `TargetName`, `RealmTargetParser` (current analog for `/` ResourceRef); `packages/d2b-core/src/workload_identity.rs`: `WorkloadIdentity`, `WorkloadTarget`, `WorkloadBackend` (`LocalVm`/`LocalQemuMedia`/`ProviderManaged` → Guest; `UnsafeLocal` → Host - not a Guest binding, not a v3 Provider; see unsafe-local anchor), `WorkloadRuntimeIntent`; `packages/d2b-core/src/realm_controller_config.rs`: `RealmControllerConfig`, `RealmControllerRuntimeProviderType`, `RealmControllerLocalWorkload`; `nixos-modules/options-realms-workloads.nix` (`d2b.realms..workloads..kind`: local-vm/qemu-media → Guest; unsafe-local → Host, see unsafe-local anchor); `nixos-modules/options-realms.nix` (`d2b.realms`, `providerKind` regex `^[a-z][a-z0-9-]*$`) | +| Current anchor (Guest) | `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind` (`LocalVm` → runtime-cloud-hypervisor Provider, `QemuMedia` → runtime-qemu-media Provider, `ProviderManaged` → ACA/relay Providers; `UnsafeLocal` → user-only **Host**, not Guest - this variant is cited here only for enum completeness; its evidence and target mapping are owned by the unsafe-local anchor row), `IsolationPosture` (`VirtualMachine` → Guest, `ProviderManaged` → Guest; `UnsafeLocal` → Host `isolationPosture="none"`, not Guest), `WorkloadExecutionPosture`, `WorkloadSummary`, `WorkloadState` (`Stopped`/`Starting`/`Running`/`Degraded`/`Failed`), `WorkloadSelector`; `packages/d2b-realm-core/src/ids.rs`: `RealmId`, `WorkloadId`, `NodeId`, `ProviderId`, `ExecutionId`, `GatewayId`; `packages/d2b-realm-core/src/realm.rs`: `RealmPath`, `RealmControllerPlacement`, `EntrypointMode`; `packages/d2b-realm-core/src/target.rs`: `RealmTarget`, `TargetName`, `RealmTargetParser` (current analog for `/` ResourceRef); `packages/d2b-contracts/src/workload_identity.rs`: `WorkloadIdentity`, `WorkloadTarget`, `WorkloadBackend` (`LocalVm`/`LocalQemuMedia`/`ProviderManaged` → Guest; `UnsafeLocal` → Host - not a Guest binding, not a v3 Provider; see unsafe-local anchor), `WorkloadRuntimeIntent`; `packages/d2b-core/src/realm_controller_config.rs`: `RealmControllerConfig`, `RealmControllerRuntimeProviderType`, `RealmControllerLocalWorkload`; `nixos-modules/options-realms-workloads.nix` (`d2b.realms..workloads..kind`: local-vm/qemu-media → Guest; unsafe-local → Host, see unsafe-local anchor); `nixos-modules/options-realms.nix` (`d2b.realms`, `providerKind` regex `^[a-z][a-z0-9-]*$`) | | Guest evidence class | `WorkloadSummary`/`WorkloadState`/`WorkloadProviderKind` implemented-and-reachable for local-vm/qemu-media paths; ACA (`d2b-provider-aca/`) and relay (`d2b-provider-relay/`) Providers have live runtime paths via `AcaWorkloadProvider`/`WorkloadProvider` trait; host Provider adapters in `d2b-host-providers/src/lib.rs` (`HostCheckSubstrateProvider`, `LocalMicroVmProvider`) are thin adapters, not fully wired to the daemon (see `packages/d2bd/src/realm_stubs.rs` `dead_code` note); Guest ResourceType is ADR-only; v3 runtime Provider resources are ADR-only | | Current anchor (Guest runtime Providers) | `packages/d2b-realm-provider/src/provider.rs`: `HostSubstrateProvider`, `RuntimeProvider`, `WorkloadProvider`, `DurableExecutionProvider`, `GuestControlEndpointProvider`, `PersistentShellProvider`, `DisplayProvider`, `RelayProvider`, `NodeProvider` (traits); `packages/d2b-realm-provider/src/capabilities.rs`: `RuntimeCapabilitySet`, `WorkloadCapabilitySet`, `DisplayCapabilitySet`, `NodeCapabilitySet`, `HostSubstrateKind`; `packages/d2b-host-providers/src/lib.rs`: `HostCheckSubstrateProvider` (NIXOS_HOST_SUBSTRATE_PROVIDER_ID, GENERIC_LINUX_HOST_SUBSTRATE_PROVIDER_ID), `LocalMicroVmProvider` (CLOUD_HYPERVISOR_RUNTIME_PROVIDER_ID), LOCAL_QEMU_MEDIA_RUNTIME_PROVIDER_ID, LOCAL_CROSS_DOMAIN_WAYLAND_PROVIDER_ID; `packages/d2b-provider-aca/src/lib.rs`: `AcaWorkloadProvider` (ACA sandbox path, live); `packages/d2b-provider-relay/src/lib.rs` (relay transport, live) | | Guest runtime Provider evidence class | ACA (`AcaWorkloadProvider`) and relay Provider are implemented-and-reachable with live data-plane REST and relay paths; `LocalMicroVmProvider`/`HostCheckSubstrateProvider` are implemented-but-unwired (`realm_stubs.rs` stubs are `dead_code`; gateway-mode wiring is incomplete); all v3 Provider resources are ADR-only | -| Current anchor (Process/EphemeralProcess) | `packages/d2b-core/src/processes.rs`: `ProcessRole` (18 variants), `VmProcessDag`, `ProcessNode`, `RoleProfile`, `NamespaceSet`, `MountPolicy`, `CgroupPlacement`, `ReadinessPredicate`; `packages/d2bd/src/`: `DagExecutor`, `NodeOutcome`, `NodeHistory`, `NodeBudget`, `SplitReadinessMode`; `packages/d2bd/src/pidfd_table.rs`: `PidfdTable`, `PidfdEntry`, `PidfdRegistration`, `WaitTermination`, `BrokerReapLog`; `packages/d2b-broker/` SpawnRunner; `packages/d2b-guestd/src/exec.rs`, `exec_linux.rs`, `exec_pty.rs`, `detached.rs`; `packages/d2b-realm-core/src/execution.rs`: `ExecState`, `ExecAttachMode`, `ExecStartRequest`, `ExecAttachRequest` (current exec lifecycle analog for EphemeralProcess); `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind::UnsafeLocal` → user-only Host `isolationPosture="none"`, `IsolationPosture::UnsafeLocal` → Host `isolationPosture="none"` (these current enum variants are evidence for the no-isolation posture concept; they are retained in current evidence citations but not carried forward as target naming); `packages/d2b-core/src/workload_identity.rs`: `WorkloadBackend::UnsafeLocal` → Host `isolationPosture="none"` (same evidence classification) | +| Current anchor (Process/EphemeralProcess) | `packages/d2b-core/src/processes.rs`: `ProcessRole` (18 variants), `VmProcessDag`, `ProcessNode`, `RoleProfile`, `NamespaceSet`, `MountPolicy`, `CgroupPlacement`, `ReadinessPredicate`; `packages/d2bd/src/`: `DagExecutor`, `NodeOutcome`, `NodeHistory`, `NodeBudget`, `SplitReadinessMode`; `packages/d2bd/src/pidfd_table.rs`: `PidfdTable`, `PidfdEntry`, `PidfdRegistration`, `WaitTermination`, `BrokerReapLog`; `packages/d2b-broker/` SpawnRunner; `packages/d2b-guestd/src/exec.rs`, `exec_linux.rs`, `exec_pty.rs`, `detached.rs`; `packages/d2b-realm-core/src/execution.rs`: `ExecState`, `ExecAttachMode`, `ExecStartRequest`, `ExecAttachRequest` (current exec lifecycle analog for EphemeralProcess); `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind::UnsafeLocal` → user-only Host `isolationPosture="none"`, `IsolationPosture::UnsafeLocal` → Host `isolationPosture="none"` (these current enum variants are evidence for the no-isolation posture concept; they are retained in current evidence citations but not carried forward as target naming); `packages/d2b-contracts/src/workload_identity.rs`: `WorkloadBackend::UnsafeLocal` → Host `isolationPosture="none"` (same evidence classification) | | Process evidence class | `ProcessRole`/`VmProcessDag`/`ProcessNode`/`RoleProfile`/`PidfdTable` implemented-and-reachable; `ExecState`/`ExecStartRequest` implemented-and-reachable for guest exec; Process/EphemeralProcess ResourceTypes are ADR-only | -| Current anchor (unsafe-local) | `packages/d2b-unsafe-local-helper/src/`: `lib.rs`, `protocol.rs` (`HelperClient`), `runtime.rs` (`ScopeRuntime`, `SupervisorSpec`), `systemd.rs`; `packages/d2bd/src/unsafe_local_helper.rs`; `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind::UnsafeLocal`, `IsolationPosture::UnsafeLocal`; `packages/d2b-core/src/workload_identity.rs`: `WorkloadBackend::UnsafeLocal`; `nixos-modules/options-realms-workloads.nix` (`d2b.realms..workloads..kind = "unsafe-local"`) | +| Current anchor (unsafe-local) | `packages/d2b-unsafe-local-helper/src/`: `lib.rs`, `protocol.rs` (`HelperClient`), `runtime.rs` (`ScopeRuntime`, `SupervisorSpec`), `systemd.rs`; `packages/d2bd/src/unsafe_local_helper.rs`; `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind::UnsafeLocal`, `IsolationPosture::UnsafeLocal`; `packages/d2b-contracts/src/workload_identity.rs`: `WorkloadBackend::UnsafeLocal`; `nixos-modules/options-realms-workloads.nix` (`d2b.realms..workloads..kind = "unsafe-local"`) | | unsafe-local evidence class | implemented-and-reachable (`HelperClient`/`ScopeRuntime`/`WorkloadProviderKind::UnsafeLocal` are all live); v3 user-only Host (`isolationPosture="none"`) is ADR-only | | Current anchor (guestd) | `packages/d2b-guestd/src/`: `auth.rs`, `exec.rs` (`ExecPolicy`, `ExecState`, `ExecError`, `ExitOutcome`, `SpawnedProcess`, `RingChunk`), `exec_linux.rs`, `exec_pty.rs`, `detached.rs` (`ManagedUnit`, `UnitError`, `UnitIdentity`), `detached_registry.rs`, `service.rs`, `shell.rs` (`ShellRuntime`, `ShellRuntimeConfig`), `login_session.rs`; `packages/d2b-realm-core/src/execution.rs`: `ExecState`, `ExecAttachMode`, `ExecStartRequest` (guestd uses these DTOs in the vsock/ttrpc protocol) | | guestd evidence class | implemented-and-reachable for guest exec; v3 EphemeralProcess/Process/ComponentSession is ADR-only | @@ -2359,7 +2359,7 @@ A work item whose `Destination` row introduces a new `d2b-provider-*` crate must | --- | --- | | Work item ID | `ADR046-exec-001` | | Dependency/owner | W0 shared contract root; `d2b-contracts` | -| Current source | `packages/d2b-core/src/processes.rs`: `ProcessRole` (18 variants), `ProcessNode`, `RoleProfile`, `NamespaceSet`, `MountPolicy`, `CgroupPlacement`, `ReadinessPredicate`; `packages/d2b-core/src/minijail_profile.rs`: `MinijailProfile`, `UserNamespaceProfile`, `NamespaceSet`, `MountPolicy`, `BindMount`, `CgroupPlacement`; `packages/d2b-core/src/storage.rs`: `StoragePathSpec`, `AclGrant`, `CleanupPolicy`, `RepairPolicy`; `packages/d2b-realm-core/src/ids.rs`: `RealmId`, `WorkloadId` (→ GuestRef), `NodeId` (→ HostRef), `ProviderId` (→ Provider ResourceRef), `ExecutionId` (→ EphemeralProcess exec identity), `PrincipalId` (→ User ResourceRef), `AllocatorLeaseId`, `ControllerGenerationId`; `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind` (`LocalVm`→runtime-cloud-hypervisor Provider, `QemuMedia`→runtime-qemu-media Provider, `ProviderManaged`→ACA/relay Providers, `UnsafeLocal`→user-only Host `isolationPosture="none"`), `IsolationPosture` (`VirtualMachine`→Guest, `ProviderManaged`→Guest, `UnsafeLocal`→Host `isolationPosture="none"`), `WorkloadExecutionPosture`, `WorkloadSummary`, `WorkloadState`; `packages/d2b-realm-core/src/target.rs`: `RealmTarget`, `TargetName`, `RealmTargetParser` (current analog for `/` ResourceRef parsing); `packages/d2b-realm-core/src/realm.rs`: `RealmPath`, `RealmControllerPlacement`, `EntrypointMode` (current Zone hierarchy analog); `packages/d2b-core/src/workload_identity.rs`: `WorkloadIdentity`, `WorkloadTarget` (= `RealmTarget`), `WorkloadBackend`, `WorkloadRuntimeIntent` (identity/backend separation reuse model for Host/Guest ResourceType split) | +| Current source | `packages/d2b-core/src/processes.rs`: `ProcessRole` (18 variants), `ProcessNode`, `RoleProfile`, `NamespaceSet`, `MountPolicy`, `CgroupPlacement`, `ReadinessPredicate`; `packages/d2b-core/src/minijail_profile.rs`: `MinijailProfile`, `UserNamespaceProfile`, `NamespaceSet`, `MountPolicy`, `BindMount`, `CgroupPlacement`; `packages/d2b-core/src/storage.rs`: `StoragePathSpec`, `AclGrant`, `CleanupPolicy`, `RepairPolicy`; `packages/d2b-realm-core/src/ids.rs`: `RealmId`, `WorkloadId` (→ GuestRef), `NodeId` (→ HostRef), `ProviderId` (→ Provider ResourceRef), `ExecutionId` (→ EphemeralProcess exec identity), `PrincipalId` (→ User ResourceRef), `AllocatorLeaseId`, `ControllerGenerationId`; `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind` (`LocalVm`→runtime-cloud-hypervisor Provider, `QemuMedia`→runtime-qemu-media Provider, `ProviderManaged`→ACA/relay Providers, `UnsafeLocal`→user-only Host `isolationPosture="none"`), `IsolationPosture` (`VirtualMachine`→Guest, `ProviderManaged`→Guest, `UnsafeLocal`→Host `isolationPosture="none"`), `WorkloadExecutionPosture`, `WorkloadSummary`, `WorkloadState`; `packages/d2b-realm-core/src/target.rs`: `RealmTarget`, `TargetName`, `RealmTargetParser` (current analog for `/` ResourceRef parsing); `packages/d2b-realm-core/src/realm.rs`: `RealmPath`, `RealmControllerPlacement`, `EntrypointMode` (current Zone hierarchy analog); `packages/d2b-contracts/src/workload_identity.rs`: `WorkloadIdentity`, `WorkloadTarget` (= `RealmTarget`), `WorkloadBackend`, `WorkloadRuntimeIntent` (identity/backend separation reuse model for Host/Guest ResourceType split) | | Reuse source | `packages/d2b-contracts/src/v3/` as destination; no equivalent main source for Host/Guest/Process ResourceType contracts | | Reuse action | adapt | | Destination | `packages/d2b-contracts/`, `packages/d2b-contracts/`, `packages/d2b-contracts/`, `packages/d2b-contracts/`, `packages/d2b-contracts/`, `packages/d2b-contracts/`, `packages/d2b-contracts/` | @@ -2496,7 +2496,7 @@ A work item whose `Destination` row introduces a new `d2b-provider-*` crate must | --- | --- | | Work item ID | `ADR046-exec-009` | | Dependency/owner | ADR046-exec-001; unsafe-local migration owner | -| Current source | `packages/d2b-unsafe-local-helper/src/lib.rs`: `UserdConfig`, protocol traits; `packages/d2b-unsafe-local-helper/src/runtime.rs` (`ScopeRuntime`, `SupervisorSpec`); `packages/d2b-unsafe-local-helper/src/systemd.rs`; `packages/d2bd/src/unsafe_local_helper.rs`; `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind::UnsafeLocal`, `IsolationPosture::UnsafeLocal` (current evidence that the no-isolation posture exists and is classified separately from VM isolation - the exact semantics this spec's `Host.spec.isolationPosture="none"` preserves); `packages/d2b-core/src/workload_identity.rs`: `WorkloadBackend::UnsafeLocal`; `nixos-modules/options-realms-workloads.nix` (`d2b.realms..workloads..kind = "unsafe-local"`) | +| Current source | `packages/d2b-unsafe-local-helper/src/lib.rs`: `UserdConfig`, protocol traits; `packages/d2b-unsafe-local-helper/src/runtime.rs` (`ScopeRuntime`, `SupervisorSpec`); `packages/d2b-unsafe-local-helper/src/systemd.rs`; `packages/d2bd/src/unsafe_local_helper.rs`; `packages/d2b-realm-core/src/workload.rs`: `WorkloadProviderKind::UnsafeLocal`, `IsolationPosture::UnsafeLocal` (current evidence that the no-isolation posture exists and is classified separately from VM isolation - the exact semantics this spec's `Host.spec.isolationPosture="none"` preserves); `packages/d2b-contracts/src/workload_identity.rs`: `WorkloadBackend::UnsafeLocal`; `nixos-modules/options-realms-workloads.nix` (`d2b.realms..workloads..kind = "unsafe-local"`) | | Reuse action | adapt | | Destination | `packages/d2b-provider-system-core/src/host.rs` (user-only no-isolation Host); `nixos-modules/options-zones.nix` (Nix unsafe-local Host declaration) | | Detailed design | v3 unsafe-local migration: `kind = "unsafe-local"` in the current Nix Realm workload model becomes a Host resource with `providerRef: Provider/system-core`, `spec.isolationPosture: "none"`, `defaultDomain: user`, `allowedDomains: [user]`, `defaultUserRef: User/`. This is a Host ResourceType, not a Guest and not a v3 Provider. Child Process and EphemeralProcess resources on this Host use the normal Process Providers (Provider/system-systemd for user-domain transient user scope; Provider/system-minijail is also valid for callers that explicitly request namespace isolation within the user session). No special unsafe-local-specific Provider is introduced. The explicit no-isolation posture and its warnings are preserved: Host status reflects `isolationPosture="none"` and this is surfaced in every operator CLI/UI view as an explicit "no isolation boundary" warning; `ProcessEffect` audit records (launch, stop, adopt, quarantine) for child Processes and EphemeralProcesses carry the stable `no_isolation=true` attribute; operator CLI/UI always shows the warning and may not suppress it. The `no_isolation=true` attribute belongs on ProcessEffect records only - it must NOT appear on OTEL metric labels, span attributes, log fields, or audit records for other event kinds. The legacy helper protocol (`d2b-unsafe-local-helper`) is not exposed as a v3 ComponentSession service. | diff --git a/docs/specs/ADR-046-resources-zone-control.md b/docs/specs/ADR-046-resources-zone-control.md index 2e1266005..0419158ee 100644 --- a/docs/specs/ADR-046-resources-zone-control.md +++ b/docs/specs/ADR-046-resources-zone-control.md @@ -4401,7 +4401,7 @@ Evidence classes: | `MAX_REALM_LABELS = 16` | `d2b-realm-core/src/realm.rs:67` | `implemented-and-reachable` | Compiler-only `parentZone` ancestry bound | | `RealmControllerPlacement::{HostLocal, GatewayVm, CloudFullHost, ProviderController, ProviderAgent}` | `d2b-realm-core/src/realm.rs:26` | `implemented-and-reachable` | **Partially reused**: these placement labels map to Provider component `placement` descriptor semantics, but the target is a Provider resource field, not a realm process property. Not a 1:1 rename. | | `EntrypointMode::{HostResident, GatewayBacked}` | `d2b-realm-core/src/realm.rs:12` | `implemented-and-reachable` | Informs ZoneLink transport binding (host-local socket vs. remote transport); maps to the resolved `transportProviderRef` selector semantics | -| `RealmTarget { workload: WorkloadId, realm: RealmPath }` | `d2b-realm-core/src/target.rs:39` | `implemented-and-reachable` (CLI routing path) | `RealmTarget` is the current addressable unit (`..d2b`); maps to `ResourceRef` (target scoped to Zone); NOT a Zone identity. `WorkloadTarget = RealmTarget` alias in `d2b-core/src/workload_identity.rs:55` | +| `RealmTarget { workload: WorkloadId, realm: RealmPath }` | `d2b-realm-core/src/target.rs:39` | `implemented-and-reachable` (CLI routing path) | `RealmTarget` is the current addressable unit (`..d2b`); maps to `ResourceRef` (target scoped to Zone); NOT a Zone identity. `WorkloadTarget = RealmTarget` alias in `d2b-contracts/src/workload_identity.rs:55` | | `TargetName`, `RealmTargetParser`, `RealmTargetParseError` | `d2b-realm-core/src/target.rs:122,373,280` | `implemented-and-reachable` | Maps to ResourceRef `/` parser in ADR046-identities-001 | | `LegacyNodeQualifiedTarget` | `d2b-realm-core/src/target.rs:242` | `implemented-and-reachable` | Migration artifact; removed after target format normalizes to ResourceRef | @@ -4506,7 +4506,7 @@ Evidence classes: | `EnvironmentPosture::{RuntimeManaged, SystemdUserManagerAmbient}` | `d2b-realm-core/src/workload.rs:39` | `implemented-and-reachable` | `SystemdUserManagerAmbient` is the unsafe-local environment posture; maps to Host `status.observedPosture.environment` field and audit record body; not emitted as an OTEL label | | `ExecutionIdentityPosture::{WorkloadUser, ProviderManaged, AuthenticatedRequesterUid}` | `d2b-realm-core/src/workload.rs:61` | `implemented-and-reachable` | `AuthenticatedRequesterUid` is the unsafe-local identity posture; maps to Host `spec.defaultUserRef=User/` and audit label `execution_identity=authenticated-requester-uid` | | `SessionPersistencePosture::{RuntimeManaged, UserManagerLifetime}` | `d2b-realm-core/src/workload.rs:73` | `implemented-and-reachable` | `UserManagerLifetime` is the unsafe-local session posture; maps to Host status field noting session lifetime bound to the systemd user manager | -| `UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalLauncherItem::{Exec, Shell}`, `UnsafeLocalExecItem`, `UnsafeLocalShellItem`, `UnsafeLocalShellPolicy` | `d2b-core/src/unsafe_local_workloads.rs:16,47,106,129,141,150` | `implemented-and-reachable` (consumed by `d2b-core/src/bundle_resolver.rs:85,106`) | Private configured-item contract loaded via bundle resolver. `UnsafeLocalWorkload.identity` → Host `metadata.name` + `spec.defaultUserRef`; `UnsafeLocalShellPolicy.{defaultName, maxSessions}` → Host `spec.shellPolicy`; `UnsafeLocalExecItem` → Host launcher item contract. Constants: `MAX_UNSAFE_LOCAL_WORKLOADS=256`, `MAX_LAUNCHER_ITEMS_PER_WORKLOAD=64`, `MAX_UNSAFE_LOCAL_SHELL_SESSIONS=64` → Host cardinality bounds | +| `UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalLauncherItem::{Exec, Shell}`, `UnsafeLocalExecItem`, `UnsafeLocalShellItem`, `UnsafeLocalShellPolicy` | `d2b-contracts/src/unsafe_local_workloads.rs:16,47,106,129,141,150` | `implemented-and-reachable` (consumed by `d2b-core/src/bundle_resolver.rs:85,106`) | Private configured-item contract loaded via bundle resolver. `UnsafeLocalWorkload.identity` → Host `metadata.name` + `spec.defaultUserRef`; `UnsafeLocalShellPolicy.{defaultName, maxSessions}` → Host `spec.shellPolicy`; `UnsafeLocalExecItem` → Host launcher item contract. Constants: `MAX_UNSAFE_LOCAL_WORKLOADS=256`, `MAX_LAUNCHER_ITEMS_PER_WORKLOAD=64`, `MAX_UNSAFE_LOCAL_SHELL_SESSIONS=64` → Host cardinality bounds | | `HelperRegistry`, `bind_helper_socket`, `dispatch_launch`, `HelperReply`, `HelperSnapshot`, `active_generation()` | `d2bd/src/unsafe_local_helper.rs:41,62,149,167,176,208,221` | `implemented-and-reachable` (live in `d2bd/src/lib.rs:1346-1468`) | Per-uid launch broker for unsafe-local helper sessions, bound at daemon startup (`d2bd/src/lib.rs:1356`). Maps to Zone runtime Host/Process broker: `dispatch_launch` → Process launch request; `HelperRegistry.allowed_uids` → Host subject UID allowlist derived from `spec.defaultUserRef` | | `d2b.realms..policy.allowUnsafeLocal` | `nixos-modules/options-realms.nix:346` | `generated-or-eval-contract` | Gate option that permits `kind = "unsafe-local"` workloads in a realm; assertion at `nixos-modules/assertions.nix:730` blocks unsafe-local without this flag. Maps to a separate Host admission gate for user-domain unsafe-local resources, not Zone.spec | | `kind = "unsafe-local"` enum value, doc "Host-user process runtime with no isolation boundary" | `nixos-modules/options-realms-workloads.nix:221,233` | `generated-or-eval-contract` | Nix workload `kind` enum value for unsafe-local Host resources. Maps to Host resource with `spec.defaultDomain=user` authored via `d2b.zones..resources. = { type = "Host"; spec = { ... }; };` (ADR046-zone-control-008) | @@ -4693,7 +4693,7 @@ None of the following exist in baseline: | --- | --- | | Work item ID | `ADR046-zone-control-008` | | Dependency/owner | ADR046-zone-control-001 (Zone resource); ADR046-zone-control-003 (Provider/system-core installed) | -| Current source | `d2b-realm-core/src/workload.rs:13,27,83` (`WorkloadProviderKind::UnsafeLocal`, `IsolationPosture::UnsafeLocal`, `WorkloadExecutionPosture` with canonical unsafe-local tuple at lines 206-211: `isolation=unsafe-local`, `environment=systemd-user-manager-ambient`, `executionIdentity=authenticated-requester-uid`, `sessionPersistence=user-manager-lifetime` - `implemented-and-reachable`, baseline `b5ddbed6`); `d2b-core/src/unsafe_local_workloads.rs:16,47,106,150` (`UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalShellPolicy`, `MAX_UNSAFE_LOCAL_SHELL_SESSIONS=64`, `MAX_UNSAFE_LOCAL_WORKLOADS=256` - `implemented-and-reachable`); `d2bd/src/unsafe_local_helper.rs` (`HelperRegistry`, `bind_helper_socket`, `dispatch_launch` - `implemented-and-reachable`, live in `d2bd/src/lib.rs:1346-1468`); `nixos-modules/options-realms.nix:346` (`policy.allowUnsafeLocal` - `generated-or-eval-contract`); `nixos-modules/options-realms-workloads.nix:221,233` (`kind = "unsafe-local"`, doc "no isolation boundary" - `generated-or-eval-contract`) | +| Current source | `d2b-realm-core/src/workload.rs:13,27,83` (`WorkloadProviderKind::UnsafeLocal`, `IsolationPosture::UnsafeLocal`, `WorkloadExecutionPosture` with canonical unsafe-local tuple at lines 206-211: `isolation=unsafe-local`, `environment=systemd-user-manager-ambient`, `executionIdentity=authenticated-requester-uid`, `sessionPersistence=user-manager-lifetime` - `implemented-and-reachable`, baseline `b5ddbed6`); `d2b-contracts/src/unsafe_local_workloads.rs:16,47,106,150` (`UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalShellPolicy`, `MAX_UNSAFE_LOCAL_SHELL_SESSIONS=64`, `MAX_UNSAFE_LOCAL_WORKLOADS=256` - `implemented-and-reachable`); `d2bd/src/unsafe_local_helper.rs` (`HelperRegistry`, `bind_helper_socket`, `dispatch_launch` - `implemented-and-reachable`, live in `d2bd/src/lib.rs:1346-1468`); `nixos-modules/options-realms.nix:346` (`policy.allowUnsafeLocal` - `generated-or-eval-contract`); `nixos-modules/options-realms-workloads.nix:221,233` (`kind = "unsafe-local"`, doc "no isolation boundary" - `generated-or-eval-contract`) | | Reuse action | adapt | | Destination | `packages/d2b-contracts/` (Host resource schema, user-domain variant); `packages/d2b-core-controller/` (reconciler owned by Provider/system-core); Nix Host authoring via `d2b.zones..resources. = { type = "Host"; spec = { ... }; };` (validated per ResourceTypeSchema; no separate `options-zones-hosts.nix` submodule) | | Detailed design | Host ResourceType schema for user-domain variant: `spec.defaultDomain=user`, `spec.allowedDomains=[user]`, `spec.defaultUserRef=User/`, `spec.shellPolicy` (adapted from `UnsafeLocalShellPolicy`), `spec.launcherItems` (adapted from `UnsafeLocalLauncherItem`). No-isolation posture recorded in `status.observedPosture`. A dedicated Host admission gate blocks unsafe-local Host creation without opt-in. Mandatory no-isolation warning in Host `status.conditions[0].message` and CLI/UI output for all Host commands. No-isolation posture included in audit record body (`isolation=no-isolation`); it is never emitted as an OTEL metric label value or span attribute. Child processes use standard Process Providers - no Provider resource with name or kind `unsafe-local` is created. Cardinality bounds: max 256 user-domain Hosts per Zone, max 64 launcher items per Host, max 64 shell sessions per Host. Primary reuse disposition: `adapt`. Preserved source-plan detail: adapt (`WorkloadExecutionPosture` unsafe-local posture tuple → Host `status.observedPosture`; posture details in audit record body, not OTEL labels; `UnsafeLocalShellPolicy.{defaultName,maxSessions}` → Host `spec.shellPolicy`; `HelperRegistry.dispatch_launch` → Zone runtime Host process launch broker; `policy.allowUnsafeLocal` → dedicated Host admission gate); new (Host ResourceType user-domain schema with `defaultDomain`, `allowedDomains`, `defaultUserRef`, `shellPolicy`, cardinality bounds). | @@ -4711,7 +4711,7 @@ None of the following exist in baseline: | --- | --- | | Work item ID | `ADR046-zone-control-009` | | Dependency/owner | ADR046-zone-control-001; Zone store (ADR046-store-001); Quota handler owner | -| Current source | `packages/d2b-realm-core/src/ids.rs` (`LABEL_PATTERN`, `MAX_ID_LEN` - ResourceName validation for quotaRef); `packages/d2b-core/src/unsafe_local_workloads.rs:16-164` (`MAX_UNSAFE_LOCAL_WORKLOADS=256`, etc. - bound evidence for quota ceiling defaults); no current quota ResourceType exists (`ADR-only`) | +| Current source | `packages/d2b-realm-core/src/ids.rs` (`LABEL_PATTERN`, `MAX_ID_LEN` - ResourceName validation for quotaRef); `packages/d2b-contracts/src/unsafe_local_workloads.rs:16-164` (`MAX_UNSAFE_LOCAL_WORKLOADS=256`, etc. - bound evidence for quota ceiling defaults); no current quota ResourceType exists (`ADR-only`) | | Reuse source | None | | Reuse action | create | | Destination | `packages/d2b-contracts/`; `packages/d2b-core-controller/`; `packages/d2b-resource-api/` | @@ -4929,7 +4929,7 @@ Evidence class for all: `main-reuse-source`. | --- | --- | | Work item ID | `ADR046-zone-control-016` | | Dependency/owner | ADR046-zone-control-015; ADR046-zone-control-001; configuration publication handler owner | -| Current source | `packages/d2bd/src/lib.rs` lines 1408 and 16741 (`RealmControllersJson` load - live active generation load pattern); `nixos-modules/realm-controller-config-json.nix` (current config bundle emit to `/etc/d2b/`); `packages/d2b-realm-core/src/allocator_engine.rs` (generation/activation pattern); `packages/d2b-core/src/unsafe_local_workloads.rs:16-164` (`MAX_UNSAFE_LOCAL_WORKLOADS=256`, etc. - bounds reference for Credential/Host cleanup) | +| Current source | `packages/d2bd/src/lib.rs` lines 1408 and 16741 (`RealmControllersJson` load - live active generation load pattern); `nixos-modules/realm-controller-config-json.nix` (current config bundle emit to `/etc/d2b/`); `packages/d2b-realm-core/src/allocator_engine.rs` (generation/activation pattern); `packages/d2b-contracts/src/unsafe_local_workloads.rs:16-164` (`MAX_UNSAFE_LOCAL_WORKLOADS=256`, etc. - bounds reference for Credential/Host cleanup) | | Reuse source | main `a1cc0b2d`: `packages/d2b-session/src/lifecycle.rs` `begin_reconnect` exponential backoff logic (cleanup retry); `packages/d2b-state/` lock/lease types (ADR046-store-001 dependency for bundle file locking) | | Reuse action | adapt | | Destination | `packages/d2b-core-controller/{mod,bundle_apply,generation_transition}.rs` (Phase 3 activation, diff, delete dispatch); `packages/d2b-core-controller/` (pending tracking, status, stuck detection, rollback verb handler) | diff --git a/docs/specs/ADR-046-telemetry-audit-and-support.md b/docs/specs/ADR-046-telemetry-audit-and-support.md index e9bf3fb6a..030eabdd6 100644 --- a/docs/specs/ADR-046-telemetry-audit-and-support.md +++ b/docs/specs/ADR-046-telemetry-audit-and-support.md @@ -37,7 +37,7 @@ baseline symbols named below. | `ProcessRole::OtelHostBridge` | `Process` resource under `observability-otel` Provider | implemented-and-reachable | | `RunnerRole::OtelHostBridge` (`d2b-contracts/src/broker_wire.rs`) | `Process` resource under `observability-otel` Provider; broker `SpawnRunner` becomes Provider supervisor ticket | implemented-and-reachable | | `RunnerRole::CloudHypervisor`, `QemuMedia`, `Virtiofsd`, `Swtpm`, etc. | `Process` or `EphemeralProcess` under each VM/Device Provider; see ADR-046-components-processes-and-sandbox | implemented-and-reachable | -| `WorkloadIdentity` / `WorkloadTarget` / `RealmTarget` (`d2b-core/src/workload_identity.rs`) | Zone self-resource reference `Zone/` | implemented-and-reachable | +| `WorkloadIdentity` / `WorkloadTarget` / `RealmTarget` (`d2b-contracts/src/workload_identity.rs`) | Zone self-resource reference `Zone/` | implemented-and-reachable | | `d2b.realms` Nix option (`nixos-modules/options-realms.nix`) | `d2b.zones` Nix option (ADR-only target) | generated-or-eval-contract | | `realm-controllers.json` bundle artifact | Zone runtime config (new generated artifact; existing file is retired) | generated-or-eval-contract | | `d2b_daemon_vm_*` metrics with `vm` label (`packages/d2bd/src/metrics.rs`) | `vm` label (VM name) removed from v3 metric labels; VM identity carried only in bounded OTEL resource attributes and permitted audit fields | implemented-and-reachable | @@ -46,7 +46,7 @@ baseline symbols named below. | `config_source = "realm-controllers"` tracing field (`d2b-priv-broker/src/runtime.rs`) | `config_source = "zone-config"` in v3 startup tracing | implemented-and-reachable | | `d2b-clipd/src/audit.rs::AuditEvent.source_realm`, `.destination_realm` | `source_zone`, `destination_zone` (cross-Zone clipboard audit) | implemented-and-reachable | | `kind = "unsafe-local"` workload (`nixos-modules/options-realms-workloads.nix:221,233`) | `Host/` resource - user-only, **no isolation boundary**; reconciled by `Provider/system-core` with `defaultDomain=user`, `allowedDomains=[user]`, `defaultUserRef=User/`; child processes use normal Process Providers; **not** a v3 Provider | implemented-and-reachable | -| `UnsafeLocalWorkloadsJson` / `UnsafeLocalWorkload` / `UnsafeLocalLauncherItem` (`packages/d2b-core/src/unsafe_local_workloads.rs`) | `Host` resource spec serialized in the private bundle; `UnsafeLocalWorkload.identity.runtime_kind = "unsafe-local"` / `provider_id = "unsafe-local"` → `Provider/system-core` catalog entry | implemented-and-reachable | +| `UnsafeLocalWorkloadsJson` / `UnsafeLocalWorkload` / `UnsafeLocalLauncherItem` (`packages/d2b-contracts/src/unsafe_local_workloads.rs`) | `Host` resource spec serialized in the private bundle; `UnsafeLocalWorkload.identity.runtime_kind = "unsafe-local"` / `provider_id = "unsafe-local"` → `Provider/system-core` catalog entry | implemented-and-reachable | | `HelperRegistry` / `HelperConnection` / `dispatch_launch` (`packages/d2bd/src/unsafe_local_helper.rs`) | user-domain process supervision; `HelperRegistry::allowed_uids` → `defaultUserRef=User/` constraint; v3 replaces with normal Process Provider supervisor ticket | implemented-and-reachable | | `DaemonToUnsafeLocalHelper` / `UnsafeLocalHelperToDaemon` / `HelperLaunchRequest` / `HelperShellRequest` (`packages/d2b-contracts/src/unsafe_local_wire.rs`) | internal launch/shell protocol between `d2bd` and the helper binary; retired in v3 when launch moves to Process Provider supervisor ticket | implemented-and-reachable | | `d2b-unsafe-local-helper` binary (`packages/d2b-unsafe-local-helper/src/{main,protocol,runtime,systemd}.rs`) | fixed user-domain supervisor process; v3 equivalent is a user-domain `Process` under `Provider/system-core` | implemented-and-reachable | @@ -1949,7 +1949,7 @@ New `packages/d2b-core-controller/tests/config_cleanup.rs`: | Item | Treatment | | --- | --- | -| Current anchor | (1) `packages/d2bd/src/metrics.rs`: 16-metric hand-rolled Prometheus registry; `vm` name labels; `VM_START_BUCKETS_SECONDS`, `BROKER_REQUEST_BUCKETS_SECONDS`, `ACTIVATION_PHASE_BUCKETS_SECONDS`. (2) `packages/d2bd/src/daemon_audit.rs`: hash-chain JSONL; `DaemonEvent` variants; `VmStartRunnerExitReason`, `RunnerExitKind`, `VmShutdownProvider` enums. **No** `DaemonEvent` for unsafe-local launches - this is a gap documented in the ProcessEffect section. (3) `packages/d2b-broker/src/audit.rs`: `AuditWriteClass`, `AuditDropSummary`, rate-limit, O_APPEND, rotation. (4) `packages/d2b-realm-core/src/audit.rs`: `AuditHash`, `AuditChainLink`, `AuditChainRecord{realm: RealmPath, node: NodeId}`, `AuditStreamKind::{Gateway,RemoteNode,Daemon}`, `AuditEnvelope{realm, node, workload, principal}`, `AuditSinkHealth`. (5) `packages/d2b-realm-core/src/trace_context.rs`: `TraceContext{trace_id, span_id}`. (6) `packages/d2b-realm-core/src/ids.rs`: `RealmId`, `WorkloadId`, `NodeId`, `PrincipalId`, `OperationId`, `CorrelationId`. (7) `packages/d2b-gateway/src/audit.rs`: `GatewayAuditEvent`, `GatewayAuditKind`. (8) `packages/d2b-gateway-runtime/src/audit_jsonl.rs`: `JsonlGatewayAudit`, `DEFAULT_GATEWAY_AUDIT_RETENTION_DAYS`. (9) `packages/d2b-broker/src/ops/audit_op.rs`: `OpAuditRecord`, `SwtpmDirAudit`. (10) `packages/d2b-host/src/otel_host_bridge_argv.rs`, `packages/d2bd/src/otel_host_bridge_readiness.rs`. (11) `nixos-modules/components/observability/{host,stack,guest}.nix`: `scrapeJournal`, `identityName`/`vmName`, `vm.name`/`vm.env`/`vm.role` OTEL resource attributes, SigNoz stack. (12) `packages/d2b-contract-tests/tests/{policy_observability,policy_metrics,minijail_relay_otel}.rs`. (13) `packages/d2b/tests/{audit_contract,host_doctor_contract}.rs`. (14) `packages/d2b-broker/tests/broker_export_audit.rs`. (15) **unsafe-local sources**: `packages/d2b-core/src/unsafe_local_workloads.rs` (`UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalLauncherItem`, `UnsafeLocalExecItem`, `UnsafeLocalShellItem`, `UnsafeLocalShellPolicy`, `UNSAFE_LOCAL_WORKLOADS_SCHEMA_VERSION`, `MAX_UNSAFE_LOCAL_WORKLOADS`); `packages/d2b-contracts/src/unsafe_local_wire.rs` (`HelperHello`, `HelperLaunchRequest`, `HelperShellRequest`, `HelperFailureCode`, `HelperScopeKind`, `DaemonToUnsafeLocalHelper`, `UnsafeLocalHelperToDaemon`); `packages/d2bd/src/unsafe_local_helper.rs` (`HelperRegistry`, `HelperConnection`, `dispatch_launch`, `allowed_uids`, `bind_helper_socket`); `packages/d2b-unsafe-local-helper/src/{main,protocol,runtime,systemd}.rs` (`HelperClient`, `ScopeRuntime`, `run_scope_supervisor`, `SystemdUserScopeManager`); `nixos-modules/options-realms-workloads.nix` (lines 221, 233-235, 264-275: `kind = "unsafe-local"`, null `stateDir`/`runDir`); `nixos-modules/unsafe-local-workloads-json.nix`; `nixos-modules/unsafe-local-helper.nix`. | +| Current anchor | (1) `packages/d2bd/src/metrics.rs`: 16-metric hand-rolled Prometheus registry; `vm` name labels; `VM_START_BUCKETS_SECONDS`, `BROKER_REQUEST_BUCKETS_SECONDS`, `ACTIVATION_PHASE_BUCKETS_SECONDS`. (2) `packages/d2bd/src/daemon_audit.rs`: hash-chain JSONL; `DaemonEvent` variants; `VmStartRunnerExitReason`, `RunnerExitKind`, `VmShutdownProvider` enums. **No** `DaemonEvent` for unsafe-local launches - this is a gap documented in the ProcessEffect section. (3) `packages/d2b-broker/src/audit.rs`: `AuditWriteClass`, `AuditDropSummary`, rate-limit, O_APPEND, rotation. (4) `packages/d2b-realm-core/src/audit.rs`: `AuditHash`, `AuditChainLink`, `AuditChainRecord{realm: RealmPath, node: NodeId}`, `AuditStreamKind::{Gateway,RemoteNode,Daemon}`, `AuditEnvelope{realm, node, workload, principal}`, `AuditSinkHealth`. (5) `packages/d2b-realm-core/src/trace_context.rs`: `TraceContext{trace_id, span_id}`. (6) `packages/d2b-realm-core/src/ids.rs`: `RealmId`, `WorkloadId`, `NodeId`, `PrincipalId`, `OperationId`, `CorrelationId`. (7) `packages/d2b-gateway/src/audit.rs`: `GatewayAuditEvent`, `GatewayAuditKind`. (8) `packages/d2b-gateway-runtime/src/audit_jsonl.rs`: `JsonlGatewayAudit`, `DEFAULT_GATEWAY_AUDIT_RETENTION_DAYS`. (9) `packages/d2b-broker/src/ops/audit_op.rs`: `OpAuditRecord`, `SwtpmDirAudit`. (10) `packages/d2b-host/src/otel_host_bridge_argv.rs`, `packages/d2bd/src/otel_host_bridge_readiness.rs`. (11) `nixos-modules/components/observability/{host,stack,guest}.nix`: `scrapeJournal`, `identityName`/`vmName`, `vm.name`/`vm.env`/`vm.role` OTEL resource attributes, SigNoz stack. (12) `packages/d2b-contract-tests/tests/{policy_observability,policy_metrics,minijail_relay_otel}.rs`. (13) `packages/d2b/tests/{audit_contract,host_doctor_contract}.rs`. (14) `packages/d2b-broker/tests/broker_export_audit.rs`. (15) **unsafe-local sources**: `packages/d2b-contracts/src/unsafe_local_workloads.rs` (`UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalLauncherItem`, `UnsafeLocalExecItem`, `UnsafeLocalShellItem`, `UnsafeLocalShellPolicy`, `UNSAFE_LOCAL_WORKLOADS_SCHEMA_VERSION`, `MAX_UNSAFE_LOCAL_WORKLOADS`); `packages/d2b-contracts/src/unsafe_local_wire.rs` (`HelperHello`, `HelperLaunchRequest`, `HelperShellRequest`, `HelperFailureCode`, `HelperScopeKind`, `DaemonToUnsafeLocalHelper`, `UnsafeLocalHelperToDaemon`); `packages/d2bd/src/unsafe_local_helper.rs` (`HelperRegistry`, `HelperConnection`, `dispatch_launch`, `allowed_uids`, `bind_helper_socket`); `packages/d2b-unsafe-local-helper/src/{main,protocol,runtime,systemd}.rs` (`HelperClient`, `ScopeRuntime`, `run_scope_supervisor`, `SystemdUserScopeManager`); `nixos-modules/options-realms-workloads.nix` (lines 221, 233-235, 264-275: `kind = "unsafe-local"`, null `stateDir`/`runDir`); `nixos-modules/unsafe-local-workloads-json.nix`; `nixos-modules/unsafe-local-helper.nix`. | | Evidence class | (1) Hand-rolled metrics: implemented-and-reachable (no OTEL SDK). (2-4) Audit JSONL/hash/rate-limit: implemented-and-reachable. (5-6) TraceContext/IDs: implemented-and-reachable. (7-9) Gateway/broker/op audit: implemented-and-reachable. (10) OtelHostBridge runner: implemented-and-reachable. (11) Nix OTEL pipeline: implemented-and-reachable for the v1 daemon; the v3 `observability-otel` Provider is ADR-only. (12-14) Tests: implemented-and-reachable. (15) unsafe-local: implemented-and-reachable; **gap**: no `DaemonEvent` for unsafe-local launch/stop in current daemon. | | Behavior retained | SHA-256 hash chain `prev_hash`/`record_hash`; O_APPEND JSONL segment files; privileged-never-dropped audit rate-limit invariant; `TraceContext` opaque bounded fields; SigNoz backend + OTEL Collector pipeline shape; `vm.name`/`vm.env`/`vm.role` OTEL resource attributes (advisory); journald scrape option; startup-tracing-avoids-host-path policy; `loki_native_otel_resource_attributes` closed allowlist; `broker_export_audit` admin-only / path-free / NDJSON contract; `UnsafeLocalWorkload` private-bundle-only argv/shell policy; `HelperRegistry::allowed_uids` per-UID isolation | | Required delta | Lightweight `BoundedEmitter` crate (no OTEL SDK in core); v3 metrics with no `vm`-name labels; traces with `d2b.zone`/`d2b.provider` resource attributes; v3 resource/RBAC/session/route/state-reset audit records; `zone` field replacing `realm: RealmPath` in all audit records; per-Zone emitter socket; `observability-otel` Provider (full OTEL SDK in its own Process only); `d2b zone doctor`/`support-bundle` CLI; performance histogram benchmarks; **user-only Host resource `isolationPosture: "none"` status field**; **ProcessEffect `no_isolation: true` for all user-only Host (unsafe-local successor) process launches and stops** (gap fill); **CLI/UI isolation warning for user-only Host only**; `isolation-posture-declared` doctor check | @@ -2204,7 +2204,7 @@ New `packages/d2b-core-controller/tests/config_cleanup.rs`: | --- | --- | | Work item ID | `ADR046-host-posture-001` | | Dependency/owner | ADR046-audit-001 + ADR046-core-001; `Provider/system-core` owner | -| Current source | `packages/d2b-core/src/unsafe_local_workloads.rs` (`UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalLauncherItem`, `UNSAFE_LOCAL_WORKLOADS_SCHEMA_VERSION = "v2"`, `MAX_UNSAFE_LOCAL_WORKLOADS = 256`); `packages/d2b-contracts/src/unsafe_local_wire.rs` (`HelperHello.uid: u32`, `HelperLaunchRequest`, `HelperShellRequest`, `HelperScopeKind::{Exec,Shell}`, `DaemonToUnsafeLocalHelper`, `UnsafeLocalHelperToDaemon`); `packages/d2bd/src/unsafe_local_helper.rs` (`HelperRegistry::new(daemon_uid, allowed_uids)`, `dispatch_launch`, `bind_helper_socket`); `packages/d2b-unsafe-local-helper/src/{main,protocol,runtime,systemd}.rs` (`HelperClient`, `ScopeRuntime`, `run_scope_supervisor`, `SystemdUserScopeManager`); `nixos-modules/options-realms-workloads.nix` (lines 221, 233-235 `kind = "unsafe-local"` description; lines 264-275 null `stateDir`/`runDir`); `nixos-modules/unsafe-local-workloads-json.nix` (`runtimeKind = "unsafe-local"`, `providerId = "unsafe-local"`); `nixos-modules/unsafe-local-helper.nix` (service unit) | +| Current source | `packages/d2b-contracts/src/unsafe_local_workloads.rs` (`UnsafeLocalWorkloadsJson`, `UnsafeLocalWorkload`, `UnsafeLocalLauncherItem`, `UNSAFE_LOCAL_WORKLOADS_SCHEMA_VERSION = "v2"`, `MAX_UNSAFE_LOCAL_WORKLOADS = 256`); `packages/d2b-contracts/src/unsafe_local_wire.rs` (`HelperHello.uid: u32`, `HelperLaunchRequest`, `HelperShellRequest`, `HelperScopeKind::{Exec,Shell}`, `DaemonToUnsafeLocalHelper`, `UnsafeLocalHelperToDaemon`); `packages/d2bd/src/unsafe_local_helper.rs` (`HelperRegistry::new(daemon_uid, allowed_uids)`, `dispatch_launch`, `bind_helper_socket`); `packages/d2b-unsafe-local-helper/src/{main,protocol,runtime,systemd}.rs` (`HelperClient`, `ScopeRuntime`, `run_scope_supervisor`, `SystemdUserScopeManager`); `nixos-modules/options-realms-workloads.nix` (lines 221, 233-235 `kind = "unsafe-local"` description; lines 264-275 null `stateDir`/`runDir`); `nixos-modules/unsafe-local-workloads-json.nix` (`runtimeKind = "unsafe-local"`, `providerId = "unsafe-local"`); `nixos-modules/unsafe-local-helper.nix` (service unit) | | Reuse action | adapt | | Destination | `packages/d2b-provider-system-core/src/{host_reconciler.rs,host_status.rs,host_process_audit.rs}`; adapted `nixos-modules/unsafe-local-workloads-json.nix`; `packages/d2b-provider-system-core/` | | Detailed design | `Provider/system-core` reconciler: (1) On user-only `Host` resource creation (`defaultDomain=user`, `allowedDomains=[user]`), set `status.isolationPosture = "none"` and `status.isolationPostureMessage = "..."` unconditionally; reject any operator-supplied value for these fields. Host resources with other execution policies do not receive `isolationPosture`. (2) On every user-only Host process launch: emit `ProcessEffect{event:"launch", provider:"system-core-user", domain:"user", no_isolation:true, ...}` audit record. (3) On every user-only Host process stop: emit `ProcessEffect{event:"stop", ...}`. (4) `d2b zone list`/`inspect` CLI renders `⚠ no isolation boundary (user domain)` annotation only for `Host` resources with `isolationPosture: "none"`; annotation is not suppressible. (5) `isolation-posture-declared` doctor check: passes when user-only `Host` resource status has `isolationPosture: "none"`; omitted when Zone has no user-only `Host` resources. (6) `no_isolation=true` is emitted in `ProcessEffect` records only; it does not appear in any OTEL span attribute, log field, or metric label. Primary reuse disposition: `adapt`. Preserved source-plan detail: adapt `UnsafeLocalWorkload` private-bundle contract for the `Host` resource spec payload; adapt `HelperRegistry::allowed_uids` constraint as `defaultUserRef=User/` validation; adapt Nix `unsafe-local-workloads-json.nix` emitter for the new Host resource shape; gap-fill: add `ProcessEffect{no_isolation:true}` at `dispatch_launch` / stop call sites. | diff --git a/packages/Cargo.guest.lock b/packages/Cargo.guest.lock index 4d1a0a3c1..c7e030c6f 100644 --- a/packages/Cargo.guest.lock +++ b/packages/Cargo.guest.lock @@ -839,6 +839,7 @@ dependencies = [ "serde_json", "sha2", "tokio", + "tracing", ] [[package]] diff --git a/packages/d2b-provider-seccomp-profile/src/lib.rs b/packages/d2b-provider-seccomp-profile/src/lib.rs index fb1173bb0..33fe1fc9c 100644 --- a/packages/d2b-provider-seccomp-profile/src/lib.rs +++ b/packages/d2b-provider-seccomp-profile/src/lib.rs @@ -20,6 +20,7 @@ mod seccomp_profile; pub use driver::seccomp_profile_descriptor; pub use seccomp_profile::{ - DeviceBind, DeviceNodeKind, DeviceNodePath, SECCOMP_PROFILE_RESOURCE_TYPE, - SeccompCgroups, SeccompDeviceAccess, SeccompNamespaces, SeccompProfileSpec, + DeviceBind, DeviceNodeKind, DeviceNodePath, MAX_DEVICE_NODE_PATH_BYTES, + MAX_SECCOMP_DEVICE_BINDS, MAX_SECCOMP_SYSCALLS, SECCOMP_PROFILE_RESOURCE_TYPE, SeccompCgroups, + SeccompDeviceAccess, SeccompNamespaces, SeccompProfileContractError, SeccompProfileSpec, }; diff --git a/packages/d2bd-runtime/src/broker_transport.rs b/packages/d2bd-runtime/src/broker_transport.rs index 9916f0c28..f5871d1d3 100644 --- a/packages/d2bd-runtime/src/broker_transport.rs +++ b/packages/d2bd-runtime/src/broker_transport.rs @@ -63,17 +63,25 @@ pub fn dispatch_broker_request_to_socket( /// # Errors /// /// Returns `WireInvalidFrame` when the cited identities are not canonical -/// audit digests, so a malformed broker claim cannot poison the log. +/// audit digests. The identities are produced by hashing the request's +/// authoritative fields, so the canonical spelling holds by construction and +/// today's producers cannot reach the refusal; it converts the fallible +/// digest constructor into a typed error so this dispatch path never panics +/// on a value derived from the wire. pub fn default_audit_join_context( request: &BrokerRequest, ) -> Result, TypedError> { let Some((zone_id, operation_identity)) = request.authoritative_audit_join() else { return Ok(None); }; - let zone_id = CanonicalAuditDigest::parse(zone_id) - .map_err(|_| TypedError::WireInvalidFrame { detail: "audit zone identity invalid".to_owned() })?; + let zone_id = + CanonicalAuditDigest::parse(zone_id).map_err(|_| TypedError::WireInvalidFrame { + detail: "audit zone identity invalid".to_owned(), + })?; let operation_identity = CanonicalAuditDigest::parse(operation_identity).map_err(|_| { - TypedError::WireInvalidFrame { detail: "audit operation identity invalid".to_owned() } + TypedError::WireInvalidFrame { + detail: "audit operation identity invalid".to_owned(), + } })?; Ok(Some(AuditJoinContext { zone_id, @@ -345,27 +353,7 @@ impl std::error::Error for ModeBoundBrokerError {} mod tests { use super::*; use d2b_contracts::types::{RoleId, VmId}; - use d2b_contracts_broker::broker_wire::{ - HelloRequest, LaunchMinijailChildRequest, SecretByIdRequest, - }; - - fn request_with_opaque_id(opaque_id: &str) -> BrokerRequest { - BrokerRequest::InjectSecretById(SecretByIdRequest { - opaque_id: opaque_id.to_owned(), - tracing_span_id: None, - }) - } - - #[test] - fn malformed_audit_join_material_does_not_panic() { - // The audit-join material is wire-supplied (a client-controlled - // opaque id), so a non-canonical value must never panic the daemon. - let request = request_with_opaque_id("not-a-canonical-digest"); - let context = default_audit_join_context(&request) - .expect("malformed audit-join material must not panic") - .expect("audit join is present for secret requests"); - assert!(context.zone_id.as_str().starts_with("sha256:")); - } + use d2b_contracts_broker::broker_wire::{HelloRequest, LaunchMinijailChildRequest}; #[test] fn request_without_audit_join_yields_none() { @@ -438,6 +426,8 @@ mod tests { Err(TypedError::InternalBrokerTimeout { .. }) )); let future = Instant::now() + Duration::from_secs(60); - assert!(broker_remaining_before_op(future, Path::new("/run/d2b/guest-broker.sock")).is_ok()); + assert!( + broker_remaining_before_op(future, Path::new("/run/d2b/guest-broker.sock")).is_ok() + ); } } diff --git a/tests/fixtures/guest-rust-workspace/d2b-core.Cargo.toml b/tests/fixtures/guest-rust-workspace/d2b-core.Cargo.toml index 76a6a4bec..15ad18004 100644 --- a/tests/fixtures/guest-rust-workspace/d2b-core.Cargo.toml +++ b/tests/fixtures/guest-rust-workspace/d2b-core.Cargo.toml @@ -26,3 +26,4 @@ semver = "1" rustix = { workspace = true } sha2 = { workspace = true } tokio = { workspace = true } +tracing = "0.1" From 003cfc7afd72fad9055bdb3a11cb45c5e2bcb4d1 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 10:44:13 -0700 Subject: [PATCH 725/726] fix(audit): regenerate the Guest policy inputs and tighten two tests Adding the mirror's `tracing` dependency moved `packages/Cargo.guest.lock`, so the committed guest-static policy inputs recorded a stale `lockSha256` and the drift gate failed; regenerated through `make generate`, which also emits the new `d2b-core -> tracing` closure edge. The storage-lifecycle schema test now compares the issue kinds its fixtures exercise against the kinds the published schema declares, instead of asserting the length of the literal list it just built, and the auth-status contract's module doc no longer says the launcher gains `up`. --- .../tests/storage_lifecycle_schema.rs | 29 ++++++++++++++++--- packages/d2b/tests/auth_status_contract.rs | 5 ++-- .../guest-static/policy/Cargo.lock | 1 + .../guest-static/policy/closure.json | 8 ++++- .../guest-static/policy/metadata.json | 2 +- .../guest-static/production/Cargo.lock | 1 + .../guest-static/production/closure.json | 8 ++++- .../guest-static/production/metadata.json | 2 +- .../guest-static/policy/Cargo.lock | 1 + .../guest-static/policy/closure.json | 8 ++++- .../guest-static/policy/metadata.json | 2 +- .../guest-static/production/Cargo.lock | 1 + .../guest-static/production/closure.json | 8 ++++- .../guest-static/production/metadata.json | 2 +- 14 files changed, 64 insertions(+), 14 deletions(-) diff --git a/packages/d2b-core/tests/storage_lifecycle_schema.rs b/packages/d2b-core/tests/storage_lifecycle_schema.rs index 9c9ecc57b..73f3ee0ba 100644 --- a/packages/d2b-core/tests/storage_lifecycle_schema.rs +++ b/packages/d2b-core/tests/storage_lifecycle_schema.rs @@ -15,6 +15,7 @@ use d2b_core::storage_lifecycle::{ SyncContractValidationReason, }; use serde_json::Value; +use std::collections::BTreeSet; /// The committed consumer-facing schema, not a fresh generator run. const PUBLISHED_SCHEMA: &str = @@ -80,16 +81,36 @@ fn every_issue_variant_satisfies_the_published_schema() { .issues .iter() .map(StorageLifecycleIssue::kind_name) - .collect::>(); + .collect::>(); assert_eq!( - variants.len(), - 8, - "one serialized issue per declared variant, so a new variant cannot skip the schema" + variants, + declared_issue_kinds(&schema), + "the fixtures must exercise every issue kind the published schema declares, so a new \ + variant cannot skip the schema" ); validate(&schema, &schema, &bytes).expect("serialized report satisfies the published schema"); } +/// The issue kinds the published schema declares, read from its `oneOf` +/// alternatives rather than from the Rust enum, so a kind the fixtures do not +/// exercise fails here instead of passing unvalidated. +fn declared_issue_kinds(schema: &Value) -> BTreeSet<&str> { + schema + .pointer("/definitions/StorageLifecycleIssue/oneOf") + .and_then(Value::as_array) + .map(|alternatives| { + alternatives + .iter() + .filter_map(|alternative| alternative.pointer("/properties/kind/enum")) + .filter_map(Value::as_array) + .filter_map(|declared| declared.first()) + .filter_map(Value::as_str) + .collect() + }) + .expect("the published schema declares one alternative per issue kind") +} + /// Validate `instance` against `schema`, both borrowed from the published /// document, returning the first disagreement. fn validate(root: &Value, schema: &Value, instance: &Value) -> Result<(), String> { diff --git a/packages/d2b/tests/auth_status_contract.rs b/packages/d2b/tests/auth_status_contract.rs index 40d322289..e83cddc15 100644 --- a/packages/d2b/tests/auth_status_contract.rs +++ b/packages/d2b/tests/auth_status_contract.rs @@ -10,8 +10,9 @@ //! typed deserialize equivalent to the schema check the bash gate did via //! docs/reference/cli-output/auth-status.schema.json); //! * the per-role allowed/denied subcommand authz surface matches the binary's -//! contract (launcher gets `up` but keeps `audit` denied; `none` stays -//! read-only; admin gains `audit` and denies nothing); +//! contract (launcher gains `list`, does not report the retired v2 verb +//! `up` as allowed, and keeps `audit` denied; `none` stays read-only; admin +//! gains `audit` and denies nothing); //! * `auth status --human` summarizes the role and the denied `audit` access. //! //! Unlike the `list` gate, `auth status` is driven entirely by env-file fixtures diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock index bb0790f45..3072ec471 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/Cargo.lock @@ -888,6 +888,7 @@ dependencies = [ "serde_json", "sha2", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json index b9a7d5236..cf113124f 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lock_sha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5353,6 +5353,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json index e7cf3f7f4..2f70e0ac8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lockSha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock index bb0790f45..3072ec471 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/Cargo.lock @@ -888,6 +888,7 @@ dependencies = [ "serde_json", "sha2", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json index 88df3cc63..44cfb911a 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lock_sha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5353,6 +5353,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json index e7cf3f7f4..2f70e0ac8 100644 --- a/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json +++ b/packages/policy-inputs/aarch64-linux/aarch64-unknown-linux-musl/guest-static/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lockSha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock index bb0790f45..3072ec471 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/Cargo.lock @@ -888,6 +888,7 @@ dependencies = [ "serde_json", "sha2", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json index 20236dcbb..1f9113dce 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lock_sha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5353,6 +5353,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json index 8d03d7b6e..c9198ef43 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/policy/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lockSha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock index bb0790f45..3072ec471 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/Cargo.lock @@ -888,6 +888,7 @@ dependencies = [ "serde_json", "sha2", "tokio", + "tracing", ] diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json index b2a60e67d..422433ba3 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/closure.json @@ -11,7 +11,7 @@ "features": [], "default_features": false, "source_authority": "packages/Cargo.guest.lock", - "lock_sha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lock_sha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "packages": [ { "id": "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", @@ -5353,6 +5353,12 @@ "kind": "normal", "target": null }, + { + "from": "d2b-core@0.0.0-bootstrap#path", + "to": "tracing@0.1.44#registry+https://github.com/rust-lang/crates.io-index", + "kind": "normal", + "target": null + }, { "from": "d2b-host@0.0.0-bootstrap#path", "to": "d2b-contracts-resource@0.0.0-bootstrap#path", diff --git a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json index 8d03d7b6e..c9198ef43 100644 --- a/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json +++ b/packages/policy-inputs/x86_64-linux/x86_64-unknown-linux-musl/guest-static/production/metadata.json @@ -2,7 +2,7 @@ "authority": "cargo-locked-metadata", "defaultFeatures": false, "features": [], - "lockSha256": "a67f038b0ff8824e30bc4f1e6cefb5b5817391c66e54ac4088802c3424c73027", + "lockSha256": "9db1081561f765badba0a9f7432156f246cbd3f50b5ba8bd558917b4a354b835", "policyPackageCount": 467, "policyPackageIds": [ "adler2@2.0.1#registry+https://github.com/rust-lang/crates.io-index", From 4e9afdc7c86509c5c161c7508ab0668b60278897 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Sat, 26 Sep 2026 10:51:47 -0700 Subject: [PATCH 726/726] docs: drop the corpus-tracking steps and correct three shipped citations The plan still made committing the audit corpus a wave-0 requirement in its wave map, its assumptions, and U1's heading, approach step and verification, while the same document's R8 and Definition of Done state that the record does not ship and the corpus was deliberately dropped from the tree. Those steps now read as the ledger and baseline work they are. Alongside it: the USBIP lock-taxonomy fragment quotes the three real `device-worker-*` refusal codes instead of truncated tails, the parking-lot fragment names the bounded-worker allow reason instead of a plan identifier, and the v1.0-to-v1.1 migration guide's table header matches the v1.1.2 arrival its own note records. --- changelog.d/w6-03-usbip-lock-error-taxonomy.md | 6 ++++-- changelog.d/w7-26-parking-lot-ban-enforced.md | 6 +++--- docs/how-to/migrate-d2b-v1-0-to-v1-1.md | 2 +- ...-002-refactor-rust-skills-remediation-plan.md | 16 ++++++++++------ 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/changelog.d/w6-03-usbip-lock-error-taxonomy.md b/changelog.d/w6-03-usbip-lock-error-taxonomy.md index c2113a896..2631b1400 100644 --- a/changelog.d/w6-03-usbip-lock-error-taxonomy.md +++ b/changelog.d/w6-03-usbip-lock-error-taxonomy.md @@ -9,5 +9,7 @@ lock record keeps using the broker's own uid and the daemon gid. - d2b-broker: `guest_socket_directory` returns a typed `GuestSocketError` instead of a `&'static str` code, with the same stable refusal strings - ("not-a-plain-name", "not-anchored", "outside-runtime-root") surfaced - through the launch-failure envelope. \ No newline at end of file + (`device-worker-guest-not-a-plain-name`, + `device-worker-runtime-root-not-anchored`, + `device-worker-socket-dir-outside-runtime-root`) surfaced through the + launch-failure envelope. \ No newline at end of file diff --git a/changelog.d/w7-26-parking-lot-ban-enforced.md b/changelog.d/w7-26-parking-lot-ban-enforced.md index bd7ff68e7..52c200d1f 100644 --- a/changelog.d/w7-26-parking-lot-ban-enforced.md +++ b/changelog.d/w7-26-parking-lot-ban-enforced.md @@ -8,9 +8,9 @@ matches a configured method path against the definition a call resolves to, so an alias spelling never matched a call site. Reasons and replacements are unchanged, the sanctioned per-site allow - vocabulary (`synchronous path`, `cfg(test) helper`, R4 worker - boundary) is unchanged, and `parking_lot::Condvar::wait` stays as - configured because `Condvar` is a real type, not an alias. + vocabulary (`synchronous path`, `cfg(test) helper`, the dedicated + bounded-worker reason) is unchanged, and `parking_lot::Condvar::wait` stays + as configured because `Condvar` is a real type, not an alias. ### Fixed diff --git a/docs/how-to/migrate-d2b-v1-0-to-v1-1.md b/docs/how-to/migrate-d2b-v1-0-to-v1-1.md index 5186dc18b..aad4a571d 100644 --- a/docs/how-to/migrate-d2b-v1-0-to-v1-1.md +++ b/docs/how-to/migrate-d2b-v1-0-to-v1-1.md @@ -228,7 +228,7 @@ instances: `virtiofsd[store]` is the share whose `tag` is `store`; output; JSON uses `{"virtiofsd_per_share": {"store": {...}}, "usbip_backend_per_env": {"default": {...}}}`. -| V2 field (current CLI output) | V3 field (wire-side, v1.1.1+) | Notes | +| V2 field (current CLI output) | V3 field (wire-side, v1.1.2+) | Notes | | -------------------------------- | ----------------------------- | ------------------------------------------------------------------ | | `d2b` | (deleted) | The legacy wrapper unit was removed in v1.0; V3 drops the field. | | `microvm` | `hypervisor` | Cloud Hypervisor runner is broker-spawned in v1.1. | diff --git a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md index 9160d97d4..217c25b3a 100644 --- a/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md +++ b/docs/plans/2026-09-24-002-refactor-rust-skills-remediation-plan.md @@ -115,7 +115,7 @@ Wave and gate sequence - one branch, one pull request: ```mermaid flowchart TB - W0[Wave 0: commit audit corpus; baseline snapshot; clear the red-at-head rows] --> G0{Gate} + W0[Wave 0: baseline snapshot; ledger; clear the red-at-head rows] --> G0{Gate} G0 -->|green or baseline-attributed| W1[Wave 1: docs + idiom + own leaf] W1 --> G1{Gate} G1 --> W2[Wave 2: type + api + err + serde + obs leaf] @@ -135,7 +135,9 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha ### Assumptions -- The audit corpus is committed with wave 0 so worktrees and reviewers can read the lanes (its directory is currently untracked). +- The audit corpus stays working material outside the shipped tree, as R8 + requires: wave 0 reads the lane files where the audit wrote them, and each + finding's outcome is carried by its changelog fragment and by the code. - `make check` at the untouched head is red on the audit's reported test; wave 0 confirms or refutes this, and the baseline record decides how later red gates are attributed. - Findings' anchors are valid at the audit's baseline commit; the tree has not changed since, but application still locates symbols rather than lines (R3). @@ -143,14 +145,16 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha ## Implementation Units -### U1. Wave 0 - baseline, corpus commit, and the red-at-head rows +### U1. Wave 0 - baseline, ledger, and the red-at-head rows -- **Goal:** the unit of record is tracked, the gate baseline is recorded, and the correctness-first rows are fixed (or, for the one policy-confirmed row, recorded) so the first wave gate reads as evidence. +- **Goal:** the ledger is started, the gate baseline is recorded, and the + correctness-first rows are fixed (or, for the one policy-confirmed row, + recorded) so the first wave gate reads as evidence. - **Requirements:** R2, R3, R5, R10; KTD4. - **Dependencies:** none. - **Files:** `changelog.d/`, and the finding sites - `packages/d2b-resource-runtime/src/revision.rs`, `packages/d2bd-runtime/src/runtime_process.rs`, `packages/d2b-broker/src/runtime.rs`, `packages/d2b-broker/src/kernel_ops.rs`, `packages/d2b-broker/src/sys.rs`, `packages/d2b-bus/src/` (telemetry test), `packages/d2b-provider-display-wayland/src/wayland_proxy/filter.rs`, `packages/d2b-provider-wayland-policy/src/` (applied), `packages/d2b-provider-user/src/` (record-only, no code change). - **Approach:** - 1. Commit the audit corpus and create the ledger with this row schema: finding id, lens, cluster, audit verdict, outcome, apply-time anchor, wave, commit, reason or policy citation, escalation history, and - for an escalated row - the final outcome recorded when the owning wave applies it (KTD1, R8). + 1. Create the ledger with this row schema: finding id, lens, cluster, audit verdict, outcome, apply-time anchor, wave, commit, reason or policy citation, escalation history, and - for an escalated row - the final outcome recorded when the owning wave applies it (KTD1, R8). 2. Record the baseline: run the KTD3 gate set at the untouched head and write the result - pass or fail per gate, with every pre-existing failure attributed. Any additional pre-existing failure inside the audit's crates is fixed here when it blocks the gate and otherwise recorded as baseline-attributed and deferred. 3. Dispose of the 13 `high` rows, re-verified per R3: apply the four test rows, the two wire-digest panic rows, the provider-wayland-policy caller-input panic at its driver-args boundary, and the four executor-blocking rows (each with the replacement the lint vocabulary names rather than a new allowance); record the provider-user blocking-NSS row as a policy-confirmed no-op citing its policy (R14, KTD8); escalate the remaining member sites of the shared driver-args class to U5, with the escalation recorded. Those groups account for all thirteen: the eight `leaf` rows (the four test rows, the daemon audit-join digest row, two of the four executor-blocking rows, and the provider-user row recorded as a no-op), both `family` rows (the driver-args class - one applied here, one escalated), and the three `wide` rows (the broker dispatch digest row inside the wire-digest pair, and the broker reap-poll and NSS-lookup rows inside the executor-blocking four). 4. Reconcile the ratchets these rows touch, then run the gate; the wave only closes with a red-to-green delta on the baseline record. @@ -164,7 +168,7 @@ Each gate is the KTD3 set. Ratchet reconciliation (KTD6) and ledger rows (R8) ha - The provider-wayland-policy driver constructor returns a typed refusal for a malformed zone token instead of panicking. - The ledger carries the provider-user NSS row as a policy-confirmed no-op citing the policy file, with no code change in that crate. - `make check-census` is no worse than the recorded baseline after the blocking fixes. -- **Verification:** the audit corpus is tracked; the baseline record states each gate's state at the frozen head; every U1 ledger row carries an outcome and an apply-time anchor; the wave gate set is green or the residual failures are attributed to the baseline with evidence. +- **Verification:** the ledger carries a row for every finding with an outcome and an apply-time anchor; the baseline record states each gate's state at the frozen head; the wave gate set is green or the residual failures are attributed to the baseline with evidence. ### U2. Wave 1 - documentation, idiom, and ownership leaf work

}) } + /// Stop the stale candidate when no live adopter is running. + /// + /// # Errors + /// + /// Returns `IdentityUnverified` when the candidate identity is zero; + /// otherwise thee effect port's pidfd-open or stop failure + /// propagates. async fn stop_stale( &self, candidate: &AdoptionCandidate, From e36441105bd0b59c6efa5c241fbfd0d21a6fae17 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:26:27 -0700 Subject: [PATCH 107/726] d2b-provider-role: deny missing docs and document the revision cache --- packages/d2b-provider-role/src/lib.rs | 6 ++++-- packages/d2b-provider-role/src/rbac.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-role/src/lib.rs b/packages/d2b-provider-role/src/lib.rs index 4f6ee98ef..71d0dd3f4 100644 --- a/packages/d2b-provider-role/src/lib.rs +++ b/packages/d2b-provider-role/src/lib.rs @@ -7,10 +7,12 @@ //! driver of `d2b_resource_runtime::metadata`, so this crate cannot diverge //! from its siblings on it. //! -//! `Role` is an authority role: the driver converges it as metadata once -//! its desired state is admitted, and the crate carries the revision-bound +//! `Role` is an authority role:ther driver converges it as metadata once +//! its desired state is admitted,and the crate carries the revision-bound //! positive authorization decision cache (`rbac`). +#![deny(missing_docs)] + mod driver; pub mod rbac; diff --git a/packages/d2b-provider-role/src/rbac.rs b/packages/d2b-provider-role/src/rbac.rs index dffbb5f92..fe45bafa3 100644 --- a/packages/d2b-provider-role/src/rbac.rs +++ b/packages/d2b-provider-role/src/rbac.rs @@ -13,9 +13,13 @@ use d2b_contracts_resource::v3::{ /// Policy revisions that make one positive decision valid. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct PolicyRevisionSet { + /// The policy catalog revision the decision was evaluated against. pub policy_revision: u64, + /// The API catalog revision the decision was evaluated against. pub api_catalog_revision: u64, + /// The active configuration revision the decision was evaluated against. pub active_configuration_revision: ConfigurationGeneration, + /// The zone policy revision the decision was evaluated against. pub zone_policy_revision: ZoneRevision, } @@ -28,6 +32,7 @@ pub struct AuthorizationCacheKey { } impl AuthorizationCacheKey { + /// Construct the exact subject-and-attribute evidence key. pub const fn new( subject_ref: ResourceRef, subject_uid: ResourceUid, @@ -82,6 +87,9 @@ impl core::fmt::Debug for PositiveDecisionCache { } impl PositiveDecisionCache { + /// Construct a bounded positive-only cache.max_entries = 0 + /// disables caching entirely. + pub fn new(max_entries: usize) -> Self { Self { max_entries, @@ -89,6 +97,8 @@ impl PositiveDecisionCache { } } + /// Whether a non-expired entry matching the exact evidence is present. + pub fn contains( &self, key: &AuthorizationCacheKey, @@ -102,6 +112,10 @@ impl PositiveDecisionCache { .is_some_and(|entry| entry.revisions == revisions) } + /// Insert one positive decision, evicting expired entries and refusing + /// insertions past the bound. An already-expired entry is never stored. + + pub fn insert_allow( &self, key: AuthorizationCacheKey, @@ -126,6 +140,7 @@ impl PositiveDecisionCache { ); } + /// Evict every cached decision. pub fn clear(&self) { self.lock_entries().clear(); } From 40237eea003af86d88aac2a747d5218bcc4c1844 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:06 -0700 Subject: [PATCH 108/726] resource-runtime: borrow committed resources and canonical deadline const --- packages/d2bd/src/resource_runtime.rs | 58 ++++++++++----------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/packages/d2bd/src/resource_runtime.rs b/packages/d2bd/src/resource_runtime.rs index ddec6cce6..7b7b6d886 100644 --- a/packages/d2bd/src/resource_runtime.rs +++ b/packages/d2bd/src/resource_runtime.rs @@ -35,7 +35,7 @@ use d2b_contracts_resource::v3::identity::{ AuthenticatedSubjectContext, EvidenceClass, ReconnectGeneration, }; use d2b_contracts_resource::v3::{ - CanonicalJsonValue, ControllerGeneration, DesiredLifecycle, + CanonicalJsonValue, ControllerGeneration, DEFAULT_REQUEST_DEADLINE_MS, DesiredLifecycle, PlacementTargetKind, ResourceBundleGenerationId, ResourceEnvelope, ResourceGeneration, ResourceErrorKind, ResourcePhase, ResourceRef, ResourceTypeName, ResourceUid, ZoneId, ZoneRevision, @@ -178,7 +178,7 @@ fn trusted_provider_resource_types() -> Result, ResourceRu .filter(|resource_type| resource_type.contains(".d2bus.org.")) { resource_types.insert( - ResourceTypeName::parse(resource_type.to_owned()) + ResourceTypeName::parse(resource_type) .map_err(|_| ResourceRuntimeError::HandlerNotReady)?, ); } @@ -356,9 +356,8 @@ async fn committed_controller_provider_identities( if !provider_refs.contains(&row.resource_ref) { continue; } - let expected_ref = row.resource_ref.clone(); - let (_, uid, generation, _, _) = committed_provider_spec(zone, &row, &expected_ref)?; - identities.insert(expected_ref, (uid, generation)); + let (_, uid, generation, _, _) = committed_provider_spec(zone, &row, &row.resource_ref)?; + identities.insert(row.resource_ref, (uid, generation)); } Ok(identities) } @@ -4552,11 +4551,10 @@ impl ZoneResourceRuntime { return Err(ResourceRuntimeError::InteractionConfigurationUnavailable); } let plane = self.manager_plane_view()?; - let resource = current_committed_resource( + let resource = committed_resource( plane.as_ref(), &self.zone, identity.wayland_session_ref(), - "interaction-wayland-session-current", ) .await?; let spec = committed_wayland_session_spec(&self.zone, &resource)?; @@ -4622,7 +4620,7 @@ impl ZoneResourceRuntime { &self, resource_type: &str, ) -> Result, ResourceRuntimeError> { - ResourceTypeName::parse(resource_type.to_owned()) + ResourceTypeName::parse(resource_type) .map_err(|_| ResourceRuntimeError::RequestInvalid)?; self.manager_stored_rows(resource_type) .await? @@ -6893,7 +6891,6 @@ impl ControllerSessionCoordinator { // registrar, and a dropped one leaves the internal session // unrenewable (its renewals refuse `AuthenticationUnavailable`). *self.registrar.lock().await = Some(registrar); - let setup = setup; match setup { Ok(( ingress, @@ -8291,7 +8288,10 @@ impl ZoneResourceRuntime { ResourceRef::parse(value).map_err(|_| ResourceRuntimeError::RequestInvalid) })?; let mut meta = public_request_meta(operation_id); - meta.deadline_ms = 30_000; + // The peer service applies `DEFAULT_REQUEST_DEADLINE_MS` when + // the deadline is absent; set it explicitly so this public + // get is bounded by the same canonical 30s cap. + meta.deadline_ms = DEFAULT_REQUEST_DEADLINE_MS; let response = client .get(wire::GetRequest { meta: protobuf::MessageField::some(meta), @@ -8387,7 +8387,7 @@ impl ZoneResourceRuntime { "Get" => { let target = public_target_ref(request)?; let mut meta = public_request_meta(operation_id); - meta.deadline_ms = 30_000; + meta.deadline_ms = DEFAULT_REQUEST_DEADLINE_MS; let response = client .get( ttrpc::context::Context::default(), @@ -9165,22 +9165,6 @@ async fn committed_resource( validate_committed_resource(zone, resource_ref, resource) } -async fn current_committed_resource( - plane: &dyn ControllerPlaneView, - zone: &ZoneId, - resource_ref: &ResourceRef, - _operation_id: &str, -) -> Result { - if !is_supported_committed_resource_ref(resource_ref) { - return Err(ResourceRuntimeError::InteractionConfigurationUnavailable); - } - let resource = bridge_manager_row(plane, resource_ref) - .await - .map_err(|_| ResourceRuntimeError::InteractionConfigurationUnavailable)? - .ok_or(ResourceRuntimeError::InteractionConfigurationUnavailable)?; - validate_committed_resource(zone, resource_ref, resource) -} - fn is_supported_committed_resource_ref(resource_ref: &ResourceRef) -> bool { matches!( resource_ref.resource_type().as_str(), @@ -9908,7 +9892,7 @@ fn manager_plane_seal_identity( .map_err(|_| ResourceRuntimeError::StoreSealUnavailable)?; let uid = match zone_uid { Some(uid) => uid, - None => ResourceUid::parse(MANAGER_PLANE_SEAL_UID.to_owned()) + None => ResourceUid::parse(MANAGER_PLANE_SEAL_UID) .map_err(|_| ResourceRuntimeError::StoreSealUnavailable)?, }; Ok(d2b_contracts_resource::v3::StoreSealIdentity::new( @@ -9928,7 +9912,7 @@ async fn public_create_request( .and_then(Value::as_str) .ok_or(ResourceRuntimeError::RequestInvalid) .and_then(|value| { - ResourceTypeName::parse(value.to_owned()) + ResourceTypeName::parse(value) .map_err(|_| ResourceRuntimeError::RequestInvalid) })?; let input = request @@ -10093,7 +10077,7 @@ fn public_update_finalizers_request( let uid = request .get("uid") .and_then(Value::as_str) - .map(|value| ResourceUid::parse(value.to_owned())) + .map(|value| ResourceUid::parse(value)) .transpose() .map_err(|_| ResourceRuntimeError::RequestInvalid)?; let expected_revision = @@ -10135,7 +10119,7 @@ fn public_delete_request_from_current( let mut uid = request .get("uid") .and_then(Value::as_str) - .map(|value| ResourceUid::parse(value.to_owned())) + .map(|value| ResourceUid::parse(value)) .transpose() .map_err(|_| ResourceRuntimeError::RequestInvalid)?; if uid.is_none() && expected_revision.is_some() { @@ -10209,7 +10193,7 @@ fn public_uid(resource: &Value) -> Result { .and_then(Value::as_str) .ok_or(ResourceRuntimeError::ResponseInvalid) .and_then(|value| { - ResourceUid::parse(value.to_owned()).map_err(|_| ResourceRuntimeError::ResponseInvalid) + ResourceUid::parse(value).map_err(|_| ResourceRuntimeError::ResponseInvalid) }) } @@ -10239,7 +10223,7 @@ where S: d2b_resource_api::ResourceStoreBackend, { let mut meta = public_request_meta(operation_id); - meta.deadline_ms = 30_000; + meta.deadline_ms = DEFAULT_REQUEST_DEADLINE_MS; let response = client .get(wire::GetRequest { meta: protobuf::MessageField::some(meta), @@ -10277,7 +10261,7 @@ async fn gateway_get_resource( operation_id: &str, ) -> Result { let mut meta = public_request_meta(operation_id); - meta.deadline_ms = 30_000; + meta.deadline_ms = DEFAULT_REQUEST_DEADLINE_MS; let response = client .get( ttrpc::context::Context::default(), @@ -11075,11 +11059,11 @@ fn parse_network_marker(marker: &str) -> Option<(NetworkAdmissionKey, String)> { let (network, rest) = rest.split_once(":generation:")?; let (generation, rest) = rest.split_once(":attachment:")?; let (attachment, bundle) = rest.split_once(":bundle:")?; - let zone_uid = ResourceUid::parse(zone.to_owned()).ok()?; - let network_uid = ResourceUid::parse(network.to_owned()).ok()?; + let zone_uid = ResourceUid::parse(zone).ok()?; + let network_uid = ResourceUid::parse(network).ok()?; let network_generation = ResourceGeneration::new(generation.parse().ok()?).ok()?; let attachment_generation = ResourceGeneration::new(attachment.parse().ok()?).ok()?; - let bundle_generation = ResourceBundleGenerationId::parse(bundle.to_owned()).ok()?; + let bundle_generation = ResourceBundleGenerationId::parse(bundle).ok()?; Some(( NetworkAdmissionKey::new( zone_uid, From 1fcaf44ee09f48757e71a82fae1cf9d7265385ba Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:06 -0700 Subject: [PATCH 109/726] composition: hoist activation generations dispatch, drop registry dir params, document serve paths --- packages/d2bd/src/composition.rs | 102 ++++++++++++++++++------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/packages/d2bd/src/composition.rs b/packages/d2bd/src/composition.rs index 0a4251a70..aa3e150ae 100644 --- a/packages/d2bd/src/composition.rs +++ b/packages/d2bd/src/composition.rs @@ -435,6 +435,15 @@ pub struct StaticProviderComposition { } impl StaticProviderComposition { + /// Compose the static Provider deployment and fixed effect adapter for one + /// daemon mode; the deployment's admission validation runs first, so + /// an over-budget or otherwise refused deployment surfaces before any + /// socket is bound. + /// + /// # Errors + /// + /// Returns `AdmissionError` when the provider deployment admission + /// (budget, limits,or mode constraints) validation fails. pub fn new( mode: d2bd_runtime::target_runtime::DaemonMode, broker_socket: PathBuf, @@ -3452,6 +3461,19 @@ fn admission_config(state: &ServerState) -> AdmissionConfig { } } +/// Load the daemon config, apply CLI overrides, bind the operator socket, +/// and run the accept loop until a shutdown signal lands. The daemon's +/// startup contracts (pidfs support, state-lock parent, operator socket +/// posture) are enforced before any socket is served. Operator tooling +/// uses `lock_only` to hold the state lock without starting the daemon. + +/// # Errors +/// +/// Returns [`TypedError`] for config-load and override failures, invalid +/// startup-contract state (pidfs, state lock, socket path), IO failures +/// (socket bind, helper socket, pidfd-table restore), and caller +/// authorization refusals during the accept loop. + pub async fn serve(options: ServeOptions) -> Result<(), TypedError> { let mut config = load_config(&options.config_path)?; apply_overrides(&mut config, &options); @@ -4825,6 +4847,14 @@ async fn finalize_daemon_interactions(state: &ServerState) -> Result<(), TypedEr }) } +/// Acquire the daemon's state lock and hold it for the requested duration, +/// then release it. Operator tooling uses this to serialize exclusive +/// state access without starting the daemon. +/// +/// # Errors +/// +/// Returns [`TypedError`] for config-load, state-lock-parent validation,and +/// lock-acquisition failures. pub async fn lock_only(options: LockOnlyOptions) -> Result<(), TypedError> { let mut config = load_config(&options.config_path)?; if let Some(path) = options.state_lock_path.clone() { @@ -14693,10 +14723,11 @@ async fn open_resource_plane( // plane - the resources are committed, the reader is just early. let mut controller_session_startup = Err(resource_runtime::ResourceRuntimeError::HandlerNotReady); - // 30 x 2s: with fast fixture IO the reader outruns the broker's - // publication by a wide margin, and 10 attempts (20s) exhausted - // before the rows landed. Give the publication a full minute. - for attempt in 0..30 { + // The committed rows are published above; with fast fixture IO the + // reader can outrun the broker's publication, so retry the + // documented 30 x 2s window (PROVIDER_IDENTITY_SEED_*) instead of + // failing the plane. + for attempt in 0..PROVIDER_IDENTITY_SEED_ATTEMPTS { controller_session_startup = runtime .reconcile_controller_sessions(Arc::new(state.clone())) .await; @@ -14707,7 +14738,7 @@ async fn open_resource_plane( attempt, "controller session startup raced publication; retrying", ); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; + tokio::time::sleep(PROVIDER_IDENTITY_SEED_INTERVAL).await; } _ => break, } @@ -20401,7 +20432,7 @@ fn dispatch_live_guest_activation_resource( Ok(guard) => guard, Err(frame) => return Ok(frame), }; - let zone = guard.zone().clone(); + let zone = guard.zone(); let plane = state .resource_plane .try_lock() @@ -20436,24 +20467,24 @@ fn dispatch_live_guest_activation_resource( detail: "activation Guest resource unavailable".to_owned(), }); } - let (ordinal, artifact) = if mode == DaemonActivationMode::Rollback { + let list = json!({ + "zoneRef": format!("Zone/{}", zone.as_str()), + "service": "d2b.resource.v3", + "method": "List", + "resourceType": NIXOS_GENERATION_RESOURCE_TYPE, + "executionRef": guest_ref.to_canonical_string(), + "limit": 256, + }); + let resources = drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&list, peer_uid)) + .map_err(|_| TypedError::InternalConfig { + detail: "activation generations unavailable".to_owned(), + })?; + let (ordinal, artifact) = if mode == DaemonActivationMode::Rollback{ let target_ordinal = request .to_generation .ok_or_else(|| TypedError::InternalConfig { detail: "rollback target generation unavailable".to_owned(), })?; - let list = json!({ - "zoneRef": format!("Zone/{}", zone.as_str()), - "service": "d2b.resource.v3", - "method": "List", - "resourceType": NIXOS_GENERATION_RESOURCE_TYPE, - "executionRef": guest_ref.to_canonical_string(), - "limit": 256, - }); - let resources = drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&list, peer_uid)) - .map_err(|_| TypedError::InternalConfig { - detail: "rollback generations unavailable".to_owned(), - })?; let artifact = resources .get("resources") .and_then(Value::as_array) @@ -20486,18 +20517,7 @@ fn dispatch_live_guest_activation_resource( // its retained NixosGeneration resources (the same List used by the // rollback branch). The next activation is one past the max // committed ordinal; `1` when the Guest has no committed generation. - let list = json!({ - "zoneRef": format!("Zone/{}", zone.as_str()), - "service": "d2b.resource.v3", - "method": "List", - "resourceType": NIXOS_GENERATION_RESOURCE_TYPE, - "executionRef": guest_ref.to_canonical_string(), - "limit": 256, - }); - let resources = drive_sync(&state.runtime_handle, runtime.dispatch_public_cli_request(&list, peer_uid)) - .map_err(|_| TypedError::InternalConfig { - detail: "activation generations unavailable".to_owned(), - })?; + let ordinal = resources .get("resources") .and_then(Value::as_array) @@ -20635,7 +20655,7 @@ fn activation_generation_name(vm: &str, ordinal: u64, mode: DaemonActivationMode DaemonActivationMode::Rollback => "rollback", }; let readable = format!("{vm}--{suffix}-{ordinal}"); - if ResourceName::parse(readable.clone()).is_ok() { + if ResourceName::parse(&readable).is_ok() { return readable; } let mut digest = Sha256::new(); @@ -21088,7 +21108,7 @@ fn typed_error_from_resolution_error( workload_id, candidates, } => TypedError::WorkloadAliasConflict { - workload_id: workload_id.clone(), + workload_id, detail: format!("matches workloads [{}]", candidates.join(", ")), }, } @@ -21257,7 +21277,7 @@ fn public_qemu_media_status( .sources .iter() .filter(|source| source.vm == vm) - .map(|source| qemu_media_source_status(contract.registry_dir.as_str(), source)) + .map(|source| qemu_media_source_status(source)) .collect::>() }) .unwrap_or_default(); @@ -21287,8 +21307,8 @@ fn public_qemu_media_status( })) } -fn qemu_media_source_status(registry_dir: &str, source: &QemuMediaSourceIntent) -> Value { - let (state, remediation) = qemu_media_registry_state(registry_dir, source); +fn qemu_media_source_status(source: &QemuMediaSourceIntent) -> Value { + let (state, remediation) = qemu_media_registry_state(source); let status = json!({ "mediaRef": source.media_ref, "slot": source.slot, @@ -21303,10 +21323,7 @@ fn qemu_media_source_status(registry_dir: &str, source: &QemuMediaSourceIntent) status } -fn qemu_media_registry_state( - _registry_dir: &str, - source: &QemuMediaSourceIntent, -) -> (String, Option) { +fn qemu_media_registry_state(source: &QemuMediaSourceIntent) -> (String, Option) { if serde_kebab_string(&source.source_kind) != "physical-usb" { return ("direct-config".to_owned(), None); } @@ -22060,7 +22077,6 @@ mod public_status_tests { #[test] fn qemu_media_status_reports_manual_runtime_and_missing_registry() { - let root = tempfile::tempdir().expect("registry root"); let (state, _dir) = test_state(); let manifest_entry = qemu_media_manifest_entry(); let dag = qemu_media_process_dag(); @@ -22093,7 +22109,7 @@ mod public_status_tests { None ); let source_status = - qemu_media_source_status(&root.path().display().to_string(), &qemu_media_source()); + qemu_media_source_status(&qemu_media_source()); assert_eq!( source_status.pointer("/slot").and_then(Value::as_str), Some("boot") @@ -22121,7 +22137,7 @@ mod public_status_tests { #[test] fn qemu_media_status_reports_direct_image_without_enrollment_remediation() { let source_status = - qemu_media_source_status("/var/lib/d2b/media-registry", &qemu_media_image_source()); + qemu_media_source_status(&qemu_media_image_source()); assert_eq!( source_status.pointer("/sourceKind").and_then(Value::as_str), From 3220fd1ce414a81244683f0c3e4e6d56aafe0d1c Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:06 -0700 Subject: [PATCH 110/726] forward-rendezvous: borrow request zone id and drop dead bindings --- packages/d2bd/src/forward_rendezvous.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/d2bd/src/forward_rendezvous.rs b/packages/d2bd/src/forward_rendezvous.rs index fb96f245a..e2d202502 100644 --- a/packages/d2bd/src/forward_rendezvous.rs +++ b/packages/d2bd/src/forward_rendezvous.rs @@ -453,10 +453,9 @@ impl ForwardRendezvous { fds: &[RawFd], chain: &EvidenceChain, ) -> (ForwardOperationResponse, Vec) { - let zone = request.zone.clone(); let (providers, kernel, resources) = { let zones = self.zones.lock().await; - match zones.get(&zone) { + match zones.get(&request.zone) { Some(binding) => ( Some(Arc::clone(&binding.providers)), binding.kernel.clone(), @@ -645,7 +644,7 @@ impl ForwardRendezvous { // root leg. let chain = match &request.chain_identities { Some(identities) => { - let mut chain = match identities.split_first() { + let chain = match identities.split_first() { Some((head, tail)) => { let mut chain = EvidenceChain::root( request.invocation_id.clone(), @@ -665,11 +664,11 @@ impl ForwardRendezvous { .unwrap_or_else(|| "daemon".to_owned()), ), }; - // The handler-side legs append the invoking handler's own - // identity; the daemon-side record of a forwarded nested leg +// The handler-side legs append the invoking handler's own + // identity;the daemon-side record of a forwarded nested leg // keys on the root id and the chain's depth exactly as the // broker-side record of the in-broker leg does. - let _ = &mut chain; + chain } None => EvidenceChain::root( @@ -1043,7 +1042,7 @@ impl ScmFds { Self(fds) } - /// The received descriptors,borrowed across the invocation.. + /// The received descriptors, borrowed across the invocation. fn as_slice(&self) -> &[RawFd] { &self.0 } @@ -1057,8 +1056,8 @@ impl Drop for ScmFds { } /// Whether one request's declared fd leg is admitted by the descriptors the -/// frame actually attached:count equal (never truncated), indexes in frame -/// order, kinds against the kernel stat of each received descriptor,and the +/// frame actually attached: count equal (never truncated), indexes in frame +/// order, kinds against the kernel stat of each received descriptor,andthe /// whole leg within the carrier's frame ceiling. fn request_fds_admitted(request: &ForwardOperationRequest, fds: &[RawFd]) -> bool { if request.fd_indexes.len() != request.fd_kinds.len() { @@ -1087,8 +1086,8 @@ fn request_fds_admitted(request: &ForwardOperationRequest, fds: &[RawFd]) -> boo }) } -/// The kernel kind one descriptor presents,or None when its fstat reports -/// a kind the carrier vocabulary does not carry.. +/// The kernel kind one descriptor presents, or None when its fstat reports +/// a kind the carrier vocabulary does not carry. fn fd_kind_of(fd: RawFd) -> Option { let stat = nix::sys::stat::fstat(fd).ok()?; match stat.st_mode & nix::libc::S_IFMT { @@ -1428,7 +1427,7 @@ impl AsyncSeqpacket { .await } - /// One datagram write with its attachments,awaited for readiness.. + /// One datagram write with its attachments, awaited for readiness. async fn send_datagram_with_fds(&self, frame: &[u8], fds: &[RawFd]) -> io::Result<()> { self.io .async_io(Interest::WRITABLE, |socket| { From 9441488c0a0a238a2d12124523850f59a0e49989 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:07 -0700 Subject: [PATCH 111/726] interaction-composition: drop redundant supervisor clone in effect launch --- packages/d2bd/src/interaction_composition.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/d2bd/src/interaction_composition.rs b/packages/d2bd/src/interaction_composition.rs index b9e5468a9..25fc5f38c 100644 --- a/packages/d2bd/src/interaction_composition.rs +++ b/packages/d2bd/src/interaction_composition.rs @@ -4338,25 +4338,23 @@ where let supervisor = self._supervisor.clone(); let adoption_ticket = process_ticket.clone(); let adopted = run_effect(move || { - let supervisor = supervisor.clone(); - let process_ticket = adoption_ticket.clone(); async move { if let Some(candidate) = supervisor - .observe(&process_ticket) + .observe(&adoption_ticket) .await .map_err(|_| WorkerEffectError::WorkerUnavailable)? { match supervisor.open_pidfd(&candidate).await { Ok(_) => Ok(candidate.identity), Err(_) => Ok(supervisor - .launch(&process_ticket) + .launch(&adoption_ticket) .await .map_err(|_| WorkerEffectError::LaunchRejected)? .identity), } } else { Ok(supervisor - .launch(&process_ticket) + .launch(&adoption_ticket) .await .map_err(|_| WorkerEffectError::LaunchRejected)? .identity) From 274cfb3c5b989f6612637d54e62e94c76197e243 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:07 -0700 Subject: [PATCH 112/726] process-provider-runtime: match owner uid by reference --- packages/d2bd/src/process_provider_runtime.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2bd/src/process_provider_runtime.rs b/packages/d2bd/src/process_provider_runtime.rs index 3903c1fd0..016b77b25 100644 --- a/packages/d2bd/src/process_provider_runtime.rs +++ b/packages/d2bd/src/process_provider_runtime.rs @@ -4054,9 +4054,9 @@ fn resource_ticket( let ticket = ticket .with_runtime_identity(zone_uid, launch.owner_ref().cloned(), runtime_scope) .map_err(|error| format!("provider-ticket:{}", error.code()))?; - let ticket = match context.owner_uid.clone() { + let ticket = match context.owner_uid.as_ref() { Some(owner_uid) if ticket.owner_uid().is_none() => ticket - .with_owner_uid(owner_uid) + .with_owner_uid(owner_uid.clone()) .map_err(|error| format!("provider-ticket:{}", error.code()))?, _ => ticket, }; From 457373d5b21a9144604f51443dc858910c227e7a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:08 -0700 Subject: [PATCH 113/726] shared-provider-effects: validate network volume spec in place --- packages/d2bd/src/shared_provider_effects.rs | 39 ++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/d2bd/src/shared_provider_effects.rs b/packages/d2bd/src/shared_provider_effects.rs index 5054bd23a..ec0353e74 100644 --- a/packages/d2bd/src/shared_provider_effects.rs +++ b/packages/d2bd/src/shared_provider_effects.rs @@ -47,6 +47,7 @@ use d2b_resource_runtime::identity::{ResourceKey, ResourceTypeName}; use d2b_resource_runtime::manager::ResourceView; use d2b_resource_runtime::ResourceStatus; use d2b_contracts_resource::v3::{ResourceAssignmentFence, ResourceAssignmentScope}; +use serde::Deserialize; use serde_json::{Value, json}; use sha2::{Digest, Sha256}; @@ -662,7 +663,7 @@ fn network_config_projection_present(value: &Value, volume_uid: &ResourceUid) -> let Some(spec) = value.get("spec") else { return false; }; - if validate_network_config_volume_spec(spec).is_err() { + if validate_network_config_volume_spec(&mut spec.clone()).is_err() { return false; } provider.get("schemaId").and_then(Value::as_str) == Some(NETWORK_CONFIG_VOLUME_SCHEMA_ID) @@ -679,7 +680,7 @@ fn network_config_projection_present(value: &Value, volume_uid: &ResourceUid) -> .is_some_and(|content| content.volume_uid() == volume_uid) } -fn validate_network_config_volume_spec(spec: &Value) -> Result<(), NetworkEffectError> { +fn validate_network_config_volume_spec(spec: &mut Value) -> Result<(), NetworkEffectError> { let provider_ref = spec .get("providerRef") .and_then(Value::as_str) @@ -687,14 +688,17 @@ fn validate_network_config_volume_spec(spec: &Value) -> Result<(), NetworkEffect if provider_ref != "Provider/volume-local" { return Err(NetworkEffectError::NetworkAdmissionMismatch); } - let mut base = spec.clone(); - if let Some(base) = base.as_object_mut() { - base.remove("providerRef"); - base.remove("updatePolicy"); - base.remove("provider"); + // Strip the wire-only fields in place (the `VolumeSpec` wire shape + // denies unknown fields), parse the rest directly from the borrow, and + // restore them so the caller's document is unchanged by validation. + let mut removed = [None, None, None]; + if let Some(base) = spec.as_object_mut() { + removed[0] = base.remove("providerRef"); + removed[1] = base.remove("updatePolicy"); + removed[2] = base.remove("provider"); } let volume: VolumeSpec = - serde_json::from_value(base).map_err(|_| NetworkEffectError::ConfigVolume)?; + VolumeSpec::deserialize(&*spec).map_err(|_| NetworkEffectError::ConfigVolume)?; let required = [ d2b_provider_network_local::controller::NETWORK_CONFIG_FILE_DNSMASQ, d2b_provider_network_local::controller::NETWORK_CONFIG_FILE_NFTABLES, @@ -712,6 +716,17 @@ fn validate_network_config_volume_spec(spec: &Value) -> Result<(), NetworkEffect }) { return Err(NetworkEffectError::ConfigVolume); } + if let Some(base) = spec.as_object_mut() { + if let Some(value) = std::mem::take(&mut removed[0]) { + base.insert("providerRef".to_owned(), value); + } + if let Some(value) = std::mem::take(&mut removed[1]) { + base.insert("updatePolicy".to_owned(), value); + } + if let Some(value) = std::mem::take(&mut removed[2]) { + base.insert("provider".to_owned(), value); + } + } Ok(()) } @@ -779,7 +794,10 @@ fn network_config_spec_with_content( fence: &NetworkContentFence, owner_ref: &ResourceRef, ) -> Result { - validate_network_config_volume_spec(&spec)?; + // The caller validates the document before handing it over; the only flow + // into this helper validates the document, unchanged, immediately + // before the call, so re-validating here would double the parse per + // reconcile. let marker = d2b_contracts_resource::v3::derive_network_ownership_marker( &fence.provenance, "network-config", @@ -886,7 +904,7 @@ impl NetworkResourcePort for NetworkChildPort<'_> { .get("spec") .cloned() .ok_or(NetworkEffectError::ConfigVolume)?; - validate_network_config_volume_spec(&spec)?; + validate_network_config_volume_spec(&mut spec)?; let volume_uid = current .pointer("/uid") .and_then(Value::as_str) @@ -1153,7 +1171,6 @@ impl ProductionSharedProviderEffects { admission.key().attachment_generation(), admission.key().bundle_generation().clone(), ); - let _ = kind; Ok(NetworkContentFence { provenance, assignment, From 955abf0093c6adcffa0e48accb0e3813c5a999d3 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:08 -0700 Subject: [PATCH 114/726] provider-registry: drop dead error binding and unit-ify unused Refused payload --- packages/d2bd/src/provider_registry.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/d2bd/src/provider_registry.rs b/packages/d2bd/src/provider_registry.rs index 28b9161f0..a64e35f0b 100644 --- a/packages/d2bd/src/provider_registry.rs +++ b/packages/d2bd/src/provider_registry.rs @@ -411,7 +411,7 @@ enum ProviderRuntimeState { Active(ActiveProviderRuntime), /// The catalog is absent or failed validation; all lifecycle effects /// refuse until the daemon is rebuilt with a valid catalog. - Refused(ProviderCompositionError), + Refused, } /// Daemon-owned Provider composition and lifecycle routing state. @@ -425,9 +425,7 @@ impl ProviderRuntime { /// Start unavailable until a trusted Provider catalog is supplied. pub fn new() -> Self { Self { - state: tokio::sync::RwLock::new(ProviderRuntimeState::Refused( - ProviderCompositionError::ProviderNotRegistered, - )), + state: tokio::sync::RwLock::new(ProviderRuntimeState::Refused), process_providers: tokio::sync::RwLock::new(None), } } @@ -505,7 +503,7 @@ impl ProviderRuntime { ProviderRuntimeState::Active(active) => { Some(active.registry.current().snapshot().descriptors().len()) } - ProviderRuntimeState::Refused(_) => None, + ProviderRuntimeState::Refused => None, }) .unwrap_or(0) } @@ -527,10 +525,7 @@ impl ProviderRuntime { .map_err(|_| ProviderEffectError::StateUnavailable)?; let ProviderRuntimeState::Active(active) = &*state else { return match &*state { - ProviderRuntimeState::Refused(error) => { - let _ = error.code(); - Err(ProviderEffectError::RegistryUnavailable) - } + ProviderRuntimeState::Refused => Err(ProviderEffectError::RegistryUnavailable), ProviderRuntimeState::Active(_) => unreachable!("active state matched above"), }; }; From 970d1dcd54cbf8ef3932e054210ea4ff3bb0669b Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:08 -0700 Subject: [PATCH 115/726] provider-lifecycle: match registered service declarations over id guards --- packages/d2bd/src/provider_lifecycle.rs | 49 +++++++++---------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/packages/d2bd/src/provider_lifecycle.rs b/packages/d2bd/src/provider_lifecycle.rs index 5e9bd62d0..564af0e47 100644 --- a/packages/d2bd/src/provider_lifecycle.rs +++ b/packages/d2bd/src/provider_lifecycle.rs @@ -76,38 +76,23 @@ use crate::plane_port::{PlaneRefusal, ProductionPlanePort}; /// service through the U15 pass. The families with no registration row /// declare their services only through their drivers and never appear here. fn registered_service_decl(service: &str) -> Option<&'static ServiceDecl> { - if service == PROCESS_EFFECTS_SERVICE.id { - Some(&PROCESS_EFFECTS_SERVICE) - } else if service == NETWORK_EFFECTS_SERVICE.id { - Some(&NETWORK_EFFECTS_SERVICE) - } else if service == HOST_EFFECTS_SERVICE.id { - Some(&HOST_EFFECTS_SERVICE) - } else if service == PROCESS_SYSTEMD_EFFECTS_SERVICE.id { - Some(&PROCESS_SYSTEMD_EFFECTS_SERVICE) - } else if service == ACTIVATION_EFFECTS_SERVICE.id { - Some(&ACTIVATION_EFFECTS_SERVICE) - } else if service == CREDENTIAL_EFFECTS_SERVICE.id { - Some(&CREDENTIAL_EFFECTS_SERVICE) - } else if service == DEVICE_EFFECTS_SERVICE.id { - Some(&DEVICE_EFFECTS_SERVICE) - } else if service == SECURITY_KEY_EFFECTS_SERVICE.id { - Some(&SECURITY_KEY_EFFECTS_SERVICE) - } else if service == USBIP_EFFECTS_SERVICE.id { - Some(&USBIP_EFFECTS_SERVICE) - } else if service == ENDPOINT_EFFECTS_SERVICE.id { - Some(&ENDPOINT_EFFECTS_SERVICE) - } else if service == GUEST_EFFECTS_SERVICE.id { - Some(&GUEST_EFFECTS_SERVICE) - } else if service == USER_EFFECTS_SERVICE.id { - Some(&USER_EFFECTS_SERVICE) - } else if service == VOLUME_EFFECTS_SERVICE.id { - Some(&VOLUME_EFFECTS_SERVICE) - } else if service == BINDING_EFFECTS_SERVICE.id { - Some(&BINDING_EFFECTS_SERVICE) - } else if service == INTERACTION_EFFECTS_SERVICE.id { - Some(&INTERACTION_EFFECTS_SERVICE) - } else { - None + match service { + x if x ==PROCESS_EFFECTS_SERVICE.id => Some(&PROCESS_EFFECTS_SERVICE), + x if x ==NETWORK_EFFECTS_SERVICE.id => Some(&NETWORK_EFFECTS_SERVICE), + x if x ==HOST_EFFECTS_SERVICE.id => Some(&HOST_EFFECTS_SERVICE), + x if x ==PROCESS_SYSTEMD_EFFECTS_SERVICE.id => Some(&PROCESS_SYSTEMD_EFFECTS_SERVICE), + x if x ==ACTIVATION_EFFECTS_SERVICE.id => Some(&ACTIVATION_EFFECTS_SERVICE), + x if x ==CREDENTIAL_EFFECTS_SERVICE.id => Some(&CREDENTIAL_EFFECTS_SERVICE), + x if x ==DEVICE_EFFECTS_SERVICE.id => Some(&DEVICE_EFFECTS_SERVICE), + x if x ==SECURITY_KEY_EFFECTS_SERVICE.id => Some(&SECURITY_KEY_EFFECTS_SERVICE), + x if x ==USBIP_EFFECTS_SERVICE.id => Some(&USBIP_EFFECTS_SERVICE), + x if x ==ENDPOINT_EFFECTS_SERVICE.id => Some(&ENDPOINT_EFFECTS_SERVICE), + x if x ==GUEST_EFFECTS_SERVICE.id => Some(&GUEST_EFFECTS_SERVICE), + x if x ==USER_EFFECTS_SERVICE.id => Some(&USER_EFFECTS_SERVICE), + x if x ==VOLUME_EFFECTS_SERVICE.id => Some(&VOLUME_EFFECTS_SERVICE), + x if x ==BINDING_EFFECTS_SERVICE.id => Some(&BINDING_EFFECTS_SERVICE), + x if x ==INTERACTION_EFFECTS_SERVICE.id => Some(&INTERACTION_EFFECTS_SERVICE), + _ => None, } } From 14efca7ef8a8285d2bf840072a13ac9f1b9fc61a Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:09 -0700 Subject: [PATCH 116/726] resource-plane-v3: match service factories over id guardsand document registry types --- packages/d2bd/src/resource_plane_v3.rs | 90 +++++++++++--------------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/packages/d2bd/src/resource_plane_v3.rs b/packages/d2bd/src/resource_plane_v3.rs index 85a6d1fce..83949338c 100644 --- a/packages/d2bd/src/resource_plane_v3.rs +++ b/packages/d2bd/src/resource_plane_v3.rs @@ -289,6 +289,7 @@ struct RegistryInner { } impl PlaneResourceRegistry { + /// Construct an empty registry (equivalent to `Default`). pub fn new() -> Self { Self::default() } @@ -1767,6 +1768,8 @@ pub struct ZoneAuthorityInputs { pub policy_revision: Option, /// Provider assignment generation for guest execution sessions. pub provider_assignment_generation: Option, + /// The controller generation for the zone authority's process rows + /// (KTD7: from the bundle resolver, never the spec store). pub controller_generation: ControllerGeneration, pub guest_execution: Option, pub mode: DaemonMode, @@ -2242,60 +2245,39 @@ fn registered_service_factories( let mut factories = BTreeMap::new(); for registration in PROVIDER_REGISTRATIONS { for &service in registration.services { - let factory = if service == PROCESS_EFFECTS_SERVICE.id { - Arc::new(ProcessEffectsServiceFactory::new(process_facets.clone())) - as Arc - } else if service == NETWORK_EFFECTS_SERVICE.id { - Arc::new(NetworkEffectsServiceFactory::new(network_facets.clone())) - as Arc -} else if service == HOST_EFFECTS_SERVICE.id { - Arc::new(HostEffectsServiceFactory::new(host_facets.clone())) -as Arc - } else if service == ACTIVATION_EFFECTS_SERVICE.id { - Arc::new(ActivationEffectsServiceFactory::new(activation_facets.clone())) - } else if service == USER_EFFECTS_SERVICE.id { - Arc::new(UserEffectsServiceFactory::new(user_facets.clone())) - } else if service == USBIP_EFFECTS_SERVICE.id { - Arc::new(d2b_provider_device_usbip::effects_service:: - UsbipEffectsServiceFactory::new(usbip_facets.clone())) - as Arc - } else if service == SECURITY_KEY_EFFECTS_SERVICE.id { - Arc::new(d2b_provider_device_security_key::effects_service:: - SecurityKeyEffectsServiceFactory::new(security_key_facets.clone())) - as Arc - } else if service == DEVICE_EFFECTS_SERVICE.id { - Arc::new(d2b_provider_device::effects_service:: - DeviceEffectsServiceFactory::new(device_facets.clone())) - as Arc - } else if service == CREDENTIAL_EFFECTS_SERVICE.id { - Arc::new(CredentialEffectsServiceFactory::new(credential_facets.clone())) - as Arc - } else if service == VOLUME_EFFECTS_SERVICE.id { - Arc::new(VolumeEffectsServiceFactory::new(volume_facets.clone())) - as Arc - } else if service == d2b_provider_wayland_policy::INTERACTION_EFFECTS_SERVICE.id { - Arc::new( + let Some(factory) = (match service { + x if x == PROCESS_EFFECTS_SERVICE.id => Some(Arc::new(ProcessEffectsServiceFactory::new(process_facets.clone())) as Arc), + x if x == NETWORK_EFFECTS_SERVICE.id => Some(Arc::new(NetworkEffectsServiceFactory::new(network_facets.clone())) as Arc), + x if x == HOST_EFFECTS_SERVICE.id => Some(Arc::new(HostEffectsServiceFactory::new(host_facets.clone())) as Arc), + x if x == ACTIVATION_EFFECTS_SERVICE.id => Some(Arc::new(ActivationEffectsServiceFactory::new(activation_facets.clone())) as Arc), + x if x == USER_EFFECTS_SERVICE.id => Some(Arc::new(UserEffectsServiceFactory::new(user_facets.clone())) as Arc), + x if x == USBIP_EFFECTS_SERVICE.id => Some(Arc::new(d2b_provider_device_usbip::effects_service:: + UsbipEffectsServiceFactory::new(usbip_facets.clone())) as Arc), + x if x == SECURITY_KEY_EFFECTS_SERVICE.id => Some(Arc::new(d2b_provider_device_security_key::effects_service:: + SecurityKeyEffectsServiceFactory::new(security_key_facets.clone())) as Arc), + x if x == DEVICE_EFFECTS_SERVICE.id => Some(Arc::new(d2b_provider_device::effects_service:: + DeviceEffectsServiceFactory::new(device_facets.clone())) as Arc), + x if x == CREDENTIAL_EFFECTS_SERVICE.id => Some(Arc::new(CredentialEffectsServiceFactory::new(credential_facets.clone())) as Arc), + x if x == VOLUME_EFFECTS_SERVICE.id => Some(Arc::new(VolumeEffectsServiceFactory::new(volume_facets.clone())) as Arc), + x if x == d2b_provider_wayland_policy::INTERACTION_EFFECTS_SERVICE.id => Some(Arc::new( d2b_provider_wayland_policy::InteractionEffectsServiceFactory::new( interaction_facets.clone(), ), - ) as Arc - } else if service == PROCESS_SYSTEMD_EFFECTS_SERVICE.id { - // U15:the family's service carries no facet set (R2), so - // the composition root hosts its factory from crate-owned - // constants alone, over the registered service identity - the - // family itself is never named here. - - Arc::new(SystemdEffectsServiceFactory::new()) as Arc - } else if service == GUEST_EFFECTS_SERVICE.id { - Arc::new(GuestEffectsServiceFactory::new(guest_facets.clone())) - as Arc - } else if service == BINDING_EFFECTS_SERVICE.id { - Arc::new(BindingEffectsServiceFactory::new(binding_facets.clone())) - as Arc - } else if service == ENDPOINT_EFFECTS_SERVICE.id { - Arc::new(EndpointEffectsServiceFactory::new(endpoint_facets.clone())) - as Arc - } else { + ) as Arc), + x if x == PROCESS_SYSTEMD_EFFECTS_SERVICE.id => { + // U15:the family's service carries no facet set (R2), so + // the composition root hosts its factory from crate-owned + // constants alone, over the registered service identity - the + // family itself is never named here. + + + Some(Arc::new(SystemdEffectsServiceFactory::new()) as Arc) + }, + x if x == GUEST_EFFECTS_SERVICE.id => Some(Arc::new(GuestEffectsServiceFactory::new(guest_facets.clone())) as Arc), + x if x == BINDING_EFFECTS_SERVICE.id => Some(Arc::new(BindingEffectsServiceFactory::new(binding_facets.clone())) as Arc), + x if x == ENDPOINT_EFFECTS_SERVICE.id => Some(Arc::new(EndpointEffectsServiceFactory::new(endpoint_facets.clone())) as Arc), + _ => None, + }) else { continue; }; factories.insert(service, factory); @@ -3430,8 +3412,14 @@ fn bundle_desired(zone: &ZoneId, row: &BundleResource) -> DesiredResource { /// What one bundle ingestion did (U10 report). #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct BundleIngestReport { + /// The rows this ingestion applied. + pub applied: Vec, + /// The rows this ingestion removed. + pub removed: Vec, + /// The rows this ingestion protected from management-plane mutation. + pub api_protected: Vec, } From 6389b6473c5493885b54db9117cd882f8c096b03 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:09 -0700 Subject: [PATCH 117/726] effect-service-actors: derive Default serversand document call error surface --- packages/d2bd/src/effect_service_actors.rs | 34 +++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/d2bd/src/effect_service_actors.rs b/packages/d2bd/src/effect_service_actors.rs index 28cee6cd4..3652d9961 100644 --- a/packages/d2bd/src/effect_service_actors.rs +++ b/packages/d2bd/src/effect_service_actors.rs @@ -198,14 +198,30 @@ impl EffectServiceBinding { /// Call through the binding at its current revision; a mid-flight death /// of the actor surfaces as [`EffectServiceError::InFlightStale`] - the /// caller sees a refusal, never a hang. - pub async fn call(&self, call: ServiceCallData) -> Result { + /// + /// # Errors + /// + /// Returns [`EffectServiceError::UnboundService`] when no service is + /// published, [`EffectServiceError::WrongZone`] when the row belongs to + /// a different zone, [`EffectServiceError::ServiceUnavailable`] when + /// the actor refuses the call, [`EffectServiceError::InFlightStale`] + /// when the actor died mid-flight,and [`EffectServiceError::Declined`] + /// when the service declines the operation. + pub async fn call(&self, call: ServiceCallData) -> Result { self.send(call).await } /// Call guarded by a captured revision (KTD5): if a respawn or republish /// bumped the revision since the caller captured `expected`, refuse /// before dispatch. The rendezvous uses this admission check. - pub async fn call_expected( + /// + /// # Errors + /// + /// Returns [`EffectServiceError::StaleRevision`] when the binding's + /// revision moved sincethe caller captured `expected`, and the same + /// refusals as [`EffectServiceBinding::call`]: UnboundService, + /// WrongZone, ServiceUnavailable, InFlightStale,and Declined. + pub async fn call_expected( &self, expected: u64, call: ServiceCallData, @@ -257,6 +273,7 @@ pub(crate) struct EffectServiceActorState { /// inline - the fixture shape; production services forward long effects onto /// an unbounded channel pump like `ResourceActor` (KTD12) so the mailbox /// never blocks. +#[derive(Default)] pub(crate) struct EffectServiceActor; impl EffectServiceActor { @@ -265,12 +282,6 @@ impl EffectServiceActor { } } -impl Default for EffectServiceActor { - fn default() -> Self { - Self::new() - } -} - impl Actor for EffectServiceActor { type Msg = EffectServiceMsg; type State = EffectServiceActorState; @@ -400,6 +411,7 @@ pub(crate) struct EffectServiceSupervisorState { /// Per-zone supervisor for effect services (U8, KTD5): service actors are /// linked children, respawned from their durable rows on failure. +#[derive(Default)] pub(crate) struct EffectServiceSupervisor; impl EffectServiceSupervisor { @@ -408,12 +420,6 @@ impl EffectServiceSupervisor { } } -impl Default for EffectServiceSupervisor { - fn default() -> Self { - Self::new() - } -} - impl EffectServiceSupervisorState { fn resolve(&self, service: &str) -> Result { self.bindings.get(service).cloned().ok_or_else(|| EffectServiceError::UnboundService { From 4ce0faaf8a6db60abba018bb21926328a5946fec Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:09 -0700 Subject: [PATCH 118/726] provider-effects: document fixed adapter and lifecycle dispatch error surface --- packages/d2bd/src/provider_effects.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/d2bd/src/provider_effects.rs b/packages/d2bd/src/provider_effects.rs index 8f8e4ba51..ae970715e 100644 --- a/packages/d2bd/src/provider_effects.rs +++ b/packages/d2bd/src/provider_effects.rs @@ -88,6 +88,12 @@ impl FixedEffectAdapter { } /// Validate the fixed socket instance before any ticket is delivered. + /// + /// # Errors + /// + /// Returns [`FixedEffectError::Broker`] when the broker socket instance + /// fails validation. + pub fn validate_instance(&self) -> Result<(), FixedEffectError> { self.broker .validate_instance() @@ -107,7 +113,14 @@ impl FixedEffectAdapter { } } - pub fn dispatch( + /// Dispatch one effect through the fixed adapter after admission. + /// + /// # Errors + /// + /// Returns [`FixedEffectError::EffectClassDenied`] when the daemon + /// mode does not admit the class,and [`FixedEffectError::Broker`] when + /// the broker dispatch fails. + pub fn dispatch( &self, class: ProviderEffectClass, request: BrokerRequest, @@ -801,6 +814,14 @@ impl ProviderLifecycleDispatch { } /// Admit one request after checking caller role, Zone, and deduplication. + /// + /// # Errors + /// + /// Returns [`ProviderEffectError::CallerRoleDenied`], + /// [`ProviderEffectError::ZoneMismatch`], + /// [`ProviderEffectError::StopOnlyLease`], or + /// [`ProviderEffectError::StateUnavailable`]. + /// pub fn admit( &self, caller: &BrokerCallerRole, From 5bf7419ca62059b54a85b0d11825047ea79697dc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:10 -0700 Subject: [PATCH 119/726] target-session-and-audio: document error surfaces --- packages/d2bd/src/audio_dispatch.rs | 11 ++++++++++- packages/d2bd/src/guest_target_session.rs | 7 +++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/d2bd/src/audio_dispatch.rs b/packages/d2bd/src/audio_dispatch.rs index b8f3781e6..4d5880e79 100644 --- a/packages/d2bd/src/audio_dispatch.rs +++ b/packages/d2bd/src/audio_dispatch.rs @@ -369,7 +369,16 @@ pub(crate) fn combined_audio_applied( // ── dispatch_audio ──────────────────────────────────────────────────────────── -pub fn dispatch_audio( +/// Dispatch one audio op (Status, SetVolume, Mute) through the + /// capability-resolved audio provider for the target VMs. + /// + /// Status collects a per-VM result (entries and per-VM errors) from + /// the provider's state; SetVolume and Mute apply a state transition under + /// the audio serialization lock,and return [`TypedError::InternalIo`] + /// for manifest, capability, lock, read, write, or enforcement + /// failures. + + pub fn dispatch_audio( state: &ServerState, caller_role: BrokerCallerRole, op: AudioOp, diff --git a/packages/d2bd/src/guest_target_session.rs b/packages/d2bd/src/guest_target_session.rs index 9c4f9dd69..0e593aa59 100644 --- a/packages/d2bd/src/guest_target_session.rs +++ b/packages/d2bd/src/guest_target_session.rs @@ -34,6 +34,13 @@ impl GuestTargetSession for DaemonGuestTargetSession { self.session.route_binding().liveness().is_live() } + /// Forward one target-control request through the live session client. + /// + /// # Errors + /// + /// Returns [`GuestTargetError::SessionUnavailable`] when the session is + /// no longer live or the request fails. + async fn request( &self, request: ttrpc::Request, From 154d9e7750e46c1f4374215cc59406351dc86909 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:10 -0700 Subject: [PATCH 120/726] d2bd: add crate-level documentation --- packages/d2bd/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/d2bd/src/lib.rs b/packages/d2bd/src/lib.rs index 9e132fd27..9fd73630d 100644 --- a/packages/d2bd/src/lib.rs +++ b/packages/d2bd/src/lib.rs @@ -1,5 +1,13 @@ #![allow(clippy::result_large_err)] +//! The `d2bd` daemon composition wires the static Provider deployment and +//! effect adapter (U12), the Zone resource planes and their controller +//! runtimes, the interaction families (display-wayland, audio, +//! clipboard, notification, shell-pool),the guest target-control seam, +//! and the operator dispatch over the public socket. [`serve`] runs the +//! daemon accept loop; [`lock_only`] holds the state lock alone. The +//! CLI contract the daemon serves is `docs/reference/cli-contract.md`, +//! and its error surface is `docs/reference/error-codes.md`. pub(crate) mod shared_provider_effects; From 8b6efd32aaa5a97c06f0d5aa6348769973452b85 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:33 -0700 Subject: [PATCH 121/726] refactor(azure-vm): borrow handles, drop secret copy, document errors --- .../src/bootstrap.rs | 29 ++++++--- .../src/config.rs | 17 +++++ .../src/controller/mod.rs | 63 +++++++++++++++++-- 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs index 1a58a36ba..a2e3fdd09 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/bootstrap.rs @@ -12,6 +12,11 @@ pub struct BootstrapPsk(Zeroizing>); impl BootstrapPsk { /// Construct a bounded PSK. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when the secret is + /// empty or exceeds the 8192-byte bound. pub fn from_bytes(bytes: impl Into>) -> Result { let mut bytes = bytes.into(); if bytes.is_empty() || bytes.len() > 8_192 { @@ -22,6 +27,10 @@ impl BootstrapPsk { } /// Compare against a presented PSK without exposing it. + /// + /// The comparison is constant-time in the presented length: it walks + /// the longer of the two secrets with zero padding and never exits + /// early on a mismatch. pub fn matches(&self, presented: &[u8]) -> bool { let mut difference = self.0.len() ^ presented.len(); let length = self.0.len().max(presented.len()); @@ -79,6 +88,14 @@ impl BootstrapAdmission { } /// Consume the PSK if the nonce is fresh and the deadline is valid. + /// + /// # Errors + /// + /// Returns [`AzureVmError::BootstrapPskExpired`] when the deadline + /// elapsed, [`AzureVmError::BootstrapPskReplayed`] when the admission + /// was already consumed, and + /// [`AzureVmError::BootstrapEnrollmentFailed`] when the presented PSK + /// does not match. pub fn consume( &mut self, presented: &[u8], @@ -120,9 +137,10 @@ impl BootstrapAdmission { } /// Bootstrap service session state. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum BootstrapServiceState { /// Waiting for one IKpsk2 enrollment. + #[default] Waiting, /// Enrollment completed and KK may be used. Enrolled, @@ -131,18 +149,11 @@ pub enum BootstrapServiceState { } /// Gateway Guest bootstrap service. +#[derive(Default)] pub struct BootstrapService { state: BootstrapServiceState, } -impl Default for BootstrapService { - fn default() -> Self { - Self { - state: BootstrapServiceState::Waiting, - } - } -} - impl BootstrapService { /// Restore a service state from the sealed controller recovery record. pub const fn from_state(state: BootstrapServiceState) -> Self { diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/config.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/config.rs index 6e55370d1..e311f60ab 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/config.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/config.rs @@ -46,6 +46,11 @@ pub struct DataDiskSpec { impl DataDiskSpec { /// Validate one data disk intent. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when the size is zero + /// or exceeds the bound, or the label is empty, overlong, or malformed. pub fn validate(&self) -> Result<(), AzureVmError> { if self.size_gb == 0 || self.size_gb > 32_767 { return Err(AzureVmError::InvalidConfiguration); @@ -100,6 +105,12 @@ pub struct AzureVmConfig { impl AzureVmConfig { /// Validate the root configuration and its gateway boundary. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when the credential + /// reference is not a `Credential`, the controller execution reference + /// is not a `Guest`, or the network reference is not a `Network`. pub fn validate(&self) -> Result<(), AzureVmError> { if self.arm_credential_ref.resource_type().as_str() != "Credential" || self.controller_execution_ref.resource_type().as_str() != "Guest" @@ -174,6 +185,12 @@ pub struct AzureVmGuestSettings { impl AzureVmGuestSettings { /// Validate all bounds and closed sets. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when a bound or + /// closed-set check fails (OS disk size, admin user, data-disk count, + /// bootstrap deadline, tag count, or a nested disk or LUN check). pub fn validate(&self) -> Result<(), AzureVmError> { if self .os_disk_size_gb diff --git a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs index 3486d8c95..159d79d24 100644 --- a/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs +++ b/packages/d2b-provider-guest-azure-virtual-machine/src/controller/mod.rs @@ -271,6 +271,12 @@ where } /// Restore non-secret state after the controller has been reconstructed. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when the recovery + /// record is internally inconsistent (operation/phase pairing, + /// finalizer, or identifier bounds). pub fn restore_recovery_state( mut self, recovery: AzureVmRecoveryState, @@ -330,6 +336,16 @@ where } /// Reconcile without blocking on ARM polling. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when the finalizer is + /// missing, [`AzureVmError::Ambiguous`] when the owned VM identity is + /// absent or ambiguous, the transient ARM variants + /// ([`AzureVmError::Transient`], throttling, quota, and network + /// variants) for retryable effect failures, and the fatal variants + /// (`BootstrapFailed`, `ArmProvisioningFailed`, `ArmCredentialDenied`) + /// when an effect cannot be retried. pub async fn reconcile( &mut self, zone_uid: &str, @@ -415,6 +431,13 @@ where } /// Adopt a running VM only when its d2b tag digest matches. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when the finalizer is + /// missing, [`AzureVmError::Ambiguous`] when the observed VM identity + /// does not match the tag digest, and the ARM effect variants for + /// retryable and fatal effect failures. pub async fn adopt(&mut self) -> Result { if !self.finalizer { return Err(AzureVmError::InvalidConfiguration); @@ -443,6 +466,12 @@ where } /// Advance the current opaque long-running operation. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidOperationHandle`] when the supplied + /// handle is not the current operation, and the ARM effect variants for + /// retryable and fatal polling failures. pub async fn poll_operation( &mut self, operation: crate::effect::AzureOperationHandle, @@ -601,6 +630,14 @@ where } /// Start one typed mutable update without blocking on ARM. + /// + /// # Errors + /// + /// Returns [`AzureVmError::InvalidConfiguration`] when an update is + /// already pending or the finalizer is missing, the validation error + /// when the update contradicts the current VM shape, + /// [`AzureVmError::Ambiguous`] when the owned VM identity is absent, + /// and the ARM effect variants for retryable and fatal failures. pub async fn update( &mut self, zone_uid: &str, @@ -637,7 +674,7 @@ where ); return Err(error); } - let handle = self.vm_handle.clone().ok_or(AzureVmError::Ambiguous)?; + let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?; let operation_id = operation_id(zone_uid, guest_uid, generation, update.operation_class()); let token = self.arm_token().await?; @@ -670,6 +707,12 @@ where } /// Begin deletion. The finalizer is retained until the LRO succeeds. + /// + /// # Errors + /// + /// Returns [`AzureVmError::Ambiguous`] when the owned VM identity or + /// pending delete operation is absent, and the ARM effect variants for + /// retryable and fatal deletion failures. pub async fn finalize( &mut self, zone_uid: &str, @@ -745,6 +788,13 @@ where } /// Complete one authenticated bootstrap enrollment. + /// + /// # Errors + /// + /// Returns [`AzureVmError::BootstrapFailed`] when the enrollment + /// deadline elapsed, and the bootstrap admission variants + /// (`BootstrapPskExpired`, `BootstrapPskReplayed`, + /// `BootstrapEnrollmentFailed`) when the presented PSK is refused. pub fn complete_enrollment( &mut self, admission: &mut crate::bootstrap::BootstrapAdmission, @@ -761,7 +811,7 @@ where } async fn start_psk_delivery(&mut self) -> Result { - let handle = self.vm_handle.clone().ok_or(AzureVmError::Ambiguous)?; + let handle = self.vm_handle.as_ref().ok_or(AzureVmError::Ambiguous)?; let started = *self .bootstrap_started_at_unix_ms .get_or_insert_with(|| self.clock.now_unix_ms()); @@ -788,7 +838,8 @@ where .bootstrap_psk .as_ref() .ok_or(AzureVmError::BootstrapFailed)?; - let payload = PskExtensionPayload::from_secret(psk.copy_for_delivery().to_vec())?; + let mut delivery = psk.copy_for_delivery(); + let payload = PskExtensionPayload::from_secret(std::mem::take(&mut *delivery))?; let token = self.arm_token().await?; let operation = self .effect @@ -849,7 +900,7 @@ where let (handle, _) = self.verify_owned_vm(handle, tags, "pending-delete")?; let operation_id = self .pending_delete_operation_id - .clone() + .as_deref() .ok_or(AzureVmError::Ambiguous)?; let token = self.arm_token().await?; let operation = self @@ -1043,7 +1094,9 @@ fn operation_id(zone_uid: &str, guest_uid: &str, generation: u64, operation_clas digest.update(generation.to_be_bytes()); digest.update([0]); digest.update(operation_class.as_bytes()); - base32(&digest.finalize())[..20].to_owned() + let mut id = base32(&digest.finalize()); + id.truncate(20); + id } fn base32(bytes: &[u8]) -> String { From 40dc98ca3c682b402193059315f04319b24eb129 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:27:54 -0700 Subject: [PATCH 122/726] volume-local: fold phases with derived Ord and document error contracts --- .../d2b-provider-volume-local/src/content.rs | 20 +++++++++++++++++++ .../src/controller.rs | 7 +++++++ .../d2b-provider-volume-local/src/layout.rs | 6 ++++++ .../d2b-provider-volume-local/src/source.rs | 11 ++++++++++ .../d2b-provider-volume-local/src/status.rs | 6 +----- .../d2b-provider-volume-local/src/views.rs | 13 ++++++++++++ 6 files changed, 58 insertions(+), 5 deletions(-) diff --git a/packages/d2b-provider-volume-local/src/content.rs b/packages/d2b-provider-volume-local/src/content.rs index 468df6264..ddf480a3c 100644 --- a/packages/d2b-provider-volume-local/src/content.rs +++ b/packages/d2b-provider-volume-local/src/content.rs @@ -116,6 +116,13 @@ pub struct ContentFile { impl ContentFile { /// Construct a file and derive its canonical SHA-256 digest. + /// + /// # Errors + /// + /// Returns [`VolumeLocalError::InvalidSpec`] when the path is not a + /// valid anchored relative path, the owner or group is not a `User` + /// reference, the mode is not a valid octal string, or the size + /// exceeds the content ceiling. pub fn new( path: impl Into, owner: ResourceRef, @@ -212,6 +219,13 @@ pub struct ContentProjection { impl ContentProjection { /// Construct and validate a complete content declaration. + /// + /// # Errors + /// + /// Returns [`VolumeLocalError::InvalidSpec`] when the ownership marker + /// is unbounded, the file set is empty or over the ceiling, a file + /// fails its own validation, two files share a path, the total byte + /// size exceeds the ceiling, or the content digest does not match. pub fn new( volume_uid: ResourceUid, provenance: ContentProvenance, @@ -235,6 +249,12 @@ impl ContentProjection { } /// Parse and validate a serialized content projection. + /// + /// # Errors + /// + /// Returns [`VolumeLocalError::InvalidSpec`] when the value does not + /// deserialize as a content projection or the projection fails + /// validation. pub fn from_value(value: &serde_json::Value) -> Result { let projection: Self = serde_json::from_value(value.clone()).map_err(|_| VolumeLocalError::InvalidSpec)?; diff --git a/packages/d2b-provider-volume-local/src/controller.rs b/packages/d2b-provider-volume-local/src/controller.rs index 765b622a5..e14d9f953 100644 --- a/packages/d2b-provider-volume-local/src/controller.rs +++ b/packages/d2b-provider-volume-local/src/controller.rs @@ -145,6 +145,13 @@ impl VolumeLocalController } /// Reconcile one Volume and return its public status projection. + /// + /// # Errors + /// + /// Returns the layout or attachment admission error the underlying + /// pass reports (spec, source, entry, quota, or effect failures), and + /// [`VolumeLocalError::InvalidSpec`] when the provider content block is + /// missing or malformed. pub async fn reconcile( &self, volume_uid: &ResourceUid, diff --git a/packages/d2b-provider-volume-local/src/layout.rs b/packages/d2b-provider-volume-local/src/layout.rs index 9f5e18684..0c8733fca 100644 --- a/packages/d2b-provider-volume-local/src/layout.rs +++ b/packages/d2b-provider-volume-local/src/layout.rs @@ -51,6 +51,12 @@ impl EntryRequest { /// read of the same authority rather than a second vocabulary. The ACL /// projection decodes from the same rendering, so a declaration whose /// grants exceed the mode's group class fails resolution here. + /// + /// # Errors + /// + /// Returns [`VolumeLocalError::InvalidSpec`] when a lifecycle policy + /// field or the ACL projection cannot be decoded from the entry's + /// canonical rendering. pub fn resolve( volume_uid: &ResourceUid, declared: &LayoutEntry, diff --git a/packages/d2b-provider-volume-local/src/source.rs b/packages/d2b-provider-volume-local/src/source.rs index 72008f0b6..d5f8f737f 100644 --- a/packages/d2b-provider-volume-local/src/source.rs +++ b/packages/d2b-provider-volume-local/src/source.rs @@ -127,6 +127,17 @@ impl SourcePolicyCatalog { /// Validate source-kind-specific constraints that are not represented by the /// current base contract constructor. +/// +/// # Errors +/// +/// Returns [`VolumeLocalError::SourceKindVolumeKindMismatch`] when the +/// source kind is paired with an incompatible Volume kind, +/// [`VolumeLocalError::TmpfsQuotaMissing`] or +/// [`VolumeLocalError::BlockImageQuotaMissing`] when the required quota +/// ceilings are absent, [`VolumeLocalError::BlockImageTransportMismatch`] +/// when a block-image attachment does not use virtio-blk, and +/// [`VolumeLocalError::InvalidSpec`] for the remaining constraint +/// violations. pub fn validate_source_spec(spec: &VolumeSpec) -> Result<(), VolumeLocalError> { match spec.source().settings().kind() { SourceKind::LocalPath => { diff --git a/packages/d2b-provider-volume-local/src/status.rs b/packages/d2b-provider-volume-local/src/status.rs index 575065b23..def209181 100644 --- a/packages/d2b-provider-volume-local/src/status.rs +++ b/packages/d2b-provider-volume-local/src/status.rs @@ -31,11 +31,7 @@ pub enum LayoutPhase { impl LayoutPhase { /// Fold two phases, keeping the more severe one. pub fn worse(self, other: Self) -> Self { - if self as u8 >= other as u8 { - self - } else { - other - } + self.max(other) } } diff --git a/packages/d2b-provider-volume-local/src/views.rs b/packages/d2b-provider-volume-local/src/views.rs index ddb821076..505b6143e 100644 --- a/packages/d2b-provider-volume-local/src/views.rs +++ b/packages/d2b-provider-volume-local/src/views.rs @@ -71,6 +71,19 @@ pub struct AttachmentPlan { /// outside the frozen serving default, and a second virtiofs attachment /// naming a (guest, mount path) pair that an earlier attachment already /// claimed (AE5). +/// +/// # Errors +/// +/// Returns [`VolumeLocalError::ViewNotFound`] when an attachment names an +/// undeclared view, [`VolumeLocalError::ViewRightsInsufficient`] when the +/// requested access exceeds the view's rights, +/// [`VolumeLocalError::SingleWriterConflict`] for a second simultaneous +/// writer, [`VolumeLocalError::SharedWriteUnsupported`] when the Provider +/// does not declare shared write, +/// [`VolumeLocalError::AttachmentSettingsUnsupported`] for non-default +/// virtiofs serving settings, and +/// [`VolumeLocalError::DuplicateMountPath`] when two virtiofs attachments +/// claim the same guest mount path. pub fn admit_attachments( spec: &VolumeSpec, supports_shared_write: bool, From cd1a144af8e8814e6219cd80ea6c05b2b4164404 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:28:32 -0700 Subject: [PATCH 123/726] guest-cloud-hypervisor: deduplicate the child rank and complete constructor docs --- .../src/bootstrap_graph.rs | 14 ++------ .../src/controller.rs | 14 +------- .../src/descriptor.rs | 35 +++++++++++++++++++ .../src/health.rs | 24 +++++++++++++ .../src/identity.rs | 19 ++++++++++ .../src/shutdown.rs | 22 ++---------- 6 files changed, 83 insertions(+), 45 deletions(-) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs index faa669ca0..14281b8d0 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/bootstrap_graph.rs @@ -128,16 +128,6 @@ impl BootstrapGraph { }) } - /// Check the dependency barrier. - pub fn readiness( - &self, - devices_ready: bool, - networks_ready: bool, - volumes_ready: bool, - ) -> DependencyReadiness { - self.vmm_readiness(devices_ready, networks_ready, volumes_ready, true, true) - } - /// Check all pre-start dependencies without performing an effect. pub fn vmm_readiness( &self, @@ -414,11 +404,11 @@ mod tests { let graph = BootstrapGraph::new(Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()) .unwrap(); assert_eq!( - graph.readiness(true, true, true), + graph.vmm_readiness(true, true, true, true, true), DependencyReadiness::Ready ); assert_eq!( - graph.readiness(true, true, false), + graph.vmm_readiness(true, true, false, true, true), DependencyReadiness::Pending ); } diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs index 3f300b87d..2fb36fbf2 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/controller.rs @@ -1709,7 +1709,6 @@ struct StatusProjectionOptions<'a> { /// Cloud Hypervisor Guest controller. pub struct CloudHypervisorController { - _config: crate::CloudHypervisorConfig, graph: BootstrapGraph, descriptor: VerifiedGuestSetupDescriptor, registration: CloudHypervisorControllerRegistration, @@ -1719,7 +1718,6 @@ pub struct CloudHypervisorController { pending_retired_child_uids: BTreeSet<(ZoneId, ResourceRef, ResourceUid)>, retired_child_uids: BTreeSet<(ZoneId, ResourceRef, ResourceUid)>, upgrade_progress: BTreeMap, - observed_process_status: Option, lifecycle_intent: Option, } @@ -1741,7 +1739,6 @@ where let registration = CloudHypervisorControllerRegistration::from_verified_descriptor(&descriptor)?; Ok(Self { - _config: config, graph, descriptor, registration, @@ -1751,7 +1748,6 @@ where pending_retired_child_uids: BTreeSet::new(), retired_child_uids: BTreeSet::new(), upgrade_progress: BTreeMap::new(), - observed_process_status: None, lifecycle_intent: None, }) } @@ -1857,7 +1853,6 @@ where ), )); } - self.observed_process_status = None; let child_plan = BootstrapGraph::plan_children( guest.zone.clone(), guest.resource_ref.clone(), @@ -2010,11 +2005,8 @@ where ); lifecycle_conditions.push(GuestCondition::VmmProcessExited); force_degraded = true; - self.observed_process_status = Some(ProcessAdoptionStatus::Absent); - } - ProcessAdoptionStatus::Current | ProcessAdoptionStatus::Adopted => { - self.observed_process_status = Some(ProcessAdoptionStatus::Current); } + ProcessAdoptionStatus::Current | ProcessAdoptionStatus::Adopted => {} } if adoption_blocked { let status = self.project_status( @@ -2039,10 +2031,6 @@ where return Ok(CloudHypervisorReconcileOutcome::from_status(status, false)); } } - if self.observed_process_status.is_none() { - self.observed_process_status = Some(ProcessAdoptionStatus::Absent); - } - let missing = expected_refs .iter() .filter(|target| !children.contains_key(*target)) diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs index c1e51c13e..269f7766d 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/descriptor.rs @@ -380,6 +380,15 @@ impl fmt::Debug for VerifiedGuestSetupDescriptor { impl GuestSetupDescriptor { /// Construct a descriptor and compute its canonical semantic digest. + /// + /// # Errors + /// + /// Returns [`GuestSetupDescriptorError::SchemaVersionMismatch`] when the + /// schema version is unsupported, [`GuestSetupDescriptorError::CanonicalJson`] + /// when the digest cannot be encoded, [`GuestSetupDescriptorError::InvalidField`] + /// when a field fails bounded validation, and + /// [`GuestSetupDescriptorError::DigestMismatch`] when the computed digest + /// does not match. pub fn new( provider_ref: ResourceRef, provider_generation: ResourceGeneration, @@ -420,6 +429,12 @@ impl GuestSetupDescriptor { } /// Parse exactly canonical descriptor bytes. + /// + /// # Errors + /// + /// Returns [`GuestSetupDescriptorError::NonCanonical`] when the bytes are + /// not canonical JSON, and [`GuestSetupDescriptorError::InvalidEncoding`] + /// when the canonical bytes do not decode against the closed wire schema. pub fn from_canonical_bytes(bytes: &[u8]) -> Result { let value = CanonicalJsonValue::parse(bytes)?; if value.to_canonical_bytes() != bytes { @@ -429,6 +444,13 @@ impl GuestSetupDescriptor { } /// Render the exact canonical descriptor envelope bytes. + /// + /// # Errors + /// + /// Returns [`GuestSetupDescriptorError::InvalidField`] or + /// [`GuestSetupDescriptorError::DigestMismatch`] when integrity + /// validation fails, and [`GuestSetupDescriptorError::CanonicalJson`] + /// when canonical encoding fails. pub fn canonical_bytes(&self) -> Result, GuestSetupDescriptorError> { self.validate_integrity()?; Ok(CanonicalJsonValue::parse( @@ -438,6 +460,12 @@ impl GuestSetupDescriptor { } /// Validate the closed fields and self-consistent semantic digest. + /// + /// # Errors + /// + /// Returns [`GuestSetupDescriptorError::InvalidField`] when a field fails + /// bounded validation, and [`GuestSetupDescriptorError::DigestMismatch`] + /// when the computed digest does not match the stored digest. pub fn validate_integrity(&self) -> Result<(), GuestSetupDescriptorError> { self.validate_fields()?; if self.computed_digest()? != self.descriptor_digest.as_str() { @@ -448,6 +476,13 @@ impl GuestSetupDescriptor { /// Verify the catalog-bound signature and return the only child-planning /// descriptor type. + /// + /// # Errors + /// + /// Returns [`GuestSetupDescriptorError::InvalidField`] or + /// [`GuestSetupDescriptorError::DigestMismatch`] when integrity + /// validation fails, and [`GuestSetupDescriptorError::SignatureInvalid`] + /// when the signature envelope is absent or does not verify. pub fn verify_with( &self, verifier: &impl GuestSetupDescriptorVerifier, diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/health.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/health.rs index b233cf4c6..54f3901af 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/health.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/health.rs @@ -39,6 +39,11 @@ pub struct GuestSessionEvidenceBinding { impl GuestSessionEvidenceBinding { /// Validate and construct one exact Guest-session evidence binding. + /// + /// # Errors + /// + /// Returns [`GuestSessionError::Protocol`] when any identity, digest, or + /// generation value fails its bounded parse. #[allow(clippy::too_many_arguments)] pub fn new( guest_uid: impl Into, @@ -192,6 +197,13 @@ pub struct GuestSessionEvidence { impl GuestSessionEvidence { /// Construct current evidence from an authenticated ComponentSession. + /// + /// # Errors + /// + /// Returns [`GuestSessionError::AuthenticationFailed`] when the Guest + /// reference, boot-identity digest, or reconnect generation is not + /// authenticated, and [`GuestSessionError::Protocol`] when a capability + /// name is malformed or the set exceeds the bound. pub fn current( guest_ref: ResourceRef, boot_identity_digest: impl Into, @@ -229,6 +241,13 @@ impl GuestSessionEvidence { /// Construct current evidence with exact Guest, descriptor, generation, /// Endpoint, and seed commitments. + /// + /// # Errors + /// + /// Returns the same errors as [`Self::current`]: `AuthenticationFailed` + /// when the Guest reference, boot-identity digest, or reconnect + /// generation is not authenticated, and `Protocol` when a capability + /// name is malformed or the set exceeds the bound. pub fn current_bound( guest_ref: ResourceRef, boot_identity_digest: impl Into, @@ -258,6 +277,11 @@ impl GuestSessionEvidence { } /// Construct a stale evidence snapshot after a disconnected session. + /// + /// # Errors + /// + /// Returns [`GuestSessionError::AuthenticationFailed`] when the Guest + /// reference or reconnect generation is not authenticated. pub fn stale( guest_ref: ResourceRef, reconnect_generation: u64, diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs index 4bb6c99dd..fb296e260 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/identity.rs @@ -114,6 +114,16 @@ impl ChildRole { Self::VmmProcess | Self::ChApiEndpoint | Self::GuestControlEndpoint => None, } } + + /// Return the teardown and upgrade ordering rank for this role. + pub const fn rank(self) -> u8 { + match self { + Self::ChApiEndpoint => 0, + Self::GuestControlEndpoint => 1, + Self::VmmProcess => 2, + Self::SystemVolume => 3, + } + } } /// The exact closed set of direct Cloud Hypervisor child roles. @@ -583,6 +593,15 @@ pub struct GuestChildBatch { impl GuestChildBatch { /// Construct the complete UID-free child batch from a valid descriptor. + /// + /// # Errors + /// + /// Returns [`ChildIdentityError::WrongResourceType`] when the owner is + /// not a `Guest` or the execution reference is not a `Host`, + /// [`ChildIdentityError::ChildNameInvalid`] when a deterministic child + /// name exceeds the ResourceName bound, and the child-body construction + /// errors (`DescriptorInvalid`, `CanonicalJson`, `InvalidToken`, + /// `InvalidRevision`) when a child body cannot be built. pub fn from_descriptor( zone: ZoneId, owner_ref: ResourceRef, diff --git a/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs b/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs index 0a11ee8e5..25bdb4a71 100644 --- a/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs +++ b/packages/d2b-provider-guest-cloud-hypervisor/src/shutdown.rs @@ -417,7 +417,7 @@ pub fn plan_finalization( } let mut children = input.direct_children; - children.sort_by_key(|child| (deletion_rank(child.role), child.target.clone())); + children.sort_by_key(|child| (child.role.rank(), child.target.clone())); if let Some(child) = children .iter() .find(|child| !child.deletion_requested) @@ -484,15 +484,6 @@ fn blocked_plan(guest_uid: ResourceUid, reason: FinalizationBlockReason) -> Gues } } -fn deletion_rank(role: ChildRole) -> u8 { - match role { - ChildRole::ChApiEndpoint => 0, - ChildRole::GuestControlEndpoint => 1, - ChildRole::VmmProcess => 2, - ChildRole::SystemVolume => 3, - } -} - /// Infer one fixed direct-child role from its deterministic ResourceRef. pub fn child_role_for_ref(target: &ResourceRef) -> Option { [ @@ -605,7 +596,7 @@ pub fn plan_upgrade( return Err(LifecyclePlanError::ChildDuplicate); } } - children.sort_by_key(|child| (upgrade_rank(child.role), child.target.clone())); + children.sort_by_key(|child| (child.role.rank(), child.target.clone())); let durable_volumes = children .iter() .filter(|child| child.role == ChildRole::SystemVolume) @@ -664,15 +655,6 @@ pub fn plan_upgrade( }) } -fn upgrade_rank(role: ChildRole) -> u8 { - match role { - ChildRole::ChApiEndpoint => 0, - ChildRole::GuestControlEndpoint => 1, - ChildRole::VmmProcess => 2, - ChildRole::SystemVolume => 3, - } -} - /// Failure while building a bounded lifecycle plan. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LifecyclePlanError { From 9e7388e34fbbed12d4e2fd7114b300ad12b1675d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:28:50 -0700 Subject: [PATCH 124/726] refactor(d2b-provider-device-usbip): collect dependency refs by iterator --- .../d2b-provider-device-usbip/src/driver.rs | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/d2b-provider-device-usbip/src/driver.rs b/packages/d2b-provider-device-usbip/src/driver.rs index 6209223a0..aaffbf2da 100644 --- a/packages/d2b-provider-device-usbip/src/driver.rs +++ b/packages/d2b-provider-device-usbip/src/driver.rs @@ -264,23 +264,19 @@ pub fn declared_dependency_refs( spec: &Value, _metadata: &Value, ) -> Vec { - let mut refs = Vec::new(); match component { - UsbipComponent::Service => { - if let Ok(reference) = spec_ref(spec, "/spec/backingDeviceRef") { - refs.push(reference); - } - } - UsbipComponent::Binding => { - if let Ok(reference) = spec_ref(spec, "/spec/serviceRef") { - refs.push(reference); - } - if let Ok(reference) = spec_ref(spec, "/spec/guestRef") { - refs.push(reference); - } - } + UsbipComponent::Service => [spec_ref(spec, "/spec/backingDeviceRef").ok()] + .into_iter() + .flatten() + .collect(), + UsbipComponent::Binding => [ + spec_ref(spec, "/spec/serviceRef").ok(), + spec_ref(spec, "/spec/guestRef").ok(), + ] + .into_iter() + .flatten() + .collect(), } - refs } /// One reference field of a stored spec. From d674e47e9ba8eb718795db959756dc6a24df345f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:28:50 -0700 Subject: [PATCH 125/726] refactor(d2b-provider-device-usbip): store leases before cloning them --- .../d2b-provider-device-usbip/src/broker.rs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/d2b-provider-device-usbip/src/broker.rs b/packages/d2b-provider-device-usbip/src/broker.rs index 61b7c78a2..f5d335fec 100644 --- a/packages/d2b-provider-device-usbip/src/broker.rs +++ b/packages/d2b-provider-device-usbip/src/broker.rs @@ -58,6 +58,11 @@ impl core::fmt::Debug for UsbipBindingContext { impl UsbipBindingContext { /// Construct a context only from Core-resolved opaque references. + /// + /// # Errors + /// + /// Returns [`ServiceLifecycleError::InvalidState`] when any identifier + /// is empty or the physical key is all zeros. pub fn new( vm_id: impl Into, env: impl Into, @@ -199,13 +204,13 @@ impl<'a> UsbipBrokerDispatcher for KernelUsbipDispatcher<'a> { } return Err(ServiceLifecycleError::PhysicalAuthorityConflict); } - let lease = PhysicalAuthorityLease::from_adapter(ledger.token(1)); + self.physical_lease = Some(PhysicalAuthorityLease::from_adapter(ledger.token(1))); + let lease = self.physical_lease.as_ref().expect("lease just stored"); ledger.physical.insert( self.context.physical_key, (service_uid.to_canonical_string(), lease.clone()), ); - self.physical_lease = Some(lease.clone()); - Ok(lease) + Ok(lease.clone()) } fn reserve_relay( @@ -223,13 +228,13 @@ impl<'a> UsbipBrokerDispatcher for KernelUsbipDispatcher<'a> { } return Err(ServiceLifecycleError::RelayAuthorityConflict); } - let lease = ServiceRelayLease::from_adapter(ledger.token(2)); + self.relay_lease = Some(ServiceRelayLease::from_adapter(ledger.token(2))); + let lease = self.relay_lease.as_ref().expect("lease just stored"); ledger.relay.insert( self.context.env.clone(), (service_uid.to_canonical_string(), lease.clone()), ); - self.relay_lease = Some(lease.clone()); - Ok(lease) + Ok(lease.clone()) } fn bind_owned( @@ -315,10 +320,10 @@ impl<'a> UsbipBrokerDispatcher for KernelUsbipDispatcher<'a> { self.attach_slot = Some(slot.clone()); return Ok(slot.clone()); } - let slot = BindingSlotLease::from_adapter(ledger.token(4)); + self.attach_slot = Some(BindingSlotLease::from_adapter(ledger.token(4))); + let slot = self.attach_slot.as_ref().expect("slot just stored"); ledger.slots.insert(key, slot.clone()); - self.attach_slot = Some(slot.clone()); - Ok(slot) + Ok(slot.clone()) } fn start_proxy( @@ -335,10 +340,10 @@ impl<'a> UsbipBrokerDispatcher for KernelUsbipDispatcher<'a> { self.attach_proxy = Some(proxy.clone()); return Ok(proxy.clone()); } - let proxy = BindingProxyLease::from_adapter(ledger.token(5)); + self.attach_proxy = Some(BindingProxyLease::from_adapter(ledger.token(5))); + let proxy = self.attach_proxy.as_ref().expect("proxy just stored"); ledger.proxies.insert(key, proxy.clone()); - self.attach_proxy = Some(proxy.clone()); - Ok(proxy) + Ok(proxy.clone()) } // The legacy attach seams below have no live consumer (U17 site 5): the v3 From 59c6a4e3ad9d1a81f424f834c89d95cd2cf6aa68 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:28:50 -0700 Subject: [PATCH 126/726] docs(d2b-provider-device-usbip): document reconcile and state-machine surfaces --- .../src/reconcile_state.rs | 52 ++++++++++++++++++- .../src/state_machine.rs | 27 +++++++++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/packages/d2b-provider-device-usbip/src/reconcile_state.rs b/packages/d2b-provider-device-usbip/src/reconcile_state.rs index b461cda35..3e1f86178 100644 --- a/packages/d2b-provider-device-usbip/src/reconcile_state.rs +++ b/packages/d2b-provider-device-usbip/src/reconcile_state.rs @@ -3,7 +3,6 @@ //! The daemon projects these closed reasons into the probe and status surfaces; //! the module adds no broker or public wire operation. Host carrier, flow, and //! sysfs reconciliation belong to the Provider's live lifecycle path instead. -#![allow(missing_docs)] use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _}; @@ -105,23 +104,38 @@ pub enum UsbipDegradedReason { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum UsbipDegradedReasonCode { + /// One or more policy checks failed. PolicyFailed, + /// A desired device was not present at probe time. DeviceDepartedBeforeClaim, + /// Device disappeared after the daemon/broker acquired the lock. DeviceDepartedAfterLock, + /// Device disappeared while host or guest state was changing. DeviceDepartedDuringMutation, + /// A different device appeared at the expected location. DeviceReappearedWithDifferentTopology, + /// Another owner currently holds the claim. LockHeldByOtherOwner, + /// The broker-mediated claim is missing, stale, or invalid. InvalidPersistedLockClaim, + /// The host USBIP carrier or backend is unavailable. CarrierUnavailable, + /// The host device is not bound for USBIP export. HostBindUnavailable, + /// The per-environment USBIP proxy is unavailable. ProxyUnavailable, + /// The guest USBIP import has not converged. GuestImportUnavailable, + /// Host USBIP state remains after the claim was removed. StaleHostState, + /// Guest USBIP state remains after the claim was removed. StaleGuestState, + /// Probing did not produce a reconciliation-safe identity. ProbeIncomplete, } impl UsbipDegradedReasonCode { + /// Return the stable telemetry label. pub const fn telemetry_label(self) -> &'static str { match self { Self::PolicyFailed => "policy-failed", @@ -143,6 +157,7 @@ impl UsbipDegradedReasonCode { } impl UsbipPolicyFailure { + /// Return the stable telemetry label. pub const fn telemetry_label(&self) -> &'static str { match self { Self::FeatureDisabled => "feature-disabled", @@ -159,7 +174,9 @@ impl UsbipPolicyFailure { /// Bounded telemetry/log labels projected from a degraded reason. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct UsbipTelemetryLabels { + /// Stable degraded-reason label. pub reason: &'static str, + /// Stable policy-failure label, or `"none"`. pub policy: &'static str, } @@ -169,13 +186,18 @@ pub struct UsbipTelemetryLabels { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum UsbipEventType { + /// A reconciliation row became or stayed degraded. Degraded, + /// A reconciliation state transition occurred. StateTransition, + /// A repeated degraded summary was suppressed. SuppressedSummary, + /// Any other bounded event class. Other, } impl UsbipEventType { + /// Return the stable telemetry label. pub const fn telemetry_label(self) -> &'static str { match self { Self::Degraded => "degraded", @@ -191,15 +213,22 @@ impl UsbipEventType { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum UsbipEventSourceKind { + /// The guest VM the claim serves. Vm, + /// The host carrier reporting USB topology. Host, + /// The guest-side USBIP import surface. Guest, + /// The USBIP claim broker. Broker, + /// The reconciliation loop itself. Reconciler, + /// Any other bounded source class. Other, } impl UsbipEventSourceKind { + /// Return the stable telemetry label. pub const fn telemetry_label(self) -> &'static str { match self { Self::Vm => "vm", @@ -216,16 +245,19 @@ impl UsbipEventSourceKind { #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct UsbipEventSource { + /// Bounded source kind. pub kind: UsbipEventSourceKind, #[serde( default, skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_optional_usbip_event_source_vm" )] + /// Projected, bounded VM label when the source is a VM. pub vm: Option, } impl UsbipEventSource { + /// Build a VM-bucketed event source from an arbitrary VM label. pub fn vm(vm: impl AsRef) -> Self { Self { kind: UsbipEventSourceKind::Vm, @@ -233,10 +265,12 @@ impl UsbipEventSource { } } + /// Build a component-bucketed event source without a VM label. pub fn component(kind: UsbipEventSourceKind) -> Self { Self { kind, vm: None } } + /// Project the bounded telemetry label pair. pub fn telemetry_labels(&self) -> UsbipEventSourceLabels<'_> { UsbipEventSourceLabels { source_kind: self.kind.telemetry_label(), @@ -254,8 +288,11 @@ impl UsbipEventSource { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// Bounded telemetry label pair for one event source. pub struct UsbipEventSourceLabels<'a> { + /// Stable source-kind label. pub source_kind: &'static str, + /// Projected VM label, or `"none"`. pub vm: &'a str, } @@ -265,6 +302,8 @@ pub struct UsbipEventSourceLabels<'a> { pub struct UsbipReconcileCorrelationId(String); impl UsbipReconcileCorrelationId { + /// Validate abounded correlation id, returning `None` when it is empty, + /// overlong, contains an unsupported character, or looks like a trace id. pub fn new(value: impl AsRef) -> Option { let value = value.as_ref(); let valid = !value.is_empty() @@ -276,6 +315,7 @@ impl UsbipReconcileCorrelationId { valid.then(|| Self(value.to_owned())) } + /// Borrow the raw correlation id. pub fn as_str(&self) -> &str { &self.0 } @@ -304,10 +344,12 @@ impl<'de> Deserialize<'de> for UsbipReconcileCorrelationId { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct UsbipReconcileAttemptContext { + /// Correlation id for this reconcile attempt. pub correlation_id: UsbipReconcileCorrelationId, } impl UsbipDegradedReason { + /// Project the closed status code. pub fn code(&self) -> UsbipDegradedReasonCode { match self { Self::PolicyFailed(_) => UsbipDegradedReasonCode::PolicyFailed, @@ -331,6 +373,7 @@ impl UsbipDegradedReason { } } + /// Project the bounded telemetry label pair. pub fn telemetry_labels(&self) -> UsbipTelemetryLabels { UsbipTelemetryLabels { reason: self.code().telemetry_label(), @@ -341,6 +384,7 @@ impl UsbipDegradedReason { } } + /// Return the bounded human summary. pub fn summary(&self) -> &'static str { match self.code() { UsbipDegradedReasonCode::PolicyFailed => "USB policy does not allow this claim", @@ -386,6 +430,7 @@ impl UsbipDegradedReason { } } + /// Return the bounded remediation guidance. pub fn remediation(&self) -> &'static str { match self.code() { UsbipDegradedReasonCode::PolicyFailed => { @@ -429,6 +474,7 @@ impl UsbipDegradedReason { } } + /// Project the structured, redacted public reason detail. pub fn to_public_reason(&self) -> UsbipPublicDegradedReason { UsbipPublicDegradedReason { code: self.code(), @@ -446,9 +492,13 @@ impl UsbipDegradedReason { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct UsbipPublicDegradedReason { + /// Closed status code. pub code: UsbipDegradedReasonCode, #[serde(default, skip_serializing_if = "Option::is_none")] + /// Policy failure detail when the code is policy-failed. pub policy_failure: Option, + /// Bounded human summary. pub summary: String, + /// Bounded remediation guidance. pub remediation: String, } diff --git a/packages/d2b-provider-device-usbip/src/state_machine.rs b/packages/d2b-provider-device-usbip/src/state_machine.rs index e25c25203..db3a2ce6b 100644 --- a/packages/d2b-provider-device-usbip/src/state_machine.rs +++ b/packages/d2b-provider-device-usbip/src/state_machine.rs @@ -58,7 +58,6 @@ //! Failures from any step are normalised to //! [`UsbipPlanError`] so callers can map the failure into their public error //! envelope without importing daemon runtime types. -#![allow(missing_docs)] use std::fmt; @@ -112,6 +111,7 @@ pub enum UsbipClaimSource { } impl UsbipClaimSource { + /// Whether this claim originated from an explicit operator request. pub fn is_explicit(&self) -> bool { matches!(self, Self::Explicit) } @@ -210,9 +210,13 @@ pub const CANONICAL_STEPS: [UsbipBusidStep; 7] = [ /// explicit operator request (`UsbipExplicitBind` + `UsbipExplicitFirewallRule`). #[derive(Debug, Clone, PartialEq, Eq)] pub struct UsbipBusidPlan { + /// Bus identifier this plan mutates. pub busid: String, + /// Environment the plan runs in. pub env: String, + /// VM the claim serves. pub vm: String, + /// Canonical ordered step list. pub steps: Vec, /// Source of this plan: declared from bundle or explicit operator request. pub claim_source: UsbipClaimSource, @@ -251,6 +255,11 @@ impl UsbipBusidPlan { /// tagged against the step whose preconditions failed /// (`firewall` or `bind`). This is fail-fast at *plan time* so /// no executor side-effects ever run for a malformed plan. +/// # Errors +/// +/// Returns [`UsbipPlanError`] tagged against the step whose preconditions +/// failed when the bus id is empty or the resolver lacks the declared +/// firewall or bind intents. pub fn build_usbip_plan( busid: &str, env: &str, @@ -376,12 +385,19 @@ pub fn build_usbip_explicit_plan( /// Each method MUST be idempotent - replays of the same plan /// after a partial failure are expected. pub trait UsbipStepExecutor { + /// Ensure the usbip-host kernel module is loaded. fn modprobe(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + /// Acquire the broker-mediated claim lock. fn acquire_lock(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + /// Withhold non-owner VMs from the physical device. fn withhold_non_owners(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + /// Apply host firewalling for the claim. fn apply_firewall(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + /// Start the per-environment USBIP backend. fn start_backend(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + /// Bind the device to the host USBIP export. fn bind(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; + /// Start the per-environment USBIP proxy. fn start_proxy(&mut self, plan: &UsbipBusidPlan) -> Result<(), String>; } @@ -390,10 +406,15 @@ pub trait UsbipStepExecutor { /// execution halts. #[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct UsbipExecutionReport { + /// Bus identifier this report covers. pub busid: String, + /// Environment the plan ran in. pub env: String, + /// VM the claim served. pub vm: String, + /// Steps that completed successfully. pub completed: Vec, + /// First failing step and its error, when execution halted. pub failed: Option<(UsbipBusidStep, String)>, } @@ -426,6 +447,10 @@ impl UsbipExecutionReport { /// [`UsbipPlanError`] tagged with the exact step /// that blew up; the caller can lift it into the public error /// envelope unchanged. +/// # Errors +/// +/// Returns [`UsbipPlanError`] tagged with the exact step that failed; +/// prior successful steps stay recorded in the report. pub fn execute_usbip_plan( plan: &UsbipBusidPlan, executor: &mut E, From a1d9832ece67677051ccfddfbdd982a3485160a6 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:28:51 -0700 Subject: [PATCH 127/726] docs(d2b-provider-device-usbip): document error conditions on public APIs --- packages/d2b-provider-device-usbip/src/arbitration.rs | 6 ++++++ packages/d2b-provider-device-usbip/src/busid.rs | 5 +++++ packages/d2b-provider-device-usbip/src/controller.rs | 6 ++++++ packages/d2b-provider-device-usbip/src/lifecycle.rs | 4 ++++ packages/d2b-provider-device-usbip/src/vocabulary.rs | 4 ++++ 5 files changed, 25 insertions(+) diff --git a/packages/d2b-provider-device-usbip/src/arbitration.rs b/packages/d2b-provider-device-usbip/src/arbitration.rs index 55dc98a3a..721ed1b24 100644 --- a/packages/d2b-provider-device-usbip/src/arbitration.rs +++ b/packages/d2b-provider-device-usbip/src/arbitration.rs @@ -73,6 +73,12 @@ pub struct UsbipArbitrator { impl UsbipArbitrator { /// Construct an arbiter after validating the Device claim ceiling. + /// + /// # Errors + /// + /// Returns [`UsbipClaimError::ArbitrationViolation`] when the claim + /// ceiling is outside `1..=16` or an exclusive arbitration requests a + /// ceiling other than one. pub fn new( arbitration: DeviceArbitration, max_claims: u32, diff --git a/packages/d2b-provider-device-usbip/src/busid.rs b/packages/d2b-provider-device-usbip/src/busid.rs index c064a4814..f26e8d397 100644 --- a/packages/d2b-provider-device-usbip/src/busid.rs +++ b/packages/d2b-provider-device-usbip/src/busid.rs @@ -9,6 +9,11 @@ pub struct BusId(String); impl BusId { /// Parse the shared canonical USB bus-ID grammar. + /// + /// # Errors + /// + /// Returns [`BusIdError`] when the value does not match the canonical + /// bus-ID grammar. pub fn parse(value: impl Into) -> Result { let value = value.into(); validate_bus_id(&value)?; diff --git a/packages/d2b-provider-device-usbip/src/controller.rs b/packages/d2b-provider-device-usbip/src/controller.rs index 7697797cd..837a230cd 100644 --- a/packages/d2b-provider-device-usbip/src/controller.rs +++ b/packages/d2b-provider-device-usbip/src/controller.rs @@ -204,6 +204,12 @@ impl core::fmt::Debug for UsbipBindingController { impl UsbipBindingController { /// Construct a Binding controller from explicit authored references. + /// + /// # Errors + /// + /// Returns [`UsbipBindingControllerError::Admission`] when the binding, + /// service, or target reference has the wrong resource type or the + /// binding child declaration fails. pub fn new( binding_ref: &ResourceRef, service_ref: &ResourceRef, diff --git a/packages/d2b-provider-device-usbip/src/lifecycle.rs b/packages/d2b-provider-device-usbip/src/lifecycle.rs index b9b9b25c6..0eb5ccef2 100644 --- a/packages/d2b-provider-device-usbip/src/lifecycle.rs +++ b/packages/d2b-provider-device-usbip/src/lifecycle.rs @@ -40,6 +40,10 @@ const USBIP_BINDING_CHILD_REQUESTS: [BindingChildRequest; 2] = [ /// The returned children are UID-free intents. The generic Process Provider /// owns launch, adoption, signalling, and reap; this Provider only describes /// its required children and observes their status. +/// # Errors +/// +/// Returns [`BindingChildError`] when the authored references fail +/// semantic admission or the child declaration cannot be built. pub fn binding_child_resources( binding_ref: &ResourceRef, service_ref: &ResourceRef, diff --git a/packages/d2b-provider-device-usbip/src/vocabulary.rs b/packages/d2b-provider-device-usbip/src/vocabulary.rs index 0da55843b..9acfe7a04 100644 --- a/packages/d2b-provider-device-usbip/src/vocabulary.rs +++ b/packages/d2b-provider-device-usbip/src/vocabulary.rs @@ -67,6 +67,10 @@ impl std::error::Error for UsbipBindClassError {} /// The family binds physical USB devices only; a bind for a device selected /// under any other `busClass` (hidraw, drm, pci, tpm) is refused closed /// rather than admitted by default. +/// # Errors +/// +/// Returns [`UsbipBindClassError::ClassNotDeclared`] when the bus class +/// is not the family's declared USBIP class. pub fn admit_bind_bus_class(bus_class: &str) -> Result<(), UsbipBindClassError> { if bus_class == USBIP_BUS_CLASS { Ok(()) From 721c96f38d5550fd868c220081bda170f25245fc Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:30:11 -0700 Subject: [PATCH 128/726] d2b-provider-transport-unix: state the portal failure contract --- .../d2b-provider-transport-unix/src/portal.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/d2b-provider-transport-unix/src/portal.rs b/packages/d2b-provider-transport-unix/src/portal.rs index 5d8083bee..8c6fd4632 100644 --- a/packages/d2b-provider-transport-unix/src/portal.rs +++ b/packages/d2b-provider-transport-unix/src/portal.rs @@ -199,6 +199,13 @@ impl TransportPortal { /// The portal retains request binding, peer evidence, and a close-on-exec /// duplicate for observation. The original accepted descriptor has exactly /// one transfer destination. + /// + /// # Errors + /// + /// Returns `AttachmentPolicyConflict`, `SocketKindMismatch`, + /// `Cloexec`, or `PeerCredentials` when the descriptor fails admission, + /// `HandleTableFull` when the per-service monitor table is full, and + /// `MonitorUnavailable` when the portal monitor lock is poisoned. pub fn open( &self, binding: TransportRequestBinding, @@ -264,6 +271,12 @@ impl TransportPortal { } /// Close a monitored transport, refusing handles owned by another portal. + /// + /// # Errors + /// + /// Returns `UnknownHandle` when the handle is not owned by this + /// portal instance,and `MonitorUnavailable` when the portal monitor + /// lock is poisoned. A finalized handle closes idempotently. pub fn close(&self, handle: TransportHandle) -> Result<(), PortalError> { let mut state = self .state @@ -284,6 +297,12 @@ impl TransportPortal { } /// Return the current socket-level monitor state for one portal-owned fd. + /// + /// # Errors + /// + /// Returns `UnknownHandle` when the handle is not owned by this + /// portal instance,and `MonitorUnavailable` when the portal monitor + /// lock is poisoned. pub fn observe(&self, handle: TransportHandle) -> Result { let state = self .state From 2170c0cacc60fee5eaff3fb87de5a62725d63431 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:30:11 -0700 Subject: [PATCH 129/726] d2b-provider-zone: state the status emitter failure contract --- packages/d2b-provider-zone/src/zone_status.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/d2b-provider-zone/src/zone_status.rs b/packages/d2b-provider-zone/src/zone_status.rs index 8726536eb..7576caa8b 100644 --- a/packages/d2b-provider-zone/src/zone_status.rs +++ b/packages/d2b-provider-zone/src/zone_status.rs @@ -108,6 +108,12 @@ impl SystemCoreStatusEmitter { /// Emit a validated Zone status containing exactly one Host and User /// system-core record. + /// + /// # Errors + /// + /// Returns `ZoneStatusProjectionError::Contract` when the input + /// carries more than one system-core host or user handler record,or + /// when the zone status is rejected by the resource projection. pub fn emit( &self, input: ZoneStatusInput, From 61c64bf0f51b9f7e0bead7f7f5eb551a6d5598f8 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:30:12 -0700 Subject: [PATCH 130/726] d2b-resource-types: fix the invocation context field docs --- packages/d2b-resource-types/src/operation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/d2b-resource-types/src/operation.rs b/packages/d2b-resource-types/src/operation.rs index e86426946..41ab5506d 100644 --- a/packages/d2b-resource-types/src/operation.rs +++ b/packages/d2b-resource-types/src/operation.rs @@ -64,8 +64,8 @@ pub struct OperationCtx<'a> { pub operation: &'a ResourceRef, /// The invocation identifier the audit record carries. pub invocation_id: &'a str, - /// The descriptors the caller attached to this invocation,when any. - /// They belong to the transport's frame,not to the handler;the handler + /// The descriptors the caller attached to this invocation, when any. + /// They belong to the transport's frame, not to the handler; the handler /// borrows them for the duration of the invocation only. pub fds: &'a [RawFd], /// The evidence chain this invocation runs under (U10, KTD6): the From 83f133d3e1776e54ab6c0d93cf0cc34a5ec150f4 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:30:13 -0700 Subject: [PATCH 131/726] d2b-session-unix: document the session transport surface --- packages/d2b-session-unix/src/adapter.rs | 13 +++++++++++ packages/d2b-session-unix/src/credit.rs | 10 ++++++++ packages/d2b-session-unix/src/descriptor.rs | 2 ++ packages/d2b-session-unix/src/pidfd.rs | 9 +++++++ packages/d2b-session-unix/src/socket.rs | 26 +++++++++++++++++++++ packages/d2b-session-unix/src/systemd.rs | 3 +++ packages/d2b-session-unix/src/vsock.rs | 4 ++++ 7 files changed, 67 insertions(+) diff --git a/packages/d2b-session-unix/src/adapter.rs b/packages/d2b-session-unix/src/adapter.rs index 5fd451152..833e14a82 100644 --- a/packages/d2b-session-unix/src/adapter.rs +++ b/packages/d2b-session-unix/src/adapter.rs @@ -348,6 +348,9 @@ impl ReceivedPacketState { } } +/// The session-facing seqpacket transport: packet-atomic framing, +/// credit-bound dispatch, and attachment enforcement over one +/// [`SeqpacketSocket`]. pub struct UnixSeqpacketTransport { socket: Arc, class: TransportClass, @@ -375,6 +378,14 @@ impl fmt::Debug for UnixSeqpacketTransport { } impl UnixSeqpacketTransport { + /// Construct a session transport after validating the attachment + /// policy against the peer identity policy. + /// + /// # Errors + /// + /// Returns `UnixSessionError` when the policy combination is invalid + /// for the transport class or the ancillary capacity cannot satisfy + /// the policy. pub fn new( socket: SeqpacketSocket, locality: Locality, @@ -674,6 +685,8 @@ impl OwnedTransport for UnixSeqpacketTransport { } } +/// The session-facing message-stream transport: length-prefixed framming +/// with resumable partial sends and receives over one [`StreamSocket`]. pub struct UnixStreamTransport { socket: Arc, locality: Locality, diff --git a/packages/d2b-session-unix/src/credit.rs b/packages/d2b-session-unix/src/credit.rs index 259bb4b18..cd7474542 100644 --- a/packages/d2b-session-unix/src/credit.rs +++ b/packages/d2b-session-unix/src/credit.rs @@ -18,6 +18,11 @@ pub enum CreditError { Overflow, } +/// A thread-safe bounded credit pool shared across session scopes. +/// +/// Reservations are accounted atomically; dropping a reservation returns +/// its credit. + #[derive(Clone)] pub struct CreditPool { inner: Arc, @@ -39,6 +44,11 @@ impl fmt::Debug for CreditPool { } impl CreditPool { + /// Construct a bounded pool. + /// + /// # Errors + /// + /// Returns `CreditError::ZeroLimit` when the bound is zero. pub fn new(limit: usize) -> Result { if limit == 0 { return Err(CreditError::ZeroLimit); diff --git a/packages/d2b-session-unix/src/descriptor.rs b/packages/d2b-session-unix/src/descriptor.rs index 87fa2109d..efae56261 100644 --- a/packages/d2b-session-unix/src/descriptor.rs +++ b/packages/d2b-session-unix/src/descriptor.rs @@ -19,6 +19,8 @@ use rustix::{ }; use std::{fmt, sync::Arc}; +/// Kernel-verified peer credentials of one socket peer, captured at +/// accept or first packet. #[derive(Clone, Copy, PartialEq, Eq)] pub struct PeerCredentials(UCred); diff --git a/packages/d2b-session-unix/src/pidfd.rs b/packages/d2b-session-unix/src/pidfd.rs index 81f16300b..fd47659cc 100644 --- a/packages/d2b-session-unix/src/pidfd.rs +++ b/packages/d2b-session-unix/src/pidfd.rs @@ -5,6 +5,9 @@ use rustix::{ }; use std::{fmt, fs, os::fd::AsRawFd, sync::Arc}; +/// Verified pidfd identity evidence: the first-packet credentials, the +/// executable digest,and the cgroup digest must all match the expected +/// process. #[derive(Clone, Copy, PartialEq, Eq)] pub struct PidfdEvidence { expected_pid: Pid, @@ -20,6 +23,12 @@ impl fmt::Debug for PidfdEvidence { } impl PidfdEvidence { + /// Construct evidence after checking the identity fences. + /// + /// # Errors + /// + /// Returns `UnixSessionError::PidfdEvidenceUnavailable` when the + /// credentials do not match the expected pid or a digest is zero. pub fn new( expected_pid: Pid, first_packet_credentials: FirstPacketCredentials, diff --git a/packages/d2b-session-unix/src/socket.rs b/packages/d2b-session-unix/src/socket.rs index f9279c411..946a83089 100644 --- a/packages/d2b-session-unix/src/socket.rs +++ b/packages/d2b-session-unix/src/socket.rs @@ -187,6 +187,11 @@ pub struct SendBurst { pub drained_to_would_block: bool, } +/// An owned SOCK_SEQPACKET socket over the async readiness surface. +/// +/// Packet-burst sends and receives are cancellation-safe:partial bursts +/// are retained across an await. + pub struct SeqpacketSocket { io: AsyncFd, received_any: AtomicBool, @@ -199,6 +204,13 @@ impl fmt::Debug for SeqpacketSocket { } impl SeqpacketSocket { + /// Take ownership of one validated seqpacket socket. + /// + /// # Errors + /// + /// Returns `UnixSessionError` when the descriptor is not a + /// seqpacket socket or cannot be registered on the async surface. + pub fn from_owned(fd: OwnedFd) -> Result { validate_socket(&fd, SocketType::SEQPACKET)?; Ok(Self { @@ -207,6 +219,15 @@ impl SeqpacketSocket { }) } + /// Adopt a parent-prearmed seqpacket socket after verifying its + /// prearment contract. + /// + /// # Errors + /// + /// Returns `UnixSessionError` when the descriptor fails the prearmed + /// contract (socket type, async registration, or `passcred` + /// not prearmed). + pub fn from_parent_prearmed(fd: OwnedFd) -> Result { verify_parent_prearmed(&fd)?; Self::from_owned(fd) @@ -219,6 +240,11 @@ impl SeqpacketSocket { /// the controller can receive it across `execve`. This function validates /// that well-known descriptor without closing it, rearms close-on-exec, /// and then takes ownership before any session use. + /// + /// # Errors + /// + /// Returns `UnixSessionError` when the inherited descriptor cannot + /// be duplicated or fails the prearmed contract. pub fn from_inherited_fd(raw_fd: RawFd) -> Result { let fd = duplicate_inherited_fd(raw_fd)?; let socket = Self::from_parent_prearmed(fd)?; diff --git a/packages/d2b-session-unix/src/systemd.rs b/packages/d2b-session-unix/src/systemd.rs index ff710d643..88331b72e 100644 --- a/packages/d2b-session-unix/src/systemd.rs +++ b/packages/d2b-session-unix/src/systemd.rs @@ -41,10 +41,13 @@ impl std::fmt::Display for SystemdActivationError { impl std::error::Error for SystemdActivationError {} +/// One inherited systemd-activated seqpacket listener socket. pub struct ActivatedSeqpacketListener { io: AsyncFd, } +/// The inherited systemd-activated seqpacket listener set, keyed by the +/// socket unit name each descriptor was passed as. pub struct ActivatedSeqpacketListeners { listeners: BTreeMap>, } diff --git a/packages/d2b-session-unix/src/vsock.rs b/packages/d2b-session-unix/src/vsock.rs index 50946b148..442cd54df 100644 --- a/packages/d2b-session-unix/src/vsock.rs +++ b/packages/d2b-session-unix/src/vsock.rs @@ -19,6 +19,10 @@ pub const fn guest_control_transport_descriptor() -> TransportDescriptor { } } +/// A length-prefixed framed transport over one vsock stream. +/// +/// Partial sends and receives are resumable across cancellation:the +/// in-flight header and body buffers persist between calls. pub struct FramedVsockTransport { stream: S, descriptor: TransportDescriptor, From 21e8948b27f4d6efd09f864518f06e2c8f526bee Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:30:28 -0700 Subject: [PATCH 132/726] refactor(d2b-provider-network-local): simplify octet rendering and dependency collection --- .../src/controller.rs | 11 +++-------- .../d2b-provider-network-local/src/driver.rs | 19 +++++++++---------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/packages/d2b-provider-network-local/src/controller.rs b/packages/d2b-provider-network-local/src/controller.rs index 3e8fc26a8..11c545ccd 100644 --- a/packages/d2b-provider-network-local/src/controller.rs +++ b/packages/d2b-provider-network-local/src/controller.rs @@ -293,13 +293,8 @@ fn network_cidr_host_address(cidr: &str, host: u8) -> Option { } let last = octets.last_mut()?; *last = last.checked_add(host)?; - Some( - octets - .into_iter() - .map(|octet| octet.to_string()) - .collect::>() - .join("."), - ) + let [a, b, c, d] = octets.try_into().ok()?; + Some(format!("{a}.{b}.{c}.{d}")) } /// Host-fabric names and CIDRs admitted for one immutable Network identity. @@ -414,7 +409,7 @@ impl NetworkAdmissionIntent { let mut unique_interfaces = BTreeSet::new(); if interface_names .iter() - .any(|ifname| !unique_interfaces.insert(ifname.as_str().to_owned())) + .any(|ifname| !unique_interfaces.insert(ifname.as_str())) { debug!( provider = "network-local", diff --git a/packages/d2b-provider-network-local/src/driver.rs b/packages/d2b-provider-network-local/src/driver.rs index f810089ff..d5c1a8173 100644 --- a/packages/d2b-provider-network-local/src/driver.rs +++ b/packages/d2b-provider-network-local/src/driver.rs @@ -375,19 +375,18 @@ pub fn declared_dependency_refs( spec: &Value, _metadata: &Value, ) -> Vec { - let mut refs = Vec::new(); - if let Some(attachments) = spec.pointer("/spec/attachments").and_then(Value::as_array) { - for attachment in attachments { - if let Some(reference) = attachment + spec + .pointer("/spec/attachments") + .and_then(Value::as_array) + .into_iter() + .flatten() + .filter_map(|attachment| { + attachment .get("executionRef") .and_then(Value::as_str) .and_then(|value| ResourceRef::parse(value).ok()) - { - refs.push(reference); - } - } - } - refs + }) + .collect() } #[cfg(test)] From 3c9cdc40657946bad00eec4b375d7afb6b6e1e2d Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:31:07 -0700 Subject: [PATCH 133/726] resource-client: share call helpers, drop duplicate accessor, document errors --- packages/d2b-resource-client/src/call.rs | 53 +++++++++++++- packages/d2b-resource-client/src/dispatch.rs | 10 +++ .../d2b-resource-client/src/process_attach.rs | 56 ++++----------- .../d2b-resource-client/src/zone_client.rs | 71 +++++++------------ 4 files changed, 102 insertions(+), 88 deletions(-) diff --git a/packages/d2b-resource-client/src/call.rs b/packages/d2b-resource-client/src/call.rs index ac53a042f..0969eb7e4 100644 --- a/packages/d2b-resource-client/src/call.rs +++ b/packages/d2b-resource-client/src/call.rs @@ -18,7 +18,7 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; -use crate::ClientError; +use crate::{AttemptDisposition, CallDriver, ClientError, SessionFailure}; /// The protocol ceiling on one request's lifetime. pub const MAX_REQUEST_LIFETIME_MS: u64 = 15 * 60 * 1_000; @@ -87,6 +87,12 @@ impl fmt::Debug for MetadataInput { impl MetadataInput { /// Build validated metadata for one request. + /// + /// # Errors + /// + /// Returns [`ClientError::InvalidMetadata`] when the issue time is + /// zero, the expiry precedes the issue time, or the lifetime exceeds + /// the protocol ceiling. pub fn new( request_id: [u8; REQUEST_ID_BYTES], issued_at_unix_ms: u64, @@ -184,6 +190,11 @@ pub struct RetryPolicy { impl RetryPolicy { /// Allow up to `max_attempts` total attempts. + /// + /// # Errors + /// + /// Returns [`ClientError::InvalidMetadata`] when `max_attempts` is + /// zero or exceeds the retry bound. pub const fn new(max_attempts: u8) -> Result { if max_attempts == 0 || max_attempts > MAX_RETRY_ATTEMPTS { return Err(ClientError::InvalidMetadata); @@ -241,6 +252,46 @@ pub(crate) async fn retry_backoff( .await } +/// Race one future against the shared cancellation token, refusing with +/// [`ClientError::Cancelled`] when the token cancels first. +pub(crate) async fn await_with_cancellation( + future: F, + cancellation: &CancellationToken, +) -> Result +where + F: Future + Send, +{ + let mut future = Box::pin(future); + let mut cancelled = Box::pin(cancellation.cancelled()); + core::future::poll_fn(move |context| { + if let core::task::Poll::Ready(value) = future.as_mut().poll(context) { + return core::task::Poll::Ready(Ok(value)); + } + if let core::task::Poll::Ready(()) = cancelled.as_mut().poll(context) { + return core::task::Poll::Ready(Err(ClientError::Cancelled)); + } + core::task::Poll::Pending + }) + .await +} + +/// Classify one call failure into the driver's session-failure ledger and +/// the retry disposition it earns. +pub(crate) fn classify_session_error( + driver: &CallDriver, + error: ClientError, +) -> AttemptDisposition { + match error { + ClientError::SessionLost => driver.record_session_failure(SessionFailure::Disconnected), + ClientError::TransportFailed => driver.record_session_failure(SessionFailure::Retryable), + ClientError::DeadlineExpired => driver.record_session_failure(SessionFailure::Deadline), + ClientError::Cancelled => driver.record_session_failure(SessionFailure::Cancelled), + ClientError::ContractViolation => driver.record_session_failure(SessionFailure::Protocol), + ClientError::Remote { kind, retry } => driver.record_remote_verdict(kind, retry), + other => AttemptDisposition::Fail(other), + } +} + /// A cooperative cancellation signal shared by a caller and a call driver. /// /// Cancellation is observed, never inferred: a driver checks the token before diff --git a/packages/d2b-resource-client/src/dispatch.rs b/packages/d2b-resource-client/src/dispatch.rs index 109377e9d..fbb21fad6 100644 --- a/packages/d2b-resource-client/src/dispatch.rs +++ b/packages/d2b-resource-client/src/dispatch.rs @@ -173,6 +173,16 @@ impl CallDriver { /// The resolved service must match the method's service, a method that /// requires an idempotency key must have been given one, and the deadline /// must still be in the future against `clock`. + /// + /// # Errors + /// + /// Returns [`ClientError::InvalidMethod`] when the resolved service + /// does not match the method's profile, + /// [`ClientError::IdempotencyRequired`] when the profile demands an + /// idempotency key and none was supplied, + /// [`ClientError::InvalidMetadata`] when the lifetime is invalid, and + /// [`ClientError::DeadlineExpired`] when the deadline has already + /// passed. pub fn new( target: &ResolvedTarget, profile: MethodProfile, diff --git a/packages/d2b-resource-client/src/process_attach.rs b/packages/d2b-resource-client/src/process_attach.rs index cac0fb60c..34346ed3c 100644 --- a/packages/d2b-resource-client/src/process_attach.rs +++ b/packages/d2b-resource-client/src/process_attach.rs @@ -19,8 +19,8 @@ use d2b_contracts_resource::v3::ResourceRef; use d2b_contracts_zone_session::v3::zone_routing::ZonePath; use crate::{ - AttemptDisposition, CallDriver, CallOptions, CancellationToken, ClientError, MethodProfile, - ResourceClient, ServiceOwner, SessionFailure, SystemClock, TargetInput, TargetResolver, + AttemptDisposition, CallOptions, CancellationToken, ClientError, MethodProfile, + ResourceClient, ServiceOwner, SystemClock, TargetInput, TargetResolver, TransportKind, TransportSelection, WallClock, ZoneClient, ZoneServiceKind, ZoneSessionConnector, call::REQUEST_ID_BYTES, zone_client::ConnectedZoneSession, }; @@ -627,6 +627,16 @@ where /// session adapter sees the request. The adapter is responsible for /// authoritative subject mapping and the `attach` authorization verdict; /// this method cannot elevate a caller or reuse an exec admission. + /// + /// # Errors + /// + /// Returns [`ClientError::Cancelled`] when the token is already + /// cancelled, the resolver's refusal when the target cannot be + /// resolved, [`ClientError::InvalidMetadata`] when the call lifetime + /// is invalid, the admission refusal when the call cannot be admitted, + /// the connector's error when the session cannot be established, and + /// the session, transport, deadline, or remote error the open reports + /// after retries are exhausted. pub async fn attach( &self, target: ProcessAttachTarget, @@ -655,7 +665,7 @@ where self.zone .resource_client() .prepare_call(&resolved, profile, call_options, false)?; - let connection = match await_with_cancellation( + let connection = match crate::call::await_with_cancellation( self.zone .connect(&target_input, ZoneServiceKind::Zone, selection), cancellation, @@ -680,7 +690,7 @@ where let open = connection .session() .open_named_stream(request.clone(), attempt.relative_timeout_nanos()); - let result = match await_with_cancellation(open, cancellation).await { + let result = match crate::call::await_with_cancellation(open, cancellation).await { Ok(result) => result, Err(ClientError::Cancelled) => { let _ = connection.session().cancel(request_id).await; @@ -699,7 +709,7 @@ where } return Ok(stream); } - Err(error) => match classify_attach_error(&driver, error) { + Err(error) => match crate::call::classify_session_error(&driver, error) { AttemptDisposition::RetryNow => continue, AttemptDisposition::RetryAfterMs(delay) => { match crate::call::retry_backoff(delay, cancellation).await { @@ -761,42 +771,6 @@ where } } -async fn await_with_cancellation( - future: F, - cancellation: &CancellationToken, -) -> Result -where - F: Future + Send, -{ - let mut future = Box::pin(future); - let mut cancelled = Box::pin(cancellation.cancelled()); - core::future::poll_fn(move |context| { - if let core::task::Poll::Ready(value) = future.as_mut().poll(context) { - return core::task::Poll::Ready(Ok(value)); - } - if let core::task::Poll::Ready(()) = cancelled.as_mut().poll(context) { - return core::task::Poll::Ready(Err(ClientError::Cancelled)); - } - core::task::Poll::Pending - }) - .await -} - -fn classify_attach_error( - driver: &CallDriver, - error: ClientError, -) -> AttemptDisposition { - match error { - ClientError::SessionLost => driver.record_session_failure(SessionFailure::Disconnected), - ClientError::TransportFailed => driver.record_session_failure(SessionFailure::Retryable), - ClientError::DeadlineExpired => driver.record_session_failure(SessionFailure::Deadline), - ClientError::Cancelled => driver.record_session_failure(SessionFailure::Cancelled), - ClientError::ContractViolation => driver.record_session_failure(SessionFailure::Protocol), - ClientError::Remote { kind, retry } => driver.record_remote_verdict(kind, retry), - other => AttemptDisposition::Fail(other), - } -} - #[cfg(test)] mod tests { use std::{ diff --git a/packages/d2b-resource-client/src/zone_client.rs b/packages/d2b-resource-client/src/zone_client.rs index 5c411902d..54eefbfbf 100644 --- a/packages/d2b-resource-client/src/zone_client.rs +++ b/packages/d2b-resource-client/src/zone_client.rs @@ -29,7 +29,7 @@ pub use d2b_core_controller::controller_assignment::{ use crate::{ AttemptDisposition, CallDriver, CallOptions, ClientError, MethodProfile, ResolvedTarget, - ResourceClient, SessionFailure, SystemClock, TargetInput, TargetResolver, TransportKind, + ResourceClient, SystemClock, TargetInput, TargetResolver, TransportKind, TransportSelection, WallClock, ZoneServiceKind, call::REQUEST_ID_BYTES, }; @@ -195,11 +195,6 @@ impl GuestControlEndpoint { &self.uid } - /// Borrow the store-assigned Endpoint UID. - pub const fn endpoint_uid(&self) -> &ResourceUid { - &self.uid - } - /// Return the Endpoint Resource generation. pub const fn resource_generation(&self) -> ResourceGeneration { self.resource_generation @@ -673,6 +668,13 @@ where } /// Establish a session over the exact route selected by the resolver. + /// + /// # Errors + /// + /// Returns the resolver's refusal when the target cannot be resolved, + /// the connector's error when the session cannot be established, and + /// [`ClientError::TransportPolicyMismatch`] when the session pin does + /// not match the resolved route. pub async fn connect( &self, target: &TargetInput, @@ -728,6 +730,13 @@ where /// Execute a typed call over a handle whose authenticated route pin was /// checked by [`Self::connect`]. + /// + /// # Errors + /// + /// Returns [`ClientError::TransportPolicyMismatch`] when the pin no + /// longer matches the target, the profile or admission refusal when + /// the call cannot be admitted, and the session, transport, deadline, + /// or remote error the call itself reports. pub async fn call_connected( &self, connection: &ConnectedZoneClient, @@ -769,6 +778,13 @@ where /// Each target and verb is re-admitted by the non-clonable lease. The /// resulting transport descriptor is derived from that same admission /// before the existing Resource transport is used. + /// + /// # Errors + /// + /// Returns [`ClientError::ContractViolation`] when the batch is empty + /// or oversized, a mutation is not mutating or not admitted by the + /// lease, or the session pin does not match the target, and the + /// profile, admission, or call error otherwise. pub async fn scoped_commit_batch( &self, connection: &ConnectedZoneClient, @@ -868,7 +884,7 @@ where loop { let attempt = driver.begin_attempt(cancellation)?; let result = if let Some((assignment, mutations)) = scoped_call.as_ref() { - await_with_cancellation( + crate::call::await_with_cancellation( session.call_scoped_commit_batch( assignment.clone(), mutations.clone(), @@ -879,7 +895,7 @@ where ) .await } else { - await_with_cancellation( + crate::call::await_with_cancellation( session.call_with_timeout( verb, resource_target.clone(), @@ -901,7 +917,7 @@ where match result { Ok(response) => return Ok(response), - Err(error) => match classify_session_error(&driver, error) { + Err(error) => match crate::call::classify_session_error(&driver, error) { AttemptDisposition::RetryNow => continue, AttemptDisposition::RetryAfterMs(delay) => { crate::call::retry_backoff(delay, cancellation).await?; @@ -910,42 +926,6 @@ where }, } } - - async fn await_with_cancellation( - future: F, - cancellation: &crate::CancellationToken, - ) -> Result - where - F: Future + Send, - { - let mut future = Box::pin(future); - let mut cancelled = Box::pin(cancellation.cancelled()); - core::future::poll_fn(move |context| { - if let core::task::Poll::Ready(value) = future.as_mut().poll(context) { - return core::task::Poll::Ready(Ok(value)); - } - if let core::task::Poll::Ready(()) = cancelled.as_mut().poll(context) { - return core::task::Poll::Ready(Err(ClientError::Cancelled)); - } - core::task::Poll::Pending - }) - .await - } -} - -fn classify_session_error( - driver: &CallDriver, - error: ClientError, -) -> AttemptDisposition { - match error { - ClientError::SessionLost => driver.record_session_failure(SessionFailure::Disconnected), - ClientError::TransportFailed => driver.record_session_failure(SessionFailure::Retryable), - ClientError::DeadlineExpired => driver.record_session_failure(SessionFailure::Deadline), - ClientError::Cancelled => driver.record_session_failure(SessionFailure::Cancelled), - ClientError::ContractViolation => driver.record_session_failure(SessionFailure::Protocol), - ClientError::Remote { kind, retry } => driver.record_remote_verdict(kind, retry), - other => AttemptDisposition::Fail(other), - } } /// Local Zone session wrapper used by attachment clients. @@ -1064,7 +1044,6 @@ mod tests { true, ) .unwrap(); - assert_eq!(endpoint.endpoint_uid(), endpoint.uid()); assert_eq!(endpoint.zone().as_str(), "work"); assert!(!format!("{endpoint:?}").contains("gateway")); assert!(!format!("{endpoint:?}").contains("123e4567")); From 18f028fdab3732f69a28ccd94257879122164756 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:31:39 -0700 Subject: [PATCH 134/726] notification-desktop: borrow the reconciliation result and document sink errors --- .../src/action_nonce.rs | 6 +++ .../src/controller.rs | 41 ++++++++++--------- .../src/descriptor.rs | 2 +- .../src/host_sink.rs | 8 ++++ .../src/lifecycle.rs | 6 +-- .../src/runtime.rs | 5 +++ 6 files changed, 44 insertions(+), 24 deletions(-) diff --git a/packages/d2b-provider-notification-desktop/src/action_nonce.rs b/packages/d2b-provider-notification-desktop/src/action_nonce.rs index 2cd7cc97c..b9ded17a8 100644 --- a/packages/d2b-provider-notification-desktop/src/action_nonce.rs +++ b/packages/d2b-provider-notification-desktop/src/action_nonce.rs @@ -81,6 +81,12 @@ impl ActionNonceStore { } /// Register one action capability. + /// + /// # Errors + /// + /// Returns [`ActionNonceError::Capacity`] when the store is full, + /// [`ActionNonceError::Invalid`] when the action key exceeds the bound, + /// and [`ActionNonceError::Entropy`] when random nonce generation fails. pub fn register( &mut self, session: impl AsRef, diff --git a/packages/d2b-provider-notification-desktop/src/controller.rs b/packages/d2b-provider-notification-desktop/src/controller.rs index efae03bf4..20aa8a2ee 100644 --- a/packages/d2b-provider-notification-desktop/src/controller.rs +++ b/packages/d2b-provider-notification-desktop/src/controller.rs @@ -657,23 +657,24 @@ impl SourceProcessEffectReceipt { } fn expected_acknowledgements(plan: &SourceReconcileResult) -> Vec { - let mut acknowledgements = Vec::new(); - acknowledgements.extend(plan.start_endpoints.iter().map(|endpoint| { - SourceEffectAcknowledgement::Source { + let mut acknowledgements: Vec<_> = plan + .start_endpoints + .iter() + .map(|endpoint| SourceEffectAcknowledgement::Source { start: true, endpoint_digest: endpoint.endpoint_digest().to_owned(), source_generation: endpoint.source_generation(), display_generation: endpoint.display_generation(), - } - })); - acknowledgements.extend(plan.stop_endpoints.iter().map(|endpoint| { - SourceEffectAcknowledgement::Source { - start: false, - endpoint_digest: endpoint.endpoint_digest().to_owned(), - source_generation: endpoint.source_generation(), - display_generation: endpoint.display_generation(), - } - })); + }) + .chain(plan.stop_endpoints.iter().map(|endpoint| { + SourceEffectAcknowledgement::Source { + start: false, + endpoint_digest: endpoint.endpoint_digest().to_owned(), + source_generation: endpoint.source_generation(), + display_generation: endpoint.display_generation(), + } + })) + .collect(); if plan.start_host_sink { acknowledgements.push(SourceEffectAcknowledgement::HostSink { start: true, @@ -1030,7 +1031,7 @@ impl NotificationController { } }; let source_error = result.source_error; - self.commit_reconciliation(display, config, result.clone())?; + self.commit_reconciliation(display, config, &result)?; source_error.map_or(Ok(result), Err) } @@ -1055,7 +1056,7 @@ impl NotificationController { return Err("notification-process-effect-proof-mismatch"); } let source_error = result.source_error; - self.commit_reconciliation(display, config, result.clone())?; + self.commit_reconciliation(display, config, &result)?; source_error.map_or(Ok(result), Err) } @@ -1298,14 +1299,14 @@ impl NotificationController { &mut self, display: &DisplayDependencyEvidence, config: &NotificationProviderConfig, - result: SourceReconcileResult, + result: &SourceReconcileResult, ) -> Result<(), &'static str> { - for source in result.stop { - self.active_sources.remove(&source); + for source in &result.stop { + self.active_sources.remove(source); } - for endpoint in result.start_endpoints { + for endpoint in &result.start_endpoints { self.active_sources - .insert(endpoint.source_ref().clone(), endpoint); + .insert(endpoint.source_ref().clone(), endpoint.clone()); } let fingerprint = display.is_ready().then(|| display_fingerprint(display)); self.active_display_fingerprint = fingerprint; diff --git a/packages/d2b-provider-notification-desktop/src/descriptor.rs b/packages/d2b-provider-notification-desktop/src/descriptor.rs index 7d36f9deb..a72177315 100644 --- a/packages/d2b-provider-notification-desktop/src/descriptor.rs +++ b/packages/d2b-provider-notification-desktop/src/descriptor.rs @@ -41,7 +41,7 @@ impl Default for NotificationProviderDescriptor { impl NotificationProviderDescriptor { /// Notification service package. pub const fn service_package(&self) -> &'static str { - "d2b.notification.v3" + crate::SERVICE_PACKAGE } /// Notification named streams. diff --git a/packages/d2b-provider-notification-desktop/src/host_sink.rs b/packages/d2b-provider-notification-desktop/src/host_sink.rs index 2dc73c788..0449f600a 100644 --- a/packages/d2b-provider-notification-desktop/src/host_sink.rs +++ b/packages/d2b-provider-notification-desktop/src/host_sink.rs @@ -294,6 +294,14 @@ impl NotificationSink { } /// Deliver after the configured Guest-source category admission. + /// + /// # Errors + /// + /// Returns [`crate::types::NotificationError::InvalidOpaqueKey`] when the + /// Guest source rejects the session or request, and the delivery + /// validation errors (`FieldBounds`, `InvalidIcon`, `InvalidActions`, + /// `InvalidTimeout`, `InvalidOpaqueKey`, `ObserverDisabled`) when the + /// request or observer stream fails its bounded validation. pub fn deliver_from_guest_source( &mut self, port: &mut P, diff --git a/packages/d2b-provider-notification-desktop/src/lifecycle.rs b/packages/d2b-provider-notification-desktop/src/lifecycle.rs index b8fb9688e..561c92a92 100644 --- a/packages/d2b-provider-notification-desktop/src/lifecycle.rs +++ b/packages/d2b-provider-notification-desktop/src/lifecycle.rs @@ -2,7 +2,7 @@ use std::{ collections::BTreeMap, - sync::{Arc, Mutex}, + sync::Mutex, }; use tracing::{error, warn}; @@ -335,7 +335,7 @@ impl core::fmt::Debug for NotificationLifecycleReceipt { /// Core-owned lifecycle supervisor that issues receipts only after host effects. pub struct NotificationLifecycleSupervisor { - backend: Arc, + backend: B, state: Mutex, } @@ -343,7 +343,7 @@ impl NotificationLifecycleSupervisor { /// Construct one lifecycle supervisor over an authoritative host backend. pub fn new(backend: B) -> Self { Self { - backend: Arc::new(backend), + backend, state: Mutex::new(LifecycleState::default()), } } diff --git a/packages/d2b-provider-notification-desktop/src/runtime.rs b/packages/d2b-provider-notification-desktop/src/runtime.rs index 57a7b106e..117460cb7 100644 --- a/packages/d2b-provider-notification-desktop/src/runtime.rs +++ b/packages/d2b-provider-notification-desktop/src/runtime.rs @@ -61,6 +61,11 @@ pub struct NotificationRuntime { impl NotificationRuntime { /// Construct a runtime for one fixed notification Provider instance. + /// + /// # Errors + /// + /// Returns [`NotificationRuntimeError::ReconciliationFailed`] when the + /// placement controller cannot be constructed for the Provider. pub fn new( config: NotificationProviderConfig, effects: E, From 0b8ef8ff53d743085abb9e99d45210806ade463e Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:31:53 -0700 Subject: [PATCH 135/726] sk-frontend: collect zone labels by pipeline and destructure config --- packages/d2b-sk-frontend/src/config.rs | 16 +++++++++------- packages/d2b-sk-frontend/src/main.rs | 21 +++++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/packages/d2b-sk-frontend/src/config.rs b/packages/d2b-sk-frontend/src/config.rs index 2e3488eff..04e9b7b6a 100644 --- a/packages/d2b-sk-frontend/src/config.rs +++ b/packages/d2b-sk-frontend/src/config.rs @@ -80,7 +80,9 @@ impl Config { .map_err(|error| format!("D2B_SK_VSOCK_CID: {error}"))?, None => crate::link::VSOCK_HOST_CID, }; - let uhid_path = optional("D2B_SK_UHID_PATH").unwrap_or_else(|| "/dev/uhid".to_owned()); + let uhid_path = optional("D2B_SK_UHID_PATH") + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from("/dev/uhid")); let parent_zone = zone_path(&required("D2B_SK_PARENT_ZONE")?, "D2B_SK_PARENT_ZONE")?; let guest_zone = zone_path(&required("D2B_SK_GUEST_ZONE")?, "D2B_SK_GUEST_ZONE")?; @@ -175,13 +177,13 @@ fn hex(byte: u8) -> Option { /// Parse one `/`-separated Zone path, most specific first. fn zone_path(value: &str, name: &str) -> Result { - let mut labels = Vec::new(); - for label in value.split('/') { - labels.push( + let labels = value + .split('/') + .map(|label| { ZoneLabelId::parse(label) - .map_err(|_| format!("{name} is not a valid Zone label path"))?, - ); - } + .map_err(|_| format!("{name} is not a valid Zone label path")) + }) + .collect::, String>>()?; ZonePath::new(labels).map_err(|_| format!("{name} is not a valid Zone label path")) } diff --git a/packages/d2b-sk-frontend/src/main.rs b/packages/d2b-sk-frontend/src/main.rs index f4449db20..20a782fcc 100644 --- a/packages/d2b-sk-frontend/src/main.rs +++ b/packages/d2b-sk-frontend/src/main.rs @@ -51,19 +51,24 @@ fn exit_on_error(result: Result) -> T { } fn main() { - let config = exit_on_error(Config::from_env()); - let placement = exit_on_error(config.placement.clone().into_placement()); + let Config { + vm_id, + link, + uhid_path, + placement, + } = exit_on_error(Config::from_env()); + let placement = exit_on_error(placement.into_placement()); eprintln!( "[d2b-sk-frontend/{}] starting; uhid={}, allocator=vsock:{}:{}", - config.vm_id, - config.uhid_path.display(), - config.link.cid(), - config.link.port(), + vm_id, + uhid_path.display(), + link.cid(), + link.port(), ); - let agent = SecurityKeyFrontend::::open(&config.uhid_path, &config.vm_id); - let link = Box::new(VsockAllocatorLink::new(config.link.cid(), config.link.port())); + let agent = SecurityKeyFrontend::::open(&uhid_path, &vm_id); + let link = Box::new(VsockAllocatorLink::new(link.cid(), link.port())); let status = run_guest(agent, link, Arc::new(AllocatorEnrollment::new(placement))); std::process::exit(status); } From e1fab0e9b1433dc09eb6ad748e9eff33ab53930f Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:32:14 -0700 Subject: [PATCH 136/726] d2b-telemetry: state the failure contract of the public surface --- packages/d2b-telemetry/src/audit_hash.rs | 15 +++++++ packages/d2b-telemetry/src/emitter.rs | 44 ++++++++++++++++++- packages/d2b-telemetry/src/meter_registry.rs | 21 +++++++++ .../d2b-telemetry/src/metric_label_policy.rs | 6 +++ packages/d2b-telemetry/src/redaction_guard.rs | 17 +++++++ .../d2b-telemetry/src/session_metrics_sink.rs | 6 +++ 6 files changed, 107 insertions(+), 2 deletions(-) diff --git a/packages/d2b-telemetry/src/audit_hash.rs b/packages/d2b-telemetry/src/audit_hash.rs index e29a78fc4..ec379ba1b 100644 --- a/packages/d2b-telemetry/src/audit_hash.rs +++ b/packages/d2b-telemetry/src/audit_hash.rs @@ -20,6 +20,11 @@ pub struct AuditHash(String); impl AuditHash { /// Parse the canonical `sha256:` representation. + /// + /// # Errors + /// + /// Returns `AuditHashError::BadShape` when the value is not the + /// canonical lower-case SHA-256 form. pub fn parse(value: impl Into) -> Result { let value = value.into(); if !is_canonical_digest(&value) { @@ -100,6 +105,11 @@ impl AuditChainLink { } /// Verify a link against recomputed values. + /// + /// # Errors + /// + /// Returns `PreviousHashMismatch`, `PayloadHashMismatch`, or + /// `RecordHashMismatch` for the corresponding digest that changed. pub fn verify( &self, previous_hash: &AuditHash, @@ -123,6 +133,11 @@ impl AuditChainLink { /// The shorter [`Self::verify`] method intentionally remains available /// for callers that do not have a segment sequence. Export and replay /// paths should use this method when they do. + /// + /// # Errors + /// + /// Returns `SequenceMismatch` when the sequence is not the expected + /// one, plus the same digest-mismatch variants as [`Self::verify`]. pub fn verify_at( &self, expected_sequence: u64, diff --git a/packages/d2b-telemetry/src/emitter.rs b/packages/d2b-telemetry/src/emitter.rs index 3ec83ffe7..2395fd6fa 100644 --- a/packages/d2b-telemetry/src/emitter.rs +++ b/packages/d2b-telemetry/src/emitter.rs @@ -180,6 +180,11 @@ impl core::fmt::Debug for BoundedEmitter { impl BoundedEmitter { /// Construct an emitter for a private Unix datagram path. + /// + /// # Errors + /// + /// Returns `EmitterError::SocketPathInvalid` for a non-absolute + /// path,and `StatePoisoned` for a zero byte capacity. pub fn new(path: impl Into, capacity_bytes: usize) -> Result { Self::new_with_limits( path, @@ -191,6 +196,11 @@ impl BoundedEmitter { } /// Construct an emitter with explicit count, age, and retry bounds. + /// + /// # Errors + /// + /// Returns `EmitterError::SocketPathInvalid` for a non-absolute + /// path,and `StatePoisoned` when any bound is zero. pub fn new_with_limits( path: impl Into, capacity_bytes: usize, @@ -225,6 +235,10 @@ impl BoundedEmitter { } /// Construct an emitter with the default ring capacity. + /// + /// # Errors + /// + /// Returns the same `EmitterError` conditions as [`BoundedEmitter::new`]。 pub fn with_default_capacity(path: impl Into) -> Result { Self::new(path, DEFAULT_RING_CAPACITY_BYTES) } @@ -232,6 +246,12 @@ impl BoundedEmitter { /// Emit one bounded frame. // The emitter is a synchronous library surface (frozen public API, no // async form); the state lock is a short non-suspending critical section. + /// + /// # Errors + /// + /// Returns `FrameTooLarge` beyond the frame bound, `FrameRedaction` + /// when the frame cannot be redaction-parsed or its signal does not + /// match, and the metric-policy failure for a malformed metric frame. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn emit(&self, signal: Signal, frame: &[u8]) -> Result { if frame.len() > MAX_FRAME_BYTES { @@ -313,6 +333,11 @@ impl BoundedEmitter { /// The descriptor and identity canaries are checked before serialization, /// queue admission, or socket I/O. This is the emitter-side defense in /// depth for callers that have a typed metric descriptor. + /// # Errors + /// + /// Returns the metric-policy failure when the descriptor, labels, + /// or canaries fail validation, plus the `EmitterError` conditions of + /// [`BoundedEmitter::emit`]. pub fn emit_metric( &self, descriptor: &MetricDescriptor, @@ -336,6 +361,11 @@ impl BoundedEmitter { /// Try to reconnect and drain buffered frames in FIFO order. // Synchronous library surface (no async form); the state lock is a short // non-suspending critical section. + /// + /// # Errors + /// + /// Returns `EmitterError::StatePoisoned` when the state lock is + /// poisoned. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn drain(&self) -> Result { let mut state = self.state.lock().map_err(|_| EmitterError::StatePoisoned)?; @@ -380,7 +410,12 @@ impl BoundedEmitter { } /// Number of frames currently buffered. - // Synchronous library surface (no async form); short non-suspending lock. + // Synchronous library surface (no async form); short non-suspending lock.. + /// + /// # Errors + /// + /// Returns `EmitterError::StatePoisoned` when the state lock is + /// poisoned. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn buffered_frames(&self) -> Result { self.state @@ -390,7 +425,12 @@ impl BoundedEmitter { } /// Number of bytes currently retained in the ring. - // Synchronous library surface (no async form); short non-suspending lock. + // Synchronous library surface (no async form); short non-suspending lock.. + /// + /// # Errors + /// + /// Returns `EmitterError::StatePoisoned` when the state lock is + /// poisoned. #[allow(clippy::disallowed_methods, reason = "synchronous path")] pub fn buffered_bytes(&self) -> Result { self.state diff --git a/packages/d2b-telemetry/src/meter_registry.rs b/packages/d2b-telemetry/src/meter_registry.rs index 6baa6047d..2537e1ef2 100644 --- a/packages/d2b-telemetry/src/meter_registry.rs +++ b/packages/d2b-telemetry/src/meter_registry.rs @@ -38,6 +38,11 @@ pub struct MetricFamily { impl MetricFamily { /// Construct and validate a metric family. + /// + /// # Errors + /// + /// Returns `MetricPolicyError::DescriptorMalformed` when the + /// descriptor fails validation or the buckets do not match the kind. pub fn new( descriptor: MetricDescriptor, kind: MetricKind, @@ -78,6 +83,11 @@ impl MetricFamily { } /// Record a value after policy validation. + /// + /// # Errors + /// + /// Returns `MetricPolicyError` when the data point or the value-kind + /// combination fails policy validation. pub fn record( &mut self, labels: &BTreeMap, @@ -124,6 +134,11 @@ pub struct MeterRegistry { impl MeterRegistry { /// Register one family. + /// + /// # Errors + /// + /// Returns `MetricPolicyError::DescriptorMalformed` when a family + /// with the same name is already registered. pub fn register(&mut self, family: MetricFamily) -> Result<(), MetricPolicyError> { let name = family.descriptor().name().to_owned(); if self.families.contains_key(&name) { @@ -134,6 +149,12 @@ impl MeterRegistry { } /// Record a value in a registered family. + /// + /// # Errors + /// + /// Returns `MetricPolicyError::DescriptorMalformed` when the family + /// is not registered, plus the family's own record validation + /// failures. pub fn record( &mut self, name: &str, diff --git a/packages/d2b-telemetry/src/metric_label_policy.rs b/packages/d2b-telemetry/src/metric_label_policy.rs index 3e2821998..c0bf7e220 100644 --- a/packages/d2b-telemetry/src/metric_label_policy.rs +++ b/packages/d2b-telemetry/src/metric_label_policy.rs @@ -11,6 +11,12 @@ pub use d2b_contracts_provider::v3::telemetry_policy::{ }; /// Validate resource attributes with key-specific identity handling. +/// +/// # Errors +/// +/// Returns `MetricPolicyError::DescriptorMalformed` when an attribute +/// is not allowlisted or its value is empty, oversized, or +/// non-graphic. pub fn validate_resource_attributes( attributes: &BTreeMap, ) -> Result<(), MetricPolicyError> { diff --git a/packages/d2b-telemetry/src/redaction_guard.rs b/packages/d2b-telemetry/src/redaction_guard.rs index 18a611c1c..4ccb3caca 100644 --- a/packages/d2b-telemetry/src/redaction_guard.rs +++ b/packages/d2b-telemetry/src/redaction_guard.rs @@ -41,6 +41,11 @@ pub struct RedactionGuard { impl RedactionGuard { /// Validate resource attributes against the closed allowlist. + /// + /// # Errors + /// + /// Returns `RedactionError::AttributeNotAllowlisted` when an + /// attribute is not allowlisted, invalid-shaped, or duplicated. pub fn new( attributes: impl IntoIterator, impl Into)>, ) -> Result { @@ -92,6 +97,11 @@ impl RedactionGuard { } /// Validate a span field name before it is emitted. + /// + /// # Errors + /// + /// Returns `RedactionError::ForbiddenSpanField` when the name is + /// forbidden or carries a forbidden suffix. pub fn validate_span_field(key: &str) -> Result<(), RedactionError> { const FORBIDDEN: &[&str] = &[ "path", @@ -137,6 +147,13 @@ impl RedactionGuard { } /// Validate all span fields and return an owned redacted map. + /// + /// # Errors + /// + /// Returns `ForbiddenSpanField` for a forbidden, invalid-shaped, or + /// duplicated field, and `SemanticFieldNotAllowlisted` or + /// `SemanticValueNotAllowlisted` for a field or value outside the + /// closed semantic set. pub fn span_attributes( fields: impl IntoIterator, impl Into)>, ) -> Result, RedactionError> { diff --git a/packages/d2b-telemetry/src/session_metrics_sink.rs b/packages/d2b-telemetry/src/session_metrics_sink.rs index da825c4fa..1b24de098 100644 --- a/packages/d2b-telemetry/src/session_metrics_sink.rs +++ b/packages/d2b-telemetry/src/session_metrics_sink.rs @@ -45,6 +45,12 @@ impl SessionMetricsSink { } /// Record a session event with closed labels. + /// + /// # Errors + /// + /// Returns `SessionMetricsError::Policy` when the event or labels + /// fail policy validation, and `SessionMetricsError::Emitter` when + /// the emitter rejects the frame. pub fn record( &self, event: SessionMetricEvent, From 217c0c66c797de8ec408c321c3b88689322b0315 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:32:49 -0700 Subject: [PATCH 137/726] refactor(session): iterator decode, shared permit check, member bound const --- packages/d2b-session/src/admission.rs | 14 ++++++-------- packages/d2b-session/src/engine.rs | 13 +++++-------- packages/d2b-session/src/operation.rs | 8 +++++++- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/d2b-session/src/admission.rs b/packages/d2b-session/src/admission.rs index 14f875744..3d29588f1 100644 --- a/packages/d2b-session/src/admission.rs +++ b/packages/d2b-session/src/admission.rs @@ -1179,22 +1179,27 @@ impl AuthenticatedSessionRouteBinding { &self.context } + /// Borrow the authenticated Zone. pub fn zone(&self) -> &ZoneId { &self.zone } + /// Borrow the authenticated subject reference. pub fn subject_ref(&self) -> &ResourceRef { &self.subject_ref } + /// Borrow the authenticated subject UID. pub fn subject_uid(&self) -> &ResourceUid { &self.subject_uid } + /// Return the evidence class that authenticated the subject. pub const fn evidence_class(&self) -> EvidenceClass { self.evidence_class } + /// Return the authenticated locality. pub const fn locality(&self) -> Locality { self.locality } @@ -1596,14 +1601,7 @@ impl AuthenticatedComponentSession { frame: Vec, now_tick: u64, ) -> Result<()> { - if !permit.lease.is_valid_at(now_tick) - || !matches!( - permit.request.verb, - SessionVerb::Invoke | SessionVerb::AuditExport | SessionVerb::SupportBundle - ) - { - return Err(SessionError::new(SessionErrorCode::PolicyDenied)); - } + validate_ttrpc_permit(&permit, now_tick)?; self.driver.send_ttrpc(frame).await } diff --git a/packages/d2b-session/src/engine.rs b/packages/d2b-session/src/engine.rs index 632935f03..5558b342e 100644 --- a/packages/d2b-session/src/engine.rs +++ b/packages/d2b-session/src/engine.rs @@ -1798,14 +1798,11 @@ fn decode_attachment_control(bytes: &[u8]) -> Result { SessionErrorCode::AttachmentDescriptorMismatch, )); } - let mut descriptors = Vec::with_capacity(usize::from(count)); - let mut offset = 3; - for _ in 0..count { - descriptors.push(decode_attachment_descriptor( - &bytes[offset..offset + ATTACHMENT_DESCRIPTOR_BYTES], - )?); - offset += ATTACHMENT_DESCRIPTOR_BYTES; - } + let descriptors = bytes[3..] + .chunks_exact(ATTACHMENT_DESCRIPTOR_BYTES) + .take(usize::from(count)) + .map(decode_attachment_descriptor) + .collect::>>()?; Ok(AttachmentControl::Batch(AttachmentPacket { declared_count: count, descriptors: BoundedVec::new(descriptors)?, diff --git a/packages/d2b-session/src/operation.rs b/packages/d2b-session/src/operation.rs index a6f993674..79b5bc2ae 100644 --- a/packages/d2b-session/src/operation.rs +++ b/packages/d2b-session/src/operation.rs @@ -182,6 +182,12 @@ pub fn resource_operation(method: ApiMethod) -> &'static OperationCatalogEntry { .expect("every ApiMethod has one unary ResourceService member") } +/// Wire-visible admission bound on one canonical `Service/Member` spelling. +/// +/// Longer wire strings are refused at parse time so the session never +/// admits an unbounded member spelling. +pub const MAX_MEMBER_SPELLING_LEN: usize = 128; + /// Canonically spelled generated service member. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OperationMember { @@ -204,7 +210,7 @@ impl OperationMember { let mut components = value.split('/'); let service = components.next().unwrap_or_default(); let member = components.next().unwrap_or_default(); - if value.len() > 128 + if value.len() > MAX_MEMBER_SPELLING_LEN || components.next().is_some() || !valid_identifier(service) || !valid_identifier(member) From 6970c9d9e678724d9fb2f1e2aa84986c18d1afeb Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:32:49 -0700 Subject: [PATCH 138/726] docs(session): document handshake and transport contracts --- packages/d2b-session/src/error.rs | 4 + packages/d2b-session/src/handshake.rs | 103 ++++++++++++++++++++++++++ packages/d2b-session/src/transport.rs | 14 +++- 3 files changed, 118 insertions(+), 3 deletions(-) diff --git a/packages/d2b-session/src/error.rs b/packages/d2b-session/src/error.rs index 804f737ef..a494493bf 100644 --- a/packages/d2b-session/src/error.rs +++ b/packages/d2b-session/src/error.rs @@ -28,6 +28,7 @@ pub enum SessionErrorClass { } impl SessionErrorClass { + /// Return the stable kebab-case class spelling. pub const fn as_str(self) -> &'static str { match self { Self::Authentication => "authentication", @@ -44,14 +45,17 @@ impl SessionErrorClass { } impl SessionError { + /// Construct an error from a closed session error code. pub const fn new(code: SessionErrorCode) -> Self { Self { code } } + /// Return the closed error code. pub const fn code(self) -> SessionErrorCode { self.code } + /// Return the error class the code belongs to. pub const fn class(self) -> SessionErrorClass { match self.code { SessionErrorCode::AuthenticationFailed diff --git a/packages/d2b-session/src/handshake.rs b/packages/d2b-session/src/handshake.rs index ecc443e96..f2e9f24f6 100644 --- a/packages/d2b-session/src/handshake.rs +++ b/packages/d2b-session/src/handshake.rs @@ -18,10 +18,20 @@ const INIT_PAYLOAD: &[u8] = b"d2b-component-session-v3-init"; const ACCEPT_PAYLOAD: &[u8] = b"d2b-component-session-v3-accept"; const GENERATION_QUERY_MAGIC: &[u8; 8] = b"D2BGD3Q\n"; const GENERATION_REPLY_MAGIC: &[u8; 8] = b"D2BGD3A\n"; +/// Wire length of one generation-discovery request (magic plus the +/// canonical endpoint identity). pub const GENERATION_DISCOVERY_REQUEST_LEN: usize = GENERATION_QUERY_MAGIC.len() + ENDPOINT_POLICY_IDENTITY_CANONICAL_LEN; +/// Wire length of one generation-discovery response (magic plus a 32-byte +/// digest and an 8-byte generation). pub const GENERATION_DISCOVERY_RESPONSE_LEN: usize = GENERATION_REPLY_MAGIC.len() + 32 + 8; +/// Derive the X25519 public key for a private key. +/// +/// # Errors +/// +/// Returns [`SessionErrorCode::AuthenticationFailed`] when the private key +/// is the all-zero identity or the resolver cannot derive a public key. pub fn x25519_public_key(private_key: &[u8; 32]) -> Result<[u8; 32]> { if private_key == &[0; 32] { return Err(SessionError::new(SessionErrorCode::AuthenticationFailed)); @@ -35,23 +45,35 @@ pub fn x25519_public_key(private_key: &[u8; 32]) -> Result<[u8; 32]> { .map_err(|_| SessionError::new(SessionErrorCode::AuthenticationFailed)) } +/// One side of the Noise handshake. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum HandshakeRole { + /// The party that sends the first handshake message. Initiator, + /// The party that receives the first handshake message. Responder, } +/// Key material for one Noise profile. +/// +/// The `Nn` profile authenticates nothing; `Kk` authenticates both sides +/// from pre-shared static keys; `IkPsk2` authenticates the responder to the +/// initiator and adds a one-time bootstrap PSK. pub enum HandshakeCredentials { + /// Anonymous `Nn` profile. Nn, + /// `Kk` profile with both static keys. Kk { local_private: Secret32, remote_public: [u8; 32], }, + /// `IKpsk2` profile as the initiator. IkPsk2Initiator { local_private: Secret32, remote_public: [u8; 32], psk: AdmittedBootstrapPsk, }, + /// `IKpsk2` profile as the responder. IkPsk2Responder { local_private: Secret32, psk: AdmittedBootstrapPsk, @@ -73,6 +95,7 @@ impl fmt::Debug for HandshakeCredentials { } } +/// A validated handshake offer bound to one endpoint policy. pub struct NegotiatedOffer { preface: ComponentSessionPreface, offer: HandshakeOffer, @@ -80,10 +103,12 @@ pub struct NegotiatedOffer { } impl NegotiatedOffer { + /// Borrow the negotiated handshake offer. pub fn offer(&self) -> &HandshakeOffer { &self.offer } + /// Return the negotiated session preface. pub fn preface(&self) -> ComponentSessionPreface { self.preface } @@ -108,6 +133,12 @@ impl fmt::Debug for NegotiatedOffer { } } +/// Encode an endpoint policy as a preface plus canonical offer bytes. +/// +/// # Errors +/// +/// Returns the preface or canonical-encoding error when the policy cannot +/// be rendered on the wire. pub fn encode_offer(policy: &EndpointPolicy) -> Result<([u8; PREFACE_LEN], Vec)> { let offer = HandshakeOffer::from(policy.clone()); let canonical = offer.encode_canonical()?; @@ -117,6 +148,14 @@ pub fn encode_offer(policy: &EndpointPolicy) -> Result<([u8; PREFACE_LEN], Vec Result> { identity .validate_generation_discovery() @@ -148,10 +193,18 @@ pub fn encode_generation_discovery_request(identity: &EndpointPolicyIdentity) -> Ok(request) } +/// Whether the bytes carry the generation-discovery request magic. pub fn is_generation_discovery_request(bytes: &[u8]) -> bool { bytes.starts_with(GENERATION_QUERY_MAGIC) } +/// Validate a generation-discovery request and bind it to a request digest. +/// +/// # Errors +/// +/// Returns [`SessionErrorCode::MalformedHandshake`] when the length or +/// magic is wrong, and the identity, policy, or offer validation error when +/// the request does not match the endpoint policy. pub fn accept_generation_discovery_request( bytes: &[u8], policy: &EndpointPolicy, @@ -188,6 +241,14 @@ pub fn encode_generation_discovery_response( Ok(response) } +/// Decode a generation-discovery response and verify its request binding. +/// +/// # Errors +/// +/// Returns [`SessionErrorCode::MalformedHandshake`] when the length or +/// magic is wrong, [`SessionErrorCode::TranscriptMismatch`] when the +/// response does not bind the request digest, and +/// [`SessionErrorCode::GenerationMismatch`] when the generation is zero. pub fn decode_generation_discovery_response(bytes: &[u8], request: &[u8]) -> Result { if bytes.len() != GENERATION_DISCOVERY_RESPONSE_LEN || !bytes.starts_with(GENERATION_REPLY_MAGIC) @@ -236,6 +297,11 @@ fn preface_error(error: PrefaceError) -> SessionError { SessionError::new(code) } +/// A step-limited Noise handshake state machine. +/// +/// The handshake runs a fixed number of steps (one write and one read for +/// the initiator, one read and one write for the responder) and fails +/// closed on any step mismatch. pub struct NoiseHandshake { state: HandshakeState, bootstrap_identity: Option, @@ -246,6 +312,12 @@ pub struct NoiseHandshake { } impl NoiseHandshake { + /// Start a handshake from a negotiated offer and role credentials. + /// + /// # Errors + /// + /// Returns the credentials-validation error when the role, noise + /// profile, and credentials do not agree. pub fn new( role: HandshakeRole, negotiated: &NegotiatedOffer, @@ -274,6 +346,14 @@ impl NoiseHandshake { }) } + /// Write the next handshake message for the current step. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::InternalInvariant`] when the step is not + /// the one this role writes, [`SessionErrorCode::AuthenticationFailed`] + /// when the Noise write fails, and the bound error when the message + /// exceeds the negotiated limit profile. pub fn write_next(&mut self) -> Result> { let payload = match (self.role, self.step) { (HandshakeRole::Initiator, 0) => INIT_PAYLOAD, @@ -291,6 +371,16 @@ impl NoiseHandshake { Ok(output) } + /// Read and authenticate the next handshake message for the current step. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::MalformedHandshake`] when the message + /// exceeds the negotiated bound, [`SessionErrorCode::InternalInvariant`] + /// when the step is not the one this role reads, + /// [`SessionErrorCode::AuthenticationFailed`] when the Noise read + /// fails, and [`SessionErrorCode::TranscriptMismatch`] when the + /// decrypted payload is not the expected step payload. pub fn read_next(&mut self, message: &[u8]) -> Result<()> { if message.len() > self.limits.protected_ciphertext_bytes as usize { return Err(SessionError::new(SessionErrorCode::MalformedHandshake)); @@ -312,6 +402,16 @@ impl NoiseHandshake { Ok(()) } + /// Complete the handshake and enter transport mode. + /// + /// # Errors + /// + /// Returns [`SessionErrorCode::MalformedHandshake`] when the step count + /// or Noise state does not mark the handshake finished, + /// [`SessionErrorCode::InternalInvariant`] when the transcript hash + /// cannot be captured, and + /// [`SessionErrorCode::AuthenticationFailed`] when the remote static + /// key or transport-mode transition fails. pub fn finish(self) -> Result { if self.step != 2 || !self.state.is_handshake_finished() { return Err(SessionError::new(SessionErrorCode::MalformedHandshake)); @@ -438,6 +538,7 @@ fn build_state( .map_err(|_| SessionError::new(SessionErrorCode::AuthenticationFailed)) } +/// A completed Noise handshake in transport mode. pub struct EstablishedHandshake { pub(crate) transport: TransportState, transcript_hash: [u8; 32], @@ -455,10 +556,12 @@ pub(crate) struct EstablishedAuthentication { } impl EstablishedHandshake { + /// Borrow the handshake transcript hash. pub fn transcript_hash(&self) -> &[u8; 32] { &self.transcript_hash } + /// Return the bound resource generation. pub fn generation(&self) -> u64 { self.generation } diff --git a/packages/d2b-session/src/transport.rs b/packages/d2b-session/src/transport.rs index 24d7efb81..b6a49e0ee 100644 --- a/packages/d2b-session/src/transport.rs +++ b/packages/d2b-session/src/transport.rs @@ -20,6 +20,7 @@ pub struct TransportPacket { } impl TransportPacket { + /// Construct a packet with no attachments. pub fn new(bytes: Vec) -> Self { Self { bytes, @@ -27,18 +28,22 @@ impl TransportPacket { } } + /// Construct a packet with its owned attachment set. pub fn with_attachments(bytes: Vec, attachments: Vec) -> Self { Self { bytes, attachments } } + /// Borrow the packet body. pub fn as_bytes(&self) -> &[u8] { &self.bytes } + /// Borrow the attached fds. pub fn attachments(&self) -> &[OwnedAttachment] { &self.attachments } + /// Split the packet into its body and attachment set. pub fn into_parts(self) -> (Vec, Vec) { (self.bytes, self.attachments) } @@ -205,10 +210,13 @@ struct SerializedWriter { transport: std::sync::Arc>>, } -/// Compatibility split for transports that are never driven concurrently. +/// Serialized-compatibility split for transports that are never driven +/// concurrently. /// -/// Production transports and driver tests must provide independent halves; -/// this helper exists for direct engine-only test transports. +/// The reader and writer halves share one transport through a mutex, so +/// they must never be driven concurrently: a read and a write in flight at +/// the same time interleave on the same transport. Production transports +/// and driver tests provide independent halves instead. pub fn serialized_transport_split( transport: Box, ) -> (Box, Box) { From 7b621ee105dbfceff4bc133d4a7007f7f684ce96 Mon Sep 17 00:00:00 2001 From: John Vicondoa Date: Fri, 25 Sep 2026 02:32:52 -0700 Subject: [PATCH 139/726] refactor(d2b-provider-system-core): simplify hex rendering, free required_bindings, move snapshot fields --- packages/d2b-provider-system-core/src/host.rs | 76 ++++++++++++++++--- packages/d2b-provider-system-core/src/lib.rs | 2 +- packages/d2b-provider-system-core/src/user.rs | 50 +++++++----- .../tests/user_discovery.rs | 6 +- 4 files changed, 102 insertions(+), 32 deletions(-) diff --git a/packages/d2b-provider-system-core/src/host.rs b/packages/d2b-provider-system-core/src/host.rs index a5be94023..466125839 100644 --- a/packages/d2b-provider-system-core/src/host.rs +++ b/packages/d2b-provider-system-core/src/host.rs @@ -118,6 +118,12 @@ impl MinijailPlatformGate { } /// Validate the non-optional minijail placement requirements. + /// + /// # Errors + /// + /// Returns [`SystemCoreError::KernelTooOld`] when the kernel is below the + /// mandatory floor and [`SystemCoreError::CgroupKillUnavailable`] when + /// the delegated cgroup leaf has no writable `cgroup.kill`. pub fn validate(self) -> Result<(), SystemCoreError> { if !self.kernel_supported() { return Err(SystemCoreError::KernelTooOld); @@ -158,6 +164,12 @@ pub struct HostProbeMetadata { impl HostProbeSnapshot { /// Construct a bounded probe result. + /// + /// # Errors + /// + /// Returns [`SystemCoreError::HostProbeFailed`] when a string exceeds + /// its bound (64 bytes for the kernel release, 128 for the OS name) or + /// contains a control character. pub fn new( capabilities: impl IntoIterator, kernel_release: impl Into, @@ -225,12 +237,22 @@ impl HostProbeSnapshot { #[async_trait::async_trait] pub trait HostProbeEffectPort: Send + Sync { /// Probe one capability class. + /// + /// # Errors + /// + /// Returns [`SystemCoreError::HostProbeFailed`] when the capability + /// cannot be probed. async fn probe( &self, capability: HostCapabilityClass, ) -> Result; /// Return kernel/platform evidence without exposing paths or handles. + /// + /// # Errors + /// + /// Returns [`SystemCoreError::HostProbeFailed`] when platform evidence + /// cannot be collected. async fn platform(&self) -> Result; /// Return bounded metadata for the same probe pass. @@ -337,6 +359,13 @@ impl HostReconciler { provider_ref: &ResourceRef, spec: &HostSpec, ) -> Result { + // # Errors + // + // Returns [`SystemCoreError::ResourceTypeNotOwned`] when the + // reference is not a Host, [`SystemCoreError::ProviderRefMismatch`] + // when the resource names another Provider, and + // [`SystemCoreError::UserRefRequired`] when a user-domain Host + // declares no exact default user reference. ownership::require_resource_type(host_ref, HOST_RESOURCE_TYPE).inspect_err(|&error| { warn!( provider = crate::PROVIDER_NAME, @@ -389,6 +418,12 @@ impl HostReconciler { pub fn reject_operator_status_fields( submitted: &serde_json::Value, ) -> Result<(), SystemCoreError> { + // # Errors + // + // Returns [`SystemCoreError::StatusNotAnObject`] when the submitted + // value is not a JSON object and + // [`SystemCoreError::OperatorSuppliedStatusField`] when it carries a + // reconciler-owned field. let object = submitted .as_object() .ok_or(SystemCoreError::StatusNotAnObject) @@ -425,13 +460,29 @@ impl HostReconciler { required_capabilities: &BTreeSet, requires_minijail: bool, ) -> Result { + // # Errors + // + // Returns the errors of [`Self::reconcile`], plus + // [`SystemCoreError::CapabilityMissing`] when the probe lacks a + // required capability and the minijail gate errors + // ([`SystemCoreError::KernelTooOld`], + // [`SystemCoreError::CgroupKillUnavailable`]) when a minijail Host + // fails the platform gate. + let HostProbeSnapshot { + capabilities, + kernel_release, + os_name, + user_manager_available, + minijail_gate, + active_process_count, + } = snapshot; let mut status = self.reconcile(host_ref, provider_ref, spec)?; let mut required = required_capabilities.clone(); if requires_minijail { required.insert(HostCapabilityClass::Pidfd); required.insert(HostCapabilityClass::CgroupV2); } - if !required.is_subset(snapshot.capabilities()) { + if !required.is_subset(&capabilities) { warn!( provider = crate::PROVIDER_NAME, host = %host_ref.to_canonical_string(), @@ -440,7 +491,7 @@ impl HostReconciler { return Err(SystemCoreError::CapabilityMissing); } if requires_minijail { - snapshot.minijail_gate().validate().inspect_err(|&error| { + minijail_gate.validate().inspect_err(|&error| { warn!( provider = crate::PROVIDER_NAME, host = %host_ref.to_canonical_string(), @@ -449,7 +500,7 @@ impl HostReconciler { ); })?; } - if spec.policy().admits_user_domain() && !snapshot.user_manager_available() { + if spec.policy().admits_user_domain() && !user_manager_available { // User-manager unavailability is a degraded observation, not a // reason to claim a user-capable Host is Ready. System-only Hosts // remain Ready when no user manager is required. @@ -462,13 +513,13 @@ impl HostReconciler { } Ok(HostObservationReport { status, - capabilities: snapshot.capabilities().iter().copied().collect(), - kernel_release: snapshot.kernel_release().to_owned(), - os_name: snapshot.os_name().to_owned(), - user_manager_available: snapshot.user_manager_available(), - active_process_count: snapshot.active_process_count(), - minijail_ready: snapshot.minijail_gate().kernel_supported() - && snapshot.minijail_gate().cgroup_kill_available, + capabilities: capabilities.iter().copied().collect(), + kernel_release, + os_name, + user_manager_available, + active_process_count, + minijail_ready: minijail_gate.kernel_supported() + && minijail_gate.cgroup_kill_available, }) } @@ -487,6 +538,11 @@ impl HostReconciler { required_capabilities: &BTreeSet, requires_minijail: bool, ) -> Result { + // # Errors + // + // Returns the errors of [`Self::reconcile_observed`], plus + // [`SystemCoreError::HostProbeFailed`] when the injected probe port + // reports an invalid observation. let mut capabilities = BTreeSet::new(); for capability in HostCapabilityClass::ALL { if port diff --git a/packages/d2b-provider-system-core/src/lib.rs b/packages/d2b-provider-system-core/src/lib.rs index e4faa10d1..2209a8285 100644 --- a/packages/d2b-provider-system-core/src/lib.rs +++ b/packages/d2b-provider-system-core/src/lib.rs @@ -49,7 +49,7 @@ pub use host::{ pub use ownership::{DISOWNED_RESOURCE_TYPES, OWNED_RESOURCE_TYPES}; pub use user::{ DiscoveredUser, UserBinding, UserDiscoveryCondition, UserDiscoveryEffectPort, - UserIdentityDigest, UserObservation, UserReconciler, UserStatusReport, + UserIdentityDigest, UserObservation, UserReconciler, UserStatusReport, required_bindings, }; /// The Provider name this bootstrap controller implements. diff --git a/packages/d2b-provider-system-core/src/user.rs b/packages/d2b-provider-system-core/src/user.rs index 2504b54de..6828cab27 100644 --- a/packages/d2b-provider-system-core/src/user.rs +++ b/packages/d2b-provider-system-core/src/user.rs @@ -70,10 +70,13 @@ impl UserIdentityDigest { /// Render the digest as lowercase hex. pub fn to_hex(self) -> String { + const HEX: [char; 16] = [ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', + ]; let mut out = String::with_capacity(64); for byte in self.0 { - out.push(char::from_digit(u32::from(byte >> 4), 16).unwrap_or('0')); - out.push(char::from_digit(u32::from(byte & 0x0f), 16).unwrap_or('0')); + out.push(HEX[usize::from(byte >> 4)]); + out.push(HEX[usize::from(byte & 0x0f)]); } out } @@ -141,6 +144,11 @@ pub trait UserDiscoveryEffectPort: Send + Sync { /// /// `Ok(None)` means the local machine resolves no such identity, which /// is an ordinary state rather than a failure. + /// + /// # Errors + /// + /// Returns [`SystemCoreError::DiscoveryUnavailable`] when local + /// discovery cannot resolve a usable identity. async fn discover( &self, user_ref: &ResourceRef, @@ -211,6 +219,21 @@ pub struct UserReconciler { port: P, } +/// The properties a User must verify before it is reported discovered. +/// +/// The record and its primary group are always required. Group +/// memberships are required exactly when the spec declares any, so a +/// User that declares none is not held to a check with nothing to +/// check, and a User that declares some cannot be called discovered +/// while they are unverified. +pub fn required_bindings(spec: &UserSpec) -> BTreeSet { + let mut required = BTreeSet::from([UserBinding::NssRecord, UserBinding::PrimaryGroup]); + if !spec.groups().is_empty() { + required.insert(UserBinding::GroupMemberships); + } + required +} + impl UserReconciler